From 379c041038b14b2adb53ad9b16c1268b389357e2 Mon Sep 17 00:00:00 2001 From: tcambron Date: Tue, 3 Nov 2015 14:36:43 -0600 Subject: [PATCH 0001/1578] StatsD: Add res_statsd compatibility Added a new api to res_statsd.c to allow it to receive a character pointer for the value argument. This allows for a '+' and a '-' to easily be sent with the value. ASTERISK-25419 Reported By: Ashley Sanders Change-Id: Id6bb53600943d27347d2bcae26c0bd5643567611 --- include/asterisk/statsd.h | 16 ++++++++++++++++ res/res_statsd.c | 40 ++++++++++++++++++++++++++++----------- res/res_statsd.exports.in | 1 + 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/include/asterisk/statsd.h b/include/asterisk/statsd.h index 8e5e2f987db..a04407f89ba 100644 --- a/include/asterisk/statsd.h +++ b/include/asterisk/statsd.h @@ -39,6 +39,22 @@ /*! Events over time. Sorta like increment-only counters. */ #define AST_STATSD_METER "m" +/*! + * \brief Send a stat to the configured statsd server. + * + * This function uses a character argument for value instead of + * an intmax_t argument. This is designed to be simpler to use for + * updating a current value rather than resetting it. + * + * \param metric_name String (UTF-8) name of the metric. + * \param type_str Type of metric to send. + * \param value Value to send. + * \param sample_rate Percentage of samples to send. + * \since 13 + */ +AST_OPTIONAL_API(void, ast_statsd_log_string, (const char *metric_name, + const char *metric_type, const char *value, double sample_rate), {}); + /*! * \brief Send a stat to the configured statsd server. * diff --git a/res/res_statsd.c b/res/res_statsd.c index fefe395e8bd..8bf74db098c 100644 --- a/res/res_statsd.c +++ b/res/res_statsd.c @@ -97,11 +97,11 @@ static void conf_server(const struct conf *cfg, struct ast_sockaddr *addr) } } -void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name, - const char *metric_type, intmax_t value, double sample_rate) +void AST_OPTIONAL_API_NAME(ast_statsd_log_string)(const char *metric_name, + const char *metric_type, const char *value, double sample_rate) { - RAII_VAR(struct conf *, cfg, NULL, ao2_cleanup); - RAII_VAR(struct ast_str *, msg, NULL, ast_free); + struct conf *cfg; + struct ast_str *msg; size_t len; struct ast_sockaddr statsd_server; @@ -109,9 +109,6 @@ void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name, return; } - cfg = ao2_global_obj_ref(confs); - conf_server(cfg, &statsd_server); - /* Rates <= 0.0 never get logged. * Rates >= 1.0 always get logged. * All others leave it to chance. @@ -122,9 +119,11 @@ void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name, } cfg = ao2_global_obj_ref(confs); + conf_server(cfg, &statsd_server); msg = ast_str_create(40); if (!msg) { + ao2_cleanup(cfg); return; } @@ -132,7 +131,7 @@ void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name, ast_str_append(&msg, 0, "%s.", cfg->global->prefix); } - ast_str_append(&msg, 0, "%s:%jd|%s", metric_name, value, metric_type); + ast_str_append(&msg, 0, "%s:%s|%s", metric_name, value, metric_type); if (sample_rate < 1.0) { ast_str_append(&msg, 0, "|@%.2f", sample_rate); @@ -144,20 +143,39 @@ void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name, len = ast_str_strlen(msg); - ast_debug(6, "send: %s\n", ast_str_buffer(msg)); + ast_debug(6, "Sending statistic %s to StatsD server\n", ast_str_buffer(msg)); ast_sendto(socket_fd, ast_str_buffer(msg), len, 0, &statsd_server); + + ao2_cleanup(cfg); + ast_free(msg); +} + +void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name, + const char *metric_type, intmax_t value, double sample_rate) +{ + char char_value[30]; + snprintf(char_value, sizeof(char_value), "%jd", value); + + ast_statsd_log_string(metric_name, metric_type, char_value, sample_rate); + } void AST_OPTIONAL_API_NAME(ast_statsd_log)(const char *metric_name, const char *metric_type, intmax_t value) { - ast_statsd_log_full(metric_name, metric_type, value, 1.0); + char char_value[30]; + snprintf(char_value, sizeof(char_value), "%jd", value); + + ast_statsd_log_string(metric_name, metric_type, char_value, 1.0); } void AST_OPTIONAL_API_NAME(ast_statsd_log_sample)(const char *metric_name, intmax_t value, double sample_rate) { - ast_statsd_log_full(metric_name, AST_STATSD_COUNTER, value, + char char_value[30]; + snprintf(char_value, sizeof(char_value), "%jd", value); + + ast_statsd_log_string(metric_name, AST_STATSD_COUNTER, char_value, sample_rate); } diff --git a/res/res_statsd.exports.in b/res/res_statsd.exports.in index 6f02b25d6a7..d4a79c18f07 100644 --- a/res/res_statsd.exports.in +++ b/res/res_statsd.exports.in @@ -3,6 +3,7 @@ LINKER_SYMBOL_PREFIX*ast_statsd_log; LINKER_SYMBOL_PREFIX*ast_statsd_log_full; LINKER_SYMBOL_PREFIX*ast_statsd_log_sample; + LINKER_SYMBOL_PREFIX*ast_statsd_log_string; local: *; }; From cd5ae02812faa311056adb3f27cd8270642a4a6e Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 2 Nov 2015 21:11:11 -0500 Subject: [PATCH 0002/1578] Increase account code maximum length to 80. This increases the maximum length of account code's to match extensions. This ensures it is always possible to set an accountcode to ${EXTEN} without truncation. ASTERISK-23904 Reported by: Ben Merrills Change-Id: If122602304ce03362722eb213a3111b32da5eeb9 --- .../54cde9847798_expand_accountcode_to_80.py | 26 +++++++++++++++++ .../339a3bdf53fc_expand_accountcode_to_80.py | 28 +++++++++++++++++++ include/asterisk/channel.h | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 contrib/ast-db-manage/cdr/versions/54cde9847798_expand_accountcode_to_80.py create mode 100644 contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py diff --git a/contrib/ast-db-manage/cdr/versions/54cde9847798_expand_accountcode_to_80.py b/contrib/ast-db-manage/cdr/versions/54cde9847798_expand_accountcode_to_80.py new file mode 100644 index 00000000000..dd61a44ee3e --- /dev/null +++ b/contrib/ast-db-manage/cdr/versions/54cde9847798_expand_accountcode_to_80.py @@ -0,0 +1,26 @@ +"""expand accountcode to 80 + +Revision ID: 54cde9847798 +Revises: 210693f3123d +Create Date: 2015-11-05 09:54:06.815364 + +""" + +# revision identifiers, used by Alembic. +revision = '54cde9847798' +down_revision = '210693f3123d' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.alter_column('cdr', 'accountcode', type_=sa.String(80)) + op.alter_column('cdr', 'peeraccount', type_=sa.String(80)) + pass + + +def downgrade(): + op.alter_column('cdr', 'accountcode', type_=sa.String(20)) + op.alter_column('cdr', 'peeraccount', type_=sa.String(20)) + pass diff --git a/contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py b/contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py new file mode 100644 index 00000000000..31889c66bbb --- /dev/null +++ b/contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py @@ -0,0 +1,28 @@ +"""expand accountcode to 80 + +Revision ID: 339a3bdf53fc +Revises: 28ce1e718f05 +Create Date: 2015-11-05 10:10:27.465794 + +""" + +# revision identifiers, used by Alembic. +revision = '339a3bdf53fc' +down_revision = '28ce1e718f05' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.alter_column('ps_endpoints', 'accountcode', type_=sa.String(80)) + op.alter_column('sippeers', 'accountcode', type_=sa.String(80)) + op.alter_column('iaxfriends', 'accountcode', type_=sa.String(80)) + pass + + +def downgrade(): + op.alter_column('ps_endpoints', 'accountcode', type_=sa.String(20)) + op.alter_column('sippeers', 'accountcode', type_=sa.String(40)) + op.alter_column('iaxfriends', 'accountcode', type_=sa.String(20)) + pass diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index fffbe5c0936..384c22d5f67 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -158,7 +158,7 @@ extern "C" { */ #define AST_MAX_UNIQUEID (AST_MAX_PUBLIC_UNIQUEID + 2 + 1) -#define AST_MAX_ACCOUNT_CODE 20 /*!< Max length of an account code */ +#define AST_MAX_ACCOUNT_CODE 80 /*!< Max length of an account code */ #define AST_CHANNEL_NAME 80 /*!< Max length of an ast_channel name */ #define MAX_LANGUAGE 40 /*!< Max length of the language setting */ #define MAX_MUSICCLASS 80 /*!< Max length of the music class setting */ From a2c2a8e1bbca9e434dfb7eaef3cf3f42773980b9 Mon Sep 17 00:00:00 2001 From: Jonathan Rose Date: Tue, 3 Nov 2015 16:19:43 -0600 Subject: [PATCH 0003/1578] taskprocessor: Add high water mark warnings If a taskprocessor's queue grows large, this can indicate that there may be a problem with tasks not leaving the processor or else that the number of available task processors for a given type of task is too low. This patch makes it so that if a taskprocessor's task queue grows above 100 queued tasks that it will emit a warning message. Warning messages are emitted only once per task processor. ASTERISK-25518 #close Reported by: Jonathan Rose Change-Id: Ib1607c35d18c1d6a0575b3f0e3ff5d932fd6600c --- main/taskprocessor.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 5c513ee66b8..0719deec2cc 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -83,6 +83,8 @@ struct ast_taskprocessor { pthread_t thread; /*! Indicates if the taskprocessor is currently executing a task */ unsigned int executing:1; + /*! Indicates that a high water warning has been issued on this task processor */ + unsigned int high_water_warned:1; }; /*! @@ -714,6 +716,8 @@ void *ast_taskprocessor_unreference(struct ast_taskprocessor *tps) return NULL; } +#define HIGH_WATER_LEVEL 100 + /* push the task into the taskprocessor queue */ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t) { @@ -733,6 +737,13 @@ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t) ao2_lock(tps); AST_LIST_INSERT_TAIL(&tps->tps_queue, t, list); previous_size = tps->tps_queue_size++; + + if (previous_size >= HIGH_WATER_LEVEL && !tps->high_water_warned) { + ast_log(LOG_WARNING, "The '%s' task processor queue reached %d scheduled tasks.\n", + tps->name, previous_size); + tps->high_water_warned = 1; + } + /* The currently executing task counts as still in queue */ was_empty = tps->executing ? 0 : previous_size == 0; ao2_unlock(tps); From 9d6e9173491554c561a0cb13045bb17e5ced9cae Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Fri, 6 Nov 2015 13:57:15 +0100 Subject: [PATCH 0004/1578] res_pjsip_sdp_rtp: Enable Opus to be negotiated via SIP/SDP. In SIP/SDP, Opus has two channels always (see RFC 7587 section 7). The actual amount of channels is negotiated in-band. Therefore now, the Opus codec and its attribute rtpmap are registered with two channels. ASTERISK-24779 #close Reported by: PowerPBX Tested by: Alexander Traud patches: asterisk-24779.patch submitted by Sean Bright (license #5060) Change-Id: Ic7ac13cafa1d3450b4fa4987350924b42cbb657b --- res/res_pjsip_sdp_rtp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a66aebb3643..3828f7e78a8 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -396,8 +396,11 @@ static pjmedia_sdp_attr* generate_rtpmap_attr(struct ast_sip_session *session, p rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1]; rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code); pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, options)); - rtpmap.param.slen = 0; - rtpmap.param.ptr = NULL; + if (!pj_stricmp2(&rtpmap.enc_name, "opus")) { + pj_cstr(&rtpmap.param, "2"); + } else { + pj_cstr(&rtpmap.param, NULL); + } pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr); From 74e73333171f701b0140c2ca513222536cea375d Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Fri, 6 Nov 2015 14:36:40 +0100 Subject: [PATCH 0005/1578] xmldoc: Improve xmldoc wrapping of 'core show ...' output. Previously, the wrapping did both lookahead and lookback, which, together with color escape sequences, caused some lines to be wrapped way earlier than other lines. This led to inconsistent output. This simplifies the wrapping code and makes it more sane: if maxcolumns is hit, we simply jump back to the last space and wrap there. ASTERISK-25527 #close Change-Id: I56d01c6f9a812642b1b05535c98d4db48d17c957 --- main/xmldoc.c | 164 ++++++++++---------------------------------------- 1 file changed, 33 insertions(+), 131 deletions(-) diff --git a/main/xmldoc.c b/main/xmldoc.c index 86c3f651218..1e3d3686015 100644 --- a/main/xmldoc.c +++ b/main/xmldoc.c @@ -45,18 +45,9 @@ ASTERISK_REGISTER_FILE() /*! \brief Default documentation language. */ static const char default_documentation_language[] = "en_US"; -/*! - * \brief Number of columns to print when showing the XML documentation with a - * 'core show application/function *' CLI command. Used in text wrapping. - */ -static const int xmldoc_text_columns = 74; - -/*! - * \brief This is a value that we will use to let the wrapping mechanism move the cursor - * backward and forward xmldoc_max_diff positions before cutting the middle of a - * word, trying to find a space or a \n. - */ -static const int xmldoc_max_diff = 5; +/*! \brief Number of columns to print when showing the XML documentation with a + * 'core show application/function *' CLI command. Used in text wrapping.*/ +static const int xmldoc_text_columns = 79; /*! \brief XML documentation language. */ static char documentation_language[6]; @@ -174,102 +165,24 @@ static void xmldoc_setpostbr(char *postbr, size_t len, const char *text) postbr[postbrlen] = '\0'; } -/*! - * \internal - * \brief Try to find a space or a break in text starting at currentpost - * and moving at most maxdiff positions. - * Helper for xmldoc_string_wrap(). - * - * \param text Input string where it will search. - * \param currentpos Current position within text. - * \param maxdiff Not move more than maxdiff inside text. - * - * \retval 1 if a space or break is found inside text while moving. - * \retval 0 if no space or break is found. - */ -static int xmldoc_wait_nextspace(const char *text, int currentpos, int maxdiff) -{ - int i, textlen; - - if (!text) { - return 0; - } - - textlen = strlen(text); - for (i = currentpos; i < textlen; i++) { - if (text[i] == ESC) { - /* Move to the end of the escape sequence */ - while (i < textlen && text[i] != 'm') { - i++; - } - } else if (text[i] == ' ' || text[i] == '\n') { - /* Found the next space or linefeed */ - return 1; - } else if (i - currentpos > maxdiff) { - /* We have looked the max distance and didn't find it */ - return 0; - } - } - - /* Reached the end and did not find it */ - - return 0; -} - -/*! - * \internal - * \brief Helper function for xmldoc_string_wrap(). - * Try to found a space or a break inside text moving backward - * not more than maxdiff positions. - * - * \param text The input string where to search for a space. - * \param currentpos The current cursor position. - * \param maxdiff The max number of positions to move within text. - * - * \retval 0 If no space is found (Notice that text[currentpos] is not a space or a break) - * \retval > 0 If a space or a break is found, and the result is the position relative to - * currentpos. - */ -static int xmldoc_foundspace_backward(const char *text, int currentpos, int maxdiff) -{ - int i; - - for (i = currentpos; i > 0; i--) { - if (text[i] == ' ' || text[i] == '\n') { - return (currentpos - i); - } else if (text[i] == 'm' && (text[i - 1] >= '0' || text[i - 1] <= '9')) { - /* give up, we found the end of a possible ESC sequence. */ - return 0; - } else if (currentpos - i > maxdiff) { - /* give up, we can't move anymore. */ - return 0; - } - } - - /* we found the beginning of the text */ - - return 0; -} - /*! * \internal * \brief Justify a text to a number of columns. * * \param text Input text to be justified. * \param columns Number of columns to preserve in the text. - * \param maxdiff Try to not cut a word when goinf down. * * \retval NULL on error. * \retval The wrapped text. */ -static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff) +static char *xmldoc_string_wrap(const char *text, int columns) { struct ast_str *tmp; char *ret, postbr[160]; - int count = 1, i, backspace, needtobreak = 0, colmax, textlen; + int count, i, textlen, postbrlen, lastbreak; /* sanity check */ - if (!text || columns <= 0 || maxdiff < 0) { + if (!text || columns <= 0) { ast_log(LOG_WARNING, "Passing wrong arguments while trying to wrap the text\n"); return NULL; } @@ -282,55 +195,44 @@ static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff) /* Check for blanks and tabs and put them in postbr. */ xmldoc_setpostbr(postbr, sizeof(postbr), text); - colmax = columns - xmldoc_postbrlen(postbr); + postbrlen = xmldoc_postbrlen(postbr); + + count = 0; + lastbreak = 0; textlen = strlen(text); for (i = 0; i < textlen; i++) { - if (needtobreak || !(count % colmax)) { - if (text[i] == ' ') { - ast_str_append(&tmp, 0, "\n%s", postbr); - needtobreak = 0; - count = 1; - } else if (text[i] != '\n') { - needtobreak = 1; - if (xmldoc_wait_nextspace(text, i, maxdiff)) { - /* wait for the next space */ - ast_str_append(&tmp, 0, "%c", text[i]); - continue; - } - /* Try to look backwards */ - backspace = xmldoc_foundspace_backward(text, i, maxdiff); - if (backspace) { - needtobreak = 1; - ast_str_truncate(tmp, -backspace); - i -= backspace + 1; - continue; - } - ast_str_append(&tmp, 0, "\n%s", postbr); - needtobreak = 0; - count = 1; - } - /* skip blanks after a \n */ - while (text[i] == ' ') { - i++; - } - } if (text[i] == '\n') { xmldoc_setpostbr(postbr, sizeof(postbr), &text[i] + 1); - colmax = columns - xmldoc_postbrlen(postbr); - needtobreak = 0; - count = 1; - } - if (text[i] == ESC) { - /* Ignore Escape sequences. */ + postbrlen = xmldoc_postbrlen(postbr); + count = 0; + lastbreak = 0; + } else if (text[i] == ESC) { + /* Walk over escape sequences without counting them. */ do { ast_str_append(&tmp, 0, "%c", text[i]); i++; } while (i < textlen && text[i] != 'm'); } else { + if (text[i] == ' ') { + lastbreak = i; + } count++; } - ast_str_append(&tmp, 0, "%c", text[i]); + + if (count > columns) { + /* Seek backwards if it was at most 30 characters ago. */ + int back = i - lastbreak; + if (lastbreak && back > 0 && back < 30) { + ast_str_truncate(tmp, -back); + i = lastbreak; /* go back a bit */ + } + ast_str_append(&tmp, 0, "\n%s", postbr); + count = postbrlen; + lastbreak = 0; + } else { + ast_str_append(&tmp, 0, "%c", text[i]); + } } ret = ast_strdup(ast_str_buffer(tmp)); @@ -442,7 +344,7 @@ char *ast_xmldoc_printable(const char *bwinput, int withcolors) } /* Wrap the text, notice that string wrap will avoid cutting an ESC sequence. */ - wrapped = xmldoc_string_wrap(ast_str_buffer(colorized), xmldoc_text_columns, xmldoc_max_diff); + wrapped = xmldoc_string_wrap(ast_str_buffer(colorized), xmldoc_text_columns); ast_free(colorized); From d82a4b098f41efe921b02440450e58320905360a Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 6 Nov 2015 13:19:11 -0700 Subject: [PATCH 0006/1578] dns: Use ntohl for ans->ttl in dns_parse_answer_ex dns_parse_answer_ex was not converting ans->ttl from network by order to host byte order which was causing certain ttls it to go negative. In turn this was causing answer edit checks to fail. ASTERISK-25528 #close Reported-by: Daniel Tryba Tested-by: George Joseph Change-Id: I31505132d6321c46d2f39fd06c20ee808a864037 --- main/dns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/dns.c b/main/dns.c index e1b7770bf57..c3b352d4159 100644 --- a/main/dns.c +++ b/main/dns.c @@ -475,7 +475,7 @@ static int dns_parse_answer_ex(void *context, int rr_class, int rr_type, unsigne /* Skip over the records that do not have the same resource record class and type we care about */ if (ntohs(ans->class) == rr_class && ntohs(ans->rtype) == rr_type) { /* Invoke the record handler callback to deliver the discovered record */ - record_handler(context, answer, ntohs(ans->size), ans->ttl); + record_handler(context, answer, ntohs(ans->size), ntohl(ans->ttl)); /*At least one record was found */ ret = AST_DNS_SEARCH_SUCCESS; } From 39daf9f066dcc3ccf582533cc26801448aefe7dd Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Fri, 6 Nov 2015 14:52:00 +0100 Subject: [PATCH 0007/1578] docs: Fix a few typo's in app docs (more then, resourse). Change-Id: Iba57efadf6c0b822e762c7a001bc89611d98afd7 --- apps/app_chanisavail.c | 6 +++--- apps/app_dial.c | 8 ++++---- apps/app_page.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c index 0c3b27bb3a2..dbd49914cf3 100644 --- a/apps/app_chanisavail.c +++ b/apps/app_chanisavail.c @@ -56,10 +56,10 @@ static const char app[] = "ChanIsAvail"; Optional extra devices to check - If you need more then one enter them as - Technology2/Resource2&Technology3/Resourse3&..... + If you need more than one enter them as + Technology2/Resource2&Technology3/Resource3&..... - Specification of the device(s) to check. These must be in the format of + Specification of the device(s) to check. These must be in the format of Technology/Resource, where Technology represents a particular channel driver, and Resource represents a resource available to that particular channel driver. diff --git a/apps/app_dial.c b/apps/app_dial.c index 55700e9b302..540f6621cfc 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -84,12 +84,12 @@ ASTERISK_REGISTER_FILE() Optional extra devices to dial in parallel - If you need more then one enter them as - Technology2/Resource2&Technology3/Resourse3&..... + If you need more than one enter them as + Technology2/Resource2&Technology3/Resource3&..... - Specifies the number of seconds we attempt to dial the specified devices + Specifies the number of seconds we attempt to dial the specified devices. If not specified, this defaults to 136 years. @@ -491,7 +491,7 @@ ASTERISK_REGISTER_FILE() Unless there is a timeout specified, the Dial application will wait indefinitely until one of the called channels answers, the user hangs up, or - if all of the called channels are busy or unavailable. Dialplan executing will + if all of the called channels are busy or unavailable. Dialplan execution will continue if no requested channels can be called, or if the timeout expires. This application will report normal termination if the originating channel hangs up, or if the call is bridged and either of the parties in the bridge diff --git a/apps/app_page.c b/apps/app_page.c index 10a96b61bed..3543d0509d0 100644 --- a/apps/app_page.c +++ b/apps/app_page.c @@ -60,7 +60,7 @@ ASTERISK_REGISTER_FILE() Optional extra devices to dial in parallel If you need more than one, enter them as Technology2/Resource2& - Technology3/Resourse3&..... + Technology3/Resource3&..... From 7dd8f89a507f1eeab6bfaaf6c29db40ad1228c49 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Fri, 6 Nov 2015 14:54:59 +0100 Subject: [PATCH 0008/1578] func_callerid: Document that CALLERID(pres) is available. CALLERPRES() says that it's deprecated in favor of CALLERID(num-pres) and CALLERID(name-pres). But for channel driver that don't make a distinction between the two (e.g. SIP), it makes more sense to get/set both at once. This change reveals the availability of CALLERID(pres), CONNECTEDLINE(pres), REDIRECTING(orig-pres), REDIRECTING(to-pres) and REDIRECTING(from-pres). ASTERISK-25373 #close Change-Id: I5614ae4ab7d3bbe9c791c1adf147e10de8698d7a --- CHANGES | 10 ++++++++++ funcs/func_callerid.c | 39 +++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 7d0b954a852..dcda33fe5bd 100644 --- a/CHANGES +++ b/CHANGES @@ -221,6 +221,16 @@ res_pjsip * The ability to use "like" has been added to the pjsip list and show CLI commands. For instance: CLI> pjsip list endpoints like abc +func_callerid +------------------- + * CALLERID(pres) is now documented as a valid alternative to setting both + CALLERID(name-pres) and CALLERID(num-pres) at once. Some channel drivers, + like chan_sip, don't make a distinction between the two: they take the + least public value from name-pres and num-pres. By using CALLERID(pres) + for reading and writing, you touch the same combined value in the dialplan. + The same applies to CONNECTEDLINE(pres), REDIRECTING(orig-pres), + REDIRECTING(to-pres) and REDIRECTING(from-pres). + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.5.0 to Asterisk 13.6.0 ------------ ------------------------------------------------------------------------------ diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c index 15993494901..dee1977f4a6 100644 --- a/funcs/func_callerid.c +++ b/funcs/func_callerid.c @@ -40,10 +40,11 @@ ASTERISK_REGISTER_FILE() #include "asterisk/callerid.h" /* - * Do not document the CALLERID(pres) datatype. - * The name and number now have their own presentation value. The pres - * option will simply live on as a historical relic with as best - * as can be managed backward compatible meaning. + * The CALLERID(pres) datatype is shorthand for getting/setting the + * combined value of name-pres and num-pres. Some channel drivers + * don't make a distinction, so it makes sense to only use one property + * to get/set it. The same applies to CONNECTEDLINE(pres), + * REDIRECTING(orig-pres), REDIRECTING(from-pres) and REDIRECTING(to-pres). * * Do not document the CALLERID(ton) datatype. * It is an alias for num-plan. @@ -55,11 +56,6 @@ ASTERISK_REGISTER_FILE() * It has turned out to not be needed. The source value is really * only useful as a possible tracing aid. * - * Do not document the CONNECTEDLINE(pres) datatype. - * The name and number now have their own presentation value. The pres - * option will simply live on as a historical relic with as best - * as can be managed backward compatible meaning. - * * Do not document the CONNECTEDLINE(ton) datatype. * It is an alias for num-plan. * @@ -69,12 +65,6 @@ ASTERISK_REGISTER_FILE() * they are active at the same time. The plain pres option will simply * live on as a historical relic. * - * Do not document the REDIRECTING(orig-pres), REDIRECTING(from-pres), - * or REDIRECTING(to-pres) datatypes. - * The name and number now have their own presentation value. The orig-pres, - * from-pres, and to-pres options will simply live on as a historical relic - * with as best as can be managed backward compatible meaning. - * * Do not document the REDIRECTING(orig-ton), REDIRECTING(from-ton), * or REDIRECTING(to-ton) datatypes. * They are aliases for orig-num-plan, from-num-plan, and to-num-plan @@ -98,6 +88,7 @@ ASTERISK_REGISTER_FILE() + @@ -144,6 +135,9 @@ ASTERISK_REGISTER_FILE() Gets or sets Caller*ID data on the channel. Uses channel callerid by default or optional callerid, if specified. + The pres field gets/sets a combined value + for name-pres and + num-pres. The allowable values for the name-charset field are the following: @@ -168,7 +162,8 @@ ASTERISK_REGISTER_FILE() Gets or sets Caller*ID presentation on the channel. This function is deprecated in favor of CALLERID(num-pres) - and CALLERID(name-pres). + and CALLERID(name-pres) or CALLERID(pres) to get/set both + at once. The following values are valid: @@ -218,6 +213,7 @@ ASTERISK_REGISTER_FILE() + @@ -246,6 +242,9 @@ ASTERISK_REGISTER_FILE() Gets or sets Connected Line data on the channel. + The pres field gets/sets a combined value + for name-pres and + num-pres. The allowable values for the name-charset field are the following: @@ -279,6 +278,7 @@ ASTERISK_REGISTER_FILE() + @@ -294,6 +294,7 @@ ASTERISK_REGISTER_FILE() + @@ -308,6 +309,7 @@ ASTERISK_REGISTER_FILE() + @@ -366,6 +368,11 @@ ASTERISK_REGISTER_FILE() Gets or sets Redirecting data on the channel. + The orig-pres, + from-pres and to-pres + fields get/set a combined value for the corresponding + ...-name-pres and ...-num-pres + fields. The allowable values for the reason and orig-reason fields are the following: From e85f0c81af56e48711468e820d6bcdbbb65c6310 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 9 Nov 2015 14:04:43 +0100 Subject: [PATCH 0009/1578] ast_format_cap: Avoid format creation on module load, use cache instead. Since Asterisk 13, formats are immutable and cached. However while loading a module like chan_sip, some formats were created instead using cached ones. ASTERISK-25535 #close Change-Id: I479cdc220d5617c840a98f3389b3bd91e91fbd9b --- main/format_cap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main/format_cap.c b/main/format_cap.c index d486d5d8cd2..2221c533992 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -230,7 +230,10 @@ int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_typ continue; } - format = ast_format_create(codec); + format = ast_format_cache_get(codec->name); + if (!format || (codec != ast_format_get_codec(format))) { + format = ast_format_create(codec); + } ao2_ref(codec, -1); if (!format) { From cf79b627789e2c6434419b71508a296c9ee90539 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 9 Nov 2015 10:01:41 +0100 Subject: [PATCH 0010/1578] ast_format_cap_get_names: To display all formats, the buffer was increased. ASTERISK-25533 #close Change-Id: Ie1a9d1a6511b3f1a56b93d04475fbf8a4e40010a --- addons/chan_mobile.c | 2 +- addons/chan_ooh323.c | 14 +++++------ apps/app_dumpchan.c | 2 +- bridges/bridge_native_rtp.c | 4 ++-- channels/chan_alsa.c | 2 +- channels/chan_console.c | 2 +- channels/chan_iax2.c | 44 +++++++++++++++++------------------ channels/chan_mgcp.c | 10 ++++---- channels/chan_motif.c | 2 +- channels/chan_nbs.c | 2 +- channels/chan_oss.c | 2 +- channels/chan_phone.c | 2 +- channels/chan_pjsip.c | 2 +- channels/chan_sip.c | 36 ++++++++++++++-------------- channels/chan_skinny.c | 12 +++++----- channels/chan_unistim.c | 18 +++++++------- channels/chan_vpb.cc | 2 +- funcs/func_channel.c | 4 ++-- include/asterisk/format_cap.h | 5 ++++ main/channel.c | 12 +++++----- main/cli.c | 2 +- main/file.c | 2 +- main/manager.c | 2 +- main/sorcery.c | 2 +- res/res_pjsip_sdp_rtp.c | 4 ++-- tests/test_config.c | 4 ++-- tests/test_format_cap.c | 2 +- 27 files changed, 101 insertions(+), 96 deletions(-) diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c index 26056f42092..64d53b70ddf 100644 --- a/addons/chan_mobile.c +++ b/addons/chan_mobile.c @@ -902,7 +902,7 @@ static struct ast_channel *mbl_request(const char *type, struct ast_format_cap * } if (ast_format_cap_iscompatible_format(cap, DEVICE_FRAME_FORMAT) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED; return NULL; diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index aa9cbaffa86..7e50bbfa596 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -576,7 +576,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_channel *chan = NULL; struct ooh323_pvt *p = NULL; struct ooh323_peer *peer = NULL; @@ -1192,7 +1192,7 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f) if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { if (ast_format_cap_count(ast_channel_nativeformats(ast))) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", ast_format_get_name(f->subclass.format), @@ -1545,7 +1545,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra return; } if (gH323Debug) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_verb(0, "Writeformat before update %s/%s\n", ast_format_get_name(ast_channel_writeformat(p->owner)), ast_format_cap_get_names(ast_channel_nativeformats(p->owner), &codec_buf)); @@ -2114,7 +2114,7 @@ int onNewCallCreated(ooCallData *call) } if (gH323Debug) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_verb(0, " Outgoing call %s(%s) - Codec prefs - %s\n", p->username?p->username:"NULL", call->callToken, @@ -3231,7 +3231,7 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ooh323_peer *prev = NULL, *peer = NULL; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); char ip_port[30]; #define FORMAT "%-15.15s %-15.15s %-23.23s %-s\n" @@ -3370,7 +3370,7 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ooh323_user *prev = NULL, *user = NULL; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); #define FORMAT1 "%-15.15s %-15.15s %-15.15s %-s\n" switch (cmd) { @@ -3504,7 +3504,7 @@ static char *handle_cli_ooh323_show_gk(struct ast_cli_entry *e, int cmd, struct static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { char value[FORMAT_STRING_SIZE]; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ooAliases *pAlias = NULL, *pAliasNext = NULL;; switch (cmd) { diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c index 93a65063cc7..8b32b93dc12 100644 --- a/apps/app_dumpchan.c +++ b/apps/app_dumpchan.c @@ -72,7 +72,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) { long elapsed_seconds = 0; int hour = 0, min = 0, sec = 0; - struct ast_str *format_buf = ast_str_alloca(64); + struct ast_str *format_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); char cgrp[256]; char pgrp[256]; struct ast_str *write_transpath = ast_str_alloca(256); diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 606a43a2db4..6c7c1cd5c59 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -387,8 +387,8 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge) glue1->get_codec(bc1->chan, cap1); } if (ast_format_cap_count(cap0) != 0 && ast_format_cap_count(cap1) != 0 && !ast_format_cap_iscompatible(cap0, cap1)) { - struct ast_str *codec_buf0 = ast_str_alloca(64); - struct ast_str *codec_buf1 = ast_str_alloca(64); + struct ast_str *codec_buf0 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *codec_buf1 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n", ast_format_cap_get_names(cap0, &codec_buf0), ast_format_cap_get_names(cap1, &codec_buf1)); return 0; diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 9441800db3c..0e2b2577fbe 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -620,7 +620,7 @@ static struct ast_channel *alsa_request(const char *type, struct ast_format_cap struct ast_channel *tmp = NULL; if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; } diff --git a/channels/chan_console.c b/channels/chan_console.c index a8dbc9751ac..9fdecd7d4ac 100644 --- a/channels/chan_console.c +++ b/channels/chan_console.c @@ -479,7 +479,7 @@ static struct ast_channel *console_request(const char *type, struct ast_format_c } if (!(ast_format_cap_iscompatible(cap, console_tech.capabilities))) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", ast_format_cap_get_names(cap, &cap_buf)); goto return_unref; diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index da6bec7afb5..dd1bc4ca6f4 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -3803,7 +3803,7 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct char status[30]; char cbuf[256]; struct iax2_peer *peer; - struct ast_str *codec_buf = ast_str_alloca(256); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_str *encmethods = ast_str_alloca(256); int load_realtime = 0; @@ -5576,8 +5576,8 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha return AST_BRIDGE_FAILED_NOWARN; } if (!(ast_format_cap_identical(ast_channel_nativeformats(c0), ast_channel_nativeformats(c1)))) { - struct ast_str *c0_buf = ast_str_alloca(64); - struct ast_str *c1_buf = ast_str_alloca(64); + struct ast_str *c0_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *c1_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n", ast_format_cap_get_names(ast_channel_nativeformats(c0), &c0_buf), @@ -10801,9 +10801,9 @@ static int socket_process_helper(struct iax2_thread *thread) break; } if (authdebug) { - struct ast_str *peer_buf = ast_str_alloca(64); - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *peer_form_buf = ast_str_alloca(64); + struct ast_str *peer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_form_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n", @@ -10848,9 +10848,9 @@ static int socket_process_helper(struct iax2_thread *thread) } if (!format) { - struct ast_str *peer_buf = ast_str_alloca(64); - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *peer_form_buf = ast_str_alloca(64); + struct ast_str *peer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_form_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); memset(&ied0, 0, sizeof(ied0)); iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec"); @@ -11028,8 +11028,8 @@ static int socket_process_helper(struct iax2_thread *thread) break; } if (authdebug) { - struct ast_str *peer_buf = ast_str_alloca(64); - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *peer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Rejected call to %s, format %s incompatible with our capability %s.\n", ast_sockaddr_stringify(&addr), @@ -11042,7 +11042,7 @@ static int socket_process_helper(struct iax2_thread *thread) ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); iax2_lock_owner(fr->callno); if (iaxs[fr->callno] && iaxs[fr->callno]->owner && native) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); /* Switch us to use a compatible format */ iax2_codec_pref_best_bitfield2cap( @@ -11246,9 +11246,9 @@ static int socket_process_helper(struct iax2_thread *thread) iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1); } if (!format) { - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *peer_buf = ast_str_alloca(64); - struct ast_str *peer_form_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_form_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) { ast_debug(1, "We don't do requested format %s, falling back to peer capability '%s'\n", @@ -11309,9 +11309,9 @@ static int socket_process_helper(struct iax2_thread *thread) } } if (!format) { - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *peer_buf = ast_str_alloca(64); - struct ast_str *peer_form_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_form_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_ERROR, "No best format in %s???\n", iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf)); @@ -11435,7 +11435,7 @@ static int socket_process_helper(struct iax2_thread *thread) break; } } else { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); ast_verb(3, "Accepting DIAL from %s, formats = %s\n", ast_sockaddr_stringify(&addr), @@ -12514,8 +12514,8 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap res = ast_translator_best_choice(cap, ast_channel_nativeformats(c), &best_fmt_cap, &best_fmt_native); if (res < 0) { - struct ast_str *native_cap_buf = ast_str_alloca(256); - struct ast_str *cap_buf = ast_str_alloca(256); + struct ast_str *native_cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n", ast_format_cap_get_names(ast_channel_nativeformats(c), &native_cap_buf), @@ -14374,7 +14374,7 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat } else if (!strcasecmp(colname, "callerid_num")) { ast_copy_string(buf, peer->cid_num, len); } else if (!strcasecmp(colname, "codecs")) { - struct ast_str *codec_buf = ast_str_alloca(256); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); iax2_getformatname_multiple(peer->capability, &codec_buf); ast_copy_string(buf, ast_str_buffer(codec_buf), len); diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 0210e8ab2c8..8714ddbbc71 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -1253,7 +1253,7 @@ static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame) } } else { if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", ast_format_get_name(frame->subclass.format), @@ -1986,9 +1986,9 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req) int codec, codec_count=0; int iterator; struct mgcp_endpoint *p = sub->parent; - struct ast_str *global_buf = ast_str_alloca(64); - struct ast_str *peer_buf = ast_str_alloca(64); - struct ast_str *pvt_buf = ast_str_alloca(64); + struct ast_str *global_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *pvt_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); /* Get codec and RTP info from SDP */ m = get_sdp(req, "m"); @@ -3971,7 +3971,7 @@ static struct ast_channel *mgcp_request(const char *type, struct ast_format_cap char tmp[256]; if (!(ast_format_cap_iscompatible(cap, global_capability))) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &cap_buf)); /*return NULL;*/ diff --git a/channels/chan_motif.c b/channels/chan_motif.c index 0851bf01a7c..15a7b4d6d7e 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -1702,7 +1702,7 @@ static int jingle_write(struct ast_channel *ast, struct ast_frame *frame) switch (frame->frametype) { case AST_FRAME_VOICE: if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c index c23eecdc95b..d50defeaf91 100644 --- a/channels/chan_nbs.c +++ b/channels/chan_nbs.c @@ -232,7 +232,7 @@ static struct ast_channel *nbs_request(const char *type, struct ast_format_cap * struct ast_channel *tmp = NULL; if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &cap_buf)); diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 0eb777a75e3..94de58da001 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -863,7 +863,7 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap * return NULL; } if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; } diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 6d790fefdb3..b7f694f815b 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -1282,7 +1282,7 @@ static struct ast_channel *phone_request(const char *type, struct ast_format_cap restart_monitor(); if (tmp == NULL) { if (!(ast_format_cap_iscompatible(cap, phone_tech.capabilities))) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index d72a25b615f..c98be356543 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -673,7 +673,7 @@ static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame) return 0; } if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *cap_buf = ast_str_alloca(128); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 0fd9f7d1895..5a88bb4a35c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -7213,7 +7213,7 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) switch (frame->frametype) { case AST_FRAME_VOICE: if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s read/write = %s/%s\n", ast_format_get_name(frame->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf), @@ -7850,7 +7850,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit struct ast_variable *v = NULL; struct ast_format *fmt; struct ast_format_cap *what = NULL; /* SHALLOW COPY DO NOT DESTROY! */ - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); int needvideo = 0; int needtext = 0; char *exten; @@ -9911,7 +9911,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action int debug = sip_debug_test_pvt(p); /* START UNKNOWN */ - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_format *tmp_fmt; /* END UNKNOWN */ @@ -10570,11 +10570,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action if (debug) { /* shame on whoever coded this.... */ - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *peer_buf = ast_str_alloca(64); - struct ast_str *vpeer_buf = ast_str_alloca(64); - struct ast_str *tpeer_buf = ast_str_alloca(64); - struct ast_str *joint_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *peer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *vpeer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *tpeer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *joint_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s/text=%s, combined - %s\n", ast_format_cap_get_names(p->caps, &cap_buf), @@ -10781,8 +10781,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action unsigned int framing; if (debug) { - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *joint_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *joint_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_debug(1, "Setting native formats after processing SDP. peer joint formats %s, old nativeformats %s\n", ast_format_cap_get_names(p->jointcaps, &joint_buf), @@ -13116,7 +13116,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int int min_video_packet_size = 0; int min_text_packet_size = 0; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); /* Set the SDP session name */ snprintf(subject, sizeof(subject), "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession); @@ -20298,7 +20298,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct char status[30] = ""; char cbuf[256]; struct sip_peer *peer; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_variable *v; int x = 0, load_realtime; int realtimepeers; @@ -20944,7 +20944,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ { int realtimepeers; int realtimeregs; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); const char *msg; /* temporary msg pointer */ struct sip_auth_container *credentials; @@ -21265,7 +21265,7 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) if (cur->subscribed == NONE && !arg->subscriptions) { /* set if SIP transfer in progress */ const char *referstatus = cur->refer ? referstatus2str(cur->refer->status) : ""; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_cli(arg->fd, FORMAT, ast_sockaddr_stringify_addr(dst), S_OR(cur->username, S_OR(cur->cid_num, "(None)")), @@ -21511,7 +21511,7 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a if (!strncasecmp(cur->callid, a->argv[3], len)) { struct ast_str *strbuf; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_cli(a->fd, "\n"); if (cur->subscribed != NONE) { @@ -22470,7 +22470,7 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat } else if (!strcasecmp(colname, "callerid_num")) { ast_copy_string(buf, peer->cid_num, len); } else if (!strcasecmp(colname, "codecs")) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_format_cap_get_names(peer->caps, &codec_buf); ast_copy_string(buf, ast_str_buffer(codec_buf), len); } else if (!strcasecmp(colname, "encryption")) { @@ -29614,8 +29614,8 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ struct ast_channel *tmpc = NULL; char *ext = NULL, *host; char tmp[256]; - struct ast_str *codec_buf = ast_str_alloca(64); - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); char *dnid; char *secret = NULL; char *md5secret = NULL; diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 6e59e016223..6f56f732e7b 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -4176,7 +4176,7 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s struct skinny_speeddial *sd; struct skinny_addon *sa; struct skinny_serviceurl *surl; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); if (argc < 4) { return CLI_SHOWUSAGE; @@ -4425,7 +4425,7 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str struct skinny_device *d; struct skinny_line *l; struct skinny_subline *subline; - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); char group_buf[256]; char cbuf[256]; @@ -5075,7 +5075,7 @@ static int skinny_write(struct ast_channel *ast, struct ast_frame *frame) } } else { if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", ast_format_get_name(frame->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf), @@ -5351,7 +5351,7 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli struct ast_format *tmpfmt; struct ast_format_cap *caps; #ifdef AST_DEVMODE - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); #endif if (!l->device || !l->device->session) { @@ -6638,7 +6638,7 @@ static int handle_capabilities_res_message(struct skinny_req *req, struct skinny struct ast_format_cap *codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); int i; #ifdef AST_DEVMODE - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); #endif @@ -7681,7 +7681,7 @@ static struct ast_channel *skinny_request(const char *type, struct ast_format_ca char tmp[256]; if (!(ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO))) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; } diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 874f6b2dccc..c96a9c087cd 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -2890,7 +2890,7 @@ static void start_rtp(struct unistim_subchannel *sub) ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp); if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner)) == AST_FORMAT_CMP_NOT_EQUAL) { struct ast_format *tmpfmt; - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(sub->owner), 0); ast_log(LOG_WARNING, @@ -5143,7 +5143,7 @@ static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast, /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_format_cap *caps; ast_debug(1, @@ -5193,7 +5193,7 @@ static int unistim_write(struct ast_channel *ast, struct ast_frame *frame) } } else { if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n", @@ -5724,9 +5724,9 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0); if (unistimdebug) { - struct ast_str *native_buf = ast_str_alloca(64); - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *global_buf = ast_str_alloca(64); + struct ast_str *native_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *global_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n", ast_format_get_name(tmpfmt), @@ -5939,8 +5939,8 @@ static struct ast_channel *unistim_request(const char *type, struct ast_format_c char tmp[256]; if (!(ast_format_cap_iscompatible(cap, global_cap))) { - struct ast_str *cap_buf = ast_str_alloca(64); - struct ast_str *global_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *global_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format %s while capability is %s\n", ast_format_cap_get_names(cap, &cap_buf), @@ -6015,7 +6015,7 @@ static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_ struct unistim_line *line; struct unistim_subchannel *sub; struct unistimsession *s; - struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); switch (cmd) { case CLI_INIT: diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index 7cdcf303a35..1f4b861c153 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -2510,7 +2510,7 @@ static struct ast_channel *vpb_request(const char *type, struct ast_format_cap * if (!(ast_format_cap_iscompatible_format(cap, ast_format_slin))) { struct ast_str *buf; - buf = ast_str_create(256); + buf = ast_str_create(AST_FORMAT_CAP_NAMES_LEN); if (!buf) { return NULL; } diff --git a/funcs/func_channel.c b/funcs/func_channel.c index b051d892450..afe9796f6d0 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -446,7 +446,7 @@ static int func_channel_read(struct ast_channel *chan, const char *function, if (!strcasecmp(data, "audionativeformat")) { tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (tmpcap) { - struct ast_str *codec_buf = ast_str_alloca(128); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_channel_lock(chan); ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_AUDIO); @@ -457,7 +457,7 @@ static int func_channel_read(struct ast_channel *chan, const char *function, } else if (!strcasecmp(data, "videonativeformat")) { tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (tmpcap) { - struct ast_str *codec_buf = ast_str_alloca(128); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_channel_lock(chan); ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO); diff --git a/include/asterisk/format_cap.h b/include/asterisk/format_cap.h index e422cc60905..8b69e08b196 100644 --- a/include/asterisk/format_cap.h +++ b/include/asterisk/format_cap.h @@ -310,6 +310,11 @@ int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_typ */ const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf); +#ifndef AST_FORMAT_CAP_NAMES_LEN +/*! Buffer size for callers of ast_format_cap_get_names to allocate. */ +#define AST_FORMAT_CAP_NAMES_LEN 384 +#endif + /*! * \brief Determine if a format cap has no formats in it. * diff --git a/main/channel.c b/main/channel.c index 3e2636f5a72..013d2e281fb 100644 --- a/main/channel.c +++ b/main/channel.c @@ -340,7 +340,7 @@ static char *complete_channeltypes(struct ast_cli_args *a) static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct chanlist *cl = NULL; - struct ast_str *codec_buf = ast_str_alloca(256); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); switch (cmd) { case CLI_INIT: @@ -5094,7 +5094,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) f = fr; } else { if (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL) { - struct ast_str *codec_buf = ast_str_alloca(256); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); /* * We are not setup to write this frame. Things may have changed @@ -5435,8 +5435,8 @@ static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, res = ast_translator_best_choice(cap_native, cap_set, &best_native_fmt, &best_set_fmt); } if (res < 0) { - struct ast_str *codec_native = ast_str_alloca(256); - struct ast_str *codec_set = ast_str_alloca(256); + struct ast_str *codec_native = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *codec_set = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_format_cap_get_names(cap_native, &codec_native); ast_channel_unlock(chan); @@ -5978,8 +5978,8 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request res = ast_translator_best_choice(tmp_cap, chan->tech->capabilities, &tmp_fmt, &best_audio_fmt); ao2_ref(tmp_cap, -1); if (res < 0) { - struct ast_str *tech_codecs = ast_str_alloca(64); - struct ast_str *request_codecs = ast_str_alloca(64); + struct ast_str *tech_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *request_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type, ast_format_cap_get_names(chan->tech->capabilities, &tech_codecs), diff --git a/main/cli.c b/main/cli.c index e59a856d47f..b3d4cac3dcd 100644 --- a/main/cli.c +++ b/main/cli.c @@ -1528,7 +1528,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar struct ast_var_t *var; struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_bridge *bridge; ast_callid callid; char callid_buf[32]; diff --git a/main/file.c b/main/file.c index bfad6e025ff..f0f826a4ff9 100644 --- a/main/file.c +++ b/main/file.c @@ -1091,7 +1091,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p fs = ast_openstream(chan, filename, preflang); if (!fs) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), strerror(errno)); return -1; diff --git a/main/manager.c b/main/manager.c index 6e9ae00104d..d6aadf4ecaa 100644 --- a/main/manager.c +++ b/main/manager.c @@ -4343,7 +4343,7 @@ static void generate_status(struct mansession *s, struct ast_channel *chan, char RAII_VAR(struct ast_str *, variable_str, NULL, ast_free); struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); - struct ast_str *codec_buf = ast_str_alloca(128); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_party_id effective_id; int i; RAII_VAR(struct ast_channel_snapshot *, snapshot, diff --git a/main/sorcery.c b/main/sorcery.c index f9f7c387333..b751b9f0954 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -307,7 +307,7 @@ static int chararray_handler_fn(const void *obj, const intptr_t *args, char **bu static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf) { - struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_format_cap **cap = (struct ast_format_cap **)(obj + args[0]); return !(*buf = ast_strdup(ast_format_cap_get_names(*cap, &codec_buf))); } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a66aebb3643..7c1e604e536 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -323,8 +323,8 @@ static int set_caps(struct ast_sip_session *session, /* get the joint capabilities between peer and endpoint */ ast_format_cap_get_compatible(caps, peer, joint); if (!ast_format_cap_count(joint)) { - struct ast_str *usbuf = ast_str_alloca(256); - struct ast_str *thembuf = ast_str_alloca(256); + struct ast_str *usbuf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *thembuf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_rtp_codecs_payloads_destroy(&codecs); ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n", diff --git a/tests/test_config.c b/tests/test_config.c index 12c75bfc6d6..bbfec0df2af 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -1492,8 +1492,8 @@ AST_TEST_DEFINE(config_options_test) res = AST_TEST_FAIL; } if (!ast_format_cap_identical(arr[x]->codeccapopt, control->codeccapopt)) { - struct ast_str *codec_buf1 = ast_str_alloca(64); - struct ast_str *codec_buf2 = ast_str_alloca(64); + struct ast_str *codec_buf1 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *codec_buf2 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); ast_test_status_update(test, "format did not match: '%s' vs '%s' on loop %d\n", ast_format_cap_get_names(arr[x]->codeccapopt, &codec_buf1), diff --git a/tests/test_format_cap.c b/tests/test_format_cap.c index 4d810bf85eb..b62f6e5d8be 100644 --- a/tests/test_format_cap.c +++ b/tests/test_format_cap.c @@ -1079,7 +1079,7 @@ AST_TEST_DEFINE(format_cap_get_names) RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); - struct ast_str *buffer = ast_str_alloca(128); + struct ast_str *buffer = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); switch (cmd) { case TEST_INIT: From 02a124eda58808fc50418cbb2217772e47e440e4 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 10 Nov 2015 08:51:39 -0500 Subject: [PATCH 0011/1578] Remove execute permission from dns_system_resolver.c Change-Id: I3185735db42064bab00d3e073aed703385a00bf4 --- main/dns_system_resolver.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 main/dns_system_resolver.c diff --git a/main/dns_system_resolver.c b/main/dns_system_resolver.c old mode 100755 new mode 100644 From be93036a4e224e2b9a19c9bdcfb6ac34a1534b31 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 9 Nov 2015 19:19:04 -0500 Subject: [PATCH 0012/1578] Remove ABI compatibility stub functions. ABI compatibility stubs existed for ast_app_separate_args and ast_verbose, this is not needed in master. Change-Id: I07b4d2c16079da3c2c6efa55df4a74368e0bd453 --- main/app.c | 9 --------- main/logger.c | 15 --------------- 2 files changed, 24 deletions(-) diff --git a/main/app.c b/main/app.c index 2046ac8a02a..dabf15d3777 100644 --- a/main/app.c +++ b/main/app.c @@ -2098,9 +2098,6 @@ int ast_app_group_list_unlock(void) return AST_RWLIST_UNLOCK(&groups); } -#undef ast_app_separate_args -unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen); - unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, char **array, int arraylen) { int argc; @@ -2165,12 +2162,6 @@ unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, ch return argc; } -/* ABI compatible function */ -unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen) -{ - return __ast_app_separate_args(buf, delim, 1, array, arraylen); -} - static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path) { char *s; diff --git a/main/logger.c b/main/logger.c index a5925e4c02b..73b8ee1a257 100644 --- a/main/logger.c +++ b/main/logger.c @@ -2144,21 +2144,6 @@ void __ast_verbose_callid(const char *file, int line, const char *func, int leve va_end(ap); } -/* No new code should use this directly, but we have the ABI for backwards compat */ -#undef ast_verbose -void __attribute__((format(printf, 1,2))) ast_verbose(const char *fmt, ...); -void ast_verbose(const char *fmt, ...) -{ - ast_callid callid; - va_list ap; - - callid = ast_read_threadstorage_callid(); - - va_start(ap, fmt); - __ast_verbose_ap("", 0, "", 0, callid, fmt, ap); - va_end(ap); -} - /*! Console verbosity level node. */ struct verb_console { /*! List node link */ From 525c7ab780b5d05ffd9196e9abcf4d3245f64f51 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 10 Nov 2015 16:24:31 +0100 Subject: [PATCH 0013/1578] rtp_engine: Init a format-attribute module to its RFC defaults. Previously, format-attribute modules relied on an existing fmtp line in SDP negotiation. However, fmtp is optional for several formats like the Opus Codec. Now, the format-attribute module is called with an empty fmtp, which allows the module to initialise itself to RFC defaults. Furthermore now, Asterisk is able to differentiate between internally and externally created formats. ASTERISK-25537 #close Change-Id: I28f680cef7fdf51c0969ff8da71548edad72ec52 --- main/rtp_engine.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 1460a7ac8c9..32909090f66 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -973,9 +973,13 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, if (t->payload_type.asterisk_format && ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL && (options & AST_RTP_OPT_G726_NONSTANDARD)) { - new_type->format = ao2_bump(ast_format_g726_aal2); + new_type->format = ast_format_g726_aal2; } else { - new_type->format = ao2_bump(t->payload_type.format); + new_type->format = t->payload_type.format; + } + if (new_type->format) { + /* SDP parsing automatically increases the reference count */ + new_type->format = ast_format_parse_sdp_fmtp(new_type->format, ""); } if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { From 2954354404e915aa4d20f1ee400c8a3a835fac7b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 11 Nov 2015 13:04:08 -0400 Subject: [PATCH 0014/1578] threadpool: Handle worker thread transitioning to dead when going active. This change adds handling of dead worker threads when moving them to be active. When this happens the worker thread is removed from both the active and idle threads container. If no threads are able to be moved to active then the pool grows as configured. A unit test has also been added which thrashes the idle timeout and thread activation to exploit any race conditions between the two. ASTERISK-25546 #close Change-Id: I6c455f9a40de60d9e86458d447b548fb52ba1143 --- main/threadpool.c | 67 +++++++++++++++++++++++++++++---- tests/test_threadpool.c | 83 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/main/threadpool.c b/main/threadpool.c index d97a7adb800..46de9b7f805 100644 --- a/main/threadpool.c +++ b/main/threadpool.c @@ -168,7 +168,7 @@ static void *worker_start(void *arg); static struct worker_thread *worker_thread_alloc(struct ast_threadpool *pool); static int worker_thread_start(struct worker_thread *worker); static int worker_idle(struct worker_thread *worker); -static void worker_set_state(struct worker_thread *worker, enum worker_state state); +static int worker_set_state(struct worker_thread *worker, enum worker_state state); static void worker_shutdown(struct worker_thread *worker); /*! @@ -482,7 +482,16 @@ static int activate_thread(void *obj, void *arg, int flags) worker->id); return 0; } - worker_set_state(worker, ALIVE); + + if (worker_set_state(worker, ALIVE)) { + ast_debug(1, "Failed to activate thread %d. It is dead\n", + worker->id); + /* The worker thread will no longer exist in the active threads or + * idle threads container after this. + */ + ao2_unlink(pool->active_threads, worker); + } + return CMP_MATCH; } @@ -538,20 +547,33 @@ static int queued_task_pushed(void *data) struct task_pushed_data *tpd = data; struct ast_threadpool *pool = tpd->pool; int was_empty = tpd->was_empty; + unsigned int existing_active; if (pool->listener && pool->listener->callbacks->task_pushed) { pool->listener->callbacks->task_pushed(pool, pool->listener, was_empty); } - if (ao2_container_count(pool->idle_threads) == 0) { + + existing_active = ao2_container_count(pool->active_threads); + + /* The first pass transitions any existing idle threads to be active, and + * will also remove any worker threads that have recently entered the dead + * state. + */ + ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA, + activate_thread, pool); + + /* If no idle threads could be transitioned to active grow the pool as permitted. */ + if (ao2_container_count(pool->active_threads) == existing_active) { if (!pool->options.auto_increment) { + ao2_ref(tpd, -1); return 0; } grow(pool, pool->options.auto_increment); + /* An optional second pass transitions any newly added threads. */ + ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA, + activate_thread, pool); } - ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA, - activate_thread, pool); - threadpool_send_state_changed(pool); ao2_ref(tpd, -1); return 0; @@ -797,7 +819,7 @@ static int queued_set_size(void *data) /* We don't count zombie threads as being "live" when potentially resizing */ unsigned int current_size = ao2_container_count(pool->active_threads) + - ao2_container_count(pool->idle_threads); + ao2_container_count(pool->idle_threads); if (current_size == num_threads) { ast_debug(3, "Not changing threadpool size since new size %u is the same as current %u\n", @@ -806,6 +828,12 @@ static int queued_set_size(void *data) } if (current_size < num_threads) { + ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE, + activate_thread, pool); + + /* As the above may have altered the number of current threads update it */ + current_size = ao2_container_count(pool->active_threads) + + ao2_container_count(pool->idle_threads); grow(pool, num_threads - current_size); ao2_callback(pool->idle_threads, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE, activate_thread, pool); @@ -1117,13 +1145,36 @@ static int worker_idle(struct worker_thread *worker) * * The threadpool calls into this function in order to let a worker know * how it should proceed. + * + * \retval -1 failure (state transition not permitted) + * \retval 0 success */ -static void worker_set_state(struct worker_thread *worker, enum worker_state state) +static int worker_set_state(struct worker_thread *worker, enum worker_state state) { SCOPED_MUTEX(lock, &worker->lock); + + switch (state) { + case ALIVE: + /* This can occur due to a race condition between being told to go active + * and an idle timeout happening. + */ + if (worker->state == DEAD) { + return -1; + } + ast_assert(worker->state != ZOMBIE); + break; + case DEAD: + break; + case ZOMBIE: + ast_assert(worker->state != DEAD); + break; + } + worker->state = state; worker->wake_up = 1; ast_cond_signal(&worker->cond); + + return 0; } /*! Serializer group shutdown control object. */ diff --git a/tests/test_threadpool.c b/tests/test_threadpool.c index f5b1073dee5..42181a25cc9 100644 --- a/tests/test_threadpool.c +++ b/tests/test_threadpool.c @@ -571,6 +571,87 @@ AST_TEST_DEFINE(threadpool_thread_timeout) return res; } +AST_TEST_DEFINE(threadpool_thread_timeout_thrash) +{ + struct ast_threadpool *pool = NULL; + struct ast_threadpool_listener *listener = NULL; + enum ast_test_result_state res = AST_TEST_FAIL; + struct test_listener_data *tld = NULL; + struct ast_threadpool_options options = { + .version = AST_THREADPOOL_OPTIONS_VERSION, + .idle_timeout = 1, + .auto_increment = 1, + .initial_size = 0, + .max_size = 1, + }; + int iteration; + + switch (cmd) { + case TEST_INIT: + info->name = "thread_timeout_thrash"; + info->category = "/main/threadpool/"; + info->summary = "Thrash threadpool thread timeout"; + info->description = + "Repeatedly queue a task when a threadpool thread should timeout."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + tld = test_alloc(); + if (!tld) { + return AST_TEST_FAIL; + } + + listener = ast_threadpool_listener_alloc(&test_callbacks, tld); + if (!listener) { + goto end; + } + + pool = ast_threadpool_create(info->name, listener, &options); + if (!pool) { + goto end; + } + + ast_threadpool_set_size(pool, 1); + + for (iteration = 0; iteration < 30; ++iteration) { + struct simple_task_data *std = NULL; + struct timeval start = ast_tvnow(); + struct timespec end = { + .tv_sec = start.tv_sec + options.idle_timeout, + .tv_nsec = start.tv_usec * 1000 + }; + + std = simple_task_data_alloc(); + if (!std) { + goto end; + } + + /* Wait until the threadpool thread should timeout due to being idle */ + ast_mutex_lock(&tld->lock); + while (ast_cond_timedwait(&tld->cond, &tld->lock, &end) != ETIMEDOUT) { + /* This purposely left empty as we want to loop waiting for a time out */ + } + ast_mutex_unlock(&tld->lock); + + ast_threadpool_push(pool, simple_task, std); + } + + res = wait_until_thread_state(test, tld, 0, 0); + if (res == AST_TEST_FAIL) { + goto end; + } + + res = listener_check(test, listener, 1, 1, 30, 0, 0, 1); + +end: + ast_threadpool_shutdown(pool); + ao2_cleanup(listener); + ast_free(tld); + return res; +} + AST_TEST_DEFINE(threadpool_one_task_one_thread) { struct ast_threadpool *pool = NULL; @@ -1610,6 +1691,7 @@ static int unload_module(void) ast_test_unregister(threadpool_thread_creation); ast_test_unregister(threadpool_thread_destruction); ast_test_unregister(threadpool_thread_timeout); + ast_test_unregister(threadpool_thread_timeout_thrash); ast_test_unregister(threadpool_one_task_one_thread); ast_test_unregister(threadpool_one_thread_one_task); ast_test_unregister(threadpool_one_thread_multiple_tasks); @@ -1630,6 +1712,7 @@ static int load_module(void) ast_test_register(threadpool_thread_creation); ast_test_register(threadpool_thread_destruction); ast_test_register(threadpool_thread_timeout); + ast_test_register(threadpool_thread_timeout_thrash); ast_test_register(threadpool_one_task_one_thread); ast_test_register(threadpool_one_thread_one_task); ast_test_register(threadpool_one_thread_multiple_tasks); From d982b99e71abd84cb668dfee23021422ffceed9a Mon Sep 17 00:00:00 2001 From: Steve Davies Date: Wed, 11 Nov 2015 10:16:22 +0000 Subject: [PATCH 0015/1578] Further fixes to improper usage of scheduler When ASTERISK-25449 was closed, a number of scheduler issues mentioned in the comments were missed. These have since beed raised in ASTERISK-25476 and elsewhere. This patch attempts to collect all of the scheduler issues discovered so far and address them sensibly. ASTERISK-25476 #close Change-Id: I87a77d581e2e0d91d33b4b2fbff80f64a566d05b --- channels/chan_iax2.c | 6 +++--- channels/chan_sip.c | 18 ++++++++++++------ res/res_rtp_asterisk.c | 4 ++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index dd1bc4ca6f4..42ccbd5fdb9 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -7101,7 +7101,7 @@ static char *handle_cli_iax2_unregister(struct ast_cli_entry *e, int cmd, struct p = find_peer(a->argv[2], 1); if (p) { - if (p->expire > 0) { + if (p->expire > -1) { struct iax2_peer *peer; peer = ao2_find(peers, a->argv[2], OBJ_KEY); @@ -7133,8 +7133,8 @@ static char *complete_iax2_unregister(const char *line, const char *word, int po if (pos == 2) { struct ao2_iterator i = ao2_iterator_init(peers, 0); while ((p = ao2_iterator_next(&i))) { - if (!strncasecmp(p->name, word, wordlen) && - ++which > state && p->expire > 0) { + if (!strncasecmp(p->name, word, wordlen) && + ++which > state && p->expire > -1) { res = ast_strdup(p->name); peer_unref(p); break; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 5a88bb4a35c..158dc7b1818 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -20829,7 +20829,7 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg return CLI_SHOWUSAGE; if ((peer = sip_find_peer(a->argv[2], NULL, load_realtime, FINDPEERS, TRUE, 0))) { - if (peer->expire > 0) { + if (peer->expire > -1) { AST_SCHED_DEL_UNREF(sched, peer->expire, sip_unref_peer(peer, "remove register expire ref")); expire_register(sip_ref_peer(peer, "ref for expire_register")); @@ -21412,7 +21412,7 @@ static char *complete_sip_registered_peer(const char *word, int state, int flags while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) { if (!strncasecmp(word, peer->name, wordlen) && (!flags2 || ast_test_flag(&peer->flags[1], flags2)) && - ++which > state && peer->expire > 0) + ++which > state && peer->expire > -1) result = ast_strdup(peer->name); if (result) { sip_unref_peer(peer, "toss iterator peer ptr before break"); @@ -30257,13 +30257,11 @@ static struct ast_variable *add_var(const char *buf, struct ast_variable *list) /*! \brief Set peer defaults before configuring specific configurations */ static void set_peer_defaults(struct sip_peer *peer) { - if (peer->expire == 0) { + if (peer->expire < 0) { /* Don't reset expire or port time during reload if we have an active registration */ - peer->expire = -1; - peer->pokeexpire = -1; - peer->keepalivesend = -1; + peer_sched_cleanup(peer); set_socket_transport(&peer->socket, AST_TRANSPORT_UDP); } peer->type = SIP_TYPE_PEER; @@ -30348,6 +30346,10 @@ static struct sip_peer *temp_peer(const char *name) } ast_atomic_fetchadd_int(&apeerobjs, 1); + peer->expire = -1; + peer->pokeexpire = -1; + peer->keepalivesend = -1; + set_peer_defaults(peer); ast_copy_string(peer->name, name, sizeof(peer->name)); @@ -30468,6 +30470,10 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str ast_debug(3, "-REALTIME- peer built. Name: %s. Peer objects: %d\n", name, rpeerobjs); } else ast_atomic_fetchadd_int(&speerobjs, 1); + + peer->expire = -1; + peer->pokeexpire = -1; + peer->keepalivesend = -1; } /* Note that our peer HAS had its reference count increased */ diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 8cd542767a9..ac83d734be3 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4779,7 +4779,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro return; } else { if (rtp->rtcp) { - if (rtp->rtcp->schedid > 0) { + if (rtp->rtcp->schedid > -1) { if (!ast_sched_del(rtp->sched, rtp->rtcp->schedid)) { /* Successfully cancelled scheduler entry. */ ao2_ref(instance, -1); @@ -4996,7 +4996,7 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance) } #endif - if (rtp->rtcp && rtp->rtcp->schedid > 0) { + if (rtp->rtcp && rtp->rtcp->schedid > -1) { if (!ast_sched_del(rtp->sched, rtp->rtcp->schedid)) { /* successfully cancelled scheduler entry. */ ao2_ref(instance, -1); From a159747660932ff442ba737a8addd3268b835147 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 12 Nov 2015 08:24:06 -0400 Subject: [PATCH 0016/1578] format_cap: Don't append the 'none' format when appending all. When appending all formats of a type all the codecs are iterated and added. This operation was incorrectly adding the ast_format_none format which is special in that it is supposed to be used when no format is present. It shouldn't be appended. ASTERISK-25535 Change-Id: I7b00f3bdf4a5f3022e483d6ece602b1e8b12827c --- main/format_cap.c | 8 ++++++++ tests/test_format_cap.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/main/format_cap.c b/main/format_cap.c index 2221c533992..9e16aa3e131 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -231,7 +231,15 @@ int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_typ } format = ast_format_cache_get(codec->name); + + if (format == ast_format_none) { + ao2_ref(format, -1); + ao2_ref(codec, -1); + continue; + } + if (!format || (codec != ast_format_get_codec(format))) { + ao2_cleanup(format); format = ast_format_create(codec); } ao2_ref(codec, -1); diff --git a/tests/test_format_cap.c b/tests/test_format_cap.c index b62f6e5d8be..1f02c29cd36 100644 --- a/tests/test_format_cap.c +++ b/tests/test_format_cap.c @@ -245,7 +245,7 @@ AST_TEST_DEFINE(format_cap_append_all_unknown) } else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_VIDEO)) { ast_test_status_update(test, "Added all media formats but no video formats exist when they should\n"); return AST_TEST_FAIL; - } else if ((ast_format_cap_count(caps) + 1) != ast_codec_get_max()) { + } else if ((ast_format_cap_count(caps) + 1) != (ast_codec_get_max() - 1)) { ast_test_status_update(test, "The number of formats in the capabilities structure does not match known number\n"); return AST_TEST_FAIL; } From 264c74aa22aca7dffdf054ca1512a3638f3fc6dc Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 11 Nov 2015 17:11:53 -0600 Subject: [PATCH 0017/1578] res_pjsip: Deny requests when threadpool queue is backed up. We have observed situations where the SIP threadpool may become deadlocked. However, because incoming traffic is still arriving, the SIP threadpool's queue can continue to grow, eventually running the system out of memory. This change makes it so that incoming traffic gets rejected with a 503 response if the queue is backed up too much. Change-Id: I4e736d48a2ba79fd1f8056c0dcd330e38e6a3816 --- include/asterisk/res_pjsip.h | 6 ++++++ include/asterisk/taskprocessor.h | 6 ++++++ include/asterisk/threadpool.h | 6 ++++++ main/taskprocessor.c | 9 +++------ main/threadpool.c | 5 +++++ res/res_pjsip.c | 5 +++++ res/res_pjsip/pjsip_distributor.c | 14 +++++++++++++- 7 files changed, 44 insertions(+), 7 deletions(-) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index f159a572e26..95b8f23eb92 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2104,4 +2104,10 @@ int ast_sip_get_host_ip(int af, pj_sockaddr *addr); */ const char *ast_sip_get_host_ip_string(int af); +/*! + * \brief Return the size of the SIP threadpool's task queue + * \since 13.7.0 + */ +long ast_sip_threadpool_queue_size(void); + #endif /* _RES_PJSIP_H */ diff --git a/include/asterisk/taskprocessor.h b/include/asterisk/taskprocessor.h index f16f144cb55..06368867a8f 100644 --- a/include/asterisk/taskprocessor.h +++ b/include/asterisk/taskprocessor.h @@ -262,4 +262,10 @@ int ast_taskprocessor_is_task(struct ast_taskprocessor *tps); */ const char *ast_taskprocessor_name(struct ast_taskprocessor *tps); +/*! + * \brief Return the current size of the taskprocessor queue + * \since 13.7.0 + */ +long ast_taskprocessor_size(struct ast_taskprocessor *tps); + #endif /* __AST_TASKPROCESSOR_H__ */ diff --git a/include/asterisk/threadpool.h b/include/asterisk/threadpool.h index 75ce0e4e4ef..0f360c7a4a4 100644 --- a/include/asterisk/threadpool.h +++ b/include/asterisk/threadpool.h @@ -292,4 +292,10 @@ struct ast_taskprocessor *ast_threadpool_serializer(const char *name, struct ast struct ast_taskprocessor *ast_threadpool_serializer_group(const char *name, struct ast_threadpool *pool, struct ast_serializer_shutdown_group *shutdown_group); +/*! + * \brief Return the size of the threadpool's task queue + * \since 13.7.0 + */ +long ast_threadpool_queue_size(struct ast_threadpool *pool); + #endif /* ASTERISK_THREADPOOL_H */ diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 0719deec2cc..91125ad2af3 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -130,9 +130,6 @@ static int tps_ping_handler(void *datap); /*! \brief Remove the front task off the taskprocessor queue */ static struct tps_task *tps_taskprocessor_pop(struct ast_taskprocessor *tps); -/*! \brief Return the size of the taskprocessor queue */ -static int tps_taskprocessor_depth(struct ast_taskprocessor *tps); - static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); @@ -508,7 +505,7 @@ static struct tps_task *tps_taskprocessor_pop(struct ast_taskprocessor *tps) return task; } -static int tps_taskprocessor_depth(struct ast_taskprocessor *tps) +long ast_taskprocessor_size(struct ast_taskprocessor *tps) { return (tps) ? tps->tps_queue_size : -1; } @@ -765,7 +762,7 @@ int ast_taskprocessor_execute(struct ast_taskprocessor *tps) { struct ast_taskprocessor_local local; struct tps_task *t; - int size; + long size; ao2_lock(tps); t = tps_taskprocessor_pop(tps); @@ -797,7 +794,7 @@ int ast_taskprocessor_execute(struct ast_taskprocessor *tps) * after we pop an empty stack. */ tps->executing = 0; - size = tps_taskprocessor_depth(tps); + size = ast_taskprocessor_size(tps); /* If we executed a task, bump the stats */ if (tps->stats) { tps->stats->_tasks_processed_count++; diff --git a/main/threadpool.c b/main/threadpool.c index 46de9b7f805..60e1e9a3b47 100644 --- a/main/threadpool.c +++ b/main/threadpool.c @@ -1397,3 +1397,8 @@ struct ast_taskprocessor *ast_threadpool_serializer(const char *name, struct ast { return ast_threadpool_serializer_group(name, pool, NULL); } + +long ast_threadpool_queue_size(struct ast_threadpool *pool) +{ + return ast_taskprocessor_size(pool->tps); +} diff --git a/res/res_pjsip.c b/res/res_pjsip.c index cdaed4ee70a..9d0540d420b 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3809,6 +3809,11 @@ static void remove_request_headers(pjsip_endpoint *endpt) } } +long ast_sip_threadpool_queue_size(void) +{ + return ast_threadpool_queue_size(sip_threadpool); +} + AST_TEST_DEFINE(xml_sanitization_end_null) { char sanitized[8]; diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 9b052603a95..1d39e0fd280 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -246,6 +246,8 @@ static pjsip_module endpoint_mod = { .on_rx_request = endpoint_lookup, }; +#define SIP_MAX_QUEUE 500L + static pj_bool_t distributor(pjsip_rx_data *rdata) { pjsip_dialog *dlg = find_dialog(rdata); @@ -280,7 +282,17 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) clone->endpt_info.mod_data[endpoint_mod.id] = ao2_bump(dist->endpoint); } - ast_sip_push_task(serializer, distribute, clone); + if (ast_sip_threadpool_queue_size() > SIP_MAX_QUEUE) { + /* When the threadpool is backed up this much, there is a good chance that we have encountered + * some sort of terrible condition and don't need to be adding more work to the threadpool. + * It's in our best interest to send back a 503 response and be done with it. + */ + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL); + ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]); + pjsip_rx_data_free_cloned(clone); + } else { + ast_sip_push_task(serializer, distribute, clone); + } end: if (dlg) { From 40b58a5d2b2acddc8ff616b4c0fbdc808e16a9da Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 12 Nov 2015 11:17:51 -0600 Subject: [PATCH 0018/1578] res_pjsip distributor: Don't send 503 response to responses. When the SIP threadpool is backed up with tasks, we send 503 responses to ensure that we don't try to overload ourselves. The problem is that we were not insuring that we were not trying to send a 503 to an incoming SIP response. This change makes it so that we only send the 503 on incoming requests. Change-Id: Ie2b418d89c0e453cc6c2b5c7d543651c981e1404 --- res/res_pjsip/pjsip_distributor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 1d39e0fd280..c40f7f9eddb 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -287,7 +287,9 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) * some sort of terrible condition and don't need to be adding more work to the threadpool. * It's in our best interest to send back a 503 response and be done with it. */ - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL); + if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL); + } ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]); pjsip_rx_data_free_cloned(clone); } else { From fd23d423d8e7be865112b8bda58f61ea6e3d0b8f Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 11 Nov 2015 14:00:42 +0100 Subject: [PATCH 0019/1578] format: Register format-attribute module with cached formats. In Asterisk 13, cached formats are created before their corresponding format- attribute module is registered. Cached formats are involved when a local extension is called. Therefore, ast_format_generate_sdp_fmtp did not work on local extensions. This change affects the Opus Codec, H.263 (Plus), H.264, and format-attribute modules provided externally. ASTERISK-25160 #close Change-Id: I1ea1f0483e5261e2a050112e4ebdfc22057d1354 --- main/format.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/main/format.c b/main/format.c index b9931e5449b..cc9ac45d73a 100644 --- a/main/format.c +++ b/main/format.c @@ -302,6 +302,14 @@ const void *ast_format_attribute_get(const struct ast_format *format, const char { const struct ast_format_interface *interface = format->interface; + if (!interface) { + struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY); + if (format_interface) { + interface = format_interface->interface; + ao2_ref(format_interface, -1); + } + } + if (!interface || !interface->format_attribute_get) { return NULL; } @@ -330,11 +338,21 @@ struct ast_format *ast_format_parse_sdp_fmtp(const struct ast_format *format, co void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { - if (!format->interface || !format->interface->format_generate_sdp_fmtp) { + const struct ast_format_interface *interface = format->interface; + + if (!interface) { + struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY); + if (format_interface) { + interface = format_interface->interface; + ao2_ref(format_interface, -1); + } + } + + if (!interface || !interface->format_generate_sdp_fmtp) { return; } - format->interface->format_generate_sdp_fmtp(format, payload, str); + interface->format_generate_sdp_fmtp(format, payload, str); } struct ast_codec *ast_format_get_codec(const struct ast_format *format) From e8881e177046422690d2e87417a93b253469c379 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 13 Nov 2015 14:19:35 -0600 Subject: [PATCH 0020/1578] Taskprocessors: Increase high-water mark In practical tests, we have seen certain taskprocessors, specifically Stasis subscription taskprocessors, cross the recently-added high-water mark and emit a warning. This high-water mark warning is only intended to be emitted when things have tanked on the system and things are heading south quickly. In the practical tests, the Stasis taskprocessors sometimes had a max depth of 180 tasks in them, and Asterisk wasn't in any danger at all. As such, this ups the high-water mark to 500 tasks instead. It also redefines the SIP threadpool request denial number to be a multiple of the taskprocessor high-water mark. Change-Id: Ic8d3e9497452fecd768ac427bb6f58aa616eebce --- include/asterisk/taskprocessor.h | 2 ++ main/taskprocessor.c | 4 +--- res/res_pjsip/pjsip_distributor.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asterisk/taskprocessor.h b/include/asterisk/taskprocessor.h index 06368867a8f..6ebf0729cc7 100644 --- a/include/asterisk/taskprocessor.h +++ b/include/asterisk/taskprocessor.h @@ -56,6 +56,8 @@ struct ast_taskprocessor; +#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL 500 + /*! * \brief ast_tps_options for specification of taskprocessor options * diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 91125ad2af3..dfead22abda 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -713,8 +713,6 @@ void *ast_taskprocessor_unreference(struct ast_taskprocessor *tps) return NULL; } -#define HIGH_WATER_LEVEL 100 - /* push the task into the taskprocessor queue */ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t) { @@ -735,7 +733,7 @@ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t) AST_LIST_INSERT_TAIL(&tps->tps_queue, t, list); previous_size = tps->tps_queue_size++; - if (previous_size >= HIGH_WATER_LEVEL && !tps->high_water_warned) { + if (previous_size >= AST_TASKPROCESSOR_HIGH_WATER_LEVEL && !tps->high_water_warned) { ast_log(LOG_WARNING, "The '%s' task processor queue reached %d scheduled tasks.\n", tps->name, previous_size); tps->high_water_warned = 1; diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index c40f7f9eddb..0e0e90f4e96 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -246,7 +246,7 @@ static pjsip_module endpoint_mod = { .on_rx_request = endpoint_lookup, }; -#define SIP_MAX_QUEUE 500L +#define SIP_MAX_QUEUE (AST_TASKPROCESSOR_HIGH_WATER_LEVEL * 3) static pj_bool_t distributor(pjsip_rx_data *rdata) { From 436023a3225e7902178d7e619c20fd7b9f393926 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 13 Nov 2015 14:32:10 -0600 Subject: [PATCH 0021/1578] res_pjsip_rfc3326.c: Fix crash when channel goes away. If an authenticated incoming caller does not respond to our 200 OK INVITE response with an ACK then PJSIP will hangup the call. Unfortunately, there is a chance that the session's channel will go away between one use of the channel pointer and another when building the BYE request because the BYE is being built by the monitor thread and not the call's serializer thread. * Added a check to ensure that the thread trying to add the Reason header is the call's serializer thread. This ensures that the channel will not go away on us. Change-Id: I866388d2b97ea2032eaae3f3ab3f1ca6cbd2df89 --- res/res_pjsip_rfc3326.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_rfc3326.c b/res/res_pjsip_rfc3326.c index 6eb27ffe235..d49a170d33d 100644 --- a/res/res_pjsip_rfc3326.c +++ b/res/res_pjsip_rfc3326.c @@ -32,6 +32,7 @@ #include "asterisk/res_pjsip_session.h" #include "asterisk/module.h" #include "asterisk/causes.h" +#include "asterisk/threadpool.h" static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pjsip_rx_data *rdata) { @@ -101,9 +102,15 @@ static void rfc3326_add_reason_header(struct ast_sip_session *session, struct pj static void rfc3326_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata) { - if ((pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_bye_method) && - pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_cancel_method)) || - !session->channel) { + if ((pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_bye_method) + && pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_cancel_method)) + || !session->channel + /* + * The session->channel has been seen to go away on us between + * checks so we must also be running under the call's serializer + * thread. + */ + || session->serializer != ast_threadpool_serializer_get_current()) { return; } @@ -114,7 +121,9 @@ static void rfc3326_outgoing_response(struct ast_sip_session *session, struct pj { struct pjsip_status_line status = tdata->msg->line.status; - if ((status.code < 300) || !session->channel) { + if (status.code < 300 + || !session->channel + || session->serializer != ast_threadpool_serializer_get_current()) { return; } From a1fcf6f7b28caf8e2f9b808449c86515e2ef90c4 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sat, 14 Nov 2015 09:02:10 -0400 Subject: [PATCH 0022/1578] hashtab: Add NULL check when destroying iterator. The hashtab API is pretty NULL tolerant which has resulted in remaining callers not doing much checks themselves. Unfortunately the function to destroy an iterator does not do a NULL check and will result in a crash if passed NULL. This change fixes that. ASTERISK-25552 #close Change-Id: Ic1bf8eec3639e5a440f1c941d3ae3893ac6ed619 --- main/hashtab.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/hashtab.c b/main/hashtab.c index c08880c69cb..5d54fb7aa3b 100644 --- a/main/hashtab.c +++ b/main/hashtab.c @@ -746,6 +746,8 @@ struct ast_hashtab_iter *ast_hashtab_start_write_traversal(struct ast_hashtab *t void ast_hashtab_end_traversal(struct ast_hashtab_iter *it) { + if (!it) + return; if (it->tab->do_locking) ast_rwlock_unlock(&it->tab->lock); free(it); From a83e426e9105882e03f2d84a7ff03436bd76b235 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 16 Nov 2015 13:56:49 -0600 Subject: [PATCH 0023/1578] res/res_pjsip: Fix off nominal crash with requests that fail and have a timer When a request is sent using pjsip_endpt_send_request and fails, a condition exists where the request wrapper, which is an AO2 object, may be de-ref'd more times than it should. This occurs when the request's callback is called, and, in the callback, the timer on the PJSIP heap is cancelled. When that occurs, the request wrapper's lifetime is decremented. When pjsip_endpt_send_request fails, we unilaterally decrement the lifetime of the request wrapper again, even though we've already cancelled the reference associated with the timer. This patch checks the return result of pj_timer_heap_cancel_if_active before removing the reference associated with the timer. We now only decrement it in this case if a timer is cancelled as a result of the function call. Change-Id: I21332343a1a019c1117076f9bf2df27be2850102 --- res/res_pjsip.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 9d0540d420b..a4748d20e4f 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3151,9 +3151,11 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, char errmsg[PJ_ERR_MSG_SIZE]; if (timeout > 0) { - pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(endpt), + int timers_cancelled = pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(endpt), req_wrapper->timeout_timer, TIMER_INACTIVE); - ao2_ref(req_wrapper, -1); + if (timers_cancelled > 0) { + ao2_ref(req_wrapper, -1); + } } /* Complain of failure to send the request. */ From ed1373218888604be92c49494e2aa22f01e08ab6 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 13 Nov 2015 14:03:35 -0600 Subject: [PATCH 0024/1578] Confbridge: Add a user timeout option This option adds the ability to specify a timeout, in seconds, for a participant in a ConfBridge. When the user's timeout has been reached, the user is ejected from the conference with the CONFBRIDGE_RESULT channel variable set to "TIMEOUT". The rationale for this change is that there have been times where we have seen channels get "stuck" in ConfBridge because a network issue results in a SIP BYE not being received by Asterisk. While these channels can be hung up manually via CLI/AMI/ARI, adding some sort of automatic cleanup of the channels is a nice feature to have. ASTERISK-25549 #close Reported by Mark Michelson Change-Id: I2996b6c5e16a3dda27595f8352abad0bda9c2d98 --- CHANGES | 7 +++++++ apps/app_confbridge.c | 18 ++++++++++++++++++ apps/confbridge/conf_config_parser.c | 4 ++++ apps/confbridge/include/confbridge.h | 2 ++ configs/samples/confbridge.conf.sample | 6 ++++++ 5 files changed, 37 insertions(+) diff --git a/CHANGES b/CHANGES index dcda33fe5bd..d6fea74acb9 100644 --- a/CHANGES +++ b/CHANGES @@ -200,6 +200,13 @@ Queue --- Functionality changes from Asterisk 13.6.0 to Asterisk 13.7.0 ------------ ------------------------------------------------------------------------------ +ConfBridge +------------------ + * A new "timeout" user profile option has been added. This configures the number + of seconds that a participant may stay in the ConfBridge after joining. When + the time expires, the user is ejected from the conference and CONFBRIDGE_RESULT + is set to "TIMEOUT" on the channel. + chan_sip ------------------ * The websockets_enabled option has been added to the general section of diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 07188877fa2..7a04952dbd8 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -118,6 +118,7 @@ ASTERISK_REGISTER_FILE() The channel was kicked from the conference. The channel left the conference as a result of the last marked user leaving. The channel pressed a DTMF sequence to exit the conference. + The channel reached its configured timeout. @@ -1545,6 +1546,13 @@ static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user) return -1; } +static int user_timeout(struct ast_bridge_channel *bridge_channel, void *ignore) +{ + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0); + pbx_builtin_setvar_helper(bridge_channel->chan, "CONFBRIDGE_RESULT", "TIMEOUT"); + return -1; +} + static int conf_rec_name(struct confbridge_user *user, const char *conf_name) { char destdir[PATH_MAX]; @@ -1779,6 +1787,16 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) ast_autoservice_stop(chan); } + if (user.u_profile.timeout) { + ast_bridge_interval_hook(&user.features, + 0, + user.u_profile.timeout * 1000, + user_timeout, + NULL, + NULL, + AST_BRIDGE_HOOK_REMOVE_ON_PULL); + } + /* See if we need to automatically set this user as a video source or not */ handle_video_on_join(conference, user.chan, ast_test_flag(&user.u_profile, USER_OPT_MARKEDUSER)); diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 7fcc7005c23..a33c6a12a77 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -227,6 +227,9 @@ ASTERISK_REGISTER_FILE() When using the CONFBRIDGE dialplan function, use a user profile as a template for creating a new temporary profile + + Kick the user out of the conference after this many seconds. 0 means there is no timeout for the user. + A named profile to apply to specific bridges. @@ -2141,6 +2144,7 @@ int conf_load_config(void) aco_option_register(&cfg_info, "dsp_silence_threshold", ACO_EXACT, user_types, __stringify(DEFAULT_SILENCE_THRESHOLD), OPT_UINT_T, 0, FLDSET(struct user_profile, silence_threshold)); aco_option_register(&cfg_info, "dsp_talking_threshold", ACO_EXACT, user_types, __stringify(DEFAULT_TALKING_THRESHOLD), OPT_UINT_T, 0, FLDSET(struct user_profile, talking_threshold)); aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_JITTERBUFFER); + aco_option_register(&cfg_info, "timeout", ACO_EXACT, user_types, "0", OPT_UINT_T, 0, FLDSET(struct user_profile, timeout)); /* This option should only be used with the CONFBRIDGE dialplan function */ aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0); diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 54a9dc4ec20..539b9961b3f 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -141,6 +141,8 @@ struct user_profile { unsigned int talking_threshold; /*! The time in ms of silence before a user is considered to be silent by the dsp. */ unsigned int silence_threshold; + /*! The time in ms the user may stay in the confbridge */ + unsigned int timeout; }; enum conf_sounds { diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index 25ca33f8faf..85de3282bd5 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -137,6 +137,12 @@ type=user ; This option is off by default. ;announcement= ; Play a sound file to the user when they join the conference. +;timeout=3600 ; When set non-zero, this specifies the number of seconds that the participant + ; may stay in the conference before being automatically ejected. When the user + ; is ejected from the conference, the user's channel will have the CONFBRIDGE_RESULT + ; variable set to "TIMEOUT". A value of 0 indicates that there is no timeout. + ; Default: 0 + ; --- ConfBridge Bridge Profile Options --- [default_bridge] type=bridge From 6919daab61142e74f8313def68310465d7be998e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 16 Nov 2015 15:10:20 -0700 Subject: [PATCH 0025/1578] dns: Fix pointer increment in dns_parse_answer_ex When dns_parse_answer_ex was iterating over the answers it wasn't incrementing the answer pointer correctly after the first answer. The result was that no answers after the first were being returned. For results where multiple records should have been sorted by priority, weight, etc., there was nothing to sort so the only the first record was returned even if it wouldn't have been the correct record based on the sort. ASTERISK-25565 #close Reported-by: Daniel Tryba Tested-by George Joseph Change-Id: I8622604fefdcd3c11e2c5609a6382e53b1467b0b --- main/dns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/dns.c b/main/dns.c index c3b352d4159..e338d768b8b 100644 --- a/main/dns.c +++ b/main/dns.c @@ -482,7 +482,7 @@ static int dns_parse_answer_ex(void *context, int rr_class, int rr_type, unsigne /* Try and update the field to the next record, but ignore any errors that come * back because this may be the end of the line. */ - pos = dns_advance_field(&answer, pos, res + ntohs(ans->size)); + pos = dns_advance_field(&answer, pos, ntohs(ans->size)); } return ret; From 4013f9d5777e2e3048aab8108ba51cb2f963ff0b Mon Sep 17 00:00:00 2001 From: Alec Davis Date: Wed, 18 Nov 2015 19:20:22 +1300 Subject: [PATCH 0026/1578] app_queue: (try_calling): mutex 'qe->chan' freed more times than we've locked! commit aae45acbd (Mark Michelson 2015-04-15 10:38:02 -0500 6525) refer ASTERISK-24958 above commit removed ast_channel_lock(qe->chan); but failed to remove corresponding ast_channel_unlock(qe->chan); ASTERISK-25561 #close Reported Alec Davis Change-Id: Ie05f4e2d08912606178bf1fded57cc022c7a2e1a --- apps/app_queue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 862988b7c84..234543f75a2 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -6523,7 +6523,6 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, ringing); - ast_channel_unlock(qe->chan); ao2_lock(qe->parent); if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { store_next_rr(qe, outgoing); From eaf898ac881585c23ac0fcb31c5369809c68b1bb Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 17 Nov 2015 14:53:57 -0600 Subject: [PATCH 0027/1578] res_pjsip_outbound_registration.c: Fix 423 response handling. Receiving a 423 Interval Too Brief response after authentication for an outbound registration attempt results in assuming that the registrar has rejected the registration permanently. If there are no configured retries for fatal responses then the outbound registration is stopped for that endpoint. For registrations, PJSIP/PJPROJECT intercepts the handling of 423 responses and does not include any authentication in the updated registration request. When the updated request is challenged then the Asterisk code assumes that we were challenged again because the peer rejected the authentication we sent earlier. * Made registration challenges keep track of the CSeq number to determine if the received challenge response was for the request we thought we sent. If the response's CSeq number differs from the CSeq number we last sent with authentication then authenticate again because it is a challenge to a different request. Change-Id: I81b4bd36d1be095bab606e34b8b44e6302971b09 --- res/res_pjsip_outbound_registration.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 7ff5f1619bf..2fd5b8c48e6 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -335,6 +335,8 @@ struct sip_outbound_registration_client_state { unsigned int auth_rejection_permanent; /*! \brief Determines whether SIP Path support should be advertised */ unsigned int support_path; + /*! CSeq number of last sent auth request. */ + unsigned int auth_cseq; /*! \brief Serializer for stuff and things */ struct ast_taskprocessor *serializer; /*! \brief Configured authentication credentials */ @@ -758,15 +760,27 @@ static int handle_registration_response(void *data) ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n", response->code, server_uri, client_uri); - if (!response->client_state->auth_attempted && - (response->code == 401 || response->code == 407)) { + if ((response->code == 401 || response->code == 407) + && (!response->client_state->auth_attempted + || response->rdata->msg_info.cseq->cseq != response->client_state->auth_cseq)) { + int res; + pjsip_cseq_hdr *cseq_hdr; pjsip_tx_data *tdata; + if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths, response->rdata, response->old_request, &tdata)) { response->client_state->auth_attempted = 1; ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n", server_uri, client_uri); - if (registration_client_send(response->client_state, tdata) == PJ_SUCCESS) { + pjsip_tx_data_add_ref(tdata); + res = registration_client_send(response->client_state, tdata); + + /* Save the cseq that actually got sent. */ + cseq_hdr = (pjsip_cseq_hdr *) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, + NULL); + response->client_state->auth_cseq = cseq_hdr->cseq; + pjsip_tx_data_dec_ref(tdata); + if (res == PJ_SUCCESS) { ao2_ref(response, -1); return 0; } From 3dbaf696e98aa0d31de9635c00de4a3de2d3f008 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 17 Nov 2015 14:53:19 -0600 Subject: [PATCH 0028/1578] res_pjsip_outbound_registration.c: Be tolerant of short registration timeouts. Change-Id: Ie16f5053ebde0dc6507845393709b4d6a3ea526d --- res/res_pjsip_outbound_registration.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 2fd5b8c48e6..83386c61c9f 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -796,11 +796,18 @@ static int handle_registration_response(void *data) if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) { /* Check if this is in regards to registering or unregistering */ if (response->expiration) { + int next_registration_round; + /* If the registration went fine simply reschedule registration for the future */ ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri); response->client_state->status = SIP_REGISTRATION_REGISTERED; response->client_state->retries = 0; - schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME); + next_registration_round = response->expiration - REREGISTER_BUFFER_TIME; + if (next_registration_round < 0) { + /* Re-register immediately. */ + next_registration_round = 0; + } + schedule_registration(response->client_state, next_registration_round); } else { ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri); response->client_state->status = SIP_REGISTRATION_UNREGISTERED; From 05addf3d8f12ca3716408e0087b8d3642512af41 Mon Sep 17 00:00:00 2001 From: tcambron Date: Thu, 5 Nov 2015 15:37:59 -0600 Subject: [PATCH 0029/1578] StatsD: Add sample rate compatibility Implemented support for the StatsD sample rate parameter, which is a parameter for determining when to send computed statistics to a client. Valid sample rate values are: Less than or equal to 0.0 will never be sent. Between 0.0 and 1.0 will randomly be sent. Greater than or equal to 1.0 will always be sent. ASTERISK-25419 Reported By: Ashley Sanders Change-Id: I11d315d0a5034fffeae1178e650aa8264485ed52 --- apps/app_statsd.c | 673 +++++++++++++++++++++++++++++----------------- 1 file changed, 425 insertions(+), 248 deletions(-) diff --git a/apps/app_statsd.c b/apps/app_statsd.c index 176796f3777..e87aac64389 100644 --- a/apps/app_statsd.c +++ b/apps/app_statsd.c @@ -1,248 +1,425 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2015, Digium, Inc. - * - * Tyler Cambron - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - - /*** MODULEINFO - res_statsd - no - extended - ***/ - -#include "asterisk.h" - -ASTERISK_REGISTER_FILE() - -#include - -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/app.h" -#include "asterisk/pbx.h" -#include "asterisk/strings.h" -#include "asterisk/statsd.h" - -/*** DOCUMENTATION - - - Allow statistics to be passed to the StatsD server from the dialplan. - - - - The metric type to be sent to StatsD. - - - The name of the variable to be sent to StatsD. - - - The value of the variable to be sent to StatsD. - - - - This dialplan application sends statistics to the StatsD - server specified inside of statsd.conf. - - - ***/ - -static const char app[] = "StatsD"; - -/*! - * \brief Check to ensure the value is within the allowed range. - * - * \param value The value of the statistic to be sent to StatsD. - * \param metric The metric type to be sent to StatsD. - * - * This function checks to see if the value given to the StatsD daialplan - * application is within the allowed range as specified by StatsD. A counter - * is the only metric type allowed to be initialized as a negative number. - * - * \retval zero on success. - * \retval 1 on error. - */ -static int value_in_range(const char *value, const char *metric) -{ - double numerical_value = strtod(value, NULL); - - if (!strcmp(metric, "c")) { - if (numerical_value < pow(-2, 63) || numerical_value > pow(2, 63)) { - ast_log(AST_LOG_WARNING, "Value %lf out of range!\n", numerical_value); - return 1; - } - } else { - if (numerical_value < 0 || numerical_value > pow(2, 64)) { - ast_log(AST_LOG_WARNING, "Value %lf out of range!\n", numerical_value); - return 1; - } - } - - return 0; -} - -/*! - * \brief Check to ensure the metric type is a valid metric type. - * - * \param metric The metric type to be sent to StatsD. - * - * This function checks to see if the metric type given to the StatsD dialplan - * is a valid metric type. Metric types are determined by StatsD. - * - * \retval zero on success. - * \retval 1 on error. - */ -static int validate_metric(const char *metric) -{ - const char *valid_metrics[] = {"g","s","ms","c"}; - int i; - - if (ast_strlen_zero(metric)) { - ast_log(AST_LOG_ERROR, "Missing metric type argument.\n"); - return 1; - } - - for (i = 0; i < ARRAY_LEN(valid_metrics); i++) { - if (!strcmp(valid_metrics[i], metric)) { - return 0; - } - } - - ast_log(AST_LOG_ERROR, "Invalid metric type %s.\n", metric); - - return 1; -} - -/*! - * \brief Check to ensure the statistic name is valid. - * - * \param name The variable name to be sent to StatsD. - * - * This function checks to see if the statistic name given to the StatsD - * dialplan application is valid by ensuring that the name does not have any - * invalid characters. - * - * \retval zero on success. - * \retval 1 on error. - */ -static int validate_name(const char *name) -{ - if (ast_strlen_zero(name) || (strstr(name, "|") != NULL)) { - ast_log(AST_LOG_ERROR, "Statistic name %s is missing or contains a pipe (|)" - " character.\n", name); - return 1; - } - - return 0; -} - -/*! - * \brief Check to ensure the value is valid. - * - * \param value The value of the statistic to be sent to StatsD. - * \param metric The metric type to be sent to StatsD. - * - * This function checks to see if the value given to the StatsD daialplan - * application is valid by testing if it is numeric. A plus or minus is only - * allowed at the beginning of the value if it is a counter or a gauge. - * - * \retval zero on success. - * \retval 1 on error. - */ -static int validate_value(const char *value, const char *metric) -{ - const char *actual_value; - - if (ast_strlen_zero(value)) { - ast_log(AST_LOG_ERROR, "Missing value argument.\n"); - return 1; - } - - if (!strcmp(metric, "g") || !strcmp(metric, "c")) { - if ((value[0] == '+') || (value[0] == '-')) { - actual_value = &value[1]; - if (ast_strlen_zero(actual_value)) { - ast_log(AST_LOG_ERROR, "Value argument %s only contains a sign" - " operator.\n", value); - return 1; - } - } else { - actual_value = &value[0]; - } - } else { - actual_value = &value[0]; - } - - if (!isdigit(*actual_value)) { - ast_log(AST_LOG_ERROR, "Value of %s is not a valid number!\n", actual_value); - return 1; - } - - if (value_in_range(actual_value, metric)) { - return 1; - } - - return 0; -} - -static int statsd_exec(struct ast_channel *chan, const char *data) -{ - char *stats; - double numerical_value; - - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(metric_type); - AST_APP_ARG(statistic_name); - AST_APP_ARG(value); - ); - - if (!data) { - ast_log(AST_LOG_ERROR, "No parameters were provided. Correct format is " - "StatsD(metric_type,statistic_name,value). All parameters are required.\n"); - return 1; - } - - stats = ast_strdupa(data); - AST_STANDARD_APP_ARGS(args, stats); - - /* If any of the validations fail, emit a warning message. */ - if (validate_metric(args.metric_type) || validate_name(args.statistic_name) - || validate_value(args.value, args.metric_type)) { - ast_log(AST_LOG_WARNING, "Invalid parameters provided. Correct format is " - "StatsD(metric_type,statistic_name,value). All parameters are required.\n"); - - return 1; - } - - /* - * Conversion to a double is safe here since the value would have been validated as a - * number in validate_value(). - */ - numerical_value = strtod(args.value, NULL); - ast_statsd_log(args.statistic_name, args.metric_type, numerical_value); - - return 0; -} - -static int unload_module(void) -{ - return ast_unregister_application(app); -} - -static int load_module(void) -{ - return ast_register_application_xml(app, statsd_exec); -} - -AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "StatsD Dialplan Application"); +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Digium, Inc. + * + * Tyler Cambron + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + + /*** MODULEINFO + res_statsd + no + extended + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include + +#include "asterisk/module.h" +#include "asterisk/logger.h" +#include "asterisk/app.h" +#include "asterisk/pbx.h" +#include "asterisk/strings.h" +#include "asterisk/statsd.h" + +/*** DOCUMENTATION + + + Allow statistics to be passed to the StatsD server from the dialplan. + + + + The metric type to be sent to StatsD. Valid metric types + are 'g' for gauge, 'c' for counter, 'ms' for timer, and 's' for + sets. + + + The name of the variable to be sent to StatsD. Statistic + names cannot contain the pipe (|) character. + + + The value of the variable to be sent to StatsD. Values + must be numeric. Values for gauge and counter metrics can be + sent with a '+' or '-' to update a value after the value has + been initialized. Only counters can be initialized as negative. + Sets can send a string as the value parameter, but the string + cannot contain the pipe character. + + + The value of the sample rate to be sent to StatsD. Sample + rates less than or equal to 0 will never be sent and sample rates + greater than or equal to 1 will always be sent. Any rate + between 1 and 0 will be compared to a randomly generated value, + and if it is greater than the random value, it will be sent. + + + + This dialplan application sends statistics to the StatsD + server specified inside of statsd.conf. + + + ***/ + +static const char app[] = "StatsD"; + +/*! + * \brief Check to ensure the value is within the allowed range. + * + * \param value The value of the statistic to be sent to StatsD. + * + * This function checks to see if the value given to the StatsD daialplan + * application is within the allowed range of [-2^63, 2^63] as specified by StatsD. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int value_in_range(const char *value) { + double numerical_value = strtod(value, NULL); + + if (numerical_value < pow(-2, 63) || numerical_value > pow(2, 63)) { + ast_log(AST_LOG_WARNING, "Value %lf out of range!\n", numerical_value); + return 1; + } + + return 0; +} + +/*! + * \brief Check to ensure the value is within the allowed range. + * + * \param value The value of the statistic to be sent to StatsD. + * + * This function checks to see if the value given to the StatsD daialplan + * application is within the allowed range of [0, 2^64] as specified by StatsD. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int non_neg_value_range(const char *value) { + double numerical_value = strtod(value, NULL); + + if (numerical_value < 0 || numerical_value > pow(2, 64)) { + ast_log(AST_LOG_WARNING, "Value %lf out of range!\n", numerical_value); + return 1; + } + + return 0; +} + +/*! + * \brief Check to ensure the metric type is a valid metric type. + * + * \param metric The metric type to be sent to StatsD. + * + * This function checks to see if the metric type given to the StatsD dialplan + * is a valid metric type. Metric types are determined by StatsD. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int validate_metric(const char *metric) +{ + const char *valid_metrics[] = {"g","s","ms","c"}; + int i; + + if (ast_strlen_zero(metric)) { + ast_log(AST_LOG_ERROR, "Missing metric type argument.\n"); + return 1; + } + + for (i = 0; i < ARRAY_LEN(valid_metrics); i++) { + if (!strcmp(valid_metrics[i], metric)) { + return 0; + } + } + + ast_log(AST_LOG_ERROR, "Invalid metric type %s.\n", metric); + + return 1; +} + +/*! + * \brief Check to ensure that a numeric value is valid. + * + * \param numeric_value The numeric value to be sent to StatsD. + * + * This function checks to see if a number to be sent to StatsD is actually + * a valid number. One decimal is allowed. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int validate_numeric(const char *numeric_value) { + const char *num; + int decimal_counter = 0; + + num = numeric_value; + while (*num) { + if (!isdigit(*num++)) { + if (strstr(numeric_value, ".") != NULL && decimal_counter == 0) { + decimal_counter++; + continue; + } + ast_log(AST_LOG_ERROR, "%s is not a number!\n", numeric_value); + return 1; + } + } + + return 0; +} + +/*! + * \brief Determines the actual value of a number by looking for a leading + or -. + * + * \param raw_value The entire numeric string to be sent to StatsD. + * + * This function checks to see if the numeric string contains valid characters + * and then isolates the actual number to be sent for validation. Returns the + * result of the numeric validation. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int determine_actual_value(const char *raw_value) { + const char *actual_value; + + if ((raw_value[0] == '+') || (raw_value[0] == '-')) { + actual_value = &raw_value[1]; + if (ast_strlen_zero(actual_value)) { + ast_log(AST_LOG_ERROR, "Value argument %s only contains a sign" + " operator.\n", raw_value); + return 1; + } + } else { + actual_value = &raw_value[0]; + } + + return validate_numeric(actual_value); +} + +/*! + * \brief Check to ensure the statistic name is valid. + * + * \param name The variable name to be sent to StatsD. + * + * This function checks to see if the statistic name given to the StatsD + * dialplan application is valid by ensuring that the name does not have any + * invalid characters. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int validate_name(const char *name) +{ + if (ast_strlen_zero(name) || (strstr(name, "|") != NULL)) { + ast_log(AST_LOG_ERROR, "Statistic name %s is missing or contains a pipe (|)" + " character.\n", name); + return 1; + } + + return 0; +} + + +/*! + * \brief Calls the appropriate functions to validate a gauge metric. + * + * \param statistic_name The statistic name to be sent to StatsD. + * \param value The value to be sent to StatsD. + * + * This function calls other validating functions to correctly validate each + * input based on allowable input for a gauge metric. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int validate_metric_type_gauge(const char *statistic_name, const char *value) { + + if (ast_strlen_zero(value)) { + ast_log(AST_LOG_ERROR, "Missing value argument.\n"); + return 1; + } + + if (validate_name(statistic_name) || determine_actual_value(value) + || value_in_range(value)) { + return 1; + } + + return 0; +} + +/*! + * \brief Calls the appropriate functions to validate a counter metric. + * + * \param statistic_name The statistic name to be sent to StatsD. + * \param value The value to be sent to StatsD. + * + * This function calls other validating functions to correctly validate each + * input based on allowable input for a counter metric. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int validate_metric_type_counter(const char *statistic_name, const char *value) { + + if (ast_strlen_zero(value)) { + ast_log(AST_LOG_ERROR, "Missing value argument.\n"); + return 1; + } + + if (validate_name(statistic_name) || determine_actual_value(value) + || value_in_range(value)) { + return 1; + } + + return 0; +} + +/*! + * \brief Calls the appropriate functions to validate a timer metric. + * + * \param statistic_name The statistic name to be sent to StatsD. + * \param value The value to be sent to StatsD. + * + * This function calls other validating functions to correctly validate each + * input based on allowable input for a timer metric. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int validate_metric_type_timer(const char *statistic_name, const char *value) { + + if (ast_strlen_zero(value)) { + ast_log(AST_LOG_ERROR, "Missing value argument.\n"); + return 1; + } + + if (validate_name(statistic_name) || validate_numeric(value) + || non_neg_value_range(value)) { + return 1; + } + + return 0; +} + +/*! + * \brief Calls the appropriate functions to validate a set metric. + * + * \param statistic_name The statistic name to be sent to StatsD. + * \param value The value to be sent to StatsD. + * + * This function calls other validating functions to correctly validate each + * input based on allowable input for a set metric. + * + * \retval zero on success. + * \retval 1 on error. + */ +static int validate_metric_type_set(const char *statistic_name, const char *value) { + if (ast_strlen_zero(value)) { + ast_log(AST_LOG_ERROR, "Missing value argument.\n"); + return 1; + } + + if (validate_name(statistic_name)) { + return 1; + } + + if (strstr(value, "|") != NULL) { + ast_log(AST_LOG_ERROR, "Pipe (|) character is not allowed for value %s" + " in a set metric.\n", value); + return 1; + } + + return 0; +} + +static int statsd_exec(struct ast_channel *chan, const char *data) +{ + char *stats; + double numerical_rate = 1.0; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(metric_type); + AST_APP_ARG(statistic_name); + AST_APP_ARG(value); + AST_APP_ARG(sample_rate); + ); + + if (!data) { + ast_log(AST_LOG_ERROR, "No parameters were provided. Correct format is " + "StatsD(metric_type,statistic_name,value[,sample_rate]). Sample rate is the " + "only optional parameter.\n"); + return 1; + } + + stats = ast_strdupa(data); + AST_STANDARD_APP_ARGS(args, stats); + + if (validate_metric(args.metric_type)) { + return 1; + } + + if (!strcmp(args.metric_type, "g")) { + if (validate_metric_type_gauge(args.statistic_name, args.value)) { + ast_log(AST_LOG_ERROR, "Invalid input for a gauge metric.\n"); + return 1; + } + } + else if (!strcmp(args.metric_type, "c")) { + if (validate_metric_type_counter(args.statistic_name, args.value)) { + ast_log(AST_LOG_ERROR, "Invalid input for a counter metric.\n"); + return 1; + } + } + else if (!strcmp(args.metric_type, "ms")) { + if (validate_metric_type_timer(args.statistic_name, args.value)) { + ast_log(AST_LOG_ERROR, "Invalid input for a timer metric.\n"); + return 1; + } + } + else if (!strcmp(args.metric_type, "s")) { + if (validate_metric_type_set(args.statistic_name, args.value)) { + ast_log(AST_LOG_ERROR, "Invalid input for a set metric.\n"); + return 1; + } + } + + if (args.sample_rate) { + + if (validate_numeric(args.sample_rate)) { + return 1; + } + + numerical_rate = strtod(args.sample_rate, NULL); + } + + ast_statsd_log_string(args.statistic_name, args.metric_type, args.value, + numerical_rate); + + return 0; +} + +static int unload_module(void) +{ + return ast_unregister_application(app); +} + +static int load_module(void) +{ + return ast_register_application_xml(app, statsd_exec); +} + +AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "StatsD Dialplan Application"); From 8c14b91651fc9a608c0017a8d6850c5a9bd1ed02 Mon Sep 17 00:00:00 2001 From: Alec Davis Date: Wed, 18 Nov 2015 21:25:15 +1300 Subject: [PATCH 0030/1578] app_bridgeaddchan: ability to barge into existing call To be able to barge into a call by dialling a prefix+extension that maps to the extensions device. Senario is that DECT headset users may be away from their desks and need to transfer the call, the goal is that from any phone they dial a prefix then their extension and are added to the bridge that they are in, from there they can drop the headset call, as it's also on the handset, and transfer the caller. The dialplan would look like, where prefix=73, extension = 8512; exten => _738512,1,BridgeAdd(SIP/cisco0001) ASTERISK-25551 #close Reported By: Alec Davis Change-Id: I8eb5096a02168dcc8d7aeea416ef36ba4ed10540 --- CHANGES | 5 ++ apps/app_bridgeaddchan.c | 124 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 apps/app_bridgeaddchan.c diff --git a/CHANGES b/CHANGES index d6fea74acb9..6e96515c3a6 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,11 @@ Applications ------------------ +BridgeAdd +------------------ + * A new application in Asterisk, this will join the calling channel + to an existing bridge containing the named channel prefix. + ConfBridge ------------------ * Added the ability to pass options to MixMonitor when recording is used with diff --git a/apps/app_bridgeaddchan.c b/apps/app_bridgeaddchan.c new file mode 100644 index 00000000000..fda6ca5ed86 --- /dev/null +++ b/apps/app_bridgeaddchan.c @@ -0,0 +1,124 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Digium, Inc. + * + * Alec Davis + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Application to place the channel into an existing Bridge + * + * \author Alec Davis + * + * \ingroup applications + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/file.h" +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/bridge.h" +#include "asterisk/features.h" + +/*** DOCUMENTATION + + + Join a bridge that contains the specified channel. + + + + Name of the channel in an existing bridge + + + + + This application places the incoming channel into + the bridge containing the specified channel. The specified + channel only needs to be the prefix of a full channel name + IE. 'SIP/cisco0001'. + + + + ***/ + +static const char app[] = "BridgeAdd"; + +static int bridgeadd_exec(struct ast_channel *chan, const char *data) +{ + struct ast_channel *c_ref; + struct ast_bridge_features chan_features; + struct ast_bridge *bridge; + char *c_name; + + /* Answer the channel if needed */ + if (ast_channel_state(chan) != AST_STATE_UP) { + ast_answer(chan); + } + + if (!(c_ref = ast_channel_get_by_name_prefix(data, strlen(data)))) { + ast_log(LOG_WARNING, "Channel %s not found\n", data); + return -1; + } + + c_name = ast_strdupa(ast_channel_name(c_ref)); + + ast_channel_lock(c_ref); + bridge = ast_channel_get_bridge(c_ref); + ast_channel_unlock(c_ref); + + ast_channel_unref(c_ref); + + if (!bridge) { + ast_log(LOG_WARNING, "Channel %s is not in a bridge\n", c_name); + return -1; + } + + ast_verb(3, "%s is joining %s in bridge %s\n", ast_channel_name(chan), + c_name, bridge->uniqueid); + + if (ast_bridge_features_init(&chan_features) + || ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 0)) { + + ast_log(LOG_WARNING, "%s failed to join %s in bridge %s\n", ast_channel_name(chan), + c_name, bridge->uniqueid); + + ast_bridge_features_cleanup(&chan_features); + ao2_cleanup(bridge); + return -1; + } + + ast_bridge_features_cleanup(&chan_features); + ao2_cleanup(bridge); + return 0; +} + +static int unload_module(void) +{ + return ast_unregister_application(app); +} + +static int load_module(void) +{ + return ast_register_application_xml(app, bridgeadd_exec); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bridge Add Channel Application"); From 92ea46ba94028c7082a0e1ae8fb22d9a327c90fa Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 19 Nov 2015 08:03:54 +0100 Subject: [PATCH 0031/1578] res_format_attr_h264: Do not reset string buffer. When no parameter is present, Asterisk does not generate the line fmtp, as expected. However, because a buffer was reset, even rtpmap and fmtp of previous media codecs got removed. Now, Asterisk does not reset other codecs in case of no parameter for H.264. ASTERISK-25573 #close Change-Id: I93811331f4a28c45418a9e14ee46c0debd47a286 --- res/res_format_attr_h264.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/res/res_format_attr_h264.c b/res/res_format_attr_h264.c index 95274691c58..ccf2176f2d6 100644 --- a/res/res_format_attr_h264.c +++ b/res/res_format_attr_h264.c @@ -236,7 +236,7 @@ static struct ast_format *h264_parse_sdp_fmtp(const struct ast_format *format, c if (field != H264_ATTR_KEY_UNSET) { \ if (added) { \ ast_str_append(str, 0, ";"); \ - } else { \ + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { \ added = 1; \ } \ ast_str_append(str, 0, "%s=%u", name, field); \ @@ -247,7 +247,7 @@ static struct ast_format *h264_parse_sdp_fmtp(const struct ast_format *format, c if (field) { \ if (added) { \ ast_str_append(str, 0, ";"); \ - } else { \ + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { \ added = 1; \ } \ ast_str_append(str, 0, "%s=%u", name, field); \ @@ -263,8 +263,6 @@ static void h264_generate_sdp_fmtp(const struct ast_format *format, unsigned int return; } - ast_str_append(str, 0, "a=fmtp:%u ", payload); - APPEND_IF_NONZERO(attr->MAX_MBPS, str, "max-mbps"); APPEND_IF_NONZERO(attr->MAX_FS, str, "max-fs"); APPEND_IF_NONZERO(attr->MAX_CPB, str, "max-cpb"); @@ -287,7 +285,7 @@ static void h264_generate_sdp_fmtp(const struct ast_format *format, unsigned int if (attr->PROFILE_IDC && attr->PROFILE_IOP && attr->LEVEL) { if (added) { ast_str_append(str, 0, ";"); - } else { + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { added = 1; } ast_str_append(str, 0, "profile-level-id=%02X%02X%02X", attr->PROFILE_IDC, attr->PROFILE_IOP, attr->LEVEL); @@ -296,15 +294,13 @@ static void h264_generate_sdp_fmtp(const struct ast_format *format, unsigned int if (!ast_strlen_zero(attr->SPS) && !ast_strlen_zero(attr->PPS)) { if (added) { ast_str_append(str, 0, ";"); - } else { + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { added = 1; } - ast_str_append(str, 0, ";sprop-parameter-sets=%s,%s", attr->SPS, attr->PPS); + ast_str_append(str, 0, "sprop-parameter-sets=%s,%s", attr->SPS, attr->PPS); } - if (!added) { - ast_str_reset(*str); - } else { + if (added) { ast_str_append(str, 0, "\r\n"); } From 8ccb1d2bed90629c8755b362ee6850ef9586be14 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 11 Nov 2015 13:29:24 +0100 Subject: [PATCH 0032/1578] translate: Provide translation modules the result of SDP negotiation. Previously, a trancoding module did not have access to the joint but cached format. Therefore, the module did not have access to the attributes negotiated via SDP (line fmtp). Now, a translation module receives the joint format. ASTERISK-25545 #close Change-Id: Id6878a989b50573298dab115d3371ea369e1a718 --- include/asterisk/translate.h | 8 ++++++++ main/translate.c | 31 ++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h index 87e9a2cabd3..b8cd219713b 100644 --- a/include/asterisk/translate.h +++ b/include/asterisk/translate.h @@ -223,6 +223,14 @@ struct ast_trans_pvt { struct ast_trans_pvt *next; /*!< next in translator chain */ struct timeval nextin; struct timeval nextout; + /*! If a translation path using a format with attributes requires the output + * to be a specific set of attributes, this variable will be set describing + * those attributes to the translator. Otherwise, the translator must choose + * a set of format attributes for the destination that preserves the quality + * of the audio in the best way possible. For example with the Opus Codec, + * explicit_dst contains an attribute which describes whether both parties + * want to do forward-error correction (FEC). */ + struct ast_format *explicit_dst; }; /*! \brief generic frameout function */ diff --git a/main/translate.c b/main/translate.c index 334d3b5503f..61a827b71a6 100644 --- a/main/translate.c +++ b/main/translate.c @@ -298,6 +298,10 @@ static void destroy(struct ast_trans_pvt *pvt) t->destroy(pvt); } ao2_cleanup(pvt->f.subclass.format); + if (pvt->explicit_dst) { + ao2_ref(pvt->explicit_dst, -1); + pvt->explicit_dst = NULL; + } ast_free(pvt); ast_module_unref(t->module); } @@ -306,7 +310,7 @@ static void destroy(struct ast_trans_pvt *pvt) * \brief Allocate the descriptor, required outbuf space, * and possibly desc. */ -static struct ast_trans_pvt *newpvt(struct ast_translator *t) +static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format *explicit_dst) { struct ast_trans_pvt *pvt; int len; @@ -332,6 +336,12 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t) if (t->buf_size) {/* finally buffer and header */ pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET; } + /* + * If the format has an attribute module, explicit_dst includes the (joined) + * result of the SDP negotiation. For example with the Opus Codec, the format + * knows whether both parties want to do forward-error correction (FEC). + */ + pvt->explicit_dst = ao2_bump(explicit_dst); ast_module_ref(t->module); @@ -349,9 +359,16 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t) pvt->f.src = pvt->t->name; pvt->f.data.ptr = pvt->outbuf.c; - /* if the translator has not provided a format find one in the cache or create one */ + /* + * If the translator has not provided a format + * A) use the joined one, + * B) use the cached one, or + * C) create one. + */ if (!pvt->f.subclass.format) { - if (!ast_strlen_zero(pvt->t->format)) { + pvt->f.subclass.format = ao2_bump(pvt->explicit_dst); + + if (!pvt->f.subclass.format && !ast_strlen_zero(pvt->t->format)) { pvt->f.subclass.format = ast_format_cache_get(pvt->t->format); } @@ -477,6 +494,7 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a while (src_index != dst_index) { struct ast_trans_pvt *cur; + struct ast_format *explicit_dst = NULL; struct ast_translator *t = matrix_get(src_index, dst_index)->step; if (!t) { ast_log(LOG_WARNING, "No translator path from %s to %s\n", @@ -484,7 +502,10 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a AST_RWLIST_UNLOCK(&translators); return NULL; } - if (!(cur = newpvt(t))) { + if ((t->dst_codec.sample_rate == ast_format_get_sample_rate(dst)) && (t->dst_codec.type == ast_format_get_type(dst)) && (!strcmp(t->dst_codec.name, ast_format_get_name(dst)))) { + explicit_dst = dst; + } + if (!(cur = newpvt(t, explicit_dst))) { ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n", ast_format_get_name(src), ast_format_get_name(dst)); if (head) { @@ -638,7 +659,7 @@ static void generate_computational_cost(struct ast_translator *t, int seconds) return; } - pvt = newpvt(t); + pvt = newpvt(t, NULL); if (!pvt) { ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name); t->comp_cost = 999999; From 1bca90fcbe7d3581b9c568361267faf488141868 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 19 Nov 2015 09:40:24 -0600 Subject: [PATCH 0033/1578] res/res_pjsip_outbound_registration: Apply configuration on object type load When Asterisk is configured to use a dynamic sorcery backend (such as res_sorcery_astdb) with 'registration' objects, it will fail to create the internal state objects associated with the registration objects on module load. This is due to nothing actually querying for the specific objects and calling their sorcery apply handler during module load. This patch fixes that by calling get_registrations in the sorcery observer's object_type_loaded handler. Doing this causes the sorcery backends to be asked for the current state of all registration objects, which causes the apply handler to be called and the internal run-time state to be created. ASTERISK-25575 #close Change-Id: Ie9306e797098c6d4da7bcf4a5434a15891508b23 --- res/res_pjsip_outbound_registration.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 7ff5f1619bf..7b125334a87 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1846,6 +1846,13 @@ static void registration_loaded_observer(const char *name, const struct ast_sorc return; } + /* + * Refresh the current configured registrations. We don't need to hold + * onto the objects, as the apply handler will cause their states to + * be created appropriately. + */ + ao2_cleanup(get_registrations()); + /* Now to purge dead registrations. */ ao2_callback(states, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, check_state, NULL); ao2_ref(states, -1); From d2b141c79f2bd9f117bf657662ffdb99b1c9223e Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 20 Nov 2015 21:07:27 -0600 Subject: [PATCH 0034/1578] res/res_pjsip_t38: Add debug statements This patch adds some debug statements to res_pjsip_t38. These statements help to determine which SDP negotiation callbacks are being executed, and, when a particular callback exits, why a callback may not have applied its logic to the local or remote SDP. Change-Id: I61b3fb9183b7ebbb5da8e9f48b59a5d9d7042d77 --- res/res_pjsip_t38.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 40899bf512e..dde68781955 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -264,6 +264,7 @@ static int t38_initialize_session(struct ast_sip_session *session, struct ast_si ast_udptl_set_error_correction_scheme(session_media->udptl, session->endpoint->media.t38.error_correction); ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat); ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->media.t38.maxdatagram); + ast_debug(3, "UDPTL initialized on session for %s\n", ast_channel_name(session->channel)); return 0; } @@ -630,10 +631,12 @@ static enum ast_sip_session_sdp_stream_defer defer_incoming_sdp_stream( struct t38_state *state; if (!session->endpoint->media.t38.enabled) { + ast_debug(3, "Not deferring incoming SDP stream: T.38 not enabled on %s\n", ast_channel_name(session->channel)); return AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED; } if (t38_initialize_session(session, session_media)) { + ast_debug(3, "Not deferring incoming SDP stream: Failed to initialize UDPTL on %s\n", ast_channel_name(session->channel)); return AST_SIP_SESSION_SDP_DEFER_ERROR; } @@ -646,6 +649,7 @@ static enum ast_sip_session_sdp_stream_defer defer_incoming_sdp_stream( /* If they are initiating the re-invite we need to defer responding until later */ if (session->t38state == T38_DISABLED) { t38_change_state(session, session_media, state, T38_PEER_REINVITE); + ast_debug(3, "Deferring incoming SDP stream on %s for peer re-invite\n", ast_channel_name(session->channel)); return AST_SIP_SESSION_SDP_DEFER_NEEDED; } @@ -661,6 +665,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); if (!session->endpoint->media.t38.enabled) { + ast_debug(3, "Declining; T.38 not enabled on session\n"); return -1; } @@ -669,6 +674,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct } if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) { + ast_debug(3, "Declining; T.38 state is rejected or declined\n"); t38_change_state(session, session_media, state, T38_DISABLED); return -1; } @@ -678,6 +684,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct /* Ensure that the address provided is valid */ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) { /* The provided host was actually invalid so we error out this negotiation */ + ast_debug(3, "Declining; provided host is invalid\n"); return -1; } @@ -685,6 +692,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) || (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) { /* The address does not match configured */ + ast_debug(3, "Declining, provided host does not match configured address family\n"); return -1; } @@ -713,13 +721,16 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as pj_str_t stmp; if (!session->endpoint->media.t38.enabled) { + ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n"); return 1; } else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) && (session->t38state != T38_ENABLED)) { + ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n"); return 1; } else if (!(state = t38_state_get_or_alloc(session))) { return -1; } else if (t38_initialize_session(session, session_media)) { + ast_debug(3, "Not creating outgoing SDP stream: Failed to initialize T.38 session\n"); return -1; } @@ -738,6 +749,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } if (ast_strlen_zero(hostip)) { + ast_debug(3, "Not creating outgoing SDP stream: no known host IP\n"); return -1; } @@ -805,6 +817,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a struct t38_state *state; if (!session_media->udptl) { + ast_debug(3, "Not applying negotiated SDP stream: no UDTPL session\n"); return 0; } @@ -817,6 +830,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a /* Ensure that the address provided is valid */ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) { /* The provided host was actually invalid so we error out this negotiation */ + ast_debug(3, "Not applying negotiated SDP stream: failed to resolve remote stream host\n"); return -1; } From 9315a93757e2f78d5d54e9363a45bc8e1cba7f33 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 22 Oct 2015 09:44:43 -0500 Subject: [PATCH 0035/1578] main/cli: Use proper string methods to check existence of context/exten/app Because the context, extension, and application are stored in stringfields, checking for them being NULL doesn't work so well. This patch uses the appropriate string library call, ast_strlen_zero, to see if there is a value in the context/exten/app values. Change-Id: Ie09623bfdf35f5a8d3b23dd596647fe3c97b9a23 --- main/cli.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main/cli.c b/main/cli.c index b3d4cac3dcd..917305594a9 100644 --- a/main/cli.c +++ b/main/cli.c @@ -1076,10 +1076,12 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar char locbuf[40] = "(None)"; char appdata[40] = "(None)"; - if (!cs->context && !cs->exten) + if (!ast_strlen_zero(cs->context) && !ast_strlen_zero(cs->exten)) { snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->exten, cs->context, cs->priority); - if (cs->appl) + } + if (!ast_strlen_zero(cs->appl)) { snprintf(appdata, sizeof(appdata), "%s(%s)", cs->appl, S_OR(cs->data, "")); + } ast_cli(a->fd, FORMAT_STRING, cs->name, locbuf, ast_state2str(cs->state), appdata); } } From 726ee873a6d88a133cf6d75fc97fb1af6af09c52 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 20 Nov 2015 21:08:49 -0600 Subject: [PATCH 0036/1578] chan_pjsip: Handle T.38 faxes with direct media bridges When a channel is in a direct media bridge, a re-INVITE may arrive that forces Asterisk to re-negotiate the media to a T.38 fax. When this occurs, the bridge must change its technology to a simple bridge, and re-INVITE the media back to Asterisk. Generally, this logic mostly already exists in Asterisk. However, prior to this patch, there were a few bugs: (1) The T.38 framehook currently prevents a channel capable of T.38 faxes from ever entering into a direct media bridge. This applies even when the only media being passed over the channel is audio. This patch fixes this bug by having the framehook specify that it defers caring about any frame type. This allows the channels to enter into a direct media bridge, which will be broken when a re-INVITE is received. (2) When a re-INVITE is received, nothing instructed the bridging layer to re-inspect the allowed bridging technology. This now occurs when either a re-INVITE is received from a peer, or when a response is received from the far end (that is, when the T.38 state changes to either T38_PEER_REINVITE or T38_LOCAL_REINVITE). (3) chan_pjsip needs to do a small amount of work to prevent a direct media bridge from being chosen when a T.38 session is in progress. When a T.38 session supplement has a t38 datastore - which is added when we detect we should start thinking about T.38 on a channel - we now refuse a native RTP bridge. (4) When a BYE request is received, we don't terminate the T.38 session. If the other side of a T.38 fax survives the hangup (due to the 'g' flag in Dial, for example), we don't currently re-INVITE the media on the other channel back to audio. This patch now has res_pjsip_t38 intercept BYE requests and inform the far side that the T.38 session is terminated. This naturally causes the correct re-INVITEs to be sent. ASTERISK-25582 Change-Id: Iabd6aa578e633d16e6b9f342091264e4324a79eb --- channels/chan_pjsip.c | 7 ++++++ res/res_pjsip_t38.c | 53 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index c98be356543..32291e54c22 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -162,11 +162,18 @@ static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); struct chan_pjsip_pvt *pvt; struct ast_sip_endpoint *endpoint; + struct ast_datastore *datastore; if (!channel || !channel->session || !(pvt = channel->pvt) || !pvt->media[SIP_MEDIA_AUDIO]->rtp) { return AST_RTP_GLUE_RESULT_FORBID; } + datastore = ast_sip_session_get_datastore(channel->session, "t38"); + if (datastore) { + ao2_ref(datastore, -1); + return AST_RTP_GLUE_RESULT_FORBID; + } + endpoint = channel->session->endpoint; *instance = pvt->media[SIP_MEDIA_AUDIO]->rtp; diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index dde68781955..85feedc068d 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -161,6 +161,9 @@ static void t38_change_state(struct ast_sip_session *session, struct ast_sip_ses parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl); parameters.request_response = AST_T38_REQUEST_NEGOTIATE; ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel)); + + /* Inform the bridge the channel is in that it needs to be reconfigured */ + ast_channel_set_unbridged(session->channel, 1); break; case T38_ENABLED: parameters = state->their_parms; @@ -177,7 +180,8 @@ static void t38_change_state(struct ast_sip_session *session, struct ast_sip_ses } break; case T38_LOCAL_REINVITE: - /* wait until we get a peer response before responding to local reinvite */ + /* Inform the bridge the channel is in that it needs to be reconfigured */ + ast_channel_set_unbridged(session->channel, 1); break; case T38_MAX_ENUM: /* Well, that shouldn't happen */ @@ -463,6 +467,11 @@ static void t38_masq(void *data, int framehook_id, ast_framehook_detach(new_chan, framehook_id); } +static int t38_consume(void *data, enum ast_frame_type type) +{ + return 0; +} + static const struct ast_datastore_info t38_framehook_datastore = { .type = "T38 framehook", }; @@ -475,6 +484,7 @@ static void t38_attach_framehook(struct ast_sip_session *session) static struct ast_framehook_interface hook = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = t38_framehook, + .consume_cb = t38_consume, .chan_fixup_cb = t38_masq, .chan_breakdown_cb = t38_masq, }; @@ -560,6 +570,41 @@ static struct ast_sip_session_supplement t38_supplement = { .outgoing_request = t38_outgoing_invite_request, }; +static int t38_incoming_bye_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) +{ + struct ast_datastore *datastore; + struct ast_sip_session_media *session_media; + + if (!session->channel) { + return 0; + } + + datastore = ast_sip_session_get_datastore(session, "t38"); + if (!datastore) { + return 0; + } + + session_media = ao2_find(session->media, "image", OBJ_KEY); + if (!session_media) { + ao2_ref(datastore, -1); + return 0; + } + + t38_change_state(session, session_media, datastore->data, T38_REJECTED); + + ao2_ref(datastore, -1); + ao2_ref(session_media, -1); + + return 0; +} + +/*! \brief Supplement for handling a remote termination of T.38 state */ +static struct ast_sip_session_supplement t38_bye_supplement = { + .method = "BYE", + .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1, + .incoming_request = t38_incoming_bye_request, +}; + /*! \brief Parse a T.38 image stream and store the attribute information */ static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream) @@ -889,6 +934,7 @@ static int unload_module(void) { ast_sip_session_unregister_sdp_handler(&image_sdp_handler, "image"); ast_sip_session_unregister_supplement(&t38_supplement); + ast_sip_session_unregister_supplement(&t38_bye_supplement); return 0; } @@ -915,6 +961,11 @@ static int load_module(void) goto end; } + if (ast_sip_session_register_supplement(&t38_bye_supplement)) { + ast_log(LOG_ERROR, "Unable to register T.38 BYE session supplement\n"); + goto end; + } + if (ast_sip_session_register_sdp_handler(&image_sdp_handler, "image")) { ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n"); goto end; From 97d7b344de46236d153cdcc162371178c7b39854 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 18 Nov 2015 10:05:07 -0600 Subject: [PATCH 0037/1578] res_statsd: Add functions that support variable arguments Often, the metric names of statistics we are generating for StatsD have some dynamic component to them. This can be the name of a particular resource, or some internal status label in Asterisk. With the current set of functions, callers of the statsd API must first build the metric name themselves, then pass this to the API functions. This results in a large amount of boilerplate code and usage of either fixed length static buffers or dynamic memory allocation, neither of which is desireable. This patch adds two new functions to the StatsD API that support a printf style format specifier for constructing the metric name. A dynamic string, allocated in threadstorage, is used to build the metric name. This eases the burden on users of the StatsD API. Change-Id: If533c72d1afa26d807508ea48b4d8c7b32f414ea --- include/asterisk/statsd.h | 48 +++++++++++++++++++++++++++++++++++++-- res/res_statsd.c | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/include/asterisk/statsd.h b/include/asterisk/statsd.h index a04407f89ba..c4ecce8f600 100644 --- a/include/asterisk/statsd.h +++ b/include/asterisk/statsd.h @@ -57,9 +57,31 @@ AST_OPTIONAL_API(void, ast_statsd_log_string, (const char *metric_name, /*! * \brief Send a stat to the configured statsd server. + * \since 13.7.0 * - * The is the most flexible function for sending a message to the statsd server, - * but also the least easy to use. See ast_statsd_log() or + * This is the most flexible function for sending a message to the statsd + * server. In addition to allowing the string value and sample rate to be specified, + * the metric_name can be formed as a printf style string with variable + * arguments. + * + * \param metric_name Format string (UTF-8) specifying the name of the metric. + * \param metric_type Type of metric to send. + * \param value Value to send. + * \param sample_rate Percentage of samples to send. + * + * Example Usage: + * \code + * ast_statsd_log_string_va(AST_STATSD_GUAGE, "+1", 1.0, "endpoints.states.%s", state_name); + * \endcode + */ +AST_OPTIONAL_API_ATTR(void, format(printf, 1, 5), ast_statsd_log_string_va, + (const char *metric_name, const char *metric_type, const char *value, double sample_rate, ...), {}); + +/*! + * \brief Send a stat to the configured statsd server. + * + * The is nearly the most flexible function for sending a message to the statsd + * server, but also the least easy to use. See ast_statsd_log() or * ast_statsd_log_sample() for a slightly more convenient interface. * * \param metric_name String (UTF-8) name of the metric. @@ -71,6 +93,28 @@ AST_OPTIONAL_API(void, ast_statsd_log_string, (const char *metric_name, AST_OPTIONAL_API(void, ast_statsd_log_full, (const char *metric_name, const char *metric_type, intmax_t value, double sample_rate), {}); +/*! + * \brief Send a stat to the configured statsd server. + * \since 13.7.0 + * + * This is the most flexible function for sending a message to the statsd + * server. In addition to allowing the value and sample rate to be specified, + * the metric_name can be formed as a printf style string with variable + * arguments. + * + * \param metric_name Format string (UTF-8) specifying the name of the metric. + * \param metric_type Type of metric to send. + * \param value Value to send. + * \param sample_rate Percentage of samples to send. + * + * Example Usage: + * \code + * ast_statsd_log_full_va(AST_STATSD_TIMER, rtt, 1.0, "endpoint.%s.rtt", endpoint_name); + * \endcode + */ +AST_OPTIONAL_API_ATTR(void, format(printf, 1, 5), ast_statsd_log_full_va, + (const char *metric_name, const char *metric_type, intmax_t value, double sample_rate, ...), {}); + /*! * \brief Send a stat to the configured statsd server. * \param metric_name String (UTF-8) name of the metric. diff --git a/res/res_statsd.c b/res/res_statsd.c index 8bf74db098c..f3a64e0f8ef 100644 --- a/res/res_statsd.c +++ b/res/res_statsd.c @@ -160,6 +160,54 @@ void AST_OPTIONAL_API_NAME(ast_statsd_log_full)(const char *metric_name, } +AST_THREADSTORAGE(statsd_buf); + +void AST_OPTIONAL_API_NAME(ast_statsd_log_string_va)(const char *metric_name, + const char *metric_type, const char *value, double sample_rate, ...) +{ + struct ast_str *buf; + va_list ap; + int res; + + buf = ast_str_thread_get(&statsd_buf, 128); + if (!buf) { + return; + } + + va_start(ap, sample_rate); + res = ast_str_set_va(&buf, 0, metric_name, ap); + va_end(ap); + + if (res == AST_DYNSTR_BUILD_FAILED) { + return; + } + + ast_statsd_log_string(ast_str_buffer(buf), metric_type, value, sample_rate); +} + +void AST_OPTIONAL_API_NAME(ast_statsd_log_full_va)(const char *metric_name, + const char *metric_type, intmax_t value, double sample_rate, ...) +{ + struct ast_str *buf; + va_list ap; + int res; + + buf = ast_str_thread_get(&statsd_buf, 128); + if (!buf) { + return; + } + + va_start(ap, sample_rate); + res = ast_str_set_va(&buf, 0, metric_name, ap); + va_end(ap); + + if (res == AST_DYNSTR_BUILD_FAILED) { + return; + } + + ast_statsd_log_full(ast_str_buffer(buf), metric_type, value, sample_rate); +} + void AST_OPTIONAL_API_NAME(ast_statsd_log)(const char *metric_name, const char *metric_type, intmax_t value) { From 482f2fc5ff67b3a7fd26b5df174ec847c05f4643 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 13 Nov 2015 10:34:03 -0600 Subject: [PATCH 0038/1578] res/res_pjsip_outbound_registration: Add registration statistics for StatsD This patch adds outbound registration statistics for StatsD. This includes the following: * A GUAGE metric for the overall count of outbound registrations. * A GUAGE metric for each state an outbound registration can be in. As the outbound registrations change state, the overall count of how many outbound registrations are in the particular state is changed. These statistics are particularly useful for systems with a large number of SIP trunks, and where measuring the change in state of the trunks is useful for monitoring. ASTERISK-25571 Change-Id: Iba6ff248f5d1c1e01acbb63e9f0da1901692eb37 --- CHANGES | 10 ++++++ res/res_pjsip_outbound_registration.c | 47 +++++++++++++++++++++------ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 6e96515c3a6..8958210a1f3 100644 --- a/CHANGES +++ b/CHANGES @@ -227,6 +227,16 @@ Dialplan Functions the 'hold' raised by a channel to be intercepted and converted into an event instead. +res_pjsip_outbound_registration +------------------------------- + * If res_statsd is loaded and a StatsD server is configured, basic statistics + regarding the state of outbound registrations will now be emitted. This + includes: + - A GUAGE statistic for the overall number of outbound registrations, i.e.: + PJSIP.registrations.count + - A GUAGE statistic for the overall number of outbound registrations in a + particular state, e.g.: + PJSIP.registrations.state.Registered res_pjsip ------------------ diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index e6cd9618314..e6c3cfecca9 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -35,6 +35,7 @@ #include "asterisk/stasis_system.h" #include "asterisk/threadstorage.h" #include "asterisk/threadpool.h" +#include "asterisk/statsd.h" #include "res_pjsip/include/res_pjsip_private.h" /*** DOCUMENTATION @@ -612,6 +613,19 @@ static void schedule_registration(struct sip_outbound_registration_client_state } } +static void update_client_state_status(struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status) +{ + if (client_state->status == status) { + return; + } + + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "-1", 1.0, + sip_outbound_registration_status_str(client_state->status)); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "+1", 1.0, + sip_outbound_registration_status_str(status)); + client_state->status = status; +} + /*! \brief Callback function for unregistering (potentially) and destroying state */ static int handle_client_state_destruction(void *data) { @@ -645,7 +659,7 @@ static int handle_client_state_destruction(void *data) (int) info.server_uri.slen, info.server_uri.ptr, (int) info.client_uri.slen, info.client_uri.ptr); - client_state->status = SIP_REGISTRATION_STOPPING; + update_client_state_status(client_state, SIP_REGISTRATION_STOPPING); client_state->destroy = 1; if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS && registration_client_send(client_state, tdata) == PJ_SUCCESS) { @@ -664,7 +678,7 @@ static int handle_client_state_destruction(void *data) client_state->client = NULL; } - client_state->status = SIP_REGISTRATION_STOPPED; + update_client_state_status(client_state, SIP_REGISTRATION_STOPPED); ast_sip_auth_vector_destroy(&client_state->outbound_auths); ao2_ref(client_state, -1); @@ -726,7 +740,7 @@ static int sip_outbound_registration_is_temporal(unsigned int code, static void schedule_retry(struct registration_response *response, unsigned int interval, const char *server_uri, const char *client_uri) { - response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); schedule_registration(response->client_state, interval); if (response->rdata) { @@ -800,7 +814,7 @@ static int handle_registration_response(void *data) /* If the registration went fine simply reschedule registration for the future */ ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri); - response->client_state->status = SIP_REGISTRATION_REGISTERED; + update_client_state_status(response->client_state, SIP_REGISTRATION_REGISTERED); response->client_state->retries = 0; next_registration_round = response->expiration - REREGISTER_BUFFER_TIME; if (next_registration_round < 0) { @@ -810,7 +824,7 @@ static int handle_registration_response(void *data) schedule_registration(response->client_state, next_registration_round); } else { ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri); - response->client_state->status = SIP_REGISTRATION_UNREGISTERED; + update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED); } } else if (response->client_state->destroy) { /* We need to deal with the pending destruction instead. */ @@ -821,7 +835,7 @@ static int handle_registration_response(void *data) && sip_outbound_registration_is_temporal(response->code, response->client_state)) { if (response->client_state->retries == response->client_state->max_retries) { /* If we received enough temporal responses to exceed our maximum give up permanently */ - response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT); ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n", server_uri, client_uri); } else { @@ -834,7 +848,7 @@ static int handle_registration_response(void *data) && response->client_state->forbidden_retry_interval && response->client_state->retries < response->client_state->max_retries) { /* A forbidden response retry interval is configured and there are retries remaining */ - response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); response->client_state->retries++; schedule_registration(response->client_state, response->client_state->forbidden_retry_interval); ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", @@ -842,14 +856,14 @@ static int handle_registration_response(void *data) } else if (response->client_state->fatal_retry_interval && response->client_state->retries < response->client_state->max_retries) { /* Some kind of fatal failure response received, so retry according to configured interval */ - response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); response->client_state->retries++; schedule_registration(response->client_state, response->client_state->fatal_retry_interval); ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", response->code, server_uri, client_uri, response->client_state->fatal_retry_interval); } else { /* Finally if there's no hope of registering give up */ - response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT); if (response->rdata) { ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n", response->code, server_uri, client_uri); @@ -934,7 +948,6 @@ static void sip_outbound_registration_state_destroy(void *obj) ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n", state->registration->server_uri, state->registration->client_uri); - ao2_cleanup(state->registration); if (!state->client_state) { @@ -953,6 +966,10 @@ static void sip_outbound_registration_client_state_destroy(void *obj) { struct sip_outbound_registration_client_state *client_state = obj; + ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GUAGE, "-1", 1.0); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "-1", 1.0, + sip_outbound_registration_status_str(client_state->status)); + ast_taskprocessor_unreference(client_state->serializer); } @@ -981,6 +998,10 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a state->client_state->timer.user_data = state->client_state; state->client_state->timer.cb = sip_outbound_registration_timer_cb; + ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GUAGE, "+1", 1.0); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "+1", 1.0, + sip_outbound_registration_status_str(state->client_state->status)); + state->registration = ao2_bump(registration); return state; } @@ -2013,6 +2034,12 @@ static int load_module(void) ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register); ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations); + /* Clear any previous statsd gauges in case we weren't shutdown cleanly */ + ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GUAGE, 0); + ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GUAGE, 0); + ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GUAGE, 0); + ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GUAGE, 0); + /* Load configuration objects */ ast_sorcery_load_object(ast_sip_get_sorcery(), "registration"); From 75d90a9951b6b679d475335698544540089750a1 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 18 Nov 2015 10:07:09 -0600 Subject: [PATCH 0039/1578] res_pjsip/pjsip_options: Add StatsD statistics for PJSIP contacts This patch adds the ability to send StatsD statistics related to the state of PJSIP contacts. This includes: * A GUAGE statistic measuring the count of contacts in a particular state. This measures how many contacts are reachable, unreachable, etc. * The RTT time for each contact, if those contacts are qualified. This provides StatsD engines useful time-based data about each contact. ASTERISK-25571 Change-Id: Ib8378d73afedfc622be0643b87c542557e0b332c --- CHANGES | 8 ++++++++ res/res_pjsip/location.c | 12 ++++++++++++ res/res_pjsip/pjsip_options.c | 16 ++++++++++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 6e96515c3a6..6adba3b00e2 100644 --- a/CHANGES +++ b/CHANGES @@ -233,6 +233,14 @@ res_pjsip * The ability to use "like" has been added to the pjsip list and show CLI commands. For instance: CLI> pjsip list endpoints like abc + * If res_statsd is loaded and a StatsD server is configured, basic statistics + regarding the state of PJSIP contacts will not be emitted. This includes: + - A GUAGE statistic for the overall number of contacts in a particular + state, e.g.: + PJSIP.contacts.states.Reachable + - A TIMER statistic for the RTT time for each qualified contact, e.g.: + PJSIP.contacts.alice@@127.0.0.1:5061.rtt + func_callerid ------------------- * CALLERID(pres) is now documented as a valid alternative to setting both diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index eef1d43d2cc..9cc7f1629d5 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -26,6 +26,7 @@ #include "asterisk/sorcery.h" #include "include/res_pjsip_private.h" #include "asterisk/res_pjsip_cli.h" +#include "asterisk/statsd.h" /*! \brief Destructor for AOR */ static void aor_destroy(void *obj) @@ -940,6 +941,8 @@ static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object int ast_sip_initialize_sorcery_location(void) { struct ast_sorcery *sorcery = ast_sip_get_sorcery(); + int i; + ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar"); ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor"); @@ -1006,6 +1009,15 @@ int ast_sip_initialize_sorcery_location(void) ast_sip_register_cli_formatter(aor_formatter); ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + /* + * Reset StatsD gauges in case we didn't shut down cleanly. + * Note that this must done here, as contacts will create the contact_status + * object before PJSIP options handling is initialized. + */ + for (i = 0; i < REMOVED; i++) { + ast_statsd_log_full_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, 0, 1.0, ast_sip_get_contact_status_label(i)); + } + return 0; } diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index d8e3779e578..c7579fdc142 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -29,6 +29,7 @@ #include "asterisk/cli.h" #include "asterisk/time.h" #include "asterisk/test.h" +#include "asterisk/statsd.h" #include "include/res_pjsip_private.h" #define DEFAULT_LANGUAGE "en" @@ -113,6 +114,9 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const return NULL; } + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, + "+1", 1.0, ast_sip_get_contact_status_label(status->status)); + return status; } @@ -143,6 +147,12 @@ static void update_contact_status(const struct ast_sip_contact *contact, update->last_status = status->status; update->status = value; + if (update->last_status != update->status) { + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, + "-1", 1.0, ast_sip_get_contact_status_label(update->last_status)); + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, + "+1", 1.0, ast_sip_get_contact_status_label(update->status)); + } /* if the contact is available calculate the rtt as the diff between the last start time and "now" */ @@ -151,10 +161,12 @@ static void update_contact_status(const struct ast_sip_contact *contact, update->rtt_start = ast_tv(0, 0); + ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER, + update->rtt / 1000, 1.0, ast_sorcery_object_get_id(update)); ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", "Contact: %s\r\n" - "Status: %s\r\n" - "RTT: %" PRId64, + "Status: %s\r\n" + "RTT: %" PRId64, ast_sorcery_object_get_id(update), ast_sip_get_contact_status_label(update->status), update->rtt); From 9ca652f1b913607a9ab181a9950d091fc56554f3 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 23 Nov 2015 14:27:27 -0600 Subject: [PATCH 0040/1578] res_sorcery_realtime.c: Fix crash from NULL sorcery object type. If the sorcery object type is not found a NULL is returned. Unfortunately, sorcery_realtime_filter_objectset() will crash after complaining about not finding the object type and saying to expect errors. * Use ao2_cleanup() instead of ao2_ref() to prevent the crash. ASTERISK-25165 Reported by Corey Farrell Change-Id: Ic3b64453ea3058cb68d5c26d97d4fe7b8eea2e97 --- res/res_sorcery_realtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index b2df2981491..8807c01961a 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -142,7 +142,7 @@ static struct ast_variable *sorcery_realtime_filter_objectset(struct ast_variabl } } - ao2_ref(object_type, -1); + ao2_cleanup(object_type); return objectset; } From ee9c1147475c1dde32c48a502817622b92fb0584 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 18 Nov 2015 09:43:08 -0600 Subject: [PATCH 0041/1578] res/res_endpoint_stats: Add module to emit endpoint StatsD statistics This patch adds a module that emits StatsD statistics about Asterisk endpoints. This includes: * A GAUGE statistic for endpoint states, tracking how many endpoints are in a particular state. * A GAUGE statistic for each endpoint, counting the number of channels currently associated with an endpoint. ASTERISK-25572 Change-Id: If7e1333c5aeda8d136850b30c2101c0ee1c97305 --- CHANGES | 12 +++ res/res_endpoint_stats.c | 157 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 res/res_endpoint_stats.c diff --git a/CHANGES b/CHANGES index 6e96515c3a6..754beb704a8 100644 --- a/CHANGES +++ b/CHANGES @@ -243,6 +243,18 @@ func_callerid The same applies to CONNECTEDLINE(pres), REDIRECTING(orig-pres), REDIRECTING(to-pres) and REDIRECTING(from-pres). +res_endpoint_stats +------------------- + * A new module that emits StatsD statistics regarding Asterisk endpoints. + This includes a total count of the number of endpoints, the count of the + number of endpoints in the technology agnosti state of the endpoint - + online or offline - as well as the number of channels associated with each + endpoint. These are recorded as three differeng GUAGE statistics: + - endpoints.count + - endpoints.state.{unknown|offline|online} + - endpoints.{tech}.{resource}.channels + + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.5.0 to Asterisk 13.6.0 ------------ ------------------------------------------------------------------------------ diff --git a/res/res_endpoint_stats.c b/res/res_endpoint_stats.c new file mode 100644 index 00000000000..8accfd6afd8 --- /dev/null +++ b/res/res_endpoint_stats.c @@ -0,0 +1,157 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Digium, Inc. + * + * Matthew Jordan + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \brief Statsd Endpoint stats. + * + * This module subscribes to Stasis endpoints and send statistics + * based on their state. + * + * \author Matthew Jordan + * \since 13.7.0 + */ + +/*** MODULEINFO + res_statsd + no + extended + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/module.h" +#include "asterisk/stasis_endpoints.h" +#include "asterisk/stasis_message_router.h" +#include "asterisk/statsd.h" + +/*! Stasis message router */ +static struct stasis_message_router *router; + +static void update_endpoint_state(struct ast_endpoint_snapshot *snapshot, const char *delta) +{ + switch (snapshot->state) { + case AST_ENDPOINT_UNKNOWN: + ast_statsd_log_string("endpoints.state.unknown", AST_STATSD_GUAGE, delta, 1.0); + break; + case AST_ENDPOINT_OFFLINE: + ast_statsd_log_string("endpoints.state.offline", AST_STATSD_GUAGE, delta, 1.0); + break; + case AST_ENDPOINT_ONLINE: + ast_statsd_log_string("endpoints.state.online", AST_STATSD_GUAGE, delta, 1.0); + break; + } +} + +static void handle_endpoint_update(struct ast_endpoint_snapshot *old_snapshot, struct ast_endpoint_snapshot *new_snapshot) +{ + if (!old_snapshot && new_snapshot) { + ast_statsd_log_string("endpoints.count", AST_STATSD_GUAGE, "+1", 1.0); + update_endpoint_state(new_snapshot, "+1"); + } else if (old_snapshot && !new_snapshot) { + ast_statsd_log_string("endpoints.count", AST_STATSD_GUAGE, "-1", 1.0); + update_endpoint_state(old_snapshot, "-1"); + } else { + if (old_snapshot->state != new_snapshot->state) { + update_endpoint_state(old_snapshot, "-1"); + update_endpoint_state(new_snapshot, "+1"); + } + ast_statsd_log_full_va("endpoints.%s.%s.channels", AST_STATSD_GUAGE, new_snapshot->num_channels, 1.0, + new_snapshot->tech, new_snapshot->resource); + } +} + +static void cache_update_cb(void *data, struct stasis_subscription *sub, + struct stasis_message *message) +{ + struct stasis_cache_update *update = stasis_message_data(message); + struct ast_endpoint_snapshot *old_snapshot; + struct ast_endpoint_snapshot *new_snapshot; + + if (ast_endpoint_snapshot_type() != update->type) { + return; + } + + old_snapshot = stasis_message_data(update->old_snapshot); + new_snapshot = stasis_message_data(update->new_snapshot); + + handle_endpoint_update(old_snapshot, new_snapshot); +} + +static int dump_cache_load(void *obj, void *arg, int flags) +{ + struct stasis_message *msg = obj; + struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg); + + handle_endpoint_update(NULL, snapshot); + + return 0; +} + +static int dump_cache_unload(void *obj, void *arg, int flags) +{ + struct stasis_message *msg = obj; + struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg); + + handle_endpoint_update(snapshot, NULL); + + return 0; +} + +static int load_module(void) +{ + struct ao2_container *endpoints; + + router = stasis_message_router_create(ast_endpoint_topic_all_cached()); + if (!router) { + return AST_MODULE_LOAD_FAILURE; + } + stasis_message_router_add(router, stasis_cache_update_type(), cache_update_cb, NULL); + + endpoints = stasis_cache_dump(ast_endpoint_cache(), ast_endpoint_snapshot_type()); + if (endpoints) { + ao2_callback(endpoints, OBJ_MULTIPLE | OBJ_NODATA | OBJ_NOLOCK, dump_cache_load, NULL); + ao2_ref(endpoints, -1); + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + struct ao2_container *endpoints; + + endpoints = stasis_cache_dump(ast_endpoint_cache(), ast_endpoint_snapshot_type()); + if (endpoints) { + ao2_callback(endpoints, OBJ_MULTIPLE | OBJ_NODATA | OBJ_NOLOCK, dump_cache_unload, NULL); + ao2_ref(endpoints, -1); + } + + stasis_message_router_unsubscribe_and_join(router); + router = NULL; + + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Endpoint statistics", + .support_level = AST_MODULE_SUPPORT_EXTENDED, + .load = load_module, + .unload = unload_module, + .nonoptreq = "res_statsd" + ); From fb45130476bf2530a189eda5119dd0e817202ac1 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 24 Nov 2015 14:07:12 -0500 Subject: [PATCH 0042/1578] res_pjsip_notify: Fix CLI usage info The usage info for 'pjsip send notify' previously referenced the chan_sip configuration sip_notify.conf. Fix this to reference the correct configuration pjsip_notify.conf. ASTERISK-25590 #close Change-Id: I3898271a8e8a8b1db201741e790ebe2c6bf5cdea --- res/res_pjsip_notify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_notify.c b/res/res_pjsip_notify.c index 2396337ef30..6d524152c4f 100644 --- a/res/res_pjsip_notify.c +++ b/res/res_pjsip_notify.c @@ -840,7 +840,7 @@ static char *cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a e->usage = "Usage: pjsip send notify {endpoint|uri} [...]\n" " Send a NOTIFY request to an endpoint\n" - " Message types are defined in sip_notify.conf\n"; + " Message types are defined in pjsip_notify.conf\n"; return NULL; case CLI_GENERATE: if (a->argc > 4 && (!strcasecmp(a->argv[4], "uri"))) { From 91346b9fb7d8b6ec2c37ac796904a955a9caf89c Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Tue, 24 Nov 2015 13:54:54 -0600 Subject: [PATCH 0043/1578] Fixed some typos Fixes some minor typos in the CHANGES file, plus an embarrasing typo in the StatsD API. Change-Id: I9ca4858c64a4a07d2643b81baa64baebb27a4eb7 --- CHANGES | 10 +++++----- include/asterisk/statsd.h | 9 +++++++-- res/res_endpoint_stats.c | 12 ++++++------ res/res_pjsip/location.c | 2 +- res/res_pjsip/pjsip_options.c | 6 +++--- res/res_pjsip_outbound_registration.c | 20 ++++++++++---------- 6 files changed, 32 insertions(+), 27 deletions(-) diff --git a/CHANGES b/CHANGES index 5dc81aea61e..fb149ce870e 100644 --- a/CHANGES +++ b/CHANGES @@ -232,9 +232,9 @@ res_pjsip_outbound_registration * If res_statsd is loaded and a StatsD server is configured, basic statistics regarding the state of outbound registrations will now be emitted. This includes: - - A GUAGE statistic for the overall number of outbound registrations, i.e.: + - A GAUGE statistic for the overall number of outbound registrations, i.e.: PJSIP.registrations.count - - A GUAGE statistic for the overall number of outbound registrations in a + - A GAUGE statistic for the overall number of outbound registrations in a particular state, e.g.: PJSIP.registrations.state.Registered @@ -245,7 +245,7 @@ res_pjsip * If res_statsd is loaded and a StatsD server is configured, basic statistics regarding the state of PJSIP contacts will not be emitted. This includes: - - A GUAGE statistic for the overall number of contacts in a particular + - A GAUGE statistic for the overall number of contacts in a particular state, e.g.: PJSIP.contacts.states.Reachable - A TIMER statistic for the RTT time for each qualified contact, e.g.: @@ -265,9 +265,9 @@ res_endpoint_stats ------------------- * A new module that emits StatsD statistics regarding Asterisk endpoints. This includes a total count of the number of endpoints, the count of the - number of endpoints in the technology agnosti state of the endpoint - + number of endpoints in the technology agnostic state of the endpoint - online or offline - as well as the number of channels associated with each - endpoint. These are recorded as three differeng GUAGE statistics: + endpoint. These are recorded as three different GAUGE statistics: - endpoints.count - endpoints.state.{unknown|offline|online} - endpoints.{tech}.{resource}.channels diff --git a/include/asterisk/statsd.h b/include/asterisk/statsd.h index c4ecce8f600..4cbd213ad0d 100644 --- a/include/asterisk/statsd.h +++ b/include/asterisk/statsd.h @@ -29,7 +29,12 @@ #include "asterisk/optional_api.h" /*! An instantaneous measurement of a value. */ -#define AST_STATSD_GUAGE "g" +#define AST_STATSD_GAUGE "g" +/*! + * Embarrassingly, gauge was misspelled for quite some time. + * \deprecated You should spell gauge correctly. + */ +#define AST_STATSD_GUAGE AST_STATSD_GAUGE /*! A change in a value. */ #define AST_STATSD_COUNTER "c" /*! Measure of milliseconds. */ @@ -71,7 +76,7 @@ AST_OPTIONAL_API(void, ast_statsd_log_string, (const char *metric_name, * * Example Usage: * \code - * ast_statsd_log_string_va(AST_STATSD_GUAGE, "+1", 1.0, "endpoints.states.%s", state_name); + * ast_statsd_log_string_va(AST_STATSD_GAUGE, "+1", 1.0, "endpoints.states.%s", state_name); * \endcode */ AST_OPTIONAL_API_ATTR(void, format(printf, 1, 5), ast_statsd_log_string_va, diff --git a/res/res_endpoint_stats.c b/res/res_endpoint_stats.c index 8accfd6afd8..28e47d0d6f2 100644 --- a/res/res_endpoint_stats.c +++ b/res/res_endpoint_stats.c @@ -48,13 +48,13 @@ static void update_endpoint_state(struct ast_endpoint_snapshot *snapshot, const { switch (snapshot->state) { case AST_ENDPOINT_UNKNOWN: - ast_statsd_log_string("endpoints.state.unknown", AST_STATSD_GUAGE, delta, 1.0); + ast_statsd_log_string("endpoints.state.unknown", AST_STATSD_GAUGE, delta, 1.0); break; case AST_ENDPOINT_OFFLINE: - ast_statsd_log_string("endpoints.state.offline", AST_STATSD_GUAGE, delta, 1.0); + ast_statsd_log_string("endpoints.state.offline", AST_STATSD_GAUGE, delta, 1.0); break; case AST_ENDPOINT_ONLINE: - ast_statsd_log_string("endpoints.state.online", AST_STATSD_GUAGE, delta, 1.0); + ast_statsd_log_string("endpoints.state.online", AST_STATSD_GAUGE, delta, 1.0); break; } } @@ -62,17 +62,17 @@ static void update_endpoint_state(struct ast_endpoint_snapshot *snapshot, const static void handle_endpoint_update(struct ast_endpoint_snapshot *old_snapshot, struct ast_endpoint_snapshot *new_snapshot) { if (!old_snapshot && new_snapshot) { - ast_statsd_log_string("endpoints.count", AST_STATSD_GUAGE, "+1", 1.0); + ast_statsd_log_string("endpoints.count", AST_STATSD_GAUGE, "+1", 1.0); update_endpoint_state(new_snapshot, "+1"); } else if (old_snapshot && !new_snapshot) { - ast_statsd_log_string("endpoints.count", AST_STATSD_GUAGE, "-1", 1.0); + ast_statsd_log_string("endpoints.count", AST_STATSD_GAUGE, "-1", 1.0); update_endpoint_state(old_snapshot, "-1"); } else { if (old_snapshot->state != new_snapshot->state) { update_endpoint_state(old_snapshot, "-1"); update_endpoint_state(new_snapshot, "+1"); } - ast_statsd_log_full_va("endpoints.%s.%s.channels", AST_STATSD_GUAGE, new_snapshot->num_channels, 1.0, + ast_statsd_log_full_va("endpoints.%s.%s.channels", AST_STATSD_GAUGE, new_snapshot->num_channels, 1.0, new_snapshot->tech, new_snapshot->resource); } } diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 9cc7f1629d5..2e0d84b84a4 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1015,7 +1015,7 @@ int ast_sip_initialize_sorcery_location(void) * object before PJSIP options handling is initialized. */ for (i = 0; i < REMOVED; i++) { - ast_statsd_log_full_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, 0, 1.0, ast_sip_get_contact_status_label(i)); + ast_statsd_log_full_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, 0, 1.0, ast_sip_get_contact_status_label(i)); } return 0; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index c7579fdc142..d55a9958718 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -114,7 +114,7 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const return NULL; } - ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "+1", 1.0, ast_sip_get_contact_status_label(status->status)); return status; @@ -148,9 +148,9 @@ static void update_contact_status(const struct ast_sip_contact *contact, update->last_status = status->status; update->status = value; if (update->last_status != update->status) { - ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "-1", 1.0, ast_sip_get_contact_status_label(update->last_status)); - ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GUAGE, + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "+1", 1.0, ast_sip_get_contact_status_label(update->status)); } diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index e6c3cfecca9..88007d1d2fd 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -619,9 +619,9 @@ static void update_client_state_status(struct sip_outbound_registration_client_s return; } - ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "-1", 1.0, + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0, sip_outbound_registration_status_str(client_state->status)); - ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "+1", 1.0, + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0, sip_outbound_registration_status_str(status)); client_state->status = status; } @@ -966,8 +966,8 @@ static void sip_outbound_registration_client_state_destroy(void *obj) { struct sip_outbound_registration_client_state *client_state = obj; - ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GUAGE, "-1", 1.0); - ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "-1", 1.0, + ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0, sip_outbound_registration_status_str(client_state->status)); ast_taskprocessor_unreference(client_state->serializer); @@ -998,8 +998,8 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a state->client_state->timer.user_data = state->client_state; state->client_state->timer.cb = sip_outbound_registration_timer_cb; - ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GUAGE, "+1", 1.0); - ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "+1", 1.0, + ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0, sip_outbound_registration_status_str(state->client_state->status)); state->registration = ao2_bump(registration); @@ -2035,10 +2035,10 @@ static int load_module(void) ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations); /* Clear any previous statsd gauges in case we weren't shutdown cleanly */ - ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GUAGE, 0); - ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GUAGE, 0); - ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GUAGE, 0); - ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GUAGE, 0); + ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GAUGE, 0); + ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GAUGE, 0); + ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GAUGE, 0); + ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GAUGE, 0); /* Load configuration objects */ ast_sorcery_load_object(ast_sip_get_sorcery(), "registration"); From 03759c5587229b95204288e0969f928c20764a6e Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Wed, 25 Nov 2015 20:29:55 +0100 Subject: [PATCH 0044/1578] main: Slight refactor of main. Improve color situation. Several issues are addressed here: - main() is large, and half of it is only used if we're not rasterisk; fixed by spliting up the daemon part into a separate function. - Call ast_term_init from rasterisk as well. - Remove duplicate code reading/writing asterisk history file. - Attempt to tackle background color issues and color changes that occur. Tested by starting asterisk -c until the colors stopped changing at odd locations. - Remove unused term_prep() and term_prompt() functions. ASTERISK-25585 #close Change-Id: Ib641a0964c59ef9fe6f59efa8ccb481a9580c52f --- include/asterisk/term.h | 8 +-- main/asterisk.c | 123 ++++++++++++++++++++++------------------ main/term.c | 64 ++++----------------- 3 files changed, 83 insertions(+), 112 deletions(-) diff --git a/include/asterisk/term.h b/include/asterisk/term.h index 18d743b7607..f91b047816c 100644 --- a/include/asterisk/term.h +++ b/include/asterisk/term.h @@ -67,8 +67,8 @@ extern "C" { #define COLORIZE_FMT "%s%s%s" #define COLORIZE(fg, bg, str) ast_term_color(fg,bg),str,ast_term_reset() /*! \brief Maximum number of characters needed for a color escape sequence, - * plus a null char */ -#define AST_TERM_MAX_ESCAPE_CHARS 12 + * and another one for a trailing reset, plus a null char */ +#define AST_TERM_MAX_ESCAPE_CHARS 23 #define AST_TERM_MAX_ROTATING_BUFFERS 15 /*! \brief Colorize a specified string by adding terminal color codes @@ -137,10 +137,6 @@ char *term_strip(char *outbuf, const char *inbuf, int maxout); void term_filter_escapes(char *line); -char *term_prompt(char *outbuf, const char *inbuf, int maxout); - -const char *term_prep(void); - const char *term_end(void); const char *term_quit(void); diff --git a/main/asterisk.c b/main/asterisk.c index e0a87d6b159..93937afa974 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -373,9 +373,14 @@ struct console consoles[AST_MAX_CONNECTS]; char ast_defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE; -static int ast_el_add_history(char *); -static int ast_el_read_history(char *); -static int ast_el_write_history(char *); +static int ast_el_add_history(const char *); +static int ast_el_read_history(const char *); +static int ast_el_write_history(const char *); + +static void ast_el_read_default_histfile(void); +static void ast_el_write_default_histfile(void); + +static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup); struct _cfg_paths { char config_dir[PATH_MAX]; @@ -1965,13 +1970,7 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart) } if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) { - char filename[80] = ""; - if (getenv("HOME")) { - snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); - } - if (!ast_strlen_zero(filename)) { - ast_el_write_history(filename); - } + ast_el_write_default_histfile(); if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) { /* Only end if we are the consolethread, otherwise there's a race with that thread. */ if (el != NULL) { @@ -2202,7 +2201,7 @@ static void console_verboser(const char *s) } } -static int ast_all_zeros(char *s) +static int ast_all_zeros(const char *s) { while (*s) { if (*s > 32) @@ -2213,7 +2212,7 @@ static int ast_all_zeros(char *s) } /* This is the main console CLI command handler. Run by the main() thread. */ -static void consolehandler(char *s) +static void consolehandler(const char *s) { printf("%s", term_end()); fflush(stdout); @@ -2231,7 +2230,7 @@ static void consolehandler(char *s) ast_cli_command(STDOUT_FILENO, s); } -static int remoteconsolehandler(char *s) +static int remoteconsolehandler(const char *s) { int ret = 0; @@ -3147,7 +3146,7 @@ static int ast_el_initialize(void) #define MAX_HISTORY_COMMAND_LENGTH 256 -static int ast_el_add_history(char *buf) +static int ast_el_add_history(const char *buf) { HistEvent ev; char *stripped_buf; @@ -3169,7 +3168,7 @@ static int ast_el_add_history(char *buf) return history(el_hist, &ev, H_ENTER, stripped_buf); } -static int ast_el_write_history(char *filename) +static int ast_el_write_history(const char *filename) { HistEvent ev; @@ -3179,7 +3178,7 @@ static int ast_el_write_history(char *filename) return (history(el_hist, &ev, H_SAVE, filename)); } -static int ast_el_read_history(char *filename) +static int ast_el_read_history(const char *filename) { HistEvent ev; @@ -3190,11 +3189,32 @@ static int ast_el_read_history(char *filename) return history(el_hist, &ev, H_LOAD, filename); } +static void ast_el_read_default_histfile(void) +{ + char histfile[80] = ""; + const char *home = getenv("HOME"); + + if (!ast_strlen_zero(home)) { + snprintf(histfile, sizeof(histfile), "%s/.asterisk_history", home); + ast_el_read_history(histfile); + } +} + +static void ast_el_write_default_histfile(void) +{ + char histfile[80] = ""; + const char *home = getenv("HOME"); + + if (!ast_strlen_zero(home)) { + snprintf(histfile, sizeof(histfile), "%s/.asterisk_history", home); + ast_el_write_history(histfile); + } +} + static void ast_remotecontrol(char *data) { char buf[256] = ""; int res; - char filename[80] = ""; char *hostname; char *cpid; char *version; @@ -3204,6 +3224,10 @@ static void ast_remotecontrol(char *data) char *ebuf; int num = 0; + ast_term_init(); + printf("%s", term_end()); + fflush(stdout); + memset(&sig_flags, 0, sizeof(sig_flags)); signal(SIGINT, __remote_quit_handler); signal(SIGTERM, __remote_quit_handler); @@ -3302,16 +3326,12 @@ static void ast_remotecontrol(char *data) ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid); remotehostname = hostname; - if (getenv("HOME")) - snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); if (el_hist == NULL || el == NULL) ast_el_initialize(); + ast_el_read_default_histfile(); el_set(el, EL_GETCFN, ast_el_read_char); - if (!ast_strlen_zero(filename)) - ast_el_read_history(filename); - for (;;) { ebuf = (char *)el_gets(el, &num); @@ -3780,17 +3800,10 @@ static void main_atexit(void) int main(int argc, char *argv[]) { int c; - char filename[80] = ""; - char hostname[MAXHOSTNAMELEN] = ""; char * xarg = NULL; int x; - FILE *f; - sigset_t sigs; - int num; int isroot = 1, rundir_exists = 0; - char *buf; const char *runuser = NULL, *rungroup = NULL; - int moduleresult; /*!< Result from the module load subsystem */ struct rlimit l; static const char *getopt_settings = "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:"; @@ -3810,13 +3823,8 @@ int main(int argc, char *argv[]) if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) { ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE); } - if (gethostname(hostname, sizeof(hostname)-1)) - ast_copy_string(hostname, "", sizeof(hostname)); ast_mainpid = getpid(); - if (getenv("HOME")) - snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); - /* Set config file to default before checking arguments for override. */ ast_copy_string(cfg_paths.config_file, DEFAULT_CONFIG_FILE, sizeof(cfg_paths.config_file)); @@ -4197,6 +4205,10 @@ int main(int argc, char *argv[]) quit_handler(0, SHUTDOWN_FAST, 0); exit(0); } + ast_term_init(); + printf("%s", term_end()); + fflush(stdout); + print_intro_message(runuser, rungroup); printf("%s", term_quit()); ast_remotecontrol(NULL); @@ -4213,6 +4225,19 @@ int main(int argc, char *argv[]) exit(1); } + /* Not a remote console? Start the daemon. */ + asterisk_daemon(isroot, runuser, rungroup); + return 0; +} + +static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup) +{ + FILE *f; + sigset_t sigs; + int num; + char *buf; + int moduleresult; /*!< Result from the module load subsystem */ + /* This needs to remain as high up in the initial start up as possible. * daemon causes a fork to occur, which has all sorts of unintended * consequences for things that interact with threads. This call *must* @@ -4309,9 +4334,7 @@ int main(int argc, char *argv[]) if (ast_opt_console) { if (el_hist == NULL || el == NULL) ast_el_initialize(); - - if (!ast_strlen_zero(filename)) - ast_el_read_history(filename); + ast_el_read_default_histfile(); } ast_json_init(); @@ -4476,7 +4499,7 @@ int main(int argc, char *argv[]) /* initialize the data retrieval API */ if (ast_data_init()) { - printf ("Failed: ast_data_init\n%s", term_quit()); + printf("Failed: ast_data_init\n%s", term_quit()); exit(1); } @@ -4658,6 +4681,11 @@ int main(int argc, char *argv[]) /* Console stuff now... */ /* Register our quit function */ char title[256]; + char hostname[MAXHOSTNAMELEN] = ""; + + if (gethostname(hostname, sizeof(hostname) - 1)) { + ast_copy_string(hostname, "", sizeof(hostname)); + } ast_pthread_create_detached(&mon_sig_flags, NULL, monitor_sig_flags, NULL); @@ -4675,30 +4703,17 @@ int main(int argc, char *argv[]) buf = (char *) el_gets(el, &num); if (!buf && write(1, "", 1) < 0) - goto lostterm; + return; /* quit */ if (buf) { if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; - consolehandler((char *)buf); - } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n", - strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) { - /* Whoa, stdout disappeared from under us... Make /dev/null's */ - int fd; - fd = open("/dev/null", O_RDWR); - if (fd > -1) { - dup2(fd, STDOUT_FILENO); - dup2(fd, STDIN_FILENO); - } else - ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n"); - break; + consolehandler(buf); } } } + /* Stall until a quit signal is given */ monitor_sig_flags(NULL); - -lostterm: - return 0; } diff --git a/main/term.c b/main/term.c index cf21719ae36..11fbe2da9da 100644 --- a/main/term.c +++ b/main/term.c @@ -44,7 +44,6 @@ ASTERISK_REGISTER_FILE() static int vt100compat; -static char prepdata[80] = ""; static char enddata[80] = ""; static char quitdata[80] = ""; @@ -173,18 +172,13 @@ int ast_term_init(void) if (vt100compat) { /* Make commands show up in nice colors */ if (ast_opt_light_background) { - snprintf(prepdata, sizeof(prepdata), "%c[%dm", ESC, COLOR_BROWN); snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, COLOR_BLACK); - snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC); } else if (ast_opt_force_black_background) { - snprintf(prepdata, sizeof(prepdata), "%c[%d;%d;%dm", ESC, ATTR_BRIGHT, COLOR_BROWN, COLOR_BLACK + 10); snprintf(enddata, sizeof(enddata), "%c[%d;%d;%dm", ESC, ATTR_RESET, COLOR_WHITE, COLOR_BLACK + 10); - snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC); } else { - snprintf(prepdata, sizeof(prepdata), "%c[%d;%dm", ESC, ATTR_BRIGHT, COLOR_BROWN); - snprintf(enddata, sizeof(enddata), "%c[%d;%dm", ESC, ATTR_RESET, COLOR_WHITE); - snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC); + snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, ATTR_RESET); } + snprintf(quitdata, sizeof(quitdata), "%c[%dm", ESC, ATTR_RESET); } return 0; } @@ -216,9 +210,12 @@ char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int } if (ast_opt_force_black_background) { - snprintf(outbuf, maxout, "%c[%d;%d;%dm%s%c[%d;%dm", ESC, attr, fgcolor, bgcolor + 10, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10); + if (!bgcolor) { + bgcolor = COLOR_BLACK; + } + snprintf(outbuf, maxout, "%c[%d;%d;%dm%s%s", ESC, attr, fgcolor, bgcolor + 10, inbuf, term_end()); } else { - snprintf(outbuf, maxout, "%c[%d;%dm%s%c[0m", ESC, attr, fgcolor, inbuf, ESC); + snprintf(outbuf, maxout, "%c[%d;%dm%s%s", ESC, attr, fgcolor, inbuf, term_end()); } return outbuf; } @@ -242,16 +239,16 @@ static void check_bgcolor(int *bgcolor) } } -static int check_colors_allowed(int fgcolor) +static int check_colors_allowed(void) { - return (!vt100compat || !fgcolor) ? 0 : 1; + return vt100compat; } int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor) { int attr = 0; - if (!check_colors_allowed(fgcolor)) { + if (!check_colors_allowed()) { return -1; } @@ -273,7 +270,7 @@ char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout) { int attr = 0; - if (!check_colors_allowed(fgcolor)) { + if (!check_colors_allowed()) { *outbuf = '\0'; return outbuf; } @@ -310,11 +307,7 @@ const char *ast_term_color(int fgcolor, int bgcolor) const char *ast_term_reset(void) { - if (ast_opt_force_black_background) { - return enddata; - } else { - return quitdata; - } + return term_end(); } char *term_strip(char *outbuf, const char *inbuf, int maxout) @@ -339,34 +332,6 @@ char *term_strip(char *outbuf, const char *inbuf, int maxout) return outbuf; } -char *term_prompt(char *outbuf, const char *inbuf, int maxout) -{ - if (!vt100compat) { - ast_copy_string(outbuf, inbuf, maxout); - return outbuf; - } - if (ast_opt_force_black_background) { - snprintf(outbuf, maxout, "%c[%d;%d;%dm%c%c[%d;%dm%s", - ESC, ATTR_BRIGHT, COLOR_BLUE, COLOR_BLACK + 10, - inbuf[0], - ESC, COLOR_WHITE, COLOR_BLACK + 10, - inbuf + 1); - } else if (ast_opt_light_background) { - snprintf(outbuf, maxout, "%c[%d;0m%c%c[0m%s", - ESC, COLOR_BLUE, - inbuf[0], - ESC, - inbuf + 1); - } else { - snprintf(outbuf, maxout, "%c[%d;%d;0m%c%c[0m%s", - ESC, ATTR_BRIGHT, COLOR_BLUE, - inbuf[0], - ESC, - inbuf + 1); - } - return outbuf; -} - /* filter escape sequences */ void term_filter_escapes(char *line) { @@ -390,11 +355,6 @@ void term_filter_escapes(char *line) } } -const char *term_prep(void) -{ - return prepdata; -} - const char *term_end(void) { return enddata; From 9014f1f4a52dce9acbc2d1d1e7fdbb00f2a52154 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Wed, 25 Nov 2015 15:26:35 -0600 Subject: [PATCH 0045/1578] fastagi: record file closed after sending result The fastagi record-file testsuite test sometimes fails reporting an empty recorded file. This was happening because Asterisk was sending the agi result notification prior to actually closing the file and the data, being buffered, had not been written to the file yet when the test attempts to check the file size. This patch makes it so the record file stream is closed prior to sending the agi result notification. ASTERISK-25593 #close Change-Id: I6b2b3be3ae37f7c7b18e672c419a89b3b8513cde --- res/res_agi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/res_agi.c b/res/res_agi.c index 1dc6d404069..f6ce7496015 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -2630,8 +2630,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const } f = ast_read(chan); if (!f) { - ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset); ast_closestream(fs); + ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset); if (sildet) ast_dsp_free(sildet); return RESULT_FAILURE; @@ -2645,8 +2645,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const ast_stream_rewind(fs, 200); ast_truncstream(fs); sample_offset = ast_tellstream(fs); - ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset); ast_closestream(fs); + ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset); ast_frfree(f); if (sildet) ast_dsp_free(sildet); @@ -2690,8 +2690,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const ast_truncstream(fs); sample_offset = ast_tellstream(fs); } - ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); ast_closestream(fs); + ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); } if (silence > 0) { From 7cb8f2f33eef3e1f47da1313a3154a6dacb89e05 Mon Sep 17 00:00:00 2001 From: Niklas Larsson Date: Fri, 27 Nov 2015 14:39:22 +0100 Subject: [PATCH 0046/1578] CHANGES: Fix a typo Change-Id: Iceb3d9bb78140c376174a7bee197dfcf8ef9cda7 --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index fb149ce870e..ca7d1610087 100644 --- a/CHANGES +++ b/CHANGES @@ -244,7 +244,7 @@ res_pjsip CLI commands. For instance: CLI> pjsip list endpoints like abc * If res_statsd is loaded and a StatsD server is configured, basic statistics - regarding the state of PJSIP contacts will not be emitted. This includes: + regarding the state of PJSIP contacts will now be emitted. This includes: - A GAUGE statistic for the overall number of contacts in a particular state, e.g.: PJSIP.contacts.states.Reachable From f2a84b500d0706ce411940e72562118c263ab9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Mon, 9 Nov 2015 02:49:08 -0300 Subject: [PATCH 0047/1578] app_queue: Show reason of pause on CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add value of pause reason when is paused on CLI command "queue show" ASTERISK-25581 #close Report by: Rodrigo Ramírez Norambuena Change-Id: I887028a40cd97b350da9a3bb2719616b7fec9864 --- apps/app_queue.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 234543f75a2..a2ed2c924af 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999 - 2006, Digium, Inc. + * Copyright (C) 1999 - 2015, Digium, Inc. * * Mark Spencer * @@ -9250,10 +9250,20 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled"); - ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s (%s%s%s)", + ast_str_append(&out, 0, "%s%s%s%s%s%s", mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(), - mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(), - mem->paused ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->paused ? " (paused)" : "", ast_term_reset(), + mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset()); + if (mem->paused) { + if (ast_strlen_zero(mem->reason_paused)) { + ast_str_append(&out, 0, " %s(paused)%s", + ast_term_color(COLOR_BROWN, COLOR_BLACK), ast_term_reset()); + } else { + ast_str_append(&out, 0, " %s(paused:%s)%s", ast_term_color(COLOR_BROWN, COLOR_BLACK), + mem->reason_paused, ast_term_reset()); + } + } + + ast_str_append(&out, 0, " (%s%s%s)", ast_term_color( mem->status == AST_DEVICE_UNAVAILABLE || mem->status == AST_DEVICE_UNKNOWN ? COLOR_RED : COLOR_GREEN, COLOR_BLACK), From 270f7be54f608b469ad1bcd927fc19a6d8f7ccad Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 25 Nov 2015 17:42:31 +0100 Subject: [PATCH 0048/1578] Build System: Support include-what-you-use. ASTERISK-25591 #close Change-Id: I8d3efa0826142ece9cbed2fd0d46f3b607fee6ae --- configure | 10 +++++----- configure.ac | 12 ++++-------- include/asterisk/astmm.h | 1 + include/asterisk/autoconfig.h.in | 7 +++---- include/asterisk/compat.h | 8 +++++--- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/configure b/configure index 509e29fd10c..bc51839c823 100755 --- a/configure +++ b/configure @@ -13653,7 +13653,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13699,7 +13699,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13723,7 +13723,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13768,7 +13768,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13792,7 +13792,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; diff --git a/configure.ac b/configure.ac index 7f69430b789..021d0d167e4 100644 --- a/configure.ac +++ b/configure.ac @@ -218,17 +218,13 @@ if test ! x"${UNAME}" = xNo; then fi AC_SUBST(PBX_OSREV) -AH_TOP( -#ifndef ASTERISK_AUTOCONFIG_H +AH_TOP([#ifndef ASTERISK_AUTOCONFIG_H #define ASTERISK_AUTOCONFIG_H +/* IWYU pragma: private, include "asterisk.h" */ -#include "asterisk/buildopts.h" +#include "asterisk/buildopts.h" /* IWYU pragma: export */]) -) - -AH_BOTTOM( -#endif -) +AH_BOTTOM([#endif /* ASTERISK_AUTOCONFIG_H */]) # cross-compile checks if test "${cross_compiling}" = "yes"; diff --git a/include/asterisk/astmm.h b/include/asterisk/astmm.h index 6c9a8aeeeb2..83c34bed345 100644 --- a/include/asterisk/astmm.h +++ b/include/asterisk/astmm.h @@ -30,6 +30,7 @@ extern "C" { #ifndef _ASTERISK_ASTMM_H #define _ASTERISK_ASTMM_H +/* IWYU pragma: private, include "asterisk/utils.h" */ #ifndef STANDALONE diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 17aac1d83a7..d86ba4a6aad 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -2,10 +2,9 @@ #ifndef ASTERISK_AUTOCONFIG_H #define ASTERISK_AUTOCONFIG_H +/* IWYU pragma: private, include "asterisk.h" */ -#include "asterisk/buildopts.h" - - +#include "asterisk/buildopts.h" /* IWYU pragma: export */ /* Define to 1 if internal poll should be used. */ #undef AST_POLL_COMPAT @@ -1381,4 +1380,4 @@ code using `volatile' can become incorrect without. Disable with care. */ #undef volatile -#endif +#endif /* ASTERISK_AUTOCONFIG_H */ diff --git a/include/asterisk/compat.h b/include/asterisk/compat.h index c9c99c150cf..3eb6c96a2d3 100644 --- a/include/asterisk/compat.h +++ b/include/asterisk/compat.h @@ -15,10 +15,12 @@ * especially those related to header files. */ -#include "asterisk/compiler.h" - #ifndef _COMPAT_H #define _COMPAT_H +/* IWYU pragma: private, include "asterisk.h" */ +/* IWYU pragma: begin_exports */ + +#include "asterisk/compiler.h" #ifndef __STDC_VERSION__ /* flex output wants to find this defined. */ @@ -231,5 +233,5 @@ float roundf(float x); #ifndef NAN #define NAN (0.0/0.0) #endif - +/* IWYU pragma: end_exports */ #endif From e5723d27763b85b66972a275cd90f4a592bcc21f Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 30 Nov 2015 10:13:35 -0700 Subject: [PATCH 0049/1578] dns: Change lookup failures from LOG_ERROR to debug 1. dns.c and dns_system_resolver.c were spitting out errors for lookup failures for things like not finding a SRV record even though there was an A record. Those have been changed to debug messages. Logging not finding ANY record is left to the higher level caller. Also, dns_system_resolver was using Windows line endings so I converted them to Unix style. The actual log changes are on lines 156 and 159. Change-Id: I65be16ea15304b96f9dcb4d289dbd3e2286fc094 --- main/dns.c | 2 +- main/dns_system_resolver.c | 535 +++++++++++++++++++------------------ 2 files changed, 269 insertions(+), 268 deletions(-) diff --git a/main/dns.c b/main/dns.c index e338d768b8b..96227949ee2 100644 --- a/main/dns.c +++ b/main/dns.c @@ -558,7 +558,7 @@ enum ast_dns_search_result ast_search_dns_ex(void *context, const char *dname, i sizeof(dns_response)); if (dns_response_len < 0) { - ast_log(LOG_ERROR, "DNS search failed for %s\n", dname); + ast_debug(1, "DNS search failed for %s\n", dname); response_handler(context, (unsigned char *)"", 0, ns_r_nxdomain); return AST_DNS_SEARCH_FAILURE; } diff --git a/main/dns_system_resolver.c b/main/dns_system_resolver.c index a5ac7712731..d57814874cd 100644 --- a/main/dns_system_resolver.c +++ b/main/dns_system_resolver.c @@ -1,267 +1,268 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2015, Digium, Inc. - * - * Ashley Sanders - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief The default DNS resolver for Asterisk. - * - * \arg See also \ref res_resolver_unbound - * - * \author Ashley Sanders - */ - -#include "asterisk.h" - -ASTERISK_REGISTER_FILE() - -#include "asterisk/_private.h" -#include "asterisk/astobj2.h" -#include "asterisk/dns.h" -#include "asterisk/dns_core.h" -#include "asterisk/dns_resolver.h" -#include "asterisk/linkedlists.h" -#include "asterisk/taskprocessor.h" - -/*! \brief The consideration priority for this resolver implementation. */ -#define DNS_SYSTEM_RESOLVER_PRIORITY INT_MAX - -/*! \brief Resolver return code upon success. */ -#define DNS_SYSTEM_RESOLVER_SUCCESS 0 - -/*! \brief Resolver return code upon failure. */ -#define DNS_SYSTEM_RESOLVER_FAILURE -1 - - -static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl); -static int dns_system_resolver_cancel(struct ast_dns_query *query); -static void dns_system_resolver_destroy(void); -static int dns_system_resolver_process_query(void *data); -static int dns_system_resolver_resolve(struct ast_dns_query *query); -static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode); - - -/*! \brief The task processor to use for making DNS searches asynchronous. */ -static struct ast_taskprocessor *dns_system_resolver_tp; - -/*! \brief The base definition for the dns_system_resolver */ -struct ast_dns_resolver dns_system_resolver_base = { - .name = "system", - .priority = DNS_SYSTEM_RESOLVER_PRIORITY, - .resolve = dns_system_resolver_resolve, - .cancel = dns_system_resolver_cancel, -}; - -/*! - * \brief Callback to handle processing resource records. - * - * \details Adds an individual resource record discovered with ast_search_dns_ex to the - * ast_dns_query currently being resolved. - * - * \internal - * - * \param context A void pointer to the ast_dns_query being processed. - * \param record An individual resource record discovered during the DNS search. - * \param record_len The length of the resource record. - * \param ttl The resource record's expiration time limit (time to live). - * - * \retval 0 on success - * \retval -1 on failure - */ -static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl) -{ - struct ast_dns_query *query = context; - - /* Add the record to the query.*/ - return ast_dns_resolver_add_record(query, - ast_dns_query_get_rr_type(query), - ast_dns_query_get_rr_class(query), - ttl, - (const char*) record, - record_len); -} - -/*! - * \brief Cancels processing resolution for a given query. - * - * \note The system API calls block so there is no way to cancel them. Therefore, this function always - * returns failure when invoked. - * - * \internal - * - * \param query The ast_dns_query to cancel. - * - * \retval 0 on success - * \retval -1 on failure - */ -static int dns_system_resolver_cancel(struct ast_dns_query *query) -{ - return DNS_SYSTEM_RESOLVER_FAILURE; -} - -/*! - * \brief Destructor. - * - * \internal - */ -static void dns_system_resolver_destroy(void) -{ - /* Unreference the task processor */ - dns_system_resolver_tp = ast_taskprocessor_unreference(dns_system_resolver_tp); - - /* Unregister the base resolver */ - ast_dns_resolver_unregister(&dns_system_resolver_base); -} - -/*! - * \brief Callback to handle processing the query from the ast_taskprocessor instance. - * - * \internal - * - * \param data A void pointer to the ast_dns_query being processed. - * - * \retval -1 on search failure - * \retval 0 on no records found - * \retval 1 on success - */ -static int dns_system_resolver_process_query(void *data) -{ - struct ast_dns_query *query = data; - - /* Perform the DNS search */ - enum ast_dns_search_result res = ast_search_dns_ex(query, - ast_dns_query_get_name(query), - ast_dns_query_get_rr_class(query), - ast_dns_query_get_rr_type(query), - dns_system_resolver_set_response, - dns_system_resolver_add_record); - - /* Handle the possible return values from the DNS search */ - if (res == AST_DNS_SEARCH_FAILURE) { - ast_log(LOG_ERROR, "DNS search failed for query: '%s'\n", - ast_dns_query_get_name(query)); - } else if (res == AST_DNS_SEARCH_NO_RECORDS) { - ast_log(LOG_WARNING, "DNS search failed to yield any results for query: '%s'\n", - ast_dns_query_get_name(query)); - } - - /* Mark the query as complete */ - ast_dns_resolver_completed(query); - - /* Reduce the reference count on the query object */ - ao2_ref(query, -1); - - return res; -} - -/*! - * \brief Resolves a DNS query. - * - * \internal - * - * \param query The ast_dns_query to resolve. - * - * \retval 0 on successful load of query handler to the ast_taskprocessor instance - * \retval -1 on failure to load the query handler to the ast_taskprocessor instance - */ -static int dns_system_resolver_resolve(struct ast_dns_query *query) -{ - /* Add query processing handler to the task processor */ - int res = ast_taskprocessor_push(dns_system_resolver_tp, - dns_system_resolver_process_query, - ao2_bump(query)); - - /* The query processing handler was not added to the task processor */ - if (res < 0) { - ast_log(LOG_ERROR, "Failed to perform async DNS resolution of '%s'\n", - ast_dns_query_get_name(query)); - ao2_ref(query, -1); - } - - /* Return the result of adding the query processing handler to the task processor */ - return res; -} - -/*! - * \brief Callback to handle initializing the results field. - * - * \internal - * - * \param dns_response The full DNS response. - * \param dns_response The length of the full DNS response. - * \param rcode The DNS response code. - * - * \retval 0 on success - * \retval -1 on failure - */ -static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode) -{ - struct ast_dns_query *query = context; - int res; - - /* Instantiate the query's result field (if necessary). */ - if (!ast_dns_query_get_result(query)) { - res = ast_dns_resolver_set_result(query, - 0, - 0, - rcode, - ast_dns_query_get_name(query), - (const char*) dns_response, - dns_response_len); - - if (res) { - /* There was a problem instantiating the results field. */ - ast_log(LOG_ERROR, "Could not instantiate the results field for query: '%s'\n", - ast_dns_query_get_name(query)); - } - } else { - res = DNS_SYSTEM_RESOLVER_SUCCESS; - } - - return res; -} - -/*! - * \brief Initializes the resolver. - * - * \retval 0 on success - * \retval -1 on failure - */ -int ast_dns_system_resolver_init(void) -{ - /* Register the base resolver */ - int res = ast_dns_resolver_register(&dns_system_resolver_base); - - if (res) { - return DNS_SYSTEM_RESOLVER_FAILURE; - } - - /* Instantiate the task processor */ - dns_system_resolver_tp = ast_taskprocessor_get("dns_system_resolver_tp", - TPS_REF_DEFAULT); - - /* Return error if the task processor failed to instantiate */ - if (!dns_system_resolver_tp) { - dns_system_resolver_destroy(); - return DNS_SYSTEM_RESOLVER_FAILURE; - } - - /* Register the cleanup function */ - ast_register_cleanup(dns_system_resolver_destroy); - - return DNS_SYSTEM_RESOLVER_SUCCESS; -} +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Digium, Inc. + * + * Ashley Sanders + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief The default DNS resolver for Asterisk. + * + * \arg See also \ref res_resolver_unbound + * + * \author Ashley Sanders + */ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/astobj2.h" +#include "asterisk/dns.h" +#include "asterisk/dns_core.h" +#include "asterisk/dns_resolver.h" +#include "asterisk/linkedlists.h" +#include "asterisk/taskprocessor.h" +#include "asterisk/utils.h" + +/*! \brief The consideration priority for this resolver implementation. */ +#define DNS_SYSTEM_RESOLVER_PRIORITY INT_MAX + +/*! \brief Resolver return code upon success. */ +#define DNS_SYSTEM_RESOLVER_SUCCESS 0 + +/*! \brief Resolver return code upon failure. */ +#define DNS_SYSTEM_RESOLVER_FAILURE -1 + + +static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl); +static int dns_system_resolver_cancel(struct ast_dns_query *query); +static void dns_system_resolver_destroy(void); +static int dns_system_resolver_process_query(void *data); +static int dns_system_resolver_resolve(struct ast_dns_query *query); +static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode); + + +/*! \brief The task processor to use for making DNS searches asynchronous. */ +static struct ast_taskprocessor *dns_system_resolver_tp; + +/*! \brief The base definition for the dns_system_resolver */ +struct ast_dns_resolver dns_system_resolver_base = { + .name = "system", + .priority = DNS_SYSTEM_RESOLVER_PRIORITY, + .resolve = dns_system_resolver_resolve, + .cancel = dns_system_resolver_cancel, +}; + +/*! + * \brief Callback to handle processing resource records. + * + * \details Adds an individual resource record discovered with ast_search_dns_ex to the + * ast_dns_query currently being resolved. + * + * \internal + * + * \param context A void pointer to the ast_dns_query being processed. + * \param record An individual resource record discovered during the DNS search. + * \param record_len The length of the resource record. + * \param ttl The resource record's expiration time limit (time to live). + * + * \retval 0 on success + * \retval -1 on failure + */ +static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl) +{ + struct ast_dns_query *query = context; + + /* Add the record to the query.*/ + return ast_dns_resolver_add_record(query, + ast_dns_query_get_rr_type(query), + ast_dns_query_get_rr_class(query), + ttl, + (const char*) record, + record_len); +} + +/*! + * \brief Cancels processing resolution for a given query. + * + * \note The system API calls block so there is no way to cancel them. Therefore, this function always + * returns failure when invoked. + * + * \internal + * + * \param query The ast_dns_query to cancel. + * + * \retval 0 on success + * \retval -1 on failure + */ +static int dns_system_resolver_cancel(struct ast_dns_query *query) +{ + return DNS_SYSTEM_RESOLVER_FAILURE; +} + +/*! + * \brief Destructor. + * + * \internal + */ +static void dns_system_resolver_destroy(void) +{ + /* Unreference the task processor */ + dns_system_resolver_tp = ast_taskprocessor_unreference(dns_system_resolver_tp); + + /* Unregister the base resolver */ + ast_dns_resolver_unregister(&dns_system_resolver_base); +} + +/*! + * \brief Callback to handle processing the query from the ast_taskprocessor instance. + * + * \internal + * + * \param data A void pointer to the ast_dns_query being processed. + * + * \retval -1 on search failure + * \retval 0 on no records found + * \retval 1 on success + */ +static int dns_system_resolver_process_query(void *data) +{ + struct ast_dns_query *query = data; + + /* Perform the DNS search */ + enum ast_dns_search_result res = ast_search_dns_ex(query, + ast_dns_query_get_name(query), + ast_dns_query_get_rr_class(query), + ast_dns_query_get_rr_type(query), + dns_system_resolver_set_response, + dns_system_resolver_add_record); + + /* Handle the possible return values from the DNS search */ + if (res == AST_DNS_SEARCH_FAILURE) { + ast_debug(1, "DNS search failed for query: '%s'\n", + ast_dns_query_get_name(query)); + } else if (res == AST_DNS_SEARCH_NO_RECORDS) { + ast_debug(1, "DNS search failed to yield any results for query: '%s'\n", + ast_dns_query_get_name(query)); + } + + /* Mark the query as complete */ + ast_dns_resolver_completed(query); + + /* Reduce the reference count on the query object */ + ao2_ref(query, -1); + + return res; +} + +/*! + * \brief Resolves a DNS query. + * + * \internal + * + * \param query The ast_dns_query to resolve. + * + * \retval 0 on successful load of query handler to the ast_taskprocessor instance + * \retval -1 on failure to load the query handler to the ast_taskprocessor instance + */ +static int dns_system_resolver_resolve(struct ast_dns_query *query) +{ + /* Add query processing handler to the task processor */ + int res = ast_taskprocessor_push(dns_system_resolver_tp, + dns_system_resolver_process_query, + ao2_bump(query)); + + /* The query processing handler was not added to the task processor */ + if (res < 0) { + ast_log(LOG_ERROR, "Failed to perform async DNS resolution of '%s'\n", + ast_dns_query_get_name(query)); + ao2_ref(query, -1); + } + + /* Return the result of adding the query processing handler to the task processor */ + return res; +} + +/*! + * \brief Callback to handle initializing the results field. + * + * \internal + * + * \param dns_response The full DNS response. + * \param dns_response The length of the full DNS response. + * \param rcode The DNS response code. + * + * \retval 0 on success + * \retval -1 on failure + */ +static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode) +{ + struct ast_dns_query *query = context; + int res; + + /* Instantiate the query's result field (if necessary). */ + if (!ast_dns_query_get_result(query)) { + res = ast_dns_resolver_set_result(query, + 0, + 0, + rcode, + ast_dns_query_get_name(query), + (const char*) dns_response, + dns_response_len); + + if (res) { + /* There was a problem instantiating the results field. */ + ast_log(LOG_ERROR, "Could not instantiate the results field for query: '%s'\n", + ast_dns_query_get_name(query)); + } + } else { + res = DNS_SYSTEM_RESOLVER_SUCCESS; + } + + return res; +} + +/*! + * \brief Initializes the resolver. + * + * \retval 0 on success + * \retval -1 on failure + */ +int ast_dns_system_resolver_init(void) +{ + /* Register the base resolver */ + int res = ast_dns_resolver_register(&dns_system_resolver_base); + + if (res) { + return DNS_SYSTEM_RESOLVER_FAILURE; + } + + /* Instantiate the task processor */ + dns_system_resolver_tp = ast_taskprocessor_get("dns_system_resolver_tp", + TPS_REF_DEFAULT); + + /* Return error if the task processor failed to instantiate */ + if (!dns_system_resolver_tp) { + dns_system_resolver_destroy(); + return DNS_SYSTEM_RESOLVER_FAILURE; + } + + /* Register the cleanup function */ + ast_register_cleanup(dns_system_resolver_destroy); + + return DNS_SYSTEM_RESOLVER_SUCCESS; +} From b24f2f4c2e220ec9b33cb84c8325985e76252a7d Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 1 Dec 2015 14:55:13 +0100 Subject: [PATCH 0050/1578] codec_resample: Increase buffer for Opus Codec. ASTERISK-25599 #close Change-Id: I1f88a88c59fb4e1e62bbdbb100c7152d48e73f10 --- codecs/codec_resample.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codecs/codec_resample.c b/codecs/codec_resample.c index 67e9ce2b0ff..3c8a149d78f 100644 --- a/codecs/codec_resample.c +++ b/codecs/codec_resample.c @@ -38,7 +38,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/translate.h" #include "asterisk/slin.h" -#define OUTBUF_SIZE 8096 +#define OUTBUF_SAMPLES 5760 static struct ast_translator *translators; static int trans_size; @@ -114,7 +114,7 @@ static void resamp_destroy(struct ast_trans_pvt *pvt) static int resamp_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { SpeexResamplerState *resamp_pvt = pvt->pvt; - unsigned int out_samples = (OUTBUF_SIZE / sizeof(int16_t)) - pvt->samples; + unsigned int out_samples = OUTBUF_SAMPLES - pvt->samples; unsigned int in_samples; if (!f->datalen) { @@ -167,8 +167,8 @@ static int load_module(void) translators[idx].destroy = resamp_destroy; translators[idx].framein = resamp_framein; translators[idx].desc_size = 0; - translators[idx].buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)); - translators[idx].buf_size = OUTBUF_SIZE; + translators[idx].buffer_samples = OUTBUF_SAMPLES; + translators[idx].buf_size = (OUTBUF_SAMPLES * sizeof(int16_t)); memcpy(&translators[idx].src_codec, &codec_list[x], sizeof(struct ast_codec)); memcpy(&translators[idx].dst_codec, &codec_list[y], sizeof(struct ast_codec)); snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %ukhz -> %ukhz", From fa2072903238ddb8dbba7d75ccf70edb36581f36 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 24 Nov 2015 12:44:53 -0600 Subject: [PATCH 0051/1578] Audit improper usage of scheduler exposed by 5c713fdf18f. channels/chan_iax2.c: * Initialize struct chan_iax2_pvt scheduler ids earlier because of iax2_destroy_helper(). channels/chan_sip.c: channels/sip/config_parser.c: * Fix initialization of scheduler id struct members. Some off nominal paths had 0 as a scheduler id to be destroyed when it was never started. chan_skinny.c: * Fix some scheduler id comparisons that excluded the valid 0 id. channel.c: * Fix channel initialization of the video stream scheduler id. pbx_dundi.c: * Fix channel initialization of the packet retransmission scheduler id. ASTERISK-25476 Change-Id: I07a3449f728f671d326a22fcbd071f150ba2e8c8 --- channels/chan_iax2.c | 15 ++++++++------- channels/chan_sip.c | 6 ++++++ channels/chan_skinny.c | 8 ++++---- channels/sip/config_parser.c | 9 ++++++--- main/channel.c | 1 + pbx/pbx_dundi.c | 1 + 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 42ccbd5fdb9..af44de96c6c 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -2236,6 +2236,14 @@ static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host return NULL; } + tmp->pingid = -1; + tmp->lagid = -1; + tmp->autoid = -1; + tmp->authid = -1; + tmp->initid = -1; + tmp->keyrotateid = -1; + tmp->jbid = -1; + if (ast_string_field_init(tmp, 32)) { ao2_ref(tmp, -1); tmp = NULL; @@ -2243,18 +2251,11 @@ static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host } tmp->prefs = prefs_global; - tmp->pingid = -1; - tmp->lagid = -1; - tmp->autoid = -1; - tmp->authid = -1; - tmp->initid = -1; - tmp->keyrotateid = -1; ast_string_field_set(tmp,exten, "s"); ast_string_field_set(tmp,host, host); tmp->jb = jb_new(); - tmp->jbid = -1; jbconf.max_jitterbuf = maxjitterbuffer; jbconf.resync_threshold = resyncthreshold; jbconf.max_contig_interp = maxjitterinterps; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 158dc7b1818..6cfb5987958 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1709,6 +1709,7 @@ static int publish_expire(const void *data) ast_assert(esc != NULL); ao2_unlink(esc->compositor, esc_entry); + esc_entry->sched_id = -1; ao2_ref(esc_entry, -1); return 0; } @@ -1741,6 +1742,11 @@ static struct sip_esc_entry *create_esc_entry(struct event_state_compositor *esc /* Bump refcount for scheduler */ ao2_ref(esc_entry, +1); esc_entry->sched_id = ast_sched_add(sched, expires_ms, publish_expire, esc_entry); + if (esc_entry->sched_id == -1) { + ao2_ref(esc_entry, -1); + ao2_ref(esc_entry, -1); + return NULL; + } /* Note: This links the esc_entry into the ESC properly */ create_new_sip_etag(esc_entry, 0); diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 6f56f732e7b..707ab02c5fd 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -5548,12 +5548,12 @@ static void setsubstate(struct skinny_subchannel *sub, int state) skinny_locksub(sub); - if (sub->dialer_sched) { + if (-1 < sub->dialer_sched) { skinny_sched_del(sub->dialer_sched, sub); sub->dialer_sched = -1; } - if (state != SUBSTATE_RINGIN && sub->aa_sched) { + if (state != SUBSTATE_RINGIN && -1 < sub->aa_sched) { skinny_sched_del(sub->aa_sched, sub); sub->aa_sched = -1; sub->aa_beep = 0; @@ -6238,7 +6238,7 @@ static int handle_keypad_button_message(struct skinny_req *req, struct skinnyses } if ((sub->owner && ast_channel_state(sub->owner) < AST_STATE_UP)) { - if (sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) { + if (-1 < sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) { SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Got a digit and not timed out, so try dialing\n", sub->callid); sub->dialer_sched = -1; len = strlen(sub->exten); @@ -7075,7 +7075,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse case SOFTKEY_BKSPC: SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_BKSPC from %s, inst %d, callref %d\n", d->name, instance, callreference); - if (sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) { + if (-1 < sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) { size_t len; sub->dialer_sched = -1; len = strlen(sub->exten); diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index a3964b047d5..56d04b260eb 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -79,13 +79,17 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const AST_APP_ARG(port); ); - if (!value) { + if (!reg) { return -1; } - if (!reg) { + reg->expire = -1; + reg->timeout = -1; + + if (!value) { return -1; } + ast_copy_string(buf, value, sizeof(buf)); /*! register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] @@ -261,7 +265,6 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const ast_string_field_set(reg, regdomain, ast_strip_quoted(S_OR(user2.domain, ""), "\"", "\"")); reg->transport = transport; - reg->timeout = reg->expire = -1; reg->portno = portnum; reg->regdomainport = domainport; reg->callid_valid = FALSE; diff --git a/main/channel.c b/main/channel.c index 013d2e281fb..f5a9afade5a 100644 --- a/main/channel.c +++ b/main/channel.c @@ -877,6 +877,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD); ast_channel_streamid_set(tmp, -1); + ast_channel_vstreamid_set(tmp, -1); ast_channel_fin_set(tmp, global_fin); ast_channel_fout_set(tmp, global_fout); diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index 660968f14a2..ec1d2189c37 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -3264,6 +3264,7 @@ static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, i pack = ast_calloc(1, len); if (pack) { pack->h = (struct dundi_hdr *)(pack->data); + pack->retransid = -1; if (cmdresp != DUNDI_COMMAND_ACK) { pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack); pack->retrans = DUNDI_DEFAULT_RETRANS - 1; From 145d10a5d0c1f7a0b6d3fe27462c922d4ca27091 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 25 Nov 2015 12:23:47 -0600 Subject: [PATCH 0052/1578] Audit improper usage of scheduler exposed by 5c713fdf18f. (v13 additions) chan_sip.c: * Initialize mwi subscription scheduler ids earlier because of ASTOBJ to ao2 conversion. * Initialize register scheduler ids earlier because of ASTOBJ to ao2 conversion. chan_skinny.c: * Fix more scheduler usage for the valid 0 id value. ASTERISK-25476 Change-Id: If9f0e5d99638b2f9d102d1ebc9c5a14b2d706e95 --- channels/chan_sip.c | 6 +++++- channels/chan_skinny.c | 33 +++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 6cfb5987958..3b200e21723 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -9364,6 +9364,9 @@ static int sip_register(const char *value, int lineno) return -1; } + reg->expire = -1; + reg->timeout = -1; + if (ast_string_field_init(reg, 256)) { ao2_t_ref(reg, -1, "failed to string_field_init, drop reg"); return -1; @@ -9437,6 +9440,8 @@ static int sip_subscribe_mwi(const char *value, int lineno) return -1; } + mwi->resub = -1; + if (ast_string_field_init(mwi, 256)) { ao2_t_ref(mwi, -1, "failed to string_field_init, drop mwi"); return -1; @@ -9451,7 +9456,6 @@ static int sip_subscribe_mwi(const char *value, int lineno) } ast_string_field_set(mwi, hostname, hostname); ast_string_field_set(mwi, mailbox, mailbox); - mwi->resub = -1; mwi->portno = portnum; mwi->transport = transport; diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 707ab02c5fd..da156fc5e47 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -1364,6 +1364,12 @@ static int gendigittimeout = 8000; /* How long to wait for an extra digit, if there is an ambiguous match */ static int matchdigittimeout = 3000; +/*! + * To apease the stupid compiler option on ast_sched_del() + * since we don't care about the return value. + */ +static int not_used; + #define SUBSTATE_UNSET 0 #define SUBSTATE_OFFHOOK 1 #define SUBSTATE_ONHOOK 2 @@ -2262,10 +2268,10 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s) int instance; int res = -1; - if (s->auth_timeout_sched && ast_sched_del(sched, s->auth_timeout_sched)) { - return 0; + if (-1 < s->auth_timeout_sched) { + not_used = ast_sched_del(sched, s->auth_timeout_sched); + s->auth_timeout_sched = -1; } - s->auth_timeout_sched = 0; AST_LIST_LOCK(&devices); AST_LIST_TRAVERSE(&devices, d, list){ @@ -5571,6 +5577,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) sub->cfwd_sched = -1; } else if (state == SUBSTATE_ONHOOK) { skinny_sched_del(sub->cfwd_sched, sub); + sub->cfwd_sched = -1; } } @@ -6170,9 +6177,7 @@ static int handle_ip_port_message(struct skinny_req *req, struct skinnysession * static void handle_keepalive_message(struct skinny_req *req, struct skinnysession *s) { - if (ast_sched_del(sched, s->keepalive_timeout_sched)) { - return; - } + not_used = ast_sched_del(sched, s->keepalive_timeout_sched); #ifdef AST_DEVMODE { @@ -7415,7 +7420,7 @@ static int skinny_noauth_cb(const void *data) { struct skinnysession *s = (struct skinnysession *)data; ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds (SCHED %d)\n", auth_timeout, s->auth_timeout_sched); - s->auth_timeout_sched = 0; + s->auth_timeout_sched = -1; end_session(s); return 0; } @@ -7424,7 +7429,7 @@ static int skinny_nokeepalive_cb(const void *data) { struct skinnysession *s = (struct skinnysession *)data; ast_log(LOG_WARNING, "Skinny Client failed to send keepalive in last %d seconds (SCHED %d)\n", keep_alive*3, s->keepalive_timeout_sched); - s->keepalive_timeout_sched = 0; + s->keepalive_timeout_sched = -1; end_session(s); return 0; } @@ -7442,11 +7447,13 @@ static void skinny_session_cleanup(void *data) ast_mutex_unlock(&s->lock); } - if (s->auth_timeout_sched && !ast_sched_del(sched, s->auth_timeout_sched)) { - s->auth_timeout_sched = 0; + if (-1 < s->auth_timeout_sched) { + not_used = ast_sched_del(sched, s->auth_timeout_sched); + s->auth_timeout_sched = -1; } - if (s->keepalive_timeout_sched && !ast_sched_del(sched, s->keepalive_timeout_sched)) { - s->keepalive_timeout_sched = 0; + if (-1 < s->keepalive_timeout_sched) { + not_used = ast_sched_del(sched, s->keepalive_timeout_sched); + s->keepalive_timeout_sched = -1; } if (d) { @@ -7651,6 +7658,8 @@ static void *accept_thread(void *ignore) ast_mutex_init(&s->lock); memcpy(&s->sin, &sin, sizeof(sin)); s->fd = as; + s->auth_timeout_sched = -1; + s->keepalive_timeout_sched = -1; if (ast_pthread_create(&s->t, NULL, skinny_session, s)) { destroy_session(s); From ef77439e39fe7bfc894e4ad41b866d3f6cf8f750 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 30 Nov 2015 16:42:47 -0600 Subject: [PATCH 0053/1578] sched.c: Make not return a sched id of 0. According to the API doxygen a sched ID of 0 is valid. Unfortunately, 0 was never returned historically and several users incorrectly coded usage of the returned sched ID assuming that 0 was invalid. ASTERISK-25476 Change-Id: Ib19c7ebb44ec9fd393ef6646dea806d4f34e3a20 --- main/sched.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/main/sched.c b/main/sched.c index a7e67032081..7b7021d6170 100644 --- a/main/sched.c +++ b/main/sched.c @@ -315,9 +315,16 @@ static int add_ids(struct ast_sched_context *con) if (!new_id) { break; } - new_id->id = i; + + /* + * According to the API doxygen a sched ID of 0 is valid. + * Unfortunately, 0 was never returned historically and + * several users incorrectly coded usage of the returned + * sched ID assuming that 0 was invalid. + */ + new_id->id = ++con->id_queue_size; + AST_LIST_INSERT_TAIL(&con->id_queue, new_id, list); - ++con->id_queue_size; } return con->id_queue_size - original_size; From 59ba84e5cd0fd06173a63ad73fc903298a47a4e2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 30 Nov 2015 14:22:55 -0600 Subject: [PATCH 0054/1578] res_sorcery_memory_cache.c: Fix off nominal ref leak. Change-Id: If83d63cf11cbc6df9b15251848b01feb570ade49 --- res/res_sorcery_memory_cache.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index bfa90e801fd..0d7630e854d 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -850,13 +850,16 @@ static void *sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, if (cached->stale_update_sched_id == -1) { struct stale_update_task_data *task_data; - task_data = stale_update_task_data_alloc((struct ast_sorcery *)sorcery, cache, - type, cached->object); + task_data = stale_update_task_data_alloc((struct ast_sorcery *) sorcery, + cache, type, cached->object); if (task_data) { ast_debug(1, "Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n", type, id); - cached->stale_update_sched_id = ast_sched_add(sched, 1, stale_item_update, task_data); - } else { + cached->stale_update_sched_id = ast_sched_add(sched, 1, + stale_item_update, task_data); + } + if (cached->stale_update_sched_id < 0) { + ao2_cleanup(task_data); ast_log(LOG_ERROR, "Unable to update stale cached object type '%s', ID '%s'.\n", type, id); } From b5281b74e0572e9ca574098937765647bf2e953a Mon Sep 17 00:00:00 2001 From: Jonathan Rose Date: Tue, 1 Dec 2015 16:11:07 -0600 Subject: [PATCH 0055/1578] Unset BRIDGEPEER when leaving a bridge Currently if a channel is transferred out of a bridge, the BRIDGEPEER variable (also BRIDGEPVTCALLID) remain set even once the channel is out of the bridge. This patch removes these variables when leaving the bridge. ASTERISK-25600 #close Reported by: Mark Michelson Change-Id: I753ead2fffbfc65427ed4e9244c7066610e546da --- include/asterisk/bridge.h | 12 ++++++++++++ main/bridge.c | 10 +++++----- main/bridge_channel.c | 4 ++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index 8858cf02cf6..acea2f01fbb 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -746,6 +746,18 @@ int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan); */ int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan); +/*! + * \brief Sets BRIDGECHANNEL and BRIDGEPVTCALLID for a channel + * + * \pre chan must be locked before calling + * + * \param name channel name of the bridged peer + * \param pvtid Private CallID of the bridged peer + * + * \return nothing + */ +void ast_bridge_vars_set(struct ast_channel *chan, const char *name, const char *pvtid); + struct ast_unreal_pvt; /*! diff --git a/main/bridge.c b/main/bridge.c index ebbfc397654..7451a163c7e 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -1211,7 +1211,7 @@ static void check_bridge_play_sounds(struct ast_bridge *bridge) } } -static void update_bridge_vars_set(struct ast_channel *chan, const char *name, const char *pvtid) +void ast_bridge_vars_set(struct ast_channel *chan, const char *name, const char *pvtid) { ast_channel_stage_snapshot(chan); pbx_builtin_setvar_helper(chan, "BRIDGEPEER", name); @@ -1251,12 +1251,12 @@ static void set_bridge_peer_vars_2party(struct ast_channel *c0, struct ast_chann ast_channel_unlock(c1); ast_channel_lock(c0); - update_bridge_vars_set(c0, c1_name, c1_pvtid); + ast_bridge_vars_set(c0, c1_name, c1_pvtid); UPDATE_BRIDGE_VARS_GET(c0, c0_name, c0_pvtid); ast_channel_unlock(c0); ast_channel_lock(c1); - update_bridge_vars_set(c1, c0_name, c0_pvtid); + ast_bridge_vars_set(c1, c0_name, c0_pvtid); ast_channel_unlock(c1); } @@ -1357,7 +1357,7 @@ static void set_bridge_peer_vars_multiparty(struct ast_bridge *bridge) ++idx; ast_channel_lock(bridge_channel->chan); - update_bridge_vars_set(bridge_channel->chan, buf, NULL); + ast_bridge_vars_set(bridge_channel->chan, buf, NULL); ast_channel_unlock(bridge_channel->chan); } } @@ -1379,7 +1379,7 @@ static void set_bridge_peer_vars_holding(struct ast_bridge *bridge) AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { ast_channel_lock(bridge_channel->chan); - update_bridge_vars_set(bridge_channel->chan, NULL, NULL); + ast_bridge_vars_set(bridge_channel->chan, NULL, NULL); ast_channel_unlock(bridge_channel->chan); } } diff --git a/main/bridge_channel.c b/main/bridge_channel.c index be0819a5c4f..f3483e4403f 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -289,6 +289,10 @@ void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_ch channel_set_cause(bridge_channel->chan, cause); + ast_channel_lock(bridge_channel->chan); + ast_bridge_vars_set(bridge_channel->chan, NULL, NULL); + ast_channel_unlock(bridge_channel->chan); + /* Change the state on the bridge channel */ bridge_channel->state = new_state; From bd265a90be0f372ce71301ce358e92cdf2a5434d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 30 Nov 2015 21:19:18 -0700 Subject: [PATCH 0056/1578] res_pjsip: Update logging to show contact->uri in messages An earlier commit changed the id of dynamic contacts to contain a hash instead of the uri. This patch updates status change logging to show the aor/uri instead of the id. This required adding the aor id to contact and contact_status and adding uri to contact_status. The aor id gets added to contact and contact_status in their allocators and the uri gets added to contact_status in pjsip_options when the contact_status is created or updated. ASTERISK-25598 #close Reported-by: George Joseph Tested-by: George Joseph Change-Id: I56cbec1d2ddbe8461367dd8b6da8a6f47f6fe511 --- include/asterisk/res_pjsip.h | 8 ++ res/res_pjsip/location.c | 18 +++- res/res_pjsip/pjsip_configuration.c | 138 +++++++++++----------------- res/res_pjsip/pjsip_options.c | 63 +++++++++---- 4 files changed, 120 insertions(+), 107 deletions(-) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 95b8f23eb92..d9123f983b1 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -159,6 +159,8 @@ struct ast_sip_contact { AST_STRING_FIELD(path); /*! Content of the User-Agent header in REGISTER request */ AST_STRING_FIELD(user_agent); + /*! The name of the aor this contact belongs to */ + AST_STRING_FIELD(aor); ); /*! Absolute time that this contact is no longer valid after */ struct timeval expiration_time; @@ -193,6 +195,12 @@ enum ast_sip_contact_status_type { */ struct ast_sip_contact_status { SORCERY_OBJECT(details); + AST_DECLARE_STRING_FIELDS( + /*! The original contact's URI */ + AST_STRING_FIELD(uri); + /*! The name of the aor this contact_status belongs to */ + AST_STRING_FIELD(aor); + ); /*! Current status for a contact (default - unavailable) */ enum ast_sip_contact_status_type status; /*! The round trip start time set before sending a qualify request */ diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 2e0d84b84a4..4471d7c5884 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -99,6 +99,9 @@ static void contact_destroy(void *obj) static void *contact_alloc(const char *name) { struct ast_sip_contact *contact = ast_sorcery_generic_alloc(sizeof(*contact), contact_destroy); + char *id = ast_strdupa(name); + char *aor = id; + char *aor_separator = NULL; if (!contact) { return NULL; @@ -109,6 +112,14 @@ static void *contact_alloc(const char *name) return NULL; } + /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ + if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) { + *aor_separator = '\0'; + } + ast_assert(aor_separator != NULL); + + ast_string_field_set(contact, aor, aor); + return contact; } @@ -790,13 +801,14 @@ static int cli_contact_print_body(void *obj, void *arg, int flags) ast_assert(context->output_buffer != NULL); indent = CLI_INDENT_TO_SPACES(context->indent_level); - flexwidth = CLI_LAST_TABSTOP - indent - 2; + flexwidth = CLI_LAST_TABSTOP - indent - 2 - strlen(contact->aor) + 1; - ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s %11.3f\n", + ast_str_append(&context->output_buffer, 0, "%*s: %s/%-*.*s %-12.12s %11.3f\n", indent, "Contact", + contact->aor, flexwidth, flexwidth, - wrapper->contact_id, + contact->uri, ast_sip_get_contact_short_status_label(status ? status->status : UNKNOWN), (status && (status->status != UNKNOWN) ? ((long long) status->rtt) / 1000.0 : NAN)); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 3a6f9d7609a..30e56749bff 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -56,47 +56,37 @@ static int persistent_endpoint_cmp(void *obj, void *arg, int flags) return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0; } -/*! \brief Structure for communicating contact status to - * persistent_endpoint_update_state from the contact/contact_status - * observers. - */ -struct sip_contact_status { - char *uri; - enum ast_sip_contact_status_type status; - int64_t rtt; -}; - /*! \brief Callback function for changing the state of an endpoint */ -static int persistent_endpoint_update_state(void *obj, void *arg, void *data, int flags) +static int persistent_endpoint_update_state(void *obj, void *arg, int flags) { struct sip_persistent_endpoint *persistent = obj; struct ast_endpoint *endpoint = persistent->endpoint; - char *aor = arg; - struct sip_contact_status *status = data; + struct ast_sip_contact_status *status = arg; struct ao2_container *contacts; struct ast_json *blob; struct ao2_iterator i; struct ast_sip_contact *contact; enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; - if (!ast_strlen_zero(aor)) { - if (!strstr(persistent->aors, aor)) { + if (status) { + char rtt[32]; + + /* If the status' aor isn't one of the endpoint's, we skip */ + if (!strstr(persistent->aors, status->aor)) { return 0; } - if (status) { - char rtt[32]; - snprintf(rtt, 31, "%" PRId64, status->rtt); - blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", - "contact_status", ast_sip_get_contact_status_label(status->status), - "aor", aor, - "uri", status->uri, - "roundtrip_usec", rtt, - "endpoint_name", ast_endpoint_get_resource(endpoint)); - ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); - ast_json_unref(blob); - } + snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt); + blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", + "contact_status", ast_sip_get_contact_status_label(status->status), + "aor", status->aor, + "uri", status->uri, + "roundtrip_usec", rtt, + "endpoint_name", ast_endpoint_get_resource(endpoint)); + ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); + ast_json_unref(blob); } + /* Find all the contacts for this endpoint. If ANY are available, * mark the endpoint as ONLINE. */ @@ -142,57 +132,50 @@ static int persistent_endpoint_update_state(void *obj, void *arg, void *data, in return 0; } -/*! \brief Function called when stuff relating to a contact happens (created/deleted) */ +/*! \brief Function called when a contact is created */ static void persistent_endpoint_contact_created_observer(const void *object) { const struct ast_sip_contact *contact = object; - char *id = ast_strdupa(ast_sorcery_object_get_id(contact)); - char *aor = NULL; - char *contact_uri = NULL; - struct sip_contact_status status; - - aor = id; - /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ - if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) { - *contact_uri = '\0'; - contact_uri += 2; - } else { - contact_uri = id; + struct ast_sip_contact_status *contact_status; + + contact_status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, + ast_sorcery_object_get_id(contact)); + if (!contact_status) { + ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", + contact->aor, contact->uri); + return; } + ast_string_field_set(contact_status, uri, contact->uri); - status.uri = contact_uri; - status.status = CREATED; - status.rtt = 0; + contact_status->status = CREATED; - ast_verb(1, "Contact %s/%s has been created\n", aor, contact_uri); + ast_verb(1, "Contact %s/%s has been created\n",contact->aor, contact->uri); - ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status); + ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); + ao2_cleanup(contact_status); } -/*! \brief Function called when stuff relating to a contact happens (created/deleted) */ +/*! \brief Function called when a contact is deleted */ static void persistent_endpoint_contact_deleted_observer(const void *object) { - char *id = ast_strdupa(ast_sorcery_object_get_id(object)); - char *aor = NULL; - char *contact_uri = NULL; - struct sip_contact_status status; + const struct ast_sip_contact *contact = object; + struct ast_sip_contact_status *contact_status; - aor = id; - /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ - if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) { - *contact_uri = '\0'; - contact_uri += 2; - } else { - contact_uri = id; + contact_status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, + ast_sorcery_object_get_id(contact)); + if (!contact_status) { + ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", + contact->aor, contact->uri); + return; } + ast_string_field_set(contact_status, uri, contact->uri); - ast_verb(1, "Contact %s/%s has been deleted\n", aor, contact_uri); + contact_status->status = REMOVED; - status.uri = contact_uri; - status.status = REMOVED; - status.rtt = 0; + ast_verb(1, "Contact %s/%s has been deleted\n", contact->aor, contact->uri); - ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status); + ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); + ao2_cleanup(contact_status); } /*! \brief Observer for contacts so state can be updated on respective endpoints */ @@ -201,36 +184,23 @@ static const struct ast_sorcery_observer state_contact_observer = { .deleted = persistent_endpoint_contact_deleted_observer, }; -/*! \brief Function called when stuff relating to a contact status happens (updated) */ +/*! \brief Function called when a contact_status is updated */ static void persistent_endpoint_contact_status_observer(const void *object) { - const struct ast_sip_contact_status *contact_status = object; - char *id = ast_strdupa(ast_sorcery_object_get_id(object)); - char *aor = NULL; - char *contact_uri = NULL; - struct sip_contact_status status; + struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object; /* If rtt_start is set (this is the outgoing OPTIONS), ignore. */ if (contact_status->rtt_start.tv_sec > 0) { return; } - aor = id; - /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ - if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) { - *contact_uri = '\0'; - contact_uri += 2; - } else { - contact_uri = id; - } - if (contact_status->status == contact_status->last_status) { - ast_debug(3, "Contact %s status didn't change: %s, RTT: %.3f msec\n", - contact_uri, ast_sip_get_contact_status_label(contact_status->status), + ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n", + contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); return; } else { - ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", aor, contact_uri, + ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); } @@ -241,11 +211,7 @@ static void persistent_endpoint_contact_status_observer(const void *object) ast_sorcery_object_get_id(contact_status), ast_sip_get_contact_status_label(contact_status->status)); - status.uri = contact_uri; - status.status = contact_status->status; - status.rtt = contact_status->rtt; - - ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status); + ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); } /*! \brief Observer for contacts so state can be updated on respective endpoints */ @@ -1085,7 +1051,7 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_ if (ast_strlen_zero(persistent->aors)) { ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN); } else { - persistent_endpoint_update_state(persistent, NULL, NULL, 0); + persistent_endpoint_update_state(persistent, NULL, 0); } ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK); diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index d55a9958718..6762b754e4a 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -42,7 +42,6 @@ static const char *status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", - }; static const char *short_status_map [] = { @@ -63,20 +62,47 @@ const char *ast_sip_get_contact_short_status_label(const enum ast_sip_contact_st return short_status_map[status]; } +/*! + * \internal + * \brief Destroy a ast_sip_contact_status object. + */ +static void contact_status_destroy(void * obj) +{ + struct ast_sip_contact_status *status = obj; + + ast_string_field_free_memory(status); +} + /*! * \internal * \brief Create a ast_sip_contact_status object. */ static void *contact_status_alloc(const char *name) { - struct ast_sip_contact_status *status = ast_sorcery_generic_alloc(sizeof(*status), NULL); + struct ast_sip_contact_status *status = ast_sorcery_generic_alloc(sizeof(*status), contact_status_destroy); + char *id = ast_strdupa(name); + char *aor = id; + char *aor_separator = NULL; if (!status) { ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status\n"); return NULL; } - status->status = UNKNOWN; + if (ast_string_field_init(status, 256)) { + ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status stringfields\n"); + ao2_cleanup(status); + return NULL; + } + + /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ + if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) { + *aor_separator = '\0'; + } + ast_assert(aor_separator != NULL); + + ast_string_field_set(status, aor, aor); + status->status = CREATED; return status; } @@ -98,12 +124,12 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!status) { - ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s\n", - contact->uri); + ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", + contact->aor, contact->uri); return NULL; } - status->status = UNKNOWN; + ast_string_field_set(status, uri, contact->uri); status->rtt_start = ast_tv(0, 0); status->rtt = 0; @@ -127,8 +153,8 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const static void update_contact_status(const struct ast_sip_contact *contact, enum ast_sip_contact_status_type value) { - struct ast_sip_contact_status *status; - struct ast_sip_contact_status *update; + RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup); status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { @@ -145,6 +171,7 @@ static void update_contact_status(const struct ast_sip_contact *contact, return; } + ast_string_field_set(update, uri, contact->uri); update->last_status = status->status; update->status = value; if (update->last_status != update->status) { @@ -175,9 +202,6 @@ static void update_contact_status(const struct ast_sip_contact *contact, ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", contact->uri); } - - ao2_ref(status, -1); - ao2_ref(update, -1); } /*! @@ -187,8 +211,8 @@ static void update_contact_status(const struct ast_sip_contact *contact, */ static void init_start_time(const struct ast_sip_contact *contact) { - struct ast_sip_contact_status *status; - struct ast_sip_contact_status *update; + RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup); status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { @@ -205,6 +229,7 @@ static void init_start_time(const struct ast_sip_contact *contact) return; } + ast_string_field_set(status, uri, contact->uri); update->status = status->status; update->last_status = status->last_status; update->rtt = status->rtt; @@ -214,9 +239,6 @@ static void init_start_time(const struct ast_sip_contact *contact) ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", contact->uri); } - - ao2_ref(status, -1); - ao2_ref(update, -1); } /*! @@ -993,6 +1015,9 @@ static int rtt_start_to_str(const void *obj, const intptr_t *args, char **buf) return 0; } +static char status_value_unknown[2]; +static char status_value_created[2]; + int ast_sip_initialize_sorcery_qualify(void) { struct ast_sorcery *sorcery = ast_sip_get_sorcery(); @@ -1006,10 +1031,12 @@ int ast_sip_initialize_sorcery_qualify(void) return -1; } + snprintf(status_value_unknown, sizeof(status_value_unknown), "%u", UNKNOWN); ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "last_status", - "0", OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, last_status)); + status_value_unknown, OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, last_status)); + snprintf(status_value_created, sizeof(status_value_created), "%u", CREATED); ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "status", - "0", OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, status)); + status_value_created, OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, status)); ast_sorcery_object_field_register_custom_nodoc(sorcery, CONTACT_STATUS, "rtt_start", "0.0", rtt_start_handler, rtt_start_to_str, NULL, 0, 0); ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "rtt", From 59591860170264e2a48677b63a65d54e261fd69e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 3 Dec 2015 11:07:49 -0700 Subject: [PATCH 0057/1578] res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph --- res/res_pjsip/location.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 4471d7c5884..8f540cf6be5 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -388,7 +388,8 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab while ((contact_uri = strsep(&contacts, ","))) { struct ast_sip_contact *contact; struct ast_sip_contact_status *status; - char contact_id[strlen(aor_id) + strlen(contact_uri) + 2 + 1]; + char hash[33]; + char contact_id[strlen(aor_id) + sizeof(hash) + 2 + 1]; if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, @@ -398,7 +399,8 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab } } - snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, contact_uri); + ast_md5_hash(hash, contact_uri); + snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, hash); contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id); if (!contact) { return -1; @@ -774,12 +776,12 @@ static int cli_contact_print_header(void *obj, void *arg, int flags) { struct ast_sip_cli_context *context = arg; int indent = CLI_INDENT_TO_SPACES(context->indent_level); - int filler = CLI_LAST_TABSTOP - indent - 18; + int filler = CLI_LAST_TABSTOP - indent - 23; ast_assert(context->output_buffer != NULL); ast_str_append(&context->output_buffer, 0, - "%*s: \n", + "%*s: \n", indent, "Contact", filler, filler, CLI_HEADER_FILLER); return 0; @@ -792,23 +794,26 @@ static int cli_contact_print_body(void *obj, void *arg, int flags) struct ast_sip_cli_context *context = arg; int indent; int flexwidth; + const char *contact_id = ast_sorcery_object_get_id(contact); + const char *hash_start = contact_id + strlen(contact->aor) + 2; RAII_VAR(struct ast_sip_contact_status *, status, - ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)), + ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, contact_id), ao2_cleanup); ast_assert(contact->uri != NULL); ast_assert(context->output_buffer != NULL); indent = CLI_INDENT_TO_SPACES(context->indent_level); - flexwidth = CLI_LAST_TABSTOP - indent - 2 - strlen(contact->aor) + 1; + flexwidth = CLI_LAST_TABSTOP - indent - 9 - strlen(contact->aor) + 1; - ast_str_append(&context->output_buffer, 0, "%*s: %s/%-*.*s %-12.12s %11.3f\n", + ast_str_append(&context->output_buffer, 0, "%*s: %s/%-*.*s %-10.10s %-7.7s %11.3f\n", indent, "Contact", contact->aor, flexwidth, flexwidth, contact->uri, + hash_start, ast_sip_get_contact_short_status_label(status ? status->status : UNKNOWN), (status && (status->status != UNKNOWN) ? ((long long) status->rtt) / 1000.0 : NAN)); From 69457b8d61ddc62e018dd4037fb42a231f73c3b5 Mon Sep 17 00:00:00 2001 From: Jonathan Rose Date: Wed, 2 Dec 2015 14:11:08 -0600 Subject: [PATCH 0058/1578] Fix crash in audiohook translate to slin This patch fixes a crash which would occur when an audiohook was applied to a channel using an audio codec that could not be translated to signed linear (such as when using pass-through codecs like OPUS or when the codec translator module for the format in use is not loaded). ASTERISK-25498 #close Reported by: Ben Langfeld Change-Id: Ib6ea7373fcc22e537cad373996136636201f4384 --- main/audiohook.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/main/audiohook.c b/main/audiohook.c index 73bb0ff110c..e3089131e18 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -824,13 +824,20 @@ static struct ast_frame *audiohook_list_translate_to_slin(struct ast_audiohook_l return new_frame; } - if (ast_format_cmp(frame->subclass.format, in_translate->format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (!in_translate->format || + ast_format_cmp(frame->subclass.format, in_translate->format) != AST_FORMAT_CMP_EQUAL) { + struct ast_trans_pvt *new_trans; + + new_trans = ast_translator_build_path(slin, frame->subclass.format); + if (!new_trans) { + return NULL; + } + if (in_translate->trans_pvt) { ast_translator_free_path(in_translate->trans_pvt); } - if (!(in_translate->trans_pvt = ast_translator_build_path(slin, frame->subclass.format))) { - return NULL; - } + in_translate->trans_pvt = new_trans; + ao2_replace(in_translate->format, frame->subclass.format); } From dcc01bc0a7ced76246f5fd85c1217407e86d3026 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Sat, 21 Nov 2015 12:35:33 +0100 Subject: [PATCH 0059/1578] res_format_attr_opus: Update to latest RFC 7587. Beside that, the format-attribute module sends only non-default values in the line fmtp, now. This avoids unnecessary overhead in SDP messages. Furthermore, previously the parameter stereo was not parsed when being the first parameter. ASTERISK-25583 #close Change-Id: Iae85ba3e5960bfd5d51cf65bcffad00dd4875a73 --- res/res_format_attr_opus.c | 210 ++++++++++++++++++++++++++----------- 1 file changed, 151 insertions(+), 59 deletions(-) diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index 3c9c3ef304a..4c09bef6756 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -33,28 +33,36 @@ ASTERISK_REGISTER_FILE() #include "asterisk/module.h" #include "asterisk/format.h" +#include "asterisk/logger.h" /* for ast_log, LOG_WARNING */ +#include "asterisk/strings.h" /* for ast_str_append */ +#include "asterisk/utils.h" /* for MIN, ast_malloc, ast_free */ /*! * \brief Opus attribute structure. * - * \note http://tools.ietf.org/html/draft-ietf-payload-rtp-opus-00. + * \note http://tools.ietf.org/html/rfc7587#section-6 */ struct opus_attr { - unsigned int maxbitrate; /* Default 64-128 kb/s for FB stereo music */ - unsigned int maxplayrate /* Default 48000 */; - unsigned int minptime; /* Default 3, but it's 10 in format.c */ - unsigned int stereo; /* Default 0 */ - unsigned int cbr; /* Default 0 */ - unsigned int fec; /* Default 0 */ - unsigned int dtx; /* Default 0 */ - unsigned int spropmaxcapturerate; /* Default 48000 */ - unsigned int spropstereo; /* Default 0 */ + unsigned int maxbitrate; + unsigned int maxplayrate; + unsigned int unused; /* was minptime, kept for binary compatibility */ + unsigned int stereo; + unsigned int cbr; + unsigned int fec; + unsigned int dtx; + unsigned int spropmaxcapturerate; + unsigned int spropstereo; }; static struct opus_attr default_opus_attr = { - .fec = 0, - .dtx = 0, - .stereo = 0, + .maxplayrate = 48000, + .spropmaxcapturerate = 48000, + .maxbitrate = 510000, + .stereo = 0, + .spropstereo = 0, + .cbr = 0, + .fec = 1, + .dtx = 0, }; static void opus_destroy(struct ast_format *format) @@ -67,7 +75,7 @@ static void opus_destroy(struct ast_format *format) static int opus_clone(const struct ast_format *src, struct ast_format *dst) { struct opus_attr *original = ast_format_get_attribute_data(src); - struct opus_attr *attr = ast_calloc(1, sizeof(*attr)); + struct opus_attr *attr = ast_malloc(sizeof(*attr)); if (!attr) { return -1; @@ -75,6 +83,8 @@ static int opus_clone(const struct ast_format *src, struct ast_format *dst) if (original) { *attr = *original; + } else { + *attr = default_opus_attr; } ast_format_set_attribute_data(dst, attr); @@ -97,33 +107,54 @@ static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, c if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) { attr->maxplayrate = val; + } else { + attr->maxplayrate = 48000; } + if ((kvp = strstr(attributes, "sprop-maxcapturerate")) && sscanf(kvp, "sprop-maxcapturerate=%30u", &val) == 1) { attr->spropmaxcapturerate = val; + } else { + attr->spropmaxcapturerate = 48000; } - if ((kvp = strstr(attributes, "minptime")) && sscanf(kvp, "minptime=%30u", &val) == 1) { - attr->minptime = val; - } + if ((kvp = strstr(attributes, "maxaveragebitrate")) && sscanf(kvp, "maxaveragebitrate=%30u", &val) == 1) { attr->maxbitrate = val; + } else { + attr->maxbitrate = 510000; } - if ((kvp = strstr(attributes, " stereo")) && sscanf(kvp, " stereo=%30u", &val) == 1) { - attr->stereo = val; - } - if ((kvp = strstr(attributes, ";stereo")) && sscanf(kvp, ";stereo=%30u", &val) == 1) { - attr->stereo = val; + + if (!strncmp(attributes, "stereo=1", 8)) { + attr->stereo = 1; + } else if (strstr(attributes, " stereo=1")) { + attr->stereo = 1; + } else if (strstr(attributes, ";stereo=1")) { + attr->stereo = 1; + } else { + attr->stereo = 0; } - if ((kvp = strstr(attributes, "sprop-stereo")) && sscanf(kvp, "sprop-stereo=%30u", &val) == 1) { - attr->spropstereo = val; + + if (strstr(attributes, "sprop-stereo=1")) { + attr->spropstereo = 1; + } else { + attr->spropstereo = 0; } - if ((kvp = strstr(attributes, "cbr")) && sscanf(kvp, "cbr=%30u", &val) == 1) { - attr->cbr = val; + + if (strstr(attributes, "cbr=1")) { + attr->cbr = 1; + } else { + attr->cbr = 0; } - if ((kvp = strstr(attributes, "useinbandfec")) && sscanf(kvp, "useinbandfec=%30u", &val) == 1) { - attr->fec = val; + + if (strstr(attributes, "useinbandfec=1")) { + attr->fec = 1; + } else { + attr->fec = 0; } - if ((kvp = strstr(attributes, "usedtx")) && sscanf(kvp, "usedtx=%30u", &val) == 1) { - attr->dtx = val; + + if (strstr(attributes, "usedtx=1")) { + attr->dtx = 1; + } else { + attr->dtx = 0; } return cloned; @@ -132,34 +163,92 @@ static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, c static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { struct opus_attr *attr = ast_format_get_attribute_data(format); + int added = 0; if (!attr) { - return; + /* + * (Only) cached formats do not have attribute data assigned because + * they were created before this attribute module was registered. + * Therefore, we assume the default attribute values here. + */ + attr = &default_opus_attr; + } + + if (48000 != attr->maxplayrate) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "maxplaybackrate=%u", attr->maxplayrate); + } + + if (48000 != attr->spropmaxcapturerate) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "sprop-maxcapturerate=%u", attr->spropmaxcapturerate); + } + + if (510000 != attr->maxbitrate) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "maxaveragebitrate=%u", attr->maxbitrate); + } + + if (0 != attr->stereo) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "stereo=%u", attr->stereo); } - /* FIXME should we only generate attributes that were explicitly set? */ - ast_str_append(str, 0, - "a=fmtp:%u " - "maxplaybackrate=%u;" - "sprop-maxcapturerate=%u;" - "minptime=%u;" - "maxaveragebitrate=%u;" - "stereo=%d;" - "sprop-stereo=%d;" - "cbr=%d;" - "useinbandfec=%d;" - "usedtx=%d\r\n", - payload, - attr->maxplayrate ? attr->maxplayrate : 48000, /* maxplaybackrate */ - attr->spropmaxcapturerate ? attr->spropmaxcapturerate : 48000, /* sprop-maxcapturerate */ - attr->minptime > 10 ? attr->minptime : 10, /* minptime */ - attr->maxbitrate ? attr->maxbitrate : 20000, /* maxaveragebitrate */ - attr->stereo ? 1 : 0, /* stereo */ - attr->spropstereo ? 1 : 0, /* sprop-stereo */ - attr->cbr ? 1 : 0, /* cbr */ - attr->fec ? 1 : 0, /* useinbandfec */ - attr->dtx ? 1 : 0 /* usedtx */ - ); + if (0 != attr->spropstereo) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "sprop-stereo=%u", attr->spropstereo); + } + + if (0 != attr->cbr) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "cbr=%u", attr->cbr); + } + + if (0 != attr->fec) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "useinbandfec=%u", attr->fec); + } + + if (0 != attr->dtx) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "usedtx=%u", attr->dtx); + } + + if (added) { + ast_str_append(str, 0, "\r\n"); + } } static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2) @@ -183,19 +272,22 @@ static struct ast_format *opus_getjoint(const struct ast_format *format1, const } attr_res = ast_format_get_attribute_data(jointformat); - /* Only do dtx if both sides want it. DTX is a trade off between - * computational complexity and bandwidth. */ - attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0; + attr_res->dtx = attr1->dtx || attr2->dtx ? 1 : 0; /* Only do FEC if both sides want it. If a peer specifically requests not * to receive with FEC, it may be a waste of bandwidth. */ attr_res->fec = attr1->fec && attr2->fec ? 1 : 0; + attr_res->cbr = attr1->cbr || attr2->cbr ? 1 : 0; + attr_res->spropstereo = attr1->spropstereo || attr2->spropstereo ? 1 : 0; + /* Only do stereo if both sides want it. If a peer specifically requests not * to receive stereo signals, it may be a waste of bandwidth. */ attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0; - /* FIXME: do we need to join other attributes as well, e.g., minptime, cbr, etc.? */ + attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); + attr_res->spropmaxcapturerate = MIN(attr1->spropmaxcapturerate, attr2->spropmaxcapturerate); + attr_res->maxplayrate = MIN(attr1->maxplayrate, attr2->maxplayrate); return jointformat; } @@ -223,7 +315,7 @@ static struct ast_format *opus_set(const struct ast_format *format, const char * } else if (!strcasecmp(name, "max_playrate")) { attr->maxplayrate = val; } else if (!strcasecmp(name, "minptime")) { - attr->minptime = val; + attr->unused = val; } else if (!strcasecmp(name, "stereo")) { attr->stereo = val; } else if (!strcasecmp(name, "cbr")) { From f42d22d3a1ca5c8ea73df99a50c6a28caa8f8749 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 28 Nov 2015 08:46:02 -0600 Subject: [PATCH 0060/1578] bridges/bridge_t38: Add a bridging module for managing T.38 state When 4875e5ac32 was merged, it fixed several issues with a direct media bridge transitioning to handling a T.38 fax. However, it uncovered a race condition caused by the bridging core. When a channel involved in a T.38 fax leaves a bridge, the frame queued by the channel driver that should inform the far side that it is no longer in a T.38 fax may not make it across the bridge. The bridging framework is *extremely* aggressive in tearing down the bridge, and control frames that are currently in flight *may* get dropped. This patch adds a new module to the bridging framework, bridge_t38. This module maintains some notion of the T.38 state for the two channels in a bridge. When the bridge detects that it is being torn down or when one of the two channels leaves, it informs the respective channel(s) that they should stop faxing. This ensures that channels switch back to audio if they survive and are ejected out of a bridge while faxing. ASTERISK-25582 Change-Id: If5b0bb478eb01c4607c9f4a7fc17c7957d260ea0 --- CHANGES | 8 ++ bridges/bridge_t38.c | 261 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+) create mode 100644 bridges/bridge_t38.c diff --git a/CHANGES b/CHANGES index ca7d1610087..2b9f8e6972e 100644 --- a/CHANGES +++ b/CHANGES @@ -205,6 +205,14 @@ Queue --- Functionality changes from Asterisk 13.6.0 to Asterisk 13.7.0 ------------ ------------------------------------------------------------------------------ +bridge_t38 +------------------ + * A new module for the bridging framework, this bridge technology acts in the + same fashion as bridge_simple, save that it helps to maintain the state of + T.38 for two channels passing a fax through Asterisk. This helps to resolve + several esoteric issues that can occur when channels are removed from a + bridge after completing a T.38 fax. + ConfBridge ------------------ * A new "timeout" user profile option has been added. This configures the number diff --git a/bridges/bridge_t38.c b/bridges/bridge_t38.c new file mode 100644 index 00000000000..eb4e4536a55 --- /dev/null +++ b/bridges/bridge_t38.c @@ -0,0 +1,261 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Digium, Inc. + * + * Matt Jordan + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Bridging module for maintaining T.38 state for faxing channels + * + * \author Matt Jordan + * + * \ingroup bridges + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/bridge.h" +#include "asterisk/bridge_technology.h" +#include "asterisk/frame.h" + +/*! \brief The current state of the T.38 fax for the channels in our bridge */ +struct t38_bridge_state { + /* \brief First channel in the bridge */ + struct ast_bridge_channel *bc0; + /*! \brief Second channel in the bridge */ + struct ast_bridge_channel *bc1; + /*! \brief T.38 state of \c bc0 */ + enum ast_t38_state c0_state; + /*! \brief T.38 state of \c bc1 */ + enum ast_t38_state c1_state; +}; + +static void t38_bridge_destroy(struct ast_bridge *bridge) +{ + struct t38_bridge_state *state = bridge->tech_pvt; + + ast_free(state); + bridge->tech_pvt = NULL; +} + +static int t38_bridge_create(struct ast_bridge *bridge) +{ + struct t38_bridge_state *state; + + state = ast_calloc(1, sizeof(*state)); + if (!state) { + return -1; + } + + bridge->tech_pvt = state; + + return 0; +} + +static int t38_bridge_start(struct ast_bridge *bridge) +{ + struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); + struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); + struct t38_bridge_state *state = bridge->tech_pvt; + + state->bc0 = bc0; + state->bc1 = bc1; + state->c0_state = ast_channel_get_t38_state(state->bc0->chan); + state->c1_state = ast_channel_get_t38_state(state->bc1->chan); + + return 0; +} + +static void send_termination_update(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, enum ast_t38_state chan_state) +{ + /* Inform the other side that T.38 faxing is done */ + struct ast_control_t38_parameters parameters = { .request_response = 0, }; + + if (!bridge_channel) { + return; + } + + ast_debug(5, "Bridge %s T.38: Current state of %s is %d\n", + bridge->uniqueid, ast_channel_name(bridge_channel->chan), chan_state); + if (chan_state == T38_STATE_NEGOTIATING) { + parameters.request_response = AST_T38_REFUSED; + } else if (chan_state == T38_STATE_NEGOTIATED) { + parameters.request_response = AST_T38_TERMINATED; + } + + if (parameters.request_response) { + struct ast_frame f = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_T38_PARAMETERS, + .data.ptr = ¶meters, + .datalen = sizeof(parameters), + }; + + /* When sending a termination update to a channel, the bridge is highly + * likely to be getting torn down. Queueing a frame through the bridging + * framework won't work, as the frame will likely just get tossed as the + * bridge collapses. Hence, we write directly to the channel to ensure that + * they know they aren't in a T.38 fax any longer. + */ + ast_debug(3, "Bridge %s T.38: Informing %s to switch to %d\n", + bridge->uniqueid, ast_channel_name(bridge_channel->chan), parameters.request_response); + ast_write(bridge_channel->chan, &f); + } +} + +static void t38_bridge_stop(struct ast_bridge *bridge) +{ + struct t38_bridge_state *state = bridge->tech_pvt; + + send_termination_update(bridge, state->bc0, state->c0_state); + send_termination_update(bridge, state->bc1, state->c1_state); +} + +static void t38_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) +{ + struct t38_bridge_state *state = bridge->tech_pvt; + + if (bridge_channel == state->bc0) { + send_termination_update(bridge, state->bc0, state->c0_state); + state->bc0 = NULL; + state->c0_state = T38_STATE_UNKNOWN; + } else { + send_termination_update(bridge, state->bc1, state->c1_state); + state->bc1 = NULL; + state->c1_state = T38_STATE_UNKNOWN; + } +} + +static int t38_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) +{ + struct t38_bridge_state *state = bridge->tech_pvt; + enum ast_t38_state *c_state; + enum ast_t38_state *other_state; + + if (!bridge_channel) { + return -1; + } + + c_state = bridge_channel == state->bc0 ? &(state->c0_state) : &(state->c1_state); + other_state = bridge_channel == state->bc0 ? &(state->c1_state) : &(state->c0_state); + + switch (frame->frametype) { + case AST_FRAME_CONTROL: + switch (frame->subclass.integer) { + case AST_CONTROL_T38_PARAMETERS: + { + struct ast_control_t38_parameters *parameters = frame->data.ptr; + + switch (parameters->request_response) { + case AST_T38_REQUEST_NEGOTIATE: + *c_state = T38_STATE_NEGOTIATING; + *other_state = T38_STATE_NEGOTIATING; + break; + case AST_T38_NEGOTIATED: + *c_state = T38_STATE_NEGOTIATED; + break; + case AST_T38_TERMINATED: + case AST_T38_REQUEST_TERMINATE: + case AST_T38_REFUSED: + *c_state = T38_STATE_REJECTED; + break; + case AST_T38_REQUEST_PARMS: + default: + /* No state change */ + break; + } + ast_debug(3, "Bridge %s T.38 state: %s: %d; %s: %d\n", + bridge->uniqueid, ast_channel_name(state->bc0->chan), state->c0_state, + ast_channel_name(state->bc1->chan), state->c1_state); + break; + } + default: + break; + } + break; + default: + break; + } + + return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame); +} + +static int t38_bridge_compatible(struct ast_bridge *bridge) +{ + struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); + struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); + enum ast_t38_state c0_state; + enum ast_t38_state c1_state; + + /* We must have two, and only two, channels in a T.38 bridge */ + if (bridge->num_channels != 2) { + ast_debug(1, "Bridge '%s' can not use T.38 bridge as two channels are required\n", + bridge->uniqueid); + return 0; + } + + /* We can be the bridge tech so long as one side is in the process + * of negotiating T.38 + */ + c0_state = ast_channel_get_t38_state(bc0->chan); + c1_state = ast_channel_get_t38_state(bc1->chan); + if (c0_state != T38_STATE_NEGOTIATING && c0_state != T38_STATE_NEGOTIATED + && c1_state != T38_STATE_NEGOTIATING && c1_state != T38_STATE_NEGOTIATED) { + ast_debug(1, "Bridge '%s' can not use T.38 bridge: channel %s has T.38 state %d; channel %s has T.38 state %d\n", + bridge->uniqueid, ast_channel_name(bc0->chan), c0_state, ast_channel_name(bc1->chan), c1_state); + return 0; + } + + return 1; +} + +static struct ast_bridge_technology t38_bridge = { + .name = "t38_bridge", + .capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX, + .preference = AST_BRIDGE_PREFERENCE_BASE_1TO1MIX + 1, + .create = t38_bridge_create, + .destroy = t38_bridge_destroy, + .start = t38_bridge_start, + .stop = t38_bridge_stop, + .leave = t38_bridge_leave, + .write = t38_bridge_write, + .compatible = t38_bridge_compatible, +}; + +static int unload_module(void) +{ + ast_bridge_technology_unregister(&t38_bridge); + + return 0; +} + +static int load_module(void) +{ + if (ast_bridge_technology_register(&t38_bridge)) { + return AST_MODULE_LOAD_DECLINE; + } + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Two channel bridging module that maintains T.38 state"); From 63c6d39a3e7e059ab122ec991d1e892f615d863d Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Sat, 21 Nov 2015 13:08:49 +0100 Subject: [PATCH 0061/1578] res_format_attr_vp8: In SDP, forward max-fr and max-fs for video-codec VP8. ASTERISK-25584 #close Change-Id: Iae00071b4ff1ae76f24995aeac4d00284fd14f91 --- CHANGES | 5 + res/res_format_attr_vp8.c | 228 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 res/res_format_attr_vp8.c diff --git a/CHANGES b/CHANGES index 2b9f8e6972e..1180fbfa3b3 100644 --- a/CHANGES +++ b/CHANGES @@ -213,6 +213,11 @@ bridge_t38 several esoteric issues that can occur when channels are removed from a bridge after completing a T.38 fax. +Codecs +------------------ + * Added format attribute negotiation for the VP8 video codec. Format attribute + negotiation is provided by the res_format_attr_vp8 module. + ConfBridge ------------------ * A new "timeout" user profile option has been added. This configures the number diff --git a/res/res_format_attr_vp8.c b/res/res_format_attr_vp8.c new file mode 100644 index 00000000000..777239aaea9 --- /dev/null +++ b/res/res_format_attr_vp8.c @@ -0,0 +1,228 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Alexander Traud + * + * Alexander Traud + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief VP8 format attribute interface + * + * \author Alexander Traud + * + * \note http://tools.ietf.org/html/draft-ietf-payload-vp8 + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/module.h" +#include "asterisk/format.h" +#include "asterisk/logger.h" /* for ast_log, LOG_WARNING */ +#include "asterisk/strings.h" /* for ast_str_append */ +#include "asterisk/utils.h" /* for MIN, ast_malloc, ast_free */ + +struct vp8_attr { + unsigned int maximum_frame_rate; + unsigned int maximum_frame_size; +}; + +static struct vp8_attr default_vp8_attr = { + .maximum_frame_rate = UINT_MAX, + .maximum_frame_size = UINT_MAX, +}; + +static void vp8_destroy(struct ast_format *format) +{ + struct vp8_attr *attr = ast_format_get_attribute_data(format); + + ast_free(attr); +} + +static int vp8_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct vp8_attr *original = ast_format_get_attribute_data(src); + struct vp8_attr *attr = ast_malloc(sizeof(*attr)); + + if (!attr) { + return -1; + } + + if (original) { + *attr = *original; + } else { + *attr = default_vp8_attr; + } + + ast_format_set_attribute_data(dst, attr); + + return 0; +} + +static struct ast_format *vp8_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + struct ast_format *cloned; + struct vp8_attr *attr; + const char *kvp; + unsigned int val; + + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + if ((kvp = strstr(attributes, "max-fr")) && sscanf(kvp, "max-fr=%30u", &val) == 1) { + attr->maximum_frame_rate = val; + } else { + attr->maximum_frame_rate = UINT_MAX; + } + + if ((kvp = strstr(attributes, "max-fs")) && sscanf(kvp, "max-fs=%30u", &val) == 1) { + attr->maximum_frame_size = val; + } else { + attr->maximum_frame_size = UINT_MAX; + } + + return cloned; +} + +static void vp8_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) +{ + struct vp8_attr *attr = ast_format_get_attribute_data(format); + int added = 0; + + if (!attr) { + /* + * (Only) cached formats do not have attribute data assigned because + * they were created before this attribute module was registered. + * Therefore, we assume the default attribute values here. + */ + attr = &default_vp8_attr; + } + + if (UINT_MAX != attr->maximum_frame_rate) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "max-fr=%u", attr->maximum_frame_rate); + } + + if (UINT_MAX != attr->maximum_frame_size) { + if (added) { + ast_str_append(str, 0, ";"); + } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { + added = 1; + } + ast_str_append(str, 0, "max-fs=%u", attr->maximum_frame_size); + } + + if (added) { + ast_str_append(str, 0, "\r\n"); + } +} + +static struct ast_format *vp8_getjoint(const struct ast_format *format1, const struct ast_format *format2) +{ + struct vp8_attr *attr1 = ast_format_get_attribute_data(format1); + struct vp8_attr *attr2 = ast_format_get_attribute_data(format2); + struct ast_format *jointformat; + struct vp8_attr *attr_res; + + if (!attr1) { + attr1 = &default_vp8_attr; + } + + if (!attr2) { + attr2 = &default_vp8_attr; + } + + jointformat = ast_format_clone(format1); + if (!jointformat) { + return NULL; + } + attr_res = ast_format_get_attribute_data(jointformat); + + attr_res->maximum_frame_rate = MIN(attr1->maximum_frame_rate, attr2->maximum_frame_rate); + attr_res->maximum_frame_size = MIN(attr1->maximum_frame_size, attr2->maximum_frame_size); + + return jointformat; +} + +static struct ast_format *vp8_set(const struct ast_format *format, const char *name, const char *value) +{ + struct ast_format *cloned; + struct vp8_attr *attr; + unsigned int val; + + if (sscanf(value, "%30u", &val) != 1) { + ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n", + value, name); + return NULL; + } + + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + if (!strcasecmp(name, "maximum_frame_rate")) { + attr->maximum_frame_rate = val; + } else if (!strcasecmp(name, "maximum_frame_size")) { + attr->maximum_frame_size = val; + } else { + ast_log(LOG_WARNING, "unknown attribute type %s\n", name); + } + + return cloned; +} + +static struct ast_format_interface vp8_interface = { + .format_destroy = vp8_destroy, + .format_clone = vp8_clone, + .format_get_joint = vp8_getjoint, + .format_attribute_set = vp8_set, + .format_parse_sdp_fmtp = vp8_parse_sdp_fmtp, + .format_generate_sdp_fmtp = vp8_generate_sdp_fmtp, +}; + +static int load_module(void) +{ + if (ast_format_interface_register("vp8", &vp8_interface)) { + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "VP8 Format Attribute Module", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND, +); From 4be231e82f840fb1cb2329698ba2184d8b726f2c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 4 Dec 2015 15:23:21 -0700 Subject: [PATCH 0062/1578] res_pjsip/contacts/statsd: Make contact lifecycle events more consistent It will never be perfect or even pretty, mostly because of the differences between static and dynamic contacts. Created: Can't use the contact or contact_status alloc functions because the objects come and go regardless of the actual state. Can't use the contact_apply_handler, ast_sip_location_add_contact or a sorcery created handler because they only get called for dynamic contacts. Similarly, permanent_uri_handler only gets called for static contacts. So, Matt had it right. :) ast_res_pjsip_find_or_create_contact_status is the only place it can go and not have duplicated code. Both permanent_uri_handler and contact_apply_handler call find_or_create. Removed: Can't use the destructors for the same reason as above. The only place to put this is in persistent_endpoint_contact_deleted_observer which I believe is the "correct" place but even that will handle only dynamic contacts. This doesn't called on shutdown however. There is no hook to use for static contacts that may be removed because of a config change while asterisk is in operation. I moved the cleanup of contact_status from ast_sip_location_delete_contact to the handler as well. Status Change and RTT: Although they worked fine where they were (in update_contact_status) I moved them to persistent_endpoint_contact_status_observer to make it more consistent with removed. There was logic there already to detect a state change. Finally, fixed a nit in permanent_uri_handler rmudgett reported eralier. ASTERISK-25608 #close Change-Id: I4b56e7dfc3be3baaaf6f1eac5b2068a0b79e357d Reported-by: George Joseph Tested-by: George Joseph --- res/res_pjsip/location.c | 15 +++------- res/res_pjsip/pjsip_configuration.c | 45 +++++++++++++++++------------ res/res_pjsip/pjsip_options.c | 9 ------ 3 files changed, 31 insertions(+), 38 deletions(-) diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 8f540cf6be5..c070e7dbceb 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -317,14 +317,6 @@ int ast_sip_location_update_contact(struct ast_sip_contact *contact) int ast_sip_location_delete_contact(struct ast_sip_contact *contact) { - void *contact_status_obj; - - contact_status_obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); - if (contact_status_obj) { - ast_sorcery_delete(ast_sip_get_sorcery(), contact_status_obj); - ao2_ref(contact_status_obj, -1); - } - return ast_sorcery_delete(ast_sip_get_sorcery(), contact); } @@ -389,7 +381,7 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab struct ast_sip_contact *contact; struct ast_sip_contact_status *status; char hash[33]; - char contact_id[strlen(aor_id) + sizeof(hash) + 2 + 1]; + char contact_id[strlen(aor_id) + sizeof(hash) + 2]; if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, @@ -406,6 +398,8 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab return -1; } + ast_string_field_set(contact, uri, contact_uri); + status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { ao2_ref(contact, -1); @@ -413,7 +407,6 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab } ao2_ref(status, -1); - ast_string_field_set(contact, uri, contact_uri); ao2_link(aor->permanent_contacts, contact); ao2_ref(contact, -1); } @@ -1031,7 +1024,7 @@ int ast_sip_initialize_sorcery_location(void) * Note that this must done here, as contacts will create the contact_status * object before PJSIP options handling is initialized. */ - for (i = 0; i < REMOVED; i++) { + for (i = 0; i <= REMOVED; i++) { ast_statsd_log_full_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, 0, 1.0, ast_sip_get_contact_status_label(i)); } diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 30e56749bff..3bb08694517 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -20,6 +20,7 @@ #include "asterisk/sorcery.h" #include "asterisk/callerid.h" #include "asterisk/test.h" +#include "asterisk/statsd.h" /*! \brief Number of buckets for persistent endpoint information */ #define PERSISTENT_BUCKETS 53 @@ -161,20 +162,21 @@ static void persistent_endpoint_contact_deleted_observer(const void *object) const struct ast_sip_contact *contact = object; struct ast_sip_contact_status *contact_status; - contact_status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, - ast_sorcery_object_get_id(contact)); + contact_status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!contact_status) { ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", contact->aor, contact->uri); return; } - ast_string_field_set(contact_status, uri, contact->uri); - - contact_status->status = REMOVED; ast_verb(1, "Contact %s/%s has been deleted\n", contact->aor, contact->uri); + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, + "-1", 1.0, ast_sip_get_contact_status_label(contact_status->status)); + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, + "+1", 1.0, ast_sip_get_contact_status_label(REMOVED)); ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); + ast_sorcery_delete(ast_sip_get_sorcery(), contact_status); ao2_cleanup(contact_status); } @@ -194,24 +196,31 @@ static void persistent_endpoint_contact_status_observer(const void *object) return; } - if (contact_status->status == contact_status->last_status) { - ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n", - contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), - contact_status->rtt / 1000.0); - return; - } else { + if (contact_status->status != contact_status->last_status) { ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); - } - ast_test_suite_event_notify("AOR_CONTACT_UPDATE", - "Contact: %s\r\n" - "Status: %s", - ast_sorcery_object_get_id(contact_status), - ast_sip_get_contact_status_label(contact_status->status)); + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, + "-1", 1.0, ast_sip_get_contact_status_label(contact_status->last_status)); + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, + "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status)); - ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); + ast_test_suite_event_notify("AOR_CONTACT_UPDATE", + "Contact: %s\r\n" + "Status: %s", + ast_sorcery_object_get_id(contact_status), + ast_sip_get_contact_status_label(contact_status->status)); + + ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); + } else { + ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n", + contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), + contact_status->rtt / 1000.0); + } + + ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER, + contact_status->status != AVAILABLE ? -1 : contact_status->rtt / 1000, 1.0, ast_sorcery_object_get_id(contact_status)); } /*! \brief Observer for contacts so state can be updated on respective endpoints */ diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 6762b754e4a..089703b2690 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -174,22 +174,13 @@ static void update_contact_status(const struct ast_sip_contact *contact, ast_string_field_set(update, uri, contact->uri); update->last_status = status->status; update->status = value; - if (update->last_status != update->status) { - ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, - "-1", 1.0, ast_sip_get_contact_status_label(update->last_status)); - ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, - "+1", 1.0, ast_sip_get_contact_status_label(update->status)); - } /* if the contact is available calculate the rtt as the diff between the last start time and "now" */ update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ? ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0; - update->rtt_start = ast_tv(0, 0); - ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER, - update->rtt / 1000, 1.0, ast_sorcery_object_get_id(update)); ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", "Contact: %s\r\n" "Status: %s\r\n" From 75c800eb2885588fa958e3b82815639c84c0de93 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sun, 6 Dec 2015 16:35:24 -0600 Subject: [PATCH 0063/1578] Revert "bridges/bridge_t38: Add a bridging module for managing T.38 state" This reverts commit f42d22d3a1ca5c8ea73df99a50c6a28caa8f8749. Unfortunately, using a bridge to manage T.38 state will cause severe deadlocks in core_unreal/chan_local. Local channels attempt to reach across both their peer and the peer's bridge to inspect T.38 state. Given the propensity of Local channel chains, managing the locking situation in such a scenario is practically infeasible. Change-Id: I932107387c13aad2c75a7a4c1e94197a9d6d8a51 --- CHANGES | 8 -- bridges/bridge_t38.c | 261 ------------------------------------------- 2 files changed, 269 deletions(-) delete mode 100644 bridges/bridge_t38.c diff --git a/CHANGES b/CHANGES index 1180fbfa3b3..dfb159082be 100644 --- a/CHANGES +++ b/CHANGES @@ -205,14 +205,6 @@ Queue --- Functionality changes from Asterisk 13.6.0 to Asterisk 13.7.0 ------------ ------------------------------------------------------------------------------ -bridge_t38 ------------------- - * A new module for the bridging framework, this bridge technology acts in the - same fashion as bridge_simple, save that it helps to maintain the state of - T.38 for two channels passing a fax through Asterisk. This helps to resolve - several esoteric issues that can occur when channels are removed from a - bridge after completing a T.38 fax. - Codecs ------------------ * Added format attribute negotiation for the VP8 video codec. Format attribute diff --git a/bridges/bridge_t38.c b/bridges/bridge_t38.c deleted file mode 100644 index eb4e4536a55..00000000000 --- a/bridges/bridge_t38.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2015, Digium, Inc. - * - * Matt Jordan - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Bridging module for maintaining T.38 state for faxing channels - * - * \author Matt Jordan - * - * \ingroup bridges - */ - -/*** MODULEINFO - core - ***/ - -#include "asterisk.h" - -ASTERISK_REGISTER_FILE() - -#include "asterisk/module.h" -#include "asterisk/channel.h" -#include "asterisk/bridge.h" -#include "asterisk/bridge_technology.h" -#include "asterisk/frame.h" - -/*! \brief The current state of the T.38 fax for the channels in our bridge */ -struct t38_bridge_state { - /* \brief First channel in the bridge */ - struct ast_bridge_channel *bc0; - /*! \brief Second channel in the bridge */ - struct ast_bridge_channel *bc1; - /*! \brief T.38 state of \c bc0 */ - enum ast_t38_state c0_state; - /*! \brief T.38 state of \c bc1 */ - enum ast_t38_state c1_state; -}; - -static void t38_bridge_destroy(struct ast_bridge *bridge) -{ - struct t38_bridge_state *state = bridge->tech_pvt; - - ast_free(state); - bridge->tech_pvt = NULL; -} - -static int t38_bridge_create(struct ast_bridge *bridge) -{ - struct t38_bridge_state *state; - - state = ast_calloc(1, sizeof(*state)); - if (!state) { - return -1; - } - - bridge->tech_pvt = state; - - return 0; -} - -static int t38_bridge_start(struct ast_bridge *bridge) -{ - struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); - struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); - struct t38_bridge_state *state = bridge->tech_pvt; - - state->bc0 = bc0; - state->bc1 = bc1; - state->c0_state = ast_channel_get_t38_state(state->bc0->chan); - state->c1_state = ast_channel_get_t38_state(state->bc1->chan); - - return 0; -} - -static void send_termination_update(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, enum ast_t38_state chan_state) -{ - /* Inform the other side that T.38 faxing is done */ - struct ast_control_t38_parameters parameters = { .request_response = 0, }; - - if (!bridge_channel) { - return; - } - - ast_debug(5, "Bridge %s T.38: Current state of %s is %d\n", - bridge->uniqueid, ast_channel_name(bridge_channel->chan), chan_state); - if (chan_state == T38_STATE_NEGOTIATING) { - parameters.request_response = AST_T38_REFUSED; - } else if (chan_state == T38_STATE_NEGOTIATED) { - parameters.request_response = AST_T38_TERMINATED; - } - - if (parameters.request_response) { - struct ast_frame f = { - .frametype = AST_FRAME_CONTROL, - .subclass.integer = AST_CONTROL_T38_PARAMETERS, - .data.ptr = ¶meters, - .datalen = sizeof(parameters), - }; - - /* When sending a termination update to a channel, the bridge is highly - * likely to be getting torn down. Queueing a frame through the bridging - * framework won't work, as the frame will likely just get tossed as the - * bridge collapses. Hence, we write directly to the channel to ensure that - * they know they aren't in a T.38 fax any longer. - */ - ast_debug(3, "Bridge %s T.38: Informing %s to switch to %d\n", - bridge->uniqueid, ast_channel_name(bridge_channel->chan), parameters.request_response); - ast_write(bridge_channel->chan, &f); - } -} - -static void t38_bridge_stop(struct ast_bridge *bridge) -{ - struct t38_bridge_state *state = bridge->tech_pvt; - - send_termination_update(bridge, state->bc0, state->c0_state); - send_termination_update(bridge, state->bc1, state->c1_state); -} - -static void t38_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) -{ - struct t38_bridge_state *state = bridge->tech_pvt; - - if (bridge_channel == state->bc0) { - send_termination_update(bridge, state->bc0, state->c0_state); - state->bc0 = NULL; - state->c0_state = T38_STATE_UNKNOWN; - } else { - send_termination_update(bridge, state->bc1, state->c1_state); - state->bc1 = NULL; - state->c1_state = T38_STATE_UNKNOWN; - } -} - -static int t38_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) -{ - struct t38_bridge_state *state = bridge->tech_pvt; - enum ast_t38_state *c_state; - enum ast_t38_state *other_state; - - if (!bridge_channel) { - return -1; - } - - c_state = bridge_channel == state->bc0 ? &(state->c0_state) : &(state->c1_state); - other_state = bridge_channel == state->bc0 ? &(state->c1_state) : &(state->c0_state); - - switch (frame->frametype) { - case AST_FRAME_CONTROL: - switch (frame->subclass.integer) { - case AST_CONTROL_T38_PARAMETERS: - { - struct ast_control_t38_parameters *parameters = frame->data.ptr; - - switch (parameters->request_response) { - case AST_T38_REQUEST_NEGOTIATE: - *c_state = T38_STATE_NEGOTIATING; - *other_state = T38_STATE_NEGOTIATING; - break; - case AST_T38_NEGOTIATED: - *c_state = T38_STATE_NEGOTIATED; - break; - case AST_T38_TERMINATED: - case AST_T38_REQUEST_TERMINATE: - case AST_T38_REFUSED: - *c_state = T38_STATE_REJECTED; - break; - case AST_T38_REQUEST_PARMS: - default: - /* No state change */ - break; - } - ast_debug(3, "Bridge %s T.38 state: %s: %d; %s: %d\n", - bridge->uniqueid, ast_channel_name(state->bc0->chan), state->c0_state, - ast_channel_name(state->bc1->chan), state->c1_state); - break; - } - default: - break; - } - break; - default: - break; - } - - return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame); -} - -static int t38_bridge_compatible(struct ast_bridge *bridge) -{ - struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); - struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); - enum ast_t38_state c0_state; - enum ast_t38_state c1_state; - - /* We must have two, and only two, channels in a T.38 bridge */ - if (bridge->num_channels != 2) { - ast_debug(1, "Bridge '%s' can not use T.38 bridge as two channels are required\n", - bridge->uniqueid); - return 0; - } - - /* We can be the bridge tech so long as one side is in the process - * of negotiating T.38 - */ - c0_state = ast_channel_get_t38_state(bc0->chan); - c1_state = ast_channel_get_t38_state(bc1->chan); - if (c0_state != T38_STATE_NEGOTIATING && c0_state != T38_STATE_NEGOTIATED - && c1_state != T38_STATE_NEGOTIATING && c1_state != T38_STATE_NEGOTIATED) { - ast_debug(1, "Bridge '%s' can not use T.38 bridge: channel %s has T.38 state %d; channel %s has T.38 state %d\n", - bridge->uniqueid, ast_channel_name(bc0->chan), c0_state, ast_channel_name(bc1->chan), c1_state); - return 0; - } - - return 1; -} - -static struct ast_bridge_technology t38_bridge = { - .name = "t38_bridge", - .capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX, - .preference = AST_BRIDGE_PREFERENCE_BASE_1TO1MIX + 1, - .create = t38_bridge_create, - .destroy = t38_bridge_destroy, - .start = t38_bridge_start, - .stop = t38_bridge_stop, - .leave = t38_bridge_leave, - .write = t38_bridge_write, - .compatible = t38_bridge_compatible, -}; - -static int unload_module(void) -{ - ast_bridge_technology_unregister(&t38_bridge); - - return 0; -} - -static int load_module(void) -{ - if (ast_bridge_technology_register(&t38_bridge)) { - return AST_MODULE_LOAD_DECLINE; - } - return AST_MODULE_LOAD_SUCCESS; -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Two channel bridging module that maintains T.38 state"); From 48c065e46db8c8f9301ee0220229a58c43f958ec Mon Sep 17 00:00:00 2001 From: Christof Lauber Date: Fri, 13 Nov 2015 14:58:15 +0100 Subject: [PATCH 0064/1578] chan_sip: Support parsing of Q.850 reason header in SIP BYE and CANCEL requests. Current support for reason header did work only in SIP responses. According to RFC3336 the reason header might appear in any SIP request. But it seems to make most sence in BYE and CANCEL so parasing is done there too (if use_q850_reason=yes). Change-Id: Ib6be7b34c23a76d0e98dfd0816c89931000ac790 --- channels/chan_sip.c | 71 +++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 3b200e21723..4870d0f4a29 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1399,6 +1399,7 @@ static char *remove_uri_parameters(char *uri); static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req); static int get_also_info(struct sip_pvt *p, struct sip_request *oreq); static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req); +static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req); static int set_address_from_contact(struct sip_pvt *pvt); static void check_via(struct sip_pvt *p, const struct sip_request *req); static int get_rpid(struct sip_pvt *p, struct sip_request *oreq); @@ -16121,6 +16122,49 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req) return TRUE; } +/*! + * \brief Parses SIP reason header according to RFC3326 and sets channel's hangupcause if configured so + * and header present + * + * \note This is used in BYE and CANCEL request and SIP response, but according to RFC3326 it could + * appear in any request, but makes not a lot of sense in others than BYE or CANCEL. + * Currently only implemented for Q.850 status codes. + * \retval 0 success + * \retval -1 on failure or if not configured + */ +static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req) +{ + int ret, cause; + const char *rp, *rh; + + if (!pvt->owner) { + return -1; + } + + if (!ast_test_flag(&pvt->flags[1], SIP_PAGE2_Q850_REASON) || + !(rh = sip_get_header(req, "Reason"))) { + return -1; + } + + rh = ast_skip_blanks(rh); + if (strncasecmp(rh, "Q.850", 5)) { + return -1; + } + + ret = -1; + cause = ast_channel_hangupcause(pvt->owner); + rp = strstr(rh, "cause="); + if (rp && sscanf(rp + 6, "%3d", &cause) == 1) { + ret = 0; + ast_channel_hangupcause_set(pvt->owner, cause & 0x7f); + if (req->debug) { + ast_verbose("Using Reason header for cause code: %d\n", + ast_channel_hangupcause(pvt->owner)); + } + } + return ret; +} + /*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled * * \note This calls parse_uri which has the unexpected property that passing more @@ -24107,27 +24151,13 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc msg = ""; sipmethod = find_sip_method(msg); - owner = p->owner; if (owner) { - const char *rp = NULL, *rh = NULL; - ast_channel_hangupcause_set(owner, 0); - if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && (rh = sip_get_header(req, "Reason"))) { - rh = ast_skip_blanks(rh); - if (!strncasecmp(rh, "Q.850", 5)) { - int cause = ast_channel_hangupcause(owner); - rp = strstr(rh, "cause="); - if (rp && sscanf(rp + 6, "%30d", &cause) == 1) { - ast_channel_hangupcause_set(owner, cause & 0x7f); - if (req->debug) - ast_verbose("Using Reason header for cause code: %d\n", ast_channel_hangupcause(owner)); - } - } - } - - if (!ast_channel_hangupcause(owner)) + if (use_reason_header(p, req)) { + /* Use the SIP cause */ ast_channel_hangupcause_set(owner, hangup_sip2cause(resp)); + } } if (p->socket.type == AST_TRANSPORT_UDP) { @@ -26419,6 +26449,8 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req) return 0; } + use_reason_header(p, req); + /* At this point, we could have cancelled the invite at the same time as the other side sends a CANCEL. Our final reply with error code might not have been received by the other side before the CANCEL @@ -26435,7 +26467,7 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req) stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */ if (p->owner) { - sip_queue_hangup_cause(p, 0); + sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner)); } else { sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); } @@ -26614,6 +26646,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req) stop_session_timer(p); /* Stop Session-Timer */ } + use_reason_header(p, req); if (!ast_strlen_zero(sip_get_header(req, "Also"))) { ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method. Ask vendor to support REFER instead\n", ast_sockaddr_stringify(&p->recv)); @@ -26654,7 +26687,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req) ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR); } } else if (p->owner) { - sip_queue_hangup_cause(p, 0); + sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner)); sip_scheddestroy_final(p, DEFAULT_TRANS_TIMEOUT); ast_debug(3, "Received bye, issuing owner hangup\n"); } else { From 65c8147952b60b1f16e05fb62d5b5f889775d3a6 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 4 Dec 2015 15:36:45 -0600 Subject: [PATCH 0065/1578] chan_sip: Fix crash involving the bogus peer during sip reload. A crash happens sometimes when performing a CLI "sip reload". The bogus peer gets refreshed while it is in use by a new call which can cause the crash. * Protected the global bogus peer object with an ao2 global object container. ASTERISK-25610 #close Change-Id: I5b528c742195681abcf713c6e1011ea65354eeed --- channels/chan_sip.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4870d0f4a29..b2d61127fc6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -997,9 +997,9 @@ static struct ao2_container *threadt; static struct ao2_container *peers; static struct ao2_container *peers_by_ip; -/*! \brief A bogus peer, to be used when authentication should fail */ -static struct sip_peer *bogus_peer; -/*! \brief We can recognise the bogus peer by this invalid MD5 hash */ +/*! \brief A bogus peer, to be used when authentication should fail */ +static AO2_GLOBAL_OBJ_STATIC(g_bogus_peer); +/*! \brief We can recognize the bogus peer by this invalid MD5 hash */ #define BOGUS_PEER_MD5SECRET "intentionally_invalid_md5_string" /*! \brief The register list: Other SIP proxies we register with and receive calls from */ @@ -17228,8 +17228,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock /* If we don't want username disclosure, use the bogus_peer when a user * is not found. */ if (!peer && sip_cfg.alwaysauthreject && sip_cfg.autocreatepeer == AUTOPEERS_DISABLED) { - peer = bogus_peer; - sip_ref_peer(peer, "register_verify: ref the bogus_peer"); + peer = ao2_t_global_obj_ref(g_bogus_peer, "register_verify: Get the bogus peer."); } if (!(peer && ast_apply_acl(peer->acl, addr, "SIP Peer ACL: "))) { @@ -18482,6 +18481,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, enum check_auth_result res; int debug = sip_debug_test_addr(addr); struct sip_peer *peer; + struct sip_peer *bogus_peer; if (sipmethod == SIP_SUBSCRIBE) { /* For subscribes, match on device name only; for other methods, @@ -18521,8 +18521,13 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, /* If you do mind, we use a peer that will never authenticate. * This ensures that we follow the same code path as regular * auth: less chance for username disclosure. */ - peer = bogus_peer; - sip_ref_peer(peer, "sip_ref_peer: check_peer_ok: must ref bogus_peer so unreffing it does not fail"); + peer = ao2_t_global_obj_ref(g_bogus_peer, "check_peer_ok: Get the bogus peer."); + if (!peer) { + return AUTH_DONT_KNOW; + } + bogus_peer = peer; + } else { + bogus_peer = NULL; } /* build_peer, called through sip_find_peer, is not able to check the @@ -33194,7 +33199,7 @@ static int sip_do_reload(enum channelreloadreason reason) /*! \brief Force reload of module from cli */ static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - static struct sip_peer *tmp_peer, *new_peer; + static struct sip_peer *new_peer; switch (cmd) { case CLI_INIT: @@ -33217,13 +33222,13 @@ static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a ast_mutex_unlock(&sip_reload_lock); restart_monitor(); - tmp_peer = bogus_peer; /* Create new bogus peer possibly with new global settings. */ if ((new_peer = temp_peer("(bogus_peer)"))) { ast_string_field_set(new_peer, md5secret, BOGUS_PEER_MD5SECRET); ast_clear_flag(&new_peer->flags[0], SIP_INSECURE); - bogus_peer = new_peer; - ao2_t_ref(tmp_peer, -1, "unref the old bogus_peer during reload"); + ao2_t_global_obj_replace_unref(g_bogus_peer, new_peer, + "Replacing the old bogus peer during reload."); + ao2_t_ref(new_peer, -1, "done with new_peer"); } else { ast_log(LOG_ERROR, "Could not update the fake authentication peer.\n"); /* You probably have bigger (memory?) issues to worry about though.. */ @@ -34474,6 +34479,8 @@ static int unload_module(void); */ static int load_module(void) { + struct sip_peer *bogus_peer; + ast_verbose("SIP channel loading...\n"); if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) { @@ -34545,6 +34552,8 @@ static int load_module(void) /* Make sure the auth will always fail. */ ast_string_field_set(bogus_peer, md5secret, BOGUS_PEER_MD5SECRET); ast_clear_flag(&bogus_peer->flags[0], SIP_INSECURE); + ao2_t_global_obj_replace_unref(g_bogus_peer, bogus_peer, "Set the initial bogus peer."); + ao2_t_ref(bogus_peer, -1, "Module load is done with the bogus peer."); /* Prepare the version that does not require DTMF BEGIN frames. * We need to use tricks such as memcpy and casts because the variable @@ -34829,7 +34838,7 @@ static int unload_module(void) ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); } - ao2_t_cleanup(bogus_peer, "unref the bogus_peer"); + ao2_t_global_obj_release(g_bogus_peer, "Release the bogus peer."); ao2_t_cleanup(peers, "unref the peers table"); ao2_t_cleanup(peers_by_ip, "unref the peers_by_ip table"); From 64f899e5f3d4afe9de56653e5a65236197d819b5 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 8 Dec 2015 10:46:21 +0100 Subject: [PATCH 0066/1578] translate: Avoid a warning message when doing FEC within Opus Codec. ASTERISK-25616 #close Change-Id: Ibe729aaf2e6e25506cff247cec5149ec1e589319 --- main/translate.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/main/translate.c b/main/translate.c index 61a827b71a6..8d37e372416 100644 --- a/main/translate.c +++ b/main/translate.c @@ -397,9 +397,6 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format /*! \brief framein wrapper, deals with bound checks. */ static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { - int ret; - int samples = pvt->samples; /* initial value */ - /* Copy the last in jb timing info to the pvt */ ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO); pvt->f.ts = f->ts; @@ -423,12 +420,7 @@ static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f) /* we require a framein routine, wouldn't know how to do * it otherwise. */ - ret = pvt->t->framein(pvt, f); - /* diagnostic ... */ - if (pvt->samples == samples) - ast_log(LOG_WARNING, "%s did not update samples %d\n", - pvt->t->name, pvt->samples); - return ret; + return pvt->t->framein(pvt, f); } /*! \brief generic frameout routine. From 55dd7125b386aa3648fc5bb96998b6a1d275f49d Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 8 Dec 2015 15:39:03 +0100 Subject: [PATCH 0067/1578] codec_resample: Increase buffer for Opus Codec with FEC. ASTERISK-25599 #close Change-Id: Idbd187f711b2ec63dda949ca0f79aa0c1a0a0b6e --- codecs/codec_resample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecs/codec_resample.c b/codecs/codec_resample.c index 3c8a149d78f..1c73bf3c8ed 100644 --- a/codecs/codec_resample.c +++ b/codecs/codec_resample.c @@ -38,7 +38,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/translate.h" #include "asterisk/slin.h" -#define OUTBUF_SAMPLES 5760 +#define OUTBUF_SAMPLES 11520 static struct ast_translator *translators; static int trans_size; From 28ab03fbf74d52ccf2d31f2f8f06ad0127924ce6 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 8 Dec 2015 10:03:53 -0700 Subject: [PATCH 0068/1578] res_pjsip/config_transport: Prevent async_operations > 1 when protocol = tls See ASTERISK-25615. If the transport protocol is tls and async_operations > 1, pjproject will segfault if more than one operation is attempted on the same socket. Until this is fixed upstream, a check has been added to throw an error if a tls transport config has async_operations set to > 1. ASTERISK-25615 Change-Id: I76b9a5b2a5a0054fe71ca5851e635f2dca7685a6 Reported-by: George Joseph Tested-by: George Joseph --- res/res_pjsip/config_transport.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index e9986612c6a..e2f0c7f4347 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -216,6 +216,14 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory); } else if (transport->type == AST_TRANSPORT_TLS) { + /* The following check is a work-around for ASTERISK-25615. + * When that issue is resolved in upstream pjproject, this check can be removed. + */ + if (transport->async_operations > 1) { + ast_log(LOG_ERROR, "Transport: %s: When protocol=tls, async_operations can't be > 1 (ASTERISK-25615)\n", + ast_sorcery_object_get_id(obj)); + return -1; + } transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file); #ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 transport->tls.ca_list_path = pj_str((char*)transport->ca_list_path); From 59a91c350a48dcea7dc2bf1e22f5c2cef602772b Mon Sep 17 00:00:00 2001 From: Filip Jenicek Date: Tue, 8 Dec 2015 08:57:22 +0100 Subject: [PATCH 0069/1578] chan_sip: Check sip_pvt pointer in ast_channel_get_t38_state(c) Asterisk may crash when calling ast_channel_get_t38_state(c) on a locked channel which is being hung up. ASTERISK-25609 #close Change-Id: Ifaa707c04b865a290ffab719bd2e5c48ff667c7b --- channels/chan_sip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b2d61127fc6..cd03e151a19 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -4757,6 +4757,11 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int struct sip_pvt *p = (struct sip_pvt *) ast_channel_tech_pvt(chan); char *cp; + if (!p) { + ast_debug(1, "Attempt to Ref a null pointer. Sip private structure is gone!\n"); + return -1; + } + sip_pvt_lock(p); switch (option) { From be693539c3119e0f1ce6d4c031e9fc11e4489bba Mon Sep 17 00:00:00 2001 From: Eugene Voityuk Date: Wed, 2 Dec 2015 20:42:15 +0200 Subject: [PATCH 0070/1578] chan_sip.c: Start ICE negotiation when response is sent or received. The current logic for ICE negotiation starts it when receiving an SDP with ICE candidates. This is incorrect as ICE negotiation can only start when each call party have at least one pair of local and remote candidate. Starting ICE negotiation early would result in negotiation failure and ultimately no audio. This change makes it so ICE negotiation is only started when a response with SDP is received or when a response with SDP is sent. ASTERISK-24146 Change-Id: I55a632bde9e9827871b09141d82747e08379a8ca --- channels/chan_sip.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b2d61127fc6..812232ef148 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -10629,7 +10629,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Setup audio address and port */ if (p->rtp) { if (sa && portno > 0) { - start_ice(p->rtp, (req->method != SIP_RESPONSE) ? 0 : 1); + /* Start ICE negotiation here, only when it is response, and setting that we are conrolling agent, + as we are offerer */ + if (req->method == SIP_RESPONSE) { + start_ice(p->rtp, 1); + } ast_sockaddr_set_port(sa, portno); ast_rtp_instance_set_remote_address(p->rtp, sa); if (debug) { @@ -13403,6 +13407,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int if (!doing_directmedia) { if (ast_test_flag(&p->flags[2], SIP_PAGE3_ICE_SUPPORT)) { add_ice_to_sdp(p->rtp, &a_audio); + /* Start ICE negotiation, and setting that we are controlled agent, + as this is response to offer */ + if (resp->method == SIP_RESPONSE) { + start_ice(p->rtp, 0); + } } add_dtls_to_sdp(p->rtp, &a_audio); From a9874345648dbcf66eefecc8fc2ccaba93fa216e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 8 Dec 2015 16:49:20 -0700 Subject: [PATCH 0071/1578] res_pjsip: Add existence and readablity checks for tls related files Both transport and endpoint now check for the existence and readability of tls certificate and key files before passing them on to pjproject. This will cause the object to not load rather than waiting for pjproject to discover that there's a problem when a session is attempted. NOTE: chan_sip also uses ast_rtp_dtls_cfg_parse but it's located in build_peer which is gigantic and I didn't want to disturb it. Error messages will emit but it won't interrupt chan_sip loading. ASTERISK-25618 #close Change-Id: Ie43f2c1d653ac1fda6a6f6faecb7c2ebadaf47c9 Reported-by: George Joseph Tested-by: George Joseph --- include/asterisk/utils.h | 10 ++++++++++ main/rtp_engine.c | 16 ++++++++++++++++ main/utils.c | 17 +++++++++++++++++ res/res_pjsip/config_transport.c | 29 +++++++++++++++++++++++++++++ res/res_pjsip/pjsip_configuration.c | 2 +- 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 664e347cf26..832500c31e7 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -1089,4 +1089,14 @@ char *ast_crypt_encrypt(const char *key); */ int ast_crypt_validate(const char *key, const char *expected); +/* + * \brief Test that a file exists and is readable by the effective user. + * \since 13.7.0 + * + * \param filename File to test. + * \return True (non-zero) if the file exists and is readable. + * \return False (zero) if the file either doesn't exists or is not readable. + */ +int ast_file_is_readable(const char *filename); + #endif /* _ASTERISK_UTILS_H */ diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 32909090f66..24e56b49fb1 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2118,18 +2118,34 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, } } else if (!strcasecmp(name, "dtlscertfile")) { ast_free(dtls_cfg->certfile); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->certfile = ast_strdup(value); } else if (!strcasecmp(name, "dtlsprivatekey")) { ast_free(dtls_cfg->pvtfile); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->pvtfile = ast_strdup(value); } else if (!strcasecmp(name, "dtlscipher")) { ast_free(dtls_cfg->cipher); dtls_cfg->cipher = ast_strdup(value); } else if (!strcasecmp(name, "dtlscafile")) { ast_free(dtls_cfg->cafile); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->cafile = ast_strdup(value); } else if (!strcasecmp(name, "dtlscapath") || !strcasecmp(name, "dtlscadir")) { ast_free(dtls_cfg->capath); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->capath = ast_strdup(value); } else if (!strcasecmp(name, "dtlssetup")) { if (!strcasecmp(value, "active")) { diff --git a/main/utils.c b/main/utils.c index ba1a07ca242..74932b8c27d 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2927,3 +2927,20 @@ int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2) { return memcmp(eid1, eid2, sizeof(*eid1)); } + +int ast_file_is_readable(const char *filename) +{ +#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) +#if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS) +#define eaccess euidaccess +#endif + return eaccess(filename, R_OK) == 0; +#else + int fd = open(filename, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + return 0; + } + close(fd); + return 1; +#endif +} diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index e2f0c7f4347..d8ece150944 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -27,6 +27,7 @@ #include "asterisk/astobj2.h" #include "asterisk/sorcery.h" #include "asterisk/acl.h" +#include "asterisk/utils.h" #include "include/res_pjsip_private.h" #include "asterisk/http_websocket.h" @@ -224,8 +225,22 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) ast_sorcery_object_get_id(obj)); return -1; } + if (!ast_strlen_zero(transport->ca_list_file)) { + if (!ast_file_is_readable(transport->ca_list_file)) { + ast_log(LOG_ERROR, "Transport: %s: ca_list_file %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->ca_list_file); + return -1; + } + } transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file); #ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 + if (!ast_strlen_zero(transport->ca_list_path)) { + if (!ast_file_is_readable(transport->ca_list_path)) { + ast_log(LOG_ERROR, "Transport: %s: ca_list_path %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->ca_list_path); + return -1; + } + } transport->tls.ca_list_path = pj_str((char*)transport->ca_list_path); #else if (!ast_strlen_zero(transport->ca_list_path)) { @@ -233,7 +248,21 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) "support the 'ca_list_path' option. Please upgrade to version 2.4 or later.\n"); } #endif + if (!ast_strlen_zero(transport->cert_file)) { + if (!ast_file_is_readable(transport->cert_file)) { + ast_log(LOG_ERROR, "Transport: %s: cert_file %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->cert_file); + return -1; + } + } transport->tls.cert_file = pj_str((char*)transport->cert_file); + if (!ast_strlen_zero(transport->privkey_file)) { + if (!ast_file_is_readable(transport->privkey_file)) { + ast_log(LOG_ERROR, "Transport: %s: privkey_file %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->privkey_file); + return -1; + } + } transport->tls.privkey_file = pj_str((char*)transport->privkey_file); transport->tls.password = pj_str((char*)transport->password); set_qos(transport, &transport->tls.qos_params); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 3bb08694517..72f896ad0c4 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -680,7 +680,7 @@ static int media_encryption_handler(const struct aco_option *opt, struct ast_var endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_SDES; } else if (!strcasecmp("dtls", var->value)) { endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS; - ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes"); + return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes"); } else { return -1; } From 5790700497972687dd79567acd89b27c90a86a22 Mon Sep 17 00:00:00 2001 From: tcambron Date: Wed, 9 Dec 2015 09:48:29 -0600 Subject: [PATCH 0072/1578] res_chan_stats: Fix bug to send correct statistics to StatsD Fixed a bug that originally would show a negative number of active calls occuring in Asterisk. A gauge is persistent so incrementing and decrementing it results in a more consistent performance. Also changed to the call to StatsD to use ast_statsd_log_string() so that a "+" could be sent to StatsD. ASTERISK-25619 #close Change-Id: Iaaeff5c4c6a46535366b4d16ea0ed0ee75ab2ee7 --- res/res_chan_stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_chan_stats.c b/res/res_chan_stats.c index 8b188dc130c..dfca39a8bf5 100644 --- a/res/res_chan_stats.c +++ b/res/res_chan_stats.c @@ -111,7 +111,7 @@ static void updates(void *data, struct stasis_subscription *sub, if (!update->old_snapshot && update->new_snapshot) { /* Initial cache entry; count a channel creation */ - ast_statsd_log("channels.count", AST_STATSD_COUNTER, 1); + ast_statsd_log_string("channels.count", AST_STATSD_GAUGE, "+1", 1.0); } else if (update->old_snapshot && !update->new_snapshot) { /* Cache entry removed. Compute the age of the channel and post * that, as well as decrementing the channel count. @@ -125,7 +125,7 @@ static void updates(void *data, struct stasis_subscription *sub, ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age); /* And decrement the channel count */ - ast_statsd_log("channels.count", AST_STATSD_COUNTER, -1); + ast_statsd_log_string("channels.count", AST_STATSD_GAUGE, "-1", 1.0); } } From fcaebb0e432ad7d296680457ca3081bb2e7604ee Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 7 Dec 2015 14:07:32 -0500 Subject: [PATCH 0073/1578] app_meetme: Set default value for audio_buffers. The default value was never set for audio_buffers, causing bad audio quality. This ensures the default is always set. ASTERISK-25569 #close Change-Id: I2d2ee3e644120b0f9f6ea6ab9286d7d590942a44 --- apps/app_meetme.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 0c339d6ba50..ab6b94f3ee2 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -5774,6 +5774,9 @@ static void meetme_set_defaults(void) /* Logging of participants defaults to ON for compatibility reasons */ rt_log_members = 1; + + /* Set default number of buffers to be allocated. */ + audio_buffers = DEFAULT_AUDIO_BUFFERS; } static void load_config_meetme(int reload) From ceebdfce40d278d17ecfb82afdffc41a8cc1cc94 Mon Sep 17 00:00:00 2001 From: Jonathan Rose Date: Thu, 10 Dec 2015 11:44:03 -0600 Subject: [PATCH 0074/1578] chan_sip: Add TCP/TLS keepalive to TCP/TLS server Adds the TCP Keep Alive option to TCP and TLS server sockets. Previously this option was only being set on session sockets. http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/ According to the link above, the SO_KEEPALIVE option is useful for knowing when a TCP connected endpoint has severed communication without indicating it or has become unreachable for some reason. Without this patch, keep alive is not set on the socket listening for incoming TCP sessions and in Komatsu's report this resulted in the thread listening for TCP becoming stuck in a waiting state. ASTERISK-25364 #close Reported by: Hiroaki Komatsu Change-Id: I7ed7bcfa982b367dc64b4b73fbd962da49b9af36 --- channels/chan_sip.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index cc73a15054f..378774a92b6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -32289,6 +32289,12 @@ static int reload_config(enum channelreloadreason reason) ast_log(LOG_ERROR, "SIP TCP Server start failed. Not listening on TCP socket.\n"); } else { ast_debug(2, "SIP TCP server started\n"); + if (sip_tcp_desc.accept_fd >= 0) { + int flags = 1; + if (setsockopt(sip_tcp_desc.accept_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) { + ast_log(LOG_ERROR, "Error enabling TCP keep-alive on sip socket: %s\n", strerror(errno)); + } + } } /* Start TLS server if needed */ @@ -32309,6 +32315,13 @@ static int reload_config(enum channelreloadreason reason) ast_log(LOG_ERROR, "TLS Server start failed. Not listening on TLS socket.\n"); sip_tls_desc.tls_cfg = NULL; } + if (sip_tls_desc.accept_fd >= 0) { + int flags = 1; + if (setsockopt(sip_tls_desc.accept_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) { + ast_log(LOG_ERROR, "Error enabling TCP keep-alive on sip socket: %s\n", strerror(errno)); + sip_tls_desc.tls_cfg = NULL; + } + } } else if (sip_tls_desc.tls_cfg->enabled) { sip_tls_desc.tls_cfg = NULL; ast_log(LOG_WARNING, "SIP TLS server did not load because of errors.\n"); From 3e6637feb581fd8488227e78ae4823be560aafce Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 12 Dec 2015 10:08:50 -0700 Subject: [PATCH 0075/1578] pjsip/config_transport: Check pjproject version at runtime for async ops pjproject < 2.5.0 will segfault on a tls transport if async_operations is greater than 1. A runtime version check has been added to throw an error if the version is < 2.5.0 and async_operations > 1. To assist in the check, a new api "ast_compare_versions" was added to utils which compares 2 major.minor.patch.extra version strings. ASTERISK-25615 #close Change-Id: I8e88bb49cbcfbca88d9de705496d6f6a8c938a98 Reported-by: George Joseph Tested-by: George Joseph --- include/asterisk/utils.h | 12 ++++++++++++ main/utils.c | 23 +++++++++++++++++++++++ res/res_pjsip/config_transport.c | 7 ++----- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 832500c31e7..cfb78c02792 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -1099,4 +1099,16 @@ int ast_crypt_validate(const char *key, const char *expected); */ int ast_file_is_readable(const char *filename); +/* + * \brief Compare 2 major.minor.patch.extra version strings. + * \since 13.7.0 + * + * \param version1. + * \param version2. + * \return -1 if version 1 < version 2. + * \return 0 if version 1 = version 2. + * \return 1 if version 1 > version 2. + */ +int ast_compare_versions(const char *version1, const char *version2); + #endif /* _ASTERISK_UTILS_H */ diff --git a/main/utils.c b/main/utils.c index 74932b8c27d..87241f19766 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2944,3 +2944,26 @@ int ast_file_is_readable(const char *filename) return 1; #endif } + +int ast_compare_versions(const char *version1, const char *version2) +{ + u_int64_t major[2] = { 0 }; + u_int64_t minor[2] = { 0 }; + u_int64_t patch[2] = { 0 }; + u_int64_t extra[2] = { 0 }; + u_int64_t v1, v2; + + sscanf(version1, "%lu.%lu.%lu.%lu", &major[0], &minor[0], &patch[0], &extra[0]); + sscanf(version2, "%lu.%lu.%lu.%lu", &major[1], &minor[1], &patch[1], &extra[1]); + + v1 = major[0] << 48 | minor[0] << 32 | patch[0] << 16 | extra[0]; + v2 = major[1] << 48 | minor[1] << 32 | patch[1] << 16 | extra[1]; + + if (v1 < v2) { + return -1; + } else if (v1 > v2) { + return 1; + } else { + return 0; + } +} diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index d8ece150944..840824bd945 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -217,11 +217,8 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory); } else if (transport->type == AST_TRANSPORT_TLS) { - /* The following check is a work-around for ASTERISK-25615. - * When that issue is resolved in upstream pjproject, this check can be removed. - */ - if (transport->async_operations > 1) { - ast_log(LOG_ERROR, "Transport: %s: When protocol=tls, async_operations can't be > 1 (ASTERISK-25615)\n", + if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) { + ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n", ast_sorcery_object_get_id(obj)); return -1; } From 9a96a86e2d95645f05b160d2efc942c1a3c129d2 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sun, 13 Dec 2015 13:13:55 -0600 Subject: [PATCH 0076/1578] main/utils: Don't emit an ERROR message if the read end of a pipe closes An ERROR or WARNING message should generally indicate that something has gone wrong in Asterisk. In the case of writing to a file descriptor, Asterisk is not in control of when the far end closes its reading on a file descriptor. If the far end does close the file descriptor in an unclean fashion, this isn't a bug or error in Asterisk, particularly when the situation can be gracefully handled in Asterisk. Currently, when this happens, a user would see the following somewhat cryptic ERROR message: "utils.c: write() returned error: Broken pipe" There's a few problems with this: (1) It doesn't provide any context, other than 'something broke a pipe' (2) As noted, it isn't actually an error in Asterisk (3) It can get rather spammy if the thing breaking the pipe occurs often, such as a FastAGI server (4) Spammy ERROR messages make Asterisk appear to be having issues, or can even mask legitimate issues This patch changes ast_carefulwrite to only log an ERROR if we actually had one that was reasonably under our control. For debugging purposes, we still emit a debug message if we detect that the far side has stopped reading. Change-Id: Ia503bb1efcec685fa6f3017bedf98061f8e1b566 --- main/utils.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/main/utils.c b/main/utils.c index 74932b8c27d..db3e4babee7 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1399,7 +1399,13 @@ int ast_carefulwrite(int fd, char *s, int len, int timeoutms) if (res < 0 && errno != EAGAIN && errno != EINTR) { /* fatal error from write() */ - ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno)); + if (errno == EPIPE) { +#ifndef STANDALONE + ast_debug(1, "write() failed due to reading end being closed: %s\n", strerror(errno)); +#endif + } else { + ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno)); + } return -1; } From 3e7522533c7f7e147f792614128cc375a89e02cf Mon Sep 17 00:00:00 2001 From: Carlos Oliva Date: Mon, 14 Dec 2015 13:26:35 +0100 Subject: [PATCH 0077/1578] app_queue: update RT members when the 1st call joins a queue with no agents If a call enters on a queue and the members on that queue are updated in realtime (ex: using mysql inserting a new agent) the queue members are never refreshed and the call will stay in the queue until other event occurs. This happens only if this is the first call of the queue and there is no agents servicing. This patch prevent this issue, ensuring realtime members are updated if there is one call in the queue and no available agents ASTERISK-25442 #close Change-Id: If1e036d013a5c1d8b0bf60d71d48fe98694a8682 --- apps/app_queue.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index a2ed2c924af..416ebff4ae1 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5214,6 +5214,11 @@ static int is_our_turn(struct queue_ent *qe) res = 0; } + /* Update realtime members if this is the first call and number of avalable members is 0 */ + if (avl == 0 && qe->pos == 1) { + update_realtime_members(qe->parent); + } + return res; } From eccdf2250b066fb8d67b38c096da444417a8da22 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 14 Dec 2015 15:25:02 -0600 Subject: [PATCH 0078/1578] Fix sscanf() format string type mismatch. ASTERISK-25615 Reported by: George Joseph Change-Id: Ieff35307254ca193f3d473cff2e396ca57c7ce0b --- include/asterisk/utils.h | 7 ++++--- main/utils.c | 35 +++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index cfb78c02792..c7a473732eb 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -1105,9 +1105,10 @@ int ast_file_is_readable(const char *filename); * * \param version1. * \param version2. - * \return -1 if version 1 < version 2. - * \return 0 if version 1 = version 2. - * \return 1 if version 1 > version 2. + * + * \return <0 if version 1 < version 2. + * \return =0 if version 1 = version 2. + * \return >0 if version 1 > version 2. */ int ast_compare_versions(const char *version1, const char *version2); diff --git a/main/utils.c b/main/utils.c index b4c494e34be..5cebed16472 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2953,23 +2953,26 @@ int ast_file_is_readable(const char *filename) int ast_compare_versions(const char *version1, const char *version2) { - u_int64_t major[2] = { 0 }; - u_int64_t minor[2] = { 0 }; - u_int64_t patch[2] = { 0 }; - u_int64_t extra[2] = { 0 }; - u_int64_t v1, v2; - - sscanf(version1, "%lu.%lu.%lu.%lu", &major[0], &minor[0], &patch[0], &extra[0]); - sscanf(version2, "%lu.%lu.%lu.%lu", &major[1], &minor[1], &patch[1], &extra[1]); + unsigned int major[2] = { 0 }; + unsigned int minor[2] = { 0 }; + unsigned int patch[2] = { 0 }; + unsigned int extra[2] = { 0 }; + int res; - v1 = major[0] << 48 | minor[0] << 32 | patch[0] << 16 | extra[0]; - v2 = major[1] << 48 | minor[1] << 32 | patch[1] << 16 | extra[1]; + sscanf(version1, "%u.%u.%u.%u", &major[0], &minor[0], &patch[0], &extra[0]); + sscanf(version2, "%u.%u.%u.%u", &major[1], &minor[1], &patch[1], &extra[1]); - if (v1 < v2) { - return -1; - } else if (v1 > v2) { - return 1; - } else { - return 0; + res = major[0] - major[1]; + if (res) { + return res; + } + res = minor[0] - minor[1]; + if (res) { + return res; + } + res = patch[0] - patch[1]; + if (res) { + return res; } + return extra[0] - extra[1]; } From 52ca6fb94a63c32886bd5f862fe6c2e0e572d02b Mon Sep 17 00:00:00 2001 From: pchero Date: Tue, 8 Dec 2015 20:04:12 +0100 Subject: [PATCH 0079/1578] AMI: Fixed OriginateResponse message When the asterisk sending OriginateResponse message, it doesn't set the "Uniqueid". And it didn't support correct response message for Application originate. ASTERISK-25624 #close Change-Id: I26f54f677ccfb0b7cfd4967a844a1657fd69b74d --- main/manager.c | 55 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/main/manager.c b/main/manager.c index d6aadf4ecaa..544f4fdcd87 100644 --- a/main/manager.c +++ b/main/manager.c @@ -659,6 +659,8 @@ ASTERISK_REGISTER_FILE() + + @@ -4993,22 +4995,43 @@ static void *fast_originate(void *data) } /* Tell the manager what happened with the channel */ chans[0] = chan; - ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans, - "%s" - "Response: %s\r\n" - "Channel: %s\r\n" - "Context: %s\r\n" - "Exten: %s\r\n" - "Reason: %d\r\n" - "Uniqueid: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n", - in->idtext, res ? "Failure" : "Success", - chan ? ast_channel_name(chan) : requested_channel, in->context, in->exten, reason, - chan ? ast_channel_uniqueid(chan) : "", - S_OR(in->cid_num, ""), - S_OR(in->cid_name, "") - ); + if (!ast_strlen_zero(in->app)) { + ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans, + "%s" + "Response: %s\r\n" + "Channel: %s\r\n" + "Application: %s\r\n" + "Data: %s\r\n" + "Reason: %d\r\n" + "Uniqueid: %s\r\n" + "CallerIDNum: %s\r\n" + "CallerIDName: %s\r\n", + in->idtext, res ? "Failure" : "Success", + chan ? ast_channel_name(chan) : requested_channel, + in->app, in->appdata, reason, + chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, ""), + S_OR(in->cid_num, ""), + S_OR(in->cid_name, "") + ); + } else { + ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans, + "%s" + "Response: %s\r\n" + "Channel: %s\r\n" + "Context: %s\r\n" + "Exten: %s\r\n" + "Reason: %d\r\n" + "Uniqueid: %s\r\n" + "CallerIDNum: %s\r\n" + "CallerIDName: %s\r\n", + in->idtext, res ? "Failure" : "Success", + chan ? ast_channel_name(chan) : requested_channel, + in->context, in->exten, reason, + chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, ""), + S_OR(in->cid_num, ""), + S_OR(in->cid_name, "") + ); + } /* Locked and ref'd by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */ if (chan) { From 32ec83f37f97987284813124fe972b25cf161955 Mon Sep 17 00:00:00 2001 From: server-pandora Date: Mon, 14 Dec 2015 11:53:20 -0800 Subject: [PATCH 0080/1578] res_rtp_asterisk.c: Fix DTLS negotiation delays. - Trigger pending DTLS packets to send out, once the RTP instance's remote address is set. - Avoids locking the DTLS structure unnecessarily by only doing this if DTLS is passive. - Add DTLS locks around the structurally sensitive calls in the SSL portion of __rtp_recvfrom, since dtls_srtp_check_pending does not lock inside of itself, and we're dealing with the SSL BIO in at least two threads. WebRTC channels may receive a DTLS handshake before ast_rtp_remote_address_set is called, which causes there to be a pending response to send out. Previous to 1ad827, this was handled by calling dtls_srtp_check_pending on receipt of any RTP packet - a STUN or RTP packet could trigger the pending handshake response. Since that was rightfully removed, whenever the DTLS handshake is received before the remote address is set, we would have to wait until another SSL packet arrives. As of Chrome M47's optimizations to their handshake process, WebRTC conversations between Chrome M47+ and Asterisk, where Asterisk is passive, experience a 1 second delay without this patch, because the SSL handshake is received before ICE negotation stores the remote_address, and the next SSL packet isn't received until after a 1 second timeout in Chrome, which causes a new handshake request. ASTERISK-25614 #close Change-Id: I547f1be7e302dbf71f6553dd8cbc0657b1d0b908 --- res/res_rtp_asterisk.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index ac83d734be3..6f09368b891 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2118,6 +2118,8 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s SSL_set_accept_state(dtls->ssl); } + ast_mutex_lock(&dtls->lock); + dtls_srtp_check_pending(instance, rtp, rtcp); BIO_write(dtls->read_bio, buf, len); @@ -2128,6 +2130,7 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s unsigned long error = ERR_get_error(); ast_log(LOG_ERROR, "DTLS failure occurred on RTP instance '%p' due to reason '%s', terminating\n", instance, ERR_reason_error_string(error)); + ast_mutex_unlock(&dtls->lock); return -1; } @@ -2145,6 +2148,8 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s dtls_srtp_start_timeout_timer(instance, rtp, rtcp); } + ast_mutex_unlock(&dtls->lock); + return res; } #endif @@ -4816,6 +4821,9 @@ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp) static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); +#ifdef HAVE_OPENSSL_SRTP + struct dtls_details *dtls; +#endif if (rtp->rtcp) { ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance); @@ -4833,6 +4841,28 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno); } +#ifdef HAVE_OPENSSL_SRTP + /* Trigger pending outbound DTLS packets received before the address was set. Avoid unnecessary locking + * by checking if we're passive. Without this, we only send the pending packets once a new SSL packet is + * received in __rtp_recvfrom. + */ + dtls = &rtp->dtls; + if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + ast_mutex_lock(&dtls->lock); + dtls_srtp_check_pending(instance, rtp, 0); + ast_mutex_unlock(&dtls->lock); + } + + if (rtp->rtcp) { + dtls = &rtp->rtcp->dtls; + if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + ast_mutex_lock(&dtls->lock); + dtls_srtp_check_pending(instance, rtp, 1); + ast_mutex_unlock(&dtls->lock); + } + } +#endif + return; } From cfb34adb836f61fcb55ef139ac0e9c57f647f3a6 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 16 Dec 2015 11:28:14 -0600 Subject: [PATCH 0081/1578] Alembic: Increase column size of PJSIP AOR "contact". When running the PJSIP AMI "show_endpoint" test with automatic conversion to realtime, the test would fail. This was because the AOR "contact" column was sized at 40, and the configured contact was larger than that. This commit increases the size of the contact column to 255 characters. Change-Id: Ia65bc7fd37699b7c0eaef9629a1a31eab9a24ba1 --- ...078ec071b7_increaes_contact_column_size.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py diff --git a/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py new file mode 100644 index 00000000000..2ade86f9f3d --- /dev/null +++ b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py @@ -0,0 +1,22 @@ +"""increaes_contact_column_size + +Revision ID: 2d078ec071b7 +Revises: 189a235b3fd7 +Create Date: 2015-12-16 11:26:54.218985 + +""" + +# revision identifiers, used by Alembic. +revision = '2d078ec071b7' +down_revision = '189a235b3fd7' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.alter_column('ps_aors', 'contact', type_=sa.String(255)) + + +def downgrade(): + op.alter_column('ps_aors', 'contact', type_=sa.String(40)) From d17d9a92886429b185b7bc2e02e429fc43d39652 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 14 Dec 2015 14:04:15 -0400 Subject: [PATCH 0082/1578] json: Audit ast_json_* usage for thread safety. The JSON library Asterisk uses, jansson, is not thread safe for us in a few ways. To help with this wrappers for JSON object reference count increasing and decreasing were added which use a global lock to ensure they don't clobber over each other. This does not extend to reference count manipulation within the jansson library itself. This means you can't safely use the object borrowing specifier (O) in ast_json_pack and you can't share JSON instances between objects. This change removes uses of the O specifier and replaces them with the o specifier and an explicit ast_json_ref. Some cases of instance sharing have also been removed. ASTERISK-25601 #close Change-Id: I06550d8b0cc1bfeb56cab580a4e608ae4f1ec7d1 --- main/aoc.c | 20 ++++++++++---------- main/loader.c | 4 ++-- main/rtp_engine.c | 14 +++++++------- main/stasis.c | 4 ++-- main/stasis_channels.c | 24 +++++++++++++++++------- res/res_fax.c | 4 ++-- res/res_stasis.c | 6 +++--- res/res_stasis_playback.c | 4 ++-- res/res_stasis_recording.c | 4 ++-- res/stasis/app.c | 4 ++-- 10 files changed, 49 insertions(+), 39 deletions(-) diff --git a/main/aoc.c b/main/aoc.c index ba44fbfb978..54edafad647 100644 --- a/main/aoc.c +++ b/main/aoc.c @@ -1667,11 +1667,11 @@ static struct ast_json *charge_to_json(const struct ast_aoc_decoded *decoded) } return ast_json_pack( - "{s:s, s:s, s:s, s:O}", + "{s:s, s:s, s:s, s:o}", "Type", aoc_charge_type_str(decoded->charge_type), "BillingID", aoc_billingid_str(decoded->billing_id), "TotalType", aoc_type_of_totaling_str(decoded->total_type), - obj_type, obj); + obj_type, ast_json_ref(obj)); } static struct ast_json *association_to_json(const struct ast_aoc_decoded *decoded) @@ -1738,10 +1738,10 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded) "Scale", decoded->aoc_s_entries[i].rate.duration.granularity_time_scale); } - type = ast_json_pack("{s:O, s:s, s:O, s:O}", "Currency", currency, "ChargingType", + type = ast_json_pack("{s:o, s:s, s:o, s:o}", "Currency", ast_json_ref(currency), "ChargingType", decoded->aoc_s_entries[i].rate.duration.charging_type ? - "StepFunction" : "ContinuousCharging", "Time", time, - "Granularity", granularity ? granularity : ast_json_null()); + "StepFunction" : "ContinuousCharging", "Time", ast_json_ref(time), + "Granularity", granularity ? ast_json_ref(granularity) : ast_json_ref(ast_json_null())); break; } @@ -1751,7 +1751,7 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded) decoded->aoc_s_entries[i].rate.flat.amount, decoded->aoc_s_entries[i].rate.flat.multiplier); - type = ast_json_pack("{s:O}", "Currency", currency); + type = ast_json_pack("{s:o}", "Currency", ast_json_ref(currency)); break; case AST_AOC_RATE_TYPE_VOLUME: currency = currency_to_json( @@ -1760,9 +1760,9 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded) decoded->aoc_s_entries[i].rate.volume.multiplier); type = ast_json_pack( - "{s:s, s:O}", "Unit", aoc_volume_unit_str( + "{s:s, s:o}", "Unit", aoc_volume_unit_str( decoded->aoc_s_entries[i].rate.volume.volume_unit), - "Currency", currency); + "Currency", ast_json_ref(currency)); break; case AST_AOC_RATE_TYPE_SPECIAL_CODE: type = ast_json_pack("{s:i}", "SpecialCode", @@ -1772,8 +1772,8 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded) break; } - rate = ast_json_pack("{s:s, s:O}", "Chargeable", charge_item, - aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), type); + rate = ast_json_pack("{s:s, s:o}", "Chargeable", charge_item, + aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), ast_json_ref(type)); if (ast_json_array_append(rates, rate)) { break; } diff --git a/main/loader.c b/main/loader.c index b2bdd4a3d2d..954b288b3d4 100644 --- a/main/loader.c +++ b/main/loader.c @@ -846,10 +846,10 @@ static void publish_reload_message(const char *name, enum ast_module_reload_resu event_object = ast_json_pack("{s: s, s: s}", "Module", S_OR(name, "All"), "Status", res_buffer); - json_object = ast_json_pack("{s: s, s: i, s: O}", + json_object = ast_json_pack("{s: s, s: i, s: o}", "type", "Reload", "class_type", EVENT_FLAG_SYSTEM, - "event", event_object); + "event", ast_json_ref(event_object)); if (!json_object) { return; diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 24e56b49fb1..035739f03ac 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2493,12 +2493,12 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg, } } - json_rtcp_report = ast_json_pack("{s: i, s: i, s: i, s: O, s: O}", + json_rtcp_report = ast_json_pack("{s: i, s: i, s: i, s: o, s: o}", "ssrc", payload->report->ssrc, "type", payload->report->type, "report_count", payload->report->reception_report_count, - "sender_information", json_rtcp_sender_info ? json_rtcp_sender_info : ast_json_null(), - "report_blocks", json_rtcp_report_blocks); + "sender_information", json_rtcp_sender_info ? ast_json_ref(json_rtcp_sender_info) : ast_json_ref(ast_json_null()), + "report_blocks", ast_json_ref(json_rtcp_report_blocks)); if (!json_rtcp_report) { return NULL; } @@ -2510,10 +2510,10 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg, } } - return ast_json_pack("{s: O, s: O, s: O}", - "channel", payload->snapshot ? json_channel : ast_json_null(), - "rtcp_report", json_rtcp_report, - "blob", payload->blob); + return ast_json_pack("{s: o, s: o, s: o}", + "channel", payload->snapshot ? ast_json_ref(json_channel) : ast_json_ref(ast_json_null()), + "rtcp_report", ast_json_ref(json_rtcp_report), + "blob", ast_json_deep_copy(payload->blob)); } static void rtp_rtcp_report_dtor(void *obj) diff --git a/main/stasis.c b/main/stasis.c index e168ce93b08..fe940d351ff 100644 --- a/main/stasis.c +++ b/main/stasis.c @@ -1274,8 +1274,8 @@ static struct ast_json *multi_user_event_to_json( ast_json_object_set(out, "type", ast_json_string_create("ChannelUserevent")); ast_json_object_set(out, "timestamp", ast_json_timeval(*tv, NULL)); - ast_json_object_set(out, "eventname", ast_json_ref(ast_json_object_get(blob, "eventname"))); - ast_json_object_set(out, "userevent", ast_json_ref(blob)); /* eventname gets duplicated, that's ok */ + ast_json_object_set(out, "eventname", ast_json_string_create(ast_json_string_get((ast_json_object_get(blob, "eventname"))))); + ast_json_object_set(out, "userevent", ast_json_deep_copy(blob)); for (type = 0; type < STASIS_UMOS_MAX; ++type) { for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) { diff --git a/main/stasis_channels.c b/main/stasis_channels.c index 1a4a90f52f7..eb1f1bc6229 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -1016,6 +1016,10 @@ static struct ast_json *dtmf_end_to_json( struct ast_channel_snapshot *snapshot = channel_blob->snapshot; const char *direction = ast_json_string_get(ast_json_object_get(blob, "direction")); + const char *digit = + ast_json_string_get(ast_json_object_get(blob, "digit")); + long duration_ms = + ast_json_integer_get(ast_json_object_get(blob, "duration_ms")); const struct timeval *tv = stasis_message_timestamp(message); struct ast_json *json_channel; @@ -1029,11 +1033,11 @@ static struct ast_json *dtmf_end_to_json( return NULL; } - return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}", + return ast_json_pack("{s: s, s: o, s: s, s: i, s: o}", "type", "ChannelDtmfReceived", "timestamp", ast_json_timeval(*tv, NULL), - "digit", ast_json_object_get(blob, "digit"), - "duration_ms", ast_json_object_get(blob, "duration_ms"), + "digit", digit, + "duration_ms", duration_ms, "channel", json_channel); } @@ -1057,6 +1061,12 @@ static struct ast_json *dial_to_json( { struct ast_multi_channel_blob *payload = stasis_message_data(message); struct ast_json *blob = ast_multi_channel_blob_get_json(payload); + const char *dialstatus = + ast_json_string_get(ast_json_object_get(blob, "dialstatus")); + const char *forward = + ast_json_string_get(ast_json_object_get(blob, "forward")); + const char *dialstring = + ast_json_string_get(ast_json_object_get(blob, "dialstring")); struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize); struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize); struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize); @@ -1064,12 +1074,12 @@ static struct ast_json *dial_to_json( const struct timeval *tv = stasis_message_timestamp(message); int res = 0; - json = ast_json_pack("{s: s, s: o, s: O, s: O, s: O}", + json = ast_json_pack("{s: s, s: o, s: s, s: s, s: s}", "type", "Dial", "timestamp", ast_json_timeval(*tv, NULL), - "dialstatus", ast_json_object_get(blob, "dialstatus"), - "forward", ast_json_object_get(blob, "forward"), - "dialstring", ast_json_object_get(blob, "dialstring")); + "dialstatus", dialstatus, + "forward", forward, + "dialstring", dialstring); if (!json) { ast_json_unref(caller_json); ast_json_unref(peer_json); diff --git a/res/res_fax.c b/res/res_fax.c index 62fe726de99..f171af92a93 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -2028,14 +2028,14 @@ static int report_receive_fax_status(struct ast_channel *chan, const char *filen fax_bitrate = ast_strdupa(fax_bitrate); } - json_object = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: O}", + json_object = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o}", "type", "receive", "remote_station_id", S_OR(remote_station_id, ""), "local_station_id", S_OR(local_station_id, ""), "fax_pages", S_OR(fax_pages, ""), "fax_resolution", S_OR(fax_resolution, ""), "fax_bitrate", S_OR(fax_bitrate, ""), - "filenames", json_array); + "filenames", ast_json_ref(json_array)); if (!json_object) { return -1; } diff --git a/res/res_stasis.c b/res/res_stasis.c index abca895ee1d..63c565d44d1 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -150,10 +150,10 @@ static struct ast_json *stasis_start_to_json(struct stasis_message *message, return NULL; } - msg = ast_json_pack("{s: s, s: O, s: O, s: o}", + msg = ast_json_pack("{s: s, s: o, s: o, s: o}", "type", "StasisStart", - "timestamp", ast_json_object_get(payload->blob, "timestamp"), - "args", ast_json_object_get(payload->blob, "args"), + "timestamp", ast_json_copy(ast_json_object_get(payload->blob, "timestamp")), + "args", ast_json_deep_copy(ast_json_object_get(payload->blob, "args")), "channel", ast_channel_snapshot_to_json(payload->channel, NULL)); if (!msg) { ast_log(LOG_ERROR, "Failed to pack JSON for StasisStart message\n"); diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index 9abfe3d17c8..74336abdcf2 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -105,9 +105,9 @@ static struct ast_json *playback_to_json(struct stasis_message *message, return NULL; } - return ast_json_pack("{s: s, s: O}", + return ast_json_pack("{s: s, s: o}", "type", type, - "playback", blob); + "playback", ast_json_deep_copy(blob)); } STASIS_MESSAGE_TYPE_DEFN(stasis_app_playback_snapshot_type, diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c index 02ad875a8f0..dcabfa69950 100644 --- a/res/res_stasis_recording.c +++ b/res/res_stasis_recording.c @@ -91,9 +91,9 @@ static struct ast_json *recording_to_json(struct stasis_message *message, return NULL; } - return ast_json_pack("{s: s, s: O}", + return ast_json_pack("{s: s, s: o}", "type", type, - "recording", blob); + "recording", ast_json_deep_copy(blob)); } STASIS_MESSAGE_TYPE_DEFN(stasis_app_recording_snapshot_type, diff --git a/res/stasis/app.c b/res/stasis/app.c index 5002a0ba88a..6e5a396be34 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -609,11 +609,11 @@ static int message_received_handler(const char *endpoint_id, struct ast_json *js return -1; } - app_send(app, ast_json_pack("{s: s, s: o, s: o, s: O}", + app_send(app, ast_json_pack("{s: s, s: o, s: o, s: o}", "type", "TextMessageReceived", "timestamp", ast_json_timeval(ast_tvnow(), NULL), "endpoint", json_endpoint, - "message", json_msg)); + "message", ast_json_ref(json_msg))); return 0; } From d2c8614122bf0ddd29ab81c238a7f927fb731975 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 17 Dec 2015 10:10:43 -0400 Subject: [PATCH 0083/1578] chan_sip: Enable WebSocket support by default. Per the documentation the WebSocket support in chan_sip is supposed to be enabled by default but is not. This change corrects that. Change-Id: Icb02bbcad47b11a795c14ce20a9bf29649a54423 --- channels/chan_sip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 378774a92b6..f7fbed72029 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -31510,6 +31510,7 @@ static int reload_config(enum channelreloadreason reason) sip_cfg.peer_rtupdate = TRUE; global_dynamic_exclude_static = 0; /* Exclude static peers */ sip_cfg.tcp_enabled = FALSE; + sip_cfg.websocket_enabled = TRUE; /* Session-Timers */ global_st_mode = SESSION_TIMER_MODE_ACCEPT; From a2431f83ef01200f59fc6844f3129fddba00398d Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 17 Dec 2015 12:25:47 -0400 Subject: [PATCH 0084/1578] rtp_engine: Ignore empty filenames in DTLS configuration. When applying an empty DTLS configuration the filenames in the configuration will be empty. This is actually valid to do and each filename should simply be ignored. Change-Id: Ib761dc235638a3fb701df337952f831fc3e69539 --- main/rtp_engine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 24e56b49fb1..6a7ace7bdc6 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2118,14 +2118,14 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, } } else if (!strcasecmp(name, "dtlscertfile")) { ast_free(dtls_cfg->certfile); - if (!ast_file_is_readable(value)) { + if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) { ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); return -1; } dtls_cfg->certfile = ast_strdup(value); } else if (!strcasecmp(name, "dtlsprivatekey")) { ast_free(dtls_cfg->pvtfile); - if (!ast_file_is_readable(value)) { + if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) { ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); return -1; } @@ -2135,14 +2135,14 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, dtls_cfg->cipher = ast_strdup(value); } else if (!strcasecmp(name, "dtlscafile")) { ast_free(dtls_cfg->cafile); - if (!ast_file_is_readable(value)) { + if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) { ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); return -1; } dtls_cfg->cafile = ast_strdup(value); } else if (!strcasecmp(name, "dtlscapath") || !strcasecmp(name, "dtlscadir")) { ast_free(dtls_cfg->capath); - if (!ast_file_is_readable(value)) { + if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) { ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); return -1; } From 902309fd0422382eb6de4ba1d92724be437c2561 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sat, 5 Dec 2015 12:01:55 -0400 Subject: [PATCH 0085/1578] res_sorcery_memory_cache: Add support for a full backend cache. This change introduces the configuration option 'full_backend_cache' which changes the cache to be a full mirror of the backend instead of a per-object cache. This allows all sorcery retrieval operations to be carried out against it and is useful for object types which are used in a "retrieve all" or "retrieve some" pattern. ASTERISK-25625 #close Change-Id: Ie2993487e9c19de563413ad5561c7403b48caab5 --- CHANGES | 8 + main/sorcery.c | 6 +- res/res_pjsip_endpoint_identifier_ip.c | 2 +- res/res_sorcery_memory_cache.c | 1040 ++++++++++++++++++++++-- 4 files changed, 995 insertions(+), 61 deletions(-) diff --git a/CHANGES b/CHANGES index dfb159082be..9421f0ba299 100644 --- a/CHANGES +++ b/CHANGES @@ -256,6 +256,14 @@ res_pjsip - A TIMER statistic for the RTT time for each qualified contact, e.g.: PJSIP.contacts.alice@@127.0.0.1:5061.rtt +res_sorcery_memory_cache +------------------------ + * A new caching strategy, full_backend_cache, has been added which caches + all stored objects in the backend. When enabled all objects will be + expired or go stale according to the configuration. As well when enabled + all retrieval operations will be performed against the cache instead of + the backend. + func_callerid ------------------- * CALLERID(pres) is now documented as a valid alternative to setting both diff --git a/main/sorcery.c b/main/sorcery.c index b751b9f0954..0f8ec5cd055 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -1901,7 +1901,7 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch } } - if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) { + if (((flags & AST_RETRIEVE_FLAG_MULTIPLE) && (!ao2_container_count(object) || !wizard->caching)) || !object) { continue; } @@ -1939,6 +1939,10 @@ struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *so } wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex); + + if (wizard->caching && ao2_container_count(objects)) { + break; + } } AST_VECTOR_RW_UNLOCK(&object_type->wizards); diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 39d75737876..f73bdae7e43 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -465,7 +465,7 @@ static int load_module(void) ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name)); ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0); - ast_sorcery_reload_object(ast_sip_get_sorcery(), "identify"); + ast_sorcery_load_object(ast_sip_get_sorcery(), "identify"); ast_sip_register_endpoint_identifier_with_name(&ip_identifier, "ip"); ast_sip_register_endpoint_formatter(&endpoint_identify_formatter); diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index 0d7630e854d..0421d815839 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -104,6 +104,20 @@ ASTERISK_REGISTER_FILE() Marks ALL objects in a sorcery memory cache as stale. + + + Expire all objects from a memory cache and populate it with all objects from the backend. + + + + + The name of the cache to populate. + + + + Expires all objects from a memory cache and populate it with all objects from the backend. + + ***/ /*! \brief Structure for storing a memory cache */ @@ -118,12 +132,20 @@ struct sorcery_memory_cache { unsigned int object_lifetime_maximum; /*! \brief The amount of time (in seconds) before an object is marked as stale, 0 if disabled */ unsigned int object_lifetime_stale; - /** \brief Whether all objects are expired when the object type is reloaded, 0 if disabled */ + /*! \brief Whether all objects are expired when the object type is reloaded, 0 if disabled */ unsigned int expire_on_reload; + /*! \brief Whether this is a cache of the entire backend, 0 if disabled */ + unsigned int full_backend_cache; /*! \brief Heap of cached objects. Oldest object is at the top. */ struct ast_heap *object_heap; /*! \brief Scheduler item for expiring oldest object. */ int expire_id; + /*! \brief scheduler id of stale update task */ + int stale_update_sched_id; + /*! \brief An unreffed pointer to the sorcery instance, accessible only with lock held */ + const struct ast_sorcery *sorcery; + /*! \brief The type of object we are caching */ + char *object_type; /*! TRUE if trying to stop the oldest object expiration scheduler item. */ unsigned int del_expire:1; #ifdef TEST_FRAMEWORK @@ -148,6 +170,22 @@ struct sorcery_memory_cached_object { ssize_t __heap_index; /*! \brief scheduler id of stale update task */ int stale_update_sched_id; + /*! \brief Cached objectset for field and regex retrieval */ + struct ast_variable *objectset; +}; + +/*! \brief Structure used for fields comparison */ +struct sorcery_memory_cache_fields_cmp_params { + /*! \brief Pointer to the sorcery structure */ + const struct ast_sorcery *sorcery; + /*! \brief The sorcery memory cache */ + struct sorcery_memory_cache *cache; + /*! \brief Pointer to the fields to check */ + const struct ast_variable *fields; + /*! \brief Regular expression for checking object id */ + regex_t *regex; + /*! \brief Optional container to put object into */ + struct ao2_container *container; }; static void *sorcery_memory_cache_open(const char *data); @@ -156,6 +194,12 @@ static void sorcery_memory_cache_load(void *data, const struct ast_sorcery *sorc static void sorcery_memory_cache_reload(void *data, const struct ast_sorcery *sorcery, const char *type); static void *sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id); +static void *sorcery_memory_cache_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, + const struct ast_variable *fields); +static void sorcery_memory_cache_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const struct ast_variable *fields); +static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *regex); static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_memory_cache_close(void *data); @@ -168,6 +212,9 @@ static struct ast_sorcery_wizard memory_cache_object_wizard = { .load = sorcery_memory_cache_load, .reload = sorcery_memory_cache_reload, .retrieve_id = sorcery_memory_cache_retrieve_id, + .retrieve_fields = sorcery_memory_cache_retrieve_fields, + .retrieve_multiple = sorcery_memory_cache_retrieve_multiple, + .retrieve_regex = sorcery_memory_cache_retrieve_regex, .close = sorcery_memory_cache_close, }; @@ -186,48 +233,44 @@ static struct ao2_container *caches; /*! \brief Scheduler for cache management */ static struct ast_sched_context *sched; -#define STALE_UPDATE_THREAD_ID 0x5EED1E55 -AST_THREADSTORAGE(stale_update_id_storage); +#define PASSTHRU_UPDATE_THREAD_ID 0x5EED1E55 +AST_THREADSTORAGE(passthru_update_id_storage); -static int is_stale_update(void) +static int is_passthru_update(void) { - uint32_t *stale_update_thread_id; + uint32_t *passthru_update_thread_id; - stale_update_thread_id = ast_threadstorage_get(&stale_update_id_storage, - sizeof(*stale_update_thread_id)); - if (!stale_update_thread_id) { + passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage, + sizeof(*passthru_update_thread_id)); + if (!passthru_update_thread_id) { return 0; } - return *stale_update_thread_id == STALE_UPDATE_THREAD_ID; + return *passthru_update_thread_id == PASSTHRU_UPDATE_THREAD_ID; } -static void start_stale_update(void) +static void set_passthru_update(uint32_t value) { - uint32_t *stale_update_thread_id; + uint32_t *passthru_update_thread_id; - stale_update_thread_id = ast_threadstorage_get(&stale_update_id_storage, - sizeof(*stale_update_thread_id)); - if (!stale_update_thread_id) { - ast_log(LOG_ERROR, "Could not set stale update ID for sorcery memory cache thread\n"); + passthru_update_thread_id = ast_threadstorage_get(&passthru_update_id_storage, + sizeof(*passthru_update_thread_id)); + if (!passthru_update_thread_id) { + ast_log(LOG_ERROR, "Could not set passthru update ID for sorcery memory cache thread\n"); return; } - *stale_update_thread_id = STALE_UPDATE_THREAD_ID; + *passthru_update_thread_id = value; } -static void end_stale_update(void) +static void start_passthru_update(void) { - uint32_t *stale_update_thread_id; - - stale_update_thread_id = ast_threadstorage_get(&stale_update_id_storage, - sizeof(*stale_update_thread_id)); - if (!stale_update_thread_id) { - ast_log(LOG_ERROR, "Could not set stale update ID for sorcery memory cache thread\n"); - return; - } + set_passthru_update(PASSTHRU_UPDATE_THREAD_ID); +} - *stale_update_thread_id = 0; +static void end_passthru_update(void) +{ + set_passthru_update(0); } /*! @@ -375,6 +418,7 @@ static void sorcery_memory_cache_destructor(void *obj) ast_heap_destroy(cache->object_heap); } ao2_cleanup(cache->objects); + ast_free(cache->object_type); } /*! @@ -388,6 +432,7 @@ static void sorcery_memory_cached_object_destructor(void *obj) struct sorcery_memory_cached_object *cached = obj; ao2_cleanup(cached->object); + ast_variables_destroy(cached->objectset); } static int schedule_cache_expiration(struct sorcery_memory_cache *cache); @@ -673,10 +718,17 @@ static int remove_oldest_from_cache(struct sorcery_memory_cache *cache) static int add_to_cache(struct sorcery_memory_cache *cache, struct sorcery_memory_cached_object *cached_object) { + struct sorcery_memory_cached_object *front; + if (!ao2_link_flags(cache->objects, cached_object, OBJ_NOLOCK)) { return -1; } + if (cache->full_backend_cache && (front = ast_heap_peek(cache->object_heap, 1))) { + /* For a full backend cache all objects share the same lifetime */ + cached_object->created = front->created; + } + if (ast_heap_push(cache->object_heap, cached_object)) { ao2_find(cache->objects, cached_object, OBJ_SEARCH_OBJECT | OBJ_UNLINK | OBJ_NODATA | OBJ_NOLOCK); @@ -690,6 +742,45 @@ static int add_to_cache(struct sorcery_memory_cache *cache, return 0; } +/*! + * \internal + * \brief Allocate a cached object for caching an object + * + * \param sorcery The sorcery instance + * \param cache The sorcery memory cache + * \param object The object to cache + * + * \retval non-NULL success + * \retval NULL failure + */ +static struct sorcery_memory_cached_object *sorcery_memory_cached_object_alloc(const struct ast_sorcery *sorcery, + const struct sorcery_memory_cache *cache, void *object) +{ + struct sorcery_memory_cached_object *cached; + + cached = ao2_alloc(sizeof(*cached), sorcery_memory_cached_object_destructor); + if (!cached) { + return NULL; + } + + cached->object = ao2_bump(object); + cached->created = ast_tvnow(); + cached->stale_update_sched_id = -1; + + if (cache->full_backend_cache) { + /* A cached objectset allows us to easily perform all retrieval operations in a + * minimal of time. + */ + cached->objectset = ast_sorcery_objectset_create(sorcery, object); + if (!cached->objectset) { + ao2_ref(cached, -1); + return NULL; + } + } + + return cached; +} + /*! * \internal * \brief Callback function to cache an object in a memory cache @@ -706,13 +797,10 @@ static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void * struct sorcery_memory_cache *cache = data; struct sorcery_memory_cached_object *cached; - cached = ao2_alloc(sizeof(*cached), sorcery_memory_cached_object_destructor); + cached = sorcery_memory_cached_object_alloc(sorcery, cache, object); if (!cached) { return -1; } - cached->object = ao2_bump(object); - cached->created = ast_tvnow(); - cached->stale_update_sched_id = -1; /* As there is no guarantee that this won't be called by multiple threads wanting to cache * the same object we remove any old ones, which turns this into a create/update function @@ -745,6 +833,116 @@ static int sorcery_memory_cache_create(const struct ast_sorcery *sorcery, void * return 0; } +/*! + * \internal + * \brief AO2 callback function for adding an object to a memory cache + * + * \param obj The cached object + * \param arg The sorcery instance + * \param data The cache itself + * \param flags Unused flags + */ +static int object_add_to_cache_callback(void *obj, void *arg, void *data, int flags) +{ + struct sorcery_memory_cache *cache = data; + struct sorcery_memory_cached_object *cached; + + cached = sorcery_memory_cached_object_alloc(arg, cache, obj); + if (!cached) { + return CMP_STOP; + } + + add_to_cache(cache, cached); + ao2_ref(cached, -1); + + return 0; +} + +struct stale_cache_update_task_data { + struct ast_sorcery *sorcery; + struct sorcery_memory_cache *cache; + char *type; +}; + +static void stale_cache_update_task_data_destructor(void *obj) +{ + struct stale_cache_update_task_data *task_data = obj; + + ao2_cleanup(task_data->cache); + ast_sorcery_unref(task_data->sorcery); + ast_free(task_data->type); +} + +static struct stale_cache_update_task_data *stale_cache_update_task_data_alloc(struct ast_sorcery *sorcery, + struct sorcery_memory_cache *cache, const char *type) +{ + struct stale_cache_update_task_data *task_data; + + task_data = ao2_alloc_options(sizeof(*task_data), stale_cache_update_task_data_destructor, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!task_data) { + return NULL; + } + + task_data->sorcery = ao2_bump(sorcery); + task_data->cache = ao2_bump(cache); + task_data->type = ast_strdup(type); + if (!task_data->type) { + ao2_ref(task_data, -1); + return NULL; + } + + return task_data; +} + +static int stale_cache_update(const void *data) +{ + struct stale_cache_update_task_data *task_data = (struct stale_cache_update_task_data *) data; + struct ao2_container *backend_objects; + + start_passthru_update(); + backend_objects = ast_sorcery_retrieve_by_fields(task_data->sorcery, task_data->type, + AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + end_passthru_update(); + + if (!backend_objects) { + task_data->cache->stale_update_sched_id = -1; + ao2_ref(task_data, -1); + return 0; + } + + if (task_data->cache->maximum_objects && ao2_container_count(backend_objects) >= task_data->cache->maximum_objects) { + ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n", + ao2_container_count(backend_objects), task_data->cache->name, task_data->cache->maximum_objects); + task_data->cache->stale_update_sched_id = -1; + ao2_ref(task_data, -1); + return 0; + } + + ao2_wrlock(task_data->cache->objects); + remove_all_from_cache(task_data->cache); + ao2_callback_data(backend_objects, OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE, object_add_to_cache_callback, + task_data->sorcery, task_data->cache); + + /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation + * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly + * as it may be able to provide what is wanted. + */ + if (ao2_container_count(task_data->cache->objects) != ao2_container_count(backend_objects)) { + ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n", + ao2_container_count(backend_objects), ao2_container_count(task_data->cache->objects), task_data->cache->name); + remove_all_from_cache(task_data->cache); + } + + ao2_unlock(task_data->cache->objects); + ao2_ref(backend_objects, -1); + + task_data->cache->stale_update_sched_id = -1; + ao2_ref(task_data, -1); + + return 0; +} + struct stale_update_task_data { struct ast_sorcery *sorcery; struct sorcery_memory_cache *cache; @@ -783,7 +981,7 @@ static int stale_item_update(const void *data) struct stale_update_task_data *task_data = (struct stale_update_task_data *) data; void *object; - start_stale_update(); + start_passthru_update(); object = ast_sorcery_retrieve_by_id(task_data->sorcery, ast_sorcery_object_get_type(task_data->object), @@ -807,11 +1005,194 @@ static int stale_item_update(const void *data) ast_sorcery_object_get_id(task_data->object)); ao2_ref(task_data, -1); - end_stale_update(); + end_passthru_update(); return 0; } +/*! + * \internal + * \brief Populate the cache with all objects from the backend + * + * \pre cache->objects is write-locked + * + * \param sorcery The sorcery instance + * \param type The type of object + * \param cache The sorcery memory cache + */ +static void memory_cache_populate(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache) +{ + struct ao2_container *backend_objects; + + start_passthru_update(); + backend_objects = ast_sorcery_retrieve_by_fields(sorcery, type, AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + end_passthru_update(); + + if (!backend_objects) { + /* This will occur in off-nominal memory allocation failure scenarios */ + return; + } + + if (cache->maximum_objects && ao2_container_count(backend_objects) >= cache->maximum_objects) { + ast_log(LOG_ERROR, "The backend contains %d objects while the sorcery memory cache '%s' is explicitly configured to only allow %d\n", + ao2_container_count(backend_objects), cache->name, cache->maximum_objects); + return; + } + + ao2_callback_data(backend_objects, OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE, object_add_to_cache_callback, + (struct ast_sorcery*)sorcery, cache); + + /* If the number of cached objects does not match the number of backend objects we encountered a memory allocation + * failure and the cache is incomplete, so drop everything and fall back to querying the backend directly + * as it may be able to provide what is wanted. + */ + if (ao2_container_count(cache->objects) != ao2_container_count(backend_objects)) { + ast_log(LOG_WARNING, "The backend contains %d objects while only %d could be added to sorcery memory cache '%s'\n", + ao2_container_count(backend_objects), ao2_container_count(cache->objects), cache->name); + remove_all_from_cache(cache); + } + + ao2_ref(backend_objects, -1); +} + +/*! + * \internal + * \brief Determine if a full backend cache update is needed and do it + * + * \param sorcery The sorcery instance + * \param type The type of object + * \param cache The sorcery memory cache + */ +static void memory_cache_full_update(const struct ast_sorcery *sorcery, const char *type, struct sorcery_memory_cache *cache) +{ + if (!cache->full_backend_cache) { + return; + } + + ao2_wrlock(cache->objects); + if (!ao2_container_count(cache->objects)) { + memory_cache_populate(sorcery, type, cache); + } + ao2_unlock(cache->objects); +} + +/*! + * \internal + * \brief Queue a full cache update + * + * \param sorcery The sorcery instance + * \param cache The sorcery memory cache + * \param type The type of object + */ +static void memory_cache_stale_update_full(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, + const char *type) +{ + ao2_wrlock(cache->objects); + if (cache->stale_update_sched_id == -1) { + struct stale_cache_update_task_data *task_data; + + task_data = stale_cache_update_task_data_alloc((struct ast_sorcery *) sorcery, + cache, type); + if (task_data) { + cache->stale_update_sched_id = ast_sched_add(sched, 1, + stale_cache_update, task_data); + } + if (cache->stale_update_sched_id < 0) { + ao2_cleanup(task_data); + } + } + ao2_unlock(cache->objects); +} + +/*! + * \internal + * \brief Queue a stale object update + * + * \param sorcery The sorcery instance + * \param cache The sorcery memory cache + * \param cached The cached object + */ +static void memory_cache_stale_update_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, + struct sorcery_memory_cached_object *cached) +{ + ao2_lock(cached); + if (cached->stale_update_sched_id == -1) { + struct stale_update_task_data *task_data; + + task_data = stale_update_task_data_alloc((struct ast_sorcery *) sorcery, + cache, ast_sorcery_object_get_type(cached->object), cached->object); + if (task_data) { + ast_debug(1, "Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n", + ast_sorcery_object_get_type(cached->object), ast_sorcery_object_get_id(cached->object)); + cached->stale_update_sched_id = ast_sched_add(sched, 1, + stale_item_update, task_data); + } + if (cached->stale_update_sched_id < 0) { + ao2_cleanup(task_data); + ast_log(LOG_ERROR, "Unable to update stale cached object type '%s', ID '%s'.\n", + ast_sorcery_object_get_type(cached->object), ast_sorcery_object_get_id(cached->object)); + } + } + ao2_unlock(cached); +} + +/*! + * \internal + * \brief Check whether an object (or cache) is stale and queue an update + * + * \param sorcery The sorcery instance + * \param cache The sorcery memory cache + * \param cached The cached object + */ +static void memory_cache_stale_check_object(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache, + struct sorcery_memory_cached_object *cached) +{ + struct timeval elapsed; + + if (!cache->object_lifetime_stale) { + return; + } + + /* For a full cache as every object has the same expiration/staleness we can do the same check */ + elapsed = ast_tvsub(ast_tvnow(), cached->created); + + if (elapsed.tv_sec < cache->object_lifetime_stale) { + return; + } + + if (cache->full_backend_cache) { + memory_cache_stale_update_full(sorcery, cache, ast_sorcery_object_get_type(cached->object)); + } else { + memory_cache_stale_update_object(sorcery, cache, cached); + } + +} + +/*! + * \internal + * \brief Check whether the entire cache is stale or not and queue an update + * + * \param sorcery The sorcery instance + * \param cache The sorcery memory cache + * + * \note Unlike \ref memory_cache_stale_check this does not require an explicit object + */ +static void memory_cache_stale_check(const struct ast_sorcery *sorcery, struct sorcery_memory_cache *cache) +{ + struct sorcery_memory_cached_object *cached; + + ao2_rdlock(cache->objects); + cached = ao2_bump(ast_heap_peek(cache->object_heap, 1)); + ao2_unlock(cache->objects); + + if (!cached) { + return; + } + + memory_cache_stale_check_object(sorcery, cache, cached); + ao2_ref(cached, -1); +} + /*! * \internal * \brief Callback function to retrieve an object from a memory cache @@ -830,10 +1211,12 @@ static void *sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, struct sorcery_memory_cached_object *cached; void *object; - if (is_stale_update()) { + if (is_passthru_update()) { return NULL; } + memory_cache_full_update(sorcery, type, cache); + cached = ao2_find(cache->objects, id, OBJ_SEARCH_KEY); if (!cached) { return NULL; @@ -841,32 +1224,7 @@ static void *sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, ast_assert(!strcmp(ast_sorcery_object_get_id(cached->object), id)); - if (cache->object_lifetime_stale) { - struct timeval elapsed; - - elapsed = ast_tvsub(ast_tvnow(), cached->created); - if (elapsed.tv_sec > cache->object_lifetime_stale) { - ao2_lock(cached); - if (cached->stale_update_sched_id == -1) { - struct stale_update_task_data *task_data; - - task_data = stale_update_task_data_alloc((struct ast_sorcery *) sorcery, - cache, type, cached->object); - if (task_data) { - ast_debug(1, "Cached sorcery object type '%s' ID '%s' is stale. Refreshing\n", - type, id); - cached->stale_update_sched_id = ast_sched_add(sched, 1, - stale_item_update, task_data); - } - if (cached->stale_update_sched_id < 0) { - ao2_cleanup(task_data); - ast_log(LOG_ERROR, "Unable to update stale cached object type '%s', ID '%s'.\n", - type, id); - } - } - ao2_unlock(cached); - } - } + memory_cache_stale_check_object(sorcery, cache, cached); object = ao2_bump(cached->object); ao2_ref(cached, -1); @@ -874,6 +1232,150 @@ static void *sorcery_memory_cache_retrieve_id(const struct ast_sorcery *sorcery, return object; } +/*! + * \internal + * \brief AO2 callback function for comparing a retrieval request and finding applicable objects + * + * \param obj The cached object + * \param arg The comparison parameters + * \param flags Unused flags + */ +static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags) +{ + struct sorcery_memory_cached_object *cached = obj; + const struct sorcery_memory_cache_fields_cmp_params *params = arg; + RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy); + + if (params->regex) { + /* If a regular expression has been provided see if it matches, otherwise move on */ + if (!regexec(params->regex, ast_sorcery_object_get_id(cached->object), 0, NULL, 0)) { + ao2_link(params->container, cached->object); + } + return 0; + } else if (params->fields && + (ast_sorcery_changeset_create(cached->objectset, params->fields, &diff) || + diff)) { + /* If we can't turn the object into an object set OR if differences exist between the fields + * passed in and what are present on the object they are not a match. + */ + return 0; + } + + if (params->container) { + ao2_link(params->container, cached->object); + + /* As multiple objects are being returned keep going */ + return 0; + } else { + /* Immediately stop and return, we only want a single object */ + return CMP_MATCH | CMP_STOP; + } +} + +/*! + * \internal + * \brief Callback function to retrieve a single object based on fields + * + * \param sorcery The sorcery instance + * \param data The sorcery memory cache + * \param type The type of the object to retrieve + * \param fields Any explicit fields to search for + */ +static void *sorcery_memory_cache_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, + const struct ast_variable *fields) +{ + struct sorcery_memory_cache *cache = data; + struct sorcery_memory_cache_fields_cmp_params params = { + .sorcery = sorcery, + .cache = cache, + .fields = fields, + }; + struct sorcery_memory_cached_object *cached; + void *object = NULL; + + if (is_passthru_update() || !cache->full_backend_cache || !fields) { + return NULL; + } + + cached = ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, ¶ms); + + if (cached) { + memory_cache_stale_check_object(sorcery, cache, cached); + object = ao2_bump(cached->object); + ao2_ref(cached, -1); + } + + return object; +} + +/*! + * \internal + * \brief Callback function to retrieve multiple objects from a memory cache + * + * \param sorcery The sorcery instance + * \param data The sorcery memory cache + * \param type The type of the object to retrieve + * \param objects Container to place the objects into + * \param fields Any explicit fields to search for + */ +static void sorcery_memory_cache_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const struct ast_variable *fields) +{ + struct sorcery_memory_cache *cache = data; + struct sorcery_memory_cache_fields_cmp_params params = { + .sorcery = sorcery, + .cache = cache, + .fields = fields, + .container = objects, + }; + + if (is_passthru_update() || !cache->full_backend_cache) { + return; + } + + memory_cache_full_update(sorcery, type, cache); + ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, ¶ms); + + if (ao2_container_count(objects)) { + memory_cache_stale_check(sorcery, cache); + } +} + +/*! + * \internal + * \brief Callback function to retrieve multiple objects using a regex on the object id + * + * \param sorcery The sorcery instance + * \param data The sorcery memory cache + * \param type The type of the object to retrieve + * \param objects Container to place the objects into + * \param regex Regular expression to apply to the object id + */ +static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *regex) +{ + struct sorcery_memory_cache *cache = data; + regex_t expression; + struct sorcery_memory_cache_fields_cmp_params params = { + .sorcery = sorcery, + .cache = cache, + .container = objects, + .regex = &expression, + }; + + if (is_passthru_update() || !cache->full_backend_cache || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) { + return; + } + + memory_cache_full_update(sorcery, type, cache); + ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, ¶ms); + regfree(&expression); + + if (ao2_container_count(objects)) { + memory_cache_stale_check(sorcery, cache); + } +} + /*! * \internal * \brief Callback function to finish configuring the memory cache @@ -894,6 +1396,11 @@ static void sorcery_memory_cache_load(void *data, const struct ast_sorcery *sorc ao2_link(caches, cache); ast_debug(1, "Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n", cache->name, sorcery, ast_sorcery_get_module(sorcery), type); + + if (cache->full_backend_cache) { + cache->sorcery = sorcery; + cache->object_type = ast_strdup(type); + } } /*! @@ -962,6 +1469,7 @@ static void *sorcery_memory_cache_open(const char *data) } cache->expire_id = -1; + cache->stale_update_sched_id = -1; /* If no configuration options have been provided this memory cache will operate in a default * configuration. @@ -996,6 +1504,8 @@ static void *sorcery_memory_cache_open(const char *data) } } else if (!strcasecmp(name, "expire_on_reload")) { cache->expire_on_reload = ast_true(value); + } else if (!strcasecmp(name, "full_backend_cache")) { + cache->full_backend_cache = ast_true(value); } else { ast_log(LOG_ERROR, "Unsupported option '%s' used for memory cache\n", name); return NULL; @@ -1079,6 +1589,12 @@ static void sorcery_memory_cache_close(void *data) ao2_unlock(cache->objects); } + if (cache->full_backend_cache) { + ao2_wrlock(cache->objects); + cache->sorcery = NULL; + ao2_unlock(cache->objects); + } + ao2_ref(cache, -1); } @@ -1406,11 +1922,72 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct return CLI_SUCCESS; } +/*! + * \internal + * \brief CLI command implementation for 'sorcery memory cache populate' + */ +static char *sorcery_memory_cache_populate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct sorcery_memory_cache *cache; + + switch (cmd) { + case CLI_INIT: + e->command = "sorcery memory cache populate"; + e->usage = + "Usage: sorcery memory cache populate \n" + " Expire all objects in the cache and populate it with ALL objects from backend.\n"; + return NULL; + case CLI_GENERATE: + if (a->pos == 4) { + return sorcery_memory_cache_complete_name(a->word, a->n); + } else { + return NULL; + } + } + + if (a->argc > 5) { + return CLI_SHOWUSAGE; + } + + cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY); + if (!cache) { + ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]); + return CLI_FAILURE; + } + + if (!cache->full_backend_cache) { + ast_cli(a->fd, "Specified sorcery memory cache '%s' does not have full backend caching enabled\n", a->argv[4]); + ao2_ref(cache, -1); + return CLI_FAILURE; + } + + ao2_wrlock(cache->objects); + if (!cache->sorcery) { + ast_cli(a->fd, "Specified sorcery memory cache '%s' is no longer active\n", a->argv[4]); + ao2_unlock(cache->objects); + ao2_ref(cache, -1); + return CLI_FAILURE; + } + + remove_all_from_cache(cache); + memory_cache_populate(cache->sorcery, cache->object_type, cache); + + ast_cli(a->fd, "Specified sorcery memory cache '%s' has been populated with '%d' objects from the backend\n", + a->argv[4], ao2_container_count(cache->objects)); + + ao2_unlock(cache->objects); + + ao2_ref(cache, -1); + + return CLI_SUCCESS; +} + static struct ast_cli_entry cli_memory_cache[] = { AST_CLI_DEFINE(sorcery_memory_cache_show, "Show sorcery memory cache information"), AST_CLI_DEFINE(sorcery_memory_cache_dump, "Dump all objects within a sorcery memory cache"), AST_CLI_DEFINE(sorcery_memory_cache_expire, "Expire a specific object or ALL objects within a sorcery memory cache"), AST_CLI_DEFINE(sorcery_memory_cache_stale, "Mark a specific object or ALL objects as stale within a sorcery memory cache"), + AST_CLI_DEFINE(sorcery_memory_cache_populate, "Clear and populate the sorcery memory cache with objects from the backend"), }; /*! @@ -1555,6 +2132,52 @@ static int sorcery_memory_cache_ami_stale(struct mansession *s, const struct mes return 0; } +/*! + * \internal + * \brief AMI command implementation for 'SorceryMemoryCachePopulate' + */ +static int sorcery_memory_cache_ami_populate(struct mansession *s, const struct message *m) +{ + const char *cache_name = astman_get_header(m, "Cache"); + struct sorcery_memory_cache *cache; + + if (ast_strlen_zero(cache_name)) { + astman_send_error(s, m, "SorceryMemoryCachePopulate requires that a cache name be provided.\n"); + return 0; + } + + cache = ao2_find(caches, cache_name, OBJ_SEARCH_KEY); + if (!cache) { + astman_send_error(s, m, "The provided cache does not exist\n"); + return 0; + } + + if (!cache->full_backend_cache) { + astman_send_error(s, m, "The provided cache does not have full backend caching enabled\n"); + ao2_ref(cache, -1); + return 0; + } + + ao2_wrlock(cache->objects); + if (!cache->sorcery) { + astman_send_error(s, m, "The provided cache is no longer active\n"); + ao2_unlock(cache->objects); + ao2_ref(cache, -1); + return 0; + } + + remove_all_from_cache(cache); + memory_cache_populate(cache->sorcery, cache->object_type, cache); + + ao2_unlock(cache->objects); + + ao2_ref(cache, -1); + + astman_send_ack(s, m, "Cache has been expired and populated\n"); + + return 0; +} + #ifdef TEST_FRAMEWORK /*! \brief Dummy sorcery object */ @@ -2319,12 +2942,52 @@ static void *mock_retrieve_id(const struct ast_sorcery *sorcery, void *data, return b_data; } +/*! + * \brief Callback for retrieving multiple sorcery objects + * + * The mock wizard uses the \ref real_backend_data in order to construct + * objects. If the backend data is "nonexisent" then no object is returned. + * Otherwise, the number of objects matching the exists value will be returned. + * + * \param sorcery The sorcery instance + * \param data Unused + * \param type The object type. Will always be "test". + * \param objects Container to place objects into. + * \param fields Fields to search for. + */ +static void mock_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, + const char *type, struct ao2_container *objects, const struct ast_variable *fields) +{ + int i; + + if (fields) { + return; + } + + for (i = 0; i < real_backend_data->exists; ++i) { + char uuid[AST_UUID_STR_LEN]; + struct test_data *b_data; + + b_data = ast_sorcery_alloc(sorcery, type, ast_uuid_generate_str(uuid, sizeof(uuid))); + if (!b_data) { + continue; + } + + b_data->salt = real_backend_data->salt; + b_data->pepper = real_backend_data->pepper; + + ao2_link(objects, b_data); + ao2_ref(b_data, -1); + } +} + /*! * \brief A mock sorcery wizard used for the stale test */ static struct ast_sorcery_wizard mock_wizard = { .name = "mock", .retrieve_id = mock_retrieve_id, + .retrieve_multiple = mock_retrieve_multiple, }; /*! @@ -2488,6 +3151,259 @@ AST_TEST_DEFINE(stale) return res; } +AST_TEST_DEFINE(full_backend_cache_expiration) +{ + int res = AST_TEST_FAIL; + struct ast_sorcery *sorcery = NULL; + struct backend_data initial = { + .salt = 0, + .pepper = 0, + .exists = 4, + }; + struct ao2_container *objects; + ast_mutex_t lock; + ast_cond_t cond; + struct timeval start; + struct timespec end; + + switch (cmd) { + case TEST_INIT: + info->name = "full_backend_cache_expiration"; + info->category = "/res/res_sorcery_memory_cache/"; + info->summary = "Ensure that the full backend cache actually caches the backend"; + info->description = "This test performs the following:\n" + "\t* Create a sorcery instance with two wizards" + "\t\t* The first is a memory cache that expires objects after 3 seconds and does full backend caching\n" + "\t\t* The second is a mock of a back-end\n" + "\t* Populates the cache by requesting all objects which returns 4.\n" + "\t* Updates the backend to contain a different number of objects, 8.\n" + "\t* Requests all objects and confirms the number returned is only 4.\n" + "\t* Wait for cached objects to expire.\n" + "\t* Requests all objects and confirms the number returned is 8."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_sorcery_wizard_register(&mock_wizard); + + sorcery = ast_sorcery_open(); + if (!sorcery) { + ast_test_status_update(test, "Failed to create sorcery instance\n"); + goto cleanup; + } + + ast_sorcery_apply_wizard_mapping(sorcery, "test", "memory_cache", + "object_lifetime_maximum=3,full_backend_cache=yes", 1); + ast_sorcery_apply_wizard_mapping(sorcery, "test", "mock", NULL, 0); + ast_sorcery_internal_object_register(sorcery, "test", test_data_alloc, NULL, NULL); + ast_sorcery_object_field_register_nodoc(sorcery, "test", "salt", "0", OPT_UINT_T, 0, FLDSET(struct test_data, salt)); + ast_sorcery_object_field_register_nodoc(sorcery, "test", "pepper", "0", OPT_UINT_T, 0, FLDSET(struct test_data, pepper)); + + /* Prepopulate the cache */ + real_backend_data = &initial; + + /* Get all current objects in the backend */ + objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (!objects) { + ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n"); + goto cleanup; + } + ao2_ref(objects, -1); + + /* Update the backend to have a different number of objects */ + initial.exists = 8; + + /* Get all current objects in the backend */ + objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (!objects) { + ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n"); + goto cleanup; + } + + if (ao2_container_count(objects) == initial.exists) { + ast_test_status_update(test, "Number of objects returned is of the current backend and not the cache\n"); + ao2_ref(objects, -1); + goto cleanup; + } + + ao2_ref(objects, -1); + + ast_mutex_init(&lock); + ast_cond_init(&cond, NULL); + + start = ast_tvnow(); + end.tv_sec = start.tv_sec + 5; + end.tv_nsec = start.tv_usec * 1000; + + ast_mutex_lock(&lock); + while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) { + } + ast_mutex_unlock(&lock); + + ast_mutex_destroy(&lock); + ast_cond_destroy(&cond); + + /* Get all current objects in the backend */ + objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (!objects) { + ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n"); + goto cleanup; + } + + if (ao2_container_count(objects) != initial.exists) { + ast_test_status_update(test, "Number of objects returned is NOT of the current backend when it should be\n"); + ao2_ref(objects, -1); + goto cleanup; + } + + ao2_ref(objects, -1); + + res = AST_TEST_PASS; + +cleanup: + if (sorcery) { + ast_sorcery_unref(sorcery); + } + ast_sorcery_wizard_unregister(&mock_wizard); + return res; +} + +AST_TEST_DEFINE(full_backend_cache_stale) +{ + int res = AST_TEST_FAIL; + struct ast_sorcery *sorcery = NULL; + struct backend_data initial = { + .salt = 0, + .pepper = 0, + .exists = 4, + }; + struct ao2_container *objects; + ast_mutex_t lock; + ast_cond_t cond; + struct timeval start; + struct timespec end; + + switch (cmd) { + case TEST_INIT: + info->name = "full_backend_cache_stale"; + info->category = "/res/res_sorcery_memory_cache/"; + info->summary = "Ensure that the full backend cache works with staleness"; + info->description = "This test performs the following:\n" + "\t* Create a sorcery instance with two wizards" + "\t\t* The first is a memory cache that stales objects after 1 second and does full backend caching\n" + "\t\t* The second is a mock of a back-end\n" + "\t* Populates the cache by requesting all objects which returns 4.\n" + "\t* Wait for objects to go stale.\n" + "\t* Updates the backend to contain a different number of objects, 8.\"" + "\t* Requests all objects and confirms the number returned is only 4.\n" + "\t* Wait for objects to be refreshed from backend.\n" + "\t* Requests all objects and confirms the number returned is 8."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_sorcery_wizard_register(&mock_wizard); + + ast_mutex_init(&lock); + ast_cond_init(&cond, NULL); + + sorcery = ast_sorcery_open(); + if (!sorcery) { + ast_test_status_update(test, "Failed to create sorcery instance\n"); + goto cleanup; + } + + ast_sorcery_apply_wizard_mapping(sorcery, "test", "memory_cache", + "object_lifetime_stale=1,full_backend_cache=yes", 1); + ast_sorcery_apply_wizard_mapping(sorcery, "test", "mock", NULL, 0); + ast_sorcery_internal_object_register(sorcery, "test", test_data_alloc, NULL, NULL); + ast_sorcery_object_field_register_nodoc(sorcery, "test", "salt", "0", OPT_UINT_T, 0, FLDSET(struct test_data, salt)); + ast_sorcery_object_field_register_nodoc(sorcery, "test", "pepper", "0", OPT_UINT_T, 0, FLDSET(struct test_data, pepper)); + + /* Prepopulate the cache */ + real_backend_data = &initial; + + /* Get all current objects in the backend */ + objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (!objects) { + ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n"); + goto cleanup; + } + ao2_ref(objects, -1); + + start = ast_tvnow(); + end.tv_sec = start.tv_sec + 5; + end.tv_nsec = start.tv_usec * 1000; + + ast_mutex_lock(&lock); + while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) { + } + ast_mutex_unlock(&lock); + + initial.exists = 8; + + /* Get all current objects in the backend */ + objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (!objects) { + ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n"); + goto cleanup; + } + + if (ao2_container_count(objects) == initial.exists) { + ast_test_status_update(test, "Number of objects returned is of the backend and not the cache\n"); + ao2_ref(objects, -1); + goto cleanup; + } + + ao2_ref(objects, -1); + + start = ast_tvnow(); + end.tv_sec = start.tv_sec + 5; + end.tv_nsec = start.tv_usec * 1000; + + ast_mutex_lock(&lock); + while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) { + } + ast_mutex_unlock(&lock); + + /* Get all current objects in the backend */ + objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (!objects) { + ast_test_status_update(test, "Unable to retrieve all objects in backend and populate cache\n"); + goto cleanup; + } + + if (ao2_container_count(objects) != initial.exists) { + ast_test_status_update(test, "Number of objects returned is not of backend\n"); + ao2_ref(objects, -1); + goto cleanup; + } + + ao2_ref(objects, -1); + + start = ast_tvnow(); + end.tv_sec = start.tv_sec + 5; + end.tv_nsec = start.tv_usec * 1000; + + ast_mutex_lock(&lock); + while (ast_cond_timedwait(&cond, &lock, &end) != ETIMEDOUT) { + } + ast_mutex_unlock(&lock); + + res = AST_TEST_PASS; + +cleanup: + if (sorcery) { + ast_sorcery_unref(sorcery); + } + ast_sorcery_wizard_unregister(&mock_wizard); + ast_mutex_destroy(&lock); + ast_cond_destroy(&cond); + return res; +} + #endif static int unload_module(void) @@ -2500,11 +3416,14 @@ static int unload_module(void) AST_TEST_UNREGISTER(maximum_objects); AST_TEST_UNREGISTER(expiration); AST_TEST_UNREGISTER(stale); + AST_TEST_UNREGISTER(full_backend_cache_expiration); + AST_TEST_UNREGISTER(full_backend_cache_stale); ast_manager_unregister("SorceryMemoryCacheExpireObject"); ast_manager_unregister("SorceryMemoryCacheExpire"); ast_manager_unregister("SorceryMemoryCacheStaleObject"); ast_manager_unregister("SorceryMemoryCacheStale"); + ast_manager_unregister("SorceryMemoryCachePopulate"); ast_cli_unregister_multiple(cli_memory_cache, ARRAY_LEN(cli_memory_cache)); @@ -2560,6 +3479,7 @@ static int load_module(void) res |= ast_manager_register_xml("SorceryMemoryCacheExpire", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_expire); res |= ast_manager_register_xml("SorceryMemoryCacheStaleObject", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_stale_object); res |= ast_manager_register_xml("SorceryMemoryCacheStale", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_stale); + res |= ast_manager_register_xml("SorceryMemoryCachePopulate", EVENT_FLAG_SYSTEM, sorcery_memory_cache_ami_populate); if (res) { unload_module(); @@ -2577,6 +3497,8 @@ static int load_module(void) AST_TEST_REGISTER(delete); AST_TEST_REGISTER(maximum_objects); AST_TEST_REGISTER(expiration); + AST_TEST_REGISTER(full_backend_cache_expiration); + AST_TEST_REGISTER(full_backend_cache_stale); return AST_MODULE_LOAD_SUCCESS; } From 648ca2b1b811e266c9dc75f686ec29cf26cacbc0 Mon Sep 17 00:00:00 2001 From: Dade Brandon Date: Thu, 17 Dec 2015 17:05:00 -0800 Subject: [PATCH 0086/1578] res_rtp_asterisk: Resolve further timing issues with DTLS negotiation Resolves an edge case dtls negotiation delay for certain networks which somehow manage to drop the rtcp side's packet when these are both sent ast_rtp_remote_address_set, causing it to have to time-out and restart the handshake. Move dtls pending bio flush in to it's own function, and call it from ast_rtp_on_ice_complete, when we're rtp->ice, rather than when ast_rtp_remote_address_set. Keep the existing flush from the recent change to res_rtp_remote_address_set if ice is not being used. ASTERISK-25614 #close Reported-by: XenCALL Tested by: XenCALL Change-Id: Ie2caedbdee1783159f375589b6fd3845c8577ba5 --- res/res_rtp_asterisk.c | 54 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 6f09368b891..1fb4e1ceb5d 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -444,6 +444,7 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level); #ifdef HAVE_OPENSSL_SRTP static int ast_rtp_activate(struct ast_rtp_instance *instance); static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp); +static void dtls_srtp_flush_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp); static void dtls_srtp_start_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp); static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp); #endif @@ -1683,15 +1684,20 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) if (rtp->rtcp) { update_address_with_ice_candidate(rtp, AST_RTP_ICE_COMPONENT_RTCP, &rtp->rtcp->them); } - } #ifdef HAVE_OPENSSL_SRTP - dtls_perform_handshake(instance, &rtp->dtls, 0); + if (rtp->dtls.dtls_setup != AST_RTP_DTLS_SETUP_PASSIVE) { + dtls_perform_handshake(instance, &rtp->dtls, 0); + } + else { + dtls_srtp_flush_pending(instance, rtp); /* this flushes pending BIO for both rtp & rtcp as needed. */ + } - if (rtp->rtcp) { - dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); - } + if (rtp->rtcp && rtp->rtcp->dtls.dtls_setup != AST_RTP_DTLS_SETUP_PASSIVE) { + dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); + } #endif + } if (!strictrtp) { return; @@ -1886,6 +1892,23 @@ static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, stru AST_SCHED_DEL_UNREF(rtp->sched, dtls->timeout_timer, ao2_ref(instance, -1)); } +static void dtls_srtp_flush_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp) +{ + struct dtls_details *dtls; + + dtls = &rtp->dtls; + ast_mutex_lock(&dtls->lock); + dtls_srtp_check_pending(instance, rtp, 0); + ast_mutex_unlock(&dtls->lock); + + if (rtp->rtcp) { + dtls = &rtp->rtcp->dtls; + ast_mutex_lock(&dtls->lock); + dtls_srtp_check_pending(instance, rtp, 1); + ast_mutex_unlock(&dtls->lock); + } +} + static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp) { struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; @@ -4821,9 +4844,6 @@ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp) static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); -#ifdef HAVE_OPENSSL_SRTP - struct dtls_details *dtls; -#endif if (rtp->rtcp) { ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance); @@ -4844,22 +4864,10 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct #ifdef HAVE_OPENSSL_SRTP /* Trigger pending outbound DTLS packets received before the address was set. Avoid unnecessary locking * by checking if we're passive. Without this, we only send the pending packets once a new SSL packet is - * received in __rtp_recvfrom. + * received in __rtp_recvfrom. If rtp->ice, this is instead done on_ice_complete */ - dtls = &rtp->dtls; - if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { - ast_mutex_lock(&dtls->lock); - dtls_srtp_check_pending(instance, rtp, 0); - ast_mutex_unlock(&dtls->lock); - } - - if (rtp->rtcp) { - dtls = &rtp->rtcp->dtls; - if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { - ast_mutex_lock(&dtls->lock); - dtls_srtp_check_pending(instance, rtp, 1); - ast_mutex_unlock(&dtls->lock); - } + if (!rtp->ice && rtp->dtls.dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + dtls_srtp_flush_pending(instance, rtp); } #endif From ca394161cf15b018e7cdf8f3015e1363476c10f1 Mon Sep 17 00:00:00 2001 From: Dade Brandon Date: Sun, 20 Dec 2015 19:33:02 -0800 Subject: [PATCH 0087/1578] app_amd: Correct maximum_number_of_words functionality & documentation - The maximum_number_of_words was previously documented as being the number of words that when exceeded, would result in the AMD application returning that the audio represents a machine. This was inconsistent with its actual functionality - it was a number of words that when REACHED, would result in determination as a machine. This update corrects the functionality to match the previously documented functionality. This is a backwards incompatible change in configuration file, and has been added to UPGRADE.txt as a result. The sample configuration file and application defaults have been updated so that the default value is now 2, which reflects the same default functionality as previous versions. - Update documentation for silence_threshold, which previously implied that it was measuring time, rather than noise averages in the sample. - Update the comments in amd.conf.sample. ASTERISK-25639 #close Change-Id: I4b1451e5dc9cb3cb06d59b6ab872f5275ba79093 --- UPGRADE.txt | 10 ++++++++++ apps/app_amd.c | 20 ++++++++++---------- configs/samples/amd.conf.sample | 26 +++++++++++++++++--------- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/UPGRADE.txt b/UPGRADE.txt index 91d9edc9249..6fb82c43aa2 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -64,5 +64,15 @@ AMI: Commands that fail to execute (no such command, invalid syntax etc.) now return an Error response instead of Success. +app_amd: + - The 'maximum_number_of_words' configuration option and parameter to the AMD + application previously did not match the documented functionality + variable + name. In Asterisk 13, a value of '3' would mean that if '3' words were detected, + the result would be detection as a 'MACHINE'. As of this version, the value + reflects the maximum words that if EXCEEDED (rather than reached), would + result in detection as a machine. This means that you should update this + value to be one higher than your previos value, if your previous value + was working well for you. + =========================================================== =========================================================== diff --git a/apps/app_amd.c b/apps/app_amd.c index ee421b6bc34..83da5330d89 100644 --- a/apps/app_amd.c +++ b/apps/app_amd.c @@ -62,19 +62,19 @@ ASTERISK_REGISTER_FILE() Is maximum initial silence duration before greeting. - If this is exceeded set as MACHINE + If this is exceeded, the result is detection as a MACHINE is the maximum length of a greeting. - If this is exceeded set as MACHINE + If this is exceeded, the result is detection as a MACHINE Is the silence after detecting a greeting. - If this is exceeded set as HUMAN + If this is exceeded, the result is detection as a HUMAN Is the maximum time allowed for the algorithm - to decide HUMAN or MACHINE + to decide on whether the audio represents a HUMAN, or a MACHINE Is the minimum duration of Voice considered to be a word @@ -85,14 +85,14 @@ ASTERISK_REGISTER_FILE() Is the maximum number of words in a greeting - If this is exceeded set as MACHINE + If this is exceeded, then the result is detection as a MACHINE - How long do we consider silence + What is the average level of noise from 0 to 32767 which if not exceeded, should be considered silence? Is the maximum duration of a word to accept. - If exceeded set as MACHINE + If exceeded, then the result is detection as a MACHINE @@ -130,7 +130,7 @@ ASTERISK_REGISTER_FILE() Word Count - maximum number of words. - + @@ -154,7 +154,7 @@ static int dfltAfterGreetingSilence = 800; static int dfltTotalAnalysisTime = 5000; static int dfltMinimumWordLength = 100; static int dfltBetweenWordsSilence = 50; -static int dfltMaximumNumberOfWords = 3; +static int dfltMaximumNumberOfWords = 2; static int dfltSilenceThreshold = 256; static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */ @@ -367,7 +367,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data) sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration); break; } - if (iWordsCount >= maximumNumberOfWords) { + if (iWordsCount > maximumNumberOfWords) { ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", ast_channel_name(chan), iWordsCount); ast_frfree(f); strcpy(amdStatus , "MACHINE"); diff --git a/configs/samples/amd.conf.sample b/configs/samples/amd.conf.sample index d7323ecf225..d1764b50cea 100644 --- a/configs/samples/amd.conf.sample +++ b/configs/samples/amd.conf.sample @@ -3,17 +3,25 @@ ; [general] +total_analysis_time = 5000 ; Maximum time allowed for the algorithm to decide + ; on whether the audio represents a HUMAN, or a MACHINE +silence_threshold = 256 ; If the average level of noise in a sample does not reach + ; this value, from a scale of 0 to 32767, then we will consider + ; it to be silence. + +; Greeting ; initial_silence = 2500 ; Maximum silence duration before the greeting. - ; If exceeded then MACHINE. -greeting = 1500 ; Maximum length of a greeting. If exceeded then MACHINE. + ; If exceeded, then the result is detection as a MACHINE. after_greeting_silence = 800 ; Silence after detecting a greeting. - ; If exceeded then HUMAN -total_analysis_time = 5000 ; Maximum time allowed for the algorithm to decide - ; on a HUMAN or MACHINE + ; If exceeded, then the result is detection as a HUMAN +greeting = 1500 ; Maximum length of a greeting. If exceeded, then the + ; result is detection as a MACHINE. + +; Word detection ; min_word_length = 100 ; Minimum duration of Voice to considered as a word +maximum_word_length = 5000 ; Maximum duration of a single Voice utterance allowed. between_words_silence = 50 ; Minimum duration of silence after a word to consider ; the audio what follows as a new word -maximum_number_of_words = 3 ; Maximum number of words in the greeting. - ; If exceeded then MACHINE -maximum_word_length = 5000 ; Maximum duration of a single Voice utterance allowed. -silence_threshold = 256 + +maximum_number_of_words = 2 ; Maximum number of words in the greeting + ; If exceeded, then the result is detection as a MACHINE From b8876711f37a5d34e0091befa5cdaad6dcb35da9 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 24 Dec 2015 10:18:22 -0600 Subject: [PATCH 0088/1578] res_rtp_asterisk: rtp->ice check not wrapped in HAVE_PJPROJECT ifdef Change-Id: I19b49112e1b630bd04e859f14ccf96f8ebd6b151 --- res/res_rtp_asterisk.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 1fb4e1ceb5d..3f65f1344d3 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4866,12 +4866,15 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct * by checking if we're passive. Without this, we only send the pending packets once a new SSL packet is * received in __rtp_recvfrom. If rtp->ice, this is instead done on_ice_complete */ - if (!rtp->ice && rtp->dtls.dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { +#ifdef HAVE_PJPROJECT + if (rtp->ice) { + return; + } +#endif + if (rtp->dtls.dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { dtls_srtp_flush_pending(instance, rtp); } #endif - - return; } /*! \brief Write t140 redundacy frame From 2df4ad647c06451715a22efb17c05ceb4875fa69 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 24 Dec 2015 12:19:51 -0600 Subject: [PATCH 0089/1578] res/res_pjsip_location: Delete contact_status object when contact is deleted In 450579e908, a change was made that removed the deletion of the 'contact_status' object when a 'contact' object is deleted in sorcery. This unfortunately means that the 'contact_status' object persists, even when something has explicitly removed a contact. The result is that the state of the contact will not be regenerated if that contact is re-created, and the stale state will be reported/used for that contact. It also results in no ContactStatusChanged events being generated for either ARI or AMI. This patch restores the deletion logic that was removed. Doing so now results in the expected events being generated again. Change-Id: I28789a112e845072308b5b34522690e3faf58f07 --- res/res_pjsip/location.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index c070e7dbceb..04521842404 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -317,6 +317,14 @@ int ast_sip_location_update_contact(struct ast_sip_contact *contact) int ast_sip_location_delete_contact(struct ast_sip_contact *contact) { + void *contact_status_obj; + + contact_status_obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); + if (contact_status_obj) { + ast_sorcery_delete(ast_sip_get_sorcery(), contact_status_obj); + ao2_ref(contact_status_obj, -1); + } + return ast_sorcery_delete(ast_sip_get_sorcery(), contact); } From 8eb5da0679a8e8ed28940ed77eb1ccaf0296a621 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 23 Dec 2015 17:40:39 -0600 Subject: [PATCH 0090/1578] bridge_basic.c: Fix GOTO_ON_BLINDXFR Use of GOTO_ON_BLINDXFR would not work at all. The target location would never be executed by the transferring channel. * Made feature_blind_transfer() call ast_bridge_set_after_go_on() with valid context, exten, and priority parameters from the transferring channel. * Renamed some feature_blind_transfer() local variables for clarity. ASTERISK-25641 #close Reported by Dmitry Melekhov Change-Id: I19bead9ffdc4aee8d58c654ca05a198da1e4b7ac --- main/bridge_basic.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/main/bridge_basic.c b/main/bridge_basic.c index 5e20f303ddd..cd19915205a 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -3383,35 +3383,46 @@ static void blind_transfer_cb(struct ast_channel *new_channel, struct transfer_c /*! \brief Internal built in feature for blind transfers */ static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { - char exten[AST_MAX_EXTENSION] = ""; + char xfer_exten[AST_MAX_EXTENSION] = ""; struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt; - const char *context; + const char *xfer_context; char *goto_on_blindxfr; ast_bridge_channel_write_hold(bridge_channel, NULL); ast_channel_lock(bridge_channel->chan); - context = ast_strdupa(get_transfer_context(bridge_channel->chan, + xfer_context = ast_strdupa(get_transfer_context(bridge_channel->chan, blind_transfer ? blind_transfer->context : NULL)); goto_on_blindxfr = ast_strdupa(S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "GOTO_ON_BLINDXFR"), "")); ast_channel_unlock(bridge_channel->chan); /* Grab the extension to transfer to */ - if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) { + if (grab_transfer(bridge_channel->chan, xfer_exten, sizeof(xfer_exten), xfer_context)) { ast_bridge_channel_write_unhold(bridge_channel); return 0; } if (!ast_strlen_zero(goto_on_blindxfr)) { + const char *chan_context; + const char *chan_exten; + int chan_priority; + ast_debug(1, "After transfer, transferer %s goes to %s\n", ast_channel_name(bridge_channel->chan), goto_on_blindxfr); - ast_bridge_set_after_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr); + + ast_channel_lock(bridge_channel->chan); + chan_context = ast_strdupa(ast_channel_context(bridge_channel->chan)); + chan_exten = ast_strdupa(ast_channel_exten(bridge_channel->chan)); + chan_priority = ast_channel_priority(bridge_channel->chan); + ast_channel_unlock(bridge_channel->chan); + ast_bridge_set_after_go_on(bridge_channel->chan, + chan_context, chan_exten, chan_priority, goto_on_blindxfr); } - if (ast_bridge_transfer_blind(0, bridge_channel->chan, exten, context, blind_transfer_cb, - bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS && - !ast_strlen_zero(goto_on_blindxfr)) { + if (ast_bridge_transfer_blind(0, bridge_channel->chan, xfer_exten, xfer_context, + blind_transfer_cb, bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS + && !ast_strlen_zero(goto_on_blindxfr)) { ast_bridge_discard_after_goto(bridge_channel->chan); } From 6dc21bbf00388778bcd865f6cb7169e8029e001a Mon Sep 17 00:00:00 2001 From: Dade Brandon Date: Fri, 25 Dec 2015 07:56:44 -0800 Subject: [PATCH 0091/1578] chan_sip.c: fix websocket_write_timeout default value websocket_write_timeout was not being set to its default value during sip config reload, which meant that prior to this commit, 1) the default value of 100 was not used, unless an invalid value (or 1) was specified in sip.conf for websocket_write_timeout, and 2) if the websocket_write_timeout directive was removed from sip.conf without a full restart of asterisk, then the previous value would continue to be used indefinitely. This essentially lead to a 0ms write timeout (the first write attempt in ast_careful_fwrite must have succeeded) in websocket write requests from chan_sip, unless websocket_write_timeout was explicitely set in sip.conf. Changes to websocket_write_timeout still only apply to new websocket sessions, after the sip reload -- timeouts on existing sessions are not adjusted during sip reload. Change-Id: Ibed3816ed29cc354af6564c5ab3e75eab72cb953 --- channels/chan_sip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f7fbed72029..b4c2602503d 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -31511,6 +31511,7 @@ static int reload_config(enum channelreloadreason reason) global_dynamic_exclude_static = 0; /* Exclude static peers */ sip_cfg.tcp_enabled = FALSE; sip_cfg.websocket_enabled = TRUE; + sip_cfg.websocket_write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT; /* Session-Timers */ global_st_mode = SESSION_TIMER_MODE_ACCEPT; From d4b10cfb3e41e7635385866b7f96968c6b1e9cb1 Mon Sep 17 00:00:00 2001 From: Ward van Wanrooij Date: Sat, 26 Dec 2015 16:24:09 +0100 Subject: [PATCH 0092/1578] chan_sip: option 'notifyringing' change and doc fix In the sample sip.conf this is written with regard to notifyringing: ;notifyringing = no ; Control whether subscriptions already INUSE get sent RINGING when another call is sent (default: yes) However, this setting changes whether or not any RINGING indications are sent to subscriptions. There is no separate configurable setting that allows to control whether INUSE subscriptions also get sent RINGING. This is however a useful option, to see (using BLF) if somebody else is able to handle an incoming call or if everybody is busy. This patch corrects the documentation for notifyringing (so the documentation matches the functionality) and make notifyringing a tri-state option, by adding the value 'notinuse' (in addition to 'yes' and 'no'). When notifyringing = notinuse, only subscriptions that are not INUSE are sent the RINGING signal. The default setting for notifyringing remains set to yes, so the default behaviour is not affected. ASTERISK-25558 Change-Id: I88f7036ee084bb3f43b74f15612695c6708f74aa --- channels/chan_sip.c | 10 +++++++--- channels/sip/include/sip.h | 9 ++++++++- configs/samples/sip.conf.sample | 8 ++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 158dc7b1818..fa4b864b136 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -14630,7 +14630,7 @@ static void state_notify_build_xml(struct state_notify_data *data, int full, con switch (data->state) { case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE): - statestring = (sip_cfg.notifyringing) ? "early" : "confirmed"; + statestring = (sip_cfg.notifyringing == NOTIFYRINGING_ENABLED) ? "early" : "confirmed"; local_state = NOTIFY_INUSE; pidfstate = "busy"; pidfnote = "Ringing"; @@ -21120,7 +21120,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, " Outbound reg. timeout: %d secs\n", global_reg_timeout); ast_cli(a->fd, " Outbound reg. attempts: %d\n", global_regattempts_max); ast_cli(a->fd, " Outbound reg. retry 403:%d\n", global_reg_retry_403); - ast_cli(a->fd, " Notify ringing state: %s\n", AST_CLI_YESNO(sip_cfg.notifyringing)); + ast_cli(a->fd, " Notify ringing state: %s%s\n", AST_CLI_YESNO(sip_cfg.notifyringing), sip_cfg.notifyringing == NOTIFYRINGING_NOTINUSE ? " (when not in use)" : ""); if (sip_cfg.notifyringing) { ast_cli(a->fd, " Include CID: %s%s\n", AST_CLI_YESNO(sip_cfg.notifycid), @@ -31676,7 +31676,11 @@ static int reload_config(enum channelreloadreason reason) } else if (!strcasecmp(v->name, "directrtpsetup")) { sip_cfg.directrtpsetup = ast_true(v->value); } else if (!strcasecmp(v->name, "notifyringing")) { - sip_cfg.notifyringing = ast_true(v->value); + if (!strcasecmp(v->value, "notinuse")) { + sip_cfg.notifyringing = NOTIFYRINGING_NOTINUSE; + } else { + sip_cfg.notifyringing = ast_true(v->value) ? NOTIFYRINGING_ENABLED : NOTIFYRINGING_DISABLED; + } } else if (!strcasecmp(v->name, "notifyhold")) { sip_cfg.notifyhold = ast_true(v->value); } else if (!strcasecmp(v->name, "notifycid")) { diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 87b59f66155..d60f49ecbe9 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -211,7 +211,7 @@ #define DEFAULT_ALLOW_EXT_DOM TRUE /*!< Allow external domains */ #define DEFAULT_REALM "asterisk" /*!< Realm for HTTP digest authentication */ #define DEFAULT_DOMAINSASREALM FALSE /*!< Use the domain option to guess the realm for registration and invite requests */ -#define DEFAULT_NOTIFYRINGING TRUE /*!< Notify devicestate system on ringing state */ +#define DEFAULT_NOTIFYRINGING NOTIFYRINGING_ENABLED /*!< Notify devicestate system on ringing state */ #define DEFAULT_NOTIFYCID DISABLED /*!< Include CID with ringing notifications */ #define DEFAULT_PEDANTIC TRUE /*!< Follow SIP standards for dialog matching */ #define DEFAULT_AUTOCREATEPEER AUTOPEERS_DISABLED /*!< Don't create peers automagically */ @@ -622,6 +622,13 @@ enum sipmethod { SIP_PING, /*!< Not supported at all, no standard but still implemented out there */ }; +/*! \brief Setting for the 'notifyringing' option, see sip.conf.sample for details. */ +enum notifyringing_setting { + NOTIFYRINGING_DISABLED = 0, + NOTIFYRINGING_ENABLED = 1, + NOTIFYRINGING_NOTINUSE = 2, +}; + /*! \brief Settings for the 'notifycid' option, see sip.conf.sample for details. */ enum notifycid_setting { DISABLED = 0, diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample index 0fc5af2ea63..fe685141af6 100644 --- a/configs/samples/sip.conf.sample +++ b/configs/samples/sip.conf.sample @@ -694,8 +694,12 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;subscribecontext = default ; Set a specific context for SUBSCRIBE requests ; Useful to limit subscriptions to local extensions ; Settable per peer/user also -;notifyringing = no ; Control whether subscriptions already INUSE get sent - ; RINGING when another call is sent (default: yes) +;notifyringing = no ; Control when subscriptions get notified of ringing state. + ; Specify 'no' to not send any ringing notifications. + ; Specify 'yes' to always send ringing notifications (default). + ; Specify 'notinuse' to only send ringing notifications for + ; extensions that are not currently in use. This is useful as a + ; visual indication of who is available to pick up an incoming call ;notifyhold = yes ; Notify subscriptions on HOLD state (default: no) ; Turning on notifyringing and notifyhold will add a lot ; more database transactions if you are using realtime. From 6b08f01c60dc73d8b2b27f7d4cbc9c0b9b2f6fd6 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sun, 27 Dec 2015 23:38:37 -0500 Subject: [PATCH 0093/1578] Remove res_jabber file that was left behind. Change-Id: I9d88fac0394d5bbaff0900a2ee911c4e4478846b --- res/res_jabber.exports.in | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 res/res_jabber.exports.in diff --git a/res/res_jabber.exports.in b/res/res_jabber.exports.in deleted file mode 100644 index 926f24259b3..00000000000 --- a/res/res_jabber.exports.in +++ /dev/null @@ -1,16 +0,0 @@ -{ - global: - LINKER_SYMBOL_PREFIXast_aji_create_chat; - LINKER_SYMBOL_PREFIXast_aji_disconnect; - LINKER_SYMBOL_PREFIXast_aji_get_client; - LINKER_SYMBOL_PREFIXast_aji_get_clients; - LINKER_SYMBOL_PREFIXast_aji_increment_mid; - LINKER_SYMBOL_PREFIXast_aji_invite_chat; - LINKER_SYMBOL_PREFIXast_aji_join_chat; - LINKER_SYMBOL_PREFIXast_aji_send; - LINKER_SYMBOL_PREFIXast_aji_send_chat; - LINKER_SYMBOL_PREFIXast_aji_client_destroy; - LINKER_SYMBOL_PREFIXast_aji_buddy_destroy; - local: - *; -}; From 22db16fa8143bc669de1037462f23ed93b8f1043 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 27 May 2015 12:22:39 -0600 Subject: [PATCH 0094/1578] endpoint/stasis: Eliminate duplicate events on endpoint status change When an endpoint is created, its messages are forwarded to both the tech endpoint topic and the all endpoints topic. This is done so that various parties interested in endpoint messages can subscribe to just the tech endpoint and receive all messages associated with that particular technology, as opposed to subscribing to the all endpoints topic. Unfortunately, when the tech endpoint is created, it also forwards all of its messages to the all topic. This results in duplicate messages whenever an endpoint publishes its messages. This patch resolves the duplicate message issue by creating a new function for Stasis caching topics, stasis_cp_sink_create. In most respects, this acts as a normal caching topic, save that it no longer forwards messages it receives to the all endpoints topic. This allows it to act as an aggregation "sink", while preserving the necessary caching behaviour. ASTERISK-25137 #close Reported-by: Vitezslav Novy ASTERISK-25116 #close Reported-by: George Joseph Tested-by: George Joseph Change-Id: Ie47784adfb973ab0063e59fc18f390d7dd26d17b --- include/asterisk/stasis_cache_pattern.h | 19 ++++++++++++++ main/endpoints.c | 20 ++++++++++----- main/stasis_cache_pattern.c | 34 +++++++++++++++++-------- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/include/asterisk/stasis_cache_pattern.h b/include/asterisk/stasis_cache_pattern.h index 2ea643e192f..e61d3e931cf 100644 --- a/include/asterisk/stasis_cache_pattern.h +++ b/include/asterisk/stasis_cache_pattern.h @@ -109,6 +109,8 @@ struct stasis_cp_single; /*! * \brief Create the 'one' side of the cache pattern. * + * Create the 'one' and forward to all's topic and topic_cached. + * * Dispose of using stasis_cp_single_unsubscribe(). * * \param all Corresponding all side. @@ -118,6 +120,23 @@ struct stasis_cp_single; struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all, const char *name); +/*! + * \brief Create a sink in the cache pattern + * + * Create the 'one' but do not automatically forward to the all's topic. + * This is useful when aggregating other topic's messages created with + * \c stasis_cp_single_create in another caching topic without replicating + * those messages in the all's topics. + * + * Dispose of using stasis_cp_single_unsubscribe(). + * + * \param all Corresponding all side. + * \param name Base name for the topics. + * \return One side instance + */ +struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all, + const char *name); + /*! * \brief Stops caching and forwarding messages. * diff --git a/main/endpoints.c b/main/endpoints.c index 21326561ce9..b73edd379a6 100644 --- a/main/endpoints.c +++ b/main/endpoints.c @@ -303,13 +303,14 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha return NULL; } - endpoint->topics = stasis_cp_single_create(ast_endpoint_cache_all(), - endpoint->id); - if (!endpoint->topics) { - return NULL; - } - if (!ast_strlen_zero(resource)) { + + endpoint->topics = stasis_cp_single_create(ast_endpoint_cache_all(), + endpoint->id); + if (!endpoint->topics) { + return NULL; + } + endpoint->router = stasis_message_router_create_pool(ast_endpoint_topic(endpoint)); if (!endpoint->router) { return NULL; @@ -325,9 +326,16 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha endpoint->tech_forward = stasis_forward_all(stasis_cp_single_topic(endpoint->topics), stasis_cp_single_topic(tech_endpoint->topics)); + endpoint_publish_snapshot(endpoint); ao2_link(endpoints, endpoint); } else { + endpoint->topics = stasis_cp_sink_create(ast_endpoint_cache_all(), + endpoint->id); + if (!endpoint->topics) { + return NULL; + } + ao2_link(tech_endpoints, endpoint); } diff --git a/main/stasis_cache_pattern.c b/main/stasis_cache_pattern.c index bbe63ba1de4..66563c4c6d6 100644 --- a/main/stasis_cache_pattern.c +++ b/main/stasis_cache_pattern.c @@ -138,20 +138,11 @@ struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all, { RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup); - one = ao2_t_alloc(sizeof(*one), one_dtor, name); + one = stasis_cp_sink_create(all, name); if (!one) { return NULL; } - one->topic = stasis_topic_create(name); - if (!one->topic) { - return NULL; - } - one->topic_cached = stasis_caching_topic_create(one->topic, all->cache); - if (!one->topic_cached) { - return NULL; - } - one->forward_topic_to_all = stasis_forward_all(one->topic, all->topic); if (!one->forward_topic_to_all) { return NULL; @@ -166,6 +157,29 @@ struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all, return one; } +struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all, + const char *name) +{ + RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup); + + one = ao2_t_alloc(sizeof(*one), one_dtor, name); + if (!one) { + return NULL; + } + + one->topic = stasis_topic_create(name); + if (!one->topic) { + return NULL; + } + one->topic_cached = stasis_caching_topic_create(one->topic, all->cache); + if (!one->topic_cached) { + return NULL; + } + + ao2_ref(one, +1); + return one; +} + void stasis_cp_single_unsubscribe(struct stasis_cp_single *one) { if (!one) { From 3bddcc0219bbe18ae925e1d41301fa9001530804 Mon Sep 17 00:00:00 2001 From: Dade Brandon Date: Thu, 24 Dec 2015 20:19:59 -0800 Subject: [PATCH 0095/1578] res_http_websocket.c: prevent avoidable disconnections caused by write errors Updated ast_websocket_write to encode the entire frame in to one write operation, to ensure that we don't end up with a situation where the websocket header has been sent, while the body can not be written. Previous to August's patch in commit b9bd3c14, certain network conditions could cause the header to be written, and then the sub-sequent body to fail - which would cause the next successful write to contain a new header, and a new body (resulting in the peer receiving two headers - the second of which would be read as part of the body for the first header). This was patched to have both write operations individually fail by closing the websocket. In a case available to the submitter of this patch, the same body which would consistently fail to write, would succeed if written at the same time as the header. This update merges the two operations in to one, adds debug messages indicating the reason for a websocket connection being closed during a write operation, and clarifies some variable names for code legibility. Change-Id: I4db7a586af1c7a57184c31d3d55bf146f1a40598 --- include/asterisk/http_websocket.h | 4 ++-- res/res_http_websocket.c | 33 ++++++++++++++++--------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h index 23492ff9556..cd49dbe4825 100644 --- a/include/asterisk/http_websocket.h +++ b/include/asterisk/http_websocket.h @@ -266,12 +266,12 @@ AST_OPTIONAL_API(int, ast_websocket_read_string, * \param session Pointer to the WebSocket session * \param opcode WebSocket operation code to place in the frame * \param payload Optional pointer to a payload to add to the frame - * \param actual_length Length of the payload (0 if no payload) + * \param payload_size Length of the payload (0 if no payload) * * \retval 0 if successfully written * \retval -1 if error occurred */ -AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), { errno = ENOSYS; return -1;}); +AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size), { errno = ENOSYS; return -1;}); /*! * \brief Construct and transmit a WebSocket frame containing string data. diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index c40aae6d279..2654578549c 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -332,18 +332,19 @@ static const char *websocket_opcode2str(enum ast_websocket_opcode opcode) } /*! \brief Write function for websocket traffic */ -int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length) +int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size) { size_t header_size = 2; /* The minimum size of a websocket frame is 2 bytes */ char *frame; uint64_t length; + uint64_t frame_size; ast_debug(3, "Writing websocket %s frame, length %" PRIu64 "\n", - websocket_opcode2str(opcode), actual_length); + websocket_opcode2str(opcode), payload_size); - if (actual_length < 126) { - length = actual_length; - } else if (actual_length < (1 << 16)) { + if (payload_size < 126) { + length = payload_size; + } else if (payload_size < (1 << 16)) { length = 126; /* We need an additional 2 bytes to store the extended length */ header_size += 2; @@ -353,37 +354,37 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en header_size += 8; } - frame = ast_alloca(header_size); - memset(frame, 0, header_size); + frame_size = header_size + payload_size; + + frame = ast_alloca(frame_size + 1); + memset(frame, 0, frame_size + 1); frame[0] = opcode | 0x80; frame[1] = length; /* Use the additional available bytes to store the length */ if (length == 126) { - put_unaligned_uint16(&frame[2], htons(actual_length)); + put_unaligned_uint16(&frame[2], htons(payload_size)); } else if (length == 127) { - put_unaligned_uint64(&frame[2], htonll(actual_length)); + put_unaligned_uint64(&frame[2], htonll(payload_size)); } + memcpy(&frame[header_size], payload, payload_size); + ao2_lock(session); if (session->closing) { ao2_unlock(session); return -1; } - if (ast_careful_fwrite(session->f, session->fd, frame, header_size, session->timeout)) { - ao2_unlock(session); - /* 1011 - server terminating connection due to not being able to fulfill the request */ - ast_websocket_close(session, 1011); - return -1; - } - if (ast_careful_fwrite(session->f, session->fd, payload, actual_length, session->timeout)) { + if (ast_careful_fwrite(session->f, session->fd, frame, frame_size, session->timeout)) { ao2_unlock(session); /* 1011 - server terminating connection due to not being able to fulfill the request */ + ast_debug(1, "Closing WS with 1011 because we can't fulfill a write request\n"); ast_websocket_close(session, 1011); return -1; } + fflush(session->f); ao2_unlock(session); From 96b32e0321bf37322c85bc57721903dc4a3cc968 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 24 Dec 2015 20:26:46 -0600 Subject: [PATCH 0096/1578] tests/test_stasis_endpoints: Remove expected duplicate events The cache_clear test was written to expect duplicate Stasis messages sent from the technology endpoint to the all caching topic. This patch fixes the test to no longer expect these duplicate messages. ASTERISK-25137 Change-Id: I58075d70d6cdf42e792e0fb63ba624720bfce981 --- tests/test_stasis_endpoints.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_stasis_endpoints.c b/tests/test_stasis_endpoints.c index 848d86b1c50..6e972758899 100644 --- a/tests/test_stasis_endpoints.c +++ b/tests/test_stasis_endpoints.c @@ -186,9 +186,10 @@ AST_TEST_DEFINE(cache_clear) /* Note: there's a few messages between the creation and the clear. * Wait for all of them... */ - message_index = stasis_message_sink_wait_for(sink, message_index + 4, + message_index = stasis_message_sink_wait_for(sink, message_index + 2, cache_update, __func__, STASIS_SINK_DEFAULT_WAIT); ast_test_validate(test, 0 <= message_index); + /* Now we should have a cache removal entry */ msg = sink->messages[message_index]; type = stasis_message_type(msg); From a05bb258b15455dedf282be0baae5dc3098442c1 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 28 Dec 2015 16:02:19 -0400 Subject: [PATCH 0097/1578] test_time: Provide a timeout when waiting. The test_timezone_watch unit test is written to expect a condition to be signaled when the inotify daemon thread runs. There exists a small window where the test_timezone_watch thread can signal the inotify daemon thread while it is not reading on the underlying file descriptor. If this occurs the test_timezone_watch thread will wait indefinitely for a signal that will never arrive. This change adds a timeout to the condition so it will return regardless after a period of time. Change-Id: Ifed981879df6de3d93acd3ee0a70f92546517390 --- main/stdtime/localtime.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main/stdtime/localtime.c b/main/stdtime/localtime.c index 927d473fd30..c10b7af6232 100644 --- a/main/stdtime/localtime.c +++ b/main/stdtime/localtime.c @@ -796,13 +796,16 @@ static void sstate_free(struct state *p) void ast_localtime_wakeup_monitor(struct ast_test *info) { + struct timeval wait_now = ast_tvnow(); + struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 2, .tv_nsec = wait_now.tv_usec * 1000 }; + if (inotify_thread != AST_PTHREADT_NULL) { AST_LIST_LOCK(&zonelist); #ifdef TEST_FRAMEWORK test = info; #endif pthread_kill(inotify_thread, SIGURG); - ast_cond_wait(&initialization, &(&zonelist)->lock); + ast_cond_timedwait(&initialization, &(&zonelist)->lock, &wait_time); #ifdef TEST_FRAMEWORK test = NULL; #endif From 5e67e51c6ae6a89f0d011809940da6c90e281e4d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 28 Dec 2015 18:18:01 -0700 Subject: [PATCH 0098/1578] main/pbx: Move pbx_builtin dialplan applications to pbx_builtins.c We joked about splitting pbx.c into multiple files but this first step was fairly easy. All of the pbx_builtin dialplan applications have been moved into pbx_builtins.c and a new pbx_private.h file was added. load_pbx_builtins() is called by asterisk.c just after load_pbx(). A few functions were renamed and are cross-exposed between the 2 source files. Change-Id: I87066be3dbf7f5822942ac1449d98cc43fc7561a --- include/asterisk/_private.h | 1 + main/asterisk.c | 5 + main/pbx.c | 1526 +---------------------------------- main/pbx_builtins.c | 1500 ++++++++++++++++++++++++++++++++++ main/pbx_private.h | 37 + 5 files changed, 1572 insertions(+), 1497 deletions(-) create mode 100644 main/pbx_builtins.c create mode 100644 main/pbx_private.h diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 2966f8787ce..e58828c39d0 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -17,6 +17,7 @@ int load_modules(unsigned int); /*!< Provided by loader.c */ int load_pbx(void); /*!< Provided by pbx.c */ +int load_pbx_builtins(void); /*!< Provided by pbx_builtins.c */ int init_logger(void); /*!< Provided by logger.c */ void close_logger(void); /*!< Provided by logger.c */ void logger_queue_start(void); /*!< Provided by logger.c */ diff --git a/main/asterisk.c b/main/asterisk.c index 93937afa974..a72e249e005 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4595,6 +4595,11 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou exit(1); } + if (load_pbx_builtins()) { + printf("Failed: load_pbx_builtins\n%s", term_quit()); + exit(1); + } + if (ast_local_init()) { printf("Failed: ast_local_init\n%s", term_quit()); exit(1); diff --git a/main/pbx.c b/main/pbx.c index 202940e1160..c54eca81df4 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -73,6 +73,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_channels.h" #include "asterisk/dial.h" #include "asterisk/vector.h" +#include "pbx_private.h" /*! * \note I M P O R T A N T : @@ -96,637 +97,6 @@ ASTERISK_REGISTER_FILE() */ /*** DOCUMENTATION - - - Answer a channel if ringing. - - - - Asterisk will wait this number of milliseconds before returning to - the dialplan after answering the call. - - - - If the call has not been answered, this application will - answer it. Otherwise, it has no effect on the call. - - - Hangup - - - - - Play an audio file while waiting for digits of an extension to go to. - - - - - - - - - - - - - - - Explicitly specifies which language to attempt to use for the requested sound files. - - - This is the dialplan context that this application will use when exiting - to a dialed extension. - - - - This application will play the given list of files (do not put extension) - while waiting for an extension to be dialed by the calling channel. To continue waiting - for digits after this application has finished playing files, the WaitExten - application should be used. - If one of the requested sound files does not exist, call processing will be terminated. - This application sets the following channel variable upon completion: - - - The status of the background attempt as a text string. - - - - - - - ControlPlayback - WaitExten - BackgroundDetect - TIMEOUT - - - - - Indicate the Busy condition. - - - - If specified, the calling channel will be hung up after the specified number of seconds. - Otherwise, this application will wait until the calling channel hangs up. - - - - This application will indicate the busy condition to the calling channel. - - - Congestion - Progress - Playtones - Hangup - - - - - Indicate the Congestion condition. - - - - If specified, the calling channel will be hung up after the specified number of seconds. - Otherwise, this application will wait until the calling channel hangs up. - - - - This application will indicate the congestion condition to the calling channel. - - - Busy - Progress - Playtones - Hangup - - - - - Conditional application execution based on the current time. - - - - - - - - - - - - - - - This application will execute the specified dialplan application, with optional - arguments, if the current time matches the given time specification. - - - Exec - ExecIf - TryExec - GotoIfTime - - - - - Jump to a particular priority, extension, or context. - - - - - - - - This application will set the current context, extension, and priority in the channel structure. - After it completes, the pbx engine will continue dialplan execution at the specified location. - If no specific extension, or extension and - context, are specified, then this application will - just set the specified priority of the current extension. - At least a priority is required as an argument, or the goto will - return a -1, and the channel and call will be terminated. - If the location that is put into the channel information is bogus, and asterisk cannot - find that location in the dialplan, then the execution engine will try to find and execute the code in - the i (invalid) extension in the current context. If that does not exist, it will try to execute the - h extension. If neither the h nor i extensions - have been defined, the channel is hung up, and the execution of instructions on the channel is terminated. - What this means is that, for example, you specify a context that does not exist, then - it will not be possible to find the h or i extensions, - and the call will terminate! - - - GotoIf - GotoIfTime - Gosub - Macro - - - - - Conditional goto. - - - - - - Continue at labeliftrue if the condition is true. - Takes the form similar to Goto() of [[context,]extension,]priority. - - - Continue at labeliffalse if the condition is false. - Takes the form similar to Goto() of [[context,]extension,]priority. - - - - - This application will set the current context, extension, and priority in the channel structure - based on the evaluation of the given condition. After this application completes, the - pbx engine will continue dialplan execution at the specified location in the dialplan. - The labels are specified with the same syntax as used within the Goto application. - If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the - next instruction. If the target location is bogus, and does not exist, the execution engine will try - to find and execute the code in the i (invalid) extension in the current context. - If that does not exist, it will try to execute the h extension. - If neither the h nor i extensions have been defined, - the channel is hung up, and the execution of instructions on the channel is terminated. - Remember that this command can set the current context, and if the context specified - does not exist, then it will not be able to find any 'h' or 'i' extensions there, and - the channel and call will both be terminated!. - - - Goto - GotoIfTime - GosubIf - MacroIf - - - - - Conditional Goto based on the current time. - - - - - - - - - - - - Continue at labeliftrue if the condition is true. - Takes the form similar to Goto() of [[context,]extension,]priority. - - - Continue at labeliffalse if the condition is false. - Takes the form similar to Goto() of [[context,]extension,]priority. - - - - - This application will set the context, extension, and priority in the channel structure - based on the evaluation of the given time specification. After this application completes, - the pbx engine will continue dialplan execution at the specified location in the dialplan. - If the current time is within the given time specification, the channel will continue at - labeliftrue. Otherwise the channel will continue at labeliffalse. - If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next - instruction. If the target jump location is bogus, the same actions would be taken as for Goto. - Further information on the time specification can be found in examples - illustrating how to do time-based context includes in the dialplan. - - - GotoIf - Goto - IFTIME - TESTTIME - - - - - Import a variable from a channel into a new variable. - - - - - - - - - - This application imports a variable from the specified - channel (as opposed to the current one) and stores it as a variable - (newvar) in the current channel (the channel that is calling this - application). Variables created by this application have the same inheritance properties as those - created with the Set application. - - - Set - - - - - Hang up the calling channel. - - - - If a causecode is given the channel's - hangup cause will be set to the given value. - - - - This application will hang up the calling channel. - - - Answer - Busy - Congestion - - - - - Returns AST_PBX_INCOMPLETE value. - - - - If specified, then Incomplete will not attempt to answer the channel first. - Most channel types need to be in Answer state in order to receive DTMF. - - - - Signals the PBX routines that the previous matched extension is incomplete - and that further input should be allowed before matching can be considered - to be complete. Can be used within a pattern match when certain criteria warrants - a longer match. - - - - - Do Nothing (No Operation). - - - - Any text provided can be viewed at the Asterisk CLI. - - - - This application does nothing. However, it is useful for debugging purposes. - This method can be used to see the evaluations of variables or functions without having any effect. - - - Verbose - Log - - - - - Indicate proceeding. - - - - This application will request that a proceeding message be provided to the calling channel. - - - - - Indicate progress. - - - - This application will request that in-band progress information be provided to the calling channel. - - - Busy - Congestion - Ringing - Playtones - - - - - Handle an exceptional condition. - - - - - - This application will jump to the e extension in the current context, setting the - dialplan function EXCEPTION(). If the e extension does not exist, the call will hangup. - - - Exception - - - - - Indicate ringing tone. - - - - This application will request that the channel indicate a ringing tone to the user. - - - Busy - Congestion - Progress - Playtones - - - - - Say Alpha. - - - - - - This application will play the sounds that correspond to the letters - of the given string. If the channel variable - SAY_DTMF_INTERRUPT is set to 'true' (case insensitive), - then this application will react to DTMF in the same way as - Background. - - - SayDigits - SayNumber - SayPhonetic - CHANNEL - - - - - Say Alpha. - - - - - - Case sensitive (all) pronunciation. - (Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c). - - - Case sensitive (lower) pronunciation. - (Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c). - - - Case insensitive pronunciation. Equivalent to SayAlpha. - (Ex: SayAlphaCase(n,aBc) - a b c). - - - Case sensitive (upper) pronunciation. - (Ex: SayAlphaCase(u,aBc); - a uppercase b c). - - - - - - - This application will play the sounds that correspond to the letters of the - given string. Optionally, a casetype may be - specified. This will be used for case-insensitive or case-sensitive pronunciations. If the channel - variable SAY_DTMF_INTERRUPT is set to 'true' (case insensitive), then this - application will react to DTMF in the same way as Background. - - - SayDigits - SayNumber - SayPhonetic - SayAlpha - CHANNEL - - - - - Say Digits. - - - - - - This application will play the sounds that correspond to the digits of - the given number. This will use the language that is currently set for the channel. - If the channel variable SAY_DTMF_INTERRUPT is set to 'true' - (case insensitive), then this application will react to DTMF in the same way as - Background. - - - SayAlpha - SayNumber - SayPhonetic - CHANNEL - - - - - Say Number. - - - - - - - This application will play the sounds that correspond to the given - digits. Optionally, a gender may be - specified. This will use the language that is currently set for the channel. See the CHANNEL() - function for more information on setting the language for the channel. If the channel variable - SAY_DTMF_INTERRUPT is set to 'true' (case insensitive), then this - application will react to DTMF in the same way as Background. - - - SayAlpha - SayDigits - SayPhonetic - CHANNEL - - - - - Say Phonetic. - - - - - - This application will play the sounds from the phonetic alphabet that correspond to the - letters in the given string. If the channel variable - SAY_DTMF_INTERRUPT is set to 'true' (case insensitive), then this - application will react to DTMF in the same way as Background. - - - SayAlpha - SayDigits - SayNumber - - - - - Set channel variable or function value. - - - - - - - This function can be used to set the value of channel variables or dialplan functions. - When setting variables, if the variable name is prefixed with _, - the variable will be inherited into channels created from the current channel. - If the variable name is prefixed with __, the variable will be - inherited into channels created from the current channel and all children channels. - If (and only if), in /etc/asterisk/asterisk.conf, you have - a [compat] category, and you have app_set = 1.4 under that, then - the behavior of this app changes, and strips surrounding quotes from the right hand side as - it did previously in 1.4. - The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar) - were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly - protect separators and quotes in various database access strings has been greatly - reduced by these changes. - - - MSet - GLOBAL - SET - ENV - - - - - Set channel variable(s) or function value(s). - - - - - - - - - - - - - This function can be used to set the value of channel variables or dialplan functions. - When setting variables, if the variable name is prefixed with _, - the variable will be inherited into channels created from the current channel - If the variable name is prefixed with __, the variable will be - inherited into channels created from the current channel and all children channels. - MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus - prone to doing things that you may not expect. For example, it strips surrounding - double-quotes from the right-hand side (value). If you need to put a separator - character (comma or vert-bar), you will need to escape them by inserting a backslash - before them. Avoid its use if possible. - - - Set - - - - - Set the AMA Flags. - - - - - - This application will set the channel's AMA Flags for billing purposes. - This application is deprecated. Please use the CHANNEL function instead. - - - CDR - CHANNEL - - - - - Waits for some time. - - - - Can be passed with fractions of a second. For example, 1.5 will ask the - application to wait for 1.5 seconds. - - - - This application waits for a specified number of seconds. - - - - - Waits for an extension to be entered. - - - - Can be passed with fractions of a second. For example, 1.5 will ask the - application to wait for 1.5 seconds. - - - - - - - - - This application waits for the user to enter a new extension for a specified number - of seconds. - - - - Background - TIMEOUT - - Retrieve the details of the current dialplan exception. @@ -850,32 +220,10 @@ ASTERISK_REGISTER_FILE() #define SWITCH_DATA_LENGTH 256 -#define VAR_BUF_SIZE 4096 - #define VAR_NORMAL 1 #define VAR_SOFTTRAN 2 #define VAR_HARDTRAN 3 -#define BACKGROUND_SKIP (1 << 0) -#define BACKGROUND_NOANSWER (1 << 1) -#define BACKGROUND_MATCHEXTEN (1 << 2) -#define BACKGROUND_PLAYBACK (1 << 3) - -AST_APP_OPTIONS(background_opts, { - AST_APP_OPTION('s', BACKGROUND_SKIP), - AST_APP_OPTION('n', BACKGROUND_NOANSWER), - AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN), - AST_APP_OPTION('p', BACKGROUND_PLAYBACK), -}); - -#define WAITEXTEN_MOH (1 << 0) -#define WAITEXTEN_DIALTONE (1 << 1) - -AST_APP_OPTIONS(waitexten_opts, { - AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0), - AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0), -}); - struct ast_context; struct ast_app; @@ -1263,34 +611,10 @@ struct pbx_exception { int priority; /*!< Priority associated with this exception */ }; -static int pbx_builtin_answer(struct ast_channel *, const char *); -static int pbx_builtin_goto(struct ast_channel *, const char *); -static int pbx_builtin_hangup(struct ast_channel *, const char *); -static int pbx_builtin_background(struct ast_channel *, const char *); -static int pbx_builtin_wait(struct ast_channel *, const char *); -static int pbx_builtin_waitexten(struct ast_channel *, const char *); -static int pbx_builtin_incomplete(struct ast_channel *, const char *); -static int pbx_builtin_setamaflags(struct ast_channel *, const char *); -static int pbx_builtin_ringing(struct ast_channel *, const char *); -static int pbx_builtin_proceeding(struct ast_channel *, const char *); -static int pbx_builtin_progress(struct ast_channel *, const char *); -static int pbx_builtin_congestion(struct ast_channel *, const char *); -static int pbx_builtin_busy(struct ast_channel *, const char *); -static int pbx_builtin_noop(struct ast_channel *, const char *); -static int pbx_builtin_gotoif(struct ast_channel *, const char *); -static int pbx_builtin_gotoiftime(struct ast_channel *, const char *); -static int pbx_builtin_execiftime(struct ast_channel *, const char *); -static int pbx_builtin_saynumber(struct ast_channel *, const char *); -static int pbx_builtin_saydigits(struct ast_channel *, const char *); -static int pbx_builtin_saycharacters(struct ast_channel *, const char *); -static int pbx_builtin_saycharacters_case(struct ast_channel *, const char *); -static int pbx_builtin_sayphonetic(struct ast_channel *, const char *); static int matchcid(const char *cidpattern, const char *callerid); #ifdef NEED_DEBUG static void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */ #endif -static int pbx_builtin_importvar(struct ast_channel *, const char *); -static void set_ext_pri(struct ast_channel *c, const char *exten, int pri); static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action); @@ -1442,43 +766,6 @@ static int totalcalls; */ static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function); -/*! \brief Declaration of builtin applications */ -static struct pbx_builtin { - char name[AST_MAX_APP]; - int (*execute)(struct ast_channel *chan, const char *data); -} builtins[] = -{ - /* These applications are built into the PBX core and do not - need separate modules */ - - { "Answer", pbx_builtin_answer }, - { "BackGround", pbx_builtin_background }, - { "Busy", pbx_builtin_busy }, - { "Congestion", pbx_builtin_congestion }, - { "ExecIfTime", pbx_builtin_execiftime }, - { "Goto", pbx_builtin_goto }, - { "GotoIf", pbx_builtin_gotoif }, - { "GotoIfTime", pbx_builtin_gotoiftime }, - { "ImportVar", pbx_builtin_importvar }, - { "Hangup", pbx_builtin_hangup }, - { "Incomplete", pbx_builtin_incomplete }, - { "NoOp", pbx_builtin_noop }, - { "Proceeding", pbx_builtin_proceeding }, - { "Progress", pbx_builtin_progress }, - { "RaiseException", pbx_builtin_raise_exception }, - { "Ringing", pbx_builtin_ringing }, - { "SayAlpha", pbx_builtin_saycharacters }, - { "SayAlphaCase", pbx_builtin_saycharacters_case }, - { "SayDigits", pbx_builtin_saydigits }, - { "SayNumber", pbx_builtin_saynumber }, - { "SayPhonetic", pbx_builtin_sayphonetic }, - { "Set", pbx_builtin_setvar }, - { "MSet", pbx_builtin_setvar_multiple }, - { "SetAMAFlags", pbx_builtin_setamaflags }, - { "Wait", pbx_builtin_wait }, - { "WaitExten", pbx_builtin_waitexten } -}; - static struct ast_context *contexts; static struct ast_hashtab *contexts_table = NULL; @@ -3822,7 +3109,7 @@ static const struct ast_datastore_info exception_store_info = { * \retval 0 on success. * \retval -1 on error. */ -static int raise_exception(struct ast_channel *chan, const char *reason, int priority) +int raise_exception(struct ast_channel *chan, const char *reason, int priority) { struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL); struct pbx_exception *exception = NULL; @@ -3848,12 +3135,6 @@ static int raise_exception(struct ast_channel *chan, const char *reason, int pri return 0; } -int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason) -{ - /* Priority will become 1, next time through the AUTOLOOP */ - return raise_exception(chan, reason, 0); -} - static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) { struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL); @@ -6463,7 +5744,7 @@ static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast } /*! helper function to set extension and priority */ -static void set_ext_pri(struct ast_channel *c, const char *exten, int pri) +void set_ext_pri(struct ast_channel *c, const char *exten, int pri) { ast_channel_lock(c); ast_channel_exten_set(c, exten); @@ -6723,11 +6004,11 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, status = "UNKNOWN"; ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status); if (!strcasecmp(status, "CONGESTION")) - res = pbx_builtin_congestion(c, "10"); + res = indicate_congestion(c, "10"); else if (!strcasecmp(status, "CHANUNAVAIL")) - res = pbx_builtin_congestion(c, "10"); + res = indicate_congestion(c, "10"); else if (!strcasecmp(status, "BUSY")) - res = pbx_builtin_busy(c, "10"); + res = indicate_busy(c, "10"); error = 1; /* XXX disable message */ break; /* exit from the 'for' loop */ } @@ -11047,7 +10328,7 @@ void ast_context_destroy(struct ast_context *con, const char *registrar) ast_unlock_contexts(); } -static void wait_for_hangup(struct ast_channel *chan, const void *data) +void wait_for_hangup(struct ast_channel *chan, const void *data) { int res; struct ast_frame *f; @@ -11070,211 +10351,29 @@ static void wait_for_hangup(struct ast_channel *chan, const void *data) } /*! - * \ingroup applications + * \ingroup functions */ -static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data) +static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value) { - ast_indicate(chan, AST_CONTROL_PROCEEDING); - return 0; -} - -/*! - * \ingroup applications - */ -static int pbx_builtin_progress(struct ast_channel *chan, const char *data) -{ - ast_indicate(chan, AST_CONTROL_PROGRESS); - return 0; -} - -/*! - * \ingroup applications - */ -static int pbx_builtin_ringing(struct ast_channel *chan, const char *data) -{ - ast_indicate(chan, AST_CONTROL_RINGING); - return 0; -} - -/*! - * \ingroup applications - */ -static int pbx_builtin_busy(struct ast_channel *chan, const char *data) -{ - ast_indicate(chan, AST_CONTROL_BUSY); - /* Don't change state of an UP channel, just indicate - busy in audio */ - ast_channel_lock(chan); - if (ast_channel_state(chan) != AST_STATE_UP) { - ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY); - ast_setstate(chan, AST_STATE_BUSY); - } - ast_channel_unlock(chan); - wait_for_hangup(chan, data); - return -1; -} - -/*! - * \ingroup applications - */ -static int pbx_builtin_congestion(struct ast_channel *chan, const char *data) -{ - ast_indicate(chan, AST_CONTROL_CONGESTION); - /* Don't change state of an UP channel, just indicate - congestion in audio */ - ast_channel_lock(chan); - if (ast_channel_state(chan) != AST_STATE_UP) { - ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION); - ast_setstate(chan, AST_STATE_BUSY); - } - ast_channel_unlock(chan); - wait_for_hangup(chan, data); - return -1; -} - -/*! - * \ingroup applications - */ -static int pbx_builtin_answer(struct ast_channel *chan, const char *data) -{ - int delay = 0; - char *parse; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(delay); - AST_APP_ARG(answer_cdr); - ); - - if (ast_strlen_zero(data)) { - return __ast_answer(chan, 0); - } - - parse = ast_strdupa(data); - - AST_STANDARD_APP_ARGS(args, parse); - - if (!ast_strlen_zero(args.delay) && (ast_channel_state(chan) != AST_STATE_UP)) - delay = atoi(data); - - if (delay < 0) { - delay = 0; - } - - if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) { - ast_log(AST_LOG_WARNING, "The nocdr option for the Answer application has been removed and is no longer supported.\n"); - } - - return __ast_answer(chan, delay); -} - -static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data) -{ - const char *options = data; - int answer = 1; - - /* Some channels can receive DTMF in unanswered state; some cannot */ - if (!ast_strlen_zero(options) && strchr(options, 'n')) { - answer = 0; - } - - /* If the channel is hungup, stop waiting */ - if (ast_check_hangup(chan)) { - return -1; - } else if (ast_channel_state(chan) != AST_STATE_UP && answer) { - __ast_answer(chan, 0); - } - - ast_indicate(chan, AST_CONTROL_INCOMPLETE); - - return AST_PBX_INCOMPLETE; -} - -/*! - * \ingroup applications - */ -static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data) -{ - ast_log(AST_LOG_WARNING, "The SetAMAFlags application is deprecated. Please use the CHANNEL function instead.\n"); - - if (ast_strlen_zero(data)) { - ast_log(AST_LOG_WARNING, "No parameter passed to SetAMAFlags\n"); - return 0; - } - /* Copy the AMA Flags as specified */ - ast_channel_lock(chan); - if (isdigit(data[0])) { - int amaflags; - if (sscanf(data, "%30d", &amaflags) != 1) { - ast_log(AST_LOG_WARNING, "Unable to set AMA flags on channel %s\n", ast_channel_name(chan)); - ast_channel_unlock(chan); - return 0; - } - ast_channel_amaflags_set(chan, amaflags); - } else { - ast_channel_amaflags_set(chan, ast_channel_string2amaflag(data)); - } - ast_channel_unlock(chan); - return 0; -} - -/*! - * \ingroup applications - */ -static int pbx_builtin_hangup(struct ast_channel *chan, const char *data) -{ - int cause; - - ast_set_hangupsource(chan, "dialplan/builtin", 0); - - if (!ast_strlen_zero(data)) { - cause = ast_str2cause(data); - if (cause <= 0) { - if (sscanf(data, "%30d", &cause) != 1 || cause <= 0) { - ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", data); - cause = 0; - } - } - } else { - cause = 0; - } - - ast_channel_lock(chan); - if (cause <= 0) { - cause = ast_channel_hangupcause(chan); - if (cause <= 0) { - cause = AST_CAUSE_NORMAL_CLEARING; - } - } - ast_channel_hangupcause_set(chan, cause); - ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT); - ast_channel_unlock(chan); - - return -1; -} - -/*! - * \ingroup functions - */ -static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value) -{ - struct ast_tm tm; - struct timeval tv; - char *remainder, result[30], timezone[80]; - - /* Turn off testing? */ - if (!pbx_checkcondition(value)) { - pbx_builtin_setvar_helper(chan, "TESTTIME", NULL); - return 0; - } - - /* Parse specified time */ - if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) { - return -1; - } - sscanf(remainder, "%79s", timezone); - tv = ast_mktime(&tm, S_OR(timezone, NULL)); - - snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec); - pbx_builtin_setvar_helper(chan, "__TESTTIME", result); + struct ast_tm tm; + struct timeval tv; + char *remainder, result[30], timezone[80]; + + /* Turn off testing? */ + if (!pbx_checkcondition(value)) { + pbx_builtin_setvar_helper(chan, "TESTTIME", NULL); + return 0; + } + + /* Parse specified time */ + if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) { + return -1; + } + sscanf(remainder, "%79s", timezone); + tv = ast_mktime(&tm, S_OR(timezone, NULL)); + + snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec); + pbx_builtin_setvar_helper(chan, "__TESTTIME", result); return 0; } @@ -11283,333 +10382,6 @@ static struct ast_custom_function testtime_function = { .write = testtime_write, }; -/*! - * \ingroup applications - */ -static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data) -{ - char *s, *ts, *branch1, *branch2, *branch; - struct ast_timing timing; - const char *ctime; - struct timeval tv = ast_tvnow(); - long timesecs; - - if (!chan) { - ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n"); - return -1; - } - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n + + Bind the RTP instance to the media_address + + If media_address is specified, this option causes the RTP instance to be bound to the + specified ip address which causes the packets to be sent from that address. + + + Force use of return port diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 72f896ad0c4..926bf3793cb 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1847,6 +1847,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.address)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bind_rtp_to_media_address", "no", OPT_BOOL_T, 1, STRFLDSET(struct ast_sip_endpoint, media.bind_rtp_to_media_address)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, ident_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.enabled)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, direct_media_method_to_str, NULL, 0, 0); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 1f2f21d7330..2a1f56ed495 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -175,8 +175,15 @@ static int rtp_check_timeout(const void *data) static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, unsigned int ipv6) { struct ast_rtp_engine_ice *ice; + struct ast_sockaddr temp_media_address; + struct ast_sockaddr *media_address = ipv6 ? &address_ipv6 : &address_ipv4; - if (!(session_media->rtp = ast_rtp_instance_new(session->endpoint->media.rtp.engine, sched, ipv6 ? &address_ipv6 : &address_ipv4, NULL))) { + if (session->endpoint->media.bind_rtp_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) { + ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0); + media_address = &temp_media_address; + } + + if (!(session_media->rtp = ast_rtp_instance_new(session->endpoint->media.rtp.engine, sched, media_address, NULL))) { ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", session->endpoint->media.rtp.engine); return -1; } From 01c5e2a07e5b08f2dd99523571d00735ee0cb89f Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 12 Jan 2016 10:36:15 -0600 Subject: [PATCH 0137/1578] res_sorcery_realtime: Remove leading ^ requirement. res_sorcery_realtime's search-by-regex callback performed a check to ensure that the passed-in regex began with a caret (^). If it did not, then no results would be returned. This callback only started to become used when "like" support was added to PJSIP CLI commands. The CLI command for listing objects would pass an empty regex ("") to the sorcery backend if no "like" statement was present. For most sorcery backends, this resulted in returning all objects. However, for realtime, this resulted in returning no objects. This commit seeks to fix the regression by removing the requirement from res_sorcery_realtime for the passed-in-regex to begin with a caret. ASTERISK-25689 #close Reported by Marcelo Terres Change-Id: I22b4dc5d7f3f11bb29ac2e42ef94682e9bab3b20 --- res/res_sorcery_realtime.c | 8 ++------ tests/test_sorcery_realtime.c | 10 +++------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index 8807c01961a..1a30e0c5908 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -218,16 +218,12 @@ static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex) { - char field[strlen(UUID_FIELD) + 6], value[strlen(regex) + 2]; + char field[strlen(UUID_FIELD) + 6], value[strlen(regex) + 3]; RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy); /* The realtime API provides no direct ability to do regex so for now we support a limited subset using pattern matching */ - if (regex[0] != '^') { - return; - } - snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); - snprintf(value, sizeof(value), "%s%%", regex + 1); + snprintf(value, sizeof(value), "%%%s%%", regex); if (!(fields = ast_variable_new(field, value, ""))) { return; diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c index 347280d897e..76dfb660359 100644 --- a/tests/test_sorcery_realtime.c +++ b/tests/test_sorcery_realtime.c @@ -67,17 +67,13 @@ static int realtime_is_object_matching(const char *object_id, const struct ast_v /* If we are doing a pattern matching we need to remove the LIKE from the name */ if ((like = strstr(name, " LIKE"))) { - char *pattern, *field_value = ast_strdupa(field->value); + char *field_value = ast_strdupa(field->value); *like = '\0'; value = ast_strdupa(ast_variable_retrieve(realtime_objects, object_id, name)); - if (!(pattern = strchr(field_value, '%'))) { - return 0; - } - - *pattern = '\0'; + field_value = ast_strip_quoted(field_value, "%", "%"); if (strncmp(value, field_value, strlen(field_value))) { return 0; @@ -567,7 +563,7 @@ AST_TEST_DEFINE(object_retrieve_regex) return AST_TEST_FAIL; } - if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) { + if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "blah-"))) { ast_test_status_update(test, "Failed to retrieve a container of objects\n"); return AST_TEST_FAIL; } else if (ao2_container_count(objects) != 2) { From 1fffe71f77ddcae415f47131fc629a914c1fdde0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 12 Jan 2016 14:25:09 -0600 Subject: [PATCH 0138/1578] res_pjsip_log_forwarder.c: Add CLI "pjsip show buildopts". PJPROJECT has a function available to dump the compile time options used when building the library. * Add CLI "pjsip show buildopts" command. * Update contrib/scripts/autosupport to get pjproject information. Change-Id: Id93a6a916d765b2a2e5a1aeb54caaf83206be748 --- contrib/scripts/autosupport | 12 ++++--- res/res_pjsip_log_forwarder.c | 61 +++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) mode change 100644 => 100755 contrib/scripts/autosupport diff --git a/contrib/scripts/autosupport b/contrib/scripts/autosupport old mode 100644 new mode 100755 index e41215f40b0..3e0213afe2f --- a/contrib/scripts/autosupport +++ b/contrib/scripts/autosupport @@ -3,7 +3,7 @@ # Autosupport Version 2.1.0 # Collect support information # -# Copyright (C) 2005-2013, Digium, Inc. +# Copyright (C) 2005-2016, Digium, Inc. # # Written by John Bigelow (support@digium.com) # Charles Moye (cmoye@digium.com) @@ -38,7 +38,7 @@ then -h | --help) echo echo "Digium autosupport script" - echo "Copyright (C) 2005-2013, Digium, Inc." + echo "Copyright (C) 2005-2016, Digium, Inc." echo "Licensed under the terms of the GNU General Public License" echo echo "usage: autosupport [prefix]" @@ -186,7 +186,9 @@ asterisk -V >> $OUTPUT; echo >> $OUTPUT; # Add check to see if asterisk is running. if [ -e /var/run/asterisk.ctl ] || [ -e /var/run/asterisk/asterisk.ctl ]; then - for command in "core show version" "pri show version" "dahdi show version" "core show translation" \ + for command in "core show version" "pri show version" "dahdi show version" \ + "pjsip show version" "pjsip show buildopts" \ + "core show translation" \ "core show uptime" "core show settings" "core show sysinfo" "core show channels" \ "pri show spans" "dahdi show status" "dahdi show channels" "dahdi show channel 1" \ "pjsip show endpoints" "pjsip show registrations" "pjsip list channels" \ @@ -194,9 +196,9 @@ if [ -e /var/run/asterisk.ctl ] || [ -e /var/run/asterisk/asterisk.ctl ]; then "show g729" "g729 show version" "g729 show licenses" "g729 show hostid" \ "digium_phones show version" "digium_phones show alerts" "digium_phones show applications" \ "digium_phones show firmwares" "digium_phones show lines" "digium_phones show networks" \ - "digium_phones show phones" "digium_phones show sessions" "digium_phones show settings" \ + "digium_phones show phones" "digium_phones show sessions" "digium_phones show settings" \ "digium_phones show translations" ; - do + do echo "asterisk -rx \"$command\"" >> $OUTPUT; asterisk -rx "$command" >> $OUTPUT; echo >> $OUTPUT; diff --git a/res/res_pjsip_log_forwarder.c b/res/res_pjsip_log_forwarder.c index 85ca9358c3c..c6b396afc5f 100644 --- a/res/res_pjsip_log_forwarder.c +++ b/res/res_pjsip_log_forwarder.c @@ -46,10 +46,24 @@ ASTERISK_REGISTER_FILE() #include "asterisk/logger.h" #include "asterisk/module.h" +#include "asterisk/cli.h" static pj_log_func *log_cb_orig; static unsigned decor_orig; +/*! Protection from other CLI instances. */ +AST_MUTEX_DEFINE_STATIC(show_buildopts_lock); + +struct pjsip_show_buildopts { + pthread_t thread; + int fd; +}; + +static struct pjsip_show_buildopts show_buildopts = { + .thread = AST_PTHREADT_NULL, + .fd = -1, +}; + static void log_cb(int level, const char *data, int len) { int ast_level; @@ -59,6 +73,15 @@ static void log_cb(int level, const char *data, int len) const char *log_func = ""; int mod_level; + if (show_buildopts.fd != -1 && show_buildopts.thread == pthread_self()) { + /* + * We are handling the CLI command dumping the + * PJPROJECT compile time config option settings. + */ + ast_cli(show_buildopts.fd, "%s\n", data); + return; + } + /* Lower number indicates higher importance */ switch (level) { case 0: /* level zero indicates fatal error, according to docs */ @@ -86,6 +109,40 @@ static void log_cb(int level, const char *data, int len) ast_log(ast_level, log_source, log_line, log_func, "\t%s\n", data); } +static char *handle_pjsip_show_buildopts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch(cmd) { + case CLI_INIT: + e->command = "pjsip show buildopts"; + e->usage = + "Usage: pjsip show buildopts\n" + " Show the compile time config of pjproject that res_pjsip is\n" + " running against.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + ast_cli(a->fd, "PJPROJECT compile time config currently running against:\n"); + + /* Protect from other CLI instances trying to do this at the same time. */ + ast_mutex_lock(&show_buildopts_lock); + + show_buildopts.thread = pthread_self(); + show_buildopts.fd = a->fd; + pj_dump_config(); + show_buildopts.fd = -1; + show_buildopts.thread = AST_PTHREADT_NULL; + + ast_mutex_unlock(&show_buildopts_lock); + + return CLI_SUCCESS; +} + +static struct ast_cli_entry pjsip_cli[] = { + AST_CLI_DEFINE(handle_pjsip_show_buildopts, "Show the compiled config of pjproject in use"), +}; + static int load_module(void) { pj_init(); @@ -102,11 +159,15 @@ static int load_module(void) pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT); pj_log_set_log_func(log_cb); + ast_cli_register_multiple(pjsip_cli, ARRAY_LEN(pjsip_cli)); + return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { + ast_cli_unregister_multiple(pjsip_cli, ARRAY_LEN(pjsip_cli)); + pj_log_set_log_func(log_cb_orig); pj_log_set_decor(decor_orig); From 79a7321a4762fc461e735f9c11b3b9799d1adb2e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 13 Jan 2016 08:20:24 -0500 Subject: [PATCH 0139/1578] res_musiconhold: Prevent multiple simultaneous reloads. There are two ways in which the reload() function in res_musiconhold can be called from the CLI: * module reload res_musiconhold.so * moh reload In the former case, the module loader holds a lock that prevents multiple concurrent calls, but in the latter there is no such protection. This patch changes the 'moh reload' CLI command to invoke the module loader directly, rather than call reload() explicitly. ASTERISK-25687 #close Change-Id: I408968b4c8932864411b7f9ad88cfdc7b9ba711c --- res/res_musiconhold.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index bf7635ea27f..4e5056358fb 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1808,7 +1808,8 @@ static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_ if (a->argc != e->args) return CLI_SHOWUSAGE; - reload(); + /* The module loader will prevent concurrent reloads from occurring, so we delegate */ + ast_module_reload("res_musiconhold"); return CLI_SUCCESS; } From 022423b98b6283185cf05e32520a201c5f263c55 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 12 Jan 2016 13:14:29 -0400 Subject: [PATCH 0140/1578] app: Queue hangup if channel is hung up during sub or macro execution. This issue was exposed when executing a connected line subroutine. When connected or redirected subroutines or macros are executed it is expected that the underlying applications and logic invoked are fast and do not consume frames. In practice this constraint is not enforced and if not adhered to will cause channels to continue when they shouldn't. This is because each caller of the connected or redirected logic does not check whether the channel has been hung up on return. As a result the the hung up channel continues. This change makes it so when the API to execute a subroutine or macro is invoked the channel is checked to determine if it has hung up. If it has then a hangup is queued again so the caller will see it and stop. ASTERISK-25690 #close Change-Id: I1f9a8ceb1487df0389f0d346ce0f6dcbcaf476ea --- main/app.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/main/app.c b/main/app.c index 36330ac118b..826e41128c9 100644 --- a/main/app.c +++ b/main/app.c @@ -357,6 +357,11 @@ int ast_app_exec_macro(struct ast_channel *autoservice_chan, struct ast_channel if (autoservice_chan) { ast_autoservice_stop(autoservice_chan); } + + if (ast_check_hangup_locked(macro_chan)) { + ast_queue_hangup(macro_chan); + } + return res; } @@ -433,6 +438,11 @@ int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *s if (autoservice_chan) { ast_autoservice_stop(autoservice_chan); } + + if (!ignore_hangup && ast_check_hangup_locked(sub_chan)) { + ast_queue_hangup(sub_chan); + } + return res; } From 8182146e850515084056acc9f3d7b0b6534af44e Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Sun, 10 Jan 2016 22:22:12 +0000 Subject: [PATCH 0141/1578] pjsip: Add option global/regcontext Added new global option (regcontext) to pjsip. When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given endpoint who registers or unregisters with us. ASTERISK-25670 #close Reported-by: Daniel Journo Change-Id: Ib1530c5b45340625805c057f8ff1fb240a43ea62 --- CHANGES | 7 ++++++ configs/samples/pjsip.conf.sample | 4 ++++ .../136885b81223_add_regcontext_to_pj.py | 20 ++++++++++++++++ include/asterisk/res_pjsip.h | 11 +++++++++ res/res_pjsip.c | 4 ++++ res/res_pjsip/config_global.c | 22 ++++++++++++++++++ res/res_pjsip/pjsip_configuration.c | 23 +++++++++++++++++++ 7 files changed, 91 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py diff --git a/CHANGES b/CHANGES index 6885c512adf..93ecf94c193 100644 --- a/CHANGES +++ b/CHANGES @@ -205,6 +205,13 @@ Queue --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ ------------------------------------------------------------------------------ +res_pjsip +------------------ + + * Added new global option (regcontext) to pjsip. When set, Asterisk will + dynamically create and destroy a NoOp priority 1 extension + for a given endpoint who registers or unregisters with us. + res_pjsip_history ------------------ * A new module, res_pjsip_history, has been added that provides SIP history diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index c8d7cc90e9a..363ef8557e2 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -896,6 +896,10 @@ ; startup that qualifies should be attempted on all ; contacts. If greater than the qualify_frequency ; for an aor, qualify_frequency will be used instead. +; If regcontext is specified, Asterisk will dynamically create and destroy a +; NoOp priority 1 extension for a given endpoint who registers or unregisters +; with us. The extension added is the name of the endpoint. +;regcontext=sipregistrations ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl ;==========================ACL SECTION OPTIONS========================= diff --git a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py new file mode 100644 index 00000000000..78accc32299 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py @@ -0,0 +1,20 @@ +"""add regcontext to pjsip + +Revision ID: 136885b81223 +Revises: 2d078ec071b7 +Create Date: 2016-01-11 22:32:45.470522 + +""" + +# revision identifiers, used by Alembic. +revision = '136885b81223' +down_revision = '2d078ec071b7' + +from alembic import op +import sqlalchemy as sa + +def upgrade(): + op.add_column('ps_globals', sa.Column('regcontext', sa.String(80))) + +def downgrade(): + op.drop_column('ps_globals', 'regcontext') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 0c82732833a..1ff361f5468 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2028,6 +2028,17 @@ void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement); */ char *ast_sip_get_debug(void); +/*! + * \brief Retrieve the global regcontext setting. + * + * \since 13.8.0 + * + * \note returned string needs to be de-allocated by caller. + * + * \retval the global regcontext setting + */ +char *ast_sip_get_regcontext(void); + /*! * \brief Retrieve the global endpoint_identifier_order setting. * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 90be734e678..b3c6773b482 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1282,6 +1282,10 @@ Value used in User-Agent header for SIP requests and Server header for SIP responses. + + When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given + peer who registers or unregisters with us. + Endpoint to use when sending an outbound request to a URI without a specified endpoint. diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index ef706f0b350..3d88ffc2a9a 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -35,6 +35,7 @@ #define DEFAULT_ENDPOINT_IDENTIFIER_ORDER "ip,username,anonymous" #define DEFAULT_MAX_INITIAL_QUALIFY_TIME 0 #define DEFAULT_FROM_USER "asterisk" +#define DEFAULT_REGCONTEXT "" static char default_useragent[256]; @@ -42,6 +43,7 @@ struct global_config { SORCERY_OBJECT(details); AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(useragent); + AST_STRING_FIELD(regcontext); AST_STRING_FIELD(default_outbound_endpoint); /*! Debug logging yes|no|host */ AST_STRING_FIELD(debug); @@ -137,6 +139,23 @@ char *ast_sip_get_debug(void) return res; } +char *ast_sip_get_regcontext(void) +{ + char *res; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return ast_strdup(DEFAULT_REGCONTEXT); + } + + res = ast_strdup(cfg->regcontext); + ao2_ref(cfg, -1); + + return res; +} + + char *ast_sip_get_endpoint_identifier_order(void) { char *res; @@ -310,6 +329,9 @@ int ast_sip_initialize_sorcery_global(void) OPT_UINT_T, 0, FLDSET(struct global_config, max_initial_qualify_time)); ast_sorcery_object_field_register(sorcery, "global", "default_from_user", DEFAULT_FROM_USER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_from_user)); + ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT, + OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); + if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 926bf3793cb..4afa9507d1a 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -21,6 +21,7 @@ #include "asterisk/callerid.h" #include "asterisk/test.h" #include "asterisk/statsd.h" +#include "asterisk/pbx.h" /*! \brief Number of buckets for persistent endpoint information */ #define PERSISTENT_BUCKETS 53 @@ -68,6 +69,7 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) struct ao2_iterator i; struct ast_sip_contact *contact; enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; + char *regcontext; if (status) { char rtt[32]; @@ -116,16 +118,37 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) return 0; } + regcontext = ast_sip_get_regcontext(); + if (state == AST_ENDPOINT_ONLINE) { ast_endpoint_set_state(endpoint, AST_ENDPOINT_ONLINE); blob = ast_json_pack("{s: s}", "peer_status", "Reachable"); + + if (!ast_strlen_zero(regcontext)) { + if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL)) { + ast_add_extension(regcontext, 1, ast_endpoint_get_resource(endpoint), 1, NULL, NULL, + "Noop", ast_strdup(ast_endpoint_get_resource(endpoint)), ast_free_ptr, "SIP"); + } + } + ast_verb(1, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint)); } else { ast_endpoint_set_state(endpoint, AST_ENDPOINT_OFFLINE); blob = ast_json_pack("{s: s}", "peer_status", "Unreachable"); + + if (!ast_strlen_zero(regcontext)) { + struct pbx_find_info q = { .stacklen = 0 }; + + if (pbx_find_extension(NULL, NULL, &q, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL, "", E_MATCH)) { + ast_context_remove_extension(regcontext, ast_endpoint_get_resource(endpoint), 1, NULL); + } + } + ast_verb(1, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint)); } + ast_free(regcontext); + ast_endpoint_blob_publish(endpoint, ast_endpoint_state_type(), blob); ast_json_unref(blob); ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint)); From 68cad96ffd5e81cd161325e81b5fa3e41b9b8a64 Mon Sep 17 00:00:00 2001 From: Rusty Newton Date: Thu, 14 Jan 2016 09:26:15 -0600 Subject: [PATCH 0142/1578] func_channel: Add help text for undocumented CHANNEL function arguments Adding help text documentation for: * hangupsource * appname * appdata * exten * context * channame * uniqueid * linkedid ASTERISK-24097 #close Reported by: Steven T. Wheeler Tested by: Rusty Newton Change-Id: Ib94b00568b0433987df87d5b67ea529b5905754d --- funcs/func_channel.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/funcs/func_channel.c b/funcs/func_channel.c index afe9796f6d0..39d7499c78f 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -208,6 +208,30 @@ ASTERISK_REGISTER_FILE() R/W whether or not context tracing is enabled, only available if CHANNEL_TRACE is defined. + + R/W returns the channel responsible for hangup. + + + R/O returns the internal application name. + + + R/O returns the application data if available. + + + R/O returns the extension for an outbound channel. + + + R/O returns the context for an outbound channel. + + + R/O returns the channel name for an outbound channel. + + + R/O returns the channel uniqueid. + + + R/O returns the linkedid if available, otherwise returns the uniqueid. + chan_sip provides the following additional options: From c7caee6c4b05c733f21f5fb6c723371820204be1 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 14 Jan 2016 15:36:10 -0500 Subject: [PATCH 0143/1578] Remove *.gcna / *.gcno files from added module sources. Asterisk uses a Makefile macro to associate additional sources with a module. This macro is responsible for creating clean targets but previously left behind *.gcna and *.gcno files. ASTERISK-25683 #close Reported by yaron nahum Change-Id: Idc0823fe80a25c42cefae901fde875e9fc38d8ea --- Makefile.moddir_rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules index df715d9875d..a92b0d82580 100644 --- a/Makefile.moddir_rules +++ b/Makefile.moddir_rules @@ -77,7 +77,7 @@ $$(subst $(3),$(5),$(2)): _ASTCFLAGS+=$$(call MOD_ASTCFLAGS,$(1)) clean:: clean-$(1)$(3) clean-$(1)$(3): - rm -f $$(subst $(3),$(5),$(2)) $$(subst $(3),$(4),$(2)) + rm -f $$(subst $(3),$(4),$(2)) $$(subst $(3),$(5),$(2)) $$(subst $(3),$(6),$(2)) $$(subst $(3),$(7),$(2)) endef From 84b30c5e18fa3395a1ec8e236038b8f525d3205a Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 14 Jan 2016 16:00:50 -0600 Subject: [PATCH 0144/1578] bridge_basic: don't play an attended transfer fail sound after target hangs up If the attended transfer destination answers (picks call up or goes to voicemail) and then hangs up on the transferer then transferer hears the fail sound. This patch makes it so the fail sound is not played when the transfer destination/target hangs up after answering. ASTERISK-25697 #close Change-Id: I97f142fe4fc2805d1a24b7c16143069dc03d9ded --- main/bridge_basic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main/bridge_basic.c b/main/bridge_basic.c index cd19915205a..47d838fcae5 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -2178,6 +2178,7 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro bridge_unhold(props->transferee_bridge); return TRANSFER_COMPLETE; case STIMULUS_TRANSFER_TARGET_HANGUP: + return TRANSFER_REBRIDGE; case STIMULUS_DTMF_ATXFER_ABORT: play_sound(props->transferer, props->failsound); return TRANSFER_REBRIDGE; From 0a878020dce6c3710c8a43cf613b6d3cdaa8386c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Jan 2016 18:20:57 -0600 Subject: [PATCH 0145/1578] astmm.c: Add more stats to CLI "memory show" commands. * Add freed regions totals to allocations and summary. * Add totals for all allocations and not just the selected allocations. Change-Id: I61d5a5112617b0733097f2545a3006a344b4032a --- main/astmm.c | 107 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 17 deletions(-) diff --git a/main/astmm.c b/main/astmm.c index 8260460ab3b..1599d107a7e 100644 --- a/main/astmm.c +++ b/main/astmm.c @@ -663,6 +663,32 @@ int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, return size; } +/*! + * \internal + * \brief Count the number of bytes in the specified freed region. + * + * \param freed Already freed region blocks storage. + * + * \note reglock must be locked before calling. + * + * \return Number of bytes in freed region. + */ +static size_t freed_regions_size(struct ast_freed_regions *freed) +{ + size_t total_len = 0; + int idx; + struct ast_region *old; + + for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) { + old = freed->regions[idx]; + if (old) { + total_len += old->len; + } + } + + return total_len; +} + static char *handle_memory_atexit_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { switch (cmd) { @@ -765,12 +791,54 @@ static char *handle_memory_atexit_summary(struct ast_cli_entry *e, int cmd, stru return CLI_SUCCESS; } +/*! + * \internal + * \brief Common summary output at the end of the memory show commands. + * + * \param fd CLI output file descriptor. + * \param whales_len Accumulated size of free large allocations. + * \param minnows_len Accumulated size of free small allocations. + * \param total_len Accumulated size of all current allocations. + * \param selected_len Accumulated size of the selected allocations. + * \param cache_len Accumulated size of the allocations that are part of a cache. + * \param count Number of selected allocations. + * + * \return Nothing + */ +static void print_memory_show_common_stats(int fd, + unsigned int whales_len, + unsigned int minnows_len, + unsigned int total_len, + unsigned int selected_len, + unsigned int cache_len, + unsigned int count) +{ + if (cache_len) { + ast_cli(fd, "%10u bytes allocated (%u in caches) in %u selected allocations\n\n", + selected_len, cache_len, count); + } else { + ast_cli(fd, "%10u bytes allocated in %u selected allocations\n\n", + selected_len, count); + } + + ast_cli(fd, "%10u bytes in all allocations\n", total_len); + ast_cli(fd, "%10u bytes in deferred free large allocations\n", whales_len); + ast_cli(fd, "%10u bytes in deferred free small allocations\n", minnows_len); + ast_cli(fd, "%10u bytes in deferred free allocations\n", + whales_len + minnows_len); + ast_cli(fd, "%10u bytes in all allocations and deferred free allocations\n", + total_len + whales_len + minnows_len); +} + static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { const char *fn = NULL; struct ast_region *reg; unsigned int idx; - unsigned int len = 0; + unsigned int whales_len; + unsigned int minnows_len; + unsigned int total_len = 0; + unsigned int selected_len = 0; unsigned int cache_len = 0; unsigned int count = 0; @@ -804,6 +872,7 @@ static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, st ast_mutex_lock(®lock); for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { + total_len += reg->len; if (fn && strcasecmp(fn, reg->file)) { continue; } @@ -814,21 +883,21 @@ static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, st (unsigned int) reg->len, reg->cache ? " (cache)" : "", reg->func, reg->lineno, reg->file); - len += reg->len; + selected_len += reg->len; if (reg->cache) { cache_len += reg->len; } ++count; } } + + whales_len = freed_regions_size(&whales); + minnows_len = freed_regions_size(&minnows); ast_mutex_unlock(®lock); - if (cache_len) { - ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n", - len, cache_len, count); - } else { - ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count); - } + print_memory_show_common_stats(a->fd, + whales_len, minnows_len, total_len, + selected_len, cache_len, count); return CLI_SUCCESS; } @@ -841,7 +910,10 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct int idx; int cmp; struct ast_region *reg; - unsigned int len = 0; + unsigned int whales_len; + unsigned int minnows_len; + unsigned int total_len = 0; + unsigned int selected_len = 0; unsigned int cache_len = 0; unsigned int count = 0; struct file_summary { @@ -859,7 +931,7 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct e->usage = "Usage: memory show summary []\n" " Summarizes heap memory allocations by file, or optionally\n" - " by line, if a file is specified.\n"; + " by line if a file is specified.\n"; return NULL; case CLI_GENERATE: return NULL; @@ -874,6 +946,7 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct ast_mutex_lock(®lock); for (idx = 0; idx < ARRAY_LEN(regions); ++idx) { for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) { + total_len += reg->len; if (fn) { if (strcasecmp(fn, reg->file)) { continue; @@ -932,11 +1005,14 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct ++cur->count; } } + + whales_len = freed_regions_size(&whales); + minnows_len = freed_regions_size(&minnows); ast_mutex_unlock(®lock); /* Dump the whole list */ for (cur = list; cur; cur = cur->next) { - len += cur->len; + selected_len += cur->len; cache_len += cur->cache_len; count += cur->count; if (cur->cache_len) { @@ -958,12 +1034,9 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct } } - if (cache_len) { - ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n", - len, cache_len, count); - } else { - ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count); - } + print_memory_show_common_stats(a->fd, + whales_len, minnows_len, total_len, + selected_len, cache_len, count); return CLI_SUCCESS; } From d36c4d0b01dbd49c72b42551037bd43e83d1d41a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 10 Jul 2015 10:37:35 -0500 Subject: [PATCH 0146/1578] taskprocessor.c: Simplify ast_taskprocessor_get() return code. Change-Id: Id5bd18ef1f60ef8be453e677e98478298358a9d1 --- main/taskprocessor.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 9a4424ea328..5f2f8de445d 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -713,12 +713,7 @@ struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_o } p = __allocate_taskprocessor(name, listener); - if (!p) { - ao2_ref(listener, -1); - return NULL; - } - /* Unref listener here since the taskprocessor has gained a reference to the listener */ ao2_ref(listener, -1); return p; } From a5b38b604c9ecec8cfb209439a94476834dbb7fc Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 14 Jan 2016 14:42:57 -0600 Subject: [PATCH 0147/1578] bridge_basic: don't cache xferfailsound during an attended transfer The xferfailsound was read from the channel at the beginning of the transfer, and that value is "cached" for the duration of the transfer. Therefore, changing the xferfailsound on the channel using the FEATURE() dialplan function does nothing once the transfer is under way. This makes it so the transfer code instead gets the xferfailsound configuration options from the channel when it is actually going to be used. This patch also fixes a potential memory leak of the props object as well as making sure the condition variable gets initialized before being destroyed. ASTERISK-25696 #close Change-Id: Ic726b0f54ef588bd9c9c67f4b0e4d787934f85e4 --- include/asterisk/features_config.h | 15 ++++++ main/bridge_basic.c | 80 +++++++++++++++++++++++------- main/features_config.c | 15 ++++++ 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h index b15759ba6c4..baaff183b30 100644 --- a/include/asterisk/features_config.h +++ b/include/asterisk/features_config.h @@ -101,6 +101,21 @@ struct ast_features_xfer_config { */ struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan); +/*! + * \brief Get the transfer configuration option xferfailsound + * + * \note The channel should be locked before calling this function. + * \note The returned value has to be freed. + * + * If no channel is provided, then option is pulled from the global + * transfer configuration. + * + * \param chan The channel to get configuration options for + * \retval NULL Failed to get configuration + * \retval non-NULL The xferfailsound + */ +char *ast_get_chan_features_xferfailsound(struct ast_channel *chan); + /*! * \brief Configuration relating to call pickup */ diff --git a/main/bridge_basic.c b/main/bridge_basic.c index cd19915205a..5d8ee49d06c 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -1296,8 +1296,6 @@ struct attended_transfer_properties { AST_STRING_FIELD(exten); /*! Context of transfer target */ AST_STRING_FIELD(context); - /*! Sound to play on failure */ - AST_STRING_FIELD(failsound); /*! Sound to play when transfer completes */ AST_STRING_FIELD(xfersound); /*! The channel technology of the transferer channel */ @@ -1421,12 +1419,21 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc( struct ast_flags *transferer_features; props = ao2_alloc(sizeof(*props), attended_transfer_properties_destructor); - if (!props || ast_string_field_init(props, 64)) { + if (!props) { + ast_log(LOG_ERROR, "Unable to create props - channel %s, context %s\n", + ast_channel_name(transferer), context); return NULL; } ast_cond_init(&props->cond, NULL); + if (ast_string_field_init(props, 64)) { + ast_log(LOG_ERROR, "Unable to initialize prop fields - channel %s, context %s\n", + ast_channel_name(transferer), context); + ao2_ref(props, -1); + return NULL; + } + props->target_framehook_id = -1; props->transferer = ast_channel_ref(transferer); @@ -1447,7 +1454,6 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc( props->atxfernoanswertimeout = xfer_cfg->atxfernoanswertimeout; props->atxferloopdelay = xfer_cfg->atxferloopdelay; ast_string_field_set(props, context, get_transfer_context(transferer, context)); - ast_string_field_set(props, failsound, xfer_cfg->xferfailsound); ast_string_field_set(props, xfersound, xfer_cfg->xfersound); ao2_ref(xfer_cfg, -1); @@ -1707,6 +1713,44 @@ static void play_sound(struct ast_channel *chan, const char *sound) } } +/*! + * \brief Helper method to play a fail sound on a channel in a bridge + * + * \param chan The channel to play the fail sound to + */ +static void play_failsound(struct ast_channel *chan) +{ + char *sound; + + ast_channel_lock(chan); + sound = ast_get_chan_features_xferfailsound(chan); + ast_channel_unlock(chan); + + if (sound) { + play_sound(chan, sound); + ast_free(sound); + } +} + +/*! + * \brief Helper method to stream a fail sound on a channel + * + * \param chan The channel to stream the fail sound to + */ +static void stream_failsound(struct ast_channel *chan) +{ + char *sound; + + ast_channel_lock(chan); + sound = ast_get_chan_features_xferfailsound(chan); + ast_channel_unlock(chan); + + if (sound) { + ast_stream_and_wait(chan, sound, AST_DIGIT_NONE); + ast_free(sound); + } +} + /*! * \brief Helper method to place a channel in a bridge on hold */ @@ -2049,7 +2093,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer { switch (stimulus) { case STIMULUS_TRANSFEREE_HANGUP: - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); publish_transfer_fail(props); return TRANSFER_FAIL; case STIMULUS_DTMF_ATXFER_COMPLETE: @@ -2061,7 +2105,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer case STIMULUS_TRANSFER_TARGET_HANGUP: case STIMULUS_TIMEOUT: case STIMULUS_DTMF_ATXFER_ABORT: - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); return TRANSFER_REBRIDGE; case STIMULUS_DTMF_ATXFER_THREEWAY: bridge_unhold(props->transferee_bridge); @@ -2090,7 +2134,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope { switch (stimulus) { case STIMULUS_TRANSFEREE_HANGUP: - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); publish_transfer_fail(props); return TRANSFER_FAIL; case STIMULUS_DTMF_ATXFER_COMPLETE: @@ -2101,7 +2145,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope case STIMULUS_TRANSFER_TARGET_HANGUP: case STIMULUS_TIMEOUT: case STIMULUS_DTMF_ATXFER_ABORT: - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); return TRANSFER_RESUME; case STIMULUS_DTMF_ATXFER_THREEWAY: return TRANSFER_THREEWAY; @@ -2163,7 +2207,7 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro * a sound to the transferer to indicate the transferee is gone. */ bridge_basic_change_personality(props->target_bridge, BRIDGE_BASIC_PERSONALITY_NORMAL, NULL); - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); ast_bridge_merge_inhibit(props->target_bridge, -1); /* These next two lines are here to ensure that our reference to the target bridge * is cleaned up properly and that the target bridge is not destroyed when the @@ -2179,7 +2223,7 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro return TRANSFER_COMPLETE; case STIMULUS_TRANSFER_TARGET_HANGUP: case STIMULUS_DTMF_ATXFER_ABORT: - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); return TRANSFER_REBRIDGE; case STIMULUS_DTMF_ATXFER_THREEWAY: bridge_unhold(props->transferee_bridge); @@ -2211,7 +2255,7 @@ static enum attended_transfer_state double_checking_exit(struct attended_transfe { switch (stimulus) { case STIMULUS_TRANSFEREE_HANGUP: - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); publish_transfer_fail(props); return TRANSFER_FAIL; case STIMULUS_TRANSFERER_HANGUP: @@ -2221,7 +2265,7 @@ static enum attended_transfer_state double_checking_exit(struct attended_transfe return TRANSFER_COMPLETE; case STIMULUS_TRANSFER_TARGET_HANGUP: case STIMULUS_DTMF_ATXFER_ABORT: - play_sound(props->transferer, props->failsound); + play_failsound(props->transferer); return TRANSFER_RESUME; case STIMULUS_DTMF_ATXFER_THREEWAY: bridge_unhold(props->target_bridge); @@ -3295,7 +3339,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, props->transfer_target = dial_transfer(bridge_channel->chan, destination); if (!props->transfer_target) { ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target.\n"); - ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); return 0; @@ -3306,7 +3350,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, props->target_bridge = ast_bridge_basic_new(); if (!props->target_bridge) { ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target.\n"); - ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3317,7 +3361,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, if (attach_framehook(props, props->transfer_target)) { ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n"); - ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3332,7 +3376,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, if (ast_call(props->transfer_target, destination, 0)) { ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n"); - ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3348,7 +3392,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, if (ast_bridge_impart(props->target_bridge, props->transfer_target, NULL, NULL, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { ast_log(LOG_ERROR, "Unable to place transfer target into bridge.\n"); - ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3358,7 +3402,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, if (ast_pthread_create_detached(&thread, NULL, attended_transfer_monitor_thread, props)) { ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer.\n"); - ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); return 0; diff --git a/main/features_config.c b/main/features_config.c index 3db1a780a4a..58ccb959b21 100644 --- a/main/features_config.c +++ b/main/features_config.c @@ -1158,6 +1158,21 @@ struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_ch return cfg->global->xfer; } +char *ast_get_chan_features_xferfailsound(struct ast_channel *chan) +{ + char *res; + struct ast_features_xfer_config *cfg = ast_get_chan_features_xfer_config(chan); + + if (!cfg) { + return NULL; + } + + res = ast_strdup(cfg->xferfailsound); + ao2_ref(cfg, -1); + + return res; +} + struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan) { RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup); From 480ccfcc97a022555ef27bc135026f97e0133b01 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 15 Jan 2016 20:52:26 -0500 Subject: [PATCH 0148/1578] main/config: Clean config maps on shutdown. ASTERISK-25700 #close Change-Id: I096da84f9c62c6095f68bcf98eac4b7c7868e808 --- main/config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/config.c b/main/config.c index 98fa9a29260..04e9367b767 100644 --- a/main/config.c +++ b/main/config.c @@ -3863,6 +3863,8 @@ static void config_shutdown(void) ast_cli_unregister_multiple(cli_config, ARRAY_LEN(cli_config)); + clear_config_maps(); + ao2_cleanup(cfg_hooks); cfg_hooks = NULL; } From c60d6c016252e6aad08cb88066076c57388cf700 Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Wed, 13 Jan 2016 21:58:22 +0000 Subject: [PATCH 0149/1578] pjsip/alembic: Fix qualify_timeout column definition Corrects the qualify_timeout column type from Integer to Decimal ASTERISK-25686 #close Reported-by: Marcelo Terres Change-Id: I757d0e3c011ee9be6cd5abd48bc92441a405d3c8 --- .../3d00be6d0c1f_fix_pjsip_qualify_ti.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/3d00be6d0c1f_fix_pjsip_qualify_ti.py diff --git a/contrib/ast-db-manage/config/versions/3d00be6d0c1f_fix_pjsip_qualify_ti.py b/contrib/ast-db-manage/config/versions/3d00be6d0c1f_fix_pjsip_qualify_ti.py new file mode 100644 index 00000000000..e0ee399f2ce --- /dev/null +++ b/contrib/ast-db-manage/config/versions/3d00be6d0c1f_fix_pjsip_qualify_ti.py @@ -0,0 +1,27 @@ +"""fix pjsip qualify timeout + +Revision ID: 3d00be6d0c1f +Revises: 26d7f3bf0fa5 +Create Date: 2016-01-16 19:48:31.730429 + +""" + +# revision identifiers, used by Alembic. +revision = '3d00be6d0c1f' +down_revision = '26d7f3bf0fa5' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Decimal) + op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Decimal) + pass + + +def downgrade(): + op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Integer) + op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Integer) + pass + From eaf2b5052e1fae7f0d797431a0589af8537b21aa Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Sat, 16 Jan 2016 19:18:19 +0000 Subject: [PATCH 0150/1578] Update version number in features.conf.sample Update the version number in the comments from Asterisk 12 to Asterisk 12+ Change-Id: Ie692ac8cda3c993c3bf10f27f51a1cca3317ec7b --- configs/samples/features.conf.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/samples/features.conf.sample b/configs/samples/features.conf.sample index aeb25c05d29..223d6935872 100644 --- a/configs/samples/features.conf.sample +++ b/configs/samples/features.conf.sample @@ -2,7 +2,7 @@ ; Sample Call Features (transfer, monitor/mixmonitor, etc) configuration ; -; Asterisk 12 Note - All parking lot configuration is now done in res_parking.conf +; Note: From Asterisk 12 - All parking lot configuration is now done in res_parking.conf [general] ;transferdigittimeout => 3 ; Number of seconds to wait between digits when transferring a call From 130aa1427eeb6d56c149ca1f30a170d38d4830dc Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 18 Jan 2016 18:01:36 -0700 Subject: [PATCH 0151/1578] pjsip_loging_refactor: Rename res_pjsip_log_forwarder to res_pjproject Change-Id: I5387821f29e5caa0cba0b7d62b0fc0d341e7e20b --- res/{res_pjsip_log_forwarder.c => res_pjproject.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename res/{res_pjsip_log_forwarder.c => res_pjproject.c} (100%) diff --git a/res/res_pjsip_log_forwarder.c b/res/res_pjproject.c similarity index 100% rename from res/res_pjsip_log_forwarder.c rename to res/res_pjproject.c From 378fed4900a308965a197fd4f29bd953c05efb46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 19 Jan 2016 01:10:06 -0300 Subject: [PATCH 0152/1578] app_queue: Fix preserved reason of pause when Asterisk is restared MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the Asterisk is restared is not preseved reason paused of members. This patch fixed this cases, retain data on astdb and set when Asterisk is started. ASTERISK-25732 #close Report by: Rodrigo Ramírez Norambuena Change-Id: Id3fb744c579e006d27cda4a02334ac0e4bed9eb5 --- apps/app_queue.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index c4025d2454a..964ee237004 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999 - 2015, Digium, Inc. + * Copyright (C) 1999 - 2016, Digium, Inc. * * Mark Spencer * @@ -6959,13 +6959,14 @@ static void dump_queue_members(struct call_queue *pm_queue) continue; } - ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s", + ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s", ast_str_strlen(value) ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, - cur_member->state_interface); + cur_member->state_interface, + cur_member->reason_paused); ao2_ref(cur_member, -1); } @@ -7042,7 +7043,7 @@ static int remove_from_queue(const char *queuename, const char *interface) * \retval RES_EXISTS queue exists but no members * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member */ -static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface) +static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused) { struct call_queue *q; struct member *new_member, *old_member; @@ -7059,6 +7060,9 @@ static int add_to_queue(const char *queuename, const char *interface, const char if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse))) { new_member->ringinuse = q->ringinuse; new_member->dynamic = 1; + if (reason_paused) { + ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused)); + } member_add_to_queue(q, new_member); queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member)); @@ -7415,6 +7419,7 @@ static void reload_queue_members(void) int penalty = 0; char *paused_tok; int paused = 0; + char *reason_paused; struct ast_db_entry *db_tree; struct ast_db_entry *entry; struct call_queue *cur_queue; @@ -7461,6 +7466,7 @@ static void reload_queue_members(void) paused_tok = strsep(&member, ";"); membername = strsep(&member, ";"); state_interface = strsep(&member, ";"); + reason_paused = strsep(&member, ";"); if (!penalty_tok) { ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); @@ -7482,9 +7488,10 @@ static void reload_queue_members(void) break; } - ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); + ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s\n", + queue_name, interface, membername, penalty, paused, reason_paused); - if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { + if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused) == RES_OUTOFMEMORY) { ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); break; } @@ -7681,7 +7688,7 @@ static int aqm_exec(struct ast_channel *chan, const char *data) } } - switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { + switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL)) { case RES_OKAY: if (ast_strlen_zero(args.membername) || !log_membername_as_agent) { ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", ""); @@ -9775,7 +9782,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message * paused = abs(ast_true(paused_s)); } - switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { + switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, NULL)) { case RES_OKAY: if (ast_strlen_zero(membername) || !log_membername_as_agent) { ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); @@ -10081,7 +10088,7 @@ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct as state_interface = a->argv[11]; } - switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { + switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface, NULL)) { case RES_OKAY: if (ast_strlen_zero(membername) || !log_membername_as_agent) { ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); From 35a3e8cc7fa2ed0e9775dc0910c9d0b8d03d9850 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 5 Jan 2016 18:12:54 -0500 Subject: [PATCH 0153/1578] Refactor init_logger_chain locking. This removes logchannels locking from init_logger_chain, puts the responsibility on the caller. Adds locking around the one call that was missing it. ASTERISK-24833 Change-Id: I6cc42117338bf9575650a67bcb78ab1a33d7bad8 --- main/logger.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/main/logger.c b/main/logger.c index 73b8ee1a257..fac68d9b6b9 100644 --- a/main/logger.c +++ b/main/logger.c @@ -560,13 +560,14 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo } /* \brief Read config, setup channels. - * \param locked The logchannels list is locked and this is a reload * \param altconf Alternate configuration file to read. * + * \pre logchannels list is write locked + * * \retval 0 Success * \retval -1 No config found or Failed */ -static int init_logger_chain(int locked, const char *altconf) +static int init_logger_chain(const char *altconf) { struct logchannel *chan; struct ast_config *cfg; @@ -578,10 +579,6 @@ static int init_logger_chain(int locked, const char *altconf) cfg = NULL; } - if (!locked) { - AST_RWLIST_WRLOCK(&logchannels); - } - /* Set defaults */ hostname[0] = '\0'; display_callids = 1; @@ -597,9 +594,6 @@ static int init_logger_chain(int locked, const char *altconf) ast_free(chan); } global_logmask = 0; - if (!locked) { - AST_RWLIST_UNLOCK(&logchannels); - } errno = 0; /* close syslog */ @@ -615,14 +609,8 @@ static int init_logger_chain(int locked, const char *altconf) chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR; memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter)); - if (!locked) { - AST_RWLIST_WRLOCK(&logchannels); - } AST_RWLIST_INSERT_HEAD(&logchannels, chan, list); global_logmask |= chan->logmask; - if (!locked) { - AST_RWLIST_UNLOCK(&logchannels); - } return -1; } @@ -675,9 +663,6 @@ static int init_logger_chain(int locked, const char *altconf) } } - if (!locked) { - AST_RWLIST_WRLOCK(&logchannels); - } var = ast_variable_browse(cfg, "logfiles"); for (; var; var = var->next) { if (!(chan = make_logchannel(var->name, var->value, var->lineno, 0))) { @@ -697,10 +682,6 @@ static int init_logger_chain(int locked, const char *altconf) qlog = NULL; } - if (!locked) { - AST_RWLIST_UNLOCK(&logchannels); - } - ast_config_destroy(cfg); return 0; @@ -1055,7 +1036,7 @@ static int reload_logger(int rotate, const char *altconf) filesize_reload_needed = 0; - init_logger_chain(1 /* locked */, altconf); + init_logger_chain(altconf); ast_unload_realtime("queue_log"); if (logfiles.queue_log) { @@ -1153,7 +1134,7 @@ int ast_logger_rotate_channel(const char *log_channel) } } - init_logger_chain(1 /* locked */, NULL); + init_logger_chain(NULL); AST_RWLIST_UNLOCK(&logchannels); @@ -1725,7 +1706,9 @@ int init_logger(void) ast_mkdir(ast_config_AST_LOG_DIR, 0777); /* create log channels */ - res = init_logger_chain(0 /* locked */, NULL); + AST_RWLIST_WRLOCK(&logchannels); + res = init_logger_chain(NULL); + AST_RWLIST_UNLOCK(&logchannels); ast_verb_update(); logger_initialized = 1; if (res) { From a4dcbdf50ff2f0d3928d926c99567e1837ca58b5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 19 Jan 2016 14:16:17 -0600 Subject: [PATCH 0154/1578] Fix alembic branches on master. Change-Id: I64ed21fec50eb833641ca49d92184f6aaabd86e8 --- .../versions/136885b81223_add_regcontext_to_pj.py | 4 ++-- ...ify_ti.py => 423f34ad36e2_fix_pjsip_qualify_ti.py} | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) rename contrib/ast-db-manage/config/versions/{3d00be6d0c1f_fix_pjsip_qualify_ti.py => 423f34ad36e2_fix_pjsip_qualify_ti.py} (75%) diff --git a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py index 78accc32299..724a5e57695 100644 --- a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py +++ b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py @@ -1,14 +1,14 @@ """add regcontext to pjsip Revision ID: 136885b81223 -Revises: 2d078ec071b7 +Revises: 26d7f3bf0fa5 Create Date: 2016-01-11 22:32:45.470522 """ # revision identifiers, used by Alembic. revision = '136885b81223' -down_revision = '2d078ec071b7' +down_revision = '26d7f3bf0fa5' from alembic import op import sqlalchemy as sa diff --git a/contrib/ast-db-manage/config/versions/3d00be6d0c1f_fix_pjsip_qualify_ti.py b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py similarity index 75% rename from contrib/ast-db-manage/config/versions/3d00be6d0c1f_fix_pjsip_qualify_ti.py rename to contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py index e0ee399f2ce..594f1eb7e04 100644 --- a/contrib/ast-db-manage/config/versions/3d00be6d0c1f_fix_pjsip_qualify_ti.py +++ b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py @@ -1,14 +1,14 @@ """fix pjsip qualify timeout -Revision ID: 3d00be6d0c1f -Revises: 26d7f3bf0fa5 -Create Date: 2016-01-16 19:48:31.730429 +Revision ID: 423f34ad36e2 +Revises: 136885b81223 +Create Date: 2016-01-13 21:49:21.557734 """ # revision identifiers, used by Alembic. -revision = '3d00be6d0c1f' -down_revision = '26d7f3bf0fa5' +revision = '423f34ad36e2' +down_revision = '136885b81223' from alembic import op import sqlalchemy as sa @@ -24,4 +24,3 @@ def downgrade(): op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Integer) op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Integer) pass - From 6e2a867716e89bd3472fd750f04fe6953bef3d16 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 18 Jan 2016 19:43:41 -0600 Subject: [PATCH 0155/1578] taskprocessor.c: Fix some taskprocessor unrefs. You have to call ast_taskprocessor_unref() outside of the taskprocessor implementation code. Taskprocessor use since v12 has become more transient than just the singleton uses in earlier versions. Change-Id: If7675299924c0cc65f2a43a85254e6f06f2d61bb --- main/taskprocessor.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 5f2f8de445d..49022d34eb7 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -332,10 +332,11 @@ static void *tps_task_free(struct tps_task *task) } /* taskprocessor tab completion */ -static char *tps_taskprocessor_tab_complete(struct ast_taskprocessor *p, struct ast_cli_args *a) +static char *tps_taskprocessor_tab_complete(struct ast_cli_args *a) { int tklen; int wordnum = 0; + struct ast_taskprocessor *p; char *name = NULL; struct ao2_iterator i; @@ -347,10 +348,10 @@ static char *tps_taskprocessor_tab_complete(struct ast_taskprocessor *p, struct while ((p = ao2_iterator_next(&i))) { if (!strncasecmp(a->word, p->name, tklen) && ++wordnum > a->n) { name = ast_strdup(p->name); - ao2_ref(p, -1); + ast_taskprocessor_unreference(p); break; } - ao2_ref(p, -1); + ast_taskprocessor_unreference(p); } ao2_iterator_destroy(&i); return name; @@ -372,7 +373,7 @@ static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args const char *name; struct timeval when; struct timespec ts; - struct ast_taskprocessor *tps = NULL; + struct ast_taskprocessor *tps; switch (cmd) { case CLI_INIT: @@ -382,7 +383,7 @@ static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args " Displays the time required for a task to be processed\n"; return NULL; case CLI_GENERATE: - return tps_taskprocessor_tab_complete(tps, a); + return tps_taskprocessor_tab_complete(a); } if (a->argc != 4) @@ -401,7 +402,7 @@ static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args if (ast_taskprocessor_push(tps, tps_ping_handler, 0) < 0) { ast_mutex_unlock(&cli_ping_cond_lock); ast_cli(a->fd, "\nping failed: could not push task to %s\n\n", name); - ao2_ref(tps, -1); + ast_taskprocessor_unreference(tps); return CLI_FAILURE; } ast_cond_timedwait(&cli_ping_cond, &cli_ping_cond_lock, &ts); @@ -409,7 +410,7 @@ static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args end = ast_tvnow(); delta = ast_tvsub(end, begin); ast_cli(a->fd, "\n\t%24s ping time: %.1ld.%.6ld sec\n\n", name, (long)delta.tv_sec, (long int)delta.tv_usec); - ao2_ref(tps, -1); + ast_taskprocessor_unreference(tps); return CLI_SUCCESS; } @@ -663,6 +664,8 @@ static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, stru if (!(ao2_link(tps_singletons, p))) { ast_log(LOG_ERROR, "Failed to add taskprocessor '%s' to container\n", p->name); + listener->tps = NULL; + ao2_ref(p, -1); return NULL; } From c9f7269b2eab5e575ea1a85ee8a7883a568a92ac Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 18 Jan 2016 19:44:24 -0600 Subject: [PATCH 0156/1578] taskprocessor.c: Increase CLI "core ping taskprocessor" timeout. Change-Id: I4892d6acbb580d6c207d006341eaf5e0f8f2a029 --- main/taskprocessor.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 5f2f8de445d..a45be1a17a5 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -394,9 +394,18 @@ static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args return CLI_SUCCESS; } ast_cli(a->fd, "\npinging %s ...", name); - when = ast_tvadd((begin = ast_tvnow()), ast_samp2tv(1000, 1000)); + + /* + * Wait up to 5 seconds for a ping reply. + * + * On a very busy system it could take awhile to get a + * ping response from some taskprocessors. + */ + begin = ast_tvnow(); + when = ast_tvadd(begin, ast_samp2tv(5000, 1000)); ts.tv_sec = when.tv_sec; ts.tv_nsec = when.tv_usec * 1000; + ast_mutex_lock(&cli_ping_cond_lock); if (ast_taskprocessor_push(tps, tps_ping_handler, 0) < 0) { ast_mutex_unlock(&cli_ping_cond_lock); @@ -406,6 +415,7 @@ static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args } ast_cond_timedwait(&cli_ping_cond, &cli_ping_cond_lock, &ts); ast_mutex_unlock(&cli_ping_cond_lock); + end = ast_tvnow(); delta = ast_tvsub(end, begin); ast_cli(a->fd, "\n\t%24s ping time: %.1ld.%.6ld sec\n\n", name, (long)delta.tv_sec, (long int)delta.tv_usec); From 9fa76ba215ebe3ac225f2dd37f16942caf4e7e63 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 19 Jan 2016 19:15:50 -0400 Subject: [PATCH 0157/1578] test_threadpool: Wait for each task to complete and fix memory leak. This change makes the thread_timeout_thrash unit test wait for each task to complete. This fixes the problem where the test would prematurely end when all threads were gone and a new one had to be started to handle the last task. It also increases the thrasing as it is now more likely for each task to encounter the above scenario. This also fixes a memory leak where the data for each task was not being freed. ASTERISK-25611 #close Change-Id: I5017d621a4dc911f509074c16229b86bff2fb3c6 --- tests/test_threadpool.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_threadpool.c b/tests/test_threadpool.c index 42181a25cc9..afb981be605 100644 --- a/tests/test_threadpool.c +++ b/tests/test_threadpool.c @@ -636,6 +636,14 @@ AST_TEST_DEFINE(threadpool_thread_timeout_thrash) ast_mutex_unlock(&tld->lock); ast_threadpool_push(pool, simple_task, std); + + res = wait_for_completion(test, std); + + ast_free(std); + + if (res == AST_TEST_FAIL) { + goto end; + } } res = wait_until_thread_state(test, tld, 0, 0); From 479cc99acd6fe9fca253be58c9ef8f791bf05482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Wed, 20 Jan 2016 10:52:45 -0300 Subject: [PATCH 0158/1578] README: Update year in copyright Change-Id: I56240f537fb3205672cdb2a74f0591ae7bb73dbc --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index d5f86c1ac5e..10f2824fdda 100644 --- a/README +++ b/README @@ -4,7 +4,7 @@ === by Mark Spencer === and the Asterisk.org developer community === -=== Copyright (C) 2001-2009 Digium, Inc. +=== Copyright (C) 2001-2016 Digium, Inc. === and other copyright holders. =============================================================================== From 3b9cba4294c0ace7a337fdce299d9d4796236cab Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 18 Jan 2016 17:16:24 -0600 Subject: [PATCH 0159/1578] funcs/func_cdr: Correctly report high precision values for duration and billsec When CDRs were refactored, func_cdr's ability to report high precision values for duration and billsec (the 'f' option) was broken. This was due to func_cdr incorrectly interpreting the duration/billsec values provided by the CDR engine in milliseconds, as opposed to seconds. Since the CDR engine only provides duration and billsec in seconds, and does not expose either attribute with sufficient precision to merely pass back the underlying value, this patch fixes the bug by re-calculating duration and billsec with microsecond precision based on the start/answer/end times on the CDR. ASTERISK-25179 #close Change-Id: I8bc63822b496537a5bf80baf6102c06206bee841 --- funcs/func_cdr.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 8d98479d151..ae15f6aa945 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -221,6 +221,26 @@ STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_read_message_type); STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_write_message_type); STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_prop_write_message_type); +static struct timeval cdr_retrieve_time(struct ast_channel *chan, const char *time_name) +{ + struct timeval time; + char *value = NULL; + char tempbuf[128]; + + if (ast_strlen_zero(ast_channel_name(chan))) { + /* Format request on a dummy channel */ + ast_cdr_format_var(ast_channel_cdr(chan), time_name, &value, tempbuf, sizeof(tempbuf), 1); + } else { + ast_cdr_getvar(ast_channel_name(chan), time_name, tempbuf, sizeof(tempbuf)); + } + + if (sscanf(tempbuf, "%ld.%ld", &time.tv_sec, &time.tv_usec) != 2) { + ast_log(AST_LOG_WARNING, "Failed to fully extract '%s' from CDR\n", time_name); + } + + return time; +} + static void cdr_read_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct cdr_func_payload *payload = stasis_message_data(message); @@ -268,16 +288,21 @@ static void cdr_read_callback(void *data, struct stasis_subscription *sub, struc if (ast_test_flag(&flags, OPT_FLOAT) && (!strcasecmp("billsec", args.variable) || !strcasecmp("duration", args.variable))) { - long ms; - double dtime; + struct timeval start = cdr_retrieve_time(payload->chan, !strcasecmp("billsec", args.variable) ? "answer" : "start"); + struct timeval finish = cdr_retrieve_time(payload->chan, "end"); + double delta; - if (sscanf(tempbuf, "%30ld", &ms) != 1) { - ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n", - args.variable, tempbuf, ast_channel_name(payload->chan)); - return; + if (ast_tvzero(finish)) { + finish = ast_tvnow(); } - dtime = (double)(ms / 1000.0); - snprintf(tempbuf, sizeof(tempbuf), "%lf", dtime); + + if (ast_tvzero(start)) { + delta = 0.0; + } else { + delta = (double)(ast_tvdiff_us(finish, start) / 1000000.0); + } + snprintf(tempbuf, sizeof(tempbuf), "%lf", delta); + } else if (!ast_test_flag(&flags, OPT_UNPARSED)) { if (!strcasecmp("start", args.variable) || !strcasecmp("end", args.variable) From dd5c063934ab816f3826d89d363f285307d1f051 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 18 Jan 2016 18:27:57 -0700 Subject: [PATCH 0160/1578] res_pjproject: Add module providing pjproject logging and utils res_pjsip_log_forwarder has been renamed to res_pjproject and enhanced as follows: As a follow-on to the recent 'Add CLI "pjsip show buildopts"' patch, a new ast_pjproject_get_buildopt function has been added. It allows the caller to get the value of one of the buildopts. The initial use case is retrieving the runtime value of PJ_MAX_HOSTNAME to insure we don't send a hostname greater than pjproject can handle. Since it can differ between the version of pjproject that Asterisk was compiled against and the version of pjproject that Asterisk is running against, we can't use the PJ_MAX_HOSTNAME macro directly in Asterisk source code. Change-Id: Iab6e82fec3d7cf00c1cf6185c42be3e7569dee1e --- CHANGES | 8 ++ include/asterisk/res_pjproject.h | 62 +++++++++++++ res/res_pjproject.c | 152 ++++++++++++++++++------------- res/res_pjproject.exports.in | 6 ++ 4 files changed, 167 insertions(+), 61 deletions(-) create mode 100644 include/asterisk/res_pjproject.h create mode 100644 res/res_pjproject.exports.in diff --git a/CHANGES b/CHANGES index 93ecf94c193..173a41127c7 100644 --- a/CHANGES +++ b/CHANGES @@ -205,6 +205,14 @@ Queue --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ ------------------------------------------------------------------------------ +res_pjproject +------------------ + * This module is the successor of res_pjsip_log_forwarder. As well as + handling the log forwarding (which now displays as 'pjproject:0' instead + of 'pjsip:0'), it also adds a 'pjproject show buildopts' command to the CLI. + This displays the compiled-in options of the pjproject installation + Asterisk is currently running against. + res_pjsip ------------------ diff --git a/include/asterisk/res_pjproject.h b/include/asterisk/res_pjproject.h new file mode 100644 index 00000000000..2095caed262 --- /dev/null +++ b/include/asterisk/res_pjproject.h @@ -0,0 +1,62 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _RES_PJPROJECT_H +#define _RES_PJPROJECT_H + +/*! + * \brief Retrieve a pjproject build option + * + * \param option The build option requested + * \param format_string A scanf-style format string to parse the option value into + * \param ... Pointers to variables to receive the values parsed + * + * \retval The number of values parsed + * + * \since 13.8.0 + * + * \note The option requested must be from those returned by pj_dump_config() + * which can be displayed with the 'pjsip show buildopts' CLI command. + * + * Sample Usage: + * \code + * + * int max_hostname; + * + * ast_sip_get_pjproject_buildopt("PJ_MAX_HOSTNAME", "%d", &max_hostname); + * + * \endcode + * + */ +int ast_pjproject_get_buildopt(char *option, char *format_string, ...) __attribute__((format(scanf, 2,3))); + +/*! + * \brief Increment the res_pjproject reference count. + * + * This ensures graceful shutdown happens in the proper order. + */ +void ast_pjproject_ref(void); + +/*! + * \brief Decrement the res_pjproject reference count. + * + * This ensures graceful shutdown happens in the proper order. + */ +void ast_pjproject_unref(void); + +#endif /* _RES_PJPROJECT_H */ diff --git a/res/res_pjproject.c b/res/res_pjproject.c index c6b396afc5f..de1cecbc8e7 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -18,18 +18,18 @@ /*! \file * - * \brief Bridge PJSIP logging to Asterisk logging. + * \brief Bridge PJPROJECT logging to Asterisk logging. * \author David M. Lee, II * - * PJSIP logging doesn't exactly match Asterisk logging, but mapping the two is - * not too bad. PJSIP log levels are identified by a single int. Limits are - * not specified by PJSIP, but their implementation used 1 through 6. + * PJPROJECT logging doesn't exactly match Asterisk logging, but mapping the two is + * not too bad. PJPROJECT log levels are identified by a single int. Limits are + * not specified by PJPROJECT, but their implementation used 1 through 6. * * The mapping is as follows: * - 0: LOG_ERROR * - 1: LOG_ERROR * - 2: LOG_WARNING - * - 3 and above: equivalent to ast_debug(level, ...) for res_pjsip.so + * - 3 and above: equivalent to ast_debug(level, ...) for res_pjproject.so */ /*** MODULEINFO @@ -41,47 +41,31 @@ ASTERISK_REGISTER_FILE() +#include +#include #include #include #include "asterisk/logger.h" #include "asterisk/module.h" #include "asterisk/cli.h" +#include "asterisk/res_pjproject.h" +#include "asterisk/vector.h" static pj_log_func *log_cb_orig; static unsigned decor_orig; -/*! Protection from other CLI instances. */ -AST_MUTEX_DEFINE_STATIC(show_buildopts_lock); +static AST_VECTOR(buildopts, char *) buildopts; -struct pjsip_show_buildopts { - pthread_t thread; - int fd; -}; - -static struct pjsip_show_buildopts show_buildopts = { - .thread = AST_PTHREADT_NULL, - .fd = -1, -}; - -static void log_cb(int level, const char *data, int len) +static void log_forwarder(int level, const char *data, int len) { int ast_level; - /* PJSIP doesn't provide much in the way of source info */ - const char * log_source = "pjsip"; + /* PJPROJECT doesn't provide much in the way of source info */ + const char * log_source = "pjproject"; int log_line = 0; const char *log_func = ""; int mod_level; - if (show_buildopts.fd != -1 && show_buildopts.thread == pthread_self()) { - /* - * We are handling the CLI command dumping the - * PJPROJECT compile time config option settings. - */ - ast_cli(show_buildopts.fd, "%s\n", data); - return; - } - /* Lower number indicates higher importance */ switch (level) { case 0: /* level zero indicates fatal error, according to docs */ @@ -94,29 +78,72 @@ static void log_cb(int level, const char *data, int len) default: ast_level = __LOG_DEBUG; - /* For levels 3 and up, obey the debug level for res_pjsip */ + /* For levels 3 and up, obey the debug level for res_pjproject */ mod_level = ast_opt_dbg_module ? - ast_debug_get_by_module("res_pjsip") : 0; + ast_debug_get_by_module("res_pjproject") : 0; if (option_debug < level && mod_level < level) { return; } break; } - /* PJSIP uses indention to indicate function call depth. We'll prepend + /* PJPROJECT uses indention to indicate function call depth. We'll prepend * log statements with a tab so they'll have a better shot at lining * up */ ast_log(ast_level, log_source, log_line, log_func, "\t%s\n", data); } -static char *handle_pjsip_show_buildopts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +static void capture_buildopts_cb(int level, const char *data, int len) +{ + if (strstr(data, "Teluu") || strstr(data, "Dumping")) { + return; + } + + AST_VECTOR_ADD_SORTED(&buildopts, ast_strdup(ast_skip_blanks(data)), strcmp); +} + +int ast_pjproject_get_buildopt(char *option, char *format_string, ...) +{ + int res = 0; + char *format_temp; + int i; + + format_temp = ast_alloca(strlen(option) + strlen(" : ") + strlen(format_string) + 1); + sprintf(format_temp, "%s : %s", option, format_string); + + for (i = 0; i < AST_VECTOR_SIZE(&buildopts); i++) { + va_list arg_ptr; + va_start(arg_ptr, format_string); + res = vsscanf(AST_VECTOR_GET(&buildopts, i), format_temp, arg_ptr); + va_end(arg_ptr); + if (res) { + break; + } + } + + return res; +} + +void ast_pjproject_ref(void) { - switch(cmd) { + ast_module_ref(ast_module_info->self); +} + +void ast_pjproject_unref(void) +{ + ast_module_unref(ast_module_info->self); +} + +static char *handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + int i; + + switch (cmd) { case CLI_INIT: - e->command = "pjsip show buildopts"; + e->command = "pjproject show buildopts"; e->usage = - "Usage: pjsip show buildopts\n" - " Show the compile time config of pjproject that res_pjsip is\n" + "Usage: pjproject show buildopts\n" + " Show the compile time config of the pjproject that Asterisk is\n" " running against.\n"; return NULL; case CLI_GENERATE: @@ -125,60 +152,63 @@ static char *handle_pjsip_show_buildopts(struct ast_cli_entry *e, int cmd, struc ast_cli(a->fd, "PJPROJECT compile time config currently running against:\n"); - /* Protect from other CLI instances trying to do this at the same time. */ - ast_mutex_lock(&show_buildopts_lock); - - show_buildopts.thread = pthread_self(); - show_buildopts.fd = a->fd; - pj_dump_config(); - show_buildopts.fd = -1; - show_buildopts.thread = AST_PTHREADT_NULL; - - ast_mutex_unlock(&show_buildopts_lock); + for (i = 0; i < AST_VECTOR_SIZE(&buildopts); i++) { + ast_cli(a->fd, "%s\n", AST_VECTOR_GET(&buildopts, i)); + } return CLI_SUCCESS; } -static struct ast_cli_entry pjsip_cli[] = { - AST_CLI_DEFINE(handle_pjsip_show_buildopts, "Show the compiled config of pjproject in use"), +static struct ast_cli_entry pjproject_cli[] = { + AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"), }; static int load_module(void) { + ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n"); + pj_init(); decor_orig = pj_log_get_decor(); log_cb_orig = pj_log_get_log_func(); - ast_debug(3, "Forwarding PJSIP logger to Asterisk logger\n"); - /* SENDER prepends the source to the log message. This could be a - * filename, object reference, or simply a string - * - * INDENT is assumed to be on by most log statements in PJSIP itself. + if (AST_VECTOR_INIT(&buildopts, 64)) { + return AST_MODULE_LOAD_DECLINE; + } + + /* + * On startup, we want to capture the dump once and store it. */ + pj_log_set_log_func(capture_buildopts_cb); + pj_log_set_decor(0); + pj_dump_config(); pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT); - pj_log_set_log_func(log_cb); + pj_log_set_log_func(log_forwarder); - ast_cli_register_multiple(pjsip_cli, ARRAY_LEN(pjsip_cli)); + ast_cli_register_multiple(pjproject_cli, ARRAY_LEN(pjproject_cli)); return AST_MODULE_LOAD_SUCCESS; } +#define NOT_EQUALS(a, b) (a != b) + static int unload_module(void) { - ast_cli_unregister_multiple(pjsip_cli, ARRAY_LEN(pjsip_cli)); - + ast_cli_unregister_multiple(pjproject_cli, ARRAY_LEN(pjproject_cli)); pj_log_set_log_func(log_cb_orig); pj_log_set_decor(decor_orig); + AST_VECTOR_REMOVE_CMP_UNORDERED(&buildopts, NULL, NOT_EQUALS, ast_free); + AST_VECTOR_FREE(&buildopts); + + ast_debug(3, "Stopped PJPROJECT logging to Asterisk logger\n"); + pj_shutdown(); return 0; } -/* While we don't really export global symbols, we want to load before other - * modules that do */ -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Log Forwarder", +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJPROJECT Log and Utility Support", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, diff --git a/res/res_pjproject.exports.in b/res/res_pjproject.exports.in new file mode 100644 index 00000000000..f1821a6a28c --- /dev/null +++ b/res/res_pjproject.exports.in @@ -0,0 +1,6 @@ +{ + global: + LINKER_SYMBOL_PREFIXast_pjproject_*; + local: + *; +}; From b259ac95acefd67a90a451f55acab7fd6ce77d97 Mon Sep 17 00:00:00 2001 From: Diederik de Groot Date: Mon, 18 Jan 2016 10:49:48 +0100 Subject: [PATCH 0161/1578] main/asterisk.c: ast_el_read_char Make sure buf[res] is not accessed at res=-1 (buffer underrun). Address Sanitizer will complain about this quite loudly. ASTERISK-24801 #close Change-Id: Ifcd7f691310815a31756b76067c56fba299d3ae9 --- main/asterisk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/asterisk.c b/main/asterisk.c index a7842a6ab68..ca560cdb273 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -2708,11 +2708,12 @@ static int ast_el_read_char(EditLine *editline, char *cp) console_print(buf, 0); - if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) { + if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (res >= 2 && buf[res-2] == '\n'))) { *cp = CC_REFRESH; return(1); - } else + } else { lastpos = 1; + } } } From 5615db3714fbc8ca14e9c57921d3f05185f197f0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Jan 2016 16:49:22 -0600 Subject: [PATCH 0162/1578] res_pjsip: Add CLI "pjsip dump endpt [details]" Dump the res_pjsip endpt internals. In non-developer mode we will not document or make easily accessible the "details" option even though it is still available. The user has to know it exists to use it. Presumably they would also be aware of the potential crash warning below. Warning: PJPROJECT documents that the function used by this CLI command may cause a crash when asking for details because it tries to access all active memory pools. Change-Id: If2d98a3641c9873364d1daaad971376311aef3cb --- include/asterisk/res_pjproject.h | 36 +++++++++++++++++- res/res_pjproject.c | 40 ++++++++++++++++++++ res/res_pjsip.c | 64 +++++++++++++++++++++++++++++++- 3 files changed, 137 insertions(+), 3 deletions(-) diff --git a/include/asterisk/res_pjproject.h b/include/asterisk/res_pjproject.h index 2095caed262..8828b340c82 100644 --- a/include/asterisk/res_pjproject.h +++ b/include/asterisk/res_pjproject.h @@ -19,6 +19,14 @@ #ifndef _RES_PJPROJECT_H #define _RES_PJPROJECT_H +/*! \brief Determines whether the res_pjproject module is loaded */ +#define CHECK_PJPROJECT_MODULE_LOADED() \ + do { \ + if (!ast_module_check("res_pjproject.so")) { \ + return AST_MODULE_LOAD_DECLINE; \ + } \ + } while(0) + /*! * \brief Retrieve a pjproject build option * @@ -43,7 +51,33 @@ * \endcode * */ -int ast_pjproject_get_buildopt(char *option, char *format_string, ...) __attribute__((format(scanf, 2,3))); +int ast_pjproject_get_buildopt(char *option, char *format_string, ...) __attribute__((format(scanf, 2, 3))); + +/*! + * \brief Begin PJPROJECT log interception for CLI output. + * \since 13.8.0 + * + * \param fd CLI file descriptior to send intercepted output. + * + * \note ast_pjproject_log_intercept_begin() and + * ast_pjproject_log_intercept_end() must always be called + * in pairs. + * + * \return Nothing + */ +void ast_pjproject_log_intercept_begin(int fd); + +/*! + * \brief End PJPROJECT log interception for CLI output. + * \since 13.8.0 + * + * \note ast_pjproject_log_intercept_begin() and + * ast_pjproject_log_intercept_end() must always be called + * in pairs. + * + * \return Nothing + */ +void ast_pjproject_log_intercept_end(void); /*! * \brief Increment the res_pjproject reference count. diff --git a/res/res_pjproject.c b/res/res_pjproject.c index de1cecbc8e7..e9f0d15c4bb 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -57,6 +57,19 @@ static unsigned decor_orig; static AST_VECTOR(buildopts, char *) buildopts; +/*! Protection from other log intercept instances. There can be only one at a time. */ +AST_MUTEX_DEFINE_STATIC(pjproject_log_intercept_lock); + +struct pjproject_log_intercept_data { + pthread_t thread; + int fd; +}; + +static struct pjproject_log_intercept_data pjproject_log_intercept = { + .thread = AST_PTHREADT_NULL, + .fd = -1, +}; + static void log_forwarder(int level, const char *data, int len) { int ast_level; @@ -66,6 +79,16 @@ static void log_forwarder(int level, const char *data, int len) const char *log_func = ""; int mod_level; + if (pjproject_log_intercept.fd != -1 + && pjproject_log_intercept.thread == pthread_self()) { + /* + * We are handling a CLI command intercepting PJPROJECT + * log output. + */ + ast_cli(pjproject_log_intercept.fd, "%s\n", data); + return; + } + /* Lower number indicates higher importance */ switch (level) { case 0: /* level zero indicates fatal error, according to docs */ @@ -124,6 +147,23 @@ int ast_pjproject_get_buildopt(char *option, char *format_string, ...) return res; } +void ast_pjproject_log_intercept_begin(int fd) +{ + /* Protect from other CLI instances trying to do this at the same time. */ + ast_mutex_lock(&pjproject_log_intercept_lock); + + pjproject_log_intercept.thread = pthread_self(); + pjproject_log_intercept.fd = fd; +} + +void ast_pjproject_log_intercept_end(void) +{ + pjproject_log_intercept.fd = -1; + pjproject_log_intercept.thread = AST_PTHREADT_NULL; + + ast_mutex_unlock(&pjproject_log_intercept_lock); +} + void ast_pjproject_ref(void) { ast_module_ref(ast_module_info->self); diff --git a/res/res_pjsip.c b/res/res_pjsip.c index b3c6773b482..2b7625aba2f 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -42,9 +42,11 @@ #include "asterisk/res_pjsip_cli.h" #include "asterisk/test.h" #include "asterisk/res_pjsip_presence_xml.h" +#include "asterisk/res_pjproject.h" /*** MODULEINFO pjproject + res_pjproject res_sorcery_config res_sorcery_memory res_sorcery_astdb @@ -2216,6 +2218,57 @@ struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata) return endpoint; } +static int do_cli_dump_endpt(void *v_a) +{ + struct ast_cli_args *a = v_a; + + ast_pjproject_log_intercept_begin(a->fd); + pjsip_endpt_dump(ast_sip_get_pjsip_endpoint(), a->argc == 4 ? PJ_TRUE : PJ_FALSE); + ast_pjproject_log_intercept_end(); + + return 0; +} + +static char *cli_dump_endpt(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: +#ifdef AST_DEVMODE + e->command = "pjsip dump endpt [details]"; + e->usage = + "Usage: pjsip dump endpt [details]\n" + " Dump the res_pjsip endpt internals.\n" + "\n" + "Warning: PJPROJECT documents that the function used by this\n" + "CLI command may cause a crash when asking for details because\n" + "it tries to access all active memory pools.\n"; +#else + /* + * In non-developer mode we will not document or make easily accessible + * the details option even though it is still available. The user has + * to know it exists to use it. Presumably they would also be aware of + * the potential crash warning. + */ + e->command = "pjsip dump endpt"; + e->usage = + "Usage: pjsip dump endpt\n" + " Dump the res_pjsip endpt internals.\n"; +#endif /* AST_DEVMODE */ + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (4 < a->argc + || (a->argc == 4 && strcasecmp(a->argv[3], "details"))) { + return CLI_SHOWUSAGE; + } + + ast_sip_push_task_synchronous(NULL, do_cli_dump_endpt, a); + + return CLI_SUCCESS; +} + static char *cli_show_endpoint_identifiers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { #define ENDPOINT_IDENTIFIER_FORMAT "%-20.20s\n" @@ -2279,8 +2332,9 @@ static char *cli_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ } static struct ast_cli_entry cli_commands[] = { - AST_CLI_DEFINE(cli_show_settings, "Show global and system configuration options"), - AST_CLI_DEFINE(cli_show_endpoint_identifiers, "List registered endpoint identifiers") + AST_CLI_DEFINE(cli_dump_endpt, "Dump the res_pjsip endpt internals"), + AST_CLI_DEFINE(cli_show_settings, "Show global and system configuration options"), + AST_CLI_DEFINE(cli_show_endpoint_identifiers, "List registered endpoint identifiers") }; AST_RWLIST_HEAD_STATIC(endpoint_formatters, ast_sip_endpoint_formatter); @@ -3895,6 +3949,8 @@ static int load_module(void) pj_status_t status; struct ast_threadpool_options options; + CHECK_PJPROJECT_MODULE_LOADED(); + if (pj_init() != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; } @@ -4041,6 +4097,8 @@ static int load_module(void) AST_TEST_REGISTER(xml_sanitization_end_null); AST_TEST_REGISTER(xml_sanitization_exceeds_buffer); + ast_pjproject_ref(); + return AST_MODULE_LOAD_SUCCESS; } @@ -4094,6 +4152,8 @@ static int unload_module(void) ast_threadpool_shutdown(sip_threadpool); ast_sip_destroy_cli(); + ast_pjproject_unref(); + return 0; } From 04078f43b5e2970455307e22010ecd873a70e061 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 19 Jan 2016 18:20:59 -0600 Subject: [PATCH 0163/1578] res/res_pjsip/presence_xml.c: Add missing 2nd call presence state case. ASTERISK-25712 #close Reported by: Richard Mudgett Change-Id: I70634df24f8c6c3a2c66c45af61d021e4999253f --- res/res_pjsip/presence_xml.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/presence_xml.c b/res/res_pjsip/presence_xml.c index b98ea0237e9..c991a0d68c9 100644 --- a/res/res_pjsip/presence_xml.c +++ b/res/res_pjsip/presence_xml.c @@ -91,6 +91,12 @@ void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **p *pidfstate = "busy"; *pidfnote = "Ringing"; break; + case (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING): + *statestring = "confirmed"; + *local_state = NOTIFY_INUSE; + *pidfstate = "busy"; + *pidfnote = "Ringing"; + break; case AST_EXTENSION_INUSE: *statestring = "confirmed"; *local_state = NOTIFY_INUSE; @@ -121,7 +127,7 @@ void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **p *statestring = "terminated"; *local_state = NOTIFY_OPEN; *pidfstate = "--"; - *pidfnote ="Ready"; + *pidfnote = "Ready"; break; } } From 5dde111719aeb782f0ea1c6b253d143d75cf7091 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 21 Jan 2016 17:40:47 -0500 Subject: [PATCH 0164/1578] Build System: Add support for checking alembic branches. * Add 'check-alembic' target to root Makefile. * Create build_tools/make_check_alembic to do the actual checks. ASTERISK-25685 Change-Id: Ibb3cae7d1202ac23dc70b0f3b5801571ad46b004 --- Makefile | 5 ++++ build_tools/make_check_alembic | 29 +++++++++++++++++++ configure | 52 ++++++++++++++++++++++++++++++---- configure.ac | 1 + makeopts.in | 1 + 5 files changed, 83 insertions(+), 5 deletions(-) create mode 100755 build_tools/make_check_alembic diff --git a/Makefile b/Makefile index 4b1c57b8bc5..b1de3d2445b 100644 --- a/Makefile +++ b/Makefile @@ -1009,6 +1009,10 @@ else rest-api/resources.json . endif +check-alembic: makeopts + @find contrib/ast-db-manage/ -name '*.pyc' -delete + @ALEMBIC=$(ALEMBIC) build_tools/make_check_alembic config cdr voicemail >&2 + .PHONY: menuselect .PHONY: main .PHONY: sounds @@ -1030,6 +1034,7 @@ endif .PHONY: _clean .PHONY: ari-stubs .PHONY: basic-pbx +.PHONY: check-alembic .PHONY: $(SUBDIRS_INSTALL) .PHONY: $(SUBDIRS_DIST_CLEAN) .PHONY: $(SUBDIRS_CLEAN) diff --git a/build_tools/make_check_alembic b/build_tools/make_check_alembic new file mode 100755 index 00000000000..ecc5fc1c960 --- /dev/null +++ b/build_tools/make_check_alembic @@ -0,0 +1,29 @@ +#!/bin/sh +if [ -z "$ALEMBIC" -o ! -d contrib/ast-db-manage ]; then + echo "Run 'make check-alembic' to use this script" >&2 + exit 1 +fi + +if [ "$ALEMBIC" = ":" ]; then + echo "Install alembic and re-run configure before using this target." + exit 1 +fi + +cd contrib/ast-db-manage + +FOUNDERROR= +for id in "$@"; do + if [ -n "$($ALEMBIC -c ${id}.ini.sample branches)" ]; then + echo "Alembic branches exist for $id - details follow:" + # This second run is needed to display the errors because + # formatting was lost in the first execution. + $ALEMBIC -c ${id}.ini.sample branches + # Display all errors before reporting failure to Make. + FOUNDERROR=yes + fi +done + +if [ -n "$FOUNDERROR" ]; then + # One or more failures. + exit 1 +fi diff --git a/configure b/configure index bc51839c823..fc7613120e6 100755 --- a/configure +++ b/configure @@ -1174,6 +1174,7 @@ SHA1SUM LDCONFIG DOWNLOAD FETCH +ALEMBIC GIT XMLSTARLET XMLLINT @@ -7479,6 +7480,47 @@ $as_echo "no" >&6; } fi +# Extract the first word of "alembic", so it can be a program name with args. +set dummy alembic; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ALEMBIC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ALEMBIC in + [\\/]* | ?:[\\/]*) + ac_cv_path_ALEMBIC="$ALEMBIC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ALEMBIC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_ALEMBIC" && ac_cv_path_ALEMBIC=":" + ;; +esac +fi +ALEMBIC=$ac_cv_path_ALEMBIC +if test -n "$ALEMBIC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ALEMBIC" >&5 +$as_echo "$ALEMBIC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} else if test "${CURL}" != ":" ; then @@ -13653,7 +13695,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13699,7 +13741,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13723,7 +13765,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13768,7 +13810,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13792,7 +13834,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; diff --git a/configure.ac b/configure.ac index 021d0d167e4..e7b7e578100 100644 --- a/configure.ac +++ b/configure.ac @@ -279,6 +279,7 @@ AC_PATH_PROG([KPATHSEA], [kpsewhich], :) AC_PATH_PROG([XMLLINT], [xmllint], :) AC_PATH_PROG([XMLSTARLET], [xmlstarlet], :) AC_PATH_PROG([GIT], [git], :) +AC_PATH_PROG([ALEMBIC], [alembic], :) if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} else if test "${CURL}" != ":" ; then diff --git a/makeopts.in b/makeopts.in index d91dc9ba4a0..f606acee0e1 100644 --- a/makeopts.in +++ b/makeopts.in @@ -38,6 +38,7 @@ SHA1SUM=@SHA1SUM@ OPENSSL=@OPENSSL@ LDCONFIG=@LDCONFIG@ GIT=@GIT@ +ALEMBIC=@ALEMBIC@ BUILD_PLATFORM=@BUILD_PLATFORM@ BUILD_CPU=@BUILD_CPU@ From d3969d09ae6c37f7f942b9116c2c3a1b2b9ad08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 22 Jan 2016 14:18:57 -0300 Subject: [PATCH 0165/1578] app_queue.c: remove include for core_unreal.h not used in code. Change-Id: Idc2ae8a6bd869a66544916906744a5678622262d --- apps/app_queue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index c4025d2454a..6827409776a 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -110,7 +110,6 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_bridges.h" #include "asterisk/core_local.h" #include "asterisk/mixmonitor.h" -#include "asterisk/core_unreal.h" #include "asterisk/bridge_basic.h" #include "asterisk/max_forwards.h" From 9714da7aa4021ba495d5f4ad02fb4128e54689ab Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 23 Dec 2015 15:07:05 -0600 Subject: [PATCH 0166/1578] res_odbc: Remove connection management Asterisk by default will create a single database connection and share it among all threads that attempt to access the database. In previous versions of Asterisk, this was tolerable, because the most used channel driver, chan_sip, mostly accessed the database from a single thread. With PJSIP, however, many threads may be attempting to perform database operations, and there is the potential for many more database accesses, meaning the concurrency is a horrible bottleneck if only one connection is shared. Asterisk has a connection pooling facility built into it, but the implementation has flaws. For one, there is a strict limit on the number of simultaneous connections that could be made to the database. Anything beyond the maximum would result in a failed operation. Attempting to predict what the maximum should be is nearly impossible even for someone intimately familiar with Asterisk's threading model. In addition, use of transactions in the dialplan can cause some severe bugs if connection pooling is enabled. This commit seeks to fix the concurrency problem by removing all connection management code from Asterisk and leaving that to the underlying unixODBC code instead. Now, Asterisk does not share a single connection, nor does it try to maintain a connection pool. Instead, all Asterisk ever does is request a connection from unixODBC and allow unixODBC to either allocate those connections or retrieve them from a pool. Doing this has a bit of a ripple effect. For one, since connections are not long-lived objects, several of the safeguards that previously existed have been removed. We don't have to worry about trying to use a connection that has gone stale. In every case, when we request a connection, it has just been made and we don't need to perform any sanity checks to be sure it's still active. Another major player affected by this change is transactions. Transactions and their respective connections were so tightly coupled that it was almost pornographic. This code change moves transaction-related code to its own file separate from the core ODBC functionality. This way, the core of ODBC does not even have to know that transactions exist. In making this large change, I had to look at a lot of code and understand it. When making this change, I discovered several places where the behavior is definitely not ideal, but it seemed outside the scope of this change to be fixing it. Instead, any place where I saw some sort of room for improvement has had a XXX comment added explaining what could be altered to improve it. Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf --- funcs/func_odbc.c | 1 + include/asterisk/config.h | 11 + include/asterisk/res_odbc.h | 78 +- include/asterisk/res_odbc_transaction.h | 54 ++ res/res_odbc.c | 1179 +++-------------------- res/res_odbc.exports.in | 6 +- res/res_odbc_transaction.c | 529 ++++++++++ res/res_odbc_transaction.exports.in | 6 + 8 files changed, 767 insertions(+), 1097 deletions(-) create mode 100644 include/asterisk/res_odbc_transaction.h create mode 100644 res/res_odbc_transaction.c create mode 100644 res/res_odbc_transaction.exports.in diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 4744ba626fd..23930ed4d8b 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -42,6 +42,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/pbx.h" #include "asterisk/config.h" #include "asterisk/res_odbc.h" +#include "asterisk/res_odbc_transaction.h" #include "asterisk/app.h" #include "asterisk/cli.h" #include "asterisk/strings.h" diff --git a/include/asterisk/config.h b/include/asterisk/config.h index bd268a333ef..9a899d8d06d 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -495,6 +495,17 @@ int ast_unload_realtime(const char *family); * * \note You should use the constant SENTINEL to terminate arguments, in * order to preserve cross-platform compatibility. + * + * TODO The return value of this function is routinely ignored. Ignoring + * the return value means that it's mostly pointless to be calling this. + * You'll see some warning messages potentially, but that's it. + * + * XXX This function is super useful for detecting configuration problems + * early, but unfortunately, the latest in configuration management, sorcery, + * doesn't work well with this. Users of sorcery are familiar with the fields + * they will need to write but don't know if realtime is being used. Sorcery + * knows what storage mechanism is being used but has no high-level knowledge + * of what sort of data is going to be written. */ int ast_realtime_require_field(const char *family, ...) attribute_sentinel; diff --git a/include/asterisk/res_odbc.h b/include/asterisk/res_odbc.h index 7d9d4a19e80..8c7b5495063 100644 --- a/include/asterisk/res_odbc.h +++ b/include/asterisk/res_odbc.h @@ -46,16 +46,11 @@ enum { struct odbc_obj { SQLHDBC con; /*!< ODBC Connection Handle */ struct odbc_class *parent; /*!< Information about the connection is protected */ - struct timeval last_used; /*!< Used by idlecheck to determine if the connection should be renegotiated */ #ifdef DEBUG_THREADS char file[80]; char function[80]; int lineno; #endif - unsigned int used:1; /*!< Is this connection currently in use? */ - unsigned int up:1; - unsigned int tx:1; /*!< Should this connection be unshared, regardless of the class setting? */ - struct odbc_txn_frame *txf; /*!< Reference back to the transaction frame, if applicable */ AST_LIST_ENTRY(odbc_obj) list; }; @@ -102,39 +97,29 @@ int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt) __attribute__((d /*! * \brief Retrieves a connected ODBC object - * \param name The name of the ODBC class for which a connection is needed. - * \param flags One or more of the following flags: - * \li RES_ODBC_SANITY_CHECK Whether to ensure that a connection is valid before returning the handle. Usually unnecessary. - * \li RES_ODBC_INDEPENDENT_CONNECTION Return a handle which is independent from all others. Usually used when starting a transaction. - * \li RES_ODBC_CONNECTED Only return a connected handle. Intended for use with peers which use idlecheck, which are checked periodically for reachability. - * \param file, function, lineno * - * \return ODBC object - * \retval NULL if there is no connection available with the requested name. + * \deprecated * - * Connection classes may, in fact, contain multiple connection handles. If - * the connection is pooled, then each connection will be dedicated to the - * thread which requests it. Note that all connections should be released - * when the thread is done by calling ast_odbc_release_obj(), below. + * This is only around for backwards-compatibility with older versions of Asterisk. */ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno); + +/*! + * \brief Get a ODBC connection object + * + * The "check" parameter is leftover from an earlier implementation where database connections + * were cached by res_odbc. Since connections are managed by unixODBC now, this parameter is + * only kept around for API compatibility. + * + * \param name The name of the res_odbc.conf section describing the database to connect to + * \param check unused + * \return A connection to the database. Call ast_odbc_release_obj() when finished. + */ struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno); #define ast_odbc_request_obj2(a, b) _ast_odbc_request_obj2(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__) #define ast_odbc_request_obj(a, b) _ast_odbc_request_obj(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__) -/*! - * \brief Retrieve a stored ODBC object, if a transaction has been started. - * \param chan Channel associated with the transaction. - * \param objname Name of the database handle. This name corresponds to the name passed - * to \see ast_odbc_request_obj2 (or formerly, to ast_odbc_request_obj). Note that the - * existence of this parameter name explicitly allows for multiple transactions to be open - * at once, albeit to different databases. - * \retval A stored ODBC object, if a transaction was already started. - * \retval NULL, if no transaction yet exists. - */ -struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname); - /*! * \brief Releases an ODBC object previously allocated by ast_odbc_request_obj() * \param obj The ODBC object @@ -223,4 +208,39 @@ int ast_odbc_clear_cache(const char *database, const char *tablename); */ SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind); +/*! + * \brief Shortcut for printing errors to logs after a failed SQL operation. + * + * \param handle_type The type of SQL handle on which to gather diagnostics + * \param handle The SQL handle to gather diagnostics from + * \param operation The name of the failed operation. + * \return The error string that was printed to the logs + */ +struct ast_str *ast_odbc_print_errors(SQLSMALLINT handle_type, SQLHANDLE handle, const char *operation); + +/*! + * \brief Get the transaction isolation setting for an ODBC class + */ +unsigned int ast_odbc_class_get_isolation(struct odbc_class *class); + +/*! + * \brief Get the transaction forcecommit setting for an ODBC class + */ +unsigned int ast_odbc_class_get_forcecommit(struct odbc_class *class); + +/*! + * \brief Get the name of an ODBC class. + */ +const char *ast_odbc_class_get_name(struct odbc_class *class); + +/*! + * \brief Convert from textual transaction isolation values to their numeric constants + */ +int ast_odbc_text2isolation(const char *txt); + +/*! + * \brief Convert from numeric transaction isolation values to their textual counterparts + */ +const char *ast_odbc_isolation2text(int iso); + #endif /* _ASTERISK_RES_ODBC_H */ diff --git a/include/asterisk/res_odbc_transaction.h b/include/asterisk/res_odbc_transaction.h new file mode 100644 index 00000000000..b0f9316a1cf --- /dev/null +++ b/include/asterisk/res_odbc_transaction.h @@ -0,0 +1,54 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef RES_ODBC_TRANSACTION_H +#define RES_ODBC_TRANSACTION_H + +/*! + * \brief + * + * Retrieve an ODBC transaction connection with the given ODBC class name. + * + * \note The name passed here is *not* the name of the transaction but the name of the + * ODBC class defined in res_odbc.conf. + * + * \note Do not call ast_odbc_release_obj() on the retrieved connection. Calling this function + * does not make you the owner of the connection. + * + * XXX This function is majorly flawed because it ignores properties of transactions and simply + * finds one that corresponds to the given DSN. The problem here is that transactions have names + * and they maintain which transaction is "active" for operations like transaction creation, + * commit, and rollback. However, when it comes to intermediary operations to be made on the + * transactions, all that is ignored. It means that if a channel has created multiple transactions + * for the same DSN, it's a crapshoot which of those transactions the operation will be performed + * on. This can potentially lead to baffling errors under the right circumstances. + * + * XXX The semantics of this function make for writing some awkward code. If you use func_odbc as + * an example, it has to first try to retrieve a transactional connection, then failing that, create + * a non-transactional connection. The result is that it has to remember which type of connection it's + * using and know whether to release the connection when completed or not. It would be much better + * if callers did not have to jump through such hoops. + * + * \param chan Channel on which the ODBC transaction was created + * \param objname The name of the ODBC class configured in res_odbc.conf + * \retval NULL Transaction connection could not be found. + * \retval non-NULL A transactional connection + */ +struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname); + +#endif /* RES_ODBC_TRANSACTION_H */ diff --git a/res/res_odbc.c b/res/res_odbc.c index 06009a2a5ef..609d68a4cfb 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -64,66 +64,6 @@ ASTERISK_REGISTER_FILE() #include "asterisk/threadstorage.h" #include "asterisk/data.h" -/*** DOCUMENTATION - - - Controls ODBC transaction properties. - - - - - - Gets or sets the active transaction ID. If set, and the transaction ID does not - exist and a database name is specified as an argument, it will be created. - - - Controls whether a transaction will be automatically committed when the channel - hangs up. Defaults to false. If a transaction ID is specified in the optional argument, - the property will be applied to that ID, otherwise to the current active ID. - - - Controls the data isolation on uncommitted transactions. May be one of the - following: read_committed, read_uncommitted, - repeatable_read, or serializable. Defaults to the - database setting in res_odbc.conf or read_committed - if not specified. If a transaction ID is specified as an optional argument, it will be - applied to that ID, otherwise the current active ID. - - - - - - - The ODBC() function allows setting several properties to influence how a connected - database processes transactions. - - - - - Commits a currently open database transaction. - - - - - - Commits the database transaction specified by transaction ID - or the current active transaction, if not specified. - - - - - Rollback a currently open database transaction. - - - - - - Rolls back the database transaction specified by transaction ID - or the current active transaction, if not specified. - - - ***/ - struct odbc_class { AST_LIST_ENTRY(odbc_class) list; @@ -133,21 +73,15 @@ struct odbc_class char *password; char *sanitysql; SQLHENV env; - unsigned int haspool:1; /*!< Boolean - TDS databases need this */ unsigned int delme:1; /*!< Purge the class */ unsigned int backslash_is_escape:1; /*!< On this database, the backslash is a native escape sequence */ unsigned int forcecommit:1; /*!< Should uncommitted transactions be auto-committed on handle release? */ unsigned int isolation; /*!< Flags for how the DB should deal with data in other, uncommitted transactions */ - unsigned int limit; /*!< Maximum number of database handles we will allow */ - int count; /*!< Running count of pooled connections */ - unsigned int idlecheck; /*!< Recheck the connection if it is idle for this long (in seconds) */ unsigned int conntimeout; /*!< Maximum time the connection process should take */ /*! When a connection fails, cache that failure for how long? */ struct timeval negative_connection_cache; /*! When a connection fails, when did that last occur? */ struct timeval last_negative_connect; - /*! List of handles associated with this class */ - struct ao2_container *obj_container; }; static struct ao2_container *class_container; @@ -157,16 +91,9 @@ static AST_RWLIST_HEAD_STATIC(odbc_tables, odbc_cache_tables); static odbc_status odbc_obj_connect(struct odbc_obj *obj); static odbc_status odbc_obj_disconnect(struct odbc_obj *obj); static int odbc_register_class(struct odbc_class *class, int connect); -static void odbc_txn_free(void *data); -static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx); AST_THREADSTORAGE(errors_buf); -static const struct ast_datastore_info txn_info = { - .type = "ODBC_Transaction", - .destroy = odbc_txn_free, -}; - struct odbc_txn_frame { AST_LIST_ENTRY(odbc_txn_frame) list; struct ast_channel *owner; @@ -189,13 +116,11 @@ struct odbc_txn_frame { MEMBER(odbc_class, dsn, AST_DATA_STRING) \ MEMBER(odbc_class, username, AST_DATA_STRING) \ MEMBER(odbc_class, password, AST_DATA_PASSWORD) \ - MEMBER(odbc_class, limit, AST_DATA_INTEGER) \ - MEMBER(odbc_class, count, AST_DATA_INTEGER) \ MEMBER(odbc_class, forcecommit, AST_DATA_BOOLEAN) AST_DATA_STRUCTURE(odbc_class, DATA_EXPORT_ODBC_CLASS); -static const char *isolation2text(int iso) +const char *ast_odbc_isolation2text(int iso) { if (iso == SQL_TXN_READ_COMMITTED) { return "read_committed"; @@ -210,7 +135,7 @@ static const char *isolation2text(int iso) } } -static int text2isolation(const char *txt) +int ast_odbc_text2isolation(const char *txt) { if (strncasecmp(txt, "read_", 5) == 0) { if (strncasecmp(txt + 5, "c", 1) == 0) { @@ -229,176 +154,6 @@ static int text2isolation(const char *txt) } } -static struct odbc_txn_frame *find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active) -{ - struct ast_datastore *txn_store; - AST_LIST_HEAD(, odbc_txn_frame) *oldlist; - struct odbc_txn_frame *txn = NULL; - - if (!chan && obj && obj->txf && obj->txf->owner) { - chan = obj->txf->owner; - } else if (!chan) { - /* No channel == no transaction */ - return NULL; - } - - ast_channel_lock(chan); - if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { - oldlist = txn_store->data; - } else { - /* Need to create a new datastore */ - if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) { - ast_log(LOG_ERROR, "Unable to allocate a new datastore. Cannot create a new transaction.\n"); - ast_channel_unlock(chan); - return NULL; - } - - if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) { - ast_log(LOG_ERROR, "Unable to allocate datastore list head. Cannot create a new transaction.\n"); - ast_datastore_free(txn_store); - ast_channel_unlock(chan); - return NULL; - } - - txn_store->data = oldlist; - AST_LIST_HEAD_INIT(oldlist); - ast_channel_datastore_add(chan, txn_store); - } - - AST_LIST_LOCK(oldlist); - ast_channel_unlock(chan); - - /* Scanning for an object is *fast*. Scanning for a name is much slower. */ - if (obj != NULL || active == 1) { - AST_LIST_TRAVERSE(oldlist, txn, list) { - if (txn->obj == obj || txn->active) { - AST_LIST_UNLOCK(oldlist); - return txn; - } - } - } - - if (name != NULL) { - AST_LIST_TRAVERSE(oldlist, txn, list) { - if (!strcasecmp(txn->name, name)) { - AST_LIST_UNLOCK(oldlist); - return txn; - } - } - } - - /* Nothing found, create one */ - if (name && obj && (txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1))) { - struct odbc_txn_frame *otxn; - - strcpy(txn->name, name); /* SAFE */ - txn->obj = obj; - txn->isolation = obj->parent->isolation; - txn->forcecommit = obj->parent->forcecommit; - txn->owner = chan; - txn->active = 1; - - /* On creation, the txn becomes active, and all others inactive */ - AST_LIST_TRAVERSE(oldlist, otxn, list) { - otxn->active = 0; - } - AST_LIST_INSERT_TAIL(oldlist, txn, list); - - obj->txf = txn; - obj->tx = 1; - } - AST_LIST_UNLOCK(oldlist); - - return txn; -} - -static struct odbc_txn_frame *release_transaction(struct odbc_txn_frame *tx) -{ - if (!tx) { - return NULL; - } - - ast_debug(2, "release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->obj, tx->obj ? tx->obj->txf : NULL); - - /* If we have an owner, disassociate */ - if (tx->owner) { - struct ast_datastore *txn_store; - AST_LIST_HEAD(, odbc_txn_frame) *oldlist; - - ast_channel_lock(tx->owner); - if ((txn_store = ast_channel_datastore_find(tx->owner, &txn_info, NULL))) { - oldlist = txn_store->data; - AST_LIST_LOCK(oldlist); - AST_LIST_REMOVE(oldlist, tx, list); - AST_LIST_UNLOCK(oldlist); - } - ast_channel_unlock(tx->owner); - tx->owner = NULL; - } - - if (tx->obj) { - /* If we have any uncommitted transactions, they are handled when we release the object */ - struct odbc_obj *obj = tx->obj; - /* Prevent recursion during destruction */ - tx->obj->txf = NULL; - tx->obj = NULL; - odbc_release_obj2(obj, tx); - } - ast_free(tx); - return NULL; -} - -static void odbc_txn_free(void *vdata) -{ - struct odbc_txn_frame *tx; - AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata; - - ast_debug(2, "odbc_txn_free(%p) called\n", vdata); - - AST_LIST_LOCK(oldlist); - while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) { - release_transaction(tx); - } - AST_LIST_UNLOCK(oldlist); - AST_LIST_HEAD_DESTROY(oldlist); - ast_free(oldlist); -} - -static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx) -{ - struct ast_datastore *txn_store; - AST_LIST_HEAD(, odbc_txn_frame) *oldlist; - struct odbc_txn_frame *active = NULL, *txn; - - if (!chan && tx && tx->owner) { - chan = tx->owner; - } - - if (!chan) { - return -1; - } - - ast_channel_lock(chan); - if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { - ast_channel_unlock(chan); - return -1; - } - - oldlist = txn_store->data; - AST_LIST_LOCK(oldlist); - AST_LIST_TRAVERSE(oldlist, txn, list) { - if (txn == tx) { - txn->active = 1; - active = txn; - } else { - txn->active = 0; - } - } - AST_LIST_UNLOCK(oldlist); - ast_channel_unlock(chan); - return active ? 0 : -1; -} - static void odbc_class_destructor(void *data) { struct odbc_class *class = data; @@ -414,7 +169,6 @@ static void odbc_class_destructor(void *data) if (class->sanitysql) { ast_free(class->sanitysql); } - ao2_ref(class->obj_container, -1); SQLFreeHandle(SQL_HANDLE_ENV, class->env); } @@ -451,6 +205,21 @@ static void destroy_table_cache(struct odbc_cache_tables *table) { * \retval A structure describing the table layout, or NULL, if the table is not found or another error occurs. * When a structure is returned, the contained columns list will be * rdlock'ed, to ensure that it will be retained in memory. + * + * XXX This creates a connection and disconnects it. In some situations, the caller of + * this function has its own connection and could donate it to this function instead of + * needing to create another one. + * + * XXX The automatic readlock of the columns is awkward. It's done because it's possible for + * multiple threads to have references to the table, and the table is not refcounted. Possible + * changes here would be + * * Eliminate the table cache entirely. The use of ast_odbc_find_table() is generally + * questionable. The only real good use right now is from ast_realtime_require_field() in + * order to make sure the DB has the expected columns in it. Since that is only used sparingly, + * the need to cache tables is questionable. Instead, the table structure can be fetched from + * the DB directly each time, resulting in a single owner of the data. + * * Make odbc_cache_tables a refcounted object. + * * \since 1.6.1 */ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *tablename) @@ -460,7 +229,7 @@ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char * char columnname[80]; SQLLEN sqlptr; SQLHSTMT stmt = NULL; - int res = 0, error = 0, try = 0; + int res = 0, error = 0; struct odbc_obj *obj; AST_RWLIST_RDLOCK(&odbc_tables); @@ -482,27 +251,16 @@ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char * } /* Table structure not already cached; build it now. */ - ao2_lock(obj); do { res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - if (try == 0) { - try = 1; - ast_odbc_sanity_check(obj); - continue; - } ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database); break; } res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - if (try == 0) { - try = 1; - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_sanity_check(obj); - continue; - } + SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database); break; } @@ -553,7 +311,6 @@ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char * AST_RWLIST_RDLOCK(&(tableptr->columns)); break; } while (1); - ao2_unlock(obj); AST_RWLIST_UNLOCK(&odbc_tables); @@ -595,125 +352,52 @@ int ast_odbc_clear_cache(const char *database, const char *tablename) SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT (*exec_cb)(struct odbc_obj *obj, void *data), void *data) { - int attempt; SQLHSTMT stmt; - ao2_lock(obj); - - for (attempt = 0; attempt < 2; attempt++) { - stmt = exec_cb(obj, data); - - if (stmt) { - break; - } else if (obj->tx) { - ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n"); - break; - } else if (attempt == 0) { - ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn); - } - if (!ast_odbc_sanity_check(obj)) { - break; - } - } - - ao2_unlock(obj); + stmt = exec_cb(obj, data); return stmt; } SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT (*prepare_cb)(struct odbc_obj *obj, void *data), void *data) { - int res = 0, i, attempt; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0; - unsigned char state[10], diagnostic[256]; + int res = 0; SQLHSTMT stmt; - ao2_lock(obj); - - for (attempt = 0; attempt < 2; attempt++) { - /* This prepare callback may do more than just prepare -- it may also - * bind parameters, bind results, etc. The real key, here, is that - * when we disconnect, all handles become invalid for most databases. - * We must therefore redo everything when we establish a new - * connection. */ - stmt = prepare_cb(obj, data); - - if (stmt) { - res = SQLExecute(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { - if (res == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } + /* This prepare callback may do more than just prepare -- it may also + * bind parameters, bind results, etc. The real key, here, is that + * when we disconnect, all handles become invalid for most databases. + * We must therefore redo everything when we establish a new + * connection. */ + stmt = prepare_cb(obj, data); - if (obj->tx) { - ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n"); - break; - } else { - ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - stmt = NULL; - - obj->up = 0; - /* - * While this isn't the best way to try to correct an error, this won't automatically - * fail when the statement handle invalidates. - */ - if (!ast_odbc_sanity_check(obj)) { - break; - } - continue; - } - } else { - obj->last_used = ast_tvnow(); + if (stmt) { + res = SQLExecute(stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { + if (res == SQL_ERROR) { + ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute"); } - break; - } else if (attempt == 0) { - ast_odbc_sanity_check(obj); + + ast_log(LOG_WARNING, "SQL Execute error %d!\n", res); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + stmt = NULL; } } - ao2_unlock(obj); - return stmt; } int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt) { - int res = 0, i; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0; - unsigned char state[10], diagnostic[256]; - - ao2_lock(obj); + int res = 0; res = SQLExecute(stmt); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { if (res == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } + ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute"); } - } else { - obj->last_used = ast_tvnow(); } - ao2_unlock(obj); - return res; } @@ -734,39 +418,47 @@ SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTM return res; } -int ast_odbc_sanity_check(struct odbc_obj *obj) -{ - char *test_sql = "select 1"; - SQLHSTMT stmt; - int res = 0; - - if (!ast_strlen_zero(obj->parent->sanitysql)) - test_sql = obj->parent->sanitysql; - - if (obj->up) { - res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - obj->up = 0; - } else { - res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - obj->up = 0; - } else { - res = SQLExecute(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - obj->up = 0; - } - } +struct ast_str *ast_odbc_print_errors(SQLSMALLINT handle_type, SQLHANDLE handle, const char *operation) +{ + struct ast_str *errors = ast_str_thread_get(&errors_buf, 16); + SQLINTEGER nativeerror = 0; + SQLINTEGER numfields = 0; + SQLSMALLINT diagbytes = 0; + SQLSMALLINT i; + unsigned char state[10]; + unsigned char diagnostic[256]; + + ast_str_reset(errors); + SQLGetDiagField(handle_type, handle, 1, SQL_DIAG_NUMBER, &numfields, + SQL_IS_INTEGER, &diagbytes); + for (i = 0; i < numfields; i++) { + SQLGetDiagRec(handle_type, handle, i + 1, state, &nativeerror, + diagnostic, sizeof(diagnostic), &diagbytes); + ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state); + ast_log(LOG_WARNING, "%s returned an error: %s: %s\n", operation, state, diagnostic); + /* XXX Why is this here? */ + if (i > 10) { + ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); + break; } - SQLFreeHandle (SQL_HANDLE_STMT, stmt); } - if (!obj->up && !obj->tx) { /* Try to reconnect! */ - ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); - odbc_obj_disconnect(obj); - odbc_obj_connect(obj); - } - return obj->up; + return errors; +} + +unsigned int ast_odbc_class_get_isolation(struct odbc_class *class) +{ + return class->isolation; +} + +unsigned int ast_odbc_class_get_forcecommit(struct odbc_class *class) +{ + return class->forcecommit; +} + +const char *ast_odbc_class_get_name(struct odbc_class *class) +{ + return class->name; } static int load_odbc_config(void) @@ -776,9 +468,8 @@ static int load_odbc_config(void) struct ast_variable *v; char *cat; const char *dsn, *username, *password, *sanitysql; - int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation; + int enabled, bse, conntimeout, forcecommit, isolation; struct timeval ncache = { 0, 0 }; - unsigned int idlecheck; int preconnect = 0, res = 0; struct ast_flags config_flags = { 0 }; @@ -799,33 +490,17 @@ static int load_odbc_config(void) /* Reset all to defaults for each class of odbc connections */ dsn = username = password = sanitysql = NULL; enabled = 1; - preconnect = idlecheck = 0; - pooling = 0; - limit = 0; + preconnect = 0; bse = 1; conntimeout = 10; forcecommit = 0; isolation = SQL_TXN_READ_COMMITTED; for (v = ast_variable_browse(config, cat); v; v = v->next) { - if (!strcasecmp(v->name, "pooling")) { - if (ast_true(v->value)) - pooling = 1; - } else if (!strncasecmp(v->name, "share", 5)) { - /* "shareconnections" is a little clearer in meaning than "pooling" */ - if (ast_false(v->value)) - pooling = 1; - } else if (!strcasecmp(v->name, "limit")) { - sscanf(v->value, "%30d", &limit); - if (ast_true(v->value) && !limit) { - ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Setting limit to 1023 for ODBC class '%s'.\n", v->value, cat); - limit = 1023; - } else if (ast_false(v->value)) { - ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); - enabled = 0; - break; - } - } else if (!strcasecmp(v->name, "idlecheck")) { - sscanf(v->value, "%30u", &idlecheck); + if (!strcasecmp(v->name, "pooling") || + !strncasecmp(v->name, "share", 5) || + !strcasecmp(v->name, "limit") || + !strcasecmp(v->name, "idlecheck")) { + ast_log(LOG_WARNING, "The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options are deprecated. Please see UPGRADE.txt for information"); } else if (!strcasecmp(v->name, "enabled")) { enabled = ast_true(v->value); } else if (!strcasecmp(v->name, "pre-connect")) { @@ -859,7 +534,7 @@ static int load_odbc_config(void) } else if (!strcasecmp(v->name, "forcecommit")) { forcecommit = ast_true(v->value); } else if (!strcasecmp(v->name, "isolation")) { - if ((isolation = text2isolation(v->value)) == 0) { + if ((isolation = ast_odbc_text2isolation(v->value)) == 0) { ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat); isolation = SQL_TXN_READ_COMMITTED; } @@ -883,22 +558,9 @@ static int load_odbc_config(void) return res; } - new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr); - - if (pooling) { - new->haspool = pooling; - if (limit) { - new->limit = limit; - } else { - ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); - new->limit = 5; - } - } - new->backslash_is_escape = bse ? 1 : 0; new->forcecommit = forcecommit ? 1 : 0; new->isolation = isolation; - new->idlecheck = idlecheck; new->conntimeout = conntimeout; new->negative_connection_cache = ncache; @@ -934,7 +596,6 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c { struct ao2_iterator aoi; struct odbc_class *class; - struct odbc_obj *current; int length = 0; int which = 0; char *ret = NULL; @@ -973,7 +634,6 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c aoi = ao2_iterator_init(class_container, 0); while ((class = ao2_iterator_next(&aoi))) { if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) { - int count = 0; char timestr[80]; struct ast_tm tm; @@ -981,38 +641,6 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm); ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn); ast_cli(a->fd, " Last connection attempt: %s\n", timestr); - - if (class->haspool) { - struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0); - - ast_cli(a->fd, " Pooled: Yes\n Limit: %u\n Connections in use: %d\n", class->limit, class->count); - - while ((current = ao2_iterator_next(&aoi2))) { - ao2_lock(current); -#ifdef DEBUG_THREADS - ast_cli(a->fd, " - Connection %d: %s (%s:%d %s)\n", ++count, - current->used ? "in use" : - current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected", - current->file, current->lineno, current->function); -#else - ast_cli(a->fd, " - Connection %d: %s\n", ++count, - current->used ? "in use" : - current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); -#endif - ao2_unlock(current); - ao2_ref(current, -1); - } - ao2_iterator_destroy(&aoi2); - } else { - /* Should only ever be one of these (unless there are transactions) */ - struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0); - while ((current = ao2_iterator_next(&aoi2))) { - ast_cli(a->fd, " Pooled: No\n Connected: %s\n", current->used ? "In use" : - current->up && ast_odbc_sanity_check(current) ? "Yes" : "No"); - ao2_ref(current, -1); - } - ao2_iterator_destroy(&aoi2); - } ast_cli(a->fd, "\n"); } ao2_ref(class, -1); @@ -1048,150 +676,23 @@ static int odbc_register_class(struct odbc_class *class, int preconnect) } } -static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx) +void ast_odbc_release_obj(struct odbc_obj *obj) { - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0, i; - unsigned char state[10], diagnostic[256]; - - ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf); - if (tx) { - ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK"); - if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) { - /* Handle possible transaction commit failure */ - SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic); - if (!strcmp((char *)state, "25S02") || !strcmp((char *)state, "08007")) { - /* These codes mean that a commit failed and a transaction - * is still active. We must rollback, or things will get - * very, very weird for anybody using the handle next. */ - SQLEndTran(SQL_HANDLE_DBC, obj->con, SQL_ROLLBACK); - } - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } - - /* Transaction is done, reset autocommit */ - if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } - } + ast_debug(2, "Releasing ODBC handle %p\n", obj); #ifdef DEBUG_THREADS obj->file[0] = '\0'; obj->function[0] = '\0'; obj->lineno = 0; #endif - - /* For pooled connections, this frees the connection to be - * reused. For non-pooled connections, it does nothing. */ - obj->used = 0; - if (obj->txf) { - /* Prevent recursion -- transaction is already closed out. */ - obj->txf->obj = NULL; - obj->txf = release_transaction(obj->txf); - } ao2_ref(obj, -1); } -void ast_odbc_release_obj(struct odbc_obj *obj) -{ - struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0); - odbc_release_obj2(obj, tx); -} - int ast_odbc_backslash_is_escape(struct odbc_obj *obj) { return obj->parent->backslash_is_escape; } -static int commit_exec(struct ast_channel *chan, const char *data) -{ - struct odbc_txn_frame *tx; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0, i; - unsigned char state[10], diagnostic[256]; - - if (ast_strlen_zero(data)) { - tx = find_transaction(chan, NULL, NULL, 1); - } else { - tx = find_transaction(chan, NULL, data, 0); - } - - pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK"); - - if (tx) { - if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) { - struct ast_str *errors = ast_str_thread_get(&errors_buf, 16); - ast_str_reset(errors); - - /* Handle possible transaction commit failure */ - SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state); - ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors)); - } - } - return 0; -} - -static int rollback_exec(struct ast_channel *chan, const char *data) -{ - struct odbc_txn_frame *tx; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0, i; - unsigned char state[10], diagnostic[256]; - - if (ast_strlen_zero(data)) { - tx = find_transaction(chan, NULL, NULL, 1); - } else { - tx = find_transaction(chan, NULL, data, 0); - } - - pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK"); - - if (tx) { - if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) { - struct ast_str *errors = ast_str_thread_get(&errors_buf, 16); - ast_str_reset(errors); - - /* Handle possible transaction commit failure */ - SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state); - ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors)); - } - } - return 0; -} - static int aoro2_class_cb(void *obj, void *arg, int flags) { struct odbc_class *class = obj; @@ -1202,275 +703,41 @@ static int aoro2_class_cb(void *obj, void *arg, int flags) return 0; } -#define USE_TX (void *)(long)1 -#define NO_TX (void *)(long)2 -#define EOR_TX (void *)(long)3 - -static int aoro2_obj_cb(void *vobj, void *arg, int flags) -{ - struct odbc_obj *obj = vobj; - ao2_lock(obj); - if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) { - obj->used = 1; - ao2_unlock(obj); - return CMP_MATCH | CMP_STOP; - } - ao2_unlock(obj); - return 0; -} - -/* This function should only be called for shared connections. Otherwise, the lack of - * setting vobj->used breaks EOR_TX searching. For nonshared connections, use - * aoro2_obj_cb instead. */ -static int aoro2_obj_notx_cb(void *vobj, void *arg, int flags) -{ - struct odbc_obj *obj = vobj; - if (!obj->tx) { - return CMP_MATCH | CMP_STOP; - } - return 0; -} - struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno) { struct odbc_obj *obj = NULL; struct odbc_class *class; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0, i; - unsigned char state[10], diagnostic[256]; if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) { ast_debug(1, "Class '%s' not found!\n", name); return NULL; } - ast_assert(ao2_ref(class, 0) > 1); - - if (class->haspool) { - /* Recycle connections before building another */ - obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX); - - if (obj) { - ast_assert(ao2_ref(obj, 0) > 1); - } - if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit)) { - obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); - if (!obj) { - class->count--; - ao2_ref(class, -1); - ast_debug(3, "Unable to allocate object\n"); - ast_atomic_fetchadd_int(&class->count, -1); - return NULL; - } - ast_assert(ao2_ref(obj, 0) == 1); - /* obj inherits the outstanding reference to class */ - obj->parent = class; - class = NULL; - if (odbc_obj_connect(obj) == ODBC_FAIL) { - ast_log(LOG_WARNING, "Failed to connect to %s\n", name); - ast_assert(ao2_ref(obj->parent, 0) > 0); - /* Because it was never within the container, we have to manually decrement the count here */ - ast_atomic_fetchadd_int(&obj->parent->count, -1); - ao2_ref(obj, -1); - obj = NULL; - } else { - obj->used = 1; - ao2_link(obj->parent->obj_container, obj); - } - } else { - /* If construction fails due to the limit (or negative timecache), reverse our increment. */ - if (!obj) { - ast_atomic_fetchadd_int(&class->count, -1); - } - /* Object is not constructed, so delete outstanding reference to class. */ - ao2_ref(class, -1); - class = NULL; - } - - if (!obj) { - return NULL; - } - - ao2_lock(obj); - - if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { - /* Ensure this connection has autocommit turned off. */ - if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } - } - } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { - /* Non-pooled connections -- but must use a separate connection handle */ - if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) { - ast_debug(1, "Object not found\n"); - obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); - if (!obj) { - ao2_ref(class, -1); - ast_debug(3, "Unable to allocate object\n"); - return NULL; - } - /* obj inherits the outstanding reference to class */ - obj->parent = class; - class = NULL; - if (odbc_obj_connect(obj) == ODBC_FAIL) { - ast_log(LOG_WARNING, "Failed to connect to %s\n", name); - ao2_ref(obj, -1); - obj = NULL; - } else { - obj->used = 1; - ao2_link(obj->parent->obj_container, obj); - ast_atomic_fetchadd_int(&obj->parent->count, +1); - } - } - - if (!obj) { - return NULL; - } - - ao2_lock(obj); - - if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } - } else { - /* Non-pooled connection: multiple modules can use the same connection. */ - if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_notx_cb, NO_TX))) { - /* Object is not constructed, so delete outstanding reference to class. */ - ast_assert(ao2_ref(class, 0) > 1); - ao2_ref(class, -1); - class = NULL; - } else { - /* No entry: build one */ - if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) { - ast_assert(ao2_ref(class, 0) > 1); - ao2_ref(class, -1); - ast_debug(3, "Unable to allocate object\n"); - return NULL; - } - /* obj inherits the outstanding reference to class */ - obj->parent = class; - class = NULL; - if (odbc_obj_connect(obj) == ODBC_FAIL) { - ast_log(LOG_WARNING, "Failed to connect to %s\n", name); - ao2_ref(obj, -1); - obj = NULL; - } else { - ao2_link(obj->parent->obj_container, obj); - ast_assert(ao2_ref(obj, 0) > 1); - } - } - - if (!obj) { - return NULL; - } - - ao2_lock(obj); - - if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } - } - - ast_assert(obj != NULL); - - /* Set the isolation property */ - if (SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } - - if (ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) { - odbc_obj_connect(obj); - } else if (ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) { - ast_odbc_sanity_check(obj); - } else if (obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) { - odbc_obj_connect(obj); + /* XXX ODBC connection objects do not have shared ownership, so there is no reason + * to use refcounted objects here. + */ + obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); + /* Inherit reference from the ao2_callback from before */ + obj->parent = class; + if (odbc_obj_connect(obj) == ODBC_FAIL) { + ao2_ref(obj, -1); + return NULL; } -#ifdef DEBUG_THREADS - ast_copy_string(obj->file, file, sizeof(obj->file)); - ast_copy_string(obj->function, function, sizeof(obj->function)); - obj->lineno = lineno; -#endif - - /* We had it locked because of the obj_connects we see here. */ - ao2_unlock(obj); - - ast_assert(class == NULL); - - ast_assert(ao2_ref(obj, 0) > 1); return obj; } struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno) { struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 }; + /* XXX New flow means that the "check" parameter doesn't do anything. We're requesting + * a connection from ODBC. We'll either get a new one, which obviously is already connected, or + * we'll get one from the ODBC connection pool. In that case, it will ensure to only give us a + * live connection + */ return _ast_odbc_request_obj2(name, flags, file, function, lineno); } -struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname) -{ - struct ast_datastore *txn_store; - AST_LIST_HEAD(, odbc_txn_frame) *oldlist; - struct odbc_txn_frame *txn = NULL; - - if (!chan) { - /* No channel == no transaction */ - return NULL; - } - - ast_channel_lock(chan); - if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { - oldlist = txn_store->data; - } else { - ast_channel_unlock(chan); - return NULL; - } - - AST_LIST_LOCK(oldlist); - ast_channel_unlock(chan); - - AST_LIST_TRAVERSE(oldlist, txn, list) { - if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) { - AST_LIST_UNLOCK(oldlist); - return txn->obj; - } - } - AST_LIST_UNLOCK(oldlist); - return NULL; -} - static odbc_status odbc_obj_disconnect(struct odbc_obj *obj) { int res; @@ -1490,20 +757,19 @@ static odbc_status odbc_obj_disconnect(struct odbc_obj *obj) if (obj->parent) { if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) { - ast_debug(1, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn); + ast_debug(3, "Disconnected %d from %s [%s](%p)\n", res, obj->parent->name, obj->parent->dsn, obj); } else { - ast_debug(1, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn); + ast_debug(3, "res_odbc: %s [%s](%p) already disconnected\n", obj->parent->name, obj->parent->dsn, obj); } } if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) == SQL_SUCCESS) { - ast_debug(1, "Database handle %p deallocated\n", con); + ast_debug(3, "Database handle %p (connection %p) deallocated\n", obj, con); } else { SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen); ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg); } - obj->up = 0; return ODBC_SUCCESS; } @@ -1520,13 +786,8 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj) SQLHDBC con; long int negative_cache_expiration; - if (obj->up) { - odbc_obj_disconnect(obj); - ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name); - } else { - ast_assert(obj->con == NULL); - ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name); - } + ast_assert(obj->con == NULL); + ast_debug(3, "Connecting %s(%p)\n", obj->parent->name, obj); /* Dont connect while server is marked as unreachable via negative_connection_cache */ negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec; @@ -1564,155 +825,13 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj) } return ODBC_FAIL; } else { - ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn); - obj->up = 1; - obj->last_used = ast_tvnow(); + ast_debug(3, "res_odbc: Connected to %s [%s (%p)]\n", obj->parent->name, obj->parent->dsn, obj); } obj->con = con; return ODBC_SUCCESS; } -static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) -{ - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(property); - AST_APP_ARG(opt); - ); - struct odbc_txn_frame *tx; - - AST_STANDARD_APP_ARGS(args, data); - if (strcasecmp(args.property, "transaction") == 0) { - if ((tx = find_transaction(chan, NULL, NULL, 1))) { - ast_copy_string(buf, tx->name, len); - return 0; - } - } else if (strcasecmp(args.property, "isolation") == 0) { - if (!ast_strlen_zero(args.opt)) { - tx = find_transaction(chan, NULL, args.opt, 0); - } else { - tx = find_transaction(chan, NULL, NULL, 1); - } - if (tx) { - ast_copy_string(buf, isolation2text(tx->isolation), len); - return 0; - } - } else if (strcasecmp(args.property, "forcecommit") == 0) { - if (!ast_strlen_zero(args.opt)) { - tx = find_transaction(chan, NULL, args.opt, 0); - } else { - tx = find_transaction(chan, NULL, NULL, 1); - } - if (tx) { - ast_copy_string(buf, tx->forcecommit ? "1" : "0", len); - return 0; - } - } - return -1; -} - -static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value) -{ - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(property); - AST_APP_ARG(opt); - ); - struct odbc_txn_frame *tx; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0, i; - unsigned char state[10], diagnostic[256]; - - AST_STANDARD_APP_ARGS(args, s); - if (strcasecmp(args.property, "transaction") == 0) { - /* Set active transaction */ - struct odbc_obj *obj; - if ((tx = find_transaction(chan, NULL, value, 0))) { - mark_transaction_active(chan, tx); - } else { - /* No such transaction, create one */ - struct ast_flags flags = { RES_ODBC_INDEPENDENT_CONNECTION }; - if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) { - ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, "")); - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB"); - return -1; - } - if (!find_transaction(chan, obj, value, 0)) { - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); - return -1; - } - obj->tx = 1; - } - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); - return 0; - } else if (strcasecmp(args.property, "forcecommit") == 0) { - /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */ - if (ast_strlen_zero(args.opt)) { - tx = find_transaction(chan, NULL, NULL, 1); - } else { - tx = find_transaction(chan, NULL, args.opt, 0); - } - if (!tx) { - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); - return -1; - } - if (ast_true(value)) { - tx->forcecommit = 1; - } else if (ast_false(value)) { - tx->forcecommit = 0; - } else { - ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, "")); - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE"); - return -1; - } - - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); - return 0; - } else if (strcasecmp(args.property, "isolation") == 0) { - /* How do uncommitted transactions affect reads? */ - int isolation = text2isolation(value); - if (ast_strlen_zero(args.opt)) { - tx = find_transaction(chan, NULL, NULL, 1); - } else { - tx = find_transaction(chan, NULL, args.opt, 0); - } - if (!tx) { - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); - return -1; - } - if (isolation == 0) { - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE"); - ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, "")); - } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) { - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR"); - SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i = 0; i < numfields; i++) { - SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } else { - pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); - tx->isolation = isolation; - } - return 0; - } else { - ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property); - return -1; - } -} - -static struct ast_custom_function odbc_function = { - .name = "ODBC", - .read = acf_transaction_read, - .write = acf_transaction_write, -}; - -static const char * const app_commit = "ODBC_Commit"; -static const char * const app_rollback = "ODBC_Rollback"; - /*! * \internal * \brief Implements the channels provider. @@ -1720,12 +839,10 @@ static const char * const app_rollback = "ODBC_Rollback"; static int data_odbc_provider_handler(const struct ast_data_search *search, struct ast_data *root) { - struct ao2_iterator aoi, aoi2; + struct ao2_iterator aoi; struct odbc_class *class; - struct odbc_obj *current; - struct ast_data *data_odbc_class, *data_odbc_connections, *data_odbc_connection; + struct ast_data *data_odbc_class, *data_odbc_connections; struct ast_data *enum_node; - int count; aoi = ao2_iterator_init(class_container, 0); while ((class = ao2_iterator_next(&aoi))) { @@ -1737,18 +854,12 @@ static int data_odbc_provider_handler(const struct ast_data_search *search, ast_data_add_structure(odbc_class, data_odbc_class, class); - if (!ao2_container_count(class->obj_container)) { - ao2_ref(class, -1); - continue; - } - data_odbc_connections = ast_data_add_node(data_odbc_class, "connections"); if (!data_odbc_connections) { ao2_ref(class, -1); continue; } - ast_data_add_bool(data_odbc_class, "shared", !class->haspool); /* isolation */ enum_node = ast_data_add_node(data_odbc_class, "isolation"); if (!enum_node) { @@ -1756,30 +867,7 @@ static int data_odbc_provider_handler(const struct ast_data_search *search, continue; } ast_data_add_int(enum_node, "value", class->isolation); - ast_data_add_str(enum_node, "text", isolation2text(class->isolation)); - - count = 0; - aoi2 = ao2_iterator_init(class->obj_container, 0); - while ((current = ao2_iterator_next(&aoi2))) { - data_odbc_connection = ast_data_add_node(data_odbc_connections, "connection"); - if (!data_odbc_connection) { - ao2_ref(current, -1); - continue; - } - - ao2_lock(current); - ast_data_add_str(data_odbc_connection, "status", current->used ? "in use" : - current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); - ast_data_add_bool(data_odbc_connection, "transactional", current->tx); - ao2_unlock(current); - - if (class->haspool) { - ast_data_add_int(data_odbc_connection, "number", ++count); - } - - ao2_ref(current, -1); - } - ao2_iterator_destroy(&aoi2); + ast_data_add_str(enum_node, "text", ast_odbc_isolation2text(class->isolation)); ao2_ref(class, -1); if (!ast_data_search_match(search, data_odbc_class)) { @@ -1807,7 +895,6 @@ static int reload(void) { struct odbc_cache_tables *table; struct odbc_class *class; - struct odbc_obj *current; struct ao2_iterator aoi = ao2_iterator_init(class_container, 0); /* First, mark all to be purged */ @@ -1819,51 +906,12 @@ static int reload(void) load_odbc_config(); - /* Purge remaining classes */ - - /* Note on how this works; this is a case of circular references, so we - * explicitly do NOT want to use a callback here (or we wind up in - * recursive hell). - * - * 1. Iterate through all the classes. Note that the classes will currently - * contain two classes of the same name, one of which is marked delme and - * will be purged when all remaining objects of the class are released, and - * the other, which was created above when we re-parsed the config file. - * 2. On each class, there is a reference held by the master container and - * a reference held by each connection object. There are two cases for - * destruction of the class, noted below. However, in all cases, all O-refs - * (references to objects) will first be freed, which will cause the C-refs - * (references to classes) to be decremented (but never to 0, because the - * class container still has a reference). - * a) If the class has outstanding objects, the C-ref by the class - * container will then be freed, which leaves only C-refs by any - * outstanding objects. When the final outstanding object is released - * (O-refs held by applications and dialplan functions), it will in turn - * free the final C-ref, causing class destruction. - * b) If the class has no outstanding objects, when the class container - * removes the final C-ref, the class will be destroyed. - */ aoi = ao2_iterator_init(class_container, 0); - while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */ + while ((class = ao2_iterator_next(&aoi))) { if (class->delme) { - struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0); - while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */ - ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */ - ao2_ref(current, -1); /* O-ref-- (by iterator) */ - /* At this point, either - * a) there's an outstanding O-ref, or - * b) the object has already been destroyed. - */ - } - ao2_iterator_destroy(&aoi2); - ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */ - /* At this point, either - * a) there's an outstanding O-ref, which holds an outstanding C-ref, or - * b) the last remaining C-ref is held by the iterator, which will be - * destroyed in the next step. - */ + ao2_unlink(class_container, class); } - ao2_ref(class, -1); /* C-ref-- (by iterator) */ + ao2_ref(class, -1); } ao2_iterator_destroy(&aoi); @@ -1901,9 +949,6 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; ast_cli_register_multiple(cli_odbc, ARRAY_LEN(cli_odbc)); ast_data_register_multiple(odbc_providers, ARRAY_LEN(odbc_providers)); - ast_register_application_xml(app_commit, commit_exec); - ast_register_application_xml(app_rollback, rollback_exec); - ast_custom_function_register(&odbc_function); ast_log(LOG_NOTICE, "res_odbc loaded.\n"); return 0; } diff --git a/res/res_odbc.exports.in b/res/res_odbc.exports.in index ad674beb178..84bbc48dd7b 100644 --- a/res/res_odbc.exports.in +++ b/res/res_odbc.exports.in @@ -12,9 +12,13 @@ LINKER_SYMBOL_PREFIX_ast_odbc_request_obj; LINKER_SYMBOL_PREFIXast_odbc_request_obj2; LINKER_SYMBOL_PREFIX_ast_odbc_request_obj2; - LINKER_SYMBOL_PREFIXast_odbc_retrieve_transaction_obj; LINKER_SYMBOL_PREFIXast_odbc_sanity_check; LINKER_SYMBOL_PREFIXast_odbc_smart_execute; + LINKER_SYMBOL_PREFIXast_odbc_class_get_isolation; + LINKER_SYMBOL_PREFIXast_odbc_class_get_forcecommit; + LINKER_SYMBOL_PREFIXast_odbc_class_get_name; + LINKER_SYMBOL_PREFIXast_odbc_text2isolation; + LINKER_SYMBOL_PREFIXast_odbc_isolation2text; local: *; }; diff --git a/res/res_odbc_transaction.c b/res/res_odbc_transaction.c new file mode 100644 index 00000000000..33800c3ce31 --- /dev/null +++ b/res/res_odbc_transaction.c @@ -0,0 +1,529 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include "asterisk.h" + +#include "asterisk/res_odbc.h" +#include "asterisk/res_odbc_transaction.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/app.h" +#include "asterisk/module.h" + +/*** MODULEINFO + res_odbc + core + ***/ + +/*** DOCUMENTATION + + + Controls ODBC transaction properties. + + + + + + Gets or sets the active transaction ID. If set, and the transaction ID does not + exist and a database name is specified as an argument, it will be created. + + + Controls whether a transaction will be automatically committed when the channel + hangs up. Defaults to false. If a transaction ID is specified in the optional argument, + the property will be applied to that ID, otherwise to the current active ID. + + + Controls the data isolation on uncommitted transactions. May be one of the + following: read_committed, read_uncommitted, + repeatable_read, or serializable. Defaults to the + database setting in res_odbc.conf or read_committed + if not specified. If a transaction ID is specified as an optional argument, it will be + applied to that ID, otherwise the current active ID. + + + + + + + The ODBC() function allows setting several properties to influence how a connected + database processes transactions. + + + + + Commits a currently open database transaction. + + + + + + Commits the database transaction specified by transaction ID + or the current active transaction, if not specified. + + + + + Rollback a currently open database transaction. + + + + + + Rolls back the database transaction specified by transaction ID + or the current active transaction, if not specified. + + + ***/ + +struct odbc_txn_frame { + AST_LIST_ENTRY(odbc_txn_frame) list; + struct odbc_obj *obj; /*!< Database handle within which transacted statements are run */ + /*!\brief Is this record the current active transaction within the channel? + * Note that the active flag is really only necessary for statements which + * are triggered from the dialplan, as there isn't a direct correlation + * between multiple statements. Applications wishing to use transactions + * may simply perform each statement on the same odbc_obj, which keeps the + * transaction persistent. + */ + unsigned int active:1; + unsigned int forcecommit:1; /*!< Should uncommitted transactions be auto-committed on handle release? */ + unsigned int isolation; /*!< Flags for how the DB should deal with data in other, uncommitted transactions */ + char name[0]; /*!< Name of this transaction ID */ +}; + +static struct odbc_txn_frame *release_transaction(struct odbc_txn_frame *tx); + +static void odbc_txn_free(void *vdata) +{ + struct odbc_txn_frame *tx; + AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata; + + ast_debug(2, "odbc_txn_free(%p) called\n", vdata); + + AST_LIST_LOCK(oldlist); + while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) { + release_transaction(tx); + } + AST_LIST_UNLOCK(oldlist); + AST_LIST_HEAD_DESTROY(oldlist); + ast_free(oldlist); +} + +static const struct ast_datastore_info txn_info = { + .type = "ODBC_Transaction", + .destroy = odbc_txn_free, +}; + +static struct odbc_txn_frame *create_transaction(struct ast_channel *chan, const char *name, const char *dsn) +{ + struct ast_datastore *txn_store; + AST_LIST_HEAD(, odbc_txn_frame) *oldlist; + struct odbc_txn_frame *txn = NULL; + struct odbc_txn_frame *otxn; + + if (ast_strlen_zero(dsn)) { + return NULL; + } + + ast_channel_lock(chan); + if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { + oldlist = txn_store->data; + } else { + if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) { + ast_log(LOG_ERROR, "Unable to allocate a new datastore. Cannot create a new transaction.\n"); + ast_channel_unlock(chan); + return NULL; + } + + if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) { + ast_log(LOG_ERROR, "Unable to allocate datastore list head. Cannot create a new transaction.\n"); + ast_datastore_free(txn_store); + ast_channel_unlock(chan); + return NULL; + } + + txn_store->data = oldlist; + AST_LIST_HEAD_INIT(oldlist); + ast_channel_datastore_add(chan, txn_store); + } + ast_channel_unlock(chan); + + txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1); + if (!txn) { + return NULL; + } + + strcpy(txn->name, name); /* SAFE */ + txn->obj = ast_odbc_request_obj(dsn, 0); + if (!txn->obj) { + ast_free(txn); + return NULL; + } + txn->isolation = ast_odbc_class_get_isolation(txn->obj->parent); + txn->forcecommit = ast_odbc_class_get_isolation(txn->obj->parent); + txn->active = 1; + + if (SQLSetConnectAttr(txn->obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { + ast_odbc_print_errors(SQL_HANDLE_DBC, txn->obj->con, "SetConnectAttr (Autocommit)"); + ast_odbc_release_obj(txn->obj); + ast_free(txn); + return NULL; + } + + /* Set the isolation property */ + if (SQLSetConnectAttr(txn->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)txn->isolation, 0) == SQL_ERROR) { + ast_odbc_print_errors(SQL_HANDLE_DBC, txn->obj->con, "SetConnectAttr"); + ast_odbc_release_obj(txn->obj); + ast_free(txn); + return NULL; + } + + /* On creation, the txn becomes active, and all others inactive */ + AST_LIST_LOCK(oldlist); + AST_LIST_TRAVERSE(oldlist, otxn, list) { + otxn->active = 0; + } + AST_LIST_INSERT_TAIL(oldlist, txn, list); + AST_LIST_UNLOCK(oldlist); + + return txn; +} + +static struct odbc_txn_frame *find_transaction(struct ast_channel *chan, const char *name, int active) +{ + struct ast_datastore *txn_store; + AST_LIST_HEAD(, odbc_txn_frame) *oldlist; + struct odbc_txn_frame *txn = NULL; + + if (!chan || (!active && !name)) { + return NULL; + } + + ast_channel_lock(chan); + txn_store = ast_channel_datastore_find(chan, &txn_info, NULL); + ast_channel_unlock(chan); + + if (!txn_store) { + /* No datastore? Definitely no transaction then */ + return NULL; + } + + oldlist = txn_store->data; + AST_LIST_LOCK(oldlist); + + AST_LIST_TRAVERSE(oldlist, txn, list) { + if (active) { + if (txn->active) { + break; + } + } else if (!strcasecmp(txn->name, name)) { + break; + } + } + AST_LIST_UNLOCK(oldlist); + + return txn; +} + +static struct odbc_txn_frame *release_transaction(struct odbc_txn_frame *tx) +{ + if (!tx) { + return NULL; + } + + ast_debug(2, "release_transaction(%p) called (tx->obj = %p\n", tx, tx->obj); + + ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK"); + if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) { + ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran"); + } + + /* Transaction is done, reset autocommit + * + * XXX I'm unsure if this is actually necessary, since we're releasing + * the connection back to unixODBC. However, if unixODBC pooling is enabled, + * it can't hurt to do just in case. + */ + if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { + ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLSetAttr"); + } + + ast_odbc_release_obj(tx->obj); + ast_free(tx); + return NULL; +} + +static int commit_exec(struct ast_channel *chan, const char *data) +{ + struct odbc_txn_frame *tx; + + if (ast_strlen_zero(data)) { + tx = find_transaction(chan, NULL, 1); + } else { + tx = find_transaction(chan, data, 0); + } + + /* XXX COMMIT_RESULT is set to OK even if no transaction was found. Very misleading */ + pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK"); + + if (tx) { + if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) { + struct ast_str *errors = ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran"); + pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors)); + } + } + return 0; +} + +static int rollback_exec(struct ast_channel *chan, const char *data) +{ + struct odbc_txn_frame *tx; + + if (ast_strlen_zero(data)) { + tx = find_transaction(chan, NULL, 1); + } else { + tx = find_transaction(chan, data, 0); + } + + /* XXX ROLLBACK_RESULT is set to OK even if no transaction was found. Very misleading */ + pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK"); + + if (tx) { + if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) { + struct ast_str *errors = ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran"); + pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors)); + } + } + return 0; +} + +static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(property); + AST_APP_ARG(opt); + ); + struct odbc_txn_frame *tx; + + AST_STANDARD_APP_ARGS(args, data); + if (strcasecmp(args.property, "transaction") == 0) { + if ((tx = find_transaction(chan, NULL, 1))) { + ast_copy_string(buf, tx->name, len); + return 0; + } + } else if (strcasecmp(args.property, "isolation") == 0) { + if (!ast_strlen_zero(args.opt)) { + tx = find_transaction(chan, args.opt, 0); + } else { + tx = find_transaction(chan, NULL, 1); + } + if (tx) { + ast_copy_string(buf, ast_odbc_isolation2text(tx->isolation), len); + return 0; + } + } else if (strcasecmp(args.property, "forcecommit") == 0) { + if (!ast_strlen_zero(args.opt)) { + tx = find_transaction(chan, args.opt, 0); + } else { + tx = find_transaction(chan, NULL, 1); + } + if (tx) { + ast_copy_string(buf, tx->forcecommit ? "1" : "0", len); + return 0; + } + } + return -1; +} + +/* XXX The idea of "active" transactions is silly and makes things + * more prone to error. It would be much better if the transaction + * always had to be specified by name so that no implicit behavior + * occurred. + */ +static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx) +{ + struct ast_datastore *txn_store; + AST_LIST_HEAD(, odbc_txn_frame) *oldlist; + struct odbc_txn_frame *active = NULL, *txn; + + if (!chan) { + return -1; + } + + ast_channel_lock(chan); + if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { + ast_channel_unlock(chan); + return -1; + } + + oldlist = txn_store->data; + AST_LIST_LOCK(oldlist); + AST_LIST_TRAVERSE(oldlist, txn, list) { + if (txn == tx) { + txn->active = 1; + active = txn; + } else { + txn->active = 0; + } + } + AST_LIST_UNLOCK(oldlist); + ast_channel_unlock(chan); + return active ? 0 : -1; +} + +static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(property); + AST_APP_ARG(opt); + ); + struct odbc_txn_frame *tx; + + AST_STANDARD_APP_ARGS(args, s); + if (strcasecmp(args.property, "transaction") == 0) { + /* Set active transaction */ + if ((tx = find_transaction(chan, value, 0))) { + mark_transaction_active(chan, tx); + } else if (!create_transaction(chan, value, args.opt)) { + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); + return -1; + } + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); + return 0; + } else if (strcasecmp(args.property, "forcecommit") == 0) { + /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */ + if (ast_strlen_zero(args.opt)) { + tx = find_transaction(chan, NULL, 1); + } else { + tx = find_transaction(chan, args.opt, 0); + } + if (!tx) { + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); + return -1; + } + if (ast_true(value)) { + tx->forcecommit = 1; + } else if (ast_false(value)) { + tx->forcecommit = 0; + } else { + ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, "")); + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE"); + return -1; + } + + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); + return 0; + } else if (strcasecmp(args.property, "isolation") == 0) { + /* How do uncommitted transactions affect reads? */ + /* XXX This is completely useless. The problem is that setting the isolation here + * does not actually alter the connection. The only time the isolation gets set is + * when the transaction is created. The only way to set isolation is to set it on + * the ODBC class's configuration in res_odbc.conf. + */ + int isolation = ast_odbc_text2isolation(value); + if (ast_strlen_zero(args.opt)) { + tx = find_transaction(chan, NULL, 1); + } else { + tx = find_transaction(chan, args.opt, 0); + } + if (!tx) { + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); + return -1; + } + if (isolation == 0) { + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE"); + ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, "")); + } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) { + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR"); + ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SetConnectAttr (Txn isolation)"); + } else { + pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); + tx->isolation = isolation; + } + return 0; + } else { + ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property); + return -1; + } +} + +struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname) +{ + struct ast_datastore *txn_store; + AST_LIST_HEAD(, odbc_txn_frame) *oldlist; + struct odbc_txn_frame *txn = NULL; + + if (!chan || !objname) { + /* No channel == no transaction */ + return NULL; + } + + ast_channel_lock(chan); + if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { + oldlist = txn_store->data; + } else { + ast_channel_unlock(chan); + return NULL; + } + + AST_LIST_LOCK(oldlist); + ast_channel_unlock(chan); + + AST_LIST_TRAVERSE(oldlist, txn, list) { + if (txn->obj && txn->obj->parent && !strcmp(ast_odbc_class_get_name(txn->obj->parent), objname)) { + AST_LIST_UNLOCK(oldlist); + return txn->obj; + } + } + AST_LIST_UNLOCK(oldlist); + return NULL; +} + +static struct ast_custom_function odbc_function = { + .name = "ODBC", + .read = acf_transaction_read, + .write = acf_transaction_write, +}; + +static const char * const app_commit = "ODBC_Commit"; +static const char * const app_rollback = "ODBC_Rollback"; + +/* XXX res_odbc takes the path of disallowing unloads from happening. + * It's not a great precedent, but since trying to deal with unloading the module + * while transactions are active seems like a huge pain to deal with, we'll go + * the same way here. + */ +static int unload_module(void) +{ + return -1; +} + +static int load_module(void) +{ + ast_register_application_xml(app_commit, commit_exec); + ast_register_application_xml(app_rollback, rollback_exec); + ast_custom_function_register(&odbc_function); + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "ODBC transaction resource", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_REALTIME_DEPEND, + ); diff --git a/res/res_odbc_transaction.exports.in b/res/res_odbc_transaction.exports.in new file mode 100644 index 00000000000..5b061554712 --- /dev/null +++ b/res/res_odbc_transaction.exports.in @@ -0,0 +1,6 @@ +{ + global: + LINKER_SYMBOL_PREFIXast_odbc_retrieve_transaction_obj; + local: + *; +}; From 7866806fc3bbb716064fb9e4e0a1436e3325a637 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 22 Jan 2016 11:48:24 -0600 Subject: [PATCH 0167/1578] logger.c: Fix buffer overrun found by address sanitizer. The null terminator of the tail struct member was not being allocated when no logger.conf config file is installed. ASTERISK-25714 #close Reported by: Badalian Vyacheslav Change-Id: I45770fdd08af39506a3bc33ba279c4f16e047a30 --- main/logger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/logger.c b/main/logger.c index fac68d9b6b9..13f6de89026 100644 --- a/main/logger.c +++ b/main/logger.c @@ -601,7 +601,7 @@ static int init_logger_chain(const char *altconf) /* If no config file, we're fine, set default options. */ if (!cfg) { - if (!(chan = ast_calloc(1, sizeof(*chan)))) { + if (!(chan = ast_calloc(1, sizeof(*chan) + 1))) { fprintf(stderr, "Failed to initialize default logging\n"); return -1; } From a45eacebf326741821e7c954ac48e72c4c1b1274 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 21 Jan 2016 10:58:02 -0600 Subject: [PATCH 0168/1578] Stasis: Use control queue to prevent crash. A crash occurred when attempting to set a channel variable on a channel that had already been hung up. This is because there is a small window between when a control is grabbed and when the channel variable is set that the channel can be hung up. The fix here is to queue the setting of the channel variable onto the control queue. This way, the manipulation of the channel happens in a thread where it is safe to be done. In this change, I also noticed that the setting of bridge roles on channels was being done outside of the control queue, so I also changed those operations to be done in the control queue. ASTERISK-25709 #close Reported by Mark Michelson Change-Id: I2a0a4d51bce6fba6f1d9954e40935e42f366ea78 --- res/stasis/control.c | 50 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/res/stasis/control.c b/res/stasis/control.c index 99407dfab33..030ea8fb440 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -355,14 +355,39 @@ int stasis_app_control_dial(struct stasis_app_control *control, const char *endp return 0; } +static int app_control_add_role(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + char *role = data; + + return ast_channel_add_bridge_role(chan, role); +} + int stasis_app_control_add_role(struct stasis_app_control *control, const char *role) { - return ast_channel_add_bridge_role(control->channel, role); + char *role_dup; + + role_dup = ast_strdup(role); + if (!role_dup) { + return -1; + } + + stasis_app_send_command_async(control, app_control_add_role, role_dup, ast_free_ptr); + + return 0; +} + +static int app_control_clear_roles(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + ast_channel_clear_bridge_roles(chan); + + return 0; } void stasis_app_control_clear_roles(struct stasis_app_control *control) { - ast_channel_clear_bridge_roles(control->channel); + stasis_app_send_command_async(control, app_control_clear_roles, NULL, NULL); } int control_command_count(struct stasis_app_control *control) @@ -598,9 +623,28 @@ int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int d return 0; } +static int app_control_set_channel_var(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + struct ast_variable *var = data; + + pbx_builtin_setvar_helper(control->channel, var->name, var->value); + + return 0; +} + int stasis_app_control_set_channel_var(struct stasis_app_control *control, const char *variable, const char *value) { - return pbx_builtin_setvar_helper(control->channel, variable, value); + struct ast_variable *var; + + var = ast_variable_new(variable, value, "ARI"); + if (!var) { + return -1; + } + + stasis_app_send_command_async(control, app_control_set_channel_var, var, ast_free_ptr); + + return 0; } static int app_control_hold(struct stasis_app_control *control, From 959f7436cc16ac9e956df8692fd0ac25324236d5 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 22 Jan 2016 15:08:58 -0600 Subject: [PATCH 0169/1578] Stasis: Fix potential memory leak of control data. When queuing tasks onto the Stasis control queue, you can pass an arbitrary data pointer and a function to free that data. All ARI commands that use the Stasis control queue made the assumption that the destructor function would be called in all paths, whether the task was queued successfully or not. However, this was not correct. If a task was queued onto a control structure that was already completed, the allocated data would not be freed properly. This patch corrects this by making sure that all return paths call the data destructor. Change-Id: Ibf06522094f8e5c4cce652537dc5d7222b1c4fcb --- res/stasis/control.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/res/stasis/control.c b/res/stasis/control.c index 99407dfab33..bae64ecc241 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -746,6 +746,14 @@ static int app_send_command_on_condition(struct stasis_app_control *control, RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); if (control == NULL || control->is_done) { + /* If exec_command_on_condition fails, it calls the data_destructor. + * In order to provide consistent behavior, we'll also call the data_destructor + * on this error path. This way, callers never have to call the + * data_destructor themselves. + */ + if (data_destructor) { + data_destructor(data); + } return -1; } @@ -771,6 +779,14 @@ int stasis_app_send_command_async(struct stasis_app_control *control, RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); if (control == NULL || control->is_done) { + /* If exec_command fails, it calls the data_destructor. In order to + * provide consistent behavior, we'll also call the data_destructor + * on this error path. This way, callers never have to call the + * data_destructor themselves. + */ + if (data_destructor) { + data_destructor(data); + } return -1; } From 2fb45c7801cbb543b1be1efe400d255f3e8c9ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sat, 23 Jan 2016 14:41:38 -0300 Subject: [PATCH 0170/1578] cdr_pgsql.cl: REFACTOR Macro LENGTHEN_BUF Remove repeated code on macro of assigned buffer to SQL vars. Add table and connection name to log error message when is not possible allocate memory. Change-Id: I1fbf37d286a032d38fdda72a9f736356956c9ffe --- cdr/cdr_pgsql.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c index 8dc49e1071e..aec21165034 100644 --- a/cdr/cdr_pgsql.c +++ b/cdr/cdr_pgsql.c @@ -101,35 +101,26 @@ struct columns { static AST_RWLIST_HEAD_STATIC(psql_columns, columns); -#define LENGTHEN_BUF1(size) \ - do { \ - /* Lengthen buffer, if necessary */ \ - if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \ - if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 3) / 512 + 1) * 512) != 0) { \ - ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR failed.\n"); \ - ast_free(sql); \ - ast_free(sql2); \ - AST_RWLIST_UNLOCK(&psql_columns); \ - ast_mutex_unlock(&pgsql_lock); \ - return -1; \ - } \ - } \ - } while (0) - -#define LENGTHEN_BUF2(size) \ - do { \ - if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) { \ - if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \ - ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR failed.\n"); \ - ast_free(sql); \ - ast_free(sql2); \ +#define LENGTHEN_BUF(size, var_sql) \ + do { \ + /* Lengthen buffer, if necessary */ \ + if (ast_str_strlen(var_sql) + size + 1 > ast_str_size(var_sql)) { \ + if (ast_str_make_space(&var_sql, ((ast_str_size(var_sql) + size + 3) / 512 + 1) * 512) != 0) { \ + ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", pghostname, table); \ + ast_free(sql); \ + ast_free(sql2); \ AST_RWLIST_UNLOCK(&psql_columns); \ - ast_mutex_unlock(&pgsql_lock); \ - return -1; \ - } \ - } \ + ast_mutex_unlock(&pgsql_lock); \ + return -1; \ + } \ + } \ } while (0) +#define LENGTHEN_BUF1(size) \ + LENGTHEN_BUF(size, sql); +#define LENGTHEN_BUF2(size) \ + LENGTHEN_BUF(size, sql2); + /*! \brief Handle the CLI command cdr show pgsql status */ static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { From 8c664da0ffbd7c26120374544ed82d689dfadc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sat, 23 Jan 2016 15:34:11 -0300 Subject: [PATCH 0171/1578] app_queue: fix some tab format Change-Id: I2734392b131f1fb0949515d538f83f30fbc15d8c --- apps/app_queue.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index c4025d2454a..b064a184a69 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1333,9 +1333,9 @@ enum { }; enum { - QUEUE_AUTOPAUSE_OFF = 0, - QUEUE_AUTOPAUSE_ON, - QUEUE_AUTOPAUSE_ALL + QUEUE_AUTOPAUSE_OFF = 0, + QUEUE_AUTOPAUSE_ON, + QUEUE_AUTOPAUSE_ALL }; enum queue_reload_mask { @@ -1525,7 +1525,7 @@ struct queue_ent { int linwrapped; /*!< Is the linpos wrapped? */ time_t start; /*!< When we started holding */ time_t expire; /*!< When this entry should expire (time out of queue) */ - int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/ + int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/ struct ast_channel *chan; /*!< Our channel */ AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */ struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */ @@ -1548,7 +1548,7 @@ struct member { int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */ time_t lastcall; /*!< When last successful call was hungup */ unsigned int in_call:1; /*!< True if member is still in call. (so lastcall is not actual) */ - struct call_queue *lastqueue; /*!< Last queue we received a call */ + struct call_queue *lastqueue; /*!< Last queue we received a call */ unsigned int dead:1; /*!< Used to detect members deleted in realtime */ unsigned int delme:1; /*!< Flag to delete entry on reload */ unsigned int call_pending:1; /*!< TRUE if the Q is attempting to place a call to the member. */ @@ -1685,7 +1685,7 @@ struct call_queue { int memberdelay; /*!< Seconds to delay connecting member to caller */ int autofill; /*!< Ignore the head call status and ring an available agent */ - struct ao2_container *members; /*!< Head of the list of members */ + struct ao2_container *members; /*!< Head of the list of members */ struct queue_ent *head; /*!< Head of the list of callers */ AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */ AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */ From f299dc0d76a362a63222195da05af48a435d394f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sat, 23 Jan 2016 19:45:30 -0300 Subject: [PATCH 0172/1578] app_queue: Add Lastpause field of queue member Add time when started a the last pause for a queue member for QueueMemberStatus ami event. Also show accumulate time in seconds when started a pause for a queue member to CLI command 'queue show'. ASTERISK-16394 #close Change-Id: I4b12aa3b2efa8d02939db3e13712510b4879865c --- CHANGES | 5 +++++ apps/app_queue.c | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 173a41127c7..74919b7b323 100644 --- a/CHANGES +++ b/CHANGES @@ -200,6 +200,11 @@ Queue ------------------- * Added field ReasonPause on QueueMemberStatus if set when paused, the reason the queue member was paused. + * Added field LastPause on QueueMemberStatus for time when started the last + pause for a queue member. + * Show the time when started the last pause for queue member on CLI for command + 'queue show'. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ diff --git a/apps/app_queue.c b/apps/app_queue.c index ac105e4d816..15f32fadb86 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1022,6 +1022,9 @@ ASTERISK_REGISTER_FILE() The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC. + + The time when started last paused the queue member. + Set to 1 if member is in call. Set to 0 after LastCall time is updated. @@ -1546,6 +1549,7 @@ struct member { char reason_paused[80]; /*!< Reason of paused if member is paused */ int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */ time_t lastcall; /*!< When last successful call was hungup */ + time_t lastpause; /*!< When started the last pause */ unsigned int in_call:1; /*!< True if member is still in call. (so lastcall is not actual) */ struct call_queue *lastqueue; /*!< Last queue we received a call */ unsigned int dead:1; /*!< Used to detect members deleted in realtime */ @@ -2184,7 +2188,7 @@ static void queue_publish_member_blob(struct stasis_message_type *type, struct a static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem) { - return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i}", + return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i}", "Queue", q->name, "MemberName", mem->membername, "Interface", mem->interface, @@ -2193,6 +2197,7 @@ static struct ast_json *queue_member_blob_create(struct call_queue *q, struct me "Penalty", mem->penalty, "CallsTaken", mem->calls, "LastCall", (int)mem->lastcall, + "LastPause", (int)mem->lastpause, "InCall", mem->in_call, "Status", mem->status, "Paused", mem->paused, @@ -2514,6 +2519,9 @@ static struct member *create_queue_member(const char *interface, const char *mem cur->ringinuse = ringinuse; cur->penalty = penalty; cur->paused = paused; + if (paused) { + time(&cur->lastpause); /* Update time of last pause */ + } ast_copy_string(cur->interface, interface, sizeof(cur->interface)); if (!ast_strlen_zero(state_interface)) { ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); @@ -7139,6 +7147,7 @@ static void set_queue_member_pause(struct call_queue *q, struct member *mem, con if (!ast_strlen_zero(reason)) { ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused)); } + time(&mem->lastpause); /* update last pause field */ } else { ast_copy_string(mem->reason_paused, "", sizeof(mem->reason_paused)); } @@ -9321,11 +9330,11 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * mem->in_call ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->in_call ? " (in call)" : "", ast_term_reset()); if (mem->paused) { if (ast_strlen_zero(mem->reason_paused)) { - ast_str_append(&out, 0, " %s(paused)%s", - ast_term_color(COLOR_BROWN, COLOR_BLACK), ast_term_reset()); + ast_str_append(&out, 0, " %s(paused was %ld secs ago)%s", + ast_term_color(COLOR_BROWN, COLOR_BLACK), (long) (time(NULL) - mem->lastpause), ast_term_reset()); } else { - ast_str_append(&out, 0, " %s(paused:%s)%s", ast_term_color(COLOR_BROWN, COLOR_BLACK), - mem->reason_paused, ast_term_reset()); + ast_str_append(&out, 0, " %s(paused:%s was %ld secs ago)%s", ast_term_color(COLOR_BROWN, COLOR_BLACK), + mem->reason_paused, (long) (time(NULL) - mem->lastcall), ast_term_reset()); } } @@ -9697,6 +9706,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) "Penalty: %d\r\n" "CallsTaken: %d\r\n" "LastCall: %d\r\n" + "LastPause: %d\r\n" "InCall: %d\r\n" "Status: %d\r\n" "Paused: %d\r\n" @@ -9704,7 +9714,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) "%s" "\r\n", q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static", - mem->penalty, mem->calls, (int)mem->lastcall, mem->in_call, mem->status, + mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, mem->in_call, mem->status, mem->paused, mem->reason_paused, idText); ++q_items; } From 830f8933c29f36484e7a106c9c92446bab6a555c Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 25 Jan 2016 12:03:21 -0500 Subject: [PATCH 0173/1578] chan_sip: Fix buffer overrun in sip_sipredirect. sip_sipredirect uses sscanf to copy up to 256 characters to a stacked buffer of 256 characters. This patch reduces the copy to 255 characters to leave room for the string null terminator. ASTERISK-25722 #close Change-Id: Id6c3a629a609e94153287512c59aa1923e8a03ab --- channels/chan_sip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 9e870275d32..a3c6fb29678 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -33012,8 +33012,8 @@ static int sip_sipredirect(struct sip_pvt *p, const char *dest) memset(ldomain, 0, sizeof(ldomain)); local_to_header++; - /* This is okey because lhost and lport are as big as tmp */ - sscanf(local_to_header, "%256[^<>; ]", ldomain); + /* Will copy no more than 255 chars plus null terminator. */ + sscanf(local_to_header, "%255[^<>; ]", ldomain); if (ast_strlen_zero(ldomain)) { ast_log(LOG_ERROR, "Can't find the host address\n"); return 0; From b073244c511f9634de57ea401ab9dbebcf2390e8 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 25 Jan 2016 16:51:25 -0600 Subject: [PATCH 0174/1578] res_pjsip_pubsub: Prevent crash from AMI command on freed subscription. A test recently uncovered that running an ill-timed AMI command to show inbound subscriptions could cause a crash since Asterisk will try to operate on a freed subscription. The fix for this is to remove the subscription tree from the list of subscriptions at the time that we are sending our final NOTIFY request out. This way, as the subscription is in the process of dying, it is inaccessible from AMI. Change-Id: Ic0239003d8d73e04c47c12dd2a7e23867e5b5b23 --- res/res_pjsip_pubsub.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index a703e29a151..dc7f5ed9e67 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1202,8 +1202,6 @@ static void subscription_tree_destructor(void *obj) ast_debug(3, "Destroying subscription tree %p\n", sub_tree); - remove_subscription(sub_tree); - ao2_cleanup(sub_tree->endpoint); destroy_subscriptions(sub_tree->root); @@ -3295,6 +3293,7 @@ static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event) } } + remove_subscription(sub_tree); pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL); sub_tree->evsub = NULL; ast_sip_dialog_set_serializer(sub_tree->dlg, NULL); From 289daca9e8444c5fee07708499f7b13253ea7538 Mon Sep 17 00:00:00 2001 From: Rusty Newton Date: Mon, 25 Jan 2016 16:56:04 -0600 Subject: [PATCH 0175/1578] sounds/Makefile: Incremented core and extra sounds versions to 1.5 Core and extra sounds 1.5 was recently released! The tarballs contain change descriptions however I figure more people will see this one so I'll try to be a bit detailed. Approximately 60 sounds were moved from Extra to Core for en, en_GB, fr and added for languages that didn't already have Extra sound sets (it,ja,ru). In addition all of the English and Russian sounds have been completely re-recorded. Sounds moved and added: activated,added,all-circuits-busy-now,astcc-followed-by-pound at-tone-time-exactly,call-forwarding,call-fwd-no-ans,call-fwd-on-busy ,call-fwd-unconditional,calling,call-waiting,cancelled, cannot-complete-as-dialed,check-number-dial-again,conf-full,de-activated ,disabled,do-not-disturb,enabled,enter-num-blacklist,entr-num-rmv-blklist ,extension,feature-not-avail-line,for,from-unknown-caller,goodbye,hello ,if-correct-press,im-sorry,info-about-last-call,is,is-in-use,is-set-to ,location,number,number-not-answering,num-was-successfully,one-moment-please ,please-try-again,pls-hold-while-try,pls-try-call-later,pm-invalid-option ,privacy-to-blacklist-last-caller,removed,simul-call-limit-reached ,something-terribly-wrong,sorry,sorry-youre-having-problems,speed-dial ,speed-dial-empty,telephone-number,time,to-call-this-number,to-extension ,to-listen-to-it,to-rerecord-it,unidentified-no-callback,with,you-entered ,your There were also a few random fixes here and there to file names for a few of the languages. ASTERISK-25068 #close Change-Id: I2b594344ec585d7dfd922b40c1af43b1508828b3 --- sounds/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sounds/Makefile b/sounds/Makefile index a726ece157f..84d0f45c049 100644 --- a/sounds/Makefile +++ b/sounds/Makefile @@ -19,8 +19,8 @@ CMD_PREFIX?=@ SOUNDS_DIR:=$(DESTDIR)$(ASTDATADIR)/sounds SOUNDS_CACHE_DIR?= MOH_DIR:=$(DESTDIR)$(ASTDATADIR)/moh -CORE_SOUNDS_VERSION:=1.4.27 -EXTRA_SOUNDS_VERSION:=1.4.15 +CORE_SOUNDS_VERSION:=1.5 +EXTRA_SOUNDS_VERSION:=1.5 MOH_VERSION:=2.03 SOUNDS_URL:=http://downloads.asterisk.org/pub/telephony/sounds/releases MCS:=$(subst -EN-,-en-,$(MENUSELECT_CORE_SOUNDS)) From a706ad44e6834da6034ce6b179195d161f782a61 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 25 Jan 2016 10:23:18 -0600 Subject: [PATCH 0176/1578] Stasis: Use custom structure when setting variables. A recent change to queue channel variable setting to the Stasis control queue caused a regression. When setting channel variables, it is possible to give a NULL channel variable value in order to unset the variable (i.e. remove it from the channel variable list). The change introduced a call to ast_variable_new(), which is not tolerant of NULL channel variable values. This new change switches from using ast_variable to using a custom channel variable struct that is lighter weight and NULL value-tolerant. Change-Id: I784d7beaaa3c036ea936d103e7caf0bb1562162d --- res/stasis/control.c | 49 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/res/stasis/control.c b/res/stasis/control.c index 903b5752df0..41d538cbe19 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -623,10 +623,36 @@ int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int d return 0; } +/*! + * \brief structure for queuing ARI channel variable setting + * + * It may seem weird to define this custom structure given that we already have + * ast_var_t and ast_variable defined elsewhere. The problem with those is that + * they are not tolerant of NULL channel variable value pointers. In fact, in both + * cases, the best they could do is to have a zero-length variable value. However, + * when un-setting a channel variable, it is important to pass a NULL value, not + * a zero-length string. + */ +struct chanvar { + /*! Name of variable to set/unset */ + char *name; + /*! Value of variable to set. If unsetting, this will be NULL */ + char *value; +}; + +static void free_chanvar(void *data) +{ + struct chanvar *var = data; + + ast_free(var->name); + ast_free(var->value); + ast_free(var); +} + static int app_control_set_channel_var(struct stasis_app_control *control, struct ast_channel *chan, void *data) { - struct ast_variable *var = data; + struct chanvar *var = data; pbx_builtin_setvar_helper(control->channel, var->name, var->value); @@ -635,14 +661,29 @@ static int app_control_set_channel_var(struct stasis_app_control *control, int stasis_app_control_set_channel_var(struct stasis_app_control *control, const char *variable, const char *value) { - struct ast_variable *var; + struct chanvar *var; - var = ast_variable_new(variable, value, "ARI"); + var = ast_calloc(1, sizeof(*var)); if (!var) { return -1; } - stasis_app_send_command_async(control, app_control_set_channel_var, var, ast_free_ptr); + var->name = ast_strdup(variable); + if (!var->name) { + free_chanvar(var); + return -1; + } + + /* It's kosher for value to be NULL. It means the variable is being unset */ + if (value) { + var->value = ast_strdup(value); + if (!var->value) { + free_chanvar(var); + return -1; + } + } + + stasis_app_send_command_async(control, app_control_set_channel_var, var, free_chanvar); return 0; } From 1dfd104a276459bf5c7ad07c4f9615b4b8c5e2d4 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 25 Jan 2016 11:35:21 -0400 Subject: [PATCH 0177/1578] config: Allow options to register when documentation is unavailable. The config options framework is strict in that configuration options must be documented unless XML documentation support is not available. In practice this is useful as it ensures documentation exists however in off-nominal cases this can cause strange problems. If it is expected that a config option has a non-zero or non-empty default value but the config option documentation is unavailable this reasonable expectation will not be met. This can cause obscure crashes and weirdness depending on how the code handles it. This change tweaks the behavior to ensure that the config option is still allowed to register, apply default values, and be set when devmode is not enabled. If devmode is enabled then the option can NOT be set. This also does not remove the initial documentation error message that is output on load when registering the configuration option. ASTERISK-25725 #close Change-Id: Iec42fca6b35f31326c33fcdc25473f6fd7bc8af8 --- main/config_options.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/main/config_options.c b/main/config_options.c index 4ab7a5b9a3f..abc6eed782b 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -71,6 +71,9 @@ struct aco_option { aco_option_handler handler; unsigned int flags; unsigned int no_doc:1; +#ifdef AST_DEVMODE + unsigned int doc_unavailable:1; +#endif unsigned char deprecated:1; size_t argc; intptr_t args[0]; @@ -183,18 +186,20 @@ static int link_option_to_types(struct aco_info *info, struct aco_type **types, ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n"); return -1; } - if (!ao2_link(type->internal->opts, opt) -#ifdef AST_XML_DOCS - || (!info->hidden && - !opt->no_doc && - xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type)) -#endif /* AST_XML_DOCS */ - ) { + if (!ao2_link(type->internal->opts, opt)) { do { ao2_unlink(types[idx - 1]->internal->opts, opt); } while (--idx); return -1; } +#ifdef AST_XML_DOCS + if (!info->hidden && !opt->no_doc && + xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type)) { +#ifdef AST_DEVMODE + opt->doc_unavailable = 1; +#endif +#endif + } } /* The container(s) should hold the only ref to opt */ ao2_ref(opt, -1); @@ -716,6 +721,14 @@ int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name); return -1; } + +#ifdef AST_DEVMODE + if (opt->doc_unavailable) { + ast_log(LOG_ERROR, "Config option '%s' of type '%s' is not completely documented and can not be set\n", var->name, type->name); + return -1; + } +#endif + if (opt->handler(opt, var, obj)) { ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file); return -1; From c53903d447b8dff414188933328e4593bc7d1b63 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 27 Jan 2016 09:29:13 -0700 Subject: [PATCH 0178/1578] build_system: Prevent goals needing makeopts from running when it's missing The Makefile only optionally includes makeopts so when goals like uninstall that dont depend on anything else are run after a distclean, rules like 'rm -f "$(DESTDIR)$(ASTMODDIR)/"*' get run as 'rm -f ""/*' which attempts to remove everything in the root directory. Although there's a rule defined for makeopts which prints a message and does an 'exit 1', since '-include makepopts' was specified (with the -), the exit was ignored letting the rest of the rules run. This patch makes makeopts required unless the goal has the string 'clean' in it. ASTERISK-25730 #close Reported-by: George Joseph Change-Id: I1bce59a7ea4f48e7a468e22b2abbb13c63417ac7 --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b1de3d2445b..a07a3299b17 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,10 @@ export LDCONFIG export LDCONFIG_FLAGS export PYTHON --include makeopts +# makeopts is required unless the goal is clean or distclean +ifeq ($(findstring clean,$(MAKECMDGOALS)),) +include makeopts +endif # start the primary CFLAGS and LDFLAGS with any that were provided # to the configure script From f19bf7a32141a1282f00a4da1c677a893b9a6d1b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 27 Jan 2016 12:08:29 -0700 Subject: [PATCH 0179/1578] res_pjsip: Add res_pjproject dependency to samples Since res_pjsip now depends on res_pjproject, this has been added to basic-pbx modules.conf. Change-Id: I42826597d5e10f08e518208860c44c96e52f1b2d --- configs/basic-pbx/modules.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/basic-pbx/modules.conf b/configs/basic-pbx/modules.conf index c0416a06ffa..90ced108596 100644 --- a/configs/basic-pbx/modules.conf +++ b/configs/basic-pbx/modules.conf @@ -65,6 +65,7 @@ load = pbx_functions.so load = res_hep_pjsip.so load = res_musiconhold.so +load = res_pjproject.so load = res_pjsip_acl.so load = res_pjsip_authenticator_digest.so load = res_pjsip_caller_id.so From 12c93e8f81ff12ddf0ea41925ccca9d6014d4187 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 25 Jan 2016 15:48:04 -0600 Subject: [PATCH 0180/1578] app_confbridge: Make non-admin users join a muted conference muted. ASTERISK-20987 #close Reported by: hristo Change-Id: Ic61a2b524ab3a4cfadf227fc6b3506527bc03f38 --- apps/app_confbridge.c | 13 +++++++------ configs/samples/confbridge.conf.sample | 10 ++++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 7a04952dbd8..9bda5440d9f 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1313,6 +1313,13 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen ao2_lock(conference); + /* Determine if the new user should join the conference muted. */ + if (ast_test_flag(&user->u_profile, USER_OPT_STARTMUTED) + || (!ast_test_flag(&user->u_profile, USER_OPT_ADMIN) && conference->muted)) { + /* Set user level mute request. */ + user->muted = 1; + } + /* * Suspend any MOH until the user actually joins the bridge of * the conference. This way any pre-join file playback does not @@ -1730,12 +1737,6 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) } } - /* If the caller should be joined already muted, set the flag before we join. */ - if (ast_test_flag(&user.u_profile, USER_OPT_STARTMUTED)) { - /* Set user level mute request. */ - user.muted = 1; - } - /* Look for a conference bridge matching the provided name */ if (!(conference = join_conference_bridge(args.conf_name, &user))) { pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED"); diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index 85de3282bd5..e7386859688 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -340,10 +340,12 @@ type=bridge ; upon release of the video src. ; admin_toggle_mute_participants ; This action allows an administrator to toggle the mute - ; state for all non-admins within a conference. All - ; admin users are unaffected by this option. Note that all - ; users, regardless of their admin status, are notified - ; that the conference is muted. + ; state for all non-admins within a conference. + ; Subsequent non-admins joining a muted conference will + ; start muted. All admin users are unaffected by this + ; option. Note that all users, regardless of their admin + ; status, are notified that the conference is muted when + ; the state is toggled. ; participant_count ; This action plays back the number of participants currently ; in a conference From 894045e7cf00ad0f375e0cf879745fd3d0564cc4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 26 Jan 2016 17:59:28 -0600 Subject: [PATCH 0181/1578] app_confbridge.c: Update CONFBRIDGE and CONFBRIDGE_INFO documentation. Change-Id: Ic1f9e22ba1f2ff3b3f5cb017c5ddcd9bd48eccc7 --- apps/app_confbridge.c | 72 +++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 9bda5440d9f..8ded5102673 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -130,32 +130,51 @@ ASTERISK_REGISTER_FILE() - Set a custom dynamic bridge, user, or menu profile on a channel for the ConfBridge application using the same options defined in confbridge.conf. + Set a custom dynamic bridge, user, or menu profile on a channel for the + ConfBridge application using the same options available in confbridge.conf. - Type refers to which type of profile the option belongs too. Type can be bridge, user, or - menu. + To what type of conference profile the option applies. + + + + + - Option refers to confbridge.conf option that is being set dynamically on this channel, or - clear to remove already applied options from the channel. + Option refers to a confbridge.conf option + that is being set dynamically on this channel, or clear + to remove already applied profile options from the channel. + A custom profile uses the default profile type settings defined in + confbridge.conf as defaults if the profile template + is not explicitly specified first. + For bridge profiles the default template is default_bridge. + For menu profiles the default template is default_menu. + For user profiles the default template is default_user. ---- Example 1 ---- - In this example the custom set user profile on this channel will automatically be used by the ConfBridge app. - exten => 1,1,Answer() - exten => 1,n,Set(CONFBRIDGE(user,announce_join_leave)=yes) - exten => 1,n,Set(CONFBRIDGE(user,startmuted)=yes) - exten => 1,n,ConfBridge(1) + In this example the custom user profile set on the channel will + automatically be used by the ConfBridge application. + exten => 1,1,Answer() + ; In this example the effect of the following line is + ; implied: + ; same => n,Set(CONFBRIDGE(user,template)=default_user) + same => n,Set(CONFBRIDGE(user,announce_join_leave)=yes) + same => n,Set(CONFBRIDGE(user,startmuted)=yes) + same => n,ConfBridge(1) ---- Example 2 ---- - This example shows how to use a predefined user or bridge profile in confbridge.conf as a template for a dynamic profile. Here we make a admin/marked user out of the default_user profile that is already defined in confbridge.conf. - exten => 1,1,Answer() - exten => 1,n,Set(CONFBRIDGE(user,template)=default_user) - exten => 1,n,Set(CONFBRIDGE(user,admin)=yes) - exten => 1,n,Set(CONFBRIDGE(user,marked)=yes) - exten => 1,n,ConfBridge(1) + This example shows how to use a predefined user profile in + confbridge.conf as a template for a dynamic profile. + Here we make an admin/marked user out of the my_user + profile that you define in confbridge.conf. + exten => 1,1,Answer() + same => n,Set(CONFBRIDGE(user,template)=my_user) + same => n,Set(CONFBRIDGE(user,admin)=yes) + same => n,Set(CONFBRIDGE(user,marked)=yes) + same => n,ConfBridge(1) @@ -164,14 +183,29 @@ ASTERISK_REGISTER_FILE() - Type can be parties, admins, marked, or locked. + What conference information is requested. + + + Get the number of admin users in the conference. + + + Determine if the conference is locked. (0 or 1) + + + Get the number of marked users in the conference. + + + Get the number of users in the conference. + + - Conf refers to the name of the conference being referenced. + The name of the conference being referenced. - This function returns a non-negative integer for valid conference identifiers (0 or 1 for locked) and "" for invalid conference identifiers. + This function returns a non-negative integer for valid conference + names and an empty string for invalid conference names. From 7932336a3d1e09ee88b8416ebc1abbdb8692660a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 25 Jan 2016 16:05:09 -0600 Subject: [PATCH 0182/1578] app_confbridge: Add ability to get the muted conference state. * Added CONFBRIDGE_INFO(muted,) for querying the muted conference state. * Added Muted header to AMI ConfbridgeListRooms action response list events to indicate the muted conference state. * Added Muted column to CLI "confbridge list" output to indicate the muted conference state and made the locked column a yes/no value instead of a locked/unlocked value. ASTERISK-20987 Reported by: hristo Change-Id: I4076bd8ea1c23a3afd4f5833e9291b49a0c448b1 --- CHANGES | 12 +++++++++++- apps/app_confbridge.c | 31 +++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 173a41127c7..f1f5f424802 100644 --- a/CHANGES +++ b/CHANGES @@ -205,6 +205,17 @@ Queue --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ ------------------------------------------------------------------------------ +app_confbridge +------------------ + * Added CONFBRIDGE_INFO(muted,) for querying the muted conference state. + + * Added Muted header to AMI ConfbridgeListRooms action response list events + to indicate the muted conference state. + + * Added Muted column to CLI "confbridge list" output to indicate the muted + conference state and made the locked column a yes/no value instead of a + locked/unlocked value. + res_pjproject ------------------ * This module is the successor of res_pjsip_log_forwarder. As well as @@ -215,7 +226,6 @@ res_pjproject res_pjsip ------------------ - * Added new global option (regcontext) to pjsip. When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given endpoint who registers or unregisters with us. diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 8ded5102673..18e192ca212 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -194,6 +194,9 @@ ASTERISK_REGISTER_FILE() Get the number of marked users in the conference. + + Determine if the conference is muted. (0 or 1) + Get the number of users in the conference. @@ -2486,11 +2489,16 @@ static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct if (a->argc == 2) { struct ao2_iterator iter; - ast_cli(a->fd, "Conference Bridge Name Users Marked Locked?\n"); - ast_cli(a->fd, "================================ ====== ====== ========\n"); + ast_cli(a->fd, "Conference Bridge Name Users Marked Locked Muted\n"); + ast_cli(a->fd, "================================ ====== ====== ====== =====\n"); iter = ao2_iterator_init(conference_bridges, 0); while ((conference = ao2_iterator_next(&iter))) { - ast_cli(a->fd, "%-32s %6u %6u %s\n", conference->name, conference->activeusers + conference->waitingusers, conference->markedusers, (conference->locked ? "locked" : "unlocked")); + ast_cli(a->fd, "%-32s %6u %6u %-6s %s\n", + conference->name, + conference->activeusers + conference->waitingusers, + conference->markedusers, + AST_CLI_YESNO(conference->locked), + AST_CLI_YESNO(conference->muted)); ao2_ref(conference, -1); } ao2_iterator_destroy(&iter); @@ -2980,12 +2988,14 @@ static int action_confbridgelistrooms(struct mansession *s, const struct message "Parties: %u\r\n" "Marked: %u\r\n" "Locked: %s\r\n" + "Muted: %s\r\n" "\r\n", id_text, conference->name, conference->activeusers + conference->waitingusers, conference->markedusers, - conference->locked ? "Yes" : "No"); + AST_YESNO(conference->locked), + AST_YESNO(conference->muted)); ao2_unlock(conference); ao2_ref(conference, -1); @@ -3256,30 +3266,31 @@ static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char /* get the correct count for the type requested */ ao2_lock(conference); - if (!strncasecmp(args.type, "parties", 7)) { + if (!strcasecmp(args.type, "parties")) { AST_LIST_TRAVERSE(&conference->active_list, user, list) { count++; } AST_LIST_TRAVERSE(&conference->waiting_list, user, list) { count++; } - } else if (!strncasecmp(args.type, "admins", 6)) { + } else if (!strcasecmp(args.type, "admins")) { AST_LIST_TRAVERSE(&conference->active_list, user, list) { if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) { count++; } } - } else if (!strncasecmp(args.type, "marked", 6)) { + } else if (!strcasecmp(args.type, "marked")) { AST_LIST_TRAVERSE(&conference->active_list, user, list) { if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) { count++; } } - } else if (!strncasecmp(args.type, "locked", 6)) { + } else if (!strcasecmp(args.type, "locked")) { count = conference->locked; + } else if (!strcasecmp(args.type, "muted")) { + count = conference->muted; } else { - ast_log(LOG_ERROR, "Invalid keyword '%s' passed to CONFBRIDGE_INFO. Should be one of: " - "parties, admins, marked, or locked.\n", args.type); + ast_log(LOG_ERROR, "Invalid keyword '%s' passed to CONFBRIDGE_INFO.\n", args.type); } snprintf(buf, len, "%d", count); ao2_unlock(conference); From af6b15976da099c90cee92252bf244597350a9de Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 25 Jan 2016 17:34:20 -0600 Subject: [PATCH 0183/1578] app_confbridge.c: Replace inlined code with existing function. Change-Id: Ida5594e9f8d7c1fc18eeb733a11f8fb96326da51 --- apps/app_confbridge.c | 66 +++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 18e192ca212..97c73bd7444 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1089,6 +1089,31 @@ void conf_update_user_mute(struct confbridge_user *user) ast_channel_name(user->chan)); } +/* + * \internal + * \brief Mute/unmute a single user. + */ +static void generic_mute_unmute_user(struct confbridge_conference *conference, struct confbridge_user *user, int mute) +{ + /* Set user level mute request. */ + user->muted = mute ? 1 : 0; + + conf_update_user_mute(user); + ast_test_suite_event_notify("CONF_MUTE", + "Message: participant %s %s\r\n" + "Conference: %s\r\n" + "Channel: %s", + ast_channel_name(user->chan), + mute ? "muted" : "unmuted", + conference->b_profile.name, + ast_channel_name(user->chan)); + if (mute) { + send_mute_event(user, conference); + } else { + send_unmute_event(user, conference); + } +} + void conf_moh_stop(struct confbridge_user *user) { user->playing_moh = 0; @@ -1925,22 +1950,7 @@ static int action_toggle_mute(struct confbridge_conference *conference, /* Toggle user level mute request. */ mute = !user->muted; - user->muted = mute; - - conf_update_user_mute(user); - ast_test_suite_event_notify("CONF_MUTE", - "Message: participant %s %s\r\n" - "Conference: %s\r\n" - "Channel: %s", - ast_channel_name(user->chan), - mute ? "muted" : "unmuted", - user->b_profile.name, - ast_channel_name(user->chan)); - if (mute) { - send_mute_event(user, conference); - } else { - send_unmute_event(user, conference); - } + generic_mute_unmute_user(conference, user, mute); return play_file(bridge_channel, NULL, (mute ? conf_get_sound(CONF_SOUND_MUTED, user->b_profile.sounds) : @@ -2554,30 +2564,6 @@ static int generic_lock_unlock_helper(int lock, const char *conference_name) return res; } -/* \internal - * \brief Mute/unmute a single user. - */ -static void generic_mute_unmute_user(struct confbridge_conference *conference, struct confbridge_user *user, int mute) -{ - /* Set user level mute request. */ - user->muted = mute ? 1 : 0; - - conf_update_user_mute(user); - ast_test_suite_event_notify("CONF_MUTE", - "Message: participant %s %s\r\n" - "Conference: %s\r\n" - "Channel: %s", - ast_channel_name(user->chan), - mute ? "muted" : "unmuted", - conference->b_profile.name, - ast_channel_name(user->chan)); - if (mute) { - send_mute_event(user, conference); - } else { - send_unmute_event(user, conference); - } -} - /* \internal * \brief finds a conference user by channel name and mutes/unmutes them. * From d2397f028fd4b92a96ad2232ba73400ca9afafb0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 28 Jan 2016 12:44:43 -0600 Subject: [PATCH 0184/1578] config_options.c: Fix warning message wording. Change-Id: I915ea437936320393afde0e7552cf0a980a6b2e4 --- main/config_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/config_options.c b/main/config_options.c index 4ab7a5b9a3f..f7f181b890e 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -1050,7 +1050,7 @@ static int xmldoc_update_config_option(struct aco_type **types, const char *modu } if (!(option = ast_xml_xpath_get_first_result(results))) { - ast_log(LOG_WARNING, "Could obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module); + ast_log(LOG_WARNING, "Could not obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module); return XMLDOC_STRICT ? -1 : 0; } ast_xml_set_attribute(option, "regex", regex ? "true" : "false"); From 55a7367ad4d3c45856554b4be32d2fd0f70c0dda Mon Sep 17 00:00:00 2001 From: StefanEng86 Date: Fri, 29 Jan 2016 14:39:06 +0100 Subject: [PATCH 0185/1578] chan_sip.c: AMI & CLI notify methods get different values of asterisk's own ip. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When I ask asterisk to send a SIP NOTIFY message to a sip peer using either a) AMI action: SIPnotify or b) cli command: sip notify , I expect asterisk to include the same value for its own ip in both cases a) and b), but it seems a) produces a contact header like Contact: whereas b) produces a contact header like . 0.0.0.0:8060 is my udpbindaddr in sip.conf My guess is that manager_sipnotify should call ast_sip_ouraddrfor(&p->sa, &p->ourip, p) the same way sip_cli_notify does, because after applying this patch, both cases a) and b) produce the contact header that I expect: Reported by: Stefan Engström Tested by: Stefan Engström Change-Id: I86af5e209db64aab82c25417de6c768fb645f476 --- channels/chan_sip.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index a3c6fb29678..10b0d23f2d4 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -15160,6 +15160,12 @@ static int manager_sipnotify(struct mansession *s, const struct message *m) } } + /* Now that we have the peer's address, set our ip and change callid */ + ast_sip_ouraddrfor(&p->sa, &p->ourip, p); + build_via(p); + + change_callid_pvt(p, NULL); + sip_scheddestroy(p, SIP_TRANS_TIMEOUT); transmit_invite(p, SIP_NOTIFY, 0, 2, NULL); dialog_unref(p, "bump down the count of p since we're done with it."); From 52b29f9b4cd373be7357cd03e01cfeb2d0029140 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 31 Jan 2016 19:13:58 -0700 Subject: [PATCH 0186/1578] pjsip/alembic: Fix definition of qualify_timeout A recent commit set qualify_timeout to Decimal which isn't supported. This path corrects it to Float. Change-Id: I038f5274ba8cb60f8518a5845ce448d49306aadf --- .../config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py index 594f1eb7e04..cda0b9af570 100644 --- a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py +++ b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py @@ -15,8 +15,8 @@ def upgrade(): - op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Decimal) - op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Decimal) + op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Float) + op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Float) pass From 40da6434c1189e2557d20ea3871761cb34595257 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 1 Feb 2016 12:04:06 -0700 Subject: [PATCH 0187/1578] build_system: Fix some warnings highlighted by clang Fix some warnings found with clang. Change-Id: I5195b6189b148c2ee3ed4a19d015a6d4ef3e77bd --- addons/res_config_mysql.c | 6 +++--- apps/app_fax.c | 4 ++-- apps/app_meetme.c | 2 +- apps/app_minivm.c | 14 +++++++------- channels/chan_dahdi.c | 2 +- channels/chan_motif.c | 1 - channels/sig_analog.c | 6 +++--- main/manager.c | 2 +- res/res_pjproject.c | 2 ++ 9 files changed, 20 insertions(+), 19 deletions(-) diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c index a805cb4b4d7..c9fa7c74425 100644 --- a/addons/res_config_mysql.c +++ b/addons/res_config_mysql.c @@ -1518,7 +1518,7 @@ static int load_mysql_config(struct ast_config *config, const char *category, st ast_debug(1, "MySQL RealTime database name: %s\n", conn->name); ast_debug(1, "MySQL RealTime user: %s\n", conn->user); ast_debug(1, "MySQL RealTime password: %s\n", conn->pass); - if(conn->charset) + if(!ast_strlen_zero(conn->charset)) ast_debug(1, "MySQL RealTime charset: %s\n", conn->charset); return 1; @@ -1533,13 +1533,13 @@ static int mysql_reconnect(struct mysql_conn *conn) /* mutex lock should have been locked before calling this function. */ reconnect_tryagain: - if ((!conn->connected) && (!ast_strlen_zero(conn->host) || conn->sock) && !ast_strlen_zero(conn->user) && !ast_strlen_zero(conn->name)) { + if ((!conn->connected) && (!ast_strlen_zero(conn->host) || !ast_strlen_zero(conn->sock)) && !ast_strlen_zero(conn->user) && !ast_strlen_zero(conn->name)) { if (!mysql_init(&conn->handle)) { ast_log(LOG_WARNING, "MySQL RealTime: Insufficient memory to allocate MySQL resource.\n"); conn->connected = 0; return 0; } - if(conn->charset && strlen(conn->charset) > 2){ + if(strlen(conn->charset) > 2){ char set_names[255]; char statement[512]; snprintf(set_names, sizeof(set_names), "SET NAMES %s", conn->charset); diff --git a/apps/app_fax.c b/apps/app_fax.c index d6e9b4de011..bf57d827df9 100644 --- a/apps/app_fax.c +++ b/apps/app_fax.c @@ -356,8 +356,8 @@ static int fax_generator_generate(struct ast_channel *chan, void *data, int len, } static struct ast_generator generator = { - alloc: fax_generator_alloc, - generate: fax_generator_generate, + .alloc = fax_generator_alloc, + .generate = fax_generator_generate, }; diff --git a/apps/app_meetme.c b/apps/app_meetme.c index ab6b94f3ee2..791f75eb0a3 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -2936,7 +2936,7 @@ static void meetme_menu_admin(enum menu_modes *menu_mode, int *dtmf, struct ast_ tweak_talk_volume(user, VOL_UP); break; default: - menu_mode = MENU_DISABLED; + *menu_mode = MENU_DISABLED; /* Play an error message! */ if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) { ast_waitstream(chan, ""); diff --git a/apps/app_minivm.c b/apps/app_minivm.c index 4b1c4b5753a..e97150b137c 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -2998,10 +2998,10 @@ static char *handle_minivm_list_templates(struct ast_cli_entry *e, int cmd, stru ast_cli(a->fd, HVLT_OUTPUT_FORMAT, "-------------", "-------", "------", "------------", "-------"); AST_LIST_TRAVERSE(&message_templates, this, list) { ast_cli(a->fd, HVLT_OUTPUT_FORMAT, this->name, - this->charset ? this->charset : "-", - this->locale ? this->locale : "-", + S_OR(this->charset, "-"), + S_OR(this->locale, "-"), this->attachment ? "Yes" : "No", - this->subject ? this->subject : "-"); + S_OR(this->subject, "-")); count++; } AST_LIST_UNLOCK(&message_templates); @@ -3069,10 +3069,10 @@ static char *handle_minivm_show_users(struct ast_cli_entry *e, int cmd, struct a if ((a->argc == 3) || ((a->argc == 5) && !strcmp(a->argv[4], vmu->domain))) { count++; snprintf(tmp, sizeof(tmp), "%s@%s", vmu->username, vmu->domain); - ast_cli(a->fd, HMSU_OUTPUT_FORMAT, tmp, vmu->etemplate ? vmu->etemplate : "-", - vmu->ptemplate ? vmu->ptemplate : "-", - vmu->zonetag ? vmu->zonetag : "-", - vmu->attachfmt ? vmu->attachfmt : "-", + ast_cli(a->fd, HMSU_OUTPUT_FORMAT, tmp, S_OR(vmu->etemplate, "-"), + S_OR(vmu->ptemplate, "-"), + S_OR(vmu->zonetag, "-"), + S_OR(vmu->attachfmt, "-"), vmu->fullname); } } diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 697c720e359..2d923433c51 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -4704,7 +4704,7 @@ static int drc_sample(int sample, float drc) neg = (sample < 0 ? -1 : 1); steep = drc*sample; shallow = neg*(max-max/drc)+(float)sample/drc; - if (abs(steep) < abs(shallow)) { + if (fabsf(steep) < fabsf(shallow)) { sample = steep; } else { diff --git a/channels/chan_motif.c b/channels/chan_motif.c index 15a7b4d6d7e..118d1d9fb17 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -320,7 +320,6 @@ struct jingle_session { ast_callid callid; /*!< Bound session call-id */ }; -static const char desc[] = "Motif Jingle Channel"; static const char channel_type[] = "Motif"; struct jingle_config { diff --git a/channels/sig_analog.c b/channels/sig_analog.c index 0608c3429fb..110942cba00 100644 --- a/channels/sig_analog.c +++ b/channels/sig_analog.c @@ -70,7 +70,7 @@ static char analog_defaultozz[64] = ""; static const struct { enum analog_sigtype sigtype; - const char const *name; + const char *name; } sigtypes[] = { { ANALOG_SIG_FXOLS, "fxo_ls" }, { ANALOG_SIG_FXOKS, "fxo_ks" }, @@ -97,7 +97,7 @@ static const struct { static const struct { unsigned int cid_type; - const char const *name; + const char *name; } cidtypes[] = { { CID_SIG_BELL, "bell" }, { CID_SIG_V23, "v23" }, @@ -2670,7 +2670,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_ { int res, x; int mysig; - enum analog_sub idx; + int idx; char *c; pthread_t threadid; struct ast_channel *chan; diff --git a/main/manager.c b/main/manager.c index 6c692d5d51b..2adcb3e5a6a 100644 --- a/main/manager.c +++ b/main/manager.c @@ -2342,7 +2342,7 @@ static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli " write perm: %s\n" " displayconnects: %s\n" "allowmultiplelogin: %s\n", - (user->username ? user->username : "(N/A)"), + S_OR(user->username, "(N/A)"), (user->secret ? "" : "(N/A)"), ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"), user_authority_to_str(user->readperm, &rauthority), diff --git a/res/res_pjproject.c b/res/res_pjproject.c index e9f0d15c4bb..9e08bf3e0e6 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -125,6 +125,7 @@ static void capture_buildopts_cb(int level, const char *data, int len) AST_VECTOR_ADD_SORTED(&buildopts, ast_strdup(ast_skip_blanks(data)), strcmp); } +#pragma GCC diagnostic ignored "-Wformat-nonliteral" int ast_pjproject_get_buildopt(char *option, char *format_string, ...) { int res = 0; @@ -146,6 +147,7 @@ int ast_pjproject_get_buildopt(char *option, char *format_string, ...) return res; } +#pragma GCC diagnostic warning "-Wformat-nonliteral" void ast_pjproject_log_intercept_begin(int fd) { From 2a6f18cd55d0108e7a3de2f6f71602c11ac2d485 Mon Sep 17 00:00:00 2001 From: Karsten Wemheuer Date: Tue, 2 Feb 2016 11:05:15 +0100 Subject: [PATCH 0188/1578] res_xmpp: Does not connect in component mode The module res_xmpp does not accept usernames in the form used in component mode (XEP-0114). In component mode there is no @something in the name. In component mode the connection is now not dropped anymore. If the xmpp server sends out a "stream" tag before handshake is finished, the connection gets dropped in res_xmpp. Now this tag will be ignored and the connection will be established. After connecting there will be an exchange of presence states. This does not work as expected in component mode. The responsible function "xmpp_pak_presence" is left before the states get sent out. Sending presence states in component mode is now moved to the top of the function. ASTERISK-25735 #close Change-Id: I70e036f931c3124ebb2ad1e56f93ed35cfdd9d5c --- res/res_xmpp.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 2a087b055b9..67e479d8620 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -3130,6 +3130,10 @@ static int xmpp_component_service_discovery_items_hook(void *data, ikspak *pak) /*! \brief Internal function called when we authenticated as a component */ static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node) { + if (!strcmp(iks_name(node), "stream:features")) { + return 0; + } + if (strcmp(iks_name(node), "handshake")) { ast_log(LOG_ERROR, "Failed to authenticate component '%s'\n", client->name); return -1; @@ -3305,6 +3309,11 @@ static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_cli int status = pak->show ? pak->show : STATUS_DISAPPEAR; enum ast_device_state state = AST_DEVICE_UNAVAILABLE; + /* If this is a component presence probe request answer immediately with our presence status */ + if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) { + xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg); + } + /* If no resource is available this is a general buddy presence update, which we will ignore */ if (!pak->from->resource) { return 0; @@ -3319,11 +3328,6 @@ static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_cli return 0; } - /* If this is a component presence probe request answer immediately with our presence status */ - if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) { - xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg); - } - ao2_lock(buddy->resources); if (!(resource = ao2_callback(buddy->resources, OBJ_NOLOCK, xmpp_resource_cmp, pak->from->resource))) { @@ -3864,7 +3868,7 @@ static int xmpp_client_config_post_apply(void *obj, void *arg, int flags) cfg->client->jid = iks_id_new(cfg->client->stack, cfg->user); } - if (!cfg->client->jid || ast_strlen_zero(cfg->client->jid->user)) { + if (!cfg->client->jid || (ast_strlen_zero(cfg->client->jid->user) && !ast_test_flag(&cfg->flags, XMPP_COMPONENT))) { ast_log(LOG_ERROR, "Jabber identity '%s' could not be created for client '%s' - client not active\n", cfg->user, cfg->name); return -1; } From 65223618717be8c6db93e324e2273b1dd79eb182 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 2 Feb 2016 10:52:29 -0600 Subject: [PATCH 0189/1578] res_sorcery_realtime: Fix regex regression. A regression was introduced where searching for realtime PJSIP objects by regex by starting the regex with a leading "^" would cause no items to be returned. This was due to a change which attempted to drop the requirement for a leading "^" to be present due to how some CLI commands formulate their regexes. However, the change, rather than simply eliminating the requirement, caused any regexes that did begin with "^" to end up not returning the expected results. This change fixes the problem by inspecting the regex and formulating the realtime query differently depending on if it begins with "^". ASTERISK-25702 #close Reported by Nic Colledge Patches: realtime_retrieve_regex.patch submitted by Alexei Gradinari License #5691 Change-Id: I055df608a6e6a10732044fa737a9fe8dca602693 --- res/res_sorcery_realtime.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index 1a30e0c5908..83736a102b8 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -223,7 +223,11 @@ static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, v /* The realtime API provides no direct ability to do regex so for now we support a limited subset using pattern matching */ snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); - snprintf(value, sizeof(value), "%%%s%%", regex); + if (regex[0] == '^') { + snprintf(value, sizeof(value), "%s%%", regex + 1); + } else { + snprintf(value, sizeof(value), "%%%s%%", regex); + } if (!(fields = ast_variable_new(field, value, ""))) { return; From dcbedf9ab187f999d4edc5d7eca252cc931040d9 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 3 Feb 2016 13:07:07 -0700 Subject: [PATCH 0190/1578] logging: Remove/fix some message annoyances test_dlinklists doesn't need to NOTICE everyone that every macro worked. res_phoneprov doesn't need to VERBOSE everyone that a phoneprov extension or provider was registered. res_odbc was missing a newline at the end of one message. Change-Id: I6c06361518ef3711821795e535acd439782a995e --- res/res_odbc.c | 2 +- res/res_phoneprov.c | 5 ---- tests/test_dlinklists.c | 54 ++++++++++++++++++++--------------------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/res/res_odbc.c b/res/res_odbc.c index 609d68a4cfb..81e1b3c135b 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -500,7 +500,7 @@ static int load_odbc_config(void) !strncasecmp(v->name, "share", 5) || !strcasecmp(v->name, "limit") || !strcasecmp(v->name, "idlecheck")) { - ast_log(LOG_WARNING, "The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options are deprecated. Please see UPGRADE.txt for information"); + ast_log(LOG_WARNING, "The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options are deprecated. Please see UPGRADE.txt for information\n"); } else if (!strcasecmp(v->name, "enabled")) { enabled = ast_true(v->value); } else if (!strcasecmp(v->name, "pre-connect")) { diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c index cf566b3d0ab..51c0b4a51a6 100644 --- a/res/res_phoneprov.c +++ b/res/res_phoneprov.c @@ -1476,7 +1476,6 @@ static int reload(void) ao2_lock(providers); i = ao2_iterator_init(providers, 0); for(; (provider = ao2_iterator_next(&i)); ao2_ref(provider, -1)) { - ast_log(LOG_VERBOSE, "Reloading provider '%s' users.\n", provider->provider_name); if (provider->load_users()) { ast_log(LOG_ERROR, "Unable to load provider '%s' users. Reload aborted.\n", provider->provider_name); continue; @@ -1553,7 +1552,6 @@ int ast_phoneprov_provider_register(char *provider_name, return -1; } - ast_log(LOG_VERBOSE, "Registered phoneprov provider '%s'.\n", provider_name); return 0; } @@ -1606,7 +1604,6 @@ void ast_phoneprov_provider_unregister(char *provider_name) ast_phoneprov_delete_extensions(provider_name); ao2_find(providers, provider_name, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK); - ast_log(LOG_VERBOSE, "Unegistered phoneprov provider '%s'.\n", provider_name); } int ast_phoneprov_add_extension(char *provider_name, struct varshead *vars) @@ -1679,7 +1676,6 @@ int ast_phoneprov_add_extension(char *provider_name, struct varshead *vars) ast_log(LOG_WARNING, "Could not create http routes for '%s' - skipping\n", user->macaddress); return -1; } - ast_log(LOG_VERBOSE, "Created %s/%s for provider '%s'.\n", username, mac, provider_name); ao2_link(users, user); } else { @@ -1698,7 +1694,6 @@ int ast_phoneprov_add_extension(char *provider_name, struct varshead *vars) exten = delete_extension(exten); return -1; } - ast_log(LOG_VERBOSE, "Added %s/%s for provider '%s'.\n", username, mac, provider_name); } return 0; diff --git a/tests/test_dlinklists.c b/tests/test_dlinklists.c index a4495088aaa..581bf4d5804 100644 --- a/tests/test_dlinklists.c +++ b/tests/test_dlinklists.c @@ -70,7 +70,7 @@ static void print_list(struct test_container *x, char *expect) strcat(buff," <=> "); } - ast_log(LOG_NOTICE,"Got: %s [expect %s]\n", buff, expect); + ast_debug(1,"Got: %s [expect %s]\n", buff, expect); } static void print_list_backwards(struct test_container *x, char *expect) @@ -84,7 +84,7 @@ static void print_list_backwards(struct test_container *x, char *expect) strcat(buff," <=> "); } - ast_log(LOG_NOTICE,"Got: %s [expect %s]\n", buff, expect); + ast_debug(1,"Got: %s [expect %s]\n", buff, expect); } static struct test_container *make_cont(void) @@ -180,7 +180,7 @@ static void dll_tests(void) struct test1 *d; struct test1 *e; - ast_log(LOG_NOTICE,"Test AST_DLLIST_INSERT_HEAD, AST_DLLIST_TRAVERSE, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END\n"); + ast_debug(1,"Test AST_DLLIST_INSERT_HEAD, AST_DLLIST_TRAVERSE, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END\n"); tc = make_cont(); a = make_test1("A"); b = make_test1("B"); @@ -197,9 +197,9 @@ static void dll_tests(void) tc = make_cont(); if (AST_DLLIST_EMPTY(&tc->entries)) - ast_log(LOG_NOTICE,"Test AST_DLLIST_EMPTY....OK\n"); + ast_debug(1,"Test AST_DLLIST_EMPTY....OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_EMPTY....PROBLEM!!\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_EMPTY....PROBLEM!!\n"); a = make_test1("A"); @@ -207,7 +207,7 @@ static void dll_tests(void) c = make_test1("C"); d = make_test1("D"); - ast_log(LOG_NOTICE,"Test AST_DLLIST_INSERT_TAIL\n"); + ast_debug(1,"Test AST_DLLIST_INSERT_TAIL\n"); AST_DLLIST_INSERT_TAIL(&tc->entries, a, list); AST_DLLIST_INSERT_TAIL(&tc->entries, b, list); AST_DLLIST_INSERT_TAIL(&tc->entries, c, list); @@ -215,24 +215,24 @@ static void dll_tests(void) print_list(tc, "A <=> B <=> C <=> D"); if (AST_DLLIST_FIRST(&tc->entries) == a) - ast_log(LOG_NOTICE,"Test AST_DLLIST_FIRST....OK\n"); + ast_debug(1,"Test AST_DLLIST_FIRST....OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_FIRST....PROBLEM\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_FIRST....PROBLEM\n"); if (AST_DLLIST_LAST(&tc->entries) == d) - ast_log(LOG_NOTICE,"Test AST_DLLIST_LAST....OK\n"); + ast_debug(1,"Test AST_DLLIST_LAST....OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_LAST....PROBLEM\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_LAST....PROBLEM\n"); if (AST_DLLIST_NEXT(a,list) == b) - ast_log(LOG_NOTICE,"Test AST_DLLIST_NEXT....OK\n"); + ast_debug(1,"Test AST_DLLIST_NEXT....OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_NEXT....PROBLEM\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_NEXT....PROBLEM\n"); if (AST_DLLIST_PREV(d,list) == c) - ast_log(LOG_NOTICE,"Test AST_DLLIST_PREV....OK\n"); + ast_debug(1,"Test AST_DLLIST_PREV....OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_PREV....PROBLEM\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_PREV....PROBLEM\n"); destroy_test_container(tc); @@ -243,35 +243,35 @@ static void dll_tests(void) c = make_test1("C"); d = make_test1("D"); - ast_log(LOG_NOTICE,"Test AST_DLLIST_INSERT_AFTER, AST_DLLIST_TRAVERSE_BACKWARDS\n"); + ast_debug(1,"Test AST_DLLIST_INSERT_AFTER, AST_DLLIST_TRAVERSE_BACKWARDS\n"); AST_DLLIST_INSERT_HEAD(&tc->entries, a, list); AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list); AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list); AST_DLLIST_INSERT_AFTER(&tc->entries, c, d, list); print_list_backwards(tc, "D <=> C <=> B <=> A"); - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE_HEAD\n"); + ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD\n"); AST_DLLIST_REMOVE_HEAD(&tc->entries, list); print_list_backwards(tc, "D <=> C <=> B"); - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE_HEAD\n"); + ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD\n"); AST_DLLIST_REMOVE_HEAD(&tc->entries, list); print_list_backwards(tc, "D <=> C"); - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE_HEAD\n"); + ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD\n"); AST_DLLIST_REMOVE_HEAD(&tc->entries, list); print_list_backwards(tc, "D"); AST_DLLIST_REMOVE_HEAD(&tc->entries, list); if (AST_DLLIST_EMPTY(&tc->entries)) - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE_HEAD....OK\n"); + ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD....OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE_HEAD....PROBLEM!!\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_REMOVE_HEAD....PROBLEM!!\n"); AST_DLLIST_INSERT_HEAD(&tc->entries, a, list); AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list); AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list); AST_DLLIST_INSERT_AFTER(&tc->entries, c, d, list); - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE\n"); + ast_debug(1,"Test AST_DLLIST_REMOVE\n"); AST_DLLIST_REMOVE(&tc->entries, c, list); print_list(tc, "A <=> B <=> D"); AST_DLLIST_REMOVE(&tc->entries, a, list); @@ -281,9 +281,9 @@ static void dll_tests(void) AST_DLLIST_REMOVE(&tc->entries, b, list); if (AST_DLLIST_EMPTY(&tc->entries)) - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE....OK\n"); + ast_debug(1,"Test AST_DLLIST_REMOVE....OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE....PROBLEM!!\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_REMOVE....PROBLEM!!\n"); AST_DLLIST_INSERT_HEAD(&tc->entries, a, list); AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list); @@ -295,11 +295,11 @@ static void dll_tests(void) } AST_DLLIST_TRAVERSE_SAFE_END; if (AST_DLLIST_EMPTY(&tc->entries)) - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE_CURRENT... OK\n"); + ast_debug(1,"Test AST_DLLIST_REMOVE_CURRENT... OK\n"); else - ast_log(LOG_NOTICE,"Test AST_DLLIST_REMOVE_CURRENT... PROBLEM\n"); + ast_log(LOG_ERROR,"Test AST_DLLIST_REMOVE_CURRENT... PROBLEM\n"); - ast_log(LOG_NOTICE,"Test AST_DLLIST_MOVE_CURRENT, AST_DLLIST_INSERT_BEFORE_CURRENT\n"); + ast_debug(1,"Test AST_DLLIST_MOVE_CURRENT, AST_DLLIST_INSERT_BEFORE_CURRENT\n"); AST_DLLIST_INSERT_HEAD(&tc->entries, a, list); AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list); AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list); @@ -325,7 +325,7 @@ static void dll_tests(void) c = make_test1("C"); d = make_test1("D"); - ast_log(LOG_NOTICE,"Test: AST_DLLIST_MOVE_CURRENT_BACKWARDS and AST_DLLIST_INSERT_BEFORE_CURRENT_BACKWARDS\n"); + ast_debug(1,"Test: AST_DLLIST_MOVE_CURRENT_BACKWARDS and AST_DLLIST_INSERT_BEFORE_CURRENT_BACKWARDS\n"); AST_DLLIST_INSERT_HEAD(&tc->entries, a, list); AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list); AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list); From a877e0d94b263bcb3d2b378dc952b759d58a2b43 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 28 Sep 2015 17:07:42 -0500 Subject: [PATCH 0191/1578] AST-2016-002 chan_sip.c: Fix retransmission timeout integer overflow. Setting the sip.conf timert1 value to a value higher than 1245 can cause an integer overflow and result in large retransmit timeout times. These large timeout times hold system file descriptors hostage and can cause the system to run out of file descriptors. NOTE: The default sip.conf timert1 value is 500 which does not expose the vulnerability. * The overflow is now detected and the previous timeout time is calculated. ASTERISK-25397 #close Reported by: Alexander Traud Change-Id: Ia7231f2f415af1cbf90b923e001b9219cff46290 --- channels/chan_sip.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 10b0d23f2d4..aaf0b6d51da 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3970,6 +3970,13 @@ static int retrans_pkt(const void *data) } /* For non-invites, a maximum of 4 secs */ + if (INT_MAX / pkt->timer_a < pkt->timer_t1) { + /* + * Uh Oh, we will have an integer overflow. + * Recalculate previous timeout time instead. + */ + pkt->timer_a = pkt->timer_a / 2; + } siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */ if (pkt->method != SIP_INVITE && siptimer_a > 4000) { siptimer_a = 4000; From e67b445e8dcca2bff043f2ed095b7fa8f5311c61 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 7 Dec 2015 12:46:53 -0600 Subject: [PATCH 0192/1578] AST-2016-003 udptl.c: Fix uninitialized values. Sending UDPTL packets to Asterisk with the right amount of missing sequence numbers and enough redundant 0-length IFP packets, can make Asterisk crash. ASTERISK-25603 #close Reported by: Walter Doekes ASTERISK-25742 #close Reported by: Torrey Searle Change-Id: I97df8375041be986f3f266ac1946a538023a5255 --- main/udptl.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/main/udptl.c b/main/udptl.c index c059ad3a4b5..a0f533fd0cc 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -305,16 +305,15 @@ static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len, if (decode_length(buf, limit, len, &octet_cnt) != 0) return -1; - if (octet_cnt > 0) { - /* Make sure the buffer contains at least the number of bits requested */ - if ((*len + octet_cnt) > limit) - return -1; - - *p_num_octets = octet_cnt; - *p_object = &buf[*len]; - *len += octet_cnt; + /* Make sure the buffer contains at least the number of bits requested */ + if ((*len + octet_cnt) > limit) { + return -1; } + *p_num_octets = octet_cnt; + *p_object = &buf[*len]; + *len += octet_cnt; + return 0; } /*- End of function --------------------------------------------------------*/ From 0de74fad5597ba12ec68bcc935330a612ee255d6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 3 Feb 2016 14:05:20 -0400 Subject: [PATCH 0193/1578] AST-2016-001 http: Provide greater control of TLS and set modern defaults. This change exposes the configuration of various aspects of the TLS support and sets the default to the modern standards. The TLS cipher is now set to the best values according to the Mozilla OpSec team, different TLS versions can now be disabled, and the cipher order can be forced to be that of the server instead of the client. ASTERISK-24972 #close Change-Id: I0a10f2883f7559af5e48dee0901251dbf30d45b8 --- configs/samples/http.conf.sample | 20 ++++++++++++++++++++ include/asterisk/tcptls.h | 10 +++++++++- main/http.c | 7 ++++--- main/tcptls.c | 30 ++++++++++++++++++++++++++---- 4 files changed, 59 insertions(+), 8 deletions(-) diff --git a/configs/samples/http.conf.sample b/configs/samples/http.conf.sample index a4093bd88a7..28437b0f505 100644 --- a/configs/samples/http.conf.sample +++ b/configs/samples/http.conf.sample @@ -90,6 +90,26 @@ bindaddr=127.0.0.1 ; private in same .pem file. ; openssl req -new -x509 -days 365 -nodes -out /tmp/foo.pem -keyout /tmp/foo.pem ; +; tlscipher= ; The list of allowed ciphers +; ; if none are specified the following cipher +; ; list will be used instead: +; ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384: +; ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256: +; kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA: +; ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384: +; ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA: +; DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA: +; AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA: +; AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH: +; !EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA +; +; tlsdisablev1=yes ; Disable TLSv1 support - if not set this defaults to "yes" +; tlsdisablev11=yes ; Disable TLSv1.1 support - if not set this defaults to "no" +; tlsdisablev12=yes ; Disable TLSv1.2 support - if not set this defaults to "no" +; +; tlsservercipherorder=yes ; Use the server preference order instead of the client order +; ; Defaults to "yes" +; ; The post_mappings section maps URLs to real paths on the filesystem. If a ; POST is done from within an authenticated manager session to one of the ; configured POST mappings, then any files in the POST will be placed in the diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h index a3f3f2884a7..3c5f4504caf 100644 --- a/include/asterisk/tcptls.h +++ b/include/asterisk/tcptls.h @@ -87,7 +87,15 @@ enum ast_ssl_flags { /*! Use SSLv3 for outgoing client connections */ AST_SSL_SSLV3_CLIENT = (1 << 4), /*! Use TLSv1 for outgoing client connections */ - AST_SSL_TLSV1_CLIENT = (1 << 5) + AST_SSL_TLSV1_CLIENT = (1 << 5), + /*! Use server cipher order instead of the client order */ + AST_SSL_SERVER_CIPHER_ORDER = (1 << 6), + /*! Disable TLSv1 support */ + AST_SSL_DISABLE_TLSV1 = (1 << 7), + /*! Disable TLSv1.1 support */ + AST_SSL_DISABLE_TLSV11 = (1 << 8), + /*! Disable TLSv1.2 support */ + AST_SSL_DISABLE_TLSV12 = (1 << 9), }; struct ast_tls_config { diff --git a/main/http.c b/main/http.c index 3a9d9ce9cbf..5ec94a7e199 100644 --- a/main/http.c +++ b/main/http.c @@ -2102,10 +2102,13 @@ static int __ast_http_load(int reload) } http_tls_cfg.pvtfile = ast_strdup(""); + /* Apply modern intermediate settings according to the Mozilla OpSec team as of July 30th, 2015 but disable TLSv1 */ + ast_set_flag(&http_tls_cfg.flags, AST_SSL_DISABLE_TLSV1 | AST_SSL_SERVER_CIPHER_ORDER); + if (http_tls_cfg.cipher) { ast_free(http_tls_cfg.cipher); } - http_tls_cfg.cipher = ast_strdup(""); + http_tls_cfg.cipher = ast_strdup("ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"); AST_RWLIST_WRLOCK(&uri_redirects); while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) { @@ -2131,8 +2134,6 @@ static int __ast_http_load(int reload) && strcasecmp(v->name, "tlsdontverifyserver") && strcasecmp(v->name, "tlsclientmethod") && strcasecmp(v->name, "sslclientmethod") - && strcasecmp(v->name, "tlscipher") - && strcasecmp(v->name, "sslcipher") && !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) { continue; } diff --git a/main/tcptls.c b/main/tcptls.c index 7ead094ac04..39417946303 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -816,7 +816,8 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client) return 0; #else int disable_ssl = 0; - + long ssl_opts = 0; + if (!cfg->enabled) { return 0; } @@ -864,11 +865,24 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client) * them. SSLv23_*_method supports TLSv1+. */ if (disable_ssl) { - long ssl_opts; + ssl_opts |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + } + + if (ast_test_flag(&cfg->flags, AST_SSL_SERVER_CIPHER_ORDER)) { + ssl_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE; + } - ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; - SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts); + if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV1)) { + ssl_opts |= SSL_OP_NO_TLSv1; } + if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV11)) { + ssl_opts |= SSL_OP_NO_TLSv1_1; + } + if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV12)) { + ssl_opts |= SSL_OP_NO_TLSv1_2; + } + + SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts); SSL_CTX_set_verify(cfg->ssl_ctx, ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, @@ -1232,6 +1246,14 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_ ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); } + } else if (!strcasecmp(varname, "tlsservercipherorder")) { + ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_SERVER_CIPHER_ORDER); + } else if (!strcasecmp(varname, "tlsdisablev1")) { + ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DISABLE_TLSV1); + } else if (!strcasecmp(varname, "tlsdisablev11")) { + ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DISABLE_TLSV11); + } else if (!strcasecmp(varname, "tlsdisablev12")) { + ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DISABLE_TLSV12); } else { return -1; } From d83dba7099f990027e1d6408c12a2ef9b0db3af0 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 27 Jan 2016 11:44:10 -0500 Subject: [PATCH 0194/1578] res_rtp_asterisk: Allow ICE host candidates to be overriden During ICE negotiation the IPs of the local interfaces are sent to the remote peer as host candidates. In many cases Asterisk is behind a static one-to-one NAT, so these host addresses will be internal IP addresses. To help in hiding the topology of the internal network, this patch adds the ability to override the host candidates by matching them against a user-defined list of replacements. Change-Id: I1c9541af97b83a4c690c8150d19bf7202c8bff1f --- CHANGES | 7 +++ configs/samples/rtp.conf.sample | 27 +++++++++++ res/res_rtp_asterisk.c | 81 +++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) diff --git a/CHANGES b/CHANGES index 173a41127c7..d24f840e57a 100644 --- a/CHANGES +++ b/CHANGES @@ -257,6 +257,13 @@ res_pjsip_sdp_rtp originate from the media address instead of the operating system's "primary" ip address. +res_rtp_asterisk +------------------ + * A new configuration section - ice_host_candidates - has been added to + rtp.conf, allowing automatically discovered ICE host candidates to be + overriden. This allows an Asterisk server behind a 1:1 NAT to send its + external IP as a host candidate rather than relying on STUN to discover it. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.6.0 to Asterisk 13.7.0 ------------ ------------------------------------------------------------------------------ diff --git a/configs/samples/rtp.conf.sample b/configs/samples/rtp.conf.sample index c22acaa9fa5..2ef5dd28a7c 100644 --- a/configs/samples/rtp.conf.sample +++ b/configs/samples/rtp.conf.sample @@ -58,3 +58,30 @@ rtpend=20000 ; ; Password used to authenticate with TURN relay server. ; turnpassword= +; +[ice_host_candidates] +; +; When Asterisk is behind a static one-to-one NAT and ICE is in use, ICE will +; expose the server's internal IP address as one of the host candidates. +; Although using STUN (see the 'stunaddr' configuration option) will provide a +; publicly accessible IP, the internal IP will still be sent to the remote +; peer. To help hide the topology of your internal network, you can override +; the host candidates that Asterisk will send to the remote peer. +; +; IMPORTANT: Only use this functionality when your Asterisk server is behind a +; one-to-one NAT and you know what you're doing. If you do define anything +; here, you almost certainly will NOT want to specify 'stunaddr' or 'turnaddr' +; above. +; +; The format for these overrides is: +; +; => +; +; The following will replace 192.168.1.10 with 1.2.3.4 during ICE +; negotiation: +; +;192.168.1.10 => 1.2.3.4 +; +; You can define an override for more than 1 interface if you have a multihomed +; server. Any local interface that is not matched will be passed through +; unaltered. Both IPv4 and IPv6 addresses are supported. diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 85d997fc2ff..9c7432e8c07 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -182,6 +182,16 @@ struct ast_rtp_ioqueue_thread { /*! \brief List of ioqueue threads */ static AST_LIST_HEAD_STATIC(ioqueues, ast_rtp_ioqueue_thread); +/*! \brief Structure which contains ICE host candidate mapping information */ +struct ast_ice_host_candidate { + pj_sockaddr local; + pj_sockaddr advertised; + AST_RWLIST_ENTRY(ast_ice_host_candidate) next; +}; + +/*! \brief List of ICE host candidate mappings */ +static AST_RWLIST_HEAD_STATIC(host_candidates, ast_ice_host_candidate); + #endif #define FLAG_3389_WARNING (1 << 0) @@ -451,6 +461,38 @@ static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, stru static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp); #ifdef HAVE_PJPROJECT +/*! \brief Helper function which clears the ICE host candidate mapping */ +static void host_candidate_overrides_clear(void) +{ + struct ast_ice_host_candidate *candidate; + + AST_RWLIST_WRLOCK(&host_candidates); + AST_RWLIST_TRAVERSE_SAFE_BEGIN(&host_candidates, candidate, next) { + AST_RWLIST_REMOVE_CURRENT(next); + ast_free(candidate); + } + AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_UNLOCK(&host_candidates); +} + +/*! \brief Applies the ICE host candidate mapping */ +static void host_candidate_overrides_apply(unsigned int count, pj_sockaddr addrs[]) +{ + int pos; + struct ast_ice_host_candidate *candidate; + + AST_RWLIST_RDLOCK(&host_candidates); + for (pos = 0; pos < count; pos++) { + AST_LIST_TRAVERSE(&host_candidates, candidate, next) { + if (!pj_sockaddr_cmp(&candidate->local, &addrs[pos])) { + pj_sockaddr_copy_addr(&addrs[pos], &candidate->advertised); + break; + } + } + } + AST_RWLIST_UNLOCK(&host_candidates); +} + /*! \brief Helper function which updates an ast_sockaddr with the candidate used for the component */ static void update_address_with_ice_candidate(struct ast_rtp *rtp, enum ast_rtp_ice_component_type component, struct ast_sockaddr *cand_address) @@ -2368,6 +2410,8 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct pj_enum_ip_interface(pj_AF_INET6(), &count, address); } + host_candidate_overrides_apply(count, address); + for (pos = 0; pos < count; pos++) { pj_sockaddr_set_port(&address[pos], port); ast_rtp_ice_add_cand(rtp, component, transport, PJ_ICE_CAND_TYPE_HOST, 65535, &address[pos], &address[pos], NULL, @@ -5256,6 +5300,11 @@ static int rtp_reload(int reload) const char *s; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; +#ifdef HAVE_PJPROJECT + struct ast_variable *var; + struct ast_ice_host_candidate *candidate; +#endif + cfg = ast_config_load2("rtp.conf", "rtp", config_flags); if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { return 0; @@ -5282,6 +5331,7 @@ static int rtp_reload(int reload) turnaddr = pj_str(NULL); turnusername = pj_str(NULL); turnpassword = pj_str(NULL); + host_candidate_overrides_clear(); #endif if (cfg) { @@ -5361,6 +5411,36 @@ static int rtp_reload(int reload) if ((s = ast_variable_retrieve(cfg, "general", "turnpassword"))) { pj_strdup2_with_null(pool, &turnpassword, s); } + + AST_RWLIST_WRLOCK(&host_candidates); + for (var = ast_variable_browse(cfg, "ice_host_candidates"); var; var = var->next) { + struct ast_sockaddr local_addr, advertised_addr; + pj_str_t address; + + ast_sockaddr_setnull(&local_addr); + ast_sockaddr_setnull(&advertised_addr); + + if (ast_parse_arg(var->name, PARSE_ADDR | PARSE_PORT_IGNORE, &local_addr)) { + ast_log(LOG_WARNING, "Invalid local ICE host address: %s\n", var->name); + continue; + } + + if (ast_parse_arg(var->value, PARSE_ADDR | PARSE_PORT_IGNORE, &advertised_addr)) { + ast_log(LOG_WARNING, "Invalid advertised ICE host address: %s\n", var->value); + continue; + } + + if (!(candidate = ast_calloc(1, sizeof(*candidate)))) { + ast_log(LOG_ERROR, "Failed to allocate ICE host candidate mapping.\n"); + break; + } + + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&local_addr)), &candidate->local); + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&advertised_addr)), &candidate->advertised); + + AST_RWLIST_INSERT_TAIL(&host_candidates, candidate, next); + } + AST_RWLIST_UNLOCK(&host_candidates); #endif ast_config_destroy(cfg); } @@ -5463,6 +5543,7 @@ static int unload_module(void) ast_cli_unregister_multiple(cli_rtp, ARRAY_LEN(cli_rtp)); #ifdef HAVE_PJPROJECT + host_candidate_overrides_clear(); pj_thread_register_check(); rtp_terminate_pjproject(); #endif From 82e2938fa873f9d680b7924ac5c9822fd1995a84 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 4 Feb 2016 11:39:10 -0600 Subject: [PATCH 0195/1578] res_stasis_device_state: Fix refcounting error. Device state subscription lifetimes were governed by when the subscription was established and unsubscribed from. However, it is possible that at the time of unsubscription, there could be device state events still in flight. When those device state events occur, the device state callback could attempt to dereference a freed pointer. Crash. This change ensures that the lifetime of the device state subscription does not end until the underlying stasis subscription has confirmed that its final message has been sent. Change-Id: I25a0f1472894c1a562252fb7129671478e25e9b2 --- res/res_stasis_device_state.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c index 40936460c19..453bfae6d61 100644 --- a/res/res_stasis_device_state.c +++ b/res/res_stasis_device_state.c @@ -303,6 +303,12 @@ static void device_state_cb(void *data, struct stasis_subscription *sub, { struct ast_device_state_message *device_state; + if (stasis_subscription_final_message(sub, msg)) { + /* Remove stasis subscription's reference to device_state_subscription */ + ao2_ref(data, -1); + return; + } + if (ast_device_state_message_type() != stasis_message_type(msg)) { return; } @@ -365,10 +371,12 @@ static int subscribe_device_state(struct stasis_app *app, void *obj) ast_debug(3, "Subscribing to device %s\n", sub->device_name); - sub->sub = stasis_subscribe_pool(topic, device_state_cb, sub); + sub->sub = stasis_subscribe_pool(topic, device_state_cb, ao2_bump(sub)); if (!sub->sub) { ast_log(LOG_ERROR, "Unable to subscribe to device %s\n", sub->device_name); + /* Reference we added when attempting to stasis_subscribe_pool */ + ao2_ref(sub, -1); return -1; } From 9b13ab6a632dc13c613ae3cacb2d398a733eaf6e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 3 Feb 2016 13:25:23 -0700 Subject: [PATCH 0196/1578] pjsip/alembic: Add missing columns to system and registration ps_systems needed disable_tcp_switch ps_registrations needed line and endpoint ASTERISK-25737 #close Change-Id: Iaf9c2d69e62243d9fa53104c28c5339c47d4ac19 --- configs/samples/pjsip.conf.sample | 9 +++++ ...a908_add_missing_columns_to_sys_and_reg.py | 37 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 363ef8557e2..5c326f2c570 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -948,6 +948,15 @@ ; 407 become subject to this retry interval. ;server_uri= ; SIP URI of the server to register against (default: "") ;transport= ; Transport used for outbound authentication (default: "") +;line= ; When enabled this option will cause a 'line' parameter to be + ; added to the Contact header placed into the outgoing + ; registration request. If the remote server sends a call + ; this line parameter will be used to establish a relationship + ; to the outbound registration, ultimately causing the + ; configured endpoint to be used (default: "no") +;endpoint= ; When line support is enabled this configured endpoint name + ; is used for incoming calls that are related to the outbound + ; registration (default: "") ;type= ; Must be of type registration (default: "") diff --git a/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py new file mode 100644 index 00000000000..8f4621642de --- /dev/null +++ b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py @@ -0,0 +1,37 @@ +"""Add missing columns to system and registration + +Revision ID: dbc44d5a908 +Revises: 423f34ad36e2 +Create Date: 2016-02-03 13:15:15.083043 + +""" + +# revision identifiers, used by Alembic. +revision = 'dbc44d5a908' +down_revision = '423f34ad36e2' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_systems', sa.Column('disable_tcp_switch', yesno_values)) + op.add_column('ps_registrations', sa.Column('line', yesno_values)) + op.add_column('ps_registrations', sa.Column('endpoint', sa.String(40))) + pass + + +def downgrade(): + op.drop_column('ps_systems', 'disable_tcp_switch') + op.drop_column('ps_registrations', 'line') + op.drop_column('ps_registrations', 'endpoint') + pass From 3b426a8b09c127941b29600271184583f2199a19 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 4 Feb 2016 16:17:55 -0600 Subject: [PATCH 0197/1578] Check for OpenSSL defines before trying to use them. The SSL_OP_NO_TLSv1_1 and SSL_OP_NO_TLSv1_2 defines did not exist prior to OpenSSL version 1.0.1. A recent commit attempts to, by default, set these options, which can cause problems on systems with older OpenSSL installations. This commit adds a configure script check for those defines and will not attempt to make use of those if they do not exist. We will print a warning urging the user to upgrade their OpenSSL installation if those defines are not present. Change-Id: I6a2eb9a43fd0738b404d8f6f2cf4b5c22d9d752d --- configure | 108 +++++++++++++++++++++++++++++-- configure.ac | 6 ++ include/asterisk/autoconfig.h.in | 6 ++ main/tcptls.c | 5 ++ 4 files changed, 120 insertions(+), 5 deletions(-) diff --git a/configure b/configure index fc7613120e6..c382032463f 100755 --- a/configure +++ b/configure @@ -651,6 +651,8 @@ PBX_MSG_NOSIGNAL PBX_IXJUSER GMIME_LIBS GMIME_CFLAGS +PBX_SSL_OP_NO_TLSV1_2 +PBX_SSL_OP_NO_TLSV1_1 OPENH323_BUILD OPENH323_SUFFIX OPENH323_LIBDIR @@ -13695,7 +13697,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13741,7 +13743,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13765,7 +13767,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13810,7 +13812,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13834,7 +13836,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -30763,6 +30765,102 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi +if test "$PBX_OPENSSL" = "1"; +then + + if test "x${PBX_SSL_OP_NO_TLSV1_1}" != "x1"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_OP_NO_TLSv1_1 in openssl/ssl.h" >&5 +$as_echo_n "checking for SSL_OP_NO_TLSv1_1 in openssl/ssl.h... " >&6; } + saved_cppflags="${CPPFLAGS}" + if test "x${SSL_OP_NO_TLSV1_1_DIR}" != "x"; then + SSL_OP_NO_TLSV1_1_INCLUDE="-I${SSL_OP_NO_TLSV1_1_DIR}/include" + fi + CPPFLAGS="${CPPFLAGS} ${SSL_OP_NO_TLSV1_1_INCLUDE}" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ +#if defined(SSL_OP_NO_TLSv1_1) + int foo = 0; + #else + int foo = bar; + #endif + 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_SSL_OP_NO_TLSV1_1=1 + +$as_echo "#define HAVE_SSL_OP_NO_TLSV1_1 1" >>confdefs.h + + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CPPFLAGS="${saved_cppflags}" + fi + + + + if test "x${PBX_SSL_OP_NO_TLSV1_2}" != "x1"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_OP_NO_TLSv1_2 in openssl/ssl.h" >&5 +$as_echo_n "checking for SSL_OP_NO_TLSv1_2 in openssl/ssl.h... " >&6; } + saved_cppflags="${CPPFLAGS}" + if test "x${SSL_OP_NO_TLSV1_2_DIR}" != "x"; then + SSL_OP_NO_TLSV1_2_INCLUDE="-I${SSL_OP_NO_TLSV1_2_DIR}/include" + fi + CPPFLAGS="${CPPFLAGS} ${SSL_OP_NO_TLSV1_2_INCLUDE}" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ +#if defined(SSL_OP_NO_TLSv1_2) + int foo = 0; + #else + int foo = bar; + #endif + 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_SSL_OP_NO_TLSV1_2=1 + +$as_echo "#define HAVE_SSL_OP_NO_TLSV1_2 1" >>confdefs.h + + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CPPFLAGS="${saved_cppflags}" + fi + + +fi + if test "x${PBX_SRTP}" != "x1" -a "${USE_SRTP}" != "no"; then pbxlibdir="" diff --git a/configure.ac b/configure.ac index e7b7e578100..723b0af0f24 100644 --- a/configure.ac +++ b/configure.ac @@ -2302,6 +2302,12 @@ then AST_C_DECLARE_CHECK([OPENSSL_ECDH_AUTO], [SSL_CTX_set_ecdh_auto], [openssl/ssl.h]) fi +if test "$PBX_OPENSSL" = "1"; +then + AST_C_DEFINE_CHECK([SSL_OP_NO_TLSV1_1], [SSL_OP_NO_TLSv1_1], [openssl/ssl.h]) + AST_C_DEFINE_CHECK([SSL_OP_NO_TLSV1_2], [SSL_OP_NO_TLSv1_2], [openssl/ssl.h]) +fi + AST_EXT_LIB_CHECK([SRTP], [srtp], [srtp_init], [srtp/srtp.h]) if test "$PBX_SRTP" = "1"; diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index d86ba4a6aad..a9179bae679 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -832,6 +832,12 @@ /* Define to 1 if you have the ISDN SS7 library. */ #undef HAVE_SS7 +/* Define if your system has the SSL_OP_NO_TLSV1_1 headers. */ +#undef HAVE_SSL_OP_NO_TLSV1_1 + +/* Define if your system has the SSL_OP_NO_TLSV1_2 headers. */ +#undef HAVE_SSL_OP_NO_TLSV1_2 + /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG diff --git a/main/tcptls.c b/main/tcptls.c index 39417946303..f56e0aa70c3 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -875,12 +875,17 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client) if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV1)) { ssl_opts |= SSL_OP_NO_TLSv1; } +#if defined(HAVE_SSL_OP_NO_TLSV1_1) && defined(HAVE_SSL_OP_NO_TLSV1_2) if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV11)) { ssl_opts |= SSL_OP_NO_TLSv1_1; } if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV12)) { ssl_opts |= SSL_OP_NO_TLSv1_2; } +#else + ast_log(LOG_WARNING, "Your version of OpenSSL leaves you potentially vulnerable " + "to the SSL BEAST attack. Please upgrade to OpenSSL 1.0.1 or later\n"); +#endif SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts); From 1bc54aee8037b6338bd53625e6c8d7699b40a9f7 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 25 Jan 2016 17:36:50 -0600 Subject: [PATCH 0198/1578] app_confbridge: Only use b_profile options from the conference. A user cannot set new bridge options after the conference is created by the first user. Attempting to do so is documented as undefined behavior. This patch ensures that the bridge profile options used are from the conference and not what a subsequent user may have tried to set. Change-Id: I1b6383eba654679e5739d5a8de98199cf074a266 --- apps/app_confbridge.c | 63 ++++++++++++----------- apps/confbridge/conf_state_multi_marked.c | 12 ++--- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 97c73bd7444..b3609b6734a 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1085,7 +1085,7 @@ void conf_update_user_mute(struct confbridge_user *user) "Conference: %s\r\n" "Channel: %s", mute_effective ? "muted" : "unmuted", - user->b_profile.name, + user->conference->b_profile.name, ast_channel_name(user->chan)); } @@ -1206,7 +1206,7 @@ int conf_handle_inactive_waitmarked(struct confbridge_user *user) { /* If we have not been quieted play back that they are waiting for the leader */ if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET) && play_prompt_to_user(user, - conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, user->b_profile.sounds))) { + conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, user->conference->b_profile.sounds))) { /* user hungup while the sound was playing */ return -1; } @@ -1218,7 +1218,7 @@ int conf_handle_only_unmarked(struct confbridge_user *user) /* If audio prompts have not been quieted or this prompt quieted play it on out */ if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) { if (play_prompt_to_user(user, - conf_get_sound(CONF_SOUND_ONLY_PERSON, user->b_profile.sounds))) { + conf_get_sound(CONF_SOUND_ONLY_PERSON, user->conference->b_profile.sounds))) { /* user hungup while the sound was playing */ return -1; } @@ -1292,11 +1292,11 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen /* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */ if (conference && (max_members_reached || conference->locked) && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) { ao2_unlock(conference_bridges); - ao2_ref(conference, -1); ast_debug(1, "Conference '%s' is locked and caller is not an admin\n", conference_name); ast_stream_and_wait(user->chan, - conf_get_sound(CONF_SOUND_LOCKED, user->b_profile.sounds), - ""); + conf_get_sound(CONF_SOUND_LOCKED, conference->b_profile.sounds), + ""); + ao2_ref(conference, -1); return NULL; } @@ -1330,7 +1330,6 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen app, conference_name, NULL); if (!conference->bridge) { ao2_ref(conference, -1); - conference = NULL; ao2_unlock(conference_bridges); ast_log(LOG_ERROR, "Conference '%s' mixing bridge could not be created.\n", conference_name); return NULL; @@ -1348,7 +1347,6 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen /* Link it into the conference bridges container */ if (!ao2_link(conference_bridges, conference)) { ao2_ref(conference, -1); - conference = NULL; ao2_unlock(conference_bridges); ast_log(LOG_ERROR, "Conference '%s' could not be added to the conferences list.\n", conference_name); @@ -1393,6 +1391,7 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen /* Invalid event, nothing was done, so we don't want to process a leave. */ ao2_unlock(conference); ao2_ref(conference, -1); + user->conference = NULL; return NULL; } @@ -1584,7 +1583,12 @@ static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user) const char *pin = user->u_profile.pin; char *tmp = pin_guess; int i, res; - unsigned int len = MAX_PIN ; + unsigned int len = MAX_PIN; + + /* + * NOTE: We have not joined a conference yet so we have to use + * the bridge profile requested by the user. + */ /* give them three tries to get the pin right */ for (i = 0; i < 3; i++) { @@ -1836,13 +1840,13 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) ast_autoservice_start(chan); play_sound_file(conference, user.name_rec_location); play_sound_file(conference, - conf_get_sound(CONF_SOUND_HAS_JOINED, user.b_profile.sounds)); + conf_get_sound(CONF_SOUND_HAS_JOINED, conference->b_profile.sounds)); ast_autoservice_stop(chan); } /* Play the Join sound to both the conference and the user entering. */ if (!quiet) { - const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, user.b_profile.sounds); + const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference->b_profile.sounds); ast_stream_and_wait(chan, join_sound, ""); ast_autoservice_start(chan); @@ -1901,29 +1905,29 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) ast_autoservice_start(chan); play_sound_file(conference, user.name_rec_location); play_sound_file(conference, - conf_get_sound(CONF_SOUND_HAS_LEFT, user.b_profile.sounds)); + conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds)); ast_autoservice_stop(chan); } /* play the leave sound */ if (!quiet) { - const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, user.b_profile.sounds); + const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference->b_profile.sounds); ast_autoservice_start(chan); play_sound_file(conference, leave_sound); ast_autoservice_stop(chan); } - /* Easy as pie, depart this channel from the conference bridge */ - leave_conference(&user); - conference = NULL; - /* If the user was kicked from the conference play back the audio prompt for it */ if (!quiet && user.kicked) { res = ast_stream_and_wait(chan, - conf_get_sound(CONF_SOUND_KICKED, user.b_profile.sounds), + conf_get_sound(CONF_SOUND_KICKED, conference->b_profile.sounds), ""); } + /* Easy as pie, depart this channel from the conference bridge */ + leave_conference(&user); + conference = NULL; + /* Restore volume adjustments to previous values in case they were changed */ if (volume_adjustments[0]) { ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]); @@ -1952,9 +1956,9 @@ static int action_toggle_mute(struct confbridge_conference *conference, mute = !user->muted; generic_mute_unmute_user(conference, user, mute); - return play_file(bridge_channel, NULL, (mute ? - conf_get_sound(CONF_SOUND_MUTED, user->b_profile.sounds) : - conf_get_sound(CONF_SOUND_UNMUTED, user->b_profile.sounds))) < 0; + return play_file(bridge_channel, NULL, + conf_get_sound(mute ? CONF_SOUND_MUTED : CONF_SOUND_UNMUTED, + conference->b_profile.sounds)) < 0; } static int action_toggle_mute_participants(struct confbridge_conference *conference, struct confbridge_user *user) @@ -1979,8 +1983,9 @@ static int action_toggle_mute_participants(struct confbridge_conference *confere ao2_unlock(conference); - sound_to_play = conf_get_sound((mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED), - user->b_profile.sounds); + sound_to_play = conf_get_sound( + mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED, + conference->b_profile.sounds); /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */ ast_stream_and_wait(user->chan, sound_to_play, ""); @@ -2087,7 +2092,7 @@ static int action_kick_last(struct confbridge_conference *conference, if (!isadmin) { play_file(bridge_channel, NULL, - conf_get_sound(CONF_SOUND_ERROR_MENU, user->b_profile.sounds)); + conf_get_sound(CONF_SOUND_ERROR_MENU, conference->b_profile.sounds)); ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n", ast_channel_name(bridge_channel->chan), conference->name); @@ -2099,7 +2104,7 @@ static int action_kick_last(struct confbridge_conference *conference, || (ast_test_flag(&last_user->u_profile, USER_OPT_ADMIN))) { ao2_unlock(conference); play_file(bridge_channel, NULL, - conf_get_sound(CONF_SOUND_ERROR_MENU, user->b_profile.sounds)); + conf_get_sound(CONF_SOUND_ERROR_MENU, conference->b_profile.sounds)); } else if (last_user && !last_user->kicked) { last_user->kicked = 1; pbx_builtin_setvar_helper(last_user->chan, "CONFBRIDGE_RESULT", "KICKED"); @@ -2228,9 +2233,9 @@ static int execute_menu_entry(struct confbridge_conference *conference, } conference->locked = (!conference->locked ? 1 : 0); res |= play_file(bridge_channel, NULL, - (conference->locked ? - conf_get_sound(CONF_SOUND_LOCKED_NOW, user->b_profile.sounds) : - conf_get_sound(CONF_SOUND_UNLOCKED_NOW, user->b_profile.sounds))) < 0; + conf_get_sound( + conference->locked ? CONF_SOUND_LOCKED_NOW : CONF_SOUND_UNLOCKED_NOW, + conference->b_profile.sounds)) < 0; break; case MENU_ACTION_ADMIN_KICK_LAST: res |= action_kick_last(conference, bridge_channel, user); @@ -2461,7 +2466,7 @@ static void handle_cli_confbridge_list_item(struct ast_cli_args *a, struct confb ast_channel_name(user->chan), flag_str, user->u_profile.name, - user->b_profile.name, + user->conference->b_profile.name, user->menu_name, S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "")); diff --git a/apps/confbridge/conf_state_multi_marked.c b/apps/confbridge/conf_state_multi_marked.c index 5d977f7a2a0..fabe99b9054 100644 --- a/apps/confbridge/conf_state_multi_marked.c +++ b/apps/confbridge/conf_state_multi_marked.c @@ -163,7 +163,7 @@ static void leave_marked(struct confbridge_user *user) ao2_unlock(user->conference); ast_autoservice_start(user->chan); play_sound_file(user->conference, - conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, user->b_profile.sounds)); + conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, user->conference->b_profile.sounds)); ast_autoservice_stop(user->chan); ao2_lock(user->conference); } @@ -182,14 +182,14 @@ static void leave_marked(struct confbridge_user *user) } } -static int post_join_play_begin(struct confbridge_user *cbu) +static int post_join_play_begin(struct confbridge_user *user) { int res; - ast_autoservice_start(cbu->chan); - res = play_sound_file(cbu->conference, - conf_get_sound(CONF_SOUND_BEGIN, cbu->b_profile.sounds)); - ast_autoservice_stop(cbu->chan); + ast_autoservice_start(user->chan); + res = play_sound_file(user->conference, + conf_get_sound(CONF_SOUND_BEGIN, user->conference->b_profile.sounds)); + ast_autoservice_stop(user->chan); return res; } From b69729dde54792cc43d2ce0f281075867f3fbdf8 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 5 Feb 2016 09:29:00 -0700 Subject: [PATCH 0199/1578] chan_misdn: Fix a few issues causing compile errors Change-Id: I54b48c24d7ca88ed80496fdfd142d08772a7ab98 --- channels/chan_misdn.c | 4 ++-- channels/misdn_config.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index 4bfb1993d70..67f009d5024 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -369,8 +369,8 @@ struct hold_info { int channel; }; -#define chan_list_ref(obj, debug) (ao2_t_ref((obj), +1, (debug)), (obj)) -#define chan_list_unref(obj, debug) (ao2_t_ref((obj), -1, (debug)), NULL) +#define chan_list_ref(obj, debug) ao2_t_ref((obj), +1, (debug)) +#define chan_list_unref(obj, debug) ao2_t_ref((obj), -1, (debug)) /*! * \brief Channel call record structure diff --git a/channels/misdn_config.c b/channels/misdn_config.c index 5915b6e9e4c..ef644f2cbb7 100644 --- a/channels/misdn_config.c +++ b/channels/misdn_config.c @@ -698,7 +698,7 @@ void misdn_cfg_get_desc (enum misdn_cfg_elements elem, void *buf, int bufsize, v else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST)) spec = (struct misdn_cfg_spec *)gen_spec; - if (!spec || !spec[place].desc) + if (!spec) memset(buf, 0, 1); else { ast_copy_string(buf, spec[place].desc, bufsize); From 72bf53eea5b5220e537f9895192ba5cf5173bddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sun, 7 Feb 2016 16:00:24 -0300 Subject: [PATCH 0200/1578] res_config_pgsql: Add message on cli failed command status In case failed of command "realtime show pgsql status" show a message the data of connection to more clear information in error. Change-Id: Ia8e9e2400466606e7118f52a46e05df0719b6a29 --- res/res_config_pgsql.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 7fe1daa650f..d0e01bc8d49 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999-2010, Digium, Inc. + * Copyright (C) 1999 - 2016, Digium, Inc. * * Manuel Guesdon - PostgreSQL RealTime Driver Author/Adaptor * Mark Spencer - Asterisk Author @@ -1571,7 +1571,7 @@ static char *handle_cli_realtime_pgsql_cache(struct ast_cli_entry *e, int cmd, s static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char status[256], credentials[100] = ""; + char connection_info[256], credentials[100] = ""; int ctimesec = time(NULL) - connect_time; switch (cmd) { @@ -1588,36 +1588,37 @@ static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, if (a->argc != 4) return CLI_SHOWUSAGE; - if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { - if (!ast_strlen_zero(dbhost)) - snprintf(status, sizeof(status), "Connected to %s@%s, port %d", dbname, dbhost, dbport); - else if (!ast_strlen_zero(dbsock)) - snprintf(status, sizeof(status), "Connected to %s on socket file %s", dbname, dbsock); - else - snprintf(status, sizeof(status), "Connected to %s@%s", dbname, dbhost); + if (!ast_strlen_zero(dbhost)) + snprintf(connection_info, sizeof(connection_info), "%s@%s, port %d", dbname, dbhost, dbport); + else if (!ast_strlen_zero(dbsock)) + snprintf(connection_info, sizeof(connection_info), "%s on socket file %s", dbname, dbsock); + else + snprintf(connection_info, sizeof(connection_info), "%s@%s", dbname, dbhost); - if (!ast_strlen_zero(dbuser)) - snprintf(credentials, sizeof(credentials), " with username %s", dbuser); + if (!ast_strlen_zero(dbuser)) + snprintf(credentials, sizeof(credentials), " with username %s", dbuser); + if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { if (ctimesec > 31536000) - ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", - status, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400, + ast_cli(a->fd, "Connected to %s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", + connection_info, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60); else if (ctimesec > 86400) - ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, + ast_cli(a->fd, "Connected to %s%s for %d days, %d hours, %d minutes, %d seconds.\n", connection_info, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60); else if (ctimesec > 3600) - ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, credentials, + ast_cli(a->fd, "Connected to %s%s for %d hours, %d minutes, %d seconds.\n", connection_info, credentials, ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60); else if (ctimesec > 60) - ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, ctimesec / 60, + ast_cli(a->fd, "Connected to %s%s for %d minutes, %d seconds.\n", connection_info, credentials, ctimesec / 60, ctimesec % 60); else - ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec); + ast_cli(a->fd, "Connected to %s%s for %d seconds.\n", connection_info, credentials, ctimesec); return CLI_SUCCESS; } else { + ast_cli(a->fd, "Unable to connect %s%s\n", connection_info, credentials); return CLI_FAILURE; } } From bbf3ace68292c136ae0455332a1893de4c4b4c13 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 29 Jan 2016 16:56:42 -0700 Subject: [PATCH 0201/1578] res_pjsip: Fix infinite recursion when loading transports from realtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attempting to load a transport from realtime was forcing asterisk into an infinite recursion loop. The first thing transport_apply did was to do a sorcery retrieve by id for an existing transport of the same name. For files, this just returns the previous object from res_sorcery_config's internal container, if any. For realtime, the res_sourcery_realtime driver looks in the database and finds the existing row but now it has to rehydrate it into a sorcery object which means calling... transport_apply. And so it goes. The main issue with loading from realtime (apart from the loop) was that transport stores structures and pointers directly in the ast_sip_transport structure instead of the separate ast_transport_state structure. This patch separates those items into the ast_sip_transport_state structure. The pattern is roughly the same as res_pjsip_outbound_registration. Although all current usages of ast_sip_transport and ast_sip_transport_state were modified to use the new ast_sip_get_transport_state API, the original items are left in ast_sip_transport and kept updated to maintain ABI compatability for third-party modules. They are marked as deprecated and noted that they're now in ast_sip_transport_state. ASTERISK-25606 #close Reported-by: Martin Moučka Change-Id: Ic7a836ea8e786e8def51fe3f8cce855ea54f5f19 --- include/asterisk/res_pjsip.h | 138 +++- res/res_pjsip.c | 12 +- res/res_pjsip/config_transport.c | 703 ++++++++++++++---- res/res_pjsip_endpoint_identifier_anonymous.c | 20 +- res/res_pjsip_endpoint_identifier_user.c | 22 +- res/res_pjsip_multihomed.c | 20 +- res/res_pjsip_nat.c | 39 +- res/res_pjsip_outbound_registration.c | 12 +- res/res_pjsip_sdp_rtp.c | 5 +- res/res_pjsip_session.c | 5 +- res/res_pjsip_t38.c | 5 +- res/res_pjsip_transport_websocket.c | 19 +- 12 files changed, 761 insertions(+), 239 deletions(-) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 1ff361f5468..ad34c8f5af0 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -54,34 +54,59 @@ struct pjsip_tpfactory; struct pjsip_tls_setting; struct pjsip_tpselector; +/*! \brief Maximum number of ciphers supported for a TLS transport */ +#define SIP_TLS_MAX_CIPHERS 64 + /*! * \brief Structure for SIP transport information */ struct ast_sip_transport_state { /*! \brief Transport itself */ struct pjsip_transport *transport; - /*! \brief Transport factory */ struct pjsip_tpfactory *factory; + /*! + * Transport id + * \since 13.8.0 + */ + char *id; + /*! + * Transport type + * \since 13.8.0 + */ + enum ast_transport type; + /*! + * Address and port to bind to + * \since 13.8.0 + */ + pj_sockaddr host; + /*! + * TLS settings + * \since 13.8.0 + */ + pjsip_tls_setting tls; + /*! + * Configured TLS ciphers + * \since 13.8.0 + */ + pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS]; + /*! + * Optional local network information, used for NAT purposes + * \since 13.8.0 + */ + struct ast_ha *localnet; + /*! + * DNS manager for refreshing the external address + * \since 13.8.0 + */ + struct ast_dnsmgr_entry *external_address_refresher; + /*! + * Optional external address information + * \since 13.8.0 + */ + struct ast_sockaddr external_address; }; -#define SIP_SORCERY_DOMAIN_ALIAS_TYPE "domain_alias" - -/*! - * Details about a SIP domain alias - */ -struct ast_sip_domain_alias { - /*! Sorcery object details */ - SORCERY_OBJECT(details); - AST_DECLARE_STRING_FIELDS( - /*! Domain to be aliased to */ - AST_STRING_FIELD(domain); - ); -}; - -/*! \brief Maximum number of ciphers supported for a TLS transport */ -#define SIP_TLS_MAX_CIPHERS 64 - /* * \brief Transport to bind to */ @@ -108,23 +133,51 @@ struct ast_sip_transport { ); /*! Type of transport */ enum ast_transport type; - /*! Address and port to bind to */ + /*! + * \deprecated Moved to ast_sip_transport_state + * \version 13.8.0 deprecated + * Address and port to bind to + */ pj_sockaddr host; /*! Number of simultaneous asynchronous operations */ unsigned int async_operations; /*! Optional external port for signaling */ unsigned int external_signaling_port; - /*! TLS settings */ + /*! + * \deprecated Moved to ast_sip_transport_state + * \version 13.7.1 deprecated + * TLS settings + */ pjsip_tls_setting tls; - /*! Configured TLS ciphers */ + /*! + * \deprecated Moved to ast_sip_transport_state + * \version 13.7.1 deprecated + * Configured TLS ciphers + */ pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS]; - /*! Optional local network information, used for NAT purposes */ + /*! + * \deprecated Moved to ast_sip_transport_state + * \version 13.7.1 deprecated + * Optional local network information, used for NAT purposes + */ struct ast_ha *localnet; - /*! DNS manager for refreshing the external address */ + /*! + * \deprecated Moved to ast_sip_transport_state + * \version 13.7.1 deprecated + * DNS manager for refreshing the external address + */ struct ast_dnsmgr_entry *external_address_refresher; - /*! Optional external address information */ + /*! + * \deprecated Moved to ast_sip_transport_state + * \version 13.7.1 deprecated + * Optional external address information + */ struct ast_sockaddr external_address; - /*! Transport state information */ + /*! + * \deprecated + * \version 13.7.1 deprecated + * Transport state information + */ struct ast_sip_transport_state *state; /*! QOS DSCP TOS bits */ unsigned int tos; @@ -134,6 +187,20 @@ struct ast_sip_transport { int write_timeout; }; +#define SIP_SORCERY_DOMAIN_ALIAS_TYPE "domain_alias" + +/*! + * Details about a SIP domain alias + */ +struct ast_sip_domain_alias { + /*! Sorcery object details */ + SORCERY_OBJECT(details); + AST_DECLARE_STRING_FIELDS( + /*! Domain to be aliased to */ + AST_STRING_FIELD(domain); + ); +}; + /*! * \brief Structure for SIP nat hook information */ @@ -2135,4 +2202,25 @@ const char *ast_sip_get_host_ip_string(int af); */ long ast_sip_threadpool_queue_size(void); +/*! + * \brief Retrieve transport state + * \since 13.7.1 + * + * @param transport_id + * @returns transport_state + * + * \note ao2_cleanup(...) or ao2_ref(..., -1) must be called on the returned object + */ +struct ast_sip_transport_state *ast_sip_get_transport_state(const char *transport_id); + +/*! + * \brief Retrieves all transport states + * \since 13.7.1 + * + * @returns ao2_container + * + * \note ao2_cleanup(...) or ao2_ref(..., -1) must be called on the returned object + */ +struct ao2_container *ast_sip_get_transport_states(void); + #endif /* _RES_PJSIP_H */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 2b7625aba2f..0fc5346bd43 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2482,6 +2482,7 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpoint, pjsip_tpselector *selector) { RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); const char *transport_name = endpoint->transport; if (ast_strlen_zero(transport_name)) { @@ -2489,19 +2490,20 @@ static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpo } transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_name); + transport_state = ast_sip_get_transport_state(transport_name); - if (!transport || !transport->state) { + if (!transport || !transport_state) { ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' for endpoint '%s'\n", transport_name, ast_sorcery_object_get_id(endpoint)); return -1; } - if (transport->state->transport) { + if (transport_state->transport) { selector->type = PJSIP_TPSELECTOR_TRANSPORT; - selector->u.transport = transport->state->transport; - } else if (transport->state->factory) { + selector->u.transport = transport_state->transport; + } else if (transport_state->factory) { selector->type = PJSIP_TPSELECTOR_LISTENER; - selector->u.listener = transport->state->factory; + selector->u.listener = transport_state->factory; } else if (transport->type == AST_TRANSPORT_WS || transport->type == AST_TRANSPORT_WSS) { /* The WebSocket transport has no factory as it can not create outgoing connections, so * even if an endpoint is locked to a WebSocket transport we let the PJSIP logic diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 840824bd945..0fcd7d923cd 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -31,6 +31,82 @@ #include "include/res_pjsip_private.h" #include "asterisk/http_websocket.h" +#define MAX_POINTER_STRING 33 + +/*! \brief Default number of state container buckets */ +#define DEFAULT_STATE_BUCKETS 53 +static struct ao2_container *transport_states; + +struct internal_state { + char *id; + /*! Set if there was a change detected */ + int change_detected; + /*! \brief Transport configuration object */ + struct ast_sip_transport *transport; + /*! \brief Transport state information */ + struct ast_sip_transport_state *state; +}; + +static void temp_state_store_cleanup(void *data) +{ + struct ast_sip_transport_state **temp_state = data; + + ao2_cleanup(*temp_state); + ast_free(data); +} + +AST_THREADSTORAGE_CUSTOM(temp_state_store, NULL, temp_state_store_cleanup); + +/*! \brief hashing function for state objects */ +static int internal_state_hash(const void *obj, const int flags) +{ + const struct internal_state *object; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + object = obj; + key = object->id; + break; + default: + ast_assert(0); + return 0; + } + return ast_str_hash(key); +} + +/*! \brief comparator function for state objects */ +static int internal_state_cmp(void *obj, void *arg, int flags) +{ + const struct internal_state *object_left = obj; + const struct internal_state *object_right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->id; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(object_left->id, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + /* Not supported by container. */ + ast_assert(0); + return 0; + default: + cmp = 0; + break; + } + if (cmp) { + return 0; + } + return CMP_MATCH; +} + static int sip_transport_to_ami(const struct ast_sip_transport *transport, struct ast_str **buf) { @@ -75,69 +151,206 @@ struct ast_sip_endpoint_formatter endpoint_transport_formatter = { .format_ami = format_ami_endpoint_transport }; -static int destroy_transport_state(void *data) +static void set_qos(struct ast_sip_transport *transport, pj_qos_params *qos) +{ + int tos_as_dscp = transport->tos >> 2; + + if (transport->tos) { + qos->flags |= PJ_QOS_PARAM_HAS_DSCP; + qos->dscp_val = tos_as_dscp; + } + if (transport->cos) { + qos->flags |= PJ_QOS_PARAM_HAS_SO_PRIO; + qos->so_prio = transport->cos; + } +} + +/*! \brief Destructor for transport */ +static void sip_transport_destroy(void *obj) +{ + struct ast_sip_transport *transport = obj; + + ast_string_field_free_memory(transport); +} + +/*! \brief Allocator for transport */ +static void *sip_transport_alloc(const char *name) +{ + struct ast_sip_transport *transport = ast_sorcery_generic_alloc(sizeof(*transport), sip_transport_destroy); + + if (!transport) { + return NULL; + } + + if (ast_string_field_init(transport, 256)) { + ao2_cleanup(transport); + return NULL; + } + + return transport; +} + +static int destroy_sip_transport_state(void *data) { - pjsip_transport *transport = data; - pjsip_transport_shutdown(transport); + struct ast_sip_transport_state *transport_state = data; + + ast_free(transport_state->id); + ast_free_ha(transport_state->localnet); + + if (transport_state->external_address_refresher) { + ast_dnsmgr_release(transport_state->external_address_refresher); + } + if (transport_state->transport) { + pjsip_transport_shutdown(transport_state->transport); + } + return 0; } -/*! \brief Destructor for transport state information */ -static void transport_state_destroy(void *obj) +/*! \brief Destructor for ast_sip_transport state information */ +static void sip_transport_state_destroy(void *obj) { struct ast_sip_transport_state *state = obj; - if (state->transport) { - ast_sip_push_task_synchronous(NULL, destroy_transport_state, state->transport); + ast_sip_push_task_synchronous(NULL, destroy_sip_transport_state, state); +} + +/*! \brief Destructor for ast_sip_transport state information */ +static void internal_state_destroy(void *obj) +{ + struct internal_state *state = obj; + + ast_free(state->id); + ao2_cleanup(state->transport); + ao2_cleanup(state->state); +} + +static struct internal_state *find_internal_state_by_transport(const struct ast_sip_transport *transport) +{ + const char *key = ast_sorcery_object_get_id(transport); + + return ao2_find(transport_states, key, OBJ_SEARCH_KEY | OBJ_NOLOCK); +} + +static struct ast_sip_transport_state *find_state_by_transport(const struct ast_sip_transport *transport) +{ + struct internal_state *state; + + state = find_internal_state_by_transport(transport); + if (!state) { + return NULL; } + ao2_bump(state->state); + ao2_cleanup(state); + + return state->state; } -/*! \brief Destructor for transport */ -static void transport_destroy(void *obj) +static int remove_temporary_state(void) { - struct ast_sip_transport *transport = obj; + struct ast_sip_transport_state **state; - ast_string_field_free_memory(transport); - ast_free_ha(transport->localnet); + state = ast_threadstorage_get(&temp_state_store, sizeof(state)); + if (!state) { + return -1; + } + + ao2_cleanup(*state); + *state = NULL; + return 0; +} - if (transport->external_address_refresher) { - ast_dnsmgr_release(transport->external_address_refresher); +static struct ast_sip_transport_state *find_temporary_state(struct ast_sip_transport *transport) +{ + struct ast_sip_transport_state **state; + + state = ast_threadstorage_get(&temp_state_store, sizeof(state)); + if (state && *state) { + ao2_ref(*state, +1); + return *state; } - ao2_cleanup(transport->state); + return NULL; } -/*! \brief Allocator for transport */ -static void *transport_alloc(const char *name) +static struct internal_state *internal_state_alloc(struct ast_sip_transport *transport) { - struct ast_sip_transport *transport = ast_sorcery_generic_alloc(sizeof(*transport), transport_destroy); + struct internal_state *internal_state; - if (!transport) { + internal_state = ao2_alloc(sizeof(*internal_state), internal_state_destroy); + if (!internal_state) { return NULL; } - if (ast_string_field_init(transport, 256)) { - ao2_cleanup(transport); + internal_state->id = ast_strdup(ast_sorcery_object_get_id(transport)); + if (!internal_state->id) { + ao2_cleanup(internal_state); return NULL; } - pjsip_tls_setting_default(&transport->tls); - transport->tls.ciphers = transport->ciphers; + /* We're transferring the reference from find_temporary_state */ + internal_state->state = find_temporary_state(transport); + if (!internal_state->state) { + ao2_cleanup(internal_state); + return NULL; + } + internal_state->transport = ao2_bump(transport); + internal_state->transport->state = internal_state->state; + remove_temporary_state(); - return transport; + return internal_state; } -static void set_qos(struct ast_sip_transport *transport, pj_qos_params *qos) +/*! + * \internal + * \brief Should only be called by the individual field handlers + */ +static struct ast_sip_transport_state *find_or_create_temporary_state(struct ast_sip_transport *transport) { - int tos_as_dscp = transport->tos >> 2; + struct ast_sip_transport_state **state; + struct ast_sip_transport_state *new_state; - if (transport->tos) { - qos->flags |= PJ_QOS_PARAM_HAS_DSCP; - qos->dscp_val = tos_as_dscp; + if ((new_state = find_temporary_state(transport))) { + return new_state; } - if (transport->cos) { - qos->flags |= PJ_QOS_PARAM_HAS_SO_PRIO; - qos->so_prio = transport->cos; + + state = ast_threadstorage_get(&temp_state_store, sizeof(state)); + if (!state || *state) { + return NULL; + } + + new_state = ao2_alloc(sizeof(**state), sip_transport_state_destroy); + if (!new_state) { + return NULL; + } + new_state->id = ast_strdup(ast_sorcery_object_get_id(transport)); + new_state->type = transport->type; + + pjsip_tls_setting_default(&new_state->tls); + new_state->tls.ciphers = new_state->ciphers; + + ao2_ref(new_state, +1); + *state = new_state; + + return new_state; +} + +static void copy_state_to_transport(struct ast_sip_transport *transport) +{ + ast_assert(transport && transport->state); + + memcpy(&transport->host, &transport->state->host, sizeof(transport->host)); + memcpy(&transport->tls, &transport->state->tls, sizeof(transport->tls)); + memcpy(&transport->ciphers, &transport->state->ciphers, sizeof(transport->ciphers)); + transport->localnet = transport->state->localnet; + transport->external_address_refresher = transport->state->external_address_refresher; + memcpy(&transport->external_address, &transport->state->external_address, sizeof(transport->external_address)); +} + +static void states_cleanup(void *states) +{ + if (states) { + ao2_unlock(states); } } @@ -145,64 +358,87 @@ static void set_qos(struct ast_sip_transport *transport, pj_qos_params *qos) static int transport_apply(const struct ast_sorcery *sorcery, void *obj) { struct ast_sip_transport *transport = obj; - RAII_VAR(struct ast_sip_transport *, existing, ast_sorcery_retrieve_by_id(sorcery, "transport", ast_sorcery_object_get_id(obj)), ao2_cleanup); + const char *transport_id = ast_sorcery_object_get_id(obj); + RAII_VAR(struct ao2_container *, states, transport_states, states_cleanup); + RAII_VAR(struct internal_state *, temp_state, NULL, ao2_cleanup); + RAII_VAR(struct internal_state *, perm_state, NULL, ao2_cleanup); + RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy); pj_status_t res = -1; - if (!existing || !existing->state) { - if (!(transport->state = ao2_alloc(sizeof(*transport->state), transport_state_destroy))) { - ast_log(LOG_ERROR, "Transport state for '%s' could not be allocated\n", ast_sorcery_object_get_id(obj)); - return -1; + if (!states) { + return -1; + } + + /* + * transport_apply gets called for EVERY retrieval of a transport when using realtime. + * We need to prevent multiple threads from trying to mess with underlying transports + * at the same time. The container is the only thing we have to lock on. + */ + ao2_wrlock(states); + + perm_state = find_internal_state_by_transport(transport); + if (perm_state) { + ast_sorcery_diff(sorcery, perm_state->transport, transport, &changes); + if (changes) { + if (!perm_state->change_detected) { + perm_state->change_detected = 1; + ast_log(LOG_WARNING, "Transport '%s' is not reloadable, maintaining previous values\n", transport_id); + } } - } else { - transport->state = existing->state; - ao2_ref(transport->state, +1); + + /* In case someone is using the deprecated fields, reset them */ + transport->state = perm_state->state; + copy_state_to_transport(transport); + ao2_replace(perm_state->transport, transport); + return 0; } - /* Once active a transport can not be reconfigured */ - if (transport->state->transport || transport->state->factory) { - return -1; + temp_state = internal_state_alloc(transport); + if (!temp_state) { + ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id); + goto error; } - if (transport->host.addr.sa_family != PJ_AF_INET && transport->host.addr.sa_family != PJ_AF_INET6) { - ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", ast_sorcery_object_get_id(obj)); - return -1; + if (temp_state->state->host.addr.sa_family != PJ_AF_INET && temp_state->state->host.addr.sa_family != PJ_AF_INET6) { + ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", transport_id); + goto error; } /* Set default port if not present */ - if (!pj_sockaddr_get_port(&transport->host)) { - pj_sockaddr_set_port(&transport->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060); + if (!pj_sockaddr_get_port(&temp_state->state->host)) { + pj_sockaddr_set_port(&temp_state->state->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060); } /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */ if (!ast_strlen_zero(transport->external_signaling_address)) { - if (transport->host.addr.sa_family == pj_AF_INET()) { - transport->external_address.ss.ss_family = AF_INET; - } else if (transport->host.addr.sa_family == pj_AF_INET6()) { - transport->external_address.ss.ss_family = AF_INET6; + if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { + temp_state->state->external_address.ss.ss_family = AF_INET; + } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { + temp_state->state->external_address.ss.ss_family = AF_INET6; } else { ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n", - ast_sorcery_object_get_id(obj)); - return -1; + transport_id); + goto error; } - if (ast_dnsmgr_lookup(transport->external_signaling_address, &transport->external_address, &transport->external_address_refresher, NULL) < 0) { - ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", ast_sorcery_object_get_id(obj)); - return -1; + if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_address, &temp_state->state->external_address_refresher, NULL) < 0) { + ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id); + goto error; } } if (transport->type == AST_TRANSPORT_UDP) { - if (transport->host.addr.sa_family == pj_AF_INET()) { - res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &transport->host.ipv4, NULL, transport->async_operations, &transport->state->transport); - } else if (transport->host.addr.sa_family == pj_AF_INET6()) { - res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &transport->host.ipv6, NULL, transport->async_operations, &transport->state->transport); + if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { + res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv4, NULL, transport->async_operations, &temp_state->state->transport); + } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { + res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv6, NULL, transport->async_operations, &temp_state->state->transport); } if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { pj_sock_t sock; pj_qos_params qos_params; - sock = pjsip_udp_transport_get_socket(transport->state->transport); + sock = pjsip_udp_transport_get_socket(temp_state->state->transport); pj_sock_get_qos_params(sock, &qos_params); set_qos(transport, &qos_params); pj_sock_set_qos_params(sock, &qos_params); @@ -210,61 +446,23 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; - pjsip_tcp_transport_cfg_default(&cfg, transport->host.addr.sa_family); - cfg.bind_addr = transport->host; + pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family); + cfg.bind_addr = temp_state->state->host; cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); - res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory); + res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &temp_state->state->factory); } else if (transport->type == AST_TRANSPORT_TLS) { if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) { ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n", ast_sorcery_object_get_id(obj)); - return -1; - } - if (!ast_strlen_zero(transport->ca_list_file)) { - if (!ast_file_is_readable(transport->ca_list_file)) { - ast_log(LOG_ERROR, "Transport: %s: ca_list_file %s is either missing or not readable\n", - ast_sorcery_object_get_id(obj), transport->ca_list_file); - return -1; - } - } - transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file); -#ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 - if (!ast_strlen_zero(transport->ca_list_path)) { - if (!ast_file_is_readable(transport->ca_list_path)) { - ast_log(LOG_ERROR, "Transport: %s: ca_list_path %s is either missing or not readable\n", - ast_sorcery_object_get_id(obj), transport->ca_list_path); - return -1; - } - } - transport->tls.ca_list_path = pj_str((char*)transport->ca_list_path); -#else - if (!ast_strlen_zero(transport->ca_list_path)) { - ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject that does not " - "support the 'ca_list_path' option. Please upgrade to version 2.4 or later.\n"); + goto error; } -#endif - if (!ast_strlen_zero(transport->cert_file)) { - if (!ast_file_is_readable(transport->cert_file)) { - ast_log(LOG_ERROR, "Transport: %s: cert_file %s is either missing or not readable\n", - ast_sorcery_object_get_id(obj), transport->cert_file); - return -1; - } - } - transport->tls.cert_file = pj_str((char*)transport->cert_file); - if (!ast_strlen_zero(transport->privkey_file)) { - if (!ast_file_is_readable(transport->privkey_file)) { - ast_log(LOG_ERROR, "Transport: %s: privkey_file %s is either missing or not readable\n", - ast_sorcery_object_get_id(obj), transport->privkey_file); - return -1; - } - } - transport->tls.privkey_file = pj_str((char*)transport->privkey_file); - transport->tls.password = pj_str((char*)transport->password); - set_qos(transport, &transport->tls.qos_params); - res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &transport->tls, &transport->host, NULL, transport->async_operations, &transport->state->factory); + temp_state->state->tls.password = pj_str((char*)transport->password); + set_qos(transport, &temp_state->state->tls.qos_params); + + res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls, &temp_state->state->host, NULL, transport->async_operations, &temp_state->state->factory); } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) { if (transport->cos || transport->tos) { ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n"); @@ -277,8 +475,101 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) pj_strerror(res, msg, sizeof(msg)); ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg); + goto error; + } + + copy_state_to_transport(transport); + ao2_link(states, temp_state); + + return 0; + +error: + ao2_unlink(states, temp_state); + return -1; +} + +/*! \brief Custom handler for type just makes sure the state is created */ +static int transport_state_init(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_transport *transport = obj; + struct ast_sip_transport_state *state = find_or_create_temporary_state(transport); + + ao2_cleanup(state); + + return 0; +} + +/*! \brief Custom handler for TLS method setting */ +static int transport_tls_file_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_transport *transport = obj; + RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); + + if (!state) { + return -1; + } + + if (!ast_file_is_readable(var->value)) { + ast_log(LOG_ERROR, "Transport: %s: %s %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), var->name, var->value); return -1; } + + if (!strcasecmp(var->name, "ca_list_file")) { + state->tls.ca_list_file = pj_str((char*)var->value); + ast_string_field_set(transport, ca_list_file, var->value); + } else if (!strcasecmp(var->name, "ca_list_path")) { +#ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 + state->tls.ca_list_path = pj_str((char*)var->value); + ast_string_field_set(transport, ca_list_path, var->value); +#else + ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject that does not " + "support the 'ca_list_path' option. Please upgrade to version 2.4 or later.\n"); +#endif + } else if (!strcasecmp(var->name, "cert_file")) { + state->tls.cert_file = pj_str((char*)var->value); + ast_string_field_set(transport, cert_file, var->value); + } else if (!strcasecmp(var->name, "priv_key_file")) { + state->tls.privkey_file = pj_str((char*)var->value); + ast_string_field_set(transport, privkey_file, var->value); + } + + return 0; +} + +static int ca_list_file_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + + *buf = ast_strdup(transport->ca_list_file); + + return 0; +} + +static int ca_list_path_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + + *buf = ast_strdup(transport->ca_list_path); + + return 0; +} + +static int cert_file_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + + *buf = ast_strdup(transport->cert_file); + + return 0; +} + +static int privkey_file_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + + *buf = ast_strdup(transport->privkey_file); + return 0; } @@ -328,7 +619,14 @@ static int transport_bind_handler(const struct aco_option *opt, struct ast_varia { struct ast_sip_transport *transport = obj; pj_str_t buf; - int rc = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, var->value), &transport->host); + int rc; + RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); + + if (!state) { + return -1; + } + + rc = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, var->value), &state->host); return rc != PJ_SUCCESS ? -1 : 0; } @@ -336,13 +634,18 @@ static int transport_bind_handler(const struct aco_option *opt, struct ast_varia static int transport_bind_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_transport *transport = obj; + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); + + if (!state) { + return -1; + } if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) { return -1; } /* include port as well as brackets if IPv6 */ - pj_sockaddr_print(&transport->host, *buf, MAX_OBJECT_FIELD, 1 | 2); + pj_sockaddr_print(&state->host, *buf, MAX_OBJECT_FIELD, 1 | 2); return 0; } @@ -351,13 +654,18 @@ static int transport_bind_to_str(const void *obj, const intptr_t *args, char **b static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_transport *transport = obj; + RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); + + if (!state) { + return -1; + } if (!strcasecmp(var->name, "verify_server")) { - transport->tls.verify_server = ast_true(var->value) ? PJ_TRUE : PJ_FALSE; + state->tls.verify_server = ast_true(var->value) ? PJ_TRUE : PJ_FALSE; } else if (!strcasecmp(var->name, "verify_client")) { - transport->tls.verify_client = ast_true(var->value) ? PJ_TRUE : PJ_FALSE; + state->tls.verify_client = ast_true(var->value) ? PJ_TRUE : PJ_FALSE; } else if (!strcasecmp(var->name, "require_client_cert")) { - transport->tls.require_client_cert = ast_true(var->value) ? PJ_TRUE : PJ_FALSE; + state->tls.require_client_cert = ast_true(var->value) ? PJ_TRUE : PJ_FALSE; } else { return -1; } @@ -368,21 +676,42 @@ static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_v static int verify_server_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_transport *transport = obj; - *buf = ast_strdup(AST_YESNO(transport->tls.verify_server)); + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); + + if (!state) { + return -1; + } + + *buf = ast_strdup(AST_YESNO(state->tls.verify_server)); + return 0; } static int verify_client_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_transport *transport = obj; - *buf = ast_strdup(AST_YESNO(transport->tls.verify_client)); + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); + + if (!state) { + return -1; + } + + *buf = ast_strdup(AST_YESNO(state->tls.verify_client)); + return 0; } static int require_client_cert_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_transport *transport = obj; - *buf = ast_strdup(AST_YESNO(transport->tls.require_client_cert)); + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); + + if (!state) { + return -1; + } + + *buf = ast_strdup(AST_YESNO(state->tls.require_client_cert)); + return 0; } @@ -390,19 +719,24 @@ static int require_client_cert_to_str(const void *obj, const intptr_t *args, cha static int transport_tls_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_transport *transport = obj; + RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); + + if (!state) { + return -1; + } if (ast_strlen_zero(var->value) || !strcasecmp(var->value, "default")) { - transport->tls.method = PJSIP_SSL_DEFAULT_METHOD; + state->tls.method = PJSIP_SSL_DEFAULT_METHOD; } else if (!strcasecmp(var->value, "unspecified")) { - transport->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD; + state->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD; } else if (!strcasecmp(var->value, "tlsv1")) { - transport->tls.method = PJSIP_TLSV1_METHOD; + state->tls.method = PJSIP_TLSV1_METHOD; } else if (!strcasecmp(var->value, "sslv2")) { - transport->tls.method = PJSIP_SSLV2_METHOD; + state->tls.method = PJSIP_SSLV2_METHOD; } else if (!strcasecmp(var->value, "sslv3")) { - transport->tls.method = PJSIP_SSLV3_METHOD; + state->tls.method = PJSIP_SSLV3_METHOD; } else if (!strcasecmp(var->value, "sslv23")) { - transport->tls.method = PJSIP_SSLV23_METHOD; + state->tls.method = PJSIP_SSLV23_METHOD; } else { return -1; } @@ -421,9 +755,16 @@ static const char *tls_method_map[] = { static int tls_method_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_transport *transport = obj; - if (ARRAY_IN_BOUNDS(transport->tls.method, tls_method_map)) { - *buf = ast_strdup(tls_method_map[transport->tls.method]); + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); + + if (!state) { + return -1; } + + if (ARRAY_IN_BOUNDS(state->tls.method, tls_method_map)) { + *buf = ast_strdup(tls_method_map[state->tls.method]); + } + return 0; } @@ -463,7 +804,7 @@ static pj_ssl_cipher cipher_name_to_id(const char *name) * \retval 0 on success. * \retval -1 on error. */ -static int transport_cipher_add(struct ast_sip_transport *transport, const char *name) +static int transport_cipher_add(struct ast_sip_transport_state *state, const char *name) { pj_ssl_cipher cipher; int idx; @@ -480,13 +821,13 @@ static int transport_cipher_add(struct ast_sip_transport *transport, const char } if (pj_ssl_cipher_is_supported(cipher)) { - for (idx = transport->tls.ciphers_num; idx--;) { - if (transport->ciphers[idx] == cipher) { + for (idx = state->tls.ciphers_num; idx--;) { + if (state->ciphers[idx] == cipher) { /* The cipher is already in the list. */ return 0; } } - transport->ciphers[transport->tls.ciphers_num++] = cipher; + state->ciphers[state->tls.ciphers_num++] = cipher; return 0; } else { ast_log(LOG_ERROR, "Cipher '%s' is unsupported\n", name); @@ -501,6 +842,11 @@ static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast char *parse; char *name; int res = 0; + RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); + + if (!state) { + return -1; + } parse = ast_strdupa(S_OR(var->value, "")); while ((name = strsep(&parse, ","))) { @@ -508,12 +854,12 @@ static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast if (ast_strlen_zero(name)) { continue; } - if (ARRAY_LEN(transport->ciphers) <= transport->tls.ciphers_num) { + if (ARRAY_LEN(state->ciphers) <= state->tls.ciphers_num) { ast_log(LOG_ERROR, "Too many ciphers specified\n"); res = -1; break; } - res |= transport_cipher_add(transport, name); + res |= transport_cipher_add(state, name); } return res ? -1 : 0; } @@ -543,8 +889,13 @@ static void cipher_to_str(char **buf, const pj_ssl_cipher *ciphers, unsigned int static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_transport *transport = obj; + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); + + if (!state) { + return -1; + } - cipher_to_str(buf, transport->ciphers, transport->tls.ciphers_num); + cipher_to_str(buf, state->ciphers, state->tls.ciphers_num); return *buf ? 0 : -1; } @@ -584,14 +935,19 @@ static int transport_localnet_handler(const struct aco_option *opt, struct ast_v { struct ast_sip_transport *transport = obj; int error = 0; + RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); + + if (!state) { + return -1; + } if (ast_strlen_zero(var->value)) { - ast_free_ha(transport->localnet); - transport->localnet = NULL; + ast_free_ha(state->localnet); + state->localnet = NULL; return 0; } - if (!(transport->localnet = ast_append_ha("d", var->value, transport->localnet, &error))) { + if (!(state->localnet = ast_append_ha("d", var->value, state->localnet, &error))) { return -1; } @@ -601,12 +957,16 @@ static int transport_localnet_handler(const struct aco_option *opt, struct ast_v static int localnet_to_vl(const void *obj, struct ast_variable **fields) { const struct ast_sip_transport *transport = obj; - char str[MAX_OBJECT_FIELD]; struct ast_variable *head = NULL; - struct ast_ha *ha = transport->localnet; + struct ast_ha *ha; + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); - for (; ha; ha = ha->next) { + if (!state) { + return -1; + } + + for (ha = state->localnet; ha; ha = ha->next) { const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr)); snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "", addr, ast_sockaddr_stringify_addr(&ha->netmask)); @@ -625,8 +985,13 @@ static int localnet_to_str(const void *obj, const intptr_t *args, char **buf) { RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free); const struct ast_sip_transport *transport = obj; + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); - ast_ha_join(transport->localnet, &str); + if (!state) { + return -1; + } + + ast_ha_join(state->localnet, &str); *buf = ast_strdup(ast_str_buffer(str)); return 0; } @@ -730,10 +1095,15 @@ static int cli_print_body(void *obj, void *arg, int flags) struct ast_sip_transport *transport = obj; struct ast_sip_cli_context *context = arg; char hoststr[PJ_INET6_ADDRSTRLEN]; + RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup); + + if (!state) { + return -1; + } ast_assert(context->output_buffer != NULL); - pj_sockaddr_print(&transport->host, hoststr, sizeof(hoststr), 3); + pj_sockaddr_print(&state->host, hoststr, sizeof(hoststr), 3); ast_str_append(&context->output_buffer, 0, "%*s: %-21s %6s %5u %5u %s\n", CLI_INDENT_TO_SPACES(context->indent_level), "Transport", @@ -770,25 +1140,61 @@ static struct ast_cli_entry cli_commands[] = { static struct ast_sip_cli_formatter_entry *cli_formatter; +struct ast_sip_transport_state *ast_sip_get_transport_state(const char *transport_id) +{ + struct internal_state * state = NULL; + + if (!transport_states) { + return NULL; + } + + state = ao2_find(transport_states, transport_id, OBJ_SEARCH_KEY); + if (!state || !state->state) { + ao2_cleanup(state); + return NULL; + } + + ao2_ref(state->state, +1); + ao2_ref(state, -1); + + return state->state; +} + +struct ao2_container *ast_sip_get_transport_states(void) +{ + return ao2_container_clone(transport_states, 0); +} + /*! \brief Initialize sorcery with transport support */ int ast_sip_initialize_sorcery_transport(void) { struct ast_sorcery *sorcery = ast_sip_get_sorcery(); + struct ao2_container *transports = NULL; + + /* Create outbound registration states container. */ + transport_states = ao2_container_alloc(DEFAULT_STATE_BUCKETS, internal_state_hash, internal_state_cmp); + if (!transport_states) { + ast_log(LOG_ERROR, "Unable to allocate transport states container\n"); + return AST_MODULE_LOAD_FAILURE; + } ast_sorcery_apply_default(sorcery, "transport", "config", "pjsip.conf,criteria=type=transport"); - if (ast_sorcery_object_register_no_reload(sorcery, "transport", transport_alloc, NULL, transport_apply)) { + if (ast_sorcery_object_register(sorcery, "transport", sip_transport_alloc, NULL, transport_apply)) { return -1; } - ast_sorcery_object_field_register(sorcery, "transport", "type", "", OPT_NOOP_T, 0, 0); + /* Normally type is a OPT_NOOP_T but we're using it to make sure that state is created */ + ast_sorcery_object_field_register_custom(sorcery, "transport", "type", "", transport_state_init, NULL, NULL, 0, 0); ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, transport_protocol_to_str, NULL, 0, 0); ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, transport_bind_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations)); - ast_sorcery_object_field_register(sorcery, "transport", "ca_list_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_file)); - ast_sorcery_object_field_register(sorcery, "transport", "ca_list_path", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_path)); - ast_sorcery_object_field_register(sorcery, "transport", "cert_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, cert_file)); - ast_sorcery_object_field_register(sorcery, "transport", "priv_key_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, privkey_file)); + + ast_sorcery_object_field_register_custom(sorcery, "transport", "ca_list_file", "", transport_tls_file_handler, ca_list_file_to_str, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "ca_list_path", "", transport_tls_file_handler, ca_list_path_to_str, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "cert_file", "", transport_tls_file_handler, cert_file_to_str, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "priv_key_file", "", transport_tls_file_handler, privkey_file_to_str, NULL, 0, 0); + ast_sorcery_object_field_register(sorcery, "transport", "password", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, password)); ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_signaling_address)); ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535); @@ -822,6 +1228,10 @@ int ast_sip_initialize_sorcery_transport(void) ast_sip_register_cli_formatter(cli_formatter); ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + /* trigger load of transports from realtime by trying to revrieve them all */ + transports = ast_sorcery_retrieve_by_fields(sorcery, "transport", AST_RETRIEVE_FLAG_ALL | AST_RETRIEVE_FLAG_MULTIPLE, NULL); + ao2_cleanup(transports); + return 0; } @@ -832,5 +1242,8 @@ int ast_sip_destroy_sorcery_transport(void) internal_sip_unregister_endpoint_formatter(&endpoint_transport_formatter); + ao2_ref(transport_states, -1); + transport_states = NULL; + return 0; } diff --git a/res/res_pjsip_endpoint_identifier_anonymous.c b/res/res_pjsip_endpoint_identifier_anonymous.c index 06933a9ad03..d9d7e03daab 100644 --- a/res/res_pjsip_endpoint_identifier_anonymous.c +++ b/res/res_pjsip_endpoint_identifier_anonymous.c @@ -42,14 +42,14 @@ static int get_endpoint_details(pjsip_rx_data *rdata, char *domain, size_t domai return 0; } -static int find_transport_in_use(void *obj, void *arg, int flags) +static int find_transport_state_in_use(void *obj, void *arg, int flags) { - struct ast_sip_transport *transport = obj; + struct ast_sip_transport_state *transport_state = obj; pjsip_rx_data *rdata = arg; - if ((transport->state->transport == rdata->tp_info.transport) || - (transport->state->factory && !pj_strcmp(&transport->state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) && - transport->state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) { + if (transport_state && ((transport_state->transport == rdata->tp_info.transport) || + (transport_state->factory && !pj_strcmp(&transport_state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) && + transport_state->factory->addr_name.port == rdata->tp_info.transport->local_name.port))) { return CMP_MATCH | CMP_STOP; } @@ -61,7 +61,8 @@ static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) char domain_name[64], id[AST_UUID_STR_LEN]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); - RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup); + RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) { @@ -83,9 +84,10 @@ static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) } /* See if the transport this came in on has a provided domain */ - if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) && - (transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) && - !ast_strlen_zero(transport->domain)) { + if ((transport_states = ast_sip_get_transport_states()) + && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata)) + && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id)) + && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "anonymous@%s", transport->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c index aede2f7d362..9a2bc89e45d 100644 --- a/res/res_pjsip_endpoint_identifier_user.c +++ b/res/res_pjsip_endpoint_identifier_user.c @@ -42,14 +42,14 @@ static int get_endpoint_details(pjsip_rx_data *rdata, char *endpoint, size_t end return 0; } -static int find_transport_in_use(void *obj, void *arg, int flags) +static int find_transport_state_in_use(void *obj, void *arg, int flags) { - struct ast_sip_transport *transport = obj; + struct ast_sip_transport_state *transport_state = obj; pjsip_rx_data *rdata = arg; - if ((transport->state->transport == rdata->tp_info.transport) || - (transport->state->factory && !pj_strcmp(&transport->state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) && - transport->state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) { + if (transport_state && ((transport_state->transport == rdata->tp_info.transport) || + (transport_state->factory && !pj_strcmp(&transport_state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) && + transport_state->factory->addr_name.port == rdata->tp_info.transport->local_name.port))) { return CMP_MATCH | CMP_STOP; } @@ -61,7 +61,8 @@ static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) char endpoint_name[64], domain_name[64], id[AST_UUID_STR_LEN]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); - RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup); + RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (get_endpoint_details(rdata, endpoint_name, sizeof(endpoint_name), domain_name, sizeof(domain_name))) { @@ -83,10 +84,11 @@ static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) } /* See if the transport this came in on has a provided domain */ - if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) && - (transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) && - !ast_strlen_zero(transport->domain)) { - snprintf(id, sizeof(id), "%s@%s", endpoint_name, transport->domain); + if ((transport_states = ast_sip_get_transport_states()) + && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata)) + && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id)) + && !ast_strlen_zero(transport->domain)) { + snprintf(id, sizeof(id), "anonymous@%s", transport->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; } diff --git a/res/res_pjsip_multihomed.c b/res/res_pjsip_multihomed.c index 7062fc60b76..f5deb77240c 100644 --- a/res/res_pjsip_multihomed.c +++ b/res/res_pjsip_multihomed.c @@ -33,30 +33,28 @@ /*! \brief Helper function which returns a UDP transport bound to the given address and port */ static pjsip_transport *multihomed_get_udp_transport(pj_str_t *address, int port) { - struct ao2_container *transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", - AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); - struct ast_sip_transport *transport; + struct ao2_container *transport_states = ast_sip_get_transport_states(); + struct ast_sip_transport_state *transport_state; struct ao2_iterator iter; pjsip_transport *sip_transport = NULL; - if (!transports) { + if (!transport_states) { return NULL; } - for (iter = ao2_iterator_init(transports, 0); (transport = ao2_iterator_next(&iter)); ao2_ref(transport, -1)) { - if ((transport->type != AST_TRANSPORT_UDP) || - (pj_strcmp(&transport->state->transport->local_name.host, address)) || - (transport->state->transport->local_name.port != port)) { + for (iter = ao2_iterator_init(transport_states, 0); (transport_state = ao2_iterator_next(&iter)); ao2_ref(transport_state, -1)) { + if (transport_state && ((transport_state->type != AST_TRANSPORT_UDP) || + (pj_strcmp(&transport_state->transport->local_name.host, address)) || + (transport_state->transport->local_name.port != port))) { continue; } - sip_transport = transport->state->transport; - ao2_ref(transport, -1); + sip_transport = transport_state->transport; break; } ao2_iterator_destroy(&iter); - ao2_ref(transports, -1); + ao2_ref(transport_states, -1); return sip_transport; } diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c index 683ae611013..a32d12bfdba 100644 --- a/res/res_pjsip_nat.c +++ b/res/res_pjsip_nat.c @@ -150,19 +150,19 @@ struct request_transport_details { }; /*! \brief Callback function for finding the transport the request is going out on */ -static int find_transport_in_use(void *obj, void *arg, int flags) +static int find_transport_state_in_use(void *obj, void *arg, int flags) { - struct ast_sip_transport *transport = obj; + struct ast_sip_transport_state *transport_state = obj; struct request_transport_details *details = arg; /* If an explicit transport or factory matches then this is what is in use, if we are unavailable * to compare based on that we make sure that the type is the same and the source IP address/port are the same */ - if ((details->transport && details->transport == transport->state->transport) || - (details->factory && details->factory == transport->state->factory) || - ((details->type == transport->type) && (transport->state->factory) && - !pj_strcmp(&transport->state->factory->addr_name.host, &details->local_address) && - transport->state->factory->addr_name.port == details->local_port)) { + if (transport_state && ((details->transport && details->transport == transport_state->transport) || + (details->factory && details->factory == transport_state->factory) || + ((details->type == transport_state->type) && (transport_state->factory) && + !pj_strcmp(&transport_state->factory->addr_name.host, &details->local_address) && + transport_state->factory->addr_name.port == details->local_port))) { return CMP_MATCH | CMP_STOP; } @@ -204,8 +204,9 @@ static int nat_invoke_hook(void *obj, void *arg, int flags) static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) { - RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup); + RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); struct request_transport_details details = { 0, }; pjsip_via_hdr *via = NULL; struct ast_sockaddr addr = { { 0, } }; @@ -247,9 +248,19 @@ static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) } } - if (!(transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) || - !(transport = ao2_callback(transports, 0, find_transport_in_use, &details)) || !transport->localnet || - ast_sockaddr_isnull(&transport->external_address)) { + if (!(transport_states = ast_sip_get_transport_states())) { + return PJ_SUCCESS; + } + + if (!(transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, &details))) { + return PJ_SUCCESS; + } + + if (!(transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))) { + return PJ_SUCCESS; + } + + if ( !transport_state->localnet || ast_sockaddr_isnull(&transport_state->external_address)) { return PJ_SUCCESS; } @@ -257,13 +268,13 @@ static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port); /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */ - if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) { + if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) { return PJ_SUCCESS; } /* Update the contact header with the external address */ if (uri || (uri = nat_get_contact_sip_uri(tdata))) { - pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport->external_address)); + pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_address)); if (transport->external_signaling_port) { uri->port = transport->external_signaling_port; ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port); @@ -272,7 +283,7 @@ static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) /* Update the via header if relevant */ if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) { - pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport->external_address)); + pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_address)); if (transport->external_signaling_port) { via->sent_by.port = transport->external_signaling_port; } diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 267ca5d7754..0ff609a63d6 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1172,20 +1172,20 @@ static int sip_outbound_registration_regc_alloc(void *data) pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); if (!ast_strlen_zero(registration->transport)) { - RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup); + RAII_VAR(struct ast_sip_transport_state *, transport_state, ast_sip_get_transport_state(registration->transport), ao2_cleanup); - if (!transport || !transport->state) { + if (!transport_state) { ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' " " for outbound registration", registration->transport); return -1; } - if (transport->state->transport) { + if (transport_state->transport) { selector.type = PJSIP_TPSELECTOR_TRANSPORT; - selector.u.transport = transport->state->transport; - } else if (transport->state->factory) { + selector.u.transport = transport_state->transport; + } else if (transport_state->factory) { selector.type = PJSIP_TPSELECTOR_LISTENER; - selector.u.listener = transport->state->factory; + selector.u.listener = transport_state->factory; } else { return -1; } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 2a1f56ed495..08e80a38c2f 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1360,11 +1360,12 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a /*! \brief Function which updates the media stream with external media address, if applicable */ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport) { + RAII_VAR(struct ast_sip_transport_state *, transport_state, ast_sip_get_transport_state(ast_sorcery_object_get_id(transport)), ao2_cleanup); char host[NI_MAXHOST]; struct ast_sockaddr addr = { { 0, } }; /* If the stream has been rejected there will be no connection line */ - if (!stream->conn) { + if (!stream->conn || !transport_state) { return; } @@ -1372,7 +1373,7 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID); /* Is the address within the SDP inside the same network? */ - if (ast_apply_ha(transport->localnet, &addr) == AST_SENSE_ALLOW) { + if (ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { return; } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 7f1346787bc..e7dd5b91d0b 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2805,13 +2805,14 @@ static pjsip_inv_callback inv_callback = { /*! \brief Hook for modifying outgoing messages with SDP to contain the proper address information */ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_transport *transport) { + RAII_VAR(struct ast_sip_transport_state *, transport_state, ast_sip_get_transport_state(ast_sorcery_object_get_id(transport)), ao2_cleanup); struct ast_sip_nat_hook *hook = ast_sip_mod_data_get( tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK); struct pjmedia_sdp_session *sdp; int stream; /* SDP produced by us directly will never be multipart */ - if (hook || !tdata->msg->body || pj_stricmp2(&tdata->msg->body->content_type.type, "application") || + if (!transport_state || hook || !tdata->msg->body || pj_stricmp2(&tdata->msg->body->content_type.type, "application") || pj_stricmp2(&tdata->msg->body->content_type.subtype, "sdp") || ast_strlen_zero(transport->external_media_address)) { return; } @@ -2825,7 +2826,7 @@ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_trans ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host)); ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID); - if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) { + if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) { pj_strdup2(tdata->pool, &sdp->conn->addr, transport->external_media_address); } } diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 85feedc068d..2bb6f03da6f 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -890,11 +890,12 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a /*! \brief Function which updates the media stream with external media address, if applicable */ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport) { + RAII_VAR(struct ast_sip_transport_state *, transport_state, ast_sip_get_transport_state(ast_sorcery_object_get_id(transport)), ao2_cleanup); char host[NI_MAXHOST]; struct ast_sockaddr addr = { { 0, } }; /* If the stream has been rejected there will be no connection line */ - if (!stream->conn) { + if (!stream->conn || !transport_state) { return; } @@ -902,7 +903,7 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID); /* Is the address within the SDP inside the same network? */ - if (ast_apply_ha(transport->localnet, &addr) == AST_SENSE_ALLOW) { + if (ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { return; } diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index cdf6c6733f3..b9d94ea3c65 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -275,24 +275,27 @@ static int transport_read(void *data) static int get_write_timeout(void) { int write_timeout = -1; - struct ao2_container *transports; + struct ao2_container *transport_states; - transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_ALL, NULL); + transport_states = ast_sip_get_transport_states(); - if (transports) { - struct ao2_iterator it_transports = ao2_iterator_init(transports, 0); - struct ast_sip_transport *transport; + if (transport_states) { + struct ao2_iterator it_transport_states = ao2_iterator_init(transport_states, 0); + struct ast_sip_transport_state *transport_state; - for (; (transport = ao2_iterator_next(&it_transports)); ao2_cleanup(transport)) { - if (transport->type != AST_TRANSPORT_WS && transport->type != AST_TRANSPORT_WSS) { + for (; (transport_state = ao2_iterator_next(&it_transport_states)); ao2_cleanup(transport_state)) { + struct ast_sip_transport *transport; + if (transport_state->type != AST_TRANSPORT_WS && transport_state->type != AST_TRANSPORT_WSS) { continue; } + transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id); ast_debug(5, "Found %s transport with write timeout: %d\n", transport->type == AST_TRANSPORT_WS ? "WS" : "WSS", transport->write_timeout); write_timeout = MAX(write_timeout, transport->write_timeout); } - ao2_cleanup(transports); + ao2_iterator_destroy(&it_transport_states); + ao2_cleanup(transport_states); } if (write_timeout < 0) { From e40fddbeb5dbc4f557a6c215eb211091f2fe3161 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 9 Feb 2016 09:11:36 -0400 Subject: [PATCH 0202/1578] tests/test_sorcery_memory_cache_thrash: Improve termination process. When terminating the threads thrashing a sorcery memory cache each would be told to stop and then we would wait on them. During at least one thrashing test this was problematic due to the specific usage pattern in use. It would take some time for termination of the thread to occur. This would occur due to contention between the threads retrieving and the threads updating the cache. As the retrieving threads are given priority it may be some time before the updating threads are able to proceed. This change makes it so all threads are told to stop and then each are joined to ensure they stop. This way all the threads should stop at around the same time instead of waiting for one to stop, the next to stop, then the next, and so on. As a result of this the execution time for each thrash test is much closer to their expected value than previously seen as well. Change-Id: I04a53470b0ea4170b8819180b0bd7475f3642827 --- tests/test_sorcery_memory_cache_thrash.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_sorcery_memory_cache_thrash.c b/tests/test_sorcery_memory_cache_thrash.c index daf52347108..d911e869ef1 100644 --- a/tests/test_sorcery_memory_cache_thrash.c +++ b/tests/test_sorcery_memory_cache_thrash.c @@ -304,6 +304,15 @@ static void sorcery_memory_cache_thrash_stop(struct sorcery_memory_cache_thrash } thread->stop = 1; + } + + for (idx = 0; idx < AST_VECTOR_SIZE(&thrash->threads); ++idx) { + struct sorcery_memory_cache_thrash_thread *thread; + + thread = AST_VECTOR_GET(&thrash->threads, idx); + if (thread->thread == AST_PTHREADT_NULL) { + continue; + } pthread_join(thread->thread, NULL); From 68643f83cd213e87619fa2e0d11ef38c4b2d6b6a Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 9 Feb 2016 15:21:05 -0500 Subject: [PATCH 0203/1578] Simplify and fix conditional in FD_SET. FD_SET contains a conditional statement to protect against buffer overruns. The statement was overly complicated and prevented use of the last array element of ast_fdset. We now just verify the fd is less than ast_FDMAX. Change-Id: I41895c0b497b052aef5bf49d75c817c48b326f40 --- include/asterisk/select.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/asterisk/select.h b/include/asterisk/select.h index d6d34fbbd27..d6f9d32cc3c 100644 --- a/include/asterisk/select.h +++ b/include/asterisk/select.h @@ -58,9 +58,7 @@ typedef struct { #define FD_SET(fd, fds) \ do { \ TYPEOF_FD_SET_FDS_BITS *bytes = (TYPEOF_FD_SET_FDS_BITS *) fds; \ - /* 32bit: FD / 32 + ((FD + 1) % 32 ? 1 : 0) < 1024 */ \ - /* 64bit: FD / 64 + ((FD + 1) % 64 ? 1 : 0) < 512 */ \ - if (fd / _bitsize(*bytes) + ((fd + 1) % _bitsize(*bytes) ? 1 : 0) < sizeof(*(fds)) / SIZEOF_FD_SET_FDS_BITS) { \ + if (fd < ast_FDMAX) { \ bytes[fd / _bitsize(*bytes)] |= ((TYPEOF_FD_SET_FDS_BITS) 1) << (fd % _bitsize(*bytes)); \ } else { \ fprintf(stderr, "FD %d exceeds the maximum size of ast_fdset!\n", fd); \ From c7186c7f0a70203b77f42b7e6d6997141ab8cf34 Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Wed, 10 Feb 2016 02:57:38 +0000 Subject: [PATCH 0204/1578] Build: Fix menuselect USAN conflicts USAN can be used together with other sanitizers. Reported by: Badalyan Vyacheslav Tested by: Badalyan Vyacheslav Change-Id: I3bffa350d70965c3026651dba3a12414d0aaa45f --- build_tools/cflags.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build_tools/cflags.xml b/build_tools/cflags.xml index 43f7d561233..557ea39c846 100644 --- a/build_tools/cflags.xml +++ b/build_tools/cflags.xml @@ -88,7 +88,6 @@ extended THREAD_SANITIZER LEAK_SANITIZER - UNDEFINED_SANITIZER MALLOC_DEBUG DEBUG_CHAOS @@ -96,21 +95,16 @@ extended ADDRESS_SANITIZER LEAK_SANITIZER - UNDEFINED_SANITIZER extended ADDRESS_SANITIZER THREAD_SANITIZER - UNDEFINED_SANITIZER MALLOC_DEBUG DEBUG_CHAOS extended - ADDRESS_SANITIZER - THREAD_SANITIZER - LEAK_SANITIZER BUSYDETECT_COMPARE_TONE_AND_SILENCE From a23d01e94346fb46d4b8170e72b494c90fb27d8e Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Wed, 10 Feb 2016 05:40:32 +0000 Subject: [PATCH 0205/1578] Build: Added testing compiler to support the system sanitizes In older versions of the compiler was not sanitizes. Compilers other than GCC can not support the Usan and TSAN or have other options for *FLAGS. ASTERISK-25767 #close Reported by: Badalyan Vyacheslav Tested by: Badalyan Vyacheslav Change-Id: Iefce6608221fa87884b82ae3cb5649b7b1804916 --- build_tools/cflags.xml | 4 + build_tools/menuselect-deps.in | 4 + configure | 132 +++++++++++++++++++++++++++++++++ configure.ac | 64 ++++++++++++++++ 4 files changed, 204 insertions(+) diff --git a/build_tools/cflags.xml b/build_tools/cflags.xml index 43f7d561233..763f07eeffd 100644 --- a/build_tools/cflags.xml +++ b/build_tools/cflags.xml @@ -85,6 +85,7 @@ core + HAVE_ADDRESS_SANITIZER extended THREAD_SANITIZER LEAK_SANITIZER @@ -93,12 +94,14 @@ DEBUG_CHAOS + HAVE_THREAD_SANITIZER extended ADDRESS_SANITIZER LEAK_SANITIZER UNDEFINED_SANITIZER + HAVE_LEAK_SANITIZER extended ADDRESS_SANITIZER THREAD_SANITIZER @@ -107,6 +110,7 @@ DEBUG_CHAOS + HAVE_UNDEFINED_SANITIZER extended ADDRESS_SANITIZER THREAD_SANITIZER diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index edeb8487788..f194482e958 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -73,3 +73,7 @@ WINARCH=@PBX_WINARCH@ ZLIB=@PBX_ZLIB@ TIMERFD=@PBX_TIMERFD@ NATIVE_ARCH=@AST_NATIVE_ARCH@ +HAVE_ADDRESS_SANITIZER=@AST_ADDRESS_SANITIZER@ +HAVE_LEAK_SANITIZER=@AST_LEAK_SANITIZER@ +HAVE_THREAD_SANITIZER=@AST_THREAD_SANITIZER@ +HAVE_UNDEFINED_SANITIZER=@AST_UNDEFINED_SANITIZER@ diff --git a/configure b/configure index c382032463f..a7ddb517ea4 100755 --- a/configure +++ b/configure @@ -697,6 +697,10 @@ AST_TRAMPOLINES AST_DECLARATION_AFTER_STATEMENT GC_LDFLAGS GC_CFLAGS +AST_UNDEFINED_SANITIZER +AST_LEAK_SANITIZER +AST_THREAD_SANITIZER +AST_ADDRESS_SANITIZER PBX_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PBX_PTHREAD_RWLOCK_INITIALIZER AST_ASTERISKSSL @@ -17613,6 +17617,134 @@ CFLAGS="$saved_CFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=address support" >&5 +$as_echo_n "checking for -fsanitize=address support... " >&6; } +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fsanitize=address -fno-omit-frame-pointer" +LDFLAGS="-fsanitize=address" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int x = 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + AST_ADDRESS_SANITIZER=1 +else + AST_ADDRESS_SANITIZER= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=thread support" >&5 +$as_echo_n "checking for -fsanitize=thread support... " >&6; } +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fno-omit-frame-pointer -pie -fPIE -fsanitize=thread" +LDFLAGS="-fsanitize=thread -pie -fPIE" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int x = 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + AST_THREAD_SANITIZER=1 +else + AST_THREAD_SANITIZER= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=leak support" >&5 +$as_echo_n "checking for -fsanitize=leak support... " >&6; } +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fno-omit-frame-pointer -fsanitize=leak" +LDFLAGS="-fsanitize=leak" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int x = 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + AST_LEAK_SANITIZER=1 +else + AST_LEAK_SANITIZER= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=undefined support" >&5 +$as_echo_n "checking for -fsanitize=undefined support... " >&6; } +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fno-omit-frame-pointer -fsanitize=undefined" +LDFLAGS="-fsanitize=undefined" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int x = 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + AST_UNDEFINED_SANITIZER=1 +else + AST_UNDEFINED_SANITIZER= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -ffunction-sections support" >&5 $as_echo_n "checking for -ffunction-sections support... " >&6; } saved_CFLAGS="${CFLAGS}" diff --git a/configure.ac b/configure.ac index 723b0af0f24..14b63da7212 100644 --- a/configure.ac +++ b/configure.ac @@ -1051,6 +1051,70 @@ AST_GCC_ATTRIBUTE(may_alias) AST_GCC_ATTRIBUTE(constructor) AST_GCC_ATTRIBUTE(destructor) +AC_MSG_CHECKING(for -fsanitize=address support) +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fsanitize=address -fno-omit-frame-pointer" +LDFLAGS="-fsanitize=address" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [int x = 1;])], + AC_MSG_RESULT(yes) + [AST_ADDRESS_SANITIZER=1], + [AST_ADDRESS_SANITIZER=] + AC_MSG_RESULT(no) +) +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" +AC_SUBST(AST_ADDRESS_SANITIZER) + +AC_MSG_CHECKING(for -fsanitize=thread support) +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fno-omit-frame-pointer -pie -fPIE -fsanitize=thread" +LDFLAGS="-fsanitize=thread -pie -fPIE" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [int x = 1;])], + AC_MSG_RESULT(yes) + [AST_THREAD_SANITIZER=1], + [AST_THREAD_SANITIZER=] + AC_MSG_RESULT(no) +) +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" +AC_SUBST(AST_THREAD_SANITIZER) + +AC_MSG_CHECKING(for -fsanitize=leak support) +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fno-omit-frame-pointer -fsanitize=leak" +LDFLAGS="-fsanitize=leak" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [int x = 1;])], + AC_MSG_RESULT(yes) + [AST_LEAK_SANITIZER=1], + [AST_LEAK_SANITIZER=] + AC_MSG_RESULT(no) +) +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" +AC_SUBST(AST_LEAK_SANITIZER) + +AC_MSG_CHECKING(for -fsanitize=undefined support) +saved_sanitize_CFLAGS="${CFLAGS}" +saved_sanitize_LDFLAGS="${LDFLAGS}" +CFLAGS="-fno-omit-frame-pointer -fsanitize=undefined" +LDFLAGS="-fsanitize=undefined" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [int x = 1;])], + AC_MSG_RESULT(yes) + [AST_UNDEFINED_SANITIZER=1], + [AST_UNDEFINED_SANITIZER=] + AC_MSG_RESULT(no) +) +CFLAGS="${saved_sanitize_CFLAGS}" +LDFLAGS="${saved_sanitize_LDFLAGS}" +AC_SUBST(AST_UNDEFINED_SANITIZER) + AC_MSG_CHECKING(for -ffunction-sections support) saved_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -ffunction-sections" From fd668670b5de29554780ad9ccec3cce7c2fdcb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 9 Feb 2016 23:13:07 -0300 Subject: [PATCH 0206/1578] res_config_pgsql: Show error message in reload if not connected. Change-Id: I9290115a1aaadb589eb1d02eaeb502eec01b31fa --- res/res_config_pgsql.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index d0e01bc8d49..77c52aa0b63 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -1351,6 +1351,9 @@ static int parse_config(int is_reload) config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags); if (config == CONFIG_STATUS_FILEUNCHANGED) { + if (is_reload && pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) { + ast_log(LOG_WARNING, "PostgreSQL RealTime: Not connected\n"); + } return 0; } From 168c18737f87c7bcfdc6c1bd6bbe1eeed0fcff31 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 10 Feb 2016 15:16:46 -0700 Subject: [PATCH 0207/1578] res_pjsip: Handle pjsip_dlg_create_uas deprecation Pjproject has deprecated pjsip_dlg_create_uas in 2.5 and replaced it with pjsip_dlg_create_uas_and_inc_lock which, as the name implies, automatically increments the lock on the returned dialog. To account for this, configure.ac now detects the presence of pjsip_dlg_create_uas_and_inc_lock and res_pjsip.c has an #ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK to decide whether to use the original call or the new one. If the new one was used, the ref count is decremented before returning. ASTERISK-25751 #close Reported-by Josh Colp Change-Id: I1be776b94761df03bd0693bc7795a75682615ca8 --- configure | 130 +++++++++++++++++++++++++++++-- configure.ac | 2 + include/asterisk/autoconfig.h.in | 4 + res/res_pjsip.c | 7 ++ 4 files changed, 138 insertions(+), 5 deletions(-) diff --git a/configure b/configure index a7ddb517ea4..2c0f99d4f36 100755 --- a/configure +++ b/configure @@ -935,6 +935,10 @@ PBX_PJ_TRANSACTION_GRP_LOCK PJ_TRANSACTION_GRP_LOCK_DIR PJ_TRANSACTION_GRP_LOCK_INCLUDE PJ_TRANSACTION_GRP_LOCK_LIB +PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK +PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR +PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE +PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB PBX_POPT POPT_DIR POPT_INCLUDE @@ -10475,6 +10479,18 @@ fi +PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DESCRIP="PJSIP Dialog Create UAS with Incremented Lock" +PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_OPTION=pjsip +PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR=${PJPROJECT_DIR} + +PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK=0 + + + + + + + PJ_TRANSACTION_GRP_LOCK_DESCRIP="PJSIP Transaction Group Lock Support" PJ_TRANSACTION_GRP_LOCK_OPTION=pjsip PJ_TRANSACTION_GRP_LOCK_DIR=${PJPROJECT_DIR} @@ -13701,7 +13717,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13747,7 +13763,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13771,7 +13787,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13816,7 +13832,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13840,7 +13856,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -24515,6 +24531,110 @@ fi +if test "x${PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK}" != "x1" -a "${USE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK}" != "no"; then + pbxlibdir="" + # if --with-PJSIP_DLG_CREATE_UAS_AND_INC_LOCK=DIR has been specified, use it. + if test "x${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR}" != "x"; then + if test -d ${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR}/lib; then + pbxlibdir="-L${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR}/lib" + else + pbxlibdir="-L${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR}" + fi + fi + pbxfuncname="pjsip_dlg_create_uas_and_inc_lock" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS" + as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_FOUND=yes +else + AST_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_FOUND}" = "yes"; then + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIBS" + # if --with-PJSIP_DLG_CREATE_UAS_AND_INC_LOCK=DIR has been specified, use it. + if test "x${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR}" != "x"; then + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE="-I${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR}/include" + fi + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE="${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE} $PJPROJECT_CFLAGS" + if test "xpjsip.h" = "x" ; then # no header, assume found + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default" +if test "x$ac_cv_header_pjsip_h" = xyes; then : + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_HEADER_FOUND=1 +else + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_HEADER_FOUND}" = "x0" ; then + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB="" + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB="" + fi + PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK 1 +_ACEOF + + fi + fi +fi + + + if test "x${PBX_PJ_TRANSACTION_GRP_LOCK}" != "x1" -a "${USE_PJ_TRANSACTION_GRP_LOCK}" != "no"; then pbxlibdir="" # if --with-PJ_TRANSACTION_GRP_LOCK=DIR has been specified, use it. diff --git a/configure.ac b/configure.ac index 14b63da7212..1ca5eb3dbb7 100644 --- a/configure.ac +++ b/configure.ac @@ -455,6 +455,7 @@ AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss]) AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres]) AST_EXT_LIB_SETUP([PJPROJECT], [PJPROJECT], [pjproject]) AST_EXT_LIB_SETUP([POPT], [popt], [popt]) +AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [PJSIP Dialog Create UAS with Incremented Lock], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJ_TRANSACTION_GRP_LOCK], [PJSIP Transaction Group Lock Support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_REPLACE_MEDIA_STREAM], [PJSIP Media Stream Replacement Support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_GET_DEST_INFO], [pjsip_get_dest_info support], [PJPROJECT], [pjsip]) @@ -2153,6 +2154,7 @@ fi AST_PKG_CONFIG_CHECK([PJPROJECT], [libpjproject]) +AST_EXT_LIB_CHECK([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [pjsip], [pjsip_dlg_create_uas_and_inc_lock], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJ_TRANSACTION_GRP_LOCK], [pjsip], [pjsip_tsx_create_uac2], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) saved_cppflags="${CPPFLAGS}" diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index a9179bae679..6ed96ccb5f3 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -580,6 +580,10 @@ /* Define if your system has the PJPROJECT libraries. */ #undef HAVE_PJPROJECT +/* Define to 1 if PJPROJECT has the PJSIP Dialog Create UAS with Incremented + Lock feature. */ +#undef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK + /* Define to 1 if PJPROJECT has the PJSIP External Resolver Support feature. */ #undef HAVE_PJSIP_EXTERNAL_RESOLVER diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 2b7625aba2f..cdad365ef9d 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2709,7 +2709,11 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "", (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : ""); +#ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK + *status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, &contact, &dlg); +#else *status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); +#endif if (*status != PJ_SUCCESS) { char err[PJ_ERR_MSG_SIZE]; @@ -2722,6 +2726,9 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, dlg->sess_count++; pjsip_dlg_set_transport(dlg, &selector); dlg->sess_count--; +#ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK + pjsip_dlg_dec_lock(dlg); +#endif return dlg; } From e5fd972d2474c0b200830a000bb5ce2d6b1460c2 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 11 Feb 2016 12:21:42 -0500 Subject: [PATCH 0208/1578] func_iconv: Ensure output strings are properly terminated. ASTERISK-25272 #close Reported by: Etienne Lessard patches: AST-25272.patch submitted by Etienne Lessard (license #6394) Change-Id: Id75ad202300960a1e91afe15e319d992936ecc17 --- funcs/func_iconv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/funcs/func_iconv.c b/funcs/func_iconv.c index 9582d67c51f..db52b118011 100644 --- a/funcs/func_iconv.c +++ b/funcs/func_iconv.c @@ -83,7 +83,7 @@ static int iconv_read(struct ast_channel *chan, const char *cmd, char *arguments AST_APP_ARG(text); ); iconv_t cd; - size_t incount, outcount = len; + size_t incount, outcount = len - 1; char *parse; if (ast_strlen_zero(arguments)) { @@ -120,6 +120,7 @@ static int iconv_read(struct ast_channel *chan, const char *cmd, char *arguments else ast_log(LOG_WARNING, "Iconv: error %d: %s.\n", errno, strerror(errno)); } + *buf = '\0'; iconv_close(cd); return 0; From c4d9f468783c27c6e53f6a00ae30fd90bd3ac20f Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Wed, 10 Feb 2016 04:42:11 +0000 Subject: [PATCH 0209/1578] Resources/res_phoneprov: fix memory leak and heap-use-after-free * heap-use-after-free happens when we free "cfg" but then use "value" which refers to it * A memory leak occurs because in some cases it is not released "defaults" ASTERISK-25721 #close Reported by: Badalyan Vyacheslav Tested by: Badalyan Vyacheslav Change-Id: I3807d3f4726df6864430ec144cf6265d3f538469 --- res/res_phoneprov.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c index 51c0b4a51a6..b448c8e0bb8 100644 --- a/res/res_phoneprov.c +++ b/res/res_phoneprov.c @@ -1193,8 +1193,7 @@ static struct ast_http_uri phoneprovuri = { static struct varshead *get_defaults(void) { - struct ast_config *phoneprov_cfg; - struct ast_config *cfg; + struct ast_config *phoneprov_cfg, *cfg = CONFIG_STATUS_FILEINVALID; const char *value; struct ast_variable *v; struct ast_var_t *var; @@ -1233,10 +1232,12 @@ static struct varshead *get_defaults(void) if (!value) { if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) { value = ast_variable_retrieve(cfg, "general", "bindport"); - ast_config_destroy(cfg); } } var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_SERVER_PORT], S_OR(value, "5060")); + if (cfg && cfg != CONFIG_STATUS_FILEINVALID) { + ast_config_destroy(cfg); + } AST_VAR_LIST_INSERT_TAIL(defaults, var); value = ast_variable_retrieve(phoneprov_cfg, "general", pp_general_lookup[AST_PHONEPROV_STD_PROFILE]); @@ -1288,6 +1289,7 @@ static int load_users(void) if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_WARNING, "Unable to load users.conf\n"); + ast_var_list_destroy(defaults); return -1; } @@ -1337,6 +1339,7 @@ static int load_users(void) } } ast_config_destroy(cfg); + ast_var_list_destroy(defaults); return 0; } From b37555cc94d1f82365116e6555a214f15e3f0a0d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 9 Feb 2016 16:34:05 -0700 Subject: [PATCH 0210/1578] res_pjsip: Refactor load_module/unload_module load_module was just too hairy with every step having to clean up all previous steps on failure. Some of the pjproject init calls have now been moved to a separate load_pjsip function and the unload_pjsip function was enhanced to clean up everything if an error happened at any stage of the load process. In the process, a bunch of missing pj_shutdowns, serializer_pool_shutdowns and ast_threadpool_shutdowns were also corrected. Change-Id: I5eec711b437c35b56605ed99537ebbb30463b302 --- res/res_pjsip.c | 200 +++++++++++++--------------- res/res_pjsip/pjsip_configuration.c | 8 +- 2 files changed, 99 insertions(+), 109 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 0fc5346bd43..83265f8a359 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3942,31 +3942,54 @@ static int reload_configuration_task(void *obj) return 0; } -static int load_module(void) +static int unload_pjsip(void *data) { - /* The third parameter is just copied from - * example code from PJLIB. This can be adjusted - * if necessary. + /* + * These calls need the pjsip endpoint and serializer to clean up. + * If they're not set, then there's nothing to clean up anyway. */ - pj_status_t status; - struct ast_threadpool_options options; + if (ast_pjsip_endpoint && serializer_pool[0]) { + ast_res_pjsip_cleanup_options_handling(); + ast_sip_destroy_distributor(); + ast_res_pjsip_destroy_configuration(); + ast_sip_destroy_system(); + ast_sip_destroy_global_headers(); + internal_sip_unregister_service(&supplement_module); + } - CHECK_PJPROJECT_MODULE_LOADED(); + if (monitor_thread) { + stop_monitor_thread(); + monitor_thread = NULL; + } - if (pj_init() != PJ_SUCCESS) { - return AST_MODULE_LOAD_DECLINE; + if (memory_pool) { + pj_pool_release(memory_pool); + memory_pool = NULL; } - if (pjlib_util_init() != PJ_SUCCESS) { - pj_shutdown(); - return AST_MODULE_LOAD_DECLINE; + ast_pjsip_endpoint = NULL; + + if (caching_pool.lock) { + pj_caching_pool_destroy(&caching_pool); } + pj_shutdown(); + + return 0; +} + +static int load_pjsip(void) +{ + pj_status_t status; + + /* The third parameter is just copied from + * example code from PJLIB. This can be adjusted + * if necessary. + */ pj_caching_pool_init(&caching_pool, NULL, 1024 * 1024); if (pjsip_endpt_create(&caching_pool.factory, "SIP", &ast_pjsip_endpoint) != PJ_SUCCESS) { ast_log(LOG_ERROR, "Failed to create PJSIP endpoint structure. Aborting load\n"); - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } /* PJSIP will automatically try to add a Max-Forwards header. Since we want to control that, @@ -3977,10 +4000,7 @@ static int load_module(void) memory_pool = pj_pool_create(&caching_pool.factory, "SIP", 1024, 1024, NULL); if (!memory_pool) { ast_log(LOG_ERROR, "Failed to create memory pool for SIP. Aborting load\n"); - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } if (!pj_gethostip(pj_AF_INET(), &host_ip_ipv4)) { @@ -3993,72 +4013,69 @@ static int load_module(void) ast_verb(3, "Local IPv6 address determined to be: %s\n", host_ip_ipv6_string); } + pjsip_tsx_layer_init_module(ast_pjsip_endpoint); + pjsip_ua_init_module(ast_pjsip_endpoint, NULL); + + monitor_continue = 1; + status = pj_thread_create(memory_pool, "SIP", (pj_thread_proc *) &monitor_thread_exec, + NULL, PJ_THREAD_DEFAULT_STACK_SIZE * 2, 0, &monitor_thread); + if (status != PJ_SUCCESS) { + ast_log(LOG_ERROR, "Failed to start SIP monitor thread. Aborting load\n"); + goto error; + } + + return AST_MODULE_LOAD_SUCCESS; + +error: + unload_pjsip(NULL); + return AST_MODULE_LOAD_DECLINE; +} + +static int load_module(void) +{ + struct ast_threadpool_options options; + + CHECK_PJPROJECT_MODULE_LOADED(); + + /* pjproject and config_system need to be initialized before all else */ + if (pj_init() != PJ_SUCCESS) { + return AST_MODULE_LOAD_DECLINE; + } + + if (pjlib_util_init() != PJ_SUCCESS) { + goto error; + } + if (ast_sip_initialize_system()) { ast_log(LOG_ERROR, "Failed to initialize SIP 'system' configuration section. Aborting load\n"); - pj_pool_release(memory_pool); - memory_pool = NULL; - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } + /* The serializer needs threadpool and threadpool needs pjproject to be initialized so it's next */ sip_get_threadpool_options(&options); options.thread_start = sip_thread_start; sip_threadpool = ast_threadpool_create("SIP", NULL, &options); if (!sip_threadpool) { - ast_log(LOG_ERROR, "Failed to create SIP threadpool. Aborting load\n"); - ast_sip_destroy_system(); - pj_pool_release(memory_pool); - memory_pool = NULL; - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } if (serializer_pool_setup()) { ast_log(LOG_ERROR, "Failed to create SIP serializer pool. Aborting load\n"); - ast_threadpool_shutdown(sip_threadpool); - ast_sip_destroy_system(); - pj_pool_release(memory_pool); - memory_pool = NULL; - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } - pjsip_tsx_layer_init_module(ast_pjsip_endpoint); - pjsip_ua_init_module(ast_pjsip_endpoint, NULL); - - monitor_continue = 1; - status = pj_thread_create(memory_pool, "SIP", (pj_thread_proc *) &monitor_thread_exec, - NULL, PJ_THREAD_DEFAULT_STACK_SIZE * 2, 0, &monitor_thread); - if (status != PJ_SUCCESS) { - ast_log(LOG_ERROR, "Failed to start SIP monitor thread. Aborting load\n"); - ast_sip_destroy_system(); - pj_pool_release(memory_pool); - memory_pool = NULL; - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + /* Now load all the pjproject infrastructure. */ + if (load_pjsip()) { + goto error; } + ast_sip_initialize_dns(); + ast_sip_initialize_global_headers(); if (ast_res_pjsip_initialize_configuration()) { ast_log(LOG_ERROR, "Failed to initialize SIP configuration. Aborting load\n"); - ast_sip_destroy_global_headers(); - stop_monitor_thread(); - ast_sip_destroy_system(); - pj_pool_release(memory_pool); - memory_pool = NULL; - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } ast_sip_initialize_resolver(); @@ -4066,31 +4083,12 @@ static int load_module(void) if (ast_sip_initialize_distributor()) { ast_log(LOG_ERROR, "Failed to register distributor module. Aborting load\n"); - ast_res_pjsip_destroy_configuration(); - ast_sip_destroy_global_headers(); - stop_monitor_thread(); - ast_sip_destroy_system(); - pj_pool_release(memory_pool); - memory_pool = NULL; - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } if (internal_sip_register_service(&supplement_module)) { ast_log(LOG_ERROR, "Failed to initialize supplement hooks. Aborting load\n"); - ast_sip_destroy_distributor(); - ast_res_pjsip_destroy_configuration(); - ast_sip_destroy_global_headers(); - stop_monitor_thread(); - ast_sip_destroy_system(); - pj_pool_release(memory_pool); - memory_pool = NULL; - pjsip_endpt_destroy(ast_pjsip_endpoint); - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - return AST_MODULE_LOAD_DECLINE; + goto error; } ast_res_pjsip_init_options_handling(0); @@ -4102,6 +4100,14 @@ static int load_module(void) ast_pjproject_ref(); return AST_MODULE_LOAD_SUCCESS; + +error: + /* These functions all check for NULLs and are safe to call at any time */ + unload_pjsip(NULL); + serializer_pool_shutdown(); + ast_threadpool_shutdown(sip_threadpool); + + return AST_MODULE_LOAD_DECLINE; } static int reload_module(void) @@ -4118,32 +4124,11 @@ static int reload_module(void) return 0; } -static int unload_pjsip(void *data) -{ - ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); - ast_res_pjsip_cleanup_options_handling(); - ast_sip_destroy_distributor(); - ast_res_pjsip_destroy_configuration(); - ast_sip_destroy_system(); - ast_sip_destroy_global_headers(); - internal_sip_unregister_service(&supplement_module); - if (monitor_thread) { - stop_monitor_thread(); - } - if (memory_pool) { - pj_pool_release(memory_pool); - memory_pool = NULL; - } - ast_pjsip_endpoint = NULL; - pj_caching_pool_destroy(&caching_pool); - pj_shutdown(); - return 0; -} - static int unload_module(void) { AST_TEST_UNREGISTER(xml_sanitization_end_null); AST_TEST_UNREGISTER(xml_sanitization_exceeds_buffer); + ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); /* The thread this is called from cannot call PJSIP/PJLIB functions, * so we have to push the work to the threadpool to handle @@ -4153,7 +4138,6 @@ static int unload_module(void) serializer_pool_shutdown(); ast_threadpool_shutdown(sip_threadpool); - ast_sip_destroy_cli(); ast_pjproject_unref(); return 0; diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 4afa9507d1a..2a81cfded27 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -2024,18 +2024,24 @@ int ast_res_pjsip_initialize_configuration(void) void ast_res_pjsip_destroy_configuration(void) { + if (!sip_sorcery) { + return; + } + ast_sorcery_observer_remove(sip_sorcery, CONTACT_STATUS, &state_contact_status_observer); ast_sorcery_observer_remove(sip_sorcery, "contact", &state_contact_observer); ast_sip_destroy_sorcery_global(); ast_sip_destroy_sorcery_location(); ast_sip_destroy_sorcery_auth(); ast_sip_destroy_sorcery_transport(); + ast_sorcery_unref(sip_sorcery); + sip_sorcery = NULL; ast_manager_unregister(AMI_SHOW_ENDPOINT); ast_manager_unregister(AMI_SHOW_ENDPOINTS); ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(endpoint_formatter); ast_sip_unregister_cli_formatter(channel_formatter); - ast_sorcery_unref(sip_sorcery); + ast_sip_destroy_cli(); ao2_cleanup(persistent_endpoints); } From 5c400a0fedffface7d7b41c40bcaa2810ca6da15 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 15 Feb 2016 14:52:22 -0400 Subject: [PATCH 0211/1578] res_pjsip_pubsub: Move where the subscription is stored to after initialized. A problem arose when testing the AMI subscription listing actions where it was possible for a subscription that had not been fully initialized to be listed. This was problematic as the underlying listing code would crash. This change makes it so the subscription tree is fully set up before it is added to the list of subscriptions. This ensures that when the listing actions get the subscription it is valid. ASTERISK-25738 #close Change-Id: Iace2b13641c31bbcc0d43a39f99aba1f340c0f48 --- res/res_pjsip_pubsub.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index dc7f5ed9e67..bde7075dd96 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1254,7 +1254,6 @@ static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_e sub_tree->endpoint = ao2_bump(endpoint); sub_tree->notify_sched_id = -1; - add_subscription(sub_tree); return sub_tree; } @@ -1328,6 +1327,8 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s sub_tree->is_list = 1; } + add_subscription(sub_tree); + return sub_tree; } @@ -1616,6 +1617,8 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su return NULL; } + add_subscription(sub_tree); + return sub; } From 13b6c02945655fabf2c4b1093d663c70f6ea21ea Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 15 Feb 2016 13:08:22 -0600 Subject: [PATCH 0212/1578] Fix creation race of contact_status structures. It is possible when processing a SIP REGISTER request to have two threads end up creating contact_status structures in sorcery. contact_status is created using a "find or create" function. If two threads call into this at the same time, each thread will fail to find an existing contact_status, and so both will end up creating a new contact status. During testing, we would see sporadic failures because the PJSIP_CONTACT() dialplan function would operate on a different contact_status than what had been updated by res_pjsip/pjsip_options. The fix here is two-fold: 1) The "find or create" function for contact_status now has a lock around the entire operation. This way, if two threads attempt the operation simultaneously, the first to get there will create the object, and the second will find the object created by the first thread. 2) res_sorcery_memory has had its create callback updated so that it will not allow for objects with duplicate IDs to be created. Change-Id: I55b1460ff1eb0af0a3697b82d7c2bac9f6af5b97 --- res/res_pjsip/pjsip_options.c | 3 +++ res/res_sorcery_memory.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 089703b2690..73f12a00c58 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -107,6 +107,8 @@ static void *contact_status_alloc(const char *name) return status; } +AST_MUTEX_DEFINE_STATIC(creation_lock); + /*! * \brief Retrieve a ast_sip_contact_status object from sorcery creating * one if not found. @@ -114,6 +116,7 @@ static void *contact_status_alloc(const char *name) struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact) { struct ast_sip_contact_status *status; + SCOPED_MUTEX(lock, &creation_lock); status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c index 153235838bb..95cb24835f2 100644 --- a/res/res_sorcery_memory.c +++ b/res/res_sorcery_memory.c @@ -98,7 +98,21 @@ static int sorcery_memory_cmp(void *obj, void *arg, int flags) static int sorcery_memory_create(const struct ast_sorcery *sorcery, void *data, void *object) { - ao2_link(data, object); + void *existing; + + ao2_lock(data); + + existing = ao2_find(data, ast_sorcery_object_get_id(object), OBJ_KEY | OBJ_NOLOCK); + if (existing) { + ao2_ref(existing, -1); + ao2_unlock(data); + return -1; + } + + ao2_link_flags(data, object, OBJ_NOLOCK); + + ao2_unlock(data); + return 0; } From be811c4be14d8529eb7c17a8aa756f221cd5b661 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 15 Feb 2016 14:37:30 -0700 Subject: [PATCH 0213/1578] res_pjsip_caller_id: Fix segfault when replacing rpid or pai header If the PJSIP_HEADER dialplan function adds a PAI or RPID header and send_rpid or send_pai is set, res_pjsip_caller_id attemps to retrieve, parse and modify the header added by the dialplan function. Since the header added by the dialplan function is generic string, there are no virtual functions to parse the uri and we get a segfault when we try. Since the modify, was really only an overwrite, we now just delete the old header if it was type PJSIP_H_OTHER and recreate it. This raises a question for another time though: What should happen with duplicate headers? Right now res_pjsip_header_funcs doesn't check for dups so if it's session supplement is loaded after res_pjsip_caller_id's (or any other module that adds headers), there'll be dups in the message. ASTERISK-25337 #close Change-Id: I5e296b52d30f106b822c0eb27c4c2b0e0f71c7fa --- res/res_pjsip_caller_id.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 07b12669dd1..8227cacda51 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -511,9 +511,22 @@ static void add_pai_header(pjsip_tx_data *tdata, const struct ast_party_id *id) */ old_pai = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_pai_name, NULL); if (old_pai) { - modify_id_header(tdata->pool, old_pai, id); - add_privacy_header(tdata, id); - return; + /* If type is OTHER, then the existing header was most likely + * added by the PJSIP_HEADER dial plan function as a simple + * name/value pair. We can't pass this to modify_id_header because + * there are no virtual functions to get the uri. We could parse + * it into a pjsip_fromto_hdr but it isn't worth it since + * modify_id_header is just going to overwrite the name and number + * anyway. We'll just remove it from the header list instead + * and create a new one. + */ + if (old_pai->type == PJSIP_H_OTHER) { + pj_list_erase(old_pai); + } else { + modify_id_header(tdata->pool, old_pai, id); + add_privacy_header(tdata, id); + return; + } } pai_hdr = create_new_id_hdr(&pj_pai_name, tdata, id); @@ -600,9 +613,22 @@ static void add_rpid_header(pjsip_tx_data *tdata, const struct ast_party_id *id) */ old_rpid = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_rpid_name, NULL); if (old_rpid) { - modify_id_header(tdata->pool, old_rpid, id); - add_privacy_params(tdata, old_rpid, id); - return; + /* If type is OTHER, then the existing header was most likely + * added by the PJSIP_HEADER dial plan function as a simple + * name/value pair. We can't pass this to modify_id_header because + * there are no virtual functions to get the uri. We could parse + * it into a pjsip_fromto_hdr but it isn't worth it since + * modify_id_header is just going to overwrite the name and number + * anyway. We'll just remove it from the header list instead + * and create a new one. + */ + if (old_rpid->type == PJSIP_H_OTHER) { + pj_list_erase(old_rpid); + } else { + modify_id_header(tdata->pool, old_rpid, id); + add_privacy_params(tdata, old_rpid, id); + return; + } } rpid_hdr = create_new_id_hdr(&pj_rpid_name, tdata, id); From 4f08e9fb6471b9350c1baa247361ca565a5b1b37 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 15 Feb 2016 20:31:38 -0700 Subject: [PATCH 0214/1578] res_pjsip_config_wizard: Add command to export primitive objects A new command (pjsip export config_wizard primitives) has been added that will export all the pjsip objects it created to the console or a file suitable for reuse in a pjsip.conf file. ASTERISK-24919 #close Reported-by: Ray Crumrine Change-Id: Ica2a5f494244b4f8345b0437b16d06aa0484452b --- CHANGES | 6 ++ res/res_pjsip_config_wizard.c | 111 +++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 5e4c428469f..ff3361ee65a 100644 --- a/CHANGES +++ b/CHANGES @@ -210,6 +210,12 @@ Queue --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ ------------------------------------------------------------------------------ +res_pjsip_config_wizard +------------------ + * A new command (pjsip export config_wizard primitives) has been added that + will export all the pjsip objects it created to the console or a file + suitable for reuse in a pjsip.conf file. + app_confbridge ------------------ * Added CONFBRIDGE_INFO(muted,) for querying the muted conference state. diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index 9d85a4615c2..cf09a541512 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -45,6 +45,7 @@ ASTERISK_REGISTER_FILE() #include #include "asterisk/astobj2.h" +#include "asterisk/cli.h" #include "asterisk/res_pjsip.h" #include "asterisk/module.h" #include "asterisk/pbx.h" @@ -276,7 +277,7 @@ struct object_type_wizard { struct ast_config *last_config; char object_type[]; }; -static AST_VECTOR(object_type_wizards, struct object_type_wizard *) object_type_wizards; +static AST_VECTOR_RW(object_type_wizards, struct object_type_wizard *) object_type_wizards; /*! \brief Callbacks for vector deletes */ #define NOT_EQUALS(a, b) (a != b) @@ -304,12 +305,15 @@ static struct object_type_wizard *find_wizard(const char *object_type) { int idx; + AST_VECTOR_RW_RDLOCK(&object_type_wizards); for(idx = 0; idx < AST_VECTOR_SIZE(&object_type_wizards); idx++) { struct object_type_wizard *otw = AST_VECTOR_GET(&object_type_wizards, idx); if (!strcmp(otw->object_type, object_type)) { + AST_VECTOR_RW_UNLOCK(&object_type_wizards); return otw; } } + AST_VECTOR_RW_UNLOCK(&object_type_wizards); return NULL; } @@ -1137,7 +1141,9 @@ static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery otw->wizard_data = wizard_data; otw->last_config = NULL; strcpy(otw->object_type, object_type); /* Safe */ + AST_VECTOR_RW_WRLOCK(&object_type_wizards); AST_VECTOR_APPEND(&object_type_wizards, otw); + AST_VECTOR_RW_UNLOCK(&object_type_wizards); ast_debug(1, "Wizard mapped for object_type '%s'\n", object_type); } } @@ -1177,19 +1183,118 @@ static void instance_destroying_observer(const char *name, struct ast_sorcery *s ast_module_unref(ast_module_info->self); } +static char *handle_export_primitives(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ast_sorcery *sorcery; + int idx; + FILE *f = NULL; + const char *fn = NULL; + + switch (cmd) { + case CLI_INIT: + e->command = "pjsip export config_wizard primitives [to]"; + e->usage = + "Usage: pjsip export config_wizard primitives [ to \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc > 5) { + char date[256]=""; + time_t t; + fn = a->argv[5]; + + time(&t); + ast_copy_string(date, ctime(&t), sizeof(date)); + f = fopen(fn, "w"); + if (!f) { + ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + return CLI_FAILURE; + } + + fprintf(f, ";!\n"); + fprintf(f, ";! Automatically generated configuration file\n"); + fprintf(f, ";! Filename: %s\n", fn); + fprintf(f, ";! Generator: %s\n", "'pjsip export config_wizard primitives'"); + fprintf(f, ";! Creation Date: %s", date); + fprintf(f, ";!\n"); + } + + sorcery = ast_sip_get_sorcery(); + + AST_VECTOR_RW_RDLOCK(&object_type_wizards); + for(idx = 0; idx < AST_VECTOR_SIZE(&object_type_wizards); idx++) { + struct object_type_wizard *otw = AST_VECTOR_GET(&object_type_wizards, idx); + struct ao2_container *container; + struct ao2_iterator i; + void *o; + + container = ast_sorcery_retrieve_by_fields(sorcery, otw->object_type, AST_RETRIEVE_FLAG_MULTIPLE, NULL); + if (!container) { + continue; + } + + i = ao2_iterator_init(container, 0); + while ((o = ao2_iterator_next(&i))) { + struct ast_variable *vars; + struct ast_variable *v; + + vars = ast_sorcery_objectset_create(sorcery, o); + if (vars && ast_variable_find_in_list(vars, "@pjsip_wizard")) { + if (f) { + fprintf(f, "\n[%s]\ntype = %s\n", ast_sorcery_object_get_id(o), otw->object_type); + } else { + ast_cli(a->fd, "\n[%s]\ntype = %s\n", ast_sorcery_object_get_id(o), otw->object_type); + } + for (v = vars; v; v = v->next) { + if (!ast_strlen_zero(v->value)) { + if (f) { + fprintf(f, "%s = %s\n", v->name, v->value); + } else { + ast_cli(a->fd, "%s = %s\n", v->name, v->value); + } + } + } + } + ast_variables_destroy(vars); + ao2_ref(o, -1); + } + ao2_iterator_destroy(&i); + ao2_cleanup(container); + } + AST_VECTOR_RW_UNLOCK(&object_type_wizards); + + if (f) { + fclose(f); + ast_cli(a->fd, "Wrote configuration to %s\n", fn); + } + + + return CLI_SUCCESS; +} + +static struct ast_cli_entry config_wizard_cli[] = { + AST_CLI_DEFINE(handle_export_primitives, "Export config wizard primitives"), +}; + static int load_module(void) { - AST_VECTOR_INIT(&object_type_wizards, 12); + AST_VECTOR_RW_INIT(&object_type_wizards, 12); ast_sorcery_global_observer_add(&global_observer); + ast_cli_register_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli)); return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { + ast_cli_unregister_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli)); ast_sorcery_global_observer_remove(&global_observer); AST_VECTOR_REMOVE_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB); - AST_VECTOR_FREE(&object_type_wizards); + AST_VECTOR_RW_FREE(&object_type_wizards); return 0; } From 49203628f984009011493ceefd58aa9e056b0351 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 16 Feb 2016 11:20:57 -0700 Subject: [PATCH 0215/1578] res_statsd: Fix exports.in for missing symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit res_statsd.export.in was missing the _va variations of the log functions causing Asterisk to crash in res_pjsip if OPTIONAL_API wasn't enabled. ASTERISK-25727 #close Reported-by: Gergely Dömsödi Change-Id: I395729f9f51bdd33c5ca757f5f96ebedad74077b --- res/res_statsd.exports.in | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/res/res_statsd.exports.in b/res/res_statsd.exports.in index d4a79c18f07..ca28b1605dd 100644 --- a/res/res_statsd.exports.in +++ b/res/res_statsd.exports.in @@ -1,9 +1,6 @@ { global: - LINKER_SYMBOL_PREFIX*ast_statsd_log; - LINKER_SYMBOL_PREFIX*ast_statsd_log_full; - LINKER_SYMBOL_PREFIX*ast_statsd_log_sample; - LINKER_SYMBOL_PREFIX*ast_statsd_log_string; + LINKER_SYMBOL_PREFIXast_statsd_log*; local: *; }; From 62282bb8ce15e3e70b3e2fd79834c02911b5f8ff Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 16 Feb 2016 15:37:48 -0700 Subject: [PATCH 0216/1578] res_odbc: Fix exports.in for missing symbols res_odbc.exports.in was missing a few symbols. Changed to wildcards. Change-Id: Ieadd76df24e43ea92577f651d478a0f7b742c30c --- res/res_odbc.exports.in | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/res/res_odbc.exports.in b/res/res_odbc.exports.in index 84bbc48dd7b..dc7c289e740 100644 --- a/res/res_odbc.exports.in +++ b/res/res_odbc.exports.in @@ -1,24 +1,7 @@ { global: - LINKER_SYMBOL_PREFIXast_odbc_ast_str_SQLGetData; - LINKER_SYMBOL_PREFIXast_odbc_backslash_is_escape; - LINKER_SYMBOL_PREFIXast_odbc_clear_cache; - LINKER_SYMBOL_PREFIXast_odbc_direct_execute; - LINKER_SYMBOL_PREFIXast_odbc_find_column; - LINKER_SYMBOL_PREFIXast_odbc_find_table; - LINKER_SYMBOL_PREFIXast_odbc_prepare_and_execute; - LINKER_SYMBOL_PREFIXast_odbc_release_obj; - LINKER_SYMBOL_PREFIXast_odbc_request_obj; - LINKER_SYMBOL_PREFIX_ast_odbc_request_obj; - LINKER_SYMBOL_PREFIXast_odbc_request_obj2; - LINKER_SYMBOL_PREFIX_ast_odbc_request_obj2; - LINKER_SYMBOL_PREFIXast_odbc_sanity_check; - LINKER_SYMBOL_PREFIXast_odbc_smart_execute; - LINKER_SYMBOL_PREFIXast_odbc_class_get_isolation; - LINKER_SYMBOL_PREFIXast_odbc_class_get_forcecommit; - LINKER_SYMBOL_PREFIXast_odbc_class_get_name; - LINKER_SYMBOL_PREFIXast_odbc_text2isolation; - LINKER_SYMBOL_PREFIXast_odbc_isolation2text; + LINKER_SYMBOL_PREFIXast_odbc_*; + LINKER_SYMBOL_PREFIX_ast_odbc_*; local: *; }; From 15aeb78c6668252107a6fb2860de9ece5011f77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Wed, 17 Feb 2016 02:37:43 -0300 Subject: [PATCH 0217/1578] app_queue: fix Calculate talktime when is first call answered Fix calculate of average time for talktime is wrong when is completed the first call beacuse the time for talked would be that call. ASTERISK-25800 #close Change-Id: I94f79028935913cd9174b090b52bb300b91b9492 --- apps/app_queue.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 15f32fadb86..776ada4b8fa 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5441,9 +5441,13 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom if (callcompletedinsl) { q->callscompletedinsl++; } - /* Calculate talktime using the same exponential average as holdtime code*/ - oldtalktime = q->talktime; - q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; + if (q->callscompletedinsl == 1) { + q->talktime = newtalktime; + } else { + /* Calculate talktime using the same exponential average as holdtime code */ + oldtalktime = q->talktime; + q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; + } ao2_unlock(q); return 0; } From 30a49b8a6a757d9c748f847fb71562bbbc23e1f9 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 17 Feb 2016 13:30:06 -0600 Subject: [PATCH 0218/1578] cel.c: Fix mismatch in ast_cel_track_event() return type. The return type of ast_cel_track_event() is not large enough to return all 64 potential bits of the event enable mask. Fortunately, the defined CEL events do not really need all 64 bits and the return value is only used to determine if the requested CEL event is enabled. * Made the ast_cel_track_event() return 0 or 1 only so the return value can fit inside an int type instead of zero or a truncated 64 bit non-zero value. Change-Id: I783d932320db11a95c7bf7636a72b6fe2566904c --- main/cel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/cel.c b/main/cel.c index f2d51688333..a0d0ad7235e 100644 --- a/main/cel.c +++ b/main/cel.c @@ -541,7 +541,7 @@ static int ast_cel_track_event(enum ast_cel_event_type et) return 0; } - return (cfg->general->events & ((int64_t) 1 << et)); + return (cfg->general->events & ((int64_t) 1 << et)) ? 1 : 0; } static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) From 8055d080cde418675f095703767b52d5729fb31e Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 18 Feb 2016 11:15:22 -0600 Subject: [PATCH 0219/1578] Fix failing threadpool_auto_increment test. The threadpool_auto_increment test fails infrequently for a couple of reasons * The threadpool listener was notified of fewer tasks being pushed than were actually pushed * The "was_empty" flag was set to an unexpected value. The problem is that the test pushes three tasks into the threadpool. Test expects the threadpool to essentially gather those three tasks, and then distribute those to the threadpool threads. It also expects that as the tasks are pushed in, the threadpool listener is alerted immediately that the tasks have been pushed. In reality, a task can be distributed to the threadpool threads quicker than expected, meaning that the threadpool has already emptied by the time each subsequent task is pushed. In addition, the internal threadpool queue can be delayed so that the threadpool listener is not alerted that a task has been pushed even after the task has been executed. From the test's point of view, there's no way to be able to predict exactly the order that task execution/listener notifications will occur, and there is no way to know which listener notifications will indicate that the threadpool was previously empty. For this reason, the test has been updated to only check the things it can check. It ensures that all tasks get executed, that the threads go idle after the tasks are executed, and that the listener is told the proper number of tasks that were pushed. Change-Id: I7673120d74adad64ae6894594a606e102d9a1f2c --- tests/test_threadpool.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tests/test_threadpool.c b/tests/test_threadpool.c index afb981be605..d8acf26f9f2 100644 --- a/tests/test_threadpool.c +++ b/tests/test_threadpool.c @@ -921,6 +921,41 @@ AST_TEST_DEFINE(threadpool_one_thread_multiple_tasks) return res; } +static enum ast_test_result_state wait_until_thread_state_task_pushed(struct ast_test *test, + struct test_listener_data *tld, int num_active, int num_idle, int num_tasks) +{ + enum ast_test_result_state res = AST_TEST_PASS; + struct timeval start; + struct timespec end; + + res = wait_until_thread_state(test, tld, num_active, num_idle); + if (res == AST_TEST_FAIL) { + return res; + } + + start = ast_tvnow(); + end.tv_sec = start.tv_sec + 5; + end.tv_nsec = start.tv_usec * 1000; + + ast_mutex_lock(&tld->lock); + + while (tld->num_tasks != num_tasks) { + if (ast_cond_timedwait(&tld->cond, &tld->lock, &end) == ETIMEDOUT) { + break; + } + } + + if (tld->num_tasks != num_tasks) { + ast_test_status_update(test, "Number of tasks pushed %d does not match expected %d\n", + tld->num_tasks, num_tasks); + res = AST_TEST_FAIL; + } + + ast_mutex_unlock(&tld->lock); + + return res; +} + AST_TEST_DEFINE(threadpool_auto_increment) { struct ast_threadpool *pool = NULL; @@ -1021,11 +1056,10 @@ AST_TEST_DEFINE(threadpool_auto_increment) goto end; } - res = wait_until_thread_state(test, tld, 0, 3); + res = wait_until_thread_state_task_pushed(test, tld, 0, 3, 4); if (res == AST_TEST_FAIL) { goto end; } - res = listener_check(test, listener, 1, 0, 4, 0, 3, 1); end: ast_threadpool_shutdown(pool); From 14886643c669f8c154ee3ea646ffeffeddc91309 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 18 Feb 2016 11:55:39 -0500 Subject: [PATCH 0220/1578] res_pjsip_outbound_publish: Fix processing 412 response When Asterisk receives a 412 (Conditional Request Failed) response it has to recreate publish session. There is bug in res_pjsip_outbound_publish.c The function sip_outbound_publish_client_alloc is called with wrong object while processing 412 (Conditional Request Failed) response. This patch fixes it. ASTERISK-25229 #close Change-Id: I3b62f2debf6bb1e5817cde7b13ea39ef2bf14359 --- res/res_pjsip_outbound_publish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index a58bcbb9165..856d84a7ad9 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -893,7 +893,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) pjsip_publishc_destroy(client->client); client->client = NULL; - if (sip_outbound_publish_client_alloc(publish)) { + if (sip_outbound_publish_client_alloc(client)) { ast_log(LOG_ERROR, "Failed to create a new outbound publish client for '%s' on 412 response\n", ast_sorcery_object_get_id(publish)); goto end; From f8767a8804cd46858ec3f8d25bfe5700236685f2 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 7 Feb 2016 16:34:20 -0700 Subject: [PATCH 0221/1578] res_pjproject: Add ability to map pjproject log levels to Asterisk log levels Warnings and errors in the pjproject libraries are generally handled by Asterisk. In many cases, Asterisk wouldn't even consider them to be warnings or errors so the messages emitted by pjproject directly are either superfluous or misleading. A good exampe of this are the level-0 errors pjproject emits when it can't open a TCP/TLS socket to a client to send an OPTIONS. We don't consider a failure to qualify a UDP client an "ERROR", why should a TCP/TLS client be treated any differently? A config file for res_pjproject has bene added (pjproject.conf) and a new log_mappings object allows mapping pjproject levels to Asterisk levels (or nothing). The defaults if no pjproject.conf file is found are the same as those that were hard-coded into res_pjproject initially: 0,1 = LOG_ERROR, 2 = LOG_WARNING, 3,4,5 = LOG_DEBUG Change-Id: Iba7bb349c70397586889b8f45b8c3d6c6c8c3898 --- CHANGES | 8 + configs/samples/pjproject.conf.sample | 28 ++++ res/res_pjproject.c | 224 ++++++++++++++++++++++++-- 3 files changed, 248 insertions(+), 12 deletions(-) create mode 100644 configs/samples/pjproject.conf.sample diff --git a/CHANGES b/CHANGES index 5e4c428469f..89c3b49092e 100644 --- a/CHANGES +++ b/CHANGES @@ -229,6 +229,14 @@ res_pjproject This displays the compiled-in options of the pjproject installation Asterisk is currently running against. + * Another feature of this module is the ability to map pjproject log levels + to Asterisk log levels, or to suppress the pjproject log messages + altogether. Many of the messages emitted by pjproject itself are the result + of errors which Asterisk will ultimately handle so the messages can be + misleading or just noise. A new config file (pjproject.conf) has been added + to configure the mapping and a new CLI command (pjproject show log mappings) + has been added to display the mappings currently in use. + res_pjsip ------------------ * Added new global option (regcontext) to pjsip. When set, Asterisk will diff --git a/configs/samples/pjproject.conf.sample b/configs/samples/pjproject.conf.sample new file mode 100644 index 00000000000..97af7345f40 --- /dev/null +++ b/configs/samples/pjproject.conf.sample @@ -0,0 +1,28 @@ +; Common pjproject options +; + +;========================LOG_MAPPINGS SECTION OPTIONS=============================== +;[log_mappings] +; SYNOPSIS: Provides pjproject to Asterisk log level mappings. +; NOTES: The name of this section in the pjproject.conf configuration file must +; remain log_mappings or the configuration will not be applied. +; The defaults mentioned below only apply if this file or the 'log_mappings' +; object can'tbe found. If the object is found, there are no defaults. If +; you don't specify an entry, nothing will be logged for that level. +; +;asterisk_error = ; A comma separated list of pjproject log levels to map to + ; Asterisk errors. + ; (default: "0,1") +;asterisk_warning = ; A comma separated list of pjproject log levels to map to + ; Asterisk warnings. + ; (default: "2") +;asterisk_notice = ; A comma separated list of pjproject log levels to map to + ; Asterisk notices. + ; (default: "") +;asterisk_verbose = ; A comma separated list of pjproject log levels to map to + ; Asterisk verbose. + ; (default: "") +;asterisk_debug = ; A comma separated list of pjproject log levels to map to + ; Asterisk debug + ; (default: "3,4,5") +;type= ; Must be of type log_mappings (default: "") diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 9e08bf3e0e6..9ed3d57a199 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -37,6 +37,44 @@ core ***/ +/*** DOCUMENTATION + + pjproject common configuration + + + PJPROJECT to Asterisk Log Level Mapping + Warnings and errors in the pjproject libraries are generally handled + by Asterisk. In many cases, Asterisk wouldn't even consider them to + be warnings or errors so the messages emitted by pjproject directly + are either superfluous or misleading. The 'log_mappings' + object allows mapping the pjproject levels to Asterisk levels, or nothing. + + The id of this object, as well as its type, must be + 'log_mappings' or it won't be found. + + + Must be of type 'log_mappings'. + + + A comma separated list of pjproject log levels to map to Asterisk LOG_ERROR. + + + A comma separated list of pjproject log levels to map to Asterisk LOG_WARNING. + + + A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE. + + + A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG. + + + A comma separated list of pjproject log levels to map to Asterisk LOG_VERBOSE. + + + + + ***/ + #include "asterisk.h" ASTERISK_REGISTER_FILE() @@ -51,7 +89,9 @@ ASTERISK_REGISTER_FILE() #include "asterisk/cli.h" #include "asterisk/res_pjproject.h" #include "asterisk/vector.h" +#include "asterisk/sorcery.h" +static struct ast_sorcery *pjproject_sorcery; static pj_log_func *log_cb_orig; static unsigned decor_orig; @@ -70,6 +110,66 @@ static struct pjproject_log_intercept_data pjproject_log_intercept = { .fd = -1, }; +struct log_mappings { + /*! Sorcery object details */ + SORCERY_OBJECT(details); + /*! These are all comma-separated lists of pjproject log levels */ + AST_DECLARE_STRING_FIELDS( + /*! pjproject log levels mapped to Asterisk ERROR */ + AST_STRING_FIELD(asterisk_error); + /*! pjproject log levels mapped to Asterisk WARNING */ + AST_STRING_FIELD(asterisk_warning); + /*! pjproject log levels mapped to Asterisk NOTICE */ + AST_STRING_FIELD(asterisk_notice); + /*! pjproject log levels mapped to Asterisk VERBOSE */ + AST_STRING_FIELD(asterisk_verbose); + /*! pjproject log levels mapped to Asterisk DEBUG */ + AST_STRING_FIELD(asterisk_debug); + ); +}; + +static struct log_mappings *default_log_mappings; + +static struct log_mappings *get_log_mappings(void) +{ + struct log_mappings *mappings; + + mappings = ast_sorcery_retrieve_by_id(pjproject_sorcery, "log_mappings", "log_mappings"); + if (!mappings) { + return ao2_bump(default_log_mappings); + } + + return mappings; +} + +#define __LOG_SUPPRESS -1 + +static int get_log_level(int pj_level) +{ + RAII_VAR(struct log_mappings *, mappings, get_log_mappings(), ao2_cleanup); + unsigned char l; + + if (!mappings) { + return __LOG_ERROR; + } + + l = '0' + fmin(pj_level, 9); + + if (strchr(mappings->asterisk_error, l)) { + return __LOG_ERROR; + } else if (strchr(mappings->asterisk_warning, l)) { + return __LOG_WARNING; + } else if (strchr(mappings->asterisk_notice, l)) { + return __LOG_NOTICE; + } else if (strchr(mappings->asterisk_verbose, l)) { + return __LOG_VERBOSE; + } else if (strchr(mappings->asterisk_debug, l)) { + return __LOG_DEBUG; + } + + return __LOG_SUPPRESS; +} + static void log_forwarder(int level, const char *data, int len) { int ast_level; @@ -89,25 +189,19 @@ static void log_forwarder(int level, const char *data, int len) return; } - /* Lower number indicates higher importance */ - switch (level) { - case 0: /* level zero indicates fatal error, according to docs */ - case 1: /* 1 seems to be used for errors */ - ast_level = __LOG_ERROR; - break; - case 2: /* 2 seems to be used for warnings and errors */ - ast_level = __LOG_WARNING; - break; - default: - ast_level = __LOG_DEBUG; + ast_level = get_log_level(level); + + if (ast_level == __LOG_SUPPRESS) { + return; + } + if (ast_level == __LOG_DEBUG) { /* For levels 3 and up, obey the debug level for res_pjproject */ mod_level = ast_opt_dbg_module ? ast_debug_get_by_module("res_pjproject") : 0; if (option_debug < level && mod_level < level) { return; } - break; } /* PJPROJECT uses indention to indicate function call depth. We'll prepend @@ -201,14 +295,105 @@ static char *handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, s return CLI_SUCCESS; } +static void mapping_destroy(void *object) +{ + struct log_mappings *mappings = object; + + ast_string_field_free_memory(mappings); +} + +static void *mapping_alloc(const char *name) +{ + struct log_mappings *mappings = ast_sorcery_generic_alloc(sizeof(*mappings), mapping_destroy); + if (!mappings) { + return NULL; + } + ast_string_field_init(mappings, 128); + + return mappings; +} + +static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ast_variable *objset; + struct ast_variable *i; + struct log_mappings *mappings; + + switch (cmd) { + case CLI_INIT: + e->command = "pjproject show log mappings"; + e->usage = + "Usage: pjproject show log mappings\n" + " Show pjproject to Asterisk log mappings\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + ast_cli(a->fd, "PJPROJECT to Asterisk log mappings:\n"); + ast_cli(a->fd, "Asterisk Level : PJPROJECT log levels\n"); + + mappings = get_log_mappings(); + if (!mappings) { + ast_log(LOG_ERROR, "Unable to retrieve pjproject log_mappings\n"); + return CLI_SUCCESS; + } + + objset = ast_sorcery_objectset_create(pjproject_sorcery, mappings); + if (!objset) { + ao2_ref(mappings, -1); + return CLI_SUCCESS; + } + + for (i = objset; i; i = i->next) { + ast_cli(a->fd, "%-16s : %s\n", i->name, i->value); + } + ast_variables_destroy(objset); + + ao2_ref(mappings, -1); + return CLI_SUCCESS; +} + static struct ast_cli_entry pjproject_cli[] = { AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"), + AST_CLI_DEFINE(handle_pjproject_show_log_mappings, "Show pjproject to Asterisk log mappings"), }; static int load_module(void) { ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n"); + if (!(pjproject_sorcery = ast_sorcery_open())) { + ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n"); + return AST_MODULE_LOAD_DECLINE; + } + + ast_sorcery_apply_default(pjproject_sorcery, "log_mappings", "config", "pjproject.conf,criteria=type=log_mappings"); + if (ast_sorcery_object_register(pjproject_sorcery, "log_mappings", mapping_alloc, NULL, NULL)) { + ast_log(LOG_WARNING, "Failed to register pjproject log_mappings object with sorcery\n"); + ast_sorcery_unref(pjproject_sorcery); + pjproject_sorcery = NULL; + return AST_MODULE_LOAD_DECLINE; + } + + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "type", "", OPT_NOOP_T, 0, 0); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_debug", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_debug)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_error", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_error)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_warning", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_warning)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_notice", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_notice)); + ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_verbose", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_verbose)); + + default_log_mappings = ast_sorcery_alloc(pjproject_sorcery, "log_mappings", "log_mappings"); + if (!default_log_mappings) { + ast_log(LOG_ERROR, "Unable to allocate memory for pjproject log_mappings\n"); + return AST_MODULE_LOAD_DECLINE; + } + ast_string_field_set(default_log_mappings, asterisk_error, "0,1"); + ast_string_field_set(default_log_mappings, asterisk_warning, "2"); + ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5"); + + ast_sorcery_load(pjproject_sorcery); + pj_init(); decor_orig = pj_log_get_decor(); @@ -247,12 +432,27 @@ static int unload_module(void) pj_shutdown(); + ao2_cleanup(default_log_mappings); + default_log_mappings = NULL; + + ast_sorcery_unref(pjproject_sorcery); + return 0; } +static int reload_module(void) +{ + if (pjproject_sorcery) { + ast_sorcery_reload(pjproject_sorcery); + } + + return AST_MODULE_LOAD_SUCCESS; +} + AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJPROJECT Log and Utility Support", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, + .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 6, ); From c00082329ef405ce2af6aaa8e40ada37de2aeb7b Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Fri, 19 Feb 2016 11:30:15 +0100 Subject: [PATCH 0222/1578] chan_sip: Optionally supply fromuser/fromdomain in SIP dial string. Previously you could add [!dnid] to the SIP dial string to alter the To: header. This change allows you to alter the From header as well. SIP dial string extra options now look like this: [![touser[@todomain]][![fromuser][@fromdomain]]] INCOMPATIBLE CHANGE: If you were using an exclamation mark in your To: header, that is no longer possible. ASTERISK-25803 #close Change-Id: I2457e9ba7a89eb1da22084bab5a4d4328e189db7 --- CHANGES | 5 ++++ UPGRADE.txt | 5 ++++ channels/chan_sip.c | 45 ++++++++++++++++++++++++++++++--- configs/samples/sip.conf.sample | 11 ++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 5e4c428469f..002ddb736d1 100644 --- a/CHANGES +++ b/CHANGES @@ -81,6 +81,11 @@ chan_sip * DTLS related configuration options can now be set at a general level. Enabling DTLS support, though, requires enabling it at the user or peer level. + * Added the possibility to set the From: header through the the SIP dial + string (populating the fromuser/fromdomain fields), complementing the + [!dnid] option for the To: header that has existed since 1.6.0 (1d6b192). + NOTE: This is again separated by an exclamation mark, so the To: header may + not contain one of those. chan_pjsip ------------------ diff --git a/UPGRADE.txt b/UPGRADE.txt index 6fb82c43aa2..131ce6caab2 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -31,6 +31,11 @@ chan_dahdi: ring-ring-ring pattern would exceed the pattern limits and stop Caller-ID detection. +chan_sip: + - The SIP dial string has been extended past the [!dnid] option by another + exclamation mark: [!dnid[!fromuri]. An exclamation mark in the To-URI + will now mean changes to the From-URI. + Core: - The REF_DEBUG compiler flag is now used to enable refdebug by default. The setting can be overridden in asterisk.conf by setting refdebug in diff --git a/channels/chan_sip.c b/channels/chan_sip.c index aaf0b6d51da..2e9a6d19590 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -29680,7 +29680,8 @@ static int sip_devicestate(const char *data) * or SIP/devicename/extension/IPorHost * or SIP/username@domain//IPorHost * and there is an optional [!dnid] argument you can append to alter the - * To: header. + * To: header. And after that, a [![fromuser][@fromdomain]] argument. + * Leave those blank to use the defaults. * \endverbatim */ static struct ast_channel *sip_request_call(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause) @@ -29752,11 +29753,49 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ /* Save the destination, the SIP dial string */ ast_copy_string(tmp, dest, sizeof(tmp)); - /* Find DNID and take it away */ + /* Find optional DNID (SIP to-uri) and From-CLI (SIP from-uri) + * and strip it from the dial string: + * [!touser[@todomain][![fromuser][@fromdomain]]] + * For historical reasons, the touser@todomain is passed as dnid + * while fromuser@fromdomain are split immediately. Passing a + * todomain without touser will create an invalid SIP message. */ dnid = strchr(tmp, '!'); if (dnid != NULL) { + char *fromuser_and_domain; + *dnid++ = '\0'; - ast_string_field_set(p, todnid, dnid); + if ((fromuser_and_domain = strchr(dnid, '!'))) { + char *forward_compat; + char *fromdomain; + + *fromuser_and_domain++ = '\0'; + + /* Cut it at a trailing NUL or trailing '!' for + * forward compatibility with extra arguments + * in the future. */ + if ((forward_compat = strchr(fromuser_and_domain, '!'))) { + /* Ignore the rest.. */ + *forward_compat = '\0'; + } + + if ((fromdomain = strchr(fromuser_and_domain, '@'))) { + *fromdomain++ = '\0'; + /* Set fromdomain. */ + if (!ast_strlen_zero(fromdomain)) { + ast_string_field_set(p, fromdomain, fromdomain); + } + } + + /* Set fromuser. */ + if (!ast_strlen_zero(fromuser_and_domain)) { + ast_string_field_set(p, fromuser, fromuser_and_domain); + } + } + + /* Set DNID (touser/todomain). */ + if (!ast_strlen_zero(dnid)) { + ast_string_field_set(p, todnid, dnid); + } } /* Divvy up the items separated by slashes */ diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample index fe685141af6..d89a2a15735 100644 --- a/configs/samples/sip.conf.sample +++ b/configs/samples/sip.conf.sample @@ -24,6 +24,9 @@ ; SIP/devicename/extension ; SIP/devicename/extension/IPorHost ; SIP/username@domain//IPorHost +; And to alter the To: or the From: header, you can additionally append +; the following to any of the above strings: +; [![touser[@todomain]][![fromuser][@fromdomain]]] ; ; ; Devicename @@ -57,6 +60,14 @@ ; ; SIP/sales@mysipproxy!sales@edvina.net ; +; (Specifying only @todomain without touser will create an invalid SIP +; request.) +; +; Similarly, you can specify the From header as well, after a second +; exclamation mark: +; +; SIP/customer@mysipproxy!!customersupport@wearespindle.com +; ; A new feature for 1.8 allows one to specify a host or IP address to use ; when routing the call. This is typically used in tandem with func_srv if ; multiple methods of reaching the same domain exist. The host or IP address From ba8adb4ce3ac15198b0dfe38df890d4283ad9bc8 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 11 Feb 2016 10:01:05 -0700 Subject: [PATCH 0223/1578] res_pjsip/config_transport: Allow reloading transports. The 'reload' mechanism actually involves closing the underlying socket and calling the appropriate udp, tcp or tls start functions again. Only outbound_registration, pubsub and session needed work to reset the transport before sending requests to insure that the pjsip transport didn't get pulled out from under them. In my testing, no calls were dropped when a transport was changed for any of the 3 transport types even if ip addresses or ports were changed. To be on the safe side however, a new transport option was added (allow_reload) which defaults to 'no'. Unless it's explicitly set to 'yes' for a transport, changes to that transport will be ignored on a reload of res_pjsip. This should preserve the current behavior. Change-Id: I5e759850e25958117d4c02f62ceb7244d7ec9edf --- CHANGES | 7 + configs/samples/pjsip.conf.sample | 6 + ...bc2c9_add_allow_reload_to_ps_transports.py | 27 ++++ include/asterisk/res_pjsip.h | 24 +++ res/res_pjsip.c | 55 +++++-- res/res_pjsip/config_transport.c | 139 ++++++++++++++---- res/res_pjsip_outbound_registration.c | 32 ++-- res/res_pjsip_pubsub.c | 31 +++- res/res_pjsip_session.c | 33 ++++- 9 files changed, 284 insertions(+), 70 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py diff --git a/CHANGES b/CHANGES index 5e4c428469f..260aa2f3cf1 100644 --- a/CHANGES +++ b/CHANGES @@ -231,6 +231,13 @@ res_pjproject res_pjsip ------------------ + * Transports are now reloadable. In testing, no in-progress calls were + disrupted if the ip address or port weren't changed, but the possibility + still exists. To make sure there are no unintentional drops, a new option + 'allow_reload', which defaults to 'no' has been added to transport. If + left at the default, changes to the particular transport will be ignored. + If set to 'yes', changes (if any) will be applied. + * Added new global option (regcontext) to pjsip. When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given endpoint who registers or unregisters with us. diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 5c326f2c570..2d127a1dcd7 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -818,6 +818,12 @@ ; clients are slow to process the received ; information. Value is in milliseconds; default ; is 100 ms. +;allow_reload=no ; Although transports can now be reloaded, that may not be + ; desirable because of the slight possibility of dropped + ; calls. To make sure there are no unintentional drops, if + ; this option is set to 'no' (the default) changes to the + ; particular transport will be ignored. If set to 'yes', + ; changes (if any) will be applied. ;==========================AOR SECTION OPTIONS========================= ;[aor] diff --git a/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py new file mode 100644 index 00000000000..377179b045d --- /dev/null +++ b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py @@ -0,0 +1,27 @@ +"""Add allow_reload to ps_transports + +Revision ID: 3bcc0b5bc2c9 +Revises: dbc44d5a908 +Create Date: 2016-02-05 17:43:39.183785 + +""" + +# revision identifiers, used by Alembic. +revision = '3bcc0b5bc2c9' +down_revision = 'dbc44d5a908' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + op.add_column('ps_transports', sa.Column('allow_reload', yesno_values)) + pass + +def downgrade(): + op.drop_column('ps_transports', 'allow_reload') + pass diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index ad34c8f5af0..3008475c305 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -185,6 +185,8 @@ struct ast_sip_transport { unsigned int cos; /*! Write timeout */ int write_timeout; + /*! Allow reload */ + int allow_reload; }; #define SIP_SORCERY_DOMAIN_ALIAS_TYPE "domain_alias" @@ -2223,4 +2225,26 @@ struct ast_sip_transport_state *ast_sip_get_transport_state(const char *transpor */ struct ao2_container *ast_sip_get_transport_states(void); +/*! + * \brief Sets pjsip_tpselector from ast_sip_transport + * \since 13.8.0 + * + * \param transport The transport to be used + * \param selector The selector to be populated + * \retval 0 success + * \retval -1 failure + */ +int ast_sip_set_tpselector_from_transport(const struct ast_sip_transport *transport, pjsip_tpselector *selector); + +/*! + * \brief Sets pjsip_tpselector from ast_sip_transport + * \since 13.8.0 + * + * \param transport_name The name of the transport to be used + * \param selector The selector to be populated + * \retval 0 success + * \retval -1 failure + */ +int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip_tpselector *selector); + #endif /* _RES_PJSIP_H */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index e355292536d..713d94ec504 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1029,6 +1029,14 @@ Value is in milliseconds; default is 100 ms. + + Allow this transport to be reloaded. + + Allow this transport to be reloaded when res_pjsip is reloaded. + This option defaults to "no" because reloading a transport may disrupt + in-progress calls. + + A way of creating an aliased name to a SIP URI @@ -2479,22 +2487,14 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u return 0; } -static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpoint, pjsip_tpselector *selector) +int ast_sip_set_tpselector_from_transport(const struct ast_sip_transport *transport, pjsip_tpselector *selector) { - RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); - const char *transport_name = endpoint->transport; - - if (ast_strlen_zero(transport_name)) { - return 0; - } - - transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_name); - transport_state = ast_sip_get_transport_state(transport_name); - if (!transport || !transport_state) { - ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' for endpoint '%s'\n", - transport_name, ast_sorcery_object_get_id(endpoint)); + transport_state = ast_sip_get_transport_state(ast_sorcery_object_get_id(transport)); + if (!transport_state) { + ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport state for '%s'\n", + ast_sorcery_object_get_id(transport)); return -1; } @@ -2517,6 +2517,35 @@ static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpo return 0; } +int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip_tpselector *selector) +{ + RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); + + if (ast_strlen_zero(transport_name)) { + return 0; + } + + transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_name); + if (!transport) { + ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s'\n", + transport_name); + return -1; + } + + return ast_sip_set_tpselector_from_transport(transport, selector); +} + +static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpoint, pjsip_tpselector *selector) +{ + const char *transport_name = endpoint->transport; + + if (ast_strlen_zero(transport_name)) { + return 0; + } + + return ast_sip_set_tpselector_from_transport_name(endpoint->transport, selector); +} + void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t *pool, pjsip_uri *uri) { pjsip_sip_uri *sip_uri; diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 0fcd7d923cd..e7bda5f0567 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -18,6 +18,7 @@ #include "asterisk.h" +#include #include #include @@ -347,6 +348,44 @@ static void copy_state_to_transport(struct ast_sip_transport *transport) memcpy(&transport->external_address, &transport->state->external_address, sizeof(transport->external_address)); } +static int has_state_changed(struct ast_sip_transport_state *a, struct ast_sip_transport_state *b) +{ + if (a->type != b->type) { + return -1; + } + + if (pj_sockaddr_cmp(&a->host, &b->host)) { + return -1; + } + + if ((a->localnet || b->localnet) + && ((!a->localnet != !b->localnet) + || ast_sockaddr_cmp(&a->localnet->addr, &b->localnet->addr) + || ast_sockaddr_cmp(&a->localnet->netmask, &b->localnet->netmask))) + { + return -1; + } + + if (ast_sockaddr_cmp(&a->external_address, &b->external_address)) { + return -1; + } + + if (a->tls.method != b->tls.method + || a->tls.ciphers_num != b->tls.ciphers_num + || a->tls.proto != b->tls.proto + || a->tls.verify_client != b->tls.verify_client + || a->tls.verify_server != b->tls.verify_server + || a->tls.require_client_cert != b->tls.require_client_cert) { + return -1; + } + + if (memcmp(a->ciphers, b->ciphers, sizeof(pj_ssl_cipher) * fmax(a->tls.ciphers_num, b->tls.ciphers_num))) { + return -1; + } + + return 0; +} + static void states_cleanup(void *states) { if (states) { @@ -364,6 +403,9 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) RAII_VAR(struct internal_state *, perm_state, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy); pj_status_t res = -1; + int i; +#define BIND_TRIES 3 +#define BIND_DELAY_US 100000 if (!states) { return -1; @@ -376,32 +418,39 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) */ ao2_wrlock(states); + temp_state = internal_state_alloc(transport); + if (!temp_state) { + ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id); + return -1; + } + perm_state = find_internal_state_by_transport(transport); if (perm_state) { ast_sorcery_diff(sorcery, perm_state->transport, transport, &changes); - if (changes) { + if (!changes && !has_state_changed(perm_state->state, temp_state->state)) { + /* In case someone is using the deprecated fields, reset them */ + transport->state = perm_state->state; + copy_state_to_transport(transport); + ao2_replace(perm_state->transport, transport); + return 0; + } + + if (!transport->allow_reload) { if (!perm_state->change_detected) { perm_state->change_detected = 1; ast_log(LOG_WARNING, "Transport '%s' is not reloadable, maintaining previous values\n", transport_id); } + /* In case someone is using the deprecated fields, reset them */ + transport->state = perm_state->state; + copy_state_to_transport(transport); + ao2_replace(perm_state->transport, transport); + return 0; } - - /* In case someone is using the deprecated fields, reset them */ - transport->state = perm_state->state; - copy_state_to_transport(transport); - ao2_replace(perm_state->transport, transport); - return 0; - } - - temp_state = internal_state_alloc(transport); - if (!temp_state) { - ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id); - goto error; } if (temp_state->state->host.addr.sa_family != PJ_AF_INET && temp_state->state->host.addr.sa_family != PJ_AF_INET6) { ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", transport_id); - goto error; + return -1; } /* Set default port if not present */ @@ -418,20 +467,33 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) } else { ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n", transport_id); - goto error; + return -1; } if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_address, &temp_state->state->external_address_refresher, NULL) < 0) { ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id); - goto error; + return -1; } } if (transport->type == AST_TRANSPORT_UDP) { - if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { - res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv4, NULL, transport->async_operations, &temp_state->state->transport); - } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { - res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv6, NULL, transport->async_operations, &temp_state->state->transport); + + for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { + if (perm_state && perm_state->state && perm_state->state->transport) { + pjsip_udp_transport_pause(perm_state->state->transport, + PJSIP_UDP_TRANSPORT_DESTROY_SOCKET); + usleep(BIND_DELAY_US); + } + + if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { + res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), + &temp_state->state->host.ipv4, NULL, transport->async_operations, + &temp_state->state->transport); + } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { + res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), + &temp_state->state->host.ipv6, NULL, transport->async_operations, + &temp_state->state->transport); + } } if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { @@ -451,18 +513,37 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); - res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &temp_state->state->factory); + for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { + if (perm_state && perm_state->state && perm_state->state->factory + && perm_state->state->factory->destroy) { + perm_state->state->factory->destroy(perm_state->state->factory); + usleep(BIND_DELAY_US); + } + + res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, + &temp_state->state->factory); + } } else if (transport->type == AST_TRANSPORT_TLS) { if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) { ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n", ast_sorcery_object_get_id(obj)); - goto error; + return -1; } temp_state->state->tls.password = pj_str((char*)transport->password); set_qos(transport, &temp_state->state->tls.qos_params); - res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls, &temp_state->state->host, NULL, transport->async_operations, &temp_state->state->factory); + for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { + if (perm_state && perm_state->state && perm_state->state->factory + && perm_state->state->factory->destroy) { + perm_state->state->factory->destroy(perm_state->state->factory); + usleep(BIND_DELAY_US); + } + + res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls, + &temp_state->state->host, NULL, transport->async_operations, + &temp_state->state->factory); + } } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) { if (transport->cos || transport->tos) { ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n"); @@ -475,17 +556,16 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) pj_strerror(res, msg, sizeof(msg)); ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg); - goto error; + return -1; } copy_state_to_transport(transport); - ao2_link(states, temp_state); + if (perm_state) { + ao2_unlink_flags(states, perm_state, OBJ_NOLOCK); + } + ao2_link_flags(states, temp_state, OBJ_NOLOCK); return 0; - -error: - ao2_unlink(states, temp_state); - return -1; } /*! \brief Custom handler for type just makes sure the state is created */ @@ -1209,6 +1289,7 @@ int ast_sip_initialize_sorcery_transport(void) ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos)); ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX); + ast_sorcery_object_field_register(sorcery, "transport", "allow_reload", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, allow_reload)); internal_sip_register_endpoint_formatter(&endpoint_transport_formatter); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 0ff609a63d6..dd69ff20e83 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -346,6 +346,8 @@ struct sip_outbound_registration_client_state { unsigned int destroy:1; /*! \brief Non-zero if we have attempted sending a REGISTER with authentication */ unsigned int auth_attempted:1; + /*! \brief The name of the transport to be used for the registration */ + char *transport_name; }; /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */ @@ -508,6 +510,7 @@ static pj_status_t registration_client_send(struct sip_outbound_registration_cli { pj_status_t status; int *callback_invoked; + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; callback_invoked = ast_threadstorage_get(®ister_callback_invoked, sizeof(int)); if (!callback_invoked) { @@ -517,6 +520,13 @@ static pj_status_t registration_client_send(struct sip_outbound_registration_cli /* Due to the message going out the callback may now be invoked, so bump the count */ ao2_ref(client_state, +1); + /* + * Set the transport in case transports were reloaded. + * When pjproject removes the extraneous error messages produced, + * we can check status and only set the transport and resend if there was an error + */ + ast_sip_set_tpselector_from_transport_name(client_state->transport_name, &selector); + pjsip_regc_set_transport(client_state->client, &selector); status = pjsip_regc_send(client_state->client, tdata); /* If the attempt to send the message failed and the callback was not invoked we need to @@ -966,6 +976,7 @@ static void sip_outbound_registration_client_state_destroy(void *obj) { struct sip_outbound_registration_client_state *client_state = obj; + ast_free(client_state->transport_name); ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0); ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0, sip_outbound_registration_status_str(client_state->status)); @@ -1003,6 +1014,7 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a state->client_state->status = SIP_REGISTRATION_UNREGISTERED; state->client_state->timer.user_data = state->client_state; state->client_state->timer.cb = sip_outbound_registration_timer_cb; + state->client_state->transport_name = ast_strdup(registration->transport); ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0); ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0, @@ -1171,25 +1183,6 @@ static int sip_outbound_registration_regc_alloc(void *data) pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); - if (!ast_strlen_zero(registration->transport)) { - RAII_VAR(struct ast_sip_transport_state *, transport_state, ast_sip_get_transport_state(registration->transport), ao2_cleanup); - - if (!transport_state) { - ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport '%s' " - " for outbound registration", registration->transport); - return -1; - } - - if (transport_state->transport) { - selector.type = PJSIP_TPSELECTOR_TRANSPORT; - selector.u.transport = transport_state->transport; - } else if (transport_state->factory) { - selector.type = PJSIP_TPSELECTOR_LISTENER; - selector.u.listener = transport_state->factory; - } else { - return -1; - } - } ast_assert(state->client_state->client == NULL); if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state, @@ -1198,6 +1191,7 @@ static int sip_outbound_registration_regc_alloc(void *data) return -1; } + ast_sip_set_tpselector_from_transport_name(registration->transport, &selector); pjsip_regc_set_transport(state->client_state->client, &selector); if (!ast_strlen_zero(registration->outbound_proxy)) { diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index bde7075dd96..0da43190cc1 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1559,6 +1559,28 @@ void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, co return pjsip_msg_find_hdr_by_name(msg, &name, NULL); } +/*! + * \internal + * \brief Wrapper for pjsip_evsub_send_request + * + * This function (re)sets the transport before sending to catch cases + * where the transport might have changed. + * + * If pjproject gives us the ability to resend, we'll only reset the transport + * if PJSIP_ETPNOTAVAIL is returned from send. + * + * \returns pj_status_t + */ +static pj_status_t internal_pjsip_evsub_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata) +{ + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; + + ast_sip_set_tpselector_from_transport_name(sub_tree->endpoint->transport, &selector); + pjsip_dlg_set_transport(sub_tree->dlg, &selector); + + return pjsip_evsub_send_request(sub_tree->evsub, tdata); +} + /* XXX This function is not used. */ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, const char *resource) @@ -1606,7 +1628,7 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su evsub = sub_tree->evsub; if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) { - pjsip_evsub_send_request(evsub, tdata); + internal_pjsip_evsub_send_request(sub_tree, tdata); } else { /* pjsip_evsub_terminate will result in pubsub_on_evsub_state, * being called and terminating the subscription. Therefore, we don't @@ -1687,8 +1709,8 @@ static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, { #ifdef TEST_FRAMEWORK struct ast_sip_endpoint *endpoint = sub_tree->endpoint; -#endif pjsip_evsub *evsub = sub_tree->evsub; +#endif int res; if (allocate_tdata_buffer(tdata)) { @@ -1696,7 +1718,8 @@ static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, return -1; } - res = pjsip_evsub_send_request(evsub, tdata) == PJ_SUCCESS ? 0 : -1; + res = internal_pjsip_evsub_send_request(sub_tree, tdata); + subscription_persistence_update(sub_tree, NULL); ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET", @@ -1705,7 +1728,7 @@ static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_evsub_get_state_name(evsub), ast_sorcery_object_get_id(endpoint)); - return res; + return (res == PJ_SUCCESS ? 0 : -1); } /*! diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index e7dd5b91d0b..983687174e0 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -888,10 +888,32 @@ int ast_sip_session_refresh(struct ast_sip_session *session, return 0; } +/*! + * \internal + * \brief Wrapper for pjsip_inv_send_msg + * + * This function (re)sets the transport before sending to catch cases + * where the transport might have changed. + * + * If pjproject gives us the ability to resend, we'll only reset the transport + * if PJSIP_ETPNOTAVAIL is returned from send. + * + * \returns pj_status_t + */ +static pj_status_t internal_pjsip_inv_send_msg(pjsip_inv_session *inv, const char *transport_name, pjsip_tx_data *tdata) +{ + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; + + ast_sip_set_tpselector_from_transport_name(transport_name, &selector); + pjsip_dlg_set_transport(inv->dlg, &selector); + + return pjsip_inv_send_msg(inv, tdata); +} + void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata) { handle_outgoing_response(session, tdata); - pjsip_inv_send_msg(session->inv_session, tdata); + internal_pjsip_inv_send_msg(session->inv_session, session->endpoint->transport, tdata); return; } @@ -1087,7 +1109,8 @@ void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip } handle_outgoing_request(session, tdata); - pjsip_inv_send_msg(session->inv_session, tdata); + internal_pjsip_inv_send_msg(session->inv_session, session->endpoint->transport, tdata); + return; } @@ -1852,7 +1875,7 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } - pjsip_inv_send_msg(inv_session, tdata); + internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); return NULL; } return inv_session; @@ -2005,7 +2028,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } else { - pjsip_inv_send_msg(inv_session, tdata); + internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); } return; } @@ -2015,7 +2038,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } else { - pjsip_inv_send_msg(inv_session, tdata); + internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); } ao2_cleanup(invite); } From b7970cabfab31408b55c4797fa260525465811e6 Mon Sep 17 00:00:00 2001 From: Christof Lauber Date: Tue, 16 Feb 2016 15:14:15 +0100 Subject: [PATCH 0224/1578] res_config_sqlite3: Fix crashes when reading peers from sqlite3 tables Introduced realloaction of ast_str buf in sqlite3_escape functions in case the returned buffer from threadstorage was actually too small. Change-Id: I3c5eb43aaade93ee457943daddc651781954c445 --- res/res_config_sqlite3.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index 0b0a78cf47a..a3061236883 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -127,8 +127,14 @@ static inline const char *sqlite3_escape_string_helper(struct ast_threadstorage * add two quotes, and convert NULL pointers to the word "NULL", but we * don't allow those anyway. Just going to use %q for now. */ struct ast_str *buf = ast_str_thread_get(ts, maxlen); - char *tmp = ast_str_buffer(buf); char q = ts == &escape_value_buf ? '\'' : '"'; + char *tmp; + + if (ast_str_size(buf) < maxlen) { + /* realloc if buf is too small */ + ast_str_make_space(&buf, maxlen); + } + tmp = ast_str_buffer(buf); ast_str_reset(buf); *tmp++ = q; /* Initial quote */ @@ -160,9 +166,15 @@ static const char *sqlite3_escape_column_op(const char *param) { size_t maxlen = strlen(param) * 2 + sizeof("\"\" ="); struct ast_str *buf = ast_str_thread_get(&escape_column_buf, maxlen); - char *tmp = ast_str_buffer(buf); + char *tmp; int space = 0; + if (ast_str_size(buf) < maxlen) { + /* realloc if buf is too small */ + ast_str_make_space(&buf, maxlen); + } + tmp = ast_str_buffer(buf); + ast_str_reset(buf); *tmp++ = '"'; while ((*tmp++ = *param++)) { From 886ee094711c8b81f50ec01e8dab882d54dcd633 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 23 Feb 2016 14:57:42 -0600 Subject: [PATCH 0225/1578] chan_sip.c: Suppress T.38 SDP c= line if addr is the same. Use the correct comparison function since we only care if the address without the port is the same. Change-Id: Ibf6c485f843a1be6dee58a47b33d81a7a8cbe3b0 --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index aaf0b6d51da..e1c391efc38 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -13447,7 +13447,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int ast_str_append(&m_modem, 0, "m=image %d udptl t38\r\n", ast_sockaddr_port(&udptldest)); - if (ast_sockaddr_cmp(&udptldest, &dest)) { + if (ast_sockaddr_cmp_addr(&udptldest, &dest)) { ast_str_append(&m_modem, 0, "c=IN %s %s\r\n", (ast_sockaddr_is_ipv6(&udptldest) && !ast_sockaddr_is_ipv4_mapped(&udptldest)) ? "IP6" : "IP4", ast_sockaddr_stringify_addr_remote(&udptldest)); From 803a2fc2d57110bf6f70d71a4ce9b84e41257d91 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 22 Feb 2016 19:31:24 -0600 Subject: [PATCH 0226/1578] rtp_engine.h: Remove extraneous semicolons. Change-Id: Ib462633d396fa941379dfef648dcd2245e350084 --- include/asterisk/rtp_engine.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 0f6ec7af616..67340335cfb 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -935,7 +935,7 @@ int ast_rtp_instance_set_requested_target_address(struct ast_rtp_instance *insta * \since 1.8 */ #define ast_rtp_instance_set_remote_address(instance, address) \ - ast_rtp_instance_set_requested_target_address((instance), (address)); + ast_rtp_instance_set_requested_target_address((instance), (address)) /*! * \brief Set the address that we are expecting to receive RTP on @@ -1047,7 +1047,7 @@ void ast_rtp_instance_get_requested_target_address(struct ast_rtp_instance *inst * \since 1.8 */ #define ast_rtp_instance_get_remote_address(instance, address) \ - ast_rtp_instance_get_incoming_source_address((instance), (address)); + ast_rtp_instance_get_incoming_source_address((instance), (address)) /*! * \brief Get the requested target address of the remote endpoint and @@ -1083,7 +1083,7 @@ int ast_rtp_instance_get_and_cmp_requested_target_address(struct ast_rtp_instanc * \since 1.8 */ #define ast_rtp_instance_get_and_cmp_remote_address(instance, address) \ - ast_rtp_instance_get_and_cmp_requested_target_address((instance), (address)); + ast_rtp_instance_get_and_cmp_requested_target_address((instance), (address)) /*! * \brief Set the value of an RTP instance extended property From 7e3e1ddf7ef1b0016edaebab711b874d489b9e9c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 25 Feb 2016 13:17:04 -0700 Subject: [PATCH 0227/1578] res_sorcery_memory_cache: Fix SEGV in some CLI commands A few of the CLI commands weren't checking for enough arguments and were SEGVing. Change-Id: Ie6494132ad2fe54b4f014bcdc112a37c36a9b413 --- res/res_sorcery_memory_cache.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index 0421d815839..704372e12b9 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -1832,7 +1832,7 @@ static char *sorcery_memory_cache_expire(struct ast_cli_entry *e, int cmd, struc } } - if (a->argc > 6) { + if (a->argc < 5 || a->argc > 6) { return CLI_SHOWUSAGE; } @@ -1886,7 +1886,7 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct } } - if (a->argc > 6) { + if (a->argc < 5 || a->argc > 6) { return CLI_SHOWUSAGE; } @@ -1945,7 +1945,7 @@ static char *sorcery_memory_cache_populate(struct ast_cli_entry *e, int cmd, str } } - if (a->argc > 5) { + if (a->argc != 5) { return CLI_SHOWUSAGE; } From acf329a3c7c814480b8893a189d6dae4ee7401ad Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 25 Feb 2016 14:39:54 -0700 Subject: [PATCH 0228/1578] res_pjsip_mwi: Turn some NOTICEs and WARNINGs into debug 1s. There are a few cases where we're emitting notices or warnings for things that really need neither, like a client retrying to subscribe to mwi when they're not conifgured for it. They get a 404 so there's no need for non-debug messages. Change-Id: I05e38a7ff6c2f2521146f4be6a79731b9864e61f --- res/res_pjsip_mwi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index f6600dd6363..e1eea6f2ae8 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -448,7 +448,7 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, contacts = ast_sip_location_retrieve_aor_contacts(aor); if (!contacts || (ao2_container_count(contacts) == 0)) { - ast_log(LOG_NOTICE, "No contacts bound to AOR %s. Cannot send unsolicited MWI until a contact registers.\n", aor_name); + ast_debug(1, "No contacts bound to AOR %s. Cannot send unsolicited MWI until a contact registers.\n", aor_name); continue; } @@ -600,7 +600,7 @@ static int mwi_validate_for_aor(void *obj, void *arg, int flags) mailboxes = ast_strdupa(aor->mailboxes); while ((mailbox = strsep(&mailboxes, ","))) { if (endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox)) { - ast_log(LOG_NOTICE, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. " + ast_debug(1, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. " "Denying MWI subscription to %s\n", ast_sorcery_object_get_id(endpoint), mailbox, ast_sorcery_object_get_id(aor)); return -1; @@ -710,13 +710,13 @@ static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint, aor = ast_sip_location_retrieve_aor(resource); if (!aor) { - ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n", + ast_debug(1, "Unable to locate aor %s. MWI subscription failed.\n", resource); return 404; } if (ast_strlen_zero(aor->mailboxes)) { - ast_log(LOG_NOTICE, "AOR %s has no configured mailboxes. MWI subscription failed.\n", + ast_debug(1, "AOR %s has no configured mailboxes. MWI subscription failed.\n", resource); return 404; } From 4422905218bf5f3033699ce35abe554f4c691a52 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 25 Feb 2016 14:13:19 -0700 Subject: [PATCH 0229/1578] sorcery: Refactor create, update and delete to better deal with caches The ast_sorcery_create, update and delete function have been refactored to better deal with caches and errors. The action is now called on all non-caching wizards first. If ANY succeed, the action is called on all caching wizards and the observers are notified. This way we don't put something in the cache (or update or delete) before knowing the action was performed in at least 1 backend and we only call the observers once even if there were multiple writable backends. ast_sorcery_create was never adding to caches in the first place which was preventing contacts from getting added to a memory_cache when they were created. In turn this was causing memory_cache to emit errors if the contact was deleted before being retrieved (which would have populated the cache). ASTERISK-25811 #close Reported-by: Ross Beer Change-Id: Id5596ce691685a79886e57b0865888458d6e7b46 --- main/sorcery.c | 99 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/main/sorcery.c b/main/sorcery.c index a445a6ecadd..ec340e8273c 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -1957,7 +1957,12 @@ static int sorcery_wizard_create(void *obj, void *arg, int flags) ast_debug(5, "Sorcery wizard '%s' does not support creation\n", object_wizard->wizard->callbacks.name); return 0; } - return (!object_wizard->caching && !object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0; + + if (object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) { + return 0; + } + + return CMP_MATCH; } /*! \brief Internal callback function which notifies an individual observer that an object has been created */ @@ -2002,17 +2007,31 @@ int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object) AST_VECTOR_RW_RDLOCK(&object_type->wizards); for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { found_wizard = AST_VECTOR_GET(&object_type->wizards, i); - if (sorcery_wizard_create(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) { + if (!found_wizard->caching && sorcery_wizard_create(found_wizard, &sdetails, 0) == CMP_MATCH) { object_wizard = found_wizard; - if(ao2_container_count(object_type->observers)) { - struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); + } + } - if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) { - ao2_cleanup(invocation); - } + if (object_wizard) { + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + found_wizard = AST_VECTOR_GET(&object_type->wizards, i); + if (found_wizard->caching) { + sorcery_wizard_create(found_wizard, &sdetails, 0); + } + } + + if (ao2_container_count(object_type->observers)) { + struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc( + object_type, object); + + if (invocation + && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, + invocation)) { + ao2_cleanup(invocation); } } } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object_wizard ? 0 : -1; @@ -2052,8 +2071,11 @@ static int sorcery_wizard_update(void *obj, void *arg, int flags) return 0; } - return (!object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) && - !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0; + if (object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj)) { + return 0; + } + + return CMP_MATCH; } int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object) @@ -2075,17 +2097,31 @@ int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object) AST_VECTOR_RW_RDLOCK(&object_type->wizards); for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { found_wizard = AST_VECTOR_GET(&object_type->wizards, i); - if (sorcery_wizard_update(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) { + if (!found_wizard->caching && sorcery_wizard_update(found_wizard, &sdetails, 0) == CMP_MATCH) { object_wizard = found_wizard; - if (ao2_container_count(object_type->observers)) { - struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); + } + } - if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) { - ao2_cleanup(invocation); - } + if (object_wizard) { + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + found_wizard = AST_VECTOR_GET(&object_type->wizards, i); + if (found_wizard->caching) { + sorcery_wizard_update(found_wizard, &sdetails, 0); + } + } + + if (ao2_container_count(object_type->observers)) { + struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc( + object_type, object); + + if (invocation + && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, + invocation)) { + ao2_cleanup(invocation); } } } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object_wizard ? 0 : -1; @@ -2125,8 +2161,11 @@ static int sorcery_wizard_delete(void *obj, void *arg, int flags) return 0; } - return (!object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) && - !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0; + if (object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj)) { + return 0; + } + + return CMP_MATCH; } int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object) @@ -2148,17 +2187,31 @@ int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object) AST_VECTOR_RW_RDLOCK(&object_type->wizards); for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { found_wizard = AST_VECTOR_GET(&object_type->wizards, i); - if (sorcery_wizard_delete(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) { + if (!found_wizard->caching && sorcery_wizard_delete(found_wizard, &sdetails, 0) == CMP_MATCH) { object_wizard = found_wizard; - if (ao2_container_count(object_type->observers)) { - struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object); + } + } - if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) { - ao2_cleanup(invocation); - } + if (object_wizard) { + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + found_wizard = AST_VECTOR_GET(&object_type->wizards, i); + if (found_wizard->caching) { + sorcery_wizard_delete(found_wizard, &sdetails, 0); + } + } + + if (ao2_container_count(object_type->observers)) { + struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc( + object_type, object); + + if (invocation + && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, + invocation)) { + ao2_cleanup(invocation); } } } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); return object_wizard ? 0 : -1; From 128c96456ce0fc794867317c6a47fb41795c33d5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 22 Feb 2016 12:15:34 -0600 Subject: [PATCH 0230/1578] channel.c: Route all control frames to a channel through the same code. Frame hooks can conceivably return a control frame in exchange for an audio frame inside ast_write(). Those returned control frames were not handled quite the same as if they were sent to ast_indicate(). Now it doesn't matter if you use ast_write() to send an AST_FRAME_CONTROL to a channel or ast_indicate(). ASTERISK-25582 Change-Id: I5775f41421aca2b510128198e9b827bf9169629b --- main/channel.c | 121 +++++++++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 53 deletions(-) diff --git a/main/channel.c b/main/channel.c index f5a9afade5a..f9addb01625 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4473,67 +4473,30 @@ static int indicate_redirecting(struct ast_channel *chan, const void *data, size return res ? -1 : 0; } -int ast_indicate_data(struct ast_channel *chan, int _condition, - const void *data, size_t datalen) +static int indicate_data_internal(struct ast_channel *chan, int _condition, const void *data, size_t datalen) { /* By using an enum, we'll get compiler warnings for values not handled * in switch statements. */ enum ast_control_frame_type condition = _condition; struct ast_tone_zone_sound *ts = NULL; int res; - /* this frame is used by framehooks. if it is set, we must free it at the end of this function */ - struct ast_frame *awesome_frame = NULL; - - ast_channel_lock(chan); - - /* Don't bother if the channel is about to go away, anyway. */ - if ((ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) - || (ast_check_hangup(chan) && !ast_channel_is_leaving_bridge(chan))) - && condition != AST_CONTROL_MASQUERADE_NOTIFY) { - res = -1; - goto indicate_cleanup; - } - - if (!ast_framehook_list_is_empty(ast_channel_framehooks(chan))) { - /* Do framehooks now, do it, go, go now */ - struct ast_frame frame = { - .frametype = AST_FRAME_CONTROL, - .subclass.integer = condition, - .data.ptr = (void *) data, /* this cast from const is only okay because we do the ast_frdup below */ - .datalen = datalen - }; - - /* we have now committed to freeing this frame */ - awesome_frame = ast_frdup(&frame); - - /* who knows what we will get back! the anticipation is killing me. */ - if (!(awesome_frame = ast_framehook_list_write_event(ast_channel_framehooks(chan), awesome_frame)) - || awesome_frame->frametype != AST_FRAME_CONTROL) { - res = 0; - goto indicate_cleanup; - } - - condition = awesome_frame->subclass.integer; - data = awesome_frame->data.ptr; - datalen = awesome_frame->datalen; - } switch (condition) { case AST_CONTROL_CONNECTED_LINE: if (indicate_connected_line(chan, data, datalen)) { res = 0; - goto indicate_cleanup; + return res; } break; case AST_CONTROL_REDIRECTING: if (indicate_redirecting(chan, data, datalen)) { res = 0; - goto indicate_cleanup; + return res; } break; case AST_CONTROL_HOLD: case AST_CONTROL_UNHOLD: - ast_channel_hold_state_set(chan, condition); + ast_channel_hold_state_set(chan, _condition); break; default: break; @@ -4541,7 +4504,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, if (is_visible_indication(condition)) { /* A new visible indication is requested. */ - ast_channel_visible_indication_set(chan, condition); + ast_channel_visible_indication_set(chan, _condition); } else if (condition == AST_CONTROL_UNHOLD || _condition < 0) { /* Visible indication is cleared/stopped. */ ast_channel_visible_indication_set(chan, 0); @@ -4549,7 +4512,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, if (ast_channel_tech(chan)->indicate) { /* See if the channel driver can handle this condition. */ - res = ast_channel_tech(chan)->indicate(chan, condition, data, datalen); + res = ast_channel_tech(chan)->indicate(chan, _condition, data, datalen); } else { res = -1; } @@ -4557,7 +4520,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, if (!res) { /* The channel driver successfully handled this indication */ res = 0; - goto indicate_cleanup; + return res; } /* The channel driver does not support this indication, let's fake @@ -4570,7 +4533,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, /* Stop any tones that are playing */ ast_playtones_stop(chan); res = 0; - goto indicate_cleanup; + return res; } /* Handle conditions that we have tones for. */ @@ -4578,7 +4541,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, case _XXX_AST_CONTROL_T38: /* deprecated T.38 control frame */ res = -1; - goto indicate_cleanup; + return res; case AST_CONTROL_T38_PARAMETERS: /* there is no way to provide 'default' behavior for these * control frames, so we need to return failure, but there @@ -4587,7 +4550,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, * so just return right now. in addition, we want to return * whatever value the channel driver returned, in case it * has some meaning.*/ - goto indicate_cleanup; + return res; case AST_CONTROL_RINGING: ts = ast_get_indication_tone(ast_channel_zone(chan), "ring"); /* It is common practice for channel drivers to return -1 if trying @@ -4670,6 +4633,53 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, ast_log(LOG_WARNING, "Unable to handle indication %u for '%s'\n", condition, ast_channel_name(chan)); } + return res; +} + +int ast_indicate_data(struct ast_channel *chan, int _condition, const void *data, size_t datalen) +{ + int res; + /* this frame is used by framehooks. if it is set, we must free it at the end of this function */ + struct ast_frame *awesome_frame = NULL; + + ast_channel_lock(chan); + + /* Don't bother if the channel is about to go away, anyway. */ + if ((ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) + || (ast_check_hangup(chan) && !ast_channel_is_leaving_bridge(chan))) + && _condition != AST_CONTROL_MASQUERADE_NOTIFY) { + res = -1; + goto indicate_cleanup; + } + + if (!ast_framehook_list_is_empty(ast_channel_framehooks(chan))) { + /* Do framehooks now, do it, go, go now */ + struct ast_frame frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = _condition, + .data.ptr = (void *) data, /* this cast from const is only okay because we do the ast_frdup below */ + .datalen = datalen + }; + + /* we have now committed to freeing this frame */ + awesome_frame = ast_frdup(&frame); + + /* who knows what we will get back! the anticipation is killing me. */ + awesome_frame = ast_framehook_list_write_event(ast_channel_framehooks(chan), + awesome_frame); + if (!awesome_frame + || awesome_frame->frametype != AST_FRAME_CONTROL) { + res = 0; + goto indicate_cleanup; + } + + _condition = awesome_frame->subclass.integer; + data = awesome_frame->data.ptr; + datalen = awesome_frame->datalen; + } + + res = indicate_data_internal(chan, _condition, data, datalen); + indicate_cleanup: ast_channel_unlock(chan); if (awesome_frame) { @@ -5012,10 +5022,15 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) res = ast_senddigit_end(chan, fr->subclass.integer, fr->len); ast_channel_lock(chan); CHECK_BLOCKING(chan); - } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_UNHOLD) { - /* This is a side case where Echo is basically being called and the person put themselves on hold and took themselves off hold */ - res = (ast_channel_tech(chan)->indicate == NULL) ? 0 : - ast_channel_tech(chan)->indicate(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); + } else if (fr->frametype == AST_FRAME_CONTROL + && fr->subclass.integer == AST_CONTROL_UNHOLD) { + /* + * This is a side case where Echo is basically being called + * and the person put themselves on hold and took themselves + * off hold. + */ + indicate_data_internal(chan, fr->subclass.integer, fr->data.ptr, + fr->datalen); } res = 0; /* XXX explain, why 0 ? */ goto done; @@ -5027,8 +5042,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) CHECK_BLOCKING(chan); switch (fr->frametype) { case AST_FRAME_CONTROL: - res = (ast_channel_tech(chan)->indicate == NULL) ? 0 : - ast_channel_tech(chan)->indicate(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); + indicate_data_internal(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); + res = 0; break; case AST_FRAME_DTMF_BEGIN: if (ast_channel_audiohooks(chan)) { From 86f7336c91bb3fcd0704143ed93d41275080b2e4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 19 Feb 2016 19:06:14 -0600 Subject: [PATCH 0231/1578] bridge_channel: Don't settle owed events on an optimization. Local channel optimization could cause DTMF digits to be duplicated. Pending DTMF end events would be posted to a bridge when the local channel optimizes out and is replaced by the channel further down the chain. When the real digit ends, the channel would get another DTMF end posted to the bridge. A -- LocalA;1/n -- LocalA;2/n -- LocalB;1 -- LocalB;2 -- B 1) LocalA has the /n flag to prevent optimization. 2) B is sending DTMF to A through the local channel chain. 3) When LocalB optimizes out it can move B to the position of LocalB;1 4) Without this patch, when B swaps with LocalB;1 then LocalB;1 would settle an owed DTMF end to the bridge toward LocalA;2. 5) When B finally ends its DTMF it sends the DTMF end down the chain. 6) Without this patch, A would hear the DTMF digit end when LocalB optimizes out and when B ends the original digit. ASTERISK-25582 Change-Id: I1bbd28b8b399c0fb54985a5747f330a4cd2aa251 --- include/asterisk/bridge_channel_internal.h | 23 ++++++++++++++++++- main/bridge.c | 5 ++--- main/bridge_channel.c | 26 +++++++++++++++++++++- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/include/asterisk/bridge_channel_internal.h b/include/asterisk/bridge_channel_internal.h index e3fb73d7e13..7f7d5a88b14 100644 --- a/include/asterisk/bridge_channel_internal.h +++ b/include/asterisk/bridge_channel_internal.h @@ -84,7 +84,7 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid /*! * \internal - * \brief Clear owed events by the channel to the original bridge. + * \brief Settle owed events by the channel to the original bridge. * \since 12.0.0 * * \param orig_bridge Original bridge the channel was in before leaving. @@ -116,6 +116,27 @@ void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct as */ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel); +/*! + * \internal + * \brief Push the bridge channel into its specified bridge. + * \since 13.8.0 + * + * \param bridge_channel Channel to push. + * \param optimized non-zero if the push with swap is for an optimization. + * + * \note A ref is not held by bridge_channel->swap when calling because the + * push with swap happens immediately. + * + * \note On entry, bridge_channel->bridge is already locked. + * + * \retval 0 on success. + * \retval -1 on failure. The channel did not get pushed. + * + * \note On failure the caller must call + * ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL); + */ +int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel, int optimized); + /*! * \internal * \brief Pull the bridge channel out of its current bridge. diff --git a/main/bridge.c b/main/bridge.c index 7451a163c7e..77865757ea3 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -2185,7 +2185,7 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri bridge_channel_moving(bridge_channel, orig_bridge, dst_bridge); - if (bridge_channel_internal_push(bridge_channel)) { + if (bridge_channel_internal_push_full(bridge_channel, optimized)) { /* Try to put the channel back into the original bridge. */ ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL); @@ -2198,7 +2198,6 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri AST_BRIDGE_HOOK_REMOVE_ON_PULL); ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause); - bridge_channel_settle_owed_events(orig_bridge, bridge_channel); } } else { ast_bridge_channel_leave_bridge(bridge_channel, @@ -2206,7 +2205,7 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri bridge_channel_settle_owed_events(orig_bridge, bridge_channel); } res = -1; - } else { + } else if (!optimized) { bridge_channel_settle_owed_events(orig_bridge, bridge_channel); } diff --git a/main/bridge_channel.c b/main/bridge_channel.c index f3483e4403f..3f141452e50 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -675,6 +675,22 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, return 0; } +/*! + * \internal + * \brief Cancel owed events by the channel to the bridge. + * \since 13.8.0 + * + * \param bridge_channel Channel that owes events to the bridge. + * + * \note On entry, the bridge_channel->bridge is already locked. + * + * \return Nothing + */ +static void bridge_channel_cancel_owed_events(struct ast_bridge_channel *bridge_channel) +{ + bridge_channel->owed.dtmf_digit = '\0'; +} + void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct ast_bridge_channel *bridge_channel) { if (bridge_channel->owed.dtmf_digit) { @@ -2037,7 +2053,7 @@ void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel) ast_bridge_publish_leave(bridge, bridge_channel->chan); } -int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel) +int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel, int optimized) { struct ast_bridge *bridge = bridge_channel->bridge; struct ast_bridge_channel *swap; @@ -2073,6 +2089,9 @@ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel) /* This flag is cleared so the act of this channel leaving does not cause it to dissolve if need be */ ast_clear_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_EMPTY); + if (optimized) { + bridge_channel_cancel_owed_events(swap); + } ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0); bridge_channel_internal_pull(swap); @@ -2112,6 +2131,11 @@ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel) return 0; } +int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel) +{ + return bridge_channel_internal_push_full(bridge_channel, 0); +} + /*! * \internal * \brief Handle bridge channel control frame action. From 0e296563d784b08b83a1e63c9068b5a6fc6135ef Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 19 Feb 2016 16:01:17 -0600 Subject: [PATCH 0232/1578] channel api: Create is_t38_active accessor functions. ASTERISK-25582 Change-Id: I69451920b122de7ee18d15bb231c80ea7067a22b --- include/asterisk/channel.h | 36 ++++++++++++++++++++++++++++++++++++ main/channel_internal_api.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 384c22d5f67..14bd32c0793 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -1595,6 +1595,42 @@ void ast_channel_set_unbridged(struct ast_channel *chan, int value); */ void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value); +/*! + * \brief This function will check if T.38 is active on the channel. + * + * \param chan Channel on which to check the unbridge_eval flag + * + * \return Returns 0 if the flag is down or 1 if the flag is up. + */ +int ast_channel_is_t38_active(struct ast_channel *chan); + +/*! + * \brief ast_channel_is_t38_active variant. Use this if the channel + * is already locked prior to calling. + * + * \param chan Channel on which to check the is_t38_active flag + * + * \return Returns 0 if the flag is down or 1 if the flag is up. + */ +int ast_channel_is_t38_active_nolock(struct ast_channel *chan); + +/*! + * \brief Sets the is_t38_active flag + * + * \param chan Which channel is having its is_t38_active value set + * \param is_t38_active Non-zero if T.38 is active + */ +void ast_channel_set_is_t38_active(struct ast_channel *chan, int is_t38_active); + +/*! + * \brief Variant of ast_channel_set_is_t38_active. Use this if the channel + * is already locked prior to calling. + * + * \param chan Which channel is having its is_t38_active value set + * \param is_t38_active Non-zero if T.38 is active + */ +void ast_channel_set_is_t38_active_nolock(struct ast_channel *chan, int is_t38_active); + /*! * \brief Lock the given channel, then request softhangup on the channel with the given causecode * \param chan channel on which to hang up diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 987602db68b..d94b267e680 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -173,8 +173,6 @@ struct ast_channel { * See \arg \ref AstFileDesc */ int softhangup; /*!< Whether or not we have been hung up... Do not set this value * directly, use ast_softhangup() */ - int unbridged; /*!< If non-zero, the bridge core needs to re-evaluate the current - bridging technology which is in use by this channel's bridge. */ int fdno; /*!< Which fd had an event detected on */ int streamid; /*!< For streaming playback, the schedule ID */ int vstreamid; /*!< For streaming video playback, the schedule ID */ @@ -216,6 +214,9 @@ struct ast_channel { char exten[AST_MAX_EXTENSION]; /*!< Dialplan: Current extension number */ char macrocontext[AST_MAX_CONTEXT]; /*!< Macro: Current non-macro context. See app_macro.c */ char macroexten[AST_MAX_EXTENSION]; /*!< Macro: Current non-macro extension. See app_macro.c */ + char unbridged; /*!< non-zero if the bridge core needs to re-evaluate the current + bridging technology which is in use by this channel's bridge. */ + char is_t38_active; /*!< non-zero if T.38 is active on this channel. */ char dtmf_digit_to_emulate; /*!< Digit being emulated */ char sending_dtmf_digit; /*!< Digit this channel is currently sending out. (zero if not sending) */ struct timeval sending_dtmf_tv; /*!< The time this channel started sending the current digit. (Invalid if sending_dtmf_digit is zero.) */ @@ -1146,7 +1147,7 @@ int ast_channel_unbridged(struct ast_channel *chan) void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value) { - chan->unbridged = value; + chan->unbridged = !!value; ast_queue_frame(chan, &ast_null_frame); } @@ -1157,6 +1158,33 @@ void ast_channel_set_unbridged(struct ast_channel *chan, int value) ast_channel_unlock(chan); } +int ast_channel_is_t38_active_nolock(struct ast_channel *chan) +{ + return chan->is_t38_active; +} + +int ast_channel_is_t38_active(struct ast_channel *chan) +{ + int res; + + ast_channel_lock(chan); + res = ast_channel_is_t38_active_nolock(chan); + ast_channel_unlock(chan); + return res; +} + +void ast_channel_set_is_t38_active_nolock(struct ast_channel *chan, int is_t38_active) +{ + chan->is_t38_active = !!is_t38_active; +} + +void ast_channel_set_is_t38_active(struct ast_channel *chan, int is_t38_active) +{ + ast_channel_lock(chan); + ast_channel_set_is_t38_active_nolock(chan, is_t38_active); + ast_channel_unlock(chan); +} + void ast_channel_callid_cleanup(struct ast_channel *chan) { chan->callid = 0; From c7d45b84f98e5f235d7b33478371dd010dd6973a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 22 Feb 2016 13:54:47 -0600 Subject: [PATCH 0233/1578] bridge core: Add owed T.38 terminate when channel leaves a bridge. The channel is now going to get T.38 terminated when it leaves the bridging system and the bridged peers are going to get T.38 terminated as well. ASTERISK-25582 Change-Id: I77a9205979910210e3068e1ddff400dbf35c4ca7 --- include/asterisk/bridge_channel.h | 2 ++ main/bridge_channel.c | 53 +++++++++++++++++++++++++++++++ main/channel.c | 17 ++++++++++ 3 files changed, 72 insertions(+) diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index 66f9be6e5fa..797be4ebcb1 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -162,6 +162,8 @@ struct ast_bridge_channel { struct timeval dtmf_tv; /*! Digit currently sending into the bridge. (zero if not sending) */ char dtmf_digit; + /*! Non-zero if a T.38 session terminate is owed to the bridge. */ + char t38_terminate; } owed; /*! DTMF hook sequence state */ struct { diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 3f141452e50..81726603356 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -637,6 +637,8 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int caus */ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { + const struct ast_control_t38_parameters *t38_parameters; + ast_assert(frame->frametype != AST_FRAME_BRIDGE_ACTION_SYNC); ast_bridge_channel_lock_bridge(bridge_channel); @@ -663,6 +665,27 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, * We explicitly will not remember HOLD/UNHOLD frames because * things like attended transfers will handle them. */ + switch (frame->subclass.integer) { + case AST_CONTROL_T38_PARAMETERS: + t38_parameters = frame->data.ptr; + switch (t38_parameters->request_response) { + case AST_T38_REQUEST_NEGOTIATE: + case AST_T38_NEGOTIATED: + bridge_channel->owed.t38_terminate = 1; + break; + case AST_T38_REQUEST_TERMINATE: + case AST_T38_TERMINATED: + case AST_T38_REFUSED: + bridge_channel->owed.t38_terminate = 0; + break; + default: + break; + } + break; + default: + break; + } + break; default: break; } @@ -689,6 +712,7 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, static void bridge_channel_cancel_owed_events(struct ast_bridge_channel *bridge_channel) { bridge_channel->owed.dtmf_digit = '\0'; + bridge_channel->owed.t38_terminate = 0; } void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct ast_bridge_channel *bridge_channel) @@ -710,6 +734,23 @@ void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct as bridge_channel->owed.dtmf_digit = '\0'; orig_bridge->technology->write(orig_bridge, NULL, &frame); } + if (bridge_channel->owed.t38_terminate) { + struct ast_control_t38_parameters t38_parameters = { + .request_response = AST_T38_TERMINATED, + }; + struct ast_frame frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_T38_PARAMETERS, + .data.ptr = &t38_parameters, + .datalen = sizeof(t38_parameters), + .src = "Bridge channel owed T.38 terminate", + }; + + ast_debug(1, "T.38 terminate simulated to bridge %s because %s left.\n", + orig_bridge->uniqueid, ast_channel_name(bridge_channel->chan)); + bridge_channel->owed.t38_terminate = 0; + orig_bridge->technology->write(orig_bridge, NULL, &frame); + } } /*! @@ -2736,6 +2777,18 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, ast_channel_sending_dtmf_tv(bridge_channel->chan), "bridge end"); } + /* Complete any T.38 session before exiting the bridge. */ + if (ast_channel_is_t38_active(bridge_channel->chan)) { + struct ast_control_t38_parameters t38_parameters = { + .request_response = AST_T38_TERMINATED, + }; + + ast_debug(1, "Channel %s simulating T.38 terminate for bridge end.\n", + ast_channel_name(bridge_channel->chan)); + ast_indicate_data(bridge_channel->chan, AST_CONTROL_T38_PARAMETERS, + &t38_parameters, sizeof(t38_parameters)); + } + /* Indicate a source change since this channel is leaving the bridge system. */ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE); diff --git a/main/channel.c b/main/channel.c index f9addb01625..852de1aef8f 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4479,6 +4479,7 @@ static int indicate_data_internal(struct ast_channel *chan, int _condition, cons * in switch statements. */ enum ast_control_frame_type condition = _condition; struct ast_tone_zone_sound *ts = NULL; + const struct ast_control_t38_parameters *t38_parameters; int res; switch (condition) { @@ -4498,6 +4499,22 @@ static int indicate_data_internal(struct ast_channel *chan, int _condition, cons case AST_CONTROL_UNHOLD: ast_channel_hold_state_set(chan, _condition); break; + case AST_CONTROL_T38_PARAMETERS: + t38_parameters = data; + switch (t38_parameters->request_response) { + case AST_T38_REQUEST_NEGOTIATE: + case AST_T38_NEGOTIATED: + ast_channel_set_is_t38_active_nolock(chan, 1); + break; + case AST_T38_REQUEST_TERMINATE: + case AST_T38_TERMINATED: + case AST_T38_REFUSED: + ast_channel_set_is_t38_active_nolock(chan, 0); + break; + default: + break; + } + break; default: break; } From bf29a4e2e6f890da71ab6029e7cc0911539b9368 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 18 Feb 2016 18:27:02 -0600 Subject: [PATCH 0234/1578] res_pjsip_t38.c: Back out part of an earlier fix attempt. This backs out item 4 of the 4875e5ac32f5ccad51add6a4216947bfb385245d commit. Item 4 added the t38_bye_supplement. Unfortunately, the frame that it puts into the bridge may or may not be processed by the time the bridged peer is kicked out of the bridge. If it is processed then all is well. However, if it is not processed then that channel is stuck in fax mode until it hangs up or maybe if it joins another bridge for T.38 faxing. ASTERISK-25582 Change-Id: Ib20a03ecadf1bf8a0dcadfadf6c2f2e60919a9f7 --- res/res_pjsip_t38.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 2bb6f03da6f..c02517104b1 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -570,41 +570,6 @@ static struct ast_sip_session_supplement t38_supplement = { .outgoing_request = t38_outgoing_invite_request, }; -static int t38_incoming_bye_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) -{ - struct ast_datastore *datastore; - struct ast_sip_session_media *session_media; - - if (!session->channel) { - return 0; - } - - datastore = ast_sip_session_get_datastore(session, "t38"); - if (!datastore) { - return 0; - } - - session_media = ao2_find(session->media, "image", OBJ_KEY); - if (!session_media) { - ao2_ref(datastore, -1); - return 0; - } - - t38_change_state(session, session_media, datastore->data, T38_REJECTED); - - ao2_ref(datastore, -1); - ao2_ref(session_media, -1); - - return 0; -} - -/*! \brief Supplement for handling a remote termination of T.38 state */ -static struct ast_sip_session_supplement t38_bye_supplement = { - .method = "BYE", - .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1, - .incoming_request = t38_incoming_bye_request, -}; - /*! \brief Parse a T.38 image stream and store the attribute information */ static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream) @@ -935,7 +900,6 @@ static int unload_module(void) { ast_sip_session_unregister_sdp_handler(&image_sdp_handler, "image"); ast_sip_session_unregister_supplement(&t38_supplement); - ast_sip_session_unregister_supplement(&t38_bye_supplement); return 0; } @@ -962,11 +926,6 @@ static int load_module(void) goto end; } - if (ast_sip_session_register_supplement(&t38_bye_supplement)) { - ast_log(LOG_ERROR, "Unable to register T.38 BYE session supplement\n"); - goto end; - } - if (ast_sip_session_register_sdp_handler(&image_sdp_handler, "image")) { ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n"); goto end; From 2dae4a1ccf9790b8601d59e5d7415588ca2eab85 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 22 Feb 2016 16:59:40 -0600 Subject: [PATCH 0235/1578] chan_sip.c: Fix T.38 issues caused by leaving a bridge. chan_sip could not handle AST_T38_TERMINATED frames being sent to it when the channel left the bridge. The action resulted in overlapping outgoing reINVITEs. The testsuite tests/fax/sip/directmedia_reinvite_t38 was not happy. * Force T.38 to be remembered as locally bridged. Now when the channel leaves the native RTP bridge after T.38, the channel remembers that it has already reINVITEed the media back to Asterisk. It just needs to terminate T.38 when the AST_T38_TERMINATED arrives. * Prevent redundant AST_T38_TERMINATED from causing problems. Redundant AST_T38_TERMINATED frames could cause overlapping outgoing reINVITEs if they happen before the T.38 state changes to disabled. Now the T.38 state is set to disabled before the reINVITE is sent. ASTERISK-25582 #close Change-Id: I53f5c6ce7d90b3f322a942af1a9bcab6d967b7ce --- channels/chan_sip.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 6250f4ec484..0b0d114820c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -7522,8 +7522,10 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_ AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); change_t38_state(p, T38_REJECTED); transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); - } else if (p->t38.state == T38_ENABLED) + } else if (p->t38.state == T38_ENABLED) { + change_t38_state(p, T38_DISABLED); transmit_reinvite_with_sdp(p, FALSE, FALSE); + } break; case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */ struct ast_control_t38_parameters parameters = p->t38.their_parms; @@ -10677,6 +10679,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } else if (udptlportno > 0) { if (debug) ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session.\n"); + + /* Force media to go through us for T.38. */ + memset(&p->redirip, 0, sizeof(p->redirip)); + /* Prevent audio RTCP reads */ if (p->owner) { ast_channel_set_fd(p->owner, 1, -1); @@ -13788,6 +13794,29 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old { struct sip_request req; + if (t38version) { + /* Force media to go through us for T.38. */ + memset(&p->redirip, 0, sizeof(p->redirip)); + } + if (p->rtp) { + if (t38version) { + /* Silence RTCP while audio RTP is inactive */ + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 0); + if (p->owner) { + /* Prevent audio RTCP reads */ + ast_channel_set_fd(p->owner, 1, -1); + } + } else if (ast_sockaddr_isnull(&p->redirip)) { + /* Enable RTCP since it will be inactive if we're coming back + * with this reinvite */ + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1); + if (p->owner) { + /* Enable audio RTCP reads */ + ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1)); + } + } + } + reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1); add_header(&req, "Allow", ALLOWED_METHODS); @@ -32780,14 +32809,6 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i } else if (!ast_sockaddr_isnull(&p->redirip)) { memset(&p->redirip, 0, sizeof(p->redirip)); changed = 1; - - if (p->rtp) { - /* Enable RTCP since it will be inactive if we're coming back - * from a reinvite */ - ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1); - /* Enable audio RTCP reads */ - ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(p->rtp, 1)); - } } if (vinstance) { From 3173e91bab9edca6b1d6eba499aefa18edb3d993 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 18 Jan 2016 20:54:28 -0700 Subject: [PATCH 0236/1578] build-system: Allow building with static pjproject Background here: http://lists.digium.com/pipermail/asterisk-dev/2016-January/075266.html From CHANGES: * To help insure that Asterisk is compiled and run with the same known version of pjproject, a new option (--with-pjproject-bundled) has been added to ./configure. When specified, the version of pjproject specified in third-party/versions.mak will be downloaded and configured. When you make Asterisk, the build process will also automatically build pjproject and Asterisk will be statically linked to it. Once a particular version of pjproject is configured and built, it won't be configured or built again unless you run a 'make distclean'. To facilitate testing, when 'make install' is run, the pjsua and pjsystest utilities and the pjproject python bindings will be installed in ASTDATADIR/third-party/pjproject. The default behavior remains building with the shared pjproject installation, if any. Building: All you have to do is include the --with-pjproject-bundled option on the ./configure command line (and remove any existing --with-pjproject option if specified). Everything else is automatic. Behind the scenes: The top-level Makefile was modified to include 'third-party' in the list of MOD_SUBDIRS. The third-party directory was created to contain any third party packages that may be needed in the future. Its Makefile automatically iterates over any subdirectories passing on targets. The third-party/pjproject directory was created to house the pjproject source distribution. Its Makefile contains targets to download, patch configure, generate dependencies, compile libs, apps and python bindings, sanitized build.mak and generate a symbols list. When bootstrap.sh is run, it automatically includes the configure.m4 file in third-party/pjproject. This file has a macro to download and conifgure pjproject and get and set PJPROJECT_INCLUDE, PJPROJECT_DIR and PJPROJECT_BUNDLED. It also tests for the capabilities like PJ_TRANSACTION_GRP_LOCK by parsing preprocessor output as opposed to trying to compile. Of course, bootstrap.sh is only run once and the configure file is incldued in the patch. When configure is run with the new options, the macro in configure.m4 triggers the download, patch, conifgure and tests. No compilation is performed at this time. The downloaded tarball is cached in /tmp so it doesn't get downloaded again on a distclean. When make is run in the top-level Asterisk source directory, it will automatically descend all the subdirectories in third_party just as it does for addons, apps, etc. The top-level Makefile makes sure that the 'third-party' is built before 'main' so that dependencies from the other directories are built first. When main does build, a new shared library (libasteriskpj) is created that links statically to the pjproject .a files and exports all their symbols. The asterisk binary links to that, just as it does with libasteriskssl. When Asterisk is installed, the pjsua and pjsystest apps, and the pjproject python bindings are installed in ASTDATADIR/third-party/pjproject. This will facilitate testing, including running the testsuite which will be updated to check that directory for the pjsua module ahead of the system python library. Modules should continue to depend on pjproject if they use pjproject APIs directly. They should not care about the implementation. No changes to any res_pjsip modules were made. Change-Id: Ia7a60c28c2e9ba9537c5570f933c1ebcb20a3103 --- CHANGES | 18 + Makefile | 13 +- configure | 349 ++++++++++++++++-- configure.ac | 70 +++- include/asterisk/_private.h | 1 + include/asterisk/autoconfig.h.in | 21 +- main/.gitignore | 2 + main/Makefile | 121 +++++- main/asterisk.c | 5 + main/libasteriskpj.c | 52 +++ makeopts.in | 2 + third-party/Makefile | 21 ++ third-party/Makefile.rules | 37 ++ third-party/pjproject/.gitignore | 4 + third-party/pjproject/Makefile | 110 ++++++ third-party/pjproject/Makefile.rules | 7 + third-party/pjproject/apply_patches | 39 ++ third-party/pjproject/configure.m4 | 46 +++ .../0001-2.4.5-fix-for-tls-async-ops.patch | 224 +++++++++++ ...d-transaction-log-levels-from-1-to-3.patch | 70 ++++ ...oqueue-Enable-epoll-in-aconfigure.ac.patch | 80 ++++ ...arch-for-transport-even-if-listener-.patch | 114 ++++++ third-party/pjproject/patches/config_site.h | 34 ++ third-party/pjproject/patches/user.mak | 2 + third-party/versions.mak | 2 + 25 files changed, 1359 insertions(+), 85 deletions(-) create mode 100644 main/libasteriskpj.c create mode 100644 third-party/Makefile create mode 100644 third-party/Makefile.rules create mode 100644 third-party/pjproject/.gitignore create mode 100644 third-party/pjproject/Makefile create mode 100644 third-party/pjproject/Makefile.rules create mode 100755 third-party/pjproject/apply_patches create mode 100644 third-party/pjproject/configure.m4 create mode 100644 third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch create mode 100644 third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch create mode 100644 third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch create mode 100644 third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch create mode 100644 third-party/pjproject/patches/config_site.h create mode 100644 third-party/pjproject/patches/user.mak create mode 100644 third-party/versions.mak diff --git a/CHANGES b/CHANGES index 91e170ffbb2..aaaf3f5d1a2 100644 --- a/CHANGES +++ b/CHANGES @@ -221,6 +221,24 @@ res_pjsip_config_wizard will export all the pjsip objects it created to the console or a file suitable for reuse in a pjsip.conf file. +Build System +------------------ + * To help insure that Asterisk is compiled and run with the same known + version of pjproject, a new option (--with-pjproject-bundled) has been + added to ./configure. When specified, the version of pjproject specified + in third-party/versions.mak will be downloaded and configured. When you + make Asterisk, the build process will also automatically build pjproject + and Asterisk will be statically linked to it. Once a particular version + of pjproject is configured and built, it won't be configured or built + again unless you run a 'make distclean'. + + To facilitate testing, when 'make install' is run, the pjsua and pjsystest + utilities and the pjproject python bindings will be installed in + ASTDATADIR/third-party/pjproject. + + The default behavior remains building with the shared pjproject + installation, if any. + app_confbridge ------------------ * Added CONFBRIDGE_INFO(muted,) for querying the muted conference state. diff --git a/Makefile b/Makefile index a07a3299b17..7528f83749e 100644 --- a/Makefile +++ b/Makefile @@ -249,7 +249,7 @@ endif _ASTCFLAGS+=$(OPTIONS) -MOD_SUBDIRS:=channels pbx apps codecs formats cdr cel bridges funcs tests main res addons $(LOCAL_MOD_SUBDIRS) +MOD_SUBDIRS:=third-party channels pbx apps codecs formats cdr cel bridges funcs tests main res addons $(LOCAL_MOD_SUBDIRS) OTHER_SUBDIRS:=utils agi contrib SUBDIRS:=$(OTHER_SUBDIRS) $(MOD_SUBDIRS) SUBDIRS_INSTALL:=$(SUBDIRS:%=%-install) @@ -377,8 +377,10 @@ ifeq ($(findstring $(OSARCH), mingw32 cygwin ),) # directories containing them must be completed before the main Asterisk # binary can be built. # If MENUSELECT_EMBED is empty, we don't need this and allow 'main' to be - # be built without building all dependencies first. + # be built with only third_party first. main: $(filter-out main,$(MOD_SUBDIRS)) + else +main: third-party endif else # Windows: we need to build main (i.e. the asterisk dll) first, @@ -568,7 +570,8 @@ INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTETCDIR)" "$(ASTV "$(ASTDATADIR)/documentation/thirdparty" "$(ASTDATADIR)/firmware" \ "$(ASTDATADIR)/firmware/iax" "$(ASTDATADIR)/images" "$(ASTDATADIR)/keys" \ "$(ASTDATADIR)/phoneprov" "$(ASTDATADIR)/rest-api" "$(ASTDATADIR)/static-http" \ - "$(ASTDATADIR)/sounds" "$(ASTDATADIR)/moh" "$(ASTMANDIR)/man8" "$(AGI_DIR)" "$(ASTDBDIR)" + "$(ASTDATADIR)/sounds" "$(ASTDATADIR)/moh" "$(ASTMANDIR)/man8" "$(AGI_DIR)" "$(ASTDBDIR)" \ + "$(ASTDATADIR)/third-party" installdirs: @for i in $(INSTALLDIRS); do \ @@ -611,7 +614,7 @@ ifeq ($(HAVE_DAHDI),1) endif $(SUBDIRS_INSTALL): - +@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" $(SUBMAKE) -C $(@:-install=) install + +@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" ASTDATADIR="$(ASTDATADIR)" $(SUBMAKE) -C $(@:-install=) install NEWMODS:=$(foreach d,$(MOD_SUBDIRS),$(notdir $(wildcard $(d)/*.so))) OLDMODS=$(filter-out $(NEWMODS) $(notdir $(DESTDIR)$(ASTMODDIR)),$(notdir $(wildcard $(DESTDIR)$(ASTMODDIR)/*.so))) @@ -889,7 +892,7 @@ sounds: @[ -f "$(DESTDIR)$(ASTDBDIR)/astdb.sqlite3" ] || [ ! -f "$(DESTDIR)$(ASTDBDIR)/astdb" ] || [ ! -f menuselect.makeopts ] || grep -q MENUSELECT_UTILS=.*astdb2sqlite3 menuselect.makeopts || (sed -i.orig -e's/MENUSELECT_UTILS=\(.*\)/MENUSELECT_UTILS=\1 astdb2sqlite3/' menuselect.makeopts && echo "Updating menuselect.makeopts to include astdb2sqlite3" && echo "Original version backed up to menuselect.makeopts.orig") $(SUBDIRS_UNINSTALL): - +@$(SUBMAKE) -C $(@:-uninstall=) uninstall + +@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" ASTDATADIR="$(ASTDATADIR)" $(SUBMAKE) -C $(@:-uninstall=) uninstall main-binuninstall: +@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" ASTLIBDIR="$(ASTLIBDIR)" $(SUBMAKE) -C main binuninstall diff --git a/configure b/configure index 2c0f99d4f36..3967cec633c 100755 --- a/configure +++ b/configure @@ -915,6 +915,10 @@ PBX_PORTAUDIO PORTAUDIO_DIR PORTAUDIO_INCLUDE PORTAUDIO_LIB +PBX_POPT +POPT_DIR +POPT_INCLUDE +POPT_LIB PBX_PJSIP_EXTERNAL_RESOLVER PJSIP_EXTERNAL_RESOLVER_DIR PJSIP_EXTERNAL_RESOLVER_INCLUDE @@ -939,10 +943,7 @@ PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB -PBX_POPT -POPT_DIR -POPT_INCLUDE -POPT_LIB +PJPROJECT_BUNDLED PBX_PJPROJECT PJPROJECT_DIR PJPROJECT_INCLUDE @@ -1362,6 +1363,7 @@ with_osptk with_oss with_postgres with_pjproject +with_pjproject_bundled with_popt with_portaudio with_pri @@ -2101,6 +2103,8 @@ Optional Packages: --with-oss=PATH use Open Sound System files in PATH --with-postgres=PATH use PostgreSQL files in PATH --with-pjproject=PATH use PJPROJECT files in PATH + --with-pjproject-bundled + Use bundled pjproject libraries --with-popt=PATH use popt files in PATH --with-portaudio=PATH use PortAudio files in PATH --with-pri=PATH use ISDN PRI files in PATH @@ -10415,6 +10419,7 @@ fi + PJPROJECT_DESCRIP="PJPROJECT" PJPROJECT_OPTION="pjproject" PBX_PJPROJECT=0 @@ -10446,37 +10451,28 @@ fi +PJPROJECT_BUNDLED=no - POPT_DESCRIP="popt" - POPT_OPTION="popt" - PBX_POPT=0 -# Check whether --with-popt was given. -if test "${with_popt+set}" = set; then : - withval=$with_popt; - case ${withval} in - n|no) - USE_POPT=no - # -1 is a magic value used by menuselect to know that the package - # was disabled, other than 'not found' - PBX_POPT=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} POPT" - ;; - *) - POPT_DIR="${withval}" - ac_mandatory_list="${ac_mandatory_list} POPT" - ;; - esac +# Check whether --with-pjproject-bundled was given. +if test "${with_pjproject_bundled+set}" = set; then : + withval=$with_pjproject_bundled; case "${enableval}" in + n|no) PJPROJECT_BUNDLED=no ;; + *) PJPROJECT_BUNDLED=yes ;; + esac fi +if test "$PJPROJECT_BUNDLED" = "yes" -a "${ac_mandatory_list#*PJPROJECT*}" != "$ac_mandatory_list" ; then + as_fn_error $? "--with-pjproject and --with-pjproject-bundled can't both be specified" "$LINENO" 5 +fi - - +if test "$PJPROJECT_BUNDLED" = "yes" ; then + ac_mandatory_list="$ac_mandatory_list PJPROJECT" + PJPROJECT_DIR="${ac_top_build_prefix}third-party/pjproject" +fi PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DESCRIP="PJSIP Dialog Create UAS with Incremented Lock" @@ -10551,6 +10547,39 @@ PBX_PJSIP_EXTERNAL_RESOLVER=0 + + POPT_DESCRIP="popt" + POPT_OPTION="popt" + PBX_POPT=0 + +# Check whether --with-popt was given. +if test "${with_popt+set}" = set; then : + withval=$with_popt; + case ${withval} in + n|no) + USE_POPT=no + # -1 is a magic value used by menuselect to know that the package + # was disabled, other than 'not found' + PBX_POPT=-1 + ;; + y|ye|yes) + ac_mandatory_list="${ac_mandatory_list} POPT" + ;; + *) + POPT_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} POPT" + ;; + esac + +fi + + + + + + + + PORTAUDIO_DESCRIP="PortAudio" PORTAUDIO_OPTION="portaudio" PBX_PORTAUDIO=0 @@ -24441,6 +24470,244 @@ $as_echo "$as_me: *** including --without-postgres" >&6;} fi fi +if test "$USE_PJPROJECT" != "no" ; then + if test "$PJPROJECT_BUNDLED" = "yes" ; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for embedded pjproject (may have to download)" >&5 +$as_echo_n "checking for embedded pjproject (may have to download)... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: configuring" >&5 +$as_echo "configuring" >&6; } + make --quiet --no-print-directory -C $PJPROJECT_DIR configure + if test $? -ne 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: Unable to configure $PJPROJECT_DIR" >&5 +$as_echo "$as_me: Unable to configure $PJPROJECT_DIR" >&6;} + as_fn_error $? "Run \"make -C $PJPROJECT_DIR NOISY_BUILD=yes configure\" to see error details." "$LINENO" 5 + fi + + PJPROJECT_INCLUDE=$(make --quiet --no-print-directory -C $PJPROJECT_DIR echo_cflags) + PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" + PBX_PJPROJECT=1 + PJPROJECT_BUNDLED=yes + +$as_echo "#define HAVE_PJPROJECT 1" >>confdefs.h + + +$as_echo "#define HAVE_PJPROJECT_BUNDLED 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for embedded pjproject" >&5 +$as_echo_n "checking for embedded pjproject... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE="$PJPROJECT_INCLUDE" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_dlg_create_uas_and_inc_lock declared in pjsip.h" >&5 +$as_echo_n "checking for pjsip_dlg_create_uas_and_inc_lock declared in pjsip.h... " >&6; } + + saved_cpp="$CPPFLAGS" + CPPFLAGS="$PJPROJECT_INCLUDE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "pjsip_dlg_create_uas_and_inc_lock" >/dev/null 2>&1; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK=1 + +$as_echo "#define HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK 1" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f conftest* + + + CPPGLAGS="$saved_cpp" + PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE="$PJPROJECT_INCLUDE" + + + PJ_TRANSACTION_GRP_LOCK_INCLUDE="$PJPROJECT_INCLUDE" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_tsx_create_uac2 declared in pjsip.h" >&5 +$as_echo_n "checking for pjsip_tsx_create_uac2 declared in pjsip.h... " >&6; } + + saved_cpp="$CPPFLAGS" + CPPFLAGS="$PJPROJECT_INCLUDE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "pjsip_tsx_create_uac2" >/dev/null 2>&1; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_PJ_TRANSACTION_GRP_LOCK=1 + +$as_echo "#define HAVE_PJ_TRANSACTION_GRP_LOCK 1" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f conftest* + + + CPPGLAGS="$saved_cpp" + PJ_TRANSACTION_GRP_LOCK_INCLUDE="$PJPROJECT_INCLUDE" + + + PJSIP_REPLACE_MEDIA_STREAM_INCLUDE="$PJPROJECT_INCLUDE" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE declared in pjmedia.h" >&5 +$as_echo_n "checking for PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE declared in pjmedia.h... " >&6; } + + saved_cpp="$CPPFLAGS" + CPPFLAGS="$PJPROJECT_INCLUDE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE" >/dev/null 2>&1; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_PJSIP_REPLACE_MEDIA_STREAM=1 + +$as_echo "#define HAVE_PJSIP_REPLACE_MEDIA_STREAM 1" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f conftest* + + + CPPGLAGS="$saved_cpp" + PJSIP_REPLACE_MEDIA_STREAM_INCLUDE="$PJPROJECT_INCLUDE" + + + PJSIP_GET_DEST_INFO_INCLUDE="$PJPROJECT_INCLUDE" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_get_dest_info declared in pjsip.h" >&5 +$as_echo_n "checking for pjsip_get_dest_info declared in pjsip.h... " >&6; } + + saved_cpp="$CPPFLAGS" + CPPFLAGS="$PJPROJECT_INCLUDE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "pjsip_get_dest_info" >/dev/null 2>&1; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_PJSIP_GET_DEST_INFO=1 + +$as_echo "#define HAVE_PJSIP_GET_DEST_INFO 1" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f conftest* + + + CPPGLAGS="$saved_cpp" + PJSIP_GET_DEST_INFO_INCLUDE="$PJPROJECT_INCLUDE" + + + PJ_SSL_CERT_LOAD_FROM_FILES2_INCLUDE="$PJPROJECT_INCLUDE" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pj_ssl_cert_load_from_files2 declared in pjlib.h" >&5 +$as_echo_n "checking for pj_ssl_cert_load_from_files2 declared in pjlib.h... " >&6; } + + saved_cpp="$CPPFLAGS" + CPPFLAGS="$PJPROJECT_INCLUDE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "pj_ssl_cert_load_from_files2" >/dev/null 2>&1; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_PJ_SSL_CERT_LOAD_FROM_FILES2=1 + +$as_echo "#define HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 1" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f conftest* + + + CPPGLAGS="$saved_cpp" + PJ_SSL_CERT_LOAD_FROM_FILES2_INCLUDE="$PJPROJECT_INCLUDE" + + + PJSIP_EXTERNAL_RESOLVER_INCLUDE="$PJPROJECT_INCLUDE" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_endpt_set_ext_resolver declared in pjsip.h" >&5 +$as_echo_n "checking for pjsip_endpt_set_ext_resolver declared in pjsip.h... " >&6; } + + saved_cpp="$CPPFLAGS" + CPPFLAGS="$PJPROJECT_INCLUDE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "pjsip_endpt_set_ext_resolver" >/dev/null 2>&1; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_PJSIP_EXTERNAL_RESOLVER=1 + +$as_echo "#define HAVE_PJSIP_EXTERNAL_RESOLVER 1" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f conftest* + + + CPPGLAGS="$saved_cpp" + PJSIP_EXTERNAL_RESOLVER_INCLUDE="$PJPROJECT_INCLUDE" + + + else if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then @@ -24658,7 +24925,7 @@ if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIBS $LIBS" +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24700,7 +24967,7 @@ fi # now check for the header. if test "${AST_PJ_TRANSACTION_GRP_LOCK_FOUND}" = "yes"; then - PJ_TRANSACTION_GRP_LOCK_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIBS" + PJ_TRANSACTION_GRP_LOCK_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB" # if --with-PJ_TRANSACTION_GRP_LOCK=DIR has been specified, use it. if test "x${PJ_TRANSACTION_GRP_LOCK_DIR}" != "x"; then PJ_TRANSACTION_GRP_LOCK_INCLUDE="-I${PJ_TRANSACTION_GRP_LOCK_DIR}/include" @@ -24739,10 +25006,10 @@ fi -saved_cppflags="${CPPFLAGS}" -saved_libs="${LIBS}" -CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}" -LIBS="${LIBS} ${PJPROJECT_LIBS}" + saved_cppflags="${CPPFLAGS}" + saved_libs="${LIBS}" + CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}" + LIBS="${LIBS} ${PJPROJECT_LIB}" if test "x${PBX_PJSIP_REPLACE_MEDIA_STREAM}" != "x1" -a "${USE_PJSIP_REPLACE_MEDIA_STREAM}" != "no"; then if test "x" != "x"; then @@ -24788,8 +25055,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CPPFLAGS="${saved_cppflags}" fi -LIBS="${saved_libs}" -CPPFLAGS="${saved_cppflags}" + LIBS="${saved_libs}" + CPPFLAGS="${saved_cppflags}" if test "x${PBX_PJSIP_GET_DEST_INFO}" != "x1" -a "${USE_PJSIP_GET_DEST_INFO}" != "no"; then @@ -24815,7 +25082,7 @@ if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIBS $LIBS" +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24857,7 +25124,7 @@ fi # now check for the header. if test "${AST_PJSIP_GET_DEST_INFO_FOUND}" = "yes"; then - PJSIP_GET_DEST_INFO_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIBS" + PJSIP_GET_DEST_INFO_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB" # if --with-PJSIP_GET_DEST_INFO=DIR has been specified, use it. if test "x${PJSIP_GET_DEST_INFO_DIR}" != "x"; then PJSIP_GET_DEST_INFO_INCLUDE="-I${PJSIP_GET_DEST_INFO_DIR}/include" @@ -24906,7 +25173,7 @@ if test "x${PBX_PJ_SSL_CERT_LOAD_FROM_FILES2}" != "x1" -a "${USE_PJ_SSL_CERT_LOA pbxlibdir="-L${PJ_SSL_CERT_LOAD_FROM_FILES2_DIR}" fi fi - pbxfuncname="pj_ssl_cert_load_from_files2" + pbxfuncname="pjsip/include/pjsip/sip_util.h" if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers AST_PJ_SSL_CERT_LOAD_FROM_FILES2_FOUND=yes else @@ -24919,7 +25186,7 @@ if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lpj ${pbxlibdir} $PJPROJECT_LIBS $LIBS" +LIBS="-lpj ${pbxlibdir} $PJPROJECT_LIB $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24961,7 +25228,7 @@ fi # now check for the header. if test "${AST_PJ_SSL_CERT_LOAD_FROM_FILES2_FOUND}" = "yes"; then - PJ_SSL_CERT_LOAD_FROM_FILES2_LIB="${pbxlibdir} -lpj $PJPROJECT_LIBS" + PJ_SSL_CERT_LOAD_FROM_FILES2_LIB="${pbxlibdir} -lpj $PJPROJECT_LIB" # if --with-PJ_SSL_CERT_LOAD_FROM_FILES2=DIR has been specified, use it. if test "x${PJ_SSL_CERT_LOAD_FROM_FILES2_DIR}" != "x"; then PJ_SSL_CERT_LOAD_FROM_FILES2_INCLUDE="-I${PJ_SSL_CERT_LOAD_FROM_FILES2_DIR}/include" @@ -25103,6 +25370,8 @@ _ACEOF fi + fi +fi if test "x${PBX_POPT}" != "x1" -a "${USE_POPT}" != "no"; then diff --git a/configure.ac b/configure.ac index 1ca5eb3dbb7..12cc8d276c8 100644 --- a/configure.ac +++ b/configure.ac @@ -453,14 +453,37 @@ AST_EXT_LIB_SETUP([OPUS], [Opus], [opus]) AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk]) AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss]) AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres]) + AST_EXT_LIB_SETUP([PJPROJECT], [PJPROJECT], [pjproject]) -AST_EXT_LIB_SETUP([POPT], [popt], [popt]) +PJPROJECT_BUNDLED=no +AH_TEMPLATE(m4_bpatsubst([[HAVE_PJPROJECT_BUNDLED]], [(.*)]), [Define to 1 when using the bundled pjproject.]) + +AC_ARG_WITH([pjproject-bundled], + [AS_HELP_STRING([--with-pjproject-bundled], + [Use bundled pjproject libraries])], + [case "${enableval}" in + n|no) PJPROJECT_BUNDLED=no ;; + *) PJPROJECT_BUNDLED=yes ;; + esac]) +AC_SUBST(PJPROJECT_BUNDLED) + +if test "$PJPROJECT_BUNDLED" = "yes" -a "${ac_mandatory_list#*PJPROJECT*}" != "$ac_mandatory_list" ; then + AC_MSG_ERROR(--with-pjproject and --with-pjproject-bundled can't both be specified) +fi + +if test "$PJPROJECT_BUNDLED" = "yes" ; then + ac_mandatory_list="$ac_mandatory_list PJPROJECT" + PJPROJECT_DIR="${ac_top_build_prefix}third-party/pjproject" +fi + AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [PJSIP Dialog Create UAS with Incremented Lock], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJ_TRANSACTION_GRP_LOCK], [PJSIP Transaction Group Lock Support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_REPLACE_MEDIA_STREAM], [PJSIP Media Stream Replacement Support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_GET_DEST_INFO], [pjsip_get_dest_info support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_from_files2 support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EXTERNAL_RESOLVER], [PJSIP External Resolver Support], [PJPROJECT], [pjsip]) + +AST_EXT_LIB_SETUP([POPT], [popt], [popt]) AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio]) AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri]) AST_EXT_LIB_SETUP_OPTIONAL([PRI_SETUP_ACK_INBAND], [ISDN PRI progress inband ie in SETUP ACK], [PRI], [pri]) @@ -2152,22 +2175,29 @@ if test "${PG_CONFIG}" != No; then fi fi -AST_PKG_CONFIG_CHECK([PJPROJECT], [libpjproject]) - -AST_EXT_LIB_CHECK([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [pjsip], [pjsip_dlg_create_uas_and_inc_lock], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) -AST_EXT_LIB_CHECK([PJ_TRANSACTION_GRP_LOCK], [pjsip], [pjsip_tsx_create_uac2], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) - -saved_cppflags="${CPPFLAGS}" -saved_libs="${LIBS}" -CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}" -LIBS="${LIBS} ${PJPROJECT_LIBS}" -AST_C_COMPILE_CHECK([PJSIP_REPLACE_MEDIA_STREAM], [pjmedia_mod_offer_flag flag = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE], [pjmedia.h]) -LIBS="${saved_libs}" -CPPFLAGS="${saved_cppflags}" - -AST_EXT_LIB_CHECK([PJSIP_GET_DEST_INFO], [pjsip], [pjsip_get_dest_info], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) -AST_EXT_LIB_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj], [pj_ssl_cert_load_from_files2], [pjlib.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) -AST_EXT_LIB_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip], [pjsip_endpt_set_ext_resolver], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) +if test "$USE_PJPROJECT" != "no" ; then + if test "$PJPROJECT_BUNDLED" = "yes" ; then + AC_CONFIG_MACRO_DIR(third-party/pjproject) + PJPROJECT_CONFIGURE([$PJPROJECT_DIR]) + else + AST_PKG_CONFIG_CHECK([PJPROJECT], [libpjproject]) + + AST_EXT_LIB_CHECK([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [pjsip], [pjsip_dlg_create_uas_and_inc_lock], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJ_TRANSACTION_GRP_LOCK], [pjsip], [pjsip_tsx_create_uac2], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + + saved_cppflags="${CPPFLAGS}" + saved_libs="${LIBS}" + CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}" + LIBS="${LIBS} ${PJPROJECT_LIB}" + AST_C_COMPILE_CHECK([PJSIP_REPLACE_MEDIA_STREAM], [pjmedia_mod_offer_flag flag = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE], [pjmedia.h]) + LIBS="${saved_libs}" + CPPFLAGS="${saved_cppflags}" + + AST_EXT_LIB_CHECK([PJSIP_GET_DEST_INFO], [pjsip], [pjsip_get_dest_info], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj], [pjsip/include/pjsip/sip_util.h], [pjlib.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip], [pjsip_endpt_set_ext_resolver], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) + fi +fi AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h]) @@ -2331,11 +2361,11 @@ AC_CHECK_FUNC([crypt], [SYSCRYPT=true], [SYSCRYPT=""]) if test "x$LIBCRYPT_LIB" != "x" ; then CRYPT_LIB="$LIBCRYPT_LIB" CRYPT_INCLUDE="$LIBCRYPT_INCLUDE" - AC_DEFINE([HAVE_CRYPT], [1], [Define to 1 if you have the `crypt' function.]) + AC_DEFINE([HAVE_CRYPT], [1], [Define to 1 if you have the 'crypt' function.]) elif test "x$SYSCRYPT" != "x" ; then CRYPT_LIB="" CRYPT_INCLUDE="" - AC_DEFINE([HAVE_CRYPT], [1], [Define to 1 if you have the `crypt' function.]) + AC_DEFINE([HAVE_CRYPT], [1], [Define to 1 if you have the 'crypt' function.]) fi AC_SUBST(CRYPT_LIB) @@ -2343,7 +2373,7 @@ AC_SUBST(CRYPT_INCLUDE) # Find crypt_r support AC_CHECK_LIB([crypt], [crypt_r], - [AC_DEFINE([HAVE_CRYPT_R], [1], [Define to 1 if you have the `crypt_r' function.])]) + [AC_DEFINE([HAVE_CRYPT_R], [1], [Define to 1 if you have the 'crypt_r' function.])]) AST_EXT_LIB_CHECK([CRYPTO], [crypto], [AES_encrypt], [openssl/aes.h]) diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 7963f3121ab..a4a4f1bea4b 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -53,6 +53,7 @@ void ast_stun_init(void); /*!< Provided by stun.c */ int ast_cel_engine_init(void); /*!< Provided by cel.c */ int ast_cel_engine_reload(void); /*!< Provided by cel.c */ int ast_ssl_init(void); /*!< Provided by ssl.c */ +int ast_pj_init(void); /*!< Provided by libasteriskpj.c */ int ast_test_init(void); /*!< Provided by test.c */ int ast_msg_init(void); /*!< Provided by message.c */ void ast_msg_shutdown(void); /*!< Provided by message.c */ diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 6ed96ccb5f3..43f86b08841 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -154,13 +154,13 @@ /* Define to 1 if you have the `cosl' function. */ #undef HAVE_COSL -/* Define to 1 if you have the `crypt' function. */ +/* Define to 1 if you have the 'crypt' function. */ #undef HAVE_CRYPT /* Define to 1 if you have the OpenSSL Cryptography library. */ #undef HAVE_CRYPTO -/* Define to 1 if you have the `crypt_r' function. */ +/* Define to 1 if you have the 'crypt_r' function. */ #undef HAVE_CRYPT_R /* Define to 1 if you have a functional curl library. */ @@ -580,26 +580,25 @@ /* Define if your system has the PJPROJECT libraries. */ #undef HAVE_PJPROJECT -/* Define to 1 if PJPROJECT has the PJSIP Dialog Create UAS with Incremented - Lock feature. */ +/* Define if your system has PJPROJECT_BUNDLED */ +#undef HAVE_PJPROJECT_BUNDLED + +/* Define if your system has pjsip_dlg_create_uas_and_inc_lock declared. */ #undef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK -/* Define to 1 if PJPROJECT has the PJSIP External Resolver Support feature. - */ +/* Define if your system has pjsip_endpt_set_ext_resolver declared. */ #undef HAVE_PJSIP_EXTERNAL_RESOLVER -/* Define to 1 if PJPROJECT has the pjsip_get_dest_info support feature. */ +/* Define if your system has pjsip_get_dest_info declared. */ #undef HAVE_PJSIP_GET_DEST_INFO /* Define if your system has the PJSIP_REPLACE_MEDIA_STREAM headers. */ #undef HAVE_PJSIP_REPLACE_MEDIA_STREAM -/* Define to 1 if PJPROJECT has the pj_ssl_cert_load_from_files2 support - feature. */ +/* Define if your system has pj_ssl_cert_load_from_files2 declared. */ #undef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 -/* Define to 1 if PJPROJECT has the PJSIP Transaction Group Lock Support - feature. */ +/* Define if your system has pjsip_tsx_create_uac2 declared. */ #undef HAVE_PJ_TRANSACTION_GRP_LOCK /* Define to 1 if your system defines IP_PKTINFO. */ diff --git a/main/.gitignore b/main/.gitignore index 3ff4656798b..cb90a5e3b2d 100644 --- a/main/.gitignore +++ b/main/.gitignore @@ -1,4 +1,6 @@ asterisk libasteriskssl.so.1 libasteriskssl.dylib +libasteriskpj.so.2 +libasteriskpj.dylib version.c diff --git a/main/Makefile b/main/Makefile index b25fb450ac2..50fdc5739eb 100644 --- a/main/Makefile +++ b/main/Makefile @@ -22,6 +22,9 @@ SRC:=$(wildcard *.c) ast_expr2.c ast_expr2f.c ifeq ($(AST_ASTERISKSSL),yes) SRC:=$(filter-out libasteriskssl.c,$(SRC)) endif +ifeq ($(PJPROJECT_BUNDLED),yes) +SRC:=$(filter-out libasteriskpj.c,$(SRC)) +endif OBJSFILTER=fskmodem_int.o fskmodem_float.o cygload.o buildinfo.o OBJS=$(filter-out $(OBJSFILTER),$(SRC:.c=.o)) @@ -201,7 +204,7 @@ ASTSSL_LDLIBS=-L. -lasteriskssl ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin ASTSSL_LIB:=libasteriskssl.so -$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTSSL_LIB).$(ASTSSL_SO_VERSION) +$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTSSL_LIB) $(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskssl\" -DAST_NOT_MODULE $(ASTSSL_LIB).$(ASTSSL_SO_VERSION): LIBS+=$(ASTSSL_LIBS) ifeq ($(GNU_LD),1) @@ -219,12 +222,14 @@ ifeq ($(GNU_LD),1) endif $(ECHO_PREFIX) echo " [LD] $^ -> $@" $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(CC_LDFLAGS_SO) $^ $(CC_LIBS) -ifneq ($(LDCONFIG),) - $(LDCONFIG) $(LDCONFIG_FLAGS) . -endif $(ASTSSL_LIB): $(ASTSSL_LIB).$(ASTSSL_SO_VERSION) - $(LN) -sf $< $@ + $(ECHO_PREFIX) echo " [LN] $< -> $@" +ifneq ($(LDCONFIG),) + $(CMD_PREFIX) $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null +else + $(CMD_PREFIX) $(LN) -sf $< $@ +endif else # Darwin ASTSSL_LIB:=libasteriskssl.dylib @@ -244,12 +249,92 @@ endif endif +libasteriskpj.o: _ASTCFLAGS+=$(PJPROJECT_INCLUDE) + +ifeq ($(PJPROJECT_BUNDLED),yes) + +ASTPJ_SO_VERSION=2 +ASTPJ_LDLIBS=-L. -lasteriskpj + +-include $(ASTTOPDIR)/$(PJPROJECT_DIR)/build.mak + +PJPROJECT_LDLIBS := \ +-Wl,--whole-archive \ +$(PJSUA_LIB_LDLIB) \ +$(PJSIP_UA_LDLIB) \ +$(PJSIP_SIMPLE_LDLIB) \ +$(PJSIP_LDLIB) \ +$(PJNATH_LDLIB) \ +$(PJMEDIA_CODEC_LDLIB) \ +$(PJMEDIA_VIDEODEV_LDLIB) \ +$(PJMEDIA_AUDIODEV_LDLIB) \ +$(PJMEDIA_LDLIB) \ +$(PJLIB_UTIL_LDLIB) \ +$(PJLIB_LDLIB) \ +-Wl,--no-whole-archive \ +$(APP_THIRD_PARTY_LIBS) \ +$(APP_THIRD_PARTY_EXT) + +ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin +ASTPJ_LIB:=libasteriskpj.so + +libasteriskpj.exports: $(ASTTOPDIR)/$(PJPROJECT_DIR)/pjproject.symbols + $(ECHO_PREFIX) echo " [GENERATE] libasteriskpj.exports" +ifeq ($(GNU_LD),1) + $(CMD_PREFIX) echo -e "{\n\tglobal:" > libasteriskpj.exports + $(CMD_PREFIX) sed -r -e "s/.*/\t\t$(LINKER_SYMBOL_PREFIX)&;/" $(ASTTOPDIR)/$(PJPROJECT_DIR)/pjproject.symbols >> libasteriskpj.exports + $(CMD_PREFIX) echo -e "\t\t$(LINKER_SYMBOL_PREFIX)ast_pj_init;\n" >> libasteriskpj.exports + $(CMD_PREFIX) echo -e "\tlocal:\n\t\t*;\n};" >> libasteriskpj.exports +endif + +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB) $(PJ_LDFLAGS) +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS) +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lrt -lpthread +ifeq ($(GNU_LD),1) + $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): SO_SUPPRESS_SYMBOLS=-Wl,--version-script,libasteriskpj.exports,--warn-common +endif +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): SOLINK=$(DYLINK) + +# These rules are duplicated from $(ASTTOPDIR)/Makefile.rules because the library name +# being built does not match the "%.so" pattern; there are also additional steps +# required to build a proper shared library (as opposed to the 'loadable module' +# type that are built by the standard rules) +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): libasteriskpj.o libasteriskpj.exports + $(ECHO_PREFIX) echo " [LD] $< -> $@" + $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(CC_LDFLAGS_SO) $< $(CC_LIBS) + +$(ASTPJ_LIB): $(ASTPJ_LIB).$(ASTPJ_SO_VERSION) + $(ECHO_PREFIX) echo " [LN] $< -> $@" +ifneq ($(LDCONFIG),) + $(CMD_PREFIX) $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null +else + $(CMD_PREFIX) $(LN) -sf $< $@ +endif + +else # Darwin +ASTPJ_LIB:=libasteriskpj.dylib + +# -install_name allows library to be found if installed somewhere other than +# /lib or /usr/lib +$(ASTPJ_LIB): _ASTLDFLAGS+=-dynamiclib -install_name $(ASTLIBDIR)/$(ASTPJ_LIB) $(PJ_LDFLAGS) +$(ASTPJ_LIB): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS) +$(ASTPJ_LIB): LIBS+=$(PJPROJECT_LIBS) -lssl -lcrypto -luuid -lm -lrt -lpthread +$(ASTPJ_LIB): SOLINK=$(DYLINK) + +# Special rules for building a shared library (not a dynamically loadable module) +$(ASTPJ_LIB): libasteriskpj.o + $(ECHO_PREFIX) echo " [LD] $^ -> $@" + $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(CC_LDFLAGS_SO) $^ $(CC_LIBS) +endif + +endif + tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) -$(MAIN_TGT): $(OBJS) $(ASTSSL_LIB) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) +$(MAIN_TGT): $(OBJS) $(ASTSSL_LIB) $(ASTPJ_LIB) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) @$(CC) -c -o buildinfo.o $(_ASTCFLAGS) buildinfo.c $(ASTCFLAGS) $(ECHO_PREFIX) echo " [LD] $(OBJS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) -> $@" - $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) $(ASTSSL_LDLIBS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS) $(LIBEDIT_LIB) + $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) $(ASTSSL_LDLIBS) $(ASTPJ_LDLIBS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS) $(LIBEDIT_LIB) ifeq ($(GNU_LD),1) $(MAIN_TGT): asterisk.exports @@ -266,16 +351,29 @@ ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin else # Darwin $(INSTALL) -m 755 $(ASTSSL_LIB) "$(DESTDIR)$(ASTLIBDIR)/" endif +endif +ifeq ($(PJPROJECT_BUNDLED),yes) +ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin + $(INSTALL) -m 755 $(ASTPJ_LIB).$(ASTPJ_SO_VERSION) "$(DESTDIR)$(ASTLIBDIR)/" + $(LN) -sf $(ASTPJ_LIB).$(ASTPJ_SO_VERSION) "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" +else # Darwin + $(INSTALL) -m 755 $(ASTPJ_LIB) "$(DESTDIR)$(ASTLIBDIR)/" +endif +endif ifneq ($(LDCONFIG),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" -endif endif $(LN) -sf asterisk "$(DESTDIR)$(ASTSBINDIR)/rasterisk" binuninstall: rm -f "$(DESTDIR)$(ASTSBINDIR)/$(MAIN_TGT)" rm -f "$(DESTDIR)$(ASTSBINDIR)/rasterisk" +ifneq ($(ASTSSL_LIB).$(ASTSSL_SO_VERSION),.) rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)" +endif +ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) + rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB).$(ASTPJ_SO_VERSION)" +endif ifneq ($(LDCONFIG),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" endif @@ -285,7 +383,12 @@ clean:: ifeq ($(AST_ASTERISKSSL),yes) rm -f $(ASTSSL_LIB) $(ASTSSL_LIB).* endif - rm -f asterisk.exports libasteriskssl.exports + rm -f libasteriskpj.o + rm -f libasteriskpj.so* libasteriskpj.dynlib + rm -f .libasteriskpj* + + rm -f asterisk.exports libasteriskssl.exports libasteriskpj.exports @if [ -f editline/Makefile ]; then $(MAKE) -C editline distclean ; fi @$(MAKE) -C stdtime clean rm -f libresample/src/*.o + rm -f *.tmp diff --git a/main/asterisk.c b/main/asterisk.c index ca560cdb273..da804e19639 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4478,6 +4478,11 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou exit(1); } + if (ast_pj_init()) { + printf("Failed: ast_pj_init\n%s", term_quit()); + exit(1); + } + if (app_init()) { printf("App core initialization failed.\n%s", term_quit()); exit(1); diff --git a/main/libasteriskpj.c b/main/libasteriskpj.c new file mode 100644 index 00000000000..aed0ec8b146 --- /dev/null +++ b/main/libasteriskpj.c @@ -0,0 +1,52 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2009-2012, Digium, Inc. + * Copyright (C) 2015, Fairview 5 Engineering, LLC + * + * Russell Bryant + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Loader stub for static pjproject libraries + * + * \author George Joseph + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#ifdef HAVE_PJPROJECT +#include +#endif + +#include "asterisk/_private.h" /* ast_pj_init() */ + +/*! + * \internal + * \brief Initialize static pjproject implementation + */ +int ast_pj_init(void) +{ +#ifdef HAVE_PJPROJECT_BUNDLED + pj_init(); +#endif + return 0; +} diff --git a/makeopts.in b/makeopts.in index f606acee0e1..6baef1b4660 100644 --- a/makeopts.in +++ b/makeopts.in @@ -229,8 +229,10 @@ OSS_LIB=@OSS_LIB@ @FFMPEG_LIB@ @SDL_LIB@ @SDL_IMAGE_LIB@ @X11_LIB@ PGSQL_INCLUDE=@PGSQL_INCLUDE@ PGSQL_LIB=@PGSQL_LIB@ +PJPROJECT_BUNDLED=@PJPROJECT_BUNDLED@ PJPROJECT_INCLUDE=@PJPROJECT_INCLUDE@ PJPROJECT_LIB=@PJPROJECT_LIB@ +PJPROJECT_DIR=@PJPROJECT_DIR@ POPT_INCLUDE=@POPT_INCLUDE@ POPT_LIB=@POPT_LIB@ diff --git a/third-party/Makefile b/third-party/Makefile new file mode 100644 index 00000000000..0aca21e06a3 --- /dev/null +++ b/third-party/Makefile @@ -0,0 +1,21 @@ + +include Makefile.rules + +TP_SUBDIRS := pjproject +# Sub directories that contain special install/uninstall targets must be explicitly listed +# to prevent accidentally running the package's default install target. +TP_INSTALL_SUBDIRS := pjproject + +.PHONY: all dist-clean distclean install clean moduleinfo makeopts uninstall __embed_libs __embed_ldscript __embed_ldflags $(TP_SUBDIRS) + +override MAKECMDGOALS?=all + +MAKECMDGOALS:=$(subst dist-clean,distclean,$(MAKECMDGOALS)) +MAKECMDGOALS:=$(subst tpclean,clean,$(MAKECMDGOALS)) + +all distclean dist-clean install tpclean : $(TP_SUBDIRS) +install uninstall: $(TP_INSTALL_SUBDIRS) + +$(TP_SUBDIRS): + +$(CMD_PREFIX) $(SUBMAKE) -C $@ $(MAKECMDGOALS) + diff --git a/third-party/Makefile.rules b/third-party/Makefile.rules new file mode 100644 index 00000000000..ac4189ac4d8 --- /dev/null +++ b/third-party/Makefile.rules @@ -0,0 +1,37 @@ + +ifeq ($(NOISY_BUILD),) + SUBMAKE?=$(MAKE) --quiet --no-print-directory + ECHO_PREFIX?=@ + CMD_PREFIX?=@ + QUIET_CONFIGURE=-q + REALLY_QUIET=&>/dev/null +else + SUBMAKE?=$(MAKE) + ECHO_PREFIX?=@\# + CMD_PREFIX?= + QUIET_CONFIGURE= + REALLY_QUIET= +endif + +DOWNLOAD := +DOWNLOAD != which wget 2>/dev/null +DOWNLOAD:=$(if $(DOWNLOAD),$(DOWNLOAD) -O- ,) + +ifeq ($(DOWNLOAD),) +DOWNLOAD != which curl 2>/dev/null +DOWNLOAD:=$(if $(DOWNLOAD), $(DOWNLOAD) -L ,) +endif + +ifeq ($(DOWNLOAD),) +DOWNLOAD := echo "No download program available" ; exit 1; +endif + +export SUBMAKE +export ECHO_PREFIX +export CMD_PREFIX +export QUIET_CONFIGURE +export REALLY_QUIET +export ASTTOPDIR +export ASTSBINDIR +export DESTDIR +export ASTDATADIR diff --git a/third-party/pjproject/.gitignore b/third-party/pjproject/.gitignore new file mode 100644 index 00000000000..5079deeb351 --- /dev/null +++ b/third-party/pjproject/.gitignore @@ -0,0 +1,4 @@ +source/ +**.bz2 +build.mak +pjproject.symbols diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile new file mode 100644 index 00000000000..310095159c9 --- /dev/null +++ b/third-party/pjproject/Makefile @@ -0,0 +1,110 @@ +.SUFFIXES: +.PHONY: _all all _install install clean distclean echo_cflags configure + +ifeq ($(MAKECMDGOALS),install) +include ../../makeopts +else +-include ../../makeopts +endif + +include ../versions.mak +include ../Makefile.rules +include Makefile.rules + +ECHO_PREFIX := $(ECHO_PREFIX) echo '[pjproject] ' + +ifeq ($(MAKECMDGOALS),echo_cflags) +-include build.mak +ECHO_PREFIX=@\# +endif + +ifneq ($(PJPROJECT_BUNDLED),yes) +all install: + @echo '[pjproject] Not enabled' +else + +ifneq ($(findstring clean,$(MAKECMDGOALS)),clean) +include build.mak +endif + +all: _all +install: _install +endif + +ifndef $(TMPDIR) +ifneq ($(wildcard /tmp),) +TMPDIR=/tmp +else +TMPDIR=. +endif +endif + +$(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 : ../versions.mak + $(ECHO_PREFIX) Downloading $@ with $(DOWNLOAD) + $(CMD_PREFIX) $(DOWNLOAD) $(PJPROJECT_URL)/$(@F) > $@ + +source/user.mak source/pjlib/include/pj/config_site.h: $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 patches/config_site.h patches/user.mak + $(ECHO_PREFIX) Unpacking $< + -@rm -rf source &>/dev/null + -@mkdir source &>/dev/null + $(CMD_PREFIX) tar --strip-components=1 -C source -xjf $< + $(ECHO_PREFIX) Applying patches and custom files + $(CMD_PREFIX) ./apply_patches $(QUIET_CONFIGURE) ./patches ./source + $(CMD_PREFIX) cp -f ./patches/config_site.h ./source/pjlib/include/pj/ + $(CMD_PREFIX) cp -f ./patches/user.mak ./source/ + +build.mak: source/pjlib/include/pj/config_site.h source/user.mak Makefile.rules + $(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS) + $(CMD_PREFIX) (cd source ; autoconf aconfigure.ac > aconfigure && ./aconfigure $(QUIET_CONFIGURE) $(PJPROJECT_CONFIG_OPTS)) + @sed -r -e "/prefix|export PJ_SHARED_LIBRARIES|MACHINE_NAME|OS_NAME|HOST_NAME|CC_NAME|CROSS_COMPILE|LINUX_POLL/d" source/build.mak > build.mak + +configure: build.mak + +echo_cflags: build.mak + @echo $(PJ_CFLAGS) + +source/pjlib/build/.pjlib-$(TARGET_NAME).depend: build.mak + $(ECHO_PREFIX) "Making dependencies" + +$(CMD_PREFIX) $(SUBMAKE) -C source dep + +source/pjlib/lib/libpj-$(TARGET_NAME).a: source/pjlib/build/.pjlib-$(TARGET_NAME).depend + $(ECHO_PREFIX) Compiling libs + +$(CMD_PREFIX) $(SUBMAKE) -C source lib $(REALLY_QUIET) + +pjproject.symbols: source/pjlib/lib/libpj-$(TARGET_NAME).a + $(ECHO_PREFIX) Generating symbols + $(CMD_PREFIX) nm -Pog $(PJ_LIB_FILES) | sed -n -r -e "s/.+: ([pP][jJ][^ ]+) .+/\1/gp" | sort -u > pjproject.symbols + +source/pjsip-apps/bin/pjsua-$(TARGET_NAME): source/pjlib/lib/libpj-$(TARGET_NAME).a + $(ECHO_PREFIX) Compiling apps + $(CMD_PREFIX) $(SUBMAKE) -C source/pjsip-apps/build pjsua pjsystest $(REALLY_QUIET) + +source/pjsip-apps/src/python/build/_pjsua.so: source/pjlib/lib/libpj-$(TARGET_NAME).a + $(ECHO_PREFIX) Compiling python bindings + $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; python setup.py build --build-platlib=./build $(REALLY_QUIET)) + +_all: pjproject.symbols source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/src/python/build/_pjsua.so + +_install: _all + $(ECHO_PREFIX) Installing apps and python bindings + @if [ ! -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject" ]; then \ + $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject"; \ + fi; + $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsua-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsua" + $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsystest-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsystest" + $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/src/python/build/_pjsua.so "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" + $(CMD_PREFIX) $(INSTALL) -m 644 source/pjsip-apps/src/python/build/pjsua.py "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" + +uninstall: + $(ECHO_PREFIX) Uninstalling apps and python bindings + $(CMD_PREFIX) rm -rf "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject" + +clean: + $(ECHO_PREFIX) Cleaning + -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || : + -$(CMD_PREFIX) rm -rf pjproject.symbols + +distclean: + $(ECHO_PREFIX) Distcleaning + -$(CMD_PREFIX) rm -rf source pjproject.symbols pjproject-*.tar.bz2 build.mak + diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules new file mode 100644 index 00000000000..d6e4be00be9 --- /dev/null +++ b/third-party/pjproject/Makefile.rules @@ -0,0 +1,7 @@ +PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) + +# Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe +PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --with-external-speex --with-external-gsm --with-external-srtp \ + --with-external-pa --disable-video --disable-v4l2 --disable-sound --disable-resample \ + --disable-opencore-amr --disable-ilbc-codec --without-libyuv --disable-g7221-codec \ + --enable-epoll diff --git a/third-party/pjproject/apply_patches b/third-party/pjproject/apply_patches new file mode 100755 index 00000000000..1b72d14b025 --- /dev/null +++ b/third-party/pjproject/apply_patches @@ -0,0 +1,39 @@ +#!/bin/bash + +if [ "$1" = "-q" ] ; then + quiet=1 + shift +fi + +patchdir=${1:?You must supply a patches directory} +sourcedir=${2?:You must supply a source directory} + +patchdir=`readlink -f $patchdir` +sourcedir=`readlink -f $sourcedir` + +if [ ! -d "$patchdir" ] ; then + echo "$patchdir is not a directory" >&2 + exit 1 +fi + +if [ ! -d "$sourcedir" ] ; then + echo "$sourcedir is not a directory" >&2 + exit 1 +fi + +if [ ! "$(ls -A $patchdir/*.patch 2>/dev/null)" ] ; then + echo "No patches in $patchdir" >&2 + exit 0 +fi + +for patchfile in $patchdir/*.patch ; do + patch -d $sourcedir -p1 -s -r- -f -N --dry-run -i "$patchfile" || (echo "Patchfile $(basename $patchfile) failed to apply >&2" ; exit 1) || exit 1 +done + +for patchfile in "$patchdir"/*.patch ; do + [ -z $quiet ] && echo "Applying patch $(basename $patchfile)" + patch -d "$sourcedir" -p1 -s -i "$patchfile" || exit 1 +done + +exit 0 + diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 new file mode 100644 index 00000000000..3351527ebb5 --- /dev/null +++ b/third-party/pjproject/configure.m4 @@ -0,0 +1,46 @@ +AC_DEFUN([PJPROJECT_SYMBOL_CHECK], +[ + $1_INCLUDE="$PJPROJECT_INCLUDE" + AC_MSG_CHECKING([for $2 declared in $3]) + + saved_cpp="$CPPFLAGS" + CPPFLAGS="$PJPROJECT_INCLUDE" + AC_EGREP_HEADER($2, $3, [ + AC_MSG_RESULT(yes) + PBX_$1=1 + AC_DEFINE([HAVE_$1], 1, [Define if your system has $2 declared.]) + ], [ + AC_MSG_RESULT(no) + ]) + + CPPGLAGS="$saved_cpp" + $1_INCLUDE="$PJPROJECT_INCLUDE" +]) + +AC_DEFUN([PJPROJECT_CONFIGURE], +[ + AC_MSG_CHECKING(for embedded pjproject (may have to download)) + AC_MSG_RESULT(configuring) + make --quiet --no-print-directory -C $1 configure + if test $? -ne 0 ; then + AC_MSG_RESULT(failed) + AC_MSG_NOTICE(Unable to configure $1) + AC_MSG_ERROR(Run "make -C $1 NOISY_BUILD=yes configure" to see error details.) + fi + + PJPROJECT_INCLUDE=$(make --quiet --no-print-directory -C $1 echo_cflags) + PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" + PBX_PJPROJECT=1 + PJPROJECT_BUNDLED=yes + AC_DEFINE([HAVE_PJPROJECT], 1, [Define if your system has PJPROJECT]) + AC_DEFINE([HAVE_PJPROJECT_BUNDLED], 1, [Define if your system has PJPROJECT_BUNDLED]) + AC_MSG_CHECKING(for embedded pjproject) + AC_MSG_RESULT(yes) + + PJPROJECT_SYMBOL_CHECK([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [pjsip_dlg_create_uas_and_inc_lock], [pjsip.h]) + PJPROJECT_SYMBOL_CHECK([PJ_TRANSACTION_GRP_LOCK], [pjsip_tsx_create_uac2], [pjsip.h]) + PJPROJECT_SYMBOL_CHECK([PJSIP_REPLACE_MEDIA_STREAM], [PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE], [pjmedia.h]) + PJPROJECT_SYMBOL_CHECK([PJSIP_GET_DEST_INFO], [pjsip_get_dest_info], [pjsip.h]) + PJPROJECT_SYMBOL_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_from_files2], [pjlib.h]) + PJPROJECT_SYMBOL_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip_endpt_set_ext_resolver], [pjsip.h]) +]) diff --git a/third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch b/third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch new file mode 100644 index 00000000000..33fc8ea4ec4 --- /dev/null +++ b/third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch @@ -0,0 +1,224 @@ +diff --git a/pjlib/include/pj/ssl_sock.h b/pjlib/include/pj/ssl_sock.h +index 1682bda..a69af32 100644 +--- a/pjlib/include/pj/ssl_sock.h ++++ b/pjlib/include/pj/ssl_sock.h +@@ -864,6 +864,18 @@ PJ_DECL(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param); + + + /** ++ * Duplicate pj_ssl_sock_param. ++ * ++ * @param pool Pool to allocate memory. ++ * @param dst Destination parameter. ++ * @param src Source parameter. ++ */ ++PJ_DECL(void) pj_ssl_sock_param_copy(pj_pool_t *pool, ++ pj_ssl_sock_param *dst, ++ const pj_ssl_sock_param *src); ++ ++ ++/** + * Create secure socket instance. + * + * @param pool The pool for allocating secure socket instance. +@@ -1115,6 +1127,30 @@ PJ_DECL(pj_status_t) pj_ssl_sock_start_accept(pj_ssl_sock_t *ssock, + + + /** ++ * Same as #pj_ssl_sock_start_accept(), but application can provide ++ * a secure socket parameter, which will be used to create a new secure ++ * socket reported in \a on_accept_complete() callback when there is ++ * an incoming connection. ++ * ++ * @param ssock The secure socket. ++ * @param pool Pool used to allocate some internal data for the ++ * operation. ++ * @param localaddr Local address to bind on. ++ * @param addr_len Length of buffer containing local address. ++ * @param newsock_param Secure socket parameter for new accepted sockets. ++ * ++ * @return PJ_SUCCESS if the operation has been successful, ++ * or the appropriate error code on failure. ++ */ ++PJ_DECL(pj_status_t) ++pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock, ++ pj_pool_t *pool, ++ const pj_sockaddr_t *local_addr, ++ int addr_len, ++ const pj_ssl_sock_param *newsock_param); ++ ++ ++/** + * Starts asynchronous socket connect() operation and SSL/TLS handshaking + * for this socket. Once the connection is done (either successfully or not), + * the \a on_connect_complete() callback will be called. +diff --git a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c +index 913efee..717ab1d 100644 +--- a/pjlib/src/pj/ssl_sock_common.c ++++ b/pjlib/src/pj/ssl_sock_common.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + + /* +@@ -48,6 +49,31 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param) + } + + ++/* ++ * Duplicate SSL socket parameter. ++ */ ++PJ_DEF(void) pj_ssl_sock_param_copy( pj_pool_t *pool, ++ pj_ssl_sock_param *dst, ++ const pj_ssl_sock_param *src) ++{ ++ /* Init secure socket param */ ++ pj_memcpy(dst, src, sizeof(*dst)); ++ if (src->ciphers_num > 0) { ++ unsigned i; ++ dst->ciphers = (pj_ssl_cipher*) ++ pj_pool_calloc(pool, src->ciphers_num, ++ sizeof(pj_ssl_cipher)); ++ for (i = 0; i < src->ciphers_num; ++i) ++ dst->ciphers[i] = src->ciphers[i]; ++ } ++ ++ if (src->server_name.slen) { ++ /* Server name must be null-terminated */ ++ pj_strdup_with_null(pool, &dst->server_name, &src->server_name); ++ } ++} ++ ++ + PJ_DEF(pj_status_t) pj_ssl_cert_get_verify_status_strings( + pj_uint32_t verify_status, + const char *error_strings[], +diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c +index 40a5a1e..6a701b7 100644 +--- a/pjlib/src/pj/ssl_sock_ossl.c ++++ b/pjlib/src/pj/ssl_sock_ossl.c +@@ -141,6 +141,7 @@ struct pj_ssl_sock_t + pj_pool_t *pool; + pj_ssl_sock_t *parent; + pj_ssl_sock_param param; ++ pj_ssl_sock_param newsock_param; + pj_ssl_cert_t *cert; + + pj_ssl_cert_info local_cert_info; +@@ -1757,11 +1758,9 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock, + unsigned i; + pj_status_t status; + +- PJ_UNUSED_ARG(src_addr_len); +- + /* Create new SSL socket instance */ +- status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->param, +- &ssock); ++ status = pj_ssl_sock_create(ssock_parent->pool, ++ &ssock_parent->newsock_param, &ssock); + if (status != PJ_SUCCESS) + goto on_return; + +@@ -2183,20 +2182,8 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool, + return status; + + /* Init secure socket param */ +- ssock->param = *param; ++ pj_ssl_sock_param_copy(pool, &ssock->param, param); + ssock->param.read_buffer_size = ((ssock->param.read_buffer_size+7)>>3)<<3; +- if (param->ciphers_num > 0) { +- unsigned i; +- ssock->param.ciphers = (pj_ssl_cipher*) +- pj_pool_calloc(pool, param->ciphers_num, +- sizeof(pj_ssl_cipher)); +- for (i = 0; i < param->ciphers_num; ++i) +- ssock->param.ciphers[i] = param->ciphers[i]; +- } +- +- /* Server name must be null-terminated */ +- pj_strdup_with_null(pool, &ssock->param.server_name, +- ¶m->server_name); + + /* Finally */ + *p_ssock = ssock; +@@ -2617,12 +2604,36 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock, + const pj_sockaddr_t *localaddr, + int addr_len) + { ++ return pj_ssl_sock_start_accept2(ssock, pool, localaddr, addr_len, ++ &ssock->param); ++} ++ ++ ++/** ++ * Same as #pj_ssl_sock_start_accept(), but application provides parameter ++ * for new accepted secure sockets. ++ */ ++PJ_DEF(pj_status_t) ++pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock, ++ pj_pool_t *pool, ++ const pj_sockaddr_t *localaddr, ++ int addr_len, ++ const pj_ssl_sock_param *newsock_param) ++{ + pj_activesock_cb asock_cb; + pj_activesock_cfg asock_cfg; + pj_status_t status; + + PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL); + ++ /* Verify new socket parameters */ ++ if (newsock_param->grp_lock != ssock->param.grp_lock || ++ newsock_param->sock_af != ssock->param.sock_af || ++ newsock_param->sock_type != ssock->param.sock_type) ++ { ++ return PJ_EINVAL; ++ } ++ + /* Create socket */ + status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0, + &ssock->sock); +@@ -2691,6 +2702,7 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock, + goto on_error; + + /* Start accepting */ ++ pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param); + status = pj_activesock_start_accept(ssock->asock, pool); + if (status != PJ_SUCCESS) + goto on_error; +diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c +index a9e95fb..91d99a7 100644 +--- a/pjsip/src/pjsip/sip_transport_tls.c ++++ b/pjsip/src/pjsip/sip_transport_tls.c +@@ -314,7 +314,7 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt, + int af, sip_ssl_method; + pj_uint32_t sip_ssl_proto; + struct tls_listener *listener; +- pj_ssl_sock_param ssock_param; ++ pj_ssl_sock_param ssock_param, newsock_param; + pj_sockaddr *listener_addr; + pj_bool_t has_listener; + pj_status_t status; +@@ -473,9 +473,14 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt, + */ + has_listener = PJ_FALSE; + +- status = pj_ssl_sock_start_accept(listener->ssock, pool, ++ pj_memcpy(&newsock_param, &ssock_param, sizeof(newsock_param)); ++ newsock_param.async_cnt = 1; ++ newsock_param.cb.on_data_read = &on_data_read; ++ newsock_param.cb.on_data_sent = &on_data_sent; ++ status = pj_ssl_sock_start_accept2(listener->ssock, pool, + (pj_sockaddr_t*)listener_addr, +- pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr)); ++ pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr), ++ &newsock_param); + if (status == PJ_SUCCESS || status == PJ_EPENDING) { + pj_ssl_sock_info info; + has_listener = PJ_TRUE; +-- +cgit v0.11.2 + diff --git a/third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch b/third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch new file mode 100644 index 00000000000..9873abf0e68 --- /dev/null +++ b/third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch @@ -0,0 +1,70 @@ +From a147b72df1ec150c1d733e882225db86142fb339 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Sun, 21 Feb 2016 10:01:53 -0700 +Subject: [PATCH] Bump tcp/tls and transaction log levels from 1 to 3 + +sip_transport_tcp, sip_transport_tls and sip_transaction are printing messages +at log level 1 or 2 for things that are transient, recoverable, possibly +expected, or are handled with return codes. A good example of this is if we're +trying to send an OPTIONS message to a TCP client that has disappeared. Both +sip_transport_tcp and sip_transaction are printing "connection refused" +messages because the remote client isn't listening. This is generally expected +behavior and it should be up to the app caller to determine if an error message +is warranted. +--- + pjsip/src/pjsip/sip_transaction.c | 4 ++-- + pjsip/src/pjsip/sip_transport_tcp.c | 2 +- + pjsip/src/pjsip/sip_transport_tls.c | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c +index 46bd971..1b4fdb7 100644 +--- a/pjsip/src/pjsip/sip_transaction.c ++++ b/pjsip/src/pjsip/sip_transaction.c +@@ -1898,7 +1898,7 @@ static void send_msg_callback( pjsip_send_state *send_state, + + err =pj_strerror((pj_status_t)-sent, errmsg, sizeof(errmsg)); + +- PJ_LOG(2,(tsx->obj_name, ++ PJ_LOG(3,(tsx->obj_name, + "Failed to send %s! err=%d (%s)", + pjsip_tx_data_get_info(send_state->tdata), -sent, + errmsg)); +@@ -1938,7 +1938,7 @@ static void send_msg_callback( pjsip_send_state *send_state, + } + + } else { +- PJ_PERROR(2,(tsx->obj_name, (pj_status_t)-sent, ++ PJ_PERROR(3,(tsx->obj_name, (pj_status_t)-sent, + "Temporary failure in sending %s, " + "will try next server", + pjsip_tx_data_get_info(send_state->tdata))); +diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c +index 222cb13..1bbb324 100644 +--- a/pjsip/src/pjsip/sip_transport_tcp.c ++++ b/pjsip/src/pjsip/sip_transport_tcp.c +@@ -164,7 +164,7 @@ static void tcp_perror(const char *sender, const char *title, + + pj_strerror(status, errmsg, sizeof(errmsg)); + +- PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status)); ++ PJ_LOG(3,(sender, "%s: %s [code=%d]", title, errmsg, status)); + } + + +diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c +index 617d7f5..a83ac32 100644 +--- a/pjsip/src/pjsip/sip_transport_tls.c ++++ b/pjsip/src/pjsip/sip_transport_tls.c +@@ -170,7 +170,7 @@ static void tls_perror(const char *sender, const char *title, + + pj_strerror(status, errmsg, sizeof(errmsg)); + +- PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status)); ++ PJ_LOG(3,(sender, "%s: %s [code=%d]", title, errmsg, status)); + } + + +-- +2.5.0 + diff --git a/third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch b/third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch new file mode 100644 index 00000000000..36b6c651f12 --- /dev/null +++ b/third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch @@ -0,0 +1,80 @@ +From b5c0bc905911f75e08987e6833075481fe16dab2 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Mon, 22 Feb 2016 13:05:59 -0700 +Subject: [PATCH] ioqueue: Enable epoll in aconfigure.ac + +Although the --enable-epoll option was being accepted, the result +was always forced to select. This patch updates aconfigure.ac +to properly set the value of ac_linux_poll if --enable-epoll is +specified. +--- + README.txt | 1 + + aconfigure | 11 +++++++---- + aconfigure.ac | 7 +++++-- + pjlib/include/pj/compat/os_auto.h.in | 3 +++ + 4 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/README.txt b/README.txt +index bc45da8..48415fd 100644 +--- a/README.txt ++++ b/README.txt +@@ -463,6 +463,7 @@ Using Default Settings + $ ./configure --help + ... + Optional Features: ++ --enable-epoll Use epoll on Linux instead of select + --disable-floating-point Disable floating point where possible + --disable-sound Exclude sound (i.e. use null sound) + --disable-small-filter Exclude small filter in resampling +diff --git a/aconfigure.ac b/aconfigure.ac +index 2f71abb..3e88124 100644 +--- a/aconfigure.ac ++++ b/aconfigure.ac +@@ -410,6 +410,7 @@ dnl ###################### + dnl # ioqueue selection + dnl # + AC_SUBST(ac_os_objs) ++AC_SUBST(ac_linux_poll) + AC_MSG_CHECKING([ioqueue backend]) + AC_ARG_ENABLE(epoll, + AC_HELP_STRING([--enable-epoll], +@@ -417,10 +418,13 @@ AC_ARG_ENABLE(epoll, + [ + ac_os_objs=ioqueue_epoll.o + AC_MSG_RESULT([/dev/epoll]) ++ AC_DEFINE(PJ_HAS_LINUX_EPOLL,1) ++ ac_linux_poll=epoll + ], + [ + ac_os_objs=ioqueue_select.o +- AC_MSG_RESULT([select()]) ++ AC_MSG_RESULT([select()]) ++ ac_linux_poll=select + ]) + + AC_SUBST(ac_shared_libraries) +@@ -1879,7 +1883,6 @@ esac + + + AC_SUBST(target) +-AC_SUBST(ac_linux_poll,select) + AC_SUBST(ac_host,unix) + AC_SUBST(ac_main_obj) + case $target in +diff --git a/pjlib/include/pj/compat/os_auto.h.in b/pjlib/include/pj/compat/os_auto.h.in +index 77980d3..c8e73b2 100644 +--- a/pjlib/include/pj/compat/os_auto.h.in ++++ b/pjlib/include/pj/compat/os_auto.h.in +@@ -128,6 +128,9 @@ + */ + #undef PJ_SELECT_NEEDS_NFDS + ++/* Was Linux epoll support enabled */ ++#undef PJ_HAS_LINUX_EPOLL ++ + /* Is errno a good way to retrieve OS errors? + */ + #undef PJ_HAS_ERRNO_VAR +-- +2.5.0 + diff --git a/third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch b/third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch new file mode 100644 index 00000000000..001912cfe30 --- /dev/null +++ b/third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch @@ -0,0 +1,114 @@ +From 552194179eb6deae8326eb0fef446e69240ea41b Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Fri, 19 Feb 2016 17:05:53 -0700 +Subject: [PATCH] sip_transport: Search for transport even if listener was + specified. + +If a listener was specified when calling pjsip_tpmgr_acquire_transport2, +a new transport was always created instead of using an existing one. This +caused several issues mostly related to the remote end not expecting a new +connection. I.E. A TCP client who registered to a server is not going to +be listening for connections coming back from the server and refuses the +connection. + +Now when pjsip_tpmgr_acquire_transport2 is called with a listener, the +registry is still searched for an existing transport and the listener +is used as a factory only if no existing transport can be found. +--- + pjsip/src/pjsip/sip_transport.c | 68 ++++++++++++++++++++--------------------- + 1 file changed, 34 insertions(+), 34 deletions(-) + +diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c +index 0410324..620b9c0 100644 +--- a/pjsip/src/pjsip/sip_transport.c ++++ b/pjsip/src/pjsip/sip_transport.c +@@ -1999,29 +1999,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, + + TRACE_((THIS_FILE, "Transport %s acquired", seltp->obj_name)); + return PJ_SUCCESS; +- +- +- } else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && +- sel->u.listener) +- { +- /* Application has requested that a specific listener is to +- * be used. In this case, skip transport hash table lookup. +- */ +- +- /* Verify that the listener type matches the destination type */ +- if (sel->u.listener->type != type) { +- pj_lock_release(mgr->lock); +- return PJSIP_ETPNOTSUITABLE; +- } +- +- /* We'll use this listener to create transport */ +- factory = sel->u.listener; +- + } else { + + /* + * This is the "normal" flow, where application doesn't specify +- * specific transport/listener to be used to send message to. ++ * specific transport to be used to send message to. + * In this case, lookup the transport from the hash table. + */ + pjsip_transport_key key; +@@ -2081,22 +2063,40 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, + return PJ_SUCCESS; + } + +- /* +- * Transport not found! +- * Find factory that can create such transport. +- */ +- factory = mgr->factory_list.next; +- while (factory != &mgr->factory_list) { +- if (factory->type == type) +- break; +- factory = factory->next; +- } ++ if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && ++ sel->u.listener) ++ { ++ /* Application has requested that a specific listener is to ++ * be used. ++ */ ++ ++ /* Verify that the listener type matches the destination type */ ++ if (sel->u.listener->type != type) { ++ pj_lock_release(mgr->lock); ++ return PJSIP_ETPNOTSUITABLE; ++ } + +- if (factory == &mgr->factory_list) { +- /* No factory can create the transport! */ +- pj_lock_release(mgr->lock); +- TRACE_((THIS_FILE, "No suitable factory was found either")); +- return PJSIP_EUNSUPTRANSPORT; ++ /* We'll use this listener to create transport */ ++ factory = sel->u.listener; ++ ++ } else { ++ /* ++ * Transport not found! ++ * Find factory that can create such transport. ++ */ ++ factory = mgr->factory_list.next; ++ while (factory != &mgr->factory_list) { ++ if (factory->type == type) ++ break; ++ factory = factory->next; ++ } ++ ++ if (factory == &mgr->factory_list) { ++ /* No factory can create the transport! */ ++ pj_lock_release(mgr->lock); ++ TRACE_((THIS_FILE, "No suitable factory was found either")); ++ return PJSIP_EUNSUPTRANSPORT; ++ } + } + } + +-- +2.5.0 + diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h new file mode 100644 index 00000000000..544c1e85ec6 --- /dev/null +++ b/third-party/pjproject/patches/config_site.h @@ -0,0 +1,34 @@ +/* + * Asterisk config_site.h + */ + +#include + +#define PJ_HAS_IPV6 1 +#define NDEBUG 1 +#define PJ_MAX_HOSTNAME (256) +#define PJSIP_MAX_URL_SIZE (512) +#ifdef PJ_HAS_LINUX_EPOLL +#define PJ_IOQUEUE_MAX_HANDLES (5000) +#else +#define PJ_IOQUEUE_MAX_HANDLES (FD_SETSIZE) +#endif +#define PJ_IOQUEUE_HAS_SAFE_UNREG 1 +#define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL (16) + +#define PJ_SCANNER_USE_BITWISE 0 +#define PJ_OS_HAS_CHECK_STACK 0 +#define PJ_LOG_MAX_LEVEL 3 +#define PJ_ENABLE_EXTRA_CHECK 0 +#define PJSIP_MAX_TSX_COUNT ((64*1024)-1) +#define PJSIP_MAX_DIALOG_COUNT ((64*1024)-1) +#define PJSIP_UDP_SO_SNDBUF_SIZE (512*1024) +#define PJSIP_UDP_SO_RCVBUF_SIZE (512*1024) +#define PJ_DEBUG 0 +#define PJSIP_SAFE_MODULE 0 +#define PJ_HAS_STRICMP_ALNUM 0 +#define PJ_HASH_USE_OWN_TOLOWER 1 +#define PJSIP_UNESCAPE_IN_PLACE 1 + +#undef PJ_TODO +#define PJ_TODO(x) diff --git a/third-party/pjproject/patches/user.mak b/third-party/pjproject/patches/user.mak new file mode 100644 index 00000000000..31579d19cc0 --- /dev/null +++ b/third-party/pjproject/patches/user.mak @@ -0,0 +1,2 @@ + +CFLAGS += -fPIC -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unused-label -Wno-unused-function -Wno-strict-aliasing diff --git a/third-party/versions.mak b/third-party/versions.mak new file mode 100644 index 00000000000..7b8b59c5383 --- /dev/null +++ b/third-party/versions.mak @@ -0,0 +1,2 @@ + +PJPROJECT_VERSION = 2.4.5 From 75ec137e91d60795f8c85ab42ed134dd0bc07129 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 29 Feb 2016 20:41:55 -0600 Subject: [PATCH 0237/1578] res_pjsip_send_to_voicemail.c: Fix off-nominal double channel unref. * Fix double unref of other_party channel in off nominal path. * This is unlikely to be a real problem. However, for safety, in handle_incoming_request() keep the datastore ref with the other_party channel ref until we are finished with the other_party channel. Change-Id: I78f22547bf0bb99fb20814ceab75952bd857f821 --- res/res_pjsip_send_to_voicemail.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/res_pjsip_send_to_voicemail.c b/res/res_pjsip_send_to_voicemail.c index 9d2b5b14b5e..cd0f05f2736 100644 --- a/res/res_pjsip_send_to_voicemail.c +++ b/res/res_pjsip_send_to_voicemail.c @@ -160,12 +160,10 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip sip_session_datastore->data = other_party; if (ast_sip_session_add_datastore(session, sip_session_datastore)) { - ast_channel_unref(other_party); ao2_ref(sip_session_datastore, -1); send_response(session, 500, rdata); return -1; } - ao2_ref(sip_session_datastore, -1); if (has_feature) { pbx_builtin_setvar_helper(other_party, SEND_TO_VM_HEADER, @@ -177,6 +175,7 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip SEND_TO_VM_REDIRECT_VALUE); } + ao2_ref(sip_session_datastore, -1); return 0; } From 8c8ef4efb0e6545f33c860f0fcb53cf308d34068 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 26 Feb 2016 18:54:53 -0600 Subject: [PATCH 0238/1578] res_pjsip_send_to_voicemail.c: Allow either quoted or not send_to_vm reason. Change-Id: Id6350b3c7d4ec8df7ec89863566645e2b0f441fd --- res/res_pjsip_send_to_voicemail.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_send_to_voicemail.c b/res/res_pjsip_send_to_voicemail.c index 9d2b5b14b5e..c7e62a2f72d 100644 --- a/res/res_pjsip_send_to_voicemail.c +++ b/res/res_pjsip_send_to_voicemail.c @@ -47,7 +47,8 @@ #define SEND_TO_VM_HEADER_VALUE "feature_send_to_vm" #define SEND_TO_VM_REDIRECT "REDIRECTING(reason)" -#define SEND_TO_VM_REDIRECT_VALUE "\"send_to_vm\"" +#define SEND_TO_VM_REDIRECT_VALUE "send_to_vm" +#define SEND_TO_VM_REDIRECT_QUOTED_VALUE "\"" SEND_TO_VM_REDIRECT_VALUE "\"" static void send_response(struct ast_sip_session *session, int code, struct pjsip_rx_data *rdata) { @@ -102,9 +103,13 @@ static int has_diversion_reason(pjsip_rx_data *rdata) pjsip_param *reason; pjsip_fromto_hdr *hdr = get_diversion_header(rdata); - return hdr && - (reason = get_diversion_reason(hdr)) && - !pj_stricmp2(&reason->value, SEND_TO_VM_REDIRECT_VALUE); + if (!hdr) { + return 0; + } + reason = get_diversion_reason(hdr); + return reason + && (!pj_stricmp2(&reason->value, SEND_TO_VM_REDIRECT_QUOTED_VALUE) + || !pj_stricmp2(&reason->value, SEND_TO_VM_REDIRECT_VALUE)); } static int has_call_feature(pjsip_rx_data *rdata) From 25de01f3012ca074ebc78b5082c4a4607d642405 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 26 Feb 2016 18:57:17 -0600 Subject: [PATCH 0239/1578] SIP diversion: Fix REDIRECTING(reason) value inconsistencies. Previous chan_sip behavior: Before this patch chan_sip would always strip any quotes from an incoming reason and pass that value up as the REDIRECTING(reason). For an outgoing reason value, chan_sip would check the value against known values and quote any it didn't recognize. Incoming 480 response message reason text was just assigned to the REDIRECTING(reason). Previous chan_pjsip behavior: Before this patch chan_pjsip would always pass the incoming reason value up as the REDIRECTING(reason). For an outgoing reason value, chan_pjsip would send the reason value as passed down. With this patch: Both channel drivers match incoming reason values with values documented by REDIRECTING(reason) and values documented by RFC5806 regardless of whether they are quoted or not. RFC5806 values are mapped to the equivalent REDIRECTING(reason) documented value and is set in REDIRECTING(reason). e.g., an incoming RFC5806 'unconditional' value or a quoted string version ('"unconditional"') is converted to REDIRECTING(reason)'s 'cfu' value. The user's dialplan only needs to deal with 'cfu' instead of any of the aliases. The incoming 480 response reason text supported by chan_sip checks for known reason values and if not matched then puts quotes around the reason string and assigns that to REDIRECTING(reason). Both channel drivers send outgoing known REDIRECTING(reason) values as the unquoted RFC5806 equivalent. User custom values are either sent as is or with added quotes if SIP doesn't allow a character within the value as part of a RFC3261 Section 25.1 token. Note that there are still limitations on what characters can be put in a custom user value. e.g., embedding quotes in the middle of the reason string is silly and just going to cause you grief. * Setting a REDIRECTING(reason) value now recognizes RFC5806 aliases. e.g., Setting REDIRECTING(reason) to 'unconditional' is converted to the 'cfu' value. * Added missing malloc() NULL return check in res_pjsip_diversion.c set_redirecting_reason(). * Fixed potential read from a stale pointer in res_pjsip_diversion.c add_diversion_header(). The reason string needed to be copied into the tdata memory pool to ensure that the string would always be available. Otherwise, if the reason string returned by reason_code_to_str() was a user's reason string then the string could be freed later by another thread. Change-Id: Ifba83d23a195a9f64d55b9c681d2e62476b68a87 --- CHANGES | 30 ++++++++ channels/chan_sip.c | 156 +++++++++++++++++++++----------------- main/callerid.c | 13 +++- res/res_pjsip_diversion.c | 99 ++++++++++++++++++------ 4 files changed, 204 insertions(+), 94 deletions(-) diff --git a/CHANGES b/CHANGES index 91e170ffbb2..78a464f4443 100644 --- a/CHANGES +++ b/CHANGES @@ -232,6 +232,36 @@ app_confbridge conference state and made the locked column a yes/no value instead of a locked/unlocked value. +REDIRECTING(reason) +------------------ + * The REDIRECTING(reason) value is now treated consistently between + chan_sip and chan_pjsip. + + Both channel drivers match incoming reason values with values documented + by REDIRECTING(reason) and values documented by RFC5806 regardless of + whether they are quoted or not. RFC5806 values are mapped to the + equivalent REDIRECTING(reason) documented value and is set in + REDIRECTING(reason). e.g., an incoming RFC5806 'unconditional' value or a + quoted string version ('"unconditional"') is converted to + REDIRECTING(reason)'s 'cfu' value. The user's dialplan only needs to deal + with 'cfu' instead of any of the aliases. + + The incoming 480 response reason text supported by chan_sip checks for + known reason values and if not matched then puts quotes around the reason + string and assigns that to REDIRECTING(reason). + + Both channel drivers send outgoing known REDIRECTING(reason) values as the + unquoted RFC5806 equivalent. User custom values are either sent as is or + with added quotes if SIP doesn't allow a character within the value as + part of a RFC3261 Section 25.1 token. Note that there are still + limitations on what characters can be put in a custom user value. e.g., + embedding quotes in the middle of the reason string is just going to cause + you grief. + + * Setting a REDIRECTING(reason) value now recognizes RFC5806 aliases. + e.g., Setting REDIRECTING(reason) to 'unconditional' is converted to the + 'cfu' value. + res_pjproject ------------------ * This module is the successor of res_pjsip_log_forwarder. As well as diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 0b0d114820c..2d5843d91ab 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -710,7 +710,7 @@ static const struct cfsip_methods { */ static const struct sip_reasons { enum AST_REDIRECTING_REASON code; - char * const text; + const char *text; } sip_reason_table[] = { { AST_REDIRECTING_REASON_UNKNOWN, "unknown" }, { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" }, @@ -723,8 +723,8 @@ static const struct sip_reasons { { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" }, { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" }, { AST_REDIRECTING_REASON_AWAY, "away" }, - { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"}, - { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm"}, + { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte" }, /* Non-standard */ + { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm" }, /* Non-standard */ }; @@ -2375,52 +2375,54 @@ static int map_s_x(const struct _map_x_s *table, const char *s, int errorvalue) return errorvalue; } -static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text) +/*! + * \internal + * \brief Determine if the given string is a SIP token. + * \since 13.8.0 + * + * \param str String to determine if is a SIP token. + * + * \note A token is defined by RFC3261 Section 25.1 + * + * \return Non-zero if the string is a SIP token. + */ +static int sip_is_token(const char *str) { - enum AST_REDIRECTING_REASON ast = AST_REDIRECTING_REASON_UNKNOWN; - int i; + int is_token; + + if (ast_strlen_zero(str)) { + /* An empty string is not a token. */ + return 0; + } - for (i = 0; i < ARRAY_LEN(sip_reason_table); ++i) { - if (!strcasecmp(text, sip_reason_table[i].text)) { - ast = sip_reason_table[i].code; + is_token = 1; + do { + if (!isalnum(*str) + && !strchr("-.!%*_+`'~", *str)) { + /* The character is not allowed in a token. */ + is_token = 0; break; } - } + } while (*++str); - return ast; + return is_token; } -static const char *sip_reason_code_to_str(struct ast_party_redirecting_reason *reason, int *table_lookup) +static const char *sip_reason_code_to_str(struct ast_party_redirecting_reason *reason) { - int code = reason->code; + int idx; + int code; - /* If there's a specific string set, then we just - * use it. - */ + /* use specific string if given */ if (!ast_strlen_zero(reason->str)) { - /* If we care about whether this can be found in - * the table, then we need to check about that. - */ - if (table_lookup) { - /* If the string is literally "unknown" then don't bother with the lookup - * because it can lead to a false negative. - */ - if (!strcasecmp(reason->str, "unknown") || - sip_reason_str_to_code(reason->str) != AST_REDIRECTING_REASON_UNKNOWN) { - *table_lookup = TRUE; - } else { - *table_lookup = FALSE; - } - } return reason->str; } - if (table_lookup) { - *table_lookup = TRUE; - } - - if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) { - return sip_reason_table[code].text; + code = reason->code; + for (idx = 0; idx < ARRAY_LEN(sip_reason_table); ++idx) { + if (code == sip_reason_table[idx].code) { + return sip_reason_table[idx].text; + } } return "unknown"; @@ -14219,7 +14221,7 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt) { struct ast_party_id diverting_from; const char *reason; - int found_in_table; + const char *quote_str; char header_text[256]; char encoded_number[SIPBUFSIZE/2]; @@ -14244,17 +14246,18 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt) ast_copy_string(encoded_number, diverting_from.number.str, sizeof(encoded_number)); } - reason = sip_reason_code_to_str(&ast_channel_redirecting(pvt->owner)->reason, &found_in_table); + reason = sip_reason_code_to_str(&ast_channel_redirecting(pvt->owner)->reason); + + /* Reason is either already quoted or it is a token to not need quotes added. */ + quote_str = *reason == '\"' || sip_is_token(reason) ? "" : "\""; /* We at least have a number to place in the Diversion header, which is enough */ if (!diverting_from.name.valid || ast_strlen_zero(diverting_from.name.str)) { snprintf(header_text, sizeof(header_text), ";reason=%s%s%s", - encoded_number, - ast_sockaddr_stringify_host_remote(&pvt->ourip), - found_in_table ? "" : "\"", - reason, - found_in_table ? "" : "\""); + encoded_number, + ast_sockaddr_stringify_host_remote(&pvt->ourip), + quote_str, reason, quote_str); } else { char escaped_name[SIPBUFSIZE/2]; if (sip_cfg.pedanticsipchecking) { @@ -14263,12 +14266,10 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt) ast_copy_string(escaped_name, diverting_from.name.str, sizeof(escaped_name)); } snprintf(header_text, sizeof(header_text), "\"%s\" ;reason=%s%s%s", - escaped_name, - encoded_number, - ast_sockaddr_stringify_host_remote(&pvt->ourip), - found_in_table ? "" : "\"", - reason, - found_in_table ? "" : "\""); + escaped_name, + encoded_number, + ast_sockaddr_stringify_host_remote(&pvt->ourip), + quote_str, reason, quote_str); } add_header(req, "Diversion", header_text); @@ -17740,6 +17741,9 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c char *params, *reason_param = NULL; struct sip_request *req; + ast_assert(reason_code != NULL); + ast_assert(reason_str != NULL); + req = oreq ? oreq : &p->initreq; ast_copy_string(tmp, sip_get_header(req, "Diversion"), sizeof(tmp)); @@ -17773,16 +17777,6 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c if ((end = strchr(reason_param, ';'))) { *end = '\0'; } - /* Remove enclosing double-quotes */ - if (*reason_param == '"') - reason_param = ast_strip_quoted(reason_param, "\"", "\""); - if (!ast_strlen_zero(reason_param)) { - sip_set_redirstr(p, reason_param); - if (p->owner) { - pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause); - pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param); - } - } } } @@ -17814,12 +17808,27 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c } if (!ast_strlen_zero(reason_param)) { - if (reason_code) { - *reason_code = sip_reason_str_to_code(reason_param); + *reason_str = ast_strdup(reason_param); + + /* Remove any enclosing double-quotes */ + if (*reason_param == '"') { + reason_param = ast_strip_quoted(reason_param, "\"", "\""); } - if (reason_str) { - *reason_str = ast_strdup(reason_param); + *reason_code = ast_redirecting_reason_parse(reason_param); + if (*reason_code < 0) { + *reason_code = AST_REDIRECTING_REASON_UNKNOWN; + } else { + ast_free(*reason_str); + *reason_str = ast_strdup(""); + } + + if (!ast_strlen_zero(reason_param)) { + sip_set_redirstr(p, reason_param); + if (p->owner) { + pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause); + pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param); + } } } @@ -22698,10 +22707,11 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request redirecting->to.name.str = redirecting_to_name; } redirecting->reason.code = reason; + ast_free(redirecting->reason.str); + redirecting->reason.str = reason_str; if (reason_str) { - ast_debug(3, "Got redirecting reason %s\n", reason_str); - ast_free(redirecting->reason.str); - redirecting->reason.str = reason_str; + ast_debug(3, "Got redirecting reason %s\n", ast_strlen_zero(reason_str) + ? sip_reason_code_to_str(&redirecting->reason) : reason_str); } } @@ -23502,14 +23512,22 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest if (p->owner && !req->ignore) { struct ast_party_redirecting redirecting; struct ast_set_party_redirecting update_redirecting; + char *quoted_rest = ast_alloca(strlen(rest) + 3); + ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(p->owner)); memset(&update_redirecting, 0, sizeof(update_redirecting)); - redirecting.reason.code = sip_reason_str_to_code(rest); - redirecting.reason.str = ast_strdup(rest); + redirecting.reason.code = ast_redirecting_reason_parse(rest); + if (redirecting.reason.code < 0) { + sprintf(quoted_rest, "\"%s\"", rest);/* Safe */ + + redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN; + redirecting.reason.str = quoted_rest; + } else { + redirecting.reason.str = ""; + } ast_channel_queue_redirecting_update(p->owner, &redirecting, &update_redirecting); - ast_party_redirecting_free(&redirecting); ast_queue_control(p->owner, AST_CONTROL_BUSY); } diff --git a/main/callerid.c b/main/callerid.c index 69fe6ff7062..d2b32189228 100644 --- a/main/callerid.c +++ b/main/callerid.c @@ -1209,7 +1209,16 @@ static const struct ast_value_translation redirecting_reason_types[] = { { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" }, { AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" }, { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" }, - { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", "Call is being redirected to user's voicemail"}, + { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", "Call is being redirected to user's voicemail" }, + + /* Convenience SIP aliases. Alias descriptions are not used. */ + { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" }, + { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" }, + { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" }, + { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" }, + { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" }, + { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" }, + { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" }, /* *INDENT-ON* */ }; @@ -1232,7 +1241,7 @@ const char *ast_redirecting_reason_describe(int data) for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) { if (redirecting_reason_types[index].value == data) { - return redirecting_reason_types[index].description; + return redirecting_reason_types[index].description ?: "Redirecting reason alias-bug"; } } diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c index ea2c7cd1335..f1a6ddf77e5 100644 --- a/res/res_pjsip_diversion.c +++ b/res/res_pjsip_diversion.c @@ -37,6 +37,39 @@ static const pj_str_t diversion_name = { "Diversion", 9 }; +/*! + * \internal + * \brief Determine if the given string is a SIP token. + * \since 13.8.0 + * + * \param str String to determine if is a SIP token. + * + * \note A token is defined by RFC3261 Section 25.1 + * + * \return Non-zero if the string is a SIP token. + */ +static int sip_is_token(const char *str) +{ + int is_token; + + if (ast_strlen_zero(str)) { + /* An empty string is not a token. */ + return 0; + } + + is_token = 1; + do { + if (!isalnum(*str) + && !strchr("-.!%*_+`'~", *str)) { + /* The character is not allowed in a token. */ + is_token = 0; + break; + } + } while (*++str); + + return is_token; +} + /*! \brief Diversion header reasons * * The core defines a bunch of constants used to define @@ -46,7 +79,7 @@ static const pj_str_t diversion_name = { "Diversion", 9 }; */ static const struct reasons { enum AST_REDIRECTING_REASON code; - char *const text; + const char *text; } reason_table[] = { { AST_REDIRECTING_REASON_UNKNOWN, "unknown" }, { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" }, @@ -59,39 +92,28 @@ static const struct reasons { { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" }, { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" }, { AST_REDIRECTING_REASON_AWAY, "away" }, - { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"}, - { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm"}, + { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte" }, /* Non-standard */ + { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm" }, /* Non-standard */ }; static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason) { - int code = reason->code; + int idx; + int code; /* use specific string if given */ if (!ast_strlen_zero(reason->str)) { return reason->str; } - if (code >= 0 && code < ARRAY_LEN(reason_table)) { - return reason_table[code].text; - } - - return "unknown"; -} - -static enum AST_REDIRECTING_REASON reason_str_to_code(const char *text) -{ - enum AST_REDIRECTING_REASON code = AST_REDIRECTING_REASON_UNKNOWN; - int i; - - for (i = 0; i < ARRAY_LEN(reason_table); ++i) { - if (!strcasecmp(text, reason_table[i].text)) { - code = reason_table[i].code; - break; + code = reason->code; + for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) { + if (code == reason_table[idx].code) { + return reason_table[idx].text; } } - return code; + return "unknown"; } static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata) @@ -159,13 +181,31 @@ static void set_redirecting_reason(pjsip_fromto_hdr *hdr, { static const pj_str_t reason_name = { "reason", 6 }; pjsip_param *reason = pjsip_param_find(&hdr->other_param, &reason_name); + char *reason_str; if (!reason) { return; } set_redirecting_value(&data->str, &reason->value); - data->code = reason_str_to_code(data->str); + if (!data->str) { + /* Oops, allocation failure */ + return; + } + reason_str = ast_strdupa(data->str); + + /* Remove any enclosing double-quotes */ + if (*reason_str == '"') { + reason_str = ast_strip_quoted(reason_str, "\"", "\""); + } + + data->code = ast_redirecting_reason_parse(reason_str); + if (data->code < 0) { + data->code = AST_REDIRECTING_REASON_UNKNOWN; + } else { + ast_free(data->str); + data->str = ast_strdup(""); + } } static void set_redirecting(struct ast_sip_session *session, @@ -251,6 +291,9 @@ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirect pjsip_sip_uri *uri; pjsip_param *param; pjsip_fromto_hdr *old_hdr; + const char *reason_str; + const char *quote_str; + char *reason_buf; struct ast_party_id *id = &data->from; pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri; @@ -272,7 +315,17 @@ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirect param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param); param->name = pj_str("reason"); - param->value = pj_str((char*)reason_code_to_str(&data->reason)); + + reason_str = reason_code_to_str(&data->reason); + + /* Reason is either already quoted or it is a token to not need quotes added. */ + quote_str = *reason_str == '\"' || sip_is_token(reason_str) ? "" : "\""; + + reason_buf = pj_pool_alloc(tdata->pool, strlen(reason_str) + 3); + sprintf(reason_buf, "%s%s%s", quote_str, reason_str, quote_str);/* Safe */ + + param->value = pj_str(reason_buf); + pj_list_insert_before(&hdr->other_param, param); hdr->uri = (pjsip_uri *) name_addr; From 0bdbf0d8823fcf196ff534612658f40777c5ec57 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 29 Feb 2016 18:11:33 -0600 Subject: [PATCH 0240/1578] func_callerid.c: Update REDIRECTING reason documentation. Change-Id: I6e8d39b0711110a4bceafa652e58b30465e28386 --- funcs/func_callerid.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c index dee1977f4a6..133e2592240 100644 --- a/funcs/func_callerid.c +++ b/funcs/func_callerid.c @@ -373,22 +373,27 @@ ASTERISK_REGISTER_FILE() fields get/set a combined value for the corresponding ...-name-pres and ...-num-pres fields. - The allowable values for the reason + The recognized values for the reason and orig-reason fields are the following: - Unknown + Callee is Away + Call Forwarding By The Called DTE Call Forwarding Busy Call Forwarding No Reply - Callee is Unavailable - Time of Day - Do Not Disturb + Call Forwarding Unconditional Call Deflection + Do Not Disturb Follow Me Called DTE Out-Of-Order - Callee is Away - Call Forwarding By The Called DTE - Call Forwarding Unconditional + Send the call to voicemail + Time of Day + Callee is Unavailable + Unknown + You can set a user defined reason string that SIP can + send/receive instead. The user defined reason string my need to be + quoted depending upon SIP or the peer's requirements. These strings + are treated as unknown by the non-SIP channel drivers. The allowable values for the xxx-name-charset field are the following: From 60aa871be3a9a5de2d5029a19b7f8fcfb7f4ea88 Mon Sep 17 00:00:00 2001 From: Scott Griepentrog Date: Wed, 2 Mar 2016 09:34:10 -0600 Subject: [PATCH 0241/1578] CHAOS: prevent crash on failed strdup This patch avoids crashing on a null pointer if the strdup() allocation fails. ASTERISK-25323 Change-Id: I3f67434820ba53b53663efd6cbb42749f4f6c0f5 --- res/res_pjsip_messaging.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index 7532e39be56..20d1f9d9931 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -530,6 +530,10 @@ static struct msg_data* msg_data_create(const struct ast_msg *msg, const char *t /* Make sure we start with sip: */ mdata->to = ast_begins_with(to, "sip:") ? ast_strdup(++to) : ast_strdup(to - 3); mdata->from = ast_strdup(from); + if (!mdata->to || !mdata->from) { + ao2_ref(mdata, -1); + return NULL; + } /* sometimes from can still contain the tag at this point, so remove it */ if ((tag = strchr(mdata->from, ';'))) { From 0a3f0e85ace6f55fa5826c301ccaac066d24a11f Mon Sep 17 00:00:00 2001 From: Scott Griepentrog Date: Wed, 2 Mar 2016 11:17:54 -0600 Subject: [PATCH 0242/1578] CHAOS: cleanup possible null vars on msg alloc failure In message.c, if msg_alloc fails to init the string field, vars may be null, so use a null tolerant cleanup. In res_pjsip_messaging.c, if msg_data_create fails, mdata will be null, so use a null tolerant cleanup. ASTERISK-25323 Change-Id: Ic2d55c2c3750d5616e2a05ea92a19c717507ff56 --- main/message.c | 2 +- res/res_pjsip_messaging.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/message.c b/main/message.c index 7098f698d0e..54c604c47d2 100644 --- a/main/message.c +++ b/main/message.c @@ -398,7 +398,7 @@ static void msg_destructor(void *obj) struct ast_msg *msg = obj; ast_string_field_free_memory(msg); - ao2_ref(msg->vars, -1); + ao2_cleanup(msg->vars); } struct ast_msg *ast_msg_alloc(void) diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index 7532e39be56..9a31630e716 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -597,7 +597,7 @@ static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *f if (!(mdata = msg_data_create(msg, to, from)) || ast_sip_push_task(message_serializer, msg_send, mdata)) { - ao2_ref(mdata, -1); + ao2_cleanup(mdata); return -1; } return 0; From 7b71bca8a40395341920d4d329de5af1896224c5 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 2 Mar 2016 14:55:48 -0700 Subject: [PATCH 0243/1578] config_transport: Fix objects returned by ast_sip_get_transport_states ast_sip_get_transport_states was returning a container of internal_state objects instead of ast_sip_transport_state objects. This was causing transport lookups to fail, most noticably in res_pjsip_nat, which couldn't find the correct external addresses. This was causing contacts to go out with internal ip addresses. ASTERISK-25830 #close Reported-by: Sean Bright Change-Id: I1aee6a2fd46c42e8dd0af72498d17de459ac750e --- res/res_pjsip/config_transport.c | 77 +++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index e7bda5f0567..61a979c8857 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -108,6 +108,56 @@ static int internal_state_cmp(void *obj, void *arg, int flags) return CMP_MATCH; } +/*! \brief hashing function for state objects */ +static int transport_state_hash(const void *obj, const int flags) +{ + const struct ast_sip_transport_state *object; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + object = obj; + key = object->id; + break; + default: + ast_assert(0); + return 0; + } + return ast_str_hash(key); +} + +/*! \brief comparator function for state objects */ +static int transport_state_cmp(void *obj, void *arg, int flags) +{ + const struct ast_sip_transport_state *object_left = obj; + const struct ast_sip_transport_state *object_right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->id; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(object_left->id, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + /* Not supported by container. */ + ast_assert(0); + return 0; + default: + cmp = 0; + break; + } + if (cmp) { + return 0; + } + return CMP_MATCH; +} + static int sip_transport_to_ami(const struct ast_sip_transport *transport, struct ast_str **buf) { @@ -499,7 +549,6 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { pj_sock_t sock; pj_qos_params qos_params; - sock = pjsip_udp_transport_get_socket(temp_state->state->transport); pj_sock_get_qos_params(sock, &qos_params); set_qos(transport, &qos_params); @@ -657,6 +706,11 @@ static int privkey_file_to_str(const void *obj, const intptr_t *args, char **buf static int transport_protocol_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_transport *transport = obj; + RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); + + if (!state) { + return -1; + } if (!strcasecmp(var->value, "udp")) { transport->type = AST_TRANSPORT_UDP; @@ -672,6 +726,8 @@ static int transport_protocol_handler(const struct aco_option *opt, struct ast_v return -1; } + state->type = transport->type; + return 0; } @@ -1240,9 +1296,26 @@ struct ast_sip_transport_state *ast_sip_get_transport_state(const char *transpor return state->state; } +static int populate_transport_states(void *obj, void *arg, int flags) +{ + struct internal_state *state = obj; + struct ao2_container *container = arg; + + ao2_link(container, state->state); + + return CMP_MATCH; +} + struct ao2_container *ast_sip_get_transport_states(void) { - return ao2_container_clone(transport_states, 0); + struct ao2_container *states = ao2_container_alloc(DEFAULT_STATE_BUCKETS, transport_state_hash, transport_state_cmp); + + if (!states) { + return NULL; + } + + ao2_callback(transport_states, OBJ_NODATA | OBJ_MULTIPLE, populate_transport_states, states); + return states; } /*! \brief Initialize sorcery with transport support */ From b8b7c2e4280a0cd354c79896b5a38091ef718849 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 1 Mar 2016 19:03:04 -0700 Subject: [PATCH 0244/1578] alembic: Fix downgrade and tweak for sqlite Downgrade had a few issues. First there was an errant 'update' statement in add_auto_dtmf_mode that looks like it was a copy/paste error. Second, we weren't cleaning up the ENUMs so subsequent upgrades on postgres failed because the types already existed. For sqlite... sqlite doesn't support ALTER or DROP COLUMN directly. Fortunately alembic batch_operations takes care of this for us if we use it so the alter and drops were converted to use batch operations. Here's an example downgrade: with op.batch_alter_table('ps_endpoints') as batch_op: batch_op.drop_column('tos_audio') batch_op.drop_column('tos_video') batch_op.add_column(sa.Column('tos_audio', yesno_values)) batch_op.add_column(sa.Column('tos_video', yesno_values)) batch_op.drop_column('cos_audio') batch_op.drop_column('cos_video') batch_op.add_column(sa.Column('cos_audio', yesno_values)) batch_op.add_column(sa.Column('cos_video', yesno_values)) with op.batch_alter_table('ps_transports') as batch_op: batch_op.drop_column('tos') batch_op.add_column(sa.Column('tos', yesno_values)) # Can't cast integers to YESNO_VALUES, so dropping and adding is required batch_op.drop_column('cos') batch_op.add_column(sa.Column('cos', yesno_values)) Upgrades from base to head and downgrades from head to base were tested repeatedly for postgresql, mysql/mariadb, and sqlite3. Change-Id: I862b0739eb3fd45ec3412dcc13c2340e1b7baef8 --- contrib/ast-db-manage/config/env.py | 3 +- .../10aedae86a32_add_outgoing_enum_va.py | 10 +++- .../136885b81223_add_regcontext_to_pj.py | 3 +- .../154177371065_add_default_from_user.py | 3 +- ...6f1_add_moh_passthrough_option_to_pjsip.py | 3 +- ...8e8bbf6b_increase_useragent_column_size.py | 6 ++- .../189a235b3fd7_add_keep_alive_interval.py | 3 +- .../1d50859ed02e_create_accountcode.py | 3 +- .../21e526ad3040_add_pjsip_debug_option.py | 3 +- .../23530d604b96_add_rpid_immediate.py | 3 +- ..._add_bind_rtp_to_media_address_to_pjsip.py | 3 +- .../26f10cadc157_add_pjsip_timeout_options.py | 5 +- .../28b8e71e541f_add_g726_non_standard.py | 3 +- ...8ce1e718f05_add_fatal_response_interval.py | 3 +- ...078ec071b7_increaes_contact_column_size.py | 6 ++- ...1b3_add_pjsip_endpoint_options_for_12_1.py | 31 ++++++----- .../31cd4f4891ec_add_auto_dtmf_mode.py | 16 +++--- .../339a3bdf53fc_expand_accountcode_to_80.py | 18 ++++--- ...4143e_add_user_eq_phone_option_to_pjsip.py | 3 +- .../3855ee4e5f85_add_missing_pjsip_options.py | 6 ++- ...bc2c9_add_allow_reload_to_ps_transports.py | 5 +- .../423f34ad36e2_fix_pjsip_qualify_ti.py | 15 +++--- .../43956d550a44_add_tables_for_pjsip.py | 13 +++++ ...c44_add_pjsip_endpoint_identifier_order.py | 3 +- .../461d7d691209_add_pjsip_qualify_timeout.py | 9 ++-- .../498357a710ae_add_rtp_keepalive.py | 3 +- .../4c573e7135bd_fix_tos_field_types.py | 54 +++++++++---------- .../versions/4da0c5f79a9c_create_tables.py | 14 ++++- ...253c0423_make_q_member_uniqueid_autoinc.py | 33 ++++++------ .../51f8cb66540e_add_further_dtls_options.py | 5 +- .../5950038a6ead_fix_pjsip_verifiy_typo.py | 6 ++- ...dd_media_encryption_optimistic_to_pjsip.py | 3 +- ...5e89_add_pjsip_max_initial_qualify_time.py | 3 +- ...a908_add_missing_columns_to_sys_and_reg.py | 11 ++-- .../e96a0b8071c_increase_pjsip_column_size.py | 33 ++++++------ 35 files changed, 207 insertions(+), 137 deletions(-) diff --git a/contrib/ast-db-manage/config/env.py b/contrib/ast-db-manage/config/env.py index 6740d5906d5..4118da06681 100755 --- a/contrib/ast-db-manage/config/env.py +++ b/contrib/ast-db-manage/config/env.py @@ -58,7 +58,8 @@ def run_migrations_online(): connection = engine.connect() context.configure( connection=connection, - target_metadata=target_metadata + target_metadata=target_metadata, + render_as_batch=True ) try: diff --git a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py index b4ea71cbd01..cc9f0e0cc1d 100755 --- a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py +++ b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py @@ -45,7 +45,10 @@ def upgrade(): context = op.get_context() # Upgrading to this revision WILL clear your directmedia values. - if context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name == 'sqlite': + with op.batch_alter_table('sippeers') as batch_op: + batch_op.alter_column('directmedia', type_=new_type) + elif context.bind.dialect.name != 'postgresql': op.alter_column('sippeers', 'directmedia', type_=new_type, existing_type=old_type) @@ -66,7 +69,10 @@ def downgrade(): op.execute(tcr.update().where(tcr.c.directmedia==u'outgoing') .values(directmedia=None)) - if context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name == 'sqlite': + with op.batch_alter_table('sippeers') as batch_op: + batch_op.alter_column('directmedia', type_=old_type) + elif context.bind.dialect.name != 'postgresql': op.alter_column('sippeers', 'directmedia', type_=old_type, existing_type=new_type) diff --git a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py index 724a5e57695..22fd6c7b740 100644 --- a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py +++ b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py @@ -17,4 +17,5 @@ def upgrade(): op.add_column('ps_globals', sa.Column('regcontext', sa.String(80))) def downgrade(): - op.drop_column('ps_globals', 'regcontext') + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('regcontext') diff --git a/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py b/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py index 7e6cf994f61..6c5f808bba7 100644 --- a/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py +++ b/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py @@ -19,4 +19,5 @@ def upgrade(): def downgrade(): - op.drop_column('ps_globals', 'default_from_user') + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('default_from_user') diff --git a/contrib/ast-db-manage/config/versions/15b1430ad6f1_add_moh_passthrough_option_to_pjsip.py b/contrib/ast-db-manage/config/versions/15b1430ad6f1_add_moh_passthrough_option_to_pjsip.py index 54f08ff0b62..725238cab17 100644 --- a/contrib/ast-db-manage/config/versions/15b1430ad6f1_add_moh_passthrough_option_to_pjsip.py +++ b/contrib/ast-db-manage/config/versions/15b1430ad6f1_add_moh_passthrough_option_to_pjsip.py @@ -27,4 +27,5 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('moh_passthrough', yesno_values)) def downgrade(): - op.drop_column('ps_endpoints', 'moh_passthrough') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('moh_passthrough') diff --git a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py index 215726fa059..c16cff9f4a8 100755 --- a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py +++ b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py @@ -33,9 +33,11 @@ def upgrade(): - op.alter_column('sippeers', 'useragent', type_=sa.String(255)) + with op.batch_alter_table('sippeers') as batch_op: + batch_op.alter_column('useragent', type_=sa.String(255)) def downgrade(): - op.alter_column('sippeers', 'useragent', type_=sa.String(20)) + with op.batch_alter_table('sippeers') as batch_op: + batch_op.alter_column('useragent', type_=sa.String(20)) diff --git a/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py b/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py index ba972b64ed6..dee384d4c30 100644 --- a/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py +++ b/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py @@ -19,4 +19,5 @@ def upgrade(): def downgrade(): - op.drop_column('ps_globals', 'keep_alive_interval') + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('keep_alive_interval') diff --git a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py b/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py index eb200013788..4d520fcee6c 100644 --- a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py +++ b/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py @@ -17,4 +17,5 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('accountcode', sa.String(20))) def downgrade(): - op.drop_column('ps_endpoints', 'accountcode') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('accountcode') diff --git a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py index 2adca628b51..8b77eb7ac61 100755 --- a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py +++ b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py @@ -18,4 +18,5 @@ def upgrade(): op.add_column('ps_globals', sa.Column('debug', sa.String(40))) def downgrade(): - op.drop_column('ps_globals', 'debug') + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('debug') diff --git a/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py b/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py index dc0c01c24c3..8ca63f1487c 100755 --- a/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py +++ b/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py @@ -45,4 +45,5 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('rpid_immediate', yesno_values)) def downgrade(): - op.drop_column('ps_endpoints', 'rpid_immediate') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('rpid_immediate') diff --git a/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py b/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py index e7c11da1925..1199d0c8380 100644 --- a/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py +++ b/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py @@ -28,4 +28,5 @@ def upgrade(): def downgrade(): - op.drop_column('ps_endpoints', 'bind_rtp_to_media_address') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('bind_rtp_to_media_address') diff --git a/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py b/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py index 8972d80302a..2a792d3f1e9 100644 --- a/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py +++ b/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py @@ -20,5 +20,6 @@ def upgrade(): def downgrade(): - op.drop_column('ps_endpoints', 'rtp_timeout') - op.drop_column('ps_endpoints', 'rtp_timeout_hold') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('rtp_timeout') + batch_op.drop_column('rtp_timeout_hold') diff --git a/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py b/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py index ad36bd9b7cd..09056d6c408 100644 --- a/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py +++ b/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py @@ -27,4 +27,5 @@ def upgrade(): def downgrade(): - op.drop_column('ps_endpoints', 'g726_non_standard') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('g726_non_standard') diff --git a/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py index 8c499aee8c2..8e05a62a4c2 100644 --- a/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py +++ b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py @@ -19,4 +19,5 @@ def upgrade(): def downgrade(): - op.drop_column('ps_registrations', 'fatal_retry_interval') + with op.batch_alter_table('ps_registrations') as batch_op: + batch_op.drop_column('fatal_retry_interval') diff --git a/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py index 2ade86f9f3d..9f98750f615 100644 --- a/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py +++ b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py @@ -15,8 +15,10 @@ def upgrade(): - op.alter_column('ps_aors', 'contact', type_=sa.String(255)) + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.alter_column('contact', type_=sa.String(255)) def downgrade(): - op.alter_column('ps_aors', 'contact', type_=sa.String(40)) + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.alter_column('contact', type_=sa.String(40)) diff --git a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py index 564897e8649..102265ea84a 100755 --- a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py +++ b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py @@ -120,15 +120,15 @@ def upgrade(): op.create_index('ps_registrations_id', 'ps_registrations', ['id']) ########################## add columns ########################### - + with op.batch_alter_table('ps_endpoints') as batch_op: # new columns for endpoints - op.add_column('ps_endpoints', sa.Column('media_address', sa.String(40))) - op.add_column('ps_endpoints', sa.Column('redirect_method', + batch_op.add_column(sa.Column('media_address', sa.String(40))) + batch_op.add_column(sa.Column('redirect_method', pjsip_redirect_method_values)) - op.add_column('ps_endpoints', sa.Column('set_var', sa.Text())) + batch_op.add_column(sa.Column('set_var', sa.Text())) # rename mwi_fromuser to mwi_from_user - op.alter_column('ps_endpoints', 'mwi_fromuser', + batch_op.alter_column('mwi_fromuser', new_column_name='mwi_from_user', existing_type=sa.String(40)) @@ -144,20 +144,23 @@ def upgrade(): def downgrade(): ########################## drop columns ########################## - op.drop_column('ps_aors', 'support_path') - op.drop_column('ps_aors', 'outbound_proxy') - op.drop_column('ps_aors', 'maximum_expiration') + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.drop_column('support_path') + batch_op.drop_column('outbound_proxy') + batch_op.drop_column('maximum_expiration') - op.drop_column('ps_contacts', 'path') - op.drop_column('ps_contacts', 'outbound_proxy') + with op.batch_alter_table('ps_contacts') as batch_op: + batch_op.drop_column('path') + batch_op.drop_column('outbound_proxy') - op.alter_column('ps_endpoints', 'mwi_from_user', + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.alter_column('mwi_from_user', new_column_name='mwi_fromuser', existing_type=sa.String(40)) - op.drop_column('ps_endpoints', 'set_var') - op.drop_column('ps_endpoints', 'redirect_method') - op.drop_column('ps_endpoints', 'media_address') + batch_op.drop_column('set_var') + batch_op.drop_column('redirect_method') + batch_op.drop_column('media_address') ########################## drop tables ########################### diff --git a/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py index 0d84390b29c..b1a9f8be8ed 100644 --- a/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py +++ b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py @@ -20,14 +20,14 @@ old_type = sa.Enum(*OLD_ENUM, name='pjsip_dtmf_mode_values') new_type = sa.Enum(*NEW_ENUM, name='pjsip_dtmf_mode_values_v2') -tcr = sa.sql.table('ps_endpoints', sa.Column('dtmf_mode', new_type, - nullable=True)) - def upgrade(): context = op.get_context() # Upgrading to this revision WILL clear your directmedia values. - if context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name == 'sqlite': + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.alter_column('dtmf_mode', type_=new_type) + elif context.bind.dialect.name != 'postgresql': op.alter_column('ps_endpoints', 'dtmf_mode', type_=new_type, existing_type=old_type) @@ -45,10 +45,10 @@ def upgrade(): def downgrade(): context = op.get_context() - op.execute(tcr.update().where(tcr.c.directmedia==u'outgoing') - .values(directmedia=None)) - - if context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name == 'sqlite': + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.alter_column('dtmf_mode', type_=old_type) + elif context.bind.dialect.name != 'postgresql': op.alter_column('ps_endpoints', 'dtmf_mode', type_=old_type, existing_type=new_type) diff --git a/contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py b/contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py index 31889c66bbb..48911525992 100644 --- a/contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py +++ b/contrib/ast-db-manage/config/versions/339a3bdf53fc_expand_accountcode_to_80.py @@ -15,14 +15,20 @@ def upgrade(): - op.alter_column('ps_endpoints', 'accountcode', type_=sa.String(80)) - op.alter_column('sippeers', 'accountcode', type_=sa.String(80)) - op.alter_column('iaxfriends', 'accountcode', type_=sa.String(80)) + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.alter_column('accountcode', type_=sa.String(80)) + with op.batch_alter_table('sippeers') as batch_op: + batch_op.alter_column('accountcode', type_=sa.String(80)) + with op.batch_alter_table('iaxfriends') as batch_op: + batch_op.alter_column('accountcode', type_=sa.String(80)) pass def downgrade(): - op.alter_column('ps_endpoints', 'accountcode', type_=sa.String(20)) - op.alter_column('sippeers', 'accountcode', type_=sa.String(40)) - op.alter_column('iaxfriends', 'accountcode', type_=sa.String(20)) + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.alter_column('accountcode', type_=sa.String(20)) + with op.batch_alter_table('sippeers') as batch_op: + batch_op.alter_column('accountcode', type_=sa.String(40)) + with op.batch_alter_table('iaxfriends') as batch_op: + batch_op.alter_column('accountcode', type_=sa.String(20)) pass diff --git a/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py b/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py index 145d6bea652..5de7aa862be 100644 --- a/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py +++ b/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py @@ -27,4 +27,5 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('user_eq_phone', yesno_values)) def downgrade(): - op.drop_column('ps_endpoints', 'user_eq_phone') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('user_eq_phone') diff --git a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py b/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py index afc1beb3775..08457a9d8c6 100644 --- a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py +++ b/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py @@ -20,5 +20,7 @@ def upgrade(): def downgrade(): - op.drop_column('ps_contacts', 'user_agent') - op.drop_column('ps_endpoints', 'message_context') + with op.batch_alter_table('ps_contacts') as batch_op: + batch_op.drop_column('user_agent') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('message_context') diff --git a/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py index 377179b045d..7f2c5797855 100644 --- a/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py +++ b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py @@ -20,8 +20,7 @@ def upgrade(): yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) op.add_column('ps_transports', sa.Column('allow_reload', yesno_values)) - pass def downgrade(): - op.drop_column('ps_transports', 'allow_reload') - pass + with op.batch_alter_table('ps_transports') as batch_op: + batch_op.drop_column('allow_reload') diff --git a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py index cda0b9af570..563b98d08a9 100644 --- a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py +++ b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py @@ -15,12 +15,13 @@ def upgrade(): - op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Float) - op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Float) - pass - + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.alter_column('qualify_timeout', type_=sa.Float) + with op.batch_alter_table('ps_contacts') as batch_op: + batch_op.alter_column('qualify_timeout', type_=sa.Float) def downgrade(): - op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Integer) - op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Integer) - pass + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.alter_column('qualify_timeout', type_=sa.Integer) + with op.batch_alter_table('ps_contacts') as batch_op: + batch_op.alter_column('qualify_timeout', type_=sa.Integer) diff --git a/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py b/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py index 0c4d9c8f80a..140fe5b93f2 100755 --- a/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py +++ b/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py @@ -12,6 +12,7 @@ from alembic import op import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM YESNO_VALUES = ['yes', 'no'] @@ -181,9 +182,21 @@ def upgrade(): def downgrade(): + context = op.get_context() + op.drop_table('ps_endpoints') op.drop_table('ps_auths') op.drop_table('ps_aors') op.drop_table('ps_contacts') op.drop_table('ps_domain_aliases') op.drop_table('ps_endpoint_id_ips') + + enums = ['yesno_values', + 'pjsip_100rel_values','pjsip_auth_type_values','pjsip_cid_privacy_values', + 'pjsip_connected_line_method_values','pjsip_direct_media_glare_mitigation_values', + 'pjsip_dtls_setup_values','pjsip_dtmf_mode_values','pjsip_identify_by_values', + 'pjsip_media_encryption_values','pjsip_t38udptl_ec_values','pjsip_timer_values'] + + if context.bind.dialect.name == 'postgresql': + for e in enums: + ENUM(name=e).drop(op.get_bind(), checkfirst=False) diff --git a/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py b/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py index b7d99249325..b09acf7a3f7 100644 --- a/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py +++ b/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py @@ -18,4 +18,5 @@ def upgrade(): op.add_column('ps_globals', sa.Column('endpoint_identifier_order', sa.String(40))) def downgrade(): - op.drop_column('ps_globals', 'endpoint_identifier_order') + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('endpoint_identifier_order') diff --git a/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py b/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py index 9600c04611b..ec8a90449fb 100644 --- a/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py +++ b/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py @@ -16,10 +16,9 @@ def upgrade(): op.add_column('ps_aors', sa.Column('qualify_timeout', sa.Integer)) op.add_column('ps_contacts', sa.Column('qualify_timeout', sa.Integer)) - pass - def downgrade(): - op.drop_column('ps_aors', 'qualify_timeout') - op.drop_column('ps_contacts', 'qualify_timeout') - pass + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.drop_column('qualify_timeout') + with op.batch_alter_table('ps_contacts') as batch_op: + batch_op.drop_column('qualify_timeout') diff --git a/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py index 5a4f470aad0..3ad26509b25 100644 --- a/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py +++ b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py @@ -19,4 +19,5 @@ def upgrade(): def downgrade(): - op.drop_column('ps_endpoints', 'rtp_keepalive') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('rtp_keepalive') diff --git a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py index aefddd12eb1..d9bbf8977df 100755 --- a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py +++ b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py @@ -19,43 +19,43 @@ YESNO_VALUES = ['yes', 'no'] def upgrade(): - op.alter_column('ps_endpoints', 'tos_audio', + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.alter_column('tos_audio', type_=sa.String(10)) - op.alter_column('ps_endpoints', 'tos_video', + batch_op.alter_column('tos_video', type_=sa.String(10)) - op.alter_column('ps_transports', 'tos', + batch_op.drop_column('cos_audio') + batch_op.drop_column('cos_video') + batch_op.add_column(sa.Column('cos_audio', sa.Integer)) + batch_op.add_column(sa.Column('cos_video', sa.Integer)) + + with op.batch_alter_table('ps_transports') as batch_op: + batch_op.alter_column('tos', type_=sa.String(10)) # Can't cast YENO_VALUES to Integers, so dropping and adding is required - op.drop_column('ps_endpoints', 'cos_audio') - op.drop_column('ps_endpoints', 'cos_video') - op.drop_column('ps_transports', 'cos') - - op.add_column('ps_endpoints', sa.Column('cos_audio', sa.Integer)) - op.add_column('ps_endpoints', sa.Column('cos_video', sa.Integer)) - op.add_column('ps_transports', sa.Column('cos', sa.Integer)) - pass + batch_op.drop_column('cos') + batch_op.add_column(sa.Column('cos', sa.Integer)) def downgrade(): yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) # Can't cast string to YESNO_VALUES, so dropping and adding is required - op.drop_column('ps_endpoints', 'tos_audio') - op.drop_column('ps_endpoints', 'tos_video') - op.drop_column('ps_transports', 'tos') - - op.add_column('ps_endpoints', sa.Column('tos_audio', yesno_values)) - op.add_column('ps_endpoints', sa.Column('tos_video', yesno_values)) - op.add_column('ps_transports', sa.Column('tos', yesno_values)) - + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('tos_audio') + batch_op.drop_column('tos_video') + batch_op.add_column(sa.Column('tos_audio', yesno_values)) + batch_op.add_column(sa.Column('tos_video', yesno_values)) + batch_op.drop_column('cos_audio') + batch_op.drop_column('cos_video') + batch_op.add_column(sa.Column('cos_audio', yesno_values)) + batch_op.add_column(sa.Column('cos_video', yesno_values)) + + with op.batch_alter_table('ps_transports') as batch_op: + batch_op.drop_column('tos') + batch_op.add_column(sa.Column('tos', yesno_values)) # Can't cast integers to YESNO_VALUES, so dropping and adding is required - op.drop_column('ps_endpoints', 'cos_audio') - op.drop_column('ps_endpoints', 'cos_video') - op.drop_column('ps_transports', 'cos') - - op.add_column('ps_endpoints', sa.Column('cos_audio', yesno_values)) - op.add_column('ps_endpoints', sa.Column('cos_video', yesno_values)) - op.add_column('ps_transports', sa.Column('cos', yesno_values)) - pass + batch_op.drop_column('cos') + batch_op.add_column(sa.Column('cos', yesno_values)) diff --git a/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py b/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py index ffaff9295c4..01c40acbc10 100755 --- a/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py +++ b/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py @@ -30,7 +30,7 @@ from alembic import op import sqlalchemy as sa - +from sqlalchemy.dialects.postgresql import ENUM YESNO_VALUES = ['yes', 'no'] TYPE_VALUES = ['friend', 'user', 'peer'] @@ -323,8 +323,20 @@ def upgrade(): def downgrade(): + context = op.get_context() + op.drop_table('sippeers') op.drop_table('iaxfriends') op.drop_table('voicemail') op.drop_table('meetme') op.drop_table('musiconhold') + + enums = ['type_values', 'yes_no_values', + 'sip_transport_values','sip_dtmfmode_values','sip_directmedia_values', + 'sip_progressinband_values','sip_session_timers_values','sip_session_refresher_values', + 'sip_callingpres_values','iax_requirecalltoken_values','iax_encryption_values', + 'iax_transfer_values','moh_mode_values'] + + if context.bind.dialect.name == 'postgresql': + for e in enums: + ENUM(name=e).drop(op.get_bind(), checkfirst=False) diff --git a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py index 6bcaa9a1029..632f4c4eb14 100755 --- a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py +++ b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py @@ -33,28 +33,31 @@ def upgrade(): + context = op.get_context() # Was unable to find a way to use op.alter_column() to add the unique # index property. - op.drop_column('queue_members', 'uniqueid') - op.add_column( - 'queue_members', - sa.Column( - name='uniqueid', type_=sa.Integer, nullable=False, - unique=True)) + if context.bind.dialect.name == 'sqlite': + with op.batch_alter_table('queue_members') as batch_op: + batch_op.create_primary_key('queue_members_pj', columns='uniqueid') + else: + op.drop_column('queue_members', 'uniqueid') + op.add_column( + 'queue_members', + sa.Column( + name='uniqueid', type_=sa.Integer, nullable=False, + unique=True)) # The postgres backend does not like the autoincrement needed for # mysql here. It is just the backend that is giving a warning and # not the database itself. - op.alter_column( - table_name='queue_members', column_name='uniqueid', - existing_type=sa.Integer, existing_nullable=False, - autoincrement=True) + op.alter_column( + table_name='queue_members', column_name='uniqueid', + existing_type=sa.Integer, existing_nullable=False, + autoincrement=True) def downgrade(): # Was unable to find a way to use op.alter_column() to remove the # unique index property. - op.drop_column('queue_members', 'uniqueid') - op.add_column( - 'queue_members', - sa.Column(name='uniqueid', type_=sa.String(80), nullable=False)) - + with op.batch_alter_table('queue_members') as batch_op: + batch_op.drop_column('uniqueid') + batch_op.add_column(sa.Column(name='uniqueid', type_=sa.String(80), nullable=False)) diff --git a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py b/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py index c2dacda2c68..8d0f68f03d9 100644 --- a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py +++ b/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py @@ -28,5 +28,6 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('media_use_received_transport', yesno_values)) def downgrade(): - op.drop_column('ps_endpoints', 'force_avp') - op.drop_column('ps_endpoints', 'media_use_received_transport') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('force_avp') + batch_op.drop_column('media_use_received_transport') diff --git a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py b/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py index 28ebc8b1773..ace5444231d 100644 --- a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py +++ b/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py @@ -19,11 +19,13 @@ def upgrade(): yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) - op.alter_column('ps_transports', 'verifiy_server', type_=yesno_values, + with op.batch_alter_table('ps_transports') as batch_op: + batch_op.alter_column('verifiy_server', type_=yesno_values, new_column_name='verify_server') def downgrade(): yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) - op.alter_column('ps_transports', 'verify_server', type_=yesno_values, + with op.batch_alter_table('ps_transports') as batch_op: + batch_op.alter_column('verify_server', type_=yesno_values, new_column_name='verifiy_server') diff --git a/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py b/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py index 7a463f05753..fff25040342 100644 --- a/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py +++ b/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py @@ -28,4 +28,5 @@ def upgrade(): def downgrade(): - op.drop_column('ps_endpoints', 'media_encryption_optimistic') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('media_encryption_optimistic') diff --git a/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py b/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py index 0ffd7848da2..dc06d84ef1e 100644 --- a/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py +++ b/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py @@ -17,4 +17,5 @@ def upgrade(): op.add_column('ps_globals', sa.Column('max_initial_qualify_time', sa.Integer)) def downgrade(): - op.drop_column('ps_globals', 'max_initial_qualify_time') + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('max_initial_qualify_time') diff --git a/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py index 8f4621642de..b4502eb3d13 100644 --- a/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py +++ b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py @@ -27,11 +27,10 @@ def upgrade(): op.add_column('ps_systems', sa.Column('disable_tcp_switch', yesno_values)) op.add_column('ps_registrations', sa.Column('line', yesno_values)) op.add_column('ps_registrations', sa.Column('endpoint', sa.String(40))) - pass - def downgrade(): - op.drop_column('ps_systems', 'disable_tcp_switch') - op.drop_column('ps_registrations', 'line') - op.drop_column('ps_registrations', 'endpoint') - pass + with op.batch_alter_table('ps_systems') as batch_op: + batch_op.drop_column('disable_tcp_switch') + with op.batch_alter_table('ps_registrations') as batch_op: + batch_op.drop_column('line') + batch_op.drop_column('endpoint') diff --git a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py b/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py index d386ded3fb8..f25c2987e6f 100644 --- a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py +++ b/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py @@ -15,25 +15,28 @@ def upgrade(): - op.alter_column('ps_globals', 'user_agent', type_=sa.String(255)) + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.alter_column('user_agent', type_=sa.String(255)) - op.alter_column('ps_contacts', 'id', type_=sa.String(255)) - op.alter_column('ps_contacts', 'uri', type_=sa.String(255)) - op.alter_column('ps_contacts', 'user_agent', type_=sa.String(255)) + with op.batch_alter_table('ps_contacts') as batch_op: + batch_op.alter_column('id', type_=sa.String(255)) + batch_op.alter_column('uri', type_=sa.String(255)) + batch_op.alter_column('user_agent', type_=sa.String(255)) - op.alter_column('ps_registrations', 'client_uri', type_=sa.String(255)) - op.alter_column('ps_registrations', 'server_uri', type_=sa.String(255)) + with op.batch_alter_table('ps_registrations') as batch_op: + batch_op.alter_column('client_uri', type_=sa.String(255)) + batch_op.alter_column('server_uri', type_=sa.String(255)) def downgrade(): - op.alter_column('ps_registrations', 'server_uri', type_=sa.String(40)) - op.alter_column('ps_registrations', 'client_uri', type_=sa.String(40)) - - op.alter_column('ps_contacts', 'user_agent', type_=sa.String(40)) - op.alter_column('ps_contacts', 'uri', type_=sa.String(40)) - op.alter_column('ps_contacts', 'id', type_=sa.String(40)) - - op.alter_column('ps_globals', 'user_agent', type_=sa.String(40)) - + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.alter_column('user_agent', type_=sa.String(40)) + with op.batch_alter_table('ps_contacts') as batch_op: + batch_op.alter_column('id', type_=sa.String(40)) + batch_op.alter_column('uri', type_=sa.String(40)) + batch_op.alter_column('user_agent', type_=sa.String(40)) + with op.batch_alter_table('ps_registrations') as batch_op: + batch_op.alter_column('client_uri', type_=sa.String(40)) + batch_op.alter_column('server_uri', type_=sa.String(40)) From 6af7fc4c37b314ba2bf3380d44c7e4ac409787e2 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 3 Mar 2016 10:26:10 -0400 Subject: [PATCH 0245/1578] res_pjsip_dtmf_info: NULL terminate the message body. PJSIP does not ensure that when printing the message body the buffer will be NULL terminated. This is problematic when searching for the signal and duration values of the DTMF. This change ensures the buffer is always NULL terminated. Change-Id: I52653a1a60c93092d06af31a27408d569cc98968 --- res/res_pjsip_dtmf_info.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_dtmf_info.c b/res/res_pjsip_dtmf_info.c index 78d529c30b1..47ccd1ae5cd 100644 --- a/res/res_pjsip_dtmf_info.c +++ b/res/res_pjsip_dtmf_info.c @@ -82,14 +82,13 @@ static char get_event(const char *c) static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) { pjsip_msg_body *body = rdata->msg_info.msg->body; - char buf[body ? body->len : 0]; + char buf[body ? body->len + 1 : 1]; char *cur = buf; char *line; - char event = '\0'; unsigned int duration = 100; - char is_dtmf; + int res; if (!session->channel) { return 0; @@ -107,7 +106,12 @@ static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pj return 0; } - body->print_body(body, buf, body->len); + res = body->print_body(body, buf, body->len); + if (res < 0) { + send_response(session, rdata, 500); + return 0; + } + buf[res] = '\0'; if (is_dtmf) { /* directly use what is in the message body */ From 0d2ccbca62e09dbf57ecfc921a33e4e08bbe462f Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 1 Mar 2016 18:08:52 -0600 Subject: [PATCH 0246/1578] res_pjsip_refer.c: Delay sending the initial SIP Notify with frag 100 During the transfer process, some phones (okay it was the Jitsi softphone, but maybe others are out there) send a "bye" immediately after receiving a SIP Notify. When a "bye" is received early for some types of transfers the transferer channel may no longer be available during late stage transfer processing. For instance, during an attended transfer involving stasis bridging at one point the created local channel looks for an associated swap channel in order to retrieve the stasis application name. If the transferer has hung up then the local channel will fail to find it. The local channel then has no way to know which stasis app to enter, so it fails and hangs up as well. Thus the transfer does not complete as expected. This patch delays the sending of the initial notify in order to give the transfer process enough time to gather the necessary data for a successful transfer. ASTERISK-25771 Change-Id: I09cfc9a5d6ed4c007bc70625e0972b470393bf16 --- res/res_pjsip_refer.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index f89f901cf0f..fbc3eb3e245 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -59,6 +59,8 @@ struct refer_progress { struct transfer_channel_data *transfer_data; /*! \brief Uniqueid of transferee channel */ char *transferee; + /*! \brief Non-zero if the 100 notify has been sent */ + int sent_100; }; /*! \brief REFER Progress notification structure */ @@ -133,6 +135,18 @@ static int refer_progress_notify(void *data) notification->progress->sub = NULL; } + /* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */ + if (!notification->progress->sent_100) { + notification->progress->sent_100 = 1; + if (notification->response != 100) { + ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n", + notification->progress); + if (pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) { + pjsip_xfer_send_request(sub, tdata); + } + } + } + ast_debug(3, "Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p'\n", notification->response, notification->state, sub, notification->progress); @@ -340,7 +354,6 @@ static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data * const pj_str_t str_refer_sub = { "Refer-Sub", 9 }; pjsip_generic_string_hdr *refer_sub = NULL; const pj_str_t str_true = { "true", 4 }; - pjsip_tx_data *tdata; pjsip_hdr hdr_list; char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; @@ -392,12 +405,6 @@ static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data * ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress); pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list); - /* Send initial NOTIFY Request */ - ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n", *progress); - if (pjsip_xfer_notify((*progress)->sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) { - pjsip_xfer_send_request((*progress)->sub, tdata); - } - return 0; error: From 15c5743ac1371535441e2111499d848dd9c5ff52 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 1 Mar 2016 16:18:21 -0600 Subject: [PATCH 0247/1578] bridge.c: Crash during attended transfer when missing a local channel half It's possible for the transferer channel to get hung up early during the attended transfer process. For instance, a phone may send a "bye" immediately upon receiving a sip notify that contains a sip frag 100 (I'm looking at you Jitsi). When this occurs a race begins between the transferer being hung up and completion of the transfer code. If the channel hangs up too early during a transfer involving stasis bridging for instance, then when the created local channel goes to look up its swap channel (and associated datastore) it can't find it (since it is no longer in the bridge) thus it fails to enter the stasis application. Consequently, the created local channel(s) hang up as well. If the timing is just right then the bridging code attempts to add the message link with missing local channel(s). Hence the crash. Unfortunately, there is no great way to solve the problem of the unexpected "bye". While we can't guarantee we won't receive an early hangup, and in this case still fail to enter the stasis application, we can make it so asterisk does not crash. This patch does just that by locking the local channel structure, checking that the local channel's peer has not been lost, and then continuing. This keeps the local channel's peer from being ripped out from underneath it by the local/unreal hangup code while attempting to set the stasis message link. ASTERISK-25771 Change-Id: Ie6d6061e34c7c95f07116fffac9a09e5d225c880 --- include/asterisk/core_local.h | 32 ++++++++++++++++++++++++++++ main/bridge.c | 22 +++++++++++++------- main/core_local.c | 39 +++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 8 deletions(-) diff --git a/include/asterisk/core_local.h b/include/asterisk/core_local.h index 491112d2bf0..8557072c69b 100644 --- a/include/asterisk/core_local.h +++ b/include/asterisk/core_local.h @@ -41,6 +41,38 @@ struct stasis_message_type; /* ------------------------------------------------------------------- */ +/*! + * \brief Lock the "chan" and "owner" channels (and return them) on the base + * private structure as well as the base private structure itself. + * + * \note This also adds references to each of the above mentioned elements and + * also the underlying private local structure. + * \note None of these locks should be held prior to calling this function. + * \note To undo this process call ast_local_unlock_all. + * + * \since 13.8.0 + * + * \param chan Must be a local channel + * \param outchan The local channel's "chan" channel + * \param outowner The local channel's "owner" channel + */ +void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan, + struct ast_channel **outowner); + +/*! + * \brief Unlock the "chan" and "owner" channels on the base private structure + * as well as the base private structure itself. + * + * \note This also removes references to each of the above mentioned elements and + * also the underlying private local structure. + * \note This function should be used in conjunction with ast_local_lock_all. + * + * \since 13.8.0 + * + * \param chan Must be a local channel + */ +void ast_local_unlock_all(struct ast_channel *chan); + /*! * \brief Get the other local channel in the pair. * \since 12.0.0 diff --git a/main/bridge.c b/main/bridge.c index 77865757ea3..b9a436e86a5 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -4034,19 +4034,25 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2); if (bridge2) { - RAII_VAR(struct ast_channel *, local_chan2, NULL, ao2_cleanup); struct ast_channel *locals[2]; - ast_channel_lock(local_chan); - local_chan2 = ast_local_get_peer(local_chan); - ast_channel_unlock(local_chan); - - ast_assert(local_chan2 != NULL); + /* Have to lock everything just in case a hangup comes in early */ + ast_local_lock_all(local_chan, &locals[0], &locals[1]); + if (!locals[0] || !locals[1]) { + ast_log(LOG_ERROR, "Transfer failed probably due to an early hangup - " + "missing other half of '%s'\n", ast_channel_name(local_chan)); + ast_local_unlock_all(local_chan); + ao2_cleanup(local_chan); + return AST_BRIDGE_TRANSFER_FAIL; + } - locals[0] = local_chan; - locals[1] = local_chan2; + /* Make sure the peer is properly set */ + if (local_chan != locals[0]) { + SWAP(locals[0], locals[1]); + } ast_attended_transfer_message_add_link(transfer_msg, locals); + ast_local_unlock_all(local_chan); } else { ast_attended_transfer_message_add_app(transfer_msg, app, local_chan); } diff --git a/main/core_local.c b/main/core_local.c index f81c71cd614..6644aaf5094 100644 --- a/main/core_local.c +++ b/main/core_local.c @@ -235,6 +235,45 @@ struct local_pvt { char exten[AST_MAX_EXTENSION]; }; +void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan, + struct ast_channel **outowner) +{ + struct local_pvt *p = ast_channel_tech_pvt(chan); + + *outchan = NULL; + *outowner = NULL; + + if (p) { + ao2_ref(p, 1); + ast_unreal_lock_all(&p->base, outchan, outowner); + } +} + +void ast_local_unlock_all(struct ast_channel *chan) +{ + struct local_pvt *p = ast_channel_tech_pvt(chan); + struct ast_unreal_pvt *base; + + if (!p) { + return; + } + + base = &p->base; + + if (base->owner) { + ast_channel_unlock(base->owner); + ast_channel_unref(base->owner); + } + + if (base->chan) { + ast_channel_unlock(base->chan); + ast_channel_unref(base->chan); + } + + ao2_unlock(base); + ao2_ref(p, -1); +} + struct ast_channel *ast_local_get_peer(struct ast_channel *ast) { struct local_pvt *p = ast_channel_tech_pvt(ast); From 195100e770e3a6f5252be85187539149df7c6781 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 23 Jan 2016 14:50:57 -0700 Subject: [PATCH 0248/1578] loader: Retry dlopen when loading fails Although we use the RTLD_LAZY flag when calling dlopen the first time on a module, this only defers resolution for function calls. Pointer references to functions are determined at link time so dlopen expects them to be there. Since we don't cross-module link, pointers to functions in other modules won't be available and dlopen will fail. Doing a "hardened" build also causes problems because it typically sets "-z now" on the ld command line which overrides RTLD_LAZY at run time. If the failing module isn't a GLOBAL_SYMBOLS module, then dlopen will be called again after all the GLOBAL_SYMBOLS modules have been loaded and they'll eventually resolve. If the calling module IS a GLOBAL_SYMBOLS module itself and a third module depends on it, then there's an issue because the second time through the dlopen loop, GLOBAL_SYMBOLS modules aren't given any special treatment and since the order in which dlopen is called isn't deterministic, the dependent may again be tried before the module it needs is loaded. Simple solution: Save modules that fail load_resource because of a dlopen error in a list and retry them immediately after the first pass. Keep retrying until the failed list is empty or we reach a #defined max retries. Error messages are suppressed until the final pass which also gets rid of those confusing error messages about module failures that are later corrected. Change-Id: Iddae1d97cd2f00b94e61662447432765755f64bb --- main/loader.c | 120 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 21 deletions(-) diff --git a/main/loader.c b/main/loader.c index 954b288b3d4..f9592217384 100644 --- a/main/loader.c +++ b/main/loader.c @@ -515,9 +515,11 @@ static void unload_dynamic_module(struct ast_module *mod) #endif } -static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required); +static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required); -static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, struct ast_heap *resource_heap) +#define MODULE_LOCAL_ONLY (void *)-1 + +static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap) { char fn[PATH_MAX] = ""; void *lib = NULL; @@ -545,8 +547,10 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned if (missing_so) strcat(resource_being_loaded->resource, ".so"); - if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) { - ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); + if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL))) { + if (!suppress_logging) { + ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); + } ast_free(resource_being_loaded); return NULL; } @@ -573,7 +577,7 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned and this one does not, then close it and return */ if (global_symbols_only && !wants_global) { logged_dlclose(resource_in, lib); - return NULL; + return MODULE_LOCAL_ONLY; } logged_dlclose(resource_in, lib); @@ -1053,7 +1057,7 @@ static enum ast_module_load_result start_resource(struct ast_module *mod) * * If the ast_heap is not provided, the module's load function will be executed * immediately */ -static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required) +static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required) { struct ast_module *mod; enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; @@ -1067,14 +1071,15 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi return AST_MODULE_LOAD_SKIP; } else { #ifdef LOADABLE_MODULES - if (!(mod = load_dynamic_module(resource_name, global_symbols_only, resource_heap))) { - /* don't generate a warning message during load_modules() */ + mod = load_dynamic_module(resource_name, global_symbols_only, suppress_logging, resource_heap); + if (mod == MODULE_LOCAL_ONLY) { + return AST_MODULE_LOAD_SKIP; + } + if (!mod) { if (!global_symbols_only) { ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); - return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; - } else { - return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP; } + return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; } #else ast_log(LOG_WARNING, "Module support is not available. Module '%s' could not be loaded.\n", resource_name); @@ -1111,7 +1116,7 @@ int ast_load_resource(const char *resource_name) { int res; AST_DLLIST_LOCK(&module_list); - res = load_resource(resource_name, 0, NULL, 0); + res = load_resource(resource_name, 0, 0, NULL, 0); if (!res) { ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name); } @@ -1168,6 +1173,8 @@ static int mod_load_cmp(void *a, void *b) return b_pri - a_pri; } +AST_LIST_HEAD_NOLOCK(load_retries, load_order_entry); + /*! loads modules in order by load_pri, updates mod_count \return -1 on failure to load module, -2 on failure to load required module, otherwise 0 */ @@ -1176,8 +1183,13 @@ static int load_resource_list(struct load_order *load_order, unsigned int global struct ast_heap *resource_heap; struct load_order_entry *order; struct ast_module *mod; + struct load_retries load_retries; int count = 0; int res = 0; + int i = 0; +#define LOAD_RETRIES 4 + + AST_LIST_HEAD_INIT_NOLOCK(&load_retries); if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) { return -1; @@ -1185,21 +1197,34 @@ static int load_resource_list(struct load_order *load_order, unsigned int global /* first, add find and add modules to heap */ AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) { - switch (load_resource(order->resource, global_symbols, resource_heap, order->required)) { + enum ast_module_load_result lres; + + /* Suppress log messages unless this is the last pass */ + lres = load_resource(order->resource, global_symbols, 1, resource_heap, order->required); + ast_debug(3, "PASS 0: %-46s %d %d\n", order->resource, lres, global_symbols); + switch (lres) { case AST_MODULE_LOAD_SUCCESS: + /* We're supplying a heap so SUCCESS isn't possible but we still have to test for it. */ + break; + case AST_MODULE_LOAD_FAILURE: case AST_MODULE_LOAD_DECLINE: + /* + * DECLINE or FAILURE means there was an issue with dlopen or module_register + * which might be retryable. LOAD_FAILURE only happens for required modules + * but we're still going to retry. We need to remove the entry from the + * load_order list and add it to the load_retries list. + */ AST_LIST_REMOVE_CURRENT(entry); - ast_free(order->resource); - ast_free(order); + AST_LIST_INSERT_TAIL(&load_retries, order, entry); break; - case AST_MODULE_LOAD_FAILURE: - ast_log(LOG_ERROR, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required"); - fprintf(stderr, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required"); - res = order->required ? -2 : -1; - goto done; case AST_MODULE_LOAD_SKIP: + /* + * SKIP means that dlopen worked but global_symbols was set and this module doesn't qualify. + * Leave it in load_order for the next call of load_resource_list. + */ break; case AST_MODULE_LOAD_PRIORITY: + /* load_resource worked and the module was added to the priority heap */ AST_LIST_REMOVE_CURRENT(entry); ast_free(order->resource); ast_free(order); @@ -1208,9 +1233,56 @@ static int load_resource_list(struct load_order *load_order, unsigned int global } AST_LIST_TRAVERSE_SAFE_END; + /* Retry the failures until the list is empty or we reach LOAD_RETRIES */ + for (i = 0; !AST_LIST_EMPTY(&load_retries) && i < LOAD_RETRIES; i++) { + AST_LIST_TRAVERSE_SAFE_BEGIN(&load_retries, order, entry) { + enum ast_module_load_result lres; + + /* Suppress log messages unless this is the last pass */ + lres = load_resource(order->resource, global_symbols, (i < LOAD_RETRIES - 1), resource_heap, order->required); + ast_debug(3, "PASS %d %-46s %d %d\n", i + 1, order->resource, lres, global_symbols); + switch (lres) { + /* These are all retryable. */ + case AST_MODULE_LOAD_SUCCESS: + case AST_MODULE_LOAD_DECLINE: + break; + case AST_MODULE_LOAD_FAILURE: + /* LOAD_FAILURE only happens for required modules */ + if (i == LOAD_RETRIES - 1) { + /* This was the last chance to load a required module*/ + ast_log(LOG_ERROR, "*** Failed to load module %s - Required\n", order->resource); + fprintf(stderr, "*** Failed to load module %s - Required\n", order->resource); + res = -2; + goto done; + } + break;; + case AST_MODULE_LOAD_SKIP: + /* + * SKIP means that dlopen worked but global_symbols was set and this module + * doesn't qualify. Put it back in load_order for the next call of + * load_resource_list. + */ + AST_LIST_REMOVE_CURRENT(entry); + AST_LIST_INSERT_TAIL(load_order, order, entry); + break; + case AST_MODULE_LOAD_PRIORITY: + /* load_resource worked and the module was added to the priority heap */ + AST_LIST_REMOVE_CURRENT(entry); + ast_free(order->resource); + ast_free(order); + break; + } + } + AST_LIST_TRAVERSE_SAFE_END; + } + /* second remove modules from heap sorted by priority */ while ((mod = ast_heap_pop(resource_heap))) { - switch (start_resource(mod)) { + enum ast_module_load_result lres; + + lres = start_resource(mod); + ast_debug(3, "START: %-46s %d %d\n", mod->resource, lres, global_symbols); + switch (lres) { case AST_MODULE_LOAD_SUCCESS: count++; case AST_MODULE_LOAD_DECLINE: @@ -1225,6 +1297,12 @@ static int load_resource_list(struct load_order *load_order, unsigned int global } done: + + while ((order = AST_LIST_REMOVE_HEAD(&load_retries, entry))) { + ast_free(order->resource); + ast_free(order); + } + if (mod_count) { *mod_count += count; } From 37472f7398626742fe0f426ca3a55124bcef4e45 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 3 Mar 2016 16:34:51 -0700 Subject: [PATCH 0249/1578] third_party/Makefile.rules: Replace unsupported != operator with $(shell ...) Apparently the != operator is fairly new so I've replaced it with the old $(shell ...) syntax. Change-Id: I16b2e1878a4f91e7e9740abd427f9639f933c479 Reported-by: Richard Mudgett --- third-party/Makefile.rules | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/third-party/Makefile.rules b/third-party/Makefile.rules index ac4189ac4d8..e633e0e9899 100644 --- a/third-party/Makefile.rules +++ b/third-party/Makefile.rules @@ -1,25 +1,24 @@ ifeq ($(NOISY_BUILD),) - SUBMAKE?=$(MAKE) --quiet --no-print-directory - ECHO_PREFIX?=@ - CMD_PREFIX?=@ - QUIET_CONFIGURE=-q - REALLY_QUIET=&>/dev/null +SUBMAKE?=$(MAKE) --quiet --no-print-directory +ECHO_PREFIX?=@ +CMD_PREFIX?=@ +QUIET_CONFIGURE=-q +REALLY_QUIET=&>/dev/null else - SUBMAKE?=$(MAKE) - ECHO_PREFIX?=@\# - CMD_PREFIX?= - QUIET_CONFIGURE= - REALLY_QUIET= +SUBMAKE?=$(MAKE) +ECHO_PREFIX?=@\# +CMD_PREFIX?= +QUIET_CONFIGURE= +REALLY_QUIET= endif -DOWNLOAD := -DOWNLOAD != which wget 2>/dev/null -DOWNLOAD:=$(if $(DOWNLOAD),$(DOWNLOAD) -O- ,) +DOWNLOAD := $(shell which wget 2>/dev/null) +DOWNLOAD := $(if $(DOWNLOAD),$(DOWNLOAD) -O- ,) ifeq ($(DOWNLOAD),) -DOWNLOAD != which curl 2>/dev/null -DOWNLOAD:=$(if $(DOWNLOAD), $(DOWNLOAD) -L ,) +DOWNLOAD := $(shell which curl 2>/dev/null) +DOWNLOAD := $(if $(DOWNLOAD), $(DOWNLOAD) -L ,) endif ifeq ($(DOWNLOAD),) From 2b9849625cc6a64bafc6f3f4f4e30d6a4af2e0ca Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 24 Feb 2016 16:25:09 -0700 Subject: [PATCH 0250/1578] res_pjsip_caller_id: Anonymize 'From' when caller id presentation is prohibited Per RFC3325, the 'From' header is now anonymized on outgoing calls when caller id presentation is prohibited. TID = trust_id_outbound PRO = Set(CALLERID(pres)=prohib) USR = endpoint/from_user DOM = endpoint/from_domain PAI = YES(privacy=off), NO(not sent), PRI(privacy=full) (assumes send_pai=yes) Conditions |Result --------------------|---------------------------------------------------- TID PRO USR DOM |PAI FROM --------------------|---------------------------------------------------- Y Y abc def.ghi |PRI "Anonymous" Y Y abc |PRI "Anonymous" Y Y def.ghi |PRI "Anonymous" Y Y |PRI "Anonymous" Y N abc def.ghi |YES Y N abc |YES > Y N def.ghi |YES "Caller Name" @def.ghi> Y N |YES "Caller Name" @> N Y abc def.ghi |NO "Anonymous" N Y abc |NO "Anonymous" N Y def.ghi |NO "Anonymous" N Y |NO "Anonymous" N N abc def.ghi |YES N N abc |YES > N N def.ghi |YES "Caller Name" @def.ghi> N N |YES "Caller Name" @> ASTERISK-25791 #close Reported-by: Anthony Messina Change-Id: I2c82a5ca1413c2c00fb62ea95b0ae8e97af54dc9 --- CHANGES | 5 ++ include/asterisk/res_pjsip.h | 10 +++ include/asterisk/res_pjsip_session.h | 2 + res/res_pjsip.c | 29 ++++++++ res/res_pjsip_caller_id.c | 85 ++++++------------------ res/res_pjsip_session.c | 98 ++++++++++++++++++++++++---- 6 files changed, 151 insertions(+), 78 deletions(-) diff --git a/CHANGES b/CHANGES index 7c042858260..057542f1821 100644 --- a/CHANGES +++ b/CHANGES @@ -215,6 +215,11 @@ Queue --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ ------------------------------------------------------------------------------ +res_pjsip_caller_id +------------------ + * Per RFC3325, the 'From' header is now anonymized on outgoing calls when + caller id presentation is prohibited. + res_pjsip_config_wizard ------------------ * A new command (pjsip export config_wizard primitives) has been added that diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 3008475c305..66370186a0a 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2247,4 +2247,14 @@ int ast_sip_set_tpselector_from_transport(const struct ast_sip_transport *transp */ int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip_tpselector *selector); +/*! + * \brief Set name and number information on an identity header. + * + * \param pool Memory pool to use for string duplication + * \param id_hdr A From, P-Asserted-Identity, or Remote-Party-ID header to modify + * \param id The identity information to apply to the header + */ +void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, + const struct ast_party_id *id); + #endif /* _RES_PJSIP_H */ diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 61398471306..55401e7c7a5 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -151,6 +151,8 @@ struct ast_sip_session { enum ast_sip_session_t38state t38state; /*! The AOR associated with this session */ struct ast_sip_aor *aor; + /*! From header saved at invite creation */ + pjsip_fromto_hdr *saved_from_hdr; }; typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata); diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 713d94ec504..170a19151a7 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3898,6 +3898,35 @@ const char *ast_sip_get_host_ip_string(int af) return NULL; } +/*! + * \brief Set name and number information on an identity header. + * + * \param pool Memory pool to use for string duplication + * \param id_hdr A From, P-Asserted-Identity, or Remote-Party-ID header to modify + * \param id The identity information to apply to the header + */ +void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id) +{ + pjsip_name_addr *id_name_addr; + pjsip_sip_uri *id_uri; + + id_name_addr = (pjsip_name_addr *) id_hdr->uri; + id_uri = pjsip_uri_get_uri(id_name_addr->uri); + + if (id->name.valid) { + int name_buf_len = strlen(id->name.str) * 2 + 1; + char *name_buf = ast_alloca(name_buf_len); + + ast_escape_quoted(id->name.str, name_buf, name_buf_len); + pj_strdup2(pool, &id_name_addr->display, name_buf); + } + + if (id->number.valid) { + pj_strdup2(pool, &id_uri->user, id->number.str); + } +} + + static void remove_request_headers(pjsip_endpoint *endpt) { const pjsip_hdr *request_headers = pjsip_endpt_get_request_headers(endpt); diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 8227cacda51..1818105d7da 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -396,34 +396,6 @@ static void caller_id_incoming_response(struct ast_sip_session *session, pjsip_r update_incoming_connected_line(session, rdata); } -/*! - * \internal - * \brief Set name and number information on an identity header. - * \param pool Memory pool to use for string duplication - * \param id_hdr A From, P-Asserted-Identity, or Remote-Party-ID header to modify - * \param id The identity information to apply to the header - */ -static void modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id) -{ - pjsip_name_addr *id_name_addr; - pjsip_sip_uri *id_uri; - - id_name_addr = (pjsip_name_addr *) id_hdr->uri; - id_uri = pjsip_uri_get_uri(id_name_addr->uri); - - if (id->name.valid) { - int name_buf_len = strlen(id->name.str) * 2 + 1; - char *name_buf = ast_alloca(name_buf_len); - - ast_escape_quoted(id->name.str, name_buf, name_buf_len); - pj_strdup2(pool, &id_name_addr->display, name_buf); - } - - if (id->number.valid) { - pj_strdup2(pool, &id_uri->user, id->number.str); - } -} - /*! * \internal * \brief Create an identity header for an outgoing message @@ -432,15 +404,12 @@ static void modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const st * \param id The identification information for the new header * \return newly-created header */ -static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_tx_data *tdata, const struct ast_party_id *id) +static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_fromto_hdr *base, pjsip_tx_data *tdata, const struct ast_party_id *id) { pjsip_fromto_hdr *id_hdr; - pjsip_fromto_hdr *base; pjsip_name_addr *id_name_addr; pjsip_sip_uri *id_uri; - base = tdata->msg->type == PJSIP_REQUEST_MSG ? PJSIP_MSG_FROM_HDR(tdata->msg) : - PJSIP_MSG_TO_HDR(tdata->msg); id_hdr = pjsip_from_hdr_create(tdata->pool); id_hdr->type = PJSIP_H_OTHER; pj_strdup(tdata->pool, &id_hdr->name, hdr_name); @@ -500,9 +469,10 @@ static void add_privacy_header(pjsip_tx_data *tdata, const struct ast_party_id * * \param tdata The message to add the header to * \param id The identification information used to populate the header */ -static void add_pai_header(pjsip_tx_data *tdata, const struct ast_party_id *id) +static void add_pai_header(const struct ast_sip_session *session, pjsip_tx_data *tdata, const struct ast_party_id *id) { static const pj_str_t pj_pai_name = { "P-Asserted-Identity", 19 }; + pjsip_fromto_hdr *base; pjsip_fromto_hdr *pai_hdr; pjsip_fromto_hdr *old_pai; @@ -523,13 +493,16 @@ static void add_pai_header(pjsip_tx_data *tdata, const struct ast_party_id *id) if (old_pai->type == PJSIP_H_OTHER) { pj_list_erase(old_pai); } else { - modify_id_header(tdata->pool, old_pai, id); + ast_sip_modify_id_header(tdata->pool, old_pai, id); add_privacy_header(tdata, id); return; } } - pai_hdr = create_new_id_hdr(&pj_pai_name, tdata, id); + base = tdata->msg->type == PJSIP_REQUEST_MSG ? session->saved_from_hdr : + PJSIP_MSG_TO_HDR(tdata->msg); + + pai_hdr = create_new_id_hdr(&pj_pai_name, base, tdata, id); if (!pai_hdr) { return; } @@ -602,9 +575,10 @@ static void add_privacy_params(pjsip_tx_data *tdata, pjsip_fromto_hdr *hdr, cons * \param tdata The message to add the header to * \param id The identification information used to populate the header */ -static void add_rpid_header(pjsip_tx_data *tdata, const struct ast_party_id *id) +static void add_rpid_header(const struct ast_sip_session *session, pjsip_tx_data *tdata, const struct ast_party_id *id) { static const pj_str_t pj_rpid_name = { "Remote-Party-ID", 15 }; + pjsip_fromto_hdr *base; pjsip_fromto_hdr *rpid_hdr; pjsip_fromto_hdr *old_rpid; @@ -625,13 +599,16 @@ static void add_rpid_header(pjsip_tx_data *tdata, const struct ast_party_id *id) if (old_rpid->type == PJSIP_H_OTHER) { pj_list_erase(old_rpid); } else { - modify_id_header(tdata->pool, old_rpid, id); + ast_sip_modify_id_header(tdata->pool, old_rpid, id); add_privacy_params(tdata, old_rpid, id); return; } } - rpid_hdr = create_new_id_hdr(&pj_rpid_name, tdata, id); + base = tdata->msg->type == PJSIP_REQUEST_MSG ? session->saved_from_hdr : + PJSIP_MSG_TO_HDR(tdata->msg); + + rpid_hdr = create_new_id_hdr(&pj_rpid_name, base, tdata, id); if (!rpid_hdr) { return; } @@ -658,10 +635,10 @@ static void add_id_headers(const struct ast_sip_session *session, pjsip_tx_data return; } if (session->endpoint->id.send_pai) { - add_pai_header(tdata, id); + add_pai_header(session, tdata, id); } if (session->endpoint->id.send_rpid) { - add_rpid_header(tdata, id); + add_rpid_header(session, tdata, id); } } @@ -669,10 +646,9 @@ static void add_id_headers(const struct ast_sip_session *session, pjsip_tx_data * \internal * \brief Session supplement callback for outgoing INVITE requests * - * For an initial INVITE request, we may change the From header to appropriately - * reflect the identity information. On all INVITEs (initial and reinvite) we may - * add other identity headers such as P-Asserted-Identity and Remote-Party-ID based - * on configuration and privacy settings + * On all INVITEs (initial and reinvite) we may add other identity headers + * such as P-Asserted-Identity and Remote-Party-ID based on configuration + * and privacy settings * * \param session The session on which the INVITE will be sent * \param tdata The outbound INVITE request @@ -686,33 +662,12 @@ static void caller_id_outgoing_request(struct ast_sip_session *session, pjsip_tx return; } - /* Must do a deep copy unless we hold the channel lock the entire time. */ ast_party_id_init(&connected_id); ast_channel_lock(session->channel); effective_id = ast_channel_connected_effective_id(session->channel); ast_party_id_copy(&connected_id, &effective_id); ast_channel_unlock(session->channel); - if (session->inv_session->state < PJSIP_INV_STATE_CONFIRMED) { - /* Only change the From header on the initial outbound INVITE. Switching it - * mid-call might confuse some UAs. - */ - pjsip_fromto_hdr *from; - pjsip_dialog *dlg; - - from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, tdata->msg->hdr.next); - dlg = session->inv_session->dlg; - - if (ast_strlen_zero(session->endpoint->fromuser) - && (session->endpoint->id.trust_outbound - || (ast_party_id_presentation(&connected_id) & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED)) { - modify_id_header(tdata->pool, from, &connected_id); - modify_id_header(dlg->pool, dlg->local.info, &connected_id); - } - - ast_sip_add_usereqphone(session->endpoint, tdata->pool, from->uri); - ast_sip_add_usereqphone(session->endpoint, dlg->pool, dlg->local.info->uri); - } add_id_headers(session, tdata, &connected_id); ast_party_id_free(&connected_id); } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 983687174e0..80fe8f393b5 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -30,6 +30,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_session.h" +#include "asterisk/callerid.h" #include "asterisk/datastore.h" #include "asterisk/module.h" #include "asterisk/logger.h" @@ -800,6 +801,75 @@ static pjmedia_sdp_session *generate_session_refresh_sdp(struct ast_sip_session return create_local_sdp(inv_session, session, previous_sdp); } +static void set_from_header(struct ast_sip_session *session) +{ + struct ast_party_id effective_id; + struct ast_party_id connected_id; + pj_pool_t *dlg_pool; + pjsip_fromto_hdr *dlg_info; + pjsip_name_addr *dlg_info_name_addr; + pjsip_sip_uri *dlg_info_uri; + int restricted; + + if (!session->channel || session->saved_from_hdr) { + return; + } + + /* We need to save off connected_id for RPID/PAI generation */ + ast_party_id_init(&connected_id); + ast_channel_lock(session->channel); + effective_id = ast_channel_connected_effective_id(session->channel); + ast_party_id_copy(&connected_id, &effective_id); + ast_channel_unlock(session->channel); + + restricted = + ((ast_party_id_presentation(&connected_id) & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED); + + /* Now set up dlg->local.info so pjsip can correctly generate From */ + + dlg_pool = session->inv_session->dlg->pool; + dlg_info = session->inv_session->dlg->local.info; + dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri; + dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr); + + if (session->endpoint->id.trust_outbound || !restricted) { + ast_sip_modify_id_header(dlg_pool, dlg_info, &connected_id); + } + + ast_party_id_free(&connected_id); + + if (!ast_strlen_zero(session->endpoint->fromuser)) { + dlg_info_name_addr->display.ptr = NULL; + dlg_info_name_addr->display.slen = 0; + pj_strdup2(dlg_pool, &dlg_info_uri->user, session->endpoint->fromuser); + } + + if (!ast_strlen_zero(session->endpoint->fromdomain)) { + pj_strdup2(dlg_pool, &dlg_info_uri->host, session->endpoint->fromdomain); + } + + ast_sip_add_usereqphone(session->endpoint, dlg_pool, dlg_info->uri); + + /* We need to save off the non-anonymized From for RPID/PAI generation (for domain) */ + session->saved_from_hdr = pjsip_hdr_clone(dlg_pool, dlg_info); + + /* In chan_sip, fromuser and fromdomain trump restricted so we only + * anonymize if they're not set. + */ + if (restricted) { + /* fromuser doesn't provide a display name so we always set it */ + pj_strdup2(dlg_pool, &dlg_info_name_addr->display, "Anonymous"); + + if (ast_strlen_zero(session->endpoint->fromuser)) { + pj_strdup2(dlg_pool, &dlg_info_uri->user, "anonymous"); + } + + if (ast_strlen_zero(session->endpoint->fromdomain)) { + pj_strdup2(dlg_pool, &dlg_info_uri->host, "anonymous.invalid"); + } + } +} + int ast_sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, @@ -867,6 +937,12 @@ int ast_sip_session_refresh(struct ast_sip_session *session, } } + /* + * We MUST call set_from_header() before pjsip_inv_(reinvite|update). If we don't, the + * From in the reINVITE/UPDATE will be wrong but the rest of the messages will be OK. + */ + set_from_header(session); + if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) { if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) { ast_log(LOG_WARNING, "Failed to create reinvite properly.\n"); @@ -1082,6 +1158,7 @@ static pjsip_module session_reinvite_module = { .on_rx_request = session_reinvite_on_rx_request, }; + void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata, ast_sip_session_response_cb on_response) { @@ -1095,19 +1172,6 @@ void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id, MOD_DATA_ON_RESPONSE, on_response); - if (!ast_strlen_zero(session->endpoint->fromuser) || - !ast_strlen_zero(session->endpoint->fromdomain)) { - pjsip_fromto_hdr *from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, tdata->msg->hdr.next); - pjsip_sip_uri *uri = pjsip_uri_get_uri(from->uri); - - if (!ast_strlen_zero(session->endpoint->fromuser)) { - pj_strdup2(tdata->pool, &uri->user, session->endpoint->fromuser); - } - if (!ast_strlen_zero(session->endpoint->fromdomain)) { - pj_strdup2(tdata->pool, &uri->host, session->endpoint->fromdomain); - } - } - handle_outgoing_request(session, tdata); internal_pjsip_inv_send_msg(session->inv_session, session->endpoint->transport, tdata); @@ -1133,9 +1197,17 @@ int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data #ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE); #endif + + /* + * We MUST call set_from_header() before pjsip_inv_invite. If we don't, the + * From in the initial INVITE will be wrong but the rest of the messages will be OK. + */ + set_from_header(session); + if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) { return -1; } + return 0; } From 471ff375fd4e37fbf5f67cdcf2ffadddebed8741 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 4 Mar 2016 19:37:44 -0700 Subject: [PATCH 0251/1578] install_prereq: Add packages for bundled pjproject RedHat/CentOS needs python-devel Debian/Ubuntu needs automake, libsrtp-dev and python-dev Ubuntu also needed libncurses5-dev for cmenuselect so while not needed for pjproject, I adedd it anyway. Change-Id: Idf5fa16e2d87c687439621507e122cb9461d7089 --- contrib/scripts/install_prereq | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/scripts/install_prereq b/contrib/scripts/install_prereq index 06eb05e7144..afad1f71967 100755 --- a/contrib/scripts/install_prereq +++ b/contrib/scripts/install_prereq @@ -28,12 +28,12 @@ PACKAGES_DEBIAN="$PACKAGES_DEBIAN libpq-dev unixodbc-dev libsqlite0-dev libmysql PACKAGES_DEBIAN="$PACKAGES_DEBIAN libopenh323-dev libvpb-dev libgtk2.0-dev libmysqlclient-dev libbluetooth-dev libradiusclient-ng-dev freetds-dev" PACKAGES_DEBIAN="$PACKAGES_DEBIAN libsnmp-dev libiksemel-dev libcorosync-dev libnewt-dev libpopt-dev libical-dev libspandsp-dev libjack-dev" PACKAGES_DEBIAN="$PACKAGES_DEBIAN libresample-dev libc-client-dev binutils-dev libsrtp-dev libgsm1-dev libedit-dev doxygen libjansson-dev libldap-dev" -PACKAGES_DEBIAN="$PACKAGES_DEBIAN subversion git libxslt1-dev" +PACKAGES_DEBIAN="$PACKAGES_DEBIAN subversion git libxslt1-dev automake libsrtp-dev libncurses5-dev python-dev" PACKAGES_RH="automake gcc gcc-c++ ncurses-devel openssl-devel libxml2-devel unixODBC-devel libcurl-devel libogg-devel libvorbis-devel speex-devel" PACKAGES_RH="$PACKAGES_RH spandsp-devel freetds-devel net-snmp-devel iksemel-devel corosynclib-devel newt-devel popt-devel libtool-ltdl-devel lua-devel" PACKAGES_RH="$PACKAGES_RH sqlite-devel libsqlite3x-devel radiusclient-ng-devel portaudio-devel postgresql-devel libresample-devel neon-devel libical-devel" PACKAGES_RH="$PACKAGES_RH openldap-devel gmime22-devel sqlite2-devel mysql-devel bluez-libs-devel jack-audio-connection-kit-devel gsm-devel libedit-devel libuuid-devel" -PACKAGES_RH="$PACKAGES_RH jansson-devel libsrtp-devel pjproject-devel subversion git libxslt-devel" +PACKAGES_RH="$PACKAGES_RH jansson-devel libsrtp-devel pjproject-devel subversion git libxslt-devel python-devel" PACKAGES_OBSD="popt gmake wget libxml libogg libvorbis curl iksemel spandsp speex iodbc freetds-0.63p1-msdblib mysql-client gmime sqlite sqlite3 jack libxslt" From 0ec9fe54219f8ad8a1e2c6f0a17843dcf08b7451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 18 Feb 2016 01:58:01 -0300 Subject: [PATCH 0252/1578] main/cli.c: Refactor function to print seconds formatted Refactor and created function ast_cli_print_timestr_fromseconds to print seconds formatted: year(s) week(s) day(s) hour(s) second(s) This function now is used in addons/cdr_mysql.c,cdr_pgsql.c, main/cli.c, res_config_ldap.c, res_config_pgsql.c. Change-Id: Ibeb8634102cd11d3f8623398b279cb731bcde36c --- addons/cdr_mysql.c | 19 +++++++------------ cdr/cdr_pgsql.c | 19 +++++++------------ include/asterisk/cli.h | 11 +++++++++++ main/cli.c | 21 ++++++++++++++------- res/res_config_ldap.c | 25 +++++-------------------- res/res_config_pgsql.c | 24 ++++++------------------ 6 files changed, 50 insertions(+), 69 deletions(-) diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c index d55f9e035fc..9873395c2ca 100644 --- a/addons/cdr_mysql.c +++ b/addons/cdr_mysql.c @@ -119,7 +119,9 @@ static char *handle_cli_cdr_mysql_status(struct ast_cli_entry *e, int cmd, struc return CLI_SHOWUSAGE; if (connected) { - char status[256], status2[100] = ""; + char status[256]; + char status2[100] = ""; + char buf[362]; /* 256+100+" for "+NULL */ int ctime = time(NULL) - connect_time; if (dbport) snprintf(status, 255, "Connected to %s@%s, port %d", ast_str_buffer(dbname), ast_str_buffer(hostname), dbport); @@ -132,17 +134,10 @@ static char *handle_cli_cdr_mysql_status(struct ast_cli_entry *e, int cmd, struc snprintf(status2, 99, " with username %s", ast_str_buffer(dbuser)); if (ast_str_strlen(dbtable)) snprintf(status2, 99, " using table %s", ast_str_buffer(dbtable)); - if (ctime > 31536000) { - ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60); - } else if (ctime > 86400) { - ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60); - } else if (ctime > 3600) { - ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60); - } else if (ctime > 60) { - ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60); - } else { - ast_cli(a->fd, "%s%s for %d seconds.\n", status, status2, ctime); - } + + snprintf(buf, sizeof(buf), "%s%s for ", status, status2); + ast_cli_print_timestr_fromseconds(a->fd, ctime, buf); + if (records == totalrecords) ast_cli(a->fd, " Wrote %d records since last restart.\n", totalrecords); else diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c index aec21165034..ea38cc9837c 100644 --- a/cdr/cdr_pgsql.c +++ b/cdr/cdr_pgsql.c @@ -139,7 +139,9 @@ static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct as return CLI_SHOWUSAGE; if (connected) { - char status[256], status2[100] = ""; + char status[256]; + char status2[100] = ""; + char buf[362]; /* 256+100+" for "+NULL */ int ctime = time(NULL) - connect_time; if (pgdbport) { @@ -154,17 +156,10 @@ static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct as if (table && *table) { snprintf(status2, 99, " using table %s", table); } - if (ctime > 31536000) { - ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60); - } else if (ctime > 86400) { - ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60); - } else if (ctime > 3600) { - ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60); - } else if (ctime > 60) { - ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60); - } else { - ast_cli(a->fd, "%s%s for %d seconds.\n", status, status2, ctime); - } + + snprintf(buf, sizeof(buf), "%s%s for ", status, status2); + ast_cli_print_timestr_fromseconds(a->fd, ctime, buf); + if (records == totalrecords) { ast_cli(a->fd, " Wrote %d records since last restart.\n", totalrecords); } else { diff --git a/include/asterisk/cli.h b/include/asterisk/cli.h index 82363c15f46..0bda6665ce3 100644 --- a/include/asterisk/cli.h +++ b/include/asterisk/cli.h @@ -315,6 +315,17 @@ char **ast_cli_completion_matches(const char *, const char *); */ char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos); +/*! + * \since 13.8 + * \brief Print on cli a duration in seconds in format + * %s year(s), %s week(s), %s day(s), %s hour(s), %s second(s) + * + * \param ast_cli_args fd to print by ast_cli + * \param duration The time (in seconds) to print + * \param prefix A Prefix string to add before of duration formatted + */ +void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/cli.c b/main/cli.c index 917305594a9..0ac5d612a0a 100644 --- a/main/cli.c +++ b/main/cli.c @@ -807,7 +807,7 @@ static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, return; if (printsec) { /* plain seconds output */ - ast_cli(fd, "%s: %lu\n", prefix, (u_long)timeval.tv_sec); + ast_cli(fd, "%s%lu\n", prefix, (u_long)timeval.tv_sec); return; } out = ast_str_alloca(256); @@ -841,7 +841,7 @@ static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, /* if there is nothing, print 0 seconds */ ast_str_append(&out, 0, "%d second%s", x, ESS(x)); } - ast_cli(fd, "%s: %s\n", prefix, ast_str_buffer(out)); + ast_cli(fd, "%s%s\n", prefix, ast_str_buffer(out)); } static struct ast_cli_entry *cli_next(struct ast_cli_entry *e) @@ -877,10 +877,12 @@ static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli printsec = 0; else return CLI_SHOWUSAGE; - if (ast_startuptime.tv_sec) - print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec); - if (ast_lastreloadtime.tv_sec) - print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload", printsec); + if (ast_startuptime.tv_sec) { + print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime: ", printsec); + } + if (ast_lastreloadtime.tv_sec) { + print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload: ", printsec); + } return CLI_SUCCESS; } @@ -972,7 +974,7 @@ static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_a ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls())); if (ast_startuptime.tv_sec && showuptime) { - print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec); + print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime: ", printsec); } return RESULT_SUCCESS; @@ -2744,3 +2746,8 @@ int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const c } return count; } + +void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix) +{ + print_uptimestr(fd, ast_tv(seconds, 0), prefix, 0); +} diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 95eae29c19b..8454273799a 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -1837,7 +1837,9 @@ static int ldap_reconnect(void) */ static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char status[256], credentials[100] = ""; + char status[256]; + char credentials[100] = ""; + char buf[362]; /* 256+100+" for "+NULL */ int ctimesec = time(NULL) - connect_time; switch (cmd) { @@ -1860,25 +1862,8 @@ static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_c if (!ast_strlen_zero(user)) snprintf(credentials, sizeof(credentials), " with username %s", user); - if (ctimesec > 31536000) { - ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", - status, credentials, ctimesec / 31536000, - (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600, - (ctimesec % 3600) / 60, ctimesec % 60); - } else if (ctimesec > 86400) { - ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", - status, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, - (ctimesec % 3600) / 60, ctimesec % 60); - } else if (ctimesec > 3600) { - ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", - status, credentials, ctimesec / 3600, (ctimesec % 3600) / 60, - ctimesec % 60); - } else if (ctimesec > 60) { - ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials, - ctimesec / 60, ctimesec % 60); - } else { - ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec); - } + snprintf(buf, sizeof(buf), "%s%s for ", status, credentials); + ast_cli_print_timestr_fromseconds(a->fd, ctimesec, buf); return CLI_SUCCESS; } diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 77c52aa0b63..73f43ee2cce 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -1574,7 +1574,9 @@ static char *handle_cli_realtime_pgsql_cache(struct ast_cli_entry *e, int cmd, s static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char connection_info[256], credentials[100] = ""; + char connection_info[256]; + char credentials[100] = ""; + char buf[376]; /* 256+100+"Connected to "+" for "+NULL */ int ctimesec = time(NULL) - connect_time; switch (cmd) { @@ -1601,24 +1603,10 @@ static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, if (!ast_strlen_zero(dbuser)) snprintf(credentials, sizeof(credentials), " with username %s", dbuser); - if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { - if (ctimesec > 31536000) - ast_cli(a->fd, "Connected to %s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", - connection_info, credentials, ctimesec / 31536000, (ctimesec % 31536000) / 86400, - (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, ctimesec % 60); - else if (ctimesec > 86400) - ast_cli(a->fd, "Connected to %s%s for %d days, %d hours, %d minutes, %d seconds.\n", connection_info, - credentials, ctimesec / 86400, (ctimesec % 86400) / 3600, (ctimesec % 3600) / 60, - ctimesec % 60); - else if (ctimesec > 3600) - ast_cli(a->fd, "Connected to %s%s for %d hours, %d minutes, %d seconds.\n", connection_info, credentials, - ctimesec / 3600, (ctimesec % 3600) / 60, ctimesec % 60); - else if (ctimesec > 60) - ast_cli(a->fd, "Connected to %s%s for %d minutes, %d seconds.\n", connection_info, credentials, ctimesec / 60, - ctimesec % 60); - else - ast_cli(a->fd, "Connected to %s%s for %d seconds.\n", connection_info, credentials, ctimesec); + if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { + snprintf(buf, sizeof(buf), "Connected to %s%s for ", connection_info, credentials); + ast_cli_print_timestr_fromseconds(a->fd, ctimesec, buf); return CLI_SUCCESS; } else { ast_cli(a->fd, "Unable to connect %s%s\n", connection_info, credentials); From f690c105f33c3dea0766e8bfe012af2879c6c665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Mon, 7 Mar 2016 05:02:45 -0300 Subject: [PATCH 0253/1578] res_odbc_transaction: fix some format tab Change-Id: I265e4ac47c629c9a63dd86b59df82a7ab3c64384 --- res/res_odbc_transaction.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/res/res_odbc_transaction.c b/res/res_odbc_transaction.c index 33800c3ce31..de78600f356 100644 --- a/res/res_odbc_transaction.c +++ b/res/res_odbc_transaction.c @@ -222,7 +222,7 @@ static struct odbc_txn_frame *find_transaction(struct ast_channel *chan, const c /* No datastore? Definitely no transaction then */ return NULL; } - + oldlist = txn_store->data; AST_LIST_LOCK(oldlist); @@ -522,8 +522,8 @@ static int load_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "ODBC transaction resource", - .support_level = AST_MODULE_SUPPORT_CORE, - .load = load_module, - .unload = unload_module, - .load_pri = AST_MODPRI_REALTIME_DEPEND, - ); + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_REALTIME_DEPEND, +); From d2eb65f71e9347c15d469579bbb20c47501d924b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 6 Mar 2016 13:38:41 -0700 Subject: [PATCH 0254/1578] res_pjsip: Strip spaces from items parsed from comma-separated lists Configurations like "aors = a, b, c" were either ignoring everything after "a" or trying to look up " b". Same for mailboxes, ciphers, contacts and a few others. To fix, all the strsep(©, ",") calls have been wrapped in ast_strip. To facilitate this, ast_strip, ast_skip_blanks and ast_skip_nonblanks were updated to handle null pointers. In some cases, an ast_strlen_zero() test was added to skip consecutive commas. There was also an attempt to ast_free an ast_strdupa'd string in ast_sip_for_each_aor which was causing a SEGV. I removed it. Although this issue was reported for realtime, the issue was in the res_pjsip modules so all config mechanisms were affected. ASTERISK-25829 #close Reported-by: Mateusz Kowalski Change-Id: I0b22a2cf22a7c1c50d4ecacbfa540155bec0e7a2 --- channels/pjsip/dialplan_functions.c | 2 +- include/asterisk/strings.h | 16 ++++++++++++---- res/res_pjsip/config_transport.c | 3 +-- res/res_pjsip/location.c | 11 +++++++---- res/res_pjsip/pjsip_configuration.c | 8 ++++++-- res/res_pjsip/pjsip_options.c | 8 ++++---- res/res_pjsip_endpoint_identifier_ip.c | 6 +++++- res/res_pjsip_mwi.c | 26 +++++++++++++++++++------- res/res_pjsip_notify.c | 2 +- res/res_pjsip_path.c | 6 +++++- res/res_pjsip_pubsub.c | 6 +++++- res/res_pjsip_registrar.c | 6 +++++- 12 files changed, 71 insertions(+), 29 deletions(-) diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index b86cfad5368..1c089973221 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -819,7 +819,7 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char return -1; } - while ((aor_name = strsep(&rest, ","))) { + while ((aor_name = ast_strip(strsep(&rest, ",")))) { RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); struct ao2_iterator it_contacts; diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index af5ae6c5565..3701b530593 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -145,8 +145,12 @@ static int force_inline attribute_pure ast_ends_with(const char *str, const char AST_INLINE_API( char * attribute_pure ast_skip_blanks(const char *str), { - while (*str && ((unsigned char) *str) < 33) - str++; + if (str) { + while (*str && ((unsigned char) *str) < 33) { + str++; + } + } + return (char *) str; } ) @@ -184,8 +188,12 @@ char *ast_trim_blanks(char *str), AST_INLINE_API( char * attribute_pure ast_skip_nonblanks(const char *str), { - while (*str && ((unsigned char) *str) > 32) - str++; + if (str) { + while (*str && ((unsigned char) *str) > 32) { + str++; + } + } + return (char *) str; } ) diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 61a979c8857..db579bf2f62 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -985,8 +985,7 @@ static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast } parse = ast_strdupa(S_OR(var->value, "")); - while ((name = strsep(&parse, ","))) { - name = ast_strip(name); + while ((name = ast_strip(strsep(&parse, ",")))) { if (ast_strlen_zero(name)) { continue; } diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index c070e7dbceb..4008abad1f9 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -205,7 +205,7 @@ void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, s *aor = NULL; *contact = NULL; - while ((aor_name = strsep(&rest, ","))) { + while ((aor_name = ast_strip(strsep(&rest, ",")))) { *aor = ast_sip_location_retrieve_aor(aor_name); if (!(*aor)) { @@ -377,12 +377,16 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab } contacts = ast_strdupa(var->value); - while ((contact_uri = strsep(&contacts, ","))) { + while ((contact_uri = ast_strip(strsep(&contacts, ",")))) { struct ast_sip_contact *contact; struct ast_sip_contact_status *status; char hash[33]; char contact_id[strlen(aor_id) + sizeof(hash) + 2]; + if (ast_strlen_zero(contact_uri)) { + continue; + } + if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL); @@ -442,7 +446,7 @@ int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) } copy = ast_strdupa(aors); - while ((name = strsep(©, ","))) { + while ((name = ast_strip(strsep(©, ",")))) { RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(name), ao2_cleanup); @@ -454,7 +458,6 @@ int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) return -1; } } - ast_free(copy); return 0; } diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 2a81cfded27..371e4318ba8 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -410,7 +410,7 @@ int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *valu return -1; } - while ((val = strsep(&auth_names, ","))) { + while ((val = ast_strip(strsep(&auth_names, ",")))) { if (ast_strlen_zero(val)) { continue; } @@ -477,7 +477,11 @@ static int ident_handler(const struct aco_option *opt, struct ast_variable *var, char *idents = ast_strdupa(var->value); char *val; - while ((val = strsep(&idents, ","))) { + while ((val = ast_strip(strsep(&idents, ",")))) { + if (ast_strlen_zero(val)) { + continue; + } + if (!strcasecmp(val, "username")) { endpoint->ident_method |= AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME; } else { diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 73f12a00c58..aed9620303b 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -270,7 +270,7 @@ static int on_endpoint(void *obj, void *arg, int flags) } aors = ast_strdupa(endpoint->aors); - while ((aor_name = strsep(&aors, ","))) { + while ((aor_name = ast_strip(strsep(&aors, ",")))) { struct ast_sip_aor *aor; struct ao2_container *contacts; @@ -795,7 +795,7 @@ static int cli_qualify_contacts(void *data) } aors = ast_strdupa(endpoint->aors); - while ((aor_name = strsep(&aors, ","))) { + while ((aor_name = ast_strip(strsep(&aors, ",")))) { struct ast_sip_aor *aor; struct ao2_container *contacts; @@ -899,7 +899,7 @@ static int ami_sip_qualify(struct mansession *s, const struct message *m) } aors = ast_strdupa(endpoint->aors); - while ((aor_name = strsep(&aors, ","))) { + while ((aor_name = ast_strip(strsep(&aors, ",")))) { struct ast_sip_aor *aor; struct ao2_container *contacts; @@ -1087,7 +1087,7 @@ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) } aors = ast_strdupa(endpoint->aors); - while ((aor_name = strsep(&aors, ","))) { + while ((aor_name = ast_strip(strsep(&aors, ",")))) { struct ast_sip_aor *aor; struct ao2_container *contacts; diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index f73bdae7e43..016e0b4ad08 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -164,11 +164,15 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va return 0; } - while ((current_string = strsep(&input_string, ","))) { + while ((current_string = ast_strip(strsep(&input_string, ",")))) { struct ast_sockaddr *addrs; int num_addrs = 0, error = 0, i; char *mask = strrchr(current_string, '/'); + if (ast_strlen_zero(current_string)) { + continue; + } + if (mask) { identify->matches = ast_append_ha("d", current_string, identify->matches, &error); diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index e1eea6f2ae8..c9d1b743e5d 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -432,7 +432,7 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, ast_debug(5, "Sending unsolicited MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n", sub->id, counter->new_msgs, counter->old_msgs); - while ((aor_name = strsep(&endpoint_aors, ","))) { + while ((aor_name = ast_strip(strsep(&endpoint_aors, ",")))) { RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); struct unsolicited_mwi_data mwi_data = { @@ -598,7 +598,11 @@ static int mwi_validate_for_aor(void *obj, void *arg, int flags) } mailboxes = ast_strdupa(aor->mailboxes); - while ((mailbox = strsep(&mailboxes, ","))) { + while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) { + if (ast_strlen_zero(mailbox)) { + continue; + } + if (endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox)) { ast_debug(1, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. " "Denying MWI subscription to %s\n", ast_sorcery_object_get_id(endpoint), mailbox, @@ -622,9 +626,13 @@ static int mwi_on_aor(void *obj, void *arg, int flags) } mailboxes = ast_strdupa(aor->mailboxes); - while ((mailbox = strsep(&mailboxes, ","))) { + while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) { struct mwi_stasis_subscription *mwi_stasis_sub; + if (ast_strlen_zero(mailbox)) { + continue; + } + mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub); if (!mwi_stasis_sub) { continue; @@ -890,7 +898,7 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags endpoint_aors = ast_strdupa(endpoint->aors); - while ((aor_name = strsep(&endpoint_aors, ","))) { + while ((aor_name = ast_strip(strsep(&endpoint_aors, ",")))) { RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); if (!aor) { @@ -921,11 +929,15 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags } mailboxes = ast_strdupa(endpoint->subscription.mwi.mailboxes); - while ((mailbox = strsep(&mailboxes, ","))) { - struct mwi_subscription *sub = aggregate_sub ?: - mwi_subscription_alloc(endpoint, 0, NULL); + while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) { + struct mwi_subscription *sub; struct mwi_stasis_subscription *mwi_stasis_sub; + if (ast_strlen_zero(mailbox)) { + continue; + } + + sub = aggregate_sub ?: mwi_subscription_alloc(endpoint, 0, NULL); mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub); if (mwi_stasis_sub) { ao2_link(sub->stasis_subs, mwi_stasis_sub); diff --git a/res/res_pjsip_notify.c b/res/res_pjsip_notify.c index 6d524152c4f..8de88c7e899 100644 --- a/res/res_pjsip_notify.c +++ b/res/res_pjsip_notify.c @@ -615,7 +615,7 @@ static int notify_endpoint(void *obj) aors = ast_strdupa(data->endpoint->aors); - while ((aor_name = strsep(&aors, ","))) { + while ((aor_name = ast_strip(strsep(&aors, ",")))) { RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); diff --git a/res/res_pjsip_path.c b/res/res_pjsip_path.c index 03cbe50768e..2dde7323e61 100644 --- a/res/res_pjsip_path.c +++ b/res/res_pjsip_path.c @@ -53,9 +53,13 @@ static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri configured_aors = ast_strdupa(endpoint->aors); /* Iterate the configured AORs to see if the user or the user+domain match */ - while ((aor_name = strsep(&configured_aors, ","))) { + while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { struct ast_sip_domain_alias *alias = NULL; + if (ast_strlen_zero(aor_name)) { + continue; + } + if (!pj_strcmp2(&sip_uri->user, aor_name)) { break; } diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 0da43190cc1..57ca95d8c64 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -3654,7 +3654,11 @@ static int list_item_handler(const struct aco_option *opt, char *items = ast_strdupa(var->value); char *item; - while ((item = strsep(&items, ","))) { + while ((item = ast_strip(strsep(&items, ",")))) { + if (ast_strlen_zero(item)) { + continue; + } + if (item_in_vector(list, item)) { ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item); continue; diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index accb1613771..46d24324a36 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -651,9 +651,13 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) configured_aors = ast_strdupa(endpoint->aors); /* Iterate the configured AORs to see if the user or the user+domain match */ - while ((aor_name = strsep(&configured_aors, ","))) { + while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { struct ast_sip_domain_alias *alias = NULL; + if (ast_strlen_zero(aor_name)) { + continue; + } + if (!pj_strcmp2(&uri->user, aor_name)) { break; } From fb28049de29f32bd2c7e29dfd3ec4bcc27ba4d2a Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 7 Mar 2016 20:34:12 -0700 Subject: [PATCH 0255/1578] pjproject_bundled: Remove --with-external-pa from configure options. Not sure why it was there in the first place as we already specify --disable-sound. Change-Id: Ia80a40e8b1e1acc287955ab11ba1fbd0c7d4cff9 --- third-party/pjproject/Makefile.rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index d6e4be00be9..6319ed5163d 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -2,6 +2,6 @@ PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --with-external-speex --with-external-gsm --with-external-srtp \ - --with-external-pa --disable-video --disable-v4l2 --disable-sound --disable-resample \ + --disable-video --disable-v4l2 --disable-sound --disable-resample \ --disable-opencore-amr --disable-ilbc-codec --without-libyuv --disable-g7221-codec \ --enable-epoll From dcb25bb05792f5cbbb458b264030f68cfb59b682 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Fri, 11 Mar 2016 23:03:08 +0100 Subject: [PATCH 0256/1578] app_chanspy: Fix occasional deadlock with ChanSpy and Local channels. Channel masquerading had a conflict with autochannel locking. When locking autochannel->channel, the channel is fetched from the autochannel and then locked. During the fetch, the autochannel -- which has no locks itself -- can be modified by someone who owns the channel lock. That means that the value of autochan->channel cannot be trusted until you hold the lock. In practice, this caused problems with Local channels getting masqueraded away while the ChanSpy attempted to get info from that channel. The old channel which was about to get removed got locked, but the new (replaced) channel got unlocked (no-op). Because the replaced channel was now locked (and would never get unlocked), it couldn't get removed from the channel list in a timely manner, and would now cause deadlocks when iterating over the channel list. This change checks the autochannel after locking the channel for changes to the autochannel. If the channel had been changed, the lock is reobtained on the new channel. In theory it seems possible that after this fix, the lock attempt on the old (wrong) channel can be on an already destroyed lock, maybe causing a crash. But that hasn't been observed in the wild and is harder induce than the current deadlock. Thanks go to Filip Frank for suggesting a fix similar to this and especially to IRC user hexanol for pointing out why this deadlock was possible and testing this fix. And to Richard for catching my rookie while loop mistake ;) ASTERISK-25321 #close Change-Id: I293ae0014e531cd0e675c3f02d1d118a98683def --- apps/app_chanspy.c | 8 ++++---- apps/app_mixmonitor.c | 8 ++++---- include/asterisk/autochan.h | 20 ++++++++++++++++++++ main/autochan.c | 6 +++--- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 3c7a9171635..5dbb0b86030 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -598,12 +598,12 @@ static int attach_barge(struct ast_autochan *spyee_autochan, return -1; } - ast_channel_lock(internal_bridge_autochan->chan); + ast_autochan_channel_lock(internal_bridge_autochan); if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook)) { ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name); retval = -1; } - ast_channel_unlock(internal_bridge_autochan->chan); + ast_autochan_channel_unlock(internal_bridge_autochan); *spyee_bridge_autochan = internal_bridge_autochan; @@ -632,9 +632,9 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto spyer_name = ast_strdupa(ast_channel_name(chan)); ast_channel_unlock(chan); - ast_channel_lock(spyee_autochan->chan); + ast_autochan_channel_lock(spyee_autochan); name = ast_strdupa(ast_channel_name(spyee_autochan->chan)); - ast_channel_unlock(spyee_autochan->chan); + ast_autochan_channel_unlock(spyee_autochan); ast_verb(2, "Spying on channel %s\n", name); publish_chanspy_message(chan, spyee_autochan->chan, 1); diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index f5f9b22c17b..7d7a0cbf914 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -726,11 +726,11 @@ static void *mixmonitor_thread(void *obj) ast_audiohook_unlock(&mixmonitor->audiohook); - ast_channel_lock(mixmonitor->autochan->chan); + ast_autochan_channel_lock(mixmonitor->autochan); if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) { ast_stream_and_wait(mixmonitor->autochan->chan, "beep", ""); } - ast_channel_unlock(mixmonitor->autochan->chan); + ast_autochan_channel_unlock(mixmonitor->autochan); ast_autochan_destroy(mixmonitor->autochan); @@ -802,11 +802,11 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel return -1; } - ast_channel_lock(mixmonitor->autochan->chan); + ast_autochan_channel_lock(mixmonitor->autochan); if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) { ast_stream_and_wait(mixmonitor->autochan->chan, "beep", ""); } - ast_channel_unlock(mixmonitor->autochan->chan); + ast_autochan_channel_unlock(mixmonitor->autochan); mixmonitor_ds->samp_rate = 8000; mixmonitor_ds->audiohook = &mixmonitor->audiohook; diff --git a/include/asterisk/autochan.h b/include/asterisk/autochan.h index a0981b7c9f6..319c203ab15 100644 --- a/include/asterisk/autochan.h +++ b/include/asterisk/autochan.h @@ -56,8 +56,28 @@ struct ast_autochan { * to save off the pointer using ast_channel_ref and to unref the channel when you * are finished with the pointer. If you do not do this and a masquerade occurs on * the channel, then it is possible that your saved pointer will become invalid. + * + * 3. If you want to lock the autochan->chan channel, be sure to use + * ast_autochan_channel_lock and ast_autochan_channel_unlock. An attempt to lock + * the autochan->chan directly may result in it being changed after you've + * retrieved the value of chan, but before you've had a chance to lock it. + * First when chan is locked, the autochan structure is guaranteed to keep the + * same channel. */ +#define ast_autochan_channel_lock(autochan) \ + do { \ + struct ast_channel *autochan_chan = autochan->chan; \ + ast_channel_lock(autochan_chan); \ + if (autochan->chan == autochan_chan) { \ + break; \ + } \ + ast_channel_unlock(autochan_chan); \ + } while (1) + +#define ast_autochan_channel_unlock(autochan) \ + ast_channel_unlock(autochan->chan) + /*! * \brief set up a new ast_autochan structure * diff --git a/main/autochan.c b/main/autochan.c index d41a8d82143..38d778438cb 100644 --- a/main/autochan.c +++ b/main/autochan.c @@ -51,7 +51,7 @@ struct ast_autochan *ast_autochan_setup(struct ast_channel *chan) autochan->chan = ast_channel_ref(chan); - ast_channel_lock(autochan->chan); + ast_channel_lock(autochan->chan); /* autochan is still private, no need for ast_autochan_channel_lock() */ AST_LIST_INSERT_TAIL(ast_channel_autochans(autochan->chan), autochan, list); ast_channel_unlock(autochan->chan); @@ -64,7 +64,7 @@ void ast_autochan_destroy(struct ast_autochan *autochan) { struct ast_autochan *autochan_iter; - ast_channel_lock(autochan->chan); + ast_autochan_channel_lock(autochan); AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_autochans(autochan->chan), autochan_iter, list) { if (autochan_iter == autochan) { AST_LIST_REMOVE_CURRENT(list); @@ -73,7 +73,7 @@ void ast_autochan_destroy(struct ast_autochan *autochan) } } AST_LIST_TRAVERSE_SAFE_END; - ast_channel_unlock(autochan->chan); + ast_autochan_channel_unlock(autochan); autochan->chan = ast_channel_unref(autochan->chan); From 638133131ada1f9678b93abb509082160f35ac76 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 10 Mar 2016 12:09:13 -0700 Subject: [PATCH 0257/1578] pjproject: Pass (dont_)optimize flags to pjproject and fix pjsua The pjproject Makefile now uses the Asterisk optimization flags which are determined by the setting of the DONT_OPTMIZE menuselect flag. The Makefile was also restructured so a change to the top level menuselect.makeopts will result in a rebuild of pjproject. Also, "--disable-resample" was removed from the pjproject configure options. Without resample, pjsua (which is used by the testsuite) can't make audio calls. When it can't, it segfaults. Change-Id: I24b0a4d0872acef00ed89b3c527a713ee4c2ccd4 --- third-party/pjproject/Makefile | 95 +++++++++++++++++++--------- third-party/pjproject/Makefile.rules | 2 +- 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 310095159c9..5810a65dc76 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -1,59 +1,87 @@ .SUFFIXES: .PHONY: _all all _install install clean distclean echo_cflags configure -ifeq ($(MAKECMDGOALS),install) -include ../../makeopts -else --include ../../makeopts -endif - include ../versions.mak -include ../Makefile.rules -include Makefile.rules -ECHO_PREFIX := $(ECHO_PREFIX) echo '[pjproject] ' +SPECIAL_TARGETS := -ifeq ($(MAKECMDGOALS),echo_cflags) --include build.mak -ECHO_PREFIX=@\# +ifneq ($(findstring configure,$(MAKECMDGOALS))$(findstring echo_cflags,$(MAKECMDGOALS)),) +# Run from $(ASTTOPDIR)/configure + SPECIAL_TARGETS += configure + include ../Makefile.rules + include Makefile.rules endif -ifneq ($(PJPROJECT_BUNDLED),yes) -all install: - @echo '[pjproject] Not enabled' -else +ifeq ($(findstring echo_cflags,$(MAKECMDGOALS)),echo_cflags) + -include build.mak + ECHO_PREFIX=@\# +endif -ifneq ($(findstring clean,$(MAKECMDGOALS)),clean) -include build.mak +ifeq ($(findstring clean,$(MAKECMDGOALS)),clean) +# clean or distclean + SPECIAL_TARGETS += clean + include ../Makefile.rules + include Makefile.rules endif -all: _all -install: _install +ifeq ($(SPECIAL_TARGETS),) +# Run locally or from $(ASTTOPDIR)/Makefile. All include files should be present + ifeq ($(wildcard ../../makeopts),) + $(error ASTTOPDIR/configure hasn't been run) + endif + include ../../makeopts + + ifeq ($(PJPROJECT_BUNDLED),yes) + -include ../../menuselect.makeopts + include ../Makefile.rules + + all: _all + install: _install + + include ../../Makefile.rules + include Makefile.rules + include build.mak + CF := $(filter-out -W%,$(CC_CFLAGS)) + CF := $(filter-out -I%,$(CF)) + export CFLAGS += $(CF) + export LDFLAGS += $(CC_LDFLAGS) + else + all install: + endif endif +ECHO_PREFIX := $(ECHO_PREFIX) echo '[pjproject] ' + ifndef $(TMPDIR) -ifneq ($(wildcard /tmp),) -TMPDIR=/tmp -else -TMPDIR=. -endif + ifneq ($(wildcard /tmp),) + TMPDIR=/tmp + else + TMPDIR=. + endif endif $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 : ../versions.mak $(ECHO_PREFIX) Downloading $@ with $(DOWNLOAD) $(CMD_PREFIX) $(DOWNLOAD) $(PJPROJECT_URL)/$(@F) > $@ -source/user.mak source/pjlib/include/pj/config_site.h: $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 patches/config_site.h patches/user.mak +source/.unpacked: $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 $(ECHO_PREFIX) Unpacking $< -@rm -rf source &>/dev/null -@mkdir source &>/dev/null $(CMD_PREFIX) tar --strip-components=1 -C source -xjf $< - $(ECHO_PREFIX) Applying patches and custom files + $(ECHO_PREFIX) Applying patches $(CMD_PREFIX) ./apply_patches $(QUIET_CONFIGURE) ./patches ./source - $(CMD_PREFIX) cp -f ./patches/config_site.h ./source/pjlib/include/pj/ + -@touch source/.unpacked + +source/user.mak: source/.unpacked ./patches/user.mak + $(ECHO_PREFIX) Applying user.mak $(CMD_PREFIX) cp -f ./patches/user.mak ./source/ -build.mak: source/pjlib/include/pj/config_site.h source/user.mak Makefile.rules +source/pjlib/include/pj/config_site.h: source/.unpacked ./patches/config_site.h + $(ECHO_PREFIX) Applying config_site.h + $(CMD_PREFIX) cp -f ./patches/config_site.h ./source/pjlib/include/pj/ + +build.mak: source/.unpacked source/pjlib/include/pj/config_site.h source/user.mak Makefile.rules $(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS) $(CMD_PREFIX) (cd source ; autoconf aconfigure.ac > aconfigure && ./aconfigure $(QUIET_CONFIGURE) $(PJPROJECT_CONFIG_OPTS)) @sed -r -e "/prefix|export PJ_SHARED_LIBRARIES|MACHINE_NAME|OS_NAME|HOST_NAME|CC_NAME|CROSS_COMPILE|LINUX_POLL/d" source/build.mak > build.mak @@ -67,7 +95,13 @@ source/pjlib/build/.pjlib-$(TARGET_NAME).depend: build.mak $(ECHO_PREFIX) "Making dependencies" +$(CMD_PREFIX) $(SUBMAKE) -C source dep -source/pjlib/lib/libpj-$(TARGET_NAME).a: source/pjlib/build/.pjlib-$(TARGET_NAME).depend + +menuselect: ../../menuselect.makeopts ../../makeopts + -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || : + -$(CMD_PREFIX) rm -rf pjproject.symbols + + +source/pjlib/lib/libpj-$(TARGET_NAME).a: menuselect source/pjlib/build/.pjlib-$(TARGET_NAME).depend $(ECHO_PREFIX) Compiling libs +$(CMD_PREFIX) $(SUBMAKE) -C source lib $(REALLY_QUIET) @@ -83,6 +117,7 @@ source/pjsip-apps/src/python/build/_pjsua.so: source/pjlib/lib/libpj-$(TARGET_NA $(ECHO_PREFIX) Compiling python bindings $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; python setup.py build --build-platlib=./build $(REALLY_QUIET)) + _all: pjproject.symbols source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/src/python/build/_pjsua.so _install: _all diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index 6319ed5163d..f39629b9221 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -2,6 +2,6 @@ PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --with-external-speex --with-external-gsm --with-external-srtp \ - --disable-video --disable-v4l2 --disable-sound --disable-resample \ + --with-external-pa --disable-video --disable-v4l2 --disable-sound \ --disable-opencore-amr --disable-ilbc-codec --without-libyuv --disable-g7221-codec \ --enable-epoll From 0af6b5de620a89645372e4ac7e00bcd27221ad96 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 12 Mar 2016 15:02:20 -0700 Subject: [PATCH 0258/1578] build_system: Split COMPILE_DOUBLE from DONT_OPTIMIZE I can't ever recall actually needing the intermediate files or the checking that a double compile produces. What I CAN remember is every DONT_OPTIMIZE build needing 3 invocations of gcc instead of 1 just to do the checks and produce those intermediate files. Having said that, Richard pointed out that the reason for the double compile was that there were cases in the past where a submitted patch failed to compile because the submitter never tried it with the optimizations turned on. To get the best of both worlds, COMPILE_DOUBLE has been split into its own option. If DONT_OPTIMIZE is turned on, COMPILE_DOUBLE will also be selected BUT you can then turn it off if all you need are the debugging symbols. This way you have to make an informed decision about disabling COMPILE_DOUBLE. To allow COMPILE_DOUBLE to be both auto-selected and turned off, a new feature was added to menuselect. The element can now contain an "autoselect" attribute which will turn the used member on but not create a hard dependency. The cflags.xml implementation for COMPILE_DOUBLE looks like this... COMPILE_DOUBLE core + COMPILE_DOUBLE + core + + + DONT_OPTIMIZE core diff --git a/menuselect/menuselect.c b/menuselect/menuselect.c index f4a826b842b..6136135aa58 100644 --- a/menuselect/menuselect.c +++ b/menuselect/menuselect.c @@ -357,6 +357,10 @@ static int process_xml_ref_node(xmlNode *node, struct member *mem, struct refere } } + if ((tmp = (const char *) xmlGetProp(node, BAD_CAST "autoselect"))) { + ref->autoselect = !strcasecmp(tmp, "yes"); + } + tmp = (const char *) xmlNodeGetContent(node); if (tmp && !strlen_zero(tmp)) { @@ -1154,8 +1158,16 @@ unsigned int enable_member(struct member *mem) } if ((mem->enabled = can_enable)) { + struct reference *use; + print_debug("Just set %s enabled to %d\n", mem->name, mem->enabled); while (calc_dep_failures(1, 0) || calc_conflict_failures(1, 0)); + + AST_LIST_TRAVERSE(&mem->uses, use, list) { + if (use->member && use->autoselect && !use->member->enabled) { + enable_member(use->member); + } + } } return can_enable; diff --git a/menuselect/menuselect.h b/menuselect/menuselect.h index b1d22dd7530..112f1c88cba 100644 --- a/menuselect/menuselect.h +++ b/menuselect/menuselect.h @@ -43,6 +43,8 @@ struct reference { struct member *member; /*! if this package was found */ unsigned char met:1; + /*! if this package should be autoselected */ + unsigned char autoselect:1; /*! for linking */ AST_LIST_ENTRY(reference) list; }; diff --git a/menuselect/menuselect_curses.c b/menuselect/menuselect_curses.c index 5afa9966195..00645927ad4 100644 --- a/menuselect/menuselect_curses.c +++ b/menuselect/menuselect_curses.c @@ -158,6 +158,12 @@ static int really_quit(WINDOW *win) return c; } +#define MENU_HELP_LEFT_ADJ 16 +#define MAIN_MENU_LEFT_ADJ 20 +#define CAT_MENU_LEFT_ADJ 20 +#define SCROLL_DOWN_LEFT_ADJ 15 +#define MEMBER_INFO_LEFT_ADJ 25 + static void draw_main_menu(WINDOW *menu, int curopt) { struct category *cat; @@ -167,42 +173,67 @@ static void draw_main_menu(WINDOW *menu, int curopt) wclear(menu); AST_LIST_TRAVERSE(&categories, cat, list) { - wmove(menu, i++, max_x / 2 - 10); - snprintf(buf, sizeof(buf), " %s", strlen_zero(cat->displayname) ? cat->name : cat->displayname); + wmove(menu, i++, max_x / 2 - MAIN_MENU_LEFT_ADJ); + snprintf(buf, sizeof(buf), "%s", strlen_zero(cat->displayname) ? cat->name : cat->displayname); waddstr(menu, buf); } - wmove(menu, curopt, (max_x / 2) - 15); + wmove(menu, curopt, (max_x / 2) - MAIN_MENU_LEFT_ADJ - 5); waddstr(menu, "--->"); - wmove(menu, 0, 0); + wmove(menu, curopt, (max_x / 2) - MAIN_MENU_LEFT_ADJ); wrefresh(menu); } -static void display_mem_info(WINDOW *menu, struct member *mem, int start, int end) +static void display_mem_info(WINDOW *menu, struct member *mem, int start_y, int end) { char buf[64]; struct reference *dep; struct reference *con; struct reference *use; + int start_x = (max_x / 2 - MEMBER_INFO_LEFT_ADJ); + int maxlen = (max_x - start_x); - wmove(menu, end - start + 2, max_x / 2 - 16); + wmove(menu, end - start_y + 1, start_x); + wclrtoeol(menu); + wmove(menu, end - start_y + 2, start_x); wclrtoeol(menu); - wmove(menu, end - start + 3, max_x / 2 - 16); + wmove(menu, end - start_y + 3, start_x); wclrtoeol(menu); - wmove(menu, end - start + 4, max_x / 2 - 16); + wmove(menu, end - start_y + 4, start_x); wclrtoeol(menu); - wmove(menu, end - start + 5, max_x / 2 - 16); + wmove(menu, end - start_y + 5, start_x); wclrtoeol(menu); - wmove(menu, end - start + 6, max_x / 2 - 16); + wmove(menu, end - start_y + 6, start_x); wclrtoeol(menu); if (mem->displayname) { - wmove(menu, end - start + 2, max_x / 2 - 16); - waddstr(menu, (char *) mem->displayname); + int name_len = strlen(mem->displayname); + + wmove(menu, end - start_y + 1, start_x); + if (name_len > maxlen) { + char *last_space; + char *line_1 = strdup(mem->displayname); + + if (line_1) { + line_1[maxlen] = '\0'; + last_space = strrchr(line_1, ' '); + if (last_space) { + *last_space = '\0'; + } + waddstr(menu, line_1); + wmove(menu, end - start_y + 2, start_x); + waddstr(menu, &mem->displayname[last_space - line_1]); + free(line_1); + } else { + waddstr(menu, (char *) mem->displayname); + } + } else { + waddstr(menu, (char *) mem->displayname); + } } if (!AST_LIST_EMPTY(&mem->deps)) { - wmove(menu, end - start + 3, max_x / 2 - 16); + wmove(menu, end - start_y + 3, start_x); strcpy(buf, "Depends on: "); AST_LIST_TRAVERSE(&mem->deps, dep, list) { strncat(buf, dep->displayname, sizeof(buf) - strlen(buf) - 1); @@ -213,7 +244,7 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start, int en waddstr(menu, buf); } if (!AST_LIST_EMPTY(&mem->uses)) { - wmove(menu, end - start + 4, max_x / 2 - 16); + wmove(menu, end - start_y + 4, start_x); strcpy(buf, "Can use: "); AST_LIST_TRAVERSE(&mem->uses, use, list) { strncat(buf, use->displayname, sizeof(buf) - strlen(buf) - 1); @@ -224,7 +255,7 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start, int en waddstr(menu, buf); } if (!AST_LIST_EMPTY(&mem->conflicts)) { - wmove(menu, end - start + 5, max_x / 2 - 16); + wmove(menu, end - start_y + 5, start_x); strcpy(buf, "Conflicts with: "); AST_LIST_TRAVERSE(&mem->conflicts, con, list) { strncat(buf, con->displayname, sizeof(buf) - strlen(buf) - 1); @@ -237,7 +268,7 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start, int en if (!mem->is_separator) { /* Separators lack support levels */ { /* support level */ - wmove(menu, end - start + 6, max_x / 2 - 16); + wmove(menu, end - start_y + 6, start_x); snprintf(buf, sizeof(buf), "Support Level: %s", mem->support_level); if (mem->replacement && *mem->replacement) { char buf2[64]; @@ -266,7 +297,7 @@ static void draw_category_menu(WINDOW *menu, struct category *cat, int start, in break; } } - wmove(menu, curopt - start, max_x / 2 - 9); + wmove(menu, curopt - start, (max_x / 2) - (CAT_MENU_LEFT_ADJ - 1)); wrefresh(menu); return; } @@ -279,7 +310,7 @@ static void draw_category_menu(WINDOW *menu, struct category *cat, int start, in i++; continue; } - wmove(menu, j++, max_x / 2 - 10); + wmove(menu, j++, max_x / 2 - CAT_MENU_LEFT_ADJ); i++; if ((mem->depsfailed == HARD_FAILURE) || (mem->conflictsfailed == HARD_FAILURE)) { snprintf(buf, sizeof(buf), "XXX %s", mem->name); @@ -302,11 +333,11 @@ static void draw_category_menu(WINDOW *menu, struct category *cat, int start, in } if (flags & SCROLL_DOWN) { - wmove(menu, j, max_x / 2 - sizeof(SCROLL_DOWN_INDICATOR) / 2); + wmove(menu, j, max_x / 2 - SCROLL_DOWN_LEFT_ADJ); waddstr(menu, SCROLL_DOWN_INDICATOR); } - wmove(menu, curopt - start, max_x / 2 - 9); + wmove(menu, curopt - start, (max_x / 2) - (CAT_MENU_LEFT_ADJ - 1)); wrefresh(menu); } @@ -465,7 +496,7 @@ static void draw_title_window(WINDOW *title) waddstr(title, (char *) menu_name); wmove(title, 3, (max_x / 2) - (strlen(titlebar) / 2)); waddstr(title, titlebar); - wmove(title, 5, (max_x / 2) - (strlen(MENU_HELP) / 2)); + wmove(title, 5, (max_x / 2) - MENU_HELP_LEFT_ADJ); waddstr(title, MENU_HELP); wrefresh(title); } From 4df7b3ae80d7d022c0fd941de614b829948ce3ef Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 14 Mar 2016 10:59:10 -0300 Subject: [PATCH 0259/1578] build: Add configure check for proto field of PJSIP TLS transport setting. Older versions of PJSIP do not have the proto field on the TLS transport setting structure. This change adds a configure check so even if it is not present we will still be able to build. Change-Id: Ibf3f47befb91ed1b8194bf63888baa6fee05aba9 --- configure | 81 ++++++++++++++++++++++++++++-- configure.ac | 9 ++++ include/asterisk/autoconfig.h.in | 3 ++ res/res_pjsip/config_transport.c | 2 + third-party/pjproject/configure.m4 | 1 + 5 files changed, 91 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 3967cec633c..f2d0d697099 100755 --- a/configure +++ b/configure @@ -919,6 +919,10 @@ PBX_POPT POPT_DIR POPT_INCLUDE POPT_LIB +PBX_PJSIP_TLS_TRANSPORT_PROTO +PJSIP_TLS_TRANSPORT_PROTO_DIR +PJSIP_TLS_TRANSPORT_PROTO_INCLUDE +PJSIP_TLS_TRANSPORT_PROTO_LIB PBX_PJSIP_EXTERNAL_RESOLVER PJSIP_EXTERNAL_RESOLVER_DIR PJSIP_EXTERNAL_RESOLVER_INCLUDE @@ -10547,6 +10551,18 @@ PBX_PJSIP_EXTERNAL_RESOLVER=0 +PJSIP_TLS_TRANSPORT_PROTO_DESCRIP="PJSIP TLS Transport proto field support" +PJSIP_TLS_TRANSPORT_PROTO_OPTION=pjsip +PJSIP_TLS_TRANSPORT_PROTO_DIR=${PJPROJECT_DIR} + +PBX_PJSIP_TLS_TRANSPORT_PROTO=0 + + + + + + + POPT_DESCRIP="popt" POPT_OPTION="popt" @@ -13746,7 +13762,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13792,7 +13808,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13816,7 +13832,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13861,7 +13877,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13885,7 +13901,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -24707,6 +24723,9 @@ rm -f conftest* PJSIP_EXTERNAL_RESOLVER_INCLUDE="$PJPROJECT_INCLUDE" +$as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h + + else if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then @@ -25370,6 +25389,58 @@ _ACEOF fi + + saved_cppflags="${CPPFLAGS}" + saved_libs="${LIBS}" + CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}" + LIBS="${LIBS} ${PJPROJECT_LIB}" + + if test "x${PBX_PJSIP_TLS_TRANSPORT_PROTO}" != "x1" -a "${USE_PJSIP_TLS_TRANSPORT_PROTO}" != "no"; then + if test "x" != "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for " >&5 +$as_echo_n "checking for ... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if \"struct pjsip_tls_setting setting; int proto; proto = setting.proto;\" compiles using pjsip.h" >&5 +$as_echo_n "checking if \"struct pjsip_tls_setting setting; int proto; proto = setting.proto;\" compiles using pjsip.h... " >&6; } + fi + saved_cppflags="${CPPFLAGS}" + if test "x${PJSIP_TLS_TRANSPORT_PROTO_DIR}" != "x"; then + PJSIP_TLS_TRANSPORT_PROTO_INCLUDE="-I${PJSIP_TLS_TRANSPORT_PROTO_DIR}/include" + fi + CPPFLAGS="${CPPFLAGS} ${PJSIP_TLS_TRANSPORT_PROTO_INCLUDE}" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ + struct pjsip_tls_setting setting; int proto; proto = setting.proto;; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_PJSIP_TLS_TRANSPORT_PROTO=1 + +$as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h + + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CPPFLAGS="${saved_cppflags}" + fi + + LIBS="${saved_libs}" + CPPFLAGS="${saved_cppflags}" fi fi diff --git a/configure.ac b/configure.ac index 12cc8d276c8..c0d5cb0c3ea 100644 --- a/configure.ac +++ b/configure.ac @@ -482,6 +482,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_REPLACE_MEDIA_STREAM], [PJSIP Media Stream Rep AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_GET_DEST_INFO], [pjsip_get_dest_info support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_from_files2 support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EXTERNAL_RESOLVER], [PJSIP External Resolver Support], [PJPROJECT], [pjsip]) +AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_PROTO], [PJSIP TLS Transport proto field support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP([POPT], [popt], [popt]) AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio]) @@ -2196,6 +2197,14 @@ if test "$USE_PJPROJECT" != "no" ; then AST_EXT_LIB_CHECK([PJSIP_GET_DEST_INFO], [pjsip], [pjsip_get_dest_info], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj], [pjsip/include/pjsip/sip_util.h], [pjlib.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip], [pjsip_endpt_set_ext_resolver], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) + + saved_cppflags="${CPPFLAGS}" + saved_libs="${LIBS}" + CPPFLAGS="${CPPFLAGS} ${PJPROJECT_CFLAGS}" + LIBS="${LIBS} ${PJPROJECT_LIB}" + AST_C_COMPILE_CHECK([PJSIP_TLS_TRANSPORT_PROTO], [struct pjsip_tls_setting setting; int proto; proto = setting.proto;], [pjsip.h]) + LIBS="${saved_libs}" + CPPFLAGS="${saved_cppflags}" fi fi diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 43f86b08841..b5fe655d7fa 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -595,6 +595,9 @@ /* Define if your system has the PJSIP_REPLACE_MEDIA_STREAM headers. */ #undef HAVE_PJSIP_REPLACE_MEDIA_STREAM +/* Define if your system has the PJSIP_TLS_TRANSPORT_PROTO headers. */ +#undef HAVE_PJSIP_TLS_TRANSPORT_PROTO + /* Define if your system has pj_ssl_cert_load_from_files2 declared. */ #undef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index db579bf2f62..d2c087487a5 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -422,7 +422,9 @@ static int has_state_changed(struct ast_sip_transport_state *a, struct ast_sip_t if (a->tls.method != b->tls.method || a->tls.ciphers_num != b->tls.ciphers_num +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO || a->tls.proto != b->tls.proto +#endif || a->tls.verify_client != b->tls.verify_client || a->tls.verify_server != b->tls.verify_server || a->tls.require_client_cert != b->tls.require_client_cert) { diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 3351527ebb5..74322277401 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -43,4 +43,5 @@ AC_DEFUN([PJPROJECT_CONFIGURE], PJPROJECT_SYMBOL_CHECK([PJSIP_GET_DEST_INFO], [pjsip_get_dest_info], [pjsip.h]) PJPROJECT_SYMBOL_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_from_files2], [pjlib.h]) PJPROJECT_SYMBOL_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip_endpt_set_ext_resolver], [pjsip.h]) + AC_DEFINE([HAVE_PJSIP_TLS_TRANSPORT_PROTO], 1, [Define if your system has PJSIP_TLS_TRANSPORT_PROTO]) ]) From 8be01398d93a7b3df0601e80e839b45a80245254 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 4 Mar 2016 18:25:21 -0600 Subject: [PATCH 0260/1578] chan_sip.c: Made sip_reinvite_retry() call sip_pvt_lock_full(). Change-Id: I90f04208a089f95488a2460185a8dbc3f6acca12 --- channels/chan_sip.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 2d5843d91ab..13fe7cef1d6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -22889,18 +22889,14 @@ static int sip_reinvite_retry(const void *data) struct sip_pvt *p = (struct sip_pvt *) data; struct ast_channel *owner; - sip_pvt_lock(p); /* called from schedule thread which requires a lock */ - while ((owner = p->owner) && ast_channel_trylock(owner)) { - sip_pvt_unlock(p); - usleep(1); - sip_pvt_lock(p); - } + owner = sip_pvt_lock_full(p); ast_set_flag(&p->flags[0], SIP_NEEDREINVITE); p->waitid = -1; check_pendings(p); sip_pvt_unlock(p); if (owner) { ast_channel_unlock(owner); + ast_channel_unref(owner); } dialog_unref(p, "unref the dialog ptr from sip_reinvite_retry, because it held a dialog ptr"); return 0; From cb97198ca648fb9e91f9e5f9328442d538fcbf63 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 7 Mar 2016 18:56:05 -0600 Subject: [PATCH 0261/1578] chan_sip.c: Simplify sip_pvt destructor call levels. Remove destructor calling destroy_it calling really_destroy_it for no benefit. Just make the destructor the really_destroy_it function. Change-Id: Idea0d47b27dd74f2488db75bcc7f353d8fdc614a --- channels/chan_sip.c | 33 ++++++++------------------------- channels/sip/include/dialog.h | 13 ------------- 2 files changed, 8 insertions(+), 38 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 2d5843d91ab..a8d5032062e 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -6381,11 +6381,14 @@ static void offered_media_list_destroy(struct sip_pvt *p) } } -/*! \brief Execute destruction of SIP dialog structure, release memory */ -void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist) +/*! \brief ao2 destructor for SIP dialog structure */ +static void sip_pvt_dtor(void *vdoomed) { + struct sip_pvt *p = vdoomed; struct sip_request *req; + ast_debug(3, "Destroying SIP dialog %s\n", p->callid); + /* Destroy Session-Timers if allocated */ if (p->stimer) { p->stimer->quit_flag = 1; @@ -6404,14 +6407,12 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist) /* Unlink us from the owner if we have one */ if (p->owner) { - if (lockowner) - ast_channel_lock(p->owner); + ast_channel_lock(p->owner); ast_debug(1, "Detaching from %s\n", ast_channel_name(p->owner)); ast_channel_tech_pvt_set(p->owner, NULL); /* Make sure that the channel knows its backend is going away */ ast_channel_softhangup_internal_flag_add(p->owner, AST_SOFTHANGUP_DEV); - if (lockowner) - ast_channel_unlock(p->owner); + ast_channel_unlock(p->owner); /* Give the channel a chance to react before deallocation */ usleep(1); } @@ -6716,24 +6717,6 @@ static int update_call_counter(struct sip_pvt *fup, int event) return 0; } - -static void sip_destroy_fn(void *p) -{ - sip_destroy(p); -} - -/*! \brief Destroy SIP call structure. - * Make it return NULL so the caller can do things like - * foo = sip_destroy(foo); - * and reduce the chance of bugs due to dangling pointers. - */ -struct sip_pvt *sip_destroy(struct sip_pvt *p) -{ - ast_debug(3, "Destroying SIP dialog %s\n", p->callid); - __sip_destroy(p, TRUE, TRUE); - return NULL; -} - /*! \brief Convert SIP hangup causes to Asterisk hangup causes */ int hangup_sip2cause(int cause) { @@ -8635,7 +8618,7 @@ struct sip_pvt *__sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, { struct sip_pvt *p; - p = __ao2_alloc(sizeof(*p), sip_destroy_fn, + p = __ao2_alloc(sizeof(*p), sip_pvt_dtor, AO2_ALLOC_OPT_LOCK_MUTEX, "allocate a dialog(pvt) struct", file, line, func); if (!p) { diff --git a/channels/sip/include/dialog.h b/channels/sip/include/dialog.h index beacdb9890f..f6adea59b3a 100644 --- a/channels/sip/include/dialog.h +++ b/channels/sip/include/dialog.h @@ -43,19 +43,6 @@ void sip_scheddestroy_final(struct sip_pvt *p, int ms); void sip_scheddestroy(struct sip_pvt *p, int ms); int sip_cancel_destroy(struct sip_pvt *p); -/*! \brief Destroy SIP call structure. - * Make it return NULL so the caller can do things like - * foo = sip_destroy(foo); - * and reduce the chance of bugs due to dangling pointers. - */ -struct sip_pvt *sip_destroy(struct sip_pvt *p); - -/*! \brief Destroy SIP call structure. - * Make it return NULL so the caller can do things like - * foo = sip_destroy(foo); - * and reduce the chance of bugs due to dangling pointers. - */ -void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist); /*! * \brief Unlink a dialog from the dialogs container, as well as any other places * that it may be currently stored. From 7964e260d364dd0bf57677e418de67b46fae1700 Mon Sep 17 00:00:00 2001 From: Andrew Nagy Date: Tue, 15 Mar 2016 11:31:19 -0700 Subject: [PATCH 0262/1578] app_stasis: Don't hang up if app is not registered This prevents pbx_core from hanging up the channel if the app isn't registered. ASTERISK-25846 #close Change-Id: I63216a61f30706d5362bc0906b50b6f0544aebce --- apps/app_stasis.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/app_stasis.c b/apps/app_stasis.c index aa77a0d3c38..ffe4727794a 100644 --- a/apps/app_stasis.c +++ b/apps/app_stasis.c @@ -110,10 +110,16 @@ static int app_exec(struct ast_channel *chan, const char *data) args.app_argv); } - if (ret == -1) { - pbx_builtin_setvar_helper(chan, "STASISSTATUS", "FAILED"); + if (ret) { + /* set ret to 0 so pbx_core doesnt hangup the channel */ + if (!ast_check_hangup(chan)) { + ret = 0; + } else { + ret = -1; + } + pbx_builtin_setvar_helper(chan, "STASISSTATUS", "FAILED"); } else { - pbx_builtin_setvar_helper(chan, "STASISSTATUS", "SUCCESS"); + pbx_builtin_setvar_helper(chan, "STASISSTATUS", "SUCCESS"); } return ret; From 9a7cfa2b61d90bc229d478b669833a6caf19b0c1 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 7 Mar 2016 15:50:22 -0600 Subject: [PATCH 0263/1578] sched.c: Ensure oldest expiring entry runs first. This patch is part of a series to resolve deadlocks in chan_sip.c. * Updated sched unit test to check new behavior. ASTERISK-25023 Change-Id: Ib69437327b3cda5e14c4238d9ff91b2531b34ef3 --- main/sched.c | 45 +++++++++++++++++--- tests/test_sched.c | 104 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 5 deletions(-) diff --git a/main/sched.c b/main/sched.c index 7b7021d6170..9fee5b9cf58 100644 --- a/main/sched.c +++ b/main/sched.c @@ -83,6 +83,14 @@ struct sched { /*! The ID that has been popped off the scheduler context's queue */ struct sched_id *sched_id; struct timeval when; /*!< Absolute time event should take place */ + /*! + * \brief Tie breaker in case the when is the same for multiple entries. + * + * \note The oldest expiring entry in the scheduler heap goes first. + * This is possible when multiple events are scheduled to expire at + * the same time by internal coding. + */ + unsigned int tie_breaker; int resched; /*!< When to reschedule */ int variable; /*!< Use return value from callback to reschedule */ const void *data; /*!< Data */ @@ -107,6 +115,8 @@ struct ast_sched_context { ast_mutex_t lock; unsigned int eventcnt; /*!< Number of events processed */ unsigned int highwater; /*!< highest count so far */ + /*! Next tie breaker in case events expire at the same time. */ + unsigned int tie_breaker; struct ast_heap *sched_heap; struct sched_thread *sched_thread; /*! The scheduled task that is currently executing */ @@ -213,9 +223,17 @@ int ast_sched_start_thread(struct ast_sched_context *con) return 0; } -static int sched_time_cmp(void *a, void *b) +static int sched_time_cmp(void *va, void *vb) { - return ast_tvcmp(((struct sched *) b)->when, ((struct sched *) a)->when); + struct sched *a = va; + struct sched *b = vb; + int cmp; + + cmp = ast_tvcmp(b->when, a->when); + if (!cmp) { + cmp = b->tie_breaker - a->tie_breaker; + } + return cmp; } struct ast_sched_context *ast_sched_context_create(void) @@ -442,11 +460,28 @@ int ast_sched_wait(struct ast_sched_context *con) */ static void schedule(struct ast_sched_context *con, struct sched *s) { - ast_heap_push(con->sched_heap, s); + size_t size; + + size = ast_heap_size(con->sched_heap); - if (ast_heap_size(con->sched_heap) > con->highwater) { - con->highwater = ast_heap_size(con->sched_heap); + /* Record the largest the scheduler heap became for reporting purposes. */ + if (con->highwater <= size) { + con->highwater = size + 1; } + + /* Determine the tie breaker value for the new entry. */ + if (size) { + ++con->tie_breaker; + } else { + /* + * Restart the sequence for the first entry to make integer + * roll over more unlikely. + */ + con->tie_breaker = 0; + } + s->tie_breaker = con->tie_breaker; + + ast_heap_push(con->sched_heap, s); } /*! \brief diff --git a/tests/test_sched.c b/tests/test_sched.c index ec53ce88861..23a5e3ddf89 100644 --- a/tests/test_sched.c +++ b/tests/test_sched.c @@ -45,6 +45,67 @@ static int sched_cb(const void *data) return 0; } +static int order_check; +static int order_check_failed; + +static void sched_order_check(struct ast_test *test, int order) +{ + ++order_check; + if (order_check != order) { + ast_test_status_update(test, "Unexpected execution order: expected:%d got:%d\n", + order, order_check); + order_check_failed = 1; + } +} + +static int sched_order_1_cb(const void *data) +{ + sched_order_check((void *) data, 1); + return 0; +} + +static int sched_order_2_cb(const void *data) +{ + sched_order_check((void *) data, 2); + return 0; +} + +static int sched_order_3_cb(const void *data) +{ + sched_order_check((void *) data, 3); + return 0; +} + +static int sched_order_4_cb(const void *data) +{ + sched_order_check((void *) data, 4); + return 0; +} + +static int sched_order_5_cb(const void *data) +{ + sched_order_check((void *) data, 5); + return 0; +} + +static int sched_order_6_cb(const void *data) +{ + sched_order_check((void *) data, 6); + return 0; +} + +static int sched_order_7_cb(const void *data) +{ + sched_order_check((void *) data, 7); + return 0; +} + +static int sched_order_8_cb(const void *data) +{ + sched_order_check((void *) data, 8); + return 0; +} + AST_TEST_DEFINE(sched_test_order) { struct ast_sched_context *con; @@ -152,6 +213,49 @@ AST_TEST_DEFINE(sched_test_order) goto return_cleanup; } + /* + * Schedule immediate and delayed entries to check the order + * that they get executed. They must get executed at the + * time they expire in the order they were added. + */ +#define DELAYED_SAME_EXPIRE 300 /* ms */ + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_1_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_1_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_2_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_2_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_3_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_3_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_4_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_4_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_5_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_5_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_6_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_6_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_7_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, 0, sched_order_7_cb, test), res, return_cleanup); + ast_test_validate_cleanup(test, -1 < ast_sched_add(con, DELAYED_SAME_EXPIRE, sched_order_8_cb, test), res, return_cleanup); + + /* Check order of scheduled immediate entries. */ + order_check = 0; + order_check_failed = 0; + usleep(50 * 1000);/* Ensure that all the immediate entries are ready to expire */ + ast_test_validate_cleanup(test, 7 == ast_sched_runq(con), res, return_cleanup); + ast_test_validate_cleanup(test, !order_check_failed, res, return_cleanup); + + /* Check order of scheduled entries expiring at the same time. */ + order_check = 0; + order_check_failed = 0; + usleep((DELAYED_SAME_EXPIRE + 50) * 1000);/* Ensure that all the delayed entries are ready to expire */ + ast_test_validate_cleanup(test, 8 == ast_sched_runq(con), res, return_cleanup); + ast_test_validate_cleanup(test, !order_check_failed, res, return_cleanup); + + if ((wait = ast_sched_wait(con)) != -1) { + ast_test_status_update(test, + "ast_sched_wait() should have returned -1, returned '%d'\n", + wait); + goto return_cleanup; + } + res = AST_TEST_PASS; return_cleanup: From 0987a11cce90da40f5a6bec4646474c34dc55bc2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 15 Mar 2016 14:51:25 -0500 Subject: [PATCH 0264/1578] sip/dialplan_functions.c: Fix /channels/chan_sip/test_sip_rtpqos crash. This patch is part of a series to resolve deadlocks in chan_sip.c. Delaying destruction of the chan_sip sip_pvt structures caused the /channels/chan_sip/test_sip_rtpqos unit test to crash. That test registers a special test ast_rtp_engine with the rtp engine module. When the unit test completes it cleans up by unregistering the test ast_rtp_engine and exits. Since the delayed destruction of the sip_pvt happens after the unit test returns, the destructor tries to call the rtp engine destroy callback of the test ast_rtp_engine auto variable which no longer exists on the stack. * Change the test ast_rtp_engine auto variable to a static variable. Now the variable can still exist after the unit test exits so the delayed sip_pvt destruction can complete successfully. ASTERISK-25023 Change-Id: I61e34a12d425189ef7e96fc69ae14993f82f3f13 --- channels/sip/dialplan_functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c index 33ba71c27b8..644da385292 100644 --- a/channels/sip/dialplan_functions.c +++ b/channels/sip/dialplan_functions.c @@ -273,7 +273,7 @@ static int test_sip_rtpqos_1_get_stat(struct ast_rtp_instance *instance, struct AST_TEST_DEFINE(test_sip_rtpqos_1) { int i, res = AST_TEST_PASS; - struct ast_rtp_engine test_engine = { + static struct ast_rtp_engine test_engine = { .name = "test", .new = test_sip_rtpqos_1_new, .destroy = test_sip_rtpqos_1_destroy, From 52f0932e4c6d4446afbbf0f0ffa0ac8f50593ff4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 10 Mar 2016 21:54:03 -0600 Subject: [PATCH 0265/1578] chan_sip.c: Clear scheduled immediate events on unload. This patch is part of a series to resolve deadlocks in chan_sip.c. The reordering of chan_sip's shutdown is to handle any immediate events that get put onto the scheduler so resources aren't leaked. The typical immediate events at this time are going to be concerned with stopping other scheduled events. ASTERISK-25023 Change-Id: I3f6540717634f6f2e84d8531a054976f2bbb9d20 --- channels/chan_sip.c | 53 ++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index a8d5032062e..2719372089e 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -34879,6 +34879,26 @@ static int unload_module(void) ast_mutex_unlock(&monlock); } + cleanup_all_regs(); + + { + struct ao2_iterator iter; + struct sip_subscription_mwi *iterator; + + iter = ao2_iterator_init(subscription_mwi_list, 0); + while ((iterator = ao2_t_iterator_next(&iter, "unload_module iter"))) { + ao2_lock(iterator); + if (iterator->dnsmgr) { + ast_dnsmgr_release(iterator->dnsmgr); + iterator->dnsmgr = NULL; + ao2_t_ref(iterator, -1, "dnsmgr release"); + } + ao2_unlock(iterator); + ao2_t_ref(iterator, -1, "unload_module iter"); + } + ao2_iterator_destroy(&iter); + } + /* Destroy all the dialogs and free their memory */ i = ao2_iterator_init(dialogs, 0); while ((p = ao2_t_iterator_next(&i, "iterate thru dialogs"))) { @@ -34887,6 +34907,13 @@ static int unload_module(void) } ao2_iterator_destroy(&i); + /* + * Since the monitor thread runs the scheduled events and we + * just stopped the monitor thread above, we have to run any + * pending scheduled immediate events in this thread. + */ + ast_sched_runq(sched); + /* Free memory for local network address mask */ ast_free_ha(localaddr); @@ -34908,28 +34935,6 @@ static int unload_module(void) ast_rtp_dtls_cfg_free(&default_dtls_cfg); - cleanup_all_regs(); - ao2_cleanup(registry_list); - - { - struct ao2_iterator iter; - struct sip_subscription_mwi *iterator; - - iter = ao2_iterator_init(subscription_mwi_list, 0); - while ((iterator = ao2_t_iterator_next(&iter, "unload_module iter"))) { - ao2_lock(iterator); - if (iterator->dnsmgr) { - ast_dnsmgr_release(iterator->dnsmgr); - iterator->dnsmgr = NULL; - ao2_t_ref(iterator, -1, "dnsmgr release"); - } - ao2_unlock(iterator); - ao2_t_ref(iterator, -1, "unload_module iter"); - } - ao2_iterator_destroy(&iter); - } - ao2_cleanup(subscription_mwi_list); - /* * Wait awhile for the TCP/TLS thread container to become empty. * @@ -34945,6 +34950,9 @@ static int unload_module(void) ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); } + ao2_cleanup(registry_list); + ao2_cleanup(subscription_mwi_list); + ao2_t_global_obj_release(g_bogus_peer, "Release the bogus peer."); ao2_t_cleanup(peers, "unref the peers table"); @@ -34964,6 +34972,7 @@ static int unload_module(void) close(sipsock); io_context_destroy(io); ast_sched_context_destroy(sched); + sched = NULL; ast_context_destroy_by_name(used_context, "SIP"); ast_unload_realtime("sipregs"); ast_unload_realtime("sippeers"); From 76be7093cde121ef5fbf8033ef23c17718a44c94 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 9 Mar 2016 11:22:50 -0600 Subject: [PATCH 0266/1578] chan_sip.c: Adjust how dialog_unlink_all() stops scheduled events. This patch is part of a series to resolve deadlocks in chan_sip.c. * Make dialog_unlink_all() unschedule all items at once in the sched thread. ASTERISK-25023 Change-Id: I7743072fb228836e8228b72f6dc46c8cc50b3fb4 --- channels/chan_sip.c | 98 ++++++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 36 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 2719372089e..b9facff0c22 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3245,6 +3245,60 @@ static void ref_proxy(struct sip_pvt *pvt, struct sip_proxy *proxy) } } +static void do_dialog_unlink_sched_items(struct sip_pvt *dialog) +{ + struct sip_pkt *cp; + + /* remove all current packets in this dialog */ + sip_pvt_lock(dialog); + while ((cp = dialog->packets)) { + /* Unlink the node from the list. */ + dialog->packets = dialog->packets->next; + + /* Destroy the packet object. */ + AST_SCHED_DEL(sched, cp->retransid); + dialog_unref(cp->owner, "Unlink dialog removing all retransmitable packets"); + ast_free(cp->data); + ast_free(cp); + } + sip_pvt_unlock(dialog); + + AST_SCHED_DEL_UNREF(sched, dialog->waitid, + dialog_unref(dialog, "Stop scheduled waitid")); + + AST_SCHED_DEL_UNREF(sched, dialog->initid, + dialog_unref(dialog, "Stop scheduled initid")); + + AST_SCHED_DEL_UNREF(sched, dialog->reinviteid, + dialog_unref(dialog, "Stop scheduled reinviteid")); + + AST_SCHED_DEL_UNREF(sched, dialog->autokillid, + dialog_unref(dialog, "Stop scheduled autokillid")); + + AST_SCHED_DEL_UNREF(sched, dialog->request_queue_sched_id, + dialog_unref(dialog, "Stop scheduled request_queue_sched_id")); + + AST_SCHED_DEL_UNREF(sched, dialog->provisional_keepalive_sched_id, + dialog_unref(dialog, "Stop scheduled provisional keepalive")); + + AST_SCHED_DEL_UNREF(sched, dialog->t38id, + dialog_unref(dialog, "Stop scheduled t38id")); + + if (dialog->stimer) { + stop_session_timer(dialog); + } +} + +/* Run by the sched thread. */ +static int __dialog_unlink_sched_items(const void *data) +{ + struct sip_pvt *dialog = (void *) data; + + do_dialog_unlink_sched_items(dialog); + dialog_unref(dialog, "Stop scheduled items for unlink action"); + return 0; +} + /*! * \brief Unlink a dialog from the dialogs container, as well as any other places * that it may be currently stored. @@ -3254,7 +3308,6 @@ static void ref_proxy(struct sip_pvt *pvt, struct sip_proxy *proxy) */ void dialog_unlink_all(struct sip_pvt *dialog) { - struct sip_pkt *cp; struct ast_channel *owner; dialog_ref(dialog, "Let's bump the count in the unlink so it doesn't accidentally become dead before we are done"); @@ -3292,41 +3345,14 @@ void dialog_unlink_all(struct sip_pvt *dialog) dialog->relatedpeer->call = dialog_unref(dialog->relatedpeer->call, "unset the relatedpeer->call field in tandem with relatedpeer field itself"); } - /* remove all current packets in this dialog */ - while((cp = dialog->packets)) { - dialog->packets = dialog->packets->next; - AST_SCHED_DEL(sched, cp->retransid); - dialog_unref(cp->owner, "remove all current packets in this dialog, and the pointer to the dialog too as part of __sip_destroy"); - if (cp->data) { - ast_free(cp->data); - } - ast_free(cp); - } - - AST_SCHED_DEL_UNREF(sched, dialog->waitid, dialog_unref(dialog, "when you delete the waitid sched, you should dec the refcount for the stored dialog ptr")); - - AST_SCHED_DEL_UNREF(sched, dialog->initid, dialog_unref(dialog, "when you delete the initid sched, you should dec the refcount for the stored dialog ptr")); - - if (dialog->reinviteid > -1) { - AST_SCHED_DEL_UNREF(sched, dialog->reinviteid, dialog_unref(dialog, "clear ref for reinvite_timeout")); - } - - if (dialog->autokillid > -1) { - AST_SCHED_DEL_UNREF(sched, dialog->autokillid, dialog_unref(dialog, "when you delete the autokillid sched, you should dec the refcount for the stored dialog ptr")); - } - - if (dialog->request_queue_sched_id > -1) { - AST_SCHED_DEL_UNREF(sched, dialog->request_queue_sched_id, dialog_unref(dialog, "when you delete the request_queue_sched_id sched, you should dec the refcount for the stored dialog ptr")); - } - - AST_SCHED_DEL_UNREF(sched, dialog->provisional_keepalive_sched_id, dialog_unref(dialog, "when you delete the provisional_keepalive_sched_id, you should dec the refcount for the stored dialog ptr")); - - if (dialog->t38id > -1) { - AST_SCHED_DEL_UNREF(sched, dialog->t38id, dialog_unref(dialog, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); - } - - if (dialog->stimer) { - stop_session_timer(dialog); + dialog_ref(dialog, "Stop scheduled items for unlink action"); + if (ast_sched_add(sched, 0, __dialog_unlink_sched_items, dialog) < 0) { + /* + * Uh Oh. Fall back to unscheduling things immediately + * despite the potential deadlock risk. + */ + dialog_unref(dialog, "Failed to schedule stop scheduled items for unlink action"); + do_dialog_unlink_sched_items(dialog); } dialog_unref(dialog, "Let's unbump the count in the unlink so the poor pvt can disappear if it is time"); From 67c79c326d3c0d1945a83622e490f226bc942a6d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 7 Mar 2016 18:28:58 -0600 Subject: [PATCH 0267/1578] chan_sip.c: Fix provisional_keepalive_sched_id deadlock. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. ASTERISK-25023 Change-Id: I98a694fd42bc81436c83aa92de03226e6e4e3f48 --- channels/chan_sip.c | 105 +++++++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 26 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b9facff0c22..d17f651539b 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1510,6 +1510,9 @@ static void sip_send_all_mwi_subscriptions(void); static int sip_subscribe_mwi_do(const void *data); static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi); +/* Scheduler id start/stop/reschedule functions. */ +static void stop_provisional_keepalive(struct sip_pvt *pvt); + /*! \brief Definition of this channel for PBX channel registration */ struct ast_channel_tech sip_tech = { .type = "SIP", @@ -4511,25 +4514,14 @@ static void add_blank(struct sip_request *req) } } +/* Run by the sched thread. */ static int send_provisional_keepalive_full(struct sip_pvt *pvt, int with_sdp) { const char *msg = NULL; struct ast_channel *chan; int res = 0; - int old_sched_id = pvt->provisional_keepalive_sched_id; chan = sip_pvt_lock_full(pvt); - /* Check that nothing has changed while we were waiting for the lock */ - if (old_sched_id != pvt->provisional_keepalive_sched_id) { - /* Keepalive has been cancelled or rescheduled, clean up and leave */ - if (chan) { - ast_channel_unlock(chan); - chan = ast_channel_unref(chan); - } - sip_pvt_unlock(pvt); - dialog_unref(pvt, "dialog ref for provisional keepalive"); - return 0; - } if (!pvt->last_provisional || !strncasecmp(pvt->last_provisional, "100", 3)) { msg = "183 Session Progress"; @@ -4542,25 +4534,23 @@ static int send_provisional_keepalive_full(struct sip_pvt *pvt, int with_sdp) transmit_response(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq); } res = PROVIS_KEEPALIVE_TIMEOUT; + } else { + pvt->provisional_keepalive_sched_id = -1; } + sip_pvt_unlock(pvt); if (chan) { ast_channel_unlock(chan); - chan = ast_channel_unref(chan); - } - - if (!res) { - pvt->provisional_keepalive_sched_id = -1; + ast_channel_unref(chan); } - sip_pvt_unlock(pvt); - if (!res) { - dialog_unref(pvt, "dialog ref for provisional keepalive"); + dialog_unref(pvt, "Schedule provisional keepalive complete"); } return res; } +/* Run by the sched thread. */ static int send_provisional_keepalive(const void *data) { struct sip_pvt *pvt = (struct sip_pvt *) data; @@ -4568,6 +4558,7 @@ static int send_provisional_keepalive(const void *data) return send_provisional_keepalive_full(pvt, 0); } +/* Run by the sched thread. */ static int send_provisional_keepalive_with_sdp(const void *data) { struct sip_pvt *pvt = (void *) data; @@ -4575,12 +4566,73 @@ static int send_provisional_keepalive_with_sdp(const void *data) return send_provisional_keepalive_full(pvt, 1); } +/* Run by the sched thread. */ +static int __update_provisional_keepalive_full(struct sip_pvt *pvt, int with_sdp) +{ + AST_SCHED_DEL_UNREF(sched, pvt->provisional_keepalive_sched_id, + dialog_unref(pvt, "Stop scheduled provisional keepalive for update")); + + sip_pvt_lock(pvt); + if (pvt->invitestate < INV_COMPLETED) { + /* Provisional keepalive is still needed. */ + dialog_ref(pvt, "Schedule provisional keepalive"); + pvt->provisional_keepalive_sched_id = ast_sched_add(sched, PROVIS_KEEPALIVE_TIMEOUT, + with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive, + pvt); + if (pvt->provisional_keepalive_sched_id < 0) { + dialog_unref(pvt, "Failed to schedule provisional keepalive"); + } + } + sip_pvt_unlock(pvt); + + dialog_unref(pvt, "Update provisional keepalive action"); + return 0; +} + +/* Run by the sched thread. */ +static int __update_provisional_keepalive(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + + return __update_provisional_keepalive_full(pvt, 0); +} + +/* Run by the sched thread. */ +static int __update_provisional_keepalive_with_sdp(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + + return __update_provisional_keepalive_full(pvt, 1); +} + static void update_provisional_keepalive(struct sip_pvt *pvt, int with_sdp) { - AST_SCHED_DEL_UNREF(sched, pvt->provisional_keepalive_sched_id, dialog_unref(pvt, "when you delete the provisional_keepalive_sched_id, you should dec the refcount for the stored dialog ptr")); + dialog_ref(pvt, "Update provisional keepalive action"); + if (ast_sched_add(sched, 0, + with_sdp ? __update_provisional_keepalive_with_sdp : __update_provisional_keepalive, + pvt) < 0) { + dialog_unref(pvt, "Failed to schedule update provisional keepalive action"); + } +} + +/* Run by the sched thread. */ +static int __stop_provisional_keepalive(const void *data) +{ + struct sip_pvt *pvt = (void *) data; - pvt->provisional_keepalive_sched_id = ast_sched_add(sched, PROVIS_KEEPALIVE_TIMEOUT, - with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive, dialog_ref(pvt, "Increment refcount to pass dialog pointer to sched callback")); + AST_SCHED_DEL_UNREF(sched, pvt->provisional_keepalive_sched_id, + dialog_unref(pvt, "Stop scheduled provisional keepalive")); + dialog_unref(pvt, "Stop provisional keepalive action"); + return 0; +} + +static void stop_provisional_keepalive(struct sip_pvt *pvt) +{ + dialog_ref(pvt, "Stop provisional keepalive action"); + if (ast_sched_add(sched, 0, __stop_provisional_keepalive, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule stop provisional keepalive action"); + } } static void add_required_respheader(struct sip_request *req) @@ -4636,7 +4688,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty /* If we are sending a final response to an INVITE, stop retransmitting provisional responses */ if (p->initreq.method == SIP_INVITE && reliable == XMIT_CRITICAL) { - AST_SCHED_DEL_UNREF(sched, p->provisional_keepalive_sched_id, dialog_unref(p, "when you delete the provisional_keepalive_sched_id, you should dec the refcount for the stored dialog ptr")); + stop_provisional_keepalive(p); } res = (reliable) ? @@ -7044,7 +7096,8 @@ static int sip_hangup(struct ast_channel *ast) } } else { /* Incoming call, not up */ const char *res; - AST_SCHED_DEL_UNREF(sched, p->provisional_keepalive_sched_id, dialog_unref(p, "when you delete the provisional_keepalive_sched_id, you should dec the refcount for the stored dialog ptr")); + + stop_provisional_keepalive(p); if (p->hangupcause && (res = hangup_cause2sip(p->hangupcause))) transmit_response_reliable(p, res, &p->initreq); else @@ -9094,7 +9147,7 @@ static void forked_invite_init(struct sip_request *req, const char *new_theirtag * \post pvt is locked * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL) * - * \returns a pointer to the locked and reffed pvt->owner channel if it exists. + * \return a pointer to the locked and reffed pvt->owner channel if it exists. */ static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt) { From f484ddbdfe507f296d3fa7d733aac4a345147bb7 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 9 Mar 2016 16:32:28 -0600 Subject: [PATCH 0268/1578] chan_sip.c: Fix packet retransid deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. * Fix retrans_pkt() to call check_pendings() with both the owner channel and the private objects locked as required. * Refactor dialog retransmission packet list to safely remove packet nodes. The list nodes are now ao2 objects. The list has a ref and the scheduled entry has a ref. ASTERISK-25023 Change-Id: I50926d81be53f4cd3d572a3292cd25f563f59641 --- channels/chan_sip.c | 175 ++++++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 79 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index e3aa4cf277c..17ecba22db7 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1513,6 +1513,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi); static void stop_provisional_keepalive(struct sip_pvt *pvt); static void do_stop_session_timer(struct sip_pvt *pvt); static void stop_reinvite_retry(struct sip_pvt *pvt); +static void stop_retrans_pkt(struct sip_pkt *pkt); /*! \brief Definition of this channel for PBX channel registration */ struct ast_channel_tech sip_tech = { @@ -3256,14 +3257,11 @@ static void do_dialog_unlink_sched_items(struct sip_pvt *dialog) /* remove all current packets in this dialog */ sip_pvt_lock(dialog); while ((cp = dialog->packets)) { - /* Unlink the node from the list. */ + /* Unlink and destroy the packet object. */ dialog->packets = dialog->packets->next; - - /* Destroy the packet object. */ - AST_SCHED_DEL(sched, cp->retransid); - dialog_unref(cp->owner, "Unlink dialog removing all retransmitable packets"); - ast_free(cp->data); - ast_free(cp); + AST_SCHED_DEL_UNREF(sched, cp->retransid, + ao2_t_ref(cp, -1, "Stop scheduled packet retransmission")); + ao2_t_ref(cp, -1, "Packet retransmission list"); } sip_pvt_unlock(dialog); @@ -3958,10 +3956,17 @@ static void append_history_full(struct sip_pvt *p, const char *fmt, ...) return; } -/*! \brief Retransmit SIP message if no answer (Called from scheduler) */ +/*! + * \brief Retransmit SIP message if no answer + * + * \note Run by the sched thread. + */ static int retrans_pkt(const void *data) { - struct sip_pkt *pkt = (struct sip_pkt *)data, *prev, *cur = NULL; + struct sip_pkt *pkt = (struct sip_pkt *) data; + struct sip_pkt *prev; + struct sip_pkt *cur; + struct ast_channel *owner_chan; int reschedule = DEFAULT_RETRANS; int xmitres = 0; /* how many ms until retrans timeout is reached */ @@ -4026,6 +4031,7 @@ static int retrans_pkt(const void *data) if (sip_debug_test_pvt(pkt->owner)) { const struct ast_sockaddr *dst = sip_real_dst(pkt->owner); + ast_verbose("Retransmitting #%d (%s) to %s:\n%s\n---\n", pkt->retrans, sip_nat_mode(pkt->owner), ast_sockaddr_stringify(dst), @@ -4046,7 +4052,7 @@ static int retrans_pkt(const void *data) reschedule = diff; } sip_pvt_unlock(pkt->owner); - return reschedule; + return reschedule; } } @@ -4076,16 +4082,11 @@ static int retrans_pkt(const void *data) append_history(pkt->owner, "MaxRetries", "%s", pkt->is_fatal ? "(Critical)" : "(Non-critical)"); } + sip_pvt_unlock(pkt->owner); /* SIP_PVT, not channel */ + owner_chan = sip_pvt_lock_full(pkt->owner); + if (pkt->is_fatal) { - while(pkt->owner->owner && ast_channel_trylock(pkt->owner->owner)) { - sip_pvt_unlock(pkt->owner); /* SIP_PVT, not channel */ - usleep(1); - sip_pvt_lock(pkt->owner); - } - if (pkt->owner->owner && !ast_channel_hangupcause(pkt->owner->owner)) { - ast_channel_hangupcause_set(pkt->owner->owner, AST_CAUSE_NO_USER_RESPONSE); - } - if (pkt->owner->owner) { + if (owner_chan) { ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet (see https://wiki.asterisk.org/wiki/display/AST/SIP+Retransmissions).\n", pkt->owner->callid); if (pkt->is_resp && @@ -4106,8 +4107,10 @@ static int retrans_pkt(const void *data) /* there is nothing left to do, mark the dialog as gone */ sip_alreadygone(pkt->owner); } - ast_queue_hangup_with_cause(pkt->owner->owner, AST_CAUSE_NO_USER_RESPONSE); - ast_channel_unlock(pkt->owner->owner); + if (!ast_channel_hangupcause(owner_chan)) { + ast_channel_hangupcause_set(owner_chan, AST_CAUSE_NO_USER_RESPONSE); + } + ast_queue_hangup_with_cause(owner_chan, AST_CAUSE_NO_USER_RESPONSE); } else { /* If no channel owner, destroy now */ @@ -4125,38 +4128,68 @@ static int retrans_pkt(const void *data) check_pendings(pkt->owner); } + if (owner_chan) { + ast_channel_unlock(owner_chan); + ast_channel_unref(owner_chan); + } + if (pkt->method == SIP_BYE) { /* We're not getting answers on SIP BYE's. Tear down the call anyway. */ sip_alreadygone(pkt->owner); - if (pkt->owner->owner) { - ast_channel_unlock(pkt->owner->owner); - } append_history(pkt->owner, "ByeFailure", "Remote peer doesn't respond to bye. Destroying call anyway."); pvt_set_needdestroy(pkt->owner, "no response to BYE"); } - /* Remove the packet */ + /* Unlink and destroy the packet object. */ for (prev = NULL, cur = pkt->owner->packets; cur; prev = cur, cur = cur->next) { if (cur == pkt) { + /* Unlink the node from the list. */ UNLINK(cur, pkt->owner->packets, prev); - sip_pvt_unlock(pkt->owner); - if (pkt->owner) { - pkt->owner = dialog_unref(pkt->owner,"pkt is being freed, its dialog ref is dead now"); - } - if (pkt->data) { - ast_free(pkt->data); - } - pkt->data = NULL; - ast_free(pkt); - return 0; + ao2_t_ref(pkt, -1, "Packet retransmission list (retransmission complete)"); + break; } } - /* error case */ - ast_log(LOG_WARNING, "Weird, couldn't find packet owner!\n"); + + /* + * If the object was not in the list then we were in the process of + * stopping retransmisions while we were sending this retransmission. + */ + sip_pvt_unlock(pkt->owner); + ao2_t_ref(pkt, -1, "Scheduled packet retransmission complete"); return 0; } +/* Run by the sched thread. */ +static int __stop_retrans_pkt(const void *data) +{ + struct sip_pkt *pkt = (void *) data; + + AST_SCHED_DEL_UNREF(sched, pkt->retransid, + ao2_t_ref(pkt, -1, "Stop scheduled packet retransmission")); + ao2_t_ref(pkt, -1, "Stop packet retransmission action"); + return 0; +} + +static void stop_retrans_pkt(struct sip_pkt *pkt) +{ + ao2_t_ref(pkt, +1, "Stop packet retransmission action"); + if (ast_sched_add(sched, 0, __stop_retrans_pkt, pkt) < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(pkt, -1, "Failed to schedule stop packet retransmission action"); + } +} + +static void sip_pkt_dtor(void *vdoomed) +{ + struct sip_pkt *pkt = (void *) vdoomed; + + if (pkt->owner) { + dialog_unref(pkt->owner, "Retransmission packet is being destroyed"); + } + ast_free(pkt->data); +} + /*! * \internal * \brief Transmit packet with retransmits @@ -4187,12 +4220,14 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in } } - if (!(pkt = ast_calloc(1, sizeof(*pkt)))) { + pkt = ao2_alloc_options(sizeof(*pkt), sip_pkt_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!pkt) { return AST_FAILURE; } /* copy data, add a terminator and save length */ - if (!(pkt->data = ast_str_create(ast_str_strlen(data)))) { - ast_free(pkt); + pkt->data = ast_str_create(ast_str_strlen(data)); + if (!pkt->data) { + ao2_t_ref(pkt, -1, "Failed to initialize"); return AST_FAILURE; } ast_str_set(&pkt->data, 0, "%s%s", ast_str_buffer(data), "\0"); @@ -4202,8 +4237,11 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in pkt->is_resp = resp; pkt->is_fatal = fatal; pkt->owner = dialog_ref(p, "__sip_reliable_xmit: setting pkt->owner"); + + /* The retransmission list owns a pkt ref */ pkt->next = p->packets; p->packets = pkt; /* Add it to the queue */ + if (resp) { /* Parse out the response code */ if (sscanf(ast_str_buffer(pkt->data), "SIP/2.0 %30u", &respid) == 1) { @@ -4211,7 +4249,6 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in } } pkt->timer_t1 = p->timer_t1; /* Set SIP timer T1 */ - pkt->retransid = -1; if (pkt->timer_t1) { siptimer_a = pkt->timer_t1; } @@ -4220,7 +4257,12 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in pkt->retrans_stop_time = 64 * (pkt->timer_t1 ? pkt->timer_t1 : DEFAULT_TIMER_T1); /* time in ms after pkt->time_sent to stop retransmission */ /* Schedule retransmission */ - AST_SCHED_REPLACE_VARIABLE(pkt->retransid, sched, siptimer_a, retrans_pkt, pkt, 1); + ao2_t_ref(pkt, +1, "Schedule packet retransmission"); + pkt->retransid = ast_sched_add_variable(sched, siptimer_a, retrans_pkt, pkt, 1); + if (pkt->retransid < 0) { + ao2_t_ref(pkt, -1, "Failed to schedule packet retransmission"); + } + if (sipdebug) { ast_debug(4, "*** SIP TIMER: Initializing retransmit timer on packet: Id #%d\n", pkt->retransid); } @@ -4230,11 +4272,11 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */ append_history(pkt->owner, "XmitErr", "%s", pkt->is_fatal ? "(Critical)" : "(Non-critical)"); ast_log(LOG_ERROR, "Serious Network Trouble; __sip_xmit returns error for pkt data\n"); - AST_SCHED_DEL(sched, pkt->retransid); + + /* Unlink and destroy the packet object. */ p->packets = pkt->next; - pkt->owner = dialog_unref(pkt->owner,"pkt is being freed, its dialog ref is dead now"); - ast_free(pkt->data); - ast_free(pkt); + stop_retrans_pkt(pkt); + ao2_t_ref(pkt, -1, "Packet retransmission list"); return AST_FAILURE; } else { /* This is odd, but since the retrans timer starts at 500ms and the do_monitor thread @@ -4484,33 +4526,11 @@ int __sip_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod) if (sipdebug) ast_debug(4, "** SIP TIMER: Cancelling retransmit of packet (reply received) Retransid #%d\n", cur->retransid); } - /* This odd section is designed to thwart a - * race condition in the packet scheduler. There are - * two conditions under which deleting the packet from the - * scheduler can fail. - * - * 1. The packet has been removed from the scheduler because retransmission - * is being attempted. The problem is that if the packet is currently attempting - * retransmission and we are at this point in the code, then that MUST mean - * that retrans_pkt is waiting on p's lock. Therefore we will relinquish the - * lock temporarily to allow retransmission. - * - * 2. The packet has reached its maximum number of retransmissions and has - * been permanently removed from the packet scheduler. If this is the case, then - * the packet's retransid will be set to -1. The atomicity of the setting and checking - * of the retransid to -1 is ensured since in both cases p's lock is held. - */ - while (cur->retransid > -1 && ast_sched_del(sched, cur->retransid)) { - sip_pvt_unlock(p); - usleep(1); - sip_pvt_lock(p); - } + + /* Unlink and destroy the packet object. */ UNLINK(cur, p->packets, prev); - dialog_unref(cur->owner, "unref pkt cur->owner dialog from sip ack before freeing pkt"); - if (cur->data) { - ast_free(cur->data); - } - ast_free(cur); + stop_retrans_pkt(cur); + ao2_t_ref(cur, -1, "Packet retransmission list"); break; } } @@ -4551,7 +4571,7 @@ int __sip_semi_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod) if (sipdebug) ast_debug(4, "*** SIP TIMER: Cancelling retransmission #%d - %s (got response)\n", cur->retransid, sip_methods[sipmethod].text); } - AST_SCHED_DEL(sched, cur->retransid); + stop_retrans_pkt(cur); res = TRUE; break; } @@ -26748,13 +26768,10 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req) */ for (pkt = p->packets, prev_pkt = NULL; pkt; prev_pkt = pkt, pkt = pkt->next) { if (pkt->seqno == p->lastinvite && pkt->response_code == 487) { - AST_SCHED_DEL(sched, pkt->retransid); + /* Unlink and destroy the packet object. */ UNLINK(pkt, p->packets, prev_pkt); - dialog_unref(pkt->owner, "unref packet->owner from dialog"); - if (pkt->data) { - ast_free(pkt->data); - } - ast_free(pkt); + stop_retrans_pkt(pkt); + ao2_t_ref(pkt, -1, "Packet retransmission list"); break; } } From 69810b306df0f311acf550653e5ba9e2c24e2963 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 7 Mar 2016 13:21:44 -0600 Subject: [PATCH 0269/1578] chan_sip.c: Fix autokillid deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. * Fix clearing autokillid in __sip_autodestruct() even though we could reschedule. ASTERISK-25023 Change-Id: I450580dbf26e2e3952ee6628c735b001565c368f --- channels/chan_sip.c | 210 ++++++++++++++++++++++------------ channels/sip/include/dialog.h | 15 ++- 2 files changed, 151 insertions(+), 74 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index d17f651539b..edcd66e4bd5 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -4259,6 +4259,7 @@ static int __sip_autodestruct(const void *data) /* If this is a subscription, tell the phone that we got a timeout */ if (p->subscribed && p->subscribed != MWI_NOTIFICATION && p->subscribed != CALL_COMPLETION) { struct state_notify_data data = { 0, }; + data.state = AST_EXTENSION_DEACTIVATED; transmit_state_notify(p, &data, 1, TRUE); /* Send last notification */ @@ -4272,6 +4273,7 @@ static int __sip_autodestruct(const void *data) if (p->packets) { if (!p->needdestroy) { char method_str[31]; + ast_debug(3, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : ""); append_history(p, "ReliableXmit", "timeout"); if (sscanf(p->lastmsg, "Tx: %30s", method_str) == 1 || sscanf(p->lastmsg, "Rx: %30s", method_str) == 1) { @@ -4286,66 +4288,118 @@ static int __sip_autodestruct(const void *data) } } - /* Reset schedule ID */ - p->autokillid = -1; - /* * Lock both the pvt and the channel safely so that we can queue up a frame. */ owner = sip_pvt_lock_full(p); if (owner) { - ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner %s in place (Method: %s). Rescheduling destruction for 10000 ms\n", p->callid, ast_channel_name(owner), sip_methods[p->method].text); + ast_log(LOG_WARNING, + "Autodestruct on dialog '%s' with owner %s in place (Method: %s). Rescheduling destruction for 10000 ms\n", + p->callid, ast_channel_name(owner), sip_methods[p->method].text); ast_queue_hangup_with_cause(owner, AST_CAUSE_PROTOCOL_ERROR); ast_channel_unlock(owner); ast_channel_unref(owner); sip_pvt_unlock(p); return 10000; - } else if (p->refer && !p->alreadygone) { + } + + /* Reset schedule ID */ + p->autokillid = -1; + + if (p->refer && !p->alreadygone) { ast_debug(3, "Finally hanging up channel after transfer: %s\n", p->callid); stop_media_flows(p); transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1); append_history(p, "ReferBYE", "Sending BYE on transferer call leg %s", p->callid); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); + sip_pvt_unlock(p); } else { append_history(p, "AutoDestroy", "%s", p->callid); ast_debug(3, "Auto destroying SIP dialog '%s'\n", p->callid); sip_pvt_unlock(p); dialog_unlink_all(p); /* once it's unlinked and unrefd everywhere, it'll be freed automagically */ - sip_pvt_lock(p); - /* dialog_unref(p, "unref dialog-- no other matching conditions"); -- unlink all now should finish off the dialog's references and free it. */ - /* sip_destroy(p); */ /* Go ahead and destroy dialog. All attempts to recover is done */ - /* sip_destroy also absorbs the reference */ } - sip_pvt_unlock(p); + dialog_unref(p, "autokillid complete"); - dialog_unref(p, "The ref to a dialog passed to this sched callback is going out of scope; unref it."); + return 0; +} +static void do_cancel_destroy(struct sip_pvt *pvt) +{ + if (-1 < pvt->autokillid) { + append_history(pvt, "CancelDestroy", ""); + AST_SCHED_DEL_UNREF(sched, pvt->autokillid, + dialog_unref(pvt, "Stop scheduled autokillid")); + } +} + +/* Run by the sched thread. */ +static int __sip_cancel_destroy(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + + sip_pvt_lock(pvt); + do_cancel_destroy(pvt); + sip_pvt_unlock(pvt); + dialog_unref(pvt, "Cancel destroy action"); return 0; } -/*! \brief Schedule final destruction of SIP dialog. This can not be canceled. - * This function is used to keep a dialog around for a period of time in order - * to properly respond to any retransmits. */ -void sip_scheddestroy_final(struct sip_pvt *p, int ms) +void sip_cancel_destroy(struct sip_pvt *pvt) { - if (p->final_destruction_scheduled) { - return; /* already set final destruction */ + if (pvt->final_destruction_scheduled) { + return; } - sip_scheddestroy(p, ms); - if (p->autokillid != -1) { - p->final_destruction_scheduled = 1; + dialog_ref(pvt, "Cancel destroy action"); + if (ast_sched_add(sched, 0, __sip_cancel_destroy, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule cancel destroy action"); + ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); } } -/*! \brief Schedule destruction of SIP dialog */ -void sip_scheddestroy(struct sip_pvt *p, int ms) +struct sip_scheddestroy_data { + struct sip_pvt *pvt; + int ms; +}; + +/* Run by the sched thread. */ +static int __sip_scheddestroy(const void *data) { - if (p->final_destruction_scheduled) { - return; /* already set final destruction */ + struct sip_scheddestroy_data *sched_data = (void *) data; + struct sip_pvt *pvt = sched_data->pvt; + int ms = sched_data->ms; + + ast_free(sched_data); + + sip_pvt_lock(pvt); + do_cancel_destroy(pvt); + + if (pvt->do_history) { + append_history(pvt, "SchedDestroy", "%d ms", ms); + } + + dialog_ref(pvt, "Schedule autokillid"); + pvt->autokillid = ast_sched_add(sched, ms, __sip_autodestruct, pvt); + if (pvt->autokillid < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule autokillid"); } + if (pvt->stimer) { + stop_session_timer(pvt); + } + sip_pvt_unlock(pvt); + dialog_unref(pvt, "Destroy action"); + return 0; +} + +static int sip_scheddestroy_full(struct sip_pvt *p, int ms) +{ + struct sip_scheddestroy_data *sched_data; + if (ms < 0) { if (p->timer_t1 == 0) { p->timer_t1 = global_t1; /* Set timer T1 if not set (RFC 3261) */ @@ -4356,37 +4410,44 @@ void sip_scheddestroy(struct sip_pvt *p, int ms) ms = p->timer_t1 * 64; } if (sip_debug_test_pvt(p)) { - ast_verbose("Scheduling destruction of SIP dialog '%s' in %d ms (Method: %s)\n", p->callid, ms, sip_methods[p->method].text); - } - if (sip_cancel_destroy(p)) { - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + ast_verbose("Scheduling destruction of SIP dialog '%s' in %d ms (Method: %s)\n", + p->callid, ms, sip_methods[p->method].text); } - if (p->do_history) { - append_history(p, "SchedDestroy", "%d ms", ms); + sched_data = ast_malloc(sizeof(*sched_data)); + if (!sched_data) { + /* Uh Oh. Expect bad behavior. */ + return -1; } - p->autokillid = ast_sched_add(sched, ms, __sip_autodestruct, dialog_ref(p, "setting ref as passing into ast_sched_add for __sip_autodestruct")); + sched_data->pvt = p; + sched_data->ms = ms; + dialog_ref(p, "Destroy action"); + if (ast_sched_add(sched, 0, __sip_scheddestroy, sched_data) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(p, "Failed to schedule destroy action"); + ast_free(sched_data); + return -1; + } + return 0; +} - if (p->stimer && p->stimer->st_active == TRUE && p->stimer->st_schedid > -1) { - stop_session_timer(p); +void sip_scheddestroy(struct sip_pvt *p, int ms) +{ + if (p->final_destruction_scheduled) { + return; /* already set final destruction */ } + sip_scheddestroy_full(p, ms); } -/*! \brief Cancel destruction of SIP dialog. - * Be careful as this also absorbs the reference - if you call it - * from within the scheduler, this might be the last reference. - */ -int sip_cancel_destroy(struct sip_pvt *p) +void sip_scheddestroy_final(struct sip_pvt *p, int ms) { if (p->final_destruction_scheduled) { - return 0; + return; /* already set final destruction */ } - if (p->autokillid > -1) { - append_history(p, "CancelDestroy", ""); - AST_SCHED_DEL_UNREF(sched, p->autokillid, dialog_unref(p, "remove ref for autokillid")); + if (!sip_scheddestroy_full(p, ms)) { + p->final_destruction_scheduled = 1; } - return 0; } /*! \brief Acknowledges receipt of a packet and stops retransmission @@ -7166,9 +7227,8 @@ static int sip_hangup(struct ast_channel *ast) ast_set_flag(&p->flags[0], SIP_PENDINGBYE); ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE); AST_SCHED_DEL_UNREF(sched, p->waitid, dialog_unref(p, "when you delete the waitid sched, you should dec the refcount for the stored dialog ptr")); - if (sip_cancel_destroy(p)) { - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); - } + sip_cancel_destroy(p); + /* If we have an ongoing reinvite, there is a chance that we have gotten a provisional * response, but something weird has happened and we will never receive a final response. * So, just in case, check for pending actions after a bit of time to trigger the pending @@ -17373,8 +17433,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_NAT_FORCE_RPORT); if (!(res = check_auth(p, req, peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri2, XMIT_UNRELIABLE))) { - if (sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + sip_cancel_destroy(p); if (check_request_transport(peer, req)) { ast_set_flag(&p->flags[0], SIP_PENDINGBYE); @@ -17428,8 +17487,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock ao2_t_link(peers_by_ip, peer, "link peer into peers-by-ip table"); } ao2_lock(peer); - if (sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + sip_cancel_destroy(p); switch (parse_register_contact(p, peer, req)) { case PARSE_REGISTER_DENIED: ast_log(LOG_WARNING, "Registration denied because of contact ACL\n"); @@ -23189,16 +23247,16 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest switch (resp) { case 100: /* Trying */ case 101: /* Dialog establishment */ - if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p)) { - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore && p->invitestate != INV_CANCELLED) { + sip_cancel_destroy(p); } check_pendings(p); break; case 180: /* 180 Ringing */ case 182: /* 182 Queued */ - if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p)) { - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore && p->invitestate != INV_CANCELLED) { + sip_cancel_destroy(p); } /* Store Route-set from provisional SIP responses so * early-dialog request can be routed properly @@ -23254,8 +23312,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest break; case 181: /* Call Is Being Forwarded */ - if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore && p->invitestate != INV_CANCELLED) { + sip_cancel_destroy(p); + } /* Store Route-set from provisional SIP responses so * early-dialog request can be routed properly * */ @@ -23286,8 +23345,8 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest break; case 183: /* Session progress */ - if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) { - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore && p->invitestate != INV_CANCELLED) { + sip_cancel_destroy(p); } /* Store Route-set from provisional SIP responses so * early-dialog request can be routed properly @@ -23347,8 +23406,8 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest break; case 200: /* 200 OK on invite - someone's answering our call */ - if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) { - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore && p->invitestate != INV_CANCELLED) { + sip_cancel_destroy(p); } p->authtries = 0; if (find_sdp(req)) { @@ -24624,8 +24683,9 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc } } else if ((resp >= 100) && (resp < 200)) { if (sipmethod == SIP_INVITE) { - if (!req->ignore && sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore) { + sip_cancel_destroy(p); + } if (find_sdp(req)) process_sdp(p, req, SDP_T38_NONE, FALSE); if (p->owner) { @@ -24691,8 +24751,9 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc default: /* Errors without handlers */ if ((resp >= 100) && (resp < 200)) { if (sipmethod == SIP_INVITE) { /* re-invite */ - if (!req->ignore && sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (!req->ignore) { + sip_cancel_destroy(p); + } } } else if ((resp >= 200) && (resp < 300)) { /* on any unrecognized 2XX response do the following */ if (sipmethod == SIP_INVITE) { @@ -24709,10 +24770,10 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc case 502: /* Bad gateway */ case 503: /* Service Unavailable */ case 504: /* Server timeout */ - /* re-invite failed */ - if (sipmethod == SIP_INVITE && sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + if (sipmethod == SIP_INVITE) { + sip_cancel_destroy(p); + } break; } } @@ -25660,8 +25721,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str if (!req->ignore) { int newcall = (p->initreq.headers ? TRUE : FALSE); - if (sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + sip_cancel_destroy(p); + /* This also counts as a pending invite */ p->pendinginvite = seqno; check_via(p, req); @@ -27935,10 +27996,13 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, action, p->exten, p->context, p->username); } } - if (p->autokillid > -1 && sip_cancel_destroy(p)) /* Remove subscription expiry for renewals */ - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); - if (p->expiry > 0) - sip_scheddestroy(p, (p->expiry + 10) * 1000); /* Set timer for destruction of call at expiration */ + + /* Remove subscription expiry for renewals */ + sip_cancel_destroy(p); + if (p->expiry > 0) { + /* Set timer for destruction of call at expiration */ + sip_scheddestroy(p, (p->expiry + 10) * 1000); + } if (p->subscribed == MWI_NOTIFICATION) { ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); diff --git a/channels/sip/include/dialog.h b/channels/sip/include/dialog.h index f6adea59b3a..06941709789 100644 --- a/channels/sip/include/dialog.h +++ b/channels/sip/include/dialog.h @@ -39,9 +39,22 @@ struct sip_pvt *__sip_alloc(ast_string_field callid, struct ast_sockaddr *sin, #define sip_alloc(callid, addr, useglobal_nat, intended_method, req, logger_callid) \ __sip_alloc(callid, addr, useglobal_nat, intended_method, req, logger_callid, __FILE__, __LINE__, __PRETTY_FUNCTION__) +/*! + * \brief Schedule final destruction of SIP dialog. + * + * \note This cannot be canceled. + * + * \details + * This function is used to keep a dialog around for a period of time in order + * to properly respond to any retransmits. + */ void sip_scheddestroy_final(struct sip_pvt *p, int ms); + +/*! \brief Schedule destruction of SIP dialog */ void sip_scheddestroy(struct sip_pvt *p, int ms); -int sip_cancel_destroy(struct sip_pvt *p); + +/*! \brief Cancel destruction of SIP dialog. */ +void sip_cancel_destroy(struct sip_pvt *pvt); /*! * \brief Unlink a dialog from the dialogs container, as well as any other places From c7fdff2e379c65413187433f9f4fac3f332fcf20 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 9 Mar 2016 16:34:53 -0600 Subject: [PATCH 0270/1578] chan_sip.c: Fix reinviteid deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. ASTERISK-25023 Change-Id: I9c11b9d597468f63916c99e1dabff9f4a46f84c1 --- channels/chan_sip.c | 47 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 17ecba22db7..fe06085380d 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -7046,21 +7046,44 @@ const char *hangup_cause2sip(int cause) return 0; } +/* Run by the sched thread. */ static int reinvite_timeout(const void *data) { struct sip_pvt *dialog = (struct sip_pvt *) data; - struct ast_channel *owner = sip_pvt_lock_full(dialog); + struct ast_channel *owner; + + owner = sip_pvt_lock_full(dialog); dialog->reinviteid = -1; check_pendings(dialog); if (owner) { ast_channel_unlock(owner); ast_channel_unref(owner); } - ao2_unlock(dialog); - dialog_unref(dialog, "unref for reinvite timeout"); + sip_pvt_unlock(dialog); + dialog_unref(dialog, "reinviteid complete"); + return 0; +} + +/* Run by the sched thread. */ +static int __stop_reinviteid(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + + AST_SCHED_DEL_UNREF(sched, pvt->reinviteid, + dialog_unref(pvt, "Stop scheduled reinviteid")); + dialog_unref(pvt, "Stop reinviteid action"); return 0; } +static void stop_reinviteid(struct sip_pvt *pvt) +{ + dialog_ref(pvt, "Stop reinviteid action"); + if (ast_sched_add(sched, 0, __stop_reinviteid, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule stop reinviteid action"); + } +} + /*! \brief sip_hangup: Hangup SIP call * Part of PBX interface, called from ast_hangup */ static int sip_hangup(struct ast_channel *ast) @@ -7252,7 +7275,12 @@ static int sip_hangup(struct ast_channel *ast) * So, just in case, check for pending actions after a bit of time to trigger the pending * bye that we are setting above */ if (p->ongoing_reinvite && p->reinviteid < 0) { - p->reinviteid = ast_sched_add(sched, 32 * p->timer_t1, reinvite_timeout, dialog_ref(p, "ref for reinvite_timeout")); + p->reinviteid = ast_sched_add(sched, 32 * p->timer_t1, + reinvite_timeout, dialog_ref(p, "Schedule reinviteid")); + if (p->reinviteid < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(p, "Failed to schedule reinviteid"); + } } } } @@ -22983,13 +23011,14 @@ static void check_pendings(struct sip_pvt *p) if (p->reinviteid > -1) { /* Outstanding p->reinviteid timeout, so wait... */ return; - } else if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) { + } + if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) { /* if we can't BYE, then this is really a pending CANCEL */ p->invitestate = INV_CANCELLED; transmit_request(p, SIP_CANCEL, p->lastinvite, XMIT_RELIABLE, FALSE); /* If the cancel occurred on an initial invite, cancel the pending BYE */ if (!ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED)) { - ast_clear_flag(&p->flags[0], SIP_PENDINGBYE); + ast_clear_flag(&p->flags[0], SIP_PENDINGBYE | SIP_NEEDREINVITE); } /* Actually don't destroy us yet, wait for the 487 on our original INVITE, but do set an autodestruct just in case we never get it. */ @@ -23005,7 +23034,7 @@ static void check_pendings(struct sip_pvt *p) } /* Perhaps there is an SD change INVITE outstanding */ transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE); - ast_clear_flag(&p->flags[0], SIP_PENDINGBYE); + ast_clear_flag(&p->flags[0], SIP_PENDINGBYE | SIP_NEEDREINVITE); } sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); } else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) { @@ -23301,9 +23330,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest if ((resp >= 200 && reinvite)) { p->ongoing_reinvite = 0; - if (p->reinviteid > -1) { - AST_SCHED_DEL_UNREF(sched, p->reinviteid, dialog_unref(p, "unref dialog for reinvite timeout because of a final response")); - } + stop_reinviteid(p); } /* Final response, clear out pending invite */ From 02458cc6fdc76c3782e2d657f7d11bd866513efd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 8 Mar 2016 15:08:19 -0600 Subject: [PATCH 0271/1578] chan_sip.c: Fix session timers deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. ASTERISK-25023 Change-Id: I6d65269151ba95e0d8fe4e9e611881cde2ab4900 --- channels/chan_sip.c | 243 ++++++++++++++++++++----------------- channels/sip/include/sip.h | 1 - 2 files changed, 131 insertions(+), 113 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index edcd66e4bd5..792090a5abe 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1488,7 +1488,6 @@ static void change_t38_state(struct sip_pvt *p, int state); /*------ Session-Timers functions --------- */ static void proc_422_rsp(struct sip_pvt *p, struct sip_request *rsp); -static int proc_session_timer(const void *vp); static void stop_session_timer(struct sip_pvt *p); static void start_session_timer(struct sip_pvt *p); static void restart_session_timer(struct sip_pvt *p); @@ -1512,6 +1511,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi); /* Scheduler id start/stop/reschedule functions. */ static void stop_provisional_keepalive(struct sip_pvt *pvt); +static void do_stop_session_timer(struct sip_pvt *pvt); /*! \brief Definition of this channel for PBX channel registration */ struct ast_channel_tech sip_tech = { @@ -3288,7 +3288,8 @@ static void do_dialog_unlink_sched_items(struct sip_pvt *dialog) dialog_unref(dialog, "Stop scheduled t38id")); if (dialog->stimer) { - stop_session_timer(dialog); + dialog->stimer->st_active = FALSE; + do_stop_session_timer(dialog); } } @@ -6529,12 +6530,8 @@ static void sip_pvt_dtor(void *vdoomed) ast_debug(3, "Destroying SIP dialog %s\n", p->callid); /* Destroy Session-Timers if allocated */ - if (p->stimer) { - p->stimer->quit_flag = 1; - stop_session_timer(p); - ast_free(p->stimer); - p->stimer = NULL; - } + ast_free(p->stimer); + p->stimer = NULL; if (sip_debug_test_pvt(p)) ast_verbose("Really destroying SIP dialog '%s' Method: %s\n", p->callid, sip_methods[p->method].text); @@ -7166,7 +7163,7 @@ static int sip_hangup(struct ast_channel *ast) p->invitestate = INV_TERMINATED; } } else { /* Call is in UP state, send BYE */ - if (p->stimer->st_active == TRUE) { + if (p->stimer) { stop_session_timer(p); } @@ -7339,8 +7336,8 @@ static int sip_answer(struct ast_channel *ast) ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); /* RFC says the session timer starts counting on 200, * not on INVITE. */ - if (p->stimer->st_active == TRUE) { - start_session_timer(p); + if (p->stimer) { + restart_session_timer(p); } } sip_pvt_unlock(p); @@ -8732,13 +8729,13 @@ static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p) return p->stimer; } - if (!(stp = ast_calloc(1, sizeof(struct sip_st_dlg)))) + if (!(stp = ast_calloc(1, sizeof(struct sip_st_dlg)))) { return NULL; + } + stp->st_schedid = -1; /* Session-Timers ast_sched scheduler id */ p->stimer = stp; - stp->st_schedid = -1; /* Session-Timers ast_sched scheduler id */ - return p->stimer; } @@ -25991,7 +25988,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str /* Check if OLI/ANI-II is present in From: */ parse_oli(req, p->owner); - if (reinvite && p->stimer->st_active == TRUE) { + if (reinvite && p->stimer) { restart_session_timer(p); } @@ -29216,41 +29213,110 @@ static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, restart_monitor(); } -/*! \brief Session-Timers: Restart session timer */ -static void restart_session_timer(struct sip_pvt *p) +/*! + * \brief Session-Timers: Process session refresh timeout event + * + * \note Run by the sched thread. + */ +static int proc_session_timer(const void *vp) { - if (p->stimer->st_active == TRUE) { - ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid); - AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid, - dialog_unref(p, "Removing session timer ref")); - start_session_timer(p); + struct sip_pvt *p = (struct sip_pvt *) vp; + struct sip_st_dlg *stimer = p->stimer; + int res = 0; + + ast_assert(stimer != NULL); + + ast_debug(2, "Session timer expired: %d - %s\n", stimer->st_schedid, p->callid); + + if (!p->owner) { + goto return_unref; } -} + if ((stimer->st_active != TRUE) || (ast_channel_state(p->owner) != AST_STATE_UP)) { + goto return_unref; + } -/*! \brief Session-Timers: Stop session timer */ -static void stop_session_timer(struct sip_pvt *p) + if (stimer->st_ref == SESSION_TIMER_REFRESHER_US) { + res = 1; + if (T38_ENABLED == p->t38.state) { + transmit_reinvite_with_sdp(p, TRUE, TRUE); + } else { + transmit_reinvite_with_sdp(p, FALSE, TRUE); + } + } else { + struct ast_channel *owner; + + ast_log(LOG_WARNING, "Session-Timer expired - %s\n", p->callid); + + owner = sip_pvt_lock_full(p); + if (owner) { + send_session_timeout(owner, "SIPSessionTimer"); + ast_softhangup_nolock(owner, AST_SOFTHANGUP_DEV); + ast_channel_unlock(owner); + ast_channel_unref(owner); + } + sip_pvt_unlock(p); + } + +return_unref: + if (!res) { + /* Session timer processing is no longer needed. */ + ast_debug(2, "Session timer stopped: %d - %s\n", + stimer->st_schedid, p->callid); + /* Don't pass go, don't collect $200.. we are the scheduled + * callback. We can rip ourself out here. */ + stimer->st_schedid = -1; + stimer->st_active = FALSE; + + /* If we are not asking to be rescheduled, then we need to release our + * reference to the dialog. */ + dialog_unref(p, "Session timer st_schedid complete"); + } + + return res; +} + +static void do_stop_session_timer(struct sip_pvt *pvt) { - if (p->stimer->st_active == TRUE) { - p->stimer->st_active = FALSE; - ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid); - AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid, - dialog_unref(p, "removing session timer ref")); + struct sip_st_dlg *stimer = pvt->stimer; + + if (-1 < stimer->st_schedid) { + ast_debug(2, "Session timer stopped: %d - %s\n", + stimer->st_schedid, pvt->callid); + AST_SCHED_DEL_UNREF(sched, stimer->st_schedid, + dialog_unref(pvt, "Stop scheduled session timer st_schedid")); } } +/* Run by the sched thread. */ +static int __stop_session_timer(const void *data) +{ + struct sip_pvt *pvt = (void *) data; -/*! \brief Session-Timers: Start session timer */ -static void start_session_timer(struct sip_pvt *p) + do_stop_session_timer(pvt); + dialog_unref(pvt, "Stop session timer action"); + return 0; +} + +/*! \brief Session-Timers: Stop session timer */ +static void stop_session_timer(struct sip_pvt *pvt) { - unsigned int timeout_ms; + struct sip_st_dlg *stimer = pvt->stimer; - if (p->stimer->st_schedid > -1) { - /* in the event a timer is already going, stop it */ - ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid); - AST_SCHED_DEL_UNREF(sched, p->stimer->st_schedid, - dialog_unref(p, "unref stimer->st_schedid from dialog")); + stimer->st_active = FALSE; + dialog_ref(pvt, "Stop session timer action"); + if (ast_sched_add(sched, 0, __stop_session_timer, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule stop session timer action"); } +} + +/* Run by the sched thread. */ +static int __start_session_timer(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + struct sip_st_dlg *stimer = pvt->stimer; + unsigned int timeout_ms; /* * RFC 4028 Section 10 @@ -29261,97 +29327,50 @@ static void start_session_timer(struct sip_pvt *p) * interval is RECOMMENDED. */ - timeout_ms = (1000 * p->stimer->st_interval); - if (p->stimer->st_ref == SESSION_TIMER_REFRESHER_US) { + timeout_ms = (1000 * stimer->st_interval); + if (stimer->st_ref == SESSION_TIMER_REFRESHER_US) { timeout_ms /= 2; } else { timeout_ms -= MIN(timeout_ms / 3, 32000); } - p->stimer->st_schedid = ast_sched_add(sched, timeout_ms, proc_session_timer, - dialog_ref(p, "adding session timer ref")); + /* in the event a timer is already going, stop it */ + do_stop_session_timer(pvt); - if (p->stimer->st_schedid < 0) { - dialog_unref(p, "removing session timer ref"); - ast_log(LOG_ERROR, "ast_sched_add failed - %s\n", p->callid); + dialog_ref(pvt, "Schedule session timer st_schedid"); + stimer->st_schedid = ast_sched_add(sched, timeout_ms, proc_session_timer, pvt); + if (stimer->st_schedid < 0) { + dialog_unref(pvt, "Failed to schedule session timer st_schedid"); } else { - p->stimer->st_active = TRUE; - ast_debug(2, "Session timer started: %d - %s %ums\n", p->stimer->st_schedid, p->callid, timeout_ms); + ast_debug(2, "Session timer started: %d - %s %ums\n", + stimer->st_schedid, pvt->callid, timeout_ms); } -} + dialog_unref(pvt, "Start session timer action"); + return 0; +} -/*! \brief Session-Timers: Process session refresh timeout event */ -static int proc_session_timer(const void *vp) +/*! \brief Session-Timers: Start session timer */ +static void start_session_timer(struct sip_pvt *pvt) { - struct sip_pvt *p = (struct sip_pvt *) vp; - int res = 0; - - if (!p->stimer) { - ast_log(LOG_WARNING, "Null stimer in proc_session_timer - %s\n", p->callid); - goto return_unref; - } - - ast_debug(2, "Session timer expired: %d - %s\n", p->stimer->st_schedid, p->callid); - - if (!p->owner) { - goto return_unref; - } - - if ((p->stimer->st_active != TRUE) || (ast_channel_state(p->owner) != AST_STATE_UP)) { - goto return_unref; - } - - if (p->stimer->st_ref == SESSION_TIMER_REFRESHER_US) { - res = 1; - if (T38_ENABLED == p->t38.state) { - transmit_reinvite_with_sdp(p, TRUE, TRUE); - } else { - transmit_reinvite_with_sdp(p, FALSE, TRUE); - } - } else { - if (p->stimer->quit_flag) { - goto return_unref; - } - ast_log(LOG_WARNING, "Session-Timer expired - %s\n", p->callid); - sip_pvt_lock(p); - while (p->owner && ast_channel_trylock(p->owner)) { - sip_pvt_unlock(p); - usleep(1); - if (p->stimer && p->stimer->quit_flag) { - goto return_unref; - } - sip_pvt_lock(p); - } + struct sip_st_dlg *stimer = pvt->stimer; - send_session_timeout(p->owner, "SIPSessionTimer"); - ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV); - ast_channel_unlock(p->owner); - sip_pvt_unlock(p); + stimer->st_active = TRUE; + dialog_ref(pvt, "Start session timer action"); + if (ast_sched_add(sched, 0, __start_session_timer, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule start session timer action"); } +} -return_unref: - if (!res) { - /* An error occurred. Stop session timer processing */ - if (p->stimer) { - ast_debug(2, "Session timer stopped: %d - %s\n", p->stimer->st_schedid, p->callid); - /* Don't pass go, don't collect $200.. we are the scheduled - * callback. We can rip ourself out here. */ - p->stimer->st_schedid = -1; - /* Calling stop_session_timer is nice for consistent debug - * logs. */ - stop_session_timer(p); - } - - /* If we are not asking to be rescheduled, then we need to release our - * reference to the dialog. */ - dialog_unref(p, "removing session timer ref"); +/*! \brief Session-Timers: Restart session timer */ +static void restart_session_timer(struct sip_pvt *p) +{ + if (p->stimer->st_active == TRUE) { + start_session_timer(p); } - - return res; } - /*! \brief Session-Timers: Function for parsing Min-SE header */ int parse_minse (const char *p_hdrval, int *const p_interval) { diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index d60f49ecbe9..c8854b58e62 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -959,7 +959,6 @@ struct sip_st_dlg { int st_cached_max_se; /*!< Session-Timers cached Session-Expires */ enum st_mode st_cached_mode; /*!< Session-Timers cached M.O. */ enum st_refresher st_cached_ref; /*!< Session-Timers session refresher */ - unsigned char quit_flag:1; /*!< Stop trying to lock; just quit */ }; From fbf8e04aed120930bca370fb41a40e4eac7dd134 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 10 Mar 2016 12:17:09 -0600 Subject: [PATCH 0272/1578] chan_sip.c: Fix t38id deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. ASTERISK-25023 Change-Id: If595e4456cd059d7171880c7f354e844c21b5f5f --- channels/chan_sip.c | 103 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index fe06085380d..40859a6b3dd 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1514,6 +1514,7 @@ static void stop_provisional_keepalive(struct sip_pvt *pvt); static void do_stop_session_timer(struct sip_pvt *pvt); static void stop_reinvite_retry(struct sip_pvt *pvt); static void stop_retrans_pkt(struct sip_pkt *pkt); +static void stop_t38_abort_timer(struct sip_pvt *pvt); /*! \brief Definition of this channel for PBX channel registration */ struct ast_channel_tech sip_tech = { @@ -7649,13 +7650,13 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_ /* Negotiation can not take place without a valid max_ifp value. */ if (!parameters->max_ifp) { if (p->t38.state == T38_PEER_REINVITE) { - AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); + stop_t38_abort_timer(p); transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); } change_t38_state(p, T38_REJECTED); break; } else if (p->t38.state == T38_PEER_REINVITE) { - AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); + stop_t38_abort_timer(p); p->t38.our_parms = *parameters; /* modify our parameters to conform to the peer's parameters, * based on the rules in the ITU T.38 recommendation @@ -7689,7 +7690,7 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_ case AST_T38_REFUSED: case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */ if (p->t38.state == T38_PEER_REINVITE) { - AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); + stop_t38_abort_timer(p); change_t38_state(p, T38_REJECTED); transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); } else if (p->t38.state == T38_ENABLED) { @@ -7701,7 +7702,7 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_ struct ast_control_t38_parameters parameters = p->t38.their_parms; if (p->t38.state == T38_PEER_REINVITE) { - AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); + stop_t38_abort_timer(p); parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl); parameters.request_response = AST_T38_REQUEST_NEGOTIATE; if (p->owner) { @@ -25337,27 +25338,89 @@ static int do_magic_pickup(struct ast_channel *channel, const char *extension, c return 0; } -/*! \brief Called to deny a T38 reinvite if the core does not respond to our request */ +/*! + * \brief Called to deny a T38 reinvite if the core does not respond to our request + * + * \note Run by the sched thread. + */ static int sip_t38_abort(const void *data) { - struct sip_pvt *p = (struct sip_pvt *) data; + struct sip_pvt *pvt = (struct sip_pvt *) data; + struct ast_channel *owner; - sip_pvt_lock(p); - /* an application may have taken ownership of the T.38 negotiation on this - * channel while we were waiting to grab the lock... if it did, the scheduler - * id will have been reset to -1, which is our indication that we do *not* - * want to abort the negotiation process + owner = sip_pvt_lock_full(pvt); + pvt->t38id = -1; + + /* + * An application may have taken ownership of the T.38 negotiation + * on the channel while we were waiting to grab the lock. If it + * did, the T.38 state will have been changed. This is our + * indication that we do *not* want to abort the negotiation + * process. */ - if (p->t38id != -1) { - change_t38_state(p, T38_REJECTED); - transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); - p->t38id = -1; - dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr"); + if (pvt->t38.state == T38_PEER_REINVITE) { + /* Still waiting for a response on timeout so reject the offer. */ + change_t38_state(pvt, T38_REJECTED); + transmit_response_reliable(pvt, "488 Not acceptable here", &pvt->initreq); } - sip_pvt_unlock(p); + + if (owner) { + ast_channel_unlock(owner); + ast_channel_unref(owner); + } + sip_pvt_unlock(pvt); + dialog_unref(pvt, "t38id complete"); return 0; } +/* Run by the sched thread. */ +static int __stop_t38_abort_timer(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + + AST_SCHED_DEL_UNREF(sched, pvt->t38id, + dialog_unref(pvt, "Stop scheduled t38id")); + dialog_unref(pvt, "Stop t38id action"); + return 0; +} + +static void stop_t38_abort_timer(struct sip_pvt *pvt) +{ + dialog_ref(pvt, "Stop t38id action"); + if (ast_sched_add(sched, 0, __stop_t38_abort_timer, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule stop t38id action"); + } +} + +/* Run by the sched thread. */ +static int __start_t38_abort_timer(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + + AST_SCHED_DEL_UNREF(sched, pvt->t38id, + dialog_unref(pvt, "Stop scheduled t38id")); + + dialog_ref(pvt, "Schedule t38id"); + pvt->t38id = ast_sched_add(sched, 5000, sip_t38_abort, pvt); + if (pvt->t38id < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule t38id"); + } + + dialog_unref(pvt, "Start t38id action"); + return 0; +} + +static void start_t38_abort_timer(struct sip_pvt *pvt) +{ + dialog_ref(pvt, "Start t38id action"); + if (ast_sched_add(sched, 0, __start_t38_abort_timer, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule start t38id action"); + } +} + /*! * \brief bare-bones support for SIP UPDATE * @@ -26240,11 +26303,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str transmit_response(p, "100 Trying", req); if (p->t38.state == T38_PEER_REINVITE) { - if (p->t38id > -1) { - /* reset t38 abort timer */ - AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "remove ref for t38id")); - } - p->t38id = ast_sched_add(sched, 5000, sip_t38_abort, dialog_ref(p, "passing dialog ptr into sched structure based on t38id for sip_t38_abort.")); + start_t38_abort_timer(p); } else if (p->t38.state == T38_ENABLED) { ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL))); From 7ea1e181dc7c3540c9af0c3bd6d0915260c570d8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 9 Mar 2016 16:26:26 -0600 Subject: [PATCH 0273/1578] chan_sip.c: Fix waitid deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. * Made always run check_pendings() under the scheduler thread so scheduler ids can be checked safely. ASTERISK-25023 Change-Id: Ia834d6edd5bdb47c163e4ecf884428a4a8b17d52 --- channels/chan_sip.c | 97 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 792090a5abe..e3aa4cf277c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1512,6 +1512,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi); /* Scheduler id start/stop/reschedule functions. */ static void stop_provisional_keepalive(struct sip_pvt *pvt); static void do_stop_session_timer(struct sip_pvt *pvt); +static void stop_reinvite_retry(struct sip_pvt *pvt); /*! \brief Definition of this channel for PBX channel registration */ struct ast_channel_tech sip_tech = { @@ -7223,7 +7224,7 @@ static int sip_hangup(struct ast_channel *ast) but we can't send one while we have "INVITE" outstanding. */ ast_set_flag(&p->flags[0], SIP_PENDINGBYE); ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE); - AST_SCHED_DEL_UNREF(sched, p->waitid, dialog_unref(p, "when you delete the waitid sched, you should dec the refcount for the stored dialog ptr")); + stop_reinvite_retry(p); sip_cancel_destroy(p); /* If we have an ongoing reinvite, there is a chance that we have gotten a provisional @@ -22948,10 +22949,13 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char } } -/*! \brief Check pending actions on SIP call +/*! + * \brief Check pending actions on SIP call * * \note both sip_pvt and sip_pvt's owner channel (if present) * must be locked for this function. + * + * \note Run by the sched thread. */ static void check_pendings(struct sip_pvt *p) { @@ -22986,7 +22990,11 @@ static void check_pendings(struct sip_pvt *p) sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); } else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) { /* if we can't REINVITE, hold it for later */ - if (p->pendinginvite || p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA || p->waitid > -1) { + if (p->pendinginvite + || p->invitestate == INV_CALLING + || p->invitestate == INV_PROCEEDING + || p->invitestate == INV_EARLY_MEDIA + || p->waitid > -1) { ast_debug(2, "NOT Sending pending reinvite (yet) on '%s'\n", p->callid); } else { ast_debug(2, "Sending pending reinvite on '%s'\n", p->callid); @@ -22997,10 +23005,39 @@ static void check_pendings(struct sip_pvt *p) } } -/*! \brief Reset the NEEDREINVITE flag after waiting when we get 491 on a Re-invite - to avoid race conditions between asterisk servers. - Called from the scheduler. -*/ +/* Run by the sched thread. */ +static int __sched_check_pendings(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + struct ast_channel *owner; + + owner = sip_pvt_lock_full(pvt); + check_pendings(pvt); + if (owner) { + ast_channel_unlock(owner); + ast_channel_unref(owner); + } + sip_pvt_unlock(pvt); + + dialog_unref(pvt, "Check pending actions action"); + return 0; +} + +static void sched_check_pendings(struct sip_pvt *pvt) +{ + dialog_ref(pvt, "Check pending actions action"); + if (ast_sched_add(sched, 0, __sched_check_pendings, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule check pending actions action"); + } +} + +/*! + * \brief Reset the NEEDREINVITE flag after waiting when we get 491 on a Re-invite + * to avoid race conditions between asterisk servers. + * + * \note Run by the sched thread. + */ static int sip_reinvite_retry(const void *data) { struct sip_pvt *p = (struct sip_pvt *) data; @@ -23019,10 +23056,30 @@ static int sip_reinvite_retry(const void *data) if (owner) { ast_channel_unlock(owner); } - dialog_unref(p, "unref the dialog ptr from sip_reinvite_retry, because it held a dialog ptr"); + dialog_unref(p, "Schedule waitid complete"); + return 0; +} + +/* Run by the sched thread. */ +static int __stop_reinvite_retry(const void *data) +{ + struct sip_pvt *pvt = (void *) data; + + AST_SCHED_DEL_UNREF(sched, pvt->waitid, + dialog_unref(pvt, "Stop scheduled waitid")); + dialog_unref(pvt, "Stop reinvite retry action"); return 0; } +static void stop_reinvite_retry(struct sip_pvt *pvt) +{ + dialog_ref(pvt, "Stop reinvite retry action"); + if (ast_sched_add(sched, 0, __stop_reinvite_retry, pvt) < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_unref(pvt, "Failed to schedule stop reinvite retry action"); + } +} + /*! * \brief Handle authentication challenge for SIP UPDATE * @@ -23247,7 +23304,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest if (!req->ignore && p->invitestate != INV_CANCELLED) { sip_cancel_destroy(p); } - check_pendings(p); + sched_check_pendings(p); break; case 180: /* 180 Ringing */ @@ -23305,7 +23362,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest } ast_rtp_instance_activate(p->rtp); } - check_pendings(p); + sched_check_pendings(p); break; case 181: /* Call Is Being Forwarded */ @@ -23338,7 +23395,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ast_party_redirecting_free(&redirecting); sip_handle_cc(p, req, AST_CC_CCNR); } - check_pendings(p); + sched_check_pendings(p); break; case 183: /* Session progress */ @@ -23399,7 +23456,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ast_queue_control(p->owner, AST_CONTROL_RINGING); } } - check_pendings(p); + sched_check_pendings(p); break; case 200: /* 200 OK on invite - someone's answering our call */ @@ -23550,7 +23607,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest p->invitestate = INV_TERMINATED; ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, TRUE); - check_pendings(p); + sched_check_pendings(p); break; case 407: /* Proxy authentication */ @@ -23662,7 +23719,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest update_call_counter(p, DEC_CALL_LIMIT); append_history(p, "Hangup", "Got 487 on CANCEL request from us on call without owner. Killing this dialog."); } - check_pendings(p); + sched_check_pendings(p); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); break; case 415: /* Unsupported media type */ @@ -23694,6 +23751,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest /* Reset the flag after a while */ int wait; + /* RFC 3261, if owner of call, wait between 2.1 to 4 seconds, * if not owner of call, wait 0 to 2 seconds */ if (p->outgoing_call) { @@ -23701,7 +23759,12 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest } else { wait = ast_random() % 2000; } - p->waitid = ast_sched_add(sched, wait, sip_reinvite_retry, dialog_ref(p, "passing dialog ptr into sched structure based on waitid for sip_reinvite_retry.")); + dialog_ref(p, "Schedule waitid for sip_reinvite_retry."); + p->waitid = ast_sched_add(sched, wait, sip_reinvite_retry, p); + if (p->waitid < 0) { + /* Uh Oh. Expect bad behavior. */ + dialog_ref(p, "Failed to schedule waitid"); + } ast_debug(2, "Reinvite race. Scheduled sip_reinvite_retry in %d secs in handle_response_invite (waitid %d, dialog '%s')\n", wait, p->waitid, p->callid); } @@ -26914,7 +26977,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req) /* Destroy any pending invites so we won't try to do another * scheduled reINVITE. */ - AST_SCHED_DEL_UNREF(sched, p->waitid, dialog_unref(p, "decrement refcount from sip_destroy because waitid won't be scheduled")); + stop_reinvite_retry(p); return 1; } @@ -28446,7 +28509,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as ast_queue_control(p->owner, AST_CONTROL_SRCCHANGE); } } - check_pendings(p); + sched_check_pendings(p); } else if (p->glareinvite == seqno) { /* handle ack for the 491 pending sent for glareinvite */ p->glareinvite = 0; From 72c444ba37b63b17563c2ac55b3ff1edbcacdd9a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 10 Mar 2016 17:01:12 -0600 Subject: [PATCH 0274/1578] chan_sip.c: Fix registration timeout and expire deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. ASTERISK-25023 Change-Id: I2e40de89efc8ae6e8850771d089ca44bc604b508 --- channels/chan_sip.c | 245 ++++++++++++++++++++++++++++--------- channels/sip/include/sip.h | 3 +- 2 files changed, 185 insertions(+), 63 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 40859a6b3dd..f2d60081ad6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1373,7 +1373,6 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka static void sip_registry_destroy(void *reg); static int sip_register(const char *value, int lineno); static const char *regstate2str(enum sipregistrystate regstate) attribute_const; -static int sip_reregister(const void *data); static int __sip_do_register(struct sip_registry *r); static int sip_reg_timeout(const void *data); static void sip_send_all_registers(void); @@ -6514,8 +6513,6 @@ static void sip_registry_destroy(void *obj) reg->call = dialog_unref(reg->call, "unref reg->call"); /* reg->call = sip_destroy(reg->call); */ } - AST_SCHED_DEL(sched, reg->expire); - AST_SCHED_DEL(sched, reg->timeout); ast_string_field_free_memory(reg); } @@ -15470,7 +15467,7 @@ static const struct _map_x_s regstatestrings[] = { { REG_STATE_AUTHSENT, "Auth. Sent"}, { REG_STATE_REGISTERED, "Registered"}, { REG_STATE_REJECTED, "Rejected"}, - { REG_STATE_TIMEOUT, "Timeout"}, + { REG_STATE_TIMEOUT, "Registered"},/* Hidden state. We are renewing registration. */ { REG_STATE_NOAUTH, "No Authentication"}, { -1, NULL } /* terminator */ }; @@ -15486,22 +15483,22 @@ static void sip_publish_registry(const char *username, const char *domain, const ast_system_publish_registry("SIP", username, domain, status, NULL); } -/*! \brief Update registration with SIP Proxy. +/*! + * \brief Update registration with SIP Proxy. + * + * \details * Called from the scheduler when the previous registration expires, * so we don't have to cancel the pending event. * We assume the reference so the sip_registry is valid, since it * is stored in the scheduled event anyways. + * + * \note Run by the sched thread. */ static int sip_reregister(const void *data) { /* if we are here, we know that we need to reregister. */ struct sip_registry *r = (struct sip_registry *) data; - /* if we couldn't get a reference to the registry object, punt */ - if (!r) { - return 0; - } - if (r->call && r->call->do_history) { append_history(r->call, "RegistryRenew", "Account: %s@%s", r->username, r->hostname); } @@ -15513,8 +15510,25 @@ static int sip_reregister(const void *data) r->expire = -1; r->expiry = r->configured_expiry; + switch (r->regstate) { + case REG_STATE_UNREGISTERED: + case REG_STATE_REGSENT: + case REG_STATE_AUTHSENT: + break; + case REG_STATE_REJECTED: + case REG_STATE_NOAUTH: + case REG_STATE_FAILED: + /* Restarting registration as unregistered */ + r->regstate = REG_STATE_UNREGISTERED; + break; + case REG_STATE_TIMEOUT: + case REG_STATE_REGISTERED: + /* Registration needs to be renewed. */ + r->regstate = REG_STATE_TIMEOUT; + break; + } __sip_do_register(r); - ao2_t_ref(r, -1, "unref the re-register scheduled event"); + ao2_t_ref(r, -1, "Scheduled reregister timeout complete"); return 0; } @@ -15529,21 +15543,83 @@ static int __sip_do_register(struct sip_registry *r) return res; } -/*! \brief Registration timeout, register again +struct reregister_data { + struct sip_registry *reg; + int ms; +}; + +/* Run by the sched thread. */ +static int __start_reregister_timeout(const void *data) +{ + struct reregister_data *sched_data = (void *) data; + struct sip_registry *reg = sched_data->reg; + int ms = sched_data->ms; + + ast_free(sched_data); + + AST_SCHED_DEL_UNREF(sched, reg->expire, + ao2_t_ref(reg, -1, "Stop scheduled reregister timeout")); + + ao2_t_ref(reg, +1, "Schedule reregister timeout"); + reg->expire = ast_sched_add(sched, ms, sip_reregister, reg); + if (reg->expire < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(reg, -1, "Failed to schedule reregister timeout"); + } + + ao2_t_ref(reg, -1, "Start reregister timeout action"); + return 0; +} + +static void start_reregister_timeout(struct sip_registry *reg, int ms) +{ + struct reregister_data *sched_data; + + sched_data = ast_malloc(sizeof(*sched_data)); + if (!sched_data) { + /* Uh Oh. Expect bad behavior. */ + return; + } + sched_data->reg = reg; + sched_data->ms = ms; + ao2_t_ref(reg, +1, "Start reregister timeout action"); + if (ast_sched_add(sched, 0, __start_reregister_timeout, sched_data) < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(reg, -1, "Failed to schedule start reregister timeout action"); + ast_free(sched_data); + } +} + +/*! + * \brief Registration request timeout, register again + * + * \details * Registered as a timeout handler during transmit_register(), * to retransmit the packet if a reply does not come back. - * This is called by the scheduler so the event is not pending anymore when + * + * \note This is called by the scheduler so the event is not pending anymore when * we are called. + * + * \note Run by the sched thread. */ static int sip_reg_timeout(const void *data) { - - /* if we are here, our registration timed out, so we'll just do it over */ struct sip_registry *r = (struct sip_registry *)data; /* the ref count should have been bumped when the sched item was added */ struct sip_pvt *p; - /* if we couldn't get a reference to the registry object, punt */ - if (!r) { + switch (r->regstate) { + case REG_STATE_UNREGISTERED: + case REG_STATE_REGSENT: + case REG_STATE_AUTHSENT: + case REG_STATE_TIMEOUT: + break; + default: + /* + * Registration completed because we got a request response + * and we couldn't stop the scheduled entry in time. + */ + r->timeout = -1; + ao2_t_ref(r, -1, "Scheduled register timeout completed early"); return 0; } @@ -15585,10 +15661,60 @@ static int sip_reg_timeout(const void *data) ast_log(LOG_NOTICE, " -- Registration for '%s@%s' timed out, trying again (Attempt #%d)\n", r->username, r->hostname, r->regattempts); } sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate)); - ao2_t_ref(r, -1, "unreffing registry_unref r"); + ao2_t_ref(r, -1, "Scheduled register timeout complete"); return 0; } +/* Run by the sched thread. */ +static int __stop_register_timeout(const void *data) +{ + struct sip_registry *reg = (struct sip_registry *) data; + + AST_SCHED_DEL_UNREF(sched, reg->timeout, + ao2_t_ref(reg, -1, "Stop scheduled register timeout")); + ao2_t_ref(reg, -1, "Stop register timeout action"); + return 0; +} + +static void stop_register_timeout(struct sip_registry *reg) +{ + ao2_t_ref(reg, +1, "Stop register timeout action"); + if (ast_sched_add(sched, 0, __stop_register_timeout, reg) < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(reg, -1, "Failed to schedule stop register timeout action"); + } +} + +/* Run by the sched thread. */ +static int __start_register_timeout(const void *data) +{ + struct sip_registry *reg = (struct sip_registry *) data; + + AST_SCHED_DEL_UNREF(sched, reg->timeout, + ao2_t_ref(reg, -1, "Stop scheduled register timeout")); + + ao2_t_ref(reg, +1, "Schedule register timeout"); + reg->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, reg); + if (reg->timeout < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(reg, -1, "Failed to schedule register timeout"); + } + ast_debug(1, "Scheduled a registration timeout for %s id #%d \n", + reg->hostname, reg->timeout); + + ao2_t_ref(reg, -1, "Start register timeout action"); + return 0; +} + +static void start_register_timeout(struct sip_registry *reg) +{ + ao2_t_ref(reg, +1, "Start register timeout action"); + if (ast_sched_add(sched, 0, __start_register_timeout, reg) < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(reg, -1, "Failed to schedule start register timeout action"); + } +} + static const char *sip_sanitized_host(const char *host) { struct ast_sockaddr addr = { { 0, 0, }, }; @@ -15702,16 +15828,9 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * * probably DNS. We need to reschedule a registration try */ dialog_unlink_all(p); p = dialog_unref(p, "unref dialog after unlink_all"); - if (r->timeout > -1) { - AST_SCHED_REPLACE_UNREF(r->timeout, sched, global_reg_timeout * 1000, sip_reg_timeout, r, - ao2_t_ref(_data, -1, "del for REPLACE of registry ptr"), - ao2_t_ref(r, -1, "object ptr dec when SCHED_REPLACE add failed"), - ao2_t_ref(r, +1, "add for REPLACE registry ptr")); - ast_log(LOG_WARNING, "Still have a registration timeout for %s@%s (create_addr() error), %d\n", r->username, r->hostname, r->timeout); - } else { - r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, ao2_t_bump(r, "add for REPLACE registry ptr")); - ast_log(LOG_WARNING, "Probably a DNS error for registration to %s@%s, trying REGISTER again (after %d seconds)\n", r->username, r->hostname, global_reg_timeout); - } + ast_log(LOG_WARNING, "Probably a DNS error for registration to %s@%s, trying REGISTER again (after %d seconds)\n", + r->username, r->hostname, global_reg_timeout); + start_register_timeout(r); r->regattempts++; return 0; } @@ -15774,14 +15893,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * /* set up a timeout */ if (auth == NULL) { - if (r->timeout > -1) { - ast_log(LOG_WARNING, "Still have a registration timeout, #%d - deleting it\n", r->timeout); - } - AST_SCHED_REPLACE_UNREF(r->timeout, sched, global_reg_timeout * 1000, sip_reg_timeout, r, - ao2_t_ref(_data, -1, "reg ptr unrefed from del in SCHED_REPLACE"), - ao2_t_ref(r, -1, "reg ptr unrefed from add failure in SCHED_REPLACE"), - ao2_t_ref(r, +1, "reg ptr reffed from add in SCHED_REPLACE")); - ast_debug(1, "Scheduled a registration timeout for %s id #%d \n", r->hostname, r->timeout); + start_register_timeout(r); } snprintf(from, sizeof(from), ";tag=%s", r->username, S_OR(r->regdomain, sip_sanitized_host(p->tohost)), p->tag); @@ -24100,8 +24212,8 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res break; } ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname); - AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 403")); r->regstate = REG_STATE_NOAUTH; + stop_register_timeout(r); sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate)); pvt_set_needdestroy(p, "received 403 response"); break; @@ -24111,8 +24223,8 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res if (r->call) r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 404"); r->regstate = REG_STATE_REJECTED; + stop_register_timeout(r); sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate)); - AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 404")); break; case 407: /* Proxy auth */ if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) { @@ -24131,7 +24243,6 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res case 423: /* Interval too brief */ r->expiry = atoi(sip_get_header(req, "Min-Expires")); ast_log(LOG_WARNING, "Got 423 Interval too brief for service %s@%s, minimum is %d seconds\n", p->registry->username, p->registry->hostname, r->expiry); - AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 423")); if (r->call) { r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 423"); pvt_set_needdestroy(p, "received 423 response"); @@ -24140,6 +24251,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res ast_log(LOG_WARNING, "Required expiration time from %s@%s is too high, giving up\n", p->registry->username, p->registry->hostname); r->expiry = r->configured_expiry; r->regstate = REG_STATE_REJECTED; + stop_register_timeout(r); } else { r->regstate = REG_STATE_UNREGISTERED; transmit_register(r, SIP_REGISTER, NULL, NULL); @@ -24155,8 +24267,8 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res if (r->call) r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 4xx"); r->regstate = REG_STATE_REJECTED; + stop_register_timeout(r); sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate)); - AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 479")); break; case 200: /* 200 OK */ if (!r) { @@ -24165,15 +24277,15 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res return 0; } - r->regstate = REG_STATE_REGISTERED; - r->regtime = ast_tvnow(); /* Reset time of last successful registration */ - sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate)); - r->regattempts = 0; ast_debug(1, "Registration successful\n"); if (r->timeout > -1) { ast_debug(1, "Cancelling timeout %d\n", r->timeout); } - AST_SCHED_DEL_UNREF(sched, r->timeout, ao2_t_ref(r, -1, "reg ptr unref from handle_response_register 200")); + r->regstate = REG_STATE_REGISTERED; + stop_register_timeout(r); + r->regtime = ast_tvnow(); /* Reset time of last successful registration */ + sip_publish_registry(r->username, r->hostname, regstate2str(r->regstate)); + r->regattempts = 0; if (r->call) r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 200"); ao2_t_replace(p->registry, NULL, "unref registry entry p->registry"); @@ -24227,10 +24339,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res r->refresh= (int) expires_ms / 1000; /* Schedule re-registration before we expire */ - AST_SCHED_REPLACE_UNREF(r->expire, sched, expires_ms, sip_reregister, r, - ao2_t_ref(_data, -1, "unref in REPLACE del fail"), - ao2_t_ref(r, -1, "unref in REPLACE add fail"), - ao2_t_ref(r, +1, "The Addition side of REPLACE")); + start_reregister_timeout(r, expires_ms); } return 1; } @@ -31686,9 +31795,11 @@ static void display_nat_warning(const char *cat, int reason, struct ast_flags *f } } -static int cleanup_registration(void *obj, void *arg, int flags) +/* Run by the sched thread. */ +static int __cleanup_registration(const void *data) { - struct sip_registry *reg = obj; + struct sip_registry *reg = (struct sip_registry *) data; + ao2_lock(reg); if (reg->call) { @@ -31697,12 +31808,12 @@ static int cleanup_registration(void *obj, void *arg, int flags) dialog_unlink_all(reg->call); reg->call = dialog_unref(reg->call, "remove iterator->call from registry traversal"); } - if (reg->expire > -1) { - AST_SCHED_DEL_UNREF(sched, reg->expire, ao2_t_ref(reg, -1, "reg ptr unref from reload config")); - } - if (reg->timeout > -1) { - AST_SCHED_DEL_UNREF(sched, reg->timeout, ao2_t_ref(reg, -1, "reg ptr unref from reload config")); - } + + AST_SCHED_DEL_UNREF(sched, reg->expire, + ao2_t_ref(reg, -1, "Stop scheduled reregister timeout")); + AST_SCHED_DEL_UNREF(sched, reg->timeout, + ao2_t_ref(reg, -1, "Stop scheduled register timeout")); + if (reg->dnsmgr) { ast_dnsmgr_release(reg->dnsmgr); reg->dnsmgr = NULL; @@ -31710,6 +31821,21 @@ static int cleanup_registration(void *obj, void *arg, int flags) } ao2_unlock(reg); + + ao2_t_ref(reg, -1, "cleanup_registration action"); + return 0; +} + +static int cleanup_registration(void *obj, void *arg, int flags) +{ + struct sip_registry *reg = obj; + + ao2_t_ref(reg, +1, "cleanup_registration action"); + if (ast_sched_add(sched, 0, __cleanup_registration, reg) < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(reg, -1, "Failed to schedule cleanup_registration action"); + } + return CMP_MATCH; } @@ -33524,10 +33650,7 @@ static void sip_send_all_registers(void) while ((iterator = ao2_t_iterator_next(&iter, "sip_send_all_registers iter"))) { ao2_lock(iterator); ms += regspacing; - AST_SCHED_REPLACE_UNREF(iterator->expire, sched, ms, sip_reregister, iterator, - ao2_t_ref(_data, -1, "REPLACE sched del decs the refcount"), - ao2_t_ref(iterator, -1, "REPLACE sched add failure decs the refcount"), - ao2_t_ref(iterator, +1, "REPLACE sched add incs the refcount")); + start_reregister_timeout(iterator, ms); ao2_unlock(iterator); ao2_t_ref(iterator, -1, "sip_send_all_registers iter"); } diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index c8854b58e62..92dcd56277b 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -547,8 +547,7 @@ enum sipregistrystate { * recover (not sure how correctly). */ - REG_STATE_TIMEOUT, /*!< Registration timed out - * \note XXX unused */ + REG_STATE_TIMEOUT, /*!< Registration about to expire, renewing registration */ REG_STATE_NOAUTH, /*!< We have no accepted credentials * \note fatal - no chance to proceed */ From 810f92c9dcfa2ca2b883d3f82699abe6bf219a53 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 11 Mar 2016 12:22:48 -0600 Subject: [PATCH 0275/1578] chan_sip.c: Fix mwi resub deadlock potential. This patch is part of a series to resolve deadlocks in chan_sip.c. Stopping a scheduled event can result in a deadlock if the scheduled event is running when you try to stop the event. If you hold a lock needed by the scheduled event while trying to stop the scheduled event then a deadlock can happen. The general strategy for resolving the deadlock potential is to push the actual starting and stopping of the scheduled events off onto the scheduler/do_monitor() thread by scheduling an immediate one shot scheduled event. Some restructuring may be needed because the code may assume that the start/stop of the scheduled events is immediate. ASTERISK-25023 #close Change-Id: I96d429c57a48861fd8bde63dd93db4e92dc3adb6 --- channels/chan_sip.c | 125 ++++++++++++++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 33 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f2d60081ad6..5c6f23fedbb 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1503,9 +1503,7 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i /*!--- SIP MWI Subscription support */ static int sip_subscribe_mwi(const char *value, int lineno); -static void sip_subscribe_mwi_destroy(void *data); static void sip_send_all_mwi_subscriptions(void); -static int sip_subscribe_mwi_do(const void *data); static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi); /* Scheduler id start/stop/reschedule functions. */ @@ -6521,12 +6519,12 @@ static void sip_registry_destroy(void *obj) static void sip_subscribe_mwi_destroy(void *data) { struct sip_subscription_mwi *mwi = data; + if (mwi->call) { mwi->call->mwi = NULL; mwi->call = dialog_unref(mwi->call, "sip_subscription_mwi destruction"); } - AST_SCHED_DEL(sched, mwi->resub); ast_string_field_free_memory(mwi); } @@ -14646,22 +14644,96 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init, return send_request(p, &req, init ? XMIT_CRITICAL : XMIT_RELIABLE, p->ocseq); } -/*! \brief Send a subscription or resubscription for MWI */ +/*! + * \brief Send a subscription or resubscription for MWI + * + * \note Run by the sched thread. + */ static int sip_subscribe_mwi_do(const void *data) { - struct sip_subscription_mwi *mwi = (struct sip_subscription_mwi*)data; - - if (!mwi) { - return -1; - } + struct sip_subscription_mwi *mwi = (struct sip_subscription_mwi *) data; mwi->resub = -1; __sip_subscribe_mwi_do(mwi); - ao2_t_ref(mwi, -1, "unref mwi to balance ast_sched_add"); + ao2_t_ref(mwi, -1, "Scheduled mwi resub complete"); + + return 0; +} + +/* Run by the sched thread. */ +static int __shutdown_mwi_subscription(const void *data) +{ + struct sip_subscription_mwi *mwi = (void *) data; + + AST_SCHED_DEL_UNREF(sched, mwi->resub, + ao2_t_ref(mwi, -1, "Stop scheduled mwi resub")); + + if (mwi->dnsmgr) { + ast_dnsmgr_release(mwi->dnsmgr); + mwi->dnsmgr = NULL; + ao2_t_ref(mwi, -1, "dnsmgr release"); + } + + ao2_t_ref(mwi, -1, "Shutdown MWI subscription action"); + return 0; +} + +static void shutdown_mwi_subscription(struct sip_subscription_mwi *mwi) +{ + ao2_t_ref(mwi, +1, "Shutdown MWI subscription action"); + if (ast_sched_add(sched, 0, __shutdown_mwi_subscription, mwi) < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(mwi, -1, "Failed to schedule shutdown MWI subscription action"); + } +} + +struct mwi_subscription_data { + struct sip_subscription_mwi *mwi; + int ms; +}; + +/* Run by the sched thread. */ +static int __start_mwi_subscription(const void *data) +{ + struct mwi_subscription_data *sched_data = (void *) data; + struct sip_subscription_mwi *mwi = sched_data->mwi; + int ms = sched_data->ms; + + ast_free(sched_data); + + AST_SCHED_DEL_UNREF(sched, mwi->resub, + ao2_t_ref(mwi, -1, "Stop scheduled mwi resub")); + + ao2_t_ref(mwi, +1, "Schedule mwi resub"); + mwi->resub = ast_sched_add(sched, ms, sip_subscribe_mwi_do, mwi); + if (mwi->resub < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(mwi, -1, "Failed to schedule mwi resub"); + } + ao2_t_ref(mwi, -1, "Start MWI subscription action"); return 0; } +static void start_mwi_subscription(struct sip_subscription_mwi *mwi, int ms) +{ + struct mwi_subscription_data *sched_data; + + sched_data = ast_malloc(sizeof(*sched_data)); + if (!sched_data) { + /* Uh Oh. Expect bad behavior. */ + return; + } + sched_data->mwi = mwi; + sched_data->ms = ms; + ao2_t_ref(mwi, +1, "Start MWI subscription action"); + if (ast_sched_add(sched, 0, __start_mwi_subscription, sched_data) < 0) { + /* Uh Oh. Expect bad behavior. */ + ao2_t_ref(mwi, -1, "Failed to schedule start MWI subscription action"); + ast_free(sched_data); + } +} + static void on_dns_update_registry(struct ast_sockaddr *old, struct ast_sockaddr *new, void *data) { struct sip_registry *reg = data; @@ -17203,6 +17275,7 @@ static void acl_change_event_stasis_unsubscribe(void) acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub); } +/* Run by the sched thread. */ static int network_change_sched_cb(const void *data) { network_change_sched_id = -1; @@ -24039,9 +24112,7 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *r p->options = NULL; } p->mwi->subscribed = 1; - if ((p->mwi->resub = ast_sched_add(sched, mwi_expiry * 1000, sip_subscribe_mwi_do, ao2_t_bump(p->mwi, "mwi ast_sched_add"))) < 0) { - ao2_t_ref(p->mwi, -1, "mwi ast_sched_add < 0"); - } + start_mwi_subscription(p->mwi, mwi_expiry * 1000); break; case 401: case 407: @@ -33661,18 +33732,12 @@ static void sip_send_all_registers(void) static void sip_send_all_mwi_subscriptions(void) { struct ao2_iterator iter; - struct sip_subscription_mwi *iterator; + struct sip_subscription_mwi *mwi; iter = ao2_iterator_init(subscription_mwi_list, 0); - while ((iterator = ao2_t_iterator_next(&iter, "sip_send_all_mwi_subscriptions iter"))) { - ao2_lock(iterator); - AST_SCHED_DEL(sched, iterator->resub); - ao2_t_ref(iterator, +1, "mwi added to schedule"); - if ((iterator->resub = ast_sched_add(sched, 1, sip_subscribe_mwi_do, iterator)) < 0) { - ao2_t_ref(iterator, -1, "mwi failed to schedule"); - } - ao2_unlock(iterator); - ao2_t_ref(iterator, -1, "sip_send_all_mwi_subscriptions iter"); + while ((mwi = ao2_t_iterator_next(&iter, "sip_send_all_mwi_subscriptions iter"))) { + start_mwi_subscription(mwi, 1); + ao2_t_ref(mwi, -1, "sip_send_all_mwi_subscriptions iter"); } ao2_iterator_destroy(&iter); } @@ -35334,18 +35399,12 @@ static int unload_module(void) { struct ao2_iterator iter; - struct sip_subscription_mwi *iterator; + struct sip_subscription_mwi *mwi; iter = ao2_iterator_init(subscription_mwi_list, 0); - while ((iterator = ao2_t_iterator_next(&iter, "unload_module iter"))) { - ao2_lock(iterator); - if (iterator->dnsmgr) { - ast_dnsmgr_release(iterator->dnsmgr); - iterator->dnsmgr = NULL; - ao2_t_ref(iterator, -1, "dnsmgr release"); - } - ao2_unlock(iterator); - ao2_t_ref(iterator, -1, "unload_module iter"); + while ((mwi = ao2_t_iterator_next(&iter, "unload_module iter"))) { + shutdown_mwi_subscription(mwi); + ao2_t_ref(mwi, -1, "unload_module iter"); } ao2_iterator_destroy(&iter); } From 0da36fca6bfc2c9af076f0728e718cef05c9bac8 Mon Sep 17 00:00:00 2001 From: Leif Madsen Date: Thu, 25 Feb 2016 11:29:05 -0500 Subject: [PATCH 0276/1578] Add initial support to build Docker images This work-in-progress is the first step to being able to reliably build Asterisk containers from the Asterisk source. I'm submitting this based on feedback gained at AstriDevCon 2015. Information about how to use this is provided in contrib/docker/README.md and will result in a local Asterisk container being built right from your source. I believe this can eventually be automated via hub.docker.com. Change-Id: Ifa070706d40e56755797097b6ed72c1e243bd0d1 --- .gitignore | 1 + contrib/docker/Dockerfile.asterisk | 19 ++++++++ contrib/docker/Dockerfile.packager | 9 ++++ contrib/docker/README.md | 39 ++++++++++++++++ contrib/docker/make-package.sh | 72 ++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 contrib/docker/Dockerfile.asterisk create mode 100644 contrib/docker/Dockerfile.packager create mode 100644 contrib/docker/README.md create mode 100755 contrib/docker/make-package.sh diff --git a/.gitignore b/.gitignore index 0281e107cf7..1a6deef24f1 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ menuselect-tree *.gcda latex doxygen.log +out/ diff --git a/contrib/docker/Dockerfile.asterisk b/contrib/docker/Dockerfile.asterisk new file mode 100644 index 00000000000..41bf4352413 --- /dev/null +++ b/contrib/docker/Dockerfile.asterisk @@ -0,0 +1,19 @@ +# Version 0.0.3 +FROM centos:7 +MAINTAINER Leif Madsen +ENV REFRESHED_AT 2016-02-25 +ENV STARTDIR /tmp +ENV RPMPATH ./out + +# copy is required because you can't mount volumes during build +COPY $RPMPATH/*.rpm $STARTDIR + +# install dependencies and Asterisk RPM +RUN yum install epel-release -y && \ + yum install -y *.rpm && \ + yum clean all && \ + yum autoremove -y && \ + /sbin/ldconfig + +ENTRYPOINT ["/usr/sbin/asterisk"] +CMD ["-c", "-vvvv", "-g"] diff --git a/contrib/docker/Dockerfile.packager b/contrib/docker/Dockerfile.packager new file mode 100644 index 00000000000..35882106227 --- /dev/null +++ b/contrib/docker/Dockerfile.packager @@ -0,0 +1,9 @@ +FROM alanfranz/fwd-centos-7:latest +MAINTAINER Leif Madsen +ENV REFRESHED_AT 2016-02-25 +ADD contrib/scripts/install_prereq /tmp/install_prereq +RUN yum clean metadata && \ + yum -y update && \ + yum install epel-release -y && \ + yum clean all &&\ + /tmp/install_prereq install diff --git a/contrib/docker/README.md b/contrib/docker/README.md new file mode 100644 index 00000000000..2a9bd66d43b --- /dev/null +++ b/contrib/docker/README.md @@ -0,0 +1,39 @@ +# Building Asterisk into a Docker Container Image +The following set of steps should leave you with a Docker container that +is relatively small, built from your local checked out source, and even +provides you with a nice little RPM too! + +## Build the package container image +Build the package container image. This uses FPM[1] so no `spec` files and +such are necessary. +``` +docker build --pull -f contrib/docker/Dockerfile.packager -t asterisk-build . +``` + +## Build your Asterisk RPM from source +Build the Asterisk RPM from the resulting container image. +``` +docker run -ti \ + -v $(pwd):/application:ro \ + -v $(pwd)/out:/build \ + -w /application asterisk-build \ + /application/contrib/docker/make-package.sh 13.6.0 +``` +> **NOTE**: If you need to build this on a system that has SElinux enabled +> you'll need to use the following command instead: +> ``` +> docker run -ti \ +> -v $(pwd):/application:Z \ +> -v $(pwd)/out:/build:Z \ +> -w /application asterisk-build \ +> /application/contrib/docker/make-package.sh 13.6.0 +> ``` + +## Create your Asterisk container image +Now create your own Asterisk container image from the resulting RPM. +``` +docker build --rm -t madsen/asterisk:13.6.0-1 -f contrib/docker/Dockerfile.asterisk . +``` + +# References +[1] https://github.com/jordansissel/fpm diff --git a/contrib/docker/make-package.sh b/contrib/docker/make-package.sh new file mode 100755 index 00000000000..261df60e3fe --- /dev/null +++ b/contrib/docker/make-package.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# This script intended to be run from the packager container. Please see the +# README.md file for more information on how this script is used. +# +set -ex +[ -n "$1" ] +mkdir -p /opt + +# move into the application directory where Asterisk source exists +cd /application + +# strip the source of any Git-isms +rsync -av --exclude='.git' . /tmp/application + +# move to the build directory and build Asterisk +cd /tmp/application +./configure +cd menuselect +make menuselect +cd .. +make menuselect-tree + +menuselect/menuselect --check-deps menuselect.makeopts + +# Do not include sound files. You should be mounting these from and external +# volume. +sed -i -e 's/MENUSELECT_MOH=.*$/MENUSELECT_MOH=/' menuselect.makeopts +sed -i -e 's/MENUSELECT_CORE_SOUNDS=.*$/MENUSELECT_CORE_SOUNDS=/' menuselect.makeopts + +# Build it! +make all install DESTDIR=/tmp/installdir + +rm -rf /tmp/application +cd /build + +# Use the Fine Package Management system to build us an RPM without all that +# reeking effort. +fpm -t rpm -s dir -n asterisk-custom --version "$1" \ + --depends libedit \ + --depends libxslt \ + --depends jansson \ + --depends pjproject \ + --depends openssl \ + --depends libxml2 \ + --depends unixODBC \ + --depends libcurl \ + --depends libogg \ + --depends libvorbis \ + --depends speex \ + --depends spandsp \ + --depends freetds \ + --depends net-snmp \ + --depends iksemel \ + --depends corosynclib \ + --depends newt \ + --depends lua \ + --depends sqlite \ + --depends freetds \ + --depends radiusclient-ng \ + --depends postgresql \ + --depends neon \ + --depends libical \ + --depends openldap \ + --depends sqlite2 \ + --depends mysql \ + --depends bluez \ + --depends gsm \ + --depends libuuid \ + --depends libsrtp \ + -C /tmp/installdir etc usr var + +chown -R --reference /application/contrib/docker/make-package.sh . From bdccb81157e5a0a59d7233c051da100f2aa830b4 Mon Sep 17 00:00:00 2001 From: Sergio Medina Toledo Date: Thu, 3 Mar 2016 10:43:59 +0000 Subject: [PATCH 0277/1578] res_pjsip_refer.c: Fix seg fault in process of Refer-to header. The "Refer-to" header of an incoming REFER request is parsed by pjsip_parse_uri(). That function requires the URI parameter to be NULL terminated. Unfortunately, the previous code added the NULL terminator by overwriting memory that may not be safe. The overwritten memory results could be benign, memory corruption, or a segmentation fault. Now the URI is NULL terminated safely by copying the URI to a new chunk of memory with the correct size to be NULL terminated. ASTERISK-25814 #close Change-Id: I32565496684a5a49c3278fce06474b8c94b37342 --- res/res_pjsip_refer.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index fbc3eb3e245..df542517982 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -985,6 +985,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct { pjsip_generic_string_hdr *refer_to; char *uri; + size_t uri_size; pjsip_uri *target; pjsip_sip_uri *target_uri; RAII_VAR(struct refer_progress *, progress, NULL, ao2_cleanup); @@ -1018,20 +1019,19 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct return 0; } - /* This is done on purpose (and is safe) - it's done so that the value passed to - * pjsip_parse_uri is NULL terminated as required + /* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri + * as pjsip_parse_uri require a NULL terminated uri */ - uri = refer_to->hvalue.ptr; - uri[refer_to->hvalue.slen] = '\0'; - target = pjsip_parse_uri(rdata->tp_info.pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0); + uri_size = pj_strlen(&refer_to->hvalue) + 1; + uri = ast_alloca(uri_size); + ast_copy_pj_str(uri, &refer_to->hvalue, uri_size); + + target = pjsip_parse_uri(rdata->tp_info.pool, uri, uri_size - 1, 0); + if (!target || (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target))) { - size_t uri_size = pj_strlen(&refer_to->hvalue) + 1; - char *uri = ast_alloca(uri_size); - - ast_copy_pj_str(uri, &refer_to->hvalue, uri_size); pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL); ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n", From c534bd58075e2e1a1e4f3b23c435186c71b155fd Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Wed, 16 Mar 2016 12:37:01 -0500 Subject: [PATCH 0278/1578] chan_pjsip: transfers with direct media reinvite has wrong address/port During a transfer involving direct media a race occurs between when the transferer channel is swapped out, initiating rtp changes/updates, and the subsequent reinvites. When Alice, after speaking with Charlie (Bob is on hold), connects Bob and Charlie invites are sent to each in order to establish the call between them. Bob is taken off hold and Charlie is told to have his media flow through Asterisk. However, if before those invites go out the bridge updates Bob's and/or Charlie's rtp information with direct media data (i.e. address, port) then the invite(s) will contain the remote data in the SDP instead of the Asterisk data. The race occurs in the native bridge glue code when updating the peer. The direct_media_address can get set twice before sending out the first invite during call connection. This can happen because the checking/setting of the direct_media_address happened in one thread while the sending of the invite(s) happened in another thread. This fix removes the race condition by moving the checking/setting of the direct_media_address to be in the same thread as the sending of the invites(s). This serializes the checking/setting and sending so they can no longer happen out of order. ASTERISK-25849 #close Change-Id: Idfea590175e74f401929a601dba0c91ca1a7f873 --- channels/chan_pjsip.c | 118 +++++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 35 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 32291e54c22..729f453f925 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -223,17 +223,6 @@ static void chan_pjsip_get_codec(struct ast_channel *chan, struct ast_format_cap ast_format_cap_append_from_cap(result, channel->session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); } -static int send_direct_media_request(void *data) -{ - struct ast_sip_session *session = data; - int res; - - res = ast_sip_session_refresh(session, NULL, NULL, NULL, - session->endpoint->media.direct_media.method, 1); - ao2_ref(session, -1); - return res; -} - /*! \brief Destructor function for \ref transport_info_data */ static void transport_info_destroy(void *obj) { @@ -302,6 +291,83 @@ static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instan return changed; } +struct rtp_direct_media_data { + struct ast_channel *chan; + struct ast_rtp_instance *rtp; + struct ast_rtp_instance *vrtp; + struct ast_format_cap *cap; + struct ast_sip_session *session; +}; + +static void rtp_direct_media_data_destroy(void *data) +{ + struct rtp_direct_media_data *cdata = data; + + ao2_cleanup(cdata->session); + ao2_cleanup(cdata->cap); + ao2_cleanup(cdata->vrtp); + ao2_cleanup(cdata->rtp); + ao2_cleanup(cdata->chan); +} + +static struct rtp_direct_media_data *rtp_direct_media_data_create( + struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, + const struct ast_format_cap *cap, struct ast_sip_session *session) +{ + struct rtp_direct_media_data *cdata = ao2_alloc(sizeof(*cdata), rtp_direct_media_data_destroy); + + if (!cdata) { + return NULL; + } + + cdata->chan = ao2_bump(chan); + cdata->rtp = ao2_bump(rtp); + cdata->vrtp = ao2_bump(vrtp); + cdata->cap = ao2_bump((struct ast_format_cap *)cap); + cdata->session = ao2_bump(session); + + return cdata; +} + +static int send_direct_media_request(void *data) +{ + struct rtp_direct_media_data *cdata = data; + struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(cdata->chan); + struct chan_pjsip_pvt *pvt = channel->pvt; + int changed = 0; + int res = 0; + + if (pvt->media[SIP_MEDIA_AUDIO]) { + changed |= check_for_rtp_changes( + cdata->chan, cdata->rtp, pvt->media[SIP_MEDIA_AUDIO], 1); + } + if (pvt->media[SIP_MEDIA_VIDEO]) { + changed |= check_for_rtp_changes( + cdata->chan, cdata->vrtp, pvt->media[SIP_MEDIA_VIDEO], 3); + } + + if (direct_media_mitigate_glare(cdata->session)) { + ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(cdata->chan)); + return 0; + } + + if (cdata->cap && ast_format_cap_count(cdata->cap) && + !ast_format_cap_identical(cdata->session->direct_media_cap, cdata->cap)) { + ast_format_cap_remove_by_type(cdata->session->direct_media_cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(cdata->session->direct_media_cap, cdata->cap, AST_MEDIA_TYPE_UNKNOWN); + changed = 1; + } + + if (changed) { + ast_debug(4, "RTP changed on %s; initiating direct media update\n", ast_channel_name(cdata->chan)); + res = ast_sip_session_refresh(cdata->session, NULL, NULL, NULL, + cdata->session->endpoint->media.direct_media.method, 1); + } + + ao2_ref(cdata, -1); + return res; +} + /*! \brief Function called by RTP engine to change where the remote party should send media */ static int chan_pjsip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, @@ -311,9 +377,8 @@ static int chan_pjsip_set_rtp_peer(struct ast_channel *chan, int nat_active) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_sip_session *session = channel->session; - int changed = 0; + struct rtp_direct_media_data *cdata; /* Don't try to do any direct media shenanigans on early bridges */ if ((rtp || vrtp || tpeer) && !ast_channel_is_bridged(chan)) { @@ -326,31 +391,14 @@ static int chan_pjsip_set_rtp_peer(struct ast_channel *chan, return 0; } - if (pvt->media[SIP_MEDIA_AUDIO]) { - changed |= check_for_rtp_changes(chan, rtp, pvt->media[SIP_MEDIA_AUDIO], 1); - } - if (pvt->media[SIP_MEDIA_VIDEO]) { - changed |= check_for_rtp_changes(chan, vrtp, pvt->media[SIP_MEDIA_VIDEO], 3); - } - - if (direct_media_mitigate_glare(session)) { - ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(chan)); + cdata = rtp_direct_media_data_create(chan, rtp, vrtp, cap, session); + if (!cdata) { return 0; } - if (cap && ast_format_cap_count(cap) && !ast_format_cap_identical(session->direct_media_cap, cap)) { - ast_format_cap_remove_by_type(session->direct_media_cap, AST_MEDIA_TYPE_UNKNOWN); - ast_format_cap_append_from_cap(session->direct_media_cap, cap, AST_MEDIA_TYPE_UNKNOWN); - changed = 1; - } - - if (changed) { - ao2_ref(session, +1); - - ast_debug(4, "RTP changed on %s; initiating direct media update\n", ast_channel_name(chan)); - if (ast_sip_push_task(session->serializer, send_direct_media_request, session)) { - ao2_cleanup(session); - } + if (ast_sip_push_task(session->serializer, send_direct_media_request, cdata)) { + ast_log(LOG_ERROR, "Unable to send direct media request for channel %s\n", ast_channel_name(chan)); + ao2_ref(cdata, -1); } return 0; From a3c9a74a02014986181ce46bcecb74154ae9eb01 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Fri, 18 Mar 2016 14:31:12 -0500 Subject: [PATCH 0279/1578] chan_pjsip: ref leak when checking direct_media_glare Fix the reference leak introduced in the following commit: c534bd58075e2e1a1e4f3b23c435186c71b155fd ASTERISK-25849 Change-Id: I5cfefd5ee6c1c3a1715c050330aaa10e4d2a5e85 --- channels/chan_pjsip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 729f453f925..cd55400c3ba 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -348,6 +348,7 @@ static int send_direct_media_request(void *data) if (direct_media_mitigate_glare(cdata->session)) { ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(cdata->chan)); + ao2_ref(cdata, -1); return 0; } From 8f94f947f575630200b6602eda64b1172ecae101 Mon Sep 17 00:00:00 2001 From: Gianluca Merlo Date: Sat, 19 Mar 2016 02:32:51 +0100 Subject: [PATCH 0280/1578] func_aes: fix misuse of strlen on binary data The encryption code for AES_ENCRYPT evaluates the length of the data to be encoded in base64 using strlen. The data is binary, thus the length of it can be underestimated at the first NULL character. Reuse the write pointer offset to evaluate it, instead. ASTERISK-25857 #close Change-Id: If686b5d570473eb926693c73461177b35b13b186 --- funcs/func_aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funcs/func_aes.c b/funcs/func_aes.c index 9347b6f8e22..d80636f6da6 100644 --- a/funcs/func_aes.c +++ b/funcs/func_aes.c @@ -146,7 +146,7 @@ static int aes_helper(struct ast_channel *chan, const char *cmd, char *data, } if (encrypt) { /* if encrypting encode result to base64 */ - ast_base64encode(buf, (unsigned char *) tmp, strlen(tmp), len); + ast_base64encode(buf, (unsigned char *) tmp, tmpP - tmp, len); } else { memcpy(buf, tmp, len); } From 1d3191b1182abf5896d20ebb4b946405031ef9e0 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 19 Mar 2016 16:49:25 -0600 Subject: [PATCH 0281/1578] progdocs: Exclude ./third-party from documentation generation We don't need pjproject's documentation embedded in Asterisk's. Change-Id: Iea6f5a621c0f4e3168dda3321eaab258d9f24a17 --- doc/asterisk-ng-doxygen.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/asterisk-ng-doxygen.in b/doc/asterisk-ng-doxygen.in index 51a3f5d5835..2a7002c549b 100644 --- a/doc/asterisk-ng-doxygen.in +++ b/doc/asterisk-ng-doxygen.in @@ -616,7 +616,8 @@ RECURSIVE = yes EXCLUDE = doc/api \ menuselect \ res/pjproject \ - addons/ooh323c/src + addons/ooh323c/src \ + third-party # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded From ac669999710231a2a802ee1d290921a870a6fbce Mon Sep 17 00:00:00 2001 From: Francesco Castellano Date: Fri, 20 Nov 2015 15:02:48 +0100 Subject: [PATCH 0282/1578] chan_sip.c: Space after port causes unnecessary resolution attempt check_via() already skips leading blanks where the sent-by address (with the optional port) should be placed. Since RFC 3261 allows for blanks between the port ant the Via parameters: > https://tools.ietf.org/html/rfc3261#section-20.42 (actually it allows a lot of blanks more ;-)). I just switched from ast_skip_blanks() to ast_strip() on the local copy of the string. ASTERISK-21301 #close Change-Id: Ie5b8fe5a07067b7c0dc9bcdd1707e99b23b02b06 --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 97cd6abb05e..09ab1a196d7 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -18859,7 +18859,7 @@ static void check_via(struct sip_pvt *p, const struct sip_request *req) c = strchr(via, ' '); if (c) { *c = '\0'; - c = ast_skip_blanks(c+1); + c = ast_strip(c+1); if (strcasecmp(via, "SIP/2.0/UDP") && strcasecmp(via, "SIP/2.0/TCP") && strcasecmp(via, "SIP/2.0/TLS")) { ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via); return; From 392341ba3786b3211ea305fc0b9e955e6469f8b1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 23 Mar 2016 07:59:12 -0600 Subject: [PATCH 0283/1578] pjproject-bundled: Cleanups for reported issues PortAudio should no longer be required PJSIP_MAX_PKT_LEN is now 6000 Older autoconf issue fixed. (CentOS 6) Change-Id: I463fa9586cbe7c6b3b603289f535bd8e361611dd --- bootstrap.sh | 2 +- configure | 11 ++--- configure.ac | 1 - third-party/pjproject/Makefile.rules | 4 +- ...x-autoconf-issue-with-opencore-amrnb.patch | 48 +++++++++++++++++++ third-party/pjproject/patches/config_site.h | 1 + 6 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch diff --git a/bootstrap.sh b/bootstrap.sh index 3497e24e625..051ee3e82e9 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -46,7 +46,7 @@ check_for_app aclocal${MY_AM_VER} echo "Generating the configure script ..." -aclocal${MY_AM_VER} -I autoconf +aclocal${MY_AM_VER} -I autoconf `find third-party/ -maxdepth 1 -type d -printf "-I %p "` autoconf${MY_AC_VER} autoheader${MY_AC_VER} automake${MY_AM_VER} --add-missing --copy 2>/dev/null diff --git a/configure b/configure index f2d0d697099..579678b54e9 100755 --- a/configure +++ b/configure @@ -13762,7 +13762,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13808,7 +13808,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13832,7 +13832,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13877,7 +13877,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13901,7 +13901,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -24489,7 +24489,6 @@ fi if test "$USE_PJPROJECT" != "no" ; then if test "$PJPROJECT_BUNDLED" = "yes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for embedded pjproject (may have to download)" >&5 $as_echo_n "checking for embedded pjproject (may have to download)... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: configuring" >&5 diff --git a/configure.ac b/configure.ac index c0d5cb0c3ea..b136d867f91 100644 --- a/configure.ac +++ b/configure.ac @@ -2178,7 +2178,6 @@ fi if test "$USE_PJPROJECT" != "no" ; then if test "$PJPROJECT_BUNDLED" = "yes" ; then - AC_CONFIG_MACRO_DIR(third-party/pjproject) PJPROJECT_CONFIGURE([$PJPROJECT_DIR]) else AST_PKG_CONFIG_CHECK([PJPROJECT], [libpjproject]) diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index f39629b9221..062793f12de 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -2,6 +2,6 @@ PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --with-external-speex --with-external-gsm --with-external-srtp \ - --with-external-pa --disable-video --disable-v4l2 --disable-sound \ - --disable-opencore-amr --disable-ilbc-codec --without-libyuv --disable-g7221-codec \ + --disable-video --disable-v4l2 --disable-sound --disable-opencore-amr --disable-ilbc-codec \ + --without-libyuv --disable-g7221-codec \ --enable-epoll diff --git a/third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch b/third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch new file mode 100644 index 00000000000..04d1d970344 --- /dev/null +++ b/third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch @@ -0,0 +1,48 @@ +From 1281b60a1807d1285b101b6eb61c6478f29785fe Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Wed, 23 Mar 2016 07:48:52 -0600 +Subject: [PATCH] aconfigure.ac: Fix autoconf issue with opencore-amrnb on + older systems + +autoconf 2.63 on CentOS6 produces a bad ./aconfigure file related to +opencore-amrnb. + +./aconfigure: line 15158: syntax error near unexpected token `fi' + +To get around this, a 'true;' needed to be added to the Ok case of +AC_ARG_WITH(opencore-amrnb) +--- + aconfigure | 3 +++ + aconfigure.ac | 2 +- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/aconfigure b/aconfigure +index 33a08f5..4c122c2 100755 +--- a/aconfigure ++++ b/aconfigure +@@ -7908,6 +7908,9 @@ fi + # Check whether --with-opencore-amrnb was given. + if test "${with_opencore_amrnb+set}" = set; then : + withval=$with_opencore_amrnb; as_fn_error $? "This option is obsolete and replaced by --with-opencore-amr=DIR" "$LINENO" 5 ++else ++ true; ++ + fi + + +diff --git a/aconfigure.ac b/aconfigure.ac +index 3e88124..5d3e833 100644 +--- a/aconfigure.ac ++++ b/aconfigure.ac +@@ -1631,7 +1631,7 @@ AC_ARG_WITH(opencore-amrnb, + AC_HELP_STRING([--with-opencore-amrnb=DIR], + [This option is obsolete and replaced by --with-opencore-amr=DIR]), + [AC_MSG_ERROR(This option is obsolete and replaced by --with-opencore-amr=DIR)], +- [] ++ [true;] + ) + + dnl # opencore-amr alt prefix +-- +2.5.0 + diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 544c1e85ec6..840d8b279c8 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -29,6 +29,7 @@ #define PJ_HAS_STRICMP_ALNUM 0 #define PJ_HASH_USE_OWN_TOLOWER 1 #define PJSIP_UNESCAPE_IN_PLACE 1 +#define PJSIP_MAX_PKT_LEN 6000 #undef PJ_TODO #define PJ_TODO(x) From 6bbcfb34bd411ec88a02e6c655b0d5b9821495a4 Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Sun, 26 Oct 2014 01:21:18 +0000 Subject: [PATCH 0284/1578] funcs/func_curl: Add the ability for CURL to download and store files This patch adds a write option to the CURL dialplan function, allowing it to CURL files and store them locally. The value 'written' to the CURL URL specifies the location on disk to store the file. As an example: same => n,Set(CURL(http://1.1.1.1/foo.wav)=/tmp/foo.wav) Would retrieve the file foo.wav from the remote server and store it in the /tmp directory. Due to the potentially dangerous nature of this function call, APIs are forbidden from using the write functionality unless live_dangerously is set to True in asterisk.conf. ASTERISK-25652 #close Change-Id: I44f4ad823d7d20f04ceaad3698c5c7f653c41b0d --- CHANGES | 7 ++ funcs/func_curl.c | 212 ++++++++++++++++++++++++++++++---------------- 2 files changed, 144 insertions(+), 75 deletions(-) diff --git a/CHANGES b/CHANGES index 057542f1821..1cb8a9f3d4b 100644 --- a/CHANGES +++ b/CHANGES @@ -140,6 +140,13 @@ CHANNEL * Added CHANNEL(onhold) item that returns 1 (onhold) and 0 (not-onhold) for the hold status of a channel. +CURL +------------------ + * The CURL function now supports a write option, which will save the retrieved + file to a location on disk. As an example: + same => n,Set(CURL(https://1.1.1.1/foo.wav)=/tmp/foo.wav) + will save 'foo.wav' to /tmp. + DTMF Features ------------------ * The transferdialattempts default value has been changed from 1 to 3. The diff --git a/funcs/func_curl.c b/funcs/func_curl.c index fd03fc375f7..6a8c367672e 100644 --- a/funcs/func_curl.c +++ b/funcs/func_curl.c @@ -58,15 +58,39 @@ ASTERISK_REGISTER_FILE() Retrieve content from a remote web or ftp server - + + The full URL for the resource to retrieve. + + Read Only If specified, an HTTP POST will be performed with the content of post-data, instead of an HTTP GET (default). - + + When this function is read, a HTTP GET + (by default) will be used to retrieve the contents of the provided + url. The contents are returned as the + result of the function. + + exten => s,1,Verbose(0, ${CURL(http://localhost:8088/static/astman.css)}) + + When this function is written to, a HTTP GET + will be used to retrieve the contents of the provided + url. The value written to the function + specifies the destination file of the cURL'd resource. + + exten => s,1,Set(CURL(http://localhost:8088/static/astman.css)=/var/spool/asterisk/tmp/astman.css)) + + + If live_dangerously in asterisk.conf + is set to no, this function can only be written to from the + dialplan, and not directly from external protocols. Read operations are + unaffected. + + CURLOPT @@ -526,16 +550,27 @@ static int acf_curlopt_read2(struct ast_channel *chan, const char *cmd, char *da return acf_curlopt_helper(chan, cmd, data, NULL, buf, len); } +/*! \brief Callback data passed to \ref WriteMemoryCallback */ +struct curl_write_callback_data { + /*! \brief If a string is being built, the string buffer */ + struct ast_str *str; + /*! \brief The max size of \ref str */ + ssize_t len; + /*! \brief If a file is being retrieved, the file to write to */ + FILE *out_file; +}; + static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { - register int realsize = size * nmemb; - struct ast_str **pstr = (struct ast_str **)data; - - ast_debug(3, "Called with data=%p, str=%p, realsize=%d, len=%zu, used=%zu\n", data, *pstr, realsize, ast_str_size(*pstr), ast_str_strlen(*pstr)); - - ast_str_append_substr(pstr, 0, ptr, realsize); - - ast_debug(3, "Now, len=%zu, used=%zu\n", ast_str_size(*pstr), ast_str_strlen(*pstr)); + register int realsize = 0; + struct curl_write_callback_data *cb_data = data; + + if (cb_data->str) { + realsize = size * nmemb; + ast_str_append_substr(&cb_data->str, 0, ptr, realsize); + } else if (cb_data->out_file) { + realsize = fwrite(ptr, size, nmemb, cb_data->out_file); + } return realsize; } @@ -594,15 +629,16 @@ static int url_is_vulnerable(const char *url) return 0; } -static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info, char *buf, struct ast_str **input_str, ssize_t len) +struct curl_args { + const char *url; + const char *postdata; + struct curl_write_callback_data cb_data; +}; + +static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args) { struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16); - struct ast_str *str = ast_str_create(16); int ret = -1; - AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(url); - AST_APP_ARG(postdata); - ); CURL **curl; struct curl_settings *cur; struct ast_datastore *store = NULL; @@ -610,29 +646,17 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL; char curl_errbuf[CURL_ERROR_SIZE + 1]; /* add one to be safe */ - if (buf) { - *buf = '\0'; - } - - if (!str) { - return -1; - } - if (!escapebuf) { - ast_free(str); return -1; } - if (ast_strlen_zero(info)) { - ast_log(LOG_WARNING, "CURL requires an argument (URL)\n"); - ast_free(str); + if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) { + ast_log(LOG_ERROR, "Cannot allocate curl structure\n"); return -1; } - AST_STANDARD_APP_ARGS(args, info); - - if (url_is_vulnerable(args.url)) { - ast_log(LOG_ERROR, "URL '%s' is vulnerable to HTTP injection attacks. Aborting CURL() call.\n", args.url); + if (url_is_vulnerable(args->url)) { + ast_log(LOG_ERROR, "URL '%s' is vulnerable to HTTP injection attacks. Aborting CURL() call.\n", args->url); return -1; } @@ -640,12 +664,6 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info ast_autoservice_start(chan); } - if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) { - ast_log(LOG_ERROR, "Cannot allocate curl structure\n"); - ast_free(str); - return -1; - } - AST_LIST_LOCK(&global_curl_info); AST_LIST_TRAVERSE(&global_curl_info, cur, list) { if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { @@ -668,12 +686,12 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info } } - curl_easy_setopt(*curl, CURLOPT_URL, args.url); - curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &str); + curl_easy_setopt(*curl, CURLOPT_URL, args->url); + curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &args->cb_data); - if (args.postdata) { + if (args->postdata) { curl_easy_setopt(*curl, CURLOPT_POST, 1); - curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args.postdata); + curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args->postdata); } /* Temporarily assign a buffer for curl to write errors to. */ @@ -681,7 +699,7 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, curl_errbuf); if (curl_easy_perform(*curl) != 0) { - ast_log(LOG_WARNING, "%s ('%s')\n", curl_errbuf, args.url); + ast_log(LOG_WARNING, "%s ('%s')\n", curl_errbuf, args->url); } /* Reset buffer to NULL so curl doesn't try to write to it when the @@ -694,19 +712,19 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info AST_LIST_UNLOCK(list); } - if (args.postdata) { + if (args->postdata) { curl_easy_setopt(*curl, CURLOPT_POST, 0); } - if (ast_str_strlen(str)) { - ast_str_trim_blanks(str); + if (args->cb_data.str && ast_str_strlen(args->cb_data.str)) { + ast_str_trim_blanks(args->cb_data.str); - ast_debug(3, "str='%s'\n", ast_str_buffer(str)); + ast_debug(3, "CURL returned str='%s'\n", ast_str_buffer(args->cb_data.str)); if (hashcompat) { - char *remainder = ast_str_buffer(str); + char *remainder = ast_str_buffer(args->cb_data.str); char *piece; - struct ast_str *fields = ast_str_create(ast_str_strlen(str) / 2); - struct ast_str *values = ast_str_create(ast_str_strlen(str) / 2); + struct ast_str *fields = ast_str_create(ast_str_strlen(args->cb_data.str) / 2); + struct ast_str *values = ast_str_create(ast_str_strlen(args->cb_data.str) / 2); int rowcount = 0; while (fields && values && (piece = strsep(&remainder, "&"))) { char *name = strsep(&piece, "="); @@ -720,49 +738,93 @@ static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info rowcount++; } pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields)); - if (buf) { - ast_copy_string(buf, ast_str_buffer(values), len); - } else { - ast_str_set(input_str, len, "%s", ast_str_buffer(values)); - } + ast_str_set(&args->cb_data.str, 0, "%s", ast_str_buffer(values)); ast_free(fields); ast_free(values); - } else { - if (buf) { - ast_copy_string(buf, ast_str_buffer(str), len); - } else { - ast_str_set(input_str, len, "%s", ast_str_buffer(str)); - } } ret = 0; } - ast_free(str); - if (chan) + if (chan) { ast_autoservice_stop(chan); + } return ret; } -static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len) +static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len) { - return acf_curl_helper(chan, cmd, info, buf, NULL, len); + struct curl_args curl_params = { 0, }; + int res; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(url); + AST_APP_ARG(postdata); + ); + + AST_STANDARD_APP_ARGS(args, info); + + if (ast_strlen_zero(info)) { + ast_log(LOG_WARNING, "CURL requires an argument (URL)\n"); + return -1; + } + + curl_params.url = args.url; + curl_params.postdata = args.postdata; + curl_params.cb_data.str = ast_str_create(16); + if (!curl_params.cb_data.str) { + return -1; + } + + res = acf_curl_helper(chan, &curl_params); + ast_str_set(buf, len, "%s", ast_str_buffer(curl_params.cb_data.str)); + ast_free(curl_params.cb_data.str); + + return res; } -static int acf_curl2_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len) +static int acf_curl_write(struct ast_channel *chan, const char *cmd, char *name, const char *value) { - return acf_curl_helper(chan, cmd, info, NULL, buf, len); + struct curl_args curl_params = { 0, }; + int res; + char *args_value = ast_strdupa(value); + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(file_path); + ); + + AST_STANDARD_APP_ARGS(args, args_value); + + if (ast_strlen_zero(name)) { + ast_log(LOG_WARNING, "CURL requires an argument (URL)\n"); + return -1; + } + + if (ast_strlen_zero(args.file_path)) { + ast_log(LOG_WARNING, "CURL requires a file to write\n"); + return -1; + } + + curl_params.url = name; + curl_params.cb_data.out_file = fopen(args.file_path, "w"); + if (!curl_params.cb_data.out_file) { + ast_log(LOG_WARNING, "Failed to open file %s: %s (%d)\n", + args.file_path, + strerror(errno), + errno); + return -1; + } + + res = acf_curl_helper(chan, &curl_params); + + fclose(curl_params.cb_data.out_file); + + return res; } static struct ast_custom_function acf_curl = { .name = "CURL", - .synopsis = "Retrieves the contents of a URL", - .syntax = "CURL(url[,post-data])", - .desc = - " url - URL to retrieve\n" - " post-data - Optional data to send as a POST (GET is default action)\n", - .read = acf_curl_exec, - .read2 = acf_curl2_exec, + .read2 = acf_curl_exec, + .write = acf_curl_write, }; static struct ast_custom_function acf_curlopt = { @@ -865,7 +927,7 @@ static int load_module(void) } } - res = ast_custom_function_register(&acf_curl); + res = ast_custom_function_register_escalating(&acf_curl, AST_CFE_WRITE); res |= ast_custom_function_register(&acf_curlopt); AST_TEST_REGISTER(vulnerable_url); From 791b4c9f8144fde1e2999f7cebaaf10e2ec50243 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 26 Dec 2015 15:31:26 -0600 Subject: [PATCH 0285/1578] main/media_cache: Provide an extension on the local file associated with a URI This patch does the following: First, it addresses file extension handling in the media cache. The media core in Asterisk is a bit interesting in that it wants: * A file to have an extension on it. That extension is used to associate the file with a defined format module. * The filename passed to the core to not have an extension on it. This allows the core to match the available file formats with the format a channel is capable of handling. Unfortunately, this makes the current implementation a bit lacking in the media cache. By default, we do not store the extension of a retrieved URI on the local file that is created. As a result, the media core does not know what format the file is, and the file is ignored. Modifying the file outside of the media core is bad, as we would not be able to update the internal ast_bucket_file's path. At the same time, we do not want to pass the extension out in the file_path parameter in ast_media_cache_retrieve. This parameter is intended to be fed into the media core; if we passed the extension, all callers would have to strip it off. Thus, this patch does the following: * If there is an extension specified in the URL, we append it to the local file name (if a preferred file name isn't specified), and we store that in the local file path. * The extension, however, is stripped off of the file_path parameter passed back out of ast_media_cache_retrieve. Second, this patch causes stale items to be completely removed from the system. Prior to this patch, sound files could be orphaned due to the bucket referencing the file being deleted, but the file itself not being removed. This is now addressed by explicitly calling ast_bucket_file_delete on the bucket_file when it is deemed to be stale. Note that this only happen when we know we will attempt to retrieve the resource again. Finally, this patch changes the AO2 container holding media items to just use a regular mutex. The usage for this container already assumed it was a plain mutex, and - given that retrieval of an item can cause it to be replaced in the container - a mutex makes more sense than a read/write lock. Change-Id: I51667fff86ae8d2e4a663555dfa85b11e935fe0f --- main/media_cache.c | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/main/media_cache.c b/main/media_cache.c index 1f81e3ae1ad..9d68a10a54e 100644 --- a/main/media_cache.c +++ b/main/media_cache.c @@ -189,23 +189,31 @@ static void media_cache_item_del_from_astdb(struct ast_bucket_file *bucket_file) static void bucket_file_update_path(struct ast_bucket_file *bucket_file, const char *preferred_file_name) { - if (ast_strlen_zero(preferred_file_name)) { - return; - } + char *ext; - if (!strcmp(bucket_file->path, preferred_file_name)) { - return; - } + if (!ast_strlen_zero(preferred_file_name) && strcmp(bucket_file->path, preferred_file_name)) { + /* Use the preferred file name if available */ + + rename(bucket_file->path, preferred_file_name); + ast_copy_string(bucket_file->path, preferred_file_name, + sizeof(bucket_file->path)); + } else if (!strchr(bucket_file->path, '.') && (ext = strrchr(ast_sorcery_object_get_id(bucket_file), '.'))) { + /* If we don't have a file extension and were provided one in the URI, use it */ + char new_path[PATH_MAX]; + + ast_bucket_file_metadata_set(bucket_file, "ext", ext); - rename(bucket_file->path, preferred_file_name); - ast_copy_string(bucket_file->path, preferred_file_name, - sizeof(bucket_file->path)); + snprintf(new_path, sizeof(new_path), "%s%s", bucket_file->path, ext); + rename(bucket_file->path, new_path); + ast_copy_string(bucket_file->path, new_path, sizeof(bucket_file->path)); + } } int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, char *file_path, size_t len) { struct ast_bucket_file *bucket_file; + char *ext; SCOPED_AO2LOCK(media_lock, media_cache); if (ast_strlen_zero(uri)) { @@ -220,11 +228,18 @@ int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, if (bucket_file) { if (!ast_bucket_file_is_stale(bucket_file)) { ast_copy_string(file_path, bucket_file->path, len); + if ((ext = strrchr(file_path, '.'))) { + *ext = '\0'; + } ao2_ref(bucket_file, -1); + + ast_debug(5, "Returning media at local file: %s\n", file_path); return 0; } - /* Stale! Drop the ref, as we're going to retrieve it next. */ + /* Stale! Remove the item completely, as we're going to replace it next */ + ao2_unlink_flags(media_cache, bucket_file, OBJ_NOLOCK); + ast_bucket_file_delete(bucket_file); ao2_ref(bucket_file, -1); } @@ -243,9 +258,14 @@ int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, bucket_file_update_path(bucket_file, preferred_file_name); media_cache_item_sync_to_astdb(bucket_file); ast_copy_string(file_path, bucket_file->path, len); + if ((ext = strrchr(file_path, '.'))) { + *ext = '\0'; + } ao2_link_flags(media_cache, bucket_file, OBJ_NOLOCK); ao2_ref(bucket_file, -1); + ast_debug(5, "Returning media at local file: %s\n", file_path); + return 0; } @@ -692,7 +712,7 @@ int ast_media_cache_init(void) { ast_register_atexit(media_cache_shutdown); - media_cache = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_BUCKETS, + media_cache = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, AO2_BUCKETS, media_cache_hash, media_cache_cmp); if (!media_cache) { return -1; From 22e2340813ca1b66d4ec775eb547821a074507ab Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Thu, 29 Jan 2015 14:38:23 +0000 Subject: [PATCH 0286/1578] res/res_http_media_cache: Add an HTTP(S) backend for the core media cache This patch adds a bucket backend for the core media cache that interfaces to a remote HTTP server. When a media item is requested in the cache, the cache will query its bucket backends to see if they can provide the media item. If that media item has a scheme of HTTP or HTTPS, this backend will be invoked. The backend provides callbacks for the following: * create - this will always retrieve the URI specified by the provided bucket_file, and store it in the file specified by the object. * retrieve - this will pull the URI specified and store it in a temporary file. It is then up to the media cache to move/rename this file if desired. * delete - destroys the file associated with the bucket_file. * stale - if the bucket_file has expired, based on received HTTP headers from the remote server, or if the ETag on the server no longer matches the ETag stored on the bucket_file, the resource is determined to be stale. Note that the backend respects the ETag, Expires, and Cache-Control headers provided by the HTTP server it is querying. ASTERISK-25654 Change-Id: Ie201c2b34cafc0c90a7ee18d7c8359afaccc5250 --- CHANGES | 6 + res/res_curl.c | 1 + res/res_http_media_cache.c | 447 +++++++++++++++++++++++++++++++++++++ 3 files changed, 454 insertions(+) create mode 100644 res/res_http_media_cache.c diff --git a/CHANGES b/CHANGES index 1cb8a9f3d4b..f19704d9013 100644 --- a/CHANGES +++ b/CHANGES @@ -157,6 +157,12 @@ DTMF Features Resources ------------------ +res_http_media_cache +------------------ + * A backend for the core media cache, this module retrieves media files from + a remote HTTP(S) server and stores them in the core media cache for later + playback. + res_musiconhold ------------------ * Added sort=randstart to the sort options. It sorts the files by name and diff --git a/res/res_curl.c b/res/res_curl.c index eeacbd29873..0a781f19046 100644 --- a/res/res_curl.c +++ b/res/res_curl.c @@ -51,6 +51,7 @@ ASTERISK_REGISTER_FILE() static const char *dependents[] = { "func_curl.so", "res_config_curl.so", + "res_http_media_cache.so", }; static int unload_module(void) diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c new file mode 100644 index 00000000000..2207b96ddd4 --- /dev/null +++ b/res/res_http_media_cache.c @@ -0,0 +1,447 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Matt Jordan + * + * Matt Jordan + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief + * + * \author \verbatim Matt Jordan \endverbatim + * + * HTTP backend for the core media cache + */ + +/*** MODULEINFO + curl + res_curl + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include + +#include "asterisk/module.h" +#include "asterisk/bucket.h" +#include "asterisk/sorcery.h" +#include "asterisk/threadstorage.h" + +#define GLOBAL_USERAGENT "asterisk-libcurl-agent/1.0" + +#define MAX_HEADER_LENGTH 1023 + +/*! \brief Data passed to cURL callbacks */ +struct curl_bucket_file_data { + /*! The \c ast_bucket_file object that caused the operation */ + struct ast_bucket_file *bucket_file; + /*! File to write data to */ + FILE *out_file; +}; + +/*! + * \internal \brief The cURL header callback function + */ +static size_t curl_header_callback(char *buffer, size_t size, size_t nitems, void *data) +{ + struct curl_bucket_file_data *cb_data = data; + size_t realsize; + char *value; + char *header; + + realsize = size * nitems; + + if (realsize > MAX_HEADER_LENGTH) { + ast_log(LOG_WARNING, "cURL header length of '%zu' is too large: max %d\n", + realsize, MAX_HEADER_LENGTH); + return 0; + } + + /* buffer may not be NULL terminated */ + header = ast_alloca(realsize + 1); + memcpy(header, buffer, realsize); + header[realsize] = '\0'; + value = strchr(header, ':'); + if (!value) { + /* Not a header we care about; bail */ + return realsize; + } + *value++ = '\0'; + + if (strcasecmp(header, "ETag") + && strcasecmp(header, "Cache-Control") + && strcasecmp(header, "Last-Modified") + && strcasecmp(header, "Expires")) { + return realsize; + } + + value = ast_trim_blanks(ast_skip_blanks(value)); + header = ast_str_to_lower(header); + + ast_bucket_file_metadata_set(cb_data->bucket_file, header, value); + + return realsize; +} + +/*! + * \internal \brief The cURL body callback function + */ +static size_t curl_body_callback(void *ptr, size_t size, size_t nitems, void *data) +{ + struct curl_bucket_file_data *cb_data = data; + size_t realsize; + + realsize = fwrite(ptr, size, nitems, cb_data->out_file); + + return realsize; +} + +/*! + * \internal \brief Set the expiration metadata on the bucket file based on HTTP caching rules + */ +static void bucket_file_set_expiration(struct ast_bucket_file *bucket_file) +{ + struct ast_bucket_metadata *metadata; + char time_buf[32]; + struct timeval actual_expires = ast_tvnow(); + + metadata = ast_bucket_file_metadata_get(bucket_file, "cache-control"); + if (metadata) { + char *str_max_age; + + str_max_age = strstr(metadata->value, "s-maxage"); + if (!str_max_age) { + str_max_age = strstr(metadata->value, "max-age"); + } + + if (str_max_age) { + unsigned int max_age; + char *equal = strchr(str_max_age, '='); + if (equal && (sscanf(equal + 1, "%30u", &max_age) == 1)) { + actual_expires.tv_sec += max_age; + } + } + ao2_ref(metadata, -1); + } else { + metadata = ast_bucket_file_metadata_get(bucket_file, "expires"); + if (metadata) { + struct tm expires_time; + + strptime(metadata->value, "%a, %d %b %Y %T %z", &expires_time); + expires_time.tm_isdst = -1; + actual_expires.tv_sec = mktime(&expires_time); + + ao2_ref(metadata, -1); + } + } + + /* Use 'now' if we didn't get an expiration time */ + snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec); + + ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf); +} + +/*! \internal + * \brief Return whether or not we should always revalidate against the server + */ +static int bucket_file_always_revalidate(struct ast_bucket_file *bucket_file) +{ + RAII_VAR(struct ast_bucket_metadata *, metadata, + ast_bucket_file_metadata_get(bucket_file, "cache-control"), + ao2_cleanup); + + if (!metadata) { + return 0; + } + + if (strstr(metadata->value, "no-cache") + || strstr(metadata->value, "must-revalidate")) { + return 1; + } + + return 0; +} + +/*! \internal + * \brief Return whether or not the item has expired + */ +static int bucket_file_expired(struct ast_bucket_file *bucket_file) +{ + RAII_VAR(struct ast_bucket_metadata *, metadata, + ast_bucket_file_metadata_get(bucket_file, "__actual_expires"), + ao2_cleanup); + struct timeval current_time = ast_tvnow(); + struct timeval expires = { .tv_sec = 0, .tv_usec = 0 }; + + if (!metadata) { + return 1; + } + + if (sscanf(metadata->value, "%lu", &expires.tv_sec) != 1) { + return 1; + } + + return ast_tvcmp(current_time, expires) == -1 ? 0 : 1; +} + +/*! + * \internal \brief Obtain a CURL handle with common setup options + */ +static CURL *get_curl_instance(struct curl_bucket_file_data *cb_data) +{ + CURL *curl; + + curl = curl_easy_init(); + if (!curl) { + return NULL; + } + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header_callback); + curl_easy_setopt(curl, CURLOPT_USERAGENT, GLOBAL_USERAGENT); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(curl, CURLOPT_URL, ast_sorcery_object_get_id(cb_data->bucket_file)); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, cb_data); + + return curl; +} + +/*! + * \brief Execute the CURL + */ +static long execute_curl_instance(CURL *curl) +{ + char curl_errbuf[CURL_ERROR_SIZE + 1]; + long http_code; + + curl_errbuf[CURL_ERROR_SIZE] = '\0'; + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf); + + if (curl_easy_perform(curl)) { + ast_log(LOG_WARNING, "%s\n", curl_errbuf); + return -1; + } + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_easy_cleanup(curl); + + return http_code; +} + +/*! + * \internal \brief CURL the URI specified by the bucket_file and store it in the provided path + */ +static int bucket_file_run_curl(struct ast_bucket_file *bucket_file) +{ + struct curl_bucket_file_data cb_data = { + .bucket_file = bucket_file, + }; + long http_code; + CURL *curl; + + cb_data.out_file = fopen(bucket_file->path, "wb"); + if (!cb_data.out_file) { + ast_log(LOG_WARNING, "Failed to open file '%s' for writing: %s (%d)\n", + bucket_file->path, strerror(errno), errno); + return -1; + } + + curl = get_curl_instance(&cb_data); + if (!curl) { + fclose(cb_data.out_file); + return -1; + } + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&cb_data); + + http_code = execute_curl_instance(curl); + + fclose(cb_data.out_file); + + if (http_code / 100 == 2) { + bucket_file_set_expiration(bucket_file); + return 0; + } else { + ast_log(LOG_WARNING, "Failed to retrieve URL '%s': server returned %ld\n", + ast_sorcery_object_get_id(bucket_file), http_code); + } + + return -1; +} + +static int bucket_http_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object) +{ + struct ast_bucket_file *bucket_file = object; + struct ast_bucket_metadata *metadata; + struct curl_slist *header_list = NULL; + long http_code; + CURL *curl; + struct curl_bucket_file_data cb_data = { + .bucket_file = bucket_file + }; + char etag_buf[256]; + + if (!bucket_file_expired(bucket_file) && !bucket_file_always_revalidate(bucket_file)) { + return 0; + } + + /* See if we have an ETag for this item. If not, it's stale. */ + metadata = ast_bucket_file_metadata_get(bucket_file, "etag"); + if (!metadata) { + return 1; + } + + curl = get_curl_instance(&cb_data); + + /* Set the ETag header on our outgoing request */ + snprintf(etag_buf, sizeof(etag_buf), "If-None-Match: %s", metadata->value); + header_list = curl_slist_append(header_list, etag_buf); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + ao2_ref(metadata, -1); + + http_code = execute_curl_instance(curl); + + curl_slist_free_all(header_list); + + if (http_code == 304) { + bucket_file_set_expiration(bucket_file); + return 0; + } + + return 1; +} + +static int bucket_http_wizard_create(const struct ast_sorcery *sorcery, void *data, + void *object) +{ + struct ast_bucket_file *bucket_file = object; + + return bucket_file_run_curl(bucket_file); +} + +static void *bucket_http_wizard_retrieve_id(const struct ast_sorcery *sorcery, + void *data, const char *type, const char *id) +{ + struct ast_bucket_file *bucket_file; + + if (strcmp(type, "file")) { + ast_log(LOG_WARNING, "Failed to create storage: invalid bucket type '%s'\n", type); + return NULL; + } + + if (ast_strlen_zero(id)) { + ast_log(LOG_WARNING, "Failed to create storage: no URI\n"); + return NULL; + } + + bucket_file = ast_bucket_file_alloc(id); + if (!bucket_file) { + ast_log(LOG_WARNING, "Failed to create storage for '%s'\n", id); + return NULL; + } + + if (ast_bucket_file_temporary_create(bucket_file)) { + ast_log(LOG_WARNING, "Failed to create temporary storage for '%s'\n", id); + ast_sorcery_delete(sorcery, bucket_file); + ao2_ref(bucket_file, -1); + return NULL; + } + + if (bucket_file_run_curl(bucket_file)) { + ast_sorcery_delete(sorcery, bucket_file); + ao2_ref(bucket_file, -1); + return NULL; + } + + return bucket_file; +} + +static int bucket_http_wizard_delete(const struct ast_sorcery *sorcery, void *data, + void *object) +{ + struct ast_bucket_file *bucket_file = object; + + unlink(bucket_file->path); + + return 0; +} + +static struct ast_sorcery_wizard http_bucket_wizard = { + .name = "http", + .create = bucket_http_wizard_create, + .retrieve_id = bucket_http_wizard_retrieve_id, + .delete = bucket_http_wizard_delete, + .is_stale = bucket_http_wizard_is_stale, +}; + +static struct ast_sorcery_wizard http_bucket_file_wizard = { + .name = "http", + .create = bucket_http_wizard_create, + .retrieve_id = bucket_http_wizard_retrieve_id, + .delete = bucket_http_wizard_delete, + .is_stale = bucket_http_wizard_is_stale, +}; + +static struct ast_sorcery_wizard https_bucket_wizard = { + .name = "https", + .create = bucket_http_wizard_create, + .retrieve_id = bucket_http_wizard_retrieve_id, + .delete = bucket_http_wizard_delete, + .is_stale = bucket_http_wizard_is_stale, +}; + +static struct ast_sorcery_wizard https_bucket_file_wizard = { + .name = "https", + .create = bucket_http_wizard_create, + .retrieve_id = bucket_http_wizard_retrieve_id, + .delete = bucket_http_wizard_delete, + .is_stale = bucket_http_wizard_is_stale, +}; + +static int unload_module(void) +{ + return 0; +} + +static int load_module(void) +{ + if (ast_bucket_scheme_register("http", &http_bucket_wizard, &http_bucket_file_wizard, + NULL, NULL)) { + ast_log(LOG_ERROR, "Failed to register Bucket HTTP wizard scheme implementation\n"); + return AST_MODULE_LOAD_FAILURE; + } + + if (ast_bucket_scheme_register("https", &https_bucket_wizard, &https_bucket_file_wizard, + NULL, NULL)) { + ast_log(LOG_ERROR, "Failed to register Bucket HTTPS wizard scheme implementation\n"); + return AST_MODULE_LOAD_FAILURE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "HTTP Media Cache Backend", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_DEFAULT, + ); From 01962a393250125bb86c638b1786fbcc18a246cc Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 30 Dec 2015 10:52:28 -0600 Subject: [PATCH 0287/1578] tests/test_http_media_cache: Add unit tests for res_http_media_cache This patch adds unit tests for res_http_media cache, that covers nominal creation and retrieval - and through them as well, staleness and deletion checks. In addition, this patch adds tests that covers the interaction of various HTTP headers, including Expires, Etag, and Cache-Control. ASTERISK-25654 Change-Id: I2db101e307c863857fe416d6f5bf4cace9ac7cf5 --- tests/test_http_media_cache.c | 702 ++++++++++++++++++++++++++++++++++ 1 file changed, 702 insertions(+) create mode 100644 tests/test_http_media_cache.c diff --git a/tests/test_http_media_cache.c b/tests/test_http_media_cache.c new file mode 100644 index 00000000000..6a57433cbe8 --- /dev/null +++ b/tests/test_http_media_cache.c @@ -0,0 +1,702 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Matt Jordan + * + * Matt Jordan + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Tests for the HTTP media cache backend + * + * \author \verbatim Matt Jordan \endverbatim + * + * \ingroup tests + */ + +/*** MODULEINFO + TEST_FRAMEWORK + curl + res_http_media_cache + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include + +#include "asterisk/module.h" +#include "asterisk/http.h" +#include "asterisk/bucket.h" +#include "asterisk/test.h" + +#define CATEGORY "/res/http_media_cache/" + +#define TEST_URI "test_media_cache" + +struct test_options { + int status_code; + int send_file; + struct { + int s_maxage; + int maxage; + int no_cache; + int must_revalidate; + } cache_control; + struct timeval expires; + const char *status_text; + const char *etag; +}; + +static struct test_options options; + +static char server_uri[512]; + +#define VALIDATE_EXPIRES(test, bucket_file, expected, delta) do { \ + RAII_VAR(struct ast_bucket_metadata *, metadata, ast_bucket_file_metadata_get((bucket_file), "__actual_expires"), ao2_cleanup); \ + int actual_expires; \ + ast_test_validate(test, metadata != NULL); \ + ast_test_validate(test, sscanf(metadata->value, "%d", &actual_expires) == 1); \ + ast_test_validate(test, (((expected) + (delta) > actual_expires) && ((expected) - (delta) < actual_expires))); \ +} while (0) + +#define VALIDATE_STR_METADATA(test, bucket_file, key, expected) do { \ + RAII_VAR(struct ast_bucket_metadata *, metadata, ast_bucket_file_metadata_get((bucket_file), (key)), ao2_cleanup); \ + ast_test_validate(test, metadata != NULL); \ + ast_test_validate(test, !strcmp(metadata->value, (expected))); \ +} while (0) + +#define SET_OR_APPEND_CACHE_CONTROL(str) do { \ + if (!ast_str_strlen((str))) { \ + ast_str_set(&(str), 0, "%s", "cache-control: "); \ + } else { \ + ast_str_append(&(str), 0, "%s", ", "); \ + } \ +} while (0) + +static int http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) +{ + char file_name[64] = "/tmp/test-media-cache-XXXXXX"; + struct ast_str *http_header = ast_str_create(128); + struct ast_str *cache_control = ast_str_create(128); + int fd = -1; + int unmodified = 0; + int send_file = options.send_file && method == AST_HTTP_GET; + + if (!http_header) { + goto error; + } + + if (send_file) { + char buf[1024]; + + fd = mkstemp(file_name); + if (fd == -1) { + ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno); + goto error; + } + + memset(buf, 1, sizeof(buf)); + if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { + ast_log(LOG_ERROR, "Failed to write expected number of bytes to pipe\n"); + close(fd); + goto error; + } + close(fd); + + fd = open(file_name, 0); + if (fd == -1) { + ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno); + goto error; + } + } + + if (options.cache_control.maxage) { + SET_OR_APPEND_CACHE_CONTROL(cache_control); + ast_str_append(&cache_control, 0, "max-age=%d", options.cache_control.maxage); + } + + if (options.cache_control.s_maxage) { + SET_OR_APPEND_CACHE_CONTROL(cache_control); + ast_str_append(&cache_control, 0, "s-maxage=%d", options.cache_control.s_maxage); + } + + if (options.cache_control.no_cache) { + SET_OR_APPEND_CACHE_CONTROL(cache_control); + ast_str_append(&cache_control, 0, "%s", "no-cache"); + } + + if (options.cache_control.must_revalidate) { + SET_OR_APPEND_CACHE_CONTROL(cache_control); + ast_str_append(&cache_control, 0, "%s", "must-revalidate"); + } + + if (ast_str_strlen(cache_control)) { + ast_str_append(&http_header, 0, "%s\r\n", ast_str_buffer(cache_control)); + } + + if (options.expires.tv_sec) { + struct ast_tm now_time; + char tmbuf[64]; + + ast_localtime(&options.expires, &now_time, NULL); + ast_strftime(tmbuf, sizeof(tmbuf), "%a, %d %b %Y %T %z", &now_time); + ast_str_append(&http_header, 0, "Expires: %s\r\n", tmbuf); + } + + if (!ast_strlen_zero(options.etag)) { + struct ast_variable *v; + + ast_str_append(&http_header, 0, "ETag: %s\r\n", options.etag); + for (v = headers; v; v = v->next) { + if (!strcasecmp(v->name, "If-None-Match") && !strcasecmp(v->value, options.etag)) { + unmodified = 1; + break; + } + } + } + + if (!unmodified) { + ast_http_send(ser, method, options.status_code, options.status_text, http_header, NULL, send_file ? fd : 0, 1); + } else { + ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1); + if (send_file) { + close(fd); + } + } + + if (send_file) { + unlink(file_name); + } + + ast_free(cache_control); + + return 0; + +error: + ast_free(http_header); + ast_free(cache_control); + ast_http_request_close_on_completion(ser); + ast_http_error(ser, 418, "I'm a Teapot", "Please don't ask me to brew coffee."); + + return 0; +} + +static struct ast_http_uri test_uri = { + .description = "HTTP Media Cache Test URI", + .uri = TEST_URI, + .callback = http_callback, + .has_subtree = 1, + .data = NULL, + .key = __FILE__, +}; + +static int pre_test_cb(struct ast_test_info *info, struct ast_test *test) +{ + memset(&options, 0, sizeof(options)); + + return 0; +} + +static void bucket_file_cleanup(void *obj) +{ + struct ast_bucket_file *bucket_file = obj; + + if (bucket_file) { + ast_bucket_file_delete(bucket_file); + ao2_ref(bucket_file, -1); + } +} + +AST_TEST_DEFINE(retrieve_cache_control_directives) +{ + RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup); + struct timeval now = ast_tvnow(); + char uri[1024]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test retrieval of a resource with Cache-Control directives that affect staleness"; + info->description = + "This test covers retrieval of a resource with the Cache-Control header,\n" + "which specifies no-cache and/or must-revalidate."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav"); + + options.send_file = 1; + options.status_code = 200; + options.status_text = "OK"; + + ast_test_status_update(test, "Testing no-cache...\n"); + options.cache_control.no_cache = 1; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing no-cache with ETag...\n"); + options.cache_control.no_cache = 1; + options.etag = "123456789"; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + options.etag = NULL; + + ast_test_status_update(test, "Testing no-cache with max-age...\n"); + options.cache_control.no_cache = 1; + options.cache_control.maxage = 300; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); + bucket_file_cleanup(bucket_file); + + options.cache_control.maxage = 0; + options.cache_control.no_cache = 0; + + ast_test_status_update(test, "Testing must-revalidate...\n"); + options.cache_control.must_revalidate = 1; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing must-revalidate with ETag...\n"); + options.cache_control.must_revalidate = 1; + options.etag = "123456789"; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + options.etag = NULL; + + ast_test_status_update(test, "Testing must-revalidate with max-age...\n"); + options.cache_control.must_revalidate = 1; + options.cache_control.maxage = 300; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(retrieve_cache_control_age) +{ + RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup); + struct timeval now = ast_tvnow(); + char uri[1024]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test retrieval of a resource with age specifiers in Cache-Control"; + info->description = + "This test covers retrieval of a resource with the Cache-Control header,\n" + "which specifies max-age and/or s-maxage. The test verifies proper precedence\n" + "ordering of the header attributes, along with its relation if the Expires\n" + "header is present."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav"); + + options.send_file = 1; + options.status_code = 200; + options.status_text = "OK"; + + ast_test_status_update(test, "Testing max-age...\n"); + options.cache_control.maxage = 300; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing s-maxage...\n"); + now = ast_tvnow(); + options.cache_control.maxage = 0; + options.cache_control.s_maxage = 300; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing max-age and s-maxage...\n"); + now = ast_tvnow(); + options.cache_control.maxage = 300; + options.cache_control.s_maxage = 600; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing max-age and Expires...\n"); + now = ast_tvnow(); + options.cache_control.maxage = 300; + options.cache_control.s_maxage = 0; + options.expires.tv_sec = now.tv_sec + 3000; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing s-maxage and Expires...\n"); + now = ast_tvnow(); + options.cache_control.maxage = 0; + options.cache_control.s_maxage = 300; + options.expires.tv_sec = now.tv_sec + 3000; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing s-maxage and Expires...\n"); + now = ast_tvnow(); + options.cache_control.maxage = 0; + options.cache_control.s_maxage = 300; + options.expires.tv_sec = now.tv_sec + 3000; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + bucket_file_cleanup(bucket_file); + + ast_test_status_update(test, "Testing max-age, s-maxage, and Expires...\n"); + now = ast_tvnow(); + options.cache_control.maxage = 300; + options.cache_control.s_maxage = 600; + options.expires.tv_sec = now.tv_sec + 3000; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 1); + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(retrieve_etag_expired) +{ + RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup); + struct timeval now = ast_tvnow(); + char uri[1024]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test retrieval of an expired resource with an ETag"; + info->description = + "This test covers a staleness check of a resource with an ETag\n" + "that has also expired. It guarantees that even if a resource\n" + "is expired, we will still not consider it stale if the resource\n" + "has not changed per the ETag value."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + options.send_file = 1; + options.status_code = 200; + options.status_text = "OK"; + options.etag = "123456789"; + options.expires.tv_sec = now.tv_sec - 1; + + snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav"); + + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); + ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); + VALIDATE_STR_METADATA(test, bucket_file, "etag", options.etag); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 1); + + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(retrieve_expires) +{ + RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup); + struct timeval now = ast_tvnow(); + char uri[1024]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test retrieval with explicit expiration"; + info->description = + "This test covers retrieving a resource that has an Expires.\n" + "After retrieval of the resource, staleness is checked. With\n" + "a non-expired resource, we expect the resource to not be stale.\n" + "When the expiration has occurred, we expect the staleness check\n" + "to fail."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + options.send_file = 1; + options.status_code = 200; + options.status_text = "OK"; + options.expires.tv_sec = now.tv_sec + 3000; + + snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav"); + + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); + ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 3000, 1); + + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + + /* Clean up previous result */ + bucket_file_cleanup(bucket_file); + + options.expires.tv_sec = now.tv_sec - 1; + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 1); + + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(retrieve_etag) +{ + RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup); + struct timeval now = ast_tvnow(); + char uri[1024]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test retrieval with an ETag"; + info->description = + "This test covers retrieving a resource that has an ETag.\n" + "After retrieval of the resource, staleness is checked. With\n" + "matching ETags, we expect the resource to not be stale. When\n" + "the ETag does not match, we expect the resource to be stale."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + options.send_file = 1; + options.status_code = 200; + options.status_text = "OK"; + options.etag = "123456789"; + + snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav"); + + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); + ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); + VALIDATE_STR_METADATA(test, bucket_file, "etag", options.etag); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 1); + + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); + + options.etag = "99999999"; + ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(retrieve_nominal) +{ + RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup); + struct timeval now = ast_tvnow(); + char uri[1024]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test nominal retrieval"; + info->description = + "Test nominal retrieval of a resource."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + options.send_file = 1; + options.status_code = 200; + options.status_text = "OK"; + + snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav"); + + bucket_file = ast_bucket_file_retrieve(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); + ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(create_nominal) +{ + RAII_VAR(struct ast_bucket_file *, bucket_file, NULL, bucket_file_cleanup); + struct timeval now = ast_tvnow(); + char uri[1024]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test nominal creation"; + info->description = + "Test nominal creation of a resource."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + options.send_file = 1; + options.status_code = 200; + options.status_text = "OK"; + + snprintf(uri, sizeof(uri), "%s/%s", server_uri, "foo.wav"); + + bucket_file = ast_bucket_file_alloc(uri); + ast_test_validate(test, bucket_file != NULL); + ast_test_validate(test, ast_bucket_file_temporary_create(bucket_file) == 0); + ast_test_validate(test, ast_bucket_file_create(bucket_file) == 0); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 1); + + return AST_TEST_PASS; +} + + +static int process_config(int reload) +{ + struct ast_config *config; + struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + const char *bindaddr; + const char *bindport; + const char *prefix; + const char *enabled; + + config = ast_config_load("http.conf", config_flags); + if (!config || config == CONFIG_STATUS_FILEINVALID) { + return -1; + } else if (config == CONFIG_STATUS_FILEUNCHANGED) { + return 0; + } + + enabled = ast_config_option(config, "general", "enabled"); + if (!enabled || ast_false(enabled)) { + ast_config_destroy(config); + return -1; + } + + /* Construct our Server URI */ + bindaddr = ast_config_option(config, "general", "bindaddr"); + if (!bindaddr) { + ast_config_destroy(config); + return -1; + } + + bindport = ast_config_option(config, "general", "bindport"); + if (!bindport) { + bindport = "8088"; + } + + prefix = ast_config_option(config, "general", "prefix"); + + snprintf(server_uri, sizeof(server_uri), "http://%s:%s%s/%s", bindaddr, bindport, S_OR(prefix, ""), TEST_URI); + + ast_config_destroy(config); + + return 0; +} + +static int reload_module(void) +{ + return process_config(1); +} + +static int load_module(void) +{ + if (process_config(0)) { + return AST_MODULE_LOAD_DECLINE; + } + + if (ast_http_uri_link(&test_uri)) { + return AST_MODULE_LOAD_DECLINE; + } + + AST_TEST_REGISTER(create_nominal); + + AST_TEST_REGISTER(retrieve_nominal); + AST_TEST_REGISTER(retrieve_etag); + AST_TEST_REGISTER(retrieve_expires); + AST_TEST_REGISTER(retrieve_etag_expired); + AST_TEST_REGISTER(retrieve_cache_control_age); + AST_TEST_REGISTER(retrieve_cache_control_directives); + + ast_test_register_init(CATEGORY, pre_test_cb); + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + ast_http_uri_unlink(&test_uri); + + AST_TEST_UNREGISTER(create_nominal); + + AST_TEST_UNREGISTER(retrieve_nominal); + AST_TEST_UNREGISTER(retrieve_etag); + AST_TEST_UNREGISTER(retrieve_expires); + AST_TEST_UNREGISTER(retrieve_etag_expired); + AST_TEST_UNREGISTER(retrieve_cache_control_age); + AST_TEST_UNREGISTER(retrieve_cache_control_directives); + + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "HTTP Media Cache Backend Tests", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .reload = reload_module, + .unload = unload_module, + .load_pri = AST_MODPRI_DEFAULT, + ); From ca14b99e6e7a80f648521ec81512cbadab2ed6cd Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 26 Dec 2015 15:29:04 -0600 Subject: [PATCH 0288/1578] main/file: Add the ability to play media in the media cache This patch allows applications/APIs that access media through the core file APIs to play media in the media cache. Prior to determining if a 'filename' exists, the filename is passed to the media cache's retrieve API call. If that call succeeds, the local file specified passed back by the API is opened for streaming. When used in this fashion, the 'filename' is actually a URI that the media cache process and understand. ASTERISK-25654 #close Change-Id: I73b6e2e90c3e91b8500581c45cdf9c0dc785f5f0 --- CHANGES | 26 ++++++++++++++++++++++++++ main/file.c | 5 +++++ 2 files changed, 31 insertions(+) diff --git a/CHANGES b/CHANGES index f19704d9013..da516efdc2a 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,21 @@ ConfBridge - record_command: a command to execute when recording is finished Note that these options may also be with the CONFBRIDGE function. +ControlPlayback +------------------ + * Remote files can now be retrieved and played back. See the Playback + dialplan application for more details. + +Playback +------------------ + * Remote files can now be retrieved and played back via the Playback and other + media playback dialplan applications. This is done by directly providing + the URL to play to the dialplan application: + same => n,Playback(http://1.1.1.1/howler-monkeys-fl.wav) + Note that unlike 'normal' media files, the entire URI to the file must be + provided, including the file extension. Currently, on HTTP and HTTPS URI + schemes are supported. + SMS ------------------ * Added the 'n' option, which prevents the SMS from being written to the log @@ -132,6 +147,17 @@ Core of '[json]' can be set, e.g., full => [json]debug,verbose,notice,warning,error + * The core now supports a 'media cache', which stores temporary media files + retrieved from external sources. CLI commands have been added to manipulate + and display the cached files, including: + - 'media cache show ' - show all cached media files, or details about + one particular cached media file + - 'media cache refresh ' - force a refresh of a particular media file + in the cache + - 'media cache delete ' - remove an item from the cache + - 'media cache create ' - retrieve a URI and store it in the cache + + Functions ------------------ diff --git a/main/file.c b/main/file.c index f0f826a4ff9..654937a5824 100644 --- a/main/file.c +++ b/main/file.c @@ -54,6 +54,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis.h" #include "asterisk/json.h" #include "asterisk/stasis_system.h" +#include "asterisk/media_cache.h" /*! \brief * The following variable controls the layout of localized sound files. @@ -644,6 +645,10 @@ static int fileexists_test(const char *filename, const char *fmt, const char *la return 0; } + if (!ast_media_cache_retrieve(filename, NULL, buf, buflen)) { + return filehelper(buf, result_cap, NULL, ACTION_EXISTS); + } + if (ast_language_is_prefix && !is_absolute_path(filename)) { /* new layout */ if (lang) { snprintf(buf, buflen, "%s/%s", lang, filename); From 13efea24f7ce6ccc01d1a5a0603be2636d83a408 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sun, 28 Feb 2016 19:05:16 -0600 Subject: [PATCH 0289/1578] main/app: Only look to end of file if ':end' is specified, and not just ':' There is a little known feature in app_controlplayback that will cause the specified offset to be used relative to the end of a file if a ':end' is detected within the filename. This feature is pretty bad, but okay. However, a bug exists in this code where a ':' detected in the filename will cause the end pointer to be non-NULL, even if the full ':end' isn't specified. This causes us to treat an unspecified offset (0) as being "start playing from the end of the file", resulting in no file playback occurring. This patch fixes this bug by resetting the end pointer if ':end' is not found in the filename. Change-Id: Ib4c7b1b45283e4effd622a970055c51146892f35 --- main/app.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/app.c b/main/app.c index 826e41128c9..e1d70498cf3 100644 --- a/main/app.c +++ b/main/app.c @@ -1112,6 +1112,8 @@ static int control_streamfile(struct ast_channel *chan, if (!strcasecmp(end, ":end")) { *end = '\0'; end++; + } else { + end = NULL; } } From a72f3b5bb43e8f8044d2deb77e8a65b0c70ccf14 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 24 Mar 2016 08:18:31 -0300 Subject: [PATCH 0290/1578] tests/test_http_media_cache: Fix file descriptor leak in test. Change-Id: Ie8a9ae3d13bdeaacafc8d28271adc6707f633a5f --- tests/test_http_media_cache.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_http_media_cache.c b/tests/test_http_media_cache.c index 6a57433cbe8..c08604f1e9b 100644 --- a/tests/test_http_media_cache.c +++ b/tests/test_http_media_cache.c @@ -173,12 +173,10 @@ static int http_callback(struct ast_tcptls_session_instance *ser, const struct a ast_http_send(ser, method, options.status_code, options.status_text, http_header, NULL, send_file ? fd : 0, 1); } else { ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1); - if (send_file) { - close(fd); - } } if (send_file) { + close(fd); unlink(file_name); } From 87c9ab97ea8038b3ef694d027bce26f29ea24777 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Thu, 24 Mar 2016 11:48:32 +0100 Subject: [PATCH 0291/1578] core/logging: Fix broken syslog levels on older glibc. The fix to ASTERISK-25407 introduced the usage of LOG_MAKEPRI. However this macro is broken in older glibc (< 2.17); it would left-shift the facility a second time, causing the resultant priority to become invalid. The syslog manpage mentions nothing about LOG_MAKEPRI and suggests this: The priority argument is formed by ORing the facility and the level values [...]. ASTERISK-25510 #close Reported by: Michael Newton Change-Id: Ia89debe7fac5ad090c7ef595c0707f31bb1e3d03 --- main/logger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/logger.c b/main/logger.c index 13f6de89026..42a1c700049 100644 --- a/main/logger.c +++ b/main/logger.c @@ -1514,7 +1514,8 @@ static void logger_print_normal(struct logmsg *logmsg) continue; } - syslog_level = LOG_MAKEPRI(chan->facility, syslog_level); + /* Don't use LOG_MAKEPRI because it's broken in glibc<2.17 */ + syslog_level = chan->facility | syslog_level; /* LOG_MAKEPRI(chan->facility, syslog_level); */ if (!chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) { syslog(syslog_level, "%s", buf); } From 13cdf3e8a168345ce0eb8e8fb70becec5c1c99a5 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Thu, 24 Mar 2016 13:51:00 +0100 Subject: [PATCH 0292/1578] musiconhold: Only warn if music class is not found in memory and database. The log message when a MusicOnHold music class was not found was changed from debug level to WARNING level in Asterisk 11.19 and 13.5. For those using realtime musiconhold, this message is wrong because it warns before checking the database. This changeset delays the warning until after the database has been checked. Reported-by: Conrad de Wet ASTERISK-25444 #close Change-Id: I6cfb2db2f9cfbd2bb3d30566ecae361c4abf6dbf --- res/res_musiconhold.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 4e5056358fb..f124d58f23a 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1379,6 +1379,18 @@ static struct mohclass *_moh_class_malloc(const char *file, int line, const char return class; } +static struct ast_variable *load_realtime_musiconhold(const char *name) +{ + struct ast_variable *var = ast_load_realtime("musiconhold", "name", name, SENTINEL); + if (!var) { + ast_log(LOG_WARNING, + "Music on Hold class '%s' not found in memory/database. " + "Verify your configuration.\n", + name); + } + return var; +} + static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass) { struct mohclass *mohclass = NULL; @@ -1387,6 +1399,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con int res = 0; int i; int realtime_possible = ast_check_realtime("musiconhold"); + int warn_if_not_in_memory = !realtime_possible; const char *classes[] = {NULL, NULL, interpclass, "default"}; if (ast_test_flag(global_flags, MOH_PREFERCHANNELCLASS)) { @@ -1414,9 +1427,9 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con for (i = 0; i < ARRAY_LEN(classes); ++i) { if (!ast_strlen_zero(classes[i])) { - mohclass = get_mohbyname(classes[i], 1, 0); + mohclass = get_mohbyname(classes[i], warn_if_not_in_memory, 0); if (!mohclass && realtime_possible) { - var = ast_load_realtime("musiconhold", "name", classes[i], SENTINEL); + var = load_realtime_musiconhold(classes[i]); } if (mohclass || var) { break; From 894071ea2cedcc65e452cabfe3cd805daf5a6a1d Mon Sep 17 00:00:00 2001 From: Gianluca Merlo Date: Sat, 19 Mar 2016 13:34:26 +0100 Subject: [PATCH 0293/1578] config: fix flags in uint option handler The configuration unsigned integer option handler sets flags for the parser as if the option should be a signed integer (PARSE_INT32), leading to errors on "out of range" values. Fix flags (PARSE_UINT32). A fix to res_pjsip is also present which stops invalid flags from being passed when registering sorcery object fields for qualify status. ASTERISK-25612 #close Change-Id: I96b539336275e0e72a8e8033487d2c3344debd3e --- apps/app_skel.c | 2 +- main/config_options.c | 2 +- res/res_pjsip/pjsip_options.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/app_skel.c b/apps/app_skel.c index 54ecbe1ecb7..0f17d9bf3cd 100644 --- a/apps/app_skel.c +++ b/apps/app_skel.c @@ -739,7 +739,7 @@ static int load_module(void) /* Level options */ aco_option_register(&cfg_info, "max_number", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_num)); - aco_option_register(&cfg_info, "max_guesses", ACO_EXACT, level_options, NULL, OPT_UINT_T, 1, FLDSET(struct skel_level, max_guesses)); + aco_option_register(&cfg_info, "max_guesses", ACO_EXACT, level_options, NULL, OPT_UINT_T, 0, FLDSET(struct skel_level, max_guesses)); if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) { goto error; diff --git a/main/config_options.c b/main/config_options.c index f8c7b0c6768..e59e5cf7afc 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -1346,7 +1346,7 @@ static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var */ static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) { unsigned int *field = (unsigned int *)(obj + opt->args[0]); - unsigned int flags = PARSE_INT32 | opt->flags; + unsigned int flags = PARSE_UINT32 | opt->flags; int res = 0; if (opt->flags & PARSE_IN_RANGE) { res = opt->flags & PARSE_DEFAULT ? diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index aed9620303b..4cce5583678 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1027,14 +1027,14 @@ int ast_sip_initialize_sorcery_qualify(void) snprintf(status_value_unknown, sizeof(status_value_unknown), "%u", UNKNOWN); ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "last_status", - status_value_unknown, OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, last_status)); + status_value_unknown, OPT_UINT_T, 0, FLDSET(struct ast_sip_contact_status, last_status)); snprintf(status_value_created, sizeof(status_value_created), "%u", CREATED); ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "status", - status_value_created, OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, status)); + status_value_created, OPT_UINT_T, 0, FLDSET(struct ast_sip_contact_status, status)); ast_sorcery_object_field_register_custom_nodoc(sorcery, CONTACT_STATUS, "rtt_start", "0.0", rtt_start_handler, rtt_start_to_str, NULL, 0, 0); ast_sorcery_object_field_register_nodoc(sorcery, CONTACT_STATUS, "rtt", - "0", OPT_UINT_T, 1, FLDSET(struct ast_sip_contact_status, rtt)); + "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact_status, rtt)); return 0; } From 3f720155b7c8b3089c59cbfc78150aff4efc8240 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 24 Mar 2016 20:08:10 +0100 Subject: [PATCH 0294/1578] chan_sip: Do not send all codecs on INVITE. Do not break on Session-Timers. Asterisk 13.7.0 included a fix for ASTERISK-24543, not to send all those codecs, which the caller did not request/support. That fix was not complete because on the second Session Timer all codecs were sent again. Some VoIP/SIP clients interpreted that complete codec-list as a change in the SIP session. Because of that, Asterisk did not send the RTP audio via NAT anymore which created a non-audio scenario after the second Session Timer fired. ASTERISK-24543 #close Change-Id: I1881827816ab7fd47eb4287a95961179b34a0b66 --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 09ab1a196d7..ffc2084a1b6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -13531,7 +13531,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int } /* Finally our remaining audio/video codecs */ - for (x = 0; ast_test_flag(&p->flags[0], SIP_OUTGOING) && x < ast_format_cap_count(p->caps); x++) { + for (x = 0; p->outgoing_call && x < ast_format_cap_count(p->caps); x++) { tmp_fmt = ast_format_cap_get_format(p->caps, x); if (ast_format_cap_iscompatible_format(alreadysent, tmp_fmt) != AST_FORMAT_CMP_NOT_EQUAL) { From 89e94e886c8d2a3bf31eae50d838afc2c26906f9 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 10 Mar 2016 16:58:49 -0600 Subject: [PATCH 0295/1578] Restrict CLI/AMI commands on shutdown. During stress testing, we have frequently seen crashes occur because a CLI or AMI command attempts to access information that is in the process of being destroyed. When addressing how to fix this issue, we initially considered fixing individual crashes we observed. However, the changes required to fix those problems would introduce considerable overhead to the nominal case. This is not reasonable in order to prevent a crash from occurring while Asterisk is already shutting down. Instead, this change makes it so AMI and CLI commands cannot be executed if Asterisk is being shut down. For AMI, this is absolute. For CLI, though, certain commands can be registered so that they may be run during Asterisk shutdown. ASTERISK-25825 #close Change-Id: I8887e215ac352fadf7f4c1e082da9089b1421990 --- include/asterisk/cli.h | 12 ++++++++++ main/asterisk.c | 7 ++++++ main/cli.c | 53 ++++++++++++++++++++++++++++++++++++++++-- main/manager.c | 8 +++++++ main/utils.c | 1 + 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/include/asterisk/cli.h b/include/asterisk/cli.h index 0bda6665ce3..c79a4e93ce6 100644 --- a/include/asterisk/cli.h +++ b/include/asterisk/cli.h @@ -326,6 +326,18 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta */ void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix); +/* + * \brief Allow a CLI command to be executed while Asterisk is shutting down. + * + * CLI commands by defeault are disabled when Asterisk is shutting down. This is + * to ensure the safety of the shutdown since CLI commands may attempt to access + * resources that have been freed as a result of the shutdown. + * + * If a CLI command should be allowed at shutdown, then the best way to enable this + * is to call ast_cli_allow_at_shutdown during the CLI_INIT state of the CLI handler. + */ +int ast_cli_allow_at_shutdown(struct ast_cli_entry *e); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/asterisk.c b/main/asterisk.c index da804e19639..7636ec7b40a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -2343,6 +2343,7 @@ static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_ar e->usage = "Usage: core stop now\n" " Shuts down a running Asterisk immediately, hanging up all active calls .\n"; + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: return NULL; @@ -2363,6 +2364,7 @@ static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast "Usage: core stop gracefully\n" " Causes Asterisk to not accept new calls, and exit when all\n" " active calls have terminated normally.\n"; + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: return NULL; @@ -2382,6 +2384,7 @@ static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struc e->usage = "Usage: core stop when convenient\n" " Causes Asterisk to perform a shutdown when all active calls have ended.\n"; + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: return NULL; @@ -2403,6 +2406,7 @@ static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli "Usage: core restart now\n" " Causes Asterisk to hangup all calls and exec() itself performing a cold\n" " restart.\n"; + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: return NULL; @@ -2423,6 +2427,7 @@ static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct "Usage: core restart gracefully\n" " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n" " restart when all active calls have ended.\n"; + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: return NULL; @@ -2442,6 +2447,7 @@ static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, st e->usage = "Usage: core restart when convenient\n" " Causes Asterisk to perform a cold restart when all active calls have ended.\n"; + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: return NULL; @@ -2463,6 +2469,7 @@ static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_ "Usage: core abort shutdown\n" " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n" " call operations.\n"; + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: return NULL; diff --git a/main/cli.c b/main/cli.c index 0ac5d612a0a..f2bedc91aba 100644 --- a/main/cli.c +++ b/main/cli.c @@ -63,6 +63,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/bridge.h" #include "asterisk/stasis_channels.h" #include "asterisk/stasis_bridges.h" +#include "asterisk/vector.h" /*! * \brief List of restrictions per user. @@ -109,6 +110,9 @@ static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE; AST_THREADSTORAGE(ast_cli_buf); +AST_RWLOCK_DEFINE_STATIC(shutdown_commands_lock); +static AST_VECTOR(, struct ast_cli_entry *) shutdown_commands; + /*! \brief Initial buffer size for resulting strings in ast_cli() */ #define AST_CLI_INITLEN 256 @@ -2031,6 +2035,7 @@ static void cli_shutdown(void) /*! \brief initialize the _full_cmd string in * each of the builtins. */ void ast_builtins_init(void) { + AST_VECTOR_INIT(&shutdown_commands, 0); ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli)); ast_register_cleanup(cli_shutdown); } @@ -2209,6 +2214,13 @@ static int cli_is_registered(struct ast_cli_entry *e) return 0; } +static void remove_shutdown_command(struct ast_cli_entry *e) +{ + ast_rwlock_wrlock(&shutdown_commands_lock); + AST_VECTOR_REMOVE_ELEM_UNORDERED(&shutdown_commands, e, AST_VECTOR_ELEM_CLEANUP_NOOP); + ast_rwlock_unlock(&shutdown_commands_lock); +} + int ast_cli_unregister(struct ast_cli_entry *e) { if (e->inuse) { @@ -2217,6 +2229,7 @@ int ast_cli_unregister(struct ast_cli_entry *e) AST_RWLIST_WRLOCK(&helpers); AST_RWLIST_REMOVE(&helpers, e, list); AST_RWLIST_UNLOCK(&helpers); + remove_shutdown_command(e); ast_free(e->_full_cmd); e->_full_cmd = NULL; if (e->handler) { @@ -2675,10 +2688,27 @@ char *ast_cli_generator(const char *text, const char *word, int state) return __ast_cli_generator(text, word, state, 1); } +static int allowed_on_shutdown(struct ast_cli_entry *e) +{ + int found = 0; + int i; + + ast_rwlock_rdlock(&shutdown_commands_lock); + for (i = 0; i < AST_VECTOR_SIZE(&shutdown_commands); ++i) { + if (e == AST_VECTOR_GET(&shutdown_commands, i)) { + found = 1; + break; + } + } + ast_rwlock_unlock(&shutdown_commands_lock); + + return found; +} + int ast_cli_command_full(int uid, int gid, int fd, const char *s) { const char *args[AST_MAX_ARGS + 1]; - struct ast_cli_entry *e; + struct ast_cli_entry *e = NULL; int x; char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL); char tmp[AST_MAX_ARGS + 1]; @@ -2702,6 +2732,11 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s) goto done; } + if (ast_shutting_down() && !allowed_on_shutdown(e)) { + ast_cli(fd, "Command '%s' cannot be run during shutdown\n", s); + goto done; + } + ast_join(tmp, sizeof(tmp), args + 1); /* Check if the user has rights to run this command. */ if (!cli_has_permissions(uid, gid, tmp)) { @@ -2724,8 +2759,11 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s) } else if (retval == CLI_FAILURE) { ast_cli(fd, "Command '%s' failed.\n", s); } - ast_atomic_fetchadd_int(&e->inuse, -1); + done: + if (e) { + ast_atomic_fetchadd_int(&e->inuse, -1); + } ast_free(duplicate); return retval == CLI_SUCCESS ? RESULT_SUCCESS : RESULT_FAILURE; } @@ -2751,3 +2789,14 @@ void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix) { print_uptimestr(fd, ast_tv(seconds, 0), prefix, 0); } + +int ast_cli_allow_at_shutdown(struct ast_cli_entry *e) +{ + int res; + + ast_rwlock_wrlock(&shutdown_commands_lock); + res = AST_VECTOR_APPEND(&shutdown_commands, e); + ast_rwlock_unlock(&shutdown_commands_lock); + + return res; +} diff --git a/main/manager.c b/main/manager.c index 2adcb3e5a6a..e74b253ff29 100644 --- a/main/manager.c +++ b/main/manager.c @@ -6138,6 +6138,14 @@ static int process_message(struct mansession *s, const struct message *m) return 0; } + if (ast_shutting_down()) { + ast_log(LOG_ERROR, "Unable to process manager action '%s'. Asterisk is shutting down.\n", action); + mansession_lock(s); + astman_send_error(s, m, "Asterisk is shutting down"); + mansession_unlock(s); + return 0; + } + if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") diff --git a/main/utils.c b/main/utils.c index 8a9f91062d9..6a778b90c4a 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1153,6 +1153,7 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_ "Usage: core show locks\n" " This command is for lock debugging. It prints out which locks\n" "are owned by each active thread.\n"; + ast_cli_allow_on_shutdown(e); return NULL; case CLI_GENERATE: From 72a897c5345cda22697931f458aabe98fb6c0862 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 25 Mar 2016 08:02:41 -0300 Subject: [PATCH 0296/1578] media_cache: Demote warning to debug as it may occur often. The file playback system will now query the media cache and then the old file functionality. Under normal conditions this will result in the cache failing to retrieve a file causing a warning message to get output each time a file is played back. This change demotes this warning to a debug message. Change-Id: Ib72246ba300b5cce32774bfb3c26634bfb708624 --- main/media_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/media_cache.c b/main/media_cache.c index 9d68a10a54e..958a05bb254 100644 --- a/main/media_cache.c +++ b/main/media_cache.c @@ -248,7 +248,7 @@ int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, */ bucket_file = ast_bucket_file_retrieve(uri); if (!bucket_file) { - ast_log(LOG_WARNING, "Failed to obtain media at '%s'\n", uri); + ast_debug(2, "Failed to obtain media at '%s'\n", uri); return -1; } From e2853ae3375d8ce8d2f52be5d7d9e3e7761af152 Mon Sep 17 00:00:00 2001 From: Philip Correia Date: Mon, 15 Dec 2014 13:23:53 +0200 Subject: [PATCH 0297/1578] res_parking: Update parking documentation for dynamic parking lots. * Remove duplicate res_parking.conf courtesytone config option documentation. ASTERISK-24596 #close Reported by: Philip Correia ASTERISK-24605 Reported by: Philip Correia Patches: call_park_app_doc.patch (license #6672) patch uploaded by Philip Correia Change-Id: I90a92a891c6494dc08173e675856afcc4764c5b5 --- configs/samples/res_parking.conf.sample | 42 ++++++++++++++++ res/parking/parking_applications.c | 41 ++++++++++++++++ res/res_parking.c | 65 +++++++++++++++++++++---- 3 files changed, 138 insertions(+), 10 deletions(-) diff --git a/configs/samples/res_parking.conf.sample b/configs/samples/res_parking.conf.sample index d24be2039cc..e13f780e0e3 100644 --- a/configs/samples/res_parking.conf.sample +++ b/configs/samples/res_parking.conf.sample @@ -1,5 +1,43 @@ [general] ;parkeddynamic = yes ; Enables dynamically created parkinglots. (default is no) + ; If the option is enabled then the following + ; variables can be used to dynamically create + ; new parking lots. + ; + ; The PARKINGDYNAMIC variable specifies the + ; parking lot to use as a template to create + ; a dynamic parking lot. It is an error to + ; specify a non-existent parking lot for the + ; template. If not set then the default + ; parking lot is used as the template. + ; + ; The PARKINGDYNCONTEXT variable specifies + ; the dialplan context to use for the newly + ; created dynamic parking lot. If not set + ; then the context from the parking lot + ; template is used. The context is created + ; if it does not already exist and the new + ; parking lot needs to create extensions. + ; + ; The PARKINGDYNEXTEN variable specifies the + ; parkext to use for the newly created dynamic + ; parking lot. If not set then the parkext + ; is used from the parking lot template. If + ; the template does not specify a parkext + ; then no extensions are created for the + ; newly created parking lot. The dynamic + ; parking lot cannot be created if it needs + ; to create extensions that overlap existing + ; parking lot extensions. The only exception + ; to this is for the parkext extension and + ; only if neither of the overlaping parking + ; lot's parkext is exclusive. + ; + ; The PARKINGDYNPOS variable specifies the + ; parking positions to use for the newly + ; created dynamic parking lot. If not set + ; then the parkpos from the parking lot + ; template is used. ; A parking lot named 'default' will automatically be used when no other ; named parking lot is indicated for use by the park application or a @@ -11,6 +49,10 @@ parkext => 700 ; What extension to dial to park. (optional; if ; specified, extensions will be created for parkext and ; the whole range of parkpos) + ; + ; Note: Generated parking extensions cannot overlap. + ; The only exception is if neither overlapping parkext + ; is exclusive. ;parkext_exclusive=yes ; Specify that the parkext created for this parking lot ; will only access this parking lot. (default is no) diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c index 0a0ea3c4b82..3a9527c1f92 100644 --- a/res/parking/parking_applications.c +++ b/res/parking/parking_applications.c @@ -90,6 +90,47 @@ ASTERISK_REGISTER_FILE() call on that extension. If the extension is already in use then execution will continue at the next priority. + If the parkeddynamic option is enabled in + res_parking.conf the following variables can be + used to dynamically create new parking lots. When using dynamic parking + lots, be aware of the conditions as explained in the notes section + below. + + The PARKINGDYNAMIC variable specifies the + parking lot to use as a template to create a dynamic parking lot. It + is an error to specify a non-existent parking lot for the template. + If not set then the default parking lot is used as the template. + + The PARKINGDYNCONTEXT variable specifies the + dialplan context to use for the newly created dynamic parking lot. If + not set then the context from the parking lot template is used. The + context is created if it does not already exist and the new parking lot + needs to create extensions. + + The PARKINGDYNEXTEN variable specifies the + parkext to use for the newly created dynamic + parking lot. If not set then the parkext is used from + the parking lot template. If the template does not specify a + parkext then no extensions are created for the newly + created parking lot. The dynamic parking lot cannot be created if it + needs to create extensions that overlap existing parking lot extensions. + The only exception to this is for the parkext + extension and only if neither of the overlaping parking lot's + parkext is exclusive. + + The PARKINGDYNPOS variable specifies the + parking positions to use for the newly created dynamic parking lot. If + not set then the parkpos from the parking lot template + is used. + + + This application must be used as the first extension priority + to be recognized as a parking access extension for blind transfers. + Blind transfers and the DTMF one-touch parking feature need this + distinction to operate properly. The parking access extension in + this case is treated like a dialplan hint. + + ParkedCall diff --git a/res/res_parking.c b/res/res_parking.c index 02740da61ba..727afd27d58 100644 --- a/res/res_parking.c +++ b/res/res_parking.c @@ -35,6 +35,38 @@ Options that apply to every parking lot Enables dynamically created parkinglots. + + If the option is enabled then the following variables can + be used to dynamically create new parking lots. + + The PARKINGDYNAMIC variable specifies the + parking lot to use as a template to create a dynamic parking lot. It + is an error to specify a non-existent parking lot for the template. + If not set then the default parking lot is used as the template. + + The PARKINGDYNCONTEXT variable specifies the + dialplan context to use for the newly created dynamic parking lot. If + not set then the context from the parking lot template is used. The + context is created if it does not already exist and the new parking lot + needs to create extensions. + + The PARKINGDYNEXTEN variable specifies the + parkext to use for the newly created dynamic + parking lot. If not set then the parkext is used from + the parking lot template. If the template does not specify a + parkext then no extensions are created for the newly + created parking lot. The dynamic parking lot cannot be created if it + needs to create extensions that overlap existing parking lot extensions. + The only exception to this is for the parkext + extension and only if neither of the overlaping parking lot's + parkext is exclusive. + + The PARKINGDYNPOS variable specifies the + parking positions to use for the newly created dynamic parking lot. If + not set then the parkpos from the parking lot template + is used. + + @@ -45,19 +77,35 @@ Extension to park calls to this parking lot. - If this option is used, this extension will automatically be created to place calls into - parking lots. In addition, if parkext_exclusive is set for this parking lot, the name of the parking lot - will be included in the application's arguments so that it only parks to this parking lot. The extension - will be created in context. Using this option also creates extensions for retrieving - parked calls from the parking spaces in the same context. + + If this option is used, this extension will automatically + be created to place calls into parking lots. In addition, if + parkext_exclusive is set for this parking + lot, the name of the parking lot will be included in the + application's arguments so that it only parks to this parking + lot. The extension will be created in context. + Using this option also creates extensions for retrieving + parked calls from the parking spaces in the same context. + + + Generated parking extensions cannot overlap. + The only exception is if neither overlapping + parkext is exclusive. + + + If yes, the extension registered as parkext will park exclusively to this parking lot. Numerical range of parking spaces which can be used to retrieve parked calls. - If parkext is set, these extensions will automatically be mapped in context - in order to pick up calls parked to these parking spaces. + + If parkext is set, these extensions + will automatically be mapped in context + in order to pick up calls parked to these parking spaces. + + If yes, this parking lot will add hints automatically for parking spaces. @@ -178,9 +226,6 @@ - - If set, the sound set will be played to whomever is set by parkedplay - From 13e75ee04fae19528be83093a7dc6bb4ff600aa2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 18 Mar 2016 14:01:02 -0500 Subject: [PATCH 0298/1578] res_parking: Misc fixes. res/parking/parking_applications.c: * Add malloc fail checks in setup_park_common_datastore(). * Fix playing parking failed announcement to only happen on non-blind transfers in park_app_exec(). It could never go out before because a test was provedly always false. res/parking/parking_bridge.c: * Fix NULL tolerance in generate_parked_user() because bridge_parking_push() can theoretically pass a NULL parker channel if the parker channel went away for some reason. * Clarify some weird code dealing with blind_transfer in bridge_parking_push(). res/parking/parking_bridge_features.c: * Made park_local_transfer() set BLINDTRANSFER on the Local;1 channel which will be bulk copied to the Local;2 channel on the subsequent ast_call(). The additional advantage is if the parker channel has the BLINDTRANSFER and ATTENDEDTRANSFER variables set they are now guaranteed to be overridden. res/parking/parking_manager.c: * Fix AMI Park action input range checking of the Timeout header in manager_park(). * Reduced locking scope to where needed in manager_park(). res/res_parking.c: * Fix some off nominal missing unlocks by eliminating the returns. Change-Id: Ib64945bc285acb05a306dc12e6f16854898915ca --- res/parking/parking_applications.c | 40 ++++++++++++++------------- res/parking/parking_bridge.c | 17 +++++------- res/parking/parking_bridge_features.c | 3 +- res/parking/parking_manager.c | 8 +++--- res/res_parking.c | 22 ++++----------- 5 files changed, 38 insertions(+), 52 deletions(-) diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c index 0a0ea3c4b82..bd72b85d510 100644 --- a/res/parking/parking_applications.c +++ b/res/parking/parking_applications.c @@ -339,16 +339,17 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p ast_datastore_free(datastore); return -1; } + datastore->data = park_datastore; - if (parker_uuid) { - park_datastore->parker_uuid = ast_strdup(parker_uuid); + park_datastore->parker_uuid = ast_strdup(parker_uuid); + if (!park_datastore->parker_uuid) { + ast_datastore_free(datastore); + return -1; } ast_channel_lock(parkee); - attended_transfer = pbx_builtin_getvar_helper(parkee, "ATTENDEDTRANSFER"); blind_transfer = pbx_builtin_getvar_helper(parkee, "BLINDTRANSFER"); - if (!ast_strlen_zero(attended_transfer)) { parker_dial_string = ast_strdupa(attended_transfer); } else if (!ast_strlen_zero(blind_transfer)) { @@ -356,7 +357,6 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p /* Ensure that attended_transfer is NULL and not an empty string. */ attended_transfer = NULL; } - ast_channel_unlock(parkee); if (!ast_strlen_zero(parker_dial_string)) { @@ -365,6 +365,10 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p parker_dial_string, attended_transfer ? "ATTENDEDTRANSFER" : "BLINDTRANSFER"); park_datastore->parker_dial_string = ast_strdup(parker_dial_string); + if (!park_datastore->parker_dial_string) { + ast_datastore_free(datastore); + return -1; + } } park_datastore->randomize = randomize; @@ -373,10 +377,13 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p if (comeback_override) { park_datastore->comeback_override = ast_strdup(comeback_override); + if (!park_datastore->comeback_override) { + ast_datastore_free(datastore); + return -1; + } } - datastore->data = park_datastore; ast_channel_lock(parkee); ast_channel_datastore_add(parkee, datastore); ast_channel_unlock(parkee); @@ -391,23 +398,23 @@ struct park_common_datastore *get_park_common_datastore_copy(struct ast_channel struct park_common_datastore *data_copy; SCOPED_CHANNELLOCK(lock, parkee); + if (!(datastore = ast_channel_datastore_find(parkee, &park_common_info, NULL))) { return NULL; } data = datastore->data; - if (!data) { - /* This data should always be populated if this datastore was appended to the channel */ - ast_assert(0); - } + /* This data should always be populated if this datastore was appended to the channel */ + ast_assert(data != NULL); data_copy = ast_calloc(1, sizeof(*data_copy)); if (!data_copy) { return NULL; } - if (!(data_copy->parker_uuid = ast_strdup(data->parker_uuid))) { + data_copy->parker_uuid = ast_strdup(data->parker_uuid); + if (!data_copy->parker_uuid) { park_common_datastore_free(data_copy); return NULL; } @@ -457,7 +464,6 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan if (!lot) { lot = parking_create_dynamic_lot(lot_name, parkee); } - if (!lot) { ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", lot_name); return NULL; @@ -504,7 +510,7 @@ static int park_app_exec(struct ast_channel *chan, const char *data) struct ast_bridge_features chan_features; int res; int silence_announcements = 0; - const char *transferer; + int blind_transfer; /* Answer the channel if needed */ if (ast_channel_state(chan) != AST_STATE_UP) { @@ -512,15 +518,12 @@ static int park_app_exec(struct ast_channel *chan, const char *data) } ast_channel_lock(chan); - if (!(transferer = pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER"))) { - transferer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); - } - transferer = ast_strdupa(S_OR(transferer, "")); + blind_transfer = !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")); ast_channel_unlock(chan); /* Handle the common parking setup stuff */ if (!(parking_bridge = park_application_setup(chan, NULL, data, &silence_announcements))) { - if (!silence_announcements && !transferer) { + if (!silence_announcements && !blind_transfer) { ast_stream_and_wait(chan, "pbx-parkingfailed", ""); } publish_parked_call_failure(chan); @@ -593,7 +596,6 @@ static int parked_call_app_exec(struct ast_channel *chan, const char *data) } lot = parking_lot_find_by_name(lot_name); - if (!lot) { ast_log(LOG_ERROR, "Could not find the requested parking lot\n"); ast_stream_and_wait(chan, "pbx-invalidpark", ""); diff --git a/res/parking/parking_bridge.c b/res/parking/parking_bridge.c index 4f7198b4fad..e61486e3ccb 100644 --- a/res/parking/parking_bridge.c +++ b/res/parking/parking_bridge.c @@ -167,7 +167,7 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct if (parker_dial_string) { new_parked_user->parker_dial_string = ast_strdup(parker_dial_string); } else { - if (parked_user_set_parker_dial_string(new_parked_user, parker)) { + if (!parker || parked_user_set_parker_dial_string(new_parked_user, parker)) { ao2_ref(new_parked_user, -1); ao2_unlock(lot); return NULL; @@ -269,14 +269,11 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg * the park application. It's possible that the channel that transferred it is still alive (particularly * when a multichannel bridge is parked), so try to get the real parker if possible. */ ast_channel_lock(bridge_channel->chan); - blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"), - ast_channel_name(bridge_channel->chan)); - if (blind_transfer) { - blind_transfer = ast_strdupa(blind_transfer); - } + blind_transfer = pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"); + blind_transfer = ast_strdupa(S_OR(blind_transfer, "")); ast_channel_unlock(bridge_channel->chan); - - if (parker == bridge_channel->chan) { + if ((!parker || parker == bridge_channel->chan) + && !ast_strlen_zero(blind_transfer)) { struct ast_channel *real_parker = ast_channel_get_by_name(blind_transfer); if (real_parker) { @@ -300,8 +297,8 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg /* Generate ParkedCall Stasis Message */ publish_parked_call(pu, PARKED_CALL); - /* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */ - if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !park_datastore->silence_announce) { + /* If not a blind transfer and silence_announce isn't set, play the announcement to the parkee */ + if (ast_strlen_zero(blind_transfer) && !park_datastore->silence_announce) { char saynum_buf[16]; snprintf(saynum_buf, sizeof(saynum_buf), "%d %d", 0, pu->parking_space); diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 4cb87c81a73..70c2fc6db02 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -238,6 +238,7 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const ast_channel_req_accountcodes(parkee, parker, AST_CHANNEL_REQUESTOR_REPLACEMENT); ast_connected_line_copy_from_caller(ast_channel_connected(parkee), ast_channel_caller(parker)); ast_channel_inherit_variables(parker, parkee); + ast_bridge_set_transfer_variables(parkee, ast_channel_name(parker), 0); ast_channel_datastore_inherit(parker, parkee); ast_channel_unlock(parker); @@ -252,8 +253,6 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const return NULL; } - ast_bridge_set_transfer_variables(parkee_side_2, ast_channel_name(parker), 0); - ast_channel_unref(parkee_side_2); /* Since the above worked fine now we actually call it and return the channel */ diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c index a560151ab25..89f553d9cfe 100644 --- a/res/parking/parking_manager.c +++ b/res/parking/parking_manager.c @@ -537,12 +537,12 @@ static int manager_park(struct mansession *s, const struct message *m) } if (!ast_strlen_zero(timeout)) { - if (sscanf(timeout, "%30d", &timeout_override) != 1 || timeout < 0) { + if (sscanf(timeout, "%30d", &timeout_override) != 1 || timeout_override < 0) { astman_send_error(s, m, "Invalid Timeout value."); return 0; } - if (timeout_override > 0) { + if (timeout_override) { /* If greater than zero, convert to seconds for internal use. Must be >= 1 second. */ timeout_override = MAX(1, timeout_override / 1000); } @@ -554,11 +554,11 @@ static int manager_park(struct mansession *s, const struct message *m) return 0; } - ast_channel_lock(chan); if (!ast_strlen_zero(timeout_channel)) { + ast_channel_lock(chan); ast_bridge_set_transfer_variables(chan, timeout_channel, 0); + ast_channel_unlock(chan); } - ast_channel_unlock(chan); parker_chan = ast_channel_bridge_peer(chan); if (!parker_chan || strcmp(ast_channel_name(parker_chan), timeout_channel)) { diff --git a/res/res_parking.c b/res/res_parking.c index 02740da61ba..26f08e414fd 100644 --- a/res/res_parking.c +++ b/res/res_parking.c @@ -738,31 +738,21 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg) } /* We need the contexts list locked to safely be able to both read and lock the specific context within */ - if (ast_wrlock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock the contexts list.\n"); - return -1; - } + ast_wrlock_contexts(); if (!(lot_context = ast_context_find_or_create(NULL, NULL, lot_cfg->parking_con, parkext_registrar_pointer))) { ast_log(LOG_ERROR, "Parking lot '%s' -- Needs a context '%s' which does not exist and Asterisk was unable to create\n", lot_cfg->name, lot_cfg->parking_con); - if (ast_unlock_contexts()) { - ast_assert(0); - } + ast_unlock_contexts(); return -1; } /* Once we know what context we will be modifying, we need to write lock it because we will be reading extensions * and we don't want something else to destroy them while we are looking at them. */ - if (ast_wrlock_context(lot_context)) { - ast_log(LOG_ERROR, "failed to obtain write lock on context\n"); - return -1; - } + ast_wrlock_context(lot_context); - if (ast_unlock_contexts()) { - ast_assert(0); - } + ast_unlock_contexts(); /* Handle generation/confirmation for the Park extension */ if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->parking_con, lot_cfg->parkext, 1, NULL, NULL, E_MATCH))) { @@ -830,9 +820,7 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg) } } - if (ast_unlock_context(lot_context)) { - ast_assert(0); - } + ast_unlock_context(lot_context); return 0; } From 3cf714031c51af0f2c21166bb9d161b144f5723c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 23 Mar 2016 14:24:49 -0500 Subject: [PATCH 0299/1578] res_parking: Cleanup find_channel_parking_lot_name() usage. Change-Id: I8f7a8890aef27824301c642d4d15407ac83e6f02 --- res/parking/parking_applications.c | 2 +- res/parking/parking_bridge_features.c | 11 ++--------- res/parking/res_parking.h | 5 +++-- res/res_parking.c | 13 ++++++------- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c index 0a0ea3c4b82..df1eb7adad7 100644 --- a/res/parking/parking_applications.c +++ b/res/parking/parking_applications.c @@ -567,7 +567,7 @@ static int parked_call_app_exec(struct ast_channel *chan, const char *data) int target_space = -1; struct ast_bridge_features chan_features; char *parse; - char *lot_name; + const char *lot_name; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(lot_name); diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 4cb87c81a73..4d1416eb84a 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -474,19 +474,12 @@ static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel static int parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length) { RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup); - const char *lot_name = NULL; + const char *lot_name; ast_channel_lock(parker->chan); - lot_name = find_channel_parking_lot_name(parker->chan); - if (!ast_strlen_zero(lot_name)) { - lot_name = ast_strdupa(lot_name); - } + lot_name = ast_strdupa(find_channel_parking_lot_name(parker->chan)); ast_channel_unlock(parker->chan); - if (ast_strlen_zero(lot_name)) { - return -1; - } - lot = parking_lot_find_by_name(lot_name); if (!lot) { ast_log(AST_LOG_WARNING, "Cannot Park %s: lot %s unknown\n", diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h index 2c4a18055e6..f4ef2ea0968 100644 --- a/res/parking/res_parking.h +++ b/res/parking/res_parking.h @@ -308,8 +308,9 @@ struct parking_lot *parking_create_dynamic_lot_forced(const char *name, struct a * * \param chan The channel we want the parking lot name for * - * \retval name of the channel's assigned parking lot if it is defined by the channel in some way - * \retval name of the default parking lot if it is not + * \return name of the parking lot to use for the channel. + * + * \note Always returns a parking lot name. * * \note Channel needs to be locked while the returned string is in use. */ diff --git a/res/res_parking.c b/res/res_parking.c index 02740da61ba..68a0e7d5c0d 100644 --- a/res/res_parking.c +++ b/res/res_parking.c @@ -568,14 +568,13 @@ const char *find_channel_parking_lot_name(struct ast_channel *chan) /* The channel variable overrides everything */ name = pbx_builtin_getvar_helper(chan, "PARKINGLOT"); - if (ast_strlen_zero(name) && !ast_strlen_zero(ast_channel_parkinglot(chan))) { - /* Use the channel's parking lot. */ - name = ast_channel_parkinglot(chan); - } - - /* If the name couldn't be pulled from that either, use the default parking lot name. */ if (ast_strlen_zero(name)) { - name = DEFAULT_PARKING_LOT; + /* Try the channel's parking lot. */ + name = ast_channel_parkinglot(chan); + if (ast_strlen_zero(name)) { + /* Fall back to the default parking lot. */ + name = DEFAULT_PARKING_LOT; + } } return name; From 8e8cf80cea37effcfdc8c82429341f33721a2ee8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 25 Mar 2016 23:19:22 -0500 Subject: [PATCH 0300/1578] res_parking: Fix blind transfer dynamic lots creation. Blind transfers to a recognized parking extension need to use the parker's channel variable values to create the dynamic parking lot. This is because there is always only one parker while the parkee may actually be a multi-party bridge. A multi-party bridge can never supply the needed channel variables to create the dynamic parking lot. In the multi-party bridge blind transfer scenario, the parker's CHANNEL(parkinglot) value and channel variables are inherited by the local channel used to park the bridge. * In park_common_setup(), make use the parker instead of the parkee to supply the dynamic parking lot channel variable values. In all but one case, the parkee is the same as the parker. However, in the recognized parking extension blind transfer scenario for a two party bridge they are different channels. For consistency, we need to use the parker channel. * In park_local_transfer(), pass the CHANNEL(parkinglot) value to the local channel when blind transferring a multi-party bridge to a recognized parking extension. * When a local channel starts a call, the Local;2 side needs to inherit the CHANNEL(parkinglot) value from Local;1. The DTMF one-touch parking case wasn't even trying to create dynamic parking lots before it aborted the attempt. * In parking_park_call(), add missing code to create a dynamic parking lot. A DTMF bridge hook is documented as returning -1 to remove the hook. Though the hook caller is really coded to accept non-zero. See the ast_bridge_hook_callback typedef. * In feature_park_call(), don't remove the DTMF one-touch parking hook because of an error. ASTERISK-24605 #close Reported by: Philip Correia Patches: call_park.patch (license #6672) patch uploaded by Philip Correia Change-Id: I221d3a8fcc181877a1158d17004474d35d8016c9 --- CHANGES | 14 ++++++++++++++ main/core_unreal.c | 4 ++-- res/parking/parking_applications.c | 2 +- res/parking/parking_bridge_features.c | 7 ++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index da516efdc2a..4b607b7a2df 100644 --- a/CHANGES +++ b/CHANGES @@ -250,6 +250,20 @@ Queue 'queue show'. +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 13.8.0 to Asterisk 13.9.0 ------------ +------------------------------------------------------------------------------ + +res_parking: + - The dynamic parking lot creation channel variables PARKINGDYNAMIC, + PARKINGDYNCONTEXT, PARKINGDYNEXTEN, and PARKINGDYNPOS are now looked + for in the parker's channel instead of the parked channel. This is only + of significance if the parker uses blind transfer or the DTMF one-step + parking feature. You need to use the double underscore '__' inheritance + for these variables. The indefinite inheritance is also recommended + for the PARKINGEXTEN variable. + + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ ------------------------------------------------------------------------------ diff --git a/main/core_unreal.c b/main/core_unreal.c index 19f2d1f6516..da0bb43bba6 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -687,13 +687,13 @@ void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2) ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1)); ast_channel_language_set(semi2, ast_channel_language(semi1)); + ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1)); + ast_channel_parkinglot_set(semi2, ast_channel_parkinglot(semi1)); /* Crossover the accountcode and peeraccount to cross the unreal bridge. */ ast_channel_accountcode_set(semi2, ast_channel_peeraccount(semi1)); ast_channel_peeraccount_set(semi2, ast_channel_accountcode(semi1)); - ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1)); - ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1)); /* diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c index 0a0ea3c4b82..7dd53599154 100644 --- a/res/parking/parking_applications.c +++ b/res/parking/parking_applications.c @@ -455,7 +455,7 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan lot = parking_lot_find_by_name(lot_name); if (!lot) { - lot = parking_create_dynamic_lot(lot_name, parkee); + lot = parking_create_dynamic_lot(lot_name, parker); } if (!lot) { diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 4cb87c81a73..5fe57642458 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -236,6 +236,7 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const /* Before we actually dial out let's inherit appropriate information. */ ast_channel_lock_both(parker, parkee); ast_channel_req_accountcodes(parkee, parker, AST_CHANNEL_REQUESTOR_REPLACEMENT); + ast_channel_parkinglot_set(parkee, ast_channel_parkinglot(parker)); ast_connected_line_copy_from_caller(ast_channel_connected(parkee), ast_channel_caller(parker)); ast_channel_inherit_variables(parker, parkee); ast_channel_datastore_inherit(parker, parkee); @@ -488,6 +489,9 @@ static int parking_park_call(struct ast_bridge_channel *parker, char *exten, siz } lot = parking_lot_find_by_name(lot_name); + if (!lot) { + lot = parking_create_dynamic_lot(lot_name, parker->chan); + } if (!lot) { ast_log(AST_LOG_WARNING, "Cannot Park %s: lot %s unknown\n", ast_channel_name(parker->chan), lot_name); @@ -504,7 +508,8 @@ static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *ho { SCOPED_MODULE_USE(AST_MODULE_SELF); - return parking_park_call(bridge_channel, NULL, 0); + parking_park_call(bridge_channel, NULL, 0); + return 0; } /*! From c948ce96512b7948595c9416e6739e0526686529 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 8 Mar 2016 14:55:30 -0700 Subject: [PATCH 0301/1578] sorcery/res_pjsip: Refactor for realtime performance There were a number of places in the res_pjsip stack that were getting all endpoints or all aors, and then filtering them locally. A good example is pjsip_options which, on startup, retrieves all endpoints, then the aors for those endpoints, then tests the aors to see if the qualify_frequency is > 0. One issue was that it never did anything with the endpoints other than retrieve the aors so we probably could have skipped a step and just retrieved all aors. But nevermind. This worked reasonably well with local config files but with a realtime backend and thousands of objects, this was a nightmare. The issue really boiled down to the fact that while realtime supports predicates that are passed to the database engine, the non-realtime sorcery backends didn't. They do now. The realtime engines have a scheme for doing simple comparisons. They take in an ast_variable (or list) for matching, and the name of each variable can contain an operator. For instance, a name of "qualify_frequency >" and a value of "0" would create a SQL predicate that looks like "where qualify_frequency > '0'". If there's no operator after the name, the engines add an '=' so a simple name of "qualify_frequency" and a value of "10" would return exact matches. The non-realtime backends decide whether to include an object in a result set by calling ast_sorcery_changeset_create on every object in the internal container. However, ast_sorcery_changeset_create only does exact string matches though so a name of "qualify_frequency >" and a value of "0" returns nothing because the literal "qualify_frequency >" doesn't match any name in the objset set. So, the real task was to create a generic string matcher that can take a left value, operator and a right value and perform the match. To that end, strings.c has a new ast_strings_match(left, operator, right) function. Left and right are the strings to operate on and the operator can be a string containing any of the following: = (or NULL or ""), !=, >, >=, <, <=, like or regex. If the operator is like or regex, the right string should be a %-pattern or a regex expression. If both left and right can be converted to float, then a numeric comparison is performed, otherwise a string comparison is performed. To use this new function on ast_variables, 2 new functions were added to config.c. One that compares 2 ast_variables, and one that compares 2 ast_variable lists. The former is useful when you want to compare 2 ast_variables that happen to be in a list but don't want to traverse the list. The latter will traverse the right list and return true if all the variables in it match the left list. Now, the backends' fields_cmp functions call ast_variable_lists_match instead of ast_sorcery_changeset_create and they can now process the same syntax as the realtime engines. The realtime backend just passes the variable list unaltered to the engine. The only gotcha is that there's no common realtime engine support for regex so that's been noted in the api docs for ast_sorcery_retrieve_by_fields. Only one more change to sorcery was done... A new config flag "allow_unqualified_fetch" was added to reg_sorcery_realtime. "no": ignore fetches if no predicate fields were supplied. "error": same as no but emit an error. (good for testing) "yes": allow (the default); "warn": allow but emit a warning. (good for testing) Now on to res_pjsip... pjsip_options was modified to retrieve aors with qualify_frequency > 0 rather than all endpoints then all aors. Not only was this a big improvement in realtime retrieval but even for config files there's an improvement because we're not going through endpoints anymore. res_pjsip_mwi was modified to retieve only endpoints with something in the mailboxes field instead of all endpoints then testing mailboxes. res_pjsip_registrar_expire was completely refactored. It was retrieving all contacts then setting up scheduler entries to check for expiration. Now, it's a single thread (like keepalive) that periodically retrieves only contacts whose expiration time is < now and deletes them. A new contact_expiration_check_interval was added to global with a default of 30 seconds. Ross Beer reports that with this patch, his Asterisk startup time dropped from around an hour to under 30 seconds. There are still objects that can't be filtered at the database like identifies, transports, and registrations. These are not going to be anywhere near as numerous as endpoints, aors, auths, contacts however. Back to allow_unqualified_fetch. If this is set to yes and you have a very large number of objects in the database, the pjsip CLI commands will attempt to retrive ALL of them if not qualified with a LIKE. Worse, if you type "pjsip show endpoint " guess what's going to happen? :) Having a cache helps but all the objects will have to be retrieved at least once to fill the cache. Setting allow_unqualified_fetch=no prevents the mass retrieve and should be used on endpoints, auths, aors, and contacts. It should NOT be used for identifies, registrations and transports since these MUST be retrieved in bulk. Example sorcery.conf: [res_pjsip] endpoint=config,pjsip.conf,criteria=type=endpoint endpoint=realtime,ps_endpoints,allow_unqualified_fetch=error ASTERISK-25826 #close Reported-by: Ross Beer Tested-by: Ross Beer Change-Id: Id2691e447db90892890036e663aaf907b2dc1c67 --- configs/samples/pjsip.conf.sample | 2 + ..._add_contact_expiration_check_interval_.py | 21 ++ include/asterisk/config.h | 81 ++++- include/asterisk/res_pjsip.h | 8 + include/asterisk/sorcery.h | 24 ++ include/asterisk/strings.h | 30 ++ main/config.c | 90 ++++++ main/strings.c | 127 ++++++++ res/res_pjsip.c | 3 + res/res_pjsip/config_global.c | 21 ++ res/res_pjsip/pjsip_options.c | 47 ++- res/res_pjsip_mwi.c | 7 +- res/res_pjsip_registrar_expire.c | 277 ++++-------------- res/res_sorcery_astdb.c | 91 ++---- res/res_sorcery_config.c | 9 +- res/res_sorcery_memory.c | 4 +- res/res_sorcery_memory_cache.c | 3 +- res/res_sorcery_realtime.c | 111 +++++-- tests/test_config.c | 62 ++++ tests/test_sorcery_astdb.c | 4 +- tests/test_sorcery_realtime.c | 212 ++++++++++---- tests/test_strings.c | 64 ++++ 22 files changed, 877 insertions(+), 421 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 2d127a1dcd7..faa92859811 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -894,6 +894,8 @@ ;keep_alive_interval=20 ; The interval (in seconds) at which to send keepalive ; messages on all active connection-oriented transports ; (default: "0") +;contact_expiration_check_interval=30 + ; The interval (in seconds) to check for expired contacts. ;endpoint_identifier_order=ip,username,anonymous ; The order by which endpoint identifiers are given priority. ; Identifier names are derived from res_pjsip_endpoint_identifier_* diff --git a/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py b/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py new file mode 100644 index 00000000000..2c61f2b9dc8 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py @@ -0,0 +1,21 @@ +"""Add contact_expiration_check_interval to ps_globals + +Revision ID: 5813202e92be +Revises: 3bcc0b5bc2c9 +Create Date: 2016-03-08 21:52:21.372310 + +""" + +# revision identifiers, used by Alembic. +revision = '5813202e92be' +down_revision = '3bcc0b5bc2c9' + +from alembic import op +import sqlalchemy as sa + +def upgrade(): + op.add_column('ps_globals', sa.Column('contact_expiration_check_interval', sa.Integer)) + +def downgrade(): + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('contact_expiration_check_interval') diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 9a899d8d06d..287635a8e05 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -307,7 +307,7 @@ const char *ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable); /*! - * \brief Gets a variable from a specific category structure + * \brief Gets a variable value from a specific category structure by name * * \param category category structure under which the variable lies * \param variable which variable you wish to get the data for @@ -321,7 +321,7 @@ const char *ast_variable_retrieve(struct ast_config *config, const char *ast_variable_find(const struct ast_category *category, const char *variable); /*! - * \brief Gets a variable from a variable list + * \brief Gets the value of a variable from a variable list by name * * \param list variable list to search * \param variable which variable you wish to get the data for @@ -335,7 +335,7 @@ const char *ast_variable_find(const struct ast_category *category, const char *v const char *ast_variable_find_in_list(const struct ast_variable *list, const char *variable); /*! - * \brief Gets the LAST occurrence of a variable from a variable list + * \brief Gets the value of the LAST occurrence of a variable from a variable list * * \param list The ast_variable list to search * \param variable The name of the ast_variable you wish to fetch data for @@ -351,6 +351,21 @@ const char *ast_variable_find_in_list(const struct ast_variable *list, const cha */ const char *ast_variable_find_last_in_list(const struct ast_variable *list, const char *variable); +/*! + * \brief Gets a variable from a variable list by name + * \since 13.9.0 + * + * \param list variable list to search + * \param variable name you wish to get the data for + * + * \details + * Goes through a given variable list and searches for the given variable + * + * \retval The variable (not the value) on success + * \retval NULL if unable to find it. + */ +const struct ast_variable *ast_variable_find_variable_in_list(const struct ast_variable *list, const char *variable_name); + /*! * \brief Retrieve a category if it exists * @@ -1217,6 +1232,66 @@ char *ast_realtime_decode_chunk(char *chunk); */ char *ast_realtime_encode_chunk(struct ast_str **dest, ssize_t maxlen, const char *chunk); +/*! + * \brief Tests 2 variable values to see if they match + * \since 13.9.0 + * + * \param left Variable to test + * \param right Variable to match against with an optional realtime-style operator in the name + * + * \retval 1 matches + * \retval 0 doesn't match + * + * \details + * + * The values of the variables are passed to ast_strings_match. + * If right->name is suffixed with a space and an operator, that operator + * is also passed to ast_strings_match. + * + * Examples: + * + * left->name = "id" (ignored) + * left->value = "abc" + * right->name = "id regex" (id is ignored) + * right->value = "a[bdef]c" + * + * will result in ast_strings_match("abc", "regex", "a[bdef]c") which will return 1. + * + * left->name = "id" (ignored) + * left->value = "abc" + * right->name = "id" (ignored) + * right->value = "abc" + * + * will result in ast_strings_match("abc", NULL, "abc") which will return 1. + * + * See the documentation for ast_strings_match for the valid operators. + */ +int ast_variables_match(const struct ast_variable *left, const struct ast_variable *right); + +/*! + * \brief Tests 2 variable lists to see if they match + * \since 13.9.0 + * + * \param left Variable list to test + * \param right Variable list with an optional realtime-style operator in the names + * \param exact_match If true, all variables in left must match all variables in right + * and vice versa. This does exact value matches only. Operators aren't supported. + * Except for order, the left and right lists must be equal. + * + * If false, every variable in the right list must match some variable in the left list + * using the operators supplied. Variables in the left list that aren't in the right + * list are ignored for matching purposes. + * + * \retval 1 matches + * \retval 0 doesn't match + * + * \details + * Iterates over the variable lists calling ast_variables_match. If any match fails + * or a variable in the right list isn't in the left list, 0 is returned. + */ +int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, + int exact_match); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 66370186a0a..b0ae2cefaf7 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2146,6 +2146,14 @@ void ast_sip_get_default_from_user(char *from_user, size_t size); */ unsigned int ast_sip_get_keep_alive_interval(void); +/*! + * \brief Retrieve the system contact expiration check interval setting. + * + * \retval the contact expiration check interval. + */ +unsigned int ast_sip_get_contact_expiration_check_interval(void); + + /*! * \brief Retrieve the system max initial qualify time. * diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h index d681ebb5abf..42ecc133ff5 100644 --- a/include/asterisk/sorcery.h +++ b/include/asterisk/sorcery.h @@ -1151,6 +1151,7 @@ void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char * /*! * \brief Retrieve an object or multiple objects using specific fields + * \since 13.9.0 * * \param sorcery Pointer to a sorcery structure * \param type Type of object to retrieve @@ -1165,6 +1166,29 @@ void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char * * * \note If the AST_RETRIEVE_FLAG_ALL flag is used you may omit fields to retrieve all objects * of the given type. + * + * \note The fields parameter can contain realtime-style expressions in variable->name. + * All operators defined for ast_strings_match can be used except for regex as + * there's no common support for regex in the realtime backends at this time. + * If multiple variables are in the fields list, all must match for an object to + * be returned. See ast_strings_match for more information. + * + * Example: + * + * The following code can be significantly faster when a realtime backend is in use + * because the expression "qualify_frequency > 0" is passed to the database to limit + * the number of rows returned. + * + * struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); + * struct ao2_container *aors; + * + * if (!var) { + * return; + * } + * + * aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + * "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); + * */ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields); diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 3701b530593..0e2f69ba892 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -1335,4 +1335,34 @@ void ast_str_container_remove(struct ao2_container *str_container, const char *r * \return A pointer to buf */ char *ast_generate_random_string(char *buf, size_t size); + +/*! + * \brief Compares 2 strings using realtime-style operators + * \since 13.9.0 + * + * \param left The left side of the equation + * \param op The operator to apply + * \param right The right side of the equation + * + * \retval 1 matches + * \retval 0 doesn't match + * + * \details + * + * Operators: + * "=", "!=", "<", "<=", ">", ">=": + * If both left and right can be converted to float, then they will be + * compared as such. Otherwise the result will be derived from strcmp(left, right). + * "regex": + * The right value will be compiled as a regular expression and matched against the left + * value. + * "like": + * Any '%' character in the right value will be converted to '.*' and the resulting + * string will be handled as a regex. + * NULL , "": + * If the right value starts and ends with a '/' then it will be processed as a regex. + * Otherwise, same as "=". + */ +int ast_strings_match(const char *left, const char *op, const char *right); + #endif /* _ASTERISK_STRINGS_H */ diff --git a/main/config.c b/main/config.c index 04e9367b767..a9ea01a8b14 100644 --- a/main/config.c +++ b/main/config.c @@ -723,6 +723,96 @@ const char *ast_variable_find(const struct ast_category *category, const char *v return ast_variable_find_in_list(category->root, variable); } +const struct ast_variable *ast_variable_find_variable_in_list(const struct ast_variable *list, const char *variable_name) +{ + const struct ast_variable *v; + + for (v = list; v; v = v->next) { + if (!strcasecmp(variable_name, v->name)) { + return v; + } + } + return NULL; +} + +int ast_variables_match(const struct ast_variable *left, const struct ast_variable *right) +{ + char *op; + + if (left == right) { + return 1; + } + + if (!(left && right)) { + return 0; + } + + op = strrchr(right->name, ' '); + if (op) { + op++; + } + + return ast_strings_match(left->value, op ? ast_strdupa(op) : NULL, right->value); +} + +int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match) +{ + const struct ast_variable *field; + int right_count = 0; + int left_count = 0; + + if (left == right) { + return 1; + } + + if (!(left && right)) { + return 0; + } + + for (field = right; field; field = field->next) { + char *space = strrchr(field->name, ' '); + const struct ast_variable *old; + char * name = (char *)field->name; + + if (space) { + name = ast_strdup(field->name); + if (!name) { + return 0; + } + name[space - field->name] = '\0'; + } + + old = ast_variable_find_variable_in_list(left, name); + if (name != field->name) { + ast_free(name); + } + + if (exact_match) { + if (!old || strcmp(old->value, field->value)) { + return 0; + } + } else { + if (!ast_variables_match(old, field)) { + return 0; + } + } + + right_count++; + } + + if (exact_match) { + for (field = left; field; field = field->next) { + left_count++; + } + + if (right_count != left_count) { + return 0; + } + } + + return 1; +} + const char *ast_variable_find_in_list(const struct ast_variable *list, const char *variable) { const struct ast_variable *v; diff --git a/main/strings.c b/main/strings.c index 495011ec5cd..f828727ad84 100644 --- a/main/strings.c +++ b/main/strings.c @@ -39,6 +39,7 @@ ASTERISK_REGISTER_FILE() +#include #include "asterisk/strings.h" #include "asterisk/pbx.h" @@ -228,3 +229,129 @@ char *ast_generate_random_string(char *buf, size_t size) return buf; } + +int ast_strings_match(const char *left, const char *op, const char *right) +{ + char *internal_op = (char *)op; + char *internal_right = (char *)right; + float left_num; + float right_num; + int scan_numeric = 0; + + if (!(left && right)) { + return 0; + } + + if (ast_strlen_zero(op)) { + if (ast_strlen_zero(left) && ast_strlen_zero(right)) { + return 1; + } + + if (strlen(right) >= 2 && right[0] == '/' && right[strlen(right) - 1] == '/') { + internal_op = "regex"; + internal_right = ast_strdupa(right); + /* strip the leading and trailing '/' */ + internal_right++; + internal_right[strlen(internal_right) - 1] = '\0'; + goto regex; + } else { + internal_op = "="; + goto equals; + } + } + + if (!strcasecmp(op, "like")) { + char *tok; + struct ast_str *buffer = ast_str_alloca(128); + + if (!strchr(right, '%')) { + return !strcmp(left, right); + } else { + internal_op = "regex"; + internal_right = ast_strdupa(right); + tok = strsep(&internal_right, "%"); + ast_str_set(&buffer, 0, "^%s", tok); + + while ((tok = strsep(&internal_right, "%"))) { + ast_str_append(&buffer, 0, ".*%s", tok); + } + ast_str_append(&buffer, 0, "%s", "$"); + + internal_right = ast_str_buffer(buffer); + /* fall through to regex */ + } + } + +regex: + if (!strcasecmp(internal_op, "regex")) { + regex_t expression; + int rc; + + if (regcomp(&expression, internal_right, REG_EXTENDED | REG_NOSUB)) { + return 0; + } + + rc = regexec(&expression, left, 0, NULL, 0); + regfree(&expression); + return !rc; + } + +equals: + scan_numeric = (sscanf(left, "%f", &left_num) && sscanf(internal_right, "%f", &right_num)); + + if (internal_op[0] == '=') { + if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) { + return 1; + } + + if (scan_numeric) { + return (left_num == right_num); + } else { + return (!strcmp(left, internal_right)); + } + } + + if (internal_op[0] == '!' && internal_op[1] == '=') { + if (scan_numeric) { + return (left_num != right_num); + } else { + return !!strcmp(left, internal_right); + } + } + + if (internal_op[0] == '<') { + if (scan_numeric) { + if (internal_op[1] == '=') { + return (left_num <= right_num); + } else { + return (left_num < right_num); + } + } else { + if (internal_op[1] == '=') { + return strcmp(left, internal_right) <= 0; + } else { + return strcmp(left, internal_right) < 0; + } + } + } + + if (internal_op[0] == '>') { + if (scan_numeric) { + if (internal_op[1] == '=') { + return (left_num >= right_num); + } else { + return (left_num > right_num); + } + } else { + if (internal_op[1] == '=') { + return strcmp(left, internal_right) >= 0; + } else { + return strcmp(left, internal_right) > 0; + } + } + } + + return 0; +} + + diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 170a19151a7..67d8dce3845 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1282,6 +1282,9 @@ The interval (in seconds) to send keepalives to active connection-oriented transports. + + The interval (in seconds) to check for expired contacts. + The maximum amount of time from startup that qualifies should be attempted on all contacts. If greater than the qualify_frequency for an aor, qualify_frequency will be used instead. diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index 3d88ffc2a9a..c0fede64d68 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -36,6 +36,7 @@ #define DEFAULT_MAX_INITIAL_QUALIFY_TIME 0 #define DEFAULT_FROM_USER "asterisk" #define DEFAULT_REGCONTEXT "" +#define DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL 30 static char default_useragent[256]; @@ -58,6 +59,8 @@ struct global_config { unsigned int keep_alive_interval; /* The maximum time for all contacts to be qualified at startup */ unsigned int max_initial_qualify_time; + /* The interval at which to check for expired contacts */ + unsigned int contact_expiration_check_interval; }; static void global_destructor(void *obj) @@ -186,6 +189,21 @@ unsigned int ast_sip_get_keep_alive_interval(void) return interval; } +unsigned int ast_sip_get_contact_expiration_check_interval(void) +{ + unsigned int interval; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL; + } + + interval = cfg->contact_expiration_check_interval; + ao2_ref(cfg, -1); + return interval; +} + unsigned int ast_sip_get_max_initial_qualify_time(void) { unsigned int time; @@ -331,6 +349,9 @@ int ast_sip_initialize_sorcery_global(void) OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_from_user)); ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); + ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval", + __stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL), + OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 4cce5583678..4713dbb0dd6 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1078,31 +1078,13 @@ static int qualify_and_schedule_cb(void *obj, void *arg, int flags) */ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) { - struct ast_sip_endpoint *endpoint = obj; - char *aors; - char *aor_name; - - if (ast_strlen_zero(endpoint->aors)) { - return 0; - } - - aors = ast_strdupa(endpoint->aors); - while ((aor_name = ast_strip(strsep(&aors, ",")))) { - struct ast_sip_aor *aor; - struct ao2_container *contacts; - - aor = ast_sip_location_retrieve_aor(aor_name); - if (!aor) { - continue; - } - - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); - ao2_ref(contacts, -1); - } + struct ast_sip_aor *aor = obj; + struct ao2_container *contacts; - ao2_ref(aor, -1); + contacts = ast_sip_location_retrieve_aor_contacts(aor); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); + ao2_ref(contacts, -1); } return 0; @@ -1123,16 +1105,25 @@ static int unschedule_all_cb(void *obj, void *arg, int flags) static void qualify_and_schedule_all(void) { - struct ao2_container *endpoints = ast_sip_get_endpoints(); + struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); + struct ao2_container *aors; + + if (!var) { + return; + } + aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); + + ast_variables_destroy(var); ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); - if (!endpoints) { + if (!aors) { return; } - ao2_callback(endpoints, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); - ao2_ref(endpoints, -1); + ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); + ao2_ref(aors, -1); } static int format_contact_status(void *obj, void *arg, int flags) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index c9d1b743e5d..be38b44c1fc 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -966,9 +966,14 @@ static int unsubscribe(void *obj, void *arg, int flags) static void create_mwi_subscriptions(void) { struct ao2_container *endpoints; + struct ast_variable *var; + + var = ast_variable_new("mailboxes !=", "", ""); endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "endpoint", - AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + AST_RETRIEVE_FLAG_MULTIPLE, var); + + ast_variables_destroy(var); if (!endpoints) { return; } diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c index 399e7bd0ed5..87edf5390c7 100644 --- a/res/res_pjsip_registrar_expire.c +++ b/res/res_pjsip_registrar_expire.c @@ -25,265 +25,102 @@ #include "asterisk.h" #include +#include +#include #include "asterisk/res_pjsip.h" #include "asterisk/module.h" -#include "asterisk/sched.h" -#define CONTACT_AUTOEXPIRE_BUCKETS 977 +/*! \brief Thread keeping things alive */ +static pthread_t check_thread = AST_PTHREADT_NULL; -static struct ao2_container *contact_autoexpire; +/*! \brief The global interval at which to check for contact expiration */ +static unsigned int check_interval; -/*! \brief Scheduler used for automatically expiring contacts */ -static struct ast_sched_context *sched; - -/*! \brief Structure used for contact auto-expiration */ -struct contact_expiration { - /*! \brief Contact that is being auto-expired */ - struct ast_sip_contact *contact; - - /*! \brief Scheduled item for performing expiration */ - int sched; -}; - -/*! \brief Destructor function for contact auto-expiration */ -static void contact_expiration_destroy(void *obj) -{ - struct contact_expiration *expiration = obj; - - ao2_cleanup(expiration->contact); -} - -/*! \brief Hashing function for contact auto-expiration */ -static int contact_expiration_hash(const void *obj, const int flags) +/*! \brief Callback function which deletes a contact */ +static int expire_contact(void *obj, void *arg, int flags) { - const struct contact_expiration *object; - const char *key; - - switch (flags & OBJ_SEARCH_MASK) { - case OBJ_SEARCH_KEY: - key = obj; - break; - case OBJ_SEARCH_OBJECT: - object = obj; - key = ast_sorcery_object_get_id(object->contact); - break; - default: - /* Hash can only work on something with a full key. */ - ast_assert(0); - return 0; - } - return ast_str_hash(key); -} - -/*! \brief Comparison function for contact auto-expiration */ -static int contact_expiration_cmp(void *obj, void *arg, int flags) -{ - const struct contact_expiration *object_left = obj; - const struct contact_expiration *object_right = arg; - const char *right_key = arg; - int cmp; - - switch (flags & OBJ_SEARCH_MASK) { - case OBJ_SEARCH_OBJECT: - right_key = ast_sorcery_object_get_id(object_right->contact); - /* Fall through */ - case OBJ_SEARCH_KEY: - cmp = strcmp(ast_sorcery_object_get_id(object_left->contact), right_key); - break; - case OBJ_SEARCH_PARTIAL_KEY: - /* - * We could also use a partial key struct containing a length - * so strlen() does not get called for every comparison instead. - */ - cmp = strncmp(ast_sorcery_object_get_id(object_left->contact), right_key, - strlen(right_key)); - break; - default: - /* - * What arg points to is specific to this traversal callback - * and has no special meaning to astobj2. - */ - cmp = 0; - break; - } - if (cmp) { - return 0; - } - /* - * At this point the traversal callback is identical to a sorted - * container. - */ - return CMP_MATCH; -} - -/*! \brief Scheduler function which deletes a contact */ -static int contact_expiration_expire(const void *data) -{ - struct contact_expiration *expiration = (void *) data; + struct ast_sip_contact *contact = obj; - expiration->sched = -1; + ast_sorcery_delete(ast_sip_get_sorcery(), contact); - /* This will end up invoking the deleted observer callback, which will perform the unlinking and such */ - ast_sorcery_delete(ast_sip_get_sorcery(), expiration->contact); - ao2_ref(expiration, -1); return 0; } -/*! \brief Observer callback for when a contact is created */ -static void contact_expiration_observer_created(const void *object) +static void *check_expiration_thread(void *data) { - const struct ast_sip_contact *contact = object; - struct contact_expiration *expiration; - int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); + struct ao2_container *contacts; + struct ast_variable *var; + char *time = alloca(64); - if (ast_tvzero(contact->expiration_time)) { - return; - } + while (check_interval) { + sleep(check_interval); - expiration = ao2_alloc_options(sizeof(*expiration), contact_expiration_destroy, - AO2_ALLOC_OPT_LOCK_NOLOCK); - if (!expiration) { - return; - } + sprintf(time, "%ld", ast_tvnow().tv_sec); + var = ast_variable_new("expiration_time <=", time, ""); - expiration->contact = (struct ast_sip_contact*)contact; - ao2_ref(expiration->contact, +1); + ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval); - ao2_ref(expiration, +1); - if ((expiration->sched = ast_sched_add(sched, expires, contact_expiration_expire, expiration)) < 0) { - ao2_ref(expiration, -1); - ast_log(LOG_ERROR, "Scheduled expiration for contact '%s' could not be performed, contact may persist past life\n", - ast_sorcery_object_get_id(contact)); - } else { - ao2_link(contact_autoexpire, expiration); - } - ao2_ref(expiration, -1); -} - -/*! \brief Observer callback for when a contact is updated */ -static void contact_expiration_observer_updated(const void *object) -{ - const struct ast_sip_contact *contact = object; - struct contact_expiration *expiration; - int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", + AST_RETRIEVE_FLAG_MULTIPLE, var); - expiration = ao2_find(contact_autoexpire, ast_sorcery_object_get_id(contact), - OBJ_SEARCH_KEY); - if (!expiration) { - return; + ast_variables_destroy(var); + if (contacts) { + ast_debug(3, "Expiring %d contacts\n\n", ao2_container_count(contacts)); + ao2_callback(contacts, OBJ_NODATA, expire_contact, NULL); + ao2_ref(contacts, -1); + } } - AST_SCHED_REPLACE_UNREF(expiration->sched, sched, expires, contact_expiration_expire, - expiration, ao2_cleanup(expiration), ao2_cleanup(expiration), ao2_ref(expiration, +1)); - ao2_ref(expiration, -1); + return NULL; } -/*! \brief Observer callback for when a contact is deleted */ -static void contact_expiration_observer_deleted(const void *object) +static void expiration_global_loaded(const char *object_type) { - struct contact_expiration *expiration; - - expiration = ao2_find(contact_autoexpire, ast_sorcery_object_get_id(object), - OBJ_SEARCH_KEY | OBJ_UNLINK); - if (!expiration) { - return; - } - - AST_SCHED_DEL_UNREF(sched, expiration->sched, ao2_cleanup(expiration)); - ao2_ref(expiration, -1); -} - -/*! \brief Observer callbacks for autoexpiring contacts */ -static const struct ast_sorcery_observer contact_expiration_observer = { - .created = contact_expiration_observer_created, - .updated = contact_expiration_observer_updated, - .deleted = contact_expiration_observer_deleted, -}; - -/*! \brief Callback function which deletes a contact if it has expired or sets up auto-expiry */ -static int contact_expiration_setup(void *obj, void *arg, int flags) -{ - struct ast_sip_contact *contact = obj; - int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); - - if (!expires) { - ast_sorcery_delete(ast_sip_get_sorcery(), contact); + check_interval = ast_sip_get_contact_expiration_check_interval(); + + /* Observer calls are serialized so this is safe without it's own lock */ + if (check_interval) { + if (check_thread == AST_PTHREADT_NULL) { + if (ast_pthread_create_background(&check_thread, NULL, check_expiration_thread, NULL)) { + ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n"); + return; + } + ast_debug(3, "Interval = %d, starting thread\n", check_interval); + } } else { - contact_expiration_observer_created(contact); - } - - return 0; -} - -/*! \brief Initialize auto-expiration of any existing contacts */ -static void contact_expiration_initialize_existing(void) -{ - struct ao2_container *contacts; - - contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", - AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); - if (!contacts) { - return; + if (check_thread != AST_PTHREADT_NULL) { + pthread_kill(check_thread, SIGURG); + check_thread = AST_PTHREADT_NULL; + ast_debug(3, "Interval = 0, shutting thread down\n"); + } } - - ao2_callback(contacts, OBJ_NODATA, contact_expiration_setup, NULL); - ao2_ref(contacts, -1); } -static int unload_observer_delete(void *obj, void *arg, int flags) -{ - struct contact_expiration *expiration = obj; - - AST_SCHED_DEL_UNREF(sched, expiration->sched, ao2_cleanup(expiration)); - return CMP_MATCH; -} +/*! \brief Observer which is used to update our interval when the global setting changes */ +static struct ast_sorcery_observer expiration_global_observer = { + .loaded = expiration_global_loaded, +}; static int unload_module(void) { - ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &contact_expiration_observer); - if (sched) { - ao2_callback(contact_autoexpire, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, - unload_observer_delete, NULL); - ast_sched_context_destroy(sched); - sched = NULL; + if (check_thread != AST_PTHREADT_NULL) { + pthread_kill(check_thread, SIGURG); + check_thread = AST_PTHREADT_NULL; } - ao2_cleanup(contact_autoexpire); - contact_autoexpire = NULL; + + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &expiration_global_observer); return 0; } + static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); - contact_autoexpire = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, - CONTACT_AUTOEXPIRE_BUCKETS, contact_expiration_hash, contact_expiration_cmp); - if (!contact_autoexpire) { - ast_log(LOG_ERROR, "Could not create container for contact auto-expiration\n"); - return AST_MODULE_LOAD_FAILURE; - } - - if (!(sched = ast_sched_context_create())) { - ast_log(LOG_ERROR, "Could not create scheduler for contact auto-expiration\n"); - unload_module(); - return AST_MODULE_LOAD_FAILURE; - } - - if (ast_sched_start_thread(sched)) { - ast_log(LOG_ERROR, "Could not start scheduler thread for contact auto-expiration\n"); - unload_module(); - return AST_MODULE_LOAD_FAILURE; - } - - contact_expiration_initialize_existing(); - - if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &contact_expiration_observer)) { - ast_log(LOG_ERROR, "Could not add observer for notifications about contacts for contact auto-expiration\n"); - unload_module(); - return AST_MODULE_LOAD_FAILURE; - } + ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &expiration_global_observer); + ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); return AST_MODULE_LOAD_SUCCESS; } diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index 4e2c3a80944..b3642d81e3f 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -63,65 +63,6 @@ static struct ast_sorcery_wizard astdb_object_wizard = { .close = sorcery_astdb_close, }; -/*! \brief Helper function which converts from a sorcery object set to a json object */ -static struct ast_json *sorcery_objectset_to_json(const struct ast_variable *objectset) -{ - struct ast_json *json = ast_json_object_create(); - const struct ast_variable *field; - - for (field = objectset; field; field = field->next) { - struct ast_json *value = ast_json_string_create(field->value); - - if (!value) { - ast_json_unref(json); - return NULL; - } else if (ast_json_object_set(json, field->name, value)) { - ast_json_unref(json); - return NULL; - } - } - - return json; -} - -/*! \brief Helper function which converts a json object to a sorcery object set */ -static struct ast_variable *sorcery_json_to_objectset(struct ast_json *json) -{ - struct ast_json_iter *field; - struct ast_variable *objset = NULL; - - for (field = ast_json_object_iter(json); field; field = ast_json_object_iter_next(json, field)) { - struct ast_json *value = ast_json_object_iter_value(field); - struct ast_variable *variable = ast_variable_new(ast_json_object_iter_key(field), ast_json_string_get(value), ""); - - if (!variable) { - ast_variables_destroy(objset); - return NULL; - } - - variable->next = objset; - objset = variable; - } - - return objset; -} - -/*! \brief Helper function which compares two json objects and sees if they are equal, but only looks at the criteria provided */ -static int sorcery_json_equal(struct ast_json *object, struct ast_json *criteria) -{ - struct ast_json_iter *field; - - for (field = ast_json_object_iter(criteria); field; field = ast_json_object_iter_next(criteria, field)) { - struct ast_json *object_field = ast_json_object_get(object, ast_json_object_iter_key(field)); - - if (!object_field || !ast_json_equal(object_field, ast_json_object_iter_value(field))) { - return 0; - } - } - - return 1; -} - static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, void *object) { RAII_VAR(struct ast_json *, objset, ast_sorcery_objectset_json_create(sorcery, object), ast_json_unref); @@ -144,12 +85,11 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); - RAII_VAR(struct ast_json *, criteria, NULL, ast_json_unref); struct ast_db_entry *entry; snprintf(family, sizeof(family), "%s/%s", prefix, type); - if (!(entries = ast_db_gettree(family, NULL)) || (fields && !(criteria = sorcery_objectset_to_json(fields)))) { + if (!(entries = ast_db_gettree(family, NULL))) { return NULL; } @@ -158,14 +98,21 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); + RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy); void *object = NULL; if (!(json = ast_json_load_string(entry->data, &error))) { return NULL; - } else if (criteria && !sorcery_json_equal(json, criteria)) { + } + if (ast_json_to_ast_variables(json, &existing) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) { + return NULL; + } + + if (fields && !ast_variable_lists_match(existing, fields, 0)) { continue; - } else if (!(objset = sorcery_json_to_objectset(json)) || - !(object = ast_sorcery_alloc(sorcery, type, key)) || + } + + if (!(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { ao2_cleanup(object); return NULL; @@ -199,9 +146,11 @@ static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void * snprintf(family, sizeof(family), "%s/%s", prefix, type); - if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &error)) || - !(objset = sorcery_json_to_objectset(json)) || !(object = ast_sorcery_alloc(sorcery, type, id)) || - ast_sorcery_objectset_apply(sorcery, object, objset)) { + if (ast_db_get_allocated(family, id, &value) + || !(json = ast_json_load_string(value, &error)) + || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) + || !(object = ast_sorcery_alloc(sorcery, type, id)) + || ast_sorcery_objectset_apply(sorcery, object, objset)) { ast_debug(3, "Failed to retrieve object '%s' from astdb\n", id); ao2_cleanup(object); return NULL; @@ -310,10 +259,10 @@ static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void if (regexec(&expression, key, 0, NULL, 0)) { continue; - } else if (!(json = ast_json_load_string(entry->data, &error)) || - !(objset = sorcery_json_to_objectset(json)) || - !(object = ast_sorcery_alloc(sorcery, type, key)) || - ast_sorcery_objectset_apply(sorcery, object, objset)) { + } else if (!(json = ast_json_load_string(entry->data, &error)) + || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) + || !(object = ast_sorcery_alloc(sorcery, type, key)) + || ast_sorcery_objectset_apply(sorcery, object, objset)) { regfree(&expression); return; } diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c index 092cc41c8db..dd4ea888674 100644 --- a/res/res_sorcery_config.c +++ b/res/res_sorcery_config.c @@ -129,7 +129,6 @@ static int sorcery_config_fields_cmp(void *obj, void *arg, int flags) { const struct sorcery_config_fields_cmp_params *params = arg; RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); - RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy); if (params->regex) { /* If a regular expression has been provided see if it matches, otherwise move on */ @@ -139,11 +138,10 @@ static int sorcery_config_fields_cmp(void *obj, void *arg, int flags) return 0; } else if (params->fields && (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) || - (ast_sorcery_changeset_create(objset, params->fields, &diff)) || - diff)) { + (!ast_variable_lists_match(objset, params->fields, 0)))) { /* If we can't turn the object into an object set OR if differences exist between the fields - * passed in and what are present on the object they are not a match. - */ + * passed in and what are present on the object they are not a match. + */ return 0; } @@ -197,6 +195,7 @@ static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, if (!config_objects) { return; } + ao2_callback(config_objects, 0, sorcery_config_fields_cmp, ¶ms); } diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c index 95cb24835f2..db1fc1ab849 100644 --- a/res/res_sorcery_memory.c +++ b/res/res_sorcery_memory.c @@ -120,7 +120,6 @@ static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags) { const struct sorcery_memory_fields_cmp_params *params = arg; RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); - RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy); if (params->regex) { /* If a regular expression has been provided see if it matches, otherwise move on */ @@ -130,8 +129,7 @@ static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags) return 0; } else if (params->fields && (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) || - (ast_sorcery_changeset_create(objset, params->fields, &diff)) || - diff)) { + (!ast_variable_lists_match(objset, params->fields, 0)))) { /* If we can't turn the object into an object set OR if differences exist between the fields * passed in and what are present on the object they are not a match. */ diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index 704372e12b9..f1fb3c38c59 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -1253,8 +1253,7 @@ static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags) } return 0; } else if (params->fields && - (ast_sorcery_changeset_create(cached->objectset, params->fields, &diff) || - diff)) { + (!ast_variable_lists_match(cached->objectset, params->fields, 0))) { /* If we can't turn the object into an object set OR if differences exist between the fields * passed in and what are present on the object they are not a match. */ diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index 83736a102b8..abf2840fb92 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -40,6 +40,18 @@ ASTERISK_REGISTER_FILE() /*! \brief They key field used to store the unique identifier for the object */ #define UUID_FIELD "id" +enum unqualified_fetch { + UNQUALIFIED_FETCH_NO, + UNQUALIFIED_FETCH_WARN, + UNQUALIFIED_FETCH_YES, + UNQUALIFIED_FETCH_ERROR, +}; + +struct sorcery_config { + enum unqualified_fetch fetch; + char family[]; +}; + static void *sorcery_realtime_open(const char *data); static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object); static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id); @@ -66,7 +78,7 @@ static struct ast_sorcery_wizard realtime_object_wizard = { static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object) { - const char *family = data; + struct sorcery_config *config = data; RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy); struct ast_variable *id = ast_variable_new(UUID_FIELD, ast_sorcery_object_get_id(object), ""); @@ -79,7 +91,7 @@ static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data id->next = fields; fields = id; - return (ast_store_realtime_fields(family, fields) <= 0) ? -1 : 0; + return (ast_store_realtime_fields(config->family, fields) <= 0) ? -1 : 0; } /*! \brief Internal helper function which returns a filtered objectset. @@ -149,12 +161,12 @@ static struct ast_variable *sorcery_realtime_filter_objectset(struct ast_variabl static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields) { - const char *family = data; + struct sorcery_config *config = data; RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy); RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy); void *object = NULL; - if (!(objectset = ast_load_realtime_fields(family, fields))) { + if (!(objectset = ast_load_realtime_fields(config->family, fields))) { return NULL; } @@ -178,7 +190,7 @@ static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, voi static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields) { - const char *family = data; + struct sorcery_config *config = data; RAII_VAR(struct ast_config *, rows, NULL, ast_config_destroy); RAII_VAR(struct ast_variable *, all, NULL, ast_variables_destroy); struct ast_category *row = NULL; @@ -186,6 +198,18 @@ static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery if (!fields) { char field[strlen(UUID_FIELD) + 6], value[2]; + if (config->fetch == UNQUALIFIED_FETCH_NO) { + return; + } + if (config->fetch == UNQUALIFIED_FETCH_ERROR) { + ast_log(LOG_ERROR, "Unqualified fetch prevented on %s\n", config->family); + return; + } + if (config->fetch == UNQUALIFIED_FETCH_WARN) { + ast_log(LOG_WARNING, "Unqualified fetch attempted on %s\n", config->family); + return; + } + /* If no fields have been specified we want all rows, so trick realtime into doing it */ snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); snprintf(value, sizeof(value), "%%"); @@ -197,7 +221,7 @@ static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery fields = all; } - if (!(rows = ast_load_realtime_multientry_fields(family, fields))) { + if (!(rows = ast_load_realtime_multientry_fields(config->family, fields))) { return; } @@ -221,16 +245,18 @@ static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, v char field[strlen(UUID_FIELD) + 6], value[strlen(regex) + 3]; RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy); - /* The realtime API provides no direct ability to do regex so for now we support a limited subset using pattern matching */ - snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); - if (regex[0] == '^') { - snprintf(value, sizeof(value), "%s%%", regex + 1); - } else { - snprintf(value, sizeof(value), "%%%s%%", regex); - } + if (!ast_strlen_zero(regex)) { + /* The realtime API provides no direct ability to do regex so for now we support a limited subset using pattern matching */ + snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); + if (regex[0] == '^') { + snprintf(value, sizeof(value), "%s%%", regex + 1); + } else { + snprintf(value, sizeof(value), "%%%s%%", regex); + } - if (!(fields = ast_variable_new(field, value, ""))) { - return; + if (!(fields = ast_variable_new(field, value, ""))) { + return; + } } sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields); @@ -238,31 +264,74 @@ static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, v static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object) { - const char *family = data; + struct sorcery_config *config = data; RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy); if (!fields) { return -1; } - return (ast_update_realtime_fields(family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0; + return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0; } static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object) { - const char *family = data; + struct sorcery_config *config = data; - return (ast_destroy_realtime_fields(family, UUID_FIELD, ast_sorcery_object_get_id(object), NULL) <= 0) ? -1 : 0; + return (ast_destroy_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), NULL) <= 0) ? -1 : 0; } static void *sorcery_realtime_open(const char *data) { + struct sorcery_config *config; + char *tmp; + char *family; + char *option; + /* We require a prefix for family string generation, or else stuff could mix together */ - if (ast_strlen_zero(data) || !ast_realtime_is_mapping_defined(data)) { + if (ast_strlen_zero(data)) { + return NULL; + } + + tmp = ast_strdupa(data); + family = strsep(&tmp, ","); + + if (!ast_realtime_is_mapping_defined(family)) { + return NULL; + } + + config = ast_calloc(1, sizeof(*config) + strlen(family) + 1); + if (!config) { return NULL; } - return ast_strdup(data); + strcpy(config->family, family); /* Safe */ + config->fetch = UNQUALIFIED_FETCH_YES; + + while ((option = strsep(&tmp, ","))) { + char *name = strsep(&option, "="); + char *value = option; + + if (!strcasecmp(name, "allow_unqualified_fetch")) { + if (ast_strlen_zero(value) || !strcasecmp(value, "yes")) { + config->fetch = UNQUALIFIED_FETCH_YES; + } else if (!strcasecmp(value, "no")) { + config->fetch = UNQUALIFIED_FETCH_NO; + } else if (!strcasecmp(value, "warn")) { + config->fetch = UNQUALIFIED_FETCH_WARN; + } else if (!strcasecmp(value, "error")) { + config->fetch = UNQUALIFIED_FETCH_ERROR; + } else { + ast_log(LOG_ERROR, "Unrecognized value in %s:%s: '%s'\n", family, name, value); + return NULL; + } + } else { + ast_log(LOG_ERROR, "Unrecognized option in %s: '%s'\n", family, name); + return NULL; + } + } + + return config; } static void sorcery_realtime_close(void *data) diff --git a/tests/test_config.c b/tests/test_config.c index bbfec0df2af..fe64a074f2b 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -1672,6 +1672,66 @@ AST_TEST_DEFINE(config_dialplan_function) return res; } +AST_TEST_DEFINE(variable_lists_match) +{ + RAII_VAR(struct ast_variable *, left, NULL, ast_variables_destroy); + RAII_VAR(struct ast_variable *, right, NULL, ast_variables_destroy); + struct ast_variable *var; + + switch (cmd) { + case TEST_INIT: + info->name = "variable_lists_match"; + info->category = "/main/config/"; + info->summary = "Test ast_variable_lists_match"; + info->description = "Test ast_variable_lists_match"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + var = ast_variable_new("aaa", "111", ""); + ast_test_validate(test, var); + left = var; + var = ast_variable_new("bbb", "222", ""); + ast_test_validate(test, var); + ast_variable_list_append(&left, var); + + var = ast_variable_new("aaa", "111", ""); + ast_test_validate(test, var); + right = var; + + ast_test_validate(test, ast_variable_lists_match(left, right, 0)); + ast_test_validate(test, !ast_variable_lists_match(left, right, 1)); + + var = ast_variable_new("bbb", "222", ""); + ast_test_validate(test, var); + ast_variable_list_append(&right, var); + + ast_test_validate(test, ast_variable_lists_match(left, right, 0)); + ast_test_validate(test, ast_variable_lists_match(left, right, 1)); + + var = ast_variable_new("ccc >", "333", ""); + ast_test_validate(test, var); + ast_variable_list_append(&right, var); + + ast_test_validate(test, !ast_variable_lists_match(left, right, 0)); + ast_test_validate(test, !ast_variable_lists_match(left, right, 1)); + + var = ast_variable_new("ccc", "444", ""); + ast_test_validate(test, var); + ast_variable_list_append(&left, var); + + ast_test_validate(test, ast_variable_lists_match(left, right, 0)); + ast_test_validate(test, !ast_variable_lists_match(left, right, 1)); + + ast_test_validate(test, !ast_variable_lists_match(left, NULL, 0)); + ast_test_validate(test, ast_variable_lists_match(NULL, NULL, 0)); + ast_test_validate(test, !ast_variable_lists_match(NULL, right, 0)); + ast_test_validate(test, ast_variable_lists_match(left, left, 0)); + + return AST_TEST_PASS; +} + static int unload_module(void) { AST_TEST_UNREGISTER(config_basic_ops); @@ -1682,6 +1742,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(ast_parse_arg_test); AST_TEST_UNREGISTER(config_options_test); AST_TEST_UNREGISTER(config_dialplan_function); + AST_TEST_UNREGISTER(variable_lists_match); return 0; } @@ -1695,6 +1756,7 @@ static int load_module(void) AST_TEST_REGISTER(ast_parse_arg_test); AST_TEST_REGISTER(config_options_test); AST_TEST_REGISTER(config_dialplan_function); + AST_TEST_REGISTER(variable_lists_match); return AST_MODULE_LOAD_SUCCESS; } diff --git a/tests/test_sorcery_astdb.c b/tests/test_sorcery_astdb.c index ce978342339..d62e844e76e 100644 --- a/tests/test_sorcery_astdb.c +++ b/tests/test_sorcery_astdb.c @@ -298,7 +298,7 @@ AST_TEST_DEFINE(object_retrieve_multiple_field) RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup); - RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "6", ""), ast_variables_destroy); + RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe >=", "6", ""), ast_variables_destroy); switch (cmd) { case TEST_INIT: @@ -345,7 +345,7 @@ AST_TEST_DEFINE(object_retrieve_multiple_field) ao2_cleanup(objects); ast_variables_destroy(fields); - if (!(fields = ast_variable_new("joe", "7", ""))) { + if (!(fields = ast_variable_new("joe <", "6", ""))) { ast_test_status_update(test, "Failed to create fields for multiple retrieval\n"); return AST_TEST_FAIL; } else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) { diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c index 76dfb660359..b33031e8e82 100644 --- a/tests/test_sorcery_realtime.c +++ b/tests/test_sorcery_realtime.c @@ -42,60 +42,12 @@ ASTERISK_REGISTER_FILE() /*! \brief Configuration structure which contains all stored objects */ static struct ast_config *realtime_objects; -/*! \brief Helper function which finds a given variable */ -static const struct ast_variable *realtime_find_variable(const struct ast_variable *fields, const char *name) -{ - const struct ast_variable *variable; - - for (variable = fields; variable; variable = variable->next) { - if (!strcmp(variable->name, name)) { - return variable; - } - } - - return NULL; -} - -/*! \brief Helper function which returns if an object is matching or not */ -static int realtime_is_object_matching(const char *object_id, const struct ast_variable *fields) -{ - const struct ast_variable *field; - - for (field = fields; field; field = field->next) { - char *name = ast_strdupa(field->name), *like; - const char *value; - - /* If we are doing a pattern matching we need to remove the LIKE from the name */ - if ((like = strstr(name, " LIKE"))) { - char *field_value = ast_strdupa(field->value); - - *like = '\0'; - - value = ast_strdupa(ast_variable_retrieve(realtime_objects, object_id, name)); - - field_value = ast_strip_quoted(field_value, "%", "%"); - - if (strncmp(value, field_value, strlen(field_value))) { - return 0; - } - } else { - value = ast_variable_retrieve(realtime_objects, object_id, name); - - if (ast_strlen_zero(value) || strcmp(value, field->value)) { - return 0; - } - } - } - - return 1; -} - static struct ast_variable *realtime_sorcery(const char *database, const char *table, const struct ast_variable *fields) { char *object_id = NULL; while ((object_id = ast_category_browse(realtime_objects, object_id))) { - if (!realtime_is_object_matching(object_id, fields)) { + if (!ast_variable_lists_match(ast_category_root(realtime_objects, object_id), fields, 0)) { continue; } @@ -116,8 +68,9 @@ static struct ast_config *realtime_sorcery_multi(const char *database, const cha while ((object_id = ast_category_browse(realtime_objects, object_id))) { struct ast_category *object; + const struct ast_variable *object_fields = ast_category_root(realtime_objects, object_id); - if (!realtime_is_object_matching(object_id, fields)) { + if (!ast_variable_lists_match(object_fields, fields, 0)) { continue; } @@ -154,7 +107,7 @@ static int realtime_sorcery_update(const char *database, const char *table, cons static int realtime_sorcery_store(const char *database, const char *table, const struct ast_variable *fields) { /* The key field is explicit within res_sorcery_realtime */ - const struct ast_variable *keyfield = realtime_find_variable(fields, "id"); + const struct ast_variable *keyfield = ast_variable_find_variable_in_list(fields, "id"); struct ast_category *object; if (!keyfield || ast_category_exist(realtime_objects, keyfield->value, NULL) || !(object = ast_category_new(keyfield->value, "", 0))) { @@ -201,7 +154,7 @@ static void *test_sorcery_object_alloc(const char *id) return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), NULL); } -static struct ast_sorcery *alloc_and_initialize_sorcery(void) +static struct ast_sorcery *alloc_and_initialize_sorcery(char *table) { struct ast_sorcery *sorcery; @@ -209,7 +162,7 @@ static struct ast_sorcery *alloc_and_initialize_sorcery(void) return NULL; } - if ((ast_sorcery_apply_default(sorcery, "test", "realtime", "sorcery_realtime_test") != AST_SORCERY_APPLY_SUCCESS) || + if ((ast_sorcery_apply_default(sorcery, "test", "realtime", table) != AST_SORCERY_APPLY_SUCCESS) || ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL) || !(realtime_objects = ast_config_new())) { ast_sorcery_unref(sorcery); @@ -246,7 +199,7 @@ AST_TEST_DEFINE(object_create) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -281,7 +234,7 @@ AST_TEST_DEFINE(object_retrieve_id) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -344,7 +297,7 @@ AST_TEST_DEFINE(object_retrieve_field) return AST_TEST_FAIL; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -402,7 +355,7 @@ AST_TEST_DEFINE(object_retrieve_multiple_all) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -440,6 +393,63 @@ AST_TEST_DEFINE(object_retrieve_multiple_all) return AST_TEST_PASS; } +AST_TEST_DEFINE(object_retrieve_multiple_all_nofetch) +{ + RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); + RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup); + RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "object_retrieve_multiple_all_nofetch"; + info->category = "/res/sorcery_realtime/"; + info->summary = "sorcery multiple object retrieval unit test"; + info->description = + "Test multiple object retrieval in sorcery using realtime wizard"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test,allow_unqualified_fetch=no"))) { + ast_test_status_update(test, "Failed to open sorcery structure\n"); + return AST_TEST_FAIL; + } + + if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) { + ast_test_status_update(test, "Failed to allocate a known object type\n"); + return AST_TEST_FAIL; + } + + if (ast_sorcery_create(sorcery, obj)) { + ast_test_status_update(test, "Failed to create object using realtime wizard\n"); + return AST_TEST_FAIL; + } + + ao2_cleanup(obj); + + if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) { + ast_test_status_update(test, "Failed to allocate second instance of a known object type\n"); + return AST_TEST_FAIL; + } + + if (ast_sorcery_create(sorcery, obj)) { + ast_test_status_update(test, "Failed to create second object using realtime wizard\n"); + return AST_TEST_FAIL; + } + + if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) { + ast_test_status_update(test, "Failed to retrieve a container of all objects\n"); + return AST_TEST_FAIL; + } else if (ao2_container_count(objects) != 0) { + ast_test_status_update(test, "Received a container with objects in it when there should be none\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + + AST_TEST_DEFINE(object_retrieve_multiple_field) { RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); @@ -464,7 +474,7 @@ AST_TEST_DEFINE(object_retrieve_multiple_field) return AST_TEST_FAIL; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -524,7 +534,7 @@ AST_TEST_DEFINE(object_retrieve_regex) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -574,6 +584,74 @@ AST_TEST_DEFINE(object_retrieve_regex) return AST_TEST_PASS; } +AST_TEST_DEFINE(object_retrieve_regex_nofetch) +{ + RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); + RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup); + RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "object_retrieve_regex_nofetch"; + info->category = "/res/sorcery_realtime/"; + info->summary = "sorcery multiple object retrieval using regex unit test"; + info->description = + "Test multiple object retrieval in sorcery using regular expression for matching using realtime wizard"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test,allow_unqualified_fetch=no"))) { + ast_test_status_update(test, "Failed to open sorcery structure\n"); + return AST_TEST_FAIL; + } + + if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) { + ast_test_status_update(test, "Failed to allocate a known object type\n"); + return AST_TEST_FAIL; + } + + if (ast_sorcery_create(sorcery, obj)) { + ast_test_status_update(test, "Failed to create object using realtime wizard\n"); + return AST_TEST_FAIL; + } + + ao2_cleanup(obj); + + if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) { + ast_test_status_update(test, "Failed to allocate second instance of a known object type\n"); + return AST_TEST_FAIL; + } + + if (ast_sorcery_create(sorcery, obj)) { + ast_test_status_update(test, "Failed to create second object using astdb wizard\n"); + return AST_TEST_FAIL; + } + + ao2_cleanup(obj); + + if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) { + ast_test_status_update(test, "Failed to allocate third instance of a known object type\n"); + return AST_TEST_FAIL; + } + + if (ast_sorcery_create(sorcery, obj)) { + ast_test_status_update(test, "Failed to create third object using astdb wizard\n"); + return AST_TEST_FAIL; + } + + if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", ""))) { + ast_test_status_update(test, "Failed to retrieve a container of objects\n"); + return AST_TEST_FAIL; + } else if (ao2_container_count(objects) != 0) { + ast_test_status_update(test, "Received a container with incorrect number of objects in it: %d instead of 0\n", ao2_container_count(objects)); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + AST_TEST_DEFINE(object_update) { RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); @@ -592,7 +670,7 @@ AST_TEST_DEFINE(object_update) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -650,7 +728,7 @@ AST_TEST_DEFINE(object_update_uncreated) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -685,7 +763,7 @@ AST_TEST_DEFINE(object_delete) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -732,7 +810,7 @@ AST_TEST_DEFINE(object_delete_uncreated) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -770,7 +848,7 @@ AST_TEST_DEFINE(object_allocate_on_retrieval) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -823,7 +901,7 @@ AST_TEST_DEFINE(object_filter) break; } - if (!(sorcery = alloc_and_initialize_sorcery())) { + if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { ast_test_status_update(test, "Failed to open sorcery structure\n"); return AST_TEST_FAIL; } @@ -859,8 +937,10 @@ static int unload_module(void) AST_TEST_UNREGISTER(object_retrieve_id); AST_TEST_UNREGISTER(object_retrieve_field); AST_TEST_UNREGISTER(object_retrieve_multiple_all); + AST_TEST_UNREGISTER(object_retrieve_multiple_all_nofetch); AST_TEST_UNREGISTER(object_retrieve_multiple_field); AST_TEST_UNREGISTER(object_retrieve_regex); + AST_TEST_UNREGISTER(object_retrieve_regex_nofetch); AST_TEST_UNREGISTER(object_update); AST_TEST_UNREGISTER(object_update_uncreated); AST_TEST_UNREGISTER(object_delete); @@ -879,8 +959,10 @@ static int load_module(void) AST_TEST_REGISTER(object_retrieve_id); AST_TEST_REGISTER(object_retrieve_field); AST_TEST_REGISTER(object_retrieve_multiple_all); + AST_TEST_REGISTER(object_retrieve_multiple_all_nofetch); AST_TEST_REGISTER(object_retrieve_multiple_field); AST_TEST_REGISTER(object_retrieve_regex); + AST_TEST_REGISTER(object_retrieve_regex_nofetch); AST_TEST_REGISTER(object_update); AST_TEST_REGISTER(object_update_uncreated); AST_TEST_REGISTER(object_delete); diff --git a/tests/test_strings.c b/tests/test_strings.c index a39ac63349f..28f6e1606ba 100644 --- a/tests/test_strings.c +++ b/tests/test_strings.c @@ -523,6 +523,68 @@ AST_TEST_DEFINE(escape_test) return AST_TEST_PASS; } +AST_TEST_DEFINE(strings_match) +{ + switch (cmd) { + case TEST_INIT: + info->name = "strings_match"; + info->category = "/main/strings/"; + info->summary = "Test ast_strings_match"; + info->description = "Test ast_strings_match"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, ast_strings_match("aaa", NULL, "aaa")); + ast_test_validate(test, ast_strings_match("aaa", "", "aaa")); + ast_test_validate(test, ast_strings_match("aaa", "=", "aaa")); + ast_test_validate(test, !ast_strings_match("aaa", "!=", "aaa")); + ast_test_validate(test, !ast_strings_match("aaa", NULL, "aba")); + ast_test_validate(test, !ast_strings_match("aaa", "", "aba")); + ast_test_validate(test, !ast_strings_match("aaa", "=", "aba")); + ast_test_validate(test, ast_strings_match("aaa", "!=", "aba")); + + ast_test_validate(test, ast_strings_match("aaa", "<=", "aba")); + ast_test_validate(test, ast_strings_match("aaa", "<=", "aaa")); + ast_test_validate(test, !ast_strings_match("aaa", "<", "aaa")); + + ast_test_validate(test, !ast_strings_match("aaa", ">=", "aba")); + ast_test_validate(test, ast_strings_match("aaa", ">=", "aaa")); + ast_test_validate(test, !ast_strings_match("aaa", ">", "aaa")); + + ast_test_validate(test, !ast_strings_match("aaa", "=", "aa")); + ast_test_validate(test, ast_strings_match("aaa", ">", "aa")); + ast_test_validate(test, !ast_strings_match("aaa", "<", "aa")); + + ast_test_validate(test, ast_strings_match("1", "=", "1")); + ast_test_validate(test, !ast_strings_match("1", "!=", "1")); + ast_test_validate(test, !ast_strings_match("2", "=", "1")); + ast_test_validate(test, ast_strings_match("2", ">", "1")); + ast_test_validate(test, ast_strings_match("2", ">=", "1")); + ast_test_validate(test, ast_strings_match("2", ">", "1.9888")); + ast_test_validate(test, ast_strings_match("2.9", ">", "1")); + ast_test_validate(test, ast_strings_match("2", ">", "1")); + ast_test_validate(test, ast_strings_match("2.999", "<", "3")); + ast_test_validate(test, ast_strings_match("2", ">", "#")); + + ast_test_validate(test, ast_strings_match("abcccc", "like", "%a%c")); + ast_test_validate(test, !ast_strings_match("abcccx", "like", "%a%c")); + ast_test_validate(test, ast_strings_match("abcccc", "regex", "a[bc]+c")); + ast_test_validate(test, !ast_strings_match("abcccx", "regex", "^a[bxdfgtc]+c$")); + + ast_test_validate(test, !ast_strings_match("neener-93joe", "LIKE", "%blah-%")); + ast_test_validate(test, ast_strings_match("blah-93joe", "LIKE", "%blah-%")); + + ast_test_validate(test, !ast_strings_match("abcccx", "regex", NULL)); + ast_test_validate(test, !ast_strings_match("abcccx", NULL, NULL)); + ast_test_validate(test, !ast_strings_match(NULL, "regex", NULL)); + ast_test_validate(test, !ast_strings_match(NULL, NULL, "abc")); + ast_test_validate(test, !ast_strings_match(NULL, NULL, NULL)); + + return AST_TEST_PASS; +} + static int unload_module(void) { AST_TEST_UNREGISTER(str_test); @@ -531,6 +593,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(strsep_test); AST_TEST_UNREGISTER(escape_semicolons_test); AST_TEST_UNREGISTER(escape_test); + AST_TEST_UNREGISTER(strings_match); return 0; } @@ -542,6 +605,7 @@ static int load_module(void) AST_TEST_REGISTER(strsep_test); AST_TEST_REGISTER(escape_semicolons_test); AST_TEST_REGISTER(escape_test); + AST_TEST_REGISTER(strings_match); return AST_MODULE_LOAD_SUCCESS; } From c971a6436646225a159c644644db91ef6de46923 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 10 Mar 2016 18:52:14 -0700 Subject: [PATCH 0302/1578] res_pjsip/pjsip_options: Fix From generation on outgoing OPTIONS No one seemed to notice but every time an OPTIONS goes out, it goes out with a From of "asterisk" (or whatever the default from_user is set to), even if you specify an endpoint. The issue had several causes... qualify_contact is only called with an endpoint if called from the CLI. If the endpoint is NULL, qualify_contact only looks up the endpoint if authenticate_qualify=yes. Even then, it never passes it on to ast_sip_create_request where the From header is set. Therefore From is always "asterisk" (or whatever the default from_user is set to). Even if ast_sip_create_request were to get an endpoint, it only sets the From if endpoint->from_user is set. The fix is 4 parts... First, create_out_of_dialog_request was modified to use the endpoint id if endpoint was specified and from_user is not set. Second, qualify_contact was modified to always look up an endpoint if one wasn't specified regardless of authenticate_qualify. It then passes the endpoint on to create_out_of_dialog_request. Third (and most importantly), find_an_endpoint was modified to find an endpoint by using an "aors LIKE %contact->aor%" predicate with ast_sorcery_retrieve_by_fields. As such, this patch will only work if the sorcery realtime optimizations patch goes in. Otherwise we'd be pulling the entire endpoints database every time we send an OPTIONS. Since we already know the contact's aor, the on_endpoint callback was also modified to just check if the contact->aor is an exact match to one of the endpoint's. Finally, since we now have an endpoint for every OPTIONS request, res_pjsip/endpt_send_request (which handles out-of-dialog reqests) was updated to get the transport from the endpoint and set it on tdata. Now the correct transport is used. Change-Id: I2207e12bb435e373bd1e03ad091d82e5aba011af --- res/res_pjsip.c | 10 ++++- res/res_pjsip/pjsip_options.c | 81 ++++++++++++----------------------- 2 files changed, 36 insertions(+), 55 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 170a19151a7..c13369ff5f3 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2859,6 +2859,7 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s pj_pool_t *pool; pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; pjsip_uri *sip_uri; + const char *fromuser; if (ast_strlen_zero(uri)) { if (!endpoint && (!contact || ast_strlen_zero(contact->uri))) { @@ -2905,7 +2906,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s return -1; } - if (sip_dialog_create_from(pool, &from, endpoint ? endpoint->fromuser : NULL, + fromuser = endpoint ? (!ast_strlen_zero(endpoint->fromuser) ? endpoint->fromuser : ast_sorcery_object_get_id(endpoint)) : NULL; + if (sip_dialog_create_from(pool, &from, fromuser, endpoint ? endpoint->fromdomain : NULL, &remote_uri, &selector)) { ast_log(LOG_ERROR, "Unable to create From header for %.*s request to endpoint %s\n", (int) pj_strlen(&method->name), pj_strbuf(&method->name), @@ -3200,6 +3202,7 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, struct send_request_wrapper *req_wrapper; pj_status_t ret_val; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; /* Create wrapper to detect if the callback was actually called on an error. */ req_wrapper = ao2_alloc(sizeof(*req_wrapper), send_request_wrapper_destructor); @@ -3250,6 +3253,11 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, */ ao2_ref(req_wrapper, +1); + if (endpoint) { + sip_get_tpselector_from_endpoint(endpoint, &selector); + pjsip_tx_data_set_transport(tdata, &selector); + } + ret_val = pjsip_endpt_send_request(endpt, tdata, -1, req_wrapper, endpt_send_request_cb); if (ret_val != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 4cce5583678..e12481a147c 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -237,31 +237,12 @@ static void init_start_time(const struct ast_sip_contact *contact) /*! * \internal - * \brief Match a container contact object with the contact sorcery id looking for. - * - * \param obj pointer to the (user-defined part) of an object. - * \param arg callback argument from ao2_callback() - * \param flags flags from ao2_callback() - * - * \return Values are a combination of enum _cb_results. - */ -static int match_contact_id(void *obj, void *arg, int flags) -{ - struct ast_sip_contact *contact = obj; - const char *looking_for = arg; - - return strcmp(ast_sorcery_object_get_id(contact), looking_for) ? 0 : CMP_MATCH; -} - -/*! - * \internal - * \brief For an endpoint try to match the given contact sorcery id. + * \brief For an endpoint try to match the given contact->aor. */ static int on_endpoint(void *obj, void *arg, int flags) { struct ast_sip_endpoint *endpoint = obj; - struct ast_sip_contact *contact; - char *looking_for = arg; + char *contact_aor = arg; char *aor_name; char *aors; @@ -271,24 +252,7 @@ static int on_endpoint(void *obj, void *arg, int flags) aors = ast_strdupa(endpoint->aors); while ((aor_name = ast_strip(strsep(&aors, ",")))) { - struct ast_sip_aor *aor; - struct ao2_container *contacts; - - aor = ast_sip_location_retrieve_aor(aor_name); - if (!aor) { - continue; - } - - contacts = ast_sip_location_retrieve_aor_contacts(aor); - ao2_ref(aor, -1); - if (!contacts) { - continue; - } - - contact = ao2_callback(contacts, 0, match_contact_id, looking_for); - ao2_ref(contacts, -1); - if (contact) { - ao2_ref(contact, -1); + if (!strcmp(contact_aor, aor_name)) { return CMP_MATCH; } } @@ -302,12 +266,26 @@ static int on_endpoint(void *obj, void *arg, int flags) */ static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact) { - char *looking_for = (char *) ast_sorcery_object_get_id(contact); - struct ao2_container *endpoints = ast_sip_get_endpoints(); + struct ao2_container *endpoints; struct ast_sip_endpoint *endpoint; + struct ast_variable *var; + char *aor = ast_alloca(strlen(contact->aor) + 3); + + sprintf(aor, "%%%s%%", contact->aor); + var = ast_variable_new("aors LIKE", aor, ""); + endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var); + + ast_variables_destroy(var); - endpoint = ao2_callback(endpoints, 0, on_endpoint, looking_for); + /* + * Because aors are a string list, we have to use a pattern match but since a simple + * pattern match could return an endpoint that has an aor of "aaabccc" when searching + * for "abc", we still have to iterate over them to find an exact aor match. + */ + endpoint = ao2_callback(endpoints, 0, on_endpoint, (char *)contact->aor); ao2_ref(endpoints, -1); + return endpoint; } @@ -346,23 +324,18 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con pjsip_tx_data *tdata; RAII_VAR(struct ast_sip_endpoint *, endpoint_local, NULL, ao2_cleanup); - if (contact->authenticate_qualify) { + if (endpoint) { endpoint_local = ao2_bump(endpoint); + } else { + endpoint_local = find_an_endpoint(contact); if (!endpoint_local) { - /* - * Find the "first" endpoint to completely qualify the contact - any - * endpoint that is associated with the contact should do. - */ - endpoint_local = find_an_endpoint(contact); - if (!endpoint_local) { - ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n", - contact->uri); - return -1; - } + ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n", + contact->uri); + return -1; } } - if (ast_sip_create_request("OPTIONS", NULL, NULL, NULL, contact, &tdata)) { + if (ast_sip_create_request("OPTIONS", NULL, endpoint_local, NULL, contact, &tdata)) { ast_log(LOG_ERROR, "Unable to create request to qualify contact %s\n", contact->uri); return -1; From 44ffb5105a7d6ff04ecd699b228614d0ac8b4466 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 27 Mar 2016 11:53:16 -0600 Subject: [PATCH 0303/1578] res_rtp_asterisk: Fix packet stats on bridged connection rxcount, txcount, rxoctetcount and txoctetcount weren't being calculated for bridged streams because the calulations were being done after the bridged short-circuit. Actually, rxoctetcount wasn't ever being calculated. Moved the calculations so they occur for all valid received packets and all transmitted packets. Also added rxoctetcount and txoctetcount to ast_rtp_instance_stat. Change-Id: I08fb06011a82d38c3b4068867a615068fbe59cbb --- include/asterisk/rtp_engine.h | 8 ++++++++ res/res_rtp_asterisk.c | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 67340335cfb..411ae8abf30 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -228,6 +228,10 @@ enum ast_rtp_instance_stat { AST_RTP_INSTANCE_STAT_REMOTE_SSRC, /*! Retrieve channel unique ID */ AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID, + /*! Retrieve number of octets transmitted */ + AST_RTP_INSTANCE_STAT_TXOCTETCOUNT, + /*! Retrieve number of octets received */ + AST_RTP_INSTANCE_STAT_RXOCTETCOUNT, }; /* Codes for RTP-specific data - not defined by our AST_FORMAT codes */ @@ -359,6 +363,10 @@ struct ast_rtp_instance_stats { unsigned int remote_ssrc; /*! The Asterisk channel's unique ID that owns this instance */ char channel_uniqueid[MAX_CHANNEL_ID]; + /*! Number of octets transmitted */ + unsigned int txoctetcount; + /*! Number of octets received */ + unsigned int rxoctetcount; }; #define AST_RTP_STAT_SET(current_stat, combined, placement, value) \ diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 9c7432e8c07..45bc3103ae9 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2252,6 +2252,7 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance); int res; + int hdrlen = 12; *ice = 0; @@ -2259,6 +2260,9 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz return -1; } + rtp->txcount++; + rtp->txoctetcount += (len - hdrlen); + #ifdef HAVE_PJPROJECT if (rtp->ice) { pj_thread_register_check(); @@ -2274,6 +2278,7 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz if (res > 0) { ast_rtp_instance_set_last_tx(instance, time(NULL)); } + return res; } @@ -3352,9 +3357,6 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN); } } else { - rtp->txcount++; - rtp->txoctetcount += (res - hdrlen); - if (rtp->rtcp && rtp->rtcp->schedid < 0) { ast_debug(1, "Starting RTCP transmission on RTP instance '%p'\n", instance); ao2_ref(instance, +1); @@ -4287,6 +4289,9 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int return -1; } + rtp->rxcount++; + rtp->rxoctetcount += (len - hdrlen); + /* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */ if (ast_rtp_codecs_find_payload_code(ast_rtp_instance_get_codecs(instance1), bridged_payload) == -1) { ast_debug(1, "Unsupported payload type received \n"); @@ -4517,6 +4522,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->seedrxseqno = 0; rtp->rxcount = 0; + rtp->rxoctetcount = 0; rtp->cycles = 0; rtp->lastrxseqno = 0; rtp->last_seqno = 0; @@ -4560,6 +4566,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } rtp->rxcount++; + rtp->rxoctetcount += (res - hdrlen); if (rtp->rxcount == 1) { rtp->seedrxseqno = seqno; } @@ -4961,6 +4968,8 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXCOUNT, -1, stats->txcount, rtp->txcount); AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXCOUNT, -1, stats->rxcount, rtp->rxcount); + AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXOCTETCOUNT, -1, stats->txoctetcount, rtp->txoctetcount); + AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXOCTETCOUNT, -1, stats->rxoctetcount, rtp->rxoctetcount); AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->txploss, rtp->rtcp->reported_lost); AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->rxploss, rtp->rtcp->expected_prior - rtp->rtcp->received_prior); From 9785e8d0902f139425e318c9df84f1857adf6aaa Mon Sep 17 00:00:00 2001 From: Jacek Konieczny Date: Fri, 25 Mar 2016 16:42:12 +0100 Subject: [PATCH 0304/1578] app_echo: forward and generate VIDUPDATE frames When using app_echo via WebRTC with VP8 video the video would appear only after a few minutes, because there would be nothing to request a full reference frame. This fixes the problem in both ways: - echos any VIDUPDATE frames received on the channel - sends one such frame when first video frame is to be forwarded This makes the echo work with Firefox and Chrome WebRTC implementation. ASTERISK-25867 #close Change-Id: I73bda87bf7532ee8bfb28d917045a21034908c1e --- apps/app_echo.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/app_echo.c b/apps/app_echo.c index 2ec9d709b4e..972e59f0aed 100644 --- a/apps/app_echo.c +++ b/apps/app_echo.c @@ -58,6 +58,7 @@ static const char app[] = "Echo"; static int echo_exec(struct ast_channel *chan, const char *data) { int res = -1; + int fir_sent = 0; while (ast_waitfor(chan, -1) > -1) { struct ast_frame *f = ast_read(chan); @@ -66,6 +67,22 @@ static int echo_exec(struct ast_channel *chan, const char *data) } f->delivery.tv_sec = 0; f->delivery.tv_usec = 0; + if (f->frametype == AST_FRAME_CONTROL + && f->subclass.integer == AST_CONTROL_VIDUPDATE) { + if (ast_write(chan, f) < 0) { + ast_frfree(f); + goto end; + } + fir_sent = 1; + } + if (!fir_sent && f->frametype == AST_FRAME_VIDEO) { + struct ast_frame frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_VIDUPDATE, + }; + ast_write(chan, &frame); + fir_sent = 1; + } if (f->frametype != AST_FRAME_CONTROL && f->frametype != AST_FRAME_MODEM && f->frametype != AST_FRAME_NULL From 970803efcb291d73bfdb0ffb91934b5a4faa1dc5 Mon Sep 17 00:00:00 2001 From: Jacek Konieczny Date: Fri, 25 Mar 2016 16:59:05 +0100 Subject: [PATCH 0305/1578] res_rtp_asterisk: Use separate SRTP session for RTCP with DTLS Asterisk uses separate UDP ports for RTP and RTCP traffic and RFC 5764 explicitly states: There MUST be a separate DTLS-SRTP session for each distinct pair of source and destination ports used by a media session This means RTP keying material cannot be used for DTLS RTCP, which was the reason why RTCP encryption would fail. ASTERISK-25642 Change-Id: I7e8779d8b63e371088081bb113131361b2847e3a --- include/asterisk/rtp_engine.h | 6 ++++-- main/rtp_engine.c | 29 ++++++++++++++++++++++------- main/sdp_srtp.c | 2 +- res/res_rtp_asterisk.c | 27 +++++++++++++++------------ 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 67340335cfb..34fb17dbdd4 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -2228,20 +2228,22 @@ int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level); * \param instance the RTP instance * \param remote_policy the remote endpoint's policy * \param local_policy our policy for this RTP instance's remote endpoint + * \param rtcp 1 for dedicated RTCP policies * * \retval 0 Success * \retval non-zero Failure */ -int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy* remote_policy, struct ast_srtp_policy *local_policy); +int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy* remote_policy, struct ast_srtp_policy *local_policy, int rtcp); /*! * \brief Obtain the SRTP instance associated with an RTP instance * * \param instance the RTP instance + * \param rtcp 1 to request instance for RTCP * \retval the SRTP instance on success * \retval NULL if no SRTP instance exists */ -struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance); +struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance, int rtcp); /*! \brief Custom formats declared in codecs.conf at startup must be communicated to the rtp_engine * so their mime type can payload number can be initialized. */ diff --git a/main/rtp_engine.c b/main/rtp_engine.c index fd472ba7290..11e94c699a9 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -188,6 +188,8 @@ struct ast_rtp_instance { struct ast_rtp_glue *glue; /*! SRTP info associated with the instance */ struct ast_srtp *srtp; + /*! SRTP info dedicated for RTCP associated with the instance */ + struct ast_srtp *rtcp_srtp; /*! Channel unique ID */ char channel_uniqueid[AST_MAX_UNIQUEID]; /*! Time of last packet sent */ @@ -364,6 +366,10 @@ static void instance_destructor(void *obj) res_srtp->destroy(instance->srtp); } + if (instance->rtcp_srtp) { + res_srtp->destroy(instance->rtcp_srtp); + } + ast_rtp_codecs_payloads_destroy(&instance->codecs); /* Drop our engine reference */ @@ -2052,29 +2058,38 @@ int ast_rtp_engine_srtp_is_registered(void) return res_srtp && res_srtp_policy; } -int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *remote_policy, struct ast_srtp_policy *local_policy) +int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *remote_policy, struct ast_srtp_policy *local_policy, int rtcp) { int res = 0; + struct ast_srtp **srtp; if (!res_srtp) { return -1; } - if (!instance->srtp) { - res = res_srtp->create(&instance->srtp, instance, remote_policy); + + srtp = rtcp ? &instance->rtcp_srtp : &instance->srtp; + + if (!*srtp) { + res = res_srtp->create(srtp, instance, remote_policy); } else { - res = res_srtp->replace(&instance->srtp, instance, remote_policy); + res = res_srtp->replace(srtp, instance, remote_policy); } if (!res) { - res = res_srtp->add_stream(instance->srtp, local_policy); + res = res_srtp->add_stream(*srtp, local_policy); } return res; } -struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance) +struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance, int rtcp) { - return instance->srtp; + if (rtcp && instance->rtcp_srtp) { + return instance->rtcp_srtp; + } + else { + return instance->srtp; + } } int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level) diff --git a/main/sdp_srtp.c b/main/sdp_srtp.c index e576258c3f9..c92387bc207 100644 --- a/main/sdp_srtp.c +++ b/main/sdp_srtp.c @@ -183,7 +183,7 @@ static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned cha } /* Add the SRTP policies */ - if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy)) { + if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy, 0)) { ast_log(LOG_WARNING, "Could not set SRTP policies\n"); goto err; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 9c7432e8c07..789535ef04c 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1982,19 +1982,20 @@ static int dtls_srtp_renegotiate(const void *data) return 0; } -static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance) +static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance, int rtcp) { unsigned char material[SRTP_MASTER_LEN * 2]; unsigned char *local_key, *local_salt, *remote_key, *remote_salt; struct ast_srtp_policy *local_policy, *remote_policy = NULL; struct ast_rtp_instance_stats stats = { 0, }; int res = -1; + struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */ if (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) { X509 *certificate; - if (!(certificate = SSL_get_peer_certificate(rtp->dtls.ssl))) { + if (!(certificate = SSL_get_peer_certificate(dtls->ssl))) { ast_log(LOG_WARNING, "No certificate was provided by the peer on RTP instance '%p'\n", instance); return -1; } @@ -2028,14 +2029,14 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as } /* Ensure that certificate verification was successful */ - if ((rtp->dtls_verify & AST_RTP_DTLS_VERIFY_CERTIFICATE) && SSL_get_verify_result(rtp->dtls.ssl) != X509_V_OK) { + if ((rtp->dtls_verify & AST_RTP_DTLS_VERIFY_CERTIFICATE) && SSL_get_verify_result(dtls->ssl) != X509_V_OK) { ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n", instance); return -1; } /* Produce key information and set up SRTP */ - if (!SSL_export_keying_material(rtp->dtls.ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { + if (!SSL_export_keying_material(dtls->ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { ast_log(LOG_WARNING, "Unable to extract SRTP keying material from DTLS-SRTP negotiation on RTP instance '%p'\n", instance); return -1; @@ -2090,7 +2091,7 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as res_srtp_policy->set_ssrc(remote_policy, 0, 1); - if (ast_rtp_instance_add_srtp_policy(instance, remote_policy, local_policy)) { + if (ast_rtp_instance_add_srtp_policy(instance, remote_policy, local_policy, rtcp)) { ast_log(LOG_WARNING, "Could not set policies when setting up DTLS-SRTP on '%p'\n", rtp); goto error; } @@ -2121,7 +2122,7 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s { int len; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance); + struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, rtcp); char *in = buf; #ifdef HAVE_PJPROJECT struct ast_sockaddr *loop = rtcp ? &rtp->rtcp_loop : &rtp->rtp_loop; @@ -2178,10 +2179,8 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s if (SSL_is_init_finished(dtls->ssl)) { /* Any further connections will be existing since this is now established */ dtls->connection = AST_RTP_DTLS_CONNECTION_EXISTING; - if (!rtcp) { - /* Use the keying material to set up key/salt information */ - res = dtls_srtp_setup(rtp, srtp, instance); - } + /* Use the keying material to set up key/salt information */ + res = dtls_srtp_setup(rtp, srtp, instance, rtcp); } else { /* Since we've sent additional traffic start the timeout timer for retransmission */ dtls_srtp_start_timeout_timer(instance, rtp, rtcp); @@ -2250,7 +2249,7 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz int len = size; void *temp = buf; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance); + struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, rtcp); int res; *ice = 0; @@ -2950,7 +2949,8 @@ static void ast_rtp_update_source(struct ast_rtp_instance *instance) static void ast_rtp_change_source(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance); + struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, 0); + struct ast_srtp *rtcp_srtp = ast_rtp_instance_get_srtp(instance, 1); unsigned int ssrc = ast_random(); if (!rtp->lastts) { @@ -2966,6 +2966,9 @@ static void ast_rtp_change_source(struct ast_rtp_instance *instance) if (srtp) { ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc); res_srtp->change_source(srtp, rtp->ssrc, ssrc); + if (rtcp_srtp != srtp) { + res_srtp->change_source(srtp, rtp->ssrc, ssrc); + } } rtp->ssrc = ssrc; From c4064727d208d61dc29721c52f450f67eb22a445 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 26 Mar 2016 21:33:14 -0600 Subject: [PATCH 0306/1578] chan_pjsip: Add 'pjsip show channelstats' Added the ability to show channel statistics to chan_pjsip (cli_functions.c) Moved the existing 'pjsip show channel(s)' functionality from pjsip_configuration to cli_functions.c. The stats needed chan_pjsip's private header so it made sense to move the existing channel commands as well. Now using stasis_cache_dump to get the channel snapshots rather than retrieving all endpoints, then getting each one's channel snapshots. Much more efficient. Change-Id: I03b114522126d27434030b285bf6d531ddd79869 --- CHANGES | 3 + channels/chan_pjsip.c | 12 + channels/pjsip/cli_commands.c | 467 +++++++++++++++++++++++++ channels/pjsip/include/cli_functions.h | 45 +++ res/res_pjsip/pjsip_cli.c | 2 +- res/res_pjsip/pjsip_configuration.c | 261 -------------- 6 files changed, 528 insertions(+), 262 deletions(-) create mode 100644 channels/pjsip/cli_commands.c create mode 100644 channels/pjsip/include/cli_functions.h diff --git a/CHANGES b/CHANGES index 4b607b7a2df..f44df328430 100644 --- a/CHANGES +++ b/CHANGES @@ -263,6 +263,9 @@ res_parking: for these variables. The indefinite inheritance is also recommended for the PARKINGEXTEN variable. +chan_pjsip +------------------ + * Added 'pjsip show channelstats' CLI command. ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index cd55400c3ba..370075d2b73 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -69,6 +69,7 @@ ASTERISK_REGISTER_FILE() #include "pjsip/include/chan_pjsip.h" #include "pjsip/include/dialplan_functions.h" +#include "pjsip/include/cli_functions.h" AST_THREADSTORAGE(uniqueid_threadbuf); #define UNIQUEID_BUFSIZE 256 @@ -2468,6 +2469,15 @@ static int load_module(void) goto end; } + if (pjsip_channel_cli_register()) { + ast_log(LOG_ERROR, "Unable to register PJSIP Channel CLI\n"); + ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement); + ast_sip_session_unregister_supplement(&pbx_start_supplement); + ast_sip_session_unregister_supplement(&chan_pjsip_supplement); + ast_sip_session_unregister_supplement(&call_pickup_supplement); + goto end; + } + /* since endpoints are loaded before the channel driver their device states get set to 'invalid', so they need to be updated */ if ((endpoints = ast_sip_get_endpoints())) { @@ -2494,6 +2504,8 @@ static int unload_module(void) ao2_cleanup(pjsip_uids_onhold); pjsip_uids_onhold = NULL; + pjsip_channel_cli_unregister(); + ast_sip_session_unregister_supplement(&chan_pjsip_supplement); ast_sip_session_unregister_supplement(&pbx_start_supplement); ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement); diff --git a/channels/pjsip/cli_commands.c b/channels/pjsip/cli_commands.c new file mode 100644 index 00000000000..8d99379ffc8 --- /dev/null +++ b/channels/pjsip/cli_commands.c @@ -0,0 +1,467 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * + * \author \verbatim George Joseph \endverbatim + * + * \ingroup functions + * + * \brief PJSIP channel CLI functions + */ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include +#include +#include + +#include "asterisk/astobj2.h" +#include "asterisk/channel.h" +#include "asterisk/format.h" +#include "asterisk/res_pjsip.h" +#include "asterisk/res_pjsip_session.h" +#include "asterisk/res_pjsip_cli.h" +#include "asterisk/stasis.h" +#include "asterisk/time.h" +#include "include/chan_pjsip.h" +#include "include/cli_functions.h" + + +static int cli_channel_iterate(void *endpoint, ao2_callback_fn callback, void *arg) +{ + return ast_sip_for_each_channel(endpoint, callback, arg); +} + +static int cli_channelstats_iterate(void *endpoint, ao2_callback_fn callback, void *arg) +{ + return ast_sip_for_each_channel(endpoint, callback, arg); +} + +static int cli_channel_sort(const void *obj, const void *arg, int flags) +{ + const struct ast_channel_snapshot *left_obj = obj; + const struct ast_channel_snapshot *right_obj = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = right_obj->name; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(left_obj->name, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncmp(left_obj->name, right_key, strlen(right_key)); + break; + default: + cmp = 0; + break; + } + + return cmp; +} + +static int cli_channelstats_sort(const void *obj, const void *arg, int flags) +{ + const struct ast_channel_snapshot *left_obj = obj; + const struct ast_channel_snapshot *right_obj = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + cmp = strcmp(left_obj->bridgeid, right_obj->bridgeid); + if (cmp) { + return cmp; + } + right_key = right_obj->name; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(left_obj->name, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncmp(left_obj->name, right_key, strlen(right_key)); + break; + default: + cmp = 0; + break; + } + + return cmp; +} + +static int cli_channel_compare(void *obj, void *arg, int flags) +{ + const struct ast_channel_snapshot *left_obj = obj; + const struct ast_channel_snapshot *right_obj = arg; + const char *right_key = arg; + int cmp = 0; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = right_obj->name; + /* Fall through */ + case OBJ_SEARCH_KEY: + if (strcmp(left_obj->name, right_key) == 0) { + cmp = CMP_MATCH | CMP_STOP; + } + break; + case OBJ_SEARCH_PARTIAL_KEY: + if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) { + cmp = CMP_MATCH; + } + break; + default: + cmp = 0; + break; + } + + return cmp; +} + +static int cli_channelstats_compare(void *obj, void *arg, int flags) +{ + const struct ast_channel_snapshot *left_obj = obj; + const struct ast_channel_snapshot *right_obj = arg; + const char *right_key = arg; + int cmp = 0; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + if (strcmp(left_obj->bridgeid, right_obj->bridgeid) == 0 + && strcmp(left_obj->name, right_obj->name) == 0) { + return CMP_MATCH | CMP_STOP; + } + break; + case OBJ_SEARCH_KEY: + if (strcmp(left_obj->name, right_key) == 0) { + cmp = CMP_MATCH | CMP_STOP; + } + break; + case OBJ_SEARCH_PARTIAL_KEY: + if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) { + cmp = CMP_MATCH; + } + break; + default: + cmp = 0; + break; + } + + return cmp; +} + +static int cli_message_to_snapshot(void *obj, void *arg, int flags) +{ + struct stasis_message *message = obj; + struct ao2_container *snapshots = arg; + struct ast_channel_snapshot *snapshot = stasis_message_data(message); + + if (!strcmp(snapshot->type, "PJSIP")) { + ao2_link(snapshots, snapshot); + return CMP_MATCH; + } + + return 0; +} + +static int cli_filter_channels(void *obj, void *arg, int flags) +{ + struct ast_channel_snapshot *channel = obj; + regex_t *regexbuf = arg; + + if (!regexec(regexbuf, channel->name, 0, NULL, 0) + || !regexec(regexbuf, channel->appl, 0, NULL, 0)) { + return 0; + } + + return CMP_MATCH; +} + +static struct ao2_container *get_container(const char *regex, ao2_sort_fn sort_fn, ao2_callback_fn compare_fn) +{ + struct ao2_container *child_container; + regex_t regexbuf; + RAII_VAR(struct ao2_container *, parent_container, + stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()), ao2_cleanup); + + if (!parent_container) { + return NULL; + } + + child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, sort_fn, compare_fn); + if (!child_container) { + return NULL; + } + + ao2_callback(parent_container, OBJ_MULTIPLE | OBJ_NODATA, cli_message_to_snapshot, child_container); + + if (!ast_strlen_zero(regex)) { + if (regcomp(®exbuf, regex, REG_EXTENDED | REG_NOSUB)) { + ao2_ref(child_container, -1); + return NULL; + } + ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, ®exbuf); + regfree(®exbuf); + } + + return child_container; +} + +static struct ao2_container *cli_channel_get_container(const char *regex) +{ + return get_container(regex, cli_channel_sort, cli_channel_compare); +} + +static struct ao2_container *cli_channelstats_get_container(const char *regex) +{ + return get_container(regex, cli_channelstats_sort, cli_channelstats_compare); +} + +static const char *cli_channel_get_id(const void *obj) +{ + const struct ast_channel_snapshot *snapshot = obj; + + return snapshot->name; +} + +static void *cli_channel_retrieve_by_id(const char *id) +{ + return ast_channel_snapshot_get_latest_by_name(id); +} + +static int cli_channel_print_header(void *obj, void *arg, int flags) +{ + struct ast_sip_cli_context *context = arg; + int indent = CLI_INDENT_TO_SPACES(context->indent_level); + int filler = CLI_LAST_TABSTOP - indent - 13; + + ast_assert(context->output_buffer != NULL); + + ast_str_append(&context->output_buffer, 0, + "%*s: \n", + indent, "Channel", filler, filler, CLI_HEADER_FILLER); + if (context->recurse) { + context->indent_level++; + indent = CLI_INDENT_TO_SPACES(context->indent_level); + filler = CLI_LAST_TABSTOP - indent - 38; + ast_str_append(&context->output_buffer, 0, + "%*s: CLCID: \n", + indent, "Exten", filler, filler, CLI_HEADER_FILLER); + context->indent_level--; + } + + return 0; +} + +static int cli_channel_print_body(void *obj, void *arg, int flags) +{ + const struct ast_channel_snapshot *snapshot = obj; + struct ast_sip_cli_context *context = arg; + char *print_name = NULL; + int print_name_len; + int indent; + int flexwidth; + char *print_time = alloca(32); + + ast_assert(context->output_buffer != NULL); + + print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2; + print_name = alloca(print_name_len); + + /* Append the application */ + snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl); + + indent = CLI_INDENT_TO_SPACES(context->indent_level); + flexwidth = CLI_LAST_TABSTOP - indent; + + ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32); + + ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s %-11.11s\n", + CLI_INDENT_TO_SPACES(context->indent_level), "Channel", + flexwidth, flexwidth, + print_name, + ast_state2str(snapshot->state), + print_time); + + if (context->recurse) { + context->indent_level++; + indent = CLI_INDENT_TO_SPACES(context->indent_level); + flexwidth = CLI_LAST_TABSTOP - indent - 25; + + ast_str_append(&context->output_buffer, 0, + "%*s: %-*.*s CLCID: \"%s\" <%s>\n", + indent, "Exten", + flexwidth, flexwidth, + snapshot->exten, + snapshot->connected_name, + snapshot->connected_number + ); + context->indent_level--; + if (context->indent_level == 0) { + ast_str_append(&context->output_buffer, 0, "\n"); + } + } + + return 0; +} + +static int cli_channelstats_print_header(void *obj, void *arg, int flags) +{ + struct ast_sip_cli_context *context = arg; + + ast_assert(context->output_buffer != NULL); + + ast_str_append(&context->output_buffer, 0, + " ...........Receive......... .........Transmit..........\n" + " BridgeId ChannelId ........ UpTime.. Codec. Count Lost Pct Jitter Count Lost Pct Jitter RTT....\n" + " ================="); + + return 0; +} + +static int cli_channelstats_print_body(void *obj, void *arg, int flags) +{ + struct ast_sip_cli_context *context = arg; + const struct ast_channel_snapshot *snapshot = obj; + struct ast_channel *channel = ast_channel_get_by_name(snapshot->name); + struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL; + struct chan_pjsip_pvt *pvt = cpvt ? cpvt->pvt : NULL; + struct ast_sip_session_media *media = pvt ? pvt->media[SIP_MEDIA_AUDIO] : NULL; + struct ast_rtp_codecs *codecs = media && media->rtp ? ast_rtp_instance_get_codecs(media->rtp) : NULL; + struct ast_format *format = codecs ? ast_rtp_codecs_get_payload_format(codecs, 0) : NULL; + struct ast_rtp_instance_stats stats; + char *print_name = NULL; + char *print_time = alloca(32); + + ast_assert(context->output_buffer != NULL); + + if (!media || !media->rtp) { + ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); + ao2_cleanup(channel); + return -1; + } + + print_name = ast_strdupa(snapshot->name); + /* Skip the PJSIP/. We know what channel type it is and we need the space. */ + print_name += 6; + + ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32); + + if (ast_rtp_instance_get_stats(media->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) { + ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name); + } else { + ast_str_append(&context->output_buffer, 0, + " %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n", + snapshot->bridgeid, + print_name, + print_time, + format ? ast_format_get_name(format) : "", + stats.rxcount > 100000 ? stats.rxcount / 1000 : stats.rxcount, + stats.rxcount > 100000 ? "K": " ", + stats.rxploss > 100000 ? stats.rxploss / 1000 : stats.rxploss, + stats.rxploss > 100000 ? "K": " ", + stats.rxcount ? (stats.rxploss * 100) / stats.rxcount : 0, + MIN(stats.rxjitter, 999.999), + stats.txcount > 100000 ? stats.txcount / 1000 : stats.txcount, + stats.txcount > 100000 ? "K": " ", + stats.txploss > 100000 ? stats.txploss / 1000 : stats.txploss, + stats.txploss > 100000 ? "K": " ", + stats.txcount ? (stats.txploss * 100) / stats.txcount : 0, + MIN(stats.txjitter, 999.999), + MIN(stats.normdevrtt, 999.999) + ); + } + + ao2_cleanup(format); + ao2_cleanup(channel); + + return 0; +} + +static struct ast_cli_entry cli_commands[] = { + AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels", + .command = "pjsip list channels", + .usage = "Usage: pjsip list channels [ like ]\n" + " List the active PJSIP channels\n" + " Optional regular expression pattern is used to filter the list.\n"), + AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels", + .command = "pjsip show channels", + .usage = "Usage: pjsip show channels [ like ]\n" + " List(detailed) the active PJSIP channels\n" + " Optional regular expression pattern is used to filter the list.\n"), + AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel", + .command = "pjsip show channel", + .usage = "Usage: pjsip show channel\n" + " List(detailed) the active PJSIP channel\n"), + + AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel Stats", + .command = "pjsip show channelstats", + .usage = "Usage: pjsip show channelstats [ like ]\n" + " List(detailed) the active PJSIP channel stats\n" + " Optional regular expression pattern is used to filter the list.\n"), +}; + +struct ast_sip_cli_formatter_entry *channelstats_formatter; +struct ast_sip_cli_formatter_entry *channel_formatter; + +int pjsip_channel_cli_register(void) +{ + channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); + if (!channel_formatter) { + ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n"); + return -1; + } + channel_formatter->name = "channel"; + channel_formatter->print_header = cli_channel_print_header; + channel_formatter->print_body = cli_channel_print_body; + channel_formatter->get_container = cli_channel_get_container; + channel_formatter->iterate = cli_channel_iterate; + channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id; + channel_formatter->get_id = cli_channel_get_id; + + channelstats_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); + if (!channelstats_formatter) { + ao2_ref(channel_formatter, -1); + ast_log(LOG_ERROR, "Unable to allocate memory for channelstats_formatter\n"); + return -1; + } + channelstats_formatter->name = "channelstat"; + channelstats_formatter->print_header = cli_channelstats_print_header; + channelstats_formatter->print_body = cli_channelstats_print_body; + channelstats_formatter->get_container = cli_channelstats_get_container; + channelstats_formatter->iterate = cli_channelstats_iterate; + channelstats_formatter->retrieve_by_id = cli_channel_retrieve_by_id; + channelstats_formatter->get_id = cli_channel_get_id; + + ast_sip_register_cli_formatter(channel_formatter); + ast_sip_register_cli_formatter(channelstats_formatter); + ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + + return 0; +} + +void pjsip_channel_cli_unregister(void) +{ + ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); + ast_sip_unregister_cli_formatter(channel_formatter); + ast_sip_unregister_cli_formatter(channelstats_formatter); +} diff --git a/channels/pjsip/include/cli_functions.h b/channels/pjsip/include/cli_functions.h new file mode 100644 index 00000000000..87200774ed7 --- /dev/null +++ b/channels/pjsip/include/cli_functions.h @@ -0,0 +1,45 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC. + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * + * \author \verbatim George Joseph \endverbatim + * + * \brief PJSIP CLI functions header file + */ + +#ifndef _PJSIP_CLI_FUNCTIONS +#define _PJSIP_CLI_FUNCTIONS + + +/*! + * \brief Registers the channel cli commands + * \since 13.9.0 + * + * \retval 0 on success + * \retval -1 on failure + */ +int pjsip_channel_cli_register(void); + +/*! + * \brief Unregisters the channel cli commands + * \since 13.9.0 + */ +void pjsip_channel_cli_unregister(void); + + +#endif /* _PJSIP_CLI_FUNCTIONS */ diff --git a/res/res_pjsip/pjsip_cli.c b/res/res_pjsip/pjsip_cli.c index bbd0ac4b877..e6433f43587 100644 --- a/res/res_pjsip/pjsip_cli.c +++ b/res/res_pjsip/pjsip_cli.c @@ -197,7 +197,7 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_ ast_str_append(&context.output_buffer, 0, "\n"); formatter_entry->print_header(NULL, &context, 0); ast_str_append(&context.output_buffer, 0, - " =========================================================================================\n\n"); + "==========================================================================================\n\n"); if (is_container || cmd == CLI_GENERATE) { container = formatter_entry->get_container(regex); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 371e4318ba8..b497f02a278 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1432,235 +1432,6 @@ static struct ao2_container *cli_endpoint_get_container(const char *regex) return s_container; } -static int cli_channel_populate_container(void *obj, void *arg, int flags) -{ - struct ast_channel_snapshot *snapshot = obj; - - ao2_link(arg, snapshot); - - return 0; -} - -static int cli_channel_iterate(void *container, ao2_callback_fn callback, void *args) -{ - const struct ast_sip_endpoint *endpoint = container; - - ast_sip_for_each_channel(endpoint, callback, args); - - return 0; -} - -static int cli_channel_sort(const void *obj, const void *arg, int flags) -{ - const struct ast_channel_snapshot *left_obj = obj; - const struct ast_channel_snapshot *right_obj = arg; - const char *right_key = arg; - int cmp; - - switch (flags & OBJ_SEARCH_MASK) { - case OBJ_SEARCH_OBJECT: - right_key = right_obj->name; - /* Fall through */ - case OBJ_SEARCH_KEY: - cmp = strcmp(left_obj->name, right_key); - break; - case OBJ_SEARCH_PARTIAL_KEY: - cmp = strncmp(left_obj->name, right_key, strlen(right_key)); - break; - default: - cmp = 0; - break; - } - - return cmp; -} - -static int cli_channel_compare(void *obj, void *arg, int flags) -{ - const struct ast_channel_snapshot *left_obj = obj; - const struct ast_channel_snapshot *right_obj = arg; - const char *right_key = arg; - int cmp = 0; - - switch (flags & OBJ_SEARCH_MASK) { - case OBJ_SEARCH_OBJECT: - right_key = right_obj->name; - /* Fall through */ - case OBJ_SEARCH_KEY: - if (strcmp(left_obj->name, right_key) == 0) { - cmp = CMP_MATCH | CMP_STOP; - } - break; - case OBJ_SEARCH_PARTIAL_KEY: - if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) { - cmp = CMP_MATCH; - } - break; - default: - cmp = 0; - break; - } - - return cmp; -} - -static int cli_channel_hash(const void *obj, int flags) -{ - const struct ast_channel_snapshot *snapshot = obj; - - if (flags & OBJ_SEARCH_OBJECT) { - return ast_str_hash(snapshot->name); - } else if (flags & OBJ_SEARCH_KEY) { - return ast_str_hash(obj); - } - - return -1; -} - -static int cli_endpoint_gather_channels(void *obj, void *arg, int flags) -{ - struct ast_sip_endpoint *endpoint = obj; - struct ao2_container *channels = arg; - - ast_sip_for_each_channel(endpoint, cli_channel_populate_container, channels); - - return 0; -} - -static int cli_filter_channels(void *obj, void *arg, int flags) -{ - struct ast_channel_snapshot *channel = obj; - regex_t *regexbuf = arg; - - if (!regexec(regexbuf, channel->name, 0, NULL, 0) - || !regexec(regexbuf, channel->appl, 0, NULL, 0)) { - return 0; - } - - return CMP_MATCH; -} - -static struct ao2_container *cli_channel_get_container(const char *regex) -{ - RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup); - struct ao2_container *child_container; - regex_t regexbuf; - - parent_container = cli_endpoint_get_container(""); - if (!parent_container) { - return NULL; - } - child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17, - cli_channel_hash, cli_channel_sort, cli_channel_compare); - if (!child_container) { - return NULL; - } - - ao2_callback(parent_container, OBJ_NODATA, cli_endpoint_gather_channels, child_container); - - if (!ast_strlen_zero(regex)) { - if (regcomp(®exbuf, regex, REG_EXTENDED | REG_NOSUB)) { - ao2_ref(child_container, -1); - return NULL; - } - ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, ®exbuf); - regfree(®exbuf); - } - - return child_container; -} - -static const char *cli_channel_get_id(const void *obj) -{ - const struct ast_channel_snapshot *snapshot = obj; - - return snapshot->name; -} - -static void *cli_channel_retrieve_by_id(const char *id) -{ - RAII_VAR(struct ao2_container *, container, cli_channel_get_container(""), ao2_cleanup); - - return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK); -} - -static int cli_channel_print_header(void *obj, void *arg, int flags) -{ - struct ast_sip_cli_context *context = arg; - int indent = CLI_INDENT_TO_SPACES(context->indent_level); - int filler = CLI_LAST_TABSTOP - indent - 13; - - ast_assert(context->output_buffer != NULL); - - ast_str_append(&context->output_buffer, 0, - "%*s: \n", - indent, "Channel", filler, filler, CLI_HEADER_FILLER); - if (context->recurse) { - context->indent_level++; - indent = CLI_INDENT_TO_SPACES(context->indent_level); - filler = CLI_LAST_TABSTOP - indent - 38; - ast_str_append(&context->output_buffer, 0, - "%*s: CLCID: \n", - indent, "Exten", filler, filler, CLI_HEADER_FILLER); - context->indent_level--; - } - - return 0; -} - -static int cli_channel_print_body(void *obj, void *arg, int flags) -{ - const struct ast_channel_snapshot *snapshot = obj; - struct ast_sip_cli_context *context = arg; - struct timeval current_time; - char *print_name = NULL; - int print_name_len; - int indent; - int flexwidth; - - ast_assert(context->output_buffer != NULL); - - gettimeofday(¤t_time, NULL); - - print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2; - if (!(print_name = alloca(print_name_len))) { - return -1; - } - - snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl); - - indent = CLI_INDENT_TO_SPACES(context->indent_level); - flexwidth = CLI_LAST_TABSTOP - indent; - - ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s %11ld\n", - CLI_INDENT_TO_SPACES(context->indent_level), "Channel", - flexwidth, flexwidth, - print_name, - ast_state2str(snapshot->state), - current_time.tv_sec - snapshot->creationtime.tv_sec); - - if (context->recurse) { - context->indent_level++; - indent = CLI_INDENT_TO_SPACES(context->indent_level); - flexwidth = CLI_LAST_TABSTOP - indent - 25; - - ast_str_append(&context->output_buffer, 0, - "%*s: %-*.*s CLCID: \"%s\" <%s>\n", - indent, "Exten", - flexwidth, flexwidth, - snapshot->exten, - snapshot->connected_name, - snapshot->connected_number - ); - context->indent_level--; - if (context->indent_level == 0) { - ast_str_append(&context->output_buffer, 0, "\n"); - } - } - - return 0; -} - static int cli_endpoint_iterate(void *obj, ao2_callback_fn callback, void *args) { ao2_callback(obj, OBJ_NODATA, callback, args); @@ -1779,21 +1550,6 @@ static int cli_endpoint_print_body(void *obj, void *arg, int flags) } static struct ast_cli_entry cli_commands[] = { - AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels", - .command = "pjsip list channels", - .usage = "Usage: pjsip list channels [ like ]\n" - " List the active PJSIP channels\n" - " Optional regular expression pattern is used to filter the list.\n"), - AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels", - .command = "pjsip show channels", - .usage = "Usage: pjsip show channels [ like ]\n" - " List(detailed) the active PJSIP channels\n" - " Optional regular expression pattern is used to filter the list.\n"), - AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel", - .command = "pjsip show channel", - .usage = "Usage: pjsip show channel\n" - " List(detailed) the active PJSIP channel\n"), - AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints", .command = "pjsip list endpoints", .usage = "Usage: pjsip list endpoints [ like ]\n" @@ -1987,21 +1743,6 @@ int ast_res_pjsip_initialize_configuration(void) return -1; } - channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); - if (!channel_formatter) { - ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n"); - ast_sorcery_unref(sip_sorcery); - sip_sorcery = NULL; - return -1; - } - channel_formatter->name = "channel"; - channel_formatter->print_header = cli_channel_print_header; - channel_formatter->print_body = cli_channel_print_body; - channel_formatter->get_container = cli_channel_get_container; - channel_formatter->iterate = cli_channel_iterate; - channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id; - channel_formatter->get_id = cli_channel_get_id; - endpoint_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); if (!endpoint_formatter) { ast_log(LOG_ERROR, "Unable to allocate memory for endpoint_formatter\n"); @@ -2017,7 +1758,6 @@ int ast_res_pjsip_initialize_configuration(void) endpoint_formatter->retrieve_by_id = cli_endpoint_retrieve_by_id; endpoint_formatter->get_id = ast_sorcery_object_get_id; - ast_sip_register_cli_formatter(channel_formatter); ast_sip_register_cli_formatter(endpoint_formatter); ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); @@ -2044,7 +1784,6 @@ void ast_res_pjsip_destroy_configuration(void) ast_manager_unregister(AMI_SHOW_ENDPOINTS); ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(endpoint_formatter); - ast_sip_unregister_cli_formatter(channel_formatter); ast_sip_destroy_cli(); ao2_cleanup(persistent_endpoints); } From 724b9ab28fecd06b0a1c13e0b71024728336bfe8 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 30 Mar 2016 08:46:32 -0600 Subject: [PATCH 0307/1578] res_rtp_asterisk: Fix placement of txcount increment Commit 1bce690ccb36a4744a327c07af23a9a3a0fa20cd was incrementing txcount for rtcp packets as well as rtp packets and that was causing sender reports to be generated instead of receiver reports in cases where no rtp was actually being sent. Moved the txcount increment from __rtp_sento, which handles both rtp and rtcp, to rtp_sento which only handles rtp packets. Discovered by the hep/rtcp-receiver test. Change-Id: Ie442e4bb947a68847a676497021ba10ffaf376d5 --- res/res_rtp_asterisk.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 45bc3103ae9..9cc9f92a903 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2252,7 +2252,6 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance); int res; - int hdrlen = 12; *ice = 0; @@ -2260,9 +2259,6 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz return -1; } - rtp->txcount++; - rtp->txoctetcount += (len - hdrlen); - #ifdef HAVE_PJPROJECT if (rtp->ice) { pj_thread_register_check(); @@ -2289,7 +2285,16 @@ static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice) { - return __rtp_sendto(instance, buf, size, flags, sa, 0, ice, 1); + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + int hdrlen = 12; + int res; + + if ((res = __rtp_sendto(instance, buf, size, flags, sa, 0, ice, 1)) > 0) { + rtp->txcount++; + rtp->txoctetcount += (res - hdrlen); + } + + return res; } static int rtp_get_rate(struct ast_format *format) From e2524fcee350e4336e67888a26c5f9656afe7d06 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 24 Mar 2016 21:55:03 -0600 Subject: [PATCH 0308/1578] res_pjsip_mwi: Add voicemail extension and mwi_subscribe_replaces_unsolicited res_pjsip_mwi was missing the chan_sip "vmexten" functionality which adds the Message-Account header to the MWI NOTIFY. Also, specifying mailboxes on endpoints for unsolicited mwi and on aors for subscriptions required that the admin know in advance which the client wanted. If you specified mailboxes on the endpoint, subscriptions were rejected even if you also specified mailboxes on the aor. Voicemail extension: * Added a global default_voicemail_extension which defaults to "". * Added voicemail_extension to both endpoint and aor. * Added ast_sip_subscription_get_dialog for support. * Added ast_sip_subscription_get_sip_uri for support. When an unsolicited NOTIFY is constructed, the From header is parsed, the voicemail extension from the endpoint is substituted for the user, and the result placed in the Message-Account field in the body. When a subscribed NOTIFY is constructed, the subscription dialog local uri is parsed, the voicemail_extension from the aor (looked up from the subscription resource name) is substituted for the user, and the result placed in the Message-Account field in the body. If no voicemail extension was defined, the Message-Account field is not added to the NOTIFY body. mwi_subscribe_replaces_unsolicited: * Added mwi_subscribe_replaces_unsolicited to endpoint. The previous behavior was to reject a subscribe if a previous internal subscription for unsolicited MWI was found for the mailbox. That remains the default. However, if there are mailboxes also set on the aor and the client subscribes and mwi_subscribe_replaces_unsolicited is set, the existing internal subscription is removed and replaced with the external subscription. This allows an admin to configure mailboxes on both the endpoint and aor and allows the client to select which to use. ASTERISK-25865 #close Reported-by: Ross Beer Change-Id: Ic15a9415091760539c7134a5ba3dc4a6a1217cea --- configs/samples/pjsip.conf.sample | 28 +++- .../1c688d9a003c_pjsip_voicemail_extension.py | 31 +++++ include/asterisk/res_pjsip.h | 17 +++ .../asterisk/res_pjsip_body_generator_types.h | 2 + include/asterisk/res_pjsip_pubsub.h | 20 +++ res/res_pjsip.c | 12 ++ res/res_pjsip/config_global.c | 44 ++++-- res/res_pjsip/location.c | 20 +++ res/res_pjsip/pjsip_configuration.c | 20 +++ res/res_pjsip_mwi.c | 130 +++++++++++++----- res/res_pjsip_mwi_body_generator.c | 5 +- res/res_pjsip_pubsub.c | 11 ++ res/res_pjsip_pubsub.exports.in | 40 +----- 13 files changed, 288 insertions(+), 92 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index faa92859811..94d17920860 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -624,7 +624,14 @@ ; "username") ;redirect_method=user ; How redirects received from an endpoint are handled ; (default: "user") -;mailboxes= ; Mailbox es to be associated with (default: "") +;mailboxes= ; NOTIFY the endpoint when state changes for any of the specified mailboxes. + ; Asterisk will send unsolicited MWI NOTIFY messages to the endpoint when state + ; changes happen for any of the specified mailboxes. (default: "") +;voicemail_extension= ; The voicemail extension to send in the NOTIFY Message-Account header + ; (default: global/default_voicemail_extension) +;mwi_subscribe_replaces_unsolicited=no + ; An MWI subscribe will replace unsoliticed NOTIFYs + ; (default: "no") ;moh_suggest=default ; Default Music On Hold class (default: "default") ;moh_passthrough=yes ; Pass Music On Hold through using SIP re-invites with sendonly ; when placing on hold and sendrecv when taking off hold @@ -832,7 +839,11 @@ ;default_expiration=3600 ; Default expiration time in seconds for ; contacts that are dynamically bound to an AoR ; (default: "3600") -;mailboxes= ; Mailbox es to be associated with (default: "") +;mailboxes= ; Allow subscriptions for the specified mailbox(es) + ; This option applies when an external entity subscribes to an AoR + ; for Message Waiting Indications. (default: "") +;voicemail_extension= ; The voicemail extension to send in the NOTIFY Message-Account header + ; (default: global/default_voicemail_extension) ;maximum_expiration=7200 ; Maximum time to keep an AoR (default: "7200") ;max_contacts=0 ; Maximum number of contacts that can bind to an AoR (default: ; "0") @@ -904,10 +915,15 @@ ; startup that qualifies should be attempted on all ; contacts. If greater than the qualify_frequency ; for an aor, qualify_frequency will be used instead. -; If regcontext is specified, Asterisk will dynamically create and destroy a -; NoOp priority 1 extension for a given endpoint who registers or unregisters -; with us. The extension added is the name of the endpoint. -;regcontext=sipregistrations +;regcontext=sipregistrations ; If regcontext is specified, Asterisk will dynamically + ; create and destroy a NoOp priority 1 extension for a + ; given endpoint who registers or unregisters with us. + ; The extension added is the name of the endpoint. +;default_voicemail_extension=asterisk + ; The voicemail extension to send in the NOTIFY Message-Account header + ; if not set on endpoint or aor. + ; (default: "") + ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl ;==========================ACL SECTION OPTIONS========================= diff --git a/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py new file mode 100644 index 00000000000..781dca703ba --- /dev/null +++ b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py @@ -0,0 +1,31 @@ +"""pjsip voicemail extension + +Revision ID: 1c688d9a003c +Revises: 5813202e92be +Create Date: 2016-03-24 22:31:45.537895 + +""" + +# revision identifiers, used by Alembic. +revision = '1c688d9a003c' +down_revision = '5813202e92be' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_globals', sa.Column('default_voicemail_extension', sa.String(40))) + op.add_column('ps_aors', sa.Column('voicemail_extension', sa.String(40))) + op.add_column('ps_endpoints', sa.Column('voicemail_extension', sa.String(40))) + op.add_column('ps_endpoints', sa.Column('mwi_subscribe_replaces_unsolicited', sa.Integer)) + + +def downgrade(): + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('default_voicemail_extension') + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.drop_column('voicemail_extension') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('voicemail_extension') + batch_op.drop_column('mwi_subscribe_replaces_unsolicited') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index b0ae2cefaf7..2c26c25dabb 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -312,6 +312,8 @@ struct ast_sip_aor { unsigned int support_path; /*! Qualify timeout. 0 is diabled. */ double qualify_timeout; + /* Voicemail extension to set in Message-Account */ + char *voicemail_extension; }; /*! @@ -466,6 +468,10 @@ struct ast_sip_mwi_configuration { ); /* Should mailbox states be combined into a single notification? */ unsigned int aggregate; + /* Should a subscribe replace unsolicited notifies? */ + unsigned int subscribe_replaces_unsolicited; + /* Voicemail extension to set in Message-Account */ + char *voicemail_extension; }; /*! @@ -2117,6 +2123,16 @@ char *ast_sip_get_regcontext(void); */ char *ast_sip_get_endpoint_identifier_order(void); +/*! + * \brief Retrieve the default voicemail extension. + * \since 13.9.0 + * + * \note returned string needs to be de-allocated by caller. + * + * \retval the default voicemail extension + */ +char *ast_sip_get_default_voicemail_extension(void); + /*! * \brief Retrieve the global default from user. * @@ -2265,4 +2281,5 @@ int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id); + #endif /* _RES_PJSIP_H */ diff --git a/include/asterisk/res_pjsip_body_generator_types.h b/include/asterisk/res_pjsip_body_generator_types.h index a2cc04313ba..aab14723860 100644 --- a/include/asterisk/res_pjsip_body_generator_types.h +++ b/include/asterisk/res_pjsip_body_generator_types.h @@ -65,6 +65,8 @@ struct ast_sip_message_accumulator { int old_msgs; /*! Number of new messages */ int new_msgs; + /*! Message-Account */ + char message_account[PJSIP_MAX_URL_SIZE]; }; #endif /* _RES_PJSIP_BODY_GENERATOR_TYPES_H */ diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h index c9b66dce342..84d86fb9ef4 100644 --- a/include/asterisk/res_pjsip_pubsub.h +++ b/include/asterisk/res_pjsip_pubsub.h @@ -339,6 +339,14 @@ struct ast_sip_subscription_handler { struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, const char *resource); +/*! + * \brief Get the pjsip dialog that is associated with this subscription + * \since 13.9.0 + * + * \retval NULL Could not get dialog + * \retval non-NULL The dialog + */ +pjsip_dialog *ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub); /*! * \brief Get the endpoint that is associated with this subscription @@ -378,6 +386,18 @@ struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_sub */ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data, int terminate); +/*! + * \brief Retrieve the local sip uri for this subscription + * \since 13.9.0 + * + * This is the local sip URI of the subscribed resource. + * + * \param sub The subscription + * \retval NULL Could not get uri + * \retval non-NULL The local pjsip_sip_uri + */ +pjsip_sip_uri *ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub); + /*! * \brief Retrieve the local URI for this subscription * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index b9d6cb6de1e..f4dc72549b4 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -302,6 +302,12 @@ configuration. + + An MWI subscribe will replace sending unsolicited NOTIFYs + + + The voicemail extension to send in the NOTIFY Message-Account header + Default Music On Hold class @@ -1138,6 +1144,9 @@ endpoint configuration section to enable unsolicited MWI NOTIFYs to the endpoint. + + The voicemail extension to send in the NOTIFY Message-Account header + Maximum time to keep an AoR @@ -1302,6 +1311,9 @@ Endpoint to use when sending an outbound request to a URI without a specified endpoint. + + The voicemail extension to send in the NOTIFY Message-Account header if not specified on endpoint or aor + Enable/Disable SIP debug logging. Valid options include yes|no or a host address diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index c0fede64d68..ad03379fdb1 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -37,6 +37,7 @@ #define DEFAULT_FROM_USER "asterisk" #define DEFAULT_REGCONTEXT "" #define DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL 30 +#define DEFAULT_VOICEMAIL_EXTENSION "" static char default_useragent[256]; @@ -52,6 +53,8 @@ struct global_config { AST_STRING_FIELD(endpoint_identifier_order); /*! User name to place in From header if there is no better option */ AST_STRING_FIELD(default_from_user); + /*! Default voicemail extension */ + AST_STRING_FIELD(default_voicemail_extension); ); /* Value to put in Max-Forwards header */ unsigned int max_forwards; @@ -144,20 +147,35 @@ char *ast_sip_get_debug(void) char *ast_sip_get_regcontext(void) { - char *res; - struct global_config *cfg; + char *res; + struct global_config *cfg; - cfg = get_global_cfg(); - if (!cfg) { - return ast_strdup(DEFAULT_REGCONTEXT); - } + cfg = get_global_cfg(); + if (!cfg) { + return ast_strdup(DEFAULT_REGCONTEXT); + } - res = ast_strdup(cfg->regcontext); - ao2_ref(cfg, -1); + res = ast_strdup(cfg->regcontext); + ao2_ref(cfg, -1); - return res; + return res; } +char *ast_sip_get_default_voicemail_extension(void) +{ + char *res; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return ast_strdup(DEFAULT_VOICEMAIL_EXTENSION); + } + + res = ast_strdup(cfg->default_voicemail_extension); + ao2_ref(cfg, -1); + + return res; +} char *ast_sip_get_endpoint_identifier_order(void) { @@ -347,12 +365,14 @@ int ast_sip_initialize_sorcery_global(void) OPT_UINT_T, 0, FLDSET(struct global_config, max_initial_qualify_time)); ast_sorcery_object_field_register(sorcery, "global", "default_from_user", DEFAULT_FROM_USER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_from_user)); + ast_sorcery_object_field_register(sorcery, "global", "default_voicemail_extension", + DEFAULT_VOICEMAIL_EXTENSION, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, + default_voicemail_extension)); ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT, - OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); + OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval", __stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL), - OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); - + OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 4008abad1f9..3145daca027 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -35,6 +35,7 @@ static void aor_destroy(void *obj) ao2_cleanup(aor->permanent_contacts); ast_string_field_free_memory(aor); + ast_free(aor->voicemail_extension); } /*! \brief Allocator for AOR */ @@ -437,6 +438,24 @@ static int contacts_to_var_list(const void *obj, struct ast_variable **fields) return 0; } +static int voicemail_extension_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_aor *aor = obj; + + aor->voicemail_extension = ast_strdup(var->value); + + return aor->voicemail_extension ? 0 : -1; +} + +static int voicemail_extension_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_aor *aor = obj; + + *buf = ast_strdup(aor->voicemail_extension); + + return 0; +} + int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) { char *copy, *name; @@ -987,6 +1006,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing)); ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes)); + ast_sorcery_object_field_register_custom(sorcery, "aor", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path)); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index b497f02a278..baa5063e43c 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1052,6 +1052,23 @@ static int set_var_to_vl(const void *obj, struct ast_variable **fields) return 0; } +static int voicemail_extension_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_endpoint *endpoint = obj; + + endpoint->subscription.mwi.voicemail_extension = ast_strdup(var->value); + + return endpoint->subscription.mwi.voicemail_extension ? 0 : -1; +} + +static int voicemail_extension_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + *buf = ast_strdup(endpoint->subscription.mwi.voicemail_extension); + + return 0; +} static void *sip_nat_hook_alloc(const char *name) { @@ -1647,7 +1664,9 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rpid_immediate", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.rpid_immediate)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes)); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_subscribe_replaces_unsolicited", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.subscribe_replaces_unsolicited)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp)); @@ -1799,6 +1818,7 @@ int ast_res_pjsip_reload_configuration(void) static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription) { ast_string_field_free_memory(&subscription->mwi); + ast_free(subscription->mwi.voicemail_extension); } static void info_configuration_destroy(struct ast_sip_endpoint_info_configuration *info) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index be38b44c1fc..bb8f004e352 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -42,6 +42,8 @@ struct mwi_subscription; static struct ao2_container *unsolicited_mwi; +static char *default_voicemail_extension; + #define STASIS_BUCKETS 13 #define MWI_BUCKETS 53 @@ -326,11 +328,30 @@ static int get_message_count(void *obj, void *arg, int flags) return 0; } +static void set_voicemail_extension(pj_pool_t *pool, pjsip_sip_uri *local_uri, + struct ast_sip_message_accumulator *counter, const char *voicemail_extension) +{ + pjsip_sip_uri *account_uri; + const char *vm_exten; + + if (ast_strlen_zero(voicemail_extension)) { + vm_exten = default_voicemail_extension; + } else { + vm_exten = voicemail_extension; + } + + if (!ast_strlen_zero(vm_exten)) { + account_uri = pjsip_uri_clone(pool, local_uri); + pj_strdup2(pool, &account_uri->user, vm_exten); + pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, account_uri, counter->message_account, sizeof(counter->message_account)); + } +} + struct unsolicited_mwi_data { struct mwi_subscription *sub; struct ast_sip_endpoint *endpoint; pjsip_evsub_state state; - const struct ast_sip_body *body; + struct ast_sip_message_accumulator *counter; }; static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flags) @@ -339,27 +360,50 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag struct mwi_subscription *sub = mwi_data->sub; struct ast_sip_endpoint *endpoint = mwi_data->endpoint; pjsip_evsub_state state = mwi_data->state; - const struct ast_sip_body *body = mwi_data->body; struct ast_sip_contact *contact = obj; const char *state_name; pjsip_tx_data *tdata; pjsip_sub_state_hdr *sub_state; pjsip_event_hdr *event; + pjsip_from_hdr *from; + pjsip_sip_uri *from_uri; const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(NULL); + struct ast_sip_body body; + struct ast_str *body_text; + struct ast_sip_body_data body_data = { + .body_type = AST_SIP_MESSAGE_ACCUMULATOR, + .body_data = mwi_data->counter, + }; if (ast_sip_create_request("NOTIFY", NULL, endpoint, NULL, contact, &tdata)) { ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->id, contact->uri); return 0; } - if (!ast_strlen_zero(endpoint->subscription.mwi.fromuser)) { - pjsip_fromto_hdr *from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL); - pjsip_name_addr *from_name_addr = (pjsip_name_addr *) from->uri; - pjsip_sip_uri *from_uri = pjsip_uri_get_uri(from_name_addr->uri); + body.type = MWI_TYPE; + body.subtype = MWI_SUBTYPE; + body_text = ast_str_create(64); + if (!body_text) { + return 0; + } + from = PJSIP_MSG_FROM_HDR(tdata->msg); + from_uri = pjsip_uri_get_uri(from->uri); + + if (!ast_strlen_zero(endpoint->subscription.mwi.fromuser)) { pj_strdup2(tdata->pool, &from_uri->user, endpoint->subscription.mwi.fromuser); } + set_voicemail_extension(tdata->pool, from_uri, mwi_data->counter, endpoint->subscription.mwi.voicemail_extension); + + if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) { + ast_log(LOG_WARNING, "Unable to generate SIP MWI NOTIFY body.\n"); + ast_free(body_text); + return 0; + } + + body.body_text = ast_str_buffer(body_text); + switch (state) { case PJSIP_EVSUB_STATE_ACTIVE: state_name = "active"; @@ -379,9 +423,11 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event); pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, allow_events)); - ast_sip_add_body(tdata, body); + ast_sip_add_body(tdata, &body); ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL); + ast_free(body_text); + return 0; } @@ -392,12 +438,6 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, "endpoint", sub->id), ao2_cleanup); char *endpoint_aors; char *aor_name; - struct ast_sip_body body; - struct ast_str *body_text; - struct ast_sip_body_data body_data = { - .body_type = AST_SIP_MESSAGE_ACCUMULATOR, - .body_data = counter, - }; if (!endpoint) { ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because endpoint does not exist\n", @@ -410,23 +450,6 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, return; } - body.type = MWI_TYPE; - body.subtype = MWI_SUBTYPE; - - body_text = ast_str_create(64); - - if (!body_text) { - return; - } - - if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) { - ast_log(LOG_WARNING, "Unable to generate SIP MWI NOTIFY body.\n"); - ast_free(body_text); - return; - } - - body.body_text = ast_str_buffer(body_text); - endpoint_aors = ast_strdupa(endpoint->aors); ast_debug(5, "Sending unsolicited MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n", @@ -438,7 +461,7 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, struct unsolicited_mwi_data mwi_data = { .sub = sub, .endpoint = endpoint, - .body = &body, + .counter = counter, }; if (!aor) { @@ -454,8 +477,6 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, ao2_callback(contacts, OBJ_NODATA, send_unsolicited_mwi_notify_to_contact, &mwi_data); } - - ast_free(body_text); } static void send_mwi_notify(struct mwi_subscription *sub) @@ -463,6 +484,7 @@ static void send_mwi_notify(struct mwi_subscription *sub) struct ast_sip_message_accumulator counter = { .old_msgs = 0, .new_msgs = 0, + .message_account[0] = '\0', }; struct ast_sip_body_data data = { .body_type = AST_SIP_MESSAGE_ACCUMULATOR, @@ -472,7 +494,17 @@ static void send_mwi_notify(struct mwi_subscription *sub) ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter); if (sub->is_solicited) { + struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(ast_sip_subscription_get_resource_name(sub->sip_sub)); + pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub->sip_sub); + pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub->sip_sub); + + if (aor && dlg && sip_uri) { + set_voicemail_extension(dlg->pool, sip_uri, &counter, aor->voicemail_extension); + } + + ao2_cleanup(aor); ast_sip_subscription_notify(sub->sip_sub, &data, 0); + return; } @@ -565,7 +597,12 @@ static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint mwi_stasis = ao2_find(mwi_sub->stasis_subs, mailbox, OBJ_SEARCH_KEY); if (mwi_stasis) { - ret = 1; + if (endpoint->subscription.mwi.subscribe_replaces_unsolicited) { + unsubscribe_stasis(mwi_stasis, NULL, 0); + ao2_unlink(mwi_sub->stasis_subs, mwi_stasis); + } else { + ret = 1; + } ao2_cleanup(mwi_stasis); } } @@ -771,6 +808,7 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub) struct ast_sip_message_accumulator *counter; struct mwi_subscription *mwi_sub; struct ast_datastore *mwi_datastore; + struct ast_sip_aor *aor; mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE); if (!mwi_datastore) { @@ -784,6 +822,16 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub) return NULL; } + if ((aor = ast_sip_location_retrieve_aor(ast_sip_subscription_get_resource_name(sub)))) { + pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub); + pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub); + + if (dlg && sip_uri) { + set_voicemail_extension(dlg->pool, sip_uri, counter, aor->voicemail_extension); + } + ao2_ref(aor, -1); + } + ao2_callback(mwi_sub->stasis_subs, OBJ_NODATA, get_message_count, counter); ao2_cleanup(mwi_datastore); return counter; @@ -1084,6 +1132,16 @@ static void mwi_startup_event_cb(void *data, struct stasis_subscription *sub, st stasis_unsubscribe(sub); } +static void global_loaded(const char *object_type) +{ + ast_free(default_voicemail_extension); + default_voicemail_extension = ast_sip_get_default_voicemail_extension(); +} + +static struct ast_sorcery_observer global_observer = { + .loaded = global_loaded, +}; + static int reload(void) { create_mwi_subscriptions(); @@ -1106,6 +1164,8 @@ static int load_module(void) create_mwi_subscriptions(); ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); + ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer); + ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { ast_sip_push_task(NULL, send_initial_notify_all, NULL); @@ -1120,8 +1180,10 @@ static int unload_module(void) { ao2_callback(unsolicited_mwi, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL); ao2_ref(unsolicited_mwi, -1); + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); ast_sip_unregister_subscription_handler(&mwi_handler); + ast_free(default_voicemail_extension); return 0; } diff --git a/res/res_pjsip_mwi_body_generator.c b/res/res_pjsip_mwi_body_generator.c index e4b39d534fa..f46ce04e396 100644 --- a/res/res_pjsip_mwi_body_generator.c +++ b/res/res_pjsip_mwi_body_generator.c @@ -46,7 +46,7 @@ static void *mwi_allocate_body(void *data) if (!mwi_str) { return NULL; } - *mwi_str = ast_str_create(64); + *mwi_str = ast_str_create(128); if (!*mwi_str) { ast_free(mwi_str); return NULL; @@ -63,6 +63,9 @@ static int mwi_generate_body_content(void *body, void *data) counter->new_msgs ? "yes" : "no"); ast_str_append(mwi, 0, "Voice-Message: %d/%d (0/0)\r\n", counter->new_msgs, counter->old_msgs); + if (!ast_strlen_zero(counter->message_account)) { + ast_str_append(mwi, 0, "Message-Account: %s\r\n", counter->message_account); + } return 0; } diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 57ca95d8c64..141c2fcf405 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1644,6 +1644,12 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su return sub; } +pjsip_dialog *ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub) +{ + ast_assert(sub->tree->dlg != NULL); + return sub->tree->dlg; +} + struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub) { ast_assert(sub->tree->endpoint != NULL); @@ -2271,6 +2277,11 @@ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip return res; } +pjsip_sip_uri *ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub) +{ + return sub->uri; +} + void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size) { pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size); diff --git a/res/res_pjsip_pubsub.exports.in b/res/res_pjsip_pubsub.exports.in index 661652489a5..a75103bb6c3 100644 --- a/res/res_pjsip_pubsub.exports.in +++ b/res/res_pjsip_pubsub.exports.in @@ -1,44 +1,6 @@ { global: - LINKER_SYMBOL_PREFIXast_sip_create_subscription; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_endpoint; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_serializer; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_evsub; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_dlg; - LINKER_SYMBOL_PREFIXast_sip_subscription_accept; - LINKER_SYMBOL_PREFIXast_sip_subscription_send_request; - LINKER_SYMBOL_PREFIXast_sip_subscription_alloc_datastore; - LINKER_SYMBOL_PREFIXast_sip_subscription_add_datastore; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_datastore; - LINKER_SYMBOL_PREFIXast_sip_subscription_remove_datastore; - LINKER_SYMBOL_PREFIXast_sip_register_subscription_handler; - LINKER_SYMBOL_PREFIXast_sip_unregister_subscription_handler; - LINKER_SYMBOL_PREFIXast_sip_create_publication; - LINKER_SYMBOL_PREFIXast_sip_publication_get_endpoint; - LINKER_SYMBOL_PREFIXast_sip_publication_get_resource; - LINKER_SYMBOL_PREFIXast_sip_publication_get_event_configuration; - LINKER_SYMBOL_PREFIXast_sip_publication_create_response; - LINKER_SYMBOL_PREFIXast_sip_publication_send_response; - LINKER_SYMBOL_PREFIXast_sip_register_publish_handler; - LINKER_SYMBOL_PREFIXast_sip_unregister_publish_handler; - LINKER_SYMBOL_PREFIXast_sip_publication_add_datastore; - LINKER_SYMBOL_PREFIXast_sip_publication_get_datastore; - LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore; - LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore; - LINKER_SYMBOL_PREFIXast_sip_pubsub_register_body_generator; - LINKER_SYMBOL_PREFIXast_sip_pubsub_unregister_body_generator; - LINKER_SYMBOL_PREFIXast_sip_pubsub_register_body_supplement; - LINKER_SYMBOL_PREFIXast_sip_pubsub_unregister_body_supplement; - LINKER_SYMBOL_PREFIXast_sip_pubsub_generate_body_content; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_body_type; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_body_subtype; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_resource_name; - LINKER_SYMBOL_PREFIXast_sip_subscription_notify; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_local_uri; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_remote_uri; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_header; - LINKER_SYMBOL_PREFIXast_sip_subscription_is_terminated; - LINKER_SYMBOL_PREFIXast_sip_subscription_destroy; + LINKER_SYMBOL_PREFIXast_sip_*; local: *; }; From 2b3261cd36f48437fe82eae3fb0a8eea1f292e2e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 30 Mar 2016 11:38:47 -0600 Subject: [PATCH 0309/1578] res_pjsip_mwi: Allow subscribe to vm access extension as an alias Background: If your extension is 1000 and the voicemail access extension is 1571 and you dial 1571, usually a dialplan rule calls voicemailmain with your extension and you are placed directly in your mailbox. Therefore most admins program the voicemail (or other speed dial) button on their phones to the access extension. Some phones (Snom at least) use whatever is programmed there to also subscribe for MWI and so can't dial one number and subscribe to another. This works fine in chan_sip because chan_sip completely ignores the user portion of the SUBSCRIBE message request URI. If it can match the peer, is subscribes to the peer's mailbox. The user could be set to anything or nothing and you'd still get subscribed to your mailbox. Issue: chan_pjsip actually uses the user portion of the URI to find an aor and its mailboxes. Therefore a subscribe to 1571 results in a 404. Sure, you can create an aor for 1571 but you certainly can't add your entire voicemail system's mailboxes to it and everyone would get notified of every MWI. Solution: When an MWI subscribe comes in and an aor can't be found that matches the resource directly, check the resource against the endpoint's aors. If an aor is found that has a voicemail_extension that matches the resource, use it. ASTERISK-25865 Reported-by: Ross Beer Change-Id: I770ea185f751f1ada888fafb4b452115f1c06e9e --- res/res_pjsip_mwi.c | 62 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index bb8f004e352..a954c9c66bb 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -431,6 +431,45 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag return 0; } +static struct ast_sip_aor *find_aor_for_resource(struct ast_sip_endpoint *endpoint, const char *resource) +{ + struct ast_sip_aor *aor; + char *aor_name; + char *aors_copy; + + /* Direct match */ + if ((aor = ast_sip_location_retrieve_aor(resource))) { + return aor; + } + + if (!endpoint) { + return NULL; + } + + /* + * This may be a subscribe to the voicemail_extension. If so, + * look for an aor belonging to this endpoint that has a matching + * voicemail_extension. + */ + aors_copy = ast_strdupa(endpoint->aors); + while ((aor_name = ast_strip(strsep(&aors_copy, ",")))) { + struct ast_sip_aor *check_aor = ast_sip_location_retrieve_aor(aor_name); + + if (!check_aor) { + continue; + } + + if (!strcasecmp(check_aor->voicemail_extension, resource)) { + ast_debug(1, "Found an aor (%s) that matches voicemail_extension %s\n", aor_name, resource); + return check_aor; + } + + ao2_ref(check_aor, -1); + } + + return NULL; +} + static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, struct ast_sip_message_accumulator *counter) { @@ -490,11 +529,13 @@ static void send_mwi_notify(struct mwi_subscription *sub) .body_type = AST_SIP_MESSAGE_ACCUMULATOR, .body_data = &counter, }; + const char *resource = ast_sip_subscription_get_resource_name(sub->sip_sub); ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter); if (sub->is_solicited) { - struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(ast_sip_subscription_get_resource_name(sub->sip_sub)); + struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sub->sip_sub); + struct ast_sip_aor *aor = find_aor_for_resource(endpoint, resource); pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub->sip_sub); pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub->sip_sub); @@ -503,6 +544,7 @@ static void send_mwi_notify(struct mwi_subscription *sub) } ao2_cleanup(aor); + ao2_cleanup(endpoint); ast_sip_subscription_notify(sub->sip_sub, &data, 0); return; @@ -707,14 +749,9 @@ static struct mwi_subscription *mwi_subscribe_single( struct ast_sip_aor *aor; struct mwi_subscription *sub; - aor = ast_sip_location_retrieve_aor(name); + aor = find_aor_for_resource(endpoint, name); if (!aor) { - /*! I suppose it's possible for the AOR to disappear on us - * between accepting the subscription and sending the first - * NOTIFY... - */ - ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n", - name); + ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n", name); return NULL; } @@ -753,10 +790,9 @@ static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint, return 200; } - aor = ast_sip_location_retrieve_aor(resource); + aor = find_aor_for_resource(endpoint, resource); if (!aor) { - ast_debug(1, "Unable to locate aor %s. MWI subscription failed.\n", - resource); + ast_debug(1, "Unable to locate aor %s. MWI subscription failed.\n", resource); return 404; } @@ -809,6 +845,7 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub) struct mwi_subscription *mwi_sub; struct ast_datastore *mwi_datastore; struct ast_sip_aor *aor; + struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sub); mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE); if (!mwi_datastore) { @@ -822,7 +859,7 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub) return NULL; } - if ((aor = ast_sip_location_retrieve_aor(ast_sip_subscription_get_resource_name(sub)))) { + if ((aor = find_aor_for_resource(endpoint, ast_sip_subscription_get_resource_name(sub)))) { pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub); pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub); @@ -831,6 +868,7 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub) } ao2_ref(aor, -1); } + ao2_cleanup(endpoint); ao2_callback(mwi_sub->stasis_subs, OBJ_NODATA, get_message_count, counter); ao2_cleanup(mwi_datastore); From 34457dd9dbbe74b0f16ca4ca7aabeb4bcd6e107d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 28 Mar 2016 14:23:59 -0500 Subject: [PATCH 0310/1578] core_unreal.c: Add clarification comment about channel ref. Change-Id: I0be0627260cd8d6b6c3cc345949dcfdf32eff1f3 --- main/core_unreal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/core_unreal.c b/main/core_unreal.c index da0bb43bba6..1f5c202ba55 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -805,9 +805,11 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge return -1; } + /* The bridge thread now controls the chan ref from the ast_unreal_pvt */ ao2_lock(p); ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); + ast_channel_unref(chan); return 0; From 2f36cba4b5613817b8218b9a763957a5494862bf Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 29 Mar 2016 14:29:53 -0500 Subject: [PATCH 0311/1578] res_stasis_recording.c: Cleanup stasis_app_recording_find_by_name(). Change-Id: Ic7d93c402c498677a122505558859c853d4e5ac7 --- res/res_stasis_recording.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c index dcabfa69950..5482124194e 100644 --- a/res/res_stasis_recording.c +++ b/res/res_stasis_recording.c @@ -265,7 +265,13 @@ static enum stasis_app_control_channel_result check_rule_recording( return STASIS_APP_CHANNEL_RECORDING; } -struct stasis_app_control_rule rule_recording = { +/* + * XXX This only works because there is one and only one rule in + * the system so it can be added to any number of channels + * without issue. However, as soon as there is another rule then + * watch out for weirdness because of cross linked lists. + */ +static struct stasis_app_control_rule rule_recording = { .check_rule = check_rule_recording }; @@ -465,15 +471,7 @@ const char *stasis_app_recording_get_name( struct stasis_app_recording *stasis_app_recording_find_by_name(const char *name) { - RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup); - - recording = ao2_find(recordings, name, OBJ_KEY); - if (recording == NULL) { - return NULL; - } - - ao2_ref(recording, +1); - return recording; + return ao2_find(recordings, name, OBJ_KEY); } struct ast_json *stasis_app_recording_to_json( From ece2edaa04a12976949b78240e8c211a19fa12b5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 29 Mar 2016 18:06:24 -0500 Subject: [PATCH 0312/1578] res_ari: Cannot get control also means channel is unavailable. The only caller of ari_bridges_play_found() has this note: If ari_bridges_play_found fails because the channel is unavailable for playback, The channel will be removed from the playback list soon. We can keep trying to get channels from the list until we either get one that will work or else there isn't a channel for this bridge anymore, in which case we'll revert to ari_bridges_play_new. Change-Id: Ib068141b367ccaa17be0dab4181c98e26c5127d6 --- res/ari/resource_bridges.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 7b9b94665f3..759947a124e 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -526,9 +526,7 @@ static enum play_found_result ari_bridges_play_found(const char *args_media, control = stasis_app_control_find_by_channel(play_channel); if (!control) { - ast_ari_response_error( - response, 500, "Internal Error", "Failed to get control snapshot"); - return PLAY_FOUND_FAILURE; + return PLAY_FOUND_CHANNEL_UNAVAILABLE; } ao2_lock(control); From 2fab4d7da82cd4799b8d1ba65dfa467255d9f6c5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 30 Mar 2016 13:31:44 -0500 Subject: [PATCH 0313/1578] res_stasis.c: Protect channel datastore list from stasis end. Change-Id: Ifadc469590bd4d5368e19d3763db3bd1f80fdb95 --- res/res_stasis.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/res/res_stasis.c b/res/res_stasis.c index 63c565d44d1..b26cfdd1f86 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1188,10 +1188,11 @@ void stasis_app_channel_set_stasis_end_published(struct ast_channel *chan) struct ast_datastore *datastore; datastore = ast_datastore_alloc(&set_end_published_info, NULL); - - ast_channel_lock(chan); - ast_channel_datastore_add(chan, datastore); - ast_channel_unlock(chan); + if (datastore) { + ast_channel_lock(chan); + ast_channel_datastore_add(chan, datastore); + ast_channel_unlock(chan); + } } int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan) @@ -1211,12 +1212,11 @@ static void remove_stasis_end_published(struct ast_channel *chan) ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &set_end_published_info, NULL); - ast_channel_unlock(chan); - if (datastore) { ast_channel_datastore_remove(chan, datastore); ast_datastore_free(datastore); } + ast_channel_unlock(chan); } /*! /brief Stasis dialplan application callback */ From 53f63ad7704b1b1f2b1465a23f89900266fc8115 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 28 Mar 2016 18:10:40 -0500 Subject: [PATCH 0314/1578] res_stasis: Fix crash on a hanging up channel. * Give the struct stasis_app_control ao2 object a ref to the channel held in the object. Now the channel will still be around if a thread needs to post a stasis message instead of crash because the topic was destroyed. * Moved stopping any lingering silence generator out of the struct stasis_app_control destructor and made it a part of exiting the Stasis application. Who knows which thread the destructor will be called under so it cannot affect the channel's silence generator. Not only was the channel unprotected when the silence generator was stopped, stasis may no longer even control the channel. ASTERISK-25882 Change-Id: I21728161b5fe638cef7976fa36a605043a7497e4 --- res/res_stasis.c | 3 +++ res/stasis/control.c | 39 +++++++++++++++++++++------------------ res/stasis/control.h | 8 ++++++++ 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/res/res_stasis.c b/res/res_stasis.c index 63c565d44d1..dc469c8cc40 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1371,6 +1371,9 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, remove_stasis_end_published(chan); } + /* Stop any lingering silence generator */ + control_silence_stop_now(control); + /* There's an off chance that app is ready for cleanup. Go ahead * and clean up, just in case */ diff --git a/res/stasis/control.c b/res/stasis/control.c index 41d538cbe19..a1004248f35 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -87,21 +87,19 @@ static void control_dtor(void *obj) { struct stasis_app_control *control = obj; - AST_LIST_HEAD_DESTROY(&control->add_rules); - AST_LIST_HEAD_DESTROY(&control->remove_rules); + ao2_cleanup(control->command_queue); - /* We may have a lingering silence generator; free it */ - ast_channel_stop_silence_generator(control->channel, control->silgen); - control->silgen = NULL; + ast_channel_cleanup(control->channel); + ao2_cleanup(control->app); - ao2_cleanup(control->command_queue); ast_cond_destroy(&control->wait_cond); - ao2_cleanup(control->app); + AST_LIST_HEAD_DESTROY(&control->add_rules); + AST_LIST_HEAD_DESTROY(&control->remove_rules); } struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app) { - RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); + struct stasis_app_control *control; int res; control = ao2_alloc(sizeof(*control), control_dtor); @@ -109,28 +107,29 @@ struct stasis_app_control *control_create(struct ast_channel *channel, struct st return NULL; } - control->app = ao2_bump(app); + AST_LIST_HEAD_INIT(&control->add_rules); + AST_LIST_HEAD_INIT(&control->remove_rules); res = ast_cond_init(&control->wait_cond, NULL); if (res != 0) { ast_log(LOG_ERROR, "Error initializing ast_cond_t: %s\n", strerror(errno)); + ao2_ref(control, -1); return NULL; } + control->app = ao2_bump(app); + + ast_channel_ref(channel); + control->channel = channel; + control->command_queue = ao2_container_alloc_list( AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL); - if (!control->command_queue) { + ao2_ref(control, -1); return NULL; } - control->channel = channel; - - AST_LIST_HEAD_INIT(&control->add_rules); - AST_LIST_HEAD_INIT(&control->remove_rules); - - ao2_ref(control, +1); return control; } @@ -785,8 +784,7 @@ void stasis_app_control_silence_start(struct stasis_app_control *control) stasis_app_send_command_async(control, app_control_silence_start, NULL, NULL); } -static int app_control_silence_stop(struct stasis_app_control *control, - struct ast_channel *chan, void *data) +void control_silence_stop_now(struct stasis_app_control *control) { if (control->silgen) { ast_debug(3, "%s: Stopping silence generator\n", @@ -795,7 +793,12 @@ static int app_control_silence_stop(struct stasis_app_control *control, control->channel, control->silgen); control->silgen = NULL; } +} +static int app_control_silence_stop(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + control_silence_stop_now(control); return 0; } diff --git a/res/stasis/control.h b/res/stasis/control.h index a139f82e430..d053a35f7c3 100644 --- a/res/stasis/control.h +++ b/res/stasis/control.h @@ -108,5 +108,13 @@ int control_add_channel_to_bridge( struct stasis_app_control *control, struct ast_channel *chan, void *obj); +/*! + * \brief Stop playing silence to a channel right now. + * \since 13.9.0 + * + * \param control The control for chan + */ +void control_silence_stop_now(struct stasis_app_control *control); + #endif /* _ASTERISK_RES_STASIS_CONTROL_H */ From 0ea742d33a89c8d1d3b92eceb833cbe79faab954 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 29 Mar 2016 13:47:08 -0500 Subject: [PATCH 0315/1578] res_stasis: Add control ref to playback and recording structs. The stasis_app_playback and stasis_app_recording structs need to have a struct stasis_app_control ref. Other threads can get a reference to the playback and recording structs from their respective global container. These other threads can then use the control pointer they contain after the control struct has gone. * Add control ref to stasis_app_playback and stasis_app_recording structs. With the refs added, the control command queue can now have a circular control reference which will cause the control struct to never get released if the control's command queue is not flushed when the channel leaves the Stasis application. Also the command queue needs better protection from adding commands if the control->is_done flag is set. * Flush the control command queue on exit. ASTERISK-25882 #close Change-Id: I3cf1fb59cbe6f50f20d9e35a2c07ac07d7f4320d --- include/asterisk/stasis_app.h | 10 ++++++++++ res/ari/resource_bridges.c | 5 +++-- res/res_stasis.c | 7 +++++++ res/res_stasis_playback.c | 2 ++ res/res_stasis_recording.c | 2 ++ res/stasis/control.c | 36 +++++++++++++++++++++++++++-------- res/stasis/control.h | 10 ++++++++++ 7 files changed, 62 insertions(+), 10 deletions(-) diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index f2b07e0bfeb..90ef82ebf43 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -439,6 +439,16 @@ void stasis_app_control_execute_until_exhausted( int stasis_app_control_is_done( struct stasis_app_control *control); +/*! + * \brief Flush the control command queue. + * \since 13.9.0 + * + * \param control Control object to flush command queue. + * + * \return Nothing + */ +void stasis_app_control_flush_queue(struct stasis_app_control *control); + /*! * \brief Returns the uniqueid of the channel associated with this control * diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 7b9b94665f3..93bdc621716 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -296,10 +296,11 @@ static void *bridge_channel_control_thread(void *data) thread_data = NULL; stasis_app_control_execute_until_exhausted(bridge_channel, control); + stasis_app_control_flush_queue(control); - ast_hangup(bridge_channel); - ao2_cleanup(control); stasis_forward_cancel(forward); + ao2_cleanup(control); + ast_hangup(bridge_channel); return NULL; } diff --git a/res/res_stasis.c b/res/res_stasis.c index dc469c8cc40..5afb90e3c3f 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1179,6 +1179,11 @@ int stasis_app_control_is_done(struct stasis_app_control *control) return control_is_done(control); } +void stasis_app_control_flush_queue(struct stasis_app_control *control) +{ + control_flush_queue(control); +} + struct ast_datastore_info set_end_published_info = { .type = "stasis_end_published", }; @@ -1371,6 +1376,8 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, remove_stasis_end_published(chan); } + control_flush_queue(control); + /* Stop any lingering silence generator */ control_silence_stop_now(control); diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index 74336abdcf2..97191c26dd1 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -118,6 +118,7 @@ static void playback_dtor(void *obj) { struct stasis_app_playback *playback = obj; + ao2_cleanup(playback->control); ast_string_field_free_memory(playback); } @@ -143,6 +144,7 @@ static struct stasis_app_playback *playback_create( ast_string_field_set(playback, id, uuid); } + ao2_ref(control, +1); playback->control = control; ao2_ref(playback, +1); diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c index dcabfa69950..c6f9002e321 100644 --- a/res/res_stasis_recording.c +++ b/res/res_stasis_recording.c @@ -358,6 +358,7 @@ static void recording_dtor(void *obj) struct stasis_app_recording *recording = obj; ast_free(recording->absolute_name); + ao2_cleanup(recording->control); ao2_cleanup(recording->options); } @@ -413,6 +414,7 @@ struct stasis_app_recording *stasis_app_control_record( ao2_ref(options, +1); recording->options = options; + ao2_ref(control, +1); recording->control = control; recording->state = STASIS_APP_RECORDING_STATE_QUEUED; diff --git a/res/stasis/control.c b/res/stasis/control.c index a1004248f35..86f94423de3 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -251,6 +251,11 @@ static struct stasis_app_command *exec_command_on_condition( } ao2_lock(control->command_queue); + if (control->is_done) { + ao2_unlock(control->command_queue); + ao2_ref(command, -1); + return NULL; + } if (can_exec_fn && (retval = can_exec_fn(control))) { ao2_unlock(control->command_queue); command_complete(command, retval); @@ -402,7 +407,10 @@ int control_is_done(struct stasis_app_control *control) void control_mark_done(struct stasis_app_control *control) { + /* Locking necessary to sync with other threads adding commands to the queue. */ + ao2_lock(control->command_queue); control->is_done = 1; + ao2_unlock(control->command_queue); } struct stasis_app_control_continue_data { @@ -427,7 +435,7 @@ static int app_control_continue(struct stasis_app_control *control, /* Called from stasis_app_exec thread; no lock needed */ ast_explicit_goto(control->channel, continue_data->context, continue_data->extension, continue_data->priority); - control->is_done = 1; + control_mark_done(control); return 0; } @@ -1115,24 +1123,36 @@ int stasis_app_control_queue_control(struct stasis_app_control *control, return ast_queue_control(control->channel, frame_type); } +void control_flush_queue(struct stasis_app_control *control) +{ + struct ao2_iterator iter; + struct stasis_app_command *command; + + iter = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK); + while ((command = ao2_iterator_next(&iter))) { + command_complete(command, -1); + ao2_ref(command, -1); + } + ao2_iterator_destroy(&iter); +} + int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan) { int count = 0; - struct ao2_iterator i; - void *obj; + struct ao2_iterator iter; + struct stasis_app_command *command; ast_assert(control->channel == chan); - i = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK); - - while ((obj = ao2_iterator_next(&i))) { - RAII_VAR(struct stasis_app_command *, command, obj, ao2_cleanup); + iter = ao2_iterator_init(control->command_queue, AO2_ITERATOR_UNLINK); + while ((command = ao2_iterator_next(&iter))) { command_invoke(command, control, chan); + ao2_ref(command, -1); ++count; } + ao2_iterator_destroy(&iter); - ao2_iterator_destroy(&i); return count; } diff --git a/res/stasis/control.h b/res/stasis/control.h index d053a35f7c3..1d37a494aec 100644 --- a/res/stasis/control.h +++ b/res/stasis/control.h @@ -40,6 +40,16 @@ */ struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app); +/*! + * \brief Flush the control command queue. + * \since 13.9.0 + * + * \param control Control object to flush command queue. + * + * \return Nothing + */ +void control_flush_queue(struct stasis_app_control *control); + /*! * \brief Dispatch all commands enqueued to this control. * From 304f81780dcb9702d46164d194b9fdd808c4b99f Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 30 Mar 2016 17:34:42 -0600 Subject: [PATCH 0316/1578] pjproject_bundled: Fix use of LDCONFIG for shared library link creation LDCONFIG apparently isn't set to something sane on all systems so the creation of the shared library links fails. Instead of just testing for non-blank, main/Makefile now checks that LDCONFIG is actually executable and reverts to LN if it isn't. This applies to both libasteriskpj and libasteriskssl. Thanks to 'abelbeck' for pointing out that the issue was LDCONFIG. ASTERISK-25873 #close Reported-by: Hans van Eijsden Change-Id: I25b76379bc637726ec044b2c0e709b56b3701729 --- main/Makefile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/main/Makefile b/main/Makefile index 50fdc5739eb..d52c3f0a722 100644 --- a/main/Makefile +++ b/main/Makefile @@ -225,11 +225,11 @@ endif $(ASTSSL_LIB): $(ASTSSL_LIB).$(ASTSSL_SO_VERSION) $(ECHO_PREFIX) echo " [LN] $< -> $@" -ifneq ($(LDCONFIG),) - $(CMD_PREFIX) $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null -else - $(CMD_PREFIX) $(LN) -sf $< $@ -endif + $(CMD_PREFIX) if [ -x "$(LDCONFIG)" ] ; then \ + $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null ;\ + else \ + $(LN) -sf $< $@ ;\ + fi else # Darwin ASTSSL_LIB:=libasteriskssl.dylib @@ -305,11 +305,11 @@ $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): libasteriskpj.o libasteriskpj.exports $(ASTPJ_LIB): $(ASTPJ_LIB).$(ASTPJ_SO_VERSION) $(ECHO_PREFIX) echo " [LN] $< -> $@" -ifneq ($(LDCONFIG),) - $(CMD_PREFIX) $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null -else - $(CMD_PREFIX) $(LN) -sf $< $@ -endif + $(CMD_PREFIX) if [ -x "$(LDCONFIG)" ] ; then \ + $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null ;\ + else \ + $(LN) -sf $< $@ ;\ + fi else # Darwin ASTPJ_LIB:=libasteriskpj.dylib From 433d2c4bbfa3f7d8bb3a194b16feb99874207f84 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 1 Apr 2016 12:09:50 -0600 Subject: [PATCH 0317/1578] utils.c: Fix typo in handle_show_locks ast_cli_allow_on_shutdown(e) should have been ast_cli_allow_at_shutdown(e). Change-Id: I4f092495c0b2bfd85c2651e0b5877bf4d05d9faf --- main/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/utils.c b/main/utils.c index 6a778b90c4a..e92f5c3d961 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1153,7 +1153,7 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_ "Usage: core show locks\n" " This command is for lock debugging. It prints out which locks\n" "are owned by each active thread.\n"; - ast_cli_allow_on_shutdown(e); + ast_cli_allow_at_shutdown(e); return NULL; case CLI_GENERATE: From 060b7b83bc80216ef0bc5677dc4ed3180d283638 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 3 Apr 2016 10:47:30 -0600 Subject: [PATCH 0318/1578] install_prereq: Fix check_installed_debs remove subversion check_installed_debs wasn't handling virtual packages like libsrtp-dev and libresample-dev and on multiarch systems it was accidentally filtering out all packages if any :i386 packages were found instead of just filtering out the :i386 packages themselves. Change-Id: Ifd68da0d1ee30cc84df14de3f9b9079d7c3cecda --- contrib/scripts/install_prereq | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/contrib/scripts/install_prereq b/contrib/scripts/install_prereq index afad1f71967..1682558ac3b 100755 --- a/contrib/scripts/install_prereq +++ b/contrib/scripts/install_prereq @@ -66,13 +66,12 @@ in_test_mode() { } check_installed_debs() { - for pack in "$@" - do - tocheck="${tocheck} ^${pack}$" + for pack in "$@" ; do + tocheck="${tocheck} ^${pack}$ ~P^${pack}$" done pkgs=$(aptitude -F '%c %p' search ${tocheck} 2>/dev/null | awk '/^p/{print $2}') - if ! [ ${#pkgs} -eq 0 ]; then - echo $pkgs | grep -v ':i386$' + if [ ${#pkgs} -ne 0 ]; then + echo $pkgs | sed -r -e "s/ ?[^ :]+:i386//g" fi } From c07e1190ec02573d80d007b6d7279b14cde8655b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 4 Apr 2016 17:02:09 -0600 Subject: [PATCH 0319/1578] res_pjsip_mwi: Fix segv caused by 16c7d8e74a9af13f98c3c22aa9c43ce39965f6b7 I forgot the new voicemail_extension wasn't a stringfield and didn't check for NULL where I should have. Change-Id: I029482d5c2ab72474838750461bd46b0809c90fb --- res/res_pjsip_mwi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index a954c9c66bb..f9bfc1904d9 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -459,7 +459,8 @@ static struct ast_sip_aor *find_aor_for_resource(struct ast_sip_endpoint *endpoi continue; } - if (!strcasecmp(check_aor->voicemail_extension, resource)) { + if (!ast_strlen_zero(check_aor->voicemail_extension) + && !strcasecmp(check_aor->voicemail_extension, resource)) { ast_debug(1, "Found an aor (%s) that matches voicemail_extension %s\n", aor_name, resource); return check_aor; } From 4d40b161c3f3f73bae5055fed0f1d0fec8a44efd Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 25 Mar 2016 22:22:34 -0600 Subject: [PATCH 0320/1578] stringfields: Refactor to allow fields to be added to the end of structures String fields are great, except that you can't add new ones without breaking ABI compatibility because it shifts down everything else in the structure. The only alternative is to add your own char * field to the end of the structure and manage the memory yourself which isn't ideal, especially since you then can't use the OPT_STRINGFIELD_T type. Background: The reason string fields had to be declared inside the AST_DECLARE_STRING_FIELDS block was to facilitate iteration over all declared fields for initialization, compare and copy. Since AST_DECLARE_STRING_FIELDS declared the pool, then the fields, then the manager, you could use the offsets of the pool and manager and iterate over the sequential addresses in between to access the fields. The actual pool, field allocation and field set operations don't actually care where the field is. It's just iteration over the fields that was the problem. Solution: Extended String Fields An extended string field is one that is declared outside the AST_DECLARE_STRING_FIELDS block but still (anywhere) inside the parent structure. Other than using AST_STRING_FIELD_EXTENDED instead of AST_STRING_FIELD, it looks the same as other string fields. It's storage comes from the pool and it participates in string field compare and copy operations peformed on the parent structure. It's also a valid target for the OPT_STRINGFIELD_T aco option type. Implementation: To keep track of the extended fields and make sure that ABI isn't broken, the existing embedded_pool pointer in the manager structure was repurposed to be a pointer to a separate header structure that contains the embedded_pool pointer plus a vector of fields. The length of the manager structure didn't change and the embedded_pool pointer isn't used in the macros, only the stringfields C code. A side benefit of this is that changing the header structure in the future won't break ABI. ast_string_fields_init initializes the normal string fields and appends them to the vector, and subsequent calls to ast_string_field_init_extended initialize and append the extended fields. Cleanup, ast_string_fields_cmp, and ast_string_fields_copy can now work on the vector instead of sequentially traversing the addresses between the pool and manager. The total size of a structure using string fields didn't change, whether using extended fields or not, nor have the offsets of any structure members, either inside the original block or outside. Adding an extended field to the end of a structure is the same as adding a char *. Details: The stringfield C code was pulled out from utils.c and into stringfields.c. It just made sense. Additional work was done in ast_string_field_init and ast_calloc_with_stringfields to handle the allocation of the new header structure and the vector, and the associated cleanup. In the process some additional NULL pointer checking was added. A lot of work was done in stringfields.h since the logic for compare and copy is there. Documentation was added as well as somne additional NULL checking. The ability to call ast_calloc_with_stringfields with a number of structures greater than 1 never really worked. Well, the calloc worked but there was no way to access the additional structures or clean them up. It was agreed that there was no use case for requesting more than 1 structure so an ast_assert was added to prevent it and the iteration code removed. Testing: The stringfield unit tests were updated to test both normal and extended fields. Tests for ast_string_field_ptr_set_by_fields and ast_calloc_with_stringfields were also added. As an ABI test, 13 was compiled from git and the res_pjsip_* modules, except res_pjsip itself, saved off. The patch was then added and a full compile and install was performed. Then the older res_pjsip_* moduled were copied over the installed versions so res_pjsip was new and the rest were old. No issues. contact->aor, which is a char * at the end of contact, was then changed to an extended string field and a recompile and reinstall was performed, again leaving stock versions of the the res_pjsip_* modules. Again, no issues with the res_pjsip_* modules using the old stringfield implementation and with contact->aor as a char *, and res_pjsip itself using the new stringfield implementation and contact->aor being an extended string field. Finally, several existing string fields were converted to extended string fields to test OPT_STRINGFIELD_T. Again, no issues. Change-Id: I235db338c5b178f5a13b7946afbaa5d4a0f91d61 --- include/asterisk/stringfields.h | 295 +++++++++++++++---- main/stringfields.c | 508 ++++++++++++++++++++++++++++++++ main/utils.c | 371 ----------------------- tests/test_stringfields.c | 205 ++++++++++--- 4 files changed, 908 insertions(+), 471 deletions(-) create mode 100644 main/stringfields.c diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h index d0879b2baa6..c24424b0a87 100644 --- a/include/asterisk/stringfields.h +++ b/include/asterisk/stringfields.h @@ -17,6 +17,7 @@ */ /*! \file + \page Stringfields String Fields \brief String fields in structures This file contains objects and macros used to manage string @@ -93,6 +94,80 @@ ast_free(x); \endcode + A new feature "Extended String Fields" has been added in 13.9.0. + + An extended field is one that is declared outside the AST_DECLARE_STRING_FIELDS + block but still inside the parent structure. It's most useful for extending + structures where adding a new string field to an existing AST_DECLARE_STRING_FIELDS + block would break ABI compatibility. + + Example: + + \code + struct original_structure_version { + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(foo); + AST_STRING_FIELD(bar); + ); + int x1; + int x2; + }; + \endcode + + Adding "blah" to the existing string fields breaks ABI compatibility because it changes + the offsets of x1 and x2. + + \code + struct new_structure_version { + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(foo); + AST_STRING_FIELD(bar); + AST_STRING_FIELD(blah); + ); + int x1; + int x2; + }; + \endcode + + However, adding "blah" as an extended string field to the end of the structure doesn't break + ABI compatibility but still allows the use of the existing pool. + + \code + struct new_structure_version { + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(foo); + AST_STRING_FIELD(bar); + ); + int x1; + int x2; + AST_STRING_FIELD_EXTENDED(blah); + }; + \endcode + + The only additional step required is to call ast_string_field_init_extended so the + pool knows about the new field. It must be called AFTER ast_string_field_init or + ast_calloc_with_stringfields. Although ast_calloc_with_stringfields is used in the + sample below, it's not necessary for extended string fields. + + \code + + struct new_structure_version *x = ast_calloc_with_stringfields(1, struct new_structure_version, 252); + if (!x) { + return; + } + + ast_string_field_init_extended(x, blah); + \endcode + + The new field can now be treated just like any other string field and it's storage will + be released with the rest of the string fields. + + \code + ast_string_field_set(x, foo, "infinite loop"); + ast_stringfield_free_memory(x); + ast_free(x); + \endcode + This completes the API description. */ @@ -100,6 +175,7 @@ #define _ASTERISK_STRINGFIELDS_H #include "asterisk/inline_api.h" +#include "asterisk/vector.h" /*! \internal @@ -137,13 +213,30 @@ struct ast_string_field_pool { char base[0] __attribute__((aligned(__alignof__(ast_string_field_allocation)))); /*!< storage space for the fields */ }; +/*! + \internal + \brief The definition for the string field vector used for compare and copy + \since 13.9.0 +*/ +AST_VECTOR(ast_string_field_vector, const char **); + +/*! + \internal + \brief Structure used to hold a pointer to the embedded pool and the field vector + \since 13.9.0 +*/ +struct ast_string_field_header { + struct ast_string_field_pool *embedded_pool; /*!< pointer to the embedded pool, if any */ + struct ast_string_field_vector string_fields; /*!< field vector for compare and copy */ +}; + /*! \internal \brief Structure used to manage the storage for a set of string fields. */ struct ast_string_field_mgr { ast_string_field last_alloc; /*!< the last field allocated */ - struct ast_string_field_pool *embedded_pool; /*!< pointer to the embedded pool, if any */ + struct ast_string_field_header *header; /*!< pointer to the header */ #if defined(__AST_DEBUG_MALLOC) const char *owner_file; /*!< filename of owner */ const char *owner_func; /*!< function name of owner */ @@ -217,6 +310,29 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, */ #define AST_STRING_FIELD(name) const ast_string_field name +/*! + \brief Declare an extended string field + \since 13.9.0 + + \param name The field name +*/ +#define AST_STRING_FIELD_EXTENDED(name) AST_STRING_FIELD(name) + +enum ast_stringfield_cleanup_type { + /*! + * Reset all string fields and free all extra pools that may have been created + * The allocation or structure can be reused as is. + */ + AST_STRINGFIELD_RESET = 0, + /*! + * Reset all string fields and free all pools. + * If the pointer was returned by ast_calloc_with_stringfields, it can NOT be reused + * and should be immediately freed. Otherwise, you must call ast_string_field_init + * again if you want to reuse it. + */ + AST_STRINGFIELD_DESTROY = -1, +}; + /*! \brief Declare the fields needed in a structure \param field_list The list of fields to declare, using AST_STRING_FIELD() for each one. @@ -239,17 +355,65 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, \brief Initialize a field pool and fields \param x Pointer to a structure containing fields \param size Amount of storage to allocate. - Use 0 to reset fields to the default value, + Use AST_STRINGFIELD_RESET to reset fields to the default value, and release all but the most recent pool. - size<0 (used internally) means free all pools. + AST_STRINGFIELD_DESTROY (used internally) means free all pools which is + equivalent to calling ast_string_field_free_memory. + \return 0 on success, non-zero on failure */ #define ast_string_field_init(x, size) \ - __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, size, __FILE__, __LINE__, __PRETTY_FUNCTION__) +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __res__ = __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, size, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } \ + __res__ ; \ +}) + +/*! + * \brief free all memory - to be called before destroying the object + * + * \param x + * + */ +#define ast_string_field_free_memory(x) \ +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __res__ = __ast_string_field_free_memory(&(x)->__field_mgr, &(x)->__field_mgr_pool, \ + AST_STRINGFIELD_DESTROY, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } \ + __res__; \ +}) + +int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type, + const char *file, int lineno, const char *func); -/*! \brief free all memory - to be called before destroying the object */ -#define ast_string_field_free_memory(x) \ - __ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, -1, __FILE__, __LINE__, __PRETTY_FUNCTION__) +/*! + * \brief Initialize an extended string field + * \since 13.9.0 + * + * \param x Pointer to a structure containing the field + * \param field The extended field to initialize + * \retval zero on success + * \retval non-zero on error + * + * \note + * This macro must be called on ALL fields defined with AST_STRING_FIELD_EXTENDED after + * ast_string_field_init has been called. + */ +#define ast_string_field_init_extended(x, field) \ +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL && (x)->__field_mgr.header != NULL) { \ + ast_string_field *non_const = (ast_string_field *)&(x)->field; \ + *non_const = __ast_string_field_empty; \ + __res__ = AST_VECTOR_APPEND(&(x)->__field_mgr.header->string_fields, non_const); \ + } \ + __res__; \ +}) /*! * \internal @@ -260,9 +424,10 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_ /*! * \brief Allocate a structure with embedded stringfields in a single allocation - * \param n Number of structures to allocate (see ast_calloc) + * \param n Current imlementation only allows 1 structure to be allocated * \param type The type of structure to allocate * \param size The number of bytes of space (minimum) to allocate for stringfields to use + * in each structure * * This function will allocate memory for one or more structures that use stringfields, and * also allocate space for the stringfields and initialize the stringfield management @@ -271,16 +436,16 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_ * \since 1.8 */ #define ast_calloc_with_stringfields(n, type, size) \ - __ast_calloc_with_stringfields(n, sizeof(type), offsetof(type, __field_mgr), offsetof(type, __field_mgr_pool), \ - size, __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_calloc_with_stringfields(n, sizeof(type), offsetof(type, __field_mgr), \ + offsetof(type, __field_mgr_pool), size, __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! * \internal * \brief internal version of ast_calloc_with_stringfields */ -void * attribute_malloc __ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset, - size_t field_mgr_pool_offset, size_t pool_size, const char *file, - int lineno, const char *func); +void * attribute_malloc __ast_calloc_with_stringfields(unsigned int num_structs, + size_t struct_size, size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, + const char *file, int lineno, const char *func); /*! \internal @@ -314,7 +479,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, \retval zero on success \retval non-zero on error */ -#define ast_string_field_ptr_set(x, ptr, data) ast_string_field_ptr_set_by_fields((x)->__field_mgr_pool, (x)->__field_mgr, ptr, data) +#define ast_string_field_ptr_set(x, ptr, data) \ +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __res__ = ast_string_field_ptr_set_by_fields((x)->__field_mgr_pool, (x)->__field_mgr, ptr, data); \ + } \ + __res__; \ +}) #define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data) \ ({ \ @@ -348,7 +520,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, \retval zero on success \retval non-zero on error */ -#define ast_string_field_set(x, field, data) ast_string_field_ptr_set(x, &(x)->field, data) +#define ast_string_field_set(x, field, data) \ +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __res__ = ast_string_field_ptr_set(x, &(x)->field, data); \ + } \ + __res__; \ +}) /*! \brief Set a field to a complex (built) value @@ -359,7 +538,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, \return nothing */ #define ast_string_field_ptr_build(x, ptr, fmt, args...) \ - __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args) +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args); \ + __res__ = 0; \ + } \ + __res__; \ +}) /*! \brief Set a field to a complex (built) value @@ -370,7 +556,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, \return nothing */ #define ast_string_field_build(x, field, fmt, args...) \ - __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args) +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args); \ + __res__ = 0; \ + } \ + __res__; \ +}) /*! \brief Set a field to a complex (built) value with prebuilt va_lists. @@ -381,7 +574,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, \return nothing */ #define ast_string_field_ptr_build_va(x, ptr, fmt, args) \ - __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args) +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args); \ + __res__ = 0; \ + } \ + __res__; \ +}) /*! \brief Set a field to a complex (built) value @@ -392,7 +592,14 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, \return nothing */ #define ast_string_field_build_va(x, field, fmt, args) \ - __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args) +({ \ + int __res__ = -1; \ + if (((void *)(x)) != NULL) { \ + __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args); \ + __res__ = 0; \ + } \ + __res__; \ +}) /*! \brief Compare the string fields in two instances of the same structure @@ -404,25 +611,16 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, */ #define ast_string_fields_cmp(instance1, instance2) \ ({ \ - int __res__ = 0; \ - size_t __ptr_size__ = sizeof(char *); \ - int __len__ = ((void *)&(instance1)->__field_mgr - (void *)&(instance1)->__field_mgr_pool)/__ptr_size__ - 1; \ - int __len2__ = ((void *)&(instance2)->__field_mgr - (void *)&(instance2)->__field_mgr_pool)/__ptr_size__ - 1; \ - if (__len__ == __len2__) { \ - char **__head1__ = (void *)&(instance1)->__field_mgr_pool + __ptr_size__; \ - char **__head2__ = (void *)&(instance2)->__field_mgr_pool + __ptr_size__; \ - for (__len__ -= 1; __len__ >= 0; __len__--) { \ - __res__ = strcmp(__head1__[__len__], __head2__[__len__]); \ - if (__res__) { \ - break; \ - } \ - } \ - } else { \ - __res__ = -1; \ + int __res__ = -1; \ + if (((void *)(instance1)) != NULL && ((void *)(instance2)) != NULL) { \ + __res__ = __ast_string_fields_cmp(&(instance1)->__field_mgr.header->string_fields, \ + &(instance2)->__field_mgr.header->string_fields); \ } \ __res__; \ }) +int __ast_string_fields_cmp(struct ast_string_field_vector *left, struct ast_string_field_vector *right); + /*! \brief Copy all string fields from one instance to another of the same structure \since 12 @@ -433,27 +631,16 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, */ #define ast_string_fields_copy(copy, orig) \ ({ \ - int __outer_res__ = 0; \ - size_t __ptr_size__ = sizeof(char *); \ - int __len__ = ((void *)&(copy)->__field_mgr - (void *)&(copy)->__field_mgr_pool)/__ptr_size__ - 1; \ - int __len2__ = ((void *)&(orig)->__field_mgr - (void *)&(orig)->__field_mgr_pool)/__ptr_size__ - 1; \ - if (__len__ == __len2__) { \ - ast_string_field *__copy_head__ = (void *)&(copy)->__field_mgr_pool + __ptr_size__; \ - ast_string_field *__orig_head__ = (void *)&(orig)->__field_mgr_pool + __ptr_size__; \ - for (__len2__ -= 1; __len2__ >= 0; __len2__--) { \ - __ast_string_field_release_active((copy)->__field_mgr_pool, __copy_head__[__len2__]); \ - __copy_head__[__len2__] = __ast_string_field_empty; \ - } \ - for (__len__ -= 1; __len__ >= 0; __len__--) { \ - if (ast_string_field_ptr_set((copy), &__copy_head__[__len__], __orig_head__[__len__])) { \ - __outer_res__ = -1; \ - break; \ - } \ - } \ - } else { \ - __outer_res__ = -1; \ + int __res__ = -1; \ + if (((void *)(copy)) != NULL && ((void *)(orig)) != NULL) { \ + __res__ = __ast_string_fields_copy(((copy)->__field_mgr_pool), \ + (struct ast_string_field_mgr *)&((copy)->__field_mgr), \ + (struct ast_string_field_mgr *)&((orig)->__field_mgr)); \ } \ - __outer_res__; \ + __res__; \ }) +int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool, + struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr); + #endif /* _ASTERISK_STRINGFIELDS_H */ diff --git a/main/stringfields.c b/main/stringfields.c new file mode 100644 index 00000000000..67dd06c9b0e --- /dev/null +++ b/main/stringfields.c @@ -0,0 +1,508 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Kevin P. Fleming + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief String fields + * + * \author Kevin P. Fleming + */ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/stringfields.h" +#include "asterisk/utils.h" + +/* this is a little complex... string fields are stored with their + allocated size in the bytes preceding the string; even the + constant 'empty' string has to be this way, so the code that + checks to see if there is enough room for a new string doesn't + have to have any special case checks +*/ + +static const struct { + ast_string_field_allocation allocation; + char string[1]; +} __ast_string_field_empty_buffer; + +ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string; + +#define ALLOCATOR_OVERHEAD 48 + +static size_t optimal_alloc_size(size_t size) +{ + unsigned int count; + + size += ALLOCATOR_OVERHEAD; + + for (count = 1; size; size >>= 1, count++); + + return (1 << count) - ALLOCATOR_OVERHEAD; +} + +static void *calloc_wrapper(unsigned int num_structs, size_t struct_size, + const char *file, int lineno, const char *func) +{ +#if defined(__AST_DEBUG_MALLOC) + return __ast_calloc(num_structs, struct_size, file, lineno, func); +#else + return ast_calloc(num_structs, struct_size); +#endif +} + +/*! \brief add a new block to the pool. + * We can only allocate from the topmost pool, so the + * fields in *mgr reflect the size of that only. + */ +static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, + size_t size, const char *file, int lineno, const char *func) +{ + struct ast_string_field_pool *pool; + size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size); + + if (!(pool = calloc_wrapper(1, alloc_size, file, lineno, func))) { + return -1; + } + + pool->prev = *pool_head; + pool->size = alloc_size - sizeof(*pool); + *pool_head = pool; + mgr->last_alloc = NULL; + + return 0; +} + +static void reset_field(const char **p) +{ + *p = __ast_string_field_empty; +} + +/*! + * \brief Internal cleanup function + * \internal + * \param mgr + * \param pool_head + * \param cleanup_type + * 0: Reset all string fields and free all pools except the last or embedded pool. + * Keep the internal management structures so the structure can be reused. + * -1: Reset all string fields and free all pools except the embedded pool. + * Free the internal management structures. + * \param file + * \param lineno + * \param func + * + * \retval 0 Success + * \retval -1 Failure + */ +int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, enum ast_stringfield_cleanup_type cleanup_type, + const char *file, int lineno, const char *func) +{ + struct ast_string_field_pool *cur = NULL; + struct ast_string_field_pool *preserve = NULL; + + if (!mgr->header) { + return -1; + } + + /* reset all the fields regardless of cleanup type */ + AST_VECTOR_CALLBACK_VOID(&mgr->header->string_fields, reset_field); + + switch (cleanup_type) { + case AST_STRINGFIELD_DESTROY: + AST_VECTOR_FREE(&mgr->header->string_fields); + + if (mgr->header->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */ + preserve = mgr->header->embedded_pool; + preserve->used = preserve->active = 0; + } + + ast_free(mgr->header); + mgr->header = NULL; + break; + case AST_STRINGFIELD_RESET: + /* Preserve the embedded pool if there is one, otherwise the last pool */ + if (mgr->header->embedded_pool) { + preserve = mgr->header->embedded_pool; + } else { + if (*pool_head == NULL) { + ast_log(LOG_WARNING, "trying to reset empty pool\n"); + return -1; + } + preserve = *pool_head; + } + preserve->used = preserve->active = 0; + break; + default: + return -1; + } + + cur = *pool_head; + while (cur) { + struct ast_string_field_pool *prev = cur->prev; + + if (cur != preserve) { + ast_free(cur); + } + cur = prev; + } + + *pool_head = preserve; + if (preserve) { + preserve->prev = NULL; + } + + return 0; +} + +/*! + * \brief Internal initialization function + * \internal + * \param mgr + * \param pool_head + * \param needed + * \param file + * \param lineno + * \param func + * + * \retval 0 Success + * \retval -1 Failure + */ +int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, + int needed, const char *file, int lineno, const char *func) +{ + const char **p = (const char **) pool_head + 1; + size_t initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p); + + if (needed <= 0) { + return __ast_string_field_free_memory(mgr, pool_head, needed, file, lineno, func); + } + + mgr->last_alloc = NULL; +#if defined(__AST_DEBUG_MALLOC) + mgr->owner_file = file; + mgr->owner_func = func; + mgr->owner_line = lineno; +#endif + + if (!(mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func))) { + return -1; + } + + if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) { + ast_free(mgr->header); + mgr->header = NULL; + return -1; + } + + while ((struct ast_string_field_mgr *) p != mgr) { + AST_VECTOR_APPEND(&mgr->header->string_fields, p); + *p++ = __ast_string_field_empty; + } + + *pool_head = NULL; + mgr->header->embedded_pool = NULL; + if (add_string_pool(mgr, pool_head, needed, file, lineno, func)) { + AST_VECTOR_FREE(&mgr->header->string_fields); + ast_free(mgr->header); + mgr->header = NULL; + return -1; + } + + return 0; +} + +ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, size_t needed) +{ + char *result = NULL; + size_t space = (*pool_head)->size - (*pool_head)->used; + size_t to_alloc; + + /* Make room for ast_string_field_allocation and make it a multiple of that. */ + to_alloc = ast_make_room_for(needed, ast_string_field_allocation); + ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0); + + if (__builtin_expect(to_alloc > space, 0)) { + size_t new_size = (*pool_head)->size; + + while (new_size < to_alloc) { + new_size *= 2; + } + +#if defined(__AST_DEBUG_MALLOC) + if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func)) + return NULL; +#else + if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__)) + return NULL; +#endif + } + + /* pool->base is always aligned (gcc aligned attribute). We ensure that + * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation) + * causing result to always be aligned as well; which in turn fixes that + * AST_STRING_FIELD_ALLOCATION(result) is aligned. */ + result = (*pool_head)->base + (*pool_head)->used; + (*pool_head)->used += to_alloc; + (*pool_head)->active += needed; + result += ast_alignof(ast_string_field_allocation); + AST_STRING_FIELD_ALLOCATION(result) = needed; + mgr->last_alloc = result; + + return result; +} + +int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, size_t needed, const ast_string_field *ptr) +{ + ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr); + size_t space = (*pool_head)->size - (*pool_head)->used; + + if (*ptr != mgr->last_alloc) { + return 1; + } + + if (space < grow) { + return 1; + } + + (*pool_head)->used += grow; + (*pool_head)->active += grow; + AST_STRING_FIELD_ALLOCATION(*ptr) += grow; + + return 0; +} + +void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, + const ast_string_field ptr) +{ + struct ast_string_field_pool *pool, *prev; + + if (ptr == __ast_string_field_empty) { + return; + } + + for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) { + if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) { + pool->active -= AST_STRING_FIELD_ALLOCATION(ptr); + if (pool->active == 0) { + if (prev) { + prev->prev = pool->prev; + ast_free(pool); + } else { + pool->used = 0; + } + } + break; + } + } +} + +void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, ast_string_field *ptr, + const char *format, va_list ap) +{ + size_t needed; + size_t available; + size_t space = (*pool_head)->size - (*pool_head)->used; + int res; + ssize_t grow; + char *target; + va_list ap2; + + /* if the field already has space allocated, try to reuse it; + otherwise, try to use the empty space at the end of the current + pool + */ + if (*ptr != __ast_string_field_empty) { + target = (char *) *ptr; + available = AST_STRING_FIELD_ALLOCATION(*ptr); + if (*ptr == mgr->last_alloc) { + available += space; + } + } else { + /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation) + * so we don't need to re-align anything here. + */ + target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation); + if (space > ast_alignof(ast_string_field_allocation)) { + available = space - ast_alignof(ast_string_field_allocation); + } else { + available = 0; + } + } + + va_copy(ap2, ap); + res = vsnprintf(target, available, format, ap2); + va_end(ap2); + + if (res < 0) { + /* Are we out of memory? */ + return; + } + if (res == 0) { + __ast_string_field_release_active(*pool_head, *ptr); + *ptr = __ast_string_field_empty; + return; + } + needed = (size_t)res + 1; /* NUL byte */ + + if (needed > available) { + /* the allocation could not be satisfied using the field's current allocation + (if it has one), or the space available in the pool (if it does not). allocate + space for it, adding a new string pool if necessary. + */ + if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) { + return; + } + vsprintf(target, format, ap); + va_end(ap); /* XXX va_end without va_start? */ + __ast_string_field_release_active(*pool_head, *ptr); + *ptr = target; + } else if (*ptr != target) { + /* the allocation was satisfied using available space in the pool, but not + using the space already allocated to the field + */ + __ast_string_field_release_active(*pool_head, *ptr); + mgr->last_alloc = *ptr = target; + ast_assert(needed < (ast_string_field_allocation)-1); + AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed; + (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation); + (*pool_head)->active += needed; + } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) { + /* the allocation was satisfied by using available space in the pool *and* + the field was the last allocated field from the pool, so it grew + */ + AST_STRING_FIELD_ALLOCATION(*ptr) += grow; + (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation); + (*pool_head)->active += grow; + } +} + +void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, + struct ast_string_field_pool **pool_head, ast_string_field *ptr, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap); + va_end(ap); +} + +void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, + size_t field_mgr_offset, size_t field_mgr_pool_offset, size_t pool_size, const char *file, + int lineno, const char *func) +{ + struct ast_string_field_mgr *mgr; + struct ast_string_field_pool *pool; + struct ast_string_field_pool **pool_head; + size_t pool_size_needed = sizeof(*pool) + pool_size; + size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed); + void *allocation; + const char **p; + size_t initial_vector_size; + + ast_assert(num_structs == 1); + + if (!(allocation = calloc_wrapper(num_structs, size_to_alloc, file, lineno, func))) { + return NULL; + } + + mgr = allocation + field_mgr_offset; + + /* + * The header is calloced in __ast_string_field_init so it also gets calloced here + * so __ast_string_fields_free_memory can always just free mgr->header. + */ + mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func); + if (!mgr->header) { + ast_free(allocation); + return NULL; + } + + pool = allocation + struct_size; + pool_head = allocation + field_mgr_pool_offset; + p = (const char **) pool_head + 1; + initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p); + + if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) { + ast_free(mgr->header); + ast_free(allocation); + return NULL; + } + + while ((struct ast_string_field_mgr *) p != mgr) { + AST_VECTOR_APPEND(&mgr->header->string_fields, p); + *p++ = __ast_string_field_empty; + } + + mgr->header->embedded_pool = pool; + *pool_head = pool; + pool->size = size_to_alloc - struct_size - sizeof(*pool); +#if defined(__AST_DEBUG_MALLOC) + mgr->owner_file = file; + mgr->owner_func = func; + mgr->owner_line = lineno; +#endif + + return allocation; +} + +int __ast_string_fields_cmp(struct ast_string_field_vector *left, + struct ast_string_field_vector *right) +{ + int i; + int res = 0; + + ast_assert(AST_VECTOR_SIZE(left) == AST_VECTOR_SIZE(right)); + + for (i = 0; i < AST_VECTOR_SIZE(left); i++) { + if ((res = strcmp(*AST_VECTOR_GET(left, i), *AST_VECTOR_GET(right, i)))) { + return res; + } + } + + return res; +} + +int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool, + struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr) +{ + int i; + struct ast_string_field_vector *dest = &(copy_mgr->header->string_fields); + struct ast_string_field_vector *src = &(orig_mgr->header->string_fields); + + ast_assert(AST_VECTOR_SIZE(dest) == AST_VECTOR_SIZE(src)); + + for (i = 0; i < AST_VECTOR_SIZE(dest); i++) { + __ast_string_field_release_active(copy_pool, *AST_VECTOR_GET(dest, i)); + *AST_VECTOR_GET(dest, i) = __ast_string_field_empty; + } + + for (i = 0; i < AST_VECTOR_SIZE(dest); i++) { + if (ast_string_field_ptr_set_by_fields(copy_pool, *copy_mgr, AST_VECTOR_GET(dest, i), + *AST_VECTOR_GET(src, i))) { + return -1; + } + } + + return 0; +} diff --git a/main/utils.c b/main/utils.c index e92f5c3d961..09839752b5b 100644 --- a/main/utils.c +++ b/main/utils.c @@ -60,9 +60,6 @@ ASTERISK_REGISTER_FILE() #define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ #include "asterisk/time.h" -#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ -#include "asterisk/stringfields.h" - #define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */ #include "asterisk/utils.h" @@ -2023,374 +2020,6 @@ char *ast_to_camel_case_delim(const char *s, const char *delim) return res; } -/* - * stringfields support routines. - */ - -/* this is a little complex... string fields are stored with their - allocated size in the bytes preceding the string; even the - constant 'empty' string has to be this way, so the code that - checks to see if there is enough room for a new string doesn't - have to have any special case checks -*/ - -static const struct { - ast_string_field_allocation allocation; - char string[1]; -} __ast_string_field_empty_buffer; - -ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string; - -#define ALLOCATOR_OVERHEAD 48 - -static size_t optimal_alloc_size(size_t size) -{ - unsigned int count; - - size += ALLOCATOR_OVERHEAD; - - for (count = 1; size; size >>= 1, count++); - - return (1 << count) - ALLOCATOR_OVERHEAD; -} - -/*! \brief add a new block to the pool. - * We can only allocate from the topmost pool, so the - * fields in *mgr reflect the size of that only. - */ -static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - size_t size, const char *file, int lineno, const char *func) -{ - struct ast_string_field_pool *pool; - size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size); - -#if defined(__AST_DEBUG_MALLOC) - if (!(pool = __ast_calloc(1, alloc_size, file, lineno, func))) { - return -1; - } -#else - if (!(pool = ast_calloc(1, alloc_size))) { - return -1; - } -#endif - - pool->prev = *pool_head; - pool->size = alloc_size - sizeof(*pool); - *pool_head = pool; - mgr->last_alloc = NULL; - - return 0; -} - -/* - * This is an internal API, code should not use it directly. - * It initializes all fields as empty, then uses 'size' for 3 functions: - * size > 0 means initialize the pool list with a pool of given size. - * This must be called right after allocating the object. - * size = 0 means release all pools except the most recent one. - * If the first pool was allocated via embedding in another - * object, that pool will be preserved instead. - * This is useful to e.g. reset an object to the initial value. - * size < 0 means release all pools. - * This must be done before destroying the object. - */ -int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - int needed, const char *file, int lineno, const char *func) -{ - const char **p = (const char **) pool_head + 1; - struct ast_string_field_pool *cur = NULL; - struct ast_string_field_pool *preserve = NULL; - - /* clear fields - this is always necessary */ - while ((struct ast_string_field_mgr *) p != mgr) { - *p++ = __ast_string_field_empty; - } - - mgr->last_alloc = NULL; -#if defined(__AST_DEBUG_MALLOC) - mgr->owner_file = file; - mgr->owner_func = func; - mgr->owner_line = lineno; -#endif - if (needed > 0) { /* allocate the initial pool */ - *pool_head = NULL; - mgr->embedded_pool = NULL; - return add_string_pool(mgr, pool_head, needed, file, lineno, func); - } - - /* if there is an embedded pool, we can't actually release *all* - * pools, we must keep the embedded one. if the caller is about - * to free the structure that contains the stringfield manager - * and embedded pool anyway, it will be freed as part of that - * operation. - */ - if ((needed < 0) && mgr->embedded_pool) { - needed = 0; - } - - if (needed < 0) { /* reset all pools */ - cur = *pool_head; - } else if (mgr->embedded_pool) { /* preserve the embedded pool */ - preserve = mgr->embedded_pool; - cur = *pool_head; - } else { /* preserve the last pool */ - if (*pool_head == NULL) { - ast_log(LOG_WARNING, "trying to reset empty pool\n"); - return -1; - } - preserve = *pool_head; - cur = preserve->prev; - } - - if (preserve) { - preserve->prev = NULL; - preserve->used = preserve->active = 0; - } - - while (cur) { - struct ast_string_field_pool *prev = cur->prev; - - if (cur != preserve) { - ast_free(cur); - } - cur = prev; - } - - *pool_head = preserve; - - return 0; -} - -ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, size_t needed) -{ - char *result = NULL; - size_t space = (*pool_head)->size - (*pool_head)->used; - size_t to_alloc; - - /* Make room for ast_string_field_allocation and make it a multiple of that. */ - to_alloc = ast_make_room_for(needed, ast_string_field_allocation); - ast_assert(to_alloc % ast_alignof(ast_string_field_allocation) == 0); - - if (__builtin_expect(to_alloc > space, 0)) { - size_t new_size = (*pool_head)->size; - - while (new_size < to_alloc) { - new_size *= 2; - } - -#if defined(__AST_DEBUG_MALLOC) - if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func)) - return NULL; -#else - if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__)) - return NULL; -#endif - } - - /* pool->base is always aligned (gcc aligned attribute). We ensure that - * to_alloc is also a multiple of ast_alignof(ast_string_field_allocation) - * causing result to always be aligned as well; which in turn fixes that - * AST_STRING_FIELD_ALLOCATION(result) is aligned. */ - result = (*pool_head)->base + (*pool_head)->used; - (*pool_head)->used += to_alloc; - (*pool_head)->active += needed; - result += ast_alignof(ast_string_field_allocation); - AST_STRING_FIELD_ALLOCATION(result) = needed; - mgr->last_alloc = result; - - return result; -} - -int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, size_t needed, - const ast_string_field *ptr) -{ - ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr); - size_t space = (*pool_head)->size - (*pool_head)->used; - - if (*ptr != mgr->last_alloc) { - return 1; - } - - if (space < grow) { - return 1; - } - - (*pool_head)->used += grow; - (*pool_head)->active += grow; - AST_STRING_FIELD_ALLOCATION(*ptr) += grow; - - return 0; -} - -void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, - const ast_string_field ptr) -{ - struct ast_string_field_pool *pool, *prev; - - if (ptr == __ast_string_field_empty) { - return; - } - - for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) { - if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) { - pool->active -= AST_STRING_FIELD_ALLOCATION(ptr); - if (pool->active == 0) { - if (prev) { - prev->prev = pool->prev; - ast_free(pool); - } else { - pool->used = 0; - } - } - break; - } - } -} - -void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, - ast_string_field *ptr, const char *format, va_list ap) -{ - size_t needed; - size_t available; - size_t space = (*pool_head)->size - (*pool_head)->used; - int res; - ssize_t grow; - char *target; - va_list ap2; - - /* if the field already has space allocated, try to reuse it; - otherwise, try to use the empty space at the end of the current - pool - */ - if (*ptr != __ast_string_field_empty) { - target = (char *) *ptr; - available = AST_STRING_FIELD_ALLOCATION(*ptr); - if (*ptr == mgr->last_alloc) { - available += space; - } - } else { - /* pool->used is always a multiple of ast_alignof(ast_string_field_allocation) - * so we don't need to re-align anything here. - */ - target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation); - if (space > ast_alignof(ast_string_field_allocation)) { - available = space - ast_alignof(ast_string_field_allocation); - } else { - available = 0; - } - } - - va_copy(ap2, ap); - res = vsnprintf(target, available, format, ap2); - va_end(ap2); - - if (res < 0) { - /* Are we out of memory? */ - return; - } - if (res == 0) { - __ast_string_field_release_active(*pool_head, *ptr); - *ptr = __ast_string_field_empty; - return; - } - needed = (size_t)res + 1; /* NUL byte */ - - if (needed > available) { - /* the allocation could not be satisfied using the field's current allocation - (if it has one), or the space available in the pool (if it does not). allocate - space for it, adding a new string pool if necessary. - */ - if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) { - return; - } - vsprintf(target, format, ap); - va_end(ap); /* XXX va_end without va_start? */ - __ast_string_field_release_active(*pool_head, *ptr); - *ptr = target; - } else if (*ptr != target) { - /* the allocation was satisfied using available space in the pool, but not - using the space already allocated to the field - */ - __ast_string_field_release_active(*pool_head, *ptr); - mgr->last_alloc = *ptr = target; - ast_assert(needed < (ast_string_field_allocation)-1); - AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed; - (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation); - (*pool_head)->active += needed; - } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) { - /* the allocation was satisfied by using available space in the pool *and* - the field was the last allocated field from the pool, so it grew - */ - AST_STRING_FIELD_ALLOCATION(*ptr) += grow; - (*pool_head)->used += ast_align_for(grow, ast_string_field_allocation); - (*pool_head)->active += grow; - } -} - -void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, - struct ast_string_field_pool **pool_head, - ast_string_field *ptr, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap); - va_end(ap); -} - -void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset, - size_t field_mgr_pool_offset, size_t pool_size, const char *file, - int lineno, const char *func) -{ - struct ast_string_field_mgr *mgr; - struct ast_string_field_pool *pool; - struct ast_string_field_pool **pool_head; - size_t pool_size_needed = sizeof(*pool) + pool_size; - size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed); - void *allocation; - unsigned int x; - -#if defined(__AST_DEBUG_MALLOC) - if (!(allocation = __ast_calloc(num_structs, size_to_alloc, file, lineno, func))) { - return NULL; - } -#else - if (!(allocation = ast_calloc(num_structs, size_to_alloc))) { - return NULL; - } -#endif - - for (x = 0; x < num_structs; x++) { - void *base = allocation + (size_to_alloc * x); - const char **p; - - mgr = base + field_mgr_offset; - pool_head = base + field_mgr_pool_offset; - pool = base + struct_size; - - p = (const char **) pool_head + 1; - while ((struct ast_string_field_mgr *) p != mgr) { - *p++ = __ast_string_field_empty; - } - - mgr->embedded_pool = pool; - *pool_head = pool; - pool->size = size_to_alloc - struct_size - sizeof(*pool); -#if defined(__AST_DEBUG_MALLOC) - mgr->owner_file = file; - mgr->owner_func = func; - mgr->owner_line = lineno; -#endif - } - - return allocation; -} - -/* end of stringfields support */ - AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */ int ast_atomic_fetchadd_int_slow(volatile int *p, int v) diff --git a/tests/test_stringfields.c b/tests/test_stringfields.c index 2eeb83d45f8..e57f8d7e861 100644 --- a/tests/test_stringfields.c +++ b/tests/test_stringfields.c @@ -24,7 +24,6 @@ * * Test module for string fields API * \ingroup tests - * \todo need to test ast_calloc_with_stringfields */ /*** MODULEINFO @@ -50,16 +49,16 @@ AST_TEST_DEFINE(string_field_test) struct { AST_DECLARE_STRING_FIELDS ( AST_STRING_FIELD(string1); - AST_STRING_FIELD(string2); ); + AST_STRING_FIELD_EXTENDED(string2); } test_struct; struct { AST_DECLARE_STRING_FIELDS ( AST_STRING_FIELD(string1); AST_STRING_FIELD(string2); - AST_STRING_FIELD(string3); ); + AST_STRING_FIELD_EXTENDED(string3); } test_struct2; switch (cmd) { @@ -74,6 +73,9 @@ AST_TEST_DEFINE(string_field_test) break; } + memset(&test_struct, 0, sizeof(test_struct)); + memset(&test_struct2, 0, sizeof(test_struct)); + ast_test_status_update(test, "First things first. Let's see if we can actually allocate string fields\n"); if (ast_string_field_init(&test_struct, 32)) { @@ -82,6 +84,7 @@ AST_TEST_DEFINE(string_field_test) } else { ast_test_status_update(test, "All right! Successfully allocated! Now let's get down to business\n"); } + ast_string_field_init_extended(&test_struct, string2); ast_test_status_update(test,"We're going to set some string fields and perform some checks\n"); @@ -255,6 +258,8 @@ AST_TEST_DEFINE(string_field_test) ast_string_field_init(&test_struct2, 32); ast_test_status_update(test, "Now using a totally separate area of memory we're going to test a basic pool freeing scenario\n"); + ast_string_field_init_extended(&test_struct2, string3); + ast_string_field_set(&test_struct2, string1, "first"); ast_string_field_set(&test_struct2, string2, "second"); @@ -294,15 +299,22 @@ AST_TEST_DEFINE(string_field_test) return AST_TEST_FAIL; } +struct test_struct { + int foo; + AST_DECLARE_STRING_FIELDS ( + AST_STRING_FIELD(string1); + ); + int foo2; + AST_STRING_FIELD_EXTENDED(string2); +}; + AST_TEST_DEFINE(string_field_aggregate_test) { - struct test_struct { - AST_DECLARE_STRING_FIELDS ( - AST_STRING_FIELD(string1); - AST_STRING_FIELD(string2); - ); - int foo; - } inst1, inst2, inst3, inst4; + enum ast_test_result_state res = AST_TEST_PASS; + struct test_struct *inst1 = NULL; + struct test_struct *inst2 = NULL; + struct test_struct *inst3 = NULL; + struct test_struct *inst4 = NULL; switch (cmd) { case TEST_INIT: @@ -316,88 +328,189 @@ AST_TEST_DEFINE(string_field_aggregate_test) break; } - ast_string_field_init(&inst1, 32); - ast_string_field_init(&inst2, 32); - ast_string_field_init(&inst3, 32); - ast_string_field_init(&inst4, 32); + inst1 = ast_calloc_with_stringfields(1, struct test_struct, 32); + if (!inst1) { + ast_test_status_update(test, "Unable to allocate structure 1!\n"); + res = AST_TEST_FAIL; + goto error; + } + ast_string_field_init_extended(inst1, string2); + + inst2 = ast_calloc_with_stringfields(1, struct test_struct, 32); + if (!inst2) { + ast_test_status_update(test, "Unable to allocate structure 2!\n"); + res = AST_TEST_FAIL; + goto error; + } + ast_string_field_init_extended(inst2, string2); + + inst3 = ast_calloc_with_stringfields(1, struct test_struct, 32); + if (!inst3) { + ast_test_status_update(test, "Unable to allocate structure 3!\n"); + res = AST_TEST_FAIL; + goto error; + } + ast_string_field_init_extended(inst3, string2); + + inst4 = ast_calloc_with_stringfields(1, struct test_struct, 32); + if (!inst4) { + ast_test_status_update(test, "Unable to allocate structure 4!\n"); + res = AST_TEST_FAIL; + goto error; + } + ast_string_field_init_extended(inst4, string2); + + + ast_string_field_set(inst1, string1, "foo"); + ast_string_field_set(inst1, string2, "bar"); + inst1->foo = 1; + + ast_string_field_ptr_set_by_fields(inst2->__field_mgr_pool, inst2->__field_mgr, &inst2->string2, "bar"); + ast_string_field_ptr_set_by_fields(inst2->__field_mgr_pool, inst2->__field_mgr, &inst2->string1, "foo"); + inst2->foo = 2; + + if (inst3->__field_mgr.header->embedded_pool->prev) { + ast_test_status_update(test, "Structure 3 embedded pool should not have a previous pool!\n"); + res = AST_TEST_FAIL; + goto error; + } + + ast_string_field_set(inst3, string1, "foo"); + + if (inst3->__field_mgr.header->embedded_pool != inst3->__field_mgr_pool) { + ast_test_status_update(test, "Structure 3 embedded pool should have been the current pool!\n"); + res = AST_TEST_FAIL; + goto error; + } + + if (inst3->__field_mgr.header->embedded_pool->prev) { + ast_test_status_update(test, "Structure 3 embedded pool should not have a previous pool!\n"); + res = AST_TEST_FAIL; + goto error; + } + + ast_test_status_update(test, "Structures 3 embedded pool initialized successfully.\n"); + + /* Exhaust the embedded pool */ + ast_string_field_set(inst3, string2, "baz 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + inst3->foo = 3; - ast_string_field_set(&inst1, string1, "foo"); - ast_string_field_set(&inst1, string2, "bar"); - inst1.foo = 1; + if (inst3->__field_mgr_pool == inst3->__field_mgr.header->embedded_pool) { + ast_test_status_update(test, "Structure 3 embedded pool should not have been the current pool!\n"); + res = AST_TEST_FAIL; + goto error; + } - ast_string_field_set(&inst2, string2, "bar"); - ast_string_field_set(&inst2, string1, "foo"); - inst2.foo = 2; + if (inst3->__field_mgr.header->embedded_pool != inst3->__field_mgr_pool->prev) { + ast_test_status_update(test, "Structure 3 embedded pool should be the current pool's previous!\n"); + res = AST_TEST_FAIL; + goto error; + } - ast_string_field_set(&inst3, string1, "foo"); - ast_string_field_set(&inst3, string2, "baz"); - inst3.foo = 3; + ast_test_status_update(test, "Structures 3 additional pool initialized successfully.\n"); - ast_string_field_set(&inst4, string1, "faz"); - ast_string_field_set(&inst4, string2, "baz"); - inst4.foo = 3; + ast_string_field_set(inst4, string1, "faz"); + /* Exhaust the embedded pool */ + ast_string_field_set(inst4, string2, "baz 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + inst4->foo = 4; - if (ast_string_fields_cmp(&inst1, &inst2)) { + if (ast_string_fields_cmp(inst1, inst2)) { ast_test_status_update(test, "Structures 1/2 should be equal!\n"); + res = AST_TEST_FAIL; goto error; } else { ast_test_status_update(test, "Structures 1/2 are equal as expected.\n"); } - if (!ast_string_fields_cmp(&inst1, &inst3)) { + if (!ast_string_fields_cmp(inst1, inst3)) { ast_test_status_update(test, "Structures 1/3 should be different!\n"); + res = AST_TEST_FAIL; goto error; } else { ast_test_status_update(test, "Structures 1/3 are different as expected.\n"); } - if (!ast_string_fields_cmp(&inst2, &inst3)) { + if (!ast_string_fields_cmp(inst2, inst3)) { ast_test_status_update(test, "Structures 2/3 should be different!\n"); + res = AST_TEST_FAIL; goto error; } else { ast_test_status_update(test, "Structures 2/3 are different as expected.\n"); } - if (!ast_string_fields_cmp(&inst3, &inst4)) { + if (!ast_string_fields_cmp(inst3, inst4)) { ast_test_status_update(test, "Structures 3/4 should be different!\n"); + res = AST_TEST_FAIL; goto error; } else { ast_test_status_update(test, "Structures 3/4 are different as expected.\n"); } - if (ast_string_fields_copy(&inst1, &inst3)) { - ast_test_status_update(test, "Copying from structure 3 to structure 4 failed!\n"); + if (ast_string_fields_copy(inst1, inst3)) { + ast_test_status_update(test, "Copying from structure 3 to structure 1 failed!\n"); + res = AST_TEST_FAIL; goto error; } else { - ast_test_status_update(test, "Copying from structure 3 to structure 4 succeeded!\n"); + ast_test_status_update(test, "Copying from structure 3 to structure 1 succeeded!\n"); } /* inst1 and inst3 should now be equal and inst1 should no longer be equal to inst2 */ - if (ast_string_fields_cmp(&inst1, &inst3)) { + if (ast_string_fields_cmp(inst1, inst3)) { ast_test_status_update(test, "Structures 1/3 should be equal!\n"); + res = AST_TEST_FAIL; goto error; } else { ast_test_status_update(test, "Structures 1/3 are equal as expected.\n"); } - if (!ast_string_fields_cmp(&inst1, &inst2)) { + if (!ast_string_fields_cmp(inst1, inst2)) { ast_test_status_update(test, "Structures 1/2 should be different!\n"); - goto error; + res = AST_TEST_FAIL; } else { ast_test_status_update(test, "Structures 1/2 are different as expected.\n"); } - ast_string_field_free_memory(&inst1); - ast_string_field_free_memory(&inst2); - ast_string_field_free_memory(&inst3); - ast_string_field_free_memory(&inst4); - return AST_TEST_PASS; + ast_test_status_update(test, "Reset but don't free.\n"); + + ast_string_field_init(inst1, AST_STRINGFIELD_RESET); + ast_string_field_init(inst2, AST_STRINGFIELD_RESET); + ast_string_field_init(inst3, AST_STRINGFIELD_RESET); + ast_string_field_init(inst4, AST_STRINGFIELD_RESET); + + if (ast_string_fields_cmp(inst1, inst2)) { + ast_test_status_update(test, "Structures 1/2 should be the same (empty)!\n"); + res = AST_TEST_FAIL; + } else { + ast_test_status_update(test, "Structures 1/2 are the same (empty) as expected.\n"); + } + + if (inst4->__field_mgr.header->embedded_pool != inst4->__field_mgr_pool) { + ast_test_status_update(test, "Structure 4 embedded pool should have been the current pool!\n"); + res = AST_TEST_FAIL; + goto error; + } else { + ast_test_status_update(test, "Structure 4 embedded pool is the current pool as expected.\n"); + } + + if (inst4->__field_mgr.header->embedded_pool->prev) { + ast_test_status_update(test, "Structure 4 embedded pool should not have a previous pool!\n"); + res = AST_TEST_FAIL; + goto error; + } else { + ast_test_status_update(test, "Structure 4 embedded pool does not have a previous as expected.\n"); + } + error: - ast_string_field_free_memory(&inst1); - ast_string_field_free_memory(&inst2); - ast_string_field_free_memory(&inst3); - ast_string_field_free_memory(&inst4); - return AST_TEST_FAIL; + ast_string_field_free_memory(inst1); + ast_free(inst1); + ast_string_field_free_memory(inst2); + ast_free(inst2); + ast_string_field_free_memory(inst3); + ast_free(inst3); + ast_string_field_free_memory(inst4); + ast_free(inst4); + + return res; } static int unload_module(void) From 784fb43f430e415ea578f11c583804018d2d9b5b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 5 Apr 2016 12:21:32 -0300 Subject: [PATCH 0321/1578] res_http_websocket: Make core supported. Websockets are a core part of ARI support and as such this module should also be core supported. Change-Id: I8f9283c6a167152761b92984779bb39e3db51a9c --- res/res_http_websocket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 2654578549c..d63caec3e71 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -24,7 +24,7 @@ */ /*** MODULEINFO - extended + core ***/ #include "asterisk.h" From 984d6fd95c4001cc9b333ac29a9e2a50ba2de238 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 27 Mar 2016 22:33:29 -0600 Subject: [PATCH 0322/1578] config: Allow filters when appending to a category In sorcery based config files where there are multiple categories with the same name, you can't use the (+) operator to reliably append to a category because config.c stops looking when it finds the first one with the same name. Example: [1000] type = endpoint [1000] type = aor [1000](+) authenticate_qualify = yes This config will fail because config.c appends authenticate_qualify to the first category it finds, the endpoint, and that's not valid for endpoint. Solution: The capability to find a category that contains a certain variable already exists so the only real change was to parse anything after the '+' that's not a comma, as a filter string. [1000] type = endpoint [1000] type = aor [1000](+type=aor) authenticate_qualify = yes This now works as expected. Although the following example doesn't make any sense for pjsip, you can even specify multiple filters: [1000](+type=aor&qualify_frequency=10) ASTERISK-25868 #close Reported-by: Nick Repin Change-Id: I10773da4c79db36fbf1993961992af63d3441580 --- main/config.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/main/config.c b/main/config.c index a9ea01a8b14..dad3b668be9 100644 --- a/main/config.c +++ b/main/config.c @@ -72,7 +72,8 @@ static char *extconfig_conf = "extconfig.conf"; static struct ao2_container *cfg_hooks; static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg); static inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2); -static int does_category_match(struct ast_category *cat, const char *category_name, const char *match); +static int does_category_match(struct ast_category *cat, const char *category_name, + const char *match, char sep); /*! \brief Structure to keep comments for rewriting configuration files */ struct ast_comment { @@ -864,7 +865,8 @@ static void move_variables(struct ast_category *old, struct ast_category *new) /*! \brief Returns true if ALL of the regex expressions and category name match. * Both can be NULL (I.E. no predicate) which results in a true return; */ -static int does_category_match(struct ast_category *cat, const char *category_name, const char *match) +static int does_category_match(struct ast_category *cat, const char *category_name, + const char *match, char sep) { char *dupmatch; char *nvp = NULL; @@ -883,7 +885,7 @@ static int does_category_match(struct ast_category *cat, const char *category_na dupmatch = ast_strdupa(match); - while ((nvp = ast_strsep(&dupmatch, ',', AST_STRSEP_STRIP))) { + while ((nvp = ast_strsep(&dupmatch, sep, AST_STRSEP_STRIP))) { struct ast_variable *v; char *match_name; char *match_value = NULL; @@ -982,19 +984,19 @@ struct ast_category *ast_category_new_template(const char *name, const char *in_ return new_category(name, in_file, lineno, 1); } -struct ast_category *ast_category_get(const struct ast_config *config, - const char *category_name, const char *filter) +static struct ast_category *category_get_sep(const struct ast_config *config, + const char *category_name, const char *filter, char sep) { struct ast_category *cat; for (cat = config->root; cat; cat = cat->next) { - if (cat->name == category_name && does_category_match(cat, category_name, filter)) { + if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) { return cat; } } for (cat = config->root; cat; cat = cat->next) { - if (does_category_match(cat, category_name, filter)) { + if (does_category_match(cat, category_name, filter, sep)) { return cat; } } @@ -1002,6 +1004,12 @@ struct ast_category *ast_category_get(const struct ast_config *config, return NULL; } +struct ast_category *ast_category_get(const struct ast_config *config, + const char *category_name, const char *filter) +{ + return category_get_sep(config, category_name, filter, ','); +} + const char *ast_category_get_name(const struct ast_category *category) { return category->name; @@ -1125,7 +1133,7 @@ static void ast_includes_destroy(struct ast_config_include *incls) static struct ast_category *next_available_category(struct ast_category *cat, const char *name, const char *filter) { - for (; cat && !does_category_match(cat, name, filter); cat = cat->next); + for (; cat && !does_category_match(cat, name, filter, ','); cat = cat->next); return cat; } @@ -1777,8 +1785,13 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat, while ((cur = strsep(&c, ","))) { if (!strcasecmp(cur, "!")) { (*cat)->ignored = 1; - } else if (!strcasecmp(cur, "+")) { - *cat = ast_category_get(cfg, catname, NULL); + } else if (cur[0] == '+') { + char *filter = NULL; + + if (cur[1] != ',') { + filter = &cur[1]; + } + *cat = category_get_sep(cfg, catname, filter, '&'); if (!(*cat)) { if (newcat) { ast_category_destroy(newcat); From ef4d3f132892a0ce12649bea2f325803e9ad7076 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 30 Mar 2016 16:47:15 -0500 Subject: [PATCH 0323/1578] Dial: Add function to append already-created channel. The Dial API takes responsiblity for creating an outbound channel when calling ast_dial_append(). This commit adds a new function, ast_dial_append_channel(), which allows us to create the channel outside the Dial API and then to append the channel to the ast_dial structure. This is useful for situations where the channel's creation and dialing are distinct operations. Upcoming ARI early bridge work will illustrate its usage. ASTERISK-25889 Change-Id: Id8179f64f8f99132f80dead8d5db2030fd2c0509 --- include/asterisk/dial.h | 12 +++++ main/dial.c | 107 ++++++++++++++++++++++++++++------------ 2 files changed, 87 insertions(+), 32 deletions(-) diff --git a/include/asterisk/dial.h b/include/asterisk/dial.h index c59257ce5b3..168c5091aa7 100644 --- a/include/asterisk/dial.h +++ b/include/asterisk/dial.h @@ -76,6 +76,18 @@ struct ast_dial *ast_dial_create(void); */ int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids); +/*! + * \brief Append a channel using an actual channel object + * + * \param dial The ast_dial to add the channel to + * \param chan The channel to add to the dial + * \retval -1 Failure + * \retval non-zero The position of the channel in the list of dialed channels + * + * \note The chan ref is stolen with a successful return. + */ +int ast_dial_append_channel(struct ast_dial *dial, struct ast_channel *chan); + /*! \brief Request all appended channels, but do not dial * \param dial Dialing structure * \param chan Optional dialing channel diff --git a/main/dial.c b/main/dial.c index 127f327d1a3..80247588d92 100644 --- a/main/dial.c +++ b/main/dial.c @@ -248,22 +248,9 @@ struct ast_dial *ast_dial_create(void) return dial; } -/*! \brief Append a channel - * \note Appends a channel to a dialing structure - * \return Returns channel reference number on success, -1 on failure - */ -int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids) +static int dial_append_common(struct ast_dial *dial, struct ast_dial_channel *channel, + const char *tech, const char *device, const struct ast_assigned_ids *assignedids) { - struct ast_dial_channel *channel = NULL; - - /* Make sure we have required arguments */ - if (!dial || !tech || !device) - return -1; - - /* Allocate new memory for dialed channel structure */ - if (!(channel = ast_calloc(1, sizeof(*channel)))) - return -1; - /* Record technology and device for when we actually dial */ channel->tech = ast_strdup(tech); channel->device = ast_strdup(device); @@ -287,6 +274,60 @@ int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, AST_LIST_INSERT_TAIL(&dial->channels, channel, list); return channel->num; + +} + +/*! \brief Append a channel + * \note Appends a channel to a dialing structure + * \return Returns channel reference number on success, -1 on failure + */ +int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids) +{ + struct ast_dial_channel *channel = NULL; + + /* Make sure we have required arguments */ + if (!dial || !tech || !device) + return -1; + + /* Allocate new memory for dialed channel structure */ + if (!(channel = ast_calloc(1, sizeof(*channel)))) + return -1; + + return dial_append_common(dial, channel, tech, device, assignedids); +} + +int ast_dial_append_channel(struct ast_dial *dial, struct ast_channel *chan) +{ + struct ast_dial_channel *channel; + char *tech; + char *device; + char *dash; + + if (!dial || !chan) { + return -1; + } + + channel = ast_calloc(1, sizeof(*channel)); + if (!channel) { + return -1; + } + channel->owner = chan; + + tech = ast_strdupa(ast_channel_name(chan)); + + device = strchr(tech, '/'); + if (!device) { + ast_free(channel); + return -1; + } + *device++ = '\0'; + + dash = strrchr(device, '-'); + if (dash) { + *dash = '\0'; + } + + return dial_append_common(dial, channel, tech, device, NULL); } /*! \brief Helper function that requests all channels */ @@ -315,27 +356,29 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe } } - /* Copy device string over */ - ast_copy_string(numsubst, channel->device, sizeof(numsubst)); + if (!channel->owner) { + /* Copy device string over */ + ast_copy_string(numsubst, channel->device, sizeof(numsubst)); - if (cap && ast_format_cap_count(cap)) { - cap_request = cap; - } else if (requester_cap) { - cap_request = requester_cap; - } else { - cap_all_audio = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - ast_format_cap_append_by_type(cap_all_audio, AST_MEDIA_TYPE_AUDIO); - cap_request = cap_all_audio; - } + if (cap && ast_format_cap_count(cap)) { + cap_request = cap; + } else if (requester_cap) { + cap_request = requester_cap; + } else { + cap_all_audio = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_format_cap_append_by_type(cap_all_audio, AST_MEDIA_TYPE_AUDIO); + cap_request = cap_all_audio; + } - /* If we fail to create our owner channel bail out */ - if (!(channel->owner = ast_request(channel->tech, cap_request, &assignedids, chan, numsubst, &channel->cause))) { + /* If we fail to create our owner channel bail out */ + if (!(channel->owner = ast_request(channel->tech, cap_request, &assignedids, chan, numsubst, &channel->cause))) { + ao2_cleanup(cap_all_audio); + return -1; + } + cap_request = NULL; + ao2_cleanup(requester_cap); ao2_cleanup(cap_all_audio); - return -1; } - cap_request = NULL; - ao2_cleanup(requester_cap); - ao2_cleanup(cap_all_audio); if (chan) { ast_channel_lock_both(chan, channel->owner); From a098251e7e4f9e019787b996e5897a067c93f41a Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 5 Apr 2016 14:23:35 -0500 Subject: [PATCH 0324/1578] res_pjsip: Handle deferred SDP hold/unhold properly. Some SIP devices indicate hold/unhold using deferred SDP reinvites. In other words, they provide no SDP in the reinvite. A typical transaction that starts hold might look something like this: * Device sends reinvite with no SDP * Asterisk sends 200 OK with SDP indicating sendrecv on streams. * Device sends ACK with SDP indicating sendonly on streams. At this point, PJMedia's SDP negotiator saves Asterisk's local state as being recvonly. Now, when the device attempts to unhold, it again uses a deferred SDP reinvite, so we end up doing the following: * Device sends reinvite with no SDP * Asterisk sends 200 OK with SDP indicating recvonly on streams * Device sends ACK with SDP indicating sendonly on streams The problem here is that Asterisk offered recvonly, and by RFC 3264's rules, if an offer is recvonly, the answer has to be sendonly. The result is that the device is not taken off hold. What is supposed to happen is that Asterisk should indicate sendrecv in the 200 OK that it sends. This way, the device has the freedom to indicate sendrecv if it wants the stream taken off hold, or it can continue to respond with sendonly if the purpose of the reinvite was something else (like a session timer refresher). The fix here is to alter the SDP negotiator's state when we receive a reinvite with no SDP. If the negotiator's state is currently in the recvonly or inactive state, then we alter our local state to be sendrecv. This way, we allow the device to indicate the stream state as desired. ASTERISK-25854 #close Reported by Robert McGilvray Change-Id: I7615737276165eef3a593038413d936247dcc6ed --- res/res_pjsip_session.c | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 80fe8f393b5..59d759fdc9f 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1125,7 +1125,54 @@ static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata) } if (!sdp_info->sdp) { + const pjmedia_sdp_session *local; + int i; + ast_queue_unhold(session->channel); + + pjmedia_sdp_neg_get_active_local(session->inv_session->neg, &local); + if (!local) { + return PJ_FALSE; + } + + /* + * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite). + * When hold is initially indicated, we + * - Receive an INVITE with no SDP + * - Send a 200 OK with SDP, indicating sendrecv in the media streams + * - Receive an ACK with SDP, indicating sendonly in the media streams + * + * At this point, the pjmedia negotiator saves the state of the media direction so that + * if we are to send any offers, we'll offer recvonly in the media streams. This is + * problematic if the device is attempting to unhold, though. If the device unholds + * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly. + * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond + * with sendonly or inactive. The result of this is that the stream is not off hold. + * + * Therefore, in this case, when we receive a reinvite while the stream is on hold, we + * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv + * in order to get the stream off hold. If this is actually a different purpose reinvite + * (like a session timer refresh), then the answerer can respond to our sendrecv with + * sendonly, keeping the stream on hold. + */ + for (i = 0; i < local->media_count; ++i) { + pjmedia_sdp_media *m = local->media[i]; + pjmedia_sdp_attr *recvonly; + pjmedia_sdp_attr *inactive; + + recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL); + inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL); + if (recvonly || inactive) { + pjmedia_sdp_attr *to_remove = recvonly ?: inactive; + pjmedia_sdp_attr *sendrecv; + + pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove); + + sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL); + pjmedia_sdp_media_add_attr(m, sendrecv); + } + } + return PJ_FALSE; } From 1dc5e28624299b245da798418bec1fbc22872ac9 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 28 Mar 2016 13:31:29 -0300 Subject: [PATCH 0325/1578] pbx: Add support for autohints. This change introduces the concept of autohints. These are hints which are created as a result of device state changes occurring within the core. When this happens a hint will be created (if it does not exist already) using the device name as the extension. For example if a device state change is received for "PJSIP/bob" and autohints are enabled on a context then a hint will exist in that context for "bob" with a device of "PJSIP/bob". For virtual or custom device states the name after the type will be used. For example if the device state of "Custom:bob" changes then a hint will exist in that context for "bob" with a device of "Custom:bob". This functionality can be enabled in extensions.conf by placing "autohints=yes" in a context. ASTERISK-25881 #close Change-Id: I7e444c7da41b7b7d33374420fec658beeb18584e --- CHANGES | 5 + include/asterisk/pbx.h | 9 ++ main/pbx.c | 215 ++++++++++++++++++++++++++++++++++++++--- pbx/pbx_config.c | 2 + 4 files changed, 219 insertions(+), 12 deletions(-) diff --git a/CHANGES b/CHANGES index f44df328430..59499505729 100644 --- a/CHANGES +++ b/CHANGES @@ -157,6 +157,11 @@ Core - 'media cache delete ' - remove an item from the cache - 'media cache create ' - retrieve a URI and store it in the cache + * The ability for hints to be automatically created as a result of device state + changes now exists in the PBX. This functionality is referred to as "autohints" + and is configurable in extensions.conf by placing "autohints=yes" in the + context. If enabled then a hint will be automatically created with the name of + the device. Functions ------------------ diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index f5feb9366ae..3b3b84150a8 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -287,6 +287,15 @@ int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data); */ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar); +/*! + * \brief Enable or disable autohints support on a context + * + * \param con pointer to the context + * \param enabled whether autohints are enabled + * + */ +void ast_context_set_autohints(struct ast_context *con, int enabled); + /*! * \brief Merge the temporary contexts into a global contexts list and delete from the * global list the ones that are being added diff --git a/main/pbx.c b/main/pbx.c index 479455ef2d0..7efbdee7a4b 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -306,7 +306,7 @@ struct scoreboard /* make sure all fields are 0 before calling new_find_extensi struct ast_exten *exten; }; -/*! \brief ast_context: An extension context */ +/*! \brief ast_context: An extension context - must remain in sync with fake_context */ struct ast_context { ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */ struct ast_exten *root; /*!< The root of the list of extensions */ @@ -317,6 +317,7 @@ struct ast_context { struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */ char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */ int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */ + int autohints; /*!< Whether autohints support is enabled or not */ AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */ ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */ char name[0]; /*!< Name of the context */ @@ -400,6 +401,19 @@ struct ast_hintdevice { char hintdevice[1]; }; +/*! \brief Container for autohint contexts */ +static struct ao2_container *autohints; + +/*! + * \brief Structure for dial plan autohints + */ +struct ast_autohint { + /*! \brief Name of the registrar */ + char *registrar; + /*! \brief Name of the context */ + char context[1]; +}; + /*! * \note Using the device for hash */ @@ -423,6 +437,7 @@ static int hintdevice_hash_cb(const void *obj, const int flags) return ast_str_case_hash(key); } + /*! * \note Devices on hints are not unique so no CMP_STOP is returned * Dont use ao2_find against hintdevices container cause there always @@ -457,6 +472,59 @@ static int hintdevice_cmp_multiple(void *obj, void *arg, int flags) return cmp ? 0 : CMP_MATCH; } +/*! + * \note Using the context name for hash + */ +static int autohint_hash_cb(const void *obj, const int flags) +{ + const struct ast_autohint *autohint; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + autohint = obj; + key = autohint->context; + break; + default: + ast_assert(0); + return 0; + } + + return ast_str_case_hash(key); +} + +static int autohint_cmp(void *obj, void *arg, int flags) +{ + struct ast_autohint *left = obj; + struct ast_autohint *right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = right->context; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcasecmp(left->context, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + /* + * We could also use a partial key struct containing a length + * so strlen() does not get called for every comparison instead. + */ + cmp = strncmp(left->context, right_key, strlen(right_key)); + break; + default: + ast_assert(0); + cmp = 0; + break; + } + return cmp ? 0 : CMP_MATCH | CMP_STOP; +} + /*! \internal \brief \c ao2_callback function to remove hintdevices */ static int hintdevice_remove_cb(void *obj, void *arg, void *data, int flags) { @@ -2323,6 +2391,7 @@ int ast_extension_close(const char *pattern, const char *data, int needmore) return extension_match_core(pattern, data, needmore); } +/* This structure must remain in sync with ast_context for proper hashtab matching */ struct fake_context /* this struct is purely for matching in the hashtab */ { ast_rwlock_t lock; @@ -2334,6 +2403,7 @@ struct fake_context /* this struct is purely for matching in the hashtab */ struct ast_ignorepat *ignorepats; const char *registrar; int refcount; + int autohints; AST_LIST_HEAD_NOLOCK(, ast_sw) alts; ast_mutex_t macrolock; char name[256]; @@ -3460,6 +3530,11 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc struct ast_hintdevice *device; struct ast_hintdevice *cmpdevice; struct ao2_iterator *dev_iter; + struct ao2_iterator auto_iter; + struct ast_autohint *autohint; + char *virtual_device; + char *type; + char *device_name; if (handle_hint_change_message_type(msg, AST_HINT_UPDATE_DEVICE)) { return; @@ -3475,7 +3550,7 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc return; } - if (ao2_container_count(hintdevices) == 0) { + if (ao2_container_count(hintdevices) == 0 && ao2_container_count(autohints) == 0) { /* There are no hints monitoring devices. */ return; } @@ -3489,25 +3564,61 @@ static void device_state_cb(void *unused, struct stasis_subscription *sub, struc strcpy(cmpdevice->hintdevice, dev_state->device); ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */ + + /* Initially we find all hints for the device and notify them */ dev_iter = ao2_t_callback(hintdevices, OBJ_SEARCH_OBJECT | OBJ_MULTIPLE, hintdevice_cmp_multiple, cmpdevice, "find devices in container"); - if (!dev_iter) { - ast_mutex_unlock(&context_merge_lock); - ast_free(hint_app); - return; + if (dev_iter) { + for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) { + if (device->hint) { + device_state_notify_callbacks(device->hint, &hint_app); + } + } + ao2_iterator_destroy(dev_iter); } - for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) { - if (device->hint) { - device_state_notify_callbacks(device->hint, &hint_app); + /* Second stage we look for any autohint contexts and if the device is not already in the hints + * we create it. + */ + type = ast_strdupa(dev_state->device); + if (ast_strlen_zero(type)) { + goto end; + } + + /* Determine if this is a virtual/custom device or a real device */ + virtual_device = strchr(type, ':'); + device_name = strchr(type, '/'); + if (virtual_device && (!device_name || (virtual_device < device_name))) { + device_name = virtual_device; + } + + /* Invalid device state name - not a virtual/custom device and not a real device */ + if (ast_strlen_zero(device_name)) { + goto end; + } + + *device_name++ = '\0'; + + auto_iter = ao2_iterator_init(autohints, 0); + for (; (autohint = ao2_iterator_next(&auto_iter)); ao2_t_ref(autohint, -1, "Next autohint")) { + if (ast_get_hint(NULL, 0, NULL, 0, NULL, autohint->context, device_name)) { + continue; } + + /* The device has no hint in the context referenced by this autohint so create one */ + ast_add_extension(autohint->context, 0, device_name, + PRIORITY_HINT, NULL, NULL, dev_state->device, + ast_strdup(dev_state->device), ast_free_ptr, autohint->registrar); + + /* Since this hint was just created there are no watchers, so we don't need to notify anyone */ } - ast_mutex_unlock(&context_merge_lock); + ao2_iterator_destroy(&auto_iter); - ao2_iterator_destroy(dev_iter); +end: + ast_mutex_unlock(&context_merge_lock); ast_free(hint_app); return; } @@ -5322,6 +5433,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, dpc->total_context++; ast_cli(fd, "[ Context '%s' created by '%s' ]\n", ast_get_context_name(c), ast_get_context_registrar(c)); + if (c->autohints) { + ast_cli(fd, "Autohints support enabled\n"); + } context_info_printed = 1; } @@ -5344,6 +5458,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } else { ast_cli(fd, "[ Context '%s' created by '%s' ]\n", ast_get_context_name(c), ast_get_context_registrar(c)); + if (c->autohints) { + ast_cli(fd, "Autohints support enabled\n"); + } } context_info_printed = 1; } @@ -6016,6 +6133,11 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, return tmp; } +void ast_context_set_autohints(struct ast_context *con, int enabled) +{ + con->autohints = enabled; +} + void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar); struct store_hint { @@ -6063,6 +6185,41 @@ static void context_merge_incls_swits_igps_other_registrars(struct ast_context * } } +/*! Set up an autohint placeholder in the hints container */ +static void context_table_create_autohints(struct ast_hashtab *table) +{ + struct ast_context *con; + struct ast_hashtab_iter *iter; + + /* Remove all autohints as the below iteration will recreate them */ + ao2_callback(autohints, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); + + iter = ast_hashtab_start_traversal(table); + while ((con = ast_hashtab_next(iter))) { + size_t name_len = strlen(con->name) + 1; + size_t registrar_len = strlen(con->registrar) + 1; + struct ast_autohint *autohint; + + if (!con->autohints) { + continue; + } + + autohint = ao2_alloc_options(sizeof(*autohint) + name_len + registrar_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!autohint) { + continue; + } + + ast_copy_string(autohint->context, con->name, name_len); + autohint->registrar = autohint->context + name_len; + ast_copy_string(autohint->registrar, con->registrar, registrar_len); + + ao2_link(autohints, autohint); + ao2_ref(autohint, -1); + + ast_verb(3, "Enabled autohints support on context '%s'\n", con->name); + } + ast_hashtab_end_traversal(iter); +} /* the purpose of this routine is to duplicate a context, with all its substructure, except for any extens that have a matching registrar */ @@ -6104,6 +6261,9 @@ static void context_merge(struct ast_context **extcontexts, struct ast_hashtab * /* make sure the new context exists, so we have somewhere to stick this exten/prio */ if (!new) { new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */ + if (new) { + new->autohints = context->autohints; + } } /* copy in the includes, switches, and ignorepats */ @@ -6150,6 +6310,10 @@ static void context_merge(struct ast_context **extcontexts, struct ast_hashtab * but that's not available, so we give it the registrar we know about */ new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar); + if (new) { + new->autohints = context->autohints; + } + /* copy in the includes, switches, and ignorepats */ context_merge_incls_swits_igps_other_registrars(new, context, registrar); } @@ -6194,6 +6358,9 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_ ast_wrlock_contexts(); if (!contexts_table) { + /* Create any autohint contexts */ + context_table_create_autohints(exttable); + /* Well, that's odd. There are no contexts. */ contexts_table = exttable; contexts = *extcontexts; @@ -6316,6 +6483,9 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_ } } + /* Create all applicable autohint contexts */ + context_table_create_autohints(contexts_table); + ao2_unlock(hints); ast_unlock_contexts(); @@ -8526,6 +8696,11 @@ static void pbx_shutdown(void) ao2_ref(hintdevices, -1); hintdevices = NULL; } + if (autohints) { + ao2_container_unregister("autohints"); + ao2_ref(autohints, -1); + autohints = NULL; + } if (statecbs) { ao2_container_unregister("statecbs"); ao2_ref(statecbs, -1); @@ -8559,6 +8734,16 @@ static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt) ast_get_context_name(ast_get_extension_context(hintdevice->hint->exten))); } +static void print_autohint_key(void *v_obj, void *where, ao2_prnt_fn *prnt) +{ + struct ast_autohint *autohint = v_obj; + + if (!autohint) { + return; + } + prnt(where, "%s", autohint->context); +} + static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt) { struct ast_state_cb *state_cb = v_obj; @@ -8579,6 +8764,12 @@ int ast_pbx_init(void) if (hintdevices) { ao2_container_register("hintdevices", hintdevices, print_hintdevices_key); } + /* This is protected by the context_and_merge lock */ + autohints = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, HASH_EXTENHINT_SIZE, + autohint_hash_cb, autohint_cmp); + if (hintdevices) { + ao2_container_register("autohints", autohints, print_autohint_key); + } statecbs = ao2_container_alloc(1, NULL, statecbs_cmp); if (statecbs) { ao2_container_register("statecbs", statecbs, print_statecbs_key); @@ -8590,5 +8781,5 @@ int ast_pbx_init(void) return -1; } - return (hints && hintdevices && statecbs) ? 0 : -1; + return (hints && hintdevices && autohints && statecbs) ? 0 : -1; } diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 5848e91d86c..eb2a64f70ef 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -1900,6 +1900,8 @@ static int pbx_load_config(const char *config_file) "Unable to include switch '%s' in context '%s' at line %d of %s\n", v->value, cxt, v->lineno, vfile); } + } else if (!strcasecmp(v->name, "autohints")) { + ast_context_set_autohints(con, ast_true(v->value)); } else { ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d of %s -- IGNORING!!!\n", From dd48d60c5ba239f76b054b1bb6c1e17c68537497 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 30 Mar 2016 17:01:28 -0500 Subject: [PATCH 0326/1578] ARI: Add method to create a new channel. This adds a new ARI method to the channels resource that allows for the creation of a new channel. The channel is created and then placed into the specified Stasis application. This is different from the existing originate method that creates a channel, dials it, and then places the answered channel into the dialplan or a Stasis application. This method does not attempt to call the channel at all. Dialing is left as a later step after channel creation. This allows for pre-dialing channel manipulation if desired. ASTERISK-25889 Change-Id: I3c96a0aba914b08e39f6256371a5bd4c92cbded8 --- CHANGES | 8 ++ res/ari/resource_channels.c | 109 +++++++++++++++++++++++++ res/ari/resource_channels.h | 34 ++++++++ res/res_ari_channels.c | 138 +++++++++++++++++++++++++++++++- rest-api/api-docs/channels.json | 62 ++++++++++++++ 5 files changed, 349 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index f44df328430..b6522564271 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,14 @@ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ +ARI +----------------- + * A new ARI method has been added to the channels resource. "create" allows for + you to create a new channel and place that channel into a Stasis application. This + is similar to origination except that the specified channel is not dialed. This + allows for an application writer to create a channel, perform manipulations on it, + and then delay dialing the channel until later. + Applications ------------------ diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index 297560175f4..1954d6bf9d0 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -1461,3 +1461,112 @@ void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers, args->snoop_id, response); } + +struct ari_channel_thread_data { + struct ast_channel *chan; + struct ast_str *stasis_stuff; +}; + +static void chan_data_destroy(struct ari_channel_thread_data *chan_data) +{ + ast_free(chan_data->stasis_stuff); + ast_hangup(chan_data->chan); + ast_free(chan_data); +} + +/*! + * \brief Thread that owns stasis-created channel. + * + * The channel enters into a Stasis application immediately upon creation. In this + * way, the channel can be manipulated by the Stasis application. Once the channel + * exits the Stasis application, it is hung up. + */ +static void *ari_channel_thread(void *data) +{ + struct ari_channel_thread_data *chan_data = data; + struct ast_app *stasis_app; + + stasis_app = pbx_findapp("Stasis"); + if (!stasis_app) { + ast_log(LOG_ERROR, "Stasis dialplan application is not registered"); + chan_data_destroy(chan_data); + return NULL; + } + + pbx_exec(chan_data->chan, stasis_app, ast_str_buffer(chan_data->stasis_stuff)); + + chan_data_destroy(chan_data); + + return NULL; +} + +void ast_ari_channels_create(struct ast_variable *headers, + struct ast_ari_channels_create_args *args, + struct ast_ari_response *response) +{ + struct ast_assigned_ids assignedids = { + .uniqueid = args->channel_id, + .uniqueid2 = args->other_channel_id, + }; + struct ari_channel_thread_data *chan_data; + struct ast_channel_snapshot *snapshot; + pthread_t thread; + char *dialtech; + char dialdevice[AST_CHANNEL_NAME]; + char *stuff; + int cause; + struct ast_format_cap *request_cap; + struct ast_channel *originator; + + chan_data = ast_calloc(1, sizeof(*chan_data)); + if (!chan_data) { + ast_ari_response_alloc_failed(response); + return; + } + + chan_data->stasis_stuff = ast_str_create(32); + if (!chan_data->stasis_stuff) { + ast_ari_response_alloc_failed(response); + chan_data_destroy(chan_data); + return; + } + + ast_str_append(&chan_data->stasis_stuff, 0, "%s", args->app); + if (!ast_strlen_zero(args->app_args)) { + ast_str_append(&chan_data->stasis_stuff, 0, ",%s", args->app_args); + } + + dialtech = ast_strdupa(args->endpoint); + if ((stuff = strchr(dialtech, '/'))) { + *stuff++ = '\0'; + ast_copy_string(dialdevice, stuff, sizeof(dialdevice)); + } + + originator = ast_channel_get_by_name(args->originator); + if (originator) { + request_cap = ao2_bump(ast_channel_nativeformats(originator)); + } else { + request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_format_cap_append_by_type(request_cap, AST_MEDIA_TYPE_AUDIO); + } + + chan_data->chan = ast_request(dialtech, request_cap, &assignedids, originator, dialdevice, &cause); + ao2_cleanup(request_cap); + ast_channel_cleanup(originator); + if (!chan_data->chan) { + ast_ari_response_alloc_failed(response); + chan_data_destroy(chan_data); + return; + } + + snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan_data->chan)); + + if (ast_pthread_create_detached(&thread, NULL, ari_channel_thread, chan_data)) { + ast_ari_response_alloc_failed(response); + chan_data_destroy(chan_data); + } else { + ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL)); + } + + ao2_ref(snapshot, -1); +} diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h index 4d3ad5f8bc0..bd34e0673b1 100644 --- a/res/ari/resource_channels.h +++ b/res/ari/resource_channels.h @@ -100,6 +100,40 @@ int ast_ari_channels_originate_parse_body( * \param[out] response HTTP response */ void ast_ari_channels_originate(struct ast_variable *headers, struct ast_ari_channels_originate_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_channels_create() */ +struct ast_ari_channels_create_args { + /*! Endpoint for channel communication */ + const char *endpoint; + /*! Stasis Application to place channel into */ + const char *app; + /*! The application arguments to pass to the Stasis application provided by 'app'. Mutually exclusive with 'context', 'extension', 'priority', and 'label'. */ + const char *app_args; + /*! The unique id to assign the channel on creation. */ + const char *channel_id; + /*! The unique id to assign the second channel when using local channels. */ + const char *other_channel_id; + /*! Unique ID of the calling channel */ + const char *originator; +}; +/*! + * \brief Body parsing function for /channels/create. + * \param body The JSON body from which to parse parameters. + * \param[out] args The args structure to parse into. + * \retval zero on success + * \retval non-zero on failure + */ +int ast_ari_channels_create_parse_body( + struct ast_json *body, + struct ast_ari_channels_create_args *args); + +/*! + * \brief Create channel. + * + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_channels_create(struct ast_variable *headers, struct ast_ari_channels_create_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_channels_get() */ struct ast_ari_channels_get_args { /*! Channel's id */ diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 05d8d071420..dbdd8f34f6c 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -265,6 +265,131 @@ static void ast_ari_channels_originate_cb( } #endif /* AST_DEVMODE */ +fin: __attribute__((unused)) + return; +} +int ast_ari_channels_create_parse_body( + struct ast_json *body, + struct ast_ari_channels_create_args *args) +{ + struct ast_json *field; + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "endpoint"); + if (field) { + args->endpoint = ast_json_string_get(field); + } + field = ast_json_object_get(body, "app"); + if (field) { + args->app = ast_json_string_get(field); + } + field = ast_json_object_get(body, "appArgs"); + if (field) { + args->app_args = ast_json_string_get(field); + } + field = ast_json_object_get(body, "channelId"); + if (field) { + args->channel_id = ast_json_string_get(field); + } + field = ast_json_object_get(body, "otherChannelId"); + if (field) { + args->other_channel_id = ast_json_string_get(field); + } + field = ast_json_object_get(body, "originator"); + if (field) { + args->originator = ast_json_string_get(field); + } + return 0; +} + +/*! + * \brief Parameter parsing callback for /channels/create. + * \param get_params GET parameters in the HTTP request. + * \param path_vars Path variables extracted from the request. + * \param headers HTTP headers. + * \param[out] response Response to the HTTP request. + */ +static void ast_ari_channels_create_cb( + struct ast_tcptls_session_instance *ser, + struct ast_variable *get_params, struct ast_variable *path_vars, + struct ast_variable *headers, struct ast_ari_response *response) +{ + struct ast_ari_channels_create_args args = {}; + struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); +#if defined(AST_DEVMODE) + int is_valid; + int code; +#endif /* AST_DEVMODE */ + + for (i = get_params; i; i = i->next) { + if (strcmp(i->name, "endpoint") == 0) { + args.endpoint = (i->value); + } else + if (strcmp(i->name, "app") == 0) { + args.app = (i->value); + } else + if (strcmp(i->name, "appArgs") == 0) { + args.app_args = (i->value); + } else + if (strcmp(i->name, "channelId") == 0) { + args.channel_id = (i->value); + } else + if (strcmp(i->name, "otherChannelId") == 0) { + args.other_channel_id = (i->value); + } else + if (strcmp(i->name, "originator") == 0) { + args.originator = (i->value); + } else + {} + } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + if (ast_ari_channels_create_parse_body(body, &args)) { + ast_ari_response_alloc_failed(response); + goto fin; + } + ast_ari_channels_create(headers, &args, response); +#if defined(AST_DEVMODE) + code = response->response_code; + + switch (code) { + case 0: /* Implementation is still a stub, or the code wasn't set */ + is_valid = response->message == NULL; + break; + case 500: /* Internal Server Error */ + case 501: /* Not Implemented */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + is_valid = ast_ari_validate_channel( + response->message); + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /channels/create\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /channels/create\n"); + ast_ari_response_error(response, 500, + "Internal Server Error", "Response validation failed"); + } +#endif /* AST_DEVMODE */ + fin: __attribute__((unused)) return; } @@ -2553,6 +2678,15 @@ fin: __attribute__((unused)) return; } +/*! \brief REST handler for /api-docs/channels.{format} */ +static struct stasis_rest_handlers channels_create = { + .path_segment = "create", + .callbacks = { + [AST_HTTP_POST] = ast_ari_channels_create_cb, + }, + .num_children = 0, + .children = { } +}; /*! \brief REST handler for /api-docs/channels.{format} */ static struct stasis_rest_handlers channels_channelId_continue = { .path_segment = "continue", @@ -2715,8 +2849,8 @@ static struct stasis_rest_handlers channels = { [AST_HTTP_GET] = ast_ari_channels_list_cb, [AST_HTTP_POST] = ast_ari_channels_originate_cb, }, - .num_children = 1, - .children = { &channels_channelId, } + .num_children = 2, + .children = { &channels_create,&channels_channelId, } }; static int load_module(void) diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index bc0879b5715..a4489fb7d64 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -139,6 +139,68 @@ } ] }, + { + "path": "/channels/create", + "description": "Create a channel and place it in a Stasis app, but do not dial the channel yet.", + "operations": [ + { + "httpMethod": "POST", + "summary": "Create channel.", + "nickname": "create", + "responseClass": "Channel", + "parameters": [ + { + "name": "endpoint", + "description": "Endpoint for channel communication", + "paramType": "query", + "required": true, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "app", + "description": "Stasis Application to place channel into", + "paramType": "query", + "required": true, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "appArgs", + "description": "The application arguments to pass to the Stasis application provided by 'app'. Mutually exclusive with 'context', 'extension', 'priority', and 'label'.", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "channelId", + "description": "The unique id to assign the channel on creation.", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "otherChannelId", + "description": "The unique id to assign the second channel when using local channels.", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "originator", + "description": "Unique ID of the calling channel", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" + } + ] + } + ] + }, { "path": "/channels/{channelId}", "description": "Active channel", From abbb2edd4c897fc3ac8a3589c5b799ff53ed10d2 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 30 Mar 2016 17:18:39 -0500 Subject: [PATCH 0327/1578] ARI: Add method to Dial a created channel. This adds a new ARI method that allows for you to dial a channel that you previously created in ARI. By combining this with the create method for channels, it allows for a workflow where a channel can be created, manipulated, and then dialed. The channel is under control of the ARI application during all stages of the Dial and can even be manipulated based on channel state changes observed within an ARI application. The overarching goal for this is to eventually be able to add a dialed channel to a Stasis bridge earlier than the "Up" state. However, at the moment more work is needed in the Dial and Bridge APIs in order to facilitate that. ASTERISK-25889 #close Change-Id: Ic6c399c791e66c4aa52454222fe4f8b02483a205 --- CHANGES | 3 + include/asterisk/stasis_app.h | 31 +++--- res/ari/resource_channels.c | 68 +++++++++++++ res/ari/resource_channels.h | 28 ++++++ res/res_ari_channels.c | 118 +++++++++++++++++++++- res/res_stasis.c | 6 +- res/stasis/control.c | 168 ++++++++++++++++---------------- rest-api/api-docs/channels.json | 53 ++++++++++ 8 files changed, 371 insertions(+), 104 deletions(-) diff --git a/CHANGES b/CHANGES index b6522564271..c30ed332318 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,9 @@ ARI allows for an application writer to create a channel, perform manipulations on it, and then delay dialing the channel until later. + * To complement the "create" method, a "dial" method has been added to the channels + resource in order to place a call to a created channel. + Applications ------------------ diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index f2b07e0bfeb..981d2d66f8e 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -450,23 +450,6 @@ int stasis_app_control_is_done( const char *stasis_app_control_get_channel_id( const struct stasis_app_control *control); -/*! - * \brief Dial an endpoint and bridge it to a channel in \c res_stasis - * - * If the channel is no longer in \c res_stasis, this function does nothing. - * - * \param control Control for \c res_stasis - * \param endpoint The endpoint to dial. - * \param exten Extension to dial if no endpoint specified. - * \param context Context to use with extension. - * \param timeout The amount of time to wait for answer, before giving up. - * - * \return 0 for success - * \return -1 for error. - */ -int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten, - const char *context, int timeout); - /*! * \brief Apply a bridge role to a channel controlled by a stasis app control * @@ -862,6 +845,20 @@ int stasis_app_channel_unreal_set_internal(struct ast_channel *chan); */ int stasis_app_channel_set_internal(struct ast_channel *chan); +struct ast_dial; + +/*! + * \brief Dial a channel + * \param control Control for \c res_stasis. + * \param dial The ast_dial for the outbound channel + */ +int stasis_app_control_dial(struct stasis_app_control *control, struct ast_dial *dial); + +/*! + * \brief Get dial structure on a control + */ +struct ast_dial *stasis_app_get_dial(struct stasis_app_control *control); + /*! @} */ #endif /* _ASTERISK_STASIS_APP_H */ diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index 1954d6bf9d0..c838bc39cce 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -1570,3 +1570,71 @@ void ast_ari_channels_create(struct ast_variable *headers, ao2_ref(snapshot, -1); } + +void ast_ari_channels_dial(struct ast_variable *headers, + struct ast_ari_channels_dial_args *args, + struct ast_ari_response *response) +{ + RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel *, caller, NULL, ast_channel_cleanup); + struct ast_channel *callee; + struct ast_dial *dial; + + control = find_control(response, args->channel_id); + if (control == NULL) { + /* Response filled in by find_control */ + return; + } + + caller = ast_channel_get_by_name(args->caller); + + callee = ast_channel_get_by_name(args->channel_id); + if (!callee) { + ast_ari_response_error(response, 404, "Not Found", + "Callee not found"); + return; + } + + if (ast_channel_state(callee) != AST_STATE_DOWN) { + ast_channel_unref(callee); + ast_ari_response_error(response, 409, "Conflict", + "Channel is not in the 'Down' state"); + return; + } + + dial = ast_dial_create(); + if (!dial) { + ast_channel_unref(callee); + ast_ari_response_alloc_failed(response); + return; + } + + if (ast_dial_append_channel(dial, callee) < 0) { + ast_channel_unref(callee); + ast_dial_destroy(dial); + ast_ari_response_alloc_failed(response); + return; + } + + /* From this point, we don't have to unref the callee channel on + * failure paths because the dial owns the reference to the called + * channel and will unref the channel for us + */ + + if (ast_dial_prerun(dial, caller, NULL)) { + ast_dial_destroy(dial); + ast_ari_response_alloc_failed(response); + return; + } + + ast_dial_set_user_data(dial, control); + ast_dial_set_global_timeout(dial, args->timeout * 1000); + + if (stasis_app_control_dial(control, dial)) { + ast_dial_destroy(dial); + ast_ari_response_alloc_failed(response); + return; + } + + ast_ari_response_no_content(response); +} diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h index bd34e0673b1..89b466d00a0 100644 --- a/res/ari/resource_channels.h +++ b/res/ari/resource_channels.h @@ -739,5 +739,33 @@ int ast_ari_channels_snoop_channel_with_id_parse_body( * \param[out] response HTTP response */ void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_with_id_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_channels_dial() */ +struct ast_ari_channels_dial_args { + /*! Channel's id */ + const char *channel_id; + /*! Channel ID of caller */ + const char *caller; + /*! Dial timeout */ + int timeout; +}; +/*! + * \brief Body parsing function for /channels/{channelId}/dial. + * \param body The JSON body from which to parse parameters. + * \param[out] args The args structure to parse into. + * \retval zero on success + * \retval non-zero on failure + */ +int ast_ari_channels_dial_parse_body( + struct ast_json *body, + struct ast_ari_channels_dial_args *args); + +/*! + * \brief Dial a created channel. + * + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_channels_dial(struct ast_variable *headers, struct ast_ari_channels_dial_args *args, struct ast_ari_response *response); #endif /* _ASTERISK_RESOURCE_CHANNELS_H */ diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index dbdd8f34f6c..1f081817021 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -2674,6 +2674,111 @@ static void ast_ari_channels_snoop_channel_with_id_cb( } #endif /* AST_DEVMODE */ +fin: __attribute__((unused)) + return; +} +int ast_ari_channels_dial_parse_body( + struct ast_json *body, + struct ast_ari_channels_dial_args *args) +{ + struct ast_json *field; + /* Parse query parameters out of it */ + field = ast_json_object_get(body, "caller"); + if (field) { + args->caller = ast_json_string_get(field); + } + field = ast_json_object_get(body, "timeout"); + if (field) { + args->timeout = ast_json_integer_get(field); + } + return 0; +} + +/*! + * \brief Parameter parsing callback for /channels/{channelId}/dial. + * \param get_params GET parameters in the HTTP request. + * \param path_vars Path variables extracted from the request. + * \param headers HTTP headers. + * \param[out] response Response to the HTTP request. + */ +static void ast_ari_channels_dial_cb( + struct ast_tcptls_session_instance *ser, + struct ast_variable *get_params, struct ast_variable *path_vars, + struct ast_variable *headers, struct ast_ari_response *response) +{ + struct ast_ari_channels_dial_args args = {}; + struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); +#if defined(AST_DEVMODE) + int is_valid; + int code; +#endif /* AST_DEVMODE */ + + for (i = get_params; i; i = i->next) { + if (strcmp(i->name, "caller") == 0) { + args.caller = (i->value); + } else + if (strcmp(i->name, "timeout") == 0) { + args.timeout = atoi(i->value); + } else + {} + } + for (i = path_vars; i; i = i->next) { + if (strcmp(i->name, "channelId") == 0) { + args.channel_id = (i->value); + } else + {} + } + /* Look for a JSON request entity */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); + goto fin; + case ENOMEM: + ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); + goto fin; + case EIO: + ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); + goto fin; + } + } + if (ast_ari_channels_dial_parse_body(body, &args)) { + ast_ari_response_alloc_failed(response); + goto fin; + } + ast_ari_channels_dial(headers, &args, response); +#if defined(AST_DEVMODE) + code = response->response_code; + + switch (code) { + case 0: /* Implementation is still a stub, or the code wasn't set */ + is_valid = response->message == NULL; + break; + case 500: /* Internal Server Error */ + case 501: /* Not Implemented */ + case 404: /* Channel cannot be found. */ + case 409: /* Channel cannot be dialed. */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + is_valid = ast_ari_validate_void( + response->message); + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/dial\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/dial\n"); + ast_ari_response_error(response, 500, + "Internal Server Error", "Response validation failed"); + } +#endif /* AST_DEVMODE */ + fin: __attribute__((unused)) return; } @@ -2831,6 +2936,15 @@ static struct stasis_rest_handlers channels_channelId_snoop = { .children = { &channels_channelId_snoop_snoopId, } }; /*! \brief REST handler for /api-docs/channels.{format} */ +static struct stasis_rest_handlers channels_channelId_dial = { + .path_segment = "dial", + .callbacks = { + [AST_HTTP_POST] = ast_ari_channels_dial_cb, + }, + .num_children = 0, + .children = { } +}; +/*! \brief REST handler for /api-docs/channels.{format} */ static struct stasis_rest_handlers channels_channelId = { .path_segment = "channelId", .is_wildcard = 1, @@ -2839,8 +2953,8 @@ static struct stasis_rest_handlers channels_channelId = { [AST_HTTP_POST] = ast_ari_channels_originate_with_id_cb, [AST_HTTP_DELETE] = ast_ari_channels_hangup_cb, }, - .num_children = 13, - .children = { &channels_channelId_continue,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop, } + .num_children = 14, + .children = { &channels_channelId_continue,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop,&channels_channelId_dial, } }; /*! \brief REST handler for /api-docs/channels.{format} */ static struct stasis_rest_handlers channels = { diff --git a/res/res_stasis.c b/res/res_stasis.c index 63c565d44d1..02645f71762 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1282,6 +1282,7 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, int r; int command_count; RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup); + struct ast_dial *dial; /* Check to see if a bridge absorbed our hangup frame */ if (ast_check_hangup_locked(chan)) { @@ -1291,6 +1292,7 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, last_bridge = bridge; bridge = ao2_bump(stasis_app_get_bridge(control)); + dial = stasis_app_get_dial(control); if (bridge != last_bridge) { app_unsubscribe_bridge(app, last_bridge); @@ -1299,8 +1301,8 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, } } - if (bridge) { - /* Bridge is handling channel frames */ + if (bridge || dial) { + /* Bridge/dial is handling channel frames */ control_wait(control); control_dispatch_all(control, chan); continue; diff --git a/res/stasis/control.c b/res/stasis/control.c index 41d538cbe19..ecd1faf9947 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -77,6 +77,10 @@ struct stasis_app_control { * The app for which this control was created */ struct stasis_app *app; + /*! + * If channel is being dialed, the dial structure. + */ + struct ast_dial *dial; /*! * When set, /c app_stasis should exit and continue in the dialplan. */ @@ -272,89 +276,6 @@ static struct stasis_app_command *exec_command( return exec_command_on_condition(control, command_fn, data, data_destructor, NULL); } -struct stasis_app_control_dial_data { - char endpoint[AST_CHANNEL_NAME]; - int timeout; -}; - -static int app_control_dial(struct stasis_app_control *control, - struct ast_channel *chan, void *data) -{ - RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy); - struct stasis_app_control_dial_data *dial_data = data; - enum ast_dial_result res; - char *tech, *resource; - struct ast_channel *new_chan; - RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup); - - tech = dial_data->endpoint; - if (!(resource = strchr(tech, '/'))) { - return -1; - } - *resource++ = '\0'; - - if (!dial) { - ast_log(LOG_ERROR, "Failed to create dialing structure.\n"); - return -1; - } - - if (ast_dial_append(dial, tech, resource, NULL) < 0) { - ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource); - return -1; - } - - ast_dial_set_global_timeout(dial, dial_data->timeout); - - res = ast_dial_run(dial, NULL, 0); - if (res != AST_DIAL_RESULT_ANSWERED || !(new_chan = ast_dial_answered_steal(dial))) { - return -1; - } - - if (!(bridge = ast_bridge_basic_new())) { - ast_log(LOG_ERROR, "Failed to create basic bridge.\n"); - return -1; - } - - if (ast_bridge_impart(bridge, new_chan, NULL, NULL, - AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { - ast_hangup(new_chan); - } else { - control_add_channel_to_bridge(control, chan, bridge); - } - - return 0; -} - -int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten, const char *context, - int timeout) -{ - struct stasis_app_control_dial_data *dial_data; - - if (!(dial_data = ast_calloc(1, sizeof(*dial_data)))) { - return -1; - } - - if (!ast_strlen_zero(endpoint)) { - ast_copy_string(dial_data->endpoint, endpoint, sizeof(dial_data->endpoint)); - } else if (!ast_strlen_zero(exten) && !ast_strlen_zero(context)) { - snprintf(dial_data->endpoint, sizeof(dial_data->endpoint), "Local/%s@%s", exten, context); - } else { - return -1; - } - - if (timeout > 0) { - dial_data->timeout = timeout * 1000; - } else if (timeout == -1) { - dial_data->timeout = -1; - } else { - dial_data->timeout = 30000; - } - - stasis_app_send_command_async(control, app_control_dial, dial_data, ast_free_ptr); - - return 0; -} - static int app_control_add_role(struct stasis_app_control *control, struct ast_channel *chan, void *data) { @@ -1185,3 +1106,84 @@ struct stasis_app *control_app(struct stasis_app_control *control) { return control->app; } + +static void app_control_dial_destroy(void *data) +{ + struct ast_dial *dial = data; + + ast_dial_join(dial); + ast_dial_destroy(dial); +} + +static int app_control_remove_dial(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + if (ast_dial_state(control->dial) != AST_DIAL_RESULT_ANSWERED) { + ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT); + } + control->dial = NULL; + return 0; +} + +static void on_dial_state(struct ast_dial *dial) +{ + enum ast_dial_result state; + struct stasis_app_control *control; + struct ast_channel *chan; + + state = ast_dial_state(dial); + control = ast_dial_get_user_data(dial); + + switch (state) { + case AST_DIAL_RESULT_ANSWERED: + /* Need to steal the reference to the answered channel so that dial doesn't + * try to hang it up when we destroy the dial structure. + */ + chan = ast_dial_answered_steal(dial); + ast_channel_unref(chan); + /* Fall through intentionally */ + case AST_DIAL_RESULT_INVALID: + case AST_DIAL_RESULT_FAILED: + case AST_DIAL_RESULT_TIMEOUT: + case AST_DIAL_RESULT_HANGUP: + case AST_DIAL_RESULT_UNANSWERED: + /* The dial has completed, so we need to break the Stasis loop so + * that the channel's frames are handled in the proper place now. + */ + stasis_app_send_command_async(control, app_control_remove_dial, dial, app_control_dial_destroy); + break; + case AST_DIAL_RESULT_TRYING: + case AST_DIAL_RESULT_RINGING: + case AST_DIAL_RESULT_PROGRESS: + case AST_DIAL_RESULT_PROCEEDING: + break; + } +} + +static int app_control_dial(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + struct ast_dial *dial = data; + + ast_dial_set_state_callback(dial, on_dial_state); + /* The dial API gives the option of providing a caller channel, but for + * Stasis, we really don't want to do that. The Dial API will take liberties such + * as passing frames along to the calling channel (think ringing, progress, etc.). + * This is not desirable in ARI applications since application writers should have + * control over what does/does not get indicated to the calling channel + */ + ast_dial_run(dial, NULL, 1); + control->dial = dial; + + return 0; +} + +struct ast_dial *stasis_app_get_dial(struct stasis_app_control *control) +{ + return control->dial; +} + +int stasis_app_control_dial(struct stasis_app_control *control, struct ast_dial *dial) +{ + return stasis_app_send_command_async(control, app_control_dial, dial, NULL); +} diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index a4489fb7d64..2389f7cb981 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -1502,6 +1502,59 @@ ] } ] + }, + { + "path": "/channels/{channelId}/dial", + "description": "Dial a channel", + "operations": [ + { + "httpMethod": "POST", + "summary": "Dial a created channel.", + "nickname": "dial", + "responseClass": "void", + "parameters": [ + { + "name": "channelId", + "description": "Channel's id", + "paramType": "path", + "required": true, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "caller", + "description": "Channel ID of caller", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "timeout", + "description": "Dial timeout", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "int", + "defaultValue": 0, + "allowableValues": { + "valueType": "RANGE", + "min": 0 + } + } + ], + "errorResponses": [ + { + "code": 404, + "reason": "Channel cannot be found." + }, + { + "code": 409, + "reason": "Channel cannot be dialed." + } + ] + } + ] } ], "models": { From 8ed5f611523e7f435433fa695fef8334e9101f36 Mon Sep 17 00:00:00 2001 From: Jacek Konieczny Date: Wed, 6 Apr 2016 15:01:47 +0200 Subject: [PATCH 0328/1578] frame.c: Copy the whole subclass in ast_frdup(). The problem is ast_frdup() does not copy whole frame.subclass for voice, video and image frames, only the format is copied. For video frames, the subclass structure contains the .frame_ending flag used to put the RTP marker where it needs to be. ASTERISK-25894 #close Change-Id: I812ca90e84ed5d4f473b997d0dd0d3c5a915fe33 --- main/frame.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main/frame.c b/main/frame.c index ae2120a5a3a..92b92b6e2e1 100644 --- a/main/frame.c +++ b/main/frame.c @@ -320,11 +320,10 @@ struct ast_frame *ast_frdup(const struct ast_frame *f) } out->frametype = f->frametype; + out->subclass = f->subclass; if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO) || (f->frametype == AST_FRAME_IMAGE)) { - out->subclass.format = ao2_bump(f->subclass.format); - } else { - memcpy(&out->subclass, &f->subclass, sizeof(out->subclass)); + ao2_bump(out->subclass.format); } out->datalen = f->datalen; out->samples = f->samples; From 3e5672d843de69761e151238111a9a49e0064b4b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 6 Apr 2016 18:28:49 -0300 Subject: [PATCH 0329/1578] res_pjsip: Fix configuration setting of "regcontext". Due to a merge problem two options were swapped causing the regcontext setting to not get set. Change-Id: Icb33edc668e7357bacbaec2861a6b5ac64edaff1 --- res/res_pjsip/config_global.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index ad03379fdb1..8348a1eb5bd 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -369,10 +369,10 @@ int ast_sip_initialize_sorcery_global(void) DEFAULT_VOICEMAIL_EXTENSION, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_voicemail_extension)); ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT, - OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); + OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval", __stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL), - OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); + OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; From 2eaeea690d14a2c9b8eb962a021a957abdb4444d Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 7 Apr 2016 13:05:26 -0300 Subject: [PATCH 0330/1578] res_pjsip_registrar_expire: Fix race condition at shutdown. When shutting down, the PJSIP sorcery is destroyed. The registrar expiration module queries the PJSIP sorcery to determine what to expire. As there was no synchronization between termination of the expiration thread and the unloading of the module it was possible for the thread to try to access the PJSIP sorcery after it had been destroyed. This change ensures that the thread is shut down before allowing the module to be considered unloaded. Change-Id: I69fd239edbaaf160c2d37ae00d3ac06e5596fe8b --- res/res_pjsip_registrar_expire.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c index 87edf5390c7..e52363e13ce 100644 --- a/res/res_pjsip_registrar_expire.c +++ b/res/res_pjsip_registrar_expire.c @@ -91,6 +91,7 @@ static void expiration_global_loaded(const char *object_type) } else { if (check_thread != AST_PTHREADT_NULL) { pthread_kill(check_thread, SIGURG); + pthread_join(check_thread, NULL); check_thread = AST_PTHREADT_NULL; ast_debug(3, "Interval = 0, shutting thread down\n"); } @@ -105,7 +106,10 @@ static struct ast_sorcery_observer expiration_global_observer = { static int unload_module(void) { if (check_thread != AST_PTHREADT_NULL) { + check_interval = 0; pthread_kill(check_thread, SIGURG); + pthread_join(check_thread, NULL); + check_thread = AST_PTHREADT_NULL; } From 751d7a5a49e67d0e13331c7a89c7eaa4724d1c87 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 7 Apr 2016 10:49:43 -0600 Subject: [PATCH 0331/1578] alembic: Remove batch operations (and sqlite support) Because SQLite doesn't support full ALTER capabilities, alembic scripts require batch operations. However, that capability wasn't available until 0.7.0 which some distributions haven't reached yet. Therefore, the batch operations introduced in commit 86d6e44cc (review 2319) have been reverted and SQLite is unsupported again, for now anyway. Tested the full upgrade and downgrade on MySQL/Mariadb and Postgresql. ASTERISK-25890 #close Reported-by: Harley Peters Change-Id: I82eba5456736320256f6775f5b0b40133f4d1c80 --- contrib/ast-db-manage/config/env.py | 3 +- .../10aedae86a32_add_outgoing_enum_va.py | 10 +--- .../136885b81223_add_regcontext_to_pj.py | 3 +- .../154177371065_add_default_from_user.py | 3 +- ...8e8bbf6b_increase_useragent_column_size.py | 6 +-- .../189a235b3fd7_add_keep_alive_interval.py | 3 +- .../1c688d9a003c_pjsip_voicemail_extension.py | 11 ++-- .../1d50859ed02e_create_accountcode.py | 3 +- .../21e526ad3040_add_pjsip_debug_option.py | 3 +- .../23530d604b96_add_rpid_immediate.py | 3 +- ..._add_bind_rtp_to_media_address_to_pjsip.py | 3 +- .../26f10cadc157_add_pjsip_timeout_options.py | 5 +- .../28b8e71e541f_add_g726_non_standard.py | 3 +- ...8ce1e718f05_add_fatal_response_interval.py | 3 +- ...078ec071b7_increaes_contact_column_size.py | 6 +-- ...1b3_add_pjsip_endpoint_options_for_12_1.py | 38 ++++++------- .../31cd4f4891ec_add_auto_dtmf_mode.py | 10 +--- ...4143e_add_user_eq_phone_option_to_pjsip.py | 3 +- .../3855ee4e5f85_add_missing_pjsip_options.py | 6 +-- ...bc2c9_add_allow_reload_to_ps_transports.py | 3 +- .../423f34ad36e2_fix_pjsip_qualify_ti.py | 12 ++--- ...c44_add_pjsip_endpoint_identifier_order.py | 3 +- .../461d7d691209_add_pjsip_qualify_timeout.py | 6 +-- .../498357a710ae_add_rtp_keepalive.py | 3 +- .../4c573e7135bd_fix_tos_field_types.py | 54 ++++++++----------- ...253c0423_make_q_member_uniqueid_autoinc.py | 25 +++------ .../51f8cb66540e_add_further_dtls_options.py | 5 +- ..._add_contact_expiration_check_interval_.py | 3 +- .../5950038a6ead_fix_pjsip_verifiy_typo.py | 6 +-- ...dd_media_encryption_optimistic_to_pjsip.py | 3 +- ...5e89_add_pjsip_max_initial_qualify_time.py | 3 +- ...a908_add_missing_columns_to_sys_and_reg.py | 8 ++- .../e96a0b8071c_increase_pjsip_column_size.py | 30 +++++------ 33 files changed, 105 insertions(+), 184 deletions(-) diff --git a/contrib/ast-db-manage/config/env.py b/contrib/ast-db-manage/config/env.py index 4118da06681..6740d5906d5 100755 --- a/contrib/ast-db-manage/config/env.py +++ b/contrib/ast-db-manage/config/env.py @@ -58,8 +58,7 @@ def run_migrations_online(): connection = engine.connect() context.configure( connection=connection, - target_metadata=target_metadata, - render_as_batch=True + target_metadata=target_metadata ) try: diff --git a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py index cc9f0e0cc1d..b4ea71cbd01 100755 --- a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py +++ b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py @@ -45,10 +45,7 @@ def upgrade(): context = op.get_context() # Upgrading to this revision WILL clear your directmedia values. - if context.bind.dialect.name == 'sqlite': - with op.batch_alter_table('sippeers') as batch_op: - batch_op.alter_column('directmedia', type_=new_type) - elif context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name != 'postgresql': op.alter_column('sippeers', 'directmedia', type_=new_type, existing_type=old_type) @@ -69,10 +66,7 @@ def downgrade(): op.execute(tcr.update().where(tcr.c.directmedia==u'outgoing') .values(directmedia=None)) - if context.bind.dialect.name == 'sqlite': - with op.batch_alter_table('sippeers') as batch_op: - batch_op.alter_column('directmedia', type_=old_type) - elif context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name != 'postgresql': op.alter_column('sippeers', 'directmedia', type_=old_type, existing_type=new_type) diff --git a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py index 22fd6c7b740..724a5e57695 100644 --- a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py +++ b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py @@ -17,5 +17,4 @@ def upgrade(): op.add_column('ps_globals', sa.Column('regcontext', sa.String(80))) def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('regcontext') + op.drop_column('ps_globals', 'regcontext') diff --git a/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py b/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py index 6c5f808bba7..7e6cf994f61 100644 --- a/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py +++ b/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py @@ -19,5 +19,4 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('default_from_user') + op.drop_column('ps_globals', 'default_from_user') diff --git a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py index c16cff9f4a8..215726fa059 100755 --- a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py +++ b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py @@ -33,11 +33,9 @@ def upgrade(): - with op.batch_alter_table('sippeers') as batch_op: - batch_op.alter_column('useragent', type_=sa.String(255)) + op.alter_column('sippeers', 'useragent', type_=sa.String(255)) def downgrade(): - with op.batch_alter_table('sippeers') as batch_op: - batch_op.alter_column('useragent', type_=sa.String(20)) + op.alter_column('sippeers', 'useragent', type_=sa.String(20)) diff --git a/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py b/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py index dee384d4c30..ba972b64ed6 100644 --- a/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py +++ b/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py @@ -19,5 +19,4 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('keep_alive_interval') + op.drop_column('ps_globals', 'keep_alive_interval') diff --git a/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py index 781dca703ba..e6f917d8708 100644 --- a/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py +++ b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py @@ -22,10 +22,7 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('default_voicemail_extension') - with op.batch_alter_table('ps_aors') as batch_op: - batch_op.drop_column('voicemail_extension') - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('voicemail_extension') - batch_op.drop_column('mwi_subscribe_replaces_unsolicited') + op.drop_column('ps_globals', 'default_voicemail_extension') + op.drop_column('ps_aors', 'voicemail_extension') + op.drop_column('ps_endpoints', 'voicemail_extension') + op.drop_column('ps_endpoints', 'mwi_subscribe_replaces_unsolicited') diff --git a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py b/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py index 4d520fcee6c..eb200013788 100644 --- a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py +++ b/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py @@ -17,5 +17,4 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('accountcode', sa.String(20))) def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('accountcode') + op.drop_column('ps_endpoints', 'accountcode') diff --git a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py index 8b77eb7ac61..2adca628b51 100755 --- a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py +++ b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py @@ -18,5 +18,4 @@ def upgrade(): op.add_column('ps_globals', sa.Column('debug', sa.String(40))) def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('debug') + op.drop_column('ps_globals', 'debug') diff --git a/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py b/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py index 8ca63f1487c..dc0c01c24c3 100755 --- a/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py +++ b/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py @@ -45,5 +45,4 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('rpid_immediate', yesno_values)) def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('rpid_immediate') + op.drop_column('ps_endpoints', 'rpid_immediate') diff --git a/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py b/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py index 1199d0c8380..e7c11da1925 100644 --- a/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py +++ b/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py @@ -28,5 +28,4 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('bind_rtp_to_media_address') + op.drop_column('ps_endpoints', 'bind_rtp_to_media_address') diff --git a/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py b/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py index 2a792d3f1e9..8972d80302a 100644 --- a/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py +++ b/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py @@ -20,6 +20,5 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('rtp_timeout') - batch_op.drop_column('rtp_timeout_hold') + op.drop_column('ps_endpoints', 'rtp_timeout') + op.drop_column('ps_endpoints', 'rtp_timeout_hold') diff --git a/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py b/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py index 09056d6c408..ad36bd9b7cd 100644 --- a/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py +++ b/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py @@ -27,5 +27,4 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('g726_non_standard') + op.drop_column('ps_endpoints', 'g726_non_standard') diff --git a/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py index 8e05a62a4c2..8c499aee8c2 100644 --- a/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py +++ b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py @@ -19,5 +19,4 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_registrations') as batch_op: - batch_op.drop_column('fatal_retry_interval') + op.drop_column('ps_registrations', 'fatal_retry_interval') diff --git a/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py index 9f98750f615..2ade86f9f3d 100644 --- a/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py +++ b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py @@ -15,10 +15,8 @@ def upgrade(): - with op.batch_alter_table('ps_aors') as batch_op: - batch_op.alter_column('contact', type_=sa.String(255)) + op.alter_column('ps_aors', 'contact', type_=sa.String(255)) def downgrade(): - with op.batch_alter_table('ps_aors') as batch_op: - batch_op.alter_column('contact', type_=sa.String(40)) + op.alter_column('ps_aors', 'contact', type_=sa.String(40)) diff --git a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py index 102265ea84a..d39ddb41a59 100755 --- a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py +++ b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py @@ -120,17 +120,15 @@ def upgrade(): op.create_index('ps_registrations_id', 'ps_registrations', ['id']) ########################## add columns ########################### - with op.batch_alter_table('ps_endpoints') as batch_op: # new columns for endpoints - batch_op.add_column(sa.Column('media_address', sa.String(40))) - batch_op.add_column(sa.Column('redirect_method', - pjsip_redirect_method_values)) - batch_op.add_column(sa.Column('set_var', sa.Text())) + op.add_column('ps_endpoints', sa.Column('media_address', sa.String(40))) + op.add_column('ps_endpoints', sa.Column('redirect_method', + pjsip_redirect_method_values)) + op.add_column('ps_endpoints', sa.Column('set_var', sa.Text())) # rename mwi_fromuser to mwi_from_user - batch_op.alter_column('mwi_fromuser', - new_column_name='mwi_from_user', - existing_type=sa.String(40)) + op.alter_column('ps_endpoints', 'mwi_fromuser', + new_column_name='mwi_from_user', existing_type=sa.String(40)) # new columns for contacts op.add_column('ps_contacts', sa.Column('outbound_proxy', sa.String(40))) @@ -144,23 +142,19 @@ def upgrade(): def downgrade(): ########################## drop columns ########################## - with op.batch_alter_table('ps_aors') as batch_op: - batch_op.drop_column('support_path') - batch_op.drop_column('outbound_proxy') - batch_op.drop_column('maximum_expiration') + op.drop_column('ps_aors', 'support_path') + op.drop_column('ps_aors', 'outbound_proxy') + op.drop_column('ps_aors', 'maximum_expiration') - with op.batch_alter_table('ps_contacts') as batch_op: - batch_op.drop_column('path') - batch_op.drop_column('outbound_proxy') + op.drop_column('ps_contacts', 'path') + op.drop_column('ps_contacts', 'outbound_proxy') - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.alter_column('mwi_from_user', - new_column_name='mwi_fromuser', - existing_type=sa.String(40)) + op.alter_column('ps_endpoints', 'mwi_from_user', + new_column_name='mwi_fromuser', existing_type=sa.String(40)) - batch_op.drop_column('set_var') - batch_op.drop_column('redirect_method') - batch_op.drop_column('media_address') + op.drop_column('ps_endpoints', 'set_var') + op.drop_column('ps_endpoints', 'redirect_method') + op.drop_column('ps_endpoints', 'media_address') ########################## drop tables ########################### diff --git a/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py index b1a9f8be8ed..778de8f37a7 100644 --- a/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py +++ b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py @@ -24,10 +24,7 @@ def upgrade(): context = op.get_context() # Upgrading to this revision WILL clear your directmedia values. - if context.bind.dialect.name == 'sqlite': - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.alter_column('dtmf_mode', type_=new_type) - elif context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name != 'postgresql': op.alter_column('ps_endpoints', 'dtmf_mode', type_=new_type, existing_type=old_type) @@ -45,10 +42,7 @@ def upgrade(): def downgrade(): context = op.get_context() - if context.bind.dialect.name == 'sqlite': - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.alter_column('dtmf_mode', type_=old_type) - elif context.bind.dialect.name != 'postgresql': + if context.bind.dialect.name != 'postgresql': op.alter_column('ps_endpoints', 'dtmf_mode', type_=old_type, existing_type=new_type) diff --git a/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py b/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py index 5de7aa862be..145d6bea652 100644 --- a/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py +++ b/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py @@ -27,5 +27,4 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('user_eq_phone', yesno_values)) def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('user_eq_phone') + op.drop_column('ps_endpoints', 'user_eq_phone') diff --git a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py b/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py index 08457a9d8c6..afc1beb3775 100644 --- a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py +++ b/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py @@ -20,7 +20,5 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_contacts') as batch_op: - batch_op.drop_column('user_agent') - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('message_context') + op.drop_column('ps_contacts', 'user_agent') + op.drop_column('ps_endpoints', 'message_context') diff --git a/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py index 7f2c5797855..0becc1e263b 100644 --- a/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py +++ b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py @@ -22,5 +22,4 @@ def upgrade(): op.add_column('ps_transports', sa.Column('allow_reload', yesno_values)) def downgrade(): - with op.batch_alter_table('ps_transports') as batch_op: - batch_op.drop_column('allow_reload') + op.drop_column('ps_transports', 'allow_reload') diff --git a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py index 563b98d08a9..b8b19b4c954 100644 --- a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py +++ b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py @@ -15,13 +15,9 @@ def upgrade(): - with op.batch_alter_table('ps_aors') as batch_op: - batch_op.alter_column('qualify_timeout', type_=sa.Float) - with op.batch_alter_table('ps_contacts') as batch_op: - batch_op.alter_column('qualify_timeout', type_=sa.Float) + op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Float) + op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Float) def downgrade(): - with op.batch_alter_table('ps_aors') as batch_op: - batch_op.alter_column('qualify_timeout', type_=sa.Integer) - with op.batch_alter_table('ps_contacts') as batch_op: - batch_op.alter_column('qualify_timeout', type_=sa.Integer) + op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Integer) + op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Integer) diff --git a/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py b/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py index b09acf7a3f7..b7d99249325 100644 --- a/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py +++ b/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py @@ -18,5 +18,4 @@ def upgrade(): op.add_column('ps_globals', sa.Column('endpoint_identifier_order', sa.String(40))) def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('endpoint_identifier_order') + op.drop_column('ps_globals', 'endpoint_identifier_order') diff --git a/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py b/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py index ec8a90449fb..0512ef93689 100644 --- a/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py +++ b/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py @@ -18,7 +18,5 @@ def upgrade(): op.add_column('ps_contacts', sa.Column('qualify_timeout', sa.Integer)) def downgrade(): - with op.batch_alter_table('ps_aors') as batch_op: - batch_op.drop_column('qualify_timeout') - with op.batch_alter_table('ps_contacts') as batch_op: - batch_op.drop_column('qualify_timeout') + op.drop_column('ps_aors', 'qualify_timeout') + op.drop_column('ps_contacts', 'qualify_timeout') diff --git a/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py index 3ad26509b25..5a4f470aad0 100644 --- a/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py +++ b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py @@ -19,5 +19,4 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('rtp_keepalive') + op.drop_column('ps_endpoints', 'rtp_keepalive') diff --git a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py index d9bbf8977df..27b498f30a7 100755 --- a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py +++ b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py @@ -19,43 +19,35 @@ YESNO_VALUES = ['yes', 'no'] def upgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.alter_column('tos_audio', - type_=sa.String(10)) - batch_op.alter_column('tos_video', - type_=sa.String(10)) - batch_op.drop_column('cos_audio') - batch_op.drop_column('cos_video') - batch_op.add_column(sa.Column('cos_audio', sa.Integer)) - batch_op.add_column(sa.Column('cos_video', sa.Integer)) - - with op.batch_alter_table('ps_transports') as batch_op: - batch_op.alter_column('tos', - type_=sa.String(10)) + op.alter_column('ps_endpoints', 'tos_audio', type_=sa.String(10)) + op.alter_column('ps_endpoints', 'tos_video', type_=sa.String(10)) + op.drop_column('ps_endpoints', 'cos_audio') + op.drop_column('ps_endpoints', 'cos_video') + op.add_column('ps_endpoints', sa.Column('cos_audio', sa.Integer)) + op.add_column('ps_endpoints', sa.Column('cos_video', sa.Integer)) - # Can't cast YENO_VALUES to Integers, so dropping and adding is required - batch_op.drop_column('cos') + op.alter_column('ps_transports', 'tos', type_=sa.String(10)) - batch_op.add_column(sa.Column('cos', sa.Integer)) + # Can't cast YENO_VALUES to Integers, so dropping and adding is required + op.drop_column('ps_transports', 'cos') + op.add_column('ps_transports', sa.Column('cos', sa.Integer)) def downgrade(): yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) # Can't cast string to YESNO_VALUES, so dropping and adding is required - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('tos_audio') - batch_op.drop_column('tos_video') - batch_op.add_column(sa.Column('tos_audio', yesno_values)) - batch_op.add_column(sa.Column('tos_video', yesno_values)) - batch_op.drop_column('cos_audio') - batch_op.drop_column('cos_video') - batch_op.add_column(sa.Column('cos_audio', yesno_values)) - batch_op.add_column(sa.Column('cos_video', yesno_values)) - - with op.batch_alter_table('ps_transports') as batch_op: - batch_op.drop_column('tos') - batch_op.add_column(sa.Column('tos', yesno_values)) + op.drop_column('ps_endpoints', 'tos_audio') + op.drop_column('ps_endpoints', 'tos_video') + op.add_column('ps_endpoints', sa.Column('tos_audio', yesno_values)) + op.add_column('ps_endpoints', sa.Column('tos_video', yesno_values)) + op.drop_column('ps_endpoints', 'cos_audio') + op.drop_column('ps_endpoints', 'cos_video') + op.add_column('ps_endpoints', sa.Column('cos_audio', yesno_values)) + op.add_column('ps_endpoints', sa.Column('cos_video', yesno_values)) + + op.drop_column('ps_transports', 'tos') + op.add_column('ps_transports', sa.Column('tos', yesno_values)) # Can't cast integers to YESNO_VALUES, so dropping and adding is required - batch_op.drop_column('cos') - batch_op.add_column(sa.Column('cos', yesno_values)) + op.drop_column('ps_transports', 'cos') + op.add_column('ps_transports', sa.Column('cos', yesno_values)) diff --git a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py index 632f4c4eb14..01d4985fe5e 100755 --- a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py +++ b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py @@ -36,28 +36,19 @@ def upgrade(): context = op.get_context() # Was unable to find a way to use op.alter_column() to add the unique # index property. - if context.bind.dialect.name == 'sqlite': - with op.batch_alter_table('queue_members') as batch_op: - batch_op.create_primary_key('queue_members_pj', columns='uniqueid') - else: - op.drop_column('queue_members', 'uniqueid') - op.add_column( - 'queue_members', - sa.Column( - name='uniqueid', type_=sa.Integer, nullable=False, - unique=True)) + op.drop_column('queue_members', 'uniqueid') + op.add_column('queue_members', sa.Column(name='uniqueid', type_=sa.Integer, + nullable=False, unique=True)) # The postgres backend does not like the autoincrement needed for # mysql here. It is just the backend that is giving a warning and # not the database itself. - op.alter_column( - table_name='queue_members', column_name='uniqueid', - existing_type=sa.Integer, existing_nullable=False, - autoincrement=True) + op.alter_column(table_name='queue_members', column_name='uniqueid', + existing_type=sa.Integer, existing_nullable=False, + autoincrement=True) def downgrade(): # Was unable to find a way to use op.alter_column() to remove the # unique index property. - with op.batch_alter_table('queue_members') as batch_op: - batch_op.drop_column('uniqueid') - batch_op.add_column(sa.Column(name='uniqueid', type_=sa.String(80), nullable=False)) + op.drop_column('queue_members', 'uniqueid') + op.add_column('queue_members', sa.Column(name='uniqueid', type_=sa.String(80), nullable=False)) diff --git a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py b/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py index 8d0f68f03d9..c2dacda2c68 100644 --- a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py +++ b/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py @@ -28,6 +28,5 @@ def upgrade(): op.add_column('ps_endpoints', sa.Column('media_use_received_transport', yesno_values)) def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('force_avp') - batch_op.drop_column('media_use_received_transport') + op.drop_column('ps_endpoints', 'force_avp') + op.drop_column('ps_endpoints', 'media_use_received_transport') diff --git a/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py b/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py index 2c61f2b9dc8..efa0196ac58 100644 --- a/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py +++ b/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py @@ -17,5 +17,4 @@ def upgrade(): op.add_column('ps_globals', sa.Column('contact_expiration_check_interval', sa.Integer)) def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('contact_expiration_check_interval') + op.drop_column('ps_globals', 'contact_expiration_check_interval') diff --git a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py b/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py index ace5444231d..28ebc8b1773 100644 --- a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py +++ b/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py @@ -19,13 +19,11 @@ def upgrade(): yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) - with op.batch_alter_table('ps_transports') as batch_op: - batch_op.alter_column('verifiy_server', type_=yesno_values, + op.alter_column('ps_transports', 'verifiy_server', type_=yesno_values, new_column_name='verify_server') def downgrade(): yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) - with op.batch_alter_table('ps_transports') as batch_op: - batch_op.alter_column('verify_server', type_=yesno_values, + op.alter_column('ps_transports', 'verify_server', type_=yesno_values, new_column_name='verifiy_server') diff --git a/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py b/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py index fff25040342..7a463f05753 100644 --- a/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py +++ b/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py @@ -28,5 +28,4 @@ def upgrade(): def downgrade(): - with op.batch_alter_table('ps_endpoints') as batch_op: - batch_op.drop_column('media_encryption_optimistic') + op.drop_column('ps_endpoints', 'media_encryption_optimistic') diff --git a/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py b/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py index dc06d84ef1e..0ffd7848da2 100644 --- a/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py +++ b/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py @@ -17,5 +17,4 @@ def upgrade(): op.add_column('ps_globals', sa.Column('max_initial_qualify_time', sa.Integer)) def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.drop_column('max_initial_qualify_time') + op.drop_column('ps_globals', 'max_initial_qualify_time') diff --git a/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py index b4502eb3d13..8aa16f1552e 100644 --- a/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py +++ b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py @@ -29,8 +29,6 @@ def upgrade(): op.add_column('ps_registrations', sa.Column('endpoint', sa.String(40))) def downgrade(): - with op.batch_alter_table('ps_systems') as batch_op: - batch_op.drop_column('disable_tcp_switch') - with op.batch_alter_table('ps_registrations') as batch_op: - batch_op.drop_column('line') - batch_op.drop_column('endpoint') + op.drop_column('ps_systems', 'disable_tcp_switch') + op.drop_column('ps_registrations', 'line') + op.drop_column('ps_registrations', 'endpoint') diff --git a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py b/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py index f25c2987e6f..9c00c012ef7 100644 --- a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py +++ b/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py @@ -15,28 +15,22 @@ def upgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.alter_column('user_agent', type_=sa.String(255)) + op.alter_column('ps_globals', 'user_agent', type_=sa.String(255)) - with op.batch_alter_table('ps_contacts') as batch_op: - batch_op.alter_column('id', type_=sa.String(255)) - batch_op.alter_column('uri', type_=sa.String(255)) - batch_op.alter_column('user_agent', type_=sa.String(255)) + op.alter_column('ps_contacts', 'id', type_=sa.String(255)) + op.alter_column('ps_contacts', 'uri', type_=sa.String(255)) + op.alter_column('ps_contacts', 'user_agent', type_=sa.String(255)) - with op.batch_alter_table('ps_registrations') as batch_op: - batch_op.alter_column('client_uri', type_=sa.String(255)) - batch_op.alter_column('server_uri', type_=sa.String(255)) + op.alter_column('ps_registrations', 'client_uri', type_=sa.String(255)) + op.alter_column('ps_registrations', 'server_uri', type_=sa.String(255)) def downgrade(): - with op.batch_alter_table('ps_globals') as batch_op: - batch_op.alter_column('user_agent', type_=sa.String(40)) + op.alter_column('ps_globals', 'user_agent', type_=sa.String(40)) - with op.batch_alter_table('ps_contacts') as batch_op: - batch_op.alter_column('id', type_=sa.String(40)) - batch_op.alter_column('uri', type_=sa.String(40)) - batch_op.alter_column('user_agent', type_=sa.String(40)) + op.alter_column('ps_contacts', 'id', type_=sa.String(40)) + op.alter_column('ps_contacts', 'uri', type_=sa.String(40)) + op.alter_column('ps_contacts', 'user_agent', type_=sa.String(40)) - with op.batch_alter_table('ps_registrations') as batch_op: - batch_op.alter_column('client_uri', type_=sa.String(40)) - batch_op.alter_column('server_uri', type_=sa.String(40)) + op.alter_column('ps_registrations', 'client_uri', type_=sa.String(40)) + op.alter_column('ps_registrations', 'server_uri', type_=sa.String(40)) From 28cefc3e888f9385443a97fcbeb0be5ee3efc76f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 7 Apr 2016 12:26:57 -0500 Subject: [PATCH 0332/1578] pbx: Update doxygen for extension state watchers. Change-Id: Id1403b12136de62a272c01bb355aef65fd2c2d1e --- include/asterisk/pbx.h | 46 +++++++++++++++++++++++++++--------------- main/pbx.c | 5 ----- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 3b3b84150a8..18b576066b9 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -582,70 +582,80 @@ int ast_hint_presence_state(struct ast_channel *c, const char *context, const ch const char *ast_extension_state2str(int extension_state); /*! - * \brief Registers a state change callback with destructor. + * \brief Add watcher for extension states with destructor. * \since 1.8.9 * \since 10.1.0 * * \param context which context to look in * \param exten which extension to get state * \param change_cb callback to call if state changed - * \param destroy_cb callback to call when registration destroyed. - * \param data to pass to callback + * \param destroy_cb callback to call when the watcher is destroyed. + * \param data to pass to callbacks + * + * \note If context and exten are NULL then the added watcher is global. + * The change_cb is called for every extension's state change. * * \note The change_cb is called if the state of an extension is changed. * - * \note The destroy_cb is called when the registration is - * deleted so the registerer can release any associated - * resources. + * \note The destroy_cb is called when the watcher is deleted so the + * watcher can release any associated resources. * * \retval -1 on failure + * \retval 0 Global watcher added successfully * \retval ID on success */ int ast_extension_state_add_destroy(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data); /*! - * \brief Registers an extended state change callback with destructor. + * \brief Add watcher for extended extension states with destructor. * \since 11 * * \param context which context to look in * \param exten which extension to get state * \param change_cb callback to call if state changed - * \param destroy_cb callback to call when registration destroyed. - * \param data to pass to callback + * \param destroy_cb callback to call when the watcher is destroyed. + * \param data to pass to callbacks + * + * \note If context and exten are NULL then the added watcher is global. + * The change_cb is called for every extension's state change. * * \note The change_cb is called if the state of an extension is changed. * The extended state is passed to the callback in the device_state_info * member of ast_state_cb_info. * - * \note The destroy_cb is called when the registration is - * deleted so the registerer can release any associated - * resources. + * \note The destroy_cb is called when the watcher is deleted so the + * watcher can release any associated resources. * * \retval -1 on failure + * \retval 0 Global watcher added successfully * \retval ID on success */ int ast_extension_state_add_destroy_extended(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data); /*! - * \brief Registers a state change callback + * \brief Add watcher for extension states. * * \param context which context to look in * \param exten which extension to get state * \param change_cb callback to call if state changed * \param data to pass to callback * + * \note If context and exten are NULL then the added watcher is global. + * The change_cb is called for every extension's state change. + * * \note The change_cb is called if the state of an extension is changed. * * \retval -1 on failure + * \retval 0 Global watcher added successfully * \retval ID on success */ int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data); /*! - * \brief Registers an extended state change callback + * \brief Add watcher for extended extension states. * \since 11 * * \param context which context to look in @@ -653,20 +663,24 @@ int ast_extension_state_add(const char *context, const char *exten, * \param change_cb callback to call if state changed * \param data to pass to callback * + * \note If context and exten are NULL then the added watcher is global. + * The change_cb is called for every extension's state change. + * * \note The change_cb is called if the state of an extension is changed. * The extended state is passed to the callback in the device_state_info * member of ast_state_cb_info. * * \retval -1 on failure + * \retval 0 Global watcher added successfully * \retval ID on success */ int ast_extension_state_add_extended(const char *context, const char *exten, ast_state_cb_type change_cb, void *data); /*! - * \brief Deletes a registered state change callback by ID + * \brief Deletes a state change watcher by ID * - * \param id of the registered state callback to delete + * \param id of the state watcher to delete (0 for global watcher) * \param change_cb callback to call if state changed (Used if id == 0 (global)) * * \retval 0 success diff --git a/main/pbx.c b/main/pbx.c index 7efbdee7a4b..1b78bbb3294 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -3732,28 +3732,24 @@ static int extension_state_add_destroy(const char *context, const char *exten, return id; } -/*! \brief Add watcher for extension states with destructor */ int ast_extension_state_add_destroy(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data) { return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0); } -/*! \brief Add watcher for extension states */ int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data) { return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0); } -/*! \brief Add watcher for extended extension states with destructor */ int ast_extension_state_add_destroy_extended(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data) { return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1); } -/*! \brief Add watcher for extended extension states */ int ast_extension_state_add_extended(const char *context, const char *exten, ast_state_cb_type change_cb, void *data) { @@ -3775,7 +3771,6 @@ static int find_hint_by_cb_id(void *obj, void *arg, int flags) return 0; } -/*! \brief ast_extension_state_del: Remove a watcher from the callback list */ int ast_extension_state_del(int id, ast_state_cb_type change_cb) { struct ast_state_cb *p_cur; From 72c19f7dc5ba83b6c0ce55264ba98db6958dab5c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 7 Apr 2016 10:59:13 -0500 Subject: [PATCH 0333/1578] pbx.c: Minor code rearangements. * Pull out a loop invariant. * Convert an else-if ladder to a switch statement. Change-Id: I0a95cfa9474a4600b9865f7b444534d275b37e95 --- main/pbx.c | 115 +++++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 53 deletions(-) diff --git a/main/pbx.c b/main/pbx.c index 7efbdee7a4b..87d8db0cb11 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -3322,7 +3322,8 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str { struct ao2_iterator cb_iter; struct ast_state_cb *state_cb; - int state, same_state; + int state; + int same_state; struct ao2_container *device_state_info; int first_extended_cb_call = 1; char context_name[AST_MAX_CONTEXT]; @@ -3361,7 +3362,8 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str device_state_info = alloc_device_state_info(); state = ast_extension_state3(*hint_app, device_state_info); - if ((same_state = state == hint->laststate) && (~state & AST_EXTENSION_RINGING)) { + same_state = state == hint->laststate; + if (same_state && (~state & AST_EXTENSION_RINGING)) { ao2_cleanup(device_state_info); return; } @@ -3370,17 +3372,19 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str hint->laststate = state; /* record we saw the change */ /* For general callbacks */ - cb_iter = ao2_iterator_init(statecbs, 0); - for (; !same_state && (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) { - execute_state_callback(state_cb->change_cb, - context_name, - exten_name, - state_cb->data, - AST_HINT_UPDATE_DEVICE, - hint, - NULL); + if (!same_state) { + cb_iter = ao2_iterator_init(statecbs, 0); + for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) { + execute_state_callback(state_cb->change_cb, + context_name, + exten_name, + state_cb->data, + AST_HINT_UPDATE_DEVICE, + hint, + NULL); + } + ao2_iterator_destroy(&cb_iter); } - ao2_iterator_destroy(&cb_iter); /* For extension callbacks */ /* extended callbacks are called when the state changed or when AST_STATE_RINGING is @@ -3395,12 +3399,12 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str } if (state_cb->extended || !same_state) { execute_state_callback(state_cb->change_cb, - context_name, - exten_name, - state_cb->data, - AST_HINT_UPDATE_DEVICE, - hint, - state_cb->extended ? device_state_info : NULL); + context_name, + exten_name, + state_cb->data, + AST_HINT_UPDATE_DEVICE, + hint, + state_cb->extended ? device_state_info : NULL); } } ao2_iterator_destroy(&cb_iter); @@ -3458,12 +3462,12 @@ static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_st cb_iter = ao2_iterator_init(statecbs, 0); for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) { execute_state_callback(state_cb->change_cb, - context_name, - exten_name, - state_cb->data, - AST_HINT_UPDATE_PRESENCE, - hint, - NULL); + context_name, + exten_name, + state_cb->data, + AST_HINT_UPDATE_PRESENCE, + hint, + NULL); } ao2_iterator_destroy(&cb_iter); @@ -3471,12 +3475,12 @@ static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_st cb_iter = ao2_iterator_init(hint->callbacks, 0); for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) { execute_state_callback(state_cb->change_cb, - context_name, - exten_name, - state_cb->data, - AST_HINT_UPDATE_PRESENCE, - hint, - NULL); + context_name, + exten_name, + state_cb->data, + AST_HINT_UPDATE_PRESENCE, + hint, + NULL); } ao2_iterator_destroy(&cb_iter); } @@ -3496,27 +3500,32 @@ static int handle_hint_change_message_type(struct stasis_message *msg, enum ast_ hint = stasis_message_data(msg); - if (reason == AST_HINT_UPDATE_DEVICE) { + switch (reason) { + case AST_HINT_UPDATE_DEVICE: device_state_notify_callbacks(hint, &hint_app); - } else if (reason == AST_HINT_UPDATE_PRESENCE) { - char *presence_subtype = NULL; - char *presence_message = NULL; - int state; + break; + case AST_HINT_UPDATE_PRESENCE: + { + char *presence_subtype = NULL; + char *presence_message = NULL; + int state; - state = extension_presence_state_helper( - hint->exten, &presence_subtype, &presence_message); + state = extension_presence_state_helper( + hint->exten, &presence_subtype, &presence_message); + { + struct ast_presence_state_message presence_state = { + .state = state > 0 ? state : AST_PRESENCE_INVALID, + .subtype = presence_subtype, + .message = presence_message + }; - { - struct ast_presence_state_message presence_state = { - .state = state > 0 ? state : AST_PRESENCE_INVALID, - .subtype = presence_subtype, - .message = presence_message - }; - presence_state_notify_callbacks(hint, &hint_app, &presence_state); - } + presence_state_notify_callbacks(hint, &hint_app, &presence_state); + } - ast_free(presence_subtype); - ast_free(presence_message); + ast_free(presence_subtype); + ast_free(presence_message); + } + break; } ast_free(hint_app); @@ -3981,12 +3990,12 @@ static int ast_add_hint(struct ast_exten *e) cb_iter = ao2_iterator_init(statecbs, 0); for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) { execute_state_callback(state_cb->change_cb, - ast_get_context_name(ast_get_extension_context(e)), - ast_get_extension_name(e), - state_cb->data, - AST_HINT_UPDATE_DEVICE, - hint_new, - NULL); + ast_get_context_name(ast_get_extension_context(e)), + ast_get_extension_name(e), + state_cb->data, + AST_HINT_UPDATE_DEVICE, + hint_new, + NULL); } ao2_iterator_destroy(&cb_iter); } From 6138a75e8e438bb92ef541a6339d2a20c5164fd0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 6 Apr 2016 17:57:20 -0500 Subject: [PATCH 0334/1578] pbx.h: Make ast_state_cb_type take more const. This eliminates some casts that I made a note saying v10 and above would no longer need them. Better late than never :) Change-Id: I346cdb3032b6478ceb40eb6fe732978b54035572 --- apps/app_queue.c | 2 +- channels/chan_sip.c | 4 ++-- channels/chan_skinny.c | 4 ++-- include/asterisk/pbx.h | 2 +- main/manager.c | 2 +- main/pbx.c | 3 +-- res/res_pjsip_exten_state.c | 9 +++++---- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 776ada4b8fa..0123e473abf 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2461,7 +2461,7 @@ static int extensionstate2devicestate(int state) return state; } -static int extension_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data) +static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data) { struct ao2_iterator miter, qiter; struct member *m; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index ffc2084a1b6..2a6dd77e7c2 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1269,7 +1269,7 @@ static void check_for_nat(const struct ast_sockaddr *them, struct sip_pvt *p); /*--- Device monitoring and Device/extension state/event handling */ static int extensionstate_update(const char *context, const char *exten, struct state_notify_data *data, struct sip_pvt *p, int force); -static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data); +static int cb_extensionstate(const char *context, const char *exten, struct ast_state_cb_info *info, void *data); static int sip_poke_noanswer(const void *data); static int sip_poke_peer(struct sip_peer *peer, int force); static void sip_poke_all_peers(void); @@ -17389,7 +17389,7 @@ static int extensionstate_update(const char *context, const char *exten, struct /*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem \note If you add an "hint" priority to the extension in the dial plan, you will get notifications on device state changes */ -static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data) +static int cb_extensionstate(const char *context, const char *exten, struct ast_state_cb_info *info, void *data) { struct sip_pvt *p = data; struct state_notify_data notify_data = { diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index da156fc5e47..76990d175c7 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -1671,7 +1671,7 @@ static struct ast_channel_tech skinny_tech = { .send_digit_end = skinny_senddigit_end, }; -static int skinny_extensionstate_cb(char *context, char *id, struct ast_state_cb_info *info, void *data); +static int skinny_extensionstate_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data); static struct skinny_line *skinny_line_alloc(void) { @@ -3413,7 +3413,7 @@ static void transmit_serviceurlstat(struct skinny_device *d, int instance) transmit_response(d, req); } -static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data) +static int skinny_extensionstate_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data) { struct skinny_container *container = data; struct skinny_device *d = NULL; diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 3b3b84150a8..09707527e40 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -109,7 +109,7 @@ struct ast_state_cb_info { }; /*! \brief Typedef for devicestate and hint callbacks */ -typedef int (*ast_state_cb_type)(char *context, char *id, struct ast_state_cb_info *info, void *data); +typedef int (*ast_state_cb_type)(const char *context, const char *exten, struct ast_state_cb_info *info, void *data); /*! \brief Typedef for devicestate and hint callback removal indication callback */ typedef void (*ast_state_cb_destroy_type)(int id, void *data); diff --git a/main/manager.c b/main/manager.c index e74b253ff29..74e95333305 100644 --- a/main/manager.c +++ b/main/manager.c @@ -6765,7 +6765,7 @@ int ast_manager_unregister(const char *action) return 0; } -static int manager_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data) +static int manager_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data) { /* Notify managers of change */ char hint[512]; diff --git a/main/pbx.c b/main/pbx.c index 7efbdee7a4b..a8128ab410d 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -3231,8 +3231,7 @@ static int execute_state_callback(ast_state_cb_type cb, info.exten_state = AST_EXTENSION_REMOVED; } - /* NOTE: The casts will not be needed for v10 and later */ - res = cb((char *) context, (char *) exten, &info, data); + res = cb(context, exten, &info, data); return res; } diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 27d16bd6702..a4ad1cd784b 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -191,8 +191,9 @@ static void notify_task_data_destructor(void *obj) ast_free(task_data->exten_state_data.user_agent); } -static struct notify_task_data *alloc_notify_task_data(char *exten, struct exten_state_subscription *exten_state_sub, - struct ast_state_cb_info *info) +static struct notify_task_data *alloc_notify_task_data(const char *exten, + struct exten_state_subscription *exten_state_sub, + struct ast_state_cb_info *info) { struct notify_task_data *task_data = ao2_alloc(sizeof(*task_data), notify_task_data_destructor); @@ -270,8 +271,8 @@ static int notify_task(void *obj) * * Upon state change, send the appropriate notification to the subscriber. */ -static int state_changed(char *context, char *exten, - struct ast_state_cb_info *info, void *data) +static int state_changed(const char *context, const char *exten, + struct ast_state_cb_info *info, void *data) { struct notify_task_data *task_data; struct exten_state_subscription *exten_state_sub = data; From b3be9454157bc542ab2672cdabbd2a03605eeaee Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 7 Apr 2016 17:39:19 -0400 Subject: [PATCH 0335/1578] res_pjsip_dialog_info: Add missing "direction" attribute in NOTIFY event BLF pickup isn't working on Cisco SPA and Snom phones if the direction="recipient" attribute is missing in 'dialog' tag. This patch adds direction="recipient" if extension state is Ringing. ASTERISK-24601 #close Change-Id: I5b2c097ca29fd59e92ba237ca5d397cb1b0bcd8c --- res/res_pjsip_dialog_info_body_generator.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c index e48057ba483..86f3986544b 100644 --- a/res/res_pjsip_dialog_info_body_generator.c +++ b/res/res_pjsip_dialog_info_body_generator.c @@ -133,6 +133,9 @@ static int dialog_info_generate_body_content(void *body, void *data) dialog = ast_sip_presence_xml_create_node(state_data->pool, dialog_info, "dialog"); ast_sip_presence_xml_create_attr(state_data->pool, dialog, "id", state_data->exten); + if (state_data->exten_state == AST_EXTENSION_RINGING) { + ast_sip_presence_xml_create_attr(state_data->pool, dialog, "direction", "recipient"); + } state = ast_sip_presence_xml_create_node(state_data->pool, dialog, "state"); pj_strdup2(state_data->pool, &state->content, statestring); From f9dab808165bdbda3dbc2dd0ae07c462abfc8162 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 7 Apr 2016 12:37:43 -0400 Subject: [PATCH 0336/1578] app_voicemail/IMAP: IMAP access FATAL error: Out of memory Sometimes uw-imap function 'mail_fetchbody' returns huge len which then pass to uw-imap function 'rfc822_base64'. uw-imap tries to allocate huge memory and abort() on fail. This patch check the len. If the len more than max size (128 Mbytes) log error. This patch also set variables len, newlen to avoid uninizialezed len. This patch also check pointer returned by rfc822_base64. ASTERISK-25899 #close Change-Id: I4a0e7d655f11abef6a5224e2169df6d5c1f1caca --- apps/app_voicemail.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index cd552545ec0..aa8da5f179b 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -580,6 +580,8 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate); #define INTRO "vm-intro" +#define MAX_MAIL_BODY_CONTENT_SIZE 134217728L // 128 Mbyte + #define MAXMSG 100 #define MAXMSGLIMIT 9999 @@ -3624,8 +3626,8 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form char *body_content; char *body_decoded; char *fn = is_intro ? vms->introfn : vms->fn; - unsigned long len; - unsigned long newlen; + unsigned long len = 0; + unsigned long newlen = 0; char filename[256]; if (!body || body == NIL) @@ -3634,12 +3636,18 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form ast_mutex_lock(&vms->lock); body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len); ast_mutex_unlock(&vms->lock); - if (body_content != NIL) { + if (len > MAX_MAIL_BODY_CONTENT_SIZE) { + ast_log(AST_LOG_ERROR, + "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n", + vms->msgArray[vms->curmsg], section, len, MAX_MAIL_BODY_CONTENT_SIZE, vms->imapuser, vms->username); + return -1; + } + if (body_content != NIL && len) { snprintf(filename, sizeof(filename), "%s.%s", fn, format); /* ast_debug(1, body_content); */ body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen); /* If the body of the file is empty, return an error */ - if (!newlen) { + if (!newlen || !body_decoded) { return -1; } write_file(filename, (char *) body_decoded, newlen); From 216abb0ae7b78c2e442a580efae0faa4d490a0f4 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 31 Mar 2016 19:04:29 -0600 Subject: [PATCH 0337/1578] lock: Add named lock capability Locking some objects like sorcery objects can be tricky because the underlying ao2 object may not be the same for all callers. For instance, two threads that call ast_sorcery_retrieve_by_id on the same aor name might actually get 2 different ao2 objects if the underlying wizard had to rehydrate the aor from a database. Locking one ao2 object doesn't have any effect on the other even if those objects had locks in the first place. Named locks allow access control by keyspace and key strings. Now an "aor" named "1000" can be locked and any other thread attempting to lock "aor" "1000" will wait regardless of whether the underlying ao2 object is the same or not. Mutex and rwlocks are supported. This capability will initially be used to lock an aor when multiple threads may be attempting to prune expired contacts from it. Change-Id: If258c0b7f92b02d07243ce70e535821a1ea7fb45 --- include/asterisk/_private.h | 1 + include/asterisk/named_locks.h | 105 +++++++++++++++++++++++ main/asterisk.c | 5 ++ main/named_locks.c | 142 +++++++++++++++++++++++++++++++ tests/test_named_lock.c | 151 +++++++++++++++++++++++++++++++++ 5 files changed, 404 insertions(+) create mode 100644 include/asterisk/named_locks.h create mode 100644 main/named_locks.c create mode 100644 tests/test_named_lock.c diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index a4a4f1bea4b..6dbf24f4d85 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -39,6 +39,7 @@ int ast_dns_system_resolver_init(void); /*!< Provided by dns_system_resolver.c * void threadstorage_init(void); /*!< Provided by threadstorage.c */ int ast_device_state_engine_init(void); /*!< Provided by devicestate.c */ int astobj2_init(void); /*!< Provided by astobj2.c */ +int ast_named_locks_init(void); /*!< Provided by named_locks.c */ int ast_file_init(void); /*!< Provided by file.c */ int ast_features_init(void); /*!< Provided by features.c */ void ast_autoservice_init(void); /*!< Provided by autoservice.c */ diff --git a/include/asterisk/named_locks.h b/include/asterisk/named_locks.h new file mode 100644 index 00000000000..0fe07d99234 --- /dev/null +++ b/include/asterisk/named_locks.h @@ -0,0 +1,105 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Named Locks + * + * \author George Joseph + */ + +#ifndef INCLUDE_ASTERISK_NAMED_LOCKS_H_ +#define INCLUDE_ASTERISK_NAMED_LOCKS_H_ + +#include "asterisk/astobj2.h" + +/*! + * \defgroup named_locks Named mutex and read-write locks + * @{ + * \page NamedLocks Named mutex and read-write locks + * \since 13.9.0 + * + * Locking some objects like sorcery objects can be tricky because the underlying + * ao2 object may not be the same for all callers. For instance, two threads that + * call ast_sorcery_retrieve_by_id on the same aor name might actually get 2 different + * ao2 objects if the underlying wizard had to rehydrate the aor from a database. + * Locking one ao2 object doesn't have any effect on the other even if those objects + * had locks in the first place + * + * Named locks allow access control by name. Now an aor named "1000" can be locked and + * any other thread attempting to lock the aor named "1000" will wait regardless of whether + * the underlying ao2 object is the same or not. + * + * To use a named lock: + * Call ast_named_lock_get with the appropriate keyspace and key. + * Use the standard ao2 lock/unlock functions as needed. + * Call ast_named_lock_put when you're finished with it. + */ + +/*! + * \brief Which type of lock to request. + */ +enum ast_named_lock_type { + /*! Request a named mutex. */ + AST_NAMED_LOCK_TYPE_MUTEX = AO2_ALLOC_OPT_LOCK_MUTEX, + /*! Request a named read/write lock. */ + AST_NAMED_LOCK_TYPE_RWLOCK = AO2_ALLOC_OPT_LOCK_RWLOCK, +}; + +struct ast_named_lock; + +struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func, + enum ast_named_lock_type lock_type, const char *keyspace, const char *key); + +int __ast_named_lock_put(const char *filename, int lineno, const char *func, + struct ast_named_lock *lock); + +/*! + * \brief Geta named lock handle + * \since 13.9.0 + * + * \param lock_type One of ast_named_lock_type + * \param keyspace + * \param key + * \retval A pointer to an ast_named_lock structure + * \retval NULL on error + * + * \note + * keyspace and key can be anything. For sorcery objects, keyspace could be the object type + * and key could be the object id. + */ +#define ast_named_lock_get(lock_type, keyspace, key) \ + __ast_named_lock_get(__FILE__, __LINE__, __PRETTY_FUNCTION__, lock_type, \ + keyspace, key) + +/*! + * \brief Put a named lock handle away + * \since 13.9.0 + * + * \param lock The pointer to the ast_named_lock structure returned by ast_named_lock_get + * \retval 0 Success + * \retval -1 Failure + */ +#define ast_named_lock_put(lock) \ + __ast_named_lock_put(__FILE__, __LINE__, __PRETTY_FUNCTION__, lock) + +/*! + * @} + */ + +#endif /* INCLUDE_ASTERISK_NAMED_LOCKS_H_ */ diff --git a/main/asterisk.c b/main/asterisk.c index 7636ec7b40a..bf2206cd77e 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4339,6 +4339,11 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou exit(1); } + if (ast_named_locks_init()) { + printf("Failed: ast_named_locks_init\n%s", term_quit()); + exit(1); + } + if (ast_opt_console) { if (el_hist == NULL || el == NULL) ast_el_initialize(); diff --git a/main/named_locks.c b/main/named_locks.c new file mode 100644 index 00000000000..b977b553c64 --- /dev/null +++ b/main/named_locks.c @@ -0,0 +1,142 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Named Locks + * + * \author George Joseph + */ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/astobj2.h" +#include "asterisk/named_locks.h" +#include "asterisk/utils.h" + +struct ao2_container *named_locks; +#define NAMED_LOCKS_BUCKETS 101 + +struct ast_named_lock { + char key[0]; +}; + +static int named_locks_hash(const void *obj, const int flags) +{ + const struct ast_named_lock *lock = obj; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + return ast_str_hash(obj); + case OBJ_SEARCH_OBJECT: + return ast_str_hash(lock->key); + default: + /* Hash can only work on something with a full key. */ + ast_assert(0); + return 0; + } +} + +static int named_locks_cmp(void *obj_left, void *obj_right, int flags) +{ + const struct ast_named_lock *object_left = obj_left; + const struct ast_named_lock *object_right = obj_right; + const char *right_key = obj_right; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->key; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(object_left->key, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncmp(object_left->key, right_key, strlen(right_key)); + break; + default: + cmp = 0; + break; + } + + return cmp ? 0 : CMP_MATCH; +} + +static void named_locks_shutdown(void) +{ + ao2_cleanup(named_locks); +} + +int ast_named_locks_init(void) +{ + named_locks = ao2_container_alloc_hash(0, 0, NAMED_LOCKS_BUCKETS, named_locks_hash, NULL, + named_locks_cmp); + if (!named_locks) { + return -1; + } + + ast_register_cleanup(named_locks_shutdown); + + return 0; +} + +struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func, + enum ast_named_lock_type lock_type, const char *keyspace, const char *key) +{ + struct ast_named_lock *lock = NULL; + int concat_key_buff_len = strlen(keyspace) + strlen(key) + 2; + char *concat_key = ast_alloca(concat_key_buff_len); + + sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */ + + ao2_lock(named_locks); + lock = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (lock) { + ao2_unlock(named_locks); + ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type); + return lock; + } + + lock = ao2_alloc_options(sizeof(*lock) + concat_key_buff_len, NULL, lock_type); + if (lock) { + strcpy(lock->key, concat_key); /* Safe */ + ao2_link_flags(named_locks, lock, OBJ_NOLOCK); + } + ao2_unlock(named_locks); + + return lock; +} + +int __ast_named_lock_put(const char *filename, int lineno, const char *func, + struct ast_named_lock *lock) +{ + if (!lock) { + return -1; + } + + ao2_lock(named_locks); + if (ao2_ref(lock, -1) == 2) { + ao2_unlink_flags(named_locks, lock, OBJ_NOLOCK); + } + ao2_unlock(named_locks); + + return 0; +} diff --git a/tests/test_named_lock.c b/tests/test_named_lock.c new file mode 100644 index 00000000000..9e383088e7f --- /dev/null +++ b/tests/test_named_lock.c @@ -0,0 +1,151 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Named Lock unit tests + * + * \author George Joseph + * + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" +#include + +#include "asterisk/test.h" +#include "asterisk/utils.h" +#include "asterisk/module.h" +#include "asterisk/lock.h" +#include "asterisk/named_locks.h" + +static void *lock_thread(void *data) +{ + struct ast_named_lock *lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "lock_test", data); + + if (!lock) { + return NULL; + } + + ao2_lock(lock); + usleep(3000000); + ao2_unlock(lock); + + ast_named_lock_put(lock); + + return NULL; +} + +AST_TEST_DEFINE(named_lock_test) +{ + enum ast_test_result_state res = AST_TEST_FAIL; + struct ast_named_lock *lock1 = NULL; + struct ast_named_lock *lock2 = NULL; + pthread_t thread1; + pthread_t thread2; + struct timeval start_time; + int64_t duration; + + switch(cmd) { + case TEST_INIT: + info->name = "named_lock_test"; + info->category = "/main/lock/"; + info->summary = "Named Lock test"; + info->description = + "Tests that named locks operate as expected"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_status_update(test, "This test should take about 3 seconds\n"); + + /* 2 locks/threads to make sure they're independent */ + ast_pthread_create(&thread1, NULL, lock_thread, "lock_1"); + ast_pthread_create(&thread2, NULL, lock_thread, "lock_2"); + + lock1 = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "lock_test", "lock_1"); + ast_test_validate_cleanup(test, lock1 != NULL, res, fail); + + lock2 = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "lock_test", "lock_2"); + ast_test_validate_cleanup(test, lock2 != NULL, res, fail); + + usleep(1000000); + + /* These should both fail */ + if (!ao2_trylock(lock1)) { + ast_test_status_update(test, "ao2_trylock on lock1 succeeded when it should have failed\n"); + ao2_unlock(lock1); + goto fail; + } + + if (!ao2_trylock(lock2)) { + ast_test_status_update(test, "ao2_trylock on lock2 succeeded when it should have failed\n"); + ao2_unlock(lock2); + goto fail; + } + + start_time = ast_tvnow(); + + /* These should both succeed eventually */ + if (ao2_lock(lock1)) { + ast_test_status_update(test, "ao2_lock on lock1 failed\n"); + goto fail; + } + ao2_unlock(lock1); + + if (ao2_lock(lock2)) { + ast_test_status_update(test, "ao2_lock on lock2 failed\n"); + goto fail; + } + ao2_unlock(lock2); + + duration = ast_tvdiff_ms(ast_tvnow(), start_time); + ast_test_validate_cleanup(test, duration > 1500 && duration < 3500, res, fail); + + res = AST_TEST_PASS; + +fail: + + ast_named_lock_put(lock1); + ast_named_lock_put(lock2); + + pthread_join(thread1, NULL); + pthread_join(thread2, NULL); + + return res; +} + + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(named_lock_test); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(named_lock_test); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Named Lock test module"); From 8637f29d24e6a4354f8b2ca2ecd9a2458a62a80d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 10 Apr 2016 13:16:42 -0600 Subject: [PATCH 0338/1578] pjproject: Add patch to fix Via IPv6 parsing There's a bug in pjproject's sip_parser where the ":" wasn't correctly interpreted. This is causing IPv6 addresses in the "received" parameter of the Via header to cause a syntax check failure. This patch was submitted to Teluu on 4/10/2016. ASTERISK-25910 #close Reported-by: Anthony Messina Change-Id: Ic7e4c4aa14ded61860401ec349f5177568c4d922 --- ...arser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch diff --git a/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch b/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch new file mode 100644 index 00000000000..60c27cb1af2 --- /dev/null +++ b/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch @@ -0,0 +1,30 @@ +From 0fc7ef5f01be9cc74d184c3ca3a973ff1ef44c93 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Sun, 10 Apr 2016 12:54:06 -0600 +Subject: [PATCH] sip_parser.c: Fix pjsip_VIA_PARAM_SPEC_ESC + +pjsip_VIA_PARAM_SPEC_ESC should have been pjsip_TOKEN_SPEC_ESC + ":" but +instead of appending ":" to pjsip_VIA_PARAM_SPEC_ESC it was being appended +to pjsip_VIA_PARAM_SPEC again. This was causing parsing of Via headers +to fail when an ipv6 address was in a "received" param and +PJSIP_UNESCAPE_IN_PLACE was used. Probably just a copy/paste error. +--- + pjsip/src/pjsip/sip_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c +index 378c22f..c18faa3 100644 +--- a/pjsip/src/pjsip/sip_parser.c ++++ b/pjsip/src/pjsip/sip_parser.c +@@ -327,7 +327,7 @@ static pj_status_t init_parser() + + status = pj_cis_dup(&pconst.pjsip_VIA_PARAM_SPEC_ESC, &pconst.pjsip_TOKEN_SPEC_ESC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); +- pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC, ":"); ++ pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC_ESC, ":"); + + status = pj_cis_dup(&pconst.pjsip_HOST_SPEC, &pconst.pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); +-- +2.5.5 + From a621dd5e963dfef65656d78d1cd212a17245055d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 1 Apr 2016 12:30:56 -0600 Subject: [PATCH 0339/1578] res_pjsip contact: Lock expiration/addition of contacts Contact expiration can occur in several places: res_pjsip_registrar, res_pjsip_registrar_expire, and automatically when anyone calls ast_sip_location_retrieve_aor_contact. At the same time, res_pjsip_registrar may also be attempting to renew or add a contact. Since none of this was locked it was possible for one thread to be renewing a contact and another thread to expire it immediately because it was working off of stale data. This was the casue of intermittent registration/inbound/nominal/multiple_contacts test failures. Now, the new named lock functionality is used to lock the aor during contact expire and add operations and res_pjsip_registrar_expire now checks the expiration with the lock held before deleting the contact. ASTERISK-25885 #close Reported-by: Josh Colp Change-Id: I83d413c46a47796f3ab052ca3b349f21cca47059 --- include/asterisk/res_pjsip.h | 43 +++++++++++++++++++++++++ res/res_pjsip/location.c | 44 +++++++++++++++++++++++-- res/res_pjsip_registrar.c | 55 ++++++++++++++++++++++++-------- res/res_pjsip_registrar_expire.c | 18 ++++++++++- 4 files changed, 143 insertions(+), 17 deletions(-) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 2c26c25dabb..1bfae66b359 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -996,9 +996,27 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct * * \retval NULL if no contacts available * \retval non-NULL if contacts available + * + * \warning + * Since this function prunes expired contacts before returning, it holds a named write + * lock on the aor. If you already hold the lock, call ast_sip_location_retrieve_aor_contacts_nolock instead. */ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor); +/*! + * \brief Retrieve all contacts currently available for an AOR without locking the AOR + * \since 13.9.0 + * + * \param aor Pointer to the AOR + * + * \retval NULL if no contacts available + * \retval non-NULL if contacts available + * + * \warning + * This function should only be called if you already hold a named write lock on the aor. + */ +struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor); + /*! * \brief Retrieve the first bound contact from a list of AORs * @@ -1049,11 +1067,36 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na * * \retval -1 failure * \retval 0 success + * + * \warning + * This function holds a named write lock on the aor. If you already hold the lock + * you should call ast_sip_location_add_contact_nolock instead. */ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, struct ast_sip_endpoint *endpoint); +/*! + * \brief Add a new contact to an AOR without locking the AOR + * \since 13.9.0 + * + * \param aor Pointer to the AOR + * \param uri Full contact URI + * \param expiration_time Optional expiration time of the contact + * \param path_info Path information + * \param user_agent User-Agent header from REGISTER request + * \param endpoint The endpoint that resulted in the contact being added + * + * \retval -1 failure + * \retval 0 success + * + * \warning + * This function should only be called if you already hold a named write lock on the aor. + */ +int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, + struct timeval expiration_time, const char *path_info, const char *user_agent, + struct ast_sip_endpoint *endpoint); + /*! * \brief Update a contact * diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 3145daca027..bc14f184b5f 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -27,6 +27,7 @@ #include "include/res_pjsip_private.h" #include "asterisk/res_pjsip_cli.h" #include "asterisk/statsd.h" +#include "asterisk/named_locks.h" /*! \brief Destructor for AOR */ static void aor_destroy(void *obj) @@ -168,7 +169,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct return contact; } -struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor) +struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor) { /* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */ char regex[strlen(ast_sorcery_object_get_id(aor)) + 4]; @@ -191,6 +192,24 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_si return contacts; } +struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor) +{ + struct ao2_container *contacts; + struct ast_named_lock *lock; + + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor)); + if (!lock) { + return NULL; + } + + ao2_wrlock(lock); + contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); + ao2_unlock(lock); + ast_named_lock_put(lock); + + return contacts; +} + void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor, struct ast_sip_contact **contact) { @@ -274,7 +293,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name); } -int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, +int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, struct ast_sip_endpoint *endpoint) { @@ -311,6 +330,27 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, return ast_sorcery_create(ast_sip_get_sorcery(), contact); } +int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, + struct timeval expiration_time, const char *path_info, const char *user_agent, + struct ast_sip_endpoint *endpoint) +{ + int res; + struct ast_named_lock *lock; + + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor)); + if (!lock) { + return -1; + } + + ao2_wrlock(lock); + res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent, + endpoint); + ao2_unlock(lock); + ast_named_lock_put(lock); + + return res; +} + int ast_sip_location_update_contact(struct ast_sip_contact *contact) { return ast_sorcery_update(ast_sip_get_sorcery(), contact); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 46d24324a36..97cf34ae6c0 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -32,6 +32,7 @@ #include "asterisk/test.h" #include "asterisk/taskprocessor.h" #include "asterisk/manager.h" +#include "asterisk/named_locks.h" #include "res_pjsip/include/res_pjsip_private.h" /*** DOCUMENTATION @@ -412,27 +413,21 @@ static int registrar_validate_path(struct rx_task_data *task_data, struct ast_st return -1; } -static int rx_task(void *data) +static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *contacts, + const char *aor_name) { static const pj_str_t USER_AGENT = { "User-Agent", 10 }; - RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup); - RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); - int added = 0, updated = 0, deleted = 0; pjsip_contact_hdr *contact_hdr = NULL; struct registrar_contact_details details = { 0, }; pjsip_tx_data *tdata; - const char *aor_name = ast_sorcery_object_get_id(task_data->aor); RAII_VAR(struct ast_str *, path_str, NULL, ast_free); struct ast_sip_contact *response_contact; char *user_agent = NULL; pjsip_user_agent_hdr *user_agent_hdr; pjsip_expires_hdr *expires_hdr; - /* Retrieve the current contacts, we'll need to know whether to update or not */ - contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor); - /* So we don't count static contacts against max_contacts we prune them out from the container */ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL); @@ -503,7 +498,7 @@ static int rx_task(void *data) continue; } - if (ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), + if (ast_sip_location_add_contact_nolock(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, user_agent, task_data->endpoint)) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", @@ -545,7 +540,7 @@ static int rx_task(void *data) if (ast_sip_location_update_contact(contact_update)) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", contact->uri, expiration); - ast_sorcery_delete(ast_sip_get_sorcery(), contact); + ast_sip_location_delete_contact(contact); continue; } ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n", @@ -584,15 +579,14 @@ static int rx_task(void *data) ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL); } - /* Update the contacts as things will probably have changed */ - ao2_cleanup(contacts); - - contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor); + /* Re-retrieve contacts. Caller will clean up the original container. */ + contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor); response_contact = ao2_callback(contacts, 0, NULL, NULL); /* Send a response containing all of the contacts (including static) that are present on this AOR */ if (ast_sip_create_response(task_data->rdata, 200, response_contact, &tdata) != PJ_SUCCESS) { ao2_cleanup(response_contact); + ao2_cleanup(contacts); return PJ_TRUE; } ao2_cleanup(response_contact); @@ -601,6 +595,7 @@ static int rx_task(void *data) registrar_add_date_header(tdata); ao2_callback(contacts, 0, registrar_add_contact, tdata); + ao2_cleanup(contacts); if ((expires_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) { expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(task_data->aor, NULL, task_data->rdata)); @@ -612,6 +607,38 @@ static int rx_task(void *data) return PJ_TRUE; } +static int rx_task(void *data) +{ + int res; + struct rx_task_data *task_data = data; + struct ao2_container *contacts = NULL; + struct ast_named_lock *lock; + const char *aor_name = ast_sorcery_object_get_id(task_data->aor); + + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", aor_name); + if (!lock) { + ao2_cleanup(task_data); + return PJ_TRUE; + } + + ao2_wrlock(lock); + contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor); + if (!contacts) { + ao2_unlock(lock); + ast_named_lock_put(lock); + ao2_cleanup(task_data); + return PJ_TRUE; + } + + res = rx_task_core(task_data, contacts, aor_name); + ao2_cleanup(contacts); + ao2_unlock(lock); + ast_named_lock_put(lock); + ao2_cleanup(task_data); + + return res; +} + static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) { RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup); diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c index e52363e13ce..0d979a13f4e 100644 --- a/res/res_pjsip_registrar_expire.c +++ b/res/res_pjsip_registrar_expire.c @@ -30,6 +30,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/module.h" +#include "asterisk/named_locks.h" /*! \brief Thread keeping things alive */ static pthread_t check_thread = AST_PTHREADT_NULL; @@ -41,8 +42,23 @@ static unsigned int check_interval; static int expire_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; + struct ast_named_lock *lock; - ast_sorcery_delete(ast_sip_get_sorcery(), contact); + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", contact->aor); + if (!lock) { + return 0; + } + + /* + * We need to check the expiration again with the aor lock held + * in case another thread is attempting to renew the contact. + */ + ao2_wrlock(lock); + if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) { + ast_sip_location_delete_contact(contact); + } + ao2_unlock(lock); + ast_named_lock_put(lock); return 0; } From 2cc56573de8ce3ea22e1d7266137fc4def6acca3 Mon Sep 17 00:00:00 2001 From: Jaco Kroon Date: Mon, 11 Apr 2016 21:26:57 +0200 Subject: [PATCH 0340/1578] core_unreal: Fix hangupcauses not getting set on Local channels ASTERISK-25912 #close Change-Id: I8e72e6894feaf36c9450f2788d205d07baec23aa --- main/core_unreal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main/core_unreal.c b/main/core_unreal.c index 1f5c202ba55..377abd1ffac 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -566,6 +566,11 @@ int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data res = -1; } break; + case AST_CONTROL_PVT_CAUSE_CODE: + /* Return -1 so that asterisk core will correctly set up hangupcauses. */ + unreal_queue_indicate(p, ast, condition, data, datalen); + res = -1; + break; default: res = unreal_queue_indicate(p, ast, condition, data, datalen); break; From 4e00e31ef13de8eac967a05e02e66503bb49ec37 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Tue, 5 Apr 2016 17:56:39 -0400 Subject: [PATCH 0341/1578] res_pjsip_outbound_publish: Add transport for outbound PUBLISH The first available transport of the appropriate type is used now. This patch adds new config option 'transport' for outbound-publish. If transport is set then outbound PUBLISH requests will use this transport. ASTERISK-25901 #close Change-Id: Ib389130489b70e36795b0003fa5fd386e2680151 --- CHANGES | 5 +++++ res/res_pjsip_outbound_publish.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/CHANGES b/CHANGES index 98df1f7563c..e7f0656f572 100644 --- a/CHANGES +++ b/CHANGES @@ -283,6 +283,11 @@ chan_pjsip ------------------ * Added 'pjsip show channelstats' CLI command. +res_pjsip_outbound_publish +------------------ + * Added support for setting the transport used on outbound publish + using the transport configuration option. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------ ------------------------------------------------------------------------------ diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 856d84a7ad9..5b27bdf0dd5 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -87,6 +87,13 @@ Maximum number of authentication attempts before stopping the publication. + + Transport used for outbound publish + + A transport configured in + pjsip.conf. As with other res_pjsip modules, this will use the first available transport of the appropriate type if unconfigured. + + Must be of type 'outbound-publish'. @@ -117,6 +124,8 @@ struct ast_sip_outbound_publish { AST_STRING_FIELD(from_uri); /*! \brief URI for the To header */ AST_STRING_FIELD(to_uri); + /*! \brief Explicit transport to use for publish */ + AST_STRING_FIELD(transport); /*! \brief Outbound proxy to use */ AST_STRING_FIELD(outbound_proxy); /*! \brief The event type to publish */ @@ -150,6 +159,8 @@ struct ast_sip_outbound_publish_client { unsigned int destroy; /*! \brief Outbound publish information */ struct ast_sip_outbound_publish *publish; + /*! \brief The name of the transport to be used for the publish */ + char *transport_name; }; /*! \brief Outbound publish state information (persists for lifetime of a publish) */ @@ -331,6 +342,12 @@ static int send_unpublish_task(void *data) pjsip_tx_data *tdata; if (pjsip_publishc_unpublish(client->client, &tdata) == PJ_SUCCESS) { + if (!ast_strlen_zero(client->transport_name)) { + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; + ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector); + pjsip_tx_data_set_transport(tdata, &selector); + } + pjsip_publishc_send(client->client, tdata); } @@ -566,6 +583,12 @@ static int sip_publish_client_service_queue(void *data) goto fatal; } + if (!ast_strlen_zero(client->transport_name)) { + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; + ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector); + pjsip_tx_data_set_transport(tdata, &selector); + } + status = pjsip_publishc_send(client->client, tdata); if (status == PJ_EBUSY) { /* We attempted to send the message but something else got there first */ @@ -647,6 +670,7 @@ static void sip_outbound_publish_client_destroy(void *obj) ao2_cleanup(client->datastores); ao2_cleanup(client->publish); + ast_free(client->transport_name); /* if unloading the module and all objects have been unpublished send the signal to finish unloading */ @@ -871,6 +895,11 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) if (!ast_sip_create_request_with_auth(&publish->outbound_auths, param->rdata, tsx->last_tx, &tdata)) { + if (!ast_strlen_zero(client->transport_name)) { + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; + ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector); + pjsip_tx_data_set_transport(tdata, &selector); + } pjsip_publishc_send(client->client, tdata); } client->auth_attempts++; @@ -1030,6 +1059,7 @@ static struct ast_sip_outbound_publish_state *sip_outbound_publish_state_alloc( state->client->timer.user_data = state->client; state->client->timer.cb = sip_outbound_publish_timer_cb; + state->client->transport_name = ast_strdup(publish->transport); state->client->publish = ao2_bump(publish); strcpy(state->id, id); @@ -1123,6 +1153,7 @@ static int load_module(void) ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, outbound_proxy)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_outbound_publish, expiration)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "max_auth_attempts", "5", OPT_UINT_T, 0, FLDSET(struct ast_sip_outbound_publish, max_auth_attempts)); + ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, transport)); ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "outbound-publish", "outbound_auth", "", outbound_auth_handler, NULL, NULL, 0, 0); ast_sorcery_reload_object(ast_sip_get_sorcery(), "outbound-publish"); From 49813bc9e569c46ced4d0f09b34153ae2f9463ab Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 7 Apr 2016 17:18:03 -0400 Subject: [PATCH 0342/1578] res_pjsip: Add headers to AMI Event ContactStatusDetail * Added Useragent and RegExpire headers to AMI Event ContactStatusDetail with associated documentation. ASTERISK-25903 #close Change-Id: If3d121e943e588d016ba51d4eb9c6a421a562239 --- res/res_pjsip.c | 6 ++++++ res/res_pjsip/pjsip_options.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index f4dc72549b4..d12951c45fe 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1835,6 +1835,12 @@ The name of the endpoint associated with this information. + + Content of the User-Agent header in REGISTER request + + + Absolute time that this contact is no longer valid after + diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 7fd606d776a..fc64947edc7 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1119,6 +1119,8 @@ static int format_contact_status(void *obj, void *arg, int flags) ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id); ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri); + ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent); + ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec); ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status)); if (status->status == UNKNOWN) { ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); From c00c298a0ec4173d8715846e9140e44b8f6e3ec5 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 7 Apr 2016 13:02:19 -0400 Subject: [PATCH 0343/1578] app_voicemail/IMAP: function 'save_to_folder' creates wrong folder If try to move message to Cust1 (number 5) the function 'save_to_folder' tries to create Greeting folder instead of Cust1. This patch fixed it by setting GREETINGS_FOLDER = -1 ASTERISK-24927 #close Change-Id: I03d1a761894bcc2d130ec9b003bbcddc28e25c51 --- apps/app_voicemail.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index aa8da5f179b..9e646a52aa6 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -622,12 +622,12 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate); #define OPERATOR_EXIT 300 enum vm_box { - NEW_FOLDER, - OLD_FOLDER, - WORK_FOLDER, - FAMILY_FOLDER, - FRIENDS_FOLDER, - GREETINGS_FOLDER + NEW_FOLDER = 0, + OLD_FOLDER = 1, + WORK_FOLDER = 2, + FAMILY_FOLDER = 3, + FRIENDS_FOLDER = 4, + GREETINGS_FOLDER = -1 }; enum vm_option_flags { From 5a0534dc62d276ce11438565ae1dc6c143f0983a Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 12 Apr 2016 11:10:45 -0300 Subject: [PATCH 0344/1578] app_voicemail: Fix test_voicemail_notify_endl test. The test_voicemail_notify_endl test checks the end-of-line characters of an email message to confirm that they are consistent. The test wrongfully assumed that reading from the email message into a buffer will always result in more than 1 character being read. This is incorrect. If only 1 character was read the test would go outside of the buffer and access other memory causing a crash. The test now checks to ensure that 2 or more characters are read in ensuring the test stays within the buffer. ASTERISK-25874 #close Change-Id: Ic2c89cea6e90f2c0bc2d8138306ebbffd4f8b710 --- apps/app_voicemail.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index aa8da5f179b..79adbd09469 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -14456,11 +14456,13 @@ AST_TEST_DEFINE(test_voicemail_notify_endl) rewind(file); while (fgets(buf, sizeof(buf), file)) { if ( + (strlen(buf) > 1 && #ifdef IMAP_STORAGE buf[strlen(buf) - 2] != '\r' #else buf[strlen(buf) - 2] == '\r' #endif + ) || buf[strlen(buf) - 1] != '\n') { res = AST_TEST_FAIL; } From bd3671b39730487e431f5813c0d7b8cb2ed8e6a8 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 12 Apr 2016 14:41:43 -0600 Subject: [PATCH 0345/1578] pjproject: Add patch for removing strip of '[]' from header params From the patch submitted to Teluu on 4/12/2016 <<<<<<<<< The wholesale stripping of '[]' from header parameters causes issues if something (like a port) occurs after the final ']'. '[2001:a::b]' will correctly parse to '2001:a::b' '[2001:a::b]:8080' will correctly parse to '2001:a::b' but the scanner is left with ':8080' and parsing stops with a syntax error. I can't even find a case where stripping the '[]' is a good thing anyway. Even if you continued to parse and resulted in a string that looks like this... '2001:a::b:8080', it's not valid. This came up in Asterisk because Kamailio sends us a Contact with an alias URI parameter that has an IPv6 address in it like this: Contact: which should be legal but causes a syntax error because of the characters after the final ']'. Even if it didn't, the '[]' should still not be stripped. I've run the Asterisk Test Suite for PJSIP (252 tests) many of which are IPv6 enabled. No issues were caused by removing the code that strips the '[]'. >>>>>>>>>>> ASTERISK-25123 #close Reported-by: Anthony Messina Change-Id: I5cb33f4ebf07ee1f2b26d07caae715e2ec65595a --- ...ove-wholesale-strip-from-parse_param.patch | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch diff --git a/third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch b/third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch new file mode 100644 index 00000000000..e0bd9129c88 --- /dev/null +++ b/third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch @@ -0,0 +1,55 @@ +From ce426249ec1270f27560919791f3e13eaeea9152 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Tue, 12 Apr 2016 14:09:53 -0600 +Subject: [PATCH] sip_parser.c: Remove wholesale '[]' strip from + parse_param_impl + +The wholesale stripping of '[]' from header parameters causes issues if +something (like a port) occurrs after the final ']'. + +'[2001:a::b]' will correctly parse to '2001:a::b' +'[2001:a::b]:8080' will correctly parse to '2001:a::b' but the scanner is left +with ':8080' and parsing stops with a syntax error. + +I can't even find a case where stripping the '[]' is a good thing anyway. Even +if you continued to parse and resulted in a string that looks like this... +'2001:a::b:8080', it's not valid. + +This came up in Asterisk because Kamailio sends us a Contact with an alias +URI parameter that has an IPv6 address in it like this: +Contact: +which should be legal but causes a syntax error because of the characters +after the final ']'. Even if it didn't, the '[]' should still not be stripped. + +I've run the Asterisk Test Suite for PJSIP (252 tests) many of which are IPv6 +enabled. No issues were caused by removing the code that strips the '[]'. + +I tried running 'make pjsip-test' but that fails even without my change. :) + +The Asterisk ticket is: https://issues.asterisk.org/jira/browse/ASTERISK-25123 +--- + pjsip/src/pjsip/sip_parser.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c +index c18faa3..98eb5ea 100644 +--- a/pjsip/src/pjsip/sip_parser.c ++++ b/pjsip/src/pjsip/sip_parser.c +@@ -1149,14 +1149,6 @@ static void parse_param_imp( pj_scanner *scanner, pj_pool_t *pool, + pvalue->ptr++; + pvalue->slen -= 2; + } +- } else if (*scanner->curptr == '[') { +- /* pvalue can be a quoted IPv6; in this case, the +- * '[' and ']' quote characters are to be removed +- * from the pvalue. +- */ +- pj_scan_get_char(scanner); +- pj_scan_get_until_ch(scanner, ']', pvalue); +- pj_scan_get_char(scanner); + } else if(pj_cis_match(spec, *scanner->curptr)) { + parser_get_and_unescape(scanner, pool, spec, esc_spec, pvalue); + } +-- +2.5.5 + From caa416d5f305526c1ef7ed9065ab5361d87ebba1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 13 Apr 2016 12:38:01 -0600 Subject: [PATCH 0346/1578] stringfields: Update extended string fields for master only. In 13, the new ast_string_field_header structure had to be dynamically allocated and assigned to a pointer in ast_string_field_mgr to preserve ABI compatability. In master, it can be converted to being a structure-in-place in ast_string_field_mgr to eliminate the extra alloc and free calls. Change-Id: Ia97c5345eec68717a15dc16fe2e6746ff2a926f4 --- include/asterisk/stringfields.h | 21 ++++--------- main/stringfields.c | 55 +++++++++------------------------ tests/test_stringfields.c | 14 ++++----- 3 files changed, 28 insertions(+), 62 deletions(-) diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h index c24424b0a87..24f945b2609 100644 --- a/include/asterisk/stringfields.h +++ b/include/asterisk/stringfields.h @@ -220,23 +220,14 @@ struct ast_string_field_pool { */ AST_VECTOR(ast_string_field_vector, const char **); -/*! - \internal - \brief Structure used to hold a pointer to the embedded pool and the field vector - \since 13.9.0 -*/ -struct ast_string_field_header { - struct ast_string_field_pool *embedded_pool; /*!< pointer to the embedded pool, if any */ - struct ast_string_field_vector string_fields; /*!< field vector for compare and copy */ -}; - /*! \internal \brief Structure used to manage the storage for a set of string fields. */ struct ast_string_field_mgr { ast_string_field last_alloc; /*!< the last field allocated */ - struct ast_string_field_header *header; /*!< pointer to the header */ + struct ast_string_field_pool *embedded_pool; /*!< pointer to the embedded pool, if any */ + struct ast_string_field_vector string_fields; /*!< field vector for compare and copy */ #if defined(__AST_DEBUG_MALLOC) const char *owner_file; /*!< filename of owner */ const char *owner_func; /*!< function name of owner */ @@ -407,10 +398,10 @@ int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr, #define ast_string_field_init_extended(x, field) \ ({ \ int __res__ = -1; \ - if (((void *)(x)) != NULL && (x)->__field_mgr.header != NULL) { \ + if (((void *)(x)) != NULL) { \ ast_string_field *non_const = (ast_string_field *)&(x)->field; \ *non_const = __ast_string_field_empty; \ - __res__ = AST_VECTOR_APPEND(&(x)->__field_mgr.header->string_fields, non_const); \ + __res__ = AST_VECTOR_APPEND(&(x)->__field_mgr.string_fields, non_const); \ } \ __res__; \ }) @@ -613,8 +604,8 @@ void __ast_string_field_release_active(struct ast_string_field_pool *pool_head, ({ \ int __res__ = -1; \ if (((void *)(instance1)) != NULL && ((void *)(instance2)) != NULL) { \ - __res__ = __ast_string_fields_cmp(&(instance1)->__field_mgr.header->string_fields, \ - &(instance2)->__field_mgr.header->string_fields); \ + __res__ = __ast_string_fields_cmp(&(instance1)->__field_mgr.string_fields, \ + &(instance2)->__field_mgr.string_fields); \ } \ __res__; \ }) diff --git a/main/stringfields.c b/main/stringfields.c index 67dd06c9b0e..e82b49b98a1 100644 --- a/main/stringfields.c +++ b/main/stringfields.c @@ -118,29 +118,23 @@ int __ast_string_field_free_memory(struct ast_string_field_mgr *mgr, struct ast_string_field_pool *cur = NULL; struct ast_string_field_pool *preserve = NULL; - if (!mgr->header) { - return -1; - } - /* reset all the fields regardless of cleanup type */ - AST_VECTOR_CALLBACK_VOID(&mgr->header->string_fields, reset_field); + AST_VECTOR_CALLBACK_VOID(&mgr->string_fields, reset_field); switch (cleanup_type) { case AST_STRINGFIELD_DESTROY: - AST_VECTOR_FREE(&mgr->header->string_fields); + AST_VECTOR_FREE(&mgr->string_fields); - if (mgr->header->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */ - preserve = mgr->header->embedded_pool; + if (mgr->embedded_pool) { /* ALWAYS preserve the embedded pool if there is one */ + preserve = mgr->embedded_pool; preserve->used = preserve->active = 0; } - ast_free(mgr->header); - mgr->header = NULL; break; case AST_STRINGFIELD_RESET: /* Preserve the embedded pool if there is one, otherwise the last pool */ - if (mgr->header->embedded_pool) { - preserve = mgr->header->embedded_pool; + if (mgr->embedded_pool) { + preserve = mgr->embedded_pool; } else { if (*pool_head == NULL) { ast_log(LOG_WARNING, "trying to reset empty pool\n"); @@ -202,27 +196,19 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_ mgr->owner_line = lineno; #endif - if (!(mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func))) { - return -1; - } - - if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) { - ast_free(mgr->header); - mgr->header = NULL; + if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) { return -1; } while ((struct ast_string_field_mgr *) p != mgr) { - AST_VECTOR_APPEND(&mgr->header->string_fields, p); + AST_VECTOR_APPEND(&mgr->string_fields, p); *p++ = __ast_string_field_empty; } *pool_head = NULL; - mgr->header->embedded_pool = NULL; + mgr->embedded_pool = NULL; if (add_string_pool(mgr, pool_head, needed, file, lineno, func)) { - AST_VECTOR_FREE(&mgr->header->string_fields); - ast_free(mgr->header); - mgr->header = NULL; + AST_VECTOR_FREE(&mgr->string_fields); return -1; } @@ -428,33 +414,22 @@ void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_siz mgr = allocation + field_mgr_offset; - /* - * The header is calloced in __ast_string_field_init so it also gets calloced here - * so __ast_string_fields_free_memory can always just free mgr->header. - */ - mgr->header = calloc_wrapper(1, sizeof(*mgr->header), file, lineno, func); - if (!mgr->header) { - ast_free(allocation); - return NULL; - } - pool = allocation + struct_size; pool_head = allocation + field_mgr_pool_offset; p = (const char **) pool_head + 1; initial_vector_size = ((size_t) (((char *)mgr) - ((char *)p))) / sizeof(*p); - if (AST_VECTOR_INIT(&mgr->header->string_fields, initial_vector_size)) { - ast_free(mgr->header); + if (AST_VECTOR_INIT(&mgr->string_fields, initial_vector_size)) { ast_free(allocation); return NULL; } while ((struct ast_string_field_mgr *) p != mgr) { - AST_VECTOR_APPEND(&mgr->header->string_fields, p); + AST_VECTOR_APPEND(&mgr->string_fields, p); *p++ = __ast_string_field_empty; } - mgr->header->embedded_pool = pool; + mgr->embedded_pool = pool; *pool_head = pool; pool->size = size_to_alloc - struct_size - sizeof(*pool); #if defined(__AST_DEBUG_MALLOC) @@ -487,8 +462,8 @@ int __ast_string_fields_copy(struct ast_string_field_pool *copy_pool, struct ast_string_field_mgr *copy_mgr, struct ast_string_field_mgr *orig_mgr) { int i; - struct ast_string_field_vector *dest = &(copy_mgr->header->string_fields); - struct ast_string_field_vector *src = &(orig_mgr->header->string_fields); + struct ast_string_field_vector *dest = &(copy_mgr->string_fields); + struct ast_string_field_vector *src = &(orig_mgr->string_fields); ast_assert(AST_VECTOR_SIZE(dest) == AST_VECTOR_SIZE(src)); diff --git a/tests/test_stringfields.c b/tests/test_stringfields.c index e57f8d7e861..706b07d8e5d 100644 --- a/tests/test_stringfields.c +++ b/tests/test_stringfields.c @@ -369,7 +369,7 @@ AST_TEST_DEFINE(string_field_aggregate_test) ast_string_field_ptr_set_by_fields(inst2->__field_mgr_pool, inst2->__field_mgr, &inst2->string1, "foo"); inst2->foo = 2; - if (inst3->__field_mgr.header->embedded_pool->prev) { + if (inst3->__field_mgr.embedded_pool->prev) { ast_test_status_update(test, "Structure 3 embedded pool should not have a previous pool!\n"); res = AST_TEST_FAIL; goto error; @@ -377,13 +377,13 @@ AST_TEST_DEFINE(string_field_aggregate_test) ast_string_field_set(inst3, string1, "foo"); - if (inst3->__field_mgr.header->embedded_pool != inst3->__field_mgr_pool) { + if (inst3->__field_mgr.embedded_pool != inst3->__field_mgr_pool) { ast_test_status_update(test, "Structure 3 embedded pool should have been the current pool!\n"); res = AST_TEST_FAIL; goto error; } - if (inst3->__field_mgr.header->embedded_pool->prev) { + if (inst3->__field_mgr.embedded_pool->prev) { ast_test_status_update(test, "Structure 3 embedded pool should not have a previous pool!\n"); res = AST_TEST_FAIL; goto error; @@ -395,13 +395,13 @@ AST_TEST_DEFINE(string_field_aggregate_test) ast_string_field_set(inst3, string2, "baz 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); inst3->foo = 3; - if (inst3->__field_mgr_pool == inst3->__field_mgr.header->embedded_pool) { + if (inst3->__field_mgr_pool == inst3->__field_mgr.embedded_pool) { ast_test_status_update(test, "Structure 3 embedded pool should not have been the current pool!\n"); res = AST_TEST_FAIL; goto error; } - if (inst3->__field_mgr.header->embedded_pool != inst3->__field_mgr_pool->prev) { + if (inst3->__field_mgr.embedded_pool != inst3->__field_mgr_pool->prev) { ast_test_status_update(test, "Structure 3 embedded pool should be the current pool's previous!\n"); res = AST_TEST_FAIL; goto error; @@ -484,7 +484,7 @@ AST_TEST_DEFINE(string_field_aggregate_test) ast_test_status_update(test, "Structures 1/2 are the same (empty) as expected.\n"); } - if (inst4->__field_mgr.header->embedded_pool != inst4->__field_mgr_pool) { + if (inst4->__field_mgr.embedded_pool != inst4->__field_mgr_pool) { ast_test_status_update(test, "Structure 4 embedded pool should have been the current pool!\n"); res = AST_TEST_FAIL; goto error; @@ -492,7 +492,7 @@ AST_TEST_DEFINE(string_field_aggregate_test) ast_test_status_update(test, "Structure 4 embedded pool is the current pool as expected.\n"); } - if (inst4->__field_mgr.header->embedded_pool->prev) { + if (inst4->__field_mgr.embedded_pool->prev) { ast_test_status_update(test, "Structure 4 embedded pool should not have a previous pool!\n"); res = AST_TEST_FAIL; goto error; From ff3af764de28821eb1ae5573537111c3b99b7f3c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 12 Apr 2016 13:10:47 -0500 Subject: [PATCH 0347/1578] bridge_softmix.c: Fix crash if could not allocate the dsp. Fix off nominal crash where we could not setup the channel to process frames for the softmix bridge technology because of allocation failure. Change-Id: Ic307a8386e46bf551e48fcd1eb97276714d56372 --- bridges/bridge_softmix.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 850e3982cef..bad3e43c442 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -357,6 +357,7 @@ static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_ch { struct softmix_channel *sc = bridge_channel->tech_pvt; struct ast_format *slin_format; + int setup_fail; slin_format = ast_format_cache_get_slin_by_rate(rate); @@ -386,17 +387,24 @@ static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_ch sc->read_slin_format = slin_format; /* Setup smoother */ - ast_slinfactory_init_with_format(&sc->factory, slin_format); + setup_fail = ast_slinfactory_init_with_format(&sc->factory, slin_format); /* set new read and write formats on channel. */ ast_channel_lock(bridge_channel->chan); - ast_set_read_format_path(bridge_channel->chan, + setup_fail |= ast_set_read_format_path(bridge_channel->chan, ast_channel_rawreadformat(bridge_channel->chan), slin_format); ast_channel_unlock(bridge_channel->chan); - ast_set_write_format(bridge_channel->chan, slin_format); + setup_fail |= ast_set_write_format(bridge_channel->chan, slin_format); /* set up new DSP. This is on the read side only right before the read frame enters the smoother. */ sc->dsp = ast_dsp_new_with_rate(rate); + if (setup_fail || !sc->dsp) { + /* Bad news. Could not setup the channel for softmix. */ + ast_mutex_unlock(&sc->lock); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0); + return; + } + /* we want to aggressively detect silence to avoid feedback */ if (bridge_channel->tech_args.talking_threshold) { ast_dsp_set_threshold(sc->dsp, bridge_channel->tech_args.talking_threshold); @@ -616,7 +624,10 @@ static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bri ast_channel_unlock(bridge_channel->chan); } - ast_dsp_silence_with_energy(sc->dsp, frame, &totalsilence, &cur_energy); + /* The channel will be leaving soon if there is no dsp. */ + if (sc->dsp) { + ast_dsp_silence_with_energy(sc->dsp, frame, &totalsilence, &cur_energy); + } if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC) { int cur_slot = sc->video_talker.energy_history_cur_slot; From 7b8b6e2e4faa21a3941bc6c71ad1bd94c40e53d1 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 14 Apr 2016 07:23:54 -0500 Subject: [PATCH 0348/1578] AST-2016-004: Fix crash on REGISTER with long URI. Due to some ignored return values, Asterisk could crash if processing an incoming REGISTER whose contact URI was above a certain length. ASTERISK-25707 #close Reported by George Joseph Patches: 0001-res_pjsip-Validate-that-URIs-don-t-exceed-pjproject-.patch AST-2016-004 Change-Id: I3ea7cee16f29c8088794de3085ca7523c1c4833d --- res/res_pjsip/include/res_pjsip_private.h | 7 ++++ res/res_pjsip/location.c | 51 +++++++++++++++++++++++ res/res_pjsip_outbound_registration.c | 8 ++++ res/res_pjsip_registrar.c | 29 ++++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 2cc9feacde4..24b8edfbccd 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -306,4 +306,11 @@ int internal_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter * \brief Finds or creates contact_status for a contact */ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact); + +/*! + * \internal + * \brief Validate that the uri meets pjproject length restrictions + */ +int ast_sip_validate_uri_length(const char *uri); + #endif /* RES_PJSIP_PRIVATE_H_ */ diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index bc14f184b5f..0a82f3a0874 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -29,6 +29,11 @@ #include "asterisk/statsd.h" #include "asterisk/named_locks.h" +#include "asterisk/res_pjproject.h" + +static int pj_max_hostname = PJ_MAX_HOSTNAME; +static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE; + /*! \brief Destructor for AOR */ static void aor_destroy(void *obj) { @@ -405,6 +410,43 @@ static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, in return cmp; } +int ast_sip_validate_uri_length(const char *contact_uri) +{ + pjsip_uri *uri; + pjsip_sip_uri *sip_uri; + pj_pool_t *pool; + int max_length = pj_max_hostname - 1; + + if (strlen(contact_uri) > pjsip_max_url_size - 1) { + return -1; + } + + if (!(pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "uri validation", 512, 512))) { + ast_log(LOG_ERROR, "Unable to allocate pool for uri validation\n"); + return -1; + } + + if (!(uri = pjsip_parse_uri(pool, (char *)contact_uri, strlen(contact_uri), 0)) || + (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) { + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + return -1; + } + + sip_uri = pjsip_uri_get_uri(uri); + if (sip_uri->port == 0) { + max_length -= strlen("_sips.tcp."); + } + + if (sip_uri->host.slen > max_length) { + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + return -1; + } + + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + + return 0; +} + /*! \brief Custom handler for permanent URIs */ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -428,6 +470,11 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab continue; } + if (ast_sip_validate_uri_length(contact_uri)) { + ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit: %s\n", contact_uri); + return -1; + } + if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL); @@ -1015,6 +1062,10 @@ int ast_sip_initialize_sorcery_location(void) struct ast_sorcery *sorcery = ast_sip_get_sorcery(); int i; + ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname); + /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */ + ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size); + ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar"); ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor"); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index dd69ff20e83..f85996ed5ed 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1290,10 +1290,18 @@ static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, vo ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'\n", ast_sorcery_object_get_id(applied)); return -1; + } else if (ast_sip_validate_uri_length(applied->server_uri)) { + ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjpropject limit '%s'\n", + ast_sorcery_object_get_id(applied)); + return -1; } else if (ast_strlen_zero(applied->client_uri)) { ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n", ast_sorcery_object_get_id(applied)); return -1; + } else if (ast_sip_validate_uri_length(applied->client_uri)) { + ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjpropject limit '%s'\n", + ast_sorcery_object_get_id(applied)); + return -1; } else if (applied->line && ast_strlen_zero(applied->endpoint)) { ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n", ast_sorcery_object_get_id(applied)); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 97cf34ae6c0..a94babd88f7 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -18,6 +18,7 @@ /*** MODULEINFO pjproject + res_pjproject res_pjsip core ***/ @@ -33,6 +34,7 @@ #include "asterisk/taskprocessor.h" #include "asterisk/manager.h" #include "asterisk/named_locks.h" +#include "asterisk/res_pjproject.h" #include "res_pjsip/include/res_pjsip_private.h" /*** DOCUMENTATION @@ -52,6 +54,9 @@ ***/ +static int pj_max_hostname = PJ_MAX_HOSTNAME; +static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE; + /*! \brief Internal function which returns the expiration time for a contact */ static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata) { @@ -86,7 +91,7 @@ struct registrar_contact_details { /*! \brief Pool used for parsing URI */ pj_pool_t *pool; /*! \brief URI being looked for */ - pjsip_uri *uri; + pjsip_sip_uri *uri; }; /*! \brief Callback function for finding a contact */ @@ -114,6 +119,7 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) { int expiration = registrar_get_expiration(aor, contact, rdata); RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup); + char contact_uri[pjsip_max_url_size]; if (contact->star) { /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */ @@ -135,6 +141,19 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co details.uri = pjsip_uri_get_uri(contact->uri); + /* pjsip_uri_print returns -1 if there's not enough room in the buffer */ + if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) { + /* If the total length of the uri is greater than pjproject can handle, go no further */ + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); + return -1; + } + + if (details.uri->host.slen >= pj_max_hostname) { + /* If the length of the hostname is greater than pjproject can handle, go no further */ + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); + return -1; + } + /* Determine if this is an add, update, or delete for policy enforcement purposes */ if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) { if (expiration) { @@ -472,7 +491,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co /* Iterate each provided Contact header and add, update, or delete */ while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { int expiration; - char contact_uri[PJSIP_MAX_URL_SIZE]; + char contact_uri[pjsip_max_url_size]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); if (contact_hdr->star) { @@ -827,6 +846,12 @@ static int load_module(void) { const pj_str_t STR_REGISTER = { "REGISTER", 8 }; + CHECK_PJPROJECT_MODULE_LOADED(); + + ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname); + /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */ + ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size); + CHECK_PJSIP_MODULE_LOADED(); if (!(serializers = ao2_container_alloc( From d9fba460164301609aa19a491fbda3089beb7862 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 8 Mar 2016 10:52:19 -0600 Subject: [PATCH 0349/1578] Rename res_pjsip_keepalive res_pjsip_transport_management ASTERISK-25796 Reported by George Joseph AST-2016-005 Change-Id: Id322a05f927392293570599730050bc677d99433 --- res/{res_pjsip_keepalive.c => res_pjsip_transport_management.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename res/{res_pjsip_keepalive.c => res_pjsip_transport_management.c} (100%) diff --git a/res/res_pjsip_keepalive.c b/res/res_pjsip_transport_management.c similarity index 100% rename from res/res_pjsip_keepalive.c rename to res/res_pjsip_transport_management.c From 216f22fd0fc195315231419e382de3c8dc300c85 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 8 Mar 2016 12:12:16 -0600 Subject: [PATCH 0350/1578] res_pjsip_transport_management: Kill idle TCP connections. "Idle" here means that someone connects to us and does not send a SIP request. PJProject will not automatically time out such connections, so it's up to Asterisk to do it instead. When we receive an incoming TCP connection, we will start a timer (equivalent to transaction timer D) waiting to receive an incoming request. If we do not receive a request in that timeframe, then we will shut down the TCP connection. ASTERISK-25796 #close Reported by George Joseph AST-2016-005 Change-Id: I7b0d303e5d140d0ccaf2f7af562071e3d1130ac6 --- res/res_pjsip_transport_management.c | 169 ++++++++++++++++++++------- 1 file changed, 124 insertions(+), 45 deletions(-) diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c index d850973f8c8..862ae721685 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip_transport_management.c @@ -32,7 +32,9 @@ #include "asterisk/astobj2.h" /*! \brief Number of buckets for keepalive transports */ -#define KEEPALIVE_TRANSPORTS_BUCKETS 53 +#define TRANSPORTS_BUCKETS 53 + +#define IDLE_TIMEOUT (pjsip_cfg()->tsx.td) /*! \brief The keep alive packet to send */ static const pj_str_t keepalive_packet = { "\r\n\r\n", 4 }; @@ -40,6 +42,9 @@ static const pj_str_t keepalive_packet = { "\r\n\r\n", 4 }; /*! \brief Global container of active transports */ static struct ao2_container *transports; +/*! \brief Scheduler context for timing out connections with no data received */ +static struct ast_sched_context *sched; + /*! \brief Thread keeping things alive */ static pthread_t keepalive_thread = AST_PTHREADT_NULL; @@ -49,24 +54,26 @@ static unsigned int keepalive_interval; /*! \brief Existing transport manager callback that we need to invoke */ static pjsip_tp_state_callback tpmgr_state_callback; -/*! \brief Structure for transport to be kept alive */ -struct keepalive_transport { +/*! \brief Structure for transport to be monitored */ +struct monitored_transport { /*! \brief The underlying PJSIP transport */ pjsip_transport *transport; + /*! \brief Non-zero if a PJSIP request was received */ + int sip_received; }; /*! \brief Callback function to send keepalive */ static int keepalive_transport_cb(void *obj, void *arg, int flags) { - struct keepalive_transport *keepalive = obj; + struct monitored_transport *monitored = obj; pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_TRANSPORT, - .u.transport = keepalive->transport, + .u.transport = monitored->transport, }; pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), - keepalive->transport->key.type, &selector, NULL, keepalive_packet.ptr, keepalive_packet.slen, - &keepalive->transport->key.rem_addr, pj_sockaddr_get_len(&keepalive->transport->key.rem_addr), + monitored->transport->key.type, &selector, NULL, keepalive_packet.ptr, keepalive_packet.slen, + &monitored->transport->key.rem_addr, pj_sockaddr_get_len(&monitored->transport->key.rem_addr), NULL, NULL); return 0; @@ -94,32 +101,60 @@ static void *keepalive_transport_thread(void *data) return NULL; } +static int idle_sched_cb(const void *data) +{ + struct monitored_transport *keepalive = (struct monitored_transport *) data; + int sip_received = ast_atomic_fetchadd_int(&keepalive->sip_received, 0); + + if (!sip_received) { + ast_log(LOG_NOTICE, "Shutting down transport '%s' since no request was received in %d seconds\n", + keepalive->transport->info, IDLE_TIMEOUT); + pjsip_transport_shutdown(keepalive->transport); + } + + ao2_ref(keepalive, -1); + return 0; +} + /*! \brief Destructor for keepalive transport */ -static void keepalive_transport_destroy(void *obj) +static void monitored_transport_destroy(void *obj) { - struct keepalive_transport *keepalive = obj; + struct monitored_transport *keepalive = obj; pjsip_transport_dec_ref(keepalive->transport); } /*! \brief Callback invoked when transport changes occur */ -static void keepalive_transport_state_callback(pjsip_transport *transport, pjsip_transport_state state, +static void monitored_transport_state_callback(pjsip_transport *transport, pjsip_transport_state state, const pjsip_transport_state_info *info) { - /* We only care about connection-oriented transports */ - if (transport->flag & PJSIP_TRANSPORT_RELIABLE) { - struct keepalive_transport *keepalive; + /* We only care about reliable transports */ + if (PJSIP_TRANSPORT_IS_RELIABLE(transport) && + (transport->dir == PJSIP_TP_DIR_INCOMING || keepalive_interval)) { + struct monitored_transport *monitored; switch (state) { case PJSIP_TP_STATE_CONNECTED: - keepalive = ao2_alloc(sizeof(*keepalive), keepalive_transport_destroy); - if (keepalive) { - keepalive->transport = transport; - pjsip_transport_add_ref(keepalive->transport); - ao2_link(transports, keepalive); - ao2_ref(keepalive, -1); + monitored = ao2_alloc(sizeof(*monitored), monitored_transport_destroy); + if (!monitored) { + break; + } + monitored->transport = transport; + pjsip_transport_add_ref(monitored->transport); + ao2_link(transports, monitored); + if (transport->dir == PJSIP_TP_DIR_INCOMING) { + /* Let the scheduler inherit the reference from allocation */ + if (ast_sched_add_variable(sched, IDLE_TIMEOUT, idle_sched_cb, monitored, 1) < 0) { + ao2_unlink(transports, monitored); + ao2_ref(monitored, -1); + pjsip_transport_shutdown(transport); + } + } else { + /* No scheduled task, so get rid of the allocation reference */ + ao2_ref(monitored, -1); } break; + case PJSIP_TP_STATE_SHUTDOWN: case PJSIP_TP_STATE_DISCONNECTED: ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NODATA | OBJ_UNLINK); break; @@ -134,10 +169,10 @@ static void keepalive_transport_state_callback(pjsip_transport *transport, pjsip } } -/*! \brief Hashing function for keepalive transport */ -static int keepalive_transport_hash_fn(const void *obj, int flags) +/*! \brief Hashing function for monitored transport */ +static int monitored_transport_hash_fn(const void *obj, int flags) { - const struct keepalive_transport *object; + const struct monitored_transport *object; const char *key; switch (flags & OBJ_SEARCH_MASK) { @@ -156,11 +191,11 @@ static int keepalive_transport_hash_fn(const void *obj, int flags) return ast_str_hash(key); } -/*! \brief Comparison function for keepalive transport */ -static int keepalive_transport_cmp_fn(void *obj, void *arg, int flags) +/*! \brief Comparison function for monitored transport */ +static int monitored_transport_cmp_fn(void *obj, void *arg, int flags) { - const struct keepalive_transport *object_left = obj; - const struct keepalive_transport *object_right = arg; + const struct monitored_transport *object_left = obj; + const struct monitored_transport *object_right = arg; const char *right_key = arg; int cmp; @@ -193,7 +228,6 @@ static int keepalive_transport_cmp_fn(void *obj, void *arg, int flags) static void keepalive_global_loaded(const char *object_type) { unsigned int new_interval = ast_sip_get_keep_alive_interval(); - pjsip_tpmgr *tpmgr; if (new_interval) { keepalive_interval = new_interval; @@ -209,28 +243,11 @@ static void keepalive_global_loaded(const char *object_type) return; } - transports = ao2_container_alloc(KEEPALIVE_TRANSPORTS_BUCKETS, keepalive_transport_hash_fn, - keepalive_transport_cmp_fn); - if (!transports) { - ast_log(LOG_ERROR, "Could not create container for transports to perform keepalive on.\n"); - return; - } - - tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); - if (!tpmgr) { - ast_log(LOG_ERROR, "No transport manager to attach keepalive functionality to.\n"); - ao2_ref(transports, -1); - return; - } - if (ast_pthread_create(&keepalive_thread, NULL, keepalive_transport_thread, NULL)) { ast_log(LOG_ERROR, "Could not create thread for sending keepalive messages.\n"); ao2_ref(transports, -1); return; } - - tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr); - pjsip_tpmgr_set_state_cb(tpmgr, &keepalive_transport_state_callback); } /*! \brief Observer which is used to update our interval when the global setting changes */ @@ -238,10 +255,72 @@ static struct ast_sorcery_observer keepalive_global_observer = { .loaded = keepalive_global_loaded, }; +/*! + * \brief + * On incoming TCP connections, when we receive a SIP request, we mark that we have + * received a valid SIP request. This way, we will not shut the transport down for + * idleness + */ +static pj_bool_t idle_monitor_on_rx_request(pjsip_rx_data *rdata) +{ + struct monitored_transport *idle_trans; + + idle_trans = ao2_find(transports, rdata->tp_info.transport->obj_name, OBJ_SEARCH_KEY); + if (!idle_trans) { + return PJ_FALSE; + } + + ast_atomic_fetchadd_int(&idle_trans->sip_received, +1); + ao2_ref(idle_trans, -1); + + return PJ_FALSE; +} + +static pjsip_module idle_monitor_module = { + .name = {"idle monitor module", 19}, + .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER + 3, + .on_rx_request = idle_monitor_on_rx_request, +}; + static int load_module(void) { + pjsip_tpmgr *tpmgr; + CHECK_PJSIP_MODULE_LOADED(); + transports = ao2_container_alloc(TRANSPORTS_BUCKETS, monitored_transport_hash_fn, + monitored_transport_cmp_fn); + if (!transports) { + ast_log(LOG_ERROR, "Could not create container for transports to perform keepalive on.\n"); + return AST_MODULE_LOAD_DECLINE; + } + + tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + if (!tpmgr) { + ast_log(LOG_ERROR, "No transport manager to attach keepalive functionality to.\n"); + ao2_ref(transports, -1); + return AST_MODULE_LOAD_DECLINE; + } + + sched = ast_sched_context_create(); + if (!sched) { + ast_log(LOG_ERROR, "Failed to create keepalive scheduler context.\n"); + ao2_ref(transports, -1); + return AST_MODULE_LOAD_DECLINE; + } + + if (ast_sched_start_thread(sched)) { + ast_log(LOG_ERROR, "Failed to start keepalive scheduler thread\n"); + ast_sched_context_destroy(sched); + ao2_ref(transports, -1); + return AST_MODULE_LOAD_DECLINE; + } + + ast_sip_register_service(&idle_monitor_module); + + tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr); + pjsip_tpmgr_set_state_cb(tpmgr, &monitored_transport_state_callback); + ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &keepalive_global_observer); ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); ast_module_shutdown_ref(ast_module_info->self); @@ -260,7 +339,7 @@ static int reload_module(void) return 0; } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Stateful Connection Keepalive Support", +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Reliable Transport Management", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, From e83499df5606e86537313286f8629d913f17267b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 17 Mar 2016 11:28:26 -0600 Subject: [PATCH 0351/1578] res_pjsip: Add serialized scheduler (res_pjsip/pjsip_scheduler.c) There are several places that do scheduled tasks or periodic housecleaning, each with its own implementation: * res_pjsip_keepalive has a thread that sends keepalives. * pjsip_distributor has a thread that cleans up expired unidentified requests. * res_pjsip_registrar_expire has a thread that cleans up expired contacts. * res_pjsip_pubsub uses ast_sched directly and then calls ast_sip_push_task. * res_pjsip_sdp_rtp also uses ast_sched to send keepalives. There are also places where we should be doing scheduled work but aren't. A good example are the places we have sorcery observers to start registration or qualify. These don't work when changes are made to a backend database without a pjsip reload. We need to check periodically. As a first step to solving these issues, a new ast_sip_sched facility has been created. ast_sip_sched wraps ast_sched but only uses ast_sched as a scheduled queue. When a task is ready to run, ast_sip_task_pusk is called for it. This ensures that the task is executed in a PJLIB registered thread and doesn't hold up the ast_sched thread so it can immediately continue processing the queue. The serializer used by ast_sip_sched is one of your choosing or a random one from the res_pjsip pool if you don't choose one. Another feature is the ability to automatically clean up the task_data when the task expires (if ever). If it's an ao2 object, it will be dereferenced, if it's a malloc'd object it will be freed. This is selectable when the task is scheduled. Even if you choose to not auto dereference an ao2 task data object, the scheduler itself maintains a reference to it while the task is under it's control. This prevents the data from disappearing out from under the task. There are two scheduling models. AST_SIP_SCHED_TASK_PERIODIC specifies that the invocations of the task occur at the specific interval. That is, every "interval" milliseconds, regardless of how long the task takes. If the task takes longer than the interval, it will be scheduled at the next available multiple of interval. For exmaple: If the task has an interval of 60 secs and the task takes 70 secs (it better not), the next invocation will happen at 120 seconds. AST_SIP_SCHED_TASK_DELAY specifies that the next invocation of the task should start "interval" milliseconds after the current invocation has finished. Also, the same ast_sched facility for fixed or variable intervals exists. The task's return code in conjunction with the AST_SIP_SCHED_TASK_FIXED or AST_SIP_SCHED_TASK_VARIABLE flags controls the next invocation start time. One res_pjsip.h housekeeping change was made. The pjsip header files were added to the top. There have been a few cases lately where I've needed res_pjsip.h just for ast_sip calls and had compiles fail spectacularly because I didn't add the pjsip header files to my source even though I never referenced any pjsip calls. Finally, a few new convenience APIs were added to astobj2 to make things a little easier in the scheduler. ao2_ref_and_lock() calls ao2_ref() and ao2_lock() in one go. ao2_unlock_and_unref() does the reverse. A few macros were also copied from res_phoneprov because I got tired of having to duplicate the same hash, sort and compare functions over and over again. The AO2_STRING_FIELD_(HASH|SORT|CMP)_FN macros will insert functions suitable for aor_container_alloc into your source. This facility can be used immediately for the situations where we already have a thread that wakes up periodically or do some scheduled work. For the registration and qualify issues, additional sorcery and schema changes would need to be made so that we can easily detect changed objects on a periodic basis without having to pull the entire database back to check. I'm thinking of a last-updated timestamp on the rows but more on this later. Change-Id: I7af6ad2b2d896ea68e478aa1ae201d6dd016ba1c --- include/asterisk/astobj2.h | 134 ++++++ include/asterisk/res_pjsip.h | 235 +++++++++- res/res_pjsip.c | 17 +- res/res_pjsip/include/res_pjsip_private.h | 19 + res/res_pjsip/pjsip_scheduler.c | 495 ++++++++++++++++++++++ tests/test_res_pjsip_scheduler.c | 400 +++++++++++++++++ 6 files changed, 1291 insertions(+), 9 deletions(-) create mode 100644 res/res_pjsip/pjsip_scheduler.c create mode 100644 tests/test_res_pjsip_scheduler.c diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index c28dd238732..0472c1b3753 100644 --- a/include/asterisk/astobj2.h +++ b/include/asterisk/astobj2.h @@ -20,6 +20,7 @@ #include "asterisk/compat.h" #include "asterisk/lock.h" #include "asterisk/linkedlists.h" +#include "asterisk/inline_api.h" /*! \file * \ref AstObj2 @@ -725,6 +726,46 @@ int __ao2_trylock(void *a, enum ao2_lock_req lock_how, const char *file, const c void *ao2_object_get_lockaddr(void *obj); +/*! + * \brief Increment reference count on an object and lock it + * \since 13.9.0 + * + * \param[in] obj A pointer to the ao2 object + * \retval 0 The object is not an ao2 object or wasn't locked successfully + * \retval 1 The object's reference count was incremented and was locked + */ +AST_INLINE_API( +int ao2_ref_and_lock(void *obj), +{ + ao2_ref(obj, +1); + if (ao2_lock(obj)) { + ao2_ref(obj, -1); + return 0; + } + return 1; +} +) + +/*! + * \brief Unlock an object and decrement its reference count + * \since 13.9.0 + * + * \param[in] obj A pointer to the ao2 object + * \retval 0 The object is not an ao2 object or wasn't unlocked successfully + * \retval 1 The object was unlocked and it's reference count was decremented + */ +AST_INLINE_API( +int ao2_unlock_and_unref(void *obj), +{ + if (ao2_unlock(obj)) { + return 0; + } + ao2_ref(obj, -1); + + return 1; +} +) + /*! Global ao2 object holder structure. */ struct ao2_global_obj { /*! Access lock to the held ao2 object. */ @@ -1903,4 +1944,97 @@ void ao2_iterator_cleanup(struct ao2_iterator *iter); */ int ao2_iterator_count(struct ao2_iterator *iter); +/*! + * \brief Creates a hash function for a structure string field. + * \param stype The structure type + * \param field The string field in the structure to hash + * + * AO2_STRING_FIELD_HASH_CB(mystruct, myfield) will produce a function + * named mystruct_hash_fn which hashes mystruct->myfield. + */ +#define AO2_STRING_FIELD_HASH_FN(stype, field) \ +static int stype ## _hash_fn(const void *obj, const int flags) \ +{ \ + const struct stype *object = obj; \ + const char *key; \ + switch (flags & OBJ_SEARCH_MASK) { \ + case OBJ_SEARCH_KEY: \ + key = obj; \ + break; \ + case OBJ_SEARCH_OBJECT: \ + key = object->field; \ + break; \ + default: \ + ast_assert(0); \ + return 0; \ + } \ + return ast_str_hash(key); \ +} + +/*! + * \brief Creates a compare function for a structure string field. + * \param stype The structure type + * \param field The string field in the structure to compare + * + * AO2_STRING_FIELD_CMP_FN(mystruct, myfield) will produce a function + * named mystruct_cmp_fn which compares mystruct->myfield. + */ +#define AO2_STRING_FIELD_CMP_FN(stype, field) \ +static int stype ## _cmp_fn(void *obj, void *arg, int flags) \ +{ \ + const struct stype *object_left = obj, *object_right = arg; \ + const char *right_key = arg; \ + int cmp; \ + switch (flags & OBJ_SEARCH_MASK) { \ + case OBJ_SEARCH_OBJECT: \ + right_key = object_right->field; \ + case OBJ_SEARCH_KEY: \ + cmp = strcmp(object_left->field, right_key); \ + break; \ + case OBJ_SEARCH_PARTIAL_KEY: \ + cmp = strncmp(object_left->field, right_key, strlen(right_key)); \ + break; \ + default: \ + cmp = 0; \ + break; \ + } \ + if (cmp) { \ + return 0; \ + } \ + return CMP_MATCH; \ +} + +/*! + * \brief Creates a sort function for a structure string field. + * \param stype The structure type + * \param field The string field in the structure to compare + * + * AO2_STRING_FIELD_SORT_FN(mystruct, myfield) will produce a function + * named mystruct_sort_fn which compares mystruct->myfield. + */ +#define AO2_STRING_FIELD_SORT_FN(stype, field) \ +static int stype ## _sort_fn(const void *obj, const void *arg, int flags) \ +{ \ + const struct stype *object_left = obj; \ + const struct stype *object_right = arg; \ + const char *right_key = arg; \ + int cmp; \ +\ + switch (flags & OBJ_SEARCH_MASK) { \ + case OBJ_SEARCH_OBJECT: \ + right_key = object_right->field; \ + /* Fall through */ \ + case OBJ_SEARCH_KEY: \ + cmp = strcmp(object_left->field, right_key); \ + break; \ + case OBJ_SEARCH_PARTIAL_KEY: \ + cmp = strncmp(object_left->field, right_key, strlen(right_key)); \ + break; \ + default: \ + cmp = 0; \ + break; \ + } \ + return cmp; \ +} + #endif /* _ASTERISK_ASTOBJ2_H */ diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 1bfae66b359..9015cb86f9f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -19,6 +19,13 @@ #ifndef _RES_PJSIP_H #define _RES_PJSIP_H +#include +/* Needed for SUBSCRIBE, NOTIFY, and PUBLISH method definitions */ +#include +#include +#include +#include + #include "asterisk/stringfields.h" /* Needed for struct ast_sockaddr */ #include "asterisk/netsock2.h" @@ -1166,8 +1173,9 @@ struct ast_sip_auth *ast_sip_get_artificial_auth(void); */ struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void); -/*! - * \page Threading model for SIP +/*! \defgroup pjsip_threading PJSIP Threading Model + * @{ + * \page PJSIP PJSIP Threading Model * * There are three major types of threads that SIP will have to deal with: * \li Asterisk threads @@ -1216,6 +1224,19 @@ struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void); * previous tasks pushed with the same serializer have completed. For more information * on serializers and the benefits they provide, see \ref ast_threadpool_serializer * + * \par Scheduler + * + * Some situations require that a task run periodically or at a future time. Normally + * the ast_sched functionality would be used but ast_sched only uses 1 thread for all + * tasks and that thread isn't registered with PJLIB and therefore can't do any PJSIP + * related work. + * + * ast_sip_sched uses ast_sched only as a scheduled queue. When a task is ready to run, + * it's pushed to a Serializer to be invoked asynchronously by a Servant. This ensures + * that the task is executed in a PJLIB registered thread and allows the ast_sched thread + * to immediately continue processing the queue. The Serializer used by ast_sip_sched + * is one of your choosing or a random one from the res_pjsip pool if you don't choose one. + * * \note * * Do not make assumptions about individual threads based on a corresponding serializer. @@ -1224,6 +1245,8 @@ struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void); * tasks, even though they are all guaranteed to be executed in sequence. */ +typedef int (*ast_sip_task)(void *user_data); + /*! * \brief Create a new serializer for SIP tasks * \since 13.8.0 @@ -1333,6 +1356,214 @@ int ast_sip_push_task_synchronous(struct ast_taskprocessor *serializer, int (*si */ int ast_sip_thread_is_servant(void); +/*! + * \brief Task flags for the res_pjsip scheduler + * + * The default is AST_SIP_SCHED_TASK_FIXED + * | AST_SIP_SCHED_TASK_DATA_NOT_AO2 + * | AST_SIP_SCHED_TASK_DATA_NO_CLEANUP + * | AST_SIP_SCHED_TASK_PERIODIC + */ +enum ast_sip_scheduler_task_flags { + /*! + * The defaults + */ + AST_SIP_SCHED_TASK_DEFAULTS = (0 << 0), + + /*! + * Run at a fixed interval. + * Stop scheduling if the callback returns 0. + * Any other value is ignored. + */ + AST_SIP_SCHED_TASK_FIXED = (0 << 0), + /*! + * Run at a variable interval. + * Stop scheduling if the callback returns 0. + * Any other return value is used as the new interval. + */ + AST_SIP_SCHED_TASK_VARIABLE = (1 << 0), + + /*! + * The task data is not an AO2 object. + */ + AST_SIP_SCHED_TASK_DATA_NOT_AO2 = (0 << 1), + /*! + * The task data is an AO2 object. + * A reference count will be held by the scheduler until + * after the task has run for the final time (if ever). + */ + AST_SIP_SCHED_TASK_DATA_AO2 = (1 << 1), + + /*! + * Don't take any cleanup action on the data + */ + AST_SIP_SCHED_TASK_DATA_NO_CLEANUP = (0 << 3), + /*! + * If AST_SIP_SCHED_TASK_DATA_AO2 is set, decrement the reference count + * otherwise call ast_free on it. + */ + AST_SIP_SCHED_TASK_DATA_FREE = ( 1 << 3 ), + + /*! \brief AST_SIP_SCHED_TASK_PERIODIC + * The task is scheduled at multiples of interval + * \see Interval + */ + AST_SIP_SCHED_TASK_PERIODIC = (0 << 4), + /*! \brief AST_SIP_SCHED_TASK_DELAY + * The next invocation of the task is at last finish + interval + * \see Interval + */ + AST_SIP_SCHED_TASK_DELAY = (1 << 4), +}; + +/*! + * \brief Scheduler task data structure + */ +struct ast_sip_sched_task; + +/*! + * \brief Schedule a task to run in the res_pjsip thread pool + * \since 13.9.0 + * + * \param serializer The serializer to use. If NULL, don't use a serializer (see note below) + * \param interval The invocation interval in milliseconds (see note below) + * \param sip_task The task to invoke + * \param name An optional name to associate with the task + * \param task_data Optional data to pass to the task + * \param flags One of enum ast_sip_scheduler_task_type + * + * \returns Pointer to \ref ast_sip_sched_task ao2 object which must be dereferenced when done. + * + * \paragraph Serialization + * + * Specifying a serializer guarantees serialized execution but NOT specifying a serializer + * may still result in tasks being effectively serialized if the thread pool is busy. + * The point of the serializer BTW is not to prevent parallel executions of the SAME task. + * That happens automatically (see below). It's to prevent the task from running at the same + * time as other work using the same serializer, whether or not it's being run by the scheduler. + * + * \paragraph Interval + * + * The interval is used to calculate the next time the task should run. There are two models. + * + * \ref AST_SIP_SCHED_TASK_PERIODIC specifies that the invocations of the task occur at the + * specific interval. That is, every \ref "interval" milliseconds, regardless of how long the task + * takes. If the task takes longer than \ref interval, it will be scheduled at the next available + * multiple of \ref interval. For exmaple: If the task has an interval of 60 seconds and the task + * takes 70 seconds, the next invocation will happen at 120 seconds. + * + * \ref AST_SIP_SCHED_TASK_DELAY specifies that the next invocation of the task should start + * at \ref interval milliseconds after the current invocation has finished. + * + */ +struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *serializer, + int interval, ast_sip_task sip_task, char *name, void *task_data, + enum ast_sip_scheduler_task_flags flags); + +/*! + * \brief Cancels the next invocation of a task + * \since 13.9.0 + * + * \param schtd The task structure pointer + * \retval 0 Success + * \retval -1 Failure + * \note Only cancels future invocations not the currently running invocation. + */ +int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd); + +/*! + * \brief Cancels the next invocation of a task by name + * \since 13.9.0 + * + * \param name The task name + * \retval 0 Success + * \retval -1 Failure + * \note Only cancels future invocations not the currently running invocation. + */ +int ast_sip_sched_task_cancel_by_name(const char *name); + +/*! + * \brief Gets the last start and end times of the task + * \since 13.9.0 + * + * \param schtd The task structure pointer + * \param[out] when_queued Pointer to a timeval structure to contain the time when queued + * \param[out] last_start Pointer to a timeval structure to contain the time when last started + * \param[out] last_end Pointer to a timeval structure to contain the time when last ended + * \retval 0 Success + * \retval -1 Failure + * \note Any of the pointers can be NULL if you don't need them. + */ +int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd, + struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end); + +/*! + * \brief Gets the last start and end times of the task by name + * \since 13.9.0 + * + * \param name The task name + * \param[out] when_queued Pointer to a timeval structure to contain the time when queued + * \param[out] last_start Pointer to a timeval structure to contain the time when last started + * \param[out] last_end Pointer to a timeval structure to contain the time when last ended + * \retval 0 Success + * \retval -1 Failure + * \note Any of the pointers can be NULL if you don't need them. + */ +int ast_sip_sched_task_get_times_by_name(const char *name, + struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end); + +/*! + * \brief Gets the number of milliseconds until the next invocation + * \since 13.9.0 + * + * \param schtd The task structure pointer + * \return The number of milliseconds until the next invocation or -1 if the task isn't scheduled + */ +int ast_sip_sched_task_get_next_run(struct ast_sip_sched_task *schtd); + +/*! + * \brief Gets the number of milliseconds until the next invocation + * \since 13.9.0 + * + * \param name The task name + * \return The number of milliseconds until the next invocation or -1 if the task isn't scheduled + */ +int ast_sip_sched_task_get_next_run_by_name(const char *name); + +/*! + * \brief Checks if the task is currently running + * \since 13.9.0 + * + * \param schtd The task structure pointer + * \retval 0 not running + * \retval 1 running + */ +int ast_sip_sched_is_task_running(struct ast_sip_sched_task *schtd); + +/*! + * \brief Checks if the task is currently running + * \since 13.9.0 + * + * \param name The task name + * \retval 0 not running or not found + * \retval 1 running + */ +int ast_sip_sched_is_task_running_by_name(const char *name); + +/*! + * \brief Gets the task name + * \since 13.9.0 + * + * \param schtd The task structure pointer + * \retval 0 success + * \retval 1 failure + */ +int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen); + +/*! + * @} + */ + /*! * \brief SIP body description * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index d12951c45fe..82bd7c98b06 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3636,11 +3636,7 @@ int ast_sip_push_task(struct ast_taskprocessor *serializer, int (*sip_task)(void serializer = serializer_pool[pos]; } - if (serializer) { - return ast_taskprocessor_push(serializer, sip_task, task_data); - } else { - return ast_threadpool_push(sip_threadpool, sip_task, task_data); - } + return ast_taskprocessor_push(serializer, sip_task, task_data); } struct sync_task_data { @@ -4158,6 +4154,11 @@ static int load_module(void) goto error; } + if (ast_sip_initialize_scheduler()) { + ast_log(LOG_ERROR, "Failed to start scheduler. Aborting load\n"); + goto error; + } + /* Now load all the pjproject infrastructure. */ if (load_pjsip()) { goto error; @@ -4196,8 +4197,10 @@ static int load_module(void) return AST_MODULE_LOAD_SUCCESS; error: - /* These functions all check for NULLs and are safe to call at any time */ unload_pjsip(NULL); + + /* These functions all check for NULLs and are safe to call at any time */ + ast_sip_destroy_scheduler(); serializer_pool_shutdown(); ast_threadpool_shutdown(sip_threadpool); @@ -4228,7 +4231,7 @@ static int unload_module(void) * so we have to push the work to the threadpool to handle */ ast_sip_push_task_synchronous(NULL, unload_pjsip, NULL); - + ast_sip_destroy_scheduler(); serializer_pool_shutdown(); ast_threadpool_shutdown(sip_threadpool); diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 24b8edfbccd..b175b5e1194 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -313,4 +313,23 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const */ int ast_sip_validate_uri_length(const char *uri); +/*! + * \brief Initialize scheduler + * \since 13.9.0 + * + * \retval -1 failure + * \retval 0 success + */ +int ast_sip_initialize_scheduler(void); + +/*! + * \internal + * \brief Destroy scheduler + * \since 13.9.0 + * + * \retval -1 failure + * \retval 0 success + */ +int ast_sip_destroy_scheduler(void); + #endif /* RES_PJSIP_PRIVATE_H_ */ diff --git a/res/res_pjsip/pjsip_scheduler.c b/res/res_pjsip/pjsip_scheduler.c new file mode 100644 index 00000000000..a5d406cb589 --- /dev/null +++ b/res/res_pjsip/pjsip_scheduler.c @@ -0,0 +1,495 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief res_pjsip Scheduler + * + * \author George Joseph + */ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/res_pjsip.h" +#include "include/res_pjsip_private.h" +#include "asterisk/res_pjsip_cli.h" + +#define TASK_BUCKETS 53 + +static struct ast_sched_context *scheduler_context; +static struct ao2_container *tasks; +static int task_count; + +struct ast_sip_sched_task { + /*! ast_sip_sched task id */ + uint32_t task_id; + /*! ast_sched scheudler id */ + int current_scheduler_id; + /*! task is currently running */ + int is_running; + /*! task */ + ast_sip_task task; + /*! task data */ + void *task_data; + /*! reschedule interval in milliseconds */ + int interval; + /*! the time the task was queued */ + struct timeval when_queued; + /*! the last time the task was started */ + struct timeval last_start; + /*! the last time the task was ended */ + struct timeval last_end; + /*! times run */ + int run_count; + /*! the task reschedule, cleanup and policy flags */ + enum ast_sip_scheduler_task_flags flags; + /*! the serializer to be used (if any) */ + struct ast_taskprocessor *serializer; + /* A name to be associated with the task */ + char name[0]; +}; + +AO2_STRING_FIELD_HASH_FN(ast_sip_sched_task, name); +AO2_STRING_FIELD_CMP_FN(ast_sip_sched_task, name); +AO2_STRING_FIELD_SORT_FN(ast_sip_sched_task, name); + +static int push_to_serializer(const void *data); + +/* + * This function is run in the context of the serializer. + * It runs the task with a simple call and reschedules based on the result. + */ +static int run_task(void *data) +{ + RAII_VAR(struct ast_sip_sched_task *, schtd, ao2_bump(data), ao2_cleanup); + int res; + int delay; + + ao2_lock(schtd); + schtd->last_start = ast_tvnow(); + schtd->is_running = 1; + schtd->run_count++; + ao2_unlock(schtd); + + res = schtd->task(schtd->task_data); + + ao2_lock(schtd); + schtd->is_running = 0; + schtd->last_end = ast_tvnow(); + + /* + * Don't restart if the task returned 0 or if the interval + * was set to 0 while the task was running + */ + if (!res || !schtd->interval) { + schtd->interval = 0; + ao2_unlock(schtd); + ao2_unlink(tasks, schtd); + return -1; + } + + if (schtd->flags & AST_SIP_SCHED_TASK_VARIABLE) { + schtd->interval = res; + } + + if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) { + delay = schtd->interval; + } else { + delay = schtd->interval - (ast_tvdiff_ms(schtd->last_end, schtd->last_start) % schtd->interval); + } + + schtd->current_scheduler_id = ast_sched_add(scheduler_context, delay, push_to_serializer, (const void *)schtd); + if (schtd->current_scheduler_id < 0) { + schtd->interval = 0; + ao2_unlock(schtd); + ao2_unlink(tasks, schtd); + return -1; + } + + ao2_unlock(schtd); + + return 0; +} + +/* + * This function is run by the scheduler thread. Its only job is to push the task + * to the serialize and return. It returns 0 so it's not rescheduled. + */ +static int push_to_serializer(const void *data) +{ + struct ast_sip_sched_task *schtd = (struct ast_sip_sched_task *)data; + + if (ast_sip_push_task(schtd->serializer, run_task, schtd)) { + ao2_ref(schtd, -1); + } + + return 0; +} + +int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd) +{ + int res; + + if (!ao2_ref_and_lock(schtd)) { + return -1; + } + + if (schtd->current_scheduler_id < 0 || schtd->interval <= 0) { + ao2_unlock_and_unref(schtd); + return 0; + } + + schtd->interval = 0; + ao2_unlock_and_unref(schtd); + ao2_unlink(tasks, schtd); + res = ast_sched_del(scheduler_context, schtd->current_scheduler_id); + + return res; +} + +int ast_sip_sched_task_cancel_by_name(const char *name) +{ + RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup); + + if (ast_strlen_zero(name)) { + return -1; + } + + schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (!schtd) { + return -1; + } + + return ast_sip_sched_task_cancel(schtd); +} + + +int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd, + struct timeval *queued, struct timeval *last_start, struct timeval *last_end) +{ + if (!ao2_ref_and_lock(schtd)) { + return -1; + } + + if (queued) { + memcpy(queued, &schtd->when_queued, sizeof(struct timeval)); + } + if (last_start) { + memcpy(last_start, &schtd->last_start, sizeof(struct timeval)); + } + if (last_end) { + memcpy(last_end, &schtd->last_end, sizeof(struct timeval)); + } + + ao2_unlock_and_unref(schtd); + + return 0; +} + +int ast_sip_sched_task_get_times_by_name(const char *name, + struct timeval *queued, struct timeval *last_start, struct timeval *last_end) +{ + RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup); + + if (ast_strlen_zero(name)) { + return -1; + } + + schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (!schtd) { + return -1; + } + + return ast_sip_sched_task_get_times(schtd, queued, last_start, last_end); +} + +int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen) +{ + if (maxlen <= 0) { + return -1; + } + + if (!ao2_ref_and_lock(schtd)) { + return -1; + } + + ast_copy_string(name, schtd->name, maxlen); + + ao2_unlock_and_unref(schtd); + + return 0; +} + +int ast_sip_sched_task_get_next_run(struct ast_sip_sched_task *schtd) +{ + int delay; + struct timeval since_when; + struct timeval now; + + if (!ao2_ref_and_lock(schtd)) { + return -1; + } + + if (schtd->interval) { + delay = schtd->interval; + now = ast_tvnow(); + + if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) { + since_when = schtd->is_running ? now : schtd->last_end; + } else { + since_when = schtd->last_start.tv_sec ? schtd->last_start : schtd->when_queued; + } + + delay -= ast_tvdiff_ms(now, since_when); + + delay = delay < 0 ? 0 : delay; + } else { + delay = -1; + } + + ao2_unlock_and_unref(schtd); + + return delay; +} + +int ast_sip_sched_task_get_next_run_by_name(const char *name) +{ + RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup); + + if (ast_strlen_zero(name)) { + return -1; + } + + schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (!schtd) { + return -1; + } + + return ast_sip_sched_task_get_next_run(schtd); +} + +int ast_sip_sched_is_task_running(struct ast_sip_sched_task *schtd) +{ + if (!schtd) { + return 0; + } + + return schtd->is_running; +} + +int ast_sip_sched_is_task_running_by_name(const char *name) +{ + RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup); + + if (ast_strlen_zero(name)) { + return 0; + } + + schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (!schtd) { + return 0; + } + + return schtd->is_running; +} + +static void schtd_destructor(void *data) +{ + struct ast_sip_sched_task *schtd = data; + + if (schtd->flags & AST_SIP_SCHED_TASK_DATA_AO2) { + /* release our own ref, then release the callers if asked to do so */ + ao2_ref(schtd->task_data, (schtd->flags & AST_SIP_SCHED_TASK_DATA_FREE) ? -2 : -1); + } else if (schtd->task_data && (schtd->flags & AST_SIP_SCHED_TASK_DATA_FREE)) { + ast_free(schtd->task_data); + } +} + +struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *serializer, + int interval, ast_sip_task sip_task, char *name, void *task_data, enum ast_sip_scheduler_task_flags flags) +{ +#define ID_LEN 13 /* task_deadbeef */ + struct ast_sip_sched_task *schtd; + int res; + + if (interval < 0) { + return NULL; + } + + schtd = ao2_alloc((sizeof(*schtd) + (!ast_strlen_zero(name) ? strlen(name) : ID_LEN) + 1), schtd_destructor); + if (!schtd) { + return NULL; + } + + schtd->task_id = ast_atomic_fetchadd_int(&task_count, 1); + schtd->serializer = serializer; + schtd->task = sip_task; + if (!ast_strlen_zero(name)) { + strcpy(schtd->name, name); /* Safe */ + } else { + sprintf(schtd->name, "task_%08x", schtd->task_id); + } + schtd->task_data = task_data; + schtd->flags = flags; + schtd->interval = interval; + schtd->when_queued = ast_tvnow(); + + if (flags & AST_SIP_SCHED_TASK_DATA_AO2) { + ao2_ref(task_data, +1); + } + res = ast_sched_add(scheduler_context, interval, push_to_serializer, (const void *)schtd); + if (res < 0) { + ao2_ref(schtd, -1); + return NULL; + } else { + schtd->current_scheduler_id = res; + ao2_link(tasks, schtd); + } + + return schtd; +#undef ID_LEN +} + +static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ao2_iterator i; + struct ast_sip_sched_task *schtd; + const char *log_format = ast_logger_get_dateformat(); + struct ast_tm tm; + char queued[32]; + char last_start[32]; + char last_end[32]; + int datelen; + struct timeval now = ast_tvnow(); + const char *separator = "======================================"; + + switch (cmd) { + case CLI_INIT: + e->command = "pjsip show scheduled_tasks"; + e->usage = "Usage: pjsip show scheduled_tasks\n" + " Show all scheduled tasks\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 3) { + return CLI_SHOWUSAGE; + } + + ast_localtime(&now, &tm, NULL); + datelen = ast_strftime(queued, sizeof(queued), log_format, &tm); + + ast_cli(a->fd, "PJSIP Scheduled Tasks:\n\n"); + + ast_cli(a->fd, " %1$-24s %2$-8s %3$-9s %4$-7s %6$-*5$s %7$-*5$s %8$-*5$s\n", + "Task Name", "Interval", "Times Run", "State", + datelen, "Queued", "Last Started", "Last Ended"); + + ast_cli(a->fd, " %1$-24.24s %2$-8.8s %3$-9.9s %4$-7.7s %6$-*5$.*5$s %7$-*5$.*5$s %8$-*5$.*5$s\n", + separator, separator, separator, separator, + datelen, separator, separator, separator); + + + ao2_ref(tasks, +1); + ao2_rdlock(tasks); + i = ao2_iterator_init(tasks, 0); + while ((schtd = ao2_iterator_next(&i))) { + + ast_localtime(&schtd->when_queued, &tm, NULL); + ast_strftime(queued, sizeof(queued), log_format, &tm); + + if (ast_tvzero(schtd->last_start)) { + strcpy(last_start, "not yet started"); + } else { + ast_localtime(&schtd->last_start, &tm, NULL); + ast_strftime(last_start, sizeof(last_start), log_format, &tm); + } + + if (ast_tvzero(schtd->last_end)) { + if (ast_tvzero(schtd->last_start)) { + strcpy(last_end, "not yet started"); + } else { + strcpy(last_end, "running"); + } + } else { + ast_localtime(&schtd->last_end, &tm, NULL); + ast_strftime(last_end, sizeof(last_end), log_format, &tm); + } + + ast_cli(a->fd, " %1$-24.24s %2$-8.3f %3$-9d %4$-7s %6$-*5$s %7$-*5$s %8$-*5$s\n", + schtd->name, + schtd->interval / 1000.0, + schtd->run_count, + schtd->is_running ? "running" : "waiting", + datelen, queued, last_start, last_end); + ao2_cleanup(schtd); + } + ao2_iterator_destroy(&i); + ao2_unlock(tasks); + ao2_ref(tasks, -1); + ast_cli(a->fd, "\n"); + + return CLI_SUCCESS; +} + +static struct ast_cli_entry cli_commands[] = { + AST_CLI_DEFINE(cli_show_tasks, "Show all scheduled tasks"), +}; + +int ast_sip_initialize_scheduler(void) +{ + if (!(scheduler_context = ast_sched_context_create())) { + ast_log(LOG_ERROR, "Failed to create scheduler. Aborting load\n"); + return -1; + } + + if (ast_sched_start_thread(scheduler_context)) { + ast_log(LOG_ERROR, "Failed to start scheduler. Aborting load\n"); + ast_sched_context_destroy(scheduler_context); + return -1; + } + + tasks = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, + TASK_BUCKETS, ast_sip_sched_task_hash_fn, ast_sip_sched_task_sort_fn, ast_sip_sched_task_cmp_fn); + if (!tasks) { + ast_log(LOG_ERROR, "Failed to allocate task container. Aborting load\n"); + ast_sched_context_destroy(scheduler_context); + return -1; + } + + ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + + return 0; +} + +int ast_sip_destroy_scheduler(void) +{ + ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); + + if (scheduler_context) { + ast_sched_context_destroy(scheduler_context); + } + + ao2_cleanup(tasks); + tasks = NULL; + + return 0; +} diff --git a/tests/test_res_pjsip_scheduler.c b/tests/test_res_pjsip_scheduler.c new file mode 100644 index 00000000000..22d2c99ce9f --- /dev/null +++ b/tests/test_res_pjsip_scheduler.c @@ -0,0 +1,400 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Fairview 5 Engineering, LLC + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief res_pjsip scheduler tests + * + * \author George Joseph + * + */ + +/*** MODULEINFO + TEST_FRAMEWORK + res_pjsip + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/taskprocessor.h" +#include "asterisk/res_pjsip.h" +#include "asterisk/utils.h" + +#define CATEGORY "/res/res_pjsip/scheduler/" + +struct test_data { + ast_mutex_t lock; + ast_cond_t cond; + pthread_t tid; + struct timeval test_start; + struct timeval task_start; + struct timeval task_end; + int is_servant; + int interval; + int sleep; + int done; + struct ast_test *test; +}; + +#define S2U(x) (long int)(x * 1000 * 1000) +#define M2U(x) (long int)(x * 1000) + +static int task_1(void *data) +{ + struct test_data *test = data; + + test->done = 0; + test->task_start = ast_tvnow(); + test->tid = pthread_self(); + test->is_servant = ast_sip_thread_is_servant(); + usleep(M2U(test->sleep)); + test->task_end = ast_tvnow(); + + ast_mutex_lock(&test->lock); + test->done = 1; + ast_mutex_unlock(&test->lock); + ast_cond_signal(&test->cond); + + return test->interval; +} + + +static void data_cleanup(void *data) +{ + struct test_data *test_data = data; + ast_mutex_destroy(&test_data->lock); + ast_cond_destroy(&test_data->cond); +} + +#define waitfor(x) \ +{ \ + ast_mutex_lock(&(x)->lock); \ + while (!(x)->done) { \ + ast_cond_wait(&(x)->cond, &(x)->lock); \ + } \ + (x)->done = 0; \ + ast_mutex_unlock(&(x)->lock); \ +} + +static int scheduler(struct ast_test *test, int serialized) +{ + RAII_VAR(struct ast_taskprocessor *, tp1, NULL, ast_taskprocessor_unreference); + RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup); + RAII_VAR(struct test_data *, test_data2, ao2_alloc(sizeof(*test_data2), data_cleanup), ao2_cleanup); + RAII_VAR(struct ast_sip_sched_task *, task1, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_sched_task *, task2, NULL, ao2_cleanup); + int duration; + int delay; + struct timeval task1_start; + + ast_test_validate(test, test_data1 != NULL); + ast_test_validate(test, test_data2 != NULL); + + test_data1->test = test; + test_data1->test_start = ast_tvnow(); + test_data1->interval = 2000; + test_data1->sleep = 1000; + ast_mutex_init(&test_data1->lock); + ast_cond_init(&test_data1->cond, NULL); + + test_data2->test = test; + test_data2->test_start = ast_tvnow(); + test_data2->interval = 2000; + test_data2->sleep = 1000; + ast_mutex_init(&test_data2->lock); + ast_cond_init(&test_data2->cond, NULL); + + if (serialized) { + ast_test_status_update(test, "This test will take about %3.1f seconds\n", + (test_data1->interval + test_data1->sleep + (MAX(test_data1->interval - test_data2->interval, 0)) + test_data2->sleep) / 1000.0); + tp1 = ast_sip_create_serializer("test-scheduler-serializer"); + ast_test_validate(test, (tp1 != NULL)); + } else { + ast_test_status_update(test, "This test will take about %3.1f seconds\n", + ((MAX(test_data1->interval, test_data2->interval) + MAX(test_data1->sleep, test_data2->sleep)) / 1000.0)); + } + + task1 = ast_sip_schedule_task(tp1, test_data1->interval, task_1, NULL, test_data1, AST_SIP_SCHED_TASK_FIXED); + ast_test_validate(test, task1 != NULL); + + task2 = ast_sip_schedule_task(tp1, test_data2->interval, task_1, NULL, test_data2, AST_SIP_SCHED_TASK_FIXED); + ast_test_validate(test, task2 != NULL); + + waitfor(test_data1); + ast_sip_sched_task_cancel(task1); + ast_test_validate(test, test_data1->is_servant); + + duration = ast_tvdiff_ms(test_data1->task_end, test_data1->test_start); + ast_test_validate(test, (duration > ((test_data1->interval + test_data1->sleep) * 0.9)) + && (duration < ((test_data1->interval + test_data1->sleep) * 1.1))); + + ast_sip_sched_task_get_times(task1, NULL, &task1_start, NULL); + delay = ast_tvdiff_ms(task1_start, test_data1->test_start); + ast_test_validate(test, (delay > (test_data1->interval * 0.9) + && (delay < (test_data1->interval * 1.1)))); + + waitfor(test_data2); + ast_sip_sched_task_cancel(task2); + ast_test_validate(test, test_data2->is_servant); + + if (serialized) { + ast_test_validate(test, test_data1->tid == test_data2->tid); + ast_test_validate(test, ast_tvdiff_ms(test_data2->task_start, test_data1->task_end) >= 0); + } else { + ast_test_validate(test, test_data1->tid != test_data2->tid); + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(serialized_scheduler) +{ + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test res_pjsip serialized scheduler"; + info->description = "Test res_pjsip serialized scheduler"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + return scheduler(test, 1); +} + +AST_TEST_DEFINE(unserialized_scheduler) +{ + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test res_pjsip unserialized scheduler"; + info->description = "Test res_pjsip unserialized scheduler"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + return scheduler(test, 0); +} + +static int run_count; +static int destruct_count; + +static int dummy_task(void *data) +{ + int *sleep = data; + + usleep(M2U(*sleep)); + run_count++; + + return 0; +} + +static void test_destructor(void *data) +{ + destruct_count++; +} + +AST_TEST_DEFINE(scheduler_cleanup) +{ + RAII_VAR(int *, sleep, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup); + int interval; + int when; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test res_pjsip scheduler cleanup"; + info->description = "Test res_pjsip scheduler cleanup"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + destruct_count = 0; + interval = 1000; + + sleep = ao2_alloc(sizeof(*sleep), test_destructor); + ast_test_validate(test, sleep != NULL); + *sleep = 500; + + ast_test_status_update(test, "This test will take about %3.1f seconds\n", + ((interval * 1.1) + *sleep) / 1000.0); + + task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep, + AST_SIP_SCHED_TASK_DATA_AO2 | AST_SIP_SCHED_TASK_DATA_FREE); + ast_test_validate(test, task != NULL); + usleep(M2U(interval * 0.5)); + when = ast_sip_sched_task_get_next_run(task); + ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6))); + usleep(M2U(interval * 0.6)); + ast_test_validate(test, ast_sip_sched_is_task_running(task)); + + usleep(M2U(*sleep)); + + ast_test_validate(test, (ast_sip_sched_is_task_running(task) == 0)); + when = ast_sip_sched_task_get_next_run(task); + ast_test_validate(test, (when < 0), res, error); + ast_test_validate(test, (ao2_ref(task, 0) == 1)); + ao2_ref(task, -1); + task = NULL; + ast_test_validate(test, (destruct_count == 1)); + sleep = NULL; + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(scheduler_cancel) +{ + RAII_VAR(int *, sleep, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup); + int interval; + int when; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test res_pjsip scheduler cancel task"; + info->description = "Test res_pjsip scheduler cancel task"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + destruct_count = 0; + interval = 1000; + + sleep = ao2_alloc(sizeof(*sleep), test_destructor); + ast_test_validate(test, sleep != NULL); + *sleep = 500; + + ast_test_status_update(test, "This test will take about %3.1f seconds\n", + (interval + *sleep) / 1000.0); + + task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep, AST_SIP_SCHED_TASK_DATA_NO_CLEANUP); + ast_test_validate(test, task != NULL); + + usleep(M2U(interval * 0.5)); + when = ast_sip_sched_task_get_next_run_by_name("dummy"); + ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6))); + ast_test_validate(test, !ast_sip_sched_is_task_running_by_name("dummy")); + ast_test_validate(test, ao2_ref(task, 0) == 2); + + ast_sip_sched_task_cancel_by_name("dummy"); + + when = ast_sip_sched_task_get_next_run(task); + ast_test_validate(test, when < 0); + + usleep(M2U(interval)); + ast_test_validate(test, run_count == 0); + ast_test_validate(test, destruct_count == 0); + ast_test_validate(test, ao2_ref(task, 0) == 1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(scheduler_policy) +{ + RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup); + RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup); + int when; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Test res_pjsip scheduler cancel task"; + info->description = "Test res_pjsip scheduler cancel task"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, test_data1 != NULL); + + destruct_count = 0; + run_count = 0; + test_data1->test = test; + test_data1->test_start = ast_tvnow(); + test_data1->interval = 1000; + test_data1->sleep = 500; + ast_mutex_init(&test_data1->lock); + ast_cond_init(&test_data1->cond, NULL); + + ast_test_status_update(test, "This test will take about %3.1f seconds\n", + ((test_data1->interval * 3) + test_data1->sleep) / 1000.0); + + task = ast_sip_schedule_task(NULL, test_data1->interval, task_1, "test_1", test_data1, + AST_SIP_SCHED_TASK_DATA_NO_CLEANUP | AST_SIP_SCHED_TASK_PERIODIC); + ast_test_validate(test, task != NULL); + + waitfor(test_data1); + when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start); + ast_test_validate(test, when > test_data1->interval * 0.9 && when < test_data1->interval * 1.1); + + waitfor(test_data1); + when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start); + ast_test_validate(test, when > test_data1->interval * 2 * 0.9 && when < test_data1->interval * 2 * 1.1); + + waitfor(test_data1); + when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start); + ast_test_validate(test, when > test_data1->interval * 3 * 0.9 && when < test_data1->interval * 3 * 1.1); + + ast_sip_sched_task_cancel(task); + ao2_ref(task, -1); + task = NULL; + + return AST_TEST_PASS; +} + +static int load_module(void) +{ + CHECK_PJSIP_MODULE_LOADED(); + + AST_TEST_REGISTER(serialized_scheduler); + AST_TEST_REGISTER(unserialized_scheduler); + AST_TEST_REGISTER(scheduler_cleanup); + AST_TEST_REGISTER(scheduler_cancel); + AST_TEST_REGISTER(scheduler_policy); + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(scheduler_cancel); + AST_TEST_UNREGISTER(scheduler_cleanup); + AST_TEST_UNREGISTER(unserialized_scheduler); + AST_TEST_UNREGISTER(serialized_scheduler); + AST_TEST_UNREGISTER(scheduler_policy); + return 0; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "res_pjsip scheduler test module"); From be4333ddadc982905e498a03d17e05984c8f07b0 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 14 Apr 2016 13:49:35 -0500 Subject: [PATCH 0352/1578] transport management: Register thread with PJProject. The scheduler thread that kills idle TCP connections was not registering with PJProject properly and causing assertions if PJProject was built in debug mode. This change registers the thread with PJProject the first time that the scheduler callback executes. AST-2016-005 Change-Id: I5f7a37e2c80726a99afe9dc2a4a69bdedf661283 --- res/res_pjsip_transport_management.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c index 862ae721685..e4ade2b44ef 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip_transport_management.c @@ -101,11 +101,29 @@ static void *keepalive_transport_thread(void *data) return NULL; } +AST_THREADSTORAGE(desc_storage); + static int idle_sched_cb(const void *data) { struct monitored_transport *keepalive = (struct monitored_transport *) data; int sip_received = ast_atomic_fetchadd_int(&keepalive->sip_received, 0); + if (!pj_thread_is_registered()) { + pj_thread_t *thread; + pj_thread_desc *desc; + + desc = ast_threadstorage_get(&desc_storage, sizeof(pj_thread_desc)); + if (!desc) { + ast_log(LOG_ERROR, "Could not get thread desc from thread-local storage.\n"); + ao2_ref(keepalive, -1); + return 0; + } + + pj_bzero(*desc, sizeof(*desc)); + + pj_thread_register("Transport Monitor", *desc, &thread); + } + if (!sip_received) { ast_log(LOG_NOTICE, "Shutting down transport '%s' since no request was received in %d seconds\n", keepalive->transport->info, IDLE_TIMEOUT); From a6e2ba187af3710428df1f18d39bd6eccf6db3db Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 11 Apr 2016 17:20:49 -0400 Subject: [PATCH 0353/1578] Codecs: strip codec name while parsing allow/disallow options Failed registration using PJSIP/Realtime if one of the codec name in allow/disallow option is wrong or contains space. This patch strip codec name. ASTERISK-25914 Change-Id: Ifdf02de94e5ddbce305640f6f0666084a3b9283d --- main/format_cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/format_cap.c b/main/format_cap.c index d3e87fafd0a..2b3e6cd5f87 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -342,7 +342,7 @@ int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const ch } - while ((this = strsep(&parse, ",|"))) { + while ((this = ast_strip(strsep(&parse, ",|")))) { int framems = 0; struct ast_format *format = NULL; From 5e64d7e7a3ddc48a578e670cd8b719bb745cb195 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 12 Apr 2016 14:55:42 -0500 Subject: [PATCH 0354/1578] Dial: Combine frame handling functions. There is a good amount of repetition in the two frame handling routines in the Dial API. This commit combines the two functions into one. This is in preparation for an upcoming commit that adds the ability to handle frames for a channel in a bridge. ASTERISK-25925 Reported by Mark Michelson Change-Id: Iaae2f174e3058e774cb44e10659fcdfb85345c58 --- main/dial.c | 126 ++++++++++++++++++++++------------------------------ 1 file changed, 52 insertions(+), 74 deletions(-) diff --git a/main/dial.c b/main/dial.c index 80247588d92..fc66af5a766 100644 --- a/main/dial.c +++ b/main/dial.c @@ -583,13 +583,17 @@ static void set_state(struct ast_dial *dial, enum ast_dial_result state) dial->state_callback(dial); } -/*! \brief Helper function that handles control frames WITH owner */ +/*! \brief Helper function that handles frames */ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr, struct ast_channel *chan) { if (fr->frametype == AST_FRAME_CONTROL) { switch (fr->subclass.integer) { case AST_CONTROL_ANSWER: - ast_verb(3, "%s answered %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); + if (chan) { + ast_verb(3, "%s answered %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); + } else { + ast_verb(3, "%s answered\n", ast_channel_name(channel->owner)); + } AST_LIST_LOCK(&dial->channels); AST_LIST_REMOVE(&dial->channels, channel, list); AST_LIST_INSERT_HEAD(&dial->channels, channel, list); @@ -613,28 +617,47 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel break; case AST_CONTROL_INCOMPLETE: ast_verb(3, "%s dialed Incomplete extension %s\n", ast_channel_name(channel->owner), ast_channel_exten(channel->owner)); - ast_indicate(chan, AST_CONTROL_INCOMPLETE); + if (chan) { + ast_indicate(chan, AST_CONTROL_INCOMPLETE); + } else { + ast_hangup(channel->owner); + channel->cause = AST_CAUSE_UNALLOCATED; + channel->owner = NULL; + } break; case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", ast_channel_name(channel->owner)); - if (!dial->options[AST_DIAL_OPTION_MUSIC]) + if (chan && !dial->options[AST_DIAL_OPTION_MUSIC]) ast_indicate(chan, AST_CONTROL_RINGING); set_state(dial, AST_DIAL_RESULT_RINGING); break; case AST_CONTROL_PROGRESS: - ast_verb(3, "%s is making progress, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); - ast_indicate(chan, AST_CONTROL_PROGRESS); + if (chan) { + ast_verb(3, "%s is making progress, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); + ast_indicate(chan, AST_CONTROL_PROGRESS); + } else { + ast_verb(3, "%s is making progress\n", ast_channel_name(channel->owner)); + } set_state(dial, AST_DIAL_RESULT_PROGRESS); break; case AST_CONTROL_VIDUPDATE: + if (!chan) { + break; + } ast_verb(3, "%s requested a video update, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); ast_indicate(chan, AST_CONTROL_VIDUPDATE); break; case AST_CONTROL_SRCUPDATE: + if (!chan) { + break; + } ast_verb(3, "%s requested a source update, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); ast_indicate(chan, AST_CONTROL_SRCUPDATE); break; case AST_CONTROL_CONNECTED_LINE: + if (!chan) { + break; + } ast_verb(3, "%s connected line has changed, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); if (ast_channel_connected_line_sub(channel->owner, chan, fr, 1) && ast_channel_connected_line_macro(channel->owner, chan, fr, 1, 1)) { @@ -642,6 +665,9 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel } break; case AST_CONTROL_REDIRECTING: + if (!chan) { + break; + } ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); if (ast_channel_redirecting_sub(channel->owner, chan, fr, 1) && ast_channel_redirecting_macro(channel->owner, chan, fr, 1, 1)) { @@ -649,15 +675,25 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel } break; case AST_CONTROL_PROCEEDING: - ast_verb(3, "%s is proceeding, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); - ast_indicate(chan, AST_CONTROL_PROCEEDING); + if (chan) { + ast_verb(3, "%s is proceeding, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); + ast_indicate(chan, AST_CONTROL_PROCEEDING); + } else { + ast_verb(3, "%s is proceeding\n", ast_channel_name(channel->owner)); + } set_state(dial, AST_DIAL_RESULT_PROCEEDING); break; case AST_CONTROL_HOLD: + if (!chan) { + break; + } ast_verb(3, "Call on %s placed on hold\n", ast_channel_name(chan)); ast_indicate_data(chan, AST_CONTROL_HOLD, fr->data.ptr, fr->datalen); break; case AST_CONTROL_UNHOLD: + if (!chan) { + break; + } ast_verb(3, "Call on %s left from hold\n", ast_channel_name(chan)); ast_indicate(chan, AST_CONTROL_UNHOLD); break; @@ -665,11 +701,15 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel case AST_CONTROL_FLASH: break; case AST_CONTROL_PVT_CAUSE_CODE: - ast_indicate_data(chan, AST_CONTROL_PVT_CAUSE_CODE, fr->data.ptr, fr->datalen); + if (chan) { + ast_indicate_data(chan, AST_CONTROL_PVT_CAUSE_CODE, fr->data.ptr, fr->datalen); + } break; case -1: - /* Prod the channel */ - ast_indicate(chan, -1); + if (chan) { + /* Prod the channel */ + ast_indicate(chan, -1); + } break; default: break; @@ -677,65 +717,6 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel } } -/*! \brief Helper function that handles control frames WITHOUT owner */ -static void handle_frame_ownerless(struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr) -{ - /* If we have no owner we can only update the state of the dial structure, so only look at control frames */ - if (fr->frametype != AST_FRAME_CONTROL) - return; - - switch (fr->subclass.integer) { - case AST_CONTROL_ANSWER: - ast_verb(3, "%s answered\n", ast_channel_name(channel->owner)); - AST_LIST_LOCK(&dial->channels); - AST_LIST_REMOVE(&dial->channels, channel, list); - AST_LIST_INSERT_HEAD(&dial->channels, channel, list); - AST_LIST_UNLOCK(&dial->channels); - ast_channel_publish_dial(NULL, channel->owner, channel->device, "ANSWER"); - set_state(dial, AST_DIAL_RESULT_ANSWERED); - break; - case AST_CONTROL_BUSY: - ast_verb(3, "%s is busy\n", ast_channel_name(channel->owner)); - ast_channel_publish_dial(NULL, channel->owner, channel->device, "BUSY"); - ast_hangup(channel->owner); - channel->cause = AST_CAUSE_USER_BUSY; - channel->owner = NULL; - break; - case AST_CONTROL_CONGESTION: - ast_verb(3, "%s is circuit-busy\n", ast_channel_name(channel->owner)); - ast_channel_publish_dial(NULL, channel->owner, channel->device, "CONGESTION"); - ast_hangup(channel->owner); - channel->cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; - channel->owner = NULL; - break; - case AST_CONTROL_INCOMPLETE: - /* - * Nothing to do but abort the call since we have no - * controlling channel to ask for more digits. - */ - ast_verb(3, "%s dialed Incomplete extension %s\n", - ast_channel_name(channel->owner), ast_channel_exten(channel->owner)); - ast_hangup(channel->owner); - channel->cause = AST_CAUSE_UNALLOCATED; - channel->owner = NULL; - break; - case AST_CONTROL_RINGING: - ast_verb(3, "%s is ringing\n", ast_channel_name(channel->owner)); - set_state(dial, AST_DIAL_RESULT_RINGING); - break; - case AST_CONTROL_PROGRESS: - ast_verb(3, "%s is making progress\n", ast_channel_name(channel->owner)); - set_state(dial, AST_DIAL_RESULT_PROGRESS); - break; - case AST_CONTROL_PROCEEDING: - ast_verb(3, "%s is proceeding\n", ast_channel_name(channel->owner)); - set_state(dial, AST_DIAL_RESULT_PROCEEDING); - break; - default: - break; - } -} - /*! \brief Helper function to handle when a timeout occurs on dialing attempt */ static int handle_timeout_trip(struct ast_dial *dial, struct timeval start) { @@ -887,10 +868,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann } /* Process the frame */ - if (chan) - handle_frame(dial, channel, fr, chan); - else - handle_frame_ownerless(dial, channel, fr); + handle_frame(dial, channel, fr, chan); /* Free the received frame and start all over */ ast_frfree(fr); From af114edb8bde5257a2e7511c6120e175f673a229 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 15 Apr 2016 16:51:58 -0500 Subject: [PATCH 0355/1578] stasis_bridge.c: Update stasis bridge push diagnostic messages. Change-Id: I195b14994c9dcccb9452491ca20a885d2a54605a --- res/stasis/stasis_bridge.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index 1f501cad11c..bfd287226c2 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -167,10 +167,15 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel if (!control && !stasis_app_channel_is_internal(bridge_channel->chan)) { /* channel not in Stasis(), get it there */ + ast_debug(1, "Bridge %s: pushing non-stasis %p(%s) setup to come back in under stasis\n", + self->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); + /* Attach after-bridge callback and pass ownership of swap_app to it */ if (ast_bridge_set_after_callback(bridge_channel->chan, bridge_stasis_run_cb, NULL, NULL)) { - ast_log(LOG_ERROR, "Failed to set after bridge callback\n"); + ast_log(LOG_ERROR, + "Failed to set after bridge callback for bridge %s non-stasis push of %s\n", + self->uniqueid, ast_channel_name(bridge_channel->chan)); return -1; } From dbb47e0a47f3205898f77e5c1479f92e880574be Mon Sep 17 00:00:00 2001 From: ibercom Date: Mon, 18 Apr 2016 11:53:14 +0200 Subject: [PATCH 0356/1578] app_queue: Frequent segfaults in function can_ring_entry() ASTERISK-25888 #close Change-Id: I007a2f2dd99823e04fb5be3ff01f02b0a2956117 --- apps/app_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 0123e473abf..40aed2fe544 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4189,7 +4189,7 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call) return 0; } - if (call->member->in_call && call->lastqueue->wrapuptime) { + if (call->member->in_call && call->lastqueue && call->lastqueue->wrapuptime) { ast_debug(1, "%s is in call, so not available (wrapuptime %d)\n", call->interface, call->lastqueue->wrapuptime); return 0; From f06ce7f90ad39f86cea909e198f4925c5cd9ce70 Mon Sep 17 00:00:00 2001 From: Jaco Kroon Date: Sun, 17 Apr 2016 22:37:53 +0200 Subject: [PATCH 0357/1578] chan_sip: Don't verify table if rtupdate=no If rtupdate=no do not verify sipregs/peers table has updatable fields. ASTERISK-25934 #close Change-Id: Iaa2c53037b93daccc7e7333c40d61861847b856d --- channels/chan_sip.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 2a6dd77e7c2..d927f06e393 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -35267,17 +35267,19 @@ static int load_module(void) /* And start the monitor for the first time */ restart_monitor(); - ast_realtime_require_field(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", - "name", RQ_CHAR, 10, - "ipaddr", RQ_CHAR, INET6_ADDRSTRLEN - 1, - "port", RQ_UINTEGER2, 5, - "regseconds", RQ_INTEGER4, 11, - "defaultuser", RQ_CHAR, 10, - "fullcontact", RQ_CHAR, 35, - "regserver", RQ_CHAR, 20, - "useragent", RQ_CHAR, 20, - "lastms", RQ_INTEGER4, 11, - SENTINEL); + if (sip_cfg.peer_rtupdate) { + ast_realtime_require_field(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", + "name", RQ_CHAR, 10, + "ipaddr", RQ_CHAR, INET6_ADDRSTRLEN - 1, + "port", RQ_UINTEGER2, 5, + "regseconds", RQ_INTEGER4, 11, + "defaultuser", RQ_CHAR, 10, + "fullcontact", RQ_CHAR, 35, + "regserver", RQ_CHAR, 20, + "useragent", RQ_CHAR, 20, + "lastms", RQ_INTEGER4, 11, + SENTINEL); + } sip_register_tests(); From 6365f0018f520957622bc927bb4c2ca3441135c7 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 15 Apr 2016 11:41:49 -0500 Subject: [PATCH 0358/1578] bridge_channel.c: Ignore role setup failure in channel push. We have to setup the channel roles after the bridge class push is called because the bridge class push callback may have set roles on the incoming channel. Since we have already partially pushed the channel into the bridge and reversing what we have already done could be problematic, the only thing we can do is press on to complete pushing the channel into the bridge. * Ignore any channel role setup errors after pushing the channel into a bridge. The channel may behave incorrectly in the bridge but we can no longer abort the push at this time. Change-Id: I08a97082b729052ee65cdca6bb730cf1289ede00 --- main/bridge_channel.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 81726603356..66f26eefeda 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2117,13 +2117,14 @@ int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel, if (bridge->dissolved || bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT || (swap && swap->state != BRIDGE_CHANNEL_STATE_WAIT) - || bridge->v_table->push(bridge, bridge_channel, swap) - || ast_bridge_channel_establish_roles(bridge_channel)) { + || bridge->v_table->push(bridge, bridge_channel, swap)) { ast_debug(1, "Bridge %s: pushing %p(%s) into bridge failed\n", bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); return -1; } + ast_bridge_channel_establish_roles(bridge_channel); + if (swap) { int dissolve = ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_EMPTY); From 6cfa02394f197ee224c563a1fa3a035bdf0fd22b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 18 Apr 2016 15:41:34 -0300 Subject: [PATCH 0359/1578] res_pjsip_transport_management: Allow unload to occur. At shutdown it is possible for modules to be unloaded that wouldn't normally be unloaded. This allows the environment to be cleaned up. The res_pjsip_transport_management module did not have the unload logic in it to clean itself up causing the res_pjsip module to not get unloaded. As a result the res_pjsip monitor thread kept going processing traffic and timers when it shouldn't. Change-Id: Ic8cadee131e3b2c436a81d3ae8bb5775999ae00a --- res/res_pjsip_transport_management.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c index e4ade2b44ef..8ba8c2da261 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip_transport_management.c @@ -24,6 +24,8 @@ #include "asterisk.h" +#include + #include #include @@ -93,7 +95,7 @@ static void *keepalive_transport_thread(void *data) /* Once loaded this module just keeps on going as it is unsafe to stop and change the underlying * callback for the transport manager. */ - while (1) { + while (keepalive_interval) { sleep(keepalive_interval); ao2_callback(transports, OBJ_NODATA, keepalive_transport_cb, NULL); } @@ -347,7 +349,19 @@ static int load_module(void) static int unload_module(void) { - /* This will never get called */ + pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + + if (keepalive_interval) { + keepalive_interval = 0; + pthread_kill(keepalive_thread, SIGURG); + pthread_join(keepalive_thread, NULL); + } + + ast_sched_context_destroy(sched); + ao2_ref(transports, -1); + + ast_sip_unregister_service(&idle_monitor_module); + pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback); return 0; } From b8b60135ecc01bcac917b6851cb1d0c7e3b2051a Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 18 Apr 2016 17:00:42 -0500 Subject: [PATCH 0360/1578] res_pjsip_registrar: Fix bad memory-ness with user_agent. Recent changes to the PJSIP registrar resulted in tests failing due to missing AOR_CONTACT_ADDED test events. The reason for this was that the user_agent string had junk values in it, resulting in being unable to generate the event. I'm going to be honest here, I have no idea why this was happening. Here are the steps needed for the user_agent variable to get messed up: * REGISTER is received * First contact in the REGISTER results in a contact being removed * Second contact in the REGISTER results in a contact being added * The contact, AOR, expiration, and user agent all have to be passed as format parameters to the creation of a string. Any subset of those parameters would not be enough to cause the problem. Looking into what was happening, the thing that struck me as odd was that the user_agent variable was meant to be set to the value of the User-Agent SIP header in the incoming REGISTER. However, when removing a contact, the user_agent variable would be set (via ast_strdupa inside a loop) to the stored contact's user_agent. This means that the user_agent's value would be incorrect when attempting to process further contacts in the incoming REGISTER. The fix here is to use a different variable for the stored user agent when removing a contact. Correcting the behavior to be correct also means the memory usage is less weird, and the issue no longer occurs. ASTERISK-25929 #close Reported by Joshua Colp Change-Id: I7cd24c86a38dec69ebcc94150614bc25f46b8c08 --- res/res_pjsip_registrar.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index a94babd88f7..8edd6ee4377 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -576,7 +576,6 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co ao2_cleanup(contact_update); } else { /* We want to report the user agent that was actually in the removed contact */ - user_agent = ast_strdupa(contact->user_agent); ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", @@ -585,7 +584,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co "UserAgent: %s", contact_uri, aor_name, - user_agent); + contact->user_agent); } } From 0235a6653262fa3bebdaf1f89aac5e570442da5c Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 18 Apr 2016 12:12:37 -0500 Subject: [PATCH 0361/1578] PJSIP: Remove PJSIP parsing functions from uri length validation. The PJSIP parsing functions provide a nice concise way to check the length of a hostname in a SIP URI. The problem is that in order to use those parsing functions, it's required to use them from a thread that has registered with PJLib. On startup, when parsing AOR configuration, the permanent URI handler may not be run from a PJLib-registered thread. Specifically, this could happen when Asterisk was started in daemon mode rather than console-mode. If PJProject were compiled with assertions enabled, then this would cause Asterisk to crash on startup. The solution presented here is to do our own parsing of the contact URI in order to ensure that the hostname in the URI is not too long. The parsing does not attempt to perform a full SIP URI parse/validation, since the hostname in the URI is what is important. ASTERISK-25928 #close Reported by Joshua Colp Change-Id: Ic3d6c20ff3502507c17244a8b7e2ca761dc7fb60 --- res/res_pjsip/location.c | 56 +++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 0a82f3a0874..db4f9ac0995 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -412,38 +412,64 @@ static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, in int ast_sip_validate_uri_length(const char *contact_uri) { - pjsip_uri *uri; - pjsip_sip_uri *sip_uri; - pj_pool_t *pool; int max_length = pj_max_hostname - 1; + char *contact = ast_strdupa(contact_uri); + char *host; + char *at; + int theres_a_port = 0; if (strlen(contact_uri) > pjsip_max_url_size - 1) { return -1; } - if (!(pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "uri validation", 512, 512))) { - ast_log(LOG_ERROR, "Unable to allocate pool for uri validation\n"); + contact = ast_strip_quoted(contact, "<", ">"); + + if (!strncasecmp(contact, "sip:", 4)) { + host = contact + 4; + } else if (!strncasecmp(contact, "sips:", 5)) { + host = contact + 5; + } else { + /* Not a SIP URI */ return -1; } - if (!(uri = pjsip_parse_uri(pool, (char *)contact_uri, strlen(contact_uri), 0)) || - (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) { - pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); - return -1; + at = strchr(contact, '@'); + if (at) { + /* sip[s]:user@host */ + host = at + 1; + } + + if (host[0] == '[') { + /* Host is an IPv6 address. Just get up to the matching bracket */ + char *close_bracket; + + close_bracket = strchr(host, ']'); + if (!close_bracket) { + return -1; + } + close_bracket++; + if (*close_bracket == ':') { + theres_a_port = 1; + } + *close_bracket = '\0'; + } else { + /* uri parameters could contain ';' so trim them off first */ + host = strsep(&host, ";?"); + /* Host is FQDN or IPv4 address. Need to find closing delimiter */ + if (strchr(host, ':')) { + theres_a_port = 1; + host = strsep(&host, ":"); + } } - sip_uri = pjsip_uri_get_uri(uri); - if (sip_uri->port == 0) { + if (!theres_a_port) { max_length -= strlen("_sips.tcp."); } - if (sip_uri->host.slen > max_length) { - pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + if (strlen(host) > max_length) { return -1; } - pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); - return 0; } From d95512a7ddeb0dcd1709e55d91cad50b436af33b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 19 Apr 2016 15:02:18 -0300 Subject: [PATCH 0362/1578] app_talkdetect: Make the module core supported. This module is used as part of testsuite tests to confirm stuff works. I'm accordingly marking it as core as it is required by those tests. Change-Id: I558e7af7679b22b8ed641d7dd37ee4ca35b11e88 --- apps/app_talkdetect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app_talkdetect.c b/apps/app_talkdetect.c index 5cb10ad7ff6..6b5a6492262 100644 --- a/apps/app_talkdetect.c +++ b/apps/app_talkdetect.c @@ -26,7 +26,7 @@ */ /*** MODULEINFO - extended + core ***/ #include "asterisk.h" From 70e860ec4905050c4cba5b6f8f5a7f710a96627b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 19 Apr 2016 16:52:15 -0600 Subject: [PATCH 0363/1578] res_pjsip_callerid: Clear out display name if id->name is not valid When create_new_id_hdr creates a new RPID or PAI header, it starts by cloning the From header, then it overwrites the display name and uri from the channel's connected.id. If the connected.id.name wasn't valid, create_new_id_hdr was leaving the display name from the From header in the new RPID or PAI header. On an attended transfer where the originator had a caller id number set but not a display name, the re-INVITE to the final transferee had the number of the originator but the display name of the transferer. Added a check to clear out the display name in the new header if connected.id.name was invalid. ASTERISK-25942 #close Change-Id: I60b4bf7a7ece9b7425eba74151c0b4969cd2738b --- res/res_pjsip_caller_id.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 1818105d7da..283ec94e51e 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -424,6 +424,12 @@ static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_fromt ast_escape_quoted(id->name.str, name_buf, name_buf_len); pj_strdup2(tdata->pool, &id_name_addr->display, name_buf); + } else { + /* + * We need to clear the remnants of the clone or it'll be left set. + * pj_strdup2 is safe to call with a NULL src and it resets both slen and ptr. + */ + pj_strdup2(tdata->pool, &id_name_addr->display, NULL); } pj_strdup2(tdata->pool, &id_uri->user, id->number.str); From 1c5248c3839a3b8f6295d4ed94765bfe0d718ef9 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 19 Apr 2016 16:58:32 -0500 Subject: [PATCH 0364/1578] bridge: Hold off more than one imparting channel at a time. An earlier patch blocked the ast_bridge_impart() call until the channel either entered the target bridge or it failed. Unfortuantely, if the target bridge is stasis and the imprted channel is not a stasis channel, stasis bounces the channel out of the bridge to come back into the bridge as a proper stasis channel. When the channel is bounced out, that released the block on ast_bridge_impart() to continue. If the impart was a result of a transfer, then it became a race to see if the swap channel would get hung up before the imparted channel could come back into the stasis bridge. If the imparted channel won then everything is fine. If the swap channel gets hung up first then the transfer will fail because the swap channel is leaving the bridge. * Allow a chain of ast_bridge_impart()'s to happen before any are unblocked to prevent the race condition described above. When the channel finally joins the bridge or completely fails to join the bridge then the ast_bridge_impart() instances are unblocked. ASTERISK-25947 Reported by: Richard Mudgett ASTERISK-24649 Reported by: John Bigelow ASTERISK-24782 Reported by: John Bigelow Change-Id: I8fef369171f295f580024ab4971e95c799d0dde1 --- include/asterisk/bridge_channel_internal.h | 38 +--- main/bridge.c | 211 ++++++++++++++++++--- main/bridge_channel.c | 26 +-- 3 files changed, 196 insertions(+), 79 deletions(-) diff --git a/include/asterisk/bridge_channel_internal.h b/include/asterisk/bridge_channel_internal.h index 7f7d5a88b14..fb8e781e8fe 100644 --- a/include/asterisk/bridge_channel_internal.h +++ b/include/asterisk/bridge_channel_internal.h @@ -151,47 +151,20 @@ int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel, void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel); /*! - * \brief Internal bridge channel wait condition and associated result. - */ -struct bridge_channel_internal_cond { - /*! Lock for the data structure */ - ast_mutex_t lock; - /*! Wait condition */ - ast_cond_t cond; - /*! Wait until done */ - int done; - /*! The bridge channel */ - struct ast_bridge_channel *bridge_channel; -}; - -/*! - * \internal - * \brief Wait for the expected signal. - * \since 13.5.0 - * - * \param cond the wait object - * - * \return Nothing - */ -void bridge_channel_internal_wait(struct bridge_channel_internal_cond *cond); - -/*! - * \internal - * \brief Signal the condition wait. - * \since 13.5.0 + * \brief Signal imparting threads to wake up. + * \since 13.9.0 * - * \param cond the wait object + * \param chan Channel imparted that we need to signal. * * \return Nothing */ -void bridge_channel_internal_signal(struct bridge_channel_internal_cond *cond); +void bridge_channel_impart_signal(struct ast_channel *chan); /*! * \internal * \brief Join the bridge_channel to the bridge (blocking) * * \param bridge_channel The Channel in the bridge - * \param cond data used for signaling * * \note The bridge_channel->swap holds a channel reference for the swap * channel going into the bridging system. The ref ensures that the swap @@ -206,8 +179,7 @@ void bridge_channel_internal_signal(struct bridge_channel_internal_cond *cond); * \retval 0 bridge channel successfully joined the bridge * \retval -1 bridge channel failed to join the bridge */ -int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, - struct bridge_channel_internal_cond *cond); +int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel); /*! * \internal diff --git a/main/bridge.c b/main/bridge.c index b9a436e86a5..7e72052743b 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -1481,6 +1481,150 @@ void ast_bridge_notify_masquerade(struct ast_channel *chan) ao2_ref(bridge_channel, -1); } +/*! + * \brief Internal bridge impart wait condition and associated conditional. + */ +struct bridge_channel_impart_cond { + AST_LIST_ENTRY(bridge_channel_impart_cond) node; + /*! Lock for the data structure */ + ast_mutex_t lock; + /*! Wait condition */ + ast_cond_t cond; + /*! Wait until done */ + int done; +}; + +AST_LIST_HEAD_NOLOCK(bridge_channel_impart_ds_head, bridge_channel_impart_cond); + +/*! + * \internal + * \brief Signal imparting threads to wake up. + * \since 13.9.0 + * + * \param ds_head List of imparting threads to wake up. + * + * \return Nothing + */ +static void bridge_channel_impart_ds_head_signal(struct bridge_channel_impart_ds_head *ds_head) +{ + if (ds_head) { + struct bridge_channel_impart_cond *cond; + + while ((cond = AST_LIST_REMOVE_HEAD(ds_head, node))) { + ast_mutex_lock(&cond->lock); + cond->done = 1; + ast_cond_signal(&cond->cond); + ast_mutex_unlock(&cond->lock); + } + } +} + +static void bridge_channel_impart_ds_head_dtor(void *doomed) +{ + bridge_channel_impart_ds_head_signal(doomed); + ast_free(doomed); +} + +/*! + * \internal + * \brief Fixup the bridge impart datastore. + * \since 13.9.0 + * + * \param data Bridge impart datastore data to fixup from old_chan. + * \param old_chan The datastore is moving from this channel. + * \param new_chan The datastore is moving to this channel. + * + * \return Nothing + */ +static void bridge_channel_impart_ds_head_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) +{ + /* + * Signal any waiting impart threads. The masquerade is going to kill + * old_chan and we don't need to be waiting on new_chan. + */ + bridge_channel_impart_ds_head_signal(data); +} + +static const struct ast_datastore_info bridge_channel_impart_ds_info = { + .type = "bridge-impart-ds", + .destroy = bridge_channel_impart_ds_head_dtor, + .chan_fixup = bridge_channel_impart_ds_head_fixup, +}; + +/*! + * \internal + * \brief Add impart wait datastore conditional to channel. + * \since 13.9.0 + * + * \param chan Channel to add the impart wait conditional. + * \param cond Imparting conditional to add. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int bridge_channel_impart_add(struct ast_channel *chan, struct bridge_channel_impart_cond *cond) +{ + struct ast_datastore *datastore; + struct bridge_channel_impart_ds_head *ds_head; + + ast_channel_lock(chan); + + datastore = ast_channel_datastore_find(chan, &bridge_channel_impart_ds_info, NULL); + if (!datastore) { + datastore = ast_datastore_alloc(&bridge_channel_impart_ds_info, NULL); + if (!datastore) { + ast_channel_unlock(chan); + return -1; + } + ds_head = ast_calloc(1, sizeof(*ds_head)); + if (!ds_head) { + ast_channel_unlock(chan); + ast_datastore_free(datastore); + return -1; + } + datastore->data = ds_head; + ast_channel_datastore_add(chan, datastore); + } else { + ds_head = datastore->data; + ast_assert(ds_head != NULL); + } + + AST_LIST_INSERT_TAIL(ds_head, cond, node); + + ast_channel_unlock(chan); + return 0; +} + +void bridge_channel_impart_signal(struct ast_channel *chan) +{ + struct ast_datastore *datastore; + + ast_channel_lock(chan); + datastore = ast_channel_datastore_find(chan, &bridge_channel_impart_ds_info, NULL); + if (datastore) { + bridge_channel_impart_ds_head_signal(datastore->data); + } + ast_channel_unlock(chan); +} + +/*! + * \internal + * \brief Block imparting channel thread until signaled. + * \since 13.9.0 + * + * \param cond Imparting conditional to wait for. + * + * \return Nothing + */ +static void bridge_channel_impart_wait(struct bridge_channel_impart_cond *cond) +{ + ast_mutex_lock(&cond->lock); + while (!cond->done) { + ast_cond_wait(&cond->cond, &cond->lock); + } + ast_mutex_unlock(&cond->lock); +} + /* * XXX ASTERISK-21271 make ast_bridge_join() require features to be allocated just like ast_bridge_impart() and not expect the struct back. * @@ -1549,7 +1693,7 @@ int ast_bridge_join(struct ast_bridge *bridge, } if (!res) { - res = bridge_channel_internal_join(bridge_channel, NULL); + res = bridge_channel_internal_join(bridge_channel); } /* Cleanup all the data in the bridge channel after it leaves the bridge. */ @@ -1566,6 +1710,7 @@ int ast_bridge_join(struct ast_bridge *bridge, join_exit:; ast_bridge_run_after_callback(chan); + bridge_channel_impart_signal(chan); if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) && !ast_bridge_setup_after_goto(chan)) { /* Claim the after bridge goto is an async goto destination. */ @@ -1579,14 +1724,13 @@ join_exit:; /*! \brief Thread responsible for imparted bridged channels to be departed */ static void *bridge_channel_depart_thread(void *data) { - struct bridge_channel_internal_cond *cond = data; - struct ast_bridge_channel *bridge_channel = cond->bridge_channel; + struct ast_bridge_channel *bridge_channel = data; if (bridge_channel->callid) { ast_callid_threadassoc_add(bridge_channel->callid); } - bridge_channel_internal_join(bridge_channel, cond); + bridge_channel_internal_join(bridge_channel); /* * cleanup @@ -1599,6 +1743,8 @@ static void *bridge_channel_depart_thread(void *data) bridge_channel->features = NULL; ast_bridge_discard_after_callback(bridge_channel->chan, AST_BRIDGE_AFTER_CB_REASON_DEPART); + /* If join failed there will be impart threads waiting. */ + bridge_channel_impart_signal(bridge_channel->chan); ast_bridge_discard_after_goto(bridge_channel->chan); return NULL; @@ -1607,15 +1753,14 @@ static void *bridge_channel_depart_thread(void *data) /*! \brief Thread responsible for independent imparted bridged channels */ static void *bridge_channel_ind_thread(void *data) { - struct bridge_channel_internal_cond *cond = data; - struct ast_bridge_channel *bridge_channel = cond->bridge_channel; + struct ast_bridge_channel *bridge_channel = data; struct ast_channel *chan; if (bridge_channel->callid) { ast_callid_threadassoc_add(bridge_channel->callid); } - bridge_channel_internal_join(bridge_channel, cond); + bridge_channel_internal_join(bridge_channel); chan = bridge_channel->chan; /* cleanup */ @@ -1632,15 +1777,18 @@ static void *bridge_channel_ind_thread(void *data) ao2_ref(bridge_channel, -1); ast_bridge_run_after_callback(chan); + /* If join failed there will be impart threads waiting. */ + bridge_channel_impart_signal(chan); ast_bridge_run_after_goto(chan); return NULL; } -int ast_bridge_impart(struct ast_bridge *bridge, +static int bridge_impart_internal(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, - enum ast_bridge_impart_flags flags) + enum ast_bridge_impart_flags flags, + struct bridge_channel_impart_cond *cond) { int res = 0; struct ast_bridge_channel *bridge_channel; @@ -1699,27 +1847,20 @@ int ast_bridge_impart(struct ast_bridge *bridge, /* Actually create the thread that will handle the channel */ if (!res) { - struct bridge_channel_internal_cond cond = { - .done = 0, - .bridge_channel = bridge_channel - }; - ast_mutex_init(&cond.lock); - ast_cond_init(&cond.cond, NULL); - + res = bridge_channel_impart_add(chan, cond); + } + if (!res) { if ((flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_INDEPENDENT) { res = ast_pthread_create_detached(&bridge_channel->thread, NULL, - bridge_channel_ind_thread, &cond); + bridge_channel_ind_thread, bridge_channel); } else { res = ast_pthread_create(&bridge_channel->thread, NULL, - bridge_channel_depart_thread, &cond); + bridge_channel_depart_thread, bridge_channel); } if (!res) { - bridge_channel_internal_wait(&cond); + bridge_channel_impart_wait(cond); } - - ast_cond_destroy(&cond.cond); - ast_mutex_destroy(&cond.lock); } if (res) { @@ -1740,6 +1881,32 @@ int ast_bridge_impart(struct ast_bridge *bridge, return 0; } +int ast_bridge_impart(struct ast_bridge *bridge, + struct ast_channel *chan, + struct ast_channel *swap, + struct ast_bridge_features *features, + enum ast_bridge_impart_flags flags) +{ + struct bridge_channel_impart_cond cond = { + .done = 0, + }; + int res; + + ast_mutex_init(&cond.lock); + ast_cond_init(&cond.cond, NULL); + + res = bridge_impart_internal(bridge, chan, swap, features, flags, &cond); + if (res) { + /* Impart failed. Signal any other waiting impart threads */ + bridge_channel_impart_signal(chan); + } + + ast_cond_destroy(&cond.cond); + ast_mutex_destroy(&cond.lock); + + return res; +} + int ast_bridge_depart(struct ast_channel *chan) { struct ast_bridge_channel *bridge_channel; diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 66f26eefeda..db4ecfe57cd 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2637,27 +2637,7 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch ao2_iterator_destroy(&iter); } -void bridge_channel_internal_wait(struct bridge_channel_internal_cond *cond) -{ - ast_mutex_lock(&cond->lock); - while (!cond->done) { - ast_cond_wait(&cond->cond, &cond->lock); - } - ast_mutex_unlock(&cond->lock); -} - -void bridge_channel_internal_signal(struct bridge_channel_internal_cond *cond) -{ - if (cond) { - ast_mutex_lock(&cond->lock); - cond->done = 1; - ast_cond_signal(&cond->cond); - ast_mutex_unlock(&cond->lock); - } -} - -int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, - struct bridge_channel_internal_cond *cond) +int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) { int res = 0; struct ast_bridge_features *channel_features; @@ -2687,7 +2667,6 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, bridge_channel->bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); - bridge_channel_internal_signal(cond); return -1; } ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge); @@ -2722,8 +2701,6 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, } bridge_reconfigured(bridge_channel->bridge, !bridge_channel->inhibit_colp); - bridge_channel_internal_signal(cond); - if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) { /* * Indicate a source change since this channel is entering the @@ -2735,6 +2712,7 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel, ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE); } + bridge_channel_impart_signal(bridge_channel->chan); ast_bridge_unlock(bridge_channel->bridge); /* Must release any swap ref after unlocking the bridge. */ From 6b1a632290567b0d482b57a07fe94ecbca164b7d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 15 Apr 2016 14:36:59 -0500 Subject: [PATCH 0365/1578] res_stasis: Handle re-enter stasis bridge with swap channel. We lose the fact that there is a swap channel if there is one. We currently wind up rejoining the stasis bridge as a normal join after the swap channel has already been kicked from the bridge. This patch preserves the swap channel so the AMI/ARI events can note that the channel joining the bridge is swapping with another channel. Another benefit to swaqpping in one operation is if there are any channels that get lonely (MOH, bridge playback, and bridge record channels). The lonely channels won't leave before the joining channel has a chance to come back in under stasis if the swap channel is the only reason the lonely channels are staying in the bridge. ASTERISK-25947 #close Reported by: Richard Mudgett ASTERISK-24649 Reported by: John Bigelow ASTERISK-24782 Reported by: John Bigelow Change-Id: If37ea508831d1fed6dbfac2f191c638fc0a850ee --- res/stasis/control.c | 12 +++++---- res/stasis/control.h | 18 +++++++++---- res/stasis/stasis_bridge.c | 54 ++++++++++++++++++++++++++++---------- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/res/stasis/control.c b/res/stasis/control.c index 3c5b75041c3..aa6866aee6d 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -903,11 +903,8 @@ static void bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason, ast_bridge_after_cb_reason_string(reason)); } -int control_add_channel_to_bridge( - struct stasis_app_control *control, - struct ast_channel *chan, void *data) +int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap) { - struct ast_bridge *bridge = data; int res; if (!control || !bridge) { @@ -960,7 +957,7 @@ int control_add_channel_to_bridge( res = ast_bridge_impart(bridge, chan, - NULL, /* swap channel */ + swap, NULL, /* features */ AST_BRIDGE_IMPART_CHAN_DEPARTABLE); if (res != 0) { @@ -976,6 +973,11 @@ int control_add_channel_to_bridge( return 0; } +int control_add_channel_to_bridge(struct stasis_app_control *control, struct ast_channel *chan, void *data) +{ + return control_swap_channel_in_bridge(control, data, chan, NULL); +} + int stasis_app_control_add_channel_to_bridge( struct stasis_app_control *control, struct ast_bridge *bridge) { diff --git a/res/stasis/control.h b/res/stasis/control.h index 1d37a494aec..868a8091bb4 100644 --- a/res/stasis/control.h +++ b/res/stasis/control.h @@ -111,12 +111,20 @@ struct stasis_app *control_app(struct stasis_app_control *control); * \brief Command callback for adding a channel to a bridge * * \param control The control for chan - * \param channel The channel on which commands should be executed - * \param bridge Data to be passed to the callback + * \param chan The channel on which commands should be executed + * \param data Bridge to be passed to the callback + */ +int control_add_channel_to_bridge(struct stasis_app_control *control, struct ast_channel *chan, void *data); + +/*! + * \brief Command for swapping a channel in a bridge + * + * \param control The control for chan + * \param chan The channel on which commands should be executed + * \param bridge Bridge to be passed to the callback + * \param swap Channel to swap with when joining the bridge */ -int control_add_channel_to_bridge( - struct stasis_app_control *control, - struct ast_channel *chan, void *obj); +int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap); /*! * \brief Stop playing silence to a channel right now. diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index bfd287226c2..aa21ec29c3a 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -76,24 +76,54 @@ static void bridge_stasis_run_cb(struct ast_channel *chan, void *data) pbx_exec(chan, app_stasis, app_name); } -static int add_channel_to_bridge( +struct defer_bridge_add_obj { + /*! Bridge to join (has ref) */ + struct ast_bridge *bridge; + /*! + * \brief Channel to swap with in the bridge. (has ref) + * + * \note NULL if not swapping with a channel. + */ + struct ast_channel *swap; +}; + +static void defer_bridge_add_dtor(void *obj) +{ + struct defer_bridge_add_obj *defer = obj; + + ao2_cleanup(defer->bridge); + ast_channel_cleanup(defer->swap); +} + +static int defer_bridge_add( struct stasis_app_control *control, struct ast_channel *chan, void *obj) { - struct ast_bridge *bridge = obj; - int res; + struct defer_bridge_add_obj *defer = obj; - res = control_add_channel_to_bridge(control, - chan, bridge); - return res; + return control_swap_channel_in_bridge(control, defer->bridge, chan, defer->swap); } static void bridge_stasis_queue_join_action(struct ast_bridge *self, - struct ast_bridge_channel *bridge_channel) + struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) { + struct defer_bridge_add_obj *defer; + + defer = ao2_alloc_options(sizeof(*defer), defer_bridge_add_dtor, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!defer) { + return; + } + ao2_ref(self, +1); + defer->bridge = self; + if (swap) { + ast_channel_ref(swap->chan); + defer->swap = swap->chan; + } + ast_channel_lock(bridge_channel->chan); - command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge, - ao2_bump(self), __ao2_cleanup); + command_prestart_queue_command(bridge_channel->chan, defer_bridge_add, + defer, __ao2_cleanup); ast_channel_unlock(bridge_channel->chan); } @@ -179,11 +209,7 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel return -1; } - bridge_stasis_queue_join_action(self, bridge_channel); - if (swap) { - /* nudge the swap channel out of the bridge */ - ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0); - } + bridge_stasis_queue_join_action(self, bridge_channel, swap); /* Return -1 so the push fails and the after-bridge callback gets called * This keeps the bridging framework from putting the channel into the bridge From c991e5472ef23db6b02abb2f54f53235f9b5ecbe Mon Sep 17 00:00:00 2001 From: Diederik de Groot Date: Thu, 21 Apr 2016 15:26:47 +0200 Subject: [PATCH 0366/1578] lock.c: Check *lt before dereferencing it *lt is NULL if t->tracking == 0 ASTERISK-25948 #close Change-Id: I4a81af28f9c82a74aa82413d772a7dc8fa6f45ba --- main/lock.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/main/lock.c b/main/lock.c index 13b8fb388e1..2b2a80984c4 100644 --- a/main/lock.c +++ b/main/lock.c @@ -286,17 +286,19 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, if (wait_time > reported_wait && (wait_time % 5) == 0) { __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n", filename, lineno, func, (int) wait_time, mutex_name); - ast_reentrancy_lock(lt); + if (lt) { + ast_reentrancy_lock(lt); #ifdef HAVE_BKTR - __dump_backtrace(<->backtrace[lt->reentrancy], canlog); + __dump_backtrace(<->backtrace[lt->reentrancy], canlog); #endif - __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", - lt->file[ROFFSET], lt->lineno[ROFFSET], - lt->func[ROFFSET], mutex_name); + __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", + lt->file[ROFFSET], lt->lineno[ROFFSET], + lt->func[ROFFSET], mutex_name); #ifdef HAVE_BKTR - __dump_backtrace(<->backtrace[ROFFSET], canlog); + __dump_backtrace(<->backtrace[ROFFSET], canlog); #endif - ast_reentrancy_unlock(lt); + ast_reentrancy_unlock(lt); + } reported_wait = wait_time; } usleep(200); From 6ede210c98210e465fe9b5b12ca2ef295ab5dc2c Mon Sep 17 00:00:00 2001 From: Leif Madsen Date: Fri, 22 Apr 2016 14:02:53 -0400 Subject: [PATCH 0367/1578] Remove reference to non-existent sip.conf option Option was removed in commit 7f883ef495b57ae9182e47213d01d5e8009dbf3f ASTERISK-25927 #close Change-Id: I92f9b0196d9fc41d1d58354c07340c465ef1fcf8 --- configs/samples/sip.conf.sample | 1 - 1 file changed, 1 deletion(-) diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample index d89a2a15735..8f28e26801a 100644 --- a/configs/samples/sip.conf.sample +++ b/configs/samples/sip.conf.sample @@ -1509,7 +1509,6 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;allow=ulaw ;allow=alaw ;mailbox=1234@default,1233@default ; Subscribe to status of multiple mailboxes -;registertrying=yes ; Send a 100 Trying when the device registers. ;[snom] ;type=friend ; Friends place calls and receive calls From 924738e950861c485d707fc5539e50bbf77b7202 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 22 Apr 2016 13:49:50 -0500 Subject: [PATCH 0368/1578] func_odbc: Use one connection per DSN. res_odbc was changed in Asterisk 13.8.0 to remove connection management, opting instead to let unixodbc maintain open connections and return those to Asterisk as requested. This was a boon for realtime, since it meant that multiple threads could potentially run parallel queries since they could each be using their own database connections. However, on the user-facing side, func_odbc, there were some inherent behaviors being relied on that no longer hold true after the change. One such reported behavior was that MySQL's LAST_INSERTED_ID() works per-connection. This means that if Asterisk uses separate connections for every database operation, whereas before it used one connection for everything, we have broken expectations and functionality. The fix provided in this patch is to make func_odbc use a single database connection per DSN. This way, user-facing database usage will have the same behavior as it did pre-13.8.0. However, realtime, which is the real workhorse of database interaction, will continue to let unixodbc manage connections. ASTERISK-25938 #close Reported by Edwin Vandamme Change-Id: Iac961fe79154c6211569afcdfec843c0c24c46dc --- funcs/func_odbc.c | 314 +++++++++++++++++++++++++++++++++------------- 1 file changed, 229 insertions(+), 85 deletions(-) diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 23930ed4d8b..ca15d703fc4 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -137,6 +137,163 @@ struct odbc_datastore { char names[0]; }; +/* \brief Data source name + * + * This holds data that pertains to a DSN + */ +struct dsn { + /*! A connection to the database */ + struct odbc_obj *connection; + /*! The name of the DSN as defined in res_odbc.conf */ + char name[0]; +}; + +#define DSN_BUCKETS 37 + +struct ao2_container *dsns; + +static int dsn_hash(const void *obj, const int flags) +{ + const struct dsn *object; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + object = obj; + key = object->name; + break; + default: + ast_assert(0); + return 0; + } + return ast_str_hash(key); +} + +static int dsn_cmp(void *obj, void *arg, int flags) +{ + const struct dsn *object_left = obj; + const struct dsn *object_right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->name; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(object_left->name, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncmp(object_left->name, right_key, strlen(right_key)); + break; + default: + cmp = 0; + break; + } + + if (cmp) { + return 0; + } + + return CMP_MATCH; +} + +static void dsn_destructor(void *obj) +{ + struct dsn *dsn = obj; + + if (dsn->connection) { + ast_odbc_release_obj(dsn->connection); + } +} + +/*! + * \brief Create a DSN and connect to the database + * + * \param name The name of the DSN as found in res_odbc.conf + * \retval NULL Fail + * \retval non-NULL The newly-created structure + */ +static struct dsn *create_dsn(const char *name) +{ + struct dsn *dsn; + + dsn = ao2_alloc(sizeof(*dsn) + strlen(name) + 1, dsn_destructor); + if (!dsn) { + return NULL; + } + + /* Safe */ + strcpy(dsn->name, name); + + dsn->connection = ast_odbc_request_obj(name, 0); + if (!dsn->connection) { + ao2_ref(dsn, -1); + return NULL; + } + + if (!ao2_link_flags(dsns, dsn, OBJ_NOLOCK)) { + ao2_ref(dsn, -1); + return NULL; + } + + return dsn; +} + +/*! + * \brief Retrieve a DSN, or create it if it does not exist. + * + * The created DSN is returned locked. This should be inconsequential + * to callers in most cases. + * + * When finished with the returned structure, the caller must call + * \ref release_dsn + * + * \param name Name of the DSN as found in res_odbc.conf + * \retval NULL Unable to retrieve or create the DSN + * \retval non-NULL The retrieved/created locked DSN + */ +static struct dsn *get_dsn(const char *name) +{ + struct dsn *dsn; + + ao2_lock(dsns); + dsn = ao2_find(dsns, name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (!dsn) { + dsn = create_dsn(name); + } + ao2_unlock(dsns); + + if (!dsn) { + return NULL; + } + + ao2_lock(dsn->connection); + + return dsn; +} + +/*! + * \brief Unlock and unreference a DSN + * + * \param dsn The dsn to unlock and unreference + * \return NULL + */ +static void *release_dsn(struct dsn *dsn) +{ + if (!dsn) { + return NULL; + } + + ao2_unlock(dsn->connection); + ao2_ref(dsn, -1); + + return NULL; +} + static AST_RWLIST_HEAD_STATIC(queries, acf_odbc_query); static int resultcount = 0; @@ -214,7 +371,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co struct odbc_obj *obj = NULL; struct acf_odbc_query *query; char *t, varname[15]; - int i, dsn, bogus_chan = 0; + int i, dsn_num, bogus_chan = 0; int transactional = 0; AST_DECLARE_APP_ARGS(values, AST_APP_ARG(field)[100]; @@ -227,6 +384,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co struct ast_str *buf = ast_str_thread_get(&sql_buf, 16); struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16); const char *status = "FAILURE"; + struct dsn *dsn = NULL; if (!buf || !insertbuf) { return -1; @@ -324,17 +482,21 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co * to multiple DSNs. We MUST have a single handle all the way through the * transaction, or else we CANNOT enforce atomicity. */ - for (dsn = 0; dsn < 5; dsn++) { - if (!ast_strlen_zero(query->writehandle[dsn])) { + for (dsn_num = 0; dsn_num < 5; dsn_num++) { + if (!ast_strlen_zero(query->writehandle[dsn_num])) { if (transactional) { /* This can only happen second time through or greater. */ ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n"); } - if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) { + if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) { transactional = 1; } else { - obj = ast_odbc_request_obj(query->writehandle[dsn], 0); + dsn = get_dsn(query->writehandle[dsn_num]); + if (!dsn) { + continue; + } + obj = dsn->connection; transactional = 0; } @@ -342,10 +504,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co break; } - if (obj && !transactional) { - ast_odbc_release_obj(obj); - obj = NULL; - } + dsn = release_dsn(dsn); } } @@ -358,25 +517,25 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co status = "SUCCESS"; } else if (query->sql_insert) { - if (obj && !transactional) { - ast_odbc_release_obj(obj); - obj = NULL; - } + dsn = release_dsn(dsn); - for (transactional = 0, dsn = 0; dsn < 5; dsn++) { - if (!ast_strlen_zero(query->writehandle[dsn])) { + for (transactional = 0, dsn_num = 0; dsn_num < 5; dsn_num++) { + if (!ast_strlen_zero(query->writehandle[dsn_num])) { if (transactional) { /* This can only happen second time through or greater. */ ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n"); } else if (obj) { - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); } - if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) { + if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) { transactional = 1; } else { - obj = ast_odbc_request_obj(query->writehandle[dsn], 0); + dsn = get_dsn(query->writehandle[dsn_num]); + if (!dsn) { + continue; + } + obj = dsn->connection; transactional = 0; } if (obj) { @@ -406,10 +565,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); } - if (obj && !transactional) { - ast_odbc_release_obj(obj); - obj = NULL; - } + dsn = release_dsn(dsn); if (!bogus_chan) { ast_autoservice_stop(chan); @@ -420,11 +576,10 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len) { - struct odbc_obj *obj = NULL; struct acf_odbc_query *query; char varname[15], rowcount[12] = "-1"; struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16); - int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn, bogus_chan = 0; + int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn_num, bogus_chan = 0; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(field)[100]; ); @@ -436,6 +591,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha struct odbc_datastore_row *row = NULL; struct ast_str *sql = ast_str_thread_get(&sql_buf, 16); const char *status = "FAILURE"; + struct dsn *dsn = NULL; if (!sql || !colnames) { if (chan) { @@ -523,28 +679,23 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha } AST_RWLIST_UNLOCK(&queries); - for (dsn = 0; dsn < 5; dsn++) { - if (!ast_strlen_zero(query->readhandle[dsn])) { - obj = ast_odbc_request_obj(query->readhandle[dsn], 0); - if (obj) { - stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)); + for (dsn_num = 0; dsn_num < 5; dsn_num++) { + if (!ast_strlen_zero(query->readhandle[dsn_num])) { + dsn = get_dsn(query->readhandle[dsn_num]); + if (!dsn) { + continue; } + stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)); } if (stmt) { break; } - if (obj) { - ast_odbc_release_obj(obj); - obj = NULL; - } + dsn = release_dsn(dsn); } if (!stmt) { ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql)); - if (obj) { - ast_odbc_release_obj(obj); - obj = NULL; - } + dsn = release_dsn(dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); ast_autoservice_stop(chan); @@ -558,8 +709,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); SQLCloseCursor(stmt); SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); ast_autoservice_stop(chan); @@ -583,8 +733,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha } SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); @@ -607,8 +756,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); ast_autoservice_stop(chan); @@ -640,8 +788,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); @@ -750,8 +897,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); ast_autoservice_stop(chan); return -1; @@ -764,8 +910,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha } SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); if (resultset && !multirow) { /* Fetch the first resultset */ if (!acf_fetch(chan, "", buf, buf, len)) { @@ -1192,8 +1337,8 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args if (a->argc == 5 && !strcmp(a->argv[4], "exec")) { /* Execute the query */ - struct odbc_obj *obj = NULL; - int dsn, executed = 0; + struct dsn *dsn = NULL; + int dsn_num, executed = 0; SQLHSTMT stmt; int rows = 0, res, x; SQLSMALLINT colcount = 0, collength; @@ -1207,19 +1352,18 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args return CLI_SUCCESS; } - for (dsn = 0; dsn < 5; dsn++) { - if (ast_strlen_zero(query->readhandle[dsn])) { + for (dsn_num = 0; dsn_num < 5; dsn_num++) { + if (ast_strlen_zero(query->readhandle[dsn_num])) { continue; } - ast_debug(1, "Found handle %s\n", query->readhandle[dsn]); - if (!(obj = ast_odbc_request_obj(query->readhandle[dsn], 0))) { + dsn = get_dsn(query->readhandle[dsn_num]); + if (!dsn) { continue; } + ast_debug(1, "Found handle %s\n", query->readhandle[dsn_num]); - ast_debug(1, "Got obj\n"); - if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { - ast_odbc_release_obj(obj); - obj = NULL; + if (!(stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)))) { + dsn = release_dsn(dsn); continue; } @@ -1230,8 +1374,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); SQLCloseCursor(stmt); SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); AST_RWLIST_UNLOCK(&queries); return CLI_SUCCESS; } @@ -1240,10 +1383,9 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); if (res == SQL_NO_DATA) { - ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql)); + ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn_num, query->readhandle[dsn_num], ast_str_buffer(sql)); break; } else { ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql)); @@ -1270,8 +1412,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql)); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; + dsn = release_dsn(dsn); AST_RWLIST_UNLOCK(&queries); return CLI_SUCCESS; } @@ -1289,15 +1430,11 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args } SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; - ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn, query->readhandle[dsn]); + dsn = release_dsn(dsn); + ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn_num, query->readhandle[dsn_num]); break; } - if (obj) { - ast_odbc_release_obj(obj); - obj = NULL; - } + dsn = release_dsn(dsn); if (!executed) { ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql)); @@ -1420,30 +1557,29 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg if (a->argc == 6 && !strcmp(a->argv[5], "exec")) { /* Execute the query */ - struct odbc_obj *obj = NULL; - int dsn, executed = 0; + struct dsn *dsn; + int dsn_num, executed = 0; SQLHSTMT stmt; SQLLEN rows = -1; - for (dsn = 0; dsn < 5; dsn++) { - if (ast_strlen_zero(query->writehandle[dsn])) { + for (dsn_num = 0; dsn_num < 5; dsn_num++) { + if (ast_strlen_zero(query->writehandle[dsn_num])) { continue; } - if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) { + dsn = get_dsn(query->writehandle[dsn_num]); + if (!dsn) { continue; } - if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { - ast_odbc_release_obj(obj); - obj = NULL; + if (!(stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)))) { + dsn = release_dsn(dsn); continue; } SQLRowCount(stmt, &rows); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - obj = NULL; - ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn, query->writehandle[dsn]); + dsn = release_dsn(dsn); + ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn_num, query->writehandle[dsn_num]); executed = 1; break; } @@ -1470,6 +1606,11 @@ static int load_module(void) char *catg; struct ast_flags config_flags = { 0 }; + dsns = ao2_container_alloc(DSN_BUCKETS, dsn_hash, dsn_cmp); + if (!dsns) { + return AST_MODULE_LOAD_DECLINE; + } + res |= ast_custom_function_register(&fetch_function); res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish); AST_RWLIST_WRLOCK(&queries); @@ -1478,6 +1619,7 @@ static int load_module(void) if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); AST_RWLIST_UNLOCK(&queries); + ao2_ref(dsns, -1); return AST_MODULE_LOAD_DECLINE; } @@ -1531,6 +1673,8 @@ static int unload_module(void) AST_RWLIST_WRLOCK(&queries); AST_RWLIST_UNLOCK(&queries); + + ao2_ref(dsns, -1); return res; } From 6ddd856b866ca248a8e7aeaaf17c59469a6e1848 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Apr 2016 17:54:26 -0500 Subject: [PATCH 0369/1578] manager.c: Eliminate most RAII_VAR usage. * Made ast_manager_event_blob_create() not allocate the ao2 event object with a lock as it is not needed. Change-Id: I8e11bfedd22c21316012e0b9dd79f5918f644b7c --- main/manager.c | 74 +++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/main/manager.c b/main/manager.c index 74e95333305..0cef582800c 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1690,17 +1690,17 @@ struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_excl static void manager_default_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup); + struct ast_manager_event_blob *ev; ev = stasis_message_to_ami(message); - - if (ev == NULL) { - /* Not and AMI message; disregard */ + if (!ev) { + /* Not an AMI message; disregard */ return; } manager_event(ev->event_flags, ev->manager_event, "%s", ev->extra_fields); + ao2_ref(ev, -1); } static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, @@ -1710,7 +1710,7 @@ static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, int class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type")); const char *type = ast_json_string_get(ast_json_object_get(payload->json, "type")); struct ast_json *event = ast_json_object_get(payload->json, "event"); - RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free); + struct ast_str *event_buffer; event_buffer = ast_manager_str_from_json_object(event, NULL); if (!event_buffer) { @@ -1718,6 +1718,7 @@ static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, return; } manager_event(class_type, type, "%s", ast_str_buffer(event_buffer)); + ast_free(event_buffer); } void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj) @@ -4716,7 +4717,7 @@ static int action_blind_transfer(struct mansession *s, const struct message *m) const char *name = astman_get_header(m, "Channel"); const char *exten = astman_get_header(m, "Exten"); const char *context = astman_get_header(m, "Context"); - RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup); + struct ast_channel *chan; if (ast_strlen_zero(name)) { astman_send_error(s, m, "No channel specified"); @@ -4753,6 +4754,7 @@ static int action_blind_transfer(struct mansession *s, const struct message *m) break; } + ast_channel_unref(chan); return 0; } @@ -5931,7 +5933,7 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m const char *actionid = astman_get_header(m, "ActionID"); char idText[256]; int numchans = 0; - RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup); + struct ao2_container *channels; struct ao2_iterator it_chans; struct stasis_message *msg; @@ -5941,7 +5943,8 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m idText[0] = '\0'; } - if (!(channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()))) { + channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()); + if (!channels) { astman_send_error(s, m, "Could not get cached channels"); return 0; } @@ -5993,6 +5996,7 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m astman_send_list_complete_start(s, m, "CoreShowChannelsComplete", numchans); astman_send_list_complete_end(s); + ao2_ref(channels, -1); return 0; } @@ -6623,11 +6627,10 @@ static int append_event(const char *str, int category) static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan) { - RAII_VAR(struct varshead *, vars, NULL, ao2_cleanup); + struct varshead *vars; struct ast_var_t *var; vars = ast_channel_get_manager_vars(chan); - if (!vars) { return; } @@ -6635,6 +6638,7 @@ static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan) AST_LIST_TRAVERSE(vars, var, entries) { ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, var->value); } + ao2_ref(vars, -1); } /* XXX see if can be moved inside the function */ @@ -6646,8 +6650,6 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount const char *fmt, ...) { RAII_VAR(struct ao2_container *, sessions, ao2_global_obj_ref(mgr_sessions), ao2_cleanup); - struct mansession_session *session; - struct manager_custom_hook *hook; struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING); const char *cat_str; va_list ap; @@ -6659,33 +6661,39 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount return 0; } - if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) { + buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE); + if (!buf) { return -1; } cat_str = authority_to_str(category, &auth); ast_str_set(&buf, 0, - "Event: %s\r\nPrivilege: %s\r\n", - event, cat_str); + "Event: %s\r\n" + "Privilege: %s\r\n", + event, cat_str); if (timestampevents) { now = ast_tvnow(); ast_str_append(&buf, 0, - "Timestamp: %ld.%06lu\r\n", - (long)now.tv_sec, (unsigned long) now.tv_usec); + "Timestamp: %ld.%06lu\r\n", + (long)now.tv_sec, (unsigned long) now.tv_usec); } if (manager_debug) { static int seq; + ast_str_append(&buf, 0, - "SequenceNumber: %d\r\n", - ast_atomic_fetchadd_int(&seq, 1)); + "SequenceNumber: %d\r\n", + ast_atomic_fetchadd_int(&seq, 1)); ast_str_append(&buf, 0, - "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func); + "File: %s\r\n" + "Line: %d\r\n" + "Func: %s\r\n", + file, line, func); } if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_str_append(&buf, 0, - "SystemName: %s\r\n", - ast_config_AST_SYSTEM_NAME); + "SystemName: %s\r\n", + ast_config_AST_SYSTEM_NAME); } va_start(ap, fmt); @@ -6701,9 +6709,11 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount /* Wake up any sleeping sessions */ if (sessions) { - struct ao2_iterator i; - i = ao2_iterator_init(sessions, 0); - while ((session = ao2_iterator_next(&i))) { + struct ao2_iterator iter; + struct mansession_session *session; + + iter = ao2_iterator_init(sessions, 0); + while ((session = ao2_iterator_next(&iter))) { ao2_lock(session); if (session->waiting_thread != AST_PTHREADT_NULL) { pthread_kill(session->waiting_thread, SIGURG); @@ -6718,10 +6728,12 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount ao2_unlock(session); unref_mansession(session); } - ao2_iterator_destroy(&i); + ao2_iterator_destroy(&iter); } if (category != EVENT_FLAG_SHUTDOWN && !AST_RWLIST_EMPTY(&manager_hooks)) { + struct manager_custom_hook *hook; + AST_RWLIST_RDLOCK(&manager_hooks); AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) { hook->helper(category, event, ast_str_buffer(buf)); @@ -9217,6 +9229,7 @@ int ast_str_append_event_header(struct ast_str **fields_string, static void manager_event_blob_dtor(void *obj) { struct ast_manager_event_blob *ev = obj; + ast_string_field_free_memory(ev); } @@ -9228,18 +9241,19 @@ ast_manager_event_blob_create( const char *extra_fields_fmt, ...) { - RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup); + struct ast_manager_event_blob *ev; va_list argp; ast_assert(extra_fields_fmt != NULL); ast_assert(manager_event != NULL); - ev = ao2_alloc(sizeof(*ev), manager_event_blob_dtor); + ev = ao2_alloc_options(sizeof(*ev), manager_event_blob_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!ev) { return NULL; } if (ast_string_field_init(ev, 20)) { + ao2_ref(ev, -1); return NULL; } @@ -9247,10 +9261,8 @@ ast_manager_event_blob_create( ev->event_flags = event_flags; va_start(argp, extra_fields_fmt); - ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, - argp); + ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, argp); va_end(argp); - ao2_ref(ev, +1); return ev; } From 06632a0d11ff328a43a8fa6864d5e3a1523859d1 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 12 Apr 2016 15:29:52 -0500 Subject: [PATCH 0370/1578] Manager: Short circuit AMI message processing. Improve AMI message processing performance if there are no consumers listening for the messages. We now skip creating the AMI event message text strings. Change-Id: I7b22fc5ec4e500d00635c1a467aa8ea68a1bb2b3 --- include/asterisk/stasis.h | 24 ++++--- main/manager.c | 130 ++++++++++++++++++++++++++++++++------ main/stasis_message.c | 35 +++++++--- 3 files changed, 152 insertions(+), 37 deletions(-) diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h index 69b2d0f2267..14ab7d93b24 100644 --- a/include/asterisk/stasis.h +++ b/include/asterisk/stasis.h @@ -414,14 +414,14 @@ const struct timeval *stasis_message_timestamp(const struct stasis_message *msg) * May return \c NULL, to indicate no representation. The returned object should * be ast_json_unref()'ed. * - * \param message Message to convert to JSON string. + * \param msg Message to convert to JSON string. * \param sanitize Snapshot sanitization callback. * * \return Newly allocated string with JSON message. * \return \c NULL on error. * \return \c NULL if JSON format is not supported. */ -struct ast_json *stasis_message_to_json(struct stasis_message *message, struct stasis_message_sanitizer *sanitize); +struct ast_json *stasis_message_to_json(struct stasis_message *msg, struct stasis_message_sanitizer *sanitize); /*! * \brief Build the AMI representation of the message. @@ -429,12 +429,21 @@ struct ast_json *stasis_message_to_json(struct stasis_message *message, struct s * May return \c NULL, to indicate no representation. The returned object should * be ao2_cleanup()'ed. * - * \param message Message to convert to AMI. + * \param msg Message to convert to AMI. * \return \c NULL on error. * \return \c NULL if AMI format is not supported. */ -struct ast_manager_event_blob *stasis_message_to_ami( - struct stasis_message *message); +struct ast_manager_event_blob *stasis_message_to_ami(struct stasis_message *msg); + +/*! + * \brief Determine if the given message can be converted to AMI. + * + * \param msg Message to see if can be converted to AMI. + * + * \retval 0 Cannot be converted + * \retval non-zero Can be converted + */ +int stasis_message_can_be_ami(struct stasis_message *msg); /*! * \brief Build the \ref AstGenericEvents representation of the message. @@ -442,12 +451,11 @@ struct ast_manager_event_blob *stasis_message_to_ami( * May return \c NULL, to indicate no representation. The returned object should * be disposed of via \ref ast_event_destroy. * - * \param message Message to convert to AMI. + * \param msg Message to convert to AMI. * \return \c NULL on error. * \return \c NULL if AMI format is not supported. */ -struct ast_event *stasis_message_to_event( - struct stasis_message *message); +struct ast_event *stasis_message_to_event(struct stasis_message *msg); /*! * \brief A topic to which messages may be posted, and subscribers, well, subscribe diff --git a/main/manager.c b/main/manager.c index 0cef582800c..d2fdc403dbc 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1549,6 +1549,17 @@ static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook); /*! \brief A container of event documentation nodes */ static AO2_GLOBAL_OBJ_STATIC(event_docs); +static int __attribute__((format(printf, 9, 0))) __manager_event_sessions( + struct ao2_container *sessions, + int category, + const char *event, + int chancount, + struct ast_channel **chans, + const char *file, + int line, + const char *func, + const char *fmt, + ...); static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters); static int match_filter(struct mansession *s, char *eventdata); @@ -1687,38 +1698,75 @@ struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_excl return res; } +#define manager_event_sessions(sessions, category, event, contents , ...) \ + __manager_event_sessions(sessions, category, event, 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__) + +#define any_manager_listeners(sessions) \ + ((sessions && ao2_container_count(sessions)) || !AST_RWLIST_EMPTY(&manager_hooks)) + static void manager_default_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { + struct ao2_container *sessions; struct ast_manager_event_blob *ev; + if (!stasis_message_can_be_ami(message)) { + /* Not an AMI message; disregard */ + return; + } + + sessions = ao2_global_obj_ref(mgr_sessions); + if (!any_manager_listeners(sessions)) { + /* Nobody is listening */ + ao2_cleanup(sessions); + return; + } + ev = stasis_message_to_ami(message); if (!ev) { - /* Not an AMI message; disregard */ + /* Conversion failure */ + ao2_cleanup(sessions); return; } - manager_event(ev->event_flags, ev->manager_event, "%s", - ev->extra_fields); + manager_event_sessions(sessions, ev->event_flags, ev->manager_event, + "%s", ev->extra_fields); ao2_ref(ev, -1); + ao2_cleanup(sessions); } static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - struct ast_json_payload *payload = stasis_message_data(message); - int class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type")); - const char *type = ast_json_string_get(ast_json_object_get(payload->json, "type")); - struct ast_json *event = ast_json_object_get(payload->json, "event"); + struct ast_json_payload *payload; + int class_type; + const char *type; + struct ast_json *event; struct ast_str *event_buffer; + struct ao2_container *sessions; + + sessions = ao2_global_obj_ref(mgr_sessions); + if (!any_manager_listeners(sessions)) { + /* Nobody is listening */ + ao2_cleanup(sessions); + return; + } + + payload = stasis_message_data(message); + class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type")); + type = ast_json_string_get(ast_json_object_get(payload->json, "type")); + event = ast_json_object_get(payload->json, "event"); event_buffer = ast_manager_str_from_json_object(event, NULL); if (!event_buffer) { ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type); + ao2_cleanup(sessions); return; } - manager_event(class_type, type, "%s", ast_str_buffer(event_buffer)); + manager_event_sessions(sessions, class_type, type, + "%s", ast_str_buffer(event_buffer)); ast_free(event_buffer); + ao2_cleanup(sessions); } void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj) @@ -6645,22 +6693,24 @@ static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan) AST_THREADSTORAGE(manager_event_buf); #define MANAGER_EVENT_BUF_INITSIZE 256 -int __ast_manager_event_multichan(int category, const char *event, int chancount, - struct ast_channel **chans, const char *file, int line, const char *func, - const char *fmt, ...) +static int __attribute__((format(printf, 9, 0))) __manager_event_sessions_va( + struct ao2_container *sessions, + int category, + const char *event, + int chancount, + struct ast_channel **chans, + const char *file, + int line, + const char *func, + const char *fmt, + va_list ap) { - RAII_VAR(struct ao2_container *, sessions, ao2_global_obj_ref(mgr_sessions), ao2_cleanup); struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING); const char *cat_str; - va_list ap; struct timeval now; struct ast_str *buf; int i; - if (!(sessions && ao2_container_count(sessions)) && AST_RWLIST_EMPTY(&manager_hooks)) { - return 0; - } - buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE); if (!buf) { return -1; @@ -6696,9 +6746,7 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount ast_config_AST_SYSTEM_NAME); } - va_start(ap, fmt); ast_str_append_va(&buf, 0, fmt, ap); - va_end(ap); for (i = 0; i < chancount; i++) { append_channel_vars(&buf, chans[i]); } @@ -6744,6 +6792,50 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount return 0; } +static int __attribute__((format(printf, 9, 0))) __manager_event_sessions( + struct ao2_container *sessions, + int category, + const char *event, + int chancount, + struct ast_channel **chans, + const char *file, + int line, + const char *func, + const char *fmt, + ...) +{ + va_list ap; + int res; + + va_start(ap, fmt); + res = __manager_event_sessions_va(sessions, category, event, chancount, chans, + file, line, func, fmt, ap); + va_end(ap); + return res; +} + +int __ast_manager_event_multichan(int category, const char *event, int chancount, + struct ast_channel **chans, const char *file, int line, const char *func, + const char *fmt, ...) +{ + struct ao2_container *sessions = ao2_global_obj_ref(mgr_sessions); + va_list ap; + int res; + + if (!any_manager_listeners(sessions)) { + /* Nobody is listening */ + ao2_cleanup(sessions); + return 0; + } + + va_start(ap, fmt); + res = __manager_event_sessions_va(sessions, category, event, chancount, chans, + file, line, func, fmt, ap); + va_end(ap); + ao2_cleanup(sessions); + return res; +} + /*! \brief * support functions to register/unregister AMI action handlers, */ diff --git a/main/stasis_message.c b/main/stasis_message.c index 0e6ff920462..37b9a2b6ff5 100644 --- a/main/stasis_message.c +++ b/main/stasis_message.c @@ -170,17 +170,17 @@ const struct timeval *stasis_message_timestamp(const struct stasis_message *msg) return &msg->timestamp; } -#define INVOKE_VIRTUAL(fn, ...) \ - ({ \ - if (msg == NULL) { \ - return NULL; \ - } \ - ast_assert(msg->type != NULL); \ +#define INVOKE_VIRTUAL(fn, ...) \ + ({ \ + if (!msg) { \ + return NULL; \ + } \ + ast_assert(msg->type != NULL); \ ast_assert(msg->type->vtable != NULL); \ - if (msg->type->vtable->fn == NULL) { \ - return NULL; \ - } \ - msg->type->vtable->fn(__VA_ARGS__); \ + if (!msg->type->vtable->fn) { \ + return NULL; \ + } \ + msg->type->vtable->fn(__VA_ARGS__); \ }) struct ast_manager_event_blob *stasis_message_to_ami(struct stasis_message *msg) @@ -199,3 +199,18 @@ struct ast_event *stasis_message_to_event(struct stasis_message *msg) { return INVOKE_VIRTUAL(to_event, msg); } + +#define HAS_VIRTUAL(fn, msg) \ + ({ \ + if (!msg) { \ + return 0; \ + } \ + ast_assert(msg->type != NULL); \ + ast_assert(msg->type->vtable != NULL); \ + !!msg->type->vtable->fn; \ + }) + +int stasis_message_can_be_ami(struct stasis_message *msg) +{ + return HAS_VIRTUAL(to_ami, msg); +} From 71dfa355403e41850fd7c4cb4228626e5d9476b9 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Apr 2016 13:20:23 -0500 Subject: [PATCH 0371/1578] bridge_softmix.c: Fix crash if channel fails to join mixing tech. softmix_bridge_join() failed because of an allocation failure. To address this, the softmix bridge technology now checks if the channel failed to join softmix successfully. In addition, the bridge now begins the process of kicking the channel out of the bridge so we don't have channels partially in the bridge for very long. * Fix the test_channel_feature_hooks.c unit tests. The test channel must have a valid codec to join the simple_bridge technology. This patch makes joining a bridge more strict by not allowing partially joined channels to remain in the bridge. Change-Id: I97e2ade6a2bcd1214f24fb839fda948825b61a2b --- bridges/bridge_softmix.c | 13 +++++++++++-- include/asterisk/bridge_technology.h | 3 +++ main/bridge.c | 4 +++- tests/test_channel_feature_hooks.c | 15 +++++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index bad3e43c442..0991e289700 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -359,6 +359,9 @@ static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_ch struct ast_format *slin_format; int setup_fail; + /* The callers have already ensured that sc is never NULL. */ + ast_assert(sc != NULL); + slin_format = ast_format_cache_get_slin_by_rate(rate); ast_mutex_lock(&sc->lock); @@ -714,7 +717,7 @@ static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_cha { int res = 0; - if (!bridge->tech_pvt || (bridge_channel && !bridge_channel->tech_pvt)) { + if (!bridge->tech_pvt || !bridge_channel || !bridge_channel->tech_pvt) { /* "Accept" the frame and discard it. */ return 0; } @@ -984,6 +987,11 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { struct softmix_channel *sc = bridge_channel->tech_pvt; + if (!sc) { + /* This channel failed to join successfully. */ + continue; + } + /* Update the sample rate to match the bridge's native sample rate if necessary. */ if (update_all_rates) { set_softmix_bridge_data(softmix_data->internal_rate, softmix_data->internal_mixing_interval, bridge_channel, 1); @@ -1019,7 +1027,8 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { struct softmix_channel *sc = bridge_channel->tech_pvt; - if (bridge_channel->suspended) { + if (!sc || bridge_channel->suspended) { + /* This channel failed to join successfully or is suspended. */ continue; } diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridge_technology.h index b83a51b69d2..8df19d9e97e 100644 --- a/include/asterisk/bridge_technology.h +++ b/include/asterisk/bridge_technology.h @@ -107,6 +107,9 @@ struct ast_bridge_technology { * \retval -1 on failure * * \note On entry, bridge is already locked. + * + * \note The bridge technology must tollerate a failed to join channel + * until it can be kicked from the bridge. */ int (*join)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); /*! diff --git a/main/bridge.c b/main/bridge.c index b9a436e86a5..a56555bc9fa 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -420,10 +420,12 @@ static void bridge_channel_complete_join(struct ast_bridge *bridge, struct ast_b bridge->technology->name); if (bridge->technology->join && bridge->technology->join(bridge, bridge_channel)) { - ast_debug(1, "Bridge %s: %p(%s) failed to join %s technology\n", + /* We cannot leave the channel partially in the bridge so we must kick it out */ + ast_debug(1, "Bridge %s: %p(%s) failed to join %s technology (Kicking it out)\n", bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan), bridge->technology->name); bridge_channel->just_joined = 1; + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0); return; } diff --git a/tests/test_channel_feature_hooks.c b/tests/test_channel_feature_hooks.c index ad726882253..94037e2fa50 100644 --- a/tests/test_channel_feature_hooks.c +++ b/tests/test_channel_feature_hooks.c @@ -40,6 +40,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/bridge.h" #include "asterisk/bridge_basic.h" #include "asterisk/features.h" +#include "asterisk/format_cache.h" #define TEST_CATEGORY "/channels/features/" @@ -47,6 +48,8 @@ ASTERISK_REGISTER_FILE() #define TEST_BACKEND_NAME "Features Test Logging" +#define TEST_CHANNEL_FORMAT ast_format_slin + /*! \brief A channel technology used for the unit tests */ static struct ast_channel_tech test_features_chan_tech = { .type = CHANNEL_TECH_NAME, @@ -94,6 +97,11 @@ static void wait_for_unbridged(struct ast_channel *channel) #define START_CHANNEL(channel, name, number) do { \ channel = ast_channel_alloc(0, AST_STATE_UP, number, name, number, number, \ "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/" name); \ + ast_channel_nativeformats_set(channel, test_features_chan_tech.capabilities); \ + ast_channel_set_rawwriteformat(channel, TEST_CHANNEL_FORMAT); \ + ast_channel_set_rawreadformat(channel, TEST_CHANNEL_FORMAT); \ + ast_channel_set_writeformat(channel, TEST_CHANNEL_FORMAT); \ + ast_channel_set_readformat(channel, TEST_CHANNEL_FORMAT); \ ast_channel_unlock(channel); \ } while (0) @@ -329,12 +337,19 @@ static int unload_module(void) AST_TEST_UNREGISTER(test_features_channel_interval); ast_channel_unregister(&test_features_chan_tech); + ao2_cleanup(test_features_chan_tech.capabilities); + test_features_chan_tech.capabilities = NULL; return 0; } static int load_module(void) { + test_features_chan_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!test_features_chan_tech.capabilities) { + return AST_MODULE_LOAD_FAILURE; + } + ast_format_cap_append(test_features_chan_tech.capabilities, TEST_CHANNEL_FORMAT, 0); ast_channel_register(&test_features_chan_tech); AST_TEST_REGISTER(test_features_channel_dtmf); From a63656b41975a4f77c8d953b5dc7f966332892f4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Apr 2016 13:50:04 -0500 Subject: [PATCH 0372/1578] Bridge system: Fix memory leaks and double frees on impart failure. You cannot reference the passed in features struct after calling ast_bridge_impart(). Even if the call fails. Change-Id: I902b88ba0d5d39520e670fb635078a367268ea21 --- apps/confbridge/conf_chan_announce.c | 1 - include/asterisk/features.h | 9 ++++++++- main/bridge.c | 7 ++++--- main/core_unreal.c | 1 - main/features.c | 1 - 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/confbridge/conf_chan_announce.c b/apps/confbridge/conf_chan_announce.c index 8ced0cccd8b..ff30499086c 100644 --- a/apps/confbridge/conf_chan_announce.c +++ b/apps/confbridge/conf_chan_announce.c @@ -199,7 +199,6 @@ int conf_announce_channel_push(struct ast_channel *ast) /* Impart the output channel into the bridge */ if (ast_bridge_impart(p->bridge, chan, NULL, features, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { - ast_bridge_features_destroy(features); ast_channel_unref(chan); return -1; } diff --git a/include/asterisk/features.h b/include/asterisk/features.h index b63124c2f1f..a4aed5d18cb 100644 --- a/include/asterisk/features.h +++ b/include/asterisk/features.h @@ -51,6 +51,7 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct a /*! * \brief Bridge a call, and add additional flags to the bridge * + * \details * This does the same thing as \ref ast_bridge_call, except that once the bridge * is created, the provided flags are set on the bridge. The provided flags are * added to the bridge's flags; they will not clear any flags already set. @@ -70,6 +71,7 @@ int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *pee * \brief Add an arbitrary channel to a bridge * \since 12.0.0 * + * \details * The channel that is being added to the bridge can be in any state: unbridged, * bridged, answered, unanswered, etc. The channel will be added asynchronously, * meaning that when this function returns once the channel has been added to @@ -87,11 +89,16 @@ int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *pee * \param features Features for this channel in the bridge * \param play_tone Indicates if a tone should be played to the channel * \param xfersound Sound that should be used to indicate transfer with play_tone + * + * \note The features parameter must be NULL or obtained by + * ast_bridge_features_new(). You must not dereference features + * after calling even if the call fails. + * * \retval 0 Success * \retval -1 Failure */ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan, - struct ast_bridge_features *features, int play_tone, const char *xfersound); + struct ast_bridge_features *features, int play_tone, const char *xfersound); diff --git a/main/bridge.c b/main/bridge.c index a56555bc9fa..64c750b1e6b 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -2318,6 +2318,9 @@ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan, if (chan_bridge) { struct ast_bridge_channel *bridge_channel; + /* The channel is in a bridge so it is not getting any new features. */ + ast_bridge_features_destroy(features); + ast_bridge_lock_both(bridge, chan_bridge); bridge_channel = bridge_find_channel(chan_bridge, chan); @@ -2340,9 +2343,6 @@ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan, bridge_dissolve_check_stolen(chan_bridge, bridge_channel); ast_bridge_unlock(chan_bridge); ast_bridge_unlock(bridge); - - /* The channel was in a bridge so it is not getting any new features. */ - ast_bridge_features_destroy(features); } else { /* Slightly less easy case. We need to yank channel A from * where he currently is and impart him into our bridge. @@ -2350,6 +2350,7 @@ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan, yanked_chan = ast_channel_yank(chan); if (!yanked_chan) { ast_log(LOG_WARNING, "Could not gain control of channel %s\n", ast_channel_name(chan)); + ast_bridge_features_destroy(features); return -1; } if (ast_channel_state(yanked_chan) != AST_STATE_UP) { diff --git a/main/core_unreal.c b/main/core_unreal.c index 377abd1ffac..28886b63595 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -805,7 +805,6 @@ int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge /* Impart the semi2 channel into the bridge */ if (ast_bridge_impart(bridge, chan, NULL, features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { - ast_bridge_features_destroy(features); ast_channel_unref(chan); return -1; } diff --git a/main/features.c b/main/features.c index 618f91c52d3..7dfe4cde576 100644 --- a/main/features.c +++ b/main/features.c @@ -1103,7 +1103,6 @@ static int bridge_exec(struct ast_channel *chan, const char *data) xfer_cfg ? xfer_cfg->xfersound : NULL); ao2_cleanup(xfer_cfg); if (bridge_add_failed) { - ast_bridge_features_destroy(peer_features); ast_bridge_features_cleanup(&chan_features); ast_bridge_destroy(bridge, 0); goto done; From b3cc74fda954b330944397d5bbca4ff98698661f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Apr 2016 17:09:53 -0500 Subject: [PATCH 0373/1578] manager_channels.c: Fix allocation failure crash. An earlier allocation failure failed to create a channel snapshot for the AMI HangupRequest/SoftHangupRequest event which resulted in a crash in channel_hangup_request_cb(). Where the stasis message gets generated cannot tell if the NULL snapshot returned was because of an allocation failure or the channel was a dummy channel. * Made channel_hangup_request_cb() check if the channel blob has a snapshot and exit if it doesn't. * Eliminated the RAII_VAR usage in channel_hangup_request_cb(). Change-Id: I0b6a1c4e95cbb7d80b2a7054c6eadecc169dfd24 --- main/manager_channels.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/main/manager_channels.c b/main/manager_channels.c index da9bf476dc8..c395708cc9a 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -697,28 +697,33 @@ static void channel_hangup_request_cb(void *data, struct stasis_message *message) { struct ast_channel_blob *obj = stasis_message_data(message); - RAII_VAR(struct ast_str *, extra, NULL, ast_free); - RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); + struct ast_str *extra; + struct ast_str *channel_event_string; struct ast_json *cause; int is_soft; char *manager_event = "HangupRequest"; + if (!obj->snapshot) { + /* No snapshot? Likely an earlier allocation failure creating it. */ + return; + } + extra = ast_str_create(20); if (!extra) { return; } channel_event_string = ast_manager_build_channel_state_string(obj->snapshot); - if (!channel_event_string) { + ast_free(extra); return; } cause = ast_json_object_get(obj->blob, "cause"); if (cause) { ast_str_append(&extra, 0, - "Cause: %jd\r\n", - ast_json_integer_get(cause)); + "Cause: %jd\r\n", + ast_json_integer_get(cause)); } is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft")); @@ -727,9 +732,12 @@ static void channel_hangup_request_cb(void *data, } manager_event(EVENT_FLAG_CALL, manager_event, - "%s%s", - ast_str_buffer(channel_event_string), - ast_str_buffer(extra)); + "%s%s", + ast_str_buffer(channel_event_string), + ast_str_buffer(extra)); + + ast_free(channel_event_string); + ast_free(extra); } static void channel_chanspy_stop_cb(void *data, struct stasis_subscription *sub, From 41ecf225876d518a01116fe66491ee018b487813 Mon Sep 17 00:00:00 2001 From: kkm Date: Thu, 21 Apr 2016 21:53:46 -0700 Subject: [PATCH 0374/1578] chan_sip: Make autocreated peers send PeerStatus events Since Stasis has been introduced, an attempt to send AMI messages by an autocreated peer caused a crash, and all events from autocreated peers were semi-inadvertently disabled altogether in 0b83761. This change restores the disabled functionality. ASTERISK-25950 Change-Id: Iecc350f23db603fadb2f302064643ebe9664e974 --- channels/chan_sip.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index d927f06e393..830a524cd44 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -17713,6 +17713,10 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock if (!peer && sip_cfg.autocreatepeer != AUTOPEERS_DISABLED) { /* Create peer if we have autocreate mode enabled */ peer = temp_peer(name); + if (peer && !(peer->endpoint = ast_endpoint_create("SIP", name))) { + ao2_t_ref(peer, -1, "failed to allocate Stasis endpoint, drop peer"); + peer = NULL; + } if (peer) { ao2_t_link(peers, peer, "link peer into peer table"); if (!ast_sockaddr_isnull(&peer->addr)) { From 757ec6172b4fa46ae9e97790a3dc44f2b36c9805 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 22 Apr 2016 15:25:29 -0500 Subject: [PATCH 0375/1578] test_message.c: Wait longer in case dialplan also processes the test message. Bumped the wait from 1 second to 5 seconds. The test message was hitting my default call handler and failing the test because it took longer. Change-Id: I3a03737f25e92983de00548fcc7bbc50dd7544ba --- tests/test_message.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_message.c b/tests/test_message.c index 3c3b8302a94..017b84cf2d0 100644 --- a/tests/test_message.c +++ b/tests/test_message.c @@ -232,8 +232,8 @@ static int user_event_hook_cb(int category, const char *event, char *body) static int handler_wait_for_message(struct ast_test *test) { int error = 0; - struct timeval wait_now = ast_tvnow(); - struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 }; + struct timeval wait = ast_tvadd(ast_tvnow(), ast_tv(5 /* seconds */, 0)); + struct timespec wait_time = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000 }; ast_mutex_lock(&handler_lock); while (!handler_received_message) { @@ -253,8 +253,8 @@ static int handler_wait_for_message(struct ast_test *test) static int user_event_wait_for_events(struct ast_test *test, int expected_events) { int error; - struct timeval wait_now = ast_tvnow(); - struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 }; + struct timeval wait = ast_tvadd(ast_tvnow(), ast_tv(5 /* seconds */, 0)); + struct timespec wait_time = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000 }; expected_user_events = expected_events; From 99fcf2a791c2c78ae0ffffce2ac3e8db18ca5be0 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 22 Apr 2016 16:53:23 -0600 Subject: [PATCH 0376/1578] res_agi: Prevent run_agi from eating frames it shouldn't The run_agi function is eating control frames when it shouldn't be. This is causing issues when an AGI is run from CONNECTED_LINE_SEND_SUB in a blond transfer. Alice calls Bob. Bob attended transfers to Charlie but hangs up before Charlie answers. Alice gets the COLP UPDATE indicating Charlie but Charlie never gets an UPDATE and is left thinking he's connected to Bob. In this case, when CONNECTED_LINE_SEND_SUB runs on Alice's channel and it calls an AGI, the extra eaten frames prevent CONNECTED_LINE_SEND_SUB from running on Charlie's channel. The fix was to accumulate deferrable frames in the "forever" loop instead of dropping them, and re-queue them just before running the actual agi command or exiting. ASTERISK-25951 #close Change-Id: I0f4bbfd72fc1126c2aaba41da3233a33d0433645 --- res/res_agi.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/res/res_agi.c b/res/res_agi.c index f6ce7496015..e8249e2027e 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -3736,6 +3736,24 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch return AGI_RESULT_SUCCESS; } + +AST_LIST_HEAD_NOLOCK(deferred_frames, ast_frame); + +static void queue_deferred_frames(struct deferred_frames *deferred_frames, + struct ast_channel *chan) +{ + struct ast_frame *f; + + if (!AST_LIST_EMPTY(deferred_frames)) { + ast_channel_lock(chan); + while ((f = AST_LIST_REMOVE_HEAD(deferred_frames, frame_list))) { + ast_queue_frame_head(chan, f); + ast_frfree(f); + } + ast_channel_unlock(chan); + } +} + static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[]) { struct ast_channel *c; @@ -3754,6 +3772,9 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi const char *sighup_str; const char *exit_on_hangup_str; int exit_on_hangup; + struct deferred_frames deferred_frames; + + AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); ast_channel_lock(chan); sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); @@ -3815,8 +3836,20 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi /* Write, ignoring errors */ if (write(agi->audio, f->data.ptr, f->datalen) < 0) { } + ast_frfree(f); + } else if (ast_is_deferrable_frame(f)) { + struct ast_frame *dup_f; + + if ((dup_f = ast_frisolate(f))) { + AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); + } + + if (dup_f != f) { + ast_frfree(f); + } + } else { + ast_frfree(f); } - ast_frfree(f); } } else if (outfd > -1) { size_t len = sizeof(buf); @@ -3864,6 +3897,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi buf[buflen - 1] = '\0'; } + queue_deferred_frames(&deferred_frames, chan); + if (agidebug) ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf); cmd_status = agi_handle_command(chan, agi, buf, dead); @@ -3885,6 +3920,9 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi } } } + + queue_deferred_frames(&deferred_frames, chan); + if (agi->speech) { ast_speech_destroy(agi->speech); } From 30ab21d5fa42ef1412e0dede665eda7c77784627 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 21 Apr 2016 14:23:21 -0500 Subject: [PATCH 0377/1578] app_queue: queue members can receive multiple calls It was possible for a queue member that is a member of at least 2 or more queues to receive mulitiple calls at the same time. This happened because of a race between when a member was being rung and when the device state notified the other queue(s) member object of the state change. This patch makes it so when a queue member is being rung it gets added to a global pool of queue members. If that same member is tried again, e.g. from another queue, and it is found to already exist in the pending member container then it will not ring that member. ASTERISK-16115 #close Change-Id: I546dd474776d158c2b6be44205353dee5bac7e48 --- apps/app_queue.c | 145 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 44 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 40aed2fe544..f9655f75b42 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1554,7 +1554,6 @@ struct member { struct call_queue *lastqueue; /*!< Last queue we received a call */ unsigned int dead:1; /*!< Used to detect members deleted in realtime */ unsigned int delme:1; /*!< Flag to delete entry on reload */ - unsigned int call_pending:1; /*!< TRUE if the Q is attempting to place a call to the member. */ char rt_uniqueid[80]; /*!< Unique id of realtime member entry */ unsigned int ringinuse:1; /*!< Flag to ring queue members even if their status is 'inuse' */ }; @@ -2289,6 +2288,70 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena return -1; } +/* + * A "pool" of member objects that calls are currently pending on. If an + * agent is a member of multiple queues it's possible for that agent to be + * called by each of the queues at the same time. This happens because device + * state is slow to notify the queue app of one of it's member's being rung. + * This "pool" allows us to track which members are currently being rung while + * we wait on the device state change. + */ +static struct ao2_container *pending_members; +#define MAX_CALL_ATTEMPT_BUCKETS 353 + +static int pending_members_hash(const void *obj, const int flags) +{ + const struct member *object; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + object = obj; + key = object->interface; + break; + default: + ast_assert(0); + return 0; + } + return ast_str_case_hash(key); +} + +static int pending_members_cmp(void *obj, void *arg, int flags) +{ + const struct member *object_left = obj; + const struct member *object_right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->interface; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcasecmp(object_left->interface, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + /* Not supported by container. */ + ast_assert(0); + return 0; + default: + cmp = 0; + break; + } + if (cmp) { + return 0; + } + return CMP_MATCH; +} + +static void pending_members_remove(struct member *mem) +{ + ao2_find(pending_members, mem, OBJ_POINTER | OBJ_NODATA | OBJ_UNLINK); +} + /*! \brief set a member's status based on device state of that member's state_interface. * * Lock interface list find sc, iterate through each queues queue_member list for member to @@ -2298,6 +2361,9 @@ static void update_status(struct call_queue *q, struct member *m, const int stat { m->status = status; + /* Whatever the status is clear the member from the pending members pool */ + pending_members_remove(m); + queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m)); } @@ -3157,6 +3223,7 @@ static void member_add_to_queue(struct call_queue *queue, struct member *mem) */ static void member_remove_from_queue(struct call_queue *queue, struct member *mem) { + pending_members_remove(mem); ao2_lock(queue->members); ast_devstate_changed(QUEUE_UNKNOWN_PAUSED_DEVSTATE, AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface); queue_member_follower_removal(queue, mem); @@ -4133,41 +4200,6 @@ static int member_status_available(int status) return status == AST_DEVICE_NOT_INUSE || status == AST_DEVICE_UNKNOWN; } -/*! - * \internal - * \brief Clear the member call pending flag. - * - * \param mem Queue member. - * - * \return Nothing - */ -static void member_call_pending_clear(struct member *mem) -{ - ao2_lock(mem); - mem->call_pending = 0; - ao2_unlock(mem); -} - -/*! - * \internal - * \brief Set the member call pending flag. - * - * \param mem Queue member. - * - * \retval non-zero if call pending flag was already set. - */ -static int member_call_pending_set(struct member *mem) -{ - int old_pending; - - ao2_lock(mem); - old_pending = mem->call_pending; - mem->call_pending = 1; - ao2_unlock(mem); - - return old_pending; -} - /*! * \internal * \brief Determine if can ring a queue entry. @@ -4210,12 +4242,31 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call) } if (!call->member->ringinuse) { - if (member_call_pending_set(call->member)) { - ast_debug(1, "%s has another call pending, can't receive call\n", - call->interface); + struct member *mem; + + ao2_lock(pending_members); + + mem = ao2_find(pending_members, call->member, + OBJ_SEARCH_OBJECT | OBJ_NOLOCK); + if (mem) { + /* + * If found that means this member is currently being attempted + * from another calling thread, so stop trying from this thread + */ + ast_debug(1, "%s has another call trying, can't receive call\n", + call->interface); + ao2_ref(mem, -1); + ao2_unlock(pending_members); return 0; } + /* + * If not found add it to the container so another queue + * won't attempt to call this member at the same time. + */ + ao2_link(pending_members, call->member); + ao2_unlock(pending_members); + /* * The queue member is available. Get current status to be sure * because the device state and extension state callbacks may @@ -4224,7 +4275,7 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call) if (!member_status_available(get_queue_member_status(call->member))) { ast_debug(1, "%s actually not available, can't receive call\n", call->interface); - member_call_pending_clear(call->member); + pending_members_remove(call->member); return 0; } } @@ -4261,7 +4312,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies ++*busies; return 0; } - ast_assert(tmp->member->ringinuse || tmp->member->call_pending); ast_copy_string(tech, tmp->interface, sizeof(tech)); if ((location = strchr(tech, '/'))) { @@ -4278,7 +4328,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies qe->linpos++; ao2_unlock(qe->parent); - member_call_pending_clear(tmp->member); + pending_members_remove(tmp->member); publish_dial_end_event(qe->chan, tmp, NULL, "BUSY"); tmp->stillgoing = 0; @@ -4349,7 +4399,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies /* Again, keep going even if there's an error */ ast_verb(3, "Couldn't call %s\n", tmp->interface); do_hang(tmp); - member_call_pending_clear(tmp->member); + pending_members_remove(tmp->member); ++*busies; return 0; } @@ -4369,7 +4419,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies ast_verb(3, "Called %s\n", tmp->interface); - member_call_pending_clear(tmp->member); return 1; } @@ -10934,6 +10983,7 @@ static int unload_module(void) ast_extension_state_del(0, extension_state_cb); ast_unload_realtime("queue_members"); + ao2_cleanup(pending_members); ao2_cleanup(queues); queues = NULL; return 0; @@ -10962,6 +11012,13 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } + pending_members = ao2_container_alloc( + MAX_CALL_ATTEMPT_BUCKETS, pending_members_hash, pending_members_cmp); + if (!pending_members) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + use_weight = 0; if (reload_handler(0, &mask, NULL)) { From f99ec857c8b663c931f5587a09a5f517a3c5c196 Mon Sep 17 00:00:00 2001 From: DarkS Date: Mon, 25 Apr 2016 15:11:31 +0200 Subject: [PATCH 0378/1578] Fix case sensitive actions in AMI QueueSummary and QueueStatus ASTERISK-25954 #close Reported by: Javier Acosta Change-Id: I00be83d45cc7e8385de2523012bd196aafeeb256 (cherry picked from commit c0688a6398f27296ff849848a2e416e036d794e3) --- apps/app_queue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 40aed2fe544..f8cf36bdc7d 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -9599,7 +9599,7 @@ static int manager_queues_summary(struct mansession *s, const struct message *m) ao2_lock(q); /* List queue properties */ - if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { + if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) { /* Reset the necessary local variables if no queuefilter is set*/ qmemcount = 0; qmemavail = 0; @@ -9677,7 +9677,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) ao2_lock(q); /* List queue properties */ - if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { + if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) { sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); astman_append(s, "Event: QueueParams\r\n" "Queue: %s\r\n" From 284bb814ac09a10e3bababa2e126d69d16fd93c4 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 24 Apr 2016 21:51:16 -0600 Subject: [PATCH 0379/1578] config: Fix ast_config_text_file_save2 writability check for missing files A patch I did back in 2014 modified ast_config_text_file_save2 to check the writability of the main file and include files before truncating and re-writing them. An unintended side-effect of this was that if a file doesn't exist, the check fails and the write is aborted. This patch causes ast_config_text_file_save2 to check the writability of the parent directory of missing files instead of checking the file itself. This allows missing files to be created again. A unit test was also added to test_config to test saving of config files. The regression was discovered when app_voicemail's passwordlocation=spooldir feature stopped working. ASTERISK-25917 #close Reported-by: Jonathan Rose Change-Id: Ic4dbe58c277a47b674679e49daed5fc6de349f80 --- main/config.c | 34 ++++++++++++++++---- tests/test_config.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/main/config.c b/main/config.c index dad3b668be9..59927038489 100644 --- a/main/config.c +++ b/main/config.c @@ -36,6 +36,9 @@ ASTERISK_REGISTER_FILE() #include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */ #include "asterisk/network.h" /* we do some sockaddr manipulation here */ + +#include +#include #include #include @@ -2512,6 +2515,25 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c return ast_config_text_file_save2(configfile, cfg, generator, CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT); } +static int is_writable(const char *fn) +{ + if (access(fn, F_OK)) { + char *dn = dirname(ast_strdupa(fn)); + + if (access(dn, R_OK | W_OK)) { + ast_log(LOG_ERROR, "Unable to write to directory %s (%s)\n", dn, strerror(errno)); + return 0; + } + } else { + if (access(fn, R_OK | W_OK)) { + ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + return 0; + } + } + + return 1; +} + int ast_config_text_file_save2(const char *configfile, const struct ast_config *cfg, const char *generator, uint32_t flags) { FILE *f; @@ -2534,20 +2556,20 @@ int ast_config_text_file_save2(const char *configfile, const struct ast_config * for (incl = cfg->includes; incl; incl = incl->next) { /* reset all the output flags in case this isn't our first time saving this data */ incl->output = 0; - /* now make sure we have write access */ + if (!incl->exec) { + /* now make sure we have write access to the include file or its parent directory */ make_fn(fn, sizeof(fn), incl->included_file, configfile); - if (access(fn, R_OK | W_OK)) { - ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + /* If the file itself doesn't exist, make sure we have write access to the directory */ + if (!is_writable(fn)) { return -1; } } } - /* now make sure we have write access to the main config file */ + /* now make sure we have write access to the main config file or its parent directory */ make_fn(fn, sizeof(fn), 0, configfile); - if (access(fn, R_OK | W_OK)) { - ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + if (!is_writable(fn)) { return -1; } diff --git a/tests/test_config.c b/tests/test_config.c index fe64a074f2b..eb5409b3a13 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -34,6 +34,7 @@ ASTERISK_REGISTER_FILE(); #include /* HUGE_VAL */ +#include #include "asterisk/config.h" #include "asterisk/module.h" @@ -49,6 +50,7 @@ ASTERISK_REGISTER_FILE(); #include "asterisk/format_cap.h" #define CONFIG_FILE "test_config.conf" +#define CONFIG_INCLUDE_FILE "test_config_include.conf" /* * This builds the folowing config: @@ -881,6 +883,77 @@ static int hook_cb(struct ast_config *cfg) return 0; } +AST_TEST_DEFINE(config_save) +{ + enum ast_test_result_state res = AST_TEST_FAIL; + struct ast_flags config_flags = { 0 }; + struct ast_config *cfg; + char config_filename[PATH_MAX]; + char include_filename[PATH_MAX]; + struct stat config_stat; + off_t before_save; + + switch (cmd) { + case TEST_INIT: + info->name = "config_save"; + info->category = "/main/config/"; + info->summary = "Test config save"; + info->description = + "Test configuration save."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (write_config_file()) { + ast_test_status_update(test, "Could not write initial config files\n"); + return res; + } + + snprintf(config_filename, PATH_MAX, "%s/%s", ast_config_AST_CONFIG_DIR, CONFIG_FILE); + snprintf(include_filename, PATH_MAX, "%s/%s", ast_config_AST_CONFIG_DIR, CONFIG_INCLUDE_FILE); + + cfg = ast_config_load(CONFIG_FILE, config_flags); + if (!cfg) { + ast_test_status_update(test, "Could not load config\n"); + goto out; + } + + /* We need to re-save to get the generator header */ + if (ast_config_text_file_save(CONFIG_FILE, cfg, "TEST")) { + ast_test_status_update(test, "Unable to write files\n"); + goto out; + } + + stat(config_filename, &config_stat); + before_save = config_stat.st_size; + + if (!ast_include_new(cfg, CONFIG_FILE, CONFIG_INCLUDE_FILE, 0, NULL, 4, include_filename, PATH_MAX)) { + ast_test_status_update(test, "Could not create include\n"); + goto out; + } + + if (ast_config_text_file_save(CONFIG_FILE, cfg, "TEST")) { + ast_test_status_update(test, "Unable to write files\n"); + goto out; + } + + stat(config_filename, &config_stat); + if (config_stat.st_size <= before_save) { + ast_test_status_update(test, "Did not save config file with #include\n"); + goto out; + } + + res = AST_TEST_PASS; + +out: + ast_config_destroy(cfg); + unlink(config_filename); + unlink(include_filename); + + return res; +} + AST_TEST_DEFINE(config_hook) { enum ast_test_result_state res = AST_TEST_FAIL; @@ -1734,6 +1807,7 @@ AST_TEST_DEFINE(variable_lists_match) static int unload_module(void) { + AST_TEST_UNREGISTER(config_save); AST_TEST_UNREGISTER(config_basic_ops); AST_TEST_UNREGISTER(config_filtered_ops); AST_TEST_UNREGISTER(config_template_ops); @@ -1748,6 +1822,7 @@ static int unload_module(void) static int load_module(void) { + AST_TEST_REGISTER(config_save); AST_TEST_REGISTER(config_basic_ops); AST_TEST_REGISTER(config_filtered_ops); AST_TEST_REGISTER(config_template_ops); From 8ae69cffef03dcd4ba8a2ef56299ea3d19546a34 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 26 Apr 2016 07:48:40 -0300 Subject: [PATCH 0380/1578] app_queue: Fix crash when unloading module. When unloading the app_queue module the members in each queue are destroyed and as part of this they are removed from the pending members container. Unfortunately a crash would occur as the container was destroyed before the members were removed. This change tweaks ordering so the container destruction occurs after the members are destroyed. ASTERISK-16115 Change-Id: I48c728668c55aee3d05b751a5d450fb57e87f44b --- apps/app_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 927c4967ec9..8171d11cb47 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -10983,8 +10983,9 @@ static int unload_module(void) ast_extension_state_del(0, extension_state_cb); ast_unload_realtime("queue_members"); - ao2_cleanup(pending_members); ao2_cleanup(queues); + ao2_cleanup(pending_members); + queues = NULL; return 0; } From c48015904514327d2e4f0fd74d3abdd8dc425f83 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 26 Apr 2016 13:13:14 -0300 Subject: [PATCH 0381/1578] chan_sip: Give more time for TCP/TLS threads to stop. The unload process currently tells each TCP/TLS to terminate but does not wait for them to do so. This introduces a race condition where the container holding the threads may be destroyed before the threads are able to remove themselves from it. When they finally do the container is invalid and can't be used causing a crash. A previous change existed which waited a bit to wait for any stranglers to finish. This change extends this and waits longer. ASTERISK-25961 #close Change-Id: Idc6262b670ca49ede32061159e323b7b63c6f3c6 --- channels/chan_sip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index d927f06e393..9e5a7fd83c8 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -35298,7 +35298,7 @@ static int unload_module(void) struct sip_pvt *p; struct sip_threadinfo *th; struct ao2_iterator i; - int wait_count; + struct timeval start; ast_sip_api_provider_unregister(); @@ -35450,11 +35450,11 @@ static int unload_module(void) * joinable. They can die on their own and remove themselves * from the container thus resulting in a huge memory leak. */ - wait_count = 1000; - while (ao2_container_count(threadt) && --wait_count) { + start = ast_tvnow(); + while (ao2_container_count(threadt) && (ast_tvdiff_sec(ast_tvnow(), start) < 5)) { sched_yield(); } - if (!wait_count) { + if (ao2_container_count(threadt)) { ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); } From 81ea80b74ce1ae35eb5b377a825948c27ef65b45 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 14 Apr 2016 09:03:24 -0300 Subject: [PATCH 0382/1578] res_pjsip_exten_state: Add config support for exten state publishers. This change adds the ability to configure outbound publishing of extension state. Right now stuff is merely set up to store the configuration and to register a global extension state callback. The act of constructing the body and sending is not yet complete. Configurable elements right now are a regex for filtering the context, a regex for filtering the extension, and the body type to publish. ASTERISK-25922 #close Change-Id: Ia7e630136dfc355073c1cadff8ad394a08523d78 --- res/res_pjsip_exten_state.c | 303 ++++++++++++++++++++++++++++++++++-- 1 file changed, 294 insertions(+), 9 deletions(-) diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index a4ad1cd784b..1f8b121e85f 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -20,16 +20,20 @@ pjproject res_pjsip res_pjsip_pubsub + res_pjsip_outbound_publish core ***/ #include "asterisk.h" +#include + #include #include #include #include "asterisk/res_pjsip.h" +#include "asterisk/res_pjsip_outbound_publish.h" #include "asterisk/res_pjsip_pubsub.h" #include "asterisk/res_pjsip_body_generator_types.h" #include "asterisk/module.h" @@ -42,6 +46,16 @@ #define BODY_SIZE 1024 #define EVENT_TYPE_SIZE 50 +/*! + * \brief The number of buckets to use for storing publishers + */ +#define PUBLISHER_BUCKETS 31 + +/*! + * \brief Container of active outbound extension state publishers + */ +static struct ao2_container *publishers; + /*! * \brief A subscription for extension state * @@ -68,6 +82,29 @@ struct exten_state_subscription { enum ast_presence_state last_presence_state; }; +/*! + * \brief An extension state publisher + * + */ +struct exten_state_publisher { + /*! Regular expression for context filtering */ + regex_t context_regex; + /*! Regular expression for extension filtering */ + regex_t exten_regex; + /*! Publish client to use for sending publish messages */ + struct ast_sip_outbound_publish_client *client; + /*! Whether context filtering is active */ + unsigned int context_filter; + /*! Whether extension filtering is active */ + unsigned int exten_filter; + /*! The body type to use for this publisher - stored after the name */ + char *body_type; + /*! The body subtype to use for this publisher - stored after the body type */ + char *body_subtype; + /*! The name of this publisher */ + char name[0]; +}; + #define DEFAULT_PRESENCE_BODY "application/pidf+xml" #define DEFAULT_DIALOG_BODY "application/dialog-info+xml" @@ -77,6 +114,9 @@ static int subscription_established(struct ast_sip_subscription *sub); static void *get_notify_data(struct ast_sip_subscription *sub); static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf); +static int publisher_start(struct ast_sip_outbound_publish *configuration, + struct ast_sip_outbound_publish_client *client); +static int publisher_stop(struct ast_sip_outbound_publish_client *client); struct ast_sip_notifier presence_notifier = { .default_accept = DEFAULT_PRESENCE_BODY, @@ -101,6 +141,12 @@ struct ast_sip_subscription_handler presence_handler = { .notifier = &presence_notifier, }; +struct ast_sip_event_publisher_handler presence_publisher = { + .event_name = "presence", + .start_publishing = publisher_start, + .stop_publishing = publisher_stop, +}; + struct ast_sip_subscription_handler dialog_handler = { .event_name = "dialog", .body_type = AST_SIP_EXTEN_STATE_DATA, @@ -110,6 +156,12 @@ struct ast_sip_subscription_handler dialog_handler = { .notifier = &dialog_notifier, }; +struct ast_sip_event_publisher_handler dialog_publisher = { + .event_name = "dialog", + .start_publishing = publisher_start, + .stop_publishing = publisher_stop, +}; + static void exten_state_subscription_destructor(void *obj) { struct exten_state_subscription *sub = obj; @@ -490,31 +542,264 @@ static void to_ami(struct ast_sip_subscription *sub, exten_state_sub->last_exten_state)); } +/*! + * \brief Global extension state callback function + */ +static int exten_state_publisher_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data) +{ + struct ao2_iterator publisher_iter; + struct exten_state_publisher *publisher; + + publisher_iter = ao2_iterator_init(publishers, 0); + for (; (publisher = ao2_iterator_next(&publisher_iter)); ao2_ref(publisher, -1)) { + if ((publisher->context_filter && regexec(&publisher->context_regex, context, 0, NULL, 0)) || + (publisher->exten_filter && regexec(&publisher->exten_regex, exten, 0, NULL, 0))) { + continue; + } + /* This is a placeholder for additional code to come */ + } + ao2_iterator_destroy(&publisher_iter); + + return 0; +} + +/*! + * \brief Hashing function for extension state publisher + */ +static int exten_state_publisher_hash(const void *obj, const int flags) +{ + const struct exten_state_publisher *object; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + object = obj; + key = object->name; + break; + default: + ast_assert(0); + return 0; + } + return ast_str_hash(key); +} + +/*! + * \brief Comparator function for extension state publisher + */ +static int exten_state_publisher_cmp(void *obj, void *arg, int flags) +{ + const struct exten_state_publisher *object_left = obj; + const struct exten_state_publisher *object_right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->name; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(object_left->name, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + /* Not supported by container. */ + ast_assert(0); + return 0; + default: + cmp = 0; + break; + } + if (cmp) { + return 0; + } + return CMP_MATCH; +} + +/*! + * \brief Destructor for extension state publisher + */ +static void exten_state_publisher_destroy(void *obj) +{ + struct exten_state_publisher *publisher = obj; + + if (publisher->context_filter) { + regfree(&publisher->context_regex); + } + + if (publisher->exten_filter) { + regfree(&publisher->exten_regex); + } + + ao2_cleanup(publisher->client); +} + +static int build_regex(regex_t *regex, const char *text) +{ + int res; + + if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) { + size_t len = regerror(res, regex, NULL, 0); + char buf[len]; + regerror(res, regex, buf, len); + ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf); + return -1; + } + + return 0; +} + +static int publisher_start(struct ast_sip_outbound_publish *configuration, struct ast_sip_outbound_publish_client *client) +{ + struct exten_state_publisher *publisher; + size_t name_size; + size_t body_type_size; + size_t body_subtype_size; + char *body_subtype; + const char *body_full; + const char *body_type; + const char *name; + const char *context; + const char *exten; + + name = ast_sorcery_object_get_id(configuration); + + body_full = ast_sorcery_object_get_extended(configuration, "body"); + if (ast_strlen_zero(body_full)) { + ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Body not set\n", + name); + return -1; + } + + body_subtype = ast_strdupa(body_full); + body_type = strsep(&body_subtype, "/"); + if (ast_strlen_zero(body_type) || ast_strlen_zero(body_subtype)) { + ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Body '%s' missing type or subtype\n", + name, body_full); + return -1; + } + + name_size = strlen(name) + 1; + body_type_size = strlen(body_type) + 1; + body_subtype_size = strlen(body_subtype) + 1; + + publisher = ao2_alloc_options( + sizeof(*publisher) + name_size + body_type_size + body_subtype_size, + exten_state_publisher_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!publisher) { + return -1; + } + + ast_copy_string(publisher->name, name, name_size); + publisher->body_type = publisher->name + name_size; + ast_copy_string(publisher->body_type, body_type, body_type_size); + publisher->body_subtype = publisher->body_type + body_type_size; + ast_copy_string(publisher->body_subtype, body_subtype, body_subtype_size); + + context = ast_sorcery_object_get_extended(configuration, "context"); + if (!ast_strlen_zero(context)) { + if (build_regex(&publisher->context_regex, context)) { + ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not build context filter '%s'\n", + name, context); + ao2_ref(publisher, -1); + return -1; + } + + publisher->context_filter = 1; + } + + exten = ast_sorcery_object_get_extended(configuration, "exten"); + if (!ast_strlen_zero(exten)) { + if (build_regex(&publisher->exten_regex, exten)) { + ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not build exten filter '%s'\n", + name, exten); + ao2_ref(publisher, -1); + return -1; + } + + publisher->exten_filter = 1; + } + + publisher->client = ao2_bump(client); + + ao2_lock(publishers); + if (!ao2_container_count(publishers)) { + ast_extension_state_add(NULL, NULL, exten_state_publisher_state_cb, NULL); + } + ao2_link_flags(publishers, publisher, OBJ_NOLOCK); + ao2_unlock(publishers); + + ao2_ref(publisher, -1); + + return 0; +} + +static int publisher_stop(struct ast_sip_outbound_publish_client *client) +{ + ao2_find(publishers, ast_sorcery_object_get_id(client), OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); + return 0; +} + +static int unload_module(void) +{ + ast_sip_unregister_event_publisher_handler(&dialog_publisher); + ast_sip_unregister_subscription_handler(&dialog_handler); + ast_sip_unregister_event_publisher_handler(&presence_publisher); + ast_sip_unregister_subscription_handler(&presence_handler); + + ast_extension_state_del(0, exten_state_publisher_state_cb); + ao2_cleanup(publishers); + publishers = NULL; + + return 0; +} + static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); + CHECK_PJSIP_PUBSUB_MODULE_LOADED(); + + if (!ast_module_check("res_pjsip_outbound_publish.so")) { + ast_log(LOG_WARNING, "This module requires the 'res_pjsip_outbound_publish.so' module to be loaded\n"); + return AST_MODULE_LOAD_DECLINE; + } + + publishers = ao2_container_alloc(PUBLISHER_BUCKETS, exten_state_publisher_hash, + exten_state_publisher_cmp); + if (!publishers) { + ast_log(LOG_WARNING, "Unable to create container to store extension state publishers\n"); + return AST_MODULE_LOAD_DECLINE; + } if (ast_sip_register_subscription_handler(&presence_handler)) { ast_log(LOG_WARNING, "Unable to register subscription handler %s\n", presence_handler.event_name); + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + + if (ast_sip_register_event_publisher_handler(&presence_publisher)) { + ast_log(LOG_WARNING, "Unable to register presence publisher %s\n", + presence_publisher.event_name); + unload_module(); return AST_MODULE_LOAD_DECLINE; } if (ast_sip_register_subscription_handler(&dialog_handler)) { ast_log(LOG_WARNING, "Unable to register subscription handler %s\n", dialog_handler.event_name); - ast_sip_unregister_subscription_handler(&presence_handler); + unload_module(); return AST_MODULE_LOAD_DECLINE; } - return AST_MODULE_LOAD_SUCCESS; -} + if (ast_sip_register_event_publisher_handler(&dialog_publisher)) { + ast_log(LOG_WARNING, "Unable to register presence publisher %s\n", + dialog_publisher.event_name); + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_sip_unregister_subscription_handler(&dialog_handler); - ast_sip_unregister_subscription_handler(&presence_handler); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State Notifications", From 72817707104f1d564c75be5ecd9aa0ce01f38589 Mon Sep 17 00:00:00 2001 From: Jean Aunis Date: Fri, 1 Apr 2016 14:50:30 +0200 Subject: [PATCH 0383/1578] app_chanspy: reduce audio loss on the spying channel. ChanSpy was creating its audiohook with the flags AST_AUDIOHOOK_TRIGGER_SYNC and AST_AUDIOHOOK_SMALL_QUEUE, which caused audio frames to be lost when queues grow too large or when read and write queues go out of sync. Now these flags are set conditionally: - AST_AUDIOHOOK_TRIGGER_SYNC is not set if the option "o" is set - a new option "l" is created: if set, AST_AUDIOHOOK_SMALL_QUEUE will not be set on the audiohook ASTERISK-25866 Change-Id: I9c7652f41d9fa72c8691e4e70ec4fd16b047a4dd --- CHANGES | 7 +++++++ apps/app_chanspy.c | 32 ++++++++++++++++++++++++-------- main/audiohook.c | 5 +++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index e7f0656f572..56e63157016 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,13 @@ BridgeAdd * A new application in Asterisk, this will join the calling channel to an existing bridge containing the named channel prefix. +ChanSpy +------------------ + * Added the 'l' option, which forces ChanSpy's audiohook to use a long queue + to store the audio frames. This option is useful if audio loss is + experienced when using ChanSpy, but may introduce some delay in the audio + feed on the listening channel. + ConfBridge ------------------ * Added the ability to pass options to MixMonitor when recording is used with diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 5dbb0b86030..400eed11a2d 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -117,6 +117,10 @@ ASTERISK_REGISTER_FILE() either a single group or a colon-delimited list of groups, such as sales:support:accounting. + + @@ -1304,6 +1321,24 @@ The maximum amount of time from startup that qualifies should be attempted on all contacts. If greater than the qualify_frequency for an aor, qualify_frequency will be used instead. + + The number of seconds over which to accumulate unidentified requests. + + If unidentified_request_count unidentified requests are received + during unidentified_request_period, a security event will be generated. + + + + The number of unidentified requests from a single IP to allow. + + If unidentified_request_count unidentified requests are received + during unidentified_request_period, a security event will be generated. + + + + The interval at which unidentified requests are older than + twice the unidentified_request_period are pruned. + Must be of type 'global'. @@ -1327,13 +1362,35 @@ The order by which endpoint identifiers are processed and checked. Identifier names are usually derived from and can be found in the endpoint - identifier module itself (res_pjsip_endpoint_identifier_*) + identifier module itself (res_pjsip_endpoint_identifier_*). + You can use the CLI command "pjsip show identifiers" to see the + identifiers currently available. + + + One of the identifiers is "auth_username" which matches on the username in + an Authentication header. This method has some security considerations because an + Authentication header is not present on the first message of a dialog when + digest authentication is used. The client can't generate it until the server + sends the challenge in a 401 response. Since Asterisk normally sends a security + event when an incoming request can't be matched to an endpoint, using auth_username + requires that the security event be deferred until a request is received with + the Authentication header and only generated if the username doesn't result in a + match. This may result in a delay before an attack is recognized. You can control + how many unmatched requests are received from a single ip address before a security + event is generated using the unidentified_request parameters. + + When Asterisk generates an outgoing SIP request, the From header username will be set to this value if there is no better option (such as CallerID) to be used. + + When Asterisk generates an challenge, the digest will be + set to this value if there is no better option (such as auth/realm) to be + used. + diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index ccfec543572..6bb68880494 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -35,10 +35,14 @@ #define DEFAULT_ENDPOINT_IDENTIFIER_ORDER "ip,username,anonymous" #define DEFAULT_MAX_INITIAL_QUALIFY_TIME 0 #define DEFAULT_FROM_USER "asterisk" +#define DEFAULT_REALM "asterisk" #define DEFAULT_REGCONTEXT "" #define DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL 30 #define DEFAULT_DISABLE_MULTI_DOMAIN 0 #define DEFAULT_VOICEMAIL_EXTENSION "" +#define DEFAULT_UNIDENTIFIED_REQUEST_COUNT 5 +#define DEFAULT_UNIDENTIFIED_REQUEST_PERIOD 5 +#define DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL 30 static char default_useragent[256]; @@ -56,6 +60,8 @@ struct global_config { AST_STRING_FIELD(default_from_user); /*! Default voicemail extension */ AST_STRING_FIELD(default_voicemail_extension); + /*! Realm to use in challenges before an endpoint is identified */ + AST_STRING_FIELD(default_realm); ); /* Value to put in Max-Forwards header */ unsigned int max_forwards; @@ -67,6 +73,12 @@ struct global_config { unsigned int contact_expiration_check_interval; /*! Nonzero to disable multi domain support */ unsigned int disable_multi_domain; + /* The maximum number of unidentified requests per source IP address before a security event is logged */ + unsigned int unidentified_request_count; + /* The period during which unidentified requests are accumulated */ + unsigned int unidentified_request_period; + /* Interval at which expired unidentifed requests will be pruned */ + unsigned int unidentified_request_prune_interval; }; static void global_destructor(void *obj) @@ -255,6 +267,40 @@ unsigned int ast_sip_get_max_initial_qualify_time(void) return time; } +void ast_sip_get_unidentified_request_thresholds(unsigned int *count, unsigned int *period, + unsigned int *prune_interval) +{ + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + *count = DEFAULT_UNIDENTIFIED_REQUEST_COUNT; + *period = DEFAULT_UNIDENTIFIED_REQUEST_PERIOD; + *prune_interval = DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL; + return; + } + + *count = cfg->unidentified_request_count; + *period = cfg->unidentified_request_period; + *prune_interval = cfg->unidentified_request_prune_interval; + + ao2_ref(cfg, -1); + return; +} + +void ast_sip_get_default_realm(char *realm, size_t size) +{ + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + ast_copy_string(realm, DEFAULT_REALM, size); + } else { + ast_copy_string(realm, cfg->default_realm, size); + ao2_ref(cfg, -1); + } +} + void ast_sip_get_default_from_user(char *from_user, size_t size) { struct global_config *cfg; @@ -393,6 +439,17 @@ int ast_sip_initialize_sorcery_global(void) OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); ast_sorcery_object_field_register(sorcery, "global", "disable_multi_domain", "no", OPT_BOOL_T, 1, FLDSET(struct global_config, disable_multi_domain)); + ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_count", + __stringify(DEFAULT_UNIDENTIFIED_REQUEST_COUNT), + OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_count)); + ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_period", + __stringify(DEFAULT_UNIDENTIFIED_REQUEST_PERIOD), + OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_period)); + ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_prune_interval", + __stringify(DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL), + OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_prune_interval)); + ast_sorcery_object_field_register(sorcery, "global", "default_realm", DEFAULT_REALM, + OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_realm)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index baa5063e43c..c370ab75f39 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -476,6 +476,16 @@ static int ident_handler(const struct aco_option *opt, struct ast_variable *var, struct ast_sip_endpoint *endpoint = obj; char *idents = ast_strdupa(var->value); char *val; + enum ast_sip_endpoint_identifier_type method; + + /* + * If there's already something in the vector when we get here, + * it's the default value so we need to clean it out. + */ + if (AST_VECTOR_SIZE(&endpoint->ident_method_order)) { + AST_VECTOR_RESET(&endpoint->ident_method_order, AST_VECTOR_ELEM_CLEANUP_NOOP); + endpoint->ident_method = 0; + } while ((val = ast_strip(strsep(&idents, ",")))) { if (ast_strlen_zero(val)) { @@ -483,27 +493,55 @@ static int ident_handler(const struct aco_option *opt, struct ast_variable *var, } if (!strcasecmp(val, "username")) { - endpoint->ident_method |= AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME; + method = AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME; + } else if (!strcasecmp(val, "auth_username")) { + method = AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME; } else { ast_log(LOG_ERROR, "Unrecognized identification method %s specified for endpoint %s\n", val, ast_sorcery_object_get_id(endpoint)); + AST_VECTOR_RESET(&endpoint->ident_method_order, AST_VECTOR_ELEM_CLEANUP_NOOP); + endpoint->ident_method = 0; return -1; } + + endpoint->ident_method |= method; + AST_VECTOR_APPEND(&endpoint->ident_method_order, method); } + return 0; } static int ident_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_endpoint *endpoint = obj; - switch (endpoint->ident_method) { - case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME : - *buf = "username"; break; - default: + int methods; + char *method; + int i; + int j = 0; + + methods = AST_VECTOR_SIZE(&endpoint->ident_method_order); + if (!methods) { return 0; } - *buf = ast_strdup(*buf); + if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) { + return -1; + } + + for (i = 0; i < methods; i++) { + switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) { + case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME : + method = "username"; + break; + case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME : + method = "auth_username"; + break; + default: + continue; + } + j = sprintf(*buf + j, "%s%s", method, i < methods - 1 ? "," : ""); + } + return 0; } @@ -1849,6 +1887,7 @@ static void endpoint_destructor(void* obj) endpoint->pickup.named_pickupgroups = ast_unref_namedgroups(endpoint->pickup.named_pickupgroups); ao2_cleanup(endpoint->persistent); ast_variables_destroy(endpoint->channel_vars); + AST_VECTOR_FREE(&endpoint->ident_method_order); } static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription) @@ -1893,6 +1932,11 @@ void *ast_sip_endpoint_alloc(const char *name) return NULL; } ast_party_id_init(&endpoint->id.self); + + if (AST_VECTOR_INIT(&endpoint->ident_method_order, 1)) { + return NULL; + } + return endpoint; } diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 834ca10d39f..cbe95572807 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -24,6 +24,7 @@ #include "include/res_pjsip_private.h" #include "asterisk/taskprocessor.h" #include "asterisk/threadpool.h" +#include "asterisk/res_pjsip_cli.h" static int distribute(void *data); static pj_bool_t distributor(pjsip_rx_data *rdata); @@ -37,6 +38,26 @@ static pjsip_module distributor_mod = { .on_rx_response = distributor, }; +struct ast_sched_context *prune_context; + +/* From the auth/realm realtime column size */ +#define MAX_REALM_LENGTH 40 +static char default_realm[MAX_REALM_LENGTH + 1]; + +#define DEFAULT_SUSPECTS_BUCKETS 53 + +static struct ao2_container *unidentified_requests; +static unsigned int unidentified_count; +static unsigned int unidentified_period; +static unsigned int unidentified_prune_interval; +static int using_auth_username; + +struct unidentified_request{ + struct timeval first_seen; + int count; + char src_name[]; +}; + /*! * \internal * \brief Record the task's serializer name on the tdata structure. @@ -322,7 +343,7 @@ static int create_artificial_auth(void) return -1; } - ast_string_field_set(artificial_auth, realm, "asterisk"); + ast_string_field_set(artificial_auth, realm, default_realm); ast_string_field_set(artificial_auth, auth_user, ""); ast_string_field_set(artificial_auth, auth_pass, ""); artificial_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL; @@ -359,27 +380,65 @@ struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void) return artificial_endpoint; } -static void log_unidentified_request(pjsip_rx_data *rdata) +static void log_unidentified_request(pjsip_rx_data *rdata, unsigned int count, unsigned int period) { char from_buf[PJSIP_MAX_URL_SIZE]; char callid_buf[PJSIP_MAX_URL_SIZE]; pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.from->uri, from_buf, PJSIP_MAX_URL_SIZE); ast_copy_pj_str(callid_buf, &rdata->msg_info.cid->id, PJSIP_MAX_URL_SIZE); - ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found\n", - from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf); + if (count) { + ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found" + " after %u tries in %.3f ms\n", + from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, count, period / 1000.0); + } else { + ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found", + from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf); + } +} + +static void check_endpoint(pjsip_rx_data *rdata, struct unidentified_request *unid, + const char *name) +{ + int64_t ms = ast_tvdiff_ms(ast_tvnow(), unid->first_seen); + + ao2_wrlock(unid); + unid->count++; + + if (ms < (unidentified_period * 1000) && unid->count >= unidentified_count) { + log_unidentified_request(rdata, unid->count, ms); + ast_sip_report_invalid_endpoint(name, rdata); + } + ao2_unlock(unid); } static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) { struct ast_sip_endpoint *endpoint; + struct unidentified_request *unid; int is_ack = rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD; endpoint = rdata->endpt_info.mod_data[endpoint_mod.id]; if (endpoint) { + /* + * ao2_find with OBJ_UNLINK always write locks the container before even searching + * for the object. Since the majority case is that the object won't be found, do + * the find without OBJ_UNLINK to prevent the unnecessary write lock, then unlink + * if needed. + */ + if ((unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY))) { + ao2_unlink(unidentified_requests, unid); + ao2_ref(unid, -1); + } return PJ_FALSE; } endpoint = ast_sip_identify_endpoint(rdata); + if (endpoint) { + if ((unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY))) { + ao2_unlink(unidentified_requests, unid); + ao2_ref(unid, -1); + } + } if (!endpoint && !is_ack) { char name[AST_UUID_STR_LEN] = ""; @@ -397,8 +456,32 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) ast_copy_pj_str(name, &sip_from->user, sizeof(name)); } - log_unidentified_request(rdata); - ast_sip_report_invalid_endpoint(name, rdata); + if ((unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY))) { + check_endpoint(rdata, unid, name); + ao2_ref(unid, -1); + } else if (using_auth_username) { + ao2_wrlock(unidentified_requests); + /* The check again with the write lock held allows us to eliminate the DUPS_REPLACE and sort_fn */ + if ((unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) { + check_endpoint(rdata, unid, name); + } else { + unid = ao2_alloc_options(sizeof(*unid) + strlen(rdata->pkt_info.src_name) + 1, NULL, + AO2_ALLOC_OPT_LOCK_RWLOCK); + if (!unid) { + ao2_unlock(unidentified_requests); + return PJ_TRUE; + } + strcpy(unid->src_name, rdata->pkt_info.src_name); /* Safe */ + unid->first_seen = ast_tvnow(); + unid->count = 1; + ao2_link_flags(unidentified_requests, unid, OBJ_NOLOCK); + } + ao2_ref(unid, -1); + ao2_unlock(unidentified_requests); + } else { + log_unidentified_request(rdata, 0, 0); + ast_sip_report_invalid_endpoint(name, rdata); + } } rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint; return PJ_FALSE; @@ -413,6 +496,8 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) if (!is_ack && ast_sip_requires_authentication(endpoint, rdata)) { pjsip_tx_data *tdata; + struct unidentified_request *unid; + pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 401, NULL, &tdata); switch (ast_sip_check_authentication(endpoint, rdata, tdata)) { case AST_SIP_AUTHENTICATION_CHALLENGE: @@ -421,6 +506,11 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); return PJ_TRUE; case AST_SIP_AUTHENTICATION_SUCCESS: + /* See note in endpoint_lookup about not holding an unnecessary write lock */ + if ((unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY))) { + ao2_unlink(unidentified_requests, unid); + ao2_ref(unid, -1); + } ast_sip_report_auth_success(endpoint, rdata); pjsip_tx_data_dec_ref(tdata); return PJ_FALSE; @@ -480,31 +570,287 @@ struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata) return endpoint; } +static int suspects_sort(const void *obj, const void *arg, int flags) +{ + const struct unidentified_request *object_left = obj; + const struct unidentified_request *object_right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->src_name; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcmp(object_left->src_name, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncmp(object_left->src_name, right_key, strlen(right_key)); + break; + default: + cmp = 0; + break; + } + return cmp; +} + +static int suspects_compare(void *obj, void *arg, int flags) +{ + const struct unidentified_request *object_left = obj; + const struct unidentified_request *object_right = arg; + const char *right_key = arg; + int cmp = 0; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->src_name; + /* Fall through */ + case OBJ_SEARCH_KEY: + if (strcmp(object_left->src_name, right_key) == 0) { + cmp = CMP_MATCH | CMP_STOP; + } + break; + case OBJ_SEARCH_PARTIAL_KEY: + if (strncmp(object_left->src_name, right_key, strlen(right_key)) == 0) { + cmp = CMP_MATCH; + } + break; + default: + cmp = 0; + break; + } + return cmp; +} + +static int suspects_hash(const void *obj, int flags) { + const struct unidentified_request *object_left = obj; + + if (flags & OBJ_SEARCH_OBJECT) { + return ast_str_hash(object_left->src_name); + } else if (flags & OBJ_SEARCH_KEY) { + return ast_str_hash(obj); + } + return -1; +} + +static struct ao2_container *cli_unid_get_container(const char *regex) +{ + struct ao2_container *s_container; + + s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, + suspects_sort, suspects_compare); + if (!s_container) { + return NULL; + } + + if (ao2_container_dup(s_container, unidentified_requests, 0)) { + ao2_ref(s_container, -1); + return NULL; + } + + return s_container; +} + +static int cli_unid_iterate(void *container, ao2_callback_fn callback, void *args) +{ + ao2_callback(container, 0, callback, args); + + return 0; +} + +static void *cli_unid_retrieve_by_id(const char *id) +{ + return ao2_find(unidentified_requests, id, OBJ_SEARCH_KEY); +} + +static const char *cli_unid_get_id(const void *obj) +{ + const struct unidentified_request *unid = obj; + + return unid->src_name; +} + +static int cli_unid_print_header(void *obj, void *arg, int flags) +{ + struct ast_sip_cli_context *context = arg; + RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup); + + int indent = CLI_INDENT_TO_SPACES(context->indent_level); + int filler = CLI_LAST_TABSTOP - indent - 7; + + ast_assert(context->output_buffer != NULL); + + ast_str_append(&context->output_buffer, 0, + "%*s: \n", + indent, "Request", filler, filler, CLI_HEADER_FILLER); + + return 0; +} +static int cli_unid_print_body(void *obj, void *arg, int flags) +{ + struct unidentified_request *unid = obj; + struct ast_sip_cli_context *context = arg; + int indent; + int flexwidth; + int64_t ms = ast_tvdiff_ms(ast_tvnow(), unid->first_seen); + + ast_assert(context->output_buffer != NULL); + + indent = CLI_INDENT_TO_SPACES(context->indent_level); + flexwidth = CLI_LAST_TABSTOP - 4; + + ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %7d %10.3f\n", + indent, + "Request", + flexwidth, flexwidth, + unid->src_name, unid->count, ms / 1000.0); + + return 0; +} + +static struct ast_cli_entry cli_commands[] = { + AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Unidentified Requests", + .command = "pjsip show unidentified_requests", + .usage = "Usage: pjsip show unidentified_requests\n" + " Show the PJSIP Unidentified Requests\n"), +}; + +struct ast_sip_cli_formatter_entry *unid_formatter; + +static int expire_requests(void *object, void *arg, int flags) +{ + struct unidentified_request *unid = object; + int *maxage = arg; + int64_t ms = ast_tvdiff_ms(ast_tvnow(), unid->first_seen); + + if (ms > (*maxage) * 2 * 1000) { + return CMP_MATCH; + } + + return 0; +} + +static int prune_task(const void *data) +{ + unsigned int maxage; + + ast_sip_get_unidentified_request_thresholds(&unidentified_count, &unidentified_period, &unidentified_prune_interval); + maxage = unidentified_period * 2; + ao2_callback(unidentified_requests, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, expire_requests, &maxage); + + return unidentified_prune_interval * 1000; +} + +static int clean_task(const void *data) +{ + return 0; +} + +static void global_loaded(const char *object_type) +{ + char *identifier_order = ast_sip_get_endpoint_identifier_order(); + char *io_copy = ast_strdupa(identifier_order); + char *identify_method; + + ast_free(identifier_order); + using_auth_username = 0; + while ((identify_method = ast_strip(strsep(&io_copy, ",")))) { + if (!strcmp(identify_method, "auth_username")) { + using_auth_username = 1; + break; + } + } + + ast_sip_get_default_realm(default_realm, sizeof(default_realm)); + ast_sip_get_unidentified_request_thresholds(&unidentified_count, &unidentified_period, &unidentified_prune_interval); + + /* Clean out the old task, if any */ + ast_sched_clean_by_callback(prune_context, prune_task, clean_task); + if (ast_sched_add_variable(prune_context, unidentified_prune_interval * 1000, prune_task, NULL, 1) < 0) { + return; + } +} + +/*! \brief Observer which is used to update our interval and default_realm when the global setting changes */ +static struct ast_sorcery_observer global_observer = { + .loaded = global_loaded, +}; + + int ast_sip_initialize_distributor(void) { + unidentified_requests = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, + DEFAULT_SUSPECTS_BUCKETS, suspects_hash, NULL, suspects_compare); + if (!unidentified_requests) { + return -1; + } + + prune_context = ast_sched_context_create(); + if (!prune_context) { + ast_sip_destroy_distributor(); + return -1; + } + + if (ast_sched_start_thread(prune_context)) { + ast_sip_destroy_distributor(); + return -1; + } + + ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer); + ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); + if (create_artificial_endpoint() || create_artificial_auth()) { + ast_sip_destroy_distributor(); return -1; } if (internal_sip_register_service(&distributor_mod)) { + ast_sip_destroy_distributor(); return -1; } if (internal_sip_register_service(&endpoint_mod)) { + ast_sip_destroy_distributor(); return -1; } if (internal_sip_register_service(&auth_mod)) { + ast_sip_destroy_distributor(); return -1; } + unid_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); + if (!unid_formatter) { + ast_log(LOG_ERROR, "Unable to allocate memory for unid_formatter\n"); + return -1; + } + unid_formatter->name = "unidentified_request"; + unid_formatter->print_header = cli_unid_print_header; + unid_formatter->print_body = cli_unid_print_body; + unid_formatter->get_container = cli_unid_get_container; + unid_formatter->iterate = cli_unid_iterate; + unid_formatter->get_id = cli_unid_get_id; + unid_formatter->retrieve_by_id = cli_unid_retrieve_by_id; + ast_sip_register_cli_formatter(unid_formatter); + ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + return 0; } void ast_sip_destroy_distributor(void) { + ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); + ast_sip_unregister_cli_formatter(unid_formatter); + internal_sip_unregister_service(&distributor_mod); internal_sip_unregister_service(&endpoint_mod); internal_sip_unregister_service(&auth_mod); ao2_cleanup(artificial_auth); ao2_cleanup(artificial_endpoint); + ao2_cleanup(unidentified_requests); + + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); + + if (prune_context) { + ast_sched_context_destroy(prune_context); + } } diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c index e610bb80446..4a31edfc46f 100644 --- a/res/res_pjsip_authenticator_digest.c +++ b/res/res_pjsip_authenticator_digest.c @@ -31,6 +31,10 @@ core ***/ +/* From the auth/realm realtime column size */ +#define MAX_REALM_LENGTH 40 +static char default_realm[MAX_REALM_LENGTH + 1]; + AO2_GLOBAL_OBJ_STATIC(entity_id); /*! @@ -409,7 +413,7 @@ static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint for (i = 0; i < auth_size; ++i) { if (ast_strlen_zero(auths[i]->realm)) { - ast_string_field_set(auths[i], realm, "asterisk"); + ast_string_field_set(auths[i], realm, default_realm); } verify_res[i] = verify(auths[i], rdata, tdata->pool); if (verify_res[i] == AUTH_SUCCESS) { @@ -456,6 +460,16 @@ static int build_entity_id(void) return 0; } +static void global_loaded(const char *object_type) +{ + ast_sip_get_default_realm(default_realm, sizeof(default_realm)); +} + +/*! \brief Observer which is used to update our default_realm when the global setting changes */ +static struct ast_sorcery_observer global_observer = { + .loaded = global_loaded, +}; + static int reload_module(void) { if (build_entity_id()) { @@ -471,6 +485,10 @@ static int load_module(void) if (build_entity_id()) { return AST_MODULE_LOAD_DECLINE; } + + ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer); + ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); + if (ast_sip_register_authenticator(&digest_authenticator)) { ao2_global_obj_release(entity_id); return AST_MODULE_LOAD_DECLINE; @@ -480,6 +498,7 @@ static int load_module(void) static int unload_module(void) { + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); ast_sip_unregister_authenticator(&digest_authenticator); ao2_global_obj_release(entity_id); return 0; diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c index 12af2edb98e..172566a9fdb 100644 --- a/res/res_pjsip_endpoint_identifier_user.c +++ b/res/res_pjsip_endpoint_identifier_user.c @@ -29,7 +29,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/module.h" -static int get_endpoint_details(pjsip_rx_data *rdata, char *endpoint, size_t endpoint_size, char *domain, size_t domain_size) +static int get_from_header(pjsip_rx_data *rdata, char *username, size_t username_size, char *domain, size_t domain_size) { pjsip_uri *from = rdata->msg_info.from->uri; pjsip_sip_uri *sip_from; @@ -37,11 +37,28 @@ static int get_endpoint_details(pjsip_rx_data *rdata, char *endpoint, size_t end return -1; } sip_from = (pjsip_sip_uri *) pjsip_uri_get_uri(from); - ast_copy_pj_str(endpoint, &sip_from->user, endpoint_size); + ast_copy_pj_str(username, &sip_from->user, username_size); ast_copy_pj_str(domain, &sip_from->host, domain_size); return 0; } +static pjsip_authorization_hdr *get_auth_header(pjsip_rx_data *rdata, char *username, + size_t username_size, char *realm, size_t realm_size, pjsip_authorization_hdr *start) +{ + pjsip_authorization_hdr *header; + + header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, start); + + if (!header || pj_stricmp2(&header->scheme, "digest")) { + return NULL; + } + + ast_copy_pj_str(username, &header->credential.digest.username, username_size); + ast_copy_pj_str(realm, &header->credential.digest.realm, realm_size); + + return header; +} + static int find_transport_state_in_use(void *obj, void *arg, int flags) { struct ast_sip_transport_state *transport_state = obj; @@ -56,34 +73,30 @@ static int find_transport_state_in_use(void *obj, void *arg, int flags) return 0; } -static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) +static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoint_name, + char *domain_name) { - char endpoint_name[64], domain_name[64], id[AST_UUID_STR_LEN]; + char id[AST_UUID_STR_LEN]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); - if (get_endpoint_details(rdata, endpoint_name, sizeof(endpoint_name), domain_name, sizeof(domain_name))) { - return NULL; - } - if (!ast_sip_get_disable_multi_domain()) { /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { - goto done; + return endpoint; } /* See if an alias exists for the domain provided */ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { - goto done; + return endpoint; } } - /* See if the transport this came in on has a provided domain */ if ((transport_states = ast_sip_get_transport_states()) && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata)) @@ -91,41 +104,95 @@ static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "anonymous@%s", transport->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { - goto done; + return endpoint; } } } /* Fall back to no domain */ - endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name); + return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name); +} -done: - if (endpoint) { - if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME)) { - ao2_ref(endpoint, -1); - return NULL; - } - ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint)); - } else { - ast_debug(3, "Could not identify endpoint by username '%s'\n", endpoint_name); +static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) +{ + char username[64], domain[64]; + struct ast_sip_endpoint *endpoint; + + if (get_from_header(rdata, username, sizeof(username), domain, sizeof(domain))) { + return NULL; + } + ast_debug(3, "Attempting identify by From username '%s' domain '%s'\n", username, domain); + + endpoint = find_endpoint(rdata, username, domain); + if (!endpoint) { + ast_debug(3, "Endpoint not found for From username '%s' domain '%s'\n", username, domain); + ao2_cleanup(endpoint); + return NULL; + } + if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME)) { + ast_debug(3, "Endpoint found for '%s' but 'username' method not supported'\n", username); + ao2_cleanup(endpoint); + return NULL; } + ast_debug(3, "Identified by From username '%s' domain '%s'\n", username, domain); + return endpoint; } +static struct ast_sip_endpoint *auth_username_identify(pjsip_rx_data *rdata) +{ + char username[64], realm[64]; + struct ast_sip_endpoint *endpoint; + pjsip_authorization_hdr *auth_header = NULL; + + while ((auth_header = get_auth_header(rdata, username, sizeof(username), realm, sizeof(realm), + auth_header ? auth_header->next : NULL))) { + ast_debug(3, "Attempting identify by Authorization username '%s' realm '%s'\n", username, + realm); + + endpoint = find_endpoint(rdata, username, realm); + if (!endpoint) { + ast_debug(3, "Endpoint not found for Authentication username '%s' realm '%s'\n", + username, realm); + ao2_cleanup(endpoint); + continue; + } + if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME)) { + ast_debug(3, "Endpoint found for '%s' but 'auth_username' method not supported'\n", + username); + ao2_cleanup(endpoint); + continue; + } + ast_debug(3, "Identified by Authorization username '%s' realm '%s'\n", username, realm); + + return endpoint; + } + + return NULL; +} + + static struct ast_sip_endpoint_identifier username_identifier = { .identify_endpoint = username_identify, }; +static struct ast_sip_endpoint_identifier auth_username_identifier = { + .identify_endpoint = auth_username_identify, +}; + + static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); ast_sip_register_endpoint_identifier_with_name(&username_identifier, "username"); + ast_sip_register_endpoint_identifier_with_name(&auth_username_identifier, "auth_username"); return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { + ast_sip_unregister_endpoint_identifier(&auth_username_identifier); ast_sip_unregister_endpoint_identifier(&username_identifier); return 0; } diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 8edd6ee4377..ae8440aabe7 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -657,6 +657,65 @@ static int rx_task(void *data) return res; } +static int match_aor(const char *aor_name, const char *id) +{ + if (ast_strlen_zero(aor_name)) { + return 0; + } + + if (!strcmp(aor_name, id)) { + ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name); + return 1; + } + + return 0; +} + +static char *find_aor_name(const char *username, const char *domain, const char *aors) +{ + char *configured_aors; + char *aor_name; + char *id_domain; + struct ast_sip_domain_alias *alias; + + id_domain = ast_alloca(strlen(username) + strlen(domain) + 2); + sprintf(id_domain, "%s@%s", username, domain); + + /* Look for exact match on username@domain */ + configured_aors = ast_strdupa(aors); + while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { + if (match_aor(aor_name, id_domain)) { + return ast_strdup(aor_name); + } + } + + /* If there's a domain alias, look for exact match on username@domain_alias */ + alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain); + if (alias) { + char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2); + + sprintf(id_domain, "%s@%s", username, alias->domain); + ao2_cleanup(alias); + + configured_aors = ast_strdupa(aors); + while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { + if (match_aor(aor_name, id_domain_alias)) { + return ast_strdup(aor_name); + } + } + } + + /* Look for exact match on username only */ + configured_aors = ast_strdupa(aors); + while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { + if (match_aor(aor_name, username)) { + return ast_strdup(aor_name); + } + } + + return NULL; +} + static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) { RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup); @@ -665,10 +724,10 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup); RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup); - pjsip_sip_uri *uri; - char *domain_name; - char *configured_aors, *aor_name; - RAII_VAR(struct ast_str *, id, NULL, ast_free); + char *domain_name = NULL; + char *username = NULL; + RAII_VAR(char *, aor_name, NULL, ast_free); + int i; if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) { return PJ_FALSE; @@ -689,38 +748,46 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) return PJ_TRUE; } - uri = pjsip_uri_get_uri(rdata->msg_info.to->uri); - domain_name = ast_alloca(uri->host.slen + 1); - ast_copy_pj_str(domain_name, &uri->host, uri->host.slen + 1); + for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); i++) { + pjsip_sip_uri *uri; + pjsip_authorization_hdr *header = NULL; - configured_aors = ast_strdupa(endpoint->aors); + switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) { + case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME : + uri = pjsip_uri_get_uri(rdata->msg_info.to->uri); - /* Iterate the configured AORs to see if the user or the user+domain match */ - while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { - struct ast_sip_domain_alias *alias = NULL; + domain_name = ast_alloca(uri->host.slen + 1); + ast_copy_pj_str(domain_name, &uri->host, uri->host.slen + 1); + username = ast_alloca(uri->user.slen + 1); + ast_copy_pj_str(username, &uri->user, uri->user.slen + 1); - if (ast_strlen_zero(aor_name)) { - continue; - } - - if (!pj_strcmp2(&uri->user, aor_name)) { + aor_name = find_aor_name(username, domain_name, endpoint->aors); + if (aor_name) { + ast_debug(3, "Matched aor '%s' by To username\n", aor_name); + } break; + case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME : + while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, + header ? header->next : NULL))) { + if (header && !pj_stricmp2(&header->scheme, "digest")) { + username = ast_alloca(header->credential.digest.username.slen + 1); + ast_copy_pj_str(username, &header->credential.digest.username, header->credential.digest.username.slen + 1); + domain_name = ast_alloca(header->credential.digest.realm.slen + 1); + ast_copy_pj_str(domain_name, &header->credential.digest.realm, header->credential.digest.realm.slen + 1); + + aor_name = find_aor_name(username, domain_name, endpoint->aors); + if (aor_name) { + ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name); + break; + } + } + } + break; + default: + continue; } - if (!id && !(id = ast_str_create(uri->user.slen + uri->host.slen + 2))) { - return PJ_TRUE; - } - - ast_str_set(&id, 0, "%.*s@", (int)uri->user.slen, uri->user.ptr); - if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { - ast_str_append(&id, 0, "%s", alias->domain); - ao2_cleanup(alias); - } else { - ast_str_append(&id, 0, "%s", domain_name); - } - - if (!strcmp(aor_name, ast_str_buffer(id))) { - ast_free(id); + if (aor_name) { break; } } @@ -729,7 +796,7 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) /* The provided AOR name was not found (be it within the configuration or sorcery itself) */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found"); - ast_log(LOG_WARNING, "AOR '%.*s' not found for endpoint '%s'\n", (int)uri->user.slen, uri->user.ptr, ast_sorcery_object_get_id(endpoint)); + ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", username, ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } From 76ea4cfaaeec33328b0852fa9e37682f29569ba4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 25 Apr 2016 16:00:30 -0500 Subject: [PATCH 0387/1578] res_pjsip_outbound_publish.c: Remove redundant flag check. Change-Id: I0da80a3c3e0eae0c52ff27e7412ba027d6f52353 --- res/res_pjsip_outbound_publish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 5b27bdf0dd5..0fe2e3e5d80 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -389,7 +389,7 @@ static void sip_outbound_publish_synchronize(struct ast_sip_event_publisher_hand } else { state->client->started = 1; } - } else if (state->client->started && !handler && removed && !strcmp(publish->event, removed->event_name)) { + } else if (!handler && removed && !strcmp(publish->event, removed->event_name)) { /* If the publisher client has been started but it is going away stop it */ removed->stop_publishing(state->client); state->client->started = 0; From 906ea2c43f12c3c4c18f81fa007fc4cb295251e0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 26 Apr 2016 15:13:50 -0500 Subject: [PATCH 0388/1578] res_pjsip_pubsub.h: Fix doxygen association. Change-Id: I110d3e3572598289fcd4215d966cf0c858f98632 --- include/asterisk/res_pjsip_pubsub.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h index 84d86fb9ef4..94576d38b04 100644 --- a/include/asterisk/res_pjsip_pubsub.h +++ b/include/asterisk/res_pjsip_pubsub.h @@ -214,9 +214,9 @@ enum ast_sip_subscription_notify_reason { AST_SIP_SUBSCRIPTION_NOTIFY_REASON_OTHER }; -/*! Type used for conveying mailbox state */ -#define AST_SIP_EXTEN_STATE_DATA "ast_sip_exten_state_data" /*! Type used for extension state/presence */ +#define AST_SIP_EXTEN_STATE_DATA "ast_sip_exten_state_data" +/*! Type used for conveying mailbox state */ #define AST_SIP_MESSAGE_ACCUMULATOR "ast_sip_message_accumulator" /*! From 30415944a861b9f025ac68efabbb4eb7774c7491 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 28 Apr 2016 15:54:07 -0600 Subject: [PATCH 0389/1578] pjproject_bundled: Disable PJSIP_UNESCAPE_IN_PLACE When pjsip_parse_uri is called with PJSIP_UNESCAPE_IN_PLACE enabled, the input uri string will become corrupted if it contains escape sequences. It's not possible to automatically strdup or strdupa the input string because the output uri pj_str_t's will have pointers to chunks of the input string. Getting around this would require more memory management code and wouldn't be worth the savings of doing the unescape in place. ASTERISK-25970 #close Reported-by: Dmitriy Serov Change-Id: I28dc0e599b5108f7959b9c46dc8278371b372f88 --- third-party/pjproject/patches/config_site.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 840d8b279c8..8e854b72324 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -28,7 +28,11 @@ #define PJSIP_SAFE_MODULE 0 #define PJ_HAS_STRICMP_ALNUM 0 #define PJ_HASH_USE_OWN_TOLOWER 1 -#define PJSIP_UNESCAPE_IN_PLACE 1 +/* + It is imperative that PJSIP_UNESCAPE_IN_PLACE remain 0 or undefined. + Enabling it will result in SEGFAULTS when URIs containing escape sequences are encountered. +*/ +#undef PJSIP_UNESCAPE_IN_PLACE #define PJSIP_MAX_PKT_LEN 6000 #undef PJ_TODO From 8e1b663b874606defc2d3defdacc0ca77efc7092 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 26 Apr 2016 15:58:06 -0500 Subject: [PATCH 0390/1578] res_pjsip_pubsub.c: Fix body generator registration race. Change-Id: Id8752073ef06472a2fd96080f4009fac42843e67 --- res/res_pjsip_pubsub.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 141c2fcf405..97fe45a24a7 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -2541,20 +2541,28 @@ void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler AST_RWLIST_TRAVERSE_SAFE_END; } -static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype(const char *content_type, - const char *content_subtype) +static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype_nolock(const char *type, const char *subtype) { - struct ast_sip_pubsub_body_generator *iter; - SCOPED_LOCK(lock, &body_generators, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + struct ast_sip_pubsub_body_generator *gen; - AST_LIST_TRAVERSE(&body_generators, iter, list) { - if (!strcmp(iter->type, content_type) && - !strcmp(iter->subtype, content_subtype)) { + AST_LIST_TRAVERSE(&body_generators, gen, list) { + if (!strcmp(gen->type, type) + && !strcmp(gen->subtype, subtype)) { break; } - }; + } - return iter; + return gen; +} + +static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype(const char *type, const char *subtype) +{ + struct ast_sip_pubsub_body_generator *gen; + + AST_RWLIST_RDLOCK(&body_generators); + gen = find_body_generator_type_subtype_nolock(type, subtype); + AST_RWLIST_UNLOCK(&body_generators); + return gen; } static struct ast_sip_pubsub_body_generator *find_body_generator_accept(const char *accept) @@ -3092,14 +3100,14 @@ int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator pj_str_t accept; pj_size_t accept_len; - existing = find_body_generator_type_subtype(generator->type, generator->subtype); + AST_RWLIST_WRLOCK(&body_generators); + existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype); if (existing) { - ast_log(LOG_WARNING, "Cannot register body generator of %s/%s." - "One is already registered.\n", generator->type, generator->subtype); + AST_RWLIST_UNLOCK(&body_generators); + ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n", + generator->type, generator->subtype); return -1; } - - AST_RWLIST_WRLOCK(&body_generators); AST_LIST_INSERT_HEAD(&body_generators, generator, list); AST_RWLIST_UNLOCK(&body_generators); From 3af83ea2fb4a670ca98c635a0c05a9cdb6559251 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 28 Apr 2016 16:06:57 -0500 Subject: [PATCH 0391/1578] res_pjsip_pubsub.c: Add useful information to some messages. Change-Id: Ia0b2e15773894c599e5c5748bbc70e99f434192a --- res/res_pjsip_pubsub.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 141c2fcf405..b88d7af2939 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -3179,14 +3179,15 @@ int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype, } if (strcmp(data->body_type, generator->body_type)) { - ast_log(LOG_WARNING, "Body generator does not accept the type of data provided\n"); + ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n", + type, subtype); return -1; } body = generator->allocate_body(data->body_data); if (!body) { - ast_log(LOG_WARNING, "Unable to allocate a NOTIFY body of type %s/%s\n", - type, subtype); + ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n", + type, subtype); return -1; } From 369182d0847c256afeea36e62dba0a48c5f6ea30 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 28 Apr 2016 11:35:44 -0500 Subject: [PATCH 0392/1578] res_pjsip: Start body generator users after suppliers. Change-Id: I8f0b57841feaab56c8a4e821b5ccb4e05e5fbadb --- res/res_pjsip_exten_state.c | 2 +- res/res_pjsip_mwi.c | 2 +- res/res_pjsip_publish_asterisk.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 1f8b121e85f..555402469e0 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -806,5 +806,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, ); diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index f9bfc1904d9..9eba335b542 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -1231,5 +1231,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP MWI resource", .load = load_module, .unload = unload_module, .reload = reload, - .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, ); diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 50d4cc38723..3218b0a0cd3 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -926,5 +926,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Asterisk Event .load = load_module, .reload = reload_module, .unload = unload_module, - .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, ); From 0b5292525cce32e9944b02b17748c4c7ec89ede3 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 26 Apr 2016 16:10:26 -0500 Subject: [PATCH 0393/1578] res_pjsip_exten_state: Check if body generator is available. When starting the extension state publishers, check if the requested message body generator is available. If not available give error message and skip starting that publisher. * res_pjsip_pubsub.c: Create new API if type/subtype generator registered. * res_pjsip_exten_state.c: Use new body generator API for validation. ASTERISK-25922 Change-Id: I4ad69200666e3cc909d4619e3c81042d7f9db25c --- include/asterisk/res_pjsip_pubsub.h | 13 +++++++++++++ res/res_pjsip_exten_state.c | 6 ++++++ res/res_pjsip_pubsub.c | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h index 84d86fb9ef4..72a3053f27e 100644 --- a/include/asterisk/res_pjsip_pubsub.h +++ b/include/asterisk/res_pjsip_pubsub.h @@ -648,6 +648,19 @@ struct ast_sip_pubsub_body_supplement { int ast_sip_pubsub_generate_body_content(const char *content_type, const char *content_subtype, struct ast_sip_body_data *data, struct ast_str **str); +/*! + * \brief Is a body generator registered for the given type/subtype. + * \since 14.0.0 + * + * \param type The content type of the body + * \param subtype The content subtype of the body + * + * \note In "plain/text", "plain" is the type and "text" is the subtype. + * + * \retval non-zero if a generator is registered. + */ +int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype); + /*! * \since 13.0.0 * \brief Register a body generator with the pubsub core. diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 1f8b121e85f..e84a25c6ae4 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -680,6 +680,12 @@ static int publisher_start(struct ast_sip_outbound_publish *configuration, struc return -1; } + if (!ast_sip_pubsub_is_body_generator_registered(body_type, body_subtype)) { + ast_log(LOG_ERROR, "Outbound extension state publisher '%s': '%s' body generator not registered\n", + name, body_full); + return -1; + } + name_size = strlen(name) + 1; body_type_size = strlen(body_type) + 1; body_subtype_size = strlen(body_subtype) + 1; diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 141c2fcf405..dca2e310972 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -3086,6 +3086,11 @@ const char *ast_sip_publication_get_event_configuration(const struct ast_sip_pub return pub->event_configuration_name; } +int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype) +{ + return !!find_body_generator_type_subtype(type, subtype); +} + int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator) { struct ast_sip_pubsub_body_generator *existing; From 2c46063d54e41f3fad81eafb7d24f0308034bd96 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 27 Apr 2016 17:19:53 -0500 Subject: [PATCH 0394/1578] res_pjsip_exten_state: Create PUBLISH messages. Create PUBLISH messages to update a third party when an extension state changes because of either a device or presence state change. A configuration example: [exten-state-publisher] type=outbound-publish server_uri=sip:instance1@172.16.10.2 event=presence ; Optional regex for context filtering, if specified only extension state ; for contexts matching the regex will cause a PUBLISH to be sent. @context=^users ; Optional regex for extension filtering, if specified only extension ; state for extensions matching the regex will cause a PUBLISH to be sent. @exten=^[0-9]* ; Required body type for the PUBLISH message. ; ; Supported values are: ; application/pidf+xml ; application/xpidf+xml ; application/cpim-pidf+xml ; application/dialog-info+xml (Planned support but not yet) @body=application/pidf+xml The '@' extended variables are used because the implementation can't extend the outbound publish type as it is provided by the outbound publish module. That means you either have to use extended variables, or implement some sort of custom extended variable thing in the outbound publish module. Another option would be to refactor that stuff to have an option which specifies the use of an alternate implementation's configuration and then have that passed to the implementation. JColp opted for the extended variables method originally. ASTERISK-25972 #close Change-Id: Ic0dab4022f5cf59302129483ed38398764ee3cca --- include/asterisk/res_pjsip_outbound_publish.h | 22 +++ res/res_pjsip_exten_state.c | 182 +++++++++++++++++- res/res_pjsip_outbound_publish.c | 14 ++ 3 files changed, 216 insertions(+), 2 deletions(-) diff --git a/include/asterisk/res_pjsip_outbound_publish.h b/include/asterisk/res_pjsip_outbound_publish.h index debec9413e0..b2038f58b03 100644 --- a/include/asterisk/res_pjsip_outbound_publish.h +++ b/include/asterisk/res_pjsip_outbound_publish.h @@ -92,6 +92,28 @@ void ast_sip_unregister_event_publisher_handler(struct ast_sip_event_publisher_h */ struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name); +/*! + * \brief Get the From URI the client will use. + * \since 14.0.0 + * + * \param client The publication client to get the From URI + * + * \retval From-uri on success + * \retval Empty-string on failure + */ +const char *ast_sip_publish_client_get_from_uri(struct ast_sip_outbound_publish_client *client); + +/*! + * \brief Get the To URI the client will use. + * \since 14.0.0 + * + * \param client The publication client to get the To URI + * + * \retval From-uri on success + * \retval Empty-string on failure + */ +const char *ast_sip_publish_client_get_to_uri(struct ast_sip_outbound_publish_client *client); + /*! * \brief Alternative for ast_datastore_alloc() * diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 6b4e758d3d1..76a88a29cf7 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -56,6 +56,9 @@ */ static struct ao2_container *publishers; +/*! Serializer for outbound extension state publishing. */ +static struct ast_taskprocessor *publish_exten_state_serializer; + /*! * \brief A subscription for extension state * @@ -542,6 +545,142 @@ static void to_ami(struct ast_sip_subscription *sub, exten_state_sub->last_exten_state)); } +struct exten_state_pub_data { + /*! Publishers needing state update */ + AST_VECTOR(name, struct exten_state_publisher *) pubs; + /*! Body generator state data */ + struct ast_sip_exten_state_data exten_state_data; +}; + +static void exten_state_pub_data_destroy(struct exten_state_pub_data *doomed) +{ + if (!doomed) { + return; + } + + ast_free((void *) doomed->exten_state_data.exten); + ast_free(doomed->exten_state_data.presence_subtype); + ast_free(doomed->exten_state_data.presence_message); + ao2_cleanup(doomed->exten_state_data.device_state_info); + + AST_VECTOR_CALLBACK_VOID(&doomed->pubs, ao2_ref, -1); + AST_VECTOR_FREE(&doomed->pubs); + + ast_free(doomed); +} + +static struct exten_state_pub_data *exten_state_pub_data_alloc(const char *exten, struct ast_state_cb_info *info) +{ + struct exten_state_pub_data *pub_data; + + pub_data = ast_calloc(1, sizeof(*pub_data)); + if (!pub_data) { + return NULL; + } + + if (AST_VECTOR_INIT(&pub_data->pubs, ao2_container_count(publishers))) { + exten_state_pub_data_destroy(pub_data); + return NULL; + } + + /* Save off currently known information for the body generators. */ + pub_data->exten_state_data.exten = ast_strdup(exten); + pub_data->exten_state_data.exten_state = info->exten_state; + pub_data->exten_state_data.presence_state = info->presence_state; + pub_data->exten_state_data.presence_subtype = ast_strdup(info->presence_subtype); + pub_data->exten_state_data.presence_message = ast_strdup(info->presence_message); + pub_data->exten_state_data.device_state_info = ao2_bump(info->device_state_info); + if (!pub_data->exten_state_data.exten + || !pub_data->exten_state_data.presence_subtype + || !pub_data->exten_state_data.presence_message) { + exten_state_pub_data_destroy(pub_data); + return NULL; + } + return pub_data; +} + +/*! + * \internal + * \brief Create exten state PUBLISH messages under PJSIP thread. + * \since 14.0.0 + * + * \return 0 + */ +static int exten_state_publisher_cb(void *data) +{ + struct exten_state_pub_data *pub_data = data; + struct exten_state_publisher *publisher; + size_t idx; + struct ast_str *body_text; + pj_pool_t *pool; + struct ast_sip_body_data gen_data = { + .body_type = AST_SIP_EXTEN_STATE_DATA, + .body_data = &pub_data->exten_state_data, + }; + struct ast_sip_body body; + + body_text = ast_str_create(64); + if (!body_text) { + exten_state_pub_data_destroy(pub_data); + return 0; + } + + /* Need a PJSIP memory pool to generate the bodies. */ + pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "pub_state_body", + 1024, 1024); + if (!pool) { + ast_log(LOG_WARNING, "Exten state publishing unable to create memory pool\n"); + exten_state_pub_data_destroy(pub_data); + ast_free(body_text); + return 0; + } + pub_data->exten_state_data.pool = pool; + + for (idx = 0; idx < AST_VECTOR_SIZE(&pub_data->pubs); ++idx) { + const char *uri; + int res; + + publisher = AST_VECTOR_GET(&pub_data->pubs, idx); + + uri = ast_sip_publish_client_get_from_uri(publisher->client); + if (ast_strlen_zero(uri)) { + ast_log(LOG_WARNING, "PUBLISH client '%s' has no from_uri or server_uri defined.\n", + publisher->name); + continue; + } + ast_copy_string(pub_data->exten_state_data.local, uri, sizeof(pub_data->exten_state_data.local)); + + uri = ast_sip_publish_client_get_to_uri(publisher->client); + if (ast_strlen_zero(uri)) { + ast_log(LOG_WARNING, "PUBLISH client '%s' has no to_uri or server_uri defined.\n", + publisher->name); + continue; + } + ast_copy_string(pub_data->exten_state_data.remote, uri, sizeof(pub_data->exten_state_data.remote)); + + res = ast_sip_pubsub_generate_body_content(publisher->body_type, + publisher->body_subtype, &gen_data, &body_text); + pj_pool_reset(pool); + if (res) { + ast_log(LOG_WARNING, + "PUBLISH client '%s' unable to generate %s/%s PUBLISH body.\n", + publisher->name, publisher->body_type, publisher->body_subtype); + continue; + } + + body.type = publisher->body_type; + body.subtype = publisher->body_subtype; + body.body_text = ast_str_buffer(body_text); + ast_sip_publish_client_send(publisher->client, &body); + } + + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + + ast_free(body_text); + exten_state_pub_data_destroy(pub_data); + return 0; +} + /*! * \brief Global extension state callback function */ @@ -549,17 +688,46 @@ static int exten_state_publisher_state_cb(const char *context, const char *exten { struct ao2_iterator publisher_iter; struct exten_state_publisher *publisher; - + struct exten_state_pub_data *pub_data = NULL; + + ast_debug(5, "Exten state publisher: %s@%s Reason:%s State:%s Presence:%s Subtype:'%s' Message:'%s'\n", + exten, context, + info->reason == AST_HINT_UPDATE_DEVICE + ? "Device" + : info->reason == AST_HINT_UPDATE_PRESENCE + ? "Presence" + : "Unknown", + ast_extension_state2str(info->exten_state), + ast_presence_state2str(info->presence_state), + S_OR(info->presence_subtype, ""), + S_OR(info->presence_message, "")); publisher_iter = ao2_iterator_init(publishers, 0); for (; (publisher = ao2_iterator_next(&publisher_iter)); ao2_ref(publisher, -1)) { if ((publisher->context_filter && regexec(&publisher->context_regex, context, 0, NULL, 0)) || (publisher->exten_filter && regexec(&publisher->exten_regex, exten, 0, NULL, 0))) { continue; } - /* This is a placeholder for additional code to come */ + + if (!pub_data) { + pub_data = exten_state_pub_data_alloc(exten, info); + if (!pub_data) { + ao2_ref(publisher, -1); + break; + } + } + + ao2_ref(publisher, +1); + AST_VECTOR_APPEND(&pub_data->pubs, publisher); + ast_debug(5, "'%s' will publish exten state\n", publisher->name); } ao2_iterator_destroy(&publisher_iter); + if (pub_data + && ast_sip_push_task(publish_exten_state_serializer, exten_state_publisher_cb, + pub_data)) { + exten_state_pub_data_destroy(pub_data); + } + return 0; } @@ -755,6 +923,10 @@ static int unload_module(void) ast_sip_unregister_subscription_handler(&presence_handler); ast_extension_state_del(0, exten_state_publisher_state_cb); + + ast_taskprocessor_unreference(publish_exten_state_serializer); + publish_exten_state_serializer = NULL; + ao2_cleanup(publishers); publishers = NULL; @@ -777,6 +949,12 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } + publish_exten_state_serializer = ast_sip_create_serializer("pjsip/exten_state"); + if (!publish_exten_state_serializer) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + if (ast_sip_register_subscription_handler(&presence_handler)) { ast_log(LOG_WARNING, "Unable to register subscription handler %s\n", presence_handler.event_name); diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 0fe2e3e5d80..0265c424e32 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -425,6 +425,20 @@ struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *n return state->client; } +const char *ast_sip_publish_client_get_from_uri(struct ast_sip_outbound_publish_client *client) +{ + struct ast_sip_outbound_publish *publish = client->publish; + + return S_OR(publish->from_uri, S_OR(publish->server_uri, "")); +} + +const char *ast_sip_publish_client_get_to_uri(struct ast_sip_outbound_publish_client *client) +{ + struct ast_sip_outbound_publish *publish = client->publish; + + return S_OR(publish->to_uri, S_OR(publish->server_uri, "")); +} + int ast_sip_register_event_publisher_handler(struct ast_sip_event_publisher_handler *handler) { struct ast_sip_event_publisher_handler *existing; From bf13b590625cfc311412bee29809c0dadba6f7d3 Mon Sep 17 00:00:00 2001 From: Diederik de Groot Date: Sun, 1 May 2016 09:21:33 +0200 Subject: [PATCH 0395/1578] configs/basic-pbx/asterisk.conf: contains incorrect path separator Note: When packagers use these files (as an example) the paths are never really used when they are split using '='. Note: Thirdparty applications will also have trouble parsing the file when expecting '=>'. Change-Id: I0ada647f588e81f023fb1333ca15a1a333fd6004 --- configs/basic-pbx/asterisk.conf | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/configs/basic-pbx/asterisk.conf b/configs/basic-pbx/asterisk.conf index 3ee7b99b875..576cc976b6d 100644 --- a/configs/basic-pbx/asterisk.conf +++ b/configs/basic-pbx/asterisk.conf @@ -1,15 +1,15 @@ [directories] -astetcdir = /etc/asterisk -astmoddir = /usr/lib/asterisk/modules -astvarlibdir = /var/lib/asterisk -astdbdir = /var/lib/asterisk -astkeydir = /var/lib/asterisk -astdatadir = /var/lib/asterisk -astagidir = /var/lib/asterisk/agi-bin -astspooldir = /var/spool/asterisk -astrundir = /var/run/asterisk -astlogdir = /var/log/asterisk -astsbindir = /usr/sbin +astetcdir => /etc/asterisk +astmoddir => /usr/lib/asterisk/modules +astvarlibdir => /var/lib/asterisk +astdbdir => /var/lib/asterisk +astkeydir => /var/lib/asterisk +astdatadir => /var/lib/asterisk +astagidir => /var/lib/asterisk/agi-bin +astspooldir => /var/spool/asterisk +astrundir => /var/run/asterisk +astlogdir => /var/log/asterisk +astsbindir => /usr/sbin [options] ; If we want to start Asterisk with a default verbosity for the verbose From 2b1edee772ae3690d060bd067b489cbbb72b24f5 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 15 Apr 2016 15:26:15 -0400 Subject: [PATCH 0396/1578] pjsip: Added "reg_server" to contacts. If the Asterisk system name is set in asterisk.conf, it will be stored into the "reg_server" field in the ps_contacts table to facilitate multi-server setups. ASTERISK-25931 Change-Id: Ia8f6bd2267809c78753b52bcf21835b9b59f4cb8 --- CHANGES | 9 +++++++ ...b01a191a46_pjsip_add_contact_reg_server.py | 25 +++++++++++++++++++ include/asterisk/res_pjsip.h | 2 ++ res/res_pjsip.c | 6 +++++ res/res_pjsip/location.c | 8 ++++++ res/res_pjsip_registrar.c | 4 +++ 6 files changed, 54 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py diff --git a/CHANGES b/CHANGES index 1f5ea540611..9f067bd9f7f 100644 --- a/CHANGES +++ b/CHANGES @@ -272,6 +272,15 @@ Queue * Show the time when started the last pause for queue member on CLI for command 'queue show'. +--- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- +------------------------------------------------------------------------------ + +res_pjsip +------------------ + * Added "reg_server" to contacts. + If the Asterisk system name is set in asterisk.conf, it will be stored + into the "reg_server" field in the ps_contacts table to facilitate + multi-server setups. ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.8.0 to Asterisk 13.9.0 ------------ diff --git a/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py new file mode 100644 index 00000000000..8bd151bd7a9 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py @@ -0,0 +1,25 @@ +"""pjsip: add contact reg_server + +Revision ID: 81b01a191a46 +Revises: 65eb22eb195 +Create Date: 2016-04-15 15:00:35.024525 + +""" + +# revision identifiers, used by Alembic. +revision = '81b01a191a46' +down_revision = '65eb22eb195' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_contacts', sa.Column('reg_server', sa.String(20))) + op.drop_constraint(UniqueConstraint('id'), 'ps_contacts', type_='unique') + op.create_unique_constraint('ps_contacts_uq', 'ps_contacts', ['id','reg_server']) + +def downgrade(): + op.drop_constraint('ps_contacts_uq', 'ps_contacts', type_='unique') + op.drop_column('reg_server') + op.create_unique_constraint(None, 'ps_contacts', 'id') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 6939d275943..b6684ae56f9 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -248,6 +248,8 @@ struct ast_sip_contact { double qualify_timeout; /*! Endpoint that added the contact, only available in observers */ struct ast_sip_endpoint *endpoint; + /*! Asterisk Server name */ + AST_STRING_FIELD_EXTENDED(reg_server); }; #define CONTACT_STATUS "contact_status" diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 6890e637baa..db3395fa704 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1112,6 +1112,12 @@ REGISTER requests and is not intended to be configured manually. + + Asterisk Server name + + Asterisk Server name on which SIP endpoint registered. + + The configuration for a location of an endpoint diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index db4f9ac0995..2779fe3969e 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -23,6 +23,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/logger.h" #include "asterisk/astobj2.h" +#include "asterisk/paths.h" #include "asterisk/sorcery.h" #include "include/res_pjsip_private.h" #include "asterisk/res_pjsip_cli.h" @@ -119,6 +120,8 @@ static void *contact_alloc(const char *name) return NULL; } + ast_string_field_init_extended(contact, reg_server); + /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) { *aor_separator = '\0'; @@ -330,6 +333,10 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri ast_string_field_set(contact, user_agent, user_agent); } + if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { + ast_string_field_set(contact, reg_server, ast_config_AST_SYSTEM_NAME); + } + contact->endpoint = ao2_bump(endpoint); return ast_sorcery_create(ast_sip_get_sorcery(), contact); @@ -1111,6 +1118,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout)); ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); + ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration)); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index ae8440aabe7..65fd56c02dd 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -30,6 +30,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/module.h" +#include "asterisk/paths.h" #include "asterisk/test.h" #include "asterisk/taskprocessor.h" #include "asterisk/manager.h" @@ -555,6 +556,9 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co if (user_agent) { ast_string_field_set(contact_update, user_agent, user_agent); } + if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { + ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME); + } if (ast_sip_location_update_contact(contact_update)) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", From 080c6216b61c108ec3b836a098fdd39bf946ce54 Mon Sep 17 00:00:00 2001 From: Andrew Nagy Date: Thu, 17 Mar 2016 12:29:38 -0700 Subject: [PATCH 0397/1578] app_voicemail: always copy dynamic struct to avoid race condition Voicemail email addresses can be corrupt or voicemail emails can end up being sent to the wrong email address if asterisk is reading voicemail.conf during a reload and processing an email at the same time. This patch always copies the struct that would otherwise only be copied once. ASTERISK-24463 #close Reported by: John Campbell Tested by: Etienne Lessard Tested by: Andrew Nagy Change-Id: I3a0643813116da84e2617291903d0d489b7425fb --- apps/app_voicemail.c | 101 +++++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 23 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 6701db5b7ab..e7de8a2b2b3 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -1725,13 +1725,14 @@ static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *contex } if (cur) { /* Make a copy, so that on a reload, we have no race */ - if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) { + if ((vmu = (ivm ? ivm : ast_calloc(1, sizeof(*vmu))))) { + ast_free(vmu->email); + ast_free(vmu->emailbody); + ast_free(vmu->emailsubject); *vmu = *cur; - if (!ivm) { - vmu->email = ast_strdup(cur->email); - vmu->emailbody = ast_strdup(cur->emailbody); - vmu->emailsubject = ast_strdup(cur->emailsubject); - } + vmu->email = ast_strdup(cur->email); + vmu->emailbody = ast_strdup(cur->emailbody); + vmu->emailsubject = ast_strdup(cur->emailsubject); ast_set2_flag(vmu, !ivm, VM_ALLOCED); AST_LIST_NEXT(vmu, list) = NULL; } @@ -2009,17 +2010,18 @@ static int get_folder_by_name(const char *name) static void free_user(struct ast_vm_user *vmu) { - if (ast_test_flag(vmu, VM_ALLOCED)) { - - ast_free(vmu->email); - vmu->email = NULL; - - ast_free(vmu->emailbody); - vmu->emailbody = NULL; + if (!vmu) { + return; + } - ast_free(vmu->emailsubject); - vmu->emailsubject = NULL; + ast_free(vmu->email); + vmu->email = NULL; + ast_free(vmu->emailbody); + vmu->emailbody = NULL; + ast_free(vmu->emailsubject); + vmu->emailsubject = NULL; + if (ast_test_flag(vmu, VM_ALLOCED)) { ast_free(vmu); } } @@ -2457,14 +2459,17 @@ static int __messagecount(const char *context, const char *mailbox, const char * return 0; /* We have to get the user before we can open the stream! */ + memset(&vmus, 0, sizeof(vmus)); vmu = find_user(&vmus, context, mailbox); if (!vmu) { ast_log(AST_LOG_WARNING, "Couldn't find mailbox %s in context %s\n", mailbox, context); + free_user(vmu); return -1; } else { /* No IMAP account available */ if (vmu->imapuser[0] == '\0') { ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox); + free_user(vmu); return -1; } } @@ -2484,9 +2489,11 @@ static int __messagecount(const char *context, const char *mailbox, const char * if (vms_p) { ast_debug(3, "Returning before search - user is logged in\n"); if (fold == 0) { /* INBOX */ + free_user(vmu); return urgent ? vms_p->urgentmessages : vms_p->newmessages; } if (fold == 1) { /* Old messages */ + free_user(vmu); return vms_p->oldmessages; } } @@ -2503,6 +2510,7 @@ static int __messagecount(const char *context, const char *mailbox, const char * ret = init_mailstream(vms_p, fold); if (!vms_p->mailstream) { ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n"); + free_user(vmu); return -1; } if (ret == 0) { @@ -2546,6 +2554,7 @@ static int __messagecount(const char *context, const char *mailbox, const char * /*Freeing the searchpgm also frees the searchhdr*/ mail_free_searchpgm(&pgm); ast_mutex_unlock(&vms_p->lock); + free_user(vmu); vms_p->updated = 0; return vms_p->vmArrayIndex; } else { @@ -2553,6 +2562,7 @@ static int __messagecount(const char *context, const char *mailbox, const char * mail_ping(vms_p->mailstream); ast_mutex_unlock(&vms_p->lock); } + free_user(vmu); return 0; } @@ -6185,6 +6195,7 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata) return -1; } + memset(&svm, 0, sizeof(svm)); if (!(recipient = find_user(&svm, recdata->context, recdata->mailbox))) { ast_log(LOG_ERROR, "No entry in voicemail config file for '%s@%s'\n", recdata->mailbox, recdata->context); return -1; @@ -6500,6 +6511,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ } ast_debug(3, "Before find_user\n"); + memset(&svm, 0, sizeof(svm)); if (!(vmu = find_user(&svm, context, ext))) { ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); @@ -6529,6 +6541,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext); if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) { ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile); + free_user(vmu); ast_free(tmp); return -1; } @@ -6672,9 +6685,9 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ } ast_play_and_wait(chan, "transfer"); ast_channel_priority_set(chan, 0); - free_user(vmu); pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); } + free_user(vmu); ast_free(tmp); return OPERATOR_EXIT; } @@ -6708,6 +6721,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ res = inboxcount(ext_context, &newmsgs, &oldmsgs); if (res < 0) { ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n"); + free_user(vmu); ast_free(tmp); return -1; } @@ -6718,6 +6732,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ */ if (!(vms = create_vm_state_from_user(vmu))) { ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n"); + free_user(vmu); ast_free(tmp); return -1; } @@ -6912,6 +6927,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ *cntx = '\0'; cntx++; } + memset(&recipu, 0, sizeof(recipu)); if ((recip = find_user(&recipu, cntx, exten))) { copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL); free_user(recip); @@ -10939,6 +10955,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ } ast_debug(1, "Before find user for mailbox %s\n", mailbox); + memset(&vmus, 0, sizeof(vmus)); vmu = find_user(&vmus, context, mailbox); if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) { /* saved password is blank, so don't bother asking */ @@ -10946,10 +10963,12 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ } else { if (ast_streamfile(chan, vm_password, ast_channel_language(chan))) { ast_log(AST_LOG_WARNING, "Unable to stream password file\n"); + free_user(vmu); return -1; } if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) { ast_log(AST_LOG_WARNING, "Unable to read password\n"); + free_user(vmu); return -1; } else if (password[0] == '*') { /* user entered '*' */ @@ -10957,11 +10976,13 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) { mailbox[0] = '*'; + free_user(vmu); return -1; } ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n"); mailbox[0] = '\0'; /* if the password entered was '*', do not let a user mailbox be created if the extension 'a' is not defined */ + free_user(vmu); vmu = NULL; } } @@ -10982,6 +11003,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ if (skipuser || logretries >= max_logins) { if (ast_streamfile(chan, "vm-incorrect", ast_channel_language(chan))) { ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n"); + free_user(vmu); return -1; } } else { @@ -10989,16 +11011,20 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ adsi_login(chan); if (ast_streamfile(chan, "vm-incorrect-mailbox", ast_channel_language(chan))) { ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n"); + free_user(vmu); return -1; } } - if (ast_waitstream(chan, "")) /* Channel is hung up */ + if (ast_waitstream(chan, "")) { /* Channel is hung up */ + free_user(vmu); return -1; + } } } if (!valid && (logretries >= max_logins)) { ast_stopstream(chan); ast_play_and_wait(chan, "vm-goodbye"); + free_user(vmu); return -1; } if (vmu && !skipuser) { @@ -11106,6 +11132,8 @@ static int play_message_by_id(struct ast_channel *chan, const char *mailbox, con } #endif + free_user(vmu); + return res; } @@ -12301,7 +12329,7 @@ AST_TEST_DEFINE(test_voicemail_vmuser) static int vm_box_exists(struct ast_channel *chan, const char *data) { - struct ast_vm_user svm; + struct ast_vm_user svm, *vmu; char *context, *box; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(mbox); @@ -12331,8 +12359,10 @@ static int vm_box_exists(struct ast_channel *chan, const char *data) context++; } - if (find_user(&svm, context, args.mbox)) { + vmu = find_user(&svm, context, args.mbox); + if (vmu) { pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS"); + free_user(vmu); } else pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED"); @@ -12341,7 +12371,7 @@ static int vm_box_exists(struct ast_channel *chan, const char *data) static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len) { - struct ast_vm_user svm; + struct ast_vm_user svm, *vmu; AST_DECLARE_APP_ARGS(arg, AST_APP_ARG(mbox); AST_APP_ARG(context); @@ -12360,7 +12390,10 @@ static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *a ast_log(AST_LOG_WARNING, "MAILBOX_EXISTS is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", args); } - ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len); + vmu = find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox); + ast_copy_string(buf, vmu ? "1" : "0", len); + free_user(vmu); + return 0; } @@ -12396,10 +12429,12 @@ static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, ch return -1; } + memset(&svm, 0, sizeof(svm)); vmu = find_user(&svm, context, mailbox); if (!strncasecmp(arg.attribute, "exists", 5)) { ast_copy_string(buf, vmu ? "1" : "0", len); + free_user(vmu); return 0; } @@ -12428,13 +12463,16 @@ static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, ch res = messagecount(mailbox_id, arg.folder); if (res < 0) { ast_log(LOG_ERROR, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context); + free_user(vmu); return -1; } snprintf(buf, len, "%d", res); } else { ast_log(LOG_ERROR, "Unknown attribute '%s' for VM_INFO\n", arg.attribute); + free_user(vmu); return -1; } + free_user(vmu); } return 0; @@ -14248,6 +14286,7 @@ AST_TEST_DEFINE(test_voicemail_msgcount) } #endif + memset(&svm, 0, sizeof(svm)); if (!(vmu = find_user(&svm, testcontext, testmailbox)) && !(vmu = find_or_create(testcontext, testmailbox))) { ast_test_status_update(test, "Cannot create vmu structure\n"); @@ -14277,6 +14316,7 @@ AST_TEST_DEFINE(test_voicemail_msgcount) #ifdef IMAP_STORAGE chan = ast_channel_unref(chan); #endif + free_user(vmu); return AST_TEST_FAIL; } } @@ -14360,6 +14400,7 @@ AST_TEST_DEFINE(test_voicemail_msgcount) syserr > 0 ? strerror(syserr) : "unable to fork()"); } + free_user(vmu); return res; } @@ -14469,6 +14510,7 @@ AST_TEST_DEFINE(test_voicemail_notify_endl) } } fclose(file); + free_user(vmu); return res; } @@ -14629,6 +14671,7 @@ AST_TEST_DEFINE(test_voicemail_vm_info) } chan = ast_channel_unref(chan); + free_user(vmu); return res; } #endif /* defined(TEST_FRAMEWORK) */ @@ -15020,8 +15063,10 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s ast_config_destroy(msg_cfg); return res; } else { - struct ast_vm_user vmu2; - if (find_user(&vmu2, vmu->context, num)) { + struct ast_vm_user vmu2, *vmu3; + memset(&vmu2, 0, sizeof(vmu2)); + vmu3 = find_user(&vmu2, vmu->context, num); + if (vmu3) { struct leave_vm_options leave_options; char mailbox[AST_MAX_EXTENSION * 2 + 2]; snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context); @@ -15034,6 +15079,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s if (!res) res = 't'; ast_config_destroy(msg_cfg); + free_user(vmu3); return res; } else { /* Sender has no mailbox, can't reply */ @@ -15528,11 +15574,13 @@ static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *ma if (!(mailbox_snapshot = ast_calloc(1, sizeof(*mailbox_snapshot)))) { ast_log(AST_LOG_ERROR, "Failed to allocate memory for mailbox snapshot\n"); + free_user(vmu); return NULL; } if (!(mailbox_snapshot->snapshots = ast_calloc(ARRAY_LEN(mailbox_folders), sizeof(*mailbox_snapshot->snapshots)))) { ast_free(mailbox_snapshot); + free_user(vmu); return NULL; } @@ -15593,6 +15641,7 @@ static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *ma } #endif + free_user(vmu); return mailbox_snapshot; } @@ -15747,6 +15796,7 @@ static int vm_msg_forward(const char *from_mailbox, if (!(to_vmu = find_user(&to_vmus, to_context, to_mailbox))) { ast_log(LOG_WARNING, "Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context); + free_user(vmu); return -1; } @@ -15827,6 +15877,8 @@ static int vm_msg_forward(const char *from_mailbox, notify_new_state(to_vmu); } + free_user(vmu); + free_user(to_vmu); return res; } @@ -15930,6 +15982,7 @@ static int vm_msg_move(const char *mailbox, notify_new_state(vmu); } + free_user(vmu); return res; } @@ -16027,6 +16080,7 @@ static int vm_msg_remove(const char *mailbox, notify_new_state(vmu); } + free_user(vmu); return res; } @@ -16140,6 +16194,7 @@ static int vm_msg_play(struct ast_channel *chan, notify_new_state(vmu); } + free_user(vmu); return res; } From e61716b7740da5f87efedb7682a69b8ccf9d55c1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 30 Apr 2016 16:52:47 -0600 Subject: [PATCH 0398/1578] pjproject_bundled: Various fixes discovered during testing of OSes For all OSes: * Disabled third-party codecs in pjproject and added '--disable-speex-codec --disable-speex-aec --disable-gsm-codec' to the configure options since we don't use the pjsip codec capability. FreeBSD: * Added FreeBSD support to install_prereq. * Changed pjproject/configure.m4 to use $GNU_MAKE instead of hardcoding "make". * Added __progname and environ to asterisk.exports.in. * Reverted the use of ldconfig to create shared library symlinks to ln. * Only enable epoll in pjproject if `uname -s` is Linux. * Added a patch to pjproject to take the name of the 'make' command from an environment variable if supplied. This is needed for the python bindings. (merged by Teluu into pjproject trunk 5/3/2016) FreeBSD support isn't complete. Still some general issues regarding make/gmake having nothing to do with pjproject. With some handholding it DOES build successfully. CentOS: Added 'patch' and 'bzip2' to install_prereq PACKAGES_RH. CentOS 6/7 32/64 build and run the pjsip testsuite successfully. Ubuntu: No changes required. Ubuntu 15/16 32/64 build and run the pjsip testsuite successfully. Debian: No changes required. Debian 6/7/8 32/64 build and run the pjsip testsuite successfully. There will utimately be a follow-up patch to create an install_prereq for the testsuite as I've discovered a few missing requirements. ASTERISK-25968 #close Change-Id: I5756a07facfc63798115a5e73a8709382fe9259c --- configure | 6 +-- contrib/scripts/install_prereq | 36 +++++++++++-- main/Makefile | 12 +---- main/asterisk.exports.in | 2 + third-party/pjproject/Makefile | 3 +- third-party/pjproject/Makefile.rules | 11 ++-- third-party/pjproject/apply_patches | 4 +- third-party/pjproject/configure.m4 | 6 +-- ...ython-setup.py-Take-make-from-the-en.patch | 51 +++++++++++++++++++ 9 files changed, 102 insertions(+), 29 deletions(-) create mode 100644 third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch diff --git a/configure b/configure index 579678b54e9..171693a3113 100755 --- a/configure +++ b/configure @@ -24493,16 +24493,16 @@ if test "$USE_PJPROJECT" != "no" ; then $as_echo_n "checking for embedded pjproject (may have to download)... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: configuring" >&5 $as_echo "configuring" >&6; } - make --quiet --no-print-directory -C $PJPROJECT_DIR configure + ${GNU_MAKE} --quiet --no-print-directory -C $PJPROJECT_DIR configure if test $? -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: Unable to configure $PJPROJECT_DIR" >&5 $as_echo "$as_me: Unable to configure $PJPROJECT_DIR" >&6;} - as_fn_error $? "Run \"make -C $PJPROJECT_DIR NOISY_BUILD=yes configure\" to see error details." "$LINENO" 5 + as_fn_error $? "Run \"${GNU_MAKE} -C $PJPROJECT_DIR NOISY_BUILD=yes configure\" to see error details." "$LINENO" 5 fi - PJPROJECT_INCLUDE=$(make --quiet --no-print-directory -C $PJPROJECT_DIR echo_cflags) + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C $PJPROJECT_DIR echo_cflags) PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" PBX_PJPROJECT=1 PJPROJECT_BUNDLED=yes diff --git a/contrib/scripts/install_prereq b/contrib/scripts/install_prereq index 1682558ac3b..bda28e9f7ee 100755 --- a/contrib/scripts/install_prereq +++ b/contrib/scripts/install_prereq @@ -29,13 +29,15 @@ PACKAGES_DEBIAN="$PACKAGES_DEBIAN libopenh323-dev libvpb-dev libgtk2.0-dev libmy PACKAGES_DEBIAN="$PACKAGES_DEBIAN libsnmp-dev libiksemel-dev libcorosync-dev libnewt-dev libpopt-dev libical-dev libspandsp-dev libjack-dev" PACKAGES_DEBIAN="$PACKAGES_DEBIAN libresample-dev libc-client-dev binutils-dev libsrtp-dev libgsm1-dev libedit-dev doxygen libjansson-dev libldap-dev" PACKAGES_DEBIAN="$PACKAGES_DEBIAN subversion git libxslt1-dev automake libsrtp-dev libncurses5-dev python-dev" -PACKAGES_RH="automake gcc gcc-c++ ncurses-devel openssl-devel libxml2-devel unixODBC-devel libcurl-devel libogg-devel libvorbis-devel speex-devel" +PACKAGES_RH="automake bzip2 gcc gcc-c++ patch ncurses-devel openssl-devel libxml2-devel unixODBC-devel libcurl-devel libogg-devel libvorbis-devel speex-devel" PACKAGES_RH="$PACKAGES_RH spandsp-devel freetds-devel net-snmp-devel iksemel-devel corosynclib-devel newt-devel popt-devel libtool-ltdl-devel lua-devel" PACKAGES_RH="$PACKAGES_RH sqlite-devel libsqlite3x-devel radiusclient-ng-devel portaudio-devel postgresql-devel libresample-devel neon-devel libical-devel" PACKAGES_RH="$PACKAGES_RH openldap-devel gmime22-devel sqlite2-devel mysql-devel bluez-libs-devel jack-audio-connection-kit-devel gsm-devel libedit-devel libuuid-devel" PACKAGES_RH="$PACKAGES_RH jansson-devel libsrtp-devel pjproject-devel subversion git libxslt-devel python-devel" PACKAGES_OBSD="popt gmake wget libxml libogg libvorbis curl iksemel spandsp speex iodbc freetds-0.63p1-msdblib mysql-client gmime sqlite sqlite3 jack libxslt" +PACKAGES_FBSD="autoconf gcc binutils popt gmake wget libxml2 libogg libvorbis curl iksemel spandsp speex unixODBC freetds-devel mysql55-client gmime2 sqlite" +PACKAGES_FBSD="$PACKAGES_FBSD sqlite3 libxslt jansson e2fsprogs-libuuid gsm libsrtp libsamplerate" KVERS=`uname -r` @@ -95,23 +97,45 @@ check_installed_pkgs() { done } +check_installed_fpkgs() { + for pack in "$@" + do + if [ `pkg info -a | grep $pack | wc -l` = 0 ]; then + echo $pack + fi + done +} + handle_debian() { if ! [ -x "$(command -v aptitude)" ]; then apt-get install aptitude fi extra_packs=`check_installed_debs $PACKAGES_DEBIAN` $testcmd aptitude update - $testcmd aptitude install -y $extra_packs + if [ x"$extra_packs" != "x" ] ; then + $testcmd aptitude install -y $extra_packs + fi } handle_rh() { extra_packs=`check_installed_rpms $PACKAGES_RH` - $testcmd yum install -y $extra_packs + if [ x"$extra_packs" != "x" ] ; then + $testcmd yum install -y $extra_packs + fi } handle_obsd() { extra_packs=`check_installed_pkgs $PACKAGES_OBSD` - $testcmd pkg_add $extra_packs + if [ x"$extra_packs" != "x" ] ; then + $testcmd pkg_add $extra_packs + fi +} + +handle_fbsd() { + extra_packs=`check_installed_fpkgs $PACKAGES_FBSD` + if [ x"$extra_packs" != "x" ] ; then + $testcmd pkg install -y $extra_packs + fi } install_unpackaged() { @@ -188,7 +212,7 @@ OS=`uname -s` unsupported_distro='' # A number of distributions we don't (yet?) support. -if [ "$OS" != 'Linux' -a "$OS" != 'OpenBSD' ]; then +if [ "$OS" != 'Linux' -a "$OS" != 'OpenBSD' -a "$OS" != 'FreeBSD' ]; then echo >&2 "$0: Your OS ($OS) is currently not supported. Aborting." exit 1 fi @@ -221,6 +245,8 @@ elif [ -r /etc/redhat-release ]; then handle_rh elif [ "$OS" = 'OpenBSD' ]; then handle_obsd +elif [ "$OS" = 'FreeBSD' ]; then + handle_fbsd fi if ! in_test_mode; then diff --git a/main/Makefile b/main/Makefile index d52c3f0a722..3863978011e 100644 --- a/main/Makefile +++ b/main/Makefile @@ -225,11 +225,7 @@ endif $(ASTSSL_LIB): $(ASTSSL_LIB).$(ASTSSL_SO_VERSION) $(ECHO_PREFIX) echo " [LN] $< -> $@" - $(CMD_PREFIX) if [ -x "$(LDCONFIG)" ] ; then \ - $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null ;\ - else \ - $(LN) -sf $< $@ ;\ - fi + $(LN) -sf $< $@ ;\ else # Darwin ASTSSL_LIB:=libasteriskssl.dylib @@ -305,11 +301,7 @@ $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): libasteriskpj.o libasteriskpj.exports $(ASTPJ_LIB): $(ASTPJ_LIB).$(ASTPJ_SO_VERSION) $(ECHO_PREFIX) echo " [LN] $< -> $@" - $(CMD_PREFIX) if [ -x "$(LDCONFIG)" ] ; then \ - $(LDCONFIG) $(LDCONFIG_FLAGS) . 2>/dev/null ;\ - else \ - $(LN) -sf $< $@ ;\ - fi + $(LN) -sf $< $@ ;\ else # Darwin ASTPJ_LIB:=libasteriskpj.dylib diff --git a/main/asterisk.exports.in b/main/asterisk.exports.in index 364b3b05e98..f997587c9f3 100644 --- a/main/asterisk.exports.in +++ b/main/asterisk.exports.in @@ -49,6 +49,8 @@ LINKER_SYMBOL_PREFIXres_srtp; LINKER_SYMBOL_PREFIXres_srtp_policy; LINKER_SYMBOL_PREFIXsecure_call_info; + LINKER_SYMBOL_PREFIX__progname; + LINKER_SYMBOL_PREFIXenviron; /* If _IO_stdin_used is not exported, stdout/stderr may not get diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 5810a65dc76..7fa3902baa7 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -115,8 +115,7 @@ source/pjsip-apps/bin/pjsua-$(TARGET_NAME): source/pjlib/lib/libpj-$(TARGET_NAME source/pjsip-apps/src/python/build/_pjsua.so: source/pjlib/lib/libpj-$(TARGET_NAME).a $(ECHO_PREFIX) Compiling python bindings - $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; python setup.py build --build-platlib=./build $(REALLY_QUIET)) - + $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; MAKE=$(MAKE) python setup.py build --build-platlib=./build $(REALLY_QUIET)) _all: pjproject.symbols source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/src/python/build/_pjsua.so diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index 062793f12de..6b51c2f2a76 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -1,7 +1,10 @@ PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe -PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --with-external-speex --with-external-gsm --with-external-srtp \ - --disable-video --disable-v4l2 --disable-sound --disable-opencore-amr --disable-ilbc-codec \ - --without-libyuv --disable-g7221-codec \ - --enable-epoll +PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --disable-speex-codec --disable-speex-aec \ + --disable-gsm-codec --disable-video --disable-v4l2 --disable-sound --disable-opencore-amr \ + --disable-ilbc-codec --without-libyuv --disable-g7221-codec + +ifeq ($(shell uname -s),Linux) + PJPROJECT_CONFIG_OPTS += --enable-epoll +endif diff --git a/third-party/pjproject/apply_patches b/third-party/pjproject/apply_patches index 1b72d14b025..5dfdd2a3c86 100755 --- a/third-party/pjproject/apply_patches +++ b/third-party/pjproject/apply_patches @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh if [ "$1" = "-q" ] ; then quiet=1 @@ -27,7 +27,7 @@ if [ ! "$(ls -A $patchdir/*.patch 2>/dev/null)" ] ; then fi for patchfile in $patchdir/*.patch ; do - patch -d $sourcedir -p1 -s -r- -f -N --dry-run -i "$patchfile" || (echo "Patchfile $(basename $patchfile) failed to apply >&2" ; exit 1) || exit 1 + patch -d $sourcedir -p1 -s -r- -f -N --dry-run -i "$patchfile" || (echo "Patchfile $(basename $patchfile) failed to apply" >&2 ; exit 1) || exit 1 done for patchfile in "$patchdir"/*.patch ; do diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 74322277401..2cc18bfa8d7 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -21,14 +21,14 @@ AC_DEFUN([PJPROJECT_CONFIGURE], [ AC_MSG_CHECKING(for embedded pjproject (may have to download)) AC_MSG_RESULT(configuring) - make --quiet --no-print-directory -C $1 configure + ${GNU_MAKE} --quiet --no-print-directory -C $1 configure if test $? -ne 0 ; then AC_MSG_RESULT(failed) AC_MSG_NOTICE(Unable to configure $1) - AC_MSG_ERROR(Run "make -C $1 NOISY_BUILD=yes configure" to see error details.) + AC_MSG_ERROR(Run "${GNU_MAKE} -C $1 NOISY_BUILD=yes configure" to see error details.) fi - PJPROJECT_INCLUDE=$(make --quiet --no-print-directory -C $1 echo_cflags) + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C $1 echo_cflags) PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" PBX_PJPROJECT=1 PJPROJECT_BUNDLED=yes diff --git a/third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch b/third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch new file mode 100644 index 00000000000..80f8bc0b35f --- /dev/null +++ b/third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch @@ -0,0 +1,51 @@ +From 61668b8fcaa0f2a8a05100097284c0c427600033 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Mon, 2 May 2016 17:08:15 -0600 +Subject: [PATCH] pjsip-apps/src/python/setup.py: Take "make" from the + environment + +With "make" hard coded in setup.py, it chokes on FreeBSD because the system +make command isn't GNU compatibile. This patch allows setup.py to take the +name of the make command from the MAKE environment variable if it exists. +If it doesn't, it defaults to "make". +--- + pjsip-apps/src/python/setup.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/pjsip-apps/src/python/setup.py b/pjsip-apps/src/python/setup.py +index 69a9859..ea1427d 100644 +--- a/pjsip-apps/src/python/setup.py ++++ b/pjsip-apps/src/python/setup.py +@@ -60,25 +60,25 @@ if pj_version_suffix: + pj_version += "-" + pj_version_suffix + + #print 'PJ_VERSION = "'+ pj_version + '"' +- ++MAKE = os.environ.get('MAKE') or "make" + + # Fill in pj_inc_dirs + pj_inc_dirs = [] +-f = os.popen("make -f helper.mak inc_dir") ++f = os.popen("%s -f helper.mak inc_dir" % MAKE) + for line in f: + pj_inc_dirs.append(line.rstrip("\r\n")) + f.close() + + # Fill in pj_lib_dirs + pj_lib_dirs = [] +-f = os.popen("make -f helper.mak lib_dir") ++f = os.popen("%s -f helper.mak lib_dir" % MAKE) + for line in f: + pj_lib_dirs.append(line.rstrip("\r\n")) + f.close() + + # Fill in pj_libs + pj_libs = [] +-f = os.popen("make -f helper.mak libs") ++f = os.popen("%s -f helper.mak libs" % MAKE) + for line in f: + pj_libs.append(line.rstrip("\r\n")) + f.close() +-- +2.5.5 + From a4cfcda0367e282d7ff9d937676c7f83d0ce8521 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 7 Apr 2016 17:33:49 -0400 Subject: [PATCH 0399/1578] res_pjsip/AMI: add contact.updated event With the old SIP module AMI sends PeerStatus event on every successfully REGISTER requests, ie, on start registration, update registration and stop registration. With PJSIP AMI sends ContactStatus only when status is changed. Regarding registration: on start registration - Created on stop registration - Removed but on update registration nothing This patch added contact.updated event. ASTERISK-25904 Change-Id: I8fad8aae9305481469c38d2146e1ba3a56d3108f --- CHANGES | 2 ++ include/asterisk/res_pjsip.h | 1 + res/res_pjsip/pjsip_options.c | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 9f067bd9f7f..8d1e339d614 100644 --- a/CHANGES +++ b/CHANGES @@ -277,6 +277,8 @@ Queue res_pjsip ------------------ + * Added new status Updated to AMI event ContactStatus on update registration + * Added "reg_server" to contacts. If the Asterisk system name is set in asterisk.conf, it will be stored into the "reg_server" field in the ps_contacts table to facilitate diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index b6684ae56f9..05f8100cf54 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -263,6 +263,7 @@ enum ast_sip_contact_status_type { UNKNOWN, CREATED, REMOVED, + UPDATED, }; /*! diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index fc64947edc7..c0d41c3d190 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -42,6 +42,7 @@ static const char *status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", + [UPDATED] = "Updated", }; static const char *short_status_map [] = { @@ -50,6 +51,7 @@ static const char *short_status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", + [UPDATED] = "Updated", }; const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status) @@ -530,6 +532,16 @@ static void contact_created(const void *obj) qualify_and_schedule((struct ast_sip_contact *) obj); } +/*! + * \internal + * \brief A contact has been updated. + */ +static void contact_updated(const void *obj) +{ + update_contact_status((struct ast_sip_contact *) obj, UPDATED); + qualify_and_schedule((struct ast_sip_contact *) obj); +} + /*! * \internal * \brief A contact has been deleted remove status tracking. @@ -556,7 +568,8 @@ static void contact_deleted(const void *obj) static const struct ast_sorcery_observer contact_observer = { .created = contact_created, - .deleted = contact_deleted + .deleted = contact_deleted, + .updated = contact_updated }; static pj_bool_t options_start(void) From 0c9faaee47ec6c1c25201c1a51975d88382a90bd Mon Sep 17 00:00:00 2001 From: Jean Aunis Date: Mon, 2 May 2016 12:56:24 +0200 Subject: [PATCH 0400/1578] app_chanspy: fix audiohook options in non read-only mode When option 'o' was not set, ChanSpy created its audiohook with the flag AST_AUDIOHOOK_MUTE_WRITE, which caused ChanSpy to listen audio from one direction only. ASTERISK-25866 #close Change-Id: I5c745855eea29a3fbc4e4aed0b0c0f53580535e0 --- apps/app_chanspy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 400eed11a2d..df2deae3f54 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -509,8 +509,10 @@ static struct ast_generator spygen = { static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags) { ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan)); - if(!ast_test_flag(flags, OPTION_READONLY)) { - ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_MUTE_WRITE); + if(ast_test_flag(flags, OPTION_READONLY)) { + ast_set_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE); + } else { + ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); } if(ast_test_flag(flags, OPTION_LONG_QUEUE)) { ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n"); From 380ac201acf29efb2a69a4ef668a8d7da387f47b Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 2 May 2016 17:08:06 -0400 Subject: [PATCH 0401/1578] res_fax: add FAXMODE variable The app_fax set FAXMODE variable, but res_fax missing this feature. This patch add FAXMODE variable which is set to either "audio" or "T38". ASTERISK-25980 Change-Id: Ie3dcbfb72cc681e9e267a60202f7fb8723a51b6b --- CHANGES | 5 +++++ res/res_fax.c | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGES b/CHANGES index 8d1e339d614..255ccd24acc 100644 --- a/CHANGES +++ b/CHANGES @@ -275,6 +275,11 @@ Queue --- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- ------------------------------------------------------------------------------ +res_fax +------------------ + * Added FAXMODE variable to let dialplan know what fax transport was used. + FAXMODE variable is set to either "audio" or "T38". + res_pjsip ------------------ * Added new status Updated to AMI event ContactStatus on update registration diff --git a/res/res_fax.c b/res/res_fax.c index f171af92a93..33c3f116b90 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -1447,6 +1447,12 @@ static void set_channel_variables(struct ast_channel *chan, struct ast_fax_sessi pbx_builtin_setvar_helper(chan, "FAXBITRATE", S_OR(details->transfer_rate, NULL)); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", S_OR(details->resolution, NULL)); + if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) { + pbx_builtin_setvar_helper(chan, "FAXMODE", "T38"); + } else { + pbx_builtin_setvar_helper(chan, "FAXMODE", "audio"); + } + snprintf(buf, sizeof(buf), "%u", details->pages_transferred); pbx_builtin_setvar_helper(chan, "FAXPAGES", buf); } @@ -2071,6 +2077,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data) pbx_builtin_setvar_helper(chan, "FAXPAGES", "0"); pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); + pbx_builtin_setvar_helper(chan, "FAXMODE", NULL); /* Get a FAX session details structure from the channel's FAX datastore and create one if * it does not already exist. */ @@ -2578,6 +2585,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data) pbx_builtin_setvar_helper(chan, "FAXPAGES", "0"); pbx_builtin_setvar_helper(chan, "FAXBITRATE", NULL); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", NULL); + pbx_builtin_setvar_helper(chan, "FAXMODE", NULL); /* Get a requirement structure and set it. This structure is used * to tell the FAX technology module about the higher level FAX session */ From 02f4ca1079582ea6a095447a088420397cc36e45 Mon Sep 17 00:00:00 2001 From: Chris Trobridge Date: Wed, 4 May 2016 09:17:26 +0100 Subject: [PATCH 0402/1578] config_options.c: Expand #ifdef to contain whole if statement. ASTERISK-25956 #close Change-Id: If6961ec54be276d5ab4f012ee7e7b420cb45de38 --- main/config_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/config_options.c b/main/config_options.c index e59e5cf7afc..c58dfdd8686 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -197,9 +197,9 @@ static int link_option_to_types(struct aco_info *info, struct aco_type **types, xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type)) { #ifdef AST_DEVMODE opt->doc_unavailable = 1; -#endif #endif } +#endif } /* The container(s) should hold the only ref to opt */ ao2_ref(opt, -1); From 4df48581f18924614f3daca243fcff1a7482817b Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Wed, 4 May 2016 17:11:17 -0400 Subject: [PATCH 0403/1578] pjsip: Added "reg_server" to contacts (fixed alembic) ASTERISK-25931 Change-Id: Icc4321a88f5c93ff809da3f372eebbf69c6a8549 --- .../versions/81b01a191a46_pjsip_add_contact_reg_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py index 8bd151bd7a9..c25fc72335a 100644 --- a/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py +++ b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py @@ -21,5 +21,5 @@ def upgrade(): def downgrade(): op.drop_constraint('ps_contacts_uq', 'ps_contacts', type_='unique') - op.drop_column('reg_server') + op.drop_column('ps_contacts', 'reg_server') op.create_unique_constraint(None, 'ps_contacts', 'id') From 92f85fe766b47f6b7e2da149fcab00071e3aaa85 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 2 May 2016 17:52:16 -0400 Subject: [PATCH 0404/1578] res_fax/t38_gateway: Peer V.21 session is created on wrong channel The channel and peer V.21 sessions are created on the same channel now. The peer V.21 session should be created only on peer channel when one of channel can handle T.38. Also this patch enable debug for T.38 gateway session if global fax debug enabled. ASTERISK-25982 Change-Id: I78387156ea521a77eb0faf170179ddd37a50430e --- res/res_fax.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/res/res_fax.c b/res/res_fax.c index 33c3f116b90..c8ff1e988c6 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -626,6 +626,8 @@ static const struct ast_datastore_info fax_datastore = { static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_details *details); static int fax_detect_attach(struct ast_channel *chan, int timeout, int flags); static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan); +static struct ast_fax_session *fax_v21_session_new (struct ast_channel *chan); + /*! \brief Copies fax detection and gateway framehooks during masquerades * @@ -2835,6 +2837,23 @@ static void destroy_gateway(void *data) ao2_cleanup(gateway->peer_write_format); } +static struct ast_fax_session *fax_v21_session_new (struct ast_channel *chan) { + struct ast_fax_session_details *v21_details; + struct ast_fax_session *v21_session; + + if (!chan || !(v21_details = session_details_new())) { + return NULL; + } + + v21_details->caps = AST_FAX_TECH_V21_DETECT; + if (!(v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { + ao2_ref(v21_details, -1); + return NULL; + } + + return v21_session; +} + /*! \brief Create a new fax gateway object. * \param chan the channel the gateway object will be attached to * \param details the fax session details @@ -2843,30 +2862,16 @@ static void destroy_gateway(void *data) static struct fax_gateway *fax_gateway_new(struct ast_channel *chan, struct ast_fax_session_details *details) { struct fax_gateway *gateway = ao2_alloc(sizeof(*gateway), destroy_gateway); - struct ast_fax_session_details *v21_details; if (!gateway) { return NULL; } - if (!(v21_details = session_details_new())) { + if (!(gateway->chan_v21_session = fax_v21_session_new(chan))) { + ast_log(LOG_ERROR, "Can't create V21 session on chan %s for T.38 gateway session\n", ast_channel_name(chan)); ao2_ref(gateway, -1); return NULL; } - v21_details->caps = AST_FAX_TECH_V21_DETECT; - if (!(gateway->chan_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { - ao2_ref(v21_details, -1); - ao2_ref(gateway, -1); - return NULL; - } - - if (!(gateway->peer_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { - ao2_ref(v21_details, -1); - ao2_ref(gateway, -1); - return NULL; - } - ao2_ref(v21_details, -1); - gateway->framehook = -1; details->caps = AST_FAX_TECH_GATEWAY; @@ -3360,6 +3365,11 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_channel_unlock(peer); gateway->bridged = 1; + if (!(gateway->peer_v21_session = fax_v21_session_new(peer))) { + ast_log(LOG_ERROR, "Can't create V21 session on chan %s for T.38 gateway session\n", ast_channel_name(peer)); + ast_framehook_detach(chan, gateway->framehook); + return f; + } } if (gateway->bridged && !ast_tvzero(gateway->timeout_start)) { @@ -3486,6 +3496,10 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d .disable_inheritance = 1, /* Masquerade inheritance is handled through the datastore fixup */ }; + if (global_fax_debug) { + details->option.debug = AST_FAX_OPTFLAG_TRUE; + } + ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "gateway operation started successfully"); ast_string_field_set(details, error, "NO_ERROR"); From cc4c5f5693101b3c63ba083044729f24c3924685 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 15 Apr 2016 10:32:12 -0400 Subject: [PATCH 0405/1578] res_pjsip: improve realtime performance This patch modified pjsip_options to retrieve only permament contacts for aor if the qualify_frequency is > 0 and persisted contacts if the qualify_frequency is > 0. This patch also fixed a bug in res_sorcery_astdb. res_sorcery_astdb doesn't save object data retrived from astdb. ASTERISK-25826 Change-Id: I1831fa46c4578eae5a3e574ee3362fddf08a1f05 --- ...fb_ps_contacts_add_authenticate_qualify.py | 32 ++++++++++ res/res_pjsip.c | 7 ++ res/res_pjsip/location.c | 1 + res/res_pjsip/pjsip_options.c | 64 +++++++++++++------ res/res_sorcery_astdb.c | 3 +- 5 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py diff --git a/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py b/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py new file mode 100644 index 00000000000..76faf394cfd --- /dev/null +++ b/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py @@ -0,0 +1,32 @@ +"""ps_contacts add authenticate_qualify + +Revision ID: 6be31516058d +Revises: 81b01a191a46 +Create Date: 2016-05-03 14:57:12.538179 + +""" + +# revision identifiers, used by Alembic. +revision = '6be31516058d' +down_revision = '81b01a191a46' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_contacts', sa.Column('authenticate_qualify', yesno_values)) + + +def downgrade(): + op.drop_column('ps_contacts', 'authenticate_qualify') + diff --git a/res/res_pjsip.c b/res/res_pjsip.c index db3395fa704..a3b2d081d27 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1095,6 +1095,13 @@ If 0 no timeout. Time in fractional seconds. + + Authenticates a qualify request if needed + + If true and a qualify request receives a challenge or authenticate response + authentication is attempted before declaring the contact available. + + Outbound proxy used when sending OPTIONS request diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 2779fe3969e..fd6db6edc18 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1116,6 +1116,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400); ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout)); + ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify)); ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index c0d41c3d190..62640fe4e63 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1025,17 +1025,11 @@ int ast_sip_initialize_sorcery_qualify(void) return 0; } -static int qualify_and_schedule_cb(void *obj, void *arg, int flags) +static void qualify_and_schedule_contact(struct ast_sip_contact *contact) { - struct ast_sip_contact *contact = obj; - struct ast_sip_aor *aor = arg; int initial_interval; int max_time = ast_sip_get_max_initial_qualify_time(); - contact->qualify_frequency = aor->qualify_frequency; - contact->qualify_timeout = aor->qualify_timeout; - contact->authenticate_qualify = aor->authenticate_qualify; - /* Delay initial qualification by a random fraction of the specified interval */ if (max_time && max_time < contact->qualify_frequency) { initial_interval = max_time; @@ -1051,26 +1045,47 @@ static int qualify_and_schedule_cb(void *obj, void *arg, int flags) } else { update_contact_status(contact, UNKNOWN); } +} + +static int qualify_and_schedule_cb_with_aor(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_aor *aor = arg; + + contact->qualify_frequency = aor->qualify_frequency; + contact->qualify_timeout = aor->qualify_timeout; + contact->authenticate_qualify = aor->authenticate_qualify; + + qualify_and_schedule_contact(contact); + + return 0; +} + +static int qualify_and_schedule_cb_without_aor(void *obj, void *arg, int flags) +{ + qualify_and_schedule_contact((struct ast_sip_contact *) obj); return 0; } /*! * \internal - * \brief Qualify and schedule an endpoint's contacts + * \brief Qualify and schedule an aor's contacts * - * \details For the given endpoint retrieve its list of aors, qualify all - * contacts, and schedule for checks if configured. + * \details For the given aor check if it has permanent contacts, + * qualify all contacts and schedule for checks if configured. */ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) { struct ast_sip_aor *aor = obj; struct ao2_container *contacts; - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); - ao2_ref(contacts, -1); + if (aor->permanent_contacts) { + contacts = ast_sip_location_retrieve_aor_contacts(aor); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); + ao2_ref(contacts, -1); + } } return 0; @@ -1093,6 +1108,7 @@ static void qualify_and_schedule_all(void) { struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); struct ao2_container *aors; + struct ao2_container *contacts; if (!var) { return; @@ -1100,16 +1116,22 @@ static void qualify_and_schedule_all(void) aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); - ast_variables_destroy(var); - ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); - if (!aors) { - return; + if (aors) { + ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); + ao2_ref(aors, -1); } - ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); - ao2_ref(aors, -1); + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); + ao2_ref(contacts, -1); + } + + ast_variables_destroy(var); + } static int format_contact_status(void *obj, void *arg, int flags) @@ -1175,7 +1197,7 @@ static void aor_observer_modified(const void *obj) contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); ao2_ref(contacts, -1); } } diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index b3642d81e3f..dcfaba528b8 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -97,7 +97,6 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; - RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy); void *object = NULL; @@ -113,7 +112,7 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc } if (!(object = ast_sorcery_alloc(sorcery, type, key)) || - ast_sorcery_objectset_apply(sorcery, object, objset)) { + ast_sorcery_objectset_apply(sorcery, object, existing)) { ao2_cleanup(object); return NULL; } From 17b6ba49efcd9ca33c6202eb88bf6748fc0f3ebf Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 5 May 2016 07:07:50 -0300 Subject: [PATCH 0406/1578] file: Ensure nativeformats remains valid for lifetime of use. It is possible for the nativeformats of a channel to change throughout its lifetime. As a result a user of it needs to either ensure the channel is locked when accessing the formats or keep a reference to the nativeformats themselves. This change fixes the file playback support so it keeps a reference to the nativeformats when accessing things. ASTERISK-25998 #close Change-Id: Ie45b65475e1481ddf05b874ee48f63e39fff8915 --- main/file.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/main/file.c b/main/file.c index 654937a5824..450362544a9 100644 --- a/main/file.c +++ b/main/file.c @@ -799,7 +799,7 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil /* As above, but for video. But here we don't have translators * so we must enforce a format. */ - struct ast_format_cap *tmp_cap; + struct ast_format_cap *nativeformats, *tmp_cap; char *buf; int buflen; int i, fd; @@ -810,16 +810,23 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil buflen = strlen(preflang) + strlen(filename) + 4; buf = ast_alloca(buflen); + ast_channel_lock(chan); + nativeformats = ao2_bump(ast_channel_nativeformats(chan)); + ast_channel_unlock(chan); + /* is the channel capable of video without translation ?*/ - if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO)) { + if (!ast_format_cap_has_type(nativeformats, AST_MEDIA_TYPE_VIDEO)) { + ao2_cleanup(nativeformats); return NULL; } if (!(tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ao2_cleanup(nativeformats); return NULL; } /* Video is supported, so see what video formats exist for this file */ if (!fileexists_core(filename, NULL, preflang, buf, buflen, tmp_cap)) { ao2_ref(tmp_cap, -1); + ao2_cleanup(nativeformats); return NULL; } @@ -828,7 +835,7 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil struct ast_format *format = ast_format_cap_get_format(tmp_cap, i); if ((ast_format_get_type(format) != AST_MEDIA_TYPE_VIDEO) || - !ast_format_cap_iscompatible(ast_channel_nativeformats(chan), tmp_cap)) { + !ast_format_cap_iscompatible(nativeformats, tmp_cap)) { ao2_ref(format, -1); continue; } @@ -837,12 +844,14 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil if (fd >= 0) { ao2_ref(format, -1); ao2_ref(tmp_cap, -1); + ao2_cleanup(nativeformats); return ast_channel_vstream(chan); } ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename); ao2_ref(format, -1); } ao2_ref(tmp_cap, -1); + ao2_cleanup(nativeformats); return NULL; } @@ -1097,8 +1106,10 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p fs = ast_openstream(chan, filename, preflang); if (!fs) { struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + ast_channel_lock(chan); ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), strerror(errno)); + ast_channel_unlock(chan); return -1; } @@ -1133,7 +1144,12 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p res = ast_playstream(fs); if (!res && vfs) res = ast_playstream(vfs); - ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default"); + + if (VERBOSITY_ATLEAST(3)) { + ast_channel_lock(chan); + ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default"); + ast_channel_unlock(chan); + } return res; } From dfbb03cc8e1d284b50805be8dfd6eb5595172143 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 3 May 2016 15:31:19 -0500 Subject: [PATCH 0407/1578] res_pjsip_outbound_publish: Potential crash due to off nominal path It was possible for the explicit publish destroy function to be called without the pjsip client ever being initialized. This fix checks to make sure there is a client to destroy before attempting. Change-Id: I8eea1bfa3bd472149bfc255310be2a6248688f5c --- res/res_pjsip_outbound_publish.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 0265c424e32..ed06a33d1ae 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -701,8 +701,15 @@ static int explicit_publish_destroy(void *data) { struct ast_sip_outbound_publish_client *client = data; - pjsip_publishc_destroy(client->client); - ao2_ref(client, -1); + /* + * If there is no pjsip publishing client then we obviously don't need + * to destroy it. Also, the ref for the Asterisk publishing client that + * pjsip had would not exist or should already be gone as well. + */ + if (client->client) { + pjsip_publishc_destroy(client->client); + ao2_ref(client, -1); + } return 0; } From 41fccbfeb19a2e96596fe867a3cd94397f307ba4 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 3 May 2016 14:59:06 -0500 Subject: [PATCH 0408/1578] res_pjsip_outbound_publish: Ref leak in off nominal callback paths There were a few spots where the client object's reference was being leaked in sip_outbound_publish_callback. This patch cleans up those leaks. Change-Id: I485d0bc9335090f373026f77c548042e258461df --- res/res_pjsip_outbound_publish.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index ed06a33d1ae..f13af10def0 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -889,6 +889,11 @@ static int sip_outbound_publish_client_alloc(void *data) /*! \brief Callback function for publish client responses */ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) { +#define DESTROY_CLIENT() do { \ + pjsip_publishc_destroy(client->client); \ + client->client = NULL; \ + ao2_ref(client, -1); } while (0) + RAII_VAR(struct ast_sip_outbound_publish_client *, client, ao2_bump(param->token), ao2_cleanup); RAII_VAR(struct ast_sip_outbound_publish *, publish, ao2_bump(client->publish), ao2_cleanup); SCOPED_AO2LOCK(lock, client); @@ -906,8 +911,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) ao2_ref(client, -1); } /* Once the destroy is called this callback will not get called any longer, so drop the client ref */ - pjsip_publishc_destroy(client->client); - ao2_ref(client, -1); + DESTROY_CLIENT(); return; } @@ -926,9 +930,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) client->auth_attempts++; if (client->auth_attempts == publish->max_auth_attempts) { - pjsip_publishc_destroy(client->client); - client->client = NULL; - + DESTROY_CLIENT(); ast_log(LOG_ERROR, "Reached maximum number of PUBLISH authentication attempts on outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); @@ -940,9 +942,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) client->auth_attempts = 0; if (param->code == 412) { - pjsip_publishc_destroy(client->client); - client->client = NULL; - + DESTROY_CLIENT(); if (sip_outbound_publish_client_alloc(client)) { ast_log(LOG_ERROR, "Failed to create a new outbound publish client for '%s' on 412 response\n", ast_sorcery_object_get_id(publish)); @@ -957,10 +957,9 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) expires = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_MIN_EXPIRES, NULL); if (!expires || !expires->ivalue) { + DESTROY_CLIENT(); ast_log(LOG_ERROR, "Received 423 response on outbound publish '%s' without a Min-Expires header\n", ast_sorcery_object_get_id(publish)); - pjsip_publishc_destroy(client->client); - client->client = NULL; goto end; } From 3b0ce5169d123312e4b4ac5a65b23325a59ba2a7 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 3 May 2016 15:39:32 -0500 Subject: [PATCH 0409/1578] res_pjsip_outbound_publish: Won't unload if condition wait times out When res_pjsip_outbound_publish unloads it has to wait for all current publishing objects to get done. However if the wait condition times out then it does not fail the unload. This sometimes results in an infinite loop check while unloading. This patch now fails the unload operation if the condition times out. Change-Id: Id57b8cbed9d61222690fcba1e4f18e259df4c7ec --- res/res_pjsip_outbound_publish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index f13af10def0..0f0e290af95 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -1221,7 +1221,7 @@ static int unload_module(void) /* wait for items to unpublish */ ast_verb(5, "Waiting to complete unpublishing task(s)\n"); - while (unloading.count) { + while (unloading.count && !res) { res = ast_cond_timedwait(&unloading.cond, &unloading.lock, &end); } ast_mutex_unlock(&unloading.lock); From adc82a2260382383bfb6593adfaa8b8b7ef7d7d8 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 3 May 2016 15:35:24 -0500 Subject: [PATCH 0410/1578] res_pjsip_outbound_publishing: After unloading the library won't load again The same thing was happening in res_pjsip_publish_asterisk. When the library was unloaded it did not unregister the object type from sorcery. Subsequent loads resulted in a failed load due to the sorcery type already existing. Change-Id: Ifdc25e94e4cd40bc5a19eb4d0a00b86c2e9fedc9 --- res/res_pjsip_outbound_publish.c | 2 ++ res/res_pjsip_publish_asterisk.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 0f0e290af95..c08737bd6a5 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -1162,6 +1162,7 @@ static int load_module(void) if (ast_sorcery_object_register(ast_sip_get_sorcery(), "outbound-publish", sip_outbound_publish_alloc, NULL, sip_outbound_publish_apply)) { + ast_log(LOG_ERROR, "Unable to register 'outbound-publish' type with sorcery\n"); return AST_MODULE_LOAD_DECLINE; } @@ -1234,6 +1235,7 @@ static int unload_module(void) "in the allowed time\n", unloading.count); } else { ast_verb(5, "All items successfully unpublished\n"); + ast_sorcery_object_unregister(ast_sip_get_sorcery(), "outbound-publish"); } return res; diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 3218b0a0cd3..002d976d42e 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -862,6 +862,7 @@ static int load_module(void) ast_sorcery_apply_default(ast_sip_get_sorcery(), "asterisk-publication", "config", "pjsip.conf,criteria=type=asterisk-publication"); if (ast_sorcery_object_register(ast_sip_get_sorcery(), "asterisk-publication", asterisk_publication_config_alloc, NULL, NULL)) { + ast_log(LOG_ERROR, "Unable to register 'asterisk-publication' type with sorcery\n"); return AST_MODULE_LOAD_DECLINE; } @@ -919,6 +920,7 @@ static int unload_module(void) ast_sip_unregister_publish_handler(&asterisk_mwi_publication_handler); ast_sip_unregister_event_publisher_handler(&asterisk_devicestate_publisher_handler); ast_sip_unregister_event_publisher_handler(&asterisk_mwi_publisher_handler); + ast_sorcery_object_unregister(ast_sip_get_sorcery(), "asterisk-publication"); return 0; } From 64e058f75ad6e1dd81e43200344b759fd45a3cde Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 3 May 2016 15:43:16 -0500 Subject: [PATCH 0411/1578] res_pjsip_outbound_publish: state potential dropped on reloads/realtime fetches When reloading, or fetching realtime data, if the "apply" failed for any numerous reasons the current state object would not be maintained. This potentially resulted in publishes being stopped for some states/clients when they should not have been. This patch makes it so the current state object is kept upon any type of reload/ fetch failures. Change-Id: Iab6020c116d628ed2ae81183e987e2eaa3c90b30 --- res/res_pjsip_outbound_publish.c | 153 +++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 36 deletions(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index c08737bd6a5..51e8a06be6c 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -406,22 +406,30 @@ static void sip_outbound_publish_synchronize(struct ast_sip_event_publisher_hand ao2_ref(states, -1); } -struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name) +static struct ast_sip_outbound_publish_state *sip_publish_state_get(const char *id) { - RAII_VAR(struct ao2_container *, states, - ao2_global_obj_ref(current_states), ao2_cleanup); - RAII_VAR(struct ast_sip_outbound_publish_state *, state, NULL, ao2_cleanup); + struct ao2_container *states = ao2_global_obj_ref(current_states); + struct ast_sip_outbound_publish_state *res; if (!states) { return NULL; } - state = ao2_find(states, name, OBJ_SEARCH_KEY); + res = ao2_find(states, id, OBJ_SEARCH_KEY); + ao2_ref(states, -1); + return res; +} + +struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name) +{ + struct ast_sip_outbound_publish_state *state = sip_publish_state_get(name); + if (!state) { return NULL; } ao2_ref(state->client, +1); + ao2_ref(state, -1); return state->client; } @@ -1086,25 +1094,89 @@ static struct ast_sip_outbound_publish_state *sip_outbound_publish_state_alloc( return state; } -/*! \brief Apply function which finds or allocates a state structure */ -static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *obj) +static int initialize_publish_client(struct ast_sip_outbound_publish *publish, + struct ast_sip_outbound_publish_state *state) { - RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup); - RAII_VAR(struct ast_sip_outbound_publish_state *, state, NULL, ao2_cleanup); - struct ast_sip_outbound_publish *applied = obj; + if (ast_sip_push_task_synchronous(NULL, sip_outbound_publish_client_alloc, state->client)) { + ast_log(LOG_ERROR, "Unable to create client for outbound publish '%s'\n", + ast_sorcery_object_get_id(publish)); + return -1; + } - if (ast_strlen_zero(applied->server_uri)) { + return 0; +} + +static int validate_publish_config(struct ast_sip_outbound_publish *publish) +{ + if (ast_strlen_zero(publish->server_uri)) { ast_log(LOG_ERROR, "No server URI specified on outbound publish '%s'\n", - ast_sorcery_object_get_id(applied)); + ast_sorcery_object_get_id(publish)); return -1; - } else if (ast_strlen_zero(applied->event)) { + } else if (ast_strlen_zero(publish->event)) { ast_log(LOG_ERROR, "No event type specified for outbound publish '%s'\n", - ast_sorcery_object_get_id(applied)); + ast_sorcery_object_get_id(publish)); + return -1; + } + return 0; +} + +static int current_state_reusable(struct ast_sip_outbound_publish *publish, + struct ast_sip_outbound_publish_state *current_state) +{ + struct ast_sip_outbound_publish *old_publish; + + if (!can_reuse_publish(current_state->client->publish, publish)) { + /* + * Something significant has changed in the configuration, so we are + * unable to use the old state object. The current state needs to go + * away and a new one needs to be created. + */ + return 0; + } + + /* + * We can reuse the current state object so keep it, but swap out the + * underlying publish object with the new one. + */ + old_publish = current_state->client->publish; + current_state->client->publish = publish; + if (initialize_publish_client(publish, current_state)) { + /* + * If the state object fails to re-initialize then swap + * the old publish info back in. + */ + current_state->client->publish = publish; return -1; } + /* + * Since we swapped out the publish object the new one needs a ref + * while the old one needs to go away. + */ + ao2_ref(current_state->client->publish, +1); + ao2_cleanup(old_publish); + + /* Tell the caller that the current state object should be used */ + return 1; +} + +/*! \brief Apply function which finds or allocates a state structure */ +static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *obj) +{ +#define ADD_TO_NEW_STATES(__obj) \ + do { if (__obj) { \ + ao2_link(new_states, __obj); \ + ao2_ref(__obj, -1); } } while (0) + + struct ast_sip_outbound_publish *applied = obj; + struct ast_sip_outbound_publish_state *current_state, *new_state; + int res; + + /* + * New states are being loaded or reloaded. We'll need to add the new + * object if created/updated, or keep the old object if an error occurs. + */ if (!new_states) { - /* make sure new_states has been allocated as we will be adding to it */ new_states = ao2_container_alloc_options( AO2_ALLOC_OPT_LOCK_NOLOCK, DEFAULT_STATE_BUCKETS, outbound_publish_state_hash, outbound_publish_state_cmp); @@ -1115,35 +1187,44 @@ static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *o } } - if (states) { - state = ao2_find(states, ast_sorcery_object_get_id(obj), OBJ_SEARCH_KEY); - if (state) { - if (can_reuse_publish(state->client->publish, applied)) { - ao2_replace(state->client->publish, applied); - } else { - ao2_ref(state, -1); - state = NULL; - } - } + /* If there is current state we'll want to maintain it if any errors occur */ + current_state = sip_publish_state_get(ast_sorcery_object_get_id(applied)); + + if ((res = validate_publish_config(applied))) { + ADD_TO_NEW_STATES(current_state); + return res; } - if (!state) { - state = sip_outbound_publish_state_alloc(applied); - if (!state) { - ast_log(LOG_ERROR, "Unable to create state for outbound publish '%s'\n", - ast_sorcery_object_get_id(applied)); - return -1; - }; + if (current_state && (res = current_state_reusable(applied, current_state))) { + /* + * The current state object was able to be reused, or an error + * occurred. Either way we keep the current state and be done. + */ + ADD_TO_NEW_STATES(current_state); + return res == 1 ? 0 : -1; } - if (ast_sip_push_task_synchronous(NULL, sip_outbound_publish_client_alloc, state->client)) { - ast_log(LOG_ERROR, "Unable to create client for outbound publish '%s'\n", + /* + * No current state was found or it was unable to be reused. Either way + * we'll need to create a new state object. + */ + new_state = sip_outbound_publish_state_alloc(applied); + if (!new_state) { + ast_log(LOG_ERROR, "Unable to create state for outbound publish '%s'\n", ast_sorcery_object_get_id(applied)); + ADD_TO_NEW_STATES(current_state); + return -1; + }; + + if (initialize_publish_client(applied, new_state)) { + ADD_TO_NEW_STATES(current_state); + ao2_ref(new_state, -1); return -1; } - ao2_link(new_states, state); - return 0; + ADD_TO_NEW_STATES(new_state); + ao2_cleanup(current_state); + return res; } static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) From 516f49f316222a7e15919e5d8b3b69d4254ed2b2 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 5 May 2016 16:16:16 -0400 Subject: [PATCH 0412/1578] stasis_endpoints: Add new Status and Headers to ContactStatus ASTERISK-25903 added a new headers to AMI Event ContactStatusDetail. ASTERISK-25904 added a new Status to AMI Event ContactStatusDetail. These additions should be also in stasis_endpoints to include in command "manager show event ContactStatus" Change-Id: I7610ad02a998e1f26c20caa27aa50279d0164f6a --- main/stasis_endpoints.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index 931bbb97d91..14d3d0ca1e5 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -86,6 +86,7 @@ ASTERISK_REGISTER_FILE() + @@ -97,6 +98,12 @@ ASTERISK_REGISTER_FILE() The RTT measured during the last qualify. + + Content of the User-Agent header in REGISTER request + + + Absolute time that this contact is no longer valid after + From 322c3b4262a8f5d2184465e0f86445864e1a533d Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 6 May 2016 12:54:17 -0400 Subject: [PATCH 0413/1578] res_pjsip: module load priority The res_pjsip_authenticator_digest, res_pjsip_endpoint_identifier_* and res_pjsip_registrar modules should load ASAP to avoid "No matching endpoint found" for legitimate endpoint. ASTERISK-25994 Change-Id: Iac95d95ad031e0be104189d29e923a2ad7c24a1b --- res/res_pjsip_authenticator_digest.c | 2 +- res/res_pjsip_endpoint_identifier_ip.c | 2 +- res/res_pjsip_endpoint_identifier_user.c | 2 +- res/res_pjsip_registrar.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c index 4a31edfc46f..a512b45b1bf 100644 --- a/res/res_pjsip_authenticator_digest.c +++ b/res/res_pjsip_authenticator_digest.c @@ -509,5 +509,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication .load = load_module, .unload = unload_module, .reload = reload_module, - .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, ); diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 016e0b4ad08..7a7af0b4e02 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -515,5 +515,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP IP endpoint ide .load = load_module, .reload = reload_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, ); diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c index 172566a9fdb..6aa2c553206 100644 --- a/res/res_pjsip_endpoint_identifier_user.c +++ b/res/res_pjsip_endpoint_identifier_user.c @@ -201,5 +201,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP username endpoi .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, ); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 65fd56c02dd..cbc33ab80f1 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -957,5 +957,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Suppo .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3, ); From facce6f63220b996dbb0f57412a051876e468973 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 8 May 2016 19:19:50 -0600 Subject: [PATCH 0414/1578] pjproject_bundled: Check for python-dev and TEST_FRAMEWORK The pjsua and pjsystest apps are now built only if TEST_FRAMEWORK is set. The python bindings are now built only if TEST_FRAMEWORK is set and a python development package is installed. libresample was also disabled. ASTERISK-25993 #close Reported-by: Joshua Colp Change-Id: If4e91c503a02f113d5b71bc8b972081fa3ff6f03 --- configure | 101 +++++++++++++++++++++++++++ configure.ac | 4 ++ include/asterisk/autoconfig.h.in | 3 + makeopts.in | 3 + third-party/pjproject/Makefile | 20 ++++-- third-party/pjproject/Makefile.rules | 2 +- 6 files changed, 127 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 171693a3113..751fbea5dad 100755 --- a/configure +++ b/configure @@ -663,6 +663,10 @@ PWLIB_LIBDIR PWLIB_INCDIR PWLIBDIR PTLIB_CONFIG +PYTHONDEV_LIBS +PYTHONDEV_CFLAGS +PYTHONDEV_INCLUDE +PYTHONDEV_LIB PJPROJECT_LIBS PJPROJECT_CFLAGS PG_CONFIG @@ -1425,6 +1429,8 @@ LIBEDIT_CFLAGS LIBEDIT_LIBS PJPROJECT_CFLAGS PJPROJECT_LIBS +PYTHONDEV_CFLAGS +PYTHONDEV_LIBS GMIME_CFLAGS GMIME_LIBS GTK2_CFLAGS @@ -2168,6 +2174,10 @@ Some influential environment variables: C compiler flags for PJPROJECT, overriding pkg-config PJPROJECT_LIBS linker flags for PJPROJECT, overriding pkg-config + PYTHONDEV_CFLAGS + C compiler flags for PYTHONDEV, overriding pkg-config + PYTHONDEV_LIBS + linker flags for PYTHONDEV, overriding pkg-config GMIME_CFLAGS C compiler flags for GMIME, overriding pkg-config GMIME_LIBS linker flags for GMIME, overriding pkg-config @@ -25444,6 +25454,97 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi + + + if test "x${PBX_PYTHONDEV}" != "x1" -a "${USE_PYTHONDEV}" != "no"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYTHONDEV" >&5 +$as_echo_n "checking for PYTHONDEV... " >&6; } + +if test -n "$PYTHONDEV_CFLAGS"; then + pkg_cv_PYTHONDEV_CFLAGS="$PYTHONDEV_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"python\""; } >&5 + ($PKG_CONFIG --exists --print-errors "python") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PYTHONDEV_CFLAGS=`$PKG_CONFIG --cflags "python" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PYTHONDEV_LIBS"; then + pkg_cv_PYTHONDEV_LIBS="$PYTHONDEV_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"python\""; } >&5 + ($PKG_CONFIG --exists --print-errors "python") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PYTHONDEV_LIBS=`$PKG_CONFIG --libs "python" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PYTHONDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "python" 2>&1` + else + PYTHONDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "python" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PYTHONDEV_PKG_ERRORS" >&5 + + + PBX_PYTHONDEV=0 + + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + PBX_PYTHONDEV=0 + + +else + PYTHONDEV_CFLAGS=$pkg_cv_PYTHONDEV_CFLAGS + PYTHONDEV_LIBS=$pkg_cv_PYTHONDEV_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + PBX_PYTHONDEV=1 + PYTHONDEV_INCLUDE="$PYTHONDEV_CFLAGS" + PYTHONDEV_LIB="$PYTHONDEV_LIBS" + +$as_echo "#define HAVE_PYTHONDEV 1" >>confdefs.h + + +fi + fi + + + if test "x${PBX_POPT}" != "x1" -a "${USE_POPT}" != "no"; then pbxlibdir="" # if --with-POPT=DIR has been specified, use it. diff --git a/configure.ac b/configure.ac index b136d867f91..9c11054e93c 100644 --- a/configure.ac +++ b/configure.ac @@ -2207,6 +2207,10 @@ if test "$USE_PJPROJECT" != "no" ; then fi fi +AC_SUBST([PYTHONDEV_LIB]) +AC_SUBST([PYTHONDEV_INCLUDE]) +AST_PKG_CONFIG_CHECK([PYTHONDEV], [python]) + AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h]) AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h]) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index b5fe655d7fa..72242122828 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -730,6 +730,9 @@ /* Define if your system has the PWLib libraries. */ #undef HAVE_PWLIB +/* Define if your system has the PYTHONDEV libraries. */ +#undef HAVE_PYTHONDEV + /* Define to 1 if you have the Radius Client library. */ #undef HAVE_RADIUS diff --git a/makeopts.in b/makeopts.in index 6baef1b4660..d4347daf1be 100644 --- a/makeopts.in +++ b/makeopts.in @@ -243,6 +243,9 @@ PORTAUDIO_LIB=@PORTAUDIO_LIB@ PRI_INCLUDE=@PRI_INCLUDE@ PRI_LIB=@PRI_LIB@ +PYTHONDEV_INCLUDE=@PYTHONDEV_INCLUDE@ +PYTHONDEV_LIB=@PYTHONDEV_LIB@ + RESAMPLE_INCLUDE=@RESAMPLE_INCLUDE@ RESAMPLE_LIB=@RESAMPLE_LIB@ diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 7fa3902baa7..7349db62f83 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -45,6 +45,13 @@ ifeq ($(SPECIAL_TARGETS),) CF := $(filter-out -I%,$(CF)) export CFLAGS += $(CF) export LDFLAGS += $(CC_LDFLAGS) + TARGETS := pjproject.symbols + ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),TEST_FRAMEWORK) + TARGETS += source/pjsip-apps/bin/pjsua-$(TARGET_NAME) + ifneq ($(PYTHONDEV_LIB),) + TARGETS += source/pjsip-apps/src/python/build/_pjsua.so + endif + endif else all install: endif @@ -95,12 +102,10 @@ source/pjlib/build/.pjlib-$(TARGET_NAME).depend: build.mak $(ECHO_PREFIX) "Making dependencies" +$(CMD_PREFIX) $(SUBMAKE) -C source dep - menuselect: ../../menuselect.makeopts ../../makeopts -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || : -$(CMD_PREFIX) rm -rf pjproject.symbols - source/pjlib/lib/libpj-$(TARGET_NAME).a: menuselect source/pjlib/build/.pjlib-$(TARGET_NAME).depend $(ECHO_PREFIX) Compiling libs +$(CMD_PREFIX) $(SUBMAKE) -C source lib $(REALLY_QUIET) @@ -117,17 +122,22 @@ source/pjsip-apps/src/python/build/_pjsua.so: source/pjlib/lib/libpj-$(TARGET_NA $(ECHO_PREFIX) Compiling python bindings $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; MAKE=$(MAKE) python setup.py build --build-platlib=./build $(REALLY_QUIET)) -_all: pjproject.symbols source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/src/python/build/_pjsua.so +_all: $(TARGETS) _install: _all - $(ECHO_PREFIX) Installing apps and python bindings @if [ ! -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject" ]; then \ $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject"; \ fi; +ifneq ($(findstring source/pjsip-apps/bin/pjsua-$(TARGET_NAME),$(TARGETS)),) + $(ECHO_PREFIX) Installing apps $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsua-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsua" $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsystest-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsystest" +endif +ifneq ($(findstring source/pjsip-apps/src/python/build/_pjsua.so,$(TARGETS)),) + $(ECHO_PREFIX) Installing python bindings $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/src/python/build/_pjsua.so "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" $(CMD_PREFIX) $(INSTALL) -m 644 source/pjsip-apps/src/python/build/pjsua.py "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" +endif uninstall: $(ECHO_PREFIX) Uninstalling apps and python bindings @@ -135,7 +145,7 @@ uninstall: clean: $(ECHO_PREFIX) Cleaning - -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || : + -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build ; rm -rf source/pjsip-apps/bin/* ) || : -$(CMD_PREFIX) rm -rf pjproject.symbols distclean: diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index 6b51c2f2a76..d2e7d25a4b7 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -3,7 +3,7 @@ PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --disable-speex-codec --disable-speex-aec \ --disable-gsm-codec --disable-video --disable-v4l2 --disable-sound --disable-opencore-amr \ - --disable-ilbc-codec --without-libyuv --disable-g7221-codec + --disable-ilbc-codec --without-libyuv --disable-g7221-codec --disable-resample ifeq ($(shell uname -s),Linux) PJPROJECT_CONFIG_OPTS += --enable-epoll From 8923c9ac965a156bd2c0839e95d30023cd4088d4 Mon Sep 17 00:00:00 2001 From: Jaco Kroon Date: Wed, 4 May 2016 09:40:55 +0200 Subject: [PATCH 0415/1578] app_confbridge: Add a regcontext option for confbridge bridge profiles. This patch allows for having app_confbridge register the name of the conference as an extension into a specific context, similar to regcontext for chan_sip. This variant is not quite as involved as the one in chan_sip and doesn't allow for multiple contexts or custom extensions, you can only specify the context and the conference name will always be used as the extension to register. ASTERISK-25989 #close Change-Id: Icacf94d9f2b5dfd31ef36f6cb702392619a7902f --- CHANGES | 8 ++++++++ apps/app_confbridge.c | 15 +++++++++++++++ apps/confbridge/conf_config_parser.c | 19 +++++++++++++++++++ apps/confbridge/include/confbridge.h | 1 + configs/samples/confbridge.conf.sample | 2 ++ 5 files changed, 45 insertions(+) diff --git a/CHANGES b/CHANGES index 8d1e339d614..f11212810de 100644 --- a/CHANGES +++ b/CHANGES @@ -284,6 +284,14 @@ res_pjsip into the "reg_server" field in the ps_contacts table to facilitate multi-server setups. +app_confbridge +------------------ + * Added a bridge profile option called regcontext that allows you to + dynamically register the conference bridge name as an extension into + the specified context. This allows tracking down conferences on multi- + server installations via alternate means (DUNDI for example). By default + this feature is not used. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.8.0 to Asterisk 13.9.0 ------------ ------------------------------------------------------------------------------ diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index b3609b6734a..82204c48fce 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1256,9 +1256,17 @@ void conf_handle_second_active(struct confbridge_conference *conference) void conf_ended(struct confbridge_conference *conference) { + struct pbx_find_info q = { .stacklen = 0 }; + /* Called with a reference to conference */ ao2_unlink(conference_bridges, conference); send_conf_end_event(conference); + if (!ast_strlen_zero(conference->b_profile.regcontext) && + pbx_find_extension(NULL, NULL, &q, conference->b_profile.regcontext, + conference->name, 1, NULL, "", E_MATCH)) { + ast_context_remove_extension(conference->b_profile.regcontext, + conference->name, 1, NULL); + } ao2_lock(conference); conf_stop_record(conference); ao2_unlock(conference); @@ -1363,6 +1371,13 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen } send_conf_start_event(conference); + + if (!ast_strlen_zero(conference->b_profile.regcontext)) { + if (!ast_exists_extension(NULL, conference->b_profile.regcontext, conference->name, 1, NULL)) { + ast_add_extension(conference->b_profile.regcontext, 1, conference->name, 1, NULL, NULL, "Noop", NULL, NULL, "ConfBridge"); + } + } + ast_debug(1, "Created conference '%s' and linked to container.\n", conference_name); } diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index a33c6a12a77..69d6f69eafd 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -339,6 +339,22 @@ ASTERISK_REGISTER_FILE() unescaped to X. All variables will be evaluated at the time ConfBridge is called. + + The name of the context into which to register the name of the conference bridge as NoOP() at priority 1 + + When set this will cause the name of the created conference to be registered + into the named context at priority 1 with an operation of NoOP(). This can + then be used in other parts of the dialplan to test for the existence of a + specific conference bridge. + You should be aware that there are potential races between testing for the + existence of a bridge, and taking action upon that information, consider + for example two callers executing the check simultaniously, and then taking + special action as "first caller" into the bridge. The same for exiting, + directly after the check the bridge can be destroyed before the new caller + enters (creating a new bridge), for example, and the "first member" actions + could thus be missed. + + Sets how confbridge handles video distribution to the conference participants @@ -1595,6 +1611,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, ast_cli(a->fd,"Max Members: No Limit\n"); } + ast_cli(a->fd,"Registration context: %s\n", b_profile.regcontext); + switch (b_profile.flags & (BRIDGE_OPT_VIDEO_SRC_LAST_MARKED | BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) { @@ -2163,6 +2181,7 @@ int conf_load_config(void) aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file)); aco_option_register(&cfg_info, "record_options", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_options)); aco_option_register(&cfg_info, "record_command", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_command)); + aco_option_register(&cfg_info, "regcontext", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, regcontext)); aco_option_register(&cfg_info, "language", ACO_EXACT, bridge_types, "en", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, language)); aco_option_register_custom(&cfg_info, "^sound_", ACO_REGEX, bridge_types, NULL, sound_option_handler, 0); /* This option should only be used with the CONFBRIDGE dialplan function */ diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 539b9961b3f..5ae0421131b 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -210,6 +210,7 @@ struct bridge_profile { unsigned int internal_sample_rate; /*!< The internal sample rate of the bridge. 0 when set to auto adjust mode. */ unsigned int mix_interval; /*!< The internal mixing interval used by the bridge. When set to 0 the bridgewill use a default interval. */ struct bridge_profile_sounds *sounds; + char regcontext[AST_MAX_CONTEXT]; }; /*! \brief The structure that represents a conference bridge */ diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index e7386859688..5b9f52d4f74 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -217,6 +217,8 @@ type=bridge ;language=en ; Set the language used for announcements to the conference. ; Default is en (English). +;regcontext=conferences ; The name of the context into which to register conference names as extensions. + ; All sounds in the conference are customizable using the bridge profile options below. ; Simply state the option followed by the filename or full path of the filename after ; the option. Example: sound_had_joined=conf-hasjoin This will play the conf-hasjoin From 94cd351ec422287295c79658fb3d36f04b5966a5 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 5 May 2016 11:12:59 -0300 Subject: [PATCH 0416/1578] datastore: Add common container based datastores API. This change introduces a common container based datastores management API. This has been done in a few places across the tree but this consolidates all of the logic into one place in a generic fashion. ASTERISK-25999 Change-Id: I72eb15941dcdbc2a37bb00a33ce00f8755bd336a --- include/asterisk/datastore.h | 58 ++++++++++++++++++++++++++ main/datastore.c | 80 ++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/include/asterisk/datastore.h b/include/asterisk/datastore.h index 8f59fd3cf7e..85e9c6890ac 100644 --- a/include/asterisk/datastore.h +++ b/include/asterisk/datastore.h @@ -92,6 +92,64 @@ struct ast_datastore * attribute_malloc __ast_datastore_alloc(const struct ast_d */ int ast_datastore_free(struct ast_datastore *datastore); +/*! + * \brief Allocate a specialized data stores container + * + * \return a container for storing data stores + * + * \since 14.0.0 + */ +struct ao2_container *ast_datastores_alloc(void); + +/*! + * \brief Add a data store to a container + * + * \param[in] datastores container to store datastore in + * \param[in] datastore datastore to add + * + * \retval 0 success + * \retval -1 failure + * + * \since 14.0.0 + */ +int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore); + +/*! + * \brief Remove a data store from a container + * + * \param[in] datastores container to remove datastore from + * \param[in] name name of the data store to remove + * + * \since 14.0.0 + */ +void ast_datastores_remove(struct ao2_container *datastores, const char *name); + +/*! + * \brief Find a data store in a container + * + * \param[in] datastores container to find datastore in + * \param[in] name name of the data store to find + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 14.0.0 + */ +struct ast_datastore *ast_datastores_find(struct ao2_container *datastores, const char *name); + +/*! + * \brief Allocate a datastore for use with the datastores container + * + * \param[in] info information about the datastore + * \param[in] uid unique identifier for the datastore + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 14.0.0 + */ +struct ast_datastore *ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/datastore.c b/main/datastore.c index a9079e8375e..c2bba41904b 100644 --- a/main/datastore.c +++ b/main/datastore.c @@ -31,6 +31,11 @@ ASTERISK_REGISTER_FILE() #include "asterisk/datastore.h" #include "asterisk/utils.h" +#include "asterisk/astobj2.h" +#include "asterisk/uuid.h" + +/*! \brief Number of buckets for datastore container */ +#define DATASTORE_BUCKETS 53 struct ast_datastore *__ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid, const char *file, int line, const char *function) @@ -83,3 +88,78 @@ int ast_datastore_free(struct ast_datastore *datastore) return res; } + +AO2_STRING_FIELD_HASH_FN(ast_datastore, uid); +AO2_STRING_FIELD_CMP_FN(ast_datastore, uid); + +struct ao2_container *ast_datastores_alloc(void) +{ + return ao2_container_alloc(DATASTORE_BUCKETS, ast_datastore_hash_fn, ast_datastore_cmp_fn); +} + +int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore) +{ + ast_assert(datastore != NULL); + ast_assert(datastore->info != NULL); + ast_assert(!ast_strlen_zero(datastore->uid)); + + if (!ao2_link(datastores, datastore)) { + return -1; + } + + return 0; +} + +void ast_datastores_remove(struct ao2_container *datastores, const char *name) +{ + ao2_find(datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); +} + +struct ast_datastore *ast_datastores_find(struct ao2_container *datastores, const char *name) +{ + return ao2_find(datastores, name, OBJ_SEARCH_KEY); +} + +static void datastore_destroy(void *obj) +{ + struct ast_datastore *datastore = obj; + + /* Using the destroy function (if present) destroy the data */ + if (datastore->info->destroy != NULL && datastore->data != NULL) { + datastore->info->destroy(datastore->data); + datastore->data = NULL; + } + + ast_free((void *) datastore->uid); + datastore->uid = NULL; +} + +struct ast_datastore *ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid) +{ + struct ast_datastore *datastore; + char uuid_buf[AST_UUID_STR_LEN]; + const char *uid_ptr = uid; + + if (!info) { + return NULL; + } + + datastore = ao2_alloc(sizeof(*datastore), datastore_destroy); + if (!datastore) { + return NULL; + } + + datastore->info = info; + if (ast_strlen_zero(uid)) { + /* They didn't provide an ID so we'll provide one ourself */ + uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf)); + } + + datastore->uid = ast_strdup(uid_ptr); + if (!datastore->uid) { + ao2_ref(datastore, -1); + return NULL; + } + + return datastore; +} From d03e170ae7e9ac577a53a948548b1871d722a9f9 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 5 May 2016 11:14:00 -0300 Subject: [PATCH 0417/1578] res_pjsip_pubsub: Use common datastores container API. This migrates res_pjsip_pubsub over to using the newly introduce common datastores management API instead of using its own implementations for both subscriptions and publications. As well the extension state data now provides a generic datastores container instead of a subscription. This allows the dialog-info+xml body generator to work for both subscriptions and publications. ASTERISK-25999 #close Change-Id: I773f9e4f35092da0f653566736a8647e8cfebef1 --- .../asterisk/res_pjsip_body_generator_types.h | 5 + include/asterisk/res_pjsip_pubsub.h | 28 +++++ res/res_pjsip_dialog_info_body_generator.c | 16 +-- res/res_pjsip_exten_state.c | 16 +++ res/res_pjsip_pubsub.c | 103 ++++-------------- 5 files changed, 76 insertions(+), 92 deletions(-) diff --git a/include/asterisk/res_pjsip_body_generator_types.h b/include/asterisk/res_pjsip_body_generator_types.h index aab14723860..f61534b1075 100644 --- a/include/asterisk/res_pjsip_body_generator_types.h +++ b/include/asterisk/res_pjsip_body_generator_types.h @@ -21,6 +21,9 @@ #include "asterisk/pbx.h" +/*! \brief Forward declaration for ao2_container so full astobj2.h is not required */ +struct ao2_container; + /*! * \brief structure used for presence XML bodies * @@ -51,6 +54,8 @@ struct ast_sip_exten_state_data { char remote[PJSIP_MAX_URL_SIZE]; /*! Optional subscription */ struct ast_sip_subscription *sub; + /*! A datastores container to persist datastores */ + struct ao2_container *datastores; /*! Allocation pool */ pj_pool_t *pool; }; diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h index 4f9a7633afb..cb51db31ffe 100644 --- a/include/asterisk/res_pjsip_pubsub.h +++ b/include/asterisk/res_pjsip_pubsub.h @@ -165,6 +165,20 @@ struct ast_datastore *ast_sip_publication_get_datastore(struct ast_sip_publicati */ void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name); +/*! + * \brief Get the datastores container for a publication + * + * \param publication The publication to get the datastores container from + * + * \retval NULL datastores container not present + * \retval non-NULL datastores container + * + * \note The container is NOT returned with reference count bumped + * + * \since 14.0.0 + */ +struct ao2_container *ast_sip_publication_get_datastores(const struct ast_sip_publication *publication); + /*! * \brief Opaque structure representing an RFC 3265 SIP subscription */ @@ -517,6 +531,20 @@ struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscrip */ void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name); +/*! + * \brief Get the datastores container for a subscription + * + * \param subscription The subscription to get the datastores container from + * + * \retval NULL datastores container not present + * \retval non-NULL datastores container + * + * \note The container is NOT returned with reference count bumped + * + * \since 14.0.0 + */ +struct ao2_container *ast_sip_subscription_get_datastores(const struct ast_sip_subscription *subscription); + /*! * \brief Register a subscription handler * diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c index 86f3986544b..d21af2ae61c 100644 --- a/res/res_pjsip_dialog_info_body_generator.c +++ b/res/res_pjsip_dialog_info_body_generator.c @@ -61,20 +61,20 @@ static void *dialog_info_allocate_body(void *data) return ast_sip_presence_xml_create_node(state_data->pool, NULL, "dialog-info"); } -static struct ast_datastore *dialog_info_xml_state_find_or_create(struct ast_sip_subscription *sub) +static struct ast_datastore *dialog_info_xml_state_find_or_create(struct ao2_container *datastores) { - struct ast_datastore *datastore = ast_sip_subscription_get_datastore(sub, "dialog-info+xml"); + struct ast_datastore *datastore = ast_datastores_find(datastores, "dialog-info+xml"); if (datastore) { return datastore; } - datastore = ast_sip_subscription_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml"); + datastore = ast_datastores_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml"); if (!datastore) { return NULL; } datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state)); - if (!datastore->data || ast_sip_subscription_add_datastore(sub, datastore)) { + if (!datastore->data || ast_datastores_add(datastores, datastore)) { ao2_ref(datastore, -1); return NULL; } @@ -82,9 +82,9 @@ static struct ast_datastore *dialog_info_xml_state_find_or_create(struct ast_sip return datastore; } -static unsigned int dialog_info_xml_get_version(struct ast_sip_subscription *sub, unsigned int *version) +static unsigned int dialog_info_xml_get_version(struct ao2_container *datastores, unsigned int *version) { - struct ast_datastore *datastore = dialog_info_xml_state_find_or_create(sub); + struct ast_datastore *datastore = dialog_info_xml_state_find_or_create(datastores); struct dialog_info_xml_state *state; if (!datastore) { @@ -108,11 +108,11 @@ static int dialog_info_generate_body_content(void *body, void *data) unsigned int version; char version_str[32], sanitized[PJSIP_MAX_URL_SIZE]; - if (!local || !state_data->sub) { + if (!local || !state_data->datastores) { return -1; } - if (dialog_info_xml_get_version(state_data->sub, &version)) { + if (dialog_info_xml_get_version(state_data->datastores, &version)) { ast_log(LOG_WARNING, "dialog-info+xml version could not be retrieved from datastore\n"); return -1; } diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 76a88a29cf7..22fb69c29a5 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -96,6 +96,8 @@ struct exten_state_publisher { regex_t exten_regex; /*! Publish client to use for sending publish messages */ struct ast_sip_outbound_publish_client *client; + /*! Datastores container to hold persistent information */ + struct ao2_container *datastores; /*! Whether context filtering is active */ unsigned int context_filter; /*! Whether extension filtering is active */ @@ -271,6 +273,7 @@ static struct notify_task_data *alloc_notify_task_data(const char *exten, task_data->exten_state_data.user_agent = ast_strdup(exten_state_sub->user_agent); task_data->exten_state_data.device_state_info = ao2_bump(info->device_state_info); task_data->exten_state_data.sub = exten_state_sub->sip_sub; + task_data->exten_state_data.datastores = ast_sip_subscription_get_datastores(exten_state_sub->sip_sub); if ((info->exten_state == AST_EXTENSION_DEACTIVATED) || (info->exten_state == AST_EXTENSION_REMOVED)) { @@ -311,6 +314,7 @@ static int notify_task(void *obj) } task_data->exten_state_data.sub = task_data->exten_state_sub->sip_sub; + task_data->exten_state_data.datastores = ast_sip_subscription_get_datastores(task_data->exten_state_sub->sip_sub); ast_sip_subscription_notify(task_data->exten_state_sub->sip_sub, &data, task_data->terminate); @@ -498,6 +502,7 @@ static struct ast_sip_exten_state_data *exten_state_data_alloc(struct ast_sip_su ast_sip_subscription_get_remote_uri(sip_sub, exten_state_data->remote, sizeof(exten_state_data->remote)); exten_state_data->sub = sip_sub; + exten_state_data->datastores = ast_sip_subscription_get_datastores(sip_sub); exten_state_data->exten_state = ast_extension_state_extended( NULL, exten_state_sub->context, exten_state_sub->exten, @@ -658,6 +663,8 @@ static int exten_state_publisher_cb(void *data) } ast_copy_string(pub_data->exten_state_data.remote, uri, sizeof(pub_data->exten_state_data.remote)); + pub_data->exten_state_data.datastores = publisher->datastores; + res = ast_sip_pubsub_generate_body_content(publisher->body_type, publisher->body_subtype, &gen_data, &body_text); pj_pool_reset(pool); @@ -801,6 +808,7 @@ static void exten_state_publisher_destroy(void *obj) } ao2_cleanup(publisher->client); + ao2_cleanup(publisher->datastores); } static int build_regex(regex_t *regex, const char *text) @@ -895,6 +903,14 @@ static int publisher_start(struct ast_sip_outbound_publish *configuration, struc publisher->exten_filter = 1; } + publisher->datastores = ast_datastores_alloc(); + if (!publisher->datastores) { + ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not create datastores container\n", + name); + ao2_ref(publisher, -1); + return -1; + } + publisher->client = ao2_bump(client); ao2_lock(publishers); diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 755a154a5a4..10ffb19fcc1 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1001,28 +1001,6 @@ static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct a } } -static int datastore_hash(const void *obj, int flags) -{ - const struct ast_datastore *datastore = obj; - const char *uid = flags & OBJ_KEY ? obj : datastore->uid; - - ast_assert(uid != NULL); - - return ast_str_hash(uid); -} - -static int datastore_cmp(void *obj, void *arg, int flags) -{ - const struct ast_datastore *datastore1 = obj; - const struct ast_datastore *datastore2 = arg; - const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid; - - ast_assert(datastore1->uid != NULL); - ast_assert(uid2 != NULL); - - return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP; -} - static void add_subscription(struct sip_subscription_tree *obj) { SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); @@ -1086,7 +1064,7 @@ static struct ast_sip_subscription *allocate_subscription(const struct ast_sip_s } strcpy(sub->resource, resource); /* Safe */ - sub->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp); + sub->datastores = ast_datastores_alloc(); if (!sub->datastores) { destroy_subscription(sub); return NULL; @@ -2323,92 +2301,49 @@ static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1; } -static void subscription_datastore_destroy(void *obj) -{ - struct ast_datastore *datastore = obj; - - /* Using the destroy function (if present) destroy the data */ - if (datastore->info->destroy != NULL && datastore->data != NULL) { - datastore->info->destroy(datastore->data); - datastore->data = NULL; - } - - ast_free((void *) datastore->uid); - datastore->uid = NULL; -} - struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid) { - RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup); - char uuid_buf[AST_UUID_STR_LEN]; - const char *uid_ptr = uid; - - if (!info) { - return NULL; - } - - datastore = ao2_alloc(sizeof(*datastore), subscription_datastore_destroy); - if (!datastore) { - return NULL; - } - - datastore->info = info; - if (ast_strlen_zero(uid)) { - /* They didn't provide an ID so we'll provide one ourself */ - uid_ptr = ast_uuid_generate_str(uuid_buf, sizeof(uuid_buf)); - } - - datastore->uid = ast_strdup(uid_ptr); - if (!datastore->uid) { - return NULL; - } - - ao2_ref(datastore, +1); - return datastore; + return ast_datastores_alloc_datastore(info, uid); } int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore) { - ast_assert(datastore != NULL); - ast_assert(datastore->info != NULL); - ast_assert(!ast_strlen_zero(datastore->uid)); - - if (!ao2_link(subscription->datastores, datastore)) { - return -1; - } - return 0; + return ast_datastores_add(subscription->datastores, datastore); } struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name) { - return ao2_find(subscription->datastores, name, OBJ_KEY); + return ast_datastores_find(subscription->datastores, name); } void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name) { - ao2_find(subscription->datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); + ast_datastores_remove(subscription->datastores, name); } -int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore) +struct ao2_container *ast_sip_subscription_get_datastores(const struct ast_sip_subscription *subscription) { - ast_assert(datastore != NULL); - ast_assert(datastore->info != NULL); - ast_assert(!ast_strlen_zero(datastore->uid)); + return subscription->datastores; +} - if (!ao2_link(publication->datastores, datastore)) { - return -1; - } - return 0; +int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore) +{ + return ast_datastores_add(publication->datastores, datastore); } struct ast_datastore *ast_sip_publication_get_datastore(struct ast_sip_publication *publication, const char *name) { - return ao2_find(publication->datastores, name, OBJ_KEY); + return ast_datastores_find(publication->datastores, name); } void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name) { - ao2_callback(publication->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name); + ast_datastores_remove(publication->datastores, name); +} + +struct ao2_container *ast_sip_publication_get_datastores(const struct ast_sip_publication *publication) +{ + return publication->datastores; } AST_RWLIST_HEAD_STATIC(publish_handlers, ast_sip_publish_handler); @@ -2830,7 +2765,7 @@ static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoin return NULL; } - if (!(publication->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp))) { + if (!(publication->datastores = ast_datastores_alloc())) { ao2_ref(publication, -1); return NULL; } From dfefbf873199f17569ba764b81e10a977cde87dc Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 7 May 2016 13:39:25 -0600 Subject: [PATCH 0418/1578] config_transport: Tell pjproject to allow all SSL/TLS protocols The default tls settings for pjproject only allow TLS 1, TLS 1.1 and TLS 1.2. SSL is not allowed. So, even if you specify "sslv3" for a transport method, it's silently ignored and one of the TLS protocols is used. This was a new behavior of pjsip_tls_setting_default() in 2.4 (when tls.proto was added) that we never caught. Now we need to set tls.proto = 0 after we call pjsip_tls_setting_default(). This tells pjproject to set the socket protocol to match the method. ASTERISK-26004 #close Change-Id: Icfb55c1ebe921298dedb4b1a1d3bdc3ca41dd078 --- res/res_pjsip/config_transport.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index d2c087487a5..3a5afb6bcc8 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -378,6 +378,10 @@ static struct ast_sip_transport_state *find_or_create_temporary_state(struct ast new_state->type = transport->type; pjsip_tls_setting_default(&new_state->tls); +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + /* proto must be forced to 0 to enable all protocols otherwise only TLS will work */ + new_state->tls.proto = 0; +#endif new_state->tls.ciphers = new_state->ciphers; ao2_ref(new_state, +1); From 1e876d691588a9196ad987b0f81192c12d3a0c81 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 5 May 2016 11:37:37 -0500 Subject: [PATCH 0419/1578] res_pjsip_authenticator_digest: Don't use source port in nonce verification From the issue reporter: "res_pjsip_outbound_authenticator_digest builds a nonce that is a hash of the timestamp, the source address, the source port, a server UUID that is calculated at startup, and the authentication realm. Rather than caching nonces that we create, we instead attempt to re-calculate the nonce when receiving an incoming request with authentication. We then compare the re-calculated nonce to the incoming nonce, and if they don't match, then authentication has failed early. The problem is that it is possible, especially when using TCP, to receive two requests from the same endpoint but have differing source ports for those requests. Asterisk itself commonly will use different source ports for outbound TCP requests." This patch removes the source port dependency when building the nonce. ASTERISK-25978 #close Change-Id: I871b5f4adce102df1c4988066283095ec509dffe --- res/res_pjsip_authenticator_digest.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c index a512b45b1bf..4bc35c5ff6b 100644 --- a/res/res_pjsip_authenticator_digest.c +++ b/res/res_pjsip_authenticator_digest.c @@ -206,9 +206,12 @@ static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsi RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup); char hash[33]; + /* + * Note you may be tempted to think why not include the port. The reason + * is that when using TCP the port can potentially differ from before. + */ ast_str_append(&str, 0, "%s", timestamp); ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name); - ast_str_append(&str, 0, ":%d", rdata->pkt_info.src_port); ast_str_append(&str, 0, ":%s", eid); ast_str_append(&str, 0, ":%s", realm); ast_md5_hash(hash, ast_str_buffer(str)); From f943a1fd84c9b9e55d848954cf78dfff375acf77 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 10 May 2016 10:56:40 +0300 Subject: [PATCH 0420/1578] basic-cfg: asterisk.conf: remove [directories] A minimal configuration does not need to explicitly spell out the directories. The built-in defaults will do just fine. In many cases they are wrong. Change-Id: Id1a671e5c5e9923765a4156b57f9f7e263fdd26c Signed-off-by: Tzafrir Cohen --- configs/basic-pbx/asterisk.conf | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/configs/basic-pbx/asterisk.conf b/configs/basic-pbx/asterisk.conf index 576cc976b6d..06c632e79d0 100644 --- a/configs/basic-pbx/asterisk.conf +++ b/configs/basic-pbx/asterisk.conf @@ -1,16 +1,3 @@ -[directories] -astetcdir => /etc/asterisk -astmoddir => /usr/lib/asterisk/modules -astvarlibdir => /var/lib/asterisk -astdbdir => /var/lib/asterisk -astkeydir => /var/lib/asterisk -astdatadir => /var/lib/asterisk -astagidir => /var/lib/asterisk/agi-bin -astspooldir => /var/spool/asterisk -astrundir => /var/run/asterisk -astlogdir => /var/log/asterisk -astsbindir => /usr/sbin - [options] ; If we want to start Asterisk with a default verbosity for the verbose ; or debug logger channel types, then we use these settings. From d0ba3e8196f57e5b308daf6b890c612a94435b3d Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 10 May 2016 11:06:10 +0300 Subject: [PATCH 0421/1578] basic-cfg: asterisk.conf: defaults of options Note the default of remmed-out options. To clarify that those values are not the defaults. Change-Id: I849c29b7a710f0abc37355fcb5bfee335ae30738 Signed-off-by: Tzafrir Cohen --- configs/basic-pbx/asterisk.conf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/configs/basic-pbx/asterisk.conf b/configs/basic-pbx/asterisk.conf index 06c632e79d0..67c5e40da01 100644 --- a/configs/basic-pbx/asterisk.conf +++ b/configs/basic-pbx/asterisk.conf @@ -1,13 +1,14 @@ [options] ; If we want to start Asterisk with a default verbosity for the verbose -; or debug logger channel types, then we use these settings. +; or debug logger channel types, then we use these settings (by default +; they are disabled). ;verbose = 5 ;debug = 5 ; User and group to run asterisk as. NOTE: This will require changes to ; directory and device permissions. -;runuser = asterisk ; The user to run as. -;rungroup = asterisk ; The group to run as. +;runuser = asterisk ; The user to run as. The default is root. +;rungroup = asterisk ; The group to run as. The default is root defaultlanguage = en documentation_language = en_US From 1b0a9bb2c4237e8654ee1e8cda41f71ff25dfbb0 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 10 May 2016 11:08:33 +0300 Subject: [PATCH 0422/1578] basic-cfg: asterisk.conf: debug level 5 spams Don't suggest users to use debug level 5, which spews (usually non-useful) debug information. Reduce the suggestion to (an arbitrarily-selected) level 2. Change-Id: Ib53195f78945970956ff59ef13fa89b90e0fcd60 Signed-off-by: Tzafrir Cohen --- configs/basic-pbx/asterisk.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/basic-pbx/asterisk.conf b/configs/basic-pbx/asterisk.conf index 67c5e40da01..d0812656f33 100644 --- a/configs/basic-pbx/asterisk.conf +++ b/configs/basic-pbx/asterisk.conf @@ -3,7 +3,7 @@ ; or debug logger channel types, then we use these settings (by default ; they are disabled). ;verbose = 5 -;debug = 5 +;debug = 2 ; User and group to run asterisk as. NOTE: This will require changes to ; directory and device permissions. From ec85ea3c214ebdada3e3f72707534a9178b9c855 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 10 May 2016 11:10:55 +0300 Subject: [PATCH 0423/1578] basic-cfg: asterisk.conf: don't set languages * No need to set language in a miniml configuration. 'en' will do just fine. * It would be useful to have an example of setting it to a different language. * Setting the documentation language explicitly is likewise not required. Setting it to a different value is not common. At least until there is a set of translated documentation. Change-Id: I94d91ea34e129925f25af81ef8dc0906fb568cb7 Signed-off-by: Tzafrir Cohen --- configs/basic-pbx/asterisk.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configs/basic-pbx/asterisk.conf b/configs/basic-pbx/asterisk.conf index d0812656f33..ff66ceea7ab 100644 --- a/configs/basic-pbx/asterisk.conf +++ b/configs/basic-pbx/asterisk.conf @@ -10,5 +10,4 @@ ;runuser = asterisk ; The user to run as. The default is root. ;rungroup = asterisk ; The group to run as. The default is root -defaultlanguage = en -documentation_language = en_US +;defaultlanguage = es From b5c471b33970a6864872b992c8a26136644ee5ee Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 10 May 2016 16:17:29 +0300 Subject: [PATCH 0424/1578] followme: delete the right recorded name file FollowMe with the option a records the name of the caller and plays it to the callee. However it has failed to clean up that recorded file as it tried to delete the file name without the '.sln' extension. ASTERISK-26008 #close Change-Id: I79d7b1be7d5cde57bf076d9389e2a8a4422776ec Signed-off-by: Tzafrir Cohen --- apps/app_followme.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/app_followme.c b/apps/app_followme.c index d2000fd1353..106902043a5 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -66,6 +66,8 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_channels.h" #include "asterisk/max_forwards.h" +#define REC_FORMAT "sln" + /*** DOCUMENTATION @@ -1421,7 +1423,7 @@ static int app_exec(struct ast_channel *chan, const char *data) snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s", ast_config_AST_SPOOL_DIR, ast_channel_uniqueid(chan)); - if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, "sln", &duration, + if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, REC_FORMAT, &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) { goto outrun; } @@ -1522,7 +1524,18 @@ static int app_exec(struct ast_channel *chan, const char *data) ast_free(nm); } if (!ast_strlen_zero(targs->namerecloc)) { - unlink(targs->namerecloc); + int ret; + char fn[PATH_MAX]; + + snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc, + REC_FORMAT); + ret = unlink(fn); + if (ret != 0) { + ast_log(LOG_NOTICE, "Failed to delete recorded name file %s: %d (%s)\n", + fn, errno, strerror(errno)); + } else { + ast_debug(2, "deleted recorded prompt %s.\n", fn); + } } ast_free((char *) targs->predial_callee); ast_party_connected_line_free(&targs->connected_in); From 5236ffed97bf5d4a6b54cfefd672f9dc31f0a563 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 11 May 2016 14:07:17 -0500 Subject: [PATCH 0425/1578] configure: Fix errors with AST_UNDEFINED_SANITIZER/AST_LEAK_SANITIZER When running on a system that does not support or use AST_UNDEFINED_SANITIZER or AST_LEAK_SANITIZER, the configure script would incorrectly set those constants to a blank value, e.g., 'AST_UNDEFINED_SANITIZER='. This would cause menuselect to error out, complaining that a blank value is not a valid option. This patch corrects the issue by setting the value to 0 if the options that those constants enable/disable is not found. Change-Id: Ib39814aaf940f308d500c1e026edb3d70de47fba --- configure | 14 +++++++------- configure.ac | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 751fbea5dad..9e3772748f8 100755 --- a/configure +++ b/configure @@ -13772,7 +13772,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13818,7 +13818,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13842,7 +13842,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13887,7 +13887,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13911,7 +13911,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -17774,7 +17774,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_LEAK_SANITIZER=1 else - AST_LEAK_SANITIZER= + AST_LEAK_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } @@ -17806,7 +17806,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_UNDEFINED_SANITIZER=1 else - AST_UNDEFINED_SANITIZER= + AST_UNDEFINED_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } diff --git a/configure.ac b/configure.ac index 9c11054e93c..5852d3fa2a6 100644 --- a/configure.ac +++ b/configure.ac @@ -1117,7 +1117,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_LEAK_SANITIZER=1], - [AST_LEAK_SANITIZER=] + [AST_LEAK_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" @@ -1133,7 +1133,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_UNDEFINED_SANITIZER=1], - [AST_UNDEFINED_SANITIZER=] + [AST_UNDEFINED_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" From 9f996624b09f2610ed1b80e8cbbc3f1885bb1c6f Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 5 May 2016 17:41:21 -0400 Subject: [PATCH 0426/1578] logger: Add PID to syslog messages. During refactoring of this support the addition of the PID to messages was removed. This change adds it back in. ASTERISK-25538 #close Change-Id: Ie2d43b0652e59b7ac319a7dba94501540d70ba36 --- main/logger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main/logger.c b/main/logger.c index 42a1c700049..c9cf50e09fb 100644 --- a/main/logger.c +++ b/main/logger.c @@ -531,6 +531,7 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo } chan->type = LOGTYPE_SYSLOG; + openlog("asterisk", LOG_PID, chan->facility); } else { if (!(chan->fileptr = fopen(chan->filename, "a"))) { /* Can't do real logging here since we're called with a lock From d14d1ba826f8ac7f340fd67df41ed2c5dcd17539 Mon Sep 17 00:00:00 2001 From: Sebastian Damm Date: Tue, 10 May 2016 17:19:48 +0200 Subject: [PATCH 0427/1578] res_pjsip_outbound_registration: generate correct Contact URI for TLS There are two types of SIP URIs indicating a secure transport: * sips:user@example.org * sip:user@example.org;transport=tls When using a sips URI, Asterisk checks incoming INVITEs and answers from the other side for sips URIs, and rejects the packet if there are only sip URIs. So Asterisk should only generate a sips Contact URI if the other side supports it. This patch makes Asterisk generate either a sip or sips Contact URI depending on the format of the server URI. If you want a sip URI, use: server_uri=sip:example.org\;transport=tls If you want a sips URI, use: server_uri=sips:example.org ASTERISK-25990 #close Reported-by: Sebastian Damm Change-Id: I5ae57d6531ce940b5fc64d5cd2673e60db0f9ba2 --- res/res_pjsip_outbound_registration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index f85996ed5ed..815432d10e0 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1096,7 +1096,7 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE, "<%s:%s@%s%.*s%s:%d%s%s%s%s>", - (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip", + ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip", user, (type & PJSIP_TRANSPORT_IPV6) ? "[" : "", (int)local_addr.slen, From 4f8cfa0220ce435976e46b478c2f8216065aefaa Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 12 May 2016 08:13:55 -0600 Subject: [PATCH 0428/1578] pjsip_distributor: Add missing newline to NOTICE There was a newline missing from the end of the "no matching endpoint" notice. Change-Id: Idc11fe5bc0354072291663dbffe648c471e39181 --- res/res_pjsip/pjsip_distributor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index cbe95572807..b7da81433d0 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -391,7 +391,7 @@ static void log_unidentified_request(pjsip_rx_data *rdata, unsigned int count, u " after %u tries in %.3f ms\n", from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, count, period / 1000.0); } else { - ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found", + ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found\n", from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf); } } From fd3f70598d193d10bed997eaaea128a7bdbb2143 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 12 May 2016 14:36:25 -0500 Subject: [PATCH 0429/1578] Use doubles instead of floats for conversions when comparing strings. In 13.9.0, there was an issue where PJSIP contacts added to an AOR would be deleted at seemingly random times. One reason this was happening was because of an operation to retrieve the contacts whose expiration time was less than or equal to the current time. When retrieving existing contacts, the contact's expiration time and the current time were converted from a string to a float, and those two floats were compared. On some systems, including mine, this conversion was horribly off. For instance, I could regularly see the string "1463079214" get converted into 1463079168.000000. When switching from using a float to using a double, the conversion was as expected. Why was the conversion to float off? My best guess is that the conversion to float was attempting to store the entire value in the 23 bit significand of the IEEE-754 floating point number. In particular, if you take only the 23 most significant bits of 1463079214, you get the messed up 1463079168 that we were seeing in the conversion. It likely was possible to get a more precise value by composing the number using an exponent, but the conversion did not work that way. With a double, you have a 52 bit significand, allowing the entire value to fit there, and thereby allowing an accurate conversion. ASTERISK-26007 #close Reported by Greg Siemon Change-Id: I83ca7944aae8b7cd994b254c78ec02411d321070 --- main/strings.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/strings.c b/main/strings.c index f828727ad84..b9c88dea572 100644 --- a/main/strings.c +++ b/main/strings.c @@ -234,8 +234,8 @@ int ast_strings_match(const char *left, const char *op, const char *right) { char *internal_op = (char *)op; char *internal_right = (char *)right; - float left_num; - float right_num; + double left_num; + double right_num; int scan_numeric = 0; if (!(left && right)) { @@ -297,7 +297,7 @@ int ast_strings_match(const char *left, const char *op, const char *right) } equals: - scan_numeric = (sscanf(left, "%f", &left_num) && sscanf(internal_right, "%f", &right_num)); + scan_numeric = (sscanf(left, "%lf", &left_num) && sscanf(internal_right, "%lf", &right_num)); if (internal_op[0] == '=') { if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) { From 69a85a519f0f5acc11d167a500b99806530ff822 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 13 May 2016 12:46:52 -0400 Subject: [PATCH 0430/1578] res_pjsip: Endpoint IP Access Controls With the old SIP module we can use IP access controls per peer. PJSIP module missing this feature. This patch added next configuration Endpoint options: "acl" - list of IP ACL section names in acl.conf "deny" - List of IP addresses to deny access from "permit" - List of IP addresses to permit access from "contact_acl" - List of Contact ACL section names in acl.conf "contact_deny" - List of Contact header addresses to deny "contact_permit" - List of Contact header addresses to permit This patch also better logging failed request: add custom message instead of "No matching endpoint found" add SIP method to logging ASTERISK-25900 Change-Id: I456dea3909d929d413864fb347d28578415ebf02 --- CHANGES | 9 ++ ...b_add_pjsip_endpoint_ip_access_control_.py | 32 ++++++ include/asterisk/res_pjsip.h | 4 + res/res_pjsip.c | 50 +++++++++ res/res_pjsip/pjsip_configuration.c | 71 +++++++++++- res/res_pjsip/pjsip_distributor.c | 101 ++++++++++++++++-- 6 files changed, 257 insertions(+), 10 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py diff --git a/CHANGES b/CHANGES index ec44e30fc4b..b2a0b28748c 100644 --- a/CHANGES +++ b/CHANGES @@ -282,6 +282,15 @@ res_fax res_pjsip ------------------ + * Endpoint IP Access Controls + Added new configuration Endpoint options: + "acl" - list of IP ACL section names in acl.conf + "deny" - List of IP addresses to deny access from + "permit" - List of IP addresses to permit access from + "contact_acl" - List of Contact ACL section names in acl.conf + "contact_deny" - List of Contact header addresses to deny + "contact_permit" - List of Contact header addresses to permit + * Added new status Updated to AMI event ContactStatus on update registration * Added "reg_server" to contacts. diff --git a/contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py b/contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py new file mode 100644 index 00000000000..e119b2aa439 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/837aa67461fb_add_pjsip_endpoint_ip_access_control_.py @@ -0,0 +1,32 @@ +"""Add PJSIP Endpoint IP Access Control options + +Revision ID: d7e3c73eb2bf +Revises: 6be31516058d +Create Date: 2016-05-13 12:45:45.071871 + +""" + +# revision identifiers, used by Alembic. +revision = 'd7e3c73eb2bf' +down_revision = '6be31516058d' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('deny', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('permit', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('acl', sa.String(40))) + op.add_column('ps_endpoints', sa.Column('contact_deny', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('contact_permit', sa.String(95))) + op.add_column('ps_endpoints', sa.Column('contact_acl', sa.String(40))) + + +def downgrade(): + op.drop_column('ps_endpoints', 'contact_acl') + op.drop_column('ps_endpoints', 'contact_permit') + op.drop_column('ps_endpoints', 'contact_deny') + op.drop_column('ps_endpoints', 'acl') + op.drop_column('ps_endpoints', 'permit') + op.drop_column('ps_endpoints', 'deny') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 05f8100cf54..cf8c719d5b3 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -738,6 +738,10 @@ struct ast_sip_endpoint { unsigned int usereqphone; /*! Whether to pass through hold and unhold using re-invites with recvonly and sendrecv */ unsigned int moh_passthrough; + /* Access control list */ + struct ast_acl_list *acl; + /* Restrict what IPs are allowed in the Contact header (for registration) */ + struct ast_acl_list *contact_acl; }; /*! diff --git a/res/res_pjsip.c b/res/res_pjsip.c index a3b2d081d27..c06b67ecf7b 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -849,6 +849,56 @@ channel is hung up. By default this option is set to 0, which means do not check. + + List of IP ACL section names in acl.conf + + This matches sections configured in acl.conf. The value is + defined as a list of comma-delimited section names. + + + + List of IP addresses to deny access from + + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + + + + List of IP addresses to permit access from + + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + + + + List of Contact ACL section names in acl.conf + + This matches sections configured in acl.conf. The value is + defined as a list of comma-delimited section names. + + + + List of Contact header addresses to deny + + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + + + + List of Contact header addresses to permit + + The value is a comma-delimited list of IP addresses. IP addresses may + have a subnet mask appended. The subnet mask may be written in either + CIDR or dotted-decimal notation. Separate the IP address and subnet + mask with a slash ('/') + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index c370ab75f39..8b6fe61d8d6 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -262,6 +262,65 @@ static const struct ast_sorcery_observer endpoint_observers = { .deleted = endpoint_deleted_observer, }; +static int endpoint_acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_endpoint *endpoint = obj; + int error = 0; + int ignore; + + if (ast_strlen_zero(var->value)) return 0; + + if (!strncmp(var->name, "contact_", 8)) { + ast_append_acl(var->name + 8, var->value, &endpoint->contact_acl, &error, &ignore); + } else { + ast_append_acl(var->name, var->value, &endpoint->acl, &error, &ignore); + } + + return error; +} + +static int acl_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + struct ast_acl_list *acl_list; + struct ast_acl *first_acl; + + if (endpoint && !ast_acl_list_is_empty(acl_list=endpoint->acl)) { + AST_LIST_LOCK(acl_list); + first_acl = AST_LIST_FIRST(acl_list); + if (ast_strlen_zero(first_acl->name)) { + *buf = "deny/permit"; + } else { + *buf = first_acl->name; + } + AST_LIST_UNLOCK(acl_list); + } + + *buf = ast_strdup(*buf); + return 0; +} + +static int contact_acl_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + struct ast_acl_list *acl_list; + struct ast_acl *first_acl; + + if (endpoint && !ast_acl_list_is_empty(acl_list=endpoint->contact_acl)) { + AST_LIST_LOCK(acl_list); + first_acl = AST_LIST_FIRST(acl_list); + if (ast_strlen_zero(first_acl->name)) { + *buf = "deny/permit"; + } else { + *buf = first_acl->name; + } + AST_LIST_UNLOCK(acl_list); + } + + *buf = ast_strdup(*buf); + return 0; +} + static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -272,8 +331,8 @@ static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, endpoint->dtmf = AST_SIP_DTMF_INBAND; } else if (!strcasecmp(var->value, "info")) { endpoint->dtmf = AST_SIP_DTMF_INFO; - } else if (!strcasecmp(var->value, "auto")) { - endpoint->dtmf = AST_SIP_DTMF_AUTO; + } else if (!strcasecmp(var->value, "auto")) { + endpoint->dtmf = AST_SIP_DTMF_AUTO; } else if (!strcasecmp(var->value, "none")) { endpoint->dtmf = AST_SIP_DTMF_NONE; } else { @@ -295,7 +354,7 @@ static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf) case AST_SIP_DTMF_INFO : *buf = "info"; break; case AST_SIP_DTMF_AUTO : - *buf = "auto"; break; + *buf = "auto"; break; default: *buf = "none"; } @@ -1760,6 +1819,12 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, message_context)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, accountcode)); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "deny", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "permit", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "acl", "", endpoint_acl_handler, acl_to_str, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_deny", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index b7da81433d0..d902ed45614 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -21,6 +21,7 @@ #include #include "asterisk/res_pjsip.h" +#include "asterisk/acl.h" #include "include/res_pjsip_private.h" #include "asterisk/taskprocessor.h" #include "asterisk/threadpool.h" @@ -380,19 +381,21 @@ struct ast_sip_endpoint *ast_sip_get_artificial_endpoint(void) return artificial_endpoint; } -static void log_unidentified_request(pjsip_rx_data *rdata, unsigned int count, unsigned int period) +static void log_failed_request(pjsip_rx_data *rdata, char *msg, unsigned int count, unsigned int period) { char from_buf[PJSIP_MAX_URL_SIZE]; char callid_buf[PJSIP_MAX_URL_SIZE]; + char method_buf[PJSIP_MAX_URL_SIZE]; pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.from->uri, from_buf, PJSIP_MAX_URL_SIZE); ast_copy_pj_str(callid_buf, &rdata->msg_info.cid->id, PJSIP_MAX_URL_SIZE); + ast_copy_pj_str(method_buf, &rdata->msg_info.msg->line.req.method.name, PJSIP_MAX_URL_SIZE); if (count) { - ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found" + ast_log(LOG_NOTICE, "Request '%s' from '%s' failed for '%s:%d' (callid: %s) - %s" " after %u tries in %.3f ms\n", - from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, count, period / 1000.0); + method_buf, from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, msg, count, period / 1000.0); } else { - ast_log(LOG_NOTICE, "Request from '%s' failed for '%s:%d' (callid: %s) - No matching endpoint found\n", - from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf); + ast_log(LOG_NOTICE, "Request '%s' from '%s' failed for '%s:%d' (callid: %s) - %s\n", + method_buf, from_buf, rdata->pkt_info.src_name, rdata->pkt_info.src_port, callid_buf, msg); } } @@ -405,7 +408,7 @@ static void check_endpoint(pjsip_rx_data *rdata, struct unidentified_request *un unid->count++; if (ms < (unidentified_period * 1000) && unid->count >= unidentified_count) { - log_unidentified_request(rdata, unid->count, ms); + log_failed_request(rdata, "No matching endpoint found", unid->count, ms); ast_sip_report_invalid_endpoint(name, rdata); } ao2_unlock(unid); @@ -479,7 +482,7 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) ao2_ref(unid, -1); ao2_unlock(unidentified_requests); } else { - log_unidentified_request(rdata, 0, 0); + log_failed_request(rdata, "No matching endpoint found", 0, 0); ast_sip_report_invalid_endpoint(name, rdata); } } @@ -487,6 +490,79 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) return PJ_FALSE; } +static int apply_endpoint_acl(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint) +{ + struct ast_sockaddr addr; + + if (ast_acl_list_is_empty(endpoint->acl)) { + return 0; + } + + memset(&addr, 0, sizeof(addr)); + ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID); + ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port); + + if (ast_apply_acl(endpoint->acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) { + log_failed_request(rdata, "Not match Endpoint ACL", 0, 0); + ast_sip_report_failed_acl(endpoint, rdata, "not_match_endpoint_acl"); + return 1; + } + return 0; +} + +static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs) +{ + pjsip_sip_uri *sip_uri; + char host[256]; + + if (!contact || contact->star) { + *addrs = NULL; + return 0; + } + if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) { + *addrs = NULL; + return 0; + } + sip_uri = pjsip_uri_get_uri(contact->uri); + ast_copy_pj_str(host, &sip_uri->host, sizeof(host)); + return ast_sockaddr_resolve(addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC); +} + +static int apply_endpoint_contact_acl(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint) +{ + int num_contact_addrs; + int forbidden = 0; + struct ast_sockaddr *contact_addrs; + int i; + pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; + + if (ast_acl_list_is_empty(endpoint->contact_acl)) { + return 0; + } + + while ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) { + num_contact_addrs = extract_contact_addr(contact, &contact_addrs); + if (num_contact_addrs <= 0) { + continue; + } + for (i = 0; i < num_contact_addrs; ++i) { + if (ast_apply_acl(endpoint->contact_acl, &contact_addrs[i], "SIP Contact ACL: ") != AST_SENSE_ALLOW) { + log_failed_request(rdata, "Not match Endpoint Contact ACL", 0, 0); + ast_sip_report_failed_acl(endpoint, rdata, "not_match_endpoint_contact_acl"); + forbidden = 1; + break; + } + } + ast_free(contact_addrs); + if (forbidden) { + /* No use checking other contacts if we already have failed ACL check */ + break; + } + } + + return forbidden; +} + static pj_bool_t authenticate(pjsip_rx_data *rdata) { RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup); @@ -494,6 +570,15 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) ast_assert(endpoint != NULL); + if (endpoint!=artificial_endpoint) { + if (apply_endpoint_acl(rdata, endpoint) || apply_endpoint_contact_acl(rdata, endpoint)) { + if (!is_ack) { + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); + } + return PJ_TRUE; + } + } + if (!is_ack && ast_sip_requires_authentication(endpoint, rdata)) { pjsip_tx_data *tdata; struct unidentified_request *unid; @@ -515,10 +600,12 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) pjsip_tx_data_dec_ref(tdata); return PJ_FALSE; case AST_SIP_AUTHENTICATION_FAILED: + log_failed_request(rdata, "Failed to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); return PJ_TRUE; case AST_SIP_AUTHENTICATION_ERROR: + log_failed_request(rdata, "Error to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); pjsip_tx_data_dec_ref(tdata); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); From e06a23681ca8c6933d705ad9e52c24395ed0a506 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 11 May 2016 20:17:15 -0500 Subject: [PATCH 0431/1578] res_hep: Provide an option to pick the UUID type At one point in time, it seemed like a good idea to use the Asterisk channel name as the HEP correlation UUID. In particular, it felt like this would be a useful identifier to tie PJSIP messages and RTCP messages together, along with whatever other data we may eventually send to Homer. This also had the benefit of keeping the correlation UUID channel technology agnostic. In practice, it isn't as useful as hoped, for two reasons: 1) The first INVITE request received doesn't have a channel. As a result, there is always an 'odd message out', leading it to be potentially uncorrelated in Homer. 2) Other systems sending capture packets (Kamailio) use the SIP Call-ID. This causes RTCP information to be uncorrelated to the SIP message traffic seen by those capture nodes. In order to support both (in case someone is trying to use res_hep_rtcp with a non-PJSIP channel), this patch adds a new option, uuid_type, with two valid values - 'call-id' and 'channel'. The uuid_type option is used by a module to determine the preferred UUID type. When available, that source of a correlation UUID is used; when not, the more readily available source is used. For res_hep_pjsip: - uuid_type = call-id: the module uses the SIP Call-ID header value - uuid_type = channel: the module uses the channel name if available, falling back to SIP Call-ID if not For res_hep_rtcp: - uuid_type = call-id: the module uses the SIP Call-ID header if the channel type is PJSIP and we have a channel, falling back to the Stasis event provided channel name if not - uuid_type = channel: the module uses the channel name ASTERISK-25352 #close Change-Id: Ide67e59a52d9c806e3cc0a797ea1a4b88a00122c --- CHANGES | 10 +++++++++ configs/samples/hep.conf.sample | 4 ++++ include/asterisk/res_hep.h | 14 +++++++++++++ res/res_hep.c | 37 +++++++++++++++++++++++++++++++++ res/res_hep.exports.in | 1 + res/res_hep_pjsip.c | 9 ++++++-- res/res_hep_rtcp.c | 33 ++++++++++++++++++++++++++++- 7 files changed, 105 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index ec44e30fc4b..3ec0bfb2077 100644 --- a/CHANGES +++ b/CHANGES @@ -289,6 +289,16 @@ res_pjsip into the "reg_server" field in the ps_contacts table to facilitate multi-server setups. +res_hep +------------------ + * Added a new option, 'uuid_type', that sets the preferred source of the Homer + correlation UUID. The valid options are: + - call-id: Use the PJSIP SIP Call-ID header value + - channel: Use the Asterisk channel name + The default value is 'call-id'. In the event that a HEP module cannot find a + valid value using the specified 'uuid_type', the module may fallback to a + more readily available source for the correlation UUID. + app_confbridge ------------------ * Added a bridge profile option called regcontext that allows you to diff --git a/configs/samples/hep.conf.sample b/configs/samples/hep.conf.sample index 40b17aa0e34..6e409d151c0 100644 --- a/configs/samples/hep.conf.sample +++ b/configs/samples/hep.conf.sample @@ -13,4 +13,8 @@ capture_password = foo ; If specified, the authorization passsword capture_id = 1234 ; A unique integer identifier for this ; server. This ID will be embedded sent ; with each packet from this server. +uuid_type = call-id ; Specify the preferred source for the Homer + ; correlation UUID. Valid options are: + ; - 'call-id' for the PJSIP SIP Call-ID + ; - 'channel' for the Asterisk channel name diff --git a/include/asterisk/res_hep.h b/include/asterisk/res_hep.h index 8839fd60ab9..bd0129eeada 100644 --- a/include/asterisk/res_hep.h +++ b/include/asterisk/res_hep.h @@ -49,6 +49,11 @@ enum hepv3_capture_type { HEPV3_CAPTURE_TYPE_IAX = 0x10, }; +enum hep_uuid_type { + HEP_UUID_TYPE_CALL_ID = 0, + HEP_UUID_TYPE_CHANNEL, +}; + /*! \brief HEPv3 Capture Info */ struct hepv3_capture_info { /*! The source address of the packet */ @@ -104,6 +109,15 @@ struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t */ int hepv3_send_packet(struct hepv3_capture_info *capture_info); +/*! + * \brief Get the preferred UUID type + * + * \since 13.10.0 + * + * \retval The type of UUID the packet should use + */ +enum hep_uuid_type hepv3_get_uuid_type(void); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/res/res_hep.c b/res/res_hep.c index e831fff0271..45201359dbb 100644 --- a/res/res_hep.c +++ b/res/res_hep.c @@ -60,6 +60,15 @@ + + The preferred type of UUID to pass to Homer. + + + Use the PJSIP Call-Id + Use the Asterisk channel name + + + The address and port of the Homer server to send packets to. @@ -231,6 +240,7 @@ struct hep_generic { struct hepv3_global_config { unsigned int enabled; /*!< Whether or not sending is enabled */ unsigned int capture_id; /*!< Capture ID for this agent */ + enum hep_uuid_type uuid_type; /*!< The preferred type of the UUID */ AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(capture_address); /*!< Address to send to */ AST_STRING_FIELD(capture_password); /*!< Password for Homer server */ @@ -329,6 +339,25 @@ static void *module_config_alloc(void) return config; } +/*! \brief Handler for the uuid_type attribute */ +static int uuid_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct hepv3_global_config *global_config = obj; + + if (strcasecmp(var->name, "uuid_type")) { + return -1; + } + + if (!strcasecmp(var->value, "channel")) { + global_config->uuid_type = HEP_UUID_TYPE_CHANNEL; + } else if (!strcasecmp(var->value, "call-id")) { + global_config->uuid_type = HEP_UUID_TYPE_CALL_ID; + } else { + return -1; + } + return 0; +} + /*! \brief HEPv3 run-time data destructor */ static void hepv3_data_dtor(void *obj) { @@ -376,6 +405,13 @@ static void capture_info_dtor(void *obj) ast_free(info->payload); } +enum hep_uuid_type hepv3_get_uuid_type(void) +{ + RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup); + + return config->general->uuid_type; +} + struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len) { struct hepv3_capture_info *info; @@ -607,6 +643,7 @@ static int load_module(void) aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, DEFAULT_HEP_SERVER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_address)); aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password)); aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id)); + aco_option_register_custom(&cfg_info, "uuid_type", ACO_EXACT, global_options, "call-id", uuid_type_handler, 0); if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) { goto error; diff --git a/res/res_hep.exports.in b/res/res_hep.exports.in index d09d3f40934..df0f2b4f704 100644 --- a/res/res_hep.exports.in +++ b/res/res_hep.exports.in @@ -2,6 +2,7 @@ global: LINKER_SYMBOL_PREFIX*hepv3_send_packet; LINKER_SYMBOL_PREFIX*hepv3_create_capture_info; + LINKER_SYMBOL_PREFIX*hepv3_get_uuid_type; local: *; }; diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index 87d68e36d46..effcc85dd66 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -51,13 +51,18 @@ static char *assign_uuid(const pj_str_t *call_id, const pj_str_t *local_tag, con RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup); pjsip_dialog *dlg; char *uuid = NULL; + enum hep_uuid_type uuid_type = hepv3_get_uuid_type(); - if ((dlg = pjsip_ua_find_dialog(call_id, local_tag, remote_tag, PJ_FALSE)) + if ((uuid_type == HEP_UUID_TYPE_CHANNEL) + && (dlg = pjsip_ua_find_dialog(call_id, local_tag, remote_tag, PJ_FALSE)) && (session = ast_sip_dialog_get_session(dlg)) && (session->channel)) { uuid = ast_strdup(ast_channel_name(session->channel)); - } else { + } + + /* If we couldn't get the channel or we never wanted it, default to the call-id */ + if (!uuid) { uuid = ast_malloc(pj_strlen(call_id) + 1); if (uuid) { diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 25aed152077..8643d4db6bc 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -36,6 +36,8 @@ ASTERISK_REGISTER_FILE() #include "asterisk/res_hep.h" #include "asterisk/module.h" #include "asterisk/netsock2.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" #include "asterisk/stasis.h" #include "asterisk/rtp_engine.h" #include "asterisk/json.h" @@ -43,6 +45,35 @@ ASTERISK_REGISTER_FILE() static struct stasis_subscription *stasis_rtp_subscription; +static char *assign_uuid(struct ast_json *json_channel) +{ + const char *channel_name = ast_json_string_get(ast_json_object_get(json_channel, "name")); + enum hep_uuid_type uuid_type = hepv3_get_uuid_type(); + char *uuid = NULL; + + if (!channel_name) { + return NULL; + } + + if (uuid_type == HEP_UUID_TYPE_CALL_ID && ast_begins_with(channel_name, "PJSIP")) { + struct ast_channel *chan = ast_channel_get_by_name(channel_name); + char buf[128]; + + if (chan && !ast_func_read(chan, "CHANNEL(pjsip,call-id)", buf, sizeof(buf))) { + uuid = ast_strdup(buf); + } + + ast_channel_cleanup(chan); + } + + /* If we couldn't get the call-id or didn't want it, just use the channel name */ + if (!uuid) { + uuid = ast_strdup(channel_name); + } + + return uuid; +} + static void rtcp_message_handler(struct stasis_message *message) { @@ -94,7 +125,7 @@ static void rtcp_message_handler(struct stasis_message *message) ast_sockaddr_parse(&capture_info->src_addr, ast_json_string_get(from), PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, ast_json_string_get(to), PARSE_PORT_REQUIRE); - capture_info->uuid = ast_strdup(ast_json_string_get(ast_json_object_get(json_channel, "name"))); + capture_info->uuid = assign_uuid(json_channel); if (!capture_info->uuid) { ao2_ref(capture_info, -1); return; From 14938184a38bd76b0b7bf04d583bbc1c2933407d Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sat, 14 May 2016 13:29:09 -0400 Subject: [PATCH 0432/1578] res_ari: Correct Location headers returned by some ARI resources The Location headers returned by: * /bridges/{bridgeId}/play * /bridges/{bridgeId}/record * /channels/{channelId}/play * /channels/{channelId}/record Did not have the '/ari' prefix, and in the case of the 'play' resources, were using 'playback' instead of 'playbacks.' Change-Id: I957c58a3a1471bf477dae7c67faa1b74fcd9241c --- res/ari/resource_bridges.c | 2 +- res/ari/resource_channels.c | 2 +- res/res_ari.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 6018c43bebd..57c1c273889 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -380,7 +380,7 @@ static int ari_bridges_play_helper(const char *args_media, return -1; } - if (ast_asprintf(playback_url, "/playback/%s", + if (ast_asprintf(playback_url, "/playbacks/%s", stasis_app_playback_get_id(playback)) == -1) { playback_url = NULL; ast_ari_response_alloc_failed(response); diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index c838bc39cce..edf1a20e6cb 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -524,7 +524,7 @@ static void ari_channels_handle_play( return; } - if (ast_asprintf(&playback_url, "/playback/%s", + if (ast_asprintf(&playback_url, "/playbacks/%s", stasis_app_playback_get_id(playback)) == -1) { playback_url = NULL; ast_ari_response_error( diff --git a/res/res_ari.c b/res/res_ari.c index 62083bfb12d..14dece8e4e0 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -304,10 +304,11 @@ void ast_ari_response_alloc_failed(struct ast_ari_response *response) void ast_ari_response_created(struct ast_ari_response *response, const char *url, struct ast_json *message) { + RAII_VAR(struct stasis_rest_handlers *, root, get_root_handler(), ao2_cleanup); response->message = message; response->response_code = 201; response->response_text = "Created"; - ast_str_append(&response->headers, 0, "Location: %s\r\n", url); + ast_str_append(&response->headers, 0, "Location: /%s%s\r\n", root->path_segment, url); } static void add_allow_header(struct stasis_rest_handlers *handler, From d29c17834ccbfc03406660fb3b1992bf07e84250 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 12 May 2016 07:08:08 -0500 Subject: [PATCH 0433/1578] res/res_hep_pjsip: Fix reported local IP address when bound to 'any' When bound to an 'any' address, e.g., 0.0.0.0, PJSIP reports as its local address the 'any' address, as opposed to the IP address we actually received the packet on. This can cause some confusion in Homer, as it will dutifully report what we send it. This patch uses the PJSIP inspection routines to determine which IP address we probably received the packet on based on the remote party's IP address. In the event that this fails, it falls back to the IP address natively reported by the transport. Change-Id: I076f835d2aef489e1ee1d01595b211eb2ce62da3 --- res/res_hep_pjsip.c | 54 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index 87d68e36d46..a19b15f0ea3 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -77,13 +77,35 @@ static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) pjsip_cid_hdr *cid_hdr; pjsip_from_hdr *from_hdr; pjsip_to_hdr *to_hdr; + pjsip_tpmgr_fla2_param prm; capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start)); if (!capture_info) { return PJ_SUCCESS; } - pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); + /* Attempt to determine what IP address will we send this packet out of */ + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = tdata->tp_info.transport->key.type; + pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); + prm.local_if = PJ_TRUE; + + /* If we can't get the local address use what we have already */ + if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { + pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); + } else { + if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { + snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } else { + snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } + } pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3); cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg); @@ -115,17 +137,39 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) char remote_buf[256]; char *uuid; struct hepv3_capture_info *capture_info; + pjsip_tpmgr_fla2_param prm; capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len); if (!capture_info) { return PJ_SUCCESS; } - if (rdata->tp_info.transport->addr_len) { - pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); + if (!rdata->pkt_info.src_addr_len) { + return PJ_SUCCESS; } - if (rdata->pkt_info.src_addr_len) { - pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3); + pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3); + + /* Attempt to determine what IP address we probably received this packet on */ + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = rdata->tp_info.transport->key.type; + pj_strset2(&prm.dst_host, rdata->pkt_info.src_name); + prm.local_if = PJ_TRUE; + + /* If we can't get the local address use what we have already */ + if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) { + pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); + } else { + if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { + snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } else { + snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } } uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag); From a1803cb5f4afb8d5286bb91b664f9fedb2c7dc8a Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 14 May 2016 21:48:56 -0500 Subject: [PATCH 0434/1578] configs/samples/pjsip.conf.sample: Fix typo A ':' is not a valid token for starting a comment. Change-Id: I123592d93a83d1bdde3e352822881eb9da85e5ad --- configs/samples/pjsip.conf.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index cd8709151d5..9069a669f76 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -624,7 +624,7 @@ ; identified. ; "username": Identify by the From or To username and domain ; "auth_username": Identify by the Authorization username and realm - : In all cases, if an exact match on username and domain/realm fails, + ; In all cases, if an exact match on username and domain/realm fails, ; the match will be retried with just the username. ; (default: "username") ;redirect_method=user ; How redirects received from an endpoint are handled From 352237651270c1e766cd7b0eecbf615b495cb833 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 14 May 2016 07:24:07 -0500 Subject: [PATCH 0435/1578] logger: Support JSON logging with Verbose messages When 2d7a4a3357 was merged, it missed the fact that Verbose log messages are formatted and handled by 'verbosers'. Verbosers are registered functions that handle verbose messages only; they exist as a separate class of callbacks. This was done to handle the 'magic' that must be inserted into Verbose messages sent to remote consoles, so that the consoles can format the messages correctly, i.e., the leading tabs/characters. In reality, verbosers are a weird appendage: they're a separate class of formatters/message handlers outside of what handles all other log messages in Asterisk. After some code inspection, it became clear that simply passing a Verbose message along with its 'sublevel' importance through the normal logging mechanisms removes the need for verbosers altogether. This patch removes the verbosers, and makes the default log formatter aware that, if the log channel is a console log, it should simply insert the 'verbose magic' into the log messages itself. This allows the console handlers to interpret and format the verbose message themselves. This simplifies the code quite a lot, and should improve the performance of printing verbose messages by a reasonable factor: (1) It removes a number of memory allocations that were done on each verobse message (2) It removes the need to strip the verbose magic out of the verbose log messages before passing them to non-console log channels (3) It now performs fewer iterations over lists when handling verbose messages Since verbose messages are now handled like other log messages (for the most part), the JSON formatting of the messages works as well. ASTERISK-25425 Change-Id: I21bf23f0a1e489b5102f8a035fe8871552ce4f96 --- include/asterisk/logger.h | 18 +++- main/asterisk.c | 73 +++++-------- main/logger.c | 215 +++++++++++--------------------------- utils/extconf.c | 3 - 4 files changed, 103 insertions(+), 206 deletions(-) diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index bf8ce6acf2d..9f9f671c06f 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -195,11 +195,25 @@ int ast_unregister_verbose(void (*verboser)(const char *string)) attribute_warn_ void ast_console_puts(const char *string); /*! - * \brief log the string to the console, and all attached - * console clients + * \brief log the string to the console, and all attached console clients + * + * \param string The message to write to the console + * \param level The log level of the message + * * \version 1.6.1 added level parameter */ void ast_console_puts_mutable(const char *string, int level); + +/*! + * \brief log the string to the console, and all attached console clients + * \since 14.0.0 + * + * \param message The message to write to the console + * \param sublevel If the log level supports it, the sub-level of the message + * \param level The log level of the message + */ +void ast_console_puts_mutable_full(const char *message, int level, int sublevel); + void ast_console_toggle_mute(int fd, int silent); /*! diff --git a/main/asterisk.c b/main/asterisk.c index bf2206cd77e..6cfbc1b336b 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1257,14 +1257,15 @@ void ast_console_toggle_mute(int fd, int silent) /*! * \brief log the string to all attached network console clients */ -static void ast_network_puts_mutable(const char *string, int level) +static void ast_network_puts_mutable(const char *string, int level, int sublevel) { int x; for (x = 0; x < AST_MAX_CONNECTS; ++x) { if (consoles[x].fd < 0 || consoles[x].mute - || consoles[x].levels[level]) { + || consoles[x].levels[level] + || (level == __LOG_VERBOSE && consoles[x].option_verbose < sublevel)) { continue; } fdprint(consoles[x].p[1], string); @@ -1276,13 +1277,24 @@ static void ast_network_puts_mutable(const char *string, int level) * network console clients */ void ast_console_puts_mutable(const char *string, int level) +{ + ast_console_puts_mutable_full(string, level, 0); +} + +static int console_print(const char *s); + +void ast_console_puts_mutable_full(const char *message, int level, int sublevel) { /* Send to the root console */ - fputs(string, stdout); - fflush(stdout); + console_print(message); + + /* Wake up a poll()ing console */ + if (ast_opt_console && consolethread != AST_PTHREADT_NULL) { + pthread_kill(consolethread, SIGURG); + } /* Send to any network console clients */ - ast_network_puts_mutable(string, level); + ast_network_puts_mutable(message, level, sublevel); } /*! @@ -1314,24 +1326,6 @@ void ast_console_puts(const char *string) ast_network_puts(string); } -static void network_verboser(const char *string) -{ - int x; - int verb_level; - - /* Send to any network console clients if client verbocity allows. */ - verb_level = VERBOSE_MAGIC2LEVEL(string); - for (x = 0; x < AST_MAX_CONNECTS; ++x) { - if (consoles[x].fd < 0 - || consoles[x].mute - || consoles[x].levels[__LOG_VERBOSE] - || consoles[x].option_verbose < verb_level) { - continue; - } - fdprint(consoles[x].p[1], string); - } -} - static pthread_t lthread; /*! @@ -1594,9 +1588,6 @@ static int ast_makesocket(void) ast_socket = -1; return -1; } - if (ast_register_verbose(network_verboser)) { - ast_log(LOG_WARNING, "Unable to register network verboser?\n"); - } if (ast_pthread_create_background(<hread, NULL, listener, NULL)) { ast_log(LOG_WARNING, "Unable to create listener thread.\n"); @@ -2118,7 +2109,7 @@ static int console_state_init(void *ptr) AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr); -static int console_print(const char *s, int local) +static int console_print(const char *s) { struct console_state_data *state = ast_threadstorage_get(&console_state, sizeof(*state)); @@ -2189,18 +2180,6 @@ static int console_print(const char *s, int local) return res; } -static void console_verboser(const char *s) -{ - if (!console_print(s, 1)) { - return; - } - - /* Wake up a poll()ing console */ - if (ast_opt_console && consolethread != AST_PTHREADT_NULL) { - pthread_kill(consolethread, SIGURG); - } -} - static int ast_all_zeros(const char *s) { while (*s) { @@ -2713,7 +2692,7 @@ static int ast_el_read_char(EditLine *editline, char *cp) } } - console_print(buf, 0); + console_print(buf); if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (res >= 2 && buf[res-2] == '\n'))) { *cp = CC_REFRESH; @@ -3786,10 +3765,6 @@ static void env_init(void) static void print_intro_message(const char *runuser, const char *rungroup) { if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) { - if (ast_register_verbose(console_verboser)) { - fprintf(stderr, "Unable to register console verboser?\n"); - return; - } WELCOME_MESSAGE; if (runuser) { ast_verbose("Running as user '%s'\n", runuser); @@ -4424,6 +4399,11 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou aco_init(); + if (init_logger()) { /* Start logging subsystem */ + printf("Failed: init_logger\n%s", term_quit()); + exit(1); + } + if (ast_bucket_init()) { printf("Failed: ast_bucket_init\n%s", term_quit()); exit(1); @@ -4466,11 +4446,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou srand((unsigned int) getpid() + (unsigned int) time(NULL)); initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool)); - if (init_logger()) { /* Start logging subsystem */ - printf("Failed: init_logger\n%s", term_quit()); - exit(1); - } - threadstorage_init(); if (ast_rtp_engine_init()) { diff --git a/main/logger.c b/main/logger.c index 42a1c700049..90d7cd6b111 100644 --- a/main/logger.c +++ b/main/logger.c @@ -158,6 +158,7 @@ enum logmsgtypes { struct logmsg { enum logmsgtypes type; int level; + int sublevel; int line; int lwp; ast_callid callid; @@ -307,6 +308,52 @@ static struct logformatter logformatter_json = { .format_log = format_log_json }; +static int logger_add_verbose_magic(struct logmsg *logmsg, char *buf, size_t size) +{ + const char *p; + const char *fmt; + struct ast_str *prefixed; + signed char magic = logmsg->sublevel > 9 ? -10 : -logmsg->sublevel - 1; /* 0 => -1, 1 => -2, etc. Can't pass NUL, as it is EOS-delimiter */ + + /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */ + if (logmsg->sublevel < 0) { + if (!strncmp(logmsg->message, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) { + magic = -5; + } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) { + magic = -4; + } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) { + magic = -3; + } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) { + magic = -2; + } else { + magic = -1; + } + } + + if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE))) { + return -1; + } + + ast_str_reset(prefixed); + + /* for every newline found in the buffer add verbose prefix data */ + fmt = logmsg->message; + do { + if (!(p = strchr(fmt, '\n'))) { + p = strchr(fmt, '\0') - 1; + } + ++p; + + ast_str_append(&prefixed, 0, "%c", (char)magic); + ast_str_append_substr(&prefixed, 0, fmt, p - fmt); + fmt = p; + } while (p && *p); + + snprintf(buf, size, "%s", ast_str_buffer(prefixed)); + + return 0; +} + static int format_log_default(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size) { char call_identifier_str[13]; @@ -334,6 +381,14 @@ static int format_log_default(struct logchannel *chan, struct logmsg *msg, char { char linestr[32]; + /* + * Verbose messages are interpreted by console channels in their own + * special way + */ + if (msg->level == __LOG_VERBOSE) { + return logger_add_verbose_magic(msg, buf, size); + } + /* Turn the numeric line number into a string for colorization */ snprintf(linestr, sizeof(linestr), "%d", msg->line); @@ -1405,13 +1460,6 @@ static char *handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, stru } } -struct verb { - void (*verboser)(const char *string); - AST_LIST_ENTRY(verb) list; -}; - -static AST_RWLIST_HEAD_STATIC(verbosers, verb); - static struct ast_cli_entry cli_logger[] = { AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"), AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"), @@ -1432,60 +1480,13 @@ static struct sigaction handle_SIGXFSZ = { .sa_flags = SA_RESTART, }; -static char *logger_strip_verbose_magic(const char *message, int level) -{ - const char *begin, *end; - char *stripped_message, *dst; - char magic = -(level + 1); - - if (!(stripped_message = ast_malloc(strlen(message) + 1))) { - return NULL; - } - - begin = message; - dst = stripped_message; - do { - end = strchr(begin, magic); - if (end) { - size_t len = end - begin; - memcpy(dst, begin, len); - begin = end + 1; - dst += len; - } else { - strcpy(dst, begin); /* safe */ - break; - } - } while (1); - - return stripped_message; -} - /*! \brief Print a normal log message to the channels */ static void logger_print_normal(struct logmsg *logmsg) { struct logchannel *chan = NULL; char buf[BUFSIZ]; - struct verb *v = NULL; - char *tmpmsg; int level = 0; - if (logmsg->level == __LOG_VERBOSE) { - - /* Iterate through the list of verbosers and pass them the log message string */ - AST_RWLIST_RDLOCK(&verbosers); - AST_RWLIST_TRAVERSE(&verbosers, v, list) - v->verboser(logmsg->message); - AST_RWLIST_UNLOCK(&verbosers); - - level = VERBOSE_MAGIC2LEVEL(logmsg->message); - - tmpmsg = logger_strip_verbose_magic(logmsg->message, level); - if (tmpmsg) { - ast_string_field_set(logmsg, message, tmpmsg); - ast_free(tmpmsg); - } - } - AST_RWLIST_RDLOCK(&logchannels); if (!AST_RWLIST_EMPTY(&logchannels)) { AST_RWLIST_TRAVERSE(&logchannels, chan, list) { @@ -1522,13 +1523,8 @@ static void logger_print_normal(struct logmsg *logmsg) } break; case LOGTYPE_CONSOLE: - /* The Console already is a verboser as well */ - if (logmsg->level == __LOG_VERBOSE) { - continue; - } - if (!chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) { - ast_console_puts_mutable(buf, logmsg->level); + ast_console_puts_mutable_full(buf, logmsg->level, logmsg->sublevel); } break; case LOGTYPE_FILE: @@ -1722,7 +1718,6 @@ int init_logger(void) void close_logger(void) { struct logchannel *f = NULL; - struct verb *cur = NULL; ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger)); @@ -1734,14 +1729,9 @@ void close_logger(void) ast_cond_signal(&logcond); AST_LIST_UNLOCK(&logmsgs); - if (logthread != AST_PTHREADT_NULL) + if (logthread != AST_PTHREADT_NULL) { pthread_join(logthread, NULL); - - AST_RWLIST_WRLOCK(&verbosers); - while ((cur = AST_LIST_REMOVE_HEAD(&verbosers, list))) { - ast_free(cur); } - AST_RWLIST_UNLOCK(&verbosers); AST_RWLIST_WRLOCK(&logchannels); @@ -1893,7 +1883,7 @@ void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created) /*! * \brief send log messages to syslog and/or the console */ -static void __attribute__((format(printf, 6, 0))) ast_log_full(int level, const char *file, int line, const char *function, ast_callid callid, const char *fmt, va_list ap) +static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel, const char *file, int line, const char *function, ast_callid callid, const char *fmt, va_list ap) { struct logmsg *logmsg = NULL; struct ast_str *buf = NULL; @@ -1955,6 +1945,7 @@ static void __attribute__((format(printf, 6, 0))) ast_log_full(int level, const /* Copy over data */ logmsg->level = level; + logmsg->sublevel = sublevel; logmsg->line = line; ast_string_field_set(logmsg, level_name, levels[level]); ast_string_field_set(logmsg, file, file); @@ -1989,7 +1980,7 @@ void ast_log(int level, const char *file, int line, const char *function, const if (level == __LOG_VERBOSE) { __ast_verbose_ap(file, line, function, 0, callid, fmt, ap); } else { - ast_log_full(level, file, line, function, callid, fmt, ap); + ast_log_full(level, -1, file, line, function, callid, fmt, ap); } va_end(ap); } @@ -2013,7 +2004,7 @@ void ast_log_safe(int level, const char *file, int line, const char *function, c callid = ast_read_threadstorage_callid(); va_start(ap, fmt); - ast_log_full(level, file, line, function, callid, fmt, ap); + ast_log_full(level, -1, file, line, function, callid, fmt, ap); va_end(ap); /* Clear flag so the next allocation failure can be logged. */ @@ -2024,7 +2015,7 @@ void ast_log_callid(int level, const char *file, int line, const char *function, { va_list ap; va_start(ap, fmt); - ast_log_full(level, file, line, function, callid, fmt, ap); + ast_log_full(level, -1, file, line, function, callid, fmt, ap); va_end(ap); } @@ -2059,53 +2050,7 @@ void ast_log_backtrace(void) void __ast_verbose_ap(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, va_list ap) { - const char *p; - struct ast_str *prefixed, *buf; - int res = 0; - signed char magic = level > 9 ? -10 : -level - 1; /* 0 => -1, 1 => -2, etc. Can't pass NUL, as it is EOS-delimiter */ - - /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */ - if (level < 0) { - if (!strncmp(fmt, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) { - magic = -5; - } else if (!strncmp(fmt, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) { - magic = -4; - } else if (!strncmp(fmt, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) { - magic = -3; - } else if (!strncmp(fmt, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) { - magic = -2; - } else { - magic = -1; - } - } - - if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)) || - !(buf = ast_str_thread_get(&verbose_build_buf, VERBOSE_BUF_INIT_SIZE))) { - return; - } - - res = ast_str_set_va(&buf, 0, fmt, ap); - /* If the build failed then we can drop this allocated message */ - if (res == AST_DYNSTR_BUILD_FAILED) { - return; - } - - ast_str_reset(prefixed); - - /* for every newline found in the buffer add verbose prefix data */ - fmt = ast_str_buffer(buf); - do { - if (!(p = strchr(fmt, '\n'))) { - p = strchr(fmt, '\0') - 1; - } - ++p; - - ast_str_append(&prefixed, 0, "%c", (char)magic); - ast_str_append_substr(&prefixed, 0, fmt, p - fmt); - fmt = p; - } while (p && *p); - - ast_log_callid(__LOG_VERBOSE, file, line, func, callid, "%s", ast_str_buffer(prefixed)); + ast_log_full(__LOG_VERBOSE, level, file, line, func, callid, fmt, ap); } void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...) @@ -2270,40 +2215,6 @@ void ast_verb_console_set(int verb_level) ast_verb_update(); } -int ast_register_verbose(void (*v)(const char *string)) -{ - struct verb *verb; - - if (!(verb = ast_malloc(sizeof(*verb)))) - return -1; - - verb->verboser = v; - - AST_RWLIST_WRLOCK(&verbosers); - AST_RWLIST_INSERT_HEAD(&verbosers, verb, list); - AST_RWLIST_UNLOCK(&verbosers); - - return 0; -} - -int ast_unregister_verbose(void (*v)(const char *string)) -{ - struct verb *cur; - - AST_RWLIST_WRLOCK(&verbosers); - AST_RWLIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) { - if (cur->verboser == v) { - AST_RWLIST_REMOVE_CURRENT(list); - ast_free(cur); - break; - } - } - AST_RWLIST_TRAVERSE_SAFE_END; - AST_RWLIST_UNLOCK(&verbosers); - - return cur ? 0 : -1; -} - static void update_logchannels(void) { struct logchannel *cur; diff --git a/utils/extconf.c b/utils/extconf.c index 4eaea3c2d37..48053aed662 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -120,9 +120,6 @@ void ast_queue_log(const char *queuename, const char *callid, const char *agent, /* IN CONFLICT: void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2))); */ -int ast_register_verbose(void (*verboser)(const char *string)); -int ast_unregister_verbose(void (*verboser)(const char *string)); - void ast_console_puts(const char *string); #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__ From 8b5cee4a4f62c4b7ebcd94aa834c5e84ac108b09 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 15 May 2016 18:05:34 -0600 Subject: [PATCH 0436/1578] res_pjsip: Set TCP_NODELAY on TCP transports Although it's perfectly legal to place multiple SIP messages in the same packet, it can cause problems because the Linux default is to enable Path MTU Discovery which sets the Don't Fragment bit on the packets. If adding a second message to the packet causes the MTU to be exceeded, and the destination isn't equipped to send a FRAGMENTATION NEEDED response to a large packet, the packet will just be dropped. We can't specifically tell the stack to send only 1 message per packet, but we can turn on TCP_NODELAY when we create the transport. This will at least tell the stack to send packets as soon as possible. ASTERISK-26005 #close Reported-by: Ross Beer Change-Id: I820f23227183f2416ca5e393bec510e8fe1c8fbd --- res/res_pjsip/config_transport.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 3a5afb6bcc8..b9208976fc3 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -562,11 +562,17 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) } } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; + int option = 1; pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family); cfg.bind_addr = temp_state->state->host; cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); + cfg.sockopt_params.options[0].level = pj_SOL_TCP(); + cfg.sockopt_params.options[0].optname = pj_TCP_NODELAY(); + cfg.sockopt_params.options[0].optval = &option; + cfg.sockopt_params.options[0].optlen = sizeof(option); + cfg.sockopt_params.cnt = 1; for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory From ae81b55361f3919706775b5a64ab8327a8edab4f Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 16 May 2016 14:29:38 -0600 Subject: [PATCH 0437/1578] res_pjsip_outbound_registration: Clean up state when registration is deleted Nothing was cleaning up the registration state object when ast_sorcery_delete was called on a registration. So, the registration was deleted from sorcery but the state object went right on refreshing the registration (or failing to refresh the registration) with the peer. * Added a 'deleted' observer on registration that removes the state object. ASTERISK-25964 #close Reported-by Matt Jordan Change-Id: I2db792145cdb1f72ebbf57dd9099596dbbf12c23 --- res/res_pjsip_outbound_registration.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 815432d10e0..62fe6dab2f1 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1912,6 +1912,26 @@ static const struct ast_sorcery_instance_observer observer_callbacks_registratio .object_type_loaded = registration_loaded_observer, }; +static void registration_deleted_observer(const void *obj) +{ + const struct sip_outbound_registration *registration = obj; + struct ao2_container *states; + + states = ao2_global_obj_ref(current_states); + if (!states) { + /* Global container has gone. Likely shutting down. */ + return; + } + + ao2_find(states, ast_sorcery_object_get_id(registration), OBJ_UNLINK | OBJ_NODATA | OBJ_SEARCH_KEY); + + ao2_ref(states, -1); +} + +static const struct ast_sorcery_observer registration_observer = { + .deleted = registration_deleted_observer, +}; + static int unload_module(void) { int remaining; @@ -2011,7 +2031,9 @@ static int load_module(void) if (ast_sorcery_instance_observer_add(ast_sip_get_sorcery(), &observer_callbacks_registrations) || ast_sorcery_observer_add(ast_sip_get_sorcery(), "auth", - &observer_callbacks_auth)) { + &observer_callbacks_auth) + || ast_sorcery_observer_add(ast_sip_get_sorcery(), "registration", + ®istration_observer)) { ast_log(LOG_ERROR, "Unable to register observers.\n"); unload_module(); return AST_MODULE_LOAD_FAILURE; From 5bd1bf281604b653134d79e7094c7cec00785ff1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 17 May 2016 10:14:51 -0600 Subject: [PATCH 0438/1578] chan_sip: Prevent extra Session-Expires headers from being added When chan_sip does a re-INVITE to refresh a session and authentication is required, the INVITE with the Authorization header containes a second Session-Expires header without the ";refersher=" parameter. This is causing some proxies to return a 400. Also, when Asterisk is the uas and the refresher, it is including the Session-Expires and Min-SE headers in OPTIONS messages which is not allowed per RFC4028. This patch (based on the reporter's) Checks to see if a Session-Expires header is already in the message before adding another one. It also checks that the method is INVITE or UPDATE. ASTERISK-26030 #close Change-Id: I58a7b07bab5a3177748d8a7034fb8ad8e11ce1d9 --- channels/chan_sip.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 7fde6f8f950..19f8aa308a8 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -14529,10 +14529,12 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init, add_header(&req, "Require", "replaces"); } - /* Add Session-Timers related headers */ - if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE + /* Add Session-Timers related headers if not already there */ + if (ast_strlen_zero(sip_get_header(&req, "Session-Expires")) && + (sipmethod == SIP_INVITE || sipmethod == SIP_UPDATE) && + (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE || (st_get_mode(p, 0) == SESSION_TIMER_MODE_ACCEPT - && st_get_se(p, FALSE) != DEFAULT_MIN_SE)) { + && st_get_se(p, FALSE) != DEFAULT_MIN_SE))) { char i2astr[10]; if (!p->stimer->st_interval) { From 03d88b56565301d0552676ceb72f059b9267bca7 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 18 Apr 2016 18:17:08 -0500 Subject: [PATCH 0439/1578] ARI: Add the ability to play multiple media URIs in a single operation Many ARI applications will want to play multiple media files in a row to a resource. The most common use case is when building long-ish IVR prompts made up of multiple, smaller sound files. Today, that requires building a small state machine, listening for each PlaybackFinished event, and triggering the next sound file to play. While not especially challenging, it is tedious work. Since requiring developers to write tedious code to do normal activities stinks, this patch adds the ability to play back a list of media files to a resource. Each of the 'play' operations on supported resources (channels and bridges) now accepts a comma delineated list of media URIs to play. A single Playback resource is created as a handle to the entire list. The operation of playing a list is identical to playing a single media URI, save that a new event, PlaybackContinuing, is raised instead of a PlaybackFinished for each non-final media URI. When the entire list is finished being played, a PlaybackFinished event is raised. In order to help inform applications where they are in the list playback, the Playback resource now includes a new, optional attribute, 'next_media_uri', that contains the next URI in the list to be played. It's important to note the following: - If an offset is provided to the 'play' operations, it only applies to the first media URI, as it would be weird to skip n seconds forward in every media resource. - Operations that control the position of the media only affect the current media being played. For example, once a media resource in the list completes, a 'reverse' operation on a subsequent media resource will not start a previously completed media resource at the appropiate offset. - This patch does not add any new operations to control the list. Hopefully, user feedback and/or future patches would add that if people want it. ASTERISK-26022 #close Change-Id: Ie1ea5356573447b8f51f2e7964915ea01792f16f --- CHANGES | 9 ++ include/asterisk/stasis_app_playback.h | 17 +- res/ari/ari_model_validators.c | 94 +++++++++++ res/ari/ari_model_validators.h | 24 +++ res/ari/resource_bridges.c | 42 +++-- res/ari/resource_bridges.h | 20 ++- res/ari/resource_channels.c | 7 +- res/ari/resource_channels.h | 20 ++- res/res_ari_bridges.c | 142 ++++++++++++++++- res/res_ari_channels.c | 142 ++++++++++++++++- res/res_stasis_playback.c | 210 ++++++++++++++++--------- rest-api/api-docs/bridges.json | 12 +- rest-api/api-docs/channels.json | 12 +- rest-api/api-docs/events.json | 12 ++ rest-api/api-docs/playbacks.json | 10 +- 15 files changed, 645 insertions(+), 128 deletions(-) diff --git a/CHANGES b/CHANGES index ec44e30fc4b..15b4d0c670d 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,15 @@ ARI * To complement the "create" method, a "dial" method has been added to the channels resource in order to place a call to a created channel. + * All operations that initiate playback of media on a resource now support + a list of media URIs. The list of URIs are played in the order they are + presented to the resource. A new event, "PlaybackContinuing", is raised when + a media URI finishes but before the next media URI starts. When a list is + played, the "Playback" model will contain the optional attribute + "next_media_uri", which specifies the next media URI in the list to be played + back to the resource. The "PlaybackFinished" event is raised when all media + URIs are done. + Applications ------------------ diff --git a/include/asterisk/stasis_app_playback.h b/include/asterisk/stasis_app_playback.h index b35299581cf..0038fd6d081 100644 --- a/include/asterisk/stasis_app_playback.h +++ b/include/asterisk/stasis_app_playback.h @@ -41,6 +41,8 @@ enum stasis_app_playback_state { STASIS_PLAYBACK_STATE_PLAYING, /*! The media is currently playing */ STASIS_PLAYBACK_STATE_PAUSED, + /*! The media is transitioning to the next in the list */ + STASIS_PLAYBACK_STATE_CONTINUING, /*! The media has stopped playing */ STASIS_PLAYBACK_STATE_COMPLETE, /*! The playback was canceled. */ @@ -84,7 +86,8 @@ enum stasis_app_playback_target_type { * available codecs for the channel. * * \param control Control for \c res_stasis. - * \param file Base filename for the file to play. + * \param media Array of const char * media files to play. + * \param media_count The number of media files in \c media. * \param language Selects the file based on language. * \param target_id ID of the target bridge or channel. * \param target_type What the target type is @@ -95,8 +98,8 @@ enum stasis_app_playback_target_type { * \return \c NULL on error. */ struct stasis_app_playback *stasis_app_control_play_uri( - struct stasis_app_control *control, const char *file, - const char *language, const char *target_id, + struct stasis_app_control *control, const char **media, + size_t media_count, const char *language, const char *target_id, enum stasis_app_playback_target_type target_type, int skipms, long offsetms, const char *id); @@ -128,6 +131,14 @@ const char *stasis_app_playback_get_id( */ struct stasis_app_playback *stasis_app_playback_find_by_id(const char *id); +/*! + * \brief Convert a playback to its JSON representation + * + * \param playback The playback object to convert to JSON + * + * \retval \c NULL on error + * \retval A JSON object on success + */ struct ast_json *stasis_app_playback_to_json( const struct stasis_app_playback *playback); diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index 623d5b54162..8f05db03561 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -1744,6 +1744,15 @@ int ast_ari_validate_playback(struct ast_json *json) res = 0; } } else + if (strcmp("next_media_uri", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Playback field next_media_uri failed validation\n"); + res = 0; + } + } else if (strcmp("state", ast_json_object_iter_key(iter)) == 0) { int prop_is_valid; has_state = 1; @@ -4741,6 +4750,9 @@ int ast_ari_validate_event(struct ast_json *json) if (strcmp("PeerStatusChange", discriminator) == 0) { return ast_ari_validate_peer_status_change(json); } else + if (strcmp("PlaybackContinuing", discriminator) == 0) { + return ast_ari_validate_playback_continuing(json); + } else if (strcmp("PlaybackFinished", discriminator) == 0) { return ast_ari_validate_playback_finished(json); } else @@ -4930,6 +4942,9 @@ int ast_ari_validate_message(struct ast_json *json) if (strcmp("PeerStatusChange", discriminator) == 0) { return ast_ari_validate_peer_status_change(json); } else + if (strcmp("PlaybackContinuing", discriminator) == 0) { + return ast_ari_validate_playback_continuing(json); + } else if (strcmp("PlaybackFinished", discriminator) == 0) { return ast_ari_validate_playback_finished(json); } else @@ -5216,6 +5231,85 @@ ari_validator ast_ari_validate_peer_status_change_fn(void) return ast_ari_validate_peer_status_change; } +int ast_ari_validate_playback_continuing(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_type = 0; + int has_application = 0; + int has_playback = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("type", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_type = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PlaybackContinuing field type failed validation\n"); + res = 0; + } + } else + if (strcmp("application", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_application = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PlaybackContinuing field application failed validation\n"); + res = 0; + } + } else + if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_date( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PlaybackContinuing field timestamp failed validation\n"); + res = 0; + } + } else + if (strcmp("playback", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_playback = 1; + prop_is_valid = ast_ari_validate_playback( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PlaybackContinuing field playback failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI PlaybackContinuing has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_type) { + ast_log(LOG_ERROR, "ARI PlaybackContinuing missing required field type\n"); + res = 0; + } + + if (!has_application) { + ast_log(LOG_ERROR, "ARI PlaybackContinuing missing required field application\n"); + res = 0; + } + + if (!has_playback) { + ast_log(LOG_ERROR, "ARI PlaybackContinuing missing required field playback\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_playback_continuing_fn(void) +{ + return ast_ari_validate_playback_continuing; +} + int ast_ari_validate_playback_finished(struct ast_json *json) { int res = 1; diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index 0bcdb0fa211..2634528bace 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -1186,6 +1186,24 @@ int ast_ari_validate_peer_status_change(struct ast_json *json); */ ari_validator ast_ari_validate_peer_status_change_fn(void); +/*! + * \brief Validator for PlaybackContinuing. + * + * Event showing the continuation of a media playback operation from one media URI to the next in the list. + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_playback_continuing(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_playback_continuing(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_playback_continuing_fn(void); + /*! * \brief Validator for PlaybackFinished. * @@ -1457,6 +1475,7 @@ ari_validator ast_ari_validate_application_fn(void); * - id: string (required) * - language: string * - media_uri: string (required) + * - next_media_uri: string * - state: string (required) * - target_uri: string (required) * DeviceState @@ -1670,6 +1689,11 @@ ari_validator ast_ari_validate_application_fn(void); * - timestamp: Date * - endpoint: Endpoint (required) * - peer: Peer (required) + * PlaybackContinuing + * - type: string (required) + * - application: string (required) + * - timestamp: Date + * - playback: Playback (required) * PlaybackFinished * - type: string (required) * - application: string (required) diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 57c1c273889..cec443dbab4 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -332,7 +332,8 @@ static struct ast_channel *prepare_bridge_media_channel(const char *type) * \brief Performs common setup for a bridge playback operation * with both new controls and when existing controls are found. * - * \param args_media media string split from arguments + * \param args_media medias to play + * \param args_media_count number of media items in \c media * \param args_lang language string split from arguments * \param args_offset_ms milliseconds offset split from arguments * \param args_playback_id string to use for playback split from @@ -346,7 +347,8 @@ static struct ast_channel *prepare_bridge_media_channel(const char *type) * \retval -1 operation failed * \retval operation was successful */ -static int ari_bridges_play_helper(const char *args_media, +static int ari_bridges_play_helper(const char **args_media, + size_t args_media_count, const char *args_lang, int args_offset_ms, int args_skipms, @@ -371,8 +373,8 @@ static int ari_bridges_play_helper(const char *args_media, language = S_OR(args_lang, snapshot->language); - playback = stasis_app_control_play_uri(control, args_media, language, - bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms, + playback = stasis_app_control_play_uri(control, args_media, args_media_count, + language, bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms, args_offset_ms, args_playback_id); if (!playback) { @@ -396,7 +398,8 @@ static int ari_bridges_play_helper(const char *args_media, return 0; } -static void ari_bridges_play_new(const char *args_media, +static void ari_bridges_play_new(const char **args_media, + size_t args_media_count, const char *args_lang, int args_offset_ms, int args_skipms, @@ -449,9 +452,9 @@ static void ari_bridges_play_new(const char *args_media, } ao2_lock(control); - if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms, - args_skipms, args_playback_id, response, bridge, control, - &json, &playback_url)) { + if (ari_bridges_play_helper(args_media, args_media_count, args_lang, + args_offset_ms, args_skipms, args_playback_id, response, bridge, + control, &json, &playback_url)) { ao2_unlock(control); return; } @@ -497,7 +500,8 @@ enum play_found_result { * \brief Performs common setup for a bridge playback operation * with both new controls and when existing controls are found. * - * \param args_media media string split from arguments + * \param args_media medias to play + * \param args_media_count number of media items in \c media * \param args_lang language string split from arguments * \param args_offset_ms milliseconds offset split from arguments * \param args_playback_id string to use for playback split from @@ -511,7 +515,8 @@ enum play_found_result { * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because * the channel requested to playback with is breaking down. */ -static enum play_found_result ari_bridges_play_found(const char *args_media, +static enum play_found_result ari_bridges_play_found(const char **args_media, + size_t args_media_count, const char *args_lang, int args_offset_ms, int args_skipms, @@ -537,9 +542,9 @@ static enum play_found_result ari_bridges_play_found(const char *args_media, return PLAY_FOUND_CHANNEL_UNAVAILABLE; } - if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms, - args_skipms, args_playback_id, response, bridge, control, - &json, &playback_url)) { + if (ari_bridges_play_helper(args_media, args_media_count, + args_lang, args_offset_ms, args_skipms, args_playback_id, + response, bridge, control, &json, &playback_url)) { ao2_unlock(control); return PLAY_FOUND_FAILURE; } @@ -551,7 +556,8 @@ static enum play_found_result ari_bridges_play_found(const char *args_media, static void ari_bridges_handle_play( const char *args_bridge_id, - const char *args_media, + const char **args_media, + size_t args_media_count, const char *args_lang, int args_offset_ms, int args_skipms, @@ -574,15 +580,15 @@ static void ari_bridges_handle_play( * that will work or else there isn't a channel for this bridge anymore, * in which case we'll revert to ari_bridges_play_new. */ - if (ari_bridges_play_found(args_media, args_lang, args_offset_ms, - args_skipms, args_playback_id, response,bridge, + if (ari_bridges_play_found(args_media, args_media_count, args_lang, + args_offset_ms, args_skipms, args_playback_id, response,bridge, play_channel) == PLAY_FOUND_CHANNEL_UNAVAILABLE) { continue; } return; } - ari_bridges_play_new(args_media, args_lang, args_offset_ms, + ari_bridges_play_new(args_media, args_media_count, args_lang, args_offset_ms, args_skipms, args_playback_id, response, bridge); } @@ -593,6 +599,7 @@ void ast_ari_bridges_play(struct ast_variable *headers, { ari_bridges_handle_play(args->bridge_id, args->media, + args->media_count, args->lang, args->offsetms, args->skipms, @@ -606,6 +613,7 @@ void ast_ari_bridges_play_with_id(struct ast_variable *headers, { ari_bridges_handle_play(args->bridge_id, args->media, + args->media_count, args->lang, args->offsetms, args->skipms, diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h index 36ff6a01784..17a3b8365f0 100644 --- a/res/ari/resource_bridges.h +++ b/res/ari/resource_bridges.h @@ -245,11 +245,15 @@ void ast_ari_bridges_stop_moh(struct ast_variable *headers, struct ast_ari_bridg struct ast_ari_bridges_play_args { /*! Bridge's id */ const char *bridge_id; - /*! Media's URI to play. */ - const char *media; + /*! Array of Media URIs to play. */ + const char **media; + /*! Length of media array. */ + size_t media_count; + /*! Parsing context for media. */ + char *media_parse; /*! For sounds, selects language for sound. */ const char *lang; - /*! Number of media to skip before playing. */ + /*! Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified. */ int offsetms; /*! Number of milliseconds to skip for forward/reverse operations. */ int skipms; @@ -283,11 +287,15 @@ struct ast_ari_bridges_play_with_id_args { const char *bridge_id; /*! Playback ID. */ const char *playback_id; - /*! Media's URI to play. */ - const char *media; + /*! Array of Media URIs to play. */ + const char **media; + /*! Length of media array. */ + size_t media_count; + /*! Parsing context for media. */ + char *media_parse; /*! For sounds, selects language for sound. */ const char *lang; - /*! Number of media to skip before playing. */ + /*! Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified. */ int offsetms; /*! Number of milliseconds to skip for forward/reverse operations. */ int skipms; diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index edf1a20e6cb..b42581c8463 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -469,7 +469,8 @@ void ast_ari_channels_stop_silence(struct ast_variable *headers, static void ari_channels_handle_play( const char *args_channel_id, - const char *args_media, + const char **args_media, + size_t args_media_count, const char *args_lang, int args_offsetms, int args_skipms, @@ -515,7 +516,7 @@ static void ari_channels_handle_play( language = S_OR(args_lang, snapshot->language); - playback = stasis_app_control_play_uri(control, args_media, language, + playback = stasis_app_control_play_uri(control, args_media, args_media_count, language, args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id); if (!playback) { ast_ari_response_error( @@ -551,6 +552,7 @@ void ast_ari_channels_play(struct ast_variable *headers, ari_channels_handle_play( args->channel_id, args->media, + args->media_count, args->lang, args->offsetms, args->skipms, @@ -565,6 +567,7 @@ void ast_ari_channels_play_with_id(struct ast_variable *headers, ari_channels_handle_play( args->channel_id, args->media, + args->media_count, args->lang, args->offsetms, args->skipms, diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h index 89b466d00a0..c690d70c813 100644 --- a/res/ari/resource_channels.h +++ b/res/ari/resource_channels.h @@ -505,11 +505,15 @@ void ast_ari_channels_stop_silence(struct ast_variable *headers, struct ast_ari_ struct ast_ari_channels_play_args { /*! Channel's id */ const char *channel_id; - /*! Media's URI to play. */ - const char *media; + /*! Array of Media URIs to play. */ + const char **media; + /*! Length of media array. */ + size_t media_count; + /*! Parsing context for media. */ + char *media_parse; /*! For sounds, selects language for sound. */ const char *lang; - /*! Number of media to skip before playing. */ + /*! Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified. */ int offsetms; /*! Number of milliseconds to skip for forward/reverse operations. */ int skipms; @@ -543,11 +547,15 @@ struct ast_ari_channels_play_with_id_args { const char *channel_id; /*! Playback ID. */ const char *playback_id; - /*! Media's URI to play. */ - const char *media; + /*! Array of Media URIs to play. */ + const char **media; + /*! Length of media array. */ + size_t media_count; + /*! Parsing context for media. */ + char *media_parse; /*! For sounds, selects language for sound. */ const char *lang; - /*! Number of media to skip before playing. */ + /*! Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified. */ int offsetms; /*! Number of milliseconds to skip for forward/reverse operations. */ int skipms; diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 633dc94eb2a..119687999fd 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -935,7 +935,32 @@ int ast_ari_bridges_play_parse_body( /* Parse query parameters out of it */ field = ast_json_object_get(body, "media"); if (field) { - args->media = ast_json_string_get(field); + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args->media); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args->media_count = ast_json_array_size(field); + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + + if (!args->media) { + return -1; + } + + for (i = 0; i < args->media_count; ++i) { + args->media[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args->media_count = 1; + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + if (!args->media) { + return -1; + } + args->media[0] = ast_json_string_get(field); + } } field = ast_json_object_get(body, "lang"); if (field) { @@ -978,7 +1003,47 @@ static void ast_ari_bridges_play_cb( for (i = get_params; i; i = i->next) { if (strcmp(i->name, "media") == 0) { - args.media = (i->value); + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.media_parse = ast_strdup(i->value); + if (!args.media_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (strlen(args.media_parse) == 0) { + /* ast_app_separate_args can't handle "" */ + args.media_count = 1; + vals[0] = args.media_parse; + } else { + args.media_count = ast_app_separate_args( + args.media_parse, ',', vals, + ARRAY_LEN(vals)); + } + + if (args.media_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.media_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for media"); + goto fin; + } + + args.media = ast_malloc(sizeof(*args.media) * args.media_count); + if (!args.media) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.media_count; ++j) { + args.media[j] = (vals[j]); + } } else if (strcmp(i->name, "lang") == 0) { args.lang = (i->value); @@ -1051,6 +1116,8 @@ static void ast_ari_bridges_play_cb( #endif /* AST_DEVMODE */ fin: __attribute__((unused)) + ast_free(args.media_parse); + ast_free(args.media); return; } int ast_ari_bridges_play_with_id_parse_body( @@ -1061,7 +1128,32 @@ int ast_ari_bridges_play_with_id_parse_body( /* Parse query parameters out of it */ field = ast_json_object_get(body, "media"); if (field) { - args->media = ast_json_string_get(field); + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args->media); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args->media_count = ast_json_array_size(field); + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + + if (!args->media) { + return -1; + } + + for (i = 0; i < args->media_count; ++i) { + args->media[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args->media_count = 1; + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + if (!args->media) { + return -1; + } + args->media[0] = ast_json_string_get(field); + } } field = ast_json_object_get(body, "lang"); if (field) { @@ -1100,7 +1192,47 @@ static void ast_ari_bridges_play_with_id_cb( for (i = get_params; i; i = i->next) { if (strcmp(i->name, "media") == 0) { - args.media = (i->value); + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.media_parse = ast_strdup(i->value); + if (!args.media_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (strlen(args.media_parse) == 0) { + /* ast_app_separate_args can't handle "" */ + args.media_count = 1; + vals[0] = args.media_parse; + } else { + args.media_count = ast_app_separate_args( + args.media_parse, ',', vals, + ARRAY_LEN(vals)); + } + + if (args.media_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.media_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for media"); + goto fin; + } + + args.media = ast_malloc(sizeof(*args.media) * args.media_count); + if (!args.media) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.media_count; ++j) { + args.media[j] = (vals[j]); + } } else if (strcmp(i->name, "lang") == 0) { args.lang = (i->value); @@ -1173,6 +1305,8 @@ static void ast_ari_bridges_play_with_id_cb( #endif /* AST_DEVMODE */ fin: __attribute__((unused)) + ast_free(args.media_parse); + ast_free(args.media); return; } int ast_ari_bridges_record_parse_body( diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 1f081817021..951a5475bc0 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -1842,7 +1842,32 @@ int ast_ari_channels_play_parse_body( /* Parse query parameters out of it */ field = ast_json_object_get(body, "media"); if (field) { - args->media = ast_json_string_get(field); + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args->media); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args->media_count = ast_json_array_size(field); + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + + if (!args->media) { + return -1; + } + + for (i = 0; i < args->media_count; ++i) { + args->media[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args->media_count = 1; + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + if (!args->media) { + return -1; + } + args->media[0] = ast_json_string_get(field); + } } field = ast_json_object_get(body, "lang"); if (field) { @@ -1885,7 +1910,47 @@ static void ast_ari_channels_play_cb( for (i = get_params; i; i = i->next) { if (strcmp(i->name, "media") == 0) { - args.media = (i->value); + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.media_parse = ast_strdup(i->value); + if (!args.media_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (strlen(args.media_parse) == 0) { + /* ast_app_separate_args can't handle "" */ + args.media_count = 1; + vals[0] = args.media_parse; + } else { + args.media_count = ast_app_separate_args( + args.media_parse, ',', vals, + ARRAY_LEN(vals)); + } + + if (args.media_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.media_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for media"); + goto fin; + } + + args.media = ast_malloc(sizeof(*args.media) * args.media_count); + if (!args.media) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.media_count; ++j) { + args.media[j] = (vals[j]); + } } else if (strcmp(i->name, "lang") == 0) { args.lang = (i->value); @@ -1958,6 +2023,8 @@ static void ast_ari_channels_play_cb( #endif /* AST_DEVMODE */ fin: __attribute__((unused)) + ast_free(args.media_parse); + ast_free(args.media); return; } int ast_ari_channels_play_with_id_parse_body( @@ -1968,7 +2035,32 @@ int ast_ari_channels_play_with_id_parse_body( /* Parse query parameters out of it */ field = ast_json_object_get(body, "media"); if (field) { - args->media = ast_json_string_get(field); + /* If they were silly enough to both pass in a query param and a + * JSON body, free up the query value. + */ + ast_free(args->media); + if (ast_json_typeof(field) == AST_JSON_ARRAY) { + /* Multiple param passed as array */ + size_t i; + args->media_count = ast_json_array_size(field); + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + + if (!args->media) { + return -1; + } + + for (i = 0; i < args->media_count; ++i) { + args->media[i] = ast_json_string_get(ast_json_array_get(field, i)); + } + } else { + /* Multiple param passed as single value */ + args->media_count = 1; + args->media = ast_malloc(sizeof(*args->media) * args->media_count); + if (!args->media) { + return -1; + } + args->media[0] = ast_json_string_get(field); + } } field = ast_json_object_get(body, "lang"); if (field) { @@ -2007,7 +2099,47 @@ static void ast_ari_channels_play_with_id_cb( for (i = get_params; i; i = i->next) { if (strcmp(i->name, "media") == 0) { - args.media = (i->value); + /* Parse comma separated list */ + char *vals[MAX_VALS]; + size_t j; + + args.media_parse = ast_strdup(i->value); + if (!args.media_parse) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (strlen(args.media_parse) == 0) { + /* ast_app_separate_args can't handle "" */ + args.media_count = 1; + vals[0] = args.media_parse; + } else { + args.media_count = ast_app_separate_args( + args.media_parse, ',', vals, + ARRAY_LEN(vals)); + } + + if (args.media_count == 0) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + if (args.media_count >= MAX_VALS) { + ast_ari_response_error(response, 400, + "Bad Request", + "Too many values for media"); + goto fin; + } + + args.media = ast_malloc(sizeof(*args.media) * args.media_count); + if (!args.media) { + ast_ari_response_alloc_failed(response); + goto fin; + } + + for (j = 0; j < args.media_count; ++j) { + args.media[j] = (vals[j]); + } } else if (strcmp(i->name, "lang") == 0) { args.lang = (i->value); @@ -2080,6 +2212,8 @@ static void ast_ari_channels_play_with_id_cb( #endif /* AST_DEVMODE */ fin: __attribute__((unused)) + ast_free(args.media_parse); + ast_free(args.media); return; } int ast_ari_channels_record_parse_body( diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index 97191c26dd1..a64ecffa706 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -70,10 +70,16 @@ static struct ao2_container *playbacks; struct stasis_app_playback { AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(id); /*!< Playback unique id */ - AST_STRING_FIELD(media); /*!< Playback media uri */ + AST_STRING_FIELD(media); /*!< The current media playing */ AST_STRING_FIELD(language); /*!< Preferred language */ AST_STRING_FIELD(target); /*!< Playback device uri */ - ); + ); + /*! The list of medias to play back */ + AST_VECTOR(, char *) medias; + + /*! The current index in \c medias we're playing */ + size_t media_index; + /*! Control object for the channel we're playing back to */ struct stasis_app_control *control; /*! Number of milliseconds to skip before playing */ @@ -99,6 +105,8 @@ static struct ast_json *playback_to_json(struct stasis_message *message, if (!strcmp(state, "playing")) { type = "PlaybackStarted"; + } else if (!strcmp(state, "continuing")) { + type = "PlaybackContinuing"; } else if (!strcmp(state, "done")) { type = "PlaybackFinished"; } else { @@ -117,6 +125,14 @@ STASIS_MESSAGE_TYPE_DEFN(stasis_app_playback_snapshot_type, static void playback_dtor(void *obj) { struct stasis_app_playback *playback = obj; + int i; + + for (i = 0; i < AST_VECTOR_SIZE(&playback->medias); i++) { + char *media = AST_VECTOR_GET(&playback->medias, i); + + ast_free(media); + } + AST_VECTOR_FREE(&playback->medias); ao2_cleanup(playback->control); ast_string_field_free_memory(playback); @@ -137,6 +153,11 @@ static struct stasis_app_playback *playback_create( return NULL; } + if (AST_VECTOR_INIT(&playback->medias, 8)) { + ao2_ref(playback, -1); + return NULL; + } + if (!ast_strlen_zero(id)) { ast_string_field_set(playback, id, id); } else { @@ -180,6 +201,8 @@ static const char *state_to_string(enum stasis_app_playback_state state) return "playing"; case STASIS_PLAYBACK_STATE_PAUSED: return "paused"; + case STASIS_PLAYBACK_STATE_CONTINUING: + return "continuing"; case STASIS_PLAYBACK_STATE_STOPPED: case STASIS_PLAYBACK_STATE_COMPLETE: case STASIS_PLAYBACK_STATE_CANCELED: @@ -241,7 +264,11 @@ static void playback_final_update(struct stasis_app_playback *playback, playback->playedms = playedms; if (res == 0) { - playback->state = STASIS_PLAYBACK_STATE_COMPLETE; + if (playback->media_index == AST_VECTOR_SIZE(&playback->medias) - 1) { + playback->state = STASIS_PLAYBACK_STATE_COMPLETE; + } else { + playback->state = STASIS_PLAYBACK_STATE_CONTINUING; + } } else { if (playback->state == STASIS_PLAYBACK_STATE_STOPPED) { ast_log(LOG_NOTICE, "%s: Playback stopped for %s\n", @@ -262,7 +289,7 @@ static void play_on_channel(struct stasis_app_playback *playback, int res; long offsetms; - /* Even though these local variables look fairly pointless, the avoid + /* Even though these local variables look fairly pointless, they avoid * having a bunch of NULL's passed directly into * ast_control_streamfile() */ const char *fwd = NULL; @@ -273,73 +300,80 @@ static void play_on_channel(struct stasis_app_playback *playback, ast_assert(playback != NULL); - offsetms = playback->offsetms; - - res = playback_first_update(playback, ast_channel_uniqueid(chan)); - - if (res != 0) { - return; - } - if (ast_channel_state(chan) != AST_STATE_UP) { ast_indicate(chan, AST_CONTROL_PROGRESS); } - if (ast_begins_with(playback->media, SOUND_URI_SCHEME)) { - playback->controllable = 1; - - /* Play sound */ - res = ast_control_streamfile_lang(chan, playback->media + strlen(SOUND_URI_SCHEME), - fwd, rev, stop, pause, restart, playback->skipms, playback->language, - &offsetms); - } else if (ast_begins_with(playback->media, RECORDING_URI_SCHEME)) { - /* Play recording */ - RAII_VAR(struct stasis_app_stored_recording *, recording, NULL, - ao2_cleanup); - const char *relname = - playback->media + strlen(RECORDING_URI_SCHEME); - recording = stasis_app_stored_recording_find_by_name(relname); - - if (!recording) { - ast_log(LOG_ERROR, "Attempted to play recording '%s' on channel '%s' but recording does not exist", - relname, ast_channel_name(chan)); - return; - } + offsetms = playback->offsetms; - playback->controllable = 1; + for (; playback->media_index < AST_VECTOR_SIZE(&playback->medias); playback->media_index++) { - res = ast_control_streamfile_lang(chan, - stasis_app_stored_recording_get_file(recording), fwd, rev, stop, pause, - restart, playback->skipms, playback->language, &offsetms); - } else if (ast_begins_with(playback->media, NUMBER_URI_SCHEME)) { - int number; + /* Set the current media to play */ + ast_string_field_set(playback, media, AST_VECTOR_GET(&playback->medias, playback->media_index)); - if (sscanf(playback->media + strlen(NUMBER_URI_SCHEME), "%30d", &number) != 1) { - ast_log(LOG_ERROR, "Attempted to play number '%s' on channel '%s' but number is invalid", - playback->media + strlen(NUMBER_URI_SCHEME), ast_channel_name(chan)); + res = playback_first_update(playback, ast_channel_uniqueid(chan)); + if (res != 0) { return; } - res = ast_say_number(chan, number, stop, playback->language, NULL); - } else if (ast_begins_with(playback->media, DIGITS_URI_SCHEME)) { - res = ast_say_digit_str(chan, playback->media + strlen(DIGITS_URI_SCHEME), - stop, playback->language); - } else if (ast_begins_with(playback->media, CHARACTERS_URI_SCHEME)) { - res = ast_say_character_str(chan, playback->media + strlen(CHARACTERS_URI_SCHEME), - stop, playback->language, AST_SAY_CASE_NONE); - } else if (ast_begins_with(playback->media, TONE_URI_SCHEME)) { - playback->controllable = 1; - res = ast_control_tone(chan, playback->media + strlen(TONE_URI_SCHEME)); - } else { - /* Play URL */ - ast_log(LOG_ERROR, "Attempted to play URI '%s' on channel '%s' but scheme is unsupported\n", - playback->media, ast_channel_name(chan)); - return; - } + if (ast_begins_with(playback->media, SOUND_URI_SCHEME)) { + playback->controllable = 1; + + /* Play sound */ + res = ast_control_streamfile_lang(chan, playback->media + strlen(SOUND_URI_SCHEME), + fwd, rev, stop, pause, restart, playback->skipms, playback->language, + &offsetms); + } else if (ast_begins_with(playback->media, RECORDING_URI_SCHEME)) { + /* Play recording */ + RAII_VAR(struct stasis_app_stored_recording *, recording, NULL, + ao2_cleanup); + const char *relname = + playback->media + strlen(RECORDING_URI_SCHEME); + recording = stasis_app_stored_recording_find_by_name(relname); + + if (!recording) { + ast_log(LOG_ERROR, "Attempted to play recording '%s' on channel '%s' but recording does not exist", + relname, ast_channel_name(chan)); + continue; + } + + playback->controllable = 1; + + res = ast_control_streamfile_lang(chan, + stasis_app_stored_recording_get_file(recording), fwd, rev, stop, pause, + restart, playback->skipms, playback->language, &offsetms); + } else if (ast_begins_with(playback->media, NUMBER_URI_SCHEME)) { + int number; + + if (sscanf(playback->media + strlen(NUMBER_URI_SCHEME), "%30d", &number) != 1) { + ast_log(LOG_ERROR, "Attempted to play number '%s' on channel '%s' but number is invalid", + playback->media + strlen(NUMBER_URI_SCHEME), ast_channel_name(chan)); + continue; + } + + res = ast_say_number(chan, number, stop, playback->language, NULL); + } else if (ast_begins_with(playback->media, DIGITS_URI_SCHEME)) { + res = ast_say_digit_str(chan, playback->media + strlen(DIGITS_URI_SCHEME), + stop, playback->language); + } else if (ast_begins_with(playback->media, CHARACTERS_URI_SCHEME)) { + res = ast_say_character_str(chan, playback->media + strlen(CHARACTERS_URI_SCHEME), + stop, playback->language, AST_SAY_CASE_NONE); + } else if (ast_begins_with(playback->media, TONE_URI_SCHEME)) { + playback->controllable = 1; + res = ast_control_tone(chan, playback->media + strlen(TONE_URI_SCHEME)); + } else { + /* Play URL */ + ast_log(LOG_ERROR, "Attempted to play URI '%s' on channel '%s' but scheme is unsupported\n", + playback->media, ast_channel_name(chan)); + continue; + } - playback_final_update(playback, offsetms, res, - ast_channel_uniqueid(chan)); + playback_final_update(playback, offsetms, res, + ast_channel_uniqueid(chan)); + /* Reset offset for any subsequent media */ + offsetms = 0; + } return; } @@ -431,30 +465,45 @@ static void set_target_uri( } struct stasis_app_playback *stasis_app_control_play_uri( - struct stasis_app_control *control, const char *uri, - const char *language, const char *target_id, + struct stasis_app_control *control, const char **media, + size_t media_count, const char *language, const char *target_id, enum stasis_app_playback_target_type target_type, int skipms, long offsetms, const char *id) { struct stasis_app_playback *playback; + size_t i; - if (skipms < 0 || offsetms < 0) { + if (skipms < 0 || offsetms < 0 || media_count == 0) { return NULL; } - ast_debug(3, "%s: Sending play(%s) command\n", - stasis_app_control_get_channel_id(control), uri); - playback = playback_create(control, id); if (!playback) { return NULL; } + for (i = 0; i < media_count; i++) { + char *media_uri; + + media_uri = ast_malloc(strlen(media[i]) + 1); + if (!media_uri) { + ao2_ref(playback, -1); + return NULL; + } + + ast_debug(3, "%s: Sending play(%s) command\n", + stasis_app_control_get_channel_id(control), media[i]); + + /* safe */ + strcpy(media_uri, media[i]); + AST_VECTOR_APPEND(&playback->medias, media_uri); + } + if (skipms == 0) { skipms = PLAYBACK_DEFAULT_SKIPMS; } - ast_string_field_set(playback, media, uri); + ast_string_field_set(playback, media, AST_VECTOR_GET(&playback->medias, 0)); ast_string_field_set(playback, language, language); set_target_uri(playback, target_type, target_id); playback->skipms = skipms; @@ -497,12 +546,22 @@ struct ast_json *stasis_app_playback_to_json( return NULL; } - json = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", - "id", playback->id, - "media_uri", playback->media, - "target_uri", playback->target, - "language", playback->language, - "state", state_to_string(playback->state)); + if (playback->media_index == AST_VECTOR_SIZE(&playback->medias) - 1) { + json = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", + "id", playback->id, + "media_uri", playback->media, + "target_uri", playback->target, + "language", playback->language, + "state", state_to_string(playback->state)); + } else { + json = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s}", + "id", playback->id, + "media_uri", playback->media, + "next_media_uri", AST_VECTOR_GET(&playback->medias, playback->media_index + 1), + "target_uri", playback->target, + "language", playback->language, + "state", state_to_string(playback->state)); + } return ast_json_ref(json); } @@ -615,6 +674,13 @@ playback_opreation_cb operations[STASIS_PLAYBACK_STATE_MAX][STASIS_PLAYBACK_MEDI [STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_REVERSE] = playback_reverse, [STASIS_PLAYBACK_STATE_PLAYING][STASIS_PLAYBACK_FORWARD] = playback_forward, + [STASIS_PLAYBACK_STATE_CONTINUING][STASIS_PLAYBACK_STOP] = playback_stop, + [STASIS_PLAYBACK_STATE_CONTINUING][STASIS_PLAYBACK_RESTART] = playback_restart, + [STASIS_PLAYBACK_STATE_CONTINUING][STASIS_PLAYBACK_PAUSE] = playback_pause, + [STASIS_PLAYBACK_STATE_CONTINUING][STASIS_PLAYBACK_UNPAUSE] = playback_noop, + [STASIS_PLAYBACK_STATE_CONTINUING][STASIS_PLAYBACK_REVERSE] = playback_reverse, + [STASIS_PLAYBACK_STATE_CONTINUING][STASIS_PLAYBACK_FORWARD] = playback_forward, + [STASIS_PLAYBACK_STATE_PAUSED][STASIS_PLAYBACK_STOP] = playback_stop, [STASIS_PLAYBACK_STATE_PAUSED][STASIS_PLAYBACK_PAUSE] = playback_noop, [STASIS_PLAYBACK_STATE_PAUSED][STASIS_PLAYBACK_UNPAUSE] = playback_unpause, diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json index b608be6d6b5..ab2c6c2d545 100644 --- a/rest-api/api-docs/bridges.json +++ b/rest-api/api-docs/bridges.json @@ -328,10 +328,10 @@ }, { "name": "media", - "description": "Media's URI to play.", + "description": "Media URIs to play.", "paramType": "query", "required": true, - "allowMultiple": false, + "allowMultiple": true, "dataType": "string" }, { @@ -344,7 +344,7 @@ }, { "name": "offsetms", - "description": "Number of media to skip before playing.", + "description": "Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified.", "paramType": "query", "required": false, "allowMultiple": false, @@ -420,10 +420,10 @@ }, { "name": "media", - "description": "Media's URI to play.", + "description": "Media URIs to play.", "paramType": "query", "required": true, - "allowMultiple": false, + "allowMultiple": true, "dataType": "string" }, { @@ -436,7 +436,7 @@ }, { "name": "offsetms", - "description": "Number of media to skip before playing.", + "description": "Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified.", "paramType": "query", "required": false, "allowMultiple": false, diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index 2389f7cb981..aafd231a1f3 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -973,10 +973,10 @@ }, { "name": "media", - "description": "Media's URI to play.", + "description": "Media URIs to play.", "paramType": "query", "required": true, - "allowMultiple": false, + "allowMultiple": true, "dataType": "string" }, { @@ -989,7 +989,7 @@ }, { "name": "offsetms", - "description": "Number of media to skip before playing.", + "description": "Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified.", "paramType": "query", "required": false, "allowMultiple": false, @@ -1055,10 +1055,10 @@ }, { "name": "media", - "description": "Media's URI to play.", + "description": "Media URIs to play.", "paramType": "query", "required": true, - "allowMultiple": false, + "allowMultiple": true, "dataType": "string" }, { @@ -1071,7 +1071,7 @@ }, { "name": "offsetms", - "description": "Number of media to skip before playing.", + "description": "Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified.", "paramType": "query", "required": false, "allowMultiple": false, diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json index dee7c2db934..ca26161017a 100644 --- a/rest-api/api-docs/events.json +++ b/rest-api/api-docs/events.json @@ -146,6 +146,7 @@ "subTypes": [ "DeviceStateChanged", "PlaybackStarted", + "PlaybackContinuing", "PlaybackFinished", "RecordingStarted", "RecordingFinished", @@ -270,6 +271,17 @@ } } }, + "PlaybackContinuing": { + "id": "PlaybackContinuing", + "description": "Event showing the continuation of a media playback operation from one media URI to the next in the list.", + "properties": { + "playback": { + "type": "Playback", + "description": "Playback control object", + "required": true + } + } + }, "PlaybackFinished": { "id": "PlaybackFinished", "description": "Event showing the completion of a media playback operation.", diff --git a/rest-api/api-docs/playbacks.json b/rest-api/api-docs/playbacks.json index 63df3f24b48..9f90035588c 100644 --- a/rest-api/api-docs/playbacks.json +++ b/rest-api/api-docs/playbacks.json @@ -124,9 +124,14 @@ }, "media_uri": { "type": "string", - "description": "URI for the media to play back.", + "description": "The URI for the media currently being played back.", "required": true }, + "next_media_uri": { + "type": "string", + "description": "If a list of URIs is being played, the next media URI to be played back.", + "required": false + }, "target_uri": { "type": "string", "description": "URI for the channel or bridge to play the media on", @@ -145,7 +150,8 @@ "values": [ "queued", "playing", - "complete" + "continuing", + "done" ] } } From 52148d93f4f672433a28f0f60cca9f20055a8c5c Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sun, 15 May 2016 12:22:42 -0500 Subject: [PATCH 0440/1578] CHANGES: Update formatting of items * Provide consistent indenting of lines in bulleted paragraphs * Respect the 80 character column width * Group all like items together, e.g., all dialplan applications under "Applications", etc. * Use a single blank line to break up functionality changes within a larger section * Use two blanks lines to delineate larger sections Change-Id: I0488554f5cb7c51da70003d69288a21c9aab9647 --- CHANGES | 90 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/CHANGES b/CHANGES index 15b4d0c670d..9c60b2443cc 100644 --- a/CHANGES +++ b/CHANGES @@ -15,13 +15,13 @@ ARI ----------------- * A new ARI method has been added to the channels resource. "create" allows for - you to create a new channel and place that channel into a Stasis application. This - is similar to origination except that the specified channel is not dialed. This - allows for an application writer to create a channel, perform manipulations on it, - and then delay dialing the channel until later. + you to create a new channel and place that channel into a Stasis application. + This is similar to origination except that the specified channel is not + dialed. This allows for an application writer to create a channel, perform + manipulations on it, and then delay dialing the channel until later. - * To complement the "create" method, a "dial" method has been added to the channels - resource in order to place a call to a created channel. + * To complement the "create" method, a "dial" method has been added to the + channels resource in order to place a call to a created channel. * All operations that initiate playback of media on a resource now support a list of media URIs. The list of URIs are played in the order they are @@ -32,6 +32,7 @@ ARI back to the resource. The "PlaybackFinished" event is raised when all media URIs are done. + Applications ------------------ @@ -73,6 +74,17 @@ Playback provided, including the file extension. Currently, on HTTP and HTTPS URI schemes are supported. +Queue +------------------- + * Added field ReasonPause on QueueMemberStatus if set when paused, the reason + the queue member was paused. + + * Added field LastPause on QueueMemberStatus for time when started the last + pause for a queue member. + + * Show the time when started the last pause for queue member on CLI for command + 'queue show'. + SMS ------------------ * Added the 'n' option, which prevents the SMS from being written to the log @@ -80,20 +92,6 @@ SMS providers to not log SMS content. -CDRs ------------------- -cdr_odbc ------------------- - * Added a new configuration option, "newcdrcolumns", which enables use of the - post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. - ------------------- -cdr_csv ------------------- - * Added a new configuration option, "newcdrcolumns", which enables use of the - post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. - - Channel Drivers ------------------ @@ -101,6 +99,7 @@ chan_dahdi ------------------ * The CALLERID(ani2) value for incoming calls is now populated in featdmf signaling mode. The information was previously discarded. + * Added the force_restart_unavailable_chans compatibility option. When enabled it causes Asterisk to restart the ISDN B channel if an outgoing call receives cause 44 (Requested channel not available). @@ -110,6 +109,7 @@ chan_iax2 * The iax.conf forcejitterbuffer option has been removed. It is now always forced if you set iax.conf jitterbuffer=yes. If you put a jitter buffer on a channel it will be on the channel. + * A new configuration parameters, 'calltokenexpiration', has been added that controls the duration before a call token expires. Default duration is 10 seconds. Setting this to a higher value may help in lagged networks or those @@ -120,9 +120,11 @@ chan_sip * New 'rtpbindaddr' global setting. This allows a user to define which ipaddress to bind the rtpengine to. For example, chan_sip might bind to eth0 (10.0.0.2) but rtpengine to eth1 (192.168.1.10). + * DTLS related configuration options can now be set at a general level. Enabling DTLS support, though, requires enabling it at the user or peer level. + * Added the possibility to set the From: header through the the SIP dial string (populating the fromuser/fromdomain fields), complementing the [!dnid] option for the To: header that has existed since 1.6.0 (1d6b192). @@ -132,17 +134,22 @@ chan_sip chan_pjsip ------------------ * New 'user_eq_phone' endpoint setting. This adds a 'user=phone' parameter - to the request URI and From URI if the user is determined to be a phone number. - * New 'moh_passthrough' endpoint setting. This will pass hold and unhold requests - through using SIP re-invites with sendonly and sendrecv accordingly. + to the request URI and From URI if the user is determined to be a phone + number. + + * New 'moh_passthrough' endpoint setting. This will pass hold and unhold + requests through using SIP re-invites with sendonly and sendrecv accordingly. + * Added the pjsip.conf system type disable_tcp_switch option. The option allows the user to disable switching from UDP to TCP transports described by RFC 3261 section 18.1.1. - * New 'line' and 'endpoint' options added on outbound registrations. This allows some - identifying information to be added to the Contact of the outbound registration. - If this information is present on messages received from the remote server - the message will automatically be associated with the configured endpoint on the - outbound registration. + + * New 'line' and 'endpoint' options added on outbound registrations. This + allows some identifying information to be added to the Contact of the + outbound registration. If this information is present on messages received + from the remote server the message will automatically be associated with the + configured endpoint on the outbound registration. + Core ------------------ @@ -190,6 +197,7 @@ Core context. If enabled then a hint will be automatically created with the name of the device. + Functions ------------------ @@ -208,8 +216,9 @@ CURL DTMF Features ------------------ * The transferdialattempts default value has been changed from 1 to 3. The - transferinvalidsound has been changed from "pbx-invalid" to "privacy-incorrect". - These were changed to make DTMF transfers be more user-friendly by default. + transferinvalidsound has been changed from "pbx-invalid" to + "privacy-incorrect". These were changed to make DTMF transfers be more + user-friendly by default. Resources @@ -250,6 +259,7 @@ res_pjsip_outbound_registration outbound registration, registration is retried at the given interval up to 'max_retries'. + CEL Backends ------------------ @@ -262,6 +272,7 @@ cel_pgsql configurable for cel_pgsql via the 'schema' in configuration file cel_pgsql.conf. + CDR Backends ------------------ @@ -272,15 +283,18 @@ cdr_adaptive_odbc names. This setting is configurable for cdr_adaptive_odbc via the quoted_identifiers in configuration file cdr_adaptive_odbc.conf. -Queue -------------------- - * Added field ReasonPause on QueueMemberStatus if set when paused, the reason - the queue member was paused. - * Added field LastPause on QueueMemberStatus for time when started the last - pause for a queue member. - * Show the time when started the last pause for queue member on CLI for command - 'queue show'. +cdr_odbc +------------------ + * Added a new configuration option, "newcdrcolumns", which enables use of the + post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. +cdr_csv +------------------ + * Added a new configuration option, "newcdrcolumns", which enables use of the + post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. + + +------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- ------------------------------------------------------------------------------ From 6e5e84458fe89b22e4883364aa9f66b1005f9985 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 18 May 2016 06:54:14 -0600 Subject: [PATCH 0441/1578] udptl: Don't eat sequence numbers until OK is received Scenario: Local fax -> Asterisk w/ firewall -> Provider -> Remote fax * Local fax starts rtp call to remote fax * Remote fax starts t38 call back to local fax. * Local fax sends t38 no-signal to Asterisk before sending an OK. * udptl processes the frame and increments the expected sequence number. * chan_sip drops the frame because the call isn't up so nothing goes out the external interface to open the port for incoming packets. * Local fax sends OK and Asterisk sends OK to the remote fax. * Remote fax sends t38 packets which are dropped by the firewall. * Local fax re-sends t38 no-signal with the same sequence number. * udptl drops the frame because it thinks it's a dup. * Still no outgoing packets to open the firewall. * t38 negotiation fails. The patch drops frames t38 received before udptl sequence processing when the call hasn't been answered yet. The second no-signal frame is then seen as new and is relayed out the external interface which opens the port and allows negotiation to continue. ASTERISK-26034 #close Change-Id: I11744b39748bd2ecbbe8ea84cdb4f3c5943c5af9 --- main/udptl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/main/udptl.c b/main/udptl.c index a0f533fd0cc..e543b4e8eec 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -769,6 +769,18 @@ struct ast_frame *ast_udptl_read(struct ast_udptl *udptl) return &ast_null_frame; } + /* + * If early media isn't turned on for the channel driver, it's going to + * drop this frame. By that time though, udptl has already incremented + * the expected sequence number so if the CPE re-sends, the second frame + * will be dropped as a dup even though the first frame never went through. + * So we drop the frame here if the channel isn't up. 'tag' is set by the + * channel drivers on T38_ENABLED or T38_PEER_REINVITE. + */ + if (udptl->tag == NULL) { + return &ast_null_frame; + } + if (udptl->nat) { /* Send to whoever sent to us */ if (ast_sockaddr_cmp(&udptl->them, &addr)) { From 3905997bae4096f04320d409cf1058b1dc378bda Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 3 May 2016 16:07:23 -0500 Subject: [PATCH 0442/1578] res_pjsip_outbound_publish: Add multi-user support per configuration Added a new multi_user option that when specified allows a particular configuration to be used for multiple users. It does this by replacing the user portion of the server uri with a dynamically created one. Two new API calls have been added in order to make use of the new functionality: ast_sip_publish_user_send - Sends an outgoing publish message based on the given user. If state for the user already exists it uses that, otherwise it dynamically creates new outbound publishing state for the user at that time. ast_sip_publish_user_remove - Removes all outbound publish state objects associated with the user. This essentially stops outbound publishing for the user. ASTERISK-25965 #close Change-Id: Ib88dde024cc83c916424645d4f5bb84a0fa936cc --- CHANGES | 4 + include/asterisk/res_pjsip_outbound_publish.h | 22 + res/res_pjsip_outbound_publish.c | 789 ++++++++++++------ 3 files changed, 568 insertions(+), 247 deletions(-) diff --git a/CHANGES b/CHANGES index 9c60b2443cc..628bde2ad72 100644 --- a/CHANGES +++ b/CHANGES @@ -259,6 +259,10 @@ res_pjsip_outbound_registration outbound registration, registration is retried at the given interval up to 'max_retries'. +res_pjsip_outbound_publish +------------------ + * Added a new multi_user option that when set to 'yes' allows a given configuration + to be used for multiple users. CEL Backends ------------------ diff --git a/include/asterisk/res_pjsip_outbound_publish.h b/include/asterisk/res_pjsip_outbound_publish.h index b2038f58b03..2831afb3517 100644 --- a/include/asterisk/res_pjsip_outbound_publish.h +++ b/include/asterisk/res_pjsip_outbound_publish.h @@ -184,4 +184,26 @@ void ast_sip_publish_client_remove_datastore(struct ast_sip_outbound_publish_cli int ast_sip_publish_client_send(struct ast_sip_outbound_publish_client *client, const struct ast_sip_body *body); +/*! +* \brief Send an outgoing PUBLISH message based on the user +* +* \param client The publication client to send from +* \param user The user to send to +* \param body An optional body to add to the PUBLISH +* +* \retval -1 failure +* \retval 0 success +*/ +int ast_sip_publish_client_user_send(struct ast_sip_outbound_publish_client *client, + const char *user, const struct ast_sip_body *body); + +/*! +* \brief Remove the user from the client (stopping it from publishing) +* +* \param client The publication client +* \param user The user to remove +*/ +void ast_sip_publish_client_remove(struct ast_sip_outbound_publish_client *client, + const char *user); + #endif /* RES_PJSIP_OUTBOUND_PUBLISH_H */ diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 51e8a06be6c..f37ce2305f3 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -27,6 +27,7 @@ #include #include +#include "asterisk/res_pjproject.h" #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_outbound_publish.h" #include "asterisk/module.h" @@ -94,6 +95,10 @@ pjsip.conf. As with other res_pjsip modules, this will use the first available transport of the appropriate type if unconfigured. + + Enable multi-user support + When enabled the user portion of the server uri is replaced by a dynamically created user + Must be of type 'outbound-publish'. @@ -102,6 +107,8 @@ ***/ +static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE; + /*! \brief Queued outbound publish message */ struct sip_outbound_publish_message { /*! \brief Optional body */ @@ -112,6 +119,39 @@ struct sip_outbound_publish_message { char body_contents[0]; }; +/* + * A note about some of the object types used in this module: + * + * The reason we currently have 4 separate object types that relate to configuration, + * publishing, state, and client information is due to object lifetimes and order of + * destruction dependencies. + * + * Separation of concerns is a good thing and of course it makes sense to have a + * configuration object type as well as an object type wrapper around pjsip's publishing + * client class. There also may be run time state data that needs to be tracked, so + * again having something to handle that is prudent. However, it may be tempting to think + * "why not combine the state and client object types?" Especially seeing as how they have + * a one-to-one relationship. The answer is, it's possible, but it'd make the code a bit + * more awkward. + * + * Currently this module maintains a global container of current state objects. When this + * states container is replaced, or deleted, it un-references all contained objects. Any + * state with a reference left have probably been carried over from a reload/realtime fetch. + * States not carried over are destructed and the associated client (and all its publishers) + * get unpublished. + * + * This "unpublishing" goes through a careful process of unpublishing the client, all its + * publishers, and making sure all the appropriate references are removed in a sane order. + * This process is essentially kicked off with the destruction of the state. If the state + * and client objects were to be merged, where clients became the globally tracked object + * type, this "unpublishing" process would never start because of the multiple references + * held to the client object over it's lifetime. Meaning the global tracking container + * would remove its reference to the client object when done with it, but other sources + * would still be holding a reference to it (namely the datastore and publisher(s)). + * + * Thus at this time it is easier to keep them separate. + */ + /*! \brief Outbound publish information */ struct ast_sip_outbound_publish { /*! \brief Sorcery object details */ @@ -137,30 +177,43 @@ struct ast_sip_outbound_publish { unsigned int max_auth_attempts; /*! \brief Configured authentication credentials */ struct ast_sip_auth_vector outbound_auths; + /*! \brief The publishing client is used for multiple users when true */ + unsigned int multi_user; }; -/*! \brief Outbound publish client state information (persists for lifetime that publish should exist) */ -struct ast_sip_outbound_publish_client { +struct sip_outbound_publisher { + /*! \brief The client object that 'owns' this client + + \note any potential circular reference problems are accounted + for (see publisher alloc for more information) + */ + struct ast_sip_outbound_publish_client *owner; /*! \brief Underlying publish client */ pjsip_publishc *client; /*! \brief Timer entry for refreshing publish */ pj_timer_entry timer; - /*! \brief Publisher datastores set up by handlers */ - struct ao2_container *datastores; /*! \brief The number of auth attempts done */ unsigned int auth_attempts; /*! \brief Queue of outgoing publish messages to send*/ AST_LIST_HEAD_NOLOCK(, sip_outbound_publish_message) queue; /*! \brief The message currently being sent */ struct sip_outbound_publish_message *sending; - /*! \brief Publish client has been fully started and event type informed */ - unsigned int started; /*! \brief Publish client should be destroyed */ unsigned int destroy; + /*! \brief User, if any, associated with the publisher */ + char user[0]; +}; + +/*! \brief Outbound publish client state information (persists for lifetime of a publish) */ +struct ast_sip_outbound_publish_client { /*! \brief Outbound publish information */ struct ast_sip_outbound_publish *publish; - /*! \brief The name of the transport to be used for the publish */ - char *transport_name; + /*! \brief Publisher datastores set up by handlers */ + struct ao2_container *datastores; + /*! \brief Container of all the client publishing objects */ + struct ao2_container *publishers; + /*! \brief Publishing has been fully started and event type informed */ + unsigned int started; }; /*! \brief Outbound publish state information (persists for lifetime of a publish) */ @@ -171,6 +224,20 @@ struct ast_sip_outbound_publish_state { char id[0]; }; +/*! + * \brief Used for locking while loading/reloading + * + * Mutli-user configurations make it so publishers can be dynamically added and + * removed. Publishers should not be added or removed during a [re]load since + * it could cause the current_clients container to be out of sync. Thus the + * reason for this lock. + */ +AST_RWLOCK_DEFINE_STATIC(load_lock); + +#define DEFAULT_PUBLISHER_BUCKETS 119 +AO2_STRING_FIELD_HASH_FN(sip_outbound_publisher, user); +AO2_STRING_FIELD_CMP_FN(sip_outbound_publisher, user); + /*! \brief Unloading data */ struct unloading_data { int is_unloading; @@ -238,6 +305,7 @@ static int outbound_publish_state_cmp(void *obj, void *arg, int flags) static struct ao2_container *get_publishes_and_update_state(void) { struct ao2_container *container; + SCOPED_WRLOCK(lock, &load_lock); container = ast_sorcery_retrieve_by_fields( ast_sip_get_sorcery(), "outbound-publish", @@ -274,22 +342,22 @@ static struct ast_sip_event_publisher_handler *find_publisher_handler_for_event_ return iter; } -/*! \brief Helper function which cancels the refresh timer on a client */ -static void cancel_publish_refresh(struct ast_sip_outbound_publish_client *client) +/*! \brief Helper function which cancels the refresh timer on a publisher */ +static void cancel_publish_refresh(struct sip_outbound_publisher *publisher) { - if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client->timer)) { - /* The timer was successfully cancelled, drop the refcount of the client */ - ao2_ref(client, -1); + if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &publisher->timer)) { + /* The timer was successfully cancelled, drop the refcount of the publisher */ + ao2_ref(publisher, -1); } } /*! \brief Helper function which sets up the timer to send publication */ -static void schedule_publish_refresh(struct ast_sip_outbound_publish_client *client, int expiration) +static void schedule_publish_refresh(struct sip_outbound_publisher *publisher, int expiration) { - struct ast_sip_outbound_publish *publish = ao2_bump(client->publish); + struct ast_sip_outbound_publish *publish = ao2_bump(publisher->owner->publish); pj_time_val delay = { .sec = 0, }; - cancel_publish_refresh(client); + cancel_publish_refresh(publisher); if (expiration > 0) { delay.sec = expiration - PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH; @@ -301,61 +369,83 @@ static void schedule_publish_refresh(struct ast_sip_outbound_publish_client *cli delay.sec = PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH; } - ao2_ref(client, +1); - if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client->timer, &delay) != PJ_SUCCESS) { + ao2_ref(publisher, +1); + if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &publisher->timer, &delay) != PJ_SUCCESS) { ast_log(LOG_WARNING, "Failed to pass timed publish refresh to scheduler\n"); - ao2_ref(client, -1); + ao2_ref(publisher, -1); } ao2_ref(publish, -1); } +static int publisher_client_send(void *obj, void *arg, void *data, int flags); + /*! \brief Publish client timer callback function */ static void sip_outbound_publish_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry) { - struct ast_sip_outbound_publish_client *client = entry->user_data; + struct sip_outbound_publisher *publisher = entry->user_data; - ao2_lock(client); - if (AST_LIST_EMPTY(&client->queue)) { + ao2_lock(publisher); + if (AST_LIST_EMPTY(&publisher->queue)) { + int res; /* If there are no outstanding messages send an empty PUBLISH message so our publication doesn't expire */ - ast_sip_publish_client_send(client, NULL); + publisher_client_send(publisher, NULL, &res, 0); } - ao2_unlock(client); + ao2_unlock(publisher); - ao2_ref(client, -1); + ao2_ref(publisher, -1); } /*! \brief Task for cancelling a refresh timer */ static int cancel_refresh_timer_task(void *data) { - struct ast_sip_outbound_publish_client *client = data; + struct sip_outbound_publisher *publisher = data; - cancel_publish_refresh(client); - ao2_ref(client, -1); + cancel_publish_refresh(publisher); + ao2_ref(publisher, -1); return 0; } +static void set_transport(struct sip_outbound_publisher *publisher, pjsip_tx_data *tdata) +{ + if (!ast_strlen_zero(publisher->owner->publish->transport)) { + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; + ast_sip_set_tpselector_from_transport_name( + publisher->owner->publish->transport, &selector); + pjsip_tx_data_set_transport(tdata, &selector); + } +} + /*! \brief Task for sending an unpublish */ static int send_unpublish_task(void *data) { - struct ast_sip_outbound_publish_client *client = data; + struct sip_outbound_publisher *publisher = data; pjsip_tx_data *tdata; - if (pjsip_publishc_unpublish(client->client, &tdata) == PJ_SUCCESS) { - if (!ast_strlen_zero(client->transport_name)) { - pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; - ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector); - pjsip_tx_data_set_transport(tdata, &selector); - } - - pjsip_publishc_send(client->client, tdata); + if (pjsip_publishc_unpublish(publisher->client, &tdata) == PJ_SUCCESS) { + set_transport(publisher, tdata); + pjsip_publishc_send(publisher->client, tdata); } - ao2_ref(client, -1); + ao2_ref(publisher, -1); return 0; } +static void stop_publishing(struct ast_sip_outbound_publish_client *client, + struct ast_sip_event_publisher_handler *handler) +{ + if (!handler) { + handler = find_publisher_handler_for_event_name(client->publish->event); + } + + if (handler) { + handler->stop_publishing(client); + } +} + +static int cancel_and_unpublish(void *obj, void *arg, int flags); + /*! \brief Helper function which starts or stops publish clients when applicable */ static void sip_outbound_publish_synchronize(struct ast_sip_event_publisher_handler *removed) { @@ -389,15 +479,10 @@ static void sip_outbound_publish_synchronize(struct ast_sip_event_publisher_hand } else { state->client->started = 1; } - } else if (!handler && removed && !strcmp(publish->event, removed->event_name)) { - /* If the publisher client has been started but it is going away stop it */ - removed->stop_publishing(state->client); + } else if (state->client->started && !handler && removed && !strcmp(publish->event, removed->event_name)) { + stop_publishing(state->client, removed); + ao2_callback(state->client->publishers, OBJ_NODATA, cancel_and_unpublish, NULL); state->client->started = 0; - if (ast_sip_push_task(NULL, cancel_refresh_timer_task, ao2_bump(state->client))) { - ast_log(LOG_WARNING, "Could not stop refresh timer on client '%s'\n", - ast_sorcery_object_get_id(publish)); - ao2_ref(state->client, -1); - } } ao2_ref(publish, -1); ao2_ref(state, -1); @@ -583,19 +668,19 @@ void ast_sip_publish_client_remove_datastore(struct ast_sip_outbound_publish_cli ao2_find(client->datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); } -static int sip_publish_client_service_queue(void *data) +static int sip_publisher_service_queue(void *data) { - RAII_VAR(struct ast_sip_outbound_publish_client *, client, data, ao2_cleanup); - SCOPED_AO2LOCK(lock, client); + RAII_VAR(struct sip_outbound_publisher *, publisher, data, ao2_cleanup); + SCOPED_AO2LOCK(lock, publisher); struct sip_outbound_publish_message *message; pjsip_tx_data *tdata; pj_status_t status; - if (client->destroy || client->sending || !(message = AST_LIST_FIRST(&client->queue))) { + if (publisher->destroy || publisher->sending || !(message = AST_LIST_FIRST(&publisher->queue))) { return 0; } - if (pjsip_publishc_publish(client->client, PJ_FALSE, &tdata) != PJ_SUCCESS) { + if (pjsip_publishc_publish(publisher->client, PJ_FALSE, &tdata) != PJ_SUCCESS) { goto fatal; } @@ -605,13 +690,9 @@ static int sip_publish_client_service_queue(void *data) goto fatal; } - if (!ast_strlen_zero(client->transport_name)) { - pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; - ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector); - pjsip_tx_data_set_transport(tdata, &selector); - } + set_transport(publisher, tdata); - status = pjsip_publishc_send(client->client, tdata); + status = pjsip_publishc_send(publisher->client, tdata); if (status == PJ_EBUSY) { /* We attempted to send the message but something else got there first */ goto service; @@ -619,30 +700,31 @@ static int sip_publish_client_service_queue(void *data) goto fatal; } - client->sending = message; + publisher->sending = message; return 0; fatal: - AST_LIST_REMOVE_HEAD(&client->queue, entry); + AST_LIST_REMOVE_HEAD(&publisher->queue, entry); ast_free(message); service: - if (ast_sip_push_task(NULL, sip_publish_client_service_queue, ao2_bump(client))) { - ao2_ref(client, -1); + if (ast_sip_push_task(NULL, sip_publisher_service_queue, ao2_bump(publisher))) { + ao2_ref(publisher, -1); } return -1; } -int ast_sip_publish_client_send(struct ast_sip_outbound_publish_client *client, - const struct ast_sip_body *body) +static int publisher_client_send(void *obj, void *arg, void *data, int flags) { - SCOPED_AO2LOCK(lock, client); + struct sip_outbound_publisher *publisher = obj; + const struct ast_sip_body *body = arg; struct sip_outbound_publish_message *message; size_t type_len = 0, subtype_len = 0, body_text_len = 0; - int res; + int *res = data; - if (!client->client) { + *res = -1; + if (!publisher->client) { return -1; } @@ -668,31 +750,191 @@ int ast_sip_publish_client_send(struct ast_sip_outbound_publish_client *client, message->body.body_text = strcpy(dst, body->body_text); } - AST_LIST_INSERT_TAIL(&client->queue, message, entry); + AST_LIST_INSERT_TAIL(&publisher->queue, message, entry); - res = ast_sip_push_task(NULL, sip_publish_client_service_queue, ao2_bump(client)); - if (res) { - ao2_ref(client, -1); + *res = ast_sip_push_task(NULL, sip_publisher_service_queue, ao2_bump(publisher)); + if (*res) { + ao2_ref(publisher, -1); } + return *res; +} + +int ast_sip_publish_client_send(struct ast_sip_outbound_publish_client *client, + const struct ast_sip_body *body) +{ + SCOPED_AO2LOCK(lock, client); + int res = 0; + + ao2_callback_data(client->publishers, OBJ_NODATA, + publisher_client_send, (void *)body, &res); return res; } +static int sip_outbound_publisher_set_uri( + pj_pool_t *pool, const char *uri, const char *user, pj_str_t *res_uri) +{ + pj_str_t tmp; + pjsip_uri *parsed; + pjsip_sip_uri *parsed_uri; + int size; + + pj_strdup2_with_null(pool, &tmp, uri); + if (!(parsed = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0))) { + return -1; + } + + if (!(parsed_uri = pjsip_uri_get_uri(parsed))) { + return -1; + } + + if (!ast_strlen_zero(user)) { + pj_strdup2(pool, &parsed_uri->user, user); + } + + res_uri->ptr = (char*) pj_pool_alloc(pool, pjsip_max_url_size); + if (!res_uri->ptr) { + return -1; + } + + if ((size = pjsip_uri_print(PJSIP_URI_IN_OTHER, parsed_uri, res_uri->ptr, + pjsip_max_url_size - 1)) <= 0) { + return -1; + } + res_uri->ptr[size] = '\0'; + res_uri->slen = size; + + return 0; +} + +static int sip_outbound_publisher_set_uris( + pj_pool_t *pool, struct sip_outbound_publisher *publisher, + pj_str_t *server_uri, pj_str_t *to_uri, pj_str_t *from_uri) +{ + struct ast_sip_outbound_publish *publish = publisher->owner->publish; + + if (sip_outbound_publisher_set_uri(pool, publish->server_uri, publisher->user, server_uri)) { + ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound publish '%s'\n", + publish->server_uri, ast_sorcery_object_get_id(publish)); + return -1; + } + + if (ast_strlen_zero(publish->to_uri)) { + to_uri->ptr = server_uri->ptr; + to_uri->slen = server_uri->slen; + } else if (sip_outbound_publisher_set_uri(pool, publish->to_uri, publisher->user, to_uri)) { + ast_log(LOG_ERROR, "Invalid to URI '%s' specified on outbound publish '%s'\n", + publish->to_uri, ast_sorcery_object_get_id(publish)); + return -1; + } + + if (ast_strlen_zero(publish->from_uri)) { + from_uri->ptr = server_uri->ptr; + from_uri->slen = server_uri->slen; + } else if (sip_outbound_publisher_set_uri(pool, publish->from_uri, publisher->user, from_uri)) { + ast_log(LOG_ERROR, "Invalid from URI '%s' specified on outbound publish '%s'\n", + publish->from_uri, ast_sorcery_object_get_id(publish)); + return -1; + } + + return 0; +} + +static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param); + +/*! \brief Helper function that allocates a pjsip publish client and configures it */ +static int sip_outbound_publisher_init(void *data) +{ + struct sip_outbound_publisher *publisher = data; + RAII_VAR(struct ast_sip_outbound_publish *, publish, NULL, ao2_cleanup); + pjsip_publishc_opt opt = { + .queue_request = PJ_FALSE, + }; + pj_pool_t *pool; + pj_str_t event, server_uri, to_uri, from_uri; + + if (publisher->client) { + return 0; + } + + if (pjsip_publishc_create(ast_sip_get_pjsip_endpoint(), &opt, + ao2_bump(publisher), sip_outbound_publish_callback, + &publisher->client) != PJ_SUCCESS) { + ao2_ref(publisher, -1); + return -1; + } + + publish = ao2_bump(publisher->owner->publish); + + if (!ast_strlen_zero(publish->outbound_proxy)) { + pjsip_route_hdr route_set, *route; + static const pj_str_t ROUTE_HNAME = { "Route", 5 }; + + pj_list_init(&route_set); + + if (!(route = pjsip_parse_hdr(pjsip_publishc_get_pool(publisher->client), &ROUTE_HNAME, + (char*)publish->outbound_proxy, strlen(publish->outbound_proxy), NULL))) { + pjsip_publishc_destroy(publisher->client); + return -1; + } + pj_list_insert_nodes_before(&route_set, route); + + pjsip_publishc_set_route_set(publisher->client, &route_set); + } + + pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", + pjsip_max_url_size, pjsip_max_url_size); + if (!pool) { + ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound publish '%s'\n", + ast_sorcery_object_get_id(publish)); + pjsip_publishc_destroy(publisher->client); + return -1; + } + + if (sip_outbound_publisher_set_uris(pool, publisher, &server_uri, &from_uri, &to_uri)) { + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + pjsip_publishc_destroy(publisher->client); + return -1; + } + + pj_cstr(&event, publish->event); + if (pjsip_publishc_init(publisher->client, &event, &server_uri, &from_uri, &to_uri, + publish->expiration != PJ_SUCCESS)) { + ast_log(LOG_ERROR, "Failed to initialize publishing client on outbound publish '%s'\n", + ast_sorcery_object_get_id(publish)); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + pjsip_publishc_destroy(publisher->client); + return -1; + } + + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + return 0; +} + +static int sip_outbound_publisher_reinit(void *obj, void *arg, int flags) +{ + return sip_outbound_publisher_init(obj); +} + +static int sip_outbound_publisher_reinit_all(void *data) +{ + ao2_callback(data, OBJ_NODATA, sip_outbound_publisher_reinit, NULL); + return 0; +} + /*! \brief Destructor function for publish client */ -static void sip_outbound_publish_client_destroy(void *obj) +static void sip_outbound_publisher_destroy(void *obj) { - struct ast_sip_outbound_publish_client *client = obj; + struct sip_outbound_publisher *publisher = obj; struct sip_outbound_publish_message *message; /* You might be tempted to think "the publish client isn't being destroyed" but it actually is - just elsewhere */ - while ((message = AST_LIST_REMOVE_HEAD(&client->queue, entry))) { + while ((message = AST_LIST_REMOVE_HEAD(&publisher->queue, entry))) { ast_free(message); } - ao2_cleanup(client->datastores); - ao2_cleanup(client->publish); - ast_free(client->transport_name); + ao2_cleanup(publisher->owner); /* if unloading the module and all objects have been unpublished send the signal to finish unloading */ @@ -705,67 +947,195 @@ static void sip_outbound_publish_client_destroy(void *obj) } } +static struct sip_outbound_publisher *sip_outbound_publisher_alloc( + struct ast_sip_outbound_publish_client *client, const char *user) +{ + struct sip_outbound_publisher *publisher; + + publisher = ao2_alloc(sizeof(*publisher) + (user ? strlen(user) : 0) + 1, + sip_outbound_publisher_destroy); + if (!publisher) { + return NULL; + } + + /* + * Bump the ref to the client. This essentially creates a circular reference, + * but it is needed in order to make sure the client object doesn't get pulled + * out from under us when the publisher stops publishing. + * + * The circular reference is alleviated by calling cancel_and_unpublish for + * each client, from the state's destructor. By calling it there all references + * to the publishers should go to zero, thus calling the publisher's destructor. + * This in turn removes the client reference we added here. The state then removes + * its reference to the client, which should take it to zero. + */ + publisher->owner = ao2_bump(client); + publisher->timer.user_data = publisher; + publisher->timer.cb = sip_outbound_publish_timer_cb; + if (user) { + strcpy(publisher->user, user); + } else { + *publisher->user = '\0'; + } + + if (ast_sip_push_task_synchronous(NULL, sip_outbound_publisher_init, publisher)) { + ast_log(LOG_ERROR, "Unable to create publisher for outbound publish '%s'\n", + ast_sorcery_object_get_id(client->publish)); + ao2_ref(publisher, -1); + return NULL; + } + + return publisher; +} + +static struct sip_outbound_publisher *sip_outbound_publish_client_add_publisher( + struct ast_sip_outbound_publish_client *client, const char *user) +{ + struct sip_outbound_publisher *publisher = + sip_outbound_publisher_alloc(client, user); + + if (!publisher) { + return NULL; + } + + if (!ao2_link(client->publishers, publisher)) { + /* + * No need to bump the reference here. The task will take care of + * removing the reference. + */ + if (ast_sip_push_task(NULL, cancel_refresh_timer_task, publisher)) { + ao2_ref(publisher, -1); + } + return NULL; + } + + return publisher; +} + +int ast_sip_publish_client_user_send(struct ast_sip_outbound_publish_client *client, + const char *user, const struct ast_sip_body *body) +{ + struct sip_outbound_publisher *publisher; + int res; + + /* + * Lock before searching since there could be a race between searching and adding. + * Just use the load_lock since we might need to lock it anyway (if adding) and + * also it simplifies the code (otherwise we'd have to lock the publishers, no- + * lock the search and pass a flag to 'add publisher to no-lock the potential link). + */ + ast_rwlock_wrlock(&load_lock); + publisher = ao2_find(client->publishers, user, OBJ_SEARCH_KEY); + if (!publisher) { + if (!(publisher = sip_outbound_publish_client_add_publisher(client, user))) { + ast_rwlock_unlock(&load_lock); + return -1; + } + } + ast_rwlock_unlock(&load_lock); + + publisher_client_send(publisher, (void *)body, &res, 0); + ao2_ref(publisher, -1); + return res; +} + +void ast_sip_publish_client_remove(struct ast_sip_outbound_publish_client *client, + const char *user) +{ + SCOPED_WRLOCK(lock, &load_lock); + ao2_find(client->publishers, user, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); +} + static int explicit_publish_destroy(void *data) { - struct ast_sip_outbound_publish_client *client = data; + struct sip_outbound_publisher *publisher = data; /* * If there is no pjsip publishing client then we obviously don't need * to destroy it. Also, the ref for the Asterisk publishing client that * pjsip had would not exist or should already be gone as well. */ - if (client->client) { - pjsip_publishc_destroy(client->client); - ao2_ref(client, -1); + if (publisher->client) { + pjsip_publishc_destroy(publisher->client); + ao2_ref(publisher, -1); } return 0; } /*! \brief Helper function which cancels and un-publishes a no longer used client */ -static int cancel_and_unpublish(struct ast_sip_outbound_publish_client *client) +static int cancel_and_unpublish(void *obj, void *arg, int flags) { - struct ast_sip_event_publisher_handler *handler; - SCOPED_AO2LOCK(lock, client); + struct sip_outbound_publisher *publisher = obj; + struct ast_sip_outbound_publish_client *client = publisher->owner; + + SCOPED_AO2LOCK(lock, publisher); if (!client->started) { - /* If the client was never started, there's nothing to unpublish, so just - * destroy the publication and remove its reference to the client. + /* If the publisher was never started, there's nothing to unpublish, so just + * destroy the publication and remove its reference to the publisher. */ - ast_sip_push_task(NULL, explicit_publish_destroy, client); + ast_sip_push_task(NULL, explicit_publish_destroy, publisher); return 0; } - handler = find_publisher_handler_for_event_name(client->publish->event); - if (handler) { - handler->stop_publishing(client); - } - - client->started = 0; - if (ast_sip_push_task(NULL, cancel_refresh_timer_task, ao2_bump(client))) { + if (ast_sip_push_task(NULL, cancel_refresh_timer_task, ao2_bump(publisher))) { ast_log(LOG_WARNING, "Could not stop refresh timer on outbound publish '%s'\n", ast_sorcery_object_get_id(client->publish)); - ao2_ref(client, -1); + ao2_ref(publisher, -1); } /* If nothing is being sent right now send the unpublish - the destroy will happen in the subsequent callback */ - if (!client->sending) { - if (ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(client))) { + if (!publisher->sending) { + if (ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(publisher))) { ast_log(LOG_WARNING, "Could not send unpublish message on outbound publish '%s'\n", ast_sorcery_object_get_id(client->publish)); - ao2_ref(client, -1); + ao2_ref(publisher, -1); } } - client->destroy = 1; + publisher->destroy = 1; return 0; } +/*! \brief Destructor function for publish client */ +static void sip_outbound_publish_client_destroy(void *obj) +{ + struct ast_sip_outbound_publish_client *client = obj; + + ao2_cleanup(client->datastores); + + /* + * The client's publishers have already been unpublished and destroyed + * by this point, so it is safe to finally remove the reference to the + * publish object. The client needed to hold a reference to it until + * the publishers were done with it. + */ + ao2_cleanup(client->publish); +} + /*! \brief Destructor function for publish state */ static void sip_outbound_publish_state_destroy(void *obj) { struct ast_sip_outbound_publish_state *state = obj; - cancel_and_unpublish(state->client); + stop_publishing(state->client, NULL); + /* + * Since the state is being destroyed the associated client needs to also + * be destroyed. However simply removing the reference to the client will + * not initiate client destruction since the client's publisher(s) hold a + * reference to the client object as well. So we need to unpublish the + * the client's publishers here, which will remove the publisher's client + * reference during that process. + * + * That being said we don't want to remove the client's reference to the + * publish object just yet. We'll hold off on that until client destruction + * itself. This is because the publishers need access to the client's + * publish object while they are unpublishing. + */ + ao2_callback(state->client->publishers, OBJ_NODATA | OBJ_UNLINK, cancel_and_unpublish, NULL); + ao2_cleanup(state->client->publishers); + + state->client->started = 0; ao2_cleanup(state->client); } @@ -799,126 +1169,31 @@ static int can_reuse_publish(struct ast_sip_outbound_publish *existing, struct a return 1; } -static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param); - -/*! \brief Helper function that allocates a pjsip publish client and configures it */ -static int sip_outbound_publish_client_alloc(void *data) -{ - struct ast_sip_outbound_publish_client *client = data; - RAII_VAR(struct ast_sip_outbound_publish *, publish, NULL, ao2_cleanup); - pjsip_publishc_opt opt = { - .queue_request = PJ_FALSE, - }; - pj_str_t event, server_uri, to_uri, from_uri; - pj_status_t status; - - if (client->client) { - return 0; - } else if (pjsip_publishc_create(ast_sip_get_pjsip_endpoint(), &opt, ao2_bump(client), sip_outbound_publish_callback, - &client->client) != PJ_SUCCESS) { - ao2_ref(client, -1); - return -1; - } - - publish = ao2_bump(client->publish); - - if (!ast_strlen_zero(publish->outbound_proxy)) { - pjsip_route_hdr route_set, *route; - static const pj_str_t ROUTE_HNAME = { "Route", 5 }; - - pj_list_init(&route_set); - - if (!(route = pjsip_parse_hdr(pjsip_publishc_get_pool(client->client), &ROUTE_HNAME, - (char*)publish->outbound_proxy, strlen(publish->outbound_proxy), NULL))) { - pjsip_publishc_destroy(client->client); - return -1; - } - pj_list_insert_nodes_before(&route_set, route); - - pjsip_publishc_set_route_set(client->client, &route_set); - } - - pj_cstr(&event, publish->event); - pj_cstr(&server_uri, publish->server_uri); - pj_cstr(&to_uri, S_OR(publish->to_uri, publish->server_uri)); - pj_cstr(&from_uri, S_OR(publish->from_uri, publish->server_uri)); - - status = pjsip_publishc_init(client->client, &event, &server_uri, &from_uri, &to_uri, - publish->expiration); - if (status == PJSIP_EINVALIDURI) { - pj_pool_t *pool; - pj_str_t tmp; - pjsip_uri *uri; - - pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256); - if (!pool) { - ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound publish '%s'\n", - ast_sorcery_object_get_id(publish)); - pjsip_publishc_destroy(client->client); - return -1; - } - - pj_strdup2_with_null(pool, &tmp, publish->server_uri); - uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0); - if (!uri) { - ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound publish '%s'\n", - publish->server_uri, ast_sorcery_object_get_id(publish)); - } - - if (!ast_strlen_zero(publish->to_uri)) { - pj_strdup2_with_null(pool, &tmp, publish->to_uri); - uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0); - if (!uri) { - ast_log(LOG_ERROR, "Invalid to URI '%s' specified on outbound publish '%s'\n", - publish->to_uri, ast_sorcery_object_get_id(publish)); - } - } - - if (!ast_strlen_zero(publish->from_uri)) { - pj_strdup2_with_null(pool, &tmp, publish->from_uri); - uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0); - if (!uri) { - ast_log(LOG_ERROR, "Invalid from URI '%s' specified on outbound publish '%s'\n", - publish->from_uri, ast_sorcery_object_get_id(publish)); - } - } - - pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); - pjsip_publishc_destroy(client->client); - return -1; - } else if (status != PJ_SUCCESS) { - pjsip_publishc_destroy(client->client); - return -1; - } - - return 0; -} - /*! \brief Callback function for publish client responses */ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) { #define DESTROY_CLIENT() do { \ - pjsip_publishc_destroy(client->client); \ - client->client = NULL; \ - ao2_ref(client, -1); } while (0) + pjsip_publishc_destroy(publisher->client); \ + publisher->client = NULL; \ + ao2_ref(publisher, -1); } while (0) - RAII_VAR(struct ast_sip_outbound_publish_client *, client, ao2_bump(param->token), ao2_cleanup); - RAII_VAR(struct ast_sip_outbound_publish *, publish, ao2_bump(client->publish), ao2_cleanup); - SCOPED_AO2LOCK(lock, client); + RAII_VAR(struct sip_outbound_publisher *, publisher, ao2_bump(param->token), ao2_cleanup); + RAII_VAR(struct ast_sip_outbound_publish *, publish, ao2_bump(publisher->owner->publish), ao2_cleanup); + SCOPED_AO2LOCK(lock, publisher); pjsip_tx_data *tdata; - if (client->destroy) { - if (client->sending) { - client->sending = NULL; + if (publisher->destroy) { + if (publisher->sending) { + publisher->sending = NULL; - if (!ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(client))) { + if (!ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(publisher))) { return; } ast_log(LOG_WARNING, "Could not send unpublish message on outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); - ao2_ref(client, -1); + ao2_ref(publisher, -1); } - /* Once the destroy is called this callback will not get called any longer, so drop the client ref */ + /* Once the destroy is called this callback will not get called any longer, so drop the publisher ref */ DESTROY_CLIENT(); return; } @@ -928,16 +1203,12 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) if (!ast_sip_create_request_with_auth(&publish->outbound_auths, param->rdata, tsx->last_tx, &tdata)) { - if (!ast_strlen_zero(client->transport_name)) { - pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; - ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector); - pjsip_tx_data_set_transport(tdata, &selector); - } - pjsip_publishc_send(client->client, tdata); + set_transport(publisher, tdata); + pjsip_publishc_send(publisher->client, tdata); } - client->auth_attempts++; + publisher->auth_attempts++; - if (client->auth_attempts == publish->max_auth_attempts) { + if (publisher->auth_attempts == publish->max_auth_attempts) { DESTROY_CLIENT(); ast_log(LOG_ERROR, "Reached maximum number of PUBLISH authentication attempts on outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); @@ -947,18 +1218,18 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) return; } - client->auth_attempts = 0; + publisher->auth_attempts = 0; if (param->code == 412) { DESTROY_CLIENT(); - if (sip_outbound_publish_client_alloc(client)) { + if (sip_outbound_publisher_init(publisher)) { ast_log(LOG_ERROR, "Failed to create a new outbound publish client for '%s' on 412 response\n", ast_sorcery_object_get_id(publish)); goto end; } /* Setting this to NULL will cause a new PUBLISH to get created and sent for the same underlying body */ - client->sending = NULL; + publisher->sending = NULL; } else if (param->code == 423) { /* Update the expiration with the new expiration time if available */ pjsip_expires_hdr *expires; @@ -971,33 +1242,33 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) goto end; } - pjsip_publishc_update_expires(client->client, expires->ivalue); - client->sending = NULL; - } else if (client->sending) { + pjsip_publishc_update_expires(publisher->client, expires->ivalue); + publisher->sending = NULL; + } else if (publisher->sending) { /* Remove the message currently being sent so that when the queue is serviced another will get sent */ - AST_LIST_REMOVE_HEAD(&client->queue, entry); - ast_free(client->sending); - client->sending = NULL; + AST_LIST_REMOVE_HEAD(&publisher->queue, entry); + ast_free(publisher->sending); + publisher->sending = NULL; if (!param->rdata) { ast_log(LOG_NOTICE, "No response received for outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); } } - if (AST_LIST_EMPTY(&client->queue)) { - schedule_publish_refresh(client, param->expiration); + if (AST_LIST_EMPTY(&publisher->queue)) { + schedule_publish_refresh(publisher, param->expiration); } end: - if (!client->client) { + if (!publisher->client) { struct sip_outbound_publish_message *message; - while ((message = AST_LIST_REMOVE_HEAD(&client->queue, entry))) { + while ((message = AST_LIST_REMOVE_HEAD(&publisher->queue, entry))) { ast_free(message); } } else { - if (ast_sip_push_task(NULL, sip_publish_client_service_queue, ao2_bump(client))) { - ao2_ref(client, -1); + if (ast_sip_push_task(NULL, sip_publisher_service_queue, ao2_bump(publisher))) { + ao2_ref(publisher, -1); } } } @@ -1085,27 +1356,18 @@ static struct ast_sip_outbound_publish_state *sip_outbound_publish_state_alloc( return NULL; } - state->client->timer.user_data = state->client; - state->client->timer.cb = sip_outbound_publish_timer_cb; - state->client->transport_name = ast_strdup(publish->transport); + state->client->publishers = ao2_container_alloc(DATASTORE_BUCKETS, sip_outbound_publisher_hash_fn, + sip_outbound_publisher_cmp_fn); + if (!state->client->publishers) { + ao2_ref(state, -1); + return NULL; + } state->client->publish = ao2_bump(publish); strcpy(state->id, id); return state; } -static int initialize_publish_client(struct ast_sip_outbound_publish *publish, - struct ast_sip_outbound_publish_state *state) -{ - if (ast_sip_push_task_synchronous(NULL, sip_outbound_publish_client_alloc, state->client)) { - ast_log(LOG_ERROR, "Unable to create client for outbound publish '%s'\n", - ast_sorcery_object_get_id(publish)); - return -1; - } - - return 0; -} - static int validate_publish_config(struct ast_sip_outbound_publish *publish) { if (ast_strlen_zero(publish->server_uri)) { @@ -1125,6 +1387,15 @@ static int current_state_reusable(struct ast_sip_outbound_publish *publish, { struct ast_sip_outbound_publish *old_publish; + /* + * Don't maintain the old state/client objects if the multi_user option changed. + */ + if ((!publish->multi_user && current_state->client->publish->multi_user) || + (publish->multi_user && !current_state->client->publish->multi_user)) { + return 0; + } + + if (!can_reuse_publish(current_state->client->publish, publish)) { /* * Something significant has changed in the configuration, so we are @@ -1140,12 +1411,15 @@ static int current_state_reusable(struct ast_sip_outbound_publish *publish, */ old_publish = current_state->client->publish; current_state->client->publish = publish; - if (initialize_publish_client(publish, current_state)) { + if (ast_sip_push_task_synchronous( + NULL, sip_outbound_publisher_reinit_all, current_state->client->publishers)) { /* * If the state object fails to re-initialize then swap * the old publish info back in. */ current_state->client->publish = publish; + ast_log(LOG_ERROR, "Unable to reinitialize client(s) for outbound publish '%s'\n", + ast_sorcery_object_get_id(current_state->client->publish)); return -1; } @@ -1170,6 +1444,7 @@ static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *o struct ast_sip_outbound_publish *applied = obj; struct ast_sip_outbound_publish_state *current_state, *new_state; + struct sip_outbound_publisher *publisher = NULL; int res; /* @@ -1216,11 +1491,13 @@ static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *o return -1; }; - if (initialize_publish_client(applied, new_state)) { + if (!applied->multi_user && + !(publisher = sip_outbound_publish_client_add_publisher(new_state->client, NULL))) { ADD_TO_NEW_STATES(current_state); ao2_ref(new_state, -1); return -1; } + ao2_cleanup(publisher); ADD_TO_NEW_STATES(new_state); ao2_cleanup(current_state); @@ -1238,6 +1515,9 @@ static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); + /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */ + ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size); + ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_publish"); ast_sorcery_apply_default(ast_sip_get_sorcery(), "outbound-publish", "config", "pjsip.conf,criteria=type=outbound-publish"); @@ -1257,6 +1537,7 @@ static int load_module(void) ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "max_auth_attempts", "5", OPT_UINT_T, 0, FLDSET(struct ast_sip_outbound_publish, max_auth_attempts)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, transport)); ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "outbound-publish", "outbound_auth", "", outbound_auth_handler, NULL, NULL, 0, 0); + ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "multi_user", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_outbound_publish, multi_user)); ast_sorcery_reload_object(ast_sip_get_sorcery(), "outbound-publish"); @@ -1279,6 +1560,13 @@ static int reload_module(void) return 0; } +static int current_publishing_count(void *obj, void *arg, int flags) +{ + struct ast_sip_outbound_publish_state *state = obj; + unloading.count += ao2_container_count(state->client->publishers); + return 0; +} + static int unload_module(void) { struct timeval start = ast_tvnow(); @@ -1289,11 +1577,18 @@ static int unload_module(void) int res = 0; struct ao2_container *states = ao2_global_obj_ref(current_states); - if (!states || !(unloading.count = ao2_container_count(states))) { + if (!states) { return 0; } + + unloading.count = 0; + ao2_callback(states, OBJ_NODATA, current_publishing_count, NULL); ao2_ref(states, -1); + if (!unloading.count) { + return 0; + } + ast_mutex_init(&unloading.lock); ast_cond_init(&unloading.cond, NULL); ast_mutex_lock(&unloading.lock); From d4b77dad1b0154eb3b89133d941dd8d624deda54 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 10 May 2016 13:28:04 -0300 Subject: [PATCH 0443/1578] res_pjsip_exten_state: Use the extension for publishing to. This change uses the newly added multi-user support for outbound publish to publish to the specific user that an extension state change is for. This also extends the res_pjsip_outbound_publish support to include the user specific From and To URI information in the outbound publishing of extension state. Since the URI is used when constructing the body it is important to ensure that the correct local and remote URIs are used. Finally the max string growths for the dialog-info+xml body generator has been increased as through testing it has proven to be too conservative. ASTERISK-25965 Change-Id: I668fdf697b1e171d4c7e6f282b2e1590f8356ca1 --- include/asterisk/res_pjsip_outbound_publish.h | 30 ++++++ res/res_pjsip_dialog_info_body_generator.c | 2 +- res/res_pjsip_exten_state.c | 10 +- res/res_pjsip_outbound_publish.c | 91 ++++++++++++++++--- 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/include/asterisk/res_pjsip_outbound_publish.h b/include/asterisk/res_pjsip_outbound_publish.h index 2831afb3517..a578b5aece2 100644 --- a/include/asterisk/res_pjsip_outbound_publish.h +++ b/include/asterisk/res_pjsip_outbound_publish.h @@ -103,6 +103,21 @@ struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *n */ const char *ast_sip_publish_client_get_from_uri(struct ast_sip_outbound_publish_client *client); +/*! + * \brief Get the From URI the client will use for a specific user. + * \since 14.0.0 + * + * \param client The publication client to get the From URI of a user + * \param user The user to retrieve the From URI for + * \param uri A buffer to place the URI into + * \param size The size of the buffer + * + * \retval From-uri on success + * \retval Empty-string on failure + */ +const char *ast_sip_publish_client_get_user_from_uri(struct ast_sip_outbound_publish_client *client, const char *user, + char *uri, size_t size); + /*! * \brief Get the To URI the client will use. * \since 14.0.0 @@ -114,6 +129,21 @@ const char *ast_sip_publish_client_get_from_uri(struct ast_sip_outbound_publish_ */ const char *ast_sip_publish_client_get_to_uri(struct ast_sip_outbound_publish_client *client); +/*! + * \brief Get the To URI the client will use for a specific user. + * \since 14.0.0 + * + * \param client The publication client to get the To URI of a user + * \param user The user to retrieve the To URI for + * \param uri A buffer to place the URI into + * \param size The size of the buffer + * + * \retval To-uri on success + * \retval Empty-string on failure + */ +const char *ast_sip_publish_client_get_user_to_uri(struct ast_sip_outbound_publish_client *client, const char *user, + char *uri, size_t size); + /*! * \brief Alternative for ast_datastore_alloc() * diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c index d21af2ae61c..5006b9efb4e 100644 --- a/res/res_pjsip_dialog_info_body_generator.c +++ b/res/res_pjsip_dialog_info_body_generator.c @@ -157,7 +157,7 @@ static int dialog_info_generate_body_content(void *body, void *data) /* The maximum number of times the ast_str() for the body text can grow before we declare an XML body * too large to send. */ -#define MAX_STRING_GROWTHS 3 +#define MAX_STRING_GROWTHS 6 static void dialog_info_to_string(void *body, struct ast_str **str) { diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 22fb69c29a5..25b9bf1fe84 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -647,21 +647,21 @@ static int exten_state_publisher_cb(void *data) publisher = AST_VECTOR_GET(&pub_data->pubs, idx); - uri = ast_sip_publish_client_get_from_uri(publisher->client); + uri = ast_sip_publish_client_get_user_from_uri(publisher->client, pub_data->exten_state_data.exten, + pub_data->exten_state_data.local, sizeof(pub_data->exten_state_data.local)); if (ast_strlen_zero(uri)) { ast_log(LOG_WARNING, "PUBLISH client '%s' has no from_uri or server_uri defined.\n", publisher->name); continue; } - ast_copy_string(pub_data->exten_state_data.local, uri, sizeof(pub_data->exten_state_data.local)); - uri = ast_sip_publish_client_get_to_uri(publisher->client); + uri = ast_sip_publish_client_get_user_to_uri(publisher->client, pub_data->exten_state_data.exten, + pub_data->exten_state_data.remote, sizeof(pub_data->exten_state_data.remote)); if (ast_strlen_zero(uri)) { ast_log(LOG_WARNING, "PUBLISH client '%s' has no to_uri or server_uri defined.\n", publisher->name); continue; } - ast_copy_string(pub_data->exten_state_data.remote, uri, sizeof(pub_data->exten_state_data.remote)); pub_data->exten_state_data.datastores = publisher->datastores; @@ -678,7 +678,7 @@ static int exten_state_publisher_cb(void *data) body.type = publisher->body_type; body.subtype = publisher->body_subtype; body.body_text = ast_str_buffer(body_text); - ast_sip_publish_client_send(publisher->client, &body); + ast_sip_publish_client_user_send(publisher->client, pub_data->exten_state_data.exten, &body); } pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index f37ce2305f3..1c3b0c6444d 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -190,6 +190,10 @@ struct sip_outbound_publisher { struct ast_sip_outbound_publish_client *owner; /*! \brief Underlying publish client */ pjsip_publishc *client; + /*! \brief The From URI for this specific publisher */ + char *from_uri; + /*! \brief The To URI for this specific publisher */ + char *to_uri; /*! \brief Timer entry for refreshing publish */ pj_timer_entry timer; /*! \brief The number of auth attempts done */ @@ -525,6 +529,49 @@ const char *ast_sip_publish_client_get_from_uri(struct ast_sip_outbound_publish_ return S_OR(publish->from_uri, S_OR(publish->server_uri, "")); } +static struct sip_outbound_publisher *sip_outbound_publish_client_add_publisher( + struct ast_sip_outbound_publish_client *client, const char *user); + +static struct sip_outbound_publisher *sip_outbound_publish_client_get_publisher( + struct ast_sip_outbound_publish_client *client, const char *user) +{ + struct sip_outbound_publisher *publisher; + + /* + * Lock before searching since there could be a race between searching and adding. + * Just use the load_lock since we might need to lock it anyway (if adding) and + * also it simplifies the code (otherwise we'd have to lock the publishers, no- + * lock the search and pass a flag to 'add publisher to no-lock the potential link). + */ + ast_rwlock_wrlock(&load_lock); + publisher = ao2_find(client->publishers, user, OBJ_SEARCH_KEY); + if (!publisher) { + if (!(publisher = sip_outbound_publish_client_add_publisher(client, user))) { + ast_rwlock_unlock(&load_lock); + return NULL; + } + } + ast_rwlock_unlock(&load_lock); + + return publisher; +} + +const char *ast_sip_publish_client_get_user_from_uri(struct ast_sip_outbound_publish_client *client, const char *user, + char *uri, size_t size) +{ + struct sip_outbound_publisher *publisher; + + publisher = sip_outbound_publish_client_get_publisher(client, user); + if (!publisher) { + return NULL; + } + + ast_copy_string(uri, publisher->from_uri, size); + ao2_ref(publisher, -1); + + return uri; +} + const char *ast_sip_publish_client_get_to_uri(struct ast_sip_outbound_publish_client *client) { struct ast_sip_outbound_publish *publish = client->publish; @@ -532,6 +579,22 @@ const char *ast_sip_publish_client_get_to_uri(struct ast_sip_outbound_publish_cl return S_OR(publish->to_uri, S_OR(publish->server_uri, "")); } +const char *ast_sip_publish_client_get_user_to_uri(struct ast_sip_outbound_publish_client *client, const char *user, + char *uri, size_t size) +{ + struct sip_outbound_publisher *publisher; + + publisher = sip_outbound_publish_client_get_publisher(client, user); + if (!publisher) { + return NULL; + } + + ast_copy_string(uri, publisher->to_uri, size); + ao2_ref(publisher, -1); + + return uri; +} + int ast_sip_register_event_publisher_handler(struct ast_sip_event_publisher_handler *handler) { struct ast_sip_event_publisher_handler *existing; @@ -828,6 +891,11 @@ static int sip_outbound_publisher_set_uris( return -1; } + publisher->to_uri = ast_strdup(to_uri->ptr); + if (!publisher->to_uri) { + return -1; + } + if (ast_strlen_zero(publish->from_uri)) { from_uri->ptr = server_uri->ptr; from_uri->slen = server_uri->slen; @@ -837,6 +905,11 @@ static int sip_outbound_publisher_set_uris( return -1; } + publisher->from_uri = ast_strdup(from_uri->ptr); + if (!publisher->from_uri) { + return -1; + } + return 0; } @@ -936,6 +1009,9 @@ static void sip_outbound_publisher_destroy(void *obj) ao2_cleanup(publisher->owner); + ast_free(publisher->from_uri); + ast_free(publisher->to_uri); + /* if unloading the module and all objects have been unpublished send the signal to finish unloading */ if (unloading.is_unloading) { @@ -1018,21 +1094,10 @@ int ast_sip_publish_client_user_send(struct ast_sip_outbound_publish_client *cli struct sip_outbound_publisher *publisher; int res; - /* - * Lock before searching since there could be a race between searching and adding. - * Just use the load_lock since we might need to lock it anyway (if adding) and - * also it simplifies the code (otherwise we'd have to lock the publishers, no- - * lock the search and pass a flag to 'add publisher to no-lock the potential link). - */ - ast_rwlock_wrlock(&load_lock); - publisher = ao2_find(client->publishers, user, OBJ_SEARCH_KEY); + publisher = sip_outbound_publish_client_get_publisher(client, user); if (!publisher) { - if (!(publisher = sip_outbound_publish_client_add_publisher(client, user))) { - ast_rwlock_unlock(&load_lock); - return -1; - } + return -1; } - ast_rwlock_unlock(&load_lock); publisher_client_send(publisher, (void *)body, &res, 0); ao2_ref(publisher, -1); From 111c4b03241f29cb80292570fb4d1c261e3d1adb Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Wed, 18 May 2016 18:58:20 +0300 Subject: [PATCH 0444/1578] Makefile: remove OSARCH check for init install There are more specific checks for the platform. Specifically this allows installing OS/X init scripts. ASTERISK-26038 #close Change-Id: If08933621145b10362a0cfe73c079301d9c13f50 Signed-off-by: Tzafrir Cohen --- Makefile | 102 ++++++++++++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/Makefile b/Makefile index 7528f83749e..b988c8ff625 100644 --- a/Makefile +++ b/Makefile @@ -824,60 +824,56 @@ install-logrotate: rm -f contrib/scripts/asterisk.logrotate.tmp config: - @if [ "${OSARCH}" = "linux-gnu" -o "${OSARCH}" = "kfreebsd-gnu" ]; then \ - if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ - ./build_tools/install_subst contrib/init.d/rc.redhat.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ - if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/chkconfig --add asterisk ; \ - fi ; \ - elif [ -f /etc/debian_version ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.debian.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - if [ ! -f "$(DESTDIR)/etc/default/asterisk" ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/default/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /usr/sbin/update-rc.d asterisk defaults 50 91 ; \ - fi ; \ - elif [ -f /etc/gentoo-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.gentoo.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/rc-update add asterisk default ; \ - fi ; \ - elif [ -f /etc/mandrake-release -o -f /etc/mandriva-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.mandriva.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ - if [ ! -f /etc/sysconfig/asterisk ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/chkconfig --add asterisk ; \ - fi ; \ - elif [ -f /etc/SuSE-release -o -f /etc/novell-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.suse.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - if [ ! -f /etc/sysconfig/asterisk ] ; then \ - $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ - fi ; \ - if [ -z "$(DESTDIR)" ] ; then \ - /sbin/chkconfig --add asterisk ; \ - fi ; \ - elif [ -f /etc/arch-release -o -f /etc/arch-release ] ; then \ - ./build_tools/install_subst contrib/init.d/rc.archlinux.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ - elif [ -d "$(DESTDIR)/Library/LaunchDaemons" ]; then \ - if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist" ]; then \ - ./build_tools/install_subst contrib/init.d/org.asterisk.asterisk.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist"; \ - fi; \ - if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist" ]; then \ - ./build_tools/install_subst contrib/init.d/org.asterisk.muted.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist"; \ - fi; \ - elif [ -f /etc/slackware-version ]; then \ - echo "Slackware is not currently supported, although an init script does exist for it."; \ - else \ - echo "We could not install init scripts for your distribution." ; \ - fi \ + if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ + ./build_tools/install_subst contrib/init.d/rc.redhat.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ + if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/chkconfig --add asterisk ; \ + fi ; \ + elif [ -f /etc/debian_version ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.debian.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + if [ ! -f "$(DESTDIR)/etc/default/asterisk" ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/default/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /usr/sbin/update-rc.d asterisk defaults 50 91 ; \ + fi ; \ + elif [ -f /etc/gentoo-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.gentoo.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/rc-update add asterisk default ; \ + fi ; \ + elif [ -f /etc/mandrake-release -o -f /etc/mandriva-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.mandriva.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ + if [ ! -f /etc/sysconfig/asterisk ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/chkconfig --add asterisk ; \ + fi ; \ + elif [ -f /etc/SuSE-release -o -f /etc/novell-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.suse.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + if [ ! -f /etc/sysconfig/asterisk ] ; then \ + $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ + fi ; \ + if [ -z "$(DESTDIR)" ] ; then \ + /sbin/chkconfig --add asterisk ; \ + fi ; \ + elif [ -f /etc/arch-release -o -f /etc/arch-release ] ; then \ + ./build_tools/install_subst contrib/init.d/rc.archlinux.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \ + elif [ -d "$(DESTDIR)/Library/LaunchDaemons" ]; then \ + if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist" ]; then \ + ./build_tools/install_subst contrib/init.d/org.asterisk.asterisk.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist"; \ + fi; \ + if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist" ]; then \ + ./build_tools/install_subst contrib/init.d/org.asterisk.muted.plist "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.muted.plist"; \ + fi; \ + elif [ -f /etc/slackware-version ]; then \ + echo "Slackware is not currently supported, although an init script does exist for it."; \ else \ - echo "We could not install init scripts for your operating system." ; \ + echo "We could not install init scripts for your distribution." ; \ fi sounds: From 9766a12b4c5a0b7bd5d01dcd63a4bbd3b9c68f54 Mon Sep 17 00:00:00 2001 From: snuffy Date: Tue, 10 May 2016 12:40:08 +1000 Subject: [PATCH 0445/1578] res_pjsip_empty_info: Respond to empty SIP INFO packets Some SBCs require responses to empty SIP INFO packets after establishing call via INVITE, if not responded to they may drop your call after unspecified timeout of X minutes. They are identified by having no Content-Type, check for this and respond with 200 - OK message. ASTERISK-24986 #close Reported-by: Ilya Trikoz, Federico Santulli Change-Id: Ib27e4f07151e5aef28fa587e4ead36c5b87c43e0 --- CHANGES | 7 +++ res/res_pjsip_dtmf_info.c | 7 ++- res/res_pjsip_empty_info.c | 89 +++++++++++++++++++++++++++ res/res_pjsip_one_touch_record_info.c | 9 +-- 4 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 res/res_pjsip_empty_info.c diff --git a/CHANGES b/CHANGES index 91f5ce5dfa4..a22c0cdfa38 100644 --- a/CHANGES +++ b/CHANGES @@ -252,6 +252,12 @@ res_pjsip will be used instead. The new SIP resolver provides NAPTR support, improved SRV support, and AAAA record support. +res_pjsip_info_empty +-------------------- + * A new module that can respond to empty Content-Type INFO packets during call. + Some SBCs will terminate a call if their empty INFO packets are not responded + to within a predefined time. + res_pjsip_outbound_registration ------------------------------- * A new 'fatal_retry_interval' option has been added to outbound registration. @@ -264,6 +270,7 @@ res_pjsip_outbound_publish * Added a new multi_user option that when set to 'yes' allows a given configuration to be used for multiple users. + CEL Backends ------------------ diff --git a/res/res_pjsip_dtmf_info.c b/res/res_pjsip_dtmf_info.c index 47ccd1ae5cd..e534f3e27ed 100644 --- a/res/res_pjsip_dtmf_info.c +++ b/res/res_pjsip_dtmf_info.c @@ -103,13 +103,13 @@ static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pj if (!body || !body->len) { /* need to return 200 OK on empty body */ send_response(session, rdata, 200); - return 0; + return 1; } res = body->print_body(body, buf, body->len); if (res < 0) { send_response(session, rdata, 500); - return 0; + return 1; } buf[res] = '\0'; @@ -150,11 +150,12 @@ static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pj } send_response(session, rdata, event ? 200 : 500); - return event ? 0 : -1; + return 1; } static struct ast_sip_session_supplement dtmf_info_supplement = { .method = "INFO", + .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST, .incoming_request = dtmf_info_incoming_request, }; diff --git a/res/res_pjsip_empty_info.c b/res/res_pjsip_empty_info.c new file mode 100644 index 00000000000..09109ba2c3b --- /dev/null +++ b/res/res_pjsip_empty_info.c @@ -0,0 +1,89 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Bradley Latus + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + pjproject + res_pjsip + res_pjsip_session + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include +#include + +#include "asterisk/res_pjsip.h" +#include "asterisk/res_pjsip_session.h" +#include "asterisk/module.h" + +static void send_response(struct ast_sip_session *session, + struct pjsip_rx_data *rdata, int code) +{ + pjsip_tx_data *tdata; + pjsip_dialog *dlg = session->inv_session->dlg; + + if (pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata) == PJ_SUCCESS) { + struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); + pjsip_dlg_send_response(dlg, tsx, tdata); + } +} + +static int empty_info_incoming_request(struct ast_sip_session *session, + struct pjsip_rx_data *rdata) +{ + if (!rdata->msg_info.ctype) { + /* Need to return 200 OK on empty body */ + /* Some SBCs use empty INFO as a KEEPALIVE */ + send_response(session, rdata, 200); + return 1; + } + + /* Let another module respond */ + return 0; + +} + +static struct ast_sip_session_supplement empty_info_supplement = { + .method = "INFO", + .priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST, + .incoming_request = empty_info_incoming_request, +}; + +static int load_module(void) +{ + CHECK_PJSIP_SESSION_MODULE_LOADED(); + + ast_sip_session_register_supplement(&empty_info_supplement); + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + ast_sip_session_unregister_supplement(&empty_info_supplement); + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Empty INFO Support", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_APP_DEPEND, +); diff --git a/res/res_pjsip_one_touch_record_info.c b/res/res_pjsip_one_touch_record_info.c index 30dfcaabf87..2d53fd48ee0 100644 --- a/res/res_pjsip_one_touch_record_info.c +++ b/res/res_pjsip_one_touch_record_info.c @@ -72,13 +72,13 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip if (!session->channel) { send_response(session, 481, rdata); - return 0; + return 1; } /* Is this endpoint configured with One Touch Recording? */ if (!session->endpoint->info.recording.enabled || ast_strlen_zero(feature)) { send_response(session, 403, rdata); - return 0; + return 1; } ast_channel_lock(session->channel); @@ -87,7 +87,7 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip if (feature_res || ast_strlen_zero(feature_code)) { send_response(session, 403, rdata); - return 0; + return 1; } for (digit = feature_code; *digit; ++digit) { @@ -97,11 +97,12 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip send_response(session, 200, rdata); - return 0; + return 1; } static struct ast_sip_session_supplement info_supplement = { .method = "INFO", + .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST, .incoming_request = handle_incoming_request, }; From 40cb0320099ea750c63d35729eb3c76dc5c439cd Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 19 May 2016 13:41:45 -0300 Subject: [PATCH 0446/1578] res_sorcery_astdb: Filter fields to only the registered ones. This change introduces the same filtering that is done in res_sorcery_realtime to the res_sorcery_astdb module. This allows persisted sorcery objects that may contain unknown fields to still be read in from the AstDB and used. This is particularly useful when switching between different versions of Asterisk that may have introduced additional fields. ASTERISK-26014 #close Change-Id: Ib655130485a3ccfd635b7ed5546010ca14690fb2 --- res/res_sorcery_astdb.c | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index dcfaba528b8..79db6680889 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -79,6 +79,58 @@ static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, v return ast_db_put(family, ast_sorcery_object_get_id(object), value); } +/*! \brief Internal helper function which returns a filtered objectset. + * + * The following are filtered out of the objectset: + * \li Fields that are not registered with sorcery. + * + * \param objectset Objectset to filter. + * \param sorcery The sorcery instance that is requesting an objectset. + * \param type The object type + * + * \return The filtered objectset + */ +static struct ast_variable *sorcery_astdb_filter_objectset(struct ast_variable *objectset, const struct ast_sorcery *sorcery, + const char *type) +{ + struct ast_variable *previous = NULL, *field = objectset; + struct ast_sorcery_object_type *object_type; + + object_type = ast_sorcery_get_object_type(sorcery, type); + if (!object_type) { + ast_log(LOG_WARNING, "Unknown sorcery object type %s. Expect errors\n", type); + return objectset; + } + + while (field) { + struct ast_variable *removed; + + if (ast_sorcery_is_object_field_registered(object_type, field->name)) { + previous = field; + field = field->next; + continue; + } + + ast_debug(1, "Filtering out astdb field '%s' from retrieval\n", field->name); + + if (previous) { + previous->next = field->next; + } else { + objectset = field->next; + } + + removed = field; + field = field->next; + removed->next = NULL; + + ast_variables_destroy(removed); + } + + ao2_cleanup(object_type); + + return objectset; +} + /*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects) { @@ -103,10 +155,13 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc if (!(json = ast_json_load_string(entry->data, &error))) { return NULL; } + if (ast_json_to_ast_variables(json, &existing) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) { return NULL; } + existing = sorcery_astdb_filter_objectset(existing, sorcery, type); + if (fields && !ast_variable_lists_match(existing, fields, 0)) { continue; } @@ -148,6 +203,7 @@ static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void * if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &error)) || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) + || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) || !(object = ast_sorcery_alloc(sorcery, type, id)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { ast_debug(3, "Failed to retrieve object '%s' from astdb\n", id); @@ -260,6 +316,7 @@ static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void continue; } else if (!(json = ast_json_load_string(entry->data, &error)) || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) + || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) || !(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { regfree(&expression); From e773e3a9bbaf378d53647e4bac3ffcd61afb4ae6 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 18 May 2016 06:19:58 -0500 Subject: [PATCH 0447/1578] ARI: Add the ability to download the media associated with a stored recording This patch adds a new feature to ARI that allows a client to download the media associated with a stored recording. The new route is /recordings/stored/{name}/file, and transmits the underlying binary file using Asterisk's HTTP server's underlying file transfer facilities. Because this REST route returns non-JSON, a few small enhancements had to be made to the Python Swagger generation code, as well as the mustache templates that generate the ARI bindings. ASTERISK-26042 #close Change-Id: I49ec5c4afdec30bb665d9c977ab423b5387e0181 --- CHANGES | 4 ++ include/asterisk/ari.h | 2 + include/asterisk/stasis_app_recording.h | 24 +++++++ res/ari/resource_recordings.c | 44 ++++++++++++ res/ari/resource_recordings.h | 14 ++++ res/res_ari.c | 8 ++- res/res_ari_recordings.c | 72 ++++++++++++++++++- res/stasis_recording/stored.c | 18 +++++ rest-api-templates/ari_resource.h.mustache | 8 +++ .../res_ari_resource.c.mustache | 11 +++ rest-api-templates/swagger_model.py | 3 + rest-api/api-docs/recordings.json | 32 +++++++++ 12 files changed, 235 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 628bde2ad72..a547fbc864e 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,10 @@ ARI back to the resource. The "PlaybackFinished" event is raised when all media URIs are done. + * Stored recordings now allow for the media associated with a stored recording + to be retrieved. The new route, GET /recordings/stored/{name}/file, will + transmit the raw media file to the requester as binary. + Applications ------------------ diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h index c9f47a6e587..79b9516eb39 100644 --- a/include/asterisk/ari.h +++ b/include/asterisk/ari.h @@ -95,6 +95,8 @@ struct ast_ari_response { /*! HTTP response code. * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html */ int response_code; + /*! File descriptor for whatever file we want to respond with */ + int fd; /*! Corresponding text for the response code */ const char *response_text; /* Shouldn't http.c handle this? */ /*! Flag to indicate that no further response is needed */ diff --git a/include/asterisk/stasis_app_recording.h b/include/asterisk/stasis_app_recording.h index 543207a479a..bded30629dc 100644 --- a/include/asterisk/stasis_app_recording.h +++ b/include/asterisk/stasis_app_recording.h @@ -48,6 +48,30 @@ struct stasis_app_stored_recording; const char *stasis_app_stored_recording_get_file( struct stasis_app_stored_recording *recording); +/*! + * \brief Returns the full filename, with extension, for this recording. + * \since 14.0.0 + * + * \param recording Recording to query. + * + * \return Absolute path to the recording file, with the extension. + * \return \c NULL on error + */ +const char *stasis_app_stored_recording_get_filename( + struct stasis_app_stored_recording *recording); + +/*! + * \brief Returns the extension for this recording. + * \since 14.0.0 + * + * \param recording Recording to query. + * + * \return The extension associated with this recording. + * \return \c NULL on error + */ +const char *stasis_app_stored_recording_get_extension( + struct stasis_app_stored_recording *recording); + /*! * \brief Convert stored recording info to JSON. * diff --git a/res/ari/resource_recordings.c b/res/ari/resource_recordings.c index a49c3b12e87..5661d608d90 100644 --- a/res/ari/resource_recordings.c +++ b/res/ari/resource_recordings.c @@ -101,6 +101,50 @@ void ast_ari_recordings_get_stored(struct ast_variable *headers, ast_ari_response_ok(response, json); } +void ast_ari_recordings_get_stored_file(struct ast_tcptls_session_instance *ser, + struct ast_variable *headers, struct ast_ari_recordings_get_stored_file_args *args, + struct ast_ari_response *response) +{ + RAII_VAR(struct stasis_app_stored_recording *, recording, + stasis_app_stored_recording_find_by_name(args->recording_name), + ao2_cleanup); + static const char *format_type_names[AST_MEDIA_TYPE_TEXT + 1] = { + [AST_MEDIA_TYPE_UNKNOWN] = "binary", + [AST_MEDIA_TYPE_AUDIO] = "audio", + [AST_MEDIA_TYPE_VIDEO] = "video", + [AST_MEDIA_TYPE_IMAGE] = "image", + [AST_MEDIA_TYPE_TEXT] = "text", + }; + struct ast_format *format; + + response->message = ast_json_null(); + + if (!recording) { + ast_ari_response_error(response, 404, "Not Found", + "Recording not found"); + return; + } + + format = ast_get_format_for_file_ext(stasis_app_stored_recording_get_extension(recording)); + if (!format) { + ast_ari_response_error(response, 500, "Internal Server Error", + "Format specified by recording not available or loaded"); + return; + } + + response->fd = open(stasis_app_stored_recording_get_filename(recording), O_RDONLY); + if (response->fd < 0) { + ast_ari_response_error(response, 403, "Forbidden", + "Recording could not be opened"); + return; + } + + ast_str_append(&response->headers, 0, "Content-Type: %s/%s\r\n", + format_type_names[ast_format_get_type(format)], + stasis_app_stored_recording_get_extension(recording)); + ast_ari_response_ok(response, ast_json_null()); +} + void ast_ari_recordings_copy_stored(struct ast_variable *headers, struct ast_ari_recordings_copy_stored_args *args, struct ast_ari_response *response) diff --git a/res/ari/resource_recordings.h b/res/ari/resource_recordings.h index 196122f4489..1bc93c52781 100644 --- a/res/ari/resource_recordings.h +++ b/res/ari/resource_recordings.h @@ -76,6 +76,20 @@ struct ast_ari_recordings_delete_stored_args { * \param[out] response HTTP response */ void ast_ari_recordings_delete_stored(struct ast_variable *headers, struct ast_ari_recordings_delete_stored_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_recordings_get_stored_file() */ +struct ast_ari_recordings_get_stored_file_args { + /*! The name of the recording */ + const char *recording_name; +}; +/*! + * \brief Get the file associated with the stored recording. + * + * \param ser TCP/TLS session instance + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_recordings_get_stored_file(struct ast_tcptls_session_instance *ser, struct ast_variable *headers, struct ast_ari_recordings_get_stored_file_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_recordings_copy_stored() */ struct ast_ari_recordings_copy_stored_args { /*! The name of the recording to copy */ diff --git a/res/res_ari.c b/res/res_ari.c index 14dece8e4e0..0cc1ee7b0d5 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -870,7 +870,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup); RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free); RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup); - struct ast_ari_response response = {}; + struct ast_ari_response response = { .fd = -1, 0 }; RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy); if (!response_body) { @@ -1011,11 +1011,14 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body)); ast_http_send(ser, method, response.response_code, response.response_text, response.headers, response_body, - 0, 0); + response.fd != -1 ? response.fd : 0, 0); /* ast_http_send takes ownership, so we don't have to free them */ response_body = NULL; ast_json_unref(response.message); + if (response.fd >= 0) { + close(response.fd); + } return 0; } @@ -1023,7 +1026,6 @@ static struct ast_http_uri http_uri = { .callback = ast_ari_callback, .description = "Asterisk RESTful API", .uri = "ari", - .has_subtree = 1, .data = NULL, .key = __FILE__, diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index df4a124bebc..abc264d9e51 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -218,6 +218,65 @@ static void ast_ari_recordings_delete_stored_cb( } #endif /* AST_DEVMODE */ +fin: __attribute__((unused)) + return; +} +/*! + * \brief Parameter parsing callback for /recordings/stored/{recordingName}/file. + * \param get_params GET parameters in the HTTP request. + * \param path_vars Path variables extracted from the request. + * \param headers HTTP headers. + * \param[out] response Response to the HTTP request. + */ +static void ast_ari_recordings_get_stored_file_cb( + struct ast_tcptls_session_instance *ser, + struct ast_variable *get_params, struct ast_variable *path_vars, + struct ast_variable *headers, struct ast_ari_response *response) +{ + struct ast_ari_recordings_get_stored_file_args args = {}; + struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); +#if defined(AST_DEVMODE) + int is_valid; + int code; +#endif /* AST_DEVMODE */ + + for (i = path_vars; i; i = i->next) { + if (strcmp(i->name, "recordingName") == 0) { + args.recording_name = (i->value); + } else + {} + } + ast_ari_recordings_get_stored_file(ser, headers, &args, response); +#if defined(AST_DEVMODE) + code = response->response_code; + + switch (code) { + case 0: /* Implementation is still a stub, or the code wasn't set */ + is_valid = response->message == NULL; + break; + case 500: /* Internal Server Error */ + case 501: /* Not Implemented */ + case 404: /* Recording not found */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + /* No validation on a raw binary response */ + is_valid = 1; + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingName}/file\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingName}/file\n"); + ast_ari_response_error(response, 500, + "Internal Server Error", "Response validation failed"); + } +#endif /* AST_DEVMODE */ + fin: __attribute__((unused)) return; } @@ -737,6 +796,15 @@ fin: __attribute__((unused)) return; } +/*! \brief REST handler for /api-docs/recordings.{format} */ +static struct stasis_rest_handlers recordings_stored_recordingName_file = { + .path_segment = "file", + .callbacks = { + [AST_HTTP_GET] = ast_ari_recordings_get_stored_file_cb, + }, + .num_children = 0, + .children = { } +}; /*! \brief REST handler for /api-docs/recordings.{format} */ static struct stasis_rest_handlers recordings_stored_recordingName_copy = { .path_segment = "copy", @@ -754,8 +822,8 @@ static struct stasis_rest_handlers recordings_stored_recordingName = { [AST_HTTP_GET] = ast_ari_recordings_get_stored_cb, [AST_HTTP_DELETE] = ast_ari_recordings_delete_stored_cb, }, - .num_children = 1, - .children = { &recordings_stored_recordingName_copy, } + .num_children = 2, + .children = { &recordings_stored_recordingName_file,&recordings_stored_recordingName_copy, } }; /*! \brief REST handler for /api-docs/recordings.{format} */ static struct stasis_rest_handlers recordings_stored = { diff --git a/res/stasis_recording/stored.c b/res/stasis_recording/stored.c index acabb65bbed..50232c42754 100644 --- a/res/stasis_recording/stored.c +++ b/res/stasis_recording/stored.c @@ -62,6 +62,24 @@ const char *stasis_app_stored_recording_get_file( return recording->file; } +const char *stasis_app_stored_recording_get_filename( + struct stasis_app_stored_recording *recording) +{ + if (!recording) { + return NULL; + } + return recording->file_with_ext; +} + +const char *stasis_app_stored_recording_get_extension( + struct stasis_app_stored_recording *recording) +{ + if (!recording) { + return NULL; + } + return recording->format; +} + /*! * \brief Split a path into directory and file, resolving canonical directory. * diff --git a/rest-api-templates/ari_resource.h.mustache b/rest-api-templates/ari_resource.h.mustache index 5e06af734f7..df075af3574 100644 --- a/rest-api-templates/ari_resource.h.mustache +++ b/rest-api-templates/ari_resource.h.mustache @@ -82,11 +82,19 @@ int ast_ari_{{c_name}}_{{c_nickname}}_parse_body( * {{{notes}}} {{/notes}} * +{{#is_binary_response}} + * \param ser TCP/TLS session instance +{{/is_binary_response}} * \param headers HTTP headers * \param args Swagger parameters * \param[out] response HTTP response */ +{{^is_binary_response}} void ast_ari_{{c_name}}_{{c_nickname}}(struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args, struct ast_ari_response *response); +{{/is_binary_response}} +{{#is_binary_response}} +void ast_ari_{{c_name}}_{{c_nickname}}(struct ast_tcptls_session_instance *ser, struct ast_variable *headers, struct ast_ari_{{c_name}}_{{c_nickname}}_args *args, struct ast_ari_response *response); +{{/is_binary_response}} {{/is_req}} {{#is_websocket}} diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index 23f2a52ac2f..c4e6f3d5418 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -91,7 +91,12 @@ static void ast_ari_{{c_name}}_{{c_nickname}}_cb( #endif /* AST_DEVMODE */ {{> param_parsing}} +{{^is_binary_response}} ast_ari_{{c_name}}_{{c_nickname}}(headers, &args, response); +{{/is_binary_response}} +{{#is_binary_response}} + ast_ari_{{c_name}}_{{c_nickname}}(ser, headers, &args, response); +{{/is_binary_response}} #if defined(AST_DEVMODE) code = response->response_code; @@ -114,8 +119,14 @@ static void ast_ari_{{c_name}}_{{c_nickname}}_cb( ast_ari_validate_{{c_singular_name}}_fn()); {{/is_list}} {{^is_list}} +{{^is_binary_response}} is_valid = ast_ari_validate_{{c_name}}( response->message); +{{/is_binary_response}} +{{#is_binary_response}} + /* No validation on a raw binary response */ + is_valid = 1; +{{/is_binary_response}} {{/is_list}} {{/response_class}} } else { diff --git a/rest-api-templates/swagger_model.py b/rest-api-templates/swagger_model.py index f3b49e12e32..c76cb7f28c6 100644 --- a/rest-api-templates/swagger_model.py +++ b/rest-api-templates/swagger_model.py @@ -332,6 +332,7 @@ def __init__(self): self.is_list = None self.singular_name = None self.is_primitive = None + self.is_binary = None def load(self, type_name, processor, context): # Some common errors @@ -346,6 +347,7 @@ def load(self, type_name, processor, context): else: self.singular_name = self.name self.is_primitive = self.singular_name in SWAGGER_PRIMITIVES + self.is_binary = (self.singular_name == 'binary') processor.process_type(self, context) return self @@ -401,6 +403,7 @@ def load(self, op_json, processor, context): self.has_header_parameters = self.header_parameters and True self.has_parameters = self.has_query_parameters or \ self.has_path_parameters or self.has_header_parameters + self.is_binary_response = self.response_class.is_binary # Body param is different, since there's at most one self.body_parameter = [ diff --git a/rest-api/api-docs/recordings.json b/rest-api/api-docs/recordings.json index 51f0a21f4d4..d173ac98eb5 100644 --- a/rest-api/api-docs/recordings.json +++ b/rest-api/api-docs/recordings.json @@ -69,6 +69,38 @@ } ] }, + { + "path": "/recordings/stored/{recordingName}/file", + "description": "The actual file associated with the stored recording", + "operations": [ + { + "httpMethod": "GET", + "summary": "Get the file associated with the stored recording.", + "nickname": "getStoredFile", + "responseClass": "binary", + "parameters": [ + { + "name": "recordingName", + "description": "The name of the recording", + "paramType": "path", + "required": true, + "allowMultiple": false, + "dataType": "string" + } + ], + "errorResponses": [ + { + "code": 403, + "reason": "The recording file could not be opened" + }, + { + "code": 404, + "reason": "Recording not found" + } + ] + } + ] + }, { "path": "/recordings/stored/{recordingName}/copy", "description": "Copy an individual recording", From 1c02b19b79019c7438e162d4db83a5fbf6c46554 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 20 May 2016 09:39:10 -0500 Subject: [PATCH 0448/1578] res_pjsip: Match dialogs on responses better. When receiving an incoming response to a dialog-starting INVITE, we were not matching the response to the INVITE dialog. Since we had not recorded the to-tag to the dialog structure, the PJSIP-provided method to find the dialog did not match. Most of the time, this was not a problem, because there is a fall-back that makes the response get routed to the same serializer that the request was sent on. However, in cases where an asynchronous DNS lookup occurs in the PJSIP core, the thread that sends the INVITE is not actually a threadpool serializer thread. This means we are unable to record a serializer to handle the incoming response. Now, imagine what happens when an INVITE is sent on a non-serialized thread, and an error response (such as a 486) arrives. The 486 ends up getting put on some random threadpool thread. Eventually, a hangup task gets queued on the INVITE dialog serializer. Since the 486 is being handled on a different thread, the hangup task can execute at the same time that the 486 is being handled. The hangup task assumes that it is the sole owner of the INVITE session and channel, so it ends up potentially freeing the channel and NULLing the session's channel pointer. The thread handling the 486 can crash as a result. This change has the incoming response match the INVITE transaction, and then get the dialog from that transaction. It's the same method we had been using for matching incoming CANCEL requests. By doing this, we get the INVITE dialog and can ensure that the 486 response ends up being handled by the same thread as the hangup, ensuring that the hangup runs after the 486 has been completely handled. ASTERISK-25941 #close Reported by Javier Riveros Change-Id: I0d4cc5d07e2a8d03e9db704d34bdef2ba60794a0 --- res/res_pjsip/pjsip_distributor.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index d902ed45614..2ab954eb04b 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -231,20 +231,33 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG || pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || rdata->msg_info.to->tag.slen != 0) { - return pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag, + dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag, remote_tag, PJ_TRUE); + if (dlg) { + return dlg; + } } - /* Incoming CANCEL without a to-tag can't use same method for finding the - * dialog. Instead, we have to find the matching INVITE transaction and - * then get the dialog from the transaction + /* + * There may still be a matching dialog if this is + * 1) an incoming CANCEL request without a to-tag + * 2) an incoming response to a dialog-creating request. */ - pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS, - pjsip_get_invite_method(), rdata); + if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { + /* CANCEL requests will need to match the INVITE we initially received. Any + * other request type will either have been matched already or is not in + * dialog + */ + pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS, + pjsip_get_invite_method(), rdata); + } else { + pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAC, + &rdata->msg_info.cseq->method, rdata); + } tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); if (!tsx) { - ast_log(LOG_ERROR, "Could not find matching INVITE transaction for CANCEL request\n"); + ast_debug(3, "Could not find matching transaction for %s\n", rdata->msg_info.info); return NULL; } From c378b00a839e4a2457eae0510ef6ec992199b07a Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 12 May 2016 16:18:22 -0400 Subject: [PATCH 0449/1578] func_odbc: single database connection should be optional func_odbc was changed in Asterisk 13.9.0 to make func_odbc use a single database connection per DSN because of reported bug ASTERISK-25938 with MySQL/MariaDB LAST_INSERT_ID(). This is drawback in performance when func_odbc is used very often in dialplan. Single database connection should be optional. ASTERISK-26010 Change-Id: I7091783a7150252de8eeb455115bd00514dfe843 --- CHANGES | 8 + configs/samples/func_odbc.conf.sample | 14 ++ funcs/func_odbc.c | 215 +++++++++++++++++++------- 3 files changed, 177 insertions(+), 60 deletions(-) diff --git a/CHANGES b/CHANGES index ec44e30fc4b..0e99ab9d87e 100644 --- a/CHANGES +++ b/CHANGES @@ -183,6 +183,8 @@ Core Functions ------------------ + * The func_odbc global option "single_db_connection" default value has been + changed to 'no'. CHANNEL ------------------ @@ -275,6 +277,12 @@ Queue --- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- ------------------------------------------------------------------------------ +func_odbc +------------------ + * Added new global option "single_db_connection". + Enabling this option func_odbc will use a single database connection per DSN. + This option is enabled by default. + res_fax ------------------ * Added FAXMODE variable to let dialplan know what fax transport was used. diff --git a/configs/samples/func_odbc.conf.sample b/configs/samples/func_odbc.conf.sample index fd528d21663..f4d90b79976 100644 --- a/configs/samples/func_odbc.conf.sample +++ b/configs/samples/func_odbc.conf.sample @@ -1,6 +1,20 @@ ; ; func_odbc.conf ; +[general] +; +; Asterisk uses separate connections for every database operation. +; If single_db_connection is enabled then func_odbc will use a single +; database connection per DSN. +; This option exists for those who expect that a second func_odbc call +; works on the same connection. That allows you to do a LAST_INSERT_ID() +; in a second func_odbc call. +; Note that you'll need additional dialplan locks for this behaviour to work. +; There are better ways: using stored procedures/functions instead. +; This option is disabled by default. +;single_db_connection=no +; +; ; Each context is a separately defined function. By convention, all ; functions are entirely uppercase, so the defined contexts should also ; be all-uppercase, but there is nothing that enforces this. All functions diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index d8ffd90bbd6..489f3734b97 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -101,6 +101,12 @@ ASTERISK_REGISTER_FILE() static char *config = "func_odbc.conf"; +#define DEFAULT_SINGLE_DB_CONNECTION 0 + +static int single_db_connection; + +AST_RWLOCK_DEFINE_STATIC(single_db_connection_lock); + enum odbc_option_flags { OPT_ESCAPECOMMAS = (1 << 0), OPT_MULTIROW = (1 << 1), @@ -221,6 +227,10 @@ static struct dsn *create_dsn(const char *name) { struct dsn *dsn; + if (!dsns) { + return NULL; + } + dsn = ao2_alloc(sizeof(*dsn) + strlen(name) + 1, dsn_destructor); if (!dsn) { return NULL; @@ -296,6 +306,10 @@ static struct dsn *get_dsn(const char *name) { struct dsn *dsn; + if (!dsns) { + return NULL; + } + ao2_lock(dsns); dsn = ao2_find(dsns, name, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!dsn) { @@ -332,21 +346,55 @@ static struct dsn *get_dsn(const char *name) } /*! - * \brief Unlock and unreference a DSN + * \brief Get a DB handle via a DSN or directly * - * \param dsn The dsn to unlock and unreference - * \return NULL + * If single db connection then get the DB handle via DSN + * else by requesting a connection directly + * + * \param dsn_name Name of the DSN as found in res_odbc.conf + * \param dsn The pointer to the DSN + * \retval NULL Unable to retrieve the DB handle + * \retval non-NULL The retrieved DB handle */ -static void *release_dsn(struct dsn *dsn) +static struct odbc_obj *get_odbc_obj(const char *dsn_name, struct dsn **dsn) { - if (!dsn) { - return NULL; + struct odbc_obj *obj = NULL; + + ast_rwlock_rdlock(&single_db_connection_lock); + if (single_db_connection) { + if (dsn) { + *dsn = get_dsn(dsn_name); + if (*dsn) { + obj = (*dsn)->connection; + } + } + } else { + obj = ast_odbc_request_obj(dsn_name, 0); } + ast_rwlock_unlock(&single_db_connection_lock); - ao2_unlock(dsn); - ao2_ref(dsn, -1); + return obj; +} - return NULL; +/*! + * \brief Release an ODBC obj or a DSN + * + * If single db connection then unlock and unreference the DSN + * else release the ODBC obj + * + * \param obj The pointer to the ODBC obj to release + * \param dsn The pointer to the dsn to unlock and unreference + */ +static inline void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn) +{ + if (dsn && *dsn) { + ao2_unlock(*dsn); + ao2_ref(*dsn, -1); + *dsn = NULL; + } else if (obj && *obj) { + ast_odbc_release_obj(*obj); + *obj = NULL; + } } static AST_RWLIST_HEAD_STATIC(queries, acf_odbc_query); @@ -568,19 +616,16 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) { transactional = 1; } else { - dsn = get_dsn(query->writehandle[dsn_num]); - if (!dsn) { - continue; - } - obj = dsn->connection; + obj = get_odbc_obj(query->writehandle[dsn_num], &dsn); transactional = 0; } if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) { break; } - - dsn = release_dsn(dsn); + if (!transactional) { + release_obj_or_dsn (&obj, &dsn); + } } } @@ -593,25 +638,23 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co status = "SUCCESS"; } else if (query->sql_insert) { - dsn = release_dsn(dsn); + if (!transactional) { + release_obj_or_dsn (&obj, &dsn); + } for (transactional = 0, dsn_num = 0; dsn_num < 5; dsn_num++) { if (!ast_strlen_zero(query->writehandle[dsn_num])) { if (transactional) { /* This can only happen second time through or greater. */ ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n"); - } else if (obj) { - dsn = release_dsn(dsn); + } else { + release_obj_or_dsn (&obj, &dsn); } if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) { transactional = 1; } else { - dsn = get_dsn(query->writehandle[dsn_num]); - if (!dsn) { - continue; - } - obj = dsn->connection; + obj = get_odbc_obj(query->writehandle[dsn_num], &dsn); transactional = 0; } if (obj) { @@ -641,7 +684,9 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); } - dsn = release_dsn(dsn); + if (!transactional) { + release_obj_or_dsn (&obj, &dsn); + } if (!bogus_chan) { ast_autoservice_stop(chan); @@ -652,6 +697,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len) { + struct odbc_obj *obj = NULL; struct acf_odbc_query *query; char varname[15], rowcount[12] = "-1"; struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16); @@ -757,21 +803,21 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha for (dsn_num = 0; dsn_num < 5; dsn_num++) { if (!ast_strlen_zero(query->readhandle[dsn_num])) { - dsn = get_dsn(query->readhandle[dsn_num]); - if (!dsn) { + obj = get_odbc_obj(query->readhandle[dsn_num], &dsn); + if (!obj) { continue; } - stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)); + stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)); } if (stmt) { break; } - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); } if (!stmt) { ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql)); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); ast_autoservice_stop(chan); @@ -785,7 +831,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); SQLCloseCursor(stmt); SQLFreeHandle (SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); ast_autoservice_stop(chan); @@ -809,7 +855,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha } SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); @@ -832,7 +878,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); ast_autoservice_stop(chan); @@ -864,7 +910,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (!bogus_chan) { pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); @@ -973,7 +1019,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); ast_autoservice_stop(chan); return -1; @@ -986,7 +1032,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha } SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (resultset && !multirow) { /* Fetch the first resultset */ if (!acf_fetch(chan, "", buf, buf, len)) { @@ -1413,6 +1459,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args if (a->argc == 5 && !strcmp(a->argv[4], "exec")) { /* Execute the query */ + struct odbc_obj *obj = NULL; struct dsn *dsn = NULL; int dsn_num, executed = 0; SQLHSTMT stmt; @@ -1432,14 +1479,14 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args if (ast_strlen_zero(query->readhandle[dsn_num])) { continue; } - dsn = get_dsn(query->readhandle[dsn_num]); - if (!dsn) { + obj = get_odbc_obj(query->readhandle[dsn_num], &dsn); + if (!obj) { continue; } ast_debug(1, "Found handle %s\n", query->readhandle[dsn_num]); - if (!(stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)))) { - dsn = release_dsn(dsn); + if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { + release_obj_or_dsn (&obj, &dsn); continue; } @@ -1450,7 +1497,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); SQLCloseCursor(stmt); SQLFreeHandle (SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); AST_RWLIST_UNLOCK(&queries); return CLI_SUCCESS; } @@ -1459,7 +1506,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (res == SQL_NO_DATA) { ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn_num, query->readhandle[dsn_num], ast_str_buffer(sql)); break; @@ -1488,7 +1535,7 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql)); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); AST_RWLIST_UNLOCK(&queries); return CLI_SUCCESS; } @@ -1506,11 +1553,11 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args } SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn_num, query->readhandle[dsn_num]); break; } - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); if (!executed) { ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql)); @@ -1633,7 +1680,8 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg if (a->argc == 6 && !strcmp(a->argv[5], "exec")) { /* Execute the query */ - struct dsn *dsn; + struct odbc_obj *obj = NULL; + struct dsn *dsn = NULL; int dsn_num, executed = 0; SQLHSTMT stmt; SQLLEN rows = -1; @@ -1642,19 +1690,19 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg if (ast_strlen_zero(query->writehandle[dsn_num])) { continue; } - dsn = get_dsn(query->writehandle[dsn_num]); - if (!dsn) { + obj = get_odbc_obj(query->writehandle[dsn_num], &dsn); + if (!obj) { continue; } - if (!(stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)))) { - dsn = release_dsn(dsn); + if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { + release_obj_or_dsn (&obj, &dsn); continue; } SQLRowCount(stmt, &rows); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); - dsn = release_dsn(dsn); + release_obj_or_dsn (&obj, &dsn); ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn_num, query->writehandle[dsn_num]); executed = 1; break; @@ -1680,31 +1728,48 @@ static int load_module(void) int res = 0; struct ast_config *cfg; char *catg; + const char *s; struct ast_flags config_flags = { 0 }; - dsns = ao2_container_alloc(DSN_BUCKETS, dsn_hash, dsn_cmp); - if (!dsns) { - return AST_MODULE_LOAD_DECLINE; - } - res |= ast_custom_function_register(&fetch_function); res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish); - AST_RWLIST_WRLOCK(&queries); cfg = ast_config_load(config, config_flags); if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); - AST_RWLIST_UNLOCK(&queries); - ao2_ref(dsns, -1); return AST_MODULE_LOAD_DECLINE; } + ast_rwlock_wrlock(&single_db_connection_lock); + if ((s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) { + single_db_connection = ast_true(s); + } else { + single_db_connection = DEFAULT_SINGLE_DB_CONNECTION; + } + + dsns = NULL; + + if (single_db_connection) { + dsns = ao2_container_alloc(DSN_BUCKETS, dsn_hash, dsn_cmp); + if (!dsns) { + ast_log(LOG_ERROR, "Could not initialize DSN container\n"); + ast_rwlock_unlock(&single_db_connection_lock); + return AST_MODULE_LOAD_DECLINE; + } + } + ast_rwlock_unlock(&single_db_connection_lock); + + AST_RWLIST_WRLOCK(&queries); for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) { struct acf_odbc_query *query = NULL; int err; + if (!strcasecmp(catg, "general")) { + continue; + } + if ((err = init_acf_query(cfg, catg, &query))) { if (err == ENOMEM) ast_log(LOG_ERROR, "Out of memory\n"); @@ -1750,7 +1815,9 @@ static int unload_module(void) AST_RWLIST_UNLOCK(&queries); - ao2_ref(dsns, -1); + if (dsns) { + ao2_ref(dsns, -1); + } return res; } @@ -1760,12 +1827,36 @@ static int reload(void) struct ast_config *cfg; struct acf_odbc_query *oldquery; char *catg; + const char *s; struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; cfg = ast_config_load(config, config_flags); if (cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) return 0; + ast_rwlock_wrlock(&single_db_connection_lock); + + if (dsns) { + ao2_ref(dsns, -1); + dsns = NULL; + } + + if (cfg && (s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) { + single_db_connection = ast_true(s); + } else { + single_db_connection = DEFAULT_SINGLE_DB_CONNECTION; + } + + if (single_db_connection) { + dsns = ao2_container_alloc(DSN_BUCKETS, dsn_hash, dsn_cmp); + if (!dsns) { + ast_log(LOG_ERROR, "Could not initialize DSN container\n"); + ast_rwlock_unlock(&single_db_connection_lock); + return 0; + } + } + ast_rwlock_unlock(&single_db_connection_lock); + AST_RWLIST_WRLOCK(&queries); while (!AST_RWLIST_EMPTY(&queries)) { @@ -1784,6 +1875,10 @@ static int reload(void) catg = ast_category_browse(cfg, catg)) { struct acf_odbc_query *query = NULL; + if (!strcasecmp(catg, "general")) { + continue; + } + if (init_acf_query(cfg, catg, &query)) { ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); } else { From ade5275a3e1b0dac1d00936e92f93d957384fe8b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 20 May 2016 16:59:52 -0500 Subject: [PATCH 0450/1578] parking.h: Update ast_parking_park_call() doxygen to reality. ASTERISK-26029 Change-Id: I2db14d102a48d3224010e6d1c69e856373cc1260 --- include/asterisk/parking.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h index 4c93c3b457b..53dfe93208d 100644 --- a/include/asterisk/parking.h +++ b/include/asterisk/parking.h @@ -211,12 +211,19 @@ int ast_parking_is_exten_park(const char *context, const char *exten); * \brief Park the bridge and/or callers that this channel is in * * \param parker The bridge_channel parking the bridge - * \param exten Optional. The extension the channel or bridge was parked at if the - * call succeeds. + * \param[out] exten Optional. The parking exten to access the parking lot. * \param length Optional. If \c exten is specified, the size of the buffer. * * \note This is safe to be called outside of the \ref AstBridging Bridging API. * + * \note The exten parameter was intended to return the extension the channel or + * bridge was parked at if the call succeeds. However, accessing that information + * is very difficult to do with the new asynchronous design. That information may + * not be available anywhere by the time this function currently returns. + * + * Only, chan_skinny is known to call this function and use the exten parameter + * for the phone display. + * * \retval 0 on success * \retval non-zero on error */ From 2a77af9ed0244f3b880d4e845760fef6e475afa8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 20 May 2016 19:03:53 -0500 Subject: [PATCH 0451/1578] chan_rtp.c: Cleanup ast_request() parameter parsing. * Fixed NULL crash potential if parameters are missing. * Reordered some operations so further diagnostic messages can be more helpful. Change-Id: Ibbdc67a2496508cbfbfef0cf19c35177ae2fbd70 --- channels/chan_rtp.c | 86 +++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index 04eb0b1fe1f..56705b1f034 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -141,19 +141,32 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo parse = ast_strdupa(data); AST_NONSTANDARD_APP_ARGS(args, parse, '/'); - fmt = ast_format_cap_get_format(cap, 0); + if (ast_strlen_zero(args.type)) { + ast_log(LOG_ERROR, "Type is required for the 'MulticastRTP' channel\n"); + goto failure; + } - ast_sockaddr_setnull(&control_address); + if (ast_strlen_zero(args.destination)) { + ast_log(LOG_ERROR, "Destination is required for the 'MulticastRTP' channel\n"); + goto failure; + } + if (!ast_sockaddr_parse(&destination_address, args.destination, PARSE_PORT_REQUIRE)) { + ast_log(LOG_ERROR, "Destination address '%s' could not be parsed\n", + args.destination); + goto failure; + } - if (!ast_strlen_zero(args.control) && - !ast_sockaddr_parse(&control_address, args.control, PARSE_PORT_REQUIRE)) { + ast_sockaddr_setnull(&control_address); + if (!ast_strlen_zero(args.control) + && !ast_sockaddr_parse(&control_address, args.control, PARSE_PORT_REQUIRE)) { ast_log(LOG_ERROR, "Control address '%s' could not be parsed\n", args.control); goto failure; } - if (!ast_sockaddr_parse(&destination_address, args.destination, - PARSE_PORT_REQUIRE)) { - ast_log(LOG_ERROR, "Destination address '%s' could not be parsed\n", args.destination); + fmt = ast_format_cap_get_format(cap, 0); + if (!fmt) { + ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n", + args.destination); goto failure; } @@ -162,12 +175,17 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo goto failure; } - if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, args.type))) { - ast_log(LOG_ERROR, "Could not create RTP instance for sending media to '%s'\n", args.destination); + instance = ast_rtp_instance_new("multicast", NULL, &control_address, args.type); + if (!instance) { + ast_log(LOG_ERROR, + "Could not create '%s' multicast RTP instance for sending media to '%s'\n", + args.type, args.destination); goto failure; } - if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, requestor, 0, "MulticastRTP/%p", instance))) { + chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, + requestor, 0, "MulticastRTP/%p", instance); + if (!chan) { ast_rtp_instance_destroy(instance); goto failure; } @@ -216,40 +234,54 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form ); if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n"); goto failure; } parse = ast_strdupa(data); AST_NONSTANDARD_APP_ARGS(args, parse, '/'); - if (!ast_strlen_zero(args.format)) { - fmt = ast_format_cache_get(args.format); - } else { - fmt = ast_format_cap_get_format(cap, 0); - } - - if (!fmt) { - ast_log(LOG_ERROR, "No format specified for sending RTP to '%s'\n", args.destination); + if (ast_strlen_zero(args.destination)) { + ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n"); goto failure; } - - if (!ast_sockaddr_parse(&address, args.destination, - PARSE_PORT_REQUIRE)) { + if (!ast_sockaddr_parse(&address, args.destination, PARSE_PORT_REQUIRE)) { ast_log(LOG_ERROR, "Destination '%s' could not be parsed\n", args.destination); goto failure; } + if (!ast_strlen_zero(args.format)) { + fmt = ast_format_cache_get(args.format); + if (!fmt) { + ast_log(LOG_ERROR, "Format '%s' not found for sending RTP to '%s'\n", + args.format, args.destination); + goto failure; + } + } else { + fmt = ast_format_cap_get_format(cap, 0); + if (!fmt) { + ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n", + args.destination); + goto failure; + } + } + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!caps) { goto failure; } ast_ouraddrfor(&address, &local_address); - if (!(instance = ast_rtp_instance_new(args.engine, NULL, &local_address, NULL))) { - ast_log(LOG_ERROR, "Could not create RTP instance for sending media to '%s'\n", args.destination); + instance = ast_rtp_instance_new(args.engine, NULL, &local_address, NULL); + if (!instance) { + ast_log(LOG_ERROR, + "Could not create %s RTP instance for sending media to '%s'\n", + S_OR(args.engine, "default"), args.destination); goto failure; } - if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, requestor, 0, "UnicastRTP/%s-%p", args.destination, instance))) { + chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, + requestor, 0, "UnicastRTP/%s-%p", args.destination, instance); + if (!chan) { ast_rtp_instance_destroy(instance); goto failure; } @@ -268,9 +300,11 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form ast_channel_tech_pvt_set(chan, instance); - pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS", ast_sockaddr_stringify_addr(&local_address)); + pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS", + ast_sockaddr_stringify_addr(&local_address)); ast_rtp_instance_get_local_address(instance, &local_address); - pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT", ast_sockaddr_stringify_port(&local_address)); + pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT", + ast_sockaddr_stringify_port(&local_address)); ast_channel_unlock(chan); From 31897d2d99c82f3bfe254f7b4456acef24a53cad Mon Sep 17 00:00:00 2001 From: Ivan Poddubny Date: Sat, 21 May 2016 13:42:45 +0300 Subject: [PATCH 0452/1578] func_curl: Don't trim response text on non-ASCII characters The characters 0x80-0xFF were trimmed as well as 0x00-0x20 because of a signed comparison. ASTERISK-25669 #close Reported by: Jesper patches: strings.curl.trim.patch submitted by Jesper (License 5518) Change-Id: Ia51e169f24e3252a7ebbaab3728630138ec6f60a --- include/asterisk/strings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 0e2f69ba892..2ca75a69c47 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -688,7 +688,7 @@ void ast_str_trim_blanks(struct ast_str *buf), if (!buf) { return; } - while (buf->__AST_STR_USED && buf->__AST_STR_STR[buf->__AST_STR_USED - 1] < 33) { + while (buf->__AST_STR_USED && ((unsigned char) buf->__AST_STR_STR[buf->__AST_STR_USED - 1]) < 33) { buf->__AST_STR_STR[--(buf->__AST_STR_USED)] = '\0'; } } From 85d0272e76858a571d01bcf2ccaba871daa10e16 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 22 May 2016 13:03:20 -0300 Subject: [PATCH 0453/1578] res_pjsip: Only check transaction on transaction state events. The send request callback function currently assumes that it will only ever be called on transaction state changes. This is not always true. If our own timer callback occurs we will call the callback with a timer event instead of a transaction state change event. In this case the transaction on the event is invalid and accessing it will result in a crash. ASTERISK-26049 #close Change-Id: I623211c8533eb73056b0250b4580b49ad4174dfc --- res/res_pjsip.c | 72 +++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index c06b67ecf7b..bebe941b511 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3513,46 +3513,48 @@ static void send_request_cb(void *token, pjsip_event *e) pjsip_rx_data *challenge; struct ast_sip_supplement *supplement; - switch(e->body.tsx_state.type) { - case PJSIP_EVENT_TRANSPORT_ERROR: - case PJSIP_EVENT_TIMER: - /* - * Check the request status on transport error or timeout. A transport - * error can occur when a TCP socket closes and that can be the result - * of a 503. Also we may need to failover on a timeout (408). - */ - if (check_request_status(req_data, e)) { - return; - } - break; - case PJSIP_EVENT_RX_MSG: - challenge = e->body.tsx_state.src.rdata; - - /* - * Call any supplements that want to know about a response - * with any received data. - */ - AST_RWLIST_RDLOCK(&supplements); - AST_LIST_TRAVERSE(&supplements, supplement, next) { - if (supplement->incoming_response - && does_method_match(&challenge->msg_info.cseq->method.name, - supplement->method)) { - supplement->incoming_response(req_data->endpoint, challenge); + if (e->type == PJSIP_EVENT_TSX_STATE) { + switch(e->body.tsx_state.type) { + case PJSIP_EVENT_TRANSPORT_ERROR: + case PJSIP_EVENT_TIMER: + /* + * Check the request status on transport error or timeout. A transport + * error can occur when a TCP socket closes and that can be the result + * of a 503. Also we may need to failover on a timeout (408). + */ + if (check_request_status(req_data, e)) { + return; } - } - AST_RWLIST_UNLOCK(&supplements); + break; + case PJSIP_EVENT_RX_MSG: + challenge = e->body.tsx_state.src.rdata; - if (check_request_status(req_data, e)) { /* - * Request with challenge response or failover sent. - * Passed our req_data ref to the new request. + * Call any supplements that want to know about a response + * with any received data. */ - return; + AST_RWLIST_RDLOCK(&supplements); + AST_LIST_TRAVERSE(&supplements, supplement, next) { + if (supplement->incoming_response + && does_method_match(&challenge->msg_info.cseq->method.name, + supplement->method)) { + supplement->incoming_response(req_data->endpoint, challenge); + } + } + AST_RWLIST_UNLOCK(&supplements); + + if (check_request_status(req_data, e)) { + /* + * Request with challenge response or failover sent. + * Passed our req_data ref to the new request. + */ + return; + } + break; + default: + ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type); + break; } - break; - default: - ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type); - break; } if (req_data->callback) { From f6c33771f660c3ad15bc554b355cb21e83c85e36 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 9 May 2016 14:27:53 -0500 Subject: [PATCH 0454/1578] Bridging: introduce "invisible" bridges. Invisible bridges function the same as normal bridges, but they have the following restrictions: * They never show up in CLI, AMI, or ARI queries. * They do not have Stasis messages published about them. Invisible bridges' main use is for when use of the bridging system is desired, but the bridge should not be known to users of the Asterisk system. ASTERISK-25925 Change-Id: I804a209d3181d7c54e3d61a60eb462e7ce0e3670 --- include/asterisk/bridge_features.h | 2 ++ main/bridge.c | 24 ++++++++++++++---------- main/manager_bridges.c | 2 +- main/stasis_bridges.c | 13 +++++++++++++ main/stasis_channels.c | 4 +++- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/include/asterisk/bridge_features.h b/include/asterisk/bridge_features.h index df01a0dca8c..7fcb85bd20b 100644 --- a/include/asterisk/bridge_features.h +++ b/include/asterisk/bridge_features.h @@ -53,6 +53,8 @@ enum ast_bridge_feature_flags { AST_BRIDGE_FLAG_TRANSFER_PROHIBITED = (1 << 8), /*! Bridge transfers require transfer of entire bridge rather than individual channels */ AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY = (1 << 9), + /*! Bridge is invisible to AMI/CLI/ARI/etc. */ + AST_BRIDGE_FLAG_INVISIBLE = (1 << 10), }; /*! \brief Flags used for per bridge channel features */ diff --git a/main/bridge.c b/main/bridge.c index ce6b9601bef..68ac24bba54 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -759,11 +759,13 @@ struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabiliti ast_set_flag(&self->feature_flags, flags); self->allowed_capabilities = capabilities; - if (bridge_topics_init(self) != 0) { - ast_log(LOG_WARNING, "Bridge %s: Could not initialize topics\n", - self->uniqueid); - ao2_ref(self, -1); - return NULL; + if (!(flags & AST_BRIDGE_FLAG_INVISIBLE)) { + if (bridge_topics_init(self) != 0) { + ast_log(LOG_WARNING, "Bridge %s: Could not initialize topics\n", + self->uniqueid); + ao2_ref(self, -1); + return NULL; + } } /* Use our helper function to find the "best" bridge technology. */ @@ -793,9 +795,11 @@ struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabiliti return NULL; } - if (!ast_bridge_topic(self)) { - ao2_ref(self, -1); - return NULL; + if (!(flags & AST_BRIDGE_FLAG_INVISIBLE)) { + if (!ast_bridge_topic(self)) { + ao2_ref(self, -1); + return NULL; + } } return self; @@ -4321,8 +4325,8 @@ static struct ast_bridge *acquire_bridge(struct ast_channel *chan) bridge = ast_channel_get_bridge(chan); ast_channel_unlock(chan); - if (bridge - && ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)) { + if (bridge && ast_test_flag(&bridge->feature_flags, + (AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_INVISIBLE))) { ao2_ref(bridge, -1); bridge = NULL; } diff --git a/main/manager_bridges.c b/main/manager_bridges.c index dd3e98b8d5e..2069d507cd7 100644 --- a/main/manager_bridges.c +++ b/main/manager_bridges.c @@ -572,7 +572,7 @@ static int manager_bridge_kick(struct mansession *s, const struct message *m) } } else { bridge = ast_bridge_find_by_id(bridge_uniqueid); - if (!bridge) { + if (!bridge || ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) { astman_send_error(s, m, "Bridge not found"); return 0; } diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c index d06ee14a7a6..0e46edbea3b 100644 --- a/main/stasis_bridges.c +++ b/main/stasis_bridges.c @@ -232,6 +232,10 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup); struct ast_bridge_channel *bridge_channel; + if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) { + return NULL; + } + snapshot = ao2_alloc_options(sizeof(*snapshot), bridge_snapshot_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!snapshot || ast_string_field_init(snapshot, 128)) { @@ -371,6 +375,8 @@ void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from) ast_assert(to != NULL); ast_assert(from != NULL); + ast_assert(ast_test_flag(&to->feature_flags, AST_BRIDGE_FLAG_INVISIBLE) == 0); + ast_assert(ast_test_flag(&from->feature_flags, AST_BRIDGE_FLAG_INVISIBLE) == 0); merge_msg = bridge_merge_message_create(to, from); if (!merge_msg) { @@ -447,6 +453,10 @@ void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *cha RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); + if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) { + return; + } + if (swap) { blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap)); if (!blob) { @@ -468,6 +478,9 @@ void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *cha { RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) { + return; + } msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL); if (!msg) { return; diff --git a/main/stasis_channels.c b/main/stasis_channels.c index eb1f1bc6229..e56d1b928b2 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -256,7 +256,9 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha ast_string_field_set(snapshot, language, ast_channel_language(chan)); if ((bridge = ast_channel_get_bridge(chan))) { - ast_string_field_set(snapshot, bridgeid, bridge->uniqueid); + if (!ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) { + ast_string_field_set(snapshot, bridgeid, bridge->uniqueid); + } ao2_cleanup(bridge); } From 070eab6ed26b1bc287618f0372b8b4489f7479f3 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 24 May 2016 07:28:17 -0300 Subject: [PATCH 0455/1578] res_pjsip_outbound_publish: Ensure publish is valid when explicitly destroying. Recent changes to res_pjsip_outbound_publish have introduced a race condition at shutdown where an outbound publish may be shutdown twice. In this case the first succeeds as a result of the unpublish. In the second invocation since it's been unpublished a task is queued to just destroy the client. This task holds no ref to the publish and as a result the publish may be destroyed before the task is run, causing a crash. This explicit destruction task now holds a reference to the publish to ensure it remains valid. ASTERISK-26053 #close Change-Id: I10789b98add3e50292ee3b33a55a1d9061cec94b --- res/res_pjsip_outbound_publish.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 1c3b0c6444d..53e15a0a48d 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -1125,6 +1125,8 @@ static int explicit_publish_destroy(void *data) ao2_ref(publisher, -1); } + ao2_ref(publisher, -1); + return 0; } @@ -1140,7 +1142,9 @@ static int cancel_and_unpublish(void *obj, void *arg, int flags) /* If the publisher was never started, there's nothing to unpublish, so just * destroy the publication and remove its reference to the publisher. */ - ast_sip_push_task(NULL, explicit_publish_destroy, publisher); + if (ast_sip_push_task(NULL, explicit_publish_destroy, ao2_bump(publisher))) { + ao2_ref(publisher, -1); + } return 0; } From 80ff2c2540544123b1cf040f1a651cbde4ab4e14 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 12 Feb 2016 10:59:44 -0500 Subject: [PATCH 0456/1578] threadpool: Fix potential data race. worker_start checked for ZOMBIE status without holding a lock. All other read/write of worker status are performed with a lock, so this check should do the same. ASTERISK-25777 #close Change-Id: I5e33685a5c26fdb300851989a3b82be8c4e03781 --- main/threadpool.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main/threadpool.c b/main/threadpool.c index 60e1e9a3b47..9cd33ab1a4a 100644 --- a/main/threadpool.c +++ b/main/threadpool.c @@ -1012,6 +1012,7 @@ static void worker_thread_destroy(void *obj) static void *worker_start(void *arg) { struct worker_thread *worker = arg; + enum worker_state saved_state; if (worker->options.thread_start) { worker->options.thread_start(); @@ -1027,6 +1028,7 @@ static void *worker_start(void *arg) } threadpool_active_thread_idle(worker->pool, worker); } + saved_state = worker->state; ast_mutex_unlock(&worker->lock); /* Reaching this portion means the thread is @@ -1037,7 +1039,7 @@ static void *worker_start(void *arg) * that the thread can be removed from the * list of zombie threads. */ - if (worker->state == ZOMBIE) { + if (saved_state == ZOMBIE) { threadpool_zombie_thread_dead(worker->pool, worker); } From 1d60bfcdf1ad7a265177fa35a9d2a55468bbe78f Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 3 May 2016 19:11:20 +0300 Subject: [PATCH 0457/1578] followme: allow disabling callee prompt Add the option 'enable_callee_prompt' to followme.conf. Enabled by default. If disabled, a callee is not prompted to accept or reject the forwarded call. ASTERISK-26064 #close Change-Id: I0a8b19d4cf95c86a07c992813babb9e4a4acfff5 Signed-off-by: Tzafrir Cohen --- CHANGES | 5 ++ apps/app_followme.c | 90 ++++++++++++++++++---------- configs/samples/followme.conf.sample | 8 +++ 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/CHANGES b/CHANGES index 281cff393ca..4916c501547 100644 --- a/CHANGES +++ b/CHANGES @@ -68,6 +68,11 @@ ControlPlayback * Remote files can now be retrieved and played back. See the Playback dialplan application for more details. +FollowMe +------------------ + * It is now possible to disable the prompt from a callee by setting + 'enable_callee_prompt = no' in followme.conf. + Playback ------------------ * Remote files can now be retrieved and played back via the Playback and other diff --git a/apps/app_followme.c b/apps/app_followme.c index 106902043a5..7d13bb4b41b 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -168,6 +168,8 @@ struct call_followme { char context[AST_MAX_CONTEXT]; /*!< Context to dial from */ unsigned int active; /*!< Profile is active (1), or disabled (0). */ int realtime; /*!< Cached from realtime */ + /*! Allow callees to accept/reject the forwarded call */ + unsigned int enable_callee_prompt:1; char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */ char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */ char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */ @@ -198,6 +200,8 @@ struct fm_args { unsigned int pending_out_connected_update:1; /*! TRUE if caller has a pending hold request for the winning call. */ unsigned int pending_hold:1; + /*! TRUE if callees will be prompted to answer */ + unsigned int enable_callee_prompt:1; /*! Music On Hold Class suggested by caller hold for winning call. */ char suggested_moh[MAX_MUSICCLASS]; char context[AST_MAX_CONTEXT]; @@ -268,6 +272,7 @@ static const char *defaultmoh = "default"; /*!< Default Music-On-Hold Class static char takecall[MAX_YN_STRING] = "1"; static char nextindp[MAX_YN_STRING] = "2"; +static int enable_callee_prompt = 1; static char callfromprompt[PATH_MAX] = "followme/call-from"; static char norecordingprompt[PATH_MAX] = "followme/no-recording"; static char optionsprompt[PATH_MAX] = "followme/options"; @@ -313,6 +318,7 @@ static struct call_followme *alloc_profile(const char *fmname) ast_copy_string(f->name, fmname, sizeof(f->name)); f->moh[0] = '\0'; f->context[0] = '\0'; + f->enable_callee_prompt = enable_callee_prompt; ast_copy_string(f->takecall, takecall, sizeof(f->takecall)); ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp)); ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt)); @@ -343,6 +349,8 @@ static void profile_set_param(struct call_followme *f, const char *param, const ast_copy_string(f->moh, val, sizeof(f->moh)); else if (!strcasecmp(param, "context")) ast_copy_string(f->context, val, sizeof(f->context)); + else if (!strcasecmp(param, "enable_callee_prompt")) + f->enable_callee_prompt = ast_true(val); else if (!strcasecmp(param, "takecall")) ast_copy_string(f->takecall, val, sizeof(f->takecall)); else if (!strcasecmp(param, "declinecall")) @@ -398,6 +406,7 @@ static int reload_followme(int reload) char *numberstr; int timeout; int numorder; + const char* enable_callee_prompt_str; const char *takecallstr; const char *declinecallstr; const char *tmpstr; @@ -430,6 +439,12 @@ static int reload_followme(int reload) featuredigittimeout = 5000; } + if ((enable_callee_prompt_str = ast_variable_retrieve(cfg, "general", + "enable_callee_prompt")) && + !ast_strlen_zero(enable_callee_prompt_str)) { + enable_callee_prompt = ast_true(enable_callee_prompt_str); + } + if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) { ast_copy_string(takecall, takecallstr, sizeof(takecall)); } @@ -651,26 +666,30 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) { ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n", ast_channel_name(tmpuser->ochan)); - if (!ast_strlen_zero(tpargs->namerecloc)) { - tmpuser->state = 1; - tmpuser->digts = 0; - if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) { - ast_sched_runq(ast_channel_sched(tmpuser->ochan)); + if (tpargs->enable_callee_prompt) { + if (!ast_strlen_zero(tpargs->namerecloc)) { + tmpuser->state = 1; + tmpuser->digts = 0; + if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) { + ast_sched_runq(ast_channel_sched(tmpuser->ochan)); + } else { + ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); + clear_caller(tmpuser); + continue; + } } else { - ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); - clear_caller(tmpuser); - continue; + tmpuser->state = 2; + tmpuser->digts = 0; + if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan))) + ast_sched_runq(ast_channel_sched(tmpuser->ochan)); + else { + ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); + clear_caller(tmpuser); + continue; + } } } else { - tmpuser->state = 2; - tmpuser->digts = 0; - if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan))) - ast_sched_runq(ast_channel_sched(tmpuser->ochan)); - else { - ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); - clear_caller(tmpuser); - continue; - } + tmpuser->state = 3; } } if (ast_channel_stream(tmpuser->ochan)) { @@ -787,23 +806,28 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us /* If call has been answered, then the eventual hangup is likely to be normal hangup */ ast_channel_hangupcause_set(winner, AST_CAUSE_NORMAL_CLEARING); ast_channel_hangupcause_set(caller, AST_CAUSE_NORMAL_CLEARING); - ast_verb(3, "Starting playback of %s\n", callfromname); - if (!ast_strlen_zero(tpargs->namerecloc)) { - if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) { - ast_sched_runq(ast_channel_sched(winner)); - tmpuser->state = 1; + if (tpargs->enable_callee_prompt) { + ast_verb(3, "Starting playback of %s\n", callfromname); + if (!ast_strlen_zero(tpargs->namerecloc)) { + if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) { + ast_sched_runq(ast_channel_sched(winner)); + tmpuser->state = 1; + } else { + ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); + clear_caller(tmpuser); + } } else { - ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); - clear_caller(tmpuser); + tmpuser->state = 2; + if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan))) + ast_sched_runq(ast_channel_sched(tmpuser->ochan)); + else { + ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); + clear_caller(tmpuser); + } } } else { + ast_verb(3, "Skip playback of caller name / norecording\n"); tmpuser->state = 2; - if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan))) - ast_sched_runq(ast_channel_sched(tmpuser->ochan)); - else { - ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); - clear_caller(tmpuser); - } } break; case AST_CONTROL_BUSY: @@ -927,6 +951,11 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us break; } } + if (!tpargs->enable_callee_prompt && tmpuser) { + ast_debug(1, "Taking call with no prompt\n"); + ast_frfree(f); + return tmpuser->ochan; + } if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) { int cmp_len; @@ -1365,6 +1394,7 @@ static int app_exec(struct ast_channel *chan, const char *data) /* Lock the profile lock and copy out everything we need to run with before unlocking it again */ ast_mutex_lock(&f->lock); + targs->enable_callee_prompt = f->enable_callee_prompt; targs->mohclass = ast_strdupa(f->moh); ast_copy_string(targs->context, f->context, sizeof(targs->context)); ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall)); diff --git a/configs/samples/followme.conf.sample b/configs/samples/followme.conf.sample index a233948bf90..7e1d40ff431 100644 --- a/configs/samples/followme.conf.sample +++ b/configs/samples/followme.conf.sample @@ -5,6 +5,11 @@ featuredigittimeout=>5000 ; The number of ms to wait for a digit input for the callee on whether to take the call or ; not before we consider them "done" entering digits. ; +enable_callee_prompt=>true +; Enable prompting a callee to either accept or reject the forwarded call. +; If disabled, the optional prompting for caller name (option 'a') is +; likewise disabled. Enabled by default. +; takecall=>1 ; The global default keypress for the callee to take taking the current call. This can be ; a single digit or multiple digits. Default is "1". @@ -54,6 +59,9 @@ number=>01233456,25 ; step to make a choice on whether to take the call or not. That being the case, ; you may want to make the timeout on the last step longer to give enough time to ; make the choice to accept or not. +enable_callee_prompt=>true +; Enable prompting the callee to accept the forwarded call. The default +; is the global value. takecall=>1 ; The keypress for the callee to take taking the current call. This can be ; a single digit or multiple digits. Default is the global default. From 7d44d12816ce46c742a5a621e400344d025bb007 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 25 May 2016 18:30:07 -0500 Subject: [PATCH 0458/1578] pjsip_distributor.c: Use correct rdata info access method. The pjproject doxygen for rdata->msg_info.info says to call pjsip_rx_data_get_info() instead of accessing the struct member directly. You need to call the function mostly because the function will generate the struct member value if it is not already setup. Change-Id: Iafe8b01242b7deb0ebfdc36685e21374a43936d2 --- res/res_pjsip/pjsip_distributor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 2ab954eb04b..0d3df06f071 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -257,7 +257,8 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); if (!tsx) { - ast_debug(3, "Could not find matching transaction for %s\n", rdata->msg_info.info); + ast_debug(3, "Could not find matching transaction for %s\n", + pjsip_rx_data_get_info(rdata)); return NULL; } From b3142e99e4a03c5137a72d87f31f525f0a817f8f Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 20 May 2016 14:56:30 -0400 Subject: [PATCH 0459/1578] app_voicemail: fix bugs, imap mm_status log change to debug Fixed some bugs: - create dirpath when save downloading message from IMAP storage. - create IMAP folder if not exists when saving to IMAP storage - check if file successfully opened before write to it - some IMAP checks - remove non-standard flag 'Unseen' etc Change to debug IMAP mm_status log instead of verbose. Remove unused X-Asterisk-VM-Caller-channel message header for security reason. The clients should not know name of peer/endpoint. ASTERISK-26045 #close Change-Id: I7f83d88b69b36934e2539c114b9fb612deed971b --- apps/app_voicemail.c | 226 ++++++++++++++++++++++++++++++------------- 1 file changed, 160 insertions(+), 66 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index e7de8a2b2b3..1d5b2dcb39c 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -1088,7 +1088,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context); static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir, - signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id); + signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id, int forwardintro); static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain); static int vm_play_folder_name(struct ast_channel *chan, char *mbox); static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag); @@ -2174,6 +2174,7 @@ static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_ { struct vm_state *vms_p; char *file, *filename; + char dest[PATH_MAX]; char *attachment; int i; BODY *body; @@ -2237,6 +2238,7 @@ static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_ if (!strcmp(filename, file)) { ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn)); vms_p->msgArray[vms_p->curmsg] = i + 1; + create_dirpath(dest, sizeof(dest), vmu->context, vms_p->username, ""); save_body(body, vms_p, "2", attachment, 0); ret = 0; break; @@ -2369,7 +2371,8 @@ static int imap_retrieve_file(const char *dir, const int msgnum, const char *mai snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt"); if (!(text_file_ptr = fopen(text_file, "w"))) { - ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno)); + ast_log(LOG_ERROR, "Unable to open/create file %s: %s\n", text_file, strerror(errno)); + goto exit; } fprintf(text_file_ptr, "%s\n", "[message]"); @@ -2709,8 +2712,8 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char } make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX", - S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL), - S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL), + chan ? S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL) : NULL, + chan ? S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL) : NULL, fn, introfn, fmt, duration, 1, chan, NULL, 1, flag, msg_id); /* read mail file to memory */ len = ftell(p); @@ -3018,6 +3021,10 @@ static int init_mailstream(struct vm_state *vms, int box) ast_mutex_lock(&vms->lock); ast_mutex_lock(&mail_open_lock); vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL); + /* Create the folder if it dosn't exist */ + if (vms->mailstream && !mail_status(vms->mailstream, tmp, SA_UIDNEXT)) { + mail_create(vms->mailstream, tmp); + } ast_mutex_unlock(&mail_open_lock); ast_mutex_unlock(&vms->lock); if (vms->mailstream == NIL) { @@ -3112,7 +3119,15 @@ static void write_file(char *filename, char *buffer, unsigned long len) { FILE *output; - output = fopen (filename, "w"); + if (!filename || !buffer) { + return; + } + + if (!(output = fopen(filename, "w"))) { + ast_log(LOG_ERROR, "Unable to open/create file %s: %s\n", filename, strerror(errno)); + return; + } + if (fwrite(buffer, len, 1, output) != 1) { if (ferror(output)) { ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno)); @@ -3247,18 +3262,30 @@ void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes) void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status) { - ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox); - if (status->flags & SA_MESSAGES) - ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages); - if (status->flags & SA_RECENT) - ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent); - if (status->flags & SA_UNSEEN) - ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen); - if (status->flags & SA_UIDVALIDITY) - ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity); - if (status->flags & SA_UIDNEXT) - ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext); - ast_log(AST_LOG_NOTICE, "\n"); + struct ast_str *str; + if (!DEBUG_ATLEAST(5) || !(str = ast_str_create(MAX_OBJECT_FIELD))) { + return; + } + + ast_str_append(&str, 0, " Mailbox %s", mailbox); + if (status->flags & SA_MESSAGES) { + ast_str_append(&str, 0, ", %lu messages", status->messages); + } + if (status->flags & SA_RECENT) { + ast_str_append(&str, 0, ", %lu recent", status->recent); + } + if (status->flags & SA_UNSEEN) { + ast_str_append(&str, 0, ", %lu unseen", status->unseen); + } + if (status->flags & SA_UIDVALIDITY) { + ast_str_append(&str, 0, ", %lu UID validity", status->uidvalidity); + } + if (status->flags & SA_UIDNEXT) { + ast_str_append(&str, 0, ", %lu next UID", status->uidnext); + } + ast_log(LOG_DEBUG, "%s\n", ast_str_buffer(str)); + + ast_free(str); } @@ -3446,8 +3473,9 @@ static struct vm_state *get_vm_state_by_imapuser(const char *user, int interacti if (interactive) { struct vm_state *vms; pthread_once(&ts_vmstate.once, ts_vmstate.key_init); - vms = pthread_getspecific(ts_vmstate.key); - return vms; + if ((vms = pthread_getspecific(ts_vmstate.key)) && vms->imapuser && !strcmp(vms->imapuser, user)) { + return vms; + } } AST_LIST_LOCK(&vmstates); @@ -3485,8 +3513,10 @@ static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char if (interactive) { struct vm_state *vms; pthread_once(&ts_vmstate.once, ts_vmstate.key_init); - vms = pthread_getspecific(ts_vmstate.key); - return vms; + if ((vms = pthread_getspecific(ts_vmstate.key)) && vms->username && vms->context && + !strcmp(vms->username,mailbox) && !strcmp(vms->context, local_context)) { + return vms; + } } AST_LIST_LOCK(&vmstates); @@ -5133,7 +5163,9 @@ static void make_email_file(FILE *p, first_line = 0; } - if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) { + if (msgnum <= -1) { + fprintf(p, "Subject: New greeting '%s' on %s." ENDL, greeting_attachment, date); + } else if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) { char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject; struct ast_channel *ast; if ((ast = ast_dummy_channel_alloc())) { @@ -5186,9 +5218,8 @@ static void make_email_file(FILE *p, fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox); #endif /* flag added for Urgent */ - fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag); + fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, S_OR(flag, "")); fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan ? ast_channel_priority(chan) : 0); - fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan ? ast_channel_name(chan) : ""); fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum); fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname); fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration); @@ -5219,7 +5250,11 @@ static void make_email_file(FILE *p, fprintf(p, "--%s" ENDL, bound); } fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset); - if (emailbody || vmu->emailbody) { + if (msgnum <= -1) { + fprintf(p, "This message is to let you know that your greeting '%s' was changed on %s." ENDL + "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, + greeting_attachment, date); + } else if (emailbody || vmu->emailbody) { char* e_body = vmu->emailbody ? vmu->emailbody : emailbody; struct ast_channel *ast; if ((ast = ast_dummy_channel_alloc())) { @@ -5245,7 +5280,7 @@ static void make_email_file(FILE *p, } else { ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); } - } else if (msgnum > -1) { + } else { if (strcmp(vmu->mailbox, mailbox)) { /* Forwarded type */ struct ast_config *msg_cfg; @@ -5290,9 +5325,6 @@ static void make_email_file(FILE *p, ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date); } - } else { - fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL - "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date); } if (imap || attach_user_voicemail) { @@ -6851,7 +6883,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan)); goto leave_vm_out; } - res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag, msg_id); + res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag, msg_id, 0); if (txt) { fprintf(txt, "flag=%s\n", flag); @@ -7055,6 +7087,7 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg char sequence[10]; char mailbox[256]; int res; + int curr_mbox; /* get the real IMAP message number for this message */ snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]); @@ -7064,26 +7097,35 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg /* if save to Old folder, put in INBOX as read */ if (box == OLD_FOLDER) { mail_setflag(vms->mailstream, sequence, "\\Seen"); - mail_clearflag(vms->mailstream, sequence, "\\Unseen"); } else if (box == NEW_FOLDER) { - mail_setflag(vms->mailstream, sequence, "\\Unseen"); mail_clearflag(vms->mailstream, sequence, "\\Seen"); } if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) { ast_mutex_unlock(&vms->lock); return 0; } - /* Create the folder if it don't exist */ + + /* get the current mailbox so that we can point the mailstream back to it later */ + curr_mbox = get_folder_by_name(vms->curbox); + + /* Create the folder if it dosn't exist */ imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1); /* Get the full mailbox name */ - ast_debug(5, "Checking if folder exists: %s\n", mailbox); - if (mail_create(vms->mailstream, mailbox) == NIL) - ast_debug(5, "Folder exists.\n"); - else - ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box)); - if (move) { - res = !mail_move(vms->mailstream, sequence, (char *) mbox(vmu, box)); + if (vms->mailstream && !mail_status(vms->mailstream, mailbox, SA_UIDNEXT)) { + if (mail_create(vms->mailstream, mailbox) != NIL) { + ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box)); + } + } + + /* restore previous mbox stream */ + if (init_mailstream(vms, curr_mbox) || !vms->mailstream) { + ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n"); + res = -1; } else { - res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box)); + if (move) { + res = !mail_move(vms->mailstream, sequence, (char *) mbox(vmu, box)); + } else { + res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box)); + } } ast_mutex_unlock(&vms->lock); return res; @@ -7814,9 +7856,9 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, } make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg); strncat(vms->introfn, "intro", sizeof(vms->introfn)); - ast_play_and_wait(chan, INTRO); + ast_play_and_wait(chan, "vm-record-prepend"); ast_play_and_wait(chan, "beep"); - cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag, msg_id); + cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag, msg_id, 1); if (cmd == -1) { break; } @@ -8085,6 +8127,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user); char *stringp; const char *s; + const char mailbox_context[256]; int saved_messages = 0; int valid_extensions = 0; char *dir; @@ -8193,20 +8236,44 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st /* start optimistic */ valid_extensions = 1; while (s) { + snprintf((char*)mailbox_context, sizeof(mailbox_context), "%s@%s", s, context ? context : "default"); if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) { int oldmsgs; int newmsgs; int capacity; - if (inboxcount(s, &newmsgs, &oldmsgs)) { - ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s); + + if (inboxcount(mailbox_context, &newmsgs, &oldmsgs)) { + ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", mailbox_context); /* Shouldn't happen, but allow trying another extension if it does */ res = ast_play_and_wait(chan, "pbx-invalid"); valid_extensions = 0; break; } +#ifdef IMAP_STORAGE + if (!(dstvms = get_vm_state_by_mailbox(s, context, 0))) { + if (!(dstvms = create_vm_state_from_user(receiver))) { + ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n"); + /* Shouldn't happen, but allow trying another extension if it does */ + res = ast_play_and_wait(chan, "pbx-invalid"); + valid_extensions = 0; + break; + } + } + check_quota(dstvms, imapfolder); + if (dstvms->quota_limit && dstvms->quota_usage >= dstvms->quota_limit) { + ast_log(LOG_NOTICE, "Mailbox '%s' is exceeded quota %u >= %u\n", mailbox_context, dstvms->quota_usage, dstvms->quota_limit); + res = ast_play_and_wait(chan, "vm-mailboxfull"); + valid_extensions = 0; + while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) { + inprocess_count(vmtmp->mailbox, vmtmp->context, -1); + free_user(vmtmp); + } + break; + } +#endif capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1); if ((newmsgs + oldmsgs) >= capacity) { - ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity); + ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", mailbox_context, capacity); res = ast_play_and_wait(chan, "vm-mailboxfull"); valid_extensions = 0; while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) { @@ -8226,7 +8293,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) { free_user(receiver); } - ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s); + ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", mailbox_context); /* "I am sorry, that's not a valid extension. Please try again." */ res = ast_play_and_wait(chan, "pbx-invalid"); valid_extensions = 0; @@ -8306,7 +8373,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st if (!dstvms->mailstream) { ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox); } else { - copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id); + copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id); run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str); } } else { @@ -8342,10 +8409,6 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st res = ast_play_and_wait(chan, "vm-messages"); if (!res) res = ast_play_and_wait(chan, "vm-saved"); */ -#ifdef IMAP_STORAGE - /* If forwarded with intro, DON'T PLAY THIS MESSAGE AGAIN! */ - if (ast_strlen_zero(vmstmp.introfn)) -#endif res = ast_play_and_wait(chan, "vm-msgforwarded"); } #ifndef IMAP_STORAGE @@ -8814,6 +8877,7 @@ static int imap_delete_old_greeting (char *dir, struct vm_state *vms) char arg[10]; int i; BODY* body; + int curr_mbox; file = strrchr(ast_strdupa(dir), '/'); if (file) { @@ -8824,6 +8888,16 @@ static int imap_delete_old_greeting (char *dir, struct vm_state *vms) } ast_mutex_lock(&vms->lock); + + /* get the current mailbox so that we can point the mailstream back to it later */ + curr_mbox = get_folder_by_name(vms->curbox); + + if (init_mailstream(vms, GREETINGS_FOLDER) || !vms->mailstream) { + ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n"); + ast_mutex_unlock(&vms->lock); + return -1; + } + for (i = 0; i < vms->mailstream->nmsgs; i++) { mail_fetchstructure(vms->mailstream, i + 1, &body); /* We have the body, now we extract the file name of the first attachment. */ @@ -8841,6 +8915,14 @@ static int imap_delete_old_greeting (char *dir, struct vm_state *vms) } } mail_expunge(vms->mailstream); + + if (curr_mbox != -1) { + /* restore previous mbox stream */ + if (init_mailstream(vms, curr_mbox) || !vms->mailstream) { + ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n"); + } + } + ast_mutex_unlock(&vms->lock); return 0; } @@ -10348,7 +10430,7 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct if (ast_test_flag(vmu, VM_FORCENAME)) { snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username); if (ast_fileexists(prefile, NULL, NULL) < 1) { - cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } @@ -10358,14 +10440,14 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct if (ast_test_flag(vmu, VM_FORCEGREET)) { snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username); if (ast_fileexists(prefile, NULL, NULL) < 1) { - cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username); if (ast_fileexists(prefile, NULL, NULL) < 1) { - cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } @@ -10447,15 +10529,15 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct switch (cmd) { case '1': /* Record your unavailable message */ snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); break; case '2': /* Record your busy message */ snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); break; case '3': /* Record greeting */ snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); break; case '4': /* manage the temporary greeting */ cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain); @@ -10589,7 +10671,7 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st retries = 0; RETRIEVE(prefile, -1, vmu->mailbox, vmu->context); if (ast_fileexists(prefile, NULL, NULL) <= 0) { - cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); if (cmd == -1) { break; } @@ -10597,7 +10679,7 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st } else { switch (cmd) { case '1': - cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL); + cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0); break; case '2': DELETE(prefile, -1, prefile, vmu); @@ -11876,7 +11958,13 @@ static int vm_execmain(struct ast_channel *chan, const char *data) cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain); if (useadsi) adsi_status(chan, &vms); - break; + /* Reopen play_folder */ + res = open_mailbox(&vms, vmu, play_folder); + if (res < 0) { + goto out; + } + vms.starting = 1; + break; default: /* Nothing */ ast_test_suite_event_notify("PLAYBACK", "Message: instructions"); cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent); @@ -15109,7 +15197,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir, - signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id) + signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id, int forwardintro) { /* Record message & let caller review or re-record it, or set options if applicable */ int res = 0; @@ -15151,7 +15239,9 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re ast_verb(3, "Saving message as is\n"); if (!outsidecaller) ast_filerename(tempfile, recordfile, NULL); - ast_stream_and_wait(chan, "vm-msgsaved", ""); + if (!forwardintro) { + ast_stream_and_wait(chan, "vm-msgsaved", ""); + } if (!outsidecaller) { /* Saves to IMAP server only if imapgreeting=yes */ STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag, msg_id); @@ -15174,7 +15264,11 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re ast_verb(3, "Recording the message\n"); if (recorded && outsidecaller) { - cmd = ast_play_and_wait(chan, INTRO); + if (forwardintro) { + cmd = ast_play_and_wait(chan, "vm-record-prepend"); + } else { + cmd = ast_play_and_wait(chan, INTRO); + } cmd = ast_play_and_wait(chan, "beep"); } recorded = 1; @@ -15295,10 +15389,10 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re } return cmd; default: - /* If the caller is an ouside caller, and the review option is enabled, + /* If the caller is an ouside caller and the review option is enabled or it's forward intro allow them to review the message, but let the owner of the box review their OGM's */ - if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW)) + if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW) && !forwardintro) return cmd; if (msg_exists) { cmd = ast_play_and_wait(chan, "vm-review"); From 574c9e77ebd535daa39607c3a47d11fa0a7de261 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Tue, 24 May 2016 17:56:49 -0400 Subject: [PATCH 0460/1578] res_pjsip: chatty verbose messages There are a lot of verbose messages about Endpoint and Contact status changes if there are many dynamic endpoints. The patch sets verbose level 2 for Endpoint status changes and verbose level 3 for Contact status changes. ASTERISK-26055 #close Change-Id: Ie64e261ddbbc41bfff0f0190241152cc123fe6d7 --- res/res_pjsip/pjsip_configuration.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 8b6fe61d8d6..3c4949573a6 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -131,7 +131,7 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) } } - ast_verb(1, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint)); + ast_verb(2, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint)); } else { ast_endpoint_set_state(endpoint, AST_ENDPOINT_OFFLINE); blob = ast_json_pack("{s: s}", "peer_status", "Unreachable"); @@ -144,7 +144,7 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) } } - ast_verb(1, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint)); + ast_verb(2, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint)); } ast_free(regcontext); @@ -173,7 +173,7 @@ static void persistent_endpoint_contact_created_observer(const void *object) contact_status->status = CREATED; - ast_verb(1, "Contact %s/%s has been created\n",contact->aor, contact->uri); + ast_verb(2, "Contact %s/%s has been created\n",contact->aor, contact->uri); ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); ao2_cleanup(contact_status); @@ -192,7 +192,7 @@ static void persistent_endpoint_contact_deleted_observer(const void *object) return; } - ast_verb(1, "Contact %s/%s has been deleted\n", contact->aor, contact->uri); + ast_verb(2, "Contact %s/%s has been deleted\n", contact->aor, contact->uri); ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "-1", 1.0, ast_sip_get_contact_status_label(contact_status->status)); ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, @@ -220,7 +220,7 @@ static void persistent_endpoint_contact_status_observer(const void *object) } if (contact_status->status != contact_status->last_status) { - ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", contact_status->aor, contact_status->uri, + ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n", contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); From 31f17abe449c2a9b43ef4e820792fb52d4b27d7a Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 19 May 2016 15:56:26 -0400 Subject: [PATCH 0461/1578] res_pjsip: add "via_addr", "via_port", "call_id" to contact As res_pjsip_nat rewrites contact's address, only the last Via header can contain the source address of registered endpoint. Also Call-Id header may contain the source address of registered endpoint. Added "via_addr", "via_port", "call_id" to contact. Added new fields ViaAddress, CallID to AMI event ContactStatus. ASTERISK-26011 Change-Id: I36bcc0bf422b3e0623680152d80486aeafe4c576 --- CHANGES | 6 ++++ ...184_res_pjsip_add_contact_via_addr_and_.py | 25 +++++++++++++++ include/asterisk/res_pjsip.h | 8 +++++ main/stasis_endpoints.c | 6 ++++ res/res_pjsip.c | 28 ++++++++++++++++ res/res_pjsip/location.c | 17 ++++++++++ res/res_pjsip/pjsip_options.c | 10 ++++++ res/res_pjsip_registrar.c | 32 +++++++++++++++++-- 8 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py diff --git a/CHANGES b/CHANGES index 281cff393ca..7b129e03ad2 100644 --- a/CHANGES +++ b/CHANGES @@ -328,6 +328,12 @@ res_fax res_pjsip ------------------ + * Added "via_addr", "via_port", "call_id" to contacts. + As res_pjsip_nat rewrites contact's address, only the last Via header + can contain the source address of registered endpoint. + Also Call-Id header may contain the source address of registered endpoint. + Added new fields ViaAddress,CallID to AMI event ContactStatus + * Endpoint IP Access Controls Added new configuration Endpoint options: "acl" - list of IP ACL section names in acl.conf diff --git a/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py b/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py new file mode 100644 index 00000000000..893d9d82e7a --- /dev/null +++ b/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py @@ -0,0 +1,25 @@ +"""res_pjsip: add contact via_addr and callid + +Revision ID: a845e4d8ade8 +Revises: bca7113d796f +Create Date: 2016-05-19 15:51:33.410852 + +""" + +# revision identifiers, used by Alembic. +revision = 'a845e4d8ade8' +down_revision = 'bca7113d796f' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_contacts', sa.Column('via_addr', sa.String(40))) + op.add_column('ps_contacts', sa.Column('via_port', sa.Integer)) + op.add_column('ps_contacts', sa.Column('call_id', sa.String(255))) + +def downgrade(): + op.drop_column('ps_contacts', 'via_addr') + op.drop_column('ps_contacts', 'via_port') + op.drop_column('ps_contacts', 'call_id') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index cf8c719d5b3..50d02d9808f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -250,6 +250,12 @@ struct ast_sip_contact { struct ast_sip_endpoint *endpoint; /*! Asterisk Server name */ AST_STRING_FIELD_EXTENDED(reg_server); + /*! IP-address of the Via header in REGISTER request */ + AST_STRING_FIELD_EXTENDED(via_addr); + /* Port of the Via header in REGISTER request */ + int via_port; + /*! Content of the Call-ID header in REGISTER request */ + AST_STRING_FIELD_EXTENDED(call_id); }; #define CONTACT_STATUS "contact_status" @@ -1093,6 +1099,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na */ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint); /*! @@ -1114,6 +1121,7 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, */ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint); /*! diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index 14d3d0ca1e5..2d114210b75 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -104,6 +104,12 @@ ASTERISK_REGISTER_FILE() Absolute time that this contact is no longer valid after + + IP address:port of the last Via header in REGISTER request + + + Content of the Call-ID header in REGISTER request + diff --git a/res/res_pjsip.c b/res/res_pjsip.c index bebe941b511..8fc3c530e12 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1175,6 +1175,28 @@ Asterisk Server name on which SIP endpoint registered. + + IP-address of the last Via header from registration. + + The last Via header should contain the address of UA which sent the request. + The IP-address of the last Via header is automatically stored based on data present + in incoming SIP REGISTER requests and is not intended to be configured manually. + + + + IP-port of the last Via header from registration. + + The IP-port of the last Via header is automatically stored based on data present + in incoming SIP REGISTER requests and is not intended to be configured manually. + + + + Call-ID header from registration. + + The Call-ID header is automatically stored based on data present + in incoming SIP REGISTER requests and is not intended to be configured manually. + + The configuration for a location of an endpoint @@ -1967,6 +1989,12 @@ Absolute time that this contact is no longer valid after + + IP address:port of the last Via header in REGISTER request + + + Content of the Call-ID header in REGISTER request + diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index fd6db6edc18..43e6ea40f43 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -121,6 +121,8 @@ static void *contact_alloc(const char *name) } ast_string_field_init_extended(contact, reg_server); + ast_string_field_init_extended(contact, via_addr); + ast_string_field_init_extended(contact, call_id); /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) { @@ -303,6 +305,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint) { char name[MAX_OBJECT_FIELD * 2 + 3]; @@ -337,6 +340,15 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri ast_string_field_set(contact, reg_server, ast_config_AST_SYSTEM_NAME); } + if (!ast_strlen_zero(via_addr)) { + ast_string_field_set(contact, via_addr, via_addr); + } + contact->via_port = via_port; + + if (!ast_strlen_zero(call_id)) { + ast_string_field_set(contact, call_id, call_id); + } + contact->endpoint = ao2_bump(endpoint); return ast_sorcery_create(ast_sip_get_sorcery(), contact); @@ -344,6 +356,7 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint) { int res; @@ -356,6 +369,7 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, ao2_wrlock(lock); res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent, + via_addr, via_port, call_id, endpoint); ao2_unlock(lock); ast_named_lock_put(lock); @@ -1120,6 +1134,9 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); + ast_sorcery_object_field_register(sorcery, "contact", "via_addr", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, via_addr)); + ast_sorcery_object_field_register(sorcery, "contact", "via_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact, via_port)); + ast_sorcery_object_field_register(sorcery, "contact", "call_id", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, call_id)); ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration)); diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 62640fe4e63..1114336bd07 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1156,6 +1156,16 @@ static int format_contact_status(void *obj, void *arg, int flags) ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri); ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent); ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec); + if (!ast_strlen_zero(contact->via_addr)) { + ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr); + if (contact->via_port) { + ast_str_append(&buf, 0, ":%d", contact->via_port); + } + ast_str_append(&buf, 0, "\r\n"); + } + if (!ast_strlen_zero(contact->call_id)) { + ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id); + } ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status)); if (status->status == UNKNOWN) { ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index cbc33ab80f1..0e14ab7868f 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -447,6 +447,13 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co char *user_agent = NULL; pjsip_user_agent_hdr *user_agent_hdr; pjsip_expires_hdr *expires_hdr; + pjsip_via_hdr *via_hdr; + pjsip_via_hdr *via_hdr_last; + char *via_addr = NULL; + int via_port = 0; + pjsip_cid_hdr *call_id_hdr; + char *call_id = NULL; + size_t alloc_size; /* So we don't count static contacts against max_contacts we prune them out from the container */ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL); @@ -484,11 +491,32 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co user_agent_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &USER_AGENT, NULL); if (user_agent_hdr) { - size_t alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; + alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; user_agent = ast_alloca(alloc_size); ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size); } + /* Find the first Via header */ + via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_VIA, NULL); + if (via_hdr) { + /* Find the last Via header */ + while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, + PJSIP_H_VIA, via_hdr->next)) != NULL) { + via_hdr_last = via_hdr; + } + alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1; + via_addr = ast_alloca(alloc_size); + ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size); + via_port=via_hdr_last->sent_by.port; + } + + call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL); + if (call_id_hdr) { + alloc_size = pj_strlen(&call_id_hdr->id) + 1; + call_id = ast_alloca(alloc_size); + ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size); + } + /* Iterate each provided Contact header and add, update, or delete */ while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { int expiration; @@ -520,7 +548,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co if (ast_sip_location_add_contact_nolock(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, - user_agent, task_data->endpoint)) { + user_agent, via_addr, via_port, call_id, task_data->endpoint)) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", contact_uri, aor_name); continue; From 88d997913faabe81f8b9e7bdaa56742be0d669b9 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 9 May 2016 14:48:51 -0500 Subject: [PATCH 0462/1578] ARI: Re-implement the ARI dial command, allowing for early bridging. ARI dial had been implemented using the Dial API. This made great sense when dialing was 100% separate from bridging. However, if a channel were to be added to a bridge during the dial attempt, there would be a conflict between the dialing thread and the bridging thread. Each would be attempting to read frames from the dialed channel and act on them. The initial attempt to make the two play nice was to have the Dial API suspend the channel in the bridge and stay in charge of the channel until the dial was complete. The problem with this was that it was riddled with potential race conditions. It also was not well-suited for the case where the channel changed which bridge it was in during the dial. This new approach removes the use of the Dial API altogether. Instead, the channel we are dialing is placed into an invisible ARI dialing bridge. The bridge channel thread handles incoming frames from the channel. If the channel is added to a real bridge, it is departed from the invisible bridge and then added to the real bridge. Similarly, if the channel is removed from the real bridge, it is automatically added back to the invisible bridge if the dial attempt is still active. This approach keeps the threading simple by always having the channel being handled by bridge channel threads. ASTERISK-25925 Change-Id: I7750359ddf45fcd45eaec749c5b3822de4a8ddbb --- include/asterisk/stasis_app.h | 29 ++- res/ari/resource_channels.c | 139 ++++++++++--- res/res_stasis.c | 22 +- res/stasis/control.c | 376 ++++++++++++++++++++++++++++------ 4 files changed, 470 insertions(+), 96 deletions(-) diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index 0863f9f98c2..a73461547e0 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -672,6 +672,18 @@ int stasis_app_control_queue_control(struct stasis_app_control *control, */ struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id); +/*! + * \brief Create an invisible bridge of the specified type. + * + * \param type The type of bridge to be created + * \param name Optional name to give to the bridge + * \param id Optional Unique ID to give to the bridge + * + * \return New bridge. + * \return \c NULL on error. + */ +struct ast_bridge *stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id); + /*! * \brief Returns the bridge with the given id. * \param bridge_id Uniqueid of the bridge. @@ -855,20 +867,23 @@ int stasis_app_channel_unreal_set_internal(struct ast_channel *chan); */ int stasis_app_channel_set_internal(struct ast_channel *chan); -struct ast_dial; - /*! * \brief Dial a channel * \param control Control for \c res_stasis. - * \param dial The ast_dial for the outbound channel + * \param dialstring The dialstring to pass to the channel driver + * \param timeout Optional timeout in milliseconds */ -int stasis_app_control_dial(struct stasis_app_control *control, struct ast_dial *dial); +int stasis_app_control_dial(struct stasis_app_control *control, + const char *dialstring, unsigned int timeout); /*! - * \brief Get dial structure on a control + * \brief Let Stasis app internals shut down + * + * This is called when res_stasis is unloaded. It ensures that + * the Stasis app internals can free any resources they may have + * allocated during the time that res_stasis was loaded. */ -struct ast_dial *stasis_app_get_dial(struct stasis_app_control *control); - +void stasis_app_control_shutdown(void); /*! @} */ #endif /* _ASTERISK_STASIS_APP_H */ diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index c838bc39cce..d0abcfd25f7 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -48,6 +48,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/format_cache.h" #include "asterisk/core_local.h" #include "asterisk/dial.h" +#include "asterisk/max_forwards.h" #include "resource_channels.h" #include @@ -1500,6 +1501,67 @@ static void *ari_channel_thread(void *data) return NULL; } +struct ast_datastore_info dialstring_info = { + .type = "ARI Dialstring", + .destroy = ast_free_ptr, +}; + +/*! + * \brief Save dialstring onto a channel datastore + * + * This will later be retrieved when it comes time to actually dial the channel + * + * \param chan The channel on which to save the dialstring + * \param dialstring The dialstring to save + * \retval 0 SUCCESS! + * \reval -1 Failure :( + */ +static int save_dialstring(struct ast_channel *chan, const char *dialstring) +{ + struct ast_datastore *datastore; + + datastore = ast_datastore_alloc(&dialstring_info, NULL); + if (!datastore) { + return -1; + } + + datastore->data = ast_strdup(dialstring); + if (!datastore->data) { + ast_datastore_free(datastore); + return -1; + } + + ast_channel_lock(chan); + if (ast_channel_datastore_add(chan, datastore)) { + ast_channel_unlock(chan); + ast_datastore_free(datastore); + return -1; + } + ast_channel_unlock(chan); + + return 0; +} + +/*! + * \brief Retrieve the dialstring from the channel datastore + * + * \pre chan is locked + * \param chan Channel that was previously created in ARI + * \retval NULL Failed to find datastore + * \retval non-NULL The dialstring + */ +static char *restore_dialstring(struct ast_channel *chan) +{ + struct ast_datastore *datastore; + + datastore = ast_channel_datastore_find(chan, &dialstring_info, NULL); + if (!datastore) { + return NULL; + } + + return datastore->data; +} + void ast_ari_channels_create(struct ast_variable *headers, struct ast_ari_channels_create_args *args, struct ast_ari_response *response) @@ -1559,6 +1621,12 @@ void ast_ari_channels_create(struct ast_variable *headers, return; } + if (save_dialstring(chan_data->chan, stuff)) { + ast_ari_response_alloc_failed(response); + chan_data_destroy(chan_data); + return; + } + snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan_data->chan)); if (ast_pthread_create_detached(&thread, NULL, ari_channel_thread, chan_data)) { @@ -1577,8 +1645,8 @@ void ast_ari_channels_dial(struct ast_variable *headers, { RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); RAII_VAR(struct ast_channel *, caller, NULL, ast_channel_cleanup); - struct ast_channel *callee; - struct ast_dial *dial; + RAII_VAR(struct ast_channel *, callee, NULL, ast_channel_cleanup); + char *dialstring; control = find_control(response, args->channel_id); if (control == NULL) { @@ -1595,43 +1663,64 @@ void ast_ari_channels_dial(struct ast_variable *headers, return; } - if (ast_channel_state(callee) != AST_STATE_DOWN) { - ast_channel_unref(callee); + if (ast_channel_state(callee) != AST_STATE_DOWN + && ast_channel_state(callee) != AST_STATE_RESERVED) { ast_ari_response_error(response, 409, "Conflict", "Channel is not in the 'Down' state"); return; } - dial = ast_dial_create(); - if (!dial) { - ast_channel_unref(callee); - ast_ari_response_alloc_failed(response); - return; + /* XXX This is straight up copied from main/dial.c. It's probably good + * to separate this to some common method. + */ + if (caller) { + ast_channel_lock_both(caller, callee); + } else { + ast_channel_lock(callee); } - if (ast_dial_append_channel(dial, callee) < 0) { - ast_channel_unref(callee); - ast_dial_destroy(dial); - ast_ari_response_alloc_failed(response); + dialstring = restore_dialstring(callee); + if (!dialstring) { + ast_channel_unlock(callee); + if (caller) { + ast_channel_unlock(caller); + } + ast_ari_response_error(response, 409, "Conflict", + "Dialing a channel not created by ARI"); return; } - - /* From this point, we don't have to unref the callee channel on - * failure paths because the dial owns the reference to the called - * channel and will unref the channel for us + /* Make a copy of the dialstring just in case some jerk tries to hang up the + * channel before we can actually dial */ + dialstring = ast_strdupa(dialstring); - if (ast_dial_prerun(dial, caller, NULL)) { - ast_dial_destroy(dial); - ast_ari_response_alloc_failed(response); - return; + ast_channel_stage_snapshot(callee); + if (caller) { + ast_channel_inherit_variables(caller, callee); + ast_channel_datastore_inherit(caller, callee); + ast_max_forwards_decrement(callee); + + /* Copy over callerid information */ + ast_party_redirecting_copy(ast_channel_redirecting(callee), ast_channel_redirecting(caller)); + + ast_channel_dialed(callee)->transit_network_select = ast_channel_dialed(caller)->transit_network_select; + + ast_connected_line_copy_from_caller(ast_channel_connected(callee), ast_channel_caller(caller)); + + ast_channel_language_set(callee, ast_channel_language(caller)); + ast_channel_req_accountcodes(callee, caller, AST_CHANNEL_REQUESTOR_BRIDGE_PEER); + if (ast_strlen_zero(ast_channel_musicclass(callee))) + ast_channel_musicclass_set(callee, ast_channel_musicclass(caller)); + + ast_channel_adsicpe_set(callee, ast_channel_adsicpe(caller)); + ast_channel_transfercapability_set(callee, ast_channel_transfercapability(caller)); + ast_channel_unlock(caller); } - ast_dial_set_user_data(dial, control); - ast_dial_set_global_timeout(dial, args->timeout * 1000); + ast_channel_stage_snapshot_done(callee); + ast_channel_unlock(callee); - if (stasis_app_control_dial(control, dial)) { - ast_dial_destroy(dial); + if (stasis_app_control_dial(control, dialstring, args->timeout)) { ast_ari_response_alloc_failed(response); return; } diff --git a/res/res_stasis.c b/res/res_stasis.c index 346be563c1a..e7e6bcaa317 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -749,7 +749,7 @@ static void control_unlink(struct stasis_app_control *control) ao2_cleanup(control); } -struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id) +static struct ast_bridge *bridge_create_common(const char *type, const char *name, const char *id, int invisible) { struct ast_bridge *bridge; char *requested_type, *requested_types = ast_strdupa(S_OR(type, "mixing")); @@ -758,6 +758,10 @@ struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY; + if (invisible) { + flags |= AST_BRIDGE_FLAG_INVISIBLE; + } + while ((requested_type = strsep(&requested_types, ","))) { requested_type = ast_strip(requested_type); @@ -789,6 +793,16 @@ struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, return bridge; } +struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id) +{ + return bridge_create_common(type, name, id, 0); +} + +struct ast_bridge *stasis_app_bridge_create_invisible(const char *type, const char *name, const char *id) +{ + return bridge_create_common(type, name, id, 1); +} + void stasis_app_bridge_destroy(const char *bridge_id) { struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id); @@ -1287,7 +1301,6 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, int r; int command_count; RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup); - struct ast_dial *dial; /* Check to see if a bridge absorbed our hangup frame */ if (ast_check_hangup_locked(chan)) { @@ -1297,7 +1310,6 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, last_bridge = bridge; bridge = ao2_bump(stasis_app_get_bridge(control)); - dial = stasis_app_get_dial(control); if (bridge != last_bridge) { app_unsubscribe_bridge(app, last_bridge); @@ -1306,7 +1318,7 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, } } - if (bridge || dial) { + if (bridge) { /* Bridge/dial is handling channel frames */ control_wait(control); control_dispatch_all(control, chan); @@ -1951,6 +1963,8 @@ static int unload_module(void) ao2_cleanup(app_bridges_playback); app_bridges_playback = NULL; + stasis_app_control_shutdown(); + STASIS_MESSAGE_TYPE_CLEANUP(end_message_type); STASIS_MESSAGE_TYPE_CLEANUP(start_message_type); diff --git a/res/stasis/control.c b/res/stasis/control.c index aa6866aee6d..b255477bf73 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -28,6 +28,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_channels.h" +#include "asterisk/stasis_app.h" #include "command.h" #include "control.h" @@ -43,6 +44,11 @@ ASTERISK_REGISTER_FILE() AST_LIST_HEAD(app_control_rules, stasis_app_control_rule); +/*! + * \brief Indicates if the Stasis app internals are being shut down + */ +static int shutting_down; + struct stasis_app_control { ast_cond_t wait_cond; /*! Queue of commands to dispatch on the channel */ @@ -77,10 +83,6 @@ struct stasis_app_control { * The app for which this control was created */ struct stasis_app *app; - /*! - * If channel is being dialed, the dial structure. - */ - struct ast_dial *dial; /*! * When set, /c app_stasis should exit and continue in the dialplan. */ @@ -825,6 +827,128 @@ struct ast_bridge *stasis_app_get_bridge(struct stasis_app_control *control) } } +/*! + * \brief Singleton dial bridge + * + * The dial bridge is a holding bridge used to hold all + * outbound dialed channels that are not in any "real" ARI-created + * bridge. The dial bridge is invisible, meaning that it does not + * show up in channel snapshots, AMI or ARI output, and no events + * get raised for it. + * + * This is used to keep dialed channels confined to the bridging system + * and unify the threading model used for dialing outbound channels. + */ +static struct ast_bridge *dial_bridge; +AST_MUTEX_DEFINE_STATIC(dial_bridge_lock); + +/*! + * \brief Retrieve a reference to the dial bridge. + * + * If the dial bridge has not been created yet, it will + * be created, otherwise, a reference to the existing bridge + * will be returned. + * + * The caller will need to unreference the dial bridge once + * they are finished with it. + * + * \retval NULL Unable to find/create the dial bridge + * \retval non-NULL A reference to teh dial bridge + */ +static struct ast_bridge *get_dial_bridge(void) +{ + struct ast_bridge *ret_bridge = NULL; + + ast_mutex_lock(&dial_bridge_lock); + + if (shutting_down) { + goto end; + } + + if (dial_bridge) { + ret_bridge = ao2_bump(dial_bridge); + goto end; + } + + dial_bridge = stasis_app_bridge_create_invisible("holding", "dial_bridge", NULL); + if (!dial_bridge) { + goto end; + } + ret_bridge = ao2_bump(dial_bridge); + +end: + ast_mutex_unlock(&dial_bridge_lock); + return ret_bridge; +} + +/*! + * \brief after bridge callback for the dial bridge + * + * The only purpose of this callback is to ensure that the control structure's + * bridge pointer is NULLed + */ +static void dial_bridge_after_cb(struct ast_channel *chan, void *data) +{ + struct stasis_app_control *control = data; + + control->bridge = NULL; +} + +static void dial_bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason, void *data) +{ + struct stasis_app_control *control = data; + + dial_bridge_after_cb(control->channel, data); +} + +/*! + * \brief Add a channel to the singleton dial bridge. + * + * \param control The Stasis control structure + * \param chan The channel to add to the bridge + * \retval -1 Failed + * \retval 0 Success + */ +static int add_to_dial_bridge(struct stasis_app_control *control, struct ast_channel *chan) +{ + struct ast_bridge *bridge; + + bridge = get_dial_bridge(); + if (!bridge) { + return -1; + } + + control->bridge = bridge; + ast_bridge_set_after_callback(chan, dial_bridge_after_cb, dial_bridge_after_cb_failed, control); + if (ast_bridge_impart(bridge, chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { + control->bridge = NULL; + ao2_ref(bridge, -1); + return -1; + } + + ao2_ref(bridge, -1); + + return 0; +} + +/*! + * \brief Depart a channel from a bridge, and potentially add it back to the dial bridge + * + * \param control Take a guess + * \param chan Take another guess + */ +static int depart_channel(struct stasis_app_control *control, struct ast_channel *chan) +{ + ast_bridge_depart(chan); + + if (!ast_check_hangup(chan) && ast_channel_state(chan) != AST_STATE_UP) { + /* Channel is still being dialed, so put it back in the dialing bridge */ + add_to_dial_bridge(control, chan); + } + + return 0; +} + static int bridge_channel_depart(struct stasis_app_control *control, struct ast_channel *chan, void *data) { @@ -843,7 +967,7 @@ static int bridge_channel_depart(struct stasis_app_control *control, ast_debug(3, "%s: Channel departing bridge\n", ast_channel_uniqueid(chan)); - ast_bridge_depart(chan); + depart_channel(control, chan); return 0; } @@ -903,6 +1027,107 @@ static void bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason, ast_bridge_after_cb_reason_string(reason)); } +/*! + * \brief Dial timeout datastore + * + * A datastore is used because a channel may change + * bridges during the course of a dial attempt. This + * may be because the channel changes from the dial bridge + * to a standard bridge, or it may move between standard + * bridges. In order to keep the dial timeout, we need + * to keep the timeout information local to the channel. + * That is what this datastore is for + */ +struct ast_datastore_info timeout_datastore = { + .type = "ARI dial timeout", +}; + +static int hangup_channel(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT); + return 0; +} + +/*! + * \brief Dial timeout + * + * This is a bridge interval hook callback. The interval hook triggering + * means that the dial timeout has been reached. If the channel has not + * been answered by the time this callback is called, then the channel + * is hung up + * + * \param bridge_channel Bridge channel on which interval hook has been called + * \param ignore Ignored + * \return -1 (i.e. remove the interval hook) + */ +static int bridge_timeout(struct ast_bridge_channel *bridge_channel, void *ignore) +{ + struct ast_datastore *datastore; + RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); + + control = stasis_app_control_find_by_channel(bridge_channel->chan); + + ast_channel_lock(bridge_channel->chan); + if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) { + /* Don't bother removing the datastore because it will happen when the channel is hung up */ + ast_channel_unlock(bridge_channel->chan); + stasis_app_send_command_async(control, hangup_channel, NULL, NULL); + return -1; + } + + datastore = ast_channel_datastore_find(bridge_channel->chan, &timeout_datastore, NULL); + if (!datastore) { + ast_channel_unlock(bridge_channel->chan); + return -1; + } + ast_channel_datastore_remove(bridge_channel->chan, datastore); + ast_channel_unlock(bridge_channel->chan); + ast_datastore_free(datastore); + + return -1; +} + +/*! + * \brief Set a dial timeout interval hook on the channel. + * + * The absolute time that the timeout should occur is stored on + * a datastore on the channel. This time is converted into a relative + * number of milliseconds in the future. Then an interval hook is set + * to trigger in that number of milliseconds. + * + * \pre chan is locked + * + * \param chan The channel on which to set the interval hook + */ +static void set_interval_hook(struct ast_channel *chan) +{ + struct ast_datastore *datastore; + struct timeval *hangup_time; + int64_t ms; + struct ast_bridge_channel *bridge_channel; + + datastore = ast_channel_datastore_find(chan, &timeout_datastore, NULL); + if (!datastore) { + return; + } + + hangup_time = datastore->data; + + ms = ast_tvdiff_ms(*hangup_time, ast_tvnow()); + bridge_channel = ast_channel_get_bridge_channel(chan); + if (!bridge_channel) { + return; + } + + if (ast_bridge_interval_hook(bridge_channel->features, 0, ms > 0 ? ms : 1, + bridge_timeout, NULL, NULL, 0)) { + return; + } + + ast_queue_frame(bridge_channel->chan, &ast_null_frame); +} + int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap) { int res; @@ -969,6 +1194,10 @@ int control_swap_channel_in_bridge(struct stasis_app_control *control, struct as ast_assert(stasis_app_get_bridge(control) == NULL); control->bridge = bridge; + + ast_channel_lock(chan); + set_interval_hook(chan); + ast_channel_unlock(chan); } return 0; } @@ -1011,7 +1240,7 @@ static int app_control_remove_channel_from_bridge( return -1; } - ast_bridge_depart(chan); + depart_channel(control, chan); return 0; } @@ -1132,83 +1361,110 @@ struct stasis_app *control_app(struct stasis_app_control *control) return control->app; } -static void app_control_dial_destroy(void *data) +struct control_dial_args { + unsigned int timeout; + char dialstring[0]; +}; + +static struct control_dial_args *control_dial_args_alloc(const char *dialstring, + unsigned int timeout) { - struct ast_dial *dial = data; + struct control_dial_args *args; + + args = ast_malloc(sizeof(*args) + strlen(dialstring) + 1); + if (!args) { + return NULL; + } + + args->timeout = timeout; + /* Safe */ + strcpy(args->dialstring, dialstring); - ast_dial_join(dial); - ast_dial_destroy(dial); + return args; } -static int app_control_remove_dial(struct stasis_app_control *control, - struct ast_channel *chan, void *data) +static void control_dial_args_destroy(void *data) { - if (ast_dial_state(control->dial) != AST_DIAL_RESULT_ANSWERED) { - ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT); - } - control->dial = NULL; - return 0; + struct control_dial_args *args = data; + + ast_free(args); } -static void on_dial_state(struct ast_dial *dial) +/*! + * \brief Set dial timeout on a channel to be dialed. + * + * \param chan The channel on which to set the dial timeout + * \param timeout The timeout in seconds + */ +static int set_timeout(struct ast_channel *chan, unsigned int timeout) { - enum ast_dial_result state; - struct stasis_app_control *control; - struct ast_channel *chan; + struct ast_datastore *datastore; + struct timeval *hangup_time; - state = ast_dial_state(dial); - control = ast_dial_get_user_data(dial); + hangup_time = ast_malloc(sizeof(struct timeval)); - switch (state) { - case AST_DIAL_RESULT_ANSWERED: - /* Need to steal the reference to the answered channel so that dial doesn't - * try to hang it up when we destroy the dial structure. - */ - chan = ast_dial_answered_steal(dial); - ast_channel_unref(chan); - /* Fall through intentionally */ - case AST_DIAL_RESULT_INVALID: - case AST_DIAL_RESULT_FAILED: - case AST_DIAL_RESULT_TIMEOUT: - case AST_DIAL_RESULT_HANGUP: - case AST_DIAL_RESULT_UNANSWERED: - /* The dial has completed, so we need to break the Stasis loop so - * that the channel's frames are handled in the proper place now. - */ - stasis_app_send_command_async(control, app_control_remove_dial, dial, app_control_dial_destroy); - break; - case AST_DIAL_RESULT_TRYING: - case AST_DIAL_RESULT_RINGING: - case AST_DIAL_RESULT_PROGRESS: - case AST_DIAL_RESULT_PROCEEDING: - break; + datastore = ast_datastore_alloc(&timeout_datastore, NULL); + if (!datastore) { + return -1; + } + *hangup_time = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1)); + datastore->data = hangup_time; + + ast_channel_lock(chan); + ast_channel_datastore_add(chan, datastore); + + if (ast_channel_is_bridged(chan)) { + set_interval_hook(chan); } + ast_channel_unlock(chan); + + return 0; } static int app_control_dial(struct stasis_app_control *control, struct ast_channel *chan, void *data) { - struct ast_dial *dial = data; + struct control_dial_args *args = data; + int bridged; - ast_dial_set_state_callback(dial, on_dial_state); - /* The dial API gives the option of providing a caller channel, but for - * Stasis, we really don't want to do that. The Dial API will take liberties such - * as passing frames along to the calling channel (think ringing, progress, etc.). - * This is not desirable in ARI applications since application writers should have - * control over what does/does not get indicated to the calling channel - */ - ast_dial_run(dial, NULL, 1); - control->dial = dial; + ast_channel_lock(chan); + bridged = ast_channel_is_bridged(chan); + ast_channel_unlock(chan); + + if (!bridged && add_to_dial_bridge(control, chan)) { + return -1; + } + + if (args->timeout && set_timeout(chan, args->timeout)) { + return -1; + } + + if (ast_call(chan, args->dialstring, 0)) { + return -1; + } return 0; } -struct ast_dial *stasis_app_get_dial(struct stasis_app_control *control) +int stasis_app_control_dial(struct stasis_app_control *control, + const char *dialstring, unsigned int timeout) { - return control->dial; + struct control_dial_args *args; + + args = control_dial_args_alloc(dialstring, timeout); + if (!args) { + return -1; + } + + return stasis_app_send_command_async(control, app_control_dial, + args, control_dial_args_destroy); } -int stasis_app_control_dial(struct stasis_app_control *control, struct ast_dial *dial) +void stasis_app_control_shutdown(void) { - return stasis_app_send_command_async(control, app_control_dial, dial, NULL); + ast_mutex_lock(&dial_bridge_lock); + shutting_down = 1; + ao2_cleanup(dial_bridge); + dial_bridge = NULL; + ast_mutex_unlock(&dial_bridge_lock); } From bb0f4a6310fecb0f160b9e481fa751de6e35724a Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 26 May 2016 15:14:50 -0500 Subject: [PATCH 0463/1578] multicast RTP: Add dialing options This adds a new parameter to the end of a multicast RTP dialing string. This parameter defines the following options: * i: Set the interface from which multicast RTP is sent * l: Set whether multicast packets are looped back to the sender * t: Set the TTL for multicast packets * c: Set the codec to use for RTP ASTERISK-26068 #close Reported by Mark Michelson Change-Id: I033b706b533f0aa635c342eb738e0bcefa07e219 --- channels/chan_rtp.c | 17 ++- include/asterisk/multicast_rtp.h | 58 ++++++++++ res/res_rtp_multicast.c | 189 +++++++++++++++++++++++++++++-- res/res_rtp_multicast.exports.in | 6 + 4 files changed, 260 insertions(+), 10 deletions(-) create mode 100644 include/asterisk/multicast_rtp.h create mode 100644 res/res_rtp_multicast.exports.in diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index 56705b1f034..093602823d4 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -43,6 +43,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/rtp_engine.h" #include "asterisk/causes.h" #include "asterisk/format_cache.h" +#include "asterisk/multicast_rtp.h" /* Forward declarations */ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause); @@ -132,7 +133,9 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo AST_APP_ARG(type); AST_APP_ARG(destination); AST_APP_ARG(control); + AST_APP_ARG(options); ); + struct ast_multicast_rtp_options *mcast_options = NULL; if (ast_strlen_zero(data)) { ast_log(LOG_ERROR, "A multicast type and destination must be given to the 'MulticastRTP' channel\n"); @@ -163,7 +166,15 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo goto failure; } - fmt = ast_format_cap_get_format(cap, 0); + mcast_options = ast_multicast_rtp_create_options(args.type, args.options); + if (!mcast_options) { + goto failure; + } + + fmt = ast_multicast_rtp_options_get_format(mcast_options); + if (!fmt) { + fmt = ast_format_cap_get_format(cap, 0); + } if (!fmt) { ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n", args.destination); @@ -175,7 +186,7 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo goto failure; } - instance = ast_rtp_instance_new("multicast", NULL, &control_address, args.type); + instance = ast_rtp_instance_new("multicast", NULL, &control_address, mcast_options); if (!instance) { ast_log(LOG_ERROR, "Could not create '%s' multicast RTP instance for sending media to '%s'\n", @@ -207,12 +218,14 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo ao2_ref(fmt, -1); ao2_ref(caps, -1); + ast_multicast_rtp_free_options(mcast_options); return chan; failure: ao2_cleanup(fmt); ao2_cleanup(caps); + ast_multicast_rtp_free_options(mcast_options); *cause = AST_CAUSE_FAILURE; return NULL; } diff --git a/include/asterisk/multicast_rtp.h b/include/asterisk/multicast_rtp.h new file mode 100644 index 00000000000..c286c1f9698 --- /dev/null +++ b/include/asterisk/multicast_rtp.h @@ -0,0 +1,58 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef MULTICAST_RTP_H_ +#define MULTICAST_RTP_H_ +struct ast_multicast_rtp_options; + +/*! + * \brief Create multicast RTP options. + * + * These are passed to the multicast RTP engine on its creation. + * + * \param type The type of multicast RTP, either "basic" or "linksys" + * \param options Miscellaneous options + * \retval NULL Failure + * \retval non-NULL success + */ +struct ast_multicast_rtp_options *ast_multicast_rtp_create_options(const char *type, + const char *options); + +/*! + * \brief Free multicast RTP options + * + * This function is NULL-tolerant + * + * \param mcast_options Options to free + */ +void ast_multicast_rtp_free_options(struct ast_multicast_rtp_options *mcast_options); + +/*! + * \brief Get format specified in multicast options + * + * Multicast options allow for a format to be selected. + * This function accesses the selected format and creates + * an ast_format structure for it. + * + * \param mcast_options The options where a codec was specified + * \retval NULL No format specified in the options + * \revval non-NULL The format to use for communication + */ +struct ast_format *ast_multicast_rtp_options_get_format(struct ast_multicast_rtp_options *mcast_options); + +#endif /* MULTICAST_RTP_H_ */ diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index 192f3d13735..5c419d3e7cf 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -54,6 +54,8 @@ ASTERISK_REGISTER_FILE() #include "asterisk/module.h" #include "asterisk/rtp_engine.h" #include "asterisk/format_cache.h" +#include "asterisk/multicast_rtp.h" +#include "asterisk/app.h" /*! Command value used for Linksys paging to indicate we are starting */ #define LINKSYS_MCAST_STARTCMD 6 @@ -63,8 +65,10 @@ ASTERISK_REGISTER_FILE() /*! \brief Type of paging to do */ enum multicast_type { + /*! Type has not been set yet */ + MULTICAST_TYPE_UNSPECIFIED = 0, /*! Simple multicast enabled client/receiver paging like Snom and Barix uses */ - MULTICAST_TYPE_BASIC = 0, + MULTICAST_TYPE_BASIC, /*! More advanced Linksys type paging which requires a start and stop packet */ MULTICAST_TYPE_LINKSYS, }; @@ -95,6 +99,91 @@ struct multicast_rtp { struct timeval txcore; }; +enum { + OPT_CODEC = (1 << 0), + OPT_LOOP = (1 << 1), + OPT_TTL = (1 << 2), + OPT_IF = (1 << 3), +}; + +enum { + OPT_ARG_CODEC = 0, + OPT_ARG_LOOP, + OPT_ARG_TTL, + OPT_ARG_IF, + OPT_ARG_ARRAY_SIZE, +}; + +AST_APP_OPTIONS(multicast_rtp_options, BEGIN_OPTIONS + /*! Set the codec to be used for multicast RTP */ + AST_APP_OPTION_ARG('c', OPT_CODEC, OPT_ARG_CODEC), + /*! Set whether multicast RTP is looped back to the sender */ + AST_APP_OPTION_ARG('l', OPT_LOOP, OPT_ARG_LOOP), + /*! Set the hop count for multicast RTP */ + AST_APP_OPTION_ARG('t', OPT_TTL, OPT_ARG_TTL), + /*! Set the interface from which multicast RTP is sent */ + AST_APP_OPTION_ARG('i', OPT_IF, OPT_ARG_IF), +END_OPTIONS ); + +struct ast_multicast_rtp_options { + char *type; + char *options; + struct ast_format *fmt; + struct ast_flags opts; + char *opt_args[OPT_ARG_ARRAY_SIZE]; + /*! The type and options are stored in this buffer */ + char buf[0]; +}; + +struct ast_multicast_rtp_options *ast_multicast_rtp_create_options(const char *type, + const char *options) +{ + struct ast_multicast_rtp_options *mcast_options; + char *pos; + + mcast_options = ast_calloc(1, sizeof(*mcast_options) + + strlen(type) + + strlen(options) + 2); + if (!mcast_options) { + return NULL; + } + + pos = mcast_options->buf; + + /* Safe */ + strcpy(pos, type); + mcast_options->type = pos; + pos += strlen(type) + 1; + + /* Safe */ + strcpy(pos, options); + mcast_options->options = pos; + + if (ast_app_parse_options(multicast_rtp_options, &mcast_options->opts, + mcast_options->opt_args, mcast_options->options)) { + ast_log(LOG_WARNING, "Error parsing multicast RTP options\n"); + ast_multicast_rtp_free_options(mcast_options); + return NULL; + } + + return mcast_options; +} + +void ast_multicast_rtp_free_options(struct ast_multicast_rtp_options *mcast_options) +{ + ast_free(mcast_options); +} + +struct ast_format *ast_multicast_rtp_options_get_format(struct ast_multicast_rtp_options *mcast_options) +{ + if (ast_test_flag(&mcast_options->opts, OPT_CODEC) + && !ast_strlen_zero(mcast_options->opt_args[OPT_ARG_CODEC])) { + return ast_format_cache_get(mcast_options->opt_args[OPT_ARG_CODEC]); + } + + return NULL; +} + /* Forward Declarations */ static int multicast_rtp_new(struct ast_rtp_instance *instance, struct ast_sched_context *sched, struct ast_sockaddr *addr, void *data); static int multicast_rtp_activate(struct ast_rtp_instance *instance); @@ -112,21 +201,93 @@ static struct ast_rtp_engine multicast_rtp_engine = { .read = multicast_rtp_read, }; +static int set_type(struct multicast_rtp *multicast, const char *type) +{ + if (!strcasecmp(type, "basic")) { + multicast->type = MULTICAST_TYPE_BASIC; + } else if (!strcasecmp(type, "linksys")) { + multicast->type = MULTICAST_TYPE_LINKSYS; + } else { + ast_log(LOG_WARNING, "Unrecognized multicast type '%s' specified.\n", type); + return -1; + } + + return 0; +} + +static void set_ttl(int sock, const char *ttl_str) +{ + int ttl; + + if (ast_strlen_zero(ttl_str)) { + return; + } + + ast_debug(3, "Setting multicast TTL to %s\n", ttl_str); + + if (sscanf(ttl_str, "%30d", &ttl) < 1) { + ast_log(LOG_WARNING, "Inavlid multicast ttl option '%s'\n", ttl_str); + return; + } + + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) { + ast_log(LOG_WARNING, "Could not set multicast ttl to '%s': %s\n", + ttl_str, strerror(errno)); + } +} + +static void set_loop(int sock, const char *loop_str) +{ + unsigned char loop; + + if (ast_strlen_zero(loop_str)) { + return; + } + + ast_debug(3, "Setting multicast loop to %s\n", loop_str); + + if (sscanf(loop_str, "%30hhu", &loop) < 1) { + ast_log(LOG_WARNING, "Invalid multicast loop option '%s'\n", loop_str); + return; + } + + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { + ast_log(LOG_WARNING, "Could not set multicast loop to '%s': %s\n", + loop_str, strerror(errno)); + } +} + +static void set_if(int sock, const char *if_str) +{ + struct in_addr iface; + + if (ast_strlen_zero(if_str)) { + return; + } + + ast_debug(3, "Setting multicast if to %s\n", if_str); + + if (!inet_aton(if_str, &iface)) { + ast_log(LOG_WARNING, "Cannot parse if option '%s'\n", if_str); + } + + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &iface, sizeof(iface)) < 0) { + ast_log(LOG_WARNING, "Could not set multicast if to '%s': %s\n", + if_str, strerror(errno)); + } +} + /*! \brief Function called to create a new multicast instance */ static int multicast_rtp_new(struct ast_rtp_instance *instance, struct ast_sched_context *sched, struct ast_sockaddr *addr, void *data) { struct multicast_rtp *multicast; - const char *type = data; + struct ast_multicast_rtp_options *mcast_options = data; if (!(multicast = ast_calloc(1, sizeof(*multicast)))) { return -1; } - if (!strcasecmp(type, "basic")) { - multicast->type = MULTICAST_TYPE_BASIC; - } else if (!strcasecmp(type, "linksys")) { - multicast->type = MULTICAST_TYPE_LINKSYS; - } else { + if (set_type(multicast, mcast_options->type)) { ast_free(multicast); return -1; } @@ -136,6 +297,18 @@ static int multicast_rtp_new(struct ast_rtp_instance *instance, struct ast_sched return -1; } + if (ast_test_flag(&mcast_options->opts, OPT_LOOP)) { + set_loop(multicast->socket, mcast_options->opt_args[OPT_ARG_LOOP]); + } + + if (ast_test_flag(&mcast_options->opts, OPT_TTL)) { + set_ttl(multicast->socket, mcast_options->opt_args[OPT_ARG_TTL]); + } + + if (ast_test_flag(&mcast_options->opts, OPT_IF)) { + set_if(multicast->socket, mcast_options->opt_args[OPT_ARG_IF]); + } + multicast->ssrc = ast_random(); ast_rtp_instance_set_data(instance, multicast); @@ -316,7 +489,7 @@ static int unload_module(void) return 0; } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Multicast RTP Engine", +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Multicast RTP Engine", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, diff --git a/res/res_rtp_multicast.exports.in b/res/res_rtp_multicast.exports.in new file mode 100644 index 00000000000..995a1802ec1 --- /dev/null +++ b/res/res_rtp_multicast.exports.in @@ -0,0 +1,6 @@ +{ + global: + LINKER_SYMBOL_PREFIXast_multicast_rtp*; + local: + *; +}; From b56f61185641d06e10105b6e5444e3fcccbe6616 Mon Sep 17 00:00:00 2001 From: Rusty Newton Date: Fri, 27 May 2016 12:25:55 -0500 Subject: [PATCH 0464/1578] res_pjsip: Add clarifying documentation to PJSIP_HEADER help text Added notes about when you can read or write headers. Specifically about being able to read on the inbound channel and write on an outbound channel. ASTERISK-26063 #close Reported by: Private Name Tested by: Rusty Newton Change-Id: Ibeb64af17d1f6451028b3c29855a3f151a01d8c5 --- res/res_pjsip_header_funcs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_header_funcs.c b/res/res_pjsip_header_funcs.c index 7d164b12a9d..648f1c8602c 100644 --- a/res/res_pjsip_header_funcs.c +++ b/res/res_pjsip_header_funcs.c @@ -39,7 +39,8 @@ /*** DOCUMENTATION - Gets, adds, updates or removes the specified SIP header from a PJSIP session. + Gets headers from an inbound PJSIP channel. Adds, updates or removes the + specified SIP header from an outbound PJSIP channel. @@ -75,6 +76,10 @@ + PJSIP_HEADER allows you to read specific SIP headers from the inbound + PJSIP channel as well as write(add, update, remove) headers on the outbound + channel. One exception is that you can read headers that you have already + added on the outbound channel. Examples: ; ; Set 'somevar' to the value of the 'From' header. @@ -120,7 +125,7 @@ If you call PJSIP_HEADER in a normal dialplan context you'll be operating on the caller's (incoming) channel which - may not be what you want. To operate on the callee's (outgoing) + may not be what you want. To operate on the callee's (outgoing) channel call PJSIP_HEADER in a pre-dial handler. Example: ; From 7fa5766752f261318d7d3a2c83d1cc467440ec17 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 30 May 2016 09:58:35 -0600 Subject: [PATCH 0465/1578] pjproject_bundled: Move to pjproject 2.5 Although all the patches we had against 2.4.5 were applied by Teluu, a new bug was introduced preventing re-use of tcp and tls transports This patch removes all the previous patches against 2.4.5, updates the version to 2.5, and adds a new patch to correct the transport re-use problem. Change-Id: I0dc6c438c3910f7887418a5832ca186aea23d068 --- .../0001-2.4.5-fix-for-tls-async-ops.patch | 224 ------------------ ...d-transaction-log-levels-from-1-to-3.patch | 70 ------ ...oqueue-Enable-epoll-in-aconfigure.ac.patch | 80 ------- ...ython-setup.py-Take-make-from-the-en.patch | 51 ---- ...arser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch | 30 --- ...ove-wholesale-strip-from-parse_param.patch | 55 ----- ...arch-for-transport-even-if-listener-.patch | 114 --------- ...p-tls-Set-factory-on-transports-crea.patch | 48 ++++ ...x-autoconf-issue-with-opencore-amrnb.patch | 48 ---- third-party/versions.mak | 2 +- 10 files changed, 49 insertions(+), 673 deletions(-) delete mode 100644 third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch delete mode 100644 third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch delete mode 100644 third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch delete mode 100644 third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch delete mode 100644 third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch delete mode 100644 third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch delete mode 100644 third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch create mode 100644 third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch delete mode 100644 third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch diff --git a/third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch b/third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch deleted file mode 100644 index 33fc8ea4ec4..00000000000 --- a/third-party/pjproject/patches/0001-2.4.5-fix-for-tls-async-ops.patch +++ /dev/null @@ -1,224 +0,0 @@ -diff --git a/pjlib/include/pj/ssl_sock.h b/pjlib/include/pj/ssl_sock.h -index 1682bda..a69af32 100644 ---- a/pjlib/include/pj/ssl_sock.h -+++ b/pjlib/include/pj/ssl_sock.h -@@ -864,6 +864,18 @@ PJ_DECL(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param); - - - /** -+ * Duplicate pj_ssl_sock_param. -+ * -+ * @param pool Pool to allocate memory. -+ * @param dst Destination parameter. -+ * @param src Source parameter. -+ */ -+PJ_DECL(void) pj_ssl_sock_param_copy(pj_pool_t *pool, -+ pj_ssl_sock_param *dst, -+ const pj_ssl_sock_param *src); -+ -+ -+/** - * Create secure socket instance. - * - * @param pool The pool for allocating secure socket instance. -@@ -1115,6 +1127,30 @@ PJ_DECL(pj_status_t) pj_ssl_sock_start_accept(pj_ssl_sock_t *ssock, - - - /** -+ * Same as #pj_ssl_sock_start_accept(), but application can provide -+ * a secure socket parameter, which will be used to create a new secure -+ * socket reported in \a on_accept_complete() callback when there is -+ * an incoming connection. -+ * -+ * @param ssock The secure socket. -+ * @param pool Pool used to allocate some internal data for the -+ * operation. -+ * @param localaddr Local address to bind on. -+ * @param addr_len Length of buffer containing local address. -+ * @param newsock_param Secure socket parameter for new accepted sockets. -+ * -+ * @return PJ_SUCCESS if the operation has been successful, -+ * or the appropriate error code on failure. -+ */ -+PJ_DECL(pj_status_t) -+pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock, -+ pj_pool_t *pool, -+ const pj_sockaddr_t *local_addr, -+ int addr_len, -+ const pj_ssl_sock_param *newsock_param); -+ -+ -+/** - * Starts asynchronous socket connect() operation and SSL/TLS handshaking - * for this socket. Once the connection is done (either successfully or not), - * the \a on_connect_complete() callback will be called. -diff --git a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c -index 913efee..717ab1d 100644 ---- a/pjlib/src/pj/ssl_sock_common.c -+++ b/pjlib/src/pj/ssl_sock_common.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - - /* -@@ -48,6 +49,31 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param) - } - - -+/* -+ * Duplicate SSL socket parameter. -+ */ -+PJ_DEF(void) pj_ssl_sock_param_copy( pj_pool_t *pool, -+ pj_ssl_sock_param *dst, -+ const pj_ssl_sock_param *src) -+{ -+ /* Init secure socket param */ -+ pj_memcpy(dst, src, sizeof(*dst)); -+ if (src->ciphers_num > 0) { -+ unsigned i; -+ dst->ciphers = (pj_ssl_cipher*) -+ pj_pool_calloc(pool, src->ciphers_num, -+ sizeof(pj_ssl_cipher)); -+ for (i = 0; i < src->ciphers_num; ++i) -+ dst->ciphers[i] = src->ciphers[i]; -+ } -+ -+ if (src->server_name.slen) { -+ /* Server name must be null-terminated */ -+ pj_strdup_with_null(pool, &dst->server_name, &src->server_name); -+ } -+} -+ -+ - PJ_DEF(pj_status_t) pj_ssl_cert_get_verify_status_strings( - pj_uint32_t verify_status, - const char *error_strings[], -diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c -index 40a5a1e..6a701b7 100644 ---- a/pjlib/src/pj/ssl_sock_ossl.c -+++ b/pjlib/src/pj/ssl_sock_ossl.c -@@ -141,6 +141,7 @@ struct pj_ssl_sock_t - pj_pool_t *pool; - pj_ssl_sock_t *parent; - pj_ssl_sock_param param; -+ pj_ssl_sock_param newsock_param; - pj_ssl_cert_t *cert; - - pj_ssl_cert_info local_cert_info; -@@ -1757,11 +1758,9 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock, - unsigned i; - pj_status_t status; - -- PJ_UNUSED_ARG(src_addr_len); -- - /* Create new SSL socket instance */ -- status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->param, -- &ssock); -+ status = pj_ssl_sock_create(ssock_parent->pool, -+ &ssock_parent->newsock_param, &ssock); - if (status != PJ_SUCCESS) - goto on_return; - -@@ -2183,20 +2182,8 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool, - return status; - - /* Init secure socket param */ -- ssock->param = *param; -+ pj_ssl_sock_param_copy(pool, &ssock->param, param); - ssock->param.read_buffer_size = ((ssock->param.read_buffer_size+7)>>3)<<3; -- if (param->ciphers_num > 0) { -- unsigned i; -- ssock->param.ciphers = (pj_ssl_cipher*) -- pj_pool_calloc(pool, param->ciphers_num, -- sizeof(pj_ssl_cipher)); -- for (i = 0; i < param->ciphers_num; ++i) -- ssock->param.ciphers[i] = param->ciphers[i]; -- } -- -- /* Server name must be null-terminated */ -- pj_strdup_with_null(pool, &ssock->param.server_name, -- ¶m->server_name); - - /* Finally */ - *p_ssock = ssock; -@@ -2617,12 +2604,36 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock, - const pj_sockaddr_t *localaddr, - int addr_len) - { -+ return pj_ssl_sock_start_accept2(ssock, pool, localaddr, addr_len, -+ &ssock->param); -+} -+ -+ -+/** -+ * Same as #pj_ssl_sock_start_accept(), but application provides parameter -+ * for new accepted secure sockets. -+ */ -+PJ_DEF(pj_status_t) -+pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock, -+ pj_pool_t *pool, -+ const pj_sockaddr_t *localaddr, -+ int addr_len, -+ const pj_ssl_sock_param *newsock_param) -+{ - pj_activesock_cb asock_cb; - pj_activesock_cfg asock_cfg; - pj_status_t status; - - PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL); - -+ /* Verify new socket parameters */ -+ if (newsock_param->grp_lock != ssock->param.grp_lock || -+ newsock_param->sock_af != ssock->param.sock_af || -+ newsock_param->sock_type != ssock->param.sock_type) -+ { -+ return PJ_EINVAL; -+ } -+ - /* Create socket */ - status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0, - &ssock->sock); -@@ -2691,6 +2702,7 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock, - goto on_error; - - /* Start accepting */ -+ pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param); - status = pj_activesock_start_accept(ssock->asock, pool); - if (status != PJ_SUCCESS) - goto on_error; -diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c -index a9e95fb..91d99a7 100644 ---- a/pjsip/src/pjsip/sip_transport_tls.c -+++ b/pjsip/src/pjsip/sip_transport_tls.c -@@ -314,7 +314,7 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt, - int af, sip_ssl_method; - pj_uint32_t sip_ssl_proto; - struct tls_listener *listener; -- pj_ssl_sock_param ssock_param; -+ pj_ssl_sock_param ssock_param, newsock_param; - pj_sockaddr *listener_addr; - pj_bool_t has_listener; - pj_status_t status; -@@ -473,9 +473,14 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt, - */ - has_listener = PJ_FALSE; - -- status = pj_ssl_sock_start_accept(listener->ssock, pool, -+ pj_memcpy(&newsock_param, &ssock_param, sizeof(newsock_param)); -+ newsock_param.async_cnt = 1; -+ newsock_param.cb.on_data_read = &on_data_read; -+ newsock_param.cb.on_data_sent = &on_data_sent; -+ status = pj_ssl_sock_start_accept2(listener->ssock, pool, - (pj_sockaddr_t*)listener_addr, -- pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr)); -+ pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr), -+ &newsock_param); - if (status == PJ_SUCCESS || status == PJ_EPENDING) { - pj_ssl_sock_info info; - has_listener = PJ_TRUE; --- -cgit v0.11.2 - diff --git a/third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch b/third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch deleted file mode 100644 index 9873abf0e68..00000000000 --- a/third-party/pjproject/patches/0001-Bump-tcp-tls-and-transaction-log-levels-from-1-to-3.patch +++ /dev/null @@ -1,70 +0,0 @@ -From a147b72df1ec150c1d733e882225db86142fb339 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Sun, 21 Feb 2016 10:01:53 -0700 -Subject: [PATCH] Bump tcp/tls and transaction log levels from 1 to 3 - -sip_transport_tcp, sip_transport_tls and sip_transaction are printing messages -at log level 1 or 2 for things that are transient, recoverable, possibly -expected, or are handled with return codes. A good example of this is if we're -trying to send an OPTIONS message to a TCP client that has disappeared. Both -sip_transport_tcp and sip_transaction are printing "connection refused" -messages because the remote client isn't listening. This is generally expected -behavior and it should be up to the app caller to determine if an error message -is warranted. ---- - pjsip/src/pjsip/sip_transaction.c | 4 ++-- - pjsip/src/pjsip/sip_transport_tcp.c | 2 +- - pjsip/src/pjsip/sip_transport_tls.c | 2 +- - 3 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c -index 46bd971..1b4fdb7 100644 ---- a/pjsip/src/pjsip/sip_transaction.c -+++ b/pjsip/src/pjsip/sip_transaction.c -@@ -1898,7 +1898,7 @@ static void send_msg_callback( pjsip_send_state *send_state, - - err =pj_strerror((pj_status_t)-sent, errmsg, sizeof(errmsg)); - -- PJ_LOG(2,(tsx->obj_name, -+ PJ_LOG(3,(tsx->obj_name, - "Failed to send %s! err=%d (%s)", - pjsip_tx_data_get_info(send_state->tdata), -sent, - errmsg)); -@@ -1938,7 +1938,7 @@ static void send_msg_callback( pjsip_send_state *send_state, - } - - } else { -- PJ_PERROR(2,(tsx->obj_name, (pj_status_t)-sent, -+ PJ_PERROR(3,(tsx->obj_name, (pj_status_t)-sent, - "Temporary failure in sending %s, " - "will try next server", - pjsip_tx_data_get_info(send_state->tdata))); -diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c -index 222cb13..1bbb324 100644 ---- a/pjsip/src/pjsip/sip_transport_tcp.c -+++ b/pjsip/src/pjsip/sip_transport_tcp.c -@@ -164,7 +164,7 @@ static void tcp_perror(const char *sender, const char *title, - - pj_strerror(status, errmsg, sizeof(errmsg)); - -- PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status)); -+ PJ_LOG(3,(sender, "%s: %s [code=%d]", title, errmsg, status)); - } - - -diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c -index 617d7f5..a83ac32 100644 ---- a/pjsip/src/pjsip/sip_transport_tls.c -+++ b/pjsip/src/pjsip/sip_transport_tls.c -@@ -170,7 +170,7 @@ static void tls_perror(const char *sender, const char *title, - - pj_strerror(status, errmsg, sizeof(errmsg)); - -- PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status)); -+ PJ_LOG(3,(sender, "%s: %s [code=%d]", title, errmsg, status)); - } - - --- -2.5.0 - diff --git a/third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch b/third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch deleted file mode 100644 index 36b6c651f12..00000000000 --- a/third-party/pjproject/patches/0001-ioqueue-Enable-epoll-in-aconfigure.ac.patch +++ /dev/null @@ -1,80 +0,0 @@ -From b5c0bc905911f75e08987e6833075481fe16dab2 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Mon, 22 Feb 2016 13:05:59 -0700 -Subject: [PATCH] ioqueue: Enable epoll in aconfigure.ac - -Although the --enable-epoll option was being accepted, the result -was always forced to select. This patch updates aconfigure.ac -to properly set the value of ac_linux_poll if --enable-epoll is -specified. ---- - README.txt | 1 + - aconfigure | 11 +++++++---- - aconfigure.ac | 7 +++++-- - pjlib/include/pj/compat/os_auto.h.in | 3 +++ - 4 files changed, 16 insertions(+), 6 deletions(-) - -diff --git a/README.txt b/README.txt -index bc45da8..48415fd 100644 ---- a/README.txt -+++ b/README.txt -@@ -463,6 +463,7 @@ Using Default Settings - $ ./configure --help - ... - Optional Features: -+ --enable-epoll Use epoll on Linux instead of select - --disable-floating-point Disable floating point where possible - --disable-sound Exclude sound (i.e. use null sound) - --disable-small-filter Exclude small filter in resampling -diff --git a/aconfigure.ac b/aconfigure.ac -index 2f71abb..3e88124 100644 ---- a/aconfigure.ac -+++ b/aconfigure.ac -@@ -410,6 +410,7 @@ dnl ###################### - dnl # ioqueue selection - dnl # - AC_SUBST(ac_os_objs) -+AC_SUBST(ac_linux_poll) - AC_MSG_CHECKING([ioqueue backend]) - AC_ARG_ENABLE(epoll, - AC_HELP_STRING([--enable-epoll], -@@ -417,10 +418,13 @@ AC_ARG_ENABLE(epoll, - [ - ac_os_objs=ioqueue_epoll.o - AC_MSG_RESULT([/dev/epoll]) -+ AC_DEFINE(PJ_HAS_LINUX_EPOLL,1) -+ ac_linux_poll=epoll - ], - [ - ac_os_objs=ioqueue_select.o -- AC_MSG_RESULT([select()]) -+ AC_MSG_RESULT([select()]) -+ ac_linux_poll=select - ]) - - AC_SUBST(ac_shared_libraries) -@@ -1879,7 +1883,6 @@ esac - - - AC_SUBST(target) --AC_SUBST(ac_linux_poll,select) - AC_SUBST(ac_host,unix) - AC_SUBST(ac_main_obj) - case $target in -diff --git a/pjlib/include/pj/compat/os_auto.h.in b/pjlib/include/pj/compat/os_auto.h.in -index 77980d3..c8e73b2 100644 ---- a/pjlib/include/pj/compat/os_auto.h.in -+++ b/pjlib/include/pj/compat/os_auto.h.in -@@ -128,6 +128,9 @@ - */ - #undef PJ_SELECT_NEEDS_NFDS - -+/* Was Linux epoll support enabled */ -+#undef PJ_HAS_LINUX_EPOLL -+ - /* Is errno a good way to retrieve OS errors? - */ - #undef PJ_HAS_ERRNO_VAR --- -2.5.0 - diff --git a/third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch b/third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch deleted file mode 100644 index 80f8bc0b35f..00000000000 --- a/third-party/pjproject/patches/0001-pjsip-apps-src-python-setup.py-Take-make-from-the-en.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 61668b8fcaa0f2a8a05100097284c0c427600033 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Mon, 2 May 2016 17:08:15 -0600 -Subject: [PATCH] pjsip-apps/src/python/setup.py: Take "make" from the - environment - -With "make" hard coded in setup.py, it chokes on FreeBSD because the system -make command isn't GNU compatibile. This patch allows setup.py to take the -name of the make command from the MAKE environment variable if it exists. -If it doesn't, it defaults to "make". ---- - pjsip-apps/src/python/setup.py | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/pjsip-apps/src/python/setup.py b/pjsip-apps/src/python/setup.py -index 69a9859..ea1427d 100644 ---- a/pjsip-apps/src/python/setup.py -+++ b/pjsip-apps/src/python/setup.py -@@ -60,25 +60,25 @@ if pj_version_suffix: - pj_version += "-" + pj_version_suffix - - #print 'PJ_VERSION = "'+ pj_version + '"' -- -+MAKE = os.environ.get('MAKE') or "make" - - # Fill in pj_inc_dirs - pj_inc_dirs = [] --f = os.popen("make -f helper.mak inc_dir") -+f = os.popen("%s -f helper.mak inc_dir" % MAKE) - for line in f: - pj_inc_dirs.append(line.rstrip("\r\n")) - f.close() - - # Fill in pj_lib_dirs - pj_lib_dirs = [] --f = os.popen("make -f helper.mak lib_dir") -+f = os.popen("%s -f helper.mak lib_dir" % MAKE) - for line in f: - pj_lib_dirs.append(line.rstrip("\r\n")) - f.close() - - # Fill in pj_libs - pj_libs = [] --f = os.popen("make -f helper.mak libs") -+f = os.popen("%s -f helper.mak libs" % MAKE) - for line in f: - pj_libs.append(line.rstrip("\r\n")) - f.close() --- -2.5.5 - diff --git a/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch b/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch deleted file mode 100644 index 60c27cb1af2..00000000000 --- a/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0fc7ef5f01be9cc74d184c3ca3a973ff1ef44c93 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Sun, 10 Apr 2016 12:54:06 -0600 -Subject: [PATCH] sip_parser.c: Fix pjsip_VIA_PARAM_SPEC_ESC - -pjsip_VIA_PARAM_SPEC_ESC should have been pjsip_TOKEN_SPEC_ESC + ":" but -instead of appending ":" to pjsip_VIA_PARAM_SPEC_ESC it was being appended -to pjsip_VIA_PARAM_SPEC again. This was causing parsing of Via headers -to fail when an ipv6 address was in a "received" param and -PJSIP_UNESCAPE_IN_PLACE was used. Probably just a copy/paste error. ---- - pjsip/src/pjsip/sip_parser.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c -index 378c22f..c18faa3 100644 ---- a/pjsip/src/pjsip/sip_parser.c -+++ b/pjsip/src/pjsip/sip_parser.c -@@ -327,7 +327,7 @@ static pj_status_t init_parser() - - status = pj_cis_dup(&pconst.pjsip_VIA_PARAM_SPEC_ESC, &pconst.pjsip_TOKEN_SPEC_ESC); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); -- pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC, ":"); -+ pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC_ESC, ":"); - - status = pj_cis_dup(&pconst.pjsip_HOST_SPEC, &pconst.pjsip_ALNUM_SPEC); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); --- -2.5.5 - diff --git a/third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch b/third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch deleted file mode 100644 index e0bd9129c88..00000000000 --- a/third-party/pjproject/patches/0001-sip_parser.c-Remove-wholesale-strip-from-parse_param.patch +++ /dev/null @@ -1,55 +0,0 @@ -From ce426249ec1270f27560919791f3e13eaeea9152 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Tue, 12 Apr 2016 14:09:53 -0600 -Subject: [PATCH] sip_parser.c: Remove wholesale '[]' strip from - parse_param_impl - -The wholesale stripping of '[]' from header parameters causes issues if -something (like a port) occurrs after the final ']'. - -'[2001:a::b]' will correctly parse to '2001:a::b' -'[2001:a::b]:8080' will correctly parse to '2001:a::b' but the scanner is left -with ':8080' and parsing stops with a syntax error. - -I can't even find a case where stripping the '[]' is a good thing anyway. Even -if you continued to parse and resulted in a string that looks like this... -'2001:a::b:8080', it's not valid. - -This came up in Asterisk because Kamailio sends us a Contact with an alias -URI parameter that has an IPv6 address in it like this: -Contact: -which should be legal but causes a syntax error because of the characters -after the final ']'. Even if it didn't, the '[]' should still not be stripped. - -I've run the Asterisk Test Suite for PJSIP (252 tests) many of which are IPv6 -enabled. No issues were caused by removing the code that strips the '[]'. - -I tried running 'make pjsip-test' but that fails even without my change. :) - -The Asterisk ticket is: https://issues.asterisk.org/jira/browse/ASTERISK-25123 ---- - pjsip/src/pjsip/sip_parser.c | 8 -------- - 1 file changed, 8 deletions(-) - -diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c -index c18faa3..98eb5ea 100644 ---- a/pjsip/src/pjsip/sip_parser.c -+++ b/pjsip/src/pjsip/sip_parser.c -@@ -1149,14 +1149,6 @@ static void parse_param_imp( pj_scanner *scanner, pj_pool_t *pool, - pvalue->ptr++; - pvalue->slen -= 2; - } -- } else if (*scanner->curptr == '[') { -- /* pvalue can be a quoted IPv6; in this case, the -- * '[' and ']' quote characters are to be removed -- * from the pvalue. -- */ -- pj_scan_get_char(scanner); -- pj_scan_get_until_ch(scanner, ']', pvalue); -- pj_scan_get_char(scanner); - } else if(pj_cis_match(spec, *scanner->curptr)) { - parser_get_and_unescape(scanner, pool, spec, esc_spec, pvalue); - } --- -2.5.5 - diff --git a/third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch b/third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch deleted file mode 100644 index 001912cfe30..00000000000 --- a/third-party/pjproject/patches/0001-sip_transport-Search-for-transport-even-if-listener-.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 552194179eb6deae8326eb0fef446e69240ea41b Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Fri, 19 Feb 2016 17:05:53 -0700 -Subject: [PATCH] sip_transport: Search for transport even if listener was - specified. - -If a listener was specified when calling pjsip_tpmgr_acquire_transport2, -a new transport was always created instead of using an existing one. This -caused several issues mostly related to the remote end not expecting a new -connection. I.E. A TCP client who registered to a server is not going to -be listening for connections coming back from the server and refuses the -connection. - -Now when pjsip_tpmgr_acquire_transport2 is called with a listener, the -registry is still searched for an existing transport and the listener -is used as a factory only if no existing transport can be found. ---- - pjsip/src/pjsip/sip_transport.c | 68 ++++++++++++++++++++--------------------- - 1 file changed, 34 insertions(+), 34 deletions(-) - -diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c -index 0410324..620b9c0 100644 ---- a/pjsip/src/pjsip/sip_transport.c -+++ b/pjsip/src/pjsip/sip_transport.c -@@ -1999,29 +1999,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, - - TRACE_((THIS_FILE, "Transport %s acquired", seltp->obj_name)); - return PJ_SUCCESS; -- -- -- } else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && -- sel->u.listener) -- { -- /* Application has requested that a specific listener is to -- * be used. In this case, skip transport hash table lookup. -- */ -- -- /* Verify that the listener type matches the destination type */ -- if (sel->u.listener->type != type) { -- pj_lock_release(mgr->lock); -- return PJSIP_ETPNOTSUITABLE; -- } -- -- /* We'll use this listener to create transport */ -- factory = sel->u.listener; -- - } else { - - /* - * This is the "normal" flow, where application doesn't specify -- * specific transport/listener to be used to send message to. -+ * specific transport to be used to send message to. - * In this case, lookup the transport from the hash table. - */ - pjsip_transport_key key; -@@ -2081,22 +2063,40 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, - return PJ_SUCCESS; - } - -- /* -- * Transport not found! -- * Find factory that can create such transport. -- */ -- factory = mgr->factory_list.next; -- while (factory != &mgr->factory_list) { -- if (factory->type == type) -- break; -- factory = factory->next; -- } -+ if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && -+ sel->u.listener) -+ { -+ /* Application has requested that a specific listener is to -+ * be used. -+ */ -+ -+ /* Verify that the listener type matches the destination type */ -+ if (sel->u.listener->type != type) { -+ pj_lock_release(mgr->lock); -+ return PJSIP_ETPNOTSUITABLE; -+ } - -- if (factory == &mgr->factory_list) { -- /* No factory can create the transport! */ -- pj_lock_release(mgr->lock); -- TRACE_((THIS_FILE, "No suitable factory was found either")); -- return PJSIP_EUNSUPTRANSPORT; -+ /* We'll use this listener to create transport */ -+ factory = sel->u.listener; -+ -+ } else { -+ /* -+ * Transport not found! -+ * Find factory that can create such transport. -+ */ -+ factory = mgr->factory_list.next; -+ while (factory != &mgr->factory_list) { -+ if (factory->type == type) -+ break; -+ factory = factory->next; -+ } -+ -+ if (factory == &mgr->factory_list) { -+ /* No factory can create the transport! */ -+ pj_lock_release(mgr->lock); -+ TRACE_((THIS_FILE, "No suitable factory was found either")); -+ return PJSIP_EUNSUPTRANSPORT; -+ } - } - } - --- -2.5.0 - diff --git a/third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch b/third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch new file mode 100644 index 00000000000..d8a9adbde52 --- /dev/null +++ b/third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch @@ -0,0 +1,48 @@ +From b7cb93b0e1729589a71e8b30d9a9893f0918e2a2 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Mon, 30 May 2016 11:58:22 -0600 +Subject: [PATCH] sip_transport_tcp/tls: Set factory on transports created + from accept + +The ability to re-use tcp and tls transports when a factory is +specified now depends on transport->factory being set which is a new field +in 2.5. This was being set only on new outgoing sockets not on +incoming sockets. The result was that a client REGISTER created a new +socket but without the factory set, the next outgoing request to the +client, OPTIONS, INVITE, etc, would attempt to create another socket +which the client would refuse. + +This patch sets the factory on transports created as a result of an +accept. +--- + pjsip/src/pjsip/sip_transport_tcp.c | 1 + + pjsip/src/pjsip/sip_transport_tls.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c +index 1bbb324..00eb8fc 100644 +--- a/pjsip/src/pjsip/sip_transport_tcp.c ++++ b/pjsip/src/pjsip/sip_transport_tcp.c +@@ -713,6 +713,7 @@ static pj_status_t tcp_create( struct tcp_listener *listener, + tcp->base.send_msg = &tcp_send_msg; + tcp->base.do_shutdown = &tcp_shutdown; + tcp->base.destroy = &tcp_destroy_transport; ++ tcp->base.factory = &listener->factory; + + /* Create group lock */ + status = pj_grp_lock_create(pool, NULL, &tcp->grp_lock); +diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c +index a83ac32..36ee70d 100644 +--- a/pjsip/src/pjsip/sip_transport_tls.c ++++ b/pjsip/src/pjsip/sip_transport_tls.c +@@ -742,6 +742,7 @@ static pj_status_t tls_create( struct tls_listener *listener, + tls->base.send_msg = &tls_send_msg; + tls->base.do_shutdown = &tls_shutdown; + tls->base.destroy = &tls_destroy_transport; ++ tls->base.factory = &listener->factory; + + tls->ssock = ssock; + +-- +2.5.5 + diff --git a/third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch b/third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch deleted file mode 100644 index 04d1d970344..00000000000 --- a/third-party/pjproject/patches/0002-aconfigure.ac-Fix-autoconf-issue-with-opencore-amrnb.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 1281b60a1807d1285b101b6eb61c6478f29785fe Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Wed, 23 Mar 2016 07:48:52 -0600 -Subject: [PATCH] aconfigure.ac: Fix autoconf issue with opencore-amrnb on - older systems - -autoconf 2.63 on CentOS6 produces a bad ./aconfigure file related to -opencore-amrnb. - -./aconfigure: line 15158: syntax error near unexpected token `fi' - -To get around this, a 'true;' needed to be added to the Ok case of -AC_ARG_WITH(opencore-amrnb) ---- - aconfigure | 3 +++ - aconfigure.ac | 2 +- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/aconfigure b/aconfigure -index 33a08f5..4c122c2 100755 ---- a/aconfigure -+++ b/aconfigure -@@ -7908,6 +7908,9 @@ fi - # Check whether --with-opencore-amrnb was given. - if test "${with_opencore_amrnb+set}" = set; then : - withval=$with_opencore_amrnb; as_fn_error $? "This option is obsolete and replaced by --with-opencore-amr=DIR" "$LINENO" 5 -+else -+ true; -+ - fi - - -diff --git a/aconfigure.ac b/aconfigure.ac -index 3e88124..5d3e833 100644 ---- a/aconfigure.ac -+++ b/aconfigure.ac -@@ -1631,7 +1631,7 @@ AC_ARG_WITH(opencore-amrnb, - AC_HELP_STRING([--with-opencore-amrnb=DIR], - [This option is obsolete and replaced by --with-opencore-amr=DIR]), - [AC_MSG_ERROR(This option is obsolete and replaced by --with-opencore-amr=DIR)], -- [] -+ [true;] - ) - - dnl # opencore-amr alt prefix --- -2.5.0 - diff --git a/third-party/versions.mak b/third-party/versions.mak index 7b8b59c5383..ca40531dfba 100644 --- a/third-party/versions.mak +++ b/third-party/versions.mak @@ -1,2 +1,2 @@ -PJPROJECT_VERSION = 2.4.5 +PJPROJECT_VERSION = 2.5 From 8a6a14590d4c2f6c840d0e192c4113f700c682fa Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 30 May 2016 18:27:35 -0600 Subject: [PATCH 0466/1578] res_pjsip_mwi_body_generator: Re-order the body items Re-ordered the body items so Message-Account is second. Messages-Waiting: no Message-Account: sip:1571@:5060 Voice-Message: 0/0 (0/0) ASTERISK-26065 #close Reported-by: Ross Beer Change-Id: If5d35a64656eac98c2dd5e490cc0b2807bed80c3 --- res/res_pjsip_mwi_body_generator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_mwi_body_generator.c b/res/res_pjsip_mwi_body_generator.c index f46ce04e396..e8279101c87 100644 --- a/res/res_pjsip_mwi_body_generator.c +++ b/res/res_pjsip_mwi_body_generator.c @@ -61,11 +61,11 @@ static int mwi_generate_body_content(void *body, void *data) ast_str_append(mwi, 0, "Messages-Waiting: %s\r\n", counter->new_msgs ? "yes" : "no"); - ast_str_append(mwi, 0, "Voice-Message: %d/%d (0/0)\r\n", - counter->new_msgs, counter->old_msgs); if (!ast_strlen_zero(counter->message_account)) { ast_str_append(mwi, 0, "Message-Account: %s\r\n", counter->message_account); } + ast_str_append(mwi, 0, "Voice-Message: %d/%d (0/0)\r\n", + counter->new_msgs, counter->old_msgs); return 0; } From 205a31f86c4ceec4966492363fb9ac674c990235 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 9 May 2016 15:00:56 -0500 Subject: [PATCH 0467/1578] Expand the scope of Dial Events Dial events up to this point have come in two flavors * A Dial event with no status to indicate that dialing has begun * A Dial event with a status to indicate that dialing has ended With this change, Dial events have been expanded to also give intermediate events, such as "RINGING", "PROCEEDING", and "PROGRESS". This is especially useful for ARI dialing, as it gives the application writer the opportunity to place a channel into an early bridge when early media is detected. AMI handles these in-progress dial events by sending a new event called "DialState" that simply indicates that dial state has changed but has not ended. ARI never distinguished between DialBegin and DialEnd, so no change was made to the event itself. Another change here relates to dial forwards. A forward-related event was previously only sent when a channel was successfully able to forward a call to a new channel. With this set of changes, if forwarding is blocked, we send a Dial event with a forwarding destination but no forwarding channel, since we were prevented from creating one. This is again useful for ARI since application writers can now handle call forward attempts from within their own application. ASTERISK-25925 #close Reported by Mark Michelson Change-Id: I42cbec7730d84640a434d143a0d172a740995543 --- CHANGES | 11 +++++++++++ UPGRADE.txt | 8 ++++++++ apps/app_dial.c | 5 +++++ apps/app_followme.c | 3 +++ apps/app_queue.c | 4 ++++ main/bridge_channel.c | 29 +++++++++++++++++++++++++++++ main/cdr.c | 9 ++++++++- main/dial.c | 3 +++ main/manager_channels.c | 36 +++++++++++++++++++++++++++++++++++- main/stasis_channels.c | 2 +- 10 files changed, 107 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 255ccd24acc..fe3a2539641 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,13 @@ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ +AMI +----------------- + * A new event, "DialState" has been added. This is similar to "DialBegin" and + "DialEnd" in that it tracks the state of a dialed call. The difference is that + this indicates some intermediate state change in the dial attempt, such as + "RINGING", "PROGRESS", or "PROCEEDING". + ARI ----------------- * A new ARI method has been added to the channels resource. "create" allows for @@ -23,6 +30,10 @@ ARI * To complement the "create" method, a "dial" method has been added to the channels resource in order to place a call to a created channel. + * "Dial" events have been modified to not only be sent when dialing begins and ends. + They now are also sent for intermediate states, such as "RINGING", "PROGRESS", and + "PROCEEDING". + Applications ------------------ diff --git a/UPGRADE.txt b/UPGRADE.txt index 131ce6caab2..f8fa7906b42 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -22,6 +22,14 @@ === UPGRADE-13.txt -- Upgrade info for 12 to 13 =========================================================== +ARI: + - The policy for when to send "Dial" events has changed. Previously, "Dial" + events were sent on the calling channel's topic. However, starting in Asterisk + 14, if there is no calling channel on which to send the event, the event is + instead sent on the called channel's topic. Note that for the ARI channels + resource's dial operation, this means that the "Dial" events will always be + sent on the called channel's topic. + Channel Drivers: chan_dahdi: diff --git a/apps/app_dial.c b/apps/app_dial.c index 11591bdfbe7..5e034d3ebe2 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -872,6 +872,8 @@ static void do_forward(struct chanlist *o, struct cause_args *num, /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */ if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) { ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", ast_channel_name(in), tech, stuff); + ast_channel_publish_dial_forward(in, original, NULL, NULL, "CANCEL", + ast_channel_call_forward(original)); c = o->chan = NULL; cause = AST_CAUSE_BUSY; } else { @@ -1385,6 +1387,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, pa->sentringing++; } } + ast_channel_publish_dial(in, c, NULL, "RINGING"); break; case AST_CONTROL_PROGRESS: ast_verb(3, "%s is making progress passing it to %s\n", ast_channel_name(c), ast_channel_name(in)); @@ -1404,6 +1407,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, dtmf_progress); ast_dtmf_stream(c, in, dtmf_progress, 250, 0); } + ast_channel_publish_dial(in, c, NULL, "PROGRESS"); break; case AST_CONTROL_VIDUPDATE: case AST_CONTROL_SRCUPDATE: @@ -1476,6 +1480,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } if (!ast_test_flag64(outgoing, OPT_RINGBACK)) ast_indicate(in, AST_CONTROL_PROCEEDING); + ast_channel_publish_dial(in, c, NULL, "PROCEEDING"); break; case AST_CONTROL_HOLD: /* XXX this should be saved like AST_CONTROL_CONNECTED_LINE for !single || caller_entertained */ diff --git a/apps/app_followme.c b/apps/app_followme.c index d2000fd1353..6687534171b 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -822,9 +822,11 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us break; case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", ast_channel_name(winner)); + ast_channel_publish_dial(caller, winner, NULL, "RINGING"); break; case AST_CONTROL_PROGRESS: ast_verb(3, "%s is making progress\n", ast_channel_name(winner)); + ast_channel_publish_dial(caller, winner, NULL, "PROGRESS"); break; case AST_CONTROL_VIDUPDATE: ast_verb(3, "%s requested a video update\n", ast_channel_name(winner)); @@ -834,6 +836,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us break; case AST_CONTROL_PROCEEDING: ast_verb(3, "%s is proceeding\n", ast_channel_name(winner)); + ast_channel_publish_dial(caller, winner, NULL, "PROCEEDING"); break; case AST_CONTROL_HOLD: ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner)); diff --git a/apps/app_queue.c b/apps/app_queue.c index 8171d11cb47..165924e0c88 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4846,6 +4846,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte /* Before processing channel, go ahead and check for forwarding */ if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) { ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan)); + ast_channel_publish_dial_forward(qe->chan, o->chan, NULL, NULL, + "CANCEL", ast_channel_call_forward(o->chan)); numnochan++; do_hang(o); winner = NULL; @@ -5052,6 +5054,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", ochan_name); + ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING"); + /* Start ring indication when the channel is ringing, if specified */ if (qe->ring_when_ringing) { ast_moh_stop(qe->chan); diff --git a/main/bridge_channel.c b/main/bridge_channel.c index db4ecfe57cd..6766dff8ec1 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2393,6 +2393,14 @@ static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_ch return frame; } +static const char *controls[] = { + [AST_CONTROL_RINGING] = "RINGING", + [AST_CONTROL_PROCEEDING] = "PROCEEDING", + [AST_CONTROL_PROGRESS] = "PROGRESS", + [AST_CONTROL_BUSY] = "BUSY", + [AST_CONTROL_CONGESTION] = "CONGESTION", + [AST_CONTROL_ANSWER] = "ANSWER", +}; /*! * \internal @@ -2404,6 +2412,17 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) { struct ast_frame *frame; + if (!ast_strlen_zero(ast_channel_call_forward(bridge_channel->chan))) { + /* TODO If early bridging is ever used by anything other than ARI, + * it's important that we actually attempt to handle the call forward + * attempt, as well as expand features on a bridge channel to allow/disallow + * call forwarding. For now, all we do is raise an event, showing that + * a call forward is being attempted. + */ + ast_channel_publish_dial_forward(NULL, bridge_channel->chan, NULL, NULL, "CANCEL", + ast_channel_call_forward(bridge_channel->chan)); + } + if (bridge_channel->features->mute) { frame = ast_read_noaudio(bridge_channel->chan); } else { @@ -2417,10 +2436,20 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) switch (frame->frametype) { case AST_FRAME_CONTROL: switch (frame->subclass.integer) { + case AST_CONTROL_CONGESTION: + case AST_CONTROL_BUSY: + ast_channel_publish_dial(NULL, bridge_channel->chan, NULL, controls[frame->subclass.integer]); + break; case AST_CONTROL_HANGUP: ast_bridge_channel_kick(bridge_channel, 0); bridge_frame_free(frame); return; + case AST_CONTROL_RINGING: + case AST_CONTROL_PROGRESS: + case AST_CONTROL_PROCEEDING: + case AST_CONTROL_ANSWER: + ast_channel_publish_dial(NULL, bridge_channel->chan, NULL, controls[frame->subclass.integer]); + break; default: break; } diff --git a/main/cdr.c b/main/cdr.c index b6a0b428c98..b43e3610c07 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1902,6 +1902,13 @@ static int filter_channel_cache_message(struct ast_channel_snapshot *old_snapsho return ret; } +static int dial_status_end(const char *dialstatus) +{ + return (strcmp(dialstatus, "RINGING") && + strcmp(dialstatus, "PROCEEDING") && + strcmp(dialstatus, "PROGRESS")); +} + /* TOPIC ROUTER CALLBACKS */ /*! @@ -1970,7 +1977,7 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str res &= it_cdr->fn_table->process_dial_begin(it_cdr, caller, peer); - } else { + } else if (dial_status_end(dial_status)) { if (!it_cdr->fn_table->process_dial_end) { continue; } diff --git a/main/dial.c b/main/dial.c index fc66af5a766..bac191e0657 100644 --- a/main/dial.c +++ b/main/dial.c @@ -627,11 +627,13 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel break; case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", ast_channel_name(channel->owner)); + ast_channel_publish_dial(chan, channel->owner, channel->device, "RINGING"); if (chan && !dial->options[AST_DIAL_OPTION_MUSIC]) ast_indicate(chan, AST_CONTROL_RINGING); set_state(dial, AST_DIAL_RESULT_RINGING); break; case AST_CONTROL_PROGRESS: + ast_channel_publish_dial(chan, channel->owner, channel->device, "PROGRESS"); if (chan) { ast_verb(3, "%s is making progress, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); ast_indicate(chan, AST_CONTROL_PROGRESS); @@ -675,6 +677,7 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel } break; case AST_CONTROL_PROCEEDING: + ast_channel_publish_dial(chan, channel->owner, channel->device, "PROCEEDING"); if (chan) { ast_verb(3, "%s is proceeding, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); ast_indicate(chan, AST_CONTROL_PROCEEDING); diff --git a/main/manager_channels.c b/main/manager_channels.c index c395708cc9a..ec1f807dcf2 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -142,6 +142,33 @@ ASTERISK_REGISTER_FILE() + + + Raised when dial status has changed. + + + + + The new state of the outbound dial attempt. + + + The outbound channel is ringing. + + + The call to the outbound channel is proceeding. + + + Progress has been received on the outbound channel. + + + + + If the call was forwarded, where the call was + forwarded to. + + + + Raised when a dial action has completed. @@ -1034,6 +1061,13 @@ static void channel_monitor_stop_cb(void *data, struct stasis_subscription *sub, publish_basic_channel_event("MonitorStop", EVENT_FLAG_CALL, payload->snapshot); } +static int dial_status_end(const char *dialstatus) +{ + return (strcmp(dialstatus, "RINGING") && + strcmp(dialstatus, "PROCEEDING") && + strcmp(dialstatus, "PROGRESS")); +} + /*! * \brief Callback processing messages for channel dialing */ @@ -1077,7 +1111,7 @@ static void channel_dial_cb(void *data, struct stasis_subscription *sub, } else { int forwarded = !ast_strlen_zero(forward); - manager_event(EVENT_FLAG_CALL, "DialEnd", + manager_event(EVENT_FLAG_CALL, dial_status_end(dialstatus) ? "DialEnd" : "DialState", "%s" "%s" "%s%s%s" diff --git a/main/stasis_channels.c b/main/stasis_channels.c index e56d1b928b2..e1c50c6d05f 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -362,7 +362,7 @@ static void ast_channel_publish_dial_internal(struct ast_channel *caller, return; } - publish_message_for_channel_topics(msg, caller); + publish_message_for_channel_topics(msg, caller ?: peer); } static void remove_dial_masquerade(struct ast_channel *peer); From aec7916595b24c7504751231f648fff36fdb1707 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 31 May 2016 13:02:15 -0500 Subject: [PATCH 0468/1578] pjsip_distributor.c: Use correct rdata info access method (Part 2). The pjproject doxygen for rdata->msg_info.info says to call pjsip_rx_data_get_info() instead of accessing the struct member directly. You need to call the function mostly because the function will generate the struct member value if it is not already setup. Change-Id: I4d519385a577f3e9d9193a88125e493cf17fa799 --- res/res_pjsip/pjsip_distributor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 0d3df06f071..3867eaea0c8 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -297,13 +297,13 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) if (dlg) { ast_debug(3, "Searching for serializer on dialog %s for %s\n", - dlg->obj_name, rdata->msg_info.info); + dlg->obj_name, pjsip_rx_data_get_info(rdata)); dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id); if (dist) { serializer = ao2_bump(dist->serializer); if (serializer) { ast_debug(3, "Found serializer %s on dialog %s\n", - ast_taskprocessor_name(serializer), dlg->obj_name); + ast_taskprocessor_name(serializer), dlg->obj_name); } } pjsip_dlg_dec_lock(dlg); @@ -313,7 +313,7 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) /* We have a serializer so we know where to send the message. */ } else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) { ast_debug(3, "No dialog serializer for response %s. Using request transaction as basis\n", - rdata->msg_info.info); + pjsip_rx_data_get_info(rdata)); serializer = find_request_serializer(rdata); } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || !pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method)) { From 40d19f2e5531fd3455e21a51e39a7244580609bb Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 1 Jun 2016 13:57:53 -0500 Subject: [PATCH 0469/1578] logging,cdr,cel: Fix stringfield memory leak. The stringfields refactor to allow adding stringfields to the end of a structure (f6f4cf459f43f072604927209b39646f84aaa2e2) exposed some incomplete cleanup code by some stringfield users. The most noticeable leaker is the logging system where there is a leak for every log message generated. ASTERISK-26078 #close Reported by: Etienne Lessard Patches: jira_asterisk_26078_v13.patch (license #5621) patch uploaded by Richard Mudgett Change-Id: If6a08b31336b492c3de6f9dfd07c447f8d5a8782 --- cdr/cdr_custom.c | 2 ++ cdr/cdr_syslog.c | 2 ++ cel/cel_custom.c | 2 ++ main/logger.c | 1 + 4 files changed, 7 insertions(+) diff --git a/cdr/cdr_custom.c b/cdr/cdr_custom.c index 24cb834f699..bb63ea0c646 100644 --- a/cdr/cdr_custom.c +++ b/cdr/cdr_custom.c @@ -81,8 +81,10 @@ static AST_RWLIST_HEAD_STATIC(sinks, cdr_custom_config); static void free_config(void) { struct cdr_custom_config *sink; + while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) { ast_mutex_destroy(&sink->lock); + ast_string_field_free_memory(sink); ast_free(sink); } } diff --git a/cdr/cdr_syslog.c b/cdr/cdr_syslog.c index 85860ececdc..39f115920dc 100644 --- a/cdr/cdr_syslog.c +++ b/cdr/cdr_syslog.c @@ -76,8 +76,10 @@ static AST_RWLIST_HEAD_STATIC(sinks, cdr_syslog_config); static void free_config(void) { struct cdr_syslog_config *sink; + while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) { ast_mutex_destroy(&sink->lock); + ast_string_field_free_memory(sink); ast_free(sink); } } diff --git a/cel/cel_custom.c b/cel/cel_custom.c index f6377fcd71b..f75efdd4be4 100644 --- a/cel/cel_custom.c +++ b/cel/cel_custom.c @@ -71,8 +71,10 @@ static AST_RWLIST_HEAD_STATIC(sinks, cel_config); static void free_config(void) { struct cel_config *sink; + while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) { ast_mutex_destroy(&sink->lock); + ast_string_field_free_memory(sink); ast_free(sink); } } diff --git a/main/logger.c b/main/logger.c index ae1e0bd8d18..9a16dcf13bc 100644 --- a/main/logger.c +++ b/main/logger.c @@ -174,6 +174,7 @@ struct logmsg { static void logmsg_free(struct logmsg *msg) { + ast_string_field_free_memory(msg); ast_free(msg); } From 4505a59dc97463a93871e499c59a641874db8574 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 2 Jun 2016 06:59:06 -0300 Subject: [PATCH 0470/1578] alembic: Fix migration. The 81b01a191a46_pjsip_add_contact_reg_server.py script was attempting to use UniqueConstraint and failing. It was not imported and after importing it also continued to fail. I've changed the script to use the explicit name of the constraint instead. Change-Id: I2438b0be90b7ce583b47dd27983c0c1a02cea5b9 --- .../versions/81b01a191a46_pjsip_add_contact_reg_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py index c25fc72335a..0318b9a4fcf 100644 --- a/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py +++ b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py @@ -16,7 +16,7 @@ def upgrade(): op.add_column('ps_contacts', sa.Column('reg_server', sa.String(20))) - op.drop_constraint(UniqueConstraint('id'), 'ps_contacts', type_='unique') + op.drop_constraint('id', 'ps_contacts', type_='unique') op.create_unique_constraint('ps_contacts_uq', 'ps_contacts', ['id','reg_server']) def downgrade(): From 8a5c2e736cd7c9bb3c9806c54c9d0c12d23a5a05 Mon Sep 17 00:00:00 2001 From: Niklas Larsson Date: Wed, 25 May 2016 15:45:08 +0200 Subject: [PATCH 0471/1578] core/manager: Add uptime field to FullyBooted Add Uptime and LastReload to event FullyBooted. ASTERISK-26058 #close Reported by: Niklas Larsson Change-Id: I909b330801c0990d78df9b272ab0adc95aecb15e --- main/asterisk.c | 30 +++++++++++++++++++++++++++--- main/manager.c | 18 +++++++++++++++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/main/asterisk.c b/main/asterisk.c index 6cfbc1b336b..25c6c956905 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -260,6 +260,12 @@ int daemon(int, int); /* defined in libresolv of all places */ Informational message + + Seconds since start + + + Seconds since last reload + @@ -1020,9 +1026,25 @@ static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_c static void publish_fully_booted(void) { RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref); + int uptime = 0; + int lastreloaded = 0; + struct timeval tmp; + struct timeval curtime = ast_tvnow(); - json_object = ast_json_pack("{s: s}", - "Status", "Fully Booted"); + if (ast_startuptime.tv_sec) { + tmp = ast_tvsub(curtime, ast_startuptime); + uptime = (int) tmp.tv_sec; + } + + if (ast_lastreloadtime.tv_sec) { + tmp = ast_tvsub(curtime, ast_lastreloadtime); + lastreloaded = (int) tmp.tv_sec; + } + + json_object = ast_json_pack("{s: s, s: i, s: i}", + "Status", "Fully Booted", + "Uptime", uptime, + "LastReload", lastreloaded); ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object); } @@ -4221,6 +4243,9 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou char *buf; int moduleresult; /*!< Result from the module load subsystem */ + /* Set time as soon as possible */ + ast_lastreloadtime = ast_startuptime = ast_tvnow(); + /* This needs to remain as high up in the initial start up as possible. * daemon causes a fork to occur, which has all sorts of unintended * consequences for things that interact with threads. This call *must* @@ -4689,7 +4714,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou __ast_mm_init_phase_2(); #endif /* defined(__AST_DEBUG_MALLOC) */ - ast_lastreloadtime = ast_startuptime = ast_tvnow(); ast_cli_register_multiple(cli_asterisk_shutdown, ARRAY_LEN(cli_asterisk_shutdown)); ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk)); ast_register_cleanup(main_atexit); diff --git a/main/manager.c b/main/manager.c index d2fdc403dbc..94415b7a0d8 100644 --- a/main/manager.c +++ b/main/manager.c @@ -4157,10 +4157,26 @@ static int action_login(struct mansession *s, const struct message *m) && ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING); const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth); + long uptime = 0; + long lastreloaded = 0; + struct timeval tmp; + struct timeval curtime = ast_tvnow(); + + if (ast_startuptime.tv_sec) { + tmp = ast_tvsub(curtime, ast_startuptime); + uptime = tmp.tv_sec; + } + + if (ast_lastreloadtime.tv_sec) { + tmp = ast_tvsub(curtime, ast_lastreloadtime); + lastreloaded = tmp.tv_sec; + } astman_append(s, "Event: FullyBooted\r\n" "Privilege: %s\r\n" - "Status: Fully Booted\r\n\r\n", cat_str); + "Uptime: %ld\r\n" + "LastReload: %ld\r\n" + "Status: Fully Booted\r\n\r\n", cat_str, uptime, lastreloaded); } return 0; } From 9c1d95e87358b17aec9fbb0a13c31b7bb9350450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 2 Jun 2016 22:53:39 +0300 Subject: [PATCH 0472/1578] Fix #include poll.h and sys/cdefs.h POSIX defines poll.h, sys/poll.h should not be used at is c-library internal header which may or may not exist. Notable in musl it generates warning of being incorrect. And add explict include of sys/cdefs.h where needed. Change-Id: I142930df53fe7585a06b854b6faddc5301e024be --- include/asterisk/compat.h | 2 +- include/asterisk/poll-compat.h | 2 +- main/ast_expr2.c | 1 + main/ast_expr2.y | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/asterisk/compat.h b/include/asterisk/compat.h index 3eb6c96a2d3..252ce914a27 100644 --- a/include/asterisk/compat.h +++ b/include/asterisk/compat.h @@ -70,7 +70,7 @@ #endif #ifndef AST_POLL_COMPAT -#include +#include #else #include "asterisk/poll-compat.h" #endif diff --git a/include/asterisk/poll-compat.h b/include/asterisk/poll-compat.h index cbb61092514..72ac2c3e2f2 100644 --- a/include/asterisk/poll-compat.h +++ b/include/asterisk/poll-compat.h @@ -83,7 +83,7 @@ #ifndef AST_POLL_COMPAT -#include +#include #define ast_poll(a, b, c) poll(a, b, c) diff --git a/main/ast_expr2.c b/main/ast_expr2.c index d41072d6e4b..c700b01d73f 100644 --- a/main/ast_expr2.c +++ b/main/ast_expr2.c @@ -94,6 +94,7 @@ #define ASTMM_LIBC ASTMM_REDIRECT #include "asterisk.h" +#include #include #include diff --git a/main/ast_expr2.y b/main/ast_expr2.y index 762e83d840f..df87bcc7f6b 100644 --- a/main/ast_expr2.y +++ b/main/ast_expr2.y @@ -15,6 +15,7 @@ #define ASTMM_LIBC ASTMM_REDIRECT #include "asterisk.h" +#include #include #include From 3c1fec80995dc9ada49f471310877e9d9e12ad55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 2 Jun 2016 22:57:49 +0300 Subject: [PATCH 0473/1578] Fix res_search usage Resolver state is not part of res_search API. This fixes compilation error: dns.c:261:8: error: too many arguments to function 'res_search' ret = res_search(&dns_state, Change-Id: Ia600a58557040df83f744da3dde23225293845a5 --- main/dns.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/main/dns.c b/main/dns.c index 96227949ee2..fa94089e792 100644 --- a/main/dns.c +++ b/main/dns.c @@ -254,12 +254,10 @@ static int dns_search_res(const char *dname, int rr_class, int rr_type, { int ret = AST_DNS_SEARCH_FAILURE; - struct __res_state dns_state; ast_mutex_lock(&res_lock); res_init(); - ret = res_search(&dns_state, - dname, + ret = res_search(dname, rr_class, rr_type, dns_response, From 797695c5ccbfb242f763d552921a23ce03b779ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 3 Jun 2016 08:39:02 +0300 Subject: [PATCH 0474/1578] Make use of GLOB_BRACE and GLOB_NOMAGIC optional These flags are non-portable GNU extensions. Make their use optional. This fixes complication error on e.g. musl c-library based systems. Change-Id: I0aa06efc62aa8995f091445c8b762a75a91042f3 --- res/ael/ael.flex | 6 ++++++ res/ael/ael_lex.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/res/ael/ael.flex b/res/ael/ael.flex index b1b2bd76dca..4e87f3a401e 100644 --- a/res/ael/ael.flex +++ b/res/ael/ael.flex @@ -80,6 +80,12 @@ ASTERISK_REGISTER_FILE() #if !defined(GLOB_ABORTED) #define GLOB_ABORTED GLOB_ABEND #endif +#if !defined(GLOB_BRACE) +#define GLOB_BRACE 0 +#endif +#if !defined(GLOB_NOMAGIC) +#define GLOB_NOMAGIC 0 +#endif #include "asterisk/logger.h" #include "asterisk/utils.h" diff --git a/res/ael/ael_lex.c b/res/ael/ael_lex.c index a7a20aa60f1..9fbd664294e 100644 --- a/res/ael/ael_lex.c +++ b/res/ael/ael_lex.c @@ -839,6 +839,12 @@ ASTERISK_REGISTER_FILE() #if !defined(GLOB_ABORTED) #define GLOB_ABORTED GLOB_ABEND #endif +#if !defined(GLOB_BRACE) +#define GLOB_BRACE 0 +#endif +#if !defined(GLOB_NOMAGIC) +#define GLOB_NOMAGIC 0 +#endif #include "asterisk/logger.h" #include "asterisk/utils.h" From 538c6415c6d255876a808d69acd9f5ebd603b286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 3 Jun 2016 09:33:08 +0300 Subject: [PATCH 0475/1578] chan_sip: Support auth username for callbackextension feature ASTERISK-20527 #close Change-Id: I659cf7f00836a09d09d146ad226a40477d731239 --- channels/chan_sip.c | 2 +- configs/samples/sip.conf.sample | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 19f8aa308a8..03cba924476 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -31811,7 +31811,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str olddirectmediaacl = ast_free_acl_list(olddirectmediaacl); if (!ast_strlen_zero(peer->callback)) { /* build string from peer info */ char *reg_string; - if (ast_asprintf(®_string, "%s?%s:%s@%s/%s", peer->name, peer->username, !ast_strlen_zero(peer->remotesecret) ? peer->remotesecret : peer->secret, peer->tohost, peer->callback) >= 0) { + if (ast_asprintf(®_string, "%s?%s:%s:%s@%s/%s", peer->name, S_OR(peer->fromuser, peer->username), S_OR(peer->remotesecret, peer->secret), peer->username, peer->tohost, peer->callback) >= 0) { sip_register(reg_string, 0); /* XXX TODO: count in registry_count */ ast_free(reg_string); } diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample index 8f28e26801a..a7b74df690d 100644 --- a/configs/samples/sip.conf.sample +++ b/configs/samples/sip.conf.sample @@ -786,7 +786,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; A similar effect can be achieved by adding a "callbackextension" option in a peer section. ; this is equivalent to having the following line in the general section: ; -; register => username:secret@host/callbackextension +; register => fromuser:secret:username@host/callbackextension ; ; and more readable because you don't have to write the parameters in two places ; (note that the "port" is ignored - this is a bug that should be fixed). From a2f820e8dc168e93d00245bd0e4a4a8e8eb64022 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 27 May 2016 13:49:42 -0600 Subject: [PATCH 0476/1578] ari/resource_channels: Add 'formats' to channel create/originate If you create a local channel and don't specify an originator channel to take capabilities from, we automatically add all audio formats to the new channel's capabilities. When we try to make the channel compatible with another, the "best format" functions pick the best format available, which in this case will be slin192. While this is great for preserving quality, it's the worst for performance and overkill for the vast majority of applications. In the absense of any other information, adding all formats is the correct thing to do and it's not always possible to supply an originator so a new parameter 'formats' has been added to the channel create/originate functions. It's just a comma separated list of formats to make availalble for the channel. Example: "ulaw,slin,slin16". 'formats' and 'originator' are mutually exclusive. To facilitate determination of format names, the format name has been added to "core show codecs". ASTERISK-26070 #close Change-Id: I091b23ecd41c1b4128d85028209772ee139f604b --- CHANGES | 12 +++++ include/asterisk/codec.h | 2 + main/codec.c | 10 ++-- main/codec_builtin.c | 6 ++- res/ari/resource_channels.c | 88 ++++++++++++++++++++++++++++++++- res/ari/resource_channels.h | 6 +++ res/res_ari_channels.c | 21 ++++++++ res/res_ari_recordings.c | 1 + rest-api/api-docs/channels.json | 24 +++++++++ 9 files changed, 162 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 281cff393ca..789ef7d0abe 100644 --- a/CHANGES +++ b/CHANGES @@ -362,6 +362,18 @@ app_confbridge server installations via alternate means (DUNDI for example). By default this feature is not used. +Codecs +------------------ + * Added the associated format name to 'core show codecs'. + +res_ari_channels +------------------ + * Added 'formats' to channel create/originate to allow setting the allowed + formats for a channel when no originator channel is available. Especially + useful for Local channel creation where no other format information is + available. 'core show codecs' can now be used to look up suitable format + names. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.8.0 to Asterisk 13.9.0 ------------ ------------------------------------------------------------------------------ diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h index 3873324b143..4ea94f9bbd0 100644 --- a/include/asterisk/codec.h +++ b/include/asterisk/codec.h @@ -77,6 +77,8 @@ struct ast_codec { unsigned int smooth; /*! \brief The module that registered this codec */ struct ast_module *mod; + /*! \brief A format name for a default sane format using this codec */ + const char *format_name; }; /*! diff --git a/main/codec.c b/main/codec.c index 9c4169a1cc7..a7626450303 100644 --- a/main/codec.c +++ b/main/codec.c @@ -135,8 +135,8 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args * "\tIt does not indicate anything about your configuration.\n"); } - ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION"); - ast_cli(a->fd, "-----------------------------------------------------------------------------------\n"); + ast_cli(a->fd, "%8s %-5s %-12s %-16s %s\n","ID","TYPE","NAME","FORMAT","DESCRIPTION"); + ast_cli(a->fd, "------------------------------------------------------------------------------------------------\n"); ao2_rdlock(codecs); i = ao2_iterator_init(codecs, AO2_ITERATOR_DONTLOCK); @@ -164,10 +164,11 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args * } } - ast_cli(a->fd, "%8u %5s %8s (%s)\n", + ast_cli(a->fd, "%8u %-5s %-12s %-16s (%s)\n", codec->id, ast_codec_media_type2str(codec->type), codec->name, + S_OR(codec->format_name, "no cached format"), codec->description); } @@ -216,7 +217,8 @@ static char *show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a return CLI_SUCCESS; } - ast_cli(a->fd, "%11u %s\n", (unsigned int) codec->id, codec->description); + ast_cli(a->fd, "%11u %s (%s)\n", (unsigned int) codec->id, codec->description, + S_OR(codec->format_name, "no format")); ao2_ref(codec, -1); diff --git a/main/codec_builtin.c b/main/codec_builtin.c index f86a8dfc89e..fdaa018255f 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -774,6 +774,7 @@ static struct ast_codec t140 = { int __res_ ## __LINE__ = 0; \ struct ast_format *__fmt_ ## __LINE__; \ struct ast_codec *__codec_ ## __LINE__; \ + codec.format_name = (codec).name; \ res |= __ast_codec_register(&(codec), NULL); \ __codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \ __fmt_ ## __LINE__ = __codec_ ## __LINE__ ? ast_format_create(__codec_ ## __LINE__) : NULL; \ @@ -783,14 +784,15 @@ static struct ast_codec t140 = { __res_ ## __LINE__; \ }) -#define CODEC_REGISTER_AND_CACHE_NAMED(format_name, codec) \ +#define CODEC_REGISTER_AND_CACHE_NAMED(fmt_name, codec) \ ({ \ int __res_ ## __LINE__ = 0; \ struct ast_format *__fmt_ ## __LINE__; \ struct ast_codec *__codec_ ## __LINE__; \ + codec.format_name = fmt_name; \ res |= __ast_codec_register(&(codec), NULL); \ __codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \ - __fmt_ ## __LINE__ = ast_format_create_named((format_name), __codec_ ## __LINE__); \ + __fmt_ ## __LINE__ = ast_format_create_named((fmt_name), __codec_ ## __LINE__); \ res |= ast_format_cache_set(__fmt_ ## __LINE__); \ ao2_ref(__fmt_ ## __LINE__, -1); \ ao2_ref(__codec_ ## __LINE__, -1); \ diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index b42581c8463..7c43bdd7280 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -915,6 +915,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint, const char *args_channel_id, const char *args_other_channel_id, const char *args_originator, + const char *args_formats, struct ast_ari_response *response) { char *dialtech; @@ -933,6 +934,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint, }; struct ari_origination *origination; pthread_t thread; + struct ast_format_cap *format_cap = NULL; if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid)) || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) { @@ -947,6 +949,12 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint, return; } + if (!ast_strlen_zero(args_originator) && !ast_strlen_zero(args_formats)) { + ast_ari_response_error(response, 400, "Bad Request", + "Originator and formats can't both be specified"); + return; + } + dialtech = ast_strdupa(args_endpoint); if ((stuff = strchr(dialtech, '/'))) { *stuff++ = '\0'; @@ -1069,7 +1077,41 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint, } } - if (ast_dial_prerun(dial, other, NULL)) { + if (!ast_strlen_zero(args_formats)) { + char *format_name; + char *formats_copy = ast_strdupa(args_formats); + + if (!(format_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ast_ari_response_alloc_failed(response); + ast_dial_destroy(dial); + ast_free(origination); + ast_channel_cleanup(other); + return; + } + + while ((format_name = ast_strip(strsep(&formats_copy, ",")))) { + struct ast_format *fmt = ast_format_cache_get(format_name); + + if (!fmt || ast_format_cap_append(format_cap, fmt, 0)) { + if (!fmt) { + ast_ari_response_error( + response, 400, "Bad Request", + "Provided format (%s) was not found", format_name); + } else { + ast_ari_response_alloc_failed(response); + } + ast_dial_destroy(dial); + ast_free(origination); + ast_channel_cleanup(other); + ao2_ref(format_cap, -1); + ao2_cleanup(fmt); + return; + } + ao2_ref(fmt, -1); + } + } + + if (ast_dial_prerun(dial, other, format_cap)) { ast_ari_response_alloc_failed(response); ast_dial_destroy(dial); ast_free(origination); @@ -1078,6 +1120,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint, } ast_channel_cleanup(other); + ao2_cleanup(format_cap); chan = ast_dial_get_channel(dial, 0); if (!chan) { @@ -1218,6 +1261,7 @@ void ast_ari_channels_originate_with_id(struct ast_variable *headers, args->channel_id, args->other_channel_id, args->originator, + args->formats, response); ast_variables_destroy(variables); } @@ -1254,6 +1298,7 @@ void ast_ari_channels_originate(struct ast_variable *headers, args->channel_id, args->other_channel_id, args->originator, + args->formats, response); ast_variables_destroy(variables); } @@ -1527,6 +1572,12 @@ void ast_ari_channels_create(struct ast_variable *headers, return; } + if (!ast_strlen_zero(args->originator) && !ast_strlen_zero(args->formats)) { + ast_ari_response_error(response, 400, "Bad Request", + "Originator and formats can't both be specified"); + return; + } + chan_data->stasis_stuff = ast_str_create(32); if (!chan_data->stasis_stuff) { ast_ari_response_alloc_failed(response); @@ -1548,8 +1599,41 @@ void ast_ari_channels_create(struct ast_variable *headers, originator = ast_channel_get_by_name(args->originator); if (originator) { request_cap = ao2_bump(ast_channel_nativeformats(originator)); + } else if (!ast_strlen_zero(args->formats)) { + char *format_name; + char *formats_copy = ast_strdupa(args->formats); + + if (!(request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ast_ari_response_alloc_failed(response); + chan_data_destroy(chan_data); + return; + } + + while ((format_name = ast_strip(strsep(&formats_copy, ",")))) { + struct ast_format *fmt = ast_format_cache_get(format_name); + + if (!fmt || ast_format_cap_append(request_cap, fmt, 0)) { + if (!fmt) { + ast_ari_response_error( + response, 400, "Bad Request", + "Provided format (%s) was not found", format_name); + } else { + ast_ari_response_alloc_failed(response); + } + ao2_ref(request_cap, -1); + ao2_cleanup(fmt); + chan_data_destroy(chan_data); + return; + } + ao2_ref(fmt, -1); + } } else { - request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!(request_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ast_ari_response_alloc_failed(response); + chan_data_destroy(chan_data); + return; + } + ast_format_cap_append_by_type(request_cap, AST_MEDIA_TYPE_AUDIO); } diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h index c690d70c813..951433f1312 100644 --- a/res/ari/resource_channels.h +++ b/res/ari/resource_channels.h @@ -78,6 +78,8 @@ struct ast_ari_channels_originate_args { const char *other_channel_id; /*! The unique id of the channel which is originating this one. */ const char *originator; + /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */ + const char *formats; }; /*! * \brief Body parsing function for /channels. @@ -114,6 +116,8 @@ struct ast_ari_channels_create_args { const char *other_channel_id; /*! Unique ID of the calling channel */ const char *originator; + /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */ + const char *formats; }; /*! * \brief Body parsing function for /channels/create. @@ -175,6 +179,8 @@ struct ast_ari_channels_originate_with_id_args { const char *other_channel_id; /*! The unique id of the channel which is originating this one. */ const char *originator; + /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */ + const char *formats; }; /*! * \brief Body parsing function for /channels/{channelId}. diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 951a5475bc0..412c06d9860 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -157,6 +157,10 @@ int ast_ari_channels_originate_parse_body( if (field) { args->originator = ast_json_string_get(field); } + field = ast_json_object_get(body, "formats"); + if (field) { + args->formats = ast_json_string_get(field); + } return 0; } @@ -217,6 +221,9 @@ static void ast_ari_channels_originate_cb( if (strcmp(i->name, "originator") == 0) { args.originator = (i->value); } else + if (strcmp(i->name, "formats") == 0) { + args.formats = (i->value); + } else {} } /* Look for a JSON request entity */ @@ -298,6 +305,10 @@ int ast_ari_channels_create_parse_body( if (field) { args->originator = ast_json_string_get(field); } + field = ast_json_object_get(body, "formats"); + if (field) { + args->formats = ast_json_string_get(field); + } return 0; } @@ -340,6 +351,9 @@ static void ast_ari_channels_create_cb( if (strcmp(i->name, "originator") == 0) { args.originator = (i->value); } else + if (strcmp(i->name, "formats") == 0) { + args.formats = (i->value); + } else {} } /* Look for a JSON request entity */ @@ -502,6 +516,10 @@ int ast_ari_channels_originate_with_id_parse_body( if (field) { args->originator = ast_json_string_get(field); } + field = ast_json_object_get(body, "formats"); + if (field) { + args->formats = ast_json_string_get(field); + } return 0; } @@ -559,6 +577,9 @@ static void ast_ari_channels_originate_with_id_cb( if (strcmp(i->name, "originator") == 0) { args.originator = (i->value); } else + if (strcmp(i->name, "formats") == 0) { + args.formats = (i->value); + } else {} } for (i = path_vars; i; i = i->next) { diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index abc264d9e51..a21943520c9 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -257,6 +257,7 @@ static void ast_ari_recordings_get_stored_file_cb( break; case 500: /* Internal Server Error */ case 501: /* Not Implemented */ + case 403: /* The recording file could not be opened */ case 404: /* Recording not found */ is_valid = 1; break; diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index aafd231a1f3..9e8c7c3d4cb 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -128,6 +128,14 @@ "required": false, "allowMultiple": false, "dataType": "string" + }, + { + "name": "formats", + "description": "The format name capability list to use if originator is not specified. Ex. \"ulaw,slin16\". Format names can be found with \"core show codecs\".", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" } ], "errorResponses": [ @@ -196,6 +204,14 @@ "required": false, "allowMultiple": false, "dataType": "string" + }, + { + "name": "formats", + "description": "The format name capability list to use if originator is not specified. Ex. \"ulaw,slin16\". Format names can be found with \"core show codecs\".", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" } ] } @@ -338,6 +354,14 @@ "required": false, "allowMultiple": false, "dataType": "string" + }, + { + "name": "formats", + "description": "The format name capability list to use if originator is not specified. Ex. \"ulaw,slin16\". Format names can be found with \"core show codecs\".", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" } ], "errorResponses": [ From 3e8d523d889351c69b21fdc563cb98d18a7bdb66 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Wed, 25 May 2016 11:34:42 -0400 Subject: [PATCH 0477/1578] core/dial: New channel variable FORWARDERNAME Added a new channel variable FORWARDERNAME which indicates which channel was responsible for a forwarding requests received on dial attempt. Fixed a bug in the app_queue: FORWARD_CONTEXT is not used. ASTERISK-26059 #close Change-Id: I34e93e8c1b5e17776a77b319703c48c8ca48e7b2 --- CHANGES | 5 +++++ apps/app_dial.c | 3 +++ apps/app_queue.c | 9 ++++++++- main/bridge_channel.c | 3 ++- main/channel.c | 3 +++ main/dial.c | 14 +++++++++++--- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 6ffefbf35fa..608a4a4b33b 100644 --- a/CHANGES +++ b/CHANGES @@ -331,6 +331,11 @@ cdr_csv --- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- ------------------------------------------------------------------------------ +Core +------------------ + * A channel variable FORWARDERNAME is now set which indicates which channel + was responsible for a forwarding requests received on dial attempt. + func_odbc ------------------ * Added new global option "single_db_connection". diff --git a/apps/app_dial.c b/apps/app_dial.c index 5e034d3ebe2..1f019d6c8ab 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -834,6 +834,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num, struct ast_party_id *forced_clid, struct ast_party_id *stored_clid) { char tmpchan[256]; + char forwarder[AST_CHANNEL_NAME]; struct ast_channel *original = o->chan; struct ast_channel *c = o->chan; /* the winner */ struct ast_channel *in = num->chan; /* the input channel */ @@ -842,6 +843,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num, int cause; struct ast_party_caller caller; + ast_copy_string(forwarder, ast_channel_name(c), sizeof(forwarder)); ast_copy_string(tmpchan, ast_channel_call_forward(c), sizeof(tmpchan)); if ((stuff = strchr(tmpchan, '/'))) { *stuff++ = '\0'; @@ -895,6 +897,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num, ast_channel_lock_both(in, o->chan); ast_channel_inherit_variables(in, o->chan); ast_channel_datastore_inherit(in, o->chan); + pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder); ast_max_forwards_decrement(o->chan); ast_channel_unlock(in); ast_channel_unlock(o->chan); diff --git a/apps/app_queue.c b/apps/app_queue.c index 165924e0c88..45297f5f2d3 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4854,16 +4854,22 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte continue; } else if (!ast_strlen_zero(ast_channel_call_forward(o->chan))) { struct ast_channel *original = o->chan; + char forwarder[AST_CHANNEL_NAME]; char tmpchan[256]; char *stuff; char *tech; ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan)); + ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder)); if ((stuff = strchr(tmpchan, '/'))) { *stuff++ = '\0'; tech = tmpchan; } else { - snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), ast_channel_context(o->chan)); + const char *forward_context; + ast_channel_lock(o->chan); + forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT"); + snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan)); + ast_channel_unlock(o->chan); stuff = tmpchan; tech = "Local"; } @@ -4895,6 +4901,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_channel_lock_both(o->chan, in); ast_channel_inherit_variables(in, o->chan); ast_channel_datastore_inherit(in, o->chan); + pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder); ast_max_forwards_decrement(o->chan); if (o->pending_connected_update) { diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 6766dff8ec1..3ba61aa3342 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2162,9 +2162,10 @@ int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel, ast_bridge_publish_enter(bridge, bridge_channel->chan, swap ? swap->chan : NULL); - /* Clear any BLINDTRANSFER and ATTENDEDTRANSFER since the transfer has completed. */ + /* Clear any BLINDTRANSFER,ATTENDEDTRANSFER and FORWARDERNAME since the transfer has completed. */ pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", NULL); pbx_builtin_setvar_helper(bridge_channel->chan, "ATTENDEDTRANSFER", NULL); + pbx_builtin_setvar_helper(bridge_channel->chan, "FORWARDERNAME", NULL); /* Wake up the bridge channel thread to reevaluate any interval timers. */ ast_queue_frame(bridge_channel->chan, &ast_null_frame); diff --git a/main/channel.c b/main/channel.c index 852de1aef8f..f654e4d2577 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5663,6 +5663,7 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, struct ast_format_cap *cap, struct outgoing_helper *oh, int *outstate) { char tmpchan[256]; + char forwarder[AST_CHANNEL_NAME]; struct ast_channel *new_chan = NULL; char *data, *type; int cause = 0; @@ -5670,6 +5671,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan /* gather data and request the new forward channel */ ast_copy_string(tmpchan, ast_channel_call_forward(orig), sizeof(tmpchan)); + ast_copy_string(forwarder, ast_channel_name(orig), sizeof(forwarder)); if ((data = strchr(tmpchan, '/'))) { *data++ = '\0'; type = tmpchan; @@ -5713,6 +5715,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan ast_set_flag(ast_channel_flags(new_chan), AST_FLAG_ORIGINATED); ast_channel_lock_both(orig, new_chan); + pbx_builtin_setvar_helper(new_chan, "FORWARDERNAME", forwarder); ast_party_connected_line_copy(ast_channel_connected(new_chan), ast_channel_connected(orig)); ast_party_redirecting_copy(ast_channel_redirecting(new_chan), ast_channel_redirecting(orig)); ast_channel_req_accountcodes(new_chan, orig, AST_CHANNEL_REQUESTOR_REPLACEMENT); diff --git a/main/dial.c b/main/dial.c index bac191e0657..7677c5a7d0f 100644 --- a/main/dial.c +++ b/main/dial.c @@ -454,16 +454,24 @@ int ast_dial_prerun(struct ast_dial *dial, struct ast_channel *chan, struct ast_ } /*! \brief Helper function that does the beginning dialing per-appended channel */ -static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_channel *chan, int async, const char *predial_string) +static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_channel *chan, int async, const char *predial_string, struct ast_channel *forwarder_chan) { char numsubst[AST_MAX_EXTENSION]; int res = 1; + char forwarder[AST_CHANNEL_NAME]; /* If no owner channel exists yet execute pre-run */ if (!channel->owner && begin_dial_prerun(channel, chan, NULL, predial_string)) { return 0; } + if (forwarder_chan) { + ast_copy_string(forwarder, ast_channel_name(forwarder_chan), sizeof(forwarder)); + ast_channel_lock(channel->owner); + pbx_builtin_setvar_helper(channel->owner, "FORWARDERNAME", forwarder); + ast_channel_unlock(channel->owner); + } + /* Copy device string over */ ast_copy_string(numsubst, channel->device, sizeof(numsubst)); @@ -494,7 +502,7 @@ static int begin_dial(struct ast_dial *dial, struct ast_channel *chan, int async /* Iterate through channel list, requesting and calling each one */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { - success += begin_dial_channel(channel, chan, async, predial_string); + success += begin_dial_channel(channel, chan, async, predial_string, NULL); } AST_LIST_UNLOCK(&dial->channels); @@ -550,7 +558,7 @@ static int handle_call_forward(struct ast_dial *dial, struct ast_dial_channel *c channel->owner = NULL; /* Finally give it a go... send it out into the world */ - begin_dial_channel(channel, chan, chan ? 0 : 1, predial_string); + begin_dial_channel(channel, chan, chan ? 0 : 1, predial_string, original); ast_channel_publish_dial_forward(chan, original, channel->owner, NULL, "CANCEL", ast_channel_call_forward(original)); From 5bfef2a8b4674382f959b21a3b8e14cf1d942bab Mon Sep 17 00:00:00 2001 From: Jaco Kroon Date: Mon, 2 May 2016 12:57:03 +0200 Subject: [PATCH 0478/1578] translate: Enables native Packet-Loss Concealment (PLC) for supporting codecs. ASTERISK-25629 #close Change-Id: Ibfcf0670e094e9718d82fd9920f1fb2dae122006 --- main/translate.c | 135 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 122 insertions(+), 13 deletions(-) diff --git a/main/translate.c b/main/translate.c index 8d37e372416..b7443b81b9a 100644 --- a/main/translate.c +++ b/main/translate.c @@ -358,6 +358,7 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format pvt->f.offset = AST_FRIENDLY_OFFSET; pvt->f.src = pvt->t->name; pvt->f.data.ptr = pvt->outbuf.c; + pvt->f.seqno = 0x10000; /* * If the translator has not provided a format @@ -524,13 +525,46 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a /*! \brief do the actual translation */ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume) { - struct ast_trans_pvt *p = path; - struct ast_frame *out; + const unsigned int rtp_seqno_max_value = 0xffff; + struct ast_frame *out_last, *out = NULL; + struct ast_trans_pvt *step; struct timeval delivery; int has_timing_info; long ts; long len; - int seqno; + int seqno, frames_missing; + + /* Determine the amount of lost packets for PLC */ + /* But not at start with first frame = path->f.seqno is still 0x10000 */ + /* But not when there is no sequence number = frame created internally */ + if ((path->f.seqno <= rtp_seqno_max_value) && (path->f.seqno != f->seqno)) { + if (f->seqno < path->f.seqno) { /* seqno overrun situation */ + frames_missing = rtp_seqno_max_value + f->seqno - path->f.seqno - 1; + } else { + frames_missing = f->seqno - path->f.seqno - 1; + } + /* Out-of-order packet - more precise: late packet */ + if ((rtp_seqno_max_value + 1) / 2 < frames_missing) { + if (consume) { + ast_frfree(f); + } + /* + * Do not pass late packets to any transcoding module, because that + * confuses the state of any library (packets inter-depend). With + * the next packet, this one is going to be treated as lost packet. + */ + return NULL; + } + + if (frames_missing > 96) { + struct ast_str *str = ast_str_alloca(256); + + /* not DEBUG but NOTICE because of WARNING in main/cannel.c:__ast_queue_frame */ + ast_log(LOG_NOTICE, "%d lost frame(s) %d/%d %s\n", frames_missing, f->seqno, path->f.seqno, ast_translate_path_to_str(path, &str)); + } + } else { + frames_missing = 0; + } has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); ts = f->ts; @@ -560,18 +594,93 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, f->samples, ast_format_get_sample_rate(f->subclass.format))); } delivery = f->delivery; - for (out = f; out && p ; p = p->next) { - struct ast_frame *current = out; - - do { - framein(p, current); - current = AST_LIST_NEXT(current, frame_list); - } while (current); - if (out != f) { - ast_frfree(out); + + for (out_last = NULL; frames_missing + 1; frames_missing--) { + struct ast_frame *frame_to_translate, *inner_head; + struct ast_frame missed = { + .frametype = AST_FRAME_VOICE, + .subclass.format = f->subclass.format, + .datalen = 0, + /* In RTP, the amount of samples might change anytime */ + /* If that happened while frames got lost, what to do? */ + .samples = f->samples, /* FIXME */ + .src = __FUNCTION__, + .data.uint32 = 0, + .delivery.tv_sec = 0, + .delivery.tv_usec = 0, + .flags = 0, + /* RTP sequence number is between 0x0001 and 0xffff */ + .seqno = (rtp_seqno_max_value + 1 + f->seqno - frames_missing) & rtp_seqno_max_value, + }; + + if (frames_missing) { + frame_to_translate = &missed; + } else { + frame_to_translate = f; + } + + /* The translation path from one format to another might contain several steps */ + /* out* collects the result for missed frame(s) and input frame(s) */ + /* out is the result of the conversion of all frames, translated into the destination format */ + /* out_last is the last frame in that list, to add frames faster */ + for (step = path, inner_head = frame_to_translate; inner_head && step; step = step->next) { + struct ast_frame *current, *inner_last, *inner_prev = frame_to_translate; + + /* inner* collects the result of each conversion step, the input for the next step */ + /* inner_head is a list of frames created by each conversion step */ + /* inner_last is the last frame in that list, to add frames faster */ + for (inner_last = NULL, current = inner_head; current; current = AST_LIST_NEXT(current, frame_list)) { + struct ast_frame *tmp; + + framein(step, current); + tmp = step->t->frameout(step); + + if (!tmp) { + continue; + } else if (inner_last) { + struct ast_frame *t; + + /* Determine the last frame of the list before appending to it */ + while ((t = AST_LIST_NEXT(inner_last, frame_list))) { + inner_last = t; + } + AST_LIST_NEXT(inner_last, frame_list) = tmp; + } else { + inner_prev = inner_head; + inner_head = tmp; + inner_last = tmp; + } + } + + /* The current step did not create any frames = no frames for the next step */ + /* The steps are not lost because framein buffered those for the next input frame */ + if (!inner_last) { + inner_prev = inner_head; + inner_head = NULL; + } + if (inner_prev != frame_to_translate) { + ast_frfree(inner_prev); /* Frees just the intermediate lists */ + } + } + + /* This frame created no frames after translation = continue with next frame */ + /* The frame is not lost because framein buffered it to be combined with the next frame */ + if (!inner_head) { + continue; + } else if (out_last) { + struct ast_frame *t; + + /* Determine the last frame of the list before appending to it */ + while ((t = AST_LIST_NEXT(out_last, frame_list))) { + out_last = t; + } + AST_LIST_NEXT(out_last, frame_list) = inner_head; + } else { + out = inner_head; + out_last = inner_head; } - out = p->t->frameout(p); } + if (out) { /* we have a frame, play with times */ if (!ast_tvzero(delivery)) { From dca052e53171d266501d1325c7a92e5570f22090 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 1 Jun 2016 16:57:36 -0500 Subject: [PATCH 0479/1578] chan_rtp.c: Simplify options to UnicastRTP channel creation. Change the awkward and not as flexible UnicastRTP options format From: Dial(UnicastRTP/127.0.0.1[/[][/[]]]) To: Dial(UnicastRTP/127.0.0.1[/[]]) Where can be standard Asterisk flag options: c() - Specify which codec/format to use such as 'ulaw'. e() - Specify which RTP engine to use such as 'asterisk'. More option flags can be easily added later such as the codec's RTP payload type to use when the codec does not have a static payload type defined. Change-Id: I0c297aaf09e2ee515536cb7437bb8042ff8ff3c9 --- CHANGES | 26 ++++++++++++++++++++++ channels/chan_rtp.c | 53 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 608a4a4b33b..e799f71ef8b 100644 --- a/CHANGES +++ b/CHANGES @@ -135,6 +135,32 @@ chan_iax2 seconds. Setting this to a higher value may help in lagged networks or those experiencing high packet loss. +chan_rtp (was chan_multicast_rtp) +------------------ + * Added unicast RTP support and renamed chan_multicast_rtp to chan_rtp. + + * The format for dialing a unicast RTP channel is: + UnicastRTP/[/[]] + Where is something like '127.0.0.1:5060'. + Where are in standard Asterisk flag options format: + c() - Specify which codec/format to use such as 'ulaw'. + e() - Specify which RTP engine to use such as 'asterisk'. + + * New options were added for a multicast RTP channel. The format for + dialing a multicast RTP channel is: + MulticastRTP//[/[][/[]]] + Where can be either 'basic' or 'linksys'. + Where is something like '224.0.0.3:5060'. + Where is something like '127.0.0.1:5060'. + Where are in standard Asterisk flag options format: + c() - Specify which codec/format to use such as 'ulaw'. + i(
) - Specify the interface address from which multicast RTP + is sent. + l() - Set whether packets are looped back to the sender. The + enable value can be 0 to set looping to off and non-zero to set + looping on. + t() - Set the time-to-live (TTL) value for multicast packets. + chan_sip ------------------ * New 'rtpbindaddr' global setting. This allows a user to define which diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index 093602823d4..0fe66bd2092 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -176,7 +176,7 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo fmt = ast_format_cap_get_format(cap, 0); } if (!fmt) { - ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n", + ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n", args.destination); goto failure; } @@ -230,6 +230,25 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo return NULL; } +enum { + OPT_RTP_CODEC = (1 << 0), + OPT_RTP_ENGINE = (1 << 1), +}; + +enum { + OPT_ARG_RTP_CODEC, + OPT_ARG_RTP_ENGINE, + /* note: this entry _MUST_ be the last one in the enum */ + OPT_ARG_ARRAY_SIZE +}; + +AST_APP_OPTIONS(unicast_rtp_options, BEGIN_OPTIONS + /*! Set the codec to be used for unicast RTP */ + AST_APP_OPTION_ARG('c', OPT_RTP_CODEC, OPT_ARG_RTP_CODEC), + /*! Set the RTP engine to use for unicast RTP */ + AST_APP_OPTION_ARG('e', OPT_RTP_ENGINE, OPT_ARG_RTP_ENGINE), +END_OPTIONS ); + /*! \brief Function called when we should prepare to call the unicast destination */ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { @@ -240,11 +259,13 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form struct ast_channel *chan; struct ast_format_cap *caps = NULL; struct ast_format *fmt = NULL; + const char *engine_name; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(destination); - AST_APP_ARG(engine); - AST_APP_ARG(format); + AST_APP_ARG(options); ); + struct ast_flags opts = { 0, }; + char *opt_args[OPT_ARG_ARRAY_SIZE]; if (ast_strlen_zero(data)) { ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n"); @@ -262,17 +283,26 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form goto failure; } - if (!ast_strlen_zero(args.format)) { - fmt = ast_format_cache_get(args.format); + if (!ast_strlen_zero(args.options) + && ast_app_parse_options(unicast_rtp_options, &opts, opt_args, + ast_strdupa(args.options))) { + ast_log(LOG_ERROR, "'UnicastRTP' channel options '%s' parse error\n", + args.options); + goto failure; + } + + if (ast_test_flag(&opts, OPT_RTP_CODEC) + && !ast_strlen_zero(opt_args[OPT_ARG_RTP_CODEC])) { + fmt = ast_format_cache_get(opt_args[OPT_ARG_RTP_CODEC]); if (!fmt) { - ast_log(LOG_ERROR, "Format '%s' not found for sending RTP to '%s'\n", - args.format, args.destination); + ast_log(LOG_ERROR, "Codec '%s' not found for sending RTP to '%s'\n", + opt_args[OPT_ARG_RTP_CODEC], args.destination); goto failure; } } else { fmt = ast_format_cap_get_format(cap, 0); if (!fmt) { - ast_log(LOG_ERROR, "No format available for sending RTP to '%s'\n", + ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n", args.destination); goto failure; } @@ -283,12 +313,15 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form goto failure; } + engine_name = S_COR(ast_test_flag(&opts, OPT_RTP_ENGINE), + opt_args[OPT_ARG_RTP_ENGINE], NULL); + ast_ouraddrfor(&address, &local_address); - instance = ast_rtp_instance_new(args.engine, NULL, &local_address, NULL); + instance = ast_rtp_instance_new(engine_name, NULL, &local_address, NULL); if (!instance) { ast_log(LOG_ERROR, "Could not create %s RTP instance for sending media to '%s'\n", - S_OR(args.engine, "default"), args.destination); + S_OR(engine_name, "default"), args.destination); goto failure; } From da943ec5c072d2fcbcd91496c66a83a3b72f0b28 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 7 Jun 2016 09:16:02 +0200 Subject: [PATCH 0480/1578] BuildSystem: Avoid 'ar cru' and use 'ar cr' instead. In several internal library projects, the files are archived with the help of 'ar cr'. Only the projects editline and the Objective Open H.323 stack implementation in C (ooh323c) use 'ar cru' instead. Recently, some platforms changed the default parameters of AR which creates "/usr/bin/ar: `u' modifier ignored since `D' is the default (see `U')". For consistency and to avoid this message all projects use 'ar cr' now. ASTERISK-26091 #close Change-Id: I710a9b1c01c1b5a1931a646098c044c8161ead40 --- addons/ooh323c/src/Makefile.in | 2 +- main/editline/Makefile.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/ooh323c/src/Makefile.in b/addons/ooh323c/src/Makefile.in index d3a96024bdb..15b14f7dfde 100644 --- a/addons/ooh323c/src/Makefile.in +++ b/addons/ooh323c/src/Makefile.in @@ -104,7 +104,7 @@ CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LIBRARIES = $(noinst_LIBRARIES) -libooh323c_a_AR = $(AR) cru +libooh323c_a_AR = $(AR) cr libooh323c_a_LIBADD = am_libooh323c_a_OBJECTS = ooLogChan.$(OBJEXT) ooUtils.$(OBJEXT) \ ooGkClient.$(OBJEXT) context.$(OBJEXT) ooDateTime.$(OBJEXT) \ diff --git a/main/editline/Makefile.in b/main/editline/Makefile.in index 112b68b6498..2be4333d504 100644 --- a/main/editline/Makefile.in +++ b/main/editline/Makefile.in @@ -187,7 +187,7 @@ distclean : clean # $(LIB_A) : $(BGCSRCS:.c=.o_a) $(CCSRCS:.c=.o_a) - $(AR) cru $@ $? + $(AR) cr $@ $? $(RANLIB) $@ $(LIB_S) : $(BGCSRCS:.c=.o_s) $(CCSRCS:.c=.o_s) From 52120204c9a538e00679461ec5404d04a07e57f4 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 7 Jun 2016 12:45:34 +0200 Subject: [PATCH 0481/1578] res_srtp: Instead of libSRTP use OpenSSL as random source. Since libSRTP 1.5, its Random Number Generator (RNG) is not maintained anymore. Therefore, the symbol RAND_bytes is used instead of crypto_get_random. ASTERISK-24436 #close Change-Id: Iea0bae4d4e3c9aa0926ea442b6484b5159789d96 --- res/res_srtp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/res/res_srtp.c b/res/res_srtp.c index 1e68f9675ce..0b1fb73e700 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -40,7 +40,11 @@ ASTERISK_REGISTER_FILE() #include +#ifdef HAVE_OPENSSL +#include +#else #include +#endif #include "asterisk/lock.h" #include "asterisk/sched.h" @@ -305,7 +309,11 @@ static int ast_srtp_policy_set_master_key(struct ast_srtp_policy *policy, const static int ast_srtp_get_random(unsigned char *key, size_t len) { +#ifdef HAVE_OPENSSL + return RAND_bytes(key, len) > 0 ? 0: -1; +#else return crypto_get_random(key, len) != err_status_ok ? -1: 0; +#endif } static void ast_srtp_set_cb(struct ast_srtp *srtp, const struct ast_srtp_cb *cb, void *data) From 60caebc738d96c092ca1f1f51881ed41e4a52192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rn=20Arnarson?= Date: Mon, 6 Jun 2016 16:13:01 +0000 Subject: [PATCH 0482/1578] apps/app_voicemail.c and main/say.c: Add support for Icelandic language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Icelandic has some weird grammar rules when dealing with dates and numbers. There are different genders used depending on which number you're dealing with, and only a handful of numbers do change depending on the gender. There is also an implied gender in several cases. This patch was originally written for asterisk 1.6, and has been in use for several years without crashes. I cleaned it up a bit and rewrote what was necessary for Asterisk 13. The functions were copied from other similar languages and modified where appropriate. If i recall correctly, the German and Danish functions were used as a base. ASTERISK-26087 Reported by: Örn Arnarson Tested by: Örn Arnarson Change-Id: Ib7d8bd7b0fede5767921ed821315b5b508c0e665 --- CHANGES | 3 + apps/app_voicemail.c | 79 ++++++ main/say.c | 573 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 655 insertions(+) diff --git a/CHANGES b/CHANGES index 608a4a4b33b..d6f049b47d2 100644 --- a/CHANGES +++ b/CHANGES @@ -1010,6 +1010,8 @@ Say language. The 'language' parameter in say.conf now recognizes a setting of 'ja', which will enable Japanese language specific mechanisms for playing back numbers, dates, and other items. + * Counting, enumeration and dates now supports Icelandic grammar with the + 'language' parameter set to 'is'. SayCountPL ------------------ @@ -5163,6 +5165,7 @@ Voicemail Changes the message as urgent after he has recorded a voicemail by following the voice instructions. When listening to voicemails using VoiceMailMain urgent messages will be presented before other messages + * Added "is" language support Queue changes ------------- diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 1d5b2dcb39c..586086c55a9 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -8527,6 +8527,8 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL); } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */ res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL); + } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL); } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */ res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL); } else if (!strcasecmp(ast_channel_language(chan),"ja")) { /* Japanese syntax */ @@ -8753,6 +8755,12 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc res = wait_file2(chan, vms, "vm-number"); res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f"); } + /* ICELANDIC syntax */ + } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { + res = wait_file2(chan, vms, "vm-message"); + if (vms->curmsg && (vms->curmsg != vms->lastmsg)) { + res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "n"); + } /* VIETNAMESE syntax */ } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) { if (!vms->curmsg) { @@ -9492,6 +9500,75 @@ static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms) return res; } +/* ICELANDIC syntax */ +static int vm_intro_is(struct ast_channel *chan, struct vm_state *vms) +{ + int res; + + /* Introduce messages they have */ + res = ast_play_and_wait(chan, "vm-youhave"); + if (!res) { + if (vms->urgentmessages) { + /* Digits 1-4 are spoken in neutral and plural when talking about messages, + however, feminine is used for 1 as it is the same as the neutral for plural, + and singular neutral is the same after 1. */ + if (vms->urgentmessages < 5) { + char recname[16]; + if (vms->urgentmessages == 1) + snprintf(recname, sizeof(recname), "digits/1kvk"); + else + snprintf(recname, sizeof(recname), "digits/%dhk", vms->urgentmessages); + res = ast_play_and_wait(chan, recname); + } else if (!res) + res = ast_play_and_wait(chan, "vm-Urgent"); + if ((vms->oldmessages || vms->newmessages) && !res) { + res = ast_play_and_wait(chan, "vm-and"); + } else if (!res) + res = ast_play_and_wait(chan, "vm-messages"); + } + if (vms->newmessages) { + if (vms->newmessages < 5) { + char recname[16]; + if (vms->newmessages == 1) + snprintf(recname, sizeof(recname), "digits/1kvk"); + else + snprintf(recname, sizeof(recname), "digits/%dhk", vms->newmessages); + res = ast_play_and_wait(chan, recname); + } else + res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan)); + if (!res) + res = ast_play_and_wait(chan, "vm-INBOX"); + if (vms->oldmessages && !res) + res = ast_play_and_wait(chan, "vm-and"); + else if (!res) + res = ast_play_and_wait(chan, "vm-messages"); + } + if (!res && vms->oldmessages) { + if (vms->oldmessages < 5) { + char recname[16]; + if (vms->oldmessages == 1) + snprintf(recname, sizeof(recname), "digits/1kvk"); + else + snprintf(recname, sizeof(recname), "digits/%dhk", vms->oldmessages); + res = ast_play_and_wait(chan, recname); + } else + res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)); + if (!res) + res = ast_play_and_wait(chan, "vm-Old"); + if (!res) + res = ast_play_and_wait(chan, "vm-messages"); + } + if (!res) { + if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) { + res = ast_play_and_wait(chan, "vm-no"); + if (!res) + res = ast_play_and_wait(chan, "vm-messages"); + } + } + } + return res; +} + /* ITALIAN syntax */ static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms) { @@ -10156,6 +10233,8 @@ static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm return vm_intro_gr(chan, vms); } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW syntax */ return vm_intro_he(chan, vms); + } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */ + return vm_intro_is(chan, vms); } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */ return vm_intro_it(chan, vms); } else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE syntax */ diff --git a/main/say.c b/main/say.c index 95792932638..6e51de20143 100644 --- a/main/say.c +++ b/main/say.c @@ -317,6 +317,7 @@ static int say_digit_str_full(struct ast_channel *chan, const char *str, const c \arg \b es - Spanish, Mexican \arg \b fr - French \arg \b he - Hebrew + \arg \b is - Icelandic \arg \b it - Italian \arg \b nl - Dutch \arg \b no - Norwegian @@ -373,6 +374,7 @@ static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const ch static int ast_say_number_full_es(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_number_full_fr(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_number_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); +static int ast_say_number_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); static int ast_say_number_full_no(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); @@ -394,6 +396,7 @@ static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_enumeration_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_enumeration_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); +static int ast_say_enumeration_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_enumeration_full_vi(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */ @@ -409,6 +412,7 @@ static int ast_say_date_ka(struct ast_channel *chan, time_t t, const char *ints, static int ast_say_date_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang); static int ast_say_date_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang); static int ast_say_date_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang); +static int ast_say_date_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang); static int ast_say_date_with_format_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); @@ -416,6 +420,7 @@ static int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const static int ast_say_date_with_format_es(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); +static int ast_say_date_with_format_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_it(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_pl(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); @@ -511,6 +516,8 @@ static int say_number_full(struct ast_channel *chan, int num, const char *ints, return ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd); } else if (!strncasecmp(language, "hu", 2)) { /* Hungarian syntax */ return ast_say_number_full_hu(chan, num, ints, language, audiofd, ctrlfd); + } else if (!strncasecmp(language, "is", 2)) { /* Icelandic syntax */ + return ast_say_number_full_is(chan, num, ints, language, options, audiofd, ctrlfd); } else if (!strncasecmp(language, "it", 2)) { /* Italian syntax */ return ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd); } else if (!strncasecmp(language, "ka", 2)) { /* Georgian syntax */ @@ -1518,6 +1525,129 @@ static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char return res; } +/*! \brief ast_say_number_full_is: Icelandic syntax */ +/* New files: + In addition to American English, the following sounds are required: "hundreds", "millions", "1kvk", "1hk", "2kvk", "2hk", "3kvk", "3hk", "4kvk", "4hk" + */ +static int ast_say_number_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd) +{ + int res = 0; + int playh = 0; + int playa = 0; + int cn = 1; /* 1 = masc; 2 = fem; 3 = neut */ + char fn[256] = ""; + + if (!num) + return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd); + + if (options && !strncasecmp(options, "f", 1)) cn = 2; + if (options && !strncasecmp(options, "c", 1)) cn = 3; + /* It seems that sometimes people are using c and sometimes n. */ + if (options && !strncasecmp(options, "n", 1)) cn = 3; + + while (!res && (num || playh || playa )) { + if (num < 0) { + ast_copy_string(fn, "digits/minus", sizeof(fn)); + if ( num > INT_MIN ) { + num = -num; + } else { + num = 0; + } + } else if (playh) { + if (playh > 1) + ast_copy_string(fn, "digits/hundreds", sizeof(fn)); + else + ast_copy_string(fn, "digits/hundred", sizeof(fn)); + playh = 0; + } else if (playa) { + ast_copy_string(fn, "digits/and", sizeof(fn)); + playa = 0; + } else if (num < 5 && cn == 2) { + snprintf(fn, sizeof(fn), "digits/%dkvk", num); + num = 0; + } else if (num < 5 && cn == 3) { + snprintf(fn, sizeof(fn), "digits/%dhk", num); + num = 0; + } else if (num < 20) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else if (num < 100) { + snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); + num %= 10; + if (num) + playa++; + } else if (num < 1000) { + int hundreds = num / 100; + /* The number prepending hundreds are in neutral */ + if (hundreds < 5) + snprintf(fn, sizeof(fn), "digits/%dhk", hundreds); + else + snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); + + playh = hundreds; + num -= 100 * hundreds; + if (num && num < 20) + playa++; + /* The 'and' moves forward on even tens. */ + if (num && (num % 10) == 0) + playa++; + } else if (num < 1000000) { + res = ast_say_number_full_is(chan, num / 1000, ints, language, "n", audiofd, ctrlfd); + /* Play 'and' if it's an even hundred. */ + if ((num % 100) == 0 && (num % 1000 != 0)) { + playa++; + } + if (res) + return res; + ast_copy_string(fn, "digits/thousand", sizeof(fn)); + num %= 1000; + if (num && (num < 20 || (num % 10 == 0))) + playa++; + } else if (num < 1000000000) { + int millions = num / 1000000; + /* The number of millions is feminine */ + res = ast_say_number_full_is(chan, millions, ints, language, "f", audiofd, ctrlfd); + if (res) + return res; + if (millions > 1) + ast_copy_string(fn, "digits/millions", sizeof(fn)); + else + ast_copy_string(fn, "digits/million", sizeof(fn)); + num %= 1000000; + if (num && num < 100) + playa++; + } else if (num < INT_MAX) { + int milliards = num / 1000000000; + /* The number of milliards is masculine */ + res = ast_say_number_full_is(chan, milliards, ints, language, "m", audiofd, ctrlfd); + if (res) + return res; + if (milliards > 1) + ast_copy_string(fn, "digits/milliards", sizeof(fn)); + else + ast_copy_string(fn, "digits/milliard", sizeof(fn)); + num %= 1000000000; + if (num && num < 100) + playa++; + } else { + ast_debug(1, "Number '%d' is too big for me\n", num); + res = -1; + } + + if (!res) { + if (!ast_streamfile(chan, fn, language)) { + if ((audiofd > -1) && (ctrlfd > -1)) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + } + } + return res; +} + + /*! \brief ast_say_number_full_it: Italian */ static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) { @@ -2789,6 +2919,8 @@ static int say_enumeration_full(struct ast_channel *chan, int num, const char *i return ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd); } else if (!strncasecmp(language, "he", 2)) { /* Hebrew syntax */ return ast_say_enumeration_full_he(chan, num, ints, language, options, audiofd, ctrlfd); + } else if (!strncasecmp(language, "is", 2)) { /* Icelandic syntax */ + return ast_say_enumeration_full_is(chan, num, ints, language, options, audiofd, ctrlfd); } else if (!strncasecmp(language, "vi", 2)) { /* Vietnamese syntax */ return ast_say_enumeration_full_vi(chan, num, ints, language, audiofd, ctrlfd); } @@ -3329,6 +3461,182 @@ static int ast_say_enumeration_full_he(struct ast_channel *chan, int num, const return res; } +/*! \brief ast_say_enumeration_full_is: Icelandic syntax */ +static int ast_say_enumeration_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd) +{ + /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */ + int res = 0, t = 0; + char fn[256] = "", fna[256] = ""; + char *gender; + + if (options && !strncasecmp(options, "f", 1)) { + gender = "F"; + } else if (options && !strncasecmp(options, "n", 1)) { + gender = "N"; + } else { + gender = ""; + } + + if (!num) + return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd); + + while (!res && num) { + if (num < 0) { + ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */ + if ( num > INT_MIN ) { + num = -num; + } else { + num = 0; + } + } else if (num < 100 && t) { + ast_copy_string(fn, "digits/and", sizeof(fn)); + t = 0; + } else if (num < 20) { + snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender); + num = 0; + } else if (num < 100) { + int ones = num % 10; + if (ones) { + int tens = num - ones; + snprintf(fn, sizeof(fn), "digits/h-%d%s", tens, gender); + num = ones; + t++; + } + else if (t) { + snprintf(fn, sizeof(fn), "digits/and"); + t = 0; + } + else { + snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender); + num = 0; + } + + } else if (num == 100 && t == 0) { + snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender); + num = 0; + } else if (num < 1000) { + int hundreds = num / 100; + num = num % 100; + if (hundreds == 1) { + ast_copy_string(fn, "digits/1hk", sizeof(fn)); + } else { + snprintf(fn, sizeof(fn), "digits/%d", hundreds); + } + if (num) { + ast_copy_string(fna, "digits/hundred", sizeof(fna)); + } else { + snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender); + } + t = 1; + } else if (num < 1000000) { + int thousands = num / 1000; + num = num % 1000; + if (thousands == 1) { + if (num) { + /* Thousand is a neutral word, so use the neutral recording */ + ast_copy_string(fn, "digits/1hk", sizeof(fn)); + ast_copy_string(fna, "digits/thousand", sizeof(fna)); + } else { + if (t) { + ast_copy_string(fn, "digits/1hk", sizeof(fn)); + snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender); + } else { + snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender); + } + } + } else { + res = ast_say_number_full_is(chan, thousands, ints, language, options, audiofd, ctrlfd); + if (res) { + return res; + } + if (num) { + ast_copy_string(fn, "digits/thousand", sizeof(fn)); + } else { + snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender); + } + } + if (num) + t = 1; + } else if (num < 1000000000) { + int millions = num / 1000000; + num = num % 1000000; + if (millions == 1) { + if (num) { + /* Million is a feminine word, so use the female form */ + ast_copy_string(fn, "digits/1kvk", sizeof(fn)); + ast_copy_string(fna, "digits/million", sizeof(fna)); + } else { + ast_copy_string(fn, "digits/1hk", sizeof(fn)); + snprintf(fna, sizeof(fna), "digits/h-million%s", gender); + } + } else { + res = ast_say_number_full_is(chan, millions, ints, language, options, audiofd, ctrlfd); + if (res) { + return res; + } + if (num) { + ast_copy_string(fn, "digits/millions", sizeof(fn)); + } else { + snprintf(fn, sizeof(fn), "digits/h-million%s", gender); + } + } + if (num) + t = 1; + } else if (num < INT_MAX) { + int billions = num / 1000000000; + num = num % 1000000000; + if (billions == 1) { + if (num) { + ast_copy_string(fn, "digits/1", sizeof(fn)); + ast_copy_string(fna, "digits/milliard", sizeof(fna)); + } else { + ast_copy_string(fn, "digits/1hk", sizeof(fn)); + snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender); + } + } else { + res = ast_say_number_full_is(chan, billions, ints, language, options, audiofd, ctrlfd); + if (res) + return res; + if (num) { + ast_copy_string(fn, "digits/milliards", sizeof(fna)); + } else { + snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender); + } + } + if (num) + t = 1; + } else if (num == INT_MAX) { + snprintf(fn, sizeof(fn), "digits/h-last%s", gender); + num = 0; + } else { + ast_debug(1, "Number '%d' is too big for me\n", num); + res = -1; + } + + if (!res) { + if (!ast_streamfile(chan, fn, language)) { + if ((audiofd > -1) && (ctrlfd > -1)) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + if (!res) { + if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) { + if ((audiofd > -1) && (ctrlfd > -1)) { + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + } else { + res = ast_waitstream(chan, ints); + } + } + ast_stopstream(chan); + strcpy(fna, ""); + } + } + } + return res; +} + static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang) { if (!strncasecmp(lang, "en", 2)) { /* English syntax */ @@ -3353,6 +3661,8 @@ static int say_date(struct ast_channel *chan, time_t t, const char *ints, const return ast_say_date_he(chan, t, ints, lang); } else if (!strncasecmp(lang, "hu", 2)) { /* Hungarian syntax */ return ast_say_date_hu(chan, t, ints, lang); + } else if (!strncasecmp(lang, "is", 2)) { /* Icelandic syntax */ + return ast_say_date_is(chan, t, ints, lang); } else if (!strncasecmp(lang, "ka", 2)) { /* Georgian syntax */ return ast_say_date_ka(chan, t, ints, lang); } else if (!strncasecmp(lang, "nl", 2)) { /* Dutch syntax */ @@ -3682,6 +3992,55 @@ int ast_say_date_he(struct ast_channel *chan, time_t t, const char *ints, const return res; } +/* Icelandic syntax */ +int ast_say_date_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang) +{ + struct timeval when = { t, 0 }; + struct ast_tm tm; + char fn[256]; + int res = 0; + ast_localtime(&when, &tm, NULL); + if (!res) { + snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); + res = ast_streamfile(chan, fn, lang); + if (!res) + res = ast_waitstream(chan, ints); + } + if (!res) + res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL); + if (!res) + res = ast_waitstream(chan, ints); + if (!res) { + snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); + res = ast_streamfile(chan, fn, lang); + if (!res) + res = ast_waitstream(chan, ints); + } + if (!res) { + /* Year */ + int year = tm.tm_year + 1900; + if (year > 1999) { /* year 2000 and later */ + res = ast_say_number(chan, year, ints, lang, (char *) NULL); + } else { + if (year < 1100) { + /* I'm not going to handle 1100 and prior */ + /* We'll just be silent on the year, instead of bombing out. */ + } else { + /* year 1100 to 1999. will anybody need this?!? */ + snprintf(fn, sizeof(fn), "digits/%d", (year / 100)); + res = wait_file(chan, ints, fn, lang); + if (!res) { + res = wait_file(chan, ints, "digits/hundred", lang); + if (!res && year % 100 != 0) { + res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL); + } + } + } + } + } + return res; +} + static int say_date_with_format(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone) { if (!strncasecmp(lang, "en", 2)) { /* English syntax */ @@ -3698,6 +4057,8 @@ static int say_date_with_format(struct ast_channel *chan, time_t t, const char * return ast_say_date_with_format_fr(chan, t, ints, lang, format, tzone); } else if (!strncasecmp(lang, "gr", 2)) { /* Greek syntax */ return ast_say_date_with_format_gr(chan, t, ints, lang, format, tzone); + } else if (!strncasecmp(lang, "is", 2)) { /* Icelandic syntax */ + return ast_say_date_with_format_is(chan, t, ints, lang, format, tzone); } else if (!strncasecmp(lang, "ja", 2)) { /* Japanese syntax */ return ast_say_date_with_format_ja(chan, t, ints, lang, format, tzone); } else if (!strncasecmp(lang, "it", 2)) { /* Italian syntax */ @@ -4384,6 +4745,218 @@ int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const char * return res; } +/* Icelandic syntax */ +int ast_say_date_with_format_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone) +{ + struct timeval when = { t, 0 }; + struct ast_tm tm; + int res=0, offset, sndoffset; + char sndfile[256], nextmsg[256]; + + if (!format) + format = "A dBY HMS"; + + ast_localtime(&when, &tm, tzone); + + for (offset=0 ; format[offset] != '\0' ; offset++) { + ast_debug(1, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); + switch (format[offset]) { + /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ + case '\'': + /* Literal name of a sound file */ + for (sndoffset = 0; !strchr("\'\0", format[++offset]) && (sndoffset < sizeof(sndfile) - 1) ; sndoffset++) { + sndfile[sndoffset] = format[offset]; + } + sndfile[sndoffset] = '\0'; + res = wait_file(chan, ints, sndfile, lang); + break; + case 'A': + case 'a': + /* Sunday - Saturday */ + snprintf(nextmsg, sizeof(nextmsg), "digits/day-%d", tm.tm_wday); + res = wait_file(chan, ints, nextmsg, lang); + break; + case 'B': + case 'b': + case 'h': + /* January - December */ + snprintf(nextmsg, sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); + res = wait_file(chan, ints, nextmsg, lang); + break; + case 'm': + /* Month enumerated */ + res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, "m"); + break; + case 'd': + case 'e': + /* First - Thirtyfirst */ + res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, "m"); + break; + case 'Y': + /* Year */ + { + int year = tm.tm_year + 1900; + if (year > 1999) { /* year 2000 and later */ + res = ast_say_number(chan, year, ints, lang, (char *) NULL); + } else { + if (year < 1100) { + /* I'm not going to handle 1100 and prior */ + /* We'll just be silent on the year, instead of bombing out. */ + } else { + /* year 1100 to 1999. will anybody need this?!? */ + /* say 1967 as 'nineteen hundred seven and sixty' */ + snprintf(nextmsg, sizeof(nextmsg), "digits/%d", (year / 100) ); + res = wait_file(chan, ints, nextmsg, lang); + if (!res) { + res = wait_file(chan, ints, "digits/hundred", lang); + if (!res && year % 100 != 0) { + res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL); + } + } + } + } + } + break; + case 'I': + case 'l': + /* 12-Hour */ + res = wait_file(chan, ints, "digits/oclock", lang); + if (tm.tm_hour == 0) + ast_copy_string(nextmsg, "digits/12", sizeof(nextmsg)); + else if (tm.tm_hour > 12) + snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); + else + snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour); + if (!res) { + res = wait_file(chan, ints, nextmsg, lang); + } + break; + case 'H': + /* 24-Hour, single digit hours preceeded by "oh" (0) */ + if (tm.tm_hour < 10 && tm.tm_hour > 0) { + res = wait_file(chan, ints, "digits/0", lang); + } + /* FALLTRHU */ + case 'k': + /* 24-Hour */ + res = ast_say_number(chan, tm.tm_hour, ints, lang, "n"); + break; + case 'M': + /* Minute */ + if (tm.tm_min > 0 || next_item(&format[offset + 1]) == 'S') { /* zero 'digits/0' only if seconds follow */ + if (tm.tm_min < 10) + res = wait_file(chan, ints, "digits/0", lang); + /* Gender depends on whether or not seconds follow */ + if (next_item(&format[offset + 1]) == 'S') + res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); + else + res = ast_say_number(chan, tm.tm_min, ints, lang, "n"); + } + if (!res && next_item(&format[offset + 1]) == 'S') { /* minutes only if seconds follow */ + /* Say minute/minutes depending on whether minutes end in 1 */ + if ((tm.tm_min % 10 == 1) && (tm.tm_min != 11)) { + res = wait_file(chan, ints, "digits/minute", lang); + } else { + res = wait_file(chan, ints, "digits/minutes", lang); + } + } + break; + case 'P': + case 'p': + /* AM/PM */ + if (tm.tm_hour > 11) + ast_copy_string(nextmsg, "digits/p-m", sizeof(nextmsg)); + else + ast_copy_string(nextmsg, "digits/a-m", sizeof(nextmsg)); + res = wait_file(chan, ints, nextmsg, lang); + break; + case 'Q': + /* Shorthand for "Today", "Yesterday", or AdBY */ + /* XXX As emphasized elsewhere, this should the native way in your + * language to say the date, with changes in what you say, depending + * upon how recent the date is. XXX */ + { + struct timeval now = ast_tvnow(); + struct ast_tm tmnow; + time_t beg_today; + + ast_localtime(&now, &tmnow, tzone); + /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ + /* In any case, it saves not having to do ast_mktime() */ + beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); + if (beg_today < t) { + /* Today */ + res = wait_file(chan, ints, "digits/today", lang); + } else if (beg_today - 86400 < t) { + /* Yesterday */ + res = wait_file(chan, ints, "digits/yesterday", lang); + } else { + res = ast_say_date_with_format_is(chan, t, ints, lang, "AdBY", tzone); + } + } + break; + case 'q': + /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */ + /* XXX As emphasized elsewhere, this should the native way in your + * language to say the date, with changes in what you say, depending + * upon how recent the date is. XXX */ + { + struct timeval now = ast_tvnow(); + struct ast_tm tmnow; + time_t beg_today; + + ast_localtime(&now, &tmnow, tzone); + /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ + /* In any case, it saves not having to do ast_mktime() */ + beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); + if (beg_today < t) { + /* Today */ + } else if ((beg_today - 86400) < t) { + /* Yesterday */ + res = wait_file(chan, ints, "digits/yesterday", lang); + } else if (beg_today - 86400 * 6 < t) { + /* Within the last week */ + res = ast_say_date_with_format_is(chan, t, ints, lang, "A", tzone); + } else { + res = ast_say_date_with_format_is(chan, t, ints, lang, "AdBY", tzone); + } + } + break; + case 'R': + res = ast_say_date_with_format_is(chan, t, ints, lang, "HM", tzone); + break; + case 'S': + /* Seconds */ + res = wait_file(chan, ints, "digits/and", lang); + if (!res) { + res = ast_say_number(chan, tm.tm_sec, ints, lang, "f"); + /* Say minute/minutes depending on whether seconds end in 1 */ + if (!res && (tm.tm_sec % 10 == 1) && (tm.tm_sec != 11)) { + res = wait_file(chan, ints, "digits/second", lang); + } else { + res = wait_file(chan, ints, "digits/seconds", lang); + } + } + break; + case 'T': + res = ast_say_date_with_format_is(chan, t, ints, lang, "HMS", tzone); + break; + case ' ': + case ' ': + /* Just ignore spaces and tabs */ + break; + default: + /* Unknown character */ + ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); + } + /* Jump out on DTMF */ + if (res) { + break; + } + } + return res; +} + /*! \brief Thai syntax */ int ast_say_date_with_format_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone) { From 80ff7912a18619f9549d2090be2cf4c9dbeea356 Mon Sep 17 00:00:00 2001 From: Vasil Kolev Date: Tue, 31 May 2016 17:10:29 +0300 Subject: [PATCH 0483/1578] chan_sip: bigger buffers for headers, better failure mode Currently chan_sip can give weird messages if the contacts don't fit in the From: or To: headers. This fix changes the from,to and invite variables to use ast_str, allocates and deallocates them and resizes them if needed. ASTERISK-26069 #close Change-Id: I1b68fcbddca6f6cc7d7a92fe1cb0d5430282b2b3 --- channels/chan_sip.c | 77 +++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 19f8aa308a8..1fc9ce92145 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -14155,9 +14155,10 @@ static void build_contact(struct sip_pvt *p, struct sip_request *req, int incomi /*! \brief Initiate new SIP request to peer/user */ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, const char * const explicit_uri) { - struct ast_str *invite = ast_str_alloca(256); - char from[256]; - char to[256]; +#define SIPHEADER 256 + struct ast_str *invite = ast_str_create(SIPHEADER); + struct ast_str *from = ast_str_create(SIPHEADER); + struct ast_str *to = ast_str_create(SIPHEADER); char tmp_n[SIPBUFSIZE/2]; /* build a local copy of 'n' if needed */ char tmp_l[SIPBUFSIZE/2]; /* build a local copy of 'l' if needed */ const char *l = NULL; /* XXX what is this, exactly ? */ @@ -14259,34 +14260,40 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho ourport = (p->fromdomainport && (p->fromdomainport != STANDARD_SIP_PORT)) ? p->fromdomainport : ast_sockaddr_port(&p->ourip); if (!sip_standard_port(p->socket.type, ourport)) { - ret = snprintf(from, sizeof(from), ";tag=%s", tmp_l, d, ourport, p->tag); + ret = ast_str_set(&from, 0, ";tag=%s", tmp_l, d, ourport, p->tag); } else { - ret = snprintf(from, sizeof(from), ";tag=%s", tmp_l, d, p->tag); + ret = ast_str_set(&from, 0, ";tag=%s", tmp_l, d, p->tag); } - if (ret < 0 || ret >= sizeof(from)) { /* a return value of size or more means that the output was truncated */ + if (ret == AST_DYNSTR_BUILD_FAILED) { /* We don't have an escape path from here... */ ast_log(LOG_ERROR, "The From header was truncated in call '%s'. This call setup will fail.\n", p->callid); + /* Make sure that the field contains something non-broken. + See https://issues.asterisk.org/jira/browse/ASTERISK-26069 + */ + ast_str_set(&from, 3, "<>"); + } /* If a caller id name was specified, prefix a display name, if there is enough room. */ if (cid_has_name || !cid_has_num) { - size_t written = strlen(from); - ssize_t left = sizeof(from) - written - 4; /* '"" \0' */ - if (left > 0) { - size_t name_len; - if (sip_cfg.pedanticsipchecking) { - ast_escape_quoted(n, tmp_n, MIN(left + 1, sizeof(tmp_n))); - n = tmp_n; - } - name_len = strlen(n); - if (left < name_len) { - name_len = left; - } - memmove(from + name_len + 3, from, written + 1); - from[0] = '"'; - memcpy(from + 1, n, name_len); - from[name_len + 1] = '"'; - from[name_len + 2] = ' '; + size_t written = ast_str_strlen(from); + size_t name_len; + if (sip_cfg.pedanticsipchecking) { + ast_escape_quoted(n, tmp_n, sizeof(tmp_n)); + n = tmp_n; + } + name_len = strlen(n); + ret = ast_str_make_space(&from, name_len + written + 4); + + if (ret == 0) { + /* needed again, as ast_str_make_space coud've changed the pointer */ + char *from_buf = ast_str_buffer(from); + + memmove(from_buf + name_len + 3, from_buf, written + 1); + from_buf[0] = '"'; + memcpy(from_buf + 1, n, name_len); + from_buf[name_len + 1] = '"'; + from_buf[name_len + 2] = ' '; } } @@ -14329,24 +14336,28 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho /*! \todo Need to add back the VXML URL here at some point, possibly use build_string for all this junk */ if (!strchr(p->todnid, '@')) { /* We have no domain in the dnid */ - ret = snprintf(to, sizeof(to), "%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); + ret = ast_str_set(&to, 0, "%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); } else { - ret = snprintf(to, sizeof(to), "%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); + ret = ast_str_set(&to, 0, "%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); } } else { if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) { /* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */ - ret = snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "sip:" : ""), p->uri, p->theirtag); + ret = ast_str_set(&to, 0, "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "sip:" : ""), p->uri, p->theirtag); } else if (p->options && p->options->vxml_url) { /* If there is a VXML URL append it to the SIP URL */ - ret = snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url); + ret = ast_str_set(&to, 0, "<%s>;%s", p->uri, p->options->vxml_url); } else { - ret = snprintf(to, sizeof(to), "<%s>", p->uri); + ret = ast_str_set(&to, 0, "<%s>", p->uri); } } - if (ret < 0 || ret >= sizeof(to)) { /* a return value of size or more means that the output was truncated */ + if (ret == AST_DYNSTR_BUILD_FAILED) { /* We don't have an escape path from here... */ ast_log(LOG_ERROR, "The To header was truncated in call '%s'. This call setup will fail.\n", p->callid); + /* Make sure that the field contains something non-broken. + See https://issues.asterisk.org/jira/browse/ASTERISK-26069 + */ + ast_str_set(&to, 3, "<>"); } init_req(req, sipmethod, p->uri); @@ -14361,8 +14372,8 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho */ add_route(req, &p->route, 0); - add_header(req, "From", from); - add_header(req, "To", to); + add_header(req, "From", ast_str_buffer(from)); + add_header(req, "To", ast_str_buffer(to)); ast_string_field_set(p, exten, l); build_contact(p, req, 0); add_header(req, "Contact", p->our_contact); @@ -14371,6 +14382,10 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho if (!ast_strlen_zero(global_useragent)) { add_header(req, "User-Agent", global_useragent); } + + ast_free(from); + ast_free(to); + ast_free(invite); } /*! \brief Add "Diversion" header to outgoing message From 31a5c28339312fe32ee35ff9ef286a5d25861323 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 2 Jun 2016 14:04:45 -0300 Subject: [PATCH 0484/1578] res_odbc: Implement a connection pool. Testing has shown that our usage of UnixODBC is problematic due to bugs within UnixODBC itself as well as the heavy weight cost of connecting and disconnecting database connections, even when pooling is enabled. For users of UnixODBC 2.3.1 and earlier crashes would occur due to insufficient protection of the disconnect operation. This was fixed in UnixODBC 2.3.2 and above. For users of UnixODBC 2.3.3 and higher a slow-down would occur under heavy database use due to repeated connection establishment. A regression is present where on each connection the database configuration is cached again, with the cache growing out of control. The connection pool implementation present in this change helps to mitigate these issues by reducing how much we connect and disconnect database connections. We also solve the issue of crashes under UnixODBC 2.3.1 by defaulting the maximum number of connections to 1, returning us to the previous working behavior. For users who may have a fixed version the maximum concurrent connection limit can be increased helping with performance. The connection pool works by keeping a list of active connections. If the connection limit has not been reached a new connection is established. If the connection limit has been reached then the request waits until a connection becomes available before continuing. ASTERISK-26074 #close ASTERISK-26054 #close Change-Id: I6774bf4bac49a0b30242c76a09c403d2e856ecff --- CHANGES | 6 + configs/samples/res_odbc.conf.sample | 5 + res/res_odbc.c | 232 ++++++++++++++++++++------- 3 files changed, 187 insertions(+), 56 deletions(-) diff --git a/CHANGES b/CHANGES index 608a4a4b33b..8275a99a57b 100644 --- a/CHANGES +++ b/CHANGES @@ -381,6 +381,12 @@ res_hep valid value using the specified 'uuid_type', the module may fallback to a more readily available source for the correlation UUID. +res_odbc +------------------ + * A new option has been added, 'max_connections', which sets the maximum number + of concurrent connections to the database. This option defaults to 1 which + returns the behavior to that of Asterisk 13.7 and prior. + app_confbridge ------------------ * Added a bridge profile option called regcontext that allows you to diff --git a/configs/samples/res_odbc.conf.sample b/configs/samples/res_odbc.conf.sample index 66659ae42ea..a21e96d0713 100644 --- a/configs/samples/res_odbc.conf.sample +++ b/configs/samples/res_odbc.conf.sample @@ -51,6 +51,11 @@ pre-connect => yes ; that we should attempt? ;limit => 5 ; +; The maximum number of connections to have open at any given time. +; This defaults to 1 and it is highly recommended to only set this higher +; if using a version of UnixODBC greater than 2.3.1. +;max_connections => 20 +; ; When the channel is destroyed, should any uncommitted open transactions ; automatically be committed? ;forcecommit => no diff --git a/res/res_odbc.c b/res/res_odbc.c index 81e1b3c135b..a89c954924a 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -78,10 +78,19 @@ struct odbc_class unsigned int forcecommit:1; /*!< Should uncommitted transactions be auto-committed on handle release? */ unsigned int isolation; /*!< Flags for how the DB should deal with data in other, uncommitted transactions */ unsigned int conntimeout; /*!< Maximum time the connection process should take */ + unsigned int maxconnections; /*!< Maximum number of allowed connections */ /*! When a connection fails, cache that failure for how long? */ struct timeval negative_connection_cache; /*! When a connection fails, when did that last occur? */ struct timeval last_negative_connect; + /*! A pool of available connections */ + AST_LIST_HEAD_NOLOCK(, odbc_obj) connections; + /*! Lock to protect the connections */ + ast_mutex_t lock; + /*! Condition to notify any pending connection requesters */ + ast_cond_t cond; + /*! The total number of current connections */ + size_t connection_cnt; }; static struct ao2_container *class_container; @@ -90,7 +99,7 @@ static AST_RWLIST_HEAD_STATIC(odbc_tables, odbc_cache_tables); static odbc_status odbc_obj_connect(struct odbc_obj *obj); static odbc_status odbc_obj_disconnect(struct odbc_obj *obj); -static int odbc_register_class(struct odbc_class *class, int connect); +static void odbc_register_class(struct odbc_class *class, int connect); AST_THREADSTORAGE(errors_buf); @@ -157,6 +166,8 @@ int ast_odbc_text2isolation(const char *txt) static void odbc_class_destructor(void *data) { struct odbc_class *class = data; + struct odbc_obj *obj; + /* Due to refcounts, we can safely assume that any objects with a reference * to us will prevent our destruction, so we don't need to worry about them. */ @@ -169,7 +180,14 @@ static void odbc_class_destructor(void *data) if (class->sanitysql) { ast_free(class->sanitysql); } + + while ((obj = AST_LIST_REMOVE_HEAD(&class->connections, list))) { + ao2_ref(obj, -1); + } + SQLFreeHandle(SQL_HANDLE_ENV, class->env); + ast_mutex_destroy(&class->lock); + ast_cond_destroy(&class->cond); } static int null_hash_fn(const void *obj, const int flags) @@ -180,21 +198,23 @@ static int null_hash_fn(const void *obj, const int flags) static void odbc_obj_destructor(void *data) { struct odbc_obj *obj = data; - struct odbc_class *class = obj->parent; - obj->parent = NULL; + odbc_obj_disconnect(obj); - ao2_ref(class, -1); } -static void destroy_table_cache(struct odbc_cache_tables *table) { +static void destroy_table_cache(struct odbc_cache_tables *table) +{ struct odbc_cache_columns *col; + ast_debug(1, "Destroying table cache for %s\n", table->table); + AST_RWLIST_WRLOCK(&table->columns); while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) { ast_free(col); } AST_RWLIST_UNLOCK(&table->columns); AST_RWLIST_HEAD_DESTROY(&table->columns); + ast_free(table); } @@ -370,18 +390,19 @@ SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT (*prepare_c * We must therefore redo everything when we establish a new * connection. */ stmt = prepare_cb(obj, data); + if (!stmt) { + return NULL; + } - if (stmt) { - res = SQLExecute(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { - if (res == SQL_ERROR) { - ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute"); - } - - ast_log(LOG_WARNING, "SQL Execute error %d!\n", res); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - stmt = NULL; + res = SQLExecute(stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { + if (res == SQL_ERROR) { + ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute"); } + + ast_log(LOG_WARNING, "SQL Execute error %d!\n", res); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + stmt = NULL; } return stmt; @@ -468,7 +489,7 @@ static int load_odbc_config(void) struct ast_variable *v; char *cat; const char *dsn, *username, *password, *sanitysql; - int enabled, bse, conntimeout, forcecommit, isolation; + int enabled, bse, conntimeout, forcecommit, isolation, maxconnections; struct timeval ncache = { 0, 0 }; int preconnect = 0, res = 0; struct ast_flags config_flags = { 0 }; @@ -495,6 +516,7 @@ static int load_odbc_config(void) conntimeout = 10; forcecommit = 0; isolation = SQL_TXN_READ_COMMITTED; + maxconnections = 1; for (v = ast_variable_browse(config, cat); v; v = v->next) { if (!strcasecmp(v->name, "pooling") || !strncasecmp(v->name, "share", 5) || @@ -538,6 +560,11 @@ static int load_odbc_config(void) ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat); isolation = SQL_TXN_READ_COMMITTED; } + } else if (!strcasecmp(v->name, "max_connections")) { + if (sscanf(v->value, "%30d", &maxconnections) != 1 || maxconnections < 1) { + ast_log(LOG_WARNING, "max_connections must be a positive integer\n"); + maxconnections = 1; + } } } @@ -563,6 +590,7 @@ static int load_odbc_config(void) new->isolation = isolation; new->conntimeout = conntimeout; new->negative_connection_cache = ncache; + new->maxconnections = maxconnections; if (cat) ast_copy_string(new->name, cat, sizeof(new->name)); @@ -581,6 +609,9 @@ static int load_odbc_config(void) break; } + ast_mutex_init(&new->lock); + ast_cond_init(&new->cond, NULL); + odbc_register_class(new, preconnect); ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); ao2_ref(new, -1); @@ -641,6 +672,7 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm); ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn); ast_cli(a->fd, " Last connection attempt: %s\n", timestr); + ast_cli(a->fd, " Number of active connections: %zd (out of %d)\n", class->connection_cnt, class->maxconnections); ast_cli(a->fd, "\n"); } ao2_ref(class, -1); @@ -654,38 +686,47 @@ static struct ast_cli_entry cli_odbc[] = { AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)") }; -static int odbc_register_class(struct odbc_class *class, int preconnect) +static void odbc_register_class(struct odbc_class *class, int preconnect) { struct odbc_obj *obj; - if (class) { - ao2_link(class_container, class); - /* I still have a reference in the caller, so a deref is NOT missing here. */ - - if (preconnect) { - /* Request and release builds a connection */ - obj = ast_odbc_request_obj(class->name, 0); - if (obj) { - ast_odbc_release_obj(obj); - } - } - return 0; - } else { - ast_log(LOG_WARNING, "Attempted to register a NULL class?\n"); - return -1; + ao2_link(class_container, class); + /* I still have a reference in the caller, so a deref is NOT missing here. */ + + if (!preconnect) { + return; } + + /* Request and release builds a connection */ + obj = ast_odbc_request_obj(class->name, 0); + if (obj) { + ast_odbc_release_obj(obj); + } + + return; } void ast_odbc_release_obj(struct odbc_obj *obj) { - ast_debug(2, "Releasing ODBC handle %p\n", obj); + struct odbc_class *class = obj->parent; -#ifdef DEBUG_THREADS - obj->file[0] = '\0'; - obj->function[0] = '\0'; - obj->lineno = 0; -#endif - ao2_ref(obj, -1); + ast_debug(2, "Releasing ODBC handle %p into pool\n", obj); + + /* The odbc_obj only holds a reference to the class when it is + * actively being used. This guarantees no circular reference + * between odbc_class and odbc_obj. Since it is being released + * we also release our class reference. If a reload occurred before + * the class will go away automatically once all odbc_obj are + * released back. + */ + obj->parent = NULL; + + ast_mutex_lock(&class->lock); + AST_LIST_INSERT_HEAD(&class->connections, obj, list); + ast_cond_signal(&class->cond); + ast_mutex_unlock(&class->lock); + + ao2_ref(class, -1); } int ast_odbc_backslash_is_escape(struct odbc_obj *obj) @@ -703,6 +744,50 @@ static int aoro2_class_cb(void *obj, void *arg, int flags) return 0; } +/* + * \brief Determine if the connection has died. + * + * \param connection The connection to check + * \param class The ODBC class + * \retval 1 Yep, it's dead + * \retval 0 It's alive and well + */ +static int connection_dead(struct odbc_obj *connection, struct odbc_class *class) +{ + char *test_sql = "select 1"; + SQLINTEGER dead; + SQLRETURN res; + SQLHSTMT stmt; + + res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0); + if (SQL_SUCCEEDED(res)) { + return dead == SQL_CD_TRUE ? 1 : 0; + } + + /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a + * probing query instead + */ + res = SQLAllocHandle(SQL_HANDLE_STMT, connection->con, &stmt); + if (!SQL_SUCCEEDED(res)) { + return 1; + } + + if (!ast_strlen_zero(class->sanitysql)) { + test_sql = class->sanitysql; + } + + res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); + if (!SQL_SUCCEEDED(res)) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return 1; + } + + res = SQLExecute(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + + return SQL_SUCCEEDED(res) ? 0 : 1; +} + struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno) { struct odbc_obj *obj = NULL; @@ -713,17 +798,60 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags return NULL; } - /* XXX ODBC connection objects do not have shared ownership, so there is no reason - * to use refcounted objects here. - */ - obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); - /* Inherit reference from the ao2_callback from before */ - obj->parent = class; - if (odbc_obj_connect(obj) == ODBC_FAIL) { - ao2_ref(obj, -1); - return NULL; + ast_mutex_lock(&class->lock); + + while (!obj) { + obj = AST_LIST_REMOVE_HEAD(&class->connections, list); + + if (!obj) { + if (class->connection_cnt < class->maxconnections) { + /* If no connection is immediately available establish a new + * one if allowed. If we try and fail we give up completely as + * we could go into an infinite loop otherwise. + */ + obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); + if (!obj) { + break; + } + + obj->parent = ao2_bump(class); + if (odbc_obj_connect(obj) == ODBC_FAIL) { + ao2_ref(obj->parent, -1); + ao2_ref(obj, -1); + obj = NULL; + break; + } + + class->connection_cnt++; + ast_debug(2, "Created ODBC handle %p on class '%s', new count is %zd\n", obj, + name, class->connection_cnt); + } else { + /* Otherwise if we're not allowed to create a new one we + * wait for another thread to give up the connection they + * own. + */ + ast_cond_wait(&class->cond, &class->lock); + } + } else if (connection_dead(obj, class)) { + /* If the connection is dead try to grab another functional one from the + * pool instead of trying to resurrect this one. + */ + ao2_ref(obj, -1); + obj = NULL; + class->connection_cnt--; + ast_debug(2, "ODBC handle %p dead - removing from class '%s', new count is %zd\n", + obj, name, class->connection_cnt); + } else { + /* We successfully grabbed a connection from the pool and all is well! + */ + obj->parent = ao2_bump(class); + ast_debug(2, "Reusing ODBC handle %p from class '%s'\n", obj, name); + } } + ast_mutex_unlock(&class->lock); + ao2_ref(class, -1); + return obj; } @@ -755,14 +883,6 @@ static odbc_status odbc_obj_disconnect(struct odbc_obj *obj) obj->con = NULL; res = SQLDisconnect(con); - if (obj->parent) { - if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) { - ast_debug(3, "Disconnected %d from %s [%s](%p)\n", res, obj->parent->name, obj->parent->dsn, obj); - } else { - ast_debug(3, "res_odbc: %s [%s](%p) already disconnected\n", obj->parent->name, obj->parent->dsn, obj); - } - } - if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) == SQL_SUCCESS) { ast_debug(3, "Database handle %p (connection %p) deallocated\n", obj, con); } else { From 784c18128b4b96c9993e7cfff93a70b75096762c Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 8 Jun 2016 09:11:40 +0200 Subject: [PATCH 0485/1578] chan_sip: No rtpmap for static RTP payload IDs in SDP. This saves around 100 bytes when G.711, G.722, G.729, and GSM are advertised in SDP. This reduces the chance to hit the MTU bearer of 1300 bytes for SIP over UDP, if many codecs are allowed in Asterisk. This new feature is enabled together with the optional feature compactheaders=yes via the file sip.conf. ASTERISK-25578 #close Change-Id: I16491b1937862de26f84fa0ffe679a6bab925044 --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 19f8aa308a8..d44bf8a83e3 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -12996,7 +12996,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p, /* Opus mandates 2 channels in rtpmap */ if (ast_format_cmp(format, ast_format_opus) == AST_FORMAT_CMP_EQUAL) { ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u/2\r\n", rtp_code, mime, rate); - } else { + } else if ((35 <= rtp_code) || !(sip_cfg.compactheaders)) { ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate); } From 7f5ca67e5fbc6d4e39a8f1f881faea568770819f Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 8 Jun 2016 12:26:29 -0500 Subject: [PATCH 0486/1578] res_hep_{pjsip|rtcp}: Decline module loads if res_hep had not loaded A crash can occur in res_hep_pjsip or res_hep_rtcp if res_hep has not loaded and does not have a configuration file. Previously when this occurred, checks were put in to see if the configuration was loaded successfully. While this is a good idea - and has been added to the offending function in res_hep - the reality is res_hep_pjsip and res_hep_rtcp have no business running if res_hep isn't also running. As such, this patch also adds a function to res_hep that returns whether or not it successfully loaded. Oddly enough, ast_module_check returns "everything is peachy" even if a module declined its load - so it cannot be solely relied on. res_hep_pjsip and res_hep_rtcp now also check this function to see if they should continue to load; if it fails, they decline their load as well. ASTERISK-26096 #close Change-Id: I007e535fcc2e51c2ca48534f48c5fc2ac38935ea --- include/asterisk/res_hep.h | 8 ++++++++ res/res_hep.c | 12 ++++++++++++ res/res_hep.exports.in | 1 + res/res_hep_pjsip.c | 5 +++++ res/res_hep_rtcp.c | 4 ++++ 5 files changed, 30 insertions(+) diff --git a/include/asterisk/res_hep.h b/include/asterisk/res_hep.h index bd0129eeada..cfd213ad7b4 100644 --- a/include/asterisk/res_hep.h +++ b/include/asterisk/res_hep.h @@ -118,6 +118,14 @@ int hepv3_send_packet(struct hepv3_capture_info *capture_info); */ enum hep_uuid_type hepv3_get_uuid_type(void); +/*! + * \brief Return whether or not we're currently loaded and active + * + * \retval 0 The module is not loaded + * \retval 1 The module is loaded + */ +int hepv3_is_loaded(void); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/res/res_hep.c b/res/res_hep.c index 45201359dbb..e79f2b67abc 100644 --- a/res/res_hep.c +++ b/res/res_hep.c @@ -409,9 +409,21 @@ enum hep_uuid_type hepv3_get_uuid_type(void) { RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup); + if (!config) { + /* Well, that's unfortunate. Return something. */ + return HEP_UUID_TYPE_CALL_ID; + } + return config->general->uuid_type; } +int hepv3_is_loaded(void) +{ + RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup); + + return (config != NULL) ? 1 : 0; +} + struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len) { struct hepv3_capture_info *info; diff --git a/res/res_hep.exports.in b/res/res_hep.exports.in index df0f2b4f704..e318ac97f60 100644 --- a/res/res_hep.exports.in +++ b/res/res_hep.exports.in @@ -3,6 +3,7 @@ LINKER_SYMBOL_PREFIX*hepv3_send_packet; LINKER_SYMBOL_PREFIX*hepv3_create_capture_info; LINKER_SYMBOL_PREFIX*hepv3_get_uuid_type; + LINKER_SYMBOL_PREFIX*hepv3_is_loaded; local: *; }; diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index 0cc54c237ab..a3a93e9b28a 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -210,6 +210,11 @@ static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); + if (!ast_module_check("res_hep.so") || !hepv3_is_loaded()) { + ast_log(AST_LOG_WARNING, "res_hep is not loaded or running; declining module load\n"); + return AST_MODULE_LOAD_DECLINE; + } + ast_sip_register_service(&logging_module); return AST_MODULE_LOAD_SUCCESS; } diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 8643d4db6bc..03db1815966 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -149,6 +149,10 @@ static void rtp_topic_handler(void *data, struct stasis_subscription *sub, struc static int load_module(void) { + if (!ast_module_check("res_hep.so") || !hepv3_is_loaded()) { + ast_log(AST_LOG_WARNING, "res_hep is not loaded or running; declining module load\n"); + return AST_MODULE_LOAD_DECLINE; + } stasis_rtp_subscription = stasis_subscribe(ast_rtp_topic(), rtp_topic_handler, NULL); From 39b69ab5373222812d4e981b27681cd0925fed73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 3 Jun 2016 08:57:02 +0300 Subject: [PATCH 0487/1578] Fixes to include signal.h POSIX defines signal.h. sys/signal.h should not be used as it is c-library internal header which may or may not exist. Notably with musl it generates warning of being incorrect. Change-Id: Ia56b0aa1d84b5c590114867b1b384a624f39a6fc --- addons/chan_ooh323.h | 1 - apps/app_dahdiras.c | 5 ----- apps/app_dial.c | 2 +- apps/app_queue.c | 2 +- channels/chan_console.c | 2 +- channels/chan_dahdi.c | 4 +--- channels/chan_iax2.c | 1 - channels/chan_mgcp.c | 1 - channels/chan_motif.c | 2 +- channels/chan_sip.c | 1 - channels/chan_skinny.c | 1 - main/cli.c | 1 - main/features.c | 2 +- main/http.c | 2 +- main/tcptls.c | 1 - pbx/pbx_dundi.c | 2 +- res/res_musiconhold.c | 2 +- 17 files changed, 9 insertions(+), 23 deletions(-) diff --git a/addons/chan_ooh323.h b/addons/chan_ooh323.h index 89caaff63b2..1279a2246d3 100644 --- a/addons/chan_ooh323.h +++ b/addons/chan_ooh323.h @@ -38,7 +38,6 @@ #include #include #include -#include #include "asterisk/lock.h" #include "asterisk/channel.h" diff --git a/apps/app_dahdiras.c b/apps/app_dahdiras.c index e8bdad01e15..51921a98ec7 100644 --- a/apps/app_dahdiras.c +++ b/apps/app_dahdiras.c @@ -36,12 +36,7 @@ ASTERISK_REGISTER_FILE() #include #include -#ifdef __linux__ -#include -#else #include -#endif /* __linux__ */ - #include #include diff --git a/apps/app_dial.c b/apps/app_dial.c index 5e034d3ebe2..f05521b5d82 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -35,7 +35,7 @@ ASTERISK_REGISTER_FILE() #include -#include +#include #include #include diff --git a/apps/app_queue.c b/apps/app_queue.c index 165924e0c88..cd545d2fa51 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -72,7 +72,7 @@ ASTERISK_REGISTER_FILE() #include -#include +#include #include #include diff --git a/channels/chan_console.c b/channels/chan_console.c index 9fdecd7d4ac..bd849ad5329 100644 --- a/channels/chan_console.c +++ b/channels/chan_console.c @@ -64,7 +64,7 @@ ASTERISK_REGISTER_FILE() -#include /* SIGURG */ +#include /* SIGURG */ #include diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 2d923433c51..e4b7c0ee8a4 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -58,10 +58,8 @@ ASTERISK_REGISTER_FILE() #if defined(__NetBSD__) || defined(__FreeBSD__) #include -#include -#else -#include #endif +#include #include #include diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index af44de96c6c..721da9a044a 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -68,7 +68,6 @@ ASTERISK_REGISTER_FILE() #include #include #include -#include #include #include #include diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 8714ddbbc71..6df5d3fd0fc 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -47,7 +47,6 @@ ASTERISK_REGISTER_FILE() #include #include #include -#include #include #include #include diff --git a/channels/chan_motif.c b/channels/chan_motif.c index 118d1d9fb17..0c710923f68 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -51,7 +51,7 @@ ASTERISK_REGISTER_FILE() #include #include #include -#include +#include #include #include diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 19f8aa308a8..fc26e7ebf04 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -224,7 +224,6 @@ ASTERISK_REGISTER_FILE() #include -#include #include #include diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 76990d175c7..fb6e619a1e5 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -49,7 +49,6 @@ ASTERISK_REGISTER_FILE() #include #include #include -#include #include #include diff --git a/main/cli.c b/main/cli.c index f2bedc91aba..8af20b61bd2 100644 --- a/main/cli.c +++ b/main/cli.c @@ -42,7 +42,6 @@ ASTERISK_REGISTER_FILE() #include "asterisk/_private.h" #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */ -#include #include #include #include diff --git a/main/features.c b/main/features.c index 7dfe4cde576..6806fe749fc 100644 --- a/main/features.c +++ b/main/features.c @@ -46,7 +46,7 @@ ASTERISK_REGISTER_FILE() #include #include #include -#include +#include #include #include "asterisk/lock.h" diff --git a/main/http.c b/main/http.c index 5ec94a7e199..a8362829efa 100644 --- a/main/http.c +++ b/main/http.c @@ -49,7 +49,7 @@ ASTERISK_REGISTER_FILE() #include #include #include -#include +#include #include #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */ diff --git a/main/tcptls.c b/main/tcptls.c index f56e0aa70c3..046501b77e2 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -38,7 +38,6 @@ ASTERISK_REGISTER_FILE() #endif #include -#include #include "asterisk/compat.h" #include "asterisk/tcptls.h" diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index 10495acb6fd..94b71a002eb 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -43,7 +43,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/network.h" #include #include -#include +#include #include #include diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index f124d58f23a..3c7199ef459 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -44,7 +44,7 @@ ASTERISK_REGISTER_FILE() #include #include #include -#include +#include #include #include #include From 72d190eb69e22661806f1235e7b0d30b555cfb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 3 Jun 2016 08:59:30 +0300 Subject: [PATCH 0488/1578] Detect and use proper libraries for musl toolchains Change-Id: I8d9b212f70813404b82918a3f99439e500d4bfcb --- configure | 19 ++++++++++++------- configure.ac | 9 +++++++-- main/Makefile | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 9e3772748f8..bcc427c8467 100755 --- a/configure +++ b/configure @@ -4866,6 +4866,9 @@ case "${host_os}" in linux-gnueabi* | linux-gnuspe) OSARCH=linux-gnu ;; + linux-musl*) + OSARCH=linux-musl + ;; kfreebsd*-gnu) OSARCH=kfreebsd-gnu ;; @@ -13772,7 +13775,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13818,7 +13821,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13842,7 +13845,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13887,7 +13890,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13911,7 +13914,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -19328,7 +19331,8 @@ fi fi -if test "x${OSARCH}" = "xlinux-gnu" ; then +case "${OSARCH}" in +linux*) if test "x${PBX_CAP}" != "x1" -a "${USE_CAP}" != "no"; then pbxlibdir="" @@ -19433,7 +19437,8 @@ _ACEOF fi -fi + ;; +esac if test "x${PBX_DAHDI}" != "x1"; then diff --git a/configure.ac b/configure.ac index 5852d3fa2a6..3cc8588fe96 100644 --- a/configure.ac +++ b/configure.ac @@ -181,6 +181,9 @@ case "${host_os}" in linux-gnueabi* | linux-gnuspe) OSARCH=linux-gnu ;; + linux-musl*) + OSARCH=linux-musl + ;; kfreebsd*-gnu) OSARCH=kfreebsd-gnu ;; @@ -1388,9 +1391,11 @@ if test "${PBX_BFD}" = "0"; then AST_EXT_LIB_CHECK([BFD], [bfd], [bfd_check_format], [bfd.h], [-ldl -liberty -lz]) fi -if test "x${OSARCH}" = "xlinux-gnu" ; then +case "${OSARCH}" in +linux*) AST_EXT_LIB_CHECK([CAP], [cap], [cap_from_text], [sys/capability.h]) -fi + ;; +esac AST_C_DEFINE_CHECK([DAHDI], [DAHDI_RESET_COUNTERS], [dahdi/user.h], [230]) AST_C_DEFINE_CHECK([DAHDI], [DAHDI_DEFAULT_MTU_MRU], [dahdi/user.h], [220]) diff --git a/main/Makefile b/main/Makefile index 3863978011e..729ae9c0131 100644 --- a/main/Makefile +++ b/main/Makefile @@ -46,7 +46,7 @@ AST_LIBS+=$(CRYPT_LIB) AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS) AST_LIBS+=$(RT_LIB) -ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc kfreebsd-gnu),) +ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc linux-musl kfreebsd-gnu),) ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),) AST_LIBS+=-ldl endif From d21a77b325d814eca76290b11a276199841d8bfa Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 9 Jun 2016 08:20:33 -0600 Subject: [PATCH 0489/1578] build: Fix ast_sockaddr initialization to be more portable A change to glibc 2.22 changed the order of the sockadddr_storage members which caused the places where we do an initialization of ast_sockaddr with '{ { 0, 0, } }' to fail compilation. Those initializers (which we shouldn't have been using anyway) have been replaced with memsets. Change-Id: Idd1b3b320903d8771bfe221f0b015685de628fa4 --- channels/chan_sip.c | 3 ++- tests/test_netsock2.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index eec904f57f5..4c3516d8cd9 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -15790,11 +15790,12 @@ static void start_register_timeout(struct sip_registry *reg) static const char *sip_sanitized_host(const char *host) { - struct ast_sockaddr addr = { { 0, 0, }, }; + struct ast_sockaddr addr; /* peer/sip_pvt->tohost and sip_registry->hostname should never have a port * in them, so we use PARSE_PORT_FORBID here. If this lookup fails, we return * the original host which is most likely a host name and not an IP. */ + memset(&addr, 0, sizeof(addr)); if (!ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID)) { return host; } diff --git a/tests/test_netsock2.c b/tests/test_netsock2.c index 638ff37ccb6..780b0b06f26 100644 --- a/tests/test_netsock2.c +++ b/tests/test_netsock2.c @@ -75,7 +75,7 @@ AST_TEST_DEFINE(parsing) }; size_t x; - struct ast_sockaddr addr = { { 0, 0, } }; + struct ast_sockaddr addr; int parse_result; switch (cmd) { @@ -91,15 +91,17 @@ AST_TEST_DEFINE(parsing) } for (x = 0; x < ARRAY_LEN(test_vals); x++) { + memset(&addr, 0, sizeof(addr)); if ((parse_result = ast_sockaddr_parse(&addr, test_vals[x].address, 0)) != test_vals[x].expected_result) { ast_test_status_update(test, "On '%s' expected %d but got %d\n", test_vals[x].address, test_vals[x].expected_result, parse_result); res = AST_TEST_FAIL; } if (parse_result) { - struct ast_sockaddr tmp_addr = { { 0, 0, } }; + struct ast_sockaddr tmp_addr; const char *tmp; tmp = ast_sockaddr_stringify(&addr); + memset(&tmp_addr, 0, sizeof(tmp_addr)); ast_sockaddr_parse(&tmp_addr, tmp, 0); if (ast_sockaddr_cmp_addr(&addr, &tmp_addr)) { char buf[64]; From df2791da8f15aca4608e9bc748b43776c7797340 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 2 Jun 2016 12:51:31 -0500 Subject: [PATCH 0490/1578] pjsip_distributor.c: Ignore messages until fully booted. We should not be processing any incoming messages until we are fully booted. We may not have dialplan or other needed configuration loaded yet. ASTERISK-26089 #close Reported by: Scott Griepentrog ASTERISK-26088 Reported by: Richard Mudgett Change-Id: I584aefb4f34b885a8927e1f13a2c64babd606264 --- CHANGES | 3 +++ res/res_pjsip/pjsip_distributor.c | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 43dc18f4bae..56daf17670e 100644 --- a/CHANGES +++ b/CHANGES @@ -397,6 +397,9 @@ res_pjsip into the "reg_server" field in the ps_contacts table to facilitate multi-server setups. + * When starting Asterisk, received traffic will now be ignored until Asterisk + has loaded all modules and is fully booted. + res_hep ------------------ * Added a new option, 'uuid_type', that sets the preferred source of the Homer diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 3867eaea0c8..288a3e00a88 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -290,11 +290,20 @@ static pjsip_module endpoint_mod = { static pj_bool_t distributor(pjsip_rx_data *rdata) { - pjsip_dialog *dlg = find_dialog(rdata); + pjsip_dialog *dlg; struct distributor_dialog_data *dist = NULL; struct ast_taskprocessor *serializer = NULL; pjsip_rx_data *clone; + if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { + /* + * Ignore everything until we are fully booted. Let the + * peer retransmit messages until we are ready. + */ + return PJ_TRUE; + } + + dlg = find_dialog(rdata); if (dlg) { ast_debug(3, "Searching for serializer on dialog %s for %s\n", dlg->obj_name, pjsip_rx_data_get_info(rdata)); From 2ff26e97467fabc390cf887fcda84f2e26b83895 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 26 May 2016 17:35:04 -0500 Subject: [PATCH 0491/1578] pjsip_distributor.c: Consistently pick a serializer for messages. Incoming messages that are not part of a dialog or a recognized response to one of our requests need to be sent to a consistent serializer. Under load we may be queueing retransmissions before we can process the original message. We don't need to throw these messages onto random serializers and cause reentrancy and message sequencing problems. * Created a pool of pjsip/distributor serializers that get picked by hashing the call-id and remote tag strings of the received messages. * Made ast_sip_destroy_distributor() destroy items in the reverse order of creation. ASTERISK-26088 Reported by: Richard Mudgett Change-Id: I2ce769389fc060d9f379977f559026fbcb632407 --- include/asterisk/res_pjsip.h | 11 ++ res/res_pjsip/pjsip_distributor.c | 160 +++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 5 deletions(-) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 50d02d9808f..d1f0c9825b4 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -1300,6 +1300,17 @@ struct ast_serializer_shutdown_group; */ struct ast_taskprocessor *ast_sip_create_serializer_group(const char *name, struct ast_serializer_shutdown_group *shutdown_group); +/*! + * \brief Determine the distributor serializer for the SIP message. + * \since 13.10.0 + * + * \param rdata The incoming message. + * + * \retval Calculated distributor serializer on success. + * \retval NULL on error. + */ +struct ast_taskprocessor *ast_sip_get_distributor_serializer(pjsip_rx_data *rdata); + /*! * \brief Set a serializer on a SIP dialog so requests and responses are automatically serialized * diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 288a3e00a88..75ae461cd0a 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -59,6 +59,12 @@ struct unidentified_request{ char src_name[]; }; +/*! Number of serializers in pool if one not otherwise known. (Best if prime number) */ +#define DISTRIBUTOR_POOL_SIZE 31 + +/*! Pool of serializers to use if not supplied. */ +static struct ast_taskprocessor *distributor_pool[DISTRIBUTOR_POOL_SIZE]; + /*! * \internal * \brief Record the task's serializer name on the tdata structure. @@ -278,6 +284,83 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) return dlg; } +/*! + * \internal + * \brief Compute a hash value on a pjlib string + * \since 13.10.0 + * + * \param[in] str The pjlib string to add to the hash + * \param[in] hash The hash value to add to + * + * \details + * This version of the function is for when you need to compute a + * string hash of more than one string. + * + * This famous hash algorithm was written by Dan Bernstein and is + * commonly used. + * + * \sa http://www.cse.yorku.ca/~oz/hash.html + */ +static int pjstr_hash_add(pj_str_t *str, int hash) +{ + size_t len; + const char *pos; + + len = pj_strlen(str); + pos = pj_strbuf(str); + while (len--) { + hash = hash * 33 ^ *pos++; + } + + return hash; +} + +/*! + * \internal + * \brief Compute a hash value on a pjlib string + * \since 13.10.0 + * + * \param[in] str The pjlib string to hash + * + * This famous hash algorithm was written by Dan Bernstein and is + * commonly used. + * + * http://www.cse.yorku.ca/~oz/hash.html + */ +static int pjstr_hash(pj_str_t *str) +{ + return pjstr_hash_add(str, 5381); +} + +struct ast_taskprocessor *ast_sip_get_distributor_serializer(pjsip_rx_data *rdata) +{ + int hash; + pj_str_t *remote_tag; + struct ast_taskprocessor *serializer; + + if (!rdata->msg_info.msg) { + return NULL; + } + + if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { + remote_tag = &rdata->msg_info.from->tag; + } else { + remote_tag = &rdata->msg_info.to->tag; + } + + /* Compute the hash from the SIP message call-id and remote-tag */ + hash = pjstr_hash(&rdata->msg_info.cid->id); + hash = pjstr_hash_add(remote_tag, hash); + hash = abs(hash); + + serializer = ao2_bump(distributor_pool[hash % ARRAY_LEN(distributor_pool)]); + if (serializer) { + ast_debug(3, "Calculated serializer %s to use for %s\n", + ast_taskprocessor_name(serializer), pjsip_rx_data_get_info(rdata)); + } + return serializer; +} + static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata); static pjsip_module endpoint_mod = { @@ -324,12 +407,23 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) ast_debug(3, "No dialog serializer for response %s. Using request transaction as basis\n", pjsip_rx_data_get_info(rdata)); serializer = find_request_serializer(rdata); + if (!serializer) { + /* + * Pick a serializer for the unmatched response. Maybe + * the stack can figure out what it is for, or we really + * should just toss it regardless. + */ + serializer = ast_sip_get_distributor_serializer(rdata); + } } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || !pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method)) { /* We have a BYE or CANCEL request without a serializer. */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL); return PJ_TRUE; + } else { + /* Pick a serializer for the out-of-dialog request. */ + serializer = ast_sip_get_distributor_serializer(rdata); } pjsip_rx_data_clone(rdata, 0, &clone); @@ -349,7 +443,10 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]); pjsip_rx_data_free_cloned(clone); } else { - ast_sip_push_task(serializer, distribute, clone); + if (ast_sip_push_task(serializer, distribute, clone)) { + ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]); + pjsip_rx_data_free_cloned(clone); + } } ast_taskprocessor_unreference(serializer); @@ -796,6 +893,7 @@ static int cli_unid_print_header(void *obj, void *arg, int flags) return 0; } + static int cli_unid_print_body(void *obj, void *arg, int flags) { struct unidentified_request *unid = obj; @@ -886,6 +984,47 @@ static struct ast_sorcery_observer global_observer = { .loaded = global_loaded, }; +/*! + * \internal + * \brief Shutdown the serializers in the distributor pool. + * \since 13.10.0 + * + * \return Nothing + */ +static void distributor_pool_shutdown(void) +{ + int idx; + + for (idx = 0; idx < ARRAY_LEN(distributor_pool); ++idx) { + ast_taskprocessor_unreference(distributor_pool[idx]); + distributor_pool[idx] = NULL; + } +} + +/*! + * \internal + * \brief Setup the serializers in the distributor pool. + * \since 13.10.0 + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int distributor_pool_setup(void) +{ + char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; + int idx; + + for (idx = 0; idx < ARRAY_LEN(distributor_pool); ++idx) { + /* Create name with seq number appended. */ + ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/distributor"); + + distributor_pool[idx] = ast_sip_create_serializer(tps_name); + if (!distributor_pool[idx]) { + return -1; + } + } + return 0; +} int ast_sip_initialize_distributor(void) { @@ -895,6 +1034,11 @@ int ast_sip_initialize_distributor(void) return -1; } + if (distributor_pool_setup()) { + ast_sip_destroy_distributor(); + return -1; + } + prune_context = ast_sched_context_create(); if (!prune_context) { ast_sip_destroy_distributor(); @@ -927,8 +1071,10 @@ int ast_sip_initialize_distributor(void) return -1; } - unid_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); + unid_formatter = ao2_alloc_options(sizeof(struct ast_sip_cli_formatter_entry), NULL, + AO2_ALLOC_OPT_LOCK_NOLOCK); if (!unid_formatter) { + ast_sip_destroy_distributor(); ast_log(LOG_ERROR, "Unable to allocate memory for unid_formatter\n"); return -1; } @@ -940,6 +1086,7 @@ int ast_sip_initialize_distributor(void) unid_formatter->get_id = cli_unid_get_id; unid_formatter->retrieve_by_id = cli_unid_retrieve_by_id; ast_sip_register_cli_formatter(unid_formatter); + ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); return 0; @@ -950,17 +1097,20 @@ void ast_sip_destroy_distributor(void) ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(unid_formatter); - internal_sip_unregister_service(&distributor_mod); - internal_sip_unregister_service(&endpoint_mod); internal_sip_unregister_service(&auth_mod); + internal_sip_unregister_service(&endpoint_mod); + internal_sip_unregister_service(&distributor_mod); ao2_cleanup(artificial_auth); ao2_cleanup(artificial_endpoint); - ao2_cleanup(unidentified_requests); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); if (prune_context) { ast_sched_context_destroy(prune_context); } + + distributor_pool_shutdown(); + + ao2_cleanup(unidentified_requests); } From c2ae49249c37fa699fa16fc5f9f7a451406b721a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 27 May 2016 12:50:14 -0500 Subject: [PATCH 0492/1578] res_pjsip_pubsub.c: Use distributor serializer for incoming subscriptions. We must continue using the serializer that the original SUBSCRIBE came in on for the dialog. There may be retransmissions already enqueued in the original serializer that can result in reentrancy and message sequencing problems. The "sip_transaction Unable to register SUBSCRIBE transaction (key exists)" message is a notable symptom of this issue. Outgoing subscriptions still create the pjsip/pubsub/ serializers for their dialogs. ASTERISK-26088 Reported by: Richard Mudgett Change-Id: I18b00bb74a56747b2c8c29543a82440b110bf0b0 --- res/res_pjsip_pubsub.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 10ffb19fcc1..2e057617b57 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1207,10 +1207,9 @@ static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pj pjsip_dlg_inc_session(dlg, &pubsub_module); } -static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_endpoint *endpoint) +static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata) { struct sip_subscription_tree *sub_tree; - char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor); if (!sub_tree) { @@ -1219,11 +1218,24 @@ static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_e ast_module_ref(ast_module_info->self); - /* Create name with seq number appended. */ - ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s", - ast_sorcery_object_get_id(endpoint)); + if (rdata) { + /* + * We must continue using the serializer that the original + * SUBSCRIBE came in on for the dialog. There may be + * retransmissions already enqueued in the original + * serializer that can result in reentrancy and message + * sequencing problems. + */ + sub_tree->serializer = ast_sip_get_distributor_serializer(rdata); + } else { + char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; + + /* Create name with seq number appended. */ + ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s", + ast_sorcery_object_get_id(endpoint)); - sub_tree->serializer = ast_sip_create_serializer(tps_name); + sub_tree->serializer = ast_sip_create_serializer(tps_name); + } if (!sub_tree->serializer) { ao2_ref(sub_tree, -1); return NULL; @@ -1264,7 +1276,7 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s pjsip_dialog *dlg; struct subscription_persistence *persistence; - sub_tree = allocate_subscription_tree(endpoint); + sub_tree = allocate_subscription_tree(endpoint, rdata); if (!sub_tree) { *dlg_status = PJ_ENOMEM; return NULL; @@ -1571,7 +1583,7 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su pjsip_evsub *evsub; struct sip_subscription_tree *sub_tree = NULL; - sub_tree = allocate_subscription_tree(endpoint); + sub_tree = allocate_subscription_tree(endpoint, NULL); if (!sub_tree) { return NULL; } From 5b7b16a87f5f33ddc100375e4289dfe46ef3c40e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 27 May 2016 16:28:39 -0500 Subject: [PATCH 0493/1578] res_pjsip_pubsub.c: Recreate subscriptions using distributor serializer. * Resolves potential reentrancy problems if system restarted in the middle of subscription message transactions. * Fixes memory leak recreating persistent subscriptions when the subscription resource tree could not be created. ASTERISK-26088 Reported by: Richard Mudgett Change-Id: I71e34d7ae8ed35a694f1030e820e2548c48697be --- res/res_pjsip_pubsub.c | 183 ++++++++++++++++++++++++++++------------- 1 file changed, 125 insertions(+), 58 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 2e057617b57..06a1b52b1af 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -355,7 +355,7 @@ struct ast_sip_publication { struct subscription_persistence { /*! Sorcery object details */ SORCERY_OBJECT(details); - /*! The name of the endpoint involved in the subscrption */ + /*! The name of the endpoint involved in the subscription */ char *endpoint; /*! SIP message that creates the subscription */ char packet[PJSIP_MAX_PKT_LEN]; @@ -1325,109 +1325,176 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s static int initial_notify_task(void *obj); static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state); -/*! \brief Callback function to perform the actual recreation of a subscription */ -static int subscription_persistence_recreate(void *obj, void *arg, int flags) +/*! Persistent subscription recreation continuation under distributor serializer data */ +struct persistence_recreate_data { + struct subscription_persistence *persistence; + pjsip_rx_data *rdata; +}; + +/*! + * \internal + * \brief subscription_persistence_recreate continuation under distributor serializer. + * \since 13.10.0 + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int sub_persistence_recreate(void *obj) { - struct subscription_persistence *persistence = obj; - pj_pool_t *pool = arg; - pjsip_rx_data rdata = { { 0, }, }; - RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); + struct persistence_recreate_data *recreate_data = obj; + struct subscription_persistence *persistence = recreate_data->persistence; + pjsip_rx_data *rdata = recreate_data->rdata; + struct ast_sip_endpoint *endpoint; struct sip_subscription_tree *sub_tree; struct ast_sip_pubsub_body_generator *generator; - int resp; + struct ast_sip_subscription_handler *handler; char *resource; - size_t resource_size; pjsip_sip_uri *request_uri; + size_t resource_size; + int resp; struct resource_tree tree; pjsip_expires_hdr *expires_header; - struct ast_sip_subscription_handler *handler; - /* If this subscription has already expired remove it */ - if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) { - ast_sorcery_delete(ast_sip_get_sorcery(), persistence); - return 0; - } + request_uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri); + resource_size = pj_strlen(&request_uri->user) + 1; + resource = ast_alloca(resource_size); + ast_copy_pj_str(resource, &request_uri->user, resource_size); - endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", persistence->endpoint); - if (!endpoint) { - ast_log(LOG_WARNING, "A subscription for '%s' could not be recreated as the endpoint was not found\n", + handler = subscription_get_handler_from_rdata(rdata); + if (!handler || !handler->notifier) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n", persistence->endpoint); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); return 0; } - pj_pool_reset(pool); - rdata.tp_info.pool = pool; - - if (ast_sip_create_rdata(&rdata, persistence->packet, persistence->src_name, persistence->src_port, - persistence->transport_key, persistence->local_name, persistence->local_port)) { - ast_log(LOG_WARNING, "A subscription for '%s' could not be recreated as the message could not be parsed\n", + generator = subscription_get_generator_from_rdata(rdata, handler); + if (!generator) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Body generator not available.\n", persistence->endpoint); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); return 0; } - if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) { - ast_log(LOG_NOTICE, "Endpoint %s persisted a SIP response instead of a subscribe request. Unable to reload subscription.\n", - ast_sorcery_object_get_id(endpoint)); + ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data, + pubsub_module.id, MOD_DATA_PERSISTENCE, persistence); + + /* Getting the endpoint may take some time that can affect the expiration. */ + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + persistence->endpoint); + if (!endpoint) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n", + persistence->endpoint); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + ao2_ref(endpoint, -1); return 0; } - request_uri = pjsip_uri_get_uri(rdata.msg_info.msg->line.req.uri); - resource_size = pj_strlen(&request_uri->user) + 1; - resource = ast_alloca(resource_size); - ast_copy_pj_str(resource, &request_uri->user, resource_size); - /* Update the expiration header with the new expiration */ - expires_header = pjsip_msg_find_hdr(rdata.msg_info.msg, PJSIP_H_EXPIRES, rdata.msg_info.msg->hdr.next); + expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, + rdata->msg_info.msg->hdr.next); if (!expires_header) { - expires_header = pjsip_expires_hdr_create(pool, 0); + expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0); if (!expires_header) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not update expires header.\n", + persistence->endpoint); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + ao2_ref(endpoint, -1); return 0; } - pjsip_msg_add_hdr(rdata.msg_info.msg, (pjsip_hdr*)expires_header); + pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header); } expires_header->ivalue = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000); - - handler = subscription_get_handler_from_rdata(&rdata); - if (!handler || !handler->notifier) { - ast_sorcery_delete(ast_sip_get_sorcery(), persistence); - return 0; - } - - generator = subscription_get_generator_from_rdata(&rdata, handler); - if (!generator) { + if (expires_header->ivalue <= 0) { + /* The subscription expired since we started recreating the subscription. */ ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + ao2_ref(endpoint, -1); return 0; } - ast_sip_mod_data_set(rdata.tp_info.pool, rdata.endpt_info.mod_data, - pubsub_module.id, MOD_DATA_PERSISTENCE, persistence); - memset(&tree, 0, sizeof(tree)); resp = build_resource_tree(endpoint, handler, resource, &tree, - ast_sip_pubsub_has_eventlist_support(&rdata)); + ast_sip_pubsub_has_eventlist_support(rdata)); if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) { pj_status_t dlg_status; - sub_tree = create_subscription_tree(handler, endpoint, &rdata, resource, generator, &tree, &dlg_status); + sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, + &tree, &dlg_status); if (!sub_tree) { - ast_sorcery_delete(ast_sip_get_sorcery(), persistence); - ast_log(LOG_WARNING, "Failed to re-create subscription for %s\n", persistence->endpoint); - return 0; - } - sub_tree->persistence = ao2_bump(persistence); - subscription_persistence_update(sub_tree, &rdata); - if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ao2_bump(sub_tree))) { - pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); - ao2_ref(sub_tree, -1); + if (dlg_status != PJ_EEXISTS) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n", + persistence->endpoint); + ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + } + } else { + sub_tree->persistence = ao2_bump(persistence); + subscription_persistence_update(sub_tree, rdata); + if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, + ao2_bump(sub_tree))) { + /* Could not send initial subscribe NOTIFY */ + pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); + ao2_ref(sub_tree, -1); + } } } else { ast_sorcery_delete(ast_sip_get_sorcery(), persistence); } resource_tree_destroy(&tree); + ao2_ref(endpoint, -1); + + return 0; +} + +/*! \brief Callback function to perform the actual recreation of a subscription */ +static int subscription_persistence_recreate(void *obj, void *arg, int flags) +{ + struct subscription_persistence *persistence = obj; + pj_pool_t *pool = arg; + struct ast_taskprocessor *serializer; + pjsip_rx_data rdata; + struct persistence_recreate_data recreate_data; + + /* If this subscription has already expired remove it */ + if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) { + ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + return 0; + } + + memset(&rdata, 0, sizeof(rdata)); + pj_pool_reset(pool); + rdata.tp_info.pool = pool; + + if (ast_sip_create_rdata(&rdata, persistence->packet, persistence->src_name, persistence->src_port, + persistence->transport_key, persistence->local_name, persistence->local_port)) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n", + persistence->endpoint); + ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + return 0; + } + + if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) { + ast_log(LOG_NOTICE, "Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n", + persistence->endpoint); + ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + return 0; + } + + /* Continue the remainder in the distributor serializer */ + serializer = ast_sip_get_distributor_serializer(&rdata); + if (!serializer) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get distributor serializer.\n", + persistence->endpoint); + ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + return 0; + } + recreate_data.persistence = persistence; + recreate_data.rdata = &rdata; + if (ast_sip_push_task_synchronous(serializer, sub_persistence_recreate, &recreate_data)) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not continue under distributor serializer.\n", + persistence->endpoint); + ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + } + ast_taskprocessor_unreference(serializer); return 0; } From c966a035e03f1dba94fb24c4a7ed56133425c85a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 27 May 2016 17:31:52 -0500 Subject: [PATCH 0494/1578] res_pjsip_session: Use distributor serializer for incoming calls. We must continue using the serializer that the original INVITE came in on for the dialog. There may be retransmissions already enqueued in the original serializer that can result in reentrancy and message sequencing problems. Outgoing call legs create the pjsip/outsess/ serializers for their dialogs. ASTERISK-26088 Reported by: Richard Mudgett Change-Id: I24d7948749c582b8045d5389ba3f6588508adbbc --- include/asterisk/res_pjsip_session.h | 3 ++- res/res_pjsip_session.c | 30 ++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 55401e7c7a5..5ca2c99a529 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -408,9 +408,10 @@ struct ast_sip_channel_pvt *ast_sip_channel_pvt_alloc(void *pvt, struct ast_sip_ * \param endpoint The endpoint that this session communicates with * \param contact The contact associated with this session * \param inv_session The PJSIP INVITE session data + * \param rdata INVITE request received (NULL if for outgoing allocation) */ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, - struct ast_sip_contact *contact, pjsip_inv_session *inv); + struct ast_sip_contact *contact, pjsip_inv_session *inv, pjsip_rx_data *rdata); /*! * \brief Request and wait for the session serializer to be suspended. diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 59d759fdc9f..67cd09ddfd8 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1403,12 +1403,11 @@ struct ast_sip_channel_pvt *ast_sip_channel_pvt_alloc(void *pvt, struct ast_sip_ } struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, - struct ast_sip_contact *contact, pjsip_inv_session *inv_session) + struct ast_sip_contact *contact, pjsip_inv_session *inv_session, pjsip_rx_data *rdata) { RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup); struct ast_sip_session_supplement *iter; int dsp_features = 0; - char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; session = ao2_alloc(sizeof(*session), session_destructor); if (!session) { @@ -1429,11 +1428,24 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, /* fill session->media with available types */ ao2_callback(sdp_handlers, OBJ_NODATA, add_session_media, session); - /* Create name with seq number appended. */ - ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/session/%s", - ast_sorcery_object_get_id(endpoint)); + if (rdata) { + /* + * We must continue using the serializer that the original + * INVITE came in on for the dialog. There may be + * retransmissions already enqueued in the original + * serializer that can result in reentrancy and message + * sequencing problems. + */ + session->serializer = ast_sip_get_distributor_serializer(rdata); + } else { + char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; - session->serializer = ast_sip_create_serializer(tps_name); + /* Create name with seq number appended. */ + ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outsess/%s", + ast_sorcery_object_get_id(endpoint)); + + session->serializer = ast_sip_create_serializer(tps_name); + } if (!session->serializer) { return NULL; } @@ -1731,7 +1743,9 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint timer.sess_expires = endpoint->extensions.timer.sess_expires; pjsip_timer_init_session(inv_session, &timer); - if (!(session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact, inv_session))) { + session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact, + inv_session, NULL); + if (!session) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); return NULL; } @@ -2142,7 +2156,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) return; } - session = ast_sip_session_alloc(endpoint, NULL, inv_session); + session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata); if (!session) { if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); From 2cd67d5b07d28891ea7c86aece702a4d6e436afc Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 2 Jun 2016 16:08:19 -0500 Subject: [PATCH 0495/1578] taskprocessors: Implement high/low water mark alerts. When taskprocessors get backed up, there is a good chance that we are being overloaded and need to defer adding new work to the system. * Implemented a high/low water alert mechanism for modules to check if the system is being overloaded and take appropriate action. When a taskprocessor is created it has default congestion levels set. A taskprocessor can later have those congestion levels altered for specific needs if stress testing shows that the taskprocessor is a symptom of overloading or needs to handle bursty activity without triggering an overload alert. * Add CLI "core show taskprocessor" low/high water columns. * Fixed __allocate_taskprocessor() to not use RAII_VAR(). RAII_VAR() was never a good thing to use when creating a taskprocessor because of the nature of how its references needed to be cleaned up on a partial creation. * Made res_pjsip's distributor check if the taskprocessor overload alert is active before placing a message representing brand new work onto a distributor serializer. ASTERISK-26088 Reported by: Richard Mudgett Change-Id: I182f1be603529cd665958661c4c05ff9901825fa --- include/asterisk/taskprocessor.h | 23 ++++ main/taskprocessor.c | 172 ++++++++++++++++++++++-------- res/res_pjsip/pjsip_distributor.c | 38 ++++--- 3 files changed, 176 insertions(+), 57 deletions(-) diff --git a/include/asterisk/taskprocessor.h b/include/asterisk/taskprocessor.h index af3ce747f63..e51122269d4 100644 --- a/include/asterisk/taskprocessor.h +++ b/include/asterisk/taskprocessor.h @@ -59,6 +59,7 @@ struct ast_taskprocessor; /*! \brief Suggested maximum taskprocessor name length (less null terminator). */ #define AST_TASKPROCESSOR_MAX_NAME 45 +/*! Default taskprocessor high water level alert trigger */ #define AST_TASKPROCESSOR_HIGH_WATER_LEVEL 500 /*! @@ -297,4 +298,26 @@ const char *ast_taskprocessor_name(struct ast_taskprocessor *tps); */ long ast_taskprocessor_size(struct ast_taskprocessor *tps); +/*! + * \brief Get the current taskprocessor high water alert count. + * \since 13.10.0 + * + * \retval 0 if no taskprocessors are in high water alert. + * \retval non-zero if some task processors are in high water alert. + */ +unsigned int ast_taskprocessor_alert_get(void); + +/*! + * \brief Set the high and low alert water marks of the given taskprocessor queue. + * \since 13.10.0 + * + * \param tps Taskprocessor to update queue water marks. + * \param low_water New queue low water mark. (-1 to set as 90% of high_water) + * \param high_water New queue high water mark. + * + * \retval 0 on success. + * \retval -1 on error (water marks not changed). + */ +int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water); + #endif /* __AST_TASKPROCESSOR_H__ */ diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 5b8ff08f10a..2f0124045bc 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -76,6 +76,10 @@ struct ast_taskprocessor { void *local_data; /*! \brief Taskprocessor current queue size */ long tps_queue_size; + /*! \brief Taskprocessor low water clear alert level */ + long tps_queue_low; + /*! \brief Taskprocessor high water alert trigger level */ + long tps_queue_high; /*! \brief Taskprocessor queue */ AST_LIST_HEAD_NOLOCK(tps_queue, tps_task) tps_queue; struct ast_taskprocessor_listener *listener; @@ -85,6 +89,8 @@ struct ast_taskprocessor { unsigned int executing:1; /*! Indicates that a high water warning has been issued on this task processor */ unsigned int high_water_warned:1; + /*! Indicates that a high water alert is active on this taskprocessor */ + unsigned int high_water_alert:1; }; /*! @@ -121,15 +127,9 @@ static int tps_hash_cb(const void *obj, const int flags); /*! \brief The astobj2 compare callback for taskprocessors */ static int tps_cmp_cb(void *obj, void *arg, int flags); -/*! \brief Destroy the taskprocessor when its refcount reaches zero */ -static void tps_taskprocessor_destroy(void *tps); - /*! \brief CLI taskprocessor ping <blah> handler function */ static int tps_ping_handler(void *datap); -/*! \brief Remove the front task off the taskprocessor queue */ -static struct tps_task *tps_taskprocessor_pop(struct ast_taskprocessor *tps); - static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); @@ -472,8 +472,8 @@ static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_arg struct ao2_container *sorted_tps; struct ast_taskprocessor *tps; struct ao2_iterator iter; -#define FMT_HEADERS "%-45s %10s %10s %10s\n" -#define FMT_FIELDS "%-45s %10lu %10lu %10lu\n" +#define FMT_HEADERS "%-45s %10s %10s %10s %10s %10s\n" +#define FMT_FIELDS "%-45s %10lu %10lu %10lu %10lu %10lu\n" switch (cmd) { case CLI_INIT: @@ -498,7 +498,7 @@ static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_arg return CLI_FAILURE; } - ast_cli(a->fd, "\n" FMT_HEADERS, "Processor", "Processed", "In Queue", "Max Depth"); + ast_cli(a->fd, "\n" FMT_HEADERS, "Processor", "Processed", "In Queue", "Max Depth", "Low water", "High water"); tcount = 0; iter = ao2_iterator_init(sorted_tps, AO2_ITERATOR_UNLINK); while ((tps = ao2_iterator_next(&iter))) { @@ -511,7 +511,8 @@ static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_arg maxqsize = 0; processed = 0; } - ast_cli(a->fd, FMT_FIELDS, name, processed, qsize, maxqsize); + ast_cli(a->fd, FMT_FIELDS, name, processed, qsize, maxqsize, + tps->tps_queue_low, tps->tps_queue_high); ast_taskprocessor_unreference(tps); ++tcount; } @@ -539,28 +540,106 @@ static int tps_cmp_cb(void *obj, void *arg, int flags) return !strcasecmp(lhs->name, rhsname) ? CMP_MATCH | CMP_STOP : 0; } +/*! Count of the number of taskprocessors in high water alert. */ +static unsigned int tps_alert_count; + +/*! Access protection for tps_alert_count */ +AST_RWLOCK_DEFINE_STATIC(tps_alert_lock); + +/*! + * \internal + * \brief Add a delta to tps_alert_count with protection. + * \since 13.10.0 + * + * \param tps Taskprocessor updating queue water mark alert trigger. + * \param delta The amount to add to tps_alert_count. + * + * \return Nothing + */ +static void tps_alert_add(struct ast_taskprocessor *tps, int delta) +{ + unsigned int old; + + ast_rwlock_wrlock(&tps_alert_lock); + old = tps_alert_count; + tps_alert_count += delta; + if (DEBUG_ATLEAST(3) + /* and tps_alert_count becomes zero or non-zero */ + && !old != !tps_alert_count) { + ast_log(LOG_DEBUG, "Taskprocessor '%s' %s the high water alert.\n", + tps->name, tps_alert_count ? "triggered" : "cleared"); + } + ast_rwlock_unlock(&tps_alert_lock); +} + +unsigned int ast_taskprocessor_alert_get(void) +{ + unsigned int count; + + ast_rwlock_rdlock(&tps_alert_lock); + count = tps_alert_count; + ast_rwlock_unlock(&tps_alert_lock); + + return count; +} + +int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water) +{ + if (!tps || high_water < 0 || high_water < low_water) { + return -1; + } + + if (low_water < 0) { + /* Set low water level to 90% of high water level */ + low_water = (high_water * 9) / 10; + } + + ao2_lock(tps); + + tps->tps_queue_low = low_water; + tps->tps_queue_high = high_water; + + if (tps->high_water_alert) { + if (!tps->tps_queue_size || tps->tps_queue_size < low_water) { + /* Update water mark alert immediately */ + tps->high_water_alert = 0; + tps_alert_add(tps, -1); + } + } else { + if (high_water <= tps->tps_queue_size) { + /* Update water mark alert immediately */ + tps->high_water_alert = 1; + tps_alert_add(tps, +1); + } + } + + ao2_unlock(tps); + + return 0; +} + /* destroy the taskprocessor */ -static void tps_taskprocessor_destroy(void *tps) +static void tps_taskprocessor_dtor(void *tps) { struct ast_taskprocessor *t = tps; struct tps_task *task; - if (!tps) { - ast_log(LOG_ERROR, "missing taskprocessor\n"); - return; + while ((task = AST_LIST_REMOVE_HEAD(&t->tps_queue, list))) { + tps_task_free(task); } - ast_debug(1, "destroying taskprocessor '%s'\n", t->name); - /* free it */ + t->tps_queue_size = 0; + + if (t->high_water_alert) { + t->high_water_alert = 0; + tps_alert_add(t, -1); + } + ast_free(t->stats); t->stats = NULL; ast_free((char *) t->name); - if (t->listener) { - ao2_ref(t->listener, -1); - t->listener = NULL; - } - while ((task = AST_LIST_REMOVE_HEAD(&t->tps_queue, list))) { - tps_task_free(task); - } + t->name = NULL; + ao2_cleanup(t->listener); + t->listener = NULL; } /* pop the front task and return it */ @@ -569,7 +648,11 @@ static struct tps_task *tps_taskprocessor_pop(struct ast_taskprocessor *tps) struct tps_task *task; if ((task = AST_LIST_REMOVE_HEAD(&tps->tps_queue, list))) { - tps->tps_queue_size--; + --tps->tps_queue_size; + if (tps->high_water_alert && tps->tps_queue_size <= tps->tps_queue_low) { + tps->high_water_alert = 0; + tps_alert_add(tps, -1); + } } return task; } @@ -648,19 +731,22 @@ static void *default_listener_pvt_alloc(void) static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, struct ast_taskprocessor_listener *listener) { - RAII_VAR(struct ast_taskprocessor *, p, - ao2_alloc(sizeof(*p), tps_taskprocessor_destroy), ao2_cleanup); + struct ast_taskprocessor *p; + p = ao2_alloc(sizeof(*p), tps_taskprocessor_dtor); if (!p) { ast_log(LOG_WARNING, "failed to create taskprocessor '%s'\n", name); return NULL; } - if (!(p->stats = ast_calloc(1, sizeof(*p->stats)))) { - ast_log(LOG_WARNING, "failed to create taskprocessor stats for '%s'\n", name); - return NULL; - } - if (!(p->name = ast_strdup(name))) { + /* Set default congestion water level alert triggers. */ + p->tps_queue_low = (AST_TASKPROCESSOR_HIGH_WATER_LEVEL * 9) / 10; + p->tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL; + + p->stats = ast_calloc(1, sizeof(*p->stats)); + p->name = ast_strdup(name); + if (!p->stats || !p->name) { + ao2_ref(p, -1); return NULL; } @@ -675,22 +761,18 @@ static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, stru if (!(ao2_link(tps_singletons, p))) { ast_log(LOG_ERROR, "Failed to add taskprocessor '%s' to container\n", p->name); listener->tps = NULL; - ao2_ref(p, -1); + ao2_ref(p, -2); return NULL; } if (p->listener->callbacks->start(p->listener)) { - ast_log(LOG_ERROR, "Unable to start taskprocessor listener for taskprocessor %s\n", p->name); + ast_log(LOG_ERROR, "Unable to start taskprocessor listener for taskprocessor %s\n", + p->name); ast_taskprocessor_unreference(p); return NULL; } - /* RAII_VAR will decrement the refcount at the end of the function. - * Since we want to pass back a reference to p, we bump the refcount - */ - ao2_ref(p, +1); return p; - } /* Provide a reference to a taskprocessor. Create the taskprocessor if necessary, but don't @@ -799,10 +881,16 @@ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t) AST_LIST_INSERT_TAIL(&tps->tps_queue, t, list); previous_size = tps->tps_queue_size++; - if (previous_size >= AST_TASKPROCESSOR_HIGH_WATER_LEVEL && !tps->high_water_warned) { - ast_log(LOG_WARNING, "The '%s' task processor queue reached %d scheduled tasks.\n", - tps->name, previous_size); - tps->high_water_warned = 1; + if (previous_size >= tps->tps_queue_high) { + if (!tps->high_water_warned) { + tps->high_water_warned = 1; + ast_log(LOG_WARNING, "The '%s' task processor queue reached %d scheduled tasks.\n", + tps->name, previous_size); + } + if (!tps->high_water_alert) { + tps->high_water_alert = 1; + tps_alert_add(tps, +1); + } } /* The currently executing task counts as still in queue */ diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 75ae461cd0a..715ecb26319 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -369,8 +369,6 @@ static pjsip_module endpoint_mod = { .on_rx_request = endpoint_lookup, }; -#define SIP_MAX_QUEUE (AST_TASKPROCESSOR_HIGH_WATER_LEVEL * 3) - static pj_bool_t distributor(pjsip_rx_data *rdata) { pjsip_dialog *dlg; @@ -408,6 +406,13 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) pjsip_rx_data_get_info(rdata)); serializer = find_request_serializer(rdata); if (!serializer) { + if (ast_taskprocessor_alert_get()) { + /* We're overloaded, ignore the unmatched response. */ + ast_debug(3, "Taskprocessor overload alert: Ignoring unmatched '%s'.\n", + pjsip_rx_data_get_info(rdata)); + return PJ_TRUE; + } + /* * Pick a serializer for the unmatched response. Maybe * the stack can figure out what it is for, or we really @@ -422,6 +427,21 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL); return PJ_TRUE; } else { + if (ast_taskprocessor_alert_get()) { + /* + * When taskprocessors get backed up, there is a good chance that + * we are being overloaded and need to defer adding new work to + * the system. To defer the work we will ignore the request and + * rely on the peer's transport layer to retransmit the message. + * We usually work off the overload within a few seconds. The + * alternative is to send back a 503 response to these requests + * and be done with it. + */ + ast_debug(3, "Taskprocessor overload alert: Ignoring '%s'.\n", + pjsip_rx_data_get_info(rdata)); + return PJ_TRUE; + } + /* Pick a serializer for the out-of-dialog request. */ serializer = ast_sip_get_distributor_serializer(rdata); } @@ -432,21 +452,9 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) clone->endpt_info.mod_data[endpoint_mod.id] = ao2_bump(dist->endpoint); } - if (ast_sip_threadpool_queue_size() > SIP_MAX_QUEUE) { - /* When the threadpool is backed up this much, there is a good chance that we have encountered - * some sort of terrible condition and don't need to be adding more work to the threadpool. - * It's in our best interest to send back a 503 response and be done with it. - */ - if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL); - } + if (ast_sip_push_task(serializer, distribute, clone)) { ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]); pjsip_rx_data_free_cloned(clone); - } else { - if (ast_sip_push_task(serializer, distribute, clone)) { - ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]); - pjsip_rx_data_free_cloned(clone); - } } ast_taskprocessor_unreference(serializer); From 4879cd875c932817c8259934814dd18cf15f5a1c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 2 Jun 2016 18:19:13 -0500 Subject: [PATCH 0496/1578] sorcery: Add setting object type congestion levels. Sorcery creates taskprocessors for object types to process object observer callbacks. An API call is needed to be able to set the congestion levels of these taskprocessors for selected object types. * Updated PJSIP's contact and contact_status sorcery object type observer default congestion levels based upon stress testing. Increased the congestion levels to reduce the potential for bursty register/unregister and subscribe/unsubscribe activity from triggering the taskprocessor overload alert. ASTERISK-26088 Reported by: Richard Mudgett Change-Id: I4542e83b556f0714009bfeff89505c801f1218c6 --- include/asterisk/sorcery.h | 14 ++++++++++++++ main/sorcery.c | 14 ++++++++++++++ res/res_pjsip/location.c | 3 +++ res/res_pjsip/pjsip_options.c | 3 +++ 4 files changed, 34 insertions(+) diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h index 42ecc133ff5..23219ec41cc 100644 --- a/include/asterisk/sorcery.h +++ b/include/asterisk/sorcery.h @@ -694,6 +694,20 @@ int __ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, #define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply) \ __ast_sorcery_object_register((sorcery), (type), 1, 1, (alloc), (transform), (apply)) +/*! + * \brief Set the high and low alert water marks of the sorcery object type. + * \since 13.10.0 + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object + * \param low_water New queue low water mark. (-1 to set as 90% of high_water) + * \param high_water New queue high water mark. + * + * \retval 0 on success. + * \retval -1 on error (water marks not changed). + */ +int ast_sorcery_object_set_congestion_levels(struct ast_sorcery *sorcery, const char *type, long low_water, long high_water); + /*! * \brief Set the copy handler for an object type * diff --git a/main/sorcery.c b/main/sorcery.c index ec340e8273c..6a7b54bbf31 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -1164,6 +1164,20 @@ int __ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, return 0; } +int ast_sorcery_object_set_congestion_levels(struct ast_sorcery *sorcery, const char *type, long low_water, long high_water) +{ + struct ast_sorcery_object_type *object_type; + int res = -1; + + object_type = ao2_find(sorcery->types, type, OBJ_SEARCH_KEY); + if (object_type) { + res = ast_taskprocessor_alert_set_levels(object_type->serializer, + low_water, high_water); + ao2_ref(object_type, -1); + } + return res; +} + void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy) { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 43e6ea40f43..8f8c030c35f 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -25,6 +25,7 @@ #include "asterisk/astobj2.h" #include "asterisk/paths.h" #include "asterisk/sorcery.h" +#include "asterisk/taskprocessor.h" #include "include/res_pjsip_private.h" #include "asterisk/res_pjsip_cli.h" #include "asterisk/statsd.h" @@ -1114,6 +1115,8 @@ int ast_sip_initialize_sorcery_location(void) ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size); ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar"); + ast_sorcery_object_set_congestion_levels(sorcery, "contact", -1, + 3 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL); ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor"); if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, contact_apply_handler) || diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 1114336bd07..381de37545c 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -31,6 +31,7 @@ #include "asterisk/test.h" #include "asterisk/statsd.h" #include "include/res_pjsip_private.h" +#include "asterisk/taskprocessor.h" #define DEFAULT_LANGUAGE "en" #define DEFAULT_ENCODING "text/plain" @@ -1004,6 +1005,8 @@ int ast_sip_initialize_sorcery_qualify(void) /* initialize sorcery ast_sip_contact_status resource */ ast_sorcery_apply_default(sorcery, CONTACT_STATUS, "memory", NULL); + ast_sorcery_object_set_congestion_levels(sorcery, CONTACT_STATUS, -1, + 3 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL); if (ast_sorcery_internal_object_register(sorcery, CONTACT_STATUS, contact_status_alloc, NULL, NULL)) { From dcfef53ee2339d09f839aa4e333419b80b309d8a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 3 Jun 2016 11:35:49 -0500 Subject: [PATCH 0497/1578] stasis: Add setting subscription congestion levels. Stasis subscriptions and message routers create taskprocessors to process the event messages. API calls are needed to be able to set the congestion levels of these taskprocessors for selected subscriptions and message routers. * Updated CDR, CEL, and manager's stasis subscription congestion levels based upon stress testing. Increased the congestion levels to reduce the potential for bursty call setup/teardown activity from triggering the taskprocessor overload alert. CDRs in particular need an extra high congestion level because they can take awhile to process the stasis messages. ASTERISK-26088 Reported by: Richard Mudgett Change-Id: Id0a716394b4eee746dd158acc63d703902450244 --- include/asterisk/stasis.h | 14 ++++++++++++++ include/asterisk/stasis_message_router.h | 14 ++++++++++++++ main/cdr.c | 3 +++ main/cel.c | 3 +++ main/manager.c | 3 +++ main/stasis.c | 12 ++++++++++++ main/stasis_message_router.c | 12 ++++++++++++ 7 files changed, 61 insertions(+) diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h index 14ab7d93b24..62ed1ed1a00 100644 --- a/include/asterisk/stasis.h +++ b/include/asterisk/stasis.h @@ -590,6 +590,20 @@ struct stasis_subscription *stasis_subscribe_pool(struct stasis_topic *topic, struct stasis_subscription *stasis_unsubscribe( struct stasis_subscription *subscription); +/*! + * \brief Set the high and low alert water marks of the stasis subscription. + * \since 13.10.0 + * + * \param subscription Pointer to a stasis subscription + * \param low_water New queue low water mark. (-1 to set as 90% of high_water) + * \param high_water New queue high water mark. + * + * \retval 0 on success. + * \retval -1 on error (water marks not changed). + */ +int stasis_subscription_set_congestion_limits(struct stasis_subscription *subscription, + long low_water, long high_water); + /*! * \brief Block until the last message is processed on a subscription. * diff --git a/include/asterisk/stasis_message_router.h b/include/asterisk/stasis_message_router.h index 89657a5ee5e..50270a788b4 100644 --- a/include/asterisk/stasis_message_router.h +++ b/include/asterisk/stasis_message_router.h @@ -126,6 +126,20 @@ int stasis_message_router_is_done(struct stasis_message_router *router); void stasis_message_router_publish_sync(struct stasis_message_router *router, struct stasis_message *message); +/*! + * \brief Set the high and low alert water marks of the stasis message router. + * \since 13.10.0 + * + * \param router Pointer to a stasis message router + * \param low_water New queue low water mark. (-1 to set as 90% of high_water) + * \param high_water New queue high water mark. + * + * \retval 0 on success. + * \retval -1 on error (water marks not changed). + */ +int stasis_message_router_set_congestion_limits(struct stasis_message_router *router, + long low_water, long high_water); + /*! * \brief Add a route to a message router. * diff --git a/main/cdr.c b/main/cdr.c index b43e3610c07..3ddf55b6bf0 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -71,6 +71,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_bridges.h" #include "asterisk/stasis_message_router.h" #include "asterisk/astobj2.h" +#include "asterisk/taskprocessor.h" /*** DOCUMENTATION @@ -4221,6 +4222,8 @@ int ast_cdr_engine_init(void) if (!stasis_router) { return -1; } + stasis_message_router_set_congestion_limits(stasis_router, -1, + 10 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL); if (STASIS_MESSAGE_TYPE_INIT(cdr_sync_message_type)) { return -1; diff --git a/main/cel.c b/main/cel.c index a0d0ad7235e..887a9e6a56a 100644 --- a/main/cel.c +++ b/main/cel.c @@ -59,6 +59,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/parking.h" #include "asterisk/pickup.h" #include "asterisk/core_local.h" +#include "asterisk/taskprocessor.h" /*** DOCUMENTATION @@ -1575,6 +1576,8 @@ static int create_routes(void) if (!cel_state_router) { return -1; } + stasis_message_router_set_congestion_limits(cel_state_router, -1, + 6 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL); ret |= stasis_message_router_add(cel_state_router, stasis_cache_update_type(), diff --git a/main/manager.c b/main/manager.c index 94415b7a0d8..029da70f730 100644 --- a/main/manager.c +++ b/main/manager.c @@ -100,6 +100,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/rtp_engine.h" #include "asterisk/format_cache.h" #include "asterisk/translate.h" +#include "asterisk/taskprocessor.h" /*** DOCUMENTATION @@ -8692,6 +8693,8 @@ static int manager_subscriptions_init(void) if (!stasis_router) { return -1; } + stasis_message_router_set_congestion_limits(stasis_router, -1, + 6 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL); res |= stasis_message_router_set_default(stasis_router, manager_default_msg_cb, NULL); diff --git a/main/stasis.c b/main/stasis.c index 9fe3a2aae59..91ad94e7664 100644 --- a/main/stasis.c +++ b/main/stasis.c @@ -564,6 +564,18 @@ struct stasis_subscription *stasis_unsubscribe(struct stasis_subscription *sub) return NULL; } +int stasis_subscription_set_congestion_limits(struct stasis_subscription *subscription, + long low_water, long high_water) +{ + int res = -1; + + if (subscription) { + res = ast_taskprocessor_alert_set_levels(subscription->mailbox, + low_water, high_water); + } + return res; +} + void stasis_subscription_join(struct stasis_subscription *subscription) { if (subscription) { diff --git a/main/stasis_message_router.c b/main/stasis_message_router.c index f60180d68bb..85034bcf958 100644 --- a/main/stasis_message_router.c +++ b/main/stasis_message_router.c @@ -289,6 +289,18 @@ void stasis_message_router_publish_sync(struct stasis_message_router *router, ao2_cleanup(router); } +int stasis_message_router_set_congestion_limits(struct stasis_message_router *router, + long low_water, long high_water) +{ + int res = -1; + + if (router) { + res = stasis_subscription_set_congestion_limits(router->subscription, + low_water, high_water); + } + return res; +} + int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data) From 04ec9c745e6fe97e8047f7b5c85dce3d2c239c7d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 3 Jun 2016 22:44:46 -0500 Subject: [PATCH 0498/1578] res_pjsip_registrar.c: Eliminate rx REGISTER request race condition. This patch fixes a race condition processing received REGISTER requests and their retransmissions caused by REGISTER requests being processed by two threads. The "sip_transaction Unable to register REGISTER transaction (key exists)" message is a notable symptom of this issue. This issue was more likely to happen before the pjsip/distributor serializers were created. Instead of steps one and two below placing the REGISTER messages into the same pjsip/distributor they were placed in random pjsip/default serializers. 1) REGISTER requests come in and get placed on the pjsip/distributor serializer. 2) Before the first request is processed a retransmission comes in and is placed on the same pjsip/distributor serializer. 3) The first request goes up the pjsip stack and is then shunted off to the pjsip/aor/ serializer. 4) Before the first request is completed processing in the pjsip/aor/ serializer, the second request goes up the pjsip stack and is also shunted off to the pjsip/aor/ serializer. 5) The first request completes processing and sends out its response. 6) The second request completes processing and tries to send out its response but pjlib complains that the REGISTER transaction key already exists. 7) Sadness ensues. * The race is eliminated by removing the pjsip/aor/ serializer and continuing the processing in the pjsip/distributor serializer. Now any retransmissions queued in the pjsip/distributor serializer will be processed after the first message is completely processed. ASTERISK-26088 #close Reported by: Richard Mudgett Change-Id: I842d714346088bf717ea27437f1dd85bff0bab5a --- res/res_pjsip_registrar.c | 339 ++++++++++---------------------------- 1 file changed, 90 insertions(+), 249 deletions(-) diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 0e14ab7868f..a39dac676ea 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -231,155 +231,11 @@ static void registrar_add_date_header(pjsip_tx_data *tdata) ast_sip_add_header(tdata, "Date", date); } -#define SERIALIZER_BUCKETS 59 - -static struct ao2_container *serializers; - -/*! \brief Serializer with associated aor key */ -struct serializer { - /* Serializer to distribute tasks to */ - struct ast_taskprocessor *serializer; - /* The name of the aor to associate with the serializer */ - char aor_name[0]; -}; - -static void serializer_destroy(void *obj) -{ - struct serializer *ser = obj; - - ast_taskprocessor_unreference(ser->serializer); -} - -static struct serializer *serializer_create(const char *aor_name) -{ - char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; - size_t size = strlen(aor_name) + 1; - struct serializer *ser = ao2_alloc( - sizeof(*ser) + size, serializer_destroy); - - if (!ser) { - return NULL; - } - - /* Create name with seq number appended. */ - ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/aor/%s", - aor_name); - - if (!(ser->serializer = ast_sip_create_serializer(tps_name))) { - ao2_ref(ser, -1); - return NULL; - } - - strcpy(ser->aor_name, aor_name); - return ser; -} - -static struct serializer *serializer_find_or_create(const char *aor_name) -{ - struct serializer *ser = ao2_find(serializers, aor_name, OBJ_SEARCH_KEY); - - if (ser) { - return ser; - } - - if (!(ser = serializer_create(aor_name))) { - return NULL; - } - - ao2_link(serializers, ser); - return ser; -} - -static int serializer_hash(const void *obj, const int flags) -{ - const struct serializer *object; - const char *key; - - switch (flags & OBJ_SEARCH_MASK) { - case OBJ_SEARCH_KEY: - key = obj; - return ast_str_hash(key); - case OBJ_SEARCH_OBJECT: - object = obj; - return ast_str_hash(object->aor_name); - default: - /* Hash can only work on something with a full key. */ - ast_assert(0); - return 0; - } -} - -static int serializer_cmp(void *obj_left, void *obj_right, int flags) -{ - const struct serializer *object_left = obj_left; - const struct serializer *object_right = obj_right; - const char *right_key = obj_right; - int cmp; - - switch (flags & OBJ_SEARCH_MASK) { - case OBJ_SEARCH_OBJECT: - right_key = object_right->aor_name; - /* Fall through */ - case OBJ_SEARCH_KEY: - cmp = strcmp(object_left->aor_name, right_key); - break; - case OBJ_SEARCH_PARTIAL_KEY: - /* - * We could also use a partial key struct containing a length - * so strlen() does not get called for every comparison instead. - */ - cmp = strncmp(object_left->aor_name, right_key, strlen(right_key)); - break; - default: - cmp = 0; - break; - } - - return cmp ? 0 : CMP_MATCH; -} - -struct rx_task_data { - pjsip_rx_data *rdata; - struct ast_sip_endpoint *endpoint; - struct ast_sip_aor *aor; -}; - -static void rx_task_data_destroy(void *obj) -{ - struct rx_task_data *task_data = obj; - - pjsip_rx_data_free_cloned(task_data->rdata); - ao2_cleanup(task_data->endpoint); - ao2_cleanup(task_data->aor); -} - -static struct rx_task_data *rx_task_data_create(pjsip_rx_data *rdata, - struct ast_sip_endpoint *endpoint, - struct ast_sip_aor *aor) -{ - struct rx_task_data *task_data = ao2_alloc( - sizeof(*task_data), rx_task_data_destroy); - - if (!task_data) { - return NULL; - } - - pjsip_rx_data_clone(rdata, 0, &task_data->rdata); - - task_data->endpoint = endpoint; - ao2_ref(task_data->endpoint, +1); - - task_data->aor = aor; - ao2_ref(task_data->aor, +1); - - return task_data; -} - static const pj_str_t path_hdr_name = { "Path", 4 }; -static int build_path_data(struct rx_task_data *task_data, struct ast_str **path_str) +static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str) { - pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &path_hdr_name, NULL); + pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL); if (!path_hdr) { return 0; @@ -392,24 +248,24 @@ static int build_path_data(struct rx_task_data *task_data, struct ast_str **path ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr); - while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) { + while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) { ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr); } return 0; } -static int registrar_validate_path(struct rx_task_data *task_data, struct ast_str **path_str) +static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str) { const pj_str_t path_supported_name = { "path", 4 }; pjsip_supported_hdr *supported_hdr; int i; - if (!task_data->aor->support_path) { + if (!aor->support_path) { return 0; } - if (build_path_data(task_data, path_str)) { + if (build_path_data(rdata, path_str)) { return -1; } @@ -417,7 +273,7 @@ static int registrar_validate_path(struct rx_task_data *task_data, struct ast_st return 0; } - supported_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL); + supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL); if (!supported_hdr) { return -1; } @@ -433,8 +289,11 @@ static int registrar_validate_path(struct rx_task_data *task_data, struct ast_st return -1; } -static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *contacts, - const char *aor_name) +static int register_aor_core(pjsip_rx_data *rdata, + struct ast_sip_endpoint *endpoint, + struct ast_sip_aor *aor, + const char *aor_name, + struct ao2_container *contacts) { static const pj_str_t USER_AGENT = { "User-Agent", 10 }; @@ -458,38 +317,38 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co /* So we don't count static contacts against max_contacts we prune them out from the container */ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL); - if (registrar_validate_contacts(task_data->rdata, contacts, task_data->aor, &added, &updated, &deleted)) { + if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) { /* The provided Contact headers do not conform to the specification */ - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 400, NULL, NULL, NULL); - ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_invalid_contacts_provided"); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL); + ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided"); ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n", - ast_sorcery_object_get_id(task_data->endpoint)); + ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } - if (registrar_validate_path(task_data, &path_str)) { + if (registrar_validate_path(rdata, aor, &path_str)) { /* Ensure that intervening proxies did not make invalid modifications to the request */ - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 420, NULL, NULL, NULL); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 420, NULL, NULL, NULL); ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n", - ast_sorcery_object_get_id(task_data->endpoint)); + ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } - if ((MAX(added - deleted, 0) + (!task_data->aor->remove_existing ? ao2_container_count(contacts) : 0)) > task_data->aor->max_contacts) { + if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) { /* Enforce the maximum number of contacts */ - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 403, NULL, NULL, NULL); - ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_attempt_exceeds_maximum_configured_contacts"); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); + ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts"); ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n", - ast_sorcery_object_get_id(task_data->endpoint), ast_sorcery_object_get_id(task_data->aor), task_data->aor->max_contacts); + ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts); return PJ_TRUE; } if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) { - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 500, NULL, NULL, NULL); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } - user_agent_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &USER_AGENT, NULL); + user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL); if (user_agent_hdr) { alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; user_agent = ast_alloca(alloc_size); @@ -497,10 +356,10 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co } /* Find the first Via header */ - via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_VIA, NULL); + via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL); if (via_hdr) { /* Find the last Via header */ - while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, + while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, via_hdr->next)) != NULL) { via_hdr_last = via_hdr; } @@ -510,7 +369,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co via_port=via_hdr_last->sent_by.port; } - call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL); + call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL); if (call_id_hdr) { alloc_size = pj_strlen(&call_id_hdr->id) + 1; call_id = ast_alloca(alloc_size); @@ -518,7 +377,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co } /* Iterate each provided Contact header and add, update, or delete */ - while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { + while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { int expiration; char contact_uri[pjsip_max_url_size]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); @@ -534,7 +393,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co continue; } - expiration = registrar_get_expiration(task_data->aor, contact_hdr, task_data->rdata); + expiration = registrar_get_expiration(aor, contact_hdr, rdata); details.uri = pjsip_uri_get_uri(contact_hdr->uri); pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)); @@ -546,9 +405,9 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co continue; } - if (ast_sip_location_add_contact_nolock(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), + if (ast_sip_location_add_contact_nolock(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, - user_agent, via_addr, via_port, call_id, task_data->endpoint)) { + user_agent, via_addr, via_port, call_id, endpoint)) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", contact_uri, aor_name); continue; @@ -576,8 +435,8 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co } contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); - contact_update->qualify_frequency = task_data->aor->qualify_frequency; - contact_update->authenticate_qualify = task_data->aor->authenticate_qualify; + contact_update->qualify_frequency = aor->qualify_frequency; + contact_update->authenticate_qualify = aor->authenticate_qualify; if (path_str) { ast_string_field_set(contact_update, path, ast_str_buffer(path_str)); } @@ -625,16 +484,16 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER * do so */ - if (task_data->aor->remove_existing) { + if (aor->remove_existing) { ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL); } /* Re-retrieve contacts. Caller will clean up the original container. */ - contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor); + contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); response_contact = ao2_callback(contacts, 0, NULL, NULL); /* Send a response containing all of the contacts (including static) that are present on this AOR */ - if (ast_sip_create_response(task_data->rdata, 200, response_contact, &tdata) != PJ_SUCCESS) { + if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) { ao2_cleanup(response_contact); ao2_cleanup(contacts); return PJ_TRUE; @@ -647,44 +506,42 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co ao2_callback(contacts, 0, registrar_add_contact, tdata); ao2_cleanup(contacts); - if ((expires_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) { - expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(task_data->aor, NULL, task_data->rdata)); + if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) { + expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata)); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr); } - ast_sip_send_stateful_response(task_data->rdata, tdata, task_data->endpoint); + ast_sip_send_stateful_response(rdata, tdata, endpoint); return PJ_TRUE; } -static int rx_task(void *data) +static int register_aor(pjsip_rx_data *rdata, + struct ast_sip_endpoint *endpoint, + struct ast_sip_aor *aor, + const char *aor_name) { int res; - struct rx_task_data *task_data = data; struct ao2_container *contacts = NULL; struct ast_named_lock *lock; - const char *aor_name = ast_sorcery_object_get_id(task_data->aor); lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", aor_name); if (!lock) { - ao2_cleanup(task_data); return PJ_TRUE; } ao2_wrlock(lock); - contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor); + contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); if (!contacts) { ao2_unlock(lock); ast_named_lock_put(lock); - ao2_cleanup(task_data); return PJ_TRUE; } - res = rx_task_core(task_data, contacts, aor_name); + res = register_aor_core(rdata, endpoint, aor, aor_name, contacts); ao2_cleanup(contacts); ao2_unlock(lock); ast_named_lock_put(lock); - ao2_cleanup(task_data); return res; } @@ -748,44 +605,20 @@ static char *find_aor_name(const char *username, const char *domain, const char return NULL; } -static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) +static struct ast_sip_aor *find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint) { - RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup); - struct rx_task_data *task_data; - - RAII_VAR(struct ast_sip_endpoint *, endpoint, - ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup); - RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup); - char *domain_name = NULL; + struct ast_sip_aor *aor = NULL; + char *aor_name = NULL; + char *domain_name; char *username = NULL; - RAII_VAR(char *, aor_name, NULL, ast_free); int i; - if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) { - return PJ_FALSE; - } - - if (ast_strlen_zero(endpoint->aors)) { - /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */ - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); - ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors"); - ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint)); - return PJ_TRUE; - } - - if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) { - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL); - ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received"); - ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint)); - return PJ_TRUE; - } - - for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); i++) { + for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) { pjsip_sip_uri *uri; pjsip_authorization_hdr *header = NULL; switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) { - case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME : + case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME: uri = pjsip_uri_get_uri(rdata->msg_info.to->uri); domain_name = ast_alloca(uri->host.slen + 1); @@ -798,7 +631,7 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) ast_debug(3, "Matched aor '%s' by To username\n", aor_name); } break; - case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME : + case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME: while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, header ? header->next : NULL))) { if (header && !pj_stricmp2(&header->scheme, "digest")) { @@ -828,42 +661,57 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) /* The provided AOR name was not found (be it within the configuration or sorcery itself) */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found"); - ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", username, ast_sorcery_object_get_id(endpoint)); - return PJ_TRUE; + ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", + username ?: "", ast_sorcery_object_get_id(endpoint)); } + ast_free(aor_name); + return aor; +} - if (!aor->max_contacts) { - /* Registration is not permitted for this AOR */ +static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) +{ + RAII_VAR(struct ast_sip_endpoint *, endpoint, + ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup); + struct ast_sip_aor *aor; + const char *aor_name; + + if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) { + return PJ_FALSE; + } + + if (ast_strlen_zero(endpoint->aors)) { + /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); - ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted"); - ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n", - ast_sorcery_object_get_id(aor), ast_sorcery_object_get_id(endpoint)); + ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors"); + ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } - if (!(ser = serializer_find_or_create(aor_name))) { - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); - ast_sip_report_mem_limit(endpoint, rdata); - ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not get serializer\n", - ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor)); + if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) { + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL); + ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received"); + ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } - if (!(task_data = rx_task_data_create(rdata, endpoint, aor))) { - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); - ast_sip_report_mem_limit(endpoint, rdata); - ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not create rx_task_data\n", - ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor)); + aor = find_registrar_aor(rdata, endpoint); + if (!aor) { + /* We've already responded about not finding an AOR. */ return PJ_TRUE; } - if (ast_sip_push_task(ser->serializer, rx_task, task_data)) { + aor_name = ast_sorcery_object_get_id(aor); + + if (!aor->max_contacts) { + /* Registration is not permitted for this AOR */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); - ast_sip_report_mem_limit(endpoint, rdata); - ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not serialize task\n", - ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor)); - ao2_ref(task_data, -1); + ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted"); + ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n", + aor_name, ast_sorcery_object_get_id(endpoint)); + } else { + register_aor(rdata, endpoint, aor, aor_name); } + ao2_ref(aor, -1); return PJ_TRUE; } @@ -952,11 +800,6 @@ static int load_module(void) CHECK_PJSIP_MODULE_LOADED(); - if (!(serializers = ao2_container_alloc( - SERIALIZER_BUCKETS, serializer_hash, serializer_cmp))) { - return AST_MODULE_LOAD_DECLINE; - } - if (ast_sip_register_service(®istrar_module)) { return AST_MODULE_LOAD_DECLINE; } @@ -976,8 +819,6 @@ static int unload_module(void) { ast_manager_unregister(AMI_SHOW_REGISTRATIONS); ast_sip_unregister_service(®istrar_module); - - ao2_cleanup(serializers); return 0; } From cdb7edbe7b3f4fdedf999b03c2073ca15c326c31 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 9 Jun 2016 10:37:53 -0500 Subject: [PATCH 0499/1578] chan_pjsip: Lock channel when checking for RTP changes. bridge_native_rtp can call into an RTP-capable channel driver in order for the driver to update information about who the channel is communicating with. For SIP channel drivers, this means deactivating RTCP and sending a reinvite so that the endpoints can communicate directly. bridge_native_rtp does the right thing and has the channel locked when calling into the channel driver. chan_pjsip can't alter session properties in this thread, though. chan_pjsip queues a task on the session serializer in order to update properties there. The problem is that this queued task was not locking the channel. This meant that the queued task could attempt to deactivate RTCP at the same time that the channel thread was attempting to process an incoming RTCP packet. This could lead to a crash. This patch fixes the issue by locking the channel in the queued task when altering RTP properties. ASTERISK-26092 #close Reported by Niklas Larsson Change-Id: I3464e226a3c41f6b915f97891e07fa1599e2a159 --- channels/chan_pjsip.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 370075d2b73..22f834d376b 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -269,6 +269,9 @@ static int direct_media_mitigate_glare(struct ast_sip_session *session) return 0; } +/*! + * \pre chan is locked + */ static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_sip_session_media *media, int rtcp_fd) { @@ -338,6 +341,11 @@ static int send_direct_media_request(void *data) int changed = 0; int res = 0; + /* The channel needs to be locked when checking for RTP changes. + * Otherwise, we could end up destroying an underlying RTCP structure + * at the same time that the channel thread is attempting to read RTCP + */ + ast_channel_lock(cdata->chan); if (pvt->media[SIP_MEDIA_AUDIO]) { changed |= check_for_rtp_changes( cdata->chan, cdata->rtp, pvt->media[SIP_MEDIA_AUDIO], 1); @@ -346,6 +354,7 @@ static int send_direct_media_request(void *data) changed |= check_for_rtp_changes( cdata->chan, cdata->vrtp, pvt->media[SIP_MEDIA_VIDEO], 3); } + ast_channel_unlock(cdata->chan); if (direct_media_mitigate_glare(cdata->session)) { ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(cdata->chan)); From f0855358a64cea11567b64b4e8bf93aeb7ae1a73 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 9 Jun 2016 09:33:48 -0600 Subject: [PATCH 0500/1578] cdr.c: Remove assert in base_process_dial_end Scenario: Caller blonde transfer Bob calls Charlie who answers. Bob puts Charlie on hold and calls Alice. Before Alice answers, Bob transfers Charlie to Alice. Charlie's channel triggers an assert because he gets an "ANSWERED" event even though he never dialed anything. With recent changes to dial events, this is now a valid scenario so the assert needed to be removed. ASTERISK-26103 #close Change-Id: I2679b517b696e7952ab7fb29403df9140e7d1de2 --- main/cdr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index b43e3610c07..8658710d523 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1415,8 +1415,6 @@ static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_s static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status) { - /* In general, most things shouldn't get a dial end. */ - ast_assert(0); return 0; } From 56bdf048d2c873d0ddfad3672a07e7a08f0b706e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 3 Jun 2016 09:20:39 +0300 Subject: [PATCH 0501/1578] Add support for OGG/Speex file format ASTERISK-18995 #close Change-Id: I98518bd28fc8f95668b3fe27d2cab45045ff3f7a --- CHANGES | 7 + formats/format_ogg_speex.c | 345 +++++++++++++++++++++++++++++++++++++ 2 files changed, 352 insertions(+) create mode 100644 formats/format_ogg_speex.c diff --git a/CHANGES b/CHANGES index 43dc18f4bae..175138ada14 100644 --- a/CHANGES +++ b/CHANGES @@ -249,6 +249,13 @@ Functions * The func_odbc global option "single_db_connection" default value has been changed to 'no'. + +Formats +------------------ + * New module format_ogg_speex added which supports Speex codec inside + Ogg containers (filename extension .spx). + + CHANNEL ------------------ * Added CHANNEL(onhold) item that returns 1 (onhold) and 0 (not-onhold) for diff --git a/formats/format_ogg_speex.c b/formats/format_ogg_speex.c new file mode 100644 index 00000000000..6152e9c52ec --- /dev/null +++ b/formats/format_ogg_speex.c @@ -0,0 +1,345 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011-2016, Timo Teräs + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief OGG/Speex streams. + * \arg File name extension: spx + * \ingroup formats + */ + +/*** MODULEINFO + speex + ogg + extended + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/mod_format.h" +#include "asterisk/module.h" +#include "asterisk/format_cache.h" + +#include +#include + +#define BLOCK_SIZE 4096 /* buffer size for feeding OGG routines */ +#define BUF_SIZE 200 + +struct speex_desc { /* format specific parameters */ + /* structures for handling the Ogg container */ + ogg_sync_state oy; + ogg_stream_state os; + ogg_page og; + ogg_packet op; + + int serialno; + + /*! \brief Indicates whether an End of Stream condition has been detected. */ + int eos; +}; + +static int read_packet(struct ast_filestream *fs) +{ + struct speex_desc *s = (struct speex_desc *)fs->_private; + char *buffer; + int result; + size_t bytes; + + while (1) { + /* Get one packet */ + result = ogg_stream_packetout(&s->os, &s->op); + if (result > 0) { + if (s->op.bytes >= 5 && !memcmp(s->op.packet, "Speex", 5)) { + s->serialno = s->os.serialno; + } + if (s->serialno == -1 || s->os.serialno != s->serialno) { + continue; + } + return 0; + } + + if (result < 0) { + ast_log(LOG_WARNING, + "Corrupt or missing data at this page position; continuing...\n"); + } + + /* No more packets left in the current page... */ + if (s->eos) { + /* No more pages left in the stream */ + return -1; + } + + while (!s->eos) { + /* See if OGG has any pages in it's internal buffers */ + result = ogg_sync_pageout(&s->oy, &s->og); + if (result > 0) { + /* Read all streams. */ + if (ogg_page_serialno(&s->og) != s->os.serialno) { + ogg_stream_reset_serialno(&s->os, ogg_page_serialno(&s->og)); + } + /* Yes, OGG has more pages in it's internal buffers, + add the page to the stream state */ + result = ogg_stream_pagein(&s->os, &s->og); + if (result == 0) { + /* Yes, got a new, valid page */ + if (ogg_page_eos(&s->og) && + ogg_page_serialno(&s->og) == s->serialno) + s->eos = 1; + break; + } + ast_log(LOG_WARNING, + "Invalid page in the bitstream; continuing...\n"); + } + + if (result < 0) { + ast_log(LOG_WARNING, + "Corrupt or missing data in bitstream; continuing...\n"); + } + + /* No, we need to read more data from the file descrptor */ + /* get a buffer from OGG to read the data into */ + buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); + bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); + ogg_sync_wrote(&s->oy, bytes); + if (bytes == 0) { + s->eos = 1; + } + } + } +} + +/*! + * \brief Create a new OGG/Speex filestream and set it up for reading. + * \param fs File that points to on disk storage of the OGG/Speex data. + * \return The new filestream. + */ +static int ogg_speex_open(struct ast_filestream *fs) +{ + char *buffer; + size_t bytes; + struct speex_desc *s = (struct speex_desc *)fs->_private; + SpeexHeader *hdr = NULL; + int i, result, expected_rate; + + expected_rate = ast_format_get_sample_rate(fs->fmt->format); + s->serialno = -1; + ogg_sync_init(&s->oy); + + buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); + bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); + ogg_sync_wrote(&s->oy, bytes); + + result = ogg_sync_pageout(&s->oy, &s->og); + if (result != 1) { + if(bytes < BLOCK_SIZE) { + ast_log(LOG_ERROR, "Run out of data...\n"); + } else { + ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); + } + ogg_sync_clear(&s->oy); + return -1; + } + + ogg_stream_init(&s->os, ogg_page_serialno(&s->og)); + if (ogg_stream_pagein(&s->os, &s->og) < 0) { + ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); + goto error; + } + + if (read_packet(fs) < 0) { + ast_log(LOG_ERROR, "Error reading initial header packet.\n"); + goto error; + } + + hdr = speex_packet_to_header((char*)s->op.packet, s->op.bytes); + if (memcmp(hdr->speex_string, "Speex ", 8)) { + ast_log(LOG_ERROR, "OGG container does not contain Speex audio!\n"); + goto error; + } + if (hdr->frames_per_packet != 1) { + ast_log(LOG_ERROR, "Only one frame-per-packet OGG/Speex files are currently supported!\n"); + goto error; + } + if (hdr->nb_channels != 1) { + ast_log(LOG_ERROR, "Only monophonic OGG/Speex files are currently supported!\n"); + goto error; + } + if (hdr->rate != expected_rate) { + ast_log(LOG_ERROR, "Unexpected sampling rate (%d != %d)!\n", + hdr->rate, expected_rate); + goto error; + } + + /* this packet is the comment */ + if (read_packet(fs) < 0) { + ast_log(LOG_ERROR, "Error reading comment packet.\n"); + goto error; + } + for (i = 0; i < hdr->extra_headers; i++) { + if (read_packet(fs) < 0) { + ast_log(LOG_ERROR, "Error reading extra header packet %d.\n", i+1); + goto error; + } + } + speex_header_free(hdr); + + return 0; +error: + if (hdr) { + speex_header_free(hdr); + } + ogg_stream_clear(&s->os); + ogg_sync_clear(&s->oy); + return -1; +} + +/*! + * \brief Close a OGG/Speex filestream. + * \param fs A OGG/Speex filestream. + */ +static void ogg_speex_close(struct ast_filestream *fs) +{ + struct speex_desc *s = (struct speex_desc *)fs->_private; + + ogg_stream_clear(&s->os); + ogg_sync_clear(&s->oy); +} + +/*! + * \brief Read a frame full of audio data from the filestream. + * \param fs The filestream. + * \param whennext Number of sample times to schedule the next call. + * \return A pointer to a frame containing audio data or NULL ifthere is no more audio data. + */ +static struct ast_frame *ogg_speex_read(struct ast_filestream *fs, + int *whennext) +{ + struct speex_desc *s = (struct speex_desc *)fs->_private; + + if (read_packet(fs) < 0) { + return NULL; + } + + AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); + memcpy(fs->fr.data.ptr, s->op.packet, s->op.bytes); + fs->fr.datalen = s->op.bytes; + fs->fr.samples = *whennext = ast_codec_samples_count(&fs->fr); + + return &fs->fr; +} + +/*! + * \brief Trucate an OGG/Speex filestream. + * \param s The filestream to truncate. + * \return 0 on success, -1 on failure. + */ + +static int ogg_speex_trunc(struct ast_filestream *s) +{ + ast_log(LOG_WARNING, "Truncation is not supported on OGG/Speex streams!\n"); + return -1; +} + +/*! + * \brief Seek to a specific position in an OGG/Speex filestream. + * \param s The filestream to truncate. + * \param sample_offset New position for the filestream, measured in 8KHz samples. + * \param whence Location to measure + * \return 0 on success, -1 on failure. + */ +static int ogg_speex_seek(struct ast_filestream *s, off_t sample_offset, int whence) +{ + ast_log(LOG_WARNING, "Seeking is not supported on OGG/Speex streams!\n"); + return -1; +} + +static off_t ogg_speex_tell(struct ast_filestream *s) +{ + ast_log(LOG_WARNING, "Telling is not supported on OGG/Speex streams!\n"); + return -1; +} + +static struct ast_format_def speex_f = { + .name = "ogg_speex", + .exts = "spx", + .open = ogg_speex_open, + .seek = ogg_speex_seek, + .trunc = ogg_speex_trunc, + .tell = ogg_speex_tell, + .read = ogg_speex_read, + .close = ogg_speex_close, + .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET, + .desc_size = sizeof(struct speex_desc), +}; + +static struct ast_format_def speex16_f = { + .name = "ogg_speex16", + .exts = "spx16", + .open = ogg_speex_open, + .seek = ogg_speex_seek, + .trunc = ogg_speex_trunc, + .tell = ogg_speex_tell, + .read = ogg_speex_read, + .close = ogg_speex_close, + .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET, + .desc_size = sizeof(struct speex_desc), +}; + +static struct ast_format_def speex32_f = { + .name = "ogg_speex32", + .exts = "spx32", + .open = ogg_speex_open, + .seek = ogg_speex_seek, + .trunc = ogg_speex_trunc, + .tell = ogg_speex_tell, + .read = ogg_speex_read, + .close = ogg_speex_close, + .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET, + .desc_size = sizeof(struct speex_desc), +}; + +static int load_module(void) +{ + speex_f.format = ast_format_speex; + speex16_f.format = ast_format_speex16; + speex32_f.format = ast_format_speex32; + + if (ast_format_def_register(&speex_f) || + ast_format_def_register(&speex16_f) || + ast_format_def_register(&speex32_f)) { + return AST_MODULE_LOAD_FAILURE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + int res = 0; + res |= ast_format_def_unregister(speex_f.name); + res |= ast_format_def_unregister(speex16_f.name); + res |= ast_format_def_unregister(speex32_f.name); + return res; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "OGG/Speex audio", + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_APP_DEPEND +); From 10019dc70c7785b26bdd794ea7e0224c464dda91 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 8 Jun 2016 11:27:41 -0500 Subject: [PATCH 0502/1578] test_http_media_cache: Fix failing test. The retrieve_cache_control_directives test has been failing occasionally in Jenkins. The apparent failure occurs when attempting to validate the expiration of the retrieved file. After reproducing, the problem was pretty clear. At the beginning of the test, the current time is retrieved. The seconds value of this timestamp is X. When the file is retrieved, res_http_media_cache calculates the expiration and in doing so retrieves the current time. In most cases, since the test executes quickly, it will also retrieve a timestamp with X seconds. However, if the test starts very near to when the timestamp seconds are set to increment, res_http_media_cache may retrieve a timestamp with X+1 seconds instead. The test attempted to account for this by allowing a tolerance of 1 second when validating the expiration. However, the problem was that the comparisons being used in the validation used > and < operations. This meant that values that fell within the tolerance (because they equaled the upper bound of the tolerance) would fail. The solution is to use >= and <= operators in the expiration validation. However, I estimated that while the one second tolerance should be fine on most machines, it would still be possible on a very slow machine to end up falling outside the one second tolerance. So I have also relaxed the tolerance of expiration validation to be three seconds instead. The final change here is to add a debug message when validating expiration so that we can see what values are being compared. ASTERISK-25959 #close Reported by Joshua Colp Change-Id: Ic1a0e10722c1c5d276d5a4d6a67136d6ec26c247 --- tests/test_http_media_cache.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/test_http_media_cache.c b/tests/test_http_media_cache.c index c08604f1e9b..4cc4e38dc22 100644 --- a/tests/test_http_media_cache.c +++ b/tests/test_http_media_cache.c @@ -70,7 +70,10 @@ static char server_uri[512]; int actual_expires; \ ast_test_validate(test, metadata != NULL); \ ast_test_validate(test, sscanf(metadata->value, "%d", &actual_expires) == 1); \ - ast_test_validate(test, (((expected) + (delta) > actual_expires) && ((expected) - (delta) < actual_expires))); \ + ast_test_status_update(test, "Checking %d >= %d and %d <= %d\n", \ + (int) ((expected) + (delta)), actual_expires, \ + (int) ((expected) - (delta)), actual_expires); \ + ast_test_validate(test, (((expected) + (delta) >= actual_expires) && ((expected) - (delta) <= actual_expires))); \ } while (0) #define VALIDATE_STR_METADATA(test, bucket_file, key, expected) do { \ @@ -266,7 +269,7 @@ AST_TEST_DEFINE(retrieve_cache_control_directives) options.cache_control.maxage = 300; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); bucket_file_cleanup(bucket_file); @@ -295,7 +298,7 @@ AST_TEST_DEFINE(retrieve_cache_control_directives) options.cache_control.maxage = 300; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); return AST_TEST_PASS; @@ -332,7 +335,7 @@ AST_TEST_DEFINE(retrieve_cache_control_age) options.cache_control.maxage = 300; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); bucket_file_cleanup(bucket_file); @@ -342,7 +345,7 @@ AST_TEST_DEFINE(retrieve_cache_control_age) options.cache_control.s_maxage = 300; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); bucket_file_cleanup(bucket_file); @@ -352,7 +355,7 @@ AST_TEST_DEFINE(retrieve_cache_control_age) options.cache_control.s_maxage = 600; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); bucket_file_cleanup(bucket_file); @@ -363,7 +366,7 @@ AST_TEST_DEFINE(retrieve_cache_control_age) options.expires.tv_sec = now.tv_sec + 3000; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); bucket_file_cleanup(bucket_file); @@ -374,7 +377,7 @@ AST_TEST_DEFINE(retrieve_cache_control_age) options.expires.tv_sec = now.tv_sec + 3000; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); bucket_file_cleanup(bucket_file); @@ -385,7 +388,7 @@ AST_TEST_DEFINE(retrieve_cache_control_age) options.expires.tv_sec = now.tv_sec + 3000; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 300, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); bucket_file_cleanup(bucket_file); @@ -396,7 +399,7 @@ AST_TEST_DEFINE(retrieve_cache_control_age) options.expires.tv_sec = now.tv_sec + 3000; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 600, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); return AST_TEST_PASS; @@ -436,7 +439,7 @@ AST_TEST_DEFINE(retrieve_etag_expired) ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); VALIDATE_STR_METADATA(test, bucket_file, "etag", options.etag); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); @@ -476,7 +479,7 @@ AST_TEST_DEFINE(retrieve_expires) ast_test_validate(test, bucket_file != NULL); ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 3000, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec + 3000, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); @@ -486,7 +489,7 @@ AST_TEST_DEFINE(retrieve_expires) options.expires.tv_sec = now.tv_sec - 1; bucket_file = ast_bucket_file_retrieve(uri); ast_test_validate(test, bucket_file != NULL); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec - 1, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 1); @@ -526,7 +529,7 @@ AST_TEST_DEFINE(retrieve_etag) ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); VALIDATE_STR_METADATA(test, bucket_file, "etag", options.etag); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 3); ast_test_validate(test, ast_bucket_file_is_stale(bucket_file) == 0); @@ -564,7 +567,7 @@ AST_TEST_DEFINE(retrieve_nominal) ast_test_validate(test, bucket_file != NULL); ast_test_validate(test, !strcmp(uri, ast_sorcery_object_get_id(bucket_file))); ast_test_validate(test, !ast_strlen_zero(bucket_file->path)); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 3); return AST_TEST_PASS; } @@ -597,7 +600,7 @@ AST_TEST_DEFINE(create_nominal) ast_test_validate(test, bucket_file != NULL); ast_test_validate(test, ast_bucket_file_temporary_create(bucket_file) == 0); ast_test_validate(test, ast_bucket_file_create(bucket_file) == 0); - VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 1); + VALIDATE_EXPIRES(test, bucket_file, now.tv_sec, 3); return AST_TEST_PASS; } From 1fd3a7849e3a1136f5722221a9f1874a5587b6d6 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 1 Jun 2016 13:48:00 -0500 Subject: [PATCH 0503/1578] ARI: Ensure proper channel state on operations. ARI was recently outfitted with operations to create and dial channels. This leads to the ability to try funny stuff. You could create a channel and then immediately try to play back media on it. You could create a channel, dial it, and while it is ringing attempt to make it continue in the dialplan. This commit attempts to fix this by adding a channel state check to operations that should not be able to operate on outbound channels that have not yet answered. If a channel is in an invalid state, we will send a 412 response. ASTERISK-26047 #close Reported by Mark Michelson Change-Id: I2ca51bf9ef2b44a1dc5a73f2d2de35c62c37dfd8 --- res/ari/resource_channels.c | 115 ++++++++++++++++++++++++++++++++ res/res_ari_channels.c | 16 +++++ res/res_ari_recordings.c | 1 + rest-api/api-docs/channels.json | 64 ++++++++++++++++++ 4 files changed, 196 insertions(+) diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index 0f18b2dc1d5..88e66f11ab9 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -53,6 +53,60 @@ ASTERISK_REGISTER_FILE() #include +/*! + * \brief Ensure channel is in a state that allows operation to be performed. + * + * Since Asterisk 14, it has been possible for down channels, as well as unanswered + * outbound channels to enter Stasis. While some operations are fine to perform on + * such channels, operations that + * + * - Attempt to manipulate channel state + * - Attempt to play media + * - Attempt to control the channel's location in the dialplan + * + * are invalid. This function can be used to determine if the channel is in an + * appropriate state. + * + * \note When this function returns an error, the HTTP response is taken care of. + * + * \param control The app control + * \param response Response to fill in if there is an error + * + * \retval 0 Channel is in a valid state. Continue on! + * \retval non-zero Channel is in an invalid state. Bail! + */ +static int channel_state_invalid(struct stasis_app_control *control, + struct ast_ari_response *response) +{ + struct ast_channel_snapshot *snapshot; + + snapshot = stasis_app_control_get_snapshot(control); + if (!snapshot) { + ast_ari_response_error(response, 404, "Not Found", "Channel not found"); + return -1; + } + + /* These channel states apply only to outbound channels: + * - Down: Channel has been created, and nothing else has been done + * - Reserved: For a PRI, an underlying B-channel is reserved, + * but the channel is not yet dialed + * - Ringing: The channel has been dialed. + * + * This does not affect inbound channels. Inbound channels, when they + * enter the dialplan, are in the "Ring" state. If they have already + * been answered, then they are in the "Up" state. + */ + if (snapshot->state == AST_STATE_DOWN + || snapshot->state == AST_STATE_RESERVED + || snapshot->state == AST_STATE_RINGING) { + ast_ari_response_error(response, 412, "Precondition Failed", + "Channel in invalid state"); + return -1; + } + + return 0; +} + /*! * \brief Finds the control object for a channel, filling the response with an * error, if appropriate. @@ -107,8 +161,13 @@ void ast_ari_channels_continue_in_dialplan( return; } + if (channel_state_invalid(control, response)) { + return; + } + snapshot = stasis_app_control_get_snapshot(control); if (!snapshot) { + ast_ari_response_error(response, 404, "Not Found", "Channel not found"); return; } @@ -175,6 +234,10 @@ void ast_ari_channels_redirect(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + if (ast_strlen_zero(args->endpoint)) { ast_ari_response_error(response, 400, "Not Found", "Required parameter 'endpoint' not provided."); @@ -229,6 +292,10 @@ void ast_ari_channels_answer(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + if (stasis_app_control_answer(control) != 0) { ast_ari_response_error( response, 500, "Internal Server Error", @@ -250,6 +317,10 @@ void ast_ari_channels_ring(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_ring(control); ast_ari_response_no_content(response); @@ -266,6 +337,10 @@ void ast_ari_channels_ring_stop(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_ring_stop(control); ast_ari_response_no_content(response); @@ -284,6 +359,10 @@ void ast_ari_channels_mute(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + if (ast_strlen_zero(args->direction)) { ast_ari_response_error( response, 400, "Bad Request", @@ -322,6 +401,10 @@ void ast_ari_channels_unmute(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + if (ast_strlen_zero(args->direction)) { ast_ari_response_error( response, 400, "Bad Request", @@ -358,6 +441,10 @@ void ast_ari_channels_send_dtmf(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + if (ast_strlen_zero(args->dtmf)) { ast_ari_response_error( response, 400, "Bad Request", @@ -382,6 +469,10 @@ void ast_ari_channels_hold(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_hold(control); ast_ari_response_no_content(response); @@ -399,6 +490,10 @@ void ast_ari_channels_unhold(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_unhold(control); ast_ari_response_no_content(response); @@ -416,6 +511,10 @@ void ast_ari_channels_start_moh(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_moh_start(control, args->moh_class); ast_ari_response_no_content(response); } @@ -432,6 +531,10 @@ void ast_ari_channels_stop_moh(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_moh_stop(control); ast_ari_response_no_content(response); } @@ -448,6 +551,10 @@ void ast_ari_channels_start_silence(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_silence_start(control); ast_ari_response_no_content(response); } @@ -464,6 +571,10 @@ void ast_ari_channels_stop_silence(struct ast_variable *headers, return; } + if (channel_state_invalid(control, response)) { + return; + } + stasis_app_control_silence_stop(control); ast_ari_response_no_content(response); } @@ -493,6 +604,10 @@ static void ari_channels_handle_play( return; } + if (channel_state_invalid(control, response)) { + return; + } + snapshot = stasis_app_control_get_snapshot(control); if (!snapshot) { ast_ari_response_error( diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 951a5475bc0..2b7bfe2dbcf 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -811,6 +811,7 @@ static void ast_ari_channels_continue_in_dialplan_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -911,6 +912,7 @@ static void ast_ari_channels_redirect_cb( case 404: /* Channel or endpoint not found */ case 409: /* Channel not in a Stasis application */ case 422: /* Endpoint is not the same type as the channel */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -971,6 +973,7 @@ static void ast_ari_channels_answer_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1031,6 +1034,7 @@ static void ast_ari_channels_ring_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1091,6 +1095,7 @@ static void ast_ari_channels_ring_stop_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1218,6 +1223,7 @@ static void ast_ari_channels_send_dtmf_cb( case 400: /* DTMF is required */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1316,6 +1322,7 @@ static void ast_ari_channels_mute_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1414,6 +1421,7 @@ static void ast_ari_channels_unmute_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1474,6 +1482,7 @@ static void ast_ari_channels_hold_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1534,6 +1543,7 @@ static void ast_ari_channels_unhold_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1632,6 +1642,7 @@ static void ast_ari_channels_start_moh_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1692,6 +1703,7 @@ static void ast_ari_channels_stop_moh_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1752,6 +1764,7 @@ static void ast_ari_channels_start_silence_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -1812,6 +1825,7 @@ static void ast_ari_channels_stop_silence_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -2003,6 +2017,7 @@ static void ast_ari_channels_play_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: @@ -2192,6 +2207,7 @@ static void ast_ari_channels_play_with_id_cb( case 501: /* Not Implemented */ case 404: /* Channel not found */ case 409: /* Channel not in a Stasis application */ + case 412: /* Channel in invalid state */ is_valid = 1; break; default: diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index abc264d9e51..a21943520c9 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -257,6 +257,7 @@ static void ast_ari_recordings_get_stored_file_cb( break; case 500: /* Internal Server Error */ case 501: /* Not Implemented */ + case 403: /* The recording file could not be opened */ case 404: /* Recording not found */ is_valid = 1; break; diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index aafd231a1f3..34436c7b8c0 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -453,6 +453,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -501,6 +505,10 @@ { "code": 422, "reason": "Endpoint is not the same type as the channel" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -533,6 +541,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -565,6 +577,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] }, @@ -591,6 +607,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -671,6 +691,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -720,6 +744,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] }, @@ -763,6 +791,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -795,6 +827,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] }, @@ -821,6 +857,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -862,6 +902,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] }, @@ -888,6 +932,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -921,6 +969,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] }, @@ -947,6 +999,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -1021,6 +1077,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } @@ -1095,6 +1155,10 @@ { "code": 409, "reason": "Channel not in a Stasis application" + }, + { + "code": 412, + "reason": "Channel in invalid state" } ] } From d338343dac2af045ec44ad1b19b479ed3a94c295 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 7 Jun 2016 20:45:37 -0300 Subject: [PATCH 0504/1578] cel: Ensure only one dial status per channel exists. CEL wrongly assumed that a channel would only have a single dial event on it. This is incorrect. Particularly in a queue each call attempt to a member will result in a dial event, adding a new dial status in CEL without removing the old one. This would cause the container to grow with only one dial status being removed when the channel went away. The other dial status entries would remain leaking memory. This change fixes the memory leak by ensuring that only one dial status will only ever exist for each channel. The behavior during the scenario where multiple events are received has also been improved. For failure cases the first failure will be the dial status. If an answer dial status is received, though, it will take priority and the dial status for the channel will be answer. Memory usage has also been decreased by storing the minimal amount of information and the code has been cleaned up slightly. ASTERISK-25262 #close Change-Id: I5944eb923db17b6a0faa7317ff6abc9307c009fe --- main/cel.c | 108 +++++++++++++++++++++++++++-------------------- tests/test_cel.c | 2 +- 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/main/cel.c b/main/cel.c index a0d0ad7235e..85311d290bd 100644 --- a/main/cel.c +++ b/main/cel.c @@ -170,6 +170,13 @@ struct cel_linkedid { /*! Container of channel references to a linkedid for CEL purposes. */ static AO2_GLOBAL_OBJ_STATIC(cel_linkedids); +struct cel_dialstatus { + /*! Uniqueid of the channel */ + char uniqueid[AST_MAX_UNIQUEID]; + /*! The dial status */ + char dialstatus[0]; +}; + /*! \brief Destructor for cel_config */ static void cel_general_config_dtor(void *obj) { @@ -372,20 +379,10 @@ static int cel_backend_cmp(void *obj, void *arg, int flags) return CMP_MATCH; } -static const char *get_caller_uniqueid(struct ast_multi_channel_blob *blob) -{ - struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller"); - if (!caller) { - return NULL; - } - - return caller->uniqueid; -} - /*! \brief Hashing function for dialstatus container */ static int dialstatus_hash(const void *obj, int flags) { - struct ast_multi_channel_blob *blob; + const struct cel_dialstatus *dialstatus; const char *key; switch (flags & OBJ_SEARCH_MASK) { @@ -393,8 +390,8 @@ static int dialstatus_hash(const void *obj, int flags) key = obj; break; case OBJ_SEARCH_OBJECT: - blob = (void *) obj; - key = get_caller_uniqueid(blob); + dialstatus = obj; + key = dialstatus->uniqueid; break; default: /* Hash can only work on something with a full key. */ @@ -407,24 +404,24 @@ static int dialstatus_hash(const void *obj, int flags) /*! \brief Comparator function for dialstatus container */ static int dialstatus_cmp(void *obj, void *arg, int flags) { - struct ast_multi_channel_blob *object_left = obj; - struct ast_multi_channel_blob *object_right = arg; + struct cel_dialstatus *object_left = obj; + struct cel_dialstatus *object_right = arg; const char *right_key = arg; int cmp; switch (flags & OBJ_SEARCH_MASK) { case OBJ_SEARCH_OBJECT: - right_key = get_caller_uniqueid(object_right); + right_key = object_right->uniqueid; /* Fall through */ case OBJ_SEARCH_KEY: - cmp = strcmp(get_caller_uniqueid(object_left), right_key); + cmp = strcmp(object_left->uniqueid, right_key); break; case OBJ_SEARCH_PARTIAL_KEY: /* * We could also use a partial key struct containing a length * so strlen() does not get called for every comparison instead. */ - cmp = strncmp(get_caller_uniqueid(object_left), right_key, strlen(right_key)); + cmp = strncmp(object_left->uniqueid, right_key, strlen(right_key)); break; default: /* @@ -958,16 +955,16 @@ typedef void (*cel_channel_snapshot_monitor)( struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot); -static struct ast_multi_channel_blob *get_dialstatus_blob(const char *uniqueid) +static struct cel_dialstatus *get_dialstatus(const char *uniqueid) { struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store); - struct ast_multi_channel_blob *blob = NULL; + struct cel_dialstatus *dialstatus = NULL; if (dial_statuses) { - blob = ao2_find(dial_statuses, uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK); + dialstatus = ao2_find(dial_statuses, uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK); ao2_ref(dial_statuses, -1); } - return blob; + return dialstatus; } static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const char *varname) @@ -1010,19 +1007,15 @@ static void cel_channel_state_change( if (!was_hungup && is_hungup) { struct ast_json *extra; - struct ast_multi_channel_blob *blob = get_dialstatus_blob(new_snapshot->uniqueid); - const char *dialstatus = ""; + struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->uniqueid); - if (blob && !ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) { - dialstatus = get_blob_variable(blob, "dialstatus"); - } extra = ast_json_pack("{s: i, s: s, s: s}", "hangupcause", new_snapshot->hangupcause, "hangupsource", new_snapshot->hangupsource, - "dialstatus", dialstatus); + "dialstatus", dialstatus ? dialstatus->dialstatus : ""); cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL); ast_json_unref(extra); - ao2_cleanup(blob); + ao2_cleanup(dialstatus); return; } @@ -1254,16 +1247,48 @@ static void cel_parking_cb( } } -static void save_dialstatus(struct ast_multi_channel_blob *blob) +static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_channel_snapshot *snapshot) { struct ao2_container *dial_statuses = ao2_global_obj_ref(cel_dialstatus_store); + const char *dialstatus_string = get_blob_variable(blob, "dialstatus"); + struct cel_dialstatus *dialstatus; + size_t dialstatus_string_len; - ast_assert(blob != NULL); + if (!dial_statuses || ast_strlen_zero(dialstatus_string)) { + ao2_cleanup(dial_statuses); + return; + } - if (dial_statuses) { - ao2_link(dial_statuses, blob); + dialstatus = ao2_find(dial_statuses, snapshot->uniqueid, OBJ_SEARCH_KEY); + if (dialstatus) { + if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) { + /* In the case of an answer after we already have a dial status we give + * priority to the answer since the call was, well, answered. In the case of + * failure dial status results we simply let the first failure be the status. + */ + ao2_unlink(dial_statuses, dialstatus); + ao2_ref(dialstatus, -1); + } else { + ao2_ref(dialstatus, -1); + ao2_ref(dial_statuses, -1); + return; + } + } + + dialstatus_string_len = strlen(dialstatus_string) + 1; + dialstatus = ao2_alloc_options(sizeof(*dialstatus) + dialstatus_string_len, NULL, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!dialstatus) { ao2_ref(dial_statuses, -1); + return; } + + ast_copy_string(dialstatus->uniqueid, snapshot->uniqueid, sizeof(dialstatus->uniqueid)); + ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len); + + ao2_link(dial_statuses, dialstatus); + ao2_ref(dialstatus, -1); + ao2_ref(dial_statuses, -1); } static int is_valid_dialstatus(struct ast_multi_channel_blob *blob) @@ -1299,32 +1324,25 @@ static void cel_dial_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct ast_multi_channel_blob *blob = stasis_message_data(message); + struct ast_channel_snapshot *snapshot; - if (cel_filter_channel_snapshot(ast_multi_channel_blob_get_channel(blob, "caller"))) { - return; - } - - if (!get_caller_uniqueid(blob)) { + snapshot = ast_multi_channel_blob_get_channel(blob, "caller"); + if (!snapshot || cel_filter_channel_snapshot(snapshot)) { return; } if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) { - struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller"); struct ast_json *extra; - if (!caller) { - return; - } - extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward")); if (extra) { - cel_report_event(caller, AST_CEL_FORWARD, NULL, extra, NULL); + cel_report_event(snapshot, AST_CEL_FORWARD, NULL, extra, NULL); ast_json_unref(extra); } } if (is_valid_dialstatus(blob)) { - save_dialstatus(blob); + save_dialstatus(blob, snapshot); } } diff --git a/tests/test_cel.c b/tests/test_cel.c index 0cd8c5cfab7..e54fb598451 100644 --- a/tests/test_cel.c +++ b/tests/test_cel.c @@ -1610,7 +1610,7 @@ AST_TEST_DEFINE(test_cel_dial_pickup) ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER"); - HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "CANCEL"); + HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER"); HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, ""); return AST_TEST_PASS; From 0bf1a53db381da91741acf545e9c6aa98421660d Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 8 Jun 2016 13:05:22 +0200 Subject: [PATCH 0505/1578] astfd: With RLIMIT_NOFILE only the current value is sensible. With menuselect "DEBUG_FD_LEAKS" and CLI "core show fd", both the maximum max and current max of possible file descriptors were shown. Both show the same value always. Not to confuse users, just the current maximum is shown now. ASTERISK-26097 Change-Id: I49cf7952d73aec9e3f6a88942842c39be18380fa --- main/astfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/astfd.c b/main/astfd.c index d1879f092c3..0a5e7ec801c 100644 --- a/main/astfd.c +++ b/main/astfd.c @@ -276,10 +276,10 @@ static char *handle_show_fd(struct ast_cli_entry *e, int cmd, struct ast_cli_arg return NULL; } getrlimit(RLIMIT_NOFILE, &rl); - if (rl.rlim_cur == RLIM_INFINITY || rl.rlim_max == RLIM_INFINITY) { + if (rl.rlim_cur == RLIM_INFINITY) { ast_copy_string(line, "unlimited", sizeof(line)); } else { - snprintf(line, sizeof(line), "%d/%d", (int) rl.rlim_cur, (int) rl.rlim_max); + snprintf(line, sizeof(line), "%d", (int) rl.rlim_cur); } ast_cli(a->fd, "Current maxfiles: %s\n", line); for (i = 0; i < ARRAY_LEN(fdleaks); i++) { From 4eb8cf26847489e9ae69a0c0c6fb5cd64ac84467 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 10 Jun 2016 12:39:27 -0300 Subject: [PATCH 0506/1578] translate: Enables native Packet-Loss Concealment (PLC) for supporting codecs. This reverts commit 5bfef2a8b4674382f959b21a3b8e14cf1d942bab as it caused fax test failures. ASTERISK-25629 Change-Id: I79de974dc4f63a1cafe0d2509169fd9a6b3cbaf4 --- main/translate.c | 135 +++++------------------------------------------ 1 file changed, 13 insertions(+), 122 deletions(-) diff --git a/main/translate.c b/main/translate.c index b7443b81b9a..8d37e372416 100644 --- a/main/translate.c +++ b/main/translate.c @@ -358,7 +358,6 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format pvt->f.offset = AST_FRIENDLY_OFFSET; pvt->f.src = pvt->t->name; pvt->f.data.ptr = pvt->outbuf.c; - pvt->f.seqno = 0x10000; /* * If the translator has not provided a format @@ -525,46 +524,13 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a /*! \brief do the actual translation */ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume) { - const unsigned int rtp_seqno_max_value = 0xffff; - struct ast_frame *out_last, *out = NULL; - struct ast_trans_pvt *step; + struct ast_trans_pvt *p = path; + struct ast_frame *out; struct timeval delivery; int has_timing_info; long ts; long len; - int seqno, frames_missing; - - /* Determine the amount of lost packets for PLC */ - /* But not at start with first frame = path->f.seqno is still 0x10000 */ - /* But not when there is no sequence number = frame created internally */ - if ((path->f.seqno <= rtp_seqno_max_value) && (path->f.seqno != f->seqno)) { - if (f->seqno < path->f.seqno) { /* seqno overrun situation */ - frames_missing = rtp_seqno_max_value + f->seqno - path->f.seqno - 1; - } else { - frames_missing = f->seqno - path->f.seqno - 1; - } - /* Out-of-order packet - more precise: late packet */ - if ((rtp_seqno_max_value + 1) / 2 < frames_missing) { - if (consume) { - ast_frfree(f); - } - /* - * Do not pass late packets to any transcoding module, because that - * confuses the state of any library (packets inter-depend). With - * the next packet, this one is going to be treated as lost packet. - */ - return NULL; - } - - if (frames_missing > 96) { - struct ast_str *str = ast_str_alloca(256); - - /* not DEBUG but NOTICE because of WARNING in main/cannel.c:__ast_queue_frame */ - ast_log(LOG_NOTICE, "%d lost frame(s) %d/%d %s\n", frames_missing, f->seqno, path->f.seqno, ast_translate_path_to_str(path, &str)); - } - } else { - frames_missing = 0; - } + int seqno; has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); ts = f->ts; @@ -594,93 +560,18 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, f->samples, ast_format_get_sample_rate(f->subclass.format))); } delivery = f->delivery; - - for (out_last = NULL; frames_missing + 1; frames_missing--) { - struct ast_frame *frame_to_translate, *inner_head; - struct ast_frame missed = { - .frametype = AST_FRAME_VOICE, - .subclass.format = f->subclass.format, - .datalen = 0, - /* In RTP, the amount of samples might change anytime */ - /* If that happened while frames got lost, what to do? */ - .samples = f->samples, /* FIXME */ - .src = __FUNCTION__, - .data.uint32 = 0, - .delivery.tv_sec = 0, - .delivery.tv_usec = 0, - .flags = 0, - /* RTP sequence number is between 0x0001 and 0xffff */ - .seqno = (rtp_seqno_max_value + 1 + f->seqno - frames_missing) & rtp_seqno_max_value, - }; - - if (frames_missing) { - frame_to_translate = &missed; - } else { - frame_to_translate = f; - } - - /* The translation path from one format to another might contain several steps */ - /* out* collects the result for missed frame(s) and input frame(s) */ - /* out is the result of the conversion of all frames, translated into the destination format */ - /* out_last is the last frame in that list, to add frames faster */ - for (step = path, inner_head = frame_to_translate; inner_head && step; step = step->next) { - struct ast_frame *current, *inner_last, *inner_prev = frame_to_translate; - - /* inner* collects the result of each conversion step, the input for the next step */ - /* inner_head is a list of frames created by each conversion step */ - /* inner_last is the last frame in that list, to add frames faster */ - for (inner_last = NULL, current = inner_head; current; current = AST_LIST_NEXT(current, frame_list)) { - struct ast_frame *tmp; - - framein(step, current); - tmp = step->t->frameout(step); - - if (!tmp) { - continue; - } else if (inner_last) { - struct ast_frame *t; - - /* Determine the last frame of the list before appending to it */ - while ((t = AST_LIST_NEXT(inner_last, frame_list))) { - inner_last = t; - } - AST_LIST_NEXT(inner_last, frame_list) = tmp; - } else { - inner_prev = inner_head; - inner_head = tmp; - inner_last = tmp; - } - } - - /* The current step did not create any frames = no frames for the next step */ - /* The steps are not lost because framein buffered those for the next input frame */ - if (!inner_last) { - inner_prev = inner_head; - inner_head = NULL; - } - if (inner_prev != frame_to_translate) { - ast_frfree(inner_prev); /* Frees just the intermediate lists */ - } - } - - /* This frame created no frames after translation = continue with next frame */ - /* The frame is not lost because framein buffered it to be combined with the next frame */ - if (!inner_head) { - continue; - } else if (out_last) { - struct ast_frame *t; - - /* Determine the last frame of the list before appending to it */ - while ((t = AST_LIST_NEXT(out_last, frame_list))) { - out_last = t; - } - AST_LIST_NEXT(out_last, frame_list) = inner_head; - } else { - out = inner_head; - out_last = inner_head; + for (out = f; out && p ; p = p->next) { + struct ast_frame *current = out; + + do { + framein(p, current); + current = AST_LIST_NEXT(current, frame_list); + } while (current); + if (out != f) { + ast_frfree(out); } + out = p->t->frameout(p); } - if (out) { /* we have a frame, play with times */ if (!ast_tvzero(delivery)) { From ac683f13c9d377b41aee36c665057d64d28420e5 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 8 Jun 2016 13:15:15 +0200 Subject: [PATCH 0507/1578] core: Not the configured but granted number of possible file descriptors. With CLI "core show settings", simply the parameter maxfiles of the file asterisk.conf was shown. If that parameter was not set, nothing was displayed although the environment might have set a default number itself. Or if maxfiles were not granted (completely), still maxfiles was shown. Now, the maximum number of possible file descriptors in the environment is shown. ASTERISK-26097 Change-Id: I2df5c58863b5007b34b77adbe28b885dfcdf7e0b --- main/asterisk.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/main/asterisk.c b/main/asterisk.c index 25c6c956905..95f1b3ed035 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -596,6 +596,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c char buf[BUFSIZ]; struct ast_tm tm; char eid_str[128]; + struct rlimit limits; switch (cmd) { case CLI_INIT: @@ -617,10 +618,17 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", ast_option_maxcalls, ast_active_channels()); else ast_cli(a->fd, " Maximum calls: Not set\n"); - if (ast_option_maxfiles) - ast_cli(a->fd, " Maximum open file handles: %d\n", ast_option_maxfiles); - else - ast_cli(a->fd, " Maximum open file handles: Not set\n"); + + if (getrlimit(RLIMIT_NOFILE, &limits)) { + ast_cli(a->fd, " Maximum open file handles: Error because of %s\n", strerror(errno)); + } else if (limits.rlim_cur == RLIM_INFINITY) { + ast_cli(a->fd, " Maximum open file handles: Unlimited\n"); + } else if (limits.rlim_cur < ast_option_maxfiles) { + ast_cli(a->fd, " Maximum open file handles: %d (is) %d (requested)\n", (int) limits.rlim_cur, ast_option_maxfiles); + } else { + ast_cli(a->fd, " Maximum open file handles: %d\n", (int) limits.rlim_cur); + } + ast_cli(a->fd, " Root console verbosity: %d\n", option_verbose); ast_cli(a->fd, " Current console verbosity: %d\n", ast_verb_console_get()); ast_cli(a->fd, " Debug level: %d\n", option_debug); From 3d0632a9c2d87f2a731539e66e9e7f8ed3fa8a83 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 11 Feb 2016 18:15:31 -0600 Subject: [PATCH 0508/1578] res_pjsip_session.c: Reorganize ast_sip_session_terminate(). Change-Id: I68a2128bcba4830985d2d441e70dfd1ac5bd712b --- res/res_pjsip_session.c | 47 ++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 67cd09ddfd8..fad0606de81 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1794,29 +1794,38 @@ void ast_sip_session_terminate(struct ast_sip_session *session, int response) response = 603; } - if ((session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) && session->inv_session->invite_tsx) { - ast_debug(3, "Delay sending BYE to %s because of outstanding transaction...\n", - ast_sorcery_object_get_id(session->endpoint)); - /* If this is delayed the only thing that will happen is a BYE request so we don't - * actually need to store the response code for when it happens. - */ - delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE); - } else if (session->inv_session->state == PJSIP_INV_STATE_NULL) { + switch (session->inv_session->state) { + case PJSIP_INV_STATE_NULL: pjsip_inv_terminate(session->inv_session, response, PJ_TRUE); - } else if (((status = pjsip_inv_end_session(session->inv_session, response, NULL, &packet)) == PJ_SUCCESS) - && packet) { - struct ast_sip_session_delayed_request *delay; - - /* Flush any delayed requests so they cannot overlap this transaction. */ - while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) { - ast_free(delay); + break; + case PJSIP_INV_STATE_CONFIRMED: + if (session->inv_session->invite_tsx) { + ast_debug(3, "Delay sending BYE to %s because of outstanding transaction...\n", + ast_sorcery_object_get_id(session->endpoint)); + /* If this is delayed the only thing that will happen is a BYE request so we don't + * actually need to store the response code for when it happens. + */ + delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE); + break; } + /* Fall through */ + default: + status = pjsip_inv_end_session(session->inv_session, response, NULL, &packet); + if (status == PJ_SUCCESS && packet) { + struct ast_sip_session_delayed_request *delay; - if (packet->msg->type == PJSIP_RESPONSE_MSG) { - ast_sip_session_send_response(session, packet); - } else { - ast_sip_session_send_request(session, packet); + /* Flush any delayed requests so they cannot overlap this transaction. */ + while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) { + ast_free(delay); + } + + if (packet->msg->type == PJSIP_RESPONSE_MSG) { + ast_sip_session_send_response(session, packet); + } else { + ast_sip_session_send_request(session, packet); + } } + break; } } From 51cc5c31c43b29559c223d1a5ff8d6b8495d631b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 13 Jun 2016 13:33:53 -0500 Subject: [PATCH 0509/1578] res_rtp_multicast.c: Fix warning message typo. Change-Id: Ic9928208b9957e09866abe3d9649030942ec52b3 --- res/res_rtp_multicast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index 5c419d3e7cf..5a7b26b6a70 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -226,7 +226,7 @@ static void set_ttl(int sock, const char *ttl_str) ast_debug(3, "Setting multicast TTL to %s\n", ttl_str); if (sscanf(ttl_str, "%30d", &ttl) < 1) { - ast_log(LOG_WARNING, "Inavlid multicast ttl option '%s'\n", ttl_str); + ast_log(LOG_WARNING, "Invalid multicast ttl option '%s'\n", ttl_str); return; } From 7c59f2126fe313e4e8ae351b2176ab33bc53fcf2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 5 Jan 2016 19:08:24 -0600 Subject: [PATCH 0510/1578] res_pjsip.c: Add check that timer actually got scheduled. Change-Id: Iabaa2e5dccf0762c258101ea0eb1487cf6959ad1 --- res/res_pjsip.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 8fc3c530e12..9944702c350 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3406,7 +3406,7 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, ast_debug(2, "%p: Set timer to %d msec\n", req_wrapper, timeout); pj_timer_entry_init(req_wrapper->timeout_timer, TIMEOUT_TIMER2, - req_wrapper, &send_request_timer_callback); + req_wrapper, send_request_timer_callback); pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(endpt), req_wrapper->timeout_timer, TIMER_INACTIVE); @@ -3415,8 +3415,18 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, * timer callback is executed. */ ao2_ref(req_wrapper, +1); - pj_timer_heap_schedule(pjsip_endpt_get_timer_heap(endpt), + ret_val = pj_timer_heap_schedule(pjsip_endpt_get_timer_heap(endpt), req_wrapper->timeout_timer, &timeout_timer_val); + if (ret_val != PJ_SUCCESS) { + ao2_unlock(req_wrapper); + ast_log(LOG_ERROR, + "Failed to set timer. Not sending %.*s request to endpoint %s.\n", + (int) pj_strlen(&tdata->msg->line.req.method.name), + pj_strbuf(&tdata->msg->line.req.method.name), + endpoint ? ast_sorcery_object_get_id(endpoint) : ""); + ao2_t_ref(req_wrapper, -2, "Drop timer and routine ref"); + return ret_val; + } req_wrapper->timeout_timer->id = TIMEOUT_TIMER2; } else { From 3c80f84cd03d3857e7c90b280c5101d60767b277 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 18 May 2016 17:37:27 -0500 Subject: [PATCH 0511/1578] res_pjsip_transport_management.c: Misc cleanups to survive shutdown. * In unload_module(), reordered destroying things to minimize the window that the global transports container could be used by other threads on shutdown. When shutting down you need to stop things in the opposite order of creation. * Put the global transports container into an AO2_GLOBAL_OBJ_STATIC to eliminate the crash potential by other threads using the container on shutdown. * Made struct monitored_transport.sip_received not use ast_atomic_fetchadd_int() since it is used as a boolean value that is only set TRUE. It was previously incremented for every received SIP message and could theoretically overflow. * In monitored_transport_state_callback(), allocated the monitored transport object without a lock since the lock was unused. * In keepalive_global_loaded(), removed releasing the transports container if the keepalive_thread could not be started. I set it up to be tried again if the user reloads the configuration. Change-Id: I8d12d16ef564290fa6d25a32334bb5ce8fdf87ff --- res/res_pjsip_transport_management.c | 88 ++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 25 deletions(-) diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c index 8ba8c2da261..1cf8e50466e 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip_transport_management.c @@ -42,7 +42,7 @@ static const pj_str_t keepalive_packet = { "\r\n\r\n", 4 }; /*! \brief Global container of active transports */ -static struct ao2_container *transports; +static AO2_GLOBAL_OBJ_STATIC(monitored_transports); /*! \brief Scheduler context for timing out connections with no data received */ static struct ast_sched_context *sched; @@ -84,6 +84,7 @@ static int keepalive_transport_cb(void *obj, void *arg, int flags) /*! \brief Thread which sends keepalives to all active connection-oriented transports */ static void *keepalive_transport_thread(void *data) { + struct ao2_container *transports; pj_thread_desc desc; pj_thread_t *thread; @@ -92,6 +93,11 @@ static void *keepalive_transport_thread(void *data) return NULL; } + transports = ao2_global_obj_ref(monitored_transports); + if (!transports) { + return NULL; + } + /* Once loaded this module just keeps on going as it is unsafe to stop and change the underlying * callback for the transport manager. */ @@ -100,6 +106,7 @@ static void *keepalive_transport_thread(void *data) ao2_callback(transports, OBJ_NODATA, keepalive_transport_cb, NULL); } + ao2_ref(transports, -1); return NULL; } @@ -108,7 +115,6 @@ AST_THREADSTORAGE(desc_storage); static int idle_sched_cb(const void *data) { struct monitored_transport *keepalive = (struct monitored_transport *) data; - int sip_received = ast_atomic_fetchadd_int(&keepalive->sip_received, 0); if (!pj_thread_is_registered()) { pj_thread_t *thread; @@ -126,7 +132,7 @@ static int idle_sched_cb(const void *data) pj_thread_register("Transport Monitor", *desc, &thread); } - if (!sip_received) { + if (!keepalive->sip_received) { ast_log(LOG_NOTICE, "Shutting down transport '%s' since no request was received in %d seconds\n", keepalive->transport->info, IDLE_TIMEOUT); pjsip_transport_shutdown(keepalive->transport); @@ -148,23 +154,30 @@ static void monitored_transport_destroy(void *obj) static void monitored_transport_state_callback(pjsip_transport *transport, pjsip_transport_state state, const pjsip_transport_state_info *info) { + struct ao2_container *transports; + /* We only care about reliable transports */ - if (PJSIP_TRANSPORT_IS_RELIABLE(transport) && - (transport->dir == PJSIP_TP_DIR_INCOMING || keepalive_interval)) { + if (PJSIP_TRANSPORT_IS_RELIABLE(transport) + && (transport->dir == PJSIP_TP_DIR_INCOMING || keepalive_interval) + && (transports = ao2_global_obj_ref(monitored_transports))) { struct monitored_transport *monitored; switch (state) { case PJSIP_TP_STATE_CONNECTED: - monitored = ao2_alloc(sizeof(*monitored), monitored_transport_destroy); + monitored = ao2_alloc_options(sizeof(*monitored), + monitored_transport_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!monitored) { break; } monitored->transport = transport; pjsip_transport_add_ref(monitored->transport); + ao2_link(transports, monitored); + if (transport->dir == PJSIP_TP_DIR_INCOMING) { /* Let the scheduler inherit the reference from allocation */ if (ast_sched_add_variable(sched, IDLE_TIMEOUT, idle_sched_cb, monitored, 1) < 0) { + /* Uh Oh. Could not schedule the idle check. Kill the transport. */ ao2_unlink(transports, monitored); ao2_ref(monitored, -1); pjsip_transport_shutdown(transport); @@ -181,6 +194,8 @@ static void monitored_transport_state_callback(pjsip_transport *transport, pjsip default: break; } + + ao2_ref(transports, -1); } /* Forward to the old state callback if present */ @@ -242,7 +257,7 @@ static int monitored_transport_cmp_fn(void *obj, void *arg, int flags) break; } - return !cmp ? CMP_MATCH | CMP_STOP : 0; + return !cmp ? CMP_MATCH : 0; } static void keepalive_global_loaded(const char *object_type) @@ -265,8 +280,8 @@ static void keepalive_global_loaded(const char *object_type) if (ast_pthread_create(&keepalive_thread, NULL, keepalive_transport_thread, NULL)) { ast_log(LOG_ERROR, "Could not create thread for sending keepalive messages.\n"); - ao2_ref(transports, -1); - return; + keepalive_thread = AST_PTHREADT_NULL; + keepalive_interval = 0; } } @@ -283,14 +298,21 @@ static struct ast_sorcery_observer keepalive_global_observer = { */ static pj_bool_t idle_monitor_on_rx_request(pjsip_rx_data *rdata) { + struct ao2_container *transports; struct monitored_transport *idle_trans; + transports = ao2_global_obj_ref(monitored_transports); + if (!transports) { + return PJ_FALSE; + } + idle_trans = ao2_find(transports, rdata->tp_info.transport->obj_name, OBJ_SEARCH_KEY); + ao2_ref(transports, -1); if (!idle_trans) { return PJ_FALSE; } - ast_atomic_fetchadd_int(&idle_trans->sip_received, +1); + idle_trans->sip_received = 1; ao2_ref(idle_trans, -1); return PJ_FALSE; @@ -304,35 +326,38 @@ static pjsip_module idle_monitor_module = { static int load_module(void) { + struct ao2_container *transports; pjsip_tpmgr *tpmgr; CHECK_PJSIP_MODULE_LOADED(); + tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + if (!tpmgr) { + ast_log(LOG_ERROR, "No transport manager to attach keepalive functionality to.\n"); + return AST_MODULE_LOAD_DECLINE; + } + transports = ao2_container_alloc(TRANSPORTS_BUCKETS, monitored_transport_hash_fn, monitored_transport_cmp_fn); if (!transports) { ast_log(LOG_ERROR, "Could not create container for transports to perform keepalive on.\n"); return AST_MODULE_LOAD_DECLINE; } - - tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); - if (!tpmgr) { - ast_log(LOG_ERROR, "No transport manager to attach keepalive functionality to.\n"); - ao2_ref(transports, -1); - return AST_MODULE_LOAD_DECLINE; - } + ao2_global_obj_replace_unref(monitored_transports, transports); + ao2_ref(transports, -1); sched = ast_sched_context_create(); if (!sched) { ast_log(LOG_ERROR, "Failed to create keepalive scheduler context.\n"); - ao2_ref(transports, -1); + ao2_global_obj_release(monitored_transports); return AST_MODULE_LOAD_DECLINE; } if (ast_sched_start_thread(sched)) { ast_log(LOG_ERROR, "Failed to start keepalive scheduler thread\n"); ast_sched_context_destroy(sched); - ao2_ref(transports, -1); + sched = NULL; + ao2_global_obj_release(monitored_transports); return AST_MODULE_LOAD_DECLINE; } @@ -343,25 +368,38 @@ static int load_module(void) ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &keepalive_global_observer); ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); + ast_module_shutdown_ref(ast_module_info->self); return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { - pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + pjsip_tpmgr *tpmgr; if (keepalive_interval) { keepalive_interval = 0; - pthread_kill(keepalive_thread, SIGURG); - pthread_join(keepalive_thread, NULL); + if (keepalive_thread != AST_PTHREADT_NULL) { + pthread_kill(keepalive_thread, SIGURG); + pthread_join(keepalive_thread, NULL); + keepalive_thread = AST_PTHREADT_NULL; + } } - ast_sched_context_destroy(sched); - ao2_ref(transports, -1); + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &keepalive_global_observer); + + tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + if (tpmgr) { + pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback); + } ast_sip_unregister_service(&idle_monitor_module); - pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback); + + ast_sched_context_destroy(sched); + sched = NULL; + + ao2_global_obj_release(monitored_transports); + return 0; } From f72ffc1ff9743f89f044e97d573cb3719c5eeeaf Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 20 Jun 2016 15:05:09 +0200 Subject: [PATCH 0512/1578] http: leverage 'bindaddr' for TLS in http.conf The internal HTTP/WebSocket server supports both TCP and TLS, which can be activated separately via the file http.conf. The source code intends to re-use the TCP parameter 'bindaddr' for TLS, even if 'tlsbindaddr' is not specified explicitly. This did not work because of a typo. This change resolves this typo. ASTERISK-26126 #close Change-Id: I5efb0409ae12044dfb3495b6b97b6d40a8c9c51f --- main/http.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/http.c b/main/http.c index a8362829efa..bc23e6e5637 100644 --- a/main/http.c +++ b/main/http.c @@ -2220,7 +2220,7 @@ static int __ast_http_load(int reload) * the non-TLS bindaddress here. */ if (ast_sockaddr_isnull(&https_desc.local_address) && http_desc.accept_fd != -1) { - ast_sockaddr_copy(&https_desc.local_address, &https_desc.local_address); + ast_sockaddr_copy(&https_desc.local_address, &http_desc.local_address); /* Of course, we can't use the same port though. * Since no bind address was specified, we just use the * default TLS port From 11caa10cf5abae8abef91a887c30e81e8d38486a Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 13 Jun 2016 17:40:07 -0500 Subject: [PATCH 0513/1578] ARI: Ensure announcer channels are destroyed. Announcer channels were not being destroyed because the stasis_app_control structure that referenced them was not being destroyed. The control structure was not being destroyed because it was not being unlinked from its container. It was not being unlinked from its container because the after bridge callback for the announcer channel was not being run. The after bridge callback was not being run because the after bridge datastore was not being removed from the channel on destruction. The channel was not being destroyed because the hangup that used to destroy the channel was now only reducing the reference count to one. The reference count of the channel was only being reduced to one because the stasis_app_control structure was holding the final reference... The control structure used to not keep a reference to the channel, so that loop described above did not happen. The solution is to manually remove the control structure from its container when the playback on a bridge is complete. ASTERISK-26083 #close Reported by Joshua Colp Change-Id: I0ddc0f64484ea0016245800b409b567dfe85cfb4 --- include/asterisk/stasis_app.h | 9 +++++++++ res/ari/resource_bridges.c | 9 ++++++++- res/res_stasis.c | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index a73461547e0..3497bf437af 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -740,6 +740,15 @@ int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge, struct ast_channel *chan, struct stasis_app_control *control); +/*! + * \brief remove channel from list of ARI playback channels for bridges. + * + * \param bridge_id The unique ID of the bridge the playback channel is in. + * \param control The app control structure for the playback channel + */ +void stasis_app_bridge_playback_channel_remove(char *bridge_id, + struct stasis_app_control *control); + /*! * \brief Result codes used when adding/removing channels to/from bridges. */ diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index cec443dbab4..28c3e436052 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -278,6 +278,7 @@ struct bridge_channel_control_thread_data { struct ast_channel *bridge_channel; struct stasis_app_control *control; struct stasis_forward *forward; + char bridge_id[0]; }; static void *bridge_channel_control_thread(void *data) @@ -287,6 +288,7 @@ static void *bridge_channel_control_thread(void *data) struct stasis_app_control *control = thread_data->control; struct stasis_forward *forward = thread_data->forward; ast_callid callid = ast_channel_callid(bridge_channel); + char *bridge_id = ast_strdupa(thread_data->bridge_id); if (callid) { ast_callid_threadassoc_add(callid); @@ -298,6 +300,7 @@ static void *bridge_channel_control_thread(void *data) stasis_app_control_execute_until_exhausted(bridge_channel, control); stasis_app_control_flush_queue(control); + stasis_app_bridge_playback_channel_remove(bridge_id, control); stasis_forward_cancel(forward); ao2_cleanup(control); ast_hangup(bridge_channel); @@ -466,8 +469,9 @@ static void ari_bridges_play_new(const char **args_media, } /* Give play_channel and control reference to the thread data */ - thread_data = ast_calloc(1, sizeof(*thread_data)); + thread_data = ast_malloc(sizeof(*thread_data) + strlen(bridge->uniqueid) + 1); if (!thread_data) { + stasis_app_bridge_playback_channel_remove((char *)bridge->uniqueid, control); ast_ari_response_alloc_failed(response); return; } @@ -475,8 +479,11 @@ static void ari_bridges_play_new(const char **args_media, thread_data->bridge_channel = play_channel; thread_data->control = control; thread_data->forward = channel_forward; + /* Safe */ + strcpy(thread_data->bridge_id, bridge->uniqueid); if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) { + stasis_app_bridge_playback_channel_remove((char *)bridge->uniqueid, control); ast_ari_response_alloc_failed(response); ast_free(thread_data); return; diff --git a/res/res_stasis.c b/res/res_stasis.c index e7e6bcaa317..464f7c42f1b 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -713,6 +713,22 @@ int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge, return 0; } +void stasis_app_bridge_playback_channel_remove(char *bridge_id, + struct stasis_app_control *control) +{ + struct stasis_app_bridge_channel_wrapper *wrapper; + + wrapper = ao2_find(app_bridges_playback, bridge_id, OBJ_SEARCH_KEY | OBJ_UNLINK); + if (wrapper) { + /* If wrapper is not found, then that means the after bridge callback has been + * called or is in progress. No need to unlink the control here since that has + * been done or is about to be done in the after bridge callback + */ + ao2_unlink(app_controls, control); + ao2_ref(wrapper, -1); + } +} + struct ast_channel *stasis_app_bridge_playback_channel_find(struct ast_bridge *bridge) { struct stasis_app_bridge_channel_wrapper *playback_wrapper; From 820ed3d4b35d5a906863375f0336e881530fa99c Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 17 Jun 2016 14:51:57 -0400 Subject: [PATCH 0514/1578] fix: memory leaks, resource leaks, out of bounds and bugs ASTERISK-26119 #close Change-Id: Iecbf7d0f360a021147344c4e83ab242fd1e7512c --- main/ast_expr2.c | 9 +++++- main/ast_expr2.y | 9 +++++- main/say.c | 4 +-- res/ael/pval.c | 70 ++++++++++++++++++++++++++++++----------- res/res_phoneprov.c | 5 ++- res/res_pjsip_sdp_rtp.c | 2 +- 6 files changed, 74 insertions(+), 25 deletions(-) diff --git a/main/ast_expr2.c b/main/ast_expr2.c index c700b01d73f..b914598ec82 100644 --- a/main/ast_expr2.c +++ b/main/ast_expr2.c @@ -3669,13 +3669,20 @@ op_tildetilde (struct val *a, struct val *b) /* strip double quotes from both -- */ strip_quotes(a); strip_quotes(b); - + vs = malloc(strlen(a->u.s)+strlen(b->u.s)+1); + if (vs == NULL) { + ast_log(LOG_WARNING, "malloc() failed\n"); + return NULL; + } + strcpy(vs,a->u.s); strcat(vs,b->u.s); v = make_str(vs); + free(vs); + /* free arguments */ free_value(a); free_value(b); diff --git a/main/ast_expr2.y b/main/ast_expr2.y index df87bcc7f6b..29fee35cf6c 100644 --- a/main/ast_expr2.y +++ b/main/ast_expr2.y @@ -1662,13 +1662,20 @@ op_tildetilde (struct val *a, struct val *b) /* strip double quotes from both -- */ strip_quotes(a); strip_quotes(b); - + vs = malloc(strlen(a->u.s)+strlen(b->u.s)+1); + if (vs == NULL) { + ast_log(LOG_WARNING, "malloc() failed\n"); + return NULL; + } + strcpy(vs,a->u.s); strcat(vs,b->u.s); v = make_str(vs); + free(vs); + /* free arguments */ free_value(a); free_value(b); diff --git a/main/say.c b/main/say.c index 6e51de20143..e4e3743299e 100644 --- a/main/say.c +++ b/main/say.c @@ -8521,9 +8521,9 @@ int ast_say_date_with_format_ja(struct ast_channel *chan, time_t time, const cha /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ case '\'': /* Literal name of a sound file */ - sndoffset=0; - for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) + for (sndoffset = 0 ; (format[++offset] != '\'') && (sndoffset < sizeof(sndfile) - 1) ; sndoffset++) { sndfile[sndoffset] = format[offset]; + } sndfile[sndoffset] = '\0'; res = wait_file(chan,ints,sndfile,lang); break; diff --git a/res/ael/pval.c b/res/ael/pval.c index d5ea5accf03..ce9458c06dd 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -3356,9 +3356,9 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, #ifdef OLD_RAND_ACTION struct ael_priority *rand_test, *rand_end, *rand_skip; #endif - char *buf1; - char *buf2; - char *new_label; + RAII_VAR(char *, buf1, NULL, free); + RAII_VAR(char *, buf2, NULL, free); + RAII_VAR(char *, new_label, NULL, free); char *strp, *strp2; int default_exists; int local_control_statement_count; @@ -4192,9 +4192,6 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, break; } } - free(buf1); - free(buf2); - free(new_label); return 0; } @@ -5053,7 +5050,10 @@ int pvalCheckType( pval *p, char *funcname, pvaltype type ) pval *pvalCreateNode( pvaltype type ) { pval *p = calloc(1,sizeof(pval)); /* why, oh why, don't I use ast_calloc? Way, way, way too messy if I do! */ - p->type = type; /* remember, this can be used externally or internally to asterisk */ + /* remember, this can be used externally or internally to asterisk */ + if (p) { + p->type = type; + } return p; } @@ -5414,14 +5414,30 @@ void pvalIncludesAddInclude( pval *p, const char *include ) void pvalIncludesAddIncludeWithTimeConstraints( pval *p, const char *include, char *hour_range, char *dom_range, char *dow_range, char *month_range ) { - pval *hr = pvalCreateNode(PV_WORD); - pval *dom = pvalCreateNode(PV_WORD); - pval *dow = pvalCreateNode(PV_WORD); - pval *mon = pvalCreateNode(PV_WORD); - pval *s = pvalCreateNode(PV_WORD); - - if (!pvalCheckType(p, "pvalIncludeAddIncludeWithTimeConstraints", PV_INCLUDES)) + pval *hr; + pval *dom; + pval *dow; + pval *mon; + pval *s; + + if (!pvalCheckType(p, "pvalIncludeAddIncludeWithTimeConstraints", PV_INCLUDES)) { + return; + } + + hr = pvalCreateNode(PV_WORD); + dom = pvalCreateNode(PV_WORD); + dow = pvalCreateNode(PV_WORD); + mon = pvalCreateNode(PV_WORD); + s = pvalCreateNode(PV_WORD); + + if (!hr || !dom || !dow || !mon || !s) { + destroy_pval(hr); + destroy_pval(dom); + destroy_pval(dow); + destroy_pval(mon); + destroy_pval(s); return; + } s->u1.str = (char *)include; p->u1.list = linku1(p->u1.list, s); @@ -5668,12 +5684,28 @@ char* pvalIfGetCondition( pval *p ) void pvalIfTimeSetCondition( pval *p, char *hour_range, char *dow_range, char *dom_range, char *mon_range ) /* time range format: 24-hour format begin-end|dow range|dom range|month range */ { - pval *hr = pvalCreateNode(PV_WORD); - pval *dow = pvalCreateNode(PV_WORD); - pval *dom = pvalCreateNode(PV_WORD); - pval *mon = pvalCreateNode(PV_WORD); - if (!pvalCheckType(p, "pvalIfTimeSetCondition", PV_IFTIME)) + pval *hr; + pval *dow; + pval *dom; + pval *mon; + + if (!pvalCheckType(p, "pvalIfTimeSetCondition", PV_IFTIME)) { return; + } + + hr = pvalCreateNode(PV_WORD); + dow = pvalCreateNode(PV_WORD); + dom = pvalCreateNode(PV_WORD); + mon = pvalCreateNode(PV_WORD); + + if (!hr || !dom || !dow || !mon) { + destroy_pval(hr); + destroy_pval(dom); + destroy_pval(dow); + destroy_pval(mon); + return; + } + pvalWordSetString(hr, hour_range); pvalWordSetString(dow, dow_range); pvalWordSetString(dom, dom_range); diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c index b448c8e0bb8..2e4f8736235 100644 --- a/res/res_phoneprov.c +++ b/res/res_phoneprov.c @@ -410,10 +410,13 @@ static int load_file(const char *filename, char **ret) fseek(f, 0, SEEK_END); len = ftell(f); fseek(f, 0, SEEK_SET); - if (!(*ret = ast_malloc(len + 1))) + if (!(*ret = ast_malloc(len + 1))) { + fclose(f); return -2; + } if (len != fread(*ret, sizeof(char), len, f)) { + fclose(f); ast_free(*ret); *ret = NULL; return -3; diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 08e80a38c2f..048209ce11f 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -429,7 +429,7 @@ static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format * *++tmp = '\0'; /* ast...generate gives us everything, just need value */ tmp = strchr(ast_str_buffer(fmtp0), ':'); - if (tmp && tmp + 1) { + if (tmp && tmp[1] != '\0') { fmtp1 = pj_str(tmp + 1); } else { fmtp1 = pj_str(ast_str_buffer(fmtp0)); From 0a300082243b4d011455b7d86a2d9fbbef06a9cc Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 20 Jun 2016 12:13:27 -0500 Subject: [PATCH 0515/1578] app_voicemail.c: Fix IMAP compile error. Fix compile error introduced by the patch for ASTERISK-26045 Change-Id: I5b02876266f2824f4cec2b54d6ff4db5de5778d3 --- apps/app_voicemail.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 586086c55a9..6607f529e8d 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -3263,7 +3263,8 @@ void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes) void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status) { struct ast_str *str; - if (!DEBUG_ATLEAST(5) || !(str = ast_str_create(MAX_OBJECT_FIELD))) { + + if (!DEBUG_ATLEAST(5) || !(str = ast_str_create(256))) { return; } From e94aae00a7e871d789d4196a7c5b38738c5be4e8 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 20 Jun 2016 12:29:13 -0300 Subject: [PATCH 0516/1578] res_pjsip_session: Handle race condition at shutdown with timer. When shutting down res_pjsip_session will get unloaded before res_pjsip. The act of unloading unregisters all the PJSIP services and sets their module IDs to -1. In some cases it is possible for a timer to occur after this happens which calls into res_pjsip_session. The res_pjsip_session module can then try to get the session from the INVITE session using the module ID. Since the module ID is now -1 this fails. This change stores a copy of the module ID and uses it for the timer callback scenario. If the module ID is -1 the callback immediately returns but if the module ID is valid then it continues as normal. This works as the original ID of the module is guaranteed to still be valid when used with the INVITE session. ASTERISK-26127 #close Change-Id: I88df72525c4e9ef9f19c13aedddd3ac4a335c573 --- res/res_pjsip_session.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index fad0606de81..eb9551097af 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2315,7 +2315,8 @@ static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session static void __print_debug_details(const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) { - struct ast_sip_session *session; + int id = session_module.id; + struct ast_sip_session *session = NULL; if (!DEBUG_ATLEAST(5)) { /* Debug not spamy enough */ @@ -2330,7 +2331,9 @@ static void __print_debug_details(const char *function, pjsip_inv_session *inv, pjsip_tsx_state_str(tsx->state)); return; } - session = inv->mod_data[session_module.id]; + if (id > -1) { + session = inv->mod_data[session_module.id]; + } if (!session) { ast_log(LOG_DEBUG, "inv_session %p has no ast session\n", inv); } else { @@ -2584,9 +2587,22 @@ static void session_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e) static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) { ast_sip_session_response_cb cb; - struct ast_sip_session *session = inv->mod_data[session_module.id]; + int id = session_module.id; + struct ast_sip_session *session; pjsip_tx_data *tdata; + /* + * A race condition exists at shutdown where the res_pjsip_session can be + * unloaded but this callback may still get called afterwards. In this case + * the id may end up being -1 which is useless to us. To work around this + * we store the current value and check/use it. + */ + if (id < 0) { + return; + } + + session = inv->mod_data[id]; + print_debug_details(inv, tsx, e); if (!session) { /* The session has ended. Ignore the transaction change. */ @@ -2600,10 +2616,10 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans * we transfer the data into the transaction. This way, when we receive a response, we * can dig this data out again */ - tsx->mod_data[session_module.id] = e->body.tsx_state.src.tdata->mod_data[session_module.id]; + tsx->mod_data[id] = e->body.tsx_state.src.tdata->mod_data[id]; break; case PJSIP_EVENT_RX_MSG: - cb = ast_sip_mod_data_get(tsx->mod_data, session_module.id, MOD_DATA_ON_RESPONSE); + cb = ast_sip_mod_data_get(tsx->mod_data, id, MOD_DATA_ON_RESPONSE); /* As the PJSIP invite session implementation responds with a 200 OK before we have a * chance to be invoked session supplements for BYE requests actually end up executing * in the invite session state callback as well. To prevent session supplements from @@ -2682,7 +2698,7 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans * Clear the module data now to block session_inv_on_state_changed() * from calling session_end() if it hasn't already done so. */ - inv->mod_data[session_module.id] = NULL; + inv->mod_data[id] = NULL; if (inv->state != PJSIP_INV_STATE_DISCONNECTED) { session_end(session); @@ -2705,8 +2721,8 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans * the dialog locked to get the session by other threads. */ pjsip_dlg_inc_lock(inv->dlg); - session = inv->mod_data[session_module.id]; - inv->mod_data[session_module.id] = NULL; + session = inv->mod_data[id]; + inv->mod_data[id] = NULL; pjsip_dlg_dec_lock(inv->dlg); /* From 9e222efbf20f30a70a6ab9308fde79b5045f8f7b Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 21 Jun 2016 15:01:40 +0200 Subject: [PATCH 0517/1578] BuildSystem: Avoid obsolete warning with HELP_STRING on autoconf. Some configure scripts used both AC_HELP_STRING and its replacement AS_HELP_STRING. For consistency and to avoid obsolete warnings, those were changed to AS_HELP_STRING. ASTERISK-26046 Change-Id: I8aad4fd2bdee40aa2a31ce3339a1eb33ff4f5b0f --- autoconf/ast_ext_lib.m4 | 2 +- autoconf/ast_prog_ld.m4 | 2 +- configure | 10 +++++----- configure.ac | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/autoconf/ast_ext_lib.m4 b/autoconf/ast_ext_lib.m4 index 8f35f4bad83..2c73b40c5de 100644 --- a/autoconf/ast_ext_lib.m4 +++ b/autoconf/ast_ext_lib.m4 @@ -11,7 +11,7 @@ AC_DEFUN([AST_EXT_LIB_SETUP], $1_DESCRIP="$2" $1_OPTION="$3" PBX_$1=0 - AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH$4]), + AC_ARG_WITH([$3], AS_HELP_STRING([--with-$3=PATH],[use $2 files in PATH$4]), [ case ${withval} in n|no) diff --git a/autoconf/ast_prog_ld.m4 b/autoconf/ast_prog_ld.m4 index 9177fedb365..b69c2c2ac08 100644 --- a/autoconf/ast_prog_ld.m4 +++ b/autoconf/ast_prog_ld.m4 @@ -3,7 +3,7 @@ # find the pathname to the GNU or non-GNU linker AC_DEFUN([AST_PROG_LD], [AC_ARG_WITH([gnu-ld], - [AC_HELP_STRING([--with-gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no]) diff --git a/configure b/configure index bcc427c8467..04183b401c2 100755 --- a/configure +++ b/configure @@ -13775,7 +13775,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13821,7 +13821,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13845,7 +13845,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13890,7 +13890,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13914,7 +13914,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; diff --git a/configure.ac b/configure.ac index 3cc8588fe96..2c47dc453d1 100644 --- a/configure.ac +++ b/configure.ac @@ -1234,7 +1234,7 @@ AC_SUBST(AST_NATIVE_ARCH) dnl Check to see if rpath should be set in LDFLAGS AC_ARG_ENABLE(rpath, - [AC_HELP_STRING([--disable-rpath], + [AS_HELP_STRING([--disable-rpath], [Disables rpath linker option checking])], [case "${enableval}" in y|ye|yes) check_rpath=yes ;; From 596d0b0bc39a945490bc00ee90e406f42062a0b9 Mon Sep 17 00:00:00 2001 From: Scott Griepentrog Date: Tue, 21 Jun 2016 10:53:05 -0500 Subject: [PATCH 0518/1578] PJSIP: provide transport type with received messages The receipt of a SIP MESSAGE may occur over any transport including TCP and TLS. When the message is received, the original URI is added to the message in the field PJSIP_RECVADDR, but this is insufficient to ensure a reply message can reach the originating endpoint. This patch adds the PJSIP_TRANSPORT field populated with the transport type. ASTERISK-26132 #close Change-Id: I28c4b1e40d573a056c81deb213ecf53e968f725e --- res/res_pjsip_messaging.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index f72f3f01548..b508a2a596e 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -476,6 +476,24 @@ static enum pjsip_status_code rx_data_to_ast_msg(pjsip_rx_data *rdata, struct as field = pj_sockaddr_print(&rdata->pkt_info.src_addr, buf, sizeof(buf) - 1, 1); res |= ast_msg_set_var(msg, "PJSIP_RECVADDR", field); + switch (rdata->tp_info.transport->key.type) { + case PJSIP_TRANSPORT_UDP: + case PJSIP_TRANSPORT_UDP6: + field = "udp"; + break; + case PJSIP_TRANSPORT_TCP: + case PJSIP_TRANSPORT_TCP6: + field = "tcp"; + break; + case PJSIP_TRANSPORT_TLS: + case PJSIP_TRANSPORT_TLS6: + field = "tls"; + break; + default: + field = rdata->tp_info.transport->type_name; + } + ast_msg_set_var(msg, "PJSIP_TRANSPORT", field); + if (print_body(rdata, buf, sizeof(buf) - 1) > 0) { res |= ast_msg_set_body(msg, "%s", buf); } From 6eb0354f2d0a7845ee3f302a54a84c39f10be620 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 21 Jun 2016 14:05:30 +0200 Subject: [PATCH 0519/1578] res_rtp_asterisk: Use latest DTLS version available by underlying platform. Do not use DTLSv1_method() but DTLS_method() when available in OpenSSL of the underlying platform. This change enables DTLS 1.2 since OpenSSL 1.0.2, for WebRTC (DTLS-SRTP via SIP-over-WebSockets). This change enables AEAD-based cipher-suites. ASTERISK-26130 #close Change-Id: I41f24448d6d2953e8bdb97c9f4a6bc8a8f055fd0 --- res/res_rtp_asterisk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 9e3ff757c52..1bf16941dcb 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1357,7 +1357,12 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con return 0; } - if (!(rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method()))) { +#if OPENSSL_VERSION_NUMBER < 0x10002000L + rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method()); +#else + rtp->ssl_ctx = SSL_CTX_new(DTLS_method()); +#endif + if (!rtp->ssl_ctx) { return -1; } From b57cd0140477fc92ed81644f457cd87f8b7114b9 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 12 Jun 2016 10:19:27 -0600 Subject: [PATCH 0520/1578] res_pjsip_pubsub: Address SEGV when attempting to terminate a subscription Occasionally under load we'll attempt to send a final NOTIFY on a subscription that's already been terminated and a SEGV will occur down in pjproject's evsub_destroy function. This is a result of a race condition between all the paths that can generate a notify and/or destroy the underlying pjproject evsub object: * The client can send a SUBSCRIBE with Expires: 0. * The client can send a SUBSCRIBE/refresh. * The subscription timer can expire. * An extension state can change. * An MWI event can be generated. * The pjproject transaction timer (timer_b) can expire. Normally when our pubsub_on_evsub_state is called with a terminate, we push a task to the serializer and return at which point the dialog is unlocked. This is usually not a problem because the task runs immediately and locks the dialog again. When the system is heavily loaded though, there may be a delay between the unlock and relock during which another event may occur such as the subscription timer or timer_b expiring, an extension state change, etc. These may also cause a terminate to be processed and if so, we could cause pjproject to try to destroy the evsub structure twice. There's no way for us to tell that the evsub was already destroyed and the evsub's group lock can't tolerate this and SEGVs. The remedy is twofold. * A patch has been submitted to Teluu and added to the bundled pjproject which adds add/decrement operations on evsub's group lock. * In res_pjsip_pubsub: * configure.ac and pjproject-bundled's configure.m4 were updated to check for the new evsub group lock APIs. * We now add a reference to the evsub group lock when we create the subscription and remove the reference when we clean up the subscription. This prevents evsub from being destroyed before we're done with it. * A state has been added to the subscription tree structure so termination progress can be tracked through the asyncronous tasks. * The pubsub_on_evsub_state callback has been split so it's not doing double duty. It now only handles the final cleanup of the subscription tree. pubsub_on_rx_refresh now handles both client refreshes and client terminates. It was always being called for both anyway. * The serialized_on_server_timeout task was removed since serialized_pubsub_on_rx_refresh was almost identical. * Missing state checks and ao2_cleanups were added. * Some debug levels were adjusted to make seeing only off-nominal things at level 1 and nominal or progress things at level 2+. ASTERISK-26099 #close Reported-by: Ross Beer. Change-Id: I779d11802cf672a51392e62a74a1216596075ba1 --- configure | 134 +++++++- configure.ac | 3 + include/asterisk/autoconfig.h.in | 3 + res/res_pjsip_pubsub.c | 311 +++++++++++------- third-party/pjproject/configure.m4 | 1 + ...o-add-decrement-an-event-subscriptio.patch | 73 ++++ 6 files changed, 395 insertions(+), 130 deletions(-) create mode 100644 third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch diff --git a/configure b/configure index 04183b401c2..3aa6004424c 100755 --- a/configure +++ b/configure @@ -923,6 +923,10 @@ PBX_POPT POPT_DIR POPT_INCLUDE POPT_LIB +PBX_PJSIP_EVSUB_GRP_LOCK +PJSIP_EVSUB_GRP_LOCK_DIR +PJSIP_EVSUB_GRP_LOCK_INCLUDE +PJSIP_EVSUB_GRP_LOCK_LIB PBX_PJSIP_TLS_TRANSPORT_PROTO PJSIP_TLS_TRANSPORT_PROTO_DIR PJSIP_TLS_TRANSPORT_PROTO_INCLUDE @@ -10576,6 +10580,18 @@ PBX_PJSIP_TLS_TRANSPORT_PROTO=0 +PJSIP_EVSUB_GRP_LOCK_DESCRIP="PJSIP EVSUB Group Lock support" +PJSIP_EVSUB_GRP_LOCK_OPTION=pjsip +PJSIP_EVSUB_GRP_LOCK_DIR=${PJPROJECT_DIR} + +PBX_PJSIP_EVSUB_GRP_LOCK=0 + + + + + + + POPT_DESCRIP="popt" POPT_OPTION="popt" @@ -13775,7 +13791,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13821,7 +13837,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13845,7 +13861,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13890,7 +13906,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13914,7 +13930,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -24740,6 +24756,9 @@ rm -f conftest* $as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h +$as_echo "#define HAVE_PJSIP_EVSUB_GRP_LOCK 1" >>confdefs.h + + else if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then @@ -25455,6 +25474,111 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext LIBS="${saved_libs}" CPPFLAGS="${saved_cppflags}" + + +if test "x${PBX_PJSIP_EVSUB_GRP_LOCK}" != "x1" -a "${USE_PJSIP_EVSUB_GRP_LOCK}" != "no"; then + pbxlibdir="" + # if --with-PJSIP_EVSUB_GRP_LOCK=DIR has been specified, use it. + if test "x${PJSIP_EVSUB_GRP_LOCK_DIR}" != "x"; then + if test -d ${PJSIP_EVSUB_GRP_LOCK_DIR}/lib; then + pbxlibdir="-L${PJSIP_EVSUB_GRP_LOCK_DIR}/lib" + else + pbxlibdir="-L${PJSIP_EVSUB_GRP_LOCK_DIR}" + fi + fi + pbxfuncname="pjsip_evsub_add_lock" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_PJSIP_EVSUB_GRP_LOCK_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS" + as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_PJSIP_EVSUB_GRP_LOCK_FOUND=yes +else + AST_PJSIP_EVSUB_GRP_LOCK_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_PJSIP_EVSUB_GRP_LOCK_FOUND}" = "yes"; then + PJSIP_EVSUB_GRP_LOCK_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB" + # if --with-PJSIP_EVSUB_GRP_LOCK=DIR has been specified, use it. + if test "x${PJSIP_EVSUB_GRP_LOCK_DIR}" != "x"; then + PJSIP_EVSUB_GRP_LOCK_INCLUDE="-I${PJSIP_EVSUB_GRP_LOCK_DIR}/include" + fi + PJSIP_EVSUB_GRP_LOCK_INCLUDE="${PJSIP_EVSUB_GRP_LOCK_INCLUDE} $PJPROJECT_CFLAGS" + if test "xpjsip.h" = "x" ; then # no header, assume found + PJSIP_EVSUB_GRP_LOCK_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${PJSIP_EVSUB_GRP_LOCK_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default" +if test "x$ac_cv_header_pjsip_h" = xyes; then : + PJSIP_EVSUB_GRP_LOCK_HEADER_FOUND=1 +else + PJSIP_EVSUB_GRP_LOCK_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${PJSIP_EVSUB_GRP_LOCK_HEADER_FOUND}" = "x0" ; then + PJSIP_EVSUB_GRP_LOCK_LIB="" + PJSIP_EVSUB_GRP_LOCK_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + PJSIP_EVSUB_GRP_LOCK_LIB="" + fi + PBX_PJSIP_EVSUB_GRP_LOCK=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_PJSIP_EVSUB_GRP_LOCK 1 +_ACEOF + + fi + fi +fi + + fi fi diff --git a/configure.ac b/configure.ac index 2c47dc453d1..72a47e2d19c 100644 --- a/configure.ac +++ b/configure.ac @@ -486,6 +486,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_GET_DEST_INFO], [pjsip_get_dest_info support], AST_EXT_LIB_SETUP_OPTIONAL([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_from_files2 support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EXTERNAL_RESOLVER], [PJSIP External Resolver Support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_PROTO], [PJSIP TLS Transport proto field support], [PJPROJECT], [pjsip]) +AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_GRP_LOCK], [PJSIP EVSUB Group Lock support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP([POPT], [popt], [popt]) AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio]) @@ -2209,6 +2210,8 @@ if test "$USE_PJPROJECT" != "no" ; then AST_C_COMPILE_CHECK([PJSIP_TLS_TRANSPORT_PROTO], [struct pjsip_tls_setting setting; int proto; proto = setting.proto;], [pjsip.h]) LIBS="${saved_libs}" CPPFLAGS="${saved_cppflags}" + + AST_EXT_LIB_CHECK([PJSIP_EVSUB_GRP_LOCK], [pjsip], [pjsip_evsub_add_lock], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) fi fi diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 72242122828..cd228d7d4ba 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -586,6 +586,9 @@ /* Define if your system has pjsip_dlg_create_uas_and_inc_lock declared. */ #undef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK +/* Define if your system has PJSIP_EVSUB_GRP_LOCK */ +#undef HAVE_PJSIP_EVSUB_GRP_LOCK + /* Define if your system has pjsip_endpt_set_ext_resolver declared. */ #undef HAVE_PJSIP_EXTERNAL_RESOLVER diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 06a1b52b1af..4e4180957ea 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -377,6 +377,20 @@ struct subscription_persistence { struct timeval expires; }; +/*! + * \brief The state of the subscription tree + */ +enum sip_subscription_tree_state { + /*! Normal operation */ + SIP_SUB_TREE_NORMAL = 0, + /*! A terminate has been requested by Asterisk, the client, or pjproject */ + SIP_SUB_TREE_TERMINATE_PENDING, + /*! The terminate is in progress */ + SIP_SUB_TREE_TERMINATE_IN_PROGRESS, + /*! The terminate process has finished and the subscription tree is no longer valid */ + SIP_SUB_TREE_TERMINATED, +}; + /*! * \brief A tree of SIP subscriptions * @@ -411,8 +425,8 @@ struct sip_subscription_tree { int is_list; /*! Next item in the list */ AST_LIST_ENTRY(sip_subscription_tree) next; - /*! Indicates that a NOTIFY is currently being sent on the SIP subscription */ - int last_notify; + /*! Subscription tree state */ + enum sip_subscription_tree_state state; }; /*! @@ -879,15 +893,15 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct "allocation error afterwards\n", resource); continue; } - ast_debug(1, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n", + ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n", resource, parent->resource); AST_VECTOR_APPEND(&parent->children, current); } else { - ast_debug(1, "Subscription to leaf resource %s resulted in error response %d\n", + ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n", resource, resp); } } else { - ast_debug(1, "Resource %s (child of %s) is a list\n", resource, parent->resource); + ast_debug(2, "Resource %s (child of %s) is a list\n", resource, parent->resource); current = tree_node_alloc(resource, visited, child_list->full_state); if (!current) { ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource); @@ -898,7 +912,7 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_debug(1, "List %s had no successful children.\n", resource); AST_VECTOR_APPEND(&parent->children, current); } else { - ast_debug(1, "List %s had successful children. Adding to parent %s\n", + ast_debug(2, "List %s had successful children. Adding to parent %s\n", resource, parent->resource); tree_node_destroy(current); } @@ -970,7 +984,7 @@ static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct a struct resources visited; if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) { - ast_debug(1, "Subscription to resource %s is not to a list\n", resource); + ast_debug(2, "Subscription to resource %s is not to a list\n", resource); tree->root = tree_node_alloc(resource, NULL, 0); if (!tree->root) { return 500; @@ -978,7 +992,7 @@ static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct a return handler->notifier->new_subscribe(endpoint, resource); } - ast_debug(1, "Subscription to resource %s is a list\n", resource); + ast_debug(2, "Subscription to resource %s is a list\n", resource); if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) { return 500; } @@ -1015,7 +1029,7 @@ static void remove_subscription(struct sip_subscription_tree *obj) if (i == obj) { AST_RWLIST_REMOVE_CURRENT(next); if (i->root) { - ast_debug(1, "Removing subscription to resource %s from list of subscriptions\n", + ast_debug(2, "Removing subscription to resource %s from list of subscriptions\n", ast_sip_subscription_get_resource_name(i->root)); } break; @@ -1307,6 +1321,10 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub); subscription_setup_dialog(sub_tree, dlg); +#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK + pjsip_evsub_add_ref(sub_tree->evsub); +#endif + ast_sip_mod_data_set(dlg->pool, dlg->mod_data, pubsub_module.id, MOD_DATA_MSG, pjsip_msg_clone(dlg->pool, rdata->msg_info.msg)); @@ -2230,10 +2248,8 @@ static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int forc pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require); } - if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) { - sub_tree->last_notify = 1; - } if (sip_subscription_send_request(sub_tree, tdata)) { + pjsip_tx_data_dec_ref(tdata); return -1; } @@ -2248,21 +2264,32 @@ static int serialized_send_notify(void *userdata) pjsip_dialog *dlg = sub_tree->dlg; pjsip_dlg_inc_lock(dlg); + /* It's possible that between when the notification was scheduled - * and now, that a new SUBSCRIBE arrived, requiring full state to be - * sent out in an immediate NOTIFY. If that has happened, we need to + * and now a new SUBSCRIBE arrived requiring full state to be + * sent out in an immediate NOTIFY. It's also possible that we're + * already processing a terminate. If that has happened, we need to * bail out here instead of sending the batched NOTIFY. */ - if (!sub_tree->send_scheduled_notify) { + + if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS + || !sub_tree->send_scheduled_notify) { pjsip_dlg_dec_lock(dlg); ao2_cleanup(sub_tree); return 0; } + if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) { + sub_tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS; + } + send_notify(sub_tree, 0); - ast_test_suite_event_notify("SUBSCRIPTION_STATE_CHANGED", - "Resource: %s", - sub_tree->root->resource); + + ast_test_suite_event_notify( + sub_tree->state == SIP_SUB_TREE_TERMINATED + ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED", + "Resource: %s", sub_tree->root->resource); + sub_tree->notify_sched_id = -1; pjsip_dlg_dec_lock(dlg); ao2_cleanup(sub_tree); @@ -2274,7 +2301,10 @@ static int sched_cb(const void *data) struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data; /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */ - ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree); + if (ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree)) { + ao2_cleanup(sub_tree); + } + return 0; } @@ -2285,12 +2315,13 @@ static int schedule_notification(struct sip_subscription_tree *sub_tree) return 0; } + sub_tree->send_scheduled_notify = 1; sub_tree->notify_sched_id = ast_sched_add(sched, sub_tree->notification_batch_interval, sched_cb, ao2_bump(sub_tree)); if (sub_tree->notify_sched_id < 0) { + ao2_cleanup(sub_tree); return -1; } - sub_tree->send_scheduled_notify = 1; return 0; } @@ -2302,7 +2333,7 @@ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip pjsip_dlg_inc_lock(dlg); - if (!sub->tree->evsub) { + if (sub->tree->state != SIP_SUB_TREE_NORMAL) { pjsip_dlg_dec_lock(dlg); return 0; } @@ -2316,6 +2347,7 @@ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip sub->body_changed = 1; if (terminate) { sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED; + sub->tree->state = SIP_SUB_TREE_TERMINATE_PENDING; } if (sub->tree->notification_batch_interval) { @@ -2323,6 +2355,9 @@ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip } else { /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */ ao2_ref(sub->tree, +1); + if (terminate) { + sub->tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS; + } res = send_notify(sub->tree, 0); ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED", "Resource: %s", @@ -3268,71 +3303,72 @@ static void set_state_terminated(struct ast_sip_subscription *sub) } } -/* XXX This function and serialized_pubsub_on_rx_refresh are nearly identical */ -static int serialized_pubsub_on_server_timeout(void *userdata) -{ - struct sip_subscription_tree *sub_tree = userdata; - pjsip_dialog *dlg = sub_tree->dlg; - - pjsip_dlg_inc_lock(dlg); - if (!sub_tree->evsub) { - pjsip_dlg_dec_lock(dlg); - return 0; - } - set_state_terminated(sub_tree->root); - send_notify(sub_tree, 1); - ast_test_suite_event_notify("SUBSCRIPTION_TERMINATED", - "Resource: %s", - sub_tree->root->resource); - - pjsip_dlg_dec_lock(dlg); - ao2_cleanup(sub_tree); - return 0; -} - /*! - * \brief PJSIP callback when underlying SIP subscription changes state - * - * This callback is a bit of a mess, because it's not always called when - * you might expect it to be, and it can be called multiple times for the - * same state. + * \brief Callback sequence for subscription terminate: * - * For instance, this function is not called at all when an incoming SUBSCRIBE - * arrives to refresh a subscription. That makes sense in a way, since the - * subscription state has not made a change; it was active and remains active. + * * Client initiated: + * pjproject receives SUBSCRIBE on the subscription's serializer thread + * calls pubsub_on_rx_refresh with dialog locked + * pubsub_on_rx_refresh sets TERMINATE_PENDING + * pushes serialized_pubsub_on_refresh_timeout + * returns to pjproject + * pjproject calls pubsub_on_evsub_state + * pubsub_evsub_set_state checks state == TERMINATE_IN_PROGRESS (no) + * ignore and return + * pjproject unlocks dialog + * serialized_pubsub_on_refresh_timeout starts (1) + * locks dialog + * checks state == TERMINATE_PENDING + * sets TERMINATE_IN_PROGRESS + * calls send_notify (2) + * send_notify ultimately calls pjsip_evsub_send_request + * pjsip_evsub_send_request calls evsub's set_state + * set_state calls pubsub_evsub_set_state + * pubsub_evsub_set_state checks state == TERMINATE_IN_PROGRESS + * removes the subscriptions + * cleans up references to evsub + * sets state = TERMINATED + * serialized_pubsub_on_refresh_timeout unlocks dialog * - * However, if an incoming SUBSCRIBE arrives to end a subscription, then this - * will be called into once upon receiving the SUBSCRIBE (after the call to - * pubsub_on_rx_refresh) and again when sending a NOTIFY to end the subscription. - * In both cases, the apparent state of the subscription is "terminated". + * * Subscription timer expires: + * pjproject timer expires + * locks dialog + * calls pubsub_on_server_timeout + * pubsub_on_server_timeout checks state == NORMAL + * sets TERMINATE_PENDING + * pushes serialized_pubsub_on_refresh_timeout + * returns to pjproject + * pjproject unlocks dialog + * serialized_pubsub_on_refresh_timeout starts + * See (1) Above * - * However, the double-terminated state changes don't happen in all cases. For - * instance, if a subscription expires, then the only time this callback is - * called is when we send the NOTIFY to end the subscription. * - * As far as state changes are concerned, we only ever care about transitions - * to the "terminated" state. The action we take here is dependent on the - * conditions behind why the state change to "terminated" occurred. If the - * state change has occurred because we are sending a NOTIFY to end the - * subscription, we consider this to be the final hurrah of the subscription - * and take measures to start shutting things down. If the state change to - * terminated occurs for a different reason (e.g. transaction timeout, - * incoming SUBSCRIBE to end the subscription), then we push a task to - * send out a NOTIFY. When that NOTIFY is sent, this callback will be - * called again and we will actually shut down the subscription. The - * subscription tree's last_notify field let's us know if this is being - * called as a result of a terminating NOTIFY or not. + * * ast_sip_subscription_notify is called + * checks state == NORMAL + * if not batched... + * sets TERMINATE_IN_PROGRESS (if terminate is requested) + * calls send_notify + * See (2) Above + * if batched... + * sets TERMINATE_PENDING + * schedules task + * scheduler runs sched_task + * sched_task pushes serialized_send_notify + * serialized_send_notify starts + * checks state <= TERMINATE_PENDING + * if state == TERMINATE_PENDING set state = TERMINATE_IN_PROGRESS + * call send_notify + * See (2) Above * - * There is no guarantee that this function will be called from a serializer - * thread since it can be called due to a transaction timeout. Therefore - * synchronization primitives are necessary to ensure that no operations - * step on each others' toes. The dialog lock is always held when this - * callback is called, so we ensure that relevant structures that may - * be touched in this function are always protected by the dialog lock - * elsewhere as well. The dialog lock in particular protects + */ + +/*! + * \brief PJSIP callback when underlying SIP subscription changes state * - * \li The subscription tree's last_notify field - * \li The subscription tree's evsub pointer + * Although this function is called for every state change, we only care + * about the TERMINATED state, and only when we're actually processing the final + * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS). In this case, we do all + * the subscription tree cleanup tasks and decrement the evsub reference. */ static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event) { @@ -3345,51 +3381,55 @@ static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event) } sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); - if (!sub_tree) { + if (!sub_tree || sub_tree->state != SIP_SUB_TREE_TERMINATE_IN_PROGRESS) { + ast_debug(1, "Possible terminate race prevented %p\n", sub_tree); return; } - if (!sub_tree->last_notify) { - if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_server_timeout, ao2_bump(sub_tree))) { - ast_log(LOG_ERROR, "Failed to push task to send final NOTIFY.\n"); - ao2_ref(sub_tree, -1); - } else { - return; - } - } - remove_subscription(sub_tree); + pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL); + +#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK + pjsip_evsub_dec_ref(sub_tree->evsub); +#endif + sub_tree->evsub = NULL; + ast_sip_dialog_set_serializer(sub_tree->dlg, NULL); ast_sip_dialog_set_endpoint(sub_tree->dlg, NULL); + subscription_persistence_remove(sub_tree); shutdown_subscriptions(sub_tree->root); + sub_tree->state = SIP_SUB_TREE_TERMINATED; /* Remove evsub's reference to the sub_tree */ ao2_ref(sub_tree, -1); } -static int serialized_pubsub_on_rx_refresh(void *userdata) +static int serialized_pubsub_on_refresh_timeout(void *userdata) { struct sip_subscription_tree *sub_tree = userdata; pjsip_dialog *dlg = sub_tree->dlg; pjsip_dlg_inc_lock(dlg); - if (!sub_tree->evsub) { + if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) { + ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree->evsub, sub_tree->state); pjsip_dlg_dec_lock(dlg); + ao2_cleanup(sub_tree); return 0; } - if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) { + if (sub_tree->state == SIP_SUB_TREE_TERMINATE_PENDING) { + sub_tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS; set_state_terminated(sub_tree->root); } send_notify(sub_tree, 1); ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? - "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED", - "Resource: %s", sub_tree->root->resource); + "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED", + "Resource: %s", sub_tree->root->resource); pjsip_dlg_dec_lock(dlg); ao2_cleanup(sub_tree); @@ -3402,10 +3442,8 @@ static int serialized_pubsub_on_rx_refresh(void *userdata) * This includes both SUBSCRIBE requests that actually refresh the subscription * as well as SUBSCRIBE requests that end the subscription. * - * In the case where the SUBSCRIBE is actually refreshing the subscription we - * push a task to send an appropriate NOTIFY request. In the case where the - * SUBSCRIBE is ending the subscription, we let the pubsub_on_evsub_state - * callback take care of sending the terminal NOTIFY request instead. + * In either case we push serialized_pubsub_on_refresh_timeout to send an + * appropriate NOTIFY request. */ static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) @@ -3413,18 +3451,24 @@ static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata, struct sip_subscription_tree *sub_tree; sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); - if (!sub_tree) { + if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) { + ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree, sub_tree ? sub_tree->state : -1 ); return; } /* PJSIP will set the evsub's state to terminated before calling into this function * if the Expires value of the incoming SUBSCRIBE is 0. */ - if (pjsip_evsub_get_state(sub_tree->evsub) != PJSIP_EVSUB_STATE_TERMINATED) { - if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_rx_refresh, ao2_bump(sub_tree))) { - /* If we can't push the NOTIFY refreshing task...we'll just go with it. */ - ao2_ref(sub_tree, -1); - } + + if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) { + sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING; + } + + if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_refresh_timeout, ao2_bump(sub_tree))) { + /* If we can't push the NOTIFY refreshing task...we'll just go with it. */ + ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n"); + sub_tree->state = SIP_SUB_TREE_NORMAL; + ao2_ref(sub_tree, -1); } if (sub_tree->is_list) { @@ -3435,9 +3479,9 @@ static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata, static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) { - struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); + struct ast_sip_subscription *sub; - if (!sub) { + if (!(sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) { return; } @@ -3450,45 +3494,62 @@ static int serialized_pubsub_on_client_refresh(void *userdata) struct sip_subscription_tree *sub_tree = userdata; pjsip_tx_data *tdata; + if (!sub_tree->evsub) { + ao2_cleanup(sub_tree); + return 0; + } + if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) { pjsip_evsub_send_request(sub_tree->evsub, tdata); } else { pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); } + ao2_cleanup(sub_tree); return 0; } static void pubsub_on_client_refresh(pjsip_evsub *evsub) { - struct sip_subscription_tree *sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); + struct sip_subscription_tree *sub_tree; + + if (!(sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) { + return; + } - ao2_ref(sub_tree, +1); - ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_client_refresh, sub_tree); + if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_client_refresh, ao2_bump(sub_tree))) { + ao2_cleanup(sub_tree); + } } static void pubsub_on_server_timeout(pjsip_evsub *evsub) { + struct sip_subscription_tree *sub_tree; - struct sip_subscription_tree *sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); - if (!sub_tree) { - /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE - * with Expires: 0 arrives to end a subscription, nor does it terminate - * this timer when we send a NOTIFY request in response to receiving such - * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the - * NOTIFY transaction has finished (either through receiving a response - * or through a transaction timeout). - * - * Therefore, it is possible that we can be told that a server timeout - * occurred after we already thought that the subscription had been - * terminated. In such a case, we will have already removed the sub_tree - * from the evsub's mod_data array. - */ + /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE + * with Expires: 0 arrives to end a subscription, nor does it terminate + * this timer when we send a NOTIFY request in response to receiving such + * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the + * NOTIFY transaction has finished (either through receiving a response + * or through a transaction timeout). + * + * Therefore, it is possible that we can be told that a server timeout + * occurred after we already thought that the subscription had been + * terminated. In such a case, we will have already removed the sub_tree + * from the evsub's mod_data array. + */ + + sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); + if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) { + ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree, sub_tree ? sub_tree->state : -1 ); return; } - ao2_ref(sub_tree, +1); - ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_server_timeout, sub_tree); + sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING; + if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_refresh_timeout, ao2_bump(sub_tree))) { + sub_tree->state = SIP_SUB_TREE_NORMAL; + ao2_cleanup(sub_tree); + } } static int ami_subscription_detail(struct sip_subscription_tree *sub_tree, diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 2cc18bfa8d7..67ac04d4d86 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -44,4 +44,5 @@ AC_DEFUN([PJPROJECT_CONFIGURE], PJPROJECT_SYMBOL_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_from_files2], [pjlib.h]) PJPROJECT_SYMBOL_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip_endpt_set_ext_resolver], [pjsip.h]) AC_DEFINE([HAVE_PJSIP_TLS_TRANSPORT_PROTO], 1, [Define if your system has PJSIP_TLS_TRANSPORT_PROTO]) + AC_DEFINE([HAVE_PJSIP_EVSUB_GRP_LOCK], 1, [Define if your system has PJSIP_EVSUB_GRP_LOCK]) ]) diff --git a/third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch b/third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch new file mode 100644 index 00000000000..d2a47c6c5b6 --- /dev/null +++ b/third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch @@ -0,0 +1,73 @@ +From a5030c9b33b2c936879fbacb1d2ea5edc2979181 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Sat, 18 Jun 2016 10:14:34 -0600 +Subject: [PATCH] evsub: Add APIs to add/decrement an event subscription's + group lock + +These APIs can be used to ensure that the evsub isn't destroyed before +an application is finished using it. +--- + pjsip/include/pjsip-simple/evsub.h | 20 ++++++++++++++++++++ + pjsip/src/pjsip-simple/evsub.c | 14 ++++++++++++++ + 2 files changed, 34 insertions(+) + +diff --git a/pjsip/include/pjsip-simple/evsub.h b/pjsip/include/pjsip-simple/evsub.h +index 2dc4d69..31f85f8 100644 +--- a/pjsip/include/pjsip-simple/evsub.h ++++ b/pjsip/include/pjsip-simple/evsub.h +@@ -490,6 +490,26 @@ PJ_DECL(void) pjsip_evsub_set_mod_data( pjsip_evsub *sub, unsigned mod_id, + PJ_DECL(void*) pjsip_evsub_get_mod_data( pjsip_evsub *sub, unsigned mod_id ); + + ++/** ++ * Increment the event subscription's group lock. ++ * ++ * @param sub The server subscription instance. ++ * ++ * @return PJ_SUCCESS on success. ++ */ ++PJ_DEF(pj_status_t) pjsip_evsub_add_ref(pjsip_evsub *sub); ++ ++ ++/** ++ * Decrement the event subscription's group lock. ++ * ++ * @param sub The server subscription instance. ++ * ++ * @return PJ_SUCCESS on success. ++ */ ++PJ_DEF(pj_status_t) pjsip_evsub_dec_ref(pjsip_evsub *sub); ++ ++ + + PJ_END_DECL + +diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c +index 7cd8859..68a9564 100644 +--- a/pjsip/src/pjsip-simple/evsub.c ++++ b/pjsip/src/pjsip-simple/evsub.c +@@ -831,7 +831,21 @@ static pj_status_t evsub_create( pjsip_dialog *dlg, + return PJ_SUCCESS; + } + ++/* ++ * Increment the event subscription's group lock. ++ */ ++PJ_DEF(pj_status_t) pjsip_evsub_add_ref(pjsip_evsub *sub) ++{ ++ return pj_grp_lock_add_ref(sub->grp_lock); ++} + ++/* ++ * Decrement the event subscription's group lock. ++ */ ++PJ_DEF(pj_status_t) pjsip_evsub_dec_ref(pjsip_evsub *sub) ++{ ++ return pj_grp_lock_dec_ref(sub->grp_lock); ++} + + /* + * Create client subscription session. +-- +2.5.5 + From f572b264958eef821234215bba50933b2e740aef Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 21 Jun 2016 17:42:28 -0500 Subject: [PATCH 0521/1578] res_pjproject.c: Replace inlined DEBUG_ATLEAST() with macro. Change-Id: I8799fb0a347ad76e747dafd0eacf1ea1086b9a8c --- res/res_pjproject.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 9ed3d57a199..151c99603d3 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -177,7 +177,6 @@ static void log_forwarder(int level, const char *data, int len) const char * log_source = "pjproject"; int log_line = 0; const char *log_func = ""; - int mod_level; if (pjproject_log_intercept.fd != -1 && pjproject_log_intercept.thread == pthread_self()) { @@ -196,10 +195,8 @@ static void log_forwarder(int level, const char *data, int len) } if (ast_level == __LOG_DEBUG) { - /* For levels 3 and up, obey the debug level for res_pjproject */ - mod_level = ast_opt_dbg_module ? - ast_debug_get_by_module("res_pjproject") : 0; - if (option_debug < level && mod_level < level) { + /* Obey the debug level for res_pjproject */ + if (!DEBUG_ATLEAST(level)) { return; } } From 804005d2517e8772d432a4bd3048030decb66cf4 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Tue, 21 Jun 2016 13:52:20 +0200 Subject: [PATCH 0522/1578] res_rtp_asterisk: fix memory leak in dtls ensure that cert bios get freed after creating the fingerprint ASTERISK-26129 #close Change-Id: I44d23aea07dce80176ca1ff877c5ace9452ef451 --- res/res_rtp_asterisk.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 1bf16941dcb..119e45d878b 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1398,7 +1398,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con if (!ast_strlen_zero(dtls_cfg->certfile)) { char *private = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile; BIO *certbio; - X509 *cert; + X509 *cert = NULL; const EVP_MD *type; unsigned int size, i; unsigned char fingerprint[EVP_MAX_MD_SIZE]; @@ -1440,6 +1440,9 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n", dtls_cfg->certfile, instance); BIO_free_all(certbio); + if (cert) { + X509_free(cert); + } return -1; } @@ -1451,6 +1454,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con *(local_fingerprint-1) = 0; BIO_free_all(certbio); + X509_free(cert); } if (!ast_strlen_zero(dtls_cfg->cipher)) { From 5f23aacda418afc377b0ab7d66645d0ccd6fdc0f Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 22 Jun 2016 17:55:05 +0200 Subject: [PATCH 0523/1578] BuildSystem: Avoid obsolete warning with AC_FUNC_SETVBUF_REVERSED on autoconf. Removed the obsolete macro AC_FUNC_SETVBUF_REVERSED because Asterisk does not support the platform SVR2 from the year 1987 anymore. ASTERISK-26046 Change-Id: I28161b037feb2d29ab46ed20e785928460226c22 --- configure | 7 ------- configure.ac | 1 - 2 files changed, 8 deletions(-) diff --git a/configure b/configure index 04183b401c2..b7c8a91f801 100755 --- a/configure +++ b/configure @@ -15311,13 +15311,6 @@ _ACEOF rm -f conftest* -if ${ac_cv_func_setvbuf_reversed+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_func_setvbuf_reversed=no -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if ${ac_cv_type_signal+:} false; then : diff --git a/configure.ac b/configure.ac index 2c47dc453d1..08238e44eaa 100644 --- a/configure.ac +++ b/configure.ac @@ -686,7 +686,6 @@ AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_FUNC_MMAP AC_FUNC_SELECT_ARGTYPES -AC_FUNC_SETVBUF_REVERSED AC_TYPE_SIGNAL AC_FUNC_STAT AC_FUNC_STRCOLL From 3b4f5d1345a1bf143136b5523ea39e6397910fdd Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 22 Jun 2016 09:51:14 -0600 Subject: [PATCH 0524/1578] test_res_pjsip_scheduler: Add 'depends' on pjproject in MODULEINFO Since the file was missing the depends on pjproject, it wasn't picking up the pjproject related include path. If there was no system installed pjproject and pjproject-bundled was used, a compile would fail because pjsip.h wasn't found. ASTERISK-26139 #close Change-Id: I2ee64a999051452bc198c4e2c168c70769cd3757 --- tests/test_res_pjsip_scheduler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_res_pjsip_scheduler.c b/tests/test_res_pjsip_scheduler.c index 22d2c99ce9f..cc5313fd6fd 100644 --- a/tests/test_res_pjsip_scheduler.c +++ b/tests/test_res_pjsip_scheduler.c @@ -26,6 +26,7 @@ /*** MODULEINFO TEST_FRAMEWORK + pjproject res_pjsip core ***/ From b6bd97eea2ddeba2b0ea2380da29fba98b8a3208 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 20 Jun 2016 13:21:52 -0500 Subject: [PATCH 0525/1578] Fix Alembic upgrades. A non-existent constraint was being referenced in the upgrade script. This patch corrects the problem by removing the reference. In addition, the head of the alembic branch referred to a non-existent revision. This has been fixed by referring to the proper revision. This patch fixes another realtime problem as well. Our Alembic scripts store booleans as yes or no values. However, Sorcery tries to insert "true" or "false" instead. This patch introduces a new boolean type that translates to "yes" or "no" instead. ASTERISK-26128 #close Change-Id: I51574736a881189de695a824883a18d66a52dcef --- ...184_res_pjsip_add_contact_via_addr_and_.py | 2 +- ...b01a191a46_pjsip_add_contact_reg_server.py | 2 -- include/asterisk/config_options.h | 23 +++++++++++++++++++ main/config_options.c | 5 ++++ main/sorcery.c | 7 ++++++ res/res_pjsip/location.c | 2 +- 6 files changed, 37 insertions(+), 4 deletions(-) diff --git a/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py b/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py index 893d9d82e7a..77242ac4b3f 100644 --- a/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py +++ b/contrib/ast-db-manage/config/versions/6d8c104e6184_res_pjsip_add_contact_via_addr_and_.py @@ -8,7 +8,7 @@ # revision identifiers, used by Alembic. revision = 'a845e4d8ade8' -down_revision = 'bca7113d796f' +down_revision = 'd7e3c73eb2bf' from alembic import op import sqlalchemy as sa diff --git a/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py index 0318b9a4fcf..0919370ba66 100644 --- a/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py +++ b/contrib/ast-db-manage/config/versions/81b01a191a46_pjsip_add_contact_reg_server.py @@ -16,10 +16,8 @@ def upgrade(): op.add_column('ps_contacts', sa.Column('reg_server', sa.String(20))) - op.drop_constraint('id', 'ps_contacts', type_='unique') op.create_unique_constraint('ps_contacts_uq', 'ps_contacts', ['id','reg_server']) def downgrade(): op.drop_constraint('ps_contacts_uq', 'ps_contacts', type_='unique') op.drop_column('ps_contacts', 'reg_server') - op.create_unique_constraint(None, 'ps_contacts', 'id') diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h index 30c04217637..f2a457eb57a 100644 --- a/include/asterisk/config_options.h +++ b/include/asterisk/config_options.h @@ -445,6 +445,29 @@ enum aco_option_type { * {endcode} */ OPT_UINT_T, + + /*! \brief Type for default option handler for bools (ast_true/ast_false) + * \note aco_option_register flags: + * non-zero : process via ast_true + * 0 : process via ast_false + * aco_option_register varargs: + * FLDSET macro with the field of type int. It is important to note that the field + * cannot be a bitfield. If bitfields are required, they must be set via a custom handler. + * + * This is exactly the same as OPT_BOOL_T. The only difference is that when + * translated to a string, OPT_BOOL_T becomes "true" or "false"; OPT_YESNO_T becomes + * "yes" or "no". + * + * Example: + * {code} + * struct test_item { + * int enabled; + * }; + * aco_option_register(&cfg_info, "enabled", ACO_EXACT, my_types, "no", OPT_YESNO_T, 1, FLDSET(struct test_item, enabled)); + * {endcode} + */ + OPT_YESNO_T, + }; /*! \brief A callback function for handling a particular option diff --git a/main/config_options.c b/main/config_options.c index c58dfdd8686..2d2300893dc 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -97,6 +97,7 @@ static char *aco_option_type_string[] = { "IP Address", /* OPT_SOCKADDR_T, */ "String", /* OPT_STRINGFIELD_T, */ "Unsigned Integer", /* OPT_UINT_T, */ + "Boolean", /* OPT_YESNO_T, */ }; void *aco_pending_config(struct aco_info *info) @@ -139,6 +140,10 @@ static aco_option_handler ast_config_option_default_handler(enum aco_option_type switch(type) { case OPT_ACL_T: return acl_handler_fn; case OPT_BOOL_T: return bool_handler_fn; + /* Reading from config files, BOOL and YESNO are handled exactly the + * same. Their difference is in how they are rendered to users + */ + case OPT_YESNO_T: return bool_handler_fn; case OPT_BOOLFLAG_T: return boolflag_handler_fn; case OPT_CHAR_ARRAY_T: return chararray_handler_fn; case OPT_CODEC_T: return codec_handler_fn; diff --git a/main/sorcery.c b/main/sorcery.c index 6a7b54bbf31..a739f5eb8cf 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -293,6 +293,12 @@ static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf) return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0; } +static int yesno_handler_fn(const void *obj, const intptr_t *args, char **buf) +{ + unsigned int *field = (unsigned int *)(obj + args[0]); + return !(*buf = ast_strdup(*field ? "yes" : "no")) ? -1 : 0; +} + static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf) { struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]); @@ -316,6 +322,7 @@ static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type { switch(type) { case OPT_BOOL_T: return bool_handler_fn; + case OPT_YESNO_T: return yesno_handler_fn; case OPT_CHAR_ARRAY_T: return chararray_handler_fn; case OPT_CODEC_T: return codec_handler_fn; case OPT_DOUBLE_T: return double_handler_fn; diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 8f8c030c35f..4f8f56fca0e 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1133,7 +1133,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400); ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout)); - ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify)); + ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify)); ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); From c7309a525484f0509e940f01d630dbe2efe093ea Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 22 Jun 2016 09:37:23 -0600 Subject: [PATCH 0526/1578] chan_unistim: Fix memcpy in get_to_address A code block only enabled when HAVE_PKTINFO is not defined (FreeBSD) was using a pointer to a pointer as the destination of a memcpy and a '&' instead of '*' in the sizeof. ASTERISK-26138 #close Change-Id: Id4927ff256c0e470bdf7bcfc025146a2f656e708 --- channels/chan_unistim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index c96a9c087cd..973f3522b5e 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -1021,7 +1021,7 @@ static int get_to_address(int fd, struct sockaddr_in *toAddr) memcpy(&toAddr->sin_addr, &ip_msg.address, sizeof(struct in_addr)); return err; #else - memcpy(&toAddr, &public_ip, sizeof(&toAddr)); + memcpy(toAddr, &public_ip, sizeof(*toAddr)); return 0; #endif } From d293ead07726cd8cee8b5277c2536db7d50cbabd Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 22 Jun 2016 12:41:57 -0600 Subject: [PATCH 0527/1578] res_rtp_asterisk: Fix a self-comparison identified by gcc 6 gcc 6 caught a previously unidentified self-comparison in ice_candidate_cmp. Fixed it and re-ordered the predicates for better short-circuiting. ASTERISK-26140 #close Change-Id: I3da713c568e24064430257b3502fbdafd35af7a7 --- res/res_rtp_asterisk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 119e45d878b..79aab1697c8 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -540,8 +540,8 @@ static int ice_candidate_cmp(void *obj, void *arg, int flags) if (strcmp(candidate1->foundation, candidate2->foundation) || candidate1->id != candidate2->id || - ast_sockaddr_cmp(&candidate1->address, &candidate2->address) || - candidate1->type != candidate1->type) { + candidate1->type != candidate2->type || + ast_sockaddr_cmp(&candidate1->address, &candidate2->address)) { return 0; } From 6fa3ed067957e580e208ead7a62a095ac26f5fa9 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Wed, 22 Jun 2016 15:25:23 -0400 Subject: [PATCH 0528/1578] res_pjsip: improve realtime performance #2 The patch removes updating all Endpoints' status on startup. Instead, only non-qualified aors with static contact and non-qualified non-expired contacts are retrieved from the realtime to update the endpoint status to ONLINE. The endpoint name was added to the contact object to simply find the endpoint that created this contact. The status of endpoints with qualified aors will be updated by 'qualify' functions. ASTERISK-26061 #close Change-Id: Id324c1776fa55d3741e0c5457ecac0304cb1a0df --- ...64_ps_contacts_add_endpoint_and_modify_.py | 33 +++++ include/asterisk/res_pjsip.h | 12 ++ res/res_pjsip.c | 6 + res/res_pjsip/location.c | 6 + res/res_pjsip/pjsip_configuration.c | 126 +++++++++++------ res/res_pjsip/pjsip_options.c | 128 +++++++++++++++++- 6 files changed, 265 insertions(+), 46 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py diff --git a/contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py b/contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py new file mode 100644 index 00000000000..ff18343290d --- /dev/null +++ b/contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py @@ -0,0 +1,33 @@ +"""ps_contacts add endpoint and modify expiration_time to bigint + +Revision ID: ef7efc2d3964 +Revises: a845e4d8ade8 +Create Date: 2016-06-02 18:18:46.231920 + +""" + +# revision identifiers, used by Alembic. +revision = 'ef7efc2d3964' +down_revision = 'a845e4d8ade8' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + context = op.get_context() + + op.add_column('ps_contacts', sa.Column('endpoint', sa.String(40))) + + if context.bind.dialect.name != 'postgresql': + op.alter_column('ps_contacts', 'expiration_time', type_=sa.BigInteger) + else: + op.execute('ALTER TABLE ps_contacts ALTER COLUMN expiration_time TYPE BIGINT USING expiration_time::bigint') + + op.create_index('ps_contacts_qualifyfreq_exptime', 'ps_contacts', ['qualify_frequency', 'expiration_time']) + op.create_index('ps_aors_qualifyfreq_contact', 'ps_aors', ['qualify_frequency', 'contact']) +def downgrade(): + op.drop_index('ps_aors_qualifyfreq_contact') + op.drop_index('ps_contacts_qualifyfreq_exptime') + op.drop_column('ps_contacts', 'endpoint') + op.alter_column('ps_contacts', 'expiration_time', type_=sa.String(40)) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index d1f0c9825b4..f9f9e2037eb 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -256,6 +256,8 @@ struct ast_sip_contact { int via_port; /*! Content of the Call-ID header in REGISTER request */ AST_STRING_FIELD_EXTENDED(call_id); + /*! The name of the endpoint that added the contact */ + AST_STRING_FIELD_EXTENDED(endpoint_name); }; #define CONTACT_STATUS "contact_status" @@ -977,6 +979,16 @@ void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier * */ void *ast_sip_endpoint_alloc(const char *name); +/*! + * \brief Change state of a persistent endpoint. + * + * \param endpoint The SIP endpoint name to change state. + * \param state The new state + * \retval 0 Success + * \retval -1 Endpoint not found + */ +int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state); + /*! * \brief Get a pointer to the PJSIP endpoint. * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 9944702c350..12bb930b566 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1169,6 +1169,12 @@ REGISTER requests and is not intended to be configured manually. + + Endpoint name + + The name of the endpoint this contact belongs to + + Asterisk Server name diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 8f8c030c35f..aad76a69476 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -121,6 +121,7 @@ static void *contact_alloc(const char *name) return NULL; } + ast_string_field_init_extended(contact, endpoint_name); ast_string_field_init_extended(contact, reg_server); ast_string_field_init_extended(contact, via_addr); ast_string_field_init_extended(contact, call_id); @@ -352,6 +353,10 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri contact->endpoint = ao2_bump(endpoint); + if (endpoint) { + ast_string_field_set(contact, endpoint_name, ast_sorcery_object_get_id(endpoint)); + } + return ast_sorcery_create(ast_sip_get_sorcery(), contact); } @@ -1136,6 +1141,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify)); ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); + ast_sorcery_object_field_register(sorcery, "contact", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, endpoint_name)); ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); ast_sorcery_object_field_register(sorcery, "contact", "via_addr", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, via_addr)); ast_sorcery_object_field_register(sorcery, "contact", "via_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact, via_port)); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 3c4949573a6..8a5ff416ad6 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -58,6 +58,53 @@ static int persistent_endpoint_cmp(void *obj, void *arg, int flags) return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0; } +/*! \brief Internal function for changing the state of an endpoint */ +static void endpoint_update_state(struct ast_endpoint *endpoint, enum ast_endpoint_state state) +{ + struct ast_json *blob; + char *regcontext; + + /* If there was no state change, don't publish anything. */ + if (ast_endpoint_get_state(endpoint) == state) { + return; + } + + regcontext = ast_sip_get_regcontext(); + + if (state == AST_ENDPOINT_ONLINE) { + ast_endpoint_set_state(endpoint, AST_ENDPOINT_ONLINE); + blob = ast_json_pack("{s: s}", "peer_status", "Reachable"); + + if (!ast_strlen_zero(regcontext)) { + if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL)) { + ast_add_extension(regcontext, 1, ast_endpoint_get_resource(endpoint), 1, NULL, NULL, + "Noop", ast_strdup(ast_endpoint_get_resource(endpoint)), ast_free_ptr, "SIP"); + } + } + + ast_verb(2, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint)); + } else { + ast_endpoint_set_state(endpoint, AST_ENDPOINT_OFFLINE); + blob = ast_json_pack("{s: s}", "peer_status", "Unreachable"); + + if (!ast_strlen_zero(regcontext)) { + struct pbx_find_info q = { .stacklen = 0 }; + + if (pbx_find_extension(NULL, NULL, &q, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL, "", E_MATCH)) { + ast_context_remove_extension(regcontext, ast_endpoint_get_resource(endpoint), 1, NULL); + } + } + + ast_verb(2, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint)); + } + + ast_free(regcontext); + + ast_endpoint_blob_publish(endpoint, ast_endpoint_state_type(), blob); + ast_json_unref(blob); + ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint)); +} + /*! \brief Callback function for changing the state of an endpoint */ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) { @@ -69,7 +116,6 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) struct ao2_iterator i; struct ast_sip_contact *contact; enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; - char *regcontext; if (status) { char rtt[32]; @@ -113,45 +159,7 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) ao2_ref(contacts, -1); } - /* If there was no state change, don't publish anything. */ - if (ast_endpoint_get_state(endpoint) == state) { - return 0; - } - - regcontext = ast_sip_get_regcontext(); - - if (state == AST_ENDPOINT_ONLINE) { - ast_endpoint_set_state(endpoint, AST_ENDPOINT_ONLINE); - blob = ast_json_pack("{s: s}", "peer_status", "Reachable"); - - if (!ast_strlen_zero(regcontext)) { - if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL)) { - ast_add_extension(regcontext, 1, ast_endpoint_get_resource(endpoint), 1, NULL, NULL, - "Noop", ast_strdup(ast_endpoint_get_resource(endpoint)), ast_free_ptr, "SIP"); - } - } - - ast_verb(2, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint)); - } else { - ast_endpoint_set_state(endpoint, AST_ENDPOINT_OFFLINE); - blob = ast_json_pack("{s: s}", "peer_status", "Unreachable"); - - if (!ast_strlen_zero(regcontext)) { - struct pbx_find_info q = { .stacklen = 0 }; - - if (pbx_find_extension(NULL, NULL, &q, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL, "", E_MATCH)) { - ast_context_remove_extension(regcontext, ast_endpoint_get_resource(endpoint), 1, NULL); - } - } - - ast_verb(2, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint)); - } - - ast_free(regcontext); - - ast_endpoint_blob_publish(endpoint, ast_endpoint_state_type(), blob); - ast_json_unref(blob); - ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint)); + endpoint_update_state(endpoint,state); return 0; } @@ -1181,6 +1189,20 @@ static void persistent_endpoint_destroy(void *obj) ast_free(persistent->aors); } +int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state) +{ + RAII_VAR(struct sip_persistent_endpoint *, persistent, NULL, ao2_cleanup); + SCOPED_AO2LOCK(lock, persistent_endpoints); + + if (!(persistent = ao2_find(persistent_endpoints, endpoint_name, OBJ_KEY | OBJ_NOLOCK))) { + return -1; + } + + endpoint_update_state(persistent->endpoint, state); + + return 0; +} + /*! \brief Internal function which finds (or creates) persistent endpoint information */ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_sip_endpoint *endpoint) { @@ -1198,11 +1220,7 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_ persistent->aors = ast_strdup(endpoint->aors); - if (ast_strlen_zero(persistent->aors)) { - ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN); - } else { - persistent_endpoint_update_state(persistent, NULL, 0); - } + ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN); ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK); } @@ -1683,6 +1701,22 @@ static struct ast_cli_entry cli_commands[] = { struct ast_sip_cli_formatter_entry *channel_formatter; struct ast_sip_cli_formatter_entry *endpoint_formatter; +static int on_load_endpoint(void *obj, void *arg, int flags) +{ + return sip_endpoint_apply_handler(sip_sorcery, obj); +} + +static void load_all_endpoints(void) +{ + struct ao2_container *endpoints; + + endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (endpoints) { + ao2_callback(endpoints, OBJ_NODATA, on_load_endpoint, NULL); + ao2_ref(endpoints, -1); + } +} + int ast_res_pjsip_initialize_configuration(void) { if (ast_manager_register_xml(AMI_SHOW_ENDPOINTS, EVENT_FLAG_SYSTEM, ami_show_endpoints) || @@ -1885,6 +1919,8 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_load(sip_sorcery); + load_all_endpoints(); + return 0; } diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 381de37545c..dc3bce06f1d 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -330,7 +330,12 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con if (endpoint) { endpoint_local = ao2_bump(endpoint); } else { - endpoint_local = find_an_endpoint(contact); + if (!ast_strlen_zero(contact->endpoint_name)) { + endpoint_local = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", contact->endpoint_name); + } + if (!endpoint_local) { + endpoint_local = find_an_endpoint(contact); + } if (!endpoint_local) { ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n", contact->uri); @@ -1240,6 +1245,126 @@ static const struct ast_sorcery_observer observer_callbacks_options = { .deleted = aor_observer_deleted }; +static int aor_update_endpoint_state(void *obj, void *arg, int flags) +{ + struct ast_sip_endpoint *endpoint = obj; + const char *endpoint_name = ast_sorcery_object_get_id(endpoint); + char *aor = arg; + char *endpoint_aor; + char *endpoint_aors; + + if (ast_strlen_zero(aor) || ast_strlen_zero(endpoint->aors)) { + return 0; + } + + endpoint_aors = ast_strdupa(endpoint->aors); + while ((endpoint_aor = ast_strip(strsep(&endpoint_aors, ",")))) { + if (!strcmp(aor, endpoint_aor)) { + if (ast_sip_persistent_endpoint_update_state(endpoint_name, AST_ENDPOINT_ONLINE) == -1) { + ast_log(LOG_WARNING, "Unable to find persistent endpoint '%s' for aor '%s'\n", + endpoint_name, aor); + } + } + } + + return 0; +} + +static int on_aor_update_endpoint_state(void *obj, void *arg, int flags) +{ + struct ast_sip_aor *aor = obj; + struct ao2_container *endpoints; + RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy); + const char *aor_name = ast_sorcery_object_get_id(aor); + char *aor_like; + + if (ast_strlen_zero(aor_name)) { + return -1; + } + + if (aor->permanent_contacts && ((int)(aor->qualify_frequency * 1000)) <= 0) { + aor_like = ast_alloca(strlen(aor_name) + 3); + sprintf(aor_like, "%%%s%%", aor_name); + var = ast_variable_new("aors LIKE", aor_like, ""); + if (!var) { + return -1; + } + endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var); + + if (endpoints) { + /* + * Because aors are a string list, we have to use a pattern match but since a simple + * pattern match could return an endpoint that has an aor of "aaabccc" when searching + * for "abc", we still have to iterate over them to find an exact aor match. + */ + ao2_callback(endpoints, 0, aor_update_endpoint_state, (char *)aor_name); + ao2_ref(endpoints, -1); + } + } + + return 0; +} + +static int contact_update_endpoint_state(void *obj, void *arg, int flags) +{ + const struct ast_sip_contact *contact = obj; + struct timeval tv = ast_tvnow(); + + if (!ast_strlen_zero(contact->endpoint_name) && ((int)(contact->qualify_frequency * 1000)) <= 0 && + contact->expiration_time.tv_sec > tv.tv_sec) { + + if (ast_sip_persistent_endpoint_update_state(contact->endpoint_name, AST_ENDPOINT_ONLINE) == -1) { + ast_log(LOG_WARNING, "Unable to find persistent endpoint '%s' for contact '%s/%s'\n", + contact->endpoint_name, contact->aor, contact->uri); + return -1; + } + } + + return 0; +} + +static void update_all_unqualified_endpoints(void) +{ + struct ao2_container *aors; + struct ao2_container *contacts; + RAII_VAR(struct ast_variable *, var_aor, NULL, ast_variables_destroy); + RAII_VAR(struct ast_variable *, var_contact, NULL, ast_variables_destroy); + RAII_VAR(char *, time_now, NULL, ast_free); + struct timeval tv = ast_tvnow(); + + if (!(var_aor = ast_variable_new("contact !=", "", ""))) { + return; + } + if (!(var_aor->next = ast_variable_new("qualify_frequency <=", "0", ""))) { + return; + } + + if (ast_asprintf(&time_now, "%ld", tv.tv_sec) == -1) { + return; + } + if (!(var_contact = ast_variable_new("expiration_time >", time_now, ""))) { + return; + } + if (!(var_contact->next = ast_variable_new("qualify_frequency <=", "0", ""))) { + return; + } + + aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "aor", AST_RETRIEVE_FLAG_MULTIPLE, var_aor); + if (aors) { + ao2_callback(aors, OBJ_NODATA, on_aor_update_endpoint_state, NULL); + ao2_ref(aors, -1); + } + + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "contact", AST_RETRIEVE_FLAG_MULTIPLE, var_contact); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, contact_update_endpoint_state, NULL); + ao2_ref(contacts, -1); + } +} + int ast_res_pjsip_init_options_handling(int reload) { static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 }; @@ -1281,6 +1406,7 @@ int ast_res_pjsip_init_options_handling(int reload) ast_manager_register_xml("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify); ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options)); + update_all_unqualified_endpoints(); qualify_and_schedule_all(); return 0; From 8c7017f76e06644e6a0ad5e363465cd06c89078e Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 22 Jun 2016 16:04:54 -0400 Subject: [PATCH 0529/1578] res_fax: Fix reference leak in fax_v21_session_new. fax_v21_session_new created a session details object but only released the allocation reference during error conditions. fax_session_new adds it's own reference to details if needed so the caller is always responsible for cleaning it's own reference. ASTERISK-26141 #close Change-Id: Ie7fc52a83b6596ce9ce2d5a2bd9f3e204f48fc88 --- res/res_fax.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/res/res_fax.c b/res/res_fax.c index c8ff1e988c6..347168e56be 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -2846,11 +2846,8 @@ static struct ast_fax_session *fax_v21_session_new (struct ast_channel *chan) { } v21_details->caps = AST_FAX_TECH_V21_DETECT; - if (!(v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { - ao2_ref(v21_details, -1); - return NULL; - } - + v21_session = fax_session_new(v21_details, chan, NULL, NULL); + ao2_ref(v21_details, -1); return v21_session; } From 6e87bf746a268a3364863bec7e2de1e208a5c4b2 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 23 Jun 2016 11:33:06 +0200 Subject: [PATCH 0530/1578] BuildSystem: Avoid obsolete warning with AC_TYPE_SIGNAL on autoconf. Removed the obsolete macro AC_TYPE_SIGNAL because Asterisk does not use K&R C but requires ANSI C anyway. ASTERISK-26046 Change-Id: I914c014385e1862102d90fe7650621def78db02e --- configure | 33 -------------------------------- configure.ac | 1 - include/asterisk/autoconfig.h.in | 3 --- 3 files changed, 37 deletions(-) diff --git a/configure b/configure index b7c8a91f801..0fc13a8fee5 100755 --- a/configure +++ b/configure @@ -15311,39 +15311,6 @@ _ACEOF rm -f conftest* -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 -$as_echo_n "checking return type of signal handlers... " >&6; } -if ${ac_cv_type_signal+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -int -main () -{ -return *(signal (0, 0)) (0) == 1; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_type_signal=int -else - ac_cv_type_signal=void -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 -$as_echo "$ac_cv_type_signal" >&6; } - -cat >>confdefs.h <<_ACEOF -#define RETSIGTYPE $ac_cv_type_signal -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 $as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then : diff --git a/configure.ac b/configure.ac index 08238e44eaa..2969321f32c 100644 --- a/configure.ac +++ b/configure.ac @@ -686,7 +686,6 @@ AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_FUNC_MMAP AC_FUNC_SELECT_ARGTYPES -AC_TYPE_SIGNAL AC_FUNC_STAT AC_FUNC_STRCOLL AC_FUNC_STRFTIME diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 72242122828..803c37b2c94 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -1254,9 +1254,6 @@ /* Define if your system needs braces around PTHREAD_ONCE_INIT */ #undef PTHREAD_ONCE_INIT_NEEDS_BRACES -/* Define as the return type of signal handlers (`int' or `void'). */ -#undef RETSIGTYPE - /* Define to the type of arg 1 for `select'. */ #undef SELECT_TYPE_ARG1 From 75818b40848f2ae1e994a173e87b8bf877706c6a Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 22 Jun 2016 13:19:32 -0300 Subject: [PATCH 0531/1578] siren: Add format attribute modules for Siren7 and Siren14. This change removes hardcoded SDP parsing and generation for Siren7 and Siren14 from chan_sip and moves it to format attribute modules so it can also be used by chan_pjsip. With this the fmtp lines for both are added with the bitrate information. ASTERISK-26021 Change-Id: Ibb004eda37a14c0a35ef0613f6237977fc800037 --- channels/chan_sip.c | 26 +--------- res/res_format_attr_siren14.c | 94 +++++++++++++++++++++++++++++++++++ res/res_format_attr_siren7.c | 94 +++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 25 deletions(-) create mode 100644 res/res_format_attr_siren14.c create mode 100644 res/res_format_attr_siren7.c diff --git a/channels/chan_sip.c b/channels/chan_sip.c index a317879e4ba..e086711c2ca 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -11332,25 +11332,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); } - if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) { - if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { - if (bit_rate != 32000) { - ast_log(LOG_WARNING, "Got Siren7 offer at %u bps, but only 32000 bps supported; ignoring.\n", bit_rate); - ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); - } else { - found = TRUE; - } - } - } else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) { - if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { - if (bit_rate != 48000) { - ast_log(LOG_WARNING, "Got Siren14 offer at %u bps, but only 48000 bps supported; ignoring.\n", bit_rate); - ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); - } else { - found = TRUE; - } - } - } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { + if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { if (bit_rate != 64000) { ast_log(LOG_WARNING, "Got G.719 offer at %u bps, but only 64000 bps supported; ignoring.\n", bit_rate); @@ -13009,12 +12991,6 @@ static void add_codec_to_sdp(const struct sip_pvt *p, } else if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we don't support VAD (G.723.1 annex A) */ ast_str_append(a_buf, 0, "a=fmtp:%d annexa=no\r\n", rtp_code); - } else if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) { - /* Indicate that we only expect 32Kbps */ - ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=32000\r\n", rtp_code); - } else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) { - /* Indicate that we only expect 48Kbps */ - ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=48000\r\n", rtp_code); } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we only expect 64Kbps */ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code); diff --git a/res/res_format_attr_siren14.c b/res/res_format_attr_siren14.c new file mode 100644 index 00000000000..335b575980b --- /dev/null +++ b/res/res_format_attr_siren14.c @@ -0,0 +1,94 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Siren14 format attribute interface + * + * \author Joshua Colp + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/module.h" +#include "asterisk/format.h" + +/* Destroy is a required callback and must exist */ +static void siren14_destroy(struct ast_format *format) +{ +} + +/* Clone is a required callback and must exist */ +static int siren14_clone(const struct ast_format *src, struct ast_format *dst) +{ + return 0; +} + +static struct ast_format *siren14_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + unsigned int val; + + if (sscanf(attributes, "bitrate=%30u", &val) == 1) { + if (val != 48000) { + ast_log(LOG_WARNING, "Got siren14 offer at %u bps, but only 48000 bps supported; ignoring.\n", val); + return NULL; + } + } + + /* We aren't modifying the format and once passed back it won't be touched, so use what we were given */ + return ao2_bump((struct ast_format *)format); +} + +static void siren14_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) +{ + ast_str_append(str, 0, "a=fmtp:%u bitrate=48000\r\n", payload); +} + +static struct ast_format_interface siren14_interface = { + .format_destroy = siren14_destroy, + .format_clone = siren14_clone, + .format_parse_sdp_fmtp = siren14_parse_sdp_fmtp, + .format_generate_sdp_fmtp = siren14_generate_sdp_fmtp, +}; + +static int load_module(void) +{ + if (ast_format_interface_register("siren14", &siren14_interface)) { + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Siren14 Format Attribute Module", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND, +); diff --git a/res/res_format_attr_siren7.c b/res/res_format_attr_siren7.c new file mode 100644 index 00000000000..7aef019dabe --- /dev/null +++ b/res/res_format_attr_siren7.c @@ -0,0 +1,94 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Siren7 format attribute interface + * + * \author Joshua Colp + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/module.h" +#include "asterisk/format.h" + +/* Destroy is a required callback and must exist */ +static void siren7_destroy(struct ast_format *format) +{ +} + +/* Clone is a required callback and must exist */ +static int siren7_clone(const struct ast_format *src, struct ast_format *dst) +{ + return 0; +} + +static struct ast_format *siren7_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + unsigned int val; + + if (sscanf(attributes, "bitrate=%30u", &val) == 1) { + if (val != 32000) { + ast_log(LOG_WARNING, "Got Siren7 offer at %u bps, but only 32000 bps supported; ignoring.\n", val); + return NULL; + } + } + + /* We aren't modifying the format and once passed back it won't be touched, so use what we were given */ + return ao2_bump((struct ast_format *)format); +} + +static void siren7_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) +{ + ast_str_append(str, 0, "a=fmtp:%u bitrate=32000\r\n", payload); +} + +static struct ast_format_interface siren7_interface = { + .format_destroy = siren7_destroy, + .format_clone = siren7_clone, + .format_parse_sdp_fmtp = siren7_parse_sdp_fmtp, + .format_generate_sdp_fmtp = siren7_generate_sdp_fmtp, +}; + +static int load_module(void) +{ + if (ast_format_interface_register("siren7", &siren7_interface)) { + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Siren7 Format Attribute Module", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND, +); From 83f2c2573bdf680caeafdab0f31f331fe7fa6609 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 28 Jun 2016 10:33:30 -0500 Subject: [PATCH 0532/1578] configs/basic-pbx/modules.conf: Remove 'bad' modules This patch removes the following modules: - pbx_functions: It never existed. - res_pjsip_log_forwarder: It no longer exists. - res_hep_pjsip: The base HEP module wasn't loaded, and most basic PBXs aren't going to be installing HOMER - res_pjsip_phoneprov_provider: The basic res_phoneprov module isn't loaded, and we aren't configured to make use of the module Change-Id: Id91f68cae7c9c8c3d370029fe1268cb51e4ff5a5 --- configs/basic-pbx/modules.conf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configs/basic-pbx/modules.conf b/configs/basic-pbx/modules.conf index 90ced108596..8de58bf2d9b 100644 --- a/configs/basic-pbx/modules.conf +++ b/configs/basic-pbx/modules.conf @@ -59,11 +59,9 @@ load = func_strings.so ; Core/PBX load = pbx_config.so -load = pbx_functions.so ; Resources -load = res_hep_pjsip.so load = res_musiconhold.so load = res_pjproject.so load = res_pjsip_acl.so @@ -77,7 +75,6 @@ load = res_pjsip_endpoint_identifier_ip.so load = res_pjsip_endpoint_identifier_user.so load = res_pjsip_exten_state.so load = res_pjsip_header_funcs.so -load = res_pjsip_log_forwarder.so load = res_pjsip_logger.so load = res_pjsip_messaging.so load = res_pjsip_multihomed.so @@ -90,7 +87,6 @@ load = res_pjsip_outbound_authenticator_digest.so load = res_pjsip_outbound_publish.so load = res_pjsip_outbound_registration.so load = res_pjsip_path.so -load = res_pjsip_phoneprov_provider.so load = res_pjsip_pidf_body_generator.so load = res_pjsip_pidf_digium_body_supplement.so load = res_pjsip_pidf_eyebeam_body_supplement.so From 651290a80902f1ba095f343f0e5c75e61a3ccd7c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 28 Jun 2016 07:22:24 -0600 Subject: [PATCH 0533/1578] BuildSystem: Fix a few issues hightlighted by gcc 6.x gcc 6.1.1 caught a few more issues. Made sure the unit tests still pass for the func_env and stdtime issues. ASTERISK-26157 #close Change-Id: I6664d8f34a45bc1481d2a854481c7878b0c1cf8e --- channels/chan_unistim.c | 2 ++ funcs/func_env.c | 4 ++-- main/say.c | 16 +++++++++------- main/stdtime/localtime.c | 11 ++++++----- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 973f3522b5e..5b64f963bf3 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -567,8 +567,10 @@ static const unsigned char packet_send_stream_based_tone_off[] = { 0x16, 0x05, 0x1c, 0x00, 0x00 }; static const unsigned char packet_send_mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 }; +#ifdef NOT_USED static const unsigned char packet_send_CloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff }; static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 }; +#endif static const unsigned char packet_send_stream_based_tone_on[] = { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 }; static const unsigned char packet_send_stream_based_tone_single_freq[] = diff --git a/funcs/func_env.c b/funcs/func_env.c index 8f9753aaa92..3883de60164 100644 --- a/funcs/func_env.c +++ b/funcs/func_env.c @@ -624,7 +624,7 @@ static int file_read(struct ast_channel *chan, const char *cmd, char *data, stru ast_log(LOG_ERROR, "Cannot seek to offset %" PRId64 ": %s\n", i, strerror(errno)); } end = fread(fbuf, 1, sizeof(fbuf), ff); - for (pos = (end < sizeof(fbuf) ? fbuf + end - 1 : fbuf + sizeof(fbuf) - 1); pos > fbuf - 1; pos--) { + for (pos = (end < sizeof(fbuf) ? fbuf + end - 1 : fbuf + sizeof(fbuf) - 1); pos >= fbuf; pos--) { LINE_COUNTER(pos, format, count); if (length < 0 && count * -1 == length) { @@ -1024,7 +1024,7 @@ static int file_write(struct ast_channel *chan, const char *cmd, char *data, con fclose(ff); return -1; } - for (pos = fbuf + sizeof(fbuf) - 1; pos > fbuf - 1; pos--) { + for (pos = fbuf + sizeof(fbuf) - 1; pos >= fbuf; pos--) { LINE_COUNTER(pos, newline_format, count); if (length < 0 && count * -1 == length) { diff --git a/main/say.c b/main/say.c index e4e3743299e..9f6f1eacbc6 100644 --- a/main/say.c +++ b/main/say.c @@ -5774,13 +5774,14 @@ int ast_say_date_with_format_it(struct ast_channel *chan, time_t t, const char * case 'I': case 'l': /* 12-Hour */ - if (tm.tm_hour == 0) + if (tm.tm_hour == 0) { ast_copy_string(nextmsg, "digits/12", sizeof(nextmsg)); - else if (tm.tm_hour > 12) + } else if (tm.tm_hour > 12) { snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); - else + } else { snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour); - res = wait_file(chan, ints, nextmsg, lang); + } + res = wait_file(chan, ints, nextmsg, lang); break; case 'H': case 'k': @@ -5800,11 +5801,12 @@ int ast_say_date_with_format_it(struct ast_channel *chan, time_t t, const char * case 'P': case 'p': /* AM/PM */ - if (tm.tm_hour > 11) + if (tm.tm_hour > 11) { ast_copy_string(nextmsg, "digits/p-m", sizeof(nextmsg)); - else + } else { ast_copy_string(nextmsg, "digits/a-m", sizeof(nextmsg)); - res = wait_file(chan, ints, nextmsg, lang); + } + res = wait_file(chan, ints, nextmsg, lang); break; case 'Q': /* Shorthand for "Today", "Yesterday", or ABdY */ diff --git a/main/stdtime/localtime.c b/main/stdtime/localtime.c index c10b7af6232..c946c5fa8d2 100644 --- a/main/stdtime/localtime.c +++ b/main/stdtime/localtime.c @@ -1849,13 +1849,14 @@ void ast_get_dst_info(const time_t * const timep, int *dst_enabled, time_t *dst_ *dst_enabled = 0; /* Find where I can get gmtoff */ i = 0; - while (sp->ttis[i].tt_isdst) + while (sp->ttis[i].tt_isdst) { if (++i >= sp->typecnt) { - i = 0; - break; + i = 0; + break; } - *gmt_off = sp->ttis[i].tt_gmtoff; - return; + } + *gmt_off = sp->ttis[i].tt_gmtoff; + return; } for (i = 1; i < sp->timecnt; ++i) { From 4045e6d8ba6677f86483df28d902090fd5b471cd Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 28 Jun 2016 08:00:32 -0600 Subject: [PATCH 0534/1578] codecs: Fix ABI incompatibility created by adding format_name to ast_codec Adding format_name even to the end of ast_codec caused issued with binary codec modules because the pointer would be garbage in asterisk when they registered. So, the ast_codec structure was reverted and an internal_ast_codec structure was created just for use in codec.c. A new internal-only API was also added (__ast_codec_register_with_format) so that codec_builtin could register codecs with the format_name in a separate parameter rather than in the ast_codec structure. ASTERISK-26144 #close Reported-by: Alexei Gradinari Change-Id: I6df1b08f6a6ae089db23adfe1ebc8636330265ba --- include/asterisk/codec.h | 2 -- main/codec.c | 62 ++++++++++++++++++++++++++++++---------- main/codec_builtin.c | 9 +++--- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h index 4ea94f9bbd0..3873324b143 100644 --- a/include/asterisk/codec.h +++ b/include/asterisk/codec.h @@ -77,8 +77,6 @@ struct ast_codec { unsigned int smooth; /*! \brief The module that registered this codec */ struct ast_module *mod; - /*! \brief A format name for a default sane format using this codec */ - const char *format_name; }; /*! diff --git a/main/codec.c b/main/codec.c index a7626450303..49356a22fb1 100644 --- a/main/codec.c +++ b/main/codec.c @@ -49,6 +49,32 @@ static int codec_id = 1; /*! \brief Registered codecs */ static struct ao2_container *codecs; +/*! + * \internal + * \brief Internal codec structure + * + * External codecs won't know about the format_name field so the public + * ast_codec structure has to leave it out. This structure will be used + * for the internal codecs. + * + */ +struct internal_ast_codec { + /*! \brief Public codec structure. Must remain first. */ + struct ast_codec external; + /*! \brief A format name for a default sane format using this codec */ + const char *format_name; +}; + +/*! + * \internal + * \brief Internal function for registration with format name + * + * This function is only used by codec.c and codec_builtin.c and + * will be removed in Asterisk 14 + */ +int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name, + struct ast_module *mod); + static int codec_hash(const void *obj, int flags) { const struct ast_codec *codec; @@ -113,7 +139,7 @@ static int codec_cmp(void *obj, void *arg, int flags) static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ao2_iterator i; - struct ast_codec *codec; + struct internal_ast_codec *codec; switch (cmd) { case CLI_INIT: @@ -144,19 +170,19 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args * for (; (codec = ao2_iterator_next(&i)); ao2_ref(codec, -1)) { if (a->argc == 4) { if (!strcasecmp(a->argv[3], "audio")) { - if (codec->type != AST_MEDIA_TYPE_AUDIO) { + if (codec->external.type != AST_MEDIA_TYPE_AUDIO) { continue; } } else if (!strcasecmp(a->argv[3], "video")) { - if (codec->type != AST_MEDIA_TYPE_VIDEO) { + if (codec->external.type != AST_MEDIA_TYPE_VIDEO) { continue; } } else if (!strcasecmp(a->argv[3], "image")) { - if (codec->type != AST_MEDIA_TYPE_IMAGE) { + if (codec->external.type != AST_MEDIA_TYPE_IMAGE) { continue; } } else if (!strcasecmp(a->argv[3], "text")) { - if (codec->type != AST_MEDIA_TYPE_TEXT) { + if (codec->external.type != AST_MEDIA_TYPE_TEXT) { continue; } } else { @@ -165,11 +191,11 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args * } ast_cli(a->fd, "%8u %-5s %-12s %-16s (%s)\n", - codec->id, - ast_codec_media_type2str(codec->type), - codec->name, + codec->external.id, + ast_codec_media_type2str(codec->external.type), + codec->external.name, S_OR(codec->format_name, "no cached format"), - codec->description); + codec->external.description); } ao2_iterator_destroy(&i); @@ -190,7 +216,7 @@ static int codec_id_cmp(void *obj, void *arg, int flags) static char *show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { int type_punned_codec; - struct ast_codec *codec; + struct internal_ast_codec *codec; switch (cmd) { case CLI_INIT: @@ -217,7 +243,7 @@ static char *show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a return CLI_SUCCESS; } - ast_cli(a->fd, "%11u %s (%s)\n", (unsigned int) codec->id, codec->description, + ast_cli(a->fd, "%11u %s (%s)\n", (unsigned int) codec->external.id, codec->external.description, S_OR(codec->format_name, "no format")); ao2_ref(codec, -1); @@ -262,9 +288,14 @@ static void codec_dtor(void *obj) } int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod) +{ + return __ast_codec_register_with_format(codec, NULL, mod); +} + +int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name, struct ast_module *mod) { SCOPED_AO2WRLOCK(lock, codecs); - struct ast_codec *codec_new; + struct internal_ast_codec *codec_new; /* Some types have specific requirements */ if (codec->type == AST_MEDIA_TYPE_UNKNOWN) { @@ -293,8 +324,9 @@ int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod) codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate); return -1; } - *codec_new = *codec; - codec_new->id = codec_id++; + codec_new->external = *codec; + codec_new->format_name = format_name; + codec_new->external.id = codec_id++; ao2_link_flags(codecs, codec_new, OBJ_NOLOCK); @@ -302,7 +334,7 @@ int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod) ast_module_shutdown_ref(mod); ast_verb(2, "Registered '%s' codec '%s' at sample rate '%u' with id '%u'\n", - ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->id); + ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->external.id); ao2_ref(codec_new, -1); diff --git a/main/codec_builtin.c b/main/codec_builtin.c index fdaa018255f..9131643287d 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -38,6 +38,9 @@ ASTERISK_REGISTER_FILE() #include "asterisk/format_cache.h" #include "asterisk/frame.h" +int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name, + struct ast_module *mod); + enum frame_type { TYPE_HIGH, /* 0x0 */ TYPE_LOW, /* 0x1 */ @@ -774,8 +777,7 @@ static struct ast_codec t140 = { int __res_ ## __LINE__ = 0; \ struct ast_format *__fmt_ ## __LINE__; \ struct ast_codec *__codec_ ## __LINE__; \ - codec.format_name = (codec).name; \ - res |= __ast_codec_register(&(codec), NULL); \ + res |= __ast_codec_register_with_format(&(codec), (codec).name, NULL); \ __codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \ __fmt_ ## __LINE__ = __codec_ ## __LINE__ ? ast_format_create(__codec_ ## __LINE__) : NULL; \ res |= ast_format_cache_set(__fmt_ ## __LINE__); \ @@ -789,8 +791,7 @@ static struct ast_codec t140 = { int __res_ ## __LINE__ = 0; \ struct ast_format *__fmt_ ## __LINE__; \ struct ast_codec *__codec_ ## __LINE__; \ - codec.format_name = fmt_name; \ - res |= __ast_codec_register(&(codec), NULL); \ + res |= __ast_codec_register_with_format(&(codec), fmt_name, NULL); \ __codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \ __fmt_ ## __LINE__ = ast_format_create_named((fmt_name), __codec_ ## __LINE__); \ res |= ast_format_cache_set(__fmt_ ## __LINE__); \ From 9129ac8e73924e856217a222869c35b095c8bf8b Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 29 Jun 2016 15:09:02 -0500 Subject: [PATCH 0535/1578] pjproject/patches/config_site: Increase the max number of ICE candidates When negotiating ICE candidates with WebRTC capable endpoints, many networks will result in a browser offering ICE candidates that exceeds the default number of max candidates, 16. This patch bumps the max candidates to 32, with the max checks at twice the number of candidates. In practice, this has shown to be sufficient for browser/WebRTC negotiation. Change-Id: Ifd8da8b315f5ae14814d4ce20e10d2e6355020e5 --- third-party/pjproject/patches/config_site.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 8e854b72324..eb9f8b15cdf 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -37,3 +37,7 @@ #undef PJ_TODO #define PJ_TODO(x) + +/* Defaults too low for WebRTC */ +#define PJ_ICE_MAX_CAND 32 +#define PJ_ICE_MAX_CHECKS (PJ_ICE_MAX_CAND * 2) From dab2a6b68942e11c72013e93151dd5a36e2cd0aa Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 29 Jun 2016 15:31:30 -0500 Subject: [PATCH 0536/1578] hep.conf.sample: Default 'enabled' to 'no' Following the principle of least surprise, we should not be sending massive numbers of PJSIP and RTCP HEP packets out into the ether to some only-slightly-random IP address. Having 'enabled' set to 'no' in the sample configuration file should prevent this from happening for those who run 'make samples'. ASTERISK-26159 #close Change-Id: I1753a64ca83a3442a6ebdc31061f8185c062d9b1 --- configs/samples/hep.conf.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/samples/hep.conf.sample b/configs/samples/hep.conf.sample index 6e409d151c0..e1cd52ebb0a 100644 --- a/configs/samples/hep.conf.sample +++ b/configs/samples/hep.conf.sample @@ -4,7 +4,7 @@ ; All settings are currently set in the general section. [general] -enabled = yes ; Enable/disable forwarding of packets to a +enabled = no ; Enable/disable forwarding of packets to a ; HEP server. Default is "yes". capture_address = 192.168.1.1:9061 ; The address of the HEP capture server. capture_password = foo ; If specified, the authorization passsword From 5ad7e1c09a7db698f0e4dd95f9153a70f8a1c667 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 30 Jun 2016 07:25:09 -0600 Subject: [PATCH 0537/1578] configure: Fix HAVE_PJSIP_EVSUB_GRP_LOCK not set with external pjproject There was a typo in configure.ac preventing HAVE_PJSIP_EVSUB_GRP_LOCK from getting set when using an external pjproject. ASTERISK-26099 #close Reported-by: Ross Beer Change-Id: I709af70428e125fb5ccd44b171d25dd29141f0ae --- configure | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 7f3d09c743e..5e5667c97d4 100755 --- a/configure +++ b/configure @@ -25446,7 +25446,7 @@ if test "x${PBX_PJSIP_EVSUB_GRP_LOCK}" != "x1" -a "${USE_PJSIP_EVSUB_GRP_LOCK}" pbxlibdir="-L${PJSIP_EVSUB_GRP_LOCK_DIR}" fi fi - pbxfuncname="pjsip_evsub_add_lock" + pbxfuncname="pjsip_evsub_add_ref" if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers AST_PJSIP_EVSUB_GRP_LOCK_FOUND=yes else diff --git a/configure.ac b/configure.ac index 0698834aaf1..6256ef7fb82 100644 --- a/configure.ac +++ b/configure.ac @@ -2209,7 +2209,7 @@ if test "$USE_PJPROJECT" != "no" ; then LIBS="${saved_libs}" CPPFLAGS="${saved_cppflags}" - AST_EXT_LIB_CHECK([PJSIP_EVSUB_GRP_LOCK], [pjsip], [pjsip_evsub_add_lock], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJSIP_EVSUB_GRP_LOCK], [pjsip], [pjsip_evsub_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) fi fi From 4f7b85972669500d7f52598811935ebedfdee545 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 30 Jun 2016 15:17:02 -0500 Subject: [PATCH 0538/1578] features: Fix channel datastore access. Found as a result of the testsuite tests/callparking test crashing. Several calls to ast_get_chan_featuremap_config() and ast_get_chan_features_xfer_config() did not lock the channel before calling so the channel's datastore list was accessed without the lock's protection. Apparently another thread deleted a datastore on the channel's list while the crashing thread was walking the list. Crash at 0xdeaddead due to MALLOC_DEBUG's memory filler value as a result. * Add missing channel locks to calls that were not already protected as the doxygen for those calls indicates. Change-Id: Id273b3d305cc616406c353cbc841b2b7655efaa1 --- main/bridge_channel.c | 9 +++++++-- main/features.c | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 3ba61aa3342..18f71950619 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -1543,8 +1543,13 @@ static void testsuite_notify_feature_success(struct ast_channel *chan, const cha { #ifdef TEST_FRAMEWORK char *feature = "unknown"; - struct ast_featuremap_config *featuremap = ast_get_chan_featuremap_config(chan); - struct ast_features_xfer_config *xfer = ast_get_chan_features_xfer_config(chan); + struct ast_featuremap_config *featuremap; + struct ast_features_xfer_config *xfer; + + ast_channel_lock(chan); + featuremap = ast_get_chan_featuremap_config(chan); + xfer = ast_get_chan_features_xfer_config(chan); + ast_channel_unlock(chan); if (featuremap) { if (!strcmp(dtmf, featuremap->blindxfer)) { diff --git a/main/features.c b/main/features.c index 6806fe749fc..b6e9630b52b 100644 --- a/main/features.c +++ b/main/features.c @@ -766,8 +766,8 @@ static int action_bridge(struct mansession *s, const struct message *m) astman_send_error(s, m, buf); return 0; } - xfer_cfg_a = ast_get_chan_features_xfer_config(chana); ast_channel_lock(chana); + xfer_cfg_a = ast_get_chan_features_xfer_config(chana); chana_exten = ast_strdupa(ast_channel_exten(chana)); chana_context = ast_strdupa(ast_channel_context(chana)); chana_priority = ast_channel_priority(chana); @@ -782,8 +782,8 @@ static int action_bridge(struct mansession *s, const struct message *m) astman_send_error(s, m, buf); return 0; } - xfer_cfg_b = ast_get_chan_features_xfer_config(chanb); ast_channel_lock(chanb); + xfer_cfg_b = ast_get_chan_features_xfer_config(chanb); chanb_exten = ast_strdupa(ast_channel_exten(chanb)); chanb_context = ast_strdupa(ast_channel_context(chanb)); chanb_priority = ast_channel_priority(chanb); @@ -1097,7 +1097,9 @@ static int bridge_exec(struct ast_channel *chan, const char *data) goto done; } + ast_channel_lock(current_dest_chan); xfer_cfg = ast_get_chan_features_xfer_config(current_dest_chan); + ast_channel_unlock(current_dest_chan); bridge_add_failed = ast_bridge_add_channel(bridge, current_dest_chan, peer_features, ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE), xfer_cfg ? xfer_cfg->xfersound : NULL); From 656ed73ac686f2e7d4afcbd46a4a04086a3502c6 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 22 Jun 2016 18:02:59 -0500 Subject: [PATCH 0539/1578] res_pjsip: Add missing NULL checks when using pjsip_inv_end_session(). pjsip_inv_end_session() is documented as being able to return the passed in tdata parameter set to NULL on success. Change-Id: I09d53725c49b7183c41bfa1be3ff225f3a8d3047 --- channels/chan_pjsip.c | 6 ++++-- res/res_pjsip_refer.c | 3 ++- res/res_pjsip_session.c | 6 ++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 22f834d376b..5ad11740476 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1466,7 +1466,8 @@ static void transfer_redirect(struct ast_sip_session *session, const char *targe pjsip_contact_hdr *contact; pj_str_t tmp; - if (pjsip_inv_end_session(session->inv_session, 302, NULL, &packet) != PJ_SUCCESS) { + if (pjsip_inv_end_session(session->inv_session, 302, NULL, &packet) != PJ_SUCCESS + || !packet) { ast_log(LOG_WARNING, "Failed to redirect PJSIP session for channel %s\n", ast_channel_name(session->channel)); message = AST_TRANSFER_FAILED; @@ -2231,7 +2232,8 @@ static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct p ast_sip_session_add_datastore(session, datastore); if (!(session->channel = chan_pjsip_new(session, AST_STATE_RING, session->exten, NULL, NULL, NULL, NULL))) { - if (pjsip_inv_end_session(session->inv_session, 503, NULL, &packet) == PJ_SUCCESS) { + if (pjsip_inv_end_session(session->inv_session, 503, NULL, &packet) == PJ_SUCCESS + && packet) { ast_sip_session_send_response(session, packet); } diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index df542517982..1043a1e24d8 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -969,7 +969,8 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct session->defer_terminate = 1; ast_hangup(session->channel); - if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS) { + if (pjsip_inv_end_session(session->inv_session, response, NULL, &packet) == PJ_SUCCESS + && packet) { ast_sip_session_send_response(session, packet); } } else { diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index eb9551097af..6287c17ec05 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2651,7 +2651,8 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } if (tsx->status_code != 488) { /* Other reinvite failures (except 488) result in destroying the session. */ - if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) { + if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS + && tdata) { ast_sip_session_send_request(session, tdata); } } @@ -2664,7 +2665,8 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans * a cancelled call. Our role is to immediately send a BYE to end the * dialog. */ - if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) { + if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS + && tdata) { ast_sip_session_send_request(session, tdata); } } From 5d2fc6bab70279c1e3f43916c7b8257a365be858 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 27 Jun 2016 16:56:33 -0500 Subject: [PATCH 0540/1578] res_pjsip_session.c: Remove unused parameter from handle_incoming(). Change-Id: Iedd182d189ec947c42edc2c66c4bda3c22060daa --- res/res_pjsip_session.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 6287c17ec05..56e3ce11293 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -53,10 +53,10 @@ #define MOD_DATA_NAT_HOOK "nat_hook" /* Some forward declarations */ -static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type); -static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type, +static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata); +static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority); -static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type, +static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority); static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata); static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata); @@ -2143,7 +2143,7 @@ static int new_invite(void *data) } ast_sip_session_send_response(invite->session, tdata); - handle_incoming_request(invite->session, invite->rdata, PJSIP_EVENT_RX_MSG); + handle_incoming_request(invite->session, invite->rdata); return 0; } @@ -2364,7 +2364,7 @@ static void __print_debug_details(const char *function, pjsip_inv_session *inv, #define print_debug_details(inv, tsx, e) __print_debug_details(__PRETTY_FUNCTION__, (inv), (tsx), (e)) -static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type) +static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata) { struct ast_sip_session_supplement *supplement; struct pjsip_request_line req = rdata->msg_info.msg->line.req; @@ -2379,7 +2379,7 @@ static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_da } } -static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type, +static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority) { struct ast_sip_session_supplement *supplement; @@ -2398,16 +2398,16 @@ static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_d } } -static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_event_id_e type, +static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata, enum ast_sip_session_response_priority response_priority) { ast_debug(3, "Received %s\n", rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ? "request" : "response"); if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { - handle_incoming_request(session, rdata, type); + handle_incoming_request(session, rdata); } else { - handle_incoming_response(session, rdata, type, response_priority); + handle_incoming_response(session, rdata, response_priority); } return 0; @@ -2534,8 +2534,8 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) handle_outgoing(session, e->body.tx_msg.tdata); break; case PJSIP_EVENT_RX_MSG: - handle_incoming(session, e->body.rx_msg.rdata, type, - AST_SIP_SESSION_BEFORE_MEDIA); + handle_incoming(session, e->body.rx_msg.rdata, + AST_SIP_SESSION_BEFORE_MEDIA); break; case PJSIP_EVENT_TSX_STATE: ast_debug(3, "Source of transaction state change is %s\n", pjsip_event_str(e->body.tsx_state.type)); @@ -2546,8 +2546,8 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) break; case PJSIP_EVENT_RX_MSG: if (!check_request_status(inv, e)) { - handle_incoming(session, e->body.tsx_state.src.rdata, type, - AST_SIP_SESSION_BEFORE_MEDIA); + handle_incoming(session, e->body.tsx_state.src.rdata, + AST_SIP_SESSION_BEFORE_MEDIA); } break; case PJSIP_EVENT_TRANSPORT_ERROR: @@ -2627,8 +2627,8 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans */ if ((e->body.tsx_state.src.rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) || (tsx->method.id != PJSIP_BYE_METHOD)) { - handle_incoming(session, e->body.tsx_state.src.rdata, e->type, - AST_SIP_SESSION_AFTER_MEDIA); + handle_incoming(session, e->body.tsx_state.src.rdata, + AST_SIP_SESSION_AFTER_MEDIA); } if (tsx->method.id == PJSIP_INVITE_METHOD) { if (tsx->role == PJSIP_ROLE_UAC) { @@ -2953,8 +2953,7 @@ static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const return PJSIP_REDIRECT_STOP; } - handle_incoming(session, e->body.rx_msg.rdata, PJSIP_EVENT_RX_MSG, - AST_SIP_SESSION_BEFORE_REDIRECTING); + handle_incoming(session, e->body.rx_msg.rdata, AST_SIP_SESSION_BEFORE_REDIRECTING); uri = pjsip_uri_get_uri(target); From e6e12c752cfb6ef1a0164c290ebc27b093f1041f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 23 Jun 2016 15:13:24 -0500 Subject: [PATCH 0541/1578] res_pjsip.c: Register PJMEDIA error code decoder. Registering the PJMEDIA error codes allows errors found when parsing an incoming SDP to be easier to figure out. "Missing SDP rtpmap for dynamic payload type (PJMEDIA_SDP_EMISSINGRTPMAP)" is much easier to understand than "Unknown error 220030". ASTERISK-25772 Change-Id: I44b2dcea656fedd7593171be9e845880a2c70ca0 --- res/res_pjsip.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 9944702c350..516cb54d867 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "asterisk/res_pjsip.h" #include "res_pjsip/include/res_pjsip_private.h" @@ -4287,6 +4288,19 @@ static int load_pjsip(void) return AST_MODULE_LOAD_DECLINE; } +/* + * This is a place holder function to ensure that pjmedia_strerr() is at + * least directly referenced by this module to ensure that the loader + * linker will link to the function. If a module only indirectly + * references a function from another module, such as a callback parameter + * to a function, the loader linker has been known to miss the link. + */ +void never_called_res_pjsip(void); +void never_called_res_pjsip(void) +{ + pjmedia_strerror(0, NULL, 0); +} + static int load_module(void) { struct ast_threadpool_options options; @@ -4302,6 +4316,12 @@ static int load_module(void) goto error; } + /* Register PJMEDIA error codes for SDP parsing errors */ + if (pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE, pjmedia_strerror) + != PJ_SUCCESS) { + ast_log(LOG_WARNING, "Failed to register pjmedia error codes. Codes will not be decoded.\n"); + } + if (ast_sip_initialize_system()) { ast_log(LOG_ERROR, "Failed to initialize SIP 'system' configuration section. Aborting load\n"); goto error; From 08d3b9a89ef521e84e61ea1d6110b000454076cd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 27 Jun 2016 17:19:08 -0500 Subject: [PATCH 0542/1578] res_pjsip_session.c: End call on initial invalid SDP negotiation. When an incoming call defers SDP negotiation and then sends us an invalid SDP in the ACK, we need to send a BYE to disconnect the call. In this case SDP negotiation has failed and we don't have valid media streams negotiated. ASTERISK-25772 Change-Id: Ia358516b0fc1e6c4c139b78246f10b9da7a2dfb8 --- res/res_pjsip_session.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 56e3ce11293..405fdf839bd 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2513,6 +2513,36 @@ static int check_request_status(pjsip_inv_session *inv, pjsip_event *e) return 1; } +static void handle_incoming_before_media(pjsip_inv_session *inv, + struct ast_sip_session *session, pjsip_rx_data *rdata) +{ + pjsip_msg *msg; + + handle_incoming(session, rdata, AST_SIP_SESSION_BEFORE_MEDIA); + msg = rdata->msg_info.msg; + if (msg->type == PJSIP_REQUEST_MSG + && msg->line.req.method.id == PJSIP_ACK_METHOD + && pjmedia_sdp_neg_get_state(inv->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { + pjsip_tx_data *tdata; + + /* + * SDP negotiation failed on an incoming call that delayed + * negotiation and then gave us an invalid SDP answer. We + * need to send a BYE to end the call because of the invalid + * SDP answer. + */ + ast_debug(1, + "Endpoint '%s(%s)': Ending session due to incomplete SDP negotiation. %s\n", + ast_sorcery_object_get_id(session->endpoint), + session->channel ? ast_channel_name(session->channel) : "", + pjsip_rx_data_get_info(rdata)); + if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS + && tdata) { + ast_sip_session_send_request(session, tdata); + } + } +} + static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) { struct ast_sip_session *session = inv->mod_data[session_module.id]; @@ -2534,8 +2564,7 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) handle_outgoing(session, e->body.tx_msg.tdata); break; case PJSIP_EVENT_RX_MSG: - handle_incoming(session, e->body.rx_msg.rdata, - AST_SIP_SESSION_BEFORE_MEDIA); + handle_incoming_before_media(inv, session, e->body.rx_msg.rdata); break; case PJSIP_EVENT_TSX_STATE: ast_debug(3, "Source of transaction state change is %s\n", pjsip_event_str(e->body.tsx_state.type)); @@ -2546,8 +2575,7 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) break; case PJSIP_EVENT_RX_MSG: if (!check_request_status(inv, e)) { - handle_incoming(session, e->body.tsx_state.src.rdata, - AST_SIP_SESSION_BEFORE_MEDIA); + handle_incoming_before_media(inv, session, e->body.tsx_state.src.rdata); } break; case PJSIP_EVENT_TRANSPORT_ERROR: From 9f2c00725409a462935f343813fb10aba0c449ca Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 22 Jun 2016 17:26:38 -0500 Subject: [PATCH 0543/1578] res_pjsip_session.c: Don't send extra BYE if SDP invalid. When an answer SDP is invalid we were disconnecting the outgoing call and sending two BYE requests. The first BYE was sent by PJPROJECT because of the invalid SDP answer. The second BYE was sent by Asterisk because it thought the canceled call was the result of the RFC5407 section 3.1.2 race condition. * Made not send the BYE on a canceled session if the SDP negotiation is incomplete because PJPROJECT has already sent a BYE for the failed negotiation. ASTERISK-25772 #close Reported by: Dmitriy Serov Change-Id: I44ad0bd0605e8eeb7035c890d6f97a1331f1a836 --- res/res_pjsip_session.c | 48 +++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 405fdf839bd..9f98e34b832 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -46,6 +46,7 @@ #include "asterisk/acl.h" #include "asterisk/features_config.h" #include "asterisk/pickup.h" +#include "asterisk/test.h" #define SDP_HANDLER_BUCKETS 11 @@ -2687,14 +2688,49 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { if (inv->cancelling && tsx->status_code == PJSIP_SC_OK) { - /* This is a race condition detailed in RFC 5407 section 3.1.2. - * We sent a CANCEL at the same time that the UAS sent us a 200 OK for - * the original INVITE. As a result, we have now received a 200 OK for - * a cancelled call. Our role is to immediately send a BYE to end the - * dialog. + int sdp_negotiation_done = + pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE; + + /* + * We can get here for the following reasons. + * + * 1) The race condition detailed in RFC5407 section 3.1.2. + * We sent a CANCEL at the same time that the UAS sent us a + * 200 OK with a valid SDP for the original INVITE. As a + * result, we have now received a 200 OK for a cancelled + * call and the SDP negotiation is complete. We need to + * immediately send a BYE to end the dialog. + * + * 2) We sent a CANCEL and hit the race condition but the + * UAS sent us an invalid SDP with the 200 OK. In this case + * the SDP negotiation is incomplete and PJPROJECT has + * already sent the BYE for us because of the invalid SDP. + * + * 3) We didn't send a CANCEL but the UAS sent us an invalid + * SDP with the 200 OK. In this case the SDP negotiation is + * incomplete and PJPROJECT has already sent the BYE for us + * because of the invalid SDP. */ - if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS + ast_test_suite_event_notify("PJSIP_SESSION_CANCELED", + "Endpoint: %s\r\n" + "Channel: %s\r\n" + "Message: %s\r\n" + "SDP: %s", + ast_sorcery_object_get_id(session->endpoint), + session->channel ? ast_channel_name(session->channel) : "", + pjsip_rx_data_get_info(e->body.tsx_state.src.rdata), + sdp_negotiation_done ? "complete" : "incomplete"); + if (!sdp_negotiation_done) { + ast_debug(1, "Endpoint '%s(%s)': Incomplete SDP negotiation cancelled session. %s\n", + ast_sorcery_object_get_id(session->endpoint), + session->channel ? ast_channel_name(session->channel) : "", + pjsip_rx_data_get_info(e->body.tsx_state.src.rdata)); + } else if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS && tdata) { + ast_debug(1, "Endpoint '%s(%s)': Ending session due to RFC5407 race condition. %s\n", + ast_sorcery_object_get_id(session->endpoint), + session->channel ? ast_channel_name(session->channel) : "", + pjsip_rx_data_get_info(e->body.tsx_state.src.rdata)); ast_sip_session_send_request(session, tdata); } } From 32cb981d049b8f64706e764fcab114232c9baa8a Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 4 Jul 2016 12:58:39 +0200 Subject: [PATCH 0544/1578] BuildSystem: Avoid obsolete warning with libcurl.m4 on autoconf. Updated the macro-set autoconf/libcurl.m4 to its latest upstream version. This avoids a warning about an obsolete macro on AC_HELP_STRING, because Asterisk is using AS_HELP_STRING everywhere else already. ASTERISK-26046 Change-Id: I8299faf504ceaeee3e39930c59293809e116c631 --- autoconf/libcurl.m4 | 49 ++++++++++++++++++++++++++------ configure | 21 ++++++++++---- include/asterisk/autoconfig.h.in | 12 ++++++++ 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/autoconf/libcurl.m4 b/autoconf/libcurl.m4 index 085ee0ea089..9a31bfc8bbb 100644 --- a/autoconf/libcurl.m4 +++ b/autoconf/libcurl.m4 @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 2006, David Shaw +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### # LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], # [ACTION-IF-YES], [ACTION-IF-NO]) # ---------------------------------------------------------- @@ -55,10 +76,14 @@ AC_DEFUN([AST_LIBCURL_CHECK_CONFIG], AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) + AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) AC_SUBST(PBX_CURL) AC_ARG_WITH(libcurl, - AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]), + AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) if test "$_libcurl_with" != "no" ; then @@ -72,10 +97,10 @@ AC_DEFUN([AST_LIBCURL_CHECK_CONFIG], if test -d "$_libcurl_with" ; then CURL_INCLUDE="-I$withval/include" _libcurl_ldflags="-L$withval/lib" - AC_PATH_PROG([_libcurl_config],[curl-config],["$withval/bin"], + AC_PATH_PROG([_libcurl_config],[curl-config],[], ["$withval/bin"]) else - AC_PATH_PROG([_libcurl_config],[curl-config]) + AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) fi if test x$_libcurl_config != "x" ; then @@ -143,18 +168,19 @@ AC_DEFUN([AST_LIBCURL_CHECK_CONFIG], _libcurl_save_libs=$LIBS LIBS="$CURL_LIB $LIBS" - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],[ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ /* Try and use a few common options to force a failure if we are missing symbols or can't link. */ int x; curl_easy_setopt(NULL,CURLOPT_URL,NULL); x=CURL_ERROR_SIZE; x=CURLOPT_WRITEFUNCTION; -x=CURLOPT_FILE; +x=CURLOPT_WRITEDATA; x=CURLOPT_ERRORBUFFER; x=CURLOPT_STDERR; x=CURLOPT_VERBOSE; -])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) +if (x) {;} +]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) CPPFLAGS=$_libcurl_save_cppflags LIBS=$_libcurl_save_libs @@ -196,17 +222,23 @@ x=CURLOPT_VERBOSE; # We don't have --protocols, so just assume that all # protocols are available - _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT" + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" if test x$libcurl_feature_SSL = xyes ; then _libcurl_protocols="$_libcurl_protocols HTTPS" # FTPS wasn't standards-compliant until version - # 7.11.0 + # 7.11.0 (0x070b00 == 461568) if test $_libcurl_version -ge 461568; then _libcurl_protocols="$_libcurl_protocols FTPS" fi fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi fi for _libcurl_protocol in $_libcurl_protocols ; do @@ -241,4 +273,3 @@ x=CURLOPT_VERBOSE; unset _libcurl_with ])dnl - diff --git a/configure b/configure index 5e5667c97d4..aaad401d76b 100755 --- a/configure +++ b/configure @@ -2095,7 +2095,8 @@ Optional Packages: --with-uriparser=PATH use uriparser library files in PATH --with-kqueue=PATH use kqueue support files in PATH --with-ldap=PATH use OpenLDAP files in PATH - --with-libcurl=DIR look for the curl library in DIR + --with-libcurl=PREFIX look for the curl library in PREFIX/lib and headers + in PREFIX/include --with-libedit=PATH use NetBSD Editline library files in PATH, use 'internal' Editline otherwise --with-libxml2=PATH use LibXML2 files in PATH @@ -9459,6 +9460,10 @@ fi + + + + @@ -9551,7 +9556,6 @@ done done IFS=$as_save_IFS - test -z "$ac_cv_path__libcurl_config" && ac_cv_path__libcurl_config=""$withval/bin"" ;; esac fi @@ -9701,10 +9705,11 @@ int x; curl_easy_setopt(NULL,CURLOPT_URL,NULL); x=CURL_ERROR_SIZE; x=CURLOPT_WRITEFUNCTION; -x=CURLOPT_FILE; +x=CURLOPT_WRITEDATA; x=CURLOPT_ERRORBUFFER; x=CURLOPT_STDERR; x=CURLOPT_VERBOSE; +if (x) {;} ; return 0; @@ -9771,17 +9776,23 @@ _ACEOF # We don't have --protocols, so just assume that all # protocols are available - _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT" + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" if test x$libcurl_feature_SSL = xyes ; then _libcurl_protocols="$_libcurl_protocols HTTPS" # FTPS wasn't standards-compliant until version - # 7.11.0 + # 7.11.0 (0x070b00 == 461568) if test $_libcurl_version -ge 461568; then _libcurl_protocols="$_libcurl_protocols FTPS" fi fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi fi for _libcurl_protocol in $_libcurl_protocols ; do diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 5834de77eea..cdcc4d0064c 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -1216,9 +1216,21 @@ /* Defined if libcurl supports HTTPS */ #undef LIBCURL_PROTOCOL_HTTPS +/* Defined if libcurl supports IMAP */ +#undef LIBCURL_PROTOCOL_IMAP + /* Defined if libcurl supports LDAP */ #undef LIBCURL_PROTOCOL_LDAP +/* Defined if libcurl supports POP3 */ +#undef LIBCURL_PROTOCOL_POP3 + +/* Defined if libcurl supports RTSP */ +#undef LIBCURL_PROTOCOL_RTSP + +/* Defined if libcurl supports SMTP */ +#undef LIBCURL_PROTOCOL_SMTP + /* Defined if libcurl supports TELNET */ #undef LIBCURL_PROTOCOL_TELNET From 1c949eea6cbd644a9e96b447381faecc5230b85c Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Wed, 6 Jul 2016 10:29:27 -0400 Subject: [PATCH 0545/1578] res_pjsip: Added "subscribe_context" to endpoint If specified, incoming SUBSCRIBE requests will be searched for the matching extension in the indicated context. If no "subscribe_context" is specified, then the "context" setting is used. ASTERISK-25471 #close Change-Id: I3fb7a15f5bc154079bd348c08b7ad1cdd2d5e514 --- CHANGES | 11 ++++++++++ ...deac0ae4717_pjsip_add_subscribe_context.py | 21 +++++++++++++++++++ include/asterisk/res_pjsip.h | 2 ++ res/res_pjsip.c | 12 +++++++++++ res/res_pjsip/pjsip_configuration.c | 1 + res/res_pjsip_exten_state.c | 10 ++++++--- 6 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py diff --git a/CHANGES b/CHANGES index 6e6bec6d07a..19a2830a4cd 100644 --- a/CHANGES +++ b/CHANGES @@ -360,6 +360,17 @@ cdr_csv post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- +------------------------------------------------------------------------------ + +res_pjsip +------------------ + * Added "subscribe_context" to endpoint. + If specified, incoming SUBSCRIBE requests will be searched for the matching + extension in the indicated context. If no "subscribe_context" is specified, + then the "context" setting is used. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- ------------------------------------------------------------------------------ diff --git a/contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py b/contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py new file mode 100644 index 00000000000..2358fdd5937 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py @@ -0,0 +1,21 @@ +"""pjsip_add_subscribe_context + +Revision ID: 9deac0ae4717 +Revises: ef7efc2d3964 +Create Date: 2016-07-04 12:11:28.117788 + +""" + +# revision identifiers, used by Alembic. +revision = '9deac0ae4717' +down_revision = 'ef7efc2d3964' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('subscribe_context', sa.String(40))) + +def downgrade(): + op.drop_column('ps_endpoints', 'subscribe_context') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index f9f9e2037eb..db559921394 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -505,6 +505,8 @@ struct ast_sip_endpoint_subscription_configuration { unsigned int minexpiry; /*! Message waiting configuration */ struct ast_sip_mwi_configuration mwi; + /* Context for SUBSCRIBE requests */ + char context[AST_MAX_CONTEXT]; }; /*! diff --git a/res/res_pjsip.c b/res/res_pjsip.c index d99c1cf841d..af2f93749f0 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -900,6 +900,15 @@ mask with a slash ('/') + + Context for incoming MESSAGE requests. + + If specified, incoming SUBSCRIBE requests will be searched for the matching + extension in the indicated context. + If no subscribe_context is specified, + then the context setting is used. + + Authentication type @@ -1964,6 +1973,9 @@ The number of active channels associated with this endpoint. + + + diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 8a5ff416ad6..a8b451767b2 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1859,6 +1859,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_deny", "", endpoint_acl_handler, NULL, NULL, 0, 0); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 25b9bf1fe84..9bb53bfe31c 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -412,9 +412,11 @@ static void subscription_shutdown(struct ast_sip_subscription *sub) static int new_subscribe(struct ast_sip_endpoint *endpoint, const char *resource) { - if (!ast_exists_extension(NULL, endpoint->context, resource, PRIORITY_HINT, NULL)) { + const char *context = S_OR(endpoint->subscription.context, endpoint->context); + + if (!ast_exists_extension(NULL, context, resource, PRIORITY_HINT, NULL)) { ast_log(LOG_NOTICE, "Extension state subscription failed: Extension %s does not exist in context '%s' or has no associated hint\n", - resource, endpoint->context); + resource, context); return 404; } @@ -432,7 +434,9 @@ static int subscription_established(struct ast_sip_subscription *sip_sub) return -1; } - ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context)); + ast_copy_string(exten_state_sub->context, + S_OR(endpoint->subscription.context, endpoint->context), + sizeof(exten_state_sub->context)); ast_copy_string(exten_state_sub->exten, resource, sizeof(exten_state_sub->exten)); if ((exten_state_sub->id = ast_extension_state_add_destroy_extended( From fb96492ec49b75eb8b6d60e1ce5b68cd8b57c1df Mon Sep 17 00:00:00 2001 From: Scott Griepentrog Date: Thu, 7 Jul 2016 10:55:42 -0500 Subject: [PATCH 0546/1578] PJSIP: provide valid tcp nodelay option for reuse When using TCP transport with chan_pjsip, the TCP_NODELAY option value was allocated on the stack, then passed as a pointer to the tcp transport configuration structure, and later re-used on subsequently created sockets when it was no longer valid. This patch changes the allocation to be a static. ASTERISK-26180 #close Reported by: Scott Griepentrog Change-Id: I3251164c7f710dbdab031282f00e30a9770626a0 --- res/res_pjsip/config_transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index b9208976fc3..60b4507cdb8 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -562,12 +562,13 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) } } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; - int option = 1; + static int option = 1; pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family); cfg.bind_addr = temp_state->state->host; cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); + /* sockopt_params.options is copied to each newly connected socket */ cfg.sockopt_params.options[0].level = pj_SOL_TCP(); cfg.sockopt_params.options[0].optname = pj_TCP_NODELAY(); cfg.sockopt_params.options[0].optval = &option; From 302be4809aefc850f9b2335e074e5c88c4655fb6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 7 Jul 2016 12:38:45 -0300 Subject: [PATCH 0547/1578] chan_sip/res_pjsip_t38: Handle a request to negotiate T.38 after it is enabled. Some T.38 implementations may send another re-invite after the initial one which adds additional negotiation details (such as the max bitrate). Currently this will fail when passthrough is being done in chan_sip as we do nothing if T.38 is already active. Other handlers of T.38 inside of Asterisk (such as res_fax) handle this scenario so this change adds support for it to chan_sip and res_pjsip_t38. If a request to negotiate is received while T.38 is already enabled a new re-INVITE is sent and negotiation is done again. ASTERISK-26179 #close Change-Id: I0298494d3da6df3219bbfa4be9aa04015043145c --- channels/chan_sip.c | 3 ++- res/res_pjsip_t38.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index e086711c2ca..28379ff85d9 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -7669,7 +7669,8 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_ ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp); change_t38_state(p, T38_ENABLED); transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL); - } else if (p->t38.state != T38_ENABLED) { + } else if ((p->t38.state != T38_ENABLED) || ((p->t38.state == T38_ENABLED) && + (parameters->request_response == AST_T38_REQUEST_NEGOTIATE))) { p->t38.our_parms = *parameters; ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp); change_t38_state(p, T38_LOCAL_REINVITE); diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index c02517104b1..76720acee2b 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -361,7 +361,9 @@ static int t38_interpret_parameters(void *obj) ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp); t38_change_state(data->session, session_media, state, T38_ENABLED); ast_sip_session_resume_reinvite(data->session); - } else if (data->session->t38state != T38_ENABLED) { + } else if ((data->session->t38state != T38_ENABLED) || + ((data->session->t38state == T38_ENABLED) && + (parameters->request_response == AST_T38_REQUEST_NEGOTIATE))) { if (t38_initialize_session(data->session, session_media)) { break; } From c832f100d9c019d85eed9219b2577d38c935c7b4 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 4 Jul 2016 17:38:57 -0400 Subject: [PATCH 0548/1578] res_sorcery_realtime: fix bug when successful UPDATE is treated as failed If the SQL UPDATE statement changes nothing then SQLRowCount returns 0. This value should be treated as success. But the function sorcery_realtime_update treats it as failed. This bug was found using stress tests on PJSIP. If there are 2 consecutive SIP REGISTER requests with the same contact data during 1 second then res_pjsip_registrar adds contact location on 1st request and tries to update contact location on 2nd. The update fails and res_pjsip_registrar even removes correct contact location. The test "object_update_uncreated" was removed from test_sorcery_realtime.c because it's now a valid situation. This patch also adds missing debug of extra SQL parameter. ASTERISK-26172 #close Change-Id: I05a7f3051455336c9dda29efc229decf86071303 --- res/res_config_odbc.c | 1 + res/res_sorcery_realtime.c | 2 +- tests/test_sorcery_realtime.c | 37 ----------------------------------- 3 files changed, 2 insertions(+), 38 deletions(-) diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 37c6d3ff905..26aa17b1704 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -137,6 +137,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data) if (!ast_strlen_zero(cps->extra)) { const char *newval = cps->extra; + ast_debug(1, "Parameter %d = '%s'\n", x, newval); if (strchr(newval, ';') || strchr(newval, '^')) { ENCODE_CHUNK(encodebuf, newval); ast_string_field_set(cps, encoding[x], encodebuf); diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index abf2840fb92..4023654ab27 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -271,7 +271,7 @@ static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data return -1; } - return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0; + return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) < 0) ? -1 : 0; } static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object) diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c index b33031e8e82..033bf5d6f64 100644 --- a/tests/test_sorcery_realtime.c +++ b/tests/test_sorcery_realtime.c @@ -711,41 +711,6 @@ AST_TEST_DEFINE(object_update) return AST_TEST_PASS; } -AST_TEST_DEFINE(object_update_uncreated) -{ - RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); - RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup); - - switch (cmd) { - case TEST_INIT: - info->name = "object_update_uncreated"; - info->category = "/res/sorcery_realtime/"; - info->summary = "sorcery object update unit test"; - info->description = - "Test updating of an uncreated object in sorcery using realtime wizard"; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { - ast_test_status_update(test, "Failed to open sorcery structure\n"); - return AST_TEST_FAIL; - } - - if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) { - ast_test_status_update(test, "Failed to allocate a known object type\n"); - return AST_TEST_FAIL; - } - - if (!ast_sorcery_update(sorcery, obj)) { - ast_test_status_update(test, "Successfully updated an object which has not been created yet\n"); - return AST_TEST_FAIL; - } - - return AST_TEST_PASS; -} - AST_TEST_DEFINE(object_delete) { RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); @@ -942,7 +907,6 @@ static int unload_module(void) AST_TEST_UNREGISTER(object_retrieve_regex); AST_TEST_UNREGISTER(object_retrieve_regex_nofetch); AST_TEST_UNREGISTER(object_update); - AST_TEST_UNREGISTER(object_update_uncreated); AST_TEST_UNREGISTER(object_delete); AST_TEST_UNREGISTER(object_delete_uncreated); AST_TEST_UNREGISTER(object_allocate_on_retrieval); @@ -964,7 +928,6 @@ static int load_module(void) AST_TEST_REGISTER(object_retrieve_regex); AST_TEST_REGISTER(object_retrieve_regex_nofetch); AST_TEST_REGISTER(object_update); - AST_TEST_REGISTER(object_update_uncreated); AST_TEST_REGISTER(object_delete); AST_TEST_REGISTER(object_delete_uncreated); AST_TEST_REGISTER(object_allocate_on_retrieval); From 7408c51a48cbe98f3e19c0935659bbba1b5f76bb Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 7 Jul 2016 13:44:39 -0400 Subject: [PATCH 0549/1578] REF_DEBUG: Prevent logging of container node objects. Using AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE can result in an unref being recorded to the refs log for the node being replaced. This prevents logging of those unrefs since they would produce errors in refcounter.py. ASTERISK-26181 #close Change-Id: Ie4fded84e8a1a58b3a59ce59dfd7eb0da3ddc5d4 --- main/astobj2_hash.c | 4 ++-- main/astobj2_rbtree.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main/astobj2_hash.c b/main/astobj2_hash.c index b036911b484..072cd181556 100644 --- a/main/astobj2_hash.c +++ b/main/astobj2_hash.c @@ -274,7 +274,7 @@ static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash break; case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE: SWAP(cur->common.obj, node->common.obj); - ao2_t_ref(node, -1, "Discard the new node."); + ao2_t_ref(node, -1, NULL); return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED; } } @@ -307,7 +307,7 @@ static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash break; case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE: SWAP(cur->common.obj, node->common.obj); - ao2_t_ref(node, -1, "Discard the new node."); + ao2_t_ref(node, -1, NULL); return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED; } } diff --git a/main/astobj2_rbtree.c b/main/astobj2_rbtree.c index b06813d6fd3..03efd886fca 100644 --- a/main/astobj2_rbtree.c +++ b/main/astobj2_rbtree.c @@ -1243,7 +1243,7 @@ static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree break; case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE: SWAP(cur->common.obj, node->common.obj); - ao2_t_ref(node, -1, "Don't need the new node."); + ao2_t_ref(node, -1, NULL); return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED; } From ad30d60c692b53eeb305ee6ee166a108144d03bb Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 9 Jul 2016 14:32:27 -0400 Subject: [PATCH 0550/1578] chan_sip: Fix reference leaks in error paths. * get_sip_pvt_from_replaces leaks sip_pvt_ptr on any error. * build_peer leaks peer on failure to allocate the endpoint. This patch fixes get_sip_pvt by using an RAII_VAR, build_peer is fixed with an unref in the appropriate place. ASTERISK-26184 #close Change-Id: I728b424648ad041409f7d90880f4c28b3ce2ca12 --- channels/chan_sip.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 28379ff85d9..599ecd639e2 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -18386,7 +18386,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re static int get_sip_pvt_from_replaces(const char *callid, const char *totag, const char *fromtag, struct sip_pvt **out_pvt, struct ast_channel **out_chan) { - struct sip_pvt *sip_pvt_ptr; + RAII_VAR(struct sip_pvt *, sip_pvt_ptr, NULL, ao2_cleanup); struct sip_pvt tmp_dialog = { .callid = callid, }; @@ -18461,6 +18461,9 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag, } } + /* If we're here sip_pvt_ptr has been copied to *out_pvt, prevent RAII_VAR cleanup */ + sip_pvt_ptr = NULL; + return 0; } @@ -31095,6 +31098,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str return NULL; } if (!(peer->endpoint = ast_endpoint_create("SIP", name))) { + ao2_t_ref(peer, -1, "failed to allocate endpoint, drop peer"); return NULL; } if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { From 8476a9332fb0a1bff0b18a5ec30ec012be8a6798 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 11 Jul 2016 17:17:47 +0200 Subject: [PATCH 0551/1578] install_prereq: Checkout of libSRTP 1.5.x. Since 5th November 2014, the master branch of libSRTP changed the prefix of several member names and is not compatible with the source code in Asterisk anymore. Therefore instead, this change checks out the latest version of the libSRTP 1.5.x branch. Furthermore now, libSRTP is compiled with OpenSSL as backend. This makes AES-GCM and AES-IN possible. ASTERISK-22131 #close Change-Id: I2e396cdc01da0ff610686e398ed210ca7408f7d6 --- contrib/scripts/install_prereq | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/scripts/install_prereq b/contrib/scripts/install_prereq index bda28e9f7ee..fb240890bb4 100755 --- a/contrib/scripts/install_prereq +++ b/contrib/scripts/install_prereq @@ -175,7 +175,9 @@ install_unpackaged() { cd libsrtp git pull fi - ./configure CFLAGS=-fPIC && make libsrtp.a && make uninstall && make install + git checkout "1_5_x_throttle" + ./configure --disable-debug --disable-stdout --enable-openssl + make shared_library uninstall install cd .. echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local.conf /sbin/ldconfig From 44f16af7cc9a6bc5203106a81b595997cb31c4fd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 11 Jul 2016 13:42:55 -0500 Subject: [PATCH 0552/1578] ast_expr2: Fix off-nominal memory leak. Thanks to ibercom for pointing out a memory leak that was missed in the earlier patch for the issue. ASTERISK-26119 Reported by: Alexei Gradinari Change-Id: I9a151f5c4725d97fb82a9e938bc73dc659532b71 --- main/ast_expr2.c | 2 ++ main/ast_expr2.y | 2 ++ 2 files changed, 4 insertions(+) diff --git a/main/ast_expr2.c b/main/ast_expr2.c index b914598ec82..215f8312fd3 100644 --- a/main/ast_expr2.c +++ b/main/ast_expr2.c @@ -3673,6 +3673,8 @@ op_tildetilde (struct val *a, struct val *b) vs = malloc(strlen(a->u.s)+strlen(b->u.s)+1); if (vs == NULL) { ast_log(LOG_WARNING, "malloc() failed\n"); + free_value(a); + free_value(b); return NULL; } diff --git a/main/ast_expr2.y b/main/ast_expr2.y index 29fee35cf6c..8b32b2b9c01 100644 --- a/main/ast_expr2.y +++ b/main/ast_expr2.y @@ -1666,6 +1666,8 @@ op_tildetilde (struct val *a, struct val *b) vs = malloc(strlen(a->u.s)+strlen(b->u.s)+1); if (vs == NULL) { ast_log(LOG_WARNING, "malloc() failed\n"); + free_value(a); + free_value(b); return NULL; } From 110b01a0bc59b3cf6570cfabec7684627371fb2b Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 12 Jul 2016 10:50:22 +0200 Subject: [PATCH 0553/1578] BuildSystem: Allow own CFLAGS on ./configure. Before this change, make failed with the error Unknown value '' found in build_tools/menuselect-deps for NATIVE_ARCH when CFLAGS were supplied to the configure script. This was introduced with which disabled BUILD_NATIVE when CFLAGS were supplied. Those who need different -march= values, please, go for ./configure make menuselect.makeopts or make menuselect ./menuselect/menuselect --disable BUILD_NATIVE ASTERISK-25289 #close Change-Id: Ic6365d5a97bb9b3556858f06432a8d1cfa83eebc --- configure | 12 +++--------- configure.ac | 11 +++-------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/configure b/configure index 5e5667c97d4..b8d4b33a3a8 100755 --- a/configure +++ b/configure @@ -17919,19 +17919,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -march=native support" >&5 $as_echo_n "checking for -march=native support... " >&6; } if $(${CC} -march=native -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then - if test "${CONFIG_CFLAGS}" = ""; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - AST_NATIVE_ARCH=1 - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: user CFLAGS present" >&5 -$as_echo "user CFLAGS present" >&6; } - AST_NATIVE_ARCH= - fi + AST_NATIVE_ARCH=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - AST_NATIVE_ARCH= + AST_NATIVE_ARCH=0 fi diff --git a/configure.ac b/configure.ac index 6256ef7fb82..3cb0fed05f3 100644 --- a/configure.ac +++ b/configure.ac @@ -1217,16 +1217,11 @@ AC_SUBST(AST_SHADOW_WARNINGS) AC_MSG_CHECKING(for -march=native support) if $(${CC} -march=native -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then - if test "${CONFIG_CFLAGS}" = ""; then - AC_MSG_RESULT(yes) - AST_NATIVE_ARCH=1 - else - AC_MSG_RESULT(user CFLAGS present) - AST_NATIVE_ARCH= - fi + AC_MSG_RESULT(yes) + AST_NATIVE_ARCH=1 else AC_MSG_RESULT(no) - AST_NATIVE_ARCH= + AST_NATIVE_ARCH=0 fi AC_SUBST(AST_NATIVE_ARCH) From 4ad333bb0e365b8a2795756225794c9d0b09e05c Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 10 Jul 2016 21:08:28 -0300 Subject: [PATCH 0554/1578] func_odbc: Fix connection deadlock. The func_odbc module was modified to ensure that the previous behavior of using a single database connection was maintained. This was done by getting a single database connection and holding on to it. With the new multiple connection support in res_odbc this will actually starve every other thread from getting access to the database as it also maintains the previous behavior of having only a single database connection. This change disables the func_odbc specific behavior if the res_odbc module is running with only a single database connection active. The connection is only kept for the duration of the request. ASTERISK-26177 #close Change-Id: I9bdbd8a300fb3233877735ad3fd07bce38115b7f --- funcs/func_odbc.c | 16 ++++++++++++++++ include/asterisk/res_odbc.h | 5 +++++ res/res_odbc.c | 16 ++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 489f3734b97..224cd7a7f68 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -388,9 +388,25 @@ static struct odbc_obj *get_odbc_obj(const char *dsn_name, struct dsn **dsn) static inline void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn) { if (dsn && *dsn) { + /* If multiple connections are not enabled then the guarantee + * of a single connection already exists and holding on to the + * connection would prevent any other user from acquiring it + * indefinitely. + */ + if (ast_odbc_get_max_connections((*dsn)->name) < 2) { + ast_odbc_release_obj((*dsn)->connection); + (*dsn)->connection = NULL; + } ao2_unlock(*dsn); ao2_ref(*dsn, -1); *dsn = NULL; + /* Some callers may provide both an obj and dsn. To ensure that + * the connection is not released twice we set it to NULL here if + * present. + */ + if (obj) { + *obj = NULL; + } } else if (obj && *obj) { ast_odbc_release_obj(*obj); *obj = NULL; diff --git a/include/asterisk/res_odbc.h b/include/asterisk/res_odbc.h index 8c7b5495063..137f7d4a545 100644 --- a/include/asterisk/res_odbc.h +++ b/include/asterisk/res_odbc.h @@ -243,4 +243,9 @@ int ast_odbc_text2isolation(const char *txt); */ const char *ast_odbc_isolation2text(int iso); +/*! + * \brief Return the current configured maximum number of connections for a class + */ +unsigned int ast_odbc_get_max_connections(const char *name); + #endif /* _ASTERISK_RES_ODBC_H */ diff --git a/res/res_odbc.c b/res/res_odbc.c index a89c954924a..bd64b9fef67 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -744,6 +744,22 @@ static int aoro2_class_cb(void *obj, void *arg, int flags) return 0; } +unsigned int ast_odbc_get_max_connections(const char *name) +{ + struct odbc_class *class; + unsigned int max_connections; + + class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name); + if (!class) { + return 0; + } + + max_connections = class->maxconnections; + ao2_ref(class, -1); + + return max_connections; +} + /* * \brief Determine if the connection has died. * From b85446d039d59afd0ffa6b79884e0ea44717a49b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 11 Jul 2016 10:25:04 -0500 Subject: [PATCH 0555/1578] res_pjsip: Fix statsd regression. The ASTERISK-25904 change-id I8fad8aae9305481469c38d2146e1ba3a56d3108f patch introduced several regressions when the newly created "Updated" state goes out for each endpoint registration refresh. 1) It restarted any OPTIONS RTT ping cycle. 2) It would interfere with a currently active ping and throw off that ping's resulting RTT calculation. 3) It cleared the RTT time each time the endpoint was refreshed. 4) The cleared RTT time was sent out as a statsd update each time. 5) It created two AMI events for each update. * Revert the original patch and reimplement it. Now the current contact status state is re-sent instead of the state being momentarily toggled every time the endpoint refreshes its registration. The statsd events are not created for the re-sent refresh because they are sent after every OPTIONS ping. ASTERISK-26160 #close Reported by: Matt Jordan Change-Id: Ie072be790fbb2a8f5c1c874266e4143fa31f66d1 --- CHANGES | 2 - include/asterisk/res_pjsip.h | 3 +- res/res_pjsip/pjsip_configuration.c | 64 +++++++++++++++------- res/res_pjsip/pjsip_options.c | 84 +++++++++++++++++++---------- 4 files changed, 105 insertions(+), 48 deletions(-) diff --git a/CHANGES b/CHANGES index 6e6bec6d07a..cbe03fd3e54 100644 --- a/CHANGES +++ b/CHANGES @@ -397,8 +397,6 @@ res_pjsip "contact_deny" - List of Contact header addresses to deny "contact_permit" - List of Contact header addresses to permit - * Added new status Updated to AMI event ContactStatus on update registration - * Added "reg_server" to contacts. If the Asterisk system name is set in asterisk.conf, it will be stored into the "reg_server" field in the ps_contacts table to facilitate diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index f9f9e2037eb..f43a11cb04f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -271,7 +271,6 @@ enum ast_sip_contact_status_type { UNKNOWN, CREATED, REMOVED, - UPDATED, }; /*! @@ -296,6 +295,8 @@ struct ast_sip_contact_status { int64_t rtt; /*! Last status for a contact (default - unavailable) */ enum ast_sip_contact_status_type last_status; + /*! TRUE if the contact was refreshed. e.g., re-registered */ + unsigned int refresh:1; }; /*! diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 8a5ff416ad6..6890cedf0a8 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -105,6 +105,40 @@ static void endpoint_update_state(struct ast_endpoint *endpoint, enum ast_endpoi ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint)); } +static void endpoint_publish_contact_status(struct ast_endpoint *endpoint, struct ast_sip_contact_status *contact) +{ + struct ast_json *blob; + char rtt[32]; + + snprintf(rtt, sizeof(rtt), "%" PRId64, contact->rtt); + blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", + "contact_status", ast_sip_get_contact_status_label(contact->status), + "aor", contact->aor, + "uri", contact->uri, + "roundtrip_usec", rtt, + "endpoint_name", ast_endpoint_get_resource(endpoint)); + if (blob) { + ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); + ast_json_unref(blob); + } +} + +/*! \brief Callback function for publishing the status of an endpoint */ +static int persistent_endpoint_publish_status(void *obj, void *arg, int flags) +{ + struct sip_persistent_endpoint *persistent = obj; + struct ast_endpoint *endpoint = persistent->endpoint; + struct ast_sip_contact_status *status = arg; + + /* If the status' aor isn't one of the endpoint's, we skip */ + if (!strstr(persistent->aors, status->aor)) { + return 0; + } + + endpoint_publish_contact_status(endpoint, status); + return 0; +} + /*! \brief Callback function for changing the state of an endpoint */ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) { @@ -112,30 +146,17 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) struct ast_endpoint *endpoint = persistent->endpoint; struct ast_sip_contact_status *status = arg; struct ao2_container *contacts; - struct ast_json *blob; struct ao2_iterator i; struct ast_sip_contact *contact; enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; - if (status) { - char rtt[32]; - - /* If the status' aor isn't one of the endpoint's, we skip */ - if (!strstr(persistent->aors, status->aor)) { - return 0; - } - - snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt); - blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", - "contact_status", ast_sip_get_contact_status_label(status->status), - "aor", status->aor, - "uri", status->uri, - "roundtrip_usec", rtt, - "endpoint_name", ast_endpoint_get_resource(endpoint)); - ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); - ast_json_unref(blob); + /* If the status' aor isn't one of the endpoint's, we skip */ + if (!strstr(persistent->aors, status->aor)) { + return 0; } + endpoint_publish_contact_status(endpoint, status); + /* Find all the contacts for this endpoint. If ANY are available, * mark the endpoint as ONLINE. */ @@ -222,6 +243,13 @@ static void persistent_endpoint_contact_status_observer(const void *object) { struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object; + if (contact_status->refresh) { + /* We are only re-publishing the contact status. */ + ao2_callback(persistent_endpoints, OBJ_NODATA, + persistent_endpoint_publish_status, contact_status); + return; + } + /* If rtt_start is set (this is the outgoing OPTIONS), ignore. */ if (contact_status->rtt_start.tv_sec > 0) { return; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index dc3bce06f1d..808ee171a1c 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -43,7 +43,6 @@ static const char *status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", - [UPDATED] = "Updated", }; static const char *short_status_map [] = { @@ -52,7 +51,6 @@ static const char *short_status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", - [UPDATED] = "Updated", }; const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status) @@ -157,7 +155,7 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const * \brief Update an ast_sip_contact_status's elements. */ static void update_contact_status(const struct ast_sip_contact *contact, - enum ast_sip_contact_status_type value) + enum ast_sip_contact_status_type value, int is_contact_refresh) { RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup); @@ -169,6 +167,26 @@ static void update_contact_status(const struct ast_sip_contact *contact, return; } + if (is_contact_refresh + && status->status == CREATED) { + /* + * The contact status hasn't been updated since creation + * and we don't want to re-send a created status. + */ + if (contact->qualify_frequency + || status->rtt_start.tv_sec > 0) { + /* Ignore, the status will change soon. */ + return; + } + + /* + * Convert to a regular contact status update + * because the status may never change. + */ + is_contact_refresh = 0; + value = UNKNOWN; + } + update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(status)); if (!update) { @@ -178,22 +196,35 @@ static void update_contact_status(const struct ast_sip_contact *contact, } ast_string_field_set(update, uri, contact->uri); - update->last_status = status->status; - update->status = value; - - /* if the contact is available calculate the rtt as - the diff between the last start time and "now" */ - update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ? - ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0; - update->rtt_start = ast_tv(0, 0); - - ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", - "Contact: %s\r\n" - "Status: %s\r\n" - "RTT: %" PRId64, - ast_sorcery_object_get_id(update), - ast_sip_get_contact_status_label(update->status), - update->rtt); + + if (is_contact_refresh) { + /* Copy everything just to set the refresh flag. */ + update->status = status->status; + update->last_status = status->last_status; + update->rtt = status->rtt; + update->rtt_start = status->rtt_start; + update->refresh = 1; + } else { + update->last_status = status->status; + update->status = value; + + /* + * if the contact is available calculate the rtt as + * the diff between the last start time and "now" + */ + update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 + ? ast_tvdiff_us(ast_tvnow(), status->rtt_start) + : 0; + update->rtt_start = ast_tv(0, 0); + + ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", + "Contact: %s\r\n" + "Status: %s\r\n" + "RTT: %" PRId64, + ast_sorcery_object_get_id(update), + ast_sip_get_contact_status_label(update->status), + update->rtt); + } if (ast_sorcery_update(ast_sip_get_sorcery(), update)) { ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", @@ -306,10 +337,10 @@ static void qualify_contact_cb(void *token, pjsip_event *e) /* Fall through */ case PJSIP_EVENT_TRANSPORT_ERROR: case PJSIP_EVENT_TIMER: - update_contact_status(contact, UNAVAILABLE); + update_contact_status(contact, UNAVAILABLE, 0); break; case PJSIP_EVENT_RX_MSG: - update_contact_status(contact, AVAILABLE); + update_contact_status(contact, AVAILABLE, 0); break; } ao2_cleanup(contact); @@ -365,7 +396,7 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n", contact->uri); - update_contact_status(contact, UNAVAILABLE); + update_contact_status(contact, UNAVAILABLE, 0); ao2_ref(contact, -1); return -1; } @@ -525,7 +556,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact) schedule_qualify(contact, contact->qualify_frequency * 1000); } else { - update_contact_status(contact, UNKNOWN); + update_contact_status(contact, UNKNOWN, 0); } } @@ -544,8 +575,7 @@ static void contact_created(const void *obj) */ static void contact_updated(const void *obj) { - update_contact_status((struct ast_sip_contact *) obj, UPDATED); - qualify_and_schedule((struct ast_sip_contact *) obj); + update_contact_status(obj, AVAILABLE, 1); } /*! @@ -574,8 +604,8 @@ static void contact_deleted(const void *obj) static const struct ast_sorcery_observer contact_observer = { .created = contact_created, + .updated = contact_updated, .deleted = contact_deleted, - .updated = contact_updated }; static pj_bool_t options_start(void) @@ -1051,7 +1081,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact) if (contact->qualify_frequency) { schedule_qualify(contact, initial_interval); } else { - update_contact_status(contact, UNKNOWN); + update_contact_status(contact, UNKNOWN, 0); } } From 886f2cab232e1dca65a90036aef39eda27443f4e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 11 Jul 2016 19:07:20 -0600 Subject: [PATCH 0556/1578] rest_api/channels: Fix multiple issues with create and dial * We weren't properly subscribing to the channel and it's originator on create. * We weren't doing a publish_dial after calling ast_call on dial. * We weren't calling depart_bridge when a channel left the dial bridge. The first 2 issues were causing events to not be generated and the third was actually causing channels to not get properly destroyed when hung up. Together these 3 issues were causing the new rest_apichannels/create_dial_bridge tests to fail. As a result of the fixes, the cdr state machine had to be slightly tweaked to allow bridge leave events without asserting and the tests themselves had to be updated to account for the channels now cleaning themselves up. Change-Id: Ibf23abf5a62de76e82afb4461af5099c961b97d8 --- main/cdr.c | 4 +--- res/ari/resource_channels.c | 12 +++++++++++- res/stasis/control.c | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 586a10684a3..e2f9b764cf2 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1409,9 +1409,7 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel) { - /* In general, most things shouldn't get a bridge leave */ - ast_assert(0); - return 1; + return 0; } static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status) diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index bce7c7def2f..35b757267c3 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -1776,6 +1776,9 @@ void ast_ari_channels_create(struct ast_variable *headers, originator = ast_channel_get_by_name(args->originator); if (originator) { request_cap = ao2_bump(ast_channel_nativeformats(originator)); + if (!ast_strlen_zero(args->app)) { + stasis_app_subscribe_channel(args->app, originator); + } } else if (!ast_strlen_zero(args->formats)) { char *format_name; char *formats_copy = ast_strdupa(args->formats); @@ -1816,13 +1819,20 @@ void ast_ari_channels_create(struct ast_variable *headers, chan_data->chan = ast_request(dialtech, request_cap, &assignedids, originator, dialdevice, &cause); ao2_cleanup(request_cap); - ast_channel_cleanup(originator); + if (!chan_data->chan) { ast_ari_response_alloc_failed(response); + ast_channel_cleanup(originator); chan_data_destroy(chan_data); return; } + if (!ast_strlen_zero(args->app)) { + stasis_app_subscribe_channel(args->app, chan_data->chan); + } + + ast_channel_cleanup(originator); + if (save_dialstring(chan_data->chan, stuff)) { ast_ari_response_alloc_failed(response); chan_data_destroy(chan_data); diff --git a/res/stasis/control.c b/res/stasis/control.c index b255477bf73..219a2c6cd27 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -881,6 +881,9 @@ static struct ast_bridge *get_dial_bridge(void) return ret_bridge; } +static int bridge_channel_depart(struct stasis_app_control *control, + struct ast_channel *chan, void *data); + /*! * \brief after bridge callback for the dial bridge * @@ -890,6 +893,15 @@ static struct ast_bridge *get_dial_bridge(void) static void dial_bridge_after_cb(struct ast_channel *chan, void *data) { struct stasis_app_control *control = data; + struct ast_bridge_channel *bridge_channel; + + ast_channel_lock(chan); + bridge_channel = ast_channel_get_bridge_channel(chan); + ast_channel_unlock(chan); + + ast_debug(3, "Channel: <%s> Reason: %d\n", ast_channel_name(control->channel), ast_channel_hangupcause(chan)); + + stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup); control->bridge = NULL; } @@ -898,6 +910,7 @@ static void dial_bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason, { struct stasis_app_control *control = data; + ast_debug(3, "Channel: <%s> Reason: %d\n", ast_channel_name(control->channel), reason); dial_bridge_after_cb(control->channel, data); } @@ -1443,6 +1456,8 @@ static int app_control_dial(struct stasis_app_control *control, return -1; } + ast_channel_publish_dial(NULL, chan, args->dialstring, NULL); + return 0; } From a3f4141f6f9df4b514774e7a29040521293a2b94 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 13 Jul 2016 15:57:08 +0200 Subject: [PATCH 0557/1578] BuildSystem: Avoid obsolete warning with pthread.m4 on autoconf. Updated the macro-set autoconf/ax_pthread.m4 to its latest upstream version. ASTERISK-26046 #close Change-Id: I11abc11d17acd2b6a8a5a5be8ae8e0949dab9cc7 --- autoconf/acx_pthread.m4 | 243 ------------- autoconf/ax_pthread.m4 | 485 +++++++++++++++++++++++++ configure | 586 +++++++++++++++++++++++++------ configure.ac | 2 +- include/asterisk/autoconfig.h.in | 3 + 5 files changed, 964 insertions(+), 355 deletions(-) delete mode 100644 autoconf/acx_pthread.m4 create mode 100644 autoconf/ax_pthread.m4 diff --git a/autoconf/acx_pthread.m4 b/autoconf/acx_pthread.m4 deleted file mode 100644 index b7ee73ddb14..00000000000 --- a/autoconf/acx_pthread.m4 +++ /dev/null @@ -1,243 +0,0 @@ -dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -dnl -dnl @summary figure out how to build C programs using POSIX threads -dnl -dnl This macro figures out how to build C programs using POSIX threads. -dnl It sets the PTHREAD_LIBS output variable to the threads library and -dnl linker flags, and the PTHREAD_CFLAGS output variable to any special -dnl C compiler flags that are needed. (The user can also force certain -dnl compiler flags/libs to be tested by setting these environment -dnl variables.) -dnl -dnl Also sets PTHREAD_CC to any special C compiler that is needed for -dnl multi-threaded programs (defaults to the value of CC otherwise). -dnl (This is necessary on AIX to use the special cc_r compiler alias.) -dnl -dnl NOTE: You are assumed to not only compile your program with these -dnl flags, but also link it with them as well. e.g. you should link -dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS -dnl $LIBS -dnl -dnl If you are only building threads programs, you may wish to use -dnl these variables in your default LIBS, CFLAGS, and CC: -dnl -dnl LIBS="$PTHREAD_LIBS $LIBS" -dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -dnl CC="$PTHREAD_CC" -dnl -dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute -dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to -dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -dnl -dnl ACTION-IF-FOUND is a list of shell commands to run if a threads -dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to -dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the -dnl default action will define HAVE_PTHREAD. -dnl -dnl Please let the authors know if this macro fails on any platform, or -dnl if you have any other suggestions or comments. This macro was based -dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with -dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros -dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. -dnl We are also grateful for the helpful feedback of numerous users. -dnl -dnl @category InstalledPackages -dnl @author Steven G. Johnson -dnl @version 2006-05-29 -dnl @license GPLWithACException - -AC_DEFUN([ACX_PTHREAD], -[ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_SAVE -AC_LANG_C -acx_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) - AC_MSG_RESULT($acx_pthread_ok) - if test x"$acx_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case "${host_cpu}-${host_os}" in - *solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" - ;; -esac - -if test x"$acx_pthread_ok" = xno; then -for flag in $acx_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - pthread-config) - AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) - if test x"$acx_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_TRY_LINK([#include ], - [pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], - [acx_pthread_ok=yes]) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT($acx_pthread_ok) - if test "x$acx_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$acx_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_TRY_LINK([#include ], [int attr=$attr; return attr;], - [attr_name=$attr; break]) - done - AC_MSG_RESULT($attr_name) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; - esac - AC_MSG_RESULT(${flag}) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: must compile with xlc_r or cc_r - if test x"$GCC" != xyes; then - AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) - else - PTHREAD_CC=$CC - fi -else - PTHREAD_CC="$CC" -fi - -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_CC) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$acx_pthread_ok" = xyes; then - ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) - : -else - acx_pthread_ok=no - $2 -fi -AC_LANG_RESTORE -])dnl ACX_PTHREAD diff --git a/autoconf/ax_pthread.m4 b/autoconf/ax_pthread.m4 new file mode 100644 index 00000000000..4c4051ea376 --- /dev/null +++ b/autoconf/ax_pthread.m4 @@ -0,0 +1,485 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC to any special C compiler that is needed for +# multi-threaded programs (defaults to the value of CC otherwise). (This +# is necessary on AIX to use the special cc_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also to link with them as well. For example, you might link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threaded programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 23 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff --git a/configure b/configure index 2834ada5861..567d5122d87 100755 --- a/configure +++ b/configure @@ -1187,7 +1187,7 @@ NOISY_BUILD PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC -acx_pthread_config +ax_pthread_config MD5 SOXMIX PBX_FLEX @@ -7927,6 +7927,76 @@ if test "${MD5}" = "digest" ; then MD5="${MD5} -a md5" fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + + @@ -7936,22 +8006,26 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -acx_pthread_ok=no +ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). +# requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + if test "x$PTHREAD_CC" != "x"; then : + CC="$PTHREAD_CC" +fi CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 -$as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5 +$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7971,18 +8045,19 @@ return pthread_join (); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - acx_pthread_ok=yes + ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 -$as_echo "$acx_pthread_ok" >&6; } - if test x"$acx_pthread_ok" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -7995,7 +8070,7 @@ fi # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. -acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: @@ -8004,59 +8079,269 @@ acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -m # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case "${host_cpu}-${host_os}" in - *solaris*) +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 +$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} +fi +rm -f conftest* + + ;; + + solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +if test "x$GCC" = "xyes"; then : + ax_pthread_flags="-pthread -pthreads $ax_pthread_flags" +fi + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; - acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" + *) + ax_pthread_check_macro="--" ;; esac +if test "x$ax_pthread_check_macro" = "x--"; then : + ax_pthread_check_cond=0 +else + ax_pthread_check_cond="!defined($ax_pthread_check_macro)" +fi + +# Are we compiling with Clang? + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5 +$as_echo_n "checking whether $CC is Clang... " >&6; } +if ${ax_cv_PTHREAD_CLANG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then : + ax_cv_PTHREAD_CLANG=yes +fi +rm -f conftest* + + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG" >&6; } +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5 +$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; } +if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + if test "x$ax_pthread_try" = "xunknown"; then : + break +fi + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_link="$ax_pthread_2step_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + if test "x$ax_pthread_try" = "x"; then : + ax_pthread_try=no +fi + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac -if test x"$acx_pthread_ok" = xno; then -for flag in $acx_pthread_flags; do +fi # $ax_pthread_clang = yes - case $flag in +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in none) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 $as_echo_n "checking whether pthreads work without any flags... " >&6; } ;; + -mt,pthread) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with -mt -lpthread" >&5 +$as_echo_n "checking whether pthreads work with -mt -lpthread... " >&6; } + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + -*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 -$as_echo_n "checking whether pthreads work with $flag... " >&6; } - PTHREAD_CFLAGS="$flag" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5 +$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; } + PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; - pthread-config) - # Extract the first word of "pthread-config", so it can be a program name with args. + pthread-config) + # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_acx_pthread_config+:} false; then : +if ${ac_cv_prog_ax_pthread_config+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$acx_pthread_config"; then - ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test. + if test -n "$ax_pthread_config"; then + ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH @@ -8065,7 +8350,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_acx_pthread_config="yes" + ac_cv_prog_ax_pthread_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -8073,35 +8358,37 @@ done done IFS=$as_save_IFS - test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no" + test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" fi fi -acx_pthread_config=$ac_cv_prog_acx_pthread_config -if test -n "$acx_pthread_config"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5 -$as_echo "$acx_pthread_config" >&6; } +ax_pthread_config=$ac_cv_prog_ax_pthread_config +if test -n "$ax_pthread_config"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 +$as_echo "$ax_pthread_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - if test x"$acx_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; + if test "x$ax_pthread_config" = "xno"; then : + continue +fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 -$as_echo_n "checking for the pthreads library -l$flag... " >&6; } - PTHREAD_LIBS="-l$flag" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5 +$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; } + PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we @@ -8112,33 +8399,42 @@ $as_echo_n "checking for the pthreads library -l$flag... " >&6; } # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; } int main () { -pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0); +pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - acx_pthread_ok=yes + ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 -$as_echo "$acx_pthread_ok" >&6; } - if test "x$acx_pthread_ok" = xyes; then - break; - fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xyes"; then : + break +fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" @@ -8146,63 +8442,127 @@ done fi # Various other checks: -if test "x$acx_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 $as_echo_n "checking for joinable pthread attribute... " >&6; } - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { -int attr=$attr; return attr; +int attr = $ax_pthread_attr; return attr /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - attr_name=$attr; break + ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - done - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 -$as_echo "$attr_name" >&6; } - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 +$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } + if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"; then : cat >>confdefs.h <<_ACEOF -#define PTHREAD_CREATE_JOINABLE $attr_name +#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR _ACEOF - fi + ax_pthread_joinable_attr_defined=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 -$as_echo_n "checking if more special flags are required for pthreads... " >&6; } - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 -$as_echo "${flag}" >&6; } - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5 +$as_echo_n "checking whether more special flags are required for pthreads... " >&6; } +if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 +$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } + if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"; then : + PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 +$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; } +if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int i = PTHREAD_PRIO_INHERIT; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_PTHREAD_PRIO_INHERIT=yes +else + ax_cv_PTHREAD_PRIO_INHERIT=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 +$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } + if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"; then : + +$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h + + ax_pthread_prio_inherit_defined=yes + +fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - # More AIX lossage: must compile with xlc_r or cc_r - if test x"$GCC" != xyes; then - for ac_prog in xlc_r cc_r + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + case "x/$CC" in #( + x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : + #handle absolute path differently from PATH based program lookup + case "x$CC" in #( + x/*) : + if as_fn_executable_p ${CC}_r; then : + PTHREAD_CC="${CC}_r" +fi ;; #( + *) : + for ac_prog in ${CC}_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -8243,27 +8603,31 @@ fi test -n "$PTHREAD_CC" && break done -test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}" - - else - PTHREAD_CC=$CC - fi -else - PTHREAD_CC="$CC" +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + ;; +esac ;; #( + *) : + ;; +esac + ;; + esac + fi fi +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$acx_pthread_ok" = xyes; then +if test "x$ax_pthread_ok" = "xyes"; then $as_echo "#define HAVE_PTHREAD 1" >>confdefs.h : else - acx_pthread_ok=no + ax_pthread_ok=no fi ac_ext=c diff --git a/configure.ac b/configure.ac index 3cb0fed05f3..462976f4f14 100644 --- a/configure.ac +++ b/configure.ac @@ -351,7 +351,7 @@ if test "${MD5}" = "digest" ; then MD5="${MD5} -a md5" fi -ACX_PTHREAD +AX_PTHREAD AC_LANG(C) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index cdcc4d0064c..e41cbfe1d6e 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -707,6 +707,9 @@ */ #undef HAVE_PTHREAD_MUTEX_RECURSIVE_NP +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + /* Define if your system has the PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP headers. */ #undef HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP From f12311ee696e4a623a4160aa0c2a83712088b5d3 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 19 Oct 2015 18:55:33 -0500 Subject: [PATCH 0558/1578] res/res_corosync: Raise a Stasis message on node join/leave events When res_corosync detects that a node leaves or joins, it currently is informed of this via Corosync callbacks. However, there are a few limitations with the information presented: (1) While we have information that Corosync is aware of - such as the Corosync nodeid - that information is really only useful inside of Corosync or res_corosync. There's no way to translate a Corosync nodeid to some other internally useful unique identifier for the Asterisk instance that just joined or left the cluster. (2) While res_corosync is notified of the instance joining or leaving the cluster, it has no mechanism to inform the Asterisk core or other modules of this event. This limits the usefulness of res_corosync as a heartbeat mechanism for other modules. This patch addresses both issues. First, it adds the notion of a cluster discovery message both within the Stasis message bus, as well as the binary event messages that res_corosync uses to transmit data back and forth within the cluster. When Asterisk joins the cluster, it sends a discovery message to the other nodes in the cluster, which correlates the Corosync nodeid along with the Asterisk EID. res_corosync now maintains a hash of Corosync nodeids to Asterisk EIDs, such that it can map changes in cluster state with the Asterisk instance that has that nodeid. Likewise, when an Asterisk instance receives a discovery message from a node in the cluster, it now sends its own discovery message back to the originating node with the local Asterisk EID. This lets Asterisk instances within the cluster build a complete picture of the other Asterisk instances within the cluster. Second, it publishes the discovery messages onto the Stasis message bus. Said messages are published whenever a node joins or leaves the cluster. Interested modules can subscribe for the ast_cluster_discovery_type() message under the ast_system_topic() and be notified when changes in cluster state occur. Change-Id: I9015f418d6ae7f47e4994e04e18948df4d49b465 --- include/asterisk/event_defs.h | 13 +- include/asterisk/stasis_system.h | 6 + main/stasis_system.c | 6 + res/res_corosync.c | 273 +++++++++++++++++++++++++++++-- 4 files changed, 281 insertions(+), 17 deletions(-) diff --git a/include/asterisk/event_defs.h b/include/asterisk/event_defs.h index 80a8d7dda17..2d5c75a44de 100644 --- a/include/asterisk/event_defs.h +++ b/include/asterisk/event_defs.h @@ -58,8 +58,10 @@ enum ast_event_type { AST_EVENT_ACL_CHANGE = 0x0b, /*! Send out a ping for debugging distributed events */ AST_EVENT_PING = 0x0c, + /*! A cluster discovery message */ + AST_EVENT_CLUSTER_DISCOVERY = 0x0d, /*! Number of event types. This should be the last event type + 1 */ - AST_EVENT_TOTAL = 0x0d, + AST_EVENT_TOTAL = 0x0e, }; /*! \brief Event Information Element types */ @@ -302,8 +304,15 @@ enum ast_event_ie_type { * Payload type: UINT */ AST_EVENT_IE_CACHABLE = 0x003d, + + /*! + * \brief Cluster node ID + * Used by: Corosync + * Payload type: UINT + */ + AST_EVENT_IE_NODE_ID = 0x003e, /*! \brief Must be the last IE value +1 */ - AST_EVENT_IE_TOTAL = 0x003e, + AST_EVENT_IE_TOTAL = 0x003f, }; /*! diff --git a/include/asterisk/stasis_system.h b/include/asterisk/stasis_system.h index 8c6e60f4624..274c02e49c8 100644 --- a/include/asterisk/stasis_system.h +++ b/include/asterisk/stasis_system.h @@ -121,6 +121,12 @@ struct stasis_message_type *ast_cc_failure_type(void); */ struct stasis_message_type *ast_cc_monitorfailed_type(void); +/*! + * \brief A \ref stasis_message_type for Cluster discovery + * \since 13.11.0 + */ +struct stasis_message_type *ast_cluster_discovery_type(void); + /*! * \brief Initialize the stasis system topic and message types * \retval 0 on success diff --git a/main/stasis_system.c b/main/stasis_system.c index 7e449b544f7..c3a4d8663eb 100644 --- a/main/stasis_system.c +++ b/main/stasis_system.c @@ -115,6 +115,7 @@ STASIS_MESSAGE_TYPE_DEFN(ast_cc_failure_type, STASIS_MESSAGE_TYPE_DEFN(ast_cc_monitorfailed_type, .to_ami = cc_monitorfailed_to_ami, ); +STASIS_MESSAGE_TYPE_DEFN(ast_cluster_discovery_type); void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause) { @@ -362,6 +363,7 @@ static void stasis_system_cleanup(void) STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_recallcomplete_type); STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_failure_type); STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_monitorfailed_type); + STASIS_MESSAGE_TYPE_CLEANUP(ast_cluster_discovery_type); } /*! \brief Initialize the system level items for \ref stasis */ @@ -422,5 +424,9 @@ int ast_stasis_system_init(void) return -1; } + if (STASIS_MESSAGE_TYPE_INIT(ast_cluster_discovery_type) != 0) { + return -1; + } + return 0; } diff --git a/res/res_corosync.c b/res/res_corosync.c index 6642acd2c4e..675bb330715 100644 --- a/res/res_corosync.c +++ b/res/res_corosync.c @@ -47,11 +47,16 @@ ASTERISK_REGISTER_FILE(); #include "asterisk/app.h" #include "asterisk/stasis.h" #include "asterisk/stasis_message_router.h" +#include "asterisk/stasis_system.h" AST_RWLOCK_DEFINE_STATIC(event_types_lock); static void publish_mwi_to_stasis(struct ast_event *event); static void publish_device_state_to_stasis(struct ast_event *event); +static void publish_cluster_discovery_to_stasis(struct ast_event *event); + +/*! \brief All the nodes that we're aware of */ +static struct ao2_container *nodes; /*! \brief The internal topic used for message forwarding and pings */ static struct stasis_topic *corosync_aggregate_topic; @@ -65,6 +70,78 @@ static struct stasis_topic *corosync_topic(void) return corosync_aggregate_topic; } +struct corosync_node { + /*! The corosync ID */ + int id; + /*! The Asterisk EID */ + struct ast_eid eid; + /*! The IP address of the node */ + struct ast_sockaddr addr; +}; + +static struct corosync_node *corosync_node_alloc(struct ast_event *event) +{ + struct corosync_node *node; + + node = ao2_alloc_options(sizeof(*node), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!node) { + return NULL; + } + + memcpy(&node->eid, (struct ast_eid *)ast_event_get_ie_raw(event, AST_EVENT_IE_EID), sizeof(node->eid)); + node->id = ast_event_get_ie_uint(event, AST_EVENT_IE_NODE_ID); + ast_sockaddr_parse(&node->addr, ast_event_get_ie_str(event, AST_EVENT_IE_LOCAL_ADDR), PARSE_PORT_IGNORE); + + return node; +} + +static int corosync_node_hash_fn(const void *obj, const int flags) +{ + const struct corosync_node *node; + const int *id; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + id = obj; + break; + case OBJ_SEARCH_OBJECT: + node = obj; + id = &node->id; + break; + default: + ast_assert(0); + return 0; + } + return *id; +} + +static int corosync_node_cmp_fn(void *obj, void *arg, int flags) +{ + struct corosync_node *left = obj; + struct corosync_node *right = arg; + const int *id = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + id = &right->id; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = (left->id == *id); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = (left->id == right->id); + break; + default: + /* Sort can only work on something with a full or partial key. */ + ast_assert(0); + cmp = 1; + break; + } + return cmp ? CMP_MATCH : 0; +} + + /*! \brief A payload wrapper around a corosync ping event */ struct corosync_ping_payload { /*! The corosync ping event being passed over \ref stasis */ @@ -167,6 +244,12 @@ static struct { .topic_fn = corosync_topic, .message_type_fn = corosync_ping_message_type, .publish_to_stasis = publish_corosync_ping_to_stasis, }, + [AST_EVENT_CLUSTER_DISCOVERY] = { .name = "cluster_discovery", + .publish_default = 1, + .subscribe_default = 1, + .topic_fn = ast_system_topic, + .message_type_fn = ast_cluster_discovery_type, + .publish_to_stasis = publish_cluster_discovery_to_stasis, }, }; static struct { @@ -197,6 +280,97 @@ static corosync_cfg_callbacks_t cfg_callbacks = { .corosync_cfg_shutdown_callback = cfg_shutdown_cb, }; +/*! \brief Publish cluster discovery to \ref stasis */ +static void publish_cluster_discovery_to_stasis_full(struct corosync_node *node, int joined) +{ + struct ast_json *json; + struct ast_json_payload *payload; + struct stasis_message *message; + char eid[18]; + const char *addr; + + ast_eid_to_str(eid, sizeof(eid), &node->eid); + addr = ast_sockaddr_stringify_addr(&node->addr); + + ast_log(AST_LOG_NOTICE, "Node %u (%s) at %s %s the cluster\n", + node->id, + eid, + addr, + joined ? "joined" : "left"); + + json = ast_json_pack("{s: s, s: i, s: s, s: i}", + "address", addr, + "node_id", node->id, + "eid", eid, + "joined", joined); + if (!json) { + return; + } + + payload = ast_json_payload_create(json); + if (!payload) { + ast_json_unref(json); + return; + } + + message = stasis_message_create(ast_cluster_discovery_type(), payload); + if (!message) { + ast_json_unref(json); + ao2_ref(payload, -1); + return; + } + + stasis_publish(ast_system_topic(), message); + ast_json_unref(json); + ao2_ref(payload, -1); + ao2_ref(message, -1); +} + +static void send_cluster_notify(void); + +/*! \brief Publish a received cluster discovery \ref ast_event to \ref stasis */ +static void publish_cluster_discovery_to_stasis(struct ast_event *event) +{ + struct corosync_node *node; + int id = ast_event_get_ie_uint(event, AST_EVENT_IE_NODE_ID); + struct ast_eid *event_eid; + + ast_assert(ast_event_get_type(event) == AST_EVENT_CLUSTER_DISCOVERY); + + event_eid = (struct ast_eid *)ast_event_get_ie_raw(event, AST_EVENT_IE_EID); + if (!ast_eid_cmp(&ast_eid_default, event_eid)) { + /* Don't feed events back in that originated locally. */ + return; + } + + ao2_lock(nodes); + node = ao2_find(nodes, &id, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (node) { + /* We already know about this node */ + ao2_unlock(nodes); + ao2_ref(node, -1); + return; + } + + node = corosync_node_alloc(event); + if (!node) { + ao2_unlock(nodes); + return; + } + ao2_link_flags(nodes, node, OBJ_NOLOCK); + ao2_unlock(nodes); + + publish_cluster_discovery_to_stasis_full(node, 1); + + ao2_ref(node, -1); + + /* + * When we get news that someone else has joined, we need to let them + * know we exist as well. + */ + send_cluster_notify(); +} + /*! \brief Publish a received MWI \ref ast_event to \ref stasis */ static void publish_mwi_to_stasis(struct ast_event *event) { @@ -228,7 +402,7 @@ static void publish_mwi_to_stasis(struct ast_event *event) if (ast_publish_mwi_state_full(mailbox, context, (int)new_msgs, (int)old_msgs, NULL, event_eid)) { - char eid[16]; + char eid[18]; ast_eid_to_str(eid, sizeof(eid), event_eid); ast_log(LOG_WARNING, "Failed to publish MWI message for %s@%s from %s\n", mailbox, context, eid); @@ -255,7 +429,7 @@ static void publish_device_state_to_stasis(struct ast_event *event) } if (ast_publish_device_state_full(device, state, cachable, event_eid)) { - char eid[16]; + char eid[18]; ast_eid_to_str(eid, sizeof(eid), event_eid); ast_log(LOG_WARNING, "Failed to publish device state message for %s from %s\n", device, eid); @@ -342,10 +516,27 @@ static void cpg_deliver_cb(cpg_handle_t handle, const struct cpg_name *group_nam publish_handler(event); } -static void publish_to_corosync(struct stasis_message *message) +static void publish_event_to_corosync(struct ast_event *event) { cs_error_t cs_err; struct iovec iov; + + iov.iov_base = (void *)event; + iov.iov_len = ast_event_get_size(event); + + ast_debug(5, "Publishing event %s (%u) to corosync\n", + ast_event_get_type_name(event), ast_event_get_type(event)); + + /* The stasis subscription will only exist if we are configured to publish + * these events, so just send away. */ + if ((cs_err = cpg_mcast_joined(cpg_handle, CPG_TYPE_FIFO, &iov, 1)) != CS_OK) { + ast_log(LOG_WARNING, "CPG mcast failed (%u) for event %s (%u)\n", + cs_err, ast_event_get_type_name(event), ast_event_get_type(event)); + } +} + +static void publish_to_corosync(struct stasis_message *message) +{ struct ast_event *event; event = stasis_message_to_event(message); @@ -368,17 +559,7 @@ static void publish_to_corosync(struct stasis_message *message) ast_log(LOG_NOTICE, "Sending event PING from this server with EID: '%s'\n", buf); } - iov.iov_base = (void *)event; - iov.iov_len = ast_event_get_size(event); - - ast_debug(5, "Publishing event %s (%u) to corosync\n", - ast_event_get_type_name(event), ast_event_get_type(event)); - - /* The stasis subscription will only exist if we are configured to publish - * these events, so just send away. */ - if ((cs_err = cpg_mcast_joined(cpg_handle, CPG_TYPE_FIFO, &iov, 1)) != CS_OK) { - ast_log(LOG_WARNING, "CPG mcast failed (%u)\n", cs_err); - } + publish_event_to_corosync(event); } static void stasis_message_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) @@ -410,9 +591,22 @@ static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_nam { unsigned int i; + + for (i = 0; i < left_list_entries; i++) { + const struct cpg_address *cpg_node = &left_list[i]; + struct corosync_node* node; + + node = ao2_find(nodes, &cpg_node->nodeid, OBJ_UNLINK | OBJ_SEARCH_KEY); + if (!node) { + continue; + } + + publish_cluster_discovery_to_stasis_full(node, 0); + ao2_ref(node, -1); + } + /* If any new nodes have joined, dump our cache of events we are publishing * that originated from this server. */ - if (!joined_list_entries) { return; } @@ -442,6 +636,45 @@ static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_nam } } +/*! \brief Informs the cluster of our EID and our IP addresses */ +static void send_cluster_notify(void) +{ + struct ast_event *event; + unsigned int node_id; + cs_error_t cs_err; + corosync_cfg_node_address_t corosync_addr; + int num_addrs = 0; + struct sockaddr *sa; + size_t sa_len; + char buf[128]; + int res; + + if ((cs_err = corosync_cfg_local_get(cfg_handle, &node_id)) != CS_OK) { + ast_log(LOG_WARNING, "Failed to extract Corosync node ID for this node. Not informing cluster of existance.\n"); + return; + } + + if (((cs_err = corosync_cfg_get_node_addrs(cfg_handle, node_id, 1, &num_addrs, &corosync_addr)) != CS_OK) || (num_addrs < 1)) { + ast_log(LOG_WARNING, "Failed to get local Corosync address. Not informing cluster of existance.\n"); + return; + } + + sa = (struct sockaddr *)corosync_addr.address; + sa_len = (size_t)corosync_addr.address_length; + if ((res = getnameinfo(sa, sa_len, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST))) { + ast_log(LOG_WARNING, "Failed to determine name of local Corosync address: %s (%d). Not informing cluster of existance.\n", + gai_strerror(res), res); + return; + } + + event = ast_event_new(AST_EVENT_CLUSTER_DISCOVERY, + AST_EVENT_IE_NODE_ID, AST_EVENT_IE_PLTYPE_UINT, node_id, + AST_EVENT_IE_LOCAL_ADDR, AST_EVENT_IE_PLTYPE_STR, buf, + AST_EVENT_IE_END); + publish_event_to_corosync(event); + ast_free(event); +} + static void *dispatch_thread_handler(void *data) { cs_error_t cs_err; @@ -463,6 +696,7 @@ static void *dispatch_thread_handler(void *data) pfd[2].fd = dispatch_thread.alert_pipe[0]; + send_cluster_notify(); while (!dispatch_thread.stop) { int res; @@ -530,6 +764,7 @@ static void *dispatch_thread_handler(void *data) } ast_log(LOG_NOTICE, "Corosync recovery complete.\n"); + send_cluster_notify(); } } @@ -858,6 +1093,9 @@ static void cleanup_module(void) ast_log(LOG_ERROR, "Failed to finalize cfg (%d)\n", (int) cs_err); } cfg_handle = 0; + + ao2_cleanup(nodes); + nodes = NULL; } static int load_module(void) @@ -865,6 +1103,11 @@ static int load_module(void) cs_error_t cs_err; struct cpg_name name; + nodes = ao2_container_alloc(23, corosync_node_hash_fn, corosync_node_cmp_fn); + if (!nodes) { + goto failed; + } + corosync_aggregate_topic = stasis_topic_create("corosync_aggregate_topic"); if (!corosync_aggregate_topic) { ast_log(AST_LOG_ERROR, "Failed to create stasis topic for corosync\n"); From c49833653bdbb10dc82ef32ae8503cd26ae3135c Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 19 Oct 2015 18:55:58 -0500 Subject: [PATCH 0559/1578] res/res_pjsip_pubsub: Add additional debug statements When something very sad and wrong occurs, it's challenging sometimes to figure out why. This patch adds some additional debug statements on off-nominal paths to try and make debugging easier. Change-Id: I7bffb73cc733b6f80193a23340881db4a102b640 --- res/res_pjsip_pubsub.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 4e4180957ea..207fae04c10 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -2965,11 +2965,14 @@ static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoi resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name); if (!resource) { + ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); return NULL; } if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) { + ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n", + resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint)); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); return NULL; } @@ -2981,6 +2984,7 @@ static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoi } if (!event_configuration_name) { + ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); return NULL; } From 0d487b53b13e9debb51ad8fe84b3767de5d25d75 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 24 Jun 2016 19:55:09 -0500 Subject: [PATCH 0560/1578] res/res_pjsip_session: Check for presence of an active negotiator It is possible in a hypothetical situation for a session refresh to be invoked on a PJSIP when the negotiatior on the INVITE session has not yet been established. While this shouldn't occur with existing uses of ast_sip_session_refresh, the crashes that occur due to improperly calling PJSIP functions that expect a non-NULL negotiatior are avoidable. PJSIP will create the negotiator in pjsip_inv_reinvite; this means that simply checking for the presence of the negotiator before passing it to other PJSIP functions that use it is allowable. As such, this patch adds checks for the presence of the negotiator before calling PJSIP functions that assume it is non-NULL. Change-Id: I1028323e7e01b0a531865e5412a71b6f6ec4276d --- res/res_pjsip_session.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 9f98e34b832..a773c16fc04 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -792,12 +792,14 @@ static int delay_request(struct ast_sip_session *session, static pjmedia_sdp_session *generate_session_refresh_sdp(struct ast_sip_session *session) { pjsip_inv_session *inv_session = session->inv_session; - const pjmedia_sdp_session *previous_sdp; + const pjmedia_sdp_session *previous_sdp = NULL; - if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) { - pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp); - } else { - pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp); + if (inv_session->neg) { + if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) { + pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp); + } else { + pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp); + } } return create_local_sdp(inv_session, session, previous_sdp); } @@ -917,7 +919,9 @@ int ast_sip_session_refresh(struct ast_sip_session *session, if (generate_new_sdp) { /* SDP can only be generated if current negotiation has already completed */ - if (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { + if (inv_session->neg + && pjmedia_sdp_neg_get_state(inv_session->neg) + != PJMEDIA_SDP_NEG_STATE_DONE) { ast_debug(3, "Delay session refresh with new SDP to %s because SDP negotiation is not yet done...\n", ast_sorcery_object_get_id(session->endpoint)); return delay_request(session, on_request_creation, on_sdp_creation, From 85212f2799bfda8b40f9261de6a874e0f7c77428 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 22 Jun 2016 14:13:39 +0200 Subject: [PATCH 0561/1578] res_rtp_asterisk: Enable Forward Secrecy (PFS) for DTLS. Since July 2014, TLS based protocols (SIP over TLS, Secure WebSockets, HTTPS) support PFS thanks to ASTERISK-23905. In July 2015, the same feature was added for DTLS. The source code from main/tcptls.c should have been re-used to ease security audits. Therefore, this change rolls back the change from July 2015 and re-uses the code from July 2014. This has the additional benefits to work under CentOS 7 and enabling not just ECDHE but DHE based cipher suites as well. ASTERISK-25659 #close Reported by: StefanEng86, urbaniak, pay123 Tested by: sarumjanuch, traud patches: res_rtp_asterisk.patch submitted by sarumjanuch dtls_centos_step_1.patch submitted by traud dtls_centos_step_2.patch submitted by traud Change-Id: I537cadf4421f092a613146b230f2c0ee1be28d5c --- CHANGES | 18 ++++++++ configure | 73 +++----------------------------- configure.ac | 6 --- include/asterisk/autoconfig.h.in | 3 -- res/res_rtp_asterisk.c | 41 +++++++++++++++--- 5 files changed, 57 insertions(+), 84 deletions(-) diff --git a/CHANGES b/CHANGES index 6a6cb6337f6..9caa524226a 100644 --- a/CHANGES +++ b/CHANGES @@ -371,6 +371,24 @@ res_pjsip extension in the indicated context. If no "subscribe_context" is specified, then the "context" setting is used. +res_rtp_asterisk +------------------ + * The DTLS part in Asterisk now supports Perfect Forward Secrecy (PFS). + Enabling PFS is attempted by default, and is dependent on the configuration + of the module using TLS. + - Ephemeral ECDH (ECDHE) is enabled by default. To disable it, do not + specify a ECDHE cipher suite in sip.conf, for example: + dtlscipher=AES128-SHA + - Ephemeral DH (DHE) is disabled by default. To enable it, add DH parameters + into the private key file, e.g., sip.conf dtlsprivatekey. For example: + openssl dhparam -out ./dh.pem 2048 + - Because clients expect the server to prefer PFS, and because OpenSSL sorts + its cipher suites by bit strength, see "openssl ciphers -v DEFAULT". + Consider re-ordering your cipher suites in the respective configuration + file. For example: + dtlscipher=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 + which forces PFS and requires at least DTLS 1.2. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- ------------------------------------------------------------------------------ diff --git a/configure b/configure index 2834ada5861..2c2e95dd9ba 100755 --- a/configure +++ b/configure @@ -1124,10 +1124,6 @@ PBX_DAHDI DAHDI_DIR DAHDI_INCLUDE DAHDI_LIB -PBX_OPENSSL_ECDH_AUTO -OPENSSL_ECDH_AUTO_DIR -OPENSSL_ECDH_AUTO_INCLUDE -OPENSSL_ECDH_AUTO_LIB PBX_OPENSSL_EC OPENSSL_EC_DIR OPENSSL_EC_INCLUDE @@ -8792,18 +8788,6 @@ PBX_OPENSSL_EC=0 -OPENSSL_ECDH_AUTO_DESCRIP="OpenSSL Auto ECDH Support" -OPENSSL_ECDH_AUTO_OPTION=crypto -OPENSSL_ECDH_AUTO_DIR=${CRYPTO_DIR} - -PBX_OPENSSL_ECDH_AUTO=0 - - - - - - - DAHDI_DESCRIP="DAHDI" DAHDI_OPTION="dahdi" PBX_DAHDI=0 @@ -13802,7 +13786,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13848,7 +13832,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13872,7 +13856,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13917,7 +13901,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13941,7 +13925,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -31502,53 +31486,6 @@ _ACEOF fi -fi - -if test "$PBX_OPENSSL" = "1"; -then - - if test "x${PBX_OPENSSL_ECDH_AUTO}" != "x1" -a "${USE_OPENSSL_ECDH_AUTO}" != "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_set_ecdh_auto declared in openssl/ssl.h" >&5 -$as_echo_n "checking for SSL_CTX_set_ecdh_auto declared in openssl/ssl.h... " >&6; } - saved_cppflags="${CPPFLAGS}" - if test "x${OPENSSL_ECDH_AUTO_DIR}" != "x"; then - OPENSSL_ECDH_AUTO_INCLUDE="-I${OPENSSL_ECDH_AUTO_DIR}/include" - fi - CPPFLAGS="${CPPFLAGS} ${OPENSSL_ECDH_AUTO_INCLUDE}" - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - #include -int -main () -{ -#if !defined(SSL_CTX_set_ecdh_auto) - (void) SSL_CTX_set_ecdh_auto; - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_OPENSSL_ECDH_AUTO=1 - -$as_echo "#define HAVE_OPENSSL_ECDH_AUTO 1" >>confdefs.h - - - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - CPPFLAGS="${saved_cppflags}" - fi - fi if test "$PBX_OPENSSL" = "1"; diff --git a/configure.ac b/configure.ac index 3cb0fed05f3..867ea9a49a2 100644 --- a/configure.ac +++ b/configure.ac @@ -414,7 +414,6 @@ AST_EXT_LIB_SETUP([CRYPT], [password and data encryption], [crypt]) AST_EXT_LIB_SETUP([CRYPTO], [OpenSSL Cryptography], [crypto]) AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_SRTP], [OpenSSL SRTP Extension Support], [CRYPTO], [crypto]) AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_EC], [OpenSSL Elliptic Curve Support], [CRYPTO], [crypto]) -AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_ECDH_AUTO], [OpenSSL Auto ECDH Support], [CRYPTO], [crypto]) AST_EXT_LIB_SETUP([DAHDI], [DAHDI], [dahdi]) AST_EXT_LIB_SETUP([FFMPEG], [Ffmpeg and avcodec], [avcodec]) AST_EXT_LIB_SETUP([GSM], [External GSM], [gsm], [, use 'internal' GSM otherwise]) @@ -2406,11 +2405,6 @@ then AST_EXT_LIB_CHECK([OPENSSL_EC], [ssl], [EC_KEY_new_by_curve_name], [openssl/ec.h], [-lcrypto]) fi -if test "$PBX_OPENSSL" = "1"; -then - AST_C_DECLARE_CHECK([OPENSSL_ECDH_AUTO], [SSL_CTX_set_ecdh_auto], [openssl/ssl.h]) -fi - if test "$PBX_OPENSSL" = "1"; then AST_C_DEFINE_CHECK([SSL_OP_NO_TLSV1_1], [SSL_OP_NO_TLSv1_1], [openssl/ssl.h]) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index cdcc4d0064c..5cd0acd6679 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -547,9 +547,6 @@ /* Define to 1 if CRYPTO has the OpenSSL Elliptic Curve Support feature. */ #undef HAVE_OPENSSL_EC -/* Define if your system has SSL_CTX_set_ecdh_auto declared. */ -#undef HAVE_OPENSSL_ECDH_AUTO - /* Define to 1 if CRYPTO has the OpenSSL SRTP Extension Support feature. */ #undef HAVE_OPENSSL_SRTP diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 79aab1697c8..c8d7f46304c 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1340,7 +1340,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); int res; -#ifndef HAVE_OPENSSL_ECDH_AUTO +#ifdef HAVE_OPENSSL_EC EC_KEY *ecdh; #endif @@ -1368,15 +1368,42 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1); -#ifdef HAVE_OPENSSL_ECDH_AUTO - SSL_CTX_set_ecdh_auto(rtp->ssl_ctx, 1); -#else +#ifdef HAVE_OPENSSL_EC + + if (!ast_strlen_zero(dtls_cfg->pvtfile)) { + BIO *bio = BIO_new_file(dtls_cfg->pvtfile, "r"); + if (bio != NULL) { + DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + if (dh != NULL) { + if (SSL_CTX_set_tmp_dh(rtp->ssl_ctx, dh)) { + long options = SSL_OP_CIPHER_SERVER_PREFERENCE | + SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE; + options = SSL_CTX_set_options(rtp->ssl_ctx, options); + ast_verb(2, "DTLS DH initialized, PFS enabled\n"); + } + DH_free(dh); + } + BIO_free(bio); + } + } + /* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */ ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - if (ecdh) { - SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh); + if (ecdh != NULL) { + if (SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh)) { + #ifndef SSL_CTRL_SET_ECDH_AUTO + #define SSL_CTRL_SET_ECDH_AUTO 94 + #endif + /* SSL_CTX_set_ecdh_auto(rtp->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */ + if (SSL_CTX_ctrl(rtp->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) { + ast_verb(2, "DTLS ECDH initialized (automatic), faster PFS enabled\n"); + } else { + ast_verb(2, "DTLS ECDH initialized (secp256r1), faster PFS enabled\n"); + } + } EC_KEY_free(ecdh); } -#endif + +#endif /* #ifdef HAVE_OPENSSL_EC */ rtp->dtls_verify = dtls_cfg->verify; From fd54d69feb806bc4052ca7270b4598a805d8975f Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 13 Jul 2016 12:30:58 -0400 Subject: [PATCH 0562/1578] threadpool: Fix leak in ast_threadpool_serializer_group error path. ast_threadpool_serializer_group leaks a reference to ser when listener is allocated but tps is not. Although listener takes the reference to ser cleanup functions are not run without tps. ASTERISK-26191 #close Change-Id: Ie3ccf69a3f1e676c2ef62a77067c0cb57dc9a585 --- main/threadpool.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main/threadpool.c b/main/threadpool.c index 9cd33ab1a4a..6240b7329a9 100644 --- a/main/threadpool.c +++ b/main/threadpool.c @@ -1384,10 +1384,12 @@ struct ast_taskprocessor *ast_threadpool_serializer_group(const char *name, ao2_ref(ser, -1); return NULL; } - /* ser ref transferred to listener */ tps = ast_taskprocessor_create_with_listener(name, listener); - if (tps && shutdown_group) { + if (!tps) { + /* ser ref transferred to listener but not cleaned without tps */ + ao2_ref(ser, -1); + } else if (shutdown_group) { serializer_shutdown_group_inc(shutdown_group); } From f73ddde7d4c5d4f7a675e13a4680d03426648bcd Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 13 Jul 2016 14:45:07 -0400 Subject: [PATCH 0563/1578] chan_sip: Fix reference leak in mwi_event_cb Cleanup the peer reference when stasis_subscription_final_message is true. Also free peer_name even if peer exists, after reload a new peer_name will be allocated. ASTERISK-26193 #close Change-Id: If7ecd52facdc5c227f701c760841e3f6ca53cc69 --- channels/chan_sip.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 599ecd639e2..b2522b6db79 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -17229,10 +17229,8 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct struct sip_peer *peer = sip_find_peer(peer_name, NULL, TRUE, FINDALLDEVICES, FALSE, 0); if (stasis_subscription_final_message(sub, msg)) { - if (peer) { - /* configuration reloaded */ - return; - } + /* peer can be non-NULL during reload. */ + ao2_cleanup(peer); ast_free(peer_name); return; } From eabcfeeaa3136b616f262f62a210af2cdab2b52e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 11 Jul 2016 10:21:35 -0500 Subject: [PATCH 0564/1578] pjsip_configuration.c: Misc cleanups. * Fix some whitespace in various routines. * Rename i to iter in persistent_endpoint_update_state(). * Fix off-nominal copy/paste message wording in persistent_endpoint_contact_deleted_observer() Change-Id: Id8e34f5d09e7eebac3af22501c44c1110a3e29d8 --- res/res_pjsip/pjsip_configuration.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 4d3fb658364..d399f0b47fe 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -146,7 +146,7 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) struct ast_endpoint *endpoint = persistent->endpoint; struct ast_sip_contact_status *status = arg; struct ao2_container *contacts; - struct ao2_iterator i; + struct ao2_iterator iter; struct ast_sip_contact *contact; enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; @@ -162,8 +162,8 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) */ contacts = ast_sip_location_retrieve_contacts_from_aor_list(persistent->aors); if (contacts) { - i = ao2_iterator_init(contacts, 0); - while (state == AST_ENDPOINT_OFFLINE && (contact = ao2_iterator_next(&i))) { + iter = ao2_iterator_init(contacts, 0); + while (state == AST_ENDPOINT_OFFLINE && (contact = ao2_iterator_next(&iter))) { struct ast_sip_contact_status *contact_status; const char *contact_id = ast_sorcery_object_get_id(contact); @@ -176,11 +176,11 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) ao2_cleanup(contact_status); ao2_ref(contact, -1); } - ao2_iterator_destroy(&i); + ao2_iterator_destroy(&iter); ao2_ref(contacts, -1); } - endpoint_update_state(endpoint,state); + endpoint_update_state(endpoint, state); return 0; } @@ -202,7 +202,7 @@ static void persistent_endpoint_contact_created_observer(const void *object) contact_status->status = CREATED; - ast_verb(2, "Contact %s/%s has been created\n",contact->aor, contact->uri); + ast_verb(2, "Contact %s/%s has been created\n", contact->aor, contact->uri); ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); ao2_cleanup(contact_status); @@ -216,7 +216,7 @@ static void persistent_endpoint_contact_deleted_observer(const void *object) contact_status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!contact_status) { - ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", + ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s/%s\n", contact->aor, contact->uri); return; } @@ -256,7 +256,8 @@ static void persistent_endpoint_contact_status_observer(const void *object) } if (contact_status->status != contact_status->last_status) { - ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n", contact_status->aor, contact_status->uri, + ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n", + contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); @@ -267,19 +268,23 @@ static void persistent_endpoint_contact_status_observer(const void *object) ast_test_suite_event_notify("AOR_CONTACT_UPDATE", "Contact: %s\r\n" - "Status: %s", + "Status: %s", ast_sorcery_object_get_id(contact_status), ast_sip_get_contact_status_label(contact_status->status)); - ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); + ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, + contact_status); } else { ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n", - contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), + contact_status->aor, contact_status->uri, + ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); } ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER, - contact_status->status != AVAILABLE ? -1 : contact_status->rtt / 1000, 1.0, ast_sorcery_object_get_id(contact_status)); + contact_status->status != AVAILABLE ? -1 : contact_status->rtt / 1000, + 1.0, + ast_sorcery_object_get_id(contact_status)); } /*! \brief Observer for contacts so state can be updated on respective endpoints */ From bc1ff41be747c69c83c2c66a04e8e440f1dc0be7 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 11 Jul 2016 10:22:35 -0500 Subject: [PATCH 0565/1578] pjsip_options.c: Fix container operation. aor_observer_deleted() needs to operate on all contacts found for the deleted AOR instead of only the first one found. This is really only a problem if there is more than one contact for the AOR. Change-Id: Id24ac0d5e8c931330231fb45dd2a331a84339dc1 --- res/res_pjsip/pjsip_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 808ee171a1c..5e0fc76cb57 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1264,7 +1264,7 @@ static void aor_observer_deleted(const void *obj) contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { - ao2_callback(contacts, OBJ_NODATA, unschedule_contact_cb, NULL); + ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, unschedule_contact_cb, NULL); ao2_ref(contacts, -1); } } From 2f26512fd804cdf1c788e3b9f7738f139186faf4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 8 Jul 2016 11:46:04 -0500 Subject: [PATCH 0566/1578] stasis_endpoint.c: Fix contactstatus_to_json(). The roundtrip_usec json member is optional. If it isn't present then don't put it into the converted json structure where ast_json_pack() will choke on it. Change-Id: I39bb2f86154ef54591270c58bfda8635070f9ea0 --- main/stasis_endpoints.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index 2d114210b75..c32dbb44f29 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -253,6 +253,7 @@ static struct ast_json *contactstatus_to_json(struct stasis_message *msg, const struct ast_endpoint_blob *obj = stasis_message_data(msg); struct ast_json *json_endpoint; struct ast_json *json_final; + const char *rtt; const struct timeval *tv = stasis_message_timestamp(msg); json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL); @@ -260,15 +261,30 @@ static struct ast_json *contactstatus_to_json(struct stasis_message *msg, const return NULL; } - json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s, s: s } } ", - "type", "ContactStatusChange", - "timestamp", ast_json_timeval(*tv, NULL), - "endpoint", json_endpoint, - "contact_info", - "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")), - "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, "contact_status")), - "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor")), - "roundtrip_usec", ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec"))); + /* The roundtrip time is optional. */ + rtt = ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec")); + if (!ast_strlen_zero(rtt)) { + json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s, s: s } } ", + "type", "ContactStatusChange", + "timestamp", ast_json_timeval(*tv, NULL), + "endpoint", json_endpoint, + "contact_info", + "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")), + "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, + "contact_status")), + "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor")), + "roundtrip_usec", rtt); + } else { + json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s } } ", + "type", "ContactStatusChange", + "timestamp", ast_json_timeval(*tv, NULL), + "endpoint", json_endpoint, + "contact_info", + "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")), + "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, + "contact_status")), + "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor"))); + } if (!json_final) { ast_json_unref(json_endpoint); } From 63ac4c9487ee085755c991813ec7e5994bf7ccc2 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Wed, 13 Jul 2016 17:45:27 -0500 Subject: [PATCH 0567/1578] translate: explicit format destination not properly set If the destination format's name differed from the codec name then the translator's explict_dst field would be improperly set. In some circumstances it would end up setting it to a newly created format that has the same name as the codec when it actually needed to be the given destination codec. This could cause the translation path to use the wrong format. For instance, if an endpoint had specified 'myulaw' as a format the translator could end up using a 'ulaw' format (with whatever/default settings) instead. If the format attribute settings differed between the two then there may unexpected results during processing. This patch removes the name check when building the translation path. This should make it always set the translator's explicit_dst to the given destination format as long as the sample rate and types match. Change-Id: Iaf8a03831d68e657d89569d54b505074efbefab5 --- main/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/translate.c b/main/translate.c index 8d37e372416..43e6e29bd5d 100644 --- a/main/translate.c +++ b/main/translate.c @@ -494,7 +494,7 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a AST_RWLIST_UNLOCK(&translators); return NULL; } - if ((t->dst_codec.sample_rate == ast_format_get_sample_rate(dst)) && (t->dst_codec.type == ast_format_get_type(dst)) && (!strcmp(t->dst_codec.name, ast_format_get_name(dst)))) { + if ((t->dst_codec.sample_rate == ast_format_get_sample_rate(dst)) && (t->dst_codec.type == ast_format_get_type(dst))) { explicit_dst = dst; } if (!(cur = newpvt(t, explicit_dst))) { From f3608b50d7c87c34b5a70d97ed4955b7039ce485 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 14 Jul 2016 03:40:26 -0400 Subject: [PATCH 0568/1578] pbx: Fix leak of timezone for time based includes. Create include_free to run ast_destroy_timing and ast_free, use that in all places that freed an ast_include structure. This fixes a couple of paths that previously did not run ast_destroy_timing. ASTERISK-26196 #close Change-Id: I1671bd111bef0dc113e8bf8f77f89fcfc395d838 --- main/pbx.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/main/pbx.c b/main/pbx.c index df9cad3266a..f065b1a2830 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -4755,6 +4755,13 @@ static struct ast_context *find_context_locked(const char *context) return c; } +/*! \brief Free an ast_include and associated data. */ +static void include_free(struct ast_include *include) +{ + ast_destroy_timing(&(include->timing)); + ast_free(include); +} + /*! * \brief Remove included contexts. * This function locks contexts list by &conlist, search for the right context @@ -4802,8 +4809,7 @@ int ast_context_remove_include2(struct ast_context *con, const char *include, co else con->includes = i->next; /* free include and return */ - ast_destroy_timing(&(i->timing)); - ast_free(i); + include_free(i); ret = 0; break; } @@ -6613,8 +6619,7 @@ int ast_context_add_include2(struct ast_context *con, const char *value, /* ... go to last include and check if context is already included too... */ for (i = con->includes; i; i = i->next) { if (!strcasecmp(i->name, new_include->name)) { - ast_destroy_timing(&(new_include->timing)); - ast_free(new_include); + include_free(new_include); ast_unlock_context(con); errno = EEXIST; return -1; @@ -7838,7 +7843,7 @@ static void __ast_internal_context_destroy( struct ast_context *con) for (tmpi = tmp->includes; tmpi; ) { /* Free includes */ struct ast_include *tmpil = tmpi; tmpi = tmpi->next; - ast_free(tmpil); + include_free(tmpil); } for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */ struct ast_ignorepat *ipl = ipi; @@ -7932,12 +7937,12 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context if (pi) { pi->next = i->next; /* free include */ - ast_free(i); + include_free(i); continue; /* don't change pi */ } else { tmp->includes = i->next; /* free include */ - ast_free(i); + include_free(i); continue; /* don't change pi */ } } From 31967dacdf53bbf52a53c59bdf69abbcf3652648 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 14 Jul 2016 09:45:10 -0300 Subject: [PATCH 0569/1578] app_queue: Only remove queue member from pending when state changes. It is possible for a not in use state change to occur multiple times causing a queue member to be removed from the pending call container prematurely. The first not in use state change will remove the queue member from the container. At this moment the member may be called and placed in the pending container. After this another not in use state change can be received which will remove it from the container. Despite being called at this point the code will incorrectly see that there are no pending calls to it. This change only removes it from the pending container if the state has actually changed. ASTERISK-26133 #close patches: app_queue.diff submitted by Richard Miller (license 5685) Change-Id: Ie5a7f17a44f98e9159e9b85009ce3f8393aa78c0 --- apps/app_queue.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 8f949635d61..39413f9a603 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2359,10 +2359,17 @@ static void pending_members_remove(struct member *mem) */ static void update_status(struct call_queue *q, struct member *m, const int status) { - m->status = status; - - /* Whatever the status is clear the member from the pending members pool */ - pending_members_remove(m); + if (m->status != status) { + m->status = status; + + /* Remove the member from the pending members pool only when the status changes. + * This is not done unconditionally because we can occasionally see multiple + * device state notifications of not in use after a previous call has ended, + * including after we have initiated a new call. This is more likely to + * happen when there is latency in the connection to the member. + */ + pending_members_remove(m); + } queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m)); } From 273052f40498378d3f2d3548347a243df68ee9a4 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 30 Jun 2016 15:58:53 -0500 Subject: [PATCH 0570/1578] Update support for SILK format. This commit adds scaffolding in order to support the SILK audio format on calls. Roughly, this is what is added: * Cached silk formats. One for each possible sample rate. * ast_codec structures for each possible sample rate. * RTP payload mappings for "SILK". In addition, this change overhauls the res_format_attr_silk file in the following ways: * The "samplerate" attribute is scrapped. That's native to the format. * There are far more checks to ensure that attributes have been allocated before attempting to reference them. * We do not SDP fmtp lines for attributes set to 0. These changes make way to be able to install a codec_silk module and have it actually work. It also should allow for passthrough silk calls in Asterisk. Change-Id: Ieeb39c95a9fecc9246bcfd3c45a6c9b51c59380e --- include/asterisk/format_cache.h | 8 +++++ main/codec_builtin.c | 63 ++++++++++++++++++++++++++++++++ main/format_cache.c | 20 +++++++++++ main/rtp_engine.c | 10 ++++++ res/res_format_attr_silk.c | 64 +++++++++++++++++---------------- 5 files changed, 134 insertions(+), 31 deletions(-) diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h index 64e53b9c5fe..3894ad21bcc 100644 --- a/include/asterisk/format_cache.h +++ b/include/asterisk/format_cache.h @@ -223,6 +223,14 @@ extern struct ast_format *ast_format_t140_red; */ extern struct ast_format *ast_format_none; +/*! + * \brief Built-in SILK format. + */ +extern struct ast_format *ast_format_silk8; +extern struct ast_format *ast_format_silk12; +extern struct ast_format *ast_format_silk16; +extern struct ast_format *ast_format_silk24; + /*! * \brief Initialize format cache support within the core. * diff --git a/main/codec_builtin.c b/main/codec_builtin.c index 9131643287d..50fbf555c03 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -772,6 +772,65 @@ static struct ast_codec t140 = { .type = AST_MEDIA_TYPE_TEXT, }; +static int silk_samples(struct ast_frame *frame) +{ + /* XXX This is likely not at all what's intended from this callback. However, + * since SILK is variable bit rate, I have no idea how to take a frame of data + * and determine the number of samples present. Instead, we base this on the + * sample rate of the codec and the expected number of samples to receive in 20ms. + * In testing, this has worked just fine. + */ + return ast_format_get_sample_rate(frame->subclass.format) / 50; +} + +static struct ast_codec silk8 = { + .name = "silk", + .description = "SILK Codec (8 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 160, + .samples_count = silk_samples +}; + +static struct ast_codec silk12 = { + .name = "silk", + .description = "SILK Codec (12 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 12000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 240, + .samples_count = silk_samples +}; + +static struct ast_codec silk16 = { + .name = "silk", + .description = "SILK Codec (16 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 320, + .samples_count = silk_samples +}; + +static struct ast_codec silk24 = { + .name = "silk", + .description = "SILK Codec (24 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 24000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 480, + .samples_count = silk_samples +}; + #define CODEC_REGISTER_AND_CACHE(codec) \ ({ \ int __res_ ## __LINE__ = 0; \ @@ -843,6 +902,10 @@ int ast_codec_builtin_init(void) res |= CODEC_REGISTER_AND_CACHE(t140red); res |= CODEC_REGISTER_AND_CACHE(t140); res |= CODEC_REGISTER_AND_CACHE(none); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk8", silk8); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk12", silk12); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk16", silk16); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk24", silk24); return res; } diff --git a/main/format_cache.c b/main/format_cache.c index def795c9d40..b4d42609251 100644 --- a/main/format_cache.c +++ b/main/format_cache.c @@ -232,6 +232,14 @@ struct ast_format *ast_format_t140_red; */ struct ast_format *ast_format_none; +/*! + * \brief Built-in "silk" format + */ +struct ast_format *ast_format_silk8; +struct ast_format *ast_format_silk12; +struct ast_format *ast_format_silk16; +struct ast_format *ast_format_silk24; + /*! \brief Number of buckets to use for the media format cache (should be prime for performance reasons) */ #define CACHE_BUCKETS 53 @@ -331,6 +339,10 @@ static void format_cache_shutdown(void) ao2_replace(ast_format_t140_red, NULL); ao2_replace(ast_format_t140, NULL); ao2_replace(ast_format_none, NULL); + ao2_replace(ast_format_silk8, NULL); + ao2_replace(ast_format_silk12, NULL); + ao2_replace(ast_format_silk16, NULL); + ao2_replace(ast_format_silk24, NULL); } int ast_format_cache_init(void) @@ -426,6 +438,14 @@ static void set_cached_format(const char *name, struct ast_format *format) ao2_replace(ast_format_t140, format); } else if (!strcmp(name, "none")) { ao2_replace(ast_format_none, format); + } else if (!strcmp(name, "silk8")) { + ao2_replace(ast_format_silk8, format); + } else if (!strcmp(name, "silk12")) { + ao2_replace(ast_format_silk12, format); + } else if (!strcmp(name, "silk16")) { + ao2_replace(ast_format_silk16, format); + } else if (!strcmp(name, "silk24")) { + ao2_replace(ast_format_silk24, format); } } diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 11e94c699a9..feadda3d379 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2690,6 +2690,11 @@ int ast_rtp_engine_init(void) /* Opus and VP8 */ set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000); set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000); + /* DA SILK */ + set_next_mime_type(ast_format_silk8, 0, "audio", "silk", 8000); + set_next_mime_type(ast_format_silk12, 0, "audio", "silk", 12000); + set_next_mime_type(ast_format_silk16, 0, "audio", "silk", 16000); + set_next_mime_type(ast_format_silk24, 0, "audio", "silk", 24000); /* Define the static rtp payload mappings */ add_static_payload(0, ast_format_ulaw, 0); @@ -2743,6 +2748,11 @@ int ast_rtp_engine_init(void) add_static_payload(100, ast_format_vp8, 0); add_static_payload(107, ast_format_opus, 0); + add_static_payload(108, ast_format_silk8, 0); + add_static_payload(109, ast_format_silk12, 0); + add_static_payload(113, ast_format_silk16, 0); + add_static_payload(114, ast_format_silk24, 0); + return 0; } diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c index f3f43821c8d..e69e3f43c1f 100644 --- a/res/res_format_attr_silk.c +++ b/res/res_format_attr_silk.c @@ -40,7 +40,6 @@ ASTERISK_REGISTER_FILE() * \note The only attribute that affects compatibility here is the sample rate. */ struct silk_attr { - unsigned int samplerate; unsigned int maxbitrate; unsigned int dtx; unsigned int fec; @@ -54,10 +53,15 @@ static void silk_destroy(struct ast_format *format) ast_free(attr); } +static void attr_init(struct silk_attr *attr) +{ + memset(attr, 0, sizeof(*attr)); +} + static int silk_clone(const struct ast_format *src, struct ast_format *dst) { struct silk_attr *original = ast_format_get_attribute_data(src); - struct silk_attr *attr = ast_calloc(1, sizeof(*attr)); + struct silk_attr *attr = ast_malloc(sizeof(*attr)); if (!attr) { return -1; @@ -65,6 +69,8 @@ static int silk_clone(const struct ast_format *src, struct ast_format *dst) if (original) { *attr = *original; + } else { + attr_init(attr); } ast_format_set_attribute_data(dst, attr); @@ -109,17 +115,17 @@ static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate); } - ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx); - ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec); + if (attr->dtx) { + ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx); + } + if (attr->fec) { + ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec); + } } static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2) { - struct silk_attr *attr1 = ast_format_get_attribute_data(format1); - struct silk_attr *attr2 = ast_format_get_attribute_data(format2); - - if (((!attr1 || !attr1->samplerate) && (!attr2 || !attr2->samplerate)) || - (attr1->samplerate == attr2->samplerate)) { + if (ast_format_get_sample_rate(format1) == ast_format_get_sample_rate(format2)) { return AST_FORMAT_CMP_EQUAL; } @@ -130,13 +136,10 @@ static struct ast_format *silk_getjoint(const struct ast_format *format1, const { struct silk_attr *attr1 = ast_format_get_attribute_data(format1); struct silk_attr *attr2 = ast_format_get_attribute_data(format2); - unsigned int samplerate; struct ast_format *jointformat; struct silk_attr *attr_res; - samplerate = attr1->samplerate & attr2->samplerate; - /* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */ - if (samplerate) { + if (ast_format_get_sample_rate(format1) != ast_format_get_sample_rate(format2)) { return NULL; } @@ -145,22 +148,25 @@ static struct ast_format *silk_getjoint(const struct ast_format *format1, const return NULL; } attr_res = ast_format_get_attribute_data(jointformat); - attr_res->samplerate = samplerate; - /* Take the lowest max bitrate */ - attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); + if (!attr1 || !attr2) { + attr_init(attr_res); + } else { + /* Take the lowest max bitrate */ + attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); - /* Only do dtx if both sides want it. DTX is a trade off between - * computational complexity and bandwidth. */ - attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0; + /* Only do dtx if both sides want it. DTX is a trade off between + * computational complexity and bandwidth. */ + attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0; - /* Only do FEC if both sides want it. If a peer specifically requests not - * to receive with FEC, it may be a waste of bandwidth. */ - attr_res->fec = attr1->fec && attr2->fec ? 1 : 0; + /* Only do FEC if both sides want it. If a peer specifically requests not + * to receive with FEC, it may be a waste of bandwidth. */ + attr_res->fec = attr1->fec && attr2->fec ? 1 : 0; - /* Use the maximum packetloss percentage between the two attributes. This affects how - * much redundancy is used in the FEC. */ - attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage); + /* Use the maximum packetloss percentage between the two attributes. This affects how + * much redundancy is used in the FEC. */ + attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage); + } return jointformat; } @@ -183,9 +189,7 @@ static struct ast_format *silk_set(const struct ast_format *format, const char * } attr = ast_format_get_attribute_data(cloned); - if (!strcasecmp(name, "sample_rate")) { - attr->samplerate = val; - } else if (!strcasecmp(name, "max_bitrate")) { + if (!strcasecmp(name, "max_bitrate")) { attr->maxbitrate = val; } else if (!strcasecmp(name, "dtx")) { attr->dtx = val; @@ -205,9 +209,7 @@ static const void *silk_get(const struct ast_format *format, const char *name) struct silk_attr *attr = ast_format_get_attribute_data(format); unsigned int *val; - if (!strcasecmp(name, "sample_rate")) { - val = &attr->samplerate; - } else if (!strcasecmp(name, "max_bitrate")) { + if (!strcasecmp(name, "max_bitrate")) { val = &attr->maxbitrate; } else if (!strcasecmp(name, "dtx")) { val = &attr->dtx; From d3348c51b54a3e201570fe60452ef7e7c754142e Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 14 Jul 2016 04:25:43 -0400 Subject: [PATCH 0571/1578] features.c: Remove unneeded adsi.h include. adsi.h is no longer used by features.c since parking was moved to a module. Change-Id: I2248b8a455225a17cb6ddaafd6c20c511a1eaf59 --- main/features.c | 1 - 1 file changed, 1 deletion(-) diff --git a/main/features.c b/main/features.c index b6e9630b52b..4062e96ce51 100644 --- a/main/features.c +++ b/main/features.c @@ -64,7 +64,6 @@ ASTERISK_REGISTER_FILE() #include "asterisk/cli.h" #include "asterisk/manager.h" #include "asterisk/utils.h" -#include "asterisk/adsi.h" #include "asterisk/devicestate.h" #include "asterisk/audiohook.h" #include "asterisk/global_datastores.h" From be36bd7ca565531c09ca444e59b6d057131a9ab0 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 14 Jul 2016 14:51:42 -0400 Subject: [PATCH 0572/1578] pbx: Create pbx_include.c for management of 'struct ast_include'. This changes context includes from a linked list to a vector, makes 'struct ast_include' opaque to pbx.c. Although ast_walk_context_includes is maintained the procedure is no longer efficient except for the first call (inc==NULL). This functionality is replaced by two new functions implemented by vector macros. * ast_context_includes_count (AST_VECTOR_SIZE) * ast_context_includes_get (AST_VECTOR_GET) As with ast_walk_context_includes callers of these functions are expected to have locked contexts. Only a few places in Asterisk walked the includes, they have been converted to use the new functions. const have been applied where possible to parameters for ast_include functions. Change-Id: Ib5c882e27cf96fb2aec67a39c18b4c71c9c83b60 --- apps/app_macro.c | 6 +- apps/app_while.c | 6 +- include/asterisk/pbx.h | 14 ++- main/pbx.c | 224 ++++++++++++++++++----------------------- main/pbx_include.c | 112 +++++++++++++++++++++ main/pbx_private.h | 11 ++ pbx/pbx_config.c | 34 +++++-- res/ael/pval.c | 2 +- utils/conf2ael.c | 4 +- utils/extconf.c | 13 +++ 10 files changed, 279 insertions(+), 147 deletions(-) create mode 100644 main/pbx_include.c diff --git a/apps/app_macro.c b/apps/app_macro.c index d2da1652371..26e4262b1b0 100644 --- a/apps/app_macro.c +++ b/apps/app_macro.c @@ -190,8 +190,8 @@ static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_cha static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid) { struct ast_exten *e; - struct ast_include *i; struct ast_context *c2; + int idx; for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) { if (ast_extension_match(ast_get_extension_name(e), exten)) { @@ -210,7 +210,9 @@ static struct ast_exten *find_matching_priority(struct ast_context *c, const cha } /* No match; run through includes */ - for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) { if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) { e = find_matching_priority(c2, exten, priority, callerid); diff --git a/apps/app_while.c b/apps/app_while.c index 273b466787e..cc048dfb3a1 100644 --- a/apps/app_while.c +++ b/apps/app_while.c @@ -117,8 +117,8 @@ static const char *get_index(struct ast_channel *chan, const char *prefix, int i static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid) { struct ast_exten *e; - struct ast_include *i; struct ast_context *c2; + int idx; for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) { if (ast_extension_match(ast_get_extension_name(e), exten)) { @@ -137,7 +137,9 @@ static struct ast_exten *find_matching_priority(struct ast_context *c, const cha } /* No match; run through includes */ - for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) { if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) { e = find_matching_priority(c2, exten, priority, callerid); diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index afdcc8da4f8..378bb556dc8 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1227,7 +1227,7 @@ int pbx_checkcondition(const char *condition); const char *ast_get_context_name(struct ast_context *con); const char *ast_get_extension_name(struct ast_exten *exten); struct ast_context *ast_get_extension_context(struct ast_exten *exten); -const char *ast_get_include_name(struct ast_include *include); +const char *ast_get_include_name(const struct ast_include *include); const char *ast_get_ignorepat_name(struct ast_ignorepat *ip); const char *ast_get_switch_name(struct ast_sw *sw); const char *ast_get_switch_data(struct ast_sw *sw); @@ -1249,7 +1249,7 @@ void *ast_get_extension_app_data(struct ast_exten *e); /*! @{ */ const char *ast_get_context_registrar(struct ast_context *c); const char *ast_get_extension_registrar(struct ast_exten *e); -const char *ast_get_include_registrar(struct ast_include *i); +const char *ast_get_include_registrar(const struct ast_include *i); const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip); const char *ast_get_switch_registrar(struct ast_sw *sw); /*! @} */ @@ -1261,13 +1261,19 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority); struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority); -struct ast_include *ast_walk_context_includes(struct ast_context *con, - struct ast_include *inc); +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, + const struct ast_include *inc); struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip); struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); /*! @} */ +/*! @name Iterator functions ... */ +/*! @{ */ +int ast_context_includes_count(const struct ast_context *con); +const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx); +/*! @} */ + /*! * \brief Create a human-readable string, specifying all variables and their corresponding values. * \param chan Channel from which to read variables diff --git a/main/pbx.c b/main/pbx.c index f065b1a2830..f6768bb5483 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -255,17 +255,6 @@ struct ast_exten { char stuff[0]; }; -/*! \brief ast_include: include= support in extensions.conf */ -struct ast_include { - const char *name; - const char *rname; /*!< Context to include */ - const char *registrar; /*!< Registrar */ - int hastime; /*!< If time construct exists */ - struct ast_timing timing; /*!< time construct */ - struct ast_include *next; /*!< Link them together */ - char stuff[0]; -}; - /*! \brief ast_sw: Switch statement in extensions.conf */ struct ast_sw { char *name; @@ -313,7 +302,7 @@ struct ast_context { struct ast_hashtab *root_table; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */ struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */ struct ast_context *next; /*!< Link them together */ - struct ast_include *includes; /*!< Include other contexts */ + struct ast_includes includes; /*!< Include other contexts */ struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */ char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */ int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */ @@ -1001,14 +990,6 @@ int check_contexts(char *file, int line ) } #endif -static inline int include_valid(struct ast_include *i) -{ - if (!i->hastime) - return 1; - - return ast_check_timing(&(i->timing)); -} - static void pbx_destroy(struct ast_pbx *p) { ast_free(p); @@ -2399,7 +2380,7 @@ struct fake_context /* this struct is purely for matching in the hashtab */ struct ast_hashtab *root_table; struct match_char *pattern_tree; struct ast_context *next; - struct ast_include *includes; + struct ast_includes includes; struct ast_ignorepat *ignorepats; const char *registrar; int refcount; @@ -2459,11 +2440,11 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, int x, res; struct ast_context *tmp = NULL; struct ast_exten *e = NULL, *eroot = NULL; - struct ast_include *i = NULL; struct ast_sw *sw = NULL; struct ast_exten pattern = {NULL, }; struct scoreboard score = {0, }; struct ast_str *tmpdata = NULL; + int idx; pattern.label = label; pattern.priority = priority; @@ -2729,9 +2710,11 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, } q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */ /* Now try any includes we have in this context */ - for (i = tmp->includes; i; i = i->next) { + for (idx = 0; idx < ast_context_includes_count(tmp); idx++) { + const struct ast_include *i = ast_context_includes_get(tmp, idx); + if (include_valid(i)) { - if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) { + if ((e = pbx_find_extension(chan, bypass, q, include_rname(i), exten, priority, label, callerid, action))) { #ifdef NEED_DEBUG_HERE ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten); #endif @@ -4755,13 +4738,6 @@ static struct ast_context *find_context_locked(const char *context) return c; } -/*! \brief Free an ast_include and associated data. */ -static void include_free(struct ast_include *include) -{ - ast_destroy_timing(&(include->timing)); - ast_free(include); -} - /*! * \brief Remove included contexts. * This function locks contexts list by &conlist, search for the right context @@ -4793,21 +4769,22 @@ int ast_context_remove_include(const char *context, const char *include, const c */ int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar) { - struct ast_include *i, *pi = NULL; int ret = -1; + int idx; ast_wrlock_context(con); /* find our include */ - for (i = con->includes; i; pi = i, i = i->next) { - if (!strcmp(i->name, include) && - (!registrar || !strcmp(i->registrar, registrar))) { + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + struct ast_include *i = AST_VECTOR_GET(&con->includes, idx); + + if (!strcmp(ast_get_include_name(i), include) && + (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) { + /* remove from list */ ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar); - if (pi) - pi->next = i->next; - else - con->includes = i->next; + AST_VECTOR_REMOVE_ORDERED(&con->includes, idx); + /* free include and return */ include_free(i); ret = 0; @@ -5406,7 +5383,7 @@ static void print_ext(struct ast_exten *e, char * buf, int buflen) } /* XXX not verified */ -static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[]) +static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, const struct ast_include *rinclude, int includecount, const char *includes[]) { struct ast_context *c = NULL; int res = 0, old_total_exten = dpc->total_exten; @@ -5415,8 +5392,8 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, /* walk all contexts ... */ while ( (c = ast_walk_contexts(c)) ) { + int idx; struct ast_exten *e; - struct ast_include *i; struct ast_ignorepat *ip; #ifndef LOW_MEMORY char buf[1024], buf2[1024]; @@ -5504,8 +5481,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } /* walk included and write info ... */ - i = NULL; - while ( (i = ast_walk_context_includes(c, i)) ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i)); if (exten) { /* Check all includes for the requested extension */ @@ -5757,7 +5735,7 @@ static void manager_dpsendack(struct mansession *s, const struct message *m) static int manager_show_dialplan_helper(struct mansession *s, const struct message *m, const char *actionidtext, const char *context, const char *exten, struct dialplan_counters *dpc, - struct ast_include *rinclude) + const struct ast_include *rinclude) { struct ast_context *c; int res = 0, old_total_exten = dpc->total_exten; @@ -5778,8 +5756,8 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa c = NULL; /* walk all contexts ... */ while ( (c = ast_walk_contexts(c)) ) { + int idx; struct ast_exten *e; - struct ast_include *i; struct ast_ignorepat *ip; if (context && strcmp(ast_get_context_name(c), context) != 0) @@ -5835,8 +5813,9 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } - i = NULL; /* walk included and write info ... */ - while ( (i = ast_walk_context_includes(c, i)) ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + if (exten) { /* Check all includes for the requested extension */ manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i); @@ -6114,7 +6093,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, tmp->root = NULL; tmp->root_table = NULL; tmp->registrar = ast_strdup(registrar); - tmp->includes = NULL; + AST_VECTOR_INIT(&tmp->includes, 0); tmp->ignorepats = NULL; tmp->refcount = 1; } else { @@ -6166,16 +6145,19 @@ AST_LIST_HEAD_NOLOCK(store_hints, store_hint); static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar) { - struct ast_include *i; + int idx; struct ast_ignorepat *ip; struct ast_sw *sw; ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar); /* copy in the includes, switches, and ignorepats */ /* walk through includes */ - for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) { - if (strcmp(ast_get_include_registrar(i), registrar) == 0) + for (idx = 0; idx < ast_context_includes_count(old); idx++) { + const struct ast_include *i = ast_context_includes_get(old, idx); + + if (!strcmp(ast_get_include_registrar(i), registrar)) { continue; /* not mine */ + } ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i)); } @@ -6586,53 +6568,32 @@ int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar) { struct ast_include *new_include; - char *c; - struct ast_include *i, *il = NULL; /* include, include_last */ - int length; - char *p; - - length = sizeof(struct ast_include); - length += 2 * (strlen(value) + 1); + int idx; /* allocate new include structure ... */ - if (!(new_include = ast_calloc(1, length))) + new_include = include_alloc(value, registrar); + if (!new_include) { return -1; - /* Fill in this structure. Use 'p' for assignments, as the fields - * in the structure are 'const char *' - */ - p = new_include->stuff; - new_include->name = p; - strcpy(p, value); - p += strlen(value) + 1; - new_include->rname = p; - strcpy(p, value); - /* Strip off timing info, and process if it is there */ - if ( (c = strchr(p, ',')) ) { - *c++ = '\0'; - new_include->hastime = ast_build_timing(&(new_include->timing), c); } - new_include->next = NULL; - new_include->registrar = registrar; ast_wrlock_context(con); /* ... go to last include and check if context is already included too... */ - for (i = con->includes; i; i = i->next) { - if (!strcasecmp(i->name, new_include->name)) { + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + const struct ast_include *i = ast_context_includes_get(con, idx); + + if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) { include_free(new_include); ast_unlock_context(con); errno = EEXIST; return -1; } - il = i; } /* ... include new context into context list, unlock, return */ - if (il) - il->next = new_include; - else - con->includes = new_include; - ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); + AST_VECTOR_APPEND(&con->includes, new_include); + ast_verb(3, "Including context '%s' in context '%s'\n", + ast_get_include_name(new_include), ast_get_context_name(con)); ast_unlock_context(con); @@ -7834,17 +7795,15 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha static void __ast_internal_context_destroy( struct ast_context *con) { - struct ast_include *tmpi; struct ast_sw *sw; struct ast_exten *e, *el, *en; struct ast_ignorepat *ipi; struct ast_context *tmp = con; - for (tmpi = tmp->includes; tmpi; ) { /* Free includes */ - struct ast_include *tmpil = tmpi; - tmpi = tmpi->next; - include_free(tmpil); - } + /* Free includes */ + AST_VECTOR_CALLBACK_VOID(&tmp->includes, include_free); + AST_VECTOR_FREE(&tmp->includes); + for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */ struct ast_ignorepat *ipl = ipi; ipi = ipi->next; @@ -7910,8 +7869,8 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context struct ast_hashtab_iter *exten_iter; struct ast_hashtab_iter *prio_iter; struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL; - struct ast_include *i, *pi = NULL, *ni = NULL; struct ast_sw *sw = NULL; + int idx; /* remove any ignorepats whose registrar matches */ for (ip = tmp->ignorepats; ip; ip = ipn) { @@ -7930,23 +7889,13 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context ipl = ip; } /* remove any includes whose registrar matches */ - for (i = tmp->includes; i; i = ni) { - ni = i->next; - if (strcmp(i->registrar, registrar) == 0) { - /* remove from list */ - if (pi) { - pi->next = i->next; - /* free include */ - include_free(i); - continue; /* don't change pi */ - } else { - tmp->includes = i->next; - /* free include */ - include_free(i); - continue; /* don't change pi */ - } + for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) { + struct ast_include *i = AST_VECTOR_GET(&tmp->includes, idx); + + if (!strcmp(ast_get_include_registrar(i), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->includes, idx); + include_free(i); } - pi = i; } /* remove any switches whose registrar matches */ AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) { @@ -8006,7 +7955,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* delete the context if it's registrar matches, is empty, has refcount of 1, */ /* it's not empty, if it has includes, ignorepats, or switches that are registered from another registrar. It's not empty if there are any extensions */ - if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) { + if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !ast_context_includes_count(tmp) && AST_LIST_EMPTY(&tmp->alts)) { ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar); ast_hashtab_remove_this_object(contexttab, tmp); @@ -8407,11 +8356,6 @@ const char *ast_get_extension_label(struct ast_exten *exten) return exten ? exten->label : NULL; } -const char *ast_get_include_name(struct ast_include *inc) -{ - return inc ? inc->name : NULL; -} - const char *ast_get_ignorepat_name(struct ast_ignorepat *ip) { return ip ? ip->pattern : NULL; @@ -8435,11 +8379,6 @@ const char *ast_get_extension_registrar(struct ast_exten *e) return e ? e->registrar : NULL; } -const char *ast_get_include_registrar(struct ast_include *i) -{ - return i ? i->registrar : NULL; -} - const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip) { return ip ? ip->registrar : NULL; @@ -8517,13 +8456,43 @@ struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, return priority ? priority->peer : exten; } -struct ast_include *ast_walk_context_includes(struct ast_context *con, - struct ast_include *inc) +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, + const struct ast_include *inc) { - if (!inc) - return con ? con->includes : NULL; - else - return inc->next; + if (inc) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + const struct ast_include *include = AST_VECTOR_GET(&con->includes, idx); + + if (next) { + return include; + } + + if (inc == include) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_includes_count(con)) { + return NULL; + } + + return ast_context_includes_get(con, 0); +} + +int ast_context_includes_count(const struct ast_context *con) +{ + return AST_VECTOR_SIZE(&con->includes); +} + +const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->includes, idx); } struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, @@ -8537,16 +8506,19 @@ struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, int ast_context_verify_includes(struct ast_context *con) { - struct ast_include *inc = NULL; + int idx; int res = 0; - while ( (inc = ast_walk_context_includes(con, inc)) ) { - if (ast_context_find(inc->rname)) + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + const struct ast_include *inc = ast_context_includes_get(con, idx); + + if (ast_context_find(include_rname(inc))) { continue; + } res = -1; ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n", - ast_get_context_name(con), inc->rname); + ast_get_context_name(con), include_rname(inc)); break; } diff --git a/main/pbx_include.c b/main/pbx_include.c new file mode 100644 index 00000000000..46a41fb20f8 --- /dev/null +++ b/main/pbx_include.c @@ -0,0 +1,112 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan context include routines. + * + * \author Corey Farrell + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! ast_include: include= support in extensions.conf */ +struct ast_include { + const char *name; + /*! Context to include */ + const char *rname; + /*! Registrar */ + const char *registrar; + /*! If time construct exists */ + int hastime; + /*! time construct */ + struct ast_timing timing; + char stuff[0]; +}; + +const char *ast_get_include_name(const struct ast_include *inc) +{ + return inc ? inc->name : NULL; +} + +const char *include_rname(const struct ast_include *inc) +{ + return inc ? inc->rname : NULL; +} + +const char *ast_get_include_registrar(const struct ast_include *inc) +{ + return inc ? inc->registrar : NULL; +} + +int include_valid(const struct ast_include *inc) +{ + if (!inc->hastime) { + return 1; + } + + return ast_check_timing(&(inc->timing)); +} + +struct ast_include *include_alloc(const char *value, const char *registrar) +{ + struct ast_include *new_include; + char *c; + int valuebufsz = strlen(value) + 1; + char *p; + + /* allocate new include structure ... */ + new_include = ast_calloc(1, sizeof(*new_include) + (valuebufsz * 2)); + if (!new_include) { + return NULL; + } + + /* Fill in this structure. Use 'p' for assignments, as the fields + * in the structure are 'const char *' + */ + p = new_include->stuff; + new_include->name = p; + strcpy(p, value); + p += valuebufsz; + new_include->rname = p; + strcpy(p, value); + /* Strip off timing info, and process if it is there */ + if ((c = strchr(p, ',')) ) { + *c++ = '\0'; + new_include->hastime = ast_build_timing(&(new_include->timing), c); + } + new_include->registrar = registrar; + + return new_include; +} + +void include_free(struct ast_include *inc) +{ + ast_destroy_timing(&(inc->timing)); + ast_free(inc); +} diff --git a/main/pbx_private.h b/main/pbx_private.h index e0919418874..22d454ad02e 100644 --- a/main/pbx_private.h +++ b/main/pbx_private.h @@ -31,6 +31,17 @@ void set_ext_pri(struct ast_channel *c, const char *exten, int pri); /*! pbx.c function needed by pbx_app.c */ void unreference_cached_app(struct ast_app *app); +/*! pbx_includes.c */ +struct ast_include; +AST_VECTOR(ast_includes, struct ast_include *); + +/*! Allocate and initialize an ast_include. */ +struct ast_include *include_alloc(const char *value, const char *registrar); +/*! Free an ast_include and associated data. */ +void include_free(struct ast_include *inc); +int include_valid(const struct ast_include *inc); +const char *include_rname(const struct ast_include *inc); + /*! pbx_builtins.c functions needed by pbx.c */ int indicate_congestion(struct ast_channel *, const char *); int indicate_busy(struct ast_channel *, const char *); diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index eb2a64f70ef..478c0a3211e 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -189,15 +189,25 @@ static char *handle_cli_dialplan_remove_include(struct ast_cli_entry *e, int cmd /*! \brief return true if 'name' is included by context c */ static int lookup_ci(struct ast_context *c, const char *name) { - struct ast_include *i = NULL; + int idx; + int ret = 0; - if (ast_rdlock_context(c)) /* error, skip */ + if (ast_rdlock_context(c)) { + /* error, skip */ return 0; - while ( (i = ast_walk_context_includes(c, i)) ) - if (!strcmp(name, ast_get_include_name(i))) + } + + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + + if (!strcmp(name, ast_get_include_name(i))) { + ret = -1; break; + } + } ast_unlock_context(c); - return i ? -1 /* success */ : 0; + + return ret; } /*! \brief return true if 'name' is in the ignorepats for context c */ @@ -282,12 +292,13 @@ static char *complete_dialplan_remove_include(struct ast_cli_args *a) } /* walk contexts and their includes, return the n-th match */ while (!res && (c = ast_walk_contexts(c))) { - struct ast_include *i = NULL; + int idx; if (ast_rdlock_context(c)) /* error ? skip this one */ continue; - while ( !res && (i = ast_walk_context_includes(c, i)) ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); const char *i_name = ast_get_include_name(i); struct ast_context *nc = NULL; int already_served = 0; @@ -906,7 +917,7 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a for (c = NULL; (c = ast_walk_contexts(c)); ) { int context_header_written = 0; struct ast_exten *ext, *last_written_e = NULL; - struct ast_include *i; + int idx; struct ast_ignorepat *ip; struct ast_sw *sw; @@ -983,14 +994,17 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a fprintf(output, "\n"); /* walk through includes */ - for (i = NULL; (i = ast_walk_context_includes(c, i)) ; ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + if (strcmp(ast_get_include_registrar(i), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; fprintf(output, "include => %s\n", ast_get_include_name(i)); } - if (ast_walk_context_includes(c, NULL)) + if (ast_context_includes_count(c)) { fprintf(output, "\n"); + } /* walk through switches */ for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) { diff --git a/res/ael/pval.c b/res/ael/pval.c index ce9458c06dd..8b6760f9967 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -4410,7 +4410,7 @@ static int context_used(struct ael_extension *exten_list, struct ast_context *co { struct ael_extension *exten; /* Check the simple elements first */ - if (ast_walk_context_extensions(context, NULL) || ast_walk_context_includes(context, NULL) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) { + if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) { return 1; } for (exten = exten_list; exten; exten = exten->next_exten) { diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 76a3ad3f2d9..8b2043082a1 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -664,8 +664,8 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct as return NULL; } -struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc); -struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc) +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc); +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc) { return NULL; } diff --git a/utils/extconf.c b/utils/extconf.c index 48053aed662..3a0b2e97c9f 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -4381,6 +4381,19 @@ static struct ast_include *ast_walk_context_includes(struct ast_context *con, return inc->next; } +int ast_context_includes_count(struct ast_context *con); +int ast_context_includes_count(struct ast_context *con) +{ + int c = 0; + struct ast_include *inc = NULL; + + while ((inc = ast_walk_context_includes(con, inc))) { + c++; + } + + return c; +} + struct ast_include *localized_walk_context_includes(struct ast_context *con, struct ast_include *inc); struct ast_include *localized_walk_context_includes(struct ast_context *con, From d56fc3b36b7bb59b5506129b9895b6c3341350c9 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Sun, 17 Jul 2016 14:43:37 +0200 Subject: [PATCH 0573/1578] translate: Enables native Packet-Loss Concealment (PLC) for supporting codecs. ASTERISK-25629 #close Change-Id: I66c0086e6c17764b8141ec60a3e2aaefe088eb78 --- main/translate.c | 180 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 153 insertions(+), 27 deletions(-) diff --git a/main/translate.c b/main/translate.c index 43e6e29bd5d..45113aa484c 100644 --- a/main/translate.c +++ b/main/translate.c @@ -31,20 +31,25 @@ ASTERISK_REGISTER_FILE() -#include -#include -#include - -#include "asterisk/lock.h" -#include "asterisk/channel.h" -#include "asterisk/translate.h" -#include "asterisk/module.h" -#include "asterisk/frame.h" -#include "asterisk/sched.h" -#include "asterisk/cli.h" -#include "asterisk/term.h" -#include "asterisk/format.h" -#include "asterisk/linkedlists.h" +#include /* for rusage, getrusage, etc */ +#include /* for timeval */ + +#include "asterisk/astobj2.h" /* for ao2_ref, ao2_cleanup, etc */ +#include "asterisk/cli.h" /* for ast_cli_args, ast_cli, etc */ +#include "asterisk/codec.h" /* for ast_codec, etc */ +#include "asterisk/format.h" /* for ast_format_get_name, etc */ +#include "asterisk/format_cache.h" /* for ast_format_cache_get, etc */ +#include "asterisk/format_cap.h" /* for ast_format_cap_count, etc */ +#include "asterisk/frame.h" /* for ast_frame, etc */ +#include "asterisk/linkedlists.h" /* for AST_RWLIST_UNLOCK, etc */ +#include "asterisk/lock.h" /* for ast_rwlock_unlock, etc */ +#include "asterisk/logger.h" /* for ast_log, LOG_WARNING, etc */ +#include "asterisk/module.h" /* for ast_module_unref, etc */ +#include "asterisk/strings.h" /* for ast_str_append, etc */ +#include "asterisk/term.h" /* for term_color, COLOR_BLACK, etc */ +#include "asterisk/time.h" /* for ast_tvzero, ast_tv, etc */ +#include "asterisk/translate.h" /* for ast_translator, etc */ +#include "asterisk/utils.h" /* for ast_free, RAII_VAR, etc */ /*! \todo * TODO: sample frames for each supported input format. @@ -358,6 +363,7 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format pvt->f.offset = AST_FRIENDLY_OFFSET; pvt->f.src = pvt->t->name; pvt->f.data.ptr = pvt->outbuf.c; + pvt->f.seqno = 0x10000; /* * If the translator has not provided a format @@ -524,13 +530,58 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a /*! \brief do the actual translation */ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume) { - struct ast_trans_pvt *p = path; - struct ast_frame *out; + const unsigned int rtp_seqno_max_value = 0xffff; + struct ast_frame *out_last, *out = NULL; + struct ast_trans_pvt *step; struct timeval delivery; int has_timing_info; long ts; long len; - int seqno; + int seqno, frames_missing; + + /* Determine the amount of lost packets for PLC */ + /* But not when Signed Linear is involved = frame created internally */ + /* But not at start with first frame = path->f.seqno is still 0x10000 */ + /* But not when there is no sequence number = frame created internally */ + if (!ast_format_cache_is_slinear(f->subclass.format) && + path->f.seqno <= rtp_seqno_max_value && + path->f.seqno != f->seqno) { + if (f->seqno < path->f.seqno) { /* seqno overrun situation */ + frames_missing = rtp_seqno_max_value + f->seqno - path->f.seqno - 1; + } else { + frames_missing = f->seqno - path->f.seqno - 1; + } + /* Out-of-order packet - more precise: late packet */ + if ((rtp_seqno_max_value + 1) / 2 < frames_missing) { + if (consume) { + ast_frfree(f); + } + /* + * Do not pass late packets to any transcoding module, because that + * confuses the state of any library (packets inter-depend). With + * the next packet, this one is going to be treated as lost packet. + */ + if (frames_missing > 96) { /* with 20 msec per frame, around 2 seconds late */ + struct ast_str *str = ast_str_alloca(256); + + /* Might indicate an error in the detection of Late Frames, report! */ + ast_log(LOG_NOTICE, "Late Frame; got Sequence Number %d expected %d %s\n", + f->seqno, rtp_seqno_max_value & (path->f.seqno + 1), + ast_translate_path_to_str(path, &str)); + } + return NULL; + } + + if (frames_missing > 96) { + struct ast_str *str = ast_str_alloca(256); + + /* not DEBUG but NOTICE because of WARNING in main/cannel.c:__ast_queue_frame */ + ast_log(LOG_NOTICE, "%d lost frame(s) %d/%d %s\n", frames_missing, + f->seqno, path->f.seqno, ast_translate_path_to_str(path, &str)); + } + } else { + frames_missing = 0; + } has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); ts = f->ts; @@ -560,18 +611,93 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, f->samples, ast_format_get_sample_rate(f->subclass.format))); } delivery = f->delivery; - for (out = f; out && p ; p = p->next) { - struct ast_frame *current = out; - - do { - framein(p, current); - current = AST_LIST_NEXT(current, frame_list); - } while (current); - if (out != f) { - ast_frfree(out); + + for (out_last = NULL; frames_missing + 1; frames_missing--) { + struct ast_frame *frame_to_translate, *inner_head; + struct ast_frame missed = { + .frametype = AST_FRAME_VOICE, + .subclass.format = f->subclass.format, + .datalen = 0, + /* In RTP, the amount of samples might change anytime */ + /* If that happened while frames got lost, what to do? */ + .samples = f->samples, /* FIXME */ + .src = __FUNCTION__, + .data.uint32 = 0, + .delivery.tv_sec = 0, + .delivery.tv_usec = 0, + .flags = 0, + /* RTP sequence number is between 0x0001 and 0xffff */ + .seqno = (rtp_seqno_max_value + 1 + f->seqno - frames_missing) & rtp_seqno_max_value, + }; + + if (frames_missing) { + frame_to_translate = &missed; + } else { + frame_to_translate = f; + } + + /* The translation path from one format to another might contain several steps */ + /* out* collects the result for missed frame(s) and input frame(s) */ + /* out is the result of the conversion of all frames, translated into the destination format */ + /* out_last is the last frame in that list, to add frames faster */ + for (step = path, inner_head = frame_to_translate; inner_head && step; step = step->next) { + struct ast_frame *current, *inner_last, *inner_prev = frame_to_translate; + + /* inner* collects the result of each conversion step, the input for the next step */ + /* inner_head is a list of frames created by each conversion step */ + /* inner_last is the last frame in that list, to add frames faster */ + for (inner_last = NULL, current = inner_head; current; current = AST_LIST_NEXT(current, frame_list)) { + struct ast_frame *tmp; + + framein(step, current); + tmp = step->t->frameout(step); + + if (!tmp) { + continue; + } else if (inner_last) { + struct ast_frame *t; + + /* Determine the last frame of the list before appending to it */ + while ((t = AST_LIST_NEXT(inner_last, frame_list))) { + inner_last = t; + } + AST_LIST_NEXT(inner_last, frame_list) = tmp; + } else { + inner_prev = inner_head; + inner_head = tmp; + inner_last = tmp; + } + } + + /* The current step did not create any frames = no frames for the next step */ + /* The steps are not lost because framein buffered those for the next input frame */ + if (!inner_last) { + inner_prev = inner_head; + inner_head = NULL; + } + if (inner_prev != frame_to_translate) { + ast_frfree(inner_prev); /* Frees just the intermediate lists */ + } + } + + /* This frame created no frames after translation = continue with next frame */ + /* The frame is not lost because framein buffered it to be combined with the next frame */ + if (!inner_head) { + continue; + } else if (out_last) { + struct ast_frame *t; + + /* Determine the last frame of the list before appending to it */ + while ((t = AST_LIST_NEXT(out_last, frame_list))) { + out_last = t; + } + AST_LIST_NEXT(out_last, frame_list) = inner_head; + } else { + out = inner_head; + out_last = inner_head; } - out = p->t->frameout(p); } + if (out) { /* we have a frame, play with times */ if (!ast_tvzero(delivery)) { From e2e8713b8405cee26ed40be092bf1320ed9b29db Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 15 Jul 2016 03:59:48 -0400 Subject: [PATCH 0574/1578] pbx: Create pbx_ignorepat.c for management of 'struct ast_ignorepat'. This changes context ignore patterns from a linked list to a vector, makes 'struct ast_ignorepat' opaque to pbx.c. Although ast_walk_context_ignorepats is maintained the procedure is no longer efficient except for the first call (inc==NULL). This functionality is replaced by two new functions implemented by vector macros. * ast_context_ignorepats_count (AST_VECTOR_SIZE) * ast_context_ignorepats_get (AST_VECTOR_GET) As with ast_walk_context_ignorepats callers of these functions are expected to have locked contexts. Only a few places in Asterisk walked the ignorepats, they have been converted to use the new functions. Change-Id: I78f2157d275ef1b7d624b4ff7d770d38e5d7f20a --- include/asterisk/pbx.h | 10 ++- main/pbx.c | 186 ++++++++++++++++++++--------------------- main/pbx_ignorepat.c | 82 ++++++++++++++++++ main/pbx_private.h | 7 ++ pbx/pbx_config.c | 32 ++++--- res/ael/pval.c | 2 +- utils/conf2ael.c | 6 -- utils/extconf.c | 25 ++++++ 8 files changed, 233 insertions(+), 117 deletions(-) create mode 100644 main/pbx_ignorepat.c diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 378bb556dc8..67cdccf900f 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1228,7 +1228,7 @@ const char *ast_get_context_name(struct ast_context *con); const char *ast_get_extension_name(struct ast_exten *exten); struct ast_context *ast_get_extension_context(struct ast_exten *exten); const char *ast_get_include_name(const struct ast_include *include); -const char *ast_get_ignorepat_name(struct ast_ignorepat *ip); +const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip); const char *ast_get_switch_name(struct ast_sw *sw); const char *ast_get_switch_data(struct ast_sw *sw); int ast_get_switch_eval(struct ast_sw *sw); @@ -1250,7 +1250,7 @@ void *ast_get_extension_app_data(struct ast_exten *e); const char *ast_get_context_registrar(struct ast_context *c); const char *ast_get_extension_registrar(struct ast_exten *e); const char *ast_get_include_registrar(const struct ast_include *i); -const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip); +const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip); const char *ast_get_switch_registrar(struct ast_sw *sw); /*! @} */ @@ -1263,8 +1263,8 @@ struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority); const struct ast_include *ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc); -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, - struct ast_ignorepat *ip); +const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con, + const struct ast_ignorepat *ip); struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); /*! @} */ @@ -1272,6 +1272,8 @@ struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw /*! @{ */ int ast_context_includes_count(const struct ast_context *con); const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx); +int ast_context_ignorepats_count(const struct ast_context *con); +const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx); /*! @} */ /*! diff --git a/main/pbx.c b/main/pbx.c index f6768bb5483..eb395eba447 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -265,13 +265,6 @@ struct ast_sw { char stuff[0]; }; -/*! \brief ast_ignorepat: Ignore patterns in dial plan */ -struct ast_ignorepat { - const char *registrar; - struct ast_ignorepat *next; - const char pattern[0]; -}; - /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */ struct match_char { @@ -303,7 +296,7 @@ struct ast_context { struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */ struct ast_context *next; /*!< Link them together */ struct ast_includes includes; /*!< Include other contexts */ - struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */ + struct ast_ignorepats ignorepats; /*!< Patterns for which to continue playing dialtone */ char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */ int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */ int autohints; /*!< Whether autohints support is enabled or not */ @@ -2381,7 +2374,7 @@ struct fake_context /* this struct is purely for matching in the hashtab */ struct match_char *pattern_tree; struct ast_context *next; struct ast_includes includes; - struct ast_ignorepat *ignorepats; + struct ast_ignorepats ignorepats; const char *registrar; int refcount; int autohints; @@ -5394,7 +5387,6 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, while ( (c = ast_walk_contexts(c)) ) { int idx; struct ast_exten *e; - struct ast_ignorepat *ip; #ifndef LOW_MEMORY char buf[1024], buf2[1024]; #else @@ -5512,10 +5504,11 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } /* walk ignore patterns and write info ... */ - ip = NULL; - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); const char *ipname = ast_get_ignorepat_name(ip); char ignorepat[AST_MAX_EXTENSION]; + snprintf(buf, sizeof(buf), "'%s'", ipname); snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname); if (!exten || ast_extension_match(ignorepat, exten)) { @@ -5758,7 +5751,6 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa while ( (c = ast_walk_contexts(c)) ) { int idx; struct ast_exten *e; - struct ast_ignorepat *ip; if (context && strcmp(ast_get_context_name(c), context) != 0) continue; /* not the name we want */ @@ -5829,8 +5821,8 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } - ip = NULL; /* walk ignore patterns and write info ... */ - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); const char *ipname = ast_get_ignorepat_name(ip); char ignorepat[AST_MAX_EXTENSION]; @@ -6094,7 +6086,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, tmp->root_table = NULL; tmp->registrar = ast_strdup(registrar); AST_VECTOR_INIT(&tmp->includes, 0); - tmp->ignorepats = NULL; + AST_VECTOR_INIT(&tmp->ignorepats, 0); tmp->refcount = 1; } else { ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name); @@ -6146,7 +6138,6 @@ AST_LIST_HEAD_NOLOCK(store_hints, store_hint); static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar) { int idx; - struct ast_ignorepat *ip; struct ast_sw *sw; ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar); @@ -6169,9 +6160,12 @@ static void context_merge_incls_swits_igps_other_registrars(struct ast_context * } /* walk thru ignorepats ... */ - for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) { - if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) + for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx); + + if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) { continue; /* not mine */ + } ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip)); } } @@ -6700,24 +6694,20 @@ int ast_context_remove_ignorepat(const char *context, const char *ignorepat, con int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar) { - struct ast_ignorepat *ip, *ipl = NULL; + int idx; ast_wrlock_context(con); - for (ip = con->ignorepats; ip; ip = ip->next) { - if (!strcmp(ip->pattern, ignorepat) && - (!registrar || (registrar == ip->registrar))) { - if (ipl) { - ipl->next = ip->next; - ast_free(ip); - } else { - con->ignorepats = ip->next; - ast_free(ip); - } + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + struct ast_ignorepat *ip = AST_VECTOR_GET(&con->ignorepats, idx); + + if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) && + (!registrar || (registrar == ast_get_ignorepat_registrar(ip)))) { + AST_VECTOR_REMOVE_ORDERED(&con->ignorepats, idx); + ignorepat_free(ip); ast_unlock_context(con); return 0; } - ipl = ip; } ast_unlock_context(con); @@ -6744,41 +6734,29 @@ int ast_context_add_ignorepat(const char *context, const char *value, const char int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar) { - struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL; - int length; - char *pattern; - length = sizeof(struct ast_ignorepat); - length += strlen(value) + 1; - if (!(ignorepat = ast_calloc(1, length))) + struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar); + int idx; + + if (!ignorepat) { return -1; - /* The cast to char * is because we need to write the initial value. - * The field is not supposed to be modified otherwise. Also, gcc 4.2 - * sees the cast as dereferencing a type-punned pointer and warns about - * it. This is the workaround (we're telling gcc, yes, that's really - * what we wanted to do). - */ - pattern = (char *) ignorepat->pattern; - strcpy(pattern, value); - ignorepat->next = NULL; - ignorepat->registrar = registrar; + } + ast_wrlock_context(con); - for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) { - ignorepatl = ignorepatc; - if (!strcasecmp(ignorepatc->pattern, value)) { + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx); + + if (!strcasecmp(ast_get_ignorepat_name(i), value)) { /* Already there */ ast_unlock_context(con); - ast_free(ignorepat); + ignorepat_free(ignorepat); errno = EEXIST; return -1; } } - if (ignorepatl) - ignorepatl->next = ignorepat; - else - con->ignorepats = ignorepat; + AST_VECTOR_APPEND(&con->ignorepats, ignorepat); ast_unlock_context(con); - return 0; + return 0; } int ast_ignore_pattern(const char *context, const char *pattern) @@ -6789,10 +6767,12 @@ int ast_ignore_pattern(const char *context, const char *pattern) ast_rdlock_contexts(); con = ast_context_find(context); if (con) { - struct ast_ignorepat *pat; + int idx; - for (pat = con->ignorepats; pat; pat = pat->next) { - if (ast_extension_match(pat->pattern, pattern)) { + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx); + + if (ast_extension_match(ast_get_ignorepat_name(pat), pattern)) { ret = 1; break; } @@ -7797,18 +7777,16 @@ static void __ast_internal_context_destroy( struct ast_context *con) { struct ast_sw *sw; struct ast_exten *e, *el, *en; - struct ast_ignorepat *ipi; struct ast_context *tmp = con; /* Free includes */ AST_VECTOR_CALLBACK_VOID(&tmp->includes, include_free); AST_VECTOR_FREE(&tmp->includes); - for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */ - struct ast_ignorepat *ipl = ipi; - ipi = ipi->next; - ast_free(ipl); - } + /* Free ignorepats */ + AST_VECTOR_CALLBACK_VOID(&tmp->ignorepats, ignorepat_free); + AST_VECTOR_FREE(&tmp->ignorepats); + if (tmp->registrar) ast_free(tmp->registrar); @@ -7868,25 +7846,17 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* then search thru and remove any extens that match registrar. */ struct ast_hashtab_iter *exten_iter; struct ast_hashtab_iter *prio_iter; - struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL; struct ast_sw *sw = NULL; int idx; /* remove any ignorepats whose registrar matches */ - for (ip = tmp->ignorepats; ip; ip = ipn) { - ipn = ip->next; - if (!strcmp(ip->registrar, registrar)) { - if (ipl) { - ipl->next = ip->next; - ast_free(ip); - continue; /* don't change ipl */ - } else { - tmp->ignorepats = ip->next; - ast_free(ip); - continue; /* don't change ipl */ - } + for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) { + struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx); + + if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->ignorepats, idx); + ignorepat_free(ip); } - ipl = ip; } /* remove any includes whose registrar matches */ for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) { @@ -7955,7 +7925,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* delete the context if it's registrar matches, is empty, has refcount of 1, */ /* it's not empty, if it has includes, ignorepats, or switches that are registered from another registrar. It's not empty if there are any extensions */ - if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !ast_context_includes_count(tmp) && AST_LIST_EMPTY(&tmp->alts)) { + if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && AST_LIST_EMPTY(&tmp->alts)) { ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar); ast_hashtab_remove_this_object(contexttab, tmp); @@ -8356,11 +8326,6 @@ const char *ast_get_extension_label(struct ast_exten *exten) return exten ? exten->label : NULL; } -const char *ast_get_ignorepat_name(struct ast_ignorepat *ip) -{ - return ip ? ip->pattern : NULL; -} - int ast_get_extension_priority(struct ast_exten *exten) { return exten ? exten->priority : -1; @@ -8379,11 +8344,6 @@ const char *ast_get_extension_registrar(struct ast_exten *e) return e ? e->registrar : NULL; } -const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip) -{ - return ip ? ip->registrar : NULL; -} - int ast_get_extension_matchcid(struct ast_exten *e) { return e ? e->matchcid : 0; @@ -8495,13 +8455,47 @@ const struct ast_include *ast_context_includes_get(const struct ast_context *con return AST_VECTOR_GET(&con->includes, idx); } -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, - struct ast_ignorepat *ip) +const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con, + const struct ast_ignorepat *ip) { - if (!ip) - return con ? con->ignorepats : NULL; - else - return ip->next; + if (!con) { + return NULL; + } + + if (ip) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx); + + if (next) { + return i; + } + + if (ip == i) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_ignorepats_count(con)) { + return NULL; + } + + return ast_context_ignorepats_get(con, 0); +} + +int ast_context_ignorepats_count(const struct ast_context *con) +{ + return AST_VECTOR_SIZE(&con->ignorepats); +} + +const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->ignorepats, idx); } int ast_context_verify_includes(struct ast_context *con) diff --git a/main/pbx_ignorepat.c b/main/pbx_ignorepat.c new file mode 100644 index 00000000000..1a2232c57ae --- /dev/null +++ b/main/pbx_ignorepat.c @@ -0,0 +1,82 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan context ignorepat routines. + * + * \author Corey Farrell + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! \brief ast_ignorepat: Ignore patterns in dial plan */ +struct ast_ignorepat { + const char *registrar; + const char pattern[0]; +}; + +const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip) +{ + return ip ? ip->pattern : NULL; +} + +const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip) +{ + return ip ? ip->registrar : NULL; +} + +struct ast_ignorepat *ignorepat_alloc(const char *value, const char *registrar) +{ + struct ast_ignorepat *ignorepat; + int length = strlen(value) + 1; + char *pattern; + + /* allocate new include structure ... */ + ignorepat = ast_calloc(1, sizeof(*ignorepat) + length); + if (!ignorepat) { + return NULL; + } + + /* The cast to char * is because we need to write the initial value. + * The field is not supposed to be modified otherwise. Also, gcc 4.2 + * sees the cast as dereferencing a type-punned pointer and warns about + * it. This is the workaround (we're telling gcc, yes, that's really + * what we wanted to do). + */ + pattern = (char *) ignorepat->pattern; + strcpy(pattern, value); + ignorepat->registrar = registrar; + + return ignorepat; +} + +void ignorepat_free(struct ast_ignorepat *ip) +{ + ast_free(ip); +} diff --git a/main/pbx_private.h b/main/pbx_private.h index 22d454ad02e..2b7d9828b63 100644 --- a/main/pbx_private.h +++ b/main/pbx_private.h @@ -31,6 +31,13 @@ void set_ext_pri(struct ast_channel *c, const char *exten, int pri); /*! pbx.c function needed by pbx_app.c */ void unreference_cached_app(struct ast_app *app); +/*! pbx_ignorepat.c */ +struct ast_ignorepat; +AST_VECTOR(ast_ignorepats, struct ast_ignorepat *); + +struct ast_ignorepat *ignorepat_alloc(const char *value, const char *registrar); +void ignorepat_free(struct ast_ignorepat *ip); + /*! pbx_includes.c */ struct ast_include; AST_VECTOR(ast_includes, struct ast_include *); diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 478c0a3211e..cb7e03a3e9c 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -213,15 +213,25 @@ static int lookup_ci(struct ast_context *c, const char *name) /*! \brief return true if 'name' is in the ignorepats for context c */ static int lookup_c_ip(struct ast_context *c, const char *name) { - struct ast_ignorepat *ip = NULL; + int idx; + int ret = 0; - if (ast_rdlock_context(c)) /* error, skip */ + if (ast_rdlock_context(c)) { + /* error, skip */ return 0; - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) - if (!strcmp(name, ast_get_ignorepat_name(ip))) + } + + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + + if (!strcmp(name, ast_get_ignorepat_name(ip))) { + ret = -1; break; + } + } ast_unlock_context(c); - return ip ? -1 /* success */ : 0; + + return ret; } /*! \brief moves to the n-th word in the string, or empty string if none */ @@ -918,7 +928,6 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a int context_header_written = 0; struct ast_exten *ext, *last_written_e = NULL; int idx; - struct ast_ignorepat *ip; struct ast_sw *sw; /* try to lock context and fireout all info */ @@ -1019,7 +1028,9 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a fprintf(output, "\n"); /* fireout ignorepats ... */ - for (ip = NULL; (ip = ast_walk_context_ignorepats(c, ip)); ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; @@ -1486,12 +1497,13 @@ static char *complete_dialplan_remove_ignorepat(struct ast_cli_args *a) } for (c = NULL; !ret && (c = ast_walk_contexts(c));) { - struct ast_ignorepat *ip; + int idx; if (ast_rdlock_context(c)) /* error, skip it */ continue; - - for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + if (partial_match(ast_get_ignorepat_name(ip), a->word, len) && ++which > a->n) { /* n-th match */ struct ast_context *cw = NULL; diff --git a/res/ael/pval.c b/res/ael/pval.c index 8b6760f9967..2941365c9f8 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -4410,7 +4410,7 @@ static int context_used(struct ael_extension *exten_list, struct ast_context *co { struct ael_extension *exten; /* Check the simple elements first */ - if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) { + if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_context_ignorepats_count(context) || ast_walk_context_switches(context, NULL)) { return 1; } for (exten = exten_list; exten; exten = exten->next_exten) { diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 8b2043082a1..f0cb83f303d 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -670,12 +670,6 @@ const struct ast_include *ast_walk_context_includes(const struct ast_context *co return NULL; } -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip); -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip) -{ - return NULL; -} - struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw) { diff --git a/utils/extconf.c b/utils/extconf.c index 3a0b2e97c9f..049882334fe 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -4402,6 +4402,31 @@ struct ast_include *localized_walk_context_includes(struct ast_context *con, return ast_walk_context_includes(con, inc); } +static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, + struct ast_ignorepat *ip); + +static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, + struct ast_ignorepat *ip) +{ + if (!ip) + return con ? con->ignorepats : NULL; + else + return ip->next; +} + +int ast_context_ignorepats_count(struct ast_context *con); +int ast_context_ignorepats_count(struct ast_context *con) +{ + int c = 0; + struct ast_ignorepat *ip = NULL; + + while ((ip = ast_walk_context_ignorepats(con, ip))) { + c++; + } + + return c; +} + static struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); From 6428580e7fd2b070e0d3e0b18ba884d4ab13195c Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 18 Jul 2016 11:14:59 +0200 Subject: [PATCH 0575/1578] Makefile: Suppress echoing of target 'config' again. ASTERISK-26038 #close Change-Id: I5746cf639f3fdc6332e8a97cf01f979e30bf403f --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b988c8ff625..37f70eb0e44 100644 --- a/Makefile +++ b/Makefile @@ -824,7 +824,7 @@ install-logrotate: rm -f contrib/scripts/asterisk.logrotate.tmp config: - if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ + @if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ ./build_tools/install_subst contrib/init.d/rc.redhat.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \ $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ From cb5e3445be6c55517c8d05aca601b648341f8ae9 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 18 Jul 2016 12:13:25 +0200 Subject: [PATCH 0576/1578] res_rtp_asterisk: Count a roll-over of the sequence number even on lost packets. With this change, the initial RTP sequence number is randomly chosen not between 0 and 65535 (0xffff) but 0 and 32767 (0x7fff). This assures, the roll-over counter (ROC) synchronization is not lost for sRTP, when the very first RTP packets get lost; see http://srtp.sourceforge.net/faq.html#Q6 ASTERISK-26207 #close Change-Id: I9a527e3aa3ce8f3becc5131d7ba32b57b5845464 --- res/res_rtp_asterisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index c8d7f46304c..6cf69ef0d7e 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2592,7 +2592,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, /* Set default parameters on the newly created RTP structure */ rtp->ssrc = ast_random(); - rtp->seqno = ast_random() & 0xffff; + rtp->seqno = ast_random() & 0x7fff; rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); if (strictrtp) { rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); From e9daa3426102f7964949a7abaa34171de8c95269 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 18 Jul 2016 10:22:57 -0400 Subject: [PATCH 0577/1578] res_pjsip_mwi: remove unneeded check on endpoint's contacts. The function create_mwi_subscriptions_for_endpoint checks if there is active contacts by retrieving aors and contacts. This function is used to create all unsolicited mwi subscriptions on startup and is used when contact added. In both cases it's not necessary to check if there are contacts. The contacts are needed when asterisk sends mwi. ASTERISK-26200 #close Change-Id: I98e43bdc97f3c0829951cd9bf5f3c6348c6ac1fa --- res/res_pjsip_mwi.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 9eba335b542..d86c96c7449 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -976,38 +976,12 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags { RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup); struct ast_sip_endpoint *endpoint = obj; - char *endpoint_aors, *aor_name, *mailboxes, *mailbox; - struct ao2_container *contacts = NULL; + char *mailboxes, *mailbox; if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { return 0; } - endpoint_aors = ast_strdupa(endpoint->aors); - - while ((aor_name = ast_strip(strsep(&endpoint_aors, ",")))) { - RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); - - if (!aor) { - continue; - } - - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (!contacts || (ao2_container_count(contacts) == 0)) { - ao2_cleanup(contacts); - contacts = NULL; - continue; - } - - break; - } - - if (!contacts) { - return 0; - } - - ao2_ref(contacts, -1); - if (endpoint->subscription.mwi.aggregate) { aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL); if (!aggregate_sub) { From cf1188a1be7c81892f480474eedf1a5639a1c1eb Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 18 Jul 2016 19:40:22 -0400 Subject: [PATCH 0578/1578] Unit tests: Use AST_TEST_DEFINE in conditional code only. If AST_TEST_DEFINE is not conditional to TEST_FRAMEWORK it produces dead code. This places all existing unit tests into a conditional block if they weren't already. ASTERISK-26211 #close Change-Id: I8ef83ee11cbc991b07b7a37ecb41433e8c734686 --- apps/app_voicemail.c | 2 ++ channels/sip/config_parser.c | 7 +++++++ channels/sip/reqresp_parser.c | 23 ++++++++++++++++++++--- funcs/func_curl.c | 2 ++ res/res_pjsip.c | 2 ++ 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 6607f529e8d..894038bdbc0 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -12307,6 +12307,7 @@ static int append_mailbox(const char *context, const char *box, const char *data return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(test_voicemail_vmuser) { int res = 0; @@ -12494,6 +12495,7 @@ AST_TEST_DEFINE(test_voicemail_vmuser) free_user(vmu); return res ? AST_TEST_FAIL : AST_TEST_PASS; } +#endif static int vm_box_exists(struct ast_channel *chan, const char *data) { diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index 56d04b260eb..036f7f7d237 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -274,6 +274,7 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_register_line_test) { int res = AST_TEST_PASS; @@ -643,6 +644,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test) ast_test_status_update(test, "Out of memory. \n"); return res; } +#endif int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport) { @@ -708,6 +710,7 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum a return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_host_line_test) { int res = AST_TEST_PASS; @@ -787,6 +790,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test) return res; } +#endif /*! \brief Parse the comma-separated nat= option values */ void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags) @@ -834,6 +838,7 @@ void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_ } } +#ifdef TEST_FRAMEWORK #define TEST_FORCE_RPORT 1 << 0 #define TEST_COMEDIA 1 << 1 #define TEST_AUTO_FORCE_RPORT 1 << 2 @@ -904,6 +909,8 @@ AST_TEST_DEFINE(sip_parse_nat_test) return res; } +#endif + /*! \brief SIP test registration */ void sip_config_parser_register_tests(void) { diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c index 298b8cb9506..358d6e568cf 100644 --- a/channels/sip/reqresp_parser.c +++ b/channels/sip/reqresp_parser.c @@ -258,7 +258,7 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, return error; } - +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_uri_full_test) { int res = AST_TEST_PASS; @@ -514,7 +514,7 @@ AST_TEST_DEFINE(sip_parse_uri_full_test) return res; } - +#endif int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport) { @@ -530,6 +530,7 @@ int parse_uri(char *uri, const char *scheme, char **user, char **pass, return ret; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_uri_test) { int res = AST_TEST_PASS; @@ -687,6 +688,7 @@ AST_TEST_DEFINE(sip_parse_uri_test) return res; } +#endif /*! \brief Get caller id name from SIP headers, copy into output buffer * @@ -817,6 +819,7 @@ const char *get_calleridname(const char *input, char *output, size_t outputsize) return input; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_calleridname_test) { int res = AST_TEST_PASS; @@ -899,6 +902,7 @@ AST_TEST_DEFINE(get_calleridname_test) return res; } +#endif int get_name_and_number(const char *hdr, char **name, char **number) { @@ -940,6 +944,7 @@ int get_name_and_number(const char *hdr, char **name, char **number) return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_name_and_number_test) { int res = AST_TEST_PASS; @@ -1044,6 +1049,7 @@ AST_TEST_DEFINE(get_name_and_number_test) return res; } +#endif int get_in_brackets_const(const char *src,const char **start,int *length) { @@ -1176,6 +1182,7 @@ char *get_in_brackets(char *tmp) return out; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_in_brackets_test) { int res = AST_TEST_PASS; @@ -1252,7 +1259,7 @@ AST_TEST_DEFINE(get_in_brackets_test) return res; } - +#endif int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, @@ -1298,6 +1305,7 @@ int parse_name_andor_addr(char *uri, const char *scheme, char **name, return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2); } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_name_andor_addr_test) { int res = AST_TEST_PASS; @@ -1427,6 +1435,7 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) return res; } +#endif int get_comma(char *in, char **out) { @@ -1523,6 +1532,7 @@ int parse_contact_header(char *contactheader, struct contactliststruct *contactl return last; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_contact_header_test) { int res = AST_TEST_PASS; @@ -1668,6 +1678,7 @@ AST_TEST_DEFINE(parse_contact_header_test) return res; } +#endif /*! * \brief Parse supported header in incoming packet @@ -1755,6 +1766,7 @@ unsigned int parse_sip_options(const char *options, char *unsupported, size_t un return profile; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_options_test) { int res = AST_TEST_PASS; @@ -1892,6 +1904,7 @@ AST_TEST_DEFINE(sip_parse_options_test) return res; } +#endif /*! \brief helper routine for sip_uri_cmp to compare URI parameters * @@ -2246,6 +2259,7 @@ int sip_uri_cmp(const char *input1, const char *input2) #define URI_CMP_MATCH 0 #define URI_CMP_NOMATCH 1 +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_uri_cmp_test) { static const struct { @@ -2362,6 +2376,7 @@ AST_TEST_DEFINE(sip_uri_cmp_test) return test_res; } +#endif void free_via(struct sip_via *v) { @@ -2448,6 +2463,7 @@ struct sip_via *parse_via(const char *header) return v; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_via_test) { int res = AST_TEST_PASS; @@ -2625,6 +2641,7 @@ AST_TEST_DEFINE(parse_via_test) } return res; } +#endif void sip_request_parser_register_tests(void) { diff --git a/funcs/func_curl.c b/funcs/func_curl.c index 6a8c367672e..8ec1032a764 100644 --- a/funcs/func_curl.c +++ b/funcs/func_curl.c @@ -856,6 +856,7 @@ static struct ast_custom_function acf_curlopt = { .write = acf_curlopt_write, }; +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(vulnerable_url) { const char *bad_urls [] = { @@ -903,6 +904,7 @@ AST_TEST_DEFINE(vulnerable_url) return res; } +#endif static int unload_module(void) { diff --git a/res/res_pjsip.c b/res/res_pjsip.c index af2f93749f0..882f57876f0 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4154,6 +4154,7 @@ long ast_sip_threadpool_queue_size(void) return ast_threadpool_queue_size(sip_threadpool); } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(xml_sanitization_end_null) { char sanitized[8]; @@ -4204,6 +4205,7 @@ AST_TEST_DEFINE(xml_sanitization_exceeds_buffer) return AST_TEST_PASS; } +#endif /*! * \internal From 6fca2b3bf0f4a64423c8578e0817c7ae02470178 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 19 Jul 2016 11:48:25 +0200 Subject: [PATCH 0579/1578] Makefile: Retain XML Declaration and DTD in docs. Since Asterisk 12, the documentation got an XML Stylesheet. Because of a typo, the XML Declaration and DTD were overwritten by this. ASTERISK-26212 #close Change-Id: If5ee4625068042e98ab3fcb22a25e2f15d0c68bd --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b988c8ff625..ddc28527938 100644 --- a/Makefile +++ b/Makefile @@ -491,7 +491,7 @@ doc/core-en_US.xml: makeopts .lastclean $(XML_core_en_US) @printf "Building Documentation For: " @echo "" > $@ @echo "" >> $@ - @echo "" > $@ + @echo "" >> $@ @echo "" >> $@ @for x in $(MOD_SUBDIRS); do \ printf "$$x " ; \ @@ -515,7 +515,7 @@ else @printf "Building Documentation For: " @echo "" > $@ @echo "" >> $@ - @echo "" > $@ + @echo "" >> $@ @echo "" >> $@ @for x in $(MOD_SUBDIRS); do \ printf "$$x " ; \ From e739888d99bc4f4ef250e9c775814f4252335726 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 15 Jul 2016 20:44:52 -0500 Subject: [PATCH 0580/1578] res_pjsip: Add fax_detect_timeout endpoint option. The new endpoint option allows the PJSIP channel driver's fax_detect endpoint option to timeout on a call after the specified number of seconds into a call. The new feature is disabled if the timeout is set to zero. The option is disabled by default. ASTERISK-26214 Reported by: Richard Mudgett Change-Id: Id5a87375fb2c4f9dc1d4b44c78ec8735ba65453d --- CHANGES | 4 ++ channels/chan_pjsip.c | 41 +++++++++++++++---- configs/samples/pjsip.conf.sample | 4 ++ ...c67fa9b7a_add_fax_detect_timeout_option.py | 23 +++++++++++ include/asterisk/res_pjsip.h | 2 + include/asterisk/res_pjsip_session.h | 2 +- main/channel.c | 33 +++++++++++++-- res/res_pjsip.c | 8 ++++ res/res_pjsip/pjsip_configuration.c | 1 + 9 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py diff --git a/CHANGES b/CHANGES index 9caa524226a..62d81783ba1 100644 --- a/CHANGES +++ b/CHANGES @@ -366,6 +366,10 @@ cdr_csv res_pjsip ------------------ + * Added "fax_detect_timeout" to endpoint. + The option determines how many seconds into a call before fax_detect + is disabled for the call. Setting the value to zero disables the timeout. + * Added "subscribe_context" to endpoint. If specified, incoming SUBSCRIBE requests will be searched for the matching extension in the indicated context. If no "subscribe_context" is specified, diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5ad11740476..5a341f866fb 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -612,10 +612,12 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se { const char *target_context; int exists; + int dsp_features; - /* If we only needed this DSP for fax detection purposes we can just drop it now */ - if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) { - ast_dsp_set_features(session->dsp, DSP_FEATURE_DIGIT_DETECT); + dsp_features = ast_dsp_get_features(session->dsp); + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); } else { ast_dsp_free(session->dsp); session->dsp = NULL; @@ -660,6 +662,7 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); + struct ast_sip_session *session; struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_frame *f; struct ast_sip_session_media *media = NULL; @@ -697,22 +700,42 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) return f; } - if (ast_format_cap_iscompatible_format(channel->session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + session = channel->session; + + if (ast_format_cap_iscompatible_format(session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when endpoint '%s' is not configured for it\n", ast_format_get_name(f->subclass.format), ast_channel_name(ast), - ast_sorcery_object_get_id(channel->session->endpoint)); + ast_sorcery_object_get_id(session->endpoint)); ast_frfree(f); return &ast_null_frame; } - if (channel->session->dsp) { - f = ast_dsp_process(ast, channel->session->dsp, f); + if (session->dsp) { + int dsp_features; + dsp_features = ast_dsp_get_features(session->dsp); + if ((dsp_features & DSP_FEATURE_FAX_DETECT) + && session->endpoint->faxdetect_timeout + && session->endpoint->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); + } else { + ast_dsp_free(session->dsp); + session->dsp = NULL; + } + ast_debug(3, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + } + if (session->dsp) { + f = ast_dsp_process(ast, session->dsp, f); if (f && (f->frametype == AST_FRAME_DTMF)) { if (f->subclass.integer == 'f') { - ast_debug(3, "Fax CNG detected on %s\n", ast_channel_name(ast)); - f = chan_pjsip_cng_tone_detected(channel->session, f); + ast_debug(3, "Channel driver fax CNG detected on %s\n", + ast_channel_name(ast)); + f = chan_pjsip_cng_tone_detected(session, f); } else { ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer, ast_channel_name(ast)); diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 9069a669f76..4c42e8a5fa2 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -693,6 +693,10 @@ ;t38_udptl_maxdatagram=0 ; T 38 UDPTL maximum datagram size (default: ; "0") ;fax_detect=no ; Whether CNG tone detection is enabled (default: "no") +;fax_detect_timeout=30 ; How many seconds into a call before fax_detect is + ; disabled for the call. + ; Zero disables the timeout. + ; (default: "0") ;t38_udptl_nat=no ; Whether NAT support is enabled on UDPTL sessions ; (default: "no") ;t38_udptl_ipv6=no ; Whether IPv6 is used for UDPTL Sessions (default: diff --git a/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py new file mode 100644 index 00000000000..91774c447cc --- /dev/null +++ b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py @@ -0,0 +1,23 @@ +"""add fax_detect_timeout option + +Revision ID: 4a6c67fa9b7a +Revises: 9deac0ae4717 +Create Date: 2016-07-18 18:20:44.249491 + +""" + +# revision identifiers, used by Alembic. +revision = '4a6c67fa9b7a' +down_revision = '9deac0ae4717' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('fax_detect_timeout', sa.Integer)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'fax_detect_timeout') + diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 6f592836510..9dd70dbcaae 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -753,6 +753,8 @@ struct ast_sip_endpoint { struct ast_acl_list *acl; /* Restrict what IPs are allowed in the Contact header (for registration) */ struct ast_acl_list *contact_acl; + /*! The number of seconds into call to disable fax detection. (0 = disabled) */ + unsigned int faxdetect_timeout; }; /*! diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 5ca2c99a529..26dd451a79b 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -139,7 +139,7 @@ struct ast_sip_session { struct ast_party_id id; /*! Requested capabilities */ struct ast_format_cap *req_caps; - /*! Optional DSP, used only for inband DTMF detection if configured */ + /*! Optional DSP, used only for inband DTMF/Fax-CNG detection if configured */ struct ast_dsp *dsp; /*! Whether the termination of the session should be deferred */ unsigned int defer_terminate:1; diff --git a/main/channel.c b/main/channel.c index f654e4d2577..911c269558d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2692,10 +2692,28 @@ void ast_hangup(struct ast_channel *chan) ast_channel_unref(chan); } +/*! + * \internal + * \brief Set channel answered time if not already set. + * \since 13.11.0 + * + * \param chan Channel to set answered time. + * + * \return Nothing + */ +static void set_channel_answer_time(struct ast_channel *chan) +{ + if (ast_tvzero(ast_channel_answertime(chan))) { + struct timeval answertime; + + answertime = ast_tvnow(); + ast_channel_answertime_set(chan, &answertime); + } +} + int ast_raw_answer(struct ast_channel *chan) { int res = 0; - struct timeval answertime; ast_channel_lock(chan); @@ -2711,8 +2729,11 @@ int ast_raw_answer(struct ast_channel *chan) return -1; } - answertime = ast_tvnow(); - ast_channel_answertime_set(chan, &answertime); + /* + * Mark when incoming channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); ast_channel_unlock(chan); @@ -3911,6 +3932,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_frfree(f); f = &ast_null_frame; } else { + /* + * Mark when outgoing channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); + ast_setstate(chan, AST_STATE_UP); } } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) { diff --git a/res/res_pjsip.c b/res/res_pjsip.c index af2f93749f0..4034fafcc02 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -600,6 +600,14 @@ detected. + + How long into a call before fax_detect is disabled for the call + + The option determines how many seconds into a call before the + fax_detect option is disabled for the call. Setting the value + to zero disables the timeout. + + Whether NAT support is enabled on UDPTL sessions diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index d399f0b47fe..16405ebce7f 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1849,6 +1849,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, faxdetect_timeout)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone)); From 0d1744e1322256c2522bab34db18b75403b7d7ee Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 18 Jul 2016 16:16:56 -0500 Subject: [PATCH 0581/1578] chan_dahdi: Add faxdetect_timeout option. The new option allows the channel driver's faxdetect option to timeout on a call after the specified number of seconds into a call. The new feature is disabled if the timeout is set to zero. The option is disabled by default. * Don't clear dsp_features after passing them to the dsp code in my_pri_ss7_open_media(). We should still remember them especially for the new faxdetect_timeout option. ASTERISK-26214 Reported by: Richard Mudgett Change-Id: Ieffd3fe788788d56282844774365546dce8ac810 --- CHANGES | 6 ++++++ channels/chan_dahdi.c | 15 ++++++++++++++- channels/chan_dahdi.h | 5 +++++ configs/samples/chan_dahdi.conf.sample | 9 +++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 62d81783ba1..c01739fb79d 100644 --- a/CHANGES +++ b/CHANGES @@ -364,6 +364,12 @@ cdr_csv --- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- ------------------------------------------------------------------------------ +chan_dahdi +------------------ + * Added "faxdetect_timeout" option. + The option determines how many seconds into a call before faxdetect + is disabled for the call. Setting the value to zero disables the timeout. + res_pjsip ------------------ * Added "fax_detect_timeout" to endpoint. diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index e4b7c0ee8a4..b18dac91c76 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -2345,7 +2345,6 @@ static void my_pri_ss7_open_media(void *p) if (pvt->dsp_features && pvt->dsp) { ast_dsp_set_features(pvt->dsp, pvt->dsp_features); - pvt->dsp_features = 0; } } #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */ @@ -8640,6 +8639,15 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) /* Perform busy detection etc on the dahdi line */ int mute; + if ((p->dsp_features & DSP_FEATURE_FAX_DETECT) + && p->faxdetect_timeout + && p->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + p->dsp_features &= ~DSP_FEATURE_FAX_DETECT; + ast_dsp_set_features(p->dsp, p->dsp_features); + ast_debug(1, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f); /* Check if DSP code thinks we should be muting this frame and mute the conference if so */ @@ -12539,6 +12547,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, tmp->callprogress = conf->chan.callprogress; tmp->waitfordialtone = conf->chan.waitfordialtone; tmp->dialtone_detect = conf->chan.dialtone_detect; + tmp->faxdetect_timeout = conf->chan.faxdetect_timeout; tmp->cancallforward = conf->chan.cancallforward; tmp->dtmfrelax = conf->chan.dtmfrelax; tmp->callwaiting = tmp->permcallwaiting; @@ -17790,6 +17799,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING; } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING; + } else if (!strcasecmp(v->name, "faxdetect_timeout")) { + if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) { + confp->chan.faxdetect_timeout = 0; + } } else if (!strcasecmp(v->name, "echocancel")) { process_echocancel(confp, v->value, v->lineno); } else if (!strcasecmp(v->name, "echotraining")) { diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h index 4bb5d19a229..ab5c1eba983 100644 --- a/channels/chan_dahdi.h +++ b/channels/chan_dahdi.h @@ -612,6 +612,11 @@ struct dahdi_pvt { */ int dialtone_detect; int dialtone_scanning_time_elapsed; /*!< Amount of audio scanned for dialtone, in frames */ + /*! + * \brief The number of seconds into call to disable fax detection. (0 = disabled) + * \note Set from the "faxdetect_timeout" value read in from chan_dahdi.conf + */ + unsigned int faxdetect_timeout; struct timeval waitingfordt; /*!< Time we started waiting for dialtone */ struct timeval flashtime; /*!< Last flash-hook time */ /*! \brief Opaque DSP configuration structure. */ diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/samples/chan_dahdi.conf.sample index e0c69ebef99..a0c729c116a 100644 --- a/configs/samples/chan_dahdi.conf.sample +++ b/configs/samples/chan_dahdi.conf.sample @@ -1119,6 +1119,15 @@ pickupgroup=1 ;faxdetect=outgoing ;faxdetect=no ; +; When 'faxdetect' is enabled, one could use 'faxdetect_timeout' to disable fax +; detection after the specified number of seconds into a call. Be aware that +; outgoing analog channels may consider the channel is answered immediately +; when dialing completes. Analog does not have a reliable method of detecting +; when the far end answers. Zero disables the timeout. +; Default is 0 to disable the timeout. +; +;faxdetect_timeout=30 +; ; When 'faxdetect' is used, one could use 'faxbuffers' to configure the DAHDI ; transmit buffer policy. The default is *OFF*. When this configuration ; option is used, the faxbuffer policy will be used for the life of the call From 804fbd9c2bb3b62a8bcdf98eee51d7a586f62140 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 12 Jul 2016 17:24:54 -0500 Subject: [PATCH 0582/1578] res_fax: Fix FAXOPT(faxdetect) timeout option. The fax detection timeout option did not work because basically the wrong variable was checked in fax_detect_framehook(). As a result, the timer would timeout immediately and disable fax detection. * Fixed ignoring negative timeout values. We'd complain and then go right on using the negative value. * Fixed destroy_faxdetect() in the off-nominal case of an incomplete object creation. * Added more range checking to FAXOPT(gateway) timeout parameter. ASTERISK-26214 #close Reported by: Richard Mudgett Change-Id: Idc5e698dfe33572de9840bc68cd9fc043cbad976 --- include/asterisk/res_fax.h | 4 ++-- res/res_fax.c | 38 +++++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/asterisk/res_fax.h b/include/asterisk/res_fax.h index 2304da734d2..5119bfa6c48 100644 --- a/include/asterisk/res_fax.h +++ b/include/asterisk/res_fax.h @@ -179,11 +179,11 @@ struct ast_fax_session_details { unsigned int t38timeout; /*! the id of the t.38 gateway framehook for this channel */ int gateway_id; - /*! the timeout for this gateway in seconds */ + /*! The timeout for this gateway in ms */ int gateway_timeout; /*! the id of the faxdetect framehook for this channel */ int faxdetect_id; - /*! The timeout for this fax detect in seconds */ + /*! The timeout for this fax detect in ms */ int faxdetect_timeout; /*! flags used for fax detection */ int faxdetect_flags; diff --git a/res/res_fax.c b/res/res_fax.c index 347168e56be..c76d5553985 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -468,8 +468,6 @@ struct fax_gateway { struct fax_detect { /*! \brief the start of our timeout counter */ struct timeval timeout_start; - /*! \brief faxdetect timeout */ - int timeout; /*! \brief DSP Processor */ struct ast_dsp *dsp; /*! \brief original audio formats */ @@ -3539,13 +3537,13 @@ static void destroy_faxdetect(void *data) ast_dsp_free(faxdetect->dsp); faxdetect->dsp = NULL; } - ao2_ref(faxdetect->details, -1); + ao2_cleanup(faxdetect->details); ao2_cleanup(faxdetect->orig_format); } /*! \brief Create a new fax detect object. * \param chan the channel attaching to - * \param timeout remove framehook in this time if set + * \param timeout in ms to remove framehook in this time if not zero * \param flags required options * \return NULL or a fax gateway object */ @@ -3652,8 +3650,9 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a return f; } - if ((!ast_tvzero(faxdetect->timeout_start) && - (ast_tvdiff_ms(ast_tvnow(), faxdetect->timeout_start) > faxdetect->timeout))) { + if (!ast_tvzero(faxdetect->timeout_start) + && ast_tvdiff_ms(ast_tvnow(), faxdetect->timeout_start) > details->faxdetect_timeout) { + ast_debug(1, "FAXOPT(faxdetect) timeout on %s\n", ast_channel_name(chan)); ast_framehook_detach(chan, details->faxdetect_id); details->faxdetect_id = -1; return f; @@ -3732,7 +3731,7 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a /*! \brief Attach a faxdetect framehook object to a channel. * \param chan the channel to attach to - * \param timeout remove framehook in this time if set + * \param timeout in ms to remove framehook in this time if not zero * \return the faxdetect structure or NULL on error * \param flags required options * \retval -1 error @@ -4480,8 +4479,14 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat details->gateway_timeout = 0; if (timeout) { unsigned int gwtimeout; - if (sscanf(timeout, "%u", &gwtimeout) == 1) { - details->gateway_timeout = gwtimeout * 1000; + + if (sscanf(timeout, "%30u", &gwtimeout) == 1) { + if (gwtimeout >= 0) { + details->gateway_timeout = gwtimeout * 1000; + } else { + ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", + cmd, data); + } } else { ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", timeout, data); } @@ -4516,11 +4521,18 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat if (ast_true(val) || !strcasecmp(val, "t38") || !strcasecmp(val, "cng")) { if (details->faxdetect_id < 0) { - if (timeout && (sscanf(timeout, "%u", &fdtimeout) == 1)) { - if (fdtimeout > 0) { - fdtimeout = fdtimeout * 1000; + if (timeout) { + if (sscanf(timeout, "%30u", &fdtimeout) == 1) { + if (fdtimeout >= 0) { + fdtimeout *= 1000; + } else { + ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", + cmd, data); + fdtimeout = 0; + } } else { - ast_log(LOG_WARNING, "Timeout cannot be negative ignoring timeout\n"); + ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", + timeout, data); } } From 9abbea162c75c8a3485722fa22b4d5c9ee641132 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 12 Jul 2016 17:33:29 -0500 Subject: [PATCH 0583/1578] res_fax.c: Fix deadlock potential in FAXOPT(faxdetect) framehook. The fax_detect_framehook() has the potential to deadlock if an incoming fax happens during the Playback or similar application. * Fixed the potential deadlock by not calling ast_async_goto() with the channel lock held. * Made always eat the fax detection frame whether there is a fax extension or not. * Made only detach the framehook if we detected a fax and not on other possible frames. ASTERISK-26216 Reported by: Richard Mudgett Change-Id: I99da35c26d1cd802626ffb4c1b4eb5b015581b6d --- res/res_fax.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/res/res_fax.c b/res/res_fax.c index 347168e56be..0c02c8b596d 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -3701,30 +3701,36 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a } if (result) { - const char *target_context = S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)); + const char *target_context; + switch (result) { case 'f': case 't': + target_context = S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)); + ast_channel_unlock(chan); + ast_frfree(f); + f = &ast_null_frame; if (ast_exists_extension(chan, target_context, "fax", 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) { - ast_channel_lock(chan); ast_verb(2, "Redirecting '%s' to fax extension due to %s detection\n", ast_channel_name(chan), (result == 'f') ? "CNG" : "T38"); pbx_builtin_setvar_helper(chan, "FAXEXTEN", ast_channel_exten(chan)); if (ast_async_goto(chan, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(chan), target_context); } - ast_frfree(f); - f = &ast_null_frame; } else { - ast_channel_lock(chan); ast_log(LOG_NOTICE, "FAX %s detected but no fax extension in context (%s)\n", (result == 'f') ? "CNG" : "T38", target_context); } + ast_channel_lock(chan); + + ast_framehook_detach(chan, details->faxdetect_id); + details->faxdetect_id = -1; + break; + default: + break; } - ast_framehook_detach(chan, details->faxdetect_id); - details->faxdetect_id = -1; } return f; From 3db468ea9e3154758a965e247adaffdbc158034c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Jul 2016 18:48:01 -0500 Subject: [PATCH 0584/1578] chan_pjsip.c: Fix deadlock potential in fax redirection. The chan_pjsip_cng_tone_detected() has the potential to deadlock if an incoming fax happens during the Playback or similar application. * Fixed the potential deadlock by not calling ast_async_goto() with the channel lock held. * Made always eat the fax detection frame whether there is a fax extension or not. ASTERISK-26216 Reported by: Richard Mudgett Change-Id: I32aecbb4818af646dc5a619f0dc040e9b1f222e5 --- channels/chan_pjsip.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5ad11740476..a0ad424a4c3 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -628,16 +628,19 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel)); - /* We need to unlock the channel here because ast_exists_extension has the + /* + * We need to unlock the channel here because ast_exists_extension has the * potential to start and stop an autoservice on the channel. Such action * is prone to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the channel lock. */ ast_channel_unlock(session->channel); + ast_frfree(f); + f = &ast_null_frame; exists = ast_exists_extension(session->channel, target_context, "fax", 1, S_COR(ast_channel_caller(session->channel)->id.number.valid, ast_channel_caller(session->channel)->id.number.str, NULL)); - ast_channel_lock(session->channel); - if (exists) { ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(session->channel)); @@ -646,12 +649,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } - ast_frfree(f); - f = &ast_null_frame; } else { ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } + ast_channel_lock(session->channel); return f; } From db4979fa79bc3f5d754aa76816a39869132b10ca Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Jul 2016 18:49:08 -0500 Subject: [PATCH 0585/1578] chan_sip.c: Fix deadlock potential in fax redirection. The sip_read() has the potential to deadlock if an incoming fax happens during the Playback or similar application. * Fixed the potential deadlock by not calling ast_async_goto() with the channel lock held. * Made always eat the fax detection frame whether there is a fax extension or not. ASTERISK-26216 Reported by: Richard Mudgett Change-Id: I6d3f5cccd4b77c3aa6ffc1a54c0f6bde61c9278e --- channels/chan_sip.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b2522b6db79..ab54c765b55 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -8609,29 +8609,31 @@ static struct ast_frame *sip_read(struct ast_channel *ast) if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because + /* + * We need to unlock 'ast' here because * ast_exists_extension has the potential to start and * stop an autoservice on the channel. Such action is * prone to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding + * the channel lock. */ sip_pvt_unlock(p); ast_channel_unlock(ast); + ast_frfree(fr); + fr = &ast_null_frame; if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(ast)); pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } - ast_frfree(fr); - fr = &ast_null_frame; } else { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n"); } + ast_channel_lock(ast); + sip_pvt_lock(p); } } From 3d62f317dd0f1fb8a919c03861f1b6f50ce6c0d7 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 19 Jul 2016 13:18:47 -0500 Subject: [PATCH 0586/1578] chan_dahdi.c: Fix deadlock potential in fax redirection. The dahdi_handle_dtmf() and my_handle_dtmf() have the potential to deadlock if an incoming fax happens during the Playback or similar application. * Fixed the potential deadlock by not calling ast_async_goto() with the channel lock held. ASTERISK-26216 #close Reported by: Richard Mudgett Change-Id: I9144b84ade5f96690996624ec8a2d40c56af40aa --- channels/chan_dahdi.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index e4b7c0ee8a4..308e0930b30 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -1693,26 +1693,28 @@ static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub a if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } @@ -7200,26 +7202,28 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } From 8f6e9ffcc6231cfd4ae6c0a8b6e1d11beb59dc58 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 18 Jul 2016 23:46:19 -0400 Subject: [PATCH 0587/1578] Add conditional support for noreturn functions. This adds support for tagging functions with the noreturn attribute. If DO_CRASH is enabled then ast_do_crash never returns. If AST_DEVMODE and DO_CRASH are enabled then failed assertions never return. This can resolve a large number of false positives with static analyzers. ASTERISK-26220 #close Change-Id: Icfb61e5fe54574eced4c3e88b317244f467ec753 --- configure | 78 ++++++++++++++++++++++++++++++-- configure.ac | 1 + include/asterisk/autoconfig.h.in | 3 ++ include/asterisk/compiler.h | 6 +++ include/asterisk/utils.h | 9 +++- main/utils.c | 4 +- 6 files changed, 92 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 6d3faf2048a..fab78d01863 100755 --- a/configure +++ b/configure @@ -14150,7 +14150,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14196,7 +14196,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14220,7 +14220,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14265,7 +14265,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14289,7 +14289,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -18026,6 +18026,74 @@ CFLAGS="$saved_CFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute noreturn' support" >&5 +$as_echo_n "checking for compiler 'attribute noreturn' support... " >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" + + +if test "xnoreturn" = "x" +then +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + void __attribute__((noreturn)) *test(void *muffin, ...) {return (void *) 0;} +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_noreturn 1 +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + void __attribute__((noreturn)) *test(void *muffin, ...) ; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_noreturn 1 +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + +CFLAGS="$saved_CFLAGS" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=address support" >&5 $as_echo_n "checking for -fsanitize=address support... " >&6; } saved_sanitize_CFLAGS="${CFLAGS}" diff --git a/configure.ac b/configure.ac index dedfd8a2e9d..3331f78feeb 100644 --- a/configure.ac +++ b/configure.ac @@ -1076,6 +1076,7 @@ AST_GCC_ATTRIBUTE(warn_unused_result) AST_GCC_ATTRIBUTE(may_alias) AST_GCC_ATTRIBUTE(constructor) AST_GCC_ATTRIBUTE(destructor) +AST_GCC_ATTRIBUTE(noreturn,noreturn) AC_MSG_CHECKING(for -fsanitize=address support) saved_sanitize_CFLAGS="${CFLAGS}" diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 51f0f146297..9d2a84c02c2 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -102,6 +102,9 @@ /* Define to 1 if your GCC C compiler supports the 'may_alias' attribute. */ #undef HAVE_ATTRIBUTE_may_alias +/* Define to 1 if your GCC C compiler supports the 'noreturn' attribute. */ +#undef HAVE_ATTRIBUTE_noreturn + /* Define to 1 if your GCC C compiler supports the 'pure' attribute. */ #undef HAVE_ATTRIBUTE_pure diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h index 77b5de40e7c..6ceaa5f7755 100644 --- a/include/asterisk/compiler.h +++ b/include/asterisk/compiler.h @@ -77,6 +77,12 @@ #define attribute_may_alias #endif +#ifdef HAVE_ATTRIBUTE_noreturn +#define attribute_noreturn __attribute__((noreturn)) +#else +#define attribute_noreturn +#endif + /* Some older version of GNU gcc (3.3.5 on OpenBSD 4.3 for example) dont like 'NULL' as sentinel */ #define SENTINEL ((char *)NULL) diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index c7a473732eb..c311e9cd5ea 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -843,9 +843,14 @@ struct ast_http_digest { */ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic); +#ifdef DO_CRASH +#define DO_CRASH_NORETURN attribute_noreturn +#else +#define DO_CRASH_NORETURN +#endif #ifdef AST_DEVMODE -void __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function); +void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function); #define ast_assert(a) _ast_assert(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) static void force_inline _ast_assert(int condition, const char *condition_str, const char *file, int line, const char *function) { @@ -864,7 +869,7 @@ static void force_inline _ast_assert(int condition, const char *condition_str, c * * \return Nothing */ -void ast_do_crash(void); +void DO_CRASH_NORETURN ast_do_crash(void); #include "asterisk/strings.h" diff --git a/main/utils.c b/main/utils.c index 09839752b5b..46edf43ea2d 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2420,7 +2420,7 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size) return NULL; } -void ast_do_crash(void) +void DO_CRASH_NORETURN ast_do_crash(void) { #if defined(DO_CRASH) abort(); @@ -2433,7 +2433,7 @@ void ast_do_crash(void) } #if defined(AST_DEVMODE) -void __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function) +void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function) { /* * Attempt to put it into the logger, but hope that at least From 1d2173c7aed0587cdd434e69e89a3972a2642cd8 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 13 Jul 2016 12:24:46 +0200 Subject: [PATCH 0588/1578] res_srtp: Enable AES-256 and AES-GCM. ASTERISK-26190 #close Change-Id: I11326d80edd656524a51a19450e586c583aa0a0b --- channels/chan_sip.c | 28 ++- configure | 374 ++++++++++++++++++++++++++++++- configure.ac | 10 + include/asterisk/autoconfig.h.in | 10 + include/asterisk/res_srtp.h | 14 +- include/asterisk/sdp_srtp.h | 18 +- main/sdp_srtp.c | 373 ++++++++++++++++++++++++------ res/res_pjsip_sdp_rtp.c | 26 ++- res/res_srtp.c | 65 ++++-- 9 files changed, 805 insertions(+), 113 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 599ecd639e2..ca8c0fdf2ec 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -284,6 +284,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/features_config.h" #include "asterisk/http_websocket.h" #include "asterisk/format_cache.h" +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT */ /*** DOCUMENTATION @@ -13220,21 +13221,34 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) { + struct ast_sdp_srtp *tmp = srtp; char *a_crypto; - const char *orig_crypto; - if (!srtp || dtls_enabled) { + if (!tmp || dtls_enabled) { return NULL; } - orig_crypto = ast_sdp_srtp_get_attrib(srtp, dtls_enabled, default_taglen_32); - if (ast_strlen_zero(orig_crypto)) { + a_crypto = ast_strdup(""); + if (!a_crypto) { return NULL; } - if (ast_asprintf(&a_crypto, "a=crypto:%s\r\n", orig_crypto) == -1) { - return NULL; - } + do { + char *copy = a_crypto; + const char *orig_crypto = ast_sdp_srtp_get_attrib(tmp, dtls_enabled, default_taglen_32); + + if (ast_strlen_zero(orig_crypto)) { + ast_free(copy); + return NULL; + } + if (ast_asprintf(&a_crypto, "%sa=crypto:%s\r\n", copy, orig_crypto) == -1) { + ast_free(copy); + return NULL; + } + + ast_free(copy); + } while ((tmp = AST_LIST_NEXT(tmp, sdp_srtp_list))); + return a_crypto; } diff --git a/configure b/configure index aaad401d76b..a15ecc674af 100755 --- a/configure +++ b/configure @@ -778,6 +778,18 @@ PBX_SRTP_SHUTDOWN SRTP_SHUTDOWN_DIR SRTP_SHUTDOWN_INCLUDE SRTP_SHUTDOWN_LIB +PBX_SRTP_GCM +SRTP_GCM_DIR +SRTP_GCM_INCLUDE +SRTP_GCM_LIB +PBX_SRTP_192 +SRTP_192_DIR +SRTP_192_INCLUDE +SRTP_192_LIB +PBX_SRTP_256 +SRTP_256_DIR +SRTP_256_INCLUDE +SRTP_256_LIB PBX_SRTP SRTP_DIR SRTP_INCLUDE @@ -11395,6 +11407,42 @@ fi +SRTP_256_DESCRIP="SRTP Library AES-256 (ICM)" +SRTP_256_OPTION=srtp +SRTP_256_DIR=${SRTP_DIR} + +PBX_SRTP_256=0 + + + + + + + +SRTP_192_DESCRIP="SRTP Library AES-192 (ICM)" +SRTP_192_OPTION=srtp +SRTP_192_DIR=${SRTP_DIR} + +PBX_SRTP_192=0 + + + + + + + +SRTP_GCM_DESCRIP="SRTP Library AES-128 (GCM) and AES-256 (GCM)" +SRTP_GCM_OPTION=srtp +SRTP_GCM_DIR=${SRTP_DIR} + +PBX_SRTP_GCM=0 + + + + + + + SRTP_SHUTDOWN_DESCRIP="SRTP Library Shutdown Function" SRTP_SHUTDOWN_OPTION=srtp SRTP_SHUTDOWN_DIR=${SRTP_DIR} @@ -13802,7 +13850,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13848,7 +13896,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13872,7 +13920,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13917,7 +13965,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13941,7 +13989,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -31820,6 +31868,322 @@ rm -f core conftest.err conftest.$ac_objext \ CFLAGS="${saved_cflags}" fi +if test "$PBX_SRTP" = "1"; +then + +if test "x${PBX_SRTP_256}" != "x1" -a "${USE_SRTP_256}" != "no"; then + pbxlibdir="" + # if --with-SRTP_256=DIR has been specified, use it. + if test "x${SRTP_256_DIR}" != "x"; then + if test -d ${SRTP_256_DIR}/lib; then + pbxlibdir="-L${SRTP_256_DIR}/lib" + else + pbxlibdir="-L${SRTP_256_DIR}" + fi + fi + pbxfuncname="crypto_policy_set_aes_cm_256_hmac_sha1_80" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_256_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_256_FOUND=yes +else + AST_SRTP_256_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_256_FOUND}" = "yes"; then + SRTP_256_LIB="${pbxlibdir} -lsrtp " + # if --with-SRTP_256=DIR has been specified, use it. + if test "x${SRTP_256_DIR}" != "x"; then + SRTP_256_INCLUDE="-I${SRTP_256_DIR}/include" + fi + SRTP_256_INCLUDE="${SRTP_256_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_256_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_256_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_256_HEADER_FOUND=1 +else + SRTP_256_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_256_HEADER_FOUND}" = "x0" ; then + SRTP_256_LIB="" + SRTP_256_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_256_LIB="" + fi + PBX_SRTP_256=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_256 1 +_ACEOF + + fi + fi +fi + + + +if test "x${PBX_SRTP_192}" != "x1" -a "${USE_SRTP_192}" != "no"; then + pbxlibdir="" + # if --with-SRTP_192=DIR has been specified, use it. + if test "x${SRTP_192_DIR}" != "x"; then + if test -d ${SRTP_192_DIR}/lib; then + pbxlibdir="-L${SRTP_192_DIR}/lib" + else + pbxlibdir="-L${SRTP_192_DIR}" + fi + fi + pbxfuncname="crypto_policy_set_aes_cm_192_hmac_sha1_80" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_192_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_192_FOUND=yes +else + AST_SRTP_192_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_192_FOUND}" = "yes"; then + SRTP_192_LIB="${pbxlibdir} -lsrtp " + # if --with-SRTP_192=DIR has been specified, use it. + if test "x${SRTP_192_DIR}" != "x"; then + SRTP_192_INCLUDE="-I${SRTP_192_DIR}/include" + fi + SRTP_192_INCLUDE="${SRTP_192_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_192_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_192_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_192_HEADER_FOUND=1 +else + SRTP_192_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_192_HEADER_FOUND}" = "x0" ; then + SRTP_192_LIB="" + SRTP_192_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_192_LIB="" + fi + PBX_SRTP_192=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_192 1 +_ACEOF + + fi + fi +fi + + + +if test "x${PBX_SRTP_GCM}" != "x1" -a "${USE_SRTP_GCM}" != "no"; then + pbxlibdir="" + # if --with-SRTP_GCM=DIR has been specified, use it. + if test "x${SRTP_GCM_DIR}" != "x"; then + if test -d ${SRTP_GCM_DIR}/lib; then + pbxlibdir="-L${SRTP_GCM_DIR}/lib" + else + pbxlibdir="-L${SRTP_GCM_DIR}" + fi + fi + pbxfuncname="aes_gcm_128_openssl" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_GCM_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_GCM_FOUND=yes +else + AST_SRTP_GCM_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_GCM_FOUND}" = "yes"; then + SRTP_GCM_LIB="${pbxlibdir} -lsrtp " + # if --with-SRTP_GCM=DIR has been specified, use it. + if test "x${SRTP_GCM_DIR}" != "x"; then + SRTP_GCM_INCLUDE="-I${SRTP_GCM_DIR}/include" + fi + SRTP_GCM_INCLUDE="${SRTP_GCM_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_GCM_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_GCM_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_GCM_HEADER_FOUND=1 +else + SRTP_GCM_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_GCM_HEADER_FOUND}" = "x0" ; then + SRTP_GCM_LIB="" + SRTP_GCM_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_GCM_LIB="" + fi + PBX_SRTP_GCM=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_GCM 1 +_ACEOF + + fi + fi +fi + + +fi + if test "x${PBX_SRTP_SHUTDOWN}" != "x1" -a "${USE_SRTP_SHUTDOWN}" != "no"; then pbxlibdir="" diff --git a/configure.ac b/configure.ac index 6256ef7fb82..59587c0f47e 100644 --- a/configure.ac +++ b/configure.ac @@ -530,6 +530,9 @@ AST_EXT_LIB_SETUP_DEPENDENT([SPEEX_PREPROCESS], [speex_preprocess_ctl], [], [spe AST_EXT_LIB_SETUP([SQLITE], [SQLite], [sqlite]) AST_EXT_LIB_SETUP([SQLITE3], [SQLite], [sqlite3]) AST_EXT_LIB_SETUP([SRTP], [Secure RTP], [srtp]) +AST_EXT_LIB_SETUP_OPTIONAL([SRTP_256], [SRTP Library AES-256 (ICM)], [SRTP], [srtp]) +AST_EXT_LIB_SETUP_OPTIONAL([SRTP_192], [SRTP Library AES-192 (ICM)], [SRTP], [srtp]) +AST_EXT_LIB_SETUP_OPTIONAL([SRTP_GCM], [SRTP Library AES-128 (GCM) and AES-256 (GCM)], [SRTP], [srtp]) AST_EXT_LIB_SETUP_OPTIONAL([SRTP_SHUTDOWN], [SRTP Library Shutdown Function], [SRTP], [srtp]) AST_EXT_LIB_SETUP([OPENSSL], [OpenSSL Secure Sockets Layer], [ssl]) AST_EXT_LIB_SETUP_OPTIONAL([RT], [Realtime functions], [rt]) @@ -2461,6 +2464,13 @@ then CFLAGS="${saved_cflags}" fi +if test "$PBX_SRTP" = "1"; +then + AST_EXT_LIB_CHECK([SRTP_256], [srtp], [crypto_policy_set_aes_cm_256_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_192], [srtp], [crypto_policy_set_aes_cm_192_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_GCM], [srtp], [aes_gcm_128_openssl]) +fi + AST_EXT_LIB_CHECK([SRTP_SHUTDOWN], [srtp], [srtp_shutdown], [srtp/srtp.h]) for ver in 2.0 2.2 2.4 2.6; do diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index cdcc4d0064c..380ac2efb9f 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -838,6 +838,16 @@ /* Define to 1 if you have the Secure RTP library. */ #undef HAVE_SRTP +/* Define to 1 if SRTP has the SRTP Library AES-192 (ICM) feature. */ +#undef HAVE_SRTP_192 + +/* Define to 1 if SRTP has the SRTP Library AES-256 (ICM) feature. */ +#undef HAVE_SRTP_256 + +/* Define to 1 if SRTP has the SRTP Library AES-128 (GCM) and AES-256 (GCM) + feature. */ +#undef HAVE_SRTP_GCM + /* Define to 1 if SRTP has the SRTP Library Shutdown Function feature. */ #undef HAVE_SRTP_SHUTDOWN diff --git a/include/asterisk/res_srtp.h b/include/asterisk/res_srtp.h index c7fdc40b7ad..741d4f9ac0f 100644 --- a/include/asterisk/res_srtp.h +++ b/include/asterisk/res_srtp.h @@ -21,6 +21,8 @@ #ifndef _ASTERISK_RES_SRTP_H #define _ASTERISK_RES_SRTP_H +#include "asterisk.h" /* for size_t */ + struct ast_srtp; struct ast_srtp_policy; struct ast_rtp_instance; @@ -52,9 +54,17 @@ struct ast_srtp_res { /* Crypto suites */ enum ast_srtp_suite { + /* https://www.iana.org/assignments/srtp-protection/srtp-protection.xhtml */ AST_AES_CM_128_HMAC_SHA1_80 = 1, - AST_AES_CM_128_HMAC_SHA1_32 = 2, - AST_F8_128_HMAC_SHA1_80 = 3 + AST_AES_CM_128_HMAC_SHA1_32, + AST_AES_CM_256_HMAC_SHA1_80, + AST_AES_CM_256_HMAC_SHA1_32, + AST_AES_GCM_128 = 7, + AST_AES_GCM_256, + AST_AES_GCM_128_8, + AST_AES_GCM_256_8, + AST_AES_CM_192_HMAC_SHA1_80, + AST_AES_CM_192_HMAC_SHA1_32, }; struct ast_srtp_policy_res { diff --git a/include/asterisk/sdp_srtp.h b/include/asterisk/sdp_srtp.h index 772c3c38db0..5d8f0e7d1ea 100644 --- a/include/asterisk/sdp_srtp.h +++ b/include/asterisk/sdp_srtp.h @@ -20,8 +20,7 @@ * * \brief SRTP and SDP Security descriptions * - * Specified in RFC 4568 - * Specified in RFC 3711 + * Specified in RFC 3711, 6188, 7714, and 4568 * * \author Mikael Magnusson */ @@ -29,7 +28,8 @@ #ifndef _SDP_SRTP_H #define _SDP_SRTP_H -#include +#include "asterisk/linkedlists.h" /* for AST_LIST_ENTRY */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_instance */ struct ast_sdp_crypto; @@ -37,12 +37,18 @@ struct ast_sdp_crypto; struct ast_sdp_srtp { unsigned int flags; struct ast_sdp_crypto *crypto; + AST_LIST_ENTRY(ast_sdp_srtp) sdp_srtp_list; }; /* SRTP flags */ -#define AST_SRTP_CRYPTO_OFFER_OK (1 << 1) -#define AST_SRTP_CRYPTO_TAG_32 (1 << 2) -#define AST_SRTP_CRYPTO_TAG_80 (1 << 3) +#define AST_SRTP_CRYPTO_OFFER_OK (1 << 1) +#define AST_SRTP_CRYPTO_TAG_32 (1 << 2) +#define AST_SRTP_CRYPTO_TAG_80 (1 << 3) +#define AST_SRTP_CRYPTO_TAG_16 (1 << 4) +#define AST_SRTP_CRYPTO_TAG_8 (1 << 5) +#define AST_SRTP_CRYPTO_AES_192 (1 << 6) +#define AST_SRTP_CRYPTO_AES_256 (1 << 7) +#define AST_SRTP_CRYPTO_OLD_NAME (1 << 8) /*! * \brief allocate a ast_sdp_srtp structure diff --git a/main/sdp_srtp.c b/main/sdp_srtp.c index c92387bc207..a55aedf8247 100644 --- a/main/sdp_srtp.c +++ b/main/sdp_srtp.c @@ -20,8 +20,7 @@ * * \brief SRTP and SDP Security descriptions * - * Specified in RFC 3711 - * Specified in RFC 4568 + * Specified in RFC 3711, 6188, 7714, and 4568 * * \author Mikael Magnusson */ @@ -34,15 +33,15 @@ ASTERISK_REGISTER_FILE() -#include -#include "asterisk/options.h" -#include "asterisk/utils.h" -#include "asterisk/sdp_srtp.h" +#include /* for pow */ +#include /* for SRTP_MAX_KEY_LEN, etc */ -#define SRTP_MASTER_LEN 30 -#define SRTP_MASTERKEY_LEN 16 -#define SRTP_MASTERSALT_LEN ((SRTP_MASTER_LEN) - (SRTP_MASTERKEY_LEN)) -#define SRTP_MASTER_LEN64 (((SRTP_MASTER_LEN) * 8 + 5) / 6 + 1) +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */ +#include "asterisk/logger.h" /* for ast_log, LOG_ERROR, etc */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_engine_dtls, etc */ +#include "asterisk/sdp_srtp.h" /* for ast_sdp_srtp, etc */ +#include "asterisk/strings.h" /* for ast_strlen_zero */ +#include "asterisk/utils.h" /* for ast_set_flag, ast_test_flag, etc */ extern struct ast_srtp_res *res_srtp; extern struct ast_srtp_policy_res *res_srtp_policy; @@ -59,22 +58,31 @@ struct ast_sdp_srtp *ast_sdp_srtp_alloc(void) void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp) { - if (srtp->crypto) { - ast_sdp_crypto_destroy(srtp->crypto); + struct ast_sdp_srtp *next; + + for (next = AST_LIST_NEXT(srtp, sdp_srtp_list); + srtp; + srtp = next, next = srtp ? AST_LIST_NEXT(srtp, sdp_srtp_list) : NULL) { + if (srtp->crypto) { + ast_sdp_crypto_destroy(srtp->crypto); + } + srtp->crypto = NULL; + ast_free(srtp); } - srtp->crypto = NULL; - ast_free(srtp); } struct ast_sdp_crypto { char *a_crypto; - unsigned char local_key[SRTP_MASTER_LEN]; + unsigned char local_key[SRTP_MAX_KEY_LEN]; int tag; - char local_key64[SRTP_MASTER_LEN64]; - unsigned char remote_key[SRTP_MASTER_LEN]; + char local_key64[((SRTP_MAX_KEY_LEN) * 8 + 5) / 6 + 1]; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int key_len; }; -static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound); +static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len); +static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len); +static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound); void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto) { @@ -83,57 +91,67 @@ void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto) ast_free(crypto); } -struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) +static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len) { - struct ast_sdp_crypto *p; - int key_len; - unsigned char remote_key[SRTP_MASTER_LEN]; + unsigned char remote_key[key_len]; - if (!ast_rtp_engine_srtp_is_registered()) { + if (res_srtp->get_random(p->local_key, key_len) < 0) { return NULL; } - if (!(p = ast_calloc(1, sizeof(*p)))) { + ast_base64encode(p->local_key64, p->local_key, key_len, sizeof(p->local_key64)); + + p->key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); + + if (p->key_len != key_len) { + ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", p->key_len, key_len); return NULL; } - p->tag = 1; - if (res_srtp->get_random(p->local_key, sizeof(p->local_key)) < 0) { - ast_sdp_crypto_destroy(p); + if (memcmp(remote_key, p->local_key, p->key_len)) { + ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); return NULL; } - ast_base64encode(p->local_key64, p->local_key, SRTP_MASTER_LEN, sizeof(p->local_key64)); + ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); - key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); + return p; +} - if (key_len != SRTP_MASTER_LEN) { - ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", key_len, SRTP_MASTER_LEN); - ast_sdp_crypto_destroy(p); +static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len) +{ + struct ast_sdp_crypto *p, *result; + + if (!ast_rtp_engine_srtp_is_registered()) { return NULL; } - if (memcmp(remote_key, p->local_key, SRTP_MASTER_LEN)) { - ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); - ast_sdp_crypto_destroy(p); + if (!(p = ast_calloc(1, sizeof(*p)))) { return NULL; } + p->tag = 1; - ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); + /* default is a key which uses AST_AES_CM_128_HMAC_SHA1_xx */ + result = crypto_init_keys(p, key_len); + if (!result) { + ast_sdp_crypto_destroy(p); + } - return p; + return result; } -static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound) +struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) { - const unsigned char *master_salt = NULL; + return sdp_crypto_alloc(SRTP_MASTER_KEY_LEN); +} +static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound) +{ if (!ast_rtp_engine_srtp_is_registered()) { return -1; } - master_salt = master_key + SRTP_MASTERKEY_LEN; - if (res_srtp_policy->set_master_key(policy, master_key, SRTP_MASTERKEY_LEN, master_salt, SRTP_MASTERSALT_LEN) < 0) { + if (res_srtp_policy->set_master_key(policy, master_key, key_len, NULL, 0) < 0) { return -1; } @@ -147,7 +165,7 @@ static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, cons return 0; } -static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, struct ast_rtp_instance *rtp) +static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, int key_len, struct ast_rtp_instance *rtp) { struct ast_srtp_policy *local_policy = NULL; struct ast_srtp_policy *remote_policy = NULL; @@ -174,11 +192,11 @@ static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned cha goto err; } - if (set_crypto_policy(local_policy, suite_val, p->local_key, stats.local_ssrc, 0) < 0) { + if (set_crypto_policy(local_policy, suite_val, p->local_key, key_len, stats.local_ssrc, 0) < 0) { goto err; } - if (set_crypto_policy(remote_policy, suite_val, remote_key, 0, 1) < 0) { + if (set_crypto_policy(remote_policy, suite_val, remote_key, key_len, 0, 1) < 0) { goto err; } @@ -215,12 +233,15 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr char *lifetime = NULL; /* Key lifetime (# of RTP packets) */ char *mki = NULL; /* Master Key Index */ int found = 0; - int key_len = 0; + int key_len_from_sdp; + int key_len_expected; + int tag_from_sdp; int suite_val = 0; - unsigned char remote_key[SRTP_MASTER_LEN]; - int taglen = 0; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int taglen; double sdes_lifetime; - struct ast_sdp_crypto *crypto = srtp->crypto; + struct ast_sdp_crypto *crypto; + struct ast_sdp_srtp *tmp; if (!ast_rtp_engine_srtp_is_registered()) { return -1; @@ -239,7 +260,7 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr } /* RFC4568 9.1 - tag is 1-9 digits, greater than zero */ - if (sscanf(tag, "%30d", &crypto->tag) != 1 || crypto->tag <= 0 || crypto->tag > 999999999) { + if (sscanf(tag, "%30d", &tag_from_sdp) != 1 || tag_from_sdp <= 0 || tag_from_sdp > 999999999) { ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag); return -1; } @@ -249,16 +270,107 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr return -1; } + /* On egress, Asterisk sent several crypto lines in the SIP/SDP offer + The remote party might have choosen another line than the first */ + for (tmp = srtp; tmp && tmp->crypto && tmp->crypto->tag != tag_from_sdp;) { + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + if (tmp) { /* tag matched an already created crypto line */ + unsigned int flags = tmp->flags; + + /* Make that crypto line the head of the list, not by changing the + list structure but by exchanging the content of the list members */ + crypto = tmp->crypto; + tmp->crypto = srtp->crypto; + tmp->flags = srtp->flags; + srtp->crypto = crypto; + srtp->flags = flags; + } else { + crypto = srtp->crypto; + crypto->tag = tag_from_sdp; + } + if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) { suite_val = AST_AES_CM_128_HMAC_SHA1_80; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - taglen = 80; + key_len_expected = 30; } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { suite_val = AST_AES_CM_128_HMAC_SHA1_32; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - taglen = 32; + key_len_expected = 30; +#ifdef HAVE_SRTP_192 + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; +#endif +#ifdef HAVE_SRTP_256 + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; +#endif +#ifdef HAVE_SRTP_GCM + } else if (!strcmp(suite, "AEAD_AES_128_GCM")) { + suite_val = AST_AES_GCM_128; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM")) { + suite_val = AST_AES_GCM_256; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; + /* RFC contained a (too) short auth tag for RTP media, some still use that */ + } else if (!strcmp(suite, "AEAD_AES_128_GCM_8")) { + suite_val = AST_AES_GCM_128_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM_8")) { + suite_val = AST_AES_GCM_256_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; +#endif } else { - ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite); + ast_verb(1, "Unsupported crypto suite: %s\n", suite); return -1; } @@ -341,23 +453,55 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr return -1; } - key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); - if (key_len != SRTP_MASTER_LEN) { - ast_log(LOG_WARNING, "SRTP descriptions key length '%d' != master length '%d'\n", - key_len, SRTP_MASTER_LEN); + key_len_from_sdp = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); + if (key_len_from_sdp != key_len_expected) { + ast_log(LOG_WARNING, "SRTP descriptions key length is '%d', not '%d'\n", + key_len_from_sdp, key_len_expected); return -1; } - if (!memcmp(crypto->remote_key, remote_key, sizeof(crypto->remote_key))) { + /* on default, the key is 30 (AES-128); throw that away (only) when the suite changed actually */ + /* ingress: optional, but saves one expensive call to get_random(.) */ + /* egress: required, because the local key was communicated before the remote key is processed */ + if (crypto->key_len != key_len_from_sdp) { + if (!crypto_init_keys(crypto, key_len_from_sdp)) { + return -1; + } + } else if (!memcmp(crypto->remote_key, remote_key, key_len_from_sdp)) { ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); return 0; } - memcpy(crypto->remote_key, remote_key, sizeof(crypto->remote_key)); - if (crypto_activate(crypto, suite_val, remote_key, rtp) < 0) { + if (key_len_from_sdp > sizeof(crypto->remote_key)) { + ast_log(LOG_ERROR, + "SRTP key buffer is %zu although it must be at least %d bytes\n", + sizeof(crypto->remote_key), key_len_from_sdp); return -1; } + memcpy(crypto->remote_key, remote_key, key_len_from_sdp); + + if (crypto_activate(crypto, suite_val, remote_key, key_len_from_sdp, rtp) < 0) { + return -1; + } + + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { + taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; + } /* Finally, rebuild the crypto line */ if (ast_sdp_crypto_build_offer(crypto, taglen)) { @@ -375,10 +519,30 @@ int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) ast_free(p->a_crypto); } - if (ast_asprintf(&p->a_crypto, "%d AES_CM_128_HMAC_SHA1_%i inline:%s", - p->tag, taglen, p->local_key64) == -1) { - ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); - return -1; + if ((taglen & 0x007f) == 8) { + if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else if ((taglen & 0x007f) == 16) { + if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else if ((taglen & 0x0300) && !(taglen & 0x0080)) { + if (ast_asprintf(&p->a_crypto, "%d AES_%d_CM_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else { + if (ast_asprintf(&p->a_crypto, "%d AES_CM_%d_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } } ast_debug(1, "Crypto line: a=crypto:%s\n", p->a_crypto); @@ -388,7 +552,7 @@ int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) { - int taglen = default_taglen_32 ? 32 : 80; + int taglen; if (!srtp) { return NULL; @@ -396,7 +560,72 @@ const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, /* Set encryption properties */ if (!srtp->crypto) { - srtp->crypto = ast_sdp_crypto_alloc(); + + if (AST_LIST_NEXT(srtp, sdp_srtp_list)) { + srtp->crypto = ast_sdp_crypto_alloc(); + ast_log(LOG_ERROR, "SRTP SDP list was not empty\n"); + } else { + const int len = default_taglen_32 ? AST_SRTP_CRYPTO_TAG_32 : AST_SRTP_CRYPTO_TAG_80; + const int attr[][3] = { + /* This array creates the following list: + * a=crypto:1 AES_CM_128_HMAC_SHA1_ ... + * a=crypto:2 AEAD_AES_128_GCM ... + * a=crypto:3 AES_256_CM_HMAC_SHA1_ ... + * a=crypto:4 AEAD_AES_256_GCM ... + * a=crypto:5 AES_192_CM_HMAC_SHA1_ ... + * something like 'AEAD_AES_192_GCM' is not specified by the RFCs + * + * If you want to prefer another crypto suite or you want to + * exclude a suite, change this array and recompile Asterisk. + * This list cannot be changed from rtp.conf because you should + * know what you are doing. Especially AES-192 and AES-GCM are + * broken in many VoIP clients, see + * https://github.com/cisco/libsrtp/pull/170 + * https://github.com/cisco/libsrtp/pull/184 + * Furthermore, AES-GCM uses a shorter crypto-suite string which + * causes Nokia phones based on Symbian/S60 to reject the whole + * INVITE with status 500, even if a matching suite was offered. + * AES-256 might just waste your processor cycles, especially if + * your TLS transport is not secured with equivalent grade, see + * https://security.stackexchange.com/q/61361 + * Therefore, AES-128 was preferred here. + * + * If you want to enable one of those defines, please, go for + * CFLAGS='-DENABLE_SRTP_AES_GCM' ./configure && sudo make install + */ + { len, 0, 30 }, +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) + { AST_SRTP_CRYPTO_TAG_16, 0, AES_128_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_256) && defined(ENABLE_SRTP_AES_256) + { len, AST_SRTP_CRYPTO_AES_256, 46 }, +#endif +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) && defined(ENABLE_SRTP_AES_256) + { AST_SRTP_CRYPTO_TAG_16, AST_SRTP_CRYPTO_AES_256, AES_256_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_192) && defined(ENABLE_SRTP_AES_192) + { len, AST_SRTP_CRYPTO_AES_192, 38 }, +#endif + }; + struct ast_sdp_srtp *tmp = srtp; + int i; + + for (i = 0; i < ARRAY_LEN(attr); i++) { + if (attr[i][0]) { + ast_set_flag(tmp, attr[i][0]); + } + if (attr[i][1]) { + ast_set_flag(tmp, attr[i][1]); + } + tmp->crypto = sdp_crypto_alloc(attr[i][2]); /* key_len */ + tmp->crypto->tag = (i + 1); /* tag starts at 1 */ + + if (i < ARRAY_LEN(attr) - 1) { + AST_LIST_NEXT(tmp, sdp_srtp_list) = ast_sdp_srtp_alloc(); + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + } + } } if (dtls_enabled) { @@ -409,6 +638,20 @@ const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, taglen = 80; } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = default_taglen_32 ? 32 : 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; } if (srtp->crypto && (ast_sdp_crypto_build_offer(srtp->crypto, taglen) >= 0)) { diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 048209ce11f..6610ef126c3 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -51,6 +51,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/acl.h" #include "asterisk/sdp_srtp.h" #include "asterisk/dsp.h" +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT */ #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_session.h" @@ -938,6 +939,7 @@ static int add_crypto_to_stream(struct ast_sip_session *session, enum ast_rtp_dtls_hash hash; const char *crypto_attribute; struct ast_rtp_engine_dtls *dtls; + struct ast_sdp_srtp *tmp; static const pj_str_t STR_NEW = { "new", 3 }; static const pj_str_t STR_EXISTING = { "existing", 8 }; static const pj_str_t STR_ACTIVE = { "active", 6 }; @@ -957,16 +959,22 @@ static int add_crypto_to_stream(struct ast_sip_session *session, } } - crypto_attribute = ast_sdp_srtp_get_attrib(session_media->srtp, - 0 /* DTLS running? No */, - session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */); - if (!crypto_attribute) { - /* No crypto attribute to add, bad news */ - return -1; - } + tmp = session_media->srtp; + + do { + crypto_attribute = ast_sdp_srtp_get_attrib(tmp, + 0 /* DTLS running? No */, + session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */); + if (!crypto_attribute) { + /* No crypto attribute to add, bad news */ + return -1; + } + + attr = pjmedia_sdp_attr_create(pool, "crypto", + pj_cstr(&stmp, crypto_attribute)); + media->attr[media->attr_count++] = attr; + } while ((tmp = AST_LIST_NEXT(tmp, sdp_srtp_list))); - attr = pjmedia_sdp_attr_create(pool, "crypto", pj_cstr(&stmp, crypto_attribute)); - media->attr[media->attr_count++] = attr; break; case AST_SIP_MEDIA_ENCRYPT_DTLS: if (setup_dtls_srtp(session, session_media)) { diff --git a/res/res_srtp.c b/res/res_srtp.c index 0b1fb73e700..59fda76dd43 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -35,7 +35,7 @@ /* See https://wiki.asterisk.org/wiki/display/AST/Secure+Calling */ -#include "asterisk.h" +#include "asterisk.h" /* for NULL, size_t, memcpy, etc */ ASTERISK_REGISTER_FILE() @@ -46,12 +46,13 @@ ASTERISK_REGISTER_FILE() #include #endif -#include "asterisk/lock.h" -#include "asterisk/sched.h" -#include "asterisk/module.h" -#include "asterisk/options.h" -#include "asterisk/rtp_engine.h" -#include "asterisk/astobj2.h" +#include "asterisk/astobj2.h" /* for ao2_t_ref, etc */ +#include "asterisk/frame.h" /* for AST_FRIENDLY_OFFSET */ +#include "asterisk/logger.h" /* for ast_log, ast_debug, etc */ +#include "asterisk/module.h" /* for ast_module_info, etc */ +#include "asterisk/res_srtp.h" /* for ast_srtp_cb, ast_srtp_suite, etc */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_engine_register_srtp, etc */ +#include "asterisk/utils.h" /* for ast_free, ast_calloc */ struct ast_srtp { struct ast_rtp_instance *rtp; @@ -257,23 +258,49 @@ static int policy_set_suite(crypto_policy_t *p, enum ast_srtp_suite suite) { switch (suite) { case AST_AES_CM_128_HMAC_SHA1_80: - p->cipher_type = AES_128_ICM; - p->cipher_key_len = 30; - p->auth_type = HMAC_SHA1; - p->auth_key_len = 20; - p->auth_tag_len = 10; - p->sec_serv = sec_serv_conf_and_auth; + crypto_policy_set_aes_cm_128_hmac_sha1_80(p); return 0; case AST_AES_CM_128_HMAC_SHA1_32: - p->cipher_type = AES_128_ICM; - p->cipher_key_len = 30; - p->auth_type = HMAC_SHA1; - p->auth_key_len = 20; - p->auth_tag_len = 4; - p->sec_serv = sec_serv_conf_and_auth; + crypto_policy_set_aes_cm_128_hmac_sha1_32(p); return 0; +#ifdef HAVE_SRTP_192 + case AST_AES_CM_192_HMAC_SHA1_80: + crypto_policy_set_aes_cm_192_hmac_sha1_80(p); + return 0; + + case AST_AES_CM_192_HMAC_SHA1_32: + crypto_policy_set_aes_cm_192_hmac_sha1_32(p); + return 0; +#endif +#ifdef HAVE_SRTP_256 + case AST_AES_CM_256_HMAC_SHA1_80: + crypto_policy_set_aes_cm_256_hmac_sha1_80(p); + return 0; + + case AST_AES_CM_256_HMAC_SHA1_32: + crypto_policy_set_aes_cm_256_hmac_sha1_32(p); + return 0; +#endif +#ifdef HAVE_SRTP_GCM + case AST_AES_GCM_128: + crypto_policy_set_aes_gcm_128_16_auth(p); + return 0; + + case AST_AES_GCM_256: + crypto_policy_set_aes_gcm_256_16_auth(p); + return 0; + + case AST_AES_GCM_128_8: + crypto_policy_set_aes_gcm_128_8_auth(p); + return 0; + + case AST_AES_GCM_256_8: + crypto_policy_set_aes_gcm_256_8_auth(p); + return 0; +#endif + default: ast_log(LOG_ERROR, "Invalid crypto suite: %u\n", suite); return -1; From 81ea024d939530b76abca07b37fda0b502d0786a Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 21 Jul 2016 11:28:36 -0400 Subject: [PATCH 0589/1578] res_pjsip_pubsub: fixed a bug when pjsip_tx_data_dec_ref is called twice. This patch removed call of pjsip_tx_data_dec_ref in send_notify if send_request failed. The pjsip_dlg_send_request deletes the message on error by itself. It seems this patch fixes next issues: ASTERISK-26199 ASTERISK-26166 ASTERISK-26174 Change-Id: I8b05917c93d993f95d604c042ace5f1a5500f59a --- res/res_pjsip_pubsub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 207fae04c10..fe16c613ab8 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -2249,7 +2249,7 @@ static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int forc } if (sip_subscription_send_request(sub_tree, tdata)) { - pjsip_tx_data_dec_ref(tdata); + /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */ return -1; } From a36a174c4b15b9aaf915a89824bdfffa468cc112 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 15 Jul 2016 20:28:16 -0400 Subject: [PATCH 0590/1578] pbx: Create pbx_sw.c for management of 'struct ast_sw'. This changes context switches from a linked list to a vector, makes 'struct ast_sw' opaque to pbx.c. Although ast_walk_context_switches is maintained the procedure is no longer efficient except for the first call (inc==NULL). This functionality is replaced by two new functions implemented by vector macros. * ast_context_switches_count (AST_VECTOR_SIZE) * ast_context_switches_get (AST_VECTOR_GET) As with ast_walk_context_switches callers of these functions are expected to have locked contexts. Only a few places in Asterisk walked the switches, they have been converted to use the new functions. Change-Id: I08deb016df22eee8288eb03de62593e45a1f0998 --- include/asterisk/pbx.h | 13 +-- main/pbx.c | 194 ++++++++++++++++++++--------------------- main/pbx_private.h | 6 ++ main/pbx_sw.c | 107 +++++++++++++++++++++++ pbx/pbx_config.c | 8 +- res/ael/pval.c | 2 +- utils/conf2ael.c | 6 -- utils/extconf.c | 13 +++ 8 files changed, 235 insertions(+), 114 deletions(-) create mode 100644 main/pbx_sw.c diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 67cdccf900f..d44a245e368 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1229,9 +1229,9 @@ const char *ast_get_extension_name(struct ast_exten *exten); struct ast_context *ast_get_extension_context(struct ast_exten *exten); const char *ast_get_include_name(const struct ast_include *include); const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip); -const char *ast_get_switch_name(struct ast_sw *sw); -const char *ast_get_switch_data(struct ast_sw *sw); -int ast_get_switch_eval(struct ast_sw *sw); +const char *ast_get_switch_name(const struct ast_sw *sw); +const char *ast_get_switch_data(const struct ast_sw *sw); +int ast_get_switch_eval(const struct ast_sw *sw); /*! @} */ @@ -1251,7 +1251,7 @@ const char *ast_get_context_registrar(struct ast_context *c); const char *ast_get_extension_registrar(struct ast_exten *e); const char *ast_get_include_registrar(const struct ast_include *i); const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip); -const char *ast_get_switch_registrar(struct ast_sw *sw); +const char *ast_get_switch_registrar(const struct ast_sw *sw); /*! @} */ /*! @name Walking functions ... */ @@ -1265,7 +1265,8 @@ const struct ast_include *ast_walk_context_includes(const struct ast_context *co const struct ast_include *inc); const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con, const struct ast_ignorepat *ip); -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); +const struct ast_sw *ast_walk_context_switches(const struct ast_context *con, + const struct ast_sw *sw); /*! @} */ /*! @name Iterator functions ... */ @@ -1274,6 +1275,8 @@ int ast_context_includes_count(const struct ast_context *con); const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx); int ast_context_ignorepats_count(const struct ast_context *con); const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx); +int ast_context_switches_count(const struct ast_context *con); +const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx); /*! @} */ /*! diff --git a/main/pbx.c b/main/pbx.c index eb395eba447..f9fad038815 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -255,16 +255,6 @@ struct ast_exten { char stuff[0]; }; -/*! \brief ast_sw: Switch statement in extensions.conf */ -struct ast_sw { - char *name; - const char *registrar; /*!< Registrar */ - char *data; /*!< Data load */ - int eval; - AST_LIST_ENTRY(ast_sw) list; - char stuff[0]; -}; - /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */ struct match_char { @@ -297,10 +287,10 @@ struct ast_context { struct ast_context *next; /*!< Link them together */ struct ast_includes includes; /*!< Include other contexts */ struct ast_ignorepats ignorepats; /*!< Patterns for which to continue playing dialtone */ + struct ast_sws alts; /*!< Alternative switches */ char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */ int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */ int autohints; /*!< Whether autohints support is enabled or not */ - AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */ ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */ char name[0]; /*!< Name of the context */ }; @@ -2375,10 +2365,10 @@ struct fake_context /* this struct is purely for matching in the hashtab */ struct ast_context *next; struct ast_includes includes; struct ast_ignorepats ignorepats; + struct ast_sws alts; const char *registrar; int refcount; int autohints; - AST_LIST_HEAD_NOLOCK(, ast_sw) alts; ast_mutex_t macrolock; char name[256]; }; @@ -2433,7 +2423,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, int x, res; struct ast_context *tmp = NULL; struct ast_exten *e = NULL, *eroot = NULL; - struct ast_sw *sw = NULL; struct ast_exten pattern = {NULL, }; struct scoreboard score = {0, }; struct ast_str *tmpdata = NULL; @@ -2657,23 +2646,28 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, } /* Check alternative switches */ - AST_LIST_TRAVERSE(&tmp->alts, sw, list) { - struct ast_switch *asw = pbx_findswitch(sw->name); + for (idx = 0; idx < ast_context_switches_count(tmp); idx++) { + const struct ast_sw *sw = ast_context_switches_get(tmp, idx); + struct ast_switch *asw = pbx_findswitch(ast_get_switch_name(sw)); ast_switch_f *aswf = NULL; - char *datap; + const char *datap; if (!asw) { - ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name); + ast_log(LOG_WARNING, "No such switch '%s'\n", ast_get_switch_name(sw)); continue; } /* Substitute variables now */ - if (sw->eval) { + if (ast_get_switch_eval(sw)) { if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) { ast_log(LOG_WARNING, "Can't evaluate switch?!\n"); continue; } - pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata)); + pbx_substitute_variables_helper(chan, ast_get_switch_data(sw), + ast_str_buffer(tmpdata), ast_str_size(tmpdata)); + datap = ast_str_buffer(tmpdata); + } else { + datap = ast_get_switch_data(sw); } /* equivalent of extension_match_core() at the switch level */ @@ -2683,7 +2677,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, aswf = asw->matchmore; else /* action == E_MATCH */ aswf = asw->exists; - datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data; if (!aswf) res = 0; else { @@ -4819,24 +4812,29 @@ int ast_context_remove_switch(const char *context, const char *sw, const char *d */ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar) { - struct ast_sw *i; + int idx; int ret = -1; ast_wrlock_context(con); /* walk switches */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) { - if (!strcmp(i->name, sw) && !strcmp(i->data, data) && - (!registrar || !strcmp(i->registrar, registrar))) { + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx); + + if (!strcmp(ast_get_switch_name(i), sw) && + !strcmp(ast_get_switch_data(i), data) && + (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) { + /* found, remove from list */ ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar); - AST_LIST_REMOVE_CURRENT(list); - ast_free(i); /* free switch and return */ + AST_VECTOR_REMOVE_ORDERED(&con->alts, idx); + + /* free switch and return */ + sw_free(i); ret = 0; break; } } - AST_LIST_TRAVERSE_SAFE_END; ast_unlock_context(con); @@ -5517,8 +5515,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } } if (!rinclude) { - struct ast_sw *sw = NULL; - while ( (sw = ast_walk_context_switches(c, sw)) ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + snprintf(buf, sizeof(buf), "'%s/%s'", ast_get_switch_name(sw), ast_get_switch_data(sw)); @@ -5836,8 +5835,9 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } if (!rinclude) { - struct ast_sw *sw = NULL; - while ( (sw = ast_walk_context_switches(c, sw)) ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + if (!dpc->total_items++) manager_dpsendack(s, m); astman_append(s, "Event: ListDialplan\r\n%s", actionidtext); @@ -6087,6 +6087,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, tmp->registrar = ast_strdup(registrar); AST_VECTOR_INIT(&tmp->includes, 0); AST_VECTOR_INIT(&tmp->ignorepats, 0); + AST_VECTOR_INIT(&tmp->alts, 0); tmp->refcount = 1; } else { ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name); @@ -6138,7 +6139,6 @@ AST_LIST_HEAD_NOLOCK(store_hints, store_hint); static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar) { int idx; - struct ast_sw *sw; ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar); /* copy in the includes, switches, and ignorepats */ @@ -6153,9 +6153,12 @@ static void context_merge_incls_swits_igps_other_registrars(struct ast_context * } /* walk through switches */ - for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) { - if (strcmp(ast_get_switch_registrar(sw), registrar) == 0) + for (idx = 0; idx < ast_context_switches_count(old); idx++) { + const struct ast_sw *sw = ast_context_switches_get(old, idx); + + if (!strcmp(ast_get_switch_registrar(sw), registrar)) { continue; /* not mine */ + } ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw)); } @@ -6622,43 +6625,24 @@ int ast_context_add_switch(const char *context, const char *sw, const char *data int ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar) { + int idx; struct ast_sw *new_sw; - struct ast_sw *i; - int length; - char *p; - - length = sizeof(struct ast_sw); - length += strlen(value) + 1; - if (data) - length += strlen(data); - length++; /* allocate new sw structure ... */ - if (!(new_sw = ast_calloc(1, length))) + if (!(new_sw = sw_alloc(value, data, eval, registrar))) { return -1; - /* ... fill in this structure ... */ - p = new_sw->stuff; - new_sw->name = p; - strcpy(new_sw->name, value); - p += strlen(value) + 1; - new_sw->data = p; - if (data) { - strcpy(new_sw->data, data); - p += strlen(data) + 1; - } else { - strcpy(new_sw->data, ""); - p++; } - new_sw->eval = eval; - new_sw->registrar = registrar; /* ... try to lock this context ... */ ast_wrlock_context(con); /* ... go to last sw and check if context is already swd too... */ - AST_LIST_TRAVERSE(&con->alts, i, list) { - if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) { - ast_free(new_sw); + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + const struct ast_sw *i = ast_context_switches_get(con, idx); + + if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) && + !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) { + sw_free(new_sw); ast_unlock_context(con); errno = EEXIST; return -1; @@ -6666,9 +6650,10 @@ int ast_context_add_switch2(struct ast_context *con, const char *value, } /* ... sw new context into context list, unlock, return */ - AST_LIST_INSERT_TAIL(&con->alts, new_sw, list); + AST_VECTOR_APPEND(&con->alts, new_sw); - ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); + ast_verb(3, "Including switch '%s/%s' in context '%s'\n", + ast_get_switch_name(new_sw), ast_get_switch_data(new_sw), ast_get_context_name(con)); ast_unlock_context(con); @@ -7775,7 +7760,6 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha static void __ast_internal_context_destroy( struct ast_context *con) { - struct ast_sw *sw; struct ast_exten *e, *el, *en; struct ast_context *tmp = con; @@ -7787,6 +7771,10 @@ static void __ast_internal_context_destroy( struct ast_context *con) AST_VECTOR_CALLBACK_VOID(&tmp->ignorepats, ignorepat_free); AST_VECTOR_FREE(&tmp->ignorepats); + /* Free switches */ + AST_VECTOR_CALLBACK_VOID(&tmp->alts, sw_free); + AST_VECTOR_FREE(&tmp->alts); + if (tmp->registrar) ast_free(tmp->registrar); @@ -7798,8 +7786,6 @@ static void __ast_internal_context_destroy( struct ast_context *con) if (tmp->pattern_tree) destroy_pattern_tree(tmp->pattern_tree); - while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list))) - ast_free(sw); for (e = tmp->root; e;) { for (en = e->peer; en;) { el = en; @@ -7846,7 +7832,6 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* then search thru and remove any extens that match registrar. */ struct ast_hashtab_iter *exten_iter; struct ast_hashtab_iter *prio_iter; - struct ast_sw *sw = NULL; int idx; /* remove any ignorepats whose registrar matches */ @@ -7868,13 +7853,14 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context } } /* remove any switches whose registrar matches */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) { - if (strcmp(sw->registrar,registrar) == 0) { - AST_LIST_REMOVE_CURRENT(list); - ast_free(sw); + for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) { + struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx); + + if (!strcmp(ast_get_switch_registrar(sw), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx); + sw_free(sw); } } - AST_LIST_TRAVERSE_SAFE_END; if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */ exten_iter = ast_hashtab_start_traversal(tmp->root_table); @@ -7925,7 +7911,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* delete the context if it's registrar matches, is empty, has refcount of 1, */ /* it's not empty, if it has includes, ignorepats, or switches that are registered from another registrar. It's not empty if there are any extensions */ - if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && AST_LIST_EMPTY(&tmp->alts)) { + if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && !ast_context_switches_count(tmp)) { ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar); ast_hashtab_remove_this_object(contexttab, tmp); @@ -8364,26 +8350,6 @@ void *ast_get_extension_app_data(struct ast_exten *e) return e ? e->data : NULL; } -const char *ast_get_switch_name(struct ast_sw *sw) -{ - return sw ? sw->name : NULL; -} - -const char *ast_get_switch_data(struct ast_sw *sw) -{ - return sw ? sw->data : NULL; -} - -int ast_get_switch_eval(struct ast_sw *sw) -{ - return sw->eval; -} - -const char *ast_get_switch_registrar(struct ast_sw *sw) -{ - return sw ? sw->registrar : NULL; -} - /* * Walking functions ... */ @@ -8401,13 +8367,43 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con, return exten->next; } -struct ast_sw *ast_walk_context_switches(struct ast_context *con, - struct ast_sw *sw) +const struct ast_sw *ast_walk_context_switches(const struct ast_context *con, + const struct ast_sw *sw) { - if (!sw) - return con ? AST_LIST_FIRST(&con->alts) : NULL; - else - return AST_LIST_NEXT(sw, list); + if (sw) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + const struct ast_sw *s = ast_context_switches_get(con, idx); + + if (next) { + return s; + } + + if (sw == s) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_switches_count(con)) { + return NULL; + } + + return ast_context_switches_get(con, 0); +} + +int ast_context_switches_count(const struct ast_context *con) +{ + return AST_VECTOR_SIZE(&con->alts); +} + +const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->alts, idx); } struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, diff --git a/main/pbx_private.h b/main/pbx_private.h index 2b7d9828b63..da1060e0e9a 100644 --- a/main/pbx_private.h +++ b/main/pbx_private.h @@ -49,6 +49,12 @@ void include_free(struct ast_include *inc); int include_valid(const struct ast_include *inc); const char *include_rname(const struct ast_include *inc); +/*! pbx_sw.c */ +struct ast_sw; +AST_VECTOR(ast_sws, struct ast_sw *); +struct ast_sw *sw_alloc(const char *value, const char *data, int eval, const char *registrar); +void sw_free(struct ast_sw *sw); + /*! pbx_builtins.c functions needed by pbx.c */ int indicate_congestion(struct ast_channel *, const char *); int indicate_busy(struct ast_channel *, const char *); diff --git a/main/pbx_sw.c b/main/pbx_sw.c new file mode 100644 index 00000000000..0490ac6a2f5 --- /dev/null +++ b/main/pbx_sw.c @@ -0,0 +1,107 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan switch routines. + * + * \author Corey Farrell + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! \brief ast_sw: Switch statement in extensions.conf */ +struct ast_sw { + const char *name; + /*! Registrar */ + const char *registrar; + /*! Data load */ + const char *data; + int eval; + AST_LIST_ENTRY(ast_sw) list; + char stuff[0]; +}; + +const char *ast_get_switch_name(const struct ast_sw *sw) +{ + return sw ? sw->name : NULL; +} + +const char *ast_get_switch_data(const struct ast_sw *sw) +{ + return sw ? sw->data : NULL; +} + +int ast_get_switch_eval(const struct ast_sw *sw) +{ + return sw->eval; +} + +const char *ast_get_switch_registrar(const struct ast_sw *sw) +{ + return sw ? sw->registrar : NULL; +} + +struct ast_sw *sw_alloc(const char *value, const char *data, int eval, const char *registrar) +{ + struct ast_sw *new_sw; + int length; + char *p; + + if (!data) { + data = ""; + } + length = sizeof(struct ast_sw); + length += strlen(value) + 1; + length += strlen(data) + 1; + + /* allocate new sw structure ... */ + if (!(new_sw = ast_calloc(1, length))) { + return NULL; + } + + /* ... fill in this structure ... */ + p = new_sw->stuff; + new_sw->name = p; + strcpy(p, value); + + p += strlen(value) + 1; + new_sw->data = p; + strcpy(p, data); + + new_sw->eval = eval; + new_sw->registrar = registrar; + + return new_sw; +} + +void sw_free(struct ast_sw *sw) +{ + ast_free(sw); +} + diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index cb7e03a3e9c..0da4168f101 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -928,7 +928,6 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a int context_header_written = 0; struct ast_exten *ext, *last_written_e = NULL; int idx; - struct ast_sw *sw; /* try to lock context and fireout all info */ if (ast_rdlock_context(c)) { /* lock failure */ @@ -1016,7 +1015,9 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a } /* walk through switches */ - for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + if (strcmp(ast_get_switch_registrar(sw), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; @@ -1024,8 +1025,9 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a ast_get_switch_name(sw), ast_get_switch_data(sw)); } - if (ast_walk_context_switches(c, NULL)) + if (ast_context_switches_count(c)) { fprintf(output, "\n"); + } /* fireout ignorepats ... */ for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { diff --git a/res/ael/pval.c b/res/ael/pval.c index 2941365c9f8..485f5ee7967 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -4410,7 +4410,7 @@ static int context_used(struct ael_extension *exten_list, struct ast_context *co { struct ael_extension *exten; /* Check the simple elements first */ - if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_context_ignorepats_count(context) || ast_walk_context_switches(context, NULL)) { + if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_context_ignorepats_count(context) || ast_context_switches_count(context)) { return 1; } for (exten = exten_list; exten; exten = exten->next_exten) { diff --git a/utils/conf2ael.c b/utils/conf2ael.c index f0cb83f303d..3136fe37883 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -670,12 +670,6 @@ const struct ast_include *ast_walk_context_includes(const struct ast_context *co return NULL; } -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw) -{ - return NULL; -} - struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, diff --git a/utils/extconf.c b/utils/extconf.c index 049882334fe..8588d1a28a9 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -4448,6 +4448,19 @@ struct ast_sw *localized_walk_context_switches(struct ast_context *con, return ast_walk_context_switches(con, sw); } +int ast_context_switches_count(struct ast_context *con); +int ast_context_switches_count(struct ast_context *con) +{ + int c = 0; + struct ast_sw *sw = NULL; + + while ((sw = ast_walk_context_switches(con, sw))) { + c++; + } + + return c; +} + static struct ast_context *ast_context_find(const char *name); From 1b4922466b7afe407fc92cb7122575cd7bc87a11 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 21 Jul 2016 08:05:03 -0600 Subject: [PATCH 0591/1578] chan_sip: Prevent deadlock when issuing "sip show channels" sip_show_channels locks the dialogs container first then locks each sip_pvt so it can spit out the details. The rest of sip dialog processing locks the sip_pvt first then locks the dialogs container if it needs to. Both lock in the order they need but deadlocks can result. To fix, sip_show_channels and sip_show_channelstats have been converted to use an iterator rather than ao2_callback. This way the container is locked only while getting the next entry and is unlocked when the callback is called. ASTERISK-23013 #close Change-Id: Id9980419909e811f89484950ed46ef117b9eb990 --- channels/chan_sip.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b2522b6db79..2149a9166dc 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -21321,15 +21321,13 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg } /*! \brief Callback for show_chanstats */ -static int show_chanstats_cb(void *__cur, void *__arg, int flags) +static int show_chanstats_cb(struct sip_pvt *cur, struct __show_chan_arg *arg) { #define FORMAT2 "%-15.15s %-11.11s %-8.8s %-10.10s %-10.10s ( %%) %-6.6s %-10.10s %-10.10s ( %%) %-6.6s\n" #define FORMAT "%-15.15s %-11.11s %-8.8s %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf\n" - struct sip_pvt *cur = __cur; struct ast_rtp_instance_stats stats; char durbuf[10]; struct ast_channel *c; - struct __show_chan_arg *arg = __arg; int fd = arg->fd; sip_pvt_lock(cur); @@ -21389,6 +21387,8 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags) static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 }; + struct sip_pvt *cur; + struct ao2_iterator i; switch (cmd) { case CLI_INIT: @@ -21406,8 +21406,14 @@ static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_ return CLI_SHOWUSAGE; ast_cli(a->fd, FORMAT2, "Peer", "Call ID", "Duration", "Recv: Pack", "Lost", "Jitter", "Send: Pack", "Lost", "Jitter"); + /* iterate on the container and invoke the callback on each item */ - ao2_t_callback(dialogs, OBJ_NODATA, show_chanstats_cb, &arg, "callback to sip show chanstats"); + i = ao2_iterator_init(dialogs, 0); + for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) { + show_chanstats_cb(cur, &arg); + } + ao2_iterator_destroy(&i); + ast_cli(a->fd, "%d active SIP channel%s\n", arg.numchans, (arg.numchans != 1) ? "s" : ""); return CLI_SUCCESS; } @@ -21727,10 +21733,8 @@ static const struct cfsubscription_types *find_subscription_type(enum subscripti #define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-3.3s %-3.3s %-15.15s %-10.10s %-10.10s\n" /*! \brief callback for show channel|subscription */ -static int show_channels_cb(void *__cur, void *__arg, int flags) +static int show_channels_cb(struct sip_pvt *cur, struct __show_chan_arg *arg) { - struct sip_pvt *cur = __cur; - struct __show_chan_arg *arg = __arg; const struct ast_sockaddr *dst; sip_pvt_lock(cur); @@ -21782,7 +21786,8 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 }; - + struct sip_pvt *cur; + struct ao2_iterator i; if (cmd == CLI_INIT) { e->command = "sip show {channels|subscriptions}"; @@ -21804,7 +21809,11 @@ static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(arg.fd, FORMAT3, "Peer", "User", "Call ID", "Extension", "Last state", "Type", "Mailbox", "Expiry"); /* iterate on the container and invoke the callback on each item */ - ao2_t_callback(dialogs, OBJ_NODATA, show_channels_cb, &arg, "callback to show channels"); + i = ao2_iterator_init(dialogs, 0); + for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) { + show_channels_cb(cur, &arg); + } + ao2_iterator_destroy(&i); /* print summary information */ ast_cli(arg.fd, "%d active SIP %s%s\n", arg.numchans, From 15bf6a87dcf27e0f106c4e14aa85e9f42ca1172f Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 21 Jul 2016 15:35:39 -0600 Subject: [PATCH 0592/1578] Create Asterisk-14: Update CHANGES and UPGRADE files Change-Id: I35b5f6657670cfa8985796fa1e1fe86ad299efdc --- CHANGES | 4 +++ UPGRADE-14.txt | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ UPGRADE.txt | 69 +------------------------------------- 3 files changed, 96 insertions(+), 68 deletions(-) create mode 100644 UPGRADE-14.txt diff --git a/CHANGES b/CHANGES index 9caa524226a..c9af0c2d050 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,10 @@ === ============================================================================== +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- +------------------------------------------------------------------------------ + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ diff --git a/UPGRADE-14.txt b/UPGRADE-14.txt new file mode 100644 index 00000000000..f8fa7906b42 --- /dev/null +++ b/UPGRADE-14.txt @@ -0,0 +1,91 @@ +=========================================================== +=== +=== Information for upgrading between Asterisk versions +=== +=== These files document all the changes that MUST be taken +=== into account when upgrading between the Asterisk +=== versions listed below. These changes may require that +=== you modify your configuration files, dialplan or (in +=== some cases) source code if you have your own Asterisk +=== modules or patches. These files also include advance +=== notice of any functionality that has been marked as +=== 'deprecated' and may be removed in a future release, +=== along with the suggested replacement functionality. +=== +=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2 +=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4 +=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6 +=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8 +=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10 +=== UPGRADE-11.txt -- Upgrade info for 10 to 11 +=== UPGRADE-12.txt -- Upgrade info for 11 to 12 +=== UPGRADE-13.txt -- Upgrade info for 12 to 13 +=========================================================== + +ARI: + - The policy for when to send "Dial" events has changed. Previously, "Dial" + events were sent on the calling channel's topic. However, starting in Asterisk + 14, if there is no calling channel on which to send the event, the event is + instead sent on the called channel's topic. Note that for the ARI channels + resource's dial operation, this means that the "Dial" events will always be + sent on the called channel's topic. + +Channel Drivers: + +chan_dahdi: + - For users using the FXO port (FXS signaling) distinctive ring detection + feature, you will need to adjust the dringX count values. The count + values now only record ring end events instead of any DAHDI event. A + ring-ring-ring pattern would exceed the pattern limits and stop + Caller-ID detection. + +chan_sip: + - The SIP dial string has been extended past the [!dnid] option by another + exclamation mark: [!dnid[!fromuri]. An exclamation mark in the To-URI + will now mean changes to the From-URI. + +Core: + - The REF_DEBUG compiler flag is now used to enable refdebug by default. + The setting can be overridden in asterisk.conf by setting refdebug in + the options category. No recompile is required to enable/disable it. + + - Modified processing of command-line options to first parse only what + is necessary to read asterisk.conf. Once asterisk.conf is fully loaded, + the remaining options are processed. The -X option now applies to + asterisk.conf only. To enable #exec for other config files you must + set execincludes=yes in asterisk.conf. Any other option set on the + command-line will now override the equivalent setting from asterisk.conf. + +AMI: + - The 'ModuleCheck' Action's Version key will no longer show the module + version. The value will always be blank. + +CLI: + - The 'core show file version' command has been removed. When Asterisk + moved to Git, the source control version support was removed. As a + result, the CLi command was no longer useful and was removed as well. + +Logging: + - The first callid created is now 1 instead of 0. The value 0 + is now reserved to represent a lack of callid. + +AMI: + - The Command action now sends the output from the CLI command as a series + of Output headers for each line instead of as a block of text with the + --END COMMAND-- delimiter to match the output from other actions. + + Commands that fail to execute (no such command, invalid syntax etc.) now + return an Error response instead of Success. + +app_amd: + - The 'maximum_number_of_words' configuration option and parameter to the AMD + application previously did not match the documented functionality + variable + name. In Asterisk 13, a value of '3' would mean that if '3' words were detected, + the result would be detection as a 'MACHINE'. As of this version, the value + reflects the maximum words that if EXCEEDED (rather than reached), would + result in detection as a machine. This means that you should update this + value to be one higher than your previos value, if your previous value + was working well for you. + +=========================================================== +=========================================================== diff --git a/UPGRADE.txt b/UPGRADE.txt index f8fa7906b42..ad03edf8485 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -20,72 +20,5 @@ === UPGRADE-11.txt -- Upgrade info for 10 to 11 === UPGRADE-12.txt -- Upgrade info for 11 to 12 === UPGRADE-13.txt -- Upgrade info for 12 to 13 -=========================================================== - -ARI: - - The policy for when to send "Dial" events has changed. Previously, "Dial" - events were sent on the calling channel's topic. However, starting in Asterisk - 14, if there is no calling channel on which to send the event, the event is - instead sent on the called channel's topic. Note that for the ARI channels - resource's dial operation, this means that the "Dial" events will always be - sent on the called channel's topic. - -Channel Drivers: - -chan_dahdi: - - For users using the FXO port (FXS signaling) distinctive ring detection - feature, you will need to adjust the dringX count values. The count - values now only record ring end events instead of any DAHDI event. A - ring-ring-ring pattern would exceed the pattern limits and stop - Caller-ID detection. - -chan_sip: - - The SIP dial string has been extended past the [!dnid] option by another - exclamation mark: [!dnid[!fromuri]. An exclamation mark in the To-URI - will now mean changes to the From-URI. - -Core: - - The REF_DEBUG compiler flag is now used to enable refdebug by default. - The setting can be overridden in asterisk.conf by setting refdebug in - the options category. No recompile is required to enable/disable it. - - - Modified processing of command-line options to first parse only what - is necessary to read asterisk.conf. Once asterisk.conf is fully loaded, - the remaining options are processed. The -X option now applies to - asterisk.conf only. To enable #exec for other config files you must - set execincludes=yes in asterisk.conf. Any other option set on the - command-line will now override the equivalent setting from asterisk.conf. - -AMI: - - The 'ModuleCheck' Action's Version key will no longer show the module - version. The value will always be blank. - -CLI: - - The 'core show file version' command has been removed. When Asterisk - moved to Git, the source control version support was removed. As a - result, the CLi command was no longer useful and was removed as well. - -Logging: - - The first callid created is now 1 instead of 0. The value 0 - is now reserved to represent a lack of callid. - -AMI: - - The Command action now sends the output from the CLI command as a series - of Output headers for each line instead of as a block of text with the - --END COMMAND-- delimiter to match the output from other actions. - - Commands that fail to execute (no such command, invalid syntax etc.) now - return an Error response instead of Success. - -app_amd: - - The 'maximum_number_of_words' configuration option and parameter to the AMD - application previously did not match the documented functionality + variable - name. In Asterisk 13, a value of '3' would mean that if '3' words were detected, - the result would be detection as a 'MACHINE'. As of this version, the value - reflects the maximum words that if EXCEEDED (rather than reached), would - result in detection as a machine. This means that you should update this - value to be one higher than your previos value, if your previous value - was working well for you. - -=========================================================== +=== UPGRADE-14.txt -- Upgrade info for 13 to 14 =========================================================== From 68de3a9e5176c90225db4d21734bf126d4380c05 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 21 Jul 2016 23:34:46 -0400 Subject: [PATCH 0593/1578] pbx.c: Remove duplicate code. Merge code found in both branches of a conditional in ast_add_extension2_lockopt. The updated code initializes peer_table and peer_label_table of the extension before linking it to the context. Change-Id: Ic759e27cdc9906c6877df41d28ee9c5be8f41c20 --- main/pbx.c | 52 +++++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/main/pbx.c b/main/pbx.c index f9fad038815..4d6d31ec4bd 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -7278,52 +7278,38 @@ static int ast_add_extension2_lockopt(struct ast_context *con, * so insert in the main list right before 'e' (if any) */ tmp->next = e; - if (el) { /* there is another exten already in this context */ - el->next = tmp; - tmp->peer_table = ast_hashtab_create(13, - hashtab_compare_exten_numbers, + tmp->peer_table = ast_hashtab_create(13, + hashtab_compare_exten_numbers, + ast_hashtab_resize_java, + ast_hashtab_newsize_java, + hashtab_hash_priority, + 0); + tmp->peer_label_table = ast_hashtab_create(7, + hashtab_compare_exten_labels, ast_hashtab_resize_java, ast_hashtab_newsize_java, - hashtab_hash_priority, + hashtab_hash_labels, 0); - tmp->peer_label_table = ast_hashtab_create(7, - hashtab_compare_exten_labels, - ast_hashtab_resize_java, - ast_hashtab_newsize_java, - hashtab_hash_labels, - 0); - if (label) { - ast_hashtab_insert_safe(tmp->peer_label_table, tmp); - } - ast_hashtab_insert_safe(tmp->peer_table, tmp); + + if (el) { /* there is another exten already in this context */ + el->next = tmp; } else { /* this is the first exten in this context */ - if (!con->root_table) + if (!con->root_table) { con->root_table = ast_hashtab_create(27, hashtab_compare_extens, ast_hashtab_resize_java, ast_hashtab_newsize_java, hashtab_hash_extens, 0); - con->root = tmp; - con->root->peer_table = ast_hashtab_create(13, - hashtab_compare_exten_numbers, - ast_hashtab_resize_java, - ast_hashtab_newsize_java, - hashtab_hash_priority, - 0); - con->root->peer_label_table = ast_hashtab_create(7, - hashtab_compare_exten_labels, - ast_hashtab_resize_java, - ast_hashtab_newsize_java, - hashtab_hash_labels, - 0); - if (label) { - ast_hashtab_insert_safe(con->root->peer_label_table, tmp); } - ast_hashtab_insert_safe(con->root->peer_table, tmp); - + con->root = tmp; + } + if (label) { + ast_hashtab_insert_safe(tmp->peer_label_table, tmp); } + ast_hashtab_insert_safe(tmp->peer_table, tmp); ast_hashtab_insert_safe(con->root_table, tmp); + if (lock_context) { ast_unlock_context(con); } From 4286a369a153d51fb6f4d6e1fbc49e222c0bbfdf Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 15 Jul 2016 16:16:18 -0500 Subject: [PATCH 0594/1578] res_pjsip: Whitespace and comment cleanup. Change-Id: I11139a4a95df34e223ba622aa6227e33ab8f6c38 --- configs/samples/pjsip.conf.sample | 18 +++++------ include/asterisk/res_pjsip.h | 4 +-- res/res_pjsip.c | 51 +++++++++++++++---------------- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 4c42e8a5fa2..99bdfb99d0a 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -672,7 +672,7 @@ ; usage of media encryption for this endpoint (default: ; "no") ;media_encryption_optimistic=no ; Use encryption if possible but don't fail the call - ; if not possible. + ; if not possible. ;g726_non_standard=no ; When set to "yes" and an endpoint negotiates g.726 ; audio then g.726 for AAL2 packing order is used contrary ; to what is recommended in RFC3551. Note, 'g726aal2' also @@ -752,7 +752,7 @@ ;srtp_tag_32=no ; Determines whether 32 byte tags should be used instead of 80 ; byte tags (default: "no") ;set_var= ; Variable set on a channel involving the endpoint. For multiple - ; channel variables specify multiple 'set_var'(s) + ; channel variables specify multiple 'set_var'(s) ;rtp_keepalive= ; Interval, in seconds, between comfort noise RTP packets if ; RTP is not flowing. This setting is useful for ensuring that ; holes in NATs and firewalls are kept open throughout a call. @@ -794,7 +794,7 @@ ; (default: "") ;ca_list_path= ; Path to directory containing certificates to read TLS ONLY. ; PJProject version 2.4 or higher is required for this option to - ; be used. + ; be used. ; (default: "") ;cert_file= ; Certificate file for endpoint TLS ONLY ; Will read .crt or .pem file but only uses cert, @@ -886,8 +886,8 @@ ;disable_tcp_switch=yes ; Disable automatic switching from UDP to TCP transports ; if outgoing request is too large. ; See RFC 3261 section 18.1.1. - ; Disabling this option has been known to cause interoperability - ; issues, so disable at your own risk. + ; Disabling this option has been known to cause interoperability + ; issues, so disable at your own risk. ; (default: "yes") ;type= ; Must be of type system (default: "") @@ -917,10 +917,10 @@ ;contact_expiration_check_interval=30 ; The interval (in seconds) to check for expired contacts. ;disable_multi_domain=no - ; Disable Multi Domain support. - ; If disabled it can improve realtime performace by reducing - ; number of database requsts - ; (default: "no") + ; Disable Multi Domain support. + ; If disabled it can improve realtime performace by reducing + ; number of database requsts + ; (default: "no") ;endpoint_identifier_order=ip,username,anonymous ; The order by which endpoint identifiers are given priority. ; Currently, "ip", "username", "auth_username" and "anonymous" are valid diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 9dd70dbcaae..9bb2a82c5de 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -749,9 +749,9 @@ struct ast_sip_endpoint { unsigned int usereqphone; /*! Whether to pass through hold and unhold using re-invites with recvonly and sendrecv */ unsigned int moh_passthrough; - /* Access control list */ + /*! Access control list */ struct ast_acl_list *acl; - /* Restrict what IPs are allowed in the Contact header (for registration) */ + /*! Restrict what IPs are allowed in the Contact header (for registration) */ struct ast_acl_list *contact_acl; /*! The number of seconds into call to disable fax detection. (0 = disabled) */ unsigned int faxdetect_timeout; diff --git a/res/res_pjsip.c b/res/res_pjsip.c index a1deb9e5fc3..f56790df701 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -217,10 +217,9 @@ DTMF is sent as SIP INFO packets. - - DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not. - - + + DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not. + @@ -510,15 +509,15 @@ Force g.726 to use AAL2 packing order when negotiating g.726 audio - When set to "yes" and an endpoint negotiates g.726 audio then use g.726 for AAL2 - packing order instead of what is recommended by RFC3551. Since this essentially - replaces the underlying 'g726' codec with 'g726aal2' then 'g726aal2' needs to be - specified in the endpoint's allowed codec list. + When set to "yes" and an endpoint negotiates g.726 audio then use g.726 for AAL2 + packing order instead of what is recommended by RFC3551. Since this essentially + replaces the underlying 'g726' codec with 'g726aal2' then 'g726aal2' needs to be + specified in the endpoint's allowed codec list. Determines whether chan_pjsip will indicate ringing using inband - progress. + progress. If set to yes, chan_pjsip will send a 183 Session Progress when told to indicate ringing and will immediately start sending ringing @@ -814,7 +813,7 @@ Variable set on a channel involving the endpoint. - When a new channel is created using the endpoint set the specified + When a new channel is created using the endpoint set the specified variable(s) on that channel. For multiple channel variables specify multiple 'set_var'(s). @@ -1455,9 +1454,9 @@ Value used in User-Agent header for SIP requests and Server header for SIP responses. - When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given - peer who registers or unregisters with us. - + When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given + peer who registers or unregisters with us. + Endpoint to use when sending an outbound request to a URI without a specified endpoint. @@ -1466,15 +1465,15 @@ Enable/Disable SIP debug logging. Valid options include yes|no or - a host address + a host address The order by which endpoint identifiers are processed and checked. - Identifier names are usually derived from and can be found in the endpoint - identifier module itself (res_pjsip_endpoint_identifier_*). - You can use the CLI command "pjsip show identifiers" to see the - identifiers currently available. - + Identifier names are usually derived from and can be found in the endpoint + identifier module itself (res_pjsip_endpoint_identifier_*). + You can use the CLI command "pjsip show identifiers" to see the + identifiers currently available. + One of the identifiers is "auth_username" which matches on the username in an Authentication header. This method has some security considerations because an @@ -1488,17 +1487,17 @@ how many unmatched requests are received from a single ip address before a security event is generated using the unidentified_request parameters. - + When Asterisk generates an outgoing SIP request, the From header username will be - set to this value if there is no better option (such as CallerID) to be - used. + set to this value if there is no better option (such as CallerID) to be + used. When Asterisk generates an challenge, the digest will be - set to this value if there is no better option (such as auth/realm) to be - used. + set to this value if there is no better option (such as auth/realm) to be + used. @@ -2066,7 +2065,7 @@ Provides a listing of all endpoints. For each endpoint an EndpointList event is raised that contains relevant attributes and status information. Once all endpoints have been listed an EndpointListComplete event is issued. - + @@ -2102,7 +2101,7 @@ IdentifyDetail. Some events may be listed multiple times if multiple objects are associated (for instance AoRs). Once all detail events have been raised a final EndpointDetailComplete event is issued. - + From 8fb807009f2e19349be778fc78be110f72ccc2f8 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 19 Jul 2016 20:39:38 +0200 Subject: [PATCH 0595/1578] codecs: Add iLBC 20. Asterisk already supported iLBC 30. This change adds iLBC 20. Now, Asterisk defaults to iLBC 20 but falls back to iLBC 30, when the remote party requests this. ASTERISK-26218 #close ASTERISK-26221 #close Reported by: Aaron Meriwether Change-Id: I07f523a3aa1338bb5217a1bf69c1eeb92adedffa --- CHANGES | 6 ++ codecs/codec_ilbc.c | 79 ++++++++++------- codecs/ex_ilbc.h | 7 +- include/asterisk/ilbc.h | 8 ++ main/codec_builtin.c | 16 ++-- res/res_format_attr_ilbc.c | 172 +++++++++++++++++++++++++++++++++++++ 6 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 include/asterisk/ilbc.h create mode 100644 res/res_format_attr_ilbc.c diff --git a/CHANGES b/CHANGES index 9caa524226a..a0dffe6841c 100644 --- a/CHANGES +++ b/CHANGES @@ -63,6 +63,12 @@ ChanSpy experienced when using ChanSpy, but may introduce some delay in the audio feed on the listening channel. +Codecs +------------------ + * Added format attribute negotiation for the iLBC audio codec. Format attribute + negotiation is provided by the res_format_attr_ilbc module. iLBC 20 is the + default now. Falls back to iLBC 30, when the remote party requests this. + ConfBridge ------------------ * Added the ability to pass options to MixMonitor when recording is used with diff --git a/codecs/codec_ilbc.c b/codecs/codec_ilbc.c index 3e480e8fd1a..fc713beb776 100644 --- a/codecs/codec_ilbc.c +++ b/codecs/codec_ilbc.c @@ -34,10 +34,13 @@ ASTERISK_REGISTER_FILE() -#include "asterisk/translate.h" +#include "asterisk/codec.h" /* for AST_MEDIA_TYPE_AUDIO */ +#include "asterisk/format.h" /* for ast_format_get_attribute_data */ +#include "asterisk/frame.h" /* for ast_frame, etc */ +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */ +#include "asterisk/logger.h" /* for ast_log, ast_debug, etc */ #include "asterisk/module.h" -#include "asterisk/utils.h" -#include "asterisk/linkedlists.h" +#include "asterisk/translate.h" /* for ast_trans_pvt, etc */ #ifdef ILBC_WEBRTC #include @@ -52,13 +55,10 @@ typedef float ilbc_block; #define BUF_TYPE uc #endif -#define USE_ILBC_ENHANCER 0 -#define ILBC_MS 30 -/* #define ILBC_MS 20 */ +#include "asterisk/ilbc.h" -#define ILBC_FRAME_LEN 50 /* apparently... */ -#define ILBC_SAMPLES 240 /* 30ms at 8000 hz */ -#define BUFFER_SAMPLES 8000 +#define USE_ILBC_ENHANCER 0 +#define BUFFER_SAMPLES 8000 /* Sample frame data */ #include "asterisk/slin.h" @@ -69,13 +69,16 @@ struct ilbc_coder_pvt { iLBC_Dec_Inst_t dec; /* Enough to store a full second */ int16_t buf[BUFFER_SAMPLES]; + int16_t inited; }; static int lintoilbc_new(struct ast_trans_pvt *pvt) { struct ilbc_coder_pvt *tmp = pvt->pvt; + struct ilbc_attr *attr = pvt->explicit_dst ? ast_format_get_attribute_data(pvt->explicit_dst) : NULL; + const unsigned int mode = attr ? attr->mode : 30; - initEncode(&tmp->enc, ILBC_MS); + initEncode(&tmp->enc, mode); return 0; } @@ -84,7 +87,7 @@ static int ilbctolin_new(struct ast_trans_pvt *pvt) { struct ilbc_coder_pvt *tmp = pvt->pvt; - initDecode(&tmp->dec, ILBC_MS, USE_ILBC_ENHANCER); + tmp->inited = 0; /* we do not know the iLBC mode, yet */ return 0; } @@ -93,13 +96,19 @@ static int ilbctolin_new(struct ast_trans_pvt *pvt) static int ilbctolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { struct ilbc_coder_pvt *tmp = pvt->pvt; + struct ilbc_attr *attr = ast_format_get_attribute_data(f->subclass.format); + const unsigned int mode = attr ? attr->mode : 30; + const unsigned int sample_rate = pvt->t->dst_codec.sample_rate; + const unsigned int samples_per_frame = mode * sample_rate / 1000; + const unsigned int octets_per_frame = (mode == 20) ? 38 : 50; + int plc_mode = 1; /* 1 = normal data, 0 = plc */ /* Assuming there's space left, decode into the current buffer at the tail location. Read in as many frames as there are */ int x,i; int datalen = f->datalen; int16_t *dst = pvt->outbuf.i16; - ilbc_block tmpf[ILBC_SAMPLES]; + ilbc_block tmpf[samples_per_frame]; if (!f->data.ptr && datalen) { ast_debug(1, "issue 16070, ILIB ERROR. data = NULL datalen = %d src = %s\n", datalen, f->src ? f->src : "no src set"); @@ -108,27 +117,32 @@ static int ilbctolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) } if (datalen == 0) { /* native PLC, set fake datalen and clear plc_mode */ - datalen = ILBC_FRAME_LEN; - f->samples = ILBC_SAMPLES; + datalen = octets_per_frame; + f->samples = samples_per_frame; plc_mode = 0; /* do native plc */ - pvt->samples += ILBC_SAMPLES; + pvt->samples += samples_per_frame; } - if (datalen % ILBC_FRAME_LEN) { - ast_log(LOG_WARNING, "Huh? An ilbc frame that isn't a multiple of 50 bytes long from %s (%d)?\n", f->src, datalen); + if (datalen % octets_per_frame) { + ast_log(LOG_WARNING, "Huh? An ilbc frame that isn't a multiple of %u bytes long from %s (%d)?\n", octets_per_frame, f->src, datalen); return -1; } - for (x=0; x < datalen ; x += ILBC_FRAME_LEN) { - if (pvt->samples + ILBC_SAMPLES > BUFFER_SAMPLES) { + if (!tmp->inited) { + initDecode(&tmp->dec, mode, USE_ILBC_ENHANCER); + tmp->inited = 1; + } + + for (x = 0; x < datalen; x += octets_per_frame) { + if (pvt->samples + samples_per_frame > BUFFER_SAMPLES) { ast_log(LOG_WARNING, "Out of buffer space\n"); return -1; } iLBC_decode(tmpf, plc_mode ? f->data.ptr + x : NULL, &tmp->dec, plc_mode); - for ( i=0; i < ILBC_SAMPLES; i++) + for (i = 0; i < samples_per_frame; i++) dst[pvt->samples + i] = tmpf[i]; - pvt->samples += ILBC_SAMPLES; - pvt->datalen += 2*ILBC_SAMPLES; + pvt->samples += samples_per_frame; + pvt->datalen += samples_per_frame * 2; } return 0; } @@ -155,20 +169,26 @@ static struct ast_frame *lintoilbc_frameout(struct ast_trans_pvt *pvt) struct ast_frame *last = NULL; int samples = 0; /* output samples */ - while (pvt->samples >= ILBC_SAMPLES) { + struct ilbc_attr *attr = ast_format_get_attribute_data(pvt->f.subclass.format); + const unsigned int mode = attr ? attr->mode : 30; + const unsigned int sample_rate = pvt->t->dst_codec.sample_rate; + const unsigned int samples_per_frame = mode * sample_rate / 1000; + const unsigned int octets_per_frame = (mode == 20) ? 38 : 50; + + while (pvt->samples >= samples_per_frame) { struct ast_frame *current; - ilbc_block tmpf[ILBC_SAMPLES]; + ilbc_block tmpf[samples_per_frame]; int i; /* Encode a frame of data */ - for (i = 0 ; i < ILBC_SAMPLES ; i++) + for (i = 0; i < samples_per_frame; i++) tmpf[i] = tmp->buf[samples + i]; iLBC_encode((ilbc_bytes *) pvt->outbuf.BUF_TYPE, tmpf, &tmp->enc); - samples += ILBC_SAMPLES; - pvt->samples -= ILBC_SAMPLES; + samples += samples_per_frame; + pvt->samples -= samples_per_frame; - current = ast_trans_frameout(pvt, ILBC_FRAME_LEN, ILBC_SAMPLES); + current = ast_trans_frameout(pvt, octets_per_frame, samples_per_frame); if (!current) { continue; } else if (last) { @@ -226,7 +246,8 @@ static struct ast_translator lintoilbc = { .frameout = lintoilbc_frameout, .sample = slin8_sample, .desc_size = sizeof(struct ilbc_coder_pvt), - .buf_size = (BUFFER_SAMPLES * ILBC_FRAME_LEN + ILBC_SAMPLES - 1) / ILBC_SAMPLES, + /* frame len (38 bytes), frame size (160 samples), ceil (+ 160 - 1) */ + .buf_size = (BUFFER_SAMPLES * 38 + 160 - 1) / 160, }; static int unload_module(void) diff --git a/codecs/ex_ilbc.h b/codecs/ex_ilbc.h index 3a79b091816..3fe2749dde0 100644 --- a/codecs/ex_ilbc.h +++ b/codecs/ex_ilbc.h @@ -7,6 +7,9 @@ * */ +#include "asterisk/format_cache.h" /* for ast_format_ilbc */ +#include "asterisk/frame.h" /* for ast_frame, etc */ + static uint8_t ex_ilbc[] = { 0xff, 0xa0, 0xff, 0xfa, 0x0f, 0x60, 0x12, 0x11, 0xa2, 0x47, 0x22, 0x8c, 0x00, 0x00, 0x01, 0x02, 0x80, 0x43, 0xa0, 0x40, @@ -20,8 +23,8 @@ static struct ast_frame *ilbc_sample(void) static struct ast_frame f = { .frametype = AST_FRAME_VOICE, .datalen = sizeof(ex_ilbc), - /* All frames are 30 ms long */ - .samples = ILBC_SAMPLES, + /* example frames are default long (30 ms) */ + .samples = 240, .mallocd = 0, .offset = 0, .src = __PRETTY_FUNCTION__, diff --git a/include/asterisk/ilbc.h b/include/asterisk/ilbc.h new file mode 100644 index 00000000000..2534367cda3 --- /dev/null +++ b/include/asterisk/ilbc.h @@ -0,0 +1,8 @@ +#ifndef _AST_FORMAT_ILBC_H_ +#define _AST_FORMAT_ILBC_H_ + +struct ilbc_attr { + unsigned int mode; +}; + +#endif /* _AST_FORMAT_ILBC_H */ \ No newline at end of file diff --git a/main/codec_builtin.c b/main/codec_builtin.c index 50fbf555c03..15147980dbb 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -31,6 +31,7 @@ ASTERISK_REGISTER_FILE() +#include "asterisk/ilbc.h" #include "asterisk/logger.h" #include "asterisk/astobj2.h" #include "asterisk/codec.h" @@ -588,7 +589,12 @@ static struct ast_codec speex32 = { static int ilbc_samples(struct ast_frame *frame) { - return 240 * (frame->datalen / 50); + struct ilbc_attr *attr = ast_format_get_attribute_data(frame->subclass.format); + const unsigned int mode = attr ? attr->mode : 30; + const unsigned int samples_per_frame = mode * ast_format_get_sample_rate(frame->subclass.format) / 1000; + const unsigned int octets_per_frame = (mode == 20) ? 38 : 50; + + return samples_per_frame * frame->datalen / octets_per_frame; } static struct ast_codec ilbc = { @@ -596,12 +602,12 @@ static struct ast_codec ilbc = { .description = "iLBC", .type = AST_MEDIA_TYPE_AUDIO, .sample_rate = 8000, - .minimum_ms = 30, + .minimum_ms = 20, .maximum_ms = 300, - .default_ms = 30, - .minimum_bytes = 50, + .default_ms = 20, + .minimum_bytes = 38, .samples_count = ilbc_samples, - .smooth = 1, + .smooth = 0, }; static struct ast_codec g722 = { diff --git a/res/res_format_attr_ilbc.c b/res/res_format_attr_ilbc.c new file mode 100644 index 00000000000..0fac55cb0c7 --- /dev/null +++ b/res/res_format_attr_ilbc.c @@ -0,0 +1,172 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Alexander Traud + * + * Alexander Traud + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief iLBC format attribute interface + * + * \author Alexander Traud + * + * \note http://tools.ietf.org/html/rfc3952 + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +#include "asterisk/module.h" +#include "asterisk/format.h" +#include "asterisk/strings.h" /* for ast_str_append */ +#include "asterisk/utils.h" /* for ast_calloc, ast_free */ + +#include "asterisk/ilbc.h" + +static struct ilbc_attr default_ilbc_attr = { + .mode = 20, +}; + +static void ilbc_destroy(struct ast_format *format) +{ + struct ilbc_attr *attr = ast_format_get_attribute_data(format); + + ast_free(attr); +} + +static int ilbc_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct ilbc_attr *original = ast_format_get_attribute_data(src); + struct ilbc_attr *attr = ast_malloc(sizeof(*attr)); + + if (!attr) { + return -1; + } + + if (original) { + *attr = *original; + } else { + *attr = default_ilbc_attr; + } + + ast_format_set_attribute_data(dst, attr); + + return 0; +} + +static struct ast_format *ilbc_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + struct ast_format *cloned; + struct ilbc_attr *attr; + const char *kvp; + unsigned int val; + + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + if ((kvp = strstr(attributes, "mode")) && sscanf(kvp, "mode=%30u", &val) == 1) { + attr->mode = val; + } else { + attr->mode = 30; /* optional attribute; 30 is default value */ + } + + return cloned; +} + +static void ilbc_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) +{ + struct ilbc_attr *attr = ast_format_get_attribute_data(format); + + if (!attr) { + attr = &default_ilbc_attr; + } + + /* When the VoIP/SIP client Zoiper calls Asterisk and its + * iLBC 20 is disabled but iLBC 30 enabled, Zoiper still + * falls back to iLBC 20, when there is no mode=30 in the + * answer. Consequently, Zoiper defaults to iLBC 20. To + * make that client happy, Asterisk sends mode always. + * tested in June 2016, Zoiper Premium 1.13.2 for iPhone + */ + /* if (attr->mode != 30) */ { + ast_str_append(str, 0, "a=fmtp:%u mode=%u\r\n", payload, attr->mode); + } +} + +static struct ast_format *ilbc_getjoint(const struct ast_format *format1, const struct ast_format *format2) +{ + struct ast_format *jointformat; + struct ilbc_attr *attr1 = ast_format_get_attribute_data(format1); + struct ilbc_attr *attr2 = ast_format_get_attribute_data(format2); + struct ilbc_attr *attr_res; + + if (!attr1) { + attr1 = &default_ilbc_attr; + } + + if (!attr2) { + attr2 = &default_ilbc_attr; + } + + jointformat = ast_format_clone(format1); + if (!jointformat) { + return NULL; + } + attr_res = ast_format_get_attribute_data(jointformat); + + if (attr1->mode != attr2->mode) { + attr_res->mode = 30; + } + + return jointformat; +} + +static struct ast_format_interface ilbc_interface = { + .format_destroy = ilbc_destroy, + .format_clone = ilbc_clone, + .format_cmp = NULL, + .format_get_joint = ilbc_getjoint, + .format_attribute_set = NULL, + .format_parse_sdp_fmtp = ilbc_parse_sdp_fmtp, + .format_generate_sdp_fmtp = ilbc_generate_sdp_fmtp, +}; + +static int load_module(void) +{ + if (ast_format_interface_register("ilbc", &ilbc_interface)) { + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, + "iLBC Format Attribute Module", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND, +); From 9be69c163632e485934ce9ca697babc10c6ea896 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 19 Jul 2016 13:16:02 +0200 Subject: [PATCH 0596/1578] chan_sip: Enable Session-Timers for SIP over TCP (and TLS). Asterisk defaults to timers=accept/refresher=uas. In that scenario, only in that scenario, Sessions-Timers (RFC 4028) had no effect via TCP. This change enables Session-Timers for SIP over TCP (and for SIP over TLS). However with longer international calls via TCP, the SIP channel might break, because all hops on the Internet route must stay online (have not a single power outage, for example). Therefore with Session-Timers enabled (which are enabled at default), you might see dropped calls. Consequently even with this change, you might be better-off going for session-timers=refuse in your sip.conf. ASTERISK-19968 #close Change-Id: I1cd33453c77c56c8e1394cd60a6f17bb61c1d957 --- CHANGES | 8 +++++++ channels/chan_sip.c | 52 +++++++++++++++++---------------------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/CHANGES b/CHANGES index 9caa524226a..6d7cb4c4238 100644 --- a/CHANGES +++ b/CHANGES @@ -177,6 +177,14 @@ chan_sip NOTE: This is again separated by an exclamation mark, so the To: header may not contain one of those. + * Session-Timers (RFC 4028) work for TCP (and TLS) transports as well now. + Previously Asterisk dropped calls only with UDP transports. However with + longer international calls via TCP, the SIP channel might break, because + all hops on the Internet route must stay online (have not a single power + outage, for example). Therefore with Session-Timers enabled (which are + enabled at default), you might see additional dropped calls. Consequently + please, consider to go for session-timers=refuse in your sip.conf. + chan_pjsip ------------------ * New 'user_eq_phone' endpoint setting. This adds a 'user=phone' parameter diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b2522b6db79..9098c14e58a 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -4204,19 +4204,6 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in p->pendinginvite = seqno; } - /* If the transport is something reliable (TCP or TLS) then don't really send this reliably */ - /* I removed the code from retrans_pkt that does the same thing so it doesn't get loaded into the scheduler */ - /*! \todo According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */ - if (!(p->socket.type & AST_TRANSPORT_UDP)) { - xmitres = __sip_xmit(p, data); /* Send packet */ - if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */ - append_history(p, "XmitErr", "%s", fatal ? "(Critical)" : "(Non-critical)"); - return AST_FAILURE; - } else { - return AST_SUCCESS; - } - } - pkt = ao2_alloc_options(sizeof(*pkt), sip_pkt_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!pkt) { return AST_FAILURE; @@ -4253,6 +4240,10 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in pkt->time_sent = ast_tvnow(); /* time packet was sent */ pkt->retrans_stop_time = 64 * (pkt->timer_t1 ? pkt->timer_t1 : DEFAULT_TIMER_T1); /* time in ms after pkt->time_sent to stop retransmission */ + if (!(p->socket.type & AST_TRANSPORT_UDP)) { + pkt->retrans_stop = 1; + } + /* Schedule retransmission */ ao2_t_ref(pkt, +1, "Schedule packet retransmission"); pkt->retransid = ast_sched_add_variable(sched, siptimer_a, retrans_pkt, pkt, 1); @@ -24629,6 +24620,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc char *c_copy = ast_strdupa(c); /* Skip the Cseq and its subsequent spaces */ const char *msg = ast_skip_blanks(ast_skip_nonblanks(c_copy)); + int ack_res = FALSE; if (!msg) msg = ""; @@ -24643,28 +24635,24 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc } } - if (p->socket.type == AST_TRANSPORT_UDP) { - int ack_res = FALSE; - - /* Acknowledge whatever it is destined for */ - if ((resp >= 100) && (resp <= 199)) { - /* NON-INVITE messages do not ack a 1XX response. RFC 3261 section 17.1.2.2 */ - if (sipmethod == SIP_INVITE) { - ack_res = __sip_semi_ack(p, seqno, 0, sipmethod); - } - } else { - ack_res = __sip_ack(p, seqno, 0, sipmethod); + /* Acknowledge whatever it is destined for */ + if ((resp >= 100) && (resp <= 199)) { + /* NON-INVITE messages do not ack a 1XX response. RFC 3261 section 17.1.2.2 */ + if (sipmethod == SIP_INVITE) { + ack_res = __sip_semi_ack(p, seqno, 0, sipmethod); } + } else { + ack_res = __sip_ack(p, seqno, 0, sipmethod); + } - if (ack_res == FALSE) { - /* RFC 3261 13.2.2.4 and 17.1.1.2 - We must re-send ACKs to re-transmitted final responses */ - if (sipmethod == SIP_INVITE && resp >= 200) { - transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, resp < 300 ? TRUE: FALSE); - } - - append_history(p, "Ignore", "Ignoring this retransmit\n"); - return; + if (ack_res == FALSE) { + /* RFC 3261 13.2.2.4 and 17.1.1.2 - We must re-send ACKs to re-transmitted final responses */ + if (sipmethod == SIP_INVITE && resp >= 200) { + transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, resp < 300 ? TRUE: FALSE); } + + append_history(p, "Ignore", "Ignoring this retransmit\n"); + return; } /* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */ From 76781a0964d43731153db5b3fb8b78fafc7467d7 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 22 Jul 2016 14:44:50 -0500 Subject: [PATCH 0597/1578] Fix sqlalchemy error regarding identifier length. sqlalchemy was complaining: sqlalchemy.exc.IdentifierError: Identifier 'ps_contacts_qualifyfreq_exptime' exceeds maximum length of 30 characters This fixes the problem by changing the index name to be "ps_contacts_qualifyfreq_exp" instead. ASTERISK-26227 #close Reported by Mark Michelson Change-Id: I0ed784f87504be2a59ee8d3242ef6f625d5ed1a9 --- .../ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py b/contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py index ff18343290d..43d4028f2b0 100644 --- a/contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py +++ b/contrib/ast-db-manage/config/versions/ef7efc2d3964_ps_contacts_add_endpoint_and_modify_.py @@ -24,10 +24,10 @@ def upgrade(): else: op.execute('ALTER TABLE ps_contacts ALTER COLUMN expiration_time TYPE BIGINT USING expiration_time::bigint') - op.create_index('ps_contacts_qualifyfreq_exptime', 'ps_contacts', ['qualify_frequency', 'expiration_time']) + op.create_index('ps_contacts_qualifyfreq_exp', 'ps_contacts', ['qualify_frequency', 'expiration_time']) op.create_index('ps_aors_qualifyfreq_contact', 'ps_aors', ['qualify_frequency', 'contact']) def downgrade(): op.drop_index('ps_aors_qualifyfreq_contact') - op.drop_index('ps_contacts_qualifyfreq_exptime') + op.drop_index('ps_contacts_qualifyfreq_exp') op.drop_column('ps_contacts', 'endpoint') op.alter_column('ps_contacts', 'expiration_time', type_=sa.String(40)) From 8852a4c3db7868c9779a747070499525d2c0e583 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 23 Jul 2016 07:51:48 -0600 Subject: [PATCH 0598/1578] asterisk.c: Add auto generation and persistence of UUID Upcoming features will require the generation and persistence of a UUID. Change-Id: I3ec0062427e133217db6ef496a4216f427c3b92d --- include/asterisk.h | 7 +++++++ main/asterisk.c | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/include/asterisk.h b/include/asterisk.h index ab2a3ddef31..e509fbc39e0 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -288,4 +288,11 @@ struct ast_module *AST_MODULE_SELF_SYM(void); #endif +/*! + * \brief Retrieve the PBX UUID + * \param pbx_uuid A buffer of at least AST_UUID_STR_LEN (36 + 1) size to receive the UUID + * \param length The buffer length + */ +int ast_pbx_uuid_get(char *pbx_uuid, int length); + #endif /* _ASTERISK_H */ diff --git a/main/asterisk.c b/main/asterisk.c index 95f1b3ed035..850003b0564 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -249,6 +249,7 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/codec.h" #include "asterisk/format_cache.h" #include "asterisk/media_cache.h" +#include "asterisk/astdb.h" #include "../defaults.h" @@ -590,6 +591,11 @@ void ast_unregister_thread(void *id) } } +int ast_pbx_uuid_get(char *pbx_uuid, int length) +{ + return ast_db_get("pbx", "UUID", pbx_uuid, length); +} + /*! \brief Give an overview of core settings */ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { @@ -597,6 +603,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c struct ast_tm tm; char eid_str[128]; struct rlimit limits; + char pbx_uuid[AST_UUID_STR_LEN]; switch (cmd) { case CLI_INIT: @@ -609,6 +616,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c } ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default); + ast_pbx_uuid_get(pbx_uuid, sizeof(pbx_uuid)); ast_cli(a->fd, "\nPBX Core settings\n"); ast_cli(a->fd, "-----------------\n"); @@ -647,6 +655,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c ast_cli(a->fd, " System: %s/%s built by %s on %s %s\n", ast_build_os, ast_build_kernel, ast_build_user, ast_build_machine, ast_build_date); ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME); ast_cli(a->fd, " Entity ID: %s\n", eid_str); + ast_cli(a->fd, " PBX UUID: %s\n", pbx_uuid); ast_cli(a->fd, " Default language: %s\n", ast_defaultlanguage); ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled"); ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP); @@ -4250,6 +4259,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou int num; char *buf; int moduleresult; /*!< Result from the module load subsystem */ + char pbx_uuid[AST_UUID_STR_LEN]; /* Set time as soon as possible */ ast_lastreloadtime = ast_startuptime = ast_tvnow(); @@ -4358,6 +4368,24 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou ast_el_read_default_histfile(); } +#ifdef AST_XML_DOCS + /* Load XML documentation. */ + ast_xmldoc_load_documentation(); +#endif + + if (astdb_init()) { + printf("Failed: astdb_init\n%s", term_quit()); + exit(1); + } + + ast_uuid_init(); + + if (ast_pbx_uuid_get(pbx_uuid, sizeof(pbx_uuid))) { + ast_uuid_generate_str(pbx_uuid, sizeof(pbx_uuid)); + ast_db_put("pbx", "UUID", pbx_uuid); + } + ast_verb(0, "PBX UUID: %s\n", pbx_uuid); + ast_json_init(); ast_ulaw_init(); ast_alaw_init(); @@ -4398,7 +4426,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou } ast_aoc_cli_init(); - ast_uuid_init(); if (ast_sorcery_init()) { printf("Failed: ast_sorcery_init\n%s", term_quit()); @@ -4425,11 +4452,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou exit(1); } -#ifdef AST_XML_DOCS - /* Load XML documentation. */ - ast_xmldoc_load_documentation(); -#endif - aco_init(); if (init_logger()) { /* Start logging subsystem */ @@ -4513,11 +4535,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou exit(1); } - if (astdb_init()) { - printf("Failed: astdb_init\n%s", term_quit()); - exit(1); - } - if (ast_msg_init()) { printf("Failed: ast_msg_init\n%s", term_quit()); exit(1); From 9db420c69d170528ee20646c5d47d8ee3ea01a30 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 24 Jul 2016 18:51:25 -0300 Subject: [PATCH 0599/1578] ari: Update version. New functionality has been added so the version has been bumped to one over the 13 version. Change-Id: I5d30077f62640c0ac83599b4e9a9b657bf184f69 --- rest-api/resources.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-api/resources.json b/rest-api/resources.json index 4a098f51f0a..ecaf723b601 100644 --- a/rest-api/resources.json +++ b/rest-api/resources.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "1.10.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "apis": [ From b4c5dcad014909310dd7a5b6112ca3c9fbb8692c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 24 Jul 2016 17:27:26 -0600 Subject: [PATCH 0600/1578] menuselect: Various menuselect enhancements * Add 'external' as a support level. * Add ability for module directories to add entries to the menu by adding members to the /.xml file. * Expand the description field to 3 lines in the ncurses implementation. * Allow the description field to wrap in the newt implementation. * Add description field to the gtk implementation. Change-Id: I7f9600a1984a42ce0696db574c1051bc9ad7c808 --- Makefile.moddir_rules | 2 +- Makefile.rules | 4 +++ menuselect/menuselect.c | 6 ++++ menuselect/menuselect.h | 3 +- menuselect/menuselect_curses.c | 61 ++++++++++++++++++---------------- menuselect/menuselect_gtk.c | 11 +++++- menuselect/menuselect_newt.c | 2 +- 7 files changed, 56 insertions(+), 33 deletions(-) diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules index a92b0d82580..9b5f3f13a27 100644 --- a/Makefile.moddir_rules +++ b/Makefile.moddir_rules @@ -164,7 +164,7 @@ dist-clean:: $(AWK) -f $(ASTTOPDIR)/build_tools/get_moduleinfo $^ >> $@ echo "" >> $@ -.moduleinfo:: $(addsuffix .moduleinfo,$(addprefix .,$(sort $(ALL_C_MODS) $(ALL_CC_MODS)))) +.moduleinfo:: $(addsuffix .moduleinfo,$(addprefix .,$(sort $(ALL_C_MODS) $(ALL_CC_MODS)))) $(wildcard $(call tolower,$(MENUSELECT_CATEGORY)).xml) @echo "" > $@ @cat $^ >> $@ @echo "" >> $@ diff --git a/Makefile.rules b/Makefile.rules index a22f19c16bc..45989d6843e 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -17,6 +17,10 @@ -include $(ASTTOPDIR)/makeopts +# Helpful functions +# call with $(call function,...) +tolower = $(shell echo $(1) | tr '[:upper:]' '[:lower:]') + .PHONY: dist-clean # If 'make' decides to create intermediate files to satisfy a build requirement diff --git a/menuselect/menuselect.c b/menuselect/menuselect.c index 6136135aa58..efae311bb7a 100644 --- a/menuselect/menuselect.c +++ b/menuselect/menuselect.c @@ -246,6 +246,10 @@ static enum support_level_values string_to_support_level(const char *support_lev return SUPPORT_DEPRECATED; } + if (!strcasecmp(support_level, "external")) { + return SUPPORT_EXTERNAL; + } + return SUPPORT_UNSPECIFIED; } @@ -259,6 +263,8 @@ static const char *support_level_to_string(enum support_level_values support_lev return "Extended"; case SUPPORT_DEPRECATED: return "Deprecated"; + case SUPPORT_EXTERNAL: + return "External"; default: return "Unspecified"; } diff --git a/menuselect/menuselect.h b/menuselect/menuselect.h index 112f1c88cba..7b3fe26567c 100644 --- a/menuselect/menuselect.h +++ b/menuselect/menuselect.h @@ -105,7 +105,8 @@ enum support_level_values { SUPPORT_EXTENDED = 1, SUPPORT_DEPRECATED = 2, SUPPORT_UNSPECIFIED = 3, - SUPPORT_COUNT = 4, /* Keep this item at the end of the list. Tracks total number of support levels. */ + SUPPORT_EXTERNAL = 4, + SUPPORT_COUNT = 5, /* Keep this item at the end of the list. Tracks total number of support levels. */ }; AST_LIST_HEAD_NOLOCK(support_level_bucket, member); diff --git a/menuselect/menuselect_curses.c b/menuselect/menuselect_curses.c index 00645927ad4..e79957485f1 100644 --- a/menuselect/menuselect_curses.c +++ b/menuselect/menuselect_curses.c @@ -194,46 +194,49 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start_y, int int start_x = (max_x / 2 - MEMBER_INFO_LEFT_ADJ); int maxlen = (max_x - start_x); - wmove(menu, end - start_y + 1, start_x); + wmove(menu, end - start_y + 1, 0); wclrtoeol(menu); - wmove(menu, end - start_y + 2, start_x); + wmove(menu, end - start_y + 2, 0); wclrtoeol(menu); - wmove(menu, end - start_y + 3, start_x); + wmove(menu, end - start_y + 3, 0); wclrtoeol(menu); - wmove(menu, end - start_y + 4, start_x); + wmove(menu, end - start_y + 4, 0); wclrtoeol(menu); - wmove(menu, end - start_y + 5, start_x); + wmove(menu, end - start_y + 5, 0); wclrtoeol(menu); - wmove(menu, end - start_y + 6, start_x); + wmove(menu, end - start_y + 6, 0); + wclrtoeol(menu); + wmove(menu, end - start_y + 7, 0); wclrtoeol(menu); if (mem->displayname) { - int name_len = strlen(mem->displayname); + char buf[maxlen + 1]; + char *displayname = strdupa(mem->displayname); + char *word; + int current_line = 1; + int new_line = 1; + buf[0] = '\0'; wmove(menu, end - start_y + 1, start_x); - if (name_len > maxlen) { - char *last_space; - char *line_1 = strdup(mem->displayname); - - if (line_1) { - line_1[maxlen] = '\0'; - last_space = strrchr(line_1, ' '); - if (last_space) { - *last_space = '\0'; - } - waddstr(menu, line_1); - wmove(menu, end - start_y + 2, start_x); - waddstr(menu, &mem->displayname[last_space - line_1]); - free(line_1); - } else { - waddstr(menu, (char *) mem->displayname); + + while ((word = strsep(&displayname, " "))) { + if ((strlen(buf) + strlen(word) + 1) > maxlen) { + waddstr(menu, buf); + current_line++; + wmove(menu, end - start_y + current_line, start_x); + buf[0] = '\0'; + new_line = 1; } - } else { - waddstr(menu, (char *) mem->displayname); + sprintf(buf, "%s%*.*s%s", buf, new_line ? 0 : 1, new_line ? 0 : 1, " ", word); + new_line = 0; + } + if (strlen(buf)) { + waddstr(menu, buf); } } + if (!AST_LIST_EMPTY(&mem->deps)) { - wmove(menu, end - start_y + 3, start_x); + wmove(menu, end - start_y + 4, start_x); strcpy(buf, "Depends on: "); AST_LIST_TRAVERSE(&mem->deps, dep, list) { strncat(buf, dep->displayname, sizeof(buf) - strlen(buf) - 1); @@ -244,7 +247,7 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start_y, int waddstr(menu, buf); } if (!AST_LIST_EMPTY(&mem->uses)) { - wmove(menu, end - start_y + 4, start_x); + wmove(menu, end - start_y + 5, start_x); strcpy(buf, "Can use: "); AST_LIST_TRAVERSE(&mem->uses, use, list) { strncat(buf, use->displayname, sizeof(buf) - strlen(buf) - 1); @@ -255,7 +258,7 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start_y, int waddstr(menu, buf); } if (!AST_LIST_EMPTY(&mem->conflicts)) { - wmove(menu, end - start_y + 5, start_x); + wmove(menu, end - start_y + 6, start_x); strcpy(buf, "Conflicts with: "); AST_LIST_TRAVERSE(&mem->conflicts, con, list) { strncat(buf, con->displayname, sizeof(buf) - strlen(buf) - 1); @@ -268,7 +271,7 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start_y, int if (!mem->is_separator) { /* Separators lack support levels */ { /* support level */ - wmove(menu, end - start_y + 6, start_x); + wmove(menu, end - start_y + 7, start_x); snprintf(buf, sizeof(buf), "Support Level: %s", mem->support_level); if (mem->replacement && *mem->replacement) { char buf2[64]; diff --git a/menuselect/menuselect_gtk.c b/menuselect/menuselect_gtk.c index cd31b3580a4..9379d7de616 100644 --- a/menuselect/menuselect_gtk.c +++ b/menuselect/menuselect_gtk.c @@ -16,6 +16,8 @@ enum { COLUMN_USES, /*! Conflicts */ COLUMN_CNFS, + /*! Description */ + COLUMN_DESC, /*! Number of columns, must be the last element in the enum */ NUM_COLUMNS, }; @@ -254,7 +256,8 @@ int run_menu(void) G_TYPE_BOOLEAN, /* COLUMN_SELECTED */ G_TYPE_STRING, /* COLUMN_DEPS */ G_TYPE_STRING, /* COLUMN_USES */ - G_TYPE_STRING); /* COLUMN_CNFS */ + G_TYPE_STRING, /* COLUMN_CNFS */ + G_TYPE_STRING); /* COLUMN_DESC */ AST_LIST_TRAVERSE(&categories, cat, list) { GtkTreeIter iter, iter2; @@ -307,6 +310,7 @@ int run_menu(void) COLUMN_DEPS, dep_buf, COLUMN_USES, use_buf, COLUMN_CNFS, cnf_buf, + COLUMN_DESC, mem->displayname, -1); } } @@ -344,6 +348,11 @@ int run_menu(void) renderer, "text", COLUMN_CNFS, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("Description", + renderer, "text", COLUMN_DESC, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); + g_signal_connect(tree, "row-activated", (GCallback) row_activated_handler, store); gtk_container_add(GTK_CONTAINER(s_window), GTK_WIDGET(tree)); diff --git a/menuselect/menuselect_newt.c b/menuselect/menuselect_newt.c index fca55878158..bc03f9b1b57 100644 --- a/menuselect/menuselect_newt.c +++ b/menuselect/menuselect_newt.c @@ -326,7 +326,7 @@ int run_menu(void) newtFormAddComponent(form, subOptions); newtComponentAddCallback(subOptions, category_menu_callback, NULL); - memberNameTextbox = newtTextbox(2, y - 13, x - 10, 1, 0); + memberNameTextbox = newtTextbox(2, y - 13, x - 10, 2, NEWT_FLAG_WRAP); dependsLabel = newtLabel(2, y - 11, " Depends on:"); usesLabel = newtLabel(2, y - 10, " Can use:"); conflictsLabel = newtLabel(2, y - 9, "Conflicts with:"); From 49461f37b75aa27275d1c4811007e2a7f94ac002 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 21 Jul 2016 22:28:25 -0500 Subject: [PATCH 0601/1578] dsp.c: Fix erroneous fax tone detection. The Goertzel calculations get less accurate the lower the signal level being worked with becomes because there is less resolution remaining. If it is too low we can erroneously detect a tone where none really exists. The searched for fax frequencies not only need to be so much stronger than the background noise they must also be a minimum strength. * Add needed minimum threshold test to tone_detect(). * Set TONE_THRESHOLD to allow low volume frequency spread detection. ASTERISK-26237 #close Reported by: Richard Mudgett Change-Id: I84dbba7f7628fa13720add6a88eae3b129e066fc --- main/dsp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/main/dsp.c b/main/dsp.c index 193bf9fd502..f043ff9d1a3 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -171,8 +171,7 @@ enum gsamp_thresh { */ #define DTMF_THRESHOLD 8.0e7 -#define FAX_THRESHOLD 8.0e7 -#define FAX_2ND_HARMONIC 2.0 /* 4dB */ +#define TONE_THRESHOLD 7.8e7 #define DEF_DTMF_NORMAL_TWIST 6.31 /* 8.0dB */ #define DEF_RELAX_DTMF_NORMAL_TWIST 6.31 /* 8.0dB */ @@ -187,8 +186,6 @@ enum gsamp_thresh { #define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ #define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ -#define DTMF_2ND_HARMONIC_ROW (relax ? 1.7 : 2.5) /* 4dB normal */ -#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ #define DTMF_TO_TOTAL_ENERGY 42.0 #define BELL_MF_THRESHOLD 1.6e9 @@ -583,7 +580,8 @@ static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp ast_debug(10, "tone %d, Ew=%.2E, Et=%.2E, s/n=%10.2f\n", s->freq, tone_energy, s->energy, tone_energy / (s->energy - tone_energy)); hit = 0; - if (tone_energy > s->energy * s->threshold) { + if (TONE_THRESHOLD <= tone_energy + && tone_energy > s->energy * s->threshold) { ast_debug(10, "Hit! count=%d\n", s->hit_count); hit = 1; } From 1e7168aee0fe34b1a99ade151ee6edd3b419da85 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 22 Jul 2016 06:43:20 -0300 Subject: [PATCH 0602/1578] astconfigparser.py: Update with realtime fixes. When configuring SIP URIs in the pjsip.conf file it is necessary to escape the semicolon so the parser does not treat it as a comment. This change allows this to work in the astconfigparser implementation. A secondary bug where some data was lost if a configuration option included a "=" in its value was also fixed. A bug where sections would be considered equal despite being different has also been fixed. Change-Id: If229f656ef22050b50e7b34e90c4bffe796431f8 --- .../scripts/sip_to_pjsip/astconfigparser.py | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/astconfigparser.py b/contrib/scripts/sip_to_pjsip/astconfigparser.py index b207b0d7c03..46f4fb484b2 100644 --- a/contrib/scripts/sip_to_pjsip/astconfigparser.py +++ b/contrib/scripts/sip_to_pjsip/astconfigparser.py @@ -1,3 +1,10 @@ +""" +Copyright (C) 2016, Digium, Inc. + +This program is free software, distributed under the terms of +the GNU General Public License Version 2. +""" + import re import itertools @@ -44,6 +51,12 @@ def __cmp__(self, other): """ return cmp(self.id, other.id) + def __eq__(self, other): + """ + Use self.id as means of determining equality + """ + return self.id == other.id + def get(self, key, from_self=True, from_templates=True, from_defaults=True): """ @@ -184,9 +197,14 @@ def remove_comment(line, is_comment): # otherwise it was an embedded comment so combine return ''.join([part[0].strip(), ' ', line]).rstrip(), False - # check for eol comment - return line.partition(COMMENT)[0].strip(), False + # find the first occurence of a comment that is not escaped + match = re.match(r'.*?([^\\];)', line) + + if match: + # the end of where the real string is is where the comment starts + line = line[0:(match.end()-1)] + return line.replace("\\", "").strip(), False def try_include(line): """ @@ -224,7 +242,7 @@ def try_section(line): def try_option(line): """Parses the line as an option, returning the key/value pair.""" - data = re.split('=>?', line) + data = re.split('=>?', line, 1) # should split in two (key/val), but either way use first two elements return data[0].rstrip(), data[1].lstrip() From 327136088e3aba15b1b2e2282df3a0409f740a7f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 25 Jul 2016 21:18:21 -0500 Subject: [PATCH 0603/1578] dsp.c: Correct DTMF twist dsp.conf documentation. Change-Id: Idf97e3a72f1edc5fca58f2fa7b20785922be0cae --- configs/samples/dsp.conf.sample | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/configs/samples/dsp.conf.sample b/configs/samples/dsp.conf.sample index 08c5a5715d0..55951582e3d 100644 --- a/configs/samples/dsp.conf.sample +++ b/configs/samples/dsp.conf.sample @@ -8,28 +8,28 @@ ; DTMF Reverse Twist and Normal Twist is the difference in power between the row and column energies. ; -; Normal Twist is where the Column energy is greater than the Row energy -; Reverse Twist is where the Row energy is greater. +; Normal Twist is where the row energy is greater than the column energy. +; Reverse Twist is where the column energy is greater. ; ; Power level difference between frequencies for different Administrations/RPOAs -; Power Gain equiv -; normal reverse dB's -; AT&T(default) 6.31 2.51 8dB(normal), 4dB(reverse) -; NTT 3.16 3.16 Max. 5dB -; Danish 3.98 3.98 Max. 6dB -; Australian 10.0 10.0 Max. 10dB -; Brazilian 7.94 7.94 Max. 9dB -; ETSI 3.98 3.98 Max. 6dB +; Power Gain equiv +; normal reverse dB's +; AT&T(default) 6.31 2.51 8dB(normal), 4dB(reverse) +; NTT 3.16 3.16 Max. 5dB +; Danish 3.98 3.98 Max. 6dB +; Australian 10.0 10.0 Max. 10dB +; Brazilian 7.94 7.94 Max. 9dB +; ETSI 3.98 3.98 Max. 6dB ;previous version compatible AT&T values ; RADIO_RELAX disabled, and relaxdtmf=no -; 6.30 2.50 7.99dB(normal), 3.98dB(reverse) +; 6.30 2.50 7.99dB(normal), 3.98dB(reverse) ; RADIO_RELAX disabled, and relaxdtmf=yes -; 6.30 4.00 7.99dB(normal), 6.02dB(reverse) +; 6.30 4.00 7.99dB(normal), 6.02dB(reverse) ; RADIO_RELAX enabled, and relaxdtmf=no -; 6.30 2.50 7.99dB(normal), 3.984dB(reverse) +; 6.30 2.50 7.99dB(normal), 3.984dB(reverse) ; RADIO_RELAX enabled, and relaxdtmf=yes -; 6.30 6.50 7.99dB(normal), 8.13dB(reverse) +; 6.30 6.50 7.99dB(normal), 8.13dB(reverse) ;If you don't know what these mean, don't change them. ;dtmf_normal_twist=6.31 From 6dfb34cf138c1b7557cbe3f0265c9359cf0869a8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Jul 2016 13:48:25 -0500 Subject: [PATCH 0604/1578] dsp.c: Fix incorrect format reference typo. Change-Id: Ia131da3ec29acf385cb43a586a29ecc975eb3896 --- main/dsp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main/dsp.c b/main/dsp.c index f043ff9d1a3..cbbf6960a51 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -200,7 +200,7 @@ enum gsamp_thresh { * followed by a 3 second silent (2100 Hz OFF) period. */ #define FAX_TONE_CNG_FREQ 1100 -#define FAX_TONE_CNG_DURATION 500 +#define FAX_TONE_CNG_DURATION 500 /* ms */ #define FAX_TONE_CNG_DB 16 /* This signal may be sent by the Terminating FAX machine anywhere between @@ -208,7 +208,7 @@ enum gsamp_thresh { * of a 2100 Hz tone that is from 2.6 to 4 seconds in duration. */ #define FAX_TONE_CED_FREQ 2100 -#define FAX_TONE_CED_DURATION 2600 +#define FAX_TONE_CED_DURATION 2600 /* ms */ #define FAX_TONE_CED_DB 16 #define DEFAULT_SAMPLE_RATE 8000 @@ -601,7 +601,7 @@ static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp } if (s->hit_count == s->hits_required) { - ast_debug(1, "%d Hz done detected\n", s->freq); + ast_debug(1, "%d Hz tone detected\n", s->freq); res = 1; } @@ -1620,7 +1620,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, for (x = 0; x < len; x++) { odata[x] = AST_LIN2MU((unsigned short) shortdata[x]); } - } else if (ast_format_cmp(af->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { + } else if (ast_format_cmp(af->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { for (x = 0; x < len; x++) { odata[x] = AST_LIN2A((unsigned short) shortdata[x]); } From a8cd5d255a5d1abf8a91192fe9690eea94a96bae Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 21 Jul 2016 11:56:53 -0500 Subject: [PATCH 0605/1578] dsp.c: Added descriptive comments to Goertzel calculations. * Added doxygen to describe some struct members and what is going on in the code. Change-Id: I2ec706a33b52aee42b16dcc356c2bd916a45190d --- main/dsp.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/main/dsp.c b/main/dsp.c index cbbf6960a51..5c4673019f5 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -238,9 +238,13 @@ static const int DEFAULT_SILENCE_THRESHOLD = 256; #define CONFIG_FILE_NAME "dsp.conf" typedef struct { + /*! The previous previous sample calculation (No binary point just plain int) */ int v2; + /*! The previous sample calculation (No binary point just plain int) */ int v3; + /*! v2 and v3 power of two exponent to keep value in int range */ int chunky; + /*! 15 bit fixed point goertzel coefficient = 2 * cos(2 * pi * freq / sample_rate) */ int fac; } goertzel_state_t; @@ -326,12 +330,22 @@ static inline void goertzel_sample(goertzel_state_t *s, short sample) { int v1; + /* + * Shift previous values so + * v1 is previous previous value + * v2 is previous value + * until the new v3 is calculated. + */ v1 = s->v2; s->v2 = s->v3; + /* Discard the binary fraction introduced by s->fac */ s->v3 = (s->fac * s->v2) >> 15; + /* Scale sample to match previous values */ s->v3 = s->v3 - v1 + (sample >> s->chunky); - if (abs(s->v3) > 32768) { + + if (abs(s->v3) > (1 << 15)) { + /* The result is now too large so increase the chunky power. */ s->chunky++; s->v3 = s->v3 >> 1; s->v2 = s->v2 >> 1; @@ -341,21 +355,26 @@ static inline void goertzel_sample(goertzel_state_t *s, short sample) static inline float goertzel_result(goertzel_state_t *s) { goertzel_result_t r; + r.value = (s->v3 * s->v3) + (s->v2 * s->v2); r.value -= ((s->v2 * s->v3) >> 15) * s->fac; + /* + * We have to double the exponent because we multiplied the + * previous sample calculation values together. + */ r.power = s->chunky * 2; return (float)r.value * (float)(1 << r.power); } static inline void goertzel_init(goertzel_state_t *s, float freq, unsigned int sample_rate) { - s->v2 = s->v3 = s->chunky = 0.0; + s->v2 = s->v3 = s->chunky = 0; s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / sample_rate)); } static inline void goertzel_reset(goertzel_state_t *s) { - s->v2 = s->v3 = s->chunky = 0.0; + s->v2 = s->v3 = s->chunky = 0; } typedef struct { From 737471f131c677136d56d9fa0a3d749d00b44490 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 21 Jul 2016 22:44:55 -0500 Subject: [PATCH 0606/1578] dsp.c: Add fax and DTMF detection unit tests. * Add fax amplitude and frequency sweep tests. * Add DTMF amplitude and twist unit tests. Change-Id: I8d77c9a1eec89e440d715f998c928687e870c3f7 --- main/dsp.c | 463 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 460 insertions(+), 3 deletions(-) diff --git a/main/dsp.c b/main/dsp.c index 5c4673019f5..1a3ebea6a15 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -68,6 +68,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/utils.h" #include "asterisk/options.h" #include "asterisk/config.h" +#include "asterisk/test.h" /*! Number of goertzels for progress detect */ enum gsamp_size { @@ -597,11 +598,11 @@ static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp tone_energy *= 2.0; s->energy *= s->block_size; - ast_debug(10, "tone %d, Ew=%.2E, Et=%.2E, s/n=%10.2f\n", s->freq, tone_energy, s->energy, tone_energy / (s->energy - tone_energy)); + ast_debug(10, "%d Hz tone %2d Ew=%.4E, Et=%.4E, s/n=%10.2f\n", s->freq, s->hit_count, tone_energy, s->energy, tone_energy / (s->energy - tone_energy)); hit = 0; if (TONE_THRESHOLD <= tone_energy && tone_energy > s->energy * s->threshold) { - ast_debug(10, "Hit! count=%d\n", s->hit_count); + ast_debug(10, "%d Hz tone Hit! %2d Ew=%.4E, Et=%.4E, s/n=%10.2f\n", s->freq, s->hit_count, tone_energy, s->energy, tone_energy / (s->energy - tone_energy)); hit = 1; } @@ -733,6 +734,10 @@ static int dtmf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp best_col = i; } } + ast_debug(10, "DTMF best '%c' Erow=%.4E Ecol=%.4E Erc=%.4E Et=%.4E\n", + dtmf_positions[(best_row << 2) + best_col], + row_energy[best_row], col_energy[best_col], + row_energy[best_row] + col_energy[best_col], s->td.dtmf.energy); hit = 0; /* Basic signal level test and the twist test */ if (row_energy[best_row] >= DTMF_THRESHOLD && @@ -753,6 +758,7 @@ static int dtmf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY * s->td.dtmf.energy) { /* Got a hit */ hit = dtmf_positions[(best_row << 2) + best_col]; + ast_debug(10, "DTMF hit '%c'\n", hit); } } @@ -1946,9 +1952,460 @@ int ast_dsp_get_threshold_from_settings(enum threshold which) return thresholds[which]; } +#ifdef TEST_FRAMEWORK +static void test_tone_sample_gen(short *slin_buf, int samples, int rate, int freq, short amplitude) +{ + int idx; + double sample_step = 2.0 * M_PI * freq / rate;/* radians per step */ + + for (idx = 0; idx < samples; ++idx) { + slin_buf[idx] = amplitude * sin(sample_step * idx); + } +} +#endif + +#ifdef TEST_FRAMEWORK +static void test_tone_sample_gen_add(short *slin_buf, int samples, int rate, int freq, short amplitude) +{ + int idx; + double sample_step = 2.0 * M_PI * freq / rate;/* radians per step */ + + for (idx = 0; idx < samples; ++idx) { + slin_buf[idx] += amplitude * sin(sample_step * idx); + } +} +#endif + +#ifdef TEST_FRAMEWORK +static void test_dual_sample_gen(short *slin_buf, int samples, int rate, int f1, short a1, int f2, short a2) +{ + test_tone_sample_gen(slin_buf, samples, rate, f1, a1); + test_tone_sample_gen_add(slin_buf, samples, rate, f2, a2); +} +#endif + +#ifdef TEST_FRAMEWORK +#define TONE_AMPLITUDE_MAX 0x7fff /* Max signed linear amplitude */ +#define TONE_AMPLITUDE_MIN 80 /* Min signed linear amplitude detectable */ + +static int test_tone_amplitude_sweep(struct ast_test *test, struct ast_dsp *dsp, tone_detect_state_t *tone_state) +{ + short slin_buf[tone_state->block_size]; + int result; + int idx; + struct { + short amp_val; + int detect; + } amp_tests[] = { + { .amp_val = TONE_AMPLITUDE_MAX, .detect = 1, }, + { .amp_val = 10000, .detect = 1, }, + { .amp_val = 1000, .detect = 1, }, + { .amp_val = 100, .detect = 1, }, + { .amp_val = TONE_AMPLITUDE_MIN, .detect = 1, }, + { .amp_val = 75, .detect = 0, }, + { .amp_val = 10, .detect = 0, }, + { .amp_val = 1, .detect = 0, }, + }; + + result = 0; + + for (idx = 0; idx < ARRAY_LEN(amp_tests); ++idx) { + int detected; + int duration; + + ast_debug(1, "Test %d Hz at amplitude %d\n", + tone_state->freq, amp_tests[idx].amp_val); + test_tone_sample_gen(slin_buf, tone_state->block_size, DEFAULT_SAMPLE_RATE, + tone_state->freq, amp_tests[idx].amp_val); + + detected = 0; + for (duration = 0; !detected && duration < tone_state->hits_required + 3; ++duration) { + detected = tone_detect(dsp, tone_state, slin_buf, tone_state->block_size) ? 1 : 0; + } + if (amp_tests[idx].detect != detected) { + /* + * Both messages are needed. ast_debug for when figuring out + * what went wrong and the test update for normal output before + * you start debugging. The different logging methods are not + * synchronized. + */ + ast_debug(1, + "Test %d Hz at amplitude %d failed. Detected: %s\n", + tone_state->freq, amp_tests[idx].amp_val, + detected ? "yes" : "no"); + ast_test_status_update(test, + "Test %d Hz at amplitude %d failed. Detected: %s\n", + tone_state->freq, amp_tests[idx].amp_val, + detected ? "yes" : "no"); + result = -1; + } + tone_state->hit_count = 0; + } + + return result; +} +#endif + +#ifdef TEST_FRAMEWORK +static int test_dtmf_amplitude_sweep(struct ast_test *test, struct ast_dsp *dsp, int digit_index) +{ + short slin_buf[DTMF_GSIZE]; + int result; + int row; + int column; + int idx; + struct { + short amp_val; + int digit; + } amp_tests[] = { + /* + * XXX Since there is no current DTMF level detection issue. This test + * just checks the current detection levels. + */ + { .amp_val = TONE_AMPLITUDE_MAX/2, .digit = dtmf_positions[digit_index], }, + { .amp_val = 10000, .digit = dtmf_positions[digit_index], }, + { .amp_val = 1000, .digit = dtmf_positions[digit_index], }, + { .amp_val = 500, .digit = dtmf_positions[digit_index], }, + { .amp_val = 250, .digit = dtmf_positions[digit_index], }, + { .amp_val = 200, .digit = dtmf_positions[digit_index], }, + { .amp_val = 180, .digit = dtmf_positions[digit_index], }, + /* Various digits detect and not detect in this range */ + { .amp_val = 170, .digit = 0, }, + { .amp_val = 100, .digit = 0, }, + /* + * Amplitudes below TONE_AMPLITUDE_MIN start having questionable detection + * over quantization and background noise. + */ + { .amp_val = TONE_AMPLITUDE_MIN, .digit = 0, }, + { .amp_val = 75, .digit = 0, }, + { .amp_val = 10, .digit = 0, }, + { .amp_val = 1, .digit = 0, }, + }; + + row = (digit_index >> 2) & 0x03; + column = digit_index & 0x03; + + result = 0; + + for (idx = 0; idx < ARRAY_LEN(amp_tests); ++idx) { + int digit; + int duration; + + ast_debug(1, "Test '%c' at amplitude %d\n", + dtmf_positions[digit_index], amp_tests[idx].amp_val); + test_dual_sample_gen(slin_buf, ARRAY_LEN(slin_buf), DEFAULT_SAMPLE_RATE, + (int) dtmf_row[row], amp_tests[idx].amp_val, + (int) dtmf_col[column], amp_tests[idx].amp_val); + + digit = 0; + for (duration = 0; !digit && duration < 3; ++duration) { + digit = dtmf_detect(dsp, &dsp->digit_state, slin_buf, ARRAY_LEN(slin_buf), + 0, 0); + } + if (amp_tests[idx].digit != digit) { + /* + * Both messages are needed. ast_debug for when figuring out + * what went wrong and the test update for normal output before + * you start debugging. The different logging methods are not + * synchronized. + */ + ast_debug(1, + "Test '%c' at amplitude %d failed. Detected Digit: '%c'\n", + dtmf_positions[digit_index], amp_tests[idx].amp_val, + digit ?: ' '); + ast_test_status_update(test, + "Test '%c' at amplitude %d failed. Detected Digit: '%c'\n", + dtmf_positions[digit_index], amp_tests[idx].amp_val, + digit ?: ' '); + result = -1; + } + ast_dsp_digitreset(dsp); + } + + return result; +} +#endif + +#ifdef TEST_FRAMEWORK +static int test_dtmf_twist_sweep(struct ast_test *test, struct ast_dsp *dsp, int digit_index) +{ + short slin_buf[DTMF_GSIZE]; + int result; + int row; + int column; + int idx; + struct { + short amp_row; + short amp_col; + int digit; + } twist_tests[] = { + /* + * XXX Since there is no current DTMF twist detection issue. This test + * just checks the current detection levels. + * + * Normal twist has the column higher than the row amplitude. + * Reverse twist is the other way. + */ + { .amp_row = 1000 + 1800, .amp_col = 1000 + 0, .digit = 0, }, + { .amp_row = 1000 + 1700, .amp_col = 1000 + 0, .digit = 0, }, + /* Various digits detect and not detect in this range */ + { .amp_row = 1000 + 1400, .amp_col = 1000 + 0, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 1300, .amp_col = 1000 + 0, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 1200, .amp_col = 1000 + 0, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 1100, .amp_col = 1000 + 0, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 1000, .amp_col = 1000 + 0, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 100, .amp_col = 1000 + 0, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 100, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 200, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 300, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 400, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 500, .digit = dtmf_positions[digit_index], }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 550, .digit = dtmf_positions[digit_index], }, + /* Various digits detect and not detect in this range */ + { .amp_row = 1000 + 0, .amp_col = 1000 + 650, .digit = 0, }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 700, .digit = 0, }, + { .amp_row = 1000 + 0, .amp_col = 1000 + 800, .digit = 0, }, + }; + float save_normal_twist; + float save_reverse_twist; + + save_normal_twist = dtmf_normal_twist; + save_reverse_twist = dtmf_reverse_twist; + dtmf_normal_twist = DEF_DTMF_NORMAL_TWIST; + dtmf_reverse_twist = DEF_DTMF_REVERSE_TWIST; + + row = (digit_index >> 2) & 0x03; + column = digit_index & 0x03; + + result = 0; + + for (idx = 0; idx < ARRAY_LEN(twist_tests); ++idx) { + int digit; + int duration; + + ast_debug(1, "Test '%c' twist row %d col %d amplitudes\n", + dtmf_positions[digit_index], + twist_tests[idx].amp_row, twist_tests[idx].amp_col); + test_dual_sample_gen(slin_buf, ARRAY_LEN(slin_buf), DEFAULT_SAMPLE_RATE, + (int) dtmf_row[row], twist_tests[idx].amp_row, + (int) dtmf_col[column], twist_tests[idx].amp_col); + + digit = 0; + for (duration = 0; !digit && duration < 3; ++duration) { + digit = dtmf_detect(dsp, &dsp->digit_state, slin_buf, ARRAY_LEN(slin_buf), + 0, 0); + } + if (twist_tests[idx].digit != digit) { + /* + * Both messages are needed. ast_debug for when figuring out + * what went wrong and the test update for normal output before + * you start debugging. The different logging methods are not + * synchronized. + */ + ast_debug(1, + "Test '%c' twist row %d col %d amplitudes failed. Detected Digit: '%c'\n", + dtmf_positions[digit_index], + twist_tests[idx].amp_row, twist_tests[idx].amp_col, + digit ?: ' '); + ast_test_status_update(test, + "Test '%c' twist row %d col %d amplitudes failed. Detected Digit: '%c'\n", + dtmf_positions[digit_index], + twist_tests[idx].amp_row, twist_tests[idx].amp_col, + digit ?: ' '); + result = -1; + } + ast_dsp_digitreset(dsp); + } + + dtmf_normal_twist = save_normal_twist; + dtmf_reverse_twist = save_reverse_twist; + + return result; +} +#endif + +#ifdef TEST_FRAMEWORK +static int test_tone_freq_sweep(struct ast_test *test, struct ast_dsp *dsp, tone_detect_state_t *tone_state, short amplitude) +{ + short slin_buf[tone_state->block_size]; + int result; + int freq; + int lower_freq; + int upper_freq; + + /* Calculate detection frequency range */ + lower_freq = tone_state->freq - 4; + upper_freq = tone_state->freq + 4; + + result = 0; + + /* Sweep frequencies loop. */ + for (freq = 100; freq <= 3500; freq += 1) { + int detected; + int duration; + int expect_detection; + + if (freq == tone_state->freq) { + /* This case is done by the amplitude sweep. */ + continue; + } + + expect_detection = (lower_freq <= freq && freq <= upper_freq) ? 1 : 0; + + ast_debug(1, "Test %d Hz detection given %d Hz tone at amplitude %d. Range:%d-%d Expect detect: %s\n", + tone_state->freq, freq, amplitude, lower_freq, upper_freq, + expect_detection ? "yes" : "no"); + test_tone_sample_gen(slin_buf, tone_state->block_size, DEFAULT_SAMPLE_RATE, freq, + amplitude); + + detected = 0; + for (duration = 0; !detected && duration < tone_state->hits_required + 3; ++duration) { + detected = tone_detect(dsp, tone_state, slin_buf, tone_state->block_size) ? 1 : 0; + } + if (expect_detection != detected) { + /* + * Both messages are needed. ast_debug for when figuring out + * what went wrong and the test update for normal output before + * you start debugging. The different logging methods are not + * synchronized. + */ + ast_debug(1, + "Test %d Hz detection given %d Hz tone at amplitude %d failed. Range:%d-%d Detected: %s\n", + tone_state->freq, freq, amplitude, lower_freq, upper_freq, + detected ? "yes" : "no"); + ast_test_status_update(test, + "Test %d Hz detection given %d Hz tone at amplitude %d failed. Range:%d-%d Detected: %s\n", + tone_state->freq, freq, amplitude, lower_freq, upper_freq, + detected ? "yes" : "no"); + result = -1; + } + tone_state->hit_count = 0; + } + + return result; +} +#endif + +#ifdef TEST_FRAMEWORK +AST_TEST_DEFINE(test_dsp_fax_detect) +{ + struct ast_dsp *dsp; + enum ast_test_result_state result; + + switch (cmd) { + case TEST_INIT: + info->name = "fax"; + info->category = "/main/dsp/"; + info->summary = "DSP fax tone detect unit test"; + info->description = + "Tests fax tone detection code."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + dsp = ast_dsp_new(); + if (!dsp) { + return AST_TEST_FAIL; + } + + result = AST_TEST_PASS; + + /* Test CNG tone amplitude detection */ + if (test_tone_amplitude_sweep(test, dsp, &dsp->cng_tone_state)) { + result = AST_TEST_FAIL; + } + + /* Test CED tone amplitude detection */ + if (test_tone_amplitude_sweep(test, dsp, &dsp->ced_tone_state)) { + result = AST_TEST_FAIL; + } + + /* Test CNG tone frequency detection */ + if (test_tone_freq_sweep(test, dsp, &dsp->cng_tone_state, TONE_AMPLITUDE_MAX)) { + result = AST_TEST_FAIL; + } + if (test_tone_freq_sweep(test, dsp, &dsp->cng_tone_state, TONE_AMPLITUDE_MIN)) { + result = AST_TEST_FAIL; + } + + /* Test CED tone frequency detection */ + if (test_tone_freq_sweep(test, dsp, &dsp->ced_tone_state, TONE_AMPLITUDE_MAX)) { + result = AST_TEST_FAIL; + } + if (test_tone_freq_sweep(test, dsp, &dsp->ced_tone_state, TONE_AMPLITUDE_MIN)) { + result = AST_TEST_FAIL; + } + + ast_dsp_free(dsp); + return result; +} +#endif + +#ifdef TEST_FRAMEWORK +AST_TEST_DEFINE(test_dsp_dtmf_detect) +{ + int idx; + struct ast_dsp *dsp; + enum ast_test_result_state result; + + switch (cmd) { + case TEST_INIT: + info->name = "dtmf"; + info->category = "/main/dsp/"; + info->summary = "DSP DTMF detect unit test"; + info->description = + "Tests DTMF detection code."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + dsp = ast_dsp_new(); + if (!dsp) { + return AST_TEST_FAIL; + } + + result = AST_TEST_PASS; + + for (idx = 0; dtmf_positions[idx]; ++idx) { + if (test_dtmf_amplitude_sweep(test, dsp, idx)) { + result = AST_TEST_FAIL; + } + } + + for (idx = 0; dtmf_positions[idx]; ++idx) { + if (test_dtmf_twist_sweep(test, dsp, idx)) { + result = AST_TEST_FAIL; + } + } + + ast_dsp_free(dsp); + return result; +} +#endif + +#ifdef TEST_FRAMEWORK +static void test_dsp_shutdown(void) +{ + AST_TEST_UNREGISTER(test_dsp_fax_detect); + AST_TEST_UNREGISTER(test_dsp_dtmf_detect); +} +#endif + int ast_dsp_init(void) { - return _dsp_init(0); + int res = _dsp_init(0); + +#ifdef TEST_FRAMEWORK + if (!res) { + AST_TEST_REGISTER(test_dsp_fax_detect); + AST_TEST_REGISTER(test_dsp_dtmf_detect); + + ast_register_cleanup(test_dsp_shutdown); + } +#endif + return res; } int ast_dsp_reload(void) From 8802e55c260e3c595c5bf584c8cb823768e51d06 Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Wed, 27 Jul 2016 09:56:29 -0500 Subject: [PATCH 0607/1578] Replace strdupa with more portable ast_strdupa The strdupa function is a GNU extension, and not widely portable. We have an ast_strdupa function used within Asterisk which is preferred. I pulled the definition up from menuselect.c into the menuselect.h header file so it can be shared across menuselect. Change-Id: I9593c97f78386b47dc1e83201e80cb2f62b36c2e --- menuselect/menuselect.c | 12 ------------ menuselect/menuselect.h | 12 ++++++++++++ menuselect/menuselect_curses.c | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/menuselect/menuselect.c b/menuselect/menuselect.c index efae311bb7a..f6a7fb39b2d 100644 --- a/menuselect/menuselect.c +++ b/menuselect/menuselect.c @@ -103,18 +103,6 @@ struct dep_file { }; AST_LIST_HEAD_NOLOCK_STATIC(deps_file, dep_file); -#if !defined(ast_strdupa) && defined(__GNUC__) -#define ast_strdupa(s) \ - (__extension__ \ - ({ \ - const char *__old = (s); \ - size_t __len = strlen(__old) + 1; \ - char *__new = __builtin_alloca(__len); \ - memcpy (__new, __old, __len); \ - __new; \ - })) -#endif - /*! \brief return a pointer to the first non-whitespace character */ static inline char *skip_blanks(char *str) { diff --git a/menuselect/menuselect.h b/menuselect/menuselect.h index 7b3fe26567c..328ac9a0ab8 100644 --- a/menuselect/menuselect.h +++ b/menuselect/menuselect.h @@ -162,4 +162,16 @@ static inline int strlen_zero(const char *s) return (!s || (*s == '\0')); } +#if !defined(ast_strdupa) && defined(__GNUC__) +#define ast_strdupa(s) \ + (__extension__ \ + ({ \ + const char *__old = (s); \ + size_t __len = strlen(__old) + 1; \ + char *__new = __builtin_alloca(__len); \ + memcpy (__new, __old, __len); \ + __new; \ + })) +#endif + #endif /* MENUSELECT_H */ diff --git a/menuselect/menuselect_curses.c b/menuselect/menuselect_curses.c index e79957485f1..260cf69a73b 100644 --- a/menuselect/menuselect_curses.c +++ b/menuselect/menuselect_curses.c @@ -211,7 +211,7 @@ static void display_mem_info(WINDOW *menu, struct member *mem, int start_y, int if (mem->displayname) { char buf[maxlen + 1]; - char *displayname = strdupa(mem->displayname); + char *displayname = ast_strdupa(mem->displayname); char *word; int current_line = 1; int new_line = 1; From 1d364ac54f2ddd2f281fec61664f9087e622727d Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Wed, 27 Jul 2016 12:36:22 -0500 Subject: [PATCH 0608/1578] rtp_engine: Failed assertion and wrong name given for codec Fixed an assert check that would trigger when the passed in value was negative. The negative value was being cast to an unsigned value. This resulted in the check failing. Also fixed another problem when loading formats in the engine. When setting the mime type the format's name was being passed in instead of the codec's name. Change-Id: I1a201cd419ba4d8e9a40d337e36b6fbe1737192c --- main/rtp_engine.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index feadda3d379..66b80e5557c 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -983,6 +983,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, } else { new_type->format = t->payload_type.format; } + if (new_type->format) { /* SDP parsing automatically increases the reference count */ new_type->format = ast_format_parse_sdp_fmtp(new_type->format, ""); @@ -2257,7 +2258,11 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code) int x; struct ast_rtp_payload_type *type; - ast_assert(map < ARRAY_LEN(static_RTP_PT)); + /* + * ARRAY_LEN's result is cast to an int so 'map' is not autocast to a size_t, + * which if negative would cause an assertion. + */ + ast_assert(map < (int)ARRAY_LEN(static_RTP_PT)); ast_rwlock_wrlock(&static_RTP_PT_lock); if (map < 0) { @@ -2268,6 +2273,7 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code) break; } } + if (map < 0) { if (format) { ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n", @@ -2300,14 +2306,10 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code) int ast_rtp_engine_load_format(struct ast_format *format) { - char *codec_name = ast_strdupa(ast_format_get_name(format)); - - codec_name = ast_str_to_upper(codec_name); - set_next_mime_type(format, 0, ast_codec_media_type2str(ast_format_get_type(format)), - codec_name, + ast_format_get_codec_name(format), ast_format_get_sample_rate(format)); add_static_payload(-1, format, 0); From feb1a434122a3cd3cbe4a6e75a4bd76a677bdb0d Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Wed, 27 Jul 2016 10:33:23 -0500 Subject: [PATCH 0609/1578] Portably sscanf tv_usec In a timeval, tv_usec is defined as a suseconds_t, which could be different underlying types on different platforms. Instead of trying to scanf directly into the timeval, scanf into a long int, then copy that into the timeval. Change-Id: I29f22d049d3f7746b6c0cc23fbf4293bdaa5eb95 --- funcs/func_cdr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index ae15f6aa945..8dcb2bd0b2d 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -223,9 +223,11 @@ STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_prop_write_message_type); static struct timeval cdr_retrieve_time(struct ast_channel *chan, const char *time_name) { - struct timeval time; + struct timeval time = { 0 }; char *value = NULL; char tempbuf[128]; + long int tv_sec; + long int tv_usec; if (ast_strlen_zero(ast_channel_name(chan))) { /* Format request on a dummy channel */ @@ -234,7 +236,11 @@ static struct timeval cdr_retrieve_time(struct ast_channel *chan, const char *ti ast_cdr_getvar(ast_channel_name(chan), time_name, tempbuf, sizeof(tempbuf)); } - if (sscanf(tempbuf, "%ld.%ld", &time.tv_sec, &time.tv_usec) != 2) { + /* time.tv_usec is suseconds_t, which could be int or long */ + if (sscanf(tempbuf, "%ld.%ld", &tv_sec, &tv_usec) == 2) { + time.tv_sec = tv_sec; + time.tv_usec = tv_usec; + } else { ast_log(AST_LOG_WARNING, "Failed to fully extract '%s' from CDR\n", time_name); } From b4f1c6380e5a3ee6dbd9ed8e7cc399c700f974fa Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 17 Jul 2016 17:28:36 -0600 Subject: [PATCH 0610/1578] pjproject_bundled: Update for pjproject 2.5.5 Add more --disable-* switches to Makefile.rules including --disable-opus which was causing bundled pjproject to fail with "undefined reference" errors in libasteriskpj. Changed PJ_ENABLE_EXTRA_CHECK to 1. Removed 2 obsolete patches and added a new one. The new one was merged by Teluu on 6/27/2016. ASTERISK-26148 #close Change-Id: Ib8af6c6a9d31f7238ce65b336134c2efdc855063 --- third-party/pjproject/Makefile.rules | 31 +++++++- ...o-add-decrement-an-event-subscriptio.patch | 73 ------------------- ...p-tls-Set-factory-on-transports-crea.patch | 48 ------------ ...einitialization-of-uninitialized-cli.patch | 56 ++++++++++++++ third-party/pjproject/patches/config_site.h | 2 +- third-party/versions.mak | 2 +- 6 files changed, 86 insertions(+), 126 deletions(-) delete mode 100644 third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch delete mode 100644 third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch create mode 100644 third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index d2e7d25a4b7..739193aca32 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -1,9 +1,34 @@ PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe -PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject --disable-speex-codec --disable-speex-aec \ - --disable-gsm-codec --disable-video --disable-v4l2 --disable-sound --disable-opencore-amr \ - --disable-ilbc-codec --without-libyuv --disable-g7221-codec --disable-resample + +PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ + --disable-speex-codec \ + --disable-speex-aec \ + --disable-speex-aec \ + --disable-gsm-codec \ + --disable-ilbc-codec \ + --disable-l16-codec \ + --disable-g711-codec \ + --disable-g722-codec \ + --disable-g7221-codec \ + --disable-opencore-amr \ + --disable-webrtc \ + --disable-silk \ + --disable-opus \ + --disable-video \ + --disable-v4l2 \ + --disable-sound \ + --disable-ext-sound \ + --disable-oss \ + --disable-sdl \ + --disable-libyuv \ + --disable-resample \ + --disable-ffmpeg \ + --disable-openh264 \ + --disable-ipp \ + --without-external-pa \ + --with-external-srtp ifeq ($(shell uname -s),Linux) PJPROJECT_CONFIG_OPTS += --enable-epoll diff --git a/third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch b/third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch deleted file mode 100644 index d2a47c6c5b6..00000000000 --- a/third-party/pjproject/patches/0001-evsub-Add-APIs-to-add-decrement-an-event-subscriptio.patch +++ /dev/null @@ -1,73 +0,0 @@ -From a5030c9b33b2c936879fbacb1d2ea5edc2979181 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Sat, 18 Jun 2016 10:14:34 -0600 -Subject: [PATCH] evsub: Add APIs to add/decrement an event subscription's - group lock - -These APIs can be used to ensure that the evsub isn't destroyed before -an application is finished using it. ---- - pjsip/include/pjsip-simple/evsub.h | 20 ++++++++++++++++++++ - pjsip/src/pjsip-simple/evsub.c | 14 ++++++++++++++ - 2 files changed, 34 insertions(+) - -diff --git a/pjsip/include/pjsip-simple/evsub.h b/pjsip/include/pjsip-simple/evsub.h -index 2dc4d69..31f85f8 100644 ---- a/pjsip/include/pjsip-simple/evsub.h -+++ b/pjsip/include/pjsip-simple/evsub.h -@@ -490,6 +490,26 @@ PJ_DECL(void) pjsip_evsub_set_mod_data( pjsip_evsub *sub, unsigned mod_id, - PJ_DECL(void*) pjsip_evsub_get_mod_data( pjsip_evsub *sub, unsigned mod_id ); - - -+/** -+ * Increment the event subscription's group lock. -+ * -+ * @param sub The server subscription instance. -+ * -+ * @return PJ_SUCCESS on success. -+ */ -+PJ_DEF(pj_status_t) pjsip_evsub_add_ref(pjsip_evsub *sub); -+ -+ -+/** -+ * Decrement the event subscription's group lock. -+ * -+ * @param sub The server subscription instance. -+ * -+ * @return PJ_SUCCESS on success. -+ */ -+PJ_DEF(pj_status_t) pjsip_evsub_dec_ref(pjsip_evsub *sub); -+ -+ - - PJ_END_DECL - -diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c -index 7cd8859..68a9564 100644 ---- a/pjsip/src/pjsip-simple/evsub.c -+++ b/pjsip/src/pjsip-simple/evsub.c -@@ -831,7 +831,21 @@ static pj_status_t evsub_create( pjsip_dialog *dlg, - return PJ_SUCCESS; - } - -+/* -+ * Increment the event subscription's group lock. -+ */ -+PJ_DEF(pj_status_t) pjsip_evsub_add_ref(pjsip_evsub *sub) -+{ -+ return pj_grp_lock_add_ref(sub->grp_lock); -+} - -+/* -+ * Decrement the event subscription's group lock. -+ */ -+PJ_DEF(pj_status_t) pjsip_evsub_dec_ref(pjsip_evsub *sub) -+{ -+ return pj_grp_lock_dec_ref(sub->grp_lock); -+} - - /* - * Create client subscription session. --- -2.5.5 - diff --git a/third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch b/third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch deleted file mode 100644 index d8a9adbde52..00000000000 --- a/third-party/pjproject/patches/0001-sip_transport_tcp-tls-Set-factory-on-transports-crea.patch +++ /dev/null @@ -1,48 +0,0 @@ -From b7cb93b0e1729589a71e8b30d9a9893f0918e2a2 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Mon, 30 May 2016 11:58:22 -0600 -Subject: [PATCH] sip_transport_tcp/tls: Set factory on transports created - from accept - -The ability to re-use tcp and tls transports when a factory is -specified now depends on transport->factory being set which is a new field -in 2.5. This was being set only on new outgoing sockets not on -incoming sockets. The result was that a client REGISTER created a new -socket but without the factory set, the next outgoing request to the -client, OPTIONS, INVITE, etc, would attempt to create another socket -which the client would refuse. - -This patch sets the factory on transports created as a result of an -accept. ---- - pjsip/src/pjsip/sip_transport_tcp.c | 1 + - pjsip/src/pjsip/sip_transport_tls.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c -index 1bbb324..00eb8fc 100644 ---- a/pjsip/src/pjsip/sip_transport_tcp.c -+++ b/pjsip/src/pjsip/sip_transport_tcp.c -@@ -713,6 +713,7 @@ static pj_status_t tcp_create( struct tcp_listener *listener, - tcp->base.send_msg = &tcp_send_msg; - tcp->base.do_shutdown = &tcp_shutdown; - tcp->base.destroy = &tcp_destroy_transport; -+ tcp->base.factory = &listener->factory; - - /* Create group lock */ - status = pj_grp_lock_create(pool, NULL, &tcp->grp_lock); -diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c -index a83ac32..36ee70d 100644 ---- a/pjsip/src/pjsip/sip_transport_tls.c -+++ b/pjsip/src/pjsip/sip_transport_tls.c -@@ -742,6 +742,7 @@ static pj_status_t tls_create( struct tls_listener *listener, - tls->base.send_msg = &tls_send_msg; - tls->base.do_shutdown = &tls_shutdown; - tls->base.destroy = &tls_destroy_transport; -+ tls->base.factory = &listener->factory; - - tls->ssock = ssock; - --- -2.5.5 - diff --git a/third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch b/third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch new file mode 100644 index 00000000000..c4288a389d5 --- /dev/null +++ b/third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch @@ -0,0 +1,56 @@ +From 33fd755e819dc85a96718abc0ae26a9b46f14800 Mon Sep 17 00:00:00 2001 +From: nanang +Date: Thu, 28 Jul 2016 08:21:45 +0000 +Subject: [PATCH 2/3] Fix #1946: Avoid deinitialization of uninitialized client + auth session. + +--- + pjsip/src/pjsip/sip_dialog.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c +index f03885d..421ddc4 100644 +--- a/pjsip/src/pjsip/sip_dialog.c ++++ b/pjsip/src/pjsip/sip_dialog.c +@@ -92,6 +92,12 @@ static pj_status_t create_dialog( pjsip_user_agent *ua, + pj_list_init(&dlg->inv_hdr); + pj_list_init(&dlg->rem_cap_hdr); + ++ /* Init client authentication session. */ ++ status = pjsip_auth_clt_init(&dlg->auth_sess, dlg->endpt, ++ dlg->pool, 0); ++ if (status != PJ_SUCCESS) ++ goto on_error; ++ + status = pj_mutex_create_recursive(pool, dlg->obj_name, &dlg->mutex_); + if (status != PJ_SUCCESS) + goto on_error; +@@ -283,12 +289,6 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua, + /* Initial route set is empty. */ + pj_list_init(&dlg->route_set); + +- /* Init client authentication session. */ +- status = pjsip_auth_clt_init(&dlg->auth_sess, dlg->endpt, +- dlg->pool, 0); +- if (status != PJ_SUCCESS) +- goto on_error; +- + /* Register this dialog to user agent. */ + status = pjsip_ua_register_dlg( ua, dlg ); + if (status != PJ_SUCCESS) +@@ -506,12 +506,6 @@ pj_status_t create_uas_dialog( pjsip_user_agent *ua, + } + dlg->route_set_frozen = PJ_TRUE; + +- /* Init client authentication session. */ +- status = pjsip_auth_clt_init(&dlg->auth_sess, dlg->endpt, +- dlg->pool, 0); +- if (status != PJ_SUCCESS) +- goto on_error; +- + /* Increment the dialog's lock since tsx may cause the dialog to be + * destroyed prematurely (such as in case of transport error). + */ +-- +2.7.4 + diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index eb9f8b15cdf..07e4d97a92e 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -19,7 +19,7 @@ #define PJ_SCANNER_USE_BITWISE 0 #define PJ_OS_HAS_CHECK_STACK 0 #define PJ_LOG_MAX_LEVEL 3 -#define PJ_ENABLE_EXTRA_CHECK 0 +#define PJ_ENABLE_EXTRA_CHECK 1 #define PJSIP_MAX_TSX_COUNT ((64*1024)-1) #define PJSIP_MAX_DIALOG_COUNT ((64*1024)-1) #define PJSIP_UDP_SO_SNDBUF_SIZE (512*1024) diff --git a/third-party/versions.mak b/third-party/versions.mak index ca40531dfba..a4d7874d54f 100644 --- a/third-party/versions.mak +++ b/third-party/versions.mak @@ -1,2 +1,2 @@ -PJPROJECT_VERSION = 2.5 +PJPROJECT_VERSION = 2.5.5 From b5bc2fdda89a183cd29fe21ce15c26cb106d8bf4 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 21 Jul 2016 11:36:44 -0400 Subject: [PATCH 0611/1578] pjproject: fixed a few bugs This patch fixes the issue in pjsip_tx_data_dec_ref() when tx_data_destroy can be called more than once, and checks if invalid value (e.g. NULL) is passed to. This patch updates array limit checks and docs in pjsip_evsub_register_pkg() and pjsip_endpt_add_capability(). Change-Id: I4c7a132b9664afaecbd6bf5ea4c951e43e273e40 --- ...-r5397-pjsip_generic_array_max_count.patch | 58 +++++++++++++++++++ .../0001-r5400-pjsip_tx_data_dec_ref.patch | 24 ++++++++ 2 files changed, 82 insertions(+) create mode 100644 third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch create mode 100644 third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch diff --git a/third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch b/third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch new file mode 100644 index 00000000000..3cc328afe36 --- /dev/null +++ b/third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch @@ -0,0 +1,58 @@ +This patch updates array limit checks and docs +in pjsip_evsub_register_pkg() and pjsip_endpt_add_capability(). + +Index: pjsip/include/pjsip/sip_endpoint.h +=================================================================== +--- a/pjsip/include/pjsip/sip_endpoint.h (revision 5396) ++++ b/pjsip/include/pjsip/sip_endpoint.h (revision 5397) +@@ -583,7 +583,8 @@ + * @param hname If htype specifies PJSIP_H_OTHER, then the header name + * must be supplied in this argument. Otherwise the value + * must be set to NULL. +- * @param count The number of tags in the array. ++ * @param count The number of tags in the array. The value must not ++ * be greater than PJSIP_GENERIC_ARRAY_MAX_COUNT. + * @param tags Array of tags describing the capabilities or extensions + * to be added to the appropriate header. + * +Index: pjsip/include/pjsip-simple/evsub.h +=================================================================== +--- a/pjsip/include/pjsip-simple/evsub.h (revision 5396) ++++ b/pjsip/include/pjsip-simple/evsub.h (revision 5397) +@@ -246,7 +246,8 @@ + * registered. + * @param event_name Event package identification. + * @param expires Default subscription expiration time, in seconds. +- * @param accept_cnt Number of strings in Accept array. ++ * @param accept_cnt Number of strings in Accept array. The value must ++ * not be greater than PJSIP_GENERIC_ARRAY_MAX_COUNT. + * @param accept Array of Accept value. + * + * @return PJ_SUCCESS on success. +Index: pjsip/src/pjsip/sip_endpoint.c +=================================================================== +--- a/pjsip/src/pjsip/sip_endpoint.c (revision 5396) ++++ b/pjsip/src/pjsip/sip_endpoint.c (revision 5397) +@@ -371,6 +371,7 @@ + + /* Check arguments. */ + PJ_ASSERT_RETURN(endpt!=NULL && count>0 && tags, PJ_EINVAL); ++ PJ_ASSERT_RETURN(count <= PJSIP_GENERIC_ARRAY_MAX_COUNT, PJ_ETOOMANY); + PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT || + htype==PJSIP_H_ALLOW || + htype==PJSIP_H_SUPPORTED, +Index: pjsip/src/pjsip-simple/evsub.c +=================================================================== +--- a/pjsip/src/pjsip-simple/evsub.c (revision 5396) ++++ b/pjsip/src/pjsip-simple/evsub.c (revision 5397) +@@ -412,7 +412,9 @@ + unsigned i; + + PJ_ASSERT_RETURN(pkg_mod && event_name, PJ_EINVAL); +- PJ_ASSERT_RETURN(accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values), ++ ++ /* Make sure accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values) */ ++ PJ_ASSERT_RETURN(accept_cnt <= PJSIP_GENERIC_ARRAY_MAX_COUNT, + PJ_ETOOMANY); + + /* Make sure evsub module has been initialized */ diff --git a/third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch b/third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch new file mode 100644 index 00000000000..b5c11db4535 --- /dev/null +++ b/third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch @@ -0,0 +1,24 @@ +This patch fixes the issue in pjsip_tx_data_dec_ref() +when tx_data_destroy can be called more than once, +and checks if invalid value (e.g. NULL) is passed to. + +Index: pjsip/src/pjsip/sip_transport.c +=================================================================== +--- a/pjsip/src/pjsip/sip_transport.c (revision 5399) ++++ b/pjsip/src/pjsip/sip_transport.c (revision 5400) +@@ -491,8 +491,13 @@ + */ + PJ_DEF(pj_status_t) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata ) + { +- pj_assert( pj_atomic_get(tdata->ref_cnt) > 0); +- if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) { ++ pj_atomic_value_t ref_cnt; ++ ++ PJ_ASSERT_RETURN(tdata && tdata->ref_cnt, PJ_EINVAL); ++ ++ ref_cnt = pj_atomic_dec_and_get(tdata->ref_cnt); ++ pj_assert( ref_cnt >= 0); ++ if (ref_cnt == 0) { + tx_data_destroy(tdata); + return PJSIP_EBUFDESTROYED; + } else { From 68ebf86e2fbd0a8e60d32c17f8ce64d4db51b7a6 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 27 Jul 2016 17:17:53 -0500 Subject: [PATCH 0612/1578] pbx.c: Allow dangerous functions when adding a hint to dialplan. We can allow dangerous functions when adding a hint since altering dialplan is itself a privileged activity. Otherwise, we could never execute dangerous functions. ASTERISK-25996 #close Reported by: Andrew Nagy Change-Id: I4929ff100ad1200a0198262d069a34f2296e77ba --- include/asterisk/pbx.h | 12 ++++++++++++ main/pbx.c | 12 ++++++++++++ main/pbx_functions.c | 19 +++++++++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index d44a245e368..6da44703498 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1618,6 +1618,18 @@ void pbx_live_dangerously(int new_live_dangerously); */ int ast_thread_inhibit_escalations(void); +/*! + * \brief Swap the current thread escalation inhibit setting. + * \since 11.24.0 + * + * \param inhibit New setting. Non-zero to inhibit. + * + * \retval 1 if dangerous function execution was inhibited. + * \retval 0 if dangerous function execution was allowed. + * \retval -1 on error. + */ +int ast_thread_inhibit_escalations_swap(int inhibit); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/pbx.c b/main/pbx.c index 4d6d31ec4bd..27f1a4ecb2b 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -7153,13 +7153,25 @@ static int ast_add_extension2_lockopt(struct ast_context *con, /* If we are adding a hint evalulate in variables and global variables */ if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') { + int inhibited; struct ast_channel *c = ast_dummy_channel_alloc(); if (c) { ast_channel_exten_set(c, extension); ast_channel_context_set(c, con->name); } + + /* + * We can allow dangerous functions when adding a hint since + * altering dialplan is itself a privileged activity. Otherwise, + * we could never execute dangerous functions. + */ + inhibited = ast_thread_inhibit_escalations_swap(0); pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf)); + if (0 < inhibited) { + ast_thread_inhibit_escalations(); + } + application = expand_buf; if (c) { ast_channel_unref(c); diff --git a/main/pbx_functions.c b/main/pbx_functions.c index bc738b0431d..558be461f0e 100644 --- a/main/pbx_functions.c +++ b/main/pbx_functions.c @@ -482,7 +482,6 @@ int ast_thread_inhibit_escalations(void) thread_inhibit_escalations = ast_threadstorage_get( &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations)); - if (thread_inhibit_escalations == NULL) { ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n"); return -1; @@ -492,6 +491,23 @@ int ast_thread_inhibit_escalations(void) return 0; } +int ast_thread_inhibit_escalations_swap(int inhibit) +{ + int *thread_inhibit_escalations; + int orig; + + thread_inhibit_escalations = ast_threadstorage_get( + &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations)); + if (thread_inhibit_escalations == NULL) { + ast_log(LOG_ERROR, "Error swapping privilege escalations inhibit for current thread\n"); + return -1; + } + + orig = *thread_inhibit_escalations; + *thread_inhibit_escalations = !!inhibit; + return orig; +} + /*! * \brief Indicates whether the current thread inhibits the execution of * dangerous functions. @@ -505,7 +521,6 @@ static int thread_inhibits_escalations(void) thread_inhibit_escalations = ast_threadstorage_get( &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations)); - if (thread_inhibit_escalations == NULL) { ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n"); /* On error, assume that we are inhibiting */ From 89a0a1eb45dd6055a1052c93e591de5833b85b47 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 28 Jul 2016 15:10:04 -0400 Subject: [PATCH 0613/1578] pbx.c: Fix handling of '-' in extension name and callerid This adds a two strings to ast_exten. name to go with exten and cidmatch_display to go with cidmatch. The new fields contain input used to add the extension in the first place. The existing fields now contain stripped input that excludes insignificant spaces and dashes. These stripped fields should always be used for comparisons. The unstripped fields should normally be used for display, but displaying stripped values will not cause runtime errors. Note the actual string is only stored twice if it contains dashes. If no dashes are found then both 'char *' fields point to the same memory. So this change has a minimum effect on memory usage. The existing functions ast_get_extension_name and ast_get_extension_cidmatch return unstripped values as they did before this change. Other similar bugs likely still exist where unstripped extensions are saved outside pbx.c then passed back in. ASTERISK-26233 #close Change-Id: I6cd61ce57acc1570ca6cc14960c4c3b0a9eb837f --- main/pbx.c | 194 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 143 insertions(+), 51 deletions(-) diff --git a/main/pbx.c b/main/pbx.c index 4d6d31ec4bd..a6771117c79 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -237,9 +237,11 @@ AST_THREADSTORAGE(extensionstate_buf); priority. */ struct ast_exten { - char *exten; /*!< Extension name */ + char *exten; /*!< Clean Extension id */ + char *name; /*!< Extension name (may include '-' eye candy) */ int matchcid; /*!< Match caller id ? */ const char *cidmatch; /*!< Caller id to match for this extension */ + const char *cidmatch_display; /*!< Caller id to match (display version) */ int priority; /*!< Priority */ const char *label; /*!< Label */ struct ast_context *parent; /*!< The context this extension belongs to */ @@ -654,6 +656,7 @@ static int ast_add_extension2_lockopt(struct ast_context *con, static struct ast_context *find_context_locked(const char *context); static struct ast_context *find_context(const char *context); static void get_device_state_causing_channels(struct ao2_container *c); +static int ext_strncpy(char *dst, const char *src, int len, int nofluff); /*! * \internal @@ -878,9 +881,13 @@ int check_contexts(char *file, int line ) e2 = ast_hashtab_lookup(c1->root_table, &ex); if (!e2) { if (e1->matchcid == AST_EXT_MATCHCID_ON) { - ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch ); + ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records " + "the exten %s (CID match: %s) but it is not in its root_table\n", + file, line, c2->name, dummy_name, e1->cidmatch_display); } else { - ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name ); + ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records " + "the exten %s but it is not in its root_table\n", + file, line, c2->name, dummy_name); } check_contexts_trouble(); } @@ -1113,11 +1120,11 @@ static void cli_match_char_tree(struct match_char *node, char *prefix, int fd) if (strlen(node->x) > 1) { ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N', node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "", - node->exten ? node->exten->exten : "", extenstr); + node->exten ? node->exten->name : "", extenstr); } else { ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N', node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "", - node->exten ? node->exten->exten : "", extenstr); + node->exten ? node->exten->name : "", extenstr); } ast_str_set(&my_prefix, 0, "%s+ ", prefix); @@ -1232,7 +1239,7 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct return; \ } \ } else { \ - ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->exten); \ + ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->name); \ return; /* the first match, by definition, will be the best, because of the sorted tree */ \ } \ } \ @@ -1245,13 +1252,13 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct if (*(str + 1) || p->next_char->x[0] == '!') { \ new_find_extension(str + 1, score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \ if (score->exten) { \ - ast_debug(4 ,"returning an exact match-- %s\n", score->exten->exten); \ + ast_debug(4 ,"returning an exact match-- %s\n", score->exten->name); \ return; /* the first match is all we need */ \ } \ } else { \ new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \ if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \ - ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten : \ + ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->name : \ "NULL"); \ return; /* the first match is all we need */ \ } \ @@ -1289,14 +1296,17 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct if (p->exten && *str2 != '/') { update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p); if (score->exten) { - ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten); + ast_debug(4, "return because scoreboard has a match with '/'--- %s\n", + score->exten->name); return; /* the first match is all we need */ } } if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) { new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action); if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { - ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL"); + ast_debug(4, "return because scoreboard has exact match OR " + "CANMATCH/MATCHMORE & canmatch set--- %s\n", + score->exten ? score->exten->name : "NULL"); return; /* the first match is all we need */ } } @@ -1311,14 +1321,17 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct if (p->exten && *str2 != '/') { update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p); if (score->exten) { - ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten); + ast_debug(4, "return because scoreboard has a '!' match--- %s\n", + score->exten->name); return; /* the first match is all we need */ } } if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) { new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action); if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { - ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL"); + ast_debug(4, "return because scoreboard has exact match OR " + "CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", + score->exten ? score->exten->name : "NULL"); return; /* the first match is all we need */ } } @@ -1327,7 +1340,9 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct if (p->next_char && callerid && *callerid) { new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action); if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { - ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL"); + ast_debug(4, "return because scoreboard has exact match OR " + "CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", + score->exten ? score->exten->name : "NULL"); return; /* the first match is all we need */ } } @@ -1680,7 +1695,7 @@ static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, str } if (m2->exten) { ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", - m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten); + m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name); } m2->exten = e1; m2->deleted = 0; @@ -1706,7 +1721,7 @@ static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, str if (!pat_node[idx_next].buf[0]) { if (m2 && m2->exten) { ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", - m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten); + m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name); } m1->deleted = 0; m1->exten = e1; @@ -2113,6 +2128,41 @@ static int ext_cmp(const char *left, const char *right) return ext_cmp_pattern(left + 1, right + 1); } +static int ext_fluff_count(const char *exten) +{ + int fluff = 0; + + if (*exten != '_') { + /* not a pattern, simple check. */ + while (*exten) { + if (*exten == '-') { + fluff++; + } + exten++; + } + + return fluff; + } + + /* do pattern check */ + while (*exten) { + if (*exten == '-') { + fluff++; + } else if (*exten == '[') { + /* skip set, dashes here matter. */ + exten = strchr(exten, ']'); + + if (!exten) { + /* we'll end up warning about this later, don't spam logs */ + return fluff; + } + } + exten++; + } + + return fluff; +} + int ast_extension_cmp(const char *a, const char *b) { int cmp; @@ -4883,6 +4933,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char * struct ast_exten *peer; struct ast_exten ex, *exten2, *exten3; char dummy_name[1024]; + char dummy_cid[1024]; struct ast_exten *previous_peer = NULL; struct ast_exten *next_peer = NULL; int found = 0; @@ -4898,9 +4949,14 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char * #endif /* find this particular extension */ ex.exten = dummy_name; + ext_strncpy(dummy_name, extension, sizeof(dummy_name), 1); ex.matchcid = matchcallerid; - ex.cidmatch = callerid; - ast_copy_string(dummy_name, extension, sizeof(dummy_name)); + if (callerid) { + ex.cidmatch = dummy_cid; + ext_strncpy(dummy_cid, callerid, sizeof(dummy_cid), 1); + } else { + ex.cidmatch = NULL; + } exten = ast_hashtab_lookup(con->root_table, &ex); if (exten) { if (priority == 0) { @@ -4923,13 +4979,19 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char * if (exten2) { if (exten2->label) { /* if this exten has a label, remove that, too */ exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2); - if (!exten3) - ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten); + if (!exten3) { + ast_log(LOG_ERROR, "Did not remove this priority label (%d/%s) " + "from the peer_label_table of context %s, extension %s!\n", + priority, exten2->label, con->name, exten2->name); + } } exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2); - if (!exten3) - ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten); + if (!exten3) { + ast_log(LOG_ERROR, "Did not remove this priority (%d) from the " + "peer_table of context %s, extension %s!\n", + priority, con->name, exten2->name); + } if (exten2 == exten && exten2->peer) { exten2 = ast_hashtab_remove_this_object(con->root_table, exten); ast_hashtab_insert_immediate(con->root_table, exten2->peer); @@ -4938,8 +5000,11 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char * /* well, if the last priority of an exten is to be removed, then, the extension is removed, too! */ exten3 = ast_hashtab_remove_this_object(con->root_table, exten); - if (!exten3) - ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority); + if (!exten3) { + ast_log(LOG_ERROR, "Did not remove this exten (%s) from the " + "context root_table (%s) (priority %d)\n", + exten->name, con->name, priority); + } if (con->pattern_tree) { struct match_char *x = add_exten_to_pattern_tree(con, exten, 1); if (x->exten) { /* this test for safety purposes */ @@ -4950,7 +5015,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char * } } else { ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n", - priority, exten->exten, con->name); + priority, exten->name, con->name); } } } else { @@ -4967,7 +5032,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char * /* scan the extension list to find first matching extension-registrar */ for (exten = con->root; exten; prev_exten = exten, exten = exten->next) { - if (!strcmp(exten->exten, extension) && + if (!strcmp(exten->exten, ex.exten) && (!registrar || !strcmp(exten->registrar, registrar)) && (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch)))) break; @@ -4981,7 +5046,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char * /* scan the priority list to remove extension with exten->priority == priority */ for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next; - peer && !strcmp(peer->exten, extension) && + peer && !strcmp(peer->exten, ex.exten) && (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, callerid))) ; peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) { @@ -6271,11 +6336,11 @@ static void context_merge(struct ast_context **extcontexts, struct ast_hashtab * dupdstr = ast_strdup(prio_item->data); - res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, + res1 = ast_add_extension2(new, 0, prio_item->name, prio_item->priority, prio_item->label, prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar); if (!res1 && new_exten_item && new_prio_item){ ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n", - context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar); + context->name, prio_item->name, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar); } else { /* we do NOT pass the priority data from the old to the new -- we pass a copy of it, so no changes to the current dialplan take place, and no double frees take place, either! */ @@ -6880,8 +6945,8 @@ int ast_async_goto_by_name(const char *channame, const char *context, const char return res; } -/*! \brief copy a string skipping whitespace */ -static int ext_strncpy(char *dst, const char *src, int len) +/*! \brief copy a string skipping whitespace and dashes */ +static int ext_strncpy(char *dst, const char *src, int len, int nofluff) { int count = 0; int insquares = 0; @@ -6894,6 +6959,9 @@ static int ext_strncpy(char *dst, const char *src, int len) } else if (*src == ' ' && !insquares) { src++; continue; + } else if (*src == '-' && !insquares && nofluff) { + src++; + continue; } *dst = *src; dst++; @@ -6919,14 +6987,14 @@ static int add_priority(struct ast_context *con, struct ast_exten *tmp, for (ep = NULL; e ; ep = e, e = e->peer) { if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) { - if (strcmp(e->exten, tmp->exten)) { + if (strcmp(e->name, tmp->name)) { ast_log(LOG_WARNING, "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n", - tmp->exten, tmp->priority, con->name, tmp->label, e->exten, e->priority); + tmp->name, tmp->priority, con->name, tmp->label, e->name, e->priority); } else { ast_log(LOG_WARNING, "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n", - tmp->exten, tmp->priority, con->name, tmp->label, e->priority); + tmp->name, tmp->priority, con->name, tmp->label, e->priority); } repeated_label = 1; } @@ -6952,14 +7020,14 @@ static int add_priority(struct ast_context *con, struct ast_exten *tmp, /* Can't have something exactly the same. Is this a replacement? If so, replace, otherwise, bonk. */ if (!replace) { - if (strcmp(e->exten, tmp->exten)) { + if (strcmp(e->name, tmp->name)) { ast_log(LOG_WARNING, "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n", - tmp->exten, tmp->priority, con->name, e->exten); + tmp->name, tmp->priority, con->name, e->name); } else { ast_log(LOG_WARNING, "Unable to register extension '%s' priority %d in '%s', already in use\n", - tmp->exten, tmp->priority, con->name); + tmp->name, tmp->priority, con->name); } return -1; @@ -7144,6 +7212,8 @@ static int ast_add_extension2_lockopt(struct ast_context *con, char expand_buf[VAR_BUF_SIZE]; struct ast_exten dummy_exten = {0}; char dummy_name[1024]; + int exten_fluff; + int callerid_fluff; if (ast_strlen_zero(extension)) { ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n", @@ -7166,15 +7236,26 @@ static int ast_add_extension2_lockopt(struct ast_context *con, } } + exten_fluff = ext_fluff_count(extension); + callerid_fluff = callerid ? ext_fluff_count(callerid) : 0; + length = sizeof(struct ast_exten); length += strlen(extension) + 1; + if (exten_fluff) { + length += strlen(extension) + 1 - exten_fluff; + } length += strlen(application) + 1; - if (label) + if (label) { length += strlen(label) + 1; - if (callerid) + } + if (callerid) { length += strlen(callerid) + 1; - else + if (callerid_fluff) { + length += strlen(callerid) + 1 - callerid_fluff; + } + } else { length ++; /* just the '\0' */ + } /* Be optimistic: Build the extension structure first */ if (!(tmp = ast_calloc(1, length))) @@ -7190,14 +7271,25 @@ static int ast_add_extension2_lockopt(struct ast_context *con, strcpy(p, label); p += strlen(label) + 1; } - tmp->exten = p; - p += ext_strncpy(p, extension, strlen(extension) + 1) + 1; + tmp->name = p; + p += ext_strncpy(p, extension, strlen(extension) + 1, 0) + 1; + if (exten_fluff) { + tmp->exten = p; + p += ext_strncpy(p, extension, strlen(extension) + 1, 1) + 1; + } else { + /* no fluff, we don't need a copy. */ + tmp->exten = tmp->name; + } tmp->priority = priority; - tmp->cidmatch = p; /* but use p for assignments below */ + tmp->cidmatch_display = tmp->cidmatch = p; /* but use p for assignments below */ /* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */ if (callerid) { - p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1; + p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0) + 1; + if (callerid_fluff) { + tmp->cidmatch = p; + p += ext_strncpy(p, callerid, strlen(callerid) + 1, 1) + 1; + } tmp->matchcid = AST_EXT_MATCHCID_ON; } else { *p++ = '\0'; @@ -7216,7 +7308,7 @@ static int ast_add_extension2_lockopt(struct ast_context *con, if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding an extension, and the trie exists, then we need to incrementally add this pattern to it. */ - ast_copy_string(dummy_name, extension, sizeof(dummy_name)); + ext_strncpy(dummy_name, tmp->exten, sizeof(dummy_name), 1); dummy_exten.exten = dummy_name; dummy_exten.matchcid = AST_EXT_MATCHCID_OFF; dummy_exten.cidmatch = 0; @@ -7320,19 +7412,19 @@ static int ast_add_extension2_lockopt(struct ast_context *con, if (option_debug) { if (tmp->matchcid == AST_EXT_MATCHCID_ON) { ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n", - tmp->exten, tmp->priority, tmp->cidmatch, con->name, con); + tmp->name, tmp->priority, tmp->cidmatch_display, con->name, con); } else { ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n", - tmp->exten, tmp->priority, con->name, con); + tmp->name, tmp->priority, con->name, con); } } if (tmp->matchcid == AST_EXT_MATCHCID_ON) { ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n", - tmp->exten, tmp->priority, tmp->cidmatch, con->name); + tmp->name, tmp->priority, tmp->cidmatch_display, con->name); } else { ast_verb(3, "Added extension '%s' priority %d to %s\n", - tmp->exten, tmp->priority, con->name); + tmp->name, tmp->priority, con->name); } return 0; @@ -7870,7 +7962,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context continue; } ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n", - tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "", con, con? con->root_table: NULL); + tmp->name, prio_item->name, prio_item->priority, registrar, con? con->name : "", con, con? con->root_table: NULL); ast_copy_string(extension, prio_item->exten, sizeof(extension)); if (prio_item->cidmatch) { ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch)); @@ -8290,7 +8382,7 @@ struct ast_context *ast_get_extension_context(struct ast_exten *exten) const char *ast_get_extension_name(struct ast_exten *exten) { - return exten ? exten->exten : NULL; + return exten ? exten->name : NULL; } const char *ast_get_extension_label(struct ast_exten *exten) @@ -8323,7 +8415,7 @@ int ast_get_extension_matchcid(struct ast_exten *e) const char *ast_get_extension_cidmatch(struct ast_exten *e) { - return e ? e->cidmatch : NULL; + return e ? e->cidmatch_display : NULL; } const char *ast_get_extension_app(struct ast_exten *e) From a7ae48441fe7027ff3d6a92b660cec51f9fe4030 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 29 Jul 2016 06:48:32 -0300 Subject: [PATCH 0614/1578] astconfigparser: Handle case where line is simply a comment. Change-Id: I2dea5815363f4d787d709228a04f33baee383ef5 --- contrib/scripts/sip_to_pjsip/astconfigparser.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/scripts/sip_to_pjsip/astconfigparser.py b/contrib/scripts/sip_to_pjsip/astconfigparser.py index 46f4fb484b2..a6d88c7b753 100644 --- a/contrib/scripts/sip_to_pjsip/astconfigparser.py +++ b/contrib/scripts/sip_to_pjsip/astconfigparser.py @@ -203,6 +203,9 @@ def remove_comment(line, is_comment): if match: # the end of where the real string is is where the comment starts line = line[0:(match.end()-1)] + elif line.startswith(";"): + # if the line is actually a comment just ignore it all + line = "" return line.replace("\\", "").strip(), False From 1cd79d6ee5e9fa53668a15e2fc5be2b7e6820b1f Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 29 Jul 2016 13:13:55 -0500 Subject: [PATCH 0615/1578] Remove SILK payload mappings from Asterisk core. SILK is a bit of a hog when it comes to using up our limited number of dynamic payload types in the RTP engine. By freeing up four slots, it allows for other codecs to potentially take the place. Now, codec_silk.so will dynamically use the payload slots in the RTP engine when it loads. A better fix would be make RTP dynamic payload types actually dynamic. However, at this stage of Asterisk 14 development, this is a risky move that would be imprudent. Change-Id: I5774e09408f9a203db189529eabdc0d3f4c1e612 --- main/rtp_engine.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 66b80e5557c..c2b1c8c2b7b 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2692,11 +2692,6 @@ int ast_rtp_engine_init(void) /* Opus and VP8 */ set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000); set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000); - /* DA SILK */ - set_next_mime_type(ast_format_silk8, 0, "audio", "silk", 8000); - set_next_mime_type(ast_format_silk12, 0, "audio", "silk", 12000); - set_next_mime_type(ast_format_silk16, 0, "audio", "silk", 16000); - set_next_mime_type(ast_format_silk24, 0, "audio", "silk", 24000); /* Define the static rtp payload mappings */ add_static_payload(0, ast_format_ulaw, 0); @@ -2750,11 +2745,6 @@ int ast_rtp_engine_init(void) add_static_payload(100, ast_format_vp8, 0); add_static_payload(107, ast_format_opus, 0); - add_static_payload(108, ast_format_silk8, 0); - add_static_payload(109, ast_format_silk12, 0); - add_static_payload(113, ast_format_silk16, 0); - add_static_payload(114, ast_format_silk24, 0); - return 0; } From f6276441b1f93f15cdf4a3586447db2a4f721417 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 1 Aug 2016 15:13:17 -0600 Subject: [PATCH 0616/1578] menuselect: Add an opaque "member_data" string to the acceptable xml Change-Id: Id5ac43b95c8d7395f3be37f983632169db3d1afe --- menuselect/menuselect.c | 6 ++++++ menuselect/menuselect.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/menuselect/menuselect.c b/menuselect/menuselect.c index f6a7fb39b2d..da972d8b12a 100644 --- a/menuselect/menuselect.c +++ b/menuselect/menuselect.c @@ -386,6 +386,11 @@ static int process_xml_use_node(xmlNode *node, struct member *mem) return process_xml_ref_node(node, mem, &mem->uses); } +static int process_xml_member_data_node(xmlNode *node, struct member *mem) +{ + return 0; +} + static int process_xml_unknown_node(xmlNode *node, struct member *mem) { fprintf(stderr, "Encountered unknown node: %s\n", node->name); @@ -404,6 +409,7 @@ static const struct { { "depend", process_xml_depend_node }, { "conflict", process_xml_conflict_node }, { "use", process_xml_use_node }, + { "member_data", process_xml_member_data_node }, }; static node_handler lookup_node_handler(xmlNode *node) diff --git a/menuselect/menuselect.h b/menuselect/menuselect.h index 328ac9a0ab8..bf2bf4c4fee 100644 --- a/menuselect/menuselect.h +++ b/menuselect/menuselect.h @@ -70,6 +70,8 @@ struct member { const char *touch_on_change; const char *support_level; const char *replacement; + /*! member_data is just an opaque, member-specific string */ + const char *member_data; /*! This module is currently selected */ unsigned int enabled:1; /*! This module was enabled when the config was loaded */ From 3ff964c6b6777dcdaffbeddb4df0c342296756f6 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 2 Aug 2016 10:08:34 +0200 Subject: [PATCH 0617/1578] res_pjsip: SIP/SDP origin (o=) contained square brackets on IP6 transports. ASTERISK-26256 #close Change-Id: I3fd68df561f81fdb8c6c497d465b50c12422f058 --- res/res_pjsip.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index f56790df701..ffbf880b11c 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2144,13 +2144,13 @@ static struct ast_threadpool *sip_threadpool; static pj_sockaddr host_ip_ipv4; /*! Local host address for IPv4 (string form) */ -static char host_ip_ipv4_string[PJ_INET6_ADDRSTRLEN + 2]; +static char host_ip_ipv4_string[PJ_INET6_ADDRSTRLEN]; /*! Local host address for IPv6 */ static pj_sockaddr host_ip_ipv6; /*! Local host address for IPv6 (string form) */ -static char host_ip_ipv6_string[PJ_INET6_ADDRSTRLEN + 2]; +static char host_ip_ipv6_string[PJ_INET6_ADDRSTRLEN]; static int register_service_noref(void *data) { @@ -4264,6 +4264,7 @@ static int unload_pjsip(void *data) static int load_pjsip(void) { + const unsigned int flags = 0; /* no port, no brackets */ pj_status_t status; /* The third parameter is just copied from @@ -4288,12 +4289,12 @@ static int load_pjsip(void) } if (!pj_gethostip(pj_AF_INET(), &host_ip_ipv4)) { - pj_sockaddr_print(&host_ip_ipv4, host_ip_ipv4_string, sizeof(host_ip_ipv4_string), 2); + pj_sockaddr_print(&host_ip_ipv4, host_ip_ipv4_string, sizeof(host_ip_ipv4_string), flags); ast_verb(3, "Local IPv4 address determined to be: %s\n", host_ip_ipv4_string); } if (!pj_gethostip(pj_AF_INET6(), &host_ip_ipv6)) { - pj_sockaddr_print(&host_ip_ipv6, host_ip_ipv6_string, sizeof(host_ip_ipv6_string), 2); + pj_sockaddr_print(&host_ip_ipv6, host_ip_ipv6_string, sizeof(host_ip_ipv6_string), flags); ast_verb(3, "Local IPv6 address determined to be: %s\n", host_ip_ipv6_string); } From 73bce50ef82c5a61f857ad1af0d63efd4175ac23 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 1 Aug 2016 16:08:15 +0000 Subject: [PATCH 0618/1578] sorcery: Use more compatible regex for local expressions. This changes the use of an empty regex for both res_sorcery_config and res_sorcery_memory to "." instead. This is a more compatible regular expression which also works on FreeBSD. ASTERISK-26206 #close Change-Id: Ia9166dd176f1597555ba22b6931180d0626c1388 --- res/res_sorcery_config.c | 4 ++++ res/res_sorcery_memory.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c index dd4ea888674..6059a529d8a 100644 --- a/res/res_sorcery_config.c +++ b/res/res_sorcery_config.c @@ -210,6 +210,10 @@ static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, voi .regex = &expression, }; + if (ast_strlen_zero(regex)) { + regex = "."; + } + if (!config_objects || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) { return; } diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c index db1fc1ab849..774c9552a60 100644 --- a/res/res_sorcery_memory.c +++ b/res/res_sorcery_memory.c @@ -188,6 +188,10 @@ static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, voi .regex = &expression, }; + if (ast_strlen_zero(regex)) { + regex = "."; + } + if (regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) { return; } From 90b30b21ac34f759dbe04fbb21fcdbbd1b645d21 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 3 Aug 2016 14:47:04 +0000 Subject: [PATCH 0619/1578] astconfigparser: Really handle case where line is simply a comment. The regular expression would match causing the code that handled the line if it was merely a comment to never get executed. Change-Id: I3e4022481037ebcba9905587fe8c764b4ce21819 --- contrib/scripts/sip_to_pjsip/astconfigparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/scripts/sip_to_pjsip/astconfigparser.py b/contrib/scripts/sip_to_pjsip/astconfigparser.py index a6d88c7b753..dc79e803218 100644 --- a/contrib/scripts/sip_to_pjsip/astconfigparser.py +++ b/contrib/scripts/sip_to_pjsip/astconfigparser.py @@ -203,7 +203,7 @@ def remove_comment(line, is_comment): if match: # the end of where the real string is is where the comment starts line = line[0:(match.end()-1)] - elif line.startswith(";"): + if line.startswith(";"): # if the line is actually a comment just ignore it all line = "" From 29b0f733a0ee97c39d8a5b7a5485779f4d80dc5b Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 3 Aug 2016 16:41:04 -0400 Subject: [PATCH 0620/1578] Add missing checks during startup. This ensures startup is canceled due to allocation failures from the following initializations. * channel.c: ast_channels_init * config_options.c: aco_init ASTERISK-26265 #close Change-Id: I911ed08fa2a3be35de55903e0225957bcdbe9611 --- include/asterisk/_private.h | 2 +- main/asterisk.c | 10 ++++++++-- main/channel.c | 8 +++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 6dbf24f4d85..36b316f2a32 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -29,7 +29,7 @@ void logger_queue_start(void); /*!< Provided by logger.c */ void clean_time_zones(void); /*!< Provided by localtime.c */ int ast_term_init(void); /*!< Provided by term.c */ int astdb_init(void); /*!< Provided by db.c */ -void ast_channels_init(void); /*!< Provided by channel.c */ +int ast_channels_init(void); /*!< Provided by channel.c */ void ast_builtins_init(void); /*!< Provided by cli.c */ int ast_cli_perms_init(int reload); /*!< Provided by cli.c */ int dnsmgr_init(void); /*!< Provided by dnsmgr.c */ diff --git a/main/asterisk.c b/main/asterisk.c index 850003b0564..05381fc1e6c 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4452,7 +4452,10 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou exit(1); } - aco_init(); + if (aco_init()) { + printf("Failed: aco_init\n%s", term_quit()); + exit(1); + } if (init_logger()) { /* Start logging subsystem */ printf("Failed: init_logger\n%s", term_quit()); @@ -4546,7 +4549,10 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou exit(1); } - ast_channels_init(); + if (ast_channels_init()) { + printf("Failed: ast_channels_init\n%s", term_quit()); + exit(1); + } if (ast_endpoint_init()) { printf ("Failed: ast_endpoint_init\n%s", term_quit()); diff --git a/main/channel.c b/main/channel.c index 911c269558d..1f18d53b15c 100644 --- a/main/channel.c +++ b/main/channel.c @@ -7803,13 +7803,14 @@ static void channels_shutdown(void) ast_channel_unregister(&surrogate_tech); } -void ast_channels_init(void) +int ast_channels_init(void) { channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS, ast_channel_hash_cb, ast_channel_cmp_cb); - if (channels) { - ao2_container_register("channels", channels, prnt_channel_key); + if (!channels) { + return -1; } + ao2_container_register("channels", channels, prnt_channel_key); ast_channel_register(&surrogate_tech); @@ -7823,6 +7824,7 @@ void ast_channels_init(void) ast_register_cleanup(channels_shutdown); + return 0; } /*! \brief Print call group and pickup group ---*/ From e711e57106369fabfe46eefb43f7c30134ffa4e9 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 4 Aug 2016 10:27:48 -0500 Subject: [PATCH 0621/1578] resource_channels: Sync with ARI stubs This file was out of sync with the current ARI definitions. Change-Id: Ie7cb7d6d3c2eeb9cc9d683ca87b43b117e713d0a --- res/ari/resource_channels.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h index 951433f1312..f68db2f5b32 100644 --- a/res/ari/resource_channels.h +++ b/res/ari/resource_channels.h @@ -116,7 +116,7 @@ struct ast_ari_channels_create_args { const char *other_channel_id; /*! Unique ID of the calling channel */ const char *originator; - /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */ + /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names can be found with "core show codecs". */ const char *formats; }; /*! From 54869e48231a8b24da4b91843e98c4779fb58abd Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 4 Aug 2016 15:16:33 +0000 Subject: [PATCH 0622/1578] res_pjsip_outbound_publish: Use a serializer shutdown group for unload. This change replaces the custom unload process for the outbound publish module with the common serializer shutdown group. ASTERISK-25217 #close Change-Id: I280a0384d860c486202d87d2d674394cca77ffb6 --- res/res_pjsip_outbound_publish.c | 143 +++++++++++++------------------ 1 file changed, 61 insertions(+), 82 deletions(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 53e15a0a48d..0aad5fcdb64 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -32,6 +32,7 @@ #include "asterisk/res_pjsip_outbound_publish.h" #include "asterisk/module.h" #include "asterisk/taskprocessor.h" +#include "asterisk/threadpool.h" #include "asterisk/datastore.h" /*** DOCUMENTATION @@ -204,6 +205,8 @@ struct sip_outbound_publisher { struct sip_outbound_publish_message *sending; /*! \brief Publish client should be destroyed */ unsigned int destroy; + /*! \brief Serializer for stuff and things */ + struct ast_taskprocessor *serializer; /*! \brief User, if any, associated with the publisher */ char user[0]; }; @@ -242,13 +245,11 @@ AST_RWLOCK_DEFINE_STATIC(load_lock); AO2_STRING_FIELD_HASH_FN(sip_outbound_publisher, user); AO2_STRING_FIELD_CMP_FN(sip_outbound_publisher, user); -/*! \brief Unloading data */ -struct unloading_data { - int is_unloading; - int count; - ast_mutex_t lock; - ast_cond_t cond; -} unloading; +/*! Time needs to be long enough for a transaction to timeout if nothing replies. */ +#define MAX_UNLOAD_TIMEOUT_TIME 35 /* Seconds */ + +/*! Shutdown group to monitor sip_outbound_registration_client_state serializers. */ +static struct ast_serializer_shutdown_group *shutdown_group; /*! \brief Default number of client state container buckets */ #define DEFAULT_STATE_BUCKETS 31 @@ -772,7 +773,7 @@ static int sip_publisher_service_queue(void *data) ast_free(message); service: - if (ast_sip_push_task(NULL, sip_publisher_service_queue, ao2_bump(publisher))) { + if (ast_sip_push_task(publisher->serializer, sip_publisher_service_queue, ao2_bump(publisher))) { ao2_ref(publisher, -1); } return -1; @@ -815,7 +816,7 @@ static int publisher_client_send(void *obj, void *arg, void *data, int flags) AST_LIST_INSERT_TAIL(&publisher->queue, message, entry); - *res = ast_sip_push_task(NULL, sip_publisher_service_queue, ao2_bump(publisher)); + *res = ast_sip_push_task(publisher->serializer, sip_publisher_service_queue, ao2_bump(publisher)); if (*res) { ao2_ref(publisher, -1); } @@ -1008,25 +1009,17 @@ static void sip_outbound_publisher_destroy(void *obj) } ao2_cleanup(publisher->owner); - ast_free(publisher->from_uri); ast_free(publisher->to_uri); - /* if unloading the module and all objects have been unpublished - send the signal to finish unloading */ - if (unloading.is_unloading) { - ast_mutex_lock(&unloading.lock); - if (--unloading.count == 0) { - ast_cond_signal(&unloading.cond); - } - ast_mutex_unlock(&unloading.lock); - } + ast_taskprocessor_unreference(publisher->serializer); } static struct sip_outbound_publisher *sip_outbound_publisher_alloc( struct ast_sip_outbound_publish_client *client, const char *user) { struct sip_outbound_publisher *publisher; + char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; publisher = ao2_alloc(sizeof(*publisher) + (user ? strlen(user) : 0) + 1, sip_outbound_publisher_destroy); @@ -1054,6 +1047,16 @@ static struct sip_outbound_publisher *sip_outbound_publisher_alloc( *publisher->user = '\0'; } + ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outpub/%s", + ast_sorcery_object_get_id(client->publish)); + + publisher->serializer = ast_sip_create_serializer_group(tps_name, + shutdown_group); + if (!publisher->serializer) { + ao2_ref(publisher, -1); + return NULL; + } + if (ast_sip_push_task_synchronous(NULL, sip_outbound_publisher_init, publisher)) { ast_log(LOG_ERROR, "Unable to create publisher for outbound publish '%s'\n", ast_sorcery_object_get_id(client->publish)); @@ -1079,7 +1082,7 @@ static struct sip_outbound_publisher *sip_outbound_publish_client_add_publisher( * No need to bump the reference here. The task will take care of * removing the reference. */ - if (ast_sip_push_task(NULL, cancel_refresh_timer_task, publisher)) { + if (ast_sip_push_task(publisher->serializer, cancel_refresh_timer_task, publisher)) { ao2_ref(publisher, -1); } return NULL; @@ -1142,13 +1145,13 @@ static int cancel_and_unpublish(void *obj, void *arg, int flags) /* If the publisher was never started, there's nothing to unpublish, so just * destroy the publication and remove its reference to the publisher. */ - if (ast_sip_push_task(NULL, explicit_publish_destroy, ao2_bump(publisher))) { + if (ast_sip_push_task(publisher->serializer, explicit_publish_destroy, ao2_bump(publisher))) { ao2_ref(publisher, -1); } return 0; } - if (ast_sip_push_task(NULL, cancel_refresh_timer_task, ao2_bump(publisher))) { + if (ast_sip_push_task(publisher->serializer, cancel_refresh_timer_task, ao2_bump(publisher))) { ast_log(LOG_WARNING, "Could not stop refresh timer on outbound publish '%s'\n", ast_sorcery_object_get_id(client->publish)); ao2_ref(publisher, -1); @@ -1156,7 +1159,7 @@ static int cancel_and_unpublish(void *obj, void *arg, int flags) /* If nothing is being sent right now send the unpublish - the destroy will happen in the subsequent callback */ if (!publisher->sending) { - if (ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(publisher))) { + if (ast_sip_push_task(publisher->serializer, send_unpublish_task, ao2_bump(publisher))) { ast_log(LOG_WARNING, "Could not send unpublish message on outbound publish '%s'\n", ast_sorcery_object_get_id(client->publish)); ao2_ref(publisher, -1); @@ -1255,7 +1258,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) if (publisher->sending) { publisher->sending = NULL; - if (!ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(publisher))) { + if (!ast_sip_push_task(publisher->serializer, send_unpublish_task, ao2_bump(publisher))) { return; } ast_log(LOG_WARNING, "Could not send unpublish message on outbound publish '%s'\n", @@ -1336,7 +1339,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) ast_free(message); } } else { - if (ast_sip_push_task(NULL, sip_publisher_service_queue, ao2_bump(publisher))) { + if (ast_sip_push_task(publisher->serializer, sip_publisher_service_queue, ao2_bump(publisher))) { ao2_ref(publisher, -1); } } @@ -1431,6 +1434,7 @@ static struct ast_sip_outbound_publish_state *sip_outbound_publish_state_alloc( ao2_ref(state, -1); return NULL; } + state->client->publish = ao2_bump(publish); strcpy(state->id, id); @@ -1580,6 +1584,32 @@ static int outbound_auth_handler(const struct aco_option *opt, struct ast_variab return ast_sip_auth_vector_init(&publish->outbound_auths, var->value); } + +static int unload_module(void) +{ + int remaining; + + ast_sorcery_object_unregister(ast_sip_get_sorcery(), "outbound-publish"); + + ao2_global_obj_release(current_states); + + /* Wait for publication serializers to get destroyed. */ + ast_debug(2, "Waiting for publication to complete for unload.\n"); + remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME); + if (remaining) { + ast_log(LOG_WARNING, "Unload incomplete. Could not stop %d outbound publications. Try again later.\n", + remaining); + return -1; + } + + ast_debug(2, "Successful shutdown.\n"); + + ao2_cleanup(shutdown_group); + shutdown_group = NULL; + + return 0; +} + static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); @@ -1587,12 +1617,18 @@ static int load_module(void) /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */ ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size); + shutdown_group = ast_serializer_shutdown_group_alloc(); + if (!shutdown_group) { + return AST_MODULE_LOAD_FAILURE; + } + ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_publish"); ast_sorcery_apply_default(ast_sip_get_sorcery(), "outbound-publish", "config", "pjsip.conf,criteria=type=outbound-publish"); if (ast_sorcery_object_register(ast_sip_get_sorcery(), "outbound-publish", sip_outbound_publish_alloc, NULL, sip_outbound_publish_apply)) { ast_log(LOG_ERROR, "Unable to register 'outbound-publish' type with sorcery\n"); + unload_module(); return AST_MODULE_LOAD_DECLINE; } @@ -1629,63 +1665,6 @@ static int reload_module(void) return 0; } -static int current_publishing_count(void *obj, void *arg, int flags) -{ - struct ast_sip_outbound_publish_state *state = obj; - unloading.count += ao2_container_count(state->client->publishers); - return 0; -} - -static int unload_module(void) -{ - struct timeval start = ast_tvnow(); - struct timespec end = { - .tv_sec = start.tv_sec + 10, - .tv_nsec = start.tv_usec * 1000 - }; - int res = 0; - struct ao2_container *states = ao2_global_obj_ref(current_states); - - if (!states) { - return 0; - } - - unloading.count = 0; - ao2_callback(states, OBJ_NODATA, current_publishing_count, NULL); - ao2_ref(states, -1); - - if (!unloading.count) { - return 0; - } - - ast_mutex_init(&unloading.lock); - ast_cond_init(&unloading.cond, NULL); - ast_mutex_lock(&unloading.lock); - - unloading.is_unloading = 1; - ao2_global_obj_release(current_states); - - /* wait for items to unpublish */ - ast_verb(5, "Waiting to complete unpublishing task(s)\n"); - while (unloading.count && !res) { - res = ast_cond_timedwait(&unloading.cond, &unloading.lock, &end); - } - ast_mutex_unlock(&unloading.lock); - - ast_mutex_destroy(&unloading.lock); - ast_cond_destroy(&unloading.cond); - - if (res) { - ast_verb(5, "At least %d items were unable to unpublish " - "in the allowed time\n", unloading.count); - } else { - ast_verb(5, "All items successfully unpublished\n"); - ast_sorcery_object_unregister(ast_sip_get_sorcery(), "outbound-publish"); - } - - return res; -} - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Publish Support", .load = load_module, .reload = reload_module, From 9042ad40f2a56d6cfd4117897cbc9943253d4e09 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 5 Aug 2016 16:34:15 -0400 Subject: [PATCH 0623/1578] app_voicemail: Add taskprocessor alert level options. On heavy loaded system with IMAP or DB storage, 'app_voicemail' taskprocessor queue could reach 500 scheduled tasks. It could happen when the IMAP or DB server dies or is unreachable. It could happen on startup when there are many (thousands) realtime endpoints configured with unsolicited mwi. If the taskprocessor queue reaches the high water level then the alert is triggered and pjsip stops processing new requests until the queue reaches the low water level to clear the alert. This patch adds 2 new 'general' configuration options to tune taskprocessor alert levels: 'tps_queue_high' - Taskprocessor high water alert trigger level. 'tps_queue_low' - Taskprocessor low water clear alert level ASTERISK-26229 #close Change-Id: I766294fbffedf64053c0d9ac0bedd3109f043ee8 --- CHANGES | 11 +++++++++++ apps/app_voicemail.c | 21 +++++++++++++++++++++ configs/samples/voicemail.conf.sample | 10 ++++++++++ 3 files changed, 42 insertions(+) diff --git a/CHANGES b/CHANGES index a43edab338d..3eadadf0927 100644 --- a/CHANGES +++ b/CHANGES @@ -378,6 +378,17 @@ cdr_csv post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 13.11.0 to Asterisk 13.12.0 ---------- +------------------------------------------------------------------------------ + +app_voicemail +------------------ + * Added "tps_queue_high" and "tps_queue_low" options. + The options can modify the taskprocessor alert levels for this module. + Additional information can be found in the sample configuration file at + config/samples/voicemail.conf.sample. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- ------------------------------------------------------------------------------ diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 894038bdbc0..4727e2ee5af 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -13532,6 +13532,8 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con int x; unsigned int tmpadsi[4]; char secretfn[PATH_MAX] = ""; + long tps_queue_low; + long tps_queue_high; #ifdef IMAP_STORAGE ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder)); @@ -14107,6 +14109,25 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con pagerbody = ast_strdup(substitute_escapes(val)); } + tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL; + if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_high"))) { + if (sscanf(val, "%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) { + ast_log(AST_LOG_WARNING, "Invalid the taskprocessor high water alert trigger level '%s'\n", val); + tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL; + } + } + tps_queue_low = -1; + if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_low"))) { + if (sscanf(val, "%30ld", &tps_queue_low) != 1 || + tps_queue_low < -1 || tps_queue_high < tps_queue_low) { + ast_log(AST_LOG_WARNING, "Invalid the taskprocessor low water clear alert level '%s'\n", val); + tps_queue_low = -1; + } + } + if (ast_taskprocessor_alert_set_levels(mwi_subscription_tps, tps_queue_low, tps_queue_high)) { + ast_log(AST_LOG_WARNING, "Failed to set alert levels for voicemail taskprocessor.\n"); + } + /* load mailboxes from users.conf */ if (ucfg) { for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) { diff --git a/configs/samples/voicemail.conf.sample b/configs/samples/voicemail.conf.sample index bb5f2495de4..248e142eb50 100644 --- a/configs/samples/voicemail.conf.sample +++ b/configs/samples/voicemail.conf.sample @@ -376,6 +376,16 @@ sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside ; defaults to being off ; backupdeleted=100 +; Asterisk Task Processor Queue Size +; On heavy loaded system you may need to increase 'app_voicemail' taskprocessor queue. +; If the taskprocessor queue size reached high water level, the alert is triggered. +; If the alert is set then some modules (for example pjsip) slow down its production +; until the alert is cleared. +; The alert is cleared when taskprocessor queue size drops to the low water clear level. +; The next options set taskprocessor queue levels for this module. +; tps_queue_high=500 ; Taskprocessor high water alert trigger level. +; tps_queue_low=450 ; Taskprocessor low water clear alert level. + ; The default is -1 for 90% of high water level. [zonemessages] ; Users may be located in different timezones, or may have different From b156a291aff717c24cd385bcc606da4992981cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 5 Aug 2016 23:06:53 -0400 Subject: [PATCH 0624/1578] cdr_adaptive_odbc: Fix DNSs mixed config quote quoted_identifiers When haved more than once DNSs config and one of their dont set quoted_identifiers and before this is with configurated with quoted_identifiers resulting a truncate statement for a reference null for quote character identifier. This patch initializes quoted flag before build SQL Query Example config for this bugfix case in cdr_adaptive_odbc.conf file [first] connection=asterisk-server1 table=cdr quoted_identifiers=" [second] connection=asterisk-server2 table=cdr [third] connection=asterisk-server3 table=cdr quoted_identifiers=` Change-Id: Ibd95667b468e10d4a19a2b9d88b9934ec7207e1d --- cdr/cdr_adaptive_odbc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cdr/cdr_adaptive_odbc.c b/cdr/cdr_adaptive_odbc.c index 0da8c01422d..f0bcc096253 100644 --- a/cdr/cdr_adaptive_odbc.c +++ b/cdr/cdr_adaptive_odbc.c @@ -408,6 +408,7 @@ static int odbc_log(struct ast_cdr *cdr) AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) { separator = ""; + quoted = 0; if (tableptr->quoted_identifiers != '\0'){ quoted = 1; } From 0749f6e6f3b39288309c546d547a1b09c9eef685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sat, 6 Aug 2016 02:37:35 -0400 Subject: [PATCH 0625/1578] res_odbc: Show only when there a fail attempt of connection in CLI When is executed CLI command "odbc show all" every time is show information about variable last_negative_connect. If not there a fail attempt of connection will show date like "1969-12-31 21:00:00". This patch fix there situation for to show only this information when exists a fail attempt before. Change-Id: I7c058b0be6f7642e922de75ee6b82c7276c9f113 --- res/res_odbc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/res/res_odbc.c b/res/res_odbc.c index bd64b9fef67..62faf98b26c 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -668,10 +668,14 @@ static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_c char timestr[80]; struct ast_tm tm; - ast_localtime(&class->last_negative_connect, &tm, NULL); - ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm); ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn); - ast_cli(a->fd, " Last connection attempt: %s\n", timestr); + + if (class->last_negative_connect.tv_sec > 0) { + ast_localtime(&class->last_negative_connect, &tm, NULL); + ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm); + ast_cli(a->fd, " Last fail connection attempt: %s\n", timestr); + } + ast_cli(a->fd, " Number of active connections: %zd (out of %d)\n", class->connection_cnt, class->maxconnections); ast_cli(a->fd, "\n"); } From 403b63571c53719bc050f4aded696cd933995d24 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 8 Aug 2016 13:53:32 -0400 Subject: [PATCH 0626/1578] res_pjsip_mwi: fix unsolicited mwi blocks PJSIP stack The PJSIP taskprocessors could be overflowed on startup if there are many (thousands) realtime endpoints configured with unsolicited mwi. The PJSIP stack could be totally unresponsive for a few minutes after boot completed. This patch creates a separate PJSIP serializers pool for mwi and makes unsolicited mwi use serializers from this pool. This patch also adds 2 new global options to tune taskprocessor alert levels: 'mwi_tps_queue_high' and 'mwi_tps_queue_low'. This patch also adds new global option 'mwi_disable_initial_unsolicited' to disable sending unsolicited mwi to all endpoints on startup. If disabled then unsolicited mwi will start processing on next endpoint's contact update. ASTERISK-26230 #close Change-Id: I4c8ecb82c249eb887930980a800c9f87f28f861a --- CHANGES | 9 ++ configs/samples/pjsip.conf.sample | 21 +++ ...a44a5a0851_pjsip_add_global_mwi_options.py | 35 +++++ include/asterisk/res_pjsip.h | 26 ++++ res/res_pjsip.c | 42 ++++++ res/res_pjsip/config_global.c | 68 +++++++++ res/res_pjsip_mwi.c | 138 +++++++++++++++++- 7 files changed, 333 insertions(+), 6 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/c7a44a5a0851_pjsip_add_global_mwi_options.py diff --git a/CHANGES b/CHANGES index 3eadadf0927..b353e96a3a5 100644 --- a/CHANGES +++ b/CHANGES @@ -389,6 +389,15 @@ app_voicemail Additional information can be found in the sample configuration file at config/samples/voicemail.conf.sample. +res_pjsip_mwi +------------------ + * Added "mwi_tps_queue_high" and "mwi_tps_queue_low" global configuration + options to tune taskprocessor alert levels. + * Added "mwi_disable_initial_unsolicited" global configuration option + to disable sending unsolicited MWI to all endpoints on startup. + Additional information can be found in the sample configuration file at + config/samples/pjsip.conf.sample. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- ------------------------------------------------------------------------------ diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 99bdfb99d0a..eac0549049f 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -964,6 +964,27 @@ ; set to this value if there is no better option (such as ; auth/realm) to be used + ; Asterisk Task Processor Queue Size + ; On heavy loaded system with DB storage you may need to increase + ; taskprocessor queue. + ; If the taskprocessor queue size reached high water level, + ; the alert is triggered. + ; If the alert is set the pjsip distibutor stops processing incoming + ; requests until the alert is cleared. + ; The alert is cleared when taskprocessor queue size drops to the + ; low water clear level. + ; The next options set taskprocessor queue levels for MWI. +;mwi_tps_queue_high=500 ; Taskprocessor high water alert trigger level. +;mwi_tps_queue_low=450 ; Taskprocessor low water clear alert level. + ; The default is -1 for 90% of high water level. + + ; Unsolicited MWI + ; If there are endpoints configured with unsolicited MWI + ; then res_pjsip_mwi module tries to send MWI to all endpoints on startup. +;mwi_disable_initial_unsolicited=no ; Disable sending unsolicited mwi to all endpoints on startup. + ; If disabled then unsolicited mwi will start processing + ; on the endpoint's next contact update. + ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl ;==========================ACL SECTION OPTIONS========================= ;[acl] diff --git a/contrib/ast-db-manage/config/versions/c7a44a5a0851_pjsip_add_global_mwi_options.py b/contrib/ast-db-manage/config/versions/c7a44a5a0851_pjsip_add_global_mwi_options.py new file mode 100644 index 00000000000..d3efa2278a5 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/c7a44a5a0851_pjsip_add_global_mwi_options.py @@ -0,0 +1,35 @@ +"""pjsip: add global MWI options + +Revision ID: c7a44a5a0851 +Revises: 4a6c67fa9b7a +Create Date: 2016-08-03 15:08:22.524727 + +""" + +# revision identifiers, used by Alembic. +revision = 'c7a44a5a0851' +down_revision = '4a6c67fa9b7a' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_globals', sa.Column('mwi_tps_queue_high', sa.Integer)) + op.add_column('ps_globals', sa.Column('mwi_tps_queue_low', sa.Integer)) + op.add_column('ps_globals', sa.Column('mwi_disable_initial_unsolicited', yesno_values)) + +def downgrade(): + op.drop_column('ps_globals', 'mwi_tps_queue_high') + op.drop_column('ps_globals', 'mwi_tps_queue_low') + op.drop_column('ps_globals', 'mwi_disable_initial_unsolicited') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 9bb2a82c5de..cd6b33db47f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2416,6 +2416,32 @@ int ast_sip_register_supplement(struct ast_sip_supplement *supplement); */ void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement); +/*! + * \brief Retrieve the global MWI taskprocessor high water alert trigger level. + * + * \since 13.12.0 + * + * \retval the system MWI taskprocessor high water alert trigger level + */ +unsigned int ast_sip_get_mwi_tps_queue_high(void); + +/*! + * \brief Retrieve the global MWI taskprocessor low water clear alert level. + * + * \since 13.12.0 + * + * \retval the system MWI taskprocessor low water clear alert level + */ +int ast_sip_get_mwi_tps_queue_low(void); + +/*! + * \brief Retrieve the global setting 'disable sending unsolicited mwi on startup'. + * \since 13.12.0 + * + * \retval non zero if disable. + */ +unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void); + /*! * \brief Retrieve the system debug setting (yes|no|host). * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index ffbf880b11c..8a9a19db89b 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1499,6 +1499,48 @@ set to this value if there is no better option (such as auth/realm) to be used. + + MWI taskprocessor high water alert trigger level. + + On a heavily loaded system you may need to adjust the + taskprocessor queue limits. If any taskprocessor queue size + reaches its high water level then pjsip will stop processing + new requests until the alert is cleared. The alert clears + when all alerting taskprocessor queues have dropped to their + low water clear level. + + + + + MWI taskprocessor low water clear alert level. + + On a heavily loaded system you may need to adjust the + taskprocessor queue limits. If any taskprocessor queue size + reaches its high water level then pjsip will stop processing + new requests until the alert is cleared. The alert clears + when all alerting taskprocessor queues have dropped to their + low water clear level. + + Set to -1 for the low water level to be 90% of + the high water level. + + + + Enable/Disable sending unsolicited MWI to all endpoints on startup. + + When the initial unsolicited MWI notification are + enabled on startup then the initial notifications + get sent at startup. If you have a lot of endpoints + (thousands) that use unsolicited MWI then you may + want to consider disabling the initial startup + notifications. + + When the initial unsolicited MWI notifications are + disabled on startup then the notifications will start + on the endpoint's next contact update. + + + diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index 6bb68880494..8a1b0d449f5 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -24,6 +24,7 @@ #include "asterisk/res_pjsip.h" #include "include/res_pjsip_private.h" #include "asterisk/sorcery.h" +#include "asterisk/taskprocessor.h" #include "asterisk/ast_version.h" #include "asterisk/res_pjsip_cli.h" @@ -43,6 +44,9 @@ #define DEFAULT_UNIDENTIFIED_REQUEST_COUNT 5 #define DEFAULT_UNIDENTIFIED_REQUEST_PERIOD 5 #define DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL 30 +#define DEFAULT_MWI_TPS_QUEUE_HIGH AST_TASKPROCESSOR_HIGH_WATER_LEVEL +#define DEFAULT_MWI_TPS_QUEUE_LOW -1 +#define DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED 0 static char default_useragent[256]; @@ -79,6 +83,14 @@ struct global_config { unsigned int unidentified_request_period; /* Interval at which expired unidentifed requests will be pruned */ unsigned int unidentified_request_prune_interval; + struct { + /*! Taskprocessor high water alert trigger level */ + unsigned int tps_queue_high; + /*! Taskprocessor low water clear alert level. */ + int tps_queue_low; + /*! Nonzero to disable sending unsolicited mwi to all endpoints on startup */ + unsigned int disable_initial_unsolicited; + } mwi; }; static void global_destructor(void *obj) @@ -314,6 +326,53 @@ void ast_sip_get_default_from_user(char *from_user, size_t size) } } + +unsigned int ast_sip_get_mwi_tps_queue_high(void) +{ + unsigned int tps_queue_high; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return DEFAULT_MWI_TPS_QUEUE_HIGH; + } + + tps_queue_high = cfg->mwi.tps_queue_high; + ao2_ref(cfg, -1); + return tps_queue_high; +} + +int ast_sip_get_mwi_tps_queue_low(void) +{ + int tps_queue_low; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return DEFAULT_MWI_TPS_QUEUE_LOW; + } + + tps_queue_low = cfg->mwi.tps_queue_low; + ao2_ref(cfg, -1); + return tps_queue_low; +} + +unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void) +{ + unsigned int disable_initial_unsolicited; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED; + } + + disable_initial_unsolicited = cfg->mwi.disable_initial_unsolicited; + ao2_ref(cfg, -1); + return disable_initial_unsolicited; +} + + /*! * \internal * \brief Observer to set default global object if none exist. @@ -450,6 +509,15 @@ int ast_sip_initialize_sorcery_global(void) OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_prune_interval)); ast_sorcery_object_field_register(sorcery, "global", "default_realm", DEFAULT_REALM, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_realm)); + ast_sorcery_object_field_register(sorcery, "global", "mwi_tps_queue_high", + __stringify(DEFAULT_MWI_TPS_QUEUE_HIGH), + OPT_UINT_T, 0, FLDSET(struct global_config, mwi.tps_queue_high)); + ast_sorcery_object_field_register(sorcery, "global", "mwi_tps_queue_low", + __stringify(DEFAULT_MWI_TPS_QUEUE_LOW), + OPT_INT_T, 0, FLDSET(struct global_config, mwi.tps_queue_low)); + ast_sorcery_object_field_register(sorcery, "global", "mwi_disable_initial_unsolicited", + DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED ? "yes" : "no", + OPT_BOOL_T, 1, FLDSET(struct global_config, mwi.disable_initial_unsolicited)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index d86c96c7449..bf7f042760e 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -35,6 +35,7 @@ #include "asterisk/module.h" #include "asterisk/logger.h" #include "asterisk/astobj2.h" +#include "asterisk/taskprocessor.h" #include "asterisk/sorcery.h" #include "asterisk/stasis.h" #include "asterisk/app.h" @@ -52,6 +53,12 @@ static char *default_voicemail_extension; #define MWI_DATASTORE "MWI datastore" +/*! Number of serializers in pool if one not supplied. */ +#define MWI_SERIALIZER_POOL_SIZE 8 + +/*! Pool of serializers to use if not supplied. */ +static struct ast_taskprocessor *mwi_serializer_pool[MWI_SERIALIZER_POOL_SIZE]; + static void mwi_subscription_shutdown(struct ast_sip_subscription *sub); static void mwi_to_ami(struct ast_sip_subscription *sub, struct ast_str **buf); static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint, @@ -119,6 +126,117 @@ struct mwi_subscription { char id[1]; }; +/*! + * \internal + * \brief Shutdown the serializers in the mwi pool. + * \since 13.12.0 + * + * \return Nothing + */ +static void mwi_serializer_pool_shutdown(void) +{ + int idx; + + for (idx = 0; idx < MWI_SERIALIZER_POOL_SIZE; ++idx) { + ast_taskprocessor_unreference(mwi_serializer_pool[idx]); + mwi_serializer_pool[idx] = NULL; + } +} + +/*! + * \internal + * \brief Setup the serializers in the mwi pool. + * \since 13.12.0 + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int mwi_serializer_pool_setup(void) +{ + char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; + int idx; + + for (idx = 0; idx < MWI_SERIALIZER_POOL_SIZE; ++idx) { + /* Create name with seq number appended. */ + ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/mwi"); + + mwi_serializer_pool[idx] = ast_sip_create_serializer(tps_name); + if (!mwi_serializer_pool[idx]) { + mwi_serializer_pool_shutdown(); + return -1; + } + } + return 0; +} + +/*! + * \internal + * \brief Pick a mwi serializer from the pool. + * \since 13.12.0 + * + * \retval least queue size task processor. + */ +static struct ast_taskprocessor *get_mwi_serializer(void) +{ + int idx; + int pos; + + if (!mwi_serializer_pool[0]) { + return NULL; + } + + for (pos = idx = 0; idx < MWI_SERIALIZER_POOL_SIZE; ++idx) { + if (ast_taskprocessor_size(mwi_serializer_pool[idx]) < ast_taskprocessor_size(mwi_serializer_pool[pos])) { + pos = idx; + } + } + + return mwi_serializer_pool[pos]; +} + +/*! + * \internal + * \brief Set taskprocessor alert levels for the serializers in the mwi pool. + * \since 13.12.0 + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int mwi_serializer_set_alert_levels(void) +{ + int idx; + long tps_queue_high; + long tps_queue_low; + + if (!mwi_serializer_pool[0]) { + return -1; + } + + tps_queue_high = ast_sip_get_mwi_tps_queue_high(); + if (tps_queue_high <= 0) { + ast_log(AST_LOG_WARNING, "Invalid taskprocessor high water alert trigger level '%ld'\n", + tps_queue_high); + tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL; + } + + tps_queue_low = ast_sip_get_mwi_tps_queue_low(); + if (tps_queue_low < -1 || tps_queue_high < tps_queue_low) { + ast_log(AST_LOG_WARNING, "Invalid taskprocessor low water clear alert level '%ld'\n", + tps_queue_low); + tps_queue_low = -1; + } + + for (idx = 0; idx < MWI_SERIALIZER_POOL_SIZE; ++idx) { + if (ast_taskprocessor_alert_set_levels(mwi_serializer_pool[idx], tps_queue_low, tps_queue_high)) { + ast_log(AST_LOG_WARNING, "Failed to set alert levels for MWI serializer pool #%d.\n", + idx); + } + } + + return 0; +} + + static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg); @@ -945,7 +1063,7 @@ static int send_notify(void *obj, void *arg, int flags) struct mwi_subscription *mwi_sub = obj; struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) - : NULL; + : get_mwi_serializer(); if (ast_sip_push_task(serializer, serialized_notify, ao2_bump(mwi_sub))) { ao2_ref(mwi_sub, -1); @@ -1063,7 +1181,7 @@ static int send_contact_notify(void *obj, void *arg, int flags) return 0; } - if (ast_sip_push_task(NULL, serialized_notify, ao2_bump(mwi_sub))) { + if (ast_sip_push_task(get_mwi_serializer(), serialized_notify, ao2_bump(mwi_sub))) { ao2_ref(mwi_sub, -1); } @@ -1149,6 +1267,7 @@ static void global_loaded(const char *object_type) { ast_free(default_voicemail_extension); default_voicemail_extension = ast_sip_get_default_voicemail_extension(); + mwi_serializer_set_alert_levels(); } static struct ast_sorcery_observer global_observer = { @@ -1175,15 +1294,21 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } + if (mwi_serializer_pool_setup()) { + ast_log(AST_LOG_WARNING, "Failed to create MWI serializer pool. The default SIP pool will be used for MWI\n"); + } + create_mwi_subscriptions(); ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer); ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); - if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { - ast_sip_push_task(NULL, send_initial_notify_all, NULL); - } else { - stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL); + if (!ast_sip_get_mwi_disable_initial_unsolicited()) { + if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { + ast_sip_push_task(NULL, send_initial_notify_all, NULL); + } else { + stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL); + } } return AST_MODULE_LOAD_SUCCESS; @@ -1193,6 +1318,7 @@ static int unload_module(void) { ao2_callback(unsolicited_mwi, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL); ao2_ref(unsolicited_mwi, -1); + mwi_serializer_pool_shutdown(); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); ast_sip_unregister_subscription_handler(&mwi_handler); From 827457dca0c9073b93822db45c859c7ae83ece76 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 8 Aug 2016 20:14:20 -0400 Subject: [PATCH 0627/1578] Produce friendly error when AST_MODULE_SELF_SYM is not defined. Modules must define AST_MODULE_SELF_SYM to be used as the name of a generated function. This produces a friendly error when it's not defined. ASTERISK-26278 #close Change-Id: Ib9d35a08104529c516d636771365e02c6e77a45b --- codecs/lpc10/Makefile | 2 +- include/asterisk.h | 4 ++++ main/Makefile | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/codecs/lpc10/Makefile b/codecs/lpc10/Makefile index bdf1a3ad7fc..b414fd77d7a 100644 --- a/codecs/lpc10/Makefile +++ b/codecs/lpc10/Makefile @@ -25,7 +25,7 @@ CFLAGS+= -fPIC -Wno-comment # The code here generates lots of warnings, so compiling with -Werror # fails miserably. Remove it for the time being. -_ASTCFLAGS:=$(_ASTCFLAGS:-Werror=) +_ASTCFLAGS:=$(_ASTCFLAGS:-Werror=) -DAST_MODULE_SELF_SYM=__internal_codec_lpc10_self LIB = $(LIB_TARGET_DIR)/liblpc10.a diff --git a/include/asterisk.h b/include/asterisk.h index e509fbc39e0..93c7cfb28db 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -286,6 +286,10 @@ struct ast_module; /* Internal/forward declaration, AST_MODULE_SELF should be used instead. */ struct ast_module *AST_MODULE_SELF_SYM(void); +#else + +#error "Externally compiled modules must declare AST_MODULE_SELF_SYM." + #endif /*! diff --git a/main/Makefile b/main/Makefile index 729ae9c0131..663508a7546 100644 --- a/main/Makefile +++ b/main/Makefile @@ -284,7 +284,7 @@ ifeq ($(GNU_LD),1) endif $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB) $(PJ_LDFLAGS) -$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS) +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" -DAST_NOT_MODULE $(PJ_CFLAGS) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lrt -lpthread ifeq ($(GNU_LD),1) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): SO_SUPPRESS_SYMBOLS=-Wl,--version-script,libasteriskpj.exports,--warn-common From 8fe9f1f7f1c37b2021483834f638972698d16ead Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 9 Aug 2016 16:19:34 -0500 Subject: [PATCH 0628/1578] res_rtp_asterisk: Cache local RTCP address. When an RTCP packet is sent or received, res_rtp_asterisk generates a Stasis event that contains the RTCP report as well as the local and remote addresses that the report pertains to. The addresses are determined using ast_find_ourip(). For the local address, this will typically result in a lookup of the hostname of the server, and then a DNS lookup of that hostname. If you do not have the host in /etc/hosts, then this results in a full DNS lookup, which can potentially block for some time. This is especially problematic when performing RTCP reads, since those are done on the same thread responsible for reading and writing media. This patch addresses the issue by performing a lookup of the local address when RTCP is allocated. We then use this cached local address for the Stasis events when necessary. ASTERISK-26280 #close Reported by Mark Michelson Change-Id: I3dd61882c2e57036f09f0c390cf38f7c87e9b556 --- res/res_rtp_asterisk.c | 69 ++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 6cf69ef0d7e..a8d4a90775b 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -407,6 +407,12 @@ struct ast_rtcp { #ifdef HAVE_OPENSSL_SRTP struct dtls_details dtls; /*!< DTLS state information */ #endif + + /* Cached local address string allows us to generate + * RTCP stasis messages without having to look up our + * own address every time + */ + char *local_addr_str; }; struct rtp_red { @@ -2700,6 +2706,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) * RTP instance while it's active. */ close(rtp->rtcp->s); + ast_free(rtp->rtcp->local_addr_str); ast_free(rtp->rtcp); } @@ -3112,12 +3119,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) int rate = rtp_get_rate(rtp->f.subclass.format); int ice; int header_offset = 0; - char *str_remote_address; - char *str_local_address; struct ast_sockaddr remote_address = { { 0, } }; - struct ast_sockaddr local_address = { { 0, } }; - struct ast_sockaddr real_remote_address = { { 0, } }; - struct ast_sockaddr real_local_address = { { 0, } }; struct ast_rtp_rtcp_report_block *report_block = NULL; RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, ast_rtp_rtcp_report_alloc(rtp->themssrc ? 1 : 0), @@ -3244,22 +3246,9 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) } } - ast_rtp_instance_get_local_address(instance, &local_address); - if (!ast_find_ourip(&real_local_address, &local_address, 0)) { - str_local_address = ast_strdupa(ast_sockaddr_stringify(&real_local_address)); - } else { - str_local_address = ast_strdupa(ast_sockaddr_stringify(&local_address)); - } - - if (!ast_find_ourip(&real_remote_address, &remote_address, 0)) { - str_remote_address = ast_strdupa(ast_sockaddr_stringify(&real_remote_address)); - } else { - str_remote_address = ast_strdupa(ast_sockaddr_stringify(&remote_address)); - } - message_blob = ast_json_pack("{s: s, s: s}", - "to", str_remote_address, - "from", str_local_address); + "to", ast_sockaddr_stringify(&remote_address), + "from", rtp->rtcp->local_addr_str); ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(), rtcp_report, message_blob); @@ -4067,11 +4056,6 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) int report_counter = 0; struct ast_rtp_rtcp_report_block *report_block; struct ast_frame *f = &ast_null_frame; - char *str_local_address; - char *str_remote_address; - struct ast_sockaddr local_address = { { 0,} }; - struct ast_sockaddr real_local_address = { { 0, } }; - struct ast_sockaddr real_remote_address = { { 0, } }; /* Read in RTCP data from the socket */ if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET, @@ -4128,8 +4112,6 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) ast_debug(1, "Got RTCP report of %d bytes\n", res); - ast_rtp_instance_get_local_address(instance, &local_address); - while (position < packetwords) { int i, pt, rc; unsigned int length; @@ -4245,21 +4227,10 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) /* If and when we handle more than one report block, this should occur outside * this loop. */ - if (!ast_find_ourip(&real_local_address, &local_address, 0)) { - str_local_address = ast_strdupa(ast_sockaddr_stringify(&real_local_address)); - } else { - str_local_address = ast_strdupa(ast_sockaddr_stringify(&local_address)); - } - - if (!ast_find_ourip(&real_remote_address, &addr, 0)) { - str_remote_address = ast_strdupa(ast_sockaddr_stringify(&real_remote_address)); - } else { - str_remote_address = ast_strdupa(ast_sockaddr_stringify(&addr)); - } message_blob = ast_json_pack("{s: s, s: s, s: f}", - "from", str_remote_address, - "to", str_local_address, + "from", ast_sockaddr_stringify(&rtp->rtcp->them), + "to", rtp->rtcp->local_addr_str, "rtt", rtp->rtcp->rtt); ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(), rtcp_report, @@ -4822,6 +4793,8 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro if (property == AST_RTP_PROPERTY_RTCP) { if (value) { + struct ast_sockaddr local_addr; + if (rtp->rtcp) { ast_debug(1, "Ignoring duplicate RTCP property on RTP instance '%p'\n", instance); return; @@ -4836,6 +4809,19 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro ast_sockaddr_set_port(&rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us) + 1); + if (!ast_find_ourip(&local_addr, &rtp->rtcp->us, 0)) { + ast_sockaddr_set_port(&local_addr, ast_sockaddr_port(&rtp->rtcp->us)); + } else { + ast_sockaddr_copy(&local_addr, &rtp->rtcp->us); + } + + rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local_addr)); + if (!rtp->rtcp->local_addr_str) { + ast_free(rtp->rtcp); + rtp->rtcp = NULL; + return; + } + if ((rtp->rtcp->s = create_new_socket("RTCP", ast_sockaddr_is_ipv4(&rtp->rtcp->us) ? @@ -4843,6 +4829,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro ast_sockaddr_is_ipv6(&rtp->rtcp->us) ? AF_INET6 : -1)) < 0) { ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance); + ast_free(rtp->rtcp->local_addr_str); ast_free(rtp->rtcp); rtp->rtcp = NULL; return; @@ -4852,6 +4839,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) { ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance); close(rtp->rtcp->s); + ast_free(rtp->rtcp->local_addr_str); ast_free(rtp->rtcp); rtp->rtcp = NULL; return; @@ -4891,6 +4879,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro SSL_free(rtp->rtcp->dtls.ssl); } #endif + ast_free(rtp->rtcp->local_addr_str); ast_free(rtp->rtcp); rtp->rtcp = NULL; } From c315460abbb6ce30423c4d5bb092f4ac17ef2cc2 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sun, 7 Aug 2016 09:58:59 -0500 Subject: [PATCH 0629/1578] channels/chan_pjsip: Add PJSIP_SEND_SESSION_REFRESH This patch adds a new PJSIP specific dialplan function, PJSIP_SEND_SESSION_REFRESH. When invoked on a PJSIP channel, the media session will be refreshed via either an UPDATE or re-INVITE request. When used in conjunction with the PJSIP_MEDIA_OFFER dialplan function, the formats in use on a PJSIP channel can be re-negotiated and changed dynamically after call setup. ASTERISK-26277 #close Change-Id: Ib98fe09ba889aafe26d58d32f0fd1323f8fd9b1b (cherry picked from commit eec60dd77394f0519895fc6abce3a6f90f6470f1) --- CHANGES | 51 +++++---- channels/chan_pjsip.c | 12 ++ channels/pjsip/dialplan_functions.c | 116 +++++++++++++++++++- channels/pjsip/include/dialplan_functions.h | 12 ++ 4 files changed, 170 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index b353e96a3a5..ee746253288 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,37 @@ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ + +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- +------------------------------------------------------------------------------ + +app_voicemail +------------------ + * Added "tps_queue_high" and "tps_queue_low" options. + The options can modify the taskprocessor alert levels for this module. + Additional information can be found in the sample configuration file at + config/samples/voicemail.conf.sample. + +res_pjsip_mwi +------------------ + * Added "mwi_tps_queue_high" and "mwi_tps_queue_low" global configuration + options to tune taskprocessor alert levels. + + * Added "mwi_disable_initial_unsolicited" global configuration option + to disable sending unsolicited MWI to all endpoints on startup. + Additional information can be found in the sample configuration file at + config/samples/pjsip.conf.sample. + +chan_pjsip +------------------ + * A new dialplan function, PJSIP_SEND_SESSION_REFRESH, has been added. When + invoked, a re-INVITE or UPDATE request will be sent immediately to the + endpoint underlying the channel. When used in combination with the existing + dialplan function PJSIP_MEDIA_OFFER, this allows the formats on a PJSIP + channel to be re-negotiated and updated after session set up. + + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ @@ -378,26 +409,6 @@ cdr_csv post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. ------------------------------------------------------------------------------- ---- Functionality changes from Asterisk 13.11.0 to Asterisk 13.12.0 ---------- ------------------------------------------------------------------------------- - -app_voicemail ------------------- - * Added "tps_queue_high" and "tps_queue_low" options. - The options can modify the taskprocessor alert levels for this module. - Additional information can be found in the sample configuration file at - config/samples/voicemail.conf.sample. - -res_pjsip_mwi ------------------- - * Added "mwi_tps_queue_high" and "mwi_tps_queue_low" global configuration - options to tune taskprocessor alert levels. - * Added "mwi_disable_initial_unsolicited" global configuration option - to disable sending unsolicited MWI to all endpoints on startup. - Additional information can be found in the sample configuration file at - config/samples/pjsip.conf.sample. - ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- ------------------------------------------------------------------------------ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 2e87393a699..02da0db35b1 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2433,6 +2433,11 @@ static struct ast_custom_function media_offer_function = { .write = pjsip_acf_media_offer_write }; +static struct ast_custom_function session_refresh_function = { + .name = "PJSIP_SEND_SESSION_REFRESH", + .write = pjsip_acf_session_refresh_write, +}; + /*! * \brief Load the module * @@ -2472,6 +2477,11 @@ static int load_module(void) goto end; } + if (ast_custom_function_register(&session_refresh_function)) { + ast_log(LOG_WARNING, "Unable to register PJSIP_SEND_SESSION_REFRESH dialplan function\n"); + goto end; + } + if (ast_sip_session_register_supplement(&chan_pjsip_supplement)) { ast_log(LOG_ERROR, "Unable to register PJSIP supplement\n"); goto end; @@ -2528,6 +2538,7 @@ static int load_module(void) pjsip_uids_onhold = NULL; ast_custom_function_unregister(&media_offer_function); ast_custom_function_unregister(&chan_pjsip_dial_contacts_function); + ast_custom_function_unregister(&session_refresh_function); ast_channel_unregister(&chan_pjsip_tech); ast_rtp_glue_unregister(&chan_pjsip_rtp_glue); @@ -2549,6 +2560,7 @@ static int unload_module(void) ast_custom_function_unregister(&media_offer_function); ast_custom_function_unregister(&chan_pjsip_dial_contacts_function); + ast_custom_function_unregister(&session_refresh_function); ast_channel_unregister(&chan_pjsip_tech); ao2_ref(chan_pjsip_tech.capabilities, -1); diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 1c089973221..c1a3873d04c 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -59,8 +59,55 @@ - Returns the codecs offered based upon the media choice + When read, returns the codecs offered based upon the media choice. + When written, sets the codecs to offer when an outbound dial attempt is made, + or when a session refresh is sent using PJSIP_SEND_SESSION_REFRESH. + + + PJSIP_SEND_SESSION_REFRESH + + + + + W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session + + + + The type of update to send. Default is invite. + + + Send the session refresh as a re-INVITE. + + + Send the session refresh as an UPDATE. + + + + + + This function will cause the PJSIP stack to immediately refresh + the media session for the channel. This will be done using either a + re-INVITE (default) or an UPDATE request. + + This is most useful when combined with the PJSIP_MEDIA_OFFER + dialplan function, as it allows the formats in use on a channel to be + re-negotiated after call setup. + + The formats the endpoint supports are not + checked or enforced by this function. Using this function to offer + formats not supported by the endpoint may result + in a loss of media. + + + ; Within some existing extension on an answered channel + same => n,Set(PJSIP_MEDIA_OFFER(audio)=!all,g722) + same => n,Set(PJSIP_SEND_SESSION_REFRESH()=invite) + + + + PJSIP_MEDIA_OFFER + @@ -961,3 +1008,70 @@ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata); } + +struct refresh_data { + struct ast_sip_session *session; + enum ast_sip_session_refresh_method method; +}; + +static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata) +{ + struct ast_format *fmt; + + if (!session->channel) { + /* Egads! */ + return 0; + } + + fmt = ast_format_cap_get_best_by_type(ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_AUDIO); + if (!fmt) { + /* No format? That's weird. */ + return 0; + } + ast_channel_set_writeformat(session->channel, fmt); + ast_channel_set_rawwriteformat(session->channel, fmt); + ast_channel_set_readformat(session->channel, fmt); + ast_channel_set_rawreadformat(session->channel, fmt); + ao2_ref(fmt, -1); + + return 0; +} + +static int refresh_write_cb(void *obj) +{ + struct refresh_data *data = obj; + + ast_sip_session_refresh(data->session, NULL, NULL, + sip_session_response_cb, data->method, 1); + + return 0; +} + +int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) +{ + struct ast_sip_channel_pvt *channel; + struct refresh_data rdata = { + .method = AST_SIP_SESSION_REFRESH_METHOD_INVITE, + }; + + if (!chan) { + ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); + return -1; + } + + if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) { + ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd); + return -1; + } + + channel = ast_channel_tech_pvt(chan); + rdata.session = channel->session; + + if (!strcmp(value, "invite")) { + rdata.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE; + } else if (!strcmp(value, "update")) { + rdata.method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE; + } + + return ast_sip_push_task_synchronous(channel->session->serializer, refresh_write_cb, &rdata); +} diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h index cbc06f07613..8b80bfa7474 100644 --- a/channels/pjsip/include/dialplan_functions.h +++ b/channels/pjsip/include/dialplan_functions.h @@ -60,6 +60,18 @@ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char */ int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len); +/*! + * \brief PJSIP_SEND_SESSION_REFRESH function write callback + * \param chan The channel the function is called on + * \param cmd the Name of the function + * \param data Arguments passed to the function + * \param value Value to be set by the function + * + * \retval 0 on success + * \retval -1 on failure + */ +int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value); + /*! * \brief PJSIP_DIAL_CONTACTS function read callback * \param chan The channel the function is called on From 8d42ff784d0da04fda44ef8395f35671bd5ec0b3 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 10 Aug 2016 10:47:32 -0600 Subject: [PATCH 0630/1578] res_resolver_unbound: Allow compilation with libunbound version < 1.5 libunbound at version 1.4.20 (which CentOS still uses) declared all of their string function parameters as as 'char *'. 1.4.21 changed them all to 'const char *'. Thankfully 1.4.21 also introduced the UNBOUND_VERSION_MAJOR define so configure now checks for that and sets HAVE_UNBOUND_CONST_PARAMS. res_resolver_unbound then checks that and casts away the 'const' if it's not set. Tested compile and testsuite on CentOS6 (1.4.20), Ubuntu14 (1.4.22) and Fedora24 (1.5.4). There are a few failing tests to be addressed though. ASTERISK-26283 #close Change-Id: Ib708b19b706c5d0ba7b7d5473e6df339d9ae4148 --- configure | 45 ++++++++++++++++++++++++++- configure.ac | 3 +- include/asterisk/autoconfig.h.in | 3 ++ res/res_resolver_unbound.c | 53 +++++++++++++++++++------------- 4 files changed, 81 insertions(+), 23 deletions(-) diff --git a/configure b/configure index 8bce35d713c..5ac2a1495b3 100755 --- a/configure +++ b/configure @@ -23683,7 +23683,7 @@ if test "x${PBX_UNBOUND}" != "x1" -a "${USE_UNBOUND}" != "no"; then pbxlibdir="-L${UNBOUND_DIR}" fi fi - pbxfuncname="ub_ctx_add_ta_autr" + pbxfuncname="ub_ctx_delete" if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers AST_UNBOUND_FOUND=yes else @@ -23777,6 +23777,49 @@ fi + if test "x${PBX_UNBOUND_CONST_PARAMS}" != "x1" -a "${USE_UNBOUND_CONST_PARAMS}" != "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for UNBOUND_VERSION_MAJOR declared in unbound.h" >&5 +$as_echo_n "checking for UNBOUND_VERSION_MAJOR declared in unbound.h... " >&6; } + saved_cppflags="${CPPFLAGS}" + if test "x${UNBOUND_CONST_PARAMS_DIR}" != "x"; then + UNBOUND_CONST_PARAMS_INCLUDE="-I${UNBOUND_CONST_PARAMS_DIR}/include" + fi + CPPFLAGS="${CPPFLAGS} ${UNBOUND_CONST_PARAMS_INCLUDE}" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ +#if !defined(UNBOUND_VERSION_MAJOR) + (void) UNBOUND_VERSION_MAJOR; + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_UNBOUND_CONST_PARAMS=1 + +$as_echo "#define HAVE_UNBOUND_CONST_PARAMS 1" >>confdefs.h + + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + CPPFLAGS="${saved_cppflags}" + fi + + if test "x${PBX_UNIXODBC}" != "x1" -a "${USE_UNIXODBC}" != "no"; then pbxlibdir="" diff --git a/configure.ac b/configure.ac index ed6f8a8d458..8ea1cb038d2 100644 --- a/configure.ac +++ b/configure.ac @@ -2101,7 +2101,8 @@ AST_EXT_LIB_CHECK([NEWT], [newt], [newtBell], [newt.h]) # script bug which does not find the ldns library. The bug is fixed in # v1.4.22 but that version is not easily detectable. # -AST_EXT_LIB_CHECK([UNBOUND], [unbound], [ub_ctx_add_ta_autr], [unbound.h], []) +AST_EXT_LIB_CHECK([UNBOUND], [unbound], [ub_ctx_delete], [unbound.h], []) +AST_C_DECLARE_CHECK([UNBOUND_CONST_PARAMS], [UNBOUND_VERSION_MAJOR], [unbound.h]) AST_EXT_LIB_CHECK([UNIXODBC], [odbc], [SQLConnect], [sql.h], []) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index b48257ec0a4..bdd93bb64c4 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -1108,6 +1108,9 @@ /* Define to 1 if you have the unbound library. */ #undef HAVE_UNBOUND +/* Define if your system has UNBOUND_VERSION_MAJOR declared. */ +#undef HAVE_UNBOUND_CONST_PARAMS + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H diff --git a/res/res_resolver_unbound.c b/res/res_resolver_unbound.c index 3eeb651697e..40f3cfe4bf2 100644 --- a/res/res_resolver_unbound.c +++ b/res/res_resolver_unbound.c @@ -79,6 +79,17 @@ ASTERISK_REGISTER_FILE() ***/ +/*! + * Unbound versions <= 1.4.20 declare string function parameters as 'char *' + * but versions >= 1.4.21 declare them as 'const char *'. Since CentOS6 is still + * at 1.4.20, we need to cast away the 'const' if we detect the earlier version. + */ +#ifdef HAVE_UNBOUND_CONST_PARAMS +#define UNBOUND_CHAR const char +#else +#define UNBOUND_CHAR char +#endif + /*! \brief Structure for an unbound resolver */ struct unbound_resolver { /*! \brief Resolver context itself */ @@ -292,7 +303,7 @@ static int unbound_resolver_resolve(struct ast_dns_query *query) data->resolver = ao2_bump(cfg->global->state->resolver); ast_dns_resolver_set_data(query, data); - res = ub_resolve_async(data->resolver->context, ast_dns_query_get_name(query), + res = ub_resolve_async(data->resolver->context, (UNBOUND_CHAR *)ast_dns_query_get_name(query), ast_dns_query_get_rr_type(query), ast_dns_query_get_rr_class(query), ao2_bump(query), unbound_resolver_callback, &data->id); @@ -404,7 +415,7 @@ static int unbound_config_preapply(struct unbound_config *cfg) if (!strcmp(cfg->global->hosts, "system")) { res = ub_ctx_hosts(cfg->global->state->resolver->context, NULL); } else if (!ast_strlen_zero(cfg->global->hosts)) { - res = ub_ctx_hosts(cfg->global->state->resolver->context, cfg->global->hosts); + res = ub_ctx_hosts(cfg->global->state->resolver->context, (UNBOUND_CHAR *)cfg->global->hosts); } if (res) { @@ -419,7 +430,7 @@ static int unbound_config_preapply(struct unbound_config *cfg) it_nameservers = ao2_iterator_init(cfg->global->nameservers, 0); while ((nameserver = ao2_iterator_next(&it_nameservers))) { - res = ub_ctx_set_fwd(cfg->global->state->resolver->context, nameserver); + res = ub_ctx_set_fwd(cfg->global->state->resolver->context, (UNBOUND_CHAR *)nameserver); if (res) { ast_log(LOG_ERROR, "Failed to add nameserver '%s' to unbound resolver: %s\n", @@ -434,7 +445,7 @@ static int unbound_config_preapply(struct unbound_config *cfg) if (!strcmp(cfg->global->resolv, "system")) { res = ub_ctx_resolvconf(cfg->global->state->resolver->context, NULL); } else if (!ast_strlen_zero(cfg->global->resolv)) { - res = ub_ctx_resolvconf(cfg->global->state->resolver->context, cfg->global->resolv); + res = ub_ctx_resolvconf(cfg->global->state->resolver->context, (UNBOUND_CHAR *)cfg->global->resolv); } if (res) { @@ -444,7 +455,7 @@ static int unbound_config_preapply(struct unbound_config *cfg) } if (!ast_strlen_zero(cfg->global->ta_file)) { - res = ub_ctx_add_ta_file(cfg->global->state->resolver->context, cfg->global->ta_file); + res = ub_ctx_add_ta_file(cfg->global->state->resolver->context, (UNBOUND_CHAR *)cfg->global->ta_file); if (res) { ast_log(LOG_ERROR, "Failed to set trusted anchor file to '%s' in unbound resolver: %s\n", @@ -740,13 +751,13 @@ static enum ast_test_result_state nominal_test(struct ast_test *test, resolve_fn static const size_t V4_SIZE = sizeof(struct in_addr); static const size_t V6_SIZE = sizeof(struct in6_addr); - static const char *DOMAIN1 = "goose.feathers"; - static const char *DOMAIN2 = "duck.feathers"; + static UNBOUND_CHAR *DOMAIN1 = "goose.feathers"; + static UNBOUND_CHAR *DOMAIN2 = "duck.feathers"; - static const char *ADDR1 = "127.0.0.2"; - static const char *ADDR2 = "127.0.0.3"; - static const char *ADDR3 = "::1"; - static const char *ADDR4 = "127.0.0.4"; + static UNBOUND_CHAR *ADDR1 = "127.0.0.2"; + static UNBOUND_CHAR *ADDR2 = "127.0.0.3"; + static UNBOUND_CHAR *ADDR3 = "::1"; + static UNBOUND_CHAR *ADDR4 = "127.0.0.4"; char addr1_buf[V4_SIZE]; char addr2_buf[V4_SIZE]; @@ -786,7 +797,7 @@ static enum ast_test_result_state nominal_test(struct ast_test *test, resolve_fn ub_ctx_zone_add(resolver->context, DOMAIN2, "static"); for (i = 0; i < ARRAY_LEN(records); ++i) { - ub_ctx_data_add(resolver->context, records[i].as_string); + ub_ctx_data_add(resolver->context, (UNBOUND_CHAR *)records[i].as_string); } for (i = 0; i < ARRAY_LEN(runs); ++i) { @@ -808,7 +819,7 @@ static enum ast_test_result_state nominal_test(struct ast_test *test, resolve_fn cleanup: for (i = 0; i < ARRAY_LEN(records); ++i) { - ub_ctx_data_remove(resolver->context, records[i].as_string); + ub_ctx_data_remove(resolver->context, (UNBOUND_CHAR *)records[i].as_string); } ub_ctx_zone_remove(resolver->context, DOMAIN1); ub_ctx_zone_remove(resolver->context, DOMAIN2); @@ -1012,10 +1023,10 @@ static enum ast_test_result_state off_nominal_test(struct ast_test *test, static const size_t V4_SIZE = sizeof(struct in_addr); - static const char *DOMAIN1 = "goose.feathers"; - static const char *DOMAIN2 = "duck.feathers"; + static UNBOUND_CHAR *DOMAIN1 = "goose.feathers"; + static UNBOUND_CHAR *DOMAIN2 = "duck.feathers"; - static const char *ADDR1 = "127.0.0.2"; + static UNBOUND_CHAR *ADDR1 = "127.0.0.2"; char addr1_buf[V4_SIZE]; @@ -1046,7 +1057,7 @@ static enum ast_test_result_state off_nominal_test(struct ast_test *test, ub_ctx_zone_add(resolver->context, DOMAIN2, "static"); for (i = 0; i < ARRAY_LEN(records); ++i) { - ub_ctx_data_add(resolver->context, records[i].as_string); + ub_ctx_data_add(resolver->context, (UNBOUND_CHAR *)records[i].as_string); } for (i = 0; i < ARRAY_LEN(runs); ++i) { @@ -1196,7 +1207,7 @@ AST_TEST_DEFINE(resolve_naptr) const struct ast_dns_record *record; - static const char * DOMAIN1 = "goose.feathers"; + static char * DOMAIN1 = "goose.feathers"; int i; enum ast_test_result_state res = AST_TEST_PASS; @@ -1234,7 +1245,7 @@ AST_TEST_DEFINE(resolve_naptr) ub_ctx_zone_add(resolver->context, DOMAIN1, "static"); for (i = 0; i < ARRAY_LEN(records); ++i) { - ub_ctx_data_add(resolver->context, records[i].zone_entry); + ub_ctx_data_add(resolver->context, (UNBOUND_CHAR *)records[i].zone_entry); } if (ast_dns_resolve(DOMAIN1, ns_t_naptr, ns_c_in, &result)) { @@ -1311,8 +1322,8 @@ AST_TEST_DEFINE(resolve_srv) RAII_VAR(struct unbound_config *, cfg, NULL, ao2_cleanup); RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free); const struct ast_dns_record *record; - static const char *DOMAIN1 = "taco.bananas"; - static const char *DOMAIN1_SRV = "taco.bananas 12345 IN SRV 10 20 5060 sip.taco.bananas"; + static UNBOUND_CHAR *DOMAIN1 = "taco.bananas"; + static UNBOUND_CHAR *DOMAIN1_SRV = "taco.bananas 12345 IN SRV 10 20 5060 sip.taco.bananas"; enum ast_test_result_state res = AST_TEST_PASS; switch (cmd) { From d4170df40a405442ba26dbaf0d8acfd1360533df Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 9 Aug 2016 12:07:20 -0500 Subject: [PATCH 0631/1578] alembic/sqlalchemy: auto increment only allowed on a single column The extensions table defined two columns (id and priority) as primary key autoincrement columns. However only one is allowed when defining the primary key. This patch removes the autoincrement attribute from the priority column since it does not need to be as such and really should not have been on there in the first place. This patch also removes 'context', 'exten', and 'priority' from the primary key index and creates a new combined unique contraint index on them. ASTERISK-26183 #close Change-Id: Ib9c712c612a4d7ec1edb0dcb77f1bae0905a470b --- .../config/versions/581a4264e537_adding_extensions.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py b/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py index ecee0e04efd..415f5bc25c4 100755 --- a/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py +++ b/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py @@ -31,20 +31,18 @@ from alembic import op import sqlalchemy as sa - def upgrade(): op.create_table( 'extensions', sa.Column('id', sa.BigInteger, primary_key=True, nullable=False, unique=True, autoincrement=True), - sa.Column('context', sa.String(40), primary_key=True, nullable=False), - sa.Column('exten', sa.String(40), primary_key=True, nullable=False), - sa.Column('priority', sa.Integer, primary_key=True, nullable=False, - autoincrement=True), + sa.Column('context', sa.String(40), nullable=False), + sa.Column('exten', sa.String(40), nullable=False), + sa.Column('priority', sa.Integer, nullable=False), sa.Column('app', sa.String(40), nullable=False), sa.Column('appdata', sa.String(256), nullable=False), + sa.UniqueConstraint('context', 'exten', 'priority') ) - def downgrade(): op.drop_table('extensions') From 820879415f7b6dd7ea300b6b43308d8cffb7256d Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Sat, 6 Aug 2016 11:57:08 -0400 Subject: [PATCH 0632/1578] pjsip: Fix deadlock with suspend taskprocessor on masquerade If both channels which should be masqueraded are in the same serializer: 1st channel will be locked waiting condition 'complete' 2nd channel will be locked waiting condition 'suspended' On heavy load system a chance that both channels will be in the same serializer 'pjsip/distibutor' is very high. To reproduce compile res_pjsip/pjsip_distributor.c with DISTRIBUTOR_POOL_SIZE=1 Steps to reproduce: 1. Party A calls Party B (bridged call 'AB') 2. Party B places Party A on hold 3. Party B calls Voicemail app (non-bridged call 'BV') 4. Party B attended transfers Party A to voicemail using REFER. 5. When asterisk masquerades calls 'AB' and 'BV', a deadlock is happened. This patch adds a suspension indicator to the taskprocessor. When a session suspends/unsuspends the serializer it sets the indicator to the appropriate state. The session checks the suspension indicator before suspend the serializer. ASTERISK-26145 #close Change-Id: Iaaebee60013a58c942ba47b1b4930a63e686663b --- include/asterisk/taskprocessor.h | 32 ++++++++++++++++++++++++++++++++ main/taskprocessor.c | 29 +++++++++++++++++++++++++++++ res/res_pjsip_session.c | 9 +++++++++ 3 files changed, 70 insertions(+) diff --git a/include/asterisk/taskprocessor.h b/include/asterisk/taskprocessor.h index e51122269d4..7c79036b37e 100644 --- a/include/asterisk/taskprocessor.h +++ b/include/asterisk/taskprocessor.h @@ -241,6 +241,38 @@ struct ast_taskprocessor_local { int ast_taskprocessor_push_local(struct ast_taskprocessor *tps, int (*task_exe)(struct ast_taskprocessor_local *local), void *datap); +/*! + * \brief Indicate the taskprocessor is suspended. + * + * \since 13.12.0 + * + * \param tps Task processor. + * \retval 0 success + * \retval -1 failure + */ +int ast_taskprocessor_suspend(struct ast_taskprocessor *tps); + +/*! + * \brief Indicate the taskprocessor is unsuspended. + * + * \since 13.12.0 + * + * \param tps Task processor. + * \retval 0 success + * \retval -1 failure + */ +int ast_taskprocessor_unsuspend(struct ast_taskprocessor *tps); + +/*! + * \brief Get the task processor suspend status + * + * \since 13.12.0 + * + * \param tps Task processor. + * \retval non-zero if the task processor is suspended + */ +int ast_taskprocessor_is_suspended(struct ast_taskprocessor *tps); + /*! * \brief Pop a task off the taskprocessor and execute it. * diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 2f0124045bc..4a8497f1104 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -91,6 +91,8 @@ struct ast_taskprocessor { unsigned int high_water_warned:1; /*! Indicates that a high water alert is active on this taskprocessor */ unsigned int high_water_alert:1; + /*! Indicates if the taskprocessor is currently suspended */ + unsigned int suspended:1; }; /*! @@ -910,6 +912,33 @@ int ast_taskprocessor_push_local(struct ast_taskprocessor *tps, int (*task_exe)( return taskprocessor_push(tps, tps_task_alloc_local(task_exe, datap)); } +int ast_taskprocessor_suspend(struct ast_taskprocessor *tps) +{ + if (tps) { + ao2_lock(tps); + tps->suspended = 1; + ao2_unlock(tps); + return 0; + } + return -1; +} + +int ast_taskprocessor_unsuspend(struct ast_taskprocessor *tps) +{ + if (tps) { + ao2_lock(tps); + tps->suspended = 0; + ao2_unlock(tps); + return 0; + } + return -1; +} + +int ast_taskprocessor_is_suspended(struct ast_taskprocessor *tps) +{ + return tps ? tps->suspended : -1; +} + int ast_taskprocessor_execute(struct ast_taskprocessor *tps) { struct ast_taskprocessor_local local; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index a773c16fc04..488492f4fb4 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1559,6 +1559,11 @@ void ast_sip_session_suspend(struct ast_sip_session *session) return; } + if (ast_taskprocessor_is_suspended(session->serializer)) { + /* The serializer already suspended. */ + return; + } + suspender = ao2_alloc(sizeof(*suspender), sip_session_suspender_dtor); if (!suspender) { /* We will just have to hope that the system does not deadlock */ @@ -1583,6 +1588,8 @@ void ast_sip_session_suspend(struct ast_sip_session *session) ast_cond_wait(&suspender->cond_suspended, ao2_object_get_lockaddr(suspender)); } ao2_unlock(suspender); + + ast_taskprocessor_suspend(session->serializer); } void ast_sip_session_unsuspend(struct ast_sip_session *session) @@ -1602,6 +1609,8 @@ void ast_sip_session_unsuspend(struct ast_sip_session *session) ao2_unlock(suspender); ao2_ref(suspender, -1); + + ast_taskprocessor_unsuspend(session->serializer); } /*! From 41aba83ff6f4cb5867209803f7bfb1c007254230 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 8 Aug 2016 14:50:53 -0500 Subject: [PATCH 0633/1578] res_srtp: Move SDP SRTP code from the core to res_srtp. A patch made to the master branch (Now the 14 branch) inadvertently made libsrtp a required dependency in order to compile Asterisk. Rather than create dummy defines to substitute for the defines supplied by libsrtp when libsrtp is not available, most of the code in sdp_srtp.c is moved into res_srtp.c. This gets more code out of Asterisk's core that isn't used when SRTP is not available. This also makes another inadvertent required dependency on libsrtp by Asterisk's core unlikely. ASTERISK-26253 #close Reported by: Ben Merrills Change-Id: I0a46cde81501c0405399c2588633ae32706d1ee7 --- include/asterisk/sdp_srtp.h | 95 +++++- main/sdp_srtp.c | 606 ++---------------------------------- res/res_srtp.c | 587 +++++++++++++++++++++++++++++++++- 3 files changed, 711 insertions(+), 577 deletions(-) diff --git a/include/asterisk/sdp_srtp.h b/include/asterisk/sdp_srtp.h index 5d8f0e7d1ea..cf89fa9e08c 100644 --- a/include/asterisk/sdp_srtp.h +++ b/include/asterisk/sdp_srtp.h @@ -63,6 +63,100 @@ struct ast_sdp_srtp *ast_sdp_srtp_alloc(void); */ void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp); +/*! \brief Destroy a previously allocated ast_sdp_crypto struct */ +typedef void (*sdp_crypto_destroy_cb)(struct ast_sdp_crypto *crypto); + +/*! + * \brief Initialize and return an ast_sdp_crypto struct + * + * \details + * This function allocates a new ast_sdp_crypto struct and initializes its values + * + * \retval NULL on failure + * \retval a pointer to a new ast_sdp_crypto structure + */ +typedef struct ast_sdp_crypto *(*sdp_crypto_alloc_cb)(void); + +/*! + * \brief Generate an SRTP a=crypto offer + * + * \details + * The offer is stored on the ast_sdp_crypto struct in a_crypto + * + * \param crypto A valid ast_sdp_crypto struct + * \param taglen Length + * + * \retval 0 success + * \retval nonzero failure + */ +typedef int (*sdp_crypto_build_offer_cb)(struct ast_sdp_crypto *crypto, int taglen); + +/*! + * \brief Parse the a=crypto line from SDP and set appropriate values on the + * ast_sdp_crypto struct. + * + * The attribute line should already have "a=crypto:" removed. + * + * \param p A valid ast_sdp_crypto struct + * \param attr the a:crypto line from SDP + * \param rtp The rtp instance associated with the SDP being parsed + * \param srtp SRTP structure + * + * \retval 0 success + * \retval nonzero failure + */ +typedef int (*sdp_crypto_parse_offer_cb)(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *srtp, const char *attr); + +/*! + * \brief Get the crypto attribute line for the srtp structure + * + * \details + * The attribute line does not contain the initial "a=crypto:" and does + * not terminate with "\r\n". + * + * \param srtp The ast_sdp_srtp structure for which to get an attribute line + * \param dtls_enabled Whether this connection is encrypted with datagram TLS + * \param default_taglen_32 Whether to default to a tag length of 32 instead of 80 + * + * \retval An attribute line containing cryptographic information + * \retval NULL if the srtp structure does not require an attribute line containing crypto information + */ +typedef const char *(*sdp_srtp_get_attr_cb)(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32); + +struct ast_sdp_crypto_api { + /*! Destroy a crypto struct */ + sdp_crypto_destroy_cb dtor; + /*! Allocate a crypto struct */ + sdp_crypto_alloc_cb alloc; + /*! Build a SDP a=crypto offer line parameter string */ + sdp_crypto_build_offer_cb build_offer; + /*! Parse a SDP a=crypto offer line parameter string */ + sdp_crypto_parse_offer_cb parse_offer; + /*! Get the SDP a=crypto offer line parameter string */ + sdp_srtp_get_attr_cb get_attr; +}; + +/*! + * \brief Register SDP SRTP crypto processing routines. + * \since 14.0.0 + * + * \param api Callbacks to register. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int ast_sdp_crypto_register(struct ast_sdp_crypto_api *api); + +/*! + * \brief Unregister SDP SRTP crypto processing routines. + * \since 14.0.0 + * + * \param api Callbacks to unregister. + * + * \return Nothing + */ +void ast_sdp_crypto_unregister(struct ast_sdp_crypto_api *api); + /*! \brief Initialize an return an ast_sdp_crypto struct * * \details @@ -104,7 +198,6 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr */ int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen); - /*! \brief Get the crypto attribute line for the srtp structure * * The attribute line does not contain the initial "a=crypto:" and does diff --git a/main/sdp_srtp.c b/main/sdp_srtp.c index a55aedf8247..940a6197d8f 100644 --- a/main/sdp_srtp.c +++ b/main/sdp_srtp.c @@ -33,18 +33,12 @@ ASTERISK_REGISTER_FILE() -#include /* for pow */ -#include /* for SRTP_MAX_KEY_LEN, etc */ - #include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */ #include "asterisk/logger.h" /* for ast_log, LOG_ERROR, etc */ -#include "asterisk/rtp_engine.h" /* for ast_rtp_engine_dtls, etc */ #include "asterisk/sdp_srtp.h" /* for ast_sdp_srtp, etc */ -#include "asterisk/strings.h" /* for ast_strlen_zero */ -#include "asterisk/utils.h" /* for ast_set_flag, ast_test_flag, etc */ -extern struct ast_srtp_res *res_srtp; -extern struct ast_srtp_policy_res *res_srtp_policy; +/*! Registered SDP crypto API */ +static struct ast_sdp_crypto_api *sdp_crypto_api; struct ast_sdp_srtp *ast_sdp_srtp_alloc(void) { @@ -63,603 +57,49 @@ void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp) for (next = AST_LIST_NEXT(srtp, sdp_srtp_list); srtp; srtp = next, next = srtp ? AST_LIST_NEXT(srtp, sdp_srtp_list) : NULL) { - if (srtp->crypto) { - ast_sdp_crypto_destroy(srtp->crypto); - } + ast_sdp_crypto_destroy(srtp->crypto); srtp->crypto = NULL; ast_free(srtp); } } -struct ast_sdp_crypto { - char *a_crypto; - unsigned char local_key[SRTP_MAX_KEY_LEN]; - int tag; - char local_key64[((SRTP_MAX_KEY_LEN) * 8 + 5) / 6 + 1]; - unsigned char remote_key[SRTP_MAX_KEY_LEN]; - int key_len; -}; - -static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len); -static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len); -static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound); - void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto) { - ast_free(crypto->a_crypto); - crypto->a_crypto = NULL; - ast_free(crypto); -} - -static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len) -{ - unsigned char remote_key[key_len]; - - if (res_srtp->get_random(p->local_key, key_len) < 0) { - return NULL; - } - - ast_base64encode(p->local_key64, p->local_key, key_len, sizeof(p->local_key64)); - - p->key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); - - if (p->key_len != key_len) { - ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", p->key_len, key_len); - return NULL; - } - - if (memcmp(remote_key, p->local_key, p->key_len)) { - ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); - return NULL; - } - - ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); - - return p; -} - -static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len) -{ - struct ast_sdp_crypto *p, *result; - - if (!ast_rtp_engine_srtp_is_registered()) { - return NULL; - } - - if (!(p = ast_calloc(1, sizeof(*p)))) { - return NULL; + if (sdp_crypto_api) { + sdp_crypto_api->dtor(crypto); } - p->tag = 1; - - /* default is a key which uses AST_AES_CM_128_HMAC_SHA1_xx */ - result = crypto_init_keys(p, key_len); - if (!result) { - ast_sdp_crypto_destroy(p); - } - - return result; } struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) { - return sdp_crypto_alloc(SRTP_MASTER_KEY_LEN); -} - -static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound) -{ - if (!ast_rtp_engine_srtp_is_registered()) { - return -1; - } - - if (res_srtp_policy->set_master_key(policy, master_key, key_len, NULL, 0) < 0) { - return -1; - } - - if (res_srtp_policy->set_suite(policy, suite_val)) { - ast_log(LOG_WARNING, "Could not set remote SRTP suite\n"); - return -1; - } - - res_srtp_policy->set_ssrc(policy, ssrc, inbound); - - return 0; -} - -static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, int key_len, struct ast_rtp_instance *rtp) -{ - struct ast_srtp_policy *local_policy = NULL; - struct ast_srtp_policy *remote_policy = NULL; - struct ast_rtp_instance_stats stats = {0,}; - int res = -1; - - if (!ast_rtp_engine_srtp_is_registered()) { - return -1; - } - - if (!p) { - return -1; - } - - if (!(local_policy = res_srtp_policy->alloc())) { - return -1; - } - - if (!(remote_policy = res_srtp_policy->alloc())) { - goto err; - } - - if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_LOCAL_SSRC)) { - goto err; - } - - if (set_crypto_policy(local_policy, suite_val, p->local_key, key_len, stats.local_ssrc, 0) < 0) { - goto err; - } - - if (set_crypto_policy(remote_policy, suite_val, remote_key, key_len, 0, 1) < 0) { - goto err; - } - - /* Add the SRTP policies */ - if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy, 0)) { - ast_log(LOG_WARNING, "Could not set SRTP policies\n"); - goto err; - } - - ast_debug(1 , "SRTP policy activated\n"); - res = 0; - -err: - if (local_policy) { - res_srtp_policy->destroy(local_policy); - } - - if (remote_policy) { - res_srtp_policy->destroy(remote_policy); + if (!sdp_crypto_api) { + return NULL; } - - return res; + return sdp_crypto_api->alloc(); } int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *srtp, const char *attr) { - char *str = NULL; - char *tag = NULL; - char *suite = NULL; - char *key_params = NULL; - char *key_param = NULL; - char *session_params = NULL; - char *key_salt = NULL; /* The actual master key and key salt */ - char *lifetime = NULL; /* Key lifetime (# of RTP packets) */ - char *mki = NULL; /* Master Key Index */ - int found = 0; - int key_len_from_sdp; - int key_len_expected; - int tag_from_sdp; - int suite_val = 0; - unsigned char remote_key[SRTP_MAX_KEY_LEN]; - int taglen; - double sdes_lifetime; - struct ast_sdp_crypto *crypto; - struct ast_sdp_srtp *tmp; - - if (!ast_rtp_engine_srtp_is_registered()) { + if (!sdp_crypto_api) { return -1; } - - str = ast_strdupa(attr); - - tag = strsep(&str, " "); - suite = strsep(&str, " "); - key_params = strsep(&str, " "); - session_params = strsep(&str, " "); - - if (!tag || !suite) { - ast_log(LOG_WARNING, "Unrecognized crypto attribute a=%s\n", attr); - return -1; - } - - /* RFC4568 9.1 - tag is 1-9 digits, greater than zero */ - if (sscanf(tag, "%30d", &tag_from_sdp) != 1 || tag_from_sdp <= 0 || tag_from_sdp > 999999999) { - ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag); - return -1; - } - - if (!ast_strlen_zero(session_params)) { - ast_log(LOG_WARNING, "Unsupported crypto parameters: %s\n", session_params); - return -1; - } - - /* On egress, Asterisk sent several crypto lines in the SIP/SDP offer - The remote party might have choosen another line than the first */ - for (tmp = srtp; tmp && tmp->crypto && tmp->crypto->tag != tag_from_sdp;) { - tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); - } - if (tmp) { /* tag matched an already created crypto line */ - unsigned int flags = tmp->flags; - - /* Make that crypto line the head of the list, not by changing the - list structure but by exchanging the content of the list members */ - crypto = tmp->crypto; - tmp->crypto = srtp->crypto; - tmp->flags = srtp->flags; - srtp->crypto = crypto; - srtp->flags = flags; - } else { - crypto = srtp->crypto; - crypto->tag = tag_from_sdp; - } - - if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) { - suite_val = AST_AES_CM_128_HMAC_SHA1_80; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - key_len_expected = 30; - } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { - suite_val = AST_AES_CM_128_HMAC_SHA1_32; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - key_len_expected = 30; -#ifdef HAVE_SRTP_192 - } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_80")) { - suite_val = AST_AES_CM_192_HMAC_SHA1_80; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); - key_len_expected = 38; - } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_32")) { - suite_val = AST_AES_CM_192_HMAC_SHA1_32; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); - key_len_expected = 38; - /* RFC used a different name while in draft, some still use that */ - } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_80")) { - suite_val = AST_AES_CM_192_HMAC_SHA1_80; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); - ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); - key_len_expected = 38; - } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_32")) { - suite_val = AST_AES_CM_192_HMAC_SHA1_32; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); - ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); - key_len_expected = 38; -#endif -#ifdef HAVE_SRTP_256 - } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_80")) { - suite_val = AST_AES_CM_256_HMAC_SHA1_80; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); - key_len_expected = 46; - } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_32")) { - suite_val = AST_AES_CM_256_HMAC_SHA1_32; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); - key_len_expected = 46; - /* RFC used a different name while in draft, some still use that */ - } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_80")) { - suite_val = AST_AES_CM_256_HMAC_SHA1_80; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); - ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); - key_len_expected = 46; - } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_32")) { - suite_val = AST_AES_CM_256_HMAC_SHA1_32; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); - ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); - key_len_expected = 46; -#endif -#ifdef HAVE_SRTP_GCM - } else if (!strcmp(suite, "AEAD_AES_128_GCM")) { - suite_val = AST_AES_GCM_128; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); - key_len_expected = AES_128_GCM_KEYSIZE_WSALT; - } else if (!strcmp(suite, "AEAD_AES_256_GCM")) { - suite_val = AST_AES_GCM_256; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); - key_len_expected = AES_256_GCM_KEYSIZE_WSALT; - /* RFC contained a (too) short auth tag for RTP media, some still use that */ - } else if (!strcmp(suite, "AEAD_AES_128_GCM_8")) { - suite_val = AST_AES_GCM_128_8; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); - key_len_expected = AES_128_GCM_KEYSIZE_WSALT; - } else if (!strcmp(suite, "AEAD_AES_256_GCM_8")) { - suite_val = AST_AES_GCM_256_8; - ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); - ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); - key_len_expected = AES_256_GCM_KEYSIZE_WSALT; -#endif - } else { - ast_verb(1, "Unsupported crypto suite: %s\n", suite); - return -1; - } - - while ((key_param = strsep(&key_params, ";"))) { - unsigned int n_lifetime; - char *method = NULL; - char *info = NULL; - - method = strsep(&key_param, ":"); - info = strsep(&key_param, ";"); - sdes_lifetime = 0; - - if (strcmp(method, "inline")) { - continue; - } - - key_salt = strsep(&info, "|"); - - /* The next parameter can be either lifetime or MKI */ - lifetime = strsep(&info, "|"); - if (!lifetime) { - found = 1; - break; - } - - mki = strchr(lifetime, ':'); - if (mki) { - mki = lifetime; - lifetime = NULL; - } else { - mki = strsep(&info, "|"); - } - - if (mki && *mki != '1') { - ast_log(LOG_NOTICE, "Crypto MKI handling is not supported: ignoring attribute %s\n", attr); - continue; - } - - if (lifetime) { - if (!strncmp(lifetime, "2^", 2)) { - char *lifetime_val = lifetime + 2; - - /* Exponential lifetime */ - if (sscanf(lifetime_val, "%30u", &n_lifetime) != 1) { - ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr); - continue; - } - - if (n_lifetime > 48) { - /* Yeah... that's a bit big. */ - ast_log(LOG_NOTICE, "Crypto lifetime exponent of '%u' is a bit large; using 48\n", n_lifetime); - n_lifetime = 48; - } - sdes_lifetime = pow(2, n_lifetime); - } else { - /* Decimal lifetime */ - if (sscanf(lifetime, "%30u", &n_lifetime) != 1) { - ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr); - continue; - } - sdes_lifetime = n_lifetime; - } - - /* Accept anything above 10 hours. Less than 10; reject. */ - if (sdes_lifetime < 1800000) { - ast_log(LOG_NOTICE, "Rejecting crypto attribute '%s': lifetime '%f' too short\n", attr, sdes_lifetime); - continue; - } - } - - ast_debug(2, "Crypto attribute '%s' accepted with lifetime '%f', MKI '%s'\n", - attr, sdes_lifetime, mki ? mki : "-"); - - found = 1; - break; - } - - if (!found) { - ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable: '%s'\n", attr); - return -1; - } - - key_len_from_sdp = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); - if (key_len_from_sdp != key_len_expected) { - ast_log(LOG_WARNING, "SRTP descriptions key length is '%d', not '%d'\n", - key_len_from_sdp, key_len_expected); - return -1; - } - - /* on default, the key is 30 (AES-128); throw that away (only) when the suite changed actually */ - /* ingress: optional, but saves one expensive call to get_random(.) */ - /* egress: required, because the local key was communicated before the remote key is processed */ - if (crypto->key_len != key_len_from_sdp) { - if (!crypto_init_keys(crypto, key_len_from_sdp)) { - return -1; - } - } else if (!memcmp(crypto->remote_key, remote_key, key_len_from_sdp)) { - ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); - ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); - return 0; - } - - if (key_len_from_sdp > sizeof(crypto->remote_key)) { - ast_log(LOG_ERROR, - "SRTP key buffer is %zu although it must be at least %d bytes\n", - sizeof(crypto->remote_key), key_len_from_sdp); - return -1; - } - memcpy(crypto->remote_key, remote_key, key_len_from_sdp); - - if (crypto_activate(crypto, suite_val, remote_key, key_len_from_sdp, rtp) < 0) { - return -1; - } - - if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { - taglen = 32; - } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { - taglen = 16; - } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { - taglen = 8; - } else { - taglen = 80; - } - if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { - taglen |= 0x0200; - } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { - taglen |= 0x0100; - } - if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { - taglen |= 0x0080; - } - - /* Finally, rebuild the crypto line */ - if (ast_sdp_crypto_build_offer(crypto, taglen)) { - return -1; - } - - ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); - return 0; + return sdp_crypto_api->parse_offer(rtp, srtp, attr); } int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) { - /* Rebuild the crypto line */ - if (p->a_crypto) { - ast_free(p->a_crypto); - } - - if ((taglen & 0x007f) == 8) { - if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM_%d inline:%s", - p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { - ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); - return -1; - } - } else if ((taglen & 0x007f) == 16) { - if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM inline:%s", - p->tag, 128 + ((taglen & 0x0300) >> 2), p->local_key64) == -1) { - ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); - return -1; - } - } else if ((taglen & 0x0300) && !(taglen & 0x0080)) { - if (ast_asprintf(&p->a_crypto, "%d AES_%d_CM_HMAC_SHA1_%d inline:%s", - p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { - ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); - return -1; - } - } else { - if (ast_asprintf(&p->a_crypto, "%d AES_CM_%d_HMAC_SHA1_%d inline:%s", - p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { - ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); - return -1; - } + if (!sdp_crypto_api) { + return -1; } - - ast_debug(1, "Crypto line: a=crypto:%s\n", p->a_crypto); - - return 0; + return sdp_crypto_api->build_offer(p, taglen); } const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) { - int taglen; - - if (!srtp) { + if (!sdp_crypto_api) { return NULL; } - - /* Set encryption properties */ - if (!srtp->crypto) { - - if (AST_LIST_NEXT(srtp, sdp_srtp_list)) { - srtp->crypto = ast_sdp_crypto_alloc(); - ast_log(LOG_ERROR, "SRTP SDP list was not empty\n"); - } else { - const int len = default_taglen_32 ? AST_SRTP_CRYPTO_TAG_32 : AST_SRTP_CRYPTO_TAG_80; - const int attr[][3] = { - /* This array creates the following list: - * a=crypto:1 AES_CM_128_HMAC_SHA1_ ... - * a=crypto:2 AEAD_AES_128_GCM ... - * a=crypto:3 AES_256_CM_HMAC_SHA1_ ... - * a=crypto:4 AEAD_AES_256_GCM ... - * a=crypto:5 AES_192_CM_HMAC_SHA1_ ... - * something like 'AEAD_AES_192_GCM' is not specified by the RFCs - * - * If you want to prefer another crypto suite or you want to - * exclude a suite, change this array and recompile Asterisk. - * This list cannot be changed from rtp.conf because you should - * know what you are doing. Especially AES-192 and AES-GCM are - * broken in many VoIP clients, see - * https://github.com/cisco/libsrtp/pull/170 - * https://github.com/cisco/libsrtp/pull/184 - * Furthermore, AES-GCM uses a shorter crypto-suite string which - * causes Nokia phones based on Symbian/S60 to reject the whole - * INVITE with status 500, even if a matching suite was offered. - * AES-256 might just waste your processor cycles, especially if - * your TLS transport is not secured with equivalent grade, see - * https://security.stackexchange.com/q/61361 - * Therefore, AES-128 was preferred here. - * - * If you want to enable one of those defines, please, go for - * CFLAGS='-DENABLE_SRTP_AES_GCM' ./configure && sudo make install - */ - { len, 0, 30 }, -#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) - { AST_SRTP_CRYPTO_TAG_16, 0, AES_128_GCM_KEYSIZE_WSALT }, -#endif -#if defined(HAVE_SRTP_256) && defined(ENABLE_SRTP_AES_256) - { len, AST_SRTP_CRYPTO_AES_256, 46 }, -#endif -#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) && defined(ENABLE_SRTP_AES_256) - { AST_SRTP_CRYPTO_TAG_16, AST_SRTP_CRYPTO_AES_256, AES_256_GCM_KEYSIZE_WSALT }, -#endif -#if defined(HAVE_SRTP_192) && defined(ENABLE_SRTP_AES_192) - { len, AST_SRTP_CRYPTO_AES_192, 38 }, -#endif - }; - struct ast_sdp_srtp *tmp = srtp; - int i; - - for (i = 0; i < ARRAY_LEN(attr); i++) { - if (attr[i][0]) { - ast_set_flag(tmp, attr[i][0]); - } - if (attr[i][1]) { - ast_set_flag(tmp, attr[i][1]); - } - tmp->crypto = sdp_crypto_alloc(attr[i][2]); /* key_len */ - tmp->crypto->tag = (i + 1); /* tag starts at 1 */ - - if (i < ARRAY_LEN(attr) - 1) { - AST_LIST_NEXT(tmp, sdp_srtp_list) = ast_sdp_srtp_alloc(); - tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); - } - } - } - } - - if (dtls_enabled) { - /* If DTLS-SRTP is enabled the key details will be pulled from TLS */ - return NULL; - } - - /* set the key length based on INVITE or settings */ - if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_80)) { - taglen = 80; - } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { - taglen = 32; - } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { - taglen = 16; - } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { - taglen = 8; - } else { - taglen = default_taglen_32 ? 32 : 80; - } - if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { - taglen |= 0x0200; - } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { - taglen |= 0x0100; - } - if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { - taglen |= 0x0080; - } - - if (srtp->crypto && (ast_sdp_crypto_build_offer(srtp->crypto, taglen) >= 0)) { - return srtp->crypto->a_crypto; - } - - ast_log(LOG_WARNING, "No SRTP key management enabled\n"); - return NULL; + return sdp_crypto_api->get_attr(srtp, dtls_enabled, default_taglen_32); } char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf, @@ -682,3 +122,19 @@ char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance } } +int ast_sdp_crypto_register(struct ast_sdp_crypto_api *api) +{ + if (sdp_crypto_api) { + return -1; + } + sdp_crypto_api = api; + return 0; +} + +void ast_sdp_crypto_unregister(struct ast_sdp_crypto_api *api) +{ + if (sdp_crypto_api == api) { + sdp_crypto_api = NULL; + } +} + diff --git a/res/res_srtp.c b/res/res_srtp.c index 59fda76dd43..1fb16ce6b94 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -39,6 +39,7 @@ ASTERISK_REGISTER_FILE() +#include /* for pow */ #include #ifdef HAVE_OPENSSL #include @@ -50,6 +51,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/frame.h" /* for AST_FRIENDLY_OFFSET */ #include "asterisk/logger.h" /* for ast_log, ast_debug, etc */ #include "asterisk/module.h" /* for ast_module_info, etc */ +#include "asterisk/sdp_srtp.h" #include "asterisk/res_srtp.h" /* for ast_srtp_cb, ast_srtp_suite, etc */ #include "asterisk/rtp_engine.h" /* for ast_rtp_engine_register_srtp, etc */ #include "asterisk/utils.h" /* for ast_free, ast_calloc */ @@ -578,10 +580,587 @@ static int ast_srtp_change_source(struct ast_srtp *srtp, unsigned int from_ssrc, return 0; } +struct ast_sdp_crypto { + char *a_crypto; + unsigned char local_key[SRTP_MAX_KEY_LEN]; + int tag; + char local_key64[((SRTP_MAX_KEY_LEN) * 8 + 5) / 6 + 1]; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int key_len; +}; + +static void res_sdp_crypto_dtor(struct ast_sdp_crypto *crypto) +{ + if (crypto) { + ast_free(crypto->a_crypto); + crypto->a_crypto = NULL; + ast_free(crypto); + + ast_module_unref(ast_module_info->self); + } +} + +static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len) +{ + unsigned char remote_key[key_len]; + + if (srtp_res.get_random(p->local_key, key_len) < 0) { + return NULL; + } + + ast_base64encode(p->local_key64, p->local_key, key_len, sizeof(p->local_key64)); + + p->key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); + + if (p->key_len != key_len) { + ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", p->key_len, key_len); + return NULL; + } + + if (memcmp(remote_key, p->local_key, p->key_len)) { + ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); + return NULL; + } + + ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); + + return p; +} + +static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len) +{ + struct ast_sdp_crypto *p, *result; + + if (!(p = ast_calloc(1, sizeof(*p)))) { + return NULL; + } + p->tag = 1; + ast_module_ref(ast_module_info->self); + + /* default is a key which uses AST_AES_CM_128_HMAC_SHA1_xx */ + result = crypto_init_keys(p, key_len); + if (!result) { + res_sdp_crypto_dtor(p); + } + + return result; +} + +static struct ast_sdp_crypto *res_sdp_crypto_alloc(void) +{ + return sdp_crypto_alloc(SRTP_MASTER_KEY_LEN); +} + +static int res_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) +{ + int res; + + /* Rebuild the crypto line */ + ast_free(p->a_crypto); + p->a_crypto = NULL; + + if ((taglen & 0x007f) == 8) { + res = ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64); + } else if ((taglen & 0x007f) == 16) { + res = ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), p->local_key64); + } else if ((taglen & 0x0300) && !(taglen & 0x0080)) { + res = ast_asprintf(&p->a_crypto, "%d AES_%d_CM_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64); + } else { + res = ast_asprintf(&p->a_crypto, "%d AES_CM_%d_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64); + } + if (res == -1 || !p->a_crypto) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + + ast_debug(1, "Crypto line: a=crypto:%s\n", p->a_crypto); + + return 0; +} + +static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound) +{ + if (policy_res.set_master_key(policy, master_key, key_len, NULL, 0) < 0) { + return -1; + } + + if (policy_res.set_suite(policy, suite_val)) { + ast_log(LOG_WARNING, "Could not set remote SRTP suite\n"); + return -1; + } + + policy_res.set_ssrc(policy, ssrc, inbound); + + return 0; +} + +static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, int key_len, struct ast_rtp_instance *rtp) +{ + struct ast_srtp_policy *local_policy = NULL; + struct ast_srtp_policy *remote_policy = NULL; + struct ast_rtp_instance_stats stats = {0,}; + int res = -1; + + if (!p) { + return -1; + } + + if (!(local_policy = policy_res.alloc())) { + return -1; + } + + if (!(remote_policy = policy_res.alloc())) { + goto err; + } + + if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_LOCAL_SSRC)) { + goto err; + } + + if (set_crypto_policy(local_policy, suite_val, p->local_key, key_len, stats.local_ssrc, 0) < 0) { + goto err; + } + + if (set_crypto_policy(remote_policy, suite_val, remote_key, key_len, 0, 1) < 0) { + goto err; + } + + /* Add the SRTP policies */ + if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy, 0)) { + ast_log(LOG_WARNING, "Could not set SRTP policies\n"); + goto err; + } + + ast_debug(1 , "SRTP policy activated\n"); + res = 0; + +err: + if (local_policy) { + policy_res.destroy(local_policy); + } + + if (remote_policy) { + policy_res.destroy(remote_policy); + } + + return res; +} + +static int res_sdp_crypto_parse_offer(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *srtp, const char *attr) +{ + char *str = NULL; + char *tag = NULL; + char *suite = NULL; + char *key_params = NULL; + char *key_param = NULL; + char *session_params = NULL; + char *key_salt = NULL; /* The actual master key and key salt */ + char *lifetime = NULL; /* Key lifetime (# of RTP packets) */ + char *mki = NULL; /* Master Key Index */ + int found = 0; + int key_len_from_sdp; + int key_len_expected; + int tag_from_sdp; + int suite_val = 0; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int taglen; + double sdes_lifetime; + struct ast_sdp_crypto *crypto; + struct ast_sdp_srtp *tmp; + + str = ast_strdupa(attr); + + tag = strsep(&str, " "); + suite = strsep(&str, " "); + key_params = strsep(&str, " "); + session_params = strsep(&str, " "); + + if (!tag || !suite) { + ast_log(LOG_WARNING, "Unrecognized crypto attribute a=%s\n", attr); + return -1; + } + + /* RFC4568 9.1 - tag is 1-9 digits, greater than zero */ + if (sscanf(tag, "%30d", &tag_from_sdp) != 1 || tag_from_sdp <= 0 || tag_from_sdp > 999999999) { + ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag); + return -1; + } + + if (!ast_strlen_zero(session_params)) { + ast_log(LOG_WARNING, "Unsupported crypto parameters: %s\n", session_params); + return -1; + } + + /* On egress, Asterisk sent several crypto lines in the SIP/SDP offer + The remote party might have choosen another line than the first */ + for (tmp = srtp; tmp && tmp->crypto && tmp->crypto->tag != tag_from_sdp;) { + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + if (tmp) { /* tag matched an already created crypto line */ + unsigned int flags = tmp->flags; + + /* Make that crypto line the head of the list, not by changing the + list structure but by exchanging the content of the list members */ + crypto = tmp->crypto; + tmp->crypto = srtp->crypto; + tmp->flags = srtp->flags; + srtp->crypto = crypto; + srtp->flags = flags; + } else { + crypto = srtp->crypto; + crypto->tag = tag_from_sdp; + } + + if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_128_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + key_len_expected = 30; + } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_128_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + key_len_expected = 30; +#ifdef HAVE_SRTP_192 + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; +#endif +#ifdef HAVE_SRTP_256 + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; +#endif +#ifdef HAVE_SRTP_GCM + } else if (!strcmp(suite, "AEAD_AES_128_GCM")) { + suite_val = AST_AES_GCM_128; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM")) { + suite_val = AST_AES_GCM_256; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; + /* RFC contained a (too) short auth tag for RTP media, some still use that */ + } else if (!strcmp(suite, "AEAD_AES_128_GCM_8")) { + suite_val = AST_AES_GCM_128_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM_8")) { + suite_val = AST_AES_GCM_256_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; +#endif + } else { + ast_verb(1, "Unsupported crypto suite: %s\n", suite); + return -1; + } + + while ((key_param = strsep(&key_params, ";"))) { + unsigned int n_lifetime; + char *method = NULL; + char *info = NULL; + + method = strsep(&key_param, ":"); + info = strsep(&key_param, ";"); + sdes_lifetime = 0; + + if (strcmp(method, "inline")) { + continue; + } + + key_salt = strsep(&info, "|"); + + /* The next parameter can be either lifetime or MKI */ + lifetime = strsep(&info, "|"); + if (!lifetime) { + found = 1; + break; + } + + mki = strchr(lifetime, ':'); + if (mki) { + mki = lifetime; + lifetime = NULL; + } else { + mki = strsep(&info, "|"); + } + + if (mki && *mki != '1') { + ast_log(LOG_NOTICE, "Crypto MKI handling is not supported: ignoring attribute %s\n", attr); + continue; + } + + if (lifetime) { + if (!strncmp(lifetime, "2^", 2)) { + char *lifetime_val = lifetime + 2; + + /* Exponential lifetime */ + if (sscanf(lifetime_val, "%30u", &n_lifetime) != 1) { + ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr); + continue; + } + + if (n_lifetime > 48) { + /* Yeah... that's a bit big. */ + ast_log(LOG_NOTICE, "Crypto lifetime exponent of '%u' is a bit large; using 48\n", n_lifetime); + n_lifetime = 48; + } + sdes_lifetime = pow(2, n_lifetime); + } else { + /* Decimal lifetime */ + if (sscanf(lifetime, "%30u", &n_lifetime) != 1) { + ast_log(LOG_NOTICE, "Failed to parse lifetime value in crypto attribute: %s\n", attr); + continue; + } + sdes_lifetime = n_lifetime; + } + + /* Accept anything above 10 hours. Less than 10; reject. */ + if (sdes_lifetime < 1800000) { + ast_log(LOG_NOTICE, "Rejecting crypto attribute '%s': lifetime '%f' too short\n", attr, sdes_lifetime); + continue; + } + } + + ast_debug(2, "Crypto attribute '%s' accepted with lifetime '%f', MKI '%s'\n", + attr, sdes_lifetime, mki ? mki : "-"); + + found = 1; + break; + } + + if (!found) { + ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable: '%s'\n", attr); + return -1; + } + + key_len_from_sdp = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); + if (key_len_from_sdp != key_len_expected) { + ast_log(LOG_WARNING, "SRTP descriptions key length is '%d', not '%d'\n", + key_len_from_sdp, key_len_expected); + return -1; + } + + /* on default, the key is 30 (AES-128); throw that away (only) when the suite changed actually */ + /* ingress: optional, but saves one expensive call to get_random(.) */ + /* egress: required, because the local key was communicated before the remote key is processed */ + if (crypto->key_len != key_len_from_sdp) { + if (!crypto_init_keys(crypto, key_len_from_sdp)) { + return -1; + } + } else if (!memcmp(crypto->remote_key, remote_key, key_len_from_sdp)) { + ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); + return 0; + } + + if (key_len_from_sdp > sizeof(crypto->remote_key)) { + ast_log(LOG_ERROR, + "SRTP key buffer is %zu although it must be at least %d bytes\n", + sizeof(crypto->remote_key), key_len_from_sdp); + return -1; + } + memcpy(crypto->remote_key, remote_key, key_len_from_sdp); + + if (crypto_activate(crypto, suite_val, remote_key, key_len_from_sdp, rtp) < 0) { + return -1; + } + + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { + taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; + } + + /* Finally, rebuild the crypto line */ + if (res_sdp_crypto_build_offer(crypto, taglen)) { + return -1; + } + + ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); + return 0; +} + +static const char *res_sdp_srtp_get_attr(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) +{ + int taglen; + + if (!srtp) { + return NULL; + } + + /* Set encryption properties */ + if (!srtp->crypto) { + if (AST_LIST_NEXT(srtp, sdp_srtp_list)) { + srtp->crypto = res_sdp_crypto_alloc(); + ast_log(LOG_ERROR, "SRTP SDP list was not empty\n"); + } else { + const int len = default_taglen_32 ? AST_SRTP_CRYPTO_TAG_32 : AST_SRTP_CRYPTO_TAG_80; + const int attr[][3] = { + /* This array creates the following list: + * a=crypto:1 AES_CM_128_HMAC_SHA1_ ... + * a=crypto:2 AEAD_AES_128_GCM ... + * a=crypto:3 AES_256_CM_HMAC_SHA1_ ... + * a=crypto:4 AEAD_AES_256_GCM ... + * a=crypto:5 AES_192_CM_HMAC_SHA1_ ... + * something like 'AEAD_AES_192_GCM' is not specified by the RFCs + * + * If you want to prefer another crypto suite or you want to + * exclude a suite, change this array and recompile Asterisk. + * This list cannot be changed from rtp.conf because you should + * know what you are doing. Especially AES-192 and AES-GCM are + * broken in many VoIP clients, see + * https://github.com/cisco/libsrtp/pull/170 + * https://github.com/cisco/libsrtp/pull/184 + * Furthermore, AES-GCM uses a shorter crypto-suite string which + * causes Nokia phones based on Symbian/S60 to reject the whole + * INVITE with status 500, even if a matching suite was offered. + * AES-256 might just waste your processor cycles, especially if + * your TLS transport is not secured with equivalent grade, see + * https://security.stackexchange.com/q/61361 + * Therefore, AES-128 was preferred here. + * + * If you want to enable one of those defines, please, go for + * CFLAGS='-DENABLE_SRTP_AES_GCM' ./configure && sudo make install + */ + { len, 0, 30 }, +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) + { AST_SRTP_CRYPTO_TAG_16, 0, AES_128_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_256) && defined(ENABLE_SRTP_AES_256) + { len, AST_SRTP_CRYPTO_AES_256, 46 }, +#endif +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) && defined(ENABLE_SRTP_AES_256) + { AST_SRTP_CRYPTO_TAG_16, AST_SRTP_CRYPTO_AES_256, AES_256_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_192) && defined(ENABLE_SRTP_AES_192) + { len, AST_SRTP_CRYPTO_AES_192, 38 }, +#endif + }; + struct ast_sdp_srtp *tmp = srtp; + int i; + + for (i = 0; i < ARRAY_LEN(attr); i++) { + if (attr[i][0]) { + ast_set_flag(tmp, attr[i][0]); + } + if (attr[i][1]) { + ast_set_flag(tmp, attr[i][1]); + } + tmp->crypto = sdp_crypto_alloc(attr[i][2]); /* key_len */ + tmp->crypto->tag = (i + 1); /* tag starts at 1 */ + + if (i < ARRAY_LEN(attr) - 1) { + AST_LIST_NEXT(tmp, sdp_srtp_list) = ast_sdp_srtp_alloc(); + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + } + } + } + + if (dtls_enabled) { + /* If DTLS-SRTP is enabled the key details will be pulled from TLS */ + return NULL; + } + + /* set the key length based on INVITE or settings */ + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_80)) { + taglen = 80; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { + taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = default_taglen_32 ? 32 : 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; + } + + if (srtp->crypto && (res_sdp_crypto_build_offer(srtp->crypto, taglen) >= 0)) { + return srtp->crypto->a_crypto; + } + + ast_log(LOG_WARNING, "No SRTP key management enabled\n"); + return NULL; +} + +static struct ast_sdp_crypto_api res_sdp_crypto_api = { + .dtor = res_sdp_crypto_dtor, + .alloc = res_sdp_crypto_alloc, + .build_offer = res_sdp_crypto_build_offer, + .parse_offer = res_sdp_crypto_parse_offer, + .get_attr = res_sdp_srtp_get_attr, +}; + static void res_srtp_shutdown(void) { - srtp_install_event_handler(NULL); + ast_sdp_crypto_unregister(&res_sdp_crypto_api); ast_rtp_engine_unregister_srtp(); + srtp_install_event_handler(NULL); #ifdef HAVE_SRTP_SHUTDOWN srtp_shutdown(); #endif @@ -607,6 +1186,12 @@ static int res_srtp_init(void) return -1; } + if (ast_sdp_crypto_register(&res_sdp_crypto_api)) { + ast_log(AST_LOG_WARNING, "Failed to register SDP SRTP crypto API\n"); + res_srtp_shutdown(); + return -1; + } + g_initialized = 1; return 0; } From b3c2f1164b95330daff5a6cf66b943dc2bf36138 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 11 Aug 2016 10:50:09 -0500 Subject: [PATCH 0634/1578] alembic: add auth_username to endpoint's identify_by enum A new identify_by option was added recently, auth_username. However, this setting was not added as an allowable choice in the database enumeration value. This patch updates the current enumeration, adding in the new setting. ASTERISK-26268 #close Change-Id: Ib4788e8485e4cd40172ec0abbf5810a147ab8bf8 --- .../3772f8f828da_update_identify_by.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/3772f8f828da_update_identify_by.py diff --git a/contrib/ast-db-manage/config/versions/3772f8f828da_update_identify_by.py b/contrib/ast-db-manage/config/versions/3772f8f828da_update_identify_by.py new file mode 100644 index 00000000000..92695b09fc0 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/3772f8f828da_update_identify_by.py @@ -0,0 +1,44 @@ +"""update_identify_by + +Revision ID: 3772f8f828da +Revises: c7a44a5a0851 +Create Date: 2016-08-11 10:47:29.211063 + +""" + +# revision identifiers, used by Alembic. +revision = '3772f8f828da' +down_revision = 'c7a44a5a0851' + +from alembic import op +import sqlalchemy as sa + + +def enum_update(table_name, column_name, enum_name, enum_values): + if op.get_context().bind.dialect.name != 'postgresql': + op.alter_column(table_name, column_name, + type_=sa.Enum(*enum_values, name=enum_name)) + return + + # Postgres requires a few more steps + tmp = enum_name + '_tmp' + + op.execute('ALTER TYPE ' + enum_name + ' RENAME TO ' + tmp) + + updated = sa.Enum(*enum_values, name=enum_name) + updated.create(op.get_bind(), checkfirst=False) + + op.execute('ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name + + ' TYPE ' + enum_name + ' USING identify_by::text::' + enum_name) + + op.execute('DROP TYPE ' + tmp) + + +def upgrade(): + enum_update('ps_endpoints', 'identify_by', 'pjsip_identify_by_values', + ['username', 'auth_username']) + + +def downgrade(): + enum_update('ps_endpoints', 'identify_by', 'pjsip_identify_by_values', + ['username']) From ac0454f9fa2c46079255e2e38ee675bce2d088c4 Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Thu, 11 Aug 2016 10:50:09 -0500 Subject: [PATCH 0635/1578] Fixed compile flags for non-module libs The non-module libs libasteriskssl.dylib and libasteriskpj.dylib have long been missing the AST_NOT_MODULE compile flag. This was mostly okay, until a recent fix to improve compiler warnings when the AST_MODULE_SELF_SYM is missing broke the build on OS X/macOS/whatever they are calling it these days. Change-Id: I2cb51c890824f001280a5114f2e775f97c163516 --- main/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/Makefile b/main/Makefile index 663508a7546..a6c3ab1b87b 100644 --- a/main/Makefile +++ b/main/Makefile @@ -233,7 +233,7 @@ ASTSSL_LIB:=libasteriskssl.dylib # -install_name allows library to be found if installed somewhere other than # /lib or /usr/lib $(ASTSSL_LIB): _ASTLDFLAGS+=-dynamiclib -install_name $(ASTLIBDIR)/$(ASTSSL_LIB) -$(ASTSSL_LIB): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskssl\" +$(ASTSSL_LIB): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskssl\" -DAST_NOT_MODULE $(ASTSSL_LIB): LIBS+=$(ASTSSL_LIBS) $(ASTSSL_LIB): SOLINK=$(DYLINK) @@ -309,7 +309,7 @@ ASTPJ_LIB:=libasteriskpj.dylib # -install_name allows library to be found if installed somewhere other than # /lib or /usr/lib $(ASTPJ_LIB): _ASTLDFLAGS+=-dynamiclib -install_name $(ASTLIBDIR)/$(ASTPJ_LIB) $(PJ_LDFLAGS) -$(ASTPJ_LIB): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS) +$(ASTPJ_LIB): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS) -DAST_NOT_MODULE $(ASTPJ_LIB): LIBS+=$(PJPROJECT_LIBS) -lssl -lcrypto -luuid -lm -lrt -lpthread $(ASTPJ_LIB): SOLINK=$(DYLINK) From b6e03a5ff3eac6f5abdc524078722400f3371dc8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 29 Jul 2016 17:41:15 -0500 Subject: [PATCH 0636/1578] pjsip_distributor.c: Add missing allocation failure check. Change-Id: I932ab2cea845e534d9ff318035b6de39972d3b28 --- res/res_pjsip/pjsip_distributor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 715ecb26319..bce428e42a8 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -965,7 +965,7 @@ static int clean_task(const void *data) static void global_loaded(const char *object_type) { char *identifier_order = ast_sip_get_endpoint_identifier_order(); - char *io_copy = ast_strdupa(identifier_order); + char *io_copy = identifier_order ? ast_strdupa(identifier_order) : NULL; char *identify_method; ast_free(identifier_order); @@ -982,6 +982,7 @@ static void global_loaded(const char *object_type) /* Clean out the old task, if any */ ast_sched_clean_by_callback(prune_context, prune_task, clean_task); + /* Have to do something with the return value to shut up the stupid compiler. */ if (ast_sched_add_variable(prune_context, unidentified_prune_interval * 1000, prune_task, NULL, 1) < 0) { return; } From 5ba6357be2a140e558ddc14b7669bb08d035944d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 3 Aug 2016 16:24:39 -0500 Subject: [PATCH 0637/1578] res_pjsip: Make aor named lock a mutex. The named aor lock was always being locked for writes so a rwlock adds no benefit and may be slower because rwlocks are biased toward read locking. Change-Id: I8c5c2c780eb30ce5441832257beeb3506fd12b28 --- main/named_locks.c | 4 ++-- res/res_pjsip/location.c | 8 ++++---- res/res_pjsip_registrar.c | 4 ++-- res/res_pjsip_registrar_expire.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/main/named_locks.c b/main/named_locks.c index b977b553c64..59604838844 100644 --- a/main/named_locks.c +++ b/main/named_locks.c @@ -87,8 +87,8 @@ static void named_locks_shutdown(void) int ast_named_locks_init(void) { - named_locks = ao2_container_alloc_hash(0, 0, NAMED_LOCKS_BUCKETS, named_locks_hash, NULL, - named_locks_cmp); + named_locks = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, + NAMED_LOCKS_BUCKETS, named_locks_hash, NULL, named_locks_cmp); if (!named_locks) { return -1; } diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 46278dd0c0c..c0c4a1f15f2 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -209,12 +209,12 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_si struct ao2_container *contacts; struct ast_named_lock *lock; - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor)); + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", ast_sorcery_object_get_id(aor)); if (!lock) { return NULL; } - ao2_wrlock(lock); + ao2_lock(lock); contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); ao2_unlock(lock); ast_named_lock_put(lock); @@ -368,12 +368,12 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, int res; struct ast_named_lock *lock; - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor)); + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", ast_sorcery_object_get_id(aor)); if (!lock) { return -1; } - ao2_wrlock(lock); + ao2_lock(lock); res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent, via_addr, via_port, call_id, endpoint); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index a39dac676ea..f99a3b84dd4 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -525,12 +525,12 @@ static int register_aor(pjsip_rx_data *rdata, struct ao2_container *contacts = NULL; struct ast_named_lock *lock; - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", aor_name); + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", aor_name); if (!lock) { return PJ_TRUE; } - ao2_wrlock(lock); + ao2_lock(lock); contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); if (!contacts) { ao2_unlock(lock); diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c index 0d979a13f4e..61841a05407 100644 --- a/res/res_pjsip_registrar_expire.c +++ b/res/res_pjsip_registrar_expire.c @@ -44,7 +44,7 @@ static int expire_contact(void *obj, void *arg, int flags) struct ast_sip_contact *contact = obj; struct ast_named_lock *lock; - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", contact->aor); + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", contact->aor); if (!lock) { return 0; } @@ -53,7 +53,7 @@ static int expire_contact(void *obj, void *arg, int flags) * We need to check the expiration again with the aor lock held * in case another thread is attempting to renew the contact. */ - ao2_wrlock(lock); + ao2_lock(lock); if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) { ast_sip_location_delete_contact(contact); } From 4a5da6c9b42d875e342672c6031de82eb5bab6fd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 2 Aug 2016 13:53:35 -0500 Subject: [PATCH 0638/1578] taskprocessor.c: Tweak high water checks. * The high water check in ast_taskprocessor_alert_set_levels() would trigger immediately if the new high water level is zero and the queue was empty. * The high water check in taskprocessor_push() was off by one. Change-Id: I687729fb4efa6a0ba38ec9c1c133c4d407bc3d5d --- main/taskprocessor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 4a8497f1104..ceb5f5c7f32 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -608,7 +608,7 @@ int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_w tps_alert_add(tps, -1); } } else { - if (high_water <= tps->tps_queue_size) { + if (high_water < tps->tps_queue_size) { /* Update water mark alert immediately */ tps->high_water_alert = 1; tps_alert_add(tps, +1); @@ -883,11 +883,11 @@ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t) AST_LIST_INSERT_TAIL(&tps->tps_queue, t, list); previous_size = tps->tps_queue_size++; - if (previous_size >= tps->tps_queue_high) { + if (tps->tps_queue_high <= tps->tps_queue_size) { if (!tps->high_water_warned) { tps->high_water_warned = 1; - ast_log(LOG_WARNING, "The '%s' task processor queue reached %d scheduled tasks.\n", - tps->name, previous_size); + ast_log(LOG_WARNING, "The '%s' task processor queue reached %ld scheduled tasks.\n", + tps->name, tps->tps_queue_size); } if (!tps->high_water_alert) { tps->high_water_alert = 1; From 36b2a4053387e5e43e4b91bef24b1b79af15aabb Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 11 Aug 2016 11:01:33 -0600 Subject: [PATCH 0639/1578] autohints: Update CHANGES and extensions.conf.sample Make it clear that we're talking about device state hints and add an entry to the sample config. Change-Id: Iaef58ffb960191a21b713e8e0b51ce1fcd47e433 --- CHANGES | 11 +++++------ configs/samples/extensions.conf.sample | 5 +++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index ee746253288..7f3b0ad7c3d 100644 --- a/CHANGES +++ b/CHANGES @@ -286,12 +286,11 @@ Core - 'media cache delete ' - remove an item from the cache - 'media cache create ' - retrieve a URI and store it in the cache - * The ability for hints to be automatically created as a result of device state - changes now exists in the PBX. This functionality is referred to as "autohints" - and is configurable in extensions.conf by placing "autohints=yes" in the - context. If enabled then a hint will be automatically created with the name of - the device. - + * The ability for device state hints to be automatically created as a result of + device state changes now exists in the PBX. This functionality is referred to + as "autohints" and is configurable in extensions.conf by placing "autohints=yes" + in the context. If enabled a device state hint will be automatically created + with the name of the device. Functions ------------------ diff --git a/configs/samples/extensions.conf.sample b/configs/samples/extensions.conf.sample index f8770c55daf..28319b59219 100644 --- a/configs/samples/extensions.conf.sample +++ b/configs/samples/extensions.conf.sample @@ -197,6 +197,11 @@ TRUNKMSD=1 ; MSD digits to strip (usually 1 or 0) ; before "B". ; ;[context] +; +;autohints = yes +; If enabled for a context, a device state hint will be automatically created in +; the context with the name of the device and updated with device state changes. +; ;exten => someexten,{priority|label{+|-}offset}[(alias)],application(arg1,arg2,...) ; ; Timing list for includes is From d4ffbccef68d158e00c5736cf4f68abd2d3241ca Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 4 Aug 2016 18:03:56 -0500 Subject: [PATCH 0640/1578] location.c: Misc fixes and cleanups. * Eliminated most RAII_VAR() usage. * Added several missing allocation failure checks. * Made ast_sip_for_each_contact() allocate the wrapper ao2 object without a lock as it is not needed. Change-Id: Ie20913365156c95dd79e5d471cfd25e99ae880bc --- res/res_pjsip/location.c | 132 ++++++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 51 deletions(-) diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 46278dd0c0c..17cff10e66d 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -168,16 +168,15 @@ static int contact_link_static(void *obj, void *arg, int flags) struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor) { - RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); - struct ast_sip_contact *contact; + struct ao2_container *contacts; + struct ast_sip_contact *contact = NULL; contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (!contacts || (ao2_container_count(contacts) == 0)) { - return NULL; + if (contacts && ao2_container_count(contacts)) { + /* Get the first AOR contact in the container. */ + contact = ao2_callback(contacts, 0, NULL, NULL); } - - /* Get the first AOR contact in the container. */ - contact = ao2_callback(contacts, 0, NULL, NULL); + ao2_cleanup(contacts); return contact; } @@ -310,14 +309,16 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint) { + struct ast_sip_contact *contact; + int res; char name[MAX_OBJECT_FIELD * 2 + 3]; - RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); char hash[33]; ast_md5_hash(hash, uri); snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), hash); - if (!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name))) { + contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name); + if (!contact) { return -1; } @@ -357,7 +358,9 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri ast_string_field_set(contact, endpoint_name, ast_sorcery_object_get_id(endpoint)); } - return ast_sorcery_create(ast_sip_get_sorcery(), contact); + res = ast_sorcery_create(ast_sip_get_sorcery(), contact); + ao2_ref(contact, -1); + return res; } int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, @@ -598,7 +601,9 @@ static int voicemail_extension_to_str(const void *obj, const intptr_t *args, cha int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) { - char *copy, *name; + char *copy; + char *name; + int res; if (!on_aor || ast_strlen_zero(aors)) { return 0; @@ -606,15 +611,15 @@ int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) copy = ast_strdupa(aors); while ((name = ast_strip(strsep(©, ",")))) { - RAII_VAR(struct ast_sip_aor *, aor, - ast_sip_location_retrieve_aor(name), ao2_cleanup); - - if (!aor) { - continue; - } + struct ast_sip_aor *aor; - if (on_aor(aor, arg, 0)) { - return -1; + aor = ast_sip_location_retrieve_aor(name); + if (aor) { + res = on_aor(aor, arg, 0); + ao2_ref(aor, -1); + if (res) { + return -1; + } } } return 0; @@ -623,15 +628,16 @@ int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) static void contact_wrapper_destroy(void *obj) { struct ast_sip_contact_wrapper *wrapper = obj; + ast_free(wrapper->aor_id); ast_free(wrapper->contact_id); - ao2_ref(wrapper->contact, -1); + ao2_cleanup(wrapper->contact); } int ast_sip_for_each_contact(const struct ast_sip_aor *aor, ao2_callback_fn on_contact, void *arg) { - RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); + struct ao2_container *contacts; struct ao2_iterator i; int res = 0; void *object = NULL; @@ -647,7 +653,8 @@ int ast_sip_for_each_contact(const struct ast_sip_aor *aor, RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup); const char *aor_id = ast_sorcery_object_get_id(aor); - wrapper = ao2_alloc(sizeof(struct ast_sip_contact_wrapper), contact_wrapper_destroy); + wrapper = ao2_alloc_options(sizeof(struct ast_sip_contact_wrapper), + contact_wrapper_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!wrapper) { res = -1; break; @@ -671,6 +678,7 @@ int ast_sip_for_each_contact(const struct ast_sip_aor *aor, } } ao2_iterator_destroy(&i); + ao2_ref(contacts, -1); return res; } @@ -686,10 +694,11 @@ int ast_sip_contact_to_str(void *object, void *arg, int flags) static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf) { - RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create2( - ast_sip_get_sorcery(), aor, AST_HANDLER_ONLY_STRING), ast_variables_destroy); + struct ast_variable *objset; struct ast_variable *i; + objset = ast_sorcery_objectset_create2(ast_sip_get_sorcery(), aor, + AST_HANDLER_ONLY_STRING); if (!objset) { return -1; } @@ -701,6 +710,7 @@ static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf) for (i = objset; i; i = i->next) { char *camel = ast_to_camel_case(i->name); + if (strcmp(camel, "Contact") == 0) { ast_free(camel); camel = NULL; @@ -709,23 +719,28 @@ static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf) ast_free(camel); } + ast_variables_destroy(objset); return 0; } static int contacts_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_aor *aor = obj; - RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free); + struct ast_str *str; + + str = ast_str_create(MAX_OBJECT_FIELD); + if (!str) { + *buf = NULL; + return -1; + } ast_sip_for_each_contact(aor, ast_sip_contact_to_str, &str); ast_str_truncate(str, -1); *buf = ast_strdup(ast_str_buffer(str)); - if (!*buf) { - return -1; - } + ast_free(str); - return 0; + return *buf ? 0 : -1; } static int format_ami_aor_handler(void *obj, void *arg, int flags) @@ -733,17 +748,20 @@ static int format_ami_aor_handler(void *obj, void *arg, int flags) struct ast_sip_aor *aor = obj; struct ast_sip_ami *ami = arg; const struct ast_sip_endpoint *endpoint = ami->arg; - RAII_VAR(struct ast_str *, buf, - ast_sip_create_ami_event("AorDetail", ami), ast_free); - + struct ast_str *buf; + struct ao2_container *contacts; int total_contacts; int num_permanent; - RAII_VAR(struct ao2_container *, contacts, - ast_sip_location_retrieve_aor_contacts(aor), ao2_cleanup); + buf = ast_sip_create_ami_event("AorDetail", ami); if (!buf) { return -1; } + contacts = ast_sip_location_retrieve_aor_contacts(aor); + if (!contacts) { + ast_free(buf); + return -1; + } sip_aor_to_ami(aor, &buf); total_contacts = ao2_container_count(contacts); @@ -759,6 +777,8 @@ static int format_ami_aor_handler(void *obj, void *arg, int flags) astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); ami->count++; + ast_free(buf); + ao2_ref(contacts, -1); return 0; } @@ -776,7 +796,7 @@ struct ast_sip_endpoint_formatter endpoint_aor_formatter = { static struct ao2_container *cli_aor_get_container(const char *regex) { - RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup); + struct ao2_container *container; struct ao2_container *s_container; container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "aor", regex); @@ -784,16 +804,15 @@ static struct ao2_container *cli_aor_get_container(const char *regex) return NULL; } + /* Create a sorted container of aors. */ s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, ast_sorcery_object_id_sort, ast_sorcery_object_id_compare); - if (!s_container) { - return NULL; - } - - if (ao2_container_dup(s_container, container, 0)) { + if (s_container + && ao2_container_dup(s_container, container, 0)) { ao2_ref(s_container, -1); - return NULL; + s_container = NULL; } + ao2_ref(container, -1); return s_container; } @@ -895,7 +914,7 @@ static struct ao2_container *cli_contact_get_container(const char *regex) struct ao2_container *child_container; regex_t regexbuf; - parent_container = cli_aor_get_container(""); + parent_container = cli_aor_get_container(""); if (!parent_container) { return NULL; } @@ -922,9 +941,17 @@ static struct ao2_container *cli_contact_get_container(const char *regex) static void *cli_contact_retrieve_by_id(const char *id) { - RAII_VAR(struct ao2_container *, container, cli_contact_get_container(""), ao2_cleanup); + struct ao2_container *container; + void *obj; - return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK); + container = cli_contact_get_container(""); + if (!container) { + return NULL; + } + + obj = ao2_find(container, id, OBJ_SEARCH_KEY); + ao2_ref(container, -1); + return obj; } static int cli_contact_print_header(void *obj, void *arg, int flags) @@ -951,14 +978,13 @@ static int cli_contact_print_body(void *obj, void *arg, int flags) int flexwidth; const char *contact_id = ast_sorcery_object_get_id(contact); const char *hash_start = contact_id + strlen(contact->aor) + 2; - - RAII_VAR(struct ast_sip_contact_status *, status, - ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, contact_id), - ao2_cleanup); + struct ast_sip_contact_status *status; ast_assert(contact->uri != NULL); ast_assert(context->output_buffer != NULL); + status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, contact_id); + indent = CLI_INDENT_TO_SPACES(context->indent_level); flexwidth = CLI_LAST_TABSTOP - indent - 9 - strlen(contact->aor) + 1; @@ -972,6 +998,7 @@ static int cli_contact_print_body(void *obj, void *arg, int flags) ast_sip_get_contact_short_status_label(status ? status->status : UNKNOWN), (status && (status->status != UNKNOWN) ? ((long long) status->rtt) / 1000.0 : NAN)); + ao2_cleanup(status); return 0; } @@ -995,8 +1022,6 @@ static const char *cli_aor_get_id(const void *obj) static int cli_aor_print_header(void *obj, void *arg, int flags) { struct ast_sip_cli_context *context = arg; - RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup); - int indent = CLI_INDENT_TO_SPACES(context->indent_level); int filler = CLI_LAST_TABSTOP - indent - 7; @@ -1007,10 +1032,13 @@ static int cli_aor_print_header(void *obj, void *arg, int flags) indent, "Aor", filler, filler, CLI_HEADER_FILLER); if (context->recurse) { + struct ast_sip_cli_formatter_entry *formatter_entry; + context->indent_level++; formatter_entry = ast_sip_lookup_cli_formatter("contact"); if (formatter_entry) { formatter_entry->print_header(NULL, context, 0); + ao2_ref(formatter_entry, -1); } context->indent_level--; } @@ -1022,7 +1050,6 @@ static int cli_aor_print_body(void *obj, void *arg, int flags) { struct ast_sip_aor *aor = obj; struct ast_sip_cli_context *context = arg; - RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup); int indent; int flexwidth; @@ -1040,11 +1067,14 @@ static int cli_aor_print_body(void *obj, void *arg, int flags) ast_sorcery_object_get_id(aor), aor->max_contacts); if (context->recurse) { + struct ast_sip_cli_formatter_entry *formatter_entry; + context->indent_level++; formatter_entry = ast_sip_lookup_cli_formatter("contact"); if (formatter_entry) { formatter_entry->iterate(aor, formatter_entry->print_body, context); + ao2_ref(formatter_entry, -1); } context->indent_level--; From 2275494e8056b8ec670ef1e6eb61c42719248153 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 1 Aug 2016 15:07:30 -0500 Subject: [PATCH 0641/1578] res_pjsip res_pjsip_mwi: Misc fixes and cleanups. * Eliminated RAII_VAR() usage in ast_sip_persistent_endpoint_update_state(). * Added a missing allocation failure check to persistent_endpoint_find_or_create(). * Made persistent_endpoint_find_or_create() create the new object without a lock as it isn't needed. * Cleaned up some ao2 container allocation idioms. * Reordered res_pjsip_mwi.c load_module() and unload_module() Change-Id: If8ce88fbd82a0c72a37a2388f74f77237a6a36a8 --- res/res_pjsip/pjsip_configuration.c | 40 +++++++++++++++++++---------- res/res_pjsip_mwi.c | 30 ++++++++++++++-------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 16405ebce7f..9871b418614 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -169,7 +169,6 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) contact_status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, contact_id); - if (contact_status && contact_status->status != UNAVAILABLE) { state = AST_ENDPOINT_ONLINE; } @@ -296,7 +295,8 @@ static void endpoint_deleted_observer(const void *object) { const struct ast_sip_endpoint *endpoint = object; - ao2_find(persistent_endpoints, ast_endpoint_get_resource(endpoint->persistent), OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); + ao2_find(persistent_endpoints, ast_endpoint_get_resource(endpoint->persistent), + OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA); } static const struct ast_sorcery_observer endpoint_observers = { @@ -1224,16 +1224,16 @@ static void persistent_endpoint_destroy(void *obj) int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state) { - RAII_VAR(struct sip_persistent_endpoint *, persistent, NULL, ao2_cleanup); - SCOPED_AO2LOCK(lock, persistent_endpoints); + struct sip_persistent_endpoint *persistent; - if (!(persistent = ao2_find(persistent_endpoints, endpoint_name, OBJ_KEY | OBJ_NOLOCK))) { - return -1; + ao2_lock(persistent_endpoints); + persistent = ao2_find(persistent_endpoints, endpoint_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (persistent) { + endpoint_update_state(persistent->endpoint, state); + ao2_ref(persistent, -1); } - - endpoint_update_state(persistent->endpoint, state); - - return 0; + ao2_unlock(persistent_endpoints); + return persistent ? 0 : -1; } /*! \brief Internal function which finds (or creates) persistent endpoint information */ @@ -1242,16 +1242,25 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_ RAII_VAR(struct sip_persistent_endpoint *, persistent, NULL, ao2_cleanup); SCOPED_AO2LOCK(lock, persistent_endpoints); - if (!(persistent = ao2_find(persistent_endpoints, ast_sorcery_object_get_id(endpoint), OBJ_KEY | OBJ_NOLOCK))) { - if (!(persistent = ao2_alloc(sizeof(*persistent), persistent_endpoint_destroy))) { + persistent = ao2_find(persistent_endpoints, ast_sorcery_object_get_id(endpoint), + OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (!persistent) { + persistent = ao2_alloc_options(sizeof(*persistent), persistent_endpoint_destroy, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!persistent) { return NULL; } - if (!(persistent->endpoint = ast_endpoint_create("PJSIP", ast_sorcery_object_get_id(endpoint)))) { + persistent->endpoint = ast_endpoint_create("PJSIP", + ast_sorcery_object_get_id(endpoint)); + if (!persistent->endpoint) { return NULL; } persistent->aors = ast_strdup(endpoint->aors); + if (!persistent->aors) { + return NULL; + } ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN); @@ -1757,7 +1766,9 @@ int ast_res_pjsip_initialize_configuration(void) return -1; } - if (!(persistent_endpoints = ao2_container_alloc(PERSISTENT_BUCKETS, persistent_endpoint_hash, persistent_endpoint_cmp))) { + persistent_endpoints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, + PERSISTENT_BUCKETS, persistent_endpoint_hash, NULL, persistent_endpoint_cmp); + if (!persistent_endpoints) { return -1; } @@ -1979,6 +1990,7 @@ void ast_res_pjsip_destroy_configuration(void) ast_sip_unregister_cli_formatter(endpoint_formatter); ast_sip_destroy_cli(); ao2_cleanup(persistent_endpoints); + persistent_endpoints = NULL; } int ast_res_pjsip_reload_configuration(void) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index bf7f042760e..925556ed48d 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -748,7 +748,6 @@ static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint int ret = 0; mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE); - if (!mwi_subs) { return 0; } @@ -1089,7 +1088,7 @@ static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub, } } -/*! \note Called with the unsolicited_mwi conainer lock held. */ +/*! \note Called with the unsolicited_mwi container lock held. */ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags) { RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup); @@ -1212,7 +1211,8 @@ static void mwi_contact_added(const void *object) ao2_lock(unsolicited_mwi); - mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK); + mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, + OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK); if (mwi_subs) { for (; (mwi_sub = ao2_iterator_next(mwi_subs)); ao2_cleanup(mwi_sub)) { unsubscribe(mwi_sub, NULL, 0); @@ -1288,17 +1288,19 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - unsolicited_mwi = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp); - if (!unsolicited_mwi) { - ast_sip_unregister_subscription_handler(&mwi_handler); - return AST_MODULE_LOAD_DECLINE; - } - if (mwi_serializer_pool_setup()) { ast_log(AST_LOG_WARNING, "Failed to create MWI serializer pool. The default SIP pool will be used for MWI\n"); } + unsolicited_mwi = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MWI_BUCKETS, + mwi_sub_hash, NULL, mwi_sub_cmp); + if (!unsolicited_mwi) { + mwi_serializer_pool_shutdown(); + ast_sip_unregister_subscription_handler(&mwi_handler); + return AST_MODULE_LOAD_DECLINE; + } create_mwi_subscriptions(); + ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer); ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); @@ -1316,13 +1318,19 @@ static int load_module(void) static int unload_module(void) { + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); + ao2_callback(unsolicited_mwi, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL); ao2_ref(unsolicited_mwi, -1); + unsolicited_mwi = NULL; + mwi_serializer_pool_shutdown(); - ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); - ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); + ast_sip_unregister_subscription_handler(&mwi_handler); + ast_free(default_voicemail_extension); + default_voicemail_extension = NULL; return 0; } From aeb859dba9a0fc62e6d46088a0d5c162909541a9 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 11 Aug 2016 11:18:15 -0600 Subject: [PATCH 0642/1578] res_pjsip: Fail global load if debug or default_from_user are empty If debug was specified in the global configuration but left blank, the logger would treat it as a wildcard and log all hosts. If default_from_user was empty, a crash would result. The global apply handler now checks for empty strings. ASTERISK-26239 #close ASTERISK-26238 #close Change-Id: Ie75727f5cd5808845d92cc81f5713842fb203336 --- res/res_pjsip/config_global.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index 8a1b0d449f5..975c5eefe7a 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -118,6 +118,18 @@ static int global_apply(const struct ast_sorcery *sorcery, void *obj) struct global_config *cfg = obj; char max_forwards[10]; + if (ast_strlen_zero(cfg->debug)) { + ast_log(LOG_ERROR, + "Global option 'debug' can't be empty. Set it to a valid value or remove the entry to accept 'no' as the default\n"); + return -1; + } + + if (ast_strlen_zero(cfg->default_from_user)) { + ast_log(LOG_ERROR, + "Global option 'default_from_user' can't be empty. Set it to a valid value or remove the entry to accept 'asterisk' as the default\n"); + return -1; + } + snprintf(max_forwards, sizeof(max_forwards), "%u", cfg->max_forwards); ast_sip_add_global_request_header("Max-Forwards", max_forwards, 1); From 225fd1003fa3016e4a8030cbcaa5b5d0d99a7f45 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 11 Aug 2016 11:13:07 -0500 Subject: [PATCH 0643/1578] app_queue: Prevent crash when a call is forwarded to an invalid location When a call forward attempt is made from a Queue member, the current code will hang up the forwarding channel in an off-nominal condition prior to raising the Stasis events informing the rest of Asterisk that the call was forwarded. This will result in a slew of dreaded FRACKs, most likely leading to a crash. This patch modifies the code such that we don't hang up the forwarding channel even in an off-nominal condition until we've safely raised the Stasis messages. ASTERISK-25797 #close Change-Id: Ife5abed351691fd79105321636eaa8ea8dcdba38 --- apps/app_queue.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 39413f9a603..a5cb1264027 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4865,6 +4865,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte char tmpchan[256]; char *stuff; char *tech; + int failed = 0; ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan)); ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder)); @@ -4977,14 +4978,20 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if (ast_call(o->chan, stuff, 0)) { ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", tech, stuff); - do_hang(o); - numnochan++; + failed = 1; } } - ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL); ast_channel_publish_dial_forward(qe->chan, original, o->chan, NULL, "CANCEL", ast_channel_call_forward(original)); + if (o->chan) { + ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL); + } + + if (failed) { + do_hang(o); + numnochan++; + } /* Hangup the original channel now, in case we needed it */ ast_hangup(winner); From d7534e016bd4afc1c21301de15de95a002afcd13 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 11 Aug 2016 10:24:34 -0600 Subject: [PATCH 0644/1578] res_pjsip_caller_id: Copy header name to short header name When compact_headers was set, we were sending a zero-length header name for PAI and RPID because we always forced the short header name length to 0. We did this because we cloned the header from "From" and wanted to clear "f" from the sname. By cloning however, we bypass pjproject's automatic logic that sets sname to name if there's no compact form of the header, which there isn't for PAI and RPID. So now we force sname to be the same as name right after we set name. res_pjsip_diversion needed the same treatment for the Diversion header. ASTERISK-26241 #close Change-Id: I633ec139630cd83809aae00336cee4a10077e467 --- res/res_pjsip_caller_id.c | 2 +- res/res_pjsip_diversion.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 283ec94e51e..429cb610783 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -413,7 +413,7 @@ static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_fromt id_hdr = pjsip_from_hdr_create(tdata->pool); id_hdr->type = PJSIP_H_OTHER; pj_strdup(tdata->pool, &id_hdr->name, hdr_name); - id_hdr->sname.slen = 0; + id_hdr->sname = id_hdr->name; id_name_addr = pjsip_uri_clone(tdata->pool, base->uri); id_uri = pjsip_uri_get_uri(id_name_addr->uri); diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c index f1a6ddf77e5..82c3caaed6e 100644 --- a/res/res_pjsip_diversion.c +++ b/res/res_pjsip_diversion.c @@ -305,7 +305,7 @@ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirect hdr = pjsip_from_hdr_create(tdata->pool); hdr->type = PJSIP_H_OTHER; pj_strdup(tdata->pool, &hdr->name, &diversion_name); - hdr->sname.slen = 0; + hdr->sname = hdr->name; name_addr = pjsip_uri_clone(tdata->pool, base); uri = pjsip_uri_get_uri(name_addr->uri); From 9debe1ca2631eb133d1f4383d733afceacc0c4a3 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 11 Aug 2016 23:12:32 -0400 Subject: [PATCH 0645/1578] Run mandatory cleanup when startup fails. Errors during startup result in an exit. These error branches should be calling ast_run_atexit(0) to ensure mandatory cleanup is run. ASTERISK-26267 #close Change-Id: If226f2326ae2df7add20040696132214cf2bb680 --- main/asterisk.c | 362 +++++++++--------------------------------------- 1 file changed, 69 insertions(+), 293 deletions(-) diff --git a/main/asterisk.c b/main/asterisk.c index 05381fc1e6c..50d8af24ae9 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4252,13 +4252,21 @@ int main(int argc, char *argv[]) return 0; } +static inline void check_init(int init_result, const char *name) +{ + if (init_result) { + printf("%s initialization failed.\n%s", name, term_quit()); + ast_run_atexits(0); + exit(init_result == -2 ? 2 : 1); + } +} + static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup) { FILE *f; sigset_t sigs; int num; char *buf; - int moduleresult; /*!< Result from the module load subsystem */ char pbx_uuid[AST_UUID_STR_LEN]; /* Set time as soon as possible */ @@ -4352,15 +4360,8 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou register_config_cli(); read_config_maps(); - if (astobj2_init()) { - printf("Failed: astobj2_init\n%s", term_quit()); - exit(1); - } - - if (ast_named_locks_init()) { - printf("Failed: ast_named_locks_init\n%s", term_quit()); - exit(1); - } + check_init(astobj2_init(), "AO2"); + check_init(ast_named_locks_init(), "Named Locks"); if (ast_opt_console) { if (el_hist == NULL || el == NULL) @@ -4373,10 +4374,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou ast_xmldoc_load_documentation(); #endif - if (astdb_init()) { - printf("Failed: astdb_init\n%s", term_quit()); - exit(1); - } + check_init(astdb_init(), "ASTdb"); ast_uuid_init(); @@ -4393,94 +4391,28 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou callerid_init(); ast_builtins_init(); - if (ast_utils_init()) { - printf("Failed: ast_utils_init\n%s", term_quit()); - exit(1); - } - - if (ast_tps_init()) { - printf("Failed: ast_tps_init\n%s", term_quit()); - exit(1); - } - - if (ast_fd_init()) { - printf("Failed: ast_fd_init\n%s", term_quit()); - exit(1); - } - - if (ast_pbx_init()) { - printf("Failed: ast_pbx_init\n%s", term_quit()); - exit(1); - } - + check_init(ast_utils_init(), "Utilities"); + check_init(ast_tps_init(), "Task Processor Core"); + check_init(ast_fd_init(), "File Descriptor Debugging"); + check_init(ast_pbx_init(), "ast_pbx_init"); #ifdef TEST_FRAMEWORK - if (ast_test_init()) { - printf("Failed: ast_test_init\n%s", term_quit()); - exit(1); - } + check_init(ast_test_init(), "Test Framework"); #endif - - if (ast_translate_init()) { - printf("Failed: ast_translate_init\n%s", term_quit()); - exit(1); - } + check_init(ast_translate_init(), "Translator Core"); ast_aoc_cli_init(); - if (ast_sorcery_init()) { - printf("Failed: ast_sorcery_init\n%s", term_quit()); - exit(1); - } - - if (ast_codec_init()) { - printf("Failed: ast_codec_init\n%s", term_quit()); - exit(1); - } - - if (ast_format_init()) { - printf("Failed: ast_format_init\n%s", term_quit()); - exit(1); - } - - if (ast_format_cache_init()) { - printf("Failed: ast_format_cache_init\n%s", term_quit()); - exit(1); - } - - if (ast_codec_builtin_init()) { - printf("Failed: ast_codec_builtin_init\n%s", term_quit()); - exit(1); - } - - if (aco_init()) { - printf("Failed: aco_init\n%s", term_quit()); - exit(1); - } - - if (init_logger()) { /* Start logging subsystem */ - printf("Failed: init_logger\n%s", term_quit()); - exit(1); - } - - if (ast_bucket_init()) { - printf("Failed: ast_bucket_init\n%s", term_quit()); - exit(1); - } - - if (stasis_init()) { - printf("Stasis initialization failed.\n%s", term_quit()); - exit(1); - } - - if (ast_stasis_system_init()) { - printf("Stasis system-level information initialization failed.\n%s", term_quit()); - exit(1); - } - - if (ast_endpoint_stasis_init()) { - printf("Endpoint initialization failed.\n%s", term_quit()); - exit(1); - } + check_init(ast_sorcery_init(), "Sorcery"); + check_init(ast_codec_init(), "Codecs"); + check_init(ast_format_init(), "Formats"); + check_init(ast_format_cache_init(), "Format Cache"); + check_init(ast_codec_builtin_init(), "Built-in Codecs"); + check_init(aco_init(), "Configuration Option Framework"); + check_init(init_logger(), "Logger"); + check_init(ast_bucket_init(), "Bucket API"); + check_init(stasis_init(), "Stasis"); + check_init(ast_stasis_system_init(), "Stasis system-level information"); + check_init(ast_endpoint_stasis_init(), "Stasis Endpoint"); ast_makesocket(); /* GCC 4.9 gives a bogus "right-hand operand of comma expression has @@ -4506,218 +4438,62 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou threadstorage_init(); - if (ast_rtp_engine_init()) { - printf("Failed: ast_rtp_engine_init\n%s", term_quit()); - exit(1); - } + check_init(ast_rtp_engine_init(), "RTP Engine"); ast_autoservice_init(); - if (ast_timing_init()) { - printf("Failed: ast_timing_init\n%s", term_quit()); - exit(1); - } - - if (ast_ssl_init()) { - printf("Failed: ast_ssl_init\n%s", term_quit()); - exit(1); - } - - if (ast_pj_init()) { - printf("Failed: ast_pj_init\n%s", term_quit()); - exit(1); - } - - if (app_init()) { - printf("App core initialization failed.\n%s", term_quit()); - exit(1); - } - - if (devstate_init()) { - printf("Device state core initialization failed.\n%s", term_quit()); - exit(1); - } - - if (ast_msg_init()) { - printf("Failed: ast_msg_init\n%s", term_quit()); - exit(1); - } - - /* initialize the data retrieval API */ - if (ast_data_init()) { - printf("Failed: ast_data_init\n%s", term_quit()); - exit(1); - } - - if (ast_channels_init()) { - printf("Failed: ast_channels_init\n%s", term_quit()); - exit(1); - } - - if (ast_endpoint_init()) { - printf ("Failed: ast_endpoint_init\n%s", term_quit()); - exit(1); - } - - if (ast_pickup_init()) { - printf("Failed: ast_pickup_init\n%s", term_quit()); - exit(1); - } - - if (ast_bridging_init()) { - printf("Failed: ast_bridging_init\n%s", term_quit()); - exit(1); - } - - if (ast_parking_stasis_init()) { - printf("Failed: ast_parking_stasis_init\n%s", term_quit()); - exit(1); - } - - if (ast_device_state_engine_init()) { - printf("Failed: ast_device_state_engine_init\n%s", term_quit()); - exit(1); - } - - if (ast_presence_state_engine_init()) { - printf("Failed: ast_presence_state_engine_init\n%s", term_quit()); - exit(1); - } - - if (ast_dns_system_resolver_init()) { /* Initialize the default DNS resolver */ - printf("Failed: ast_dns_system_resolver_init\n%s", term_quit()); - exit(1); - } - - if ((moduleresult = load_modules(1))) { /* Load modules, pre-load only */ - printf("Failed: load_modules\n%s", term_quit()); - exit(moduleresult == -2 ? 2 : 1); - } - - if (ast_features_init()) { - printf("Failed: ast_features_init\n%s", term_quit()); - exit(1); - } - - if (dnsmgr_init()) { /* Initialize the DNS manager */ - printf("Failed: dnsmgr_init\n%s", term_quit()); - exit(1); - } - - if (ast_security_stasis_init()) { /* Initialize Security Stasis Topic and Events */ - printf("Failed: ast_security_stasis_init\n%s", term_quit()); - exit(1); - } - - if (ast_named_acl_init()) { /* Initialize the Named ACL system */ - printf("Failed: ast_named_acl_init\n%s", term_quit()); - exit(1); - } + check_init(ast_timing_init(), "Timing"); + check_init(ast_ssl_init(), "SSL"); + check_init(ast_pj_init(), "Embedded PJProject"); + check_init(app_init(), "App Core"); + check_init(devstate_init(), "Device State Core"); + check_init(ast_msg_init(), "Messaging API"); + check_init(ast_data_init(), "Data Retrieval API"); + check_init(ast_channels_init(), "Channel"); + check_init(ast_endpoint_init(), "Endpoints"); + check_init(ast_pickup_init(), "Call Pickup"); + check_init(ast_bridging_init(), "Bridging"); + check_init(ast_parking_stasis_init(), "Parking Core"); + check_init(ast_device_state_engine_init(), "Device State Engine"); + check_init(ast_presence_state_engine_init(), "Presence State Engine"); + check_init(ast_dns_system_resolver_init(), "Default DNS resolver"); + check_init(load_modules(1), "Module Preload"); + check_init(ast_features_init(), "Call Features"); + check_init(dnsmgr_init(), "DNS manager"); + check_init(ast_security_stasis_init(), "Security Stasis Topic and Events"); + check_init(ast_named_acl_init(), "Named ACL system"); ast_http_init(); /* Start the HTTP server, if needed */ - if (ast_indications_init()) { - printf("Failed: ast_indications_init\n%s", term_quit()); - exit(1); - } - - if (ast_cdr_engine_init()) { - printf("Failed: ast_cdr_engine_init\n%s", term_quit()); - exit(1); - } + check_init(ast_indications_init(), "Indication Tone Handling"); + check_init(ast_cdr_engine_init(), "CDR Engine"); ast_dsp_init(); ast_udptl_init(); - if (ast_image_init()) { - printf("Failed: ast_image_init\n%s", term_quit()); - exit(1); - } - - if (ast_file_init()) { - printf("Failed: ast_file_init\n%s", term_quit()); - exit(1); - } - - if (load_pbx()) { - printf("Failed: load_pbx\n%s", term_quit()); - exit(1); - } - - if (load_pbx_builtins()) { - printf("Failed: load_pbx_builtins\n%s", term_quit()); - exit(1); - } - - if (load_pbx_functions_cli()) { - printf("Failed: load_pbx_functions_cli\n%s", term_quit()); - exit(1); - } - - if (load_pbx_variables()) { - printf("Failed: load_pbx_variables\n%s", term_quit()); - exit(1); - } - - if (load_pbx_switch()) { - printf("Failed: load_pbx_switch\n%s", term_quit()); - exit(1); - } - - if (load_pbx_app()) { - printf("Failed: load_pbx_app\n%s", term_quit()); - exit(1); - } - - if (load_pbx_hangup_handler()) { - printf("Failed: load_pbx_hangup_handler\n%s", term_quit()); - exit(1); - } - - if (ast_local_init()) { - printf("Failed: ast_local_init\n%s", term_quit()); - exit(1); - } - - if (ast_cel_engine_init()) { - printf("Failed: ast_cel_engine_init\n%s", term_quit()); - exit(1); - } - - if (init_manager()) { - printf("Failed: init_manager\n%s", term_quit()); - exit(1); - } - - if (ast_enum_init()) { - printf("Failed: ast_enum_init\n%s", term_quit()); - exit(1); - } - - if (ast_cc_init()) { - printf("Failed: ast_cc_init\n%s", term_quit()); - exit(1); - } - - if (ast_sounds_index_init()) { - printf("Failed: ast_sounds_index_init\n%s", term_quit()); - exit(1); - } - - if ((moduleresult = load_modules(0))) { /* Load modules */ - printf("%s", term_quit()); - exit(moduleresult == -2 ? 2 : 1); - } + check_init(ast_image_init(), "Image"); + check_init(ast_file_init(), "Generic File Format Support"); + check_init(load_pbx(), "load_pbx"); + check_init(load_pbx_builtins(), "Builtin PBX Applications"); + check_init(load_pbx_functions_cli(), "PBX Functions Support"); + check_init(load_pbx_variables(), "PBX Variables Support"); + check_init(load_pbx_switch(), "PBX Switch Support"); + check_init(load_pbx_app(), "PBX Application Support"); + check_init(load_pbx_hangup_handler(), "PBX Hangup Handler Support"); + check_init(ast_local_init(), "Local Proxy Channel Driver"); + check_init(ast_cel_engine_init(), "CEL Engine"); + check_init(init_manager(), "Asterisk Manager Interface"); + check_init(ast_enum_init(), "ENUM Support"); + check_init(ast_cc_init(), "Call Completion Supplementary Services"); + check_init(ast_sounds_index_init(), "Sounds Indexer"); + check_init(load_modules(0), "Module"); /* * This has to load after the dynamic modules load, as items in the media * cache can't be constructed from items in the AstDB without their * bucket backends. */ - if (ast_media_cache_init()) { - printf("Failed: ast_media_cache_init\n%s", term_quit()); - exit(1); - } + check_init(ast_media_cache_init(), "Media Cache"); /* loads the cli_permissoins.conf file needed to implement cli restrictions. */ ast_cli_perms_init(0); From 922b74169f9ac1cf83178fe24db656c5e516ef0a Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 15 Aug 2016 12:17:51 +0000 Subject: [PATCH 0646/1578] manager: Clarify that dialplan manipulation actions are under system class. ASTERISK-26246 #close Change-Id: Id673b9786389f9d2a87f638ce1a25161f5f31657 --- configs/samples/manager.conf.sample | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configs/samples/manager.conf.sample b/configs/samples/manager.conf.sample index aec2d07f1b8..0eb64c8ae7a 100644 --- a/configs/samples/manager.conf.sample +++ b/configs/samples/manager.conf.sample @@ -125,7 +125,9 @@ bindaddr = 0.0.0.0 ; ; all - All event classes below (including any we may have missed). ; system - General information about the system and ability to run system -; management commands, such as Shutdown, Restart, and Reload. +; management commands, such as Shutdown, Restart, and Reload. This +; class also includes dialplan manipulation actions such as +; DialplanExtensionAdd and DialplanExtensionRemove. ; call - Information about channels and ability to set information in a ; running channel. ; log - Logging information. Read-only. (Defined but not yet used.) From ddab42e296a0c69ab40a2ecbe5cdcc961f6b6602 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 12 Aug 2016 11:15:38 -0500 Subject: [PATCH 0647/1578] func_channel: Reorganize documentation * Following the example of the PJSIP channel driver, the channel technology specific documentation has been moved to the respective channel drivers that provide that functionality. This has the benefit of locating the documentation of items with those modules that provide it. * Examples of using the CHANNEL function for both standard items as well as for PJSIP have been added. * The 'max_forwards' standard item has been documented. Change-Id: Ifaa79a232c8ac99cf8da6ef6cc7815d398b1b79b --- addons/chan_ooh323.c | 48 ++++++ channels/chan_dahdi.c | 54 +++++++ channels/chan_iax2.c | 19 +++ channels/pjsip/dialplan_functions.c | 13 ++ channels/sip/dialplan_functions.c | 82 +++++++++++ doc/appdocsxml.dtd | 2 +- funcs/func_channel.c | 218 ++++------------------------ 7 files changed, 243 insertions(+), 193 deletions(-) diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index 7e50bbfa596..127ba0c8fe7 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -22,6 +22,54 @@ extended ***/ +/*** DOCUMENTATION + + + + R/W Fax Detect + Returns 0 or 1 + Write yes or no + + + R/W t38support + Returns 0 or 1 + Write yes or no + + + R/0 Returns caller URL + + + R/0 Returns caller h323id + + + R/0 Returns caller dialed digits + + + R/0 Returns caller email + + + R/0 Returns callee email + + + R/0 Returns callee dialed digits + + + R/0 Returns caller URL + + + R/W Get or set the maximum number of call forwards for this channel. + + This number describes the number of times a call may be forwarded by this channel + before the call fails. "Forwards" in this case refers to redirects by phones as well + as calls to local channels. + + Note that this has no relation to the SIP Max-Forwards header. + + + + + ***/ + #include "chan_ooh323.h" #include diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 7a3c31fd56b..cbe7dba545b 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -178,6 +178,60 @@ ASTERISK_REGISTER_FILE() This application will Accept the R2 call either with charge or no charge. + + + + R/O DAHDI channel related to this channel. + + + R/O DAHDI span related to this channel. + + + R/O DAHDI channel type, one of: + + + + + + + + + + R/O PRI Keypad digits that came in with the SETUP message. + + + R/O PRI Reverse Charging Indication, one of: + + None + Reverse Charging Requested + + + + R/O PRI Nonzero if the channel has no B channel. + The channel is either on hold or a call waiting call. + + + W/O Change the channel's buffer policy (for the current call only) + This option takes two arguments: + Number of buffers, + Buffer policy being one of: + full + immediate + half + + + W/O Change the configuration of the active echo + canceller on the channel (if any), for the current call + only. + Possible values are: + on Normal mode (the echo canceller is actually reinitalized) + off Disabled + fax FAX/data mode (NLP disabled if possible, otherwise + completely disabled) + voice Voice mode (returns from FAX mode, reverting the changes that were made) + + + Transfer DAHDI Channel. diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 721da9a044a..1b3e287af47 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -212,6 +212,25 @@ ASTERISK_REGISTER_FILE() Gets or sets a variable that is sent to a remote IAX2 peer during call setup. + + + + R/O Get the peer's osptoken. + + + R/O Get the peer's ip address. + + + R/O Get the peer's username. + + + R/O Get the if the IAX channel is secured. + + + R/O Get the if the IAX channel is secured. + + + List IAX peers. diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index c1a3873d04c..322f56483da 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -411,6 +411,19 @@ + + + ; Log the current Call-ID + same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)}) + + ; Log the destination address of the audio stream + same => n,Log(NOTICE, ${CHANNEL(rtp,dest)}) + + ; Store the round-trip time associated with a + ; video stream in the CDR field video-rtt + same => n,Set(CDR(video-rtt)=${CHANNEL(rtcp,rtt,video)}) + + ***/ #include "asterisk.h" diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c index 644da385292..988378835fa 100644 --- a/channels/sip/dialplan_functions.c +++ b/channels/sip/dialplan_functions.c @@ -23,6 +23,88 @@ extended ***/ +/*** DOCUMENTATION + + + + R/O Get the IP address of the peer. + + + R/O Get the source IP address of the peer. + + + R/O Get the source port of the peer. + + + R/O Get the URI from the From: header. + + + R/O Get the URI from the Contact: header. + + + R/O Get the useragent. + + + R/O Get the name of the peer. + + + R/O 1 if T38 is offered or enabled in this channel, + otherwise 0 + + + R/O Get QOS information about the RTP stream + This option takes two additional arguments: + Argument 1: + audio Get data about the audio stream + video Get data about the video stream + text Get data about the text stream + Argument 2: + local_ssrc Local SSRC (stream ID) + local_lostpackets Local lost packets + local_jitter Local calculated jitter + local_maxjitter Local calculated jitter (maximum) + local_minjitter Local calculated jitter (minimum) + local_normdevjitterLocal calculated jitter (normal deviation) + local_stdevjitter Local calculated jitter (standard deviation) + local_count Number of received packets + remote_ssrc Remote SSRC (stream ID) + remote_lostpacketsRemote lost packets + remote_jitter Remote reported jitter + remote_maxjitter Remote calculated jitter (maximum) + remote_minjitter Remote calculated jitter (minimum) + remote_normdevjitterRemote calculated jitter (normal deviation) + remote_stdevjitterRemote calculated jitter (standard deviation) + remote_count Number of transmitted packets + rtt Round trip time + maxrtt Round trip time (maximum) + minrtt Round trip time (minimum) + normdevrtt Round trip time (normal deviation) + stdevrtt Round trip time (standard deviation) + all All statistics (in a form suited to logging, + but not for parsing) + + + R/O Get remote RTP destination information. + This option takes one additional argument: + Argument 1: + audio Get audio destination + video Get video destination + text Get text destination + Defaults to audio if unspecified. + + + R/O Get source RTP destination information. + This option takes one additional argument: + Argument 1: + audio Get audio destination + video Get video destination + text Get text destination + Defaults to audio if unspecified. + + + + ***/ + #include "asterisk.h" ASTERISK_REGISTER_FILE() diff --git a/doc/appdocsxml.dtd b/doc/appdocsxml.dtd index 511930fe26a..21f1b9d528e 100644 --- a/doc/appdocsxml.dtd +++ b/doc/appdocsxml.dtd @@ -67,7 +67,7 @@ - + diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 39d7499c78f..9831dd71fd5 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -232,207 +232,41 @@ ASTERISK_REGISTER_FILE() R/O returns the linkedid if available, otherwise returns the uniqueid. - - chan_sip provides the following additional options: - - - R/O Get the IP address of the peer. - - - R/O Get the source IP address of the peer. - - - R/O Get the source port of the peer. - - - R/O Get the URI from the From: header. - - - R/O Get the URI from the Contact: header. - - - R/O Get the useragent. - - - R/O Get the name of the peer. - - - R/O 1 if T38 is offered or enabled in this channel, - otherwise 0 - - - R/O Get QOS information about the RTP stream - This option takes two additional arguments: - Argument 1: - audio Get data about the audio stream - video Get data about the video stream - text Get data about the text stream - Argument 2: - local_ssrc Local SSRC (stream ID) - local_lostpackets Local lost packets - local_jitter Local calculated jitter - local_maxjitter Local calculated jitter (maximum) - local_minjitter Local calculated jitter (minimum) - local_normdevjitterLocal calculated jitter (normal deviation) - local_stdevjitter Local calculated jitter (standard deviation) - local_count Number of received packets - remote_ssrc Remote SSRC (stream ID) - remote_lostpacketsRemote lost packets - remote_jitter Remote reported jitter - remote_maxjitter Remote calculated jitter (maximum) - remote_minjitter Remote calculated jitter (minimum) - remote_normdevjitterRemote calculated jitter (normal deviation) - remote_stdevjitterRemote calculated jitter (standard deviation) - remote_count Number of transmitted packets - rtt Round trip time - maxrtt Round trip time (maximum) - minrtt Round trip time (minimum) - normdevrtt Round trip time (normal deviation) - stdevrtt Round trip time (standard deviation) - all All statistics (in a form suited to logging, - but not for parsing) - - - R/O Get remote RTP destination information. - This option takes one additional argument: - Argument 1: - audio Get audio destination - video Get video destination - text Get text destination - Defaults to audio if unspecified. - - - R/O Get source RTP destination information. - This option takes one additional argument: - Argument 1: - audio Get audio destination - video Get video destination - text Get text destination - Defaults to audio if unspecified. - - - - chan_iax2 provides the following additional options: - - - R/O Get the peer's osptoken. - - - R/O Get the peer's ip address. - - - R/O Get the peer's username. - - - R/O Get the if the IAX channel is secured. - - - R/O Get the if the IAX channel is secured. - - - chan_dahdi provides the following additional options: - - - R/O DAHDI channel related to this channel. - - - R/O DAHDI span related to this channel. - - - R/O DAHDI channel type, one of: - - - - - - - - - - R/O PRI Keypad digits that came in with the SETUP message. - - - R/O PRI Reverse Charging Indication, one of: - - None - Reverse Charging Requested - - - - R/O PRI Nonzero if the channel has no B channel. - The channel is either on hold or a call waiting call. - - - W/O Change the channel's buffer policy (for the current call only) - This option takes two arguments: - Number of buffers, - Buffer policy being one of: - full - immediate - half - - - W/O Change the configuration of the active echo - canceller on the channel (if any), for the current call - only. - Possible values are: - on Normal mode (the echo canceller is actually reinitalized) - off Disabled - fax FAX/data mode (NLP disabled if possible, otherwise - completely disabled) - voice Voice mode (returns from FAX mode, reverting the changes that were made) - - - chan_ooh323 provides the following additional options: - - - R/W Fax Detect - Returns 0 or 1 - Write yes or no - - - R/W t38support - Returns 0 or 1 - Write yes or no - - - R/0 Returns caller URL - - - R/0 Returns caller h323id - - - R/0 Returns caller dialed digits - - - R/0 Returns caller email - - - R/0 Returns callee email - - - R/0 Returns callee dialed digits - - - R/0 Returns caller URL - - R/W Get or set the maximum number of call forwards for this channel. - - This number describes the number of times a call may be forwarded by this channel - before the call fails. "Forwards" in this case refers to redirects by phones as well - as calls to local channels. - - Note that this has no relation to the SIP Max-Forwards header. - + R/W The maximum number of forwards allowed. + + + + + Gets/sets various pieces of information about the channel, additional item may be available from the channel driver; see its documentation for details. Any item requested that is not available on the current channel will return an empty string. + + ; Push a hangup handler subroutine existing at dialplan + ; location default,s,1 onto the current channel + same => n,Set(CHANNEL(hangup_handler_push)=default,s,1) + + ; Set the current tonezone to Germany (de) + same => n,Set(CHANNEL(tonezone)=de) + + ; Set the allowed maximum number of forwarding attempts + same => n,Set(CHANNEL(max_forwards)=10) + + ; If this channel is ejected from its next bridge, and if + ; the channel is not hung up, begin executing dialplan at + ; location default,after-bridge,1 + same => n,Set(CHANNEL(after_bridge_goto)=default,after-bridge,1) + + ; Log the current state of the channel + same => n,Log(NOTICE, This channel is: ${CHANNEL(state)}) + + ***/ From a19f4affe890dba3293f277cc17ab179bce51608 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 12 Aug 2016 13:53:41 -0500 Subject: [PATCH 0648/1578] manager: Add links between related events This patch adds some see-also references between related AMI events. It focuses primarily on those events that are guaranteed to come in pairs, such as DTMFBegin/DTMFEnd, as well as those that occur during the life cycle of an Asterisk channel, such as Newchannel/Hangup. Change-Id: Iaab600477052018d0f8c03d0c624c0856e9ff1f3 --- main/manager_channels.c | 56 +++++++++++++++++++++++++++++++++++++++-- main/rtp_engine.c | 6 +++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/main/manager_channels.c b/main/manager_channels.c index ec1f807dcf2..ce0e38d9c0a 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -44,6 +44,10 @@ ASTERISK_REGISTER_FILE() + + Newstate + Hangup + @@ -52,6 +56,10 @@ ASTERISK_REGISTER_FILE() + + Newchannel + Hangup + @@ -66,6 +74,12 @@ ASTERISK_REGISTER_FILE() A description of why the channel was hung up. + + Newchannel + SoftHangupRequest + HangupRequest + Newstate + @@ -75,6 +89,10 @@ ASTERISK_REGISTER_FILE() + + SoftHangupRequest + Hangup + @@ -84,6 +102,10 @@ ASTERISK_REGISTER_FILE() + + HangupRequest + Hangup + @@ -114,6 +136,9 @@ ASTERISK_REGISTER_FILE() A description of the Caller ID presentation. + + CALLERID + @@ -125,6 +150,9 @@ ASTERISK_REGISTER_FILE() The channel's previous account code + + CHANNEL + @@ -139,6 +167,9 @@ ASTERISK_REGISTER_FILE() Dial + Originate + Originate + DialEnd @@ -219,6 +250,9 @@ ASTERISK_REGISTER_FILE() Dial + Originate + Originate + DialBegin @@ -231,6 +265,9 @@ ASTERISK_REGISTER_FILE() The suggested MusicClass, if provided. + + Unhold + @@ -239,6 +276,9 @@ ASTERISK_REGISTER_FILE() + + Hold + @@ -249,7 +289,8 @@ ASTERISK_REGISTER_FILE() - ChanSpyStop + ChanSpyStop + ChanSpy @@ -261,7 +302,8 @@ ASTERISK_REGISTER_FILE() - ChanSpyStart + ChanSpyStart + ChanSpy @@ -274,6 +316,9 @@ ASTERISK_REGISTER_FILE() Hangup handler parameter string passed to the Gosub application. + + CHANNEL + @@ -380,6 +425,7 @@ ASTERISK_REGISTER_FILE() MusicOnHoldStop + StartMusicOnHold MusicOnHold @@ -856,6 +902,9 @@ static void channel_dtmf_begin_cb(void *data, struct stasis_subscription *sub, + + DTMFEnd + ***/ manager_event(EVENT_FLAG_DTMF, "DTMFBegin", @@ -902,6 +951,9 @@ static void channel_dtmf_end_cb(void *data, struct stasis_subscription *sub, + + DTMFBegin + ***/ manager_event(EVENT_FLAG_DTMF, "DTMFEnd", diff --git a/main/rtp_engine.c b/main/rtp_engine.c index c2b1c8c2b7b..0671374ef56 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -102,6 +102,9 @@ and sending this report. + + RTCPReceived + @@ -131,6 +134,9 @@ + + RTCPSent + ***/ From 3269cf4c17dc9c6c158942b68dd37a5f53f96662 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 12 Aug 2016 15:53:52 -0500 Subject: [PATCH 0649/1578] res_agi: Improve documentation * Groups of AGI commands that have similar functionality now reference each other, and all reference the AGI application for ease of wiki reference. * The documentation for the AGI application has been improved, in particular noting the various AGI types and how they are invoked. * A warning message has been added to DeadAGI, noting that it is deprecated. Change-Id: I479ccdee8a7393f01b18692c3d4ab7e6bdd1875d --- res/res_agi.c | 384 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 370 insertions(+), 14 deletions(-) diff --git a/res/res_agi.c b/res/res_agi.c index e8249e2027e..e0eb8e2ecbf 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -22,7 +22,6 @@ * * \author Mark Spencer * - * \todo Convert the rest of the AGI commands over to XML documentation */ /*** MODULEINFO @@ -85,6 +84,7 @@ ASTERISK_REGISTER_FILE() hangup + AGI @@ -98,6 +98,7 @@ ASTERISK_REGISTER_FILE() hangup + AGI @@ -138,6 +139,9 @@ ASTERISK_REGISTER_FILE() + + AGI + @@ -188,6 +192,11 @@ ASTERISK_REGISTER_FILE() + + get option + control stream file + AGI + @@ -203,6 +212,12 @@ ASTERISK_REGISTER_FILE() Returns 1 if successful, 0 otherwise. + + database get + database put + database deltree + AGI + @@ -217,6 +232,12 @@ ASTERISK_REGISTER_FILE() within a family in the Asterisk database. Returns 1 if successful, 0 otherwise. + + database get + database put + database del + AGI + @@ -234,6 +255,12 @@ ASTERISK_REGISTER_FILE() in parenthesis. Example return code: 200 result=1 (testvariable) + + database put + database del + database deltree + AGI + @@ -250,6 +277,12 @@ ASTERISK_REGISTER_FILE() value. Returns 1 if successful, 0 otherwise. + + database get + database del + database deltree + AGI + @@ -265,6 +298,9 @@ ASTERISK_REGISTER_FILE() Returns whatever the application returns, or -2 on failure to find application. + + AGI + @@ -279,6 +315,9 @@ ASTERISK_REGISTER_FILE() Stream the given file, and receive DTMF data. Returns the digits received from the channel at the other end. + + AGI + @@ -295,6 +334,11 @@ ASTERISK_REGISTER_FILE() variables, unlike GET VARIABLE. Example return code: 200 result=1 (testvariable) + + get variable + set variable + AGI + @@ -310,6 +354,8 @@ ASTERISK_REGISTER_FILE() stream file + control stream file + AGI @@ -325,6 +371,11 @@ ASTERISK_REGISTER_FILE() the variable in parentheses. Example return code: 200 result=1 (testvariable) + + get full variable + set variable + AGI + @@ -337,6 +388,9 @@ ASTERISK_REGISTER_FILE() Hangs up the specified channel. If no channel name is given, hangs up the current channel + + AGI + @@ -346,6 +400,9 @@ ASTERISK_REGISTER_FILE() Does nothing. + + AGI + @@ -363,6 +420,10 @@ ASTERISK_REGISTER_FILE() if one is received, or 0 if the channel does not support text reception. Returns -1 only on error/hangup. + + receive text + AGI + @@ -379,6 +440,11 @@ ASTERISK_REGISTER_FILE() do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parenthesis. + + receive char + send text + AGI + @@ -404,6 +470,9 @@ ASTERISK_REGISTER_FILE() lack of dtmf digits or reaching timeout. silence value must be preceded by s= and is also optional. + + AGI + @@ -419,6 +488,15 @@ ASTERISK_REGISTER_FILE() without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or -1 on error/hangup. + + say digits + say number + say phonetic + say date + say time + say datetime + AGI + @@ -434,6 +512,15 @@ ASTERISK_REGISTER_FILE() without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or -1 on error/hangup. + + say alpha + say number + say phonetic + say date + say time + say datetime + AGI + @@ -450,6 +537,15 @@ ASTERISK_REGISTER_FILE() completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or -1 on error/hangup. + + say alpha + say digits + say phonetic + say date + say time + say datetime + AGI + @@ -465,6 +561,15 @@ ASTERISK_REGISTER_FILE() playback completes without a digit pressed, the ASCII numerical value of the digit if one was pressed, or -1 on error/hangup. + + say alpha + say digits + say number + say date + say time + say datetime + AGI + @@ -483,6 +588,15 @@ ASTERISK_REGISTER_FILE() completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or -1 on error/hangup. + + say alpha + say digits + say number + say phonetic + say time + say datetime + AGI + @@ -501,6 +615,15 @@ ASTERISK_REGISTER_FILE() without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or -1 on error/hangup. + + say alpha + say digits + say number + say phonetic + say date + say datetime + AGI + @@ -528,6 +651,15 @@ ASTERISK_REGISTER_FILE() completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or -1 on error/hangup. + + say alpha + say digits + say number + say phonetic + say date + say time + AGI + @@ -542,6 +674,9 @@ ASTERISK_REGISTER_FILE() the channel does not support image transmission. Returns -1 only on error/hangup. Image names should not include extensions. + + AGI + @@ -559,6 +694,10 @@ ASTERISK_REGISTER_FILE() channel does not support text transmission. Returns -1 only on error/hangup. + + receive text + AGI + @@ -572,6 +711,9 @@ ASTERISK_REGISTER_FILE() seconds in the future. Of course it can be hungup before then as well. Setting to 0 will cause the autohangup feature to be disabled on this channel. + + AGI + @@ -583,6 +725,9 @@ ASTERISK_REGISTER_FILE() Changes the callerid of the current channel. + + AGI + @@ -594,6 +739,11 @@ ASTERISK_REGISTER_FILE() Sets the context for continuation upon exiting the application. + + set extension + set priority + AGI + @@ -605,6 +755,11 @@ ASTERISK_REGISTER_FILE() Changes the extension for continuation upon exiting the application. + + set context + set priority + AGI + @@ -629,6 +784,9 @@ ASTERISK_REGISTER_FILE() used. This generator will be stopped automatically when playing a file. Always returns 0. + + AGI + @@ -641,6 +799,11 @@ ASTERISK_REGISTER_FILE() Changes the priority for continuation upon exiting the application. The priority must be a valid priority or label. + + set context + set extension + AGI + @@ -653,6 +816,11 @@ ASTERISK_REGISTER_FILE() Sets a variable to the current channel. + + get variable + get full variable + AGI + @@ -690,6 +858,8 @@ ASTERISK_REGISTER_FILE() control stream file + get option + AGI @@ -708,6 +878,9 @@ ASTERISK_REGISTER_FILE() Enable/Disable TDD transmission/reception on a channel. Returns 1 if successful, or 0 if channel is not TDD-capable. + + AGI + @@ -722,6 +895,9 @@ ASTERISK_REGISTER_FILE() message system. level is the verbose level (1-4). Always returns 1 + + AGI + @@ -737,6 +913,9 @@ ASTERISK_REGISTER_FILE() one is received. Use -1 for the timeout value if you desire the call to block indefinitely. + + AGI + @@ -748,6 +927,16 @@ ASTERISK_REGISTER_FILE() Create a speech object to be used by the other Speech AGI commands. + + speech set + speech destroy + speech load grammar + speech unload grammar + speech activate grammar + speech deactivate grammar + speech recognize + AGI + @@ -760,6 +949,16 @@ ASTERISK_REGISTER_FILE() Set an engine-specific setting. + + speech create + speech destroy + speech load grammar + speech unload grammar + speech activate grammar + speech deactivate grammar + speech recognize + AGI + @@ -772,6 +971,13 @@ ASTERISK_REGISTER_FILE() speech create + speech set + speech load grammar + speech unload grammar + speech activate grammar + speech deactivate grammar + speech recognize + AGI @@ -785,6 +991,16 @@ ASTERISK_REGISTER_FILE() Loads the specified grammar as the specified name. + + speech create + speech set + speech destroy + speech unload grammar + speech activate grammar + speech deactivate grammar + speech recognize + AGI + @@ -796,6 +1012,16 @@ ASTERISK_REGISTER_FILE() Unloads the specified grammar. + + speech create + speech set + speech destroy + speech load grammar + speech activate grammar + speech deactivate grammar + speech recognize + AGI + @@ -807,6 +1033,16 @@ ASTERISK_REGISTER_FILE() Activates the specified grammar on the speech object. + + speech create + speech set + speech destroy + speech load grammar + speech unload grammar + speech deactivate grammar + speech recognize + AGI + @@ -818,6 +1054,16 @@ ASTERISK_REGISTER_FILE() Deactivates the specified grammar on the speech object. + + speech create + speech set + speech destroy + speech load grammar + speech unload grammar + speech activate grammar + speech recognize + AGI + @@ -832,14 +1078,27 @@ ASTERISK_REGISTER_FILE() Plays back given prompt while listening for speech and dtmf. + + speech create + speech set + speech destroy + speech load grammar + speech unload grammar + speech activate grammar + speech deactivate grammar + AGI + Executes an AGI compliant application. - + + How AGI should be invoked on the channel. + + Arguments to pass to the AGI script or server. @@ -848,21 +1107,72 @@ ASTERISK_REGISTER_FILE() Executes an Asterisk Gateway Interface compliant program on a channel. AGI allows Asterisk to launch external programs written in any language to control a telephony channel, play audio, read DTMF digits, - etc. by communicating with the AGI protocol on stdin and - stdout. As of 1.6.0, this channel will + etc. by communicating with the AGI protocol. + The following variants of AGI exist, and are chosen based on the value + passed to command: + + + The classic variant of AGI, this will launch the script + specified by command as a new process. + Communication with the script occurs on stdin and + stdout. If the full path to the script is not + provided, the astagidir specified in + asterisk.conf will be used. + + + + Connect Asterisk to a FastAGI server using a TCP connection. + The URI to the FastAGI server should be given in the form + [scheme]://host.domain[:port][/script/name], + where scheme is either agi + or hagi. + In the case of hagi, an SRV lookup will be + performed to try to connect to a list of FastAGI servers. The hostname in + the URI must be prefixed with _agi._tcp. prior to the DNS resolution. For + example, if you specify the URI hagi://agi.example.com/foo.agi + the DNS query would be for _agi._tcp.agi.example.com. You + will need to make sure this resolves correctly. + + + Use AMI to control the channel in AGI. AGI commands can be invoked + using the AMI action, with a variety of AGI specific + events passed back over the AMI connection. AsyncAGI should be invoked + by passing agi:async to the command + parameter. + + + + As of 1.6.0, this channel will not stop dialplan execution on hangup inside of this application. Dialplan execution will continue normally, even upon hangup until the AGI application signals a desire to stop (either by exiting or, in the case of a net script, by - closing the connection). A locally executed AGI script will receive SIGHUP on - hangup from the channel except when using DeadAGI. A fast AGI server will - correspondingly receive a HANGUP inline with the command dialog. Both of theses - signals may be disabled by setting the AGISIGHUP channel - variable to no before executing the AGI application. + closing the connection). + A locally executed AGI script will receive SIGHUP on + hangup from the channel except when using DeadAGI + (or when the channel is already hungup). A fast AGI server will + correspondingly receive a HANGUP inline with the command dialog. + Both of these signals may be disabled by setting the AGISIGHUP + channel variable to no before executing the AGI application. Alternatively, if you would like the AGI application to exit immediately after a channel hangup is detected, set the AGIEXITONHANGUP variable to yes. - Use the CLI command agi show commands to list available agi - commands. + + + ; Start the AGI script /tmp/my-cool-script.sh, passing it the contents + ; of the channel variable FOO + same => n,AGI(/tmp/my-cool-script.sh,${FOO}) + + ; Start the AGI script my-cool-script.sh located in the astagidir + ; directory, specified in asterisk.conf + same => n,AGI(my-cool-script.sh) + + ; Connect to the FastAGI server located at 127.0.0.1 and start the script + ; awesome-script + same => n,AGI(agi://127.0.0.1/awesome-script) + + ; Start AsyncAGI + same => n,AGI(agi:async) + This application sets the following channel variable upon completion: @@ -876,8 +1186,12 @@ ASTERISK_REGISTER_FILE() + AGI + AsyncAGIStart + AsyncAGIEnd EAGI DeadAGI + asterisk.conf @@ -890,8 +1204,10 @@ ASTERISK_REGISTER_FILE() Using 'EAGI' provides enhanced AGI, with incoming audio available out of band - on file descriptor 3. - + on file descriptor 3. In all other respects, it behaves in the same fashion as + AGI. See the documentation for the AGI dialplan application for + more information on invoking AGI on a channel. + This application sets the following channel variable upon completion: @@ -908,7 +1224,16 @@ ASTERISK_REGISTER_FILE() - + + This application is deprecated and may be removed in a future version + of Asterisk. Use the replacement application AGI instead + of DeadAGI. + + + Execute AGI on a 'dead' or hungup channel. See the documentation for the + AGI dialplan application for more information on invoking + AGI on a channel. + This application sets the following channel variable upon completion: @@ -936,6 +1261,11 @@ ASTERISK_REGISTER_FILE() Add an AGI command to the execute queue of the channel in Async AGI. + + AsyncAGIStart + AsyncAGIExec + AsyncAGIEnd + @@ -946,6 +1276,12 @@ ASTERISK_REGISTER_FILE() URL encoded string read from the AsyncAGI server. + + AsyncAGIEnd + AsyncAGIExec + AGI + AGI + @@ -954,6 +1290,12 @@ ASTERISK_REGISTER_FILE() + + AsyncAGIStart + AsyncAGIExec + AGI + AGI + @@ -968,6 +1310,12 @@ ASTERISK_REGISTER_FILE() URL encoded result string from the executed AGI command. + + AsyncAGIStart + AsyncAGIEnd + AGI + AGI + @@ -982,6 +1330,10 @@ ASTERISK_REGISTER_FILE() Random identification number assigned to the execution of this command. + + AGIExecEnd + AGI + @@ -997,6 +1349,10 @@ ASTERISK_REGISTER_FILE() The text result reason from AGI + + AGIExecStart + AGI + ***/ From 243f0cf99a10a6f7a4700cab9d12f846f0bbc143 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 13 Aug 2016 20:13:53 -0500 Subject: [PATCH 0650/1578] manager: Add tags to relate UserEvent actions/apps/events Change-Id: I80f8a981f62f50e74609c69c49edcaca6c95efa4 --- apps/app_userevent.c | 4 ++++ main/manager.c | 4 ++++ main/stasis.c | 1 + 3 files changed, 9 insertions(+) diff --git a/apps/app_userevent.c b/apps/app_userevent.c index c4f985f0eac..826b4dcb965 100644 --- a/apps/app_userevent.c +++ b/apps/app_userevent.c @@ -62,6 +62,10 @@ ASTERISK_REGISTER_FILE() eventname under the eventname key. + + UserEvent + UserEvent + ***/ diff --git a/main/manager.c b/main/manager.c index 029da70f730..df60f400fe1 100644 --- a/main/manager.c +++ b/main/manager.c @@ -827,6 +827,10 @@ ASTERISK_REGISTER_FILE() Send an event to manager sessions. + + UserEvent + UserEvent + diff --git a/main/stasis.c b/main/stasis.c index 91ad94e7664..e04d92a4ff9 100644 --- a/main/stasis.c +++ b/main/stasis.c @@ -59,6 +59,7 @@ ASTERISK_REGISTER_FILE(); UserEvent + UserEvent From d8a7594ffd1ec0a70257a912023cc4666e3c4222 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 13 Aug 2016 20:14:50 -0500 Subject: [PATCH 0651/1578] manager: Add tags to relate AoC events and actions Change-Id: Iea89a36222712148c1775c05ed0ad1049d67a70e --- main/aoc.c | 14 ++++++++++++++ main/manager.c | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/main/aoc.c b/main/aoc.c index 54edafad647..cd9c461c149 100644 --- a/main/aoc.c +++ b/main/aoc.c @@ -85,6 +85,10 @@ ASTERISK_REGISTER_FILE(); + + AOC-D + AOC-E + @@ -138,6 +142,11 @@ ASTERISK_REGISTER_FILE(); + + AOCMessage + AOC-S + AOC-E + @@ -151,6 +160,11 @@ ASTERISK_REGISTER_FILE(); + + AOCMessage + AOC-S + AOC-D + ***/ diff --git a/main/manager.c b/main/manager.c index 029da70f730..6b44ccb0b77 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1112,6 +1112,10 @@ ASTERISK_REGISTER_FILE() Generates an AOC-D or AOC-E message on a channel. + + AOC-D + AOC-E + From a93cd39ac1b47b7e457f23793ae1277c40274435 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 13 Aug 2016 20:15:58 -0500 Subject: [PATCH 0652/1578] manager: Add tags to relate Bridge related events,actions, and apps Change-Id: I67e6b79fa3102e494b5fe6cc7510472249080e85 --- main/bridge.c | 12 +++++++++++ main/features.c | 14 +++++++++++++ main/manager_bridges.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/main/bridge.c b/main/bridge.c index 68ac24bba54..e92875d1785 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -38,6 +38,10 @@ Returns detailed information about the available bridging technologies. + + BridgeTechnologySuspend + BridgeTechnologyUnsuspend + @@ -52,6 +56,10 @@ Marks a bridging technology as suspended, which prevents subsequently created bridges from using it. + + BridgeTechnologySuspend + BridgeTechnologyUnsuspend + @@ -66,6 +74,10 @@ Clears a previously suspended bridging technology, which allows subsequently created bridges to use it. + + BridgeTechnologyList + BridgeTechnologySuspend + ***/ diff --git a/main/features.c b/main/features.c index 4062e96ce51..0af5a78e3c3 100644 --- a/main/features.c +++ b/main/features.c @@ -202,6 +202,11 @@ ASTERISK_REGISTER_FILE() + + Bridge + BridgeCreate + BridgeEnter + @@ -228,6 +233,15 @@ ASTERISK_REGISTER_FILE() Bridge together two channels already in the PBX. + + Bridge + BridgeCreate + BridgeEnter + BridgeDestroy + BridgeInfo + BridgeKick + BridgeList + ***/ diff --git a/main/manager_bridges.c b/main/manager_bridges.c index 2069d507cd7..b6aaa550e63 100644 --- a/main/manager_bridges.c +++ b/main/manager_bridges.c @@ -42,6 +42,11 @@ static struct stasis_message_router *bridge_state_router; + + BridgeDestroy + BridgeEnter + BridgeLeave + @@ -50,6 +55,11 @@ static struct stasis_message_router *bridge_state_router; + + BridgeCreate + BridgeEnter + BridgeLeave + @@ -62,6 +72,11 @@ static struct stasis_message_router *bridge_state_router; The uniqueid of the channel being swapped out of the bridge + + BridgeCreate + BridgeDestroy + BridgeLeave + @@ -71,6 +86,11 @@ static struct stasis_message_router *bridge_state_router; + + BridgeCreate + BridgeDestroy + BridgeEnter + @@ -86,6 +106,12 @@ static struct stasis_message_router *bridge_state_router; Returns a list of bridges, optionally filtering on a bridge type. + + Bridge + BridgeDestroy + BridgeInfo + BridgeKick + @@ -100,6 +126,12 @@ static struct stasis_message_router *bridge_state_router; Returns detailed information about a bridge and the channels in it. + + Bridge + BridgeDestroy + BridgeKick + BridgeList + @@ -134,6 +166,13 @@ static struct stasis_message_router *bridge_state_router; Deletes the bridge, causing channels to continue or hang up. + + Bridge + BridgeInfo + BridgeKick + BridgeList + BridgeDestroy + @@ -153,6 +192,13 @@ static struct stasis_message_router *bridge_state_router; The channel is removed from the bridge. + + Bridge + BridgeDestroy + BridgeInfo + BridgeList + BridgeLeave + ***/ From e9fe08ea37b1c6c0ef79221e3a8830fabb73810f Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 13 Aug 2016 20:16:58 -0500 Subject: [PATCH 0653/1578] manager: Add tags to relate interrelated events/actions together Change-Id: Idbac539205aa732bf786c4f765577d8e9ff28ba4 --- main/manager.c | 83 +++++++++++++++++++++++++++++++++++++++++++ main/stasis_bridges.c | 6 ++++ 2 files changed, 89 insertions(+) diff --git a/main/manager.c b/main/manager.c index 029da70f730..22af825154e 100644 --- a/main/manager.c +++ b/main/manager.c @@ -149,6 +149,9 @@ ASTERISK_REGISTER_FILE() Logoff the current manager session. + + Login + @@ -168,6 +171,9 @@ ASTERISK_REGISTER_FILE() Login Manager. + + Logoff + @@ -329,6 +335,9 @@ ASTERISK_REGISTER_FILE() If a channel name is not provided then the variable is considered global. + + Getvar + @@ -349,6 +358,9 @@ ASTERISK_REGISTER_FILE() If a channel name is not provided then the variable is considered global. + + Setvar + @@ -381,6 +393,12 @@ ASTERISK_REGISTER_FILE() In the case where a category name is non-unique, a filter may be specified to match only categories with matching variable values. + + GetConfigJSON + UpdateConfig + CreateConfig + ListCategories + @@ -405,6 +423,12 @@ ASTERISK_REGISTER_FILE() In the case where a category name is non-unique, a filter may be specified to match only categories with matching variable values. + + GetConfig + UpdateConfig + CreateConfig + ListCategories + @@ -496,6 +520,12 @@ ASTERISK_REGISTER_FILE() This action will modify, create, or delete configuration elements in Asterisk configuration files. + + GetConfig + GetConfigJSON + CreateConfig + ListCategories + @@ -512,6 +542,12 @@ ASTERISK_REGISTER_FILE() directory. This action is intended to be used before an UpdateConfig action. + + GetConfig + GetConfigJSON + UpdateConfig + ListCategories + @@ -526,6 +562,12 @@ ASTERISK_REGISTER_FILE() This action will dump the categories in a given file. + + GetConfig + GetConfigJSON + UpdateConfig + CreateConfig + @@ -561,6 +603,9 @@ ASTERISK_REGISTER_FILE() Redirect (transfer) a call. + + BlindTransfer + @@ -581,6 +626,9 @@ ASTERISK_REGISTER_FILE() Attended transfer. + + AttendedTransfer + @@ -705,6 +753,9 @@ ASTERISK_REGISTER_FILE() Will return an Extension Status message. The response will include the hint for the extension and the status. + + ExtensionStatus + @@ -721,6 +772,9 @@ ASTERISK_REGISTER_FILE() Will return a Presence State message. The response will include the presence state and, if set, a presence subtype and custom message. + + PresenceStatus + @@ -758,6 +812,9 @@ ASTERISK_REGISTER_FILE() Waiting: 0 if messages waiting, 1 if no messages waiting. + + MailboxCount + @@ -778,6 +835,9 @@ ASTERISK_REGISTER_FILE() NewMessages: count OldMessages: count + + MailboxStatus + @@ -879,6 +939,9 @@ ASTERISK_REGISTER_FILE() Send a reload event. + + ModuleLoad + @@ -991,6 +1054,10 @@ ASTERISK_REGISTER_FILE() Loads, unloads or reloads an Asterisk module in a running system. + + Reload + ModuleCheck + @@ -1006,6 +1073,9 @@ ASTERISK_REGISTER_FILE() Checks if Asterisk module is loaded. Will return Success/Failure. For success returns, the module revision number is included. + + ModuleLoad + @@ -1171,6 +1241,9 @@ ASTERISK_REGISTER_FILE() this command can be used to create filters that may bypass filters defined in manager.conf + + FilterList + @@ -1180,6 +1253,9 @@ ASTERISK_REGISTER_FILE() The filters displayed are for the current session. Only those filters defined in manager.conf will be present upon starting a new session. + + Filter + @@ -1198,6 +1274,7 @@ ASTERISK_REGISTER_FILE() Redirect + BlindTransfer @@ -1275,6 +1352,9 @@ ASTERISK_REGISTER_FILE() + + ExtensionState + @@ -1288,6 +1368,9 @@ ASTERISK_REGISTER_FILE() + + PresenceState + ***/ diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c index 0e46edbea3b..a5f29c74eff 100644 --- a/main/stasis_bridges.c +++ b/main/stasis_bridges.c @@ -79,6 +79,9 @@ ASTERISK_REGISTER_FILE() Destination extension for the blind transfer. + + BlindTransfer + @@ -131,6 +134,9 @@ ASTERISK_REGISTER_FILE() SecondTransfererChannel: Alice's channel in the bridge with Bob. SecondBridgeUniqueid: The bridge between Alice and Bob. + + AtxFer + ***/ From 9202ca34a84fc74566d79e6c7f4f54459cb72600 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 13 Aug 2016 22:02:24 -0500 Subject: [PATCH 0654/1578] app_dial: Improve documentation * Add some helpful and other embedded paragraph tags * Document some of the lesser known channel variables set by Dial * Add examples for some common Dial uses, along with some more challenging but useful options Change-Id: Ib2fb9301e8e044d14fbb2815ec64161f19bbfbc1 --- apps/app_dial.c | 126 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 29 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index c4d52730300..48193b5a0d6 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -103,15 +103,16 @@ ASTERISK_REGISTER_FILE() - - + R/O Get the peer's osptoken. diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 2c44208b46c..f57d4670b32 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -568,11 +568,11 @@ ASTERISK_REGISTER_FILE() for all of the sip peers will be retrieved. - + The from parameter can be a configured peer name or in the form of "display-name" <URI>. - + Specifying a prefix of sip: will send the message as a SIP MESSAGE request. diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 322f56483da..4d888c8faa4 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -109,7 +109,7 @@ PJSIP_MEDIA_OFFER - + R/O Retrieve media related information. @@ -411,7 +411,7 @@ - + ; Log the current Call-ID same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)}) diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c index 988378835fa..53d15dddb6d 100644 --- a/channels/sip/dialplan_functions.c +++ b/channels/sip/dialplan_functions.c @@ -24,7 +24,7 @@ ***/ /*** DOCUMENTATION - + R/O Get the IP address of the peer. diff --git a/doc/appdocsxml.xslt b/doc/appdocsxml.xslt index 6e4c5ac500d..f067decaef2 100644 --- a/doc/appdocsxml.xslt +++ b/doc/appdocsxml.xslt @@ -6,7 +6,10 @@ - + + + + diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 9831dd71fd5..e816dcae00c 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -236,11 +236,7 @@ ASTERISK_REGISTER_FILE() R/W The maximum number of forwards allowed. - - - - - + @@ -266,7 +262,7 @@ ASTERISK_REGISTER_FILE() ; Log the current state of the channel same => n,Log(NOTICE, This channel is: ${CHANNEL(state)}) - + ***/ diff --git a/main/message.c b/main/message.c index 54c604c47d2..0fc67ec0259 100644 --- a/main/message.c +++ b/main/message.c @@ -123,16 +123,12 @@ ASTERISK_REGISTER_FILE() A To URI for the message. - - - + A From URI for the message if needed for the message technology being used to send this message. - - - + @@ -168,16 +164,12 @@ ASTERISK_REGISTER_FILE() The URI the message is to be sent to. - - - + A From URI for the message if needed for the message technology being used to send this message. - - - + The message body text. This must not contain any newlines as that diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index b508a2a596e..7efb1a20e6c 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -24,11 +24,11 @@ ***/ /*** DOCUMENTATION - + The from parameter can be a configured endpoint or in the form of "display-name" <URI>. - + Specifying a prefix of pjsip: will send the message as a SIP MESSAGE request. diff --git a/res/res_xmpp.c b/res/res_xmpp.c index c2b7796285b..32e1dd1ffc9 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -278,11 +278,11 @@ ASTERISK_REGISTER_FILE() Sends a message to a Jabber Client. - + Specifying a prefix of xmpp: will send the message as an XMPP chat message. - + Specifying a prefix of xmpp: will specify the account defined in xmpp.conf to send the message from. Note that this field is required for XMPP messages. From a5c0cf4922e54e3cf64c9bd954b0543e9dd037de Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 16 Aug 2016 11:24:29 -0600 Subject: [PATCH 0662/1578] ari: Add documentation that path parameters are case-sensitive Added to api.wiki.mustache so that the generated object pages have the notation in the table header as well as under each method that has path parameters. ASTERISK-25492 #close Change-Id: I36c46c6dc0c9ac350470394a999a1b19ef3fcdaf --- rest-api-templates/api.wiki.mustache | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rest-api-templates/api.wiki.mustache b/rest-api-templates/api.wiki.mustache index 0a54a64a70c..ad12bb69549 100644 --- a/rest-api-templates/api.wiki.mustache +++ b/rest-api-templates/api.wiki.mustache @@ -1,7 +1,8 @@ {{#api_declaration}} h1. {{name_title}} -|| Method || Path || Return Model || Summary || +|| Method || Path
h5. Parameters are case-sensitive || Return Model || Summary || + {{#apis}} {{#operations}} | {{http_method}} | [{{wiki_path}}|#{{nickname}}] | {{#response_class}}{{#is_primitive}}{{name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|{{wiki_prefix}} REST Data Models#{{singular_name}}]{{/is_primitive}}{{/response_class}} | {{summary}} | @@ -17,6 +18,7 @@ h2. {{nickname}}: {{http_method}} {{wiki_path}} {{#has_path_parameters}} h3. Path parameters +Parameters are case-sensitive. {{#path_parameters}} * {{name}}: _{{data_type}}_ - {{{wiki_description}}} {{#default_value}} From 57f4e4428a830c89436bf5025ca815a4e35776ac Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 17 Aug 2016 13:12:19 +0200 Subject: [PATCH 0663/1578] BuildSystem: Detect ca_list_path capabilities in external PJProject. Since Asterisk 13.8, pj_ssl_cert_load_from_files2 got detected only in the bundled PJProject but not in an external PJProject. Therefore, ca_list_path could not be used in pjsip.conf. With this change, pj_ssl_cert_load_from_files2 is detected again to enable ca_list_path again. ASTERISK-26303 #close Change-Id: I4a4a0cdc5cdff33730911fb4cfc0498c069043d0 --- configure | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 5ac2a1495b3..43114a359a2 100755 --- a/configure +++ b/configure @@ -25697,7 +25697,7 @@ if test "x${PBX_PJ_SSL_CERT_LOAD_FROM_FILES2}" != "x1" -a "${USE_PJ_SSL_CERT_LOA pbxlibdir="-L${PJ_SSL_CERT_LOAD_FROM_FILES2_DIR}" fi fi - pbxfuncname="pjsip/include/pjsip/sip_util.h" + pbxfuncname="pj_ssl_cert_load_from_files2" if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers AST_PJ_SSL_CERT_LOAD_FROM_FILES2_FOUND=yes else diff --git a/configure.ac b/configure.ac index 8ea1cb038d2..ba13bf46d97 100644 --- a/configure.ac +++ b/configure.ac @@ -2197,7 +2197,7 @@ if test "$USE_PJPROJECT" != "no" ; then CPPFLAGS="${saved_cppflags}" AST_EXT_LIB_CHECK([PJSIP_GET_DEST_INFO], [pjsip], [pjsip_get_dest_info], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) - AST_EXT_LIB_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj], [pjsip/include/pjsip/sip_util.h], [pjlib.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj], [pj_ssl_cert_load_from_files2], [pjlib.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip], [pjsip_endpt_set_ext_resolver], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) saved_cppflags="${CPPFLAGS}" From 046069011bc618f578b625be9116b406d1d3c5e8 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Thu, 11 Aug 2016 20:10:44 +0300 Subject: [PATCH 0664/1578] followme: initialize all config items on reload Some configuration directives were not initialized on reload, and hence were not reset to default if they were removed from followme.conf. ASTERISK-26288 #close Change-Id: Ief829e16374ad1e0ecfd63e6ee4923b5a1d1c150 --- apps/app_followme.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/app_followme.c b/apps/app_followme.c index a955843bc7b..938e63ec4bf 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -316,9 +316,17 @@ static struct call_followme *alloc_profile(const char *fmname) ast_mutex_init(&f->lock); ast_copy_string(f->name, fmname, sizeof(f->name)); - f->moh[0] = '\0'; - f->context[0] = '\0'; + AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); + AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); + AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); + return f; +} + +static void init_profile(struct call_followme *f, int activate) +{ f->enable_callee_prompt = enable_callee_prompt; + f->context[0] = '\0'; + ast_copy_string(f->moh, defaultmoh, sizeof(f->moh)); ast_copy_string(f->takecall, takecall, sizeof(f->takecall)); ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp)); ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt)); @@ -327,16 +335,9 @@ static struct call_followme *alloc_profile(const char *fmname) ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt)); ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt)); ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt)); - AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); - AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); - AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); - return f; -} - -static void init_profile(struct call_followme *f) -{ - f->active = 1; - ast_copy_string(f->moh, defaultmoh, sizeof(f->moh)); + if (activate) { + f->active = 1; + } } @@ -518,7 +519,7 @@ static int reload_followme(int reload) if (!new) ast_mutex_lock(&f->lock); /* Re-initialize the profile */ - init_profile(f); + init_profile(f, 1); free_numbers(f); var = ast_variable_browse(cfg, cat); while (var) { @@ -1248,6 +1249,7 @@ static struct call_followme *find_realtime(const char *name) ast_free(str); return NULL; } + init_profile(new_follower, 0); for (v = var; v; v = v->next) { if (!strcasecmp(v->name, "active")) { From 0b4fa6553262f94bcb0d37e279e0dc499c0fdd38 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 17 Aug 2016 14:13:56 -0500 Subject: [PATCH 0665/1578] res_pjsip_session.c: Fix unbound srv failover tests. Commit 1b666549f33d69dc080b212bf92126f3bc3a18b2 broke the srv failover functionality if a TCP connection gets disconnected. Under these conditions, session_inv_on_state_changed() gets a PJSIP_EVENT_TRANSPORT_ERROR and restarts the INVITE transaction on a new transport. Unfortunately, session_inv_on_tsx_state_changed() also gets the same PJSIP_EVENT_TRANSPORT_ERROR event and unconditionally terminates the session. * Made session_inv_on_tsx_state_changed() complete terminating the session on PJSIP_EVENT_TRANSPORT_ERROR only if the session state is still PJSIP_INV_STATE_DISCONNECTED. ASTERISK-26305 #close Reported by: Richard Mudgett Change-Id: If736e766b5c55b970fa38ca6c8a885caf27b897d --- res/res_pjsip_session.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 488492f4fb4..315393fdb89 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2773,22 +2773,21 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } break; case PJSIP_EVENT_TRANSPORT_ERROR: - /* - * Clear the module data now to block session_inv_on_state_changed() - * from calling session_end() if it hasn't already done so. - */ - inv->mod_data[id] = NULL; + if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + /* + * Clear the module data now to block session_inv_on_state_changed() + * from calling session_end() if it hasn't already done so. + */ + inv->mod_data[id] = NULL; - if (inv->state != PJSIP_INV_STATE_DISCONNECTED) { - session_end(session); + /* + * Pass the session ref held by session->inv_session to + * session_end_completion(). + */ + session_end_completion(session); + return; } - - /* - * Pass the session ref held by session->inv_session to - * session_end_completion(). - */ - session_end_completion(session); - return; + break; case PJSIP_EVENT_TIMER: /* * The timer event is run by the pjsip monitor thread and not @@ -2808,7 +2807,8 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans * Pass the session ref held by session->inv_session to * session_end_completion(). */ - if (ast_sip_push_task(session->serializer, session_end_completion, session)) { + if (session + && ast_sip_push_task(session->serializer, session_end_completion, session)) { /* Do it anyway even though this is not the right thread. */ session_end_completion(session); } From 534063fd670640019327e7f37a4fd81db16372f1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 16 Aug 2016 14:36:10 -0600 Subject: [PATCH 0666/1578] res_pjsip: Add contact_user to endpoint contact_user, when specified on an endpoint, will override the user portion of the Contact header on outgoing requests. Change-Id: Icd4ebfda2f2e44d3ac749d0b4066630e988407d4 --- CHANGES | 6 ++++- configs/samples/pjsip.conf.sample | 2 ++ ...2493ef32e6_add_contact_user_to_endpoint.py | 22 +++++++++++++++ include/asterisk/res_pjsip.h | 2 ++ res/res_pjsip.c | 26 ++++++++++++++++++ res/res_pjsip/pjsip_configuration.c | 27 +++++++++++++++++++ 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py diff --git a/CHANGES b/CHANGES index 7f3b0ad7c3d..1cfa7eb7c0a 100644 --- a/CHANGES +++ b/CHANGES @@ -42,6 +42,11 @@ chan_pjsip dialplan function PJSIP_MEDIA_OFFER, this allows the formats on a PJSIP channel to be re-negotiated and updated after session set up. +res_pjsip +------------------ + * A new endpoint configuration parameter 'contact_user' has been added which + when set will override the default user set on Contact headers in outgoing + requests. ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- @@ -407,7 +412,6 @@ cdr_csv * Added a new configuration option, "newcdrcolumns", which enables use of the post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'. - ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- ------------------------------------------------------------------------------ diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index eac0549049f..0d1c03909f1 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -762,6 +762,8 @@ ;rtp_timeout_hold= ; Hang up channel if RTP is not received for the specified ; number of seconds when the channel is on hold (default: ; "0" or not enabled) +;contact_user= ; On outgoing requests, force the user portion of the Contact + ; header to this value (default: "") ;==========================AUTH SECTION OPTIONS========================= ;[auth] diff --git a/contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py b/contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py new file mode 100644 index 00000000000..f91cff04e02 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py @@ -0,0 +1,22 @@ +"""Add contact_user to endpoint + +Revision ID: 4e2493ef32e6 +Revises: 3772f8f828da +Create Date: 2016-08-16 14:19:58.918466 + +""" + +# revision identifiers, used by Alembic. +revision = '4e2493ef32e6' +down_revision = '3772f8f828da' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('contact_user', sa.String(80))) + + +def downgrade(): + op.drop_column('ps_endpoints', 'contact_user') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index cd6b33db47f..4cede43919b 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -755,6 +755,8 @@ struct ast_sip_endpoint { struct ast_acl_list *contact_acl; /*! The number of seconds into call to disable fax detection. (0 = disabled) */ unsigned int faxdetect_timeout; + /*! Override the user on the outgoing Contact header with this value. */ + char *contact_user; }; /*! diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 8a9a19db89b..34edc8ca511 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -916,6 +916,12 @@ then the context setting is used. + + Force the user on the outgoing Contact header to this value. + + On outbound requests, force the user portion of the Contact header to this value. + + Authentication type @@ -2865,8 +2871,16 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, /* Update the dialog with the new local URI, we do it afterwards so we can use the dialog pool for construction */ pj_strdup_with_null(dlg->pool, &dlg->local.info_str, &local_uri); dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.slen, 0); + dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, local_uri.ptr, local_uri.slen, NULL); + if (!ast_strlen_zero(endpoint->contact_user)) { + pjsip_sip_uri *sip_uri; + + sip_uri = pjsip_uri_get_uri(dlg->local.contact->uri); + pj_strdup2(dlg->pool, &sip_uri->user, endpoint->contact_user); + } + /* If a request user has been specified and we are permitted to change it, do so */ if (!ast_strlen_zero(request_user)) { pjsip_sip_uri *sip_uri; @@ -3168,6 +3182,18 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s return -1; } + if (endpoint && !ast_strlen_zero(endpoint->contact_user)){ + pjsip_contact_hdr *contact_hdr; + pjsip_sip_uri *contact_uri; + static const pj_str_t HCONTACT = { "Contact", 7 }; + + contact_hdr = pjsip_msg_find_hdr_by_name((*tdata)->msg, &HCONTACT, NULL); + if (contact_hdr) { + contact_uri = pjsip_uri_get_uri(contact_hdr->uri); + pj_strdup2(pool, &contact_uri->user, endpoint->contact_user); + } + } + /* Add the user=phone parameter if applicable */ ast_sip_add_usereqphone(endpoint, (*tdata)->pool, (*tdata)->msg->line.req.uri); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 9871b418614..3bced1180ca 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1208,6 +1208,31 @@ static int voicemail_extension_to_str(const void *obj, const intptr_t *args, cha return 0; } +static int contact_user_handler(const struct aco_option *opt, + struct ast_variable *var, void *obj) +{ + struct ast_sip_endpoint *endpoint = obj; + + endpoint->contact_user = ast_strdup(var->value); + if (!endpoint->contact_user) { + return -1; + } + + return 0; +} + +static int contact_user_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + *buf = ast_strdup(endpoint->contact_user); + if (!(*buf)) { + return -1; + } + + return 0; +} + static void *sip_nat_hook_alloc(const char *name) { return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL); @@ -1905,6 +1930,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context)); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); @@ -2036,6 +2062,7 @@ static void endpoint_destructor(void* obj) ao2_cleanup(endpoint->persistent); ast_variables_destroy(endpoint->channel_vars); AST_VECTOR_FREE(&endpoint->ident_method_order); + ast_free(endpoint->contact_user); } static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription) From 38491401b5b1f8a74b872c33044e07897c4cc81b Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 14:55:58 +0200 Subject: [PATCH 0667/1578] sip_to_pjsip: Add cert_file and ca_list_path. When using the migration script sip_to_pjsip.py, cert_file and ca_list_path were not migrated to pjsip.conf. ASTERISK-22374 Change-Id: I4612877d190b7f86a48698cefbf5c4db6c265825 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..ecbac1340e2 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -464,6 +464,7 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): # bind # async_operations # ca_list_file +# ca_list_path # cert_file # privkey_file # password @@ -697,6 +698,12 @@ def set_tls_bindaddr(val, pjsip, nmapped): set_value('bind', bind, 'transport-tls', pjsip, nmapped, 'transport') +def set_tls_cert_file(val, pjsip, section, nmapped): + """Sets cert_file based on sip.conf tlscertfile""" + set_value('cert_file', val, section, pjsip, nmapped, + 'transport') + + def set_tls_private_key(val, pjsip, nmapped): """Sets privkey_file based on sip.conf tlsprivatekey or sslprivatekey""" set_value('priv_key_file', val, 'transport-tls', pjsip, nmapped, @@ -714,6 +721,12 @@ def set_tls_cafile(val, pjsip, nmapped): 'transport') +def set_tls_capath(val, pjsip, nmapped): + """Sets ca_list_path based on sip.conf tlscapath""" + set_value('ca_list_path', val, 'transport-tls', pjsip, nmapped, + 'transport') + + def set_tls_verifyclient(val, pjsip, nmapped): """Sets verify_client based on sip.conf tlsverifyclient""" set_value('verify_client', val, 'transport-tls', pjsip, nmapped, @@ -755,9 +768,11 @@ def create_tls(sip, pjsip, nmapped): tls_map = [ (['tlsbindaddr', 'sslbindaddr'], set_tls_bindaddr), + (['tlscertfile', 'sslcert', 'tlscert'], set_tls_cert_file), (['tlsprivatekey', 'sslprivatekey'], set_tls_private_key), (['tlscipher', 'sslcipher'], set_tls_cipher), (['tlscafile'], set_tls_cafile), + (['tlscapath', 'tlscadir'], set_tls_capath), (['tlsverifyclient'], set_tls_verifyclient), (['tlsdontverifyserver'], set_tls_verifyserver), (['tlsclientmethod', 'sslclientmethod'], set_tls_method) From d8b5970749cd95452a1597d543e80ac241aeeb36 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:02:07 +0200 Subject: [PATCH 0668/1578] sip_to_pjsip: Write cos and tos. When using the migration script sip_to_pjsip.py, both tos_sip and cos_sip got missed, because of a typo. Therefore, cos and tos were not written to pjsip.conf. Furthermore, that revealed a misuse of an internal function, caused by a copy-and-paste error. ASTERISK-22374 Change-Id: Id245ebadf70ab9776eb280c026288540af3af5c2 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..72fd6bb3295 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -534,14 +534,14 @@ def set_transport_common(section, pjsip, nmapped): pass try: - set_value('tos', sip.get('general', 'sip_tos')[0], 'general', pjsip, - nmapped, 'transport', section) + set_value('tos', sip.get('general', 'tos_sip')[0], section, pjsip, + nmapped, 'transport') except LookupError: pass try: - set_value('cos', sip.get('general', 'sip_cos')[0], 'general', pjsip, - nmapped, 'transport', section) + set_value('cos', sip.get('general', 'cos_sip')[0], section, pjsip, + nmapped, 'transport') except LookupError: pass From 163cc2d68fe794d01c412dafa78f7c8446506b8d Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:03:24 +0200 Subject: [PATCH 0669/1578] sip_to_pjsip: Write media_encryption. When using the migration script sip_to_pjsip.py, encryption=yes got missing and media_encryption=sdes was not written to pjsip.conf, because of a typo. ASTERISK-22374 Change-Id: I0fc3e55dc512a57603ae0fef41baacccf2a35c05 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..faa9a569014 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -396,7 +396,7 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ['trustpid', set_value('trust_id_inbound')], ['sendrpid', from_sendrpid], # send_pai, send_rpid ['send_diversion', set_value], - ['encrpytion', set_media_encryption], + ['encryption', set_media_encryption], ['avpf', set_value('use_avpf')], ['recordonfeature', set_record_on_feature], # automixon ['recordofffeature', set_record_off_feature], # automixon From a937c2ccb1cebf1bf34aa0e8c3a6e4b094b55514 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:04:53 +0200 Subject: [PATCH 0670/1578] sip_to_pjsip: Add defaultexpiry, maxexpiry, and minexpiry. When using the migration script sip_to_pjsip.py, defaultexpiry, maxexpiry, and minexpiry were not migrated to pjsip.conf. ASTERISK-22374 Change-Id: I007fbf543dcadc96fc3ed71c54da502bcb209b7b --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..a3131965d92 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -440,6 +440,9 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ['host', from_host], # contact, max_contacts ['qualifyfreq', set_value('qualify_frequency', type='aor')], + ['maxexpiry', set_value('maximum_expiration', type='aor')], + ['minexpiry', set_value('minimum_expiration', type='aor')], + ['defaultexpiry', set_value('default_expiration', type='aor')], ############################# maps to auth##################################### # type = auth From c0e0075718431e1abb17d92a01186d70ae0e5ca1 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:11:02 +0200 Subject: [PATCH 0671/1578] sip_to_pjsip: Map externhost/ip to Transports. When using the migration script sip_to_pjsip.py, the externhost or externip of sip.conf were erroneously written to Endpoints instead to Transports. ASTERISK-22374 Change-Id: I2c5873386cfc388899fa9cf2368639dd12f1b8e4 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..bf45530906a 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -383,8 +383,6 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ['session-timers', set_timers], # timers ['session-minse', set_value('timers_min_se')], ['session-expires', set_value('timers_sess_expires')], - ['externip', set_value('external_media_address')], - ['externhost', set_value('external_media_address')], # identify_by ? ['directmedia', set_direct_media], # direct_media # direct_media_method @@ -598,6 +596,8 @@ def create_udp(sip, pjsip, nmapped): extern_addr = sip.multi_get('general', ['externaddr', 'externip', 'externhost'])[0] host, port = split_hostport(extern_addr) + set_value('external_media_address', host, 'transport-udp', pjsip, + nmapped, 'transport') set_value('external_signaling_address', host, 'transport-udp', pjsip, nmapped, 'transport') if port: @@ -645,6 +645,8 @@ def create_tcp(sip, pjsip, nmapped): tcpport = sip.get('general', 'externtcpport')[0] except: tcpport = port + set_value('external_media_address', host, 'transport-tcp', pjsip, + nmapped, 'transport') set_value('external_signaling_address', host, 'transport-tcp', pjsip, nmapped, 'transport') if tcpport: @@ -789,6 +791,8 @@ def create_tls(sip, pjsip, nmapped): tlsport = sip.get('general', 'externtlsport')[0] except: tlsport = port + set_value('external_media_address', host, 'transport-tls', pjsip, + nmapped, 'transport') set_value('external_signaling_address', host, 'transport-tls', pjsip, nmapped, 'transport') if tlsport: From 9907e2b1c115934d254fc79a94a54de7e3d37e0d Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:13:03 +0200 Subject: [PATCH 0672/1578] sip_to_pjsip: Write local_net, contact_acl, contact_deny, and contact_permit. When using the migration script sip_to_pjsip.py, those keys got missing. These keys might appear several times and the function "merge_value" tried to collect those. However, because these keys have different names in sip.conf and pjsip.conf, "merge_value" was not able to find the new key name in sip.conf. This change lets "merge_value" search with the old key name in sip.conf and write with the new key name in pjsip.conf. ASTERISK-22374 Change-Id: Ie53c5278ae6f1cb8fa7e96c5289877d46981d9d2 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 33 ++++++-------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..22c749e5f92 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -54,10 +54,11 @@ def _set_value(k, v, s, r, n): def merge_value(key=None, val=None, section=None, pjsip=None, - nmapped=None, type='endpoint', section_to=None): + nmapped=None, type='endpoint', section_to=None, + key_to=None): """Merge values from the given section with those from the default.""" def _merge_value(k, v, s, r, n): - merge_value(key if key else k, v, s, r, n, type, section_to) + merge_value(key if key else k, v, s, r, n, type, section_to, key_to) # if no value or section return the merge_value # function with the enclosed key and type @@ -71,7 +72,8 @@ def _merge_value(k, v, s, r, n): sect = sip.default(section)[0] # for each merged value add it to pjsip.conf for i in sect.get_merged(key): - set_value(key, i, section_to if section_to else section, + set_value(key_to if key_to else key, i, + section_to if section_to else section, pjsip, nmapped, type) @@ -454,9 +456,9 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ['permit', merge_value(type='acl', section_to='acl')], ['deny', merge_value(type='acl', section_to='acl')], ['acl', merge_value(type='acl', section_to='acl')], - ['contactpermit', merge_value('contact_permit', type='acl', section_to='acl')], - ['contactdeny', merge_value('contact_deny', type='acl', section_to='acl')], - ['contactacl', merge_value('contact_acl', type='acl', section_to='acl')], + ['contactpermit', merge_value(type='acl', section_to='acl', key_to='contact_permit')], + ['contactdeny', merge_value(type='acl', section_to='acl', key_to='contact_deny')], + ['contactacl', merge_value(type='acl', section_to='acl', key_to='contact_acl')], ########################### maps to transport ################################# # type = transport @@ -499,21 +501,6 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ] -def add_localnet(section, pjsip, nmapped): - """ - Adds localnet values from sip.conf's general section to a transport in - pjsip.conf. Ideally, we would have just created a template with the - localnet sections, but because this is a script, it's not hard to add - the same thing on to every transport. - """ - try: - merge_value('local_net', sip.get('general', 'localnet')[0], 'general', - pjsip, nmapped, 'transport', section) - except LookupError: - # No localnet options configured. No biggie! - pass - - def set_transport_common(section, pjsip, nmapped): """ sip.conf has several global settings that in pjsip.conf apply to individual @@ -527,8 +514,8 @@ def set_transport_common(section, pjsip, nmapped): """ try: - merge_value('local_net', sip.get('general', 'localnet')[0], 'general', - pjsip, nmapped, 'transport', section) + merge_value('localnet', sip.get('general', 'localnet')[0], 'general', + pjsip, nmapped, 'transport', section, "local_net") except LookupError: # No localnet options configured. Move on. pass From 3eb02235f55603b0601a4c2ea54474282f780e13 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:14:36 +0200 Subject: [PATCH 0673/1578] sip_to_pjsip: Parse register even with transport. When using the migration script sip_to_pjsip.py and the register string started with a transport in sip.conf - like tls://... - register was not parsed correctly and therefore not migrated correctly to pjsip.conf. ASTERISK-22374 Change-Id: I44c12104eea2bd8558ada6d25d77edfecd92edd2 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..5eb6598dca3 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -907,6 +907,17 @@ def parse_user_part(self, user_part): the right of the user, then finish by using rpartition calls to remove everything to the left of the user. """ + self.peer = '' + self.protocol = 'udp' + protocols = ['udp', 'tcp', 'tls'] + for protocol in protocols: + position = user_part.find(protocol + '://') + if -1 < position: + post_transport = user_part[position + 6:] + self.peer, sep, self.protocol = user_part[:position + 3].rpartition('?') + user_part = post_transport + break + colons = user_part.count(':') if (colons == 3): # :domainport:secret:authuser @@ -927,11 +938,7 @@ def parse_user_part(self, user_part): # Invalid setting raise - pre_domain, sep, self.domain = pre_auth.partition('@') - self.peer, sep, post_peer = pre_domain.rpartition('?') - transport, sep, self.user = post_peer.rpartition('://') - - self.protocol = transport if transport else 'udp' + self.user, sep, self.domain = pre_auth.partition('@') def write(self, pjsip, nmapped): """ From acc5237e91861ca45f8277166c2ddfcd3ee5844e Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:15:38 +0200 Subject: [PATCH 0674/1578] sip_to_pjsip: Write username even without authname. When using the migration script sip_to_pjsip.py, now the (mandatory) username is written to pjsip.conf, even if there was no (optional) authname in the register string in sip.conf. ASTERISK-22374 Change-Id: Ie53e1997104cd2674821688b8a8247249f5e156f --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..64bb4922876 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -981,9 +981,8 @@ def write(self, pjsip, nmapped): if hasattr(self, 'secret') and self.secret: set_value('password', self.secret, auth_section, pjsip, nmapped, 'auth') - if hasattr(self, 'authuser'): - set_value('username', self.authuser or self.user, auth_section, - pjsip, nmapped, 'auth') + set_value('username', self.authuser if hasattr(self, 'authuser') + else self.user, auth_section, pjsip, nmapped, 'auth') set_value('outbound_auth', auth_section, section, pjsip, nmapped, 'registration') From 675721a7ab76513ef121995e74f73a59c7dab0d2 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:16:45 +0200 Subject: [PATCH 0675/1578] sip_to_pjsip: Map (session-)timers correctly. When using the migration script sip_to_pjsip.py, session-timers=accept and session-timers=refuse were mapped to wrong values. ASTERISK-22374 Change-Id: Ie4e90d5f6a29aff07837b7fe5bc8aea5fb6fc092 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..444f4db8f21 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -133,11 +133,14 @@ def set_timers(key, val, section, pjsip, nmapped): found in sip.conf. """ # pjsip.conf values can be yes/no, required, always + # 'required' is a new feature of chan_pjsip, which rejects + # all SIP clients not supporting Session Timers + # 'Accept' is the default value of chan_sip and maps to 'yes' + # chan_sip ignores the case, for example 'session-timers=Refuse' + val = val.lower() if val == 'originate': set_value('timers', 'always', section, pjsip, nmapped) - elif val == 'accept': - set_value('timers', 'required', section, pjsip, nmapped) - elif val == 'never': + elif val == 'refuse': set_value('timers', 'no', section, pjsip, nmapped) else: set_value('timers', 'yes', section, pjsip, nmapped) From da14c439a3a9d1540c32d098e3d2a67451c01680 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:17:47 +0200 Subject: [PATCH 0676/1578] sip_to_pjsip: Add compactheaders, timerb, timert1, and useragent. When using the migration script sip_to_pjsip.py, no section of type=system or type=general were created. Therefore the keys compactheaders, timerb, timert1, and useragent were not migrated to pjsip.conf. ASTERISK-22374 Change-Id: I318a453843227ea36bf130d392d4abd7bd26b5a1 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..9f6919a2d41 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -1080,6 +1080,35 @@ def find_non_mapped(sections, nmapped): pass +def map_system(sip, pjsip, nmapped): + section = 'system' # Just a label; you as user can change that + type = 'system' # Not a label, therefore not the same as section + + try: + user_agent = sip.get('general', 'useragent')[0] + set_value('user_agent', user_agent, 'global', pjsip, nmapped, 'global') + except LookupError: + pass + + try: + timer_t1 = sip.get('general', 'timert1')[0] + set_value('timer_t1', timer_t1, section, pjsip, nmapped, type) + except LookupError: + pass + + try: + timer_b = sip.get('general', 'timerb')[0] + set_value('timer_b', timer_b, section, pjsip, nmapped, type) + except LookupError: + pass + + try: + compact_headers = sip.get('general', 'compactheaders')[0] + set_value('compact_headers', compact_headers, section, pjsip, nmapped, type) + except LookupError: + pass + + def convert(sip, filename, non_mappings, include): """ Entry point for configuration file conversion. This @@ -1092,6 +1121,7 @@ def convert(sip, filename, non_mappings, include): nmapped = non_mapped(non_mappings[filename]) if not include: # Don't duplicate transport and registration configs + map_system(sip, pjsip, nmapped) map_transports(sip, pjsip, nmapped) map_registrations(sip, pjsip, nmapped) map_auth(sip, pjsip, nmapped) From e55d1e47aa28f7f0477bbbb251bdabaddf640f9a Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 15:19:15 +0200 Subject: [PATCH 0677/1578] sip_to_pjsip: Map the TLS method correctly. When using the migration script sip_to_pjsip.py and tlsclientmethod is not set in sip.conf, the default value of chan_sip (sslv23) is copied to pjsip.conf, to overwrite the default of the PJProject (tlsv1). This makes sure, res_pjsip is offering/using not just TLSv1.0 but TLSv1.2 as well. ASTERISK-22374 Change-Id: Ie530a3dae9926ae14f3920a21be1e2edb15bda4f --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 25 ++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 890921673b3..a9bc78e3efb 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -731,11 +731,6 @@ def set_tls_verifyserver(val, pjsip, nmapped): 'transport') -def set_tls_method(val, pjsip, nmapped): - """Sets method based on sip.conf tlsclientmethod or sslclientmethod""" - set_value('method', val, 'transport-tls', pjsip, nmapped, 'transport') - - def create_tls(sip, pjsip, nmapped): """ Creates a 'transport-tls' section in pjsip.conf based on the following @@ -759,8 +754,7 @@ def create_tls(sip, pjsip, nmapped): (['tlscipher', 'sslcipher'], set_tls_cipher), (['tlscafile'], set_tls_cafile), (['tlsverifyclient'], set_tls_verifyclient), - (['tlsdontverifyserver'], set_tls_verifyserver), - (['tlsclientmethod', 'sslclientmethod'], set_tls_method) + (['tlsdontverifyserver'], set_tls_verifyserver) ] try: @@ -780,6 +774,23 @@ def create_tls(sip, pjsip, nmapped): except LookupError: pass + try: + method = sip.multi_get('general', ['tlsclientmethod', 'sslclientmethod'])[0] + print 'In chan_sip, you specified the TLS version. With chan_sip, this was just for outbound client connections. In chan_pjsip, this value is for client and server. Instead, consider not to specify \'tlsclientmethod\' for chan_sip and \'method = sslv23\' for chan_pjsip.' + except LookupError: + """ + OpenSSL emerged during the 90s. SSLv2 and SSLv3 were the only + existing methods at that time. The OpenSSL project continued. And as + of today (OpenSSL 1.0.2) this does not start SSLv2 and SSLv3 anymore + but TLSv1.0 and v1.2. Or stated differently: This method should + have been called 'method = secure' or 'method = automatic' back in + the 90s. The PJProject did not realize this and uses 'tlsv1' as + default when unspecified, which disables TLSv1.2. chan_sip used + 'sslv23' as default when unspecified, which gives TLSv1.0 and v1.2. + """ + method = 'sslv23' + set_value('method', val, 'transport-tls', pjsip, nmapped, 'transport') + set_transport_common('transport-tls', pjsip, nmapped) try: extern_addr = sip.multi_get('general', ['externaddr', 'externip', From 5aa877305223faab5a1119276a934893ab9dc138 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 10 Aug 2016 15:14:09 -0500 Subject: [PATCH 0678/1578] ConfBridge: Rework announcer channel methodology One feature that confbridge has is the ability to play sounds to all participants in the conference. Prior to this commit, the algorithm for this was as follows: * Grab the playback lock * Push the conference announcer channel into the bridge * Play back the sound * Pull the conference announcer channel from the bridge * Release the playback lock The issue here is that the act of adding the playback channel to the bridge and removing it for each announcement is expensive. Amongst the expenses: * The announcer channel is imparted into the bridge, meaning a new thread is spun up for each playback. * When the announcer is added or removed from the bridge, it results in the BRIDGEPEER channel variable being set on all channels in the bridge. This requires keeping the bridge locked and locking each individual channel in order to set it. * There's also just the general overhead of adding the channel and removing it from the bridge. The bridge potentially has to reconfigure every single time With this commit, the paradigm for playing back announcements has shifted. * The announcer channel is now added to the bridge when the conference is allocated, and it is hung up when the conference is destroyed. * A taskprocessor is used to queue playbacks onto the announcer channel. This keeps the behavior from before where playbacks do not overlap. * The announcer channel is no longer placed into the bridge as departable. Since we are not constantly removing the channel from the bridge, it is safe to add the channel using an independent thread and simply hang the channel up when it is time for the conference to be destroyed. The use of the taskprocessor for playbacks opens up the interesting possibility of having asynchronous announcements played. In this commit, however, the behavior is still exactly the same as it previously was. ASTERISK-26289 Reported by Mark Michelson Change-Id: Ic5cd2c4b98a1eaa1715eb7a5b35d62f1a76d78a5 --- apps/app_confbridge.c | 274 ++++++++++++++++++++++----- apps/confbridge/conf_chan_announce.c | 30 +-- apps/confbridge/include/confbridge.h | 12 +- 3 files changed, 231 insertions(+), 85 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 82204c48fce..d5cbc41595a 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -71,6 +71,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_bridges.h" #include "asterisk/json.h" #include "asterisk/format_cache.h" +#include "asterisk/taskprocessor.h" /*** DOCUMENTATION @@ -962,6 +963,59 @@ static void handle_video_on_exit(struct confbridge_conference *conference, struc ao2_unlock(conference); } +struct hangup_data +{ + struct confbridge_conference *conference; + ast_mutex_t lock; + ast_cond_t cond; + int hungup; +}; + +/*! + * \brief Hang up the announcer channel + * + * This hangs up the announcer channel in the conference. This + * runs in the playback queue taskprocessor since we do not want + * to hang up the channel while it's trying to play an announcement. + * + * This task is performed synchronously, so there is no need to + * perform any cleanup on the passed-in data. + * + * \param data A hangup_data structure + * \return 0 + */ +static int hangup_playback(void *data) +{ + struct hangup_data *hangup = data; + + ast_autoservice_stop(hangup->conference->playback_chan); + + ast_hangup(hangup->conference->playback_chan); + hangup->conference->playback_chan = NULL; + + ast_mutex_lock(&hangup->lock); + hangup->hungup = 1; + ast_cond_signal(&hangup->cond); + ast_mutex_unlock(&hangup->lock); + + return 0; +} + +static void hangup_data_init(struct hangup_data *hangup, struct confbridge_conference *conference) +{ + ast_mutex_init(&hangup->lock); + ast_cond_init(&hangup->cond, NULL); + + hangup->conference = conference; + hangup->hungup = 0; +} + +static void hangup_data_destroy(struct hangup_data *hangup) +{ + ast_mutex_destroy(&hangup->lock); + ast_cond_destroy(&hangup->cond); +} + /*! * \brief Destroy a conference bridge * @@ -976,9 +1030,22 @@ static void destroy_conference_bridge(void *obj) ast_debug(1, "Destroying conference bridge '%s'\n", conference->name); if (conference->playback_chan) { - conf_announce_channel_depart(conference->playback_chan); - ast_hangup(conference->playback_chan); - conference->playback_chan = NULL; + if (conference->playback_queue) { + struct hangup_data hangup; + hangup_data_init(&hangup, conference); + ast_taskprocessor_push(conference->playback_queue, hangup_playback, &hangup); + + ast_mutex_lock(&hangup.lock); + while (!hangup.hungup) { + ast_cond_wait(&hangup.cond, &hangup.lock); + } + ast_mutex_unlock(&hangup.lock); + hangup_data_destroy(&hangup); + } else { + /* Playback queue is not yet allocated. Just hang up the channel straight */ + ast_hangup(conference->playback_chan); + conference->playback_chan = NULL; + } } /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */ @@ -992,7 +1059,7 @@ static void destroy_conference_bridge(void *obj) ast_free(conference->record_filename); conf_bridge_profile_destroy(&conference->b_profile); - ast_mutex_destroy(&conference->playback_lock); + ast_taskprocessor_unreference(conference->playback_queue); } /*! \brief Call the proper join event handler for the user for the conference bridge's current state @@ -1272,6 +1339,72 @@ void conf_ended(struct confbridge_conference *conference) ao2_unlock(conference); } +/*! + * \internal + * \brief Allocate playback channel for a conference. + * \pre expects conference to be locked before calling this function + */ +static int alloc_playback_chan(struct confbridge_conference *conference) +{ + struct ast_format_cap *cap; + char taskprocessor_name[AST_TASKPROCESSOR_MAX_NAME + 1]; + + cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!cap) { + return -1; + } + ast_format_cap_append(cap, ast_format_slin, 0); + conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL, + conference->name, NULL); + ao2_ref(cap, -1); + if (!conference->playback_chan) { + return -1; + } + + /* To make sure playback_chan has the same language as the bridge */ + ast_channel_lock(conference->playback_chan); + ast_channel_language_set(conference->playback_chan, conference->b_profile.language); + ast_channel_unlock(conference->playback_chan); + + ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n", + ast_channel_name(conference->playback_chan), conference->name); + + ast_taskprocessor_build_name(taskprocessor_name, sizeof(taskprocessor_name), + "Confbridge/%s", conference->name); + conference->playback_queue = ast_taskprocessor_get(taskprocessor_name, TPS_REF_DEFAULT); + if (!conference->playback_queue) { + ast_hangup(conference->playback_chan); + conference->playback_chan = NULL; + return -1; + } + return 0; +} + +/*! + * \brief Push the announcer channel into the bridge + * + * This runs in the playback queue taskprocessor. + * + * \param data A confbridge_conference + * \retval 0 Success + * \retval -1 Failed to push the channel to the bridge + */ +static int push_announcer(void *data) +{ + struct confbridge_conference *conference = data; + + if (conf_announce_channel_push(conference->playback_chan)) { + ast_hangup(conference->playback_chan); + conference->playback_chan = NULL; + ao2_cleanup(conference); + return -1; + } + + ast_autoservice_start(conference->playback_chan); + ao2_cleanup(conference); + return 0; +} + /*! * \brief Join a conference bridge * @@ -1317,9 +1450,6 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen return NULL; } - /* Setup lock for playback channel */ - ast_mutex_init(&conference->playback_lock); - /* Setup for the record channel */ conference->record_filename = ast_str_create(RECORD_FILENAME_INITIAL_SPACE); if (!conference->record_filename) { @@ -1364,6 +1494,22 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen /* Set the initial state to EMPTY */ conference->state = CONF_STATE_EMPTY; + if (alloc_playback_chan(conference)) { + ao2_unlink(conference_bridges, conference); + ao2_ref(conference, -1); + ao2_unlock(conference_bridges); + ast_log(LOG_ERROR, "Could not allocate announcer channel for conference '%s'\n", conference_name); + return NULL; + } + + if (ast_taskprocessor_push(conference->playback_queue, push_announcer, ao2_bump(conference))) { + ao2_unlink(conference_bridges, conference); + ao2_ref(conference, -1); + ao2_unlock(conference_bridges); + ast_log(LOG_ERROR, "Could not add announcer channel for conference '%s' bridge\n", conference_name); + return NULL; + } + if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) { ao2_lock(conference); conf_start_record(conference); @@ -1484,67 +1630,105 @@ static void leave_conference(struct confbridge_user *user) user->conference = NULL; } +struct playback_task_data { + struct confbridge_conference *conference; + const char *filename; + int say_number; + int playback_finished; + ast_mutex_t lock; + ast_cond_t cond; +}; + /*! - * \internal - * \brief Allocate playback channel for a conference. - * \pre expects conference to be locked before calling this function + * \brief Play an announcement into a confbridge + * + * This runs in the playback queue taskprocessor. This ensures that + * all playbacks are handled in sequence and do not play over top one + * another. + * + * This task runs synchronously so there is no need for performing any + * sort of cleanup on the input parameter. + * + * \param data A playback_task_data + * \return 0 */ -static int alloc_playback_chan(struct confbridge_conference *conference) +static int playback_task(void *data) { - struct ast_format_cap *cap; + struct playback_task_data *ptd = data; - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!cap) { - return -1; + /* Don't try to play if the playback channel has been hung up */ + if (!ptd->conference->playback_chan) { + goto end; } - ast_format_cap_append(cap, ast_format_slin, 0); - conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL, - conference->name, NULL); - ao2_ref(cap, -1); - if (!conference->playback_chan) { - return -1; + + ast_autoservice_stop(ptd->conference->playback_chan); + + /* The channel is all under our control, in goes the prompt */ + if (!ast_strlen_zero(ptd->filename)) { + ast_stream_and_wait(ptd->conference->playback_chan, ptd->filename, ""); + } else if (ptd->say_number >= 0) { + ast_say_number(ptd->conference->playback_chan, ptd->say_number, "", + ast_channel_language(ptd->conference->playback_chan), NULL); } + ast_autoservice_start(ptd->conference->playback_chan); - /* To make sure playback_chan has the same language of that profile */ - ast_channel_lock(conference->playback_chan); - ast_channel_language_set(conference->playback_chan, conference->b_profile.language); - ast_channel_unlock(conference->playback_chan); +end: + ast_mutex_lock(&ptd->lock); + ptd->playback_finished = 1; + ast_cond_signal(&ptd->cond); + ast_mutex_unlock(&ptd->lock); - ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n", - ast_channel_name(conference->playback_chan), conference->name); return 0; } +static void playback_task_data_init(struct playback_task_data *ptd, struct confbridge_conference *conference, + const char *filename, int say_number) +{ + ast_mutex_init(&ptd->lock); + ast_cond_init(&ptd->cond, NULL); + + ptd->filename = filename; + ptd->say_number = say_number; + ptd->conference = conference; + ptd->playback_finished = 0; +} + +static void playback_task_data_destroy(struct playback_task_data *ptd) +{ + ast_mutex_destroy(&ptd->lock); + ast_cond_destroy(&ptd->cond); +} + static int play_sound_helper(struct confbridge_conference *conference, const char *filename, int say_number) { + struct playback_task_data ptd; + /* Do not waste resources trying to play files that do not exist */ if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) { return 0; } - ast_mutex_lock(&conference->playback_lock); - if (!conference->playback_chan && alloc_playback_chan(conference)) { - ast_mutex_unlock(&conference->playback_lock); - return -1; - } - if (conf_announce_channel_push(conference->playback_chan)) { - ast_mutex_unlock(&conference->playback_lock); + playback_task_data_init(&ptd, conference, filename, say_number); + if (ast_taskprocessor_push(conference->playback_queue, playback_task, &ptd)) { + if (!ast_strlen_zero(filename)) { + ast_log(LOG_WARNING, "Unable to play file '%s' to conference %s\n", + filename, conference->name); + } else { + ast_log(LOG_WARNING, "Unable to say number '%d' to conference %s\n", + say_number, conference->name); + } + playback_task_data_destroy(&ptd); return -1; } - /* The channel is all under our control, in goes the prompt */ - if (!ast_strlen_zero(filename)) { - ast_stream_and_wait(conference->playback_chan, filename, ""); - } else if (say_number >= 0) { - ast_say_number(conference->playback_chan, say_number, "", - ast_channel_language(conference->playback_chan), NULL); + /* Wait for the playback to complete */ + ast_mutex_lock(&ptd.lock); + while (!ptd.playback_finished) { + ast_cond_wait(&ptd.cond, &ptd.lock); } + ast_mutex_unlock(&ptd.lock); - ast_debug(1, "Departing announcer channel '%s' from conference bridge '%s'\n", - ast_channel_name(conference->playback_chan), conference->name); - conf_announce_channel_depart(conference->playback_chan); - - ast_mutex_unlock(&conference->playback_lock); + playback_task_data_destroy(&ptd); return 0; } diff --git a/apps/confbridge/conf_chan_announce.c b/apps/confbridge/conf_chan_announce.c index ff30499086c..4060b99c4f1 100644 --- a/apps/confbridge/conf_chan_announce.c +++ b/apps/confbridge/conf_chan_announce.c @@ -143,31 +143,6 @@ struct ast_channel_tech *conf_announce_get_tech(void) return &announce_tech; } -void conf_announce_channel_depart(struct ast_channel *chan) -{ - struct announce_pvt *p = ast_channel_tech_pvt(chan); - - if (!p) { - return; - } - - ao2_ref(p, +1); - ao2_lock(p); - if (!ast_test_flag(&p->base, AST_UNREAL_CARETAKER_THREAD)) { - ao2_unlock(p); - ao2_ref(p, -1); - return; - } - ast_clear_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); - chan = p->base.chan; - ao2_unlock(p); - ao2_ref(p, -1); - if (chan) { - ast_bridge_depart(chan); - ast_channel_unref(chan); - } -} - int conf_announce_channel_push(struct ast_channel *ast) { struct ast_bridge_features *features; @@ -186,20 +161,17 @@ int conf_announce_channel_push(struct ast_channel *ast) if (!chan) { return -1; } - ast_channel_ref(chan); } features = ast_bridge_features_new(); if (!features) { - ast_channel_unref(chan); return -1; } ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE); /* Impart the output channel into the bridge */ if (ast_bridge_impart(p->bridge, chan, NULL, features, - AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { - ast_channel_unref(chan); + AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { return -1; } ao2_lock(p); diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 5ae0421131b..5d71a63bccd 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -228,9 +228,9 @@ struct confbridge_conference { struct ast_channel *record_chan; /*!< Channel used for recording the conference */ struct ast_str *record_filename; /*!< Recording filename. */ struct ast_str *orig_rec_file; /*!< Previous b_profile.rec_file. */ - ast_mutex_t playback_lock; /*!< Lock used for playback channel */ AST_LIST_HEAD_NOLOCK(, confbridge_user) active_list; /*!< List of users participating in the conference bridge */ AST_LIST_HEAD_NOLOCK(, confbridge_user) waiting_list; /*!< List of users waiting to join the conference bridge */ + struct ast_taskprocessor *playback_queue; /*!< Queue for playing back bridge announcements and managing the announcer channel */ }; extern struct ao2_container *conference_bridges; @@ -609,16 +609,6 @@ struct ast_channel_tech *conf_record_get_tech(void); */ struct ast_channel_tech *conf_announce_get_tech(void); -/*! - * \brief Remove the announcer channel from the conference. - * \since 12.0.0 - * - * \param chan Either channel in the announcer channel pair. - * - * \return Nothing - */ -void conf_announce_channel_depart(struct ast_channel *chan); - /*! * \brief Push the announcer channel into the conference. * \since 12.0.0 From 966527249ed144e4817ad168e334ea236b4c5d3a Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 18 Aug 2016 12:04:56 -0500 Subject: [PATCH 0679/1578] sip_to_pjsip: Set correct tls transport method A recent update had a copy/paste error where the unused variable 'val' was being passed to the set_value function instead of the 'method' value itself. This patch passes in the right variable. ASTERISK-22374 Change-Id: I895b7b3779ce4442bc58b8ec40d59dd29bb43f06 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 4a6004ae125..2134e9a40b2 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -797,7 +797,7 @@ def create_tls(sip, pjsip, nmapped): 'sslv23' as default when unspecified, which gives TLSv1.0 and v1.2. """ method = 'sslv23' - set_value('method', val, 'transport-tls', pjsip, nmapped, 'transport') + set_value('method', method, 'transport-tls', pjsip, nmapped, 'transport') set_transport_common('transport-tls', pjsip, nmapped) try: From c7ffd6111d59fd8dd48b7c0e9ba67641c6a565f2 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 18 Aug 2016 14:15:46 -0600 Subject: [PATCH 0680/1578] res_odbc: Correct the dependency relationship with res_odbc_transaction The MODULEINFO dependencies between these 2 modules was reversed. res_odbc should depend on res_odbc_transaction, not the other way around. ASTERISK-25984 #close Change-Id: Ifcfbb49c0b51cf6640a5446d47cd6c48caf1331f --- res/res_odbc.c | 1 + res/res_odbc_transaction.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_odbc.c b/res/res_odbc.c index 62faf98b26c..f89b59e51c7 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -41,6 +41,7 @@ /*** MODULEINFO generic_odbc + res_odbc_transaction ltdl core ***/ diff --git a/res/res_odbc_transaction.c b/res/res_odbc_transaction.c index de78600f356..569fcb267fb 100644 --- a/res/res_odbc_transaction.c +++ b/res/res_odbc_transaction.c @@ -26,7 +26,6 @@ #include "asterisk/module.h" /*** MODULEINFO - res_odbc core ***/ From 7ea133f2ab656296dee0091f9006ae016783b773 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 18 Aug 2016 17:02:24 -0500 Subject: [PATCH 0681/1578] rest-api: Swagger scripts were not replacing format variable in file brief Given resource paths did not have 'json' substituted in for the '{format}'. For some auto generated documentation/comment strings it resulted in something like the following: "... REST handler for /api-docs/sounds.{format}" This patch makes sure the resource api's path is properly substituted. ASTERISK-25472 #close Change-Id: Ie3e950a35db4043e284019d6c9061f3b03922e23 --- res/res_ari_applications.c | 6 ++--- res/res_ari_asterisk.c | 26 ++++++++++---------- res/res_ari_bridges.c | 16 ++++++------ res/res_ari_channels.c | 38 ++++++++++++++--------------- res/res_ari_device_states.c | 4 +-- res/res_ari_endpoints.c | 10 ++++---- res/res_ari_events.c | 6 ++--- res/res_ari_mailboxes.c | 4 +-- res/res_ari_playbacks.c | 6 ++--- res/res_ari_recordings.c | 20 +++++++-------- res/res_ari_sounds.c | 4 +-- rest-api-templates/swagger_model.py | 4 +-- 12 files changed, 72 insertions(+), 72 deletions(-) diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c index f25fd070f8d..7ce9722fd2b 100644 --- a/res/res_ari_applications.c +++ b/res/res_ari_applications.c @@ -496,7 +496,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/applications.{format} */ +/*! \brief REST handler for /api-docs/applications.json */ static struct stasis_rest_handlers applications_applicationName_subscription = { .path_segment = "subscription", .callbacks = { @@ -506,7 +506,7 @@ static struct stasis_rest_handlers applications_applicationName_subscription = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/applications.{format} */ +/*! \brief REST handler for /api-docs/applications.json */ static struct stasis_rest_handlers applications_applicationName = { .path_segment = "applicationName", .is_wildcard = 1, @@ -516,7 +516,7 @@ static struct stasis_rest_handlers applications_applicationName = { .num_children = 1, .children = { &applications_applicationName_subscription, } }; -/*! \brief REST handler for /api-docs/applications.{format} */ +/*! \brief REST handler for /api-docs/applications.json */ static struct stasis_rest_handlers applications = { .path_segment = "applications", .callbacks = { diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index a9f82eb4af7..71f72eea1c4 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -1178,7 +1178,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType_id = { .path_segment = "id", .is_wildcard = 1, @@ -1190,7 +1190,7 @@ static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectTyp .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectType = { .path_segment = "objectType", .is_wildcard = 1, @@ -1199,7 +1199,7 @@ static struct stasis_rest_handlers asterisk_config_dynamic_configClass_objectTyp .num_children = 1, .children = { &asterisk_config_dynamic_configClass_objectType_id, } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_config_dynamic_configClass = { .path_segment = "configClass", .is_wildcard = 1, @@ -1208,7 +1208,7 @@ static struct stasis_rest_handlers asterisk_config_dynamic_configClass = { .num_children = 1, .children = { &asterisk_config_dynamic_configClass_objectType, } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_config_dynamic = { .path_segment = "dynamic", .callbacks = { @@ -1216,7 +1216,7 @@ static struct stasis_rest_handlers asterisk_config_dynamic = { .num_children = 1, .children = { &asterisk_config_dynamic_configClass, } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_config = { .path_segment = "config", .callbacks = { @@ -1224,7 +1224,7 @@ static struct stasis_rest_handlers asterisk_config = { .num_children = 1, .children = { &asterisk_config_dynamic, } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_info = { .path_segment = "info", .callbacks = { @@ -1233,7 +1233,7 @@ static struct stasis_rest_handlers asterisk_info = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_modules_moduleName = { .path_segment = "moduleName", .is_wildcard = 1, @@ -1246,7 +1246,7 @@ static struct stasis_rest_handlers asterisk_modules_moduleName = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_modules = { .path_segment = "modules", .callbacks = { @@ -1255,7 +1255,7 @@ static struct stasis_rest_handlers asterisk_modules = { .num_children = 1, .children = { &asterisk_modules_moduleName, } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_logging_logChannelName_rotate = { .path_segment = "rotate", .callbacks = { @@ -1264,7 +1264,7 @@ static struct stasis_rest_handlers asterisk_logging_logChannelName_rotate = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_logging_logChannelName = { .path_segment = "logChannelName", .is_wildcard = 1, @@ -1275,7 +1275,7 @@ static struct stasis_rest_handlers asterisk_logging_logChannelName = { .num_children = 1, .children = { &asterisk_logging_logChannelName_rotate, } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_logging = { .path_segment = "logging", .callbacks = { @@ -1284,7 +1284,7 @@ static struct stasis_rest_handlers asterisk_logging = { .num_children = 1, .children = { &asterisk_logging_logChannelName, } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk_variable = { .path_segment = "variable", .callbacks = { @@ -1294,7 +1294,7 @@ static struct stasis_rest_handlers asterisk_variable = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/asterisk.{format} */ +/*! \brief REST handler for /api-docs/asterisk.json */ static struct stasis_rest_handlers asterisk = { .path_segment = "asterisk", .callbacks = { diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 119687999fd..a60b7010a30 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -1452,7 +1452,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId_addChannel = { .path_segment = "addChannel", .callbacks = { @@ -1461,7 +1461,7 @@ static struct stasis_rest_handlers bridges_bridgeId_addChannel = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId_removeChannel = { .path_segment = "removeChannel", .callbacks = { @@ -1470,7 +1470,7 @@ static struct stasis_rest_handlers bridges_bridgeId_removeChannel = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId_moh = { .path_segment = "moh", .callbacks = { @@ -1480,7 +1480,7 @@ static struct stasis_rest_handlers bridges_bridgeId_moh = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId_play_playbackId = { .path_segment = "playbackId", .is_wildcard = 1, @@ -1490,7 +1490,7 @@ static struct stasis_rest_handlers bridges_bridgeId_play_playbackId = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId_play = { .path_segment = "play", .callbacks = { @@ -1499,7 +1499,7 @@ static struct stasis_rest_handlers bridges_bridgeId_play = { .num_children = 1, .children = { &bridges_bridgeId_play_playbackId, } }; -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId_record = { .path_segment = "record", .callbacks = { @@ -1508,7 +1508,7 @@ static struct stasis_rest_handlers bridges_bridgeId_record = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId = { .path_segment = "bridgeId", .is_wildcard = 1, @@ -1520,7 +1520,7 @@ static struct stasis_rest_handlers bridges_bridgeId = { .num_children = 5, .children = { &bridges_bridgeId_addChannel,&bridges_bridgeId_removeChannel,&bridges_bridgeId_moh,&bridges_bridgeId_play,&bridges_bridgeId_record, } }; -/*! \brief REST handler for /api-docs/bridges.{format} */ +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges = { .path_segment = "bridges", .callbacks = { diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 0952d49010c..25da17d4d96 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -2954,7 +2954,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_create = { .path_segment = "create", .callbacks = { @@ -2963,7 +2963,7 @@ static struct stasis_rest_handlers channels_create = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_continue = { .path_segment = "continue", .callbacks = { @@ -2972,7 +2972,7 @@ static struct stasis_rest_handlers channels_channelId_continue = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_redirect = { .path_segment = "redirect", .callbacks = { @@ -2981,7 +2981,7 @@ static struct stasis_rest_handlers channels_channelId_redirect = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_answer = { .path_segment = "answer", .callbacks = { @@ -2990,7 +2990,7 @@ static struct stasis_rest_handlers channels_channelId_answer = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_ring = { .path_segment = "ring", .callbacks = { @@ -3000,7 +3000,7 @@ static struct stasis_rest_handlers channels_channelId_ring = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_dtmf = { .path_segment = "dtmf", .callbacks = { @@ -3009,7 +3009,7 @@ static struct stasis_rest_handlers channels_channelId_dtmf = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_mute = { .path_segment = "mute", .callbacks = { @@ -3019,7 +3019,7 @@ static struct stasis_rest_handlers channels_channelId_mute = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_hold = { .path_segment = "hold", .callbacks = { @@ -3029,7 +3029,7 @@ static struct stasis_rest_handlers channels_channelId_hold = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_moh = { .path_segment = "moh", .callbacks = { @@ -3039,7 +3039,7 @@ static struct stasis_rest_handlers channels_channelId_moh = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_silence = { .path_segment = "silence", .callbacks = { @@ -3049,7 +3049,7 @@ static struct stasis_rest_handlers channels_channelId_silence = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_play_playbackId = { .path_segment = "playbackId", .is_wildcard = 1, @@ -3059,7 +3059,7 @@ static struct stasis_rest_handlers channels_channelId_play_playbackId = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_play = { .path_segment = "play", .callbacks = { @@ -3068,7 +3068,7 @@ static struct stasis_rest_handlers channels_channelId_play = { .num_children = 1, .children = { &channels_channelId_play_playbackId, } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_record = { .path_segment = "record", .callbacks = { @@ -3077,7 +3077,7 @@ static struct stasis_rest_handlers channels_channelId_record = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_variable = { .path_segment = "variable", .callbacks = { @@ -3087,7 +3087,7 @@ static struct stasis_rest_handlers channels_channelId_variable = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_snoop_snoopId = { .path_segment = "snoopId", .is_wildcard = 1, @@ -3097,7 +3097,7 @@ static struct stasis_rest_handlers channels_channelId_snoop_snoopId = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_snoop = { .path_segment = "snoop", .callbacks = { @@ -3106,7 +3106,7 @@ static struct stasis_rest_handlers channels_channelId_snoop = { .num_children = 1, .children = { &channels_channelId_snoop_snoopId, } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId_dial = { .path_segment = "dial", .callbacks = { @@ -3115,7 +3115,7 @@ static struct stasis_rest_handlers channels_channelId_dial = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels_channelId = { .path_segment = "channelId", .is_wildcard = 1, @@ -3127,7 +3127,7 @@ static struct stasis_rest_handlers channels_channelId = { .num_children = 14, .children = { &channels_channelId_continue,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop,&channels_channelId_dial, } }; -/*! \brief REST handler for /api-docs/channels.{format} */ +/*! \brief REST handler for /api-docs/channels.json */ static struct stasis_rest_handlers channels = { .path_segment = "channels", .callbacks = { diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c index f6d5781944f..c3876af8bbe 100644 --- a/res/res_ari_device_states.c +++ b/res/res_ari_device_states.c @@ -320,7 +320,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/deviceStates.{format} */ +/*! \brief REST handler for /api-docs/deviceStates.json */ static struct stasis_rest_handlers deviceStates_deviceName = { .path_segment = "deviceName", .is_wildcard = 1, @@ -332,7 +332,7 @@ static struct stasis_rest_handlers deviceStates_deviceName = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/deviceStates.{format} */ +/*! \brief REST handler for /api-docs/deviceStates.json */ static struct stasis_rest_handlers deviceStates = { .path_segment = "deviceStates", .callbacks = { diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index af50a09498f..fd385313c08 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -434,7 +434,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/endpoints.{format} */ +/*! \brief REST handler for /api-docs/endpoints.json */ static struct stasis_rest_handlers endpoints_sendMessage = { .path_segment = "sendMessage", .callbacks = { @@ -443,7 +443,7 @@ static struct stasis_rest_handlers endpoints_sendMessage = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/endpoints.{format} */ +/*! \brief REST handler for /api-docs/endpoints.json */ static struct stasis_rest_handlers endpoints_tech_resource_sendMessage = { .path_segment = "sendMessage", .callbacks = { @@ -452,7 +452,7 @@ static struct stasis_rest_handlers endpoints_tech_resource_sendMessage = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/endpoints.{format} */ +/*! \brief REST handler for /api-docs/endpoints.json */ static struct stasis_rest_handlers endpoints_tech_resource = { .path_segment = "resource", .is_wildcard = 1, @@ -462,7 +462,7 @@ static struct stasis_rest_handlers endpoints_tech_resource = { .num_children = 1, .children = { &endpoints_tech_resource_sendMessage, } }; -/*! \brief REST handler for /api-docs/endpoints.{format} */ +/*! \brief REST handler for /api-docs/endpoints.json */ static struct stasis_rest_handlers endpoints_tech = { .path_segment = "tech", .is_wildcard = 1, @@ -472,7 +472,7 @@ static struct stasis_rest_handlers endpoints_tech = { .num_children = 1, .children = { &endpoints_tech_resource, } }; -/*! \brief REST handler for /api-docs/endpoints.{format} */ +/*! \brief REST handler for /api-docs/endpoints.json */ static struct stasis_rest_handlers endpoints = { .path_segment = "endpoints", .callbacks = { diff --git a/res/res_ari_events.c b/res/res_ari_events.c index e4fda0a54b3..40a18b8fb86 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -408,7 +408,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/events.{format} */ +/*! \brief REST handler for /api-docs/events.json */ static struct stasis_rest_handlers events_user_eventName = { .path_segment = "eventName", .is_wildcard = 1, @@ -418,7 +418,7 @@ static struct stasis_rest_handlers events_user_eventName = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/events.{format} */ +/*! \brief REST handler for /api-docs/events.json */ static struct stasis_rest_handlers events_user = { .path_segment = "user", .callbacks = { @@ -426,7 +426,7 @@ static struct stasis_rest_handlers events_user = { .num_children = 1, .children = { &events_user_eventName, } }; -/*! \brief REST handler for /api-docs/events.{format} */ +/*! \brief REST handler for /api-docs/events.json */ static struct stasis_rest_handlers events = { .path_segment = "events", .callbacks = { diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c index 4f3c731208f..5b053230908 100644 --- a/res/res_ari_mailboxes.c +++ b/res/res_ari_mailboxes.c @@ -326,7 +326,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/mailboxes.{format} */ +/*! \brief REST handler for /api-docs/mailboxes.json */ static struct stasis_rest_handlers mailboxes_mailboxName = { .path_segment = "mailboxName", .is_wildcard = 1, @@ -338,7 +338,7 @@ static struct stasis_rest_handlers mailboxes_mailboxName = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/mailboxes.{format} */ +/*! \brief REST handler for /api-docs/mailboxes.json */ static struct stasis_rest_handlers mailboxes = { .path_segment = "mailboxes", .callbacks = { diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c index d01802145ad..b4dfd1c1cf9 100644 --- a/res/res_ari_playbacks.c +++ b/res/res_ari_playbacks.c @@ -270,7 +270,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/playbacks.{format} */ +/*! \brief REST handler for /api-docs/playbacks.json */ static struct stasis_rest_handlers playbacks_playbackId_control = { .path_segment = "control", .callbacks = { @@ -279,7 +279,7 @@ static struct stasis_rest_handlers playbacks_playbackId_control = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/playbacks.{format} */ +/*! \brief REST handler for /api-docs/playbacks.json */ static struct stasis_rest_handlers playbacks_playbackId = { .path_segment = "playbackId", .is_wildcard = 1, @@ -290,7 +290,7 @@ static struct stasis_rest_handlers playbacks_playbackId = { .num_children = 1, .children = { &playbacks_playbackId_control, } }; -/*! \brief REST handler for /api-docs/playbacks.{format} */ +/*! \brief REST handler for /api-docs/playbacks.json */ static struct stasis_rest_handlers playbacks = { .path_segment = "playbacks", .callbacks = { diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index a21943520c9..aee3d3d2ad6 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -797,7 +797,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_stored_recordingName_file = { .path_segment = "file", .callbacks = { @@ -806,7 +806,7 @@ static struct stasis_rest_handlers recordings_stored_recordingName_file = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_stored_recordingName_copy = { .path_segment = "copy", .callbacks = { @@ -815,7 +815,7 @@ static struct stasis_rest_handlers recordings_stored_recordingName_copy = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_stored_recordingName = { .path_segment = "recordingName", .is_wildcard = 1, @@ -826,7 +826,7 @@ static struct stasis_rest_handlers recordings_stored_recordingName = { .num_children = 2, .children = { &recordings_stored_recordingName_file,&recordings_stored_recordingName_copy, } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_stored = { .path_segment = "stored", .callbacks = { @@ -835,7 +835,7 @@ static struct stasis_rest_handlers recordings_stored = { .num_children = 1, .children = { &recordings_stored_recordingName, } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_live_recordingName_stop = { .path_segment = "stop", .callbacks = { @@ -844,7 +844,7 @@ static struct stasis_rest_handlers recordings_live_recordingName_stop = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_live_recordingName_pause = { .path_segment = "pause", .callbacks = { @@ -854,7 +854,7 @@ static struct stasis_rest_handlers recordings_live_recordingName_pause = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_live_recordingName_mute = { .path_segment = "mute", .callbacks = { @@ -864,7 +864,7 @@ static struct stasis_rest_handlers recordings_live_recordingName_mute = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_live_recordingName = { .path_segment = "recordingName", .is_wildcard = 1, @@ -875,7 +875,7 @@ static struct stasis_rest_handlers recordings_live_recordingName = { .num_children = 3, .children = { &recordings_live_recordingName_stop,&recordings_live_recordingName_pause,&recordings_live_recordingName_mute, } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings_live = { .path_segment = "live", .callbacks = { @@ -883,7 +883,7 @@ static struct stasis_rest_handlers recordings_live = { .num_children = 1, .children = { &recordings_live_recordingName, } }; -/*! \brief REST handler for /api-docs/recordings.{format} */ +/*! \brief REST handler for /api-docs/recordings.json */ static struct stasis_rest_handlers recordings = { .path_segment = "recordings", .callbacks = { diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index 8bb217153a5..f5a1d41abca 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -208,7 +208,7 @@ fin: __attribute__((unused)) return; } -/*! \brief REST handler for /api-docs/sounds.{format} */ +/*! \brief REST handler for /api-docs/sounds.json */ static struct stasis_rest_handlers sounds_soundId = { .path_segment = "soundId", .is_wildcard = 1, @@ -218,7 +218,7 @@ static struct stasis_rest_handlers sounds_soundId = { .num_children = 0, .children = { } }; -/*! \brief REST handler for /api-docs/sounds.{format} */ +/*! \brief REST handler for /api-docs/sounds.json */ static struct stasis_rest_handlers sounds = { .path_segment = "sounds", .callbacks = { diff --git a/rest-api-templates/swagger_model.py b/rest-api-templates/swagger_model.py index c76cb7f28c6..c71352a0125 100644 --- a/rest-api-templates/swagger_model.py +++ b/rest-api-templates/swagger_model.py @@ -691,7 +691,7 @@ def __init__(self): def load(self, api_json, processor, context): context = context.next_stack(api_json, 'path') validate_required_fields(api_json, self.required_fields, context) - self.path = api_json['path'] + self.path = api_json['path'].replace('{format}', 'json') self.description = api_json['description'] if not self.path or self.path[0] != '/': @@ -700,7 +700,7 @@ def load(self, api_json, processor, context): return self def load_api_declaration(self, base_dir, processor): - self.file = (base_dir + self.path).replace('{format}', 'json') + self.file = (base_dir + self.path) self.api_declaration = ApiDeclaration().load_file(self.file, processor) processor.process_resource_api(self, [self.file]) From 53a2f7dc88037152de88d016051ea1166323ed02 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 16 Aug 2016 15:57:24 -0500 Subject: [PATCH 0682/1578] res_format_attr_g729: Add annexb=no format parameter to SDPs Historically, Asterisk has always specified annexb=no for the g729 format. However, when using res_pjsip no format attribute was specified. This patch makes it so the SDP now contains a format attribute line with annexb=no. Note, that this means only g729a is negotiated. Even for pass through support. According to rfc7261 the type of annex used (a or b) is dependent upon the answerer. However, Asterisk being a back to back user agent makes this tricky to support at this time, thus we only allow annex 'a' for now. ASTERISK-26228 #close patches: res_format_attr_g729.c submitted by Jason Parker (license 4993) Change-Id: I76bc20cc0a01af01536e9915afef319c269c22d0 --- channels/chan_sip.c | 5 +-- res/res_format_attr_g729.c | 76 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 res/res_format_attr_g729.c diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f57d4670b32..6250731bd1d 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -12982,10 +12982,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p, framing = ast_format_cap_get_format_framing(p->caps, format); - if (ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { - /* Indicate that we don't support VAD (G.729 annex B) */ - ast_str_append(a_buf, 0, "a=fmtp:%d annexb=no\r\n", rtp_code); - } else if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { + if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we don't support VAD (G.723.1 annex A) */ ast_str_append(a_buf, 0, "a=fmtp:%d annexa=no\r\n", rtp_code); } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { diff --git a/res/res_format_attr_g729.c b/res/res_format_attr_g729.c new file mode 100644 index 00000000000..5ba4920d96d --- /dev/null +++ b/res/res_format_attr_g729.c @@ -0,0 +1,76 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Jason Parker + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/module.h" +#include "asterisk/format.h" + +/* Destroy is a required callback and must exist */ +static void g729_destroy(struct ast_format *format) +{ +} + +/* Clone is a required callback and must exist */ +static int g729_clone(const struct ast_format *src, struct ast_format *dst) +{ + return 0; +} + +static void g729_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) +{ + /* + * According to the rfc the joint annexb format parameter should be set to 'yes' + * or 'no' based on the answerer (rfc7261 - 3.3). However, Asterisk being a B2BUA + * makes things tricky. So for now Asterisk will set annexb=no. + */ + ast_str_append(str, 0, "a=fmtp:%u annexb=no\r\n", payload); +} + +static struct ast_format_interface g729_interface = { + .format_destroy = g729_destroy, + .format_clone = g729_clone, + .format_generate_sdp_fmtp = g729_generate_sdp_fmtp, +}; + +static int load_module(void) +{ + if (ast_format_interface_register("g729", &g729_interface)) { + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "G.729 Format Attribute Module", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND, +); From 1a9555f0363e9cdf94144084e6ba6fc64d6fe2f9 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 18 Aug 2016 16:21:25 +0200 Subject: [PATCH 0683/1578] sip.conf: tlsclientmethod is using sslv23 as default. When 'tlsclientmethod' is not specified in sip.conf, chan_sip uses the OpenSSL SSLv23_method. This was documented incorrectly in the file sip.conf.sample. SSLv23_method got its name in the 90s. Today, with OpenSSL 1.0.2, this method enables (just) the secure TLSv1.0 and TLSv1.2. Or stated differently, that function should have been called 'secure_method' or 'automatic_method' back in the 90s. Consequently please, specify 'tlsclientmethod=tlsv1' in your sip.conf only if you face a server which has problems like not falling back to TLSv1.0 automatically. ASTERISK-24425 Change-Id: I502ce6146b4504cadfd3973af8d6ec3994f54fa3 --- configs/samples/sip.conf.sample | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample index a7b74df690d..da176b4d66a 100644 --- a/configs/samples/sip.conf.sample +++ b/configs/samples/sip.conf.sample @@ -611,7 +611,16 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; ;tlsclientmethod=tlsv1 ; values include tlsv1, sslv3, sslv2. ; Specify protocol for outbound client connections. - ; If left unspecified, the default is sslv2. + ; If left unspecified, the default is the general- + ; purpose version-flexible SSL/TLS method (sslv23). + ; With that, the actual protocol version used will + ; be negotiated to the highest version mutually + ; supported by Asterisk and the remote server, i.e. + ; TLSv1.2. The supported protocols are listed at + ; http://www.openssl.org/docs/ssl/SSL_CTX_new.html + ; SSLv2 and SSLv3 are disabled within Asterisk. + ; Your distribution might have changed that list + ; further. ; ;--------------------------- SIP timers ---------------------------------------------------- ; These timers are used primarily in INVITE transactions. From 02a82f758eb1c11fff05d4811fe6e71becc1bcd2 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Fri, 19 Aug 2016 10:59:40 +0200 Subject: [PATCH 0684/1578] sip_to_pjsip: Add cert_file. When using the migration script sip_to_pjsip.py, cert_file was not migrated to pjsip.conf. A previous change regarding this contained a copy/paste error. ASTERISK-22374 Change-Id: I0fa72e9412117d53b4284fc6b83fa5b2b95ba03b --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index e598caad7c6..ac5aa6cc10b 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -691,9 +691,9 @@ def set_tls_bindaddr(val, pjsip, nmapped): set_value('bind', bind, 'transport-tls', pjsip, nmapped, 'transport') -def set_tls_cert_file(val, pjsip, section, nmapped): +def set_tls_cert_file(val, pjsip, nmapped): """Sets cert_file based on sip.conf tlscertfile""" - set_value('cert_file', val, section, pjsip, nmapped, + set_value('cert_file', val, 'transport-tls', pjsip, nmapped, 'transport') From c1b6a796865d11006634f39c765eb12a4bfb556d Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Wed, 17 Aug 2016 15:10:54 +0200 Subject: [PATCH 0685/1578] res_ari: Add http prefix to generated docs updated the uri handler to include the url prefix of the http server this enables res_ari to add it to the uris when generating docs Change-Id: I279335a2625261a8492206c37219698f42591c2e (cherry picked from commit 6f448f32fe9b7379e2630fab7b06205f901f2ded) --- include/asterisk/ari.h | 3 ++- include/asterisk/http.h | 1 + main/http.c | 2 ++ res/res_ari.c | 16 +++++++++++----- tests/test_ari.c | 8 ++++---- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h index 79b9516eb39..4019e94e3b7 100644 --- a/include/asterisk/ari.h +++ b/include/asterisk/ari.h @@ -146,10 +146,11 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser, * for unit testing. * * \param uri Requested URI, relative to the docs path. + * \param prefix prefix that prefixes all http requests * \param headers HTTP headers. * \param[out] response RESTful HTTP response. */ -void ast_ari_get_docs(const char *uri, struct ast_variable *headers, struct ast_ari_response *response); +void ast_ari_get_docs(const char *uri, const char *prefix, struct ast_variable *headers, struct ast_ari_response *response); /*! \brief Abstraction for reading/writing JSON to a WebSocket */ struct ast_ari_websocket_session; diff --git a/include/asterisk/http.h b/include/asterisk/http.h index bb8973dce4f..d5f54cc6573 100644 --- a/include/asterisk/http.h +++ b/include/asterisk/http.h @@ -101,6 +101,7 @@ struct ast_http_uri { AST_LIST_ENTRY(ast_http_uri) entry; const char *description; const char *uri; + const char *prefix; ast_http_callback callback; unsigned int has_subtree:1; /*! Structure is malloc'd */ diff --git a/main/http.c b/main/http.c index bc23e6e5637..da564da203a 100644 --- a/main/http.c +++ b/main/http.c @@ -671,6 +671,8 @@ int ast_http_uri_link(struct ast_http_uri *urih) AST_RWLIST_WRLOCK(&uris); + urih->prefix = prefix; + if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) { AST_RWLIST_INSERT_HEAD(&uris, urih, entry); AST_RWLIST_UNLOCK(&uris); diff --git a/res/res_ari.c b/res/res_ari.c index 0cc1ee7b0d5..eb15a88b85d 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -579,7 +579,7 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser, } } -void ast_ari_get_docs(const char *uri, struct ast_variable *headers, +void ast_ari_get_docs(const char *uri, const char *prefix, struct ast_variable *headers, struct ast_ari_response *response) { RAII_VAR(struct ast_str *, absolute_path_builder, NULL, ast_free); @@ -685,9 +685,15 @@ void ast_ari_get_docs(const char *uri, struct ast_variable *headers, } } if (host != NULL) { - ast_json_object_set( - obj, "basePath", - ast_json_stringf("http://%s/ari", host->value)); + if (prefix != NULL && strlen(prefix) > 0) { + ast_json_object_set( + obj, "basePath", + ast_json_stringf("http://%s%s/ari", host->value,prefix)); + } else { + ast_json_object_set( + obj, "basePath", + ast_json_stringf("http://%s/ari", host->value)); + } } else { /* Without the host, we don't have the basePath */ ast_json_object_del(obj, "basePath"); @@ -969,7 +975,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, ast_ari_response_error(&response, 405, "Method Not Allowed", "Unsupported method"); } else { /* Skip the api-docs prefix */ - ast_ari_get_docs(strchr(uri, '/') + 1, headers, &response); + ast_ari_get_docs(strchr(uri, '/') + 1, urih->prefix, headers, &response); } } else { /* Other RESTful resources */ diff --git a/tests/test_ari.c b/tests/test_ari.c index efec810e172..da889ec45d5 100644 --- a/tests/test_ari.c +++ b/tests/test_ari.c @@ -218,7 +218,7 @@ AST_TEST_DEFINE(get_docs) response = response_alloc(); headers = ast_variable_new("Host", "stasis.asterisk.org", __FILE__); - ast_ari_get_docs("resources.json", headers, response); + ast_ari_get_docs("resources.json", "", headers, response); ast_test_validate(test, 200 == response->response_code); /* basePath should be relative to the Host header */ @@ -248,7 +248,7 @@ AST_TEST_DEFINE(get_docs_nohost) } response = response_alloc(); - ast_ari_get_docs("resources.json", headers, response); + ast_ari_get_docs("resources.json", "", headers, response); ast_test_validate(test, 200 == response->response_code); /* basePath should be relative to the Host header */ @@ -275,7 +275,7 @@ AST_TEST_DEFINE(get_docs_notfound) } response = response_alloc(); - ast_ari_get_docs("i-am-not-a-resource.json", headers, response); + ast_ari_get_docs("i-am-not-a-resource.json", "", headers, response); ast_test_validate(test, 404 == response->response_code); return AST_TEST_PASS; @@ -298,7 +298,7 @@ AST_TEST_DEFINE(get_docs_hackerz) } response = response_alloc(); - ast_ari_get_docs("../../../../sbin/asterisk", headers, response); + ast_ari_get_docs("../../../../sbin/asterisk", "", headers, response); ast_test_validate(test, 404 == response->response_code); return AST_TEST_PASS; From 8061d9f66f636ada714f719be9809ea58cd5c871 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 19 Aug 2016 15:09:45 -0400 Subject: [PATCH 0686/1578] Fix naming mismatch of allocator functions. Allocator functions that take file/line/func parameters are prefixed with single-underscore when MALLOC_DEBUG is not defined, double-underscore when it is defined. This change updates all allocators that accept file/line/func to have the same prototype in either ABI mode. The parameter order of __ast_vasprintf and __ast_asprintf in utils.h have been changed to match that of astmm.h. End-use allocator macro's have been removed from astmm.h and moved to an unconditional part of utils.h. Change-Id: I823bb6ce2b5675b3a4735948f10a3b420e9a023a --- include/asterisk/astmm.h | 26 +---- include/asterisk/utils.h | 200 +++++++++++++++++++-------------------- main/astobj2.c | 12 --- main/ccss.c | 4 - main/datastore.c | 6 -- main/stringfields.c | 4 - main/utils.c | 2 +- utils/check_expr.c | 4 +- utils/extconf.c | 68 ++++--------- 9 files changed, 121 insertions(+), 205 deletions(-) diff --git a/include/asterisk/astmm.h b/include/asterisk/astmm.h index 83c34bed345..e129dc034a9 100644 --- a/include/asterisk/astmm.h +++ b/include/asterisk/astmm.h @@ -174,35 +174,11 @@ void __ast_mm_init_phase_2(void); #endif -/* Provide our own definitions */ - -#define ast_calloc(a,b) \ - __ast_calloc(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_calloc_cache(a,b) \ - __ast_calloc_cache(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_malloc(a) \ - __ast_malloc(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) +/* Provide our own definition for ast_free */ #define ast_free(a) \ __ast_free(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) -#define ast_realloc(a,b) \ - __ast_realloc(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_strdup(a) \ - __ast_strdup(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_strndup(a,b) \ - __ast_strndup(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_asprintf(a, b, c...) \ - __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, b, c) - -#define ast_vasprintf(a,b,c) \ - __ast_vasprintf(a,b,c,__FILE__, __LINE__, __PRETTY_FUNCTION__) - #endif /* !STANDALONE */ #else diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index c3df4779ff1..9789d34ee09 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -533,19 +533,8 @@ long int ast_random(void); ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file) #endif -/*! - * \brief A wrapper for malloc() - * - * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log - * message in the case that the allocation fails. - * - * The argument and return value are the same as malloc() - */ -#define ast_malloc(len) \ - _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - AST_INLINE_API( -void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func), +void * attribute_malloc __ast_malloc(size_t len, const char *file, int lineno, const char *func), { void *p; @@ -559,19 +548,8 @@ void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, co } ) -/*! - * \brief A wrapper for calloc() - * - * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log - * message in the case that the allocation fails. - * - * The arguments and return value are the same as calloc() - */ -#define ast_calloc(num, len) \ - _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - AST_INLINE_API( -void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func), +void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func), { void *p; @@ -585,6 +563,98 @@ void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, in } ) +AST_INLINE_API( +void * attribute_malloc __ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func), +{ + void *newp; + + DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); + + if (!(newp = realloc(p, len))) { + MALLOC_FAILURE_MSG; + } + + return newp; +} +) + +AST_INLINE_API( +char * attribute_malloc __ast_strdup(const char *str, const char *file, int lineno, const char *func), +{ + char *newstr = NULL; + + DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); + + if (str) { + if (!(newstr = strdup(str))) { + MALLOC_FAILURE_MSG; + } + } + + return newstr; +} +) + +AST_INLINE_API( +char * attribute_malloc __ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func), +{ + char *newstr = NULL; + + DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); + + if (str) { + if (!(newstr = strndup(str, len))) { + MALLOC_FAILURE_MSG; + } + } + + return newstr; +} +) + +int __attribute__((format(printf, 5, 6))) + __ast_asprintf(const char *file, int lineno, const char *func, char **ret, const char *fmt, ...); + +AST_INLINE_API( +__attribute__((format(printf, 2, 0))) +int __ast_vasprintf(char **ret, const char *fmt, va_list ap, const char *file, int lineno, const char *func), +{ + int res; + + DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1); + + if ((res = vasprintf(ret, fmt, ap)) == -1) { + MALLOC_FAILURE_MSG; + } + + return res; +} +) + +#endif /* AST_DEBUG_MALLOC */ + +/*! + * \brief A wrapper for malloc() + * + * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log + * message in the case that the allocation fails. + * + * The argument and return value are the same as malloc() + */ +#define ast_malloc(len) \ + __ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + +/*! + * \brief A wrapper for calloc() + * + * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log + * message in the case that the allocation fails. + * + * The arguments and return value are the same as calloc() + */ +#define ast_calloc(num, len) \ + __ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + /*! * \brief A wrapper for calloc() for use in cache pools * @@ -596,7 +666,7 @@ void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, in * The arguments and return value are the same as calloc() */ #define ast_calloc_cache(num, len) \ - _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! * \brief A wrapper for realloc() @@ -607,22 +677,7 @@ void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, in * The arguments and return value are the same as realloc() */ #define ast_realloc(p, len) \ - _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -AST_INLINE_API( -void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func), -{ - void *newp; - - DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); - - if (!(newp = realloc(p, len))) { - MALLOC_FAILURE_MSG; - } - - return newp; -} -) + __ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! * \brief A wrapper for strdup() @@ -637,24 +692,7 @@ void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int * The argument and return value are the same as strdup() */ #define ast_strdup(str) \ - _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -AST_INLINE_API( -char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func), -{ - char *newstr = NULL; - - DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); - - if (str) { - if (!(newstr = strdup(str))) { - MALLOC_FAILURE_MSG; - } - } - - return newstr; -} -) + __ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! * \brief A wrapper for strndup() @@ -669,24 +707,7 @@ char * attribute_malloc _ast_strdup(const char *str, const char *file, int linen * The arguments and return value are the same as strndup() */ #define ast_strndup(str, len) \ - _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -AST_INLINE_API( -char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func), -{ - char *newstr = NULL; - - DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, NULL); - - if (str) { - if (!(newstr = strndup(str, len))) { - MALLOC_FAILURE_MSG; - } - } - - return newstr; -} -) + __ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! * \brief A wrapper for asprintf() @@ -697,10 +718,7 @@ char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *fi * The arguments and return value are the same as asprintf() */ #define ast_asprintf(ret, fmt, ...) \ - _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__) - -int __attribute__((format(printf, 5, 6))) - _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...); + __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, (ret), (fmt), __VA_ARGS__) /*! * \brief A wrapper for vasprintf() @@ -711,25 +729,7 @@ int __attribute__((format(printf, 5, 6))) * The arguments and return value are the same as vasprintf() */ #define ast_vasprintf(ret, fmt, ap) \ - _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap)) - -AST_INLINE_API( -__attribute__((format(printf, 5, 0))) -int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap), -{ - int res; - - DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1); - - if ((res = vasprintf(ret, fmt, ap)) == -1) { - MALLOC_FAILURE_MSG; - } - - return res; -} -) - -#endif /* AST_DEBUG_MALLOC */ + __ast_vasprintf((ret), (fmt), (ap), __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! \brief call __builtin_alloca to ensure we get gcc builtin semantics diff --git a/main/astobj2.c b/main/astobj2.c index ed91577be40..5c92f263f1b 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -591,11 +591,7 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in switch (options & AO2_ALLOC_OPT_LOCK_MASK) { case AO2_ALLOC_OPT_LOCK_MUTEX: -#if defined(__AST_DEBUG_MALLOC) obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, func); -#else - obj_mutex = ast_calloc(1, sizeof(*obj_mutex) + data_size); -#endif if (obj_mutex == NULL) { return NULL; } @@ -604,11 +600,7 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in obj = (struct astobj2 *) &obj_mutex->priv_data; break; case AO2_ALLOC_OPT_LOCK_RWLOCK: -#if defined(__AST_DEBUG_MALLOC) obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, func); -#else - obj_rwlock = ast_calloc(1, sizeof(*obj_rwlock) + data_size); -#endif if (obj_rwlock == NULL) { return NULL; } @@ -617,11 +609,7 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in obj = (struct astobj2 *) &obj_rwlock->priv_data; break; case AO2_ALLOC_OPT_LOCK_NOLOCK: -#if defined(__AST_DEBUG_MALLOC) obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, func); -#else - obj = ast_calloc(1, sizeof(*obj) + data_size); -#endif if (obj == NULL) { return NULL; } diff --git a/main/ccss.c b/main/ccss.c index 307f71b96a1..13831b71987 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -682,11 +682,7 @@ void ast_cc_default_config_params(struct ast_cc_config_params *params) struct ast_cc_config_params *__ast_cc_config_params_init(const char *file, int line, const char *function) { -#if defined(__AST_DEBUG_MALLOC) struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function); -#else - struct ast_cc_config_params *params = ast_malloc(sizeof(*params)); -#endif if (!params) { return NULL; diff --git a/main/datastore.c b/main/datastore.c index c2bba41904b..e536d601bc9 100644 --- a/main/datastore.c +++ b/main/datastore.c @@ -47,15 +47,9 @@ struct ast_datastore *__ast_datastore_alloc(const struct ast_datastore_info *inf return NULL; } -#if defined(__AST_DEBUG_MALLOC) if (!(datastore = __ast_calloc(1, sizeof(*datastore), file, line, function))) { return NULL; } -#else - if (!(datastore = ast_calloc(1, sizeof(*datastore)))) { - return NULL; - } -#endif datastore->info = info; diff --git a/main/stringfields.c b/main/stringfields.c index e82b49b98a1..25c58446274 100644 --- a/main/stringfields.c +++ b/main/stringfields.c @@ -60,11 +60,7 @@ static size_t optimal_alloc_size(size_t size) static void *calloc_wrapper(unsigned int num_structs, size_t struct_size, const char *file, int lineno, const char *func) { -#if defined(__AST_DEBUG_MALLOC) return __ast_calloc(num_structs, struct_size, file, lineno, func); -#else - return ast_calloc(num_structs, struct_size); -#endif } /*! \brief add a new block to the pool. diff --git a/main/utils.c b/main/utils.c index 1d2aa0b2726..73b1c8703aa 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2369,7 +2369,7 @@ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, } #ifndef __AST_DEBUG_MALLOC -int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...) +int __ast_asprintf(const char *file, int lineno, const char *func, char **ret, const char *fmt, ...) { int res; va_list ap; diff --git a/utils/check_expr.c b/utils/check_expr.c index f29363c9198..36ff132026b 100644 --- a/utils/check_expr.c +++ b/utils/check_expr.c @@ -42,9 +42,9 @@ enum ast_lock_type { #define MALLOC_FAILURE_MSG \ ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file); -void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func); +void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func); -void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func) +void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func) { void *p; diff --git a/utils/extconf.c b/utils/extconf.c index 8588d1a28a9..d035e12c06c 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -684,41 +684,6 @@ int ast_channel_trylock(struct ast_channel *chan); #define ast_free free #define ast_free_ptr free -#define MALLOC_FAILURE_MSG \ - ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file); - -/*! - * \brief A wrapper for malloc() - * - * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log - * message in the case that the allocation fails. - * - * The argument and return value are the same as malloc() - */ -#define ast_malloc(len) \ - _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_calloc(num, len) \ - _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_calloc_cache(num, len) \ - _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_realloc(p, len) \ - _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_strdup(str) \ - _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_strndup(str, len) \ - _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) - -#define ast_asprintf(ret, fmt, ...) \ - _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__) - -#define ast_vasprintf(ret, fmt, ap) \ - _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap)) - struct ast_flags { /* stolen from utils.h */ unsigned int flags; }; @@ -743,6 +708,7 @@ struct ast_flags { /* stolen from utils.h */ #define MALLOC_FAILURE_MSG \ ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file); + /*! * \brief A wrapper for malloc() * @@ -752,10 +718,10 @@ struct ast_flags { /* stolen from utils.h */ * The argument and return value are the same as malloc() */ #define ast_malloc(len) \ - _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__) AST_INLINE_API( -void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func), +void * attribute_malloc __ast_malloc(size_t len, const char *file, int lineno, const char *func), { void *p; @@ -775,10 +741,10 @@ void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, co * The arguments and return value are the same as calloc() */ #define ast_calloc(num, len) \ - _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) AST_INLINE_API( -void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func), +void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func), { void *p; @@ -800,7 +766,7 @@ void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, in * The arguments and return value are the same as calloc() */ #define ast_calloc_cache(num, len) \ - _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! * \brief A wrapper for realloc() @@ -811,10 +777,10 @@ void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, in * The arguments and return value are the same as realloc() */ #define ast_realloc(p, len) \ - _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) AST_INLINE_API( -void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func), +void * attribute_malloc __ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func), { void *newp; @@ -838,10 +804,10 @@ void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int * The argument and return value are the same as strdup() */ #define ast_strdup(str) \ - _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__) AST_INLINE_API( -char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func), +char * attribute_malloc __ast_strdup(const char *str, const char *file, int lineno, const char *func), { char *newstr = NULL; @@ -867,10 +833,10 @@ char * attribute_malloc _ast_strdup(const char *str, const char *file, int linen * The arguments and return value are the same as strndup() */ #define ast_strndup(str, len) \ - _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) + __ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__) AST_INLINE_API( -char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func), +char * attribute_malloc __ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func), { char *newstr = NULL; @@ -892,11 +858,11 @@ char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *fi * The arguments and return value are the same as asprintf() */ #define ast_asprintf(ret, fmt, ...) \ - _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__) + __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, (ret), (fmt), __VA_ARGS__) AST_INLINE_API( __attribute__((format(printf, 5, 6))) -int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...), +int __ast_asprintf(const char *file, int lineno, const char *func, char **ret, const char *fmt, ...), { int res; va_list ap; @@ -919,11 +885,11 @@ int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, co * The arguments and return value are the same as vasprintf() */ #define ast_vasprintf(ret, fmt, ap) \ - _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap)) + __ast_vasprintf((ret), (fmt), (ap), __FILE__, __LINE__, __PRETTY_FUNCTION__) AST_INLINE_API( -__attribute__((format(printf, 5, 0))) -int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap), +__attribute__((format(printf, 2, 0))) +int __ast_vasprintf(char **ret, const char *fmt, va_list ap, const char *file, int lineno, const char *func), { int res; From 55ccdf93c326ecbfe6a989d45f818fbf7bbe1762 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 19 Aug 2016 19:19:28 -0400 Subject: [PATCH 0687/1578] Fix checks for allocation debugging. MALLOC_DEBUG should not be used to check if debugging is actually enabled, __AST_DEBUG_MALLOC should be used instead. MALLOC_DEBUG only indicates that debugging is requested, __AST_DEBUG_MALLOC indicates it is active. Change-Id: I3ce9cdb6ec91b74ee1302941328462231be1ea53 --- include/asterisk/chanvars.h | 2 +- include/asterisk/config.h | 2 +- include/asterisk/hashtab.h | 14 ++++++------- include/asterisk/heap.h | 4 ++-- include/asterisk/strings.h | 6 +++--- main/chanvars.c | 4 ++-- main/config.c | 4 ++-- main/hashtab.c | 40 ++++++++++++++++++------------------- main/heap.c | 14 ++++++------- main/strings.c | 4 ++-- 10 files changed, 47 insertions(+), 47 deletions(-) diff --git a/include/asterisk/chanvars.h b/include/asterisk/chanvars.h index 3693e2a3ab5..2040c7b65ff 100644 --- a/include/asterisk/chanvars.h +++ b/include/asterisk/chanvars.h @@ -35,7 +35,7 @@ AST_LIST_HEAD_NOLOCK(varshead, ast_var_t); struct varshead *ast_var_list_create(void); void ast_var_list_destroy(struct varshead *head); -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC struct ast_var_t *_ast_var_assign(const char *name, const char *value, const char *file, int lineno, const char *function); #define ast_var_assign(a,b) _ast_var_assign(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__) #else diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 287635a8e05..4944a3af202 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -907,7 +907,7 @@ void ast_category_destroy(struct ast_category *cat); struct ast_variable *ast_category_detach_variables(struct ast_category *cat); void ast_category_rename(struct ast_category *cat, const char *name); -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *function, int lineno); #define ast_variable_new(name, value, filename) _ast_variable_new(name, value, filename, __FILE__, __PRETTY_FUNCTION__, __LINE__) #else diff --git a/include/asterisk/hashtab.h b/include/asterisk/hashtab.h index 17eff704829..cfe035b28b7 100644 --- a/include/asterisk/hashtab.h +++ b/include/asterisk/hashtab.h @@ -251,7 +251,7 @@ unsigned int ast_hashtab_hash_short(const short num); * \param hash a func ptr to do the hashing * \param do_locking use locks to guarantee safety of iterators/insertion/deletion -- real simpleminded right now */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC struct ast_hashtab * _ast_hashtab_create(int initial_buckets, int (*compare)(const void *a, const void *b), int (*resize)(struct ast_hashtab *), @@ -294,7 +294,7 @@ void ast_hashtab_destroy( struct ast_hashtab *tab, void (*objdestroyfunc)(void * * \retval 1 on success * \retval 0 if there's a problem */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int _ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func); #define ast_hashtab_insert_immediate(a,b) _ast_hashtab_insert_immediate(a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__) #else @@ -311,7 +311,7 @@ int ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj); * \retval 1 on success * \retval 0 if there's a problem */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int _ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj, unsigned int h, const char *file, int lineno, const char *func); #define ast_hashtab_insert_immediate_bucket(a,b,c) _ast_hashtab_insert_immediate_bucket(a, b, c, __FILE__, __LINE__, __PRETTY_FUNCTION__) #else @@ -324,7 +324,7 @@ int ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj * \retval 1 on success * \retval 0 if there's a problem, or it's already there. */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int _ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func); #define ast_hashtab_insert_safe(a,b) _ast_hashtab_insert_safe(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) #else @@ -362,7 +362,7 @@ int ast_hashtab_size( struct ast_hashtab *tab); int ast_hashtab_capacity( struct ast_hashtab *tab); /*! \brief Return a copy of the hash table */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC struct ast_hashtab *_ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_func)(const void *obj), const char *file, int lineno, const char *func); #define ast_hashtab_dup(a,b) _ast_hashtab_dup(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__) #else @@ -370,7 +370,7 @@ struct ast_hashtab *ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_fun #endif /*! \brief Gives an iterator to hastable */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC struct ast_hashtab_iter *_ast_hashtab_start_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func); #define ast_hashtab_start_traversal(a) _ast_hashtab_start_traversal(a,__FILE__,__LINE__,__PRETTY_FUNCTION__) #else @@ -395,7 +395,7 @@ void *ast_hashtab_remove_this_object(struct ast_hashtab *tab, void *obj); /* ------------------ */ /*! \brief Gives an iterator to hastable */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC struct ast_hashtab_iter *_ast_hashtab_start_write_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func); #define ast_hashtab_start_write_traversal(a) _ast_hashtab_start_write_traversal(a,__FILE__,__LINE__,__PRETTY_FUNCTION__) #else diff --git a/include/asterisk/heap.h b/include/asterisk/heap.h index a868ac58934..7283279364f 100644 --- a/include/asterisk/heap.h +++ b/include/asterisk/heap.h @@ -97,7 +97,7 @@ typedef int (*ast_heap_cmp_fn)(void *elm1, void *elm2); * \return An instance of a max heap * \since 1.6.1 */ -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC struct ast_heap *_ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_fn, ssize_t index_offset, const char *file, int lineno, const char *func); #define ast_heap_create(a,b,c) _ast_heap_create(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) @@ -126,7 +126,7 @@ struct ast_heap *ast_heap_destroy(struct ast_heap *h); * \retval non-zero failure * \since 1.6.1 */ -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC int _ast_heap_push(struct ast_heap *h, void *elm, const char *file, int lineno, const char *func); #define ast_heap_push(a,b) _ast_heap_push(a,b,__FILE__,__LINE__,__PRETTY_FUNCTION__) #else diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 2ca75a69c47..eb5b4e43c25 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -616,7 +616,7 @@ int ast_regex_string_to_regex_pattern(const char *regex_string, struct ast_str * * \note The result of this function is dynamically allocated memory, and must * be free()'d after it is no longer needed. */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC #define ast_str_create(a) _ast_str_create(a,__FILE__,__LINE__,__PRETTY_FUNCTION__) AST_INLINE_API( struct ast_str * attribute_malloc _ast_str_create(size_t init_len, @@ -771,7 +771,7 @@ char *ast_str_truncate(struct ast_str *buf, ssize_t len), /*! * Make space in a new string (e.g. to read in data from a file) */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC AST_INLINE_API( int _ast_str_make_space(struct ast_str **buf, size_t new_len, const char *file, int lineno, const char *function), { @@ -964,7 +964,7 @@ enum { * through calling one of the other functions or macros defined in this * file. */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int __attribute__((format(printf, 4, 0))) __ast_debug_str_helper(struct ast_str **buf, ssize_t max_len, int append, const char *fmt, va_list ap, const char *file, int lineno, const char *func); #define __ast_str_helper(a,b,c,d,e) __ast_debug_str_helper(a,b,c,d,e,__FILE__,__LINE__,__PRETTY_FUNCTION__) diff --git a/main/chanvars.c b/main/chanvars.c index dc97df77353..d7922522cd4 100644 --- a/main/chanvars.c +++ b/main/chanvars.c @@ -35,7 +35,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/strings.h" #include "asterisk/utils.h" -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC struct ast_var_t *_ast_var_assign(const char *name, const char *value, const char *file, int lineno, const char *function) #else struct ast_var_t *ast_var_assign(const char *name, const char *value) @@ -45,7 +45,7 @@ struct ast_var_t *ast_var_assign(const char *name, const char *value) int name_len = strlen(name) + 1; int value_len = strlen(value) + 1; -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC if (!(var = __ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char), file, lineno, function))) { #else if (!(var = ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char)))) { diff --git a/main/config.c b/main/config.c index 59927038489..6162149b167 100644 --- a/main/config.c +++ b/main/config.c @@ -283,7 +283,7 @@ struct ast_config_include { static void ast_variable_destroy(struct ast_variable *doomed); static void ast_includes_destroy(struct ast_config_include *incls); -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno) #else struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) @@ -300,7 +300,7 @@ struct ast_variable *ast_variable_new(const char *name, const char *value, const } if ( -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC (variable = __ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable), file, lineno, func)) #else (variable = ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable))) diff --git a/main/hashtab.c b/main/hashtab.c index 5d54fb7aa3b..3719c2ad437 100644 --- a/main/hashtab.c +++ b/main/hashtab.c @@ -44,7 +44,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/hashtab.h" -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC static void _ast_hashtab_resize(struct ast_hashtab *tab, const char *file, int lineno, const char *func); #define ast_hashtab_resize(a) _ast_hashtab_resize(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) #else @@ -219,7 +219,7 @@ unsigned int ast_hashtab_hash_short(const short x) } struct ast_hashtab * -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC _ast_hashtab_create #else ast_hashtab_create @@ -230,14 +230,14 @@ ast_hashtab_create int (*newsize)(struct ast_hashtab *tab), unsigned int (*hash)(const void *obj), int do_locking -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC , const char *file, int lineno, const char *function #endif ) { struct ast_hashtab *ht; -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC if (!(ht = __ast_calloc(1, sizeof(*ht), file, lineno, function))) #else if (!(ht = ast_calloc(1, sizeof(*ht)))) @@ -247,7 +247,7 @@ ast_hashtab_create while (!ast_is_prime(initial_buckets)) /* make sure this is prime */ initial_buckets++; -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC if (!(ht->array = __ast_calloc(initial_buckets, sizeof(*(ht->array)), file, lineno, function))) { #else if (!(ht->array = ast_calloc(initial_buckets, sizeof(*(ht->array))))) { @@ -275,7 +275,7 @@ ast_hashtab_create return ht; } -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC struct ast_hashtab *_ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_func)(const void *obj), const char *file, int lineno, const char *func) #else struct ast_hashtab *ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_func)(const void *obj)) @@ -288,7 +288,7 @@ struct ast_hashtab *ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_fun return NULL; if (!(ht->array = -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC __ast_calloc(tab->hash_tab_size, sizeof(*(ht->array)), file, lineno, func) #else ast_calloc(tab->hash_tab_size, sizeof(*(ht->array))) @@ -316,7 +316,7 @@ struct ast_hashtab *ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_fun while (b) { void *newobj = (*obj_dup_func)(b->object); if (newobj) -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC _ast_hashtab_insert_immediate_bucket(ht, newobj, i, file, lineno, func); #else ast_hashtab_insert_immediate_bucket(ht, newobj, i); @@ -427,7 +427,7 @@ void ast_hashtab_destroy(struct ast_hashtab *tab, void (*objdestroyfunc)(void *o } } -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int _ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func) #else int ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj) @@ -444,7 +444,7 @@ int ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj) h = (*tab->hash)(obj) % tab->hash_tab_size; -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC res = _ast_hashtab_insert_immediate_bucket(tab, obj, h, file, lineno, func); #else res = ast_hashtab_insert_immediate_bucket(tab, obj, h); @@ -456,7 +456,7 @@ int ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj) return res; } -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int _ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj, unsigned int h, const char *file, int lineno, const char *func) #else int ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj, unsigned int h) @@ -475,7 +475,7 @@ int ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj tab->largest_bucket_size = c + 1; if (!(b = -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC __ast_calloc(1, sizeof(*b), file, lineno, func) #else ast_calloc(1, sizeof(*b)) @@ -498,7 +498,7 @@ int ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj return 1; } -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int _ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func) #else int ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj) @@ -514,7 +514,7 @@ int ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj) ast_rwlock_wrlock(&tab->lock); if (!ast_hashtab_lookup_bucket(tab, obj, &bucket)) { -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int ret2 = _ast_hashtab_insert_immediate_bucket(tab, obj, bucket, file, lineno, func); #else int ret2 = ast_hashtab_insert_immediate_bucket(tab, obj, bucket); @@ -637,7 +637,7 @@ int ast_hashtab_capacity( struct ast_hashtab *tab) /* the insert operation calls this, and is wrlock'd when it does. */ /* if you want to call it, you should set the wrlock yourself */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC static void _ast_hashtab_resize(struct ast_hashtab *tab, const char *file, int lineno, const char *func) #else static void ast_hashtab_resize(struct ast_hashtab *tab) @@ -660,7 +660,7 @@ static void ast_hashtab_resize(struct ast_hashtab *tab) } free(tab->array); if (!(tab->array = -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC __ast_calloc(newsize, sizeof(*(tab->array)), file, lineno, func) #else ast_calloc(newsize, sizeof(*(tab->array))) @@ -691,7 +691,7 @@ static void ast_hashtab_resize(struct ast_hashtab *tab) } } -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC struct ast_hashtab_iter *_ast_hashtab_start_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func) #else struct ast_hashtab_iter *ast_hashtab_start_traversal(struct ast_hashtab *tab) @@ -701,7 +701,7 @@ struct ast_hashtab_iter *ast_hashtab_start_traversal(struct ast_hashtab *tab) struct ast_hashtab_iter *it; if (!(it = -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC __ast_calloc(1, sizeof(*it), file, lineno, func) #else ast_calloc(1, sizeof(*it)) @@ -718,7 +718,7 @@ struct ast_hashtab_iter *ast_hashtab_start_traversal(struct ast_hashtab *tab) } /* use this function to get a write lock */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC struct ast_hashtab_iter *_ast_hashtab_start_write_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func) #else struct ast_hashtab_iter *ast_hashtab_start_write_traversal(struct ast_hashtab *tab) @@ -728,7 +728,7 @@ struct ast_hashtab_iter *ast_hashtab_start_write_traversal(struct ast_hashtab *t struct ast_hashtab_iter *it; if (!(it = -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC __ast_calloc(1, sizeof(*it), file, lineno, func) #else ast_calloc(1, sizeof(*it)) diff --git a/main/heap.c b/main/heap.c index 29f069b30a4..73280fedc1e 100644 --- a/main/heap.c +++ b/main/heap.c @@ -111,7 +111,7 @@ int ast_heap_verify(struct ast_heap *h) return 0; } -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC struct ast_heap *_ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_fn, ssize_t index_offset, const char *file, int lineno, const char *func) #else @@ -131,7 +131,7 @@ struct ast_heap *ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_f } if (!(h = -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC __ast_calloc(1, sizeof(*h), file, lineno, func) #else ast_calloc(1, sizeof(*h)) @@ -145,7 +145,7 @@ struct ast_heap *ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_f h->avail_len = (1 << init_height) - 1; if (!(h->heap = -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC __ast_calloc(1, h->avail_len * sizeof(void *), file, lineno, func) #else ast_calloc(1, h->avail_len * sizeof(void *)) @@ -176,7 +176,7 @@ struct ast_heap *ast_heap_destroy(struct ast_heap *h) * \brief Add a row of additional storage for the heap. */ static int grow_heap(struct ast_heap *h -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC , const char *file, int lineno, const char *func #endif ) @@ -184,7 +184,7 @@ static int grow_heap(struct ast_heap *h void **new_heap; size_t new_len = h->avail_len * 2 + 1; -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC new_heap = __ast_realloc(h->heap, new_len * sizeof(void *), file, lineno, func); #else new_heap = ast_realloc(h->heap, new_len * sizeof(void *)); @@ -244,14 +244,14 @@ static int bubble_up(struct ast_heap *h, int i) return i; } -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC int _ast_heap_push(struct ast_heap *h, void *elm, const char *file, int lineno, const char *func) #else int ast_heap_push(struct ast_heap *h, void *elm) #endif { if (h->cur_len == h->avail_len && grow_heap(h -#ifdef MALLOC_DEBUG +#ifdef __AST_DEBUG_MALLOC , file, lineno, func #endif )) { diff --git a/main/strings.c b/main/strings.c index b9c88dea572..e62eb9aad62 100644 --- a/main/strings.c +++ b/main/strings.c @@ -53,7 +53,7 @@ ASTERISK_REGISTER_FILE() * ast_str_append_va(...) */ -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC int __ast_debug_str_helper(struct ast_str **buf, ssize_t max_len, int append, const char *fmt, va_list ap, const char *file, int lineno, const char *function) #else @@ -112,7 +112,7 @@ int __ast_str_helper(struct ast_str **buf, ssize_t max_len, } if ( -#if (defined(MALLOC_DEBUG) && !defined(STANDALONE)) +#ifdef __AST_DEBUG_MALLOC _ast_str_make_space(buf, need, file, lineno, function) #else ast_str_make_space(buf, need) From 12752c64cc59f8b2d86499bd34a7de3372200af9 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Sat, 20 Aug 2016 18:18:51 +0200 Subject: [PATCH 0688/1578] pjproject_bundled: Allow IPv4/IPv6 (Dual Stack) configurations. PJProject supports a lot of platforms even Windows, some with different defaults when it comes to IPv6. In many Linux platforms like Ubuntu 16.04 LTS, "/proc/sys/net/ipv6/bindv6only" is set to 0 (false). Different than in Windows. Because of this, if configured with just an IPv6 address/transport, PJProject listens to both IPv4 and IPv6. However, this is not supported by the PJProject team. As consequence, you end-up with IPv4-mapped IPv6 addresses in SDP, incompatible with IPv4-only clients. Technically, you end-up with an IPv6-only server which accepts incoming connections on IPv4. If you try to configure two transports, one with IPv4 and one with IPv6 on the same interface, as expected by the PJProject team, the IPv4 transport is not able to bind because the IPv6 transport listens to both already. One solution would be to change "/proc/sys/net/ipv6/bindv6only" system-wide. Then, you are able to configure two transports, one for each IP version on the same interface. That way, you get a server which works with IPv4 clients and IPv6 clients at the same time over the same interface. Here, this change sets this parameter directly within PJProject to match the expectations of the PJProject team in any case. This allows IPv4/IPv6 Dual Stack servers out of the box like in chan_sip. This change was accepted by the PJProject team as and is expected to arrive in the next version, PJProject 2.6.0. Until then, this change is incorporated in the bundled PJProject of Asterisk. ASTERISK-26309 Change-Id: I3335d8718f79f4b2feae91b5b005a3ce684a63ae --- .../patches/0003-r5403-pjsip_IPV6_V6ONLY.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch diff --git a/third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch b/third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch new file mode 100644 index 00000000000..b324b53f4a9 --- /dev/null +++ b/third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch @@ -0,0 +1,13 @@ +--- a/pjlib/src/pj/sock_bsd.c ++++ b/pjlib/src/pj/sock_bsd.c +@@ -539,6 +539,10 @@ + pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_NOSIGPIPE(), + &val, sizeof(val)); + } ++ if (af != PJ_AF_INET) { /* Linux Kernel 2.4.21; June 2003 */ ++ pj_sock_setsockopt(*sock, PJ_SOL_IPV6, IPV6_V6ONLY, ++ &val, sizeof(val)); ++ } + #if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ + PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 + if (type == pj_SOCK_DGRAM()) { From eb0c9c476f77701c693d68fe8d39508027b8f62f Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Sat, 20 Aug 2016 14:51:59 -0500 Subject: [PATCH 0689/1578] res_odbc_transaction: add dep on generic_odbc When res_odbc_transaction depended on res_odbc, it got the generic_odbc headers and libs implicitly. Now that it no longer depends on res_odbc, its dependency on generic_odbc must be explicit. Change-Id: I9db88f7af7388437f49903d3008ba8d4890d5911 --- res/res_odbc_transaction.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_odbc_transaction.c b/res/res_odbc_transaction.c index 569fcb267fb..dd6ee30e5e3 100644 --- a/res/res_odbc_transaction.c +++ b/res/res_odbc_transaction.c @@ -26,6 +26,7 @@ #include "asterisk/module.h" /*** MODULEINFO + generic_odbc core ***/ From 41ee14bfaed4b184d8a577b263c6ab5ab741e35b Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 19 Aug 2016 11:21:01 -0400 Subject: [PATCH 0690/1578] compilation failed with -Werror=maybe-uninitialized The compilation failed for devmode --enable DONT_OPTIMIZE --enable BETTER_BACKTRACES --enable DO_CRASH --enable TEST_FRAMEWORK res_pjsip/pjsip_configuration.c: In function dtls_handler: res_pjsip/pjsip_configuration.c:974:20: error: back may be used uninitialized in this function [-Werror=maybe-uninitialized] int size = strlen(front); ^ cc1: all warnings being treated as errors Change-Id: I7f082ead0312792a577ec7c73015ba64dabca580 --- res/res_pjsip/pjsip_configuration.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 3bced1180ca..23aa522ce89 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -963,7 +963,9 @@ static int dtls_handler(const struct aco_option *opt, { struct ast_sip_endpoint *endpoint = obj; char *name = ast_strdupa(var->name); - char *front, *back, *buf = name; + char *front = NULL; + char *back = NULL; + char *buf = name; /* strip out underscores in the name */ front = strtok_r(buf, "_", &back); From 065d810d3ff91208e2e7784eb658d3e96b9a1931 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 23 Aug 2016 05:54:02 -0500 Subject: [PATCH 0691/1578] Revert "ConfBridge: Rework announcer channel methodology" This reverts commit 5aa877305223faab5a1119276a934893ab9dc138. Change-Id: I9ab45776e54a54ecf1bac9ae62d976dec30ef491 --- apps/app_confbridge.c | 274 +++++---------------------- apps/confbridge/conf_chan_announce.c | 30 ++- apps/confbridge/include/confbridge.h | 12 +- 3 files changed, 85 insertions(+), 231 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index d5cbc41595a..82204c48fce 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -71,7 +71,6 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_bridges.h" #include "asterisk/json.h" #include "asterisk/format_cache.h" -#include "asterisk/taskprocessor.h" /*** DOCUMENTATION @@ -963,59 +962,6 @@ static void handle_video_on_exit(struct confbridge_conference *conference, struc ao2_unlock(conference); } -struct hangup_data -{ - struct confbridge_conference *conference; - ast_mutex_t lock; - ast_cond_t cond; - int hungup; -}; - -/*! - * \brief Hang up the announcer channel - * - * This hangs up the announcer channel in the conference. This - * runs in the playback queue taskprocessor since we do not want - * to hang up the channel while it's trying to play an announcement. - * - * This task is performed synchronously, so there is no need to - * perform any cleanup on the passed-in data. - * - * \param data A hangup_data structure - * \return 0 - */ -static int hangup_playback(void *data) -{ - struct hangup_data *hangup = data; - - ast_autoservice_stop(hangup->conference->playback_chan); - - ast_hangup(hangup->conference->playback_chan); - hangup->conference->playback_chan = NULL; - - ast_mutex_lock(&hangup->lock); - hangup->hungup = 1; - ast_cond_signal(&hangup->cond); - ast_mutex_unlock(&hangup->lock); - - return 0; -} - -static void hangup_data_init(struct hangup_data *hangup, struct confbridge_conference *conference) -{ - ast_mutex_init(&hangup->lock); - ast_cond_init(&hangup->cond, NULL); - - hangup->conference = conference; - hangup->hungup = 0; -} - -static void hangup_data_destroy(struct hangup_data *hangup) -{ - ast_mutex_destroy(&hangup->lock); - ast_cond_destroy(&hangup->cond); -} - /*! * \brief Destroy a conference bridge * @@ -1030,22 +976,9 @@ static void destroy_conference_bridge(void *obj) ast_debug(1, "Destroying conference bridge '%s'\n", conference->name); if (conference->playback_chan) { - if (conference->playback_queue) { - struct hangup_data hangup; - hangup_data_init(&hangup, conference); - ast_taskprocessor_push(conference->playback_queue, hangup_playback, &hangup); - - ast_mutex_lock(&hangup.lock); - while (!hangup.hungup) { - ast_cond_wait(&hangup.cond, &hangup.lock); - } - ast_mutex_unlock(&hangup.lock); - hangup_data_destroy(&hangup); - } else { - /* Playback queue is not yet allocated. Just hang up the channel straight */ - ast_hangup(conference->playback_chan); - conference->playback_chan = NULL; - } + conf_announce_channel_depart(conference->playback_chan); + ast_hangup(conference->playback_chan); + conference->playback_chan = NULL; } /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */ @@ -1059,7 +992,7 @@ static void destroy_conference_bridge(void *obj) ast_free(conference->record_filename); conf_bridge_profile_destroy(&conference->b_profile); - ast_taskprocessor_unreference(conference->playback_queue); + ast_mutex_destroy(&conference->playback_lock); } /*! \brief Call the proper join event handler for the user for the conference bridge's current state @@ -1339,72 +1272,6 @@ void conf_ended(struct confbridge_conference *conference) ao2_unlock(conference); } -/*! - * \internal - * \brief Allocate playback channel for a conference. - * \pre expects conference to be locked before calling this function - */ -static int alloc_playback_chan(struct confbridge_conference *conference) -{ - struct ast_format_cap *cap; - char taskprocessor_name[AST_TASKPROCESSOR_MAX_NAME + 1]; - - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!cap) { - return -1; - } - ast_format_cap_append(cap, ast_format_slin, 0); - conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL, - conference->name, NULL); - ao2_ref(cap, -1); - if (!conference->playback_chan) { - return -1; - } - - /* To make sure playback_chan has the same language as the bridge */ - ast_channel_lock(conference->playback_chan); - ast_channel_language_set(conference->playback_chan, conference->b_profile.language); - ast_channel_unlock(conference->playback_chan); - - ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n", - ast_channel_name(conference->playback_chan), conference->name); - - ast_taskprocessor_build_name(taskprocessor_name, sizeof(taskprocessor_name), - "Confbridge/%s", conference->name); - conference->playback_queue = ast_taskprocessor_get(taskprocessor_name, TPS_REF_DEFAULT); - if (!conference->playback_queue) { - ast_hangup(conference->playback_chan); - conference->playback_chan = NULL; - return -1; - } - return 0; -} - -/*! - * \brief Push the announcer channel into the bridge - * - * This runs in the playback queue taskprocessor. - * - * \param data A confbridge_conference - * \retval 0 Success - * \retval -1 Failed to push the channel to the bridge - */ -static int push_announcer(void *data) -{ - struct confbridge_conference *conference = data; - - if (conf_announce_channel_push(conference->playback_chan)) { - ast_hangup(conference->playback_chan); - conference->playback_chan = NULL; - ao2_cleanup(conference); - return -1; - } - - ast_autoservice_start(conference->playback_chan); - ao2_cleanup(conference); - return 0; -} - /*! * \brief Join a conference bridge * @@ -1450,6 +1317,9 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen return NULL; } + /* Setup lock for playback channel */ + ast_mutex_init(&conference->playback_lock); + /* Setup for the record channel */ conference->record_filename = ast_str_create(RECORD_FILENAME_INITIAL_SPACE); if (!conference->record_filename) { @@ -1494,22 +1364,6 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen /* Set the initial state to EMPTY */ conference->state = CONF_STATE_EMPTY; - if (alloc_playback_chan(conference)) { - ao2_unlink(conference_bridges, conference); - ao2_ref(conference, -1); - ao2_unlock(conference_bridges); - ast_log(LOG_ERROR, "Could not allocate announcer channel for conference '%s'\n", conference_name); - return NULL; - } - - if (ast_taskprocessor_push(conference->playback_queue, push_announcer, ao2_bump(conference))) { - ao2_unlink(conference_bridges, conference); - ao2_ref(conference, -1); - ao2_unlock(conference_bridges); - ast_log(LOG_ERROR, "Could not add announcer channel for conference '%s' bridge\n", conference_name); - return NULL; - } - if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) { ao2_lock(conference); conf_start_record(conference); @@ -1630,105 +1484,67 @@ static void leave_conference(struct confbridge_user *user) user->conference = NULL; } -struct playback_task_data { - struct confbridge_conference *conference; - const char *filename; - int say_number; - int playback_finished; - ast_mutex_t lock; - ast_cond_t cond; -}; - /*! - * \brief Play an announcement into a confbridge - * - * This runs in the playback queue taskprocessor. This ensures that - * all playbacks are handled in sequence and do not play over top one - * another. - * - * This task runs synchronously so there is no need for performing any - * sort of cleanup on the input parameter. - * - * \param data A playback_task_data - * \return 0 + * \internal + * \brief Allocate playback channel for a conference. + * \pre expects conference to be locked before calling this function */ -static int playback_task(void *data) +static int alloc_playback_chan(struct confbridge_conference *conference) { - struct playback_task_data *ptd = data; + struct ast_format_cap *cap; - /* Don't try to play if the playback channel has been hung up */ - if (!ptd->conference->playback_chan) { - goto end; + cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!cap) { + return -1; } - - ast_autoservice_stop(ptd->conference->playback_chan); - - /* The channel is all under our control, in goes the prompt */ - if (!ast_strlen_zero(ptd->filename)) { - ast_stream_and_wait(ptd->conference->playback_chan, ptd->filename, ""); - } else if (ptd->say_number >= 0) { - ast_say_number(ptd->conference->playback_chan, ptd->say_number, "", - ast_channel_language(ptd->conference->playback_chan), NULL); + ast_format_cap_append(cap, ast_format_slin, 0); + conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL, + conference->name, NULL); + ao2_ref(cap, -1); + if (!conference->playback_chan) { + return -1; } - ast_autoservice_start(ptd->conference->playback_chan); -end: - ast_mutex_lock(&ptd->lock); - ptd->playback_finished = 1; - ast_cond_signal(&ptd->cond); - ast_mutex_unlock(&ptd->lock); + /* To make sure playback_chan has the same language of that profile */ + ast_channel_lock(conference->playback_chan); + ast_channel_language_set(conference->playback_chan, conference->b_profile.language); + ast_channel_unlock(conference->playback_chan); + ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n", + ast_channel_name(conference->playback_chan), conference->name); return 0; } -static void playback_task_data_init(struct playback_task_data *ptd, struct confbridge_conference *conference, - const char *filename, int say_number) -{ - ast_mutex_init(&ptd->lock); - ast_cond_init(&ptd->cond, NULL); - - ptd->filename = filename; - ptd->say_number = say_number; - ptd->conference = conference; - ptd->playback_finished = 0; -} - -static void playback_task_data_destroy(struct playback_task_data *ptd) -{ - ast_mutex_destroy(&ptd->lock); - ast_cond_destroy(&ptd->cond); -} - static int play_sound_helper(struct confbridge_conference *conference, const char *filename, int say_number) { - struct playback_task_data ptd; - /* Do not waste resources trying to play files that do not exist */ if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) { return 0; } - playback_task_data_init(&ptd, conference, filename, say_number); - if (ast_taskprocessor_push(conference->playback_queue, playback_task, &ptd)) { - if (!ast_strlen_zero(filename)) { - ast_log(LOG_WARNING, "Unable to play file '%s' to conference %s\n", - filename, conference->name); - } else { - ast_log(LOG_WARNING, "Unable to say number '%d' to conference %s\n", - say_number, conference->name); - } - playback_task_data_destroy(&ptd); + ast_mutex_lock(&conference->playback_lock); + if (!conference->playback_chan && alloc_playback_chan(conference)) { + ast_mutex_unlock(&conference->playback_lock); + return -1; + } + if (conf_announce_channel_push(conference->playback_chan)) { + ast_mutex_unlock(&conference->playback_lock); return -1; } - /* Wait for the playback to complete */ - ast_mutex_lock(&ptd.lock); - while (!ptd.playback_finished) { - ast_cond_wait(&ptd.cond, &ptd.lock); + /* The channel is all under our control, in goes the prompt */ + if (!ast_strlen_zero(filename)) { + ast_stream_and_wait(conference->playback_chan, filename, ""); + } else if (say_number >= 0) { + ast_say_number(conference->playback_chan, say_number, "", + ast_channel_language(conference->playback_chan), NULL); } - ast_mutex_unlock(&ptd.lock); - playback_task_data_destroy(&ptd); + ast_debug(1, "Departing announcer channel '%s' from conference bridge '%s'\n", + ast_channel_name(conference->playback_chan), conference->name); + conf_announce_channel_depart(conference->playback_chan); + + ast_mutex_unlock(&conference->playback_lock); return 0; } diff --git a/apps/confbridge/conf_chan_announce.c b/apps/confbridge/conf_chan_announce.c index 4060b99c4f1..ff30499086c 100644 --- a/apps/confbridge/conf_chan_announce.c +++ b/apps/confbridge/conf_chan_announce.c @@ -143,6 +143,31 @@ struct ast_channel_tech *conf_announce_get_tech(void) return &announce_tech; } +void conf_announce_channel_depart(struct ast_channel *chan) +{ + struct announce_pvt *p = ast_channel_tech_pvt(chan); + + if (!p) { + return; + } + + ao2_ref(p, +1); + ao2_lock(p); + if (!ast_test_flag(&p->base, AST_UNREAL_CARETAKER_THREAD)) { + ao2_unlock(p); + ao2_ref(p, -1); + return; + } + ast_clear_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); + chan = p->base.chan; + ao2_unlock(p); + ao2_ref(p, -1); + if (chan) { + ast_bridge_depart(chan); + ast_channel_unref(chan); + } +} + int conf_announce_channel_push(struct ast_channel *ast) { struct ast_bridge_features *features; @@ -161,17 +186,20 @@ int conf_announce_channel_push(struct ast_channel *ast) if (!chan) { return -1; } + ast_channel_ref(chan); } features = ast_bridge_features_new(); if (!features) { + ast_channel_unref(chan); return -1; } ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE); /* Impart the output channel into the bridge */ if (ast_bridge_impart(p->bridge, chan, NULL, features, - AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { + AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { + ast_channel_unref(chan); return -1; } ao2_lock(p); diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 5d71a63bccd..5ae0421131b 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -228,9 +228,9 @@ struct confbridge_conference { struct ast_channel *record_chan; /*!< Channel used for recording the conference */ struct ast_str *record_filename; /*!< Recording filename. */ struct ast_str *orig_rec_file; /*!< Previous b_profile.rec_file. */ + ast_mutex_t playback_lock; /*!< Lock used for playback channel */ AST_LIST_HEAD_NOLOCK(, confbridge_user) active_list; /*!< List of users participating in the conference bridge */ AST_LIST_HEAD_NOLOCK(, confbridge_user) waiting_list; /*!< List of users waiting to join the conference bridge */ - struct ast_taskprocessor *playback_queue; /*!< Queue for playing back bridge announcements and managing the announcer channel */ }; extern struct ao2_container *conference_bridges; @@ -609,6 +609,16 @@ struct ast_channel_tech *conf_record_get_tech(void); */ struct ast_channel_tech *conf_announce_get_tech(void); +/*! + * \brief Remove the announcer channel from the conference. + * \since 12.0.0 + * + * \param chan Either channel in the announcer channel pair. + * + * \return Nothing + */ +void conf_announce_channel_depart(struct ast_channel *chan); + /*! * \brief Push the announcer channel into the conference. * \since 12.0.0 From ded22c712a6886b45758d79c750cad199135a72a Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 10 Aug 2016 15:14:09 -0500 Subject: [PATCH 0692/1578] ConfBridge: Rework announcer channel methodology NOTE: This patch was submitted earlier and reverted because of a failing test. The test has been patched so that it adjusts for the changes here, so this is being resubmitted for review. One feature that confbridge has is the ability to play sounds to all participants in the conference. Prior to this commit, the algorithm for this was as follows: * Grab the playback lock * Push the conference announcer channel into the bridge * Play back the sound * Pull the conference announcer channel from the bridge * Release the playback lock The issue here is that the act of adding the playback channel to the bridge and removing it for each announcement is expensive. Amongst the expenses: * The announcer channel is imparted into the bridge, meaning a new thread is spun up for each playback. * When the announcer is added or removed from the bridge, it results in the BRIDGEPEER channel variable being set on all channels in the bridge. This requires keeping the bridge locked and locking each individual channel in order to set it. * There's also just the general overhead of adding the channel and removing it from the bridge. The bridge potentially has to reconfigure every single time With this commit, the paradigm for playing back announcements has shifted. * The announcer channel is now added to the bridge when the conference is allocated, and it is hung up when the conference is destroyed. * A taskprocessor is used to queue playbacks onto the announcer channel. This keeps the behavior from before where playbacks do not overlap. * The announcer channel is no longer placed into the bridge as departable. Since we are not constantly removing the channel from the bridge, it is safe to add the channel using an independent thread and simply hang the channel up when it is time for the conference to be destroyed. The use of the taskprocessor for playbacks opens up the interesting possibility of having asynchronous announcements played. In this commit, however, the behavior is still exactly the same as it previously was. ASTERISK-26289 Reported by Mark Michelson Change-Id: Ica9fa4907c2f3728cdd1cf0bc564ef4eb40754a0 --- apps/app_confbridge.c | 274 ++++++++++++++++++++++----- apps/confbridge/conf_chan_announce.c | 30 +-- apps/confbridge/include/confbridge.h | 12 +- 3 files changed, 231 insertions(+), 85 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 82204c48fce..d5cbc41595a 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -71,6 +71,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/stasis_bridges.h" #include "asterisk/json.h" #include "asterisk/format_cache.h" +#include "asterisk/taskprocessor.h" /*** DOCUMENTATION @@ -962,6 +963,59 @@ static void handle_video_on_exit(struct confbridge_conference *conference, struc ao2_unlock(conference); } +struct hangup_data +{ + struct confbridge_conference *conference; + ast_mutex_t lock; + ast_cond_t cond; + int hungup; +}; + +/*! + * \brief Hang up the announcer channel + * + * This hangs up the announcer channel in the conference. This + * runs in the playback queue taskprocessor since we do not want + * to hang up the channel while it's trying to play an announcement. + * + * This task is performed synchronously, so there is no need to + * perform any cleanup on the passed-in data. + * + * \param data A hangup_data structure + * \return 0 + */ +static int hangup_playback(void *data) +{ + struct hangup_data *hangup = data; + + ast_autoservice_stop(hangup->conference->playback_chan); + + ast_hangup(hangup->conference->playback_chan); + hangup->conference->playback_chan = NULL; + + ast_mutex_lock(&hangup->lock); + hangup->hungup = 1; + ast_cond_signal(&hangup->cond); + ast_mutex_unlock(&hangup->lock); + + return 0; +} + +static void hangup_data_init(struct hangup_data *hangup, struct confbridge_conference *conference) +{ + ast_mutex_init(&hangup->lock); + ast_cond_init(&hangup->cond, NULL); + + hangup->conference = conference; + hangup->hungup = 0; +} + +static void hangup_data_destroy(struct hangup_data *hangup) +{ + ast_mutex_destroy(&hangup->lock); + ast_cond_destroy(&hangup->cond); +} + /*! * \brief Destroy a conference bridge * @@ -976,9 +1030,22 @@ static void destroy_conference_bridge(void *obj) ast_debug(1, "Destroying conference bridge '%s'\n", conference->name); if (conference->playback_chan) { - conf_announce_channel_depart(conference->playback_chan); - ast_hangup(conference->playback_chan); - conference->playback_chan = NULL; + if (conference->playback_queue) { + struct hangup_data hangup; + hangup_data_init(&hangup, conference); + ast_taskprocessor_push(conference->playback_queue, hangup_playback, &hangup); + + ast_mutex_lock(&hangup.lock); + while (!hangup.hungup) { + ast_cond_wait(&hangup.cond, &hangup.lock); + } + ast_mutex_unlock(&hangup.lock); + hangup_data_destroy(&hangup); + } else { + /* Playback queue is not yet allocated. Just hang up the channel straight */ + ast_hangup(conference->playback_chan); + conference->playback_chan = NULL; + } } /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */ @@ -992,7 +1059,7 @@ static void destroy_conference_bridge(void *obj) ast_free(conference->record_filename); conf_bridge_profile_destroy(&conference->b_profile); - ast_mutex_destroy(&conference->playback_lock); + ast_taskprocessor_unreference(conference->playback_queue); } /*! \brief Call the proper join event handler for the user for the conference bridge's current state @@ -1272,6 +1339,72 @@ void conf_ended(struct confbridge_conference *conference) ao2_unlock(conference); } +/*! + * \internal + * \brief Allocate playback channel for a conference. + * \pre expects conference to be locked before calling this function + */ +static int alloc_playback_chan(struct confbridge_conference *conference) +{ + struct ast_format_cap *cap; + char taskprocessor_name[AST_TASKPROCESSOR_MAX_NAME + 1]; + + cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!cap) { + return -1; + } + ast_format_cap_append(cap, ast_format_slin, 0); + conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL, + conference->name, NULL); + ao2_ref(cap, -1); + if (!conference->playback_chan) { + return -1; + } + + /* To make sure playback_chan has the same language as the bridge */ + ast_channel_lock(conference->playback_chan); + ast_channel_language_set(conference->playback_chan, conference->b_profile.language); + ast_channel_unlock(conference->playback_chan); + + ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n", + ast_channel_name(conference->playback_chan), conference->name); + + ast_taskprocessor_build_name(taskprocessor_name, sizeof(taskprocessor_name), + "Confbridge/%s", conference->name); + conference->playback_queue = ast_taskprocessor_get(taskprocessor_name, TPS_REF_DEFAULT); + if (!conference->playback_queue) { + ast_hangup(conference->playback_chan); + conference->playback_chan = NULL; + return -1; + } + return 0; +} + +/*! + * \brief Push the announcer channel into the bridge + * + * This runs in the playback queue taskprocessor. + * + * \param data A confbridge_conference + * \retval 0 Success + * \retval -1 Failed to push the channel to the bridge + */ +static int push_announcer(void *data) +{ + struct confbridge_conference *conference = data; + + if (conf_announce_channel_push(conference->playback_chan)) { + ast_hangup(conference->playback_chan); + conference->playback_chan = NULL; + ao2_cleanup(conference); + return -1; + } + + ast_autoservice_start(conference->playback_chan); + ao2_cleanup(conference); + return 0; +} + /*! * \brief Join a conference bridge * @@ -1317,9 +1450,6 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen return NULL; } - /* Setup lock for playback channel */ - ast_mutex_init(&conference->playback_lock); - /* Setup for the record channel */ conference->record_filename = ast_str_create(RECORD_FILENAME_INITIAL_SPACE); if (!conference->record_filename) { @@ -1364,6 +1494,22 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen /* Set the initial state to EMPTY */ conference->state = CONF_STATE_EMPTY; + if (alloc_playback_chan(conference)) { + ao2_unlink(conference_bridges, conference); + ao2_ref(conference, -1); + ao2_unlock(conference_bridges); + ast_log(LOG_ERROR, "Could not allocate announcer channel for conference '%s'\n", conference_name); + return NULL; + } + + if (ast_taskprocessor_push(conference->playback_queue, push_announcer, ao2_bump(conference))) { + ao2_unlink(conference_bridges, conference); + ao2_ref(conference, -1); + ao2_unlock(conference_bridges); + ast_log(LOG_ERROR, "Could not add announcer channel for conference '%s' bridge\n", conference_name); + return NULL; + } + if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) { ao2_lock(conference); conf_start_record(conference); @@ -1484,67 +1630,105 @@ static void leave_conference(struct confbridge_user *user) user->conference = NULL; } +struct playback_task_data { + struct confbridge_conference *conference; + const char *filename; + int say_number; + int playback_finished; + ast_mutex_t lock; + ast_cond_t cond; +}; + /*! - * \internal - * \brief Allocate playback channel for a conference. - * \pre expects conference to be locked before calling this function + * \brief Play an announcement into a confbridge + * + * This runs in the playback queue taskprocessor. This ensures that + * all playbacks are handled in sequence and do not play over top one + * another. + * + * This task runs synchronously so there is no need for performing any + * sort of cleanup on the input parameter. + * + * \param data A playback_task_data + * \return 0 */ -static int alloc_playback_chan(struct confbridge_conference *conference) +static int playback_task(void *data) { - struct ast_format_cap *cap; + struct playback_task_data *ptd = data; - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!cap) { - return -1; + /* Don't try to play if the playback channel has been hung up */ + if (!ptd->conference->playback_chan) { + goto end; } - ast_format_cap_append(cap, ast_format_slin, 0); - conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL, - conference->name, NULL); - ao2_ref(cap, -1); - if (!conference->playback_chan) { - return -1; + + ast_autoservice_stop(ptd->conference->playback_chan); + + /* The channel is all under our control, in goes the prompt */ + if (!ast_strlen_zero(ptd->filename)) { + ast_stream_and_wait(ptd->conference->playback_chan, ptd->filename, ""); + } else if (ptd->say_number >= 0) { + ast_say_number(ptd->conference->playback_chan, ptd->say_number, "", + ast_channel_language(ptd->conference->playback_chan), NULL); } + ast_autoservice_start(ptd->conference->playback_chan); - /* To make sure playback_chan has the same language of that profile */ - ast_channel_lock(conference->playback_chan); - ast_channel_language_set(conference->playback_chan, conference->b_profile.language); - ast_channel_unlock(conference->playback_chan); +end: + ast_mutex_lock(&ptd->lock); + ptd->playback_finished = 1; + ast_cond_signal(&ptd->cond); + ast_mutex_unlock(&ptd->lock); - ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n", - ast_channel_name(conference->playback_chan), conference->name); return 0; } +static void playback_task_data_init(struct playback_task_data *ptd, struct confbridge_conference *conference, + const char *filename, int say_number) +{ + ast_mutex_init(&ptd->lock); + ast_cond_init(&ptd->cond, NULL); + + ptd->filename = filename; + ptd->say_number = say_number; + ptd->conference = conference; + ptd->playback_finished = 0; +} + +static void playback_task_data_destroy(struct playback_task_data *ptd) +{ + ast_mutex_destroy(&ptd->lock); + ast_cond_destroy(&ptd->cond); +} + static int play_sound_helper(struct confbridge_conference *conference, const char *filename, int say_number) { + struct playback_task_data ptd; + /* Do not waste resources trying to play files that do not exist */ if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) { return 0; } - ast_mutex_lock(&conference->playback_lock); - if (!conference->playback_chan && alloc_playback_chan(conference)) { - ast_mutex_unlock(&conference->playback_lock); - return -1; - } - if (conf_announce_channel_push(conference->playback_chan)) { - ast_mutex_unlock(&conference->playback_lock); + playback_task_data_init(&ptd, conference, filename, say_number); + if (ast_taskprocessor_push(conference->playback_queue, playback_task, &ptd)) { + if (!ast_strlen_zero(filename)) { + ast_log(LOG_WARNING, "Unable to play file '%s' to conference %s\n", + filename, conference->name); + } else { + ast_log(LOG_WARNING, "Unable to say number '%d' to conference %s\n", + say_number, conference->name); + } + playback_task_data_destroy(&ptd); return -1; } - /* The channel is all under our control, in goes the prompt */ - if (!ast_strlen_zero(filename)) { - ast_stream_and_wait(conference->playback_chan, filename, ""); - } else if (say_number >= 0) { - ast_say_number(conference->playback_chan, say_number, "", - ast_channel_language(conference->playback_chan), NULL); + /* Wait for the playback to complete */ + ast_mutex_lock(&ptd.lock); + while (!ptd.playback_finished) { + ast_cond_wait(&ptd.cond, &ptd.lock); } + ast_mutex_unlock(&ptd.lock); - ast_debug(1, "Departing announcer channel '%s' from conference bridge '%s'\n", - ast_channel_name(conference->playback_chan), conference->name); - conf_announce_channel_depart(conference->playback_chan); - - ast_mutex_unlock(&conference->playback_lock); + playback_task_data_destroy(&ptd); return 0; } diff --git a/apps/confbridge/conf_chan_announce.c b/apps/confbridge/conf_chan_announce.c index ff30499086c..4060b99c4f1 100644 --- a/apps/confbridge/conf_chan_announce.c +++ b/apps/confbridge/conf_chan_announce.c @@ -143,31 +143,6 @@ struct ast_channel_tech *conf_announce_get_tech(void) return &announce_tech; } -void conf_announce_channel_depart(struct ast_channel *chan) -{ - struct announce_pvt *p = ast_channel_tech_pvt(chan); - - if (!p) { - return; - } - - ao2_ref(p, +1); - ao2_lock(p); - if (!ast_test_flag(&p->base, AST_UNREAL_CARETAKER_THREAD)) { - ao2_unlock(p); - ao2_ref(p, -1); - return; - } - ast_clear_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); - chan = p->base.chan; - ao2_unlock(p); - ao2_ref(p, -1); - if (chan) { - ast_bridge_depart(chan); - ast_channel_unref(chan); - } -} - int conf_announce_channel_push(struct ast_channel *ast) { struct ast_bridge_features *features; @@ -186,20 +161,17 @@ int conf_announce_channel_push(struct ast_channel *ast) if (!chan) { return -1; } - ast_channel_ref(chan); } features = ast_bridge_features_new(); if (!features) { - ast_channel_unref(chan); return -1; } ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE); /* Impart the output channel into the bridge */ if (ast_bridge_impart(p->bridge, chan, NULL, features, - AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { - ast_channel_unref(chan); + AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { return -1; } ao2_lock(p); diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 5ae0421131b..5d71a63bccd 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -228,9 +228,9 @@ struct confbridge_conference { struct ast_channel *record_chan; /*!< Channel used for recording the conference */ struct ast_str *record_filename; /*!< Recording filename. */ struct ast_str *orig_rec_file; /*!< Previous b_profile.rec_file. */ - ast_mutex_t playback_lock; /*!< Lock used for playback channel */ AST_LIST_HEAD_NOLOCK(, confbridge_user) active_list; /*!< List of users participating in the conference bridge */ AST_LIST_HEAD_NOLOCK(, confbridge_user) waiting_list; /*!< List of users waiting to join the conference bridge */ + struct ast_taskprocessor *playback_queue; /*!< Queue for playing back bridge announcements and managing the announcer channel */ }; extern struct ao2_container *conference_bridges; @@ -609,16 +609,6 @@ struct ast_channel_tech *conf_record_get_tech(void); */ struct ast_channel_tech *conf_announce_get_tech(void); -/*! - * \brief Remove the announcer channel from the conference. - * \since 12.0.0 - * - * \param chan Either channel in the announcer channel pair. - * - * \return Nothing - */ -void conf_announce_channel_depart(struct ast_channel *chan); - /*! * \brief Push the announcer channel into the conference. * \since 12.0.0 From 2e79f52d7116e5529ab78972cee8081b6ffe6878 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 19 Jul 2016 20:14:21 +0200 Subject: [PATCH 0693/1578] codecs: Add Codec 2 mode 2400. ASTERISK-26217 #close Change-Id: I1e45d8084683fab5f2b272bf35f4a149cea8b8d6 --- build_tools/menuselect-deps.in | 1 + codecs/codec_codec2.c | 222 +++++++++++++++++++++++++++++++ codecs/ex_codec2.h | 32 +++++ configure | 143 ++++++++++++++++++++ configure.ac | 3 + include/asterisk/autoconfig.h.in | 3 + include/asterisk/format_cache.h | 5 + main/codec_builtin.c | 25 ++++ main/format_cache.c | 10 +- makeopts.in | 3 + 10 files changed, 446 insertions(+), 1 deletion(-) create mode 100644 codecs/codec_codec2.c create mode 100644 codecs/ex_codec2.h diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index f194482e958..a0444095556 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -4,6 +4,7 @@ COROSYNC=@PBX_COROSYNC@ CRYPTO=@PBX_CRYPTO@ BFD=@PBX_BFD@ BISON=@PBX_BISON@ +CODEC2=@PBX_CODEC2@ CURL=@PBX_CURL@ DAHDI=@PBX_DAHDI@ DLADDR=@PBX_DLADDR@ diff --git a/codecs/codec_codec2.c b/codecs/codec_codec2.c new file mode 100644 index 00000000000..e446854c310 --- /dev/null +++ b/codecs/codec_codec2.c @@ -0,0 +1,222 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Alexander Traud + * + * Alexander Traud + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Translate between signed linear and Codec 2 + * + * \author Alexander Traud + * + * \note http://www.rowetel.com/codec2.html + * + * \ingroup codecs + */ + +/*** MODULEINFO + codec2 + core + ***/ + +#include "asterisk.h" + +#include "asterisk/codec.h" /* for AST_MEDIA_TYPE_AUDIO */ +#include "asterisk/frame.h" /* for ast_frame */ +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */ +#include "asterisk/logger.h" /* for ast_log, etc */ +#include "asterisk/module.h" +#include "asterisk/rtp_engine.h" /* ast_rtp_engine_(un)load_format */ +#include "asterisk/translate.h" /* for ast_trans_pvt, etc */ + +#include + +#define BUFFER_SAMPLES 8000 +#define CODEC2_SAMPLES 160 /* consider codec2_samples_per_frame(.) */ +#define CODEC2_FRAME_LEN 6 /* consider codec2_bits_per_frame(.) */ + +/* Sample frame data */ +#include "asterisk/slin.h" +#include "ex_codec2.h" + +struct codec2_translator_pvt { + struct CODEC2 *state; /* May be encoder or decoder */ + int16_t buf[BUFFER_SAMPLES]; +}; + +static int codec2_new(struct ast_trans_pvt *pvt) +{ + struct codec2_translator_pvt *tmp = pvt->pvt; + + tmp->state = codec2_create(CODEC2_MODE_2400); + + if (!tmp->state) { + ast_log(LOG_ERROR, "Error creating Codec 2 conversion\n"); + return -1; + } + + return 0; +} + +/*! \brief decode and store in outbuf. */ +static int codec2tolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) +{ + struct codec2_translator_pvt *tmp = pvt->pvt; + int x; + + for (x = 0; x < f->datalen; x += CODEC2_FRAME_LEN) { + unsigned char *src = f->data.ptr + x; + int16_t *dst = pvt->outbuf.i16 + pvt->samples; + + codec2_decode(tmp->state, dst, src); + + pvt->samples += CODEC2_SAMPLES; + pvt->datalen += CODEC2_SAMPLES * 2; + } + + return 0; +} + +/*! \brief store samples into working buffer for later decode */ +static int lintocodec2_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) +{ + struct codec2_translator_pvt *tmp = pvt->pvt; + + memcpy(tmp->buf + pvt->samples, f->data.ptr, f->datalen); + pvt->samples += f->samples; + + return 0; +} + +/*! \brief encode and produce a frame */ +static struct ast_frame *lintocodec2_frameout(struct ast_trans_pvt *pvt) +{ + struct codec2_translator_pvt *tmp = pvt->pvt; + struct ast_frame *result = NULL; + struct ast_frame *last = NULL; + int samples = 0; /* output samples */ + + while (pvt->samples >= CODEC2_SAMPLES) { + struct ast_frame *current; + + /* Encode a frame of data */ + codec2_encode(tmp->state, pvt->outbuf.uc, tmp->buf + samples); + + samples += CODEC2_SAMPLES; + pvt->samples -= CODEC2_SAMPLES; + + current = ast_trans_frameout(pvt, CODEC2_FRAME_LEN, CODEC2_SAMPLES); + + if (!current) { + continue; + } else if (last) { + AST_LIST_NEXT(last, frame_list) = current; + } else { + result = current; + } + last = current; + } + + /* Move the data at the end of the buffer to the front */ + if (samples) { + memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2); + } + + return result; +} + +static void codec2_destroy_stuff(struct ast_trans_pvt *pvt) +{ + struct codec2_translator_pvt *tmp = pvt->pvt; + + if (tmp->state) { + codec2_destroy(tmp->state); + } +} + +static struct ast_translator codec2tolin = { + .name = "codec2tolin", + .src_codec = { + .name = "codec2", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", + .newpvt = codec2_new, + .framein = codec2tolin_framein, + .destroy = codec2_destroy_stuff, + .sample = codec2_sample, + .desc_size = sizeof(struct codec2_translator_pvt), + .buffer_samples = BUFFER_SAMPLES, + .buf_size = BUFFER_SAMPLES * 2, +}; + +static struct ast_translator lintocodec2 = { + .name = "lintocodec2", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "codec2", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "codec2", + .newpvt = codec2_new, + .framein = lintocodec2_framein, + .frameout = lintocodec2_frameout, + .destroy = codec2_destroy_stuff, + .sample = slin8_sample, + .desc_size = sizeof(struct codec2_translator_pvt), + .buffer_samples = BUFFER_SAMPLES, + .buf_size = (BUFFER_SAMPLES * CODEC2_FRAME_LEN + CODEC2_SAMPLES - 1) / CODEC2_SAMPLES, +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_rtp_engine_unload_format(ast_format_codec2); + res |= ast_unregister_translator(&lintocodec2); + res |= ast_unregister_translator(&codec2tolin); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_register_translator(&codec2tolin); + res |= ast_register_translator(&lintocodec2); + res |= ast_rtp_engine_load_format(ast_format_codec2); + + if (res) { + unload_module(); + return AST_MODULE_LOAD_FAILURE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Codec 2 Coder/Decoder"); diff --git a/codecs/ex_codec2.h b/codecs/ex_codec2.h new file mode 100644 index 00000000000..f2f4c9723b0 --- /dev/null +++ b/codecs/ex_codec2.h @@ -0,0 +1,32 @@ +/*! \file + * \brief 8-bit raw data + * + * Copyright (C) 2016, Alexander Traud + * + * Distributed under the terms of the GNU General Public License + * + */ + +#include "asterisk/format_cache.h" /* for ast_format_codec2 */ +#include "asterisk/frame.h" /* for ast_frame, etc */ + +static uint8_t ex_codec2[] = { + 0xea, 0xca, 0x14, 0x85, 0x91, 0x78, +}; + +static struct ast_frame *codec2_sample(void) +{ + static struct ast_frame f = { + .frametype = AST_FRAME_VOICE, + .datalen = sizeof(ex_codec2), + .samples = CODEC2_SAMPLES, + .mallocd = 0, + .offset = 0, + .src = __PRETTY_FUNCTION__, + .data.ptr = ex_codec2, + }; + + f.subclass.format = ast_format_codec2; + + return &f; +} diff --git a/configure b/configure index 6d3faf2048a..64c76831923 100755 --- a/configure +++ b/configure @@ -1152,6 +1152,10 @@ PBX_COROSYNC COROSYNC_DIR COROSYNC_INCLUDE COROSYNC_LIB +PBX_CODEC2 +CODEC2_DIR +CODEC2_INCLUDE +CODEC2_LIB PBX_CAP CAP_DIR CAP_INCLUDE @@ -1326,6 +1330,7 @@ with_bfd with_execinfo with_bluetooth with_cap +with_codec2 with_cpg with_curses with_crypt @@ -2065,6 +2070,7 @@ Optional Packages: --with-execinfo=PATH use Stack Backtrace files in PATH --with-bluetooth=PATH use Bluetooth files in PATH --with-cap=PATH use POSIX 1.e capabilities files in PATH + --with-codec2=PATH use Codec 2 Audio Decoder/Encoder files in PATH --with-cpg=PATH use Corosync files in PATH --with-curses=PATH use curses files in PATH --with-crypt=PATH use password and data encryption files in PATH @@ -8988,6 +8994,38 @@ fi + CODEC2_DESCRIP="Codec 2 Audio Decoder/Encoder" + CODEC2_OPTION="codec2" + PBX_CODEC2=0 + +# Check whether --with-codec2 was given. +if test "${with_codec2+set}" = set; then : + withval=$with_codec2; + case ${withval} in + n|no) + USE_CODEC2=no + # -1 is a magic value used by menuselect to know that the package + # was disabled, other than 'not found' + PBX_CODEC2=-1 + ;; + y|ye|yes) + ac_mandatory_list="${ac_mandatory_list} CODEC2" + ;; + *) + CODEC2_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} CODEC2" + ;; + esac + +fi + + + + + + + + COROSYNC_DESCRIP="Corosync" COROSYNC_OPTION="cpg" PBX_COROSYNC=0 @@ -30372,6 +30410,111 @@ fi fi +if test "x${PBX_CODEC2}" != "x1" -a "${USE_CODEC2}" != "no"; then + pbxlibdir="" + # if --with-CODEC2=DIR has been specified, use it. + if test "x${CODEC2_DIR}" != "x"; then + if test -d ${CODEC2_DIR}/lib; then + pbxlibdir="-L${CODEC2_DIR}/lib" + else + pbxlibdir="-L${CODEC2_DIR}" + fi + fi + pbxfuncname="codec2_create" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_CODEC2_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_codec2_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcodec2" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lcodec2... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcodec2 ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_CODEC2_FOUND=yes +else + AST_CODEC2_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_CODEC2_FOUND}" = "yes"; then + CODEC2_LIB="${pbxlibdir} -lcodec2 " + # if --with-CODEC2=DIR has been specified, use it. + if test "x${CODEC2_DIR}" != "x"; then + CODEC2_INCLUDE="-I${CODEC2_DIR}/include" + fi + CODEC2_INCLUDE="${CODEC2_INCLUDE} " + if test "xcodec2/codec2.h" = "x" ; then # no header, assume found + CODEC2_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${CODEC2_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "codec2/codec2.h" "ac_cv_header_codec2_codec2_h" "$ac_includes_default" +if test "x$ac_cv_header_codec2_codec2_h" = xyes; then : + CODEC2_HEADER_FOUND=1 +else + CODEC2_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${CODEC2_HEADER_FOUND}" = "x0" ; then + CODEC2_LIB="" + CODEC2_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + CODEC2_LIB="" + fi + PBX_CODEC2=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_CODEC2 1 +_ACEOF + + fi + fi +fi + + + + if test "x${PBX_COROSYNC}" != "x1" -a "${USE_COROSYNC}" != "no"; then pbxlibdir="" # if --with-COROSYNC=DIR has been specified, use it. diff --git a/configure.ac b/configure.ac index dedfd8a2e9d..96a20d0c368 100644 --- a/configure.ac +++ b/configure.ac @@ -407,6 +407,7 @@ AST_EXT_LIB_SETUP([BFD], [Debug symbol decoding], [bfd]) AST_EXT_LIB_SETUP([BKTR], [Stack Backtrace], [execinfo]) AST_EXT_LIB_SETUP([BLUETOOTH], [Bluetooth], [bluetooth]) AST_EXT_LIB_SETUP([CAP], [POSIX 1.e capabilities], [cap]) +AST_EXT_LIB_SETUP([CODEC2], [Codec 2 Audio Decoder/Encoder], [codec2]) AST_EXT_LIB_SETUP([COROSYNC], [Corosync], [cpg]) AST_EXT_LIB_SETUP_OPTIONAL([COROSYNC_CFG_STATE_TRACK], [A callback only in corosync 1.x], [COROSYNC], [cfg]) AST_EXT_LIB_SETUP([CURSES], [curses], [curses]) @@ -2336,6 +2337,8 @@ else AST_EXT_LIB_CHECK([RADIUS], [radiusclient-ng], [rc_read_config], [radiusclient-ng.h]) fi +AST_EXT_LIB_CHECK([CODEC2], [codec2], [codec2_create], [codec2/codec2.h]) + AST_EXT_LIB_CHECK([COROSYNC], [cpg], [cpg_join], [corosync/cpg.h], [-lcfg]) AST_EXT_LIB_CHECK([COROSYNC_CFG_STATE_TRACK], [cfg], [corosync_cfg_state_track], [corosync/cfg.h], [-lcfg]) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 51f0f146297..7d2a08c8af0 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -142,6 +142,9 @@ /* Define to 1 if you have the `closefrom' function. */ #undef HAVE_CLOSEFROM +/* Define to 1 if you have the Codec 2 Audio Decoder/Encoder library. */ +#undef HAVE_CODEC2 + /* Define to 1 if you have the Corosync library. */ #undef HAVE_COROSYNC diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h index 3894ad21bcc..6099c59ea97 100644 --- a/include/asterisk/format_cache.h +++ b/include/asterisk/format_cache.h @@ -208,6 +208,11 @@ extern struct ast_format *ast_format_siren7; */ extern struct ast_format *ast_format_opus; +/*! + * \brief Built-in cached Codec 2 format. + */ +extern struct ast_format *ast_format_codec2; + /*! * \brief Built-in cached t140 format. */ diff --git a/main/codec_builtin.c b/main/codec_builtin.c index 50fbf555c03..6fc0fd896c0 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -107,6 +107,30 @@ static struct ast_codec g723 = { .get_length = g723_length, }; +static int codec2_samples(struct ast_frame *frame) +{ + return 160 * (frame->datalen / 6); +} + +static int codec2_length(unsigned int samples) +{ + return (samples / 160) * 6; +} + +static struct ast_codec codec2 = { + .name = "codec2", + .description = "Codec 2", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 20, + .maximum_ms = 300, + .default_ms = 20, + .minimum_bytes = 6, + .samples_count = codec2_samples, + .get_length = codec2_length, + .smooth = 1, +}; + static int none_samples(struct ast_frame *frame) { return frame->datalen; @@ -863,6 +887,7 @@ int ast_codec_builtin_init(void) { int res = 0; + res |= CODEC_REGISTER_AND_CACHE(codec2); res |= CODEC_REGISTER_AND_CACHE(g723); res |= CODEC_REGISTER_AND_CACHE(ulaw); res |= CODEC_REGISTER_AND_CACHE(alaw); diff --git a/main/format_cache.c b/main/format_cache.c index b4d42609251..c704f1c379a 100644 --- a/main/format_cache.c +++ b/main/format_cache.c @@ -217,6 +217,11 @@ struct ast_format *ast_format_siren7; */ struct ast_format *ast_format_opus; +/*! + * \brief Built-in cached codec2 format. + */ +struct ast_format *ast_format_codec2; + /*! * \brief Built-in cached t140 format. */ @@ -328,6 +333,7 @@ static void format_cache_shutdown(void) ao2_replace(ast_format_testlaw, NULL); ao2_replace(ast_format_g719, NULL); ao2_replace(ast_format_opus, NULL); + ao2_replace(ast_format_codec2, NULL); ao2_replace(ast_format_jpeg, NULL); ao2_replace(ast_format_png, NULL); ao2_replace(ast_format_h261, NULL); @@ -360,7 +366,9 @@ int ast_format_cache_init(void) static void set_cached_format(const char *name, struct ast_format *format) { - if (!strcmp(name, "g723")) { + if (!strcmp(name, "codec2")) { + ao2_replace(ast_format_codec2, format); + } else if (!strcmp(name, "g723")) { ao2_replace(ast_format_g723, format); } else if (!strcmp(name, "ulaw")) { ao2_replace(ast_format_ulaw, format); diff --git a/makeopts.in b/makeopts.in index d4347daf1be..f0b0d0ef51d 100644 --- a/makeopts.in +++ b/makeopts.in @@ -126,6 +126,9 @@ BFD_LIB=@BFD_LIB@ BLUETOOTH_INCLUDE=@BLUETOOTH_INCLUDE@ BLUETOOTH_LIB=@BLUETOOTH_LIB@ +CODEC2_INCLUDE=@CODEC2_INCLUDE@ +CODEC2_LIB=@CODEC2_LIB@ + CURL_INCLUDE=@CURL_INCLUDE@ CURL_LIB=@CURL_LIB@ From e40aa40aca1a18538fe08267296ca9a2847ad63a Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 24 Aug 2016 13:42:34 -0600 Subject: [PATCH 0694/1578] res_rtp_multicast: Fix SEGV in ast_multicast_rtp_create_options ast_multicast_rtp_create_options now checks for NULL or empty options Change-Id: Ib845eae46a67a9787e89a87ebd1027344e5e0362 --- res/res_rtp_multicast.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index 5a7b26b6a70..fce49265946 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -143,7 +143,7 @@ struct ast_multicast_rtp_options *ast_multicast_rtp_create_options(const char *t mcast_options = ast_calloc(1, sizeof(*mcast_options) + strlen(type) - + strlen(options) + 2); + + strlen(S_OR(options, "")) + 2); if (!mcast_options) { return NULL; } @@ -155,8 +155,9 @@ struct ast_multicast_rtp_options *ast_multicast_rtp_create_options(const char *t mcast_options->type = pos; pos += strlen(type) + 1; - /* Safe */ - strcpy(pos, options); + if (!ast_strlen_zero(options)) { + strcpy(pos, options); /* Safe */ + } mcast_options->options = pos; if (ast_app_parse_options(multicast_rtp_options, &mcast_options->opts, From d2e03c252d128d43fdbfe5906e238e8e0f90c0ab Mon Sep 17 00:00:00 2001 From: varnav Date: Wed, 24 Aug 2016 12:44:15 +0300 Subject: [PATCH 0695/1578] chan_iax2: Set plaintext auth to deprecated as per ASTERISK-22820 Starting from draft 2 of RFC 5456 (October 23, 2006) plaintext auth is not supported in IAX2 protocol. Please refer to section 8.6.13 of RFC 5456. But plaintext auth is still supported by Asterisk implementation of IAX2. This support should be dropped. Patch, based on asterisk-dev discussion, adds deprecation warning on startup if 'auth' is set to 'plaintext', changes default values of 'auth' from 'md5, plaintext' to 'md5'. Patch is safe in terms of backwards compatibility, will work even if remote peers have auth=plaintext and we have defaults. auth=plaintext setting will remain deprecated in Asterisk 14 and 15, and IAX2 plaintext support will be removed in Asterisk 16. ASTERISK-22820 #close Change-Id: I5d2f3830cb57645604818f87518916e8a5c317bf --- CHANGES | 2 ++ channels/chan_iax2.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 1cfa7eb7c0a..542b814abcb 100644 --- a/CHANGES +++ b/CHANGES @@ -181,6 +181,8 @@ chan_iax2 seconds. Setting this to a higher value may help in lagged networks or those experiencing high packet loss. + * Plaintext auth mode is deprecated and removed from possible default modes. + chan_rtp (was chan_multicast_rtp) ------------------ * Added unicast RTP support and renamed chan_multicast_rtp to chan_rtp. diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 456ba8f1ed1..04cdad1e407 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -7997,7 +7997,7 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i * Set authmethods to the last known authmethod used by the system * Set a fake secret, it's not looked at, just required to attempt authentication. * Set authrej so the AUTHREP is rejected without even looking at its contents */ - iaxs[callno]->authmethods = last_authmethod ? last_authmethod : (IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT); + iaxs[callno]->authmethods = last_authmethod ? last_authmethod : IAX_AUTH_MD5; ast_string_field_set(iaxs[callno], secret, "badsecret"); iaxs[callno]->authrej = 1; if (!ast_strlen_zero(iaxs[callno]->username)) { @@ -9192,7 +9192,7 @@ static int registry_authrequest(int callno) * peer does not exist, and vice-versa. * Therefore, we use whatever the last peer used (which may vary over the * course of a server, which should leak minimal information). */ - sentauthmethod = p ? p->authmethods : last_authmethod ? last_authmethod : (IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT); + sentauthmethod = p ? p->authmethods : last_authmethod ? last_authmethod : IAX_AUTH_MD5; if (!p) { iaxs[callno]->authmethods = sentauthmethod; } @@ -12870,6 +12870,9 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st } } else if (!strcasecmp(v->name, "auth")) { peer->authmethods = get_auth_methods(v->value); + if (peer->authmethods & IAX_AUTH_PLAINTEXT) { + ast_log(LOG_WARNING, "Auth method for peer '%s' is set to deprecated 'plaintext' at line %d of iax.conf\n", peer->name, v->lineno); + } } else if (!strcasecmp(v->name, "encryption")) { peer->encmethods |= get_encrypt_methods(v->value); if (!peer->encmethods) { @@ -13040,7 +13043,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st } } if (!peer->authmethods) - peer->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT; + peer->authmethods = IAX_AUTH_MD5; ast_clear_flag64(peer, IAX_DELME); } @@ -13189,6 +13192,9 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st } } else if (!strcasecmp(v->name, "auth")) { user->authmethods = get_auth_methods(v->value); + if (user->authmethods & IAX_AUTH_PLAINTEXT) { + ast_log(LOG_WARNING, "Auth method for user '%s' is set to deprecated 'plaintext' at line %d of iax.conf\n", user->name, v->lineno); + } } else if (!strcasecmp(v->name, "encryption")) { user->encmethods |= get_encrypt_methods(v->value); if (!user->encmethods) { @@ -13321,13 +13327,13 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st } if (!user->authmethods) { if (!ast_strlen_zero(user->secret)) { - user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT; + user->authmethods = IAX_AUTH_MD5; if (!ast_strlen_zero(user->inkeys)) user->authmethods |= IAX_AUTH_RSA; } else if (!ast_strlen_zero(user->inkeys)) { user->authmethods = IAX_AUTH_RSA; } else { - user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT; + user->authmethods = IAX_AUTH_MD5; } } ast_clear_flag64(user, IAX_DELME); From 93b7533d74cfe30df0cd1dec22aeee3efe72a15b Mon Sep 17 00:00:00 2001 From: chrisderock Date: Wed, 17 Aug 2016 09:51:17 +0200 Subject: [PATCH 0696/1578] app_macro: Consider '~~s~~' as a macro start extension. As described in issue ASTERISK-26282 the AEL parser creates macros with extension '~~s~~'. app_macro searches only for extension 's' so the created extension cannot be found. with this patch app_macro searches for both extensions and performs the right extension. ASTERISK-26282 #close Change-Id: I939aa2a694148cc1054dd75ec0c47c47f47c90fb --- apps/app_macro.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/apps/app_macro.c b/apps/app_macro.c index 26e4262b1b0..61f3ab722ef 100644 --- a/apps/app_macro.c +++ b/apps/app_macro.c @@ -245,7 +245,7 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive int setmacrocontext=0; int autoloopflag, inhangup = 0; struct ast_str *tmp_subst = NULL; - + const char *my_macro_exten = NULL; char *save_macro_exten; char *save_macro_context; char *save_macro_priority; @@ -306,12 +306,32 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive } snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro); - if (!ast_exists_extension(chan, fullmacro, "s", 1, - S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) { - if (!ast_context_find(fullmacro)) - ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n", fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan)); - else - ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro); + + /* first search for the macro */ + if (!ast_context_find(fullmacro)) { + ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n", + fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan)); + return 0; + } + + /* now search for the right extension */ + if (ast_exists_extension(chan, fullmacro, "s", 1, + S_COR(ast_channel_caller(chan)->id.number.valid, + ast_channel_caller(chan)->id.number.str, NULL))) { + /* We have a normal macro */ + my_macro_exten = "s"; + } else if (ast_exists_extension(chan, fullmacro, "~~s~~", 1, + S_COR(ast_channel_caller(chan)->id.number.valid, + ast_channel_caller(chan)->id.number.str, NULL))) { + /* We have an AEL generated macro */ + my_macro_exten = "~~s~~"; + } + + /* do we have a valid exten? */ + if (!my_macro_exten) { + ast_log(LOG_WARNING, + "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", + fullmacro, macro); return 0; } @@ -363,7 +383,7 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive ast_set_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC); /* Setup environment for new run */ - ast_channel_exten_set(chan, "s"); + ast_channel_exten_set(chan, my_macro_exten); ast_channel_context_set(chan, fullmacro); ast_channel_priority_set(chan, 1); From 5744f434f0eaba9633e7574d9cd0f8193dfd67e1 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 22 Aug 2016 15:01:37 -0500 Subject: [PATCH 0697/1578] ast_framehook_attach() must be called with the channel locked. The framehook container could become corrupted if the channel lock is not held before calling. Change-Id: I1a6b957a1f7b899eb29a186915f8cccab886a438 --- main/bridge_basic.c | 2 ++ res/res_pjsip_refer.c | 5 ++++- res/res_pjsip_t38.c | 14 ++++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/main/bridge_basic.c b/main/bridge_basic.c index 8d7fbae7094..6c411fbaf2a 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -3088,7 +3088,9 @@ static int attach_framehook(struct attended_transfer_properties *props, struct a ao2_ref(props, +1); target_interface.data = props; + ast_channel_lock(channel); props->target_framehook_id = ast_framehook_attach(channel, &target_interface); + ast_channel_unlock(channel); if (props->target_framehook_id == -1) { ao2_ref(props, -1); return -1; diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 1043a1e24d8..78d6e23b5c0 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -607,7 +607,10 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann ao2_ref(refer->progress, +1); /* If we can't attach a frame hook for whatever reason send a notification of success immediately */ - if ((refer->progress->framehook = ast_framehook_attach(chan, &hook)) < 0) { + ast_channel_lock(chan); + refer->progress->framehook = ast_framehook_attach(chan, &hook); + ast_channel_unlock(chan); + if (refer->progress->framehook < 0) { struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200, PJSIP_EVSUB_STATE_TERMINATED); diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 76720acee2b..150336a085d 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -501,25 +501,27 @@ static void t38_attach_framehook(struct ast_sip_session *session) return; } - /* Skip attaching the framehook if the T.38 datastore already exists for the channel */ ast_channel_lock(session->channel); - if ((datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore, NULL))) { + + /* Skip attaching the framehook if the T.38 datastore already exists for the channel */ + datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore, + NULL); + if (datastore) { ast_channel_unlock(session->channel); return; } - ast_channel_unlock(session->channel); framehook_id = ast_framehook_attach(session->channel, &hook); if (framehook_id < 0) { - ast_log(LOG_WARNING, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n", + ast_log(LOG_WARNING, "Could not attach T.38 Frame hook, T.38 will be unavailable on '%s'\n", ast_channel_name(session->channel)); + ast_channel_unlock(session->channel); return; } - ast_channel_lock(session->channel); datastore = ast_datastore_alloc(&t38_framehook_datastore, NULL); if (!datastore) { - ast_log(LOG_ERROR, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n", + ast_log(LOG_ERROR, "Could not alloc T.38 Frame hook datastore, T.38 will be unavailable on '%s'\n", ast_channel_name(session->channel)); ast_framehook_detach(session->channel, framehook_id); ast_channel_unlock(session->channel); From b86771d1bf5c1db3561048d5bd5e679a6fb340fc Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 23 Aug 2016 10:42:08 -0500 Subject: [PATCH 0698/1578] ast_framehook_detach() must be called with the channel locked. The framehook container could become corrupted if the channel lock is not held before calling. Change-Id: If0a1c7ba0484ed3a191106a7516526b905952584 --- res/res_fax.c | 4 ++++ res/res_pjsip_refer.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/res/res_fax.c b/res/res_fax.c index c301aff3120..b6fefe2bee2 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -4509,7 +4509,9 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat ast_log(LOG_WARNING, "Attempt to attach a T.38 gateway on channel (%s) with gateway already running.\n", ast_channel_name(chan)); } } else if (ast_false(val)) { + ast_channel_lock(chan); ast_framehook_detach(chan, details->gateway_id); + ast_channel_unlock(chan); details->gateway_id = -1; } else { ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data); @@ -4561,7 +4563,9 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat ast_log(LOG_WARNING, "Attempt to attach a FAX detect on channel (%s) with FAX detect already running.\n", ast_channel_name(chan)); } } else if (ast_false(val)) { + ast_channel_lock(chan); ast_framehook_detach(chan, details->faxdetect_id); + ast_channel_unlock(chan); details->faxdetect_id = -1; } else { ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 78d6e23b5c0..19367bf3261 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -641,7 +641,9 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann refer_progress_notify(notification); } + ast_channel_lock(chan); ast_framehook_detach(chan, refer->progress->framehook); + ast_channel_unlock(chan); ao2_cleanup(refer->progress); } From 141cd42880b374ea03035dd5776f1e4b4fc92fe6 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 23 Aug 2016 11:16:04 -0500 Subject: [PATCH 0699/1578] res_fax.c: Add chan locked precondition comments. Change-Id: Ic10ae434536bbf7fb7055d6ab36cc50b8748a4e7 --- res/res_fax.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/res/res_fax.c b/res/res_fax.c index b6fefe2bee2..94c512de3f0 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -2880,11 +2880,17 @@ static struct fax_gateway *fax_gateway_new(struct ast_channel *chan, struct ast_ return gateway; } -/*! \brief Create a fax session and start T.30<->T.38 gateway mode +/*! + * \brief Create a fax session and start T.30<->T.38 gateway mode + * * \param gateway a fax gateway object * \param details fax session details * \param chan active channel - * \return 0 on error 1 on success*/ + * + * \pre chan is locked on entry + * + * \return 0 on error 1 on success + */ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session_details *details, struct ast_channel *chan) { struct ast_fax_session *s; @@ -2928,6 +2934,7 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session return 0; } +/*! \pre chan is locked on entry */ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_frame *f) { struct ast_frame *fp; @@ -2966,6 +2973,7 @@ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, st return fp; } +/*! \pre chan is locked on entry */ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f) { struct ast_channel *other = (active == chan) ? peer : chan; @@ -3002,12 +3010,17 @@ static int fax_gateway_indicate_t38(struct ast_channel *chan, struct ast_channel } } -/*! \brief T38 Gateway Negotiate t38 parameters +/*! + * \brief T38 Gateway Negotiate t38 parameters + * * \param gateway gateway object * \param chan channel running the gateway * \param peer channel im bridged too * \param active channel the frame originated on * \param f the control frame to process + * + * \pre chan is locked on entry + * * \return processed control frame or null frame */ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f) @@ -3250,7 +3263,8 @@ static void fax_gateway_framehook_destroy(void *data) ao2_ref(gateway, -1); } -/*! \brief T.30<->T.38 gateway framehook. +/*! + * \brief T.30<->T.38 gateway framehook. * * Intercept packets on bridged channels and determine if a T.38 gateway is * required. If a gateway is required, start a gateway and handle T.38 @@ -3261,6 +3275,8 @@ static void fax_gateway_framehook_destroy(void *data) * \param event framehook event * \param data framehook data (struct fax_gateway *) * + * \pre chan is locked on entry + * * \return processed frame or NULL when f is NULL or a null frame */ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) @@ -3491,9 +3507,9 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d .disable_inheritance = 1, /* Masquerade inheritance is handled through the datastore fixup */ }; - if (global_fax_debug) { - details->option.debug = AST_FAX_OPTFLAG_TRUE; - } + if (global_fax_debug) { + details->option.debug = AST_FAX_OPTFLAG_TRUE; + } ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "gateway operation started successfully"); From edca14c8a50e940e8d3be470d136cafa406dd596 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 22 Aug 2016 12:31:24 -0500 Subject: [PATCH 0700/1578] res_fax.c: Fix deadlock in fax_gateway_indicate_t38(). fax_gateway_indicate_t38() calls ast_indicate_data() which cannot be called with any channel locks already held. A deadlock can happen if the function is operating on a local channel. * Made fax_gateway_indicate_t38() unlock the channel before calling ast_indicate_data() since fax_gateway_indicate_t38() is always called with the channel locked. * Made fax_gateway_indicate_t38() return void since nothing cared about its return value. ASTERISK-26203 Reported by: Etienne Lessard ASTERISK-24822 Reported by: David Brillert ASTERISK-22732 Reported by: Richard Mudgett Change-Id: I701ff2d26c5fc23e0d5a48a3fd98759a9fd09407 --- res/res_fax.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/res/res_fax.c b/res/res_fax.c index 94c512de3f0..5bbc896c846 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -3001,12 +3001,15 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str return f; } -static int fax_gateway_indicate_t38(struct ast_channel *chan, struct ast_channel *active, struct ast_control_t38_parameters *control_params) +/*! \pre chan is locked on entry */ +static void fax_gateway_indicate_t38(struct ast_channel *chan, struct ast_channel *active, struct ast_control_t38_parameters *control_params) { if (active == chan) { - return ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); + ast_channel_unlock(chan); + ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); + ast_channel_lock(chan); } else { - return ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); + ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); } } From 277a2d667a51b4f683392304f0d1be47b53b1db2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 23 Aug 2016 10:39:01 -0500 Subject: [PATCH 0701/1578] res_fax: Fix deadlock setting FAXMODE channel variable. ASTERISK-25980 added the FAXMODE channel variable to res_fax.c. Unfortunately, it also introduced a deadlock potential because set_channel_variables() which sets FAXMODE can be called during a masquerade. The ast_channel_get_t38_state() which gets the value used to set FAXMODE cannot be called with the channel locked. As a result, local channels can deadlock because of how they must acquire the locks necessary to operate. The intent of FAXMODE is for dialplan to know how a fax was transferred after the fax completes. However, the previous patch sets FAXMODE to the channel's current T.38 state AFTER the fax has completed and where T.38 may have already disconnected. * Set FAXMODE based upon T.38 negotiations exchanged either with the fax applications or the fax framehooks. ASTERISK-26203 Reported by: Etienne Lessard ASTERISK-24822 Reported by: David Brillert ASTERISK-22732 Reported by: Richard Mudgett Change-Id: Id525747254b64c1efe8b1b5973d52ff9719c2ae1 --- include/asterisk/res_fax.h | 22 ++++++++++++---------- res/res_fax.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/include/asterisk/res_fax.h b/include/asterisk/res_fax.h index 5119bfa6c48..e88d8002f01 100644 --- a/include/asterisk/res_fax.h +++ b/include/asterisk/res_fax.h @@ -20,16 +20,16 @@ #ifndef _ASTERISK_RES_FAX_H #define _ASTERISK_RES_FAX_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "asterisk.h" +#include "asterisk/lock.h" +#include "asterisk/linkedlists.h" +#include "asterisk/module.h" +#include "asterisk/utils.h" +#include "asterisk/options.h" +#include "asterisk/frame.h" +#include "asterisk/cli.h" +#include "asterisk/stringfields.h" +#include "asterisk/manager.h" /*! \brief capabilities for res_fax to locate a fax technology module */ enum ast_fax_capabilities { @@ -187,6 +187,8 @@ struct ast_fax_session_details { int faxdetect_timeout; /*! flags used for fax detection */ int faxdetect_flags; + /*! Non-zero if T.38 is negotiated */ + int is_t38_negotiated; }; struct ast_fax_tech; diff --git a/res/res_fax.c b/res/res_fax.c index 5bbc896c846..a369d688b8f 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -641,6 +641,7 @@ static void fixup_callback(void *data, struct ast_channel *old_chan, struct ast_ struct ast_fax_session_details *new_details = find_or_create_details(new_chan); ast_framehook_detach(old_chan, old_details->gateway_id); + new_details->is_t38_negotiated = old_details->is_t38_negotiated; fax_gateway_attach(new_chan, new_details); ao2_cleanup(new_details); } @@ -1439,6 +1440,7 @@ static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_de static void set_channel_variables(struct ast_channel *chan, struct ast_fax_session_details *details) { char buf[10]; + pbx_builtin_setvar_helper(chan, "FAXSTATUS", S_OR(details->result, NULL)); pbx_builtin_setvar_helper(chan, "FAXERROR", S_OR(details->error, NULL)); pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", S_OR(details->resultstr, NULL)); @@ -1447,7 +1449,7 @@ static void set_channel_variables(struct ast_channel *chan, struct ast_fax_sessi pbx_builtin_setvar_helper(chan, "FAXBITRATE", S_OR(details->transfer_rate, NULL)); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", S_OR(details->resolution, NULL)); - if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) { + if (details->is_t38_negotiated) { pbx_builtin_setvar_helper(chan, "FAXMODE", "T38"); } else { pbx_builtin_setvar_helper(chan, "FAXMODE", "audio"); @@ -1656,6 +1658,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det ast_string_field_set(details, result, ""); ast_string_field_set(details, resultstr, ""); ast_string_field_set(details, error, ""); + details->is_t38_negotiated = t38negotiated; set_channel_variables(chan, details); if (fax->tech->start_session(fax) < 0) { @@ -1706,12 +1709,18 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det * do T.38 as well */ t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters); - t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED; + if (details->caps & AST_FAX_TECH_T38) { + details->is_t38_negotiated = 1; + t38_parameters.request_response = AST_T38_NEGOTIATED; + } else { + t38_parameters.request_response = AST_T38_REFUSED; + } ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)); break; case AST_T38_NEGOTIATED: t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters); t38negotiated = 1; + details->is_t38_negotiated = 1; break; default: break; @@ -2902,6 +2911,7 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error starting gateway session"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); report_fax_status(chan, details, "No Available Resource"); ast_log(LOG_ERROR, "Can't create a FAX session, gateway attempt failed.\n"); @@ -2922,6 +2932,7 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error starting gateway session"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return -1; } @@ -2967,6 +2978,7 @@ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, st gateway->t38_state = T38_STATE_NEGOTIATING; gateway->timeout_start = ast_tvnow(); + details->is_t38_negotiated = 0; details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ast_debug(1, "requesting T.38 for gateway session for %s\n", ast_channel_name(chan)); @@ -3064,6 +3076,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params); gateway->t38_state = T38_STATE_UNKNOWN; gateway->timeout_start = ast_tvnow(); + details->is_t38_negotiated = 0; details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ao2_ref(details, -1); return f; @@ -3079,12 +3092,14 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str if (fax_gateway_start(gateway, details, chan)) { ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(active), ast_channel_name(other)); gateway->t38_state = T38_STATE_REJECTED; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_REFUSED; ast_framehook_detach(chan, details->gateway_id); details->gateway_id = -1; } else { gateway->t38_state = T38_STATE_NEGOTIATED; + details->is_t38_negotiated = chan == active; control_params->request_response = AST_T38_NEGOTIATED; report_fax_status(chan, details, "T.38 Negotiated"); } @@ -3102,6 +3117,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params); gateway->t38_state = T38_STATE_UNKNOWN; gateway->timeout_start = ast_tvnow(); + details->is_t38_negotiated = 0; details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ast_debug(1, "%s is attempting to negotiate T.38 after we already sent a negotiation request based on v21 preamble detection\n", ast_channel_name(active)); @@ -3124,6 +3140,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "no gateway necessary"); ast_string_field_set(details, error, "NATIVE_T38"); + details->is_t38_negotiated = 1; set_channel_variables(chan, details); ast_debug(1, "%s is attempting to negotiate T.38 after we already negotiated T.38 with %s, disabling the gateway\n", ast_channel_name(active), ast_channel_name(other)); @@ -3138,6 +3155,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str && control_params->request_response == AST_T38_REFUSED) { ast_debug(1, "unable to negotiate T.38 on %s for fax gateway\n", ast_channel_name(active)); + details->is_t38_negotiated = 0; /* our request to negotiate T.38 was refused, if the other * channel supports T.38, they might still reinvite and save @@ -3166,11 +3184,13 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str if (fax_gateway_start(gateway, details, chan)) { ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(active), ast_channel_name(other)); gateway->t38_state = T38_STATE_NEGOTIATING; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_REQUEST_TERMINATE; fax_gateway_indicate_t38(chan, active, control_params); } else { gateway->t38_state = T38_STATE_NEGOTIATED; + details->is_t38_negotiated = chan == active; report_fax_status(chan, details, "T.38 Negotiated"); } @@ -3186,14 +3206,16 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str t38_parameters_fax_to_ast(control_params, &details->our_t38_parameters); if (fax_gateway_start(gateway, details, chan)) { - ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(active), ast_channel_name(other)); + ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(other), ast_channel_name(active)); gateway->t38_state = T38_STATE_REJECTED; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_REFUSED; ast_framehook_detach(chan, details->gateway_id); details->gateway_id = -1; } else { gateway->t38_state = T38_STATE_NEGOTIATED; + details->is_t38_negotiated = chan == other; control_params->request_response = AST_T38_NEGOTIATED; } @@ -3209,6 +3231,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str details->gateway_id = -1; gateway->t38_state = T38_STATE_REJECTED; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_TERMINATED; fax_gateway_indicate_t38(chan, active, control_params); @@ -3224,6 +3247,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "no gateway necessary"); ast_string_field_set(details, error, "NATIVE_T38"); + details->is_t38_negotiated = 1; set_channel_variables(chan, details); ao2_ref(details, -1); @@ -3351,6 +3375,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "neither channel supports T.38"); ast_string_field_set(details, error, "T38_NEG_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return f; } @@ -3395,6 +3420,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_string_field_set(details, result, "FAILED"); ast_string_field_build(details, resultstr, "no fax activity after %d ms", details->gateway_timeout); ast_string_field_set(details, error, "TIMEOUT"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return f; } @@ -3525,6 +3551,7 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error initializing gateway session"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); report_fax_status(chan, details, "No Available Resource"); return -1; @@ -3540,6 +3567,7 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error attaching gateway to channel"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return -1; } From 5eb6cb969f440200835a6e818a4f69f7a77f280f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 23 Aug 2016 11:02:35 -0500 Subject: [PATCH 0702/1578] res_fax: Fix deadlock in ast_channel_get_t38_state(). ast_channel_get_t38_state() calls ast_channel_queryoption() with AST_OPTION_T38_STATE. If the passed in channel is a local channel then a deadlock can happen if a channel lock is held when called. * Made ast_channel_get_t38_state() callers not hold a channel lock before calling. * Update ast_channel_get_t38_state() doxygen to note that no channel locks can be held when calling the function. ASTERISK-26203 #close Reported by: Etienne Lessard ASTERISK-24822 #close Reported by: David Brillert ASTERISK-22732 #close Reported by: Richard Mudgett Change-Id: I49fd76fa9af628b4198009b5c0b82c8b03681214 --- include/asterisk/channel.h | 6 +++++- res/res_fax.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 14bd32c0793..3293dd77b99 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -2549,7 +2549,11 @@ static inline int ast_fdisset(struct pollfd *pfds, int fd, int maximum, int *sta return 0; } -/*! \brief Retrieves the current T38 state of a channel */ +/*! + * \brief Retrieves the current T38 state of a channel + * + * \note Absolutely _NO_ channel locks should be held before calling this function. + */ static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan) { enum ast_t38_state state = T38_STATE_UNAVAILABLE; diff --git a/res/res_fax.c b/res/res_fax.c index a369d688b8f..a2e1793239a 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -3001,8 +3001,14 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str } if (gateway->detected_v21) { + enum ast_t38_state state_other; + destroy_v21_sessions(gateway); - if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) { + + ast_channel_unlock(chan); + state_other = ast_channel_get_t38_state(other); + ast_channel_lock(chan); + if (state_other == T38_STATE_UNKNOWN) { ast_debug(1, "detected v21 preamble from %s\n", ast_channel_name(active)); return fax_gateway_request_t38(gateway, chan, f); } else { @@ -3043,6 +3049,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str struct ast_control_t38_parameters *control_params = f->data.ptr; struct ast_channel *other = (active == chan) ? peer : chan; struct ast_fax_session_details *details; + enum ast_t38_state state_other; if (f->datalen != sizeof(struct ast_control_t38_parameters)) { /* invalaid AST_CONTROL_T38_PARAMETERS frame, we can't @@ -3065,9 +3072,11 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str } if (control_params->request_response == AST_T38_REQUEST_NEGOTIATE) { - enum ast_t38_state state = ast_channel_get_t38_state(other); + ast_channel_unlock(chan); + state_other = ast_channel_get_t38_state(other); + ast_channel_lock(chan); - if (state == T38_STATE_UNKNOWN) { + if (state_other == T38_STATE_UNKNOWN) { /* we detected a request to negotiate T.38 and the * other channel appears to support T.38, we'll pass * the request through and only step in if the other @@ -3080,7 +3089,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ao2_ref(details, -1); return f; - } else if (state == T38_STATE_UNAVAILABLE || state == T38_STATE_REJECTED) { + } else if (state_other == T38_STATE_UNAVAILABLE || state_other == T38_STATE_REJECTED) { /* the other channel does not support T.38, we need to * step in here */ ast_debug(1, "%s is attempting to negotiate T.38 but %s does not support it\n", ast_channel_name(active), ast_channel_name(other)); @@ -3160,7 +3169,10 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str /* our request to negotiate T.38 was refused, if the other * channel supports T.38, they might still reinvite and save * the day. Otherwise disable the gateway. */ - if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) { + ast_channel_unlock(chan); + state_other = ast_channel_get_t38_state(other); + ast_channel_lock(chan); + if (state_other == T38_STATE_UNKNOWN) { gateway->t38_state = T38_STATE_UNAVAILABLE; } else { ast_framehook_detach(chan, details->gateway_id); @@ -3366,8 +3378,16 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct } if (!gateway->bridged) { + enum ast_t38_state state_chan; + enum ast_t38_state state_peer; + + ast_channel_unlock(chan); + state_chan = ast_channel_get_t38_state(chan); + state_peer = ast_channel_get_t38_state(peer); + ast_channel_lock(chan); + /* don't start a gateway if neither channel can handle T.38 */ - if (ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE && ast_channel_get_t38_state(peer) == T38_STATE_UNAVAILABLE) { + if (state_chan == T38_STATE_UNAVAILABLE && state_peer == T38_STATE_UNAVAILABLE) { ast_debug(1, "not starting gateway for %s and %s; neither channel supports T.38\n", ast_channel_name(chan), ast_channel_name(peer)); ast_framehook_detach(chan, gateway->framehook); details->gateway_id = -1; From ea929d766d4d9d192870760cc4b086d7ddc60fe5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 4 Aug 2016 20:11:29 -0500 Subject: [PATCH 0703/1578] res_pjsip: Cache global config options. We may check a global config option hundreds of times a second or more. Asking sorcery for the global configuration from the config files backend involves several allocations and container traversals. Using realtime without a memory cache is a lot worse because you have to lookup in the realtime database each time to reconstitute the sorcery object. With a memory cache for realtime, there is about the same amount of overhead as for config files. Either way, it is still fairly expensive to access the sorcery object that much. * Cache the global config options so we can access them faster. You must now always perform a res_pjsip reload to change the global options. Change-Id: Ice16c7a4cbca4614da344aaea21a072b86263ef7 --- CHANGES | 6 ++++++ res/res_pjsip/config_global.c | 26 ++++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/CHANGES b/CHANGES index 542b814abcb..5857165c8d7 100644 --- a/CHANGES +++ b/CHANGES @@ -48,6 +48,12 @@ res_pjsip when set will override the default user set on Contact headers in outgoing requests. + * If you are using a sorcery realtime backend to store global res_pjsip + options (ps_globals table) then you now have to do a res_pjsip reload for + changes to these options to take effect. If you are using pjsip.conf to + configure these options then you already had to do a reload after making + changes. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index 975c5eefe7a..1d0c11c35c0 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -48,6 +48,15 @@ #define DEFAULT_MWI_TPS_QUEUE_LOW -1 #define DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED 0 +/*! + * \brief Cached global config object + * + * \details + * Cached so we don't have to keep asking sorcery for the config. + * We could ask for it hundreds of times a second if not more. + */ +static AO2_GLOBAL_OBJ_STATIC(global_cfg); + static char default_useragent[256]; struct global_config { @@ -135,23 +144,14 @@ static int global_apply(const struct ast_sorcery *sorcery, void *obj) ast_sip_add_global_request_header("Max-Forwards", max_forwards, 1); ast_sip_add_global_request_header("User-Agent", cfg->useragent, 1); ast_sip_add_global_response_header("Server", cfg->useragent, 1); + + ao2_t_global_obj_replace_unref(global_cfg, cfg, "Applying global settings"); return 0; } static struct global_config *get_global_cfg(void) { - struct global_config *cfg; - struct ao2_container *globals; - - globals = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "global", - AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); - if (!globals) { - return NULL; - } - - cfg = ao2_find(globals, NULL, 0); - ao2_ref(globals, -1); - return cfg; + return ao2_global_obj_ref(global_cfg); } char *ast_sip_global_default_outbound_endpoint(void) @@ -462,6 +462,8 @@ int ast_sip_destroy_sorcery_global(void) ast_sorcery_instance_observer_remove(sorcery, &observer_callbacks_global); + ao2_t_global_obj_release(global_cfg, "Module is unloading"); + return 0; } From f35501b8c95f6b09c11dc501f0acce1677172d38 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Sat, 20 Aug 2016 16:04:13 +0200 Subject: [PATCH 0704/1578] sip_to_pjsip: Migrate IPv4/IPv6 (Dual Stack) configurations. When using the migration script sip_to_pjsip.py, and your sip.conf is configured with bindaddr=::, two transports are written to pjsip.conf, one for 0.0.0.0 (IPv4) and one for [::] (IPv6). That way, PJProject listens on the IPv4 and IPv6 wildcards; a IPv4/IPv6 Dual Stack configuration on a single interface like in chan_sip. Furthermore, the script internal functions "build_host" and "split_hostport" did not parse Literal IPv6 addresses as expected (like [::1]:5060). This change makes sure, even such addresses are parsed correctly. ASTERISK-26309 Change-Id: Ia4799a0f80fc30c0550fc373efc207c3330aeb48 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 377 +++++++++---------- 1 file changed, 180 insertions(+), 197 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index ee01edfa2b2..1a0d6a48068 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -1,10 +1,11 @@ #!/usr/bin/python import optparse +import socket +import urlparse # Python 2.7 required for Literal IPv6 Addresses + import astdicts import astconfigparser -import socket -import re PREFIX = 'pjsip_' @@ -213,37 +214,42 @@ def from_progressinband(key, val, section, pjsip, nmapped): set_value('inband_progress', val, section, pjsip, nmapped) -def build_host(config, host, section, port_key): +def build_host(config, host, section='general', port_key=None): """ Returns a string composed of a host:port. This assumes that the host - may have a port as part of the initial value. The port_key is only used - if the host does not already have a port set on it. - Throws a LookupError if the key does not exist + may have a port as part of the initial value. The port_key overrides + a port in host, see parameter 'bindport' in chan_sip. """ - port = None - try: socket.inet_pton(socket.AF_INET6, host) if not host.startswith('['): # SIP URI will need brackets. host = '[' + host + ']' - else: - # If brackets are present, there may be a port as well - port = re.match('\[.*\]:(\d+)', host) except socket.error: - # No biggie. It's just not an IPv6 address - port = re.match('.*:(\d+)', host) + pass - result = host + # Literal IPv6 (like [::]), IPv4, or hostname + # does not work for IPv6 without brackets; case catched above + url = urlparse.urlparse('sip://' + host) - if not port: + if port_key: try: port = config.get(section, port_key)[0] - result += ':' + port + host = url.hostname # no port, but perhaps no brackets + try: + socket.inet_pton(socket.AF_INET6, host) + if not host.startswith('['): + # SIP URI will need brackets. + host = '[' + host + ']' + except socket.error: + pass + return host + ':' + port except LookupError: pass - return result + # Returns host:port, in brackets if required + # TODO Does not compress IPv6, for example 0:0:0:0:0:0:0:0 should get [::] + return url.netloc def from_host(key, val, section, pjsip, nmapped): @@ -506,17 +512,59 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ] -def set_transport_common(section, pjsip, nmapped): +def split_hostport(addr): + """ + Given an address in the form 'host:port' separate the host and port + components. + Returns a two-tuple of strings, (host, port). If no port is present in the + string, then the port section of the tuple is None. + """ + try: + socket.inet_pton(socket.AF_INET6, addr) + if not addr.startswith('['): + return (addr, None) + except socket.error: + pass + + # Literal IPv6 (like [::]), IPv4, or hostname + # does not work for IPv6 without brackets; case catched above + url = urlparse.urlparse('sip://' + addr) + # TODO Does not compress IPv6, for example 0:0:0:0:0:0:0:0 should get [::] + return (url.hostname, url.port) + + +def set_transport_common(section, sip, pjsip, protocol, nmapped): """ sip.conf has several global settings that in pjsip.conf apply to individual transports. This function adds these global settings to each individual transport. The settings included are: + externaddr (or externip) + externhost + externtcpport for TCP + externtlsport for TLS localnet tos_sip cos_sip """ + try: + extern_addr = sip.multi_get('general', ['externaddr', 'externip', + 'externhost'])[0] + host, port = split_hostport(extern_addr) + try: + port = sip.get('general', 'extern' + protocol + 'port')[0] + except LookupError: + pass + set_value('external_media_address', host, section, pjsip, + nmapped, 'transport') + set_value('external_signaling_address', host, section, pjsip, + nmapped, 'transport') + if port: + set_value('external_signaling_port', port, section, pjsip, + nmapped, 'transport') + except LookupError: + pass try: merge_value('localnet', sip.get('general', 'localnet')[0], 'general', @@ -538,34 +586,69 @@ def set_transport_common(section, pjsip, nmapped): pass -def split_hostport(addr): +def get_bind(sip, pjsip, protocol): """ - Given an address in the form 'addr:port' separate the addr and port - components. - Returns a two-tuple of strings, (addr, port). If no port is present in the - string, then the port section of the tuple is None. + Given the protocol (udp, tcp, or tls), return + - the bind address, like [::] or 0.0.0.0 + - name of the section to be created """ + section = 'transport-' + protocol + + # UDP cannot be disabled in chan_sip + if protocol != 'udp': + try: + enabled = sip.get('general', protocol + 'enable')[0] + except LookupError: + # No value means disabled by default. Don't create this transport + return (None, section) + if enabled != 'yes': + return (None, section) + try: - socket.inet_pton(socket.AF_INET6, addr) - if not addr.startswith('['): - return (addr, None) - else: - # If brackets are present, there may be a port as well - match = re.match('\[(.*\)]:(\d+)', addr) - if match: - return (match.group(1), match.group(2)) - else: - return (addr, None) - except socket.error: + bind = pjsip.get(section, 'bind')[0] + # The first run created an transport already but this + # server was not configured for IPv4/IPv6 Dual Stack + return (None, section) + except LookupError: pass - # IPv4 address or hostname - host, sep, port = addr.rpartition(':') - - if not sep and not port: - return (host, None) + try: + bind = pjsip.get(section + '6', 'bind')[0] + # The first run created an IPv6 transport, because + # the server was configured with :: as bindaddr. + # Now, re-use its port and create the IPv4 transport + host, port = split_hostport(bind) + bind = '0.0.0.0' + if port: + bind += ':' + str(port) + except LookupError: + # This is the first run, no transport in pjsip exists. + try: + bind = sip.get('general', protocol + 'bindaddr')[0] + except LookupError: + if protocol == 'udp': + try: + bind = sip.get('general', 'bindaddr')[0] + except LookupError: + bind = '0.0.0.0' + else: + try: + bind = pjsip.get('transport-udp6', 'bind')[0] + except LookupError: + bind = pjsip.get('transport-udp', 'bind')[0] + # Only TCP reuses host:port of UDP, others reuse just host + if protocol == 'tls': + bind, port = split_hostport(bind) + host, port = split_hostport(bind) + if host == '::': + section += '6' + + if protocol == 'udp': + host = build_host(sip, bind, 'general', 'bindport') else: - return (host, port) + host = build_host(sip, bind) + + return (host, section) def create_udp(sip, pjsip, nmapped): @@ -575,34 +658,13 @@ def create_udp(sip, pjsip, nmapped): bindaddr (or udpbindaddr) bindport - externaddr (or externip) - externhost """ + protocol = 'udp' + bind, section = get_bind(sip, pjsip, protocol) - try: - bind = sip.multi_get('general', ['udpbindaddr', 'bindaddr'])[0] - except LookupError: - bind = '' - - bind = build_host(sip, bind, 'general', 'bindport') - - try: - extern_addr = sip.multi_get('general', ['externaddr', 'externip', - 'externhost'])[0] - host, port = split_hostport(extern_addr) - set_value('external_media_address', host, 'transport-udp', pjsip, - nmapped, 'transport') - set_value('external_signaling_address', host, 'transport-udp', pjsip, - nmapped, 'transport') - if port: - set_value('external_signaling_port', port, 'transport-udp', pjsip, - nmapped, 'transport') - except LookupError: - pass - - set_value('protocol', 'udp', 'transport-udp', pjsip, nmapped, 'transport') - set_value('bind', bind, 'transport-udp', pjsip, nmapped, 'transport') - set_transport_common('transport-udp', pjsip, nmapped) + set_value('protocol', protocol, section, pjsip, nmapped, 'transport') + set_value('bind', bind, section, pjsip, nmapped, 'transport') + set_transport_common(section, sip, pjsip, protocol, nmapped) def create_tcp(sip, pjsip, nmapped): @@ -611,131 +673,61 @@ def create_tcp(sip, pjsip, nmapped): on the following settings from sip.conf: tcpenable - tcpbindaddr - externtcpport + tcpbindaddr (or bindaddr) """ - - try: - enabled = sip.get('general', 'tcpenable')[0] - except: - # No value means disabled by default. No need for a tranport - return - - if enabled == 'no': + protocol = 'tcp' + bind, section = get_bind(sip, pjsip, protocol) + if not bind: return - try: - bind = sip.get('general', 'tcpbindaddr')[0] - bind = build_host(sip, bind, 'general', 'bindport') - except LookupError: - # No tcpbindaddr means to default to the udpbindaddr - bind = pjsip.get('transport-udp', 'bind')[0] - - try: - extern_addr = sip.multi_get('general', ['externaddr', 'externip', - 'externhost'])[0] - host, port = split_hostport(extern_addr) - try: - tcpport = sip.get('general', 'externtcpport')[0] - except: - tcpport = port - set_value('external_media_address', host, 'transport-tcp', pjsip, - nmapped, 'transport') - set_value('external_signaling_address', host, 'transport-tcp', pjsip, - nmapped, 'transport') - if tcpport: - set_value('external_signaling_port', tcpport, 'transport-tcp', - pjsip, nmapped, 'transport') - except LookupError: - pass - - set_value('protocol', 'tcp', 'transport-tcp', pjsip, nmapped, 'transport') - set_value('bind', bind, 'transport-tcp', pjsip, nmapped, 'transport') - set_transport_common('transport-tcp', pjsip, nmapped) - - -def set_tls_bindaddr(val, pjsip, nmapped): - """ - Creates the TCP bind address. This has two possible methods of - working: - Use the 'tlsbindaddr' option from sip.conf directly if it has both - an address and port. If no port is present, use 5061 - If there is no 'tlsbindaddr' option present in sip.conf, use the - previously-established UDP bind address and port 5061 - """ - try: - bind = sip.get('general', 'tlsbindaddr')[0] - explicit = True - except LookupError: - # No tlsbindaddr means to default to the bindaddr but with standard TLS - # port - bind = pjsip.get('transport-udp', 'bind')[0] - explicit = False - - matchv4 = re.match('\d+\.\d+\.\d+\.\d+:\d+', bind) - matchv6 = re.match('\[.*\]:d+', bind) - if matchv4 or matchv6: - if explicit: - # They provided a port. We'll just use it. - set_value('bind', bind, 'transport-tls', pjsip, nmapped, - 'transport') - return - else: - # Need to strip the port from the UDP address - index = bind.rfind(':') - bind = bind[:index] - - # Reaching this point means either there was no port provided or we - # stripped the port off. We need to add on the default 5061 port - - bind += ':5061' + set_value('protocol', protocol, section, pjsip, nmapped, 'transport') + set_value('bind', bind, section, pjsip, nmapped, 'transport') + set_transport_common(section, sip, pjsip, protocol, nmapped) - set_value('bind', bind, 'transport-tls', pjsip, nmapped, 'transport') - -def set_tls_cert_file(val, pjsip, nmapped): +def set_tls_cert_file(val, pjsip, section, nmapped): """Sets cert_file based on sip.conf tlscertfile""" - set_value('cert_file', val, 'transport-tls', pjsip, nmapped, + set_value('cert_file', val, section, pjsip, nmapped, 'transport') -def set_tls_private_key(val, pjsip, nmapped): +def set_tls_private_key(val, pjsip, section, nmapped): """Sets privkey_file based on sip.conf tlsprivatekey or sslprivatekey""" - set_value('priv_key_file', val, 'transport-tls', pjsip, nmapped, + set_value('priv_key_file', val, section, pjsip, nmapped, 'transport') -def set_tls_cipher(val, pjsip, nmapped): +def set_tls_cipher(val, pjsip, section, nmapped): """Sets cipher based on sip.conf tlscipher or sslcipher""" - set_value('cipher', val, 'transport-tls', pjsip, nmapped, 'transport') + set_value('cipher', val, section, pjsip, nmapped, 'transport') -def set_tls_cafile(val, pjsip, nmapped): +def set_tls_cafile(val, pjsip, section, nmapped): """Sets ca_list_file based on sip.conf tlscafile""" - set_value('ca_list_file', val, 'transport-tls', pjsip, nmapped, + set_value('ca_list_file', val, section, pjsip, nmapped, 'transport') -def set_tls_capath(val, pjsip, nmapped): +def set_tls_capath(val, pjsip, section, nmapped): """Sets ca_list_path based on sip.conf tlscapath""" - set_value('ca_list_path', val, 'transport-tls', pjsip, nmapped, + set_value('ca_list_path', val, section, pjsip, nmapped, 'transport') -def set_tls_verifyclient(val, pjsip, nmapped): +def set_tls_verifyclient(val, pjsip, section, nmapped): """Sets verify_client based on sip.conf tlsverifyclient""" - set_value('verify_client', val, 'transport-tls', pjsip, nmapped, + set_value('verify_client', val, section, pjsip, nmapped, 'transport') -def set_tls_verifyserver(val, pjsip, nmapped): +def set_tls_verifyserver(val, pjsip, section, nmapped): """Sets verify_server based on sip.conf tlsdontverifyserver""" if val == 'no': - set_value('verify_server', 'yes', 'transport-tls', pjsip, nmapped, + set_value('verify_server', 'yes', section, pjsip, nmapped, 'transport') else: - set_value('verify_server', 'no', 'transport-tls', pjsip, nmapped, + set_value('verify_server', 'no', section, pjsip, nmapped, 'transport') @@ -745,7 +737,7 @@ def create_tls(sip, pjsip, nmapped): settings from sip.conf: tlsenable (or sslenable) - tlsbindaddr (or sslbindaddr) + tlsbindaddr (or sslbindaddr or bindaddr) tlsprivatekey (or sslprivatekey) tlscipher (or sslcipher) tlscafile @@ -755,9 +747,16 @@ def create_tls(sip, pjsip, nmapped): tlsdontverifyserver tlsclientmethod (or sslclientmethod) """ + protocol = 'tls' + bind, section = get_bind(sip, pjsip, protocol) + if not bind: + return + + set_value('protocol', protocol, section, pjsip, nmapped, 'transport') + set_value('bind', bind, section, pjsip, nmapped, 'transport') + set_transport_common(section, sip, pjsip, protocol, nmapped) tls_map = [ - (['tlsbindaddr', 'sslbindaddr'], set_tls_bindaddr), (['tlscertfile', 'sslcert', 'tlscert'], set_tls_cert_file), (['tlsprivatekey', 'sslprivatekey'], set_tls_private_key), (['tlscipher', 'sslcipher'], set_tls_cipher), @@ -767,26 +766,21 @@ def create_tls(sip, pjsip, nmapped): (['tlsdontverifyserver'], set_tls_verifyserver) ] - try: - enabled = sip.multi_get('general', ['tlsenable', 'sslenable'])[0] - except LookupError: - # Not enabled. Don't create a transport - return - - if enabled == 'no': - return - - set_value('protocol', 'tls', 'transport-tls', pjsip, nmapped, 'transport') - for i in tls_map: try: - i[1](sip.multi_get('general', i[0])[0], pjsip, nmapped) + i[1](sip.multi_get('general', i[0])[0], pjsip, section, nmapped) except LookupError: pass try: - method = sip.multi_get('general', ['tlsclientmethod', 'sslclientmethod'])[0] - print 'In chan_sip, you specified the TLS version. With chan_sip, this was just for outbound client connections. In chan_pjsip, this value is for client and server. Instead, consider not to specify \'tlsclientmethod\' for chan_sip and \'method = sslv23\' for chan_pjsip.' + method = sip.multi_get('general', ['tlsclientmethod', + 'sslclientmethod'])[0] + if section != 'transport-' + protocol + '6': # print only once + print 'In chan_sip, you specified the TLS version. With chan_sip,' \ + ' this was just for outbound client connections. In' \ + ' chan_pjsip, this value is for client and server. Instead,' \ + ' consider not to specify \'tlsclientmethod\' for chan_sip' \ + ' and \'method = sslv23\' for chan_pjsip.' except LookupError: """ OpenSSL emerged during the 90s. SSLv2 and SSLv3 were the only @@ -799,26 +793,7 @@ def create_tls(sip, pjsip, nmapped): 'sslv23' as default when unspecified, which gives TLSv1.0 and v1.2. """ method = 'sslv23' - set_value('method', method, 'transport-tls', pjsip, nmapped, 'transport') - - set_transport_common('transport-tls', pjsip, nmapped) - try: - extern_addr = sip.multi_get('general', ['externaddr', 'externip', - 'externhost'])[0] - host, port = split_hostport(extern_addr) - try: - tlsport = sip.get('general', 'externtlsport')[0] - except: - tlsport = port - set_value('external_media_address', host, 'transport-tls', pjsip, - nmapped, 'transport') - set_value('external_signaling_address', host, 'transport-tls', pjsip, - nmapped, 'transport') - if tlsport: - set_value('external_signaling_port', tlsport, 'transport-tls', - pjsip, nmapped, 'transport') - except LookupError: - pass + set_value('method', method, section, pjsip, nmapped, 'transport') def map_transports(sip, pjsip, nmapped): @@ -828,23 +803,29 @@ def map_transports(sip, pjsip, nmapped): configuration sections in pjsip.conf. sip.conf only allows a single UDP transport, TCP transport, - and TLS transport. As such, the mapping into PJSIP can be made - consistent by defining three sections: + and TLS transport for each IP version. As such, the mapping + into PJSIP can be made consistent by defining six sections: + transport-udp6 transport-udp + transport-tcp6 transport-tcp + transport-tls6 transport-tls To accommodate the default behaviors in sip.conf, we'll need to - create the UDP transport first, followed by the TCP and TLS transports. + create the UDP transports first, followed by the TCP and TLS transports. """ # First create a UDP transport. Even if no bind parameters were provided # in sip.conf, chan_sip would always bind to UDP 0.0.0.0:5060 create_udp(sip, pjsip, nmapped) + create_udp(sip, pjsip, nmapped) # TCP settings may be dependent on UDP settings, so do it second. create_tcp(sip, pjsip, nmapped) + create_tcp(sip, pjsip, nmapped) + create_tls(sip, pjsip, nmapped) create_tls(sip, pjsip, nmapped) @@ -1219,6 +1200,8 @@ def cli_options(): sip_filename, pjsip_filename = cli_options() # configuration parser for sip.conf sip = astconfigparser.MultiOrderedConfigParser() + print 'Please, report any issue at:' + print ' https://issues.asterisk.org/' print 'Reading', sip_filename sip.read(sip_filename) print 'Converting to PJSIP...' From 858fa5eb2c96149fffda629b727f8009e3b367fc Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Fri, 26 Aug 2016 15:41:16 +0200 Subject: [PATCH 0705/1578] channel: No hung-up on failing security requirements. In your Diaplan, if you specify same => n,Set(CHANNEL(secure_bridge_media)=1) same => n,Set(CHANNEL(secure_bridge_signaling)=1) only the SIP channel driver chan_sip supports this. All other channels drivers like res_pjsip fail. In case of failure, the original sRTP source code released the whole channel, even if not hung-up, yet. This change does not release the channel but instead hangs-up the channel. ASTERISK-26306 Change-Id: I0489f0cb660fab6673b0db8af027d116e70a66db --- main/channel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/channel.c b/main/channel.c index 1f18d53b15c..94505ad0e83 100644 --- a/main/channel.c +++ b/main/channel.c @@ -6093,7 +6093,7 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request if (set_security_requirements(requestor, c)) { ast_log(LOG_WARNING, "Setting security requirements failed\n"); - c = ast_channel_release(c); + ast_hangup(c); *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; return NULL; } From a7487e926153a7770db20c85b070ff0a2da7be37 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 26 Aug 2016 13:34:22 -0600 Subject: [PATCH 0706/1578] pjproject_bundled: Disable srtp use by pjmedia The reason for the disable is that while Asterisk works fine with older libsrtp versions, newer versions of pjproject won't compile with them. Debian 6 for instance, has libsrtp 1.4.4 which is older than what pjproject is expecting. We don't use most of pjmedia but we DO use it for SDP negotiation. Luckily disabling srtp in pjmedia doesn't interfere with it's ability to negitiate a secure channel. The proper crypto attributes are negotiated in both directions. ASTERISK-26279 #close Change-Id: Id25a92cdf3df97a26c53cffae65b6b82de33c8e2 --- third-party/pjproject/patches/config_site.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 07e4d97a92e..f9f76dc6c93 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -4,6 +4,14 @@ #include +/* + * Defining PJMEDIA_HAS_SRTP to 0 does NOT disable Asterisk's ability to use srtp. + * It only disables the pjmedia srtp transport which Asterisk doesn't use. + * The reason for the disable is that while Asterisk works fine with older libsrtp + * versions, newer versions of pjproject won't compile with them. + */ +#define PJMEDIA_HAS_SRTP 0 + #define PJ_HAS_IPV6 1 #define NDEBUG 1 #define PJ_MAX_HOSTNAME (256) From c21e6764f13a050d478e5aea6388e35ae57007e9 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 25 Aug 2016 12:06:41 +0000 Subject: [PATCH 0707/1578] app_queue: Ensure member is removed from pending when hanging up. When dialing channels it is possible that they may not ever leave the not in use state (Local channels in particular) by the time we cancel them. If this occurs but we know they were dialed we explicitly remove them from the pending members container so that subsequent call attempts occur. ASTERISK-26299 #close Change-Id: I6ad0d17c36480c92cebf840626228ce3f7e4bd65 --- apps/app_queue.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index a5cb1264027..f9dd86b677b 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4102,6 +4102,17 @@ static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, stru ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE); } ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL"); + + /* When dialing channels it is possible that they may not ever + * leave the not in use state (Local channels in particular) by + * the time we cancel them. If this occurs but we know they were + * dialed we explicitly remove them from the pending members + * container so that subsequent call attempts occur. + */ + if (outgoing->member->status == AST_DEVICE_NOT_INUSE) { + pending_members_remove(outgoing->member); + } + ast_hangup(outgoing->chan); } oo = outgoing; From 5e0758575caa5362b61bf10692d209fe5730ad71 Mon Sep 17 00:00:00 2001 From: Etienne Lessard Date: Mon, 29 Aug 2016 08:07:38 -0400 Subject: [PATCH 0708/1578] pbx.c: Prevent infinite recursion in manager_show_dialplan_helper. Previously, if context A was including context B and context B was including context A, i.e. if there was a circular dependency between contexts, then calling manager_show_dialplan_helper could lead to an infinite recursion, resulting in a crash. This commit applies the same solution as the one implemented in the show_dialplan_helper function. The manager_show_dialplan_helper and show_dialplan_helper functions contain lots of code in common, but the former was missing the "infinite recursion avoidance" code. ASTERISK-26226 #close Change-Id: I1aea85133c21787226f4f8442253a93000aa0897 --- main/pbx.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/main/pbx.c b/main/pbx.c index 63385f91fba..7cd420adb1b 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -5794,7 +5794,8 @@ static void manager_dpsendack(struct mansession *s, const struct message *m) static int manager_show_dialplan_helper(struct mansession *s, const struct message *m, const char *actionidtext, const char *context, const char *exten, struct dialplan_counters *dpc, - const struct ast_include *rinclude) + const struct ast_include *rinclude, + int includecount, const char *includes[]) { struct ast_context *c; int res = 0, old_total_exten = dpc->total_exten; @@ -5876,7 +5877,24 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa if (exten) { /* Check all includes for the requested extension */ - manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i); + if (includecount >= AST_PBX_MAX_STACK) { + ast_log(LOG_WARNING, "Maximum include depth exceeded!\n"); + } else { + int dupe = 0; + int x; + for (x = 0; x < includecount; x++) { + if (!strcasecmp(includes[x], ast_get_include_name(i))) { + dupe++; + break; + } + } + if (!dupe) { + includes[includecount] = ast_get_include_name(i); + manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes); + } else { + ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context); + } + } } else { if (!dpc->total_items++) manager_dpsendack(s, m); @@ -5932,6 +5950,7 @@ static int manager_show_dialplan(struct mansession *s, const struct message *m) { const char *exten, *context; const char *id = astman_get_header(m, "ActionID"); + const char *incstack[AST_PBX_MAX_STACK]; char idtext[256]; /* Variables used for different counters */ @@ -5947,7 +5966,7 @@ static int manager_show_dialplan(struct mansession *s, const struct message *m) exten = astman_get_header(m, "Extension"); context = astman_get_header(m, "Context"); - manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL); + manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL, 0, incstack); if (!ast_strlen_zero(context) && !counters.context_existence) { char errorbuf[BUFSIZ]; From c98a047ee6f484625494cf3b07d44da4e91c6577 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 22 Aug 2016 17:08:19 -0500 Subject: [PATCH 0709/1578] res_pjsip: Default endpoints to the "offline" status. A recent change attempted to optimize startup by not updating contact status. Instead, code responsible for qualifying contacts updates the status as it becomes known. The code even accounts for contacts/AORs that are not set to be qualified. The problem, though, is when there are no contacts associated with an endpoint. A common case is when an endpoint is set to register its contacts but has not done so yet. In this case, prior to registration, the endpoint's device state will appear to be "not in use" and hints associated with that device will appear to be "idle". In actuality, the device state and hint should both appear as "unavailable". The reason for the failure is that the optimization change made all persistent endpoint states set to "unknown". The fix here is to change the hard-coded "unknown" to be "offline" instead. The default state will be offline until the qualifying code determines that the contact is actually online. This way, if there are no contacts at all, then the state stays as offline, and device state and hints appear correctly. ASTERISK-26269 #close Reported by nappsoft Change-Id: Ie99b84169393983453076f5e9c0d35ff313a456a --- res/res_pjsip/pjsip_configuration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 23aa522ce89..333be71438a 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1289,7 +1289,7 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_ return NULL; } - ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN); + ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_OFFLINE); ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK); } From faf9bdebb770ac3bd7dffa477998ccbbb070b0e1 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 26 Aug 2016 11:39:11 -0400 Subject: [PATCH 0710/1578] res_pjsip: qualify/unqualify added/deleted realtime endpoints If the PJSIP endpoint's AOR with the permanent contact was deleted from the realtime storage the res_pjsip module continues trying to qualify this contact. The error 'Unable to find an endpoint to qualify contact' appeares every 'qualify_frequency' seconds. This patch deletes this contact in this case. The PJSIP endpoint's AOR with the permanent contact is never qualified if it is added to realtime storage after asterisk started. This patch adds qualifying for the AOR's permanent contacts on the first handling of this AOR. ASTERISK-26319 #close Change-Id: Ib93dded9121edb113076903d1aa95402f799f8fe --- res/res_pjsip/pjsip_options.c | 41 ++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 5e0fc76cb57..a282224c92f 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -53,6 +53,9 @@ static const char *short_status_map [] = { [REMOVED] = "Removed", }; +static void contact_deleted(const void *obj); +static void qualify_and_schedule(struct ast_sip_contact *contact); + const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status) { return status_map[status]; @@ -108,6 +111,29 @@ static void *contact_status_alloc(const char *name) return status; } +static int qualify_and_schedule_aor_contact(void *obj) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_aor *aor; + + if (!contact || ast_strlen_zero(contact->aor) || + !(aor = ast_sip_location_retrieve_aor(contact->aor))) { + ao2_ref(contact, -1); + return -1; + } + + contact->qualify_frequency = aor->qualify_frequency; + contact->qualify_timeout = aor->qualify_timeout; + contact->authenticate_qualify = aor->authenticate_qualify; + + ao2_ref(aor, -1); + + qualify_and_schedule(contact); + ao2_ref(contact, -1); + + return 0; +} + AST_MUTEX_DEFINE_STATIC(creation_lock); /*! @@ -144,6 +170,18 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const return NULL; } + /* The permanent contact added after asterisk start should be qualified. */ + if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED) && ast_tvzero(contact->expiration_time)) { + /* + * The FULLY_BOOTED to filter out contacts that already existed when asterisk started. + * The zero expiration_time to select only permanent contacts. + */ + ao2_ref((struct ast_sip_contact *) contact, +1); + if (ast_sip_push_task(NULL, qualify_and_schedule_aor_contact, (struct ast_sip_contact *) contact)) { + ao2_ref((struct ast_sip_contact *) contact, -1); + } + } + ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "+1", 1.0, ast_sip_get_contact_status_label(status->status)); @@ -368,8 +406,9 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con endpoint_local = find_an_endpoint(contact); } if (!endpoint_local) { - ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n", + ast_log(LOG_WARNING, "Unable to find an endpoint to qualify contact %s. Deleting this contact\n", contact->uri); + contact_deleted(contact); return -1; } } From 91993ebaa524c45aa105ccc3d7b7005f6c3aa8c9 Mon Sep 17 00:00:00 2001 From: Jean Aunis Date: Wed, 31 Aug 2016 12:33:28 +0200 Subject: [PATCH 0711/1578] resource_channels.c: add hangup reason "answered_elsewhere". In ARI, the channels API allows to hangup a channel with a hangup reason. This commit adds a new reason "answered_elsewhere". When using a SIP channel, this will eventually allow Asterisk to add a proper "Reason" header to a CANCEL message. ASTERISK-26321 Change-Id: Ia97675bd4acd6a7f58eb467953dfb94559f6583d --- res/ari/resource_channels.c | 2 ++ rest-api/api-docs/channels.json | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index 35b757267c3..8d329212987 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -886,6 +886,8 @@ void ast_ari_channels_hangup(struct ast_variable *headers, cause = AST_CAUSE_CONGESTION; } else if (!strcmp(args->reason, "no_answer")) { cause = AST_CAUSE_NOANSWER; + } else if(!strcmp(args->reason, "answered_elsewhere")) { + cause = AST_CAUSE_ANSWERED_ELSEWHERE; } else { ast_ari_response_error( response, 400, "Invalid Reason", diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index 75feeb1053b..ee18bfe1196 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -400,7 +400,8 @@ "normal", "busy", "congestion", - "no_answer" + "no_answer", + "answered_elsewhere" ] } } From 48fd4c815ce28ac21bebdef79cdfdb90b3d877c3 Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Wed, 31 Aug 2016 19:23:09 +0200 Subject: [PATCH 0712/1578] app_mp3: Use correct buffer size and the same sample rate as the channel Previously, the buffer used for MP3 streamed from HTTP servers had a size of 1 MB. For 8 kHz mono audio at 16 bit resolution, such a buffer covers about 1 minute. Only when the buffer is full does audio start to play. For MP3 files streamed from a server, that is usually not a big deal as long as the connection to the server is fast enough to supply that much data within a second or two. For MP3 live streams however, it takes 1 minute to download 1 minute of audio, so without this change, app_mp3 wasn't really usable for MP3 live streams. This commit changes the buffer size so that it covers 6 seconds of an MP3 file streamed from a server and 0.5 seconds of an MP3 live stream. The latter is identified by the use of a .m3u file extension. app_mp3 so far only supported 8 kHz audio. Now it always runs at the sample rate of the channel. ASTERISK-26085 #close Change-Id: Id1ee274733cd804a0edecf7450329b72f1235af0 --- apps/app_mp3.c | 52 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/apps/app_mp3.c b/apps/app_mp3.c index 5712cfe33b1..05afe54b100 100644 --- a/apps/app_mp3.c +++ b/apps/app_mp3.c @@ -77,9 +77,10 @@ ASTERISK_REGISTER_FILE() ***/ static char *app = "MP3Player"; -static int mp3play(const char *filename, int fd) +static int mp3play(const char *filename, unsigned int sampling_rate, int fd) { int res; + char sampling_rate_str[8]; res = ast_safe_fork(0); if (res < 0) @@ -93,30 +94,44 @@ static int mp3play(const char *filename, int fd) dup2(fd, STDOUT_FILENO); ast_close_fds_above_n(STDERR_FILENO); + snprintf(sampling_rate_str, 8, "%u", sampling_rate); + /* Execute mpg123, but buffer if it's a net connection */ - if (!strncasecmp(filename, "http://", 7)) { + if (!strncasecmp(filename, "http://", 7) && strstr(filename, ".m3u")) { + char buffer_size_str[8]; + snprintf(buffer_size_str, 8, "%u", (int) 0.5*2*sampling_rate/1000); // 0.5 seconds for a live stream + /* Most commonly installed in /usr/local/bin */ + execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); + /* But many places has it in /usr/bin */ + execl(MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); + /* As a last-ditch effort, try to use PATH */ + execlp("mpg123", "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); + } + else if (!strncasecmp(filename, "http://", 7)) { + char buffer_size_str[8]; + snprintf(buffer_size_str, 8, "%u", 6*2*sampling_rate/1000); // 6 seconds for a remote MP3 file /* Most commonly installed in /usr/local/bin */ - execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* But many places has it in /usr/bin */ - execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* As a last-ditch effort, try to use PATH */ - execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execlp("mpg123", "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); } else if (strstr(filename, ".m3u")) { /* Most commonly installed in /usr/local/bin */ - execl(LOCAL_MPG_123, "mpg123", "-q", "-z", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL); + execl(LOCAL_MPG_123, "mpg123", "-q", "-z", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); /* But many places has it in /usr/bin */ - execl(MPG_123, "mpg123", "-q", "-z", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL); + execl(MPG_123, "mpg123", "-q", "-z", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); /* As a last-ditch effort, try to use PATH */ - execlp("mpg123", "mpg123", "-q", "-z", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL); + execlp("mpg123", "mpg123", "-q", "-z", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); } else { /* Most commonly installed in /usr/local/bin */ - execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* But many places has it in /usr/bin */ - execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* As a last-ditch effort, try to use PATH */ - execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); } /* Can't use ast_log since FD's are closed */ fprintf(stderr, "Execute of mpg123 failed\n"); @@ -155,6 +170,9 @@ static int mp3_exec(struct ast_channel *chan, const char *data) } myf = { .f = { 0, }, }; + struct ast_format * native_format; + unsigned int sampling_rate; + struct ast_format * write_format; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); @@ -168,15 +186,19 @@ static int mp3_exec(struct ast_channel *chan, const char *data) ast_stopstream(chan); + native_format = ast_format_cap_get_format(ast_channel_nativeformats(chan), 0); + sampling_rate = ast_format_get_sample_rate(native_format); + write_format = ast_format_cache_get_slin_by_rate(sampling_rate); + owriteformat = ao2_bump(ast_channel_writeformat(chan)); - res = ast_set_write_format(chan, ast_format_slin); + res = ast_set_write_format(chan, write_format); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } myf.f.frametype = AST_FRAME_VOICE; - myf.f.subclass.format = ast_format_slin; + myf.f.subclass.format = write_format; myf.f.mallocd = 0; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; @@ -184,7 +206,7 @@ static int mp3_exec(struct ast_channel *chan, const char *data) myf.f.delivery.tv_usec = 0; myf.f.data.ptr = myf.frdata; - res = mp3play(data, fds[1]); + res = mp3play(data, sampling_rate, fds[1]); if (!strncasecmp(data, "http://", 7)) { timeout = 10000; } @@ -211,7 +233,7 @@ static int mp3_exec(struct ast_channel *chan, const char *data) res = 0; break; } - next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000)); + next = ast_tvadd(next, ast_samp2tv(myf.f.samples, sampling_rate)); } else { ms = ast_waitfor(chan, ms); if (ms < 0) { From 0c5b6e9ff559dcb20d9315154d4bd6a2ea5aa6a9 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 26 Aug 2016 14:18:10 -0400 Subject: [PATCH 0713/1578] astobj2: Support using a separate object for locking. Create ao2_alloc_with_lockobj function to support shared locking. Change-Id: Iba687eb9843922be7e481e23a32c0700ecf88a80 --- include/asterisk/astobj2.h | 27 ++++++++++++++ main/astobj2.c | 75 +++++++++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index 0472c1b3753..28ae73e87ed 100644 --- a/include/asterisk/astobj2.h +++ b/include/asterisk/astobj2.h @@ -368,6 +368,13 @@ enum ao2_alloc_opts { AO2_ALLOC_OPT_LOCK_NOLOCK = (2 << 0), /*! The ao2 object locking option field mask. */ AO2_ALLOC_OPT_LOCK_MASK = (3 << 0), + /*! + * \internal The ao2 object uses a separate object for locking. + * + * \note This option is used internally by ao2_alloc_with_lockobj and + * should never be passed directly to ao2_alloc. + */ + AO2_ALLOC_OPT_LOCK_OBJ = AO2_ALLOC_OPT_LOCK_MASK, }; /*! @@ -408,6 +415,26 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in /*! @} */ +/*! + * \since 14.1.0 + * \brief Allocate and initialize an object with separate locking. + * + * \param data_size The sizeof() of the user-defined structure. + * \param destructor_fn The destructor function (can be NULL) + * \param lockobj A separate ao2 object that will provide locking. + * \param debug_msg An ao2 object debug tracing message. + * \return A pointer to user-data. + * + * \see \ref ao2_alloc for additional details. + * + * \note lockobj must be a valid AO2 object. + */ +#define ao2_alloc_with_lockobj(data_size, destructor_fn, lockobj, tag) \ + __ao2_alloc_with_lockobj((data_size), (destructor_fn), (lockobj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__) + +void *__ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj, + const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result; + /*! \brief * Reference/unreference an object and return the old refcount. * diff --git a/main/astobj2.c b/main/astobj2.c index 5c92f263f1b..604e6a1ae41 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -108,6 +108,17 @@ struct astobj2_rwlock { void *user_data[0]; }; +struct ao2_lockobj_priv { + void *lock; +}; + +/* AstObj2 with locking provided by a separate object. */ +struct astobj2_lockobj { + struct ao2_lockobj_priv lockobj; + struct __priv_data priv_data; + void *user_data[0]; +}; + #ifdef AO2_DEBUG struct ao2_stats ao2; #endif @@ -118,6 +129,9 @@ struct ao2_stats ao2; #define INTERNAL_OBJ_RWLOCK(user_data) \ ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock))) +#define INTERNAL_OBJ_LOCKOBJ(user_data) \ + ((struct astobj2_lockobj *) (((char *) (user_data)) - sizeof(struct astobj2_lockobj))) + #define INTERNAL_OBJ(user_data) \ (struct astobj2 *) ((char *) user_data - sizeof(struct astobj2)) @@ -187,6 +201,7 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int res = 0; if (obj == NULL) { @@ -231,6 +246,10 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + res = __ao2_lock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -245,6 +264,7 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line, struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int res = 0; int current_value; @@ -281,6 +301,10 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line, case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + res = __ao2_unlock(obj_lockobj->lockobj.lock, file, func, line, var); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -295,6 +319,7 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int res = 0; if (obj == NULL) { @@ -339,6 +364,10 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ return 0; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + res = __ao2_trylock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -370,6 +399,7 @@ enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int { struct astobj2 *obj = INTERNAL_OBJ(user_data); struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; enum ao2_lock_req orig_lock; switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) { @@ -400,6 +430,10 @@ enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int break; } break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + orig_lock = __adjust_lock(obj_lockobj->lockobj.lock, lock_how, keep_stronger); + break; default: ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data); /* Fall through */ @@ -441,6 +475,7 @@ int __ao2_ref(void *user_data, int delta, struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int current_value; int ret; void *weakproxy = NULL; @@ -552,6 +587,12 @@ int __ao2_ref(void *user_data, int delta, case AO2_ALLOC_OPT_LOCK_NOLOCK: ast_free(obj); break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + ao2_t_ref(obj_lockobj->lockobj.lock, -1, "release lockobj"); + + ast_free(obj_lockobj); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -581,13 +622,14 @@ void __ao2_cleanup(void *obj) } } -void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, - const char *tag, const char *file, int line, const char *func) +static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, + void *lockobj, const char *tag, const char *file, int line, const char *func) { /* allocation */ struct astobj2 *obj; struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; switch (options & AO2_ALLOC_OPT_LOCK_MASK) { case AO2_ALLOC_OPT_LOCK_MUTEX: @@ -614,6 +656,22 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in return NULL; } break; + case AO2_ALLOC_OPT_LOCK_OBJ: + lockobj = ao2_t_bump(lockobj, "set lockobj"); + if (!lockobj) { + ast_log(__LOG_ERROR, file, line, func, "AO2_ALLOC_OPT_LOCK_OBJ requires a non-NULL lockobj.\n"); + return NULL; + } + + obj_lockobj = __ast_calloc(1, sizeof(*obj_lockobj) + data_size, file, line, func); + if (obj_lockobj == NULL) { + ao2_t_ref(lockobj, -1, "release lockobj for failed alloc"); + return NULL; + } + + obj_lockobj->lockobj.lock = lockobj; + obj = (struct astobj2 *) &obj_lockobj->priv_data; + break; default: /* Invalid option value. */ ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n"); @@ -643,6 +701,19 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in return EXTERNAL_OBJ(obj); } +void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, + const char *tag, const char *file, int line, const char *func) +{ + return internal_ao2_alloc(data_size, destructor_fn, options, NULL, tag, file, line, func); +} + +void *__ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj, + const char *tag, const char *file, int line, const char *func) +{ + return internal_ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_OBJ, lockobj, + tag, file, line, func); +} + unsigned int ao2_options_get(void *obj) { struct astobj2 *orig_obj; From 131baf70d6f349f7adee81419410f78790c0ebda Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 18 Aug 2016 14:28:57 -0400 Subject: [PATCH 0714/1578] named_locks: Use ao2_weakproxy to deal with cleanup from container. This allows standard ao2 functions to be used to release references to an ast_named_lock. This change can cause less frequent locking of the global named_locks container. The container is no longer locked when a named_lock reference is being release except when this causes the named_lock to be destroyed. Change-Id: I644e39c6d83a153d71b3fae77ec05599d725e7e6 --- include/asterisk/named_locks.h | 10 +--- main/named_locks.c | 83 +++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/include/asterisk/named_locks.h b/include/asterisk/named_locks.h index 0fe07d99234..1959841d0c5 100644 --- a/include/asterisk/named_locks.h +++ b/include/asterisk/named_locks.h @@ -48,7 +48,7 @@ * To use a named lock: * Call ast_named_lock_get with the appropriate keyspace and key. * Use the standard ao2 lock/unlock functions as needed. - * Call ast_named_lock_put when you're finished with it. + * Call ao2_cleanup when you're finished with it. */ /*! @@ -66,9 +66,6 @@ struct ast_named_lock; struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func, enum ast_named_lock_type lock_type, const char *keyspace, const char *key); -int __ast_named_lock_put(const char *filename, int lineno, const char *func, - struct ast_named_lock *lock); - /*! * \brief Geta named lock handle * \since 13.9.0 @@ -92,11 +89,8 @@ int __ast_named_lock_put(const char *filename, int lineno, const char *func, * \since 13.9.0 * * \param lock The pointer to the ast_named_lock structure returned by ast_named_lock_get - * \retval 0 Success - * \retval -1 Failure */ -#define ast_named_lock_put(lock) \ - __ast_named_lock_put(__FILE__, __LINE__, __PRETTY_FUNCTION__, lock) +#define ast_named_lock_put(lock) ao2_cleanup(lock) /*! * @} diff --git a/main/named_locks.c b/main/named_locks.c index 59604838844..c71f3b57923 100644 --- a/main/named_locks.c +++ b/main/named_locks.c @@ -35,13 +35,17 @@ ASTERISK_REGISTER_FILE() struct ao2_container *named_locks; #define NAMED_LOCKS_BUCKETS 101 -struct ast_named_lock { +struct named_lock_proxy { + AO2_WEAKPROXY(); char key[0]; }; +struct ast_named_lock { +}; + static int named_locks_hash(const void *obj, const int flags) { - const struct ast_named_lock *lock = obj; + const struct named_lock_proxy *lock = obj; switch (flags & OBJ_SEARCH_MASK) { case OBJ_SEARCH_KEY: @@ -57,8 +61,8 @@ static int named_locks_hash(const void *obj, const int flags) static int named_locks_cmp(void *obj_left, void *obj_right, int flags) { - const struct ast_named_lock *object_left = obj_left; - const struct ast_named_lock *object_right = obj_right; + const struct named_lock_proxy *object_left = obj_left; + const struct named_lock_proxy *object_right = obj_right; const char *right_key = obj_right; int cmp; @@ -98,45 +102,72 @@ int ast_named_locks_init(void) return 0; } +static void named_lock_proxy_cb(void *weakproxy, void *data) +{ + ao2_unlink(named_locks, weakproxy); +} + struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func, enum ast_named_lock_type lock_type, const char *keyspace, const char *key) { + struct named_lock_proxy *proxy = NULL; struct ast_named_lock *lock = NULL; - int concat_key_buff_len = strlen(keyspace) + strlen(key) + 2; - char *concat_key = ast_alloca(concat_key_buff_len); + int keylen = strlen(keyspace) + strlen(key) + 2; + char *concat_key = ast_alloca(keylen); sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */ ao2_lock(named_locks); - lock = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); - if (lock) { + proxy = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (proxy) { ao2_unlock(named_locks); - ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type); - return lock; - } + lock = __ao2_weakproxy_get_object(proxy, 0, __PRETTY_FUNCTION__, filename, lineno, func); + + if (lock) { + /* We have an existing lock and it's not being destroyed. */ + ao2_ref(proxy, -1); + ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type); + + return lock; + } - lock = ao2_alloc_options(sizeof(*lock) + concat_key_buff_len, NULL, lock_type); - if (lock) { - strcpy(lock->key, concat_key); /* Safe */ - ao2_link_flags(named_locks, lock, OBJ_NOLOCK); + /* the old proxy is being destroyed, clean list before creating/adding new one */ + ao2_lock(named_locks); + ao2_unlink_flags(named_locks, proxy, OBJ_NOLOCK); + ao2_ref(proxy, -1); } - ao2_unlock(named_locks); - return lock; -} + proxy = ao2_t_weakproxy_alloc(sizeof(*proxy) + keylen, NULL, concat_key); + if (!proxy) { + goto failure_cleanup; + } -int __ast_named_lock_put(const char *filename, int lineno, const char *func, - struct ast_named_lock *lock) -{ + lock = __ao2_alloc(sizeof(*lock) + keylen, NULL, lock_type, concat_key, filename, lineno, func); if (!lock) { - return -1; + goto failure_cleanup; } - ao2_lock(named_locks); - if (ao2_ref(lock, -1) == 2) { - ao2_unlink_flags(named_locks, lock, OBJ_NOLOCK); + /* We have exclusive access to proxy and lock, no need for locking here. */ + if (ao2_weakproxy_set_object(proxy, lock, OBJ_NOLOCK)) { + goto failure_cleanup; } + + if (ao2_weakproxy_subscribe(proxy, named_lock_proxy_cb, NULL, OBJ_NOLOCK)) { + goto failure_cleanup; + } + + strcpy(proxy->key, concat_key); /* Safe */ + ao2_link_flags(named_locks, proxy, OBJ_NOLOCK); ao2_unlock(named_locks); + ao2_t_ref(proxy, -1, "Release allocation reference"); - return 0; + return lock; + +failure_cleanup: + ao2_unlock(named_locks); + + ao2_cleanup(proxy); + ao2_cleanup(lock); + + return NULL; } From e875e1c12a4b954b18e136b25c2a83b5f8e15f5d Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 26 Aug 2016 18:22:51 -0400 Subject: [PATCH 0715/1578] sorcery: Create function ast_sorcery_lockable_alloc. Create an alternative to ast_sorcery_generic_alloc which uses astobj2 shared locking. Use this new method for the 'struct ast_sip_aor' allocator. Change-Id: I3f62f2ada64b622571950278fbb6ad57395b5d6f --- include/asterisk/sorcery.h | 20 ++++++++++++++++++++ main/sorcery.c | 19 ++++++++++++++++++- res/res_pjsip/location.c | 36 +++++++++++++++++------------------- res/res_pjsip_registrar.c | 14 +++----------- 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h index 23219ec41cc..89663381683 100644 --- a/include/asterisk/sorcery.h +++ b/include/asterisk/sorcery.h @@ -988,9 +988,29 @@ int ast_sorcery_changeset_create(const struct ast_variable *original, const stru * * \retval non-NULL success * \retval NULL failure + * + * \note The returned object does not support AO2 locking. */ void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor); +/*! + * \since 14.1.0 + * \brief Allocate a generic sorcery capable object with locking. + * + * \details Sorcery objects may be replaced with new allocations during reloads. + * If locking is required on sorcery objects it must be shared between the old + * object and the new one. lockobj can be any AO2 object with locking enabled, + * but in most cases named locks should be used to provide stable locking. + * + * \param size Size of the object + * \param destructor Optional destructor function + * \param lockobj An AO2 object that will provide locking. + * + * \retval non-NULL success + * \retval NULL failure + */ +void *ast_sorcery_lockable_alloc(size_t size, ao2_destructor_fn destructor, void *lockobj); + /*! * \brief Allocate an object * diff --git a/main/sorcery.c b/main/sorcery.c index 55ee830b707..9f8c35c3b9e 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -1736,9 +1736,26 @@ static void sorcery_object_destructor(void *object) ast_free(details->object->id); } +void *ast_sorcery_lockable_alloc(size_t size, ao2_destructor_fn destructor, void *lockobj) +{ + void *object = ao2_alloc_with_lockobj(size + sizeof(struct ast_sorcery_object), + sorcery_object_destructor, lockobj, ""); + struct ast_sorcery_object_details *details = object; + + if (!object) { + return NULL; + } + + details->object = object + size; + details->object->destructor = destructor; + + return object; +} + void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor) { - void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK); + void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), + sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK); struct ast_sorcery_object_details *details = object; if (!object) { diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 0ab69ec5b18..5abfcabadfc 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -49,11 +49,22 @@ static void aor_destroy(void *obj) /*! \brief Allocator for AOR */ static void *aor_alloc(const char *name) { - struct ast_sip_aor *aor = ast_sorcery_generic_alloc(sizeof(struct ast_sip_aor), aor_destroy); + void *lock; + struct ast_sip_aor *aor; + + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", name); + if (!lock) { + return NULL; + } + + aor = ast_sorcery_lockable_alloc(sizeof(struct ast_sip_aor), aor_destroy, lock); + ao2_ref(lock, -1); + if (!aor) { return NULL; } ast_string_field_init(aor, 128); + return aor; } @@ -206,17 +217,11 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor) { struct ao2_container *contacts; - struct ast_named_lock *lock; - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", ast_sorcery_object_get_id(aor)); - if (!lock) { - return NULL; - } - - ao2_lock(lock); + /* ao2_lock / ao2_unlock do not actually write aor since it has an ao2 lockobj. */ + ao2_lock((void*)aor); contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); - ao2_unlock(lock); - ast_named_lock_put(lock); + ao2_unlock((void*)aor); return contacts; } @@ -369,19 +374,12 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct ast_sip_endpoint *endpoint) { int res; - struct ast_named_lock *lock; - - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", ast_sorcery_object_get_id(aor)); - if (!lock) { - return -1; - } - ao2_lock(lock); + ao2_lock(aor); res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent, via_addr, via_port, call_id, endpoint); - ao2_unlock(lock); - ast_named_lock_put(lock); + ao2_unlock(aor); return res; } diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index f99a3b84dd4..47d5991e4bb 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -523,25 +523,17 @@ static int register_aor(pjsip_rx_data *rdata, { int res; struct ao2_container *contacts = NULL; - struct ast_named_lock *lock; - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", aor_name); - if (!lock) { - return PJ_TRUE; - } - - ao2_lock(lock); + ao2_lock(aor); contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); if (!contacts) { - ao2_unlock(lock); - ast_named_lock_put(lock); + ao2_unlock(aor); return PJ_TRUE; } res = register_aor_core(rdata, endpoint, aor, aor_name, contacts); ao2_cleanup(contacts); - ao2_unlock(lock); - ast_named_lock_put(lock); + ao2_unlock(aor); return res; } From c3b965a2c03d132d9feb91928bd72b283406f948 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 2 Sep 2016 11:36:38 -0500 Subject: [PATCH 0716/1578] format_cap.c: Fix CLI "core show channeltype Surrogate" crash. * Make ast_format_cap_get_names() NULL tolerant. ASTERISK-26331 #close Reported by: CGI.NET Change-Id: Id67e93936dc8ec2a33a9d33655843d43b59285a3 --- main/format_cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/format_cap.c b/main/format_cap.c index 2b3e6cd5f87..013b7bea1bf 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -703,7 +703,7 @@ const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str ast_str_set(buf, 0, "("); - if (!AST_VECTOR_SIZE(&cap->preference_order)) { + if (!cap || !AST_VECTOR_SIZE(&cap->preference_order)) { ast_str_append(buf, 0, "nothing)"); return ast_str_buffer(*buf); } From 4aaa27e532743af908ac525cebcdd9f942a0f871 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 31 Aug 2016 15:56:41 -0500 Subject: [PATCH 0717/1578] Sample configs: Eliminate false multiline comment block starts. Change-Id: Ie627def9604ae30abd80754f9e6f09874825aec6 --- configs/samples/alsa.conf.sample | 4 +-- configs/samples/ccss.conf.sample | 16 +++++----- configs/samples/chan_dahdi.conf.sample | 4 +-- configs/samples/console.conf.sample | 4 +-- configs/samples/mgcp.conf.sample | 6 ++-- configs/samples/minivm.conf.sample | 14 ++++---- configs/samples/misdn.conf.sample | 4 +-- configs/samples/oss.conf.sample | 4 +-- configs/samples/queues.conf.sample | 4 +-- configs/samples/res_snmp.conf.sample | 2 +- configs/samples/sip.conf.sample | 44 +++++++++++++------------- configs/samples/skinny.conf.sample | 20 ++++++------ configs/samples/unistim.conf.sample | 4 +-- configs/samples/vpb.conf.sample | 2 +- 14 files changed, 66 insertions(+), 66 deletions(-) diff --git a/configs/samples/alsa.conf.sample b/configs/samples/alsa.conf.sample index ced5b4485a7..23aac4e1048 100644 --- a/configs/samples/alsa.conf.sample +++ b/configs/samples/alsa.conf.sample @@ -46,7 +46,7 @@ extension=s ; systems where there will be no return audio path, such as overhead pagers. ;noaudiocapture=true -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an ; ALSA channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -74,5 +74,5 @@ extension=s ; network normally has low jitter, but occasionally has spikes. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- diff --git a/configs/samples/ccss.conf.sample b/configs/samples/ccss.conf.sample index 21b0b0668de..7b3fe7d2370 100644 --- a/configs/samples/ccss.conf.sample +++ b/configs/samples/ccss.conf.sample @@ -64,9 +64,9 @@ ; PLEASE READ THIS!!! ;=========================================== ; -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ; Timers -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ;There are three configurable timers for all types of CC: the ;cc_offer_timer, the ccbs_available_timer, and the ccnr_available_timer. ;In addition, when using a generic agent, there is a fourth timer, @@ -98,9 +98,9 @@ ; only affects operation when using a generic agent. ; ;cc_recall_timer = 20 -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ; Policies -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ; Policy settings tell Asterisk how to behave and what sort of ; resources to allocate in order to facilitate CC. There are two ; settings to control the actions Asterisk will take. @@ -153,9 +153,9 @@ ;cc_monitor_policy=never ; ; -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ; Limits -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ; ; The use of CC requires Asterisk to potentially use more memory than ; some administrators would like. As such, it is a good idea to limit @@ -175,9 +175,9 @@ ; ;cc_max_monitors = 5 ; -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ; Other -;--------------------------------------------------------------------- +; -------------------------------------------------------------------- ; ; When using a generic CC agent, the caller who requested CC will be ; called back when a called party becomes available. When the caller diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/samples/chan_dahdi.conf.sample index a0c729c116a..e70a2a138f6 100644 --- a/configs/samples/chan_dahdi.conf.sample +++ b/configs/samples/chan_dahdi.conf.sample @@ -1220,7 +1220,7 @@ pickupgroup=1 ; ;jitterbuffers=4 ; -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a ; DAHDI channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -1248,7 +1248,7 @@ pickupgroup=1 ; network normally has low jitter, but occasionally has spikes. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- ; ; You can define your own custom ring cadences here. You can define up to 8 ; pairs. If the silence is negative, it indicates where the caller ID spill is diff --git a/configs/samples/console.conf.sample b/configs/samples/console.conf.sample index 606254eeea4..aad306ed5c7 100644 --- a/configs/samples/console.conf.sample +++ b/configs/samples/console.conf.sample @@ -44,7 +44,7 @@ ; ;mohinterpret=default -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an ; Console channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -72,7 +72,7 @@ ; network normally has low jitter, but occasionally has spikes. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- ; diff --git a/configs/samples/mgcp.conf.sample b/configs/samples/mgcp.conf.sample index 7c725bc3d4b..f4bc0dbf2ae 100644 --- a/configs/samples/mgcp.conf.sample +++ b/configs/samples/mgcp.conf.sample @@ -11,12 +11,12 @@ ;cos=3 ; Sets 802.1p priority for signaling packets. ;cos_audio=5 ; Sets 802.1p priority for RTP audio packets. -;---------------------- DIGIT TIMEOUTS ---------------------------- +; --------------------- DIGIT TIMEOUTS ---------------------------- firstdigittimeout = 30000 ; default 16000 = 16s gendigittimeout = 10000 ; default 8000 = 8s matchdigittimeout = 5000 ; defaults 3000 = 3s -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a ; MGCP channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -48,7 +48,7 @@ matchdigittimeout = 5000 ; defaults 3000 = 3s ; network normally has low jitter, but occasionally has spikes. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- ;[dlinkgw] ;host = 192.168.0.64 diff --git a/configs/samples/minivm.conf.sample b/configs/samples/minivm.conf.sample index 55a39c869f0..2df3449d13f 100644 --- a/configs/samples/minivm.conf.sample +++ b/configs/samples/minivm.conf.sample @@ -12,7 +12,7 @@ ; this configuration file or realtime. The idea is to build voicemail as building blocks so that ; a complete and adaptive voicemail system can be built in the dialplan ; -;------------------------------ Variables to use in subject, from and message body ------------------ +; ----------------------------- Variables to use in subject, from and message body ------------------ ; Change the from, body and/or subject, variables: ; MVM_NAME, MVM_DUR, MVM_MSGNUM, VM_MAILBOX, MVM_CALLERID, MVM_CIDNUM, ; MVM_CIDNAME, MVM_DATE @@ -24,7 +24,7 @@ ; Note: The emailbody config row can only be up to 512 characters due to a ; limitation in the Asterisk configuration subsystem. ; To create longer mails, use the templatefile option when creating the template -;---------------------------------------------------------------------------------------------------- +; --------------------------------------------------------------------------------------------------- [general] ; Default format for storing and sending voicemail @@ -64,7 +64,7 @@ silencethreshold=128 ; This is used both for e-mail and pager messages ;mailcmd=/usr/sbin/sendmail -t ; -;--------------Default e-mail message template (used if no templates are used) ------ +; -------------Default e-mail message template (used if no templates are used) ------ ;fromstring=The Asterisk PBX ; @@ -82,7 +82,7 @@ emaildateformat=%A, %B %d, %Y at %r ; 24h date format ;emaildateformat=%A, %d %B %Y at %H:%M:%S ; -;--------------Default pager message template (used if no templates are used) ------ +; -------------Default pager message template (used if no templates are used) ------ ; You can also change the Pager From: string, the pager body and/or subject. ; The above defined variables also can be used here ;pagerfromstring=The Asterisk PBX @@ -90,7 +90,7 @@ emaildateformat=%A, %B %d, %Y at %r ;pagerbody=New ${MVM_DUR} long msg in box ${MVM_MAILBOX}\nfrom ${MVM_CALLERID}, on ${MVM_DATE} ; ; -;--------------Timezone definitions (used in voicemail accounts) ------------------- +; -------------Timezone definitions (used in voicemail accounts) ------------------- ; ; Users may be located in different timezones, or may have different ; message announcements for their introductory message when they enter @@ -133,7 +133,7 @@ central=America/Chicago|'vm-received' Q 'digits/at' IMp central24=America/Chicago|'vm-received' q 'digits/at' H N 'hours' military=Zulu|'vm-received' q 'digits/at' H N 'hours' 'phonetic/z_p' -;----------------------- Message body templates--------------------- +; ---------------------- Message body templates--------------------- ; [template-name] ; "template-" is a verbatim marker ; fromaddress = Your Friendly Asterisk Server ; fromemail = asteriskvm@digium.com @@ -187,7 +187,7 @@ dateformat=%A, %B %d, %Y at %r ;subject = Dear old chap, you've got an electronic communique ;charset=ascii -;----------------------- Mailbox accounts -------------------------- +; ---------------------- Mailbox accounts -------------------------- ;Template for mailbox definition - all options ; ; [username@domain] ; Has to be unique within domain (MWM_USERNAME, MWM_DOMAIN) diff --git a/configs/samples/misdn.conf.sample b/configs/samples/misdn.conf.sample index ac54dbc5ad8..ca27c03bdba 100644 --- a/configs/samples/misdn.conf.sample +++ b/configs/samples/misdn.conf.sample @@ -109,7 +109,7 @@ crypt_prefix=** ; crypt_keys=test,muh -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a ; SIP channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -140,7 +140,7 @@ crypt_keys=test,muh ; network normally has low jitter, but occasionally has spikes. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- ; users sections: ; diff --git a/configs/samples/oss.conf.sample b/configs/samples/oss.conf.sample index c3781a2a28c..ee169209fbd 100644 --- a/configs/samples/oss.conf.sample +++ b/configs/samples/oss.conf.sample @@ -46,7 +46,7 @@ ; queuesize = 10 ; frames in device driver ; frags = 8 ; argument to SETFRAGMENT - ;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- + ; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an ; OSS channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -74,7 +74,7 @@ ; network normally has low jitter, but occasionally has spikes. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". - ;----------------------------------------------------------------------------------- + ; ---------------------------------------------------------------------------------- ; below is an entry for a second console channel ; [card1] diff --git a/configs/samples/queues.conf.sample b/configs/samples/queues.conf.sample index 85cf9e40f2d..8a9c88402bb 100644 --- a/configs/samples/queues.conf.sample +++ b/configs/samples/queues.conf.sample @@ -129,7 +129,7 @@ monitor-type = MixMonitor ; ;penaltymemberslimit = 5 ; -;----------------------QUEUE TIMING OPTIONS------------------------------------ +; ---------------------QUEUE TIMING OPTIONS------------------------------------ ; A Queue has two different "timeout" values associated with it. One is the ; timeout parameter configured in queues.conf. This timeout specifies the ; amount of time to try ringing a member's phone before considering the @@ -181,7 +181,7 @@ monitor-type = MixMonitor ;retry = 5 ;timeoutpriority = app|conf ; -;-----------------------END QUEUE TIMING OPTIONS--------------------------------- +; ----------------------END QUEUE TIMING OPTIONS--------------------------------- ; Weight of queue - when compared to other queues, higher weights get ; first shot at available channels when the same channel is included in ; more than one queue. diff --git a/configs/samples/res_snmp.conf.sample b/configs/samples/res_snmp.conf.sample index a6e40c8e2e4..7f373491070 100644 --- a/configs/samples/res_snmp.conf.sample +++ b/configs/samples/res_snmp.conf.sample @@ -1,6 +1,6 @@ ; ; Configuration file for res_snmp -;--------------------------------- +; -------------------------------- ; ; Res_snmp can run as a subagent or standalone SNMP agent. The standalone snmp ; agent is based on net-snmp and will read a configuration file called diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample index da176b4d66a..916e2d67173 100644 --- a/configs/samples/sip.conf.sample +++ b/configs/samples/sip.conf.sample @@ -15,7 +15,7 @@ ; - context - Which set of services you offer various users ; ; SIP dial strings -;----------------------------------------------------------- +; ---------------------------------------------------------- ; In the dialplan (extensions.conf) you can use several ; syntaxes for dialing SIP devices. ; SIP/devicename @@ -87,7 +87,7 @@ ; sip reload Reload configuration file ; sip show settings Show the current channel configuration ; -;------- Naming devices ------------------------------------------------------ +; ------ Naming devices ------------------------------------------------------ ; ; When naming devices, make sure you understand how Asterisk matches calls ; that come in. @@ -111,7 +111,7 @@ ; not needed at all. Check below. In later releases, it's renamed ; to "defaultuser" which is a better name, since it is used in ; combination with the "defaultip" setting. -;----------------------------------------------------------------------------- +; ---------------------------------------------------------------------------- ; ** Old configuration options ** ; The "call-limit" configuation option is considered old is replaced @@ -573,7 +573,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; are not purged during SIP reloads. ; -;------------------------ TLS settings ------------------------------------------------------------ +; ----------------------- TLS settings ------------------------------------------------------------ ;tlscertfile= ; Certificate chain (*.pem format only) to use for TLS connections ; The certificates must be sorted starting with the subject's certificate ; and followed by intermediate CA certificates if applicable. If the @@ -622,7 +622,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; Your distribution might have changed that list ; further. ; -;--------------------------- SIP timers ---------------------------------------------------- +; -------------------------- SIP timers ---------------------------------------------------- ; These timers are used primarily in INVITE transactions. ; The default for Timer T1 is 500 ms or the measured run-trip time between ; Asterisk and the device if you have qualify=yes for the device. @@ -636,7 +636,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; in this amount of time, the call will autocongest ; Defaults to 64*timert1 -;--------------------------- RTP timers ---------------------------------------------------- +; -------------------------- RTP timers ---------------------------------------------------- ; These timers are currently used for both audio and video streams. The RTP timeouts ; are only applied to the audio channel. ; The settings are settable in the global section as well as per device @@ -652,7 +652,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;rtpkeepalive= ; Send keepalives in the RTP stream to keep NAT open ; (default is off - zero) -;--------------------------- SIP Session-Timers (RFC 4028)------------------------------------ +; -------------------------- SIP Session-Timers (RFC 4028)------------------------------------ ; SIP Session-Timers provide an end-to-end keep-alive mechanism for active SIP sessions. ; This mechanism can detect and reclaim SIP channels that do not terminate through normal ; signaling procedures. Session-Timers can be configured globally or at a user/peer level. @@ -681,7 +681,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;session-minse=90 ;session-refresher=uac ; -;--------------------------- SIP DEBUGGING --------------------------------------------------- +; -------------------------- SIP DEBUGGING --------------------------------------------------- ;sipdebug = yes ; Turn on SIP debugging by default, from ; the moment the channel loads this configuration. ; NOTE: You cannot use the CLI to turn it off. You'll @@ -692,7 +692,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; SIP history is output to the DEBUG logging channel -;--------------------------- STATUS NOTIFICATIONS (SUBSCRIPTIONS) ---------------------------- +; -------------------------- STATUS NOTIFICATIONS (SUBSCRIPTIONS) ---------------------------- ; You can subscribe to the status of extensions with a "hint" priority ; (See extensions.conf.sample for examples) ; chan_sip support two major formats for notifications: dialog-info and SIMPLE @@ -741,7 +741,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;callcounter = yes ; Enable call counters on devices. This can be set per ; device too. -;----------------------------------------- T.38 FAX SUPPORT ---------------------------------- +; ---------------------------------------- T.38 FAX SUPPORT ---------------------------------- ; ; This setting is available in the [general] section as well as in device configurations. ; Setting this to yes enables T.38 FAX (UDPTL) on SIP calls; it defaults to off. @@ -774,7 +774,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; faxdetect = cng ; Enables only CNG detection ; faxdetect = t38 ; Enables only T.38 detection ; -;----------------------------------------- OUTBOUND SIP REGISTRATIONS ------------------------ +; ---------------------------------------- OUTBOUND SIP REGISTRATIONS ------------------------ ; Asterisk can register as a SIP user agent to a SIP proxy (provider) ; Format for the register statement is: ; register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] @@ -851,7 +851,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; 401 responses and continue retrying according to normal ; retry rules. -;----------------------------------------- OUTBOUND MWI SUBSCRIPTIONS ------------------------- +; ---------------------------------------- OUTBOUND MWI SUBSCRIPTIONS ------------------------- ; Asterisk can subscribe to receive the MWI from another SIP server and store it locally for retrieval ; by other phones. At this time, you can only subscribe using UDP as the transport. ; Format for the mwi register statement is: @@ -866,7 +866,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; MWI received will be stored in the 1234 mailbox of the SIP_Remote context. ; It can be used by other phones by following the below: ; mailbox=1234@SIP_Remote -;----------------------------------------- NAT SUPPORT ------------------------ +; ---------------------------------------- NAT SUPPORT ------------------------ ; ; WARNING: SIP operation behind a NAT is tricky and you really need ; to read and understand well the following section. @@ -1008,7 +1008,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; ; icesupport = yes -;----------------------------------- MEDIA HANDLING -------------------------------- +; ---------------------------------- MEDIA HANDLING -------------------------------- ; By default, Asterisk tries to re-invite media streams to an optimal path. If there's ; no reason for Asterisk to stay in the media path, the media will be redirected. ; This does not really work well in the case where Asterisk is outside and the @@ -1090,7 +1090,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; option may be specified at the global or peer scope. ;force_avp=yes ; Force 'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', and 'RTP/SAVPF' to be used for ; media streams when appropriate, even if a DTLS stream is present. -;----------------------------------------- REALTIME SUPPORT ------------------------ +; ---------------------------------------- REALTIME SUPPORT ------------------------ ; For additional information on ARA, the Asterisk Realtime Architecture, ; please read https://wiki.asterisk.org/wiki/display/AST/Realtime+Database+Configuration ; @@ -1128,7 +1128,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; is still in memory (due to caching or other reasons), the ; information will not be removed from realtime storage -;----------------------------------------- SIP DOMAIN SUPPORT ------------------------ +; ---------------------------------------- SIP DOMAIN SUPPORT ------------------------ ; Incoming INVITE and REFER messages can be matched against a list of 'allowed' ; domains, each of which can direct the call to a specific context if desired. ; By default, all domains are accepted and sent to the default context or the @@ -1167,13 +1167,13 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; destinations which do not have a prior ; account relationship with your server. -;------------------------------ Advice of Charge CONFIGURATION -------------------------- +; ----------------------------- Advice of Charge CONFIGURATION -------------------------- ; snom_aoc_enabled = yes; ; This options turns on and off support for sending AOC-D and ; AOC-E to snom endpoints. This option can be used both in the ; peer and global scope. The default for this option is off. -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a ; SIP channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -1205,7 +1205,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- [authentication] ; Global credentials for outbound calls, i.e. when a proxy challenges your @@ -1224,7 +1224,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; You may also add auth= statements to [peer] definitions ; Peer auth= override all other authentication settings if we match on realm -;------------------------------------------------------------------------------ +; ----------------------------------------------------------------------------- ; DEVICE CONFIGURATION ; ; SIP entities have a 'type' which determines their roles within Asterisk. @@ -1351,7 +1351,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; ; from the peer's configuration. ; -;------------------------------------------------------------------------------ +; ----------------------------------------------------------------------------- ; DTLS-SRTP CONFIGURATION ; ; DTLS-SRTP support is available if the underlying RTP engine in use supports it. @@ -1409,7 +1409,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;port=80 ; The port number we want to connect to on the remote side ; Also used as "defaultport" in combination with "defaultip" settings -;--- sample definition for a provider +; -- sample definition for a provider ;[provider1] ;type=peer ;host=sip.provider1.com diff --git a/configs/samples/skinny.conf.sample b/configs/samples/skinny.conf.sample index be88dc23094..2bf06fbc8a1 100644 --- a/configs/samples/skinny.conf.sample +++ b/configs/samples/skinny.conf.sample @@ -54,7 +54,7 @@ keepalive=120 ;cos_audio=5 ; Sets 802.1p priority for RTP audio packets. ;cos_video=4 ; Sets 802.1p priority for RTP video packets. -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ;jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a ; skinny channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -79,10 +79,10 @@ keepalive=120 ; Defaults to fixed. ;jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- [lines] -;----------------------------------- LINES SECTION -------------------------------- +; ---------------------------------- LINES SECTION -------------------------------- ; Options set under [lines] apply to all lines unless explicitly set for a particular ; device. The options that can be set under lines are specified in GENERAL LINE OPTIONS. ; These options can also be set for each individual device as well as those under SPECIFIC @@ -95,15 +95,15 @@ keepalive=120 ; Where options are common to both lines and devices, the results typically take that of ; the least permission. ie if a no is set for either line or device, the call will not be ; able to use that permission -;-------------------------------- GENERAL LINE OPTIONS ----------------------------- +; ------------------------------- GENERAL LINE OPTIONS ----------------------------- ;earlyrtp=1 ; whether audio signalling should be provided by asterisk ; ; (earlyrtp=1) or device generated (earlyrtp=0). default=yes ;transfer=1 ; whether the device is allowed to transfer. default=yes ;context=default ; context to use for this line. ;callfwdtimeout=20000 ; ms before cfwd_noans occurs (default 20 secs) -;------------------------------- SPECIFIC LINE OPTIONS ----------------------------- +; ------------------------------ SPECIFIC LINE OPTIONS ----------------------------- ;setvar= ; allows for the setting of chanvars. -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- ;[100] ;nat=yes @@ -149,7 +149,7 @@ keepalive=120 [devices] -;---------------------------------- DEVICES SECTION ------------------------------- +; --------------------------------- DEVICES SECTION ------------------------------- ; Options set under [devices] apply to all devices unless explicitly set for a particular ; device. The options that can be set under devices are specified in GENERAL DEVICE OPTIONS. ; These options can also be set for each individual device as well as those under SPECIFIC @@ -162,16 +162,16 @@ keepalive=120 ; Where options are common to both lines and devices, the results typically take that of ; the least permission. ie if a no is set for either line or device, the call will not be ; able to use that permission -;------------------------------- GENERAL DEVICE OPTIONS ---------------------------- +; ------------------------------ GENERAL DEVICE OPTIONS ---------------------------- ;earlyrtp=1 ; whether audio signalling should be provided by asterisk ; ; (earlyrtp=1) or device generated (earlyrtp=0). default=yes ;transfer=1 ; whether the device is allowed to transfer. default=yes -;------------------------------ SPECIFIC DEVICE OPTIONS ---------------------------- +; ----------------------------- SPECIFIC DEVICE OPTIONS ---------------------------- ;device="SEPxxxxxxxxxxxx ; id of the device. Must be set. ;version=P002G204 ; firmware version to be loaded. If this version is different ; ; to the one on the device, the device will try to load this ; ; version from the tftp server. Set to device firmware version. -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- ; Typical config for 12SP+ ;[florian] diff --git a/configs/samples/unistim.conf.sample b/configs/samples/unistim.conf.sample index c33426b0c5d..a0964279641 100644 --- a/configs/samples/unistim.conf.sample +++ b/configs/samples/unistim.conf.sample @@ -17,7 +17,7 @@ port=5000 ; UDP port ;autoprovisioning=no ; Allow undeclared phones to register an extension. See README for important ; informations. no (default), yes, tn. ;mohsuggest=default -;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- +; ----------------------------- JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a ; SIP channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving @@ -41,7 +41,7 @@ port=5000 ; UDP port ; variable size, actually the new jb of IAX2). Defaults to fixed. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". -;----------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- ;[black] ; name of the device diff --git a/configs/samples/vpb.conf.sample b/configs/samples/vpb.conf.sample index fecb3ec597c..bdc89dff5af 100644 --- a/configs/samples/vpb.conf.sample +++ b/configs/samples/vpb.conf.sample @@ -199,7 +199,7 @@ grunttimeout=3600 ; mode=immediate -;------------------------------------------------------------------------- +; ------------------------------------------------------------------------ ; Channel definitions ; ; Each channel inherits the settings specified above, unless the are From dba02575fcb2852768e7149cbdf0e1e183ab40af Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 31 Aug 2016 15:13:19 -0500 Subject: [PATCH 0718/1578] sip_to_pjsip.py: Fix comment typo and tabs. Change-Id: If35174614545727817d329c60ba4456c028941b5 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 1a0d6a48068..d94939b716b 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -17,7 +17,7 @@ def section_by_type(section, pjsip, type): """Finds a section based upon the given type, adding it if not found.""" def __find_dict(mdicts, key, val): - """Given a list of mult-dicts, return the multi-dict that contains + """Given a list of multi-dicts, return the multi-dict that contains the given key/value pair.""" def found(d): @@ -1181,7 +1181,7 @@ def cli_options(): """ global PREFIX usage = "usage: %prog [options] [input-file [output-file]]\n\n" \ - "Converts the chan_sip configuration input-file to the chan_pjsip output-file.\n"\ + "Converts the chan_sip configuration input-file to the chan_pjsip output-file.\n" \ "The input-file defaults to 'sip.conf'.\n" \ "The output-file defaults to 'pjsip.conf'." parser = optparse.OptionParser(usage=usage) From 47336a0bdd2ade673c6e2fed8793a5b548061d48 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 31 Aug 2016 15:37:44 -0500 Subject: [PATCH 0719/1578] sip_to_pjsip.py: Fix typo converting outboundproxy registration. Change-Id: I6f30e5f9fcf8469ba0079fbf884047d54c2c0b15 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 1a0d6a48068..6e7735cbf35 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -1020,7 +1020,7 @@ def write(self, pjsip, nmapped): if self.outbound_proxy: set_value('outboundproxy', self.outbound_proxy, section, pjsip, - nmapped, 'registartion') + nmapped, 'registration') def map_registrations(sip, pjsip, nmapped): From edcf09e47c641fe3634735be15cfd39bb3f9f7a0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 31 Aug 2016 15:14:32 -0500 Subject: [PATCH 0720/1578] sip_to_pjsip.py: Map canreinvite as directmedia alias. Change-Id: I48b8e150f96a3d2a24d8fc25fbe4f5aff9f4a6b2 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 1a0d6a48068..437386a67d6 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -395,6 +395,7 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ['session-minse', set_value('timers_min_se')], ['session-expires', set_value('timers_sess_expires')], # identify_by ? + ['canreinvite', set_direct_media], # direct_media alias ['directmedia', set_direct_media], # direct_media # direct_media_method # directed_media_glare_mitigation From c1e438fdf7cd9f2255da332193f3784778eda8ca Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 30 Aug 2016 17:26:43 -0500 Subject: [PATCH 0721/1578] config_global.c: Comments and a default expression adjustment. Change-Id: Ia6a58f8c73a30da6874b3f94364dce162d6f1ad3 --- res/res_pjsip/config_global.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index 1d0c11c35c0..281630ae43a 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -76,21 +76,21 @@ struct global_config { /*! Realm to use in challenges before an endpoint is identified */ AST_STRING_FIELD(default_realm); ); - /* Value to put in Max-Forwards header */ + /*! Value to put in Max-Forwards header */ unsigned int max_forwards; - /* The interval at which to send keep alive messages to active connection-oriented transports */ + /*! The interval at which to send keep alive messages to active connection-oriented transports */ unsigned int keep_alive_interval; - /* The maximum time for all contacts to be qualified at startup */ + /*! The maximum time for all contacts to be qualified at startup */ unsigned int max_initial_qualify_time; - /* The interval at which to check for expired contacts */ + /*! The interval at which to check for expired contacts */ unsigned int contact_expiration_check_interval; /*! Nonzero to disable multi domain support */ unsigned int disable_multi_domain; - /* The maximum number of unidentified requests per source IP address before a security event is logged */ + /*! The maximum number of unidentified requests per source IP address before a security event is logged */ unsigned int unidentified_request_count; - /* The period during which unidentified requests are accumulated */ + /*! The period during which unidentified requests are accumulated */ unsigned int unidentified_request_period; - /* Interval at which expired unidentifed requests will be pruned */ + /*! Interval at which expired unidentifed requests will be pruned */ unsigned int unidentified_request_prune_interval; struct { /*! Taskprocessor high water alert trigger level */ @@ -510,7 +510,8 @@ int ast_sip_initialize_sorcery_global(void) ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval", __stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL), OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); - ast_sorcery_object_field_register(sorcery, "global", "disable_multi_domain", "no", + ast_sorcery_object_field_register(sorcery, "global", "disable_multi_domain", + DEFAULT_DISABLE_MULTI_DOMAIN ? "yes" : "no", OPT_BOOL_T, 1, FLDSET(struct global_config, disable_multi_domain)); ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_count", __stringify(DEFAULT_UNIDENTIFIED_REQUEST_COUNT), From 35ce4d25c7cd8312e1756069034a86b672b470f2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 29 Aug 2016 18:06:48 -0500 Subject: [PATCH 0722/1578] pjsip_configuration.c: Ignore repeated identify by methods. Change-Id: Ied0c06043d1dfef8fdc9c9a808cf89b118119838 --- res/res_pjsip/pjsip_configuration.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 333be71438a..d8ae9e0a343 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -603,6 +603,10 @@ static int ident_handler(const struct aco_option *opt, struct ast_variable *var, endpoint->ident_method = 0; return -1; } + if (endpoint->ident_method & method) { + /* We are already indentifying by this method. No need to do it again. */ + continue; + } endpoint->ident_method |= method; AST_VECTOR_APPEND(&endpoint->ident_method_order, method); From 68c7694abbf5a2d4dabd0d5a45678baf8b286e70 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 30 Aug 2016 16:40:59 -0500 Subject: [PATCH 0723/1578] res_pjsip_registrar.c: Reduce stack usage in find_aor_name(). Change-Id: I8aebad1fdcf303bd115b59a4b57fbbd5b2267f09 --- res/res_pjsip_registrar.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index f99a3b84dd4..6705f295d22 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -563,6 +563,7 @@ static int match_aor(const char *aor_name, const char *id) static char *find_aor_name(const char *username, const char *domain, const char *aors) { char *configured_aors; + char *aors_buf; char *aor_name; char *id_domain; struct ast_sip_domain_alias *alias; @@ -570,8 +571,10 @@ static char *find_aor_name(const char *username, const char *domain, const char id_domain = ast_alloca(strlen(username) + strlen(domain) + 2); sprintf(id_domain, "%s@%s", username, domain); + aors_buf = ast_strdupa(aors); + /* Look for exact match on username@domain */ - configured_aors = ast_strdupa(aors); + configured_aors = aors_buf; while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { if (match_aor(aor_name, id_domain)) { return ast_strdup(aor_name); @@ -586,7 +589,7 @@ static char *find_aor_name(const char *username, const char *domain, const char sprintf(id_domain, "%s@%s", username, alias->domain); ao2_cleanup(alias); - configured_aors = ast_strdupa(aors); + configured_aors = strcpy(aors_buf, aors);/* Safe */ while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { if (match_aor(aor_name, id_domain_alias)) { return ast_strdup(aor_name); @@ -594,8 +597,13 @@ static char *find_aor_name(const char *username, const char *domain, const char } } + if (ast_strlen_zero(username)) { + /* No username, no match */ + return NULL; + } + /* Look for exact match on username only */ - configured_aors = ast_strdupa(aors); + configured_aors = strcpy(aors_buf, aors);/* Safe */ while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { if (match_aor(aor_name, username)) { return ast_strdup(aor_name); From 6e1a3b924ed651e568af5834071c8b695fa9352a Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 3 Sep 2016 16:02:37 -0500 Subject: [PATCH 0724/1578] apps/app_dial: Set the DIALSTATUS to NOANSWER on privacy option 5 If the callee selects option '5' using the Dial application's privacy (P) option, the DIALSTATUS is erroneously set to ANSWER. This option reflects the callee sending the caller to VoiceMail one time; the call is definitely *not* ANSWERed in such a scenario. With this patch, the DIALSTATUS is instead set to NOANSWER, which is the same DIALSTATUS that is set when the 'send to VoiceMail every time' option is set. ASTERISK-25691 Change-Id: Iaf0c9f0fa00545e7366443875e2bb7d9a89a1358 --- apps/app_dial.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index 48193b5a0d6..c427faf6e16 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1919,9 +1919,10 @@ static int do_privacy(struct ast_channel *chan, struct ast_channel *peer, ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status)); break; case '5': - /* XXX should we set status to DENY ? */ - if (ast_test_flag64(opts, OPT_PRIVACY)) + if (ast_test_flag64(opts, OPT_PRIVACY)) { + ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status)); break; + } /* if not privacy, then 5 is the same as "default" case */ default: /* bad input or -1 if failure to start autoservice */ /* well, if the user messes up, ... he had his chance... What Is The Best Thing To Do? */ From 730cb3b0b741d294e7aecd22e64bb87094480063 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Sat, 3 Sep 2016 16:04:21 -0500 Subject: [PATCH 0725/1578] apps/app_dial: Fix crash on non-connect call paths for Privacy/Screening option In any scenario in which the callee is not connected to the caller, the current code in app_dial will crash due to raising a Dial End Stasis Message after the callee channel has been hung up. This patch corrects the error by simply moving the explicit hangup of the callee (peer) channel until after the dial end message. ASTERISK-25691 #close Change-Id: I816a414014424d0d8c80e2a3cbef13ef8c63798d --- apps/app_dial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index 48193b5a0d6..8ca69e6c43a 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1946,8 +1946,6 @@ static int do_privacy(struct ast_channel *chan, struct ast_channel *peer, } return 0; /* the good exit path */ } else { - /* hang up on the callee -- he didn't want to talk anyway! */ - ast_autoservice_chan_hangup_peer(chan, peer); return -1; } } @@ -2804,6 +2802,8 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) { if (do_privacy(chan, peer, &opts, opt_args, &pa)) { ast_channel_publish_dial(chan, peer, NULL, pa.status); + /* hang up on the callee -- he didn't want to talk anyway! */ + ast_autoservice_chan_hangup_peer(chan, peer); res = 0; goto out; } From d80b28560c9403033d3a35e8ec418f1ef0bb57d4 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Tue, 6 Sep 2016 09:41:06 +0200 Subject: [PATCH 0726/1578] chan_sip: Don't refuse calls with "optional crypto"; fall back to RTP. Certain SNOM phones send so-called "optional crypto" in their SDP body. Regular SRTP setup looks like this: m=audio 64620 RTP/SAVP 8 0 9 99 3 18 4 101 a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:... SNOM-style "optional crypto" looks like this: m=audio 61438 RTP/AVP 8 0 9 99 3 18 4 101 a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:... A crypto line is supplied, but the m-line does not have SAVP. When res_srtp.so is *not* loaded, then chan_sip.so treats the optional crypto as regular RTP, but when res_srtp.so *is* loaded, it refuses the incoming call with the following message: WARNING: process_sdp: Failed to receive SDP offer/answer with required SRTP crypto attributes for audio For platforms that want to start providing SRTP this presents a compatibility problem. This changeset lets chan_sip handle the SDP as if no crypto-line was supplied: i.e. accept the call as regular RTP, just like it did before res_srtp was loaded. Now you'll get this informative warning instead: WARNING: Ignoring crypto attribute in SDP because RTP transport is insecure ASTERISK-23989 #close Reported by: Olle Johansson Change-Id: I91a15ae05a0296e398d6b65f53bb11afde1d80e2 --- channels/chan_sip.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 6250731bd1d..6a18aa36b5f 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1479,7 +1479,8 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno); /*------ SRTP Support -------- */ -static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, const char *a); +static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, + const char *a, int secure_transport); /*------ T38 Support --------- */ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans); @@ -10609,7 +10610,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } } else if (process_sdp_a_sendonly(value, &sendonly)) { processed = TRUE; - } else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value)) { + } else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value, secure_audio)) { processed_crypto = TRUE; processed = TRUE; } else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec)) { @@ -10626,7 +10627,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action if (p->vsrtp) { ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK); } - } else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) { + } else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value, secure_video)) { processed_crypto = TRUE; processed = TRUE; } else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec)) { @@ -10639,7 +10640,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action processed = TRUE; } else if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec)) { processed = TRUE; - } else if (!processed_crypto && process_crypto(p, p->trtp, &p->tsrtp, value)) { + } else if (!processed_crypto && process_crypto(p, p->trtp, &p->tsrtp, value, 1)) { processed_crypto = TRUE; processed = TRUE; } @@ -33750,7 +33751,8 @@ static void sip_send_all_mwi_subscriptions(void) ao2_iterator_destroy(&iter); } -static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, const char *a) +static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, + const char *a, int secure_transport) { struct ast_rtp_engine_dtls *dtls; @@ -33766,6 +33768,23 @@ static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struc /* skip "crypto:" */ a += strlen("crypto:"); + if (!secure_transport) { + /* > The Secure Real-time Transport Protocol (SRTP) + * > [RFC3711] provides security services for RTP media + * > and is signaled by use of secure RTP transport (e.g., + * > "RTP/SAVP" or "RTP/SAVPF") in an SDP media (m=) line. + * > ... + * > The "crypto" attribute MUST only appear at the SDP + * > media level (not at the session level). + * + * Ergo, we can trust RTP/(S)AVP to be read from the m= + * line before we get here. If it was RTP/AVP, then this + * is SNOM-specific optional SRTP. Ignore it. + */ + ast_log(LOG_WARNING, "Ignoring crypto attribute in SDP because RTP transport is insecure\n"); + return FALSE; + } + if (!*srtp) { if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) { ast_log(LOG_WARNING, "Ignoring unexpected crypto attribute in SDP answer\n"); From 7bb7f7b9d52fdaf50a6e13bbe0529151f920ac08 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 18 Aug 2016 15:45:59 -0400 Subject: [PATCH 0727/1578] res_pjsip_session: segfault on already disconnected session On heavy loaded system the TCP/TLS incoming calls could be disconnected by pjproject while these calls are being processed by asterisk which could use the session's memory pools. If the session in the disconnected state then the session memory pools were already freed, so we get segfault. This patch adds a lifetime control on an INVITE session to pjproject. The lifetime of the session is manipulated by calling pjsip_inv_add_ref/pjsip_inv_dec_ref. This patch uses these functions to inform pjproject that the session is in use. This patch adds check if the session state is not disconnected and also checks if the memory pool is not NULL. This patch also places tasks 'session_end' and 'session_end_completion' into session's serializer to avoid race condition. ASTERISK-26291 #close Change-Id: I4d28b1fb3b91f0492a911d110049d670fdc3c8d7 --- configure | 123 ++++++++++ configure.ac | 2 + include/asterisk/autoconfig.h.in | 3 + res/res_pjsip_session.c | 71 +++++- third-party/pjproject/configure.m4 | 1 + ...-r5435-add-pjsip_inv_session-ref_cnt.patch | 212 ++++++++++++++++++ 6 files changed, 403 insertions(+), 9 deletions(-) create mode 100644 third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch diff --git a/configure b/configure index 3e5140ddb63..886ef6f9fa3 100755 --- a/configure +++ b/configure @@ -935,6 +935,10 @@ PBX_POPT POPT_DIR POPT_INCLUDE POPT_LIB +PBX_PJSIP_INV_SESSION_REF +PJSIP_INV_SESSION_REF_DIR +PJSIP_INV_SESSION_REF_INCLUDE +PJSIP_INV_SESSION_REF_LIB PBX_PJSIP_EVSUB_GRP_LOCK PJSIP_EVSUB_GRP_LOCK_DIR PJSIP_EVSUB_GRP_LOCK_INCLUDE @@ -11001,6 +11005,18 @@ PBX_PJSIP_EVSUB_GRP_LOCK=0 +PJSIP_INV_SESSION_REF_DESCRIP="PJSIP INVITE Session Reference Count support" +PJSIP_INV_SESSION_REF_OPTION=pjsip +PJSIP_INV_SESSION_REF_DIR=${PJPROJECT_DIR} + +PBX_PJSIP_INV_SESSION_REF=0 + + + + + + + POPT_DESCRIP="popt" POPT_OPTION="popt" @@ -25269,6 +25285,9 @@ $as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h $as_echo "#define HAVE_PJSIP_EVSUB_GRP_LOCK 1" >>confdefs.h +$as_echo "#define HAVE_PJSIP_INV_SESSION_REF 1" >>confdefs.h + + else if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then @@ -26089,6 +26108,110 @@ _ACEOF fi + +if test "x${PBX_PJSIP_INV_SESSION_REF}" != "x1" -a "${USE_PJSIP_INV_SESSION_REF}" != "no"; then + pbxlibdir="" + # if --with-PJSIP_INV_SESSION_REF=DIR has been specified, use it. + if test "x${PJSIP_INV_SESSION_REF_DIR}" != "x"; then + if test -d ${PJSIP_INV_SESSION_REF_DIR}/lib; then + pbxlibdir="-L${PJSIP_INV_SESSION_REF_DIR}/lib" + else + pbxlibdir="-L${PJSIP_INV_SESSION_REF_DIR}" + fi + fi + pbxfuncname="pjsip_inv_add_ref" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_PJSIP_INV_SESSION_REF_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS" + as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_PJSIP_INV_SESSION_REF_FOUND=yes +else + AST_PJSIP_INV_SESSION_REF_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_PJSIP_INV_SESSION_REF_FOUND}" = "yes"; then + PJSIP_INV_SESSION_REF_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB" + # if --with-PJSIP_INV_SESSION_REF=DIR has been specified, use it. + if test "x${PJSIP_INV_SESSION_REF_DIR}" != "x"; then + PJSIP_INV_SESSION_REF_INCLUDE="-I${PJSIP_INV_SESSION_REF_DIR}/include" + fi + PJSIP_INV_SESSION_REF_INCLUDE="${PJSIP_INV_SESSION_REF_INCLUDE} $PJPROJECT_CFLAGS" + if test "xpjsip.h" = "x" ; then # no header, assume found + PJSIP_INV_SESSION_REF_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${PJSIP_INV_SESSION_REF_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default" +if test "x$ac_cv_header_pjsip_h" = xyes; then : + PJSIP_INV_SESSION_REF_HEADER_FOUND=1 +else + PJSIP_INV_SESSION_REF_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${PJSIP_INV_SESSION_REF_HEADER_FOUND}" = "x0" ; then + PJSIP_INV_SESSION_REF_LIB="" + PJSIP_INV_SESSION_REF_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + PJSIP_INV_SESSION_REF_LIB="" + fi + PBX_PJSIP_INV_SESSION_REF=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_PJSIP_INV_SESSION_REF 1 +_ACEOF + + fi + fi +fi + + fi fi diff --git a/configure.ac b/configure.ac index 950cfc5a137..7fd702fee57 100644 --- a/configure.ac +++ b/configure.ac @@ -487,6 +487,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_fro AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EXTERNAL_RESOLVER], [PJSIP External Resolver Support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_PROTO], [PJSIP TLS Transport proto field support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_GRP_LOCK], [PJSIP EVSUB Group Lock support], [PJPROJECT], [pjsip]) +AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_SESSION_REF], [PJSIP INVITE Session Reference Count support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP([POPT], [popt], [popt]) AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio]) @@ -2210,6 +2211,7 @@ if test "$USE_PJPROJECT" != "no" ; then CPPFLAGS="${saved_cppflags}" AST_EXT_LIB_CHECK([PJSIP_EVSUB_GRP_LOCK], [pjsip], [pjsip_evsub_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJSIP_INV_SESSION_REF], [pjsip], [pjsip_inv_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) fi fi diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index f9a6b46e47c..5e7ea7e2ae3 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -598,6 +598,9 @@ /* Define if your system has pjsip_get_dest_info declared. */ #undef HAVE_PJSIP_GET_DEST_INFO +/* Define if your system has PJSIP_INV_SESSION_REF */ +#undef HAVE_PJSIP_INV_SESSION_REF + /* Define if your system has the PJSIP_REPLACE_MEDIA_STREAM headers. */ #undef HAVE_PJSIP_REPLACE_MEDIA_STREAM diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 315393fdb89..f54ee941199 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -213,6 +213,11 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd int i; int handled = 0; + if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) { + ast_log(LOG_ERROR, "Failed to handle incoming SDP. Session has been already disconnected\n"); + return -1; + } + for (i = 0; i < sdp->media_count; ++i) { /* See if there are registered handlers for this media stream type */ char media[20]; @@ -2087,6 +2092,16 @@ static int new_invite(void *data) * so that we will be notified so we can destroy the session properly */ + if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) { + ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n", + invite->session->inv_session->cause, + pjsip_get_status_text(invite->session->inv_session->cause)->ptr); +#ifdef HAVE_PJSIP_INV_SESSION_REF + pjsip_inv_dec_ref(invite->session->inv_session); +#endif + return -1; + } + switch (get_destination(invite->session, invite->rdata)) { case SIP_GET_DEST_EXTEN_FOUND: /* Things worked. Keep going */ @@ -2097,7 +2112,7 @@ static int new_invite(void *data) } else { pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE); } - return 0; + goto end; case SIP_GET_DEST_EXTEN_NOT_FOUND: case SIP_GET_DEST_EXTEN_PARTIAL: default: @@ -2110,7 +2125,7 @@ static int new_invite(void *data) } else { pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE); } - return 0; + goto end; }; if ((sdp_info = pjsip_rdata_get_sdp_info(invite->rdata)) && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) { @@ -2120,7 +2135,7 @@ static int new_invite(void *data) } else { pjsip_inv_terminate(invite->session->inv_session, 488, PJ_TRUE); } - return 0; + goto end; } /* We are creating a local SDP which is an answer to their offer */ local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp); @@ -2136,7 +2151,7 @@ static int new_invite(void *data) } else { pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); } - return 0; + goto end; } else { pjsip_inv_set_local_sdp(invite->session->inv_session, local); pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE); @@ -2153,12 +2168,16 @@ static int new_invite(void *data) /* At this point, we've verified what we can, so let's go ahead and send a 100 Trying out */ if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) { pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); - return 0; + goto end; } ast_sip_session_send_response(invite->session, tdata); handle_incoming_request(invite->session, invite->rdata); +end: +#ifdef HAVE_PJSIP_INV_SESSION_REF + pjsip_inv_dec_ref(invite->session->inv_session); +#endif return 0; } @@ -2179,6 +2198,20 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) return; } +#ifdef HAVE_PJSIP_INV_SESSION_REF + if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) { + ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); + if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) { + if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { + pjsip_inv_terminate(inv_session, 500, PJ_FALSE); + } else { + internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); + } + } + return; + } +#endif + session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata); if (!session) { if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { @@ -2186,6 +2219,9 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) } else { internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); } +#ifdef HAVE_PJSIP_INV_SESSION_REF + pjsip_inv_dec_ref(inv_session); +#endif return; } @@ -2196,6 +2232,9 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) } else { internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); } +#ifdef HAVE_PJSIP_INV_SESSION_REF + pjsip_inv_dec_ref(inv_session); +#endif ao2_cleanup(invite); } ao2_ref(session, -1); @@ -2467,8 +2506,9 @@ static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdat } } -static void session_end(struct ast_sip_session *session) +static int session_end(void *vsession) { + struct ast_sip_session *session = vsession; struct ast_sip_session_supplement *iter; /* Stop the scheduled termination */ @@ -2480,6 +2520,7 @@ static void session_end(struct ast_sip_session *session) iter->session_end(session); } } + return 0; } /*! @@ -2617,7 +2658,10 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) } if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - session_end(session); + if (ast_sip_push_task(session->serializer, session_end, session)) { + /* Do it anyway even though this is not the right thread. */ + session_end(session); + } } } @@ -2784,7 +2828,11 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans * Pass the session ref held by session->inv_session to * session_end_completion(). */ - session_end_completion(session); + if (session + && ast_sip_push_task(session->serializer, session_end_completion, session)) { + /* Do it anyway even though this is not the right thread. */ + session_end_completion(session); + } return; } break; @@ -2909,7 +2957,12 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru static const pj_str_t STR_IP6 = { "IP6", 3 }; pjmedia_sdp_session *local; - if (!(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) { + if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + ast_log(LOG_ERROR, "Failed to create session SDP. Session has been already disconnected\n"); + return NULL; + } + + if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) { return NULL; } diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 67ac04d4d86..7a079f6577f 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -45,4 +45,5 @@ AC_DEFUN([PJPROJECT_CONFIGURE], PJPROJECT_SYMBOL_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip_endpt_set_ext_resolver], [pjsip.h]) AC_DEFINE([HAVE_PJSIP_TLS_TRANSPORT_PROTO], 1, [Define if your system has PJSIP_TLS_TRANSPORT_PROTO]) AC_DEFINE([HAVE_PJSIP_EVSUB_GRP_LOCK], 1, [Define if your system has PJSIP_EVSUB_GRP_LOCK]) + AC_DEFINE([HAVE_PJSIP_INV_SESSION_REF], 1, [Define if your system has PJSIP_INV_SESSION_REF]) ]) diff --git a/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch b/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch new file mode 100644 index 00000000000..12ae6a0285f --- /dev/null +++ b/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch @@ -0,0 +1,212 @@ +When a transport error occured on an INVITE session +the stack calls on_tsx_state_changed with new state +PJSIP_INV_STATE_DISCONNECTED and immediately destroys +the INVITE session. +At the same time this INVITE session could being processed +on another thread. This thread could use the session's +memory pools which were already freed, so we get segfault. + +This patch adds a reference counter and new functions: +pjsip_inv_add_ref and pjsip_inv_dec_ref. +The INVITE session is destroyed only when the reference +counter has reached zero. + +To avoid race condition an application should call +pjsip_inv_add_ref/pjsip_inv_dec_ref. + +Index: pjsip/include/pjsip-ua/sip_inv.h +=================================================================== +--- a/pjsip/include/pjsip-ua/sip_inv.h (revision 5434) ++++ b/pjsip/include/pjsip-ua/sip_inv.h (revision 5435) +@@ -383,6 +383,11 @@ + * Other applications that want to use these pools must understand + * that the flip-flop pool's lifetimes are synchronized to the + * SDP offer-answer negotiation. ++ * ++ * The lifetime of this session is controlled by the reference counter in this ++ * structure, which is manipulated by calling #pjsip_inv_add_ref and ++ * #pjsip_inv_dec_ref. When the reference counter has reached zero, then ++ * this session will be destroyed. + */ + struct pjsip_inv_session + { +@@ -412,6 +417,7 @@ + struct pjsip_timer *timer; /**< Session Timers. */ + pj_bool_t following_fork; /**< Internal, following + forked media? */ ++ pj_atomic_t *ref_cnt; /**< Reference counter. */ + }; + + +@@ -631,6 +637,30 @@ + + + /** ++ * Add reference counter to the INVITE session. The reference counter controls ++ * the life time of the session, ie. when the counter reaches zero, then it ++ * will be destroyed. ++ * ++ * @param inv The INVITE session. ++ * @return PJ_SUCCESS if the INVITE session reference counter ++ * was increased. ++ */ ++PJ_DECL(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv ); ++ ++/** ++ * Decrement reference counter of the INVITE session. ++ * When the session is no longer used, it will be destroyed and ++ * caller is informed with PJ_EGONE return status. ++ * ++ * @param inv The INVITE session. ++ * @return PJ_SUCCESS if the INVITE session reference counter ++ * was decreased. A status PJ_EGONE will be returned to ++ * inform that session is destroyed. ++ */ ++PJ_DECL(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv ); ++ ++ ++/** + * Forcefully terminate and destroy INVITE session, regardless of + * the state of the session. Note that this function should only be used + * when there is failure in the INVITE session creation. After the +Index: pjsip/src/pjsip-ua/sip_inv.c +=================================================================== +--- a/pjsip/src/pjsip-ua/sip_inv.c (revision 5434) ++++ b/pjsip/src/pjsip-ua/sip_inv.c (revision 5435) +@@ -195,6 +195,65 @@ + } + + /* ++ * Add reference to INVITE session. ++ */ ++PJ_DEF(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv ) ++{ ++ PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL); ++ ++ pj_atomic_inc(inv->ref_cnt); ++ ++ return PJ_SUCCESS; ++} ++ ++static void inv_session_destroy(pjsip_inv_session *inv) ++{ ++ if (inv->last_ack) { ++ pjsip_tx_data_dec_ref(inv->last_ack); ++ inv->last_ack = NULL; ++ } ++ if (inv->invite_req) { ++ pjsip_tx_data_dec_ref(inv->invite_req); ++ inv->invite_req = NULL; ++ } ++ if (inv->pending_bye) { ++ pjsip_tx_data_dec_ref(inv->pending_bye); ++ inv->pending_bye = NULL; ++ } ++ pjsip_100rel_end_session(inv); ++ pjsip_timer_end_session(inv); ++ pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); ++ ++ /* Release the flip-flop pools */ ++ pj_pool_release(inv->pool_prov); ++ inv->pool_prov = NULL; ++ pj_pool_release(inv->pool_active); ++ inv->pool_active = NULL; ++ ++ pj_atomic_destroy(inv->ref_cnt); ++ inv->ref_cnt = NULL; ++} ++ ++/* ++ * Decrease INVITE session reference, destroy it when the reference count ++ * reaches zero. ++ */ ++PJ_DEF(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv ) ++{ ++ pj_atomic_value_t ref_cnt; ++ ++ PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL); ++ ++ ref_cnt = pj_atomic_dec_and_get(inv->ref_cnt); ++ pj_assert( ref_cnt >= 0); ++ if (ref_cnt == 0) { ++ inv_session_destroy(inv); ++ return PJ_EGONE; ++ } ++ return PJ_SUCCESS; ++} ++ ++/* + * Set session state. + */ + static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state, +@@ -261,27 +320,7 @@ + if (inv->state == PJSIP_INV_STATE_DISCONNECTED && + prev_state != PJSIP_INV_STATE_DISCONNECTED) + { +- if (inv->last_ack) { +- pjsip_tx_data_dec_ref(inv->last_ack); +- inv->last_ack = NULL; +- } +- if (inv->invite_req) { +- pjsip_tx_data_dec_ref(inv->invite_req); +- inv->invite_req = NULL; +- } +- if (inv->pending_bye) { +- pjsip_tx_data_dec_ref(inv->pending_bye); +- inv->pending_bye = NULL; +- } +- pjsip_100rel_end_session(inv); +- pjsip_timer_end_session(inv); +- pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); +- +- /* Release the flip-flop pools */ +- pj_pool_release(inv->pool_prov); +- inv->pool_prov = NULL; +- pj_pool_release(inv->pool_active); +- inv->pool_active = NULL; ++ pjsip_inv_dec_ref(inv); + } + } + +@@ -838,6 +877,12 @@ + inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session); + pj_assert(inv != NULL); + ++ status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt); ++ if (status != PJ_SUCCESS) { ++ pjsip_dlg_dec_lock(dlg); ++ return status; ++ } ++ + inv->pool = dlg->pool; + inv->role = PJSIP_ROLE_UAC; + inv->state = PJSIP_INV_STATE_NULL; +@@ -881,6 +926,7 @@ + pjsip_100rel_attach(inv); + + /* Done */ ++ pjsip_inv_add_ref(inv); + *p_inv = inv; + + pjsip_dlg_dec_lock(dlg); +@@ -1471,6 +1517,12 @@ + inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session); + pj_assert(inv != NULL); + ++ status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt); ++ if (status != PJ_SUCCESS) { ++ pjsip_dlg_dec_lock(dlg); ++ return status; ++ } ++ + inv->pool = dlg->pool; + inv->role = PJSIP_ROLE_UAS; + inv->state = PJSIP_INV_STATE_NULL; +@@ -1540,6 +1592,7 @@ + } + + /* Done */ ++ pjsip_inv_add_ref(inv); + pjsip_dlg_dec_lock(dlg); + *p_inv = inv; + From 6caf6bcdad003237725bf458a26db8ff74120508 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 1 Aug 2016 19:55:33 -0600 Subject: [PATCH 0728/1578] build: Add download capability for external packages The DPMA and g729a, silk, siren7 and siren14 codecs hosted at http://downloads.digium.com/pub/telephony/ are now listed in the "External" sections of the "Resource Modules" and "Codec Translators" pages in menuselect. Any that are selected will automatically be downloaded and installed when "make install" is run. Their LICENSE and README (if avaialble) files will be installed to ASTVARLIBDIR/documentation/thirdparty/. Example use with codecs: The codecs/codecs.xml file is a menuselect style xml file that lists the codecs to be included. Their support levels are 'external', which triggers the download and install, and defaultenabled is no. Also because codec_g729a is actually in a directory named codec_g729 on the download server, the newly added 'member_data' element is used to override the default of the directory name being the package name. You can use the 'directory_name' attribute to keep default base URL (http://downloads.digium.com/pub/telephony/) but use the new directory, or you use the 'remote_url' attribute to specify a full URL to the download directory. In this case, you must still follow the same subdirectory naming conventions as that used for the packages located at 'http://downloads.digium.com/pub/telephony'. A new configure option '--with-externals-cache' was added and like '--with-sounds-cache' it allows the installer to cache tarballs so they're not downloaded every time. To assist with the download and install process, each external package now has a manifest.xml file that, among other things, contains a package version and checksums for each file in the tarball. The manifest is saved to both the cache directory and ASTMODDIR and together with the manifest.xml on the downloads site, tells the install scripts whether a download and/or update is needed. bash and xmlstarlet are required for downloader operation. If they're not installed, the external items in menuselect will be unavailable. Change-Id: Id3dcf1289ffd3cb0bbd7dfab3cafbb87be60323a --- CHANGES | 11 ++ Makefile | 7 +- Makefile.moddir_rules | 12 ++ build_tools/download_externals | 180 +++++++++++++++++++++ build_tools/list_valid_installed_externals | 55 +++++++ build_tools/make_version | 4 +- build_tools/menuselect-deps.in | 2 + codecs/codecs.xml | 25 +++ configure | 86 ++++++++++ configure.ac | 16 ++ makeopts.in | 2 + res/res.xml | 6 + 12 files changed, 402 insertions(+), 4 deletions(-) create mode 100755 build_tools/download_externals create mode 100755 build_tools/list_valid_installed_externals create mode 100644 codecs/codecs.xml create mode 100644 res/res.xml diff --git a/CHANGES b/CHANGES index 5857165c8d7..7ca6b08d03c 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,17 @@ --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- ------------------------------------------------------------------------------ +Build System +------------------ + * The res_digium_phone, codec_g729a, codec_silk, codec_siren7 and + codec_siren14 binary modules hosted at downloads.digium.com can now be + automatically downloaded and installed during the Asterisk install + process. If selected in menuselect, when 'make install' is run, the + script will check the downloads site for a new version and download + and install it if needed. The '--with-externals-cache' option to + ./configure can be used to specify a location to cache the latest + tarballs so they don't have to be re-downloaded for every install. + app_voicemail ------------------ * Added "tps_queue_high" and "tps_queue_low" options. diff --git a/Makefile b/Makefile index bf8f0f89a11..992e1d3019a 100644 --- a/Makefile +++ b/Makefile @@ -618,9 +618,10 @@ $(SUBDIRS_INSTALL): NEWMODS:=$(foreach d,$(MOD_SUBDIRS),$(notdir $(wildcard $(d)/*.so))) OLDMODS=$(filter-out $(NEWMODS) $(notdir $(DESTDIR)$(ASTMODDIR)),$(notdir $(wildcard $(DESTDIR)$(ASTMODDIR)/*.so))) +BADMODS=$(strip $(filter-out $(shell ./build_tools/list_valid_installed_externals),$(OLDMODS))) oldmodcheck: - @if [ -n "$(OLDMODS)" ]; then \ + @if [ -n "$(BADMODS)" ]; then \ echo " WARNING WARNING WARNING" ;\ echo "" ;\ echo " Your Asterisk modules directory, located at" ;\ @@ -630,7 +631,7 @@ oldmodcheck: echo " modules are compatible with this version before" ;\ echo " attempting to run Asterisk." ;\ echo "" ;\ - for f in $(OLDMODS); do \ + for f in $(BADMODS); do \ echo " $$f" ;\ done ;\ echo "" ;\ @@ -980,7 +981,7 @@ menuselect/nmenuselect: menuselect/makeopts .lastclean menuselect/makeopts: makeopts .lastclean +$(MAKE_MENUSELECT) makeopts -menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts +menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc) $(wildcard $(dir)/*.xml)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts @echo "Generating input for menuselect ..." @echo "" > $@ @echo >> $@ diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules index 9b5f3f13a27..95e62788f2f 100644 --- a/Makefile.moddir_rules +++ b/Makefile.moddir_rules @@ -146,6 +146,18 @@ clean:: install:: all @echo "Installing modules from `basename $(CURDIR)`..." @for x in $(LOADABLE_MODS:%=%.so); do $(INSTALL) -m 755 $$x "$(DESTDIR)$(ASTMODDIR)" ; done +ifneq ($(findstring :,$(XMLSTARLET)$(BASH)),:) + @if [ -f .moduleinfo ] ; then \ + declare -A DISABLED_MODS ;\ + for x in $(MENUSELECT_$(MENUSELECT_CATEGORY)) ; do DISABLED_MODS[$${x}]=1 ; done ;\ + EXTERNAL_MODS=$$(xmlstarlet sel -t -m "/category/member[support_level = 'external']" -v "@name" -n .moduleinfo) ;\ + for x in $${EXTERNAL_MODS} ; do \ + if [ -z "$${DISABLED_MODS[$${x}]}" ] ; then \ + $(ASTTOPDIR)/build_tools/download_externals $${x} ;\ + fi ;\ + done ;\ + fi +endif uninstall:: diff --git a/build_tools/download_externals b/build_tools/download_externals new file mode 100755 index 00000000000..8d5872df799 --- /dev/null +++ b/build_tools/download_externals @@ -0,0 +1,180 @@ +#!/usr/bin/env bash + +if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO[0]} > 4 ]] ; then + shopt -s compat41 +fi +set -e + +ASTTOPDIR=${ASTTOPDIR:-.} + +module_name=$1 + +if [[ -z ${module_name} ]] ; then + echo "You must supply a module name." + exit 64 +fi + +tmpdir=$(mktemp -d) +if [[ -z "${tmpdir}" ]] ; then + echo "${module_name}: Unable to create temporary directory." + exit 1 +fi +trap "rm -rf ${tmpdir}" EXIT + +sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts +source ${tmpdir}/makeopts +if [[ -z "${ASTMODDIR}" ]] ; then + echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." + exit 1 +fi + +XMLSTARLET=${XMLSTARLET:-xmlstarlet} +if [[ "${XMLSTARLET}" = ":" ]] ; then + echo "${module_name}: The externals downloader requires xmlstarlet to be installed." + exit 1 +fi + +cache_dir="${EXTERNALS_CACHE_DIR}" +if [[ -z ${cache_dir} ]] ; then + cache_dir=${tmpdir} +fi + +version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR}) +if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then + echo "${module_name}: Couldn't parse version ${version}" + exit 1 +fi +major_version=${BASH_REMATCH[2]} + +if [[ "${major_version}" == "master" ]] ; then + echo "${module_name}: External module downloading is not available in the 'master' git branch. Please disable in menuselect and download manually." + exit 1 +fi + +major_version=${major_version}.0 + +if [[ "${HOST_CPU}" = "x86_64" ]] ; then + host_bits=64 +else + host_bits=32 +fi + +remote_url=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@remote_url" ${ASTTOPDIR}/menuselect-tree || :) +if [[ -n "${remote_url}" ]] ; then + remote_url="${remote_url}/asterisk-${major_version}/x86-${host_bits}" +else + directory_name=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@directory_name" ${ASTTOPDIR}/menuselect-tree || :) + remote_url="http://downloads.digium.com/pub/telephony/${directory_name:-${module_name}}/asterisk-${major_version}/x86-${host_bits}" +fi + +version_convert() { + local v=${1##*_} + if [[ ${v} =~ ([0-9]+)[.]([0-9]+)[.]([0-9]+) ]] ; then + v=$(( ${BASH_REMATCH[1]}<<18 | ${BASH_REMATCH[2]}<<9 | ${BASH_REMATCH[3]} )) + fi + echo ${v} +} + +${WGET} -q -O ${tmpdir}/manifest.xml ${remote_url}/manifest.xml || { + echo "${module_name}: Unable to fetch ${remote_url}/manifest.xml" + exit 1 +} + +rpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${tmpdir}/manifest.xml) +rpvi=$(version_convert ${rpv}) +echo "${module_name}: Remote package version ${rpv} (${rpvi})" + +module_dir=${module_name}-${rpv}-x86_${host_bits} +tarball=${module_dir}.tar.gz +export need_install=0 + +if [[ -f ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ]] ; then + package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) + ipv=$(${XMLSTARLET} sel -t -v "/package/@version" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) + ipvi=$(version_convert ${ipv}) + ip_major=${ipv%_*} + echo "${module_name}: Installed package version ${ipv} (${ipvi})" + if [[ "${ip_major}" != "${major_version}" || "${package_arch}" != "x86_${host_bits}" ]] ; then + echo "${module_name}: The installed package is not for this version of Asterisk. Reinstalling." + need_install=1 + elif [[ ${rpvi} > ${ipvi} ]] ; then + echo "${module_name}: A newer package is available" + need_install=1 + else + sums=$(${XMLSTARLET} sel -t -m "//file" -v "@md5sum" -n ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) + for sum in ${sums} ; do + install_path=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@install_path" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ) + f=${DESTDIR}$(eval echo ${install_path}) + if [[ ! -f ${f} ]] ; then + echo Not found: ${f} + need_install=1 + else + cs=$(md5sum ${f} | cut -b1-32) + if [[ "${cs}" != "${sum}" ]] ; then + echo Checksum mismatch: ${f} + need_install=1 + fi + fi + done + fi +else + need_install=1 +fi + +if [[ ${need_install} == 1 ]] ; then + if [[ ( -n "${ipvi}" ) && ${ipvi} > ${rpvi} ]] ; then + echo "${module_name}: Installed package is newer than that available for download." + exit 0 + fi +else + echo "${module_name} is up to date." + exit 0; +fi + +need_download=1 +if [[ -f ${cache_dir}/${module_name}.manifest.xml ]] ; then + cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${module_name}.manifest.xml) + cpvi=$(version_convert ${cpv}) + echo "${module_name}: Cached package version ${cpv} (${cpvi})" + if [[ ${cpvi} == ${rpvi} && ( -f ${cache_dir}/${tarball} ) ]] ; then + echo "${module_name}: Cached version is available." + need_download=0 + fi +fi + +if [[ ${need_download} = 1 ]] ; then + echo "${module_name}: Downloading ${remote_url}/${tarball}" + ${WGET} -q -O ${cache_dir}/${tarball} ${remote_url}/${tarball} || { + echo "${module_name}: Unable to fetch ${remote_url}/${tarball}" + exit 1 + } + cp ${tmpdir}/manifest.xml ${cache_dir}/${module_name}.manifest.xml +fi + +tar -xzf ${cache_dir}/${tarball} -C ${cache_dir} +trap "rm -rf ${cache_dir}/${module_dir} ; rm -rf ${tmpdir}" EXIT + +echo "${module_name}: Installing." + +if [[ $EUID == 0 ]] ; then + install_params="--group=0 --owner=0" +fi + +names=$(${XMLSTARLET} sel -t -m "//file" -v "@name" -n ${cache_dir}/${module_dir}/manifest.xml) +for name in ${names} ; do + source_path=${cache_dir}/${module_dir}/${name} + install_path=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@install_path" ${cache_dir}/${module_dir}/manifest.xml) + install_path=${DESTDIR}$(eval echo ${install_path}) + executable=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@executable" ${cache_dir}/${module_dir}/manifest.xml || :) + if [[ "${executable}" = "yes" ]] ; then + mode=0755 + else + mode=0644 + fi + + ${INSTALL} -Dp ${install_params} --mode=${mode} ${source_path} ${install_path} + +done +${INSTALL} -Dp ${install_params} --mode=0644 ${cache_dir}/${module_dir}/manifest.xml ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml + +echo "${module_name}: Installed." diff --git a/build_tools/list_valid_installed_externals b/build_tools/list_valid_installed_externals new file mode 100755 index 00000000000..12aff3f95a0 --- /dev/null +++ b/build_tools/list_valid_installed_externals @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO[0]} > 4 ]] ; then + shopt -s compat41 +fi +set -e + +ASTTOPDIR=${ASTTOPDIR:-.} + +tmpdir=$(mktemp -d) +if [[ -z "${tmpdir}" ]] ; then + echo "${module_name}: Unable to create temporary directory." + exit 1 +fi +trap "rm -rf ${tmpdir}" EXIT + +sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts +source ${tmpdir}/makeopts +if [[ -z "${ASTMODDIR}" ]] ; then + echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." + exit 1 +fi + +XMLSTARLET=${XMLSTARLET:-xmlstarlet} +if [[ "${XMLSTARLET}" = ":" ]] ; then + echo "${module_name}: The externals downloader requires xmlstarlet to be installed." + exit 1 +fi + +version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR}) +if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then + echo "${module_name}: Couldn't parse version ${version}" + exit 1 +fi +major_version=${BASH_REMATCH[2]}.0 + +if [[ "${HOST_CPU}" = "x86_64" ]] ; then + host_bits=64 +else + host_bits=32 +fi + +names="" +for manifest in ${DESTDIR}${ASTMODDIR}/*.manifest.xml ; do + if [ ! -f "$manifest" ] ; then + break + fi + package_version=$(${XMLSTARLET} sel -t -v "/package/@version" ${manifest}) + package_major_version=${package_version%_*} + package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${manifest}) + if [[ "$package_major_version" = "$major_version" && "${package_arch}" = "x86_${host_bits}" ]] ; then + names+=$(${XMLSTARLET} sel -t -m "//file[@executable = 'yes']" -v "concat(@name, ' ')" ${manifest}) + fi +done +echo $names diff --git a/build_tools/make_version b/build_tools/make_version index fd14a550aac..3e0f4a0b0fe 100755 --- a/build_tools/make_version +++ b/build_tools/make_version @@ -89,11 +89,13 @@ elif [ -d ${1}/.git ]; then if [ -z ${GIT} ]; then GIT="git" fi - + if ! command -v ${GIT} >/dev/null 2>&1; then echo "UNKNOWN__and_probably_unsupported" exit 1 fi + cd ${1} + # If the first log commit messages indicates that this is checked into # subversion, we'll just use the SVN- form of the revision. MODIFIED="" diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index a0444095556..9b077680e6d 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -31,6 +31,8 @@ KQUEUE=@PBX_KQUEUE@ LDAP=@PBX_LDAP@ LIBEDIT=@PBX_LIBEDIT@ LIBXML2=@PBX_LIBXML2@ +XMLSTARLET=@PBX_XMLSTARLET@ +BASH=@PBX_BASH@ LTDL=@PBX_LTDL@ LUA=@PBX_LUA@ MISDN=@PBX_MISDN@ diff --git a/codecs/codecs.xml b/codecs/codecs.xml new file mode 100644 index 00000000000..ac3c6e6389c --- /dev/null +++ b/codecs/codecs.xml @@ -0,0 +1,25 @@ + + external + xmlstarlet + bash + no + + + external + xmlstarlet + bash + no + + + external + xmlstarlet + bash + no + + + external + xmlstarlet + bash + no + + diff --git a/configure b/configure index 3e5140ddb63..6aecaa0c6ab 100755 --- a/configure +++ b/configure @@ -822,6 +822,7 @@ PBX_SPANDSP SPANDSP_DIR SPANDSP_INCLUDE SPANDSP_LIB +EXTERNALS_CACHE_DIR SOUNDS_CACHE_DIR PBX_SDL_IMAGE SDL_IMAGE_DIR @@ -1202,6 +1203,8 @@ PTHREAD_CC ax_pthread_config MD5 SOXMIX +PBX_BASH +PBX_XMLSTARLET PBX_FLEX PBX_BISON OPENSSL @@ -1211,6 +1214,7 @@ DOWNLOAD FETCH ALEMBIC GIT +BASH XMLSTARLET XMLLINT KPATHSEA @@ -1398,6 +1402,7 @@ with_resample with_sdl with_SDL_image with_sounds_cache +with_externals_cache with_spandsp with_ss7 with_speex @@ -2144,6 +2149,8 @@ Optional Packages: --with-SDL_image=PATH use Sdl Image files in PATH --with-sounds-cache=PATH use cached sound tarfiles in PATH + --with-externals-cache=PATH + use cached external module tarfiles in PATH --with-spandsp=PATH use SPANDSP files in PATH --with-ss7=PATH use ISDN SS7 files in PATH --with-speex=PATH use Speex files in PATH @@ -7489,6 +7496,47 @@ $as_echo "no" >&6; } fi +# Extract the first word of "bash", so it can be a program name with args. +set dummy bash; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BASH+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BASH in + [\\/]* | ?:[\\/]*) + ac_cv_path_BASH="$BASH" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BASH="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_BASH" && ac_cv_path_BASH=":" + ;; +esac +fi +BASH=$ac_cv_path_BASH +if test -n "$BASH"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BASH" >&5 +$as_echo "$BASH" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -7796,6 +7844,20 @@ else fi +if test "x${XMLSTARLET}" = "x:" ; then + PBX_XMLSTARLET=0 +else + PBX_XMLSTARLET=1 +fi + + +if test "x${BASH}" = "x:" ; then + PBX_BASH=0 +else + PBX_BASH=1 +fi + + if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}soxmix", so it can be a program name with args. set dummy ${ac_tool_prefix}soxmix; ac_word=$2 @@ -11526,6 +11588,30 @@ fi + +# Check whether --with-externals-cache was given. +if test "${with_externals_cache+set}" = set; then : + withval=$with_externals_cache; + case ${withval} in + n|no) + unset EXTERNALS_CACHE_DIR + ;; + *) + if test "x${withval}" = "x"; then + : + else + EXTERNALS_CACHE_DIR="${withval}" + fi + ;; + esac + +else + : +fi + + + + SPANDSP_DESCRIP="SPANDSP" SPANDSP_OPTION="spandsp" PBX_SPANDSP=0 diff --git a/configure.ac b/configure.ac index 950cfc5a137..4995d615b50 100644 --- a/configure.ac +++ b/configure.ac @@ -281,6 +281,7 @@ AC_PATH_PROG([CATDVI], [catdvi], :) AC_PATH_PROG([KPATHSEA], [kpsewhich], :) AC_PATH_PROG([XMLLINT], [xmllint], :) AC_PATH_PROG([XMLSTARLET], [xmlstarlet], :) +AC_PATH_PROG([BASH], [bash], :) AC_PATH_PROG([GIT], [git], :) AC_PATH_PROG([ALEMBIC], [alembic], :) if test "${WGET}" != ":" ; then @@ -340,6 +341,20 @@ else fi AC_SUBST(PBX_FLEX) +if test "x${XMLSTARLET}" = "x:" ; then + PBX_XMLSTARLET=0 +else + PBX_XMLSTARLET=1 +fi +AC_SUBST(PBX_XMLSTARLET) + +if test "x${BASH}" = "x:" ; then + PBX_BASH=0 +else + PBX_BASH=1 +fi +AC_SUBST(PBX_BASH) + AC_CHECK_TOOL([SOXMIX], [soxmix], [:]) if test "${SOXMIX}" != ":" ; then AC_DEFINE([HAVE_SOXMIX], 1, [Define to 1 if your system has soxmix application.]) @@ -521,6 +536,7 @@ AST_EXT_LIB_SETUP([RESAMPLE], [LIBRESAMPLE], [resample]) AST_EXT_LIB_SETUP([SDL], [Sdl], [sdl]) AST_EXT_LIB_SETUP([SDL_IMAGE], [Sdl Image], [SDL_image]) AST_OPTION_ONLY([sounds-cache], [SOUNDS_CACHE_DIR], [cached sound tarfiles], []) +AST_OPTION_ONLY([externals-cache], [EXTERNALS_CACHE_DIR], [cached external module tarfiles], []) AST_EXT_LIB_SETUP([SPANDSP], [SPANDSP], [spandsp]) AST_EXT_LIB_SETUP([SS7], [ISDN SS7], [ss7]) AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex]) diff --git a/makeopts.in b/makeopts.in index f0b0d0ef51d..86b7f9d99af 100644 --- a/makeopts.in +++ b/makeopts.in @@ -28,11 +28,13 @@ WGET=@WGET@ FETCH=@FETCH@ DOWNLOAD=@DOWNLOAD@ SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@ +EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@ RUBBER=@RUBBER@ CATDVI=@CATDVI@ KPATHSEA=@KPATHSEA@ XMLLINT=@XMLLINT@ XMLSTARLET=@XMLSTARLET@ +BASH=@BASH@ MD5=@MD5@ SHA1SUM=@SHA1SUM@ OPENSSL=@OPENSSL@ diff --git a/res/res.xml b/res/res.xml new file mode 100644 index 00000000000..e9cb5f962cf --- /dev/null +++ b/res/res.xml @@ -0,0 +1,6 @@ + + external + xmlstarlet + bash + no + From e769c19a31db0d9a64780c7370d22a6160b87ba3 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 6 Sep 2016 15:25:28 -0500 Subject: [PATCH 0729/1578] res/res_stasis_playback: Cancel the entire playlist when a stop occurs Prior to this patch, a stop issued by a delete of a Playback resource (indicated by the control frame AST_CONTROL_STREAM_STOP) would only stop the current media URI playing. Subsequent URIs specified by a playback operation would then proceed on, even though we had just indicated to the User that the Playback was finished *and* after they had just 'deleted' the resource. Whoops. This patch corrects it by bailing out of the sequence of URIs to play if one of them is terminated with an AST_CONTROL_STREAM_STOP indication. ASTERISK-26341 #close Change-Id: I2da9ec43545ba46cdfffe287c7e4907eae7fca42 --- res/res_stasis_playback.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index a64ecffa706..cfddb3af56d 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -370,6 +370,9 @@ static void play_on_channel(struct stasis_app_playback *playback, playback_final_update(playback, offsetms, res, ast_channel_uniqueid(chan)); + if (res == AST_CONTROL_STREAM_STOP) { + break; + } /* Reset offset for any subsequent media */ offsetms = 0; From baa7dba1806b6f894fccc94bc63f83020ee2345c Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 7 Sep 2016 10:59:26 +0000 Subject: [PATCH 0730/1578] res_resolver_unbound: Fix config documentation. The code was referencing the config section as 'globals' instead of 'general'. This change swaps it over to 'general'. Change-Id: I9dfe7788f41c4a6754c77e103880dc1a747de7fe --- res/res_resolver_unbound.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/res_resolver_unbound.c b/res/res_resolver_unbound.c index 40f3cfe4bf2..348e04f9340 100644 --- a/res/res_resolver_unbound.c +++ b/res/res_resolver_unbound.c @@ -44,8 +44,8 @@ ASTERISK_REGISTER_FILE() /*** DOCUMENTATION - - Options that apply globally to res_resolver_unbound + + General options for res_resolver_unbound Full path to an optional hosts file Hosts specified in a hosts file will be resolved within the resolver itself. If a value @@ -142,7 +142,7 @@ static void *unbound_config_alloc(void); /*! \brief An aco_type structure to link the "general" category to the unbound_global_config type */ static struct aco_type global_option = { .type = ACO_GLOBAL, - .name = "globals", + .name = "general", .item_offset = offsetof(struct unbound_config, global), .category_match = ACO_WHITELIST, .category = "^general$", From 7a12355dbdf7ee49713746d993c653f91b0fcbd0 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 19 Jul 2016 16:41:44 +0200 Subject: [PATCH 0731/1578] chan_sip: Allow Preferred sRTP. Following the Encrypt-all-the-things paradigm: The user enters his SIP-URI and password. Thanks to DNS-NAPTR, the phone determines SIP-over-TLS as preferred transport. In SIP/SDP, the phone starts the call with a crypto attribute, but not as RTP/sAVP but the RTP/AVP profile (sRTP is preferred aka optional; not mandatory). If the VoIP server does not support sRTP and TLS, the phone shows an open padlock icon. This paradigm is supported by several VoIP/SIP clients on default. Some implementations even cannot be changed to RTP/sAVP. Therefore here, this change allows Preferred sRTP for ingress. For egress, please, create a dial plan which starts with RTP/SAVP, and when rejected tries again with RTP/AVP. ASTERISK-20234 #close Reported by: tootai Tested by: tootai, Alexander Traud patches: srtp_patches.diff submitted by Matt Jordan Change-Id: I42cb779df3a9c7b3dd03a629fb3a296aa4ceb0fd --- CHANGES | 7 +++++++ channels/chan_sip.c | 35 +++++++++++++---------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/CHANGES b/CHANGES index 5857165c8d7..8a6c673bc9c 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,13 @@ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ +chan_sip +------------------ + * If an offer is received with optional SRTP (a media stream with RTP/AVP but + which contains a crypto line) chan_sip will now accept it and enable SRTP. + If you would like to do optional SRTP on outbound you will need to create + a dialplan that dials with it enabled initially and if it fails fall back to + without. ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 6a18aa36b5f..1d70e89753e 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1480,7 +1480,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc /*------ SRTP Support -------- */ static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, - const char *a, int secure_transport); + const char *a); /*------ T38 Support --------- */ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans); @@ -10610,9 +10610,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } } else if (process_sdp_a_sendonly(value, &sendonly)) { processed = TRUE; - } else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value, secure_audio)) { + } else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value)) { processed_crypto = TRUE; processed = TRUE; + if (secure_audio == FALSE) { + ast_log(AST_LOG_NOTICE, "Processed audio crypto attribute without SAVP specified; accepting anyway\n"); + secure_audio = TRUE; + } } else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec)) { processed = TRUE; } @@ -10627,9 +10631,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action if (p->vsrtp) { ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK); } - } else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value, secure_video)) { + } else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) { processed_crypto = TRUE; processed = TRUE; + if (secure_video == FALSE) { + ast_log(AST_LOG_NOTICE, "Processed video crypto attribute without SAVP specified; accepting anyway\n"); + secure_video = TRUE; + } } else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec)) { processed = TRUE; } @@ -10640,7 +10648,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action processed = TRUE; } else if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec)) { processed = TRUE; - } else if (!processed_crypto && process_crypto(p, p->trtp, &p->tsrtp, value, 1)) { + } else if (!processed_crypto && process_crypto(p, p->trtp, &p->tsrtp, value)) { processed_crypto = TRUE; processed = TRUE; } @@ -33752,7 +33760,7 @@ static void sip_send_all_mwi_subscriptions(void) } static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, - const char *a, int secure_transport) + const char *a) { struct ast_rtp_engine_dtls *dtls; @@ -33768,23 +33776,6 @@ static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struc /* skip "crypto:" */ a += strlen("crypto:"); - if (!secure_transport) { - /* > The Secure Real-time Transport Protocol (SRTP) - * > [RFC3711] provides security services for RTP media - * > and is signaled by use of secure RTP transport (e.g., - * > "RTP/SAVP" or "RTP/SAVPF") in an SDP media (m=) line. - * > ... - * > The "crypto" attribute MUST only appear at the SDP - * > media level (not at the session level). - * - * Ergo, we can trust RTP/(S)AVP to be read from the m= - * line before we get here. If it was RTP/AVP, then this - * is SNOM-specific optional SRTP. Ignore it. - */ - ast_log(LOG_WARNING, "Ignoring crypto attribute in SDP because RTP transport is insecure\n"); - return FALSE; - } - if (!*srtp) { if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) { ast_log(LOG_WARNING, "Ignoring unexpected crypto attribute in SDP answer\n"); From ac02bbd9a0bd7e36fa918685b6ed91ee25e10248 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 10 Aug 2016 15:14:09 -0500 Subject: [PATCH 0732/1578] ConfBridge: Make some announcements asynchronous. Confbridge announcements tend to block a channel while they are being played. In some circumstances, this is warranted since you want that particular channel not to hear the announcement (Example: "John Doe has entered the conference"). For others it makes less sense. This change first introduces methods for playing sounds asynchronously into the conference. This is very similar to how synchronous sounds are played, except the channel initiating the playback does not wait for the sound to complete before moving on. Asynchronous announcements are used for two circumstances: * Sounds played for a user after they have left the bridge * Sounds that play first to a single user and then the rest of the conference (if the channel and conference use the same language) ASTERISK-26289 #close Reported by Mark Michelson Change-Id: Ie486bb3de1646d50894489030326a423e594ab0a --- CHANGES | 6 + apps/app_confbridge.c | 370 ++++++++++++++++++++-- apps/confbridge/conf_state_multi_marked.c | 9 +- apps/confbridge/include/confbridge.h | 31 ++ 4 files changed, 375 insertions(+), 41 deletions(-) diff --git a/CHANGES b/CHANGES index 39e70cea51d..2851b2639ed 100644 --- a/CHANGES +++ b/CHANGES @@ -72,6 +72,12 @@ res_pjsip configure these options then you already had to do a reload after making changes. +app_confbridge +------------------ + * Some sounds played into the bridge are played asynchronously. This, for + instance, allows a channel to immediately exit the ConfBridge without having + to wait for a leave announcement to play. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index d5cbc41595a..a7fd92a3746 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1630,6 +1630,26 @@ static void leave_conference(struct confbridge_user *user) user->conference = NULL; } +static void playback_common(struct confbridge_conference *conference, const char *filename, int say_number) +{ + /* Don't try to play if the playback channel has been hung up */ + if (!conference->playback_chan) { + return; + } + + ast_autoservice_stop(conference->playback_chan); + + /* The channel is all under our control, in goes the prompt */ + if (!ast_strlen_zero(filename)) { + ast_stream_and_wait(conference->playback_chan, filename, ""); + } else if (say_number >= 0) { + ast_say_number(conference->playback_chan, say_number, "", + ast_channel_language(conference->playback_chan), NULL); + } + + ast_autoservice_start(conference->playback_chan); +} + struct playback_task_data { struct confbridge_conference *conference; const char *filename; @@ -1656,23 +1676,8 @@ static int playback_task(void *data) { struct playback_task_data *ptd = data; - /* Don't try to play if the playback channel has been hung up */ - if (!ptd->conference->playback_chan) { - goto end; - } - - ast_autoservice_stop(ptd->conference->playback_chan); + playback_common(ptd->conference, ptd->filename, ptd->say_number); - /* The channel is all under our control, in goes the prompt */ - if (!ast_strlen_zero(ptd->filename)) { - ast_stream_and_wait(ptd->conference->playback_chan, ptd->filename, ""); - } else if (ptd->say_number >= 0) { - ast_say_number(ptd->conference->playback_chan, ptd->say_number, "", - ast_channel_language(ptd->conference->playback_chan), NULL); - } - ast_autoservice_start(ptd->conference->playback_chan); - -end: ast_mutex_lock(&ptd->lock); ptd->playback_finished = 1; ast_cond_signal(&ptd->cond); @@ -1704,7 +1709,11 @@ static int play_sound_helper(struct confbridge_conference *conference, const cha struct playback_task_data ptd; /* Do not waste resources trying to play files that do not exist */ - if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) { + if (ast_strlen_zero(filename)) { + if (say_number < 0) { + return 0; + } + } else if (!sound_file_exists(filename)) { return 0; } @@ -1738,6 +1747,274 @@ int play_sound_file(struct confbridge_conference *conference, const char *filena return play_sound_helper(conference, filename, -1); } +struct async_playback_task_data { + struct confbridge_conference *conference; + int say_number; + struct ast_channel *initiator; + char filename[0]; +}; + +struct async_datastore_data { + ast_mutex_t lock; + ast_cond_t cond; + int wait; +}; + +static void async_datastore_data_destroy(void *data) +{ + struct async_datastore_data *add = data; + + ast_mutex_destroy(&add->lock); + ast_cond_destroy(&add->cond); + + ast_free(add); +} + +/*! + * \brief Datastore used for timing of async announcement playback + * + * Announcements that are played to the entire conference can be played + * asynchronously (i.e. The channel that queues the playback does not wait + * for the playback to complete before continuing) + * + * The thing about async announcements is that the channel that queues the + * announcement is either not in the bridge or is in some other way "occupied" + * at the time the announcement is queued. Because of that, the initiator of + * the announcement may enter after the announcement has already started, + * resulting in the sound being "clipped". + * + * This datastore makes it so that the channel that queues the async announcement + * can say "I'm ready now". This way the announcement does not start until the + * initiator of the announcement is ready to hear the sound. + */ +static struct ast_datastore_info async_datastore_info = { + .type = "Confbridge async playback", + .destroy = async_datastore_data_destroy, +}; + +static struct async_datastore_data *async_datastore_data_alloc(void) +{ + struct async_datastore_data *add; + + add = ast_malloc(sizeof(*add)); + if (!add) { + return NULL; + } + + ast_mutex_init(&add->lock); + ast_cond_init(&add->cond, NULL); + add->wait = 1; + + return add; +} + +/*! + * \brief Prepare the async playback datastore + * + * This is done prior to queuing an async announcement. If the + * datastore has not yet been created, it is allocated and initialized. + * If it already exists, we set it to be in "waiting" mode. + * + * \param initiator The channel that is queuing the async playback + * \retval 0 Success + * \retval -1 Failure :( + */ +static int setup_async_playback_datastore(struct ast_channel *initiator) +{ + struct ast_datastore *async_datastore; + + async_datastore = ast_channel_datastore_find(initiator, &async_datastore_info, NULL); + if (async_datastore) { + struct async_datastore_data *add; + + add = async_datastore->data; + add->wait = 1; + + return 0; + } + + async_datastore = ast_datastore_alloc(&async_datastore_info, NULL); + if (!async_datastore) { + return -1; + } + + async_datastore->data = async_datastore_data_alloc(); + if (!async_datastore->data) { + ast_datastore_free(async_datastore); + return -1; + } + + ast_channel_datastore_add(initiator, async_datastore); + return 0; +} + +static struct async_playback_task_data *async_playback_task_data_alloc( + struct confbridge_conference *conference, const char *filename, int say_number, + struct ast_channel *initiator) +{ + struct async_playback_task_data *aptd; + + aptd = ast_malloc(sizeof(*aptd) + strlen(filename) + 1); + if (!aptd) { + return NULL; + } + + /* Safe */ + strcpy(aptd->filename, filename); + aptd->say_number = say_number; + + /* You may think that we need to bump the conference refcount since we are pushing + * this task to the taskprocessor. + * + * In this case, that actually causes a problem. The destructor for the conference + * pushes a hangup task into the taskprocessor and waits for it to complete before + * continuing. If the destructor gets called from a taskprocessor task, we're + * deadlocked. + * + * So is there a risk of the conference being freed out from under us? No. Since + * the destructor pushes a task into the taskprocessor and waits for it to complete, + * the destructor cannot free the conference out from under us. No further tasks + * can be queued onto the taskprocessor after the hangup since no channels are referencing + * the conference at that point any more. + */ + aptd->conference = conference; + + aptd->initiator = initiator; + if (initiator) { + ast_channel_ref(initiator); + ast_channel_lock(aptd->initiator); + /* We don't really care if this fails. If the datastore fails to get set up + * we'll still play the announcement. It's possible that the sound will be + * clipped for the initiator, but that's not the end of the world. + */ + setup_async_playback_datastore(aptd->initiator); + ast_channel_unlock(aptd->initiator); + } + + return aptd; +} + +static void async_playback_task_data_destroy(struct async_playback_task_data *aptd) +{ + ast_channel_cleanup(aptd->initiator); + ast_free(aptd); +} + +/*! + * \brief Wait for the initiator of an async playback to be ready + * + * See the description on the async_datastore_info structure for more + * information about what this is about. + * + * \param initiator The channel that queued the async announcement + */ +static void wait_for_initiator(struct ast_channel *initiator) +{ + struct ast_datastore *async_datastore; + struct async_datastore_data *add; + + ast_channel_lock(initiator); + async_datastore = ast_channel_datastore_find(initiator, &async_datastore_info, NULL); + ast_channel_unlock(initiator); + + if (!async_datastore) { + return; + } + + add = async_datastore->data; + + ast_mutex_lock(&add->lock); + while (add->wait) { + ast_cond_wait(&add->cond, &add->lock); + } + ast_mutex_unlock(&add->lock); +} + +/*! + * \brief Play an announcement into a confbridge asynchronously + * + * This runs in the playback queue taskprocessor. This ensures that + * all playbacks are handled in sequence and do not play over top one + * another. + * + * \param data An async_playback_task_data + * \return 0 + */ +static int async_playback_task(void *data) +{ + struct async_playback_task_data *aptd = data; + + /* Wait for the initiator to get back in the bridge or be hung up */ + if (aptd->initiator) { + wait_for_initiator(aptd->initiator); + } + + playback_common(aptd->conference, aptd->filename, aptd->say_number); + + async_playback_task_data_destroy(aptd); + return 0; +} + +static int async_play_sound_helper(struct confbridge_conference *conference, + const char *filename, int say_number, struct ast_channel *initiator) +{ + struct async_playback_task_data *aptd; + + /* Do not waste resources trying to play files that do not exist */ + if (ast_strlen_zero(filename)) { + if (say_number < 0) { + return 0; + } + } else if (!sound_file_exists(filename)) { + return 0; + } + + aptd = async_playback_task_data_alloc(conference, filename, say_number, initiator); + if (!aptd) { + return -1; + } + + if (ast_taskprocessor_push(conference->playback_queue, async_playback_task, aptd)) { + if (!ast_strlen_zero(filename)) { + ast_log(LOG_WARNING, "Unable to play file '%s' to conference '%s'\n", + filename, conference->name); + } else { + ast_log(LOG_WARNING, "Unable to say number '%d' to conference '%s'\n", + say_number, conference->name); + } + async_playback_task_data_destroy(aptd); + return -1; + } + + return 0; +} + +int async_play_sound_file(struct confbridge_conference *conference, + const char *filename, struct ast_channel *initiator) +{ + return async_play_sound_helper(conference, filename, -1, initiator); +} + +void async_play_sound_ready(struct ast_channel *chan) +{ + struct ast_datastore *async_datastore; + struct async_datastore_data *add; + + ast_channel_lock(chan); + async_datastore = ast_channel_datastore_find(chan, &async_datastore_info, NULL); + ast_channel_unlock(chan); + if (!async_datastore) { + return; + } + + add = async_datastore->data; + + ast_mutex_lock(&add->lock); + add->wait = 0; + ast_cond_signal(&add->cond); + ast_mutex_unlock(&add->lock); +} + /*! * \brief Play number into the conference bridge * @@ -1869,6 +2146,12 @@ static int conf_rec_name(struct confbridge_user *user, const char *conf_name) return 0; } +static int join_callback(struct ast_bridge_channel *bridge_channel, void *ignore) +{ + async_play_sound_ready(bridge_channel->chan); + return 0; +} + /*! \brief The ConfBridge application */ static int confbridge_exec(struct ast_channel *chan, const char *data) { @@ -2047,10 +2330,14 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) if (!quiet) { const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference->b_profile.sounds); - ast_stream_and_wait(chan, join_sound, ""); - ast_autoservice_start(chan); - play_sound_file(conference, join_sound); - ast_autoservice_stop(chan); + if (strcmp(conference->b_profile.language, ast_channel_language(chan))) { + ast_stream_and_wait(chan, join_sound, ""); + ast_autoservice_start(chan); + play_sound_file(conference, join_sound); + ast_autoservice_stop(chan); + } else { + async_play_sound_file(conference, join_sound, chan); + } } if (user.u_profile.timeout) { @@ -2070,6 +2357,11 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) /* Join our conference bridge for real */ send_join_event(&user, conference); + + if (ast_bridge_join_hook(&user.features, join_callback, NULL, NULL, 0)) { + async_play_sound_ready(user.chan); + } + ast_bridge_join(conference->bridge, chan, NULL, @@ -2077,6 +2369,11 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) &user.tech_args, 0); + /* This is a catch-all in case joining the bridge failed or for some reason + * an async announcement got queued up and hasn't been told to play yet + */ + async_play_sound_ready(chan); + if (!user.kicked && ast_check_hangup(chan)) { pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "HANGUP"); } @@ -2101,19 +2398,15 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) /* if this user has a intro, play it when leaving */ if (!quiet && !ast_strlen_zero(user.name_rec_location)) { - ast_autoservice_start(chan); - play_sound_file(conference, user.name_rec_location); - play_sound_file(conference, - conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds)); - ast_autoservice_stop(chan); + async_play_sound_file(conference, user.name_rec_location, NULL); + async_play_sound_file(conference, + conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds), NULL); } /* play the leave sound */ if (!quiet) { const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference->b_profile.sounds); - ast_autoservice_start(chan); - play_sound_file(conference, leave_sound); - ast_autoservice_stop(chan); + async_play_sound_file(conference, leave_sound, NULL); } /* If the user was kicked from the conference play back the audio prompt for it */ @@ -2186,13 +2479,18 @@ static int action_toggle_mute_participants(struct confbridge_conference *confere mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED, conference->b_profile.sounds); - /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */ - ast_stream_and_wait(user->chan, sound_to_play, ""); + if (strcmp(conference->b_profile.language, ast_channel_language(user->chan))) { + /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */ + ast_stream_and_wait(user->chan, sound_to_play, ""); - /* Announce to the group that all participants are muted */ - ast_autoservice_start(user->chan); - play_sound_helper(conference, sound_to_play, 0); - ast_autoservice_stop(user->chan); + /* Announce to the group that all participants are muted */ + ast_autoservice_start(user->chan); + play_sound_file(conference, sound_to_play); + ast_autoservice_stop(user->chan); + } else { + /* Playing the sound asynchronously lets the sound be heard by everyone at once */ + async_play_sound_file(conference, sound_to_play, user->chan); + } return 0; } @@ -2477,6 +2775,8 @@ int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel, /* See if music on hold needs to be started back up again */ conf_moh_unsuspend(user); + async_play_sound_ready(bridge_channel->chan); + return 0; } diff --git a/apps/confbridge/conf_state_multi_marked.c b/apps/confbridge/conf_state_multi_marked.c index fabe99b9054..17ca65cc21d 100644 --- a/apps/confbridge/conf_state_multi_marked.c +++ b/apps/confbridge/conf_state_multi_marked.c @@ -160,12 +160,9 @@ static void leave_marked(struct confbridge_user *user) if (need_prompt) { /* Play back the audio prompt saying the leader has left the conference */ if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET)) { - ao2_unlock(user->conference); - ast_autoservice_start(user->chan); - play_sound_file(user->conference, - conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, user->conference->b_profile.sounds)); - ast_autoservice_stop(user->chan); - ao2_lock(user->conference); + async_play_sound_file(user->conference, + conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, user->conference->b_profile.sounds), + NULL); } AST_LIST_TRAVERSE(&user->conference->waiting_list, user_iter, list) { diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 5d71a63bccd..93cac3a72f0 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -389,6 +389,37 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data */ int play_sound_file(struct confbridge_conference *conference, const char *filename); +/*! + * \brief Play sound file into conference bridge asynchronously + * + * If the initiator parameter is non-NULL, then the playback will wait for + * that initiator channel to get back in the bridge before playing the sound + * file. This way, the initiator has no danger of hearing a "clipped" file. + * + * \param conference The conference bridge to play sound file into + * \param filename Sound file to play + * \param initiator Channel that initiated playback. + * + * \retval 0 success + * \retval -1 failure + */ +int async_play_sound_file(struct confbridge_conference *conference, const char *filename, + struct ast_channel *initiator); + +/*! + * \brief Indicate the initiator of an async sound file is ready for it to play. + * + * When playing an async sound file, the initiator is typically either out of the bridge + * or not in a position to hear the queued announcement. This function lets the announcement + * thread know that the initiator is now ready for the sound to play. + * + * If an async announcement was queued and no initiator channel was provided, then this is + * a no-op + * + * \param chan The channel that initiated the async announcement + */ +void async_play_sound_ready(struct ast_channel *chan); + /*! \brief Callback to be called when the conference has become empty * \param conference The conference bridge */ From 2e5da0c715456d48b70b1afc6f089a0c19d98983 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 7 Sep 2016 21:00:16 +0000 Subject: [PATCH 0733/1578] res_pjsip: Allow global headers to be overridden. Currently when you add global headers from the dialplan both the header in the dialplan and the globally configured header are added to the resulting SIP INVITE. This change makes it so the headers in the dialplan take precedence and are the only ones added. Change-Id: I36f864298f38db3632ad503edc11267cb8ffb3ad --- res/res_pjsip/pjsip_global_headers.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/res/res_pjsip/pjsip_global_headers.c b/res/res_pjsip/pjsip_global_headers.c index 735008dcc8b..501f5f5237d 100644 --- a/res/res_pjsip/pjsip_global_headers.c +++ b/res/res_pjsip/pjsip_global_headers.c @@ -87,6 +87,14 @@ static void add_headers_to_message(struct header_list *headers, pjsip_tx_data *t return; } AST_LIST_TRAVERSE(headers, iter, next) { + pj_str_t name; + pjsip_generic_string_hdr *hdr; + + hdr = pjsip_msg_find_hdr_by_name(tdata->msg, pj_cstr(&name, iter->name), NULL); + if (hdr) { + continue; + } + ast_sip_add_header(tdata, iter->name, iter->value); }; tdata->mod_data[global_header_mod.id] = &handled_id; From f369dbb705fb92a410e5ffb25ace1756074ccf22 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 6 Sep 2016 11:46:16 -0500 Subject: [PATCH 0734/1578] res_pjsip_messaging.c: Misc cleanups and fixes. * Eliminated RAII_VAR in get_outbound_endpoint(). * Simplify update_to() coding. However, this function can only be a NoOp because the To string can only be a URI and not a name-address formatted string. * Simplify update_from() coding. Also fixed a code path modifying the from string when the caller could still want to use the original string. * Fixed msg_data_create() incompletely removing the "pjsip:" to then add back the "sip:" string if needed. The code didn't handle the "pjsip:sip:" case because it left the colon after pjsip in the string. Change-Id: I68a09a665f6d4daa9eaa59069045ab69122e28db --- res/res_pjsip_messaging.c | 122 ++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 51 deletions(-) diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index 7efb1a20e6c..1e763da8a27 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -106,8 +106,9 @@ static const char *skip_sip(const char *fromto) * * Expects the given 'to' to be in one of the following formats: * sip[s]:endpoint[/aor] - * sip[s]:endpoint[/uri] - * sip[s]:uri <-- will use default outbound endpoint + * sip[s]:endpoint[/uri] - Where uri is: sip[s]:user@domain + * sip[s]:endpoint[@domain] + * sip[s]:unknown_user@domain <-- will use default outbound endpoint * * If an optional aor is given it will try to find an associated uri * to return. If an optional uri is given then that will be returned, @@ -116,50 +117,60 @@ static const char *skip_sip(const char *fromto) * \param to 'From' or 'To' field with possible endpoint * \param uri Optional uri to return */ -static struct ast_sip_endpoint* get_outbound_endpoint( - const char *to, char **uri) +static struct ast_sip_endpoint *get_outbound_endpoint(const char *to, char **uri) { - char *name, *aor_uri; - struct ast_sip_endpoint* endpoint; - RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); + char *name; + char *aor_uri; + struct ast_sip_endpoint *endpoint; name = ast_strdupa(skip_sip(to)); /* attempt to extract the endpoint name */ if ((aor_uri = strchr(name, '/'))) { - /* format was 'endpoint/' */ + /* format was 'endpoint/(aor_name | uri)' */ *aor_uri++ = '\0'; } else if ((aor_uri = strchr(name, '@'))) { - /* format was 'endpoint@' - don't use the rest */ + /* format was 'endpoint@domain' - discard the domain */ *aor_uri = '\0'; } /* at this point, if name is not empty then it might be an endpoint, so try to retrieve it */ - if (ast_strlen_zero(name) || !(endpoint = ast_sorcery_retrieve_by_id( - ast_sip_get_sorcery(), "endpoint", name))) { + if (ast_strlen_zero(name) + || !(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + name))) { /* an endpoint was not found, so assume sending directly to a uri and use the default outbound endpoint */ *uri = ast_strdup(to); return ast_sip_default_outbound_endpoint(); } - *uri = aor_uri; - if (*uri) { - char *end = strchr(*uri, '>'); + if (ast_strlen_zero(aor_uri)) { + *uri = NULL; + } else { + struct ast_sip_aor *aor; + struct ast_sip_contact *contact = NULL; + char *end; + + /* Trim off any stray angle bracket that shouldn't be here */ + end = strchr(aor_uri, '>'); if (end) { - *end++ = '\0'; + *end = '\0'; } - /* if what's in 'uri' is a retrievable aor use the uri on it - instead, otherwise assume what's there is already a uri*/ - if ((aor = ast_sip_location_retrieve_aor(*uri)) && - (contact = ast_sip_location_retrieve_first_aor_contact(aor))) { - *uri = (char*)contact->uri; + /* + * if what's in 'uri' is a retrievable aor use the uri on it + * instead, otherwise assume what's there is already a uri + */ + aor = ast_sip_location_retrieve_aor(aor_uri); + if (aor && (contact = ast_sip_location_retrieve_first_aor_contact(aor))) { + aor_uri = (char *) contact->uri; } /* need to copy because underlying uri goes away */ - *uri = ast_strdup(*uri); + *uri = ast_strdup(aor_uri); + + ao2_cleanup(contact); + ao2_cleanup(aor); } return endpoint; @@ -176,16 +187,16 @@ static struct ast_sip_endpoint* get_outbound_endpoint( */ static void update_to(pjsip_tx_data *tdata, char *to) { - pjsip_name_addr *name_addr = (pjsip_name_addr *) - PJSIP_MSG_TO_HDR(tdata->msg)->uri; - pjsip_uri *parsed; + pjsip_name_addr *parsed_name_addr; - if ((parsed = pjsip_parse_uri(tdata->pool, to, strlen(to), - PJSIP_PARSE_URI_AS_NAMEADDR))) { - pjsip_name_addr *parsed_name_addr = (pjsip_name_addr *)parsed; + parsed_name_addr = (pjsip_name_addr *) pjsip_parse_uri(tdata->pool, to, strlen(to), + PJSIP_PARSE_URI_AS_NAMEADDR); + if (parsed_name_addr) { if (pj_strlen(&parsed_name_addr->display)) { - pj_strdup(tdata->pool, &name_addr->display, - &parsed_name_addr->display); + pjsip_name_addr *name_addr = + (pjsip_name_addr *) PJSIP_MSG_TO_HDR(tdata->msg)->uri; + + pj_strdup(tdata->pool, &name_addr->display, &parsed_name_addr->display); } } } @@ -204,22 +215,24 @@ static void update_to(pjsip_tx_data *tdata, char *to) */ static void update_from(pjsip_tx_data *tdata, char *from) { - pjsip_name_addr *name_addr = (pjsip_name_addr *) - PJSIP_MSG_FROM_HDR(tdata->msg)->uri; - pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr); - pjsip_uri *parsed; + pjsip_name_addr *name_addr; + pjsip_sip_uri *uri; + pjsip_name_addr *parsed_name_addr; if (ast_strlen_zero(from)) { return; } - if ((parsed = pjsip_parse_uri(tdata->pool, from, strlen(from), - PJSIP_PARSE_URI_AS_NAMEADDR))) { - pjsip_name_addr *parsed_name_addr = (pjsip_name_addr *)parsed; + name_addr = (pjsip_name_addr *) PJSIP_MSG_FROM_HDR(tdata->msg)->uri; + uri = pjsip_uri_get_uri(name_addr); + + parsed_name_addr = (pjsip_name_addr *) pjsip_parse_uri(tdata->pool, from, + strlen(from), PJSIP_PARSE_URI_AS_NAMEADDR); + if (parsed_name_addr) { pjsip_sip_uri *parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri); + if (pj_strlen(&parsed_name_addr->display)) { - pj_strdup(tdata->pool, &name_addr->display, - &parsed_name_addr->display); + pj_strdup(tdata->pool, &name_addr->display, &parsed_name_addr->display); } pj_strdup(tdata->pool, &uri->user, &parsed_uri->user); @@ -228,11 +241,17 @@ static void update_from(pjsip_tx_data *tdata, char *from) } else { /* assume it is 'user[@domain]' format */ char *domain = strchr(from, '@'); + if (domain) { - *domain++ = '\0'; - pj_strdup2(tdata->pool, &uri->host, domain); + pj_str_t pj_from; + + pj_strset3(&pj_from, from, domain); + pj_strdup(tdata->pool, &uri->user, &pj_from); + + pj_strdup2(tdata->pool, &uri->host, domain + 1); + } else { + pj_strdup2(tdata->pool, &uri->user, from); } - pj_strdup2(tdata->pool, &uri->user, from); } } @@ -526,7 +545,7 @@ static void msg_data_destroy(void *obj) ast_msg_destroy(mdata->msg); } -static struct msg_data* msg_data_create(const struct ast_msg *msg, const char *to, const char *from) +static struct msg_data *msg_data_create(const struct ast_msg *msg, const char *to, const char *from) { char *tag; struct msg_data *mdata = ao2_alloc(sizeof(*mdata), msg_data_destroy); @@ -536,17 +555,17 @@ static struct msg_data* msg_data_create(const struct ast_msg *msg, const char *t } /* typecast to suppress const warning */ - mdata->msg = ast_msg_ref((struct ast_msg*)msg); + mdata->msg = ast_msg_ref((struct ast_msg *) msg); - /* starts with 'pjsip:' the 'pj' needs to be removed and maybe even - the entire string. */ + /* To starts with 'pjsip:' which needs to be removed. */ if (!(to = strchr(to, ':'))) { ao2_ref(mdata, -1); return NULL; } + ++to;/* Now skip the ':' */ /* Make sure we start with sip: */ - mdata->to = ast_begins_with(to, "sip:") ? ast_strdup(++to) : ast_strdup(to - 3); + mdata->to = ast_begins_with(to, "sip:") ? ast_strdup(to) : ast_strdup(to - 4); mdata->from = ast_strdup(from); if (!mdata->to || !mdata->from) { ao2_ref(mdata, -1); @@ -572,12 +591,13 @@ static int msg_send(void *data) pjsip_tx_data *tdata; RAII_VAR(char *, uri, NULL, ast_free); - RAII_VAR(struct ast_sip_endpoint *, endpoint, get_outbound_endpoint( - mdata->to, &uri), ao2_cleanup); + RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); + endpoint = get_outbound_endpoint(mdata->to, &uri); if (!endpoint) { - ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint '%s' and " - "no default outbound endpoint configured\n", mdata->to); + ast_log(LOG_ERROR, + "PJSIP MESSAGE - Could not find endpoint '%s' and no default outbound endpoint configured\n", + mdata->to); return -1; } From 82a3d659dceb3300acde2c3908f97a0e2bf2d6b3 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 23 Aug 2016 11:35:11 +0000 Subject: [PATCH 0735/1578] chan_sip: Don't allocate new RTP instances on top of old ones. In some scenarios dialog_initialize_rtp can be called multiple times on the same dialog. This can cause RTP instances to be leaked along with multiple file descriptors for each instance. This change makes it so the existing RTP instances are destroyed and not overwritten, stopping the memory leak. ASTERISK-26272 #close patches: ASTERISK-26272-13.patch submitted by Corey Farrell (license 5909) Change-Id: Id529de1184c68f2f4d254ab41a1f458dafdb5f73 --- channels/chan_sip.c | 61 +++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 1d70e89753e..28ba05f51ff 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -5875,6 +5875,38 @@ static void copy_socket_data(struct sip_socket *to_sock, const struct sip_socket *to_sock = *from_sock; } +/*! Cleanup the RTP and SRTP portions of a dialog + * + * \note This procedure excludes vsrtp as it is initialized differently. + */ +static void dialog_clean_rtp(struct sip_pvt *p) +{ + if (p->rtp) { + ast_rtp_instance_destroy(p->rtp); + p->rtp = NULL; + } + + if (p->vrtp) { + ast_rtp_instance_destroy(p->vrtp); + p->vrtp = NULL; + } + + if (p->trtp) { + ast_rtp_instance_destroy(p->trtp); + p->trtp = NULL; + } + + if (p->srtp) { + ast_sdp_srtp_destroy(p->srtp); + p->srtp = NULL; + } + + if (p->tsrtp) { + ast_sdp_srtp_destroy(p->tsrtp); + p->tsrtp = NULL; + } +} + /*! \brief Initialize DTLS-SRTP support on an RTP instance */ static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp) { @@ -5928,6 +5960,9 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) ast_sockaddr_copy(&bindaddr_tmp, &bindaddr); } + /* Make sure previous RTP instances/FD's do not leak */ + dialog_clean_rtp(dialog); + if (!(dialog->rtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) { return -1; } @@ -6603,18 +6638,10 @@ static void sip_pvt_dtor(void *vdoomed) ast_free(p->notify); p->notify = NULL; } - if (p->rtp) { - ast_rtp_instance_destroy(p->rtp); - p->rtp = NULL; - } - if (p->vrtp) { - ast_rtp_instance_destroy(p->vrtp); - p->vrtp = NULL; - } - if (p->trtp) { - ast_rtp_instance_destroy(p->trtp); - p->trtp = NULL; - } + + /* Free RTP and SRTP instances */ + dialog_clean_rtp(p); + if (p->udptl) { ast_udptl_destroy(p->udptl); p->udptl = NULL; @@ -6647,21 +6674,11 @@ static void sip_pvt_dtor(void *vdoomed) destroy_msg_headers(p); - if (p->srtp) { - ast_sdp_srtp_destroy(p->srtp); - p->srtp = NULL; - } - if (p->vsrtp) { ast_sdp_srtp_destroy(p->vsrtp); p->vsrtp = NULL; } - if (p->tsrtp) { - ast_sdp_srtp_destroy(p->tsrtp); - p->tsrtp = NULL; - } - if (p->directmediaacl) { p->directmediaacl = ast_free_acl_list(p->directmediaacl); } From 28b2aeba0ba14d915d13ee719b9fce84ccb92ea2 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 16 Aug 2016 15:34:53 -0500 Subject: [PATCH 0736/1578] res_pjsip: Do not crash on ACKs from unknown endpoints. The endpoint identification PJSIP module is intended to identify which endpoint an incoming request is from. If an endpoint is not identified, then an artificial endpoint is used in its place when proceeding. The problem is that the ACK request type is an exception to the rule. The artificial endpoint is not used when processing an ACK. This results in the possibility of having a NULL endpoint being used further on. The reason ACK is an exception is an attempt not to spam security logs with unidentified requests. Presumably, you've already logged the unidentified request on the preceeding INVITE. Up until Asterisk 13.10, retrieving a NULL endpoint in this fashion didn't cause an issue. A new change in 13.10 added endpoint ACL checking shortly after endpoint identification. Because we are accessing a NULL endpoint, this ACL check resulted in a crash. The fix here is to be sure to retrieve the artificial endpoint for all request types. ACKs still do not generate unidentified request security events. ASTERISK-26264 #close Reported by nappsoft AST-2016-006 Change-Id: Ie0c795ae2d72273decb972dd74b6a1489fb6b703 --- res/res_pjsip/pjsip_distributor.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index bce428e42a8..93266137857 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -571,9 +571,7 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) } } - if (!endpoint && !is_ack) { - char name[AST_UUID_STR_LEN] = ""; - pjsip_uri *from = rdata->msg_info.from->uri; + if (!endpoint) { /* always use an artificial endpoint - per discussion no reason to have "alwaysauthreject" as an option. It is felt using it @@ -581,6 +579,13 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) breaking old stuff and we really don't want to enable the discovery of SIP accounts */ endpoint = ast_sip_get_artificial_endpoint(); + } + + rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint; + + if (!is_ack) { + char name[AST_UUID_STR_LEN] = ""; + pjsip_uri *from = rdata->msg_info.from->uri; if (PJSIP_URI_SCHEME_IS_SIP(from) || PJSIP_URI_SCHEME_IS_SIPS(from)) { pjsip_sip_uri *sip_from = pjsip_uri_get_uri(from); @@ -614,7 +619,6 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) ast_sip_report_invalid_endpoint(name, rdata); } } - rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint; return PJ_FALSE; } From 2a50c2910144e1b4095d171b1386fd5ebb0c5b5a Mon Sep 17 00:00:00 2001 From: Aaron An Date: Tue, 30 Aug 2016 11:26:03 +0800 Subject: [PATCH 0737/1578] res/res_pjsip: Add preferred_codec_only config to pjsip endpoint. This patch add config to pjsip by endpoint. ;preferred_codec_only=yes ; Respond to a SIP invite with the single most preferred codec ; rather than advertising all joint codec capabilities. This ; limits the other side's codec choice to exactly what we prefer. ASTERISK-26317 #close Reported by: AaronAn Tested by: AaronAn Change-Id: Iad04dc55055403bbf5ec050997aee2dadc4f0762 --- CHANGES | 7 +++++ configs/samples/pjsip.conf.sample | 4 +++ ...dd_preferred_codec_only_option_to_pjsip.py | 30 +++++++++++++++++++ include/asterisk/res_pjsip.h | 2 ++ res/res_pjsip.c | 6 ++++ res/res_pjsip/pjsip_configuration.c | 1 + res/res_pjsip_sdp_rtp.c | 9 ++++-- res/res_pjsip_session.c | 8 +++-- 8 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/7f3e21abe318_add_preferred_codec_only_option_to_pjsip.py diff --git a/CHANGES b/CHANGES index 5857165c8d7..6032dd8a053 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,13 @@ ------------------------------------------------------------------------------ +res_pjsip +------------------ + * Added endpoint configuration parameter "preferred_codec_only". + This allow asterisk response to a SIP invite with the single most + preferred codec rather than advertising all joint codec capabilities. + This limits the other side's codec choice to exactly what we prefer. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- ------------------------------------------------------------------------------ diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 0d1c03909f1..e6b32495ba3 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -764,6 +764,10 @@ ; "0" or not enabled) ;contact_user= ; On outgoing requests, force the user portion of the Contact ; header to this value (default: "") +;preferred_codec_only=yes ; Respond to a SIP invite with the single most preferred codec + ; rather than advertising all joint codec capabilities. This + ; limits the other side's codec choice to exactly what we prefer. + ; default is no. ;==========================AUTH SECTION OPTIONS========================= ;[auth] diff --git a/contrib/ast-db-manage/config/versions/7f3e21abe318_add_preferred_codec_only_option_to_pjsip.py b/contrib/ast-db-manage/config/versions/7f3e21abe318_add_preferred_codec_only_option_to_pjsip.py new file mode 100644 index 00000000000..083d08966e8 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/7f3e21abe318_add_preferred_codec_only_option_to_pjsip.py @@ -0,0 +1,30 @@ +"""add preferred_codec_only option to pjsip + +Revision ID: 7f3e21abe318 +Revises: 4e2493ef32e6 +Create Date: 2016-09-02 11:00:23.534748 + +""" + +# revision identifiers, used by Alembic. +revision = '7f3e21abe318' +down_revision = '4e2493ef32e6' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoints', sa.Column('preferred_codec_only', yesno_values)) + +def downgrade(): + op.drop_column('ps_endpoints', 'preferred_codec_only') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 4cede43919b..8a5ad29c598 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -757,6 +757,8 @@ struct ast_sip_endpoint { unsigned int faxdetect_timeout; /*! Override the user on the outgoing Contact header with this value. */ char *contact_user; + /*! Whether to response SDP offer with single most preferred codec. */ + unsigned int preferred_codec_only; }; /*! diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 34edc8ca511..7bb10c07f01 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -833,6 +833,9 @@ have this accountcode set on it. + + Respond to a SIP invite with the single most preferred codec rather than advertising all joint codec capabilities. This limits the other side's codec choice to exactly what we prefer. + Number of seconds between RTP comfort noise keepalive packets. @@ -2022,6 +2025,9 @@ + + + The aggregate device state for this endpoint. diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 333be71438a..97c357a9e1c 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1933,6 +1933,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 6610ef126c3..68d5fdb5638 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -360,8 +360,13 @@ static int set_caps(struct ast_sip_session *session, ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_remove_by_type(caps, media_type); - ast_format_cap_append_from_cap(caps, joint, media_type); - + if (session->endpoint->preferred_codec_only){ + struct ast_format *preferred_fmt = ast_format_cap_get_format(joint, 0); + ast_format_cap_append(caps, preferred_fmt, 0); + ao2_ref(preferred_fmt, -1); + } else { + ast_format_cap_append_from_cap(caps, joint, media_type); + } /* * Apply the new formats to the channel, potentially changing * raw read/write formats and translation path while doing so. diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 315393fdb89..0ab45c74e13 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1247,7 +1247,9 @@ int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data pjsip_inv_set_local_sdp(session->inv_session, offer); pjmedia_sdp_neg_set_prefer_remote_codec_order(session->inv_session->neg, PJ_FALSE); #ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS - pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE); + if (!session->endpoint->preferred_codec_only) { + pjmedia_sdp_neg_set_answer_multiple_codecs(session->inv_session->neg, PJ_TRUE); + } #endif /* @@ -2141,7 +2143,9 @@ static int new_invite(void *data) pjsip_inv_set_local_sdp(invite->session->inv_session, local); pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE); #ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS - pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE); + if (!invite->session->endpoint->preferred_codec_only) { + pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE); + } #endif } From 901e612739e6067c4d51656f35c49f005534f1de Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 9 Sep 2016 10:39:51 +0000 Subject: [PATCH 0738/1578] res_pjsip: Only invoke unidentified endpoint logic when unidentified. The code was incorrectly invoking the unidentified logic when an endpoint had actually been identified, causing log messages to be output. ASTERISK-26349 #close Change-Id: Id8104fc9e3d138d5e8b6f6977ecc08765fd17d4f --- res/res_pjsip/pjsip_distributor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 93266137857..7412445860a 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -583,7 +583,7 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata) rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint; - if (!is_ack) { + if ((endpoint == artificial_endpoint) && !is_ack) { char name[AST_UUID_STR_LEN] = ""; pjsip_uri *from = rdata->msg_info.from->uri; From 56caf5402c14c663805e6ef4cac3e5e9be87b4bd Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Fri, 9 Sep 2016 13:26:01 +0200 Subject: [PATCH 0739/1578] contrib: Let safe_asterisk script continue without /dev/tty9. If you use the safe_asterisk script, it uses hardcoded defaults before running configurable values from /etc/asterisk/startup.d. The hardcoded default has TTY=9. Some containerized environments don't have such a TTY, and safe_asterisk would stop. The custom configuration from /etc/asterisk/startup.d/* isn't read until after it stopped, so changing TTY in a custom config did not help. This changeset changes safe_asterisk to continue if the TTY setting was untouched and /dev/tty9 and /dev/vc/9 aren't found. Change-Id: I2c7cdba549b77f418a0af4cb1227e8e6fe4148fc --- contrib/scripts/safe_asterisk | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/contrib/scripts/safe_asterisk b/contrib/scripts/safe_asterisk index 62f3dadc29f..66213a530dd 100644 --- a/contrib/scripts/safe_asterisk +++ b/contrib/scripts/safe_asterisk @@ -120,13 +120,20 @@ if test -n "$TTY" && test "$TTY" != "no"; then TTY=tty${TTY} elif test -c /dev/vc/${TTY}; then TTY=vc/${TTY} + elif test "$TTY" = "9"; then # ignore default if it was untouched + # If there is no /dev/tty9 and not /dev/vc/9 we don't + # necessarily want to die at this point. Pretend that + # TTY wasn't set. + TTY= else message "Cannot find specified TTY (${TTY})" exit 1 fi - ASTARGS="${ASTARGS} -vvvg" - if test "$CONSOLE" != "no"; then - ASTARGS="${ASTARGS} -c" + if test -n "$TTY"; then + ASTARGS="${ASTARGS} -vvvg" + if test "$CONSOLE" != "no"; then + ASTARGS="${ASTARGS} -c" + fi fi fi From ba362822f34e1967e5e15a0e81bab2f5981b014a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 29 Aug 2016 18:08:22 -0500 Subject: [PATCH 0740/1578] res_pjsip: Add ignore_uri_user_options option. This implements the chan_sip legacy_useroption_parsing option but with a better name. * Made the caller-id number and redirecting number strings obtained from incoming SIP URI user fields always truncated at the first semicolon. People don't care about anything after the semicolon showing up on their displays even though the RFC allows the semicolon. ASTERISK-26316 #close Reported by: Kevin Harwell Change-Id: Ib42b0e940dd34d84c7b14bc2e90d1ba392624f62 --- CHANGES | 11 +++++++ configs/samples/pjsip.conf.sample | 16 ++++++++++ ..._ps_globals_add_ignore_uri_user_options.py | 32 +++++++++++++++++++ include/asterisk/res_pjsip.h | 32 +++++++++++++++++++ res/res_pjsip.c | 24 ++++++++++++++ res/res_pjsip/config_global.c | 20 ++++++++++++ res/res_pjsip/pjsip_options.c | 12 +++++-- res/res_pjsip_caller_id.c | 18 +++++++++++ res/res_pjsip_diversion.c | 25 +++++++++++++-- res/res_pjsip_endpoint_identifier_user.c | 12 +++++-- res/res_pjsip_messaging.c | 25 ++++++++++++--- res/res_pjsip_path.c | 22 +++++++++---- res/res_pjsip_pubsub.c | 18 +++++++++++ res/res_pjsip_refer.c | 7 ++++ res/res_pjsip_registrar.c | 6 ++++ res/res_pjsip_session.c | 13 ++++++++ 16 files changed, 276 insertions(+), 17 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/a6ef36f1309_ps_globals_add_ignore_uri_user_options.py diff --git a/CHANGES b/CHANGES index bf7bc75de92..38228e37a23 100644 --- a/CHANGES +++ b/CHANGES @@ -79,6 +79,17 @@ res_pjsip configure these options then you already had to do a reload after making changes. + * Added "ignore_uri_user_options" global configuration option for + compatibility with an ITSP that sends URI user field options. When enabled + the user field is truncated at the first semicolon. + Example: + URI: "sip:1235557890;phone-context=national@x.x.x.x;user=phone" + The user field is "1235557890;phone-context=national" + Which is truncated to this: "1235557890" + + Note: The caller-id and redirecting number strings obtained from incoming + SIP URI user fields are now always truncated at the first semicolon. + app_confbridge ------------------ * Some sounds played into the bridge are played asynchronously. This, for diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index e6b32495ba3..c6293b6fbca 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -991,6 +991,22 @@ ; If disabled then unsolicited mwi will start processing ; on the endpoint's next contact update. +;ignore_uri_user_options=no ; Enable/Disable ignoring SIP URI user field options. + ; If you have this option enabled and there are semicolons + ; in the user field of a SIP URI then the field is truncated + ; at the first semicolon. This effectively makes the semicolon + ; a non-usable character for PJSIP endpoint names, extensions, + ; and AORs. This can be useful for improving compatability with + ; an ITSP that likes to use user options for whatever reason. + ; Example: + ; URI: "sip:1235557890;phone-context=national@x.x.x.x;user=phone" + ; The user field is "1235557890;phone-context=national" + ; Which becomes this: "1235557890" + ; + ; Note: The caller-id and redirecting number strings obtained + ; from incoming SIP URI user fields are always truncated at the + ; first semicolon. + ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl ;==========================ACL SECTION OPTIONS========================= ;[acl] diff --git a/contrib/ast-db-manage/config/versions/a6ef36f1309_ps_globals_add_ignore_uri_user_options.py b/contrib/ast-db-manage/config/versions/a6ef36f1309_ps_globals_add_ignore_uri_user_options.py new file mode 100644 index 00000000000..1556521d552 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/a6ef36f1309_ps_globals_add_ignore_uri_user_options.py @@ -0,0 +1,32 @@ +"""ps_globals add ignore_uri_user_options + +Revision ID: a6ef36f1309 +Revises: 7f3e21abe318 +Create Date: 2016-08-31 12:24:22.368956 + +""" + +# revision identifiers, used by Alembic. +revision = 'a6ef36f1309' +down_revision = '7f3e21abe318' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_globals', sa.Column('ignore_uri_user_options', yesno_values)) + + +def downgrade(): + op.drop_column('ps_globals', 'ignore_uri_user_options') + diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 8a5ad29c598..92bdabb662f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2446,6 +2446,38 @@ int ast_sip_get_mwi_tps_queue_low(void); */ unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void); +/*! + * \brief Retrieve the global setting 'ignore_uri_user_options'. + * \since 13.12.0 + * + * \retval non zero if ignore the user field options. + */ +unsigned int ast_sip_get_ignore_uri_user_options(void); + +/*! + * \brief Truncate the URI user field options string if enabled. + * \since 13.12.0 + * + * \param str URI user field string to truncate if enabled + * + * \details + * We need to be able to handle URI's looking like + * "sip:1235557890;phone-context=national@x.x.x.x;user=phone" + * + * Where the URI user field is: + * "1235557890;phone-context=national" + * + * When truncated the string will become: + * "1235557890" + */ +#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str) \ + do { \ + char *__semi = strchr((str), ';'); \ + if (__semi && ast_sip_get_ignore_uri_user_options()) { \ + *__semi = '\0'; \ + } \ + } while (0) + /*! * \brief Retrieve the system debug setting (yes|no|host). * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 7bb10c07f01..d1ebf64e433 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1550,6 +1550,30 @@ + + Enable/Disable ignoring SIP URI user field options. + + If you have this option enabled and there are semicolons + in the user field of a SIP URI then the field is truncated + at the first semicolon. This effectively makes the semicolon + a non-usable character for PJSIP endpoint names, extensions, + and AORs. This can be useful for improving compatability with + an ITSP that likes to use user options for whatever reason. + + + sip:1235557890;phone-context=national@x.x.x.x;user=phone + + + 1235557890;phone-context=national + + + 1235557890 + + The caller-id and redirecting number strings + obtained from incoming SIP URI user fields are always truncated + at the first semicolon. + + diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index 281630ae43a..fc1227d2523 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -47,6 +47,7 @@ #define DEFAULT_MWI_TPS_QUEUE_HIGH AST_TASKPROCESSOR_HIGH_WATER_LEVEL #define DEFAULT_MWI_TPS_QUEUE_LOW -1 #define DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED 0 +#define DEFAULT_IGNORE_URI_USER_OPTIONS 0 /*! * \brief Cached global config object @@ -100,6 +101,8 @@ struct global_config { /*! Nonzero to disable sending unsolicited mwi to all endpoints on startup */ unsigned int disable_initial_unsolicited; } mwi; + /*! Nonzero if URI user field options are ignored. */ + unsigned int ignore_uri_user_options; }; static void global_destructor(void *obj) @@ -384,6 +387,20 @@ unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void) return disable_initial_unsolicited; } +unsigned int ast_sip_get_ignore_uri_user_options(void) +{ + unsigned int ignore_uri_user_options; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return DEFAULT_IGNORE_URI_USER_OPTIONS; + } + + ignore_uri_user_options = cfg->ignore_uri_user_options; + ao2_ref(cfg, -1); + return ignore_uri_user_options; +} /*! * \internal @@ -533,6 +550,9 @@ int ast_sip_initialize_sorcery_global(void) ast_sorcery_object_field_register(sorcery, "global", "mwi_disable_initial_unsolicited", DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED ? "yes" : "no", OPT_BOOL_T, 1, FLDSET(struct global_config, mwi.disable_initial_unsolicited)); + ast_sorcery_object_field_register(sorcery, "global", "ignore_uri_user_options", + DEFAULT_IGNORE_URI_USER_OPTIONS ? "yes" : "no", + OPT_BOOL_T, 1, FLDSET(struct global_config, ignore_uri_user_options)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index a282224c92f..09fe1559bfb 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -750,8 +750,7 @@ static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata) pjsip_sip_uri *sip_ruri; char exten[AST_MAX_EXTENSION]; - if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, - &pjsip_options_method)) { + if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) { return PJ_FALSE; } @@ -768,13 +767,20 @@ static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata) sip_ruri = pjsip_uri_get_uri(ruri); ast_copy_pj_str(exten, &sip_ruri->user, sizeof(exten)); + /* + * We may want to match in the dialplan without any user + * options getting in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten); + if (ast_shutting_down()) { /* * Not taking any new calls at this time. * Likely a server availability OPTIONS poll. */ send_options_response(rdata, 503); - } else if (!ast_strlen_zero(exten) && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) { + } else if (!ast_strlen_zero(exten) + && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) { send_options_response(rdata, 404); } else { send_options_response(rdata, 200); diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 429cb610783..16b19ec2ba4 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -46,11 +46,29 @@ static void set_id_from_hdr(pjsip_fromto_hdr *hdr, struct ast_party_id *id) char cid_num[AST_CHANNEL_NAME]; pjsip_sip_uri *uri; pjsip_name_addr *id_name_addr = (pjsip_name_addr *) hdr->uri; + char *semi; uri = pjsip_uri_get_uri(id_name_addr); ast_copy_pj_str(cid_name, &id_name_addr->display, sizeof(cid_name)); ast_copy_pj_str(cid_num, &uri->user, sizeof(cid_num)); + /* Always truncate caller-id number at a semicolon. */ + semi = strchr(cid_num, ';'); + if (semi) { + /* + * We need to be able to handle URI's looking like + * "sip:1235557890;phone-context=national@x.x.x.x;user=phone" + * + * Where the uri->user field will result in: + * "1235557890;phone-context=national" + * + * People don't care about anything after the semicolon + * showing up on their displays even though the RFC + * allows the semicolon. + */ + *semi = '\0'; + } + ast_free(id->name.str); id->name.str = ast_strdup(cid_name); if (!ast_strlen_zero(cid_name)) { diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c index 82c3caaed6e..301d9fc9212 100644 --- a/res/res_pjsip_diversion.c +++ b/res/res_pjsip_diversion.c @@ -148,11 +148,32 @@ static void set_redirecting_id(pjsip_name_addr *name_addr, struct ast_party_id * struct ast_set_party_id *update) { pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr->uri); + char *semi; + pj_str_t uri_user; + + uri_user = uri->user; + + /* Always truncate redirecting number at a semicolon. */ + semi = pj_strchr(&uri_user, ';'); + if (semi) { + /* + * We need to be able to handle URI's looking like + * "sip:1235557890;phone-context=national@x.x.x.x;user=phone" + * + * Where the uri->user field will result in: + * "1235557890;phone-context=national" + * + * People don't care about anything after the semicolon + * showing up on their displays even though the RFC + * allows the semicolon. + */ + pj_strset(&uri_user, (char *) pj_strbuf(&uri_user), semi - pj_strbuf(&uri_user)); + } - if (pj_strlen(&uri->user)) { + if (pj_strlen(&uri_user)) { update->number = 1; data->number.valid = 1; - set_redirecting_value(&data->number.str, &uri->user); + set_redirecting_value(&data->number.str, &uri_user); } if (pj_strlen(&name_addr->display)) { diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c index 6aa2c553206..369cb62fc9e 100644 --- a/res/res_pjsip_endpoint_identifier_user.c +++ b/res/res_pjsip_endpoint_identifier_user.c @@ -33,6 +33,7 @@ static int get_from_header(pjsip_rx_data *rdata, char *username, size_t username { pjsip_uri *from = rdata->msg_info.from->uri; pjsip_sip_uri *sip_from; + if (!PJSIP_URI_SCHEME_IS_SIP(from) && !PJSIP_URI_SCHEME_IS_SIPS(from)) { return -1; } @@ -115,18 +116,25 @@ static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoi static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) { - char username[64], domain[64]; + char username[64]; + char domain[64]; struct ast_sip_endpoint *endpoint; if (get_from_header(rdata, username, sizeof(username), domain, sizeof(domain))) { return NULL; } + + /* + * We may want to be matched without any user options getting + * in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username); + ast_debug(3, "Attempting identify by From username '%s' domain '%s'\n", username, domain); endpoint = find_endpoint(rdata, username, domain); if (!endpoint) { ast_debug(3, "Endpoint not found for From username '%s' domain '%s'\n", username, domain); - ao2_cleanup(endpoint); return NULL; } if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME)) { diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index 7efb1a20e6c..e63c825b58b 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -133,6 +133,12 @@ static struct ast_sip_endpoint* get_outbound_endpoint( } else if ((aor_uri = strchr(name, '@'))) { /* format was 'endpoint@' - don't use the rest */ *aor_uri = '\0'; + + /* + * We may want to match without any user options getting + * in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(name); } /* at this point, if name is not empty then it @@ -448,6 +454,12 @@ static enum pjsip_status_code rx_data_to_ast_msg(pjsip_rx_data *rdata, struct as sip_ruri = pjsip_uri_get_uri(ruri); ast_copy_pj_str(exten, &sip_ruri->user, AST_MAX_EXTENSION); + /* + * We may want to match in the dialplan without any user + * options getting in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten); + endpt = ast_pjsip_rdata_get_endpoint(rdata); ast_assert(endpt != NULL); @@ -528,7 +540,7 @@ static void msg_data_destroy(void *obj) static struct msg_data* msg_data_create(const struct ast_msg *msg, const char *to, const char *from) { - char *tag; + char *uri_params; struct msg_data *mdata = ao2_alloc(sizeof(*mdata), msg_data_destroy); if (!mdata) { @@ -553,9 +565,14 @@ static struct msg_data* msg_data_create(const struct ast_msg *msg, const char *t return NULL; } - /* sometimes from can still contain the tag at this point, so remove it */ - if ((tag = strchr(mdata->from, ';'))) { - *tag = '\0'; + /* + * Sometimes from URI can contain URI parameters, so remove them. + * + * sip:user;user-options@domain;uri-parameters + */ + uri_params = strchr(mdata->from, '@'); + if (uri_params && (uri_params = strchr(mdata->from, ';'))) { + *uri_params = '\0'; } return mdata; } diff --git a/res/res_pjsip_path.c b/res/res_pjsip_path.c index 2dde7323e61..e170a750d8d 100644 --- a/res/res_pjsip_path.c +++ b/res/res_pjsip_path.c @@ -40,7 +40,8 @@ static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri char *configured_aors, *aor_name; pjsip_sip_uri *sip_uri; char *domain_name; - RAII_VAR(struct ast_str *, id, NULL, ast_free); + char *username; + struct ast_str *id = NULL; if (ast_strlen_zero(endpoint->aors)) { return NULL; @@ -49,6 +50,14 @@ static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri sip_uri = pjsip_uri_get_uri(uri); domain_name = ast_alloca(sip_uri->host.slen + 1); ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1); + username = ast_alloca(sip_uri->user.slen + 1); + ast_copy_pj_str(username, &sip_uri->user, sip_uri->user.slen + 1); + + /* + * We may want to match without any user options getting + * in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username); configured_aors = ast_strdupa(endpoint->aors); @@ -60,15 +69,16 @@ static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri continue; } - if (!pj_strcmp2(&sip_uri->user, aor_name)) { + if (!strcmp(username, aor_name)) { break; } - if (!id && !(id = ast_str_create(sip_uri->user.slen + sip_uri->host.slen + 2))) { - return NULL; + if (!id && !(id = ast_str_create(strlen(username) + sip_uri->host.slen + 2))) { + aor_name = NULL; + break; } - ast_str_set(&id, 0, "%.*s@", (int)sip_uri->user.slen, sip_uri->user.ptr); + ast_str_set(&id, 0, "%s@", username); if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { ast_str_append(&id, 0, "%s", alias->domain); ao2_cleanup(alias); @@ -77,10 +87,10 @@ static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri } if (!strcmp(aor_name, ast_str_buffer(id))) { - ast_free(id); break; } } + ast_free(id); if (ast_strlen_zero(aor_name)) { return NULL; diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index fe16c613ab8..015ef99c7f3 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1378,6 +1378,12 @@ static int sub_persistence_recreate(void *obj) resource = ast_alloca(resource_size); ast_copy_pj_str(resource, &request_uri->user, resource_size); + /* + * We may want to match without any user options getting + * in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource); + handler = subscription_get_handler_from_rdata(rdata); if (!handler || !handler->notifier) { ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n", @@ -2750,6 +2756,12 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata) resource = ast_alloca(resource_size); ast_copy_pj_str(resource, &request_uri_sip->user, resource_size); + /* + * We may want to match without any user options getting + * in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource); + expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next); if (expires_header) { @@ -2963,6 +2975,12 @@ static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoi resource_name = ast_alloca(resource_size); ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size); + /* + * We may want to match without any user options getting + * in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource_name); + resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name); if (!resource) { ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 19367bf3261..c1dee8225a0 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -814,6 +814,13 @@ static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_r /* Using the user portion of the target URI see if it exists as a valid extension in their context */ ast_copy_pj_str(exten, &target->user, sizeof(exten)); + + /* + * We may want to match in the dialplan without any user + * options getting in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten); + if (!ast_exists_extension(NULL, context, exten, 1, NULL)) { ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n", ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index fd87ef7bbbd..a8d2bdc4c2c 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -626,6 +626,12 @@ static struct ast_sip_aor *find_registrar_aor(struct pjsip_rx_data *rdata, struc username = ast_alloca(uri->user.slen + 1); ast_copy_pj_str(username, &uri->user, uri->user.slen + 1); + /* + * We may want to match without any user options getting + * in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username); + aor_name = find_aor_name(username, domain_name, endpoint->aors); if (aor_name) { ast_debug(3, "Matched aor '%s' by To username\n", aor_name); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index a26359ffb18..7e885c3bddb 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1982,6 +1982,12 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s sip_ruri = pjsip_uri_get_uri(ruri); ast_copy_pj_str(session->exten, &sip_ruri->user, sizeof(session->exten)); + /* + * We may want to match in the dialplan without any user + * options getting in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(session->exten); + pickup_cfg = ast_get_chan_features_pickup_config(session->channel); if (!pickup_cfg) { ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n"); @@ -3095,6 +3101,13 @@ static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const char exten[AST_MAX_EXTENSION]; ast_copy_pj_str(exten, &uri->user, sizeof(exten)); + + /* + * We may want to match in the dialplan without any user + * options getting in the way. + */ + AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten); + ast_channel_call_forward_set(session->channel, exten); } else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) { char target_uri[PJSIP_MAX_URL_SIZE]; From 82ec58aa913bf778cf4e4bc943659fa730ae91fa Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 31 Aug 2016 15:22:01 -0500 Subject: [PATCH 0741/1578] sip_to_pjsip.py: Map legacy_useroption_parsing. Map the sip.conf general section legacy_useroption_parsing to the new pjsip.conf global ignore_uri_user_options. ASTERISK-26316 Reported by: Kevin Harwell Change-Id: I78108a31995db19d41f4e1a07b3324692c5363fc --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 4da31cb59e1..40e93547d28 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -1101,6 +1101,12 @@ def map_system(sip, pjsip, nmapped): except LookupError: pass + try: + useroption_parsing = sip.get('general', 'legacy_useroption_parsing')[0] + set_value('ignore_uri_user_options', useroption_parsing, 'global', pjsip, nmapped, 'global') + except LookupError: + pass + try: timer_t1 = sip.get('general', 'timert1')[0] set_value('timer_t1', timer_t1, section, pjsip, nmapped, type) From 740292e6aef69c3a2bf1caf2bc9051f30356844d Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Mon, 12 Sep 2016 10:28:17 +0200 Subject: [PATCH 0742/1578] chan_sip: Allow target refresh (Contact update) on re-INVITE. Previously, the Contact was stored only on initial INVITE and on any 18X and 200. That meant that after re-INVITEs from *us* the Contact could get updated, but after re-INVITEs from the *peer*, it did not. This changeset fixes this inconsistency, properly allowing target refreshes through re-INVITES (RFC3261, 12.2). If your strictrtp setting allows it, this change allows you to switch the source IP of a connected/calling device mid-call with a simple re-INVITE from the new IP. ASTERISK-26358 #close Change-Id: Ibb8512054ab27c8c3d2514022568fde943bf2435 --- channels/chan_sip.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 28ba05f51ff..8d84d559cdf 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -26113,12 +26113,15 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str copy_request(&p->initreq, req); /* Save this INVITE as the transaction basis */ if (sipdebug) ast_debug(1, "Initializing initreq for method %s - callid %s\n", sip_methods[req->method].text, p->callid); + + /* Parse new contact both for existing (re-invite) and new calls. */ + parse_ok_contact(p, req); + if (!p->owner) { /* Not a re-invite */ if (req->debug) ast_verbose("Using INVITE request as basis request - %s\n", p->callid); if (newcall) append_history(p, "Invite", "New call: %s", p->callid); - parse_ok_contact(p, req); } else { /* Re-invite on existing call */ ast_clear_flag(&p->flags[0], SIP_OUTGOING); /* This is now an inbound dialog */ if (get_rpid(p, req)) { From 7d7b23f04f2d45a531afd8fd8d0a172ab8411932 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 12 Sep 2016 12:25:54 -0500 Subject: [PATCH 0743/1578] app_queue: Fix CLI "queue show" and AMI Queues action output truncation. The output of CLI "queue show" and AMI Queues action is truncated and "failed to extend from 240 to 327" messages are generated if the queue member and interface names are lengthy. * Increase the string buffer size from 240 to 512 in order to accommodate for more information fields added to the output since v1.8. ASTERISK-26360 #close Reported by: Richard Mudgett Change-Id: Id99c03cf5362453b80491a4b3b0434cb67aa966d --- apps/app_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index f9dd86b677b..873ab0ce6b9 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -9318,7 +9318,7 @@ static void do_print(struct mansession *s, int fd, const char *str) static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv) { struct call_queue *q; - struct ast_str *out = ast_str_alloca(240); + struct ast_str *out = ast_str_alloca(512); int found = 0; time_t now = time(NULL); struct ao2_iterator queue_iter; From e3487b9360bc48c9bf777bef18f19f8a8fcc7a62 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 13 Sep 2016 07:08:18 -0400 Subject: [PATCH 0744/1578] res_pjsip: Don't assume a request will have any addresses. When performing DNS resolution the failover code present in res_pjsip currently assumes that a request will always have at least one viable address. In practice this is not true. A domain may be used that has no records. The code now checks that at least one address exists on the request which prevents looping. ASTERISK-26364 #close Change-Id: Ic0761b0264864acd85915c94d878a81624940f4c --- res/res_pjsip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 7bb10c07f01..8a9322258cd 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3584,7 +3584,7 @@ int ast_sip_failover_request(pjsip_tx_data *tdata) { pjsip_via_hdr *via; - if (tdata->dest_info.cur_addr == tdata->dest_info.addr.count - 1) { + if (!tdata->dest_info.addr.count || (tdata->dest_info.cur_addr == tdata->dest_info.addr.count - 1)) { /* No more addresses to try */ return 0; } From 6ba68b486ed790695c048972f7cf05757214c1dc Mon Sep 17 00:00:00 2001 From: Steve Davies Date: Tue, 13 Sep 2016 11:34:47 +0100 Subject: [PATCH 0745/1578] chan_sip: Fix session timeout on retransmit of non-UDP packets Change-Id I1cd33453c77c56c8e1394cd60a6f17bb61c1d957 Enable Session-Timers for SIP over TCP (and TLS) also disables SIP retransmits in chan_sip for non-UDP connections, allowing the TCP layer to handle the retransmits. Unfortunately, this caused sessions to be terminated with a retransmit timeout becasue it stopped at the point of the first retrans call. This patch waits for the 64*T1 timer to expire instead. ASTERISK-19968 Change-Id: I844f26801aada10bc94e9bebe6e151f0a8443204 --- channels/chan_sip.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 28ba05f51ff..0efe687dcba 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -4243,7 +4243,10 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in pkt->retrans_stop_time = 64 * (pkt->timer_t1 ? pkt->timer_t1 : DEFAULT_TIMER_T1); /* time in ms after pkt->time_sent to stop retransmission */ if (!(p->socket.type & AST_TRANSPORT_UDP)) { + /* TCP does not need retransmits as that's built in, but with + * retrans_stop set, we must give it the full timer_H treatment */ pkt->retrans_stop = 1; + siptimer_a = pkt->retrans_stop_time; } /* Schedule retransmission */ From 5f54ac3a80c3b5e83764517912035dd6973d40ad Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 14 Sep 2016 10:51:53 -0400 Subject: [PATCH 0746/1578] res_pjsip_transport_management: Convert time in log message to seconds. ASTERISK-26375 #close Change-Id: I46496af5cae41413e76d44d2068a7431279f09dc --- res/res_pjsip_transport_management.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c index 1cf8e50466e..3e129dc5f69 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip_transport_management.c @@ -134,7 +134,7 @@ static int idle_sched_cb(const void *data) if (!keepalive->sip_received) { ast_log(LOG_NOTICE, "Shutting down transport '%s' since no request was received in %d seconds\n", - keepalive->transport->info, IDLE_TIMEOUT); + keepalive->transport->info, IDLE_TIMEOUT / 1000); pjsip_transport_shutdown(keepalive->transport); } From 89764f7ae9acee638f0a5ddeda5cfd9b525e84bb Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 14 Sep 2016 08:59:51 -0400 Subject: [PATCH 0747/1578] rtp: Preserve timestamps on video frames. Currently when receiving video over RTP we store only a calculated samples on the frame. When starting the video it can take some time for this calculation to actually yield a value as it requires constant changing timestamps. As well if a video frame passes over multiple RTP packets this calculation will fail as the timestamp is the same as the previous RTP packet and the number of samples calculated will be 0. This change preserves the timestamp on the frame and allows it to pass through the core. When sending the video this timestamp is used instead of a new one being calculated. ASTERISK-26367 #close Change-Id: Iba8179fb5c14c9443aee4baf670d2185da3ecfbd --- main/codec_builtin.c | 6 ++++++ res/res_rtp_asterisk.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/main/codec_builtin.c b/main/codec_builtin.c index facb5a84ca8..1f2cb927047 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -758,36 +758,42 @@ static struct ast_codec h261 = { .name = "h261", .description = "H.261 video", .type = AST_MEDIA_TYPE_VIDEO, + .sample_rate = 1000, }; static struct ast_codec h263 = { .name = "h263", .description = "H.263 video", .type = AST_MEDIA_TYPE_VIDEO, + .sample_rate = 1000, }; static struct ast_codec h263p = { .name = "h263p", .description = "H.263+ video", .type = AST_MEDIA_TYPE_VIDEO, + .sample_rate = 1000, }; static struct ast_codec h264 = { .name = "h264", .description = "H.264 video", .type = AST_MEDIA_TYPE_VIDEO, + .sample_rate = 1000, }; static struct ast_codec mpeg4 = { .name = "mpeg4", .description = "MPEG4 video", .type = AST_MEDIA_TYPE_VIDEO, + .sample_rate = 1000, }; static struct ast_codec vp8 = { .name = "vp8", .description = "VP8 video", .type = AST_MEDIA_TYPE_VIDEO, + .sample_rate = 1000, }; static struct ast_codec t140red = { diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index a8d4a90775b..d6eea3ce0d7 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4763,6 +4763,8 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* Video -- samples is # of samples vs. 90000 */ if (!rtp->lastividtimestamp) rtp->lastividtimestamp = timestamp; + ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO); + rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000); rtp->f.samples = timestamp - rtp->lastividtimestamp; rtp->lastividtimestamp = timestamp; rtp->f.delivery.tv_sec = 0; From bc81765bb4f11069ca8044dcdf5da6a92a586972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 9 Sep 2016 14:35:43 +0300 Subject: [PATCH 0748/1578] Fix showing of swap details when sysinfo() is available If sysinfo() is available, but not sysctl() or swapctl() the printing code for swap buffer sizes is incorrectly omitted. The above condition happens with musl c-library. Fix #if rule to consider defined(HAVE_SYSINFO). And also remove the redundant || defined(HAVE_SYSCTL) which was incorrectly there to start with. Now swap information is displayed only if an actual libc function to get it is available. This also fixes warnings previously seen with musl libc: [CC] asterisk.c -> asterisk.o asterisk.c: In function 'handle_show_sysinfo': asterisk.c:773:6: warning: variable 'totalswap' set but not used [-Wunused-but-set-variable] int totalswap = 0; ^~~~~~~~~ asterisk.c:770:11: warning: variable 'freeswap' set but not used [-Wunused-but-set-variable] uint64_t freeswap = 0; ^~~~~~~~ Change-Id: I1fb21dad8f27e416c60f138c6f2bff03fb626eca --- main/asterisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/asterisk.c b/main/asterisk.c index 3c2ca259ee9..81d49b9ad55 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -853,7 +853,7 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl #if defined(HAVE_SYSINFO) ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024); #endif -#if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL) +#if defined(HAVE_SWAPCTL) || defined(HAVE_SYSINFO) ast_cli(a->fd, " Total Swap Space: %d KiB\n", totalswap); ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap); #endif From 07b95f7c65b7c083724f1af2b26f93cc22cad58c Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Mon, 27 Jun 2016 21:26:54 +0200 Subject: [PATCH 0749/1578] sd_notify (systemd status notifications) support sd_notify() is used to notify systemd of changes to the status of the process. This allows the systemd daemon to know when the process finished loading (and thus only start another program after Asterisk has finished loading). To use this, use a systemd unit with 'Type=notify' for Asterisk. This commit also adds the function ast_sd_notify(), a wrapper around sd_notify that does nothing if not built with systemd support. Also adds support for libsystemd detection in the configure script. Change-Id: Ied6a59dafd5ef331c5c7ae8f3ccd2dfc94be7811 --- CHANGES | 4 ++ configure | 119 ++++++++++++++++++++++++++++++- configure.ac | 5 ++ include/asterisk/autoconfig.h.in | 3 + include/asterisk/io.h | 10 +++ main/Makefile | 1 + main/asterisk.c | 4 ++ main/io.c | 10 +++ main/loader.c | 9 +-- makeopts.in | 4 ++ 10 files changed, 163 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 38228e37a23..da732a7ebbe 100644 --- a/CHANGES +++ b/CHANGES @@ -347,6 +347,10 @@ Core in the context. If enabled a device state hint will be automatically created with the name of the device. +* If Asterisk is built with systemd support, and run under systemd, it will + notify systemd of its state using sd_notify. Use 'Type=notify' in + asterisk.service. + Functions ------------------ * The func_odbc global option "single_db_connection" default value has been diff --git a/configure b/configure index 51f06232825..a5da739c045 100755 --- a/configure +++ b/configure @@ -639,6 +639,11 @@ PBX_SYSLOG_FACILITY_LOG_DAEMON PBX_SYSLOG_FACILITY_LOG_CRON PBX_SYSLOG_FACILITY_LOG_AUTHPRIV PBX_SYSLOG_FACILITY_LOG_AUTH +SYSTEMD_LIBS +SYSTEMD_CFLAGS +SYSTEMD_INCLUDE +SYSTEMD_LIB +PBX_SYSTEMD PBX_GENERIC_ODBC GENERIC_ODBC_INCLUDE GENERIC_ODBC_LIB @@ -1320,6 +1325,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -1460,7 +1466,9 @@ PYTHONDEV_LIBS GMIME_CFLAGS GMIME_LIBS GTK2_CFLAGS -GTK2_LIBS' +GTK2_LIBS +SYSTEMD_CFLAGS +SYSTEMD_LIBS' # Initialize some variables set by options. @@ -1499,6 +1507,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1751,6 +1760,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1888,7 +1906,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2041,6 +2059,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -2213,6 +2232,10 @@ Some influential environment variables: GMIME_LIBS linker flags for GMIME, overriding pkg-config GTK2_CFLAGS C compiler flags for GTK2, overriding pkg-config GTK2_LIBS linker flags for GTK2, overriding pkg-config + SYSTEMD_CFLAGS + C compiler flags for SYSTEMD, overriding pkg-config + SYSTEMD_LIBS + linker flags for SYSTEMD, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -34811,6 +34834,98 @@ fi + + + + + if test "x${PBX_SYSTEMD}" != "x1" -a "${USE_SYSTEMD}" != "no"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5 +$as_echo_n "checking for SYSTEMD... " >&6; } + +if test -n "$SYSTEMD_CFLAGS"; then + pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "libsystemd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SYSTEMD_LIBS"; then + pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "libsystemd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd" 2>&1` + else + SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SYSTEMD_PKG_ERRORS" >&5 + + + PBX_SYSTEMD=0 + + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + PBX_SYSTEMD=0 + + +else + SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS + SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + PBX_SYSTEMD=1 + SYSTEMD_INCLUDE="$SYSTEMD_CFLAGS" + SYSTEMD_LIB="$SYSTEMD_LIBS" + +$as_echo "#define HAVE_SYSTEMD 1" >>confdefs.h + + +fi + fi + + PBX_SYSLOG=0 if test "${ac_cv_header_syslog_h}" = "yes"; then diff --git a/configure.ac b/configure.ac index e7fc21c66ea..17b887266fe 100644 --- a/configure.ac +++ b/configure.ac @@ -2630,6 +2630,11 @@ AC_SUBST([GENERIC_ODBC_LIB]) AC_SUBST([GENERIC_ODBC_INCLUDE]) AC_SUBST([PBX_GENERIC_ODBC]) +AC_SUBST([PBX_SYSTEMD]) +AC_SUBST([SYSTEMD_LIB]) +AC_SUBST([SYSTEMD_INCLUDE]) +AST_PKG_CONFIG_CHECK([SYSTEMD], [libsystemd]) + PBX_SYSLOG=0 if test "${ac_cv_header_syslog_h}" = "yes"; then diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 5e7ea7e2ae3..e16b6686153 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -1027,6 +1027,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H +/* Define if your system has the SYSTEMD libraries. */ +#undef HAVE_SYSTEMD + /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H diff --git a/include/asterisk/io.h b/include/asterisk/io.h index 2bddd3780b2..6ee8450bd70 100644 --- a/include/asterisk/io.h +++ b/include/asterisk/io.h @@ -139,6 +139,16 @@ int ast_restore_tty(int fd, int oldstatus); int ast_get_termcols(int fd); +/*! + * \brief a wrapper for sd_notify(): notify systemd of any state changes. + * \param state a string that states the changes. See sd_notify(3). + * The wrapper does nothing if systemd ('s development headers) was not + * detected on the system. + * \returns >=0 on success, negative value on error. + */ +int ast_sd_notify(const char *state); + + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/Makefile b/main/Makefile index a6c3ab1b87b..d41302a7fc3 100644 --- a/main/Makefile +++ b/main/Makefile @@ -45,6 +45,7 @@ AST_LIBS+=$(UUID_LIB) AST_LIBS+=$(CRYPT_LIB) AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS) AST_LIBS+=$(RT_LIB) +AST_LIBS+=$(SYSTEMD_LIB) ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc linux-musl kfreebsd-gnu),) ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),) diff --git a/main/asterisk.c b/main/asterisk.c index 3c2ca259ee9..e2f8901c28b 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1999,6 +1999,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart) ast_module_shutdown(); } + if (!restart) { + ast_sd_notify("STOPPING=1"); + } if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) { ast_el_write_default_histfile(); if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) { @@ -4526,6 +4529,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou ast_register_cleanup(main_atexit); run_startup_commands(); + ast_sd_notify("READY=1"); ast_verb(0, COLORIZE_FMT "\n", COLORIZE(COLOR_BRGREEN, 0, "Asterisk Ready.")); diff --git a/main/io.c b/main/io.c index ff5ca57f79f..3441fbae9ff 100644 --- a/main/io.c +++ b/main/io.c @@ -36,6 +36,9 @@ ASTERISK_REGISTER_FILE() #include "asterisk/io.h" #include "asterisk/utils.h" +#ifdef HAVE_SYSTEMD +#include +#endif #ifdef DEBUG_IO #define DEBUG DEBUG_M @@ -384,3 +387,10 @@ int ast_get_termcols(int fd) return cols; } +int ast_sd_notify(const char *state) { +#ifdef HAVE_SYSTEMD + return sd_notify(0, state); +#else + return 0; +#endif +} diff --git a/main/loader.c b/main/loader.c index f9592217384..36a3d5f61b6 100644 --- a/main/loader.c +++ b/main/loader.c @@ -891,6 +891,7 @@ enum ast_module_reload_result ast_module_reload(const char *name) res = AST_MODULE_RELOAD_IN_PROGRESS; goto module_reload_exit; } + ast_sd_notify("RELOAD=1"); ast_lastreloadtime = ast_tvnow(); if (ast_opt_lock_confdir) { @@ -904,9 +905,8 @@ enum ast_module_reload_result ast_module_reload(const char *name) } if (res != AST_LOCK_SUCCESS) { ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR); - ast_mutex_unlock(&reloadlock); res = AST_MODULE_RELOAD_ERROR; - goto module_reload_exit; + goto module_reload_done; } } @@ -923,8 +923,7 @@ enum ast_module_reload_result ast_module_reload(const char *name) if (ast_opt_lock_confdir) { ast_unlock_path(ast_config_AST_CONFIG_DIR); } - ast_mutex_unlock(&reloadlock); - goto module_reload_exit; + goto module_reload_done; } AST_DLLIST_LOCK(&module_list); @@ -966,7 +965,9 @@ enum ast_module_reload_result ast_module_reload(const char *name) if (ast_opt_lock_confdir) { ast_unlock_path(ast_config_AST_CONFIG_DIR); } +module_reload_done: ast_mutex_unlock(&reloadlock); + ast_sd_notify("READY=1"); module_reload_exit: publish_reload_message(name, res); diff --git a/makeopts.in b/makeopts.in index 86b7f9d99af..b2b394b5f14 100644 --- a/makeopts.in +++ b/makeopts.in @@ -259,6 +259,10 @@ RT_LIB=@RT_LIB@ SS7_INCLUDE=@SS7_INCLUDE@ SS7_LIB=@SS7_LIB@ +HAVE_SYSTEMD=@PBX_SYSTEMD@ +SYSTEMD_INCLUDE=@SYSTEMD_INCLUDE@ +SYSTEMD_LIB=@SYSTEMD_LIB@ + OPENR2_INCLUDE=@OPENR2_INCLUDE@ OPENR2_LIB=@OPENR2_LIB@ From d3ddf4b0fdaf3e9562ede947c2367031434b3b5e Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Mon, 12 Sep 2016 15:37:30 +0300 Subject: [PATCH 0750/1578] cdr_mysql: fix UTC support * Make 'cdrzone=UTC' work properly. * Fix the documentation of cdr_mysql.conf: it's cdrzone and not timezone ASTERISK-26359 #close Change-Id: I2a6f67b71bbbe77cac31a34d0bbfb1d67c933778 --- addons/cdr_mysql.c | 11 ++++++++--- configs/samples/cdr_mysql.conf.sample | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c index 9873395c2ca..896bad603ba 100644 --- a/addons/cdr_mysql.c +++ b/addons/cdr_mysql.c @@ -245,7 +245,7 @@ static int mysql_log(struct ast_cdr *cdr) struct ast_tm tm; char timestr[128]; ast_localtime(&tv, &tm, ast_str_strlen(cdrzone) ? ast_str_buffer(cdrzone) : NULL); - ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm); + ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); value = ast_strdupa(timestr); cdrname = "calldate"; } else { @@ -260,8 +260,7 @@ static int mysql_log(struct ast_cdr *cdr) /* Need the type and value to determine if we want the raw value or not */ if (entry->staticvalue) { value = ast_strdupa(entry->staticvalue); - } else if ((!strcmp(cdrname, "start") || - !strcmp(cdrname, "answer") || + } else if ((!strcmp(cdrname, "answer") || !strcmp(cdrname, "end") || !strcmp(cdrname, "disposition") || !strcmp(cdrname, "amaflags")) && @@ -273,6 +272,12 @@ static int mysql_log(struct ast_cdr *cdr) strstr(entry->type, "numeric") || strstr(entry->type, "fixed"))) { ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 1); + } else if (!strcmp(cdrname, "start")) { + struct ast_tm tm; + char timestr[128]; + ast_localtime(&cdr->start, &tm, ast_str_strlen(cdrzone) ? ast_str_buffer(cdrzone) : NULL); + ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); + value = ast_strdupa(timestr); } else if (!strcmp(cdrname, "calldate")) { /* Skip calldate - the value has already been dup'd */ } else { diff --git a/configs/samples/cdr_mysql.conf.sample b/configs/samples/cdr_mysql.conf.sample index 04b70493b55..e15a8ed9322 100644 --- a/configs/samples/cdr_mysql.conf.sample +++ b/configs/samples/cdr_mysql.conf.sample @@ -18,7 +18,10 @@ ;user=asteriskcdruser ;port=3306 ;sock=/tmp/mysql.sock -;timezone=UTC ; Previously called usegmtime +; By default CDRs are logged in the system's time zone +;cdrzone=UTC ; log CDRs with UTC +;usegmtime=yes ;log date/time in GMT. Default is "no" +;cdrzone=America/New_York ; or use a specific time zone ; ; If your system's locale differs from mysql database character set, ; cdr_mysql can damage non-latin characters in CDR variables. Use this From 47c527df0a9f32cc821565eb84885c2957bf00fd Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 7 Sep 2016 13:48:48 -0600 Subject: [PATCH 0751/1578] pjproject_bundled: Prevent SERVFAIL from marking name server bad A name server that returns "Server Failure" is indicating only that the server couldn't process that particular request. We should NOT assume that the name server is incapable of serving other requests. Here's the scenario we've been encountering... * 2 local name servers configured in resolv.conf. * An OPTIONS request causes a request for A and AAAA records to go out to both nameservers. * The A responses both come back successfully resolved. * Because of an issue at some upstream nameserver, the AAAA responses for that particular query come back as "SERVFAIL" from both local name servers. * Both local servers are marked as bad and no further queries can be sent until the 60 second ttl expires. Only previously cached results can be used. * In this case, 60 seconds is just enough time for another OPTIONS request to go out to the same host so the cycle repeats. We could set the bad ttl really low but that also affects REFUSED and NOTAUTH which probably DO signal a real server issue. Besides, even a really low bad ttl would be an issue on a pbx. Although we use our own resolver in 14 and master and don't have this issue there, Teluu has merged this patch upstream so it's appropriate to cherry-pick to 14 and master to keep pjproject consistent. Change-Id: Ie03ba902288e274aff23f9b9bb2786e1e8be09e0 --- ...nt-SERVFAIL-from-marking-name-server.patch | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch diff --git a/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch b/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch new file mode 100644 index 00000000000..55f3d2d1526 --- /dev/null +++ b/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch @@ -0,0 +1,48 @@ +From a5efddbe9151e9ad99279e59566c86f8bc27d3a9 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Wed, 7 Sep 2016 13:10:57 -0600 +Subject: [PATCH] resolver.c: Prevent SERVFAIL from marking name server bad + +A name server that returns "Server Failure" is indicating only that +the server couldn't process that particular request. We should NOT +assume that the name server is incapable of serving other requests. + +Here's the scenario we've been encountering... + +* 2 local name servers configured in resolv.conf. +* An OPTIONS request causes a request for A and AAAA records to go out + to both nameservers. +* The A responses both come back successfully resolved. +* Because of an issue at some upstream nameserver, the AAAA responses + for that particular query come back as "SERVFAIL" from both local + name servers. +* Both local servers are marked as bad and no further queries can be + sent until the 60 second ttl expires. Only previously cached results + can be used. +* In this case, 60 seconds is just enough time for another OPTIONS + request to go out to the same host so the cycle repeats. + +We could set the bad ttl really low but that also affects REFUSED and +NOTAUTH which probably DO signal a real server issue. Besides, even +a really low bad ttl would be an issue on a pbx. +--- + pjlib-util/src/pjlib-util/resolver.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c +index d277e4f..540f88f 100644 +--- a/pjlib-util/src/pjlib-util/resolver.c ++++ b/pjlib-util/src/pjlib-util/resolver.c +@@ -1384,8 +1384,7 @@ static void report_nameserver_status(pj_dns_resolver *resolver, + q_id = (pj_uint32_t)-1; + } + +- if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL || +- rcode == PJ_DNS_RCODE_REFUSED || ++ if (!pkt || rcode == PJ_DNS_RCODE_REFUSED || + rcode == PJ_DNS_RCODE_NOTAUTH) + { + is_good = PJ_FALSE; +-- +2.7.4 + From 9d894ee0a183de3fb54c662bcacf6fc4b2f8a9dd Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 14 Sep 2016 09:42:46 -0400 Subject: [PATCH 0752/1578] res_pjsip_multihomed: Change Contact port to listening port. The res_pjsip_multihomed module determines what interface and transport a request is going out on and updates the SIP message accordingly with the address information. This currently incorrectly updates the Contact header for connectionful protocols to the ephemeral connection port, instead of the bound address for the listening socket which can actually accept the connection back. If the remote side attempts to connect back on the epehemeral port it will fail. This change makes it so the port is updated to the bound port on connectionful protocols and is maintained on UDP (as there can be multiple of those). ASTERISK-26374 #close Change-Id: I50f8dab65b9f75117d73ba5f6bbcf6c9871854ab --- res/res_pjsip_multihomed.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_multihomed.c b/res/res_pjsip_multihomed.c index f5deb77240c..5deeb924768 100644 --- a/res/res_pjsip_multihomed.c +++ b/res/res_pjsip_multihomed.c @@ -109,8 +109,11 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) return PJ_SUCCESS; } - /* The port in the message should always be that of the original transport */ - prm.ret_port = tdata->tp_info.transport->local_name.port; + /* For UDP we can have multiple transports so the port needs to be maintained */ + if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || + tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) { + prm.ret_port = tdata->tp_info.transport->local_name.port; + } /* If the IP source differs from the existing transport see if we need to update it */ if (pj_strcmp(&prm.ret_addr, &tdata->tp_info.transport->local_name.host)) { From 0376af95192b0e902e52c33f9230dc5ecc90be42 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 14 Sep 2016 07:53:36 -0400 Subject: [PATCH 0753/1578] rtp: Only accept the first payload for a format in SDP. When receiving an SDP offer with multiple payloads for the same format we would generate an answer with the first payload, but during the payload crossover operation (to set the payloads for receiving) we would remove all payloads but the last. This would result in incoming traffic being matched against the wrong format and outgoing traffic being sent using the wrong payload. This change makes it so that once a format has a payload number put into the mapping all subsequent ones are ignored. This ensures there is only ever one payload in the mapping and that it is the payload placed into the answer SDP. ASTERISK-26365 #close Change-Id: I1e8150860a3518cab36d00b1fab50f9352b64e60 --- main/rtp_engine.c | 95 +++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 0671374ef56..b91bc411576 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -753,18 +753,18 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r /*! * \internal - * \brief Remove other matching payload mappings. + * \brief Determine if a type of payload is already present in mappings. * \since 14.0.0 * - * \param codecs Codecs that need tx mappings removed. - * \param instance RTP instance to notify of any payloads removed. + * \param codecs Codecs to be checked for mappings. * \param to_match Payload type object to compare against. * * \note It is assumed that codecs is write locked before calling. * - * \return Nothing + * \retval 0 not found + * \retval 1 found */ -static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_rtp_payload_type *to_match) +static int payload_mapping_tx_is_present(const struct ast_rtp_codecs *codecs, const struct ast_rtp_payload_type *to_match) { int idx; struct ast_rtp_payload_type *current; @@ -772,12 +772,18 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) { current = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx); - if (!current || current == to_match) { + if (!current) { continue; } + if (current == to_match) { + /* The exact object is already in the mapping. */ + return 1; + } if (current->asterisk_format && to_match->asterisk_format) { - if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_get_codec_id(current->format) != ast_format_get_codec_id(to_match->format)) { continue; + } else if (current->payload == to_match->payload) { + return 0; } } else if (!current->asterisk_format && !to_match->asterisk_format) { if (current->rtp_code != to_match->rtp_code) { @@ -787,13 +793,10 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code continue; } - /* Remove other mapping */ - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, idx, NULL); - ao2_ref(current, -1); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, idx, 0, NULL, 0); - } + return 1; } + + return 0; } /*! @@ -833,13 +836,14 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r if (instance && instance->engine && instance->engine->payload_set) { instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); } - - payload_mapping_tx_remove_other_mappings(dest, instance, type); } } void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) { + int idx; + struct ast_rtp_payload_type *type; + ast_rwlock_wrlock(&dest->codecs_lock); /* Deadlock avoidance because of held write lock. */ @@ -849,6 +853,17 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod ast_rwlock_wrlock(&dest->codecs_lock); } + /* + * This represents a completely new mapping of what the remote party is + * expecting for payloads, so we clear out the entire tx payload mapping + * vector and replace it. + */ + for (idx = 0; idx < AST_VECTOR_SIZE(&dest->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&dest->payload_mapping_tx, idx); + ao2_t_cleanup(type, "destroying ast_rtp_codec tx mapping"); + AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, NULL); + } + rtp_codecs_payloads_copy_rx(src, dest, instance); rtp_codecs_payloads_copy_tx(src, dest, instance); dest->framing = src->framing; @@ -921,18 +936,20 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload), - "cleaning up replaced tx payload type"); - } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); + if (!payload_mapping_tx_is_present(codecs, new_type)) { + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload), + "cleaning up replaced tx payload type"); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); + if (instance && instance->engine && instance->engine->payload_set) { + instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); + } + } else { + ao2_ref(new_type, -1); } - payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); - ast_rwlock_unlock(&codecs->codecs_lock); } @@ -995,17 +1012,20 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, new_type->format = ast_format_parse_sdp_fmtp(new_type->format, ""); } - if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt), - "cleaning up replaced tx payload type"); - } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); + if (!payload_mapping_tx_is_present(codecs, new_type)) { + if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt), + "cleaning up replaced tx payload type"); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); + if (instance && instance->engine && instance->engine->payload_set) { + instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); + } + } else { + ao2_ref(new_type, -1); } - payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); break; } @@ -1088,11 +1108,14 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay type->primary_mapping = 1; ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); + if (!payload_mapping_tx_is_present(codecs, type)) { + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type); + } else { + ao2_ref(type, -1); } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type); - payload_mapping_tx_remove_other_mappings(codecs, NULL, type); ast_rwlock_unlock(&codecs->codecs_lock); return 0; From 2820b13393bcabfa0b9d2e59c26805e1011920af Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 12 Sep 2016 18:00:22 -0500 Subject: [PATCH 0754/1578] res_config_odbc.c: Fix buffer size limitation creating invalid SQL. Creating ODBC SQL queries resulted in queries too large to fit into the supplied buffer. The resulting truncated buffer contained an invalid SQL query. * Made SQL query generation code use a thread storage buffer that can increase in size as needed. * Fixed bad multi-line warning messages. ASTERISK-26263 #close Reported by: Jeppe Ryskov Larsen Change-Id: I23f3cdd43c2dac80bed3ded4dd77d18cb17f21ae --- res/res_config_odbc.c | 174 +++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 80 deletions(-) diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 26aa17b1704..161dc534501 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -47,6 +47,9 @@ ASTERISK_REGISTER_FILE() #include "asterisk/utils.h" #include "asterisk/stringfields.h" +/*! Initial SQL query buffer size to allocate. */ +#define SQL_BUF_SIZE 1024 + AST_THREADSTORAGE(sql_buf); AST_THREADSTORAGE(rowdata_buf); @@ -114,7 +117,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data) res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql); + ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", cps->sql); SQLFreeHandle (SQL_HANDLE_STMT, stmt); return NULL; } @@ -161,13 +164,13 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data) * * \retval var on success * \retval NULL on failure -*/ + */ static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields) { struct odbc_obj *obj; SQLHSTMT stmt; - char sql[1024]; char coltitle[256]; + struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128); char *op; const struct ast_variable *field = fields; @@ -183,29 +186,30 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl SQLSMALLINT decimaldigits; SQLSMALLINT nullable; SQLLEN indicator; - struct custom_prepare_struct cps = { .sql = sql, .fields = fields, }; + struct custom_prepare_struct cps = { .fields = fields, }; struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; - if (!table || !field) { + if (!table || !field || !sql || !rowdata) { return NULL; } obj = ast_odbc_request_obj2(database, connected_flag); - if (!obj) { ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database); return NULL; } op = !strchr(field->name, ' ') ? " =" : ""; - snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op, + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op, strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : ""); while ((field = field->next)) { op = !strchr(field->name, ' ') ? " =" : ""; - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op, + ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op, strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : ""); } + cps.sql = ast_str_buffer(sql); + if (ast_string_field_init(&cps, 256)) { ast_odbc_release_obj(obj); return NULL; @@ -220,7 +224,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl res = SQLNumResultCols(stmt, &colcount); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql)); SQLFreeHandle (SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); return NULL; @@ -233,7 +237,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl return NULL; } if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql)); SQLFreeHandle (SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); return NULL; @@ -244,7 +248,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, &datatype, &colsize, &decimaldigits, &nullable); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql)); if (var) ast_variables_destroy(var); ast_odbc_release_obj(obj); @@ -273,7 +277,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl } if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql)); if (var) ast_variables_destroy(var); ast_odbc_release_obj(obj); @@ -317,13 +321,13 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl * * \retval var on success * \retval NULL on failure -*/ + */ static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields) { struct odbc_obj *obj; SQLHSTMT stmt; - char sql[1024]; char coltitle[256]; + struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128); const char *initfield; char *op; @@ -343,9 +347,9 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * SQLSMALLINT decimaldigits; SQLSMALLINT nullable; SQLLEN indicator; - struct custom_prepare_struct cps = { .sql = sql, .fields = fields, }; + struct custom_prepare_struct cps = { .fields = fields, }; - if (!table || !field) { + if (!table || !field || !sql || !rowdata) { return NULL; } @@ -360,15 +364,16 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * } op = !strchr(field->name, ' ') ? " =" : ""; - snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op, + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op, strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : ""); while ((field = field->next)) { op = !strchr(field->name, ' ') ? " =" : ""; - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op, + ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op, strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : ""); } + ast_str_append(&sql, 0, " ORDER BY %s", initfield); - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield); + cps.sql = ast_str_buffer(sql); if (ast_string_field_init(&cps, 256)) { ast_odbc_release_obj(obj); @@ -384,7 +389,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * res = SQLNumResultCols(stmt, &colcount); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql)); SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); return NULL; @@ -401,7 +406,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * while ((res=SQLFetch(stmt)) != SQL_NO_DATA) { var = NULL; if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql)); continue; } cat = ast_category_new("","",99999); @@ -415,7 +420,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, &datatype, &colsize, &decimaldigits, &nullable); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql)); ast_category_destroy(cat); goto next_sql_fetch; } @@ -440,7 +445,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * } if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql)); ast_category_destroy(cat); goto next_sql_fetch; } @@ -482,21 +487,21 @@ next_sql_fetch:; * * \retval number of rows affected * \retval -1 on failure -*/ + */ static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields) { struct odbc_obj *obj; SQLHSTMT stmt; - char sql[256]; SQLLEN rowcount=0; + struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); const struct ast_variable *field = fields; int res, count = 0, paramcount = 0; - struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, }; + struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, }; struct odbc_cache_tables *tableptr; struct odbc_cache_columns *column = NULL; struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; - if (!table || !field || !keyfield) { + if (!table || !field || !keyfield || !sql) { return -1; } @@ -510,19 +515,19 @@ static int update_odbc(const char *database, const char *table, const char *keyf ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database); } - snprintf(sql, sizeof(sql), "UPDATE %s SET ", table); + ast_str_set(&sql, 0, "UPDATE %s SET ", table); while (field) { if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) { if (paramcount++) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", "); + ast_str_append(&sql, 0, ", "); } /* NULL test for non-text columns */ if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", field->name); + ast_str_append(&sql, 0, "%s=NULL", field->name); cps.skip |= (1LL << count); } else { /* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */ - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", field->name); + ast_str_append(&sql, 0, "%s=?", field->name); } } else { /* the column does not exist in the table */ cps.skip |= (1LL << count); @@ -530,9 +535,11 @@ static int update_odbc(const char *database, const char *table, const char *keyf ++count; field = field->next; } - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield); + ast_str_append(&sql, 0, " WHERE %s=?", keyfield); ast_odbc_release_table(tableptr); + cps.sql = ast_str_buffer(sql); + if (ast_string_field_init(&cps, 256)) { ast_odbc_release_obj(obj); return -1; @@ -550,7 +557,7 @@ static int update_odbc(const char *database, const char *table, const char *keyf ast_odbc_release_obj(obj); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql)); return -1; } @@ -573,17 +580,15 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data) int res, x = 1, first = 1; struct update2_prepare_struct *ups = data; const struct ast_variable *field; - struct ast_str *sql = ast_str_thread_get(&sql_buf, 16); + struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); SQLHSTMT stmt; - struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table); + struct odbc_cache_tables *tableptr; if (!sql) { - if (tableptr) { - ast_odbc_release_table(tableptr); - } return NULL; } + tableptr = ast_odbc_find_table(ups->database, ups->table); if (!tableptr) { ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", ups->table, ups->database); return NULL; @@ -628,7 +633,7 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data) res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql)); + ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql)); SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; } @@ -674,8 +679,9 @@ static int update2_odbc(const char *database, const char *table, const struct as if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */ - sql = ast_str_thread_get(&sql_buf, 16); - ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql)); + sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); + ast_assert(sql != NULL); + ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql)); return -1; } @@ -698,36 +704,47 @@ static int update2_odbc(const char *database, const char *table, const struct as * * \retval number of rows affected * \retval -1 on failure -*/ + */ static int store_odbc(const char *database, const char *table, const struct ast_variable *fields) { struct odbc_obj *obj; SQLHSTMT stmt; - char sql[256]; - char keys[256]; - char vals[256]; SQLLEN rowcount=0; const struct ast_variable *field = fields; + struct ast_str *keys; + struct ast_str *vals; + struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); int res; - struct custom_prepare_struct cps = { .sql = sql, .extra = NULL, .fields = fields, }; + struct custom_prepare_struct cps = { .fields = fields, }; struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; - if (!table || !field) { + keys = ast_str_create(SQL_BUF_SIZE / 2); + vals = ast_str_create(SQL_BUF_SIZE / 4); + if (!table || !field || !keys || !vals || !sql) { + ast_free(vals); + ast_free(keys); return -1; } obj = ast_odbc_request_obj2(database, connected_flag); if (!obj) { + ast_free(vals); + ast_free(keys); return -1; } - snprintf(keys, sizeof(keys), "%s", field->name); - ast_copy_string(vals, "?", sizeof(vals)); + ast_str_set(&keys, 0, "%s", field->name); + ast_str_set(&vals, 0, "?"); while ((field = field->next)) { - snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", field->name); - snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?"); + ast_str_append(&keys, 0, ", %s", field->name); + ast_str_append(&vals, 0, ", ?"); } - snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals); + ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)", + table, ast_str_buffer(keys), ast_str_buffer(vals)); + + ast_free(vals); + ast_free(keys); + cps.sql = ast_str_buffer(sql); if (ast_string_field_init(&cps, 256)) { ast_odbc_release_obj(obj); @@ -746,7 +763,7 @@ static int store_odbc(const char *database, const char *table, const struct ast_ ast_odbc_release_obj(obj); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql)); return -1; } @@ -770,19 +787,19 @@ static int store_odbc(const char *database, const char *table, const struct ast_ * * \retval number of rows affected * \retval -1 on failure -*/ + */ static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields) { struct odbc_obj *obj; SQLHSTMT stmt; - char sql[256]; SQLLEN rowcount=0; + struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); const struct ast_variable *field; int res; - struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, }; + struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, }; struct ast_flags connected_flag = { RES_ODBC_CONNECTED }; - if (!table) { + if (!table || !sql) { return -1; } @@ -791,12 +808,13 @@ static int destroy_odbc(const char *database, const char *table, const char *key return -1; } - snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table); - + ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table); for (field = fields; field; field = field->next) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", field->name); + ast_str_append(&sql, 0, "%s=? AND ", field->name); } - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield); + ast_str_append(&sql, 0, "%s=?", keyfield); + + cps.sql = ast_str_buffer(sql); if (ast_string_field_init(&cps, 256)) { ast_odbc_release_obj(obj); @@ -815,7 +833,7 @@ static int destroy_odbc(const char *database, const char *table, const char *key ast_odbc_release_obj(obj); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql)); return -1; } @@ -893,9 +911,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c struct ast_category *cur_cat; int res = 0; struct odbc_obj *obj; - char sqlbuf[1024] = ""; - char *sql = sqlbuf; - size_t sqlleft = sizeof(sqlbuf); + struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE); unsigned int last_cat_metric = 0; SQLSMALLINT rowcount = 0; SQLHSTMT stmt; @@ -906,21 +922,21 @@ static struct ast_config *config_odbc(const char *database, const char *table, c memset(&q, 0, sizeof(q)); - if (!file || !strcmp (file, "res_config_odbc.conf")) + if (!file || !strcmp (file, "res_config_odbc.conf") || !sql) { return NULL; /* cant configure myself with myself ! */ + } obj = ast_odbc_request_obj2(database, connected_flag); if (!obj) return NULL; - q.sql = sqlbuf; - - ast_build_string(&sql, &sqlleft, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", table, file); + ast_str_set(&sql, 0, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", + table, file); + q.sql = ast_str_buffer(sql); stmt = ast_odbc_prepare_and_execute(obj, length_determination_odbc_prepare, &q); - if (!stmt) { - ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql)); ast_odbc_release_obj(obj); return NULL; } @@ -928,7 +944,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c res = SQLNumResultCols(stmt, &rowcount); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql)); SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); return NULL; @@ -950,12 +966,11 @@ static struct ast_config *config_odbc(const char *database, const char *table, c /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */ SQLFreeHandle(SQL_HANDLE_STMT, stmt); - sql = sqlbuf; - sqlleft = sizeof(sqlbuf); - ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table); - ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file); - ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name "); + ast_str_set(&sql, 0, "SELECT cat_metric, category, var_name, var_val FROM %s ", table); + ast_str_append(&sql, 0, "WHERE filename='%s' AND commented=0 ", file); + ast_str_append(&sql, 0, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name "); + q.sql = ast_str_buffer(sql); q.var_val_size += 1; q.var_val = ast_malloc(q.var_val_size); @@ -966,9 +981,8 @@ static struct ast_config *config_odbc(const char *database, const char *table, c } stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q); - if (!stmt) { - ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql)); ast_odbc_release_obj(obj); ast_free(q.var_val); return NULL; @@ -977,7 +991,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c res = SQLNumResultCols(stmt, &rowcount); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql); + ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql)); SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); ast_free(q.var_val); From bffaf4669007b6685824b5145aa62b8f0e2ca3d7 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Mon, 19 Sep 2016 16:40:40 +0200 Subject: [PATCH 0755/1578] asterisk.c: When astcanary dies on linux, reset priority on all threads. Previously only the canary checking thread itself had its priority set to SCHED_OTHER. Now all threads are traversed and adjusted. ASTERISK-19867 #close Reported by: Xavier Hienne Change-Id: Ie0dd02a3ec42f66a78303e9c1aac28f7ed9aae39 --- main/asterisk.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/main/asterisk.c b/main/asterisk.c index 3c2ca259ee9..37a69dff47a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1778,6 +1778,46 @@ static void set_icon(char *text) fprintf(stdout, "\033]1;%s\007", text); } +/*! \brief Set priority on all known threads. */ +static int set_priority_all(int pri) +{ +#if !defined(__linux__) + /* The non-linux version updates the entire process prio. */ + return ast_set_priority(pri); +#elif defined(LOW_MEMORY) + ast_log(LOG_WARNING, "Unable to enumerate all threads to update priority\n"); + return ast_set_priority(pri); +#else + struct thread_list_t *cur; + struct sched_param sched; + char const *policy_str; + int policy; + + memset(&sched, 0, sizeof(sched)); + if (pri) { + policy = SCHED_RR; + policy_str = "realtime"; + sched.sched_priority = 10; + } else { + policy = SCHED_OTHER; + policy_str = "regular"; + sched.sched_priority = 0; + } + if (sched_setscheduler(getpid(), policy, &sched)) { + ast_log(LOG_WARNING, "Unable to set %s thread priority on main thread\n", policy_str); + return -1; + } + ast_verb(1, "Setting %s thread priority on all threads\n", policy_str); + AST_RWLIST_RDLOCK(&thread_list); + AST_RWLIST_TRAVERSE(&thread_list, cur, list) { + /* Don't care about the return value. It should work. */ + sched_setscheduler(cur->lwp, policy, &sched); + } + AST_RWLIST_UNLOCK(&thread_list); + return 0; +#endif +} + /*! \brief We set ourselves to a high priority, that we might pre-empt * everything else. If your PBX has heavy activity on it, this is a * good thing. @@ -3744,7 +3784,7 @@ static void *canary_thread(void *unused) "He's kicked the bucket. He's shuffled off his mortal coil, " "run down the curtain, and joined the bleeding choir invisible!! " "THIS is an EX-CANARY. (Reducing priority)\n"); - ast_set_priority(0); + set_priority_all(0); pthread_exit(NULL); } From 0bc99127398946510d6f05a31806574c4816ed4d Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Mon, 19 Sep 2016 21:21:23 +0200 Subject: [PATCH 0756/1578] asterisk.c: Non-root users also get the astcanary after core restart. Without this change, a 'core restart' would kill the astcanary forever if you're not running as root. Both with and without this patch, the scheduling priority was still SCHED_RR after restart. Additionally, the astcanary is now spawned if you start with high priority and Asterisk doesn't get a chance to lower it. For example through: `chrt -r 10 sudo -u asterisk asterisk -c` Also reap killed astcanary processes on core restart. ASTERISK-26352 #close Change-Id: Iacb49f26491a0717084ad46ed96b0bea5f627a55 --- main/asterisk.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/main/asterisk.c b/main/asterisk.c index 37a69dff47a..974c51dac9b 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1778,6 +1778,26 @@ static void set_icon(char *text) fprintf(stdout, "\033]1;%s\007", text); } +/*! \brief Check whether we were set to high(er) priority. */ +static int has_priority(void) +{ + /* Neither of these calls should fail with these arguments. */ +#ifdef __linux__ + /* For SCHED_OTHER, SCHED_BATCH and SCHED_IDLE, this will return + * 0. For the realtime priorities SCHED_RR and SCHED_FIFO, it + * will return something >= 1. */ + return sched_getscheduler(0); +#else + /* getpriority() can return a value in -20..19 (or even -INF..20) + * where negative numbers are high priority. We don't bother + * checking errno. If the query fails and it returns -1, we'll + * assume that we're running at high prio; a safe assumption + * that will enable the resource starvation monitor (canary) + * just in case. */ + return (getpriority(PRIO_PROCESS, 0) < 0); +#endif +} + /*! \brief Set priority on all known threads. */ static int set_priority_all(int pri) { @@ -3796,8 +3816,11 @@ static void *canary_thread(void *unused) /* Used by libc's atexit(3) function */ static void canary_exit(void) { - if (canary_pid > 0) + if (canary_pid > 0) { + int status; kill(canary_pid, SIGKILL); + waitpid(canary_pid, &status, 0); + } } /* Execute CLI commands on startup. Run by main() thread. */ @@ -4340,8 +4363,16 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou __ast_mm_init_phase_1(); #endif /* defined(__AST_DEBUG_MALLOC) */ + /* Check whether high prio was succesfully set by us or some + * other incantation. */ + if (has_priority()) { + ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY); + } else { + ast_clear_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY); + } + /* Spawning of astcanary must happen AFTER the call to daemon(3) */ - if (isroot && ast_opt_high_priority) { + if (ast_opt_high_priority) { snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR); /* Don't let the canary child kill Asterisk, if it dies immediately */ From 74f562a8e2da5acdcde12d58f41e231962236ef9 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 20 Sep 2016 11:16:42 -0400 Subject: [PATCH 0757/1578] logger: Fix default console settings. When logger.conf is missing or invalid we should be printing notices, warnings and errors to the console. The logmask was incorrectly calculated. Change-Id: Ibaa9465a8682854bc1a5e9ba07079bea1bfb6bb3 --- main/logger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/logger.c b/main/logger.c index 9a16dcf13bc..db3d7a730a1 100644 --- a/main/logger.c +++ b/main/logger.c @@ -663,7 +663,7 @@ static int init_logger_chain(const char *altconf) return -1; } chan->type = LOGTYPE_CONSOLE; - chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR; + chan->logmask = (1 << __LOG_WARNING) | (1 << __LOG_NOTICE) | (1 << __LOG_ERROR); memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter)); AST_RWLIST_INSERT_HEAD(&logchannels, chan, list); From 00f1d05d34219f5cb0fc29032a928c3919924d62 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 20 Sep 2016 10:22:45 -0400 Subject: [PATCH 0758/1578] logger: Always enable verbose for console channel. Previous versions of Asterisk did not require verbose to be specified in logger.conf for the console channel, if it was requested by command line or asterisk.conf it just worked. This change causes Asterisk to always enable verbose in the console channel level mask. Verbose is displayed on consoles if requested by command line, option_verbose or 'core set verbose'. This also delays initialization of the logger until after threadstorage is initialized. Initializing too early can cause messages to be printed multiple times to the console (stdout). ASTERISK-26391 #close Change-Id: I52187d67c2fcb3efd5561bf04b3e5e23e5ee8a04 --- main/asterisk.c | 2 +- main/logger.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/main/asterisk.c b/main/asterisk.c index 7b1338c3dcf..fb47d9927e3 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4448,7 +4448,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou check_init(ast_format_cache_init(), "Format Cache"); check_init(ast_codec_builtin_init(), "Built-in Codecs"); check_init(aco_init(), "Configuration Option Framework"); - check_init(init_logger(), "Logger"); check_init(ast_bucket_init(), "Bucket API"); check_init(stasis_init(), "Stasis"); check_init(ast_stasis_system_init(), "Stasis system-level information"); @@ -4478,6 +4477,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou threadstorage_init(); + check_init(init_logger(), "Logger"); check_init(ast_rtp_engine_init(), "RTP Engine"); ast_autoservice_init(); diff --git a/main/logger.c b/main/logger.c index db3d7a730a1..315de9f231c 100644 --- a/main/logger.c +++ b/main/logger.c @@ -479,6 +479,7 @@ static void make_components(struct logchannel *chan) * with calculating the ast_verb_sys_level value. */ chan->verbosity = -1; + logmask |= (1 << __LOG_VERBOSE); } else { chan->verbosity = verb_level; } @@ -663,7 +664,8 @@ static int init_logger_chain(const char *altconf) return -1; } chan->type = LOGTYPE_CONSOLE; - chan->logmask = (1 << __LOG_WARNING) | (1 << __LOG_NOTICE) | (1 << __LOG_ERROR); + chan->logmask = (1 << __LOG_WARNING) | (1 << __LOG_NOTICE) | (1 << __LOG_ERROR) + | (1 << __LOG_VERBOSE); memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter)); AST_RWLIST_INSERT_HEAD(&logchannels, chan, list); From 5cb905a227c7f9dd283e87ff1b677f753c61169f Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 20 Sep 2016 16:17:42 -0400 Subject: [PATCH 0759/1578] core: Fix LOW_MEMORY missing symbol ast_pbx_uuid_get. Move the function outside the conditional block that excludes LOW_MEMORY. ASTERISK-26273 #close Change-Id: Ic290fa128222c410c3531107e30efacabc8493b4 --- main/asterisk.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main/asterisk.c b/main/asterisk.c index c9e3b59a5bd..aaabf583f82 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -591,11 +591,6 @@ void ast_unregister_thread(void *id) } } -int ast_pbx_uuid_get(char *pbx_uuid, int length) -{ - return ast_db_get("pbx", "UUID", pbx_uuid, length); -} - /*! \brief Give an overview of core settings */ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { @@ -1040,6 +1035,11 @@ static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_c #endif /* ! LOW_MEMORY */ +int ast_pbx_uuid_get(char *pbx_uuid, int length) +{ + return ast_db_get("pbx", "UUID", pbx_uuid, length); +} + static void publish_fully_booted(void) { RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref); From 923edf2596243362badeec369b27bfcbff5efe62 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 16 Aug 2016 16:21:33 -0400 Subject: [PATCH 0760/1578] logger: Simplify ast_callid handling code. Routines responsible for managing ast_callid's are overly complicated. This is left-over code from when ast_callid was an AO2 object. Now that it is an integer the code can be reduced. ast_callid handler code no longer prints it's own error message upon failure to allocate threadstorage as ast_calloc would have already printed a message. Debug messages that were printed when TEST_FRAMEWORK was enabled have been also been removed. Change-Id: I65a768a78dc6cf3cfa071e97f33ce3dce280258e --- main/logger.c | 51 +++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/main/logger.c b/main/logger.c index 9a16dcf13bc..c111182422b 100644 --- a/main/logger.c +++ b/main/logger.c @@ -1762,13 +1762,7 @@ void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid) ast_callid ast_create_callid(void) { - ast_callid call; - - call = ast_atomic_fetchadd_int(&next_unique_callid, +1); -#ifdef TEST_FRAMEWORK - ast_debug(3, "CALL_ID [C-%08x] created by thread.\n", call); -#endif - return call; + return ast_atomic_fetchadd_int(&next_unique_callid, +1); } ast_callid ast_read_threadstorage_callid(void) @@ -1778,7 +1772,6 @@ ast_callid ast_read_threadstorage_callid(void) callid = ast_threadstorage_get(&unique_callid, sizeof(*callid)); return callid ? *callid : 0; - } int ast_callid_threadassoc_change(ast_callid callid) @@ -1786,23 +1779,10 @@ int ast_callid_threadassoc_change(ast_callid callid) ast_callid *id = ast_threadstorage_get(&unique_callid, sizeof(*id)); if (!id) { - ast_log(LOG_ERROR, "Failed to allocate thread storage.\n"); return -1; } - if (*id && (*id != callid)) { -#ifdef TEST_FRAMEWORK - ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", *id); -#endif - *id = 0; - } - - if (!(*id) && callid) { - *id = callid; -#ifdef TEST_FRAMEWORK - ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", callid); -#endif - } + *id = callid; return 0; } @@ -1812,21 +1792,17 @@ int ast_callid_threadassoc_add(ast_callid callid) ast_callid *pointing; pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing)); - if (!(pointing)) { - ast_log(LOG_ERROR, "Failed to allocate thread storage.\n"); + if (!pointing) { return -1; } - if (!(*pointing)) { - *pointing = callid; -#ifdef TEST_FRAMEWORK - ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", callid); -#endif - } else { - ast_log(LOG_WARNING, "Attempted to ast_callid_threadassoc_add on thread already associated with a callid.\n"); + if (*pointing) { + ast_log(LOG_ERROR, "ast_callid_threadassoc_add(C-%08x) on thread " + "already associated with callid [C-%08x].\n", callid, *pointing); return 1; } + *pointing = callid; return 0; } @@ -1835,21 +1811,16 @@ int ast_callid_threadassoc_remove(void) ast_callid *pointing; pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing)); - if (!(pointing)) { - ast_log(LOG_ERROR, "Failed to allocate thread storage.\n"); + if (!pointing) { return -1; } - if (!(*pointing)) { - ast_log(LOG_ERROR, "Tried to clean callid thread storage with no callid in thread storage.\n"); - return -1; - } else { -#ifdef TEST_FRAMEWORK - ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", *pointing); -#endif + if (*pointing) { *pointing = 0; return 0; } + + return -1; } int ast_callid_threadstorage_auto(ast_callid *callid) From 78b6190a117f621340074068d31be1e4faaef29e Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 21 Sep 2016 13:46:36 +0000 Subject: [PATCH 0761/1578] odbc: Remove options that are no longer applicable. The pooling, shared_connection, limit, and idlecheck options are no longer used in res_odbc. ASTERISK-26389 Change-Id: I2fde7b467d01f9d1c82cc0a339bb4f7e1dd6bbe6 --- configs/samples/res_odbc.conf.sample | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/configs/samples/res_odbc.conf.sample b/configs/samples/res_odbc.conf.sample index a21e96d0713..42d89ec0fd8 100644 --- a/configs/samples/res_odbc.conf.sample +++ b/configs/samples/res_odbc.conf.sample @@ -38,19 +38,6 @@ pre-connect => yes ; record. The default is "select 1". ;sanitysql => select 1 ; -; On some databases, the connection times out and a reconnection will be -; necessary. This setting configures the amount of time a connection -; may sit idle (in seconds) before a reconnection will be attempted. -;idlecheck => 3600 -; -; Should we use a single connection for all queries? Most databases will -; allow sharing the connection, though Sybase and MS SQL Server will not. -;share_connections => yes -; -; If we aren't sharing connections, what is the maximum number of connections -; that we should attempt? -;limit => 5 -; ; The maximum number of connections to have open at any given time. ; This defaults to 1 and it is highly recommended to only set this higher ; if using a version of UnixODBC greater than 2.3.1. From 077caf566ef0bc463261e257cfc1e1c5f62fdd17 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 21 Sep 2016 15:48:47 +0000 Subject: [PATCH 0762/1578] res_odbc: Make pooling option deprecation notice more useful. This changes the notice for the deprecation of the old pooling options to point to the new option for doing pooling. This gives a clearer direction as to what to look into. ASTERISK-26389 #close Change-Id: I2ca9cdfdcd75aec170a7db9d5ff69a4cd25b7c10 --- res/res_odbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_odbc.c b/res/res_odbc.c index f89b59e51c7..b207049fef4 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -523,7 +523,7 @@ static int load_odbc_config(void) !strncasecmp(v->name, "share", 5) || !strcasecmp(v->name, "limit") || !strcasecmp(v->name, "idlecheck")) { - ast_log(LOG_WARNING, "The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options are deprecated. Please see UPGRADE.txt for information\n"); + ast_log(LOG_WARNING, "The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were replaced by 'max_connections'. See res_odbc.conf.sample.\n"); } else if (!strcasecmp(v->name, "enabled")) { enabled = ast_true(v->value); } else if (!strcasecmp(v->name, "pre-connect")) { From a805d779e84c9e0fd4905c031b291bc938fdc816 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 21 Sep 2016 19:24:08 +0000 Subject: [PATCH 0763/1578] core: Ensure presencestate subtype and message are NULL. When retrieving presence state information there is no guarantee that the subtype and message passed in are set to NULL. This change ensures they are. ASTERISK-26397 #close Change-Id: If38cd730e409e9a9b6eb9adef6591d15a9e61f86 --- main/presencestate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/presencestate.c b/main/presencestate.c index 3be2ebeede2..c0a0ebdc194 100644 --- a/main/presencestate.c +++ b/main/presencestate.c @@ -161,6 +161,9 @@ static enum ast_presence_state ast_presence_state_helper(const char *presence_pr [AST_PRESENCE_DND] = 7 }; + *subtype = NULL; + *message = NULL; + while ((label = strsep(&labels, "&"))) { enum ast_presence_state next_state = AST_PRESENCE_INVALID; char *next_subtype = NULL; From 18a8ca06eb22b38c90c2407625f4156c500995dd Mon Sep 17 00:00:00 2001 From: Aaron An Date: Thu, 22 Sep 2016 14:40:45 +0800 Subject: [PATCH 0764/1578] channels/chan_pjsip: fix HANGUPCAUSE function bug. HANGUPCAUSE not return 'SIP 200 Ok' when dialed channel answered. This patch change the call order of ast_queue_control_data and ast_queue_control in chan_pjsip_incoming_response. ASTERISK-26396 #close Reported by: AaronAn Tested by: AaronAn Change-Id: Ide2d31723d8d425961e985de7de625694580be61 --- channels/chan_pjsip.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 02da0db35b1..00d4a1452fd 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2370,6 +2370,21 @@ static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct return; } + /* Build and send the tech-specific cause information */ + /* size of the string making up the cause code is "SIP " number + " " + reason length */ + data_size += 4 + 4 + pj_strlen(&status.reason); + cause_code = ast_alloca(data_size); + memset(cause_code, 0, data_size); + + ast_copy_string(cause_code->chan_name, ast_channel_name(session->channel), AST_CHANNEL_NAME); + + snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "SIP %d %.*s", status.code, + (int) pj_strlen(&status.reason), pj_strbuf(&status.reason)); + + cause_code->ast_cause = hangup_sip2cause(status.code); + ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size); + ast_channel_hangupcause_hash_set(session->channel, cause_code, data_size); + switch (status.code) { case 180: ast_queue_control(session->channel, AST_CONTROL_RINGING); @@ -2388,21 +2403,6 @@ static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct default: break; } - - /* Build and send the tech-specific cause information */ - /* size of the string making up the cause code is "SIP " number + " " + reason length */ - data_size += 4 + 4 + pj_strlen(&status.reason); - cause_code = ast_alloca(data_size); - memset(cause_code, 0, data_size); - - ast_copy_string(cause_code->chan_name, ast_channel_name(session->channel), AST_CHANNEL_NAME); - - snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "SIP %d %.*s", status.code, - (int) pj_strlen(&status.reason), pj_strbuf(&status.reason)); - - cause_code->ast_cause = hangup_sip2cause(status.code); - ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size); - ast_channel_hangupcause_hash_set(session->channel, cause_code, data_size); } static int chan_pjsip_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata) From d425971009f84d38206392be2b20fc8da4bef820 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 20 Sep 2016 08:42:15 -0600 Subject: [PATCH 0765/1578] chan_sip: Address runaway when realtime peers subscribe to mailboxes Users upgrading from asterisk 13.5 to a later version and who use realtime with peers that have mailboxes were experiencing runaway situations that manifested as a continuous stream of taskprocessor congestion errors, memory leaks and an unresponsive chan_sip. A related issue was that setting rtcachefriends=no NEVER worked in asterisk 13 (since the move to stasis). In 13.5 and earlier, when a peer tried to register, all of the stasis threads would block and chan_sip would again become unresponsive. After 13.5, the runaway would happen. There were a number of causes... * mwi_event_cb was (indirectly) calling build_peer even though calls to mwi_event_cb are often caused by build_peer. * In an effort to prevent chan_sip from being unloaded while messages were still in flight, destroy_mailboxes was calling stasis_unsubscribe_and_join but in some cases waited forever for the final message. * add_peer_mailboxes wasn't properly marking the existing mailboxes on a peer as "keep" so build_peer would always delete them all. * add_peer_mwi_subs was unsubscribing existing mailbox subscriptions then just creating them again. All of this was causing a flood of subscribes and unsubscribes on multiple threads all for the same peer and mailbox. Fixes... * add_peer_mailboxes now marks mailboxes correctly and build_peer only deletes the ones that really are no longer needed by the peer. * add_peer_mwi_subs now only adds subscriptions marked as "new" instead of unsubscribing and resubscribing everything. It also adds the peer object's address to the mailbox instead of its name to the subscription userdata so mwi_event_cb doesn't have to call build_peer. With these changes, with rtcachefriends=yes (the most common setting), there are no leaks, locks, loops or crashes at shutdown. rtcachefriends=no still causes leaks but at least it doesn't lock, loop or crash. Since making rtcachefriends=no work wasnt in scope for this issue, further work will have to be deferred to a separate patch. Side fixes... * The ast_lock_track structure had a member named "thread" which gdb doesn't like since it conflicts with it's "thread" command. That member was renamed to "thread_id". ASTERISK-25468 #close Change-Id: I07519ef7f092629e1e844f855abd279d6475cdd0 --- channels/chan_sip.c | 59 ++++++++++++++++++++++++++------------ channels/sip/include/sip.h | 9 +++++- include/asterisk/lock.h | 2 +- main/lock.c | 36 +++++++++++------------ 4 files changed, 67 insertions(+), 39 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 08a16805f09..74514b1ef3e 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1278,6 +1278,7 @@ static void mwi_event_cb(void *, struct stasis_subscription *, struct stasis_mes static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message); static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message); static void sip_keepalive_all_peers(void); +#define peer_in_destruction(peer) (ao2_ref(peer, 0) == 0) /*--- Applications, functions, CLI and manager command helpers */ static const char *sip_nat_mode(const struct sip_pvt *p); @@ -5202,13 +5203,24 @@ static void destroy_mailbox(struct sip_mailbox *mailbox) ast_free(mailbox); } +#define REMOVE_MAILBOX_WITH_LOCKED_PEER(__peer) \ +({\ + struct sip_mailbox *__mailbox;\ + ao2_lock(__peer);\ + __mailbox = AST_LIST_REMOVE_HEAD(&(__peer->mailboxes), entry);\ + ao2_unlock(__peer);\ + __mailbox;\ +}) + /*! Destroy all peer-related mailbox subscriptions */ static void clear_peer_mailboxes(struct sip_peer *peer) { struct sip_mailbox *mailbox; - while ((mailbox = AST_LIST_REMOVE_HEAD(&peer->mailboxes, entry))) + /* Lock the peer while accessing/updating the linked list but NOT while destroying the mailbox */ + while ((mailbox = REMOVE_MAILBOX_WITH_LOCKED_PEER(peer))) { destroy_mailbox(mailbox); + } } static void sip_destroy_peer_fn(void *peer) @@ -17260,19 +17272,21 @@ static void sip_peer_hold(struct sip_pvt *p, int hold) /*! \brief Receive MWI events that we have subscribed to */ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg) { - char *peer_name = userdata; - struct sip_peer *peer = sip_find_peer(peer_name, NULL, TRUE, FINDALLDEVICES, FALSE, 0); + struct sip_peer *peer = userdata; - if (stasis_subscription_final_message(sub, msg)) { - /* peer can be non-NULL during reload. */ - ao2_cleanup(peer); - ast_free(peer_name); + /* + * peer can't be NULL here but the peer can be in the process of being + * destroyed. If it is, we don't want to send any messages. In most cases, + * the peer is actually gone and there's no sense sending NOTIFYs that will + * never be answered. + */ + if (stasis_subscription_final_message(sub, msg) || peer_in_destruction(peer)) { return; } - if (peer && ast_mwi_state_type() == stasis_message_type(msg)) { + + if (ast_mwi_state_type() == stasis_message_type(msg)) { sip_send_mwi_to_peer(peer, 0); } - ao2_cleanup(peer); } static void network_change_stasis_subscribe(void) @@ -27991,15 +28005,14 @@ static void add_peer_mwi_subs(struct sip_peer *peer) AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { struct stasis_topic *mailbox_specific_topic; - mailbox->event_sub = stasis_unsubscribe(mailbox->event_sub); + + if (mailbox->status != SIP_MAILBOX_STATUS_NEW) { + continue; + } mailbox_specific_topic = ast_mwi_topic(mailbox->id); if (mailbox_specific_topic) { - char *peer_name = ast_strdup(peer->name); - if (!peer_name) { - return; - } - mailbox->event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, peer_name); + mailbox->event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, peer); } } } @@ -29224,7 +29237,9 @@ static int get_cached_mwi(struct sip_peer *peer, int *new, int *old) } /*! \brief Send message waiting indication to alert peer that they've got voicemail - * \note Both peer and associated sip_pvt must be unlocked prior to calling this function + * \note Both peer and associated sip_pvt must be unlocked prior to calling this function. + * It's possible that this function will get called during peer destruction as final messages + * are processed. The peer will still be valid however. * \returns -1 on failure, 0 on success */ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only) @@ -31074,6 +31089,7 @@ static void add_peer_mailboxes(struct sip_peer *peer, const char *value) AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { if (!strcmp(mailbox->id, mbox)) { duplicate = 1; + mailbox->status = SIP_MAILBOX_STATUS_EXISTING; break; } } @@ -31086,14 +31102,18 @@ static void add_peer_mailboxes(struct sip_peer *peer, const char *value) continue; } strcpy(mailbox->id, mbox); /* SAFE */ + mailbox->status = SIP_MAILBOX_STATUS_NEW; + mailbox->peer = peer; AST_LIST_INSERT_TAIL(&peer->mailboxes, mailbox, entry); } } /*! \brief Build peer from configuration (file or realtime static/dynamic) */ -static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime, int devstate_only) +static struct sip_peer *build_peer(const char *name, struct ast_variable *v_head, struct ast_variable *alt, int realtime, int devstate_only) { + /* We preserve the original value of v_head to make analyzing backtraces easier */ + struct ast_variable *v = v_head; struct sip_peer *peer = NULL; struct ast_acl_list *oldacl = NULL; struct ast_acl_list *olddirectmediaacl = NULL; @@ -31157,6 +31177,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str return NULL; } + if (realtime && !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) { ast_atomic_fetchadd_int(&rpeerobjs, 1); ast_debug(3, "-REALTIME- peer built. Name: %s. Peer objects: %d\n", name, rpeerobjs); @@ -31206,7 +31227,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str if (!devstate_only) { struct sip_mailbox *mailbox; AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { - mailbox->delme = 1; + mailbox->status = SIP_MAILBOX_STATUS_UNKNOWN; } } @@ -31666,7 +31687,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str if (!devstate_only) { struct sip_mailbox *mailbox; AST_LIST_TRAVERSE_SAFE_BEGIN(&peer->mailboxes, mailbox, entry) { - if (mailbox->delme) { + if (mailbox->status == SIP_MAILBOX_STATUS_UNKNOWN) { AST_LIST_REMOVE_CURRENT(entry); destroy_mailbox(mailbox); } diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 92dcd56277b..e511d139b02 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -1237,6 +1237,12 @@ struct sip_pkt { struct ast_str *data; }; +enum sip_mailbox_status { + SIP_MAILBOX_STATUS_UNKNOWN = 0, + SIP_MAILBOX_STATUS_EXISTING, + SIP_MAILBOX_STATUS_NEW, +}; + /*! * \brief A peer's mailbox * @@ -1247,7 +1253,8 @@ struct sip_mailbox { /*! Associated MWI subscription */ struct stasis_subscription *event_sub; AST_LIST_ENTRY(sip_mailbox) entry; - unsigned int delme:1; + struct sip_peer *peer; + enum sip_mailbox_status status; char id[1]; }; diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index 35a244b5bc1..652ca136eae 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -113,7 +113,7 @@ struct ast_lock_track { int lineno[AST_MAX_REENTRANCY]; int reentrancy; const char *func[AST_MAX_REENTRANCY]; - pthread_t thread[AST_MAX_REENTRANCY]; + pthread_t thread_id[AST_MAX_REENTRANCY]; #ifdef HAVE_BKTR struct ast_bt backtrace[AST_MAX_REENTRANCY]; #endif diff --git a/main/lock.c b/main/lock.c index 2b2a80984c4..b35ec597c63 100644 --- a/main/lock.c +++ b/main/lock.c @@ -218,7 +218,7 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu lt->lineno[0] = lineno; lt->func[0] = func; lt->reentrancy = 0; - lt->thread[0] = 0; + lt->thread_id[0] = 0; #ifdef HAVE_BKTR memset(<->backtrace[0], 0, sizeof(lt->backtrace[0])); #endif @@ -322,7 +322,7 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = lineno; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } else { __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", @@ -402,7 +402,7 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = lineno; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } else { __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", @@ -445,7 +445,7 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun if (lt) { ast_reentrancy_lock(lt); - if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) { + if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) { __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n", filename, lineno, func, mutex_name); __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", @@ -466,7 +466,7 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun lt->file[lt->reentrancy] = NULL; lt->lineno[lt->reentrancy] = 0; lt->func[lt->reentrancy] = NULL; - lt->thread[lt->reentrancy] = 0; + lt->thread_id[lt->reentrancy] = 0; } #ifdef HAVE_BKTR @@ -536,7 +536,7 @@ static void restore_lock_tracking(struct ast_lock_track *lt, struct ast_lock_tra memcpy(lt->lineno, lt_saved->lineno, sizeof(lt->lineno)); lt->reentrancy = lt_saved->reentrancy; memcpy(lt->func, lt_saved->func, sizeof(lt->func)); - memcpy(lt->thread, lt_saved->thread, sizeof(lt->thread)); + memcpy(lt->thread_id, lt_saved->thread_id, sizeof(lt->thread_id)); #ifdef HAVE_BKTR memcpy(lt->backtrace, lt_saved->backtrace, sizeof(lt->backtrace)); #endif @@ -571,7 +571,7 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func, if (lt) { ast_reentrancy_lock(lt); - if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) { + if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) { __ast_mutex_logger("%s line %d (%s): attempted wait using mutex '%s' without owning it!\n", filename, lineno, func, mutex_name); __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", @@ -639,7 +639,7 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func, if (lt) { ast_reentrancy_lock(lt); - if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) { + if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) { __ast_mutex_logger("%s line %d (%s): attempted wait using mutex '%s' without owning it!\n", filename, lineno, func, mutex_name); __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", @@ -747,7 +747,7 @@ int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, con lt->lineno[0] = lineno; lt->func[0] = func; lt->reentrancy = 0; - lt->thread[0] = 0; + lt->thread_id[0] = 0; #ifdef HAVE_BKTR memset(<->backtrace[0], 0, sizeof(lt->backtrace[0])); #endif @@ -790,13 +790,13 @@ int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rw int i; pthread_t self = pthread_self(); for (i = lt->reentrancy - 1; i >= 0; --i) { - if (lt->thread[i] == self) { + if (lt->thread_id[i] == self) { lock_found = 1; if (i != lt->reentrancy - 1) { lt->file[i] = lt->file[lt->reentrancy - 1]; lt->lineno[i] = lt->lineno[lt->reentrancy - 1]; lt->func[i] = lt->func[lt->reentrancy - 1]; - lt->thread[i] = lt->thread[lt->reentrancy - 1]; + lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1]; } #ifdef HAVE_BKTR bt = <->backtrace[i]; @@ -804,7 +804,7 @@ int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rw lt->file[lt->reentrancy - 1] = NULL; lt->lineno[lt->reentrancy - 1] = 0; lt->func[lt->reentrancy - 1] = NULL; - lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL; + lt->thread_id[lt->reentrancy - 1] = AST_PTHREADT_NULL; break; } } @@ -918,7 +918,7 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = line; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } ast_reentrancy_unlock(lt); @@ -1027,7 +1027,7 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = line; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } ast_reentrancy_unlock(lt); @@ -1120,7 +1120,7 @@ int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, a lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = line; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } ast_reentrancy_unlock(lt); @@ -1213,7 +1213,7 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = line; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } ast_reentrancy_unlock(lt); @@ -1288,7 +1288,7 @@ int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = line; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } ast_reentrancy_unlock(lt); @@ -1347,7 +1347,7 @@ int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = line; lt->func[lt->reentrancy] = func; - lt->thread[lt->reentrancy] = pthread_self(); + lt->thread_id[lt->reentrancy] = pthread_self(); lt->reentrancy++; } ast_reentrancy_unlock(lt); From 5dd99465d3436a36ad68fe115d8bd1c3705a4073 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Fri, 23 Sep 2016 16:54:28 +0200 Subject: [PATCH 0766/1578] chan_sip: Resolve externhost not to IPv6; instead go for IPv4. For the channel driver chan_sip, you specify externhost=example.com in sip.conf when your Asterisk is behind a NAT and your IP address is assigned dynamically. Or stated differently: You do not have a static IP address to use "externaddr" directly. This NAT support is quite handy but just about IPv4. Previously, Asterisk resolved "externhost" to any IP version. When the first DNS answer resolved to an IPv6, Asterisk sent an IPv6 in SIP/SDP for origin (o=) and connection (c=). This happened in outgoing SIP-REGISTER and while answering SIP-INVITE. If the remote peer is IPv4-only, it might not handle o=/c= with an IPv6. This change makes sure, no IPv6 is resolved anymore for "externhost". ASTERISK-18232 #close Reported by: Jacek Kowalski Tested by: Alexander Traud patches: changes.patch submitted by Alessandro Crespi Change-Id: If68eedbeff65bd1c1d8a9ed921c02ba464b32dac --- channels/chan_sip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 08a16805f09..fadb349a16b 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3843,7 +3843,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka (!sip_cfg.matchexternaddrlocally || !ast_apply_ha(localaddr, us)) ) { /* if we used externhost, see if it is time to refresh the info */ if (externexpire && time(NULL) >= externexpire) { - if (ast_sockaddr_resolve_first(&externaddr, externhost, 0)) { + if (ast_sockaddr_resolve_first_af(&externaddr, externhost, 0, AST_AF_INET)) { ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost); } externexpire = time(NULL) + externrefresh; @@ -32573,7 +32573,7 @@ static int reload_config(enum channelreloadreason reason) externexpire = 0; } else if (!strcasecmp(v->name, "externhost")) { ast_copy_string(externhost, v->value, sizeof(externhost)); - if (ast_sockaddr_resolve_first(&externaddr, externhost, 0)) { + if (ast_sockaddr_resolve_first_af(&externaddr, externhost, 0, AST_AF_INET)) { ast_log(LOG_WARNING, "Invalid address for externhost keyword: %s\n", externhost); } externexpire = time(NULL); From 43901e94181e871c9a0e3e1f8475d4c8ee072e1e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 24 Sep 2016 18:05:02 -0600 Subject: [PATCH 0767/1578] build_tools: Add ability to download variants to download_externals Some external packages have multiple variants that apply to different builds of asterisk. The DPMA for instance has a "bundled" variant that needs to be downloaded if asterisk was configured with --with-pjproject-bundled. There are 2 ways to specify variants: If you need the user to make the decision about which variant to download, simply create multiple menuselect "member" entries like so... external xmlstarlet bash no external xmlstarlet bash no Note that the second entry has "-" appended to the name. You can then use the existing menuselect facilities to restrict which members to enable or disable. Youy probably don't want the user to enable multiple at the same time. If you want to hide the details of the variants, the better way to do it is to create 1 member with "variant" elements. external xmlstarlet bash no The condition must be a bash expression suitable for use with an "if" statement. Any environment variable can be used plus those available in makeopts. In this case, if asterisk was configured with --with-pjproject-bundled the bundled variant will be automatically downloaded. Otherwise the normal version will be downloaded. Change-Id: I4de23e06d4492b0a65e105c8369966547d0faa3e --- build_tools/download_externals | 96 +++++++++++++++++++++++++--------- res/res.xml | 7 +++ 2 files changed, 77 insertions(+), 26 deletions(-) diff --git a/build_tools/download_externals b/build_tools/download_externals index 8d5872df799..9b2b841821f 100755 --- a/build_tools/download_externals +++ b/build_tools/download_externals @@ -7,7 +7,12 @@ set -e ASTTOPDIR=${ASTTOPDIR:-.} -module_name=$1 +module_name=${1%%-*} +variant=${1##*-} + +if [[ "${variant}" = "${module_name}" ]] ; then + unset variant +fi if [[ -z ${module_name} ]] ; then echo "You must supply a module name." @@ -59,12 +64,35 @@ else host_bits=32 fi -remote_url=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@remote_url" ${ASTTOPDIR}/menuselect-tree || :) -if [[ -n "${remote_url}" ]] ; then - remote_url="${remote_url}/asterisk-${major_version}/x86-${host_bits}" +if [[ -z "${variant}" ]] ; then + variants=$(${XMLSTARLET} sel -t -m "/menu/category/member[@name = '${module_name}']/member_data/downloader/variants/variant" -v "@tag" -n ${ASTTOPDIR}/menuselect-tree || :) + member_name=${module_name} + for tag in ${variants} ; do + condition=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/variants/variant[@tag = '${tag}']/@condition" ${ASTTOPDIR}/menuselect-tree || :) + variant=$(eval "if $condition ; then echo $tag ; fi") + if [[ -n "${variant}" ]] ; then + break + fi + done else - directory_name=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@directory_name" ${ASTTOPDIR}/menuselect-tree || :) - remote_url="http://downloads.digium.com/pub/telephony/${directory_name:-${module_name}}/asterisk-${major_version}/x86-${host_bits}" + member_name=${module_name}${variant:+-${variant}} +fi + +full_name=${module_name}${variant:+-${variant}} +variant_manifest=manifest${variant:+-${variant}}.xml + +# Override the remote base for all packages +# useful for testing +remote_url=${REMOTE_BASE:+${REMOTE_BASE}/asterisk-${major_version}/x86-${host_bits}} + +if [[ -z "${remote_url}" ]] ; then + remote_url=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${member_name}']/member_data/downloader/@remote_url" ${ASTTOPDIR}/menuselect-tree || :) + if [[ -n "${remote_url}" ]] ; then + remote_url="${remote_url}/asterisk-${major_version}/x86-${host_bits}" + else + directory_name=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${member_name}']/member_data/downloader/@directory_name" ${ASTTOPDIR}/menuselect-tree || :) + remote_url="http://downloads.digium.com/pub/telephony/${directory_name:-${module_name}}/asterisk-${major_version}/x86-${host_bits}" + fi fi version_convert() { @@ -75,44 +103,60 @@ version_convert() { echo ${v} } -${WGET} -q -O ${tmpdir}/manifest.xml ${remote_url}/manifest.xml || { - echo "${module_name}: Unable to fetch ${remote_url}/manifest.xml" +${WGET} -q -O ${tmpdir}/${variant_manifest} ${remote_url}/${variant_manifest} || { + echo "${full_name}: Unable to fetch ${remote_url}/${variant_manifest}" exit 1 } -rpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${tmpdir}/manifest.xml) +rpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${tmpdir}/${variant_manifest}) rpvi=$(version_convert ${rpv}) -echo "${module_name}: Remote package version ${rpv} (${rpvi})" +echo "${full_name}: Remote package version ${rpv} (${rpvi})" -module_dir=${module_name}-${rpv}-x86_${host_bits} +module_dir=${full_name}-${rpv}-x86_${host_bits} tarball=${module_dir}.tar.gz + export need_install=0 if [[ -f ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ]] ; then package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) ipv=$(${XMLSTARLET} sel -t -v "/package/@version" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) + package_variant=$(${XMLSTARLET} sel -t -v "/package/@variant" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml || :) ipvi=$(version_convert ${ipv}) ip_major=${ipv%_*} - echo "${module_name}: Installed package version ${ipv} (${ipvi})" - if [[ "${ip_major}" != "${major_version}" || "${package_arch}" != "x86_${host_bits}" ]] ; then - echo "${module_name}: The installed package is not for this version of Asterisk. Reinstalling." + echo "${full_name}: Installed package version ${ipv} (${ipvi})" + if [[ "${ip_major}" != "${major_version}" || "${package_arch}" != "x86_${host_bits}" || "${package_variant}" != "${variant}" ]] ; then + echo "${full_name}: The installed package is not for this version of Asterisk. Reinstalling." need_install=1 elif [[ ${rpvi} > ${ipvi} ]] ; then - echo "${module_name}: A newer package is available" + echo "${full_name}: A newer package is available" need_install=1 else sums=$(${XMLSTARLET} sel -t -m "//file" -v "@md5sum" -n ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) for sum in ${sums} ; do install_path=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@install_path" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ) + executable=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@executable" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ) f=${DESTDIR}$(eval echo ${install_path}) if [[ ! -f ${f} ]] ; then echo Not found: ${f} need_install=1 + break else + if [[ "$executable" = "yes" ]] ; then + # There are easier ways of doing this (objcopy --dump-section) but not in older bunutils + length_offset=$(objdump -h $f | sed -n -r -e "s/^\s+[0-9]+\s+.ast_manifest\s+([0-9a-fA-F]+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)\s+.*$/0x\1 0x\2/p") + tags=$($(eval 'printf "dd if=$f bs=1 count=%d skip=%d\n" $length_offset') 2>/dev/null) + if [[ -n "${tags}" && "${tags}" != "${module_name},${variant},${rpv}" ]] ; then + echo Tag mismatch: ${f} File: "${tags}" Manifest: "${module_name},${variant},${rpv}" + need_install=1 + break + fi + fi + cs=$(md5sum ${f} | cut -b1-32) if [[ "${cs}" != "${sum}" ]] ; then echo Checksum mismatch: ${f} need_install=1 + break fi fi done @@ -123,38 +167,38 @@ fi if [[ ${need_install} == 1 ]] ; then if [[ ( -n "${ipvi}" ) && ${ipvi} > ${rpvi} ]] ; then - echo "${module_name}: Installed package is newer than that available for download." + echo "${full_name}: Installed package is newer than that available for download." exit 0 fi else - echo "${module_name} is up to date." + echo "${full_name} is up to date." exit 0; fi need_download=1 -if [[ -f ${cache_dir}/${module_name}.manifest.xml ]] ; then - cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${module_name}.manifest.xml) +if [[ -f ${cache_dir}/${full_name}.manifest.xml ]] ; then + cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${full_name}.manifest.xml) cpvi=$(version_convert ${cpv}) - echo "${module_name}: Cached package version ${cpv} (${cpvi})" + echo "${full_name}: Cached package version ${cpv} (${cpvi})" if [[ ${cpvi} == ${rpvi} && ( -f ${cache_dir}/${tarball} ) ]] ; then - echo "${module_name}: Cached version is available." + echo "${full_name}: Cached version is available." need_download=0 fi fi if [[ ${need_download} = 1 ]] ; then - echo "${module_name}: Downloading ${remote_url}/${tarball}" + echo "${full_name}: Downloading ${remote_url}/${tarball}" ${WGET} -q -O ${cache_dir}/${tarball} ${remote_url}/${tarball} || { - echo "${module_name}: Unable to fetch ${remote_url}/${tarball}" + echo "${full_name}: Unable to fetch ${remote_url}/${tarball}" exit 1 } - cp ${tmpdir}/manifest.xml ${cache_dir}/${module_name}.manifest.xml + cp ${tmpdir}/${variant_manifest} ${cache_dir}/${full_name}.manifest.xml fi tar -xzf ${cache_dir}/${tarball} -C ${cache_dir} trap "rm -rf ${cache_dir}/${module_dir} ; rm -rf ${tmpdir}" EXIT -echo "${module_name}: Installing." +echo "${full_name}: Installing." if [[ $EUID == 0 ]] ; then install_params="--group=0 --owner=0" @@ -177,4 +221,4 @@ for name in ${names} ; do done ${INSTALL} -Dp ${install_params} --mode=0644 ${cache_dir}/${module_dir}/manifest.xml ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml -echo "${module_name}: Installed." +echo "${full_name}: Installed." diff --git a/res/res.xml b/res/res.xml index e9cb5f962cf..a340cc2fdc5 100644 --- a/res/res.xml +++ b/res/res.xml @@ -3,4 +3,11 @@ xmlstarlet bash no + + + + + + + From 40aa28131bc30b4516da2b20eb1a1e043920169c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 23 Jul 2016 14:56:43 -0600 Subject: [PATCH 0768/1578] format_ogg_opus: New format Add Ogg/Opus playback support. This uses libopusfile in order to be able to read .opus files and play them back. Writing/recording support is not present at this time. ASTERISK-26409 Change-Id: I8815d23345108d8ca7c0bd640f6a1ce6b4f56955 (cherry picked from commit daee8bbd5209b4158bc1785eede845a26e6cbeaa) --- build_tools/menuselect-deps.in | 1 + configure | 148 ++++++++++++++++++++ configure.ac | 8 ++ formats/format_ogg_opus.c | 229 +++++++++++++++++++++++++++++++ include/asterisk/autoconfig.h.in | 3 + makeopts.in | 3 + 6 files changed, 392 insertions(+) create mode 100644 formats/format_ogg_opus.c diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index 9b077680e6d..18d4a014c41 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -45,6 +45,7 @@ NEON29=@PBX_NEON29@ OGG=@PBX_OGG@ OPENH323=@PBX_OPENH323@ OPUS=@PBX_OPUS@ +OPUSFILE=@PBX_OPUSFILE@ OSPTK=@PBX_OSPTK@ OSS=@PBX_OSS@ PGSQL=@PBX_PGSQL@ diff --git a/configure b/configure index a5da739c045..dba401d8e51 100755 --- a/configure +++ b/configure @@ -994,6 +994,10 @@ PBX_OSPTK OSPTK_DIR OSPTK_INCLUDE OSPTK_LIB +PBX_OPUSFILE +OPUSFILE_DIR +OPUSFILE_INCLUDE +OPUSFILE_LIB PBX_OPUS OPUS_DIR OPUS_INCLUDE @@ -1398,6 +1402,7 @@ with_newt with_ogg with_openr2 with_opus +with_opusfile with_osptk with_oss with_postgres @@ -2156,6 +2161,7 @@ Optional Packages: --with-ogg=PATH use OGG files in PATH --with-openr2=PATH use MFR2 files in PATH --with-opus=PATH use Opus files in PATH + --with-opusfile=PATH use Opusfile files in PATH --with-osptk=PATH use OSP Toolkit files in PATH --with-oss=PATH use Open Sound System files in PATH --with-postgres=PATH use PostgreSQL files in PATH @@ -10842,6 +10848,38 @@ fi + OPUSFILE_DESCRIP="Opusfile" + OPUSFILE_OPTION="opusfile" + PBX_OPUSFILE=0 + +# Check whether --with-opusfile was given. +if test "${with_opusfile+set}" = set; then : + withval=$with_opusfile; + case ${withval} in + n|no) + USE_OPUSFILE=no + # -1 is a magic value used by menuselect to know that the package + # was disabled, other than 'not found' + PBX_OPUSFILE=-1 + ;; + y|ye|yes) + ac_mandatory_list="${ac_mandatory_list} OPUSFILE" + ;; + *) + OPUSFILE_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} OPUSFILE" + ;; + esac + +fi + + + + + + + + OSPTK_DESCRIP="OSP Toolkit" OSPTK_OPTION="osptk" PBX_OSPTK=0 @@ -29512,6 +29550,116 @@ _ACEOF fi +# opusfile.h includes so we need to make sure that +# either $OPUS_INCLUDE or /usr/include/opus is added to the search path. +__opus_include=${OPUS_INCLUDE} +if test -z "$__opus_include" -o x"$__opus_include" = x" " ; then + __opus_include=-I/usr/include/opus +fi + +if test "x${PBX_OPUSFILE}" != "x1" -a "${USE_OPUSFILE}" != "no"; then + pbxlibdir="" + # if --with-OPUSFILE=DIR has been specified, use it. + if test "x${OPUSFILE_DIR}" != "x"; then + if test -d ${OPUSFILE_DIR}/lib; then + pbxlibdir="-L${OPUSFILE_DIR}/lib" + else + pbxlibdir="-L${OPUSFILE_DIR}" + fi + fi + pbxfuncname="op_open_callbacks" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_OPUSFILE_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} $__opus_include" + as_ac_Lib=`$as_echo "ac_cv_lib_opusfile_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lopusfile" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lopusfile... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lopusfile ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_OPUSFILE_FOUND=yes +else + AST_OPUSFILE_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_OPUSFILE_FOUND}" = "yes"; then + OPUSFILE_LIB="${pbxlibdir} -lopusfile " + # if --with-OPUSFILE=DIR has been specified, use it. + if test "x${OPUSFILE_DIR}" != "x"; then + OPUSFILE_INCLUDE="-I${OPUSFILE_DIR}/include" + fi + OPUSFILE_INCLUDE="${OPUSFILE_INCLUDE} $__opus_include" + if test "xopus/opusfile.h" = "x" ; then # no header, assume found + OPUSFILE_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${OPUSFILE_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "opus/opusfile.h" "ac_cv_header_opus_opusfile_h" "$ac_includes_default" +if test "x$ac_cv_header_opus_opusfile_h" = xyes; then : + OPUSFILE_HEADER_FOUND=1 +else + OPUSFILE_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${OPUSFILE_HEADER_FOUND}" = "x0" ; then + OPUSFILE_LIB="" + OPUSFILE_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + OPUSFILE_LIB="" + fi + PBX_OPUSFILE=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_OPUSFILE 1 +_ACEOF + + fi + fi +fi + + if test "${USE_PWLIB}" != "no"; then if test -n "${PWLIB_DIR}"; then diff --git a/configure.ac b/configure.ac index 17b887266fe..107df97b130 100644 --- a/configure.ac +++ b/configure.ac @@ -468,6 +468,7 @@ AST_EXT_LIB_SETUP([NEWT], [newt], [newt]) AST_EXT_LIB_SETUP([OGG], [OGG], [ogg]) AST_EXT_LIB_SETUP([OPENR2], [MFR2], [openr2]) AST_EXT_LIB_SETUP([OPUS], [Opus], [opus]) +AST_EXT_LIB_SETUP([OPUSFILE], [Opusfile], [opusfile]) AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk]) AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss]) AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres]) @@ -2293,6 +2294,13 @@ AST_EXT_LIB_CHECK([SS7], [ss7], [ss7_set_isup_timer], [libss7.h]) AST_EXT_LIB_CHECK([OPENR2], [openr2], [openr2_chan_new], [openr2.h]) AST_EXT_LIB_CHECK([OPUS], [opus], [opus_encoder_create], [opus/opus.h]) +# opusfile.h includes so we need to make sure that +# either $OPUS_INCLUDE or /usr/include/opus is added to the search path. +__opus_include=${OPUS_INCLUDE} +if test -z "$__opus_include" -o x"$__opus_include" = x" " ; then + __opus_include=-I/usr/include/opus +fi +AST_EXT_LIB_CHECK([OPUSFILE], [opusfile], [op_open_callbacks], [opus/opusfile.h], [], [$__opus_include]) if test "${USE_PWLIB}" != "no"; then if test -n "${PWLIB_DIR}"; then diff --git a/formats/format_ogg_opus.c b/formats/format_ogg_opus.c new file mode 100644 index 00000000000..f6a4c6c67c3 --- /dev/null +++ b/formats/format_ogg_opus.c @@ -0,0 +1,229 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + opusfile + core + ***/ + +#include "asterisk.h" + +#include +#include +#include "asterisk/mod_format.h" +#include "asterisk/utils.h" +#include "asterisk/module.h" +#include "asterisk/format_cache.h" + +/* 120ms of 48KHz audio */ +#define SAMPLES_MAX 5760 +#define BUF_SIZE (2 * SAMPLES_MAX) + +struct ogg_opus_desc { + OggOpusFile *of; +}; + +static int fread_wrapper(void *_stream, unsigned char *_ptr, int _nbytes) +{ + FILE *stream = _stream; + size_t bytes_read; + + if (!stream || _nbytes < 0) { + return -1; + } + + bytes_read = fread(_ptr, 1, _nbytes, stream); + + return bytes_read > 0 || feof(stream) ? (int) bytes_read : OP_EREAD; +} + +static int fseek_wrapper(void *_stream, opus_int64 _offset, int _whence) +{ + FILE *stream = _stream; + + return fseeko(stream, (off_t) _offset, _whence); +} + +static opus_int64 ftell_wrapper(void *_stream) +{ + FILE *stream = _stream; + + return ftello(stream); +} + +static int ogg_opus_open(struct ast_filestream *s) +{ + struct ogg_opus_desc *desc = (struct ogg_opus_desc *) s->_private; + OpusFileCallbacks cb = { + .read = fread_wrapper, + .seek = fseek_wrapper, + .tell = ftell_wrapper, + .close = NULL, + }; + + memset(desc, 0, sizeof(*desc)); + desc->of = op_open_callbacks(s->f, &cb, NULL, 0, NULL); + if (!desc->of) { + return -1; + } + + return 0; +} + +static int ogg_opus_rewrite(struct ast_filestream *s, const char *comment) +{ + /* XXX Unimplemented. We currently only can read from OGG/Opus streams */ + ast_log(LOG_ERROR, "Cannot write OGG/Opus streams. Sorry :(\n"); + return -1; +} + +static int ogg_opus_write(struct ast_filestream *fs, struct ast_frame *f) +{ + /* XXX Unimplemented. We currently only can read from OGG/Opus streams */ + ast_log(LOG_ERROR, "Cannot write OGG/Opus streams. Sorry :(\n"); + return -1; +} + +static int ogg_opus_seek(struct ast_filestream *fs, off_t sample_offset, int whence) +{ + int seek_result = -1; + off_t relative_pcm_pos; + struct ogg_opus_desc *desc = fs->_private; + + switch (whence) { + case SEEK_SET: + seek_result = op_pcm_seek(desc->of, sample_offset); + break; + case SEEK_CUR: + if ((relative_pcm_pos = op_pcm_tell(desc->of)) < 0) { + seek_result = -1; + break; + } + seek_result = op_pcm_seek(desc->of, relative_pcm_pos + sample_offset); + break; + case SEEK_END: + if ((relative_pcm_pos = op_pcm_total(desc->of, -1)) < 0) { + seek_result = -1; + break; + } + seek_result = op_pcm_seek(desc->of, relative_pcm_pos - sample_offset); + break; + default: + ast_log(LOG_WARNING, "Unknown *whence* to seek on OGG/Opus streams!\n"); + break; + } + + /* normalize error value to -1,0 */ + return (seek_result == 0) ? 0 : -1; +} + +static int ogg_opus_trunc(struct ast_filestream *fs) +{ + /* XXX Unimplemented. This is only used when recording, and we don't support that right now. */ + ast_log(LOG_ERROR, "Truncation is not supported on OGG/Opus streams!\n"); + return -1; +} + +static off_t ogg_opus_tell(struct ast_filestream *fs) +{ + struct ogg_opus_desc *desc = fs->_private; + off_t pos; + + pos = (off_t) op_pcm_tell(desc->of); + if (pos < 0) { + return -1; + } + return pos; +} + +static struct ast_frame *ogg_opus_read(struct ast_filestream *fs, int *whennext) +{ + struct ogg_opus_desc *desc = fs->_private; + int hole = 1; + int samples_read; + opus_int16 *out_buf; + + AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); + + out_buf = (opus_int16 *) fs->fr.data.ptr; + + while (hole) { + samples_read = op_read( + desc->of, + out_buf, + SAMPLES_MAX, + NULL); + + if (samples_read != OP_HOLE) { + hole = 0; + } + } + + if (samples_read <= 0) { + return NULL; + } + + fs->fr.datalen = samples_read * 2; + fs->fr.samples = samples_read; + *whennext = fs->fr.samples; + + return &fs->fr; +} + +static void ogg_opus_close(struct ast_filestream *fs) +{ + struct ogg_opus_desc *desc = fs->_private; + + op_free(desc->of); +} + +static struct ast_format_def opus_f = { + .name = "ogg_opus", + .exts = "opus", + .open = ogg_opus_open, + .rewrite = ogg_opus_rewrite, + .write = ogg_opus_write, + .seek = ogg_opus_seek, + .trunc = ogg_opus_trunc, + .tell = ogg_opus_tell, + .read = ogg_opus_read, + .close = ogg_opus_close, + .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET, + .desc_size = sizeof(struct ogg_opus_desc), +}; + +static int load_module(void) +{ + opus_f.format = ast_format_slin48; + if (ast_format_def_register(&opus_f)) { + return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + return ast_format_def_unregister(opus_f.name); +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "OGG/Opus audio", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_APP_DEPEND +); diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index e16b6686153..d34a38ae904 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -559,6 +559,9 @@ /* Define to 1 if you have the Opus library. */ #undef HAVE_OPUS +/* Define to 1 if you have the Opusfile library. */ +#undef HAVE_OPUSFILE + /* Define this to indicate the ${OSPTK_DESCRIP} library */ #undef HAVE_OSPTK diff --git a/makeopts.in b/makeopts.in index b2b394b5f14..0b268b8aa8f 100644 --- a/makeopts.in +++ b/makeopts.in @@ -223,6 +223,9 @@ OGG_LIB=@OGG_LIB@ OPUS_INCLUDE=@OPUS_INCLUDE@ OPUS_LIB=@OPUS_LIB@ +OPUSFILE_INCLUDE=@OPUSFILE_INCLUDE@ +OPUSFILE_LIB=@OPUSFILE_LIB@ + OSPTK_INCLUDE=@OSPTK_INCLUDE@ OSPTK_LIB=@OSPTK_LIB@ From 5cc3c6679f2ad65b5baa73292d8997759cb2f15b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sat, 23 Jul 2016 13:50:37 -0600 Subject: [PATCH 0769/1578] codec_opus: Replace res_format_attr_opus with the one from codec_opus Preparation ASTERISK-26409 Change-Id: I9f20e7cce00c32464d9a180e81283d49d199d0a3 (cherry picked from commit 59f7662a93bf9c07204fb50e1020a0f5bfbbd5c9) --- include/asterisk/opus.h | 51 ++++-- res/res_format_attr_opus.c | 348 ++++++++++++++++++++----------------- 2 files changed, 224 insertions(+), 175 deletions(-) diff --git a/include/asterisk/opus.h b/include/asterisk/opus.h index 0fbcfa10e35..6d2cdcf8c24 100644 --- a/include/asterisk/opus.h +++ b/include/asterisk/opus.h @@ -18,24 +18,47 @@ /*! * \file - * \brief Opus Format Attributes (http://tools.ietf.org/html/draft-ietf-payload-rtp-opus) + * \brief Codec opus externals and format attributes * - * \author Lorenzo Miniero + * RFC - https://tools.ietf.org/rfc/rfc7587.txt */ #ifndef _AST_FORMAT_OPUS_H_ #define _AST_FORMAT_OPUS_H_ -/*! Opus format attribute key value pairs, all are accessible through ast_format_get_value()*/ -enum opus_attr_keys { - OPUS_ATTR_KEY_MAX_BITRATE, /*! value is an int (6000-510000 in spec). */ - OPUS_ATTR_KEY_MAX_PLAYRATE, /*! value is an int (8000-48000), maximum output rate the receiver can render. */ - OPUS_ATTR_KEY_MINPTIME, /*! value is an int (3-120 in spec, 10-60 in format.c), decoder's minimum length of time in milliseconds. */ - OPUS_ATTR_KEY_STEREO, /*! value is an int, 1 prefer receiving stereo, 0 prefer mono. */ - OPUS_ATTR_KEY_CBR, /*! value is an int, 1 use constant bitrate, 0 use variable bitrate. */ - OPUS_ATTR_KEY_FEC, /*! value is an int, 1 encode with FEC, 0 do not use FEC. */ - OPUS_ATTR_KEY_DTX, /*! value is an int, 1 dtx is enabled, 0 dtx not enabled. */ - OPUS_ATTR_KEY_SPROP_CAPTURE_RATE, /*! value is an int (8000-48000), likely input rate we're going to produce. */ - OPUS_ATTR_KEY_SPROP_STEREO, /*! value is an int, 1 likely to send stereo, 0 likely to send mono. */ -}; +/*! \brief Maximum sampling rate an endpoint is capable of receiving */ +#define CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE "maxplaybackrate" +/*! \brief An alias for maxplaybackrate (used in older versions) */ +#define CODEC_OPUS_ATTR_MAX_CODED_AUDIO_BANDWIDTH "maxcodedaudiobandwidth" +/*! \brief Maximum sampling rate an endpoint is capable of sending */ +#define CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE "sprop-maxcapturerate" +/*! \brief Maximum duration of packet (in milliseconds) */ +#define CODEC_OPUS_ATTR_MAX_PTIME "maxptime" +/*! \brief Duration of packet (in milliseconds) */ +#define CODEC_OPUS_ATTR_PTIME "ptime" +/*! \brief Maximum average received bit rate (in bits per second) */ +#define CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE "maxaveragebitrate" +/*! \brief Decode stereo (1) vs mono (0) */ +#define CODEC_OPUS_ATTR_STEREO "stereo" +/*! \brief Likeliness of sender producing stereo (1) vs mono (0) */ +#define CODEC_OPUS_ATTR_SPROP_STEREO "sprop-stereo" +/*! \brief Decoder prefers a constant (1) vs variable (0) bitrate */ +#define CODEC_OPUS_ATTR_CBR "cbr" +/*! \brief Use forward error correction (1) or not (0) */ +#define CODEC_OPUS_ATTR_FEC "useinbandfec" +/*! \brief Use discontinuous transmission (1) or not (0) */ +#define CODEC_OPUS_ATTR_DTX "usedtx" +/*! \brief Custom data object */ +#define CODEC_OPUS_ATTR_DATA "data" + +/*! \brief Default attribute values */ +#define CODEC_OPUS_DEFAULT_SAMPLE_RATE 48000 +#define CODEC_OPUS_DEFAULT_MAX_PLAYBACK_RATE 48000 +#define CODEC_OPUS_DEFAULT_MAX_PTIME 120 +#define CODEC_OPUS_DEFAULT_PTIME 20 +#define CODEC_OPUS_DEFAULT_BITRATE -1000 /* OPUS_AUTO */ +#define CODEC_OPUS_DEFAULT_CBR 0 +#define CODEC_OPUS_DEFAULT_FEC 0 +#define CODEC_OPUS_DEFAULT_DTX 0 +#define CODEC_OPUS_DEFAULT_STEREO 0 #endif /* _AST_FORMAT_OPUS_H */ diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index 4c09bef6756..dfdf9b6d6ac 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -33,9 +33,10 @@ ASTERISK_REGISTER_FILE() #include "asterisk/module.h" #include "asterisk/format.h" -#include "asterisk/logger.h" /* for ast_log, LOG_WARNING */ -#include "asterisk/strings.h" /* for ast_str_append */ -#include "asterisk/utils.h" /* for MIN, ast_malloc, ast_free */ +#include "asterisk/logger.h" +#include "asterisk/strings.h" +#include "asterisk/utils.h" +#include "asterisk/opus.h" /*! * \brief Opus attribute structure. @@ -43,32 +44,42 @@ ASTERISK_REGISTER_FILE() * \note http://tools.ietf.org/html/rfc7587#section-6 */ struct opus_attr { - unsigned int maxbitrate; - unsigned int maxplayrate; - unsigned int unused; /* was minptime, kept for binary compatibility */ - unsigned int stereo; - unsigned int cbr; - unsigned int fec; - unsigned int dtx; - unsigned int spropmaxcapturerate; - unsigned int spropstereo; + int maxbitrate; + int maxplayrate; + int ptime; + int stereo; + int cbr; + int fec; + int dtx; + int spropmaxcapturerate; + int spropstereo; + int maxptime; + /* Note data is expected to be an ao2_object type */ + void *data; }; static struct opus_attr default_opus_attr = { - .maxplayrate = 48000, - .spropmaxcapturerate = 48000, - .maxbitrate = 510000, - .stereo = 0, - .spropstereo = 0, - .cbr = 0, - .fec = 1, - .dtx = 0, + .maxbitrate = CODEC_OPUS_DEFAULT_BITRATE, + .maxplayrate = CODEC_OPUS_DEFAULT_SAMPLE_RATE, + .ptime = CODEC_OPUS_DEFAULT_PTIME, + .stereo = CODEC_OPUS_DEFAULT_STEREO, + .cbr = CODEC_OPUS_DEFAULT_CBR, + .fec = CODEC_OPUS_DEFAULT_FEC, + .dtx = CODEC_OPUS_DEFAULT_DTX, + .spropmaxcapturerate = CODEC_OPUS_DEFAULT_SAMPLE_RATE, + .spropstereo = CODEC_OPUS_DEFAULT_STEREO, + .maxptime = CODEC_OPUS_DEFAULT_MAX_PTIME }; static void opus_destroy(struct ast_format *format) { struct opus_attr *attr = ast_format_get_attribute_data(format); + if (!attr) { + return; + } + + ao2_cleanup(attr->data); ast_free(attr); } @@ -81,81 +92,65 @@ static int opus_clone(const struct ast_format *src, struct ast_format *dst) return -1; } - if (original) { - *attr = *original; - } else { - *attr = default_opus_attr; - } + *attr = original ? *original : default_opus_attr; + ao2_bump(attr->data); ast_format_set_attribute_data(dst, attr); return 0; } +static void sdp_fmtp_get(const char *attributes, const char *name, int *attr) +{ + const char *kvp = ""; + int val; + + if (attributes && !(kvp = strstr(attributes, name))) { + return; + } + + /* + * If the named attribute is not at the start of the given attributes, and + * the preceding character is not a space or semicolon then it's not the + * attribute we are looking for. It's an attribute with the name embedded + * within it (e.g. ptime in maxptime, stereo in sprop-stereo). + */ + if (kvp != attributes && *(kvp - 1) != ' ' && *(kvp - 1) != ';') { + /* Keep searching as it might still be in the attributes string */ + sdp_fmtp_get(strchr(kvp, ';'), name, attr); + /* + * Otherwise it's a match, so retrieve the value and set the attribute. + */ + } else if (sscanf(kvp, "%*[^=]=%30d", &val) == 1) { + *attr = val; + } +} + static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) { struct ast_format *cloned; struct opus_attr *attr; - const char *kvp; - unsigned int val; cloned = ast_format_clone(format); if (!cloned) { return NULL; } - attr = ast_format_get_attribute_data(cloned); - - if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) { - attr->maxplayrate = val; - } else { - attr->maxplayrate = 48000; - } - - if ((kvp = strstr(attributes, "sprop-maxcapturerate")) && sscanf(kvp, "sprop-maxcapturerate=%30u", &val) == 1) { - attr->spropmaxcapturerate = val; - } else { - attr->spropmaxcapturerate = 48000; - } - - if ((kvp = strstr(attributes, "maxaveragebitrate")) && sscanf(kvp, "maxaveragebitrate=%30u", &val) == 1) { - attr->maxbitrate = val; - } else { - attr->maxbitrate = 510000; - } - if (!strncmp(attributes, "stereo=1", 8)) { - attr->stereo = 1; - } else if (strstr(attributes, " stereo=1")) { - attr->stereo = 1; - } else if (strstr(attributes, ";stereo=1")) { - attr->stereo = 1; - } else { - attr->stereo = 0; - } - - if (strstr(attributes, "sprop-stereo=1")) { - attr->spropstereo = 1; - } else { - attr->spropstereo = 0; - } + attr = ast_format_get_attribute_data(cloned); - if (strstr(attributes, "cbr=1")) { - attr->cbr = 1; - } else { - attr->cbr = 0; - } - - if (strstr(attributes, "useinbandfec=1")) { - attr->fec = 1; - } else { - attr->fec = 0; - } - - if (strstr(attributes, "usedtx=1")) { - attr->dtx = 1; - } else { - attr->dtx = 0; - } + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE, &attr->maxplayrate); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_MAX_CODED_AUDIO_BANDWIDTH, + &attr->maxplayrate); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE, + &attr->spropmaxcapturerate); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_MAX_PTIME, &attr->maxptime); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_PTIME, &attr->ptime); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE, &attr->maxbitrate); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_STEREO, &attr->stereo); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_SPROP_STEREO, &attr->spropstereo); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_CBR, &attr->cbr); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_FEC, &attr->fec); + sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_DTX, &attr->dtx); return cloned; } @@ -163,7 +158,7 @@ static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, c static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { struct opus_attr *attr = ast_format_get_attribute_data(format); - int added = 0; + int size; if (!attr) { /* @@ -174,79 +169,52 @@ static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int attr = &default_opus_attr; } - if (48000 != attr->maxplayrate) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "maxplaybackrate=%u", attr->maxplayrate); + size = ast_str_append(str, 0, "a=fmtp:%u ", payload); + + if (CODEC_OPUS_DEFAULT_SAMPLE_RATE != attr->maxplayrate) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE, attr->maxplayrate); } - if (48000 != attr->spropmaxcapturerate) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "sprop-maxcapturerate=%u", attr->spropmaxcapturerate); + if (CODEC_OPUS_DEFAULT_SAMPLE_RATE != attr->spropmaxcapturerate) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE, attr->spropmaxcapturerate); } - if (510000 != attr->maxbitrate) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "maxaveragebitrate=%u", attr->maxbitrate); + if (CODEC_OPUS_DEFAULT_BITRATE != attr->maxbitrate || attr->maxbitrate > 0) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE, attr->maxbitrate); } - if (0 != attr->stereo) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "stereo=%u", attr->stereo); + if (CODEC_OPUS_DEFAULT_STEREO != attr->stereo) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_STEREO, attr->stereo); } - if (0 != attr->spropstereo) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "sprop-stereo=%u", attr->spropstereo); + if (CODEC_OPUS_DEFAULT_STEREO != attr->spropstereo) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_SPROP_STEREO, attr->spropstereo); } - if (0 != attr->cbr) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "cbr=%u", attr->cbr); + if (CODEC_OPUS_DEFAULT_CBR != attr->cbr) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_CBR, attr->cbr); } - if (0 != attr->fec) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "useinbandfec=%u", attr->fec); + if (CODEC_OPUS_DEFAULT_FEC!= attr->fec) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_FEC, attr->fec); } - if (0 != attr->dtx) { - if (added) { - ast_str_append(str, 0, ";"); - } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { - added = 1; - } - ast_str_append(str, 0, "usedtx=%u", attr->dtx); + if (CODEC_OPUS_DEFAULT_DTX != attr->dtx) { + ast_str_append(str, 0, "%s=%d;", + CODEC_OPUS_ATTR_DTX, attr->dtx); } - if (added) { + if (size == ast_str_strlen(*str)) { + ast_str_reset(*str); + } else { + ast_str_truncate(*str, -1); ast_str_append(str, 0, "\r\n"); } } @@ -285,49 +253,68 @@ static struct ast_format *opus_getjoint(const struct ast_format *format1, const * to receive stereo signals, it may be a waste of bandwidth. */ attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0; - attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); + if (attr1->maxbitrate < 0) { + attr_res->maxbitrate = attr2->maxbitrate; + } else if (attr2->maxbitrate < 0) { + attr_res->maxbitrate = attr1->maxbitrate; + } else { + attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); + } + attr_res->spropmaxcapturerate = MIN(attr1->spropmaxcapturerate, attr2->spropmaxcapturerate); attr_res->maxplayrate = MIN(attr1->maxplayrate, attr2->maxplayrate); return jointformat; } -static struct ast_format *opus_set(const struct ast_format *format, const char *name, const char *value) +static struct ast_format *opus_set(const struct ast_format *format, + const char *name, const char *value) { struct ast_format *cloned; struct opus_attr *attr; - unsigned int val; + int val; - if (sscanf(value, "%30u", &val) != 1) { - ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n", - value, name); + if (!(cloned = ast_format_clone(format))) { return NULL; } - cloned = ast_format_clone(format); - if (!cloned) { + attr = ast_format_get_attribute_data(cloned); + + if (!strcmp(name, CODEC_OPUS_ATTR_DATA)) { + ao2_cleanup(attr->data); + attr->data = ao2_bump((void*)value); + return cloned; + } + + if (sscanf(value, "%30d", &val) != 1) { + ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n", + value, name); + ao2_ref(cloned, -1); return NULL; } - attr = ast_format_get_attribute_data(cloned); - if (!strcasecmp(name, "max_bitrate")) { - attr->maxbitrate = val; - } else if (!strcasecmp(name, "max_playrate")) { + if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE)) { + attr->maxplayrate = val; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_CODED_AUDIO_BANDWIDTH)) { attr->maxplayrate = val; - } else if (!strcasecmp(name, "minptime")) { - attr->unused = val; - } else if (!strcasecmp(name, "stereo")) { + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE)) { + attr->spropmaxcapturerate = val; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PTIME)) { + attr->maxptime = val; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_PTIME)) { + attr->ptime = val; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE)) { + attr->maxbitrate = val; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_STEREO)) { attr->stereo = val; - } else if (!strcasecmp(name, "cbr")) { + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_STEREO)) { + attr->spropstereo = val; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_CBR)) { attr->cbr = val; - } else if (!strcasecmp(name, "fec")) { + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_FEC)) { attr->fec = val; - } else if (!strcasecmp(name, "dtx")) { + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_DTX)) { attr->dtx = val; - } else if (!strcasecmp(name, "sprop_capture_rate")) { - attr->spropmaxcapturerate = val; - } else if (!strcasecmp(name, "sprop_stereo")) { - attr->spropstereo = val; } else { ast_log(LOG_WARNING, "unknown attribute type %s\n", name); } @@ -335,6 +322,44 @@ static struct ast_format *opus_set(const struct ast_format *format, const char * return cloned; } +static const void *opus_get(const struct ast_format *format, const char *name) +{ + struct opus_attr *attr = ast_format_get_attribute_data(format); + int *val = NULL; + + if (!attr) { + return NULL; + } + + if (!strcasecmp(name, CODEC_OPUS_ATTR_DATA)) { + return ao2_bump(attr->data); + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE)) { + val = &attr->maxplayrate; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE)) { + val = &attr->spropmaxcapturerate; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PTIME)) { + val = &attr->maxptime; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_PTIME)) { + val = &attr->ptime; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE)) { + val = &attr->maxbitrate; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_STEREO)) { + val = &attr->stereo; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_STEREO)) { + val = &attr->spropstereo; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_CBR)) { + val = &attr->cbr; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_FEC)) { + val = &attr->fec; + } else if (!strcasecmp(name, CODEC_OPUS_ATTR_DTX)) { + val = &attr->dtx; + } else { + ast_log(LOG_WARNING, "unknown attribute type %s\n", name); + } + + return val; +} + static struct ast_format_interface opus_interface = { .format_destroy = opus_destroy, .format_clone = opus_clone, @@ -342,11 +367,12 @@ static struct ast_format_interface opus_interface = { .format_attribute_set = opus_set, .format_parse_sdp_fmtp = opus_parse_sdp_fmtp, .format_generate_sdp_fmtp = opus_generate_sdp_fmtp, + .format_attribute_get = opus_get }; static int load_module(void) { - if (ast_format_interface_register("opus", &opus_interface)) { + if (__ast_format_interface_register("opus", &opus_interface, ast_module_info->self)) { return AST_MODULE_LOAD_DECLINE; } @@ -358,9 +384,9 @@ static int unload_module(void) return 0; } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module", +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .load_pri = AST_MODPRI_REALTIME_DRIVER /* Needs to load before codec_opus */ ); From c7ef1e0af350a76da57f90e5d87db7b5b0cdc565 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 22 Sep 2016 08:49:50 -0600 Subject: [PATCH 0770/1578] codec_opus: Add download ability to menuselect Updated codecs/codecs.xml to add codec_opus to the external download list. ASTERISK-26409 Change-Id: Ia07b36539f30e852125fb2b94147dc9774df31a4 (cherry picked from commit 2cdab0e36eec4997ca3bd85aa09efc477038e31c) (cherry picked from commit e9684f3acd0e8def0df582c1505dd39dd3fd1610) --- codecs/codecs.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/codecs/codecs.xml b/codecs/codecs.xml index ac3c6e6389c..0b4e2a4740e 100644 --- a/codecs/codecs.xml +++ b/codecs/codecs.xml @@ -1,3 +1,10 @@ + + external + xmlstarlet + bash + res_format_attr_opus + no + external xmlstarlet From 2d2a8944bed593e3cd2a66fe1b25288a62437423 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 27 Sep 2016 16:35:38 -0400 Subject: [PATCH 0771/1578] logger: Output early verbose messages to console. Verbose messages should be printed to the console if the sublevel is less than option_verbose. This fix ensures the welcome message with copyright and license are printed at daemon and interactive rasterisk startup. ASTERISK-26410 #close Change-Id: Ia44235e30ec328aba92ea2c8a837b094e65c9a03 --- main/logger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/logger.c b/main/logger.c index 0c839ffeea1..d4cd25122e4 100644 --- a/main/logger.c +++ b/main/logger.c @@ -1572,7 +1572,7 @@ static void logger_print_normal(struct logmsg *logmsg) break; } } - } else if (logmsg->level != __LOG_VERBOSE) { + } else if (logmsg->level != __LOG_VERBOSE || option_verbose >= logmsg->sublevel) { fputs(logmsg->message, stdout); } From a77ebb20176b194988b6c2f3a152f165bab60cf2 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 27 Sep 2016 15:10:37 -0600 Subject: [PATCH 0772/1578] download_externals: Fix issue with re-install Needed to ignore an xmlstarlet return code for optional element. Change-Id: I6a96f709b4b38c9a3f3dda4e8b07903787e16873 Reported-by: Dan Jenkins --- build_tools/download_externals | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_tools/download_externals b/build_tools/download_externals index 9b2b841821f..2bc357c2989 100755 --- a/build_tools/download_externals +++ b/build_tools/download_externals @@ -134,7 +134,7 @@ if [[ -f ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ]] ; then sums=$(${XMLSTARLET} sel -t -m "//file" -v "@md5sum" -n ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) for sum in ${sums} ; do install_path=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@install_path" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ) - executable=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@executable" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ) + executable=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@executable" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml || : ) f=${DESTDIR}$(eval echo ${install_path}) if [[ ! -f ${f} ]] ; then echo Not found: ${f} From 8c5c95ad893af5d299da2695a0770cac98739e33 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 19 Sep 2016 05:46:27 -0400 Subject: [PATCH 0773/1578] core: Remove ABI effects of LOW_MEMORY. This allows asterisk to compiled with LOW_MEMORY to load modules built without LOW_MEMORY. ASTERISK-26398 #close Change-Id: I24b78ac9493ab933b11087a8b6794f3c96d4872d --- CHANGES | 7 ++++++ UPGRADE.txt | 4 ++++ build_tools/make_buildopts_h | 1 + include/asterisk.h | 10 -------- include/asterisk/inline_api.h | 6 ++--- include/asterisk/lock.h | 32 -------------------------- include/asterisk/utils.h | 11 ++++----- main/asterisk.c | 26 +++++++++++++++++++++ main/utils.c | 43 +++++++++++++++++++++++++++++++---- utils/ael_main.c | 6 ----- utils/astman.c | 2 -- utils/check_expr.c | 4 ---- utils/conf2ael.c | 4 ---- 13 files changed, 85 insertions(+), 71 deletions(-) diff --git a/CHANGES b/CHANGES index da732a7ebbe..be279879d04 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,13 @@ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ +Build System +------------------ + * LOW_MEMORY no longer has an effect on Asterisk ABI. Symbols that were + previously suppressed by LOW_MEMORY are now replaced by stub functions. + Asterisk built with LOW_MEMORY can now successfully load binary modules + built without LOW_MEMORY and vice versa. + chan_sip ------------------ * If an offer is received with optional SRTP (a media stream with RTP/AVP but diff --git a/UPGRADE.txt b/UPGRADE.txt index ad03edf8485..7acc7a80aea 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -22,3 +22,7 @@ === UPGRADE-13.txt -- Upgrade info for 12 to 13 === UPGRADE-14.txt -- Upgrade info for 13 to 14 =========================================================== + +Build System: + - The LOW_MEMORY compile option no longer disables inline API. To disable + inline API you must use the DISABLE_INLINE option. diff --git a/build_tools/make_buildopts_h b/build_tools/make_buildopts_h index c96e5087640..900e984e21d 100755 --- a/build_tools/make_buildopts_h +++ b/build_tools/make_buildopts_h @@ -24,6 +24,7 @@ for x in ${TMP}; do -o "${x}" = "BETTER_BACKTRACES" \ -o "${x}" = "LOTS_OF_SPANS" \ -o "${x}" = "BUILD_NATIVE" \ + -o "${x}" = "LOW_MEMORY" \ -o "${x}" = "REF_DEBUG" \ -o "${x}" = "AO2_DEBUG" \ -o "${x}" = "REBUILD_PARSERS" \ diff --git a/include/asterisk.h b/include/asterisk.h index 93c7cfb28db..f5ed0916754 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -152,7 +152,6 @@ int ast_shutting_down(void); */ int ast_shutdown_final(void); -#if !defined(LOW_MEMORY) /*! * \brief Register the version of a source code file with the core. * \param file the source file name @@ -225,11 +224,7 @@ char *ast_complete_source_filename(const char *partial, int n); __ast_unregister_file(__FILE__); \ } #endif /* !MTX_PROFILE */ -#else /* LOW_MEMORY */ -#define ASTERISK_REGISTER_FILE() -#endif /* LOW_MEMORY */ -#if !defined(LOW_MEMORY) /*! * \brief support for event profiling * @@ -248,11 +243,6 @@ char *ast_complete_source_filename(const char *partial, int n); int ast_add_profile(const char *, uint64_t scale); int64_t ast_profile(int, int64_t); int64_t ast_mark(int, int start1_stop0); -#else /* LOW_MEMORY */ -#define ast_add_profile(a, b) 0 -#define ast_profile(a, b) do { } while (0) -#define ast_mark(a, b) do { } while (0) -#endif /* LOW_MEMORY */ /*! \brief * Definition of various structures that many asterisk files need, diff --git a/include/asterisk/inline_api.h b/include/asterisk/inline_api.h index 291a83828ad..5f7a43bdc90 100644 --- a/include/asterisk/inline_api.h +++ b/include/asterisk/inline_api.h @@ -33,7 +33,7 @@ copies of the function body are not built in different modules. However, since this doesn't work for clang, we go with 'static' anyway and hope for the best! - - when LOW_MEMORY is defined, inlining should be disabled + - when DISABLE_INLINE is defined, inlining should be disabled completely, even if the compiler is configured to support it The AST_INLINE_API macro allows this to happen automatically, when @@ -45,7 +45,7 @@ including the header file */ -#if !defined(LOW_MEMORY) && !defined(DISABLE_INLINE) +#if !defined(DISABLE_INLINE) #if !defined(AST_API_MODULE) #if defined(__clang__) || defined(__GNUC_STDC_INLINE__) @@ -57,7 +57,7 @@ #define AST_INLINE_API(hdr, body) hdr; hdr body #endif -#else /* defined(LOW_MEMORY) */ +#else /* defined(DISABLE_INLINE) */ #if !defined(AST_API_MODULE) #define AST_INLINE_API(hdr, body) hdr; diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index 652ca136eae..5b6817f6b52 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -240,7 +240,6 @@ enum ast_lock_type { * lock info struct. The lock is marked as pending as the thread is waiting * on the lock. ast_mark_lock_acquired() will mark it as held by this thread. */ -#if !defined(LOW_MEMORY) #ifdef HAVE_BKTR void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt); @@ -249,32 +248,15 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr); #endif /* HAVE_BKTR */ -#else - -#ifdef HAVE_BKTR -#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS,BUD) -#else -#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS) -#endif /* HAVE_BKTR */ -#endif /* !defined(LOW_MEMORY) */ - /*! * \brief Mark the last lock as acquired */ -#if !defined(LOW_MEMORY) void ast_mark_lock_acquired(void *lock_addr); -#else -#define ast_mark_lock_acquired(ignore) -#endif /*! * \brief Mark the last lock as failed (trylock) */ -#if !defined(LOW_MEMORY) void ast_mark_lock_failed(void *lock_addr); -#else -#define ast_mark_lock_failed(ignore) -#endif /*! * \brief remove lock info for the current thread @@ -282,7 +264,6 @@ void ast_mark_lock_failed(void *lock_addr); * this gets called by ast_mutex_unlock so that information on the lock can * be removed from the current thread's lock info struct. */ -#if !defined(LOW_MEMORY) #ifdef HAVE_BKTR void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt); #else @@ -290,15 +271,6 @@ void ast_remove_lock_info(void *lock_addr); #endif /* HAVE_BKTR */ void ast_suspend_lock_info(void *lock_addr); void ast_restore_lock_info(void *lock_addr); -#else -#ifdef HAVE_BKTR -#define ast_remove_lock_info(ignore,me) -#else -#define ast_remove_lock_info(ignore) -#endif /* HAVE_BKTR */ -#define ast_suspend_lock_info(ignore); -#define ast_restore_lock_info(ignore); -#endif /* !defined(LOW_MEMORY) */ /*! * \brief log info for the current lock with ast_log(). @@ -333,11 +305,7 @@ struct ast_str *ast_dump_locks(void); * this gets called during deadlock avoidance, so that the information may * be preserved as to what location originally acquired the lock. */ -#if !defined(LOW_MEMORY) int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size); -#else -#define ast_find_lock_info(a,b,c,d,e,f,g,h) -1 -#endif /*! * \brief Unlock a lock briefly diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 9789d34ee09..f9608f517be 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -423,13 +423,12 @@ int ast_careful_fwrite(FILE *f, int fd, const char *s, size_t len, int timeoutms * Thread management support (should be moved to lock.h or a different header) */ -#define AST_STACKSIZE (((sizeof(void *) * 8 * 8) - 16) * 1024) +#define AST_STACKSIZE (((sizeof(void *) * 8 * 8) - 16) * 1024) +#define AST_STACKSIZE_LOW (((sizeof(void *) * 8 * 2) - 16) * 1024) -#if defined(LOW_MEMORY) -#define AST_BACKGROUND_STACKSIZE (((sizeof(void *) * 8 * 2) - 16) * 1024) -#else -#define AST_BACKGROUND_STACKSIZE AST_STACKSIZE -#endif +int ast_background_stacksize(void); + +#define AST_BACKGROUND_STACKSIZE ast_background_stacksize() void ast_register_thread(char *name); void ast_unregister_thread(void *id); diff --git a/main/asterisk.c b/main/asterisk.c index 94481eecff3..7fc0912c48c 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -494,9 +494,11 @@ struct registered_file { }; static AST_RWLIST_HEAD_STATIC(registered_files, registered_file); +#endif /* ! LOW_MEMORY */ void __ast_register_file(const char *file) { +#if !defined(LOW_MEMORY) struct registered_file *reg; reg = ast_calloc(1, sizeof(*reg)); @@ -508,10 +510,12 @@ void __ast_register_file(const char *file) AST_RWLIST_WRLOCK(®istered_files); AST_RWLIST_INSERT_HEAD(®istered_files, reg, list); AST_RWLIST_UNLOCK(®istered_files); +#endif /* ! LOW_MEMORY */ } void __ast_unregister_file(const char *file) { +#if !defined(LOW_MEMORY) struct registered_file *find; AST_RWLIST_WRLOCK(®istered_files); @@ -527,10 +531,12 @@ void __ast_unregister_file(const char *file) if (find) { ast_free(find); } +#endif /* ! LOW_MEMORY */ } char *ast_complete_source_filename(const char *partial, int n) { +#if !defined(LOW_MEMORY) struct registered_file *find; size_t len = strlen(partial); int count = 0; @@ -545,8 +551,12 @@ char *ast_complete_source_filename(const char *partial, int n) } AST_RWLIST_UNLOCK(®istered_files); return res; +#else /* if defined(LOW_MEMORY) */ + return NULL; +#endif } +#if !defined(LOW_MEMORY) struct thread_list_t { AST_RWLIST_ENTRY(thread_list_t) list; char *name; @@ -872,12 +882,14 @@ struct profile_data { }; static struct profile_data *prof_data; +#endif /* ! LOW_MEMORY */ /*! \brief allocates a counter with a given name and scale. * \return Returns the identifier of the counter. */ int ast_add_profile(const char *name, uint64_t scale) { +#if !defined(LOW_MEMORY) int l = sizeof(struct profile_data); int n = 10; /* default entries */ @@ -904,10 +916,14 @@ int ast_add_profile(const char *name, uint64_t scale) prof_data->e[n].mark = 0; prof_data->e[n].scale = scale; return n; +#else /* if defined(LOW_MEMORY) */ + return 0; +#endif } int64_t ast_profile(int i, int64_t delta) { +#if !defined(LOW_MEMORY) if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */ return 0; if (prof_data->e[i].scale > 1) @@ -915,8 +931,12 @@ int64_t ast_profile(int i, int64_t delta) prof_data->e[i].value += delta; prof_data->e[i].events++; return prof_data->e[i].value; +#else /* if defined(LOW_MEMORY) */ + return 0; +#endif } +#if !defined(LOW_MEMORY) /* The RDTSC instruction was introduced on the Pentium processor and is not * implemented on certain clones, like the Cyrix 586. Hence, the previous * expectation of __i386__ was in error. */ @@ -940,9 +960,11 @@ rdtsc(void) return 0; } #endif +#endif /* ! LOW_MEMORY */ int64_t ast_mark(int i, int startstop) { +#if !defined(LOW_MEMORY) if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */ return 0; if (startstop == 1) @@ -955,8 +977,12 @@ int64_t ast_mark(int i, int startstop) prof_data->e[i].events++; } return prof_data->e[i].mark; +#else /* if defined(LOW_MEMORY) */ + return 0; +#endif } +#if !defined(LOW_MEMORY) #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \ max = prof_data->entries;\ if (a->argc > 3) { /* specific entries */ \ diff --git a/main/utils.c b/main/utils.c index 73b1c8703aa..c8ede91d9a1 100644 --- a/main/utils.c +++ b/main/utils.c @@ -614,10 +614,9 @@ static int dev_urandom_fd = -1; #undef pthread_create /* For ast_pthread_create function only */ #endif /* !__linux__ */ -#if !defined(LOW_MEMORY) - #ifdef DEBUG_THREADS +#if !defined(LOW_MEMORY) /*! \brief A reasonable maximum number of locks a thread would be holding ... */ #define AST_MAX_LOCKS 64 @@ -720,6 +719,8 @@ static void lock_info_destroy(void *data) * \brief The thread storage key for per-thread lock info */ AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy); +#endif /* ! LOW_MEMORY */ + #ifdef HAVE_BKTR void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) @@ -728,6 +729,7 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr) #endif { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; int i; @@ -778,10 +780,12 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename, lock_info->num_locks++; pthread_mutex_unlock(&lock_info->lock); +#endif /* ! LOW_MEMORY */ } void ast_mark_lock_acquired(void *lock_addr) { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) @@ -792,10 +796,12 @@ void ast_mark_lock_acquired(void *lock_addr) lock_info->locks[lock_info->num_locks - 1].pending = 0; } pthread_mutex_unlock(&lock_info->lock); +#endif /* ! LOW_MEMORY */ } void ast_mark_lock_failed(void *lock_addr) { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) @@ -807,10 +813,12 @@ void ast_mark_lock_failed(void *lock_addr) lock_info->locks[lock_info->num_locks - 1].times_locked--; } pthread_mutex_unlock(&lock_info->lock); +#endif /* ! LOW_MEMORY */ } int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size) { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; int i = 0; @@ -838,10 +846,14 @@ int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, in pthread_mutex_unlock(&lock_info->lock); return 0; +#else /* if defined(LOW_MEMORY) */ + return -1; +#endif } void ast_suspend_lock_info(void *lock_addr) { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; int i = 0; @@ -865,10 +877,12 @@ void ast_suspend_lock_info(void *lock_addr) lock_info->locks[i].suspended = 1; pthread_mutex_unlock(&lock_info->lock); +#endif /* ! LOW_MEMORY */ } void ast_restore_lock_info(void *lock_addr) { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; int i = 0; @@ -891,6 +905,7 @@ void ast_restore_lock_info(void *lock_addr) lock_info->locks[i].suspended = 0; pthread_mutex_unlock(&lock_info->lock); +#endif /* ! LOW_MEMORY */ } @@ -900,6 +915,7 @@ void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt) void ast_remove_lock_info(void *lock_addr) #endif { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; int i = 0; @@ -937,8 +953,10 @@ void ast_remove_lock_info(void *lock_addr) lock_info->num_locks--; pthread_mutex_unlock(&lock_info->lock); +#endif /* ! LOW_MEMORY */ } +#if !defined(LOW_MEMORY) static const char *locktype2str(enum ast_lock_type type) { switch (type) { @@ -1017,7 +1035,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info * } ast_reentrancy_unlock(lt); } - +#endif /* ! LOW_MEMORY */ /*! This function can help you find highly temporal locks; locks that happen for a short time, but at unexpected times, usually at times that create a deadlock, @@ -1040,6 +1058,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info * */ void ast_log_show_lock(void *this_lock_addr) { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; struct ast_str *str; @@ -1066,11 +1085,13 @@ void ast_log_show_lock(void *this_lock_addr) } pthread_mutex_unlock(&lock_infos_lock.mutex); ast_free(str); +#endif /* ! LOW_MEMORY */ } struct ast_str *ast_dump_locks(void) { +#if !defined(LOW_MEMORY) struct thr_lock_info *lock_info; struct ast_str *str; @@ -1137,8 +1158,12 @@ struct ast_str *ast_dump_locks(void) "\n"); return str; +#else /* if defined(LOW_MEMORY) */ + return NULL; +#endif } +#if !defined(LOW_MEMORY) static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ast_str *str; @@ -1172,9 +1197,10 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_ static struct ast_cli_entry utils_cli[] = { AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"), }; - +#endif /* ! LOW_MEMORY */ #endif /* DEBUG_THREADS */ +#if !defined(LOW_MEMORY) /* * support for 'show threads'. The start routine is wrapped by * dummy_start(), so that ast_register_thread() and @@ -1236,6 +1262,15 @@ static void *dummy_start(void *data) #endif /* !LOW_MEMORY */ +int ast_background_stacksize(void) +{ +#if !defined(LOW_MEMORY) + return AST_STACKSIZE; +#else + return AST_STACKSIZE_LOW; +#endif +} + int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data, size_t stacksize, const char *file, const char *caller, int line, const char *start_fn) diff --git a/utils/ael_main.c b/utils/ael_main.c index d2c815b3bde..1801b12b8cc 100644 --- a/utils/ael_main.c +++ b/utils/ael_main.c @@ -32,10 +32,8 @@ ASTERISK_REGISTER_FILE() int option_debug = 0; int option_verbose = 0; -#if !defined(LOW_MEMORY) void __ast_register_file(const char *file) { } void __ast_unregister_file(const char *file) { } -#endif /*** MODULEINFO res_ael_share @@ -180,7 +178,6 @@ struct ast_custom_function *ast_custom_function_find(const char *name) return 0; /* in "standalone" mode, functions are just not avail */ } -#if !defined(LOW_MEMORY) int ast_add_profile(const char *x, uint64_t scale) { if (!no_comp) @@ -188,7 +185,6 @@ int ast_add_profile(const char *x, uint64_t scale) return 0; } -#endif int ast_loader_register(int (*updater)(void)) { @@ -606,7 +602,6 @@ unsigned int ast_hashtab_hash_contexts(const void *obj) } #ifdef DEBUG_THREADS -#if !defined(LOW_MEMORY) void ast_mark_lock_acquired(void *lock_addr) { } @@ -652,5 +647,4 @@ void ast_suspend_lock_info(void *lock_addr) void ast_restore_lock_info(void *lock_addr) { } -#endif /* !defined(LOW_MEMORY) */ #endif /* DEBUG_THREADS */ diff --git a/utils/astman.c b/utils/astman.c index 50e6a890116..a6803c8a58f 100644 --- a/utils/astman.c +++ b/utils/astman.c @@ -98,7 +98,6 @@ void __ast_unregister_file(const char *file) { } -#if !defined(LOW_MEMORY) int ast_add_profile(const char *, uint64_t scale); int ast_add_profile(const char *s, uint64_t scale) { @@ -115,7 +114,6 @@ int64_t ast_mark(int key, int start1_stop0) { return 0; } -#endif /* LOW_MEMORY */ /* end of dummy functions */ diff --git a/utils/check_expr.c b/utils/check_expr.c index 36ff132026b..abfb91dcfd8 100644 --- a/utils/check_expr.c +++ b/utils/check_expr.c @@ -56,7 +56,6 @@ void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, i #endif #ifdef DEBUG_THREADS -#if !defined(LOW_MEMORY) #ifdef HAVE_BKTR void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt); @@ -117,7 +116,6 @@ void ast_mark_lock_acquired(void *foo) { /* not a lot to do in a standalone w/o threading! */ } -#endif #endif /* DEBUG_THREADS */ @@ -161,9 +159,7 @@ void parse_file(const char *fname); void __ast_register_file(const char *file); void __ast_register_file(const char *file) { } -#if !defined(LOW_MEMORY) int ast_add_profile(const char *x, uint64_t scale) { return 0;} -#endif int ast_atomic_fetchadd_int_slow(volatile int *p, int v) { int ret; diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 3136fe37883..3ebc56e4ac4 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -88,9 +88,7 @@ void __ast_unregister_file(const char *file); void __ast_unregister_file(const char *file) { } -#if !defined(LOW_MEMORY) int ast_add_profile(const char *x, uint64_t scale) { return 0;} -#endif /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */ void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf,5,6))); @@ -708,7 +706,6 @@ unsigned int ast_hashtab_hash_contexts(const void *obj) } #ifdef DEBUG_THREADS -#if !defined(LOW_MEMORY) void ast_mark_lock_acquired(void *lock_addr) { } @@ -755,5 +752,4 @@ void ast_suspend_lock_info(void *lock_addr) void ast_restore_lock_info(void *lock_addr) { } -#endif /* !defined(LOW_MEMORY) */ #endif /* DEBUG_THREADS */ From d31ffb421cff8a88bcc5b5d962fcdd77c9924b82 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 29 Sep 2016 14:02:37 -0500 Subject: [PATCH 0774/1578] Remove "format_ogg_opus: New format" This reverts commit 40aa28131bc30b4516da2b20eb1a1e043920169c. ASTERISK-26426 #close Change-Id: I81e55c3c512f1dd6f49896f0c6b97a07d74fd8f5 --- build_tools/menuselect-deps.in | 1 - configure | 148 -------------------- configure.ac | 8 -- formats/format_ogg_opus.c | 229 ------------------------------- include/asterisk/autoconfig.h.in | 3 - makeopts.in | 3 - 6 files changed, 392 deletions(-) delete mode 100644 formats/format_ogg_opus.c diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index 18d4a014c41..9b077680e6d 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -45,7 +45,6 @@ NEON29=@PBX_NEON29@ OGG=@PBX_OGG@ OPENH323=@PBX_OPENH323@ OPUS=@PBX_OPUS@ -OPUSFILE=@PBX_OPUSFILE@ OSPTK=@PBX_OSPTK@ OSS=@PBX_OSS@ PGSQL=@PBX_PGSQL@ diff --git a/configure b/configure index dba401d8e51..a5da739c045 100755 --- a/configure +++ b/configure @@ -994,10 +994,6 @@ PBX_OSPTK OSPTK_DIR OSPTK_INCLUDE OSPTK_LIB -PBX_OPUSFILE -OPUSFILE_DIR -OPUSFILE_INCLUDE -OPUSFILE_LIB PBX_OPUS OPUS_DIR OPUS_INCLUDE @@ -1402,7 +1398,6 @@ with_newt with_ogg with_openr2 with_opus -with_opusfile with_osptk with_oss with_postgres @@ -2161,7 +2156,6 @@ Optional Packages: --with-ogg=PATH use OGG files in PATH --with-openr2=PATH use MFR2 files in PATH --with-opus=PATH use Opus files in PATH - --with-opusfile=PATH use Opusfile files in PATH --with-osptk=PATH use OSP Toolkit files in PATH --with-oss=PATH use Open Sound System files in PATH --with-postgres=PATH use PostgreSQL files in PATH @@ -10848,38 +10842,6 @@ fi - OPUSFILE_DESCRIP="Opusfile" - OPUSFILE_OPTION="opusfile" - PBX_OPUSFILE=0 - -# Check whether --with-opusfile was given. -if test "${with_opusfile+set}" = set; then : - withval=$with_opusfile; - case ${withval} in - n|no) - USE_OPUSFILE=no - # -1 is a magic value used by menuselect to know that the package - # was disabled, other than 'not found' - PBX_OPUSFILE=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} OPUSFILE" - ;; - *) - OPUSFILE_DIR="${withval}" - ac_mandatory_list="${ac_mandatory_list} OPUSFILE" - ;; - esac - -fi - - - - - - - - OSPTK_DESCRIP="OSP Toolkit" OSPTK_OPTION="osptk" PBX_OSPTK=0 @@ -29550,116 +29512,6 @@ _ACEOF fi -# opusfile.h includes so we need to make sure that -# either $OPUS_INCLUDE or /usr/include/opus is added to the search path. -__opus_include=${OPUS_INCLUDE} -if test -z "$__opus_include" -o x"$__opus_include" = x" " ; then - __opus_include=-I/usr/include/opus -fi - -if test "x${PBX_OPUSFILE}" != "x1" -a "${USE_OPUSFILE}" != "no"; then - pbxlibdir="" - # if --with-OPUSFILE=DIR has been specified, use it. - if test "x${OPUSFILE_DIR}" != "x"; then - if test -d ${OPUSFILE_DIR}/lib; then - pbxlibdir="-L${OPUSFILE_DIR}/lib" - else - pbxlibdir="-L${OPUSFILE_DIR}" - fi - fi - pbxfuncname="op_open_callbacks" - if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers - AST_OPUSFILE_FOUND=yes - else - ast_ext_lib_check_save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} $__opus_include" - as_ac_Lib=`$as_echo "ac_cv_lib_opusfile_${pbxfuncname}" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lopusfile" >&5 -$as_echo_n "checking for ${pbxfuncname} in -lopusfile... " >&6; } -if eval \${$as_ac_Lib+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lopusfile ${pbxlibdir} $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char ${pbxfuncname} (); -int -main () -{ -return ${pbxfuncname} (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$as_ac_Lib=yes" -else - eval "$as_ac_Lib=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -eval ac_res=\$$as_ac_Lib - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : - AST_OPUSFILE_FOUND=yes -else - AST_OPUSFILE_FOUND=no -fi - - CFLAGS="${ast_ext_lib_check_save_CFLAGS}" - fi - - # now check for the header. - if test "${AST_OPUSFILE_FOUND}" = "yes"; then - OPUSFILE_LIB="${pbxlibdir} -lopusfile " - # if --with-OPUSFILE=DIR has been specified, use it. - if test "x${OPUSFILE_DIR}" != "x"; then - OPUSFILE_INCLUDE="-I${OPUSFILE_DIR}/include" - fi - OPUSFILE_INCLUDE="${OPUSFILE_INCLUDE} $__opus_include" - if test "xopus/opusfile.h" = "x" ; then # no header, assume found - OPUSFILE_HEADER_FOUND="1" - else # check for the header - ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" - CPPFLAGS="${CPPFLAGS} ${OPUSFILE_INCLUDE}" - ac_fn_c_check_header_mongrel "$LINENO" "opus/opusfile.h" "ac_cv_header_opus_opusfile_h" "$ac_includes_default" -if test "x$ac_cv_header_opus_opusfile_h" = xyes; then : - OPUSFILE_HEADER_FOUND=1 -else - OPUSFILE_HEADER_FOUND=0 -fi - - - CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" - fi - if test "x${OPUSFILE_HEADER_FOUND}" = "x0" ; then - OPUSFILE_LIB="" - OPUSFILE_INCLUDE="" - else - if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library - OPUSFILE_LIB="" - fi - PBX_OPUSFILE=1 - cat >>confdefs.h <<_ACEOF -#define HAVE_OPUSFILE 1 -_ACEOF - - fi - fi -fi - - if test "${USE_PWLIB}" != "no"; then if test -n "${PWLIB_DIR}"; then diff --git a/configure.ac b/configure.ac index 107df97b130..17b887266fe 100644 --- a/configure.ac +++ b/configure.ac @@ -468,7 +468,6 @@ AST_EXT_LIB_SETUP([NEWT], [newt], [newt]) AST_EXT_LIB_SETUP([OGG], [OGG], [ogg]) AST_EXT_LIB_SETUP([OPENR2], [MFR2], [openr2]) AST_EXT_LIB_SETUP([OPUS], [Opus], [opus]) -AST_EXT_LIB_SETUP([OPUSFILE], [Opusfile], [opusfile]) AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk]) AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss]) AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres]) @@ -2294,13 +2293,6 @@ AST_EXT_LIB_CHECK([SS7], [ss7], [ss7_set_isup_timer], [libss7.h]) AST_EXT_LIB_CHECK([OPENR2], [openr2], [openr2_chan_new], [openr2.h]) AST_EXT_LIB_CHECK([OPUS], [opus], [opus_encoder_create], [opus/opus.h]) -# opusfile.h includes so we need to make sure that -# either $OPUS_INCLUDE or /usr/include/opus is added to the search path. -__opus_include=${OPUS_INCLUDE} -if test -z "$__opus_include" -o x"$__opus_include" = x" " ; then - __opus_include=-I/usr/include/opus -fi -AST_EXT_LIB_CHECK([OPUSFILE], [opusfile], [op_open_callbacks], [opus/opusfile.h], [], [$__opus_include]) if test "${USE_PWLIB}" != "no"; then if test -n "${PWLIB_DIR}"; then diff --git a/formats/format_ogg_opus.c b/formats/format_ogg_opus.c deleted file mode 100644 index f6a4c6c67c3..00000000000 --- a/formats/format_ogg_opus.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2016, Digium, Inc. - * - * Mark Michelson - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*** MODULEINFO - opusfile - core - ***/ - -#include "asterisk.h" - -#include -#include -#include "asterisk/mod_format.h" -#include "asterisk/utils.h" -#include "asterisk/module.h" -#include "asterisk/format_cache.h" - -/* 120ms of 48KHz audio */ -#define SAMPLES_MAX 5760 -#define BUF_SIZE (2 * SAMPLES_MAX) - -struct ogg_opus_desc { - OggOpusFile *of; -}; - -static int fread_wrapper(void *_stream, unsigned char *_ptr, int _nbytes) -{ - FILE *stream = _stream; - size_t bytes_read; - - if (!stream || _nbytes < 0) { - return -1; - } - - bytes_read = fread(_ptr, 1, _nbytes, stream); - - return bytes_read > 0 || feof(stream) ? (int) bytes_read : OP_EREAD; -} - -static int fseek_wrapper(void *_stream, opus_int64 _offset, int _whence) -{ - FILE *stream = _stream; - - return fseeko(stream, (off_t) _offset, _whence); -} - -static opus_int64 ftell_wrapper(void *_stream) -{ - FILE *stream = _stream; - - return ftello(stream); -} - -static int ogg_opus_open(struct ast_filestream *s) -{ - struct ogg_opus_desc *desc = (struct ogg_opus_desc *) s->_private; - OpusFileCallbacks cb = { - .read = fread_wrapper, - .seek = fseek_wrapper, - .tell = ftell_wrapper, - .close = NULL, - }; - - memset(desc, 0, sizeof(*desc)); - desc->of = op_open_callbacks(s->f, &cb, NULL, 0, NULL); - if (!desc->of) { - return -1; - } - - return 0; -} - -static int ogg_opus_rewrite(struct ast_filestream *s, const char *comment) -{ - /* XXX Unimplemented. We currently only can read from OGG/Opus streams */ - ast_log(LOG_ERROR, "Cannot write OGG/Opus streams. Sorry :(\n"); - return -1; -} - -static int ogg_opus_write(struct ast_filestream *fs, struct ast_frame *f) -{ - /* XXX Unimplemented. We currently only can read from OGG/Opus streams */ - ast_log(LOG_ERROR, "Cannot write OGG/Opus streams. Sorry :(\n"); - return -1; -} - -static int ogg_opus_seek(struct ast_filestream *fs, off_t sample_offset, int whence) -{ - int seek_result = -1; - off_t relative_pcm_pos; - struct ogg_opus_desc *desc = fs->_private; - - switch (whence) { - case SEEK_SET: - seek_result = op_pcm_seek(desc->of, sample_offset); - break; - case SEEK_CUR: - if ((relative_pcm_pos = op_pcm_tell(desc->of)) < 0) { - seek_result = -1; - break; - } - seek_result = op_pcm_seek(desc->of, relative_pcm_pos + sample_offset); - break; - case SEEK_END: - if ((relative_pcm_pos = op_pcm_total(desc->of, -1)) < 0) { - seek_result = -1; - break; - } - seek_result = op_pcm_seek(desc->of, relative_pcm_pos - sample_offset); - break; - default: - ast_log(LOG_WARNING, "Unknown *whence* to seek on OGG/Opus streams!\n"); - break; - } - - /* normalize error value to -1,0 */ - return (seek_result == 0) ? 0 : -1; -} - -static int ogg_opus_trunc(struct ast_filestream *fs) -{ - /* XXX Unimplemented. This is only used when recording, and we don't support that right now. */ - ast_log(LOG_ERROR, "Truncation is not supported on OGG/Opus streams!\n"); - return -1; -} - -static off_t ogg_opus_tell(struct ast_filestream *fs) -{ - struct ogg_opus_desc *desc = fs->_private; - off_t pos; - - pos = (off_t) op_pcm_tell(desc->of); - if (pos < 0) { - return -1; - } - return pos; -} - -static struct ast_frame *ogg_opus_read(struct ast_filestream *fs, int *whennext) -{ - struct ogg_opus_desc *desc = fs->_private; - int hole = 1; - int samples_read; - opus_int16 *out_buf; - - AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); - - out_buf = (opus_int16 *) fs->fr.data.ptr; - - while (hole) { - samples_read = op_read( - desc->of, - out_buf, - SAMPLES_MAX, - NULL); - - if (samples_read != OP_HOLE) { - hole = 0; - } - } - - if (samples_read <= 0) { - return NULL; - } - - fs->fr.datalen = samples_read * 2; - fs->fr.samples = samples_read; - *whennext = fs->fr.samples; - - return &fs->fr; -} - -static void ogg_opus_close(struct ast_filestream *fs) -{ - struct ogg_opus_desc *desc = fs->_private; - - op_free(desc->of); -} - -static struct ast_format_def opus_f = { - .name = "ogg_opus", - .exts = "opus", - .open = ogg_opus_open, - .rewrite = ogg_opus_rewrite, - .write = ogg_opus_write, - .seek = ogg_opus_seek, - .trunc = ogg_opus_trunc, - .tell = ogg_opus_tell, - .read = ogg_opus_read, - .close = ogg_opus_close, - .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET, - .desc_size = sizeof(struct ogg_opus_desc), -}; - -static int load_module(void) -{ - opus_f.format = ast_format_slin48; - if (ast_format_def_register(&opus_f)) { - return AST_MODULE_LOAD_FAILURE; - } - return AST_MODULE_LOAD_SUCCESS; -} - -static int unload_module(void) -{ - return ast_format_def_unregister(opus_f.name); -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "OGG/Opus audio", - .support_level = AST_MODULE_SUPPORT_CORE, - .load = load_module, - .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND -); diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index d34a38ae904..e16b6686153 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -559,9 +559,6 @@ /* Define to 1 if you have the Opus library. */ #undef HAVE_OPUS -/* Define to 1 if you have the Opusfile library. */ -#undef HAVE_OPUSFILE - /* Define this to indicate the ${OSPTK_DESCRIP} library */ #undef HAVE_OSPTK diff --git a/makeopts.in b/makeopts.in index 0b268b8aa8f..b2b394b5f14 100644 --- a/makeopts.in +++ b/makeopts.in @@ -223,9 +223,6 @@ OGG_LIB=@OGG_LIB@ OPUS_INCLUDE=@OPUS_INCLUDE@ OPUS_LIB=@OPUS_LIB@ -OPUSFILE_INCLUDE=@OPUSFILE_INCLUDE@ -OPUSFILE_LIB=@OPUSFILE_LIB@ - OSPTK_INCLUDE=@OSPTK_INCLUDE@ OSPTK_LIB=@OSPTK_LIB@ From 806d08b6751e450e10e18ca799b5bd8b55c9448a Mon Sep 17 00:00:00 2001 From: Etienne Lessard Date: Fri, 9 Sep 2016 13:38:39 -0400 Subject: [PATCH 0775/1578] app_queue: Update dynamic members ringinuse on reload. Previously, when reloading the members of a queue, the members added statically (i.e. defined in queues.conf) would see their "ringinuse" value updated but not the members added dynamically. This change makes dynamic members ringuse value to be updated on reload. Note that it's impossible to add a dynamic member with a specific ringinuse value. For both static and dynamic members, the ringinuse value can always be changed later on with command like "queue set ringinuse" or with the AMI action "QueueMemberRingInUse". So it's possible this commit could break a user workflow if he was changing the ringinuse value of dynamic members via such commands and was also relying on the fact that a queue reload would not update the dynamic members ringinuse value. ASTERISK-26330 Change-Id: I3745cc9a06ba7e02c399636f1ee9e58c04081f3f --- UPGRADE.txt | 6 ++++++ apps/app_queue.c | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/UPGRADE.txt b/UPGRADE.txt index 7acc7a80aea..5f6cc3ed305 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -26,3 +26,9 @@ Build System: - The LOW_MEMORY compile option no longer disables inline API. To disable inline API you must use the DISABLE_INLINE option. + +Queue: + - When reloading the members of a queue, the members added dynamically (i.e. + added via the CLI command "queue add" or the AMI action "QueueAdd") now have + their ringinuse value updated to the value of the queue. Previously, the + ringinuse value for dynamic members was not updated on reload. diff --git a/apps/app_queue.c b/apps/app_queue.c index 873ab0ce6b9..a023b88ed13 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -7154,7 +7154,6 @@ static int add_to_queue(const char *queuename, const char *interface, const char ao2_lock(q); if ((old_member = interface_exists(q, interface)) == NULL) { if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse))) { - new_member->ringinuse = q->ringinuse; new_member->dynamic = 1; if (reason_paused) { ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused)); @@ -9041,6 +9040,7 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, { int new; struct call_queue *q = NULL; + struct member *member; /*We're defining a queue*/ struct call_queue tmpq = { .name = queuename, @@ -9050,6 +9050,8 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); int prev_weight = 0; struct ast_variable *var; + struct ao2_iterator mem_iter; + if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) { if (queue_reload) { /* Make one then */ @@ -9118,6 +9120,20 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, } } + /* Update ringinuse for dynamic members */ + if (member_reload) { + ao2_lock(q->members); + mem_iter = ao2_iterator_init(q->members, AO2_ITERATOR_DONTLOCK); + while ((member = ao2_iterator_next(&mem_iter))) { + if (member->dynamic) { + member->ringinuse = q->ringinuse; + } + ao2_ref(member, -1); + } + ao2_iterator_destroy(&mem_iter); + ao2_unlock(q->members); + } + /* At this point, we've determined if the queue has a weight, so update use_weight * as appropriate */ From 79532bca7526e6652608d5a8f11aadf98003e946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 30 Sep 2016 18:29:37 -0300 Subject: [PATCH 0776/1578] Add text of cdr directory into README.md for ast-db-manage Change-Id: I68321c4bea50730c39fdb486e5f23aeadd1ad636 --- contrib/ast-db-manage/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/ast-db-manage/README.md b/contrib/ast-db-manage/README.md index 3444dd5cd69..7add3ee668c 100644 --- a/contrib/ast-db-manage/README.md +++ b/contrib/ast-db-manage/README.md @@ -9,6 +9,7 @@ This is implemented as a set of repositories that contain database schema migrations, using [Alembic](http://alembic.readthedocs.org). The existing repositories include: + * `cdr` - Table used for Asterisk to store CDR records * `config` - Tables used for Asterisk realtime configuration * `voicemail` - Tables used for `ODBC_STOARGE` of voicemail messages From 2a03575c30b96ab23e75822c3b256fa0cb591aaa Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 16 Sep 2016 19:54:07 -0400 Subject: [PATCH 0777/1578] astobj2: Add backtrace to log_bad_ao2. * Compile __ast_assert_failed unconditionally. * Use __ast_assert_failed to log messages from log_bad_ao2 * Remove calls to ast_assert(0) that happen after log_bad_ao2 was run. Change-Id: I48f1af44b2718ad74a421ff75cb6397b924a9751 --- include/asterisk/utils.h | 4 +++- main/astobj2.c | 20 +++++------------ main/astobj2_container.c | 46 +++++++++++++++++++++++----------------- main/astobj2_hash.c | 4 +++- main/astobj2_rbtree.c | 4 +++- main/utils.c | 6 ++---- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index f9608f517be..2378c69713e 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -848,8 +848,10 @@ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, #define DO_CRASH_NORETURN #endif +void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, + const char *file, int line, const char *function); + #ifdef AST_DEVMODE -void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function); #define ast_assert(a) _ast_assert(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) static void force_inline _ast_assert(int condition, const char *condition_str, const char *file, int line, const char *function) { diff --git a/main/astobj2.c b/main/astobj2.c index 604e6a1ae41..72bfcc8198a 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -178,22 +178,17 @@ int internal_is_ao2_object(void *user_data) void log_bad_ao2(void *user_data, const char *file, int line, const char *func) { struct astobj2 *p; + char bad_magic[100]; if (!user_data) { - ast_log(__LOG_ERROR, file, line, func, "user_data is NULL\n"); + __ast_assert_failed(0, "user_data is NULL", file, line, func); return; } p = INTERNAL_OBJ(user_data); - if (p->priv_data.magic) { - ast_log(__LOG_ERROR, file, line, func, - "bad magic number 0x%x for object %p\n", - p->priv_data.magic, user_data); - } else { - ast_log(__LOG_ERROR, file, line, func, - "bad magic number for object %p. Object is likely destroyed.\n", - user_data); - } + snprintf(bad_magic, sizeof(bad_magic), "bad magic number 0x%x for object %p", + p->priv_data.magic, user_data); + __ast_assert_failed(0, bad_magic, file, line, func); } int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var) @@ -205,7 +200,6 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co int res = 0; if (obj == NULL) { - ast_assert(0); return -1; } @@ -269,7 +263,6 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line, int current_value; if (obj == NULL) { - ast_assert(0); return -1; } @@ -323,7 +316,6 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, int res = 0; if (obj == NULL) { - ast_assert(0); return -1; } @@ -454,7 +446,6 @@ void *ao2_object_get_lockaddr(void *user_data) obj = INTERNAL_OBJ_CHECK(user_data); if (obj == NULL) { - ast_assert(0); return NULL; } @@ -486,7 +477,6 @@ int __ao2_ref(void *user_data, int delta, user_data, delta, ast_get_tid(), file, line, func, tag ?: ""); fflush(ref_log); } - ast_assert(0); return -1; } diff --git a/main/astobj2_container.c b/main/astobj2_container.c index c00da9fd41a..15fd41286b0 100644 --- a/main/astobj2_container.c +++ b/main/astobj2_container.c @@ -101,10 +101,13 @@ int __ao2_link(struct ao2_container *self, void *obj_new, int flags, struct ao2_container_node *node; if (!__is_ao2_object(obj_new, file, line, func) - || !__is_ao2_object(self, file, line, func) - || !self->v_table || !self->v_table->new_node || !self->v_table->insert) { + || !__is_ao2_object(self, file, line, func)) { + return 0; + } + + if (!self->v_table || !self->v_table->new_node || !self->v_table->insert) { /* Sanity checks. */ - ast_assert(0); + __ast_assert_failed(0, "invalid container v_table", file, line, func); return 0; } @@ -176,7 +179,6 @@ void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags, { if (!__is_ao2_object(user_data, file, line, func)) { /* Sanity checks. */ - ast_assert(0); return NULL; } @@ -241,10 +243,14 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags struct ao2_container *multi_container = NULL; struct ao2_iterator *multi_iterator = NULL; - if (!__is_ao2_object(self, file, line, func) || !self->v_table + if (!__is_ao2_object(self, file, line, func)) { + return NULL; + } + + if (!self->v_table || !self->v_table->traverse_first || !self->v_table->traverse_next) { /* Sanity checks. */ - ast_assert(0); + __ast_assert_failed(0, "invalid container v_table", file, line, func); return NULL; } @@ -451,8 +457,7 @@ struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) void ao2_iterator_restart(struct ao2_iterator *iter) { if (!is_ao2_object(iter->c)) { - ast_log(LOG_ERROR, "Iterator container is not valid.\n"); - ast_assert(0); + /* Sanity check. */ return; } @@ -460,12 +465,6 @@ void ao2_iterator_restart(struct ao2_iterator *iter) if (iter->last_node) { enum ao2_lock_req orig_lock; - if (!is_ao2_object(iter->c)) { - /* Sanity check. */ - ast_assert(0); - return; - } - /* * Do a read lock in case the container node unref does not * destroy the node. If the container node is destroyed then @@ -521,10 +520,13 @@ void *__ao2_iterator_next(struct ao2_iterator *iter, struct ao2_container_node *node; void *ret; - if (!__is_ao2_object(iter->c, file, line, func) - || !iter->c->v_table || !iter->c->v_table->iterator_next) { + if (!__is_ao2_object(iter->c, file, line, func)) { + return NULL; + } + + if (!iter->c->v_table || !iter->c->v_table->iterator_next) { /* Sanity checks. */ - ast_assert(0); + __ast_assert_failed(0, "invalid iterator container v_table", file, line, func); return NULL; } @@ -661,12 +663,16 @@ struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum sea int failed; /* Create the clone container with the same properties as the original. */ - if (!__is_ao2_object(orig, file, line, func) - || !orig->v_table || !orig->v_table->alloc_empty_clone) { + if (!__is_ao2_object(orig, file, line, func)) { + return NULL; + } + + if (!orig->v_table || !orig->v_table->alloc_empty_clone) { /* Sanity checks. */ - ast_assert(0); + __ast_assert_failed(0, "invalid container v_table", file, line, func); return NULL; } + clone = orig->v_table->alloc_empty_clone(orig, tag, file, line, func); if (!clone) { return NULL; diff --git a/main/astobj2_hash.c b/main/astobj2_hash.c index 072cd181556..eee90f513b8 100644 --- a/main/astobj2_hash.c +++ b/main/astobj2_hash.c @@ -166,7 +166,9 @@ static void hash_ao2_node_destructor(void *v_doomed) * same node. */ my_container = (struct ao2_container_hash *) doomed->common.my_container; - ast_assert(is_ao2_object(my_container)); +#ifdef AST_DEVMODE + is_ao2_object(my_container); +#endif __adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1); diff --git a/main/astobj2_rbtree.c b/main/astobj2_rbtree.c index 03efd886fca..1760938fcb7 100644 --- a/main/astobj2_rbtree.c +++ b/main/astobj2_rbtree.c @@ -858,7 +858,9 @@ static void rb_ao2_node_destructor(void *v_doomed) * same node. */ my_container = (struct ao2_container_rbtree *) doomed->common.my_container; - ast_assert(is_ao2_object(my_container)); +#ifdef AST_DEVMODE + is_ao2_object(my_container); +#endif __adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1); diff --git a/main/utils.c b/main/utils.c index c8ede91d9a1..fc7aa30d7eb 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2467,17 +2467,16 @@ void DO_CRASH_NORETURN ast_do_crash(void) #endif /* defined(DO_CRASH) */ } -#if defined(AST_DEVMODE) void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function) { /* * Attempt to put it into the logger, but hope that at least * someone saw the message on stderr ... */ - ast_log(__LOG_ERROR, file, line, function, "FRACK!, Failed assertion %s (%d)\n", - condition_str, condition); fprintf(stderr, "FRACK!, Failed assertion %s (%d) at line %d in %s of %s\n", condition_str, condition, line, function, file); + ast_log(__LOG_ERROR, file, line, function, "FRACK!, Failed assertion %s (%d)\n", + condition_str, condition); /* Generate a backtrace for the assert */ ast_log_backtrace(); @@ -2490,7 +2489,6 @@ void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_ usleep(1); ast_do_crash(); } -#endif /* defined(AST_DEVMODE) */ char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid) { From c4558236573ac599e6664c47e4db19d8a8eb953e Mon Sep 17 00:00:00 2001 From: frahaase Date: Fri, 12 Aug 2016 18:22:02 +0200 Subject: [PATCH 0778/1578] Binaural synthesis (confbridge): interleaved two-channel audio. Asterisk only supports mono audio at the moment. This patch adds interleaved two-channel audio to Asterisk's channels. ASTERISK-26292 Change-Id: I7a547cea0fd3c6d1e502709d9e7e39605035757a --- include/asterisk/channel.h | 10 +++++++++ include/asterisk/translate.h | 1 + main/channel.c | 42 ++++++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 14bd32c0793..94f72b879a2 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -2016,6 +2016,16 @@ int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_ca */ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format); +/*! + * \brief Sets write format for a channel. + * All internal data will than be handled in an interleaved format. (needed by binaural opus) + * + * \param chan channel to change + * \param format format to set for writing + * \return Returns 0 on success, -1 on failure + */ +int ast_set_write_format_interleaved_stereo(struct ast_channel *chan, struct ast_format *format); + /*! * \brief Sends text to a channel * diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h index b8cd219713b..8188eb8ebfe 100644 --- a/include/asterisk/translate.h +++ b/include/asterisk/translate.h @@ -231,6 +231,7 @@ struct ast_trans_pvt { * explicit_dst contains an attribute which describes whether both parties * want to do forward-error correction (FEC). */ struct ast_format *explicit_dst; + int interleaved_stereo; /*!< indicates if samples are in interleaved order, for stereo lin */ }; /*! \brief generic frameout function */ diff --git a/main/channel.c b/main/channel.c index 1f18d53b15c..f8b218fd02e 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5407,7 +5407,7 @@ static const struct set_format_access set_format_access_write = { .setoption = AST_OPTION_FORMAT_WRITE, }; -static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, const int direction) +static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, const int direction, int interleaved_stereo) { struct ast_trans_pvt *trans_pvt; struct ast_format_cap *cap_native; @@ -5509,16 +5509,20 @@ static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, } /* Now we have a good choice for both. */ + trans_pvt = access->get_trans(chan); if ((ast_format_cmp(rawformat, best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) && (ast_format_cmp(format, best_set_fmt) != AST_FORMAT_CMP_NOT_EQUAL) && ((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || access->get_trans(chan))) { - /* the channel is already in these formats, so nothing to do */ - ast_channel_unlock(chan); - return 0; + /* the channel is already in these formats, so nothing to do, unless the interleaved format is not set correctly */ + if (trans_pvt != NULL) { + if (trans_pvt->interleaved_stereo == interleaved_stereo) { + ast_channel_unlock(chan); + return 0; + } + } } /* Free any translation we have right now */ - trans_pvt = access->get_trans(chan); if (trans_pvt) { ast_translator_free_path(trans_pvt); access->set_trans(chan, NULL); @@ -5536,9 +5540,11 @@ static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, if (!direction) { /* reading */ trans_pvt = ast_translator_build_path(best_set_fmt, best_native_fmt); + trans_pvt->interleaved_stereo = 0; } else { /* writing */ trans_pvt = ast_translator_build_path(best_native_fmt, best_set_fmt); + trans_pvt->interleaved_stereo = interleaved_stereo; } access->set_trans(chan, trans_pvt); res = trans_pvt ? 0 : -1; @@ -5578,7 +5584,7 @@ int ast_set_read_format(struct ast_channel *chan, struct ast_format *format) } ast_format_cap_append(cap, format, 0); - res = set_format(chan, cap, 0); + res = set_format(chan, cap, 0, 0); ao2_cleanup(cap); return res; @@ -5586,7 +5592,25 @@ int ast_set_read_format(struct ast_channel *chan, struct ast_format *format) int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap) { - return set_format(chan, cap, 0); + return set_format(chan, cap, 0, 0); +} + +int ast_set_write_format_interleaved_stereo(struct ast_channel *chan, struct ast_format *format) +{ + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + int res; + + ast_assert(format != NULL); + + if (!cap) { + return -1; + } + ast_format_cap_append(cap, format, 0); + + res = set_format(chan, cap, 1, 1); + + ao2_cleanup(cap); + return res; } int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) @@ -5601,7 +5625,7 @@ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) } ast_format_cap_append(cap, format, 0); - res = set_format(chan, cap, 1); + res = set_format(chan, cap, 1, 0); ao2_cleanup(cap); return res; @@ -5609,7 +5633,7 @@ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap) { - return set_format(chan, cap, 1); + return set_format(chan, cap, 1, 0); } const char *ast_channel_reason2str(int reason) From c4268ec734f34829f2ab455f3fecdc5cd14aae1b Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 5 Oct 2016 11:25:11 +0200 Subject: [PATCH 0779/1578] chan_sip: Honor support of Symmetric Response (rport) for SIP requests. In the SIP channel driver chan_sip, the default is "auto_force_rport". When no NAT was detected, for example in case of IPv6, Asterisk uses the IP address from the headers within the SIP-REGISTER for subsequent SIP signaling. When the remote party specifies support for Symmetric Response (RFC 3581) via the parameter "rport", Asterisk should not extract the port from the SIP headers but reuse the port of the transport. This did not happen because of a typo. ASTERISK-26438 #close Change-Id: If6e7891848aaf96666dee5305695f7c6667cd5a6 --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b9480f465be..47b90d7240b 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -16819,7 +16819,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st } if ((transport_type != AST_TRANSPORT_WS) && (transport_type != AST_TRANSPORT_WSS) && - (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) && !ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT))) { + (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) && !ast_test_flag(&pvt->flags[0], SIP_NAT_RPORT_PRESENT))) { /* use the data provided in the Contact header for call routing */ ast_debug(1, "Store REGISTER's Contact header for call routing.\n"); /* XXX This could block for a long time XXX */ From 442b597929c8d81fc41a9cbd8439e6ec215ba9ea Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 4 Oct 2016 15:59:54 -0600 Subject: [PATCH 0780/1578] alembic: Allow cdr, config and voicemail to exist in the same schema cdr, config and voicemail are all separate alembic trees. Because alembic's default is to use a table named 'alembic_version' to store the current tree revision, the 3 trees can't exist in the same schema without stepping on each other. Now each tree uses 'alembic_version_' as the version table. Each tree's env.py script now first checks for 'alembic_version'. If it finds it AND its revision is in the tree's history, the script renames it to 'alembic_version_'. Regardless, the script then continues with the migration using 'alembic_version_' and creates that table if it's not found. The result is that if an existing 'alembic_version' table was found but it didn't belong to this tree, it's left alone and 'alembic_version_' is used or created. WARNING: If multiple trees are using the same schema, they MUST NOT CRU or D any objects with names that might exist in the other trees. An example would be 'yesno_values' type. If two trees perform operations on it, one tree could pull it out from under the other. Thankfully we currently don't share any names among cdr, config and voicemail. NOTE: Since the env.py scripts in each tree were identical, a common env.py has been placed in the ast-db-manage directory and a symlink to it has been placed in each tree directory. ASTERISK-24311 #close Reported-by: Dafi Ni Change-Id: I4d593f000350deb5d21a14fa1e9bc3896844d898 --- contrib/ast-db-manage/cdr/env.py | 75 +------------ contrib/ast-db-manage/config/env.py | 75 +------------ contrib/ast-db-manage/env.py | 140 +++++++++++++++++++++++++ contrib/ast-db-manage/voicemail/env.py | 75 +------------ 4 files changed, 143 insertions(+), 222 deletions(-) mode change 100755 => 120000 contrib/ast-db-manage/cdr/env.py mode change 100755 => 120000 contrib/ast-db-manage/config/env.py create mode 100755 contrib/ast-db-manage/env.py mode change 100755 => 120000 contrib/ast-db-manage/voicemail/env.py diff --git a/contrib/ast-db-manage/cdr/env.py b/contrib/ast-db-manage/cdr/env.py deleted file mode 100755 index 6740d5906d5..00000000000 --- a/contrib/ast-db-manage/cdr/env.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import with_statement -from alembic import context -from sqlalchemy import engine_from_config, pool -from logging.config import fileConfig - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -try: - fileConfig(config.config_file_name) -except: - pass - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -target_metadata = None - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure(url=url) - - with context.begin_transaction(): - context.run_migrations() - -def run_migrations_online(): - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - engine = engine_from_config( - config.get_section(config.config_ini_section), - prefix='sqlalchemy.', - poolclass=pool.NullPool) - - connection = engine.connect() - context.configure( - connection=connection, - target_metadata=target_metadata - ) - - try: - with context.begin_transaction(): - context.run_migrations() - finally: - connection.close() - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() - diff --git a/contrib/ast-db-manage/cdr/env.py b/contrib/ast-db-manage/cdr/env.py new file mode 120000 index 00000000000..74b15c93008 --- /dev/null +++ b/contrib/ast-db-manage/cdr/env.py @@ -0,0 +1 @@ +../env.py \ No newline at end of file diff --git a/contrib/ast-db-manage/config/env.py b/contrib/ast-db-manage/config/env.py deleted file mode 100755 index 6740d5906d5..00000000000 --- a/contrib/ast-db-manage/config/env.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import with_statement -from alembic import context -from sqlalchemy import engine_from_config, pool -from logging.config import fileConfig - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -try: - fileConfig(config.config_file_name) -except: - pass - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -target_metadata = None - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure(url=url) - - with context.begin_transaction(): - context.run_migrations() - -def run_migrations_online(): - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - engine = engine_from_config( - config.get_section(config.config_ini_section), - prefix='sqlalchemy.', - poolclass=pool.NullPool) - - connection = engine.connect() - context.configure( - connection=connection, - target_metadata=target_metadata - ) - - try: - with context.begin_transaction(): - context.run_migrations() - finally: - connection.close() - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() - diff --git a/contrib/ast-db-manage/config/env.py b/contrib/ast-db-manage/config/env.py new file mode 120000 index 00000000000..74b15c93008 --- /dev/null +++ b/contrib/ast-db-manage/config/env.py @@ -0,0 +1 @@ +../env.py \ No newline at end of file diff --git a/contrib/ast-db-manage/env.py b/contrib/ast-db-manage/env.py new file mode 100755 index 00000000000..a903451b4c6 --- /dev/null +++ b/contrib/ast-db-manage/env.py @@ -0,0 +1,140 @@ +from __future__ import with_statement +from alembic import context +from alembic.script import ScriptDirectory +from alembic.operations import Operations +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig +import logging + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +try: + fileConfig(config.config_file_name) +except: + pass + +logger = logging.getLogger('alembic.runtime.setup') +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure(url=url) + + with context.begin_transaction(): + context.run_migrations() + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + engine = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool) + + logger.info('Testing for an old alembic_version table.') + + connection = engine.connect() + context.configure( + connection=connection, + target_metadata=target_metadata, + version_table='alembic_version' + ) + + script_location = config.get_main_option('script_location') + found = False + mc = context.get_context() + current_db_revision = mc.get_current_revision() + script = ScriptDirectory.from_config(config) + """ If there was an existing alembic_version table, we need to + check that it's current revision is in the history for the tree + we're working with. + """ + for x in script.iterate_revisions('head', 'base'): + if x.revision == current_db_revision: + """ An alembic_versions table was found and it belongs to + this alembic tree + """ + logger.info( + ('An old alembic_version table at revision %s was ' + 'found for %s. Renaming to alembic_version_%s.'), + current_db_revision, script_location, + script_location) + op = Operations(mc) + try: + with context.begin_transaction(): + op.rename_table( + 'alembic_version', 'alembic_version_%s' + % script_location) + found = True + except: + logger.error(('Unable to rename alembic_version to ' + 'alembic_version_%s.'), + script_location) + connection.close() + return + + break + + if not found: + logger.info('Didn\'t find an old alembic_version table.') + logger.info('Trying alembic_version_%s.' % script_location) + + """ We MAY have an alembic_version table that doesn't belong to + this tree but if we still don't have an alembic_version_ + table, alembic will create it. + """ + context.configure( + connection=connection, + target_metadata=target_metadata, + version_table='alembic_version_' + script_location + ) + mc = context.get_context() + current_db_revision = mc.get_current_revision() + if current_db_revision: + logger.info( + 'Using the alembic_version_%s table at revision %s.', + script_location, current_db_revision) + else: + logger.info('Creating new alembic_version_%s table.', + script_location) + + try: + with context.begin_transaction(): + context.run_migrations() + finally: + connection.close() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() + diff --git a/contrib/ast-db-manage/voicemail/env.py b/contrib/ast-db-manage/voicemail/env.py deleted file mode 100755 index 6740d5906d5..00000000000 --- a/contrib/ast-db-manage/voicemail/env.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import with_statement -from alembic import context -from sqlalchemy import engine_from_config, pool -from logging.config import fileConfig - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -try: - fileConfig(config.config_file_name) -except: - pass - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -target_metadata = None - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure(url=url) - - with context.begin_transaction(): - context.run_migrations() - -def run_migrations_online(): - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - engine = engine_from_config( - config.get_section(config.config_ini_section), - prefix='sqlalchemy.', - poolclass=pool.NullPool) - - connection = engine.connect() - context.configure( - connection=connection, - target_metadata=target_metadata - ) - - try: - with context.begin_transaction(): - context.run_migrations() - finally: - connection.close() - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() - diff --git a/contrib/ast-db-manage/voicemail/env.py b/contrib/ast-db-manage/voicemail/env.py new file mode 120000 index 00000000000..74b15c93008 --- /dev/null +++ b/contrib/ast-db-manage/voicemail/env.py @@ -0,0 +1 @@ +../env.py \ No newline at end of file From c5e8f5016913102833147c7ac2d09001358abacf Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 5 Oct 2016 13:53:10 -0600 Subject: [PATCH 0781/1578] pjproject_bundled: Add MALLOC_DEBUG capability pjproject_bundled will now use the asterisk memory debugging APIs if MALLOC_DEBUG is turned on in menuselect. Because this required stubs for the executable programs and the python bindings, some Makefile reorganization was needed to properly handle the dependencies. As a result, the makefile now individually makes each of the pjproject libraries separately instead of making them all in 1 shot. The only visible change is that there are separate status lines printed for each library instead oif 1 for all libs. Also, the making of the pjproject dependency files was eliminated. They're not needed for building unless you're actively modifying pjproject source files and it makes the build process faster. Finally, any issues with parallel builds should be resolved again making the build faster. Change-Id: Icc5e3d658fbfb00e0a46b44c66dcc2522d5171b0 --- third-party/Makefile.rules | 2 +- third-party/pjproject/.gitignore | 1 + third-party/pjproject/Makefile | 105 ++++++++++++------ .../pjproject/patches/asterisk_malloc_debug.c | 72 ++++++++++++ .../pjproject/patches/asterisk_malloc_debug.h | 78 +++++++++++++ third-party/pjproject/patches/config_site.h | 8 ++ 6 files changed, 231 insertions(+), 35 deletions(-) create mode 100644 third-party/pjproject/patches/asterisk_malloc_debug.c create mode 100644 third-party/pjproject/patches/asterisk_malloc_debug.h diff --git a/third-party/Makefile.rules b/third-party/Makefile.rules index e633e0e9899..92e4ebc859e 100644 --- a/third-party/Makefile.rules +++ b/third-party/Makefile.rules @@ -4,7 +4,7 @@ SUBMAKE?=$(MAKE) --quiet --no-print-directory ECHO_PREFIX?=@ CMD_PREFIX?=@ QUIET_CONFIGURE=-q -REALLY_QUIET=&>/dev/null +REALLY_QUIET=>/dev/null 2>&1 else SUBMAKE?=$(MAKE) ECHO_PREFIX?=@\# diff --git a/third-party/pjproject/.gitignore b/third-party/pjproject/.gitignore index 5079deeb351..6904ebfb641 100644 --- a/third-party/pjproject/.gitignore +++ b/third-party/pjproject/.gitignore @@ -2,3 +2,4 @@ source/ **.bz2 build.mak pjproject.symbols +.rebuild_needed diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 7349db62f83..bb98a09e311 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -1,4 +1,3 @@ -.SUFFIXES: .PHONY: _all all _install install clean distclean echo_cflags configure include ../versions.mak @@ -40,18 +39,28 @@ ifeq ($(SPECIAL_TARGETS),) include ../../Makefile.rules include Makefile.rules - include build.mak + include source/user.mak + include source/build.mak CF := $(filter-out -W%,$(CC_CFLAGS)) CF := $(filter-out -I%,$(CF)) - export CFLAGS += $(CF) - export LDFLAGS += $(CC_LDFLAGS) - TARGETS := pjproject.symbols ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),TEST_FRAMEWORK) - TARGETS += source/pjsip-apps/bin/pjsua-$(TARGET_NAME) + apps := source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/bin/pjsystest-$(TARGET_NAME) + TARGETS += $(apps) ifneq ($(PYTHONDEV_LIB),) - TARGETS += source/pjsip-apps/src/python/build/_pjsua.so + TARGETS += source/pjsip-apps/src/python/_pjsua.so endif endif + ifeq ($(findstring MALLOC_DEBUG,$(MENUSELECT_CFLAGS)),MALLOC_DEBUG) + CF += -DMALLOC_DEBUG + MALLOC_DEBUG = yes + $(apps): export LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive + $(apps): source/pjsip-apps/lib/libasterisk_malloc_debug.a + source/pjsip-apps/src/python/_pjsua.so: LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive + source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/lib/libasterisk_malloc_debug.a + endif + TARGETS += pjproject.symbols + export CFLAGS += $(CF) + export LDFLAGS += $(CC_LDFLAGS) else all install: endif @@ -73,8 +82,8 @@ $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 : ../versions.mak source/.unpacked: $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 $(ECHO_PREFIX) Unpacking $< - -@rm -rf source &>/dev/null - -@mkdir source &>/dev/null + -@rm -rf source >/dev/null 2>&1 + -@mkdir source >/dev/null 2>&1 $(CMD_PREFIX) tar --strip-components=1 -C source -xjf $< $(ECHO_PREFIX) Applying patches $(CMD_PREFIX) ./apply_patches $(QUIET_CONFIGURE) ./patches ./source @@ -84,11 +93,11 @@ source/user.mak: source/.unpacked ./patches/user.mak $(ECHO_PREFIX) Applying user.mak $(CMD_PREFIX) cp -f ./patches/user.mak ./source/ -source/pjlib/include/pj/config_site.h: source/.unpacked ./patches/config_site.h - $(ECHO_PREFIX) Applying config_site.h - $(CMD_PREFIX) cp -f ./patches/config_site.h ./source/pjlib/include/pj/ +source/pjlib/include/pj/%.h : ./patches/%.h + $(ECHO_PREFIX) Applying custom include file $< + $(CMD_PREFIX) cp -f $< ./source/pjlib/include/pj/ -build.mak: source/.unpacked source/pjlib/include/pj/config_site.h source/user.mak Makefile.rules +build.mak: source/.unpacked $(addprefix source/pjlib/include/pj/,$(notdir $(wildcard ./patches/*.h))) source/user.mak Makefile.rules $(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS) $(CMD_PREFIX) (cd source ; autoconf aconfigure.ac > aconfigure && ./aconfigure $(QUIET_CONFIGURE) $(PJPROJECT_CONFIG_OPTS)) @sed -r -e "/prefix|export PJ_SHARED_LIBRARIES|MACHINE_NAME|OS_NAME|HOST_NAME|CC_NAME|CROSS_COMPILE|LINUX_POLL/d" source/build.mak > build.mak @@ -98,29 +107,53 @@ configure: build.mak echo_cflags: build.mak @echo $(PJ_CFLAGS) -source/pjlib/build/.pjlib-$(TARGET_NAME).depend: build.mak - $(ECHO_PREFIX) "Making dependencies" - +$(CMD_PREFIX) $(SUBMAKE) -C source dep +.rebuild_needed: ../../menuselect.makeopts + $(ECHO_PREFIX) Rebuilding + $(CMD_PREFIX)$(MAKE) clean $(REALLY_QUIET) + @touch .rebuild_needed -menuselect: ../../menuselect.makeopts ../../makeopts - -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || : - -$(CMD_PREFIX) rm -rf pjproject.symbols +libpj%.a: .rebuild_needed build.mak + $(ECHO_PREFIX) Compiling lib $(@F) + $(CMD_PREFIX)$(MAKE) -C $(dir $(shell dirname $@))/build $(@F) $(REALLY_QUIET) -source/pjlib/lib/libpj-$(TARGET_NAME).a: menuselect source/pjlib/build/.pjlib-$(TARGET_NAME).depend - $(ECHO_PREFIX) Compiling libs - +$(CMD_PREFIX) $(SUBMAKE) -C source lib $(REALLY_QUIET) +# We need to compile pjlib, then pjlib-util, then the rest +# so we separate them out and create the dependencies +PJLIB_LIB_FILES = $(foreach lib,$(PJ_LIB_FILES),$(if $(findstring libpj-,$(lib)),$(lib),)) +PJLIB_UTIL_LIB_FILES = $(foreach lib,$(PJ_LIB_FILES),$(if $(findstring libpjlib-util,$(lib)),$(lib),)) +LIB_FILES = $(filter-out $(PJLIB_LIB_FILES) $(PJLIB_UTIL_LIB_FILES),$(PJ_LIB_FILES)) +ALL_LIB_FILES = $(PJLIB_LIB_FILES) $(PJLIB_UTIL_LIB_FILES) $(LIB_FILES) -pjproject.symbols: source/pjlib/lib/libpj-$(TARGET_NAME).a +$(PJLIB_UTIL_LIB_FILES): $(PJLIB_LIB_FILES) +$(LIB_FILES): $(PJLIB_UTIL_LIB_FILES) + +pjproject.symbols: $(ALL_LIB_FILES) $(ECHO_PREFIX) Generating symbols - $(CMD_PREFIX) nm -Pog $(PJ_LIB_FILES) | sed -n -r -e "s/.+: ([pP][jJ][^ ]+) .+/\1/gp" | sort -u > pjproject.symbols + $(CMD_PREFIX) nm -Pog $(ALL_LIB_FILES) | sed -n -r -e "s/.+: ([pP][jJ][^ ]+) .+/\1/gp" | sort -u > pjproject.symbols + +source/pjsip-apps/src/asterisk_malloc_debug.c: patches/asterisk_malloc_debug.c + $(ECHO_PREFIX) Copying $< to $@ + $(CMD_PREFIX) cp -f $< $@ + +source/pjsip-apps/lib/asterisk_malloc_debug.o: source/pjsip-apps/src/asterisk_malloc_debug.c .rebuild_needed + $(ECHO_PREFIX) Compiling asterisk debug malloc stubs + $(CMD_PREFIX) $(CC) -fPIC $(PJ_CFLAGS) -c $< -o $@ -source/pjsip-apps/bin/pjsua-$(TARGET_NAME): source/pjlib/lib/libpj-$(TARGET_NAME).a - $(ECHO_PREFIX) Compiling apps - $(CMD_PREFIX) $(SUBMAKE) -C source/pjsip-apps/build pjsua pjsystest $(REALLY_QUIET) +source/pjsip-apps/lib/libasterisk_malloc_debug.a: source/pjsip-apps/lib/asterisk_malloc_debug.o + $(ECHO_PREFIX) Creating archive $(@F) + $(CMD_PREFIX) ar qs $@ $< >/dev/null 2>&1 -source/pjsip-apps/src/python/build/_pjsua.so: source/pjlib/lib/libpj-$(TARGET_NAME).a +$(apps): APP = $(filter pj%,$(subst -, ,$(notdir $@))) +$(apps): pjproject.symbols + $(ECHO_PREFIX) Compiling $(APP) + $(CMD_PREFIX) +$(MAKE) -C source/pjsip-apps/build $(filter pj%,$(subst -, ,$(notdir $@))) $(REALLY_QUIET) + +source/pjsip-apps/src/python/_pjsua.o: source/pjsip-apps/src/python/_pjsua.c $(apps) $(ECHO_PREFIX) Compiling python bindings - $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; MAKE=$(MAKE) python setup.py build --build-platlib=./build $(REALLY_QUIET)) + $(CMD_PREFIX) $(CC) -o $@ -c $< $(PYTHONDEV_INCLUDE) $(CFLAGS) $(PJ_CFLAGS) + +source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/src/python/_pjsua.o + $(ECHO_PREFIX) Linking python bindings $(@F) + $(CMD_PREFIX) gcc -shared -pthread -o $@ $< $(LDFLAGS) $(PJ_LDFLAGS) $(APP_LDLIBS) $(PYTHONDEV_LIB) $(REALLY_QUIET) _all: $(TARGETS) @@ -133,10 +166,10 @@ ifneq ($(findstring source/pjsip-apps/bin/pjsua-$(TARGET_NAME),$(TARGETS)),) $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsua-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsua" $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsystest-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsystest" endif -ifneq ($(findstring source/pjsip-apps/src/python/build/_pjsua.so,$(TARGETS)),) +ifneq ($(findstring _pjsua.so,$(TARGETS)),) $(ECHO_PREFIX) Installing python bindings - $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/src/python/build/_pjsua.so "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" - $(CMD_PREFIX) $(INSTALL) -m 644 source/pjsip-apps/src/python/build/pjsua.py "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" + $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/src/python/_pjsua.so "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" + $(CMD_PREFIX) $(INSTALL) -m 644 source/pjsip-apps/src/python/pjsua.py "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/" endif uninstall: @@ -145,10 +178,14 @@ uninstall: clean: $(ECHO_PREFIX) Cleaning - -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build ; rm -rf source/pjsip-apps/bin/* ) || : + +-$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean || : ;\ + rm -rf source/pjsip-apps/bin/* || : ;\ + find source -name *.a -delete ;\ + find source -name *.o -delete ;\ + find source -name *.so -delete ; ) || : -$(CMD_PREFIX) rm -rf pjproject.symbols distclean: $(ECHO_PREFIX) Distcleaning - -$(CMD_PREFIX) rm -rf source pjproject.symbols pjproject-*.tar.bz2 build.mak + -$(CMD_PREFIX) rm -rf source pjproject.symbols pjproject-*.tar.bz2 build.mak .rebuild_needed diff --git a/third-party/pjproject/patches/asterisk_malloc_debug.c b/third-party/pjproject/patches/asterisk_malloc_debug.c new file mode 100644 index 00000000000..c41767bd869 --- /dev/null +++ b/third-party/pjproject/patches/asterisk_malloc_debug.c @@ -0,0 +1,72 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ +#define _GNU_SOURCE + +#include +#include +#include +#include + +int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...) +{ + va_list ap; + int rc = 0; + + va_start(ap, format); + rc = vasprintf(strp, format, ap); + va_end(ap); + + return rc; +} + +void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) +{ + return calloc(nmemb, size); +} + +void __ast_free(void *ptr, const char *file, int lineno, const char *func) +{ + free(ptr); +} + +void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) +{ + return malloc(size); +} + +void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) +{ + return realloc(ptr, size); +} + +char *__ast_strdup(const char *s, const char *file, int lineno, const char *func) +{ + return strdup(s); +} + +char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) +{ + return strndup(s, n); +} + +int __ast_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func) +{ + return vasprintf(strp, format, ap); +} + + diff --git a/third-party/pjproject/patches/asterisk_malloc_debug.h b/third-party/pjproject/patches/asterisk_malloc_debug.h new file mode 100644 index 00000000000..44c47375887 --- /dev/null +++ b/third-party/pjproject/patches/asterisk_malloc_debug.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef ASTERISK_MALLOC_DEBUG_H_ +#define ASTERISK_MALLOC_DEBUG_H_ + +/* Include these now to prevent them from messing up MALLOC_DEBUG */ +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...) + __attribute__((format(printf, 5, 6))); +void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func); +void __ast_free(void *ptr, const char *file, int lineno, const char *func); +void *__ast_malloc(size_t size, const char *file, int lineno, const char *func); +void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func); +char *__ast_strdup(const char *s, const char *file, int lineno, const char *func); +char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func); +int __ast_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func) + __attribute__((format(printf, 2, 0))); + +/* Undefine any macros */ +#undef asprintf +#undef calloc +#undef free +#undef malloc +#undef realloc +#undef strdup +#undef strndup +#undef vasprintf + + /* Provide our own definitions */ +#define asprintf(a, b, c...) \ + __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, b, c) + +#define calloc(a,b) \ + __ast_calloc(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#define free(a) \ + __ast_free(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#define malloc(a) \ + __ast_malloc(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#define realloc(a,b) \ + __ast_realloc(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#define strdup(a) \ + __ast_strdup(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#define strndup(a,b) \ + __ast_strndup(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#define vasprintf(a,b,c) \ + __ast_vasprintf(a,b,c,__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#ifdef __cplusplus +} +#endif + +#endif /* ASTERISK_MALLOC_DEBUG_H_ */ diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index f9f76dc6c93..0694f120e87 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -4,6 +4,14 @@ #include +/* + * Since both pjproject and asterisk source files will include config_site.h, + * we need to make sure that only pjproject source files include asterisk_malloc_debug.h. + */ +#if defined(MALLOC_DEBUG) && !defined(_ASTERISK_ASTMM_H) +#include "asterisk_malloc_debug.h" +#endif + /* * Defining PJMEDIA_HAS_SRTP to 0 does NOT disable Asterisk's ability to use srtp. * It only disables the pjmedia srtp transport which Asterisk doesn't use. From 73f75c246bc0198abc307e57c3da520f2f53ba1d Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 9 Oct 2016 23:54:53 +0000 Subject: [PATCH 0782/1578] Revert "Packet-Loss Concealment (PLC) for supporting codecs." This change introduced some fax test failures that have not yet been addressed. So this is not forgotten I'm submitting a change which reverts it. This reverts: d56fc3b36b7bb59b5506129b9895b6c3341350c9. ASTERISK-25629 Change-Id: Ibc2f23c38643f5a2c89cf8915ae2d805b81bc3d5 --- main/translate.c | 180 +++++++---------------------------------------- 1 file changed, 27 insertions(+), 153 deletions(-) diff --git a/main/translate.c b/main/translate.c index 45113aa484c..43e6e29bd5d 100644 --- a/main/translate.c +++ b/main/translate.c @@ -31,25 +31,20 @@ ASTERISK_REGISTER_FILE() -#include /* for rusage, getrusage, etc */ -#include /* for timeval */ - -#include "asterisk/astobj2.h" /* for ao2_ref, ao2_cleanup, etc */ -#include "asterisk/cli.h" /* for ast_cli_args, ast_cli, etc */ -#include "asterisk/codec.h" /* for ast_codec, etc */ -#include "asterisk/format.h" /* for ast_format_get_name, etc */ -#include "asterisk/format_cache.h" /* for ast_format_cache_get, etc */ -#include "asterisk/format_cap.h" /* for ast_format_cap_count, etc */ -#include "asterisk/frame.h" /* for ast_frame, etc */ -#include "asterisk/linkedlists.h" /* for AST_RWLIST_UNLOCK, etc */ -#include "asterisk/lock.h" /* for ast_rwlock_unlock, etc */ -#include "asterisk/logger.h" /* for ast_log, LOG_WARNING, etc */ -#include "asterisk/module.h" /* for ast_module_unref, etc */ -#include "asterisk/strings.h" /* for ast_str_append, etc */ -#include "asterisk/term.h" /* for term_color, COLOR_BLACK, etc */ -#include "asterisk/time.h" /* for ast_tvzero, ast_tv, etc */ -#include "asterisk/translate.h" /* for ast_translator, etc */ -#include "asterisk/utils.h" /* for ast_free, RAII_VAR, etc */ +#include +#include +#include + +#include "asterisk/lock.h" +#include "asterisk/channel.h" +#include "asterisk/translate.h" +#include "asterisk/module.h" +#include "asterisk/frame.h" +#include "asterisk/sched.h" +#include "asterisk/cli.h" +#include "asterisk/term.h" +#include "asterisk/format.h" +#include "asterisk/linkedlists.h" /*! \todo * TODO: sample frames for each supported input format. @@ -363,7 +358,6 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format pvt->f.offset = AST_FRIENDLY_OFFSET; pvt->f.src = pvt->t->name; pvt->f.data.ptr = pvt->outbuf.c; - pvt->f.seqno = 0x10000; /* * If the translator has not provided a format @@ -530,58 +524,13 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a /*! \brief do the actual translation */ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume) { - const unsigned int rtp_seqno_max_value = 0xffff; - struct ast_frame *out_last, *out = NULL; - struct ast_trans_pvt *step; + struct ast_trans_pvt *p = path; + struct ast_frame *out; struct timeval delivery; int has_timing_info; long ts; long len; - int seqno, frames_missing; - - /* Determine the amount of lost packets for PLC */ - /* But not when Signed Linear is involved = frame created internally */ - /* But not at start with first frame = path->f.seqno is still 0x10000 */ - /* But not when there is no sequence number = frame created internally */ - if (!ast_format_cache_is_slinear(f->subclass.format) && - path->f.seqno <= rtp_seqno_max_value && - path->f.seqno != f->seqno) { - if (f->seqno < path->f.seqno) { /* seqno overrun situation */ - frames_missing = rtp_seqno_max_value + f->seqno - path->f.seqno - 1; - } else { - frames_missing = f->seqno - path->f.seqno - 1; - } - /* Out-of-order packet - more precise: late packet */ - if ((rtp_seqno_max_value + 1) / 2 < frames_missing) { - if (consume) { - ast_frfree(f); - } - /* - * Do not pass late packets to any transcoding module, because that - * confuses the state of any library (packets inter-depend). With - * the next packet, this one is going to be treated as lost packet. - */ - if (frames_missing > 96) { /* with 20 msec per frame, around 2 seconds late */ - struct ast_str *str = ast_str_alloca(256); - - /* Might indicate an error in the detection of Late Frames, report! */ - ast_log(LOG_NOTICE, "Late Frame; got Sequence Number %d expected %d %s\n", - f->seqno, rtp_seqno_max_value & (path->f.seqno + 1), - ast_translate_path_to_str(path, &str)); - } - return NULL; - } - - if (frames_missing > 96) { - struct ast_str *str = ast_str_alloca(256); - - /* not DEBUG but NOTICE because of WARNING in main/cannel.c:__ast_queue_frame */ - ast_log(LOG_NOTICE, "%d lost frame(s) %d/%d %s\n", frames_missing, - f->seqno, path->f.seqno, ast_translate_path_to_str(path, &str)); - } - } else { - frames_missing = 0; - } + int seqno; has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); ts = f->ts; @@ -611,93 +560,18 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, f->samples, ast_format_get_sample_rate(f->subclass.format))); } delivery = f->delivery; - - for (out_last = NULL; frames_missing + 1; frames_missing--) { - struct ast_frame *frame_to_translate, *inner_head; - struct ast_frame missed = { - .frametype = AST_FRAME_VOICE, - .subclass.format = f->subclass.format, - .datalen = 0, - /* In RTP, the amount of samples might change anytime */ - /* If that happened while frames got lost, what to do? */ - .samples = f->samples, /* FIXME */ - .src = __FUNCTION__, - .data.uint32 = 0, - .delivery.tv_sec = 0, - .delivery.tv_usec = 0, - .flags = 0, - /* RTP sequence number is between 0x0001 and 0xffff */ - .seqno = (rtp_seqno_max_value + 1 + f->seqno - frames_missing) & rtp_seqno_max_value, - }; - - if (frames_missing) { - frame_to_translate = &missed; - } else { - frame_to_translate = f; - } - - /* The translation path from one format to another might contain several steps */ - /* out* collects the result for missed frame(s) and input frame(s) */ - /* out is the result of the conversion of all frames, translated into the destination format */ - /* out_last is the last frame in that list, to add frames faster */ - for (step = path, inner_head = frame_to_translate; inner_head && step; step = step->next) { - struct ast_frame *current, *inner_last, *inner_prev = frame_to_translate; - - /* inner* collects the result of each conversion step, the input for the next step */ - /* inner_head is a list of frames created by each conversion step */ - /* inner_last is the last frame in that list, to add frames faster */ - for (inner_last = NULL, current = inner_head; current; current = AST_LIST_NEXT(current, frame_list)) { - struct ast_frame *tmp; - - framein(step, current); - tmp = step->t->frameout(step); - - if (!tmp) { - continue; - } else if (inner_last) { - struct ast_frame *t; - - /* Determine the last frame of the list before appending to it */ - while ((t = AST_LIST_NEXT(inner_last, frame_list))) { - inner_last = t; - } - AST_LIST_NEXT(inner_last, frame_list) = tmp; - } else { - inner_prev = inner_head; - inner_head = tmp; - inner_last = tmp; - } - } - - /* The current step did not create any frames = no frames for the next step */ - /* The steps are not lost because framein buffered those for the next input frame */ - if (!inner_last) { - inner_prev = inner_head; - inner_head = NULL; - } - if (inner_prev != frame_to_translate) { - ast_frfree(inner_prev); /* Frees just the intermediate lists */ - } - } - - /* This frame created no frames after translation = continue with next frame */ - /* The frame is not lost because framein buffered it to be combined with the next frame */ - if (!inner_head) { - continue; - } else if (out_last) { - struct ast_frame *t; - - /* Determine the last frame of the list before appending to it */ - while ((t = AST_LIST_NEXT(out_last, frame_list))) { - out_last = t; - } - AST_LIST_NEXT(out_last, frame_list) = inner_head; - } else { - out = inner_head; - out_last = inner_head; + for (out = f; out && p ; p = p->next) { + struct ast_frame *current = out; + + do { + framein(p, current); + current = AST_LIST_NEXT(current, frame_list); + } while (current); + if (out != f) { + ast_frfree(out); } + out = p->t->frameout(p); } - if (out) { /* we have a frame, play with times */ if (!ast_tvzero(delivery)) { From 5fb848eebd7b397c9fddfa035349abb9c4de05e1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 3 Oct 2016 10:30:43 -0600 Subject: [PATCH 0783/1578] bundled_pjproject: Add tests for programs used by the Makefile, et al. Added tests for bzip2, tar, patch, sed and nm to configure.ac. Set DOWNLOAD_TO_STDOUT to a working command line regardless of whether the download program is wget, curl or fetch. Added a 'configure.m4' file to the third-party directory which takes care of calling any third-party project setup. Had to move some pjproject_bundled stuff up in configure.ac so it was called before the third-party configure macro. The pjproject tarball is now downloaded to the externals_cache_dir if it was specified on the ./configure command line Removed regeneration of the pjproject aconfigure file. It was only needed for an old patch that no longer applies. Converted the tests for symbols to explicit tests since we know that they're now available in the bundled version. Saves a little time during configure. ASTERISK-26416 #close Reported-by: Corey Farrell Change-Id: Id1d94251c0155f8dd41b7de7067f35cfbaafbb9b (cherry picked from commit e6b0053d7561032b7adbf6f3afaecf30f5046605) (cherry picked from commit a0d02f38322c2c4d7743504003fd376d32a133db) --- Makefile | 4 + configure | 629 +++++++++++++++------------- configure.ac | 51 +-- include/asterisk/autoconfig.h.in | 19 +- makeopts.in | 5 + third-party/Makefile.rules | 17 +- third-party/configure.m4 | 7 + third-party/pjproject/Makefile | 47 +-- third-party/pjproject/apply_patches | 6 +- third-party/pjproject/configure.m4 | 86 ++-- 10 files changed, 481 insertions(+), 390 deletions(-) create mode 100644 third-party/configure.m4 diff --git a/Makefile b/Makefile index 992e1d3019a..8e237e1fda7 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,10 @@ export WGET_EXTRA_ARGS export LDCONFIG export LDCONFIG_FLAGS export PYTHON +export TAR +export PATCH +export SED +export NM # makeopts is required unless the goal is clean or distclean ifeq ($(findstring clean,$(MAKECMDGOALS)),) diff --git a/configure b/configure index a5da739c045..37a8751eb25 100755 --- a/configure +++ b/configure @@ -977,11 +977,6 @@ PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB -PJPROJECT_BUNDLED -PBX_PJPROJECT -PJPROJECT_DIR -PJPROJECT_INCLUDE -PJPROJECT_LIB PBX_PGSQL PGSQL_DIR PGSQL_INCLUDE @@ -1198,6 +1193,11 @@ PBX_ALSA ALSA_DIR ALSA_INCLUDE ALSA_LIB +PJPROJECT_INCLUDE +PJPROJECT_LIB +PBX_PJPROJECT +PJPROJECT_DIR +PJPROJECT_BUNDLED AST_C_COMPILER_FAMILY AST_CLANG_BLOCKS AST_CLANG_BLOCKS_LIBS @@ -1219,8 +1219,13 @@ PBX_BISON OPENSSL SHA1SUM LDCONFIG +DOWNLOAD_TO_STDOUT DOWNLOAD FETCH +NM +PATCH +TAR +BZIP2 ALEMBIC GIT BASH @@ -1325,7 +1330,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1351,6 +1355,7 @@ enable_option_checking with_gnu_ld enable_dev_mode enable_coverage +with_pjproject_bundled with_asound with_bfd with_execinfo @@ -1402,7 +1407,6 @@ with_osptk with_oss with_postgres with_pjproject -with_pjproject_bundled with_popt with_portaudio with_pri @@ -1507,7 +1511,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1760,15 +1763,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1906,7 +1900,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2059,7 +2053,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -2105,6 +2098,8 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-pjproject-bundled + Use bundled pjproject libraries --with-asound=PATH use Advanced Linux Sound Architecture files in PATH --with-bfd=PATH use Debug symbol decoding files in PATH --with-execinfo=PATH use Stack Backtrace files in PATH @@ -2160,8 +2155,6 @@ Optional Packages: --with-oss=PATH use Open Sound System files in PATH --with-postgres=PATH use PostgreSQL files in PATH --with-pjproject=PATH use PJPROJECT files in PATH - --with-pjproject-bundled - Use bundled pjproject libraries --with-popt=PATH use popt files in PATH --with-portaudio=PATH use PortAudio files in PATH --with-pri=PATH use ISDN PRI files in PATH @@ -7646,10 +7639,218 @@ $as_echo "no" >&6; } fi +# Extract the first word of "bzip2", so it can be a program name with args. +set dummy bzip2; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BZIP2+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BZIP2 in + [\\/]* | ?:[\\/]*) + ac_cv_path_BZIP2="$BZIP2" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BZIP2="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_BZIP2" && ac_cv_path_BZIP2=":" + ;; +esac +fi +BZIP2=$ac_cv_path_BZIP2 +if test -n "$BZIP2"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BZIP2" >&5 +$as_echo "$BZIP2" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "tar", so it can be a program name with args. +set dummy tar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_TAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $TAR in + [\\/]* | ?:[\\/]*) + ac_cv_path_TAR="$TAR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_TAR="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_TAR" && ac_cv_path_TAR=":" + ;; +esac +fi +TAR=$ac_cv_path_TAR +if test -n "$TAR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TAR" >&5 +$as_echo "$TAR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "patch", so it can be a program name with args. +set dummy patch; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PATCH+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PATCH in + [\\/]* | ?:[\\/]*) + ac_cv_path_PATCH="$PATCH" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PATCH="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_PATCH" && ac_cv_path_PATCH=":" + ;; +esac +fi +PATCH=$ac_cv_path_PATCH +if test -n "$PATCH"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5 +$as_echo "$PATCH" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "sed", so it can be a program name with args. +set dummy sed; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $SED in + [\\/]* | ?:[\\/]*) + ac_cv_path_SED="$SED" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_SED" && ac_cv_path_SED=":" + ;; +esac +fi +SED=$ac_cv_path_SED +if test -n "$SED"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 +$as_echo "$SED" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "nm", so it can be a program name with args. +set dummy nm; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $NM in + [\\/]* | ?:[\\/]*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_NM="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_NM" && ac_cv_path_NM=":" + ;; +esac +fi +NM=$ac_cv_path_NM +if test -n "$NM"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NM" >&5 +$as_echo "$NM" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} + DOWNLOAD_TO_STDOUT="${WGET} -O-" else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" + DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\"" else # Extract the first word of "fetch", so it can be a program name with args. set dummy fetch; ac_word=$2 @@ -7693,9 +7894,12 @@ fi DOWNLOAD=${FETCH} + DOWNLOAD_TO_STDOUT="${FETCH} -o-" fi fi + + # Extract the first word of "ldconfig", so it can be a program name with args. set dummy ldconfig; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -8921,6 +9125,118 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$save_CFLAGS" +PJPROJECT_BUNDLED=no + + + +# Check whether --with-pjproject-bundled was given. +if test "${with_pjproject_bundled+set}" = set; then : + withval=$with_pjproject_bundled; case "${enableval}" in + n|no) PJPROJECT_BUNDLED=no ;; + *) PJPROJECT_BUNDLED=yes ;; + esac +fi + + + + + if test "$PJPROJECT_BUNDLED" = "yes" ; then + + if test "${ac_mandatory_list#*PJPROJECT*}" != "$ac_mandatory_list" ; then + as_fn_error $? "--with-pjproject and --with-pjproject-bundled can't both be specified" "$LINENO" 5 + fi + + ac_mandatory_list="$ac_mandatory_list PJPROJECT" + PJPROJECT_DIR="${ac_top_build_prefix}third-party/pjproject" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for embedded pjproject (may have to download)" >&5 +$as_echo_n "checking for embedded pjproject (may have to download)... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: configuring" >&5 +$as_echo "configuring" >&6; } + + if test "x${DOWNLOAD_TO_STDOUT}" = "x" ; then + as_fn_error $? "A download utility (wget, curl or fetch) is required to download bundled pjproject" "$LINENO" 5 + fi + if test "${BZIP2}" = ":" ; then + as_fn_error $? "bzip2 is required to extract the pjproject tar file" "$LINENO" 5 + fi + if test "${TAR}" = ":" ; then + as_fn_error $? "tar is required to extract the pjproject tar file" "$LINENO" 5 + fi + if test "${PATCH}" = ":" ; then + as_fn_error $? "patch is required to configure bundled pjproject" "$LINENO" 5 + fi + if test "${SED}" = ":" ; then + as_fn_error $? "sed is required to configure bundled pjproject" "$LINENO" 5 + fi + if test "${NM}" = ":" ; then + as_fn_error $? "nm is required to build bundled pjproject" "$LINENO" 5 + fi + + export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT + ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} configure + if test $? -ne 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: Unable to configure ${PJPROJECT_DIR}" >&5 +$as_echo "$as_me: Unable to configure ${PJPROJECT_DIR}" >&6;} + as_fn_error $? "Run \"${GNU_MAKE} -C ${PJPROJECT_DIR} NOISY_BUILD=yes configure\" to see error details." "$LINENO" 5 + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for bundled pjproject" >&5 +$as_echo_n "checking for bundled pjproject... " >&6; } + + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} echo_cflags) + PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" + PBX_PJPROJECT=1 + + +$as_echo "#define HAVE_PJPROJECT 1" >>confdefs.h + + +$as_echo "#define HAVE_PJPROJECT_BUNDLED 1" >>confdefs.h + + + +$as_echo "#define HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK 1" >>confdefs.h + + +$as_echo "#define HAVE_PJ_TRANSACTION_GRP_LOCK 1" >>confdefs.h + + +$as_echo "#define HAVE_PJSIP_REPLACE_MEDIA_STREAM 1" >>confdefs.h + + +$as_echo "#define HAVE_PJSIP_GET_DEST_INFO 1" >>confdefs.h + + +$as_echo "#define HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 1" >>confdefs.h + + +$as_echo "#define HAVE_PJSIP_EXTERNAL_RESOLVER 1" >>confdefs.h + + +$as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h + + +$as_echo "#define HAVE_PJSIP_EVSUB_GRP_LOCK 1" >>confdefs.h + + +$as_echo "#define HAVE_PJSIP_INV_SESSION_REF 1" >>confdefs.h + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + fi + + + # AST_EXT_LIB_SETUP is used to tell configure to handle variables for # various packages. # $1 is the prefix for the variables in makeopts and autoconfig.h @@ -10938,6 +11254,7 @@ fi +if test "x${PBX_PJPROJECT}" != "x1" ; then PJPROJECT_DESCRIP="PJPROJECT" PJPROJECT_OPTION="pjproject" @@ -10970,29 +11287,6 @@ fi -PJPROJECT_BUNDLED=no - - - -# Check whether --with-pjproject-bundled was given. -if test "${with_pjproject_bundled+set}" = set; then : - withval=$with_pjproject_bundled; case "${enableval}" in - n|no) PJPROJECT_BUNDLED=no ;; - *) PJPROJECT_BUNDLED=yes ;; - esac -fi - - - -if test "$PJPROJECT_BUNDLED" = "yes" -a "${ac_mandatory_list#*PJPROJECT*}" != "$ac_mandatory_list" ; then - as_fn_error $? "--with-pjproject and --with-pjproject-bundled can't both be specified" "$LINENO" 5 -fi - -if test "$PJPROJECT_BUNDLED" = "yes" ; then - ac_mandatory_list="$ac_mandatory_list PJPROJECT" - PJPROJECT_DIR="${ac_top_build_prefix}third-party/pjproject" -fi - PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DESCRIP="PJSIP Dialog Create UAS with Incremented Lock" PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_OPTION=pjsip @@ -11101,6 +11395,7 @@ PBX_PJSIP_INV_SESSION_REF=0 +fi POPT_DESCRIP="popt" @@ -25153,251 +25448,7 @@ $as_echo "$as_me: *** including --without-postgres" >&6;} fi if test "$USE_PJPROJECT" != "no" ; then - if test "$PJPROJECT_BUNDLED" = "yes" ; then - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for embedded pjproject (may have to download)" >&5 -$as_echo_n "checking for embedded pjproject (may have to download)... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: configuring" >&5 -$as_echo "configuring" >&6; } - ${GNU_MAKE} --quiet --no-print-directory -C $PJPROJECT_DIR configure - if test $? -ne 0 ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -$as_echo "failed" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: Unable to configure $PJPROJECT_DIR" >&5 -$as_echo "$as_me: Unable to configure $PJPROJECT_DIR" >&6;} - as_fn_error $? "Run \"${GNU_MAKE} -C $PJPROJECT_DIR NOISY_BUILD=yes configure\" to see error details." "$LINENO" 5 - fi - - PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C $PJPROJECT_DIR echo_cflags) - PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" - PBX_PJPROJECT=1 - PJPROJECT_BUNDLED=yes - -$as_echo "#define HAVE_PJPROJECT 1" >>confdefs.h - - -$as_echo "#define HAVE_PJPROJECT_BUNDLED 1" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for embedded pjproject" >&5 -$as_echo_n "checking for embedded pjproject... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - - - PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE="$PJPROJECT_INCLUDE" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_dlg_create_uas_and_inc_lock declared in pjsip.h" >&5 -$as_echo_n "checking for pjsip_dlg_create_uas_and_inc_lock declared in pjsip.h... " >&6; } - - saved_cpp="$CPPFLAGS" - CPPFLAGS="$PJPROJECT_INCLUDE" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "pjsip_dlg_create_uas_and_inc_lock" >/dev/null 2>&1; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK=1 - -$as_echo "#define HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK 1" >>confdefs.h - - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f conftest* - - - CPPGLAGS="$saved_cpp" - PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE="$PJPROJECT_INCLUDE" - - - PJ_TRANSACTION_GRP_LOCK_INCLUDE="$PJPROJECT_INCLUDE" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_tsx_create_uac2 declared in pjsip.h" >&5 -$as_echo_n "checking for pjsip_tsx_create_uac2 declared in pjsip.h... " >&6; } - - saved_cpp="$CPPFLAGS" - CPPFLAGS="$PJPROJECT_INCLUDE" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "pjsip_tsx_create_uac2" >/dev/null 2>&1; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_PJ_TRANSACTION_GRP_LOCK=1 - -$as_echo "#define HAVE_PJ_TRANSACTION_GRP_LOCK 1" >>confdefs.h - - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f conftest* - - - CPPGLAGS="$saved_cpp" - PJ_TRANSACTION_GRP_LOCK_INCLUDE="$PJPROJECT_INCLUDE" - - - PJSIP_REPLACE_MEDIA_STREAM_INCLUDE="$PJPROJECT_INCLUDE" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE declared in pjmedia.h" >&5 -$as_echo_n "checking for PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE declared in pjmedia.h... " >&6; } - - saved_cpp="$CPPFLAGS" - CPPFLAGS="$PJPROJECT_INCLUDE" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE" >/dev/null 2>&1; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_PJSIP_REPLACE_MEDIA_STREAM=1 - -$as_echo "#define HAVE_PJSIP_REPLACE_MEDIA_STREAM 1" >>confdefs.h - - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f conftest* - - - CPPGLAGS="$saved_cpp" - PJSIP_REPLACE_MEDIA_STREAM_INCLUDE="$PJPROJECT_INCLUDE" - - - PJSIP_GET_DEST_INFO_INCLUDE="$PJPROJECT_INCLUDE" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_get_dest_info declared in pjsip.h" >&5 -$as_echo_n "checking for pjsip_get_dest_info declared in pjsip.h... " >&6; } - - saved_cpp="$CPPFLAGS" - CPPFLAGS="$PJPROJECT_INCLUDE" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "pjsip_get_dest_info" >/dev/null 2>&1; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_PJSIP_GET_DEST_INFO=1 - -$as_echo "#define HAVE_PJSIP_GET_DEST_INFO 1" >>confdefs.h - - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f conftest* - - - CPPGLAGS="$saved_cpp" - PJSIP_GET_DEST_INFO_INCLUDE="$PJPROJECT_INCLUDE" - - - PJ_SSL_CERT_LOAD_FROM_FILES2_INCLUDE="$PJPROJECT_INCLUDE" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pj_ssl_cert_load_from_files2 declared in pjlib.h" >&5 -$as_echo_n "checking for pj_ssl_cert_load_from_files2 declared in pjlib.h... " >&6; } - - saved_cpp="$CPPFLAGS" - CPPFLAGS="$PJPROJECT_INCLUDE" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "pj_ssl_cert_load_from_files2" >/dev/null 2>&1; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_PJ_SSL_CERT_LOAD_FROM_FILES2=1 - -$as_echo "#define HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 1" >>confdefs.h - - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f conftest* - - - CPPGLAGS="$saved_cpp" - PJ_SSL_CERT_LOAD_FROM_FILES2_INCLUDE="$PJPROJECT_INCLUDE" - - - PJSIP_EXTERNAL_RESOLVER_INCLUDE="$PJPROJECT_INCLUDE" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pjsip_endpt_set_ext_resolver declared in pjsip.h" >&5 -$as_echo_n "checking for pjsip_endpt_set_ext_resolver declared in pjsip.h... " >&6; } - - saved_cpp="$CPPFLAGS" - CPPFLAGS="$PJPROJECT_INCLUDE" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "pjsip_endpt_set_ext_resolver" >/dev/null 2>&1; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_PJSIP_EXTERNAL_RESOLVER=1 - -$as_echo "#define HAVE_PJSIP_EXTERNAL_RESOLVER 1" >>confdefs.h - - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f conftest* - - - CPPGLAGS="$saved_cpp" - PJSIP_EXTERNAL_RESOLVER_INCLUDE="$PJPROJECT_INCLUDE" - - -$as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h - - -$as_echo "#define HAVE_PJSIP_EVSUB_GRP_LOCK 1" >>confdefs.h - - -$as_echo "#define HAVE_PJSIP_INV_SESSION_REF 1" >>confdefs.h - - - else + if test "$PJPROJECT_BUNDLED" = "no" ; then if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then diff --git a/configure.ac b/configure.ac index 17b887266fe..cdc6487c235 100644 --- a/configure.ac +++ b/configure.ac @@ -284,16 +284,27 @@ AC_PATH_PROG([XMLSTARLET], [xmlstarlet], :) AC_PATH_PROG([BASH], [bash], :) AC_PATH_PROG([GIT], [git], :) AC_PATH_PROG([ALEMBIC], [alembic], :) +AC_PATH_PROG([BZIP2], [bzip2], :) +AC_PATH_PROG([TAR], [tar], :) +AC_PATH_PROG([PATCH], [patch], :) +AC_PATH_PROG([SED], [sed], :) +AC_PATH_PROG([NM], [nm], :) + if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} + DOWNLOAD_TO_STDOUT="${WGET} -O-" else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" + DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\"" else AC_PATH_PROG([FETCH], [fetch], [:]) DOWNLOAD=${FETCH} + DOWNLOAD_TO_STDOUT="${FETCH} -o-" fi fi + AC_SUBST(DOWNLOAD) +AC_SUBST(DOWNLOAD_TO_STDOUT) AC_PATH_PROG([LDCONFIG], [ldconfig], :) AC_PATH_PROG([SHA1SUM], [sha1sum], $ac_aux_dir/build_tools/sha1sum-sh) AC_PATH_PROG([OPENSSL], [openssl], :) @@ -404,6 +415,19 @@ AC_SUBST(AST_CODE_COVERAGE) AST_CHECK_RAII() AST_CHECK_STRSEP_ARRAY_BOUNDS() +PJPROJECT_BUNDLED=no +AH_TEMPLATE(m4_bpatsubst([[HAVE_PJPROJECT_BUNDLED]], [(.*)]), [Define to 1 when using the bundled pjproject.]) + +AC_ARG_WITH([pjproject-bundled], + [AS_HELP_STRING([--with-pjproject-bundled], + [Use bundled pjproject libraries])], + [case "${enableval}" in + n|no) PJPROJECT_BUNDLED=no ;; + *) PJPROJECT_BUNDLED=yes ;; + esac]) + +THIRD_PARTY_CONFIGURE() + # AST_EXT_LIB_SETUP is used to tell configure to handle variables for # various packages. # $1 is the prefix for the variables in makeopts and autoconfig.h @@ -472,28 +496,8 @@ AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk]) AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss]) AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres]) +if test "x${PBX_PJPROJECT}" != "x1" ; then AST_EXT_LIB_SETUP([PJPROJECT], [PJPROJECT], [pjproject]) -PJPROJECT_BUNDLED=no -AH_TEMPLATE(m4_bpatsubst([[HAVE_PJPROJECT_BUNDLED]], [(.*)]), [Define to 1 when using the bundled pjproject.]) - -AC_ARG_WITH([pjproject-bundled], - [AS_HELP_STRING([--with-pjproject-bundled], - [Use bundled pjproject libraries])], - [case "${enableval}" in - n|no) PJPROJECT_BUNDLED=no ;; - *) PJPROJECT_BUNDLED=yes ;; - esac]) -AC_SUBST(PJPROJECT_BUNDLED) - -if test "$PJPROJECT_BUNDLED" = "yes" -a "${ac_mandatory_list#*PJPROJECT*}" != "$ac_mandatory_list" ; then - AC_MSG_ERROR(--with-pjproject and --with-pjproject-bundled can't both be specified) -fi - -if test "$PJPROJECT_BUNDLED" = "yes" ; then - ac_mandatory_list="$ac_mandatory_list PJPROJECT" - PJPROJECT_DIR="${ac_top_build_prefix}third-party/pjproject" -fi - AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [PJSIP Dialog Create UAS with Incremented Lock], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJ_TRANSACTION_GRP_LOCK], [PJSIP Transaction Group Lock Support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_REPLACE_MEDIA_STREAM], [PJSIP Media Stream Replacement Support], [PJPROJECT], [pjsip]) @@ -503,6 +507,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EXTERNAL_RESOLVER], [PJSIP External Resolver S AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_PROTO], [PJSIP TLS Transport proto field support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_GRP_LOCK], [PJSIP EVSUB Group Lock support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_SESSION_REF], [PJSIP INVITE Session Reference Count support], [PJPROJECT], [pjsip]) +fi AST_EXT_LIB_SETUP([POPT], [popt], [popt]) AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio]) @@ -2198,9 +2203,7 @@ if test "${PG_CONFIG}" != No; then fi if test "$USE_PJPROJECT" != "no" ; then - if test "$PJPROJECT_BUNDLED" = "yes" ; then - PJPROJECT_CONFIGURE([$PJPROJECT_DIR]) - else + if test "$PJPROJECT_BUNDLED" = "no" ; then AST_PKG_CONFIG_CHECK([PJPROJECT], [libpjproject]) AST_EXT_LIB_CHECK([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [pjsip], [pjsip_dlg_create_uas_and_inc_lock], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS]) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index e16b6686153..7a11ba3e476 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -586,19 +586,22 @@ /* Define if your system has PJPROJECT_BUNDLED */ #undef HAVE_PJPROJECT_BUNDLED -/* Define if your system has pjsip_dlg_create_uas_and_inc_lock declared. */ +/* Define to 1 if PJPROJECT has the PJSIP Dialog Create UAS with Incremented + Lock feature. */ #undef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK -/* Define if your system has PJSIP_EVSUB_GRP_LOCK */ +/* Define to 1 if PJPROJECT has the PJSIP EVSUB Group Lock support feature. */ #undef HAVE_PJSIP_EVSUB_GRP_LOCK -/* Define if your system has pjsip_endpt_set_ext_resolver declared. */ +/* Define to 1 if PJPROJECT has the PJSIP External Resolver Support feature. + */ #undef HAVE_PJSIP_EXTERNAL_RESOLVER -/* Define if your system has pjsip_get_dest_info declared. */ +/* Define to 1 if PJPROJECT has the pjsip_get_dest_info support feature. */ #undef HAVE_PJSIP_GET_DEST_INFO -/* Define if your system has PJSIP_INV_SESSION_REF */ +/* Define to 1 if PJPROJECT has the PJSIP INVITE Session Reference Count + support feature. */ #undef HAVE_PJSIP_INV_SESSION_REF /* Define if your system has the PJSIP_REPLACE_MEDIA_STREAM headers. */ @@ -607,10 +610,12 @@ /* Define if your system has the PJSIP_TLS_TRANSPORT_PROTO headers. */ #undef HAVE_PJSIP_TLS_TRANSPORT_PROTO -/* Define if your system has pj_ssl_cert_load_from_files2 declared. */ +/* Define to 1 if PJPROJECT has the pj_ssl_cert_load_from_files2 support + feature. */ #undef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 -/* Define if your system has pjsip_tsx_create_uac2 declared. */ +/* Define to 1 if PJPROJECT has the PJSIP Transaction Group Lock Support + feature. */ #undef HAVE_PJ_TRANSACTION_GRP_LOCK /* Define to 1 if your system defines IP_PKTINFO. */ diff --git a/makeopts.in b/makeopts.in index b2b394b5f14..a826d882b7d 100644 --- a/makeopts.in +++ b/makeopts.in @@ -27,6 +27,7 @@ STRIP=@STRIP@ WGET=@WGET@ FETCH=@FETCH@ DOWNLOAD=@DOWNLOAD@ +DOWNLOAD_TO_STDOUT=@DOWNLOAD_TO_STDOUT@ SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@ EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@ RUBBER=@RUBBER@ @@ -41,6 +42,10 @@ OPENSSL=@OPENSSL@ LDCONFIG=@LDCONFIG@ GIT=@GIT@ ALEMBIC=@ALEMBIC@ +TAR=@TAR@ +PATCH=@PATCH@ +SED=@SED@ +NM=@NM@ BUILD_PLATFORM=@BUILD_PLATFORM@ BUILD_CPU=@BUILD_CPU@ diff --git a/third-party/Makefile.rules b/third-party/Makefile.rules index 92e4ebc859e..4f804dd0e3c 100644 --- a/third-party/Makefile.rules +++ b/third-party/Makefile.rules @@ -13,18 +13,6 @@ QUIET_CONFIGURE= REALLY_QUIET= endif -DOWNLOAD := $(shell which wget 2>/dev/null) -DOWNLOAD := $(if $(DOWNLOAD),$(DOWNLOAD) -O- ,) - -ifeq ($(DOWNLOAD),) -DOWNLOAD := $(shell which curl 2>/dev/null) -DOWNLOAD := $(if $(DOWNLOAD), $(DOWNLOAD) -L ,) -endif - -ifeq ($(DOWNLOAD),) -DOWNLOAD := echo "No download program available" ; exit 1; -endif - export SUBMAKE export ECHO_PREFIX export CMD_PREFIX @@ -34,3 +22,8 @@ export ASTTOPDIR export ASTSBINDIR export DESTDIR export ASTDATADIR +export TAR +export PATCH +export SED +export NM +export DOWNLOAD diff --git a/third-party/configure.m4 b/third-party/configure.m4 new file mode 100644 index 00000000000..63544663897 --- /dev/null +++ b/third-party/configure.m4 @@ -0,0 +1,7 @@ + + +AC_DEFUN([THIRD_PARTY_CONFIGURE], +[ + PJPROJECT_CONFIGURE() +]) + diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index bb98a09e311..3fd3be73556 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -7,8 +7,6 @@ SPECIAL_TARGETS := ifneq ($(findstring configure,$(MAKECMDGOALS))$(findstring echo_cflags,$(MAKECMDGOALS)),) # Run from $(ASTTOPDIR)/configure SPECIAL_TARGETS += configure - include ../Makefile.rules - include Makefile.rules endif ifeq ($(findstring echo_cflags,$(MAKECMDGOALS)),echo_cflags) @@ -19,8 +17,10 @@ endif ifeq ($(findstring clean,$(MAKECMDGOALS)),clean) # clean or distclean SPECIAL_TARGETS += clean - include ../Makefile.rules - include Makefile.rules +endif + +ifneq ($(wildcard ../../makeopts),) + include ../../makeopts endif ifeq ($(SPECIAL_TARGETS),) @@ -28,17 +28,17 @@ ifeq ($(SPECIAL_TARGETS),) ifeq ($(wildcard ../../makeopts),) $(error ASTTOPDIR/configure hasn't been run) endif - include ../../makeopts ifeq ($(PJPROJECT_BUNDLED),yes) - -include ../../menuselect.makeopts - include ../Makefile.rules + ifneq ($(wildcard ../../menuselect.makeopts),) + include ../../menuselect.makeopts + else + $(warning ASTTOPDIR/menuselect hasn't been run yet. Can't find debug options.) + endif all: _all install: _install - include ../../Makefile.rules - include Makefile.rules include source/user.mak include source/build.mak CF := $(filter-out -W%,$(CC_CFLAGS)) @@ -66,25 +66,25 @@ ifeq ($(SPECIAL_TARGETS),) endif endif +include ../../Makefile.rules +include ../Makefile.rules +include Makefile.rules + ECHO_PREFIX := $(ECHO_PREFIX) echo '[pjproject] ' -ifndef $(TMPDIR) - ifneq ($(wildcard /tmp),) - TMPDIR=/tmp - else - TMPDIR=. - endif -endif +_all: $(TARGETS) + +TMPDIR ?= $(or $(EXTERNALS_CACHE_DIR),$(wildcard /tmp),.) $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 : ../versions.mak - $(ECHO_PREFIX) Downloading $@ with $(DOWNLOAD) - $(CMD_PREFIX) $(DOWNLOAD) $(PJPROJECT_URL)/$(@F) > $@ + $(ECHO_PREFIX) Downloading $(PJPROJECT_URL)/$(@F) to $@ + $(CMD_PREFIX) $(DOWNLOAD_TO_STDOUT) $(PJPROJECT_URL)/$(@F) > $@ source/.unpacked: $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 $(ECHO_PREFIX) Unpacking $< -@rm -rf source >/dev/null 2>&1 -@mkdir source >/dev/null 2>&1 - $(CMD_PREFIX) tar --strip-components=1 -C source -xjf $< + $(CMD_PREFIX) $(TAR) --strip-components=1 -C source -xjf $< $(ECHO_PREFIX) Applying patches $(CMD_PREFIX) ./apply_patches $(QUIET_CONFIGURE) ./patches ./source -@touch source/.unpacked @@ -99,8 +99,8 @@ source/pjlib/include/pj/%.h : ./patches/%.h build.mak: source/.unpacked $(addprefix source/pjlib/include/pj/,$(notdir $(wildcard ./patches/*.h))) source/user.mak Makefile.rules $(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS) - $(CMD_PREFIX) (cd source ; autoconf aconfigure.ac > aconfigure && ./aconfigure $(QUIET_CONFIGURE) $(PJPROJECT_CONFIG_OPTS)) - @sed -r -e "/prefix|export PJ_SHARED_LIBRARIES|MACHINE_NAME|OS_NAME|HOST_NAME|CC_NAME|CROSS_COMPILE|LINUX_POLL/d" source/build.mak > build.mak + $(CMD_PREFIX) (cd source ; ./aconfigure $(QUIET_CONFIGURE) $(PJPROJECT_CONFIG_OPTS)) + $(SED) -r -e "/prefix|export PJ_SHARED_LIBRARIES|MACHINE_NAME|OS_NAME|HOST_NAME|CC_NAME|CROSS_COMPILE|LINUX_POLL/d" source/build.mak > build.mak configure: build.mak @@ -128,7 +128,7 @@ $(LIB_FILES): $(PJLIB_UTIL_LIB_FILES) pjproject.symbols: $(ALL_LIB_FILES) $(ECHO_PREFIX) Generating symbols - $(CMD_PREFIX) nm -Pog $(ALL_LIB_FILES) | sed -n -r -e "s/.+: ([pP][jJ][^ ]+) .+/\1/gp" | sort -u > pjproject.symbols + $(CMD_PREFIX) $(NM) -Pog $(PJ_LIB_FILES) | $(SED) -n -r -e "s/.+: ([pP][jJ][^ ]+) .+/\1/gp" | sort -u > pjproject.symbols source/pjsip-apps/src/asterisk_malloc_debug.c: patches/asterisk_malloc_debug.c $(ECHO_PREFIX) Copying $< to $@ @@ -155,8 +155,6 @@ source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/src/python/_pjsua.o $(ECHO_PREFIX) Linking python bindings $(@F) $(CMD_PREFIX) gcc -shared -pthread -o $@ $< $(LDFLAGS) $(PJ_LDFLAGS) $(APP_LDLIBS) $(PYTHONDEV_LIB) $(REALLY_QUIET) -_all: $(TARGETS) - _install: _all @if [ ! -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject" ]; then \ $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject"; \ @@ -188,4 +186,3 @@ clean: distclean: $(ECHO_PREFIX) Distcleaning -$(CMD_PREFIX) rm -rf source pjproject.symbols pjproject-*.tar.bz2 build.mak .rebuild_needed - diff --git a/third-party/pjproject/apply_patches b/third-party/pjproject/apply_patches index 5dfdd2a3c86..c28f403019a 100755 --- a/third-party/pjproject/apply_patches +++ b/third-party/pjproject/apply_patches @@ -5,6 +5,8 @@ if [ "$1" = "-q" ] ; then shift fi +PATCH=${PATCH:-patch} + patchdir=${1:?You must supply a patches directory} sourcedir=${2?:You must supply a source directory} @@ -27,12 +29,12 @@ if [ ! "$(ls -A $patchdir/*.patch 2>/dev/null)" ] ; then fi for patchfile in $patchdir/*.patch ; do - patch -d $sourcedir -p1 -s -r- -f -N --dry-run -i "$patchfile" || (echo "Patchfile $(basename $patchfile) failed to apply" >&2 ; exit 1) || exit 1 + ${PATCH} -d $sourcedir -p1 -s -r- -f -N --dry-run -i "$patchfile" || (echo "Patchfile $(basename $patchfile) failed to apply" >&2 ; exit 1) || exit 1 done for patchfile in "$patchdir"/*.patch ; do [ -z $quiet ] && echo "Applying patch $(basename $patchfile)" - patch -d "$sourcedir" -p1 -s -i "$patchfile" || exit 1 + ${PATCH} -d "$sourcedir" -p1 -s -i "$patchfile" || exit 1 done exit 0 diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 7a079f6577f..386035bace9 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -1,49 +1,73 @@ -AC_DEFUN([PJPROJECT_SYMBOL_CHECK], +AC_DEFUN([_PJPROJECT_CONFIGURE], [ - $1_INCLUDE="$PJPROJECT_INCLUDE" - AC_MSG_CHECKING([for $2 declared in $3]) - - saved_cpp="$CPPFLAGS" - CPPFLAGS="$PJPROJECT_INCLUDE" - AC_EGREP_HEADER($2, $3, [ - AC_MSG_RESULT(yes) - PBX_$1=1 - AC_DEFINE([HAVE_$1], 1, [Define if your system has $2 declared.]) - ], [ - AC_MSG_RESULT(no) - ]) + if test "${ac_mandatory_list#*PJPROJECT*}" != "$ac_mandatory_list" ; then + AC_MSG_ERROR(--with-pjproject and --with-pjproject-bundled can't both be specified) + fi - CPPGLAGS="$saved_cpp" - $1_INCLUDE="$PJPROJECT_INCLUDE" -]) + ac_mandatory_list="$ac_mandatory_list PJPROJECT" + PJPROJECT_DIR="${ac_top_build_prefix}third-party/pjproject" -AC_DEFUN([PJPROJECT_CONFIGURE], -[ AC_MSG_CHECKING(for embedded pjproject (may have to download)) AC_MSG_RESULT(configuring) - ${GNU_MAKE} --quiet --no-print-directory -C $1 configure + + if test "x${DOWNLOAD_TO_STDOUT}" = "x" ; then + AC_MSG_ERROR(A download utility (wget, curl or fetch) is required to download bundled pjproject) + fi + if test "${BZIP2}" = ":" ; then + AC_MSG_ERROR(bzip2 is required to extract the pjproject tar file) + fi + if test "${TAR}" = ":" ; then + AC_MSG_ERROR(tar is required to extract the pjproject tar file) + fi + if test "${PATCH}" = ":" ; then + AC_MSG_ERROR(patch is required to configure bundled pjproject) + fi + if test "${SED}" = ":" ; then + AC_MSG_ERROR(sed is required to configure bundled pjproject) + fi + if test "${NM}" = ":" ; then + AC_MSG_ERROR(nm is required to build bundled pjproject) + fi + + export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT + ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} configure if test $? -ne 0 ; then AC_MSG_RESULT(failed) - AC_MSG_NOTICE(Unable to configure $1) - AC_MSG_ERROR(Run "${GNU_MAKE} -C $1 NOISY_BUILD=yes configure" to see error details.) + AC_MSG_NOTICE(Unable to configure ${PJPROJECT_DIR}) + AC_MSG_ERROR(Run "${GNU_MAKE} -C ${PJPROJECT_DIR} NOISY_BUILD=yes configure" to see error details.) fi - PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C $1 echo_cflags) + AC_MSG_CHECKING(for bundled pjproject) + + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} echo_cflags) PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" PBX_PJPROJECT=1 - PJPROJECT_BUNDLED=yes + AC_DEFINE([HAVE_PJPROJECT], 1, [Define if your system has PJPROJECT]) AC_DEFINE([HAVE_PJPROJECT_BUNDLED], 1, [Define if your system has PJPROJECT_BUNDLED]) - AC_MSG_CHECKING(for embedded pjproject) - AC_MSG_RESULT(yes) - PJPROJECT_SYMBOL_CHECK([PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], [pjsip_dlg_create_uas_and_inc_lock], [pjsip.h]) - PJPROJECT_SYMBOL_CHECK([PJ_TRANSACTION_GRP_LOCK], [pjsip_tsx_create_uac2], [pjsip.h]) - PJPROJECT_SYMBOL_CHECK([PJSIP_REPLACE_MEDIA_STREAM], [PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE], [pjmedia.h]) - PJPROJECT_SYMBOL_CHECK([PJSIP_GET_DEST_INFO], [pjsip_get_dest_info], [pjsip.h]) - PJPROJECT_SYMBOL_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_from_files2], [pjlib.h]) - PJPROJECT_SYMBOL_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip_endpt_set_ext_resolver], [pjsip.h]) + AC_DEFINE([HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK], 1, [Define if your system has pjsip_dlg_create_uas_and_inc_lock declared.]) + AC_DEFINE([HAVE_PJ_TRANSACTION_GRP_LOCK], 1, [Define if your system has pjsip_tsx_create_uac2 declared.]) + AC_DEFINE([HAVE_PJSIP_REPLACE_MEDIA_STREAM], 1, [Define if your system has PJSIP_REPLACE_MEDIA_STREAM declared]) + AC_DEFINE([HAVE_PJSIP_GET_DEST_INFO], 1, [Define if your system has pjsip_get_dest_info declared.]) + AC_DEFINE([HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2], 1, [Define if your system has pj_ssl_cert_load_from_files2 declared.]) + AC_DEFINE([HAVE_PJSIP_EXTERNAL_RESOLVER], 1, [Define if your system has pjsip_endpt_set_ext_resolver declared.]) AC_DEFINE([HAVE_PJSIP_TLS_TRANSPORT_PROTO], 1, [Define if your system has PJSIP_TLS_TRANSPORT_PROTO]) AC_DEFINE([HAVE_PJSIP_EVSUB_GRP_LOCK], 1, [Define if your system has PJSIP_EVSUB_GRP_LOCK]) AC_DEFINE([HAVE_PJSIP_INV_SESSION_REF], 1, [Define if your system has PJSIP_INV_SESSION_REF]) + + AC_SUBST([PJPROJECT_BUNDLED]) + AC_SUBST([PJPROJECT_DIR]) + AC_SUBST([PBX_PJPROJECT]) + AC_SUBST([PJPROJECT_LIB]) + AC_SUBST([PJPROJECT_INCLUDE]) + AC_MSG_RESULT(yes) +]) + +AC_DEFUN([PJPROJECT_CONFIGURE], +[ + if test "$PJPROJECT_BUNDLED" = "yes" ; then + _PJPROJECT_CONFIGURE() + fi ]) + \ No newline at end of file From ca2f3e5b99c81ccfaae1a3269c2437d9e436c367 Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Sun, 9 Oct 2016 22:53:07 -0400 Subject: [PATCH 0784/1578] cel_odbc: Fix memory leak on module unload Change-Id: Ic7a1236eba2408090fdabb5f717b5fa455ead715 --- cel/cel_odbc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c index 3c0be04e848..a10aadae957 100644 --- a/cel/cel_odbc.c +++ b/cel/cel_odbc.c @@ -291,6 +291,7 @@ static int load_config(void) else ast_free(tableptr); } + ast_config_destroy(cfg); return res; } From 9f62feca6085ba7bf71bfafa953846d255603369 Mon Sep 17 00:00:00 2001 From: "Ludovic Gasc (GMLudo)" Date: Thu, 29 Sep 2016 19:45:39 +0200 Subject: [PATCH 0785/1578] res_calendar: Add support for fetching calendars when reloading We use a lot res_calendar, we are very happy with that, especially because you use libical, the almost alone opensource library that supports really ical format with all types of recurrency. Nevertheless, some features are missed for our business use cases. This first patch adds a new option in calendar.conf: fetch_again_at_reload. Be my guest for a better name. If it's true, when you'll launch "module reload res_calendar.so", Asterisk will download again the calendar. The business use case is that we have a WebUI with a scheduler planner, we know when the calendars are modified. For now, we need to define 1 minute of timeout to have a chance that our user doesn't wait too long between the modification and the real test. But it generates a lot of useless HTTP traffic. ASTERISK-26422 #close Change-Id: I384b02ebfa42b142bbbd5b7221458c7f4dee7077 --- configs/samples/calendar.conf.sample | 2 ++ include/asterisk/calendar.h | 1 + res/res_calendar.c | 5 ++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/configs/samples/calendar.conf.sample b/configs/samples/calendar.conf.sample index 82b8702f014..d87b3b2c4e6 100644 --- a/configs/samples/calendar.conf.sample +++ b/configs/samples/calendar.conf.sample @@ -6,6 +6,8 @@ ;refresh = 15 ; refresh calendar every n minutes ;timeframe = 60 ; number of minutes of calendar data to pull for each refresh period ; ; should always be >= refresh +;fetch_again_at_reload = no ; to reload the calendar content when the module is reloaded +; ; ; You can set up res_calendar to execute a call upon an upcoming busy status ; The following fields are available from the ${CALENDAR_EVENT()} dialplan function: diff --git a/include/asterisk/calendar.h b/include/asterisk/calendar.h index da4af01ef3d..e9dcd880949 100644 --- a/include/asterisk/calendar.h +++ b/include/asterisk/calendar.h @@ -129,6 +129,7 @@ struct ast_calendar { int autoreminder; /*!< If set, override any calendar_tech specific notification times and use this time (in mins) */ int notify_waittime; /*!< Maxiumum time to allow for a notification attempt */ int refresh; /*!< When to refresh the calendar events */ + int fetch_again_at_reload; /*!< To reload the calendar content when the module is reloaded */ int timeframe; /*!< Span (in mins) of calendar data to pull with each request */ pthread_t thread; /*!< The thread that the calendar is loaded/updated in */ ast_cond_t unload; diff --git a/res/res_calendar.c b/res/res_calendar.c index 6f6f711b3eb..029ecebd07b 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -436,6 +436,7 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c cal->refresh = 3600; cal->timeframe = 60; cal->notify_waittime = 30000; + cal->fetch_again_at_reload = 0; for (v = ast_variable_browse(cfg, cat); v; v = v->next) { if (!strcasecmp(v->name, "autoreminder")) { @@ -457,6 +458,8 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c ast_string_field_set(cal, notify_appdata, v->value); } else if (!strcasecmp(v->name, "refresh")) { cal->refresh = atoi(v->value); + } else if (!strcasecmp(v->name, "fetch_again_at_reload")) { + cal->fetch_again_at_reload = ast_true(v->value); } else if (!strcasecmp(v->name, "timeframe")) { cal->timeframe = atoi(v->value); } else if (!strcasecmp(v->name, "setvar")) { @@ -482,7 +485,7 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c } } - if (new_calendar) { + if (new_calendar || cal->fetch_again_at_reload) { cal->thread = AST_PTHREADT_NULL; ast_cond_init(&cal->unload, NULL); ao2_link(calendars, cal); From 3ab7fae96b610a69c0a4f7fa639c658810858e63 Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Mon, 10 Oct 2016 11:59:38 -0400 Subject: [PATCH 0786/1578] res_pjsip_config_wizard: Memory leak in module_unload Fixed a memory leak. It removes only the first element. Added a useful feature in vector.h to remove all items under the CMP through a callback function / macro. ASTERISK-26453 #close Change-Id: I84508353463456d2495678f125738e20052da950 --- include/asterisk/vector.h | 48 +++++++++++++++++++++++++++++++++++ res/res_pjsip_config_wizard.c | 4 +-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index be909127235..b4a8a2c113d 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -353,6 +353,30 @@ #define AST_VECTOR_REMOVE_ORDERED(vec, idx) \ AST_VECTOR_REMOVE(vec, idx, 1) +/*! + * \brief Remove all elements from a vector that matches the given comparison + * + * \param vec Vector to remove from. + * \param value Value to pass into comparator. + * \param cmp Comparator function/macros (called as \c cmp(elem, value)) + * \param cleanup How to cleanup a removed element macro/function. + * + * \return the number of deleted elements. + */ +#define AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(vec, value, cmp, cleanup) ({ \ + int count = 0; \ + size_t idx; \ + typeof(value) __value = (value); \ + for (idx = 0; idx < (vec)->current; ++idx) { \ + if (cmp((vec)->elems[idx], __value)) { \ + cleanup((vec)->elems[idx]); \ + AST_VECTOR_REMOVE_UNORDERED((vec), idx); \ + ++count; \ + } \ + } \ + count; \ +}) + /*! * \brief Remove an element from a vector that matches the given comparison * @@ -379,6 +403,30 @@ res; \ }) +/*! + * \brief Remove all elements from a vector that matches the given comparison while maintaining order + * + * \param vec Vector to remove from. + * \param value Value to pass into comparator. + * \param cmp Comparator function/macros (called as \c cmp(elem, value)) + * \param cleanup How to cleanup a removed element macro/function. + * + * \return the number of deleted elements. + */ +#define AST_VECTOR_REMOVE_ALL_CMP_ORDERED(vec, value, cmp, cleanup) ({ \ + int count = 0; \ + size_t idx; \ + typeof(value) __value = (value); \ + for (idx = 0; idx < (vec)->current; ++idx) { \ + if (cmp((vec)->elems[idx], __value)) { \ + cleanup((vec)->elems[idx]); \ + AST_VECTOR_REMOVE_ORDERED((vec), idx); \ + ++count; \ + } \ + } \ + oount; \ +}) + /*! * \brief Remove an element from a vector that matches the given comparison while maintaining order * diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index cf09a541512..aec923dfaa5 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -989,7 +989,7 @@ static int wizard_apply_handler(const struct ast_sorcery *sorcery, struct object rc = handle_registrations(sorcery, otw, wiz, &remote_hosts_vector); } - AST_VECTOR_REMOVE_CMP_UNORDERED(&remote_hosts_vector, NULL, NOT_EQUALS, ast_free); + AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(&remote_hosts_vector, NULL, NOT_EQUALS, ast_free); AST_VECTOR_FREE(&remote_hosts_vector); ast_debug(4, "%s handler complete. rc: %d\n", otw->object_type, rc); @@ -1293,7 +1293,7 @@ static int unload_module(void) { ast_cli_unregister_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli)); ast_sorcery_global_observer_remove(&global_observer); - AST_VECTOR_REMOVE_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB); + AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB); AST_VECTOR_RW_FREE(&object_type_wizards); return 0; From 7af7490e420ec09bc60cda12df45abf664edcb34 Mon Sep 17 00:00:00 2001 From: Michael Walton Date: Wed, 5 Oct 2016 14:46:17 +1300 Subject: [PATCH 0787/1578] audiohooks: Remove redundant codec translations when using audiohooks The main frame read and write handlers in main/channel.c don't use the optimum placement in the processing flow for calling audiohooks callbacks, as far as codec translation is concerned. This change places the audiohooks callback code: * After the channel read translation if the frame is not linear before the translation, thereby increasing the chance that the frame is linear as required by audiohooks * Before the channel write translation if the frame is linear at this point This prevents the audiohooks code from instantiating additional translation paths to/from linear where a linear frame format is already available, saving valuable CPU cycles ASTERISK-26419 Change-Id: I6edd5771f0740e758e7eb42558b953f046c01f8f --- main/channel.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/main/channel.c b/main/channel.c index 94505ad0e83..e2390ad6536 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3914,6 +3914,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) struct ast_frame *readq_tail = AST_LIST_LAST(ast_channel_readq(chan)); struct ast_control_read_action_payload *read_action_payload; struct ast_party_connected_line connected; + int hooked = 0; /* if the channel driver returned more than one frame, stuff the excess into the readq for the next ast_read call @@ -4191,15 +4192,22 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) break; } } - /* Send frame to audiohooks if present */ - if (ast_channel_audiohooks(chan)) { + /* + * Send frame to audiohooks if present, if frametype is linear, to preserve + * functional compatibility with previous behavior. If not linear, hold off + * until transcoding is done where we are more likely to have a linear frame + */ + if (ast_channel_audiohooks(chan) && ast_format_cache_is_slinear(f->subclass.format)) { + /* Place hooked after declaration */ struct ast_frame *old_frame = f; + hooked = 1; f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); if (old_frame != f) { ast_frfree(old_frame); } } + if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->read_stream) { /* XXX what does this do ? */ #ifndef MONITOR_CONSTANT_DELAY @@ -4242,6 +4250,16 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) } } + /* Second chance at hooking a linear frame, also the last chance */ + if (ast_channel_audiohooks(chan) && !hooked) { + struct ast_frame *old_frame = f; + + f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f); + if (old_frame != f) { + ast_frfree(old_frame); + } + } + /* * It is possible for the translation process on the channel to have * produced multiple frames from the single input frame we passed it; if @@ -5032,6 +5050,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) int res = -1; struct ast_frame *f = NULL; int count = 0; + int hooked = 0; /*Deadlock avoidance*/ while(ast_channel_trylock(chan)) { @@ -5149,6 +5168,22 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) apply_plc(chan, fr); } + /* + * Send frame to audiohooks if present, if frametype is linear (else, later as per + * previous behavior) + */ + if (ast_channel_audiohooks(chan)) { + if (ast_format_cache_is_slinear(fr->subclass.format)) { + struct ast_frame *old_frame; + hooked = 1; + old_frame = fr; + fr = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_WRITE, fr); + if (old_frame != fr) { + ast_frfree(old_frame); + } + } + } + /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */ if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) { f = fr; @@ -5186,7 +5221,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) break; } - if (ast_channel_audiohooks(chan)) { + if (ast_channel_audiohooks(chan) && !hooked) { struct ast_frame *prev = NULL, *new_frame, *cur, *dup; int freeoldlist = 0; From fafdde322cdb303d7c7df297316a25a8ab666085 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sun, 9 Oct 2016 22:28:52 -0400 Subject: [PATCH 0788/1578] logger: Prevent output of verbose messages initiated from rasterisk. Remote asterisk consoles should only display verbose log messages created by the daemon. The first patch for ASTERISK-26410 caused a couple verbose messages to be printed when the rasterisk process ended. ASTERISK-26410 Change-Id: Ie2a1bb3753ad2724c0349ec1a336f52f7117b52a --- main/logger.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main/logger.c b/main/logger.c index d4cd25122e4..7d0d2de1e49 100644 --- a/main/logger.c +++ b/main/logger.c @@ -1867,6 +1867,10 @@ static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int su int res = 0; char datestring[256]; + if (level == __LOG_VERBOSE && ast_opt_remote && ast_opt_exec) { + return; + } + if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) return; From cc269766b8caef8dd6f5d9d705c8402425486941 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Thu, 29 Sep 2016 19:52:45 +0200 Subject: [PATCH 0789/1578] res_rtp_asterisk: Fix infinite DTMF issue when switching to P2P bridge If a bridge switched to P2P when a DTMF was in progress it was possible for the DTMF to continue being sent indefinitely. Change-Id: I7e2a3efe0d59d4b214ed50cd0b5d0317e2d92e29 --- res/res_rtp_asterisk.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index d6eea3ce0d7..520fd7602ae 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4284,6 +4284,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int int reconstruct = ntohl(rtpheader[0]); struct ast_sockaddr remote_address = { {0,} }; int ice; + unsigned int timestamp = ntohl(rtpheader[1]); /* Get fields from packet */ payload = (reconstruct & 0x7f0000) >> 16; @@ -4313,6 +4314,22 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int return -1; } + /* If bridged peer is in dtmf, feed all packets to core until it finishes to avoid infinite dtmf */ + if (bridged->sending_digit) { + ast_debug(1, "Feeding packets to core until DTMF finishes\n"); + return -1; + } + + /* + * Even if we are no longer in dtmf, we could still be receiving + * re-transmissions of the last dtmf end still. Feed those to the + * core so they can be filtered accordingly. + */ + if (rtp->last_end_timestamp == timestamp) { + ast_debug(1, "Feeding packet with duplicate timestamp to core\n"); + return -1; + } + /* If the marker bit has been explicitly set turn it on */ if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) { mark = 1; From 17031f12fe62708ca84db3a8551267ca2a0e24d8 Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Mon, 10 Oct 2016 17:59:58 -0400 Subject: [PATCH 0790/1578] vector: After remove element recheck index Small fix. It is necessary to double-check the index that we just removed because there is a new element. ASTERISK-26453 #close Change-Id: Ib947fa94dc91dcd9341f357f1084782c64434eb7 --- include/asterisk/vector.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index b4a8a2c113d..c74f0a89b58 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -367,11 +367,13 @@ int count = 0; \ size_t idx; \ typeof(value) __value = (value); \ - for (idx = 0; idx < (vec)->current; ++idx) { \ + for (idx = 0; idx < (vec)->current; ) { \ if (cmp((vec)->elems[idx], __value)) { \ cleanup((vec)->elems[idx]); \ AST_VECTOR_REMOVE_UNORDERED((vec), idx); \ ++count; \ + } else { \ + ++idx; \ } \ } \ count; \ @@ -417,14 +419,16 @@ int count = 0; \ size_t idx; \ typeof(value) __value = (value); \ - for (idx = 0; idx < (vec)->current; ++idx) { \ + for (idx = 0; idx < (vec)->current; ) { \ if (cmp((vec)->elems[idx], __value)) { \ cleanup((vec)->elems[idx]); \ - AST_VECTOR_REMOVE_ORDERED((vec), idx); \ + AST_VECTOR_REMOVE_ORDERED((vec), idx); \ ++count; \ + } else { \ + ++idx; \ } \ } \ - oount; \ + count; \ }) /*! @@ -445,7 +449,7 @@ for (idx = 0; idx < (vec)->current; ++idx) { \ if (cmp((vec)->elems[idx], __value)) { \ cleanup((vec)->elems[idx]); \ - AST_VECTOR_REMOVE_ORDERED((vec), idx); \ + AST_VECTOR_REMOVE_ORDERED((vec), idx); \ res = 0; \ break; \ } \ From 4f7f8a7e95aa344ba31ffab4da4be52952cf50d1 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 11 Oct 2016 13:55:13 +0200 Subject: [PATCH 0791/1578] chan_sip: Support nat=auto_comedia or nat=force_rport,auto_comedia. In the SIP channel driver chan_sip, auto_comedia was expected to be used in tandem with auto_force_rport. Or stated differently: Only when auto_force_rport was chosen (the default), auto_comedia worked. This change allows auto_comedia to be set independently of the state of (auto_)force_rport. For example, nat=force_rport,auto_comedia is useful for IPv4/IPv6 Dual Stack deployments when IPv6 clients are behind a Firewall. ASTERISK-26457 #close Change-Id: Ib29d66c6dbb61648e371e01fc36c6978ddae5bc2 --- channels/chan_sip.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 47b90d7240b..d8a3d5c7aae 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -30472,9 +30472,10 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ if (p->relatedpeer) { if (!ast_strlen_zero(p->relatedpeer->fullcontact) && !p->natdetected && - (ast_test_flag(&p->flags[2], SIP_PAGE3_NAT_AUTO_RPORT) && !ast_test_flag(&p->flags[0], SIP_NAT_FORCE_RPORT))) { + ((ast_test_flag(&p->flags[2], SIP_PAGE3_NAT_AUTO_RPORT) && !ast_test_flag(&p->flags[0], SIP_NAT_FORCE_RPORT)) || + (ast_test_flag(&p->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) && !ast_test_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP)))) { /* We need to make an attempt to determine if a peer is behind NAT - if the peer has the auto_force_rport flag set. */ + if the peer has the flags auto_force_rport or auto_comedia set. */ struct ast_sockaddr tmpaddr; __set_address_from_contact(p->relatedpeer->fullcontact, &tmpaddr, 0); From 86e8716952b7b7fde146f621fc5b74ef3bd2ae3a Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 6 Oct 2016 08:58:26 -0600 Subject: [PATCH 0792/1578] app_dial: Add the "Q" option to set the cause on unanswered channels The "Q" option will set the cause on the unanswered channels when another channel answers. It overrides the default of ANSWERED_ELSEWHERE. NOTE: chan_sip does not support setting the cause on a CANCEL to anything other than ANSWERED_ELSEWHERE. ASTERISK-26446 #close Change-Id: I71742e0919aaa16784c30a2b2e73fbeed7672e47 --- CHANGES | 6 ++++++ apps/app_dial.c | 56 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index be279879d04..96fdd13f791 100644 --- a/CHANGES +++ b/CHANGES @@ -103,6 +103,12 @@ app_confbridge instance, allows a channel to immediately exit the ConfBridge without having to wait for a leave announcement to play. +app_dial +------------------ + * Added the "Q" option which sets the Q.850/Q.931 cause on unanswered channels + when another channel answers the call. The default of ANSWERED_ELSEWHERE + is unchanged. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ diff --git a/apps/app_dial.c b/apps/app_dial.c index 316d38da15a..b5d8f50c767 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -375,6 +375,25 @@ ASTERISK_REGISTER_FILE() Enable privacy mode. Use x as the family/key in the AstDB database if it is provided. The current extension is used if a database family/key is not specified. + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 18664675999..00c22333078 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1938,6 +1938,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a69aa1a7438..13a71d4785c 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -385,6 +385,11 @@ static int set_caps(struct ast_sip_session *session, session->dsp = NULL; } } + + if (ast_channel_is_bridged(session->channel)) { + ast_channel_set_unbridged_nolock(session->channel, 1); + } + ast_channel_unlock(session->channel); } From 95062fe220831e1bc6781a3e5a898a2c15055605 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 26 Oct 2016 12:51:50 +0000 Subject: [PATCH 0826/1578] app_voicemail: Clear voice mailbox in MailboxExists and MAILBOX_EXISTS. When executing the MailboxExists dialplan application and MAILBOX_EXISTS dialplan function the passed in temporary voice mailbox was not cleared, causing it to try to free garbage. ASTERISK-26503 #close Change-Id: Ie21ccfa1b80b9c59318e596f6b8e17da2b5a7cb3 --- apps/app_voicemail.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 4727e2ee5af..300dc186d7d 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -12529,6 +12529,7 @@ static int vm_box_exists(struct ast_channel *chan, const char *data) context++; } + memset(&svm, 0, sizeof(svm)); vmu = find_user(&svm, context, args.mbox); if (vmu) { pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS"); @@ -12560,6 +12561,7 @@ static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *a ast_log(AST_LOG_WARNING, "MAILBOX_EXISTS is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", args); } + memset(&svm, 0, sizeof(svm)); vmu = find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox); ast_copy_string(buf, vmu ? "1" : "0", len); free_user(vmu); From 6993f3c9c318ca65efb21e47a9f8cd20a0a621d6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 27 Oct 2016 13:07:02 +0000 Subject: [PATCH 0827/1578] res_pjsip_caller_id: Fix crash on session timers UPDATE on inbound calls. The res_pjsip_caller_id module wrongly assumed that a saved From header would always exist on sessions. This is true until an inbound call is received and a session timer causes an UPDATE to be sent. In this case there will be no saved From header and a crash will occur. This change makes it fall back to the From header of the outgoing request if no saved From header is present. ASTERISK-26307 #close Change-Id: Iccc3bc8d243b5ede9b81abf960292930c908d4fa --- res/res_pjsip_caller_id.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 16b19ec2ba4..7948d33bea2 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -523,8 +523,11 @@ static void add_pai_header(const struct ast_sip_session *session, pjsip_tx_data } } - base = tdata->msg->type == PJSIP_REQUEST_MSG ? session->saved_from_hdr : - PJSIP_MSG_TO_HDR(tdata->msg); + if (tdata->msg->type == PJSIP_REQUEST_MSG) { + base = session->saved_from_hdr ? session->saved_from_hdr : PJSIP_MSG_FROM_HDR(tdata->msg); + } else { + base = PJSIP_MSG_TO_HDR(tdata->msg); + } pai_hdr = create_new_id_hdr(&pj_pai_name, base, tdata, id); if (!pai_hdr) { @@ -629,8 +632,11 @@ static void add_rpid_header(const struct ast_sip_session *session, pjsip_tx_data } } - base = tdata->msg->type == PJSIP_REQUEST_MSG ? session->saved_from_hdr : - PJSIP_MSG_TO_HDR(tdata->msg); + if (tdata->msg->type == PJSIP_REQUEST_MSG) { + base = session->saved_from_hdr ? session->saved_from_hdr : PJSIP_MSG_FROM_HDR(tdata->msg); + } else { + base = PJSIP_MSG_TO_HDR(tdata->msg); + } rpid_hdr = create_new_id_hdr(&pj_rpid_name, base, tdata, id); if (!rpid_hdr) { From a6e5bae3ef9fe498927e0b5f9318a64c9ff101a9 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 26 Oct 2016 22:40:49 -0400 Subject: [PATCH 0828/1578] Remove ASTERISK_REGISTER_FILE. ASTERISK_REGISTER_FILE no longer has any purpose so this commit removes all traces of it. Previously exported symbols removed: * __ast_register_file * __ast_unregister_file * ast_complete_source_filename This also removes the mtx_prof static variable that was declared when MTX_PROFILE was enabled. This variable was only used in lock.c so it is now initialized in that file only. ASTERISK-26480 #close Change-Id: I1074af07d71f9e159c48ef36631aa432c86f9966 --- CHANGES | 5 ++ addons/cdr_mysql.c | 2 - addons/chan_mobile.c | 2 - addons/format_mp3.c | 2 - addons/ooh323c/src/ooSocket.c | 2 - addons/res_config_mysql.c | 2 - apps/app_adsiprog.c | 2 - apps/app_agent_pool.c | 2 - apps/app_alarmreceiver.c | 2 - apps/app_amd.c | 2 - apps/app_authenticate.c | 2 - apps/app_bridgeaddchan.c | 2 - apps/app_bridgewait.c | 2 - apps/app_cdr.c | 2 - apps/app_celgenuserevent.c | 2 - apps/app_chanisavail.c | 2 - apps/app_channelredirect.c | 2 - apps/app_chanspy.c | 2 - apps/app_confbridge.c | 2 - apps/app_controlplayback.c | 2 - apps/app_dahdiras.c | 2 - apps/app_db.c | 2 - apps/app_dial.c | 2 - apps/app_dictate.c | 2 - apps/app_directed_pickup.c | 2 - apps/app_directory.c | 2 - apps/app_disa.c | 2 - apps/app_dumpchan.c | 2 - apps/app_echo.c | 2 - apps/app_exec.c | 2 - apps/app_externalivr.c | 2 - apps/app_fax.c | 2 - apps/app_festival.c | 2 - apps/app_flash.c | 2 - apps/app_followme.c | 2 - apps/app_forkcdr.c | 2 - apps/app_getcpeid.c | 2 - apps/app_ices.c | 2 - apps/app_image.c | 2 - apps/app_ivrdemo.c | 2 - apps/app_jack.c | 2 - apps/app_macro.c | 2 - apps/app_meetme.c | 2 - apps/app_milliwatt.c | 2 - apps/app_minivm.c | 2 - apps/app_mixmonitor.c | 2 - apps/app_morsecode.c | 2 - apps/app_mp3.c | 2 - apps/app_nbscat.c | 2 - apps/app_originate.c | 2 - apps/app_osplookup.c | 2 - apps/app_page.c | 2 - apps/app_playback.c | 2 - apps/app_playtones.c | 2 - apps/app_privacy.c | 2 - apps/app_queue.c | 2 - apps/app_read.c | 2 - apps/app_readexten.c | 2 - apps/app_record.c | 2 - apps/app_saycounted.c | 2 - apps/app_sayunixtime.c | 2 - apps/app_senddtmf.c | 2 - apps/app_sendtext.c | 2 - apps/app_setcallerid.c | 2 - apps/app_skel.c | 2 - apps/app_sms.c | 2 - apps/app_softhangup.c | 2 - apps/app_speech_utils.c | 2 - apps/app_stack.c | 2 - apps/app_stasis.c | 2 - apps/app_statsd.c | 2 - apps/app_system.c | 2 - apps/app_talkdetect.c | 2 - apps/app_test.c | 2 - apps/app_transfer.c | 2 - apps/app_url.c | 2 - apps/app_userevent.c | 2 - apps/app_verbose.c | 2 - apps/app_voicemail.c | 2 - apps/app_waitforring.c | 2 - apps/app_waitforsilence.c | 2 - apps/app_waituntil.c | 2 - apps/app_while.c | 2 - apps/app_zapateller.c | 2 - apps/confbridge/conf_chan_announce.c | 2 - apps/confbridge/conf_chan_record.c | 2 - apps/confbridge/conf_config_parser.c | 1 - apps/confbridge/confbridge_manager.c | 2 - bridges/bridge_builtin_features.c | 2 - bridges/bridge_builtin_interval_features.c | 2 - bridges/bridge_holding.c | 2 - bridges/bridge_native_rtp.c | 2 - bridges/bridge_simple.c | 2 - bridges/bridge_softmix.c | 2 - cdr/cdr_adaptive_odbc.c | 2 - cdr/cdr_csv.c | 2 - cdr/cdr_custom.c | 2 - cdr/cdr_manager.c | 2 - cdr/cdr_odbc.c | 2 - cdr/cdr_pgsql.c | 2 - cdr/cdr_radius.c | 2 - cdr/cdr_sqlite.c | 2 - cdr/cdr_sqlite3_custom.c | 2 - cdr/cdr_syslog.c | 2 - cdr/cdr_tds.c | 2 - cel/cel_custom.c | 2 - cel/cel_manager.c | 2 - cel/cel_odbc.c | 2 - cel/cel_pgsql.c | 2 - cel/cel_radius.c | 2 - cel/cel_sqlite3_custom.c | 2 - cel/cel_tds.c | 2 - channels/chan_alsa.c | 2 - channels/chan_bridge_media.c | 2 - channels/chan_console.c | 2 - channels/chan_dahdi.c | 2 - channels/chan_iax2.c | 2 - channels/chan_mgcp.c | 2 - channels/chan_misdn.c | 2 - channels/chan_motif.c | 2 - channels/chan_nbs.c | 2 - channels/chan_oss.c | 2 - channels/chan_phone.c | 2 - channels/chan_pjsip.c | 2 - channels/chan_rtp.c | 2 - channels/chan_sip.c | 2 - channels/chan_skinny.c | 2 - channels/chan_unistim.c | 2 - channels/chan_vpb.cc | 2 - channels/console_board.c | 1 - channels/console_video.c | 1 - channels/dahdi/bridge_native_dahdi.c | 2 - channels/iax2/codec_pref.c | 2 - channels/iax2/firmware.c | 2 - channels/iax2/format_compatibility.c | 2 - channels/iax2/parser.c | 2 - channels/iax2/provision.c | 2 - channels/misdn_config.c | 2 - channels/pjsip/cli_commands.c | 2 - channels/pjsip/dialplan_functions.c | 2 - channels/sip/config_parser.c | 2 - channels/sip/dialplan_functions.c | 2 - channels/sip/reqresp_parser.c | 2 - channels/sip/route.c | 2 - channels/sip/security_events.c | 2 - channels/vgrabbers.c | 1 - codecs/codec_a_mu.c | 2 - codecs/codec_adpcm.c | 2 - codecs/codec_alaw.c | 2 - codecs/codec_dahdi.c | 2 - codecs/codec_g722.c | 2 - codecs/codec_g726.c | 2 - codecs/codec_gsm.c | 2 - codecs/codec_ilbc.c | 2 - codecs/codec_lpc10.c | 2 - codecs/codec_resample.c | 2 - codecs/codec_speex.c | 2 - codecs/codec_ulaw.c | 2 - formats/format_g719.c | 2 - formats/format_g723.c | 2 - formats/format_g726.c | 2 - formats/format_g729.c | 2 - formats/format_gsm.c | 2 - formats/format_h263.c | 2 - formats/format_h264.c | 2 - formats/format_ilbc.c | 2 - formats/format_jpeg.c | 2 - formats/format_ogg_speex.c | 2 - formats/format_ogg_vorbis.c | 2 - formats/format_pcm.c | 2 - formats/format_siren14.c | 2 - formats/format_siren7.c | 2 - formats/format_sln.c | 2 - formats/format_vox.c | 2 - formats/format_wav.c | 2 - formats/format_wav_gsm.c | 2 - funcs/func_aes.c | 2 - funcs/func_base64.c | 2 - funcs/func_blacklist.c | 2 - funcs/func_callcompletion.c | 2 - funcs/func_callerid.c | 2 - funcs/func_cdr.c | 2 - funcs/func_channel.c | 2 - funcs/func_config.c | 2 - funcs/func_curl.c | 2 - funcs/func_cut.c | 2 - funcs/func_db.c | 2 - funcs/func_devstate.c | 2 - funcs/func_dialgroup.c | 2 - funcs/func_dialplan.c | 2 - funcs/func_enum.c | 2 - funcs/func_env.c | 2 - funcs/func_extstate.c | 2 - funcs/func_frame_trace.c | 2 - funcs/func_global.c | 2 - funcs/func_groupcount.c | 2 - funcs/func_hangupcause.c | 2 - funcs/func_holdintercept.c | 2 - funcs/func_iconv.c | 2 - funcs/func_jitterbuffer.c | 2 - funcs/func_lock.c | 2 - funcs/func_logic.c | 2 - funcs/func_math.c | 2 - funcs/func_md5.c | 2 - funcs/func_module.c | 2 - funcs/func_odbc.c | 2 - funcs/func_periodic_hook.c | 2 - funcs/func_pitchshift.c | 2 - funcs/func_pjsip_aor.c | 2 - funcs/func_pjsip_contact.c | 2 - funcs/func_pjsip_endpoint.c | 2 - funcs/func_presencestate.c | 2 - funcs/func_rand.c | 2 - funcs/func_realtime.c | 2 - funcs/func_sha1.c | 2 - funcs/func_shell.c | 2 - funcs/func_sorcery.c | 2 - funcs/func_speex.c | 2 - funcs/func_sprintf.c | 2 - funcs/func_srv.c | 2 - funcs/func_strings.c | 2 - funcs/func_sysinfo.c | 2 - funcs/func_talkdetect.c | 2 - funcs/func_timeout.c | 2 - funcs/func_uri.c | 2 - funcs/func_version.c | 2 - funcs/func_vmcount.c | 2 - funcs/func_volume.c | 2 - include/asterisk.h | 71 +------------------ main/abstract_jb.c | 2 - main/acl.c | 2 - main/alaw.c | 2 - main/aoc.c | 1 - main/app.c | 2 - main/ast_expr2.c | 5 +- main/ast_expr2.fl | 4 +- main/ast_expr2.y | 5 +- main/ast_expr2f.c | 4 +- main/asterisk.c | 71 ------------------- main/astfd.c | 2 - main/astmm.c | 2 - main/astobj2.c | 2 - main/astobj2_container.c | 2 - main/astobj2_hash.c | 2 - main/astobj2_rbtree.c | 2 - main/audiohook.c | 2 - main/autochan.c | 2 - main/autoservice.c | 2 - main/backtrace.c | 1 - main/bridge.c | 2 - main/bridge_after.c | 2 - main/bridge_basic.c | 2 - main/bridge_channel.c | 2 - main/bridge_roles.c | 2 - main/bucket.c | 2 - main/callerid.c | 2 - main/ccss.c | 2 - main/cdr.c | 2 - main/cel.c | 2 - main/channel.c | 2 - main/channel_internal_api.c | 2 - main/chanvars.c | 2 - main/cli.c | 2 - main/codec.c | 2 - main/codec_builtin.c | 2 - main/config.c | 2 - main/config_options.c | 2 - main/core_local.c | 2 - main/core_unreal.c | 2 - main/crypt.c | 2 - main/data.c | 2 - main/datastore.c | 2 - main/db.c | 2 - main/devicestate.c | 2 - main/dial.c | 2 - main/dns.c | 2 - main/dns_core.c | 2 - main/dns_naptr.c | 2 - main/dns_query_set.c | 4 +- main/dns_recurring.c | 2 - main/dns_srv.c | 2 - main/dns_system_resolver.c | 2 - main/dns_tlsa.c | 2 - main/dnsmgr.c | 2 - main/dsp.c | 2 - main/endpoints.c | 2 - main/enum.c | 2 - main/event.c | 2 - main/features.c | 2 - main/file.c | 2 - main/fixedjitterbuf.c | 2 - main/format.c | 2 - main/format_cache.c | 2 - main/format_cap.c | 2 - main/format_compatibility.c | 2 - main/frame.c | 2 - main/framehook.c | 2 - main/fskmodem_float.c | 2 - main/fskmodem_int.c | 2 - main/global_datastores.c | 2 - main/hashtab.c | 2 - main/heap.c | 2 - main/http.c | 2 - main/image.c | 2 - main/indications.c | 2 - main/io.c | 2 - main/jitterbuf.c | 2 - main/json.c | 2 - main/libasteriskpj.c | 2 - main/libasteriskssl.c | 2 - main/loader.c | 2 - main/lock.c | 9 ++- main/logger.c | 2 - main/manager.c | 2 - main/manager_bridges.c | 2 - main/manager_channels.c | 2 - main/manager_endpoints.c | 2 - main/manager_mwi.c | 2 - main/manager_system.c | 2 - main/md5.c | 2 - main/media_cache.c | 2 - main/message.c | 2 - main/mixmonitor.c | 2 - main/named_acl.c | 2 - main/named_locks.c | 2 - main/netsock.c | 2 - main/netsock2.c | 2 - main/optional_api.c | 2 - main/parking.c | 2 - main/pbx.c | 2 - main/pbx_app.c | 2 - main/pbx_builtins.c | 2 - main/pbx_functions.c | 2 - main/pbx_hangup_handler.c | 2 - main/pbx_ignorepat.c | 2 - main/pbx_include.c | 2 - main/pbx_sw.c | 2 - main/pbx_switch.c | 2 - main/pbx_timing.c | 2 - main/pbx_variables.c | 2 - main/pickup.c | 2 - main/plc.c | 2 - main/presencestate.c | 2 - main/privacy.c | 2 - main/rtp_engine.c | 2 - main/say.c | 2 - main/sched.c | 2 - main/sdp_srtp.c | 2 - main/security_events.c | 2 - main/sem.c | 2 - main/slinfactory.c | 2 - main/smoother.c | 2 - main/sorcery.c | 2 - main/srv.c | 2 - main/stasis.c | 2 - main/stasis_bridges.c | 2 - main/stasis_cache.c | 2 - main/stasis_cache_pattern.c | 2 - main/stasis_channels.c | 2 - main/stasis_endpoints.c | 2 - main/stasis_message.c | 2 - main/stasis_message_router.c | 2 - main/stasis_system.c | 2 - main/stdtime/localtime.c | 2 - main/stringfields.c | 2 - main/strings.c | 2 - main/stun.c | 2 - main/syslog.c | 2 - main/taskprocessor.c | 2 - main/tcptls.c | 2 - main/tdd.c | 2 - main/term.c | 2 - main/test.c | 2 - main/threadstorage.c | 2 - main/timing.c | 2 - main/translate.c | 2 - main/udptl.c | 2 - main/ulaw.c | 2 - main/utils.c | 2 - main/xml.c | 2 - main/xmldoc.c | 2 - pbx/dundi-parser.c | 2 - pbx/pbx_ael.c | 9 --- pbx/pbx_config.c | 2 - pbx/pbx_dundi.c | 2 - pbx/pbx_loopback.c | 2 - pbx/pbx_lua.c | 2 - pbx/pbx_realtime.c | 2 - pbx/pbx_spool.c | 2 - res/ael/ael.flex | 1 - res/ael/ael.tab.c | 2 - res/ael/ael.y | 2 - res/ael/ael_lex.c | 1 - res/ael/pval.c | 2 - res/ari/ari_model_validators.c | 2 - res/ari/ari_websockets.c | 2 - res/ari/cli.c | 2 - res/ari/config.c | 2 - res/ari/resource_applications.c | 2 - res/ari/resource_asterisk.c | 2 - res/ari/resource_bridges.c | 2 - res/ari/resource_channels.c | 2 - res/ari/resource_device_states.c | 2 - res/ari/resource_endpoints.c | 2 - res/ari/resource_events.c | 2 - res/ari/resource_mailboxes.c | 2 - res/ari/resource_playbacks.c | 2 - res/ari/resource_recordings.c | 2 - res/ari/resource_sounds.c | 2 - res/parking/parking_applications.c | 2 - res/parking/parking_bridge_features.c | 2 - res/parking/parking_manager.c | 2 - res/parking/parking_tests.c | 2 - res/parking/parking_ui.c | 2 - res/res_adsi.c | 2 - res/res_ael_share.c | 2 - res/res_agi.c | 2 - res/res_ari.c | 2 - res/res_ari_applications.c | 2 - res/res_ari_asterisk.c | 2 - res/res_ari_bridges.c | 2 - res/res_ari_channels.c | 2 - res/res_ari_device_states.c | 2 - res/res_ari_endpoints.c | 2 - res/res_ari_events.c | 2 - res/res_ari_mailboxes.c | 2 - res/res_ari_model.c | 2 - res/res_ari_playbacks.c | 2 - res/res_ari_recordings.c | 2 - res/res_ari_sounds.c | 2 - res/res_calendar.c | 2 - res/res_calendar_caldav.c | 2 - res/res_calendar_ews.c | 2 - res/res_calendar_exchange.c | 2 - res/res_calendar_icalendar.c | 2 - res/res_chan_stats.c | 2 - res/res_clialiases.c | 2 - res/res_clioriginate.c | 2 - res/res_config_curl.c | 2 - res/res_config_ldap.c | 2 - res/res_config_odbc.c | 2 - res/res_config_pgsql.c | 2 - res/res_config_sqlite.c | 1 - res/res_config_sqlite3.c | 2 - res/res_convert.c | 2 - res/res_corosync.c | 2 - res/res_crypto.c | 2 - res/res_curl.c | 2 - res/res_endpoint_stats.c | 2 - res/res_fax.c | 2 - res/res_fax_spandsp.c | 2 - res/res_format_attr_celt.c | 2 - res/res_format_attr_g729.c | 2 - res/res_format_attr_h263.c | 2 - res/res_format_attr_h264.c | 2 - res/res_format_attr_opus.c | 2 - res/res_format_attr_silk.c | 2 - res/res_format_attr_siren14.c | 2 - res/res_format_attr_siren7.c | 2 - res/res_format_attr_vp8.c | 2 - res/res_hep.c | 2 - res/res_hep_pjsip.c | 2 - res/res_hep_rtcp.c | 2 - res/res_http_media_cache.c | 2 - res/res_http_post.c | 2 - res/res_http_websocket.c | 2 - res/res_limit.c | 2 - res/res_monitor.c | 2 - res/res_musiconhold.c | 2 - res/res_mutestream.c | 2 - res/res_mwi_external.c | 2 - res/res_mwi_external_ami.c | 2 - res/res_odbc.c | 2 - res/res_parking.c | 2 - res/res_phoneprov.c | 1 - res/res_pjproject.c | 2 - res/res_pjsip/pjsip_scheduler.c | 2 - res/res_pjsip/security_events.c | 2 - res/res_pjsip_config_wizard.c | 2 - res/res_pjsip_dlg_options.c | 2 - res/res_pjsip_empty_info.c | 2 - res/res_pjsip_history.c | 2 - res/res_pjsip_logger.c | 2 - res/res_pjsip_sdp_rtp.c | 2 - res/res_pjsip_t38.c | 2 - res/res_pktccops.c | 2 - res/res_realtime.c | 2 - res/res_resolver_unbound.c | 2 - res/res_rtp_asterisk.c | 2 - res/res_rtp_multicast.c | 2 - res/res_security_log.c | 2 - res/res_smdi.c | 2 - res/res_snmp.c | 2 - res/res_sorcery_astdb.c | 2 - res/res_sorcery_config.c | 2 - res/res_sorcery_memory.c | 2 - res/res_sorcery_memory_cache.c | 2 - res/res_sorcery_realtime.c | 2 - res/res_speech.c | 2 - res/res_srtp.c | 2 - res/res_stasis.c | 2 - res/res_stasis_answer.c | 2 - res/res_stasis_device_state.c | 2 - res/res_stasis_mailbox.c | 2 - res/res_stasis_playback.c | 2 - res/res_stasis_recording.c | 2 - res/res_stasis_snoop.c | 2 - res/res_stasis_test.c | 2 - res/res_statsd.c | 2 - res/res_stun_monitor.c | 2 - res/res_timing_dahdi.c | 2 - res/res_timing_pthread.c | 2 - res/res_xmpp.c | 2 - res/snmp/agent.c | 2 - res/stasis/app.c | 2 - res/stasis/command.c | 2 - res/stasis/control.c | 2 - res/stasis/messaging.c | 2 - res/stasis/stasis_bridge.c | 2 - res/stasis_recording/stored.c | 2 - .../ari_model_validators.c.mustache | 2 - rest-api-templates/ari_resource.c.mustache | 2 - .../res_ari_resource.c.mustache | 2 - tests/test_abstract_jb.c | 2 - tests/test_acl.c | 2 - tests/test_amihooks.c | 2 - tests/test_aoc.c | 2 - tests/test_app.c | 2 - tests/test_ari.c | 2 - tests/test_ari_model.c | 2 - tests/test_ast_format_str_reduce.c | 2 - tests/test_astobj2.c | 2 - tests/test_astobj2_thrash.c | 1 - tests/test_astobj2_weaken.c | 2 - tests/test_bucket.c | 2 - tests/test_callerid.c | 2 - tests/test_cdr.c | 2 - tests/test_cel.c | 2 - tests/test_channel_feature_hooks.c | 2 - tests/test_config.c | 2 - tests/test_core_codec.c | 2 - tests/test_core_format.c | 2 - tests/test_db.c | 2 - tests/test_devicestate.c | 2 - tests/test_dlinklists.c | 2 - tests/test_endpoints.c | 2 - tests/test_event.c | 2 - tests/test_expr.c | 2 - tests/test_format_cache.c | 2 - tests/test_format_cap.c | 2 - tests/test_func_file.c | 2 - tests/test_gosub.c | 2 - tests/test_hashtab_thrash.c | 1 - tests/test_heap.c | 2 - tests/test_http_media_cache.c | 2 - tests/test_jitterbuf.c | 2 - tests/test_json.c | 1 - tests/test_linkedlists.c | 2 - tests/test_locale.c | 2 - tests/test_logger.c | 2 - tests/test_media_cache.c | 2 - tests/test_message.c | 2 - tests/test_netsock2.c | 2 - tests/test_optional_api.c | 2 - tests/test_pbx.c | 2 - tests/test_poll.c | 2 - tests/test_res_pjsip_scheduler.c | 2 - tests/test_res_stasis.c | 2 - tests/test_sched.c | 2 - tests/test_security_events.c | 2 - tests/test_skel.c | 2 - tests/test_sorcery.c | 2 - tests/test_sorcery_astdb.c | 2 - tests/test_sorcery_memory_cache_thrash.c | 2 - tests/test_sorcery_realtime.c | 2 - tests/test_stasis.c | 2 - tests/test_stasis_channels.c | 2 - tests/test_stasis_endpoints.c | 2 - tests/test_strings.c | 2 - tests/test_substitution.c | 2 - tests/test_time.c | 2 - tests/test_uri.c | 2 - tests/test_utils.c | 2 - tests/test_vector.c | 2 - tests/test_voicemail_api.c | 2 - tests/test_websocket_client.c | 2 - tests/test_xml_escape.c | 2 - utils/ael_main.c | 4 -- utils/astman.c | 11 --- utils/check_expr.c | 8 --- utils/conf2ael.c | 10 --- 591 files changed, 19 insertions(+), 1342 deletions(-) diff --git a/CHANGES b/CHANGES index 5948360dab6..959774e16b8 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,11 @@ Build System Asterisk built with LOW_MEMORY can now successfully load binary modules built without LOW_MEMORY and vice versa. +Core +------------------ + * ASTERISK_REGISTER_FILE was no longer useful and has been removed. Sources + which use mtx_prof must now manually declare and initialize the variable. + chan_sip ------------------ * If an offer is received with optional SRTP (a media stream with RTP/AVP but diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c index 896bad603ba..0878950e112 100644 --- a/addons/cdr_mysql.c +++ b/addons/cdr_mysql.c @@ -42,8 +42,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c index 64d53b70ddf..dc2efd4db30 100644 --- a/addons/chan_mobile.c +++ b/addons/chan_mobile.c @@ -42,8 +42,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/addons/format_mp3.c b/addons/format_mp3.c index 07715b548a1..e0f57b86b4f 100644 --- a/addons/format_mp3.c +++ b/addons/format_mp3.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "mp3/mpg123.h" #include "mp3/mpglib.h" diff --git a/addons/ooh323c/src/ooSocket.c b/addons/ooh323c/src/ooSocket.c index e9087d1fecc..5f8f0f37b5a 100644 --- a/addons/ooh323c/src/ooSocket.c +++ b/addons/ooh323c/src/ooSocket.c @@ -15,8 +15,6 @@ *****************************************************************************/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/io.h" #include "asterisk/lock.h" #include "asterisk/utils.h" diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c index e6b0e53c06b..bf38a4e69b6 100644 --- a/addons/res_config_mysql.c +++ b/addons/res_config_mysql.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/apps/app_adsiprog.c b/apps/app_adsiprog.c index 3f3d11c257f..9d73702f6a0 100644 --- a/apps/app_adsiprog.c +++ b/apps/app_adsiprog.c @@ -41,8 +41,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c index 68bcfdead8c..4563b58a09a 100644 --- a/apps/app_agent_pool.c +++ b/apps/app_agent_pool.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/cli.h" #include "asterisk/app.h" #include "asterisk/pbx.h" diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c index ace4df1dc5f..2169617acb3 100644 --- a/apps/app_alarmreceiver.c +++ b/apps/app_alarmreceiver.c @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_amd.c b/apps/app_amd.c index 83da5330d89..25649d4b624 100644 --- a/apps/app_amd.c +++ b/apps/app_amd.c @@ -43,8 +43,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/lock.h" #include "asterisk/channel.h" diff --git a/apps/app_authenticate.c b/apps/app_authenticate.c index f47db45346d..f58ed362619 100644 --- a/apps/app_authenticate.c +++ b/apps/app_authenticate.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/file.h" #include "asterisk/channel.h" diff --git a/apps/app_bridgeaddchan.c b/apps/app_bridgeaddchan.c index fda6ca5ed86..34642a6af9e 100644 --- a/apps/app_bridgeaddchan.c +++ b/apps/app_bridgeaddchan.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/module.h" #include "asterisk/channel.h" diff --git a/apps/app_bridgewait.c b/apps/app_bridgewait.c index 0e03ad7cecf..b17cddfb2fe 100644 --- a/apps/app_bridgewait.c +++ b/apps/app_bridgewait.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_cdr.c b/apps/app_cdr.c index 7862179f339..17dea431db2 100644 --- a/apps/app_cdr.c +++ b/apps/app_cdr.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/module.h" #include "asterisk/app.h" diff --git a/apps/app_celgenuserevent.c b/apps/app_celgenuserevent.c index b98cd674db7..67c7fbcbd75 100644 --- a/apps/app_celgenuserevent.c +++ b/apps/app_celgenuserevent.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/app.h" #include "asterisk/channel.h" diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c index dbd49914cf3..af4b616f5b0 100644 --- a/apps/app_chanisavail.c +++ b/apps/app_chanisavail.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/apps/app_channelredirect.c b/apps/app_channelredirect.c index 80c1ff03d2b..4f3b79197af 100644 --- a/apps/app_channelredirect.c +++ b/apps/app_channelredirect.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index df2deae3f54..50d8d63210e 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index a7fd92a3746..d6229b93f65 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -43,8 +43,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_controlplayback.c b/apps/app_controlplayback.c index 45580e4f0a1..cc557deea78 100644 --- a/apps/app_controlplayback.c +++ b/apps/app_controlplayback.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/app.h" #include "asterisk/module.h" diff --git a/apps/app_dahdiras.c b/apps/app_dahdiras.c index 51921a98ec7..6eaa1bd2236 100644 --- a/apps/app_dahdiras.c +++ b/apps/app_dahdiras.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_db.c b/apps/app_db.c index 1376b6874b4..e3d55054874 100644 --- a/apps/app_db.c +++ b/apps/app_db.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_dial.c b/apps/app_dial.c index b5d8f50c767..d871f7f57ae 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_dictate.c b/apps/app_dictate.c index 98e1fb15471..43ea81a1c97 100644 --- a/apps/app_dictate.c +++ b/apps/app_dictate.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */ diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c index cdcda047780..5ad29722cb4 100644 --- a/apps/app_directed_pickup.c +++ b/apps/app_directed_pickup.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_directory.c b/apps/app_directory.c index c32bccb89b4..642b9b23a08 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -30,8 +30,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */ diff --git a/apps/app_disa.c b/apps/app_disa.c index ab8d3082f20..8dc61ff64c5 100644 --- a/apps/app_disa.c +++ b/apps/app_disa.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c index 8b32b93dc12..0789ce06eb8 100644 --- a/apps/app_dumpchan.c +++ b/apps/app_dumpchan.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/channel.h" diff --git a/apps/app_echo.c b/apps/app_echo.c index 972e59f0aed..0f4c94b8d1f 100644 --- a/apps/app_echo.c +++ b/apps/app_echo.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/module.h" #include "asterisk/channel.h" diff --git a/apps/app_exec.c b/apps/app_exec.c index 1695ee5b8c2..79c1b75b996 100644 --- a/apps/app_exec.c +++ b/apps/app_exec.c @@ -31,8 +31,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c index 2bb1d8b5353..273f96381e7 100644 --- a/apps/app_externalivr.c +++ b/apps/app_externalivr.c @@ -37,8 +37,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/apps/app_fax.c b/apps/app_fax.c index 6e174d4a738..b7c39454f97 100644 --- a/apps/app_fax.c +++ b/apps/app_fax.c @@ -21,8 +21,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_festival.c b/apps/app_festival.c index 19c9f337676..3e2e020b834 100644 --- a/apps/app_festival.c +++ b/apps/app_festival.c @@ -42,8 +42,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_flash.c b/apps/app_flash.c index 79ce0d0f122..f92b68d0689 100644 --- a/apps/app_flash.c +++ b/apps/app_flash.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/apps/app_followme.c b/apps/app_followme.c index 938e63ec4bf..72afa3dd137 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -41,8 +41,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */ diff --git a/apps/app_forkcdr.c b/apps/app_forkcdr.c index 4ff5cd61034..acd8982ef4f 100644 --- a/apps/app_forkcdr.c +++ b/apps/app_forkcdr.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_getcpeid.c b/apps/app_getcpeid.c index c896f9ef073..da0d3e67f25 100644 --- a/apps/app_getcpeid.c +++ b/apps/app_getcpeid.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/file.h" #include "asterisk/channel.h" diff --git a/apps/app_ices.c b/apps/app_ices.c index 58201c4501a..4ca4b67c575 100644 --- a/apps/app_ices.c +++ b/apps/app_ices.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_image.c b/apps/app_image.c index 66751f54171..b817309c71a 100644 --- a/apps/app_image.c +++ b/apps/app_image.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/image.h" diff --git a/apps/app_ivrdemo.c b/apps/app_ivrdemo.c index 2ec28b16bff..38134e2474b 100644 --- a/apps/app_ivrdemo.c +++ b/apps/app_ivrdemo.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_jack.c b/apps/app_jack.c index e5b0b9a4188..bd964340333 100644 --- a/apps/app_jack.c +++ b/apps/app_jack.c @@ -42,8 +42,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/apps/app_macro.c b/apps/app_macro.c index 61f3ab722ef..4ef525295c0 100644 --- a/apps/app_macro.c +++ b/apps/app_macro.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 791f75eb0a3..36f5c77273f 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -47,8 +47,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/apps/app_milliwatt.c b/apps/app_milliwatt.c index a736fd47f29..3f076538cd4 100644 --- a/apps/app_milliwatt.c +++ b/apps/app_milliwatt.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_minivm.c b/apps/app_minivm.c index c84b7d7dd63..a060ad1833f 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -146,8 +146,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 7d7a0cbf914..a5a00cc4efc 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */ #include "asterisk/stringfields.h" #include "asterisk/file.h" diff --git a/apps/app_morsecode.c b/apps/app_morsecode.c index 8d06ac44c7b..048cf970f39 100644 --- a/apps/app_morsecode.c +++ b/apps/app_morsecode.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_mp3.c b/apps/app_mp3.c index 05afe54b100..678f76d7274 100644 --- a/apps/app_mp3.c +++ b/apps/app_mp3.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/apps/app_nbscat.c b/apps/app_nbscat.c index 8175fc81042..5f3bf0b92f2 100644 --- a/apps/app_nbscat.c +++ b/apps/app_nbscat.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_originate.c b/apps/app_originate.c index f744b7a9ddb..99984f5510b 100644 --- a/apps/app_originate.c +++ b/apps/app_originate.c @@ -38,8 +38,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_osplookup.c b/apps/app_osplookup.c index 25f9510ff95..d749a74ac51 100644 --- a/apps/app_osplookup.c +++ b/apps/app_osplookup.c @@ -36,8 +36,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_page.c b/apps/app_page.c index 3543d0509d0..b5221107492 100644 --- a/apps/app_page.c +++ b/apps/app_page.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/pbx.h" #include "asterisk/module.h" diff --git a/apps/app_playback.c b/apps/app_playback.c index 2875ec2b49b..35900e8f78f 100644 --- a/apps/app_playback.c +++ b/apps/app_playback.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/pbx.h" #include "asterisk/module.h" diff --git a/apps/app_playtones.c b/apps/app_playtones.c index 79e2a45769d..59fb5ad6677 100644 --- a/apps/app_playtones.c +++ b/apps/app_playtones.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/pbx.h" #include "asterisk/channel.h" diff --git a/apps/app_privacy.c b/apps/app_privacy.c index 70ec6562bb2..a9afe02220e 100644 --- a/apps/app_privacy.c +++ b/apps/app_privacy.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/file.h" #include "asterisk/utils.h" diff --git a/apps/app_queue.c b/apps/app_queue.c index 51741d37471..b40c1db30f8 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -69,8 +69,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_read.c b/apps/app_read.c index 1f586cb991e..d1e14ed806d 100644 --- a/apps/app_read.c +++ b/apps/app_read.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/pbx.h" #include "asterisk/channel.h" diff --git a/apps/app_readexten.c b/apps/app_readexten.c index a0a3c5583a4..c406a93cba5 100644 --- a/apps/app_readexten.c +++ b/apps/app_readexten.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/pbx.h" #include "asterisk/app.h" diff --git a/apps/app_record.c b/apps/app_record.c index fcd89387607..ede50be2645 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/pbx.h" #include "asterisk/module.h" diff --git a/apps/app_saycounted.c b/apps/app_saycounted.c index 55867bbeb6c..b44c1f6fed2 100644 --- a/apps/app_saycounted.c +++ b/apps/app_saycounted.c @@ -114,8 +114,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/module.h" #include "asterisk/app.h" diff --git a/apps/app_sayunixtime.c b/apps/app_sayunixtime.c index c4efaf38e44..b60c71e5137 100644 --- a/apps/app_sayunixtime.c +++ b/apps/app_sayunixtime.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_senddtmf.c b/apps/app_senddtmf.c index bca46302472..5ed426eee36 100644 --- a/apps/app_senddtmf.c +++ b/apps/app_senddtmf.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/app.h" diff --git a/apps/app_sendtext.c b/apps/app_sendtext.c index 3b7f0ca2f4c..4417dec5c37 100644 --- a/apps/app_sendtext.c +++ b/apps/app_sendtext.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_setcallerid.c b/apps/app_setcallerid.c index 36d554ee62f..3a2225b6c8e 100644 --- a/apps/app_setcallerid.c +++ b/apps/app_setcallerid.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/file.h" #include "asterisk/channel.h" diff --git a/apps/app_skel.c b/apps/app_skel.c index 0f17d9bf3cd..0dbd4c58b59 100644 --- a/apps/app_skel.c +++ b/apps/app_skel.c @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include /* log10 */ #include "asterisk/file.h" #include "asterisk/channel.h" diff --git a/apps/app_sms.c b/apps/app_sms.c index a748c3b4b19..d053ecbe6a9 100644 --- a/apps/app_sms.c +++ b/apps/app_sms.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/apps/app_softhangup.c b/apps/app_softhangup.c index 9660b4fd686..f74f7f9bd26 100644 --- a/apps/app_softhangup.c +++ b/apps/app_softhangup.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_speech_utils.c b/apps/app_speech_utils.c index 7c34dca527e..3a6a191e34a 100644 --- a/apps/app_speech_utils.c +++ b/apps/app_speech_utils.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_stack.c b/apps/app_stack.c index be8abbf5850..008627cc345 100644 --- a/apps/app_stack.c +++ b/apps/app_stack.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/app.h" diff --git a/apps/app_stasis.c b/apps/app_stasis.c index ffe4727794a..81c58e8b0cb 100644 --- a/apps/app_stasis.c +++ b/apps/app_stasis.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/pbx.h" diff --git a/apps/app_statsd.c b/apps/app_statsd.c index e87aac64389..5f865398107 100644 --- a/apps/app_statsd.c +++ b/apps/app_statsd.c @@ -24,8 +24,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/apps/app_system.c b/apps/app_system.c index 7fcffb196a1..09179f7f707 100644 --- a/apps/app_system.c +++ b/apps/app_system.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/app.h" diff --git a/apps/app_talkdetect.c b/apps/app_talkdetect.c index 6b5a6492262..fbe2ea70f49 100644 --- a/apps/app_talkdetect.c +++ b/apps/app_talkdetect.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/file.h" #include "asterisk/channel.h" diff --git a/apps/app_test.c b/apps/app_test.c index 94f746bec2e..2f0d77741fd 100644 --- a/apps/app_test.c +++ b/apps/app_test.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */ diff --git a/apps/app_transfer.c b/apps/app_transfer.c index d4cb6b6e19c..7bc67e1541a 100644 --- a/apps/app_transfer.c +++ b/apps/app_transfer.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/app.h" diff --git a/apps/app_url.c b/apps/app_url.c index 863fa09eb13..185712dece9 100644 --- a/apps/app_url.c +++ b/apps/app_url.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/app.h" diff --git a/apps/app_userevent.c b/apps/app_userevent.c index 826b4dcb965..d04e0713b00 100644 --- a/apps/app_userevent.c +++ b/apps/app_userevent.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/manager.h" diff --git a/apps/app_verbose.c b/apps/app_verbose.c index c285b2248ba..5b78e189b14 100644 --- a/apps/app_verbose.c +++ b/apps/app_verbose.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/app.h" #include "asterisk/channel.h" diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 4727e2ee5af..fd6cb725eaa 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -101,8 +101,6 @@ #endif #endif -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */ #include #include diff --git a/apps/app_waitforring.c b/apps/app_waitforring.c index c4e14ad60dd..d59f527c68d 100644 --- a/apps/app_waitforring.c +++ b/apps/app_waitforring.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_waitforsilence.c b/apps/app_waitforsilence.c index b63b0c8acbf..5eaeace349e 100644 --- a/apps/app_waitforsilence.c +++ b/apps/app_waitforsilence.c @@ -44,8 +44,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_waituntil.c b/apps/app_waituntil.c index c55b821b901..d3313615e69 100644 --- a/apps/app_waituntil.c +++ b/apps/app_waituntil.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/apps/app_while.c b/apps/app_while.c index cc048dfb3a1..6bac60ab5d9 100644 --- a/apps/app_while.c +++ b/apps/app_while.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/channel.h" diff --git a/apps/app_zapateller.c b/apps/app_zapateller.c index 27bcf6331d2..e876a70a8d7 100644 --- a/apps/app_zapateller.c +++ b/apps/app_zapateller.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/file.h" #include "asterisk/channel.h" diff --git a/apps/confbridge/conf_chan_announce.c b/apps/confbridge/conf_chan_announce.c index 4060b99c4f1..23a633668d0 100644 --- a/apps/confbridge/conf_chan_announce.c +++ b/apps/confbridge/conf_chan_announce.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/bridge.h" #include "asterisk/core_unreal.h" diff --git a/apps/confbridge/conf_chan_record.c b/apps/confbridge/conf_chan_record.c index dd438c159c3..5d3a7dbbe7c 100644 --- a/apps/confbridge/conf_chan_record.c +++ b/apps/confbridge/conf_chan_record.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/bridge.h" #include "asterisk/format_cache.h" diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 6f8510552bd..1749b585e7c 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -29,7 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include "asterisk/logger.h" #include "asterisk/config.h" #include "asterisk/config_options.h" diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c index 133aceb9f3d..a99362b33a3 100644 --- a/apps/confbridge/confbridge_manager.c +++ b/apps/confbridge/confbridge_manager.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/bridge.h" #include "asterisk/stasis.h" diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c index f1d00c5a801..3821feef9da 100644 --- a/bridges/bridge_builtin_features.c +++ b/bridges/bridge_builtin_features.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/bridges/bridge_builtin_interval_features.c b/bridges/bridge_builtin_interval_features.c index 0c8cf24fb33..a8edc21dc6b 100644 --- a/bridges/bridge_builtin_interval_features.c +++ b/bridges/bridge_builtin_interval_features.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/bridges/bridge_holding.c b/bridges/bridge_holding.c index 7bf7a392288..5f354c0d588 100644 --- a/bridges/bridge_holding.c +++ b/bridges/bridge_holding.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 6c7c1cd5c59..05ef4ea35db 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index fc12bd16af9..35544f84fac 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 0991e289700..31b72265fee 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/cdr/cdr_adaptive_odbc.c b/cdr/cdr_adaptive_odbc.c index f0bcc096253..b7417ac259a 100644 --- a/cdr/cdr_adaptive_odbc.c +++ b/cdr/cdr_adaptive_odbc.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c index 2877a6b5462..5666a3d4eea 100644 --- a/cdr/cdr_csv.c +++ b/cdr/cdr_csv.c @@ -38,8 +38,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */ #include "asterisk/config.h" #include "asterisk/channel.h" diff --git a/cdr/cdr_custom.c b/cdr/cdr_custom.c index bb63ea0c646..7d8b9d82ec9 100644 --- a/cdr/cdr_custom.c +++ b/cdr/cdr_custom.c @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */ diff --git a/cdr/cdr_manager.c b/cdr/cdr_manager.c index ef9d63e4798..3f0cc6b6dda 100644 --- a/cdr/cdr_manager.c +++ b/cdr/cdr_manager.c @@ -166,8 +166,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/channel.h" diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c index 5fddb7b23fd..b44bbf52ae4 100644 --- a/cdr/cdr_odbc.c +++ b/cdr/cdr_odbc.c @@ -44,8 +44,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/config.h" #include "asterisk/channel.h" #include "asterisk/cdr.h" diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c index ea38cc9837c..cbd9e0558b2 100644 --- a/cdr/cdr_pgsql.c +++ b/cdr/cdr_pgsql.c @@ -49,8 +49,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/config.h" diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c index ddde5b890f6..af434f61852 100644 --- a/cdr/cdr_radius.c +++ b/cdr/cdr_radius.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef FREERADIUS_CLIENT #include #else diff --git a/cdr/cdr_sqlite.c b/cdr/cdr_sqlite.c index 5a3b9e1448d..b91296073b3 100644 --- a/cdr/cdr_sqlite.c +++ b/cdr/cdr_sqlite.c @@ -43,8 +43,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/channel.h" diff --git a/cdr/cdr_sqlite3_custom.c b/cdr/cdr_sqlite3_custom.c index b7f99783217..e8d763edd52 100644 --- a/cdr/cdr_sqlite3_custom.c +++ b/cdr/cdr_sqlite3_custom.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */ diff --git a/cdr/cdr_syslog.c b/cdr/cdr_syslog.c index 39f115920dc..bbe26522954 100644 --- a/cdr/cdr_syslog.c +++ b/cdr/cdr_syslog.c @@ -43,8 +43,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/lock.h" #include "asterisk/cdr.h" diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c index 6dabeff83a0..f3d0628ec62 100644 --- a/cdr/cdr_tds.c +++ b/cdr/cdr_tds.c @@ -64,8 +64,6 @@ CREATE TABLE [dbo].[cdr] ( #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/config.h" #include "asterisk/channel.h" #include "asterisk/cdr.h" diff --git a/cel/cel_custom.c b/cel/cel_custom.c index f75efdd4be4..d1655413f3a 100644 --- a/cel/cel_custom.c +++ b/cel/cel_custom.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" #include "asterisk/channel.h" #include "asterisk/cel.h" diff --git a/cel/cel_manager.c b/cel/cel_manager.c index bdf505b66df..365bb70c284 100644 --- a/cel/cel_manager.c +++ b/cel/cel_manager.c @@ -195,8 +195,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/cel.h" #include "asterisk/module.h" diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c index a10aadae957..2ab511418d0 100644 --- a/cel/cel_odbc.c +++ b/cel/cel_odbc.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c index e4e280e41c7..8d9d5dfce71 100644 --- a/cel/cel_pgsql.c +++ b/cel/cel_pgsql.c @@ -44,8 +44,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/config.h" diff --git a/cel/cel_radius.c b/cel/cel_radius.c index f6ab8926771..e31cb5edc7c 100644 --- a/cel/cel_radius.c +++ b/cel/cel_radius.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef FREERADIUS_CLIENT #include #else diff --git a/cel/cel_sqlite3_custom.c b/cel/cel_sqlite3_custom.c index 07407829ca8..6075b8a2b5c 100644 --- a/cel/cel_sqlite3_custom.c +++ b/cel/cel_sqlite3_custom.c @@ -41,8 +41,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" diff --git a/cel/cel_tds.c b/cel/cel_tds.c index 30aa1fb0d85..0859fab7ac1 100644 --- a/cel/cel_tds.c +++ b/cel/cel_tds.c @@ -61,8 +61,6 @@ CREATE TABLE [dbo].[cel] ( #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 0e2b2577fbe..d09dc1c5347 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_bridge_media.c b/channels/chan_bridge_media.c index 8e177ae0c4f..118e08ee9a3 100644 --- a/channels/chan_bridge_media.c +++ b/channels/chan_bridge_media.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/bridge.h" #include "asterisk/core_unreal.h" diff --git a/channels/chan_console.c b/channels/chan_console.c index bd849ad5329..a24a6c8aff3 100644 --- a/channels/chan_console.c +++ b/channels/chan_console.c @@ -62,8 +62,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include /* SIGURG */ #include diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 8cccf843b42..78ebaa32d5c 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -54,8 +54,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #if defined(__NetBSD__) || defined(__FreeBSD__) #include #endif diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 04cdad1e407..e2f575d048d 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -58,8 +58,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 6df5d3fd0fc..af79e218e9c 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index 67f009d5024..dc18d719697 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -81,8 +81,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_motif.c b/channels/chan_motif.c index 0c710923f68..5828a11559f 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -44,8 +44,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c index d50defeaf91..61e5398c30e 100644 --- a/channels/chan_nbs.c +++ b/channels/chan_nbs.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 94de58da001..0d1e24ab711 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include /* isalnum() used here */ #include #include diff --git a/channels/chan_phone.c b/channels/chan_phone.c index b7f694f815b..aa10a56202d 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index ea06d6757f8..1c1f918c4ea 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -38,8 +38,6 @@ #include #include -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/channel.h" #include "asterisk/module.h" diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index f1f4f05b93f..1c824fecc2b 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/module.h" #include "asterisk/pbx.h" diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 40ef6409a91..e3a638a9f66 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -221,8 +221,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index fb6e619a1e5..0ef01663574 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 5b64f963bf3..4ad17dc66b7 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -38,8 +38,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index 1f4b861c153..595ac8fee2c 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -59,8 +59,6 @@ extern "C" { #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/utils.h" #include "asterisk/channel.h" diff --git a/channels/console_board.c b/channels/console_board.c index 7755c449f65..e5ff1fcbda5 100644 --- a/channels/console_board.c +++ b/channels/console_board.c @@ -42,7 +42,6 @@ ***/ #include "asterisk.h" /* ast_strdupa */ -ASTERISK_REGISTER_FILE() #include "asterisk/utils.h" /* ast_strdupa */ #include "console_video.h" /* ast_strdupa */ diff --git a/channels/console_video.c b/channels/console_video.c index da651baacb6..de81a8a9041 100644 --- a/channels/console_video.c +++ b/channels/console_video.c @@ -41,7 +41,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include #include "asterisk/cli.h" #include "asterisk/file.h" diff --git a/channels/dahdi/bridge_native_dahdi.c b/channels/dahdi/bridge_native_dahdi.c index 234228bd597..3302188cb83 100644 --- a/channels/dahdi/bridge_native_dahdi.c +++ b/channels/dahdi/bridge_native_dahdi.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "../sig_analog.h" #if defined(HAVE_PRI) #include "../sig_pri.h" diff --git a/channels/iax2/codec_pref.c b/channels/iax2/codec_pref.c index fba06a1ed12..7811ca86b21 100644 --- a/channels/iax2/codec_pref.c +++ b/channels/iax2/codec_pref.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/astobj2.h" #include "asterisk/codec.h" diff --git a/channels/iax2/firmware.c b/channels/iax2/firmware.c index 7e43bef43b7..00a9d9ebbeb 100644 --- a/channels/iax2/firmware.c +++ b/channels/iax2/firmware.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/iax2/format_compatibility.c b/channels/iax2/format_compatibility.c index 72fabf11608..1543792a9d7 100644 --- a/channels/iax2/format_compatibility.c +++ b/channels/iax2/format_compatibility.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/astobj2.h" #include "asterisk/codec.h" diff --git a/channels/iax2/parser.c b/channels/iax2/parser.c index 7538100703c..ec9d34608d8 100644 --- a/channels/iax2/parser.c +++ b/channels/iax2/parser.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/iax2/provision.c b/channels/iax2/provision.c index fcad2fe112d..6bd06faf93d 100644 --- a/channels/iax2/provision.c +++ b/channels/iax2/provision.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/misdn_config.c b/channels/misdn_config.c index ef644f2cbb7..bfb3e32ea94 100644 --- a/channels/misdn_config.c +++ b/channels/misdn_config.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "chan_misdn_config.h" #include "asterisk/config.h" diff --git a/channels/pjsip/cli_commands.c b/channels/pjsip/cli_commands.c index 8d99379ffc8..8ea39d144a8 100644 --- a/channels/pjsip/cli_commands.c +++ b/channels/pjsip/cli_commands.c @@ -26,8 +26,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 4d888c8faa4..c3fe848e4ac 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -432,8 +432,6 @@ #include #include -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/module.h" #include "asterisk/acl.h" diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index 036f7f7d237..4674901bee6 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "include/sip.h" #include "include/config_parser.h" #include "include/sip_utils.h" diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c index 53d15dddb6d..e21bb2c240c 100644 --- a/channels/sip/dialplan_functions.c +++ b/channels/sip/dialplan_functions.c @@ -107,8 +107,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/channel.h" diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c index 358d6e568cf..4d914460044 100644 --- a/channels/sip/reqresp_parser.c +++ b/channels/sip/reqresp_parser.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "include/sip.h" #include "include/sip_utils.h" #include "include/reqresp_parser.h" diff --git a/channels/sip/route.c b/channels/sip/route.c index 53f8805e2bd..584b46b7043 100644 --- a/channels/sip/route.c +++ b/channels/sip/route.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "include/route.h" diff --git a/channels/sip/security_events.c b/channels/sip/security_events.c index 22b767c44cd..b51c4736c35 100644 --- a/channels/sip/security_events.c +++ b/channels/sip/security_events.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "include/sip.h" #include "include/security_events.h" diff --git a/channels/vgrabbers.c b/channels/vgrabbers.c index ce8bb2b7d41..25817407e99 100644 --- a/channels/vgrabbers.c +++ b/channels/vgrabbers.c @@ -49,7 +49,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include #include "asterisk/file.h" #include "asterisk/utils.h" /* ast_calloc */ diff --git a/codecs/codec_a_mu.c b/codecs/codec_a_mu.c index a831abfcfe4..ea8d01488c4 100644 --- a/codecs/codec_a_mu.c +++ b/codecs/codec_a_mu.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/translate.h" #include "asterisk/alaw.h" diff --git a/codecs/codec_adpcm.c b/codecs/codec_adpcm.c index fa5d8769cb5..3076d264e2b 100644 --- a/codecs/codec_adpcm.c +++ b/codecs/codec_adpcm.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/linkedlists.h" #include "asterisk/module.h" diff --git a/codecs/codec_alaw.c b/codecs/codec_alaw.c index 515835dd7f4..ba16936b551 100644 --- a/codecs/codec_alaw.c +++ b/codecs/codec_alaw.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/config.h" #include "asterisk/translate.h" diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c index baa73f229d5..2d08d36cd57 100644 --- a/codecs/codec_dahdi.c +++ b/codecs/codec_dahdi.c @@ -34,8 +34,6 @@ #include "asterisk.h" #include -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/codecs/codec_g722.c b/codecs/codec_g722.c index d368c38af19..9c868d3d9ba 100644 --- a/codecs/codec_g722.c +++ b/codecs/codec_g722.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/linkedlists.h" #include "asterisk/module.h" #include "asterisk/config.h" diff --git a/codecs/codec_g726.c b/codecs/codec_g726.c index 8b44cbbd941..4bf39b7cec0 100644 --- a/codecs/codec_g726.c +++ b/codecs/codec_g726.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/linkedlists.h" #include "asterisk/module.h" diff --git a/codecs/codec_gsm.c b/codecs/codec_gsm.c index f80c955a6b4..2ae42a6c0c5 100644 --- a/codecs/codec_gsm.c +++ b/codecs/codec_gsm.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/translate.h" #include "asterisk/config.h" #include "asterisk/module.h" diff --git a/codecs/codec_ilbc.c b/codecs/codec_ilbc.c index fc713beb776..16466a9c9d4 100644 --- a/codecs/codec_ilbc.c +++ b/codecs/codec_ilbc.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/codec.h" /* for AST_MEDIA_TYPE_AUDIO */ #include "asterisk/format.h" /* for ast_format_get_attribute_data */ #include "asterisk/frame.h" /* for ast_frame, etc */ diff --git a/codecs/codec_lpc10.c b/codecs/codec_lpc10.c index e6dcf8c994f..5f6ffff8716 100644 --- a/codecs/codec_lpc10.c +++ b/codecs/codec_lpc10.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/translate.h" #include "asterisk/config.h" #include "asterisk/module.h" diff --git a/codecs/codec_resample.c b/codecs/codec_resample.c index 1c73bf3c8ed..b54f5c92197 100644 --- a/codecs/codec_resample.c +++ b/codecs/codec_resample.c @@ -32,8 +32,6 @@ #include "asterisk.h" #include "speex/speex_resampler.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/translate.h" #include "asterisk/slin.h" diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c index ca48eae6227..49990e988e8 100644 --- a/codecs/codec_speex.c +++ b/codecs/codec_speex.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include /* We require a post 1.1.8 version of Speex to enable preprocessing diff --git a/codecs/codec_ulaw.c b/codecs/codec_ulaw.c index ca2f411f93b..cf4e358da97 100644 --- a/codecs/codec_ulaw.c +++ b/codecs/codec_ulaw.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/config.h" #include "asterisk/translate.h" diff --git a/formats/format_g719.c b/formats/format_g719.c index f6807b9ca92..8cc942717a8 100644 --- a/formats/format_g719.c +++ b/formats/format_g719.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_g723.c b/formats/format_g723.c index 777cd746b9e..750bacaf153 100644 --- a/formats/format_g723.c +++ b/formats/format_g723.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/format_cache.h" diff --git a/formats/format_g726.c b/formats/format_g726.c index 684275c2b43..f3b09f0351e 100644 --- a/formats/format_g726.c +++ b/formats/format_g726.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_g729.c b/formats/format_g729.c index 69e6a2563b4..6e0632c5351 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_gsm.c b/formats/format_gsm.c index bf82dd5c636..777d49a636f 100644 --- a/formats/format_gsm.c +++ b/formats/format_gsm.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_h263.c b/formats/format_h263.c index f02d030772b..027f604f4ac 100644 --- a/formats/format_h263.c +++ b/formats/format_h263.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_h264.c b/formats/format_h264.c index 63330913842..38f2734f3c1 100644 --- a/formats/format_h264.c +++ b/formats/format_h264.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c index e07eedba0e2..b556d6cc854 100644 --- a/formats/format_ilbc.c +++ b/formats/format_ilbc.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c index ed21f88f848..f69c547d360 100644 --- a/formats/format_jpeg.c +++ b/formats/format_jpeg.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/image.h" diff --git a/formats/format_ogg_speex.c b/formats/format_ogg_speex.c index 6152e9c52ec..747adb37ff7 100644 --- a/formats/format_ogg_speex.c +++ b/formats/format_ogg_speex.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/format_cache.h" diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c index 0daf64cba9f..4c42181fcfb 100644 --- a/formats/format_ogg_vorbis.c +++ b/formats/format_ogg_vorbis.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/formats/format_pcm.c b/formats/format_pcm.c index 6361cd00f40..0b1706e504a 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_siren14.c b/formats/format_siren14.c index 71de82e98ba..1ce7d18ad29 100644 --- a/formats/format_siren14.c +++ b/formats/format_siren14.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_siren7.c b/formats/format_siren7.c index 2fcc131a314..d2059844571 100644 --- a/formats/format_siren7.c +++ b/formats/format_siren7.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_sln.c b/formats/format_sln.c index 68aa74d475d..32972d09d07 100644 --- a/formats/format_sln.c +++ b/formats/format_sln.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_vox.c b/formats/format_vox.c index 5107ab9183f..eb8ab0eadb1 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_wav.c b/formats/format_wav.c index 688c3e7e410..a415140f9f3 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c index d5661fbf68c..21a8508059f 100644 --- a/formats/format_wav_gsm.c +++ b/formats/format_wav_gsm.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" diff --git a/funcs/func_aes.c b/funcs/func_aes.c index d80636f6da6..9392a1c7db7 100644 --- a/funcs/func_aes.c +++ b/funcs/func_aes.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/pbx.h" #include "asterisk/app.h" diff --git a/funcs/func_base64.c b/funcs/func_base64.c index 5352e172c26..16619d53232 100644 --- a/funcs/func_base64.c +++ b/funcs/func_base64.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/pbx.h" /* function register/unregister */ #include "asterisk/utils.h" diff --git a/funcs/func_blacklist.c b/funcs/func_blacklist.c index 5d3d4b9c9b8..fdc899b9ab2 100644 --- a/funcs/func_blacklist.c +++ b/funcs/func_blacklist.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/channel.h" diff --git a/funcs/func_callcompletion.c b/funcs/func_callcompletion.c index d50774fa9dc..ed5238c1f04 100644 --- a/funcs/func_callcompletion.c +++ b/funcs/func_callcompletion.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/ccss.h" diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c index 133e2592240..527babb9333 100644 --- a/funcs/func_callerid.c +++ b/funcs/func_callerid.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 8dcb2bd0b2d..83942db4cd2 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_channel.c b/funcs/func_channel.c index e816dcae00c..27e9f41bf7d 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/funcs/func_config.c b/funcs/func_config.c index 64676c01176..7279cc90032 100644 --- a/funcs/func_config.c +++ b/funcs/func_config.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_curl.c b/funcs/func_curl.c index 8ec1032a764..2974b3c522d 100644 --- a/funcs/func_curl.c +++ b/funcs/func_curl.c @@ -37,8 +37,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/funcs/func_cut.c b/funcs/func_cut.c index 23995ba9123..c8cda134b04 100644 --- a/funcs/func_cut.c +++ b/funcs/func_cut.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_db.c b/funcs/func_db.c index f031645a935..b2ccb237e74 100644 --- a/funcs/func_db.c +++ b/funcs/func_db.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/funcs/func_devstate.c b/funcs/func_devstate.c index d86f54eb95e..965c7c79430 100644 --- a/funcs/func_devstate.c +++ b/funcs/func_devstate.c @@ -36,8 +36,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_dialgroup.c b/funcs/func_dialgroup.c index f6723119dc9..e5780001064 100644 --- a/funcs/func_dialgroup.c +++ b/funcs/func_dialgroup.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/funcs/func_dialplan.c b/funcs/func_dialplan.c index 0a5220b0907..6eaa03c8929 100644 --- a/funcs/func_dialplan.c +++ b/funcs/func_dialplan.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_enum.c b/funcs/func_enum.c index 58a05c0329e..2e86625aec7 100644 --- a/funcs/func_enum.c +++ b/funcs/func_enum.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_env.c b/funcs/func_env.c index 3883de60164..1b11b1fa7cf 100644 --- a/funcs/func_env.c +++ b/funcs/func_env.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include /* stat(2) */ #include "asterisk/module.h" diff --git a/funcs/func_extstate.c b/funcs/func_extstate.c index 025d4975de8..d20fb2a0ba0 100644 --- a/funcs/func_extstate.c +++ b/funcs/func_extstate.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c index e8c10945805..08c426161a2 100644 --- a/funcs/func_frame_trace.c +++ b/funcs/func_frame_trace.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_global.c b/funcs/func_global.c index 23e69d335e9..795ddaf61fc 100644 --- a/funcs/func_global.c +++ b/funcs/func_global.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/funcs/func_groupcount.c b/funcs/func_groupcount.c index 9708ca7c0cf..2b6ed40524e 100644 --- a/funcs/func_groupcount.c +++ b/funcs/func_groupcount.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_hangupcause.c b/funcs/func_hangupcause.c index 043e480f3b6..2b4f9c51855 100644 --- a/funcs/func_hangupcause.c +++ b/funcs/func_hangupcause.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_holdintercept.c b/funcs/func_holdintercept.c index 3e348c1cf1b..c2435463a0d 100644 --- a/funcs/func_holdintercept.c +++ b/funcs/func_holdintercept.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_iconv.c b/funcs/func_iconv.c index db52b118011..10ba1bb5f60 100644 --- a/funcs/func_iconv.c +++ b/funcs/func_iconv.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/funcs/func_jitterbuffer.c b/funcs/func_jitterbuffer.c index ef7ff71390a..65aea537777 100644 --- a/funcs/func_jitterbuffer.c +++ b/funcs/func_jitterbuffer.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/framehook.h" diff --git a/funcs/func_lock.c b/funcs/func_lock.c index 7bb50f5e344..88bf6e5bd30 100644 --- a/funcs/func_lock.c +++ b/funcs/func_lock.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/funcs/func_logic.c b/funcs/func_logic.c index 8724ff51f5f..1ec0b0c50a2 100644 --- a/funcs/func_logic.c +++ b/funcs/func_logic.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_math.c b/funcs/func_math.c index ae130588715..6fc725581b1 100644 --- a/funcs/func_math.c +++ b/funcs/func_math.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/funcs/func_md5.c b/funcs/func_md5.c index ff36c9e37e5..101c1fd729e 100644 --- a/funcs/func_md5.c +++ b/funcs/func_md5.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/pbx.h" diff --git a/funcs/func_module.c b/funcs/func_module.c index 143804a07cd..824d99294af 100644 --- a/funcs/func_module.c +++ b/funcs/func_module.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/pbx.h" diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index 224cd7a7f68..e014b633c60 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/file.h" #include "asterisk/channel.h" diff --git a/funcs/func_periodic_hook.c b/funcs/func_periodic_hook.c index bb0ee0db7de..aae2abc90ec 100644 --- a/funcs/func_periodic_hook.c +++ b/funcs/func_periodic_hook.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_pitchshift.c b/funcs/func_pitchshift.c index 829498ab12d..a995d42f1d4 100644 --- a/funcs/func_pitchshift.c +++ b/funcs/func_pitchshift.c @@ -64,8 +64,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_pjsip_aor.c b/funcs/func_pjsip_aor.c index 835955e1bc2..799e9e4ed5a 100644 --- a/funcs/func_pjsip_aor.c +++ b/funcs/func_pjsip_aor.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/funcs/func_pjsip_contact.c b/funcs/func_pjsip_contact.c index e9737049d84..c8403655ab1 100644 --- a/funcs/func_pjsip_contact.c +++ b/funcs/func_pjsip_contact.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/funcs/func_pjsip_endpoint.c b/funcs/func_pjsip_endpoint.c index ef544f367d3..a64d93b1edb 100644 --- a/funcs/func_pjsip_endpoint.c +++ b/funcs/func_pjsip_endpoint.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/funcs/func_presencestate.c b/funcs/func_presencestate.c index d7d6b2439ac..0f2a431427e 100644 --- a/funcs/func_presencestate.c +++ b/funcs/func_presencestate.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_rand.c b/funcs/func_rand.c index cc34517dc2a..bc514b80c98 100644 --- a/funcs/func_rand.c +++ b/funcs/func_rand.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_realtime.c b/funcs/func_realtime.c index 0ce191b543a..e0ba4a5a18e 100644 --- a/funcs/func_realtime.c +++ b/funcs/func_realtime.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_sha1.c b/funcs/func_sha1.c index 9f596c4fe2b..a3787b108c0 100644 --- a/funcs/func_sha1.c +++ b/funcs/func_sha1.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/pbx.h" diff --git a/funcs/func_shell.c b/funcs/func_shell.c index f529cbf724b..0398cd83960 100644 --- a/funcs/func_shell.c +++ b/funcs/func_shell.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_sorcery.c b/funcs/func_sorcery.c index 8c1697abaca..d4d8be2f238 100644 --- a/funcs/func_sorcery.c +++ b/funcs/func_sorcery.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/pbx.h" #include "asterisk/module.h" diff --git a/funcs/func_speex.c b/funcs/func_speex.c index a4cfa17b34b..78ac4baab9c 100644 --- a/funcs/func_speex.c +++ b/funcs/func_speex.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" #include "asterisk/channel.h" diff --git a/funcs/func_sprintf.c b/funcs/func_sprintf.c index 822937e55da..03d7bb27b0c 100644 --- a/funcs/func_sprintf.c +++ b/funcs/func_sprintf.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/funcs/func_srv.c b/funcs/func_srv.c index 79a24db00bb..17d7d7a9396 100644 --- a/funcs/func_srv.c +++ b/funcs/func_srv.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/srv.h" #include "asterisk/pbx.h" diff --git a/funcs/func_strings.c b/funcs/func_strings.c index 255e8465312..885de61c57e 100644 --- a/funcs/func_strings.c +++ b/funcs/func_strings.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/funcs/func_sysinfo.c b/funcs/func_sysinfo.c index 9d8b765e464..d0a874e3ad0 100644 --- a/funcs/func_sysinfo.c +++ b/funcs/func_sysinfo.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #if defined(HAVE_SYSINFO) #include #endif diff --git a/funcs/func_talkdetect.c b/funcs/func_talkdetect.c index b8dd2d45830..02963f20e4f 100644 --- a/funcs/func_talkdetect.c +++ b/funcs/func_talkdetect.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_timeout.c b/funcs/func_timeout.c index 1cb6b8dd4f9..05a02e15879 100644 --- a/funcs/func_timeout.c +++ b/funcs/func_timeout.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_uri.c b/funcs/func_uri.c index b7f891b70fd..dfdeae9feac 100644 --- a/funcs/func_uri.c +++ b/funcs/func_uri.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_version.c b/funcs/func_version.c index 5ccff8273ad..e2463028853 100644 --- a/funcs/func_version.c +++ b/funcs/func_version.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/funcs/func_vmcount.c b/funcs/func_vmcount.c index 2c3563192fe..be919dda18f 100644 --- a/funcs/func_vmcount.c +++ b/funcs/func_vmcount.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/file.h" diff --git a/funcs/func_volume.c b/funcs/func_volume.c index a8f84586d7e..fdf2064d562 100644 --- a/funcs/func_volume.c +++ b/funcs/func_volume.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/include/asterisk.h b/include/asterisk.h index f5ed0916754..25737805bca 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -152,78 +152,9 @@ int ast_shutting_down(void); */ int ast_shutdown_final(void); -/*! - * \brief Register the version of a source code file with the core. - * \param file the source file name - * \return nothing - * - * This function should not be called directly, but instead the - * ASTERISK_REGISTER_FILE macro should be used to register a file with the core. - */ -void __ast_register_file(const char *file); - -/*! - * \brief Unregister a source code file from the core. - * \param file the source file name - * \return nothing - * - * This function should not be called directly, but instead the - * ASTERISK_REGISTER_FILE macro should be used to automatically unregister - * the file when the module is unloaded. - */ -void __ast_unregister_file(const char *file); - -/*! - * \brief Complete a source file name - * \param partial The partial name of the file to look up. - * \param n The n-th match to return. - * - * \retval NULL if there is no match for partial at the n-th position - * \retval Matching source file name - * - * \note A matching source file is allocataed on the heap, and must be - * free'd by the caller. - */ -char *ast_complete_source_filename(const char *partial, int n); - -/*! - * \brief Register/unregister a source code file with the core. - * - * This macro will place a file-scope constructor and destructor into the - * source of the module using it; this will cause the file to be - * registered with the Asterisk core (and unregistered) at the appropriate - * times. - * - * Example: - * - * \code - * ASTERISK_REGISTER_FILE() - * \endcode - */ #ifdef MTX_PROFILE #define HAVE_MTX_PROFILE /* used in lock.h */ -#define ASTERISK_REGISTER_FILE() \ - static int mtx_prof = -1; /* profile mutex */ \ - static void __attribute__((constructor)) __register_file_version(void) \ - { \ - mtx_prof = ast_add_profile("mtx_lock_" __FILE__, 0); \ - __ast_register_file(__FILE__); \ - } \ - static void __attribute__((destructor)) __unregister_file_version(void) \ - { \ - __ast_unregister_file(__FILE__); \ - } -#else /* !MTX_PROFILE */ -#define ASTERISK_REGISTER_FILE() \ - static void __attribute__((constructor)) __register_file_version(void) \ - { \ - __ast_register_file(__FILE__); \ - } \ - static void __attribute__((destructor)) __unregister_file_version(void) \ - { \ - __ast_unregister_file(__FILE__); \ - } -#endif /* !MTX_PROFILE */ +#endif /* MTX_PROFILE */ /*! * \brief support for event profiling diff --git a/main/abstract_jb.c b/main/abstract_jb.c index c703c68727d..264ee97e620 100644 --- a/main/abstract_jb.c +++ b/main/abstract_jb.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/frame.h" #include "asterisk/channel.h" #include "asterisk/term.h" diff --git a/main/acl.c b/main/acl.c index d133b2a0719..1c35be86df4 100644 --- a/main/acl.c +++ b/main/acl.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/network.h" #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__) diff --git a/main/alaw.c b/main/alaw.c index 3b9bfd6b9c5..08de0fe63f0 100644 --- a/main/alaw.c +++ b/main/alaw.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/alaw.h" #include "asterisk/logger.h" diff --git a/main/aoc.c b/main/aoc.c index 8d4332901f6..d4b74ec921b 100644 --- a/main/aoc.c +++ b/main/aoc.c @@ -28,7 +28,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); #include "asterisk/aoc.h" #include "asterisk/utils.h" diff --git a/main/app.c b/main/app.c index e1d70498cf3..621153e250a 100644 --- a/main/app.c +++ b/main/app.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef HAVE_SYS_STAT_H #include #endif diff --git a/main/ast_expr2.c b/main/ast_expr2.c index 215f8312fd3..4b06ffe91c8 100644 --- a/main/ast_expr2.c +++ b/main/ast_expr2.c @@ -98,10 +98,7 @@ #include #include -#if !defined(STANDALONE) && !defined(STANDALONE2) \ - -ASTERISK_REGISTER_FILE() -#else +#if defined(STANDALONE) || defined(STANDALONE2) #ifndef __USE_ISOC99 #define __USE_ISOC99 1 #endif diff --git a/main/ast_expr2.fl b/main/ast_expr2.fl index af03c013fae..542f01817f9 100644 --- a/main/ast_expr2.fl +++ b/main/ast_expr2.fl @@ -25,9 +25,7 @@ #include #include -#if !defined(STANDALONE) -ASTERISK_REGISTER_FILE() -#else +#if defined(STANDALONE) #ifndef __USE_ISOC99 #define __USE_ISOC99 1 #endif diff --git a/main/ast_expr2.y b/main/ast_expr2.y index 8b32b2b9c01..f516291f9c3 100644 --- a/main/ast_expr2.y +++ b/main/ast_expr2.y @@ -19,10 +19,7 @@ #include #include -#if !defined(STANDALONE) && !defined(STANDALONE2) \ - -ASTERISK_REGISTER_FILE() -#else +#if defined(STANDALONE) || defined(STANDALONE2) #ifndef __USE_ISOC99 #define __USE_ISOC99 1 #endif diff --git a/main/ast_expr2f.c b/main/ast_expr2f.c index c6a1b97353b..f6fa6b43fee 100644 --- a/main/ast_expr2f.c +++ b/main/ast_expr2f.c @@ -520,9 +520,7 @@ static yyconst flex_int16_t yy_chk[159] = #include #include -#if !defined(STANDALONE) -ASTERISK_REGISTER_FILE() -#else +#if defined(STANDALONE) #ifndef __USE_ISOC99 #define __USE_ISOC99 1 #endif diff --git a/main/asterisk.c b/main/asterisk.c index 7fc0912c48c..d4b39a26521 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -149,8 +149,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #undef sched_setscheduler @@ -487,75 +485,6 @@ static struct { unsigned int need_quit_handler:1; } sig_flags; -#if !defined(LOW_MEMORY) -struct registered_file { - AST_RWLIST_ENTRY(registered_file) list; - const char *file; -}; - -static AST_RWLIST_HEAD_STATIC(registered_files, registered_file); -#endif /* ! LOW_MEMORY */ - -void __ast_register_file(const char *file) -{ -#if !defined(LOW_MEMORY) - struct registered_file *reg; - - reg = ast_calloc(1, sizeof(*reg)); - if (!reg) { - return; - } - - reg->file = file; - AST_RWLIST_WRLOCK(®istered_files); - AST_RWLIST_INSERT_HEAD(®istered_files, reg, list); - AST_RWLIST_UNLOCK(®istered_files); -#endif /* ! LOW_MEMORY */ -} - -void __ast_unregister_file(const char *file) -{ -#if !defined(LOW_MEMORY) - struct registered_file *find; - - AST_RWLIST_WRLOCK(®istered_files); - AST_RWLIST_TRAVERSE_SAFE_BEGIN(®istered_files, find, list) { - if (!strcasecmp(find->file, file)) { - AST_RWLIST_REMOVE_CURRENT(list); - break; - } - } - AST_RWLIST_TRAVERSE_SAFE_END; - AST_RWLIST_UNLOCK(®istered_files); - - if (find) { - ast_free(find); - } -#endif /* ! LOW_MEMORY */ -} - -char *ast_complete_source_filename(const char *partial, int n) -{ -#if !defined(LOW_MEMORY) - struct registered_file *find; - size_t len = strlen(partial); - int count = 0; - char *res = NULL; - - AST_RWLIST_RDLOCK(®istered_files); - AST_RWLIST_TRAVERSE(®istered_files, find, list) { - if (!strncasecmp(find->file, partial, len) && ++count > n) { - res = ast_strdup(find->file); - break; - } - } - AST_RWLIST_UNLOCK(®istered_files); - return res; -#else /* if defined(LOW_MEMORY) */ - return NULL; -#endif -} - #if !defined(LOW_MEMORY) struct thread_list_t { AST_RWLIST_ENTRY(thread_list_t) list; diff --git a/main/astfd.c b/main/astfd.c index 0a5e7ec801c..34cf7bb6f3b 100644 --- a/main/astfd.c +++ b/main/astfd.c @@ -31,8 +31,6 @@ #ifdef DEBUG_FD_LEAKS -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/astmm.c b/main/astmm.c index 1599d107a7e..0ad29a6fb8e 100644 --- a/main/astmm.c +++ b/main/astmm.c @@ -33,8 +33,6 @@ #if defined(__AST_DEBUG_MALLOC) -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */ #include #include diff --git a/main/astobj2.c b/main/astobj2.c index 72bfcc8198a..114f260454d 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "astobj2_private.h" diff --git a/main/astobj2_container.c b/main/astobj2_container.c index 15fd41286b0..a978db3d467 100644 --- a/main/astobj2_container.c +++ b/main/astobj2_container.c @@ -22,8 +22,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "astobj2_private.h" diff --git a/main/astobj2_hash.c b/main/astobj2_hash.c index eee90f513b8..b1a8c1ce435 100644 --- a/main/astobj2_hash.c +++ b/main/astobj2_hash.c @@ -23,8 +23,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "astobj2_private.h" diff --git a/main/astobj2_rbtree.c b/main/astobj2_rbtree.c index 1760938fcb7..61ab37b5687 100644 --- a/main/astobj2_rbtree.c +++ b/main/astobj2_rbtree.c @@ -23,8 +23,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "asterisk/utils.h" diff --git a/main/audiohook.c b/main/audiohook.c index 4a73fbd52e9..8a0055e4b46 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/channel.h" diff --git a/main/autochan.c b/main/autochan.c index 38d778438cb..c7e5c004258 100644 --- a/main/autochan.c +++ b/main/autochan.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/autochan.h" #include "asterisk/utils.h" #include "asterisk/linkedlists.h" diff --git a/main/autoservice.c b/main/autoservice.c index 1af052d0889..11c9eab969d 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/main/backtrace.c b/main/backtrace.c index 3b490e8c3c8..0b29385fdc4 100644 --- a/main/backtrace.c +++ b/main/backtrace.c @@ -27,7 +27,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); #include "asterisk/backtrace.h" #include "asterisk/utils.h" diff --git a/main/bridge.c b/main/bridge.c index e92875d1785..cd8ce99b4d5 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -83,8 +83,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/channel.h" #include "asterisk/options.h" diff --git a/main/bridge_after.c b/main/bridge_after.c index e2f14ab611b..d649717e2b8 100644 --- a/main/bridge_after.c +++ b/main/bridge_after.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/main/bridge_basic.c b/main/bridge_basic.c index 6c411fbaf2a..e31f3856134 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/utils.h" #include "asterisk/linkedlists.h" diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 18f71950619..722fc668785 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/heap.h" diff --git a/main/bridge_roles.c b/main/bridge_roles.c index 0305237351f..a9b95a35214 100644 --- a/main/bridge_roles.c +++ b/main/bridge_roles.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/logger.h" diff --git a/main/bucket.c b/main/bucket.c index 7b8c689a003..e00284842f5 100644 --- a/main/bucket.c +++ b/main/bucket.c @@ -60,8 +60,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef HAVE_URIPARSER #include #endif diff --git a/main/callerid.c b/main/callerid.c index d2b32189228..d6f8575fb28 100644 --- a/main/callerid.c +++ b/main/callerid.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/ccss.c b/main/ccss.c index 13831b71987..6c3e6cbee11 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -36,8 +36,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/strings.h" #include "asterisk/ccss.h" diff --git a/main/cdr.c b/main/cdr.c index baa17b96722..60fe977a886 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/main/cel.c b/main/cel.c index aafeea43264..faf4fde7164 100644 --- a/main/cel.c +++ b/main/cel.c @@ -38,8 +38,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/channel.h" diff --git a/main/channel.c b/main/channel.c index 4a9fe72a86a..cdb6569c3b5 100644 --- a/main/channel.c +++ b/main/channel.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 3c156d4fa21..1cb91e7c334 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/main/chanvars.c b/main/chanvars.c index d7922522cd4..2cc90e43a65 100644 --- a/main/chanvars.c +++ b/main/chanvars.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/chanvars.h" #include "asterisk/strings.h" #include "asterisk/utils.h" diff --git a/main/cli.c b/main/cli.c index 3ba743d75d4..632883d39f3 100644 --- a/main/cli.c +++ b/main/cli.c @@ -38,8 +38,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */ #include diff --git a/main/codec.c b/main/codec.c index 49356a22fb1..1870c393bc5 100644 --- a/main/codec.c +++ b/main/codec.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/codec.h" #include "asterisk/format.h" diff --git a/main/codec_builtin.c b/main/codec_builtin.c index 1f2cb927047..cc4edd23990 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/ilbc.h" #include "asterisk/logger.h" #include "asterisk/astobj2.h" diff --git a/main/config.c b/main/config.c index 6162149b167..a3e09f67ecc 100644 --- a/main/config.c +++ b/main/config.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */ #include "asterisk/network.h" /* we do some sockaddr manipulation here */ diff --git a/main/config_options.c b/main/config_options.c index 2d2300893dc..18b04ff7dcf 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/_private.h" diff --git a/main/core_local.c b/main/core_local.c index 6644aaf5094..aa232a4b6df 100644 --- a/main/core_local.c +++ b/main/core_local.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - /* ------------------------------------------------------------------- */ #include "asterisk/channel.h" diff --git a/main/core_unreal.c b/main/core_unreal.c index 28886b63595..5da7408770d 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/causes.h" #include "asterisk/channel.h" #include "asterisk/stasis_channels.h" diff --git a/main/crypt.c b/main/crypt.c index a4cf664b15b..924618205a4 100644 --- a/main/crypt.c +++ b/main/crypt.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #if defined(HAVE_CRYPT_R) #include diff --git a/main/data.c b/main/data.c index 1aaae18f184..15aca8b9d3d 100644 --- a/main/data.c +++ b/main/data.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include diff --git a/main/datastore.c b/main/datastore.c index e536d601bc9..1170e24f878 100644 --- a/main/datastore.c +++ b/main/datastore.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/datastore.h" diff --git a/main/db.c b/main/db.c index bb6e18bb55a..94324355f2a 100644 --- a/main/db.c +++ b/main/db.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/paths.h" /* use ast_config_AST_DB */ #include diff --git a/main/devicestate.c b/main/devicestate.c index 400d655f63c..1db9a1937f8 100644 --- a/main/devicestate.c +++ b/main/devicestate.c @@ -143,8 +143,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/channel.h" #include "asterisk/utils.h" diff --git a/main/dial.c b/main/dial.c index 7677c5a7d0f..cc2366ed7aa 100644 --- a/main/dial.c +++ b/main/dial.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/main/dns.c b/main/dns.c index fa94089e792..3b198a0f326 100644 --- a/main/dns.c +++ b/main/dns.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/network.h" #include /* res_* functions */ #include diff --git a/main/dns_core.c b/main/dns_core.c index cfce8efb084..e1cbc21916a 100644 --- a/main/dns_core.c +++ b/main/dns_core.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/linkedlists.h" #include "asterisk/astobj2.h" #include "asterisk/strings.h" diff --git a/main/dns_naptr.c b/main/dns_naptr.c index 4d5a5f99aed..d24e1b5f447 100644 --- a/main/dns_naptr.c +++ b/main/dns_naptr.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/dns_query_set.c b/main/dns_query_set.c index 40a89e168eb..e8492ddb3c3 100644 --- a/main/dns_query_set.c +++ b/main/dns_query_set.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/vector.h" #include "asterisk/astobj2.h" #include "asterisk/utils.h" @@ -283,4 +281,4 @@ int ast_dns_query_set_resolve_cancel(struct ast_dns_query_set *query_set) } return (query_set->queries_cancelled == query_count) ? 0 : -1; -} \ No newline at end of file +} diff --git a/main/dns_recurring.c b/main/dns_recurring.c index 99257550792..294438f34c3 100644 --- a/main/dns_recurring.c +++ b/main/dns_recurring.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/linkedlists.h" #include "asterisk/sched.h" diff --git a/main/dns_srv.c b/main/dns_srv.c index e4a3d8bbdb7..9d36fb61f9d 100644 --- a/main/dns_srv.c +++ b/main/dns_srv.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/dns_system_resolver.c b/main/dns_system_resolver.c index d57814874cd..9358577b6b8 100644 --- a/main/dns_system_resolver.c +++ b/main/dns_system_resolver.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "asterisk/dns.h" diff --git a/main/dns_tlsa.c b/main/dns_tlsa.c index 85db40b74bc..8ec7e10212b 100644 --- a/main/dns_tlsa.c +++ b/main/dns_tlsa.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/dns_core.h" #include "asterisk/dns_tlsa.h" diff --git a/main/dnsmgr.c b/main/dnsmgr.c index b976c68c536..0e5efd6da63 100644 --- a/main/dnsmgr.c +++ b/main/dnsmgr.c @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include #include diff --git a/main/dsp.c b/main/dsp.c index 1a3ebea6a15..e4e7fd3ebdd 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -55,8 +55,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/frame.h" diff --git a/main/endpoints.c b/main/endpoints.c index b73edd379a6..d31405244e0 100644 --- a/main/endpoints.c +++ b/main/endpoints.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/endpoints.h" #include "asterisk/stasis.h" diff --git a/main/enum.c b/main/enum.c index 865fa3a0787..5c217c43ca2 100644 --- a/main/enum.c +++ b/main/enum.c @@ -60,8 +60,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/event.c b/main/event.c index 3af03147e2e..1e623a19736 100644 --- a/main/event.c +++ b/main/event.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/event.h" diff --git a/main/features.c b/main/features.c index 0af5a78e3c3..ae16374b2e0 100644 --- a/main/features.c +++ b/main/features.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include diff --git a/main/file.c b/main/file.c index 450362544a9..639440830cb 100644 --- a/main/file.c +++ b/main/file.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/fixedjitterbuf.c b/main/fixedjitterbuf.c index db7c157c329..fc3e8cb664c 100644 --- a/main/fixedjitterbuf.c +++ b/main/fixedjitterbuf.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/utils.h" diff --git a/main/format.c b/main/format.c index cc9ac45d73a..b5e577913ed 100644 --- a/main/format.c +++ b/main/format.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/codec.h" #include "asterisk/format.h" diff --git a/main/format_cache.c b/main/format_cache.c index c704f1c379a..d0ae32e68dc 100644 --- a/main/format_cache.c +++ b/main/format_cache.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/format.h" #include "asterisk/format_cache.h" diff --git a/main/format_cap.c b/main/format_cap.c index ed7afc229a8..1fe342b3107 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/format.h" #include "asterisk/format_cap.h" diff --git a/main/format_compatibility.c b/main/format_compatibility.c index 9bf263b5b2c..84514ac8cdc 100644 --- a/main/format_compatibility.c +++ b/main/format_compatibility.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/astobj2.h" #include "asterisk/codec.h" diff --git a/main/frame.c b/main/frame.c index 92b92b6e2e1..0175c7226b4 100644 --- a/main/frame.c +++ b/main/frame.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/lock.h" #include "asterisk/frame.h" diff --git a/main/framehook.c b/main/framehook.c index e12b45931af..d17066d92b3 100644 --- a/main/framehook.c +++ b/main/framehook.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/linkedlists.h" #include "asterisk/framehook.h" diff --git a/main/fskmodem_float.c b/main/fskmodem_float.c index 98f0c173bab..5891191e6f3 100644 --- a/main/fskmodem_float.c +++ b/main/fskmodem_float.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/fskmodem.h" diff --git a/main/fskmodem_int.c b/main/fskmodem_int.c index 44ef928a82c..5c7f8ecf2cc 100644 --- a/main/fskmodem_int.c +++ b/main/fskmodem_int.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/fskmodem.h" #define NBW 2 diff --git a/main/global_datastores.c b/main/global_datastores.c index 8ba769d3d2f..521106defe3 100644 --- a/main/global_datastores.c +++ b/main/global_datastores.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/global_datastores.h" static void secure_call_store_destroy(void *data) diff --git a/main/hashtab.c b/main/hashtab.c index 3719c2ad437..3d7b1991c6f 100644 --- a/main/hashtab.c +++ b/main/hashtab.c @@ -29,8 +29,6 @@ #define ASTMM_LIBC ASTMM_REDIRECT #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/main/heap.c b/main/heap.c index 73280fedc1e..0f0bafd18ee 100644 --- a/main/heap.c +++ b/main/heap.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/heap.h" #include "asterisk/utils.h" #include "asterisk/cli.h" diff --git a/main/http.c b/main/http.c index da564da203a..77feb397bba 100644 --- a/main/http.c +++ b/main/http.c @@ -44,8 +44,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/image.c b/main/image.c index 22c3a016c2e..b007ae1602a 100644 --- a/main/image.c +++ b/main/image.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/indications.c b/main/indications.c index 0f0e401d983..0af6668cfc0 100644 --- a/main/indications.c +++ b/main/indications.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/lock.h" diff --git a/main/io.c b/main/io.c index 3441fbae9ff..b063c22396c 100644 --- a/main/io.c +++ b/main/io.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/main/jitterbuf.c b/main/jitterbuf.c index 0e93507ef8a..4795b6d06af 100644 --- a/main/jitterbuf.c +++ b/main/jitterbuf.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "jitterbuf.h" #include "asterisk/utils.h" diff --git a/main/json.c b/main/json.c index ca74f85dc00..7b5cfbe7e6e 100644 --- a/main/json.c +++ b/main/json.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/json.h" #include "asterisk/localtime.h" #include "asterisk/module.h" diff --git a/main/libasteriskpj.c b/main/libasteriskpj.c index aed0ec8b146..22660e686a6 100644 --- a/main/libasteriskpj.c +++ b/main/libasteriskpj.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef HAVE_PJPROJECT #include #endif diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c index 7603465c746..16a1aa7395c 100644 --- a/main/libasteriskssl.c +++ b/main/libasteriskssl.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef HAVE_OPENSSL #include #include diff --git a/main/loader.c b/main/loader.c index 36a3d5f61b6..6617783cf28 100644 --- a/main/loader.c +++ b/main/loader.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */ #include diff --git a/main/lock.c b/main/lock.c index b35ec597c63..9c1d3838326 100644 --- a/main/lock.c +++ b/main/lock.c @@ -27,7 +27,14 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() +#ifdef HAVE_MTX_PROFILE +/* profile mutex */ +static int mtx_prof = -1; +static void __attribute__((constructor)) __mtx_init(void) +{ + mtx_prof = ast_add_profile("mtx_lock_" __FILE__, 0); +} +#endif #include "asterisk/utils.h" #include "asterisk/lock.h" diff --git a/main/logger.c b/main/logger.c index 7d0d2de1e49..146d9198555 100644 --- a/main/logger.c +++ b/main/logger.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - /* When we include logger.h again it will trample on some stuff in syslog.h, but * nothing we care about in here. */ #include diff --git a/main/manager.c b/main/manager.c index 32322b8c517..ef1afb03d31 100644 --- a/main/manager.c +++ b/main/manager.c @@ -54,8 +54,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" /* use various ast_config_AST_* */ #include #include diff --git a/main/manager_bridges.c b/main/manager_bridges.c index b6aaa550e63..c6e997f42c7 100644 --- a/main/manager_bridges.c +++ b/main/manager_bridges.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/stasis_bridges.h" #include "asterisk/stasis_channels.h" #include "asterisk/manager.h" diff --git a/main/manager_channels.c b/main/manager_channels.c index ce0e38d9c0a..7f3c1b6458c 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/callerid.h" #include "asterisk/channel.h" #include "asterisk/manager.h" diff --git a/main/manager_endpoints.c b/main/manager_endpoints.c index ffcdef06f94..3b488ddbabc 100644 --- a/main/manager_endpoints.c +++ b/main/manager_endpoints.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/callerid.h" #include "asterisk/channel.h" #include "asterisk/manager.h" diff --git a/main/manager_mwi.c b/main/manager_mwi.c index 7492f78a9a6..a7f94de2477 100644 --- a/main/manager_mwi.c +++ b/main/manager_mwi.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/manager.h" #include "asterisk/app.h" #include "asterisk/channel.h" diff --git a/main/manager_system.c b/main/manager_system.c index 8417b7741af..b20deea65fe 100644 --- a/main/manager_system.c +++ b/main/manager_system.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/stasis.h" #include "asterisk/stasis_message_router.h" #include "asterisk/stasis_system.h" diff --git a/main/md5.c b/main/md5.c index 477494ccaf2..7c50bace9ad 100644 --- a/main/md5.c +++ b/main/md5.c @@ -22,8 +22,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/endian.h" #include "asterisk/md5.h" diff --git a/main/media_cache.c b/main/media_cache.c index 958a05bb254..7be358879fc 100644 --- a/main/media_cache.c +++ b/main/media_cache.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/config.h" #include "asterisk/bucket.h" diff --git a/main/message.c b/main/message.c index 0fc67ec0259..a326fb97eaf 100644 --- a/main/message.c +++ b/main/message.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/module.h" diff --git a/main/mixmonitor.c b/main/mixmonitor.c index fff51849d3f..0bd7adb94b9 100644 --- a/main/mixmonitor.c +++ b/main/mixmonitor.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/lock.h" #include "asterisk/logger.h" #include "asterisk/mixmonitor.h" diff --git a/main/named_acl.c b/main/named_acl.c index 0fc4df1871d..8b5aedabb1b 100644 --- a/main/named_acl.c +++ b/main/named_acl.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/config.h" #include "asterisk/config_options.h" #include "asterisk/utils.h" diff --git a/main/named_locks.c b/main/named_locks.c index c71f3b57923..27772f23be2 100644 --- a/main/named_locks.c +++ b/main/named_locks.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "asterisk/named_locks.h" diff --git a/main/netsock.c b/main/netsock.c index 568add4ca8e..b7a7566a76f 100644 --- a/main/netsock.c +++ b/main/netsock.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifndef __linux__ #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__) || defined(__GLIBC__) #include diff --git a/main/netsock2.c b/main/netsock2.c index d9123e434d8..bfa181c86cb 100644 --- a/main/netsock2.c +++ b/main/netsock2.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/config.h" #include "asterisk/netsock2.h" #include "asterisk/utils.h" diff --git a/main/optional_api.c b/main/optional_api.c index d89b9acb273..9b9a1a07c25 100644 --- a/main/optional_api.c +++ b/main/optional_api.c @@ -18,8 +18,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/optional_api.h" #include "asterisk/utils.h" diff --git a/main/parking.c b/main/parking.c index 61a48960dfa..bf0d0b6b78c 100644 --- a/main/parking.c +++ b/main/parking.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/astobj2.h" #include "asterisk/pbx.h" diff --git a/main/pbx.c b/main/pbx.c index 7cd420adb1b..e5c3d3c0796 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/paths.h" /* use ast_config_AST_SYSTEM_NAME */ #include diff --git a/main/pbx_app.c b/main/pbx_app.c index b7e797d88b7..0c030d12da7 100644 --- a/main/pbx_app.c +++ b/main/pbx_app.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/cli.h" #include "asterisk/linkedlists.h" diff --git a/main/pbx_builtins.c b/main/pbx_builtins.c index fa155888aec..20fdb4c22b7 100644 --- a/main/pbx_builtins.c +++ b/main/pbx_builtins.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/pbx.h" #include "asterisk/causes.h" diff --git a/main/pbx_functions.c b/main/pbx_functions.c index 558be461f0e..3c15e9d8849 100644 --- a/main/pbx_functions.c +++ b/main/pbx_functions.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/cli.h" #include "asterisk/linkedlists.h" diff --git a/main/pbx_hangup_handler.c b/main/pbx_hangup_handler.c index e013f319445..554cb342f52 100644 --- a/main/pbx_hangup_handler.c +++ b/main/pbx_hangup_handler.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/app.h" #include "asterisk/cli.h" diff --git a/main/pbx_ignorepat.c b/main/pbx_ignorepat.c index 1a2232c57ae..5b21c3a1fdb 100644 --- a/main/pbx_ignorepat.c +++ b/main/pbx_ignorepat.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/pbx.h" #include "pbx_private.h" diff --git a/main/pbx_include.c b/main/pbx_include.c index 46a41fb20f8..1bdc39605fe 100644 --- a/main/pbx_include.c +++ b/main/pbx_include.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/pbx.h" #include "pbx_private.h" diff --git a/main/pbx_sw.c b/main/pbx_sw.c index 0490ac6a2f5..0cc8c0e702b 100644 --- a/main/pbx_sw.c +++ b/main/pbx_sw.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/pbx.h" #include "pbx_private.h" diff --git a/main/pbx_switch.c b/main/pbx_switch.c index bf733aed5e5..62e7cf5a9a2 100644 --- a/main/pbx_switch.c +++ b/main/pbx_switch.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/cli.h" #include "asterisk/linkedlists.h" diff --git a/main/pbx_timing.c b/main/pbx_timing.c index 98053e6a416..b3ef0891ed8 100644 --- a/main/pbx_timing.c +++ b/main/pbx_timing.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/localtime.h" #include "asterisk/logger.h" #include "asterisk/pbx.h" diff --git a/main/pbx_variables.c b/main/pbx_variables.c index c02bdc8cc3a..eede21316fa 100644 --- a/main/pbx_variables.c +++ b/main/pbx_variables.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/app.h" #include "asterisk/ast_expr.h" diff --git a/main/pickup.c b/main/pickup.c index 8fb7e158bed..f0936ddf445 100644 --- a/main/pickup.c +++ b/main/pickup.c @@ -47,8 +47,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/pickup.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/main/plc.c b/main/plc.c index b24322350a2..b649357dcd6 100644 --- a/main/plc.c +++ b/main/plc.c @@ -36,8 +36,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/plc.h" diff --git a/main/presencestate.c b/main/presencestate.c index c0a0ebdc194..4121bf5b69a 100644 --- a/main/presencestate.c +++ b/main/presencestate.c @@ -57,8 +57,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/utils.h" #include "asterisk/lock.h" diff --git a/main/privacy.c b/main/privacy.c index 7b13fe7a825..c0cc31acfb5 100644 --- a/main/privacy.c +++ b/main/privacy.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/rtp_engine.c b/main/rtp_engine.c index b91bc411576..c9d228c5677 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -143,8 +143,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/channel.h" diff --git a/main/say.c b/main/say.c index 9f6f1eacbc6..4b3711b8545 100644 --- a/main/say.c +++ b/main/say.c @@ -37,8 +37,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/sched.c b/main/sched.c index 9fee5b9cf58..a4ca260c624 100644 --- a/main/sched.c +++ b/main/sched.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef DEBUG_SCHEDULER #define DEBUG(a) do { \ if (option_debug) \ diff --git a/main/sdp_srtp.c b/main/sdp_srtp.c index 940a6197d8f..072e6487c7b 100644 --- a/main/sdp_srtp.c +++ b/main/sdp_srtp.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */ #include "asterisk/logger.h" /* for ast_log, LOG_ERROR, etc */ #include "asterisk/sdp_srtp.h" /* for ast_sdp_srtp, etc */ diff --git a/main/security_events.c b/main/security_events.c index 9db932d85c6..adcda3d5deb 100644 --- a/main/security_events.c +++ b/main/security_events.c @@ -362,8 +362,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/strings.h" #include "asterisk/network.h" diff --git a/main/sem.c b/main/sem.c index ea2273d5a93..cb7b53123a8 100644 --- a/main/sem.c +++ b/main/sem.c @@ -23,8 +23,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/sem.h" #include "asterisk/utils.h" diff --git a/main/slinfactory.c b/main/slinfactory.c index 9b68241681e..83cf6232f6f 100644 --- a/main/slinfactory.c +++ b/main/slinfactory.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/frame.h" #include "asterisk/format_cache.h" #include "asterisk/slinfactory.h" diff --git a/main/smoother.c b/main/smoother.c index ca0c4e45a1f..461180db2bb 100644 --- a/main/smoother.c +++ b/main/smoother.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/frame.h" #include "asterisk/astobj2.h" diff --git a/main/sorcery.c b/main/sorcery.c index 9f8c35c3b9e..51b0b22bec6 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/sorcery.h" #include "asterisk/astobj2.h" diff --git a/main/srv.c b/main/srv.c index c0797499101..ef073a51785 100644 --- a/main/srv.c +++ b/main/srv.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #ifdef __APPLE__ diff --git a/main/stasis.c b/main/stasis.c index e04d92a4ff9..a82e938f4fb 100644 --- a/main/stasis.c +++ b/main/stasis.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/astobj2.h" #include "asterisk/stasis_internal.h" #include "asterisk/stasis.h" diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c index a5f29c74eff..43722b90ba6 100644 --- a/main/stasis_bridges.c +++ b/main/stasis_bridges.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/stasis.h" #include "asterisk/stasis_cache_pattern.h" diff --git a/main/stasis_cache.c b/main/stasis_cache.c index bd6d6fa1d6a..e632a21b06d 100644 --- a/main/stasis_cache.c +++ b/main/stasis_cache.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/hashtab.h" #include "asterisk/stasis_internal.h" diff --git a/main/stasis_cache_pattern.c b/main/stasis_cache_pattern.c index 66563c4c6d6..73cf0d2ca4e 100644 --- a/main/stasis_cache_pattern.c +++ b/main/stasis_cache_pattern.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/stasis_cache_pattern.h" diff --git a/main/stasis_channels.c b/main/stasis_channels.c index e1c50c6d05f..91f209290ae 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/json.h" #include "asterisk/pbx.h" diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index c32dbb44f29..161fdfa449f 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/stasis.h" #include "asterisk/stasis_endpoints.h" diff --git a/main/stasis_message.c b/main/stasis_message.c index 37b9a2b6ff5..88db49f1a63 100644 --- a/main/stasis_message.c +++ b/main/stasis_message.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/stasis.h" #include "asterisk/utils.h" diff --git a/main/stasis_message_router.c b/main/stasis_message_router.c index 85034bcf958..2c8d0a7684d 100644 --- a/main/stasis_message_router.c +++ b/main/stasis_message_router.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/stasis_message_router.h" #include "asterisk/vector.h" diff --git a/main/stasis_system.c b/main/stasis_system.c index c3a4d8663eb..ee4f6bca5bc 100644 --- a/main/stasis_system.c +++ b/main/stasis_system.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/stasis.h" #include "asterisk/stasis_system.h" diff --git a/main/stdtime/localtime.c b/main/stdtime/localtime.c index c946c5fa8d2..bb221aebf60 100644 --- a/main/stdtime/localtime.c +++ b/main/stdtime/localtime.c @@ -50,8 +50,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/stringfields.c b/main/stringfields.c index 25c58446274..7e52bbc9ef4 100644 --- a/main/stringfields.c +++ b/main/stringfields.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/stringfields.h" #include "asterisk/utils.h" diff --git a/main/strings.c b/main/strings.c index e62eb9aad62..b8f1ccbfdd9 100644 --- a/main/strings.c +++ b/main/strings.c @@ -37,8 +37,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/strings.h" #include "asterisk/pbx.h" diff --git a/main/stun.c b/main/stun.c index ecabdadef11..356266c94d6 100644 --- a/main/stun.c +++ b/main/stun.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/stun.h" #include "asterisk/cli.h" diff --git a/main/syslog.c b/main/syslog.c index 3f493064bff..c468c035eb8 100644 --- a/main/syslog.c +++ b/main/syslog.c @@ -30,8 +30,6 @@ #include "asterisk/utils.h" #include "asterisk/syslog.h" -ASTERISK_REGISTER_FILE() - #include static const struct { diff --git a/main/taskprocessor.c b/main/taskprocessor.c index ceb5f5c7f32..30ed763085d 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/module.h" #include "asterisk/time.h" diff --git a/main/tcptls.c b/main/tcptls.c index 046501b77e2..262fca07443 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #ifdef HAVE_FCNTL_H #include #endif diff --git a/main/tdd.c b/main/tdd.c index 7f0d7e310f8..370119cde3c 100644 --- a/main/tdd.c +++ b/main/tdd.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/term.c b/main/term.c index 11fbe2da9da..617f82ef38b 100644 --- a/main/term.c +++ b/main/term.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include #include diff --git a/main/test.c b/main/test.c index 2f6200f96fc..062451fb668 100644 --- a/main/test.c +++ b/main/test.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/_private.h" #ifdef TEST_FRAMEWORK diff --git a/main/threadstorage.c b/main/threadstorage.c index 920b2d50941..af37debb1aa 100644 --- a/main/threadstorage.c +++ b/main/threadstorage.c @@ -38,8 +38,6 @@ void threadstorage_init(void) #else /* !defined(DEBUG_THREADLOCALS) */ -ASTERISK_REGISTER_FILE() - #include "asterisk/strings.h" #include "asterisk/utils.h" #include "asterisk/threadstorage.h" diff --git a/main/timing.c b/main/timing.c index e2e28f04fc9..c6a9480c32b 100644 --- a/main/timing.c +++ b/main/timing.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/timing.h" diff --git a/main/translate.c b/main/translate.c index 43e6e29bd5d..fa606e71b87 100644 --- a/main/translate.c +++ b/main/translate.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/udptl.c b/main/udptl.c index e543b4e8eec..853e43c4458 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -63,8 +63,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/ulaw.c b/main/ulaw.c index 08d8060c845..c8904d56ed3 100644 --- a/main/ulaw.c +++ b/main/ulaw.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/ulaw.h" #include "asterisk/logger.h" diff --git a/main/utils.c b/main/utils.c index fd1edf49020..775fae3af8c 100644 --- a/main/utils.c +++ b/main/utils.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/main/xml.c b/main/xml.c index 72d5821c103..d32a8c5e4f4 100644 --- a/main/xml.c +++ b/main/xml.c @@ -31,8 +31,6 @@ #include "asterisk/utils.h" #include "asterisk/autoconfig.h" -ASTERISK_REGISTER_FILE() - #if defined(HAVE_LIBXML2) #include #include diff --git a/main/xmldoc.c b/main/xmldoc.c index 1e3d3686015..e9a0afcb85b 100644 --- a/main/xmldoc.c +++ b/main/xmldoc.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/paths.h" #include "asterisk/linkedlists.h" diff --git a/pbx/dundi-parser.c b/pbx/dundi-parser.c index 9b41aa9a864..3b2005fabf2 100644 --- a/pbx/dundi-parser.c +++ b/pbx/dundi-parser.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c index 1985d27a0bd..8ad49148522 100644 --- a/pbx/pbx_ael.c +++ b/pbx/pbx_ael.c @@ -29,19 +29,10 @@ #include "asterisk.h" -#if !defined(STANDALONE) -ASTERISK_REGISTER_FILE() -#endif - #include #include #include -#ifdef STANDALONE -#ifdef HAVE_MTX_PROFILE -static int mtx_prof = -1; /* helps the standalone compile with the mtx_prof flag on */ -#endif -#endif #include "asterisk/pbx.h" #include "asterisk/config.h" #include "asterisk/module.h" diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 0da4168f101..384bbc7c329 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -82,8 +82,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/paths.h" /* ast_config_AST_CONFIG_DIR */ diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index af5cb32ae30..50a91605e58 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -38,8 +38,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/network.h" #include #include diff --git a/pbx/pbx_loopback.c b/pbx/pbx_loopback.c index 2919748b7e8..2230d3593ad 100644 --- a/pbx/pbx_loopback.c +++ b/pbx/pbx_loopback.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/logger.h" #include "asterisk/channel.h" diff --git a/pbx/pbx_lua.c b/pbx/pbx_lua.c index 84b1f712662..01f468de067 100644 --- a/pbx/pbx_lua.c +++ b/pbx/pbx_lua.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c index 7a444d76359..08c90aa62f7 100644 --- a/pbx/pbx_realtime.c +++ b/pbx/pbx_realtime.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/file.h" diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c index c858ed22fbc..dcd2ce73421 100644 --- a/pbx/pbx_spool.c +++ b/pbx/pbx_spool.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/ael/ael.flex b/res/ael/ael.flex index 4e87f3a401e..b064646d9ce 100644 --- a/res/ael/ael.flex +++ b/res/ael/ael.flex @@ -70,7 +70,6 @@ %{ #define ASTMM_LIBC ASTMM_REDIRECT #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include #include diff --git a/res/ael/ael.tab.c b/res/ael/ael.tab.c index 9f1f19bb621..414914101a4 100644 --- a/res/ael/ael.tab.c +++ b/res/ael/ael.tab.c @@ -102,8 +102,6 @@ #define ASTMM_LIBC ASTMM_REDIRECT #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/ael/ael.y b/res/ael/ael.y index e5c1655c550..458863a026c 100644 --- a/res/ael/ael.y +++ b/res/ael/ael.y @@ -25,8 +25,6 @@ #define ASTMM_LIBC ASTMM_REDIRECT #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/ael/ael_lex.c b/res/ael/ael_lex.c index 9fbd664294e..10f669382b6 100644 --- a/res/ael/ael_lex.c +++ b/res/ael/ael_lex.c @@ -829,7 +829,6 @@ static yyconst flex_int16_t yy_chk[1073] = */ #line 71 "ael.flex" #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include #include diff --git a/res/ael/pval.c b/res/ael/pval.c index 485f5ee7967..6803ab634ee 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -30,8 +30,6 @@ #define ASTMM_LIBC ASTMM_REDIRECT #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index 633a94c1b0f..03cd3a2386b 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/module.h" #include "ari_model_validators.h" diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c index ed024377da2..6fe40c6b740 100644 --- a/res/ari/ari_websockets.c +++ b/res/ari/ari_websockets.c @@ -18,8 +18,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/ari.h" #include "asterisk/astobj2.h" #include "asterisk/http_websocket.h" diff --git a/res/ari/cli.c b/res/ari/cli.c index 4468e44f100..9d156f21ee7 100644 --- a/res/ari/cli.c +++ b/res/ari/cli.c @@ -24,8 +24,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/cli.h" #include "internal.h" diff --git a/res/ari/config.c b/res/ari/config.c index f8fdc27450f..deaa78073d5 100644 --- a/res/ari/config.c +++ b/res/ari/config.c @@ -24,8 +24,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/config_options.h" #include "asterisk/http_websocket.h" #include "internal.h" diff --git a/res/ari/resource_applications.c b/res/ari/resource_applications.c index 456d9c08b4c..fc93b28e228 100644 --- a/res/ari/resource_applications.c +++ b/res/ari/resource_applications.c @@ -26,8 +26,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/stasis_app.h" #include "resource_applications.h" diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c index a54ce5c325f..e76eb02bccc 100644 --- a/res/ari/resource_asterisk.c +++ b/res/ari/resource_asterisk.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/ast_version.h" #include "asterisk/buildinfo.h" #include "asterisk/logger.h" diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index 28c3e436052..f5ae1c003ac 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "resource_bridges.h" #include "asterisk/stasis.h" #include "asterisk/stasis_bridges.h" diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index afb4627a07c..6027a8059a9 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/pbx.h" #include "asterisk/bridge.h" diff --git a/res/ari/resource_device_states.c b/res/ari/resource_device_states.c index 493d7a1ee9f..020d9301f27 100644 --- a/res/ari/resource_device_states.c +++ b/res/ari/resource_device_states.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "resource_device_states.h" #include "asterisk/stasis_app_device_state.h" diff --git a/res/ari/resource_endpoints.c b/res/ari/resource_endpoints.c index 10b49e38c1b..e0bbcb53367 100644 --- a/res/ari/resource_endpoints.c +++ b/res/ari/resource_endpoints.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "resource_endpoints.h" #include "asterisk/astobj2.h" diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c index 8fa15f5aa06..597f4dfeb6f 100644 --- a/res/ari/resource_events.c +++ b/res/ari/resource_events.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "resource_events.h" #include "asterisk/astobj2.h" #include "asterisk/stasis_app.h" diff --git a/res/ari/resource_mailboxes.c b/res/ari/resource_mailboxes.c index f899ee476dd..3577e651533 100644 --- a/res/ari/resource_mailboxes.c +++ b/res/ari/resource_mailboxes.c @@ -31,8 +31,6 @@ #include "asterisk.h" #include "asterisk/stasis_app_mailbox.h" -ASTERISK_REGISTER_FILE() - #include "resource_mailboxes.h" void ast_ari_mailboxes_list(struct ast_variable *headers, diff --git a/res/ari/resource_playbacks.c b/res/ari/resource_playbacks.c index f2751f70d15..57f424c016f 100644 --- a/res/ari/resource_playbacks.c +++ b/res/ari/resource_playbacks.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/stasis_app_playback.h" #include "resource_playbacks.h" diff --git a/res/ari/resource_recordings.c b/res/ari/resource_recordings.c index 5661d608d90..39ef65ce34f 100644 --- a/res/ari/resource_recordings.c +++ b/res/ari/resource_recordings.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/stasis_app_recording.h" #include "resource_recordings.h" diff --git a/res/ari/resource_sounds.c b/res/ari/resource_sounds.c index a1420eaf220..59ace5d81fa 100644 --- a/res/ari/resource_sounds.c +++ b/res/ari/resource_sounds.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "resource_sounds.h" #include "asterisk/media_index.h" #include "asterisk/sounds_index.h" diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c index 1c95b6f03f0..dd2fb75879e 100644 --- a/res/parking/parking_applications.c +++ b/res/parking/parking_applications.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "res_parking.h" #include "asterisk/config.h" #include "asterisk/config_options.h" diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 4eb3f71ed4f..3fa7e42b31e 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "res_parking.h" #include "asterisk/utils.h" #include "asterisk/astobj2.h" diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c index 89f553d9cfe..6d0a4c06cbf 100644 --- a/res/parking/parking_manager.c +++ b/res/parking/parking_manager.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "res_parking.h" #include "asterisk/config.h" #include "asterisk/config_options.h" diff --git a/res/parking/parking_tests.c b/res/parking/parking_tests.c index e6ea9f945f0..15727882342 100644 --- a/res/parking/parking_tests.c +++ b/res/parking/parking_tests.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "res_parking.h" #include "asterisk/utils.h" #include "asterisk/module.h" diff --git a/res/parking/parking_ui.c b/res/parking/parking_ui.c index 7d4726cc210..f12963a2baf 100644 --- a/res/parking/parking_ui.c +++ b/res/parking/parking_ui.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "res_parking.h" #include "asterisk/config.h" #include "asterisk/config_options.h" diff --git a/res/res_adsi.c b/res/res_adsi.c index 314a4eabd75..698f935fbb0 100644 --- a/res/res_adsi.c +++ b/res/res_adsi.c @@ -36,8 +36,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/res/res_ael_share.c b/res/res_ael_share.c index c6306abb84c..3539eb8432f 100644 --- a/res/res_ael_share.c +++ b/res/res_ael_share.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/res/res_agi.c b/res/res_agi.c index e0eb8e2ecbf..06e8a03e251 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_ari.c b/res/res_ari.c index eb15a88b85d..e19881515ae 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -140,8 +140,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "ari/internal.h" #include "asterisk/ari.h" #include "asterisk/astobj2.h" diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c index 7ce9722fd2b..006d30ca84f 100644 --- a/res/res_ari_applications.c +++ b/res/res_ari_applications.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index 71f72eea1c4..5dbf3415c29 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index a60b7010a30..29fb07582de 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 9e8eeb4e901..252bc4fff2b 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c index c3876af8bbe..39e678fc43d 100644 --- a/res/res_ari_device_states.c +++ b/res/res_ari_device_states.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index fd385313c08..5307cd1de3d 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_events.c b/res/res_ari_events.c index 40a18b8fb86..36c9b06d8ee 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c index 5b053230908..4d418fe5320 100644 --- a/res/res_ari_mailboxes.c +++ b/res/res_ari_mailboxes.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_model.c b/res/res_ari_model.c index 14265cdce97..dd8e1af388a 100644 --- a/res/res_ari_model.c +++ b/res/res_ari_model.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "ari/ari_model_validators.h" #include "asterisk/logger.h" #include "asterisk/module.h" diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c index b4dfd1c1cf9..9678830cead 100644 --- a/res/res_ari_playbacks.c +++ b/res/res_ari_playbacks.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index aee3d3d2ad6..a43bbdd930a 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index f5a1d41abca..eb4bbb3f78b 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -40,8 +40,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/res/res_calendar.c b/res/res_calendar.c index 029ecebd07b..46775507cd9 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -38,8 +38,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/_private.h" #include "asterisk/channel.h" #include "asterisk/calendar.h" diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c index 590408571fe..11650375bd8 100644 --- a/res/res_calendar_caldav.c +++ b/res/res_calendar_caldav.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_calendar_ews.c b/res/res_calendar_ews.c index 05133a2a91a..998188dcfa8 100644 --- a/res/res_calendar_ews.c +++ b/res/res_calendar_ews.c @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_calendar_exchange.c b/res/res_calendar_exchange.c index 577d65ba696..7292ecc46bc 100644 --- a/res/res_calendar_exchange.c +++ b/res/res_calendar_exchange.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c index 507f19cbf50..33480608aad 100644 --- a/res/res_calendar_icalendar.c +++ b/res/res_calendar_icalendar.c @@ -28,8 +28,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_chan_stats.c b/res/res_chan_stats.c index dfca39a8bf5..9a26db78c2c 100644 --- a/res/res_chan_stats.c +++ b/res/res_chan_stats.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/stasis_channels.h" #include "asterisk/stasis_message_router.h" diff --git a/res/res_clialiases.c b/res/res_clialiases.c index 74d763ac7fd..1a2fc693996 100644 --- a/res/res_clialiases.c +++ b/res/res_clialiases.c @@ -41,8 +41,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/config.h" #include "asterisk/cli.h" diff --git a/res/res_clioriginate.c b/res/res_clioriginate.c index 451b1745de1..37df8ed6580 100644 --- a/res/res_clioriginate.c +++ b/res/res_clioriginate.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/channel.h" #include "asterisk/pbx.h" #include "asterisk/module.h" diff --git a/res/res_config_curl.c b/res/res_config_curl.c index 7b571d549b7..9ad7a6e3db7 100644 --- a/res/res_config_curl.c +++ b/res/res_config_curl.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/file.h" diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 8454273799a..5e95853d462 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -53,8 +53,6 @@ #include #include -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/logger.h" #include "asterisk/config.h" diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 161dc534501..5a25b6b5a0b 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 73f43ee2cce..25a482705ae 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include /* PostgreSQL */ #include "asterisk/file.h" diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c index 4375c3960ea..68594978736 100644 --- a/res/res_config_sqlite.c +++ b/res/res_config_sqlite.c @@ -86,7 +86,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index a3061236883..b5c70ec2da4 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/res/res_convert.c b/res/res_convert.c index 3ca596511ae..705e8922d9b 100644 --- a/res/res_convert.c +++ b/res/res_convert.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/module.h" #include "asterisk/cli.h" diff --git a/res/res_corosync.c b/res/res_corosync.c index dbb88469743..79cd810cef4 100644 --- a/res/res_corosync.c +++ b/res/res_corosync.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include #include diff --git a/res/res_crypto.c b/res/res_crypto.c index e7cb728789c..8f97ce9f8ba 100644 --- a/res/res_crypto.c +++ b/res/res_crypto.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/paths.h" /* use ast_config_AST_KEY_DIR */ #include #include diff --git a/res/res_curl.c b/res/res_curl.c index 0a781f19046..5c436329552 100644 --- a/res/res_curl.c +++ b/res/res_curl.c @@ -42,8 +42,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/res/res_endpoint_stats.c b/res/res_endpoint_stats.c index 28e47d0d6f2..249cbea9bb8 100644 --- a/res/res_endpoint_stats.c +++ b/res/res_endpoint_stats.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/stasis_endpoints.h" #include "asterisk/stasis_message_router.h" diff --git a/res/res_fax.c b/res/res_fax.c index f602ba9659d..b25b6d16d4a 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -65,8 +65,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/io.h" #include "asterisk/file.h" #include "asterisk/logger.h" diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c index 46db86460b3..540a9021b04 100644 --- a/res/res_fax_spandsp.c +++ b/res/res_fax_spandsp.c @@ -52,8 +52,6 @@ #define ASTMM_LIBC ASTMM_IGNORE #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/module.h" #include "asterisk/strings.h" diff --git a/res/res_format_attr_celt.c b/res/res_format_attr_celt.c index 7d3f753ff9c..4b923761ffb 100644 --- a/res/res_format_attr_celt.c +++ b/res/res_format_attr_celt.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" diff --git a/res/res_format_attr_g729.c b/res/res_format_attr_g729.c index 5ba4920d96d..2b0cb02e28a 100644 --- a/res/res_format_attr_g729.c +++ b/res/res_format_attr_g729.c @@ -22,8 +22,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" diff --git a/res/res_format_attr_h263.c b/res/res_format_attr_h263.c index d65a89fea33..139fbf17aa9 100644 --- a/res/res_format_attr_h263.c +++ b/res/res_format_attr_h263.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" diff --git a/res/res_format_attr_h264.c b/res/res_format_attr_h264.c index ccf2176f2d6..29d495bc772 100644 --- a/res/res_format_attr_h264.c +++ b/res/res_format_attr_h264.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index dfdf9b6d6ac..a3e48e3de79 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" #include "asterisk/logger.h" diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c index e69e3f43c1f..d2f9b35449c 100644 --- a/res/res_format_attr_silk.c +++ b/res/res_format_attr_silk.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" diff --git a/res/res_format_attr_siren14.c b/res/res_format_attr_siren14.c index 335b575980b..2cc2a2f2c85 100644 --- a/res/res_format_attr_siren14.c +++ b/res/res_format_attr_siren14.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" diff --git a/res/res_format_attr_siren7.c b/res/res_format_attr_siren7.c index 7aef019dabe..7f4f165ffa1 100644 --- a/res/res_format_attr_siren7.c +++ b/res/res_format_attr_siren7.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" diff --git a/res/res_format_attr_vp8.c b/res/res_format_attr_vp8.c index 777239aaea9..f9babd8715a 100644 --- a/res/res_format_attr_vp8.c +++ b/res/res_format_attr_vp8.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" #include "asterisk/logger.h" /* for ast_log, LOG_WARNING */ diff --git a/res/res_hep.c b/res/res_hep.c index e79f2b67abc..3bbf4c51ebc 100644 --- a/res/res_hep.c +++ b/res/res_hep.c @@ -85,8 +85,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/astobj2.h" #include "asterisk/config_options.h" diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index a3a93e9b28a..358cbc934e1 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 03db1815966..25b90c7a266 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/res_hep.h" #include "asterisk/module.h" #include "asterisk/netsock2.h" diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c index 2207b96ddd4..8c67285866a 100644 --- a/res/res_http_media_cache.c +++ b/res/res_http_media_cache.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/res/res_http_post.c b/res/res_http_post.c index 37fc4fa091c..241edfe5937 100644 --- a/res/res_http_post.c +++ b/res/res_http_post.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index d63caec3e71..28bf45fc8ce 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/http.h" #include "asterisk/astobj2.h" diff --git a/res/res_limit.c b/res/res_limit.c index d844efe8c95..bff777d9909 100644 --- a/res/res_limit.c +++ b/res/res_limit.c @@ -24,8 +24,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_monitor.c b/res/res_monitor.c index 6fee0c2a08c..2ab52d87304 100644 --- a/res/res_monitor.c +++ b/res/res_monitor.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 3c7199ef459..3a751ecce61 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_mutestream.c b/res/res_mutestream.c index e9b11dcc307..8040a3ac9bd 100644 --- a/res/res_mutestream.c +++ b/res/res_mutestream.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/options.h" #include "asterisk/logger.h" #include "asterisk/channel.h" diff --git a/res/res_mwi_external.c b/res/res_mwi_external.c index 3499885a5b2..d797991968e 100644 --- a/res/res_mwi_external.c +++ b/res/res_mwi_external.c @@ -54,8 +54,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/res_mwi_external.h" diff --git a/res/res_mwi_external_ami.c b/res/res_mwi_external_ami.c index 7777214cd7a..516969b1d50 100644 --- a/res/res_mwi_external_ami.c +++ b/res/res_mwi_external_ami.c @@ -127,8 +127,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/res_mwi_external.h" #include "asterisk/manager.h" diff --git a/res/res_odbc.c b/res/res_odbc.c index b207049fef4..0b81bc6396f 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -48,8 +48,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/config.h" diff --git a/res/res_parking.c b/res/res_parking.c index 78ae481ba75..171fdce6152 100644 --- a/res/res_parking.c +++ b/res/res_parking.c @@ -233,8 +233,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "parking/res_parking.h" #include "asterisk/config.h" #include "asterisk/config_options.h" diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c index 2e4f8736235..132c842ad6a 100644 --- a/res/res_phoneprov.c +++ b/res/res_phoneprov.c @@ -52,7 +52,6 @@ #ifdef SOLARIS #include #endif -ASTERISK_REGISTER_FILE() #include "asterisk/channel.h" #include "asterisk/file.h" diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 151c99603d3..66c95f2b754 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -77,8 +77,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_pjsip/pjsip_scheduler.c b/res/res_pjsip/pjsip_scheduler.c index a5d406cb589..27202c602f1 100644 --- a/res/res_pjsip/pjsip_scheduler.c +++ b/res/res_pjsip/pjsip_scheduler.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/res_pjsip.h" #include "include/res_pjsip_private.h" #include "asterisk/res_pjsip_cli.h" diff --git a/res/res_pjsip/security_events.c b/res/res_pjsip/security_events.c index f07265a320d..b8a8d521225 100644 --- a/res/res_pjsip/security_events.c +++ b/res/res_pjsip/security_events.c @@ -26,8 +26,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/res_pjsip.h" diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index aec923dfaa5..2441184a243 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -39,8 +39,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/res/res_pjsip_dlg_options.c b/res/res_pjsip_dlg_options.c index 34151244b1a..e2ed29a2c62 100644 --- a/res/res_pjsip_dlg_options.c +++ b/res/res_pjsip_dlg_options.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_pjsip_empty_info.c b/res/res_pjsip_empty_info.c index 09109ba2c3b..774f9de7e01 100644 --- a/res/res_pjsip_empty_info.c +++ b/res/res_pjsip_empty_info.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c index 339aecb74ca..41c5bdf6964 100644 --- a/res/res_pjsip_history.c +++ b/res/res_pjsip_history.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/res/res_pjsip_logger.c b/res/res_pjsip_logger.c index 427cb6fb7d8..d29a6e21367 100644 --- a/res/res_pjsip_logger.c +++ b/res/res_pjsip_logger.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/res_pjsip.h" diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a69aa1a7438..83e01ebb23f 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -38,8 +38,6 @@ #include #include -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/format.h" #include "asterisk/format_cap.h" diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index b052cc428cb..adc99c30d6b 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -37,8 +37,6 @@ #include #include -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/udptl.h" #include "asterisk/netsock2.h" diff --git a/res/res_pktccops.c b/res/res_pktccops.c index fedd069dfab..4f694487543 100644 --- a/res/res_pktccops.c +++ b/res/res_pktccops.c @@ -37,8 +37,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_realtime.c b/res/res_realtime.c index e7ef21222f9..9e487a83fd9 100644 --- a/res/res_realtime.c +++ b/res/res_realtime.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/res/res_resolver_unbound.c b/res/res_resolver_unbound.c index 348e04f9340..1877bbcc437 100644 --- a/res/res_resolver_unbound.c +++ b/res/res_resolver_unbound.c @@ -23,8 +23,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index cdf0c560d0a..79b8d4f4dce 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -35,8 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index fce49265946..42de11f65e8 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_security_log.c b/res/res_security_log.c index 94a78d8039d..555ba23c184 100644 --- a/res/res_security_log.c +++ b/res/res_security_log.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/module.h" #include "asterisk/logger.h" #include "asterisk/threadstorage.h" diff --git a/res/res_smdi.c b/res/res_smdi.c index 770ac62d2d2..4c7a45164c2 100644 --- a/res/res_smdi.c +++ b/res/res_smdi.c @@ -46,8 +46,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #include diff --git a/res/res_snmp.c b/res/res_snmp.c index 7eef9f85bec..f9f064e5570 100644 --- a/res/res_snmp.c +++ b/res/res_snmp.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/channel.h" #include "asterisk/module.h" diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index 79db6680889..8d163351168 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c index 852537b19a6..0de34c64018 100644 --- a/res/res_sorcery_config.c +++ b/res/res_sorcery_config.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c index 774c9552a60..57d5eace03d 100644 --- a/res/res_sorcery_memory.c +++ b/res/res_sorcery_memory.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index f1fb3c38c59..4ce4e18e9a0 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/sorcery.h" #include "asterisk/astobj2.h" diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index 4023654ab27..3f114046c76 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/res/res_speech.c b/res/res_speech.c index 1505ca428da..d6c5329714a 100644 --- a/res/res_speech.c +++ b/res/res_speech.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/channel.h" #include "asterisk/module.h" #include "asterisk/lock.h" diff --git a/res/res_srtp.c b/res/res_srtp.c index 1fb16ce6b94..a611e61657f 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -37,8 +37,6 @@ #include "asterisk.h" /* for NULL, size_t, memcpy, etc */ -ASTERISK_REGISTER_FILE() - #include /* for pow */ #include #ifdef HAVE_OPENSSL diff --git a/res/res_stasis.c b/res/res_stasis.c index 464f7c42f1b..8e596d557a1 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -53,8 +53,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/callerid.h" #include "asterisk/module.h" diff --git a/res/res_stasis_answer.c b/res/res_stasis_answer.c index 830de8015cc..407a6313546 100644 --- a/res/res_stasis_answer.c +++ b/res/res_stasis_answer.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/stasis_app_impl.h" diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c index 453bfae6d61..8b537591075 100644 --- a/res/res_stasis_device_state.c +++ b/res/res_stasis_device_state.c @@ -23,8 +23,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astdb.h" #include "asterisk/astobj2.h" #include "asterisk/module.h" diff --git a/res/res_stasis_mailbox.c b/res/res_stasis_mailbox.c index e34cb2058fa..4522adc10d8 100644 --- a/res/res_stasis_mailbox.c +++ b/res/res_stasis_mailbox.c @@ -24,8 +24,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astdb.h" #include "asterisk/astobj2.h" #include "asterisk/module.h" diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index cfddb3af56d..4370f17121d 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/astobj2.h" #include "asterisk/bridge.h" diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c index af5c41e877c..630205c34d5 100644 --- a/res/res_stasis_recording.c +++ b/res/res_stasis_recording.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/dsp.h" #include "asterisk/file.h" #include "asterisk/module.h" diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c index e5b5bf60464..cd51638ea91 100644 --- a/res/res_stasis_snoop.c +++ b/res/res_stasis_snoop.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/stasis_app_impl.h" #include "asterisk/stasis_app_snoop.h" diff --git a/res/res_stasis_test.c b/res/res_stasis_test.c index efdbc4b529f..8b5bad7aea2 100644 --- a/res/res_stasis_test.c +++ b/res/res_stasis_test.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/astobj2.h" #include "asterisk/module.h" #include "asterisk/stasis_test.h" diff --git a/res/res_statsd.c b/res/res_statsd.c index f3a64e0f8ef..22c4ba2e700 100644 --- a/res/res_statsd.c +++ b/res/res_statsd.c @@ -52,8 +52,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/config_options.h" #include "asterisk/module.h" #include "asterisk/netsock2.h" diff --git a/res/res_stun_monitor.c b/res/res_stun_monitor.c index e1bd85b4f08..46deaff7547 100644 --- a/res/res_stun_monitor.c +++ b/res/res_stun_monitor.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/sched.h" #include "asterisk/config.h" diff --git a/res/res_timing_dahdi.c b/res/res_timing_dahdi.c index 23fb8e35860..af2087599b5 100644 --- a/res/res_timing_dahdi.c +++ b/res/res_timing_dahdi.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include #include #include diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c index 6476e74fb0c..09952f92906 100644 --- a/res/res_timing_pthread.c +++ b/res/res_timing_pthread.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include #include #include diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 32e1dd1ffc9..1aa865cd626 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -48,8 +48,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include diff --git a/res/snmp/agent.c b/res/snmp/agent.c index f0e089fb6f2..7ff78d56e3e 100644 --- a/res/snmp/agent.c +++ b/res/snmp/agent.c @@ -22,8 +22,6 @@ #define ASTMM_LIBC ASTMM_IGNORE #include "asterisk.h" -ASTERISK_REGISTER_FILE() - /* * There is some collision collision between netsmp and asterisk names, * causing build under AST_DEVMODE to fail. diff --git a/res/stasis/app.c b/res/stasis/app.c index 8bd1bc05aba..3301d926c9e 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "app.h" #include "control.h" #include "messaging.h" diff --git a/res/stasis/command.c b/res/stasis/command.c index 6298e88960b..05ebd7b1d2c 100644 --- a/res/stasis/command.c +++ b/res/stasis/command.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "command.h" #include "asterisk/lock.h" diff --git a/res/stasis/control.c b/res/stasis/control.c index 219a2c6cd27..503f111aad6 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/stasis_channels.h" #include "asterisk/stasis_app.h" diff --git a/res/stasis/messaging.c b/res/stasis/messaging.c index 16e167e8f43..8dfd9960838 100644 --- a/res/stasis/messaging.c +++ b/res/stasis/messaging.c @@ -26,8 +26,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/message.h" #include "asterisk/endpoints.h" #include "asterisk/astobj2.h" diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index aa21ec29c3a..95e549a2956 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -29,8 +29,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/bridge.h" #include "asterisk/bridge_after.h" #include "asterisk/bridge_internal.h" diff --git a/res/stasis_recording/stored.c b/res/stasis_recording/stored.c index 50232c42754..e25f9a7af59 100644 --- a/res/stasis_recording/stored.c +++ b/res/stasis_recording/stored.c @@ -25,8 +25,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/paths.h" #include "asterisk/stasis_app_recording.h" diff --git a/rest-api-templates/ari_model_validators.c.mustache b/rest-api-templates/ari_model_validators.c.mustache index 78f19bf6697..cd77da98bf1 100644 --- a/rest-api-templates/ari_model_validators.c.mustache +++ b/rest-api-templates/ari_model_validators.c.mustache @@ -27,8 +27,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/logger.h" #include "asterisk/module.h" #include "ari_model_validators.h" diff --git a/rest-api-templates/ari_resource.c.mustache b/rest-api-templates/ari_resource.c.mustache index b8f20e67528..27e9099e549 100644 --- a/rest-api-templates/ari_resource.c.mustache +++ b/rest-api-templates/ari_resource.c.mustache @@ -26,8 +26,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "resource_{{c_name}}.h" {{#apis}} diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index c4e6f3d5418..d5c86158bcb 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -45,8 +45,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/app.h" #include "asterisk/module.h" #include "asterisk/stasis_app.h" diff --git a/tests/test_abstract_jb.c b/tests/test_abstract_jb.c index 6274fb2ef80..53614bca136 100644 --- a/tests/test_abstract_jb.c +++ b/tests/test_abstract_jb.c @@ -36,8 +36,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_acl.c b/tests/test_acl.c index ff64bc15c54..98eb4dcc048 100644 --- a/tests/test_acl.c +++ b/tests/test_acl.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/acl.h" #include "asterisk/module.h" diff --git a/tests/test_amihooks.c b/tests/test_amihooks.c index 5dda1017760..1297cb57ffc 100644 --- a/tests/test_amihooks.c +++ b/tests/test_amihooks.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/cli.h" #include "asterisk/utils.h" diff --git a/tests/test_aoc.c b/tests/test_aoc.c index 2f7336fe25e..9d1e230ffc2 100644 --- a/tests/test_aoc.c +++ b/tests/test_aoc.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_app.c b/tests/test_app.c index f81290eaeda..f3dd135b14b 100644 --- a/tests/test_app.c +++ b/tests/test_app.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_ari.c b/tests/test_ari.c index da889ec45d5..1bd77496ff6 100644 --- a/tests/test_ari.c +++ b/tests/test_ari.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/test.h" #include "asterisk/ari.h" diff --git a/tests/test_ari_model.c b/tests/test_ari_model.c index 6c5c14d507d..caf41187893 100644 --- a/tests/test_ari_model.c +++ b/tests/test_ari_model.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_ast_format_str_reduce.c b/tests/test_ast_format_str_reduce.c index db9f1a2a2e3..a5c1af79894 100644 --- a/tests/test_ast_format_str_reduce.c +++ b/tests/test_ast_format_str_reduce.c @@ -41,8 +41,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/file.h" #include "asterisk/test.h" diff --git a/tests/test_astobj2.c b/tests/test_astobj2.c index 9297fb3c057..827ebb55bbc 100644 --- a/tests/test_astobj2.c +++ b/tests/test_astobj2.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_astobj2_thrash.c b/tests/test_astobj2_thrash.c index ef0da44ca5b..a3592468d91 100644 --- a/tests/test_astobj2_thrash.c +++ b/tests/test_astobj2_thrash.c @@ -35,7 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include #include "asterisk/astobj2.h" #include "asterisk/hashtab.h" diff --git a/tests/test_astobj2_weaken.c b/tests/test_astobj2_weaken.c index 6a5eaeb99b6..2755b6e52d9 100644 --- a/tests/test_astobj2_weaken.c +++ b/tests/test_astobj2_weaken.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_bucket.c b/tests/test_bucket.c index eb8fc902886..2b6e059c370 100644 --- a/tests/test_bucket.c +++ b/tests/test_bucket.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/test.h" diff --git a/tests/test_callerid.c b/tests/test_callerid.c index 5f7af2b6c83..c7aafacf9cb 100644 --- a/tests/test_callerid.c +++ b/tests/test_callerid.c @@ -34,8 +34,6 @@ #include "asterisk.h" #include "asterisk/callerid.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_cdr.c b/tests/test_cdr.c index ef9e76d0dbe..bdbffccbc9e 100644 --- a/tests/test_cdr.c +++ b/tests/test_cdr.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_cel.c b/tests/test_cel.c index e54fb598451..c9ceaf93c94 100644 --- a/tests/test_cel.c +++ b/tests/test_cel.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_channel_feature_hooks.c b/tests/test_channel_feature_hooks.c index 94037e2fa50..c9fdf098377 100644 --- a/tests/test_channel_feature_hooks.c +++ b/tests/test_channel_feature_hooks.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/test.h" #include "asterisk/channel.h" diff --git a/tests/test_config.c b/tests/test_config.c index eb5409b3a13..6635c6f78a1 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include /* HUGE_VAL */ #include diff --git a/tests/test_core_codec.c b/tests/test_core_codec.c index 7e5677022c6..1da21cdc296 100644 --- a/tests/test_core_codec.c +++ b/tests/test_core_codec.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/codec.h" diff --git a/tests/test_core_format.c b/tests/test_core_format.c index 2140029726a..a697f8e7d59 100644 --- a/tests/test_core_format.c +++ b/tests/test_core_format.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/codec.h" diff --git a/tests/test_db.c b/tests/test_db.c index f4ce515847a..cfd036d20df 100644 --- a/tests/test_db.c +++ b/tests/test_db.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/astdb.h" diff --git a/tests/test_devicestate.c b/tests/test_devicestate.c index 52e0fe69566..afefeb0f032 100644 --- a/tests/test_devicestate.c +++ b/tests/test_devicestate.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_dlinklists.c b/tests/test_dlinklists.c index 581bf4d5804..81c10b20d21 100644 --- a/tests/test_dlinklists.c +++ b/tests/test_dlinklists.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/tests/test_endpoints.c b/tests/test_endpoints.c index d1239037b8e..85c4e76df98 100644 --- a/tests/test_endpoints.c +++ b/tests/test_endpoints.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/endpoints.h" #include "asterisk/module.h" diff --git a/tests/test_event.c b/tests/test_event.c index 0290a269761..70a93d4e27b 100644 --- a/tests/test_event.c +++ b/tests/test_event.c @@ -41,8 +41,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/utils.h" #include "asterisk/test.h" diff --git a/tests/test_expr.c b/tests/test_expr.c index 5ea86a34138..374f8574899 100644 --- a/tests/test_expr.c +++ b/tests/test_expr.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_format_cache.c b/tests/test_format_cache.c index b01b0da1c70..2ed9780c2e9 100644 --- a/tests/test_format_cache.c +++ b/tests/test_format_cache.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/codec.h" diff --git a/tests/test_format_cap.c b/tests/test_format_cap.c index 1f02c29cd36..096d17202b4 100644 --- a/tests/test_format_cap.c +++ b/tests/test_format_cap.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/codec.h" diff --git a/tests/test_func_file.c b/tests/test_func_file.c index a1e71b2707d..43995fa08dd 100644 --- a/tests/test_func_file.c +++ b/tests/test_func_file.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/app.h" #include "asterisk/module.h" diff --git a/tests/test_gosub.c b/tests/test_gosub.c index e0f618cd5f8..0a702cf866b 100644 --- a/tests/test_gosub.c +++ b/tests/test_gosub.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_hashtab_thrash.c b/tests/test_hashtab_thrash.c index 2f043c7b2b6..ee77c92c030 100644 --- a/tests/test_hashtab_thrash.c +++ b/tests/test_hashtab_thrash.c @@ -35,7 +35,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include #include "asterisk/hashtab.h" #include "asterisk/lock.h" diff --git a/tests/test_heap.c b/tests/test_heap.c index 76a6ecf3459..cb0b2484781 100644 --- a/tests/test_heap.c +++ b/tests/test_heap.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/utils.h" #include "asterisk/heap.h" diff --git a/tests/test_http_media_cache.c b/tests/test_http_media_cache.c index 4cc4e38dc22..23ebbdfdfde 100644 --- a/tests/test_http_media_cache.c +++ b/tests/test_http_media_cache.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/tests/test_jitterbuf.c b/tests/test_jitterbuf.c index 9f538ee09b6..76fb3c4fcc8 100644 --- a/tests/test_jitterbuf.c +++ b/tests/test_jitterbuf.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_json.c b/tests/test_json.c index 7362a6127a1..fee17e7c263 100644 --- a/tests/test_json.c +++ b/tests/test_json.c @@ -37,7 +37,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include "asterisk/json.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_linkedlists.c b/tests/test_linkedlists.c index 4a17e6730c1..5c3fcebb36f 100644 --- a/tests/test_linkedlists.c +++ b/tests/test_linkedlists.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/test.h" #include "asterisk/strings.h" diff --git a/tests/test_locale.c b/tests/test_locale.c index a39e2a981a8..7a591cb8b19 100644 --- a/tests/test_locale.c +++ b/tests/test_locale.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include #ifndef __USE_GNU diff --git a/tests/test_logger.c b/tests/test_logger.c index 1f7000a17f3..07a4c369b81 100644 --- a/tests/test_logger.c +++ b/tests/test_logger.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/tests/test_media_cache.c b/tests/test_media_cache.c index 685693c3645..34f53190a13 100644 --- a/tests/test_media_cache.c +++ b/tests/test_media_cache.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_message.c b/tests/test_message.c index 017b84cf2d0..1d03d74a939 100644 --- a/tests/test_message.c +++ b/tests/test_message.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/module.h" diff --git a/tests/test_netsock2.c b/tests/test_netsock2.c index 780b0b06f26..8a9579b395b 100644 --- a/tests/test_netsock2.c +++ b/tests/test_netsock2.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/netsock2.h" diff --git a/tests/test_optional_api.c b/tests/test_optional_api.c index f7809d32ba1..5c773899f49 100644 --- a/tests/test_optional_api.c +++ b/tests/test_optional_api.c @@ -36,8 +36,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/optional_api.h" #include "asterisk/test.h" diff --git a/tests/test_pbx.c b/tests/test_pbx.c index 88451672d6e..576fe1fb889 100644 --- a/tests/test_pbx.c +++ b/tests/test_pbx.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/pbx.h" #include "asterisk/test.h" diff --git a/tests/test_poll.c b/tests/test_poll.c index 10b0225cc1a..a142ffc4545 100644 --- a/tests/test_poll.c +++ b/tests/test_poll.c @@ -39,8 +39,6 @@ #include #include -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_res_pjsip_scheduler.c b/tests/test_res_pjsip_scheduler.c index cc5313fd6fd..da51d43be2b 100644 --- a/tests/test_res_pjsip_scheduler.c +++ b/tests/test_res_pjsip_scheduler.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/test.h" #include "asterisk/module.h" diff --git a/tests/test_res_stasis.c b/tests/test_res_stasis.c index 45989037323..cb79fa6fea7 100644 --- a/tests/test_res_stasis.c +++ b/tests/test_res_stasis.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/test.h" #include "asterisk/stasis_app.h" diff --git a/tests/test_sched.c b/tests/test_sched.c index 23a5e3ddf89..e995c2c885c 100644 --- a/tests/test_sched.c +++ b/tests/test_sched.c @@ -32,8 +32,6 @@ #include -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/utils.h" #include "asterisk/sched.h" diff --git a/tests/test_security_events.c b/tests/test_security_events.c index bdca9b15705..0fa5ef1f7bc 100644 --- a/tests/test_security_events.c +++ b/tests/test_security_events.c @@ -30,8 +30,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/module.h" #include "asterisk/cli.h" #include "asterisk/utils.h" diff --git a/tests/test_skel.c b/tests/test_skel.c index b5063d255e0..208751c95fe 100644 --- a/tests/test_skel.c +++ b/tests/test_skel.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/tests/test_sorcery.c b/tests/test_sorcery.c index 5d96422aa90..06623369574 100644 --- a/tests/test_sorcery.c +++ b/tests/test_sorcery.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/astobj2.h" diff --git a/tests/test_sorcery_astdb.c b/tests/test_sorcery_astdb.c index d62e844e76e..62895960caf 100644 --- a/tests/test_sorcery_astdb.c +++ b/tests/test_sorcery_astdb.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/sorcery.h" diff --git a/tests/test_sorcery_memory_cache_thrash.c b/tests/test_sorcery_memory_cache_thrash.c index d911e869ef1..c0d25feb346 100644 --- a/tests/test_sorcery_memory_cache_thrash.c +++ b/tests/test_sorcery_memory_cache_thrash.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/sorcery.h" diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c index 033bf5d6f64..8639c0f6f26 100644 --- a/tests/test_sorcery_realtime.c +++ b/tests/test_sorcery_realtime.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/sorcery.h" diff --git a/tests/test_stasis.c b/tests/test_stasis.c index 806fbf81fcd..9d42d007cdc 100644 --- a/tests/test_stasis.c +++ b/tests/test_stasis.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/module.h" #include "asterisk/stasis.h" diff --git a/tests/test_stasis_channels.c b/tests/test_stasis_channels.c index fe320f29bca..57448736478 100644 --- a/tests/test_stasis_channels.c +++ b/tests/test_stasis_channels.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/module.h" #include "asterisk/stasis.h" diff --git a/tests/test_stasis_endpoints.c b/tests/test_stasis_endpoints.c index 6e972758899..134738fee53 100644 --- a/tests/test_stasis_endpoints.c +++ b/tests/test_stasis_endpoints.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/astobj2.h" #include "asterisk/channel.h" #include "asterisk/endpoints.h" diff --git a/tests/test_strings.c b/tests/test_strings.c index 28f6e1606ba..90b0d3606c7 100644 --- a/tests/test_strings.c +++ b/tests/test_strings.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/utils.h" #include "asterisk/strings.h" diff --git a/tests/test_substitution.c b/tests/test_substitution.c index c22f5e603d2..ca84d002356 100644 --- a/tests/test_substitution.c +++ b/tests/test_substitution.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/file.h" #include "asterisk/channel.h" #include "asterisk/pbx.h" diff --git a/tests/test_time.c b/tests/test_time.c index fcba960b9fd..b58a4732b08 100644 --- a/tests/test_time.c +++ b/tests/test_time.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/app.h" #include "asterisk/module.h" diff --git a/tests/test_uri.c b/tests/test_uri.c index 8a78644eaa2..3004227a066 100644 --- a/tests/test_uri.c +++ b/tests/test_uri.c @@ -31,8 +31,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/uri.h" diff --git a/tests/test_utils.c b/tests/test_utils.c index abb0c3395b8..d8915ba28da 100644 --- a/tests/test_utils.c +++ b/tests/test_utils.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE(); - #include "asterisk/utils.h" #include "asterisk/test.h" #include "asterisk/crypto.h" diff --git a/tests/test_vector.c b/tests/test_vector.c index ff305b5d7e6..8ca4efa1abf 100644 --- a/tests/test_vector.c +++ b/tests/test_vector.c @@ -34,8 +34,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/utils.h" #include "asterisk/strings.h" diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c index fc371bad9c8..9cadf2394ed 100644 --- a/tests/test_voicemail_api.c +++ b/tests/test_voicemail_api.c @@ -33,8 +33,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include #include "asterisk/utils.h" diff --git a/tests/test_websocket_client.c b/tests/test_websocket_client.c index ca8cb85ac89..6743b53693a 100644 --- a/tests/test_websocket_client.c +++ b/tests/test_websocket_client.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/test.h" #include "asterisk/module.h" #include "asterisk/astobj2.h" diff --git a/tests/test_xml_escape.c b/tests/test_xml_escape.c index 5e6abc72ee9..a49d6c11663 100644 --- a/tests/test_xml_escape.c +++ b/tests/test_xml_escape.c @@ -32,8 +32,6 @@ #include "asterisk.h" -ASTERISK_REGISTER_FILE() - #include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/test.h" diff --git a/utils/ael_main.c b/utils/ael_main.c index 1801b12b8cc..f22e9a05b2e 100644 --- a/utils/ael_main.c +++ b/utils/ael_main.c @@ -18,8 +18,6 @@ #include #include -ASTERISK_REGISTER_FILE() - #include "asterisk/backtrace.h" #include "asterisk/channel.h" #include "asterisk/ast_expr.h" @@ -32,8 +30,6 @@ ASTERISK_REGISTER_FILE() int option_debug = 0; int option_verbose = 0; -void __ast_register_file(const char *file) { } -void __ast_unregister_file(const char *file) { } /*** MODULEINFO res_ael_share diff --git a/utils/astman.c b/utils/astman.c index a6803c8a58f..63d7f5ada1e 100644 --- a/utils/astman.c +++ b/utils/astman.c @@ -27,7 +27,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include #include @@ -88,16 +87,6 @@ struct ast_chan { static AST_LIST_HEAD_NOLOCK_STATIC(chans, ast_chan); /* dummy functions to be compatible with the Asterisk core for md5.c */ -void __ast_register_file(const char *file); -void __ast_register_file(const char *file) -{ -} - -void __ast_unregister_file(const char *file); -void __ast_unregister_file(const char *file) -{ -} - int ast_add_profile(const char *, uint64_t scale); int ast_add_profile(const char *s, uint64_t scale) { diff --git a/utils/check_expr.c b/utils/check_expr.c index abfb91dcfd8..201fa04d214 100644 --- a/utils/check_expr.c +++ b/utils/check_expr.c @@ -21,7 +21,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include "asterisk/ast_expr.h" @@ -157,8 +156,6 @@ unsigned int check_expr(char* buffer, char* error_report); int check_eval(char *buffer, char *error_report); void parse_file(const char *fname); -void __ast_register_file(const char *file); -void __ast_register_file(const char *file) { } int ast_add_profile(const char *x, uint64_t scale) { return 0;} int ast_atomic_fetchadd_int_slow(volatile int *p, int v) { @@ -168,11 +165,6 @@ int ast_atomic_fetchadd_int_slow(volatile int *p, int v) return ret; } -void __ast_unregister_file(const char *file); -void __ast_unregister_file(const char *file) -{ -} - char *find_var(const char *varname) /* the list should be pretty short, if there's any list at all */ { struct varz *t; diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 3ebc56e4ac4..1767d983337 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -28,7 +28,6 @@ ***/ #include "asterisk.h" -ASTERISK_REGISTER_FILE() #include "asterisk/paths.h" /* CONFIG_DIR */ #include @@ -79,15 +78,6 @@ char ast_config_AST_SYSTEM_NAME[20] = ""; */ int option_debug = 0; int option_verbose = 0; -void __ast_register_file(const char *file); -void __ast_register_file(const char *file) -{ -} - -void __ast_unregister_file(const char *file); -void __ast_unregister_file(const char *file) -{ -} int ast_add_profile(const char *x, uint64_t scale) { return 0;} /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */ void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf,5,6))); From 4f45d62653a2b0e5878607df355c042ea41daa13 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 26 Oct 2016 17:48:24 -0600 Subject: [PATCH 0829/1578] pjproject_bundled: Remove usage of tar's --strip-components option Older versions of tar don't support the --strip-components option so instead of doing 'tar --strip-components=1 -C source', we now just untar to the tarball's root directory (pjproject-) and rename that directory to 'source'. Also fixed an issue where the pjproject source directory is a hard coded absolute pathname. ASTERISK-26510 #close ASTERISK-22480 #close Change-Id: I9ec92952507a91ff4e4d01e0149e09fd8e8f32b0 --- third-party/pjproject/Makefile | 7 ++++--- .../pjproject/patches/0000-remove-third-party.patch | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index aaf69bff10e..07a6c9cd668 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -1,6 +1,7 @@ .PHONY: _all all _install install clean distclean echo_cflags configure include ../versions.mak +export PJDIR := $(shell pwd -P)/source SPECIAL_TARGETS := @@ -85,9 +86,9 @@ $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2: ../versions.mak source/.unpacked: $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 $(ECHO_PREFIX) Unpacking $< - -@rm -rf source >/dev/null 2>&1 - -@mkdir source >/dev/null 2>&1 - $(CMD_PREFIX) $(TAR) --strip-components=1 -C source -xjf $< + -@rm -rf source pjproject-* >/dev/null 2>&1 + $(CMD_PREFIX) $(TAR) -xjf $< + @mv pjproject-$(PJPROJECT_VERSION) source $(ECHO_PREFIX) Applying patches $(CMD_PREFIX) ./apply_patches $(QUIET_CONFIGURE) patches source -@touch source/.unpacked diff --git a/third-party/pjproject/patches/0000-remove-third-party.patch b/third-party/pjproject/patches/0000-remove-third-party.patch index 131775195a0..aca7f019888 100644 --- a/third-party/pjproject/patches/0000-remove-third-party.patch +++ b/third-party/pjproject/patches/0000-remove-third-party.patch @@ -2,6 +2,11 @@ diff --git a/build.mak.in b/build.mak.in index 802211c..006d887 100644 --- a/build.mak.in +++ b/build.mak.in +@@ -1,4 +1,3 @@ +-export PJDIR := @ac_pjdir@ + include $(PJDIR)/version.mak + export PJ_DIR := $(PJDIR) + @@ -9,7 +9,7 @@ export HOST_NAME := unix export CC_NAME := gcc export TARGET_NAME := @target@ From 0646b48ece3d1a63cd84f88b14f8679a6d919c12 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 18 Oct 2016 17:06:38 +0300 Subject: [PATCH 0830/1578] chan_dahdi: remove by_name support Support for referring to DAHDI channels by logical names was added in (FIXME: when? Asterisk 11? 1.8?) and was intended to be part of support of refering to channels by name. While technically usable, it has never been properly supported in dahdi-tools, as using it would require many changes at the Asterisk level. Instead logical mapping was added at the kernel level. Thus it seems that refering to DAHDI channels by name is not really used by anyone, and therefore should probably be removed. Change-Id: I7d50bbfd9d957586f5cd06570244ef87bd54b485 --- UPGRADE.txt | 9 +++ channels/chan_dahdi.c | 84 ++------------------------ configs/samples/chan_dahdi.conf.sample | 18 ------ 3 files changed, 14 insertions(+), 97 deletions(-) diff --git a/UPGRADE.txt b/UPGRADE.txt index 5f6cc3ed305..6cb61480726 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -32,3 +32,12 @@ Queue: added via the CLI command "queue add" or the AMI action "QueueAdd") now have their ringinuse value updated to the value of the queue. Previously, the ringinuse value for dynamic members was not updated on reload. + +Channel Drivers: + +chan_dahdi: + - Support for specifying a DAHDI channel using a path under /dev/dahdi + ("by name") has been removed. It was never used. Instead you should + use kernel-level channel number allocation using span assignments. + See the documentation of dahdi-linux and dahdi-tools. + diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 8cccf843b42..dde3c08fcf1 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -11977,38 +11977,6 @@ static int sigtype_to_signalling(int sigtype) return sigtype; } -/*! - * \internal - * \brief Get file name and channel number from (subdir,number) - * - * \param subdir name of the subdirectory under /dev/dahdi/ - * \param channel name of device file under /dev/dahdi// - * \param path buffer to put file name in - * \param pathlen maximal length of path - * - * \retval minor number of dahdi channel. - * \retval -errno on error. - */ -static int device2chan(const char *subdir, int channel, char *path, int pathlen) -{ - struct stat stbuf; - int num; - - snprintf(path, pathlen, "/dev/dahdi/%s/%d", subdir, channel); - if (stat(path, &stbuf) < 0) { - ast_log(LOG_ERROR, "stat(%s) failed: %s\n", path, strerror(errno)); - return -errno; - } - if (!S_ISCHR(stbuf.st_mode)) { - ast_log(LOG_ERROR, "%s: Not a character device file\n", path); - return -EINVAL; - } - num = minor(stbuf.st_rdev); - ast_debug(1, "%s -> %d\n", path, num); - return num; - -} - /*! * \internal * \brief Initialize/create a channel interface. @@ -17426,33 +17394,9 @@ static int unload_module(void) return __unload_module(); } -static void string_replace(char *str, int char1, int char2) -{ - for (; *str; str++) { - if (*str == char1) { - *str = char2; - } - } -} - -static char *parse_spanchan(char *chanstr, char **subdir) -{ - char *p; - - if ((p = strrchr(chanstr, '!')) == NULL) { - *subdir = NULL; - return chanstr; - } - *p++ = '\0'; - string_replace(chanstr, '!', '/'); - *subdir = chanstr; - return p; -} - static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno) { char *c, *chan; - char *subdir; int x, start, finish; struct dahdi_pvt *tmp; @@ -17462,7 +17406,6 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r } c = ast_strdupa(value); - c = parse_spanchan(c, &subdir); while ((chan = strsep(&c, ","))) { if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) { @@ -17484,39 +17427,22 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r } for (x = start; x <= finish; x++) { - char fn[PATH_MAX]; - int real_channel = x; - - if (!ast_strlen_zero(subdir)) { - real_channel = device2chan(subdir, x, fn, sizeof(fn)); - if (real_channel < 0) { - if (conf->ignore_failed_channels) { - ast_log(LOG_WARNING, "Failed configuring %s!%d, (got %d). But moving on to others.\n", - subdir, x, real_channel); - continue; - } else { - ast_log(LOG_ERROR, "Failed configuring %s!%d, (got %d).\n", - subdir, x, real_channel); - return -1; - } - } - } if (conf->wanted_channels_start && - (real_channel < conf->wanted_channels_start || - real_channel > conf->wanted_channels_end) + (x < conf->wanted_channels_start || + x > conf->wanted_channels_end) ) { continue; } - tmp = mkintf(real_channel, conf, reload); + tmp = mkintf(x, conf, reload); if (tmp) { - ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", real_channel, sig2str(tmp->sig)); + ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig)); } else { ast_log(LOG_ERROR, "Unable to %s channel '%s'\n", (reload == 1) ? "reconfigure" : "register", value); return -1; } - if (real_channel == CHAN_PSEUDO) { + if (x == CHAN_PSEUDO) { has_pseudo = 1; } } diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/samples/chan_dahdi.conf.sample index e70a2a138f6..69f75127979 100644 --- a/configs/samples/chan_dahdi.conf.sample +++ b/configs/samples/chan_dahdi.conf.sample @@ -1330,24 +1330,6 @@ pickupgroup=1 ; signalling = pri_cpe ; group = 2 ; channel => 1-23 -; -; Alternatively, the number of the channel may be replaced with a relative -; path to a device file under /dev/dahdi . The final element of that file -; must be a number, though. The directory separator is '!', as we can't -; use '/' in a dial string. So if we have -; -; /dev/dahdi/span-name/pstn/00/1 -; /dev/dahdi/span-name/pstn/00/2 -; /dev/dahdi/span-name/pstn/00/3 -; /dev/dahdi/span-name/pstn/00/4 -; -; we could use: -;channel => span-name!pstn!00!1-4 -; -; or: -;channel => span-name!pstn!00!1,2,3,4 -; -; See also ignore_failed_channels above. ; Used for distinctive ring support for x100p. ; You can see the dringX patterns is to set any one of the dringXcontext fields From badd38f03180c65cb5c4bdd6262cdee730a393dc Mon Sep 17 00:00:00 2001 From: Rusty Newton Date: Fri, 28 Oct 2016 09:50:32 -0500 Subject: [PATCH 0831/1578] SAC documentation: don't specify transports for endpoints and registrations Removing explicit transport definition for endpoints and registrations. It isn't necessary and isn't generally advised. ASTERISK-26514 #close Change-Id: Ifdec5e631962438a4683600968dfa4bfd15909fb --- configs/basic-pbx/pjsip.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/configs/basic-pbx/pjsip.conf b/configs/basic-pbx/pjsip.conf index 00e386a73ec..b20e0c623a1 100644 --- a/configs/basic-pbx/pjsip.conf +++ b/configs/basic-pbx/pjsip.conf @@ -15,7 +15,6 @@ bind = 0.0.0.0 [dcs-trunk] type = registration -transport = transport-udp-nat outbound_auth = dcs-trunk-auth server_uri = sip:sip.digiumcloud.net ;client_uri = sip:myaccountID@sip.digiumcloud.net @@ -31,7 +30,6 @@ auth_type = userpass [dcs-endpoint] type=endpoint -transport = transport-udp-nat context = DCS-Incoming allow = !all,g722,ulaw outbound_auth = dcs-auth @@ -59,7 +57,6 @@ endpoint = dcs-endpoint ; Our primary endpoint template for internal desk phones. [endpoint-internal-d70](!) type = endpoint -transport = transport-udp-nat context = Long-Distance allow = !all,g722,ulaw direct_media = no From d6ad86789702ab2e4161c5ea086cdae64c9b614d Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 27 Oct 2016 22:49:43 -0400 Subject: [PATCH 0832/1578] Fix shutdown crash caused by modules being left open. It is only safe to run ast_register_cleanup callbacks when all modules have been unloaded. Previously these callbacks were run during graceful shutdown, making it possible to crash during shutdown. ASTERISK-26513 #close Change-Id: Ibfa635bb688d1227ec54aa211d90d6bd45052e21 --- include/asterisk/_private.h | 1 + include/asterisk/module.h | 7 ------- main/asterisk.c | 5 +++-- main/loader.c | 5 ++++- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 36b316f2a32..b3c2b200206 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -16,6 +16,7 @@ #define _ASTERISK__PRIVATE_H int load_modules(unsigned int); /*!< Provided by loader.c */ +int modules_shutdown(void); /*!< Provided by loader.c */ int load_pbx(void); /*!< Provided by pbx.c */ int load_pbx_builtins(void); /*!< Provided by pbx_builtins.c */ int load_pbx_functions_cli(void); /*!< Provided by pbx_functions.c */ diff --git a/include/asterisk/module.h b/include/asterisk/module.h index d5616e9d82d..a80c7f843ae 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -228,13 +228,6 @@ int ast_loader_register(int (*updater)(void)); */ int ast_loader_unregister(int (*updater)(void)); -/*! - * \brief Run the unload() callback for all loaded modules - * - * This function should be called when Asterisk is shutting down gracefully. - */ -void ast_module_shutdown(void); - /*! * \brief Match modules names for the Asterisk cli. * \param line Unused by this function, but this should be the line we are diff --git a/main/asterisk.c b/main/asterisk.c index d4b39a26521..56fc107dba0 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -2010,8 +2010,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart) struct ast_json *json_object = NULL; int run_cleanups = niceness >= SHUTDOWN_NICE; - if (run_cleanups) { - ast_module_shutdown(); + if (run_cleanups && modules_shutdown()) { + ast_verb(0, "Some modules could not be unloaded, switching to fast shutdown\n"); + run_cleanups = 0; } if (!restart) { diff --git a/main/loader.c b/main/loader.c index 6617783cf28..dacfce1f687 100644 --- a/main/loader.c +++ b/main/loader.c @@ -607,7 +607,7 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned #endif -void ast_module_shutdown(void) +int modules_shutdown(void) { struct ast_module *mod; int somethingchanged = 1, final = 0; @@ -655,7 +655,10 @@ void ast_module_shutdown(void) } } while (somethingchanged && !final); + final = AST_DLLIST_EMPTY(&module_list); AST_DLLIST_UNLOCK(&module_list); + + return !final; } int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force) From 9d8b9b6ca5a47911c50f61696b2bc9978ab1ff80 Mon Sep 17 00:00:00 2001 From: mkrokosz Date: Fri, 28 Oct 2016 14:30:02 -0400 Subject: [PATCH 0833/1578] res_pjsip_outbound_publish: Fix crash when publishing device state. While publishing device state between multiple instances of Asterisk, a crash will sporadically occur under high CPS which looks to be a race condition operating on the publisher queue. ASTERISK-26506 Change-Id: I28da25d346deb358eff1d563485cabc433ce1ed6 --- res/res_pjsip_outbound_publish.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 0aad5fcdb64..87680480c8f 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -786,6 +786,7 @@ static int publisher_client_send(void *obj, void *arg, void *data, int flags) struct sip_outbound_publish_message *message; size_t type_len = 0, subtype_len = 0, body_text_len = 0; int *res = data; + SCOPED_AO2LOCK(lock, publisher); *res = -1; if (!publisher->client) { From 12bdde6a6cab0c88845c100764105ca8e44baa43 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 28 Oct 2016 15:59:19 -0600 Subject: [PATCH 0834/1578] pjproject_bundled: Fix issue where "/version.mak" wasn't found main/Makefile includes third-party/pjproject/build.mak but doesn't set PJDIR beforehand so "include $(PJDIR)/version.mak" evaluates to "/version.mak". Fix is to set PJDIR in main/Makefile before the include. Change-Id: I0f7c67d60209049056fe9c4b041bf0463aa95604 --- main/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/main/Makefile b/main/Makefile index d41302a7fc3..3db0392ff37 100644 --- a/main/Makefile +++ b/main/Makefile @@ -253,6 +253,7 @@ ifeq ($(PJPROJECT_BUNDLED),yes) ASTPJ_SO_VERSION=2 ASTPJ_LDLIBS=-L. -lasteriskpj +PJDIR=$(ASTTOPDIR)/$(PJPROJECT_DIR)/source -include $(ASTTOPDIR)/$(PJPROJECT_DIR)/build.mak PJPROJECT_LDLIBS := \ From 6feee22e094c6eb9df7e9682cfffe7b05dd61fce Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 28 Oct 2016 14:55:08 -0500 Subject: [PATCH 0835/1578] bundled pjproject: Crashes while resolving DNS names. PJPROJECT 2.5.5 introduced a race condition with the -r5349 IPv6 DNS patch. The patches below fix the DNS lookup race condition crash caused by attempting to send the same message twice for the single DNS lookup. 0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch 0006-r5473-svn-backport-Fix-pending-query.patch The patch below removes a cached DNS response from the hash table when another thread is referencing the old entry. The table still contained the entry when it was destroyed which can result in inexplicable crashes. 0006-r5475-svn-backport-Remove-DNS-cache-entry.patch ASTERISK-26344 #close Reported by: Ian Gilmour ASTERISK-26387 #close Reported by: Harley Peters Change-Id: I17fde80359e66f65a91341ceca58d914d0f61cc4 --- ...-backport-Various-fixes-for-DNS-IPv6.patch | 134 ++++++++++++++++++ ...r5473-svn-backport-Fix-pending-query.patch | 28 ++++ ...-svn-backport-Remove-DNS-cache-entry.patch | 70 +++++++++ 3 files changed, 232 insertions(+) create mode 100644 third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch create mode 100644 third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch create mode 100644 third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch diff --git a/third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch b/third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch new file mode 100644 index 00000000000..98c33e51105 --- /dev/null +++ b/third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch @@ -0,0 +1,134 @@ +From 2ab7a9f67caf73be3f2215473f72882cfaef4972 Mon Sep 17 00:00:00 2001 +From: Richard Mudgett +Date: Fri, 28 Oct 2016 12:11:30 -0500 +Subject: [PATCH 1/3] r5471 svn backport Various fixes for DNS IPv6 + +Fixed #1974: Various fixes for DNS IPv6 +--- + pjlib-util/src/pjlib-util/resolver.c | 11 +++++------ + pjlib-util/src/pjlib-util/srv_resolver.c | 17 +++++++++++++++-- + pjsip/src/pjsip/sip_resolve.c | 14 +++++++------- + 3 files changed, 27 insertions(+), 15 deletions(-) + +diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c +index e5e1bed..d24ef9d 100644 +--- a/pjlib-util/src/pjlib-util/resolver.c ++++ b/pjlib-util/src/pjlib-util/resolver.c +@@ -835,7 +835,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, + pj_time_val now; + struct res_key key; + struct cached_res *cache; +- pj_dns_async_query *q; ++ pj_dns_async_query *q, *p_q = NULL; + pj_uint32_t hval; + pj_status_t status = PJ_SUCCESS; + +@@ -849,9 +849,6 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, + /* Check type */ + PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL); + +- if (p_query) +- *p_query = NULL; +- + /* Build resource key for looking up hash tables */ + init_res_key(&key, type, name); + +@@ -970,10 +967,12 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, + pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key), + 0, q->hbufkey, q); + +- if (p_query) +- *p_query = q; ++ p_q = q; + + on_return: ++ if (p_query) ++ *p_query = p_q; ++ + pj_mutex_unlock(resolver->mutex); + return status; + } +diff --git a/pjlib-util/src/pjlib-util/srv_resolver.c b/pjlib-util/src/pjlib-util/srv_resolver.c +index 02672aa..ff9c979 100644 +--- a/pjlib-util/src/pjlib-util/srv_resolver.c ++++ b/pjlib-util/src/pjlib-util/srv_resolver.c +@@ -187,9 +187,12 @@ PJ_DEF(pj_status_t) pj_dns_srv_cancel_query(pj_dns_srv_async_query *query, + has_pending = PJ_TRUE; + } + if (srv->q_aaaa) { +- pj_dns_resolver_cancel_query(srv->q_aaaa, PJ_FALSE); ++ /* Check if it is a dummy query. */ ++ if (srv->q_aaaa != (pj_dns_async_query*)0x1) { ++ pj_dns_resolver_cancel_query(srv->q_aaaa, PJ_FALSE); ++ has_pending = PJ_TRUE; ++ } + srv->q_aaaa = NULL; +- has_pending = PJ_TRUE; + } + } + +@@ -485,12 +488,22 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job) + srv->common.type = PJ_DNS_TYPE_A; + srv->common_aaaa.type = PJ_DNS_TYPE_AAAA; + srv->parent = query_job; ++ srv->q_a = NULL; ++ srv->q_aaaa = NULL; + + status = PJ_SUCCESS; + + /* Start DNA A record query */ + if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY) == 0) + { ++ if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0) { ++ /* If there will be DNS AAAA query too, let's setup ++ * a dummy one here, otherwise app callback may be called ++ * immediately (before DNS AAAA query is sent) when ++ * DNS A record is available in the cache. ++ */ ++ srv->q_aaaa = (pj_dns_async_query*)0x1; ++ } + status = pj_dns_resolver_start_query(query_job->resolver, + &srv->target_name, + PJ_DNS_TYPE_A, 0, +diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c +index ed326ba..3f3654d 100644 +--- a/pjsip/src/pjsip/sip_resolve.c ++++ b/pjsip/src/pjsip/sip_resolve.c +@@ -452,7 +452,7 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver, + } + + /* Resolve DNS AAAA record if address family is not fixed to IPv4 */ +- if (af != pj_AF_INET()) { ++ if (af != pj_AF_INET() && status == PJ_SUCCESS) { + status = pj_dns_resolver_start_query(resolver->res, + &query->naptr[0].name, + PJ_DNS_TYPE_AAAA, 0, +@@ -530,9 +530,9 @@ static void dns_a_callback(void *user_data, + + ++srv->count; + } +- +- } else { +- ++ } ++ ++ if (status != PJ_SUCCESS) { + char errmsg[PJ_ERR_MSG_SIZE]; + + /* Log error */ +@@ -593,9 +593,9 @@ static void dns_aaaa_callback(void *user_data, + + ++srv->count; + } +- +- } else { +- ++ } ++ ++ if (status != PJ_SUCCESS) { + char errmsg[PJ_ERR_MSG_SIZE]; + + /* Log error */ +-- +1.7.9.5 + diff --git a/third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch b/third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch new file mode 100644 index 00000000000..4d11d57efae --- /dev/null +++ b/third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch @@ -0,0 +1,28 @@ +From 509d4339747f11cfbde3a0acc447ef5d521eea93 Mon Sep 17 00:00:00 2001 +From: Richard Mudgett +Date: Fri, 28 Oct 2016 12:12:28 -0500 +Subject: [PATCH 2/3] r5473 svn backport Fix pending query + +Re #1974: +If there is a pending query, set the return value to that query (instead of NULL) + +Thanks to Richard Mudgett for the patch. +--- + pjlib-util/src/pjlib-util/resolver.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c +index d24ef9d..fe687b7 100644 +--- a/pjlib-util/src/pjlib-util/resolver.c ++++ b/pjlib-util/src/pjlib-util/resolver.c +@@ -940,6 +940,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, + /* Done. This child query will be notified once the "parent" + * query completes. + */ ++ p_q = nq; + status = PJ_SUCCESS; + goto on_return; + } +-- +1.7.9.5 + diff --git a/third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch b/third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch new file mode 100644 index 00000000000..e378c30d757 --- /dev/null +++ b/third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch @@ -0,0 +1,70 @@ +From 46e1cfa18853a38b7fcdebad782710c5db676657 Mon Sep 17 00:00:00 2001 +From: Richard Mudgett +Date: Fri, 28 Oct 2016 12:15:44 -0500 +Subject: [PATCH 3/3] r5475 svn backport Remove DNS cache entry + +Re #1974: Remove DNS cache entry from resolver's hash table when app callback has a reference. + +Thanks to Richard Mudgett for the patch. +--- + pjlib-util/src/pjlib-util/resolver.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c +index fe687b7..52b7655 100644 +--- a/pjlib-util/src/pjlib-util/resolver.c ++++ b/pjlib-util/src/pjlib-util/resolver.c +@@ -1444,10 +1444,12 @@ static void update_res_cache(pj_dns_resolver *resolver, + if (ttl > resolver->settings.cache_max_ttl) + ttl = resolver->settings.cache_max_ttl; + ++ /* Get a cache response entry */ ++ cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key, ++ sizeof(*key), &hval); ++ + /* If TTL is zero, clear the same entry in the hash table */ + if (ttl == 0) { +- cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key, +- sizeof(*key), &hval); + /* Remove the entry before releasing its pool (see ticket #1710) */ + pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL); + +@@ -1457,24 +1459,23 @@ static void update_res_cache(pj_dns_resolver *resolver, + return; + } + +- /* Get a cache response entry */ +- cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key, +- sizeof(*key), &hval); + if (cache == NULL) { + cache = alloc_entry(resolver); +- } else if (cache->ref_cnt > 1) { +- /* When cache entry is being used by callback (to app), just decrement +- * ref_cnt so it will be freed after the callback returns and allocate +- * new entry. +- */ +- cache->ref_cnt--; +- cache = alloc_entry(resolver); + } else { + /* Remove the entry before resetting its pool (see ticket #1710) */ + pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL); + +- /* Reset cache to avoid bloated cache pool */ +- reset_entry(&cache); ++ if (cache->ref_cnt > 1) { ++ /* When cache entry is being used by callback (to app), ++ * just decrement ref_cnt so it will be freed after ++ * the callback returns and allocate new entry. ++ */ ++ cache->ref_cnt--; ++ cache = alloc_entry(resolver); ++ } else { ++ /* Reset cache to avoid bloated cache pool */ ++ reset_entry(&cache); ++ } + } + + /* Duplicate the packet. +-- +1.7.9.5 + From ad60927a40cf07bb60225c3613ae92b12aa92101 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 29 Oct 2016 11:19:53 -0400 Subject: [PATCH 0836/1578] astobj2: Declare private variable data_size for AO2_DEBUG only. Every ao2 object contains storage for a private variable data_size, though the value is never read if AO2_DEBUG is disabled. This change makes the variable conditional, reducing memory usage. ASTERISK-26524 #close Change-Id: If859929e507676ebc58b0f84247a4231e11da07f --- main/astobj2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main/astobj2.c b/main/astobj2.c index 114f260454d..c8e48bbf5a0 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -52,8 +52,10 @@ struct __priv_data { ao2_destructor_fn destructor_fn; /*! This field is used for astobj2 and ao2_weakproxy objects to reference each other */ void *weakptr; +#if defined(AO2_DEBUG) /*! User data size for stats */ size_t data_size; +#endif /*! The ao2 object option flags */ uint32_t options; /*! magic number. This is used to verify that a pointer passed in is a @@ -669,11 +671,11 @@ static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_f /* Initialize common ao2 values. */ obj->priv_data.ref_counter = 1; obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */ - obj->priv_data.data_size = data_size; obj->priv_data.options = options; obj->priv_data.magic = AO2_MAGIC; #ifdef AO2_DEBUG + obj->priv_data.data_size = data_size; ast_atomic_fetchadd_int(&ao2.total_objects, 1); ast_atomic_fetchadd_int(&ao2.total_mem, data_size); ast_atomic_fetchadd_int(&ao2.total_refs, 1); From 273debd261148dcc0962566d83ee9c601ee5c99c Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sun, 30 Oct 2016 14:33:12 -0400 Subject: [PATCH 0837/1578] vector: Prevent NULL argument to memcpy. Headers declare that memcpy does not accept NULL argument for the first two parameters. Add a conditional block to prevent memcpy and ast_free from running on vectors with NULL element array. ASTERISK-26526 #close Change-Id: I988a476bb5fcfcbd3f6d6c6b3e7769e4f9629b71 --- include/asterisk/vector.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index c74f0a89b58..83732e7c8ea 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -172,9 +172,11 @@ typeof((vec)->elems) new_elems = ast_calloc(1, \ new_max * sizeof(*new_elems)); \ if (new_elems) { \ - memcpy(new_elems, (vec)->elems, \ - (vec)->current * sizeof(*new_elems)); \ - ast_free((vec)->elems); \ + if ((vec)->elems) { \ + memcpy(new_elems, (vec)->elems, \ + (vec)->current * sizeof(*new_elems)); \ + ast_free((vec)->elems); \ + } \ (vec)->elems = new_elems; \ (vec)->max = new_max; \ } else { \ From 1648ca06c3257874e229df8f32a0b34082105471 Mon Sep 17 00:00:00 2001 From: Etienne Lessard Date: Mon, 31 Oct 2016 14:46:54 -0400 Subject: [PATCH 0838/1578] manager: Add documentation for NewConnectedLine event. The NewConnectedLine event has been added by commit fe7671f, but the documentation was missing. ASTERISK-26537 #close Change-Id: I7fc331f18caa28492da9303e576f70884ca8c9e6 --- main/manager_channels.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/main/manager_channels.c b/main/manager_channels.c index 7f3c1b6458c..22429b76a54 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -139,6 +139,17 @@ + + + Raised when a channel's connected line information is changed. + + + + + CONNECTEDLINE + + + Raised when a Channel's AccountCode is changed. From f27f837a9f5fae97af6e86d7d5f1f645e7c12186 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 31 Oct 2016 15:12:57 -0600 Subject: [PATCH 0839/1578] pjproject_bundled: Fix compile of pjsua so it handles audio In order for pjsua and its python binding to actually negotiate audio for the testsuite tests, it needs g711 and resample. The pj* libraries themselves do not. Unfortunately, pjproject relies on a brand new libresample that most distros don't ship so we need to use the libresample already bundled with pjproject. Only the pjsua executable and the _pjsua.so python library are linked with it so it shouldn't interfere with asterisk itself. Also it was pointed out that apply_patches couldn't handle multiple patches that depended on each other during the dry-run, so the dry-run was removed. Change-Id: I24f397462b486dcdde0dcafe40e6c55a6593f098 --- third-party/pjproject/Makefile | 10 ++++-- third-party/pjproject/Makefile.rules | 4 +-- third-party/pjproject/apply_patches | 10 ------ .../patches/0000-remove-third-party.patch | 33 +++++++------------ 4 files changed, 21 insertions(+), 36 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 07a6c9cd668..209e681cd7c 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -125,11 +125,17 @@ libpj%.a: .rebuild_needed source/build.mak $(CMD_PREFIX) $(MAKE) -C $(dir $(shell dirname $@))/build $(@F) $(REALLY_QUIET) -@rm -rf .rebuild_needed +# pjsua needs resample and g711 to successfully run the testsuite +libresample%.a: .rebuild_needed source/build.mak + $(ECHO_PREFIX) Compiling lib $(@F) + $(CMD_PREFIX) $(MAKE) -C $(dir $(shell dirname $@))/build/resample all $(REALLY_QUIET) + -@rm -rf .rebuild_needed + # We need to compile pjlib, then pjlib-util, then the rest # so we separate them out and create the dependencies PJLIB_LIB_FILES = $(foreach lib,$(PJ_LIB_FILES),$(if $(findstring libpj-,$(lib)),$(lib),)) PJLIB_UTIL_LIB_FILES = $(foreach lib,$(PJ_LIB_FILES),$(if $(findstring libpjlib-util,$(lib)),$(lib),)) -PJSIP_LIB_FILES = $(filter-out $(PJLIB_LIB_FILES) $(PJLIB_UTIL_LIB_FILES),$(PJ_LIB_FILES)) +PJSIP_LIB_FILES = $(filter-out $(PJLIB_LIB_FILES) $(PJLIB_UTIL_LIB_FILES) $(APP_THIRD_PARTY_LIB_FILES),$(PJ_LIB_FILES)) ALL_LIB_FILES = $(PJLIB_LIB_FILES) $(PJLIB_UTIL_LIB_FILES) $(PJSIP_LIB_FILES) $(PJLIB_UTIL_LIB_FILES): $(PJLIB_LIB_FILES) @@ -152,7 +158,7 @@ source/pjsip-apps/lib/libasterisk_malloc_debug.a: source/pjsip-apps/lib/asterisk $(CMD_PREFIX) ar qs $@ $< >/dev/null 2>&1 $(apps): APP = $(filter pj%,$(subst -, ,$(notdir $@))) -$(apps): pjproject.symbols +$(apps): pjproject.symbols $(APP_THIRD_PARTY_LIB_FILES) $(ECHO_PREFIX) Compiling $(APP) $(CMD_PREFIX) +$(MAKE) -C source/pjsip-apps/build $(filter pj%,$(subst -, ,$(notdir $@))) $(REALLY_QUIET) diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index 62d5a465305..531a259d305 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -9,7 +9,6 @@ PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ --disable-gsm-codec \ --disable-ilbc-codec \ --disable-l16-codec \ - --disable-g711-codec \ --disable-g722-codec \ --disable-g7221-codec \ --disable-opencore-amr \ @@ -23,7 +22,6 @@ PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ --disable-oss \ --disable-sdl \ --disable-libyuv \ - --disable-resample \ --disable-ffmpeg \ --disable-openh264 \ --disable-ipp \ @@ -31,5 +29,5 @@ PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ --without-external-srtp ifeq ($(shell uname -s),Linux) - PJPROJECT_CONFIG_OPTS += --enable-epoll + PJPROJECT_CONFIG_OPTS += --enable-epoll endif diff --git a/third-party/pjproject/apply_patches b/third-party/pjproject/apply_patches index 69a0ad0c164..5f9fde283fc 100755 --- a/third-party/pjproject/apply_patches +++ b/third-party/pjproject/apply_patches @@ -28,16 +28,6 @@ if [ ! "$(ls -A $patchdir/*.patch 2>/dev/null)" ] ; then exit 0 fi -if patch --dry-run /dev/null 2>&1 ; then - DRY_RUN=--dry-run -else - DRY_RUN=-C -fi - -for patchfile in $patchdir/*.patch ; do - ${PATCH} -d $sourcedir -p1 -s -r- -f -N $DRY_RUN -i "$patchfile" || (echo "Patchfile $(basename $patchfile) failed to apply" >&2 ; exit 1) || exit 1 -done - for patchfile in "$patchdir"/*.patch ; do [ -z $quiet ] && echo "Applying patch $(basename $patchfile)" ${PATCH} -d "$sourcedir" -p1 -s -i "$patchfile" || exit 1 diff --git a/third-party/pjproject/patches/0000-remove-third-party.patch b/third-party/pjproject/patches/0000-remove-third-party.patch index aca7f019888..2e3bb5f9fcf 100644 --- a/third-party/pjproject/patches/0000-remove-third-party.patch +++ b/third-party/pjproject/patches/0000-remove-third-party.patch @@ -1,5 +1,5 @@ diff --git a/build.mak.in b/build.mak.in -index 802211c..006d887 100644 +index 802211c..25fd05e 100644 --- a/build.mak.in +++ b/build.mak.in @@ -1,4 +1,3 @@ @@ -7,7 +7,7 @@ index 802211c..006d887 100644 include $(PJDIR)/version.mak export PJ_DIR := $(PJDIR) -@@ -9,7 +9,7 @@ export HOST_NAME := unix +@@ -9,7 +8,7 @@ export HOST_NAME := unix export CC_NAME := gcc export TARGET_NAME := @target@ export CROSS_COMPILE := @ac_cross_compile@ @@ -16,7 +16,7 @@ index 802211c..006d887 100644 export SHLIB_SUFFIX := @ac_shlib_suffix@ export prefix := @prefix@ -@@ -28,114 +28,6 @@ export APP_THIRD_PARTY_EXT := +@@ -28,19 +27,6 @@ export APP_THIRD_PARTY_EXT := export APP_THIRD_PARTY_LIBS := export APP_THIRD_PARTY_LIB_FILES := @@ -33,22 +33,13 @@ index 802211c..006d887 100644 -endif -endif - --ifeq (@ac_pjmedia_resample@,libresample) --APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX) --ifeq ($(PJ_SHARED_LIBRARIES),) --ifeq (@ac_resample_dll@,1) --export PJ_RESAMPLE_DLL := 1 --APP_THIRD_PARTY_LIBS += -lresample --APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX) --else --APP_THIRD_PARTY_LIBS += -lresample-$(TARGET_NAME) --endif --else --APP_THIRD_PARTY_LIBS += -lresample --APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX) --endif --endif -- + ifeq (@ac_pjmedia_resample@,libresample) + APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX) + ifeq ($(PJ_SHARED_LIBRARIES),) +@@ -57,85 +43,6 @@ APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFI + endif + endif + -ifneq (@ac_no_gsm_codec@,1) -ifeq (@ac_external_gsm@,1) -# External GSM library @@ -131,7 +122,7 @@ index 802211c..006d887 100644 # Additional flags @ac_build_mak_vars@ -@@ -149,7 +41,7 @@ SDL_CFLAGS = @ac_sdl_cflags@ +@@ -149,7 +56,7 @@ SDL_CFLAGS = @ac_sdl_cflags@ SDL_LDFLAGS = @ac_sdl_ldflags@ # FFMPEG flags @@ -140,7 +131,7 @@ index 802211c..006d887 100644 FFMPEG_LDFLAGS = @ac_ffmpeg_ldflags@ # Video4Linux2 -@@ -157,7 +49,7 @@ V4L2_CFLAGS = @ac_v4l2_cflags@ +@@ -157,7 +64,7 @@ V4L2_CFLAGS = @ac_v4l2_cflags@ V4L2_LDFLAGS = @ac_v4l2_ldflags@ # OPENH264 flags From 69fed26deb176d61bb6d37e7138b360ddf259f8f Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 1 Nov 2016 11:00:21 +0200 Subject: [PATCH 0840/1578] define PATH_MAX for HURD PATH_MAX is not guaranteed to be defined. In parctice, all but the HURD define it to a constant. It is indeed not safe to assume there won't be longer paths and Asterisk generally does err safely on such cases. So even for HURD we'll just pretend PATH_MAX is 4096. ASTERISK-25070 #close Change-Id: I53d10ba18c34c132bcb640a5fd8e0da1d9b22db3 --- include/asterisk.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/asterisk.h b/include/asterisk.h index 25737805bca..862fa1fe5f5 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -36,6 +36,15 @@ #define AST_FILE_MODE 0666 #endif +/* Make sure PATH_MAX is defined on platforms (HURD) that don't define it. + * Also be sure to handle the case of a path larger than PATH_MAX + * (err safely) in the code. + */ +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + + #define DEFAULT_LANGUAGE "en" #define DEFAULT_SAMPLE_RATE 8000 From ed08811e64722b266f6c09ad131e316928db9f3c Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 1 Nov 2016 11:18:49 +0200 Subject: [PATCH 0841/1578] netsock.c: fix includes for HURD ASTERISK-25070 Change-Id: I43bf94d2d36d3d8a8d0df40cd6c027d65a462814 --- main/netsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/netsock.c b/main/netsock.c index b7a7566a76f..91f7e73141e 100644 --- a/main/netsock.c +++ b/main/netsock.c @@ -31,7 +31,7 @@ #include "asterisk.h" -#ifndef __linux__ +#if !defined (__linux__) && !defined (__GNU__) #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__) || defined(__GLIBC__) #include #endif From 2526dff94d7d59852fe405615aef54d38dc32a80 Mon Sep 17 00:00:00 2001 From: Grachev Sergey Date: Tue, 1 Nov 2016 16:32:35 +0300 Subject: [PATCH 0842/1578] chan_sip: Incorrect display option Outbound reg. retry 403 If in sip.conf (general section) set option register_retry_403=no, the command "sip show settings" return value: Outbound reg. retry 403:0 If in sip.conf (general section) set option register_retry_403=yes, the command "sip show settings" return value: Outbound reg. retry 403:-1 * In static char "sip show settings" for "Outbound.reg. retry 403" option use AST_CLI_YESNO ASTERISK-26476 #close Change-Id: I3c14272f05f1067bd2aeaa8b3ef9cf8fcb12dcf9 --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index e3a638a9f66..225931850e4 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -21652,7 +21652,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, " Sub. max duration: %d secs\n", max_subexpiry); ast_cli(a->fd, " Outbound reg. timeout: %d secs\n", global_reg_timeout); ast_cli(a->fd, " Outbound reg. attempts: %d\n", global_regattempts_max); - ast_cli(a->fd, " Outbound reg. retry 403:%d\n", global_reg_retry_403); + ast_cli(a->fd, " Outbound reg. retry 403:%s\n", AST_CLI_YESNO(global_reg_retry_403)); ast_cli(a->fd, " Notify ringing state: %s%s\n", AST_CLI_YESNO(sip_cfg.notifyringing), sip_cfg.notifyringing == NOTIFYRINGING_NOTINUSE ? " (when not in use)" : ""); if (sip_cfg.notifyringing) { ast_cli(a->fd, " Include CID: %s%s\n", From c30d677333028f9768a3913bb73f49936805adc9 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 20 Oct 2016 07:27:21 -0500 Subject: [PATCH 0843/1578] res/stasis: Add CLI commands for displaying/debugging ARI apps This patch adds three new CLI commands: - ari show apps: list the registered ARI applications - ari show app: show detailed information about an ARI application - ari set debug: dump events being sent to an ARI application Note that while these CLI commands live in the res_stasis module, we use the 'ari' family for these commands. This was done as most users of Asterisk aren't aware of the semantic differences between ARI and res_stasis, and some 'ari' CLI commands already exist. ASTERISK-26488 #close Change-Id: I51ad6ff0cabee0d69db06858c13f18b1c513c9f5 --- CHANGES | 12 ++ include/asterisk/stasis_app.h | 10 ++ res/ari/ari_websockets.c | 2 + res/res_stasis.c | 13 +++ res/stasis/app.c | 91 +++++++++++++++ res/stasis/app.h | 26 +++++ res/stasis/cli.c | 214 ++++++++++++++++++++++++++++++++++ res/stasis/cli.h | 43 +++++++ 8 files changed, 411 insertions(+) create mode 100644 res/stasis/cli.c create mode 100644 res/stasis/cli.h diff --git a/CHANGES b/CHANGES index d64f2d5ab74..f4c5148a74e 100644 --- a/CHANGES +++ b/CHANGES @@ -69,6 +69,18 @@ chan_pjsip to asymmetric using the "asymmetric_rtp_codec" endpoint option. If this option is set then the sending and received codec are allowed to differ. +CLI Commands +------------------ + * Three new CLI commands have been added for ARI: + - ari show apps: + Displays a listing of all registered ARI applications. + - ari show app : + Display detailed information about a registered ARI application. + - ari set debug : + Enable/disable debugging of an ARI application. When debugged, verbose + information will be sent to the Asterisk CLI. + + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- ------------------------------------------------------------------------------ diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index 3497bf437af..137cbb945c9 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -76,6 +76,16 @@ typedef void (*stasis_app_cb)(void *data, const char *app_name, */ struct ao2_container *stasis_app_get_all(void); +/*! + * \brief Retrieve a handle to a Stasis application by its name + * + * \param name The name of the registered Stasis application + * + * \return \c stasis_app on success. + * \return \c NULL on error. + */ +struct stasis_app *stasis_app_get_by_name(const char *name); + /*! * \brief Register a new Stasis application. * diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c index 6fe40c6b740..f1e63d39866 100644 --- a/res/ari/ari_websockets.c +++ b/res/ari/ari_websockets.c @@ -172,7 +172,9 @@ int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session, return -1; } +#ifdef AST_DEVMODE ast_debug(3, "Examining ARI event (length %u): \n%s\n", (unsigned int) strlen(str), str); +#endif if (ast_websocket_write_string(session->ws_session, str)) { ast_log(LOG_NOTICE, "Problem occurred during websocket write, websocket closed\n"); return -1; diff --git a/res/res_stasis.c b/res/res_stasis.c index 8e596d557a1..f3d940e2db2 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -65,6 +65,7 @@ #include "stasis/app.h" #include "stasis/control.h" #include "stasis/messaging.h" +#include "stasis/cli.h" #include "stasis/stasis_bridge.h" #include "asterisk/core_unreal.h" #include "asterisk/musiconhold.h" @@ -1487,6 +1488,11 @@ static struct stasis_app *find_app_by_name(const char *app_name) return res; } +struct stasis_app *stasis_app_get_by_name(const char *name) +{ + return find_app_by_name(name); +} + static int append_name(void *obj, void *arg, int flags) { struct stasis_app *app = obj; @@ -1959,6 +1965,8 @@ static int unload_module(void) { stasis_app_unregister_event_sources(); + cli_cleanup(); + messaging_cleanup(); cleanup(); @@ -2118,6 +2126,11 @@ static int load_module(void) return AST_MODULE_LOAD_FAILURE; } + if (cli_init()) { + unload_module(); + return AST_MODULE_LOAD_FAILURE; + } + bridge_stasis_init(); stasis_app_register_event_sources(); diff --git a/res/stasis/app.c b/res/stasis/app.c index 3301d926c9e..ac316fac07a 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -30,6 +30,7 @@ #include "messaging.h" #include "asterisk/callerid.h" +#include "asterisk/cli.h" #include "asterisk/stasis_app.h" #include "asterisk/stasis_bridges.h" #include "asterisk/stasis_channels.h" @@ -59,6 +60,8 @@ struct stasis_app { void *data; /*! Subscription model for the application */ enum stasis_app_subscription_model subscription_model; + /*! Whether or not someone wants to see debug messages about this app */ + int debug; /*! Name of the Stasis application */ char name[]; }; @@ -830,6 +833,18 @@ static void bridge_default_handler(void *data, struct stasis_subscription *sub, } } +void app_set_debug(struct stasis_app *app, int debug) +{ + if (!app) { + return; + } + + { + SCOPED_AO2LOCK(lock, app); + app->debug = debug; + } +} + struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data, enum stasis_app_subscription_model subscription_model) { RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup); @@ -927,6 +942,7 @@ struct stasis_topic *ast_app_get_topic(struct stasis_app *app) void app_send(struct stasis_app *app, struct ast_json *message) { stasis_app_cb handler; + int debug; char eid[20]; RAII_VAR(void *, data, NULL, ao2_cleanup); @@ -939,6 +955,7 @@ void app_send(struct stasis_app *app, struct ast_json *message) /* Copy off mutable state with lock held */ { SCOPED_AO2LOCK(lock, app); + debug = app->debug; handler = app->handler; if (app->data) { ao2_ref(app->data, +1); @@ -947,6 +964,13 @@ void app_send(struct stasis_app *app, struct ast_json *message) /* Name is immutable; no need to copy */ } + if (debug) { + char *dump = ast_json_dump_string_format(message, AST_JSON_PRETTY); + ast_verb(0, "Dispatching message to Stasis app '%s':\n%s\n", + app->name, dump); + ast_json_free(dump); + } + if (!handler) { ast_verb(3, "Inactive Stasis app '%s' missed message\n", app->name); @@ -1024,6 +1048,73 @@ const char *app_name(const struct stasis_app *app) return app->name; } +static int forwards_filter_by_type(void *obj, void *arg, int flags) +{ + struct app_forwards *forward = obj; + enum forward_type *forward_type = arg; + + if (forward->forward_type == *forward_type) { + return CMP_MATCH; + } + + return 0; +} + +void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a) +{ + struct ao2_iterator *channels; + struct ao2_iterator *endpoints; + struct ao2_iterator *bridges; + struct app_forwards *forward; + enum forward_type forward_type; + + ast_cli(a->fd, "Name: %s\n" + " Debug: %s\n" + " Subscription Model: %s\n", + app->name, + app->debug ? "Yes" : "No", + app->subscription_model == STASIS_APP_SUBSCRIBE_ALL ? + "Global Resource Subscription" : + "Application/Explicit Resource Subscription"); + ast_cli(a->fd, " Subscriptions: %d\n", ao2_container_count(app->forwards)); + + ast_cli(a->fd, " Channels:\n"); + forward_type = FORWARD_CHANNEL; + channels = ao2_callback(app->forwards, OBJ_MULTIPLE, + forwards_filter_by_type, &forward_type); + if (channels) { + while ((forward = ao2_iterator_next(channels))) { + ast_cli(a->fd, " %s (%d)\n", forward->id, forward->interested); + ao2_ref(forward, -1); + } + ao2_iterator_destroy(channels); + } + + ast_cli(a->fd, " Bridges:\n"); + forward_type = FORWARD_BRIDGE; + bridges = ao2_callback(app->forwards, OBJ_MULTIPLE, + forwards_filter_by_type, &forward_type); + if (bridges) { + while ((forward = ao2_iterator_next(bridges))) { + ast_cli(a->fd, " %s (%d)\n", forward->id, forward->interested); + ao2_ref(forward, -1); + } + ao2_iterator_destroy(bridges); + } + + ast_cli(a->fd, " Endpoints:\n"); + forward_type = FORWARD_ENDPOINT; + endpoints = ao2_callback(app->forwards, OBJ_MULTIPLE, + forwards_filter_by_type, &forward_type); + if (endpoints) { + while ((forward = ao2_iterator_next(endpoints))) { + ast_cli(a->fd, " %s (%d)\n", forward->id, forward->interested); + ao2_ref(forward, -1); + } + ao2_iterator_destroy(endpoints); + } +} + struct ast_json *app_to_json(const struct stasis_app *app) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); diff --git a/res/stasis/app.h b/res/stasis/app.h index 2c8db1ccd3b..6ed6a295b87 100644 --- a/res/stasis/app.h +++ b/res/stasis/app.h @@ -127,8 +127,26 @@ void app_send(struct stasis_app *app, struct ast_json *message); struct app_forwards; +/*! + * \brief Create a JSON representation of a \c stasis_app + * + * \param app The application + * + * \return \c JSON blob on success + * \return \c NULL on error + */ struct ast_json *app_to_json(const struct stasis_app *app); +struct ast_cli_args; + +/*! + * \brief Dump properties of a \c stasis_app to the CLI + * + * \param app The application + * \param a The CLI arguments + */ +void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a); + /*! * \brief Subscribes an application to a channel. * @@ -282,4 +300,12 @@ char *app_get_replace_channel_app(struct ast_channel *chan); */ int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan); +/*! + * \brief Enable/disable debugging on an application + * + * \param app The app to debug + * \param debug If non-zero, enable debugging. If zero, disable. + */ +void app_set_debug(struct stasis_app *app, int debug); + #endif /* _ASTERISK_RES_STASIS_APP_H */ diff --git a/res/stasis/cli.c b/res/stasis/cli.c new file mode 100644 index 00000000000..e6065b0acc2 --- /dev/null +++ b/res/stasis/cli.c @@ -0,0 +1,214 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Matt Jordan + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Stasis CLI commands. + * + * \author Matt Jordan + */ + +#include "asterisk.h" + +#include "asterisk/cli.h" +#include "asterisk/astobj2.h" + +#include "cli.h" +#include "app.h" + + +static char *ari_show_apps(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ao2_container *apps; + struct ao2_iterator it_apps; + char *app; + + switch (cmd) { + case CLI_INIT: + e->command = "ari show apps"; + e->usage = + "Usage: ari show apps\n" + " Lists all registered applications.\n" + ; + return NULL; + case CLI_GENERATE: + return NULL; + default: + break; + } + + if (a->argc != 3) { + return CLI_SHOWUSAGE; + } + + apps = stasis_app_get_all(); + if (!apps) { + ast_cli(a->fd, "Unable to retrieve registered applications!\n"); + return CLI_FAILURE; + } + + ast_cli(a->fd, "Application Name \n"); + ast_cli(a->fd, "=========================\n"); + it_apps = ao2_iterator_init(apps, 0); + while ((app = ao2_iterator_next(&it_apps))) { + ast_cli(a->fd, "%-25.25s\n", app); + ao2_ref(app, -1); + } + + ao2_iterator_destroy(&it_apps); + ao2_ref(apps, -1); + + return CLI_SUCCESS; +} + +struct app_complete { + /*! Nth app to search for */ + int state; + /*! Which app currently on */ + int which; +}; + +static int complete_ari_app_search(void *obj, void *arg, void *data, int flags) +{ + struct app_complete *search = data; + + if (++search->which > search->state) { + return CMP_MATCH; + } + return 0; +} + +static char *complete_ari_app(struct ast_cli_args *a) +{ + RAII_VAR(struct ao2_container *, apps, stasis_app_get_all(), ao2_cleanup); + RAII_VAR(char *, app, NULL, ao2_cleanup); + + struct app_complete search = { + .state = a->n, + }; + + if (!apps) { + ast_cli(a->fd, "Error getting ARI applications\n"); + return CLI_FAILURE; + } + + app = ao2_callback_data(apps, + ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY, + complete_ari_app_search, (char*)a->word, &search); + + return app ? ast_strdup(app) : NULL; +} + +static char *complete_ari_show_app(struct ast_cli_args *a) +{ + if (a->pos == 3) { + return complete_ari_app(a); + } + + return NULL; +} + +static char *ari_show_app(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + void *app; + + switch (cmd) { + case CLI_INIT: + e->command = "ari show app"; + e->usage = + "Usage: ari show app \n" + " Provide detailed information about a registered application.\n" + ; + return NULL; + case CLI_GENERATE: + return complete_ari_show_app(a); + default: + break; + } + + if (a->argc != 4) { + return CLI_SHOWUSAGE; + } + + app = stasis_app_get_by_name(a->argv[3]); + if (!app) { + return CLI_FAILURE; + } + + app_to_cli(app, a); + + ao2_ref(app, -1); + + return CLI_SUCCESS; +} + +static char *ari_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + void *app; + int debug; + + switch (cmd) { + case CLI_INIT: + e->command = "ari set debug"; + e->usage = + "Usage: ari set debug \n" + " Enable or disable debugging on a specific application.\n" + ; + return NULL; + case CLI_GENERATE: + return complete_ari_show_app(a); + default: + break; + } + + if (a->argc != 5) { + return CLI_SHOWUSAGE; + } + + app = stasis_app_get_by_name(a->argv[3]); + if (!app) { + return CLI_FAILURE; + } + + debug = !strcmp(a->argv[4], "on"); + app_set_debug(app, debug); + ast_cli(a->fd, "Debugging on '%s' %s\n", + app_name(app), + debug ? "enabled" : "disabled"); + + ao2_ref(app, -1); + + return CLI_SUCCESS; +} + +static struct ast_cli_entry cli_ari[] = { + AST_CLI_DEFINE(ari_show_apps, "List registered ARI applications"), + AST_CLI_DEFINE(ari_show_app, "Display details of a registered ARI application"), + AST_CLI_DEFINE(ari_set_debug, "Enable/disable debugging of an ARI application"), +}; + + +int cli_init(void) +{ + return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari)); +} + +void cli_cleanup(void) +{ + ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari)); +} diff --git a/res/stasis/cli.h b/res/stasis/cli.h new file mode 100644 index 00000000000..49235c7b309 --- /dev/null +++ b/res/stasis/cli.h @@ -0,0 +1,43 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Matt Jordan + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _ASTERISK_RES_STASIS_CLI_H +#define _ASTERISK_RES_STASIS_CLI_H + +/*! \file + * + * \brief Internal API for Stasis application CLI commands + * + * \author Matt Jordan + * \since 13.13.0 + */ + +/*! + * \brief Initialize the CLI commands + * + * \retval 0 on success + * \retval non-zero on error + */ +int cli_init(void); + +/*! + * \brief Cleanup the CLI commands + */ +void cli_cleanup(void); + +#endif /* _ASTERISK_RES_STASIS_CLI_H */ From 8060cd1ec1804fa45fac37b09a59a4cef632c0be Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 31 Oct 2016 17:35:47 -0500 Subject: [PATCH 0844/1578] codecs.conf.sample: Add sample and option descriptions for codec_opus codecs.conf.sample was missing codec opus's configuration options, descriptions, and examples. This patch adds the configuration options and examples to codecs.conf.sample that can be used with codec_opus. ASTERISK-26538 #close Change-Id: I1d89bb5e01d3e3b5bd78951b8dd0ff077a83dc8b --- configs/samples/codecs.conf.sample | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/configs/samples/codecs.conf.sample b/configs/samples/codecs.conf.sample index 9b573857730..63d0352a860 100644 --- a/configs/samples/codecs.conf.sample +++ b/configs/samples/codecs.conf.sample @@ -151,3 +151,57 @@ packetloss_percentage=10; ;[celt32] ;type=celt ;samprate=32000 + +;============================ OPUS Section Options ============================ +; +;[opus] +;type= ; Must be of type "opus" (default: "") +;packet_loss= ; Encoder's packet loss percentage. Can be any number between 0 + ; and 100, inclusive. A higher value results in more loss + ; resistance. (default: 0) +;complexity= ; Encoder's computational complexity. Can be any number between 0 + ; and 10, inclusive. Note, 10 equals the highest complexity. + ; (default: 10) +;max_bandwitdth= ; Encoder's maximum bandwidth allowed. Sets an upper bandwidth + ; bound on the encoder. Can be any of the following: narrow, + ; medium, wide, super_wide, full. (default: full) +;signal= ; Encoder's signal type. Aids in mode selection on the encoder: Can + ; be any of the following: auto, voice, music. (default: auto) +;application= ; Encoder's application type. Can be any of the following: voip, + ; audio, low_delay. (default: voip) +;max_playback_rate= ; Override the maximum playback rate in the offer's SDP. + ; Any value between 8000 and 48000 (inclusive) is valid, + ; however typically it should match one of the usual opus + ; bandwidths. A value of "sdp" is also allowed. When set + ; to "sdp" then the value from the offer's SDP is used. + ; (default: "sdp") +;bitrate= ; Override the maximum average bitrate in the offer's SDP. Any value + ; between 500 and 512000 is valid. The following values are also + ; allowed: auto, max, sdp. When set to "sdp" then the value from + ; the offer's sdp is used. (default: "sdp") +;cbr= ; Override the constant bit rate parameter in the offer's SDP. A value of + ; 0/false/no represents a variable bit rate whereas 1/true/yes represents + ; a constant bit rate. A value of "sdp" is also allowed. When set to "sdp" + ; then the value from the offer's sdp is used. (default: "sdp") +;fec= ; Override the use inband fec parameter in the offer's SDP. A value of + ; 0/false/no represents disabled whereas 1/true/yes represents enabled. + ; A value of "sdp" is also allowed. When set to "sdp" then the value from + ; the offer's sdp is used. (default: "sdp") +;dtx= ; Override the use dtx parameter in the offer's SDP. A value of 0/false/no + ; represents disabled whereas 1/true/yes represents enabled. A value of + ; "sdp" is also allowed. When set to "sdp" then the value from the offer's + ; sdp is used. (default: "sdp") + +;=============================== OPUS Examples ================================ +; +;[opus] +;type=opus +;max_playback_rate=8000 ; Limit the maximum playback rate on the encoder +;fec=no ; Force no inband fec on the encoder (i.e don't use what's on the SDP) + +;[myopus] +;type=opus +;max_bandwidth=wide ; Maximum encoded bandwidth set to wide band (0-8000 Hz +; ; audio bandwidth at 16Khz sample rate) +;cbr=yes ; Force a constant bit rate (i.e don't use what's on the SDP) + From 6233e146c6ecb6abd7405d0a639cdf7276b70819 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 1 Nov 2016 11:56:24 +0000 Subject: [PATCH 0845/1578] res_pjsip_sdp_rtp: Limit number of formats to defined maximum. The res_pjsip_sdp_rtp module did not restrict the number of formats added to a media stream in the SDP to the defined limit. If allow=all was used with additional loaded codecs this could result in the next media stream being overwritten some. This change restricts the module to limit it to the defined maximum and also increases the maximum in our bundled pjproject. ASTERISK-26541 #close Change-Id: I0dc5f59d3891246cafa2f3df5ec406f088559ee8 --- res/res_pjsip_sdp_rtp.c | 10 +++++++++- third-party/pjproject/patches/config_site.h | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 037b8e45fc4..3df9df030a2 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1183,10 +1183,14 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as max_packet_size = ast_format_get_maximum_ms(format); } ao2_ref(format, -1); + + if (media->desc.fmt_count == PJMEDIA_MAX_SDP_FMT) { + break; + } } /* Add non-codec formats */ - if (media_type != AST_MEDIA_TYPE_VIDEO) { + if (media_type != AST_MEDIA_TYPE_VIDEO && media->desc.fmt_count < PJMEDIA_MAX_SDP_FMT) { for (index = 1LL; index <= AST_RTP_MAX; index <<= 1) { if (!(noncodec & index)) { continue; @@ -1208,6 +1212,10 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp)); media->attr[media->attr_count++] = attr; } + + if (media->desc.fmt_count == PJMEDIA_MAX_SDP_FMT) { + break; + } } } diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 0694f120e87..564959d84c4 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -57,3 +57,9 @@ /* Defaults too low for WebRTC */ #define PJ_ICE_MAX_CAND 32 #define PJ_ICE_MAX_CHECKS (PJ_ICE_MAX_CAND * 2) + +/* Increase limits to allow more formats */ +#define PJMEDIA_MAX_SDP_FMT 64 +#define PJMEDIA_MAX_SDP_BANDW 4 +#define PJMEDIA_MAX_SDP_ATTR (PJMEDIA_MAX_SDP_FMT*2 + 4) +#define PJMEDIA_MAX_SDP_MEDIA 16 From f29b8d62bb39767ecef2859c79cea3f6c0d1c3c2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 1 Nov 2016 13:13:13 -0500 Subject: [PATCH 0846/1578] bundled pjproject: Fix DNS write to freed memory. PJPROJECT 2.5.5 introduced a race condition with the -r5349 IPv6 DNS patch. The patch below fixes a write to freed memory under cartain DNS lookup conditions. 0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch ASTERISK-26516 Reported by: Richard Mudgett Change-Id: Ifdfae9ecf1e41b53080f33aab44ce1a220f349c5 --- ...ckport-Fix-DNS-write-on-freed-memory.patch | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch diff --git a/third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch b/third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch new file mode 100644 index 00000000000..f70dd45e7a6 --- /dev/null +++ b/third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch @@ -0,0 +1,33 @@ +From 732a997010d60fe93a7453e809672386749b0afc Mon Sep 17 00:00:00 2001 +From: Richard Mudgett +Date: Tue, 1 Nov 2016 12:55:31 -0500 +Subject: [PATCH] r5477 svn backport Fix DNS write on freed memory. + +Re #1974: Fix DNS write on freed memory. +Thanks to Richard Mudgett for the patch. +--- + pjlib-util/src/pjlib-util/resolver.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c +index 52b7655..365772e 100644 +--- a/pjlib-util/src/pjlib-util/resolver.c ++++ b/pjlib-util/src/pjlib-util/resolver.c +@@ -908,7 +908,13 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, + /* Must return PJ_SUCCESS */ + status = PJ_SUCCESS; + +- goto on_return; ++ /* ++ * We cannot write to *p_query after calling cb because what ++ * p_query points to may have been freed by cb. ++ * Refer to ticket #1974. ++ */ ++ pj_mutex_unlock(resolver->mutex); ++ return status; + } + + /* At this point, we have a cached entry, but this entry has expired. +-- +1.7.9.5 + From 6a99f007d6f13aac8032e985865cdb106c47de60 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Wed, 2 Nov 2016 12:05:18 +0200 Subject: [PATCH 0847/1578] autoconf: more variants for OSARCH linux-gnu There are quite a few odd GNU/Linux platforms. Just call all of them linux-gnu. Specifically this fixes building the Debian platforms mips64el and x32. And maybe also others. ASTERISK-26546 #close Change-Id: I06ec4bd7f0ee1c84b6b24d81538223b07c4174b1 --- configure | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index af102b4abc1..8ea92cee0e8 100755 --- a/configure +++ b/configure @@ -4927,7 +4927,7 @@ case "${host_os}" in OSARCH=cygwin PBX_WINARCH=1 ;; - linux-gnueabi* | linux-gnuspe) + linux-gnu*) OSARCH=linux-gnu ;; linux-musl*) diff --git a/configure.ac b/configure.ac index 0f2148b06a8..faca5df29fa 100644 --- a/configure.ac +++ b/configure.ac @@ -178,7 +178,7 @@ case "${host_os}" in OSARCH=cygwin PBX_WINARCH=1 ;; - linux-gnueabi* | linux-gnuspe) + linux-gnu*) OSARCH=linux-gnu ;; linux-musl*) From 9ac53877f688c06acaa7c377f15da8770e4ee88b Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 13 Sep 2016 11:08:34 +0200 Subject: [PATCH 0848/1578] rtp_engine: Allow more than 32 dynamic payload types. Since adding all remaining rates of Signed Linear (ASTERISK-24274), SILK (Gerrit 3136) and Codec 2 (ASTERISK-26217), no RTP Payload Type is left in the dynamic range (96-127). RFC 3551 section 3 allows to reassign other ranges. Consequently, when the dynamic range is exhausted, this change utilizes payload types in the range between 35 and 63 giving room for another 29 payload types. ASTERISK-26311 #close Change-Id: I7bc96ab764bc30098a178b841cbf7146f9d64964 --- CHANGES | 9 +++ configs/samples/asterisk.conf.sample | 8 +++ include/asterisk/options.h | 2 + include/asterisk/rtp_engine.h | 3 + main/asterisk.c | 21 +++++++ main/rtp_engine.c | 87 +++++++++++++++++++++++----- 6 files changed, 114 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index f4c5148a74e..2131fee3ca8 100644 --- a/CHANGES +++ b/CHANGES @@ -49,6 +49,15 @@ cel_radius * To fix a memory leak the syslog channel is now empty if it has not been set and used by a syslog channel in the logger. +RTP +------------------ + * New setting "rtp_pt_dynamic = 35" in asterisk.conf: + Normally the Dynamic RTP Payload Type numbers are 96-127, which allow just 32 + formats. To avoid the message "No Dynamic RTP mapping available", the range + was changed to 35-63,96-127. This is allowed by RFC 3551 section 3. However, + when you use more than 32 formats and calls are not accepted by a remote + implementation, please report this and go back to rtp_pt_dynamic = 96. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ---------- ------------------------------------------------------------------------------ diff --git a/configs/samples/asterisk.conf.sample b/configs/samples/asterisk.conf.sample index 6d6d2f0bb13..e13a944b06a 100644 --- a/configs/samples/asterisk.conf.sample +++ b/configs/samples/asterisk.conf.sample @@ -97,6 +97,14 @@ documentation_language = en_US ; Set the language you want documentation ; This is currently is used by DUNDi and ; Exchanging Device and Mailbox State ; using protocols: XMPP, Corosync and PJSIP. +;rtp_pt_dynamic = 35 ; Normally the Dynamic RTP Payload Type numbers + ; are 96-127, which allow just 32 formats. The + ; starting point 35 enables the range 35-63 and + ; allows 29 additional formats. When you use + ; more than 32 formats in the dynamic range and + ; calls are not accepted by a remote + ; implementation, please report this and go + ; back to value 96. ; Changing the following lines may compromise your security. ;[files] diff --git a/include/asterisk/options.h b/include/asterisk/options.h index e2709f9188f..345bacf6c58 100644 --- a/include/asterisk/options.h +++ b/include/asterisk/options.h @@ -155,6 +155,8 @@ extern int dahdi_chan_name_len; extern int ast_language_is_prefix; +extern unsigned int ast_option_rtpptdynamic; + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index a40472e9d5e..017bb7b7acd 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -84,6 +84,9 @@ extern "C" { /*! First dynamic RTP payload type */ #define AST_RTP_PT_FIRST_DYNAMIC 96 +/*! Last reassignable RTP payload type */ +#define AST_RTP_PT_LAST_REASSIGN 63 + /*! Maximum number of generations */ #define AST_RED_MAX_GENERATION 5 diff --git a/main/asterisk.c b/main/asterisk.c index 56fc107dba0..be6c7cc3242 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -248,6 +248,7 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/format_cache.h" #include "asterisk/media_cache.h" #include "asterisk/astdb.h" +#include "asterisk/options.h" #include "../defaults.h" @@ -336,6 +337,7 @@ unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */ #if defined(HAVE_SYSINFO) long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */ #endif +unsigned int ast_option_rtpptdynamic; /*! @} */ @@ -599,6 +601,19 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled"); ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration); + if (ast_option_rtpptdynamic == AST_RTP_PT_LAST_REASSIGN) { + ast_cli(a->fd, " RTP dynamic payload types: %u,%u-%u\n", + ast_option_rtpptdynamic, + AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT - 1); + } else if (ast_option_rtpptdynamic < AST_RTP_PT_LAST_REASSIGN) { + ast_cli(a->fd, " RTP dynamic payload types: %u-%u,%u-%u\n", + ast_option_rtpptdynamic, AST_RTP_PT_LAST_REASSIGN, + AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT - 1); + } else { + ast_cli(a->fd, " RTP dynamic payload types: %u-%u\n", + AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT - 1); + } + ast_cli(a->fd, "\n* Subsystems\n"); ast_cli(a->fd, " -------------\n"); ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled"); @@ -3464,6 +3479,7 @@ static void ast_readconfig(void) /* Set default value */ option_dtmfminduration = AST_MIN_DTMF_DURATION; + ast_option_rtpptdynamic = 35; /* init with buildtime config */ ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir)); @@ -3619,6 +3635,11 @@ static void ast_readconfig(void) if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) { option_dtmfminduration = AST_MIN_DTMF_DURATION; } + /* http://www.iana.org/assignments/rtp-parameters + * RTP dynamic payload types start at 96 normally; extend down to 0 */ + } else if (!strcasecmp(v->name, "rtp_pt_dynamic")) { + ast_parse_arg(v->value, PARSE_UINT32|PARSE_IN_RANGE, + &ast_option_rtpptdynamic, 0, AST_RTP_PT_FIRST_DYNAMIC); } else if (!strcasecmp(v->name, "maxcalls")) { if ((sscanf(v->value, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) { ast_option_maxcalls = 0; diff --git a/main/rtp_engine.c b/main/rtp_engine.c index c9d228c5677..4fc1414f008 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -143,23 +143,36 @@ #include "asterisk.h" -#include - -#include "asterisk/channel.h" -#include "asterisk/frame.h" -#include "asterisk/module.h" -#include "asterisk/rtp_engine.h" +#include /* for sqrt, MAX */ +#include /* for sched_yield */ +#include /* for timeval */ +#include /* for time_t */ + +#include "asterisk/_private.h" /* for ast_rtp_engine_init prototype */ +#include "asterisk/astobj2.h" /* for ao2_cleanup, ao2_ref, etc */ +#include "asterisk/channel.h" /* for ast_channel_name, etc */ +#include "asterisk/codec.h" /* for ast_codec_media_type2str, etc */ +#include "asterisk/format.h" /* for ast_format_cmp, etc */ +#include "asterisk/format_cache.h" /* for ast_format_adpcm, etc */ +#include "asterisk/format_cap.h" /* for ast_format_cap_alloc, etc */ +#include "asterisk/json.h" /* for ast_json_ref, etc */ +#include "asterisk/linkedlists.h" /* for ast_rtp_engine::, etc */ +#include "asterisk/lock.h" /* for ast_rwlock_unlock, etc */ +#include "asterisk/logger.h" /* for ast_log, ast_debug, etc */ #include "asterisk/manager.h" -#include "asterisk/options.h" -#include "asterisk/astobj2.h" -#include "asterisk/pbx.h" -#include "asterisk/translate.h" -#include "asterisk/netsock2.h" -#include "asterisk/_private.h" -#include "asterisk/framehook.h" -#include "asterisk/stasis.h" -#include "asterisk/json.h" -#include "asterisk/stasis_channels.h" +#include "asterisk/module.h" /* for ast_module_unref, etc */ +#include "asterisk/netsock2.h" /* for ast_sockaddr_copy, etc */ +#include "asterisk/options.h" /* for ast_option_rtpptdynamic */ +#include "asterisk/pbx.h" /* for pbx_builtin_setvar_helper */ +#include "asterisk/res_srtp.h" /* for ast_srtp_res */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_codecs, etc */ +#include "asterisk/stasis.h" /* for stasis_message_data, etc */ +#include "asterisk/stasis_channels.h" /* for ast_channel_stage_snapshot, etc */ +#include "asterisk/strings.h" /* for ast_str_append, etc */ +#include "asterisk/time.h" /* for ast_tvdiff_ms, ast_tvnow */ +#include "asterisk/translate.h" /* for ast_translate_available_formats */ +#include "asterisk/utils.h" /* for ast_free, ast_strdup, etc */ +#include "asterisk/vector.h" /* for AST_VECTOR_GET, etc */ struct ast_srtp_res *res_srtp = NULL; struct ast_srtp_policy_res *res_srtp_policy = NULL; @@ -2301,6 +2314,48 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code) } } + /* http://www.iana.org/assignments/rtp-parameters + * RFC 3551, Section 3: "[...] applications which need to define more + * than 32 dynamic payload types MAY bind codes below 96, in which case + * it is RECOMMENDED that unassigned payload type numbers be used + * first". Updated by RFC 5761, Section 4: "[...] values in the range + * 64-95 MUST NOT be used [to avoid conflicts with RTCP]". Summaries: + * https://tools.ietf.org/html/draft-roach-mmusic-unified-plan#section-3.2.1.2 + * https://tools.ietf.org/html/draft-wu-avtcore-dynamic-pt-usage#section-3 + */ + if (map < 0) { + for (x = MAX(ast_option_rtpptdynamic, 35); x <= AST_RTP_PT_LAST_REASSIGN; ++x) { + if (!static_RTP_PT[x]) { + map = x; + break; + } + } + } + /* Yet, reusing mappings below 35 is not supported in Asterisk because + * when Compact Headers are activated, no rtpmap is send for those below + * 35. If you want to use 35 and below + * A) do not use Compact Headers, + * B) remove that code in chan_sip/res_pjsip, or + * C) add a flag that this RTP Payload Type got reassigned dynamically + * and requires a rtpmap even with Compact Headers enabled. + */ + if (map < 0) { + for (x = MAX(ast_option_rtpptdynamic, 20); x < 35; ++x) { + if (!static_RTP_PT[x]) { + map = x; + break; + } + } + } + if (map < 0) { + for (x = MAX(ast_option_rtpptdynamic, 0); x < 20; ++x) { + if (!static_RTP_PT[x]) { + map = x; + break; + } + } + } + if (map < 0) { if (format) { ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n", From 4de5454ef1417691b012d3d83cdd1ca9a6d09401 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 2 Nov 2016 14:15:14 +0000 Subject: [PATCH 0849/1578] app_dial: Fix incorrect device state when channel is picked up. Given the scenario where multiple channels are dialed using Dial() but the caller is picked up using PickupChan() all outgoing channels except the channel specified to PickupChan() would be marked as ringing until the call had been hung up. When using the PickupChan application the channel executing the application is swapped into place of another channel. As part of this process the channel is answered. The Dial application has explicit logic which checks if the channel is answered, cancels all other outgoing channels, and bridges. This logic is different than the normal logic that is executed when an outgoing channel is answered. This different logic failed to publish dial events stating that the other outgoing channels had been canceled. As a result references to the outgoing channels were held onto by the dial masquerade process until the call had been ended and the channels had gone away. This would result in the channels appearing in the "core show channels" list despite not being present anymore and would also result in incorrect device state. This change makes it so that this logic also publishes dial events stating that the other outgoing channels have been canceled. ASTERISK-26549 Change-Id: Iea7168e6e82f7d4609ec0366153804e4f55ea64f --- apps/app_dial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/app_dial.c b/apps/app_dial.c index d871f7f57ae..2f5935d19c3 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1301,6 +1301,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } } peer = c; + publish_dial_end_event(in, out_chans, peer, "CANCEL"); ast_copy_flags64(peerflags, o, OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | From 0904c1f4ccaa5b40933dd52ffcd235a036e2ed1c Mon Sep 17 00:00:00 2001 From: Sebastian Gutierrez Date: Tue, 1 Nov 2016 21:48:50 -0300 Subject: [PATCH 0850/1578] chan_sip: add missing account code Added missing account to AMI event of sip show peers ASTERISK-26176 #close Change-Id: Ieb6c2c80a838a1b59c82103eba4c63ba238dc482 --- channels/chan_sip.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 225931850e4..5e23f6fce6c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -20135,7 +20135,9 @@ static struct sip_peer *_sip_show_peers_one(int fd, struct mansession *s, struct "ACL: %s\r\n" "Status: %s\r\n" "RealtimeDevice: %s\r\n" - "Description: %s\r\n\r\n", + "Description: %s\r\n" + "Accountcode: %s\r\n" + "\r\n", cont->idtext, peer->name, ast_sockaddr_isnull(&peer->addr) ? "-none-" : tmp_host, @@ -20150,7 +20152,8 @@ static struct sip_peer *_sip_show_peers_one(int fd, struct mansession *s, struct ast_acl_list_is_empty(peer->acl) ? "no" : "yes", /* permit/deny/acl */ status, cont->realtimepeers ? (peer->is_realtime ? "yes" : "no") : "no", - peer->description); + peer->description, + peer->accountcode); } ao2_unlock(peer); From 78dc6ceaf63e47aa90127e319f57bfaad87a114c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 3 Nov 2016 10:55:06 -0600 Subject: [PATCH 0851/1578] pjproject_bundled: Fix issue with libasteriskpj needing libresample libresample is only needed by pjproject if we're building pjsua, which we only do if TEST_FRAMEWORK is selected. It's required by pjsua to process audio which is needed by some testsuite tests. Unfortunately, pjproject relies on a newer version of libresample than the version that ships by most distros so we need to compile the version that's bundled with pjproject. Since we only need it for pjsua, we DON'T want it's symbols exposed when we actually build asterisk. There was a problem however... TEST_FRAMEWORK is only known AFTER we've already run ./configure on both asterisk and pjproject but pjproject's ./configure needs to test it to know whether to set up to build libresample or not. The previous way of figuring this out was to always tell ./configure "yes" but not actually build the library. This caused an issue where building libasteriskpj was being told to include libresample but it wasn't actually there. The solution is to still do a default pjproject configure during an asterisk ./configure but if makeopts or menuselect.makeopts changes subsequently, we now reconfigure pjproject, taking into account the current state of TEST_FRAMEWORK. Previously, if makeopts or menuselect.makeopts changed, only a recompile of pjproject was done. Change-Id: I9b5d84c61384a3ae07fe30e85c49698378cc4685 --- third-party/pjproject/Makefile | 14 +++++++------- third-party/pjproject/Makefile.rules | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 209e681cd7c..106938b6cc9 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -103,7 +103,12 @@ source/pjlib/include/pj/%.h: patches/%.h $(ECHO_PREFIX) Applying custom include file $< $(CMD_PREFIX) cp -f $< source/pjlib/include/pj/ -source/build.mak: Makefile.rules source/version.mak source/user.mak $(addprefix source/pjlib/include/pj/,$(notdir $(wildcard patches/*.h))) +.rebuild_needed: $(wildcard ../../makeopts) $(wildcard ../../menuselect.makeopts) + $(ECHO_PREFIX) Rebuilding + $(CMD_PREFIX) $(MAKE) clean $(REALLY_QUIET) + @touch .rebuild_needed + +source/build.mak: Makefile.rules source/version.mak source/user.mak $(addprefix source/pjlib/include/pj/,$(notdir $(wildcard patches/*.h))) .rebuild_needed $(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS) $(CMD_PREFIX) (cd source ; ./aconfigure $(QUIET_CONFIGURE) $(PJPROJECT_CONFIG_OPTS)) @@ -115,12 +120,7 @@ configure: source/build.mak echo_cflags: source/build.mak @echo $(PJ_CFLAGS) -.rebuild_needed: ../../makeopts ../../menuselect.makeopts - $(ECHO_PREFIX) Rebuilding - $(CMD_PREFIX) $(MAKE) clean $(REALLY_QUIET) - @touch .rebuild_needed - -libpj%.a: .rebuild_needed source/build.mak +libpj%.a: source/build.mak $(ECHO_PREFIX) Compiling lib $(@F) $(CMD_PREFIX) $(MAKE) -C $(dir $(shell dirname $@))/build $(@F) $(REALLY_QUIET) -@rm -rf .rebuild_needed diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index 531a259d305..ae4b6a5f9ee 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -28,6 +28,10 @@ PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ --without-external-pa \ --without-external-srtp +ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),) + PJPROJECT_CONFIG_OPTS += --disable-resample --disable-g711-codec +endif + ifeq ($(shell uname -s),Linux) PJPROJECT_CONFIG_OPTS += --enable-epoll endif From 15041942157242bc82bd8950df113b40925c4a7c Mon Sep 17 00:00:00 2001 From: Alexander Anikin Date: Thu, 3 Nov 2016 22:45:37 +0400 Subject: [PATCH 0852/1578] chan_ooh323: Fix infinite loop on read second part of H.225 packet Fix logic on read second part of H.225 packet. There was infinite loop on wrong connections due to read before poll. Change-Id: I42b4bf75c46e4a5c5df5c5ca1f0bd74b8944e7ff --- addons/ooh323c/src/oochannels.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/addons/ooh323c/src/oochannels.c b/addons/ooh323c/src/oochannels.c index 76f8422a5a5..a09470db134 100644 --- a/addons/ooh323c/src/oochannels.c +++ b/addons/ooh323c/src/oochannels.c @@ -1061,11 +1061,6 @@ int ooH2250Receive(OOH323CallData *call) while(total < len) { struct pollfd pfds; - recvLen = ooSocketRecv (call->pH225Channel->sock, message1, len-total); - memcpy(message+total, message1, recvLen); - total = total + recvLen; - - if(total == len) break; /* Complete message is received */ pfds.fd = call->pH225Channel->sock; pfds.events = POLLIN; @@ -1085,8 +1080,9 @@ int ooH2250Receive(OOH323CallData *call) } return OO_FAILED; } - /* If remaining part of the message is not received in 3 seconds - exit */ + + /* exit If remaining part of the message is not received in 3 seconds */ + if(!ooPDRead(&pfds, 1, call->pH225Channel->sock)) { OOTRACEERR3("Error: Incomplete H.2250 message received - clearing " @@ -1099,6 +1095,23 @@ int ooH2250Receive(OOH323CallData *call) } return OO_FAILED; } + + recvLen = ooSocketRecv (call->pH225Channel->sock, message1, len-total); + if (recvLen == 0) { + OOTRACEERR3("Error in read while receiving H.2250 message - " + "clearing call (%s, %s)\n", call->callType, + call->callToken); + ooFreeQ931Message(pctxt, pmsg); + if(call->callState < OO_CALL_CLEAR) + { + call->callEndReason = OO_REASON_TRANSPORTFAILURE; + call->callState = OO_CALL_CLEAR; + } + return OO_FAILED; + } + memcpy(message+total, message1, recvLen); + total = total + recvLen; + } OOTRACEDBGC3("Received Q.931 message: (%s, %s)\n", From bf01ff53f8d93d637981720331405e56f0b3b118 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Fri, 4 Nov 2016 10:57:43 -0500 Subject: [PATCH 0853/1578] Revert "chan_sip: Fix lastrtprx always updated" This reverts commit 93332cb1d0eea18021ea6538237297e627d6e2fc. Unfortunately, the aforementioned commit caused a regression (incoming calls would eventually disconnect). Thus it is being removed. ASTERISK-26523 #close ASTERISK-25270 Change-Id: Ibf5586adc303073a8eac667a4cbfdb6be184a64d --- channels/chan_sip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 5e23f6fce6c..32b2a3611ff 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -8631,9 +8631,7 @@ static struct ast_frame *sip_read(struct ast_channel *ast) sip_pvt_lock(p); fr = sip_rtp_read(ast, p, &faxdetected); - if (fr && fr->frametype != AST_FRAME_NULL) { - p->lastrtprx = time(NULL); - } + p->lastrtprx = time(NULL); /* If we detect a CNG tone and fax detection is enabled then send us off to the fax extension */ if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { From 70d5f90e3df0968a7a091b5f3c8d7654073de9fd Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Fri, 28 Oct 2016 15:11:35 -0500 Subject: [PATCH 0854/1578] stasis_recording/stored: remove calls to deprecated readdir_r function. The readdir_r function has been deprecated and should no longer be used. This patch removes the readdir_r dependency (replaced it with readdir) and also moves the directory search code to a more centralized spot (file.c) Also removed a strict dependency on the dirent structure's d_type field as it is not portable. The code now checks to see if the value is available. If so, it tries to use it, but defaults back to using the stats function if necessary. Lastly, for most implementations of readdir it *should* be thread-safe to make concurrent calls to it as long as different directory streams are specified. glibc falls into this category. However, since it is possible that there exist some implementations that are not safe, locking has been added for those other than glibc. ASTERISK-26412 ASTERISK-26509 #close Change-Id: Id8f54689b1e2873e82a09d0d0d2faf41964e80ba --- include/asterisk/file.h | 28 +++++ main/file.c | 148 +++++++++++++++++++++++ res/stasis_recording/stored.c | 217 +++++++++++----------------------- tests/test_file.c | 181 ++++++++++++++++++++++++++++ 4 files changed, 423 insertions(+), 151 deletions(-) create mode 100644 tests/test_file.c diff --git a/include/asterisk/file.h b/include/asterisk/file.h index c71866ead54..01e5797f561 100644 --- a/include/asterisk/file.h +++ b/include/asterisk/file.h @@ -137,6 +137,34 @@ int ast_filedelete(const char *filename, const char *fmt); */ int ast_filecopy(const char *oldname, const char *newname, const char *fmt); +/*! + * \brief Callback called for each file found when reading directories + * \param dir_name the name of the directory + * \param filename the name of the file + * \param obj user data object + * \return non-zero to stop reading, otherwise zero to continue + */ +typedef int (*ast_file_on_file)(const char *dir_name, const char *filename, void *obj); + +/*! + * \brief Recursively iterate through files and directories up to max_depth + * \param dir_name the name of the directory to search + * \param on_file callback called on each file + * \param obj user data object + * \param max_depth re-curse into sub-directories up to a given maximum (-1 = infinite) + * \return -1 or errno on failure, otherwise 0 + */ +int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth); + +/*! + * \brief Iterate over each file in a given directory + * \param dir_name the name of the directory to search + * \param on_file callback called on each file + * \param obj user data object + * \return -1 or errno on failure, otherwise 0 + */ +#define ast_file_read_dir(dir_name, on_file, obj) ast_file_read_dirs(dir_name, on_file, obj, 1) + /*! * \brief Waits for a stream to stop or digit to be pressed * \param c channel to waitstream on diff --git a/main/file.c b/main/file.c index 639440830cb..37b9e791177 100644 --- a/main/file.c +++ b/main/file.c @@ -1093,6 +1093,154 @@ int ast_filecopy(const char *filename, const char *filename2, const char *fmt) return filehelper(filename, filename2, fmt, ACTION_COPY); } +static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, + void *obj, int max_depth) +{ + DIR *dir; + struct dirent *entry; + size_t size; + int res; + + if (!(dir = opendir(ast_str_buffer(*path)))) { + ast_log(LOG_ERROR, "Error opening directory - %s: %s\n", + ast_str_buffer(*path), strerror(errno)); + return -1; + } + size = ast_str_strlen(*path); + + --max_depth; + + res = 0; + + while ((entry = readdir(dir)) != NULL && !errno) { + int is_file, is_dir, used_stat = 0; + + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { + continue; + } + +/* + * If the dirent structure has a d_type use it to determine if we are dealing with + * a file or directory. Unfortunately if it doesn't have it, or if the type is + * unknown, or a link then we'll need to use the stat function instead. + */ +#ifdef _DIRENT_HAVE_D_TYPE + if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) { + is_file = entry->d_type == DT_REG; + is_dir = entry->d_type == DT_DIR; + ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, NO USE STAT used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); + } else +#endif + { + struct stat statbuf; + + /* + * If using the stat function the file needs to be appended to the + * path so it can be found. However, before appending make sure the + * path contains only the directory for this depth level. + */ + ast_str_truncate(*path, size); + ast_str_append(path, 0, "/%s", entry->d_name); + + if (stat(ast_str_buffer(*path), &statbuf)) { + ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n", + ast_str_buffer(*path), strerror(errno)); + /* + * Output an error, but keep going. It could just be + * a broken link and other files could be fine. + */ + continue; + } + + is_file = S_ISREG(statbuf.st_mode); + is_dir = S_ISDIR(statbuf.st_mode); + used_stat = 1; + ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, WE USED IT YO used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); + } + + if (is_file) { + /* If the handler returns non-zero then stop */ + if ((res = on_file(ast_str_buffer(*path), entry->d_name, obj))) { + break; + } + /* Otherwise move on to next item in directory */ + continue; + } + + if (!is_dir) { + ast_debug(5, "Skipping %s: not a regular file or directory\n", + ast_str_buffer(*path)); + continue; + } + + /* Only re-curse into sub-directories if not at the max depth */ + if (max_depth != 0) { + /* + * If the stat function was used then the sub-directory has + * already been appended, otherwise append it. + */ + ast_log(LOG_VERBOSE, "!###### do dir d_name=%s, path=%s, used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); + if (!used_stat) { + ast_str_truncate(*path, size); + ast_str_append(path, 0, "/%s", entry->d_name); + ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s\n", entry->d_name, ast_str_buffer(*path)); + } + + if ((res = __ast_file_read_dirs(path, on_file, obj, max_depth))) { + break; + } + } + } + + closedir(dir); + + if (!res && errno) { + ast_log(LOG_ERROR, "Error while reading directories - %s: %s\n", + ast_str_buffer(*path), strerror(errno)); + res = -1; + } + + return res; +} + +#if !defined(__GLIBC__) +/*! + * \brief Lock to hold when iterating over directories. + * + * Currently, 'readdir' is not required to be thread-safe. In most modern implementations + * it should be safe to make concurrent calls into 'readdir' that specify different directory + * streams (glibc would be one of these). However, since it is potentially unsafe for some + * implementations we'll use our own locking in order to achieve synchronization for those. + */ +AST_MUTEX_DEFINE_STATIC(read_dirs_lock); +#endif + +int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth) +{ + struct ast_str *path; + int res; + + if (!(path = ast_str_create(256))) { + return -1; + } + + ast_str_set(&path, 0, "%s", dir_name); + errno = 0; + +#if !defined(__GLIBC__) + ast_mutex_lock(&read_dirs_lock); +#endif + + res = __ast_file_read_dirs(&path, on_file, obj, max_depth); + +#if !defined(__GLIBC__) + ast_mutex_unlock(&read_dirs_lock); +#endif + + ast_free(path); + return res; +} + int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang) { struct ast_filestream *fs; diff --git a/res/stasis_recording/stored.c b/res/stasis_recording/stored.c index e25f9a7af59..23d535604b9 100644 --- a/res/stasis_recording/stored.c +++ b/res/stasis_recording/stored.c @@ -29,7 +29,6 @@ #include "asterisk/paths.h" #include "asterisk/stasis_app_recording.h" -#include #include #include #include @@ -138,12 +137,47 @@ static int split_path(const char *path, char **dir, char **file) return 0; } -static void safe_closedir(DIR *dirp) +struct match_recording_data { + const char *file; + char *file_with_ext; +}; + +static int is_recording(const char *filename) { - if (!dirp) { - return; + const char *ext = strrchr(filename, '.'); + + if (!ext) { + /* No file extension; not us */ + return 0; + } + ++ext; + + if (!ast_get_format_for_file_ext(ext)) { + ast_debug(5, "Recording %s: unrecognized format %s\n", + filename, ext); + /* Keep looking */ + return 0; } - closedir(dirp); + + /* Return the index to the .ext */ + return ext - filename - 1; +} + +static int handle_find_recording(const char *dir_name, const char *filename, void *obj) +{ + struct match_recording_data *data = obj; + int num; + + /* If not a recording or the names do not match the keep searching */ + if (!(num = is_recording(filename)) || strncmp(data->file, filename, num)) { + return 0; + } + + if (ast_asprintf(&data->file_with_ext, "%s/%s", dir_name, filename)) { + return -1; + } + + return 1; } /*! @@ -159,46 +193,15 @@ static void safe_closedir(DIR *dirp) */ static char *find_recording(const char *dir_name, const char *file) { - RAII_VAR(DIR *, dir, NULL, safe_closedir); - struct dirent entry; - struct dirent *result = NULL; - char *ext = NULL; - char *file_with_ext = NULL; - - dir = opendir(dir_name); - if (!dir) { - return NULL; - } - - while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { - ext = strrchr(result->d_name, '.'); + struct match_recording_data data = { + .file = file, + .file_with_ext = NULL + }; - if (!ext) { - /* No file extension; not us */ - continue; - } - *ext++ = '\0'; - - if (strcmp(file, result->d_name) == 0) { - if (!ast_get_format_for_file_ext(ext)) { - ast_log(LOG_WARNING, - "Recording %s: unrecognized format %s\n", - result->d_name, - ext); - /* Keep looking */ - continue; - } - /* We have a winner! */ - break; - } - } + ast_file_read_dir(dir_name, handle_find_recording, &data); - if (!result) { - return NULL; - } - - ast_asprintf(&file_with_ext, "%s/%s.%s", dir_name, file, ext); - return file_with_ext; + /* Note, string potentially allocated in handle_file_recording */ + return data.file_with_ext; } /*! @@ -254,43 +257,33 @@ static int recording_sort(const void *obj_left, const void *obj_right, int flags return cmp; } -static int scan(struct ao2_container *recordings, - const char *base_dir, const char *subdir, struct dirent *entry); - -static int scan_file(struct ao2_container *recordings, - const char *base_dir, const char *subdir, const char *filename, - const char *path) +static int handle_scan_file(const char *dir_name, const char *filename, void *obj) { - RAII_VAR(struct stasis_app_stored_recording *, recording, NULL, - ao2_cleanup); - const char *ext; - char *dot; - - ext = strrchr(filename, '.'); + struct ao2_container *recordings = obj; + struct stasis_app_stored_recording *recording; + char *dot, *filepath; - if (!ext) { - ast_verb(4, " Ignore file without extension: %s\n", - filename); - /* No file extension; not us */ + /* Skip if it is not a recording */ + if (!is_recording(filename)) { return 0; } - ++ext; - if (!ast_get_format_for_file_ext(ext)) { - ast_verb(4, " Not a media file: %s\n", filename); - /* Not a media file */ - return 0; + if (ast_asprintf(&filepath, "%s/%s", dir_name, filename)) { + return -1; } recording = recording_alloc(); if (!recording) { + ast_free(filepath); return -1; } - ast_string_field_set(recording, file_with_ext, path); - + ast_string_field_set(recording, file_with_ext, filepath); /* Build file and format from full path */ - ast_string_field_set(recording, file, path); + ast_string_field_set(recording, file, filepath); + + ast_free(filepath); + dot = strrchr(recording->file, '.'); *dot = '\0'; recording->format = dot + 1; @@ -301,92 +294,14 @@ static int scan_file(struct ao2_container *recordings, /* Add it to the recordings container */ ao2_link(recordings, recording); - - return 0; -} - -static int scan_dir(struct ao2_container *recordings, - const char *base_dir, const char *subdir, const char *dirname, - const char *path) -{ - RAII_VAR(DIR *, dir, NULL, safe_closedir); - RAII_VAR(struct ast_str *, rel_dirname, NULL, ast_free); - struct dirent entry; - struct dirent *result = NULL; - - if (strcmp(dirname, ".") == 0 || - strcmp(dirname, "..") == 0) { - ast_verb(4, " Ignoring self/parent dir\n"); - return 0; - } - - /* Build relative dirname */ - rel_dirname = ast_str_create(80); - if (!rel_dirname) { - return -1; - } - if (!ast_strlen_zero(subdir)) { - ast_str_append(&rel_dirname, 0, "%s/", subdir); - } - if (!ast_strlen_zero(dirname)) { - ast_str_append(&rel_dirname, 0, "%s", dirname); - } - - /* Read the directory */ - dir = opendir(path); - if (!dir) { - ast_log(LOG_WARNING, "Error reading dir '%s'\n", path); - return -1; - } - while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { - scan(recordings, base_dir, ast_str_buffer(rel_dirname), result); - } - - return 0; -} - -static int scan(struct ao2_container *recordings, - const char *base_dir, const char *subdir, struct dirent *entry) -{ - RAII_VAR(struct ast_str *, path, NULL, ast_free); - - path = ast_str_create(255); - if (!path) { - return -1; - } - - /* Build file path */ - ast_str_append(&path, 0, "%s", base_dir); - if (!ast_strlen_zero(subdir)) { - ast_str_append(&path, 0, "/%s", subdir); - } - if (entry) { - ast_str_append(&path, 0, "/%s", entry->d_name); - } - ast_verb(4, "Scanning '%s'\n", ast_str_buffer(path)); - - /* Handle this file */ - switch (entry->d_type) { - case DT_REG: - scan_file(recordings, base_dir, subdir, entry->d_name, - ast_str_buffer(path)); - break; - case DT_DIR: - scan_dir(recordings, base_dir, subdir, entry->d_name, - ast_str_buffer(path)); - break; - default: - ast_log(LOG_WARNING, "Skipping %s: not a regular file\n", - ast_str_buffer(path)); - break; - } + ao2_ref(recording, -1); return 0; } struct ao2_container *stasis_app_stored_recording_find_all(void) { - RAII_VAR(struct ao2_container *, recordings, NULL, ao2_cleanup); + struct ao2_container *recordings; int res; recordings = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, @@ -395,13 +310,13 @@ struct ao2_container *stasis_app_stored_recording_find_all(void) return NULL; } - res = scan_dir(recordings, ast_config_AST_RECORDING_DIR, "", "", - ast_config_AST_RECORDING_DIR); - if (res != 0) { + res = ast_file_read_dirs(ast_config_AST_RECORDING_DIR, + handle_scan_file, recordings, -1); + if (res) { + ao2_ref(recordings, -1); return NULL; } - ao2_ref(recordings, +1); return recordings; } diff --git a/tests/test_file.c b/tests/test_file.c new file mode 100644 index 00000000000..64bad9218d9 --- /dev/null +++ b/tests/test_file.c @@ -0,0 +1,181 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Kevin Harwell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" + +#include "asterisk/file.h" +#include "asterisk/paths.h" +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/strings.h" +#include "asterisk/vector.h" + +#define FOUND -7 + +AST_VECTOR(_filenames, struct ast_str *); + +static void rm_file(struct ast_str *filename) +{ + if (unlink(ast_str_buffer(filename))) { + ast_log(LOG_ERROR, "Unable to remove file: %s\n", ast_str_buffer(filename)); + } + + ast_free(filename); +} + +static int test_files_destroy(struct ast_test *test, char *dir_name, + struct _filenames *filenames) +{ + int res; + + if (filenames) { + AST_VECTOR_CALLBACK_VOID(filenames, rm_file); + AST_VECTOR_FREE(filenames); + } + + if ((res = rmdir(dir_name)) < 0) { + ast_test_status_update(test, "Failed to remove directory: %s\n", dir_name); + } + + return res; +} + +static int test_files_create(struct ast_test *test, char *dir_name, + struct _filenames *filenames, int num) +{ + int i; + + if (!(mkdtemp(dir_name))) { + ast_test_status_update(test, "Failed to create directory: %s\n", dir_name); + return -1; + } + + + AST_VECTOR_INIT(filenames, num); + + /* + * Create "num" files under the specified directory + */ + for (i = 0; i < num; ++i) { + int fd; + struct ast_str *filename = ast_str_create(32); + + if (!filename) { + break; + } + + ast_str_set(&filename, 0, "%s/XXXXXX", dir_name); + + fd = mkstemp(ast_str_buffer(filename)); + if (fd < 0) { + ast_test_status_update(test, "Failed to create file: %s\n", + ast_str_buffer(filename)); + ast_free(filename); + break; + } + close(fd); + + AST_VECTOR_APPEND(filenames, filename); + } + + if (i != num) { + test_files_destroy(test, dir_name, filenames); + return -1; + } + + return 0; +} + +static char *test_files_get_one(struct _filenames *filenames, int num) +{ + /* Every file is in a directory and contains a '/' so okay to do this */ + return strrchr(ast_str_buffer( + AST_VECTOR_GET(filenames, ast_random() % (num - 1))), '/') + 1; +} + +static int handle_find_file(const char *dir_name, const char *filename, void *obj) +{ + /* obj contains the name of the file we are looking for */ + return strcmp(obj, filename) ? 0 : FOUND; +} + +AST_TEST_DEFINE(read_dirs_test) +{ + char tmp_dir[] = "/tmp/tmpdir.XXXXXX"; + struct ast_str *tmp_sub_dir; + struct _filenames filenames; + enum ast_test_result_state res; + const int num_files = 10 + (ast_random() % 10); /* 10-19 random files */ + + switch (cmd) { + case TEST_INIT: + info->name = "read_dir_test"; + info->category = "/main/file/"; + info->summary = "Read a directory's content"; + info->description = "Iterate over directories looking for a file."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* + * We want to test recursively searching into a subdirectory, so + * create a top level tmp directory where we will start the search. + */ + if (!(mkdtemp(tmp_dir))) { + ast_test_status_update(test, "Failed to create directory: %s\n", tmp_dir); + return AST_TEST_FAIL; + } + + tmp_sub_dir = ast_str_alloca(32); + ast_str_set(&tmp_sub_dir, 0, "%s/XXXXXX", tmp_dir); + + if (test_files_create(test, ast_str_buffer(tmp_sub_dir), &filenames, num_files)) { + test_files_destroy(test, tmp_dir, NULL); + return AST_TEST_FAIL; + } + + res = ast_file_read_dirs(tmp_dir, handle_find_file, test_files_get_one( + &filenames, num_files), 2) == FOUND ? AST_TEST_PASS : AST_TEST_FAIL; + + if (test_files_destroy(test, ast_str_buffer(tmp_sub_dir), &filenames) || + test_files_destroy(test, tmp_dir, NULL)) { + res = AST_TEST_FAIL; + } + + return res; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(read_dirs_test); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(read_dirs_test); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "File test module"); From fb17b630a5992a920dd2d81d6f8c1183c29fe353 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 4 Nov 2016 15:33:35 -0500 Subject: [PATCH 0855/1578] bridges/bridge_softmix: Remove SSRC changes on join/leave; update video source WebRTC clients really, really want to know the SSRC of the media they're getting. Changing the SSRC is generally not a good thing. bridge_softmix, starting in Asterisk 12, started changing the SSRC of parties as they joined or left the bridge. With most phones, this isn't a problem: phones just play back the stream they're getting. With WebRTC clients, however, the SSRC is tied to a media stream that may be negotiated. When a new SSRC just shows up, the media can be dropped. As it turns out, the SSRC change shouldn't even be necessary. From the perspective of the client, it's still talking to Asterisk with the same media stream: why indicate that the far party has suddenly changed to a different source of media? This patch opts to just remove the SSRC changes. With this patch, video clients that join/leave a softmix bridge actually get the video stream instead of freaking out. ASTERISK-26555 Change-Id: I27fec098b32e7c8718b4b65f3fd5fa73527968bf --- bridges/bridge_softmix.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 31b72265fee..a0b14749716 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -440,21 +440,6 @@ static void softmix_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridg } } -/*! - * \internal - * \brief Indicate a source change to the channel. - * \since 12.0.0 - * - * \param bridge_channel Which channel source is changing. - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int softmix_src_change(struct ast_bridge_channel *bridge_channel) -{ - return ast_bridge_channel_queue_control_data(bridge_channel, AST_CONTROL_SRCCHANGE, NULL, 0); -} - /*! \brief Function called when a channel is joined into the bridge */ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { @@ -471,8 +456,6 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan return -1; } - softmix_src_change(bridge_channel); - /* Can't forget the lock */ ast_mutex_init(&sc->lock); @@ -499,8 +482,6 @@ static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_ch } bridge_channel->tech_pvt = NULL; - softmix_src_change(bridge_channel); - /* Drop mutex lock */ ast_mutex_destroy(&sc->lock); @@ -694,6 +675,15 @@ static int softmix_bridge_write_control(struct ast_bridge *bridge, struct ast_br * XXX Softmix needs to use channel roles to determine what to * do with control frames. */ + + switch (frame->subclass.integer) { + case AST_CONTROL_VIDUPDATE: + ast_bridge_queue_everyone_else(bridge, NULL, frame); + break; + default: + break; + } + return 0; } From a70d6dba8c33b1a416159aee1a98a647d629b6ec Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 4 Nov 2016 15:36:42 -0500 Subject: [PATCH 0856/1578] main/bridge: Add some verbose logging for video source changes It's actually quite useful to see the source of a video stream change. This doesn't happen terribly often, even with talk detection - but when it does, it's nice to know which channel is now providing your video stream. As a verbose 5 level message, it shouldn't be terribly spammy or costly to have, and is 'lower level' then most other verbose messages that the bridge system emits. ASTERISK-26555 Change-Id: Ia1c20ecafa9670171fd38bddcf3beccae47fb15c --- main/bridge.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/main/bridge.c b/main/bridge.c index cd8ce99b4d5..1bb60eb7a0f 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -3770,6 +3770,10 @@ void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_ cleanup_video_mode(bridge); bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_SINGLE_SRC; bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc = ast_channel_ref(video_src_chan); + ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n", + bridge->name, bridge->uniqueid, + ast_channel_name(video_src_chan), + ast_channel_uniqueid(video_src_chan)); ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to single source\r\nVideo Mode: %u\r\nVideo Channel: %s", bridge->softmix.video_mode.mode, ast_channel_name(video_src_chan)); ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE); @@ -3810,6 +3814,10 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a } data->chan_vsrc = ast_channel_ref(chan); data->average_talking_energy = talker_energy; + ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n", + bridge->name, bridge->uniqueid, + ast_channel_name(data->chan_vsrc), + ast_channel_uniqueid(data->chan_vsrc)); ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc)); ast_indicate(data->chan_vsrc, AST_CONTROL_VIDUPDATE); } else if ((data->average_talking_energy < talker_energy) && !is_keyframe) { @@ -3817,6 +3825,10 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a } else if (!data->chan_vsrc && is_keyframe) { data->chan_vsrc = ast_channel_ref(chan); data->average_talking_energy = talker_energy; + ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n", + bridge->name, bridge->uniqueid, + ast_channel_name(data->chan_vsrc), + ast_channel_uniqueid(data->chan_vsrc)); ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc)); ast_indicate(chan, AST_CONTROL_VIDUPDATE); } else if (!data->chan_old_vsrc && is_keyframe) { From bbe943729a5f627b31f1ae5e3ed303896c5ecf0f Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 4 Nov 2016 15:37:57 -0500 Subject: [PATCH 0857/1578] main/bridge_channel: Fix channel reference leak on video source When a channel is made the video source, the bridge holds a reference to it. Whenever the video source changes, that reference is released. However, a ref leak does occur if the channel leaves the bridge (such as being hung up) while it is the video source, as the bridge never releases the ref in such a case. This patch adds a line to the bridge_channel_internal_join routine such that, when a channel finishes its time in the bridge, it notifies the bridge via ast_bridge_remove_video_src that if it is a video source its reference should be released. ASTERISK-26555 #close Change-Id: I3a2f5238a9d2fc49c591f0e65199d782ab0be76a --- main/bridge_channel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 722fc668785..7f3c8fe3106 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2770,6 +2770,9 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) bridge_channel_settle_owed_events(bridge_channel->bridge, bridge_channel); bridge_reconfigured(bridge_channel->bridge, 1); + /* Remove ourselves if we are the video source */ + ast_bridge_remove_video_src(bridge_channel->bridge, bridge_channel->chan); + ast_bridge_unlock(bridge_channel->bridge); /* Must release any swap ref after unlocking the bridge. */ From 7a449b6819e8a0cdb63f7b587591d56573464fae Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 4 Nov 2016 15:40:58 -0500 Subject: [PATCH 0858/1578] res_stasis: Set a video source mode on Stasis created bridges When a bridge is created via ARI (through res_stasis), no video source mode is set by default. As a result, any endpoint sending video media won't ever see any video reflected back to it. This patch defaults a bridge to a 'follow the talker' video mode. Further work can be done to add routes that allow for the video mode to be controlled through the /bridges resource. Change-Id: I7e9d530a5d7a97a4524a9ee4e468e1a6b3443866 --- res/res_stasis.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_stasis.c b/res/res_stasis.c index f3d940e2db2..54f65150e9a 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -800,6 +800,7 @@ static struct ast_bridge *bridge_create_common(const char *type, const char *nam bridge = bridge_stasis_new(capabilities, flags, name, id); if (bridge) { + ast_bridge_set_talker_src_video_mode(bridge); if (!ao2_link(app_bridges, bridge)) { ast_bridge_destroy(bridge, 0); bridge = NULL; From 367d4903cc76e8ea2e0b59895cf03372575169fe Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 4 Nov 2016 15:42:09 -0500 Subject: [PATCH 0859/1578] res_http_websocket: Increase the buffer size for non-LOW_MEMORY systems Not surprisingly, using Respoke (and possibly other systems) it is possible to blow past the 16k limit for a WebSocket packet size. This patch bumps it up to 32k, which, at least for Respoke, is sufficient. For now. Because 32k is laughable on a LOW_MEMORY system (as is 16k, for that matter), this patch adds a LOW_MEMORY directive that sets the buffer to 8k for systems who have asked for their reduced memory availability to be considered. Change-Id: Id235902537091b58608196844dc4b045e383cd2e --- res/res_http_websocket.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 28bf45fc8ce..c1a28f65d61 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -50,16 +50,29 @@ /*! \brief Number of buckets for registered protocols */ #define MAX_PROTOCOL_BUCKETS 7 +#ifdef LOW_MEMORY /*! \brief Size of the pre-determined buffer for WebSocket frames */ -#define MAXIMUM_FRAME_SIZE 16384 +#define MAXIMUM_FRAME_SIZE 8192 /*! \brief Default reconstruction size for multi-frame payload reconstruction. If exceeded the next frame will start a * payload. */ -#define DEFAULT_RECONSTRUCTION_CEILING 16384 +#define DEFAULT_RECONSTRUCTION_CEILING 8192 /*! \brief Maximum reconstruction size for multi-frame payload reconstruction. */ -#define MAXIMUM_RECONSTRUCTION_CEILING 16384 +#define MAXIMUM_RECONSTRUCTION_CEILING 8192 +#else +/*! \brief Size of the pre-determined buffer for WebSocket frames */ +#define MAXIMUM_FRAME_SIZE 32768 + +/*! \brief Default reconstruction size for multi-frame payload reconstruction. If exceeded the next frame will start a + * payload. + */ +#define DEFAULT_RECONSTRUCTION_CEILING 32768 + +/*! \brief Maximum reconstruction size for multi-frame payload reconstruction. */ +#define MAXIMUM_RECONSTRUCTION_CEILING 32768 +#endif /*! \brief Maximum size of a websocket frame header * 1 byte flags and opcode From fbbbd0add9c180b000309da5c00d582a51d73734 Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Sun, 6 Nov 2016 10:46:30 +0100 Subject: [PATCH 0860/1578] automon: restore mixing of the both channels after recording stops This is a regression over Asterisk 11, introduced by 2dc8a060064f359a17f5ebcd515d85fe5203c019. Previously, recordings started via the automon DTMF code would automatically be mixed together using sox because app_monitor would be called with the m option. This commit restores this behavior. Change-Id: Ibaf58684285c3f1b6ca3714524e6d638ae3b3759 --- bridges/bridge_builtin_features.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c index 3821feef9da..332857347d7 100644 --- a/bridges/bridge_builtin_features.c +++ b/bridges/bridge_builtin_features.c @@ -200,6 +200,8 @@ static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct return; } + ast_monitor_setjoinfiles(peer_chan, 1); + if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) { ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL); ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL); From b2b5f9d897d1534f366b1b96fb10ad1de4f9ba5d Mon Sep 17 00:00:00 2001 From: frahaase Date: Sun, 6 Nov 2016 12:40:14 +0100 Subject: [PATCH 0861/1578] ast_format: Adds an identifier for interleaved audio formats to the ast_format Adds an identifier (with a getter and setter) to detect channels with interleaved audio. This is needed by the binaural bridge_softmix patch (ASTERISK-26292) and was already discussed here: http://lists.digium.com/pipermail/asterisk-dev/2016-October/075900.html The identifier can be set during fmtp parsing (to be seen in the res_format_attr_opus.c change). ASTERISK-26292 Change-Id: I359801cc5f98c35671c48dabc81a7f4ee1183d63 --- include/asterisk/format.h | 18 ++++++++++++++++++ main/format.c | 13 +++++++++++++ res/res_format_attr_opus.c | 8 ++++++++ 3 files changed, 39 insertions(+) diff --git a/include/asterisk/format.h b/include/asterisk/format.h index a5ca038183a..b01592d16e9 100644 --- a/include/asterisk/format.h +++ b/include/asterisk/format.h @@ -298,6 +298,24 @@ void ast_format_set_attribute_data(struct ast_format *format, void *attribute_da */ const char *ast_format_get_name(const struct ast_format *format); +/*! + * \brief Get the channel count on a format + * + * \param The media format + * + * \return Currently set channel count + */ +unsigned int ast_format_get_channel_count(const struct ast_format *format); + +/*! + * \brief Set the channel count on a format + * + * \param format The media format + * \param channel_count The number of audio channels used + * + */ +void ast_format_set_channel_count(struct ast_format *format, unsigned int channel_count); + /*! * \brief Get the codec associated with a format * diff --git a/main/format.c b/main/format.c index b5e577913ed..5ae5ad98623 100644 --- a/main/format.c +++ b/main/format.c @@ -49,6 +49,8 @@ struct ast_format { void *attribute_data; /*! \brief Pointer to the optional format interface */ const struct ast_format_interface *interface; + /*! \brief The number if audio channels used, if more than one an interleaved format is required */ + unsigned int channel_count; }; /*! \brief Structure used when registering a format interface */ @@ -175,6 +177,16 @@ void ast_format_set_attribute_data(struct ast_format *format, void *attribute_da format->attribute_data = attribute_data; } +unsigned int ast_format_get_channel_count(const struct ast_format *format) +{ + return format->channel_count; +} + +void ast_format_set_channel_count(struct ast_format *format, unsigned int channel_count) +{ + format->channel_count = channel_count; +} + /*! \brief Destructor for media formats */ static void format_destroy(void *obj) { @@ -199,6 +211,7 @@ struct ast_format *ast_format_create_named(const char *format_name, struct ast_c } format->name = format_name; format->codec = ao2_bump(codec); + format->channel_count = 1; format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY); if (format_interface) { diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index a3e48e3de79..ad17dfb24c6 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -94,6 +94,7 @@ static int opus_clone(const struct ast_format *src, struct ast_format *dst) ao2_bump(attr->data); ast_format_set_attribute_data(dst, attr); + ast_format_set_channel_count(dst, ast_format_get_channel_count(src)); return 0; } @@ -145,6 +146,9 @@ static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, c sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_PTIME, &attr->ptime); sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE, &attr->maxbitrate); sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_STEREO, &attr->stereo); + if (attr->stereo) { + ast_format_set_channel_count(cloned, 2); + } sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_SPROP_STEREO, &attr->spropstereo); sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_CBR, &attr->cbr); sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_FEC, &attr->fec); @@ -236,6 +240,10 @@ static struct ast_format *opus_getjoint(const struct ast_format *format1, const if (!jointformat) { return NULL; } + + if (ast_format_get_channel_count(format1) == 2 || ast_format_get_channel_count(format2) == 2) { + ast_format_set_channel_count(jointformat, 2); + } attr_res = ast_format_get_attribute_data(jointformat); attr_res->dtx = attr1->dtx || attr2->dtx ? 1 : 0; From a1cdc3891a284d8a51e6f72c536fca43eae0770d Mon Sep 17 00:00:00 2001 From: Alexander Anikin Date: Thu, 3 Nov 2016 22:10:53 +0400 Subject: [PATCH 0862/1578] chan_ooh323: reset rrq count on gk registration reset registration attempts count on success registration on gatekeeper Change-Id: I5f47351852e0ca76c9ac78421659600e0f106336 --- addons/ooh323c/src/ooGkClient.c | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/ooh323c/src/ooGkClient.c b/addons/ooh323c/src/ooGkClient.c index c090796b667..1262f291434 100644 --- a/addons/ooh323c/src/ooGkClient.c +++ b/addons/ooh323c/src/ooGkClient.c @@ -1272,6 +1272,7 @@ int ooGkClientHandleRegistrationConfirm } } pGkClient->state = GkClientRegistered; + pGkClient->rrqRetries = 0; if(pGkClient->callbacks.onReceivedRegistrationConfirm) pGkClient->callbacks.onReceivedRegistrationConfirm(pRegistrationConfirm, gH323ep.aliases); From 0a698cd9329bbfe92141fb20eedfdfb30c3c57c6 Mon Sep 17 00:00:00 2001 From: Alexander Anikin Date: Thu, 3 Nov 2016 16:42:20 +0400 Subject: [PATCH 0863/1578] chan_ooh323: Fixes to work right with Cisco devices Changed output packets queue processing algo to one read-one write instead of all read-all send Remove h.245 tunneling parameter from ReleaseComplete packet ASTERISK-24400 #close Reported by: Dmitry Melekhov Tested by: Dmitry Melekhov Change-Id: I0b31933b062a21011dbac9a82b8bcfe345f406f6 --- addons/ooh323c/src/ooCalls.c | 3 ++- addons/ooh323c/src/oochannels.c | 16 +++++++--------- addons/ooh323c/src/ooq931.c | 5 ----- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/addons/ooh323c/src/ooCalls.c b/addons/ooh323c/src/ooCalls.c index 2eefb46481e..26dc63eab6f 100644 --- a/addons/ooh323c/src/ooCalls.c +++ b/addons/ooh323c/src/ooCalls.c @@ -224,7 +224,8 @@ int ooEndCall(OOH323CallData *call) call->callState = OO_CALL_CLEARED; } - if(call->callState == OO_CALL_CLEARED || call->callState == OO_CALL_CLEAR_RELEASESENT) + if(call->callState == OO_CALL_CLEARED || ((strcmp(call->callType, "incoming")) && + call->callState == OO_CALL_CLEAR_RELEASESENT)) { ooCleanCall(call); call->callState = OO_CALL_REMOVED; diff --git a/addons/ooh323c/src/oochannels.c b/addons/ooh323c/src/oochannels.c index a09470db134..0501882a9bb 100644 --- a/addons/ooh323c/src/oochannels.c +++ b/addons/ooh323c/src/oochannels.c @@ -679,9 +679,9 @@ int ooProcessCallFDSETsAndTimers if (0 != call->pH245Channel && 0 != call->pH245Channel->sock) { if(ooPDWrite(pfds, nfds, call->pH245Channel->sock)) { - while (call->pH245Channel->outQueue.count>0) { + if (call->pH245Channel->outQueue.count>0) { if (ooSendMsg(call, OOH245MSG) != OO_OK) - break; + OOTRACEERR1("Error in sending h245 message\n"); } } } @@ -699,26 +699,24 @@ int ooProcessCallFDSETsAndTimers { if(ooPDWrite(pfds, nfds, call->pH225Channel->sock)) { - while (call->pH225Channel->outQueue.count>0) + if (call->pH225Channel->outQueue.count>0) { OOTRACEDBGC3("Sending H225 message (%s, %s)\n", call->callType, call->callToken); if (ooSendMsg(call, OOQ931MSG) != OO_OK) - break; + OOTRACEERR1("Error in sending h225 message\n"); } if(call->pH245Channel && call->pH245Channel->outQueue.count>0 && OO_TESTFLAG (call->flags, OO_M_TUNNELING)) { - while (call->pH245Channel->outQueue.count>0) { OOTRACEDBGC3("H245 message needs to be tunneled. " "(%s, %s)\n", call->callType, call->callToken); if (ooSendMsg(call, OOH245MSG) != OO_OK) - break; + OOTRACEERR1("Error in sending h245 message\n"); } - } - } - } + } + } if(ooTimerNextTimeout(&call->timerList, &toNext)) { diff --git a/addons/ooh323c/src/ooq931.c b/addons/ooh323c/src/ooq931.c index cbc4afb0a8a..4d6d9936882 100644 --- a/addons/ooh323c/src/ooq931.c +++ b/addons/ooh323c/src/ooq931.c @@ -2124,9 +2124,6 @@ int ooSendReleaseComplete(OOH323CallData *call) return OO_FAILED; } memset(releaseComplete, 0, sizeof(H225ReleaseComplete_UUIE)); - q931msg->userInfo->h323_uu_pdu.m.h245TunnelingPresent=1; - q931msg->userInfo->h323_uu_pdu.h245Tunneling = OO_TESTFLAG(call->flags, - OO_M_TUNNELING); q931msg->userInfo->h323_uu_pdu.h323_message_body.t = T_H225H323_UU_PDU_h323_message_body_releaseComplete; @@ -2143,8 +2140,6 @@ int ooSendReleaseComplete(OOH323CallData *call) releaseComplete->reason.t = h225ReasonCode; /* Add user-user ie */ - q931msg->userInfo->h323_uu_pdu.m.h245TunnelingPresent=TRUE; - q931msg->userInfo->h323_uu_pdu.h245Tunneling = OO_TESTFLAG (call->flags, OO_M_TUNNELING); q931msg->userInfo->h323_uu_pdu.h323_message_body.t = T_H225H323_UU_PDU_h323_message_body_releaseComplete; From d30415bfa15989ae0477e374d37daae9694d7ad4 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 2 Nov 2016 15:52:13 +0000 Subject: [PATCH 0864/1578] res_stasis: Don't unsubscribe from a NULL bridge. A NULL bridge has special meaning in res_stasis for unsubscribing. It means that a subscription to ALL bridges should be removed. This should not be done as part of the normal subscription management in the res_stasis channel loop. ASTERISK-26468 Change-Id: I6d5bea8246dd13a22ef86b736aefbf2a39c15af0 --- res/res_stasis.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/res/res_stasis.c b/res/res_stasis.c index f3d940e2db2..e77cdb0733f 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1327,7 +1327,9 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, bridge = ao2_bump(stasis_app_get_bridge(control)); if (bridge != last_bridge) { - app_unsubscribe_bridge(app, last_bridge); + if (last_bridge) { + app_unsubscribe_bridge(app, last_bridge); + } if (bridge) { app_subscribe_bridge(app, bridge); } @@ -1388,7 +1390,9 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, ast_bridge_depart(chan); } - app_unsubscribe_bridge(app, stasis_app_get_bridge(control)); + if (stasis_app_get_bridge(control)) { + app_unsubscribe_bridge(app, stasis_app_get_bridge(control)); + } ao2_cleanup(bridge); /* Only publish a stasis_end event if it hasn't already been published */ From f073f648b87d45e4729969fd2d83695c300757d1 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 3 Nov 2016 16:36:13 -0500 Subject: [PATCH 0865/1578] Add API for channel frame deferral. There are several places in Asterisk that have duplicated logic for deferring important frames until later. This commit adds a couple of API calls to facilitate this automatically. ast_channel_start_defer_frames(): Future reads of deferrable frames on this channel will be deferred until later. ast_channel_stop_defer_frames(): Any frames that have been deferred get requeued onto the channel. ASTERISK-26343 Change-Id: I3e1b87bc6796f222442fa6f7d1b6a4706fb33641 --- include/asterisk/channel.h | 38 +++++++++++++++++++++++++++++++ main/channel.c | 45 +++++++++++++++++++++++++++++++++++++ main/channel_internal_api.c | 6 +++++ 3 files changed, 89 insertions(+) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index ff92cc87892..e5f53f08225 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -967,6 +967,11 @@ enum { * The channel is executing a subroutine or macro */ AST_FLAG_SUBROUTINE_EXEC = (1 << 27), + /*! + * The channel is currently in an operation where + * frames should be deferred. + */ + AST_FLAG_DEFER_FRAMES = (1 << 28), }; /*! \brief ast_bridge_config flags */ @@ -4671,4 +4676,37 @@ enum ast_channel_error { */ enum ast_channel_error ast_channel_errno(void); +/*! + * \brief Retrieve the deferred read queue. + */ +struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan); + +/*! + * \brief Start deferring deferrable frames on this channel + * + * Sometimes, a channel gets entered into a mode where a "main" application + * is tasked with servicing frames on the channel, but that application does + * not need to act on those frames. However, it would be imprudent to simply + * drop important frames. This function can be called so that important frames + * will be deferred, rather than placed in the channel frame queue as normal. + * + * \pre chan MUST be locked before calling + * + * \param chan The channel on which frames should be deferred + */ +void ast_channel_start_defer_frames(struct ast_channel *chan); + +/*! + * \brief Stop deferring deferrable frames on this channel + * + * When it is time to stop deferring frames on the channel, all deferred frames + * will be queued onto the channel's read queue so that the next servicer of + * the channel can handle those frames as necessary. + * + * \pre chan MUST be locked before calling + * + * \param chan The channel on which to stop deferring frames. + */ +void ast_channel_stop_defer_frames(struct ast_channel *chan); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/main/channel.c b/main/channel.c index cdb6569c3b5..6317f6f20ca 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1062,6 +1062,25 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const return tmp; } +void ast_channel_start_defer_frames(struct ast_channel *chan) +{ + ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); +} + +void ast_channel_stop_defer_frames(struct ast_channel *chan) +{ + ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); + + /* Move the deferred frames onto the channel read queue, ahead of other queued frames */ + ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan))); + /* ast_frfree will mosey down the list and free them all */ + if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) { + ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan))); + } + /* Reset the list to be empty */ + AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan)); +} + static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after) { struct ast_frame *f; @@ -3883,6 +3902,32 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) if (!AST_LIST_EMPTY(ast_channel_readq(chan))) { int skip_dtmf = should_skip_dtmf(chan); + if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) { + AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { + if (ast_is_deferrable_frame(f)) { + if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) { + struct ast_frame *dup; + + /* Hangup is a special case. We want to defer the frame, but we also do not + * want to remove it from the frame queue. So rather than just moving the frame + * over, we duplicate it and move the copy to the deferred readq. + * + * The reason for this? This way, whoever calls ast_read() will get a NULL return + * immediately and can tell the channel has hung up and do what it needs to. Also, + * when frame deferral finishes, then whoever calls ast_read() next will also get + * the hangup. + */ + dup = ast_frdup(f); + AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); + } else { + AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list); + AST_LIST_REMOVE_CURRENT(frame_list); + } + } + } + AST_LIST_TRAVERSE_SAFE_END; + } + AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { /* We have to be picky about which frame we pull off of the readq because * there are cases where we want to leave DTMF frames on the queue until diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 1cb91e7c334..50f6c5da996 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -221,6 +221,7 @@ struct ast_channel { struct stasis_cp_single *topics; /*!< Topic for all channel's events */ struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */ struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */ + struct ast_readq_list deferred_readq; }; /*! \brief The monotonically increasing integer counter for channel uniqueids */ @@ -1681,3 +1682,8 @@ enum ast_channel_error ast_channel_internal_errno(void) return *error_code; } + +struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan) +{ + return &chan->deferred_readq; +} From 28926d1c81540bbeb16802814d3f2e63c2347bd2 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 3 Nov 2016 16:42:40 -0500 Subject: [PATCH 0866/1578] AGI: Only defer frames when in an interception routine. AGI recently was modified to defer important frames. This was because when AGI was used in a connected line interception routine, the resulting connected line frame would end up getting discarded by the AGI. However, this caused bad behavior in other cases. Specifically, during a transfer, if someone attempted to manually set the Caller ID on a channel in an AGI, the deferred connected line frame would end up overwriting what had been manually set in the AGI. Since the initial issue was specific to interception routines, this change removes the manual frame deferral from AGI and instead uses the new frame deferral API in interception routines. ASTERISK-26343 #close Reported by Morton Tryfoss Change-Id: Iab7d39436d0ee99bfe32ad55ef91e9bd88db4208 --- main/channel.c | 24 ++++++++++++++++++++++++ res/res_agi.c | 38 +------------------------------------- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/main/channel.c b/main/channel.c index 6317f6f20ca..b30bb1de792 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10283,9 +10283,15 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected); } + ast_channel_start_defer_frames(macro_chan); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); + + ast_channel_lock(macro_chan); + ast_channel_stop_defer_frames(macro_chan); + ast_channel_unlock(macro_chan); + if (!retval) { struct ast_party_connected_line saved_connected; @@ -10333,9 +10339,15 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting); } + ast_channel_start_defer_frames(macro_chan); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); + + ast_channel_lock(macro_chan); + ast_channel_stop_defer_frames(macro_chan); + ast_channel_unlock(macro_chan); + if (!retval) { struct ast_party_redirecting saved_redirecting; @@ -10376,9 +10388,15 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected); } + ast_channel_start_defer_frames(sub_chan); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); + + ast_channel_lock(sub_chan); + ast_channel_stop_defer_frames(sub_chan); + ast_channel_unlock(sub_chan); + if (!retval) { struct ast_party_connected_line saved_connected; @@ -10419,9 +10437,15 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting); } + ast_channel_start_defer_frames(sub_chan); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); + + ast_channel_lock(sub_chan); + ast_channel_stop_defer_frames(sub_chan); + ast_channel_unlock(sub_chan); + if (!retval) { struct ast_party_redirecting saved_redirecting; diff --git a/res/res_agi.c b/res/res_agi.c index 06e8a03e251..5e047d4c3dc 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -4091,23 +4091,6 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch return AGI_RESULT_SUCCESS; } -AST_LIST_HEAD_NOLOCK(deferred_frames, ast_frame); - -static void queue_deferred_frames(struct deferred_frames *deferred_frames, - struct ast_channel *chan) -{ - struct ast_frame *f; - - if (!AST_LIST_EMPTY(deferred_frames)) { - ast_channel_lock(chan); - while ((f = AST_LIST_REMOVE_HEAD(deferred_frames, frame_list))) { - ast_queue_frame_head(chan, f); - ast_frfree(f); - } - ast_channel_unlock(chan); - } -} - static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[]) { struct ast_channel *c; @@ -4126,9 +4109,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi const char *sighup_str; const char *exit_on_hangup_str; int exit_on_hangup; - struct deferred_frames deferred_frames; - - AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); ast_channel_lock(chan); sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); @@ -4190,20 +4170,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi /* Write, ignoring errors */ if (write(agi->audio, f->data.ptr, f->datalen) < 0) { } - ast_frfree(f); - } else if (ast_is_deferrable_frame(f)) { - struct ast_frame *dup_f; - - if ((dup_f = ast_frisolate(f))) { - AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); - } - - if (dup_f != f) { - ast_frfree(f); - } - } else { - ast_frfree(f); } + ast_frfree(f); } } else if (outfd > -1) { size_t len = sizeof(buf); @@ -4251,8 +4219,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi buf[buflen - 1] = '\0'; } - queue_deferred_frames(&deferred_frames, chan); - if (agidebug) ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf); cmd_status = agi_handle_command(chan, agi, buf, dead); @@ -4275,8 +4241,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi } } - queue_deferred_frames(&deferred_frames, chan); - if (agi->speech) { ast_speech_destroy(agi->speech); } From afef1b8e4a311d33b3e485b9bab3c6e7fd13fbc9 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 3 Nov 2016 16:46:03 -0500 Subject: [PATCH 0867/1578] autoservice: Use frame deferral API Rather than use manual frame deferral, just let the channel API do it for us. ASTERISK-26343 Change-Id: I688386f36e765dbc07be863943a43f26bd5eac49 (cherry picked from commit 8ba3e2fc27f9966b8c7ce75c1eca6208613a9315) --- main/autoservice.c | 66 +++------------------------------------------- 1 file changed, 4 insertions(+), 62 deletions(-) diff --git a/main/autoservice.c b/main/autoservice.c index 11c9eab969d..c8a59a63906 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -59,10 +59,6 @@ struct asent { unsigned int use_count; unsigned int orig_end_dtmf_flag:1; unsigned int ignore_frame_types; - /*! Frames go on at the head of deferred_frames, so we have the frames - * from newest to oldest. As we put them at the head of the readq, we'll - * end up with them in the right order for the channel's readq. */ - AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; AST_LIST_ENTRY(asent) list; }; @@ -77,19 +73,13 @@ static int as_chan_list_state; static void *autoservice_run(void *ign) { ast_callid callid = 0; - struct ast_frame hangup_frame = { - .frametype = AST_FRAME_CONTROL, - .subclass.integer = AST_CONTROL_HANGUP, - }; while (!asexit) { struct ast_channel *mons[MAX_AUTOMONS]; - struct asent *ents[MAX_AUTOMONS]; struct ast_channel *chan; struct asent *as; - int i, x = 0, ms = 50; + int x = 0, ms = 50; struct ast_frame *f = NULL; - struct ast_frame *defer_frame = NULL; AST_LIST_LOCK(&aslist); @@ -104,7 +94,6 @@ static void *autoservice_run(void *ign) AST_LIST_TRAVERSE(&aslist, as, list) { if (!ast_check_hangup(as->chan)) { if (x < MAX_AUTOMONS) { - ents[x] = as; mons[x++] = as->chan; } else { ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n"); @@ -132,51 +121,9 @@ static void *autoservice_run(void *ign) ast_callid_threadassoc_change(callid); f = ast_read(chan); - - if (!f) { - /* No frame means the channel has been hung up. - * A hangup frame needs to be queued here as ast_waitfor() may - * never return again for the condition to be detected outside - * of autoservice. So, we'll leave a HANGUP queued up so the - * thread in charge of this channel will know. */ - - defer_frame = &hangup_frame; - } else if (ast_is_deferrable_frame(f)) { - defer_frame = f; - } else { - /* Can't defer. Discard and continue with next. */ + if (f) { ast_frfree(f); - continue; } - - for (i = 0; i < x; i++) { - struct ast_frame *dup_f; - - if (mons[i] != chan) { - continue; - } - - if (!f) { /* defer_frame == &hangup_frame */ - if ((dup_f = ast_frdup(defer_frame))) { - AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); - } - } else { - if ((dup_f = ast_frisolate(defer_frame))) { - AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); - } - if (dup_f != defer_frame) { - ast_frfree(defer_frame); - } - } - - break; - } - /* The ast_waitfor_n() call will only read frames from - * the channels' file descriptors. If ast_waitfor_n() - * returns non-NULL, then one of the channels in the - * mons array must have triggered the return. It's - * therefore impossible that we got here while (i >= x). - * If we did, we'd need to ast_frfree(f) if (f). */ } ast_callid_threadassoc_change(0); @@ -215,6 +162,7 @@ int ast_autoservice_start(struct ast_channel *chan) as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0; if (!as->orig_end_dtmf_flag) ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); + ast_channel_start_defer_frames(chan); ast_channel_unlock(chan); AST_LIST_LOCK(&aslist); @@ -248,7 +196,6 @@ int ast_autoservice_stop(struct ast_channel *chan) { int res = -1; struct asent *as, *removed = NULL; - struct ast_frame *f; int chan_list_state; AST_LIST_LOCK(&aslist); @@ -300,12 +247,7 @@ int ast_autoservice_stop(struct ast_channel *chan) } ast_channel_lock(chan); - while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) { - if (!((1 << f->frametype) & as->ignore_frame_types)) { - ast_queue_frame_head(chan, f); - } - ast_frfree(f); - } + ast_channel_stop_defer_frames(chan); ast_channel_unlock(chan); ast_free(as); From 392202304d248147378f1e16f1f012285dc1221f Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 3 Nov 2016 16:46:41 -0500 Subject: [PATCH 0868/1578] channel: Use frame deferral API for safe sleep. This is another case where manual frame deferral can be replaced with centralized routines instead. Change-Id: I42cdf205f8f29a7977e599751a57efbaac07c30e (cherry picked from commit d149c4b9e07eeb880d8428ad52c6fdb315cc15f5) --- main/channel.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/main/channel.c b/main/channel.c index b30bb1de792..872661c5a9d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1544,19 +1544,18 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c int res = 0; struct timeval start; int ms; - AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; - - AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); /* If no other generator is present, start silencegen while waiting */ if (ast_opt_transmit_silence && !ast_channel_generatordata(chan)) { silgen = ast_channel_start_silence_generator(chan); } + ast_channel_lock(chan); + ast_channel_start_defer_frames(chan); + ast_channel_unlock(chan); + start = ast_tvnow(); while ((ms = ast_remaining_ms(start, timeout_ms))) { - struct ast_frame *dup_f = NULL; - if (cond && ((*cond)(data) == 0)) { break; } @@ -1571,18 +1570,7 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c res = -1; break; } - - if (!ast_is_deferrable_frame(f)) { - ast_frfree(f); - continue; - } - - if ((dup_f = ast_frisolate(f))) { - if (dup_f != f) { - ast_frfree(f); - } - AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); - } + ast_frfree(f); } } @@ -1591,17 +1579,8 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c ast_channel_stop_silence_generator(chan, silgen); } - /* We need to free all the deferred frames, but we only need to - * queue the deferred frames if there was no error and no - * hangup was received - */ ast_channel_lock(chan); - while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { - if (!res) { - ast_queue_frame_head(chan, f); - } - ast_frfree(f); - } + ast_channel_stop_defer_frames(chan); ast_channel_unlock(chan); return res; From e5860ce07ddf0f81dd20d1b1133a9f95e17976f9 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 8 Nov 2016 10:48:32 -0600 Subject: [PATCH 0869/1578] res_pjsip_session: Do not call session supplements when it's too late. res_pjsip_sesssion was hooking into transaction and invite state changes. One of the reasons for doing so was due to the PJSIP_EVENT_TX_MSG event. The idea was that we were hooking into the message sending process, and so we should call session supplements to alter the outgoing message. In reality, this event was meant to indicate that the message either a) had already been sent, or b) required a DNS lookup and would be sent when the DNS query completed. In case (a), this meant we were altering an already-sent request/response for no reason. In case (b), this potentially meant we could be trying to alter a request/response at the same time that the DNS resolution completed. In this case, it meant we might be stomping on memory being used by the thread actually sending the message. This caused potential crashes and memory corruption. This patch removes the calls to session supplements from the case where the PJSIP_EVENT_TX_MSG event occurs. In all of these cases, trying to alter the message at this point is too late, and it can cause nothing but harm to try to do it. Because there were no longer any calls to the handle_outgoing() function, it has been removed. Change-Id: Ibcc223fb1c3a237927f38754e0429e80ee301e92 --- res/res_pjsip_session.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 7e885c3bddb..527cbd90cc3 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -61,7 +61,6 @@ static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata enum ast_sip_session_response_priority response_priority); static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata); static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata); -static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdata); /*! \brief NAT hook for modifying outgoing messages with SDP */ static struct ast_sip_nat_hook *nat_hook; @@ -2505,17 +2504,6 @@ static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_d } } -static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdata) -{ - ast_debug(3, "Sending %s\n", tdata->msg->type == PJSIP_REQUEST_MSG ? - "request" : "response"); - if (tdata->msg->type == PJSIP_REQUEST_MSG) { - handle_outgoing_request(session, tdata); - } else { - handle_outgoing_response(session, tdata); - } -} - static int session_end(void *vsession) { struct ast_sip_session *session = vsession; @@ -2626,7 +2614,6 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) switch(type) { case PJSIP_EVENT_TX_MSG: - handle_outgoing(session, e->body.tx_msg.tdata); break; case PJSIP_EVENT_RX_MSG: handle_incoming_before_media(inv, session, e->body.rx_msg.rdata); @@ -2636,7 +2623,6 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) /* Transaction state changes are prompted by some other underlying event. */ switch(e->body.tsx_state.type) { case PJSIP_EVENT_TX_MSG: - handle_outgoing(session, e->body.tsx_state.src.tdata); break; case PJSIP_EVENT_RX_MSG: if (!check_request_status(inv, e)) { @@ -2706,7 +2692,6 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } switch (e->body.tsx_state.type) { case PJSIP_EVENT_TX_MSG: - handle_outgoing(session, e->body.tsx_state.src.tdata); /* When we create an outgoing request, we do not have access to the transaction that * is created. Instead, We have to place transaction-specific data in the tdata. Here, * we transfer the data into the transaction. This way, when we receive a response, we From 4e8ab6cda972f96bf8f73a2605d18f6f1b58add5 Mon Sep 17 00:00:00 2001 From: Sebastian Gutierrez Date: Sun, 6 Nov 2016 09:04:00 -0300 Subject: [PATCH 0870/1578] app_queue: new variable set when abandoned sets the variable ABANDONED to TRUE if the call was not answered. ASTERISK-26558 Change-Id: I4729af9bff4eba436d8a776afd3374065d0036d3 --- apps/app_queue.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index b40c1db30f8..0abd512fa87 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -256,7 +256,7 @@ any of the join options cause the caller to not enter the queue. This application does not automatically answer and should be preceeded by an application such as Answer(), Progress(), or Ringing(). - This application sets the following channel variable upon completion: + This application sets the following channel variables upon completion: The status of the call as a text string. @@ -268,6 +268,10 @@ + + If the call was not answered by an agent this variable will be TRUE. + + @@ -4617,6 +4621,8 @@ static void record_abandoned(struct queue_ent *qe) { RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); + pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE"); + set_queue_variables(qe->parent, qe->chan); ao2_lock(qe->parent); blob = ast_json_pack("{s: s, s: i, s: i, s: i}", @@ -7961,6 +7967,8 @@ static int queue_exec(struct ast_channel *chan, const char *data) /* Setup our queue entry */ qe.start = time(NULL); + pbx_builtin_setvar_helper(chan, "ABANDONED", NULL); + /* set the expire time based on the supplied timeout; */ if (!ast_strlen_zero(args.queuetimeoutstr)) { qe.expire = qe.start + atoi(args.queuetimeoutstr); From edea41126bca8c89e856ff215c13b0fa9ea98f72 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 9 Nov 2016 17:18:00 -0700 Subject: [PATCH 0871/1578] build: Fix default values for some SANITIZER options 2 of the sanitizers didn't have default values so in systems that don't support sanitizers menuselect would spit out warnings. They were harmless but confusing. They've now been set to "0". Change-Id: I08dc495e3b83f1feac3160b421f538c375fc5d58 --- configure | 4 ++-- configure.ac | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index af102b4abc1..5d21730e9d0 100755 --- a/configure +++ b/configure @@ -18673,7 +18673,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_ADDRESS_SANITIZER=1 else - AST_ADDRESS_SANITIZER= + AST_ADDRESS_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } @@ -18705,7 +18705,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_THREAD_SANITIZER=1 else - AST_THREAD_SANITIZER= + AST_THREAD_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } diff --git a/configure.ac b/configure.ac index 0f2148b06a8..ea55df41634 100644 --- a/configure.ac +++ b/configure.ac @@ -1115,7 +1115,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_ADDRESS_SANITIZER=1], - [AST_ADDRESS_SANITIZER=] + [AST_ADDRESS_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" @@ -1131,7 +1131,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_THREAD_SANITIZER=1], - [AST_THREAD_SANITIZER=] + [AST_THREAD_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" From e5365dada5052b87275c048f6e29ac7d5e2b2415 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 10 Nov 2016 08:31:52 -0500 Subject: [PATCH 0872/1578] Revert "channel: Use frame deferral API for safe sleep." This reverts commit 392202304d248147378f1e16f1f012285dc1221f. Multiple testsuite issues were discovered after the fact. Change-Id: I848c4196dca2994b1a368087004326ea354cff95 --- main/channel.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/main/channel.c b/main/channel.c index 872661c5a9d..b30bb1de792 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1544,18 +1544,19 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c int res = 0; struct timeval start; int ms; + AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; + + AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); /* If no other generator is present, start silencegen while waiting */ if (ast_opt_transmit_silence && !ast_channel_generatordata(chan)) { silgen = ast_channel_start_silence_generator(chan); } - ast_channel_lock(chan); - ast_channel_start_defer_frames(chan); - ast_channel_unlock(chan); - start = ast_tvnow(); while ((ms = ast_remaining_ms(start, timeout_ms))) { + struct ast_frame *dup_f = NULL; + if (cond && ((*cond)(data) == 0)) { break; } @@ -1570,7 +1571,18 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c res = -1; break; } - ast_frfree(f); + + if (!ast_is_deferrable_frame(f)) { + ast_frfree(f); + continue; + } + + if ((dup_f = ast_frisolate(f))) { + if (dup_f != f) { + ast_frfree(f); + } + AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); + } } } @@ -1579,8 +1591,17 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c ast_channel_stop_silence_generator(chan, silgen); } + /* We need to free all the deferred frames, but we only need to + * queue the deferred frames if there was no error and no + * hangup was received + */ ast_channel_lock(chan); - ast_channel_stop_defer_frames(chan); + while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { + if (!res) { + ast_queue_frame_head(chan, f); + } + ast_frfree(f); + } ast_channel_unlock(chan); return res; From edca6911f392f47c1a5a25d1d3a357c72b04a78a Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 10 Nov 2016 08:32:50 -0500 Subject: [PATCH 0873/1578] Revert "autoservice: Use frame deferral API" This reverts commit afef1b8e4a311d33b3e485b9bab3c6e7fd13fbc9. Multiple testsuite failures were detected after the fact. Change-Id: Ib4cb0c0a6475681ce817f71b4050be25640ab67f --- main/autoservice.c | 66 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/main/autoservice.c b/main/autoservice.c index c8a59a63906..11c9eab969d 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -59,6 +59,10 @@ struct asent { unsigned int use_count; unsigned int orig_end_dtmf_flag:1; unsigned int ignore_frame_types; + /*! Frames go on at the head of deferred_frames, so we have the frames + * from newest to oldest. As we put them at the head of the readq, we'll + * end up with them in the right order for the channel's readq. */ + AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; AST_LIST_ENTRY(asent) list; }; @@ -73,13 +77,19 @@ static int as_chan_list_state; static void *autoservice_run(void *ign) { ast_callid callid = 0; + struct ast_frame hangup_frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_HANGUP, + }; while (!asexit) { struct ast_channel *mons[MAX_AUTOMONS]; + struct asent *ents[MAX_AUTOMONS]; struct ast_channel *chan; struct asent *as; - int x = 0, ms = 50; + int i, x = 0, ms = 50; struct ast_frame *f = NULL; + struct ast_frame *defer_frame = NULL; AST_LIST_LOCK(&aslist); @@ -94,6 +104,7 @@ static void *autoservice_run(void *ign) AST_LIST_TRAVERSE(&aslist, as, list) { if (!ast_check_hangup(as->chan)) { if (x < MAX_AUTOMONS) { + ents[x] = as; mons[x++] = as->chan; } else { ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n"); @@ -121,9 +132,51 @@ static void *autoservice_run(void *ign) ast_callid_threadassoc_change(callid); f = ast_read(chan); - if (f) { + + if (!f) { + /* No frame means the channel has been hung up. + * A hangup frame needs to be queued here as ast_waitfor() may + * never return again for the condition to be detected outside + * of autoservice. So, we'll leave a HANGUP queued up so the + * thread in charge of this channel will know. */ + + defer_frame = &hangup_frame; + } else if (ast_is_deferrable_frame(f)) { + defer_frame = f; + } else { + /* Can't defer. Discard and continue with next. */ ast_frfree(f); + continue; } + + for (i = 0; i < x; i++) { + struct ast_frame *dup_f; + + if (mons[i] != chan) { + continue; + } + + if (!f) { /* defer_frame == &hangup_frame */ + if ((dup_f = ast_frdup(defer_frame))) { + AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); + } + } else { + if ((dup_f = ast_frisolate(defer_frame))) { + AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); + } + if (dup_f != defer_frame) { + ast_frfree(defer_frame); + } + } + + break; + } + /* The ast_waitfor_n() call will only read frames from + * the channels' file descriptors. If ast_waitfor_n() + * returns non-NULL, then one of the channels in the + * mons array must have triggered the return. It's + * therefore impossible that we got here while (i >= x). + * If we did, we'd need to ast_frfree(f) if (f). */ } ast_callid_threadassoc_change(0); @@ -162,7 +215,6 @@ int ast_autoservice_start(struct ast_channel *chan) as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0; if (!as->orig_end_dtmf_flag) ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); - ast_channel_start_defer_frames(chan); ast_channel_unlock(chan); AST_LIST_LOCK(&aslist); @@ -196,6 +248,7 @@ int ast_autoservice_stop(struct ast_channel *chan) { int res = -1; struct asent *as, *removed = NULL; + struct ast_frame *f; int chan_list_state; AST_LIST_LOCK(&aslist); @@ -247,7 +300,12 @@ int ast_autoservice_stop(struct ast_channel *chan) } ast_channel_lock(chan); - ast_channel_stop_defer_frames(chan); + while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) { + if (!((1 << f->frametype) & as->ignore_frame_types)) { + ast_queue_frame_head(chan, f); + } + ast_frfree(f); + } ast_channel_unlock(chan); ast_free(as); From 6bce938c2fcb60b7a77a0e997a6518860c0bfa39 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 10 Nov 2016 08:33:49 -0500 Subject: [PATCH 0874/1578] Revert "AGI: Only defer frames when in an interception routine." This reverts commit 28926d1c81540bbeb16802814d3f2e63c2347bd2. Multiple testsuite failures were detected after the fact. Change-Id: I8d4f5ccbb421a351d616254844ae7e5a31053edb --- main/channel.c | 24 ------------------------ res/res_agi.c | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/main/channel.c b/main/channel.c index b30bb1de792..6317f6f20ca 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10283,15 +10283,9 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected); } - ast_channel_start_defer_frames(macro_chan); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); - - ast_channel_lock(macro_chan); - ast_channel_stop_defer_frames(macro_chan); - ast_channel_unlock(macro_chan); - if (!retval) { struct ast_party_connected_line saved_connected; @@ -10339,15 +10333,9 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting); } - ast_channel_start_defer_frames(macro_chan); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); - - ast_channel_lock(macro_chan); - ast_channel_stop_defer_frames(macro_chan); - ast_channel_unlock(macro_chan); - if (!retval) { struct ast_party_redirecting saved_redirecting; @@ -10388,15 +10376,9 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected); } - ast_channel_start_defer_frames(sub_chan); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); - - ast_channel_lock(sub_chan); - ast_channel_stop_defer_frames(sub_chan); - ast_channel_unlock(sub_chan); - if (!retval) { struct ast_party_connected_line saved_connected; @@ -10437,15 +10419,9 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting); } - ast_channel_start_defer_frames(sub_chan); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); - - ast_channel_lock(sub_chan); - ast_channel_stop_defer_frames(sub_chan); - ast_channel_unlock(sub_chan); - if (!retval) { struct ast_party_redirecting saved_redirecting; diff --git a/res/res_agi.c b/res/res_agi.c index 5e047d4c3dc..06e8a03e251 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -4091,6 +4091,23 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch return AGI_RESULT_SUCCESS; } +AST_LIST_HEAD_NOLOCK(deferred_frames, ast_frame); + +static void queue_deferred_frames(struct deferred_frames *deferred_frames, + struct ast_channel *chan) +{ + struct ast_frame *f; + + if (!AST_LIST_EMPTY(deferred_frames)) { + ast_channel_lock(chan); + while ((f = AST_LIST_REMOVE_HEAD(deferred_frames, frame_list))) { + ast_queue_frame_head(chan, f); + ast_frfree(f); + } + ast_channel_unlock(chan); + } +} + static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[]) { struct ast_channel *c; @@ -4109,6 +4126,9 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi const char *sighup_str; const char *exit_on_hangup_str; int exit_on_hangup; + struct deferred_frames deferred_frames; + + AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); ast_channel_lock(chan); sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); @@ -4170,8 +4190,20 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi /* Write, ignoring errors */ if (write(agi->audio, f->data.ptr, f->datalen) < 0) { } + ast_frfree(f); + } else if (ast_is_deferrable_frame(f)) { + struct ast_frame *dup_f; + + if ((dup_f = ast_frisolate(f))) { + AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); + } + + if (dup_f != f) { + ast_frfree(f); + } + } else { + ast_frfree(f); } - ast_frfree(f); } } else if (outfd > -1) { size_t len = sizeof(buf); @@ -4219,6 +4251,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi buf[buflen - 1] = '\0'; } + queue_deferred_frames(&deferred_frames, chan); + if (agidebug) ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf); cmd_status = agi_handle_command(chan, agi, buf, dead); @@ -4241,6 +4275,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi } } + queue_deferred_frames(&deferred_frames, chan); + if (agi->speech) { ast_speech_destroy(agi->speech); } From fa749866c17f91860d3e9f89742eab3e6f03ecbc Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 10 Nov 2016 08:34:10 -0500 Subject: [PATCH 0875/1578] Revert "Add API for channel frame deferral." This reverts commit f073f648b87d45e4729969fd2d83695c300757d1. Multiple testsuite failures were detected after the fact. Change-Id: I968c380418bf65c7166f6ecff30fe8e247ea6682 --- include/asterisk/channel.h | 38 ------------------------------- main/channel.c | 45 ------------------------------------- main/channel_internal_api.c | 6 ----- 3 files changed, 89 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index e5f53f08225..ff92cc87892 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -967,11 +967,6 @@ enum { * The channel is executing a subroutine or macro */ AST_FLAG_SUBROUTINE_EXEC = (1 << 27), - /*! - * The channel is currently in an operation where - * frames should be deferred. - */ - AST_FLAG_DEFER_FRAMES = (1 << 28), }; /*! \brief ast_bridge_config flags */ @@ -4676,37 +4671,4 @@ enum ast_channel_error { */ enum ast_channel_error ast_channel_errno(void); -/*! - * \brief Retrieve the deferred read queue. - */ -struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan); - -/*! - * \brief Start deferring deferrable frames on this channel - * - * Sometimes, a channel gets entered into a mode where a "main" application - * is tasked with servicing frames on the channel, but that application does - * not need to act on those frames. However, it would be imprudent to simply - * drop important frames. This function can be called so that important frames - * will be deferred, rather than placed in the channel frame queue as normal. - * - * \pre chan MUST be locked before calling - * - * \param chan The channel on which frames should be deferred - */ -void ast_channel_start_defer_frames(struct ast_channel *chan); - -/*! - * \brief Stop deferring deferrable frames on this channel - * - * When it is time to stop deferring frames on the channel, all deferred frames - * will be queued onto the channel's read queue so that the next servicer of - * the channel can handle those frames as necessary. - * - * \pre chan MUST be locked before calling - * - * \param chan The channel on which to stop deferring frames. - */ -void ast_channel_stop_defer_frames(struct ast_channel *chan); - #endif /* _ASTERISK_CHANNEL_H */ diff --git a/main/channel.c b/main/channel.c index 6317f6f20ca..cdb6569c3b5 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1062,25 +1062,6 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const return tmp; } -void ast_channel_start_defer_frames(struct ast_channel *chan) -{ - ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); -} - -void ast_channel_stop_defer_frames(struct ast_channel *chan) -{ - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); - - /* Move the deferred frames onto the channel read queue, ahead of other queued frames */ - ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan))); - /* ast_frfree will mosey down the list and free them all */ - if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) { - ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan))); - } - /* Reset the list to be empty */ - AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan)); -} - static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after) { struct ast_frame *f; @@ -3902,32 +3883,6 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) if (!AST_LIST_EMPTY(ast_channel_readq(chan))) { int skip_dtmf = should_skip_dtmf(chan); - if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) { - AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { - if (ast_is_deferrable_frame(f)) { - if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) { - struct ast_frame *dup; - - /* Hangup is a special case. We want to defer the frame, but we also do not - * want to remove it from the frame queue. So rather than just moving the frame - * over, we duplicate it and move the copy to the deferred readq. - * - * The reason for this? This way, whoever calls ast_read() will get a NULL return - * immediately and can tell the channel has hung up and do what it needs to. Also, - * when frame deferral finishes, then whoever calls ast_read() next will also get - * the hangup. - */ - dup = ast_frdup(f); - AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); - } else { - AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list); - AST_LIST_REMOVE_CURRENT(frame_list); - } - } - } - AST_LIST_TRAVERSE_SAFE_END; - } - AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { /* We have to be picky about which frame we pull off of the readq because * there are cases where we want to leave DTMF frames on the queue until diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 50f6c5da996..1cb91e7c334 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -221,7 +221,6 @@ struct ast_channel { struct stasis_cp_single *topics; /*!< Topic for all channel's events */ struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */ struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */ - struct ast_readq_list deferred_readq; }; /*! \brief The monotonically increasing integer counter for channel uniqueids */ @@ -1682,8 +1681,3 @@ enum ast_channel_error ast_channel_internal_errno(void) return *error_code; } - -struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan) -{ - return &chan->deferred_readq; -} From 93a0de1f0ed10c38c72c8d14032577256a1df4b6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 10 Nov 2016 14:33:41 +0000 Subject: [PATCH 0876/1578] app_queue: Add mention of 'ABANDON' variable to CHANGES. ASTERISK-26558 Change-Id: I1127010181e79c8ac291f72f036cb8e430dc7f7e --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 2131fee3ca8..a57ed88e3ab 100644 --- a/CHANGES +++ b/CHANGES @@ -90,6 +90,11 @@ CLI Commands information will be sent to the Asterisk CLI. +Queue +------------------ + * A new dialplan variable, ABANDONED, is set when the call is not answered + by an agent. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- ------------------------------------------------------------------------------ From bdb6d928c50942be88c0cf58532d4be7424464ad Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 9 Nov 2016 21:14:09 +0000 Subject: [PATCH 0877/1578] res_pjsip: Perform resolution when explicit IPv6 transport is used. This change fixes the SIP resolver such that if an IPv6 transport is explicitly used it will resolve NAPTR, SRV, and AAAA records. You can explicitly use one by specifying it on an endpoint. ASTERISK-26571 Change-Id: I2ed3ce81b43a6a8a937c0ebc1b8ed2da5ac2ef36 --- res/res_pjsip/pjsip_resolver.c | 73 ++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/res/res_pjsip/pjsip_resolver.c b/res/res_pjsip/pjsip_resolver.c index 4d4d36e2750..5a902466e3f 100644 --- a/res/res_pjsip/pjsip_resolver.c +++ b/res/res_pjsip/pjsip_resolver.c @@ -231,8 +231,13 @@ static int sip_resolve_handle_naptr(struct sip_resolve *resolve, const struct as return -1; } + /* It is possible for us to receive an explicit transport that is already IPv6, in that case + * we can't turn it into an IPv6 transport and check. If it's not IPv6 though we need to check + * for both IPv4 and IPv6 as PJSIP does not provide enough differentiation to know that we + * want only IPv4. + */ if (!sip_transport_is_available(transport) && - !sip_transport_is_available(transport + PJSIP_TRANSPORT_IPV6)) { + (!(transport & PJSIP_TRANSPORT_IPV6) && !sip_transport_is_available(transport + PJSIP_TRANSPORT_IPV6))) { ast_debug(2, "[%p] NAPTR service %s skipped as transport is unavailable\n", resolve, service); return -1; @@ -343,13 +348,19 @@ static void sip_resolve_callback(const struct ast_dns_query_set *query_set) /* SRV records just create new queries for AAAA+A, nothing fancy */ ast_debug(2, "[%p] SRV record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); - if (sip_transport_is_available(target->transport + PJSIP_TRANSPORT_IPV6)) { + /* If an explicit IPv6 target transport has been requested look for only AAAA records */ + if (target->transport & PJSIP_TRANSPORT_IPV6) { + sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_aaaa, ns_c_in, target->transport, + ast_dns_srv_get_port(record)); + have_srv = 1; + } else if (sip_transport_is_available(target->transport + PJSIP_TRANSPORT_IPV6)) { sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_aaaa, ns_c_in, target->transport + PJSIP_TRANSPORT_IPV6, ast_dns_srv_get_port(record)); have_srv = 1; } - if (sip_transport_is_available(target->transport)) { + if (!(target->transport & PJSIP_TRANSPORT_IPV6) && + sip_transport_is_available(target->transport)) { sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_a, ns_c_in, target->transport, ast_dns_srv_get_port(record)); have_srv = 1; @@ -365,14 +376,20 @@ static void sip_resolve_callback(const struct ast_dns_query_set *query_set) continue; } - if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_UDP) { - added = sip_resolve_handle_naptr(resolve, record, "sip+d2u", PJSIP_TRANSPORT_UDP); + if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_UDP || + target->transport == PJSIP_TRANSPORT_UDP6) { + added = sip_resolve_handle_naptr(resolve, record, "sip+d2u", + target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : target->transport); } - if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TCP) { - added = sip_resolve_handle_naptr(resolve, record, "sip+d2t", PJSIP_TRANSPORT_TCP); + if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TCP || + target->transport == PJSIP_TRANSPORT_TCP6) { + added = sip_resolve_handle_naptr(resolve, record, "sip+d2t", + target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TCP : target->transport); } - if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TLS) { - added = sip_resolve_handle_naptr(resolve, record, "sips+d2t", PJSIP_TRANSPORT_TLS); + if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TLS || + target->transport == PJSIP_TRANSPORT_TLS6) { + added = sip_resolve_handle_naptr(resolve, record, "sips+d2t", + target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TLS : target->transport); } /* If this record was successfully handled then we need to limit ourselves to this order */ @@ -533,25 +550,39 @@ static void sip_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip if (!target->addr.port) { char srv[NI_MAXHOST]; + /* When resolving addresses PJSIP can request an explicit transport type. It will explicitly + * request an IPv6 transport if a message has been tagged to use an explicitly IPv6 transport. + * For other cases it can be left unspecified OR an explicit non-IPv6 transport can be requested. + * In the case where a non-IPv6 transport is requested there is no way to differentiate between + * a transport being requested as part of a SIP URI (sip:test.com;transport=tcp) and a message + * being tagged with a specific IPv4 transport. In this case we look for both IPv4 and IPv6 addresses. + * If a message has been tagged with a specific IPv4 transport the IPv6 addresses will simply + * be discarded. The code below and elsewhere handles the case where we know they requested IPv6 + * explicitly and only looks for IPv6 records. + */ + res |= sip_resolve_add(resolve, host, ns_t_naptr, ns_c_in, type, 0); - if ((type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_UNSPECIFIED) && - (sip_transport_is_available(PJSIP_TRANSPORT_TLS) || - sip_transport_is_available(PJSIP_TRANSPORT_TLS6))) { + if (type == PJSIP_TRANSPORT_UNSPECIFIED || + (type == PJSIP_TRANSPORT_TLS && sip_transport_is_available(PJSIP_TRANSPORT_TLS)) || + (type == PJSIP_TRANSPORT_TLS6 && sip_transport_is_available(PJSIP_TRANSPORT_TLS6))) { snprintf(srv, sizeof(srv), "_sips._tcp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_TLS, 0); + res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, + type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TLS : type, 0); } - if ((type == PJSIP_TRANSPORT_TCP || type == PJSIP_TRANSPORT_UNSPECIFIED) && - (sip_transport_is_available(PJSIP_TRANSPORT_TCP) || - sip_transport_is_available(PJSIP_TRANSPORT_TCP6))) { + if (type == PJSIP_TRANSPORT_UNSPECIFIED || + (type == PJSIP_TRANSPORT_TCP && sip_transport_is_available(PJSIP_TRANSPORT_TCP)) || + (type == PJSIP_TRANSPORT_TCP6 && sip_transport_is_available(PJSIP_TRANSPORT_TCP6))) { snprintf(srv, sizeof(srv), "_sip._tcp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_TCP, 0); + res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, + type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TCP : type, 0); } - if ((type == PJSIP_TRANSPORT_UDP || type == PJSIP_TRANSPORT_UNSPECIFIED) && - (sip_transport_is_available(PJSIP_TRANSPORT_UDP) || - sip_transport_is_available(PJSIP_TRANSPORT_UDP6))) { + if (type == PJSIP_TRANSPORT_UNSPECIFIED || + (type == PJSIP_TRANSPORT_UDP && sip_transport_is_available(PJSIP_TRANSPORT_UDP)) || + (type == PJSIP_TRANSPORT_UDP6 && sip_transport_is_available(PJSIP_TRANSPORT_UDP6))) { snprintf(srv, sizeof(srv), "_sip._udp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_UDP, 0); + res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, + type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type, 0); } } From 73524bde9c22b7f9b07df776c32a276e778e729d Mon Sep 17 00:00:00 2001 From: "C.J. Collier" Date: Thu, 10 Nov 2016 11:38:25 -0800 Subject: [PATCH 0878/1578] chan_sip: Fix typo and re-wrap surrounding docs Correct typo of end-pints to end-points Re-wrap session timer parameter docs to max 80 chars wide; this eases reading on terminals with lower resolution, commonly the case for those with visual impairments. ASTERISK-26573 Change-Id: I22c94459f4bb6b8a2f6713cfd22e87c32f204e6b Signed-off-by: C.J. Collier --- channels/chan_sip.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 32b2a3611ff..d6d2df69bea 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -199,23 +199,29 @@ The session-timers parameter in sip.conf defines the mode of operation of SIP session-timers feature in Asterisk. The Asterisk can be configured in one of the following three modes: - 1. Accept :: In the "accept" mode, the Asterisk server honors session-timers requests - made by remote end-points. A remote end-point can request Asterisk to engage - session-timers by either sending it an INVITE request with a "Supported: timer" - header in it or by responding to Asterisk's INVITE with a 200 OK that contains - Session-Expires: header in it. In this mode, the Asterisk server does not - request session-timers from remote end-points. This is the default mode. - 2. Originate :: In the "originate" mode, the Asterisk server requests the remote - end-points to activate session-timers in addition to honoring such requests - made by the remote end-pints. In order to get as much protection as possible - against hanging SIP channels due to network or end-point failures, Asterisk - resends periodic re-INVITEs even if a remote end-point does not support - the session-timers feature. - 3. Refuse :: In the "refuse" mode, Asterisk acts as if it does not support session- - timers for inbound or outbound requests. If a remote end-point requests - session-timers in a dialog, then Asterisk ignores that request unless it's - noted as a requirement (Require: header), in which case the INVITE is - rejected with a 420 Bad Extension response. + 1. Accept :: In the "accept" mode, the Asterisk server honors + session-timers requests made by remote end-points. A remote + end-point can request Asterisk to engage session-timers by either + sending it an INVITE request with a "Supported: timer" header in + it or by responding to Asterisk's INVITE with a 200 OK that + contains Session-Expires: header in it. In this mode, the Asterisk + server does not request session-timers from remote + end-points. This is the default mode. + + 2. Originate :: In the "originate" mode, the Asterisk server + requests the remote end-points to activate session-timers in + addition to honoring such requests made by the remote + end-points. In order to get as much protection as possible against + hanging SIP channels due to network or end-point failures, + Asterisk resends periodic re-INVITEs even if a remote end-point + does not support the session-timers feature. + + 3. Refuse :: In the "refuse" mode, Asterisk acts as if it does not + support session- timers for inbound or outbound requests. If a + remote end-point requests session-timers in a dialog, then + Asterisk ignores that request unless it's noted as a requirement + (Require: header), in which case the INVITE is rejected with a 420 + Bad Extension response. */ From 9df59d9ff41afdc732a2f8e91783c1e329b933fc Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 24 Oct 2016 12:41:38 -0500 Subject: [PATCH 0879/1578] res_pjsip_registrar_expire.c: Remove extra linefeed in debug message. Change-Id: I1f9adb911f23376503396ec8867e8005b755eb94 --- res/res_pjsip_registrar_expire.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c index 61841a05407..fe4a60da871 100644 --- a/res/res_pjsip_registrar_expire.c +++ b/res/res_pjsip_registrar_expire.c @@ -82,7 +82,7 @@ static void *check_expiration_thread(void *data) ast_variables_destroy(var); if (contacts) { - ast_debug(3, "Expiring %d contacts\n\n", ao2_container_count(contacts)); + ast_debug(3, "Expiring %d contacts\n", ao2_container_count(contacts)); ao2_callback(contacts, OBJ_NODATA, expire_contact, NULL); ao2_ref(contacts, -1); } From bb196323f9383e34789e5e5c930c789dfb6f9096 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 21 Sep 2016 15:10:29 -0500 Subject: [PATCH 0880/1578] res_pjsip: Fix tdata leaks in off nominal paths. Change-Id: Ie83e06e88c2d60157775263b07e40b61718ac97b --- res/res_pjsip.c | 1 + res/res_pjsip_outbound_registration.c | 2 ++ res/res_pjsip_pubsub.c | 20 +++++++++----------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 916c464a117..655cd958668 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3557,6 +3557,7 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, pj_strbuf(&tdata->msg->line.req.method.name), endpoint ? ast_sorcery_object_get_id(endpoint) : ""); ao2_t_ref(req_wrapper, -2, "Drop timer and routine ref"); + pjsip_tx_data_dec_ref(tdata); return ret_val; } diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 62fe6dab2f1..29701a13c66 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -514,6 +514,7 @@ static pj_status_t registration_client_send(struct sip_outbound_registration_cli callback_invoked = ast_threadstorage_get(®ister_callback_invoked, sizeof(int)); if (!callback_invoked) { + pjsip_tx_data_dec_ref(tdata); return PJ_ENOMEM; } *callback_invoked = 0; @@ -567,6 +568,7 @@ static int handle_client_registration(void *data) /* insert a new Supported header */ hdr = pjsip_supported_hdr_create(tdata->pool); if (!hdr) { + pjsip_tx_data_dec_ref(tdata); return -1; } diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 015ef99c7f3..43a9d4ba65e 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1802,6 +1802,7 @@ static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, if (allocate_tdata_buffer(tdata)) { ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info); + pjsip_tx_data_dec_ref(tdata); return -1; } @@ -2912,7 +2913,6 @@ static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoin static int sip_publication_respond(struct ast_sip_publication *pub, int status_code, pjsip_rx_data *rdata) { - pj_status_t status; pjsip_tx_data *tdata; pjsip_transaction *tsx; @@ -2921,26 +2921,24 @@ static int sip_publication_respond(struct ast_sip_publication *pub, int status_c } if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) { - RAII_VAR(char *, entity_tag, NULL, ast_free_ptr); - RAII_VAR(char *, expires, NULL, ast_free_ptr); + char buf[30]; - if ((ast_asprintf(&entity_tag, "%d", pub->entity_tag) < 0) || - (ast_asprintf(&expires, "%d", pub->expires) < 0)) { - pjsip_tx_data_dec_ref(tdata); - return -1; - } + snprintf(buf, sizeof(buf), "%d", pub->entity_tag); + ast_sip_add_header(tdata, "SIP-ETag", buf); - ast_sip_add_header(tdata, "SIP-ETag", entity_tag); - ast_sip_add_header(tdata, "Expires", expires); + snprintf(buf, sizeof(buf), "%d", pub->expires); + ast_sip_add_header(tdata, "Expires", buf); } - if ((status = pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx)) != PJ_SUCCESS) { + if (pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); return -1; } pjsip_tsx_recv_msg(tsx, rdata); if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); return -1; } From 338f35edccb2043f7ed07f671e9eab5875966a7b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 23 Sep 2016 17:54:07 -0500 Subject: [PATCH 0881/1578] res_pjsip.c: Rework endpt_send_request() req_wrapper code. * Don't hold the req_wrapper lock too long in endpt_send_request(). We could block the PJSIP monitor thread if the timeout timer expires. sip_get_tpselector_from_endpoint() does a sorcery access that could take awhile accessing a database. pjsip_endpt_send_request() might take awhile if selecting a transport. * Shorten the time that the req_wrapper lock is held in the callback functions. * Simplify endpt_send_request() req_wrapper->timeout code. * Removed some redundant req_wrapper->timeout_timer->id assignments. Change-Id: I3195e3a8e0207bb8e7f49060ad2742cf21a6e4c9 --- res/res_pjsip.c | 121 +++++++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 916c464a117..6257cf1066b 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3396,6 +3396,7 @@ struct send_request_wrapper { static void endpt_send_request_cb(void *token, pjsip_event *e) { struct send_request_wrapper *req_wrapper = token; + unsigned int cb_called; if (e->body.tsx_state.type == PJSIP_EVENT_TIMER) { ast_debug(2, "%p: PJSIP tsx timer expired\n", req_wrapper); @@ -3425,7 +3426,6 @@ static void endpt_send_request_cb(void *token, pjsip_event *e) timers_cancelled = pj_timer_heap_cancel_if_active( pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), req_wrapper->timeout_timer, TIMER_INACTIVE); - if (timers_cancelled > 0) { /* If the timer was cancelled the callback will never run so * clean up its reference to the wrapper. @@ -3433,25 +3433,27 @@ static void endpt_send_request_cb(void *token, pjsip_event *e) ast_debug(3, "%p: Timer cancelled\n", req_wrapper); ao2_ref(req_wrapper, -1); } else { - /* If it wasn't cancelled, it MAY be in the callback already - * waiting on the lock so set the id to INACTIVE so - * when the callback comes out of the lock, it knows to not - * proceed. + /* + * If it wasn't cancelled, it MAY be in the callback already + * waiting on the lock. When we release the lock, it will + * now know not to proceed. */ ast_debug(3, "%p: Timer already expired\n", req_wrapper); - req_wrapper->timeout_timer->id = TIMER_INACTIVE; } } + cb_called = req_wrapper->cb_called; + req_wrapper->cb_called = 1; + ao2_unlock(req_wrapper); + /* It's possible that our own timer expired and called the callbacks * so no need to call them again. */ - if (!req_wrapper->cb_called && req_wrapper->callback) { + if (!cb_called && req_wrapper->callback) { req_wrapper->callback(req_wrapper->token, e); - req_wrapper->cb_called = 1; ast_debug(2, "%p: Callbacks executed\n", req_wrapper); } - ao2_unlock(req_wrapper); + ao2_ref(req_wrapper, -1); } @@ -3462,15 +3464,16 @@ static void endpt_send_request_cb(void *token, pjsip_event *e) */ static void send_request_timer_callback(pj_timer_heap_t *theap, pj_timer_entry *entry) { - pjsip_event event; struct send_request_wrapper *req_wrapper = entry->user_data; + unsigned int cb_called; ast_debug(2, "%p: Internal tsx timer expired after %d msec\n", req_wrapper, req_wrapper->timeout); ao2_lock(req_wrapper); - /* If the id is not TIMEOUT_TIMER2 then the timer was cancelled above - * while the lock was being held so just clean up. + /* + * If the id is not TIMEOUT_TIMER2 then the timer was cancelled + * before we got the lock or it was already handled so just clean up. */ if (entry->id != TIMEOUT_TIMER2) { ao2_unlock(req_wrapper); @@ -3478,20 +3481,24 @@ static void send_request_timer_callback(pj_timer_heap_t *theap, pj_timer_entry * ao2_ref(req_wrapper, -1); return; } + entry->id = TIMER_INACTIVE; ast_debug(3, "%p: Timer handled here\n", req_wrapper); - PJSIP_EVENT_INIT_TX_MSG(event, req_wrapper->tdata); - event.body.tsx_state.type = PJSIP_EVENT_TIMER; - entry->id = TIMER_INACTIVE; + cb_called = req_wrapper->cb_called; + req_wrapper->cb_called = 1; + ao2_unlock(req_wrapper); + + if (!cb_called && req_wrapper->callback) { + pjsip_event event; + + PJSIP_EVENT_INIT_TX_MSG(event, req_wrapper->tdata); + event.body.tsx_state.type = PJSIP_EVENT_TIMER; - if (!req_wrapper->cb_called && req_wrapper->callback) { req_wrapper->callback(req_wrapper->token, &event); - req_wrapper->cb_called = 1; ast_debug(2, "%p: Callbacks executed\n", req_wrapper); } - ao2_unlock(req_wrapper); ao2_ref(req_wrapper, -1); } @@ -3511,6 +3518,11 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; + if (!cb && token) { + /* Silly. Without a callback we cannot do anything with token. */ + return PJ_EINVAL; + } + /* Create wrapper to detect if the callback was actually called on an error. */ req_wrapper = ao2_alloc(sizeof(*req_wrapper), send_request_wrapper_destructor); if (!req_wrapper) { @@ -3528,7 +3540,10 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, /* Add a reference to tdata. The wrapper destructor cleans it up. */ pjsip_tx_data_add_ref(tdata); - ao2_lock(req_wrapper); + if (endpoint) { + sip_get_tpselector_from_endpoint(endpoint, &selector); + pjsip_tx_data_set_transport(tdata, &selector); + } if (timeout > 0) { pj_time_val timeout_timer_val = { timeout / 1000, timeout % 1000 }; @@ -3540,9 +3555,6 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, pj_timer_entry_init(req_wrapper->timeout_timer, TIMEOUT_TIMER2, req_wrapper, send_request_timer_callback); - pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(endpt), - req_wrapper->timeout_timer, TIMER_INACTIVE); - /* We need to insure that the wrapper and tdata are available if/when the * timer callback is executed. */ @@ -3550,7 +3562,6 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, ret_val = pj_timer_heap_schedule(pjsip_endpt_get_timer_heap(endpt), req_wrapper->timeout_timer, &timeout_timer_val); if (ret_val != PJ_SUCCESS) { - ao2_unlock(req_wrapper); ast_log(LOG_ERROR, "Failed to set timer. Not sending %.*s request to endpoint %s.\n", (int) pj_strlen(&tdata->msg->line.req.method.name), @@ -3559,33 +3570,22 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, ao2_t_ref(req_wrapper, -2, "Drop timer and routine ref"); return ret_val; } - - req_wrapper->timeout_timer->id = TIMEOUT_TIMER2; - } else { - req_wrapper->timeout_timer = NULL; } /* We need to insure that the wrapper and tdata are available when the * transaction callback is executed. */ ao2_ref(req_wrapper, +1); - - if (endpoint) { - sip_get_tpselector_from_endpoint(endpoint, &selector); - pjsip_tx_data_set_transport(tdata, &selector); - } - ret_val = pjsip_endpt_send_request(endpt, tdata, -1, req_wrapper, endpt_send_request_cb); if (ret_val != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; - if (timeout > 0) { - int timers_cancelled = pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(endpt), - req_wrapper->timeout_timer, TIMER_INACTIVE); - if (timers_cancelled > 0) { - ao2_ref(req_wrapper, -1); - } - } + /* + * endpt_send_request_cb is not expected to ever be called + * because the request didn't get far enough to attempt + * sending. + */ + ao2_ref(req_wrapper, -1); /* Complain of failure to send the request. */ pj_strerror(ret_val, errmsg, sizeof(errmsg)); @@ -3594,20 +3594,37 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, pj_strbuf(&tdata->msg->line.req.method.name), endpoint ? ast_sorcery_object_get_id(endpoint) : ""); - /* Was the callback called? */ - if (req_wrapper->cb_called) { - /* - * Yes so we cannot report any error. The callback - * has already freed any resources associated with - * token. - */ - ret_val = PJ_SUCCESS; - } else { - /* No and it is not expected to ever be called. */ - ao2_ref(req_wrapper, -1); + if (timeout > 0) { + int timers_cancelled; + + ao2_lock(req_wrapper); + timers_cancelled = pj_timer_heap_cancel_if_active( + pjsip_endpt_get_timer_heap(endpt), + req_wrapper->timeout_timer, TIMER_INACTIVE); + if (timers_cancelled > 0) { + ao2_ref(req_wrapper, -1); + } + + /* Was the callback called? */ + if (req_wrapper->cb_called) { + /* + * Yes so we cannot report any error. The callback + * has already freed any resources associated with + * token. + */ + ret_val = PJ_SUCCESS; + } else { + /* + * No so we claim it is called so our caller can free + * any resources associated with token because of + * failure. + */ + req_wrapper->cb_called = 1; + } + ao2_unlock(req_wrapper); } } - ao2_unlock(req_wrapper); + ao2_ref(req_wrapper, -1); return ret_val; } From 939dcf66b0fac0f0eda521a365f076d759accfbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 11 Nov 2016 08:29:40 +0200 Subject: [PATCH 0882/1578] addons/chan_mobile: do not use strerror_r The two reasons why it might be used are that some systems do not implement strerror in thread safe manner, and that strerror_r returns the error code in the string in case there's no error message. However, all of asterisk elsewhere uses strerror() and assumes it to be thread safe. And in chan_mobile the errno is also explicitly printed so neither of the above reasons are valid. The reasoning to remove usage is that there are actually two versions of strerror_r: XSI and GNU. They are incompatible in their return value, and there's no easy way to figure out which one is being used. glibc gives you the GNU version if _GNU_SOURCE is defined, but the same feature test macro is needed for other symbols. On all other systems you assumedly get XSI symbol, and compilation warnings as well as non-working error printing. Thus the easiest solution is to just remove strerror_r and use strerror as rest of the code. Alternative is to introduce ast_strerror in separate translation unit so it can request the XSI symbol in glibc case, and replace all usage of strerror. Change-Id: I84d35225b5642d85d48bc35fdf399afbae28a91d --- addons/chan_mobile.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c index dc2efd4db30..bd39bee6431 100644 --- a/addons/chan_mobile.c +++ b/addons/chan_mobile.c @@ -3853,10 +3853,7 @@ static void *do_monitor_phone(void *data) } if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) { - /* XXX gnu specific strerror_r is assummed here, this - * is not really safe. See the strerror(3) man page - * for more info. */ - ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno); + ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno); break; } @@ -3993,7 +3990,7 @@ static void *do_monitor_phone(void *data) ast_debug(1, "[%s] error parsing message\n", pvt->id); goto e_cleanup; case AT_READ_ERROR: - ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno); + ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno); goto e_cleanup; default: break; @@ -4071,11 +4068,7 @@ static void *do_monitor_headset(void *data) continue; if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) { - if (strerror_r(errno, buf, sizeof(buf))) - ast_debug(1, "[%s] error reading from device\n", pvt->id); - else - ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, buf, errno); - + ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno); goto e_cleanup; } ast_debug(1, "[%s] %s\n", pvt->id, buf); From dfb951817f52fa67cda522d957c2db5a09f0ff68 Mon Sep 17 00:00:00 2001 From: Igor Goncharovskiy Date: Fri, 11 Nov 2016 11:41:36 +0300 Subject: [PATCH 0883/1578] Fix closing rtp ports after call finished in chan_unistim. Fix ASTERISK-26565 by adding ast_rtp_instance_stop before rtp instance destroy for chan_unistim. Also several fixes for displayed text translation. Change-Id: If42a03eea09bd1633471406bdc829cf98bf6affc --- channels/chan_unistim.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 4ad17dc66b7..b8ccdbb2a5f 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -4127,7 +4127,7 @@ static void show_main_page(struct unistimsession *pte) send_date_time2(pte); send_idle_clock(pte); if (strlen(pte->device->maintext0)) { - send_text(TEXT_LINE0, TEXT_NORMAL, pte, pte->device->maintext0); + send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext(pte->device->maintext0, pte)); } } else { if (pte->device->missed_call == 1) { @@ -4146,11 +4146,11 @@ static void show_main_page(struct unistimsession *pte) strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr)); send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf); } else { - send_text(TEXT_LINE2, TEXT_NORMAL, pte, pte->device->maintext2); + send_text(TEXT_LINE2, TEXT_NORMAL, pte, ustmtext(pte->device->maintext2, pte)); } } - send_texttitle(pte, pte->device->titledefault); + send_texttitle(pte, ustmtext(pte->device->titledefault, pte)); change_favorite_icon(pte, FAV_LINE_ICON); } @@ -4405,7 +4405,7 @@ static void init_phone_step2(struct unistimsession *pte) strcat(tmp, pte->macaddr); send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp); send_text_status(pte, ""); - send_texttitle(pte, "UNISTIM for*"); + send_texttitle(pte, ustmtext("UNISTIM for*", pte)); return; } } @@ -4895,14 +4895,15 @@ static int unistim_hangup_clean(struct ast_channel *ast, struct unistim_subchann ast_channel_tech_pvt_set(ast, NULL); unistim_set_owner(sub, NULL); sub->alreadygone = 0; - ast_mutex_unlock(&sub->lock); if (sub->rtp) { if (unistimdebug) { ast_verb(0, "Destroying RTP session\n"); } + ast_rtp_instance_stop(sub->rtp); ast_rtp_instance_destroy(sub->rtp); sub->rtp = NULL; } + ast_mutex_unlock(&sub->lock); return 0; } From 1bd49040c45fe414a4e119a55ea7d5f209c6906a Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 10 Nov 2016 16:57:49 +0000 Subject: [PATCH 0884/1578] res_pjsip_sdp_rtp: Reject offer of required SRTP without res_srtp. When optimistic SRTP was on it was possible for us to still set up a call without an audio stream if an offer was received with required SRTP. This change makes it so this scenario will now fail with a 488 response. ASTERISK-26575 Change-Id: I7d14187037681f48879bd20319ac79d0877318f3 --- res/res_pjsip_sdp_rtp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 3df9df030a2..7fd4f9abc05 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -909,9 +909,11 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct res = setup_media_encryption(session, session_media, sdp, stream); if (res) { - if (!session->endpoint->media.rtp.encryption_optimistic) { + if (!session->endpoint->media.rtp.encryption_optimistic || + !pj_strncmp2(&stream->desc.transport, "RTP/SAVP", 8)) { /* If optimistic encryption is disabled and crypto should have been enabled - * but was not this session must fail. + * but was not this session must fail. This must also fail if crypto was + * required in the offer but could not be set up. */ return -1; } From 97a75e3829e2e263da1828a06dad97b40c7ff32c Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Sat, 12 Nov 2016 20:15:12 +0200 Subject: [PATCH 0885/1578] Add support for building RADIUS with radcli Radcli is yet another RADIUS client library, generally compatible with freeradius and radiusclient-ng. This commit adds autoconf option for detecting it as well and changes cdr_radius and cel_radius to use its header file in that case. ASTERISK-26540 #close Change-Id: I271f0715406334874865ffbce0b354b3a2ca148f --- CHANGES | 4 ++ cdr/cdr_radius.c | 6 +- cel/cel_radius.c | 6 +- configure | 117 ++++++++++++++++++++++++++++++- configure.ac | 10 ++- include/asterisk/autoconfig.h.in | 6 +- 6 files changed, 134 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index a57ed88e3ab..96851af6f15 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,10 @@ Build System Asterisk built with LOW_MEMORY can now successfully load binary modules built without LOW_MEMORY and vice versa. + * RADIUS backends for CEL and CDR can now also be built using the radcli + client library, in addition to the existing support for building them + using either freeradius or radiusclient-ng. + Core ------------------ * ASTERISK_REGISTER_FILE was no longer useful and has been removed. Sources diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c index af434f61852..f6b311def55 100644 --- a/cdr/cdr_radius.c +++ b/cdr/cdr_radius.c @@ -39,11 +39,7 @@ #include "asterisk.h" -#ifdef FREERADIUS_CLIENT -#include -#else -#include -#endif +#include RADIUS_HEADER_STR #include "asterisk/channel.h" #include "asterisk/cdr.h" diff --git a/cel/cel_radius.c b/cel/cel_radius.c index e31cb5edc7c..250d6a77813 100644 --- a/cel/cel_radius.c +++ b/cel/cel_radius.c @@ -33,11 +33,7 @@ #include "asterisk.h" -#ifdef FREERADIUS_CLIENT -#include -#else -#include -#endif +#include RADIUS_HEADER_STR #include "asterisk/channel.h" #include "asterisk/cel.h" diff --git a/configure b/configure index 5d21730e9d0..eeda932796b 100755 --- a/configure +++ b/configure @@ -30902,7 +30902,7 @@ fi if test "x${PBX_RADIUS}" = "x1"; then -$as_echo "#define FREERADIUS_CLIENT /**/" >>confdefs.h +$as_echo "#define RADIUS_HEADER_STR " >>confdefs.h else @@ -31009,6 +31009,121 @@ _ACEOF fi + if test "x${PBX_RADIUS}" = "x1"; then + +$as_echo "#define RADIUS_HEADER_STR " >>confdefs.h + + else + +if test "x${PBX_RADIUS}" != "x1" -a "${USE_RADIUS}" != "no"; then + pbxlibdir="" + # if --with-RADIUS=DIR has been specified, use it. + if test "x${RADIUS_DIR}" != "x"; then + if test -d ${RADIUS_DIR}/lib; then + pbxlibdir="-L${RADIUS_DIR}/lib" + else + pbxlibdir="-L${RADIUS_DIR}" + fi + fi + pbxfuncname="rc_read_config" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_RADIUS_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_radcli_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lradcli" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lradcli... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lradcli ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_RADIUS_FOUND=yes +else + AST_RADIUS_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_RADIUS_FOUND}" = "yes"; then + RADIUS_LIB="${pbxlibdir} -lradcli " + # if --with-RADIUS=DIR has been specified, use it. + if test "x${RADIUS_DIR}" != "x"; then + RADIUS_INCLUDE="-I${RADIUS_DIR}/include" + fi + RADIUS_INCLUDE="${RADIUS_INCLUDE} " + if test "xradcli/radcli.h" = "x" ; then # no header, assume found + RADIUS_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${RADIUS_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "radcli/radcli.h" "ac_cv_header_radcli_radcli_h" "$ac_includes_default" +if test "x$ac_cv_header_radcli_radcli_h" = xyes; then : + RADIUS_HEADER_FOUND=1 +else + RADIUS_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${RADIUS_HEADER_FOUND}" = "x0" ; then + RADIUS_LIB="" + RADIUS_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + RADIUS_LIB="" + fi + PBX_RADIUS=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_RADIUS 1 +_ACEOF + + fi + fi +fi + + + if test "x${PBX_RADIUS}" = "x1"; then + +$as_echo "#define RADIUS_HEADER_STR " >>confdefs.h + + fi + fi fi diff --git a/configure.ac b/configure.ac index ea55df41634..3bdf14016b2 100644 --- a/configure.ac +++ b/configure.ac @@ -2364,9 +2364,17 @@ AST_EXT_LIB_CHECK([LUA], [lua], [luaL_openlib], [lua.h], [-lm]) # just different header filenames and different SONAMEs AST_EXT_LIB_CHECK([RADIUS], [freeradius-client], [rc_read_config], [freeradius-client.h]) if test "x${PBX_RADIUS}" = "x1"; then - AC_DEFINE(FREERADIUS_CLIENT, [], [Use the FreeRADIUS-client library]) + AC_DEFINE(RADIUS_HEADER_STR, [], [Name of RADIUS library include header]) else AST_EXT_LIB_CHECK([RADIUS], [radiusclient-ng], [rc_read_config], [radiusclient-ng.h]) + if test "x${PBX_RADIUS}" = "x1"; then + AC_DEFINE(RADIUS_HEADER_STR, [], [Name of RADIUS library include header]) + else + AST_EXT_LIB_CHECK([RADIUS], [radcli], [rc_read_config], [radcli/radcli.h]) + if test "x${PBX_RADIUS}" = "x1"; then + AC_DEFINE(RADIUS_HEADER_STR, [], [Name of RADIUS library include header]) + fi + fi fi AST_EXT_LIB_CHECK([CODEC2], [codec2], [codec2_create], [codec2/codec2.h]) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 706798ced35..45bc800ee45 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -28,9 +28,6 @@ /* Define to 1 if using `alloca.c'. */ #undef C_ALLOCA -/* Use the FreeRADIUS-client library */ -#undef FREERADIUS_CLIENT - /* Define to 1 if anonymous semaphores work. */ #undef HAS_WORKING_SEMAPHORE @@ -1305,6 +1302,9 @@ /* Define if your system needs braces around PTHREAD_ONCE_INIT */ #undef PTHREAD_ONCE_INIT_NEEDS_BRACES +/* Name of RADIUS library include header */ +#undef RADIUS_HEADER_STR + /* Define to the type of arg 1 for `select'. */ #undef SELECT_TYPE_ARG1 From 72da2ef9ffb49a1fc550ec91caa1468e285f87e0 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 14 Nov 2016 11:16:03 -0700 Subject: [PATCH 0886/1578] cli: Fix ast_el_read_char to work with libedit >= 3.1 Libedit 3.1 is not build with unicode on as a default and so the prototype for the el_gets callback changed from expecting a char buffer to accepting a wchar buffer. If ast_el_read_char isn't changed, the cli reads garbage from teh terminal. Added a configure test for (*el_rfunc_t)(EditLine *, wchar_t *) and updated ast_el_read_char to use the HAVE_ define to detemrine whether to use char or wchar. ASTERISK-26592 #close Change-Id: I9099b46f68e06d0202ff80e53022a2b68b08871a --- configure | 65 +++++++++++++++++++++++++++++++- configure.ac | 6 ++- include/asterisk/autoconfig.h.in | 3 ++ main/asterisk.c | 21 ++++++++++- 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 5d21730e9d0..17f84ea7cfe 100755 --- a/configure +++ b/configure @@ -1055,6 +1055,10 @@ PBX_LIBXML2 LIBXML2_DIR LIBXML2_INCLUDE LIBXML2_LIB +PBX_LIBEDIT_IS_UNICODE +LIBEDIT_IS_UNICODE_DIR +LIBEDIT_IS_UNICODE_INCLUDE +LIBEDIT_IS_UNICODE_LIB PBX_LIBEDIT LIBEDIT_DIR LIBEDIT_INCLUDE @@ -10733,6 +10737,18 @@ fi +LIBEDIT_IS_UNICODE_DESCRIP="Libedit compiled for unicode" +LIBEDIT_IS_UNICODE_OPTION=libedit +LIBEDIT_IS_UNICODE_DIR=${LIBEDIT_DIR} + +PBX_LIBEDIT_IS_UNICODE=0 + + + + + + + LIBXML2_DESCRIP="LibXML2" LIBXML2_OPTION="libxml2" PBX_LIBXML2=0 @@ -21129,11 +21145,58 @@ fi fi if test "$PBX_LIBEDIT" = "1"; then - LIBEDIT_INTERNAL="no" + LIBEDIT_INTERNAL="no" fi fi if test "${LIBEDIT_INTERNAL}" = "yes"; then PBX_LIBEDIT=1 + LIBEDIT_IS_UNICODE=no + else + + if test "x${PBX_LIBEDIT_IS_UNICODE}" != "x1" -a "${USE_LIBEDIT_IS_UNICODE}" != "no"; then + if test "xTesting for libedit unicode support" != "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Testing for libedit unicode support" >&5 +$as_echo_n "checking for Testing for libedit unicode support... " >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if \"el_rfunc_t *callback;\" compiles using histedit.h" >&5 +$as_echo_n "checking if \"el_rfunc_t *callback;\" compiles using histedit.h... " >&6; } + fi + saved_cppflags="${CPPFLAGS}" + if test "x${LIBEDIT_IS_UNICODE_DIR}" != "x"; then + LIBEDIT_IS_UNICODE_INCLUDE="-I${LIBEDIT_IS_UNICODE_DIR}/include" + fi + CPPFLAGS="${CPPFLAGS} ${LIBEDIT_IS_UNICODE_INCLUDE}" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #include +int +main () +{ + el_rfunc_t *callback;; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_LIBEDIT_IS_UNICODE=1 + +$as_echo "#define HAVE_LIBEDIT_IS_UNICODE 1" >>confdefs.h + + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CPPFLAGS="${saved_cppflags}" + fi + fi fi diff --git a/configure.ac b/configure.ac index ea55df41634..7261e535c46 100644 --- a/configure.ac +++ b/configure.ac @@ -479,6 +479,7 @@ AST_EXT_LIB_SETUP([KQUEUE], [kqueue support], [kqueue]) AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap]) AST_LIBCURL_CHECK_CONFIG([], [7.10.1]) AST_EXT_LIB_SETUP([LIBEDIT], [NetBSD Editline library], [libedit], [, use 'internal' Editline otherwise]) +AST_EXT_LIB_SETUP_OPTIONAL([LIBEDIT_IS_UNICODE], [Libedit compiled for unicode], [LIBEDIT], [libedit]) AST_EXT_LIB_SETUP([LIBXML2], [LibXML2], [libxml2]) AST_EXT_LIB_SETUP([LIBXSLT], [LibXSLT], [libxslt]) AST_EXT_LIB_SETUP_OPTIONAL([LIBXSLT_CLEANUP], [LibXSLT Library Cleanup Function], [LIBXSLT], [libxslt]) @@ -1530,11 +1531,14 @@ if test "${USE_LIBEDIT}" != "no"; then if test "${LIBEDIT_SYSTEM}" = "yes"; then AST_PKG_CONFIG_CHECK(LIBEDIT, libedit) if test "$PBX_LIBEDIT" = "1"; then - LIBEDIT_INTERNAL="no" + LIBEDIT_INTERNAL="no" fi fi if test "${LIBEDIT_INTERNAL}" = "yes"; then PBX_LIBEDIT=1 + LIBEDIT_IS_UNICODE=no + else + AST_C_COMPILE_CHECK([LIBEDIT_IS_UNICODE], [el_rfunc_t *callback;], [histedit.h], [], [Testing for libedit unicode support]) fi fi diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 706798ced35..3673c8bc20c 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -402,6 +402,9 @@ /* Define if your system has the LIBEDIT libraries. */ #undef HAVE_LIBEDIT +/* Define if your system has the LIBEDIT_IS_UNICODE headers. */ +#undef HAVE_LIBEDIT_IS_UNICODE + /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H diff --git a/main/asterisk.c b/main/asterisk.c index be6c7cc3242..4a6567f73eb 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -2691,7 +2691,11 @@ static void send_rasterisk_connect_commands(void) } } +#ifdef HAVE_LIBEDIT_IS_UNICODE +static int ast_el_read_char(EditLine *editline, wchar_t *cp) +#else static int ast_el_read_char(EditLine *editline, char *cp) +#endif { int num_read = 0; int lastpos = 0; @@ -2721,10 +2725,16 @@ static int ast_el_read_char(EditLine *editline, char *cp) } if (!ast_opt_exec && fds[1].revents) { - num_read = read(STDIN_FILENO, cp, 1); + char c = '\0'; + num_read = read(STDIN_FILENO, &c, 1); if (num_read < 1) { break; } else { +#ifdef HAVE_LIBEDIT_IS_UNICODE + *cp = btowc(c); +#else + *cp = c; +#endif return (num_read); } } @@ -2768,7 +2778,11 @@ static int ast_el_read_char(EditLine *editline, char *cp) console_print(buf); if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (res >= 2 && buf[res-2] == '\n'))) { +#ifdef HAVE_LIBEDIT_IS_UNICODE + *cp = btowc(CC_REFRESH); +#else *cp = CC_REFRESH; +#endif return(1); } else { lastpos = 1; @@ -2776,7 +2790,12 @@ static int ast_el_read_char(EditLine *editline, char *cp) } } +#ifdef HAVE_LIBEDIT_IS_UNICODE + *cp = btowc('\0'); +#else *cp = '\0'; +#endif + return (0); } From c6d755de11e98c1f6f33b1b35db9725f64f72053 Mon Sep 17 00:00:00 2001 From: Sebastien Duthil Date: Fri, 11 Nov 2016 11:45:37 -0500 Subject: [PATCH 0887/1578] res_ari: Add support for channel variables in ARI events. This works the same as for AMI manager variables. Set "channelvars=foo,bar" in your ari.conf general section, and then the channel variables "foo" and "bar" (along with their values), will appear in every Stasis websocket channel event. ASTERISK-26492 #close patches: ari_vars.diff submitted by Mark Michelson Change-Id: I5609ba239259577c0948645df776d7f3bc864229 --- CHANGES | 6 +++ configs/samples/ari.conf.sample | 5 ++ include/asterisk/channel.h | 30 ++++++++++++ include/asterisk/json.h | 12 +++++ include/asterisk/stasis_channels.h | 1 + main/channel.c | 78 ++++++++++++++++++++++-------- main/json.c | 13 +++++ main/stasis_channels.c | 5 ++ res/ari/ari_model_validators.c | 9 ++++ res/ari/ari_model_validators.h | 1 + res/ari/config.c | 20 ++++++++ res/res_ari.c | 3 ++ rest-api/api-docs/channels.json | 5 ++ 13 files changed, 169 insertions(+), 19 deletions(-) diff --git a/CHANGES b/CHANGES index a57ed88e3ab..b9d19a6f25c 100644 --- a/CHANGES +++ b/CHANGES @@ -95,6 +95,12 @@ Queue * A new dialplan variable, ABANDONED, is set when the call is not answered by an agent. +res_ari +------------------ + * The configuration file ari.conf now supports a channelvars option, which + specifies a list of channel variables to include in each channel-oriented + ARI event. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- ------------------------------------------------------------------------------ diff --git a/configs/samples/ari.conf.sample b/configs/samples/ari.conf.sample index 59f9a44e5c3..1294814e2d9 100644 --- a/configs/samples/ari.conf.sample +++ b/configs/samples/ari.conf.sample @@ -13,6 +13,11 @@ enabled = yes ; When set to no, ARI support is disabled. ; receiving clients are slow to process the received information. Value is in ; milliseconds; default is 100 ms. ;websocket_write_timeout = 100 +; +; Display certain channel variables every time a channel-oriented +; event is emitted: +; +;channelvars = var1,var2,var3 ;[username] ;type = user ; Specifies user configuration diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index ff92cc87892..cfd8384cb87 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4339,6 +4339,36 @@ void ast_channel_set_manager_vars(size_t varc, char **vars); */ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan); +/*! + * \since 14.2.0 + * \brief Return whether or not any ARI variables have been set + * + * \retval 0 if no ARI variables are expected + * \retval 1 if ARI variables are expected + */ +int ast_channel_has_ari_vars(void); + +/*! + * \since 14.2.0 + * \brief Sets the variables to be stored in the \a ari_vars field of all + * snapshots. + * \param varc Number of variable names. + * \param vars Array of variable names. + */ +void ast_channel_set_ari_vars(size_t varc, char **vars); + +/*! + * \since 14.2.0 + * \brief Gets the variables for a given channel, as specified by ast_channel_set_ari_vars(). + * + * The returned variable list is an AO2 object, so ao2_cleanup() to free it. + * + * \param chan Channel to get variables for. + * \return List of channel variables. + * \return \c NULL on error + */ +struct varshead *ast_channel_get_ari_vars(struct ast_channel *chan); + /*! * \since 12 * \brief Gets the variables for a given channel, as set using pbx_builtin_setvar_helper(). diff --git a/include/asterisk/json.h b/include/asterisk/json.h index cfd9a29976d..bd6ba86b98a 100644 --- a/include/asterisk/json.h +++ b/include/asterisk/json.h @@ -1076,6 +1076,18 @@ enum ast_json_to_ast_vars_code { */ enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables); +struct varshead; + +/*! + * \brief Construct a JSON object from a \c ast_var_t list + * \since 14.2.0 + * + * \param channelvars The list of \c ast_var_t to represent as JSON + * + * \return JSON object with variable names as keys and variable values as values + */ +struct ast_json *ast_json_channel_vars(struct varshead *channelvars); + /*!@}*/ #endif /* _ASTERISK_JSON_H */ diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h index 6c6cd51f129..deb79b0d061 100644 --- a/include/asterisk/stasis_channels.h +++ b/include/asterisk/stasis_channels.h @@ -73,6 +73,7 @@ struct ast_channel_snapshot { struct ast_flags softhangup_flags; /*!< softhangup channel flags */ struct varshead *manager_vars; /*!< Variables to be appended to manager events */ int tech_properties; /*!< Properties of the channel's technology */ + struct varshead *ari_vars; /*!< Variables to be appended to ARI events */ }; /*! diff --git a/main/channel.c b/main/channel.c index cdb6569c3b5..bdf918fabdf 100644 --- a/main/channel.c +++ b/main/channel.c @@ -7756,35 +7756,48 @@ struct manager_channel_variable { char name[]; }; -static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable); +AST_RWLIST_HEAD(external_vars, manager_channel_variable); -static void free_channelvars(void) +static struct external_vars ami_vars; +static struct external_vars ari_vars; + +static void free_external_channelvars(struct external_vars *channelvars) { struct manager_channel_variable *var; - AST_RWLIST_WRLOCK(&channelvars); - while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) { + AST_RWLIST_WRLOCK(channelvars); + while ((var = AST_RWLIST_REMOVE_HEAD(channelvars, entry))) { ast_free(var); } - AST_RWLIST_UNLOCK(&channelvars); + AST_RWLIST_UNLOCK(channelvars); } -int ast_channel_has_manager_vars(void) +static int channel_has_external_vars(struct external_vars *channelvars) { int vars_present; - AST_RWLIST_RDLOCK(&channelvars); - vars_present = !AST_LIST_EMPTY(&channelvars); - AST_RWLIST_UNLOCK(&channelvars); + AST_RWLIST_RDLOCK(channelvars); + vars_present = !AST_LIST_EMPTY(channelvars); + AST_RWLIST_UNLOCK(channelvars); return vars_present; } -void ast_channel_set_manager_vars(size_t varc, char **vars) +int ast_channel_has_manager_vars(void) +{ + return channel_has_external_vars(&ami_vars); +} + +int ast_channel_has_ari_vars(void) +{ + return channel_has_external_vars(&ari_vars); +} + +static void channel_set_external_vars(struct external_vars *channelvars, size_t varc, char **vars) { size_t i; - free_channelvars(); - AST_RWLIST_WRLOCK(&channelvars); + free_external_channelvars(channelvars); + AST_RWLIST_WRLOCK(channelvars); for (i = 0; i < varc; ++i) { const char *var = vars[i]; struct manager_channel_variable *mcv; @@ -7795,9 +7808,20 @@ void ast_channel_set_manager_vars(size_t varc, char **vars) if (strchr(var, '(')) { mcv->isfunc = 1; } - AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry); + AST_RWLIST_INSERT_TAIL(channelvars, mcv, entry); } - AST_RWLIST_UNLOCK(&channelvars); + AST_RWLIST_UNLOCK(channelvars); + +} + +void ast_channel_set_manager_vars(size_t varc, char **vars) +{ + channel_set_external_vars(&ami_vars, varc, vars); +} + +void ast_channel_set_ari_vars(size_t varc, char **vars) +{ + channel_set_external_vars(&ari_vars, varc, vars); } /*! @@ -7839,14 +7863,15 @@ struct varshead *ast_channel_get_vars(struct ast_channel *chan) return ret; } -struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan) +static struct varshead *channel_get_external_vars(struct external_vars *channelvars, + struct ast_channel *chan) { RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup); RAII_VAR(struct ast_str *, tmp, NULL, ast_free); struct manager_channel_variable *mcv; - SCOPED_LOCK(lock, &channelvars, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + SCOPED_LOCK(lock, channelvars, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); - if (AST_LIST_EMPTY(&channelvars)) { + if (AST_LIST_EMPTY(channelvars)) { return NULL; } @@ -7857,7 +7882,7 @@ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan) return NULL; } - AST_LIST_TRAVERSE(&channelvars, mcv, entry) { + AST_LIST_TRAVERSE(channelvars, mcv, entry) { const char *val = NULL; struct ast_var_t *var; @@ -7882,11 +7907,23 @@ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan) ao2_ref(ret, +1); return ret; + +} + +struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan) +{ + return channel_get_external_vars(&ami_vars, chan); +} + +struct varshead *ast_channel_get_ari_vars(struct ast_channel *chan) +{ + return channel_get_external_vars(&ari_vars, chan); } static void channels_shutdown(void) { - free_channelvars(); + free_external_channelvars(&ami_vars); + free_external_channelvars(&ari_vars); ast_data_unregister(NULL); ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel)); @@ -7919,6 +7956,9 @@ int ast_channels_init(void) ast_register_cleanup(channels_shutdown); + AST_RWLIST_HEAD_INIT(&ami_vars); + AST_RWLIST_HEAD_INIT(&ari_vars); + return 0; } diff --git a/main/json.c b/main/json.c index 7b5cfbe7e6e..a28dbb2e22f 100644 --- a/main/json.c +++ b/main/json.c @@ -1048,3 +1048,16 @@ enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_v return AST_JSON_TO_AST_VARS_CODE_SUCCESS; } + +struct ast_json *ast_json_channel_vars(struct varshead *channelvars) +{ + struct ast_json *ret; + struct ast_var_t *var; + + ret = ast_json_object_create(); + AST_LIST_TRAVERSE(channelvars, var, entries) { + ast_json_object_set(ret, var->name, ast_json_string_create(var->value)); + } + + return ret; +} diff --git a/main/stasis_channels.c b/main/stasis_channels.c index 91f209290ae..4897af89e7e 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -270,6 +270,7 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan)); snapshot->manager_vars = ast_channel_get_manager_vars(chan); + snapshot->ari_vars = ast_channel_get_ari_vars(chan); snapshot->tech_properties = ast_channel_tech(chan)->properties; return snapshot; @@ -918,6 +919,10 @@ struct ast_json *ast_channel_snapshot_to_json( "creationtime", ast_json_timeval(snapshot->creationtime, NULL), "language", snapshot->language); + if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) { + ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars)); + } + return ast_json_ref(json_chan); } diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index 03cd3a2386b..9fd844c4d49 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -1051,6 +1051,15 @@ int ast_ari_validate_channel(struct ast_json *json) res = 0; } } else + if (strcmp("channelvars", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_object( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Channel field channelvars failed validation\n"); + res = 0; + } + } else if (strcmp("connected", ast_json_object_iter_key(iter)) == 0) { int prop_is_valid; has_connected = 1; diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index 0b08ce85e5a..fcd9fc11c0c 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -1432,6 +1432,7 @@ ari_validator ast_ari_validate_application_fn(void); * Channel * - accountcode: string (required) * - caller: CallerID (required) + * - channelvars: object * - connected: CallerID (required) * - creationtime: Date (required) * - dialplan: DialplanCEP (required) diff --git a/res/ari/config.c b/res/ari/config.c index deaa78073d5..a080bb713fe 100644 --- a/res/ari/config.c +++ b/res/ari/config.c @@ -26,6 +26,8 @@ #include "asterisk/config_options.h" #include "asterisk/http_websocket.h" +#include "asterisk/app.h" +#include "asterisk/channel.h" #include "internal.h" /*! \brief Locking container for safe configuration access. */ @@ -316,6 +318,22 @@ static int process_config(int reload) return 0; } +#define MAX_VARS 128 + +static int channelvars_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + char *parse = NULL; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(vars)[MAX_VARS]; + ); + + parse = ast_strdupa(var->value); + AST_STANDARD_APP_ARGS(args, parse); + + ast_channel_set_ari_vars(args.argc, args.vars); + return 0; +} + int ast_ari_config_init(void) { if (aco_info_init(&cfg_info)) { @@ -339,6 +357,8 @@ int ast_ari_config_init(void) aco_option_register(&cfg_info, "websocket_write_timeout", ACO_EXACT, general_options, AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_ari_conf_general, write_timeout), 1, INT_MAX); + aco_option_register_custom(&cfg_info, "channelvars", ACO_EXACT, general_options, + "", channelvars_handler, 0); /* ARI type=user category options */ aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL, diff --git a/res/res_ari.c b/res/res_ari.c index e19881515ae..e362a581169 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -112,6 +112,9 @@ Comma separated list of allowed origins, for Cross-Origin Resource Sharing. May be set to * to allow all origins. + + Comma separated list of channel variables to display in channel json. + diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index 4ca8d6582da..241b22ae8f3 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -1761,6 +1761,11 @@ "required": true, "type": "string", "description": "The default spoken language" + }, + "channelvars": { + "required": false, + "type": "object", + "description": "Channel variables" } } } From 2966fa5ad770710ca1d0ca7f306def6792255bd9 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 14 Nov 2016 14:54:36 -0500 Subject: [PATCH 0888/1578] Revert "Revert "Add API for channel frame deferral."" This reverts commit fa749866c17f91860d3e9f89742eab3e6f03ecbc. Change-Id: Idcd1b88fa0766b1326dcc87d8905dbc314c71bd7 --- include/asterisk/channel.h | 38 +++++++++++++++++++++++++++++++ main/channel.c | 45 +++++++++++++++++++++++++++++++++++++ main/channel_internal_api.c | 6 +++++ 3 files changed, 89 insertions(+) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index ff92cc87892..e5f53f08225 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -967,6 +967,11 @@ enum { * The channel is executing a subroutine or macro */ AST_FLAG_SUBROUTINE_EXEC = (1 << 27), + /*! + * The channel is currently in an operation where + * frames should be deferred. + */ + AST_FLAG_DEFER_FRAMES = (1 << 28), }; /*! \brief ast_bridge_config flags */ @@ -4671,4 +4676,37 @@ enum ast_channel_error { */ enum ast_channel_error ast_channel_errno(void); +/*! + * \brief Retrieve the deferred read queue. + */ +struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan); + +/*! + * \brief Start deferring deferrable frames on this channel + * + * Sometimes, a channel gets entered into a mode where a "main" application + * is tasked with servicing frames on the channel, but that application does + * not need to act on those frames. However, it would be imprudent to simply + * drop important frames. This function can be called so that important frames + * will be deferred, rather than placed in the channel frame queue as normal. + * + * \pre chan MUST be locked before calling + * + * \param chan The channel on which frames should be deferred + */ +void ast_channel_start_defer_frames(struct ast_channel *chan); + +/*! + * \brief Stop deferring deferrable frames on this channel + * + * When it is time to stop deferring frames on the channel, all deferred frames + * will be queued onto the channel's read queue so that the next servicer of + * the channel can handle those frames as necessary. + * + * \pre chan MUST be locked before calling + * + * \param chan The channel on which to stop deferring frames. + */ +void ast_channel_stop_defer_frames(struct ast_channel *chan); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/main/channel.c b/main/channel.c index cdb6569c3b5..6317f6f20ca 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1062,6 +1062,25 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const return tmp; } +void ast_channel_start_defer_frames(struct ast_channel *chan) +{ + ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); +} + +void ast_channel_stop_defer_frames(struct ast_channel *chan) +{ + ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); + + /* Move the deferred frames onto the channel read queue, ahead of other queued frames */ + ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan))); + /* ast_frfree will mosey down the list and free them all */ + if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) { + ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan))); + } + /* Reset the list to be empty */ + AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan)); +} + static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after) { struct ast_frame *f; @@ -3883,6 +3902,32 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) if (!AST_LIST_EMPTY(ast_channel_readq(chan))) { int skip_dtmf = should_skip_dtmf(chan); + if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) { + AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { + if (ast_is_deferrable_frame(f)) { + if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) { + struct ast_frame *dup; + + /* Hangup is a special case. We want to defer the frame, but we also do not + * want to remove it from the frame queue. So rather than just moving the frame + * over, we duplicate it and move the copy to the deferred readq. + * + * The reason for this? This way, whoever calls ast_read() will get a NULL return + * immediately and can tell the channel has hung up and do what it needs to. Also, + * when frame deferral finishes, then whoever calls ast_read() next will also get + * the hangup. + */ + dup = ast_frdup(f); + AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); + } else { + AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list); + AST_LIST_REMOVE_CURRENT(frame_list); + } + } + } + AST_LIST_TRAVERSE_SAFE_END; + } + AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { /* We have to be picky about which frame we pull off of the readq because * there are cases where we want to leave DTMF frames on the queue until diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 1cb91e7c334..50f6c5da996 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -221,6 +221,7 @@ struct ast_channel { struct stasis_cp_single *topics; /*!< Topic for all channel's events */ struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */ struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */ + struct ast_readq_list deferred_readq; }; /*! \brief The monotonically increasing integer counter for channel uniqueids */ @@ -1681,3 +1682,8 @@ enum ast_channel_error ast_channel_internal_errno(void) return *error_code; } + +struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan) +{ + return &chan->deferred_readq; +} From f62c9c42fa8a8ca72496872c0d0065b2933e6d6b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 14 Nov 2016 14:55:13 -0500 Subject: [PATCH 0889/1578] Revert "Revert "AGI: Only defer frames when in an interception routine."" This reverts commit 6bce938c2fcb60b7a77a0e997a6518860c0bfa39. Change-Id: Iadbf462bf2a52e8b2fa9ebc75b37b1f688ba51d9 --- main/channel.c | 24 ++++++++++++++++++++++++ res/res_agi.c | 38 +------------------------------------- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/main/channel.c b/main/channel.c index 6317f6f20ca..b30bb1de792 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10283,9 +10283,15 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected); } + ast_channel_start_defer_frames(macro_chan); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); + + ast_channel_lock(macro_chan); + ast_channel_stop_defer_frames(macro_chan); + ast_channel_unlock(macro_chan); + if (!retval) { struct ast_party_connected_line saved_connected; @@ -10333,9 +10339,15 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting); } + ast_channel_start_defer_frames(macro_chan); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); + + ast_channel_lock(macro_chan); + ast_channel_stop_defer_frames(macro_chan); + ast_channel_unlock(macro_chan); + if (!retval) { struct ast_party_redirecting saved_redirecting; @@ -10376,9 +10388,15 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected); } + ast_channel_start_defer_frames(sub_chan); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); + + ast_channel_lock(sub_chan); + ast_channel_stop_defer_frames(sub_chan); + ast_channel_unlock(sub_chan); + if (!retval) { struct ast_party_connected_line saved_connected; @@ -10419,9 +10437,15 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting); } + ast_channel_start_defer_frames(sub_chan); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); + + ast_channel_lock(sub_chan); + ast_channel_stop_defer_frames(sub_chan); + ast_channel_unlock(sub_chan); + if (!retval) { struct ast_party_redirecting saved_redirecting; diff --git a/res/res_agi.c b/res/res_agi.c index 06e8a03e251..5e047d4c3dc 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -4091,23 +4091,6 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch return AGI_RESULT_SUCCESS; } -AST_LIST_HEAD_NOLOCK(deferred_frames, ast_frame); - -static void queue_deferred_frames(struct deferred_frames *deferred_frames, - struct ast_channel *chan) -{ - struct ast_frame *f; - - if (!AST_LIST_EMPTY(deferred_frames)) { - ast_channel_lock(chan); - while ((f = AST_LIST_REMOVE_HEAD(deferred_frames, frame_list))) { - ast_queue_frame_head(chan, f); - ast_frfree(f); - } - ast_channel_unlock(chan); - } -} - static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[]) { struct ast_channel *c; @@ -4126,9 +4109,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi const char *sighup_str; const char *exit_on_hangup_str; int exit_on_hangup; - struct deferred_frames deferred_frames; - - AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); ast_channel_lock(chan); sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); @@ -4190,20 +4170,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi /* Write, ignoring errors */ if (write(agi->audio, f->data.ptr, f->datalen) < 0) { } - ast_frfree(f); - } else if (ast_is_deferrable_frame(f)) { - struct ast_frame *dup_f; - - if ((dup_f = ast_frisolate(f))) { - AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); - } - - if (dup_f != f) { - ast_frfree(f); - } - } else { - ast_frfree(f); } + ast_frfree(f); } } else if (outfd > -1) { size_t len = sizeof(buf); @@ -4251,8 +4219,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi buf[buflen - 1] = '\0'; } - queue_deferred_frames(&deferred_frames, chan); - if (agidebug) ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf); cmd_status = agi_handle_command(chan, agi, buf, dead); @@ -4275,8 +4241,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi } } - queue_deferred_frames(&deferred_frames, chan); - if (agi->speech) { ast_speech_destroy(agi->speech); } From 6d61f7bfd17e3c5828fdf436cb3600dd7f944e46 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 14 Nov 2016 14:55:25 -0500 Subject: [PATCH 0890/1578] Revert "Revert "autoservice: Use frame deferral API"" This reverts commit edca6911f392f47c1a5a25d1d3a357c72b04a78a. Change-Id: I76030b87333a2c390cd05392b74b75678d78ddfa --- main/autoservice.c | 66 +++------------------------------------------- 1 file changed, 4 insertions(+), 62 deletions(-) diff --git a/main/autoservice.c b/main/autoservice.c index 11c9eab969d..c8a59a63906 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -59,10 +59,6 @@ struct asent { unsigned int use_count; unsigned int orig_end_dtmf_flag:1; unsigned int ignore_frame_types; - /*! Frames go on at the head of deferred_frames, so we have the frames - * from newest to oldest. As we put them at the head of the readq, we'll - * end up with them in the right order for the channel's readq. */ - AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; AST_LIST_ENTRY(asent) list; }; @@ -77,19 +73,13 @@ static int as_chan_list_state; static void *autoservice_run(void *ign) { ast_callid callid = 0; - struct ast_frame hangup_frame = { - .frametype = AST_FRAME_CONTROL, - .subclass.integer = AST_CONTROL_HANGUP, - }; while (!asexit) { struct ast_channel *mons[MAX_AUTOMONS]; - struct asent *ents[MAX_AUTOMONS]; struct ast_channel *chan; struct asent *as; - int i, x = 0, ms = 50; + int x = 0, ms = 50; struct ast_frame *f = NULL; - struct ast_frame *defer_frame = NULL; AST_LIST_LOCK(&aslist); @@ -104,7 +94,6 @@ static void *autoservice_run(void *ign) AST_LIST_TRAVERSE(&aslist, as, list) { if (!ast_check_hangup(as->chan)) { if (x < MAX_AUTOMONS) { - ents[x] = as; mons[x++] = as->chan; } else { ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n"); @@ -132,51 +121,9 @@ static void *autoservice_run(void *ign) ast_callid_threadassoc_change(callid); f = ast_read(chan); - - if (!f) { - /* No frame means the channel has been hung up. - * A hangup frame needs to be queued here as ast_waitfor() may - * never return again for the condition to be detected outside - * of autoservice. So, we'll leave a HANGUP queued up so the - * thread in charge of this channel will know. */ - - defer_frame = &hangup_frame; - } else if (ast_is_deferrable_frame(f)) { - defer_frame = f; - } else { - /* Can't defer. Discard and continue with next. */ + if (f) { ast_frfree(f); - continue; } - - for (i = 0; i < x; i++) { - struct ast_frame *dup_f; - - if (mons[i] != chan) { - continue; - } - - if (!f) { /* defer_frame == &hangup_frame */ - if ((dup_f = ast_frdup(defer_frame))) { - AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); - } - } else { - if ((dup_f = ast_frisolate(defer_frame))) { - AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); - } - if (dup_f != defer_frame) { - ast_frfree(defer_frame); - } - } - - break; - } - /* The ast_waitfor_n() call will only read frames from - * the channels' file descriptors. If ast_waitfor_n() - * returns non-NULL, then one of the channels in the - * mons array must have triggered the return. It's - * therefore impossible that we got here while (i >= x). - * If we did, we'd need to ast_frfree(f) if (f). */ } ast_callid_threadassoc_change(0); @@ -215,6 +162,7 @@ int ast_autoservice_start(struct ast_channel *chan) as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0; if (!as->orig_end_dtmf_flag) ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); + ast_channel_start_defer_frames(chan); ast_channel_unlock(chan); AST_LIST_LOCK(&aslist); @@ -248,7 +196,6 @@ int ast_autoservice_stop(struct ast_channel *chan) { int res = -1; struct asent *as, *removed = NULL; - struct ast_frame *f; int chan_list_state; AST_LIST_LOCK(&aslist); @@ -300,12 +247,7 @@ int ast_autoservice_stop(struct ast_channel *chan) } ast_channel_lock(chan); - while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) { - if (!((1 << f->frametype) & as->ignore_frame_types)) { - ast_queue_frame_head(chan, f); - } - ast_frfree(f); - } + ast_channel_stop_defer_frames(chan); ast_channel_unlock(chan); ast_free(as); From 0dc456713358d943104bcde35b85e44673d401a3 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 14 Nov 2016 14:55:45 -0500 Subject: [PATCH 0891/1578] Revert "Revert "channel: Use frame deferral API for safe sleep."" This reverts commit e5365dada5052b87275c048f6e29ac7d5e2b2415. Change-Id: Icc40cf0c7687454760762912dd29e4ae79e8e9ee --- main/channel.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/main/channel.c b/main/channel.c index b30bb1de792..872661c5a9d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1544,19 +1544,18 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c int res = 0; struct timeval start; int ms; - AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; - - AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); /* If no other generator is present, start silencegen while waiting */ if (ast_opt_transmit_silence && !ast_channel_generatordata(chan)) { silgen = ast_channel_start_silence_generator(chan); } + ast_channel_lock(chan); + ast_channel_start_defer_frames(chan); + ast_channel_unlock(chan); + start = ast_tvnow(); while ((ms = ast_remaining_ms(start, timeout_ms))) { - struct ast_frame *dup_f = NULL; - if (cond && ((*cond)(data) == 0)) { break; } @@ -1571,18 +1570,7 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c res = -1; break; } - - if (!ast_is_deferrable_frame(f)) { - ast_frfree(f); - continue; - } - - if ((dup_f = ast_frisolate(f))) { - if (dup_f != f) { - ast_frfree(f); - } - AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); - } + ast_frfree(f); } } @@ -1591,17 +1579,8 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c ast_channel_stop_silence_generator(chan, silgen); } - /* We need to free all the deferred frames, but we only need to - * queue the deferred frames if there was no error and no - * hangup was received - */ ast_channel_lock(chan); - while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { - if (!res) { - ast_queue_frame_head(chan, f); - } - ast_frfree(f); - } + ast_channel_stop_defer_frames(chan); ast_channel_unlock(chan); return res; From 7263a17ca046923c245296a3cee21df0e4bd499a Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 14 Nov 2016 13:03:46 -0700 Subject: [PATCH 0892/1578] channel: Fix issues in hangup scenarios caused by frame deferral ASTERISK-26343 Change-Id: I06dbf7366e26028251964143454a77d017bb61c8 (cherry picked from commit 0be46aaf6b8b9eb5b0160ec591cdc2c6e1802a6d) --- include/asterisk/channel.h | 13 ++++++++++++- main/autoservice.c | 2 +- main/channel.c | 27 ++++++++++++++++----------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index e5f53f08225..9150cbbbb31 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -972,6 +972,11 @@ enum { * frames should be deferred. */ AST_FLAG_DEFER_FRAMES = (1 << 28), + /*! + * The channel is currently deferring hangup frames + * in addition to other frame types. + */ + AST_FLAG_DEFER_HANGUP_FRAMES = (1 << 29), }; /*! \brief ast_bridge_config flags */ @@ -4690,11 +4695,17 @@ struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan); * drop important frames. This function can be called so that important frames * will be deferred, rather than placed in the channel frame queue as normal. * + * Hangups are an interesting frame type. Hangups will always be detectable by + * a reader when a channel is deferring frames. If the defer_hangups parameter + * is non-zero, then the hangup frame will also be duplicated and deferred, so + * that the next reader of the channel will get the hangup frame, too. + * * \pre chan MUST be locked before calling * * \param chan The channel on which frames should be deferred + * \param defer_hangups Defer hangups in addition to other deferrable frames */ -void ast_channel_start_defer_frames(struct ast_channel *chan); +void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups); /*! * \brief Stop deferring deferrable frames on this channel diff --git a/main/autoservice.c b/main/autoservice.c index c8a59a63906..c3f24276c0e 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -162,7 +162,7 @@ int ast_autoservice_start(struct ast_channel *chan) as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0; if (!as->orig_end_dtmf_flag) ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); - ast_channel_start_defer_frames(chan); + ast_channel_start_defer_frames(chan, 1); ast_channel_unlock(chan); AST_LIST_LOCK(&aslist); diff --git a/main/channel.c b/main/channel.c index 872661c5a9d..297827893b5 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1062,9 +1062,10 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const return tmp; } -void ast_channel_start_defer_frames(struct ast_channel *chan) +void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups) { ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); + ast_set2_flag(ast_channel_flags(chan), defer_hangups, AST_FLAG_DEFER_HANGUP_FRAMES); } void ast_channel_stop_defer_frames(struct ast_channel *chan) @@ -1551,7 +1552,7 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c } ast_channel_lock(chan); - ast_channel_start_defer_frames(chan); + ast_channel_start_defer_frames(chan, 0); ast_channel_unlock(chan); start = ast_tvnow(); @@ -3884,9 +3885,9 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) { AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { if (ast_is_deferrable_frame(f)) { - if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) { - struct ast_frame *dup; - + if(f->frametype == AST_FRAME_CONTROL && + (f->subclass.integer == AST_CONTROL_HANGUP || + f->subclass.integer == AST_CONTROL_END_OF_Q)) { /* Hangup is a special case. We want to defer the frame, but we also do not * want to remove it from the frame queue. So rather than just moving the frame * over, we duplicate it and move the copy to the deferred readq. @@ -3896,8 +3897,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) * when frame deferral finishes, then whoever calls ast_read() next will also get * the hangup. */ - dup = ast_frdup(f); - AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); + if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_HANGUP_FRAMES)) { + struct ast_frame *dup; + + dup = ast_frdup(f); + AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); + } } else { AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list); AST_LIST_REMOVE_CURRENT(frame_list); @@ -10262,7 +10267,7 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected); } - ast_channel_start_defer_frames(macro_chan); + ast_channel_start_defer_frames(macro_chan, 0); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); @@ -10318,7 +10323,7 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting); } - ast_channel_start_defer_frames(macro_chan); + ast_channel_start_defer_frames(macro_chan, 0); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); @@ -10367,7 +10372,7 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected); } - ast_channel_start_defer_frames(sub_chan); + ast_channel_start_defer_frames(sub_chan, 0); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); @@ -10416,7 +10421,7 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting); } - ast_channel_start_defer_frames(sub_chan); + ast_channel_start_defer_frames(sub_chan, 0); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); From a72ef381135639c62d97b9f6b1964403c9c92b78 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 8 Nov 2016 10:11:41 -0600 Subject: [PATCH 0893/1578] res/ari/resource_bridges: Add the ability to manipulate the video source In multi-party bridges, Asterisk currently supports two video modes: * Follow the talker, in which the speaker with the most energy is shown to all participants but the speaker, and the speaker sees the previous video source * Explicitly set video sources, in which all participants see a locked video source Prior to this patch, ARI had no ability to manipulate the video source. This isn't important for two-party bridges, in which Asterisk merely relays the video between the participants. However, in a multi-party bridge, it can be advantageous to allow an external application to manipulate the video source. This patch provides two new routes to accomplish this: (1) setVideoSource: POST /bridges/{bridgeId}/videoSource/{channelId} Sets a video source to an explicit channel (2) clearVideoSource: DELETE /bridges/{bridgeId}/videoSource Removes any explicit video source, and sets the video mode to talk detection ASTERISK-26595 #close Change-Id: I98e455d5bffc08ea5e8d6b84ccaf063c714e6621 --- CHANGES | 31 +++++++ doc/appdocsxml.xslt | 20 ++++ include/asterisk/bridge.h | 9 ++ include/asterisk/stasis_bridges.h | 4 + main/bridge.c | 22 +++-- main/manager_bridges.c | 52 ++++++++++- main/stasis_bridges.c | 29 +++++- res/ari/ari_model_validators.c | 121 +++++++++++++++++++++++++ res/ari/ari_model_validators.h | 27 ++++++ res/ari/resource_bridges.c | 66 ++++++++++++++ res/ari/resource_bridges.h | 28 ++++++ res/res_ari_bridges.c | 146 +++++++++++++++++++++++++++++- res/stasis/app.c | 7 ++ rest-api/api-docs/bridges.json | 82 +++++++++++++++++ rest-api/api-docs/events.json | 15 +++ 15 files changed, 645 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index a57ed88e3ab..ccd07f68ba5 100644 --- a/CHANGES +++ b/CHANGES @@ -62,6 +62,37 @@ RTP --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ---------- ------------------------------------------------------------------------------ +AMI +------------------ + * Events that reference a bridge may now contain two new optional fields: + - 'BridgeVideoSourceMode': the video source mode for the bridge. + Can be one of 'none', 'talker', or 'single'. + - 'BridgeVideoSource': the unique ID of the channel that is the video + source in this bridge, if one exists. + + * A new event, BridgeVideoSourceUpdate, has been added with a class + authorization of CALL. The event is raised when the video source changes + in a multi-party mixing bridge. + +ARI +------------------ + * The bridges resource now exposes two new operations: + - POST /bridges/{bridgeId}/videoSource/{channelId}: Set a video source in a + multi-party mixing bridge + - DELETE /bridges/{bridgeId}/videoSource: Remove the set video source, + reverting to talk detection for the video source + + * The bridge model in any returned response or event now contains the following + optional fields: + - video_mode: the video source mode for the bridge. Can be one of 'none', + 'talker', or 'single'. + - video_source_id: the unique ID of the channel that is the video source + in this bridge, if one exists. + + * A new event, BridgeVideoSourceChanged, has been added for bridges. + Applications subscribed to a bridge will receive this event when the source + of video changes in a mixing bridge. + res_pjsip ------------------ * Automatic dual stack support is now implemented. Depending on DNS resolution diff --git a/doc/appdocsxml.xslt b/doc/appdocsxml.xslt index f067decaef2..511011ae8c5 100644 --- a/doc/appdocsxml.xslt +++ b/doc/appdocsxml.xslt @@ -145,5 +145,25 @@ Number of channels in the bridge + + + + + + + + + + The video source mode for the bridge. + + + + false + + + + + If there is a video source for the bridge, the unique ID of the channel that is the video source. + diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index acea2f01fbb..61cecbdd644 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -903,6 +903,15 @@ int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan) */ void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan); +/*! + * \brief Converts an enum representation of a bridge video mode to string + * + * \param video_mode The video mode + * + * \retval A string representation of \c video_mode + */ +const char *ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type video_mode); + enum ast_transfer_result { /*! The transfer completed successfully */ AST_BRIDGE_TRANSFER_SUCCESS, diff --git a/include/asterisk/stasis_bridges.h b/include/asterisk/stasis_bridges.h index d549e462022..05d356cc2c1 100644 --- a/include/asterisk/stasis_bridges.h +++ b/include/asterisk/stasis_bridges.h @@ -58,6 +58,10 @@ struct ast_bridge_snapshot { unsigned int num_channels; /*! Number of active channels in the bridge. */ unsigned int num_active; + /*! The video mode of the bridge */ + enum ast_bridge_video_mode_type video_mode; + /*! Unique ID of the channel providing video, if one exists */ + AST_STRING_FIELD_EXTENDED(video_source_id); }; /*! diff --git a/main/bridge.c b/main/bridge.c index 1bb60eb7a0f..13c01fa2735 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -3774,8 +3774,7 @@ void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_ bridge->name, bridge->uniqueid, ast_channel_name(video_src_chan), ast_channel_uniqueid(video_src_chan)); - ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to single source\r\nVideo Mode: %u\r\nVideo Channel: %s", - bridge->softmix.video_mode.mode, ast_channel_name(video_src_chan)); + ast_bridge_publish_state(bridge); ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE); ast_bridge_unlock(bridge); } @@ -3785,8 +3784,6 @@ void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge) ast_bridge_lock(bridge); cleanup_video_mode(bridge); bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_TALKER_SRC; - ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to talker source\r\nVideo Mode: %u", - bridge->softmix.video_mode.mode); ast_bridge_unlock(bridge); } @@ -3818,7 +3815,7 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a bridge->name, bridge->uniqueid, ast_channel_name(data->chan_vsrc), ast_channel_uniqueid(data->chan_vsrc)); - ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc)); + ast_bridge_publish_state(bridge); ast_indicate(data->chan_vsrc, AST_CONTROL_VIDUPDATE); } else if ((data->average_talking_energy < talker_energy) && !is_keyframe) { ast_indicate(chan, AST_CONTROL_VIDUPDATE); @@ -3829,7 +3826,7 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a bridge->name, bridge->uniqueid, ast_channel_name(data->chan_vsrc), ast_channel_uniqueid(data->chan_vsrc)); - ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc)); + ast_bridge_publish_state(bridge); ast_indicate(chan, AST_CONTROL_VIDUPDATE); } else if (!data->chan_old_vsrc && is_keyframe) { data->chan_old_vsrc = ast_channel_ref(chan); @@ -3920,6 +3917,19 @@ void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel * ast_bridge_unlock(bridge); } +const char *ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type video_mode) +{ + switch (video_mode) { + case AST_BRIDGE_VIDEO_MODE_TALKER_SRC: + return "talker"; + case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC: + return "single"; + case AST_BRIDGE_VIDEO_MODE_NONE: + default: + return "none"; + } +} + static int channel_hash(const void *obj, int flags) { const struct ast_channel *chan = obj; diff --git a/main/manager_bridges.c b/main/manager_bridges.c index c6e997f42c7..b7059f40c8c 100644 --- a/main/manager_bridges.c +++ b/main/manager_bridges.c @@ -91,6 +91,21 @@ static struct stasis_message_router *bridge_state_router; + + + Raised when the channel that is the source of video in a bridge changes. + + + + The unique ID of the channel that was the video source. + + + + BridgeCreate + BridgeDestroy + + + Get a list of bridges in the system. @@ -222,18 +237,30 @@ struct ast_str *ast_manager_build_bridge_state_string_prefix( "%sBridgeTechnology: %s\r\n" "%sBridgeCreator: %s\r\n" "%sBridgeName: %s\r\n" - "%sBridgeNumChannels: %u\r\n", + "%sBridgeNumChannels: %u\r\n" + "%sBridgeVideoSourceMode: %s\r\n", prefix, snapshot->uniqueid, prefix, snapshot->subclass, prefix, snapshot->technology, prefix, ast_strlen_zero(snapshot->creator) ? "": snapshot->creator, prefix, ast_strlen_zero(snapshot->name) ? "": snapshot->name, - prefix, snapshot->num_channels); + prefix, snapshot->num_channels, + prefix, ast_bridge_video_mode_to_string(snapshot->video_mode)); if (!res) { ast_free(out); return NULL; } + if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE + && !ast_strlen_zero(snapshot->video_source_id)) { + res = ast_str_append(&out, 0, "%sBridgeVideoSource: %s\r\n", + prefix, snapshot->video_source_id); + if (!res) { + ast_free(out); + return NULL; + } + } + return out; } @@ -261,6 +288,25 @@ static struct ast_manager_event_blob *bridge_create( EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS); } +/* \brief Handle video source updates */ +static struct ast_manager_event_blob *bridge_video_update( + struct ast_bridge_snapshot *old_snapshot, + struct ast_bridge_snapshot *new_snapshot) +{ + if (!new_snapshot || !old_snapshot) { + return NULL; + } + + if (!strcmp(old_snapshot->video_source_id, new_snapshot->video_source_id)) { + return NULL; + } + + return ast_manager_event_blob_create( + EVENT_FLAG_CALL, "BridgeVideoSourceUpdate", + "BridgePreviousVideoSource: %s\r\n", + old_snapshot->video_source_id); +} + /*! \brief Handle bridge destruction */ static struct ast_manager_event_blob *bridge_destroy( struct ast_bridge_snapshot *old_snapshot, @@ -274,9 +320,9 @@ static struct ast_manager_event_blob *bridge_destroy( EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS); } - bridge_snapshot_monitor bridge_monitors[] = { bridge_create, + bridge_video_update, bridge_destroy, }; diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c index 43722b90ba6..7f53bfe2da4 100644 --- a/main/stasis_bridges.c +++ b/main/stasis_bridges.c @@ -242,7 +242,13 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge snapshot = ao2_alloc_options(sizeof(*snapshot), bridge_snapshot_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); - if (!snapshot || ast_string_field_init(snapshot, 128)) { + if (!snapshot) { + return NULL; + } + + if (ast_string_field_init(snapshot, 128) + || ast_string_field_init_extended(snapshot, video_source_id)) { + ao2_ref(snapshot, -1); return NULL; } @@ -268,6 +274,16 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge snapshot->capabilities = bridge->technology->capabilities; snapshot->num_channels = bridge->num_channels; snapshot->num_active = bridge->num_active; + snapshot->video_mode = bridge->softmix.video_mode.mode; + if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_SINGLE_SRC + && bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc) { + ast_string_field_set(snapshot, video_source_id, + ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc)); + } else if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC + && bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc) { + ast_string_field_set(snapshot, video_source_id, + ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc)); + } ao2_ref(snapshot, +1); return snapshot; @@ -590,18 +606,25 @@ struct ast_json *ast_bridge_snapshot_to_json( return NULL; } - json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o}", + json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o, s: s}", "id", snapshot->uniqueid, "technology", snapshot->technology, "bridge_type", capability2str(snapshot->capabilities), "bridge_class", snapshot->subclass, "creator", snapshot->creator, "name", snapshot->name, - "channels", json_channels); + "channels", json_channels, + "video_mode", ast_bridge_video_mode_to_string(snapshot->video_mode)); if (!json_bridge) { return NULL; } + if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE + && !ast_strlen_zero(snapshot->video_source_id)) { + ast_json_object_set(json_bridge, "video_source_id", + ast_json_string_create(snapshot->video_source_id)); + } + return ast_json_ref(json_bridge); } diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index 03cd3a2386b..939e0fe4d70 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -1358,6 +1358,24 @@ int ast_ari_validate_bridge(struct ast_json *json) res = 0; } } else + if (strcmp("video_mode", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Bridge field video_mode failed validation\n"); + res = 0; + } + } else + if (strcmp("video_source_id", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Bridge field video_source_id failed validation\n"); + res = 0; + } + } else { ast_log(LOG_ERROR, "ARI Bridge has undocumented field %s\n", @@ -2713,6 +2731,103 @@ ari_validator ast_ari_validate_bridge_merged_fn(void) return ast_ari_validate_bridge_merged; } +int ast_ari_validate_bridge_video_source_changed(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_type = 0; + int has_application = 0; + int has_bridge = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("asterisk_id", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged field asterisk_id failed validation\n"); + res = 0; + } + } else + if (strcmp("type", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_type = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged field type failed validation\n"); + res = 0; + } + } else + if (strcmp("application", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_application = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged field application failed validation\n"); + res = 0; + } + } else + if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_date( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged field timestamp failed validation\n"); + res = 0; + } + } else + if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_bridge = 1; + prop_is_valid = ast_ari_validate_bridge( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged field bridge failed validation\n"); + res = 0; + } + } else + if (strcmp("old_video_source_id", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged field old_video_source_id failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI BridgeVideoSourceChanged has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_type) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged missing required field type\n"); + res = 0; + } + + if (!has_application) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged missing required field application\n"); + res = 0; + } + + if (!has_bridge) { + ast_log(LOG_ERROR, "ARI BridgeVideoSourceChanged missing required field bridge\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_bridge_video_source_changed_fn(void) +{ + return ast_ari_validate_bridge_video_source_changed; +} + int ast_ari_validate_channel_caller_id(struct ast_json *json) { int res = 1; @@ -4919,6 +5034,9 @@ int ast_ari_validate_event(struct ast_json *json) if (strcmp("BridgeMerged", discriminator) == 0) { return ast_ari_validate_bridge_merged(json); } else + if (strcmp("BridgeVideoSourceChanged", discriminator) == 0) { + return ast_ari_validate_bridge_video_source_changed(json); + } else if (strcmp("ChannelCallerId", discriminator) == 0) { return ast_ari_validate_channel_caller_id(json); } else @@ -5114,6 +5232,9 @@ int ast_ari_validate_message(struct ast_json *json) if (strcmp("BridgeMerged", discriminator) == 0) { return ast_ari_validate_bridge_merged(json); } else + if (strcmp("BridgeVideoSourceChanged", discriminator) == 0) { + return ast_ari_validate_bridge_video_source_changed(json); + } else if (strcmp("ChannelCallerId", discriminator) == 0) { return ast_ari_validate_channel_caller_id(json); } else diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index 0b08ce85e5a..a62bdf22cd7 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -716,6 +716,24 @@ int ast_ari_validate_bridge_merged(struct ast_json *json); */ ari_validator ast_ari_validate_bridge_merged_fn(void); +/*! + * \brief Validator for BridgeVideoSourceChanged. + * + * Notification that the source of video in a bridge has changed. + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_bridge_video_source_changed(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_bridge_video_source_changed(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_bridge_video_source_changed_fn(void); + /*! * \brief Validator for ChannelCallerId. * @@ -1452,6 +1470,8 @@ ari_validator ast_ari_validate_application_fn(void); * - id: string (required) * - name: string (required) * - technology: string (required) + * - video_mode: string + * - video_source_id: string * LiveRecording * - cause: string * - duration: int @@ -1543,6 +1563,13 @@ ari_validator ast_ari_validate_application_fn(void); * - timestamp: Date * - bridge: Bridge (required) * - bridge_from: Bridge (required) + * BridgeVideoSourceChanged + * - asterisk_id: string + * - type: string (required) + * - application: string (required) + * - timestamp: Date + * - bridge: Bridge (required) + * - old_video_source_id: string * ChannelCallerId * - asterisk_id: string * - type: string (required) diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index f5ae1c003ac..f243086c978 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -35,6 +35,7 @@ #include "asterisk/stasis.h" #include "asterisk/stasis_bridges.h" #include "asterisk/stasis_app.h" +#include "asterisk/stasis_app_impl.h" #include "asterisk/stasis_app_playback.h" #include "asterisk/stasis_app_recording.h" #include "asterisk/stasis_channels.h" @@ -1003,3 +1004,68 @@ void ast_ari_bridges_create_with_id(struct ast_variable *headers, ast_ari_response_ok(response, ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer())); } + +static int bridge_set_video_source_cb(struct stasis_app_control *control, + struct ast_channel *chan, void *data) +{ + struct ast_bridge *bridge = data; + + ast_bridge_lock(bridge); + ast_bridge_set_single_src_video_mode(bridge, chan); + ast_bridge_unlock(bridge); + + return 0; +} + +void ast_ari_bridges_set_video_source(struct ast_variable *headers, + struct ast_ari_bridges_set_video_source_args *args, struct ast_ari_response *response) +{ + struct ast_bridge *bridge; + struct stasis_app_control *control; + + bridge = find_bridge(response, args->bridge_id); + if (!bridge) { + return; + } + + control = find_channel_control(response, args->channel_id); + if (!control) { + ao2_ref(bridge, -1); + return; + } + + if (stasis_app_get_bridge(control) != bridge) { + ast_ari_response_error(response, 422, + "Unprocessable Entity", + "Channel not in this bridge"); + ao2_ref(bridge, -1); + ao2_ref(control, -1); + return; + } + + stasis_app_send_command(control, bridge_set_video_source_cb, + ao2_bump(bridge), __ao2_cleanup); + + ao2_ref(bridge, -1); + ao2_ref(control, -1); + + ast_ari_response_no_content(response); +} + +void ast_ari_bridges_clear_video_source(struct ast_variable *headers, + struct ast_ari_bridges_clear_video_source_args *args, struct ast_ari_response *response) +{ + struct ast_bridge *bridge; + + bridge = find_bridge(response, args->bridge_id); + if (!bridge) { + return; + } + + ast_bridge_lock(bridge); + ast_bridge_set_talker_src_video_mode(bridge); + ast_bridge_unlock(bridge); + + ao2_ref(bridge, -1); + ast_ari_response_no_content(response); +} diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h index 17a3b8365f0..e75d8e02873 100644 --- a/res/ari/resource_bridges.h +++ b/res/ari/resource_bridges.h @@ -200,6 +200,34 @@ int ast_ari_bridges_remove_channel_parse_body( * \param[out] response HTTP response */ void ast_ari_bridges_remove_channel(struct ast_variable *headers, struct ast_ari_bridges_remove_channel_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_bridges_set_video_source() */ +struct ast_ari_bridges_set_video_source_args { + /*! Bridge's id */ + const char *bridge_id; + /*! Channel's id */ + const char *channel_id; +}; +/*! + * \brief Set a channel as the video source in a multi-party mixing bridge. This operation has no effect on bridges with two or fewer participants. + * + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_bridges_set_video_source(struct ast_variable *headers, struct ast_ari_bridges_set_video_source_args *args, struct ast_ari_response *response); +/*! Argument struct for ast_ari_bridges_clear_video_source() */ +struct ast_ari_bridges_clear_video_source_args { + /*! Bridge's id */ + const char *bridge_id; +}; +/*! + * \brief Removes any explicit video source in a multi-party mixing bridge. This operation has no effect on bridges with two or fewer participants. When no explicit video source is set, talk detection will be used to determine the active video stream. + * + * \param headers HTTP headers + * \param args Swagger parameters + * \param[out] response HTTP response + */ +void ast_ari_bridges_clear_video_source(struct ast_variable *headers, struct ast_ari_bridges_clear_video_source_args *args, struct ast_ari_response *response); /*! Argument struct for ast_ari_bridges_start_moh() */ struct ast_ari_bridges_start_moh_args { /*! Bridge's id */ diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 29fb07582de..0b370c299f6 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -767,6 +767,129 @@ fin: __attribute__((unused)) ast_free(args.channel); return; } +/*! + * \brief Parameter parsing callback for /bridges/{bridgeId}/videoSource/{channelId}. + * \param get_params GET parameters in the HTTP request. + * \param path_vars Path variables extracted from the request. + * \param headers HTTP headers. + * \param[out] response Response to the HTTP request. + */ +static void ast_ari_bridges_set_video_source_cb( + struct ast_tcptls_session_instance *ser, + struct ast_variable *get_params, struct ast_variable *path_vars, + struct ast_variable *headers, struct ast_ari_response *response) +{ + struct ast_ari_bridges_set_video_source_args args = {}; + struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); +#if defined(AST_DEVMODE) + int is_valid; + int code; +#endif /* AST_DEVMODE */ + + for (i = path_vars; i; i = i->next) { + if (strcmp(i->name, "bridgeId") == 0) { + args.bridge_id = (i->value); + } else + if (strcmp(i->name, "channelId") == 0) { + args.channel_id = (i->value); + } else + {} + } + ast_ari_bridges_set_video_source(headers, &args, response); +#if defined(AST_DEVMODE) + code = response->response_code; + + switch (code) { + case 0: /* Implementation is still a stub, or the code wasn't set */ + is_valid = response->message == NULL; + break; + case 500: /* Internal Server Error */ + case 501: /* Not Implemented */ + case 404: /* Bridge or Channel not found */ + case 409: /* Channel not in Stasis application */ + case 422: /* Channel not in this Bridge */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + is_valid = ast_ari_validate_void( + response->message); + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/videoSource/{channelId}\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/videoSource/{channelId}\n"); + ast_ari_response_error(response, 500, + "Internal Server Error", "Response validation failed"); + } +#endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; +} +/*! + * \brief Parameter parsing callback for /bridges/{bridgeId}/videoSource. + * \param get_params GET parameters in the HTTP request. + * \param path_vars Path variables extracted from the request. + * \param headers HTTP headers. + * \param[out] response Response to the HTTP request. + */ +static void ast_ari_bridges_clear_video_source_cb( + struct ast_tcptls_session_instance *ser, + struct ast_variable *get_params, struct ast_variable *path_vars, + struct ast_variable *headers, struct ast_ari_response *response) +{ + struct ast_ari_bridges_clear_video_source_args args = {}; + struct ast_variable *i; + RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); +#if defined(AST_DEVMODE) + int is_valid; + int code; +#endif /* AST_DEVMODE */ + + for (i = path_vars; i; i = i->next) { + if (strcmp(i->name, "bridgeId") == 0) { + args.bridge_id = (i->value); + } else + {} + } + ast_ari_bridges_clear_video_source(headers, &args, response); +#if defined(AST_DEVMODE) + code = response->response_code; + + switch (code) { + case 0: /* Implementation is still a stub, or the code wasn't set */ + is_valid = response->message == NULL; + break; + case 500: /* Internal Server Error */ + case 501: /* Not Implemented */ + case 404: /* Bridge not found */ + is_valid = 1; + break; + default: + if (200 <= code && code <= 299) { + is_valid = ast_ari_validate_void( + response->message); + } else { + ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/videoSource\n", code); + is_valid = 0; + } + } + + if (!is_valid) { + ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/videoSource\n"); + ast_ari_response_error(response, 500, + "Internal Server Error", "Response validation failed"); + } +#endif /* AST_DEVMODE */ + +fin: __attribute__((unused)) + return; +} int ast_ari_bridges_start_moh_parse_body( struct ast_json *body, struct ast_ari_bridges_start_moh_args *args) @@ -1469,6 +1592,25 @@ static struct stasis_rest_handlers bridges_bridgeId_removeChannel = { .children = { } }; /*! \brief REST handler for /api-docs/bridges.json */ +static struct stasis_rest_handlers bridges_bridgeId_videoSource_channelId = { + .path_segment = "channelId", + .is_wildcard = 1, + .callbacks = { + [AST_HTTP_POST] = ast_ari_bridges_set_video_source_cb, + }, + .num_children = 0, + .children = { } +}; +/*! \brief REST handler for /api-docs/bridges.json */ +static struct stasis_rest_handlers bridges_bridgeId_videoSource = { + .path_segment = "videoSource", + .callbacks = { + [AST_HTTP_DELETE] = ast_ari_bridges_clear_video_source_cb, + }, + .num_children = 1, + .children = { &bridges_bridgeId_videoSource_channelId, } +}; +/*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges_bridgeId_moh = { .path_segment = "moh", .callbacks = { @@ -1515,8 +1657,8 @@ static struct stasis_rest_handlers bridges_bridgeId = { [AST_HTTP_GET] = ast_ari_bridges_get_cb, [AST_HTTP_DELETE] = ast_ari_bridges_destroy_cb, }, - .num_children = 5, - .children = { &bridges_bridgeId_addChannel,&bridges_bridgeId_removeChannel,&bridges_bridgeId_moh,&bridges_bridgeId_play,&bridges_bridgeId_record, } + .num_children = 6, + .children = { &bridges_bridgeId_addChannel,&bridges_bridgeId_removeChannel,&bridges_bridgeId_videoSource,&bridges_bridgeId_moh,&bridges_bridgeId_play,&bridges_bridgeId_record, } }; /*! \brief REST handler for /api-docs/bridges.json */ static struct stasis_rest_handlers bridges = { diff --git a/res/stasis/app.c b/res/stasis/app.c index ac316fac07a..0b75ed5d72e 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -698,6 +698,13 @@ static void sub_bridge_update_handler(void *data, json = simple_bridge_event("BridgeDestroyed", old_snapshot, tv); } else if (!old_snapshot) { json = simple_bridge_event("BridgeCreated", new_snapshot, tv); + } else if (new_snapshot && old_snapshot + && strcmp(new_snapshot->video_source_id, old_snapshot->video_source_id)) { + json = simple_bridge_event("BridgeVideoSourceChanged", new_snapshot, tv); + if (json && !ast_strlen_zero(old_snapshot->video_source_id)) { + ast_json_object_set(json, "old_video_source_id", + ast_json_string_create(old_snapshot->video_source_id)); + } } if (json) { diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json index ab2c6c2d545..8289b43e1a2 100644 --- a/rest-api/api-docs/bridges.json +++ b/rest-api/api-docs/bridges.json @@ -240,6 +240,78 @@ } ] }, + { + "path": "/bridges/{bridgeId}/videoSource/{channelId}", + "description": "Set a channel as the video source in a multi-party bridge", + "operations": [ + { + "httpMethod": "POST", + "summary": "Set a channel as the video source in a multi-party mixing bridge. This operation has no effect on bridges with two or fewer participants.", + "nickname": "setVideoSource", + "responseClass": "void", + "parameters": [ + { + "name": "bridgeId", + "description": "Bridge's id", + "paramType": "path", + "required": true, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "channelId", + "description": "Channel's id", + "paramType": "path", + "required": true, + "allowMultiple": false, + "dataType": "string" + } + ], + "errorResponses": [ + { + "code": 404, + "reason": "Bridge or Channel not found" + }, + { + "code": 409, + "reason": "Channel not in Stasis application" + }, + { + "code": 422, + "reason": "Channel not in this Bridge" + } + ] + } + ] + }, + { + "path": "/bridges/{bridgeId}/videoSource", + "description": "Removes any explicit video source", + "operations": [ + { + "httpMethod": "DELETE", + "summary": "Removes any explicit video source in a multi-party mixing bridge. This operation has no effect on bridges with two or fewer participants. When no explicit video source is set, talk detection will be used to determine the active video stream.", + "nickname": "clearVideoSource", + "responseClass": "void", + "parameters": [ + { + "name": "bridgeId", + "description": "Bridge's id", + "paramType": "path", + "required": true, + "allowMultiple": false, + "dataType": "string" + } + ], + "errorResponses": [ + { + "code": 404, + "reason": "Bridge not found" + } + ] + } + ] + }, { "path": "/bridges/{bridgeId}/moh", "description": "Play music on hold to a bridge", @@ -649,6 +721,16 @@ "type": "List[string]", "description": "Ids of channels participating in this bridge", "required": true + }, + "video_mode": { + "type": "string", + "description": "The video mode the bridge is using. One of 'none', 'talker', or 'single'.", + "required": false + }, + "video_source_id": { + "type": "string", + "description": "The ID of the channel that is the source of video in this bridge, if one exists.", + "required": false } } } diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json index 4ef1d21a49a..f99f52e67be 100644 --- a/rest-api/api-docs/events.json +++ b/rest-api/api-docs/events.json @@ -162,6 +162,7 @@ "BridgeMerged", "BridgeBlindTransfer", "BridgeAttendedTransfer", + "BridgeVideoSourceChanged", "ChannelCreated", "ChannelDestroyed", "ChannelEnteredBridge", @@ -370,6 +371,20 @@ } } }, + "BridgeVideoSourceChanged": { + "id": "BridgeVideoSourceChanged", + "description": "Notification that the source of video in a bridge has changed.", + "properties": { + "bridge": { + "required": true, + "type": "Bridge" + }, + "old_video_source_id": { + "required": false, + "type": "string" + } + } + }, "BridgeBlindTransfer": { "id": "BridgeBlindTransfer", "description": "Notification that a blind transfer has occurred.", From cc86329228a9e27add4d9962b43d37ac745abca8 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 14 Nov 2016 15:32:14 -0600 Subject: [PATCH 0894/1578] apps/app_echo: Only relay a single video source change frame In 9785e8d0, app_echo was updated to relay video source updates to the channel for the purposes of displaying video in WebRTC tests. Unfortunately, this can cause a Kafkaesque nightmare if two or more Local channels are in a bridge together where their ends are in app_echo. When this situation occurs, a video update sent into app_echo will cause the video update to be relayed to the other Local channels, causing another round of video updates, etc. In not much time at all, the channel length queues will be overwhelmed, channel alert pipes will fail, and all hell will break loose as Asterisk merrily continues to throw more video update requests onto the channels. This patch updates app_echo to *only* relay a single video update. Once a video update has been made, all further video updates are dropped. This meets the intended purpose of the original patch: if we get a video update and we're in app_echo, go ahead and ask the sender to update themselves. However, once we've got that video stream sync'd up, don't keep spamming the world. Change-Id: I9210780b08d4c17ddb38599d1c64453adfc34f74 --- apps/app_echo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/app_echo.c b/apps/app_echo.c index 0f4c94b8d1f..e50173af8bd 100644 --- a/apps/app_echo.c +++ b/apps/app_echo.c @@ -66,7 +66,8 @@ static int echo_exec(struct ast_channel *chan, const char *data) f->delivery.tv_sec = 0; f->delivery.tv_usec = 0; if (f->frametype == AST_FRAME_CONTROL - && f->subclass.integer == AST_CONTROL_VIDUPDATE) { + && f->subclass.integer == AST_CONTROL_VIDUPDATE + && !fir_sent) { if (ast_write(chan, f) < 0) { ast_frfree(f); goto end; From edd7ae85e8adfe18b401fbb0e975f389f02d88fd Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 14 Nov 2016 15:57:08 -0600 Subject: [PATCH 0895/1578] pjproject: Use a much higher limit for PJ_ICE_MAX_CHECKS The PJ_ICE_MAX_CHECKS constant is used by pjproject to determine how many pairs of local/remote candidates will be made. If for some reason we reach this upper bound, ICE will generally fail and no media will flow between the browser and Asterisk. This patch makes PJ_ICE_MAX_CHECKS set to the total possible number of pairs of candidates we'd theoretically allow, which is PJ_ICE_MAX_CAND^2. Prior to this patch, we simply multiplied PJ_ICE_MAX_CAND by two; on systems with multiple interfaces (I blame Docker), this is far too low to allow WebRTC calls to succeed. Setting this to be PJ_ICE_MAX_CAND^2 allowed WebRTC calls to succeed even when the system Asterisk was running on had quite a few virtual interfaces. Change-Id: Icd4f17de0ac9d3a83dddfc8bf1cb7616bc107d55 --- third-party/pjproject/patches/config_site.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 564959d84c4..1a48695bfb2 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -56,7 +56,7 @@ /* Defaults too low for WebRTC */ #define PJ_ICE_MAX_CAND 32 -#define PJ_ICE_MAX_CHECKS (PJ_ICE_MAX_CAND * 2) +#define PJ_ICE_MAX_CHECKS (PJ_ICE_MAX_CAND * PJ_ICE_MAX_CAND) /* Increase limits to allow more formats */ #define PJMEDIA_MAX_SDP_FMT 64 From d3b61a98f4041657d2b59aceb23533ae5bd6f133 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 15 Nov 2016 14:07:03 +0000 Subject: [PATCH 0896/1578] manager: Bump AMI version number. During the development of Asterisk 14 the behavior of the Command AMI action was altered such that the result was returned on lines with a prefix of "Output: ". While this was documented in the UPGRADE.txt file it is also reasonable that this should bump the AMI version number. ASTERISK-26556 Change-Id: Idf1bf01608e53f7bfdf43ddb4d0683e53f74ee42 --- include/asterisk/manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 1ec1cbae304..43897489d95 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -54,7 +54,7 @@ - \ref manager.c Main manager code file */ -#define AMI_VERSION "2.8.0" +#define AMI_VERSION "3.0.0" #define DEFAULT_MANAGER_PORT 5038 /* Default port for Asterisk management via TCP */ #define DEFAULT_MANAGER_TLS_PORT 5039 /* Default port for Asterisk management via TCP */ From 070a51bf7c00f49bb82d26e889b88906a9b2fd0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 2 Jun 2016 22:10:06 +0300 Subject: [PATCH 0897/1578] Implement internal abstraction for iostreams fopencookie/funclose is a non-standard API and should not be used in portable software. Additionally, the way FILE's fd is used in non-blocking mode is undefined behaviour and cannot be relied on. This introduces internal abstraction for io streams, that allows implementing the desired virtualization of read/write operations with necessary timeout handling. ASTERISK-24515 #close ASTERISK-24517 #close Change-Id: Id916aef418b665ced6a7489aef74908b6e376e85 --- apps/app_externalivr.c | 119 +++--- channels/chan_sip.c | 61 ++-- configure.ac | 4 - include/asterisk/iostream.h | 118 ++++++ include/asterisk/tcptls.h | 92 +---- main/http.c | 105 ++---- main/iostream.c | 553 ++++++++++++++++++++++++++++ main/manager.c | 142 +++---- main/tcptls.c | 711 +++++------------------------------- main/utils.c | 62 ---- res/res_http_post.c | 10 +- res/res_http_websocket.c | 116 +++--- res/res_phoneprov.c | 2 +- 13 files changed, 997 insertions(+), 1098 deletions(-) create mode 100644 include/asterisk/iostream.h create mode 100644 main/iostream.c diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c index 273f96381e7..c2224b44b66 100644 --- a/apps/app_externalivr.c +++ b/apps/app_externalivr.c @@ -150,10 +150,12 @@ struct gen_state { }; static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, - int *eivr_events_fd, int *eivr_commands_fd, int *eivr_errors_fd, + struct ast_iostream *eivr_events, + struct ast_iostream *eivr_commands, + struct ast_iostream *eivr_errors, const struct ast_str *args, const struct ast_flags flags); -static void send_eivr_event(FILE *handle, const char event, const char *data, +static void send_eivr_event(struct ast_iostream *stream, const char event, const char *data, const struct ast_channel *chan) { struct ast_str *tmp = ast_str_create(12); @@ -162,9 +164,11 @@ static void send_eivr_event(FILE *handle, const char event, const char *data, if (data) { ast_str_append(&tmp, 0, ",%s", data); } + ast_str_append(&tmp, 0, "\n"); + ast_iostream_write(stream, ast_str_buffer(tmp), strlen(ast_str_buffer(tmp))); + ast_str_truncate(tmp, -1); - fprintf(handle, "%s\n", ast_str_buffer(tmp)); - ast_debug(1, "sent '%s'\n", ast_str_buffer(tmp)); + ast_debug(1, "sent '%s'", ast_str_buffer(tmp)); ast_free(tmp); } @@ -393,6 +397,8 @@ static int app_exec(struct ast_channel *chan, const char *data) int child_stdin[2] = { -1, -1 }; int child_stdout[2] = { -1, -1 }; int child_stderr[2] = { -1, -1 }; + struct ast_iostream *stream_stdin = NULL, *stream_stdout = NULL, + *stream_stderr = NULL; int res = -1; int pid; @@ -524,7 +530,7 @@ static int app_exec(struct ast_channel *chan, const char *data) goto exit; } - res = eivr_comm(chan, u, &ser->fd, &ser->fd, NULL, comma_delim_args, flags); + res = eivr_comm(chan, u, ser->stream, ser->stream, NULL, comma_delim_args, flags); } else { if (pipe(child_stdin)) { @@ -566,7 +572,12 @@ static int app_exec(struct ast_channel *chan, const char *data) child_stdout[1] = -1; close(child_stderr[1]); child_stderr[1] = -1; - res = eivr_comm(chan, u, &child_stdin[1], &child_stdout[0], &child_stderr[0], comma_delim_args, flags); + + stream_stdin = ast_iostream_from_fd(&child_stdin[1]); + stream_stdout = ast_iostream_from_fd(&child_stdout[0]); + stream_stderr = ast_iostream_from_fd(&child_stderr[0]); + + res = eivr_comm(chan, u, stream_stdin, stream_stdout, stream_stderr, comma_delim_args, flags); } } @@ -574,6 +585,15 @@ static int app_exec(struct ast_channel *chan, const char *data) if (u->gen_active) { ast_deactivate_generator(chan); } + if (stream_stdin) { + ast_iostream_close(stream_stdin); + } + if (stream_stdout) { + ast_iostream_close(stream_stdout); + } + if (stream_stderr) { + ast_iostream_close(stream_stderr); + } if (child_stdin[0] > -1) { close(child_stdin[0]); } @@ -602,46 +622,25 @@ static int app_exec(struct ast_channel *chan, const char *data) } static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, - int *eivr_events_fd, int *eivr_commands_fd, int *eivr_errors_fd, - const struct ast_str *args, const struct ast_flags flags) + struct ast_iostream *eivr_events, + struct ast_iostream *eivr_commands, + struct ast_iostream *eivr_errors, + const struct ast_str *args, const struct ast_flags flags) { + char input[1024]; struct playlist_entry *entry; struct ast_frame *f; int ms; int exception; int ready_fd; - int waitfds[2] = { *eivr_commands_fd, (eivr_errors_fd) ? *eivr_errors_fd : -1 }; + int waitfds[2]; + int r; struct ast_channel *rchan; int res = -1; - int test_available_fd = -1; int hangup_info_sent = 0; - - FILE *eivr_commands = NULL; - FILE *eivr_errors = NULL; - FILE *eivr_events = NULL; - if (!(eivr_events = fdopen(*eivr_events_fd, "w"))) { - ast_chan_log(LOG_ERROR, chan, "Could not open stream to send events\n"); - goto exit; - } - if (!(eivr_commands = fdopen(*eivr_commands_fd, "r"))) { - ast_chan_log(LOG_ERROR, chan, "Could not open stream to receive commands\n"); - goto exit; - } - if (eivr_errors_fd) { /* if opening a socket connection, error stream will not be used */ - if (!(eivr_errors = fdopen(*eivr_errors_fd, "r"))) { - ast_chan_log(LOG_ERROR, chan, "Could not open stream to receive errors\n"); - goto exit; - } - } - - test_available_fd = open("/dev/null", O_RDONLY); - - setvbuf(eivr_events, NULL, _IONBF, 0); - setvbuf(eivr_commands, NULL, _IONBF, 0); - if (eivr_errors) { - setvbuf(eivr_errors, NULL, _IONBF, 0); - } + waitfds[0] = ast_iostream_get_fd(eivr_commands); + waitfds[1] = eivr_errors ? ast_iostream_get_fd(eivr_errors) : -1; while (1) { if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) { @@ -665,7 +664,7 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, errno = 0; exception = 0; - rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd) ? 2 : 1, &exception, &ready_fd, &ms); + rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors) ? 2 : 1, &exception, &ready_fd, &ms); if (ast_channel_state(chan) == AST_STATE_UP && !AST_LIST_EMPTY(&u->finishlist)) { AST_LIST_LOCK(&u->finishlist); @@ -713,15 +712,18 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, break; } ast_frfree(f); - } else if (ready_fd == *eivr_commands_fd) { - char input[1024]; - - if (exception || (dup2(*eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) { + } else if (ready_fd == waitfds[0]) { + if (exception) { ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); break; } - if (!fgets(input, sizeof(input), eivr_commands)) { + r = ast_iostream_gets(eivr_commands, input, sizeof(input)); + if (r <= 0) { + if (r == 0) { + ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); + break; + } continue; } @@ -867,16 +869,19 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, else ast_chan_log(LOG_WARNING, chan, "Unknown option requested: %s\n", &input[2]); } - } else if (eivr_errors_fd && (ready_fd == *eivr_errors_fd)) { - char input[1024]; - - if (exception || feof(eivr_errors)) { + } else if (ready_fd == waitfds[1]) { + if (exception) { ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); break; } - if (fgets(input, sizeof(input), eivr_errors)) { + + r = ast_iostream_gets(eivr_errors, input, sizeof(input)); + if (r > 0) { ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", ast_strip(input)); - } + } else if (r == 0) { + ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); + break; + } } else if ((ready_fd < 0) && ms) { if (errno == 0 || errno == EINTR) continue; @@ -886,23 +891,7 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, } } - exit: - if (test_available_fd > -1) { - close(test_available_fd); - } - if (eivr_events) { - fclose(eivr_events); - *eivr_events_fd = -1; - } - if (eivr_commands) { - fclose(eivr_commands); - *eivr_commands_fd = -1; - } - if (eivr_errors) { - fclose(eivr_errors); - *eivr_errors_fd = -1; - } - return res; + return res; } static int unload_module(void) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 32b2a3611ff..43d49af1b87 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -2541,7 +2541,7 @@ static struct sip_threadinfo *sip_threadinfo_create(struct ast_tcptls_session_in } ao2_t_ref(tcptls_session, +1, "tcptls_session ref for sip_threadinfo object"); th->tcptls_session = tcptls_session; - th->type = transport ? transport : (tcptls_session->ssl ? AST_TRANSPORT_TLS: AST_TRANSPORT_TCP); + th->type = transport ? transport : (ast_iostream_get_ssl(tcptls_session->stream) ? AST_TRANSPORT_TLS: AST_TRANSPORT_TCP); ao2_t_link(threadt, th, "Adding new tcptls helper thread"); ao2_t_ref(th, -1, "Decrementing threadinfo ref from alloc, only table ref remains"); return th; @@ -2564,8 +2564,7 @@ static int sip_tcptls_write(struct ast_tcptls_session_instance *tcptls_session, ao2_lock(tcptls_session); - if ((tcptls_session->fd == -1) || - !(th = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread")) || + if (!(th = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread")) || !(packet = ao2_alloc(sizeof(*packet), tcptls_packet_destructor)) || !(packet->data = ast_str_create(len))) { goto tcptls_write_setup_error; @@ -2878,7 +2877,7 @@ static int sip_tcptls_read(struct sip_request *req, struct ast_tcptls_session_in } else { timeout = -1; } - res = ast_wait_for_input(tcptls_session->fd, timeout); + res = ast_wait_for_input(ast_iostream_get_fd(tcptls_session->stream), timeout); if (res < 0) { ast_debug(2, "SIP TCP/TLS server :: ast_wait_for_input returned %d\n", res); return -1; @@ -2887,7 +2886,7 @@ static int sip_tcptls_read(struct sip_request *req, struct ast_tcptls_session_in return -1; } - res = ast_tcptls_server_read(tcptls_session, readbuf, sizeof(readbuf) - 1); + res = ast_iostream_read(tcptls_session->stream, readbuf, sizeof(readbuf) - 1); if (res < 0) { if (errno == EAGAIN || errno == EINTR) { continue; @@ -2948,18 +2947,8 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s goto cleanup; } - if ((flags = fcntl(tcptls_session->fd, F_GETFL)) == -1) { - ast_log(LOG_ERROR, "error setting socket to non blocking mode, fcntl() failed: %s\n", strerror(errno)); - goto cleanup; - } - - flags |= O_NONBLOCK; - if (fcntl(tcptls_session->fd, F_SETFL, flags) == -1) { - ast_log(LOG_ERROR, "error setting socket to non blocking mode, fcntl() failed: %s\n", strerror(errno)); - goto cleanup; - } - - if (!(me = sip_threadinfo_create(tcptls_session, tcptls_session->ssl ? AST_TRANSPORT_TLS : AST_TRANSPORT_TCP))) { + ast_iostream_nonblock(tcptls_session->stream); + if (!(me = sip_threadinfo_create(tcptls_session, ast_iostream_get_ssl(tcptls_session->stream) ? AST_TRANSPORT_TLS : AST_TRANSPORT_TCP))) { goto cleanup; } ao2_t_ref(me, +1, "Adding threadinfo ref for tcp_helper_thread"); @@ -2976,16 +2965,16 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s } flags = 1; - if (setsockopt(tcptls_session->fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) { + if (setsockopt(ast_iostream_get_fd(tcptls_session->stream), SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) { ast_log(LOG_ERROR, "error enabling TCP keep-alives on sip socket: %s\n", strerror(errno)); goto cleanup; } me->threadid = pthread_self(); - ast_debug(2, "Starting thread for %s server\n", tcptls_session->ssl ? "TLS" : "TCP"); + ast_debug(2, "Starting thread for %s server\n", ast_iostream_get_ssl(tcptls_session->stream) ? "TLS" : "TCP"); /* set up pollfd to watch for reads on both the socket and the alert_pipe */ - fds[0].fd = tcptls_session->fd; + fds[0].fd = ast_iostream_get_fd(tcptls_session->stream); fds[1].fd = me->alert_pipe[0]; fds[0].events = fds[1].events = POLLIN | POLLPRI; @@ -3005,9 +2994,9 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s * We cannot let the stream exclusively wait for data to arrive. * We have to wake up the task to send outgoing messages. */ - ast_tcptls_stream_set_exclusive_input(tcptls_session->stream_cookie, 0); + ast_iostream_set_exclusive_input(tcptls_session->stream, 0); - ast_tcptls_stream_set_timeout_sequence(tcptls_session->stream_cookie, ast_tvnow(), + ast_iostream_set_timeout_sequence(tcptls_session->stream, ast_tvnow(), tcptls_session->client ? -1 : (authtimeout * 1000)); for (;;) { @@ -3015,7 +3004,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s if (!tcptls_session->client && req.authenticated && !authenticated) { authenticated = 1; - ast_tcptls_stream_set_timeout_disable(tcptls_session->stream_cookie); + ast_iostream_set_timeout_disable(tcptls_session->stream); ast_atomic_fetchadd_int(&unauth_sessions, -1); } @@ -3026,7 +3015,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s } if (timeout == 0) { - ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "TLS": "TCP"); + ast_debug(2, "SIP %s server timed out\n", ast_iostream_get_ssl(tcptls_session->stream) ? "TLS": "TCP"); goto cleanup; } } else { @@ -3036,11 +3025,11 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s if (ast_str_strlen(tcptls_session->overflow_buf) == 0) { res = ast_poll(fds, 2, timeout); /* polls for both socket and alert_pipe */ if (res < 0) { - ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "TLS": "TCP", res); + ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", ast_iostream_get_ssl(tcptls_session->stream) ? "TLS": "TCP", res); goto cleanup; } else if (res == 0) { /* timeout */ - ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "TLS": "TCP"); + ast_debug(2, "SIP %s server timed out\n", ast_iostream_get_ssl(tcptls_session->stream) ? "TLS": "TCP"); goto cleanup; } } @@ -3065,14 +3054,14 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s memset(buf, 0, sizeof(buf)); - if (tcptls_session->ssl) { + if (ast_iostream_get_ssl(tcptls_session->stream)) { set_socket_transport(&req.socket, AST_TRANSPORT_TLS); req.socket.port = htons(ourport_tls); } else { set_socket_transport(&req.socket, AST_TRANSPORT_TCP); req.socket.port = htons(ourport_tcp); } - req.socket.fd = tcptls_session->fd; + req.socket.fd = ast_iostream_get_fd(tcptls_session->stream); res = sip_tcptls_read(&req, tcptls_session, authenticated, start); if (res < 0) { @@ -3106,7 +3095,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s ao2_unlock(me); if (packet) { - if (ast_tcptls_server_write(tcptls_session, ast_str_buffer(packet->data), packet->len) == -1) { + if (ast_iostream_write(tcptls_session->stream, ast_str_buffer(packet->data), packet->len) == -1) { ast_log(LOG_WARNING, "Failure to write to tcp/tls socket\n"); } ao2_t_ref(packet, -1, "tcptls packet sent, this is no longer needed"); @@ -3118,7 +3107,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s } } - ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "TLS" : "TCP"); + ast_debug(2, "Shutting down thread for %s server\n", ast_iostream_get_ssl(tcptls_session->stream) ? "TLS" : "TCP"); cleanup: if (tcptls_session && !tcptls_session->client && !authenticated) { @@ -29095,9 +29084,8 @@ static int sip_prepare_socket(struct sip_pvt *p) return s->fd; } if ((s->type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) && - (s->tcptls_session) && - (s->tcptls_session->fd != -1)) { - return s->tcptls_session->fd; + s->tcptls_session) { + return ast_iostream_get_fd(s->tcptls_session->stream); } if ((s->type & (AST_TRANSPORT_WS | AST_TRANSPORT_WSS))) { return s->ws_session ? ast_websocket_fd(s->ws_session) : -1; @@ -29127,7 +29115,7 @@ static int sip_prepare_socket(struct sip_pvt *p) /* 1. check for existing threads */ ast_sockaddr_copy(&sa_tmp, sip_real_dst(p)); if ((tcptls_session = sip_tcp_locate(&sa_tmp))) { - s->fd = tcptls_session->fd; + s->fd = ast_iostream_get_fd(tcptls_session->stream); if (s->tcptls_session) { ao2_ref(s->tcptls_session, -1); s->tcptls_session = NULL; @@ -29174,7 +29162,7 @@ static int sip_prepare_socket(struct sip_pvt *p) goto create_tcptls_session_fail; } - s->fd = s->tcptls_session->fd; + s->fd = ast_iostream_get_fd(s->tcptls_session->stream); /* client connections need to have the sip_threadinfo object created before * the thread is detached. This ensures the alert_pipe is up before it will @@ -29976,8 +29964,7 @@ static int sip_send_keepalive(const void *data) if ((peer->socket.fd != -1) && (peer->socket.type == AST_TRANSPORT_UDP)) { res = ast_sendto(peer->socket.fd, keepalive, sizeof(keepalive), 0, &peer->addr); } else if ((peer->socket.type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) && - (peer->socket.tcptls_session) && - (peer->socket.tcptls_session->fd != -1)) { + peer->socket.tcptls_session) { res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, sizeof(keepalive)); } else if (peer->socket.type == AST_TRANSPORT_UDP) { res = ast_sendto(sipsock, keepalive, sizeof(keepalive), 0, &peer->addr); diff --git a/configure.ac b/configure.ac index 0f2148b06a8..0574c089098 100644 --- a/configure.ac +++ b/configure.ac @@ -815,10 +815,6 @@ AC_ARG_ENABLE([asteriskssl], esac], [AST_ASTERISKSSL=yes]) AC_SUBST(AST_ASTERISKSSL) -# https support (in main/http.c) uses funopen on BSD systems, -# fopencookie on linux -AC_CHECK_FUNCS([funopen fopencookie]) - AC_CHECK_FUNCS([inet_aton]) # check if we have IP_PKTINFO constant defined diff --git a/include/asterisk/iostream.h b/include/asterisk/iostream.h new file mode 100644 index 00000000000..c641ffb3732 --- /dev/null +++ b/include/asterisk/iostream.h @@ -0,0 +1,118 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2015, Digium, Inc. + * + * Timo Teräs + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _ASTERISK_IOSTREAM_H +#define _ASTERISK_IOSTREAM_H + +/*! + * \file iostream.h + * + * \brief Generic abstraction for input/output streams. + */ + +#if defined(HAVE_OPENSSL) +#define DO_SSL /* comment in/out if you want to support ssl */ +#endif + +#ifdef DO_SSL +#include +#include +#include +#else +/* declare dummy types so we can define a pointer to them */ +typedef struct {} SSL; +typedef struct {} SSL_CTX; +#endif /* DO_SSL */ + +struct ast_iostream; + +/*! + * \brief Disable the iostream timeout timer. + * + * \param stream iostream control data. + * + * \return Nothing + */ +void ast_iostream_set_timeout_disable(struct ast_iostream *stream); + +/*! + * \brief Set the iostream inactivity timeout timer. + * + * \param stream iostream control data. + * \param timeout Number of milliseconds to wait for data transfer with the peer. + * + * \details This is basically how much time we are willing to spend + * in an I/O call before we declare the peer unresponsive. + * + * \note Setting timeout to -1 disables the timeout. + * \note Setting this timeout replaces the I/O sequence timeout timer. + * + * \return Nothing + */ +void ast_iostream_set_timeout_inactivity(struct ast_iostream *stream, int timeout); + +void ast_iostream_set_timeout_idle_inactivity(struct ast_iostream *stream, int timeout, int timeout_reset); + +/*! + * \brief Set the iostream I/O sequence timeout timer. + * + * \param stream iostream control data. + * \param start Time the I/O sequence timer starts. + * \param timeout Number of milliseconds from the start time before timeout. + * + * \details This is how much time are we willing to allow the peer + * to complete an operation that can take several I/O calls. The + * main use is as an authentication timer with us. + * + * \note Setting timeout to -1 disables the timeout. + * \note Setting this timeout replaces the inactivity timeout timer. + * + * \return Nothing + */ +void ast_iostream_set_timeout_sequence(struct ast_iostream *stream, struct timeval start, int timeout); + +/*! + * \brief Set the iostream if it can exclusively depend upon the set timeouts. + * + * \param stream iostream control data. + * \param exclusive_input TRUE if stream can exclusively wait for fd input. + * Otherwise, the stream will not wait for fd input. It will wait while + * trying to send data. + * + * \note The stream timeouts still need to be set. + * + * \return Nothing + */ +void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive_input); + +int ast_iostream_get_fd(struct ast_iostream *stream); +void ast_iostream_nonblock(struct ast_iostream *stream); + +SSL* ast_iostream_get_ssl(struct ast_iostream *stream); + +ssize_t ast_iostream_read(struct ast_iostream *stream, void *buf, size_t count); +ssize_t ast_iostream_gets(struct ast_iostream *stream, char *buf, size_t count); +ssize_t ast_iostream_discard(struct ast_iostream *stream, size_t count); +ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buf, size_t count); +ssize_t ast_iostream_printf(struct ast_iostream *stream, const void *fmt, ...); + +struct ast_iostream* ast_iostream_from_fd(int *fd); +int ast_iostream_start_tls(struct ast_iostream **stream, SSL_CTX *ctx, int client); +int ast_iostream_close(struct ast_iostream *stream); + +#endif /* _ASTERISK_IOSTREAM_H */ diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h index 3c5f4504caf..883cb9229ef 100644 --- a/include/asterisk/tcptls.h +++ b/include/asterisk/tcptls.h @@ -57,20 +57,7 @@ #include "asterisk/netsock2.h" #include "asterisk/utils.h" - -#if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE)) -#define DO_SSL /* comment in/out if you want to support ssl */ -#endif - -#ifdef DO_SSL -#include -#include -#include -#else -/* declare dummy types so we can define a pointer to them */ -typedef struct {} SSL; -typedef struct {} SSL_CTX; -#endif /* DO_SSL */ +#include "asterisk/iostream.h" /*! SSL support */ #define AST_CERTFILE "asterisk.pem" @@ -153,72 +140,10 @@ struct ast_tcptls_session_args { const char *name; }; -struct ast_tcptls_stream; - -/*! - * \brief Disable the TCP/TLS stream timeout timer. - * - * \param stream TCP/TLS stream control data. - * - * \return Nothing - */ -void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream); - -/*! - * \brief Set the TCP/TLS stream inactivity timeout timer. - * - * \param stream TCP/TLS stream control data. - * \param timeout Number of milliseconds to wait for data transfer with the peer. - * - * \details This is basically how much time we are willing to spend - * in an I/O call before we declare the peer unresponsive. - * - * \note Setting timeout to -1 disables the timeout. - * \note Setting this timeout replaces the I/O sequence timeout timer. - * - * \return Nothing - */ -void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream, int timeout); - -/*! - * \brief Set the TCP/TLS stream I/O sequence timeout timer. - * - * \param stream TCP/TLS stream control data. - * \param start Time the I/O sequence timer starts. - * \param timeout Number of milliseconds from the start time before timeout. - * - * \details This is how much time are we willing to allow the peer - * to complete an operation that can take several I/O calls. The - * main use is as an authentication timer with us. - * - * \note Setting timeout to -1 disables the timeout. - * \note Setting this timeout replaces the inactivity timeout timer. - * - * \return Nothing - */ -void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout); - -/*! - * \brief Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts. - * - * \param stream TCP/TLS stream control data. - * \param exclusive_input TRUE if stream can exclusively wait for fd input. - * Otherwise, the stream will not wait for fd input. It will wait while - * trying to send data. - * - * \note The stream timeouts still need to be set. - * - * \return Nothing - */ -void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input); - /*! \brief * describes a server instance */ struct ast_tcptls_session_instance { - FILE *f; /*!< fopen/funopen result */ - int fd; /*!< the socket returned by accept() */ - SSL *ssl; /*!< ssl state */ int client; struct ast_sockaddr remote_address; struct ast_tcptls_session_args *parent; @@ -228,20 +153,12 @@ struct ast_tcptls_session_instance { * extra data. */ struct ast_str *overflow_buf; - /*! ao2 FILE stream cookie object associated with f. */ - struct ast_tcptls_stream *stream_cookie; + /*! ao2 stream object associated with this session. */ + struct ast_iostream *stream; /*! ao2 object private data of parent->worker_fn */ void *private_data; }; -#if defined(HAVE_FUNOPEN) -#define HOOK_T int -#define LEN_T int -#else -#define HOOK_T ssize_t -#define LEN_T size_t -#endif - /*! * \brief attempts to connect and start tcptls session, on error the tcptls_session's * ref count is decremented, fd and file are closed, and NULL is returned. @@ -297,7 +214,4 @@ void ast_ssl_teardown(struct ast_tls_config *cfg); */ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value); -HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *ser, void *buf, size_t count); -HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *ser, const void *buf, size_t count); - #endif /* _ASTERISK_TCPTLS_H */ diff --git a/main/http.c b/main/http.c index 77feb397bba..9aff4d16766 100644 --- a/main/http.c +++ b/main/http.c @@ -449,11 +449,13 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, struct timeval now = ast_tvnow(); struct ast_tm tm; char timebuf[80]; + char buf[256]; + int len; int content_length = 0; int close_connection; struct ast_str *server_header_field = ast_str_create(MAX_SERVER_NAME_LENGTH); - if (!ser || !ser->f || !server_header_field) { + if (!ser || !server_header_field) { /* The connection is not open. */ ast_free(http_header); ast_free(out); @@ -503,7 +505,7 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, } /* send http header */ - fprintf(ser->f, + ast_iostream_printf(ser->stream, "HTTP/1.1 %d %s\r\n" "%s" "Date: %s\r\n" @@ -524,18 +526,16 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, /* send content */ if (method != AST_HTTP_HEAD || status_code >= 400) { if (out && ast_str_strlen(out)) { - if (fwrite(ast_str_buffer(out), ast_str_strlen(out), 1, ser->f) != 1) { + len = ast_str_strlen(out); + if (ast_iostream_write(ser->stream, ast_str_buffer(out), len) != len) { ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno)); close_connection = 1; } } if (fd) { - char buf[256]; - int len; - while ((len = read(fd, buf, sizeof(buf))) > 0) { - if (fwrite(buf, len, 1, ser->f) != 1) { + if (ast_iostream_write(ser->stream, buf, len) != len) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); close_connection = 1; break; @@ -567,7 +567,7 @@ void ast_http_create_response(struct ast_tcptls_session_instance *ser, int statu ast_free(http_header_data); ast_free(server_address); ast_free(out); - if (ser && ser->f) { + if (ser) { ast_debug(1, "HTTP closing session. OOM.\n"); ast_tcptls_close_session_file(ser); } @@ -921,9 +921,9 @@ static int http_body_read_contents(struct ast_tcptls_session_instance *ser, char { int res; - /* Stay in fread until get all the expected data or timeout. */ - res = fread(buf, length, 1, ser->f); - if (res < 1) { + /* Stream is in exclusive mode so we get it all if possible. */ + res = ast_iostream_read(ser->stream, buf, length); + if (res < length) { ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d)\n", what_getting, length); return -1; @@ -945,23 +945,12 @@ static int http_body_read_contents(struct ast_tcptls_session_instance *ser, char */ static int http_body_discard_contents(struct ast_tcptls_session_instance *ser, int length, const char *what_getting) { - int res; - char buf[MAX_HTTP_LINE_LENGTH];/* Discard buffer */ - - /* Stay in fread until get all the expected data or timeout. */ - while (sizeof(buf) < length) { - res = fread(buf, sizeof(buf), 1, ser->f); - if (res < 1) { - ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %zu of remaining %d)\n", - what_getting, sizeof(buf), length); - return -1; - } - length -= sizeof(buf); - } - res = fread(buf, length, 1, ser->f); - if (res < 1) { - ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d of remaining %d)\n", - what_getting, length, length); + ssize_t res; + + res = ast_iostream_discard(ser->stream, length); + if (res < length) { + ast_log(LOG_WARNING, "Short HTTP request %s (Wanted %d but got %zd)\n", + what_getting, length, res); return -1; } return 0; @@ -1037,7 +1026,7 @@ static int http_body_get_chunk_length(struct ast_tcptls_session_instance *ser) char header_line[MAX_HTTP_LINE_LENGTH]; /* get the line of hexadecimal giving chunk-size w/ optional chunk-extension */ - if (!fgets(header_line, sizeof(header_line), ser->f)) { + if (ast_iostream_gets(ser->stream, header_line, sizeof(header_line)) <= 0) { ast_log(LOG_WARNING, "Short HTTP read of chunked header\n"); return -1; } @@ -1065,8 +1054,8 @@ static int http_body_check_chunk_sync(struct ast_tcptls_session_instance *ser) char chunk_sync[2]; /* Stay in fread until get the expected CRLF or timeout. */ - res = fread(chunk_sync, sizeof(chunk_sync), 1, ser->f); - if (res < 1) { + res = ast_iostream_read(ser->stream, chunk_sync, sizeof(chunk_sync)); + if (res < sizeof(chunk_sync)) { ast_log(LOG_WARNING, "Short HTTP chunk sync read (Wanted %zu)\n", sizeof(chunk_sync)); return -1; @@ -1095,7 +1084,7 @@ static int http_body_discard_chunk_trailer_headers(struct ast_tcptls_session_ins char header_line[MAX_HTTP_LINE_LENGTH]; for (;;) { - if (!fgets(header_line, sizeof(header_line), ser->f)) { + if (ast_iostream_gets(ser->stream, header_line, sizeof(header_line)) <= 0) { ast_log(LOG_WARNING, "Short HTTP read of chunked trailer header\n"); return -1; } @@ -1758,7 +1747,7 @@ static int http_request_headers_get(struct ast_tcptls_session_instance *ser, str char *name; char *value; - if (!fgets(header_line, sizeof(header_line), ser->f)) { + if (ast_iostream_gets(ser->stream, header_line, sizeof(header_line)) <= 0) { ast_http_error(ser, 400, "Bad Request", "Timeout"); return -1; } @@ -1832,7 +1821,7 @@ static int httpd_process_request(struct ast_tcptls_session_instance *ser) int res; char request_line[MAX_HTTP_LINE_LENGTH]; - if (!fgets(request_line, sizeof(request_line), ser->f)) { + if (ast_iostream_gets(ser->stream, request_line, sizeof(request_line)) <= 0) { return -1; } @@ -1913,11 +1902,10 @@ static int httpd_process_request(struct ast_tcptls_session_instance *ser) static void *httpd_helper_thread(void *data) { struct ast_tcptls_session_instance *ser = data; - struct protoent *p; - int flags; int timeout; + int arg = 1; - if (!ser || !ser->f) { + if (!ser) { ao2_cleanup(ser); return NULL; } @@ -1934,23 +1922,11 @@ static void *httpd_helper_thread(void *data) * This is necessary to prevent delays (caused by buffering) as we * write to the socket in bits and pieces. */ - p = getprotobyname("tcp"); - if (p) { - int arg = 1; - - if (setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *) &arg, sizeof(arg) ) < 0) { - ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno)); - ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n"); - } - } else { - ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection, getprotobyname(\"tcp\") failed\n"); + if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg) ) < 0) { + ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno)); ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n"); } - - /* make sure socket is non-blocking */ - flags = fcntl(ser->fd, F_GETFL); - flags |= O_NONBLOCK; - fcntl(ser->fd, F_SETFL, flags); + ast_iostream_nonblock(ser->stream); /* Setup HTTP worker private data to keep track of request body reading. */ ao2_cleanup(ser->private_data); @@ -1973,23 +1949,17 @@ static void *httpd_helper_thread(void *data) } /* We can let the stream wait for data to arrive. */ - ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 1); + ast_iostream_set_exclusive_input(ser->stream, 1); for (;;) { - int ch; - /* Wait for next potential HTTP request message. */ - ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, timeout); - ch = fgetc(ser->f); - if (ch == EOF || ungetc(ch, ser->f) == EOF) { - /* Between request idle timeout */ - ast_debug(1, "HTTP idle timeout or peer closed connection.\n"); + ast_iostream_set_timeout_idle_inactivity(ser->stream, timeout, session_inactivity); + if (httpd_process_request(ser)) { + /* Break the connection or the connection closed */ break; } - - ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, session_inactivity); - if (httpd_process_request(ser) || !ser->f || feof(ser->f)) { - /* Break the connection or the connection closed */ + if (!ser->stream) { + /* Web-socket or similar that took the connection */ break; } @@ -2003,10 +1973,9 @@ static void *httpd_helper_thread(void *data) done: ast_atomic_fetchadd_int(&session_count, -1); - if (ser->f) { - ast_debug(1, "HTTP closing session. Top level\n"); - ast_tcptls_close_session_file(ser); - } + ast_debug(1, "HTTP closing session. Top level\n"); + ast_tcptls_close_session_file(ser); + ao2_ref(ser, -1); return NULL; } diff --git a/main/iostream.c b/main/iostream.c new file mode 100644 index 00000000000..46abc18a5c8 --- /dev/null +++ b/main/iostream.c @@ -0,0 +1,553 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2015, Digium, Inc. + * + * Timo Teräs + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include +#include + +#include "asterisk.h" +#include "asterisk/utils.h" +#include "asterisk/astobj2.h" +#include "asterisk/iostream.h" + +struct ast_iostream { + SSL *ssl; + struct timeval start; + int fd; + int timeout; + int timeout_reset; + int exclusive_input; + int rbuflen; + char *rbufhead; + char rbuf[2048]; +}; + +int ast_iostream_get_fd(struct ast_iostream *stream) +{ + return stream->fd; +} + +void ast_iostream_nonblock(struct ast_iostream *stream) +{ + fcntl(stream->fd, F_SETFL, fcntl(stream->fd, F_GETFL) | O_NONBLOCK); +} + +SSL *ast_iostream_get_ssl(struct ast_iostream *stream) +{ + return stream->ssl; +} + +void ast_iostream_set_timeout_disable(struct ast_iostream *stream) +{ + ast_assert(stream != NULL); + + stream->timeout = -1; + stream->timeout_reset = -1; +} + +void ast_iostream_set_timeout_inactivity(struct ast_iostream *stream, int timeout) +{ + ast_assert(stream != NULL); + + stream->start.tv_sec = 0; + stream->timeout = timeout; + stream->timeout_reset = timeout; +} + +void ast_iostream_set_timeout_idle_inactivity(struct ast_iostream *stream, int timeout, int timeout_reset) +{ + ast_assert(stream != NULL); + + stream->start.tv_sec = 0; + stream->timeout = timeout; + stream->timeout_reset = timeout_reset; +} + +void ast_iostream_set_timeout_sequence(struct ast_iostream *stream, struct timeval start, int timeout) +{ + ast_assert(stream != NULL); + + stream->start = start; + stream->timeout = timeout; + stream->timeout_reset = timeout; +} + +void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive_input) +{ + ast_assert(stream != NULL); + + stream->exclusive_input = exclusive_input; +} + +static ssize_t iostream_read(struct ast_iostream *stream, void *buf, size_t size) +{ + struct timeval start; + int ms; + int res; + + if (stream->start.tv_sec) { + start = stream->start; + } else { + start = ast_tvnow(); + } + +#if defined(DO_SSL) + if (stream->ssl) { + for (;;) { + res = SSL_read(stream->ssl, buf, size); + if (0 < res) { + /* We read some payload data. */ + stream->timeout = stream->timeout_reset; + return res; + } + switch (SSL_get_error(stream->ssl, res)) { + case SSL_ERROR_ZERO_RETURN: + /* Report EOF for a shutdown */ + ast_debug(1, "TLS clean shutdown alert reading data\n"); + return 0; + case SSL_ERROR_WANT_READ: + if (!stream->exclusive_input) { + /* We cannot wait for data now. */ + errno = EAGAIN; + return -1; + } + while ((ms = ast_remaining_ms(start, stream->timeout))) { + res = ast_wait_for_input(stream->fd, ms); + if (0 < res) { + /* Socket is ready to be read. */ + break; + } + if (res < 0) { + if (errno == EINTR || errno == EAGAIN) { + /* Try again. */ + continue; + } + ast_debug(1, "TLS socket error waiting for read data: %s\n", + strerror(errno)); + return -1; + } + } + break; + case SSL_ERROR_WANT_WRITE: + while ((ms = ast_remaining_ms(start, stream->timeout))) { + res = ast_wait_for_output(stream->fd, ms); + if (0 < res) { + /* Socket is ready to be written. */ + break; + } + if (res < 0) { + if (errno == EINTR || errno == EAGAIN) { + /* Try again. */ + continue; + } + ast_debug(1, "TLS socket error waiting for write space: %s\n", + strerror(errno)); + return -1; + } + } + break; + default: + /* Report EOF for an undecoded SSL or transport error. */ + ast_debug(1, "TLS transport or SSL error reading data\n"); + return 0; + } + if (!ms) { + /* Report EOF for a timeout */ + ast_debug(1, "TLS timeout reading data\n"); + return 0; + } + } + } +#endif /* defined(DO_SSL) */ + + for (;;) { + res = read(stream->fd, buf, size); + if (0 <= res) { + /* Got data or we cannot wait for it. */ + stream->timeout = stream->timeout_reset; + return res; + } + if (!stream->exclusive_input) { + return res; + } + if (errno != EINTR && errno != EAGAIN) { + /* Not a retryable error. */ + ast_debug(1, "TCP socket error reading data: %s\n", + strerror(errno)); + return -1; + } + ms = ast_remaining_ms(start, stream->timeout); + if (!ms) { + /* Report EOF for a timeout */ + ast_debug(1, "TCP timeout reading data\n"); + return 0; + } + ast_wait_for_input(stream->fd, ms); + } +} + +ssize_t ast_iostream_read(struct ast_iostream *stream, void *buf, size_t size) +{ + if (!size) { + /* You asked for no data you got no data. */ + return 0; + } + + if (!stream || stream->fd == -1) { + errno = EBADF; + return -1; + } + + /* Get any remains from the read buffer */ + if (stream->rbuflen) { + size_t r = size; + if (r > stream->rbuflen) { + r = stream->rbuflen; + } + memcpy(buf, stream->rbufhead, r); + stream->rbuflen -= r; + stream->rbufhead += r; + return r; + } + + return iostream_read(stream, buf, size); +} + +ssize_t ast_iostream_gets(struct ast_iostream *stream, char *buf, size_t count) +{ + ssize_t r; + char *newline; + + do { + /* Search for newline */ + newline = memchr(stream->rbufhead, '\n', stream->rbuflen); + if (newline) { + r = newline - stream->rbufhead + 1; + if (r > count-1) { + r = count-1; + } + break; + } + + /* Enough data? */ + if (stream->rbuflen >= count - 1) { + r = count - 1; + break; + } + + /* Try to fill in line buffer */ + if (stream->rbuflen && stream->rbuf != stream->rbufhead) { + memmove(&stream->rbuf, stream->rbufhead, stream->rbuflen); + } + stream->rbufhead = stream->rbuf; + + r = iostream_read(stream, stream->rbufhead + stream->rbuflen, sizeof(stream->rbuf) - stream->rbuflen); + if (r <= 0) { + return r; + } + stream->rbuflen += r; + } while (1); + + /* Return r bytes with termination byte */ + memcpy(buf, stream->rbufhead, r); + buf[r] = 0; + stream->rbuflen -= r; + stream->rbufhead += r; + + return r; +} + +ssize_t ast_iostream_discard(struct ast_iostream *stream, size_t size) +{ + char buf[1024]; + size_t remaining = size; + ssize_t ret; + + while (remaining) { + ret = ast_iostream_read(stream, buf, remaining > sizeof(buf) ? sizeof(buf) : remaining); + if (ret < 0) { + return ret; + } + remaining -= ret; + } + + return size; +} + +ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buf, size_t size) +{ + struct timeval start; + int ms; + int res; + int written; + int remaining; + + if (!size) { + /* You asked to write no data you wrote no data. */ + return 0; + } + + if (!stream || stream->fd == -1) { + errno = EBADF; + return -1; + } + + if (stream->start.tv_sec) { + start = stream->start; + } else { + start = ast_tvnow(); + } + +#if defined(DO_SSL) + if (stream->ssl) { + written = 0; + remaining = size; + for (;;) { + res = SSL_write(stream->ssl, buf + written, remaining); + if (res == remaining) { + /* Everything was written. */ + return size; + } + if (0 < res) { + /* Successfully wrote part of the buffer. Try to write the rest. */ + written += res; + remaining -= res; + continue; + } + switch (SSL_get_error(stream->ssl, res)) { + case SSL_ERROR_ZERO_RETURN: + ast_debug(1, "TLS clean shutdown alert writing data\n"); + if (written) { + /* Report partial write. */ + return written; + } + errno = EBADF; + return -1; + case SSL_ERROR_WANT_READ: + ms = ast_remaining_ms(start, stream->timeout); + if (!ms) { + /* Report partial write. */ + ast_debug(1, "TLS timeout writing data (want read)\n"); + return written; + } + ast_wait_for_input(stream->fd, ms); + break; + case SSL_ERROR_WANT_WRITE: + ms = ast_remaining_ms(start, stream->timeout); + if (!ms) { + /* Report partial write. */ + ast_debug(1, "TLS timeout writing data (want write)\n"); + return written; + } + ast_wait_for_output(stream->fd, ms); + break; + default: + /* Undecoded SSL or transport error. */ + ast_debug(1, "TLS transport or SSL error writing data\n"); + if (written) { + /* Report partial write. */ + return written; + } + errno = EBADF; + return -1; + } + } + } +#endif /* defined(DO_SSL) */ + + written = 0; + remaining = size; + for (;;) { + res = write(stream->fd, buf + written, remaining); + if (res == remaining) { + /* Yay everything was written. */ + return size; + } + if (0 < res) { + /* Successfully wrote part of the buffer. Try to write the rest. */ + written += res; + remaining -= res; + continue; + } + if (errno != EINTR && errno != EAGAIN) { + /* Not a retryable error. */ + ast_debug(1, "TCP socket error writing: %s\n", strerror(errno)); + if (written) { + return written; + } + return -1; + } + ms = ast_remaining_ms(start, stream->timeout); + if (!ms) { + /* Report partial write. */ + ast_debug(1, "TCP timeout writing data\n"); + return written; + } + ast_wait_for_output(stream->fd, ms); + } +} + +ssize_t ast_iostream_printf(struct ast_iostream *stream, const void *fmt, ...) +{ + char sbuf[256], *buf = sbuf; + int len, len2, ret = -1; + va_list va; + + va_start(va, fmt); + len = vsnprintf(buf, sizeof(sbuf), fmt, va); + va_end(va); + + if (len > sizeof(sbuf)) { + buf = ast_malloc(len); + if (!buf) { + return -1; + } + va_start(va, fmt); + len2 = vsnprintf(buf, len, fmt, va); + va_end(va); + if (len2 > len) { + goto error; + } + } + + if (ast_iostream_write(stream, buf, len) == len) + ret = len; + +error: + if (buf != sbuf) { + ast_free(buf); + } + + return ret; +} + +int ast_iostream_close(struct ast_iostream *stream) +{ + if (!stream) { + errno = EBADF; + return -1; + } + + if (stream->fd != -1) { +#if defined(DO_SSL) + if (stream->ssl) { + int res; + + /* + * According to the TLS standard, it is acceptable for an + * application to only send its shutdown alert and then + * close the underlying connection without waiting for + * the peer's response (this way resources can be saved, + * as the process can already terminate or serve another + * connection). + */ + res = SSL_shutdown(stream->ssl); + if (res < 0) { + ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n", + SSL_get_error(stream->ssl, res)); + } + + if (!stream->ssl->server) { + /* For client threads, ensure that the error stack is cleared */ + ERR_remove_state(0); + } + + SSL_free(stream->ssl); + stream->ssl = NULL; + } +#endif /* defined(DO_SSL) */ + + /* + * Issuing shutdown() is necessary here to avoid a race + * condition where the last data written may not appear + * in the TCP stream. See ASTERISK-23548 + */ + shutdown(stream->fd, SHUT_RDWR); + if (close(stream->fd)) { + ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); + } + stream->fd = -1; + } + ao2_t_ref(stream, -1, "Closed ast_iostream"); + + return 0; +} + +static void iostream_dtor(void *cookie) +{ +#ifdef AST_DEVMODE + /* Since the ast_assert below is the only one using stream, + * and ast_assert is only available with AST_DEVMODE, we + * put this in a conditional to avoid compiler warnings. */ + struct ast_iostream *stream = cookie; +#endif + + ast_assert(stream->fd == -1); +} + +struct ast_iostream *ast_iostream_from_fd(int *fd) +{ + struct ast_iostream *stream; + + stream = ao2_alloc_options(sizeof(*stream), iostream_dtor, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (stream) { + stream->timeout = -1; + stream->timeout_reset = -1; + stream->fd = *fd; + *fd = -1; + } + + return stream; +} + +int ast_iostream_start_tls(struct ast_iostream **pstream, SSL_CTX *ssl_ctx, int client) +{ +#ifdef DO_SSL + struct ast_iostream *stream = *pstream; + int (*ssl_setup)(SSL *) = client ? SSL_connect : SSL_accept; + char err[256]; + + stream->ssl = SSL_new(ssl_ctx); + if (!stream->ssl) { + ast_log(LOG_ERROR, "Unable to create new SSL connection\n"); + errno = ENOMEM; + return -1; + } + + /* + * This function takes struct ast_iostream **, so it can chain + * SSL over any ast_iostream. For now we assume it's a file descriptor. + * But later this should instead use BIO wrapper to tie SSL to another + * ast_iostream. + */ + SSL_set_fd(stream->ssl, stream->fd); + + if (ssl_setup(stream->ssl) <= 0) { + ast_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", + ERR_error_string(ERR_get_error(), err)); + errno = EIO; + return -1; + } + + return 0; +#else + ast_log(LOG_ERROR, "SSL not enabled in this build\n"); + errno = ENOTSUP; + return -1; +#endif +} diff --git a/main/manager.c b/main/manager.c index ef1afb03d31..f059015c7d4 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1549,8 +1549,7 @@ static void acl_change_stasis_unsubscribe(void) struct mansession_session { /*! \todo XXX need to document which fields it is protecting */ struct ast_sockaddr addr; /*!< address we are connecting from */ - FILE *f; /*!< fdopen() on the underlying fd */ - int fd; /*!< descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */ + struct ast_iostream *stream; /*!< AMI stream */ int inuse; /*!< number of HTTP sessions using this entry */ int needdestroy; /*!< Whether an HTTP session should be destroyed */ pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */ @@ -1592,9 +1591,8 @@ enum mansession_message_parsing { */ struct mansession { struct mansession_session *session; + struct ast_iostream *stream; struct ast_tcptls_session_instance *tcptls_session; - FILE *f; - int fd; enum mansession_message_parsing parsing; int write_error:1; struct manager_custom_hook *hook; @@ -2166,10 +2164,6 @@ static void session_destructor(void *obj) ast_datastore_free(datastore); } - if (session->f != NULL) { - fflush(session->f); - fclose(session->f); - } if (eqe) { ast_atomic_fetchadd_int(&eqe->usecount, -1); } @@ -2204,7 +2198,6 @@ static struct mansession_session *build_mansession(const struct ast_sockaddr *ad return NULL; } - newsession->fd = -1; newsession->waiting_thread = AST_PTHREADT_NULL; newsession->writetimeout = 100; newsession->send_events = -1; @@ -2617,7 +2610,7 @@ static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli ast_sockaddr_stringify_addr(&session->addr), (int) (session->sessionstart), (int) (now - session->sessionstart), - session->fd, + session->stream ? ast_iostream_get_fd(session->stream) : -1, session->inuse, session->readperm, session->writeperm); @@ -2889,7 +2882,6 @@ int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg) * This is necessary to meet the previous design of manager.c */ s.hook = hook; - s.f = (void*)1; /* set this to something so our request will make it through all functions that test it*/ ao2_lock(act_found); if (act_found->registered && act_found->func) { @@ -2920,9 +2912,8 @@ int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg) */ static int send_string(struct mansession *s, char *string) { - int res; - FILE *f = s->f ? s->f : s->session->f; - int fd = s->f ? s->fd : s->session->fd; + struct ast_iostream *stream = s->stream ? s->stream : s->session->stream; + int len, res; /* It's a result from one of the hook's action invocation */ if (s->hook) { @@ -2934,7 +2925,12 @@ static int send_string(struct mansession *s, char *string) return 0; } - if ((res = ast_careful_fwrite(f, fd, string, strlen(string), s->session->writetimeout))) { + len = strlen(string); + ast_iostream_set_timeout_inactivity(stream, s->session->writetimeout); + res = ast_iostream_write(stream, string, len); + ast_iostream_set_timeout_disable(stream); + + if (res < len) { s->write_error = 1; } @@ -2975,10 +2971,10 @@ void astman_append(struct mansession *s, const char *fmt, ...) return; } - if (s->f != NULL || s->session->f != NULL) { + if (s->tcptls_session != NULL && s->tcptls_session->stream != NULL) { send_string(s, ast_str_buffer(buf)); } else { - ast_verbose("fd == -1 in astman_append, should not happen\n"); + ast_verbose("No connection stream in astman_append, should not happen\n"); } } @@ -4119,7 +4115,7 @@ static int action_waitevent(struct mansession *s, const struct message *m) break; } if (s->session->managerid == 0) { /* AMI session */ - if (ast_wait_for_input(s->session->fd, 1000)) { + if (ast_wait_for_input(ast_iostream_get_fd(s->session->stream), 1000)) { break; } } else { /* HTTP session */ @@ -5924,7 +5920,7 @@ static int process_events(struct mansession *s) int ret = 0; ao2_lock(s->session); - if (s->session->f != NULL) { + if (s->session->stream != NULL) { struct eventqent *eqe = s->session->last_ev; while ((eqe = advance_event(eqe))) { @@ -6466,7 +6462,7 @@ static int get_input(struct mansession *s, char *output) s->session->waiting_thread = pthread_self(); ao2_unlock(s->session); - res = ast_wait_for_input(s->session->fd, timeout); + res = ast_wait_for_input(ast_iostream_get_fd(s->session->stream), timeout); ao2_lock(s->session); s->session->waiting_thread = AST_PTHREADT_NULL; @@ -6484,7 +6480,7 @@ static int get_input(struct mansession *s, char *output) } ao2_lock(s->session); - res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f); + res = ast_iostream_read(s->session->stream, src + s->session->inlen, maxlen - s->session->inlen); if (res < 1) { res = -1; /* error return */ } else { @@ -6617,13 +6613,12 @@ static void *session_do(void *data) struct mansession s = { .tcptls_session = data, }; - int flags; int res; + int arg = 1; struct ast_sockaddr ser_remote_address_tmp; - struct protoent *p; if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) { - fclose(ser->f); + ast_iostream_close(ser->stream); ast_atomic_fetchadd_int(&unauth_sessions, -1); goto done; } @@ -6632,7 +6627,7 @@ static void *session_do(void *data) session = build_mansession(&ser_remote_address_tmp); if (session == NULL) { - fclose(ser->f); + ast_iostream_close(ser->stream); ast_atomic_fetchadd_int(&unauth_sessions, -1); goto done; } @@ -6640,20 +6635,10 @@ static void *session_do(void *data) /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm. * This is necessary to prevent delays (caused by buffering) as we * write to the socket in bits and pieces. */ - p = getprotobyname("tcp"); - if (p) { - int arg = 1; - if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) { - ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\nSome manager actions may be slow to respond.\n", strerror(errno)); - } - } else { - ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY, getprotobyname(\"tcp\") failed\nSome manager actions may be slow to respond.\n"); + if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0) { + ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\nSome manager actions may be slow to respond.\n", strerror(errno)); } - - /* make sure socket is non-blocking */ - flags = fcntl(ser->fd, F_GETFL); - flags |= O_NONBLOCK; - fcntl(ser->fd, F_SETFL, flags); + ast_iostream_nonblock(ser->stream); ao2_lock(session); /* Hook to the tail of the event queue */ @@ -6662,8 +6647,7 @@ static void *session_do(void *data) ast_mutex_init(&s.lock); /* these fields duplicate those in the 'ser' structure */ - session->fd = s.fd = ser->fd; - session->f = s.f = ser->f; + session->stream = s.stream = ser->stream; ast_sockaddr_copy(&session->addr, &ser_remote_address_tmp); s.session = session; @@ -6682,9 +6666,9 @@ static void *session_do(void *data) * We cannot let the stream exclusively wait for data to arrive. * We have to wake up the task to send async events. */ - ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 0); + ast_iostream_set_exclusive_input(ser->stream, 0); - ast_tcptls_stream_set_timeout_sequence(ser->stream_cookie, + ast_iostream_set_timeout_sequence(ser->stream, ast_tvnow(), authtimeout * 1000); astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */ @@ -6693,7 +6677,7 @@ static void *session_do(void *data) break; } if (session->authenticated) { - ast_tcptls_stream_set_timeout_disable(ser->stream_cookie); + ast_iostream_set_timeout_disable(ser->stream); } } /* session is over, explain why and terminate */ @@ -7552,23 +7536,9 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *g static void close_mansession_file(struct mansession *s) { - if (s->f) { - if (fclose(s->f)) { - ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); - } - s->f = NULL; - s->fd = -1; - } else if (s->fd != -1) { - /* - * Issuing shutdown() is necessary here to avoid a race - * condition where the last data written may not appear - * in the TCP stream. See ASTERISK-23548 - */ - shutdown(s->fd, SHUT_RDWR); - if (close(s->fd)) { - ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); - } - s->fd = -1; + if (s->stream) { + ast_iostream_close(s->stream); + s->stream = NULL; } else { ast_log(LOG_ERROR, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n"); } @@ -7577,17 +7547,20 @@ static void close_mansession_file(struct mansession *s) static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format) { char *buf; - size_t l; + off_t l; + int fd; - if (!s->f) + if (!s->stream) return; /* Ensure buffer is NULL-terminated */ - fprintf(s->f, "%c", 0); - fflush(s->f); + ast_iostream_write(s->stream, "", 1); + + fd = ast_iostream_get_fd(s->stream); - if ((l = ftell(s->f)) > 0) { - if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) { + l = lseek(fd, SEEK_CUR, 0); + if (l > 0) { + if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0))) { ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n"); } else { if (format == FORMAT_XML || format == FORMAT_HTML) { @@ -7614,6 +7587,7 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser, struct mansession s = { .session = NULL, .tcptls_session = ser }; struct mansession_session *session = NULL; uint32_t ident; + int fd; int blastaway = 0; struct ast_variable *v; struct ast_variable *params = get_params; @@ -7669,17 +7643,17 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser, } s.session = session; - s.fd = mkstemp(template); /* create a temporary file for command output */ + fd = mkstemp(template); /* create a temporary file for command output */ unlink(template); - if (s.fd <= -1) { + if (fd <= -1) { ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)"); goto generic_callback_out; } - s.f = fdopen(s.fd, "w+"); - if (!s.f) { + s.stream = ast_iostream_from_fd(&fd); + if (!s.stream) { ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)"); - close(s.fd); + close(fd); goto generic_callback_out; } @@ -7819,9 +7793,9 @@ static int generic_http_callback(struct ast_tcptls_session_instance *ser, if (blastaway) { session_destroy(session); } else { - if (session->f) { - fclose(session->f); - session->f = NULL; + if (session->stream) { + ast_iostream_close(session->stream); + session->stream = NULL; } unref_mansession(session); } @@ -7846,6 +7820,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser, struct message m = { 0 }; unsigned int idx; size_t hdrlen; + int fd; time_t time_now = time(NULL); unsigned long nonce = 0, nc; @@ -8024,17 +7999,17 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser, ast_mutex_init(&s.lock); s.session = session; - s.fd = mkstemp(template); /* create a temporary file for command output */ + fd = mkstemp(template); /* create a temporary file for command output */ unlink(template); - if (s.fd <= -1) { + if (fd <= -1) { ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)"); goto auth_callback_out; } - s.f = fdopen(s.fd, "w+"); - if (!s.f) { + s.stream = ast_iostream_from_fd(&fd); + if (!s.stream) { ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)"); - close(s.fd); + close(fd); goto auth_callback_out; } @@ -8085,7 +8060,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser, m.headers[idx] = NULL; } - result_size = ftell(s.f); /* Calculate approx. size of result */ + result_size = lseek(ast_iostream_get_fd(s.stream), SEEK_CUR, 0); /* Calculate approx. size of result */ http_header = ast_str_create(80); out = ast_str_create(result_size * 2 + 512); @@ -8137,11 +8112,10 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser, ast_free(out); ao2_lock(session); - if (session->f) { - fclose(session->f); + if (session->stream) { + ast_iostream_close(session->stream); + session->stream = NULL; } - session->f = NULL; - session->fd = -1; ao2_unlock(session); if (session->needdestroy) { diff --git a/main/tcptls.c b/main/tcptls.c index 262fca07443..c8ebab43470 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -47,506 +47,13 @@ #include "asterisk/astobj2.h" #include "asterisk/pbx.h" -/*! ao2 object used for the FILE stream fopencookie()/funopen() cookie. */ -struct ast_tcptls_stream { - /*! SSL state if not NULL */ - SSL *ssl; - /*! - * \brief Start time from when an I/O sequence must complete - * by struct ast_tcptls_stream.timeout. - * - * \note If struct ast_tcptls_stream.start.tv_sec is zero then - * start time is the current I/O request. - */ - struct timeval start; - /*! - * \brief The socket returned by accept(). - * - * \note Set to -1 if the stream is closed. - */ - int fd; - /*! - * \brief Timeout in ms relative to struct ast_tcptls_stream.start - * to wait for an event on struct ast_tcptls_stream.fd. - * - * \note Set to -1 to disable timeout. - * \note The socket needs to be set to non-blocking for the timeout - * feature to work correctly. - */ - int timeout; - /*! TRUE if stream can exclusively wait for fd input. */ - int exclusive_input; -}; - -void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream) -{ - ast_assert(stream != NULL); - - stream->timeout = -1; -} - -void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream, int timeout) -{ - ast_assert(stream != NULL); - - stream->start.tv_sec = 0; - stream->timeout = timeout; -} - -void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout) -{ - ast_assert(stream != NULL); - - stream->start = start; - stream->timeout = timeout; -} - -void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input) -{ - ast_assert(stream != NULL); - - stream->exclusive_input = exclusive_input; -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream read function. - * - * \param cookie Stream control data. - * \param buf Where to put read data. - * \param size Size of the buffer. - * - * \retval number of bytes put into buf. - * \retval 0 on end of file. - * \retval -1 on error. - */ -static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size) -{ - struct ast_tcptls_stream *stream = cookie; - struct timeval start; - int ms; - int res; - - if (!size) { - /* You asked for no data you got no data. */ - return 0; - } - - if (!stream || stream->fd == -1) { - errno = EBADF; - return -1; - } - - if (stream->start.tv_sec) { - start = stream->start; - } else { - start = ast_tvnow(); - } - -#if defined(DO_SSL) - if (stream->ssl) { - for (;;) { - res = SSL_read(stream->ssl, buf, size); - if (0 < res) { - /* We read some payload data. */ - return res; - } - switch (SSL_get_error(stream->ssl, res)) { - case SSL_ERROR_ZERO_RETURN: - /* Report EOF for a shutdown */ - ast_debug(1, "TLS clean shutdown alert reading data\n"); - return 0; - case SSL_ERROR_WANT_READ: - if (!stream->exclusive_input) { - /* We cannot wait for data now. */ - errno = EAGAIN; - return -1; - } - while ((ms = ast_remaining_ms(start, stream->timeout))) { - res = ast_wait_for_input(stream->fd, ms); - if (0 < res) { - /* Socket is ready to be read. */ - break; - } - if (res < 0) { - if (errno == EINTR || errno == EAGAIN) { - /* Try again. */ - continue; - } - ast_debug(1, "TLS socket error waiting for read data: %s\n", - strerror(errno)); - return -1; - } - } - break; - case SSL_ERROR_WANT_WRITE: - while ((ms = ast_remaining_ms(start, stream->timeout))) { - res = ast_wait_for_output(stream->fd, ms); - if (0 < res) { - /* Socket is ready to be written. */ - break; - } - if (res < 0) { - if (errno == EINTR || errno == EAGAIN) { - /* Try again. */ - continue; - } - ast_debug(1, "TLS socket error waiting for write space: %s\n", - strerror(errno)); - return -1; - } - } - break; - default: - /* Report EOF for an undecoded SSL or transport error. */ - ast_debug(1, "TLS transport or SSL error reading data\n"); - return 0; - } - if (!ms) { - /* Report EOF for a timeout */ - ast_debug(1, "TLS timeout reading data\n"); - return 0; - } - } - } -#endif /* defined(DO_SSL) */ - - for (;;) { - res = read(stream->fd, buf, size); - if (0 <= res || !stream->exclusive_input) { - /* Got data or we cannot wait for it. */ - return res; - } - if (errno != EINTR && errno != EAGAIN) { - /* Not a retryable error. */ - ast_debug(1, "TCP socket error reading data: %s\n", - strerror(errno)); - return -1; - } - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report EOF for a timeout */ - ast_debug(1, "TCP timeout reading data\n"); - return 0; - } - ast_wait_for_input(stream->fd, ms); - } -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream write function. - * - * \param cookie Stream control data. - * \param buf Where to get data to write. - * \param size Size of the buffer. - * - * \retval number of bytes written from buf. - * \retval -1 on error. - */ -static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size) -{ - struct ast_tcptls_stream *stream = cookie; - struct timeval start; - int ms; - int res; - int written; - int remaining; - - if (!size) { - /* You asked to write no data you wrote no data. */ - return 0; - } - - if (!stream || stream->fd == -1) { - errno = EBADF; - return -1; - } - - if (stream->start.tv_sec) { - start = stream->start; - } else { - start = ast_tvnow(); - } - -#if defined(DO_SSL) - if (stream->ssl) { - written = 0; - remaining = size; - for (;;) { - res = SSL_write(stream->ssl, buf + written, remaining); - if (res == remaining) { - /* Everything was written. */ - return size; - } - if (0 < res) { - /* Successfully wrote part of the buffer. Try to write the rest. */ - written += res; - remaining -= res; - continue; - } - switch (SSL_get_error(stream->ssl, res)) { - case SSL_ERROR_ZERO_RETURN: - ast_debug(1, "TLS clean shutdown alert writing data\n"); - if (written) { - /* Report partial write. */ - return written; - } - errno = EBADF; - return -1; - case SSL_ERROR_WANT_READ: - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report partial write. */ - ast_debug(1, "TLS timeout writing data (want read)\n"); - return written; - } - ast_wait_for_input(stream->fd, ms); - break; - case SSL_ERROR_WANT_WRITE: - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report partial write. */ - ast_debug(1, "TLS timeout writing data (want write)\n"); - return written; - } - ast_wait_for_output(stream->fd, ms); - break; - default: - /* Undecoded SSL or transport error. */ - ast_debug(1, "TLS transport or SSL error writing data\n"); - if (written) { - /* Report partial write. */ - return written; - } - errno = EBADF; - return -1; - } - } - } -#endif /* defined(DO_SSL) */ - - written = 0; - remaining = size; - for (;;) { - res = write(stream->fd, buf + written, remaining); - if (res == remaining) { - /* Yay everything was written. */ - return size; - } - if (0 < res) { - /* Successfully wrote part of the buffer. Try to write the rest. */ - written += res; - remaining -= res; - continue; - } - if (errno != EINTR && errno != EAGAIN) { - /* Not a retryable error. */ - ast_debug(1, "TCP socket error writing: %s\n", strerror(errno)); - if (written) { - return written; - } - return -1; - } - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report partial write. */ - ast_debug(1, "TCP timeout writing data\n"); - return written; - } - ast_wait_for_output(stream->fd, ms); - } -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream close function. - * - * \param cookie Stream control data. - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int tcptls_stream_close(void *cookie) -{ - struct ast_tcptls_stream *stream = cookie; - - if (!stream) { - errno = EBADF; - return -1; - } - - if (stream->fd != -1) { -#if defined(DO_SSL) - if (stream->ssl) { - int res; - - /* - * According to the TLS standard, it is acceptable for an - * application to only send its shutdown alert and then - * close the underlying connection without waiting for - * the peer's response (this way resources can be saved, - * as the process can already terminate or serve another - * connection). - */ - res = SSL_shutdown(stream->ssl); - if (res < 0) { - ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n", - SSL_get_error(stream->ssl, res)); - } - - if (!stream->ssl->server) { - /* For client threads, ensure that the error stack is cleared */ -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - ERR_remove_thread_state(NULL); -#else - ERR_remove_state(0); -#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ - } - - SSL_free(stream->ssl); - stream->ssl = NULL; - } -#endif /* defined(DO_SSL) */ - - /* - * Issuing shutdown() is necessary here to avoid a race - * condition where the last data written may not appear - * in the TCP stream. See ASTERISK-23548 - */ - shutdown(stream->fd, SHUT_RDWR); - if (close(stream->fd)) { - ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); - } - stream->fd = -1; - } - ao2_t_ref(stream, -1, "Closed tcptls stream cookie"); - - return 0; -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream destructor function. - * - * \param cookie Stream control data. - * - * \return Nothing - */ -static void tcptls_stream_dtor(void *cookie) -{ -#ifdef AST_DEVMODE - /* Since the ast_assert below is the only one using stream, - * and ast_assert is only available with AST_DEVMODE, we - * put this in a conditional to avoid compiler warnings. */ - struct ast_tcptls_stream *stream = cookie; -#endif - - ast_assert(stream->fd == -1); -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream allocation function. - * - * \retval stream_cookie on success. - * \retval NULL on error. - */ -static struct ast_tcptls_stream *tcptls_stream_alloc(void) -{ - struct ast_tcptls_stream *stream; - - stream = ao2_alloc_options(sizeof(*stream), tcptls_stream_dtor, - AO2_ALLOC_OPT_LOCK_NOLOCK); - if (stream) { - stream->fd = -1; - stream->timeout = -1; - } - return stream; -} - -/*! - * \internal - * \brief Open a custom FILE stream for tcptls. - * - * \param stream Stream cookie control data. - * \param ssl SSL state if not NULL. - * \param fd Socket file descriptor. - * \param timeout ms to wait for an event on fd. -1 if timeout disabled. - * - * \retval fp on success. - * \retval NULL on error. - */ -static FILE *tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout) -{ - FILE *fp; - -#if defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ - static const cookie_io_functions_t cookie_funcs = { - tcptls_stream_read, - tcptls_stream_write, - NULL, - tcptls_stream_close - }; -#endif /* defined(HAVE_FOPENCOOKIE) */ - - if (fd == -1) { - /* Socket not open. */ - return NULL; - } - - stream->ssl = ssl; - stream->fd = fd; - stream->timeout = timeout; - ao2_t_ref(stream, +1, "Opening tcptls stream cookie"); - -#if defined(HAVE_FUNOPEN) /* the BSD interface */ - fp = funopen(stream, tcptls_stream_read, tcptls_stream_write, NULL, - tcptls_stream_close); -#elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ - fp = fopencookie(stream, "w+", cookie_funcs); -#else - /* could add other methods here */ - ast_debug(2, "No stream FILE methods attempted!\n"); - fp = NULL; -#endif - - if (!fp) { - stream->fd = -1; - ao2_t_ref(stream, -1, "Failed to open tcptls stream cookie"); - } - return fp; -} - -HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count) -{ - if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) { - ast_log(LOG_ERROR, "TCP/TLS read called on invalid stream.\n"); - errno = EIO; - return -1; - } - - return tcptls_stream_read(tcptls_session->stream_cookie, buf, count); -} - -HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count) -{ - if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) { - ast_log(LOG_ERROR, "TCP/TLS write called on invalid stream.\n"); - errno = EIO; - return -1; - } - - return tcptls_stream_write(tcptls_session->stream_cookie, buf, count); -} - static void session_instance_destructor(void *obj) { struct ast_tcptls_session_instance *i = obj; - if (i->stream_cookie) { - ao2_t_ref(i->stream_cookie, -1, "Destroying tcptls session instance"); - i->stream_cookie = NULL; + if (i->stream) { + ast_iostream_close(i->stream); + i->stream = NULL; } ast_free(i->overflow_buf); ao2_cleanup(i->private_data); @@ -591,9 +98,7 @@ static void *handle_tcptls_connection(void *data) { struct ast_tcptls_session_instance *tcptls_session = data; #ifdef DO_SSL - int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept; - int ret; - char err[256]; + SSL *ssl; #endif /* TCP/TLS connections are associated with external protocols, and @@ -608,123 +113,94 @@ static void *handle_tcptls_connection(void *data) return NULL; } - tcptls_session->stream_cookie = tcptls_stream_alloc(); - if (!tcptls_session->stream_cookie) { - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; - } + if (tcptls_session->parent->tls_cfg) { +#ifdef DO_SSL + if (ast_iostream_start_tls(&tcptls_session->stream, tcptls_session->parent->tls_cfg->ssl_ctx, tcptls_session->client) < 0) { + ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; + } - /* - * open a FILE * as appropriate. - */ - if (!tcptls_session->parent->tls_cfg) { - tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, NULL, - tcptls_session->fd, -1); - if (tcptls_session->f) { - if (setvbuf(tcptls_session->f, NULL, _IONBF, 0)) { + ssl = ast_iostream_get_ssl(tcptls_session->stream); + if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) + || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { + X509 *peer; + long res; + peer = SSL_get_peer_certificate(ssl); + if (!peer) { + ast_log(LOG_ERROR, "No peer SSL certificate to verify\n"); ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; } - } - } -#ifdef DO_SSL - else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) { - SSL_set_fd(tcptls_session->ssl, tcptls_session->fd); - if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) { - ast_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err)); - } else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, - tcptls_session->ssl, tcptls_session->fd, -1))) { - if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) - || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { - X509 *peer; - long res; - peer = SSL_get_peer_certificate(tcptls_session->ssl); - if (!peer) { - ast_log(LOG_ERROR, "No peer SSL certificate to verify\n"); - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; - } - res = SSL_get_verify_result(tcptls_session->ssl); - if (res != X509_V_OK) { - ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); - X509_free(peer); - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; - } - if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { - ASN1_STRING *str; - X509_NAME *name = X509_get_subject_name(peer); - STACK_OF(GENERAL_NAME) *alt_names; - int pos = -1; - int found = 0; - - for (;;) { - /* Walk the certificate to check all available "Common Name" */ - /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ - pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); - if (pos < 0) { - break; - } - - str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); - if (!check_tcptls_cert_name(str, tcptls_session->parent->hostname, "common name")) { - found = 1; - break; - } + res = SSL_get_verify_result(ssl); + if (res != X509_V_OK) { + ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); + X509_free(peer); + ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; + } + if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { + ASN1_STRING *str; + X509_NAME *name = X509_get_subject_name(peer); + STACK_OF(GENERAL_NAME) *alt_names; + int pos = -1; + int found = 0; + + for (;;) { + /* Walk the certificate to check all available "Common Name" */ + /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ + pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); + if (pos < 0) { + break; } + str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); + if (!check_tcptls_cert_name(str, tcptls_session->parent->hostname, "common name")) { + found = 1; + break; + } + } - if (!found) { - alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL); - if (alt_names != NULL) { - int alt_names_count = sk_GENERAL_NAME_num(alt_names); - - for (pos = 0; pos < alt_names_count; pos++) { - const GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, pos); + if (!found) { + alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL); + if (alt_names != NULL) { + int alt_names_count = sk_GENERAL_NAME_num(alt_names); - if (alt_name->type != GEN_DNS) { - continue; - } + for (pos = 0; pos < alt_names_count; pos++) { + const GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, pos); - if (!check_tcptls_cert_name(alt_name->d.dNSName, tcptls_session->parent->hostname, "alt name")) { - found = 1; - break; - } + if (alt_name->type != GEN_DNS) { + continue; } - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); + if (!check_tcptls_cert_name(alt_name->d.dNSName, tcptls_session->parent->hostname, "alt name")) { + found = 1; + break; + } } - } - if (!found) { - ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); - X509_free(peer); - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); } } - X509_free(peer); + + if (!found) { + ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); + X509_free(peer); + ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; + } } + X509_free(peer); } - if (!tcptls_session->f) { /* no success opening descriptor stacking */ - SSL_free(tcptls_session->ssl); - } - } -#endif /* DO_SSL */ - - if (!tcptls_session->f) { +#else + ast_log(LOG_ERROR, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); ast_tcptls_close_session_file(tcptls_session); - ast_log(LOG_WARNING, "FILE * open failed!\n"); -#ifndef DO_SSL - if (tcptls_session->parent->tls_cfg) { - ast_log(LOG_ERROR, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); - } -#endif ao2_ref(tcptls_session, -1); return NULL; +#endif /* DO_SSL */ } if (tcptls_session->parent->worker_fn) { @@ -772,7 +248,13 @@ void *ast_tcptls_server_root(void *data) tcptls_session->overflow_buf = ast_str_create(128); flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); - tcptls_session->fd = fd; + + tcptls_session->stream = ast_iostream_from_fd(&fd); + if (!tcptls_session->stream) { + ast_log(LOG_WARNING, "No memory for new session iostream\n"); + continue; + } + tcptls_session->parent = desc; ast_sockaddr_copy(&tcptls_session->remote_address, &addr); @@ -1036,7 +518,7 @@ struct ast_tcptls_session_instance *ast_tcptls_client_start(struct ast_tcptls_se struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_session_args *desc) { - int x = 1; + int fd, x = 1; struct ast_tcptls_session_instance *tcptls_session = NULL; /* Do nothing if nothing has changed */ @@ -1052,8 +534,8 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s close(desc->accept_fd); } - desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? - AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); + fd = desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? + AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); if (desc->accept_fd < 0) { ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); @@ -1079,7 +561,11 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s tcptls_session->overflow_buf = ast_str_create(128); tcptls_session->client = 1; - tcptls_session->fd = desc->accept_fd; + tcptls_session->stream = ast_iostream_from_fd(&fd); + if (!tcptls_session->stream) { + goto error; + } + tcptls_session->parent = desc; tcptls_session->parent->worker_fn = NULL; ast_sockaddr_copy(&tcptls_session->remote_address, @@ -1170,24 +656,9 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session) { - if (tcptls_session->f) { - fflush(tcptls_session->f); - if (fclose(tcptls_session->f)) { - ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); - } - tcptls_session->f = NULL; - tcptls_session->fd = -1; - } else if (tcptls_session->fd != -1) { - /* - * Issuing shutdown() is necessary here to avoid a race - * condition where the last data written may not appear - * in the TCP stream. See ASTERISK-23548 - */ - shutdown(tcptls_session->fd, SHUT_RDWR); - if (close(tcptls_session->fd)) { - ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); - } - tcptls_session->fd = -1; + if (tcptls_session->stream) { + ast_iostream_close(tcptls_session->stream); + tcptls_session->stream = NULL; } else { ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); } diff --git a/main/utils.c b/main/utils.c index 775fae3af8c..2c56af3cdc5 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1462,68 +1462,6 @@ int ast_carefulwrite(int fd, char *s, int len, int timeoutms) return res; } -int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms) -{ - struct timeval start = ast_tvnow(); - int n = 0; - int elapsed = 0; - - while (len) { - if (wait_for_output(fd, timeoutms - elapsed)) { - /* poll returned a fatal error, so bail out immediately. */ - return -1; - } - - /* Clear any errors from a previous write */ - clearerr(f); - - n = fwrite(src, 1, len, f); - - if (ferror(f) && errno != EINTR && errno != EAGAIN) { - /* fatal error from fwrite() */ - if (!feof(f)) { - /* Don't spam the logs if it was just that the connection is closed. */ - ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno)); - } - n = -1; - break; - } - - /* Update for data already written to the socket */ - len -= n; - src += n; - - elapsed = ast_tvdiff_ms(ast_tvnow(), start); - if (elapsed >= timeoutms) { - /* We've taken too long to write - * This is only an error condition if we haven't finished writing. */ - n = len ? -1 : 0; - break; - } - } - - errno = 0; - while (fflush(f)) { - if (errno == EAGAIN || errno == EINTR) { - /* fflush() does not appear to reset errno if it flushes - * and reaches EOF at the same time. It returns EOF with - * the last seen value of errno, causing a possible loop. - * Also usleep() to reduce CPU eating if it does loop */ - errno = 0; - usleep(1); - continue; - } - if (errno && !feof(f)) { - /* Don't spam the logs if it was just that the connection is closed. */ - ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno)); - } - n = -1; - break; - } - - return n < 0 ? -1 : 0; -} - char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes) { char *e; diff --git a/res/res_http_post.c b/res/res_http_post.c index 241edfe5937..3f0a58e36b8 100644 --- a/res/res_http_post.c +++ b/res/res_http_post.c @@ -211,7 +211,7 @@ static int find_sequence(char * inbuf, int inlen, char * matchbuf, int matchlen) * This function has two modes. The first to find a boundary marker. The * second is to find the filename immediately after the boundary. */ -static int readmimefile(FILE *fin, FILE *fout, char *boundary, int contentlen) +static int readmimefile(struct ast_iostream *in, FILE *fout, char *boundary, int contentlen) { int find_filename = 0; char buf[4096]; @@ -222,7 +222,7 @@ static int readmimefile(FILE *fin, FILE *fout, char *boundary, int contentlen) int boundary_len; char * path_end, * path_start, * filespec; - if (NULL == fin || NULL == fout || NULL == boundary || 0 >= contentlen) { + if (NULL == in || NULL == fout || NULL == boundary || 0 >= contentlen) { return -1; } @@ -236,8 +236,8 @@ static int readmimefile(FILE *fin, FILE *fout, char *boundary, int contentlen) } if (0 < num_to_read) { - if (fread(&(buf[char_in_buf]), 1, num_to_read, fin) < num_to_read) { - ast_log(LOG_WARNING, "fread() failed: %s\n", strerror(errno)); + if (ast_iostream_read(in, &(buf[char_in_buf]), num_to_read) < num_to_read) { + ast_log(LOG_WARNING, "read failed: %s\n", strerror(errno)); num_to_read = 0; } contentlen -= num_to_read; @@ -378,7 +378,7 @@ static int http_post_callback(struct ast_tcptls_session_instance *ser, const str */ ast_http_body_read_status(ser, 0); - if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) { + if (0 > readmimefile(ser->stream, f, boundary_marker, content_len)) { ast_debug(1, "Cannot find boundary marker in POST request.\n"); fclose(f); ast_http_error(ser, 400, "Bad Request", "Cannot find boundary marker in POST request."); diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 28bf45fc8ce..cb5e5ff91b5 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -73,8 +73,7 @@ /*! \brief Structure definition for session */ struct ast_websocket { - FILE *f; /*!< Pointer to the file instance used for writing and reading */ - int fd; /*!< File descriptor for the session, only used for polling */ + struct ast_iostream *stream; /*!< iostream of the connection */ struct ast_sockaddr address; /*!< Address of the remote client */ enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */ size_t payload_len; /*!< Length of the payload */ @@ -165,10 +164,11 @@ static void session_destroy_fn(void *obj) { struct ast_websocket *session = obj; - if (session->f) { + if (session->stream) { ast_websocket_close(session, 0); - if (session->f) { - fclose(session->f); + if (session->stream) { + ast_iostream_close(session->stream); + session->stream = NULL; ast_verb(2, "WebSocket connection %s '%s' closed\n", session->client ? "to" : "from", ast_sockaddr_stringify(&session->address)); } @@ -294,20 +294,22 @@ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, ui session->close_sent = 1; ao2_lock(session); - res = ast_careful_fwrite(session->f, session->fd, frame, 4, session->timeout); + ast_iostream_set_timeout_inactivity(session->stream, session->timeout); + res = ast_iostream_write(session->stream, frame, sizeof(frame)); + ast_iostream_set_timeout_disable(session->stream); /* If an error occurred when trying to close this connection explicitly terminate it now. * Doing so will cause the thread polling on it to wake up and terminate. */ - if (res) { - fclose(session->f); - session->f = NULL; + if (res != sizeof(frame)) { + ast_iostream_close(session->stream); + session->stream = NULL; ast_verb(2, "WebSocket connection %s '%s' forcefully closed due to fatal write error\n", session->client ? "to" : "from", ast_sockaddr_stringify(&session->address)); } ao2_unlock(session); - return res; + return res == sizeof(frame); } static const char *opcode_map[] = { @@ -375,7 +377,8 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en return -1; } - if (ast_careful_fwrite(session->f, session->fd, frame, frame_size, session->timeout)) { + ast_iostream_set_timeout_sequence(session->stream, ast_tvnow(), session->timeout); + if (ast_iostream_write(session->stream, frame, frame_size) != frame_size) { ao2_unlock(session); /* 1011 - server terminating connection due to not being able to fulfill the request */ ast_debug(1, "Closing WS with 1011 because we can't fulfill a write request\n"); @@ -383,7 +386,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en return -1; } - fflush(session->f); + ast_iostream_set_timeout_disable(session->stream); ao2_unlock(session); return 0; @@ -411,7 +414,7 @@ void AST_OPTIONAL_API_NAME(ast_websocket_unref)(struct ast_websocket *session) int AST_OPTIONAL_API_NAME(ast_websocket_fd)(struct ast_websocket *session) { - return session->closing ? -1 : session->fd; + return session->closing ? -1 : ast_iostream_get_fd(session->stream); } struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_remote_address)(struct ast_websocket *session) @@ -426,18 +429,8 @@ int AST_OPTIONAL_API_NAME(ast_websocket_is_secure)(struct ast_websocket *session int AST_OPTIONAL_API_NAME(ast_websocket_set_nonblock)(struct ast_websocket *session) { - int flags; - - if ((flags = fcntl(session->fd, F_GETFL)) == -1) { - return -1; - } - - flags |= O_NONBLOCK; - - if ((flags = fcntl(session->fd, F_SETFL, flags)) == -1) { - return -1; - } - + ast_iostream_nonblock(session->stream); + ast_iostream_set_exclusive_input(session->stream, 0); return 0; } @@ -490,17 +483,16 @@ static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len int sanity = 10; ao2_lock(session); - if (!session->f) { + if (!session->stream) { ao2_unlock(session); errno = ECONNABORTED; return -1; } for (;;) { - clearerr(session->f); - rlen = fread(rbuf, 1, xlen, session->f); - if (!rlen) { - if (feof(session->f)) { + rlen = ast_iostream_read(session->stream, rbuf, xlen); + if (rlen != xlen) { + if (rlen == 0) { ast_log(LOG_WARNING, "Web socket closed abruptly\n"); *opcode = AST_WEBSOCKET_OPCODE_CLOSE; session->closing = 1; @@ -508,7 +500,7 @@ static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len return -1; } - if (ferror(session->f) && errno != EAGAIN) { + if (rlen < 0 && errno != EAGAIN) { ast_log(LOG_ERROR, "Error reading from web socket: %s\n", strerror(errno)); *opcode = AST_WEBSOCKET_OPCODE_CLOSE; session->closing = 1; @@ -529,7 +521,7 @@ static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len if (!xlen) { break; } - if (ast_wait_for_input(session->fd, 1000) < 0) { + if (ast_wait_for_input(ast_iostream_get_fd(session->stream), 1000) < 0) { ast_log(LOG_ERROR, "ast_wait_for_input returned err: %s\n", strerror(errno)); *opcode = AST_WEBSOCKET_OPCODE_CLOSE; session->closing = 1; @@ -824,7 +816,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan ao2_ref(protocol_handler, -1); return 0; } - session->timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT; + session->timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT; /* Generate the session id */ if (!ast_uuid_generate_str(session->session_id, sizeof(session->session_id))) { @@ -854,7 +846,8 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan * Connection_. */ if (protocol) { - fprintf(ser->f, "HTTP/1.1 101 Switching Protocols\r\n" + ast_iostream_printf(ser->stream, + "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: %s\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: %s\r\n" @@ -863,15 +856,14 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan websocket_combine_key(key, base64, sizeof(base64)), protocol); } else { - fprintf(ser->f, "HTTP/1.1 101 Switching Protocols\r\n" + ast_iostream_printf(ser->stream, + "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: %s\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: %s\r\n\r\n", upgrade, websocket_combine_key(key, base64, sizeof(base64))); } - - fflush(ser->f); } else { /* Specification defined in http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 or completely unknown */ @@ -883,7 +875,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan } /* Enable keepalive on all sessions so the underlying user does not have to */ - if (setsockopt(ser->fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) { + if (setsockopt(ast_iostream_get_fd(ser->stream), SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags))) { ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to enable keepalive\n", ast_sockaddr_stringify(&ser->remote_address)); websocket_bad_request(ser); @@ -895,25 +887,23 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol ? : "", version); /* Populate the session with all the needed details */ - session->f = ser->f; - session->fd = ser->fd; + session->stream = ser->stream; ast_sockaddr_copy(&session->address, &ser->remote_address); session->opcode = -1; session->reconstruct = DEFAULT_RECONSTRUCTION_CEILING; - session->secure = ser->ssl ? 1 : 0; + session->secure = ast_iostream_get_ssl(ser->stream) ? 1 : 0; /* Give up ownership of the socket and pass it to the protocol handler */ - ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 0); + ast_iostream_set_exclusive_input(session->stream, 0); protocol_handler->session_established(session, get_vars, headers); ao2_ref(protocol_handler, -1); /* - * By dropping the FILE* and fd from the session the connection + * By dropping the stream from the session the connection * won't get closed when the HTTP server cleans up because we * passed the connection to the protocol handler. */ - ser->f = NULL; - ser->fd = -1; + ser->stream = NULL; return 0; } @@ -1247,7 +1237,7 @@ static enum ast_websocket_result websocket_client_handshake_get_response( int has_accept = 0; int has_protocol = 0; - if (!fgets(buf, sizeof(buf), client->ser->f)) { + if (ast_iostream_gets(client->ser->stream, buf, sizeof(buf)) <= 0) { ast_log(LOG_ERROR, "Unable to retrieve HTTP status line."); return WS_BAD_STATUS; } @@ -1260,7 +1250,7 @@ static enum ast_websocket_result websocket_client_handshake_get_response( /* Ignoring line folding - assuming header field values are contained within a single line */ - while (fgets(buf, sizeof(buf), client->ser->f)) { + while (ast_iostream_gets(client->ser->stream, buf, sizeof(buf)) > 0) { char *name, *value; int parsed = ast_http_header_parse(buf, &name, &value); @@ -1313,19 +1303,19 @@ static enum ast_websocket_result websocket_client_handshake( client->protocols); } - if (fprintf(client->ser->f, - "GET /%s HTTP/1.1\r\n" - "Sec-WebSocket-Version: %d\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Host: %s\r\n" - "Sec-WebSocket-Key: %s\r\n" - "%s\r\n", - client->resource_name ? ast_str_buffer(client->resource_name) : "", - client->version, - client->host, - client->key, - protocols) < 0) { + if (ast_iostream_printf(client->ser->stream, + "GET /%s HTTP/1.1\r\n" + "Sec-WebSocket-Version: %d\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Host: %s\r\n" + "Sec-WebSocket-Key: %s\r\n" + "%s\r\n", + client->resource_name ? ast_str_buffer(client->resource_name) : "", + client->version, + client->host, + client->key, + protocols) < 0) { ast_log(LOG_ERROR, "Failed to send handshake.\n"); return WS_WRITE_ERROR; } @@ -1349,9 +1339,9 @@ static enum ast_websocket_result websocket_client_connect(struct ast_websocket * return res; } - ws->f = ws->client->ser->f; - ws->fd = ws->client->ser->fd; - ws->secure = ws->client->ser->ssl ? 1 : 0; + ws->stream = ws->client->ser->stream; + ws->secure = ast_iostream_get_ssl(ws->stream) ? 1 : 0; + ws->client->ser->stream = NULL; ast_sockaddr_copy(&ws->address, &ws->client->ser->remote_address); return WS_OK; } diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c index 132c842ad6a..92eec318fb8 100644 --- a/res/res_phoneprov.c +++ b/res/res_phoneprov.c @@ -949,7 +949,7 @@ static int phoneprov_callback(struct ast_tcptls_session_instance *ser, const str socklen_t namelen = sizeof(name.sa); int res; - if ((res = getsockname(ser->fd, &name.sa, &namelen))) { + if ((res = getsockname(ast_iostream_get_fd(ser->stream), &name.sa, &namelen))) { ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n"); } else { struct extension *exten_iter; From 3017f09f227258f21fbdcfeb05fb60064dd09b7d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 15 Nov 2016 11:01:04 -0700 Subject: [PATCH 0898/1578] file.c/__ast_file_read_dirs: Fix issues on filesystems without d_type One of the code paths in __ast_file_read_dirs will only get executed if the OS doesn't support dirent->d_type OR if the filesystem the particular file is on doesn't support it. So, while standard Linux systems support the field, some filesystems like XFS do not. In this case, we need to call stat() to determine whether the directory entry is a file or directory so we append the filename to the supplied directory path and call stat. We forgot to truncate path back to just the directory afterwards though so we were passing a complete file name to the callback in the dir_name parameter instead of just the directory name. The logic has been re-written to only create a full_path if we need to call stat() or if we need to descend into another directory. Change-Id: I54e4228bd8355fad65200c6df3ec4c9c8a98dfba --- main/file.c | 65 ++++++++++++++++++++--------------------------- tests/test_file.c | 14 ++++++++++ 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/main/file.c b/main/file.c index 37b9e791177..fb4ede6c88b 100644 --- a/main/file.c +++ b/main/file.c @@ -1093,27 +1093,27 @@ int ast_filecopy(const char *filename, const char *filename2, const char *fmt) return filehelper(filename, filename2, fmt, ACTION_COPY); } -static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, +static int __ast_file_read_dirs(const char *path, ast_file_on_file on_file, void *obj, int max_depth) { DIR *dir; struct dirent *entry; - size_t size; int res; - if (!(dir = opendir(ast_str_buffer(*path)))) { + if (!(dir = opendir(path))) { ast_log(LOG_ERROR, "Error opening directory - %s: %s\n", - ast_str_buffer(*path), strerror(errno)); + path, strerror(errno)); return -1; } - size = ast_str_strlen(*path); --max_depth; res = 0; while ((entry = readdir(dir)) != NULL && !errno) { - int is_file, is_dir, used_stat = 0; + int is_file = 0; + int is_dir = 0; + RAII_VAR(char *, full_path, NULL, ast_free); if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { continue; @@ -1128,23 +1128,24 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) { is_file = entry->d_type == DT_REG; is_dir = entry->d_type == DT_DIR; - ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, NO USE STAT used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); } else #endif { struct stat statbuf; /* - * If using the stat function the file needs to be appended to the - * path so it can be found. However, before appending make sure the - * path contains only the directory for this depth level. + * Don't use alloca or we risk blowing out the stack if recursing + * into subdirectories. */ - ast_str_truncate(*path, size); - ast_str_append(path, 0, "/%s", entry->d_name); + full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2); + if (!full_path) { + return -1; + } + sprintf(full_path, "%s/%s", path, entry->d_name); - if (stat(ast_str_buffer(*path), &statbuf)) { + if (stat(full_path, &statbuf)) { ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n", - ast_str_buffer(*path), strerror(errno)); + full_path, strerror(errno)); /* * Output an error, but keep going. It could just be * a broken link and other files could be fine. @@ -1154,13 +1155,11 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, is_file = S_ISREG(statbuf.st_mode); is_dir = S_ISDIR(statbuf.st_mode); - used_stat = 1; - ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s, WE USED IT YO used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); } if (is_file) { /* If the handler returns non-zero then stop */ - if ((res = on_file(ast_str_buffer(*path), entry->d_name, obj))) { + if ((res = on_file(path, entry->d_name, obj))) { break; } /* Otherwise move on to next item in directory */ @@ -1168,25 +1167,22 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, } if (!is_dir) { - ast_debug(5, "Skipping %s: not a regular file or directory\n", - ast_str_buffer(*path)); + ast_debug(5, "Skipping %s: not a regular file or directory\n", full_path); continue; } /* Only re-curse into sub-directories if not at the max depth */ if (max_depth != 0) { - /* - * If the stat function was used then the sub-directory has - * already been appended, otherwise append it. - */ - ast_log(LOG_VERBOSE, "!###### do dir d_name=%s, path=%s, used_stat=%d\n", entry->d_name, ast_str_buffer(*path), used_stat); - if (!used_stat) { - ast_str_truncate(*path, size); - ast_str_append(path, 0, "/%s", entry->d_name); - ast_log(LOG_VERBOSE, "!###### d_name=%s, path=%s\n", entry->d_name, ast_str_buffer(*path)); + if (!full_path) { + /* Don't use alloca. See note above. */ + full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2); + if (!full_path) { + return -1; + } + sprintf(full_path, "%s/%s", path, entry->d_name); } - if ((res = __ast_file_read_dirs(path, on_file, obj, max_depth))) { + if ((res = __ast_file_read_dirs(full_path, on_file, obj, max_depth))) { break; } } @@ -1196,7 +1192,7 @@ static int __ast_file_read_dirs(struct ast_str **path, ast_file_on_file on_file, if (!res && errno) { ast_log(LOG_ERROR, "Error while reading directories - %s: %s\n", - ast_str_buffer(*path), strerror(errno)); + path, strerror(errno)); res = -1; } @@ -1217,27 +1213,20 @@ AST_MUTEX_DEFINE_STATIC(read_dirs_lock); int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth) { - struct ast_str *path; int res; - if (!(path = ast_str_create(256))) { - return -1; - } - - ast_str_set(&path, 0, "%s", dir_name); errno = 0; #if !defined(__GLIBC__) ast_mutex_lock(&read_dirs_lock); #endif - res = __ast_file_read_dirs(&path, on_file, obj, max_depth); + res = __ast_file_read_dirs(dir_name, on_file, obj, max_depth); #if !defined(__GLIBC__) ast_mutex_unlock(&read_dirs_lock); #endif - ast_free(path); return res; } diff --git a/tests/test_file.c b/tests/test_file.c index 64bad9218d9..bb8a99584d1 100644 --- a/tests/test_file.c +++ b/tests/test_file.c @@ -21,7 +21,10 @@ core ***/ + #include "asterisk.h" +#include +#include #include "asterisk/file.h" #include "asterisk/paths.h" @@ -115,6 +118,17 @@ static char *test_files_get_one(struct _filenames *filenames, int num) static int handle_find_file(const char *dir_name, const char *filename, void *obj) { + struct stat statbuf; + char *full_path = ast_alloca(strlen(dir_name) + strlen(filename) + 2); + + sprintf(full_path, "%s/%s", dir_name, filename); + + errno = 0; + if (stat(full_path, &statbuf)) { + ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n", + full_path, strerror(errno)); + return 0; + } /* obj contains the name of the file we are looking for */ return strcmp(obj, filename) ? 0 : FOUND; } From 0cd0e70c16680e155cb0ba2964bdacf6a5b0e52c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 14 Nov 2016 14:36:52 -0600 Subject: [PATCH 0899/1578] res_pjsip_outbound_authenticator_digest.c: Fix memory pool leak. Responding to authentication challenges leaks PJSIP memory pools. The leak was introduced with a pjproject 2.5.5 API change. https://trac.pjsip.org/repos/ticket/1929 changed the API usage of pjsip_auth_clt_init() to require the new API pjsip_auth_clt_deinit() to clean up cached authentication allocations that get allocated with pjsip_auth_clt_reinit_req(). ASTERISK-26516 #close Change-Id: I4473141b8c3961d0dc91c382beb3876b3efb45c8 --- configure | 123 ++++++++++++++++++ configure.ac | 2 + include/asterisk/autoconfig.h.in | 3 + res/res_pjsip_outbound_authenticator_digest.c | 13 +- third-party/pjproject/configure.m4 | 1 + 5 files changed, 140 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 5d21730e9d0..e90b3528723 100755 --- a/configure +++ b/configure @@ -943,6 +943,10 @@ PBX_POPT POPT_DIR POPT_INCLUDE POPT_LIB +PBX_PJSIP_AUTH_CLT_DEINIT +PJSIP_AUTH_CLT_DEINIT_DIR +PJSIP_AUTH_CLT_DEINIT_INCLUDE +PJSIP_AUTH_CLT_DEINIT_LIB PBX_PJSIP_INV_SESSION_REF PJSIP_INV_SESSION_REF_DIR PJSIP_INV_SESSION_REF_INCLUDE @@ -9292,6 +9296,9 @@ $as_echo "#define HAVE_PJSIP_EVSUB_GRP_LOCK 1" >>confdefs.h $as_echo "#define HAVE_PJSIP_INV_SESSION_REF 1" >>confdefs.h +$as_echo "#define HAVE_PJSIP_AUTH_CLT_DEINIT 1" >>confdefs.h + + @@ -11462,6 +11469,18 @@ PBX_PJSIP_INV_SESSION_REF=0 + +PJSIP_AUTH_CLT_DEINIT_DESCRIP="pjsip_auth_clt_deinit support" +PJSIP_AUTH_CLT_DEINIT_OPTION=pjsip +PJSIP_AUTH_CLT_DEINIT_DIR=${PJPROJECT_DIR} + +PBX_PJSIP_AUTH_CLT_DEINIT=0 + + + + + + fi @@ -26423,6 +26442,110 @@ _ACEOF fi + +if test "x${PBX_PJSIP_AUTH_CLT_DEINIT}" != "x1" -a "${USE_PJSIP_AUTH_CLT_DEINIT}" != "no"; then + pbxlibdir="" + # if --with-PJSIP_AUTH_CLT_DEINIT=DIR has been specified, use it. + if test "x${PJSIP_AUTH_CLT_DEINIT_DIR}" != "x"; then + if test -d ${PJSIP_AUTH_CLT_DEINIT_DIR}/lib; then + pbxlibdir="-L${PJSIP_AUTH_CLT_DEINIT_DIR}/lib" + else + pbxlibdir="-L${PJSIP_AUTH_CLT_DEINIT_DIR}" + fi + fi + pbxfuncname="pjsip_auth_clt_deinit" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_PJSIP_AUTH_CLT_DEINIT_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS" + as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_PJSIP_AUTH_CLT_DEINIT_FOUND=yes +else + AST_PJSIP_AUTH_CLT_DEINIT_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_PJSIP_AUTH_CLT_DEINIT_FOUND}" = "yes"; then + PJSIP_AUTH_CLT_DEINIT_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB" + # if --with-PJSIP_AUTH_CLT_DEINIT=DIR has been specified, use it. + if test "x${PJSIP_AUTH_CLT_DEINIT_DIR}" != "x"; then + PJSIP_AUTH_CLT_DEINIT_INCLUDE="-I${PJSIP_AUTH_CLT_DEINIT_DIR}/include" + fi + PJSIP_AUTH_CLT_DEINIT_INCLUDE="${PJSIP_AUTH_CLT_DEINIT_INCLUDE} $PJPROJECT_CFLAGS" + if test "xpjsip.h" = "x" ; then # no header, assume found + PJSIP_AUTH_CLT_DEINIT_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${PJSIP_AUTH_CLT_DEINIT_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default" +if test "x$ac_cv_header_pjsip_h" = xyes; then : + PJSIP_AUTH_CLT_DEINIT_HEADER_FOUND=1 +else + PJSIP_AUTH_CLT_DEINIT_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${PJSIP_AUTH_CLT_DEINIT_HEADER_FOUND}" = "x0" ; then + PJSIP_AUTH_CLT_DEINIT_LIB="" + PJSIP_AUTH_CLT_DEINIT_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + PJSIP_AUTH_CLT_DEINIT_LIB="" + fi + PBX_PJSIP_AUTH_CLT_DEINIT=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_PJSIP_AUTH_CLT_DEINIT 1 +_ACEOF + + fi + fi +fi + + fi fi diff --git a/configure.ac b/configure.ac index ea55df41634..db21fb3a658 100644 --- a/configure.ac +++ b/configure.ac @@ -510,6 +510,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EXTERNAL_RESOLVER], [PJSIP External Resolver S AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_PROTO], [PJSIP TLS Transport proto field support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_GRP_LOCK], [PJSIP EVSUB Group Lock support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_SESSION_REF], [PJSIP INVITE Session Reference Count support], [PJPROJECT], [pjsip]) +AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_AUTH_CLT_DEINIT], [pjsip_auth_clt_deinit support], [PJPROJECT], [pjsip]) fi AST_EXT_LIB_SETUP([POPT], [popt], [popt]) @@ -2233,6 +2234,7 @@ if test "$USE_PJPROJECT" != "no" ; then AST_EXT_LIB_CHECK([PJSIP_EVSUB_GRP_LOCK], [pjsip], [pjsip_evsub_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJSIP_INV_SESSION_REF], [pjsip], [pjsip_inv_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJSIP_AUTH_CLT_DEINIT], [pjsip], [pjsip_auth_clt_deinit], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) fi fi diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 706798ced35..bac2ecf487d 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -592,6 +592,9 @@ /* Define if your system has PJPROJECT_BUNDLED */ #undef HAVE_PJPROJECT_BUNDLED +/* Define to 1 if PJPROJECT has the pjsip_auth_clt_deinit support feature. */ +#undef HAVE_PJSIP_AUTH_CLT_DEINIT + /* Define to 1 if PJPROJECT has the PJSIP Dialog Create UAS with Incremented Lock feature. */ #undef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c index 86a15c7b750..ce77c3bad15 100644 --- a/res/res_pjsip_outbound_authenticator_digest.c +++ b/res/res_pjsip_outbound_authenticator_digest.c @@ -106,6 +106,7 @@ static int digest_create_request_with_auth(const struct ast_sip_auth_vector *aut { pjsip_auth_clt_sess auth_sess; pjsip_cseq_hdr *cseq; + pj_status_t status; if (pjsip_auth_clt_init(&auth_sess, ast_sip_get_pjsip_endpoint(), old_request->pool, 0) != PJ_SUCCESS) { @@ -115,11 +116,19 @@ static int digest_create_request_with_auth(const struct ast_sip_auth_vector *aut if (set_outbound_authentication_credentials(&auth_sess, auths, challenge)) { ast_log(LOG_WARNING, "Failed to set authentication credentials\n"); +#if defined(HAVE_PJSIP_AUTH_CLT_DEINIT) + /* In case it is not a noop here in the future. */ + pjsip_auth_clt_deinit(&auth_sess); +#endif return -1; } - switch (pjsip_auth_clt_reinit_req(&auth_sess, challenge, - old_request, new_request)) { + status = pjsip_auth_clt_reinit_req(&auth_sess, challenge, old_request, new_request); +#if defined(HAVE_PJSIP_AUTH_CLT_DEINIT) + /* Release any cached auths */ + pjsip_auth_clt_deinit(&auth_sess); +#endif + switch (status) { case PJ_SUCCESS: /* PJSIP creates a new transaction for new_request (meaning it creates a new * branch). However, it recycles the Call-ID, from-tag, and CSeq from the diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 870468257b3..7c60c2a02bc 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -55,6 +55,7 @@ AC_DEFUN([_PJPROJECT_CONFIGURE], AC_DEFINE([HAVE_PJSIP_TLS_TRANSPORT_PROTO], 1, [Define if your system has PJSIP_TLS_TRANSPORT_PROTO]) AC_DEFINE([HAVE_PJSIP_EVSUB_GRP_LOCK], 1, [Define if your system has PJSIP_EVSUB_GRP_LOCK]) AC_DEFINE([HAVE_PJSIP_INV_SESSION_REF], 1, [Define if your system has PJSIP_INV_SESSION_REF]) + AC_DEFINE([HAVE_PJSIP_AUTH_CLT_DEINIT], 1, [Define if your system has pjsip_auth_clt_deinit declared.]) AC_SUBST([PJPROJECT_BUNDLED]) AC_SUBST([PJPROJECT_DIR]) From ed9ced0531108b056b89c789df5c40b8b53db5ae Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 15 Nov 2016 16:23:35 -0600 Subject: [PATCH 0900/1578] codec_opus: Fix warning when Opus negotiated but codec_opus not loaded. When Opus is negotiated but not loaded, the log is spammed with messages because the system does not know how to calculate the number of samples in a frame. * Suppress the warning by supplying a function that assumes 20ms of samples in the frame. For pass through support it doesn't really seem to matter what number of samples is returned anyway. ASTERISK-26605 #close Change-Id: Icf2273692f040dc2c45b01e72a790d11092f9e0f --- main/codec_builtin.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/main/codec_builtin.c b/main/codec_builtin.c index cc4edd23990..f622c910575 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -729,6 +729,21 @@ static struct ast_codec g719 = { .get_length = g719_length, }; +static int opus_samples(struct ast_frame *frame) +{ + /* + * XXX This is likely not at all what's intended from this + * callback. If you have codec_opus.so loaded then this + * function is overridden anyway. However, since opus is + * variable bit rate and I cannot extract the calculation code + * from the opus library, I am going to punt and assume 20ms + * worth of samples. In testing, this has worked just fine. + * Pass through support doesn't seem to care about the value + * returned anyway. + */ + return ast_format_get_sample_rate(frame->subclass.format) / 50; +} + static struct ast_codec opus = { .name = "opus", .description = "Opus Codec", @@ -737,6 +752,7 @@ static struct ast_codec opus = { .minimum_ms = 20, .maximum_ms = 60, .default_ms = 20, + .samples_count = opus_samples, .minimum_bytes = 10, }; From dc8f99ee27bd9c2ed2524bf01825ac65234f59ba Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 16 Nov 2016 15:42:39 -0600 Subject: [PATCH 0901/1578] res_format_attr_opus: Fix fmtp generation. res_format_attr_opus assumed that the string being passed into it was empty. It tried to determine if the only thing it had written was a=fmtp: And if it had, it would reset the string. Its calculation was off when working with chan_sip, though. chan_sip passes the entire built SDP rather than an empty string. This resulted in always putting an empty fmtp line in the SDP. ASTERISK-26520 #close Reported by scgm11 Change-Id: Ib2e8712d26a47067e5f36d5973577added01dbb5 --- res/res_format_attr_opus.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index a3e48e3de79..81a07a1f6dc 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -156,7 +156,8 @@ static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, c static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { struct opus_attr *attr = ast_format_get_attribute_data(format); - int size; + int base_fmtp_size; + int original_size; if (!attr) { /* @@ -167,7 +168,8 @@ static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int attr = &default_opus_attr; } - size = ast_str_append(str, 0, "a=fmtp:%u ", payload); + original_size = ast_str_strlen(*str); + base_fmtp_size = ast_str_append(str, 0, "a=fmtp:%u ", payload); if (CODEC_OPUS_DEFAULT_SAMPLE_RATE != attr->maxplayrate) { ast_str_append(str, 0, "%s=%d;", @@ -209,8 +211,8 @@ static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int CODEC_OPUS_ATTR_DTX, attr->dtx); } - if (size == ast_str_strlen(*str)) { - ast_str_reset(*str); + if (base_fmtp_size == ast_str_strlen(*str) - original_size) { + ast_str_truncate(*str, original_size); } else { ast_str_truncate(*str, -1); ast_str_append(str, 0, "\r\n"); From 935f5d003bb19e4ecb683bdb6d5896d02f26f539 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 16 Nov 2016 19:24:08 -0700 Subject: [PATCH 0902/1578] build: Various OpenBSD issues OpenBSD's 'find' doesn't take the -delete argument so you have to pipe through 'xargs rm -rf'. 'echo -e' doesn't like \t starting a line. It just prints 't' which causes the libasteriskpj.exports file to be garbage. They were just cosmetic so they were removed. librt doesn't exist so the link of libasteriskpj.so fails. It's not actually needed for linux anyway so -lrt was removed from the link. res_rtp_asterisk was failing to load because of an undefined DTLS_method. '|| defined(LIBRESSL_VERSION_NUMBER)' was added to the #if so DTLSv1_method is used instead. ASTERISK-26608 Change-Id: I926ec95b0b69633231e3ad1d6e803b977272c49c --- main/Makefile | 10 +++++----- res/res_rtp_asterisk.c | 2 +- third-party/pjproject/Makefile | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/main/Makefile b/main/Makefile index 3db0392ff37..0c1b11ed83c 100644 --- a/main/Makefile +++ b/main/Makefile @@ -279,15 +279,15 @@ ASTPJ_LIB:=libasteriskpj.so libasteriskpj.exports: $(ASTTOPDIR)/$(PJPROJECT_DIR)/pjproject.symbols $(ECHO_PREFIX) echo " [GENERATE] libasteriskpj.exports" ifeq ($(GNU_LD),1) - $(CMD_PREFIX) echo -e "{\n\tglobal:" > libasteriskpj.exports - $(CMD_PREFIX) sed -r -e "s/.*/\t\t$(LINKER_SYMBOL_PREFIX)&;/" $(ASTTOPDIR)/$(PJPROJECT_DIR)/pjproject.symbols >> libasteriskpj.exports - $(CMD_PREFIX) echo -e "\t\t$(LINKER_SYMBOL_PREFIX)ast_pj_init;\n" >> libasteriskpj.exports - $(CMD_PREFIX) echo -e "\tlocal:\n\t\t*;\n};" >> libasteriskpj.exports + $(CMD_PREFIX) echo -e "{\nglobal:" > libasteriskpj.exports + $(CMD_PREFIX) sed -r -e "s/.*/$(LINKER_SYMBOL_PREFIX)&;/" $(ASTTOPDIR)/$(PJPROJECT_DIR)/pjproject.symbols >> libasteriskpj.exports + $(CMD_PREFIX) echo -e "$(LINKER_SYMBOL_PREFIX)ast_pj_init;\n" >> libasteriskpj.exports + $(CMD_PREFIX) echo -e "local:\n*;\n};" >> libasteriskpj.exports endif $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB) $(PJ_LDFLAGS) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" -DAST_NOT_MODULE $(PJ_CFLAGS) -$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lrt -lpthread +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lpthread ifeq ($(GNU_LD),1) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): SO_SUPPRESS_SYMBOLS=-Wl,--version-script,libasteriskpj.exports,--warn-common endif diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 79b8d4f4dce..a8820332022 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1365,7 +1365,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con return 0; } -#if OPENSSL_VERSION_NUMBER < 0x10002000L +#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER) rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method()); #else rtp->ssl_ctx = SSL_CTX_new(DTLS_method()); diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 106938b6cc9..5a4c2d1b6a2 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -193,9 +193,9 @@ clean: $(ECHO_PREFIX) Cleaning +-$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean || : ;\ rm -rf source/pjsip-apps/bin/* || : ;\ - find source -name *.a -delete ;\ - find source -name *.o -delete ;\ - find source -name *.so -delete ; ) || : + find source -name *.a | xargs rm -rf ;\ + find source -name *.o | xargs rm -rf ;\ + find source -name *.so | xargs rm -rf ; ) || : -$(CMD_PREFIX) rm -rf pjproject.symbols distclean: From 349e08cb482cb99df7f14a3f0c06756f5eb55828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 17 Nov 2016 16:25:41 +0200 Subject: [PATCH 0903/1578] codec_dahdi: Fix poll.h include. POSIX defines poll.h. sys/poll.h should not be used as it is c-library internal header which may or may not exist. Notably in musl including sys/poll.h generates warning of being incorrect. Change-Id: Ib318c1c7142a737bcf3caa4d8d72560bebe39252 --- codecs/codec_dahdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c index 2d08d36cd57..efb016853a9 100644 --- a/codecs/codec_dahdi.c +++ b/codecs/codec_dahdi.c @@ -34,11 +34,11 @@ #include "asterisk.h" #include +#include #include #include #include #include -#include #include #include "asterisk/lock.h" From d670ea6297f087006e9b49968d788d834c6337d4 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 17 Nov 2016 10:52:45 -0600 Subject: [PATCH 0904/1578] manager: update minor version Based on bridge video AMI event changes, bump the minor version of AMI. Change-Id: Idf84507354170400813cda780906c94c9f1b60b4 --- include/asterisk/manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 43897489d95..60c51de854c 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -54,7 +54,7 @@ - \ref manager.c Main manager code file */ -#define AMI_VERSION "3.0.0" +#define AMI_VERSION "3.1.0" #define DEFAULT_MANAGER_PORT 5038 /* Default port for Asterisk management via TCP */ #define DEFAULT_MANAGER_TLS_PORT 5039 /* Default port for Asterisk management via TCP */ From e822a50f86e85b023c1c90a352af21a5fd83d7c6 Mon Sep 17 00:00:00 2001 From: misha Date: Fri, 11 Nov 2016 14:13:30 +0100 Subject: [PATCH 0905/1578] main/app.c: Transmit Silence on ControlPlayback pause ASTERISK-26562 #close Change-Id: Ie6cb0ffc2b8c775639ce7784fe96f4ea00cfa2f8 --- main/app.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/main/app.c b/main/app.c index 621153e250a..f2e3a0fe051 100644 --- a/main/app.c +++ b/main/app.c @@ -1071,6 +1071,7 @@ static int control_streamfile(struct ast_channel *chan, int res; long pause_restart_point = 0; long offset = 0; + struct ast_silence_generator *silgen = NULL; if (!file) { return -1; @@ -1161,6 +1162,10 @@ static int control_streamfile(struct ast_channel *chan, if ((suspend && strchr(suspend, res)) || res == AST_CONTROL_STREAM_SUSPEND) { pause_restart_point = ast_tellstream(ast_channel_stream(chan)); + + if (ast_opt_transmit_silence) { + silgen = ast_channel_start_silence_generator(chan); + } ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n" "Control: %s\r\n", ast_channel_name(chan), @@ -1174,6 +1179,11 @@ static int control_streamfile(struct ast_channel *chan, break; } } + if (silgen) { + ast_channel_stop_silence_generator(chan, silgen); + silgen = NULL; + } + if ((suspend && (res == *suspend)) || res == AST_CONTROL_STREAM_SUSPEND) { res = 0; ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n" From d3f070c7a26a79e1f02a745288c5b66e41324146 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 16 Nov 2016 11:05:43 -0700 Subject: [PATCH 0906/1578] pjproject_bundled: Improve reliability of pjproject download The download process now has a timeout which will cause wget to retry if it stops retrieving data for 5 seconds and fetch and curl to timeout if the whole retrieval take smore than 30 seconds. If the tarball retrieval works, the MD5SUM file is retrieved from the downloads site and the md5 checksum is verified. If either the tarball retrieval or MD5SUM retrieval fails, or the checksums don't match, the entire process is retried once. If it fails again, any incomplete tarball is deleted. .DELETE_ON_ERROR: was also added to the Makefile. Not only does this delete the tarball on failure, it till also delete corrupted library files from the pjproject source directory should they fail to build correctly. Tested all the way back to FreeBSD 9, CentOS 6, Debian 6 and Ubuntu 14. Change-Id: Iea7d33b96a31622ab1b6e54baebaf271959514e1 --- configure | 98 +++++++++++++++++++++++++++++- configure.ac | 6 ++ makeopts.in | 2 + third-party/Makefile.rules | 4 ++ third-party/pjproject/Makefile | 23 ++++++- third-party/pjproject/configure.m4 | 8 ++- 6 files changed, 136 insertions(+), 5 deletions(-) diff --git a/configure b/configure index b3661c0fc8a..6abdc05344b 100755 --- a/configure +++ b/configure @@ -1231,6 +1231,7 @@ PBX_BISON OPENSSL SHA1SUM LDCONFIG +DOWNLOAD_TIMEOUT DOWNLOAD_TO_STDOUT DOWNLOAD FETCH @@ -1257,6 +1258,8 @@ COMPRESS FIND PYTHON FLEX +CUT +CAT CMP BISON GNU_LD @@ -6804,6 +6807,88 @@ $as_echo "no" >&6; } fi +# Extract the first word of "cat", so it can be a program name with args. +set dummy cat; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CAT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CAT in + [\\/]* | ?:[\\/]*) + ac_cv_path_CAT="$CAT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CAT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_CAT" && ac_cv_path_CAT=":" + ;; +esac +fi +CAT=$ac_cv_path_CAT +if test -n "$CAT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CAT" >&5 +$as_echo "$CAT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "cut", so it can be a program name with args. +set dummy cut; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CUT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CUT in + [\\/]* | ?:[\\/]*) + ac_cv_path_CUT="$CUT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CUT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_CUT" && ac_cv_path_CUT=":" + ;; +esac +fi +CUT=$ac_cv_path_CUT +if test -n "$CUT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CUT" >&5 +$as_echo "$CUT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Extract the first word of "flex", so it can be a program name with args. set dummy flex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -7874,9 +7959,11 @@ fi if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} DOWNLOAD_TO_STDOUT="${WGET} -O-" + DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\"" + DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)' else # Extract the first word of "fetch", so it can be a program name with args. set dummy fetch; ac_word=$2 @@ -7921,11 +8008,14 @@ fi DOWNLOAD=${FETCH} DOWNLOAD_TO_STDOUT="${FETCH} -o-" + DOWNLOAD_TIMEOUT='--timeout=$(or $2,$1)' fi fi + + # Extract the first word of "ldconfig", so it can be a program name with args. set dummy ldconfig; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -9247,8 +9337,14 @@ $as_echo "configuring" >&6; } if test "${NM}" = ":" ; then as_fn_error $? "nm is required to build bundled pjproject" "$LINENO" 5 fi + if test "${MD5}" = ":" ; then + as_fn_error $? "md5dum is required to build bundled pjproject" "$LINENO" 5 + fi + if test "${CAT}" = ":" ; then + as_fn_error $? "cat is required to build bundled pjproject" "$LINENO" 5 + fi - export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT + export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} configure if test $? -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 diff --git a/configure.ac b/configure.ac index c7f219d57d1..f3be3371f45 100644 --- a/configure.ac +++ b/configure.ac @@ -263,6 +263,7 @@ AC_SUBST(GNU_LD) AC_PATH_PROG([BISON], [bison], :) AC_PATH_PROG([CMP], [cmp], :) +AC_PATH_PROG([CAT], [cat], :) AC_PATH_PROG([FLEX], [flex], :) AC_PATH_PROG([GREP], [grep], :) AC_PATH_PROG([PYTHON], [python], :) @@ -293,18 +294,23 @@ AC_PATH_PROG([NM], [nm], :) if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} DOWNLOAD_TO_STDOUT="${WGET} -O-" + DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\"" + DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)' else AC_PATH_PROG([FETCH], [fetch], [:]) DOWNLOAD=${FETCH} DOWNLOAD_TO_STDOUT="${FETCH} -o-" + DOWNLOAD_TIMEOUT='--timeout=$(or $2,$1)' fi fi AC_SUBST(DOWNLOAD) AC_SUBST(DOWNLOAD_TO_STDOUT) +AC_SUBST(DOWNLOAD_TIMEOUT) + AC_PATH_PROG([LDCONFIG], [ldconfig], :) AC_PATH_PROG([SHA1SUM], [sha1sum], $ac_aux_dir/build_tools/sha1sum-sh) AC_PATH_PROG([OPENSSL], [openssl], :) diff --git a/makeopts.in b/makeopts.in index a145b02e6ce..c67e2f2b6ec 100644 --- a/makeopts.in +++ b/makeopts.in @@ -28,6 +28,7 @@ WGET=@WGET@ FETCH=@FETCH@ DOWNLOAD=@DOWNLOAD@ DOWNLOAD_TO_STDOUT=@DOWNLOAD_TO_STDOUT@ +DOWNLOAD_MAX_TIMEOUT=@DOWNLOAD_MAX_TIMEOUT@ SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@ EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@ RUBBER=@RUBBER@ @@ -46,6 +47,7 @@ TAR=@TAR@ PATCH=@PATCH@ SED=@SED@ NM=@NM@ +CAT=@CAT@ BUILD_PLATFORM=@BUILD_PLATFORM@ BUILD_CPU=@BUILD_CPU@ diff --git a/third-party/Makefile.rules b/third-party/Makefile.rules index 4f804dd0e3c..f8b72ba6ddb 100644 --- a/third-party/Makefile.rules +++ b/third-party/Makefile.rules @@ -26,4 +26,8 @@ export TAR export PATCH export SED export NM +export MD5 +export CAT export DOWNLOAD +export DOWNLOAD_TO_STDOUT +export DOWNLOAD_TIMEOUT diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 106938b6cc9..ff3266c16fe 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -75,14 +75,31 @@ include ../Makefile.rules include Makefile.rules ECHO_PREFIX := $(ECHO_PREFIX) echo '[pjproject] ' +SHELL_ECHO_PREFIX := echo '[pjproject] ' _all: $(TARGETS) +define download_from_pjproject + ($(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/$(@F) to $@ ;\ + $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/$(@F) > $@ &&\ + $(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM to $(PJMD5SUM) &&\ + $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\ + ($(SHELL_ECHO_PREFIX) Verifying $@ &&\ + tarball_sum=$$($(CAT) $@ | $(MD5) | $(SED) -n -r -e "s/^([^ ]+)\s+.*/\1/gp") ;\ + required_sum=$$($(SED) -n -r -e "s/^([^ ]+)\s+$(@F)/\1/gp" $(PJMD5SUM)) ;\ + if [ "$$tarball_sum" != "$$required_sum" ] ; then $(SHELL_ECHO_PREFIX) Verify failed ; exit 1 ; fi) &&\ + $(SHELL_ECHO_PREFIX) Verify successful ; exit 0) +endef + +.DELETE_ON_ERROR: + DOWNLOAD_DIR := $(or $(EXTERNALS_CACHE_DIR),$(TMPDIR),$(wildcard /tmp),.) +TARBALL = $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 +PJMD5SUM = $(patsubst %.tar.bz2,%.md5,$(TARBALL)) -$(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2: ../versions.mak - $(ECHO_PREFIX) Downloading $(PJPROJECT_URL)/$(@F) to $@ - $(CMD_PREFIX) $(DOWNLOAD_TO_STDOUT) $(PJPROJECT_URL)/$(@F) > $@ +$(TARBALL): ../versions.mak + $(CMD_PREFIX) $(download_from_pjproject) || (rm -rf $@ ;\ + $(SHELL_ECHO_PREFIX) Retrying download ; sleep 3 ; $(download_from_pjproject)) source/.unpacked: $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 $(ECHO_PREFIX) Unpacking $< diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 7c60c2a02bc..8294d8ef933 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -28,8 +28,14 @@ AC_DEFUN([_PJPROJECT_CONFIGURE], if test "${NM}" = ":" ; then AC_MSG_ERROR(nm is required to build bundled pjproject) fi + if test "${MD5}" = ":" ; then + AC_MSG_ERROR(md5sum is required to build bundled pjproject) + fi + if test "${CAT}" = ":" ; then + AC_MSG_ERROR(cat is required to build bundled pjproject) + fi - export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT + export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} configure if test $? -ne 0 ; then AC_MSG_RESULT(failed) From 7a8d6bc81b40fddffbdc00d4e9fc98856fd052ff Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 18 Nov 2016 09:46:48 -0600 Subject: [PATCH 0907/1578] Bump ARI version to 2.0.0 In order to not have version number overlap between different versions of Asterisk, each new major version of Asterisk will mean we also bump the ARI major version number. This particular change does NOT introduce any known breaking changes to ARI. For discussion relating to this topice, see: http://lists.digium.com/pipermail/asterisk-dev/2016-November/075964.html Change-Id: I712ee0df177a8fe1252da2bc029705268b97b665 --- CHANGES | 6 ++++++ rest-api/api-docs/applications.json | 2 +- rest-api/api-docs/asterisk.json | 2 +- rest-api/api-docs/bridges.json | 2 +- rest-api/api-docs/channels.json | 2 +- rest-api/api-docs/deviceStates.json | 2 +- rest-api/api-docs/endpoints.json | 2 +- rest-api/api-docs/events.json | 2 +- rest-api/api-docs/mailboxes.json | 2 +- rest-api/api-docs/playbacks.json | 2 +- rest-api/api-docs/recordings.json | 2 +- rest-api/api-docs/sounds.json | 2 +- rest-api/resources.json | 2 +- 13 files changed, 18 insertions(+), 12 deletions(-) diff --git a/CHANGES b/CHANGES index e7d6cca93a5..3db847d83d4 100644 --- a/CHANGES +++ b/CHANGES @@ -93,6 +93,12 @@ ARI Applications subscribed to a bridge will receive this event when the source of video changes in a mixing bridge. + * The ARI major version has been bumped. There are not any known breaking changes + in ARI. The major version has been bumped because otherwise we can end up with + overlapping version numbers between different Asterisk versions. Now each major + version of Asterisk will bring with it a change in the major version of ARI. + The ARI version in Asterisk 14 is now 2.0.0. + res_pjsip ------------------ * Automatic dual stack support is now implemented. Depending on DNS resolution diff --git a/rest-api/api-docs/applications.json b/rest-api/api-docs/applications.json index 6dcdb78b169..cdd69c4178d 100644 --- a/rest-api/api-docs/applications.json +++ b/rest-api/api-docs/applications.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/applications.{format}", diff --git a/rest-api/api-docs/asterisk.json b/rest-api/api-docs/asterisk.json index 0db206227c4..f40bf5c6b7e 100644 --- a/rest-api/api-docs/asterisk.json +++ b/rest-api/api-docs/asterisk.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/asterisk.{format}", diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json index 8289b43e1a2..03a1e7a69e3 100644 --- a/rest-api/api-docs/bridges.json +++ b/rest-api/api-docs/bridges.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/bridges.{format}", diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index 241b22ae8f3..602606cfe7c 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/channels.{format}", diff --git a/rest-api/api-docs/deviceStates.json b/rest-api/api-docs/deviceStates.json index e2322739612..94d5b93ce08 100644 --- a/rest-api/api-docs/deviceStates.json +++ b/rest-api/api-docs/deviceStates.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "Kevin Harwell ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/deviceStates.{format}", diff --git a/rest-api/api-docs/endpoints.json b/rest-api/api-docs/endpoints.json index 4fd077c1461..264c0eb2d06 100644 --- a/rest-api/api-docs/endpoints.json +++ b/rest-api/api-docs/endpoints.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/endpoints.{format}", diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json index f99f52e67be..9ebbac061f8 100644 --- a/rest-api/api-docs/events.json +++ b/rest-api/api-docs/events.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.2", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/events.{format}", diff --git a/rest-api/api-docs/mailboxes.json b/rest-api/api-docs/mailboxes.json index 324e3788545..ed50019f500 100644 --- a/rest-api/api-docs/mailboxes.json +++ b/rest-api/api-docs/mailboxes.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2013, Digium, Inc.", "_author": "Jonathan Rose ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/mailboxes.{format}", diff --git a/rest-api/api-docs/playbacks.json b/rest-api/api-docs/playbacks.json index 9f90035588c..3dc4e1da5a9 100644 --- a/rest-api/api-docs/playbacks.json +++ b/rest-api/api-docs/playbacks.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/playbacks.{format}", diff --git a/rest-api/api-docs/recordings.json b/rest-api/api-docs/recordings.json index d173ac98eb5..d0b9630da28 100644 --- a/rest-api/api-docs/recordings.json +++ b/rest-api/api-docs/recordings.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/recordings.{format}", diff --git a/rest-api/api-docs/sounds.json b/rest-api/api-docs/sounds.json index 628aa1948b7..8fbe1c5789e 100644 --- a/rest-api/api-docs/sounds.json +++ b/rest-api/api-docs/sounds.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.7.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "resourcePath": "/api-docs/sounds.{format}", diff --git a/rest-api/resources.json b/rest-api/resources.json index ecaf723b601..df5b8d6fd06 100644 --- a/rest-api/resources.json +++ b/rest-api/resources.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "1.10.0", + "apiVersion": "2.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "apis": [ From b546497fe0d80cfc44ecf0e88d31c7cedf5eccd8 Mon Sep 17 00:00:00 2001 From: snuffy Date: Sun, 20 Nov 2016 09:19:18 +1100 Subject: [PATCH 0908/1578] Add support for older name resolving version libraries like openBSD Fix support of OS's like openBSD that use an older nameser.h, this change reverts the defines to the older style which on other systems is found in nameser_compat.h Tested on openBSD 6.0, Debian 8 ASTERISK-26608 #close Change-Id: Iffb36caab8c5aa9dece0ce2d009041f7b56cc86a --- main/dns.c | 2 +- main/dns_core.c | 22 +++++++++++----------- main/dns_naptr.c | 13 +++++++------ main/dns_srv.c | 8 ++++---- res/res_pjsip/pjsip_resolver.c | 32 ++++++++++++++++---------------- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/main/dns.c b/main/dns.c index 3b198a0f326..76f8075e53a 100644 --- a/main/dns.c +++ b/main/dns.c @@ -555,7 +555,7 @@ enum ast_dns_search_result ast_search_dns_ex(void *context, const char *dname, i if (dns_response_len < 0) { ast_debug(1, "DNS search failed for %s\n", dname); - response_handler(context, (unsigned char *)"", 0, ns_r_nxdomain); + response_handler(context, (unsigned char *)"", 0, NXDOMAIN); return AST_DNS_SEARCH_FAILURE; } diff --git a/main/dns_core.c b/main/dns_core.c index e1cbc21916a..a243b4bdd3f 100644 --- a/main/dns_core.c +++ b/main/dns_core.c @@ -112,7 +112,7 @@ int ast_dns_result_get_lowest_ttl(const struct ast_dns_result *result) int ttl = 0; const struct ast_dns_record *record; - if (ast_dns_result_get_rcode(result) == ns_r_nxdomain) { + if (ast_dns_result_get_rcode(result) == NXDOMAIN) { return 0; } @@ -195,7 +195,7 @@ struct ast_dns_query *dns_query_alloc(const char *name, int rr_type, int rr_clas if (ast_strlen_zero(name)) { ast_log(LOG_WARNING, "Could not perform asynchronous resolution, no name provided\n"); return NULL; - } else if (rr_type > ns_t_max) { + } else if (rr_type > 65536) { ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', resource record type '%d' exceeds maximum\n", name, rr_type); return NULL; @@ -203,7 +203,7 @@ struct ast_dns_query *dns_query_alloc(const char *name, int rr_type, int rr_clas ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', invalid resource record type '%d'\n", name, rr_type); return NULL; - } else if (rr_class > ns_c_max) { + } else if (rr_class > 65536) { ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', resource record class '%d' exceeds maximum\n", name, rr_class); return NULL; @@ -317,7 +317,7 @@ int ast_dns_resolve(const char *name, int rr_type, int rr_class, struct ast_dns_ if (ast_strlen_zero(name)) { ast_log(LOG_WARNING, "Could not perform synchronous resolution, no name provided\n"); return -1; - } else if (rr_type > ns_t_max) { + } else if (rr_type > 65536) { ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', resource record type '%d' exceeds maximum\n", name, rr_type); return -1; @@ -325,7 +325,7 @@ int ast_dns_resolve(const char *name, int rr_type, int rr_class, struct ast_dns_ ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', invalid resource record type '%d'\n", name, rr_type); return -1; - } else if (rr_class > ns_c_max) { + } else if (rr_class > 65536) { ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', resource record class '%d' exceeds maximum\n", name, rr_class); return -1; @@ -443,8 +443,8 @@ static struct ast_dns_record *generic_record_alloc(struct ast_dns_query *query, typedef struct ast_dns_record *(*dns_alloc_fn)(struct ast_dns_query *query, const char *data, const size_t size); static dns_alloc_fn dns_alloc_table [] = { - [ns_t_naptr] = dns_naptr_alloc, - [ns_t_srv] = dns_srv_alloc, + [T_NAPTR] = dns_naptr_alloc, + [T_SRV] = dns_srv_alloc, }; static struct ast_dns_record *allocate_dns_record(int rr_type, struct ast_dns_query *query, const char *data, const size_t size) @@ -462,7 +462,7 @@ int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr ast_debug(2, "Query '%p': Could not add record, invalid resource record type '%d'\n", query, rr_type); return -1; - } else if (rr_type > ns_t_max) { + } else if (rr_type > 65536) { ast_debug(2, "Query '%p': Could not add record, resource record type '%d' exceeds maximum\n", query, rr_type); return -1; @@ -470,7 +470,7 @@ int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr ast_debug(2, "Query '%p': Could not add record, invalid resource record class '%d'\n", query, rr_class); return -1; - } else if (rr_class > ns_c_max) { + } else if (rr_class > 65536) { ast_debug(2, "Query '%p': Could not add record, resource record class '%d' exceeds maximum\n", query, rr_class); return -1; @@ -507,8 +507,8 @@ int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr typedef void (*dns_sort_fn)(struct ast_dns_result *result); static dns_sort_fn dns_sort_table [] = { - [ns_t_naptr] = dns_naptr_sort, - [ns_t_srv] = dns_srv_sort, + [T_NAPTR] = dns_naptr_sort, + [T_SRV] = dns_srv_sort, }; static void sort_result(int rr_type, struct ast_dns_result *result) diff --git a/main/dns_naptr.c b/main/dns_naptr.c index d24e1b5f447..5490b556830 100644 --- a/main/dns_naptr.c +++ b/main/dns_naptr.c @@ -30,6 +30,7 @@ #include "asterisk.h" #include +#include #include #include @@ -590,7 +591,7 @@ const char *ast_dns_naptr_get_flags(const struct ast_dns_record *record) { struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr); + ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR); return naptr->flags; } @@ -598,7 +599,7 @@ const char *ast_dns_naptr_get_service(const struct ast_dns_record *record) { struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr); + ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR); return naptr->service; } @@ -606,7 +607,7 @@ const char *ast_dns_naptr_get_regexp(const struct ast_dns_record *record) { struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr); + ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR); return naptr->regexp; } @@ -614,7 +615,7 @@ const char *ast_dns_naptr_get_replacement(const struct ast_dns_record *record) { struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr); + ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR); return naptr->replacement; } @@ -622,7 +623,7 @@ unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record) { struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr); + ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR); return naptr->order; } @@ -630,6 +631,6 @@ unsigned short ast_dns_naptr_get_preference(const struct ast_dns_record *record) { struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr); + ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR); return naptr->preference; } diff --git a/main/dns_srv.c b/main/dns_srv.c index 9d36fb61f9d..b562e325753 100644 --- a/main/dns_srv.c +++ b/main/dns_srv.c @@ -183,7 +183,7 @@ const char *ast_dns_srv_get_host(const struct ast_dns_record *record) { struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + ast_assert(ast_dns_record_get_rr_type(record) == T_SRV); return srv->host; } @@ -191,7 +191,7 @@ unsigned short ast_dns_srv_get_priority(const struct ast_dns_record *record) { struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + ast_assert(ast_dns_record_get_rr_type(record) == T_SRV); return srv->priority; } @@ -199,7 +199,7 @@ unsigned short ast_dns_srv_get_weight(const struct ast_dns_record *record) { struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + ast_assert(ast_dns_record_get_rr_type(record) == T_SRV); return srv->weight; } @@ -207,6 +207,6 @@ unsigned short ast_dns_srv_get_port(const struct ast_dns_record *record) { struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; - ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + ast_assert(ast_dns_record_get_rr_type(record) == T_SRV); return srv->port; } diff --git a/res/res_pjsip/pjsip_resolver.c b/res/res_pjsip/pjsip_resolver.c index 5a902466e3f..d6646d50323 100644 --- a/res/res_pjsip/pjsip_resolver.c +++ b/res/res_pjsip/pjsip_resolver.c @@ -253,7 +253,7 @@ static int sip_resolve_handle_naptr(struct sip_resolve *resolve, const struct as return -1; } - return sip_resolve_add(resolve, ast_dns_naptr_get_replacement(record), ns_t_srv, ns_c_in, + return sip_resolve_add(resolve, ast_dns_naptr_get_replacement(record), T_SRV, C_IN, transport, 0); } @@ -304,12 +304,12 @@ static void sip_resolve_callback(const struct ast_dns_query_set *query_set) target = AST_VECTOR_GET_ADDR(&resolving, idx); for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) { - if (ast_dns_record_get_rr_type(record) == ns_t_a || - ast_dns_record_get_rr_type(record) == ns_t_aaaa) { + if (ast_dns_record_get_rr_type(record) == T_A || + ast_dns_record_get_rr_type(record) == T_AAAA) { /* If NAPTR or SRV records exist the subsequent results from them take preference */ if (have_naptr || have_srv) { ast_debug(2, "[%p] %s record being skipped on target '%s' because NAPTR or SRV record exists\n", - resolve, ast_dns_record_get_rr_type(record) == ns_t_a ? "A" : "AAAA", + resolve, ast_dns_record_get_rr_type(record) == T_A ? "A" : "AAAA", ast_dns_query_get_name(query)); continue; } @@ -322,7 +322,7 @@ static void sip_resolve_callback(const struct ast_dns_query_set *query_set) resolve->addresses.entry[address_count].type = target->transport; /* Populate address information for the new address entry */ - if (ast_dns_record_get_rr_type(record) == ns_t_a) { + if (ast_dns_record_get_rr_type(record) == T_A) { ast_debug(2, "[%p] A record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); resolve->addresses.entry[address_count].addr_len = sizeof(pj_sockaddr_in); pj_sockaddr_init(pj_AF_INET(), &resolve->addresses.entry[address_count].addr, NULL, @@ -338,7 +338,7 @@ static void sip_resolve_callback(const struct ast_dns_query_set *query_set) } address_count++; - } else if (ast_dns_record_get_rr_type(record) == ns_t_srv) { + } else if (ast_dns_record_get_rr_type(record) == T_SRV) { if (have_naptr) { ast_debug(2, "[%p] SRV record being skipped on target '%s' because NAPTR record exists\n", resolve, ast_dns_query_get_name(query)); @@ -350,22 +350,22 @@ static void sip_resolve_callback(const struct ast_dns_query_set *query_set) /* If an explicit IPv6 target transport has been requested look for only AAAA records */ if (target->transport & PJSIP_TRANSPORT_IPV6) { - sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_aaaa, ns_c_in, target->transport, + sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_AAAA, C_IN, target->transport, ast_dns_srv_get_port(record)); have_srv = 1; } else if (sip_transport_is_available(target->transport + PJSIP_TRANSPORT_IPV6)) { - sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_aaaa, ns_c_in, target->transport + PJSIP_TRANSPORT_IPV6, + sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_AAAA, C_IN, target->transport + PJSIP_TRANSPORT_IPV6, ast_dns_srv_get_port(record)); have_srv = 1; } if (!(target->transport & PJSIP_TRANSPORT_IPV6) && sip_transport_is_available(target->transport)) { - sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_a, ns_c_in, target->transport, + sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_A, C_IN, target->transport, ast_dns_srv_get_port(record)); have_srv = 1; } - } else if (ast_dns_record_get_rr_type(record) == ns_t_naptr) { + } else if (ast_dns_record_get_rr_type(record) == T_NAPTR) { int added = -1; ast_debug(2, "[%p] NAPTR record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); @@ -561,39 +561,39 @@ static void sip_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip * explicitly and only looks for IPv6 records. */ - res |= sip_resolve_add(resolve, host, ns_t_naptr, ns_c_in, type, 0); + res |= sip_resolve_add(resolve, host, T_NAPTR, C_IN, type, 0); if (type == PJSIP_TRANSPORT_UNSPECIFIED || (type == PJSIP_TRANSPORT_TLS && sip_transport_is_available(PJSIP_TRANSPORT_TLS)) || (type == PJSIP_TRANSPORT_TLS6 && sip_transport_is_available(PJSIP_TRANSPORT_TLS6))) { snprintf(srv, sizeof(srv), "_sips._tcp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, + res |= sip_resolve_add(resolve, srv, T_SRV, C_IN, type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TLS : type, 0); } if (type == PJSIP_TRANSPORT_UNSPECIFIED || (type == PJSIP_TRANSPORT_TCP && sip_transport_is_available(PJSIP_TRANSPORT_TCP)) || (type == PJSIP_TRANSPORT_TCP6 && sip_transport_is_available(PJSIP_TRANSPORT_TCP6))) { snprintf(srv, sizeof(srv), "_sip._tcp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, + res |= sip_resolve_add(resolve, srv, T_SRV, C_IN, type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TCP : type, 0); } if (type == PJSIP_TRANSPORT_UNSPECIFIED || (type == PJSIP_TRANSPORT_UDP && sip_transport_is_available(PJSIP_TRANSPORT_UDP)) || (type == PJSIP_TRANSPORT_UDP6 && sip_transport_is_available(PJSIP_TRANSPORT_UDP6))) { snprintf(srv, sizeof(srv), "_sip._udp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, + res |= sip_resolve_add(resolve, srv, T_SRV, C_IN, type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type, 0); } } if ((type == PJSIP_TRANSPORT_UNSPECIFIED && sip_transport_is_available(PJSIP_TRANSPORT_UDP6)) || sip_transport_is_available(type + PJSIP_TRANSPORT_IPV6)) { - res |= sip_resolve_add(resolve, host, ns_t_aaaa, ns_c_in, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP6 : type + PJSIP_TRANSPORT_IPV6), target->addr.port); + res |= sip_resolve_add(resolve, host, T_AAAA, C_IN, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP6 : type + PJSIP_TRANSPORT_IPV6), target->addr.port); } if ((type == PJSIP_TRANSPORT_UNSPECIFIED && sip_transport_is_available(PJSIP_TRANSPORT_UDP)) || sip_transport_is_available(type)) { - res |= sip_resolve_add(resolve, host, ns_t_a, ns_c_in, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type), target->addr.port); + res |= sip_resolve_add(resolve, host, T_A, C_IN, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type), target->addr.port); } if (res) { From abae3dc36e6446980dd9e4f6eeb375dfb7a7a005 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 21 Nov 2016 08:49:45 -0700 Subject: [PATCH 0909/1578] pjproject_bundled: Use $(LIB_RT) for link of libasteriskpj libasteriskpj was hard coded to use -lrt but librt is linux specific so we now use the LIB_RT variable which gets set by configure. Change-Id: I41148884517e3031f7675a413d524c86e8614694 --- main/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/Makefile b/main/Makefile index 0c1b11ed83c..95c3c70c688 100644 --- a/main/Makefile +++ b/main/Makefile @@ -287,7 +287,7 @@ endif $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB) $(PJ_LDFLAGS) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" -DAST_NOT_MODULE $(PJ_CFLAGS) -$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lpthread +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lpthread $(RT_LIB) ifeq ($(GNU_LD),1) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): SO_SUPPRESS_SYMBOLS=-Wl,--version-script,libasteriskpj.exports,--warn-common endif @@ -312,7 +312,7 @@ ASTPJ_LIB:=libasteriskpj.dylib # /lib or /usr/lib $(ASTPJ_LIB): _ASTLDFLAGS+=-dynamiclib -install_name $(ASTLIBDIR)/$(ASTPJ_LIB) $(PJ_LDFLAGS) $(ASTPJ_LIB): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS) -DAST_NOT_MODULE -$(ASTPJ_LIB): LIBS+=$(PJPROJECT_LIBS) -lssl -lcrypto -luuid -lm -lrt -lpthread +$(ASTPJ_LIB): LIBS+=$(PJPROJECT_LIBS) -lssl -lcrypto -luuid -lm -lpthread $(RT_LIB) $(ASTPJ_LIB): SOLINK=$(DYLINK) # Special rules for building a shared library (not a dynamically loadable module) From 635b0a0a550a191727e4162a453560903e76b233 Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Tue, 15 Nov 2016 20:44:13 +0100 Subject: [PATCH 0910/1578] tcptls: Use new certificate upon sip reload Previously, a TLS server socket would only be restarted upon sip reload if the bind address had changed. This commit adds checking for changes to TLS parameters like certificate, ciphers, etc. so they get picked up without requiring a reload of the entire chan_sip module. This does not affect open connections in any way, but new connections will use the new TLS parameters. The changes also apply to HTTP and Manager. ASTERISK-26604 #close Change-Id: I169e86cefc6dcd627c915134015a6a1ab1aadbe6 --- include/asterisk/tcptls.h | 4 ++ main/tcptls.c | 86 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h index 883cb9229ef..1e3a7524bf8 100644 --- a/include/asterisk/tcptls.h +++ b/include/asterisk/tcptls.h @@ -94,6 +94,9 @@ struct ast_tls_config { char *capath; struct ast_flags flags; SSL_CTX *ssl_ctx; + char certhash[41]; + char pvthash[41]; + char cahash[41]; }; /*! \page AstTlsOverview TLS Implementation Overview @@ -138,6 +141,7 @@ struct ast_tcptls_session_args { void (*periodic_fn)(void *);/*!< something we may want to run before after select on the accept socket */ void *(*worker_fn)(void *); /*!< the function in charge of doing the actual work */ const char *name; + struct ast_tls_config *old_tls_cfg; /*!< copy of the SSL configuration to determine whether changes have been made */ }; /*! \brief diff --git a/main/tcptls.c b/main/tcptls.c index c8ebab43470..fce1558b747 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -36,6 +36,7 @@ #endif #include +#include #include "asterisk/compat.h" #include "asterisk/tcptls.h" @@ -46,6 +47,7 @@ #include "asterisk/manager.h" #include "asterisk/astobj2.h" #include "asterisk/pbx.h" +#include "asterisk/app.h" static void session_instance_destructor(void *obj) { @@ -588,9 +590,64 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) { int flags; int x = 1; + int tls_changed = 0; + + if (desc->tls_cfg) { + char hash[41]; + char *str = NULL; + struct stat st; + + /* Store the hashes of the TLS certificate etc. */ + if (stat(desc->tls_cfg->certfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->certfile))) { + memset(hash, 0, 41); + } else { + ast_sha1_hash(hash, str); + } + ast_free(str); + str = NULL; + memcpy(desc->tls_cfg->certhash, hash, 41); + if (stat(desc->tls_cfg->pvtfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->pvtfile))) { + memset(hash, 0, 41); + } else { + ast_sha1_hash(hash, str); + } + ast_free(str); + str = NULL; + memcpy(desc->tls_cfg->pvthash, hash, 41); + if (stat(desc->tls_cfg->cafile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->cafile))) { + memset(hash, 0, 41); + } else { + ast_sha1_hash(hash, str); + } + ast_free(str); + str = NULL; + memcpy(desc->tls_cfg->cahash, hash, 41); + + /* Check whether TLS configuration has changed */ + if (!desc->old_tls_cfg) { /* No previous configuration */ + tls_changed = 1; + desc->old_tls_cfg = ast_calloc(1, sizeof(*desc->old_tls_cfg)); + } else if (memcmp(desc->tls_cfg->certhash, desc->old_tls_cfg->certhash, 41)) { + tls_changed = 1; + } else if (memcmp(desc->tls_cfg->pvthash, desc->old_tls_cfg->pvthash, 41)) { + tls_changed = 1; + } else if (strcmp(desc->tls_cfg->cipher, desc->old_tls_cfg->cipher)) { + tls_changed = 1; + } else if (memcmp(desc->tls_cfg->cahash, desc->old_tls_cfg->cahash, 41)) { + tls_changed = 1; + } else if (strcmp(desc->tls_cfg->capath, desc->old_tls_cfg->capath)) { + tls_changed = 1; + } else if (memcmp(&desc->tls_cfg->flags, &desc->old_tls_cfg->flags, sizeof(desc->tls_cfg->flags))) { + tls_changed = 1; + } + + if (tls_changed) { + ast_debug(1, "Changed parameters for %s found\n", desc->name); + } + } /* Do nothing if nothing has changed */ - if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { + if (!tls_changed && !ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { ast_debug(1, "Nothing changed in %s\n", desc->name); return; } @@ -646,6 +703,22 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) /* Set current info */ ast_sockaddr_copy(&desc->old_address, &desc->local_address); + if (desc->old_tls_cfg) { + ast_free(desc->old_tls_cfg->certfile); + ast_free(desc->old_tls_cfg->pvtfile); + ast_free(desc->old_tls_cfg->cipher); + ast_free(desc->old_tls_cfg->cafile); + ast_free(desc->old_tls_cfg->capath); + desc->old_tls_cfg->certfile = ast_strdup(desc->tls_cfg->certfile); + desc->old_tls_cfg->pvtfile = ast_strdup(desc->tls_cfg->pvtfile); + desc->old_tls_cfg->cipher = ast_strdup(desc->tls_cfg->cipher); + desc->old_tls_cfg->cafile = ast_strdup(desc->tls_cfg->cafile); + desc->old_tls_cfg->capath = ast_strdup(desc->tls_cfg->capath); + memcpy(desc->old_tls_cfg->certhash, desc->tls_cfg->certhash, 41); + memcpy(desc->old_tls_cfg->pvthash, desc->tls_cfg->pvthash, 41); + memcpy(desc->old_tls_cfg->cahash, desc->tls_cfg->cahash, 41); + memcpy(&desc->old_tls_cfg->flags, &desc->tls_cfg->flags, sizeof(desc->old_tls_cfg->flags)); + } return; @@ -676,6 +749,17 @@ void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc) close(desc->accept_fd); } desc->accept_fd = -1; + + if (desc->old_tls_cfg) { + ast_free(desc->old_tls_cfg->certfile); + ast_free(desc->old_tls_cfg->pvtfile); + ast_free(desc->old_tls_cfg->cipher); + ast_free(desc->old_tls_cfg->cafile); + ast_free(desc->old_tls_cfg->capath); + ast_free(desc->old_tls_cfg); + desc->old_tls_cfg = NULL; + } + ast_debug(2, "Stopped server :: %s\n", desc->name); } From d9b24cce0add96061a0b1e0f135b3148789af5ac Mon Sep 17 00:00:00 2001 From: gestoip2 Date: Fri, 11 Nov 2016 14:16:50 +0000 Subject: [PATCH 0911/1578] res_rtp_asterisk: RTT miscalculation in RTCP When retrieving RTCP stats for PJSIP channels, RTT values are unreliable. RTT calculation is correct, but the data representation isn't. RTT is represented by a 32-bit fixed-point number with the integer part in the first 16 bits and the fractional part in the last 16 bits. In order to get the RTT value, the fractional part is miscalculated, there is an unnecessary 16 bit shift that causes overflow. Besides this there is another mistake, when transforming the integer value to the fixed point fractional part via bitwise operation, that loses precision. * RTT fractional part is no longer shifted, avoiding overflow. * RTT fractional part is transformed to its fixed-point value more precisely. * Fixed timeval2ntp() and ntp2timeval() second fraction conversions. * Fixed NTP timestamp report logging. The usec was inexplicably multiplied by 4096. ASTERISK-26566 #close Reported by Hector Royo Concepcion Change-Id: Ie09bdabfee75afb3f1b8ddfd963e5219ada3b96f --- main/rtp_engine.c | 2 +- res/res_rtp_asterisk.c | 49 +++++++++++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 4fc1414f008..3ef2d876bfa 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2493,7 +2493,7 @@ static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message * if (type == AST_RTP_RTCP_SR) { ast_str_append(&packet_string, 0, "SentNTP: %lu.%06lu\r\n", (unsigned long)payload->report->sender_information.ntp_timestamp.tv_sec, - (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec * 4096); + (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec); ast_str_append(&packet_string, 0, "SentRTP: %u\r\n", payload->report->sender_information.rtp_timestamp); ast_str_append(&packet_string, 0, "SentPackets: %u\r\n", diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index a8820332022..4136f7e7bf0 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -3084,7 +3084,26 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw) unsigned int sec, usec, frac; sec = tv.tv_sec + 2208988800u; /* Sec between 1900 and 1970 */ usec = tv.tv_usec; - frac = (usec << 12) + (usec << 8) - ((usec * 3650) >> 6); + /* + * Convert usec to 0.32 bit fixed point without overflow. + * + * = usec * 2^32 / 10^6 + * = usec * 2^32 / (2^6 * 5^6) + * = usec * 2^26 / 5^6 + * + * The usec value needs 20 bits to represent 999999 usec. So + * splitting the 2^26 to get the most precision using 32 bit + * values gives: + * + * = ((usec * 2^12) / 5^6) * 2^14 + * + * Splitting the division into two stages preserves all the + * available significant bits of usec over doing the division + * all at once. + * + * = ((((usec * 2^12) / 5^3) * 2^7) / 5^3) * 2^7 + */ + frac = ((((usec << 12) / 125) << 7) / 125) << 7; *msw = sec; *lsw = frac; } @@ -3092,7 +3111,8 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw) static void ntp2timeval(unsigned int msw, unsigned int lsw, struct timeval *tv) { tv->tv_sec = msw - 2208988800u; - tv->tv_usec = ((lsw << 6) / 3650) - (lsw >> 12) - (lsw >> 8); + /* Reverse the sequence in timeval2ntp() */ + tv->tv_usec = ((((lsw >> 7) * 125) >> 7) * 125) >> 12; } static void calculate_lost_packet_statistics(struct ast_rtp *rtp, @@ -3277,9 +3297,9 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : ""); ast_verbose(" Our SSRC: %u\n", rtcp_report->ssrc); if (sr) { - ast_verbose(" Sent(NTP): %u.%010u\n", + ast_verbose(" Sent(NTP): %u.%06u\n", (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec, - (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096); + (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec); ast_verbose(" Sent(RTP): %u\n", rtcp_report->sender_information.rtp_timestamp); ast_verbose(" Sent packets: %u\n", rtcp_report->sender_information.packet_count); ast_verbose(" Sent octets: %u\n", rtcp_report->sender_information.octet_count); @@ -4016,9 +4036,22 @@ static int update_rtt_stats(struct ast_rtp *rtp, unsigned int lsr, unsigned int lsr_a = ((msw & 0x0000ffff) << 16) | ((lsw & 0xffff0000) >> 16); rtt = lsr_a - lsr - dlsr; rtt_msw = (rtt & 0xffff0000) >> 16; - rtt_lsw = (rtt & 0x0000ffff) << 16; + rtt_lsw = (rtt & 0x0000ffff); rtt_tv.tv_sec = rtt_msw; - rtt_tv.tv_usec = ((rtt_lsw << 6) / 3650) - (rtt_lsw >> 12) - (rtt_lsw >> 8); + /* + * Convert 16.16 fixed point rtt_lsw to usec without + * overflow. + * + * = rtt_lsw * 10^6 / 2^16 + * = rtt_lsw * (2^6 * 5^6) / 2^16 + * = rtt_lsw * 5^6 / 2^10 + * + * The rtt_lsw value is in 16.16 fixed point format and 5^6 + * requires 14 bits to represent. We have enough space to + * directly do the conversion because there is no integer + * component in rtt_lsw. + */ + rtt_tv.tv_usec = (rtt_lsw * 15625) >> 10; rtp->rtcp->rtt = (double)rtt_tv.tv_sec + ((double)rtt_tv.tv_usec / 1000000); if (lsr_a - dlsr < lsr) { return 1; @@ -4214,9 +4247,9 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) &rtcp_report->sender_information.ntp_timestamp); rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]); if (rtcp_debug_test_addr(&addr)) { - ast_verbose("NTP timestamp: %u.%010u\n", + ast_verbose("NTP timestamp: %u.%06u\n", (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec, - (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096); + (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec); ast_verbose("RTP timestamp: %u\n", rtcp_report->sender_information.rtp_timestamp); ast_verbose("SPC: %u\tSOC: %u\n", rtcp_report->sender_information.packet_count, From ead773f8016f24054e8d17b0509760fd1ddc8fff Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Wed, 23 Nov 2016 21:52:29 +0100 Subject: [PATCH 0912/1578] pbx_lua: On configuration errors report module load failure instead of decline. Switched from AST_MODULE_LOAD_DECLINE to AST_MODULE_LOAD_FAILURE. Therefore, if pbx_lua fails to load and pbx_lua is marked as required, Asterisk exits as expected. If extensions.lua cannot be opened, AST_MODULE_LOAD_DECLINE is reported. Change-Id: I8e5a0037e69b41743db60c568541ebb2f52a7a8f --- pbx/pbx_lua.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/pbx/pbx_lua.c b/pbx/pbx_lua.c index 01f468de067..0754990d673 100644 --- a/pbx/pbx_lua.c +++ b/pbx/pbx_lua.c @@ -60,7 +60,7 @@ static char *registrar = "pbx_lua"; * applications might return */ #define LUA_GOTO_DETECTED 5 -static char *lua_read_extensions_file(lua_State *L, long *size); +static char *lua_read_extensions_file(lua_State *L, long *size, int *file_not_openable); static int lua_load_extensions(lua_State *L, struct ast_channel *chan); static int lua_reload_extensions(lua_State *L); static void lua_free_extensions(void); @@ -1070,12 +1070,13 @@ static int lua_extension_cmp(lua_State *L) * * \param L the lua_State to use * \param size a pointer to store the size of the buffer + * \param file_not_openable a pointer to store if config file could be opened * * \note The caller is expected to free the buffer at some point. * * \return a pointer to the buffer */ -static char *lua_read_extensions_file(lua_State *L, long *size) +static char *lua_read_extensions_file(lua_State *L, long *size, int *file_not_openable) { FILE *f; int error_func; @@ -1090,6 +1091,8 @@ static char *lua_read_extensions_file(lua_State *L, long *size) lua_pushstring(L, strerror(errno)); lua_concat(L, 4); + *file_not_openable = 1; + return NULL; } @@ -1199,10 +1202,14 @@ static int lua_reload_extensions(lua_State *L) { long size = 0; char *data = NULL; + int file_not_openable = 0; luaL_openlibs(L); - if (!(data = lua_read_extensions_file(L, &size))) { + if (!(data = lua_read_extensions_file(L, &size, &file_not_openable))) { + if (file_not_openable) { + return -1; + } return 1; } @@ -1621,17 +1628,24 @@ static struct ast_switch lua_switch = { static int load_or_reload_lua_stuff(void) { int res = AST_MODULE_LOAD_SUCCESS; + int loaded = 0; lua_State *L = luaL_newstate(); if (!L) { ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n"); - return AST_MODULE_LOAD_DECLINE; + return AST_MODULE_LOAD_FAILURE; } - if (lua_reload_extensions(L)) { + loaded = lua_reload_extensions(L); + if (loaded) { const char *error = lua_tostring(L, -1); ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error); - res = AST_MODULE_LOAD_DECLINE; + + if (loaded < 0) { + res = AST_MODULE_LOAD_DECLINE; + } else { + res = AST_MODULE_LOAD_FAILURE; + } } if (!res) { @@ -1664,7 +1678,7 @@ static int load_module(void) if (ast_register_switch(&lua_switch)) { ast_log(LOG_ERROR, "Unable to register LUA PBX switch\n"); - return AST_MODULE_LOAD_DECLINE; + return AST_MODULE_LOAD_FAILURE; } return AST_MODULE_LOAD_SUCCESS; From 0b588778c0d2400e53e7dff6a3a270579acd51d6 Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Sat, 26 Nov 2016 17:57:03 +0100 Subject: [PATCH 0913/1578] chan_sip: Fix segfault during module unload If a TCP/TLS connection was pending (not accepted and not timed out) during unload of chan_sip, Asterisk would segfault when trying to send a signal to a thread whose thread ID hadn't been recorded yet. This commit fixes that by recording the thread ID before calling the blocking connect() syscall. This was a regression introduced by 776a14386a55b5425c7e9617eff8af8b45427144. The above wasn't enough to fix the segfault, which was now delayed to the point where connect() timed out. Therefore, it was necessary to also remove the SA_RESTART flag from the SIGURG sigaction so that pthread_kill() could be used to interruput the connect() syscall. This was a regression introduced by 5d313f51b982a18f7321adcf7c7a4e822d8b2714. ASTERISK-26586 #close Change-Id: I76fd9d47d56e4264e2629bce8ec15fecba673e7b --- channels/chan_sip.c | 11 ++++++++--- main/asterisk.c | 1 - 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 870b53edf86..16d84af6c3c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -2957,6 +2957,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s if (!(me = sip_threadinfo_create(tcptls_session, ast_iostream_get_ssl(tcptls_session->stream) ? AST_TRANSPORT_TLS : AST_TRANSPORT_TCP))) { goto cleanup; } + me->threadid = pthread_self(); ao2_t_ref(me, +1, "Adding threadinfo ref for tcp_helper_thread"); } else { struct sip_threadinfo tmp = { @@ -2964,8 +2965,13 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s }; if ((!(ca = tcptls_session->parent)) || - (!(me = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread"))) || - (!(tcptls_session = ast_tcptls_client_start(tcptls_session)))) { + (!(me = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread")))) { + goto cleanup; + } + + me->threadid = pthread_self(); + + if (!(tcptls_session = ast_tcptls_client_start(tcptls_session))) { goto cleanup; } } @@ -2976,7 +2982,6 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s goto cleanup; } - me->threadid = pthread_self(); ast_debug(2, "Starting thread for %s server\n", ast_iostream_get_ssl(tcptls_session->stream) ? "TLS" : "TCP"); /* set up pollfd to watch for reads on both the socket and the alert_pipe */ diff --git a/main/asterisk.c b/main/asterisk.c index 4a6567f73eb..98ae8811f94 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1669,7 +1669,6 @@ static void _urg_handler(int num) static struct sigaction urg_handler = { .sa_handler = _urg_handler, - .sa_flags = SA_RESTART, }; static void _hup_handler(int num) From e3dae763ee77485bcbcf8818d2b8c9570afe3013 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 28 Nov 2016 13:36:18 +0000 Subject: [PATCH 0914/1578] iostream: Move include of asterisk.h The asterisk.h header file needs to be included first or else some things go awry, such as: implicit declaration of function 'vasprintf' Change-Id: I981dc2a77a1ba791888e4f1726644d4656c0407c --- main/iostream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/iostream.c b/main/iostream.c index 46abc18a5c8..008888142b4 100644 --- a/main/iostream.c +++ b/main/iostream.c @@ -16,10 +16,11 @@ * at the top of the source tree. */ +#include "asterisk.h" + #include #include -#include "asterisk.h" #include "asterisk/utils.h" #include "asterisk/astobj2.h" #include "asterisk/iostream.h" From 8a682897668d8b0c93a7ba99e59bc773af4c9528 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 28 Nov 2016 10:03:23 -0700 Subject: [PATCH 0915/1578] build_tools: Fix download_externals to handle certified branches download_externals wasn't handling the "certified/13.x" version correctly. Change-Id: I124d195bb117ca36fd7bf1150c630f3b474a9d9a --- build_tools/download_externals | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_tools/download_externals b/build_tools/download_externals index 2bc357c2989..d2e2e4fffa3 100755 --- a/build_tools/download_externals +++ b/build_tools/download_externals @@ -45,11 +45,11 @@ if [[ -z ${cache_dir} ]] ; then fi version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR}) -if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then +if [[ ! ${version} =~ ^(GIT-)?(certified/)?([^.-]+)[.-].* ]] ; then echo "${module_name}: Couldn't parse version ${version}" exit 1 fi -major_version=${BASH_REMATCH[2]} +major_version=${BASH_REMATCH[3]} if [[ "${major_version}" == "master" ]] ; then echo "${module_name}: External module downloading is not available in the 'master' git branch. Please disable in menuselect and download manually." From 0e157607957387ff211f4fa56eda58846617cb15 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 22 Nov 2016 10:27:46 -0600 Subject: [PATCH 0916/1578] res_pjsip/chan_sip: Advertise 'ws' in the SIP URI transport parameter Per RFC 7118 5.2, the SIP URI 'transport' parameter should advertise 'ws' when WebSockets are to be used as the transport. This applies to both secure and insecure WebSockets. There were two bugs in Asterisk with respect to this: (1) The most egregious occurs in res_pjsip. There, we advertise 'ws' for insecure websockets and 'wss' for secure websockets. While this would seem to make sense - since 'WS' and 'WSS' are used for the Via Transport parameter - this is not the case for the SIP URI. This patch corrects that by registering the secure websockets with pjproject using the shorthand 'WS', and by returning 'ws' when asked for the transport parameter. Note that in pjproject, it is perfectly valid to have multiple transports use the same shorthand. (2) In chan_sip, we return an upper-case version of the transport 'WS' instead of 'ws'. Since we should be strict in what we send and liberal in what we accept (within reason), this patch lower-cases the transport before appending it to the parameter. ASTERISK-24330 #close Reported by: cervajs, Inaki Baz Castillo Change-Id: Iff77b645f8cc3b7cd35168a6676c26b147f22f42 --- channels/chan_sip.c | 3 ++- res/res_pjsip_transport_websocket.c | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 870b53edf86..126a926bd9c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -14153,6 +14153,7 @@ static void build_contact(struct sip_pvt *p, struct sip_request *req, int incomi char tmp[SIPBUFSIZE]; char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user); int use_sips; + char *transport = ast_strdupa(sip_get_transport(p->socket.type)); if (incoming) { use_sips = uas_sips_contact(req); @@ -14167,7 +14168,7 @@ static void build_contact(struct sip_pvt *p, struct sip_request *req, int incomi } else { ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>", use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@", - ast_sockaddr_stringify_remote(&p->ourip), sip_get_transport(p->socket.type)); + ast_sockaddr_stringify_remote(&p->ourip), ast_str_to_lower(transport)); } } diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index b9d94ea3c65..a9f5268846f 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -378,7 +378,6 @@ static void websocket_cb(struct ast_websocket *session, struct ast_variable *par static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata) { static const pj_str_t STR_WS = { "ws", 2 }; - static const pj_str_t STR_WSS = { "wss", 3 }; pjsip_contact_hdr *contact; long type = rdata->tp_info.transport->key.type; @@ -395,7 +394,7 @@ static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata) uri->port = rdata->pkt_info.src_port; ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n", (int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port); - pj_strdup(rdata->tp_info.pool, &uri->transport_param, (type == (long)transport_type_ws) ? &STR_WS : &STR_WSS); + pj_strdup(rdata->tp_info.pool, &uri->transport_param, &STR_WS); } rdata->msg_info.via->rport_param = 0; @@ -431,7 +430,7 @@ static int load_module(void) CHECK_PJSIP_MODULE_LOADED(); pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE, "WS", 5060, &transport_type_ws); - pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "WSS", 5060, &transport_type_wss); + pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "WS", 5060, &transport_type_wss); if (ast_sip_register_service(&websocket_module) != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; From a3f48be0da4f1261cfcfd548aaf2c8778ee6da43 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Mon, 28 Nov 2016 15:12:08 -0600 Subject: [PATCH 0917/1578] res/res_pjsip: Fix documentation whitespace issues Tabs > Spaces. Change-Id: If1e43a71822615a898e958e0f8b2e882606f0bd0 --- res/res_pjsip.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 98530cb7bcf..8c2d37137d7 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -925,14 +925,14 @@ On outbound requests, force the user portion of the Contact header to this value. - - Allow the sending and receiving RTP codec to differ - - When set to "yes" the codec in use for sending will be allowed to differ from - that of the received one. PJSIP will not automatically switch the sending one - to the receiving one. - - + + Allow the sending and receiving RTP codec to differ + + When set to "yes" the codec in use for sending will be allowed to differ from + that of the received one. PJSIP will not automatically switch the sending one + to the receiving one. + + Authentication type From 0e214c4932d31c7a2ecb0ff4bd602043e725c60d Mon Sep 17 00:00:00 2001 From: "Eduardo S. Libardi" Date: Mon, 28 Nov 2016 23:43:53 -0200 Subject: [PATCH 0918/1578] res_calendar_caldav: Add support reading gmail calendar The response from gmail calendar includes the string name "caldav:calendar-data". res_calendar_caldav implements the example included in RFC 4791: string "C:calendar-data". When reading the calendar, res_calendar_caldav compare the string and if does not match just discards the event. This commit compares the response to both strings, successfully loading gmail calendar events. Writing to gmail calendar is working prior to this fix. ASTERISK-26624 Reported by: Eduardo S. Libardi Change-Id: Ia1eef10552ae616efb645d390f5ffe81260d7d4a --- res/res_calendar_caldav.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c index 11650375bd8..8a603cf47a0 100644 --- a/res/res_calendar_caldav.c +++ b/res/res_calendar_caldav.c @@ -480,7 +480,7 @@ static void handle_start_element(void *data, const xmlChar *fullname, const xmlC { struct xmlstate *state = data; - if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) { + if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data") || !xmlStrcasecmp(fullname, BAD_CAST "caldav:calendar-data")) { state->in_caldata = 1; ast_str_reset(state->cdata); } @@ -494,7 +494,7 @@ static void handle_end_element(void *data, const xmlChar *name) icalcomponent *iter; icalcomponent *comp; - if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) { + if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data") && xmlStrcasecmp(name, BAD_CAST "caldav:calendar-data")) { return; } From ddc951060ad748c31fb5c37b82d258ef6bfaa7f2 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Mon, 21 Nov 2016 16:43:47 -0500 Subject: [PATCH 0919/1578] app_originate: Add option to execute gosub prior to dial Issue/patch ASTERISK-26587 was inspired by issue ASTERISK-22992 that requested ability to add callerid into app_originate. Comments in that issue suggested that it was better solved by adding an option to gosub prior to originating the call. The attached patch implements this much like app_dial with two options one to gosub on the originating channel and one to gosub on the newly created channel and behaves just like app_dial. I have tested this patch by adding callerid info to the new channel and also SIPAddHeader (to e.g. add header to force auto answer) and confirmed it works. Have also tested both 'exten' and 'app' versions of app_originate. Opened by: dkerr Patch by: dkerr Change-Id: I36abc39b58567ffcab4a636ea196ef48be234c57 --- CHANGES | 6 ++++ apps/app_originate.c | 74 +++++++++++++++++++++++++++++++++++++++--- include/asterisk/pbx.h | 12 +++++++ main/pbx.c | 52 +++++++++++++++++++++++++++-- 4 files changed, 137 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index cb3fe951d35..448657def40 100644 --- a/CHANGES +++ b/CHANGES @@ -62,6 +62,12 @@ RTP when you use more than 32 formats and calls are not accepted by a remote implementation, please report this and go back to rtp_pt_dynamic = 96. +app_originate +------------------ + * Added support to gosub predial routines on both original channel and on the + created channel using options parameter (like app_dial) B() and b(). This + allows for adding variables to newly created channel or, e.g. setting callerid. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ---------- ------------------------------------------------------------------------------ diff --git a/apps/app_originate.c b/apps/app_originate.c index 99984f5510b..cf4ef8ef38c 100644 --- a/apps/app_originate.c +++ b/apps/app_originate.c @@ -72,6 +72,30 @@ static const char app_originate[] = "Originate"; Timeout in seconds. Default is 30 seconds. + + + + + + This application originates an outbound call and connects it to a specified extension or application. This application will block until the outgoing call fails or gets answered. At that point, this application will exit with the status variable set and dialplan processing will continue. @@ -95,6 +119,25 @@ static const char app_originate[] = "Originate"; ***/ + +enum { + OPT_PREDIAL_CALLEE = (1 << 0), + OPT_PREDIAL_CALLER = (1 << 1), +}; + +enum { + OPT_ARG_PREDIAL_CALLEE, + OPT_ARG_PREDIAL_CALLER, + /* note: this entry _MUST_ be the last one in the enum */ + OPT_ARG_ARRAY_SIZE, +}; + +AST_APP_OPTIONS(originate_exec_options, BEGIN_OPTIONS + AST_APP_OPTION_ARG('b', OPT_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLEE), + AST_APP_OPTION_ARG('B', OPT_PREDIAL_CALLER, OPT_ARG_PREDIAL_CALLER), +END_OPTIONS ); + + static int originate_exec(struct ast_channel *chan, const char *data) { AST_DECLARE_APP_ARGS(args, @@ -104,7 +147,11 @@ static int originate_exec(struct ast_channel *chan, const char *data) AST_APP_ARG(arg2); AST_APP_ARG(arg3); AST_APP_ARG(timeout); + AST_APP_ARG(options); ); + struct ast_flags64 opts = { 0, }; + char *opt_args[OPT_ARG_ARRAY_SIZE]; + char *predial_callee = NULL; char *parse; char *chantech, *chandata; int res = -1; @@ -157,6 +204,25 @@ static int originate_exec(struct ast_channel *chan, const char *data) goto return_cleanup; } + if (!ast_strlen_zero(args.options) && + ast_app_parse_options64(originate_exec_options, &opts, opt_args, args.options)) { + ast_log(LOG_ERROR, "Invalid options: '%s'\n", args.options); + goto return_cleanup; + } + + /* PREDIAL: Run gosub on the caller's channel */ + if (ast_test_flag64(&opts, OPT_PREDIAL_CALLER) + && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) { + ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]); + ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0); + } + + if (ast_test_flag64(&opts, OPT_PREDIAL_CALLEE) + && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) { + ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLEE]); + predial_callee = opt_args[OPT_ARG_PREDIAL_CALLEE]; + } + if (!strcasecmp(args.type, "exten")) { int priority = 1; /* Initialized in case priority not specified */ const char *exten = args.arg2; @@ -175,16 +241,16 @@ static int originate_exec(struct ast_channel *chan, const char *data) ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n", chantech, chandata, args.arg1, exten, priority); - ast_pbx_outgoing_exten(chantech, cap_slin, chandata, + ast_pbx_outgoing_exten_predial(chantech, cap_slin, chandata, timeout * 1000, args.arg1, exten, priority, &outgoing_status, 1, NULL, - NULL, NULL, NULL, NULL, 0, NULL); + NULL, NULL, NULL, NULL, 0, NULL, predial_callee); } else if (!strcasecmp(args.type, "app")) { ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n", chantech, chandata, args.arg1, S_OR(args.arg2, "")); - ast_pbx_outgoing_app(chantech, cap_slin, chandata, + ast_pbx_outgoing_app_predial(chantech, cap_slin, chandata, timeout * 1000, args.arg1, args.arg2, &outgoing_status, 1, NULL, - NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, predial_callee); } else { ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n", args.type); diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 6da44703498..00ca4acbefd 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1176,6 +1176,12 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids); +int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr, + int timeout, const char *context, const char *exten, int priority, int *reason, + int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, + const char *account, struct ast_channel **locked_channel, int early_media, + const struct ast_assigned_ids *assignedids, const char *predial_callee); + /*! * \brief Synchronously or asynchronously make an outbound call and execute an * application on the channel. @@ -1211,6 +1217,12 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha const char *account, struct ast_channel **locked_channel, const struct ast_assigned_ids *assignedids); +int ast_pbx_outgoing_app_predial(const char *type, struct ast_format_cap *cap, const char *addr, + int timeout, const char *app, const char *appdata, int *reason, int synchronous, + const char *cid_num, const char *cid_name, struct ast_variable *vars, + const char *account, struct ast_channel **locked_channel, + const struct ast_assigned_ids *assignedids, const char *predial_callee); + /*! * \brief Evaluate a condition * diff --git a/main/pbx.c b/main/pbx.c index e5c3d3c0796..208c2308b95 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -7631,11 +7631,13 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, - const struct ast_assigned_ids *assignedids) + const struct ast_assigned_ids *assignedids, const char *predial_callee) { RAII_VAR(struct pbx_outgoing *, outgoing, NULL, ao2_cleanup); struct ast_channel *dialed; pthread_t thread; + char tmp_cid_name[128]; + char tmp_cid_num[128]; outgoing = ao2_alloc(sizeof(*outgoing), pbx_outgoing_destroy); if (!outgoing) { @@ -7662,6 +7664,11 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, ast_dial_set_global_timeout(outgoing->dial, timeout); + if (!ast_strlen_zero(predial_callee)) { + /* note casting to void * here to suppress compiler warning message (passing const to non-const function) */ + ast_dial_option_global_enable(outgoing->dial, AST_DIAL_OPTION_PREDIAL, (void *)predial_callee); + } + if (ast_dial_prerun(outgoing->dial, NULL, cap)) { if (synchronous && reason) { *reason = pbx_dial_reason(AST_DIAL_RESULT_FAILED, @@ -7686,6 +7693,25 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, ast_channel_stage_snapshot_done(dialed); } ast_set_flag(ast_channel_flags(dialed), AST_FLAG_ORIGINATED); + + if (!ast_strlen_zero(predial_callee)) { + char *tmp = NULL; + /* + * The predial sub routine may have set callerid so set this into the new channel + * Note... cid_num and cid_name parameters to this function will always be NULL if + * predial_callee is non-NULL so we are not overwriting anything here. + */ + tmp = S_COR(ast_channel_caller(dialed)->id.number.valid, ast_channel_caller(dialed)->id.number.str, NULL); + if (tmp) { + ast_copy_string(tmp_cid_num, tmp, sizeof(tmp_cid_num)); + cid_num = tmp_cid_num; + } + tmp = S_COR(ast_channel_caller(dialed)->id.name.valid, ast_channel_caller(dialed)->id.name.str, NULL); + if (tmp) { + ast_copy_string(tmp_cid_name, tmp, sizeof(tmp_cid_name)); + cid_name = tmp_cid_name; + } + } ast_channel_unlock(dialed); if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) { @@ -7793,6 +7819,16 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids) +{ + return ast_pbx_outgoing_exten_predial(type, cap, addr, timeout, context, exten, priority, reason, + synchronous, cid_num, cid_name, vars, account, locked_channel, early_media, assignedids, NULL); +} + +int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr, + int timeout, const char *context, const char *exten, int priority, int *reason, + int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, + const char *account, struct ast_channel **locked_channel, int early_media, + const struct ast_assigned_ids *assignedids, const char *predial_callee) { int res; int my_reason; @@ -7807,7 +7843,7 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority, NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel, - early_media, assignedids); + early_media, assignedids, predial_callee); if (res < 0 /* Call failed to get connected for some reason. */ && 1 < synchronous @@ -7847,6 +7883,16 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, const struct ast_assigned_ids *assignedids) +{ + return ast_pbx_outgoing_app_predial(type, cap, addr, timeout, app, appdata, reason, synchronous, + cid_num, cid_name, vars, account, locked_channel, assignedids, NULL); +} + +int ast_pbx_outgoing_app_predial(const char *type, struct ast_format_cap *cap, const char *addr, + int timeout, const char *app, const char *appdata, int *reason, int synchronous, + const char *cid_num, const char *cid_name, struct ast_variable *vars, + const char *account, struct ast_channel **locked_channel, + const struct ast_assigned_ids *assignedids, const char *predial_callee) { if (reason) { *reason = 0; @@ -7860,7 +7906,7 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata, reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0, - assignedids); + assignedids, predial_callee); } /* this is the guts of destroying a context -- From e5e887be53ceb0b3ae4c0aa5a5cd055bd524fbde Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Tue, 15 Nov 2016 16:01:27 -0500 Subject: [PATCH 0920/1578] chan_pjsip: fix switching sending codec when asymmetric_rtp_codec=no The sending codec is switched to the receiving codec and then is switched back to the best native codec on EVERY receiving RTP packets. This is because after call of ast_channel_set_rawwriteformat there is call of ast_set_write_format which calls set_format which sets rawwriteformat to the best native format. This patch adds a new function ast_set_write_format_path which set specific write path on channel and uses this function to switch the sending codec. ASTERISK-26603 #close Change-Id: I5b7d098f8b254ce8f45546e6c36e5d324737f71d --- channels/chan_pjsip.c | 9 ++++++--- include/asterisk/channel.h | 15 +++++++++++++++ main/channel.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index d4a7d618dd9..4aae15ce972 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -677,7 +677,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se return f; } -/*! \brief Function called by core to read any waiting frames */ +/*! + * \brief Function called by core to read any waiting frames + * + * \note The channel is already locked. + */ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); @@ -735,8 +739,7 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when we're sending '%s', switching to match\n", ast_format_get_name(f->subclass.format), ast_channel_name(ast), ast_format_get_name(ast_channel_rawwriteformat(ast))); - ast_channel_set_rawwriteformat(ast, f->subclass.format); - ast_set_write_format(ast, ast_channel_writeformat(ast)); + ast_set_write_format_path(ast, ast_channel_writeformat(ast), f->subclass.format); if (ast_channel_is_bridged(ast)) { ast_channel_set_unbridged_nolock(ast, 1); diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 5c73c777e5c..6f220271a55 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -1992,6 +1992,21 @@ int ast_prod(struct ast_channel *chan); */ int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_format, struct ast_format *core_format); +/*! + * \brief Set specific write path on channel. + * \since 13.13.0 + * + * \param chan Channel to setup write path. + * \param core_format What the core wants to write. + * \param raw_format Raw write format. + * + * \pre chan is locked + * + * \retval 0 on success. + * \retval -1 on error. + */ +int ast_set_write_format_path(struct ast_channel *chan, struct ast_format *core_format, struct ast_format *raw_format); + /*! * \brief Sets read format on channel chan from capabilities * Set read format for channel to whichever component of "format" is best. diff --git a/main/channel.c b/main/channel.c index bd5f351724a..bcfb8afa9d0 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5474,6 +5474,42 @@ int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_fo return 0; } +int ast_set_write_format_path(struct ast_channel *chan, struct ast_format *core_format, struct ast_format *raw_format) +{ + struct ast_trans_pvt *trans_old; + struct ast_trans_pvt *trans_new; + + if (ast_format_cmp(ast_channel_rawwriteformat(chan), raw_format) == AST_FORMAT_CMP_EQUAL + && ast_format_cmp(ast_channel_writeformat(chan), core_format) == AST_FORMAT_CMP_EQUAL) { + /* Nothing to setup */ + return 0; + } + + ast_debug(1, "Channel %s setting write format path: %s -> %s\n", + ast_channel_name(chan), + ast_format_get_name(core_format), + ast_format_get_name(raw_format)); + + /* Setup new translation path. */ + if (ast_format_cmp(raw_format, core_format) != AST_FORMAT_CMP_EQUAL) { + trans_new = ast_translator_build_path(raw_format, core_format); + if (!trans_new) { + return -1; + } + } else { + /* No translation needed. */ + trans_new = NULL; + } + trans_old = ast_channel_writetrans(chan); + if (trans_old) { + ast_translator_free_path(trans_old); + } + ast_channel_writetrans_set(chan, trans_new); + ast_channel_set_rawwriteformat(chan, raw_format); + ast_channel_set_writeformat(chan, core_format); + return 0; +} + struct set_format_access { const char *direction; struct ast_trans_pvt *(*get_trans)(const struct ast_channel *chan); From 621d886ca70dc12cdce52c6c7a0813d580e8988c Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 30 Nov 2016 10:48:39 -0600 Subject: [PATCH 0921/1578] Frame deferral: Re-queue deferred frames one-at-a-time. The recent change that made frame deferral into an API had a behavior change to it. When frame deferral was completed, we would take all of the deferred frames and queue them all onto the channel in one call to ast_queue_frame_head(). Before frame deferral was API-ized, places that performed manual frame deferral would actually take each deferred frame and queue them onto the channel. This change in behavior caused the confbridge_recording test to start failing consistently. Without going too crazily deep into the details, a channel was getting "stuck" in an ast_safe_sleep(). An AMI redirect was attempting to break it out of the sleep, but because there were more frames in the channel read queue than expected, the channel ended up being unable to break from its sleep loop. By restoring the behavior of individual frame queuing after deferral, the test starts passing again. Note, this points to a potential underlying issue pointing to an "unbalance" that can occur when queuing multiple frames at once, and so a follow-up issue is being created to investigate that possibility. Change-Id: Ied5dacacda06d343dea751ed5814a03364fe5a7d --- main/channel.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/main/channel.c b/main/channel.c index bcfb8afa9d0..00cfa31aa07 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1070,16 +1070,15 @@ void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups) void ast_channel_stop_defer_frames(struct ast_channel *chan) { + struct ast_frame *f; + ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); /* Move the deferred frames onto the channel read queue, ahead of other queued frames */ - ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan))); - /* ast_frfree will mosey down the list and free them all */ - if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) { - ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan))); + while ((f = AST_LIST_REMOVE_HEAD(ast_channel_deferred_readq(chan), frame_list))) { + ast_queue_frame_head(chan, f); + ast_frfree(f); } - /* Reset the list to be empty */ - AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan)); } static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after) @@ -3901,10 +3900,10 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) struct ast_frame *dup; dup = ast_frdup(f); - AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list); + AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), dup, frame_list); } } else { - AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list); + AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), f, frame_list); AST_LIST_REMOVE_CURRENT(frame_list); } } From 1dfa11b65cd3bd768605eb7779214e4330f52ed3 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 23 Nov 2016 18:27:54 -0600 Subject: [PATCH 0922/1578] PJPROJECT logging: Made easier to get available logging levels. Use of the new logging is as simple as issuing the new CLI command or setting the new pjproject.conf option. Other options that can affect the logging are how you have the pjproject log levels mapped to Asterisk log types in pjproject.conf and if you have configured Asterisk to log the DEBUG type messages. Altering the pjproject.conf level mapping shouldn't be necessary for most installations as the default mapping is sensible. Configuring Asterisk to log the DEBUG message type is standard practice for collecting debug information. * Added CLI "pjproject set log level" command to dynamically adjust the maximum pjproject log message level. * Added CLI "pjproject show log level" command to see the currently set maximum pjproject log message level. * Added pjproject.conf startup section "log_level" option to set the initial maximum pjproject log message level so all messages could be captured from initialization. * Set PJ_LOG_MAX_LEVEL to 6 to compile in all defined logging levels into bundled pjproject. Pjproject will use the currently set run time log level to determine if a log message is generated just like Asterisk verbose and debug logging levels. * In log_forwarder(), made always log enabled and mapped pjproject log messages. DEBUG mapped log messages are no longer gated by the current Asterisk debug logging level. * Removed RAII_VAR() from res_pjproject.c:get_log_level(). ASTERISK-26630 #close Change-Id: I6dca12979f482ffb0450aaf58db0fe0f6d2e5389 --- CHANGES | 21 ++- configs/samples/pjproject.conf.sample | 25 +++- include/asterisk/options.h | 14 ++ main/asterisk.c | 33 +++++ main/libasteriskpj.c | 2 + res/res_pjproject.c | 145 +++++++++++++++++--- res/res_rtp_asterisk.c | 2 + third-party/pjproject/patches/config_site.h | 2 +- 8 files changed, 223 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index cb3fe951d35..886cd00d3db 100644 --- a/CHANGES +++ b/CHANGES @@ -63,7 +63,24 @@ RTP implementation, please report this and go back to rtp_pt_dynamic = 96. ------------------------------------------------------------------------------ ---- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ---------- +--- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ +------------------------------------------------------------------------------ + +res_pjproject +------------------ + * Added new CLI command "pjproject set log level". The new command allows + the maximum PJPROJECT log levels to be adjusted dynamically and + independently from the set debug logging level like many other similar + module debug logging commands. + + * Added new companion CLI command "pjproject show log level" to allow the + user to see the current maximum pjproject logging level. + + * Added new pjproject.conf startup section "log_level' option to set the + initial maximum PJPROJECT logging level. + +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------ ------------------------------------------------------------------------------ AMI @@ -143,7 +160,7 @@ res_ari ARI event. ------------------------------------------------------------------------------ ---- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- +--- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ------------ ------------------------------------------------------------------------------ Build System diff --git a/configs/samples/pjproject.conf.sample b/configs/samples/pjproject.conf.sample index 97af7345f40..82c81a1f6e0 100644 --- a/configs/samples/pjproject.conf.sample +++ b/configs/samples/pjproject.conf.sample @@ -1,15 +1,36 @@ ; Common pjproject options ; +;[startup] +; NOTES: The name of this section in the pjproject.conf configuration file must +; remain startup or the configuration will not be applied. +; +;log_level=default ; Initial maximum pjproject logging level to log + ; Valid values are: 0-6, and default + ; + ; Note: This option is needed very early in the startup + ; process so it can only be read from config files because + ; the modules for other methods have not been loaded yet. +;type= ; Must be of type startup (default: "") + ;========================LOG_MAPPINGS SECTION OPTIONS=============================== ;[log_mappings] ; SYNOPSIS: Provides pjproject to Asterisk log level mappings. ; NOTES: The name of this section in the pjproject.conf configuration file must ; remain log_mappings or the configuration will not be applied. ; The defaults mentioned below only apply if this file or the 'log_mappings' -; object can'tbe found. If the object is found, there are no defaults. If +; object can't be found. If the object is found, there are no defaults. If ; you don't specify an entry, nothing will be logged for that level. ; +; These logging level meanings are typically used by pjproject: +; - 0: fatal error +; - 1: error +; - 2: warning +; - 3: info +; - 4: debug +; - 5: trace +; - 6: more detailed trace +; ;asterisk_error = ; A comma separated list of pjproject log levels to map to ; Asterisk errors. ; (default: "0,1") @@ -24,5 +45,5 @@ ; (default: "") ;asterisk_debug = ; A comma separated list of pjproject log levels to map to ; Asterisk debug - ; (default: "3,4,5") + ; (default: "3,4,5,6") ;type= ; Must be of type log_mappings (default: "") diff --git a/include/asterisk/options.h b/include/asterisk/options.h index 345bacf6c58..ff35c16c435 100644 --- a/include/asterisk/options.h +++ b/include/asterisk/options.h @@ -132,6 +132,20 @@ enum ast_option_flags { #define ast_opt_generic_plc ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) #define ast_opt_ref_debug ast_test_flag(&ast_options, AST_OPT_FLAG_REF_DEBUG) +/*! Maximum log level defined by PJPROJECT. */ +#define MAX_PJ_LOG_MAX_LEVEL 6 +/*! + * Normal PJPROJECT active log level used by Asterisk. + * + * These levels are usually mapped to Error and + * Warning Asterisk log levels which shouldn't + * normally be suppressed. + */ +#define DEFAULT_PJ_LOG_MAX_LEVEL 2 + +/*! Current pjproject logging level */ +extern int ast_option_pjproject_log_level; + extern struct ast_flags ast_options; extern int option_verbose; diff --git a/main/asterisk.c b/main/asterisk.c index 98ae8811f94..338c1f53b94 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -330,6 +330,7 @@ int ast_verb_sys_level; int option_verbose; /*!< Verbosity level */ int option_debug; /*!< Debug level */ +int ast_option_pjproject_log_level; double ast_option_maxload; /*!< Max load avg on system */ int ast_option_maxcalls; /*!< Max number of active calls */ int ast_option_maxfiles; /*!< Max number of open file handles (files, sockets) */ @@ -3757,6 +3758,37 @@ static void ast_readconfig(void) ast_config_destroy(cfg); } +static void read_pjproject_startup_options(void) +{ + struct ast_config *cfg; + struct ast_variable *v; + struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME }; + + ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL; + + cfg = ast_config_load2("pjproject.conf", "" /* core, can't reload */, config_flags); + if (!cfg + || cfg == CONFIG_STATUS_FILEUNCHANGED + || cfg == CONFIG_STATUS_FILEINVALID) { + /* We'll have to use defaults */ + return; + } + + for (v = ast_variable_browse(cfg, "startup"); v; v = v->next) { + if (!strcasecmp(v->name, "log_level")) { + if (sscanf(v->value, "%30d", &ast_option_pjproject_log_level) != 1) { + ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL; + } else if (ast_option_pjproject_log_level < 0) { + ast_option_pjproject_log_level = 0; + } else if (MAX_PJ_LOG_MAX_LEVEL < ast_option_pjproject_log_level) { + ast_option_pjproject_log_level = MAX_PJ_LOG_MAX_LEVEL; + } + } + } + + ast_config_destroy(cfg); +} + static void *monitor_sig_flags(void *unused) { for (;;) { @@ -4513,6 +4545,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou check_init(ast_timing_init(), "Timing"); check_init(ast_ssl_init(), "SSL"); + read_pjproject_startup_options(); check_init(ast_pj_init(), "Embedded PJProject"); check_init(app_init(), "App Core"); check_init(devstate_init(), "Device State Core"); diff --git a/main/libasteriskpj.c b/main/libasteriskpj.c index 22660e686a6..0f893a2cf72 100644 --- a/main/libasteriskpj.c +++ b/main/libasteriskpj.c @@ -35,6 +35,7 @@ #include #endif +#include "asterisk/options.h" #include "asterisk/_private.h" /* ast_pj_init() */ /*! @@ -44,6 +45,7 @@ int ast_pj_init(void) { #ifdef HAVE_PJPROJECT_BUNDLED + pj_log_set_level(ast_option_pjproject_log_level); pj_init(); #endif return 0; diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 66c95f2b754..476defb4168 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -41,6 +41,27 @@ pjproject common configuration + + Asterisk startup time options for PJPROJECT + + The id of this object, as well as its type, must be + 'startup' or it won't be found. + + + Must be of type 'startup'. + + + Initial maximum pjproject logging level to log. + + Valid values are: 0-6, and default + + This option is needed very early in the startup process + so it can only be read from config files because the + modules for other methods have not been loaded yet. + + + + PJPROJECT to Asterisk Log Level Mapping Warnings and errors in the pjproject libraries are generally handled @@ -64,7 +85,7 @@ A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE. - + A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG. @@ -82,6 +103,7 @@ #include #include +#include "asterisk/options.h" #include "asterisk/logger.h" #include "asterisk/module.h" #include "asterisk/cli.h" @@ -144,9 +166,11 @@ static struct log_mappings *get_log_mappings(void) static int get_log_level(int pj_level) { - RAII_VAR(struct log_mappings *, mappings, get_log_mappings(), ao2_cleanup); + int mapped_level; unsigned char l; + struct log_mappings *mappings; + mappings = get_log_mappings(); if (!mappings) { return __LOG_ERROR; } @@ -154,18 +178,21 @@ static int get_log_level(int pj_level) l = '0' + fmin(pj_level, 9); if (strchr(mappings->asterisk_error, l)) { - return __LOG_ERROR; + mapped_level = __LOG_ERROR; } else if (strchr(mappings->asterisk_warning, l)) { - return __LOG_WARNING; + mapped_level = __LOG_WARNING; } else if (strchr(mappings->asterisk_notice, l)) { - return __LOG_NOTICE; + mapped_level = __LOG_NOTICE; } else if (strchr(mappings->asterisk_verbose, l)) { - return __LOG_VERBOSE; + mapped_level = __LOG_VERBOSE; } else if (strchr(mappings->asterisk_debug, l)) { - return __LOG_DEBUG; + mapped_level = __LOG_DEBUG; + } else { + mapped_level = __LOG_SUPPRESS; } - return __LOG_SUPPRESS; + ao2_ref(mappings, -1); + return mapped_level; } static void log_forwarder(int level, const char *data, int len) @@ -192,13 +219,6 @@ static void log_forwarder(int level, const char *data, int len) return; } - if (ast_level == __LOG_DEBUG) { - /* Obey the debug level for res_pjproject */ - if (!DEBUG_ATLEAST(level)) { - return; - } - } - /* PJPROJECT uses indention to indicate function call depth. We'll prepend * log statements with a tab so they'll have a better shot at lining * up */ @@ -349,9 +369,95 @@ static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd return CLI_SUCCESS; } +struct max_pjproject_log_level_check { + /*! + * Compile time sanity check to determine if + * MAX_PJ_LOG_MAX_LEVEL matches CLI syntax. + */ + char check[1 / (6 == MAX_PJ_LOG_MAX_LEVEL)]; +}; + +static char *handle_pjproject_set_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + int level_new; + int level_old; + + switch (cmd) { + case CLI_INIT: + e->command = "pjproject set log level {default|0|1|2|3|4|5|6}"; + e->usage = + "Usage: pjproject set log level {default|}\n" + "\n" + " Set the maximum active pjproject logging level.\n" + " See pjproject.conf.sample for additional information\n" + " about the various levels pjproject uses.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 5) { + return CLI_SHOWUSAGE; + } + + if (!strcasecmp(a->argv[4], "default")) { + level_new = DEFAULT_PJ_LOG_MAX_LEVEL; + } else { + if (sscanf(a->argv[4], "%30d", &level_new) != 1 + || level_new < 0 || MAX_PJ_LOG_MAX_LEVEL < level_new) { + return CLI_SHOWUSAGE; + } + } + + /* Update pjproject logging level */ + level_old = ast_option_pjproject_log_level; + if (level_old == level_new) { + ast_cli(a->fd, "pjproject log level is still %d.\n", level_old); + } else { + ast_cli(a->fd, "pjproject log level was %d and is now %d.\n", + level_old, level_new); + pj_log_set_level(level_new); + } + ast_option_pjproject_log_level = pj_log_get_level(); + if (ast_option_pjproject_log_level != level_new) { + ast_log(LOG_WARNING, "Asterisk built with pjproject PJ_LOG_MAX_LEVEL set too low.\n"); + } + + return CLI_SUCCESS; +} + +static char *handle_pjproject_show_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: + e->command = "pjproject show log level"; + e->usage = + "Usage: pjproject show log level\n" + "\n" + " Show the current maximum active pjproject logging level.\n" + " See pjproject.conf.sample for additional information\n" + " about the various levels pjproject uses.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 4) { + return CLI_SHOWUSAGE; + } + + ast_cli(a->fd, "pjproject log level is %d.%s\n", + ast_option_pjproject_log_level, + ast_option_pjproject_log_level == DEFAULT_PJ_LOG_MAX_LEVEL ? " (default)" : ""); + + return CLI_SUCCESS; +} + static struct ast_cli_entry pjproject_cli[] = { + AST_CLI_DEFINE(handle_pjproject_set_log_level, "Set the maximum active pjproject logging level"), AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"), AST_CLI_DEFINE(handle_pjproject_show_log_mappings, "Show pjproject to Asterisk log mappings"), + AST_CLI_DEFINE(handle_pjproject_show_log_level, "Show the maximum active pjproject logging level"), }; static int load_module(void) @@ -385,10 +491,11 @@ static int load_module(void) } ast_string_field_set(default_log_mappings, asterisk_error, "0,1"); ast_string_field_set(default_log_mappings, asterisk_warning, "2"); - ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5"); + ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5,6"); ast_sorcery_load(pjproject_sorcery); + pj_log_set_level(ast_option_pjproject_log_level); pj_init(); decor_orig = pj_log_get_decor(); @@ -403,9 +510,15 @@ static int load_module(void) */ pj_log_set_log_func(capture_buildopts_cb); pj_log_set_decor(0); + pj_log_set_level(MAX_PJ_LOG_MAX_LEVEL);/* Set level to guarantee the dump output. */ pj_dump_config(); + pj_log_set_level(ast_option_pjproject_log_level); pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT); pj_log_set_log_func(log_forwarder); + if (!AST_VECTOR_SIZE(&buildopts) + || ast_option_pjproject_log_level != pj_log_get_level()) { + ast_log(LOG_WARNING, "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL set too low.\n"); + } ast_cli_register_multiple(pjproject_cli, ARRAY_LEN(pjproject_cli)); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 4136f7e7bf0..58c217ecb48 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -52,6 +52,7 @@ #include #endif +#include "asterisk/options.h" #include "asterisk/stun.h" #include "asterisk/pbx.h" #include "asterisk/frame.h" @@ -5665,6 +5666,7 @@ static int load_module(void) #ifdef HAVE_PJPROJECT pj_lock_t *lock; + pj_log_set_level(ast_option_pjproject_log_level); if (pj_init() != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; } diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 1a48695bfb2..66e8e84d3f1 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -34,7 +34,7 @@ #define PJ_SCANNER_USE_BITWISE 0 #define PJ_OS_HAS_CHECK_STACK 0 -#define PJ_LOG_MAX_LEVEL 3 +#define PJ_LOG_MAX_LEVEL 6 #define PJ_ENABLE_EXTRA_CHECK 1 #define PJSIP_MAX_TSX_COUNT ((64*1024)-1) #define PJSIP_MAX_DIALOG_COUNT ((64*1024)-1) From 75230f4c0135f4885a49f2e5105b6ad70477f3c6 Mon Sep 17 00:00:00 2001 From: Guido Falsi Date: Tue, 22 Nov 2016 18:20:06 +0100 Subject: [PATCH 0923/1578] res_rtp: Fix regression when IPv6 is not available. The latest Release candidate fails to create RTP streams when IPv6 is not available. Due to the changes made in September the ast_sockaddr structure passed around to create these streams is always of AF_INET6 type, causing failure when used for IPv4. This patch adds a utility function to check for availability of IPv6 and applies such check at startup to determine how to create the ast_sockaddr structures. ASTERISK-26617 #close Change-Id: I627a4e91795e821111e1cda523f083a40d0e0c3e --- include/asterisk/utils.h | 9 +++++++++ main/utils.c | 12 ++++++++++++ res/res_pjsip_sdp_rtp.c | 7 ++++++- res/res_pjsip_t38.c | 7 ++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 2378c69713e..423d73b26a5 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -1126,4 +1126,13 @@ int ast_file_is_readable(const char *filename); */ int ast_compare_versions(const char *version1, const char *version2); +/* + * \brief Test that an OS supports IPv6 Networking. + * \since 13.14.0 + * + * \return True (non-zero) if the IPv6 supported. + * \return False (zero) if the OS doesn't support IPv6. + */ +int ast_check_ipv6(void); + #endif /* _ASTERISK_UTILS_H */ diff --git a/main/utils.c b/main/utils.c index 2c56af3cdc5..2033664b84d 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2391,6 +2391,18 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size) return NULL; } +int ast_check_ipv6(void) +{ + int udp6_socket = socket(AF_INET6, SOCK_DGRAM, 0); + + if (udp6_socket < 0) { + return 0; + } + + close(udp6_socket); + return 1; +} + void DO_CRASH_NORETURN ast_do_crash(void) { #if defined(DO_CRASH) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 7fd4f9abc05..4d6a1a168b9 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -38,6 +38,7 @@ #include #include +#include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/format.h" #include "asterisk/format_cap.h" @@ -1514,7 +1515,11 @@ static int load_module(void) { CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sockaddr_parse(&address_rtp, "::", 0); + if (ast_check_ipv6()) { + ast_sockaddr_parse(&address_rtp, "::", 0); + } else { + ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); + } if (!(sched = ast_sched_context_create())) { ast_log(LOG_ERROR, "Unable to create scheduler context.\n"); diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index adc99c30d6b..79dc9c3247d 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -37,6 +37,7 @@ #include #include +#include "asterisk/utils.h" #include "asterisk/module.h" #include "asterisk/udptl.h" #include "asterisk/netsock2.h" @@ -916,7 +917,11 @@ static int load_module(void) { CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sockaddr_parse(&address, "::", 0); + if (ast_check_ipv6()) { + ast_sockaddr_parse(&address, "::", 0); + } else { + ast_sockaddr_parse(&address, "0.0.0.0", 0); + } if (ast_sip_session_register_supplement(&t38_supplement)) { ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n"); From 26c8552fff499419bdf12b663e76ecfc408b3085 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 28 Jun 2016 23:26:59 +0200 Subject: [PATCH 0924/1578] OpenSSL 1.1.0 support OpenSSL 1.1.0 includes some major changes in the interface. See https://wiki.openssl.org/index.php/1.1_API_Changes . Status: Right now there are still a few deprecation notes with OpenSSL 1.1.0. But it's a start. Changes: * CRYPTO_LOCK is no longer available. Replace it with its value for now. I don't completely understand what it is used for there. * Remove several functions from libasteriskssl that seem to no longer be needed. * Structures have become opaque and are accesses with accessors. * ERR_remove_thread_state() no longer needed. * SSLv2 code now could no longer be used in 1.1. ASTERISK-26109 #close Change-Id: I5e29d477d486ca29b6aae0dc2f5dff960c1cb82b --- main/iostream.c | 10 ++++++++++ main/libasteriskssl.c | 4 +++- main/tcptls.c | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/main/iostream.c b/main/iostream.c index 008888142b4..a20a0489640 100644 --- a/main/iostream.c +++ b/main/iostream.c @@ -462,9 +462,19 @@ int ast_iostream_close(struct ast_iostream *stream) SSL_get_error(stream->ssl, res)); } +#if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L + if (!SSL_is_server(stream->ssl)) { +#else if (!stream->ssl->server) { +#endif /* For client threads, ensure that the error stack is cleared */ +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + ERR_remove_thread_state(NULL); +#else ERR_remove_state(0); +#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ +#endif /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */ } SSL_free(stream->ssl); diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c index 16a1aa7395c..9905b150c97 100644 --- a/main/libasteriskssl.c +++ b/main/libasteriskssl.c @@ -65,13 +65,14 @@ static void ssl_lock(int mode, int n, const char *file, int line) return; } - if (mode & CRYPTO_LOCK) { + if (mode & 0x1) { ast_mutex_lock(&ssl_locks[n]); } else { ast_mutex_unlock(&ssl_locks[n]); } } +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L int SSL_library_init(void) { #if defined(AST_DEVMODE) @@ -113,6 +114,7 @@ void ERR_free_strings(void) { /* we can't allow this to be called, ever */ } +#endif /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */ #endif /* HAVE_OPENSSL */ diff --git a/main/tcptls.c b/main/tcptls.c index c8ebab43470..6b040ae3e70 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -310,7 +310,7 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client) } if (client) { -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && (OPENSSL_VERSION_NUMBER < 0x10100000L) if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) { ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n"); cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method()); From 4b3d3fc7412817e76808d9ef5eff59c5713f41c5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 30 Nov 2016 18:25:11 -0600 Subject: [PATCH 0925/1578] res_pjsip_outbound_registration.c: Filter redundant statsd reporting. Increasing the testsuite shutdown timeout before forcibly killing Asterisk allowed more events to be sent out. Some tests failed as a result. The tests/channels/pjsip/statsd/registrations failed because we now get the statsd events that a comment in the test configuration stated couldn't be intercepted. Unfortunately, we get a variable number of events because of internal status state transition races generating redundant statsd events. We were reporting redundant statsd PJSIP.registrations.state changes for internal state changes that equated to the same thing publicly. * Made update_client_state_status() filter out redundant statsd updates. ASTERISK-26527 Change-Id: If851c7d514bb530d9226e4941ba97dcf52000646 --- CHANGES | 6 ++++++ res/res_pjsip_outbound_registration.c | 21 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 886cd00d3db..431218ffd18 100644 --- a/CHANGES +++ b/CHANGES @@ -79,6 +79,12 @@ res_pjproject * Added new pjproject.conf startup section "log_level' option to set the initial maximum PJPROJECT logging level. +res_pjsip_outbound_registration +------------------ + * Statsd no longer logs redundant status PJSIP.registrations.state changes + for internal state transitions that don't change the reported public status + state. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------ ------------------------------------------------------------------------------ diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 29701a13c66..d486ccd639d 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -627,15 +627,30 @@ static void schedule_registration(struct sip_outbound_registration_client_state static void update_client_state_status(struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status) { + const char *status_old; + const char *status_new; + if (client_state->status == status) { + /* Status state did not change at all. */ + return; + } + + status_old = sip_outbound_registration_status_str(client_state->status); + status_new = sip_outbound_registration_status_str(status); + client_state->status = status; + + if (!strcmp(status_old, status_new)) { + /* + * The internal status state may have changed but the status + * state we tell the world did not change at all. + */ return; } ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0, - sip_outbound_registration_status_str(client_state->status)); + status_old); ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0, - sip_outbound_registration_status_str(status)); - client_state->status = status; + status_new); } /*! \brief Callback function for unregistering (potentially) and destroying state */ From fe9f070885811c712f99317c805e3311db2ff2f0 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 6 Dec 2016 11:06:45 -0700 Subject: [PATCH 0926/1578] pjproject_bundled: Fix missing inclusion of symbols Added back in a -g3, and an -O3 when DONT_OPTIMIZE is not set, to the CFLAGS. Not sure how they went missing. Also fixed an uninstall problem where we weren't removing the symlink from libasteriskpj.so.2 to libasteriskpj.so. While I was there, I fixed it for libasteriskssl as well. Change-Id: I9e00873b1e9082d05b5549d974534b48a2142556 --- main/Makefile | 8 ++++++-- third-party/Makefile | 2 +- third-party/pjproject/Makefile | 12 ++++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/main/Makefile b/main/Makefile index 95c3c70c688..2b7321d4fe7 100644 --- a/main/Makefile +++ b/main/Makefile @@ -363,10 +363,14 @@ binuninstall: rm -f "$(DESTDIR)$(ASTSBINDIR)/$(MAIN_TGT)" rm -f "$(DESTDIR)$(ASTSBINDIR)/rasterisk" ifneq ($(ASTSSL_LIB).$(ASTSSL_SO_VERSION),.) - rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)" +# ASTSSL_SO_VERSION may not exist on Darwin + rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)" || : + rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB)" endif ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) - rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB).$(ASTPJ_SO_VERSION)" +# ASTSSL_SO_VERSION may not exist on Darwin + rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB).$(ASTPJ_SO_VERSION)" || : + rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" endif ifneq ($(LDCONFIG),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" diff --git a/third-party/Makefile b/third-party/Makefile index 0aca21e06a3..f3016f15332 100644 --- a/third-party/Makefile +++ b/third-party/Makefile @@ -13,7 +13,7 @@ override MAKECMDGOALS?=all MAKECMDGOALS:=$(subst dist-clean,distclean,$(MAKECMDGOALS)) MAKECMDGOALS:=$(subst tpclean,clean,$(MAKECMDGOALS)) -all distclean dist-clean install tpclean : $(TP_SUBDIRS) +all distclean dist-clean install uninstall tpclean : $(TP_SUBDIRS) install uninstall: $(TP_INSTALL_SUBDIRS) $(TP_SUBDIRS): diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 3f50a89b997..21bdf235e84 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -20,6 +20,11 @@ ifeq ($(findstring clean,$(MAKECMDGOALS)),clean) SPECIAL_TARGETS += clean endif +ifeq ($(findstring uninstall,$(MAKECMDGOALS)),uninstall) + SPECIAL_TARGETS += uninstall +endif + + ifneq ($(wildcard ../../makeopts),) include ../../makeopts endif @@ -62,9 +67,12 @@ ifeq ($(SPECIAL_TARGETS),) source/pjsip-apps/src/python/_pjsua.so: LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/lib/libasterisk_malloc_debug.a endif - TARGETS += pjproject.symbols - export CFLAGS += $(CF) + ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),) + CF += -O3 + endif + export CFLAGS += $(CF) -g3 export LDFLAGS += $(CC_LDFLAGS) + TARGETS += pjproject.symbols else all install: endif From bf6423a33678d95896cfb6325572dab3a23e6d6a Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 6 Dec 2016 10:56:06 -0600 Subject: [PATCH 0927/1578] Iostreams: Correct off-by-one error. ast_iostream_printf() attempts first to use a fixed-size buffer to perform its printf-like operation. If the fixed-size buffer is too small, then a heap allocation is used instead. The heap allocation in this case was exactly the length of the string to print. The issue here is that the ensuing call to vsnprintf() will print a NULL byte in the final space of the string. This meant that the final character was being chopped off the string and replaced with a NULL byte. For HTTP in particular, this caused problems because HTTP publishes the expected Contact-Length. This meant HTTP was publishing a length one character larger than what was actually present in the message. This patch corrects the issue by adding one to the allocation length. ASTERISK-26629 Reported by Joshua Colp Change-Id: Ib3c5f41e96833d0415cf000656ac368168add639 --- main/iostream.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/main/iostream.c b/main/iostream.c index a20a0489640..22cd5985c4a 100644 --- a/main/iostream.c +++ b/main/iostream.c @@ -404,7 +404,7 @@ ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buf, size_t ssize_t ast_iostream_printf(struct ast_iostream *stream, const void *fmt, ...) { - char sbuf[256], *buf = sbuf; + char sbuf[512], *buf = sbuf; int len, len2, ret = -1; va_list va; @@ -412,15 +412,18 @@ ssize_t ast_iostream_printf(struct ast_iostream *stream, const void *fmt, ...) len = vsnprintf(buf, sizeof(sbuf), fmt, va); va_end(va); - if (len > sizeof(sbuf)) { - buf = ast_malloc(len); + if (len > sizeof(sbuf) - 1) { + /* Add one to the string length to accommodate the NULL byte */ + size_t buf_len = len + 1; + + buf = ast_malloc(buf_len); if (!buf) { return -1; } va_start(va, fmt); - len2 = vsnprintf(buf, len, fmt, va); + len2 = vsnprintf(buf, buf_len, fmt, va); va_end(va); - if (len2 > len) { + if (len2 != len) { goto error; } } From 503006123a9eecdaedf74295367af99578f021b7 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 1 Dec 2016 16:49:03 -0600 Subject: [PATCH 0928/1578] http: Send headers and body in one write. This is a semi-regression caused by the iostreams change. Prior to iostreams, HTTP headers were written to a FILE handle using fprintf. Then the body was written using a call to fwrite(). Because of internal buffering, the result was that the HTTP headers and body would be sent out in a single write to the socket. With the change to iostreams, the HTTP headers are written using ast_iostream_printf(), which under the hood calls write(). The HTTP body calls ast_iostream_write(), which also calls write() under the hood. This results in two separate writes to the socket. Most HTTP client libraries out there will handle this change just fine. However, a few of our testsuite tests started failing because of the change. As a result, in order to reduce frustration for users, this change alters the HTTP code to write the headers and body in a single write operation. ASTERISK-26629 #close Reported by Joshua Colp Change-Id: Idc2d2fb3d9b3db14b8631a1e302244fa18b0e518 --- main/http.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/main/http.c b/main/http.c index 9aff4d16766..5f57b1eb01c 100644 --- a/main/http.c +++ b/main/http.c @@ -454,6 +454,7 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, int content_length = 0; int close_connection; struct ast_str *server_header_field = ast_str_create(MAX_SERVER_NAME_LENGTH); + int send_content; if (!ser || !server_header_field) { /* The connection is not open. */ @@ -504,6 +505,8 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, lseek(fd, 0, SEEK_SET); } + send_content = method != AST_HTTP_HEAD || status_code >= 400; + /* send http header */ ast_iostream_printf(ser->stream, "HTTP/1.1 %d %s\r\n" @@ -513,33 +516,25 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, "%s" "%s" "Content-Length: %d\r\n" - "\r\n", + "\r\n" + "%s", status_code, status_title ? status_title : "OK", ast_str_buffer(server_header_field), timebuf, close_connection ? "Connection: close\r\n" : "", static_content ? "" : "Cache-Control: no-cache, no-store\r\n", http_header ? ast_str_buffer(http_header) : "", - content_length + content_length, + send_content && out && ast_str_strlen(out) ? ast_str_buffer(out) : "" ); /* send content */ - if (method != AST_HTTP_HEAD || status_code >= 400) { - if (out && ast_str_strlen(out)) { - len = ast_str_strlen(out); - if (ast_iostream_write(ser->stream, ast_str_buffer(out), len) != len) { - ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno)); + if (send_content && fd) { + while ((len = read(fd, buf, sizeof(buf))) > 0) { + if (ast_iostream_write(ser->stream, buf, len) != len) { + ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); close_connection = 1; - } - } - - if (fd) { - while ((len = read(fd, buf, sizeof(buf))) > 0) { - if (ast_iostream_write(ser->stream, buf, len) != len) { - ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); - close_connection = 1; - break; - } + break; } } } From 76d52dc228ff445cdb6d597e26b5a8384fe74fb3 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 6 Dec 2016 16:45:38 -0600 Subject: [PATCH 0929/1578] Bundled pjproject: Fix finding SIP transactions. Occasionally SIP message transactions are not found when they should be. In the particular case an incoming INVITE transaction is CANCELed but the INVITE transaction cannot be found so a 481 response is returned for the CANCEL. The problematic calls have a '_' character in the Via branch parameter. The problem is in the pjproject PJ_HASH_USE_OWN_TOLOWER feature's code. The problem with the "own tolower" code is that it does not calculate the same hash value as when the pj_tolower() function is used. The "own tolower" code will erroneously modify the ASCII characters '@', '[', '\\', ']', '^', and '_'. Calls to pj_hash_calc_tolower() can use the PJ_HASH_USE_OWN_TOLOWER substitute algorithm when enabled. Calls to pj_hash_get_lower(), pj_hash_set_lower(), and pj_hash_set_np_lower() call find_entry() which never uses the PJ_HASH_USE_OWN_TOLOWER algorithm. As a result you may not be able to find a hash tabled entry because the calculated hash values would differ. * Simply disable PJ_HASH_USE_OWN_TOLOWER. ASTERISK-26490 #close Change-Id: If89bfdb5f301b8b685881a9a2a6e0c3c5af32253 --- third-party/pjproject/patches/config_site.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 66e8e84d3f1..f84adeb357e 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -43,7 +43,16 @@ #define PJ_DEBUG 0 #define PJSIP_SAFE_MODULE 0 #define PJ_HAS_STRICMP_ALNUM 0 -#define PJ_HASH_USE_OWN_TOLOWER 1 + +/* + * Do not ever enable PJ_HASH_USE_OWN_TOLOWER because the algorithm is + * inconsistently used when calculating the hash value and doesn't + * convert the same characters as pj_tolower()/tolower(). Thus you + * can get different hash values if the string hashed has certain + * characters in it. (ASCII '@', '[', '\\', ']', '^', and '_') + */ +#undef PJ_HASH_USE_OWN_TOLOWER + /* It is imperative that PJSIP_UNESCAPE_IN_PLACE remain 0 or undefined. Enabling it will result in SEGFAULTS when URIs containing escape sequences are encountered. From 3b6e6cd01c2b8ad260a08131916342f2b371d1a2 Mon Sep 17 00:00:00 2001 From: snuffy Date: Thu, 8 Dec 2016 07:22:33 +1100 Subject: [PATCH 0930/1578] tests_dns: Make DNS tests older nameser.h compatible Fix the tests for DNS to use older style nameser.h as in ASTERISK-26608. Tested on: OpenBSD 6.0, Debian 8 ASTERISK-26647 #close Change-Id: I285913c44202537c04b3ed09c015efa6e5f9052d --- tests/test_dns.c | 74 +++++++++++++++++++------------------- tests/test_dns_naptr.c | 8 ++--- tests/test_dns_query_set.c | 8 ++--- tests/test_dns_recurring.c | 26 +++++++------- tests/test_dns_srv.c | 12 +++---- 5 files changed, 64 insertions(+), 64 deletions(-) diff --git a/tests/test_dns.c b/tests/test_dns.c index fbc329b88e6..4c45c845d5e 100644 --- a/tests/test_dns.c +++ b/tests/test_dns.c @@ -304,10 +304,10 @@ AST_TEST_DEFINE(resolver_set_result) unsigned int bogus; unsigned int rcode; } results[] = { - { 0, 0, ns_r_noerror, }, - { 0, 1, ns_r_noerror, }, - { 1, 0, ns_r_noerror, }, - { 0, 0, ns_r_nxdomain, }, + { 0, 0, NOERROR, }, + { 0, 1, NOERROR, }, + { 1, 0, NOERROR, }, + { 0, 0, NXDOMAIN, }, }; int i; enum ast_test_result_state res = AST_TEST_PASS; @@ -373,7 +373,7 @@ AST_TEST_DEFINE(resolver_set_result_off_nominal) memset(&some_query, 0, sizeof(some_query)); - if (!ast_dns_resolver_set_result(&some_query, 1, 1, ns_r_noerror, "asterisk.org", + if (!ast_dns_resolver_set_result(&some_query, 1, 1, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) { ast_test_status_update(test, "Successfully added a result that was both secure and bogus\n"); result = ast_dns_query_get_result(&some_query); @@ -381,7 +381,7 @@ AST_TEST_DEFINE(resolver_set_result_off_nominal) return AST_TEST_FAIL; } - if (!ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, NULL, + if (!ast_dns_resolver_set_result(&some_query, 0, 0, NOERROR, NULL, DNS_ANSWER, DNS_ANSWER_SIZE)) { ast_test_status_update(test, "Successfully added result with no canonical name\n"); result = ast_dns_query_get_result(&some_query); @@ -440,8 +440,8 @@ AST_TEST_DEFINE(resolver_add_record) const size_t size; int visited; } records[] = { - { ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE, 0, }, - { ns_t_aaaa, ns_c_in, 12345, v6_buf, V6_BUFSIZE, 0, }, + { T_A, C_IN, 12345, v4_buf, V4_BUFSIZE, 0, }, + { T_AAAA, C_IN, 12345, v6_buf, V6_BUFSIZE, 0, }, }; int num_records_visited = 0; @@ -464,7 +464,7 @@ AST_TEST_DEFINE(resolver_add_record) memset(&some_query, 0, sizeof(some_query)); - if (ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, "asterisk.org", + if (ast_dns_resolver_set_result(&some_query, 0, 0, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) { ast_test_status_update(test, "Unable to set result for DNS query\n"); return AST_TEST_FAIL; @@ -578,12 +578,12 @@ AST_TEST_DEFINE(resolver_add_record_off_nominal) inet_ntop(AF_INET, V4, v4_buf, V4_BUFSIZE); /* Add record before setting result */ - if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) { + if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, 12345, v4_buf, V4_BUFSIZE)) { ast_test_status_update(test, "Successfully added DNS record to query before setting a result\n"); return AST_TEST_FAIL; } - if (ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, "asterisk.org", + if (ast_dns_resolver_set_result(&some_query, 0, 0, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) { ast_test_status_update(test, "Unable to set result for DNS query\n"); return AST_TEST_FAIL; @@ -593,41 +593,41 @@ AST_TEST_DEFINE(resolver_add_record_off_nominal) result = ast_dns_query_get_result(&some_query); /* Invalid RR types */ - if (!ast_dns_resolver_add_record(&some_query, -1, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) { + if (!ast_dns_resolver_add_record(&some_query, -1, C_IN, 12345, v4_buf, V4_BUFSIZE)) { ast_test_status_update(test, "Successfully added DNS record with negative RR type\n"); return AST_TEST_FAIL; } - if (!ast_dns_resolver_add_record(&some_query, ns_t_max + 1, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) { + if (!ast_dns_resolver_add_record(&some_query, 65536 + 1, C_IN, 12345, v4_buf, V4_BUFSIZE)) { ast_test_status_update(test, "Successfully added DNS record with too large RR type\n"); return AST_TEST_FAIL; } /* Invalid RR classes */ - if (!ast_dns_resolver_add_record(&some_query, ns_t_a, -1, 12345, v4_buf, V4_BUFSIZE)) { + if (!ast_dns_resolver_add_record(&some_query, T_A, -1, 12345, v4_buf, V4_BUFSIZE)) { ast_test_status_update(test, "Successfully added DNS record with negative RR class\n"); return AST_TEST_FAIL; } - if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_max + 1, 12345, v4_buf, V4_BUFSIZE)) { + if (!ast_dns_resolver_add_record(&some_query, T_A, 65536 + 1, 12345, v4_buf, V4_BUFSIZE)) { ast_test_status_update(test, "Successfully added DNS record with too large RR class\n"); return AST_TEST_FAIL; } /* Invalid TTL */ - if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, -1, v4_buf, V4_BUFSIZE)) { + if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, -1, v4_buf, V4_BUFSIZE)) { ast_test_status_update(test, "Successfully added DNS record with negative TTL\n"); return AST_TEST_FAIL; } /* No data */ - if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, NULL, 0)) { + if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, 12345, NULL, 0)) { ast_test_status_update(test, "Successfully added a DNS record with no data\n"); return AST_TEST_FAIL; } /* Lie about the length */ - if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, v4_buf, 0)) { + if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, 12345, v4_buf, 0)) { ast_test_status_update(test, "Successfully added a DNS record with length zero\n"); return AST_TEST_FAIL; } @@ -693,10 +693,10 @@ static void *resolution_thread(void *dns_query) return NULL; } - ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE); + ast_dns_resolver_set_result(query, 0, 0, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE); inet_pton(AF_INET, V4, v4_buf); - ast_dns_resolver_add_record(query, ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE); + ast_dns_resolver_add_record(query, T_A, C_IN, 12345, v4_buf, V4_BUFSIZE); test_resolver_data.resolution_complete = 1; ast_dns_resolver_completed(query); @@ -806,7 +806,7 @@ AST_TEST_DEFINE(resolver_resolve_sync) resolver_data_init(); - if (ast_dns_resolve("asterisk.org", ns_t_a, ns_c_in, &result)) { + if (ast_dns_resolve("asterisk.org", T_A, C_IN, &result)) { ast_test_status_update(test, "Resolution of address failed\n"); res = AST_TEST_FAIL; goto cleanup; @@ -876,12 +876,12 @@ AST_TEST_DEFINE(resolver_resolve_sync_off_nominal) int rr_class; struct ast_dns_result **result; } resolves [] = { - { NULL, ns_t_a, ns_c_in, &result }, - { "asterisk.org", -1, ns_c_in, &result }, - { "asterisk.org", ns_t_max + 1, ns_c_in, &result }, - { "asterisk.org", ns_t_a, -1, &result }, - { "asterisk.org", ns_t_a, ns_c_max + 1, &result }, - { "asterisk.org", ns_t_a, ns_c_in, NULL }, + { NULL, T_A, C_IN, &result }, + { "asterisk.org", -1, C_IN, &result }, + { "asterisk.org", 65536 + 1, C_IN, &result }, + { "asterisk.org", T_A, -1, &result }, + { "asterisk.org", T_A, 65536 + 1, &result }, + { "asterisk.org", T_A, C_IN, NULL }, }; int i; @@ -929,7 +929,7 @@ AST_TEST_DEFINE(resolver_resolve_sync_off_nominal) return AST_TEST_FAIL; } - if (!ast_dns_resolve("asterisk.org", ns_t_a, ns_c_in, &result)) { + if (!ast_dns_resolve("asterisk.org", T_A, C_IN, &result)) { ast_test_status_update(test, "DNS resolution succeeded when we expected it not to\n"); ast_dns_resolver_unregister(&terrible_resolver); return AST_TEST_FAIL; @@ -1052,7 +1052,7 @@ AST_TEST_DEFINE(resolver_resolve_async) goto cleanup; } - active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, async_callback, async_data); + active = ast_dns_resolve_async("asterisk.org", T_A, C_IN, async_callback, async_data); if (!active) { ast_test_status_update(test, "Asynchronous resolution of address failed\n"); res = AST_TEST_FAIL; @@ -1133,12 +1133,12 @@ AST_TEST_DEFINE(resolver_resolve_async_off_nominal) int rr_class; ast_dns_resolve_callback callback; } resolves [] = { - { NULL, ns_t_a, ns_c_in, stub_callback }, - { "asterisk.org", -1, ns_c_in, stub_callback }, - { "asterisk.org", ns_t_max + 1, ns_c_in, stub_callback }, - { "asterisk.org", ns_t_a, -1, stub_callback }, - { "asterisk.org", ns_t_a, ns_c_max + 1, stub_callback }, - { "asterisk.org", ns_t_a, ns_c_in, NULL }, + { NULL, T_A, C_IN, stub_callback }, + { "asterisk.org", -1, C_IN, stub_callback }, + { "asterisk.org", 65536 + 1, C_IN, stub_callback }, + { "asterisk.org", T_A, -1, stub_callback }, + { "asterisk.org", T_A, 65536 + 1, stub_callback }, + { "asterisk.org", T_A, C_IN, NULL }, }; struct ast_dns_query_active *active; @@ -1184,7 +1184,7 @@ AST_TEST_DEFINE(resolver_resolve_async_off_nominal) return AST_TEST_FAIL; } - active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, stub_callback, NULL); + active = ast_dns_resolve_async("asterisk.org", T_A, C_IN, stub_callback, NULL); ast_dns_resolver_unregister(&terrible_resolver); @@ -1234,7 +1234,7 @@ AST_TEST_DEFINE(resolver_resolve_async_cancel) goto cleanup; } - active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, async_callback, async_data); + active = ast_dns_resolve_async("asterisk.org", T_A, C_IN, async_callback, async_data); if (!active) { ast_test_status_update(test, "Asynchronous resolution of address failed\n"); res = AST_TEST_FAIL; diff --git a/tests/test_dns_naptr.c b/tests/test_dns_naptr.c index 96c745db95b..dc9e90826de 100644 --- a/tests/test_dns_naptr.c +++ b/tests/test_dns_naptr.c @@ -116,14 +116,14 @@ static void *naptr_thread(void *dns_query) ans_size = ast_dns_test_generate_result(query, test_records, num_test_records, sizeof(struct naptr_record), generate_naptr_record, ans_buffer); - ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "goose.feathers", ans_buffer, ans_size); + ast_dns_resolver_set_result(query, 0, 0, NOERROR, "goose.feathers", ans_buffer, ans_size); for (i = 0; i < num_test_records; ++i) { char record[128]; int naptr_size; naptr_size = generate_naptr_record(&test_records[i], record); - ast_dns_resolver_add_record(query, ns_t_naptr, ns_c_in, 12345, record, naptr_size); + ast_dns_resolver_add_record(query, T_NAPTR, C_IN, 12345, record, naptr_size); } ast_dns_resolver_completed(query); @@ -209,7 +209,7 @@ AST_TEST_DEFINE(naptr_resolve_nominal) ast_dns_resolver_register(&naptr_resolver); - if (ast_dns_resolve("goose.feathers", ns_t_naptr, ns_c_in, &result)) { + if (ast_dns_resolve("goose.feathers", T_NAPTR, C_IN, &result)) { ast_test_status_update(test, "DNS resolution failed\n"); res = AST_TEST_FAIL; goto cleanup; @@ -284,7 +284,7 @@ static enum ast_test_result_state off_nominal_test(struct ast_test *test, struct ast_dns_resolver_register(&naptr_resolver); - if (ast_dns_resolve("goose.feathers", ns_t_naptr, ns_c_in, &result)) { + if (ast_dns_resolve("goose.feathers", T_NAPTR, C_IN, &result)) { ast_test_status_update(test, "Failed to perform DNS resolution, despite using valid inputs\n"); res = AST_TEST_FAIL; goto cleanup; diff --git a/tests/test_dns_query_set.c b/tests/test_dns_query_set.c index aeb61c76750..d1e9683350d 100644 --- a/tests/test_dns_query_set.c +++ b/tests/test_dns_query_set.c @@ -94,7 +94,7 @@ static void *resolution_thread(void *dns_query) ast_assert(qsdata != NULL); - ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE); + ast_dns_resolver_set_result(query, 0, 0, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE); ast_dns_resolver_completed(query); ao2_ref(query, -1); @@ -210,7 +210,7 @@ static enum ast_test_result_state query_set_test(struct ast_test *test, int reso qsdata->cancel_allowed = cancel; for (idx = 0; idx < total; ++idx) { - if (ast_dns_query_set_add(query_set, "asterisk.org", ns_t_a, ns_c_in)) { + if (ast_dns_query_set_add(query_set, "asterisk.org", T_A, C_IN)) { ast_test_status_update(test, "Failed to add query to DNS query set\n"); res = AST_TEST_FAIL; goto cleanup; @@ -269,11 +269,11 @@ static enum ast_test_result_state query_set_test(struct ast_test *test, int reso ast_test_status_update(test, "Query did not have expected name\n"); res = AST_TEST_FAIL; } - if (ast_dns_query_get_rr_type(query) != ns_t_a) { + if (ast_dns_query_get_rr_type(query) != T_A) { ast_test_status_update(test, "Query did not have expected type\n"); res = AST_TEST_FAIL; } - if (ast_dns_query_get_rr_class(query) != ns_c_in) { + if (ast_dns_query_get_rr_class(query) != C_IN) { ast_test_status_update(test, "Query did not have expected class\n"); res = AST_TEST_FAIL; } diff --git a/tests/test_dns_recurring.c b/tests/test_dns_recurring.c index d1add6ee1f6..2596e436a01 100644 --- a/tests/test_dns_recurring.c +++ b/tests/test_dns_recurring.c @@ -129,13 +129,13 @@ static void *resolution_thread(void *dns_query) /* When the query isn't canceled, we set the TTL of the results based on what * we've been told to set it to */ - ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE); + ast_dns_resolver_set_result(query, 0, 0, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE); inet_pton(AF_INET, ADDR1, addr1_buf); - ast_dns_resolver_add_record(query, ns_t_a, ns_c_in, rdata->ttl1, addr1_buf, ADDR1_BUFSIZE); + ast_dns_resolver_add_record(query, T_A, C_IN, rdata->ttl1, addr1_buf, ADDR1_BUFSIZE); inet_pton(AF_INET, ADDR2, addr2_buf); - ast_dns_resolver_add_record(query, ns_t_a, ns_c_in, rdata->ttl2, addr2_buf, ADDR2_BUFSIZE); + ast_dns_resolver_add_record(query, T_A, C_IN, rdata->ttl2, addr2_buf, ADDR2_BUFSIZE); ++rdata->complete_resolutions; @@ -308,7 +308,7 @@ AST_TEST_DEFINE(recurring_query) rdata->ttl1 = 5; rdata->ttl2 = 20; - recurring_query = ast_dns_resolve_recurring("asterisk.org", ns_t_a, ns_c_in, async_callback, rdata); + recurring_query = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, async_callback, rdata); if (!recurring_query) { ast_test_status_update(test, "Failed to create recurring DNS query\n"); res = AST_TEST_FAIL; @@ -382,12 +382,12 @@ AST_TEST_DEFINE(recurring_query_off_nominal) int rr_class; ast_dns_resolve_callback callback; } resolves [] = { - { NULL, ns_t_a, ns_c_in, stub_callback }, - { "asterisk.org", -1, ns_c_in, stub_callback }, - { "asterisk.org", ns_t_max + 1, ns_c_in, stub_callback }, - { "asterisk.org", ns_t_a, -1, stub_callback }, - { "asterisk.org", ns_t_a, ns_c_max + 1, stub_callback }, - { "asterisk.org", ns_t_a, ns_c_in, NULL }, + { NULL, T_A, C_IN, stub_callback }, + { "asterisk.org", -1, C_IN, stub_callback }, + { "asterisk.org", 65536 + 1, C_IN, stub_callback }, + { "asterisk.org", T_A, -1, stub_callback }, + { "asterisk.org", T_A, 65536 + 1, stub_callback }, + { "asterisk.org", T_A, C_IN, NULL }, }; int i; enum ast_test_result_state res = AST_TEST_PASS; @@ -432,7 +432,7 @@ AST_TEST_DEFINE(recurring_query_off_nominal) return AST_TEST_FAIL; } - recurring = ast_dns_resolve_recurring("asterisk.org", ns_t_a, ns_c_in, stub_callback, NULL); + recurring = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, stub_callback, NULL); ast_dns_resolver_unregister(&terrible_resolver); @@ -483,7 +483,7 @@ AST_TEST_DEFINE(recurring_query_cancel_between) rdata->ttl1 = 5; rdata->ttl2 = 20; - recurring_query = ast_dns_resolve_recurring("asterisk.org", ns_t_a, ns_c_in, async_callback, rdata); + recurring_query = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, async_callback, rdata); if (!recurring_query) { ast_test_status_update(test, "Unable to make recurring query\n"); res = AST_TEST_FAIL; @@ -566,7 +566,7 @@ AST_TEST_DEFINE(recurring_query_cancel_during) rdata->ttl1 = 5; rdata->ttl2 = 20; - recurring_query = ast_dns_resolve_recurring("asterisk.org", ns_t_a, ns_c_in, async_callback, rdata); + recurring_query = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, async_callback, rdata); if (!recurring_query) { ast_test_status_update(test, "Failed to make recurring DNS query\n"); res = AST_TEST_FAIL; diff --git a/tests/test_dns_srv.c b/tests/test_dns_srv.c index 2e89dab669e..db71beb694d 100644 --- a/tests/test_dns_srv.c +++ b/tests/test_dns_srv.c @@ -87,14 +87,14 @@ static void *srv_thread(void *dns_query) ans_size = ast_dns_test_generate_result(query, test_records, num_test_records, sizeof(struct srv_record), generate_srv_record, ans_buffer); - ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "goose.feathers", ans_buffer, ans_size); + ast_dns_resolver_set_result(query, 0, 0, NOERROR, "goose.feathers", ans_buffer, ans_size); for (i = 0; i < num_test_records; ++i) { char record[128]; int srv_size; srv_size = generate_srv_record(&test_records[i], record); - ast_dns_resolver_add_record(query, ns_t_srv, ns_c_in, 12345, record, srv_size); + ast_dns_resolver_add_record(query, T_SRV, C_IN, 12345, record, srv_size); } ast_dns_resolver_completed(query); @@ -136,7 +136,7 @@ static enum ast_test_result_state nominal_test(struct ast_test *test, struct srv ast_dns_resolver_register(&srv_resolver); - if (ast_dns_resolve("goose.feathers", ns_t_srv, ns_c_in, &result)) { + if (ast_dns_resolve("goose.feathers", T_SRV, C_IN, &result)) { ast_test_status_update(test, "DNS resolution failed\n"); res = AST_TEST_FAIL; goto cleanup; @@ -295,7 +295,7 @@ AST_TEST_DEFINE(srv_resolve_same_priority_different_weights) memset(ans_buffer, 0, sizeof(ans_buffer)); - if (ast_dns_resolve("goose.feathers", ns_t_srv, ns_c_in, &result)) { + if (ast_dns_resolve("goose.feathers", T_SRV, C_IN, &result)) { ast_test_status_update(test, "DNS resolution failed\n"); res = AST_TEST_FAIL; goto cleanup; @@ -385,7 +385,7 @@ AST_TEST_DEFINE(srv_resolve_different_priorities_different_weights) memset(ans_buffer, 0, sizeof(ans_buffer)); - if (ast_dns_resolve("goose.feathers", ns_t_srv, ns_c_in, &result)) { + if (ast_dns_resolve("goose.feathers", T_SRV, C_IN, &result)) { ast_test_status_update(test, "DNS resolution failed\n"); res = AST_TEST_FAIL; goto cleanup; @@ -462,7 +462,7 @@ static enum ast_test_result_state invalid_record_test(struct ast_test *test, str ast_dns_resolver_register(&srv_resolver); - if (ast_dns_resolve("goose.feathers", ns_t_srv, ns_c_in, &result)) { + if (ast_dns_resolve("goose.feathers", T_SRV, C_IN, &result)) { ast_test_status_update(test, "DNS resolution failed\n"); res = AST_TEST_FAIL; goto cleanup; From 79b09b5f18ad3de01030d9db1f9c45e91960fd0b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 6 Dec 2016 13:54:25 -0700 Subject: [PATCH 0931/1578] res_pjsip_registrar: AMI Add RegistrationInboundContactStatuses command The PJSIPShowRegistrationsInbound AMI command was just dumping out all AORs which was pretty useless and resource heavy since it had to get all endpoints, then all aors for each endpoint, then all contacts for each aor. PJSIPShowRegistrationInboundContactStatuses sends ContactStatusDetail events which meets the intended purpose of the other command and has significantly less overhead. Also, some additional fields that were added to Contact since the original creation of the ContactStatusDetail event have been added to the end of the event. For compatibility purposes, PJSIPShowRegistrationsInbound is left intact. ASTERISK-26644 #close Change-Id: I326f12c9ecb52bf37ba03f0748749de4da01490a --- CHANGES | 13 +++++++ include/asterisk/res_pjsip.h | 10 +++++ res/res_pjsip.c | 25 ++++++++++++- res/res_pjsip/pjsip_options.c | 14 +++++-- res/res_pjsip_registrar.c | 70 ++++++++++++++++++++++++++++++++--- 5 files changed, 122 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index df0834d1166..4c3d8dbfc47 100644 --- a/CHANGES +++ b/CHANGES @@ -91,6 +91,19 @@ res_pjsip_outbound_registration for internal state transitions that don't change the reported public status state. +res_pjsip_registrar +------------------ + * The PJSIPShowRegistrationInboundContactStatuses AMI command has been added + to return ContactStatusDetail events as opposed to + PJSIPShowRegistrationsInbound which just a dumps every defined AOR. + +res_pjsip +------------------ + * Six existing contact fields have been added to the end of the + ContactStatusDetail AMI event: + ID, AuthenticateQualify, OutboundProxy, Path, QualifyFrequency and + QualifyTimeout. Existing fields have not been disturbed. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------ ------------------------------------------------------------------------------ diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 894ea76f563..09ace0775be 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2276,6 +2276,16 @@ int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf); int ast_sip_format_endpoint_ami(struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami, int *count); +/*! + * \brief Formats the contact and sends over AMI. + * + * \param obj a pointer an ast_sip_contact_wrapper structure + * \param arg a pointer to an ast_sip_ami structure + * \param flags ignored + * \retval 0 Success, otherwise non-zero on error + */ +int ast_sip_format_contact_ami(void *obj, void *arg, int flags); + /*! * \brief Format auth details for AMI. * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 8c2d37137d7..144621f6bb9 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2102,10 +2102,31 @@ Absolute time that this contact is no longer valid after - IP address:port of the last Via header in REGISTER request + IP address:port of the last Via header in REGISTER request. + Will only appear in the event if available. - Content of the Call-ID header in REGISTER request + Content of the Call-ID header in REGISTER request. + Will only appear in the event if available. + + + The sorcery ID of the contact. + + + A boolean indicating whether a qualify should be authenticated. + + + The contact's outbound proxy. + + + The Path header received on the REGISTER. + + + The interval in seconds at which the contact will be qualified. + + + The elapsed time in decimal seconds after which an OPTIONS + message is sent before the contact is considered unavailable. diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 09fe1559bfb..d2b812dfc88 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1217,7 +1217,7 @@ static void qualify_and_schedule_all(void) } -static int format_contact_status(void *obj, void *arg, int flags) +int ast_sip_format_contact_ami(void *obj, void *arg, int flags) { struct ast_sip_contact_wrapper *wrapper = obj; struct ast_sip_contact *contact = wrapper->contact; @@ -1256,7 +1256,15 @@ static int format_contact_status(void *obj, void *arg, int flags) ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt); } ast_str_append(&buf, 0, "EndpointName: %s\r\n", - ast_sorcery_object_get_id(endpoint)); + endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, "")); + + ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact)); + ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify); + ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy); + ast_str_append(&buf, 0, "Path: %s\r\n", contact->path); + ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency); + ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout); + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); ami->count++; @@ -1269,7 +1277,7 @@ static int format_contact_status_for_aor(void *obj, void *arg, int flags) { struct ast_sip_aor *aor = obj; - return ast_sip_for_each_contact(aor, format_contact_status, arg); + return ast_sip_for_each_contact(aor, ast_sip_format_contact_ami, arg); } static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint, diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index a8d2bdc4c2c..2db75388900 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -46,11 +46,32 @@ - In response InboundRegistrationDetail events showing configuration and status - information are raised for each inbound registration object. As well as AuthDetail - events for each associated auth object. Once all events are completed an - InboundRegistrationDetailComplete is issued. - + In response, InboundRegistrationDetail events showing configuration + and status information are raised for all contacts, static or dynamic. Once all events + are completed an InboundRegistrationDetailComplete is issued. + + + This command just dumps all coonfigured AORs with contacts, even if the contact + is a permanent one. To really get just inbound registrations, use + PJSIPShowRegistrationInboundContactStatuses. + + + + + PJSIPShowRegistrationInboundContactStatuses + + + + + Lists ContactStatuses for PJSIP inbound registrations. + + + + + In response, ContactStatusDetail events showing status information + are raised for each inbound registration (dynamic contact) object. Once all events + are completed a ContactStatusDetailComplete event is issued. + ***/ @@ -785,6 +806,42 @@ static int ami_show_registrations(struct mansession *s, const struct message *m) return 0; } +static int ami_show_registration_contact_statuses(struct mansession *s, const struct message *m) +{ + int count = 0; + struct ast_sip_ami ami = { .s = s, .m = m, .arg = NULL, .action_id = astman_get_header(m, "ActionID"), }; + struct ao2_container *contacts = ast_sorcery_retrieve_by_fields( + ast_sip_get_sorcery(), "contact", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + struct ao2_iterator i; + struct ast_sip_contact *contact; + + astman_send_listack(s, m, "Following are ContactStatusEvents for each Inbound " + "registration", "start"); + + if (contacts) { + i = ao2_iterator_init(contacts, 0); + while ((contact = ao2_iterator_next(&i))) { + struct ast_sip_contact_wrapper wrapper; + + wrapper.aor_id = (char *)contact->aor; + wrapper.contact = contact; + wrapper.contact_id = (char *)ast_sorcery_object_get_id(contact); + + ast_sip_format_contact_ami(&wrapper, &ami, 0); + count++; + + ao2_ref(contact, -1); + } + ao2_iterator_destroy(&i); + ao2_ref(contacts, -1); + } + + astman_send_list_complete_start(s, m, "ContactStatusDetailComplete", count); + astman_send_list_complete_end(s); + return 0; +} + +#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES "PJSIPShowRegistrationInboundContactStatuses" #define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound" static pjsip_module registrar_module = { @@ -817,6 +874,8 @@ static int load_module(void) ast_manager_register_xml(AMI_SHOW_REGISTRATIONS, EVENT_FLAG_SYSTEM, ami_show_registrations); + ast_manager_register_xml(AMI_SHOW_REGISTRATION_CONTACT_STATUSES, EVENT_FLAG_SYSTEM, + ami_show_registration_contact_statuses); return AST_MODULE_LOAD_SUCCESS; } @@ -824,6 +883,7 @@ static int load_module(void) static int unload_module(void) { ast_manager_unregister(AMI_SHOW_REGISTRATIONS); + ast_manager_unregister(AMI_SHOW_REGISTRATION_CONTACT_STATUSES); ast_sip_unregister_service(®istrar_module); return 0; } From 5c89604a32bff8682587dd67d9cf67a9a2c70598 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 15 Nov 2016 00:18:21 +0000 Subject: [PATCH 0932/1578] res_format_attr_opus: Fix crash when fmtp contains spaces. When an opus offer or answer was received that contained an fmtp line with spaces between the attributes the module would fail to properly parse it and crash due to recursion. This change makes the module handle the space properly and also removes the recursion requirement. ASTERISK-26579 Change-Id: I01f53e5d9fa9f1925a7365f8d25071b5b3ac2dc3 --- res/res_format_attr_opus.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index 45aa5e5c678..1367f95788a 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -101,27 +101,35 @@ static int opus_clone(const struct ast_format *src, struct ast_format *dst) static void sdp_fmtp_get(const char *attributes, const char *name, int *attr) { - const char *kvp = ""; + const char *kvp = attributes; int val; - if (attributes && !(kvp = strstr(attributes, name))) { + if (ast_strlen_zero(attributes)) { return; } - /* - * If the named attribute is not at the start of the given attributes, and - * the preceding character is not a space or semicolon then it's not the - * attribute we are looking for. It's an attribute with the name embedded - * within it (e.g. ptime in maxptime, stereo in sprop-stereo). + /* This logic goes through each attribute in the fmtp line looking for the + * requested named attribute. */ - if (kvp != attributes && *(kvp - 1) != ' ' && *(kvp - 1) != ';') { - /* Keep searching as it might still be in the attributes string */ - sdp_fmtp_get(strchr(kvp, ';'), name, attr); - /* - * Otherwise it's a match, so retrieve the value and set the attribute. - */ - } else if (sscanf(kvp, "%*[^=]=%30d", &val) == 1) { - *attr = val; + while (*kvp) { + /* Skip any preceeding blanks as some implementations separate attributes using spaces too */ + kvp = ast_skip_blanks(kvp); + + /* If we are at at the requested attribute get its value and return */ + if (!strncmp(kvp, name, strlen(name)) && kvp[strlen(name)] == '=') { + if (sscanf(kvp, "%*[^=]=%30d", &val) == 1) { + *attr = val; + break; + } + } + + /* Move on to the next attribute if possible */ + kvp = strchr(kvp, ';'); + if (!kvp) { + break; + } + + kvp++; } } From c796f00c35c43972bcbfa1cba55a8862f00248a9 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Wed, 30 Nov 2016 16:31:39 +0100 Subject: [PATCH 0933/1578] chan_sip: Do not allow non-SP/HTAB between header key and colon. RFC says SIP headers look like: HCOLON = *( SP / HTAB ) ":" SWS SWS = [LWS] ; sep whitespace LWS = [*WSP CRLF] 1*WSP ; linear whitespace WSP = SP / HTAB ; from rfc2234 chan_sip implemented this: HCOLON = *( LOWCTL / SP ) ":" SWS LOWCTL = %x00-1F ; CTL without DEL This discrepancy meant that SIP proxies in front of Asterisk with chan_sip could pass on unknown headers with \x00-\x1F in them, which would be treated by Asterisk as a different (known) header. For example, the "To\x01:" header would gladly be forwarded by some proxies as irrelevant, but chan_sip would treat it as the relevant "To:" header. Those relying on a SIP proxy to scrub certain headers could mistakenly get unexpected and unvalidated data fed to Asterisk. This change fixes so chan_sip only considers SP/HTAB as valid tokens before the colon, making it agree on the headers with other speakers of SIP. ASTERISK-26433 #close AST-2016-009 Change-Id: I78086fbc524ac733b8f7f78cb423c91075fd489b --- channels/chan_sip.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 44693ef32be..7f22b96c8ce 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -8449,8 +8449,6 @@ static const char *__get_header(const struct sip_request *req, const char *name, * one afterwards. If you shouldn't do it, what absolute idiot decided it was * a good idea to say you can do it, and if you can do it, why in the hell would. * you say you shouldn't. - * Anyways, pedanticsipchecking controls whether we allow spaces before ':', - * and we always allow spaces after that for compatibility. */ const char *sname = find_alias(name, NULL); int x, len = strlen(name), slen = (sname ? 1 : 0); @@ -8463,10 +8461,10 @@ static const char *__get_header(const struct sip_request *req, const char *name, if (match || smatch) { /* skip name */ const char *r = header + (match ? len : slen ); - if (sip_cfg.pedanticsipchecking) { - r = ast_skip_blanks(r); + /* HCOLON has optional SP/HTAB; skip past those */ + while (*r == ' ' || *r == '\t') { + ++r; } - if (*r == ':') { *start = x+1; return ast_skip_blanks(r+1); From 149d8db96ce4390f52be84d5846b053e02e6b907 Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Thu, 8 Dec 2016 18:34:28 +0000 Subject: [PATCH 0934/1578] Fix IO conversion bug Expression 'rlen < 0' is always false. Unsigned type value is never < 0. Change-Id: Id9f393ff25b009a6c4a6e40b95f561a9369e4585 --- res/res_http_websocket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 106ba488bee..84138234ebf 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -490,7 +490,7 @@ const char * AST_OPTIONAL_API_NAME(ast_websocket_session_id)(struct ast_websocke */ static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len, enum ast_websocket_opcode *opcode) { - size_t rlen; + ssize_t rlen; int xlen = len; char *rbuf = buf; int sanity = 10; From fe5be81821961c09b652b029671ea72e77f3f1df Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Thu, 8 Dec 2016 18:58:19 +0000 Subject: [PATCH 0935/1578] Small code cleanup in chan_sip The conditional expressions of the 'if' operators situated alongside each other are identical. Change-Id: I2cf7c317b106ec14440c7f1b5dcfbf03639f748a --- channels/chan_sip.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 7f22b96c8ce..68b5c405dfa 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -10802,6 +10802,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action struct ast_str *vpeer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_str *tpeer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_str *joint_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE); + struct ast_str *s2 = ast_str_alloca(SIPBUFSIZE); + struct ast_str *s3 = ast_str_alloca(SIPBUFSIZE); ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s/text=%s, combined - %s\n", ast_format_cap_get_names(p->caps, &cap_buf), @@ -10809,11 +10812,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_format_cap_get_names(vpeercapability, &vpeer_buf), ast_format_cap_get_names(tpeercapability, &tpeer_buf), ast_format_cap_get_names(newjointcapability, &joint_buf)); - } - if (debug) { - struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE); - struct ast_str *s2 = ast_str_alloca(SIPBUFSIZE); - struct ast_str *s3 = ast_str_alloca(SIPBUFSIZE); ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n", ast_rtp_lookup_mime_multiple2(s1, NULL, p->noncodeccapability, 0, 0), From 51118e7d70fff89b229fe9937108129911ff2f78 Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Thu, 8 Dec 2016 18:54:06 +0000 Subject: [PATCH 0936/1578] chan_sip: Delete unneeded check P is always true. We check it before Change-Id: Iee61cda002a9f61aee26b9f66c5f9b59e3389efb --- channels/chan_sip.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 7f22b96c8ce..1566b54bd10 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -6885,10 +6885,9 @@ static int update_call_counter(struct sip_pvt *fup, int event) ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event); } - if (p) { - ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name); - sip_unref_peer(p, "update_call_counter: sip_unref_peer from call counter"); - } + ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name); + sip_unref_peer(p, "update_call_counter: sip_unref_peer from call counter"); + return 0; } From 934aa2c768e3b0bd33e2308d91b5623be3a0e27c Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Thu, 8 Dec 2016 18:30:38 +0000 Subject: [PATCH 0937/1578] res_pjsip: Fix 'A = B != C' kind. Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)' Change-Id: Ibaa637dfda47d51a20e26069d3103e05ce80003d --- res/res_pjsip/pjsip_options.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 09fe1559bfb..24e9272f5c8 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -701,7 +701,8 @@ static pj_status_t send_options_response(pjsip_rx_data *rdata, int code) pj_status_t status; /* Make the response object */ - if ((status = ast_sip_create_response(rdata, code, NULL, &tdata) != PJ_SUCCESS)) { + status = ast_sip_create_response(rdata, code, NULL, &tdata); + if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to create response (%d)\n", status); return status; } From 4c6ba1dbba1650b6b644a1bcb89be89b630fac30 Mon Sep 17 00:00:00 2001 From: Badalyan Vyacheslav Date: Thu, 8 Dec 2016 18:43:23 +0000 Subject: [PATCH 0938/1578] Fix typo in chan_sip The conditional expressions of the 'if' operators situated alongside each other are identical. Change-Id: I652b6dcddb3be007e669a6aa8107edb31a1ddafb --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 7f22b96c8ce..927f0aeaecd 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -2512,7 +2512,7 @@ static void sip_threadinfo_destructor(void *obj) struct sip_threadinfo *th = obj; struct tcptls_packet *packet; - if (th->alert_pipe[1] > -1) { + if (th->alert_pipe[0] > -1) { close(th->alert_pipe[0]); } if (th->alert_pipe[1] > -1) { From 31268e0a280110748f33314a2c09563c576243de Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 9 Dec 2016 07:14:09 -0700 Subject: [PATCH 0939/1578] pjproject_bundled: Retry download if previously saved tarball is bad If a tarball is corrupted during download, the makefile will attempt to download it again. If the tarball somehow gets corrupted after it's downloaded however, the makefile was just failing. We now retry the download. ASTERISK-26653 #close Change-Id: I1b24d454852d80186f60c5a65dc4624ea8a1c359 --- third-party/pjproject/Makefile | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 21bdf235e84..e24a5df675e 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -87,29 +87,37 @@ SHELL_ECHO_PREFIX := echo '[pjproject] ' _all: $(TARGETS) +define verify_tarball + ($(SHELL_ECHO_PREFIX) Verifying $(TARBALL) &&\ + tarball_sum=$$($(CAT) $(TARBALL) | $(MD5) | $(SED) -n -r -e "s/^([^ ]+)\s+.*/\1/gp") ;\ + required_sum=$$($(SED) -n -r -e "s/^([^ ]+)\s+$(TARBALL_FILE)/\1/gp" $(PJMD5SUM)) ;\ + if [ "$$tarball_sum" != "$$required_sum" ] ; then $(SHELL_ECHO_PREFIX) Verify failed ; exit 1 ;\ + else $(SHELL_ECHO_PREFIX) Verify successful ; exit 0 ; fi; ) +endef + define download_from_pjproject - ($(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/$(@F) to $@ ;\ - $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/$(@F) > $@ &&\ + ($(SHELL_ECHO_PREFIX) Downloading $(TARBALL_URL) to $(TARBALL) ;\ + $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(TARBALL_URL) > $(TARBALL) &&\ $(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM to $(PJMD5SUM) &&\ $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\ - ($(SHELL_ECHO_PREFIX) Verifying $@ &&\ - tarball_sum=$$($(CAT) $@ | $(MD5) | $(SED) -n -r -e "s/^([^ ]+)\s+.*/\1/gp") ;\ - required_sum=$$($(SED) -n -r -e "s/^([^ ]+)\s+$(@F)/\1/gp" $(PJMD5SUM)) ;\ - if [ "$$tarball_sum" != "$$required_sum" ] ; then $(SHELL_ECHO_PREFIX) Verify failed ; exit 1 ; fi) &&\ - $(SHELL_ECHO_PREFIX) Verify successful ; exit 0) + $(verify_tarball)) endef .DELETE_ON_ERROR: DOWNLOAD_DIR := $(or $(EXTERNALS_CACHE_DIR),$(TMPDIR),$(wildcard /tmp),.) -TARBALL = $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 +TARBALL_FILE = pjproject-$(PJPROJECT_VERSION).tar.bz2 +TARBALL = $(DOWNLOAD_DIR)/$(TARBALL_FILE) +TARBALL_URL = $(PJPROJECT_URL)/$(TARBALL_FILE) PJMD5SUM = $(patsubst %.tar.bz2,%.md5,$(TARBALL)) $(TARBALL): ../versions.mak $(CMD_PREFIX) $(download_from_pjproject) || (rm -rf $@ ;\ - $(SHELL_ECHO_PREFIX) Retrying download ; sleep 3 ; $(download_from_pjproject)) + $(SHELL_ECHO_PREFIX) Retrying download ; $(download_from_pjproject)) source/.unpacked: $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 + ($(verify_tarball)) || (rm -rf $@ ;\ + $(SHELL_ECHO_PREFIX) Retrying download ; $(download_from_pjproject)) $(ECHO_PREFIX) Unpacking $< -@rm -rf source pjproject-* >/dev/null 2>&1 $(CMD_PREFIX) $(TAR) -xjf $< From 19328de2ab1317e75a7bf4cb6ebf9fce55cb05e1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 13 Dec 2016 13:06:34 -0700 Subject: [PATCH 0940/1578] res_sorcery_memory_cache: Change an error to a debug message When a sorcery user calls ast_sorcery_delete on an object that may have already expired from the cache, res_sorcery_memory_cache spits out an ERROR. Since this can happen frequently and validly when an inbound registration expires after the cache entry expired, the errors are unnecessary and misleading. Changed to a debug/1. Change-Id: Idf3a67038c16e3da814cf612ff4d6d18ad29ecd7 --- res/res_sorcery_memory_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index 4ce4e18e9a0..7da72bca4ae 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -1555,7 +1555,7 @@ static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void * ao2_unlock(cache->objects); if (res) { - ast_log(LOG_ERROR, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object)); + ast_debug(1, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object)); } return res; From 44e72c9d44c37a29dda73abc7bdca1cb34252555 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 12 Dec 2016 18:38:42 -0600 Subject: [PATCH 0941/1578] MESSAGE: Flush Message/ast_msg_queue channel alert pipe. ASTERISK-25083 Change-Id: Id54baa57a8dbca84e29f28bcd2ffc0a5ac12d8b2 --- include/asterisk/channel.h | 1 + main/channel_internal_api.c | 62 ++++++++++++++++++++++++++++++++----- main/message.c | 9 ++++++ 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 6f220271a55..1b7246b98b6 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4229,6 +4229,7 @@ typedef enum { } ast_alert_status_t; int ast_channel_alert_write(struct ast_channel *chan); int ast_channel_alert_writable(struct ast_channel *chan); +ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan); ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan); int ast_channel_internal_alert_readable(struct ast_channel *chan); void ast_channel_internal_alertpipe_clear(struct ast_channel *chan); diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 50f6c5da996..691dec0a17f 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -1239,14 +1239,9 @@ int ast_channel_alert_write(struct ast_channel *chan) return write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah); } -ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan) +static int channel_internal_alert_check_nonblock(struct ast_channel *chan) { int flags; - char blah; - - if (!ast_channel_internal_alert_readable(chan)) { - return AST_ALERT_NOT_READABLE; - } flags = fcntl(chan->alertpipe[0], F_GETFL); /* For some odd reason, the alertpipe occasionally loses nonblocking status, @@ -1255,9 +1250,62 @@ ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan) ast_log(LOG_ERROR, "Alertpipe on channel %s lost O_NONBLOCK?!!\n", ast_channel_name(chan)); if (fcntl(chan->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) { ast_log(LOG_WARNING, "Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno)); - return AST_ALERT_READ_FATAL; + return -1; + } + } + return 0; +} + +ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan) +{ + int bytes_read; + char blah[100]; + + if (!ast_channel_internal_alert_readable(chan)) { + return AST_ALERT_NOT_READABLE; + } + if (channel_internal_alert_check_nonblock(chan)) { + return AST_ALERT_READ_FATAL; + } + + /* Read the alertpipe until it is exhausted. */ + for (;;) { + bytes_read = read(chan->alertpipe[0], blah, sizeof(blah)); + if (bytes_read < 0) { + if (errno == EINTR) { + continue; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* + * Would block so nothing left to read. + * This is the normal loop exit. + */ + break; + } + ast_log(LOG_WARNING, "read() failed flushing alertpipe: %s\n", + strerror(errno)); + return AST_ALERT_READ_FAIL; + } + if (!bytes_read) { + /* Read nothing so we are done */ + break; } } + + return AST_ALERT_READ_SUCCESS; +} + +ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan) +{ + char blah; + + if (!ast_channel_internal_alert_readable(chan)) { + return AST_ALERT_NOT_READABLE; + } + if (channel_internal_alert_check_nonblock(chan)) { + return AST_ALERT_READ_FATAL; + } + if (read(chan->alertpipe[0], &blah, sizeof(blah)) < 0) { if (errno != EINTR && errno != EAGAIN) { ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno)); diff --git a/main/message.c b/main/message.c index a326fb97eaf..a6b04882824 100644 --- a/main/message.c +++ b/main/message.c @@ -775,11 +775,20 @@ static void chan_cleanup(struct ast_channel *chan) if (msg_ds) { ast_channel_datastore_add(chan, msg_ds); } + /* * Clear softhangup flags. */ ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ALL); + /* + * Flush the alert pipe in case we miscounted somewhere when + * messing with frames on the read queue, we had to flush the + * read queue above, or we had an "Exceptionally long queue + * length" event. + */ + ast_channel_internal_alert_flush(chan); + ast_channel_unlock(chan); } From 45a5e2abc6f7fc4e011c734c5a0ff743dc610f84 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 13 Dec 2016 14:34:54 -0600 Subject: [PATCH 0942/1578] res_pjsip: Add/update ERROR msg if invalid URI. ASTERISK-24499 Change-Id: Ie305153e47e922233b2ff24715e0e326e5fa3a6c --- res/res_pjsip.c | 3 ++- res/res_pjsip_session.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 144621f6bb9..6df9b704c5d 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2911,7 +2911,8 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, res = pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, NULL, &remote_uri, &target_uri, &dlg); if (res != PJ_SUCCESS) { if (res == PJSIP_EINVALIDURI) { - ast_log(LOG_ERROR, "Could not create dialog to endpoint '%s' as URI '%s' is not valid\n", + ast_log(LOG_ERROR, + "Endpoint '%s': Could not create dialog to invalid URI '%s'. Is endpoint registered?\n", ast_sorcery_object_get_id(endpoint), uri); } return NULL; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 527cbd90cc3..be07e94abcb 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1738,6 +1738,8 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint /* If we still have no URI to dial fail to create the session */ if (ast_strlen_zero(uri)) { + ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n", + ast_sorcery_object_get_id(endpoint)); return NULL; } From 9404efa6f42fcdbf1e676ce5a43477c68e16162d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 14 Dec 2016 14:21:47 -0600 Subject: [PATCH 0943/1578] chan_dahdi.c: Fix bounds check regression. Caused by ASTERISK-25494 Change-Id: I1fc408c1a083745ff59da5c4113041bbfce54bcb --- channels/chan_dahdi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index d224a204459..97c80c83e30 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -18826,8 +18826,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct } /* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */ - if (element_count >= ARRAY_LEN(c)) { - element_count = ARRAY_LEN(c) - 1; + if (element_count > ARRAY_LEN(c)) { + element_count = ARRAY_LEN(c); } /* Ring cadences cannot be negative */ From d27dee3ccada92752fe7d20f2d1523c5a01bc378 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 15 Dec 2016 13:25:50 -0600 Subject: [PATCH 0944/1578] autosupport: Add 'pjproject show buildopts' Change-Id: I8aa55a7c3fb175235ddc7f85e9457d5102d06fa7 --- contrib/scripts/autosupport | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/scripts/autosupport b/contrib/scripts/autosupport index 3e0213afe2f..948f628c983 100755 --- a/contrib/scripts/autosupport +++ b/contrib/scripts/autosupport @@ -1,6 +1,6 @@ #!/bin/sh # -# Autosupport Version 2.1.0 +# Autosupport Version 2.1.3 # Collect support information # # Copyright (C) 2005-2016, Digium, Inc. @@ -187,7 +187,7 @@ echo >> $OUTPUT; # Add check to see if asterisk is running. if [ -e /var/run/asterisk.ctl ] || [ -e /var/run/asterisk/asterisk.ctl ]; then for command in "core show version" "pri show version" "dahdi show version" \ - "pjsip show version" "pjsip show buildopts" \ + "pjsip show version" "pjsip show buildopts" "pjproject show buildopts" \ "core show translation" \ "core show uptime" "core show settings" "core show sysinfo" "core show channels" \ "pri show spans" "dahdi show status" "dahdi show channels" "dahdi show channel 1" \ From 147b8e636ef48a07891d4ce908a81f070ddf3437 Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Fri, 16 Dec 2016 01:32:57 -0600 Subject: [PATCH 0945/1578] configure: fix with-pjproject-bundled The AC_ARG_WITH macro's shell variable is withval; not enableval. Purely coincidentally, the option would work when --enable-dev-mode is given. Also fixed a portability problem with bootstrap.sh, since -printf is not a portable option for find. Change-Id: I0f0e5b1a934b5af5737713834361e9c95b96b376 --- bootstrap.sh | 2 +- configure | 2 +- configure.ac | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 051ee3e82e9..272c57b9481 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -46,7 +46,7 @@ check_for_app aclocal${MY_AM_VER} echo "Generating the configure script ..." -aclocal${MY_AM_VER} -I autoconf `find third-party/ -maxdepth 1 -type d -printf "-I %p "` +aclocal${MY_AM_VER} -I autoconf `find third-party -maxdepth 1 -type d | xargs -I {} echo -I {}` autoconf${MY_AC_VER} autoheader${MY_AC_VER} automake${MY_AM_VER} --add-missing --copy 2>/dev/null diff --git a/configure b/configure index 523f7652eed..7e720745e7c 100755 --- a/configure +++ b/configure @@ -9296,7 +9296,7 @@ PJPROJECT_BUNDLED=no # Check whether --with-pjproject-bundled was given. if test "${with_pjproject_bundled+set}" = set; then : - withval=$with_pjproject_bundled; case "${enableval}" in + withval=$with_pjproject_bundled; case "${withval}" in n|no) PJPROJECT_BUNDLED=no ;; *) PJPROJECT_BUNDLED=yes ;; esac diff --git a/configure.ac b/configure.ac index 161ccab5f86..d604d47a590 100644 --- a/configure.ac +++ b/configure.ac @@ -430,7 +430,7 @@ AH_TEMPLATE(m4_bpatsubst([[HAVE_PJPROJECT_BUNDLED]], [(.*)]), [Define to 1 when AC_ARG_WITH([pjproject-bundled], [AS_HELP_STRING([--with-pjproject-bundled], [Use bundled pjproject libraries])], - [case "${enableval}" in + [case "${withval}" in n|no) PJPROJECT_BUNDLED=no ;; *) PJPROJECT_BUNDLED=yes ;; esac]) From 8fbb384ea2f0f5e648f8137c2b77104e910a34d9 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 8 Dec 2016 21:00:02 -0500 Subject: [PATCH 0946/1578] chan_sip: Reorder unload_module to deal with stuck TCP threads. In some situations TCP threads may become frozen. This creates the possibility that Asterisk could segfault if they become unfrozen after chan_sip has been dlclose'd. This reorders the unload_module process to allow abort if threads do not exit within 5 seconds. High level order as follows: 1) Unregister from the core to stop new requests. 2) Signal threads to stop 3) Clear config based tables (but do not free the table itself). 4) Verify that threads have shutdown, cancel unload if not. 5) Clean all remaining resources. ASTERISK-26586 Change-Id: Ie23692041d838fbd35ece61868f4c640960ff882 --- channels/chan_sip.c | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index aa0d6a5ddfb..af17a386f80 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1780,7 +1780,7 @@ static void destroy_escs(void) { int i; for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) { - ao2_cleanup(event_state_compositors[i].compositor); + ao2_replace(event_state_compositors[i].compositor, NULL); } } @@ -35365,6 +35365,8 @@ static int unload_module(void) struct ao2_iterator i; struct timeval start; + ast_sched_dump(sched); + ast_sip_api_provider_unregister(); if (sip_cfg.websocket_enabled) { @@ -35374,12 +35376,11 @@ static int unload_module(void) network_change_stasis_unsubscribe(); acl_change_event_stasis_unsubscribe(); - ast_sched_dump(sched); - /* First, take us out of the channel type list */ ast_channel_unregister(&sip_tech); - ast_msg_tech_unregister(&sip_msg_tech); + ast_cc_monitor_unregister(&sip_cc_monitor_callbacks); + ast_cc_agent_unregister(&sip_cc_agent_callbacks); /* Unregister dial plan functions */ ast_custom_function_unregister(&sippeer_function); @@ -35443,8 +35444,6 @@ static int unload_module(void) } ao2_iterator_destroy(&i); - unlink_all_peers_from_tables(); - ast_mutex_lock(&monlock); if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) { pthread_t th = monitor_thread; @@ -35458,7 +35457,12 @@ static int unload_module(void) ast_mutex_unlock(&monlock); } + /* Clear containers */ + unlink_all_peers_from_tables(); cleanup_all_regs(); + sip_epa_unregister_all(); + destroy_escs(); + clear_sip_domains(); { struct ao2_iterator iter; @@ -35487,6 +35491,23 @@ static int unload_module(void) */ ast_sched_runq(sched); + /* + * Wait awhile for the TCP/TLS thread container to become empty. + * + * XXX This is a hack, but the worker threads cannot be created + * joinable. They can die on their own and remove themselves + * from the container thus resulting in a huge memory leak. + */ + start = ast_tvnow(); + while (ao2_container_count(threadt) && (ast_tvdiff_sec(ast_tvnow(), start) < 5)) { + sched_yield(); + } + if (ao2_container_count(threadt)) { + ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); + + return -1; + } + /* Free memory for local network address mask */ ast_free_ha(localaddr); @@ -35497,9 +35518,6 @@ static int unload_module(void) } ast_mutex_unlock(&authl_lock); - sip_epa_unregister_all(); - destroy_escs(); - ast_free(default_tls_cfg.certfile); ast_free(default_tls_cfg.pvtfile); ast_free(default_tls_cfg.cipher); @@ -35508,21 +35526,6 @@ static int unload_module(void) ast_rtp_dtls_cfg_free(&default_dtls_cfg); - /* - * Wait awhile for the TCP/TLS thread container to become empty. - * - * XXX This is a hack, but the worker threads cannot be created - * joinable. They can die on their own and remove themselves - * from the container thus resulting in a huge memory leak. - */ - start = ast_tvnow(); - while (ao2_container_count(threadt) && (ast_tvdiff_sec(ast_tvnow(), start) < 5)) { - sched_yield(); - } - if (ao2_container_count(threadt)) { - ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); - } - ao2_cleanup(registry_list); ao2_cleanup(subscription_mwi_list); @@ -35536,7 +35539,6 @@ static int unload_module(void) ao2_t_cleanup(threadt, "unref the thread table"); ao2_t_cleanup(sip_monitor_instances, "unref the sip_monitor_instances table"); - clear_sip_domains(); sip_cfg.contact_acl = ast_free_acl_list(sip_cfg.contact_acl); if (sipsock_read_id) { ast_io_remove(io, sipsock_read_id); @@ -35549,8 +35551,6 @@ static int unload_module(void) ast_context_destroy_by_name(used_context, "SIP"); ast_unload_realtime("sipregs"); ast_unload_realtime("sippeers"); - ast_cc_monitor_unregister(&sip_cc_monitor_callbacks); - ast_cc_agent_unregister(&sip_cc_agent_callbacks); sip_reqresp_parser_exit(); sip_unregister_tests(); From d29eb3b99d749a25827b47e6940a734441c5ba4b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 18 Dec 2016 14:23:17 -0700 Subject: [PATCH 0947/1578] pjproject_bundled: Make build single threaded There were just too many issues in various environments with multi threaded building of pjproject. It doesn't really speed things up anyway since asterisk is already being compiled in parallel. Change-Id: Ie5648fb91bb89b4224b6bf43a0daa1af793c4ce1 --- third-party/pjproject/Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index e24a5df675e..645e7c4fb5f 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -1,5 +1,7 @@ .PHONY: _all all _install install clean distclean echo_cflags configure +.NOTPARALLEL: + include ../versions.mak export PJDIR := $(shell pwd -P)/source @@ -139,7 +141,6 @@ source/pjlib/include/pj/%.h: patches/%.h .rebuild_needed: $(wildcard ../../makeopts) $(wildcard ../../menuselect.makeopts) $(ECHO_PREFIX) Rebuilding $(CMD_PREFIX) $(MAKE) clean $(REALLY_QUIET) - @touch .rebuild_needed source/build.mak: Makefile.rules source/version.mak source/user.mak $(addprefix source/pjlib/include/pj/,$(notdir $(wildcard patches/*.h))) .rebuild_needed $(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS) @@ -156,13 +157,11 @@ echo_cflags: source/build.mak libpj%.a: source/build.mak $(ECHO_PREFIX) Compiling lib $(@F) $(CMD_PREFIX) $(MAKE) -C $(dir $(shell dirname $@))/build $(@F) $(REALLY_QUIET) - -@rm -rf .rebuild_needed # pjsua needs resample and g711 to successfully run the testsuite -libresample%.a: .rebuild_needed source/build.mak +libresample%.a: source/build.mak $(ECHO_PREFIX) Compiling lib $(@F) $(CMD_PREFIX) $(MAKE) -C $(dir $(shell dirname $@))/build/resample all $(REALLY_QUIET) - -@rm -rf .rebuild_needed # We need to compile pjlib, then pjlib-util, then the rest # so we separate them out and create the dependencies From f461f65dea636c74632abf5e6e6f66e56b387ac9 Mon Sep 17 00:00:00 2001 From: Martin Tomec Date: Fri, 9 Dec 2016 19:23:37 +0100 Subject: [PATCH 0948/1578] app_queue: Ensure member is removed from pending when hanging up. In some cases member is added to pending_members, and the channel is hung up before any extension state change. So the member would stay in pending_members forever. So when we call do_hang, we should also remove member from pending. ASTERISK-26621 #close Change-Id: Iae476b5c06481db18ebe0fa594b3e80fdc9a7d54 --- apps/app_queue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 0abd512fa87..9176f936093 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2351,6 +2351,7 @@ static int pending_members_cmp(void *obj, void *arg, int flags) static void pending_members_remove(struct member *mem) { + ast_debug(3, "Removed %s from pending_members\n", mem->membername); ao2_find(pending_members, mem, OBJ_POINTER | OBJ_NODATA | OBJ_UNLINK); } @@ -4207,6 +4208,7 @@ static void do_hang(struct callattempt *o) { o->stillgoing = 0; ast_hangup(o->chan); + pending_members_remove(o->member); o->chan = NULL; } @@ -4287,6 +4289,7 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call) * If not found add it to the container so another queue * won't attempt to call this member at the same time. */ + ast_debug(3, "Add %s to pending_members\n", call->member->membername); ao2_link(pending_members, call->member); ao2_unlock(pending_members); @@ -4422,7 +4425,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies /* Again, keep going even if there's an error */ ast_verb(3, "Couldn't call %s\n", tmp->interface); do_hang(tmp); - pending_members_remove(tmp->member); ++*busies; return 0; } From bab253ac9fd825890b36f8354f1f109752aadff7 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Wed, 14 Dec 2016 10:21:25 +0200 Subject: [PATCH 0949/1578] Fixes to various issues reported by pyflakes Pyflake is a python (2) source checker. This patch fixes various (mostly trivial) errors and warnings it reports. Change-Id: Ia35c5ac61751b927814cf693994c632c412386ea --- build_tools/get_documentation.py | 3 --- build_tools/post_process_documentation.py | 4 +--- .../config/versions/4c573e7135bd_fix_tos_field_types.py | 1 - .../versions/5139253c0423_make_q_member_uniqueid_autoinc.py | 1 - rest-api-templates/asterisk_processor.py | 1 + rest-api-templates/swagger_model.py | 2 +- rest-api-templates/transform.py | 1 - 7 files changed, 3 insertions(+), 10 deletions(-) diff --git a/build_tools/get_documentation.py b/build_tools/get_documentation.py index 2ff4cb2b947..3211896460c 100644 --- a/build_tools/get_documentation.py +++ b/build_tools/get_documentation.py @@ -9,11 +9,8 @@ ''' import sys -import os import xml.dom.minidom -from xml.dom.minidom import Element - def get_manager_event_method_type(candidate_string): if "ast_manager_event_multichan" in candidate_string: diff --git a/build_tools/post_process_documentation.py b/build_tools/post_process_documentation.py index 5fa1c5b587f..c1496beabf9 100644 --- a/build_tools/post_process_documentation.py +++ b/build_tools/post_process_documentation.py @@ -9,11 +9,9 @@ ''' import sys -import os import optparse -import xml.dom.minidom -from xml.dom.minidom import Element, parse +from xml.dom.minidom import parse def merge_parameter_information(managerEvent): diff --git a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py index 27b498f30a7..17906ae19da 100755 --- a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py +++ b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py @@ -11,7 +11,6 @@ down_revision = '28887f25a46f' from alembic import op -from alembic import context import sqlalchemy as sa from sqlalchemy.dialects.postgresql import ENUM diff --git a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py index 01d4985fe5e..72f5ee16961 100755 --- a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py +++ b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py @@ -33,7 +33,6 @@ def upgrade(): - context = op.get_context() # Was unable to find a way to use op.alter_column() to add the unique # index property. op.drop_column('queue_members', 'uniqueid') diff --git a/rest-api-templates/asterisk_processor.py b/rest-api-templates/asterisk_processor.py index 68a6799946b..98129467307 100644 --- a/rest-api-templates/asterisk_processor.py +++ b/rest-api-templates/asterisk_processor.py @@ -20,6 +20,7 @@ Asterisk RESTful HTTP binding code. """ +import os import re from swagger_model import * diff --git a/rest-api-templates/swagger_model.py b/rest-api-templates/swagger_model.py index c71352a0125..08852415c00 100644 --- a/rest-api-templates/swagger_model.py +++ b/rest-api-templates/swagger_model.py @@ -737,7 +737,7 @@ def load(self, resources_json, processor, context): self.swagger_version = resources_json.get('swaggerVersion') if not self.swagger_version in SWAGGER_VERSIONS: raise SwaggerError( - "Unsupported Swagger version %s" % swagger_version, context) + "Unsupported Swagger version %s" % self.swagger_version, context) validate_required_fields(resources_json, self.required_fields, context) self.api_version = resources_json['apiVersion'] diff --git a/rest-api-templates/transform.py b/rest-api-templates/transform.py index fc12efe8593..c3a03006405 100644 --- a/rest-api-templates/transform.py +++ b/rest-api-templates/transform.py @@ -52,7 +52,6 @@ def render(self, renderer, model, dest_dir): dest_exists = os.path.exists(dest_file) if dest_exists and not self.overwrite: return - tmp_file = tempfile.mkstemp() with tempfile.NamedTemporaryFile() as out: out.write(renderer.render(self.template, model)) out.flush() From 8b7d252987ba066962b6c7707d1e00408bee3677 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 7 Dec 2016 15:23:02 -0600 Subject: [PATCH 0950/1578] res_rtp_asterisk.c: Fix off nominal memory leak. Change-Id: I95b1088d11244a2edae6607c12fbf33b38658a75 --- res/res_rtp_asterisk.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 58c217ecb48..b78fc30bd6f 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1453,12 +1453,6 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con return -1; } - if (!(certbio = BIO_new(BIO_s_file()))) { - ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n", - instance); - return -1; - } - if (rtp->local_hash == AST_RTP_DTLS_HASH_SHA1) { type = EVP_sha1(); } else if (rtp->local_hash == AST_RTP_DTLS_HASH_SHA256) { @@ -1469,6 +1463,12 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con return -1; } + if (!(certbio = BIO_new(BIO_s_file()))) { + ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n", + instance); + return -1; + } + if (!BIO_read_filename(certbio, dtls_cfg->certfile) || !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) || !X509_digest(cert, type, fingerprint, &size) || From 2fc65173e56910f72ca9a432290f49dd7a3aa82e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 21 Dec 2016 17:55:48 -0600 Subject: [PATCH 0951/1578] res_rtp_asterisk.c: Initialize ourip passed to ast_find_ourip(). We access uninitialized memory when the 'ourip' parameter does not have an initial guess to our IP address. ASTERISK-26672 Change-Id: I35507ea1ad7455d2be188f6ccdd4add7bd150e15 --- res/res_rtp_asterisk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index b78fc30bd6f..1721811eed1 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4912,9 +4912,11 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro ast_sockaddr_set_port(&rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us) + 1); + ast_sockaddr_copy(&local_addr, &rtp->rtcp->us); if (!ast_find_ourip(&local_addr, &rtp->rtcp->us, 0)) { ast_sockaddr_set_port(&local_addr, ast_sockaddr_port(&rtp->rtcp->us)); } else { + /* Failed to get local address reset to use default. */ ast_sockaddr_copy(&local_addr, &rtp->rtcp->us); } From 67b47191e9cc7f329d8a6803eb49f8cba8e68b1d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 21 Dec 2016 17:54:42 -0600 Subject: [PATCH 0952/1578] chan_rtp.c: Fix uninitialized memory crash. unicast_rtp_request() could pass an uninitialized 'us' parameter to ast_ouraddrfor(). If ast_ouraddrfor() returns an error then the 'us' parameter may not get initialized. Thus when the code tries to save the 'us' parameter to the local address we could try to copy a ridiculous sized memory buffer and segfault. * Made pass an initialized 'us' parameter to ast_ouraddrfor() and abort the UnicastRTP channel request if it fails. ASTERISK-26672 Change-Id: I1ef7a7c09f4da4f15dcb6de660d2bcac5f2a95c0 --- channels/chan_rtp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index 1c824fecc2b..6eec91e22b5 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -314,7 +314,12 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form engine_name = S_COR(ast_test_flag(&opts, OPT_RTP_ENGINE), opt_args[OPT_ARG_RTP_ENGINE], "asterisk"); - ast_ouraddrfor(&address, &local_address); + ast_sockaddr_copy(&local_address, &address); + if (ast_ouraddrfor(&address, &local_address)) { + ast_log(LOG_ERROR, "Could not get our address for sending media to '%s'\n", + args.destination); + goto failure; + } instance = ast_rtp_instance_new(engine_name, NULL, &local_address, NULL); if (!instance) { ast_log(LOG_ERROR, From 67cc8499a27a31a02bea3a370ebcc1afd1cb3f98 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 21 Dec 2016 16:25:00 -0600 Subject: [PATCH 0953/1578] acl.c: Improve ast_ouraddrfor() diagnostic messages. * Made not generate strings unless they will actually be used. ASTERISK-26672 Change-Id: I155fbe7fdff5ce47dfe5326f3baf5446849702c3 --- main/acl.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/main/acl.c b/main/acl.c index 1c35be86df4..31945676bc8 100644 --- a/main/acl.c +++ b/main/acl.c @@ -912,40 +912,48 @@ int ast_get_ip(struct ast_sockaddr *addr, const char *hostname) int ast_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us) { + /* + * We must create the errno string before creating the address + * string because it could wipe out errno on the error return + * paths. + */ + const char *sock_err; int port; int s; + /* Preserve our original address port */ port = ast_sockaddr_port(us); - if ((s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET, - SOCK_DGRAM, 0)) < 0) { - ast_log(LOG_ERROR, "Cannot create socket\n"); + s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + sock_err = ast_strdupa(strerror(errno)); + ast_log(LOG_ERROR, "Cannot create socket to %s: %s\n", + ast_sockaddr_stringify_addr(them), sock_err); return -1; } if (ast_connect(s, them)) { - ast_log(LOG_WARNING, "Cannot connect\n"); + sock_err = ast_strdupa(strerror(errno)); + ast_log(LOG_WARNING, "Cannot connect to %s: %s\n", + ast_sockaddr_stringify_addr(them), sock_err); close(s); return -1; } if (ast_getsockname(s, us)) { - - ast_log(LOG_WARNING, "Cannot get socket name\n"); + sock_err = ast_strdupa(strerror(errno)); + ast_log(LOG_WARNING, "Cannot get socket name for connection to %s: %s\n", + ast_sockaddr_stringify_addr(them), sock_err); close(s); return -1; } close(s); - { - const char *them_addr = ast_strdupa(ast_sockaddr_stringify_addr(them)); - const char *us_addr = ast_strdupa(ast_sockaddr_stringify_addr(us)); - - ast_debug(3, "For destination '%s', our source address is '%s'.\n", - them_addr, us_addr); - } - ast_sockaddr_set_port(us, port); + ast_debug(3, "For destination '%s', our source address is '%s'.\n", + ast_strdupa(ast_sockaddr_stringify_addr(them)), + ast_strdupa(ast_sockaddr_stringify_addr(us))); + return 0; } From b576b58d74e2ec85bdd4ea62912261896beee976 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 21 Dec 2016 16:28:00 -0600 Subject: [PATCH 0954/1578] res_rtp_asterisk.c: Fix uninitialized memory crash. ast_rtp_remote_address_set() could pass an uninitialized 'us' parameter to ast_ouraddrfor(). If ast_ouraddrfor() returns an error then the 'us' parameter may not get initialized. Thus when the code tries to save the 'us' parameter to the local address we could try to copy a ridiculous sized memory buffer and segfault. * Made pass an initialized 'us' parameter to ast_ouraddrfor(). * Optimized out the 'us' struct variable. ASTERISK-26672 #close Change-Id: I4acea5dcdf0813da2c7d3e11c2d6067d160d17dc --- res/res_rtp_asterisk.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 1721811eed1..4c79f8f5b5a 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -5005,31 +5005,31 @@ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp) static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct ast_sockaddr local, us; + struct ast_sockaddr local; + ast_rtp_instance_get_local_address(instance, &local); if (!ast_sockaddr_isnull(addr)) { /* Update the local RTP address with what is being used */ - ast_ouraddrfor(addr, &us); - ast_rtp_instance_get_local_address(instance, &local); - ast_sockaddr_set_port(&us, ast_sockaddr_port(&local)); - ast_rtp_instance_set_local_address(instance, &us); + if (ast_ouraddrfor(addr, &local)) { + /* Failed to update our address so reuse old local address */ + ast_rtp_instance_get_local_address(instance, &local); + } else { + ast_rtp_instance_set_local_address(instance, &local); + } } if (rtp->rtcp) { ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance); ast_sockaddr_copy(&rtp->rtcp->them, addr); if (!ast_sockaddr_isnull(addr)) { - ast_sockaddr_set_port(&rtp->rtcp->them, - ast_sockaddr_port(addr) + 1); - } + ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1); - if (!ast_sockaddr_isnull(addr)) { /* Update the local RTCP address with what is being used */ - ast_sockaddr_set_port(&us, ast_sockaddr_port(&local) + 1); - ast_sockaddr_copy(&rtp->rtcp->us, &us); + ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1); + ast_sockaddr_copy(&rtp->rtcp->us, &local); ast_free(rtp->rtcp->local_addr_str); - rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&us)); + rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local)); } } @@ -5039,8 +5039,6 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct rtp->strict_rtp_state = STRICT_RTP_LEARN; rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno); } - - return; } /*! \brief Write t140 redundacy frame From da6f40c9ff85fa665de30f89071f13d6da8f3cf1 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 23 Dec 2016 12:10:40 -0600 Subject: [PATCH 0955/1578] bridge_native_rtp.c: Fix native rtp bridge data race. native_rtp_bridge_compatible() didn't lock the bridge channels before checking the channels for native bridging ability. As a result, one of the channel's native format capabilities structure got replaced out from under the native bridge check. Use of a stale pointer to freed memory causes bad things to happen. MALLOC_DEBUG, DO_CRASH, and the tests/channels/pjsip/transfers/blind_transfer/caller_direct_media testsuite test caught this. * Add missing channel locking in native_rtp_bridge_compatible(). Change-Id: If25fdb3ac8e85563c4857fb8216b3d9dc3d0fa53 --- bridges/bridge_native_rtp.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 05ef4ea35db..736b0c35620 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -310,10 +310,8 @@ static int native_rtp_bridge_capable(struct ast_channel *chan) return !ast_channel_has_hook_requiring_audio(chan); } -static int native_rtp_bridge_compatible(struct ast_bridge *bridge) +static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct ast_bridge_channel *bc0, struct ast_bridge_channel *bc1) { - struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); - struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); enum ast_rtp_glue_result native_type; struct ast_rtp_glue *glue0, *glue1; RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup); @@ -324,13 +322,6 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge) RAII_VAR(struct ast_format_cap *, cap1, NULL, ao2_cleanup); int read_ptime0, read_ptime1, write_ptime0, write_ptime1; - /* We require two channels before even considering native bridging */ - if (bridge->num_channels != 2) { - ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n", - bridge->uniqueid); - return 0; - } - if (!native_rtp_bridge_capable(bc0->chan)) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n", bridge->uniqueid, ast_channel_name(bc0->chan)); @@ -406,6 +397,30 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge) return 1; } +static int native_rtp_bridge_compatible(struct ast_bridge *bridge) +{ + struct ast_bridge_channel *bc0; + struct ast_bridge_channel *bc1; + int is_compatible; + + /* We require two channels before even considering native bridging */ + if (bridge->num_channels != 2) { + ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n", + bridge->uniqueid); + return 0; + } + + bc0 = AST_LIST_FIRST(&bridge->channels); + bc1 = AST_LIST_LAST(&bridge->channels); + + ast_channel_lock_both(bc0->chan, bc1->chan); + is_compatible = native_rtp_bridge_compatible_check(bridge, bc0, bc1); + ast_channel_unlock(bc0->chan); + ast_channel_unlock(bc1->chan); + + return is_compatible; +} + /*! \brief Helper function which adds frame hook to bridge channel */ static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel) { From ac04e63ac24f4458165a15dd4fc6db1b184fce67 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 23 Dec 2016 12:11:02 -0600 Subject: [PATCH 0956/1578] bridge_native_rtp.c: Minor code cleanups. In native_rtp_bridge_compatible_check() * Made one variable declaration per line. * Extracted if test assignment to make the test easier to see. * Made long if tests easier to see the combinatorial logic. * Added bridge id to a couple debug messages. Change-Id: I65bc5732aa7c9a2537f062f106fbea711cf2daad --- bridges/bridge_native_rtp.c | 46 ++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 736b0c35620..e011f50374c 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -268,7 +268,6 @@ static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct a } bridge = ast_channel_get_bridge(chan); - if (bridge) { /* native_rtp_bridge_start/stop are not being called from bridging core so we need to lock the bridge prior to calling these functions @@ -313,14 +312,18 @@ static int native_rtp_bridge_capable(struct ast_channel *chan) static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct ast_bridge_channel *bc0, struct ast_bridge_channel *bc1) { enum ast_rtp_glue_result native_type; - struct ast_rtp_glue *glue0, *glue1; + struct ast_rtp_glue *glue0; + struct ast_rtp_glue *glue1; RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, cap0, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, cap1, NULL, ao2_cleanup); - int read_ptime0, read_ptime1, write_ptime0, write_ptime1; + int read_ptime0; + int read_ptime1; + int write_ptime0; + int write_ptime1; if (!native_rtp_bridge_capable(bc0->chan)) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n", @@ -334,29 +337,34 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct return 0; } - if ((native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1)) - == AST_RTP_GLUE_RESULT_FORBID) { + native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, + &instance0, &instance1, &vinstance0, &vinstance1); + if (native_type == AST_RTP_GLUE_RESULT_FORBID) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n", bridge->uniqueid); return 0; } - if (ao2_container_count(bc0->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance0)) { + if (ao2_container_count(bc0->features->dtmf_hooks) + && ast_rtp_instance_dtmf_mode_get(instance0)) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n", bridge->uniqueid, ast_channel_name(bc0->chan)); return 0; } - if (ao2_container_count(bc1->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance1)) { + if (ao2_container_count(bc1->features->dtmf_hooks) + && ast_rtp_instance_dtmf_mode_get(instance1)) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n", bridge->uniqueid, ast_channel_name(bc1->chan)); return 0; } - if ((native_type == AST_RTP_GLUE_RESULT_LOCAL) && ((ast_rtp_instance_get_engine(instance0)->local_bridge != - ast_rtp_instance_get_engine(instance1)->local_bridge) || - (ast_rtp_instance_get_engine(instance0)->dtmf_compatible && - !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan, instance0, bc1->chan, instance1)))) { + if (native_type == AST_RTP_GLUE_RESULT_LOCAL + && (ast_rtp_instance_get_engine(instance0)->local_bridge + != ast_rtp_instance_get_engine(instance1)->local_bridge + || (ast_rtp_instance_get_engine(instance0)->dtmf_compatible + && !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan, + instance0, bc1->chan, instance1)))) { ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n", bridge->uniqueid); return 0; @@ -375,11 +383,16 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct if (glue1->get_codec) { glue1->get_codec(bc1->chan, cap1); } - if (ast_format_cap_count(cap0) != 0 && ast_format_cap_count(cap1) != 0 && !ast_format_cap_iscompatible(cap0, cap1)) { + if (ast_format_cap_count(cap0) != 0 + && ast_format_cap_count(cap1) != 0 + && !ast_format_cap_iscompatible(cap0, cap1)) { struct ast_str *codec_buf0 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_str *codec_buf1 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); - ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n", - ast_format_cap_get_names(cap0, &codec_buf0), ast_format_cap_get_names(cap1, &codec_buf1)); + + ast_debug(1, "Bridge '%s': Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n", + bridge->uniqueid, + ast_format_cap_get_names(cap0, &codec_buf0), + ast_format_cap_get_names(cap1, &codec_buf1)); return 0; } @@ -389,8 +402,9 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct write_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawwriteformat(bc1->chan)); if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) { - ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n", - read_ptime0, write_ptime1, read_ptime1, write_ptime0); + ast_debug(1, "Bridge '%s': Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n", + bridge->uniqueid, + read_ptime0, write_ptime1, read_ptime1, write_ptime0); return 0; } From 5a5953f98c2580c7a9b0886c8ebed2a2d2639bec Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 30 Dec 2016 08:10:09 -0700 Subject: [PATCH 0957/1578] res_pjsip_refer: Handle compact Refer-To header. refer_incoming_refer_request needed to look for the "r" header as well as the "Refer-To" header. ASTERISK-26655 #close patches: refer_compact_fix.diff submitted by JoshE (license 6075) Change-Id: I610410a99b02427ea5db887aeb454d5f12c2259f --- res/res_pjsip_refer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index c1dee8225a0..c3e9ba53a50 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -1006,6 +1006,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct int response; static const pj_str_t str_refer_to = { "Refer-To", 8 }; + static const pj_str_t str_refer_to_s = { "r", 1 }; static const pj_str_t str_replaces = { "Replaces", 8 }; if (!session->channel) { @@ -1024,7 +1025,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct } /* A Refer-To header is required */ - refer_to = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL); + refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL); if (!refer_to) { pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL); ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n", From aad29b9bcac936d511c3b8905fd458bfa6e6dde3 Mon Sep 17 00:00:00 2001 From: Martin Tomec Date: Fri, 30 Dec 2016 13:59:00 +0100 Subject: [PATCH 0958/1578] res_calendar: delete old calendars after reload When "fetch_again_at_reload" is set in config, we create now new object and thread for each reloaded calendar (with new configuration). Old calendar should be then unlinked, so the old thread can exit and free memory. ASTERISK-26683 Change-Id: Ic17fba9371c5a8b26a6bc54ea4957c13a32a343e --- res/res_calendar.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/res/res_calendar.c b/res/res_calendar.c index 46775507cd9..92b73c1edc8 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -406,7 +406,12 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c struct ast_variable *v, *last = NULL; int new_calendar = 0; - if (!(cal = find_calendar(cat))) { + cal = find_calendar(cat); + if (cal && cal->fetch_again_at_reload) { + /** Create new calendar, old will be removed during reload */ + cal = unref_calendar(cal); + } + if (!cal) { new_calendar = 1; if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) { ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n"); @@ -483,7 +488,7 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c } } - if (new_calendar || cal->fetch_again_at_reload) { + if (new_calendar) { cal->thread = AST_PTHREADT_NULL; ast_cond_init(&cal->unload, NULL); ao2_link(calendars, cal); From 386e3a01b36bd5fdc512d267a8bcb42a9897e013 Mon Sep 17 00:00:00 2001 From: Joshua Elson Date: Sat, 31 Dec 2016 18:56:09 -0700 Subject: [PATCH 0959/1578] res_pjsip: Fix known compact header issues ASTERISK-26684 #close Change-Id: Ifd7e401c45015119dd5e8421dbfe3afa6381744a --- res/res_pjsip.c | 3 ++- res/res_pjsip_diversion.c | 3 ++- res/res_pjsip_refer.c | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 6df9b704c5d..a7dd09ee8ed 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3246,8 +3246,9 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s pjsip_contact_hdr *contact_hdr; pjsip_sip_uri *contact_uri; static const pj_str_t HCONTACT = { "Contact", 7 }; + static const pj_str_t HCONTACTSHORT = { "m", 1 }; - contact_hdr = pjsip_msg_find_hdr_by_name((*tdata)->msg, &HCONTACT, NULL); + contact_hdr = pjsip_msg_find_hdr_by_names((*tdata)->msg, &HCONTACT, &HCONTACTSHORT, NULL); if (contact_hdr) { contact_uri = pjsip_uri_get_uri(contact_hdr->uri); pj_strdup2(pool, &contact_uri->user, endpoint->contact_user); diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c index 301d9fc9212..efb5489f8e4 100644 --- a/res/res_pjsip_diversion.c +++ b/res/res_pjsip_diversion.c @@ -277,6 +277,7 @@ static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_ static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata) { static const pj_str_t contact_name = { "Contact", 7 }; + static const pj_str_t contact_name_s = { "m", 1 }; pjsip_status_line status = rdata->msg_info.msg->line.status; pjsip_fromto_hdr *div_hdr; @@ -292,7 +293,7 @@ static void diversion_incoming_response(struct ast_sip_session *session, pjsip_r div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg); } - contact_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &contact_name, NULL); + contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL); set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri : (pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index c1dee8225a0..107a3e7c35b 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -573,6 +573,7 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann pjsip_generic_string_hdr *referred_by; static const pj_str_t str_referred_by = { "Referred-By", 11 }; + static const pj_str_t str_referred_by_s = { "b", 1 }; pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes"); @@ -651,8 +652,8 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL)); - referred_by = pjsip_msg_find_hdr_by_name(refer->rdata->msg_info.msg, - &str_referred_by, NULL); + referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg, + &str_referred_by, &str_referred_by_s, NULL); if (referred_by) { size_t uri_size = pj_strlen(&referred_by->hvalue) + 1; char *uri = ast_alloca(uri_size); From ae57652983ffd9d7307d3568d82939516a6803b9 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 22 Dec 2016 22:00:58 +0000 Subject: [PATCH 0960/1578] chan_pjsip: Use session for retrieving CHANNEL() information. The CHANNEL() dialplan function implementation for PJSIP allows querying of PJSIP specific information. This used the channel passed in to get the PJSIP session and associated information. It is possible for this channel to be masqueraded and end up as a different channel type by the time the information request is actually acted upon. This change retrieves the PJSIP session safely and accesses data from it (including channel). This provides a guarantee that the session and channel will not be altered when the request is being acted upon. ASTERISK-26673 Change-Id: I335e12b89e1820cafdd92b3e7526b8ba649eb7e6 --- channels/pjsip/dialplan_functions.c | 62 ++++++++++++++--------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index c3fe848e4ac..17c19b7c0c6 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -720,7 +720,7 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const /*! \brief Struct used to push function arguments to task processor */ struct pjsip_func_args { - struct ast_channel *chan; + struct ast_sip_session *session; const char *param; const char *type; const char *field; @@ -735,49 +735,31 @@ static int read_pjsip(void *data) struct pjsip_func_args *func_args = data; if (!strcmp(func_args->param, "rtp")) { - func_args->ret = channel_read_rtp(func_args->chan, func_args->type, + func_args->ret = channel_read_rtp(func_args->session->channel, func_args->type, func_args->field, func_args->buf, func_args->len); } else if (!strcmp(func_args->param, "rtcp")) { - func_args->ret = channel_read_rtcp(func_args->chan, func_args->type, + func_args->ret = channel_read_rtcp(func_args->session->channel, func_args->type, func_args->field, func_args->buf, func_args->len); } else if (!strcmp(func_args->param, "endpoint")) { - struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan); - - if (!pvt) { - ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan)); + if (!func_args->session->endpoint) { + ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->session->channel)); return -1; } - if (!pvt->session || !pvt->session->endpoint) { - ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->chan)); - return -1; - } - snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->endpoint)); + snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->endpoint)); } else if (!strcmp(func_args->param, "contact")) { - struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan); - - if (!pvt) { - ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan)); - return -1; - } - if (!pvt->session || !pvt->session->contact) { + if (!func_args->session->contact) { return 0; } - snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->contact)); + snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->contact)); } else if (!strcmp(func_args->param, "aor")) { - struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan); - - if (!pvt) { - ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan)); - return -1; - } - if (!pvt->session || !pvt->session->aor) { + if (!func_args->session->aor) { return 0; } - snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->aor)); + snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->aor)); } else if (!strcmp(func_args->param, "pjsip")) { - func_args->ret = channel_read_pjsip(func_args->chan, func_args->type, + func_args->ret = channel_read_pjsip(func_args->session->channel, func_args->type, func_args->field, func_args->buf, func_args->len); } else { @@ -804,7 +786,6 @@ int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); return -1; } - channel = ast_channel_tech_pvt(chan); /* Check for zero arguments */ if (ast_strlen_zero(parse)) { @@ -814,29 +795,44 @@ int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data AST_STANDARD_APP_ARGS(args, parse); + ast_channel_lock(chan); + /* Sanity check */ if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) { ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd); + ast_channel_unlock(chan); return 0; } + channel = ast_channel_tech_pvt(chan); if (!channel) { - ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan)); + ast_log(LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan)); + ast_channel_unlock(chan); return -1; } + if (!channel->session) { + ast_log(LOG_WARNING, "Channel %s has no session\n", ast_channel_name(chan)); + ast_channel_unlock(chan); + return -1; + } + + func_args.session = ao2_bump(channel->session); + ast_channel_unlock(chan); + memset(buf, 0, len); - func_args.chan = chan; func_args.param = args.param; func_args.type = args.type; func_args.field = args.field; func_args.buf = buf; func_args.len = len; - if (ast_sip_push_task_synchronous(channel->session->serializer, read_pjsip, &func_args)) { + if (ast_sip_push_task_synchronous(func_args.session->serializer, read_pjsip, &func_args)) { ast_log(LOG_WARNING, "Unable to read properties of channel %s: failed to push task\n", ast_channel_name(chan)); + ao2_ref(func_args.session, -1); return -1; } + ao2_ref(func_args.session, -1); return func_args.ret; } From ceb9dae5663e03f3fe85d90c0546dc19bd721392 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 3 Jan 2017 14:14:09 -0700 Subject: [PATCH 0961/1578] pjproject_bundled: Compile pjsua with max log level = 2 A while back, we changed config_site.h to set PJ_LOG_MAX_LEVEL = 6. This allowed us to control the log level better from inside Asterisk. An unfortunate side effect of this was that the pjsua binary and python bindings were also compiled with log level set to 6 so whenever a testsuite test that uses pjsua runs, it spits out 6795 lines of debug in an instant even before the test starts. I believe this overruns the Jenkins capture buffer and prevents the test from properly terminating. In turn, this results in the testsuite just hanging until the job is killed. It's more frequent on the higher end agents because they can spit out the messages faster. Unfortunately, the messages are all spit out before we have control of the python pj.Lib instance where we can set logging levels so the only alternative was to actually compile pjsua and _pjsua.so with an overridden PJ_LOG_MAX_LEVEL. Although defining a lower max level was done in the Makefile, the define in config_site.h had to be wrapped with "#ifndef" so the change would take effect. Change-Id: I2af9e7d48dde1927279c586c9c725d868fe6f3ff --- third-party/pjproject/Makefile | 2 ++ third-party/pjproject/patches/config_site.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 645e7c4fb5f..f4cce73bf21 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -190,10 +190,12 @@ source/pjsip-apps/lib/libasterisk_malloc_debug.a: source/pjsip-apps/lib/asterisk $(CMD_PREFIX) ar qs $@ $< >/dev/null 2>&1 $(apps): APP = $(filter pj%,$(subst -, ,$(notdir $@))) +$(apps): CFLAGS += -DPJ_LOG_MAX_LEVEL=2 $(apps): pjproject.symbols $(APP_THIRD_PARTY_LIB_FILES) $(ECHO_PREFIX) Compiling $(APP) $(CMD_PREFIX) +$(MAKE) -C source/pjsip-apps/build $(filter pj%,$(subst -, ,$(notdir $@))) $(REALLY_QUIET) +source/pjsip-apps/src/python/_pjsua.o: CFLAGS += -DPJ_LOG_MAX_LEVEL=2 source/pjsip-apps/src/python/_pjsua.o: source/pjsip-apps/src/python/_pjsua.c $(apps) $(ECHO_PREFIX) Compiling python bindings $(CMD_PREFIX) $(CC) -o $@ -c $< $(PYTHONDEV_INCLUDE) $(CFLAGS) $(PJ_CFLAGS) diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index f84adeb357e..5e29cdb6aa4 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -34,7 +34,11 @@ #define PJ_SCANNER_USE_BITWISE 0 #define PJ_OS_HAS_CHECK_STACK 0 + +#ifndef PJ_LOG_MAX_LEVEL #define PJ_LOG_MAX_LEVEL 6 +#endif + #define PJ_ENABLE_EXTRA_CHECK 1 #define PJSIP_MAX_TSX_COUNT ((64*1024)-1) #define PJSIP_MAX_DIALOG_COUNT ((64*1024)-1) From e220c11bec4445ecf021b0818de711fe65a7bdbc Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 4 Jan 2017 12:50:11 +0100 Subject: [PATCH 0962/1578] chan_sip: Remember SDP negotiation on SIP_CODEC_INBOUND. After a SIP_CODEC_INBOUND in the dialplan, do not continue with cached formats but remember the joint format. Cached formats contain default parameters, often create an empty fmtp line. However, a joint format might have passed format_get_joint(.) in a res_format_attr_* module (like Opus Codec) and contain the resulting format parameters from a SDP negotiation. ASTERISK-26691 #close Change-Id: I35712d98a793d4c3efdd156cec57deab9014b1dc --- channels/chan_sip.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index af17a386f80..288933fdddf 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -7369,6 +7369,12 @@ static void try_suggested_sip_codec(struct sip_pvt *p) ao2_ref(fmt, -1); } + + /* The original joint formats may have contained negotiated parameters (fmtp) + * like the Opus Codec or iLBC 20. The cached formats contain the default + * parameters, which could be different than the negotiated (joint) result. */ + ast_format_cap_replace_from_cap(p->jointcaps, original_jointcaps, AST_MEDIA_TYPE_UNKNOWN); + ao2_ref(original_jointcaps, -1); return; } From aea228586568d30839a111af9cee713cb14f36ea Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Thu, 22 Dec 2016 16:13:46 +0100 Subject: [PATCH 0963/1578] res_pjsip_session: Access SIPDOMAIN via Dialplan. This feature was available in the SIP channel driver chan_sip. For example, Asterisk is the outbound proxy and has to handle all SIP-URIs, even domains not local to Asterisk. In that case, SIPDOMAIN is used in the Dialplan, to detect and dial remote SIP-URIs. This change here sets the SIP destination domain of an inbound call (SIPDOMAIN) in the SIP channel driver res_pjsip as well. ASTERISK-26670 #close Change-Id: I27c880dc404a3c1c6792e1ba3545475339577243 --- res/res_pjsip_session.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index be07e94abcb..ad9670cd124 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2000,6 +2000,12 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s if (!strcmp(session->exten, pickupexten) || ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) { + size_t size = pj_strlen(&sip_ruri->host) + 1; + char *domain = ast_alloca(size); + + ast_copy_pj_str(domain, &sip_ruri->host, size); + pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain); + return SIP_GET_DEST_EXTEN_FOUND; } /* XXX In reality, we'll likely have further options so that partial matches From d96e3502564508bf753aa637c5e1a0311924ab3d Mon Sep 17 00:00:00 2001 From: "Jonathan R. Rose" Date: Mon, 19 Dec 2016 15:03:52 -0600 Subject: [PATCH 0964/1578] core/pbx: dialplan show - display filename/line# Adds the ability for extensions to be registered to include filename and line number so that dialplan show output can show the filename and line number of a config file responsible for generating a given extension. This only affects config modules that are written to use the new extension registering functions. In this patch, that only includes pbx_config, so extensions registered in extensions.conf and any included extension will be shown in this manner. Extensions registered in this manner will show the filename and line number *instead* of the registrar. ASTERISK-26658 #close Reported by: Jonathan R. Rose Change-Id: Ieccc6abccdff34ed5c7da3511fd24972b8f2dd30 --- CHANGES | 6 +++ include/asterisk/pbx.h | 28 ++++++++++-- main/pbx.c | 66 +++++++++++++++++++++------ pbx/pbx_config.c | 22 ++++++--- pbx/pbx_lua.c | 2 +- res/ael/pval.c | 4 +- res/parking/parking_bridge_features.c | 2 +- res/res_parking.c | 2 +- res/res_pjsip_config_wizard.c | 2 +- utils/conf2ael.c | 2 +- 10 files changed, 106 insertions(+), 30 deletions(-) diff --git a/CHANGES b/CHANGES index 4c3d8dbfc47..ad16a4008ff 100644 --- a/CHANGES +++ b/CHANGES @@ -68,6 +68,12 @@ app_originate created channel using options parameter (like app_dial) B() and b(). This allows for adding variables to newly created channel or, e.g. setting callerid. +CLI Commands +------------------ + * 'dialplan show' output will now show [config_file:line_number] instead of + [registrar] when that information is available. Currently only extensions + registered by pbx_config when loading/reloading will use this format. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 00ca4acbefd..386f3c38bc9 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -505,11 +505,15 @@ int ast_add_extension(const char *context, int replace, const char *extension, /*! * \brief Add an extension to an extension context, this time with an ast_context *. * - * \note For details about the arguments, check ast_add_extension() + * \param registrar_file optional configuration file that defines this extension + * \param registrar_line optional line number of configuration file that defines extension + * + * \note For details about the other arguments, check ast_add_extension() */ int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, - const char *application, void *data, void (*datad)(void *), const char *registrar); + const char *application, void *data, void (*datad)(void *), const char *registrar, + const char *registrar_file, int registrar_line); /*! * \brief Same as ast_add_extension2, but assumes you have already locked context @@ -520,7 +524,8 @@ int ast_add_extension2(struct ast_context *con, int replace, const char *extensi */ int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, - const char *application, void *data, void (*datad)(void *), const char *registrar); + const char *application, void *data, void (*datad)(void *), const char *registrar, + const char *registrar_file, int registrar_line); /*! * \brief Map devstate to an extension state. @@ -1266,6 +1271,23 @@ const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip); const char *ast_get_switch_registrar(const struct ast_sw *sw); /*! @} */ +/*! + * \brief Get name of configuration file used by registrar to register this extension + * + * \retval NULL if registrar did not indicate config file when registering the extension + * \retval name of the file used to register the extension + */ +const char *ast_get_extension_registrar_file(struct ast_exten *e); + +/*! + * \brief Get line number of configuration file used by registrar to register this extension + * + * \retval 0 if the line wasn't indicated when the extension was registered + * \retval positive integer indicating what line in the config file was responsible for + * registering the extension. + */ +int ast_get_extension_registrar_line(struct ast_exten *e); + /*! @name Walking functions ... */ /*! @{ */ struct ast_context *ast_walk_contexts(struct ast_context *con); diff --git a/main/pbx.c b/main/pbx.c index 208c2308b95..3e35a3a14c5 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -251,6 +251,8 @@ struct ast_exten { struct ast_hashtab *peer_table; /*!< Priorities list in hashtab form -- only on the head of the peer list */ struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */ const char *registrar; /*!< Registrar */ + const char *registrar_file; /*!< File name used to register extension */ + int registrar_line; /*!< Line number the extension was registered in text */ struct ast_exten *next; /*!< Extension with a greater ID */ char stuff[0]; }; @@ -650,7 +652,8 @@ static int ast_add_extension_nolock(const char *context, int replace, const char static int ast_add_extension2_lockopt(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void (*datad)(void *), - const char *registrar, int lock_context); + const char *registrar, const char *registrar_file, int registrar_line, + int lock_context); static struct ast_context *find_context_locked(const char *context); static struct ast_context *find_context(const char *context); static void get_device_state_causing_channels(struct ao2_container *c); @@ -5438,6 +5441,21 @@ static void print_ext(struct ast_exten *e, char * buf, int buflen) } } +/*! \brief Writes CLI output of a single extension for show dialplan */ +static void show_dialplan_helper_extension_output(int fd, char *buf1, char *buf2, struct ast_exten *exten) +{ + if (ast_get_extension_registrar_file(exten)) { + ast_cli(fd, " %-17s %-45s [%s:%d]\n", + buf1, buf2, + ast_get_extension_registrar_file(exten), + ast_get_extension_registrar_line(exten)); + return; + } + + ast_cli(fd, " %-17s %-45s [%s]\n", + buf1, buf2, ast_get_extension_registrar(exten)); +} + /* XXX not verified */ static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, const struct ast_include *rinclude, int includecount, const char *includes[]) { @@ -5515,8 +5533,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, print_ext(e, buf2, sizeof(buf2)); - ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2, - ast_get_extension_registrar(e)); + show_dialplan_helper_extension_output(fd, buf, buf2, e); dpc->total_exten++; /* walk next extension peers */ @@ -5530,8 +5547,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, buf[0] = '\0'; print_ext(p, buf2, sizeof(buf2)); - ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2, - ast_get_extension_registrar(p)); + show_dialplan_helper_extension_output(fd, buf, buf2, p); } } @@ -6356,7 +6372,8 @@ static void context_merge(struct ast_context **extcontexts, struct ast_hashtab * dupdstr = ast_strdup(prio_item->data); res1 = ast_add_extension2(new, 0, prio_item->name, prio_item->priority, prio_item->label, - prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar); + prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar, + prio_item->registrar_file, prio_item->registrar_line); if (!res1 && new_exten_item && new_prio_item){ ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n", context->name, prio_item->name, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar); @@ -6867,7 +6884,7 @@ static int ast_add_extension_nolock(const char *context, int replace, const char c = find_context(context); if (c) { ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid, - application, data, datad, registrar, 1); + application, data, datad, registrar, NULL, 0, 1); } return ret; @@ -6887,7 +6904,7 @@ int ast_add_extension(const char *context, int replace, const char *extension, c = find_context_locked(context); if (c) { ret = ast_add_extension2(c, replace, extension, priority, label, callerid, - application, data, datad, registrar); + application, data, datad, registrar, NULL, 0); ast_unlock_contexts(); } @@ -7190,19 +7207,19 @@ static int add_priority(struct ast_context *con, struct ast_exten *tmp, int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void (*datad)(void *), - const char *registrar) + const char *registrar, const char *registrar_file, int registrar_line) { return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, - application, data, datad, registrar, 1); + application, data, datad, registrar, registrar_file, registrar_line, 1); } int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void (*datad)(void *), - const char *registrar) + const char *registrar, const char *registrar_file, int registrar_line) { return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, - application, data, datad, registrar, 0); + application, data, datad, registrar, registrar_file, registrar_line, 0); } @@ -7216,7 +7233,7 @@ int ast_add_extension2_nolock(struct ast_context *con, static int ast_add_extension2_lockopt(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void (*datad)(void *), - const char *registrar, int lock_context) + const char *registrar, const char *registrar_file, int registrar_line, int lock_context) { /* * Sort extensions (or patterns) according to the rules indicated above. @@ -7287,6 +7304,9 @@ static int ast_add_extension2_lockopt(struct ast_context *con, } else { length ++; /* just the '\0' */ } + if (registrar_file) { + length += strlen(registrar_file) + 1; + } /* Be optimistic: Build the extension structure first */ if (!(tmp = ast_calloc(1, length))) @@ -7326,12 +7346,22 @@ static int ast_add_extension2_lockopt(struct ast_context *con, *p++ = '\0'; tmp->matchcid = AST_EXT_MATCHCID_OFF; } + + if (registrar_file) { + tmp->registrar_file = p; + strcpy(p, registrar_file); + p += strlen(registrar_file) + 1; + } else { + tmp->registrar_file = NULL; + } + tmp->app = p; strcpy(p, application); tmp->parent = con; tmp->data = data; tmp->datad = datad; tmp->registrar = registrar; + tmp->registrar_line = registrar_line; if (lock_context) { ast_wrlock_context(con); @@ -8485,6 +8515,16 @@ const char *ast_get_extension_registrar(struct ast_exten *e) return e ? e->registrar : NULL; } +const char *ast_get_extension_registrar_file(struct ast_exten *e) +{ + return e ? e->registrar_file : NULL; +} + +int ast_get_extension_registrar_line(struct ast_exten *e) +{ + return e ? e->registrar_line : 0; +} + int ast_get_extension_matchcid(struct ast_exten *e) { return e ? e->matchcid : 0; diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 384bbc7c329..b96914dedd3 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -1240,7 +1240,7 @@ static int manager_dialplan_extension_add(struct mansession *s, const struct mes } if (ast_add_extension2(add_context, replace, exten, ipriority, NULL, cidmatch, - application, ast_strdup(application_data), ast_free_ptr, registrar)) { + application, ast_strdup(application_data), ast_free_ptr, registrar, NULL, 0)) { ast_unlock_contexts(); switch (errno) { case ENOMEM: @@ -1855,6 +1855,7 @@ static int pbx_load_config(const char *config_file) appl = ast_skip_blanks(appl); if (ipri) { + const char *registrar_file; if (plus) { ipri += atoi(plus); } @@ -1864,7 +1865,14 @@ static int pbx_load_config(const char *config_file) "The use of '%s' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X%c' instead at line %d of %s\n", realext, realext[1], v->lineno, vfile); } - if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, ast_strdup(data), ast_free_ptr, registrar)) { + /* Don't include full path if the configuration file includes slashes */ + registrar_file = strrchr(vfile, '/'); + if (!registrar_file) { + registrar_file = vfile; + } else { + registrar_file++; /* Skip past the end slash */ + } + if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, ast_strdup(data), ast_free_ptr, registrar, registrar_file, v->lineno)) { ast_log(LOG_WARNING, "Unable to register extension at line %d of %s\n", v->lineno, vfile); @@ -2031,19 +2039,19 @@ static void pbx_load_users(void) } /* Add hint */ - ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, NULL, NULL, registrar); + ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, NULL, NULL, registrar, NULL, 0); /* If voicemail, use "stdexten" else use plain old dial */ if (hasvoicemail) { if (ast_opt_stdexten_macro) { /* Use legacy stdexten macro method. */ snprintf(tmp, sizeof(tmp), "stdexten,%s,${HINT}", cat); - ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Macro", ast_strdup(tmp), ast_free_ptr, registrar); + ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Macro", ast_strdup(tmp), ast_free_ptr, registrar, NULL, 0); } else { snprintf(tmp, sizeof(tmp), "%s,stdexten(${HINT})", cat); - ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Gosub", ast_strdup(tmp), ast_free_ptr, registrar); + ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Gosub", ast_strdup(tmp), ast_free_ptr, registrar, NULL, 0); } } else { - ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", ast_strdup("${HINT}"), ast_free_ptr, registrar); + ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", ast_strdup("${HINT}"), ast_free_ptr, registrar, NULL, 0); } altexts = ast_variable_retrieve(cfg, cat, "alternateexts"); if (!ast_strlen_zero(altexts)) { @@ -2052,7 +2060,7 @@ static void pbx_load_users(void) c = altcopy; ext = strsep(&c, ","); while (ext) { - ast_add_extension2(con, 0, ext, 1, NULL, NULL, "Goto", ast_strdup(tmp), ast_free_ptr, registrar); + ast_add_extension2(con, 0, ext, 1, NULL, NULL, "Goto", ast_strdup(tmp), ast_free_ptr, registrar, NULL, 0); ext = strsep(&c, ","); } } diff --git a/pbx/pbx_lua.c b/pbx/pbx_lua.c index 0754990d673..088b160b4ee 100644 --- a/pbx/pbx_lua.c +++ b/pbx/pbx_lua.c @@ -1026,7 +1026,7 @@ static int lua_register_hints(lua_State *L) continue; } - if (ast_add_extension2(con, 0, hint_name, PRIORITY_HINT, NULL, NULL, hint_value, NULL, NULL, registrar)) { + if (ast_add_extension2(con, 0, hint_name, PRIORITY_HINT, NULL, NULL, hint_value, NULL, NULL, registrar, NULL, 0)) { /* remove hints table, hint name, hint value, * key copy, context name, and contex table */ lua_pop(L, 6); diff --git a/res/ael/pval.c b/res/ael/pval.c index 6803ab634ee..b0a04fe2f0b 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -4234,7 +4234,7 @@ void add_extensions(struct ael_extension *exten) pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1); if (exten->hints) { if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, - exten->hints, NULL, ast_free_ptr, registrar)) { + exten->hints, NULL, ast_free_ptr, registrar, NULL, 0)) { ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", exten->name); } @@ -4314,7 +4314,7 @@ void add_extensions(struct ael_extension *exten) label = 0; if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, - app, strdup(appargs), ast_free_ptr, registrar)) { + app, strdup(appargs), ast_free_ptr, registrar, NULL, 0)) { ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, exten->name); } diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 3fa7e42b31e..2770233332b 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -633,7 +633,7 @@ static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n", dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten)); } else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL, - "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) { + "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR, NULL, 0)) { ast_free(duplicate_returnexten); ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n", dial_string_flat, PARK_DIAL_CONTEXT, returnexten); diff --git a/res/res_parking.c b/res/res_parking.c index 171fdce6152..94cdb0e6d78 100644 --- a/res/res_parking.c +++ b/res/res_parking.c @@ -721,7 +721,7 @@ static int parking_add_extension(struct ast_context *context, int replace, const } if (ast_add_extension2_nolock(context, replace, extension, priority, NULL, NULL, - application, data_duplicate, ast_free_ptr, registrar)) { + application, data_duplicate, ast_free_ptr, registrar, NULL, 0)) { ast_free(data_duplicate); return -1; } diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index 2441184a243..83e282821f1 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -461,7 +461,7 @@ static int add_extension(struct ast_context *context, const char *exten, } if (ast_add_extension2_nolock(context, 0, exten, priority, NULL, NULL, - app, data, free_ptr, BASE_REGISTRAR)) { + app, data, free_ptr, BASE_REGISTRAR, NULL, 0)) { ast_free(data); return -1; } diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 1767d983337..5fdc570a020 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -561,7 +561,7 @@ void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void (*datad)(void *), - const char *registrar) + const char *registrar, const char *registrar_file, int registrar_line) { return localized_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar); } From 740ca862e42e6dfbd747257c84f22ff47eb8ff14 Mon Sep 17 00:00:00 2001 From: Sebastian Gutierrez Date: Sun, 6 Nov 2016 09:37:46 -0300 Subject: [PATCH 0965/1578] app_queue: add new Service Level calculation Adds a new formula for SL2 and documentation ASTERISK-26559 Change-Id: I0970c620460507cd9d45b0d43600779c8915e770 --- apps/app_queue.c | 29 +++++++++++++++++++++++++---- configs/samples/queues.conf.sample | 6 ++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 9176f936093..f33d22903cb 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1668,6 +1668,7 @@ struct call_queue { int talktime; /*!< Current avg talktime, based on the same exponential average */ int callscompleted; /*!< Number of queue calls completed */ int callsabandoned; /*!< Number of queue calls abandoned */ + int callsabandonedinsl; /*!< Number of queue calls abandoned in servicelevel */ int servicelevel; /*!< seconds setting for servicelevel*/ int callscompletedinsl; /*!< Number of calls answered with servicelevel*/ char monfmt[8]; /*!< Format to use when recording calls */ @@ -4621,6 +4622,9 @@ static int say_periodic_announcement(struct queue_ent *qe, int ringing) /*! \brief Record that a caller gave up on waiting in queue */ static void record_abandoned(struct queue_ent *qe) { + int callabandonedinsl = 0; + time_t now; + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE"); @@ -4633,6 +4637,13 @@ static void record_abandoned(struct queue_ent *qe) "OriginalPosition", qe->opos, "HoldTime", (int)(time(NULL) - qe->start)); + + time(&now); + callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel); + if (callabandonedinsl) { + qe->parent->callsabandonedinsl++; + } + qe->parent->callsabandoned++; ao2_unlock(qe->parent); @@ -9379,6 +9390,8 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { float sl; + float sl2; + struct call_queue *realtime_queue = NULL; ao2_lock(q); @@ -9411,12 +9424,16 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * ast_str_append(&out, 0, "unlimited"); } sl = 0; + sl2 = 0; if (q->callscompleted > 0) { sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); } - ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", - int2strat(q->strategy), q->holdtime, q->talktime, q->weight, - q->callscompleted, q->callsabandoned,sl,q->servicelevel); + if (q->callscompleted + q->callsabandoned > 0) { + sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)); + } + + ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds", + int2strat(q->strategy), q->holdtime, q->talktime, q->weight, q->callscompleted, q->callsabandoned, sl, sl2, q->servicelevel); do_print(s, fd, ast_str_buffer(out)); if (!ao2_container_count(q->members)) { do_print(s, fd, " No Members"); @@ -9773,6 +9790,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) struct call_queue *q; struct queue_ent *qe; float sl = 0; + float sl2 = 0; struct member *mem; struct ao2_iterator queue_iter; struct ao2_iterator mem_iter; @@ -9791,6 +9809,8 @@ static int manager_queues_status(struct mansession *s, const struct message *m) /* List queue properties */ if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) { sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); + sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0); + astman_append(s, "Event: QueueParams\r\n" "Queue: %s\r\n" "Max: %d\r\n" @@ -9802,11 +9822,12 @@ static int manager_queues_status(struct mansession *s, const struct message *m) "Abandoned: %d\r\n" "ServiceLevel: %d\r\n" "ServicelevelPerf: %2.1f\r\n" + "ServicelevelPerf2: %2.1f\r\n" "Weight: %d\r\n" "%s" "\r\n", q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, - q->callsabandoned, q->servicelevel, sl, q->weight, idText); + q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText); ++q_items; /* List Queue Members */ diff --git a/configs/samples/queues.conf.sample b/configs/samples/queues.conf.sample index 8a9c88402bb..ebb5da126cc 100644 --- a/configs/samples/queues.conf.sample +++ b/configs/samples/queues.conf.sample @@ -113,8 +113,10 @@ monitor-type = MixMonitor ;strategy = ringall ; ; Second settings for service level (default 0) -; Used for service level statistics (calls answered within service level time -; frame) +; Used for service level statistics (calls answered within service level time frame) +; There are 2 Service Level Performance Calculations SL and SL2 +; SL = (total calls answered within threshold / total calls answered) * 100 +; SL2 = ((calls answered within threshold + calls abandoned within threshold) / (answered calls + abandoned calls)) * 100 ;servicelevel = 60 ; ; A context may be specified, in which if the user types a SINGLE From a7d856cd96eb1e1f02fcde6b3e6bef35e1715bd5 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 5 Jan 2017 12:11:43 +0000 Subject: [PATCH 0966/1578] res_pjsip_endpoint_identifier_ip: Add support for SRV lookups. This change implements SRV support for the IP based endpoint identifier module. All possible addresses through SRV are looked up and added as matches. If no SRV records are available a fallback to normal host resolution is done. If an IP address is provided then no SRV lookup occurs. This is configured using the "srv_lookups" option on the identify section and defaults to "yes". ASTERISK-26693 Change-Id: I6b641e275bf96629320efa8b479737062aed82ac --- CHANGES | 6 + ...8ab27a7826d_add_srv_lookups_to_identify.py | 31 +++++ res/res_pjsip_endpoint_identifier_ip.c | 116 +++++++++++++++--- 3 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py diff --git a/CHANGES b/CHANGES index ad16a4008ff..d843848cfb3 100644 --- a/CHANGES +++ b/CHANGES @@ -110,6 +110,12 @@ res_pjsip ID, AuthenticateQualify, OutboundProxy, Path, QualifyFrequency and QualifyTimeout. Existing fields have not been disturbed. +res_pjsip_endpoint_identifier_ip +------------------ + * SRV lookups can now be done on provided hostnames to determine additional + source IP addresses for requests. This is configurable using the + "srv_lookups" option on the identify and defaults to "yes". + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------ ------------------------------------------------------------------------------ diff --git a/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py b/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py new file mode 100644 index 00000000000..8831e20023e --- /dev/null +++ b/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py @@ -0,0 +1,31 @@ +"""add srv_lookups to identify + +Revision ID: 28ab27a7826d +Revises: 4468b4a91372 +Create Date: 2017-01-06 14:53:38.829655 + +""" + +# revision identifiers, used by Alembic. +revision = '28ab27a7826d' +down_revision = '4468b4a91372' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoint_id_ips', sa.Column('srv_lookups', yesno_values)) + + +def downgrade(): + op.drop_column('ps_endpoint_id_ips', 'srv_lookups') diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 7a7af0b4e02..e095a96309a 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -51,6 +51,13 @@ mask with a slash ('/') + + Perform SRV lookups for provided hostnames. + When enabled, srv_lookups will + perform SRV lookups for _sip._udp, _sip._tcp, and _sips._tcp of the given + hostnames to determine additional addresses that traffic may originate from. + + Must be of type 'identify'. @@ -70,6 +77,8 @@ struct ip_identify_match { ); /*! \brief Networks or addresses that should match this */ struct ast_ha *matches; + /*! \brief Perform SRV resolution of hostnames */ + unsigned int srv_lookups; }; /*! \brief Destructor function for a matching object */ @@ -153,6 +162,72 @@ static struct ast_sip_endpoint_identifier ip_identifier = { .identify_endpoint = ip_identify, }; +/*! \brief Helper function which performs a host lookup and adds result to identify match */ +static int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host) +{ + struct ast_sockaddr *addrs; + int num_addrs = 0, error = 0, i; + int results = 0; + + num_addrs = ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC); + if (!num_addrs) { + return -1; + } + + for (i = 0; i < num_addrs; ++i) { + /* Check if the address is already in the list, if so don't bother adding it again */ + if (identify->matches && (ast_apply_ha(identify->matches, &addrs[i]) != AST_SENSE_ALLOW)) { + continue; + } + + /* We deny what we actually want to match because there is an implicit permit all rule for ACLs */ + identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error); + + if (!identify->matches || error) { + results = -1; + break; + } + + results += 1; + } + + ast_free(addrs); + + return results; +} + +/*! \brief Helper function which performs an SRV lookup and then resolves the hostname */ +static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host) +{ + char service[NI_MAXHOST]; + struct srv_context *context = NULL; + int srv_ret; + const char *srvhost; + unsigned short srvport; + int results = 0; + + snprintf(service, sizeof(service), "%s.%s", prefix, host); + + while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) { + int hosts; + + /* In the case of the SRV lookup we don't care if it fails, we will output a log message + * when we fallback to a normal lookup. + */ + hosts = ip_identify_match_host_lookup(identify, srvhost); + if (hosts == -1) { + results = -1; + break; + } else { + results += hosts; + } + } + + ast_srv_cleanup(&context); + + return results; +} + /*! \brief Custom handler for match field */ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -165,9 +240,9 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va } while ((current_string = ast_strip(strsep(&input_string, ",")))) { - struct ast_sockaddr *addrs; - int num_addrs = 0, error = 0, i; char *mask = strrchr(current_string, '/'); + struct ast_sockaddr address; + int error, results = 0; if (ast_strlen_zero(current_string)) { continue; @@ -185,28 +260,28 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va continue; } - num_addrs = ast_sockaddr_resolve(&addrs, current_string, PARSE_PORT_FORBID, AST_AF_UNSPEC); - if (!num_addrs) { - ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n", - var->value, ast_sorcery_object_get_id(obj)); - return -1; - } - - for (i = 0; i < num_addrs; ++i) { - /* We deny what we actually want to match because there is an implicit permit all rule for ACLs */ - identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error); - - if (!identify->matches || error) { - ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n", - ast_sockaddr_stringify_addr(&addrs[i]), ast_sorcery_object_get_id(obj)); - error = -1; - break; + /* If the provided string is not an IP address perform SRV resolution on it */ + if (identify->srv_lookups && !ast_sockaddr_parse(&address, current_string, 0)) { + results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string); + if (results != -1) { + results += ip_identify_match_srv_lookup(identify, "_sip._tcp", current_string); + } + if (results != -1) { + results += ip_identify_match_srv_lookup(identify, "_sips._tcp", current_string); } } - ast_free(addrs); + /* If SRV falls fall back to a normal lookup on the host itself */ + if (!results) { + results = ip_identify_match_host_lookup(identify, current_string); + } - if (error) { + if (results == 0) { + ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n", + current_string, ast_sorcery_object_get_id(obj)); + } else if (results == -1) { + ast_log(LOG_ERROR, "An error occurred when adding resolution results of '%s' on '%s'\n", + current_string, ast_sorcery_object_get_id(obj)); return -1; } } @@ -469,6 +544,7 @@ static int load_module(void) ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name)); ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0); + ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "srv_lookups", "yes", OPT_BOOL_T, 1, FLDSET(struct ip_identify_match, srv_lookups)); ast_sorcery_load_object(ast_sip_get_sorcery(), "identify"); ast_sip_register_endpoint_identifier_with_name(&ip_identifier, "ip"); From e54c8aec343b43745ab9d241f6c5336fdb2a29a3 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 8 Jan 2017 09:29:01 -0700 Subject: [PATCH 0967/1578] pjproject_bundled: Fix compilation with MALLOC_DEBUG When MALLOC_DEBUG was specified, make was failing. Immediately remaking would work. The issues was in the ordering of the make dependencies. Change-Id: If6030b54fc693f3179f32bfd20c6b5d5f1b3f7cd --- third-party/pjproject/Makefile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index f4cce73bf21..2398ec428da 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -63,11 +63,8 @@ ifeq ($(SPECIAL_TARGETS),) endif ifeq ($(findstring MALLOC_DEBUG,$(MENUSELECT_CFLAGS)),MALLOC_DEBUG) CF += -DMALLOC_DEBUG - MALLOC_DEBUG = yes - $(apps): export LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive - $(apps): source/pjsip-apps/lib/libasterisk_malloc_debug.a - source/pjsip-apps/src/python/_pjsua.so: LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive - source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/lib/libasterisk_malloc_debug.a + MALLOC_DEBUG_LIBS = source/pjsip-apps/lib/libasterisk_malloc_debug.a + MALLOC_DEBUG_LDFLAGS = -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive endif ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),) CF += -O3 @@ -191,7 +188,8 @@ source/pjsip-apps/lib/libasterisk_malloc_debug.a: source/pjsip-apps/lib/asterisk $(apps): APP = $(filter pj%,$(subst -, ,$(notdir $@))) $(apps): CFLAGS += -DPJ_LOG_MAX_LEVEL=2 -$(apps): pjproject.symbols $(APP_THIRD_PARTY_LIB_FILES) +$(apps): LDFLAGS += $(MALLOC_DEBUG_LDFLAGS) +$(apps): $(MALLOC_DEBUG_LIBS) pjproject.symbols $(APP_THIRD_PARTY_LIB_FILES) $(ECHO_PREFIX) Compiling $(APP) $(CMD_PREFIX) +$(MAKE) -C source/pjsip-apps/build $(filter pj%,$(subst -, ,$(notdir $@))) $(REALLY_QUIET) @@ -200,6 +198,7 @@ source/pjsip-apps/src/python/_pjsua.o: source/pjsip-apps/src/python/_pjsua.c $(a $(ECHO_PREFIX) Compiling python bindings $(CMD_PREFIX) $(CC) -o $@ -c $< $(PYTHONDEV_INCLUDE) $(CFLAGS) $(PJ_CFLAGS) +source/pjsip-apps/src/python/_pjsua.so: LDFLAGS += $(MALLOC_DEBUG_LDFLAGS) source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/src/python/_pjsua.o $(ECHO_PREFIX) Linking python bindings $(@F) $(CMD_PREFIX) gcc -shared -pthread -o $@ $< $(LDFLAGS) $(PJ_LDFLAGS) $(APP_LDLIBS) $(PYTHONDEV_LIB) $(REALLY_QUIET) From 0d53c91fbaec97a94788945044a060403a9f0bce Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 10 Jan 2017 17:10:39 -0700 Subject: [PATCH 0968/1578] debug_utilities: Create the ast_coredumper utility This utility allows easy manipulation of asterisk coredumps. * Configurable search paths and patterns for existing coredumps * Can generate a consistent coredump from the running instance * Can dump the lock_infos table from a coredump * Dumps backtraces to separate files... - thread apply 1 bt full -> .thread1.txt - thread apply all bt -> .brief.txt - thread apply all bt full -> .full.txt - lock_infos table -> .locks.txt * Can tarball corefiles and optionally delete them after processing * Can tarball results files and optionally delete them after processing * Converts ':' in coredump and results file names '-' to facilitate uploading. Jira for instance, won't accept file names with colons in them. Tested on Fedora24+, Ubuntu14+, Debian6+, CentOS6+ and FreeBSD9+[1]. [1] For *BSDs, the "devel/gdb" package might have to be installed to get a recent gdb. The utility will check all instances of gdb it finds in $PATH and if one isn't found that can run python, it prints a friendly error. Change-Id: I935d37ab9db85ef923f32b05579897f0893d33cd (cherry picked from commit cb47b4556053cd50d9102eef913671ad0306062d) --- configs/samples/ast_debug_tools.conf.sample | 40 ++ contrib/Makefile | 2 + contrib/scripts/ast_coredumper | 520 ++++++++++++++++++++ 3 files changed, 562 insertions(+) create mode 100644 configs/samples/ast_debug_tools.conf.sample create mode 100755 contrib/scripts/ast_coredumper diff --git a/configs/samples/ast_debug_tools.conf.sample b/configs/samples/ast_debug_tools.conf.sample new file mode 100644 index 00000000000..90e976f1bc5 --- /dev/null +++ b/configs/samples/ast_debug_tools.conf.sample @@ -0,0 +1,40 @@ +# +# This file is used by the Asterisk debug tools. +# Unlike other Asterisk config files, this one is +# "sourced" by bash and must adhere to bash semantics. +# + +# A list of coredumps and/or coredump search patterns. +# Bash extended globs are enabled and any resulting files +# that aren't actually coredumps are silently ignored +# so you can be liberal with the globs. +# +# If your patterns contains spaces be sure to only quote +# the portion of the pattern that DOESN'T contain wildcard +# expressions. If you quote the whole pattern, it won't +# be expanded and the glob characters will be treated as +# literals. +# +# The exclusion of files ending ".txt" is just for +# demonstration purposes as non-coredumps will be ignored +# anyway. +COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt)) + +# Date command for the "running" coredump and tarballs. +# DATEFORMAT will be executed to get the timestamp. +# Don't put quotes around the format string or they'll be +# treated as literal characters. Also be aware of colons +# in the output as you can't upload files with colons in +# the name to Jira. +# +# Unix timestamp +#DATEFORMAT='date +%s.%N' +# +# Unix timestamp on *BSD/MacOS after installing coreutils +#DATEFORMAT='gdate +%s.%N' +# +# Readable GMT +#DATEFORMAT='date -u +%FT%H-%M-%S%z' +# +# Readable Local time +DATEFORMAT='date +%FT%H-%M-%S%z' diff --git a/contrib/Makefile b/contrib/Makefile index 37f4df43921..a5775cb82c2 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -22,6 +22,8 @@ include $(ASTTOPDIR)/Makefile.rules install: $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts"; \ $(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"; \ + $(INSTALL) -m 755 scripts/ast_coredumper "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper" uninstall: rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py" + rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper" diff --git a/contrib/scripts/ast_coredumper b/contrib/scripts/ast_coredumper new file mode 100755 index 00000000000..c82732be9bf --- /dev/null +++ b/contrib/scripts/ast_coredumper @@ -0,0 +1,520 @@ +#!/usr/bin/env bash +# Turn on extended globbing +shopt -s extglob +# Bail on any error +set -e + +prog=$(basename $0) + +print_help() { +cat < | ... ] + +DESCRIPTION + + Extracts backtraces and lock tables from Asterisk coredump files. + For each coredump found, 4 new result files are created: + - .brief.txt: The output of "thread apply all bt". + + - .thread1.txt: The output of "thread apply 1 bt full". + + - .full.txt: The output of "thread apply all bt full". + + - .locks.txt: If asterisk was compiled with + "DEBUG_THREADS", this file will contain a dump of the locks + table similar to doing a "core show locks" from the asterisk + CLI. + + Optional features: + - The running asterisk process can be suspended and dumped. + - The coredumps can be merged into a tarball. + - The coredumps can be deleted after processing. + - The results files can be merged into a tarball. + - The results files can be deleted after processing. + + Options: + + --help + Print this help. + + --running + Create a coredump from the running asterisk instance and + process it along with any other coredumps found (if any). + WARNING: This WILL interrupt call processing. You will be + asked to confirm. + + --RUNNING + Same as --running but without the confirmation prompt. + DANGEROUS!! + + --latest + Process only the latest coredump from those specified (based + on last-modified time). If a dump of the running process was + requested, it is always included in addition to the latest + from the existing coredumps. + + --tarball-coredumps + Creates a gzipped tarball of all coredumps processed. + The tarball name will be: + /tmp/asterisk..coredumps.tar.gz + + --delete-coredumps-after + Deletes all processed coredumps regardless of whether + a tarball was created. + + --tarball-results + Creates a gzipped tarball of all result files produced. + The tarball name will be: + /tmp/asterisk..results.tar.gz + + --delete-results-after + Deletes all processed results regardless of whether + a tarball was created. It probably doesn't make sense + to use this option unless you have also specified + --tarball-results. + + --no-default-search + Ignore COREDUMPS from the config files and process only + coredumps listed on the command line (if any) and/or + the running asterisk instance (if requested). + + --append-coredumps + Append any coredumps specified on the command line to the + config file specified ones instead of overriding them. + + | + A list of coredumps or coredump search patterns. Unless + --append-coredumps was specified, these entries will override + those specified in the config files. + + Any resulting file that isn't actually a coredump is silently + ignored. If your patterns contains spaces be sure to only + quote the portion of the pattern that DOESN'T contain wildcard + expressions. If you quote the whole pattern, it won't be + expanded. + + If --no-default-search is specified and no files are specified + on the command line, then the only the running asterisk process + will be dumped (if requested). Otherwise if no files are + specified on the command line the value of COREDUMPS from + ast_debug_tools.conf will be used. Failing that, the following + patterns will be used: + /tmp/core[-._]asterisk!(*.txt) + /tmp/core[-._]\$(hostname)!(*.txt) + +NOTES + The script relies on not only bash, but also recent GNU date and + gdb with python support. *BSD operating systems may require + installation of the 'coreutils' and 'devel/gdb' packagess and minor + tweaking of the ast_debug_tools.conf file. + + Any files output will have ':' characters changed to '-'. This is + to facilitate uploading those files to Jira which doesn't like the + colons. + +FILES + /etc/asterisk/ast_debug_tools.conf + ~/ast_debug_tools.conf + ./ast_debug_tools.conf + + # + # This file is used by the Asterisk debug tools. + # Unlike other Asterisk config files, this one is + # "sourced" by bash and must adhere to bash semantics. + # + + # A list of coredumps and/or coredump search patterns. + # Bash extended globs are enabled and any resulting files + # that aren't actually coredumps are silently ignored + # so you can be liberal with the globs. + # + # If your patterns contains spaces be sure to only quote + # the portion of the pattern that DOESN'T contain wildcard + # expressions. If you quote the whole pattern, it won't + # be expanded and the glob characters will be treated as + # literals. + # + # The exclusion of files ending ".txt" is just for + # demonstration purposes as non-coredumps will be ignored + # anyway. + COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]\$(hostname)!(*.txt)) + + # Date command for the "running" coredump and tarballs. + # DATEFORMAT will be executed to get the timestamp. + # Don't put quotes around the format string or they'll be + # treated as literal characters. Also be aware of colons + # in the output as you can't upload files with colons in + # the name to Jira. + # + # Unix timestamp + #DATEFORMAT='date +%s.%N' + # + # *BSD/MacOS doesn't support %N but after installing GNU + # coreutils... + #DATEFORMAT='gdate +%s.%N' + # + # Readable GMT + #DATEFORMAT='date -u +%FT%H-%M-%S%z' + # + # Readable Local time + DATEFORMAT='date +%FT%H-%M-%S%z' + +EOF + exit 1 +} + +running=false +RUNNING=false +latest=false +tarball_coredumps=false +delete_coredumps_after=false +tarball_results=false +delete_results_after=false +append_coredumps=false + +declare -a COREDUMPS +declare -a ARGS_COREDUMPS + +# Read config files from least important to most important +[ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf +[ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf +[ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf + +# For *BSD, the preferred gdb may be in /usr/local/bin so we +# need to search for one that supports python. +for g in $(which -a gdb) ; do + result=$($g --batch --ex "python print('hello')" 2>/dev/null || : ) + if [[ "$result" =~ ^hello$ ]] ; then + GDB=$g + break + fi +done + +if [ -z "$GDB" ] ; then + echo "No suitable gdb was found in $PATH" + exit 1 +fi + +if [ ${#COREDUMPS[@]} -eq 0 ] ; then + COREDUMPS+=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt)) +fi + +DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'} + +# Use "$@" (with the quotes) so spaces in patterns or +# file names are preserved. +# Later on when we have to iterate over COREDUMPS, we always +# use the indexes rather than trying to expand the values of COREDUMPS +# just in case. + +for a in "$@" ; do + case "$a" in + --running) + running=true + ;; + --RUNNING) + RUNNING=true + ;; + --no-default-search) + # Clean out COREDUMPS from config files + COREDUMPS=() + ;; + --latest) + latest=true + ;; + --tarball-coredumps) + tarball_coredumps=true + ;; + --delete-coredumps-after) + delete_coredumps_after=true + ;; + --tarball-results) + tarball_results=true + ;; + --delete-results-after) + delete_results_after=true + ;; + --append-coredumps) + append_coredumps=true + ;; + --help|-*) + print_help + ;; + *) + ARGS_COREDUMPS+=("$a") + # If any files are specified on the command line, ignore those + # specified in the config files unless append-coredumps was specified. + if ! $append_coredumps ; then + COREDUMPS=() + fi + esac +done + +# append coredumps/patterns specified as command line arguments to COREDUMPS. +for i in ${!ARGS_COREDUMPS[@]} ; do + COREDUMPS+=("${ARGS_COREDUMPS[$i]}") +done + +# At this point, all glob entries that match files should be expanded. +# Any entries that don't exist are probably globs that didn't match anything +# and need to be pruned. Any non coredumps are also pruned. + +for i in ${!COREDUMPS[@]} ; do + if [ ! -f "${COREDUMPS[$i]}" ] ; then + unset COREDUMPS[$i] + continue + fi + # Some versions of 'file' don't allow only the first n bytes of the + # file to be processed so we use dd to grab just the first 32 bytes. + mimetype=$(dd if="${COREDUMPS[$i]}" bs=32 count=1 2>/dev/null | file -bi -) + if [[ ! "$mimetype" =~ coredump ]] ; then + unset COREDUMPS[$i] + continue + fi +done + +# Sort and weed out any dups +IFS=$'\x0a' +readarray -t COREDUMPS < <(echo -n "${COREDUMPS[*]}" | sort -u ) +unset IFS + +# If --latest, get the last modified timestamp of each file, +# sort them, then return the latest. +if [ ${#COREDUMPS[@]} -gt 0 ] && $latest ; then + lf=$(find "${COREDUMPS[@]}" -printf '%T@ %p\n' | sort -n | tail -1) + COREDUMPS=("${lf#* }") +fi + +# Timestamp to use for output files +df=$(${DATEFORMAT}) + +if $running || $RUNNING ; then + # We need to go through some gyrations to find the pid of the running + # MAIN asterisk process and not someone or something running asterisk -r. + # The pid file may NOT be in /var/run/asterisk so we need to find any + # running asterisk process and see if -C was specified on the command + # line. The chances of more than 1 asterisk instance running with + # different -C options is so unlikely that we're going to ignore it. + # + # 'ps axo command' should work on Linux (back to CentOS6) and FreeBSD. + # If asterisk was started with -C, get the asterisk.conf file. + # If it wasn't, assume /etc/asterisk/asterisk.conf + astetcconf=`ps axo command | sed -n -r -e "s/.*asterisk\s+.*-C\s+([^ ]+).*/\1/gp" | tail -1` + [ x$astetcconf = x ] && astetcconf=/etc/asterisk/asterisk.conf + # Now parse out astrundir and cat asterisk.pid + astrundir=$(sed -n -r -e "s/astrundir\s+[=>]+\s+(.*)/\1/gp" $astetcconf) + pid=$(cat $astrundir/asterisk.pid 2>/dev/null || : ) + if [ x$pid = x ] ; then + echo "Asterisk is not running" + else + if $RUNNING ; then + answer=Y + else + read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer + fi + if [[ "$answer" =~ ^[Yy] ]] ; then + cf="/tmp/core.asterisk.running.$df" + # We want a consistent coredump so stop the process + # and continue it after the dump is complete. + # kill -STOP $pid + ${GDB} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1 + # kill -CONT $pid + COREDUMPS+=("$cf") + else + echo "Skipping dump of running process" + fi + fi +fi + +if [ "${#COREDUMPS[@]}" -eq 0 ] ; then + echo "No coredumps found" + print_help +fi + +# Extract the gdb scripts from the end of this script +# and save them to /tmp/.gdbinit + +ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:` +tail -n +${ss} $0 >/tmp/.gdbinit + +# Now iterate over the coredumps and dump the debugging info +for i in ${!COREDUMPS[@]} ; do + cf=${COREDUMPS[$i]} + echo "Processing $cf" + ${GDB} -n --batch -q --ex "source /tmp/.gdbinit" $(which asterisk) "$cf" 2>/dev/null | ( + of=/dev/null + while IFS= read line ; do + if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then + of=$cf.${BASH_REMATCH[1]} + of=${of//:/-} + rm -f "$of" + echo "Creating $of" + fi + echo -e $"$line" >> "$of" + done + ) +done + +if $tarball_coredumps ; then + tf=/tmp/asterisk.$df.coredumps.tar + echo "Creating $tf.gz" + for i in ${!COREDUMPS[@]} ; do + tar -uvf $tf "${COREDUMPS[@]}" 2>/dev/null + done + gzip $tf +fi + +if $delete_coredumps_after ; then + for i in ${!COREDUMPS[@]} ; do + rm -rf "${COREDUMPS[$i]}" + done +fi + +if $tarball_results ; then + tf=/tmp/asterisk.$df.results.tar + echo "Creating $tf.gz" + for i in ${!COREDUMPS[@]} ; do + tar -uvf $tf "${COREDUMPS[$i]//:/-}".{brief,full,thread1,locks}.txt 2>/dev/null + done + gzip $tf +fi + +if $delete_results_after ; then + for i in ${!COREDUMPS[@]} ; do + rm -rf "${COREDUMPS[$i]//:/-}".{brief,full,thread1,locks}.txt + done +fi + +exit + +# Be careful editng the inline scripts. +# They're space-indented. + +# We need the python bit because lock_infos isn't +# a valid symbol in asterisk unless DEBUG_THREADS was +# used during the compile. Also, interrupt and continue +# are only valid for a running program. + +#@@@SCRIPTSTART@@@ +python +class DumpAsteriskCommand(gdb.Command): + + def __init__(self): + super(DumpAsteriskCommand, self).__init__ ("dump-asterisk", + gdb.COMMAND_OBSCURE, gdb.COMPLETE_COMMAND) + + def invoke(self, arg, from_tty): + try: + gdb.execute("interrupt", from_tty) + except: + pass + print("!@!@!@! thread1.txt !@!@!@!\n") + try: + gdb.execute("thread apply 1 bt full", from_tty) + except: + pass + print("!@!@!@! brief.txt !@!@!@!\n") + try: + gdb.execute("thread apply all bt", from_tty) + except: + pass + print("!@!@!@! full.txt !@!@!@!\n") + try: + gdb.execute("thread apply all bt full", from_tty) + except: + pass + print("!@!@!@! locks.txt !@!@!@!\n") + try: + gdb.execute("show_locks", from_tty) + except: + pass + try: + gdb.execute("continue", from_tty) + except: + pass + +DumpAsteriskCommand () +end + +define show_locks + set $n = lock_infos.first + + if $argc == 0 + printf " where_held count-|\n" + printf " suspended-| |\n" + printf " type- | times locked-| | |\n" + printf "thread status file line function lock name | lock addr | | |\n" + else + printf "thread,status,file,line,function,lock_name,lock_type,lock_addr,times_locked,suspended,where_held_count,where_held_file,where_held_line,where_held_function,there_held_thread\n" + end + + while $n + if $n->num_locks > 0 + set $i = 0 + while $i < $n->num_locks + if $n->locks[$i]->suspended == 0 + if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->tracking + if $n->locks[$i]->type > 0 + set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track + else + set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track + end + end + set $reentrancy = $track->reentrancy + set $pending = $n->locks[$i]->pending + if $argc > 0 + printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\ + $n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\ + $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\ + $n->locks[$i]->suspended, $track->reentrancy + if $reentrancy + if $pending + printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0] + end + end + else + if $n->locks[$i]->pending < 0 + printf "%p failed %-20s %6d %-36s %-20s %d %14p %3d %d %d",\ + $n->thread_id,\ + $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\ + $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\ + $n->locks[$i]->suspended, $track->reentrancy + end + if $n->locks[$i]->pending == 0 + printf "%p holding %-20s %6d %-36s %-20s %d %14p %3d %d %d",\ + $n->thread_id,\ + $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\ + $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\ + $n->locks[$i]->suspended, $track->reentrancy + end + if $n->locks[$i]->pending > 0 + printf "%p waiting %-20s %6d %-36s %-20s %d %14p %3d %d %d",\ + $n->thread_id,\ + $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\ + $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\ + $n->locks[$i]->suspended, $track->reentrancy + end + if $reentrancy + if $pending + printf "\n held at: %-20s %6d %-36s by 0x%08lx", $track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0] + end + end + end + printf "\n" + end + set $i = $i + 1 + end + end + set $n = $n->entry->next + end +end + +dump-asterisk From e0e502d9d24d6e99024ee6a26a3a09eb968bb62a Mon Sep 17 00:00:00 2001 From: Aaron An Date: Tue, 10 Jan 2017 19:54:16 +0800 Subject: [PATCH 0969/1578] res_rtp_asterisk: Fix bug in function CHANNEL(rtcp, all_rtt) Function CHANNEL(rtcp,all_rtt) CHANNEL(rtcp,all_loss) CHANNEL(rtcp,all_jitter) always return 0.0 due to wrong define of macro "AST_RTP_SATA_SET" and "AST_RTP_STAT_STRCPY". It should compare "combined" with "stat" not "current_stat". ASTERISK-26710 #close Reported-by: Aaron An Tested-by: AaronAn Change-Id: Id4140fafbf92e2db689dac5b17d9caa009028a15 --- include/asterisk/rtp_engine.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 017bb7b7acd..c0ae3315572 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -373,7 +373,7 @@ struct ast_rtp_instance_stats { }; #define AST_RTP_STAT_SET(current_stat, combined, placement, value) \ -if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == current_stat)) { \ +if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == stat)) { \ placement = value; \ if (stat == current_stat) { \ return 0; \ @@ -381,7 +381,7 @@ return 0; \ } #define AST_RTP_STAT_STRCPY(current_stat, combined, placement, value) \ -if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == current_stat)) { \ +if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == stat)) { \ ast_copy_string(placement, value, sizeof(placement)); \ if (stat == current_stat) { \ return 0; \ From f4e77a5678ac8babeff853988941bf821b5d23cf Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 13 Jan 2017 21:23:49 -0600 Subject: [PATCH 0970/1578] taskprocessor.c: Change when high water warning logged. The task processor queue reached X scheduled tasks message was originally intended to get logged only once per task processor to prevent spamming the log. This is no longer necessary since high and low water thresholds can better control when the message is logged. It is beneficial to generate the warning each time a task processor reaches the high water level because PJSIP stops processing new requests while any high water alert is active. Without this change you would have to enable at least debug level 3 logging to know about a repeated alert trigger. * Made generate the warning message whenever a task is pushed into the task processor that triggers the high water alert. * Appended 'again' to the warning for a repeated high water alert trigger. Change-Id: Iabf75a004f7edaf1e5e8c323099418e667cac999 --- main/taskprocessor.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/main/taskprocessor.c b/main/taskprocessor.c index 30ed763085d..6793542abf3 100644 --- a/main/taskprocessor.c +++ b/main/taskprocessor.c @@ -882,12 +882,10 @@ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t) previous_size = tps->tps_queue_size++; if (tps->tps_queue_high <= tps->tps_queue_size) { - if (!tps->high_water_warned) { - tps->high_water_warned = 1; - ast_log(LOG_WARNING, "The '%s' task processor queue reached %ld scheduled tasks.\n", - tps->name, tps->tps_queue_size); - } if (!tps->high_water_alert) { + ast_log(LOG_WARNING, "The '%s' task processor queue reached %ld scheduled tasks%s.\n", + tps->name, tps->tps_queue_size, tps->high_water_warned ? " again" : ""); + tps->high_water_warned = 1; tps->high_water_alert = 1; tps_alert_add(tps, +1); } From 8cc1cd5df70a16900082b919f8e625286bb3356f Mon Sep 17 00:00:00 2001 From: Sebastian Gutierrez Date: Sun, 6 Nov 2016 09:30:07 -0300 Subject: [PATCH 0971/1578] app_queue: Add QueueUpdate application. Add an application that allows tracking outbound calls using app_queue. ASTERISK-19862 Change-Id: Ia0ab64aed934c25b2a25022adcc7c0624224346e --- CHANGES | 5 +++ apps/app_queue.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/CHANGES b/CHANGES index d843848cfb3..5921e9b325a 100644 --- a/CHANGES +++ b/CHANGES @@ -74,6 +74,11 @@ CLI Commands [registrar] when that information is available. Currently only extensions registered by pbx_config when loading/reloading will use this format. +app_queue +------------------ + * Add 'QueueUpdate' application which can be used to track outbound calls + using app_queue. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/apps/app_queue.c b/apps/app_queue.c index 9176f936093..9b3912fd2b8 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -490,6 +490,24 @@ QUEUE_MEMBER_PENALTY + + + Writes to the queue_log file for OutBound calls and updates Realtime Data. + Is used at h extension to be able to have all the parameters. + + + + + + + + + + + Allows you to write Outbound events into the queue log. + Example: exten => h,1,QueueUpdate(${QUEUE}, ${UNIQUEID}, ${AGENT}, ${DIALSTATUS}, ${ANSWEREDTIME}, ${DIALEDTIME} | ${DIALEDNUMBER}) + + Return Queue information in variables. @@ -1403,6 +1421,8 @@ static char *app_upqm = "UnpauseQueueMember" ; static char *app_ql = "QueueLog" ; +static char *app_qupd = "QueueUpdate"; + /*! \brief Persistent Members astdb family */ static const char * const pm_family = "Queue/PersistentMembers"; @@ -10703,6 +10723,86 @@ static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cl return CLI_SUCCESS; } +/*! + * \brief Update Queue with data of an outgoing call +*/ +static int qupd_exec(struct ast_channel *chan, const char *data) +{ + int oldtalktime; + char *parse; + struct call_queue *q; + struct member *mem; + int newtalktime = 0; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(queuename); + AST_APP_ARG(uniqueid); + AST_APP_ARG(agent); + AST_APP_ARG(status); + AST_APP_ARG(talktime); + AST_APP_ARG(params);); + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n"); + return -1; + } + + parse = ast_strdupa(data); + + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) { + ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n"); + return -1; + } + + if (!ast_strlen_zero(args.talktime)) { + newtalktime = atoi(args.talktime); + } + + q = find_load_queue_rt_friendly(args.queuename); + if (!q) { + ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename); + return 0; + } + + ao2_lock(q); + if (q->members) { + struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); + while ((mem = ao2_iterator_next(&mem_iter))) { + if (!strcasecmp(mem->membername, args.agent)) { + if (!strcasecmp(args.status, "ANSWER")) { + oldtalktime = q->talktime; + q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; + time(&mem->lastcall); + mem->calls++; + mem->lastqueue = q; + q->callscompleted++; + + if (newtalktime <= q->servicelevel) { + q->callscompletedinsl++; + } + } else { + + time(&mem->lastcall); + q->callsabandoned++; + } + + ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params); + } + + ao2_ref(mem, -1); + } + + ao2_iterator_destroy(&mem_iter); + } + + ao2_unlock(q); + queue_t_unref(q, "Done with temporary pointer"); + + return 0; +} + static struct ast_cli_entry cli_queue[] = { AST_CLI_DEFINE(queue_show, "Show status of a specified queue"), AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"), @@ -11020,6 +11120,7 @@ static int unload_module(void) ast_manager_unregister("QueueRemove"); ast_manager_unregister("QueuePause"); ast_manager_unregister("QueueLog"); + ast_manager_unregister("QueueUpdate"); ast_manager_unregister("QueuePenalty"); ast_manager_unregister("QueueReload"); ast_manager_unregister("QueueReset"); @@ -11029,6 +11130,7 @@ static int unload_module(void) ast_unregister_application(app_pqm); ast_unregister_application(app_upqm); ast_unregister_application(app_ql); + ast_unregister_application(app_qupd); ast_unregister_application(app); ast_custom_function_unregister(&queueexists_function); ast_custom_function_unregister(&queuevar_function); @@ -11128,6 +11230,7 @@ static int load_module(void) err |= ast_register_application_xml(app_pqm, pqm_exec); err |= ast_register_application_xml(app_upqm, upqm_exec); err |= ast_register_application_xml(app_ql, ql_exec); + err |= ast_register_application_xml(app_qupd, qupd_exec); err |= ast_manager_register_xml("Queues", 0, manager_queues_show); err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); From 283c16c6b6136dfdb13b4fa6b524126e7aab1dfc Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 12 Jan 2017 15:58:43 -0600 Subject: [PATCH 0972/1578] abstract/fixed/adpative jitter buffer: disallow frame re-inserts It was possible for a frame to be re-inserted into a jitter buffer after it had been removed from it. A case when this happened was if a frame was read out of the jitterbuffer, passed to the translation core, and then multiple frames were returned from said translation core. Upon multiple frames being returned the first is passed on, but sebsequently "chained" frames are put back into the read queue. Thus it was possible for a frame to go back into the jitter buffer where this would cause problems. This patch adds a flag to frames that are inserted into the channel's read queue after translation. The abstract jitter buffer code then checks for this flag and ignores any frames marked as such. Change-Id: I276c44edc9dcff61e606242f71274265c7779587 --- include/asterisk/abstract_jb.h | 3 +++ include/asterisk/frame.h | 2 ++ include/jitterbuf.h | 3 +++ main/abstract_jb.c | 31 ++++++++++++++++++++++++++++++- main/channel.c | 13 ++++++++++--- main/fixedjitterbuf.c | 6 +++++- main/fixedjitterbuf.h | 3 +++ main/jitterbuf.c | 5 ++++- 8 files changed, 60 insertions(+), 6 deletions(-) diff --git a/include/asterisk/abstract_jb.h b/include/asterisk/abstract_jb.h index 8a5e3d27ffd..173b22a5c5c 100644 --- a/include/asterisk/abstract_jb.h +++ b/include/asterisk/abstract_jb.h @@ -109,6 +109,8 @@ typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout); typedef void (*jb_force_resynch_impl)(void *jb); /*! \brief Empty and reset jb */ typedef void (*jb_empty_and_reset_impl)(void *jb); +/*! \brief Check if late */ +typedef int (*jb_is_late_impl)(void *jb, long ts); /*! @@ -127,6 +129,7 @@ struct ast_jb_impl jb_remove_impl remove; jb_force_resynch_impl force_resync; jb_empty_and_reset_impl empty_and_reset; + jb_is_late_impl is_late; }; /*! diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 20f40f8634c..108dcafe0bb 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -133,6 +133,8 @@ enum ast_frame_type { enum { /*! This frame contains valid timing information */ AST_FRFLAG_HAS_TIMING_INFO = (1 << 0), + /*! This frame has been requeued */ + AST_FRFLAG_REQUEUED = (1 << 1), }; struct ast_frame_subclass { diff --git a/include/jitterbuf.h b/include/jitterbuf.h index 6da11a65bd4..32579fc6c97 100644 --- a/include/jitterbuf.h +++ b/include/jitterbuf.h @@ -166,6 +166,9 @@ enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf); typedef void __attribute__((format(printf, 1, 2))) (*jb_output_function_t)(const char *fmt, ...); void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg); +/*! \brief Checks if the given time stamp is late */ +int jb_is_late(jitterbuf *jb, long ts); + #ifdef __cplusplus } #endif diff --git a/main/abstract_jb.c b/main/abstract_jb.c index 264ee97e620..0f0e6613fad 100644 --- a/main/abstract_jb.c +++ b/main/abstract_jb.c @@ -65,6 +65,7 @@ static long jb_next_fixed(void *jb); static int jb_remove_fixed(void *jb, struct ast_frame **fout); static void jb_force_resynch_fixed(void *jb); static void jb_empty_and_reset_fixed(void *jb); +static int jb_is_late_fixed(void *jb, long ts); /* adaptive */ static void * jb_create_adaptive(struct ast_jb_conf *general_config); static void jb_destroy_adaptive(void *jb); @@ -75,6 +76,7 @@ static long jb_next_adaptive(void *jb); static int jb_remove_adaptive(void *jb, struct ast_frame **fout); static void jb_force_resynch_adaptive(void *jb); static void jb_empty_and_reset_adaptive(void *jb); +static int jb_is_late_adaptive(void *jb, long ts); /* Available jb implementations */ static const struct ast_jb_impl avail_impl[] = { @@ -90,6 +92,7 @@ static const struct ast_jb_impl avail_impl[] = { .remove = jb_remove_fixed, .force_resync = jb_force_resynch_fixed, .empty_and_reset = jb_empty_and_reset_fixed, + .is_late = jb_is_late_fixed, }, { .name = "adaptive", @@ -103,6 +106,7 @@ static const struct ast_jb_impl avail_impl[] = { .remove = jb_remove_adaptive, .force_resync = jb_force_resynch_adaptive, .empty_and_reset = jb_empty_and_reset_adaptive, + .is_late = jb_is_late_adaptive, } }; @@ -704,6 +708,11 @@ static void jb_empty_and_reset_fixed(void *jb) } } +static int jb_is_late_fixed(void *jb, long ts) +{ + return fixed_jb_is_late(jb, ts); +} + /* adaptive */ static void *jb_create_adaptive(struct ast_jb_conf *general_config) @@ -810,6 +819,11 @@ const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type) return NULL; } +static int jb_is_late_adaptive(void *jb, long ts) +{ + return jb_is_late(jb, ts); +} + #define DEFAULT_TIMER_INTERVAL 20 #define DEFAULT_SIZE 200 #define DEFAULT_TARGET_EXTRA 40 @@ -893,7 +907,22 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram } } - if (!frame) { + /* + * If the frame has been requeued (for instance when the translate core returns + * more than one frame) then if the frame is late we want to immediately return + * it. Otherwise attempt to insert it into the jitterbuffer. + * + * If the frame is requeued and late then in all likely hood it's a frame that + * that was previously retrieved from the jitterbuffer, passed to the translate + * core, and then put back into the channel read queue. Even if it had not been + * in the jitterbuffer prior to now it needs to be the next frame "out". + * + * However late arriving frames that have not been requeued (i.e. regular frames) + * need to be passed to the jitterbuffer so they can be appropriately dropped. As + * well any requeued frames that are not late should be put into the jitterbuffer. + */ + if (!frame || (ast_test_flag(frame, AST_FRFLAG_REQUEUED) && + framedata->jb_impl->is_late(framedata->jb_obj, frame->ts))) { return frame; } diff --git a/main/channel.c b/main/channel.c index 00cfa31aa07..4f8471743e7 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4333,12 +4333,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) * at the end of the queue. */ if (AST_LIST_NEXT(f, frame_list)) { + struct ast_frame *cur, *multi_frame = AST_LIST_NEXT(f, frame_list); + + /* Mark these frames as being re-queued */ + for (cur = multi_frame; cur; cur = AST_LIST_NEXT(cur, frame_list)) { + ast_set_flag(cur, AST_FRFLAG_REQUEUED); + } + if (!readq_tail) { - ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list)); + ast_queue_frame_head(chan, multi_frame); } else { - __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail); + __ast_queue_frame(chan, multi_frame, 0, readq_tail); } - ast_frfree(AST_LIST_NEXT(f, frame_list)); + ast_frfree(multi_frame); AST_LIST_NEXT(f, frame_list) = NULL; } diff --git a/main/fixedjitterbuf.c b/main/fixedjitterbuf.c index fc3e8cb664c..3c350b4bc45 100644 --- a/main/fixedjitterbuf.c +++ b/main/fixedjitterbuf.c @@ -194,7 +194,6 @@ int fixed_jb_put_first(struct fixed_jb *jb, void *data, long ms, long ts, long n return fixed_jb_put(jb, data, ms, ts, now); } - int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now) { struct fixed_jb_frame *frame, *next, *newframe; @@ -347,3 +346,8 @@ int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout) return FIXED_JB_OK; } + +int fixed_jb_is_late(struct fixed_jb *jb, long ts) +{ + return jb->rxcore + jb->delay + ts < jb->next_delivery; +} diff --git a/main/fixedjitterbuf.h b/main/fixedjitterbuf.h index df9bbac5529..ab8e5e2f886 100644 --- a/main/fixedjitterbuf.h +++ b/main/fixedjitterbuf.h @@ -85,6 +85,9 @@ int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout); void fixed_jb_set_force_resynch(struct fixed_jb *jb); +/*! \brief Checks if the given time stamp is late */ +int fixed_jb_is_late(struct fixed_jb *jb, long ts); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/jitterbuf.c b/main/jitterbuf.c index 4795b6d06af..a4d1971dddc 100644 --- a/main/jitterbuf.c +++ b/main/jitterbuf.c @@ -843,4 +843,7 @@ enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf) return JB_OK; } - +int jb_is_late(jitterbuf *jb, long ts) +{ + return ts + jb->info.current < jb->info.next_voice_ts; +} From 40b9766a3149158cb3f8c3478af64b5615b01215 Mon Sep 17 00:00:00 2001 From: Martin Tomec Date: Thu, 22 Dec 2016 11:07:33 +0100 Subject: [PATCH 0973/1578] app_queue: add RINGCANCELED log event on caller hang up QueueLog did not log ringnoanswer when the caller abandoned call before first timeout. It was impossible to get agent membername and ringing duration for this short calls. After some discusions it seems that the best way is to add new event RINGCANCELED, which is generated after caller hangup during ringing. ASTERISK-26665 Change-Id: Ic70f7b0f32fc95c9378e5bcf63865519014805d3 --- UPGRADE.txt | 4 ++++ apps/app_queue.c | 25 +++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/UPGRADE.txt b/UPGRADE.txt index 6cb61480726..569cc922274 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -33,6 +33,10 @@ Queue: their ringinuse value updated to the value of the queue. Previously, the ringinuse value for dynamic members was not updated on reload. +Queue log: + - New RINGCANCELED event is logged when the caller hangs up while ringing. + The data1 field contains number of miliseconds since start of ringing. + Channel Drivers: chan_dahdi: diff --git a/apps/app_queue.c b/apps/app_queue.c index 9176f936093..5874a49f62b 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4760,6 +4760,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte #endif char *inchan_name; struct timeval start_time_tv = ast_tvnow(); + int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */ ast_channel_lock(qe->chan); inchan_name = ast_strdupa(ast_channel_name(qe->chan)); @@ -5198,29 +5199,33 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { /* Got hung up */ *to = -1; - publish_dial_end_event(in, outgoing, NULL, "CANCEL"); if (f) { if (f->data.uint32) { ast_channel_hangupcause_set(in, f->data.uint32); } ast_frfree(f); } - return NULL; - } - - if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { + canceled_by_caller = 1; + } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); *to = 0; - publish_dial_end_event(in, outgoing, NULL, "CANCEL"); ast_frfree(f); - return NULL; - } - if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { + canceled_by_caller = 1; + } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { ast_verb(3, "User pressed digit: %c\n", f->subclass.integer); *to = 0; - publish_dial_end_event(in, outgoing, NULL, "CANCEL"); *digit = f->subclass.integer; ast_frfree(f); + canceled_by_caller = 1; + } + /* When caller hung up or pressed * or digit. */ + if (canceled_by_caller) { + publish_dial_end_event(in, outgoing, NULL, "CANCEL"); + for (o = start; o; o = o->call_next) { + if (o->chan) { + ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), o->member->membername, "RINGCANCELED", "%d", (int) ast_tvdiff_ms(ast_tvnow(), start_time_tv)); + } + } return NULL; } From 48730ae65eefdf844d61ee611d3f2a1d42af807b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sun, 1 Jan 2017 03:47:50 -0600 Subject: [PATCH 0974/1578] res_pjsip_outbound_authenticator_digest.c: Fix spacing in warning messages. Change-Id: I573f0343c0c63a785cd4da60d57cc9f8b9ce7f49 --- res/res_pjsip_outbound_authenticator_digest.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c index ce77c3bad15..4bbac342f53 100644 --- a/res/res_pjsip_outbound_authenticator_digest.c +++ b/res/res_pjsip_outbound_authenticator_digest.c @@ -141,18 +141,18 @@ static int digest_create_request_with_auth(const struct ast_sip_auth_vector *aut ++cseq->cseq; return 0; case PJSIP_ENOCREDENTIAL: - ast_log(LOG_WARNING, "Unable to create request with auth." - "No auth credentials for any realms in challenge.\n"); + ast_log(LOG_WARNING, + "Unable to create request with auth. No auth credentials for any realms in challenge.\n"); break; case PJSIP_EAUTHSTALECOUNT: - ast_log(LOG_WARNING, "Unable to create request with auth." - "Number of stale retries exceeded\n"); + ast_log(LOG_WARNING, + "Unable to create request with auth. Number of stale retries exceeded.\n"); break; case PJSIP_EFAILEDCREDENTIAL: - ast_log(LOG_WARNING, "Authentication credentials not accepted by server\n"); + ast_log(LOG_WARNING, "Authentication credentials not accepted by server.\n"); break; default: - ast_log(LOG_WARNING, "Unable to create request with auth. Unknown failure\n"); + ast_log(LOG_WARNING, "Unable to create request with auth. Unknown failure.\n"); break; } From d16b3a99171338264f9d7aa15819ed6d9c9b1d85 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 13 Jan 2017 10:03:15 -0700 Subject: [PATCH 0975/1578] debug_utilities: Create ast_loggrabber ast_loggrabber gathers log files from customizable search patterns, optionally converts POSIX timestamps to a readable format and tarballs the results. Also a few tweaks were made to ast_coredumper. Change-Id: I8bfe1468ada24c1344ce4abab7b002a59a659495 (cherry picked from commit c70915287837704090d75f181525765de7a17221) --- configs/samples/ast_debug_tools.conf.sample | 17 ++ contrib/Makefile | 10 +- contrib/scripts/ast_coredumper | 39 ++- contrib/scripts/ast_loggrabber | 255 ++++++++++++++++++++ 4 files changed, 304 insertions(+), 17 deletions(-) create mode 100755 contrib/scripts/ast_loggrabber diff --git a/configs/samples/ast_debug_tools.conf.sample b/configs/samples/ast_debug_tools.conf.sample index 90e976f1bc5..f26626b20fb 100644 --- a/configs/samples/ast_debug_tools.conf.sample +++ b/configs/samples/ast_debug_tools.conf.sample @@ -38,3 +38,20 @@ COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt)) # # Readable Local time DATEFORMAT='date +%FT%H-%M-%S%z' + +# A list of log files and/or log file search patterns using the +# same syntax as COREDUMPS. +# +LOGFILES=(/var/log/asterisk/messages* /var/log/asterisk/queue* \ + /var/log/asterisk/debug* /var/log/asterisk/security*) + +# ast_loggrabber converts POSIX timestamps to readable format +# using this Python strftime format string. If not specified +# or an empty string, no format covnersion is done. +LOG_DATEFORMAT="%m/%d-%H:%M:%S.%f" + +# The timezone to use when converting POSIX timestamps to +# readable format. It can be specified in "/" +# format or in abbreviation format such as "CST6CDT". If not +# specified, the "local" timezone is used. +# LOG_TIMEZONE= diff --git a/contrib/Makefile b/contrib/Makefile index a5775cb82c2..a6672431133 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -20,10 +20,12 @@ clean: include $(ASTTOPDIR)/Makefile.rules install: - $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts"; \ - $(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"; \ + $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts" + $(INSTALL) -m 755 scripts/ast_loggrabber "$(DESTDIR)$(ASTDATADIR)/scripts/ast_loggrabber" $(INSTALL) -m 755 scripts/ast_coredumper "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper" + $(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py" uninstall: - rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py" - rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper" + -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_loggrabber" + -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper" + -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py" diff --git a/contrib/scripts/ast_coredumper b/contrib/scripts/ast_coredumper index c82732be9bf..81e94e9458b 100755 --- a/contrib/scripts/ast_coredumper +++ b/contrib/scripts/ast_coredumper @@ -15,6 +15,7 @@ SYNOPSIS $prog [ --help ] [ --running | --RUNNING ] [ --latest ] [ --tarball-coredumps ] [ --delete-coredumps-after ] [ --tarball-results ] [ --delete-results-after ] + [ --tarball-uniqueid="" ] [ --no-default-search ] [ --append-coredumps ] [ | ... ] @@ -81,6 +82,11 @@ DESCRIPTION to use this option unless you have also specified --tarball-results. + --tarball-uniqueid="" + Normally DATEFORMAT is used to make the tarballs unique + but you can use your own unique id in the tarball names + such as the Jira issue id. + --no-default-search Ignore COREDUMPS from the config files and process only coredumps listed on the command line (if any) and/or @@ -111,6 +117,8 @@ DESCRIPTION /tmp/core[-._]\$(hostname)!(*.txt) NOTES + You must be root to use $prog. + The script relies on not only bash, but also recent GNU date and gdb with python support. *BSD operating systems may require installation of the 'coreutils' and 'devel/gdb' packagess and minor @@ -171,6 +179,11 @@ EOF exit 1 } +if [ $EUID -ne 0 ] ; then + echo "You must be root to use $prog." + exit 1 +fi + running=false RUNNING=false latest=false @@ -245,6 +258,9 @@ for a in "$@" ; do --append-coredumps) append_coredumps=true ;; + --tarball-uniqueid=*) + tarball_uniqueid=${a#*=} + ;; --help|-*) print_help ;; @@ -294,7 +310,7 @@ if [ ${#COREDUMPS[@]} -gt 0 ] && $latest ; then fi # Timestamp to use for output files -df=$(${DATEFORMAT}) +df=${tarball_uniqueid:-$(${DATEFORMAT})} if $running || $RUNNING ; then # We need to go through some gyrations to find the pid of the running @@ -321,12 +337,9 @@ if $running || $RUNNING ; then read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer fi if [[ "$answer" =~ ^[Yy] ]] ; then - cf="/tmp/core.asterisk.running.$df" - # We want a consistent coredump so stop the process - # and continue it after the dump is complete. - # kill -STOP $pid + cf="/tmp/core-asterisk-running-$df" + echo "Dumping running asterisk process to $cf" ${GDB} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1 - # kill -CONT $pid COREDUMPS+=("$cf") else echo "Skipping dump of running process" @@ -343,17 +356,17 @@ fi # and save them to /tmp/.gdbinit ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:` -tail -n +${ss} $0 >/tmp/.gdbinit +tail -n +${ss} $0 >/tmp/.ast_coredumper.gdbinit # Now iterate over the coredumps and dump the debugging info for i in ${!COREDUMPS[@]} ; do cf=${COREDUMPS[$i]} echo "Processing $cf" - ${GDB} -n --batch -q --ex "source /tmp/.gdbinit" $(which asterisk) "$cf" 2>/dev/null | ( + ${GDB} -n --batch -q --ex "source /tmp/.ast_coredumper.gdbinit" $(which asterisk) "$cf" 2>/dev/null | ( of=/dev/null while IFS= read line ; do if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then - of=$cf.${BASH_REMATCH[1]} + of=${cf}-${BASH_REMATCH[1]} of=${of//:/-} rm -f "$of" echo "Creating $of" @@ -364,7 +377,7 @@ for i in ${!COREDUMPS[@]} ; do done if $tarball_coredumps ; then - tf=/tmp/asterisk.$df.coredumps.tar + tf=/tmp/asterisk-$df.coredumps.tar echo "Creating $tf.gz" for i in ${!COREDUMPS[@]} ; do tar -uvf $tf "${COREDUMPS[@]}" 2>/dev/null @@ -379,17 +392,17 @@ if $delete_coredumps_after ; then fi if $tarball_results ; then - tf=/tmp/asterisk.$df.results.tar + tf=/tmp/asterisk-$df-results.tar echo "Creating $tf.gz" for i in ${!COREDUMPS[@]} ; do - tar -uvf $tf "${COREDUMPS[$i]//:/-}".{brief,full,thread1,locks}.txt 2>/dev/null + tar -uvf $tf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt 2>/dev/null done gzip $tf fi if $delete_results_after ; then for i in ${!COREDUMPS[@]} ; do - rm -rf "${COREDUMPS[$i]//:/-}".{brief,full,thread1,locks}.txt + rm -rf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt done fi diff --git a/contrib/scripts/ast_loggrabber b/contrib/scripts/ast_loggrabber new file mode 100755 index 00000000000..2036d54baf6 --- /dev/null +++ b/contrib/scripts/ast_loggrabber @@ -0,0 +1,255 @@ +#!/usr/bin/env bash +# Turn on extended globbing +shopt -s extglob +# Bail on any error +set -e + +prog=$(basename $0) + +print_help() { +cat < | ... ] + +DESCRIPTION + + Gathers log files, optionally converts POSIX timestamps + to readable format. and creates a tarball. + + Options: + + --help + Print this help. + + --dateformat="" + A Python strftime format string to be used when converting + POSIX timestamps in log files to readable format. If not + specified as an argument or in the config file, no conversion + is done. + + --timezone="" + The timezone to use when converting POSIX timestamps to + readable format. It can be specified in "/" + format or in abbreviation format such as "CST6CDT". If not + specified as an argument or in the config file, the "local" + timezone is used. + + --append-logfiles + Append any log files specified on the command line to the + config file specified ones instead of overriding them. + + --tarball-uniqueid="" + Normally DATEFORMAT is used to make the tarballs unique + but you can use your own unique id in the tarball names + such as a Jira issue id. + + | + A list of log files or log file search patterns. Unless + --append-logfiles was specified, these entries will override + those specified in the config files. + + If no files are specified on the command line the, value of + LOGFILES from ast_debug_tools.conf will be used. Failing + that, the following patterns will be used: + /var/log/asterisk/messages* + /var/log/asterisk/queue* + /var/log/asterisk/debug* + /var/log/asterisk/security* + +NOTES + Any files output will have ':' characters changed to '-'. This is + to facilitate uploading those files to Jira which doesn't like the + colons. + +FILES + /etc/asterisk/ast_debug_tools.conf + ~/ast_debug_tools.conf + ./ast_debug_tools.conf + + # Readable Local time for the tarball names + DATEFORMAT='date +%FT%H-%M-%S%z' + + # A list of log files and/or log file search patterns using the + # same syntax as COREDUMPS. + # + LOGFILES=(/var/log/asterisk/messages* /var/log/asterisk/queue* \\ + /var/log/asterisk/debug* /var/log/asterisk/security*) + + # $prog converts POSIX timestamps to readable format + # using this Python strftime format string. If not specified + # or an empty string, no format covnersion is done. + LOG_DATEFORMAT="%m/%d %H:%M:%S.%f" + + # The timezone to use when converting POSIX timestamps to + # readable format. It can be specified in "/" + # format or in abbreviation format such as "CST6CDT". If not + # specified, the "local" timezone is used. + # LOG_TIMEZONE= + +EOF + exit 1 +} + +append_logfiles=false + +declare -a LOGFILES +declare -a ARGS_LOGFILES + +# Read config files from least important to most important +[ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf +[ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf +[ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf + +if [ ${#LOGFILES[@]} -eq 0 ] ; then + LOGFILES+=(/var/log/asterisk/messages* /var/log/asterisk/queue* \ + /var/log/asterisk/debug* /var/log/asterisk/security*) +fi + +DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'} + +# Use "$@" (with the quotes) so spaces in patterns or +# file names are preserved. +# Later on when we have to iterate over LOGFILES, we always +# use the indexes rather than trying to expand the values of LOGFILES +# just in case. + +for a in "$@" ; do + case "$a" in + --dateformat=*) + LOG_DATEFORMAT=${a#*=} + ;; + --timezone=*) + LOG_TIMEZONE=${a#*=} + ;; + --append-logfiles) + append_logfiles=true + ;; + --tarball-uniqueid=*) + tarball_uniqueid=${a#*=} + ;; + --help|-*) + print_help + ;; + *) + ARGS_LOGFILES+=("$a") + # If any files are specified on the command line, ignore those + # specified in the config files unless append-logfiles was specified. + if ! $append_logfiles ; then + LOGFILES=() + fi + esac +done + +# append logfiles/patterns specified as command line arguments to LOGFILES. +for i in ${!ARGS_LOGFILES[@]} ; do + LOGFILES+=("${ARGS_LOGFILES[$i]}") +done + +# At this point, all glob entries that match files should be expanded. +# Any entries that don't exist are probably globs that didn't match anything +# and need to be pruned. + +for i in ${!LOGFILES[@]} ; do + if [ ! -f "${LOGFILES[$i]}" ] ; then + unset LOGFILES[$i] + continue + fi +done + +# Sort and weed out any dups +IFS=$'\x0a' +readarray -t LOGFILES < <(echo -n "${LOGFILES[*]}" | sort -u ) +unset IFS + +if [ "${#LOGFILES[@]}" -eq 0 ] ; then + echo "No log files found" + print_help +fi + +# Timestamp to use for output files +df=${tarball_uniqueid:-$(${DATEFORMAT})} + +# Extract the Python timestamp conver script from the end of this +# script and save it to /tmp/.ast_tsconvert.py + +ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:` +tail -n +${ss} $0 >/tmp/.ast_tsconvert.py + +tmpdir=$(mktemp -d) +if [ -z "$tmpdir" ] ; then + echo "${prog}: Unable to create temporary directory." + exit 1 +fi +trap "rm -rf $tmpdir" EXIT +tardir=asterisk-${df}.logfiles + +# Now iterate over the logfiles +for i in ${!LOGFILES[@]} ; do + lf=${LOGFILES[$i]} + destdir="$tmpdir/$tardir/$(dirname $lf)" + destfile="$tmpdir/$tardir/$lf" + mkdir -p "$destdir" 2>/dev/null || : + if [ -n "$LOG_DATEFORMAT" ] ; then + echo "Converting $lf" + cat "$lf" | python /tmp/.ast_tsconvert.py --format="$LOG_DATEFORMAT" --timezone="$LOG_TIMEZONE" > "${destfile}" + else + echo "Copying $lf" + cp "$lf" "${destfile}" + fi +done + +echo "Creating /tmp/$tardir.tar.gz" +tar -czvf /tmp/$tardir.tar.gz -C $tmpdir $tardir 2>/dev/null + +exit + +# Be careful editng the inline scripts. +# They're space-indented. + +# We need the python bit because lock_infos isn't +# a valid symbol in asterisk unless DEBUG_THREADS was +# used during the compile. Also, interrupt and continue +# are only valid for a running program. + +#@@@SCRIPTSTART@@@ +import argparse +import datetime as dt +import dateutil.tz as tz +import re +import sys +import time + +parser = argparse.ArgumentParser(description="Make POSIX timestamps readable") +parser.add_argument('--format', action='store', required=True) +parser.add_argument('--timezone', action='store', required=False) +args=parser.parse_args() + +# We only convert timestamps that are at the beginning of a line +# or are preceeded by a whilespace character or a '[' +rets = re.compile(r'(^|(?<=\s|\[))\d+(\.\d+)?', flags=re.M) +if args.timezone and len(args.timezone) > 0: + tzf = tz.tzfile('/usr/share/zoneinfo/' + args.timezone) +else: + tzf = tz.tzfile('/etc/localtime') + +now = time.time() +a_year_ago = now - (86400.0 * 365) + +def convert(match): + ts = float(match.group(0)) + if ts <= now and ts > a_year_ago and len(args.format) > 0: + return dt.datetime.fromtimestamp(ts, tzf).strftime(args.format) + else: + return match.group(0) + +while 1: + line = sys.stdin.readline() + if not line: + break + print(rets.sub(convert, line)) From 90f3b1270ce1b128779b4f74e28665e4a9fb1917 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Jan 2017 12:58:52 -0600 Subject: [PATCH 0976/1578] res_pjsip: alloca can never fail. Change-Id: Ia2a6158e5fdf311bc2a1c0c43417978de504b1f1 --- res/res_pjsip/pjsip_configuration.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 00c22333078..6a15946d660 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1708,9 +1708,7 @@ static int cli_endpoint_print_body(void *obj, void *arg, int flags) if (number) { print_name_len = strlen(id) + strlen(number) + 2; - if (!(print_name = alloca(print_name_len))) { - return -1; - } + print_name = ast_alloca(print_name_len); snprintf(print_name, print_name_len, "%s/%s", id, number); } From 6d648185bce79170328265c942519332c4b066e5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Jan 2017 13:01:17 -0600 Subject: [PATCH 0977/1578] res_pjsip_pubsub.c: Eliminate trivial SCOPED_LOCK usage. Change-Id: Ie0b69a830385452042fa19e7d267c6790ec6b6be --- res/res_pjsip_pubsub.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 43a9d4ba65e..ab8f9ed6bd4 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1017,14 +1017,16 @@ static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct a static void add_subscription(struct sip_subscription_tree *obj) { - SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_WRLOCK(&subscriptions); AST_RWLIST_INSERT_TAIL(&subscriptions, obj, next); + AST_RWLIST_UNLOCK(&subscriptions); } static void remove_subscription(struct sip_subscription_tree *obj) { struct sip_subscription_tree *i; - SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_WRLOCK(&subscriptions); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscriptions, i, next) { if (i == obj) { AST_RWLIST_REMOVE_CURRENT(next); @@ -1036,6 +1038,7 @@ static void remove_subscription(struct sip_subscription_tree *obj) } } AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_UNLOCK(&subscriptions); } static void destroy_subscription(struct ast_sip_subscription *sub) @@ -1578,18 +1581,19 @@ static int for_each_subscription(on_subscription_t on_subscription, void *arg) { int num = 0; struct sip_subscription_tree *i; - SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); if (!on_subscription) { return num; } + AST_RWLIST_RDLOCK(&subscriptions); AST_RWLIST_TRAVERSE(&subscriptions, i, next) { if (on_subscription(i, arg)) { break; } ++num; } + AST_RWLIST_UNLOCK(&subscriptions); return num; } @@ -2489,8 +2493,9 @@ static int publication_cmp_fn(void *obj, void *arg, int flags) static void publish_add_handler(struct ast_sip_publish_handler *handler) { - SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_WRLOCK(&publish_handlers); AST_RWLIST_INSERT_TAIL(&publish_handlers, handler, next); + AST_RWLIST_UNLOCK(&publish_handlers); } int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler) @@ -2517,7 +2522,8 @@ int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler) void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler) { struct ast_sip_publish_handler *iter; - SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_WRLOCK(&publish_handlers); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&publish_handlers, iter, next) { if (handler == iter) { AST_RWLIST_REMOVE_CURRENT(next); @@ -2527,27 +2533,30 @@ void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler) } } AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_UNLOCK(&publish_handlers); } AST_RWLIST_HEAD_STATIC(subscription_handlers, ast_sip_subscription_handler); static void sub_add_handler(struct ast_sip_subscription_handler *handler) { - SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_WRLOCK(&subscription_handlers); AST_RWLIST_INSERT_TAIL(&subscription_handlers, handler, next); ast_module_ref(ast_module_info->self); + AST_RWLIST_UNLOCK(&subscription_handlers); } static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name) { struct ast_sip_subscription_handler *iter; - SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_RDLOCK(&subscription_handlers); AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) { if (!strcmp(iter->event_name, event_name)) { break; } } + AST_RWLIST_UNLOCK(&subscription_handlers); return iter; } @@ -2586,7 +2595,8 @@ int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *h void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler) { struct ast_sip_subscription_handler *iter; - SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_WRLOCK(&subscription_handlers); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscription_handlers, iter, next) { if (handler == iter) { AST_RWLIST_REMOVE_CURRENT(next); @@ -2595,6 +2605,7 @@ void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler } } AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_UNLOCK(&subscription_handlers); } static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype_nolock(const char *type, const char *subtype) @@ -2823,8 +2834,8 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata) static struct ast_sip_publish_handler *find_pub_handler(const char *event) { struct ast_sip_publish_handler *iter = NULL; - SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_RDLOCK(&publish_handlers); AST_RWLIST_TRAVERSE(&publish_handlers, iter, next) { if (strcmp(event, iter->event_name)) { ast_debug(3, "Event %s does not match %s\n", event, iter->event_name); @@ -2833,6 +2844,7 @@ static struct ast_sip_publish_handler *find_pub_handler(const char *event) ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name); break; } + AST_RWLIST_UNLOCK(&publish_handlers); return iter; } @@ -3201,8 +3213,8 @@ int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator) { struct ast_sip_pubsub_body_generator *iter; - SCOPED_LOCK(lock, &body_generators, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_WRLOCK(&body_generators); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_generators, iter, list) { if (iter == generator) { AST_LIST_REMOVE_CURRENT(list); @@ -3210,6 +3222,7 @@ void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generat } } AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_UNLOCK(&body_generators); } int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement) @@ -3224,8 +3237,8 @@ int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplemen void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement) { struct ast_sip_pubsub_body_supplement *iter; - SCOPED_LOCK(lock, &body_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_WRLOCK(&body_supplements); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_supplements, iter, list) { if (iter == supplement) { AST_LIST_REMOVE_CURRENT(list); @@ -3233,6 +3246,7 @@ void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supple } } AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_UNLOCK(&body_supplements); } const char *ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub) From ab858295a27b7e7bb6ae028b25d6e16e8ae67076 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Jan 2017 13:02:06 -0600 Subject: [PATCH 0978/1578] res_pjsip_pubsub.c: Fix incorrect message string wrapping. Change-Id: Id771e6fe56d89ce365ddcbb423f820af97211120 --- res/res_pjsip_pubsub.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 43a9d4ba65e..0ec344334db 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -889,8 +889,9 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) { current = tree_node_alloc(resource, visited, 0); if (!current) { - ast_debug(1, "Subscription to leaf resource %s was successful, but encountered" - "allocation error afterwards\n", resource); + ast_debug(1, + "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n", + resource); continue; } ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n", @@ -2565,8 +2566,9 @@ int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *h existing = find_sub_handler_for_event_name(handler->event_name); if (existing) { - ast_log(LOG_ERROR, "Unable to register subscription handler for event %s." - "A handler is already registered\n", handler->event_name); + ast_log(LOG_ERROR, + "Unable to register subscription handler for event %s. A handler is already registered\n", + handler->event_name); return -1; } @@ -2764,7 +2766,6 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata) AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource); expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next); - if (expires_header) { if (expires_header->ivalue == 0) { ast_log(LOG_WARNING, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n", From ef9164b9cae3bfe488b471e4eb1ded8995b53668 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Jan 2017 15:11:12 -0600 Subject: [PATCH 0979/1578] res_pjsip_pubsub.c: Fix AMI event list counts. Fix the AMI PJSIPShowSubscriptionsInbound, PJSIPShowSubscriptionsOutbound, and PJSIPShowResourceLists actions event counts. The reported counts may not necessarily be accurate depending on what happens. The subscriptions count would be wrong if Asterisk ever has outbound subscriptions. The resource list count could be wrong if a list were added or removed during the AMI action being processed. Change-Id: I4344301827523fa174960a42c413fd19abe4aed5 --- res/res_pjsip_pubsub.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 43a9d4ba65e..4c980680d49 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -3586,6 +3586,8 @@ static int ami_subscription_detail(struct sip_subscription_tree *sub_tree, sip_subscription_to_ami(sub_tree, &buf); astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); ast_free(buf); + + ++ami->count; return 0; } @@ -3604,14 +3606,13 @@ static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tr static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m) { struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), }; - int num; astman_send_listack(s, m, "Following are Events for each inbound Subscription", "start"); - num = for_each_subscription(ami_subscription_detail_inbound, &ami); + for_each_subscription(ami_subscription_detail_inbound, &ami); - astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", num); + astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count); astman_send_list_complete_end(s); return 0; } @@ -3619,14 +3620,13 @@ static int ami_show_subscriptions_inbound(struct mansession *s, const struct mes static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m) { struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), }; - int num; astman_send_listack(s, m, "Following are Events for each outbound Subscription", "start"); - num = for_each_subscription(ami_subscription_detail_outbound, &ami); + for_each_subscription(ami_subscription_detail_outbound, &ami); - astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", num); + astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count); astman_send_list_complete_end(s); return 0; } @@ -3647,21 +3647,21 @@ static int format_ami_resource_lists(void *obj, void *arg, int flags) return CMP_STOP; } astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); - ast_free(buf); + + ++ami->count; return 0; } static int ami_show_resource_lists(struct mansession *s, const struct message *m) { struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), }; - int num; struct ao2_container *lists; lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); - if (!lists || !(num = ao2_container_count(lists))) { + if (!lists || !ao2_container_count(lists)) { astman_send_error(s, m, "No resource lists found\n"); return 0; } @@ -3671,7 +3671,7 @@ static int ami_show_resource_lists(struct mansession *s, const struct message *m ao2_callback(lists, OBJ_NODATA, format_ami_resource_lists, &ami); - astman_send_list_complete_start(s, m, "ResourceListDetailComplete", num); + astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count); astman_send_list_complete_end(s); return 0; } From dbb9c8141d2a72b36334b7e9044a4fe06217c0f1 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Sat, 21 Jan 2017 22:43:48 +0200 Subject: [PATCH 0980/1578] tests: use datadir for sound files Some (voicemail-related) tests API symlinks beep.gsm and other files from ast_config_AST_VAR_DIR. It should use ast_config_AST_DATA_DIR. ASTERISK-26740 #close Change-Id: Id49c56fb9e16df64b1a2b829693ca7601252df89 --- apps/app_voicemail.c | 6 +++--- tests/test_voicemail_api.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 03273c69bc7..37f8aa96f5b 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -14393,7 +14393,7 @@ AST_TEST_DEFINE(test_voicemail_vmsayname) ast_log(AST_LOG_WARNING, "Failed to make test directory\n"); goto exit_vmsayname_test; } - snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR); + snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_DATA_DIR); snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION); /* we're not going to hear the sound anyway, just use a valid gsm audio file */ if ((res = symlink(dir, dir2))) { @@ -14639,8 +14639,8 @@ AST_TEST_DEFINE(test_voicemail_notify_endl) break; } - snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR); - snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR); + snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_DATA_DIR); + snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_DATA_DIR); if (!(vmu = find_user(&vmus, testcontext, testmailbox)) && !(vmu = find_or_create(testcontext, testmailbox))) { diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c index 9cadf2394ed..77b538ef859 100644 --- a/tests/test_voicemail_api.c +++ b/tests/test_voicemail_api.c @@ -460,7 +460,7 @@ static int test_vm_api_create_voicemail_files(const char *context, const char *m folder_path, snapshot->msg_number); snprintf(snd_path, sizeof(snd_path), "%s/msg%04u.gsm", folder_path, snapshot->msg_number); - snprintf(beep_path, sizeof(beep_path), "%s/sounds/en/beep.gsm", ast_config_AST_VAR_DIR); + snprintf(beep_path, sizeof(beep_path), "%s/sounds/en/beep.gsm", ast_config_AST_DATA_DIR); if (test_vm_api_create_voicemail_folder(folder_path)) { return 1; From cfe72c39cfbd66cca9ea409f2eb76d5076ae6fd8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sun, 22 Jan 2017 17:25:57 -0600 Subject: [PATCH 0981/1578] LISTFILTER: Remove outdated ERROR message. Feeding LISTFILTER an empty variable results in an invalid ERROR message. Earlier changes made the message useless because we can no longer tell if the variable is empty or does not exist. It is valid to try to remove a value from an empty list just as it is valid to try to remove a value that is not in a non-empty list. * Removed the outdated ERROR message. * Added more test cases to the LISTFILTER unit test. Change-Id: Ided9040e6359c44a335ef54e02ef5950a1863134 --- funcs/func_strings.c | 1 - tests/test_substitution.c | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/funcs/func_strings.c b/funcs/func_strings.c index 885de61c57e..2d03c15e8c0 100644 --- a/funcs/func_strings.c +++ b/funcs/func_strings.c @@ -617,7 +617,6 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch } ast_str_substitute_variables(&orig_list, 0, chan, varsubst); if (!ast_str_strlen(orig_list)) { - ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname); if (chan) { ast_channel_unlock(chan); } diff --git a/tests/test_substitution.c b/tests/test_substitution.c index ca84d002356..3a1dc1fbac8 100644 --- a/tests/test_substitution.c +++ b/tests/test_substitution.c @@ -285,7 +285,16 @@ AST_TEST_DEFINE(test_substitution) TEST(test_expected_result(test, c, "A${${baz}o:-2:1}A", "A2A")); TEST(test_expected_result(test, c, "A${${baz}o:-2:-1}A", "A2A")); pbx_builtin_setvar_helper(c, "list1", "ab&cd&ef"); + TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,ab)}", "cd&ef")); TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,cd)}", "ab&ef")); + TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,ef)}", "ab&cd")); + TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,gh)}", "ab&cd&ef")); + TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,c)}", "ab&cd&ef")); + TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,d)}", "ab&cd&ef")); + pbx_builtin_setvar_helper(c, "list2", "ab"); + TEST(test_expected_result(test, c, "${LISTFILTER(list2,&,ab)}", "")); + pbx_builtin_setvar_helper(c, "list_empty", ""); + TEST(test_expected_result(test, c, "${LISTFILTER(list_empty,&,ab)}", "")); TEST(test_expected_result(test, c, "${SHELL(printf '%d' 123)},${SHELL(printf '%d' 456)}", "123,456")); TEST(test_expected_result(test, c, "${foo},${CDR(answer)},${SHELL(printf '%d' 456)}", "123,,456")); TEST(test_expected_result(test, c, "${foo},${CDR(answer,u)},${SHELL(printf '%d' 456)}", "123,0.000000,456")); From 1061539b75811d9115dcbc0be46967515bd9e2d1 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 29 Nov 2016 16:31:21 +0100 Subject: [PATCH 0982/1578] media: Add experimental support for RTCP feedback. This change adds experimental support for providing RTCP feedback information to codec modules so they can dynamically change themselves based on conditions. ASTERISK-26584 Change-Id: Ifd6aa77fb4a7ff546c6025900fc2baf332c31857 --- codecs/codec_speex.c | 83 ++++++++++++++++++++++++++++++ configs/samples/codecs.conf.sample | 3 ++ funcs/func_frame_trace.c | 3 ++ include/asterisk/frame.h | 2 + include/asterisk/translate.h | 10 +++- main/channel.c | 10 ++++ main/frame.c | 8 +++ main/translate.c | 11 ++++ res/res_rtp_asterisk.c | 23 +++++++++ 9 files changed, 151 insertions(+), 2 deletions(-) diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c index 49990e988e8..72ac2202324 100644 --- a/codecs/codec_speex.c +++ b/codecs/codec_speex.c @@ -55,6 +55,9 @@ #include "asterisk/frame.h" #include "asterisk/linkedlists.h" +/* For struct ast_rtp_rtcp_report and struct ast_rtp_rtcp_report_block */ +#include "asterisk/rtp_engine.h" + /* codec variables */ static int quality = 3; static int complexity = 2; @@ -64,6 +67,7 @@ static int vbr = 0; static float vbr_quality = 4; static int abr = 0; static int dtx = 0; /* set to 1 to enable silence detection */ +static int exp_rtcp_fb = 0; /* set to 1 to use experimental RTCP feedback for changing bitrate */ static int preproc = 0; static int pp_vad = 0; @@ -91,6 +95,11 @@ struct speex_coder_pvt { SpeexBits bits; int framesize; int silent_state; + + int fraction_lost; + int quality; + int default_quality; + #ifdef _SPEEX_TYPES_H SpeexPreprocessState *pp; spx_int16_t buf[BUFFER_SAMPLES]; @@ -137,6 +146,11 @@ static int speex_encoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *p speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx); tmp->silent_state = 0; + tmp->fraction_lost = 0; + tmp->default_quality = vbr ? vbr_quality : quality; + tmp->quality = tmp->default_quality; + ast_debug(3, "Default quality (%s): %d\n", vbr ? "vbr" : "cbr", tmp->default_quality); + return 0; } @@ -342,6 +356,69 @@ static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt) return result; } +/*! \brief handle incoming RTCP feedback and possibly edit encoder settings */ +static void lintospeex_feedback(struct ast_trans_pvt *pvt, struct ast_frame *feedback) +{ + struct speex_coder_pvt *tmp = pvt->pvt; + + struct ast_rtp_rtcp_report *rtcp_report; + struct ast_rtp_rtcp_report_block *report_block; + + int fraction_lost; + int percent; + int bitrate; + int q; + + if(!exp_rtcp_fb) + return; + + rtcp_report = (struct ast_rtp_rtcp_report *)feedback->data.ptr; + if (rtcp_report->reception_report_count == 0) + return; + report_block = rtcp_report->report_block[0]; + fraction_lost = report_block->lost_count.fraction; + if (fraction_lost == tmp->fraction_lost) + return; + /* Per RFC3550, fraction lost is defined to be the number of packets lost + * divided by the number of packets expected. Since it's a 8-bit value, + * and we want a percentage value, we multiply by 100 and divide by 256. */ + percent = (fraction_lost*100)/256; + bitrate = 0; + q = -1; + ast_debug(3, "Fraction lost changed: %d --> %d percent loss\n", fraction_lost, percent); + /* Handle change */ + speex_encoder_ctl(tmp->speex, SPEEX_GET_BITRATE, &bitrate); + ast_debug(3, "Current bitrate: %d\n", bitrate); + ast_debug(3, "Current quality: %d/%d\n", tmp->quality, tmp->default_quality); + /* FIXME BADLY Very ugly example of how this could be handled: probably sucks */ + if (percent < 10) { + /* Not that bad, default quality is fine */ + q = tmp->default_quality; + } else if (percent < 20) { + /* Quite bad, let's go down a bit */ + q = tmp->default_quality-1; + } else if (percent < 30) { + /* Very bad, let's go down even more */ + q = tmp->default_quality-2; + } else { + /* Really bad, use the lowest quality possible */ + q = 0; + } + if (q < 0) + q = 0; + if (q != tmp->quality) { + ast_debug(3, " -- Setting to %d\n", q); + if (vbr) { + float vbr_q = q; + speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_q); + } else { + speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &q); + } + tmp->quality = q; + } + tmp->fraction_lost = fraction_lost; +} + static void speextolin_destroy(struct ast_trans_pvt *arg) { struct speex_coder_pvt *pvt = arg->pvt; @@ -400,6 +477,7 @@ static struct ast_translator lintospeex = { .newpvt = lintospeex_new, .framein = lintospeex_framein, .frameout = lintospeex_frameout, + .feedback = lintospeex_feedback, .destroy = lintospeex_destroy, .sample = slin8_sample, .desc_size = sizeof(struct speex_coder_pvt), @@ -446,6 +524,7 @@ static struct ast_translator lin16tospeexwb = { .newpvt = lin16tospeexwb_new, .framein = lintospeex_framein, .frameout = lintospeex_frameout, + .feedback = lintospeex_feedback, .destroy = lintospeex_destroy, .sample = slin16_sample, .desc_size = sizeof(struct speex_coder_pvt), @@ -491,6 +570,7 @@ static struct ast_translator lin32tospeexuwb = { .newpvt = lin32tospeexuwb_new, .framein = lintospeex_framein, .frameout = lintospeex_frameout, + .feedback = lintospeex_feedback, .destroy = lintospeex_destroy, .desc_size = sizeof(struct speex_coder_pvt), .buffer_samples = BUFFER_SAMPLES, @@ -586,6 +666,9 @@ static int parse_config(int reload) pp_dereverb_level = res_f; } else ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n"); + } else if (!strcasecmp(var->name, "experimental_rtcp_feedback")) { + exp_rtcp_fb = ast_true(var->value) ? 1 : 0; + ast_verb(3, "CODEC SPEEX: Experimental RTCP Feedback. [%s]\n",exp_rtcp_fb ? "on" : "off"); } } ast_config_destroy(cfg); diff --git a/configs/samples/codecs.conf.sample b/configs/samples/codecs.conf.sample index 63d0352a860..e40aa35a3b9 100644 --- a/configs/samples/codecs.conf.sample +++ b/configs/samples/codecs.conf.sample @@ -57,6 +57,9 @@ pp_dereverb => false pp_dereverb_decay => 0.4 pp_dereverb_level => 0.3 +; experimental bitrate changes depending on RTCP feedback [true / false] +experimental_rtcp_feedback => false + [plc] ; for all codecs which do not support native PLC diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c index 08c426161a2..8a0b3dd5928 100644 --- a/funcs/func_frame_trace.c +++ b/funcs/func_frame_trace.c @@ -370,6 +370,9 @@ static void print_frame(struct ast_frame *frame) } ast_verbose("Bytes: %d\n", frame->datalen); break; + case AST_FRAME_RTCP: + ast_verbose("FrameType: RTCP\n"); + break; case AST_FRAME_NULL: ast_verbose("FrameType: NULL\n"); break; diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 20f40f8634c..45bc8fc3245 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -127,6 +127,8 @@ enum ast_frame_type { * directly into bridges. */ AST_FRAME_BRIDGE_ACTION_SYNC, + /*! RTCP feedback */ + AST_FRAME_RTCP, }; #define AST_FRAME_DTMF AST_FRAME_DTMF_END diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h index 8188eb8ebfe..f0fa8391837 100644 --- a/include/asterisk/translate.h +++ b/include/asterisk/translate.h @@ -121,7 +121,7 @@ enum ast_trans_cost_table { * * As a minimum, a translator should supply name, srcfmt and dstfmt, * the required buf_size (in bytes) and buffer_samples (in samples), - * and a few callbacks (framein, frameout, sample). + * and a few callbacks (framein, frameout, feedback, sample). * The outbuf is automatically prepended by AST_FRIENDLY_OFFSET * spare bytes so generic routines can place data in there. * @@ -159,6 +159,10 @@ struct ast_translator { /*!< Output frame callback. Generate a frame * with outbuf content. */ + void (*feedback)(struct ast_trans_pvt *pvt, struct ast_frame *feedback); + /*!< Feedback frame callback. Handle + * input frame. */ + void (*destroy)(struct ast_trans_pvt *pvt); /*!< cleanup private data, if needed * (often unnecessary). */ @@ -316,7 +320,9 @@ void ast_translator_free_path(struct ast_trans_pvt *tr); /*! * \brief translates one or more frames * Apply an input frame into the translator and receive zero or one output frames. Consume - * determines whether the original frame should be freed + * determines whether the original frame should be freed. In case the frame type is + * AST_FRAME_RTCP, the frame is not translated but passed to the translator codecs + * via the feedback callback, and a pointer to ast_null_frame is returned after that. * \param path tr translator structure to use for translation * \param f frame to translate * \param consume Whether or not to free the original frame diff --git a/main/channel.c b/main/channel.c index 00cfa31aa07..68c45a2609b 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1531,6 +1531,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame) case AST_FRAME_IAX: case AST_FRAME_CNG: case AST_FRAME_MODEM: + case AST_FRAME_RTCP: return 0; } return 0; @@ -2866,6 +2867,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay) case AST_FRAME_IMAGE: case AST_FRAME_HTML: case AST_FRAME_MODEM: + case AST_FRAME_RTCP: done = 1; break; case AST_FRAME_CONTROL: @@ -4348,6 +4350,14 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) */ ast_read_generator_actions(chan, f); break; + case AST_FRAME_RTCP: + /* Incoming RTCP feedback needs to get to the translator for + * outgoing media, which means we treat it as an ast_write */ + if (ast_channel_writetrans(chan)) { + ast_translate(ast_channel_writetrans(chan), f, 0); + } + ast_frfree(f); + f = &ast_null_frame; default: /* Just pass it on! */ break; diff --git a/main/frame.c b/main/frame.c index 0175c7226b4..71feacb61a8 100644 --- a/main/frame.c +++ b/main/frame.c @@ -533,6 +533,8 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch break; } break; + case AST_FRAME_RTCP: + ast_copy_string(subclass, "RTCP", slen); default: ast_copy_string(subclass, "Unknown Subclass", slen); break; @@ -584,6 +586,9 @@ void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len) case AST_FRAME_VIDEO: ast_copy_string(ftype, "Video", len); break; + case AST_FRAME_RTCP: + ast_copy_string(ftype, "RTCP", len); + break; default: snprintf(ftype, len, "Unknown Frametype '%u'", frame_type); break; @@ -621,6 +626,9 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix) if (f->frametype == AST_FRAME_VIDEO) { return; } + if (f->frametype == AST_FRAME_RTCP) { + return; + } ast_frame_type2str(f->frametype, ftype, sizeof(ftype)); ast_frame_subclass2str(f, subclass, sizeof(subclass), moreinfo, sizeof(moreinfo)); diff --git a/main/translate.c b/main/translate.c index fa606e71b87..168a72a4bd5 100644 --- a/main/translate.c +++ b/main/translate.c @@ -530,6 +530,17 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, long len; int seqno; + if (f->frametype == AST_FRAME_RTCP) { + /* Just pass the feedback to the right callback, if it exists. + * This "translation" does nothing so return a null frame. */ + struct ast_trans_pvt *tp; + for (tp = p; tp; tp = tp->next) { + if (tp->t->feedback) + tp->t->feedback(tp, f); + } + return &ast_null_frame; + } + has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); ts = f->ts; len = f->len; diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 58c217ecb48..91d09b9cf3b 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4320,6 +4320,29 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) rtcp_report, message_blob); ast_json_unref(message_blob); + + /* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report + * object as a its data */ + rtp->f.frametype = AST_FRAME_RTCP; + rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET; + memcpy(rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report)); + rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report); + if (rc > 0) { + /* There's always a single report block stored, here */ + struct ast_rtp_rtcp_report *rtcp_report2; + report_block = rtp->f.data.ptr + rtp->f.datalen + sizeof(struct ast_rtp_rtcp_report_block *); + memcpy(report_block, rtcp_report->report_block[report_counter-1], sizeof(struct ast_rtp_rtcp_report_block)); + rtcp_report2 = (struct ast_rtp_rtcp_report *)rtp->f.data.ptr; + rtcp_report2->report_block[report_counter-1] = report_block; + rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block); + } + rtp->f.offset = AST_FRIENDLY_OFFSET; + rtp->f.samples = 0; + rtp->f.mallocd = 0; + rtp->f.delivery.tv_sec = 0; + rtp->f.delivery.tv_usec = 0; + rtp->f.src = "RTP"; + f = &rtp->f; break; case RTCP_PT_FUR: /* Handle RTCP FIR as FUR */ From 23690c1b353845a2687b0f92deedd91e86612f13 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 23 Jan 2017 16:08:37 +0000 Subject: [PATCH 0983/1578] res_pjsip_endpoint_identifier_ip: Read settings before resolving. An option has been added, srv_lookups, which controls whether SRV lookups are performed on the provided match hosts or not. It was possible for this option to be applied after resolution had already happened. This change makes it so hosts are stored away, settings are read and applied, and then resolution is done. This ensures that no matter the ordering the srv_lookups option is in effect. ASTERISK-26735 Change-Id: I750378cb277be0140f8c5539450270afbfc43388 --- res/res_pjsip_endpoint_identifier_ip.c | 51 ++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index e095a96309a..63b254da803 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -66,6 +66,9 @@ ***/ +/*! \brief The number of buckets for storing hosts for resolution */ +#define HOSTS_BUCKETS 53 + /*! \brief Structure for an IP identification matching object */ struct ip_identify_match { /*! \brief Sorcery object details */ @@ -79,6 +82,8 @@ struct ip_identify_match { struct ast_ha *matches; /*! \brief Perform SRV resolution of hostnames */ unsigned int srv_lookups; + /*! \brief Hosts to be resolved after applying configuration */ + struct ao2_container *hosts; }; /*! \brief Destructor function for a matching object */ @@ -88,6 +93,7 @@ static void ip_identify_destroy(void *obj) ast_string_field_free_memory(identify); ast_free_ha(identify->matches); + ao2_cleanup(identify->hosts); } /*! \brief Allocator function for a matching object */ @@ -241,8 +247,7 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va while ((current_string = ast_strip(strsep(&input_string, ",")))) { char *mask = strrchr(current_string, '/'); - struct ast_sockaddr address; - int error, results = 0; + int error; if (ast_strlen_zero(current_string)) { continue; @@ -260,6 +265,42 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va continue; } + if (!identify->hosts) { + identify->hosts = ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, HOSTS_BUCKETS); + if (!identify->hosts) { + ast_log(LOG_ERROR, "Failed to create container to store hosts on ip endpoint identifier '%s'\n", + ast_sorcery_object_get_id(obj)); + return -1; + } + } + + error = ast_str_container_add(identify->hosts, current_string); + if (error) { + ast_log(LOG_ERROR, "Failed to store host '%s' for resolution on ip endpoint identifier '%s'\n", + current_string, ast_sorcery_object_get_id(obj)); + return -1; + } + } + + return 0; +} + +/*! \brief Apply handler for identify type */ +static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj) +{ + struct ip_identify_match *identify = obj; + char *current_string; + struct ao2_iterator i; + + if (!identify->hosts) { + return 0; + } + + i = ao2_iterator_init(identify->hosts, 0); + while ((current_string = ao2_iterator_next(&i))) { + struct ast_sockaddr address; + int results = 0; + /* If the provided string is not an IP address perform SRV resolution on it */ if (identify->srv_lookups && !ast_sockaddr_parse(&address, current_string, 0)) { results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string); @@ -286,10 +327,12 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va } } + ao2_ref(identify->hosts, -1); + identify->hosts = NULL; + return 0; } - static int match_to_str(const void *obj, const intptr_t *args, char **buf) { RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free); @@ -537,7 +580,7 @@ static int load_module(void) ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_endpoint_identifier_ip"); ast_sorcery_apply_default(ast_sip_get_sorcery(), "identify", "config", "pjsip.conf,criteria=type=identify"); - if (ast_sorcery_object_register(ast_sip_get_sorcery(), "identify", ip_identify_alloc, NULL, NULL)) { + if (ast_sorcery_object_register(ast_sip_get_sorcery(), "identify", ip_identify_alloc, NULL, ip_identify_apply)) { return AST_MODULE_LOAD_DECLINE; } From 96e7291cbd321e3fd37c09ade423db3f82769330 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 23 Jan 2017 08:10:50 -0700 Subject: [PATCH 0984/1578] pjproject_bundled: Fix setting max log level An earlier attempt to prevent pjsua from spitting out an extra 6795 lines of debug output every time the testsuite called it was also turning off the ability for asterisk to output debug info when it needed to. This patch reverts the earlier fix and instead adds a pjproject patch that sets the startup log level to 1 for pjsua pjsystest and the pjsua python binding. This is an asterisk-only patch that does not affect pjproject functionality and will not be submitted upstream. Change-Id: I347a8b58b2626f2906ccfc1d339e907627a0c9e8 --- third-party/pjproject/Makefile | 2 - .../0000-set_apps_initial_log_level.patch | 39 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 third-party/pjproject/patches/0000-set_apps_initial_log_level.patch diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 2398ec428da..bfd1c27fc52 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -187,13 +187,11 @@ source/pjsip-apps/lib/libasterisk_malloc_debug.a: source/pjsip-apps/lib/asterisk $(CMD_PREFIX) ar qs $@ $< >/dev/null 2>&1 $(apps): APP = $(filter pj%,$(subst -, ,$(notdir $@))) -$(apps): CFLAGS += -DPJ_LOG_MAX_LEVEL=2 $(apps): LDFLAGS += $(MALLOC_DEBUG_LDFLAGS) $(apps): $(MALLOC_DEBUG_LIBS) pjproject.symbols $(APP_THIRD_PARTY_LIB_FILES) $(ECHO_PREFIX) Compiling $(APP) $(CMD_PREFIX) +$(MAKE) -C source/pjsip-apps/build $(filter pj%,$(subst -, ,$(notdir $@))) $(REALLY_QUIET) -source/pjsip-apps/src/python/_pjsua.o: CFLAGS += -DPJ_LOG_MAX_LEVEL=2 source/pjsip-apps/src/python/_pjsua.o: source/pjsip-apps/src/python/_pjsua.c $(apps) $(ECHO_PREFIX) Compiling python bindings $(CMD_PREFIX) $(CC) -o $@ -c $< $(PYTHONDEV_INCLUDE) $(CFLAGS) $(PJ_CFLAGS) diff --git a/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch b/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch new file mode 100644 index 00000000000..fc0f570235e --- /dev/null +++ b/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch @@ -0,0 +1,39 @@ +diff --git a/pjsip-apps/src/pjsua/main.c b/pjsip-apps/src/pjsua/main.c +index 2baaf82..11831f2 100644 +--- a/pjsip-apps/src/pjsua/main.c ++++ b/pjsip-apps/src/pjsua/main.c +@@ -126,5 +126,7 @@ int main_func(int argc, char *argv[]) + + int main(int argc, char *argv[]) + { ++ pj_log_set_level(1); ++ + return pj_run_app(&main_func, argc, argv, 0); + } +diff --git a/pjsip-apps/src/pjsystest/main_console.c b/pjsip-apps/src/pjsystest/main_console.c +index 122cdc7..dc79eab 100644 +--- a/pjsip-apps/src/pjsystest/main_console.c ++++ b/pjsip-apps/src/pjsystest/main_console.c +@@ -133,6 +133,8 @@ void gui_sleep(unsigned sec) + + int main() + { ++ pj_log_set_level(1); ++ + if (systest_init() != PJ_SUCCESS) + return 1; + +diff --git a/pjsip-apps/src/python/_pjsua.c b/pjsip-apps/src/python/_pjsua.c +index fb80e23..c9b21d8 100644 +--- a/pjsip-apps/src/python/_pjsua.c ++++ b/pjsip-apps/src/python/_pjsua.c +@@ -4437,7 +4437,8 @@ init_pjsua(void) + PyObject* m = NULL; + #define ADD_CONSTANT(mod,name) PyModule_AddIntConstant(mod,#name,name) + +- ++ pj_log_set_level(1); ++ + PyEval_InitThreads(); + + if (PyType_Ready(&PyTyp_pjsua_callback) < 0) From f3f9175df09afb5304fa0a75c7162bae4b9e1e31 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Sat, 21 Jan 2017 07:41:53 +0200 Subject: [PATCH 0985/1578] test_voicemail_api: order of params to VERIFY macros Fix order of parameters in calls to VM_API_INT_VERIFY and VM_API_STRING_VERIFY ASTERISK-26739 #close Change-Id: I30dc6b36893aadad6012be3f16f93aa5720870d6 Note: status: builds. Not tested any further. --- tests/test_voicemail_api.c | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c index 9cadf2394ed..848c6bf1e3f 100644 --- a/tests/test_voicemail_api.c +++ b/tests/test_voicemail_api.c @@ -240,7 +240,7 @@ return AST_TEST_FAIL; \ } \ VM_API_SNAPSHOT_CREATE((mailbox), (context), (folder), 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); \ - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0); \ + VM_API_INT_VERIFY(0, test_mbox_snapshot->total_msg_num); \ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \ } while (0) @@ -1002,10 +1002,10 @@ AST_TEST_DEFINE(voicemail_api_nominal_move) test_vm_api_update_test_snapshots(test_mbox_snapshot); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); - VM_API_STRING_FIELD_VERIFY(test_snapshots[0]->folder_name, "Family"); - VM_API_STRING_FIELD_VERIFY(test_snapshots[1]->folder_name, "Family"); - VM_API_INT_VERIFY(test_snapshots[1]->msg_number, 0); - VM_API_INT_VERIFY(test_snapshots[0]->msg_number, 1); + VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[0]->folder_name); + VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[1]->folder_name); + VM_API_INT_VERIFY(0, test_snapshots[1]->msg_number); + VM_API_INT_VERIFY(1, test_snapshots[0]->msg_number); /* Move both of the 2345 messages to Family */ ast_test_status_update(test, "Test move of test_vm_api_2345 messages from Inbox to Family\n"); @@ -1016,8 +1016,8 @@ AST_TEST_DEFINE(voicemail_api_nominal_move) test_vm_api_update_test_snapshots(test_mbox_snapshot); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); - VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "Family"); - VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "Family"); + VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[2]->folder_name); + VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[3]->folder_name); ast_test_status_update(test, "Test move of test_vm_api_2345 message from Family to INBOX\n"); VM_API_MOVE_MESSAGE("test_vm_api_2345", "default", 2, "Family", multi_msg_ids, "INBOX"); @@ -1026,8 +1026,8 @@ AST_TEST_DEFINE(voicemail_api_nominal_move) test_vm_api_update_test_snapshots(test_mbox_snapshot); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); - VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "INBOX"); - VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "INBOX"); + VM_API_STRING_FIELD_VERIFY("INBOX", test_snapshots[2]->folder_name); + VM_API_STRING_FIELD_VERIFY("INBOX", test_snapshots[3]->folder_name); VM_API_TEST_CLEANUP; @@ -1248,12 +1248,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward) /* Make sure we didn't delete the message */ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1); + VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); /* We should now have a total of 3 messages in test_vm_api_2345 INBOX */ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 3); + VM_API_INT_VERIFY(3, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX with default context to test_vm_api_2345 INBOX\n"); @@ -1261,12 +1261,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward) /* Make sure we didn't delete the message */ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1); + VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); /* We should now have a total of 4 messages in test_vm_api_2345 INBOX */ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4); + VM_API_INT_VERIFY(4, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX with default context\n"); @@ -1274,12 +1274,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward) /* Make sure we didn't delete the message */ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1); + VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); /* We should now have a total of 5 messages in test_vm_api_2345 INBOX */ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 5); + VM_API_INT_VERIFY(5, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX, deleting original\n"); @@ -1287,12 +1287,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward) /* Make sure we deleted the message */ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0); + VM_API_INT_VERIFY(0, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); /* We should now have a total of 6 messages in test_vm_api_2345 INBOX */ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6); + VM_API_INT_VERIFY(6, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 INBOX"); @@ -1300,24 +1300,24 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward) /* Make sure we didn't delete the messages */ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6); + VM_API_INT_VERIFY(6, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); /* We should now have a total of 2 messages in test_vm_api_1234 INBOX */ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2); + VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 Family, deleting original\n"); VM_API_FORWARD_MESSAGE("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "Family", 2, multi_msg_ids, 1); /* Make sure we deleted the messages */ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4); + VM_API_INT_VERIFY(4, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); /* We should now have a total of 2 messages in test_vm_api_1234 Family */ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2); + VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); VM_API_TEST_CLEANUP; @@ -1447,20 +1447,20 @@ AST_TEST_DEFINE(voicemail_api_nominal_msg_playback) ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function\n"); VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", "default", "INBOX", message_id_2345[0], &message_playback_callback_fn); - VM_API_INT_VERIFY(global_entered_playback_callback, 1); + VM_API_INT_VERIFY(1, global_entered_playback_callback); global_entered_playback_callback = 0; ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function with default context\n"); VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", NULL, "INBOX", message_id_2345[1], &message_playback_callback_fn); - VM_API_INT_VERIFY(global_entered_playback_callback, 1); + VM_API_INT_VERIFY(1, global_entered_playback_callback); global_entered_playback_callback = 0; VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2); + VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); - VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2); + VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num); test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); ast_hangup(test_channel); From 66916067236dc2f5cf54fadee33a5203d8716148 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 19 Jan 2017 08:05:36 -0700 Subject: [PATCH 0986/1578] ari: Implement 'debug all' and request/response logging The 'ari set debug' command has been enhanced to accept 'all' as an application name. This allows dumping of all apps even if an app hasn't registered yet. To accomplish this, a new global_debug global variable was added to res/stasis/app.c and new APIs were added to set and query the value. 'ari set debug' now displays requests and responses as well as events. This required refactoring the existing debug code. * The implementation for 'ari set debug' was moved from stasis/cli.{c,h} to ari/cli.{c,h}, and stasis/cli.{c,h} were deleted. * In order to print the body of incoming requests even if a request failed, the consumption of the body was moved from the ari stubs to ast_ari_callback in res_ari.c and the moustache templates were then regenerated. The body is now passed to ast_ari_invoke and then on to the handlers. This results in code savings since that template was inserted multiple times into all the stubs. An additional change was made to the ao2_str_container implementation to add partial key searching and a sort function. The existing cli code assumed it was already there when it wasn't so the tab completion was never working. Change-Id: Ief936f747ce47f1fb14035fbe61152cf766406bf (cherry picked from commit 1d890874f39a5a81b20da44358143ed9b54ab0fe) --- CHANGES | 8 + include/asterisk/ari.h | 14 +- include/asterisk/stasis_app.h | 50 +++ main/strings.c | 21 +- res/ari/ari_websockets.c | 14 +- res/ari/cli.c | 175 +++++++++ res/ari/resource_events.c | 10 + res/res_ari.c | 77 +++- res/res_ari_applications.c | 42 +-- res/res_ari_asterisk.c | 120 +----- res/res_ari_bridges.c | 162 +------- res/res_ari_channels.c | 354 ++---------------- res/res_ari_device_states.c | 27 +- res/res_ari_endpoints.c | 45 +-- res/res_ari_events.c | 18 +- res/res_ari_mailboxes.c | 27 +- res/res_ari_playbacks.c | 24 +- res/res_ari_recordings.c | 51 +-- res/res_ari_sounds.c | 21 +- res/res_stasis.c | 23 +- res/stasis/app.c | 73 +++- res/stasis/app.h | 27 -- res/stasis/cli.c | 214 ----------- res/stasis/cli.h | 43 --- res/stasis/stasis_bridge.c | 4 +- rest-api-templates/param_parsing.mustache | 15 - .../res_ari_resource.c.mustache | 3 +- tests/test_ari.c | 22 +- 28 files changed, 527 insertions(+), 1157 deletions(-) delete mode 100644 res/stasis/cli.c delete mode 100644 res/stasis/cli.h diff --git a/CHANGES b/CHANGES index 5921e9b325a..1671d3635d8 100644 --- a/CHANGES +++ b/CHANGES @@ -121,6 +121,14 @@ res_pjsip_endpoint_identifier_ip source IP addresses for requests. This is configurable using the "srv_lookups" option on the identify and defaults to "yes". +ARI +------------------ + * The 'ari set debug' command has been enhanced to accept 'all' as an + application name. This allows dumping of all apps even if an app + hasn't registered yet. + + * 'ari set debug' now displays requests and responses as well as events. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------ ------------------------------------------------------------------------------ diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h index 4019e94e3b7..865b4b00cc5 100644 --- a/include/asterisk/ari.h +++ b/include/asterisk/ari.h @@ -59,7 +59,8 @@ struct ast_ari_response; typedef void (*stasis_rest_callback)( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response); + struct ast_variable *headers, struct ast_json *body, + struct ast_ari_response *response); /*! * \brief Handler for a single RESTful path segment. @@ -136,7 +137,7 @@ int ast_ari_remove_handler(struct stasis_rest_handlers *handler); void ast_ari_invoke(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers, - struct ast_ari_response *response); + struct ast_json *body, struct ast_ari_response *response); /*! * \internal @@ -200,6 +201,15 @@ int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session, const char *ast_ari_websocket_session_id( const struct ast_ari_websocket_session *session); +/*! + * \brief Get the remote address from an ARI WebSocket. + * + * \param session Session to write to. + * \return ast_sockaddr (does not have to be freed) + */ +struct ast_sockaddr *ast_ari_websocket_session_get_remote_addr( + struct ast_ari_websocket_session *session); + /*! * \brief The stock message to return when out of memory. * diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index 137cbb945c9..e131833a979 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -903,6 +903,56 @@ int stasis_app_control_dial(struct stasis_app_control *control, * allocated during the time that res_stasis was loaded. */ void stasis_app_control_shutdown(void); + +/*! + * \brief Enable/disable request/response and event logging on an application + * + * \param app The app to debug + * \param debug If non-zero, enable debugging. If zero, disable. + */ +void stasis_app_set_debug(struct stasis_app *app, int debug); + +/*! + * \brief Enable/disable request/response and event logging on an application + * + * \param app_name The app name to debug + * \param debug If non-zero, enable debugging. If zero, disable. + */ +void stasis_app_set_debug_by_name(const char *app_name, int debug); + +/*! + * \brief Get debug status of an application + * + * \param app The app to check + * \return The debug flag for the app || the global debug flag + */ +int stasis_app_get_debug(struct stasis_app *app); + +/*! + * \brief Get debug status of an application + * + * \param app_name The app_name to check + * \return The debug flag for the app || the global debug flag + */ +int stasis_app_get_debug_by_name(const char *app_name); + +/*! + * \brief Enable/disable request/response and event logging on all applications + * + * \param debug If non-zero, enable debugging. If zero, disable. + */ +void stasis_app_set_global_debug(int debug); + +struct ast_cli_args; + +/*! + * \brief Dump properties of a \c stasis_app to the CLI + * + * \param app The application + * \param a The CLI arguments + */ +void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a); + /*! @} */ #endif /* _ASTERISK_STASIS_APP_H */ diff --git a/main/strings.c b/main/strings.c index b8f1ccbfdd9..d29da67bc07 100644 --- a/main/strings.c +++ b/main/strings.c @@ -184,15 +184,32 @@ static int str_hash(const void *obj, const int flags) return ast_str_hash(obj); } +static int str_sort(const void *lhs, const void *rhs, int flags) +{ + if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) { + return strncmp(lhs, rhs, strlen(rhs)); + } else { + return strcmp(lhs, rhs); + } +} + static int str_cmp(void *lhs, void *rhs, int flags) { - return strcmp(lhs, rhs) ? 0 : CMP_MATCH; + int cmp = 0; + + if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) { + cmp = strncmp(lhs, rhs, strlen(rhs)); + } else { + cmp = strcmp(lhs, rhs); + } + + return cmp ? 0 : CMP_MATCH; } //struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets) struct ao2_container *ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets) { - return ao2_container_alloc_options(opts, buckets, str_hash, str_cmp); + return ao2_container_alloc_hash(opts, 0, buckets, str_hash, str_sort, str_cmp); } int ast_str_container_add(struct ao2_container *str_container, const char *add) diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c index f1e63d39866..4f8d6dffd17 100644 --- a/res/ari/ari_websockets.c +++ b/res/ari/ari_websockets.c @@ -21,6 +21,7 @@ #include "asterisk/ari.h" #include "asterisk/astobj2.h" #include "asterisk/http_websocket.h" +#include "asterisk/stasis_app.h" #include "internal.h" /*! \file @@ -137,6 +138,7 @@ struct ast_json *ast_ari_websocket_session_read( ast_log(LOG_WARNING, "WebSocket input failed to parse\n"); } + break; default: /* Ignore all other message types */ @@ -172,16 +174,20 @@ int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session, return -1; } -#ifdef AST_DEVMODE - ast_debug(3, "Examining ARI event (length %u): \n%s\n", (unsigned int) strlen(str), str); -#endif if (ast_websocket_write_string(session->ws_session, str)) { - ast_log(LOG_NOTICE, "Problem occurred during websocket write, websocket closed\n"); + ast_log(LOG_NOTICE, "Problem occurred during websocket write to %s, websocket closed\n", + ast_sockaddr_stringify(ast_ari_websocket_session_get_remote_addr(session))); return -1; } return 0; } +struct ast_sockaddr *ast_ari_websocket_session_get_remote_addr( + struct ast_ari_websocket_session *session) +{ + return ast_websocket_remote_address(session->ws_session); +} + void ari_handle_websocket(struct ast_websocket_server *ws_server, struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *get_params, diff --git a/res/ari/cli.c b/res/ari/cli.c index 9d156f21ee7..9d0eb3099bc 100644 --- a/res/ari/cli.c +++ b/res/ari/cli.c @@ -26,6 +26,7 @@ #include "asterisk/astobj2.h" #include "asterisk/cli.h" +#include "asterisk/stasis_app.h" #include "internal.h" static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) @@ -249,11 +250,185 @@ static char *ari_mkpasswd(struct ast_cli_entry *e, int cmd, struct ast_cli_args return CLI_SUCCESS; } +static char *ari_show_apps(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ao2_container *apps; + struct ao2_iterator it_apps; + char *app; + + switch (cmd) { + case CLI_INIT: + e->command = "ari show apps"; + e->usage = + "Usage: ari show apps\n" + " Lists all registered applications.\n" + ; + return NULL; + case CLI_GENERATE: + return NULL; + default: + break; + } + + if (a->argc != 3) { + return CLI_SHOWUSAGE; + } + + apps = stasis_app_get_all(); + if (!apps) { + ast_cli(a->fd, "Unable to retrieve registered applications!\n"); + return CLI_FAILURE; + } + + ast_cli(a->fd, "Application Name \n"); + ast_cli(a->fd, "=========================\n"); + it_apps = ao2_iterator_init(apps, 0); + while ((app = ao2_iterator_next(&it_apps))) { + ast_cli(a->fd, "%-25.25s\n", app); + ao2_ref(app, -1); + } + + ao2_iterator_destroy(&it_apps); + ao2_ref(apps, -1); + + return CLI_SUCCESS; +} + +struct app_complete { + /*! Nth app to search for */ + int state; + /*! Which app currently on */ + int which; +}; + +static int complete_ari_app_search(void *obj, void *arg, void *data, int flags) +{ + struct app_complete *search = data; + + if (++search->which > search->state) { + return CMP_MATCH; + } + return 0; +} + +static char *complete_ari_app(struct ast_cli_args *a, int include_all) +{ + RAII_VAR(struct ao2_container *, apps, stasis_app_get_all(), ao2_cleanup); + RAII_VAR(char *, app, NULL, ao2_cleanup); + + struct app_complete search = { + .state = a->n, + }; + + if (a->pos != 3) { + return NULL; + } + + if (!apps) { + ast_cli(a->fd, "Error getting ARI applications\n"); + return CLI_FAILURE; + } + + if (include_all && ast_strlen_zero(a->word)) { + ast_str_container_add(apps, " all"); + } + + app = ao2_callback_data(apps, + ast_strlen_zero(a->word) ? 0 : OBJ_SEARCH_PARTIAL_KEY, + complete_ari_app_search, (char*)a->word, &search); + + return app ? ast_strdup(app) : NULL; +} + +static char *ari_show_app(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + void *app; + + switch (cmd) { + case CLI_INIT: + e->command = "ari show app"; + e->usage = + "Usage: ari show app \n" + " Provide detailed information about a registered application.\n" + ; + return NULL; + case CLI_GENERATE: + return complete_ari_app(a, 0); + default: + break; + } + + if (a->argc != 4) { + return CLI_SHOWUSAGE; + } + + app = stasis_app_get_by_name(a->argv[3]); + if (!app) { + return CLI_FAILURE; + } + + stasis_app_to_cli(app, a); + + ao2_ref(app, -1); + + return CLI_SUCCESS; +} + +static char *ari_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + void *app; + int debug; + + switch (cmd) { + case CLI_INIT: + e->command = "ari set debug"; + e->usage = + "Usage: ari set debug \n" + " Enable or disable debugging on a specific application.\n" + ; + return NULL; + case CLI_GENERATE: + return complete_ari_app(a, 1); + default: + break; + } + + if (a->argc != 5) { + return CLI_SHOWUSAGE; + } + + debug = !strcmp(a->argv[4], "on"); + + if (!strcmp(a->argv[3], "all")) { + stasis_app_set_global_debug(debug); + ast_cli(a->fd, "Debugging on all applications %s\n", + debug ? "enabled" : "disabled"); + return CLI_SUCCESS; + } + + app = stasis_app_get_by_name(a->argv[3]); + if (!app) { + return CLI_FAILURE; + } + + stasis_app_set_debug(app, debug); + ast_cli(a->fd, "Debugging on '%s' %s\n", + stasis_app_name(app), + debug ? "enabled" : "disabled"); + + ao2_ref(app, -1); + + return CLI_SUCCESS; +} + static struct ast_cli_entry cli_ari[] = { AST_CLI_DEFINE(ari_show, "Show ARI settings"), AST_CLI_DEFINE(ari_show_users, "List ARI users"), AST_CLI_DEFINE(ari_show_user, "List single ARI user"), AST_CLI_DEFINE(ari_mkpasswd, "Encrypts a password"), + AST_CLI_DEFINE(ari_show_apps, "List registered ARI applications"), + AST_CLI_DEFINE(ari_show_app, "Display details of a registered ARI application"), + AST_CLI_DEFINE(ari_set_debug, "Enable/disable debugging of an ARI application"), }; int ast_ari_cli_register(void) { diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c index 597f4dfeb6f..ed936f73257 100644 --- a/res/ari/resource_events.c +++ b/res/ari/resource_events.c @@ -27,6 +27,7 @@ #include "resource_events.h" #include "asterisk/astobj2.h" +#include "asterisk/http_websocket.h" #include "asterisk/stasis_app.h" #include "asterisk/vector.h" @@ -108,6 +109,15 @@ static void stasis_app_message_handler( msg_type, msg_application); } else { + if (stasis_app_get_debug_by_name(app_name)) { + char *str = ast_json_dump_string_format(message, ast_ari_json_format()); + + ast_verbose("<--- Sending ARI event to %s --->\n%s\n", + ast_sockaddr_stringify(ast_ari_websocket_session_get_remote_addr(session->ws_session)), + str); + ast_json_free(str); + } + /* We are ready to publish the message */ ast_ari_websocket_session_write(session->ws_session, message); } diff --git a/res/res_ari.c b/res/res_ari.c index e362a581169..549d7835365 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -148,6 +148,7 @@ #include "asterisk/astobj2.h" #include "asterisk/module.h" #include "asterisk/paths.h" +#include "asterisk/stasis_app.h" #include #include @@ -491,7 +492,7 @@ static void handle_options(struct stasis_rest_handlers *handler, void ast_ari_invoke(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers, - struct ast_ari_response *response) + struct ast_json *body, struct ast_ari_response *response) { RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup); struct stasis_rest_handlers *handler; @@ -506,8 +507,10 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser, while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) { struct stasis_rest_handlers *found_handler = NULL; int i; + ast_uri_decode(path_segment, ast_uri_http_legacy); ast_debug(3, "Finding handler for %s\n", path_segment); + for (i = 0; found_handler == NULL && i < handler->num_children; ++i) { struct stasis_rest_handlers *child = handler->children[i]; @@ -569,7 +572,7 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser, return; } - callback(ser, get_params, path_vars, headers, response); + callback(ser, get_params, path_vars, headers, body, response); if (response->message == NULL && response->response_code == 0) { /* Really should not happen */ ast_log(LOG_ERROR, "ARI %s %s not implemented\n", @@ -879,6 +882,10 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup); struct ast_ari_response response = { .fd = -1, 0 }; RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy); + struct ast_variable *var; + const char *app_name = NULL; + RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_free); + int debug_app = 0; if (!response_body) { ast_http_request_close_on_completion(ser); @@ -926,6 +933,25 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, "Bad Request", "Error parsing request body"); goto request_failed; } + + /* Look for a JSON request entity only if there were no post_vars. + * If there were post_vars, then the request body would already have + * been consumed and can not be read again. + */ + body = ast_http_get_json(ser, headers); + if (!body) { + switch (errno) { + case EFBIG: + ast_ari_response_error(&response, 413, "Request Entity Too Large", "Request body too large"); + goto request_failed; + case ENOMEM: + ast_ari_response_error(&response, 500, "Internal Server Error", "Error processing request"); + goto request_failed; + case EIO: + ast_ari_response_error(&response, 400, "Bad Request", "Error parsing request body"); + goto request_failed; + } + } } if (get_params == NULL) { get_params = post_vars; @@ -942,6 +968,41 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, get_params = post_vars; } + /* At this point, get_params will contain post_vars (if any) */ + app_name = ast_variable_find_in_list(get_params, "app"); + if (!app_name) { + struct ast_json *app = ast_json_object_get(body, "app"); + + app_name = (app ? ast_json_string_get(app) : NULL); + } + + /* stasis_app_get_debug_by_name returns an "||" of the app's debug flag + * and the global debug flag. + */ + debug_app = stasis_app_get_debug_by_name(app_name); + if (debug_app) { + struct ast_str *buf = ast_str_create(512); + char *str = ast_json_dump_string_format(body, ast_ari_json_format()); + + if (!buf) { + ast_http_request_close_on_completion(ser); + ast_http_error(ser, 500, "Server Error", "Out of memory"); + goto request_failed; + } + + ast_str_append(&buf, 0, "<--- ARI request received from: %s --->\n", + ast_sockaddr_stringify(&ser->remote_address)); + for (var = headers; var; var = var->next) { + ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value); + } + for (var = get_params; var; var = var->next) { + ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value); + } + ast_verbose("%sbody:\n%s\n\n", ast_str_buffer(buf), str); + ast_json_free(str); + ast_free(buf); + } + user = authenticate_user(get_params, headers); if (response.response_code > 0) { /* POST parameter processing error. Do nothing. */ @@ -980,7 +1041,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, } } else { /* Other RESTful resources */ - ast_ari_invoke(ser, uri, method, get_params, headers, + ast_ari_invoke(ser, uri, method, get_params, headers, body, &response); } @@ -992,6 +1053,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, } request_failed: + /* If you explicitly want to have no content, set message to * ast_json_null(). */ @@ -1014,8 +1076,13 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, } } - ast_debug(3, "Examining ARI response:\n%d %s\n%s\n%s\n", response.response_code, - response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body)); + if (debug_app) { + ast_verbose("<--- Sending ARI response to %s --->\n%d %s\n%s%s\n\n", + ast_sockaddr_stringify(&ser->remote_address), response.response_code, + response.response_text, ast_str_buffer(response.headers), + ast_str_buffer(response_body)); + } + ast_http_send(ser, method, response.response_code, response.response_text, response.headers, response_body, response.fd != -1 ? response.fd : 0, 0); diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c index 006d30ca84f..951ee85b7c5 100644 --- a/res/res_ari_applications.c +++ b/res/res_ari_applications.c @@ -60,10 +60,9 @@ static void ast_ari_applications_list_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_applications_list_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -111,11 +110,10 @@ fin: __attribute__((unused)) static void ast_ari_applications_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_applications_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -208,11 +206,10 @@ int ast_ari_applications_subscribe_parse_body( static void ast_ari_applications_subscribe_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_applications_subscribe_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -270,21 +267,6 @@ static void ast_ari_applications_subscribe_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_applications_subscribe_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -374,11 +356,10 @@ int ast_ari_applications_unsubscribe_parse_body( static void ast_ari_applications_unsubscribe_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_applications_unsubscribe_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -436,21 +417,6 @@ static void ast_ari_applications_unsubscribe_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_applications_unsubscribe_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index 5dbf3415c29..1dbd850bb4c 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -60,11 +60,10 @@ static void ast_ari_asterisk_get_object_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_get_object_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -133,11 +132,10 @@ int ast_ari_asterisk_update_object_parse_body( static void ast_ari_asterisk_update_object_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_update_object_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -155,21 +153,6 @@ static void ast_ari_asterisk_update_object_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } args.fields = body; ast_ari_asterisk_update_object(headers, &args, response); #if defined(AST_DEVMODE) @@ -216,11 +199,10 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_delete_object_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_delete_object_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -320,11 +302,10 @@ int ast_ari_asterisk_get_info_parse_body( static void ast_ari_asterisk_get_info_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_get_info_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -376,21 +357,6 @@ static void ast_ari_asterisk_get_info_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_asterisk_get_info_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -439,10 +405,9 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_list_modules_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_list_modules_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -490,11 +455,10 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_get_module_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_get_module_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -550,11 +514,10 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_load_module_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_load_module_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -609,11 +572,10 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_unload_module_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_unload_module_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -669,11 +631,10 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_reload_module_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_reload_module_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -729,10 +690,9 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_list_log_channels_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_list_log_channels_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -793,11 +753,10 @@ int ast_ari_asterisk_add_log_parse_body( static void ast_ari_asterisk_add_log_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_add_log_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -815,21 +774,6 @@ static void ast_ari_asterisk_add_log_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_asterisk_add_log_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -878,11 +822,10 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_delete_log_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_delete_log_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -937,11 +880,10 @@ fin: __attribute__((unused)) static void ast_ari_asterisk_rotate_log_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_rotate_log_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1009,11 +951,10 @@ int ast_ari_asterisk_get_global_var_parse_body( static void ast_ari_asterisk_get_global_var_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_get_global_var_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1025,21 +966,6 @@ static void ast_ari_asterisk_get_global_var_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -1104,11 +1030,10 @@ int ast_ari_asterisk_set_global_var_parse_body( static void ast_ari_asterisk_set_global_var_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_asterisk_set_global_var_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1123,21 +1048,6 @@ static void ast_ari_asterisk_set_global_var_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 0b370c299f6..e61865e311a 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -60,10 +60,9 @@ static void ast_ari_bridges_list_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_list_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -132,11 +131,10 @@ int ast_ari_bridges_create_parse_body( static void ast_ari_bridges_create_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_create_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -154,21 +152,6 @@ static void ast_ari_bridges_create_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_create_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -232,11 +215,10 @@ int ast_ari_bridges_create_with_id_parse_body( static void ast_ari_bridges_create_with_id_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_create_with_id_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -257,21 +239,6 @@ static void ast_ari_bridges_create_with_id_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_create_with_id_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -318,11 +285,10 @@ fin: __attribute__((unused)) static void ast_ari_bridges_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -377,11 +343,10 @@ fin: __attribute__((unused)) static void ast_ari_bridges_destroy_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_destroy_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -478,11 +443,10 @@ int ast_ari_bridges_add_channel_parse_body( static void ast_ari_bridges_add_channel_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_add_channel_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -543,21 +507,6 @@ static void ast_ari_bridges_add_channel_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_add_channel_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -648,11 +597,10 @@ int ast_ari_bridges_remove_channel_parse_body( static void ast_ari_bridges_remove_channel_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_remove_channel_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -710,21 +658,6 @@ static void ast_ari_bridges_remove_channel_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_remove_channel_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -777,11 +710,10 @@ fin: __attribute__((unused)) static void ast_ari_bridges_set_video_source_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_set_video_source_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -841,11 +773,10 @@ fin: __attribute__((unused)) static void ast_ari_bridges_clear_video_source_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_clear_video_source_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -913,11 +844,10 @@ int ast_ari_bridges_start_moh_parse_body( static void ast_ari_bridges_start_moh_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_start_moh_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -935,21 +865,6 @@ static void ast_ari_bridges_start_moh_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_start_moh_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -998,11 +913,10 @@ fin: __attribute__((unused)) static void ast_ari_bridges_stop_moh_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_stop_moh_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1112,11 +1026,10 @@ int ast_ari_bridges_play_parse_body( static void ast_ari_bridges_play_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_play_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1186,21 +1099,6 @@ static void ast_ari_bridges_play_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_play_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -1301,11 +1199,10 @@ int ast_ari_bridges_play_with_id_parse_body( static void ast_ari_bridges_play_with_id_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_play_with_id_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1375,21 +1272,6 @@ static void ast_ari_bridges_play_with_id_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_play_with_id_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -1477,11 +1359,10 @@ int ast_ari_bridges_record_parse_body( static void ast_ari_bridges_record_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_bridges_record_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1517,21 +1398,6 @@ static void ast_ari_bridges_record_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_bridges_record_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 252bc4fff2b..739eb0135bb 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -60,10 +60,9 @@ static void ast_ari_channels_list_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_list_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -172,11 +171,10 @@ int ast_ari_channels_originate_parse_body( static void ast_ari_channels_originate_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_originate_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -224,21 +222,6 @@ static void ast_ari_channels_originate_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } args.variables = body; ast_ari_channels_originate(headers, &args, response); #if defined(AST_DEVMODE) @@ -321,11 +304,10 @@ int ast_ari_channels_create_parse_body( static void ast_ari_channels_create_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_create_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -355,21 +337,6 @@ static void ast_ari_channels_create_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_create_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -417,11 +384,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -533,11 +499,10 @@ int ast_ari_channels_originate_with_id_parse_body( static void ast_ari_channels_originate_with_id_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_originate_with_id_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -588,21 +553,6 @@ static void ast_ari_channels_originate_with_id_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } args.variables = body; ast_ari_channels_originate_with_id(headers, &args, response); #if defined(AST_DEVMODE) @@ -661,11 +611,10 @@ int ast_ari_channels_hangup_parse_body( static void ast_ari_channels_hangup_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_hangup_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -683,21 +632,6 @@ static void ast_ari_channels_hangup_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_hangup_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -771,11 +705,10 @@ int ast_ari_channels_continue_in_dialplan_parse_body( static void ast_ari_channels_continue_in_dialplan_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_continue_in_dialplan_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -802,21 +735,6 @@ static void ast_ari_channels_continue_in_dialplan_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_continue_in_dialplan_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -879,11 +797,10 @@ int ast_ari_channels_redirect_parse_body( static void ast_ari_channels_redirect_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_redirect_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -901,21 +818,6 @@ static void ast_ari_channels_redirect_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_redirect_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -967,11 +869,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_answer_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_answer_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1028,11 +929,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_ring_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_ring_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1089,11 +989,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_ring_stop_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_ring_stop_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1179,11 +1078,10 @@ int ast_ari_channels_send_dtmf_parse_body( static void ast_ari_channels_send_dtmf_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_send_dtmf_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1213,21 +1111,6 @@ static void ast_ari_channels_send_dtmf_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_send_dtmf_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -1291,11 +1174,10 @@ int ast_ari_channels_mute_parse_body( static void ast_ari_channels_mute_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_mute_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1313,21 +1195,6 @@ static void ast_ari_channels_mute_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_mute_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -1390,11 +1257,10 @@ int ast_ari_channels_unmute_parse_body( static void ast_ari_channels_unmute_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_unmute_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1412,21 +1278,6 @@ static void ast_ari_channels_unmute_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_unmute_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -1476,11 +1327,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_hold_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_hold_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1537,11 +1387,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_unhold_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_unhold_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1611,11 +1460,10 @@ int ast_ari_channels_start_moh_parse_body( static void ast_ari_channels_start_moh_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_start_moh_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1633,21 +1481,6 @@ static void ast_ari_channels_start_moh_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_start_moh_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -1697,11 +1530,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_stop_moh_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_stop_moh_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1758,11 +1590,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_start_silence_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_start_silence_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1819,11 +1650,10 @@ fin: __attribute__((unused)) static void ast_ari_channels_stop_silence_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_stop_silence_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -1934,11 +1764,10 @@ int ast_ari_channels_play_parse_body( static void ast_ari_channels_play_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_play_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2008,21 +1837,6 @@ static void ast_ari_channels_play_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_play_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -2124,11 +1938,10 @@ int ast_ari_channels_play_with_id_parse_body( static void ast_ari_channels_play_with_id_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_play_with_id_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2198,21 +2011,6 @@ static void ast_ari_channels_play_with_id_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_play_with_id_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -2301,11 +2099,10 @@ int ast_ari_channels_record_parse_body( static void ast_ari_channels_record_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_record_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2341,21 +2138,6 @@ static void ast_ari_channels_record_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_record_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -2419,11 +2201,10 @@ int ast_ari_channels_get_channel_var_parse_body( static void ast_ari_channels_get_channel_var_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_get_channel_var_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2441,21 +2222,6 @@ static void ast_ari_channels_get_channel_var_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_get_channel_var_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -2522,11 +2288,10 @@ int ast_ari_channels_set_channel_var_parse_body( static void ast_ari_channels_set_channel_var_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_set_channel_var_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2547,21 +2312,6 @@ static void ast_ari_channels_set_channel_var_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_set_channel_var_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -2640,11 +2390,10 @@ int ast_ari_channels_snoop_channel_parse_body( static void ast_ari_channels_snoop_channel_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_snoop_channel_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2674,21 +2423,6 @@ static void ast_ari_channels_snoop_channel_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_snoop_channel_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -2762,11 +2496,10 @@ int ast_ari_channels_snoop_channel_with_id_parse_body( static void ast_ari_channels_snoop_channel_with_id_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_snoop_channel_with_id_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2796,21 +2529,6 @@ static void ast_ari_channels_snoop_channel_with_id_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_snoop_channel_with_id_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -2876,11 +2594,10 @@ int ast_ari_channels_dial_parse_body( static void ast_ari_channels_dial_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_channels_dial_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -2901,21 +2618,6 @@ static void ast_ari_channels_dial_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_channels_dial_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c index 39e678fc43d..b2aea525e74 100644 --- a/res/res_ari_device_states.c +++ b/res/res_ari_device_states.c @@ -60,10 +60,9 @@ static void ast_ari_device_states_list_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_device_states_list_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -111,11 +110,10 @@ fin: __attribute__((unused)) static void ast_ari_device_states_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_device_states_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -182,11 +180,10 @@ int ast_ari_device_states_update_parse_body( static void ast_ari_device_states_update_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_device_states_update_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -204,21 +201,6 @@ static void ast_ari_device_states_update_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_device_states_update_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -267,11 +249,10 @@ fin: __attribute__((unused)) static void ast_ari_device_states_delete_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_device_states_delete_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index 5307cd1de3d..944146fcb53 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -60,10 +60,9 @@ static void ast_ari_endpoints_list_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_endpoints_list_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -132,11 +131,10 @@ int ast_ari_endpoints_send_message_parse_body( static void ast_ari_endpoints_send_message_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_endpoints_send_message_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -154,21 +152,6 @@ static void ast_ari_endpoints_send_message_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } args.variables = body; ast_ari_endpoints_send_message(headers, &args, response); #if defined(AST_DEVMODE) @@ -214,11 +197,10 @@ fin: __attribute__((unused)) static void ast_ari_endpoints_list_by_tech_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_endpoints_list_by_tech_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -273,11 +255,10 @@ fin: __attribute__((unused)) static void ast_ari_endpoints_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_endpoints_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -353,11 +334,10 @@ int ast_ari_endpoints_send_message_to_endpoint_parse_body( static void ast_ari_endpoints_send_message_to_endpoint_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_endpoints_send_message_to_endpoint_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -381,21 +361,6 @@ static void ast_ari_endpoints_send_message_to_endpoint_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } args.variables = body; ast_ari_endpoints_send_message_to_endpoint(headers, &args, response); #if defined(AST_DEVMODE) diff --git a/res/res_ari_events.c b/res/res_ari_events.c index 36c9b06d8ee..8ccb8870c8c 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -287,11 +287,10 @@ int ast_ari_events_user_event_parse_body( static void ast_ari_events_user_event_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_events_user_event_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -352,21 +351,6 @@ static void ast_ari_events_user_event_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } args.variables = body; ast_ari_events_user_event(headers, &args, response); #if defined(AST_DEVMODE) diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c index 4d418fe5320..2eac609872a 100644 --- a/res/res_ari_mailboxes.c +++ b/res/res_ari_mailboxes.c @@ -60,10 +60,9 @@ static void ast_ari_mailboxes_list_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_mailboxes_list_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -111,11 +110,10 @@ fin: __attribute__((unused)) static void ast_ari_mailboxes_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_mailboxes_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -187,11 +185,10 @@ int ast_ari_mailboxes_update_parse_body( static void ast_ari_mailboxes_update_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_mailboxes_update_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -212,21 +209,6 @@ static void ast_ari_mailboxes_update_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_mailboxes_update_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -274,11 +256,10 @@ fin: __attribute__((unused)) static void ast_ari_mailboxes_delete_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_mailboxes_delete_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c index 9678830cead..8267a91b5a2 100644 --- a/res/res_ari_playbacks.c +++ b/res/res_ari_playbacks.c @@ -60,11 +60,10 @@ static void ast_ari_playbacks_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_playbacks_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -119,11 +118,10 @@ fin: __attribute__((unused)) static void ast_ari_playbacks_stop_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_playbacks_stop_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -191,11 +189,10 @@ int ast_ari_playbacks_control_parse_body( static void ast_ari_playbacks_control_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_playbacks_control_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -213,21 +210,6 @@ static void ast_ari_playbacks_control_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_playbacks_control_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index a43bbdd930a..e82605c7bc7 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -60,10 +60,9 @@ static void ast_ari_recordings_list_stored_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_list_stored_args args = {}; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -111,11 +110,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_get_stored_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_get_stored_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -170,11 +168,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_delete_stored_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_delete_stored_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -229,11 +226,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_get_stored_file_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_get_stored_file_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -302,11 +298,10 @@ int ast_ari_recordings_copy_stored_parse_body( static void ast_ari_recordings_copy_stored_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_copy_stored_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -324,21 +319,6 @@ static void ast_ari_recordings_copy_stored_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_recordings_copy_stored_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -387,11 +367,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_get_live_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_get_live_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -446,11 +425,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_cancel_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_cancel_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -505,11 +483,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_stop_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_stop_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -564,11 +541,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_pause_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_pause_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -624,11 +600,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_unpause_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_unpause_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -684,11 +659,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_mute_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_mute_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -744,11 +718,10 @@ fin: __attribute__((unused)) static void ast_ari_recordings_unmute_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_recordings_unmute_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index eb4bbb3f78b..fe0692f1668 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -77,11 +77,10 @@ int ast_ari_sounds_list_parse_body( static void ast_ari_sounds_list_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_sounds_list_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; @@ -96,21 +95,6 @@ static void ast_ari_sounds_list_cb( } else {} } - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } if (ast_ari_sounds_list_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; @@ -157,11 +141,10 @@ fin: __attribute__((unused)) static void ast_ari_sounds_get_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_sounds_get_args args = {}; struct ast_variable *i; - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/res/res_stasis.c b/res/res_stasis.c index 24c2b659801..196720984ce 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -65,7 +65,6 @@ #include "stasis/app.h" #include "stasis/control.h" #include "stasis/messaging.h" -#include "stasis/cli.h" #include "stasis/stasis_bridge.h" #include "asterisk/core_unreal.h" #include "asterisk/musiconhold.h" @@ -176,11 +175,6 @@ static struct ast_json *stasis_start_to_json(struct stasis_message *message, STASIS_MESSAGE_TYPE_DEFN_LOCAL(start_message_type, .to_json = stasis_start_to_json); -const char *stasis_app_name(const struct stasis_app *app) -{ - return app_name(app); -} - /*! AO2 hash function for \ref app */ static int app_hash(const void *obj, const int flags) { @@ -956,7 +950,7 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app if (app_subscribe_channel(app, chan)) { ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n", - app_name(app), ast_channel_name(chan)); + stasis_app_name(app), ast_channel_name(chan)); return -1; } @@ -970,7 +964,7 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app payload->replace_channel = ao2_bump(replace_channel_snapshot); json_blob = ast_json_pack("{s: s, s: o, s: []}", - "app", app_name(app), + "app", stasis_app_name(app), "timestamp", ast_json_timeval(ast_tvnow(), NULL), "args"); if (!json_blob) { @@ -1040,7 +1034,7 @@ int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan) return 0; } - blob = ast_json_pack("{s: s}", "app", app_name(app)); + blob = ast_json_pack("{s: s}", "app", stasis_app_name(app)); if (!blob) { ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n"); return -1; @@ -1486,10 +1480,6 @@ static struct stasis_app *find_app_by_name(const char *app_name) res = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY); } - if (!res) { - ast_log(LOG_WARNING, "Could not find app '%s'\n", - app_name ? : "(null)"); - } return res; } @@ -1970,8 +1960,6 @@ static int unload_module(void) { stasis_app_unregister_event_sources(); - cli_cleanup(); - messaging_cleanup(); cleanup(); @@ -2131,11 +2119,6 @@ static int load_module(void) return AST_MODULE_LOAD_FAILURE; } - if (cli_init()) { - unload_module(); - return AST_MODULE_LOAD_FAILURE; - } - bridge_stasis_init(); stasis_app_register_event_sources(); diff --git a/res/stasis/app.c b/res/stasis/app.c index 0b75ed5d72e..b0bcf3c4212 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -41,6 +41,9 @@ #define CHANNEL_ALL "__AST_CHANNEL_ALL_TOPIC" #define ENDPOINT_ALL "__AST_ENDPOINT_ALL_TOPIC" +/*! Global debug flag. No need for locking */ +int global_debug; + static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, int terminate); struct stasis_app { @@ -840,15 +843,64 @@ static void bridge_default_handler(void *data, struct stasis_subscription *sub, } } -void app_set_debug(struct stasis_app *app, int debug) +void stasis_app_set_debug(struct stasis_app *app, int debug) { if (!app) { return; } - { - SCOPED_AO2LOCK(lock, app); - app->debug = debug; + app->debug = debug; +} + +void stasis_app_set_debug_by_name(const char *app_name, int debug) +{ + struct stasis_app *app = stasis_app_get_by_name(app_name); + + if (!app) { + return; + } + + app->debug = debug; + ao2_cleanup(app); +} + +int stasis_app_get_debug(struct stasis_app *app) +{ + return (app ? app->debug : 0) || global_debug; +} + +int stasis_app_get_debug_by_name(const char *app_name) +{ + RAII_VAR(struct stasis_app *, app, stasis_app_get_by_name(app_name), ao2_cleanup); + + return (app ? app->debug : 0) || global_debug; +} + +void stasis_app_set_global_debug(int debug) +{ + global_debug = debug; + if (!global_debug) { + struct ao2_container *app_names = stasis_app_get_all(); + struct ao2_iterator it_app_names; + char *app_name; + struct stasis_app *app; + + if (!app_names || !ao2_container_count(app_names)) { + ao2_cleanup(app_names); + return; + } + + it_app_names = ao2_iterator_init(app_names, 0); + while ((app_name = ao2_iterator_next(&it_app_names))) { + if ((app = stasis_app_get_by_name(app_name))) { + stasis_app_set_debug(app, 0); + } + + ao2_cleanup(app_name); + ao2_cleanup(app); + } + ao2_iterator_cleanup(&it_app_names); + ao2_cleanup(app_names); } } @@ -949,7 +1001,6 @@ struct stasis_topic *ast_app_get_topic(struct stasis_app *app) void app_send(struct stasis_app *app, struct ast_json *message) { stasis_app_cb handler; - int debug; char eid[20]; RAII_VAR(void *, data, NULL, ao2_cleanup); @@ -962,7 +1013,6 @@ void app_send(struct stasis_app *app, struct ast_json *message) /* Copy off mutable state with lock held */ { SCOPED_AO2LOCK(lock, app); - debug = app->debug; handler = app->handler; if (app->data) { ao2_ref(app->data, +1); @@ -971,13 +1021,6 @@ void app_send(struct stasis_app *app, struct ast_json *message) /* Name is immutable; no need to copy */ } - if (debug) { - char *dump = ast_json_dump_string_format(message, AST_JSON_PRETTY); - ast_verb(0, "Dispatching message to Stasis app '%s':\n%s\n", - app->name, dump); - ast_json_free(dump); - } - if (!handler) { ast_verb(3, "Inactive Stasis app '%s' missed message\n", app->name); @@ -1050,7 +1093,7 @@ void app_update(struct stasis_app *app, stasis_app_cb handler, void *data) app->data = data; } -const char *app_name(const struct stasis_app *app) +const char *stasis_app_name(const struct stasis_app *app) { return app->name; } @@ -1067,7 +1110,7 @@ static int forwards_filter_by_type(void *obj, void *arg, int flags) return 0; } -void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a) +void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a) { struct ao2_iterator *channels; struct ao2_iterator *endpoints; diff --git a/res/stasis/app.h b/res/stasis/app.h index 6ed6a295b87..ac4ac59fbd6 100644 --- a/res/stasis/app.h +++ b/res/stasis/app.h @@ -108,15 +108,6 @@ int app_is_finished(struct stasis_app *app); */ void app_update(struct stasis_app *app, stasis_app_cb handler, void *data); -/*! - * \brief Return an application's name. - * - * \param app Application. - * \return Name of the application. - * \return \c NULL is \a app is \c NULL. - */ -const char *app_name(const struct stasis_app *app); - /*! * \brief Send a message to an application. * @@ -137,16 +128,6 @@ struct app_forwards; */ struct ast_json *app_to_json(const struct stasis_app *app); -struct ast_cli_args; - -/*! - * \brief Dump properties of a \c stasis_app to the CLI - * - * \param app The application - * \param a The CLI arguments - */ -void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a); - /*! * \brief Subscribes an application to a channel. * @@ -300,12 +281,4 @@ char *app_get_replace_channel_app(struct ast_channel *chan); */ int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan); -/*! - * \brief Enable/disable debugging on an application - * - * \param app The app to debug - * \param debug If non-zero, enable debugging. If zero, disable. - */ -void app_set_debug(struct stasis_app *app, int debug); - #endif /* _ASTERISK_RES_STASIS_APP_H */ diff --git a/res/stasis/cli.c b/res/stasis/cli.c deleted file mode 100644 index e6065b0acc2..00000000000 --- a/res/stasis/cli.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2016, Digium, Inc. - * - * Matt Jordan - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Stasis CLI commands. - * - * \author Matt Jordan - */ - -#include "asterisk.h" - -#include "asterisk/cli.h" -#include "asterisk/astobj2.h" - -#include "cli.h" -#include "app.h" - - -static char *ari_show_apps(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - struct ao2_container *apps; - struct ao2_iterator it_apps; - char *app; - - switch (cmd) { - case CLI_INIT: - e->command = "ari show apps"; - e->usage = - "Usage: ari show apps\n" - " Lists all registered applications.\n" - ; - return NULL; - case CLI_GENERATE: - return NULL; - default: - break; - } - - if (a->argc != 3) { - return CLI_SHOWUSAGE; - } - - apps = stasis_app_get_all(); - if (!apps) { - ast_cli(a->fd, "Unable to retrieve registered applications!\n"); - return CLI_FAILURE; - } - - ast_cli(a->fd, "Application Name \n"); - ast_cli(a->fd, "=========================\n"); - it_apps = ao2_iterator_init(apps, 0); - while ((app = ao2_iterator_next(&it_apps))) { - ast_cli(a->fd, "%-25.25s\n", app); - ao2_ref(app, -1); - } - - ao2_iterator_destroy(&it_apps); - ao2_ref(apps, -1); - - return CLI_SUCCESS; -} - -struct app_complete { - /*! Nth app to search for */ - int state; - /*! Which app currently on */ - int which; -}; - -static int complete_ari_app_search(void *obj, void *arg, void *data, int flags) -{ - struct app_complete *search = data; - - if (++search->which > search->state) { - return CMP_MATCH; - } - return 0; -} - -static char *complete_ari_app(struct ast_cli_args *a) -{ - RAII_VAR(struct ao2_container *, apps, stasis_app_get_all(), ao2_cleanup); - RAII_VAR(char *, app, NULL, ao2_cleanup); - - struct app_complete search = { - .state = a->n, - }; - - if (!apps) { - ast_cli(a->fd, "Error getting ARI applications\n"); - return CLI_FAILURE; - } - - app = ao2_callback_data(apps, - ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY, - complete_ari_app_search, (char*)a->word, &search); - - return app ? ast_strdup(app) : NULL; -} - -static char *complete_ari_show_app(struct ast_cli_args *a) -{ - if (a->pos == 3) { - return complete_ari_app(a); - } - - return NULL; -} - -static char *ari_show_app(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - void *app; - - switch (cmd) { - case CLI_INIT: - e->command = "ari show app"; - e->usage = - "Usage: ari show app \n" - " Provide detailed information about a registered application.\n" - ; - return NULL; - case CLI_GENERATE: - return complete_ari_show_app(a); - default: - break; - } - - if (a->argc != 4) { - return CLI_SHOWUSAGE; - } - - app = stasis_app_get_by_name(a->argv[3]); - if (!app) { - return CLI_FAILURE; - } - - app_to_cli(app, a); - - ao2_ref(app, -1); - - return CLI_SUCCESS; -} - -static char *ari_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - void *app; - int debug; - - switch (cmd) { - case CLI_INIT: - e->command = "ari set debug"; - e->usage = - "Usage: ari set debug \n" - " Enable or disable debugging on a specific application.\n" - ; - return NULL; - case CLI_GENERATE: - return complete_ari_show_app(a); - default: - break; - } - - if (a->argc != 5) { - return CLI_SHOWUSAGE; - } - - app = stasis_app_get_by_name(a->argv[3]); - if (!app) { - return CLI_FAILURE; - } - - debug = !strcmp(a->argv[4], "on"); - app_set_debug(app, debug); - ast_cli(a->fd, "Debugging on '%s' %s\n", - app_name(app), - debug ? "enabled" : "disabled"); - - ao2_ref(app, -1); - - return CLI_SUCCESS; -} - -static struct ast_cli_entry cli_ari[] = { - AST_CLI_DEFINE(ari_show_apps, "List registered ARI applications"), - AST_CLI_DEFINE(ari_show_app, "Display details of a registered ARI application"), - AST_CLI_DEFINE(ari_set_debug, "Enable/disable debugging of an ARI application"), -}; - - -int cli_init(void) -{ - return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari)); -} - -void cli_cleanup(void) -{ - ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari)); -} diff --git a/res/stasis/cli.h b/res/stasis/cli.h deleted file mode 100644 index 49235c7b309..00000000000 --- a/res/stasis/cli.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2016, Digium, Inc. - * - * Matt Jordan - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -#ifndef _ASTERISK_RES_STASIS_CLI_H -#define _ASTERISK_RES_STASIS_CLI_H - -/*! \file - * - * \brief Internal API for Stasis application CLI commands - * - * \author Matt Jordan - * \since 13.13.0 - */ - -/*! - * \brief Initialize the CLI commands - * - * \retval 0 on success - * \retval non-zero on error - */ -int cli_init(void); - -/*! - * \brief Cleanup the CLI commands - */ -void cli_cleanup(void); - -#endif /* _ASTERISK_RES_STASIS_CLI_H */ diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index 95e549a2956..e88fb2de29a 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -155,13 +155,13 @@ static int bridge_stasis_push_peek(struct ast_bridge *self, struct ast_bridge_ch } to_be_replaced = ast_channel_snapshot_get_latest(ast_channel_uniqueid(swap->chan)); - ast_debug(3, "Copying stasis app name %s from %s to %s\n", app_name(control_app(swap_control)), + ast_debug(3, "Copying stasis app name %s from %s to %s\n", stasis_app_name(control_app(swap_control)), ast_channel_name(swap->chan), ast_channel_name(bridge_channel->chan)); ast_channel_lock(bridge_channel->chan); /* copy the app name from the swap channel */ - app_set_replace_channel_app(bridge_channel->chan, app_name(control_app(swap_control))); + app_set_replace_channel_app(bridge_channel->chan, stasis_app_name(control_app(swap_control))); /* set the replace channel snapshot */ app_set_replace_channel_snapshot(bridge_channel->chan, to_be_replaced); diff --git a/rest-api-templates/param_parsing.mustache b/rest-api-templates/param_parsing.mustache index 247c121d9c9..d156ab79941 100644 --- a/rest-api-templates/param_parsing.mustache +++ b/rest-api-templates/param_parsing.mustache @@ -85,21 +85,6 @@ {{/has_path_parameters}} {{^is_websocket}} {{#parse_body}} - /* Look for a JSON request entity */ - body = ast_http_get_json(ser, headers); - if (!body) { - switch (errno) { - case EFBIG: - ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); - goto fin; - case ENOMEM: - ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); - goto fin; - case EIO: - ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); - goto fin; - } - } {{#body_parameter}} args.{{c_name}} = body; {{/body_parameter}} diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index d5c86158bcb..c28a62cd9ec 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -76,13 +76,12 @@ static void ast_ari_{{c_name}}_{{c_nickname}}_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, - struct ast_variable *headers, struct ast_ari_response *response) + struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response) { struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {}; {{#has_parameters}} struct ast_variable *i; {{/has_parameters}} - RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; diff --git a/tests/test_ari.c b/tests/test_ari.c index 1bd77496ff6..bce5f95d64c 100644 --- a/tests/test_ari.c +++ b/tests/test_ari.c @@ -61,6 +61,7 @@ static void handler(const char *name, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, + struct ast_json *body, struct ast_ari_response *response) { struct ast_json *message = ast_json_pack("{s: s, s: {}, s: {}, s: {}}", @@ -98,9 +99,10 @@ static void handler(const char *name, struct ast_variable *get_params, \ struct ast_variable *path_vars, \ struct ast_variable *headers, \ + struct ast_json *body, \ struct ast_ari_response *response) \ { \ - handler(#name, response_code, get_params, path_vars, headers, response); \ + handler(#name, response_code, get_params, path_vars, headers, body, response); \ } HANDLER(bang_get, 200) @@ -343,7 +345,8 @@ AST_TEST_DEFINE(invoke_get) "head2", "head-two", "path_vars"); - ast_ari_invoke(NULL, "foo", AST_HTTP_GET, get_params, headers, response); + ast_ari_invoke(NULL, "foo", AST_HTTP_GET, get_params, headers, + ast_json_null(), response); ast_test_validate(test, 1 == invocation_count); ast_test_validate(test, 200 == response->response_code); @@ -380,7 +383,8 @@ AST_TEST_DEFINE(invoke_wildcard) "path_vars", "bam", "foshizzle"); - ast_ari_invoke(NULL, "foo/foshizzle", AST_HTTP_GET, get_params, headers, response); + ast_ari_invoke(NULL, "foo/foshizzle", AST_HTTP_GET, get_params, headers, + ast_json_null(), response); ast_test_validate(test, 1 == invocation_count); ast_test_validate(test, 200 == response->response_code); @@ -417,7 +421,8 @@ AST_TEST_DEFINE(invoke_delete) "path_vars", "bam", "foshizzle"); - ast_ari_invoke(NULL, "foo/foshizzle/bang", AST_HTTP_DELETE, get_params, headers, response); + ast_ari_invoke(NULL, "foo/foshizzle/bang", AST_HTTP_DELETE, get_params, headers, + ast_json_null(), response); ast_test_validate(test, 1 == invocation_count); ast_test_validate(test, 204 == response->response_code); @@ -467,7 +472,8 @@ AST_TEST_DEFINE(invoke_post) "head2", "head-two", "path_vars"); - ast_ari_invoke(NULL, "foo/bar", AST_HTTP_POST, get_params, headers, response); + ast_ari_invoke(NULL, "foo/bar", AST_HTTP_POST, get_params, headers, + ast_json_null(), response); ast_test_validate(test, 1 == invocation_count); ast_test_validate(test, 200 == response->response_code); @@ -496,7 +502,8 @@ AST_TEST_DEFINE(invoke_bad_post) fixture = setup_invocation_test(); response = response_alloc(); - ast_ari_invoke(NULL, "foo", AST_HTTP_POST, get_params, headers, response); + ast_ari_invoke(NULL, "foo", AST_HTTP_POST, get_params, headers, + ast_json_null(), response); ast_test_validate(test, 0 == invocation_count); ast_test_validate(test, 405 == response->response_code); @@ -524,7 +531,8 @@ AST_TEST_DEFINE(invoke_not_found) fixture = setup_invocation_test(); response = response_alloc(); - ast_ari_invoke(NULL, "foo/fizzle/i-am-not-a-resource", AST_HTTP_GET, get_params, headers, response); + ast_ari_invoke(NULL, "foo/fizzle/i-am-not-a-resource", AST_HTTP_GET, get_params, headers, + ast_json_null(), response); ast_test_validate(test, 0 == invocation_count); ast_test_validate(test, 404 == response->response_code); From 4bfeda6ee4bfc217d1273aad0bc64791591bbabf Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Mon, 23 Jan 2017 16:18:18 -0600 Subject: [PATCH 0987/1578] Free endpoint ACLs when destroying PJSIP endpoints. If endpoint ACLs were specified, they were not being freed when endpoints were destroyed. On systems with realtime endpoints, this could add up quickly since each DB lookup would allocate the ACL without freeing it. ASTERISK-26731 #close Reported by Ustinov Artem Change-Id: Ie1f8bf5b7a0de628c975beba01e69c56893331ad --- res/res_pjsip/pjsip_configuration.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 6a15946d660..1111664dc3e 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -2069,6 +2069,8 @@ static void endpoint_destructor(void* obj) ast_variables_destroy(endpoint->channel_vars); AST_VECTOR_FREE(&endpoint->ident_method_order); ast_free(endpoint->contact_user); + ast_free_acl_list(endpoint->contact_acl); + ast_free_acl_list(endpoint->acl); } static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription) From 0ea3c371c5286daffd9986417d46af214b0dc663 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Jan 2017 13:21:08 -0600 Subject: [PATCH 0988/1578] res_pjsip_pubsub.c: Implement "pjsip show subscriptions" commands. ASTERISK-23828 #close Change-Id: Ifb8a3b61f447aedc58a8e6b36a810f7566018567 --- res/res_pjsip_pubsub.c | 556 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 548 insertions(+), 8 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 5799379a6e1..42f0dc11ec8 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -42,6 +42,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/callerid.h" #include "asterisk/manager.h" +#include "asterisk/cli.h" #include "asterisk/test.h" #include "res_pjsip/include/res_pjsip_private.h" #include "asterisk/res_pjsip_presence_xml.h" @@ -3694,6 +3695,541 @@ static int ami_show_resource_lists(struct mansession *s, const struct message *m #define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound" #define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound" +#define MAX_REGEX_ERROR_LEN 128 + +struct cli_sub_parms { + /*! CLI handler entry e parameter */ + struct ast_cli_entry *e; + /*! CLI handler entry a parameter */ + struct ast_cli_args *a; + /*! CLI subscription entry output line(s) */ + struct ast_str *buf; + /*! Compiled regular expression to select if buf is written to CLI when not NULL. */ + regex_t *like; + int count; +}; + +struct cli_sub_complete_parms { + struct ast_cli_args *a; + /*! Found callid for search position */ + char *callid; + int wordlen; + int which; +}; + +static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli) +{ + pj_str_t *callid; + + if (!sub_tree->dlg) { + return 0; + } + + callid = &sub_tree->dlg->call_id->id; + if (cli->wordlen <= pj_strlen(callid) + && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen) + && (++cli->which > cli->a->n)) { + cli->callid = ast_malloc(pj_strlen(callid) + 1); + if (cli->callid) { + ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1); + } + return -1; + } + return 0; +} + +static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_NOTIFIER + ? cli_complete_subscription_common(sub_tree, arg) : 0; +} + +static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_SUBSCRIBER + ? cli_complete_subscription_common(sub_tree, arg) : 0; +} + +static char *cli_complete_subscription_callid(struct ast_cli_args *a) +{ + struct cli_sub_complete_parms cli; + on_subscription_t on_subscription; + + if (a->pos != 4) { + return NULL; + } + + if (!strcasecmp(a->argv[3], "inbound")) { + on_subscription = cli_complete_subscription_inbound; + } else if (!strcasecmp(a->argv[3], "outbound")) { + on_subscription = cli_complete_subscription_outbound; + } else { + /* Should never get here */ + ast_assert(0); + return NULL; + } + + cli.a = a; + cli.callid = NULL; + cli.wordlen = strlen(a->word); + cli.which = 0; + for_each_subscription(on_subscription, &cli); + + return cli.callid; +} + +static int cli_subscription_expiry(struct sip_subscription_tree *sub_tree) +{ + int expiry; + + expiry = sub_tree->persistence + ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000 + : 0; + if (expiry < 0) { + /* Subscription expired */ + expiry = 0; + } + return expiry; +} + +static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli) +{ + const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */ + pj_str_t *sub_callid; + struct ast_str *buf; + char *src; + char *dest; + char *key; + char *value; + char *value_end; + int key_len; + int key_filler_width; + int value_len; + + if (!sub_tree->dlg) { + return 0; + } + sub_callid = &sub_tree->dlg->call_id->id; + if (pj_strcmp2(sub_callid, callid)) { + return 0; + } + + buf = ast_str_create(512); + if (!buf) { + return -1; + } + + ast_cli(cli->a->fd, + "%-20s: %s\n" + "===========================================================================\n", + "ParameterName", "ParameterValue"); + + ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource); + ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name); + ast_str_append(&buf, 0, "Expiry: %d\n", cli_subscription_expiry(sub_tree)); + + sip_subscription_to_ami(sub_tree, &buf); + + /* Convert AMI \r\n to \n line terminators. */ + src = strchr(ast_str_buffer(buf), '\r'); + if (src) { + dest = src; + ++src; + while (*src) { + if (*src == '\r') { + ++src; + continue; + } + *dest++ = *src++; + } + *dest = '\0'; + ast_str_update(buf); + } + + /* Reformat AMI key value pairs to pretty columns */ + key = ast_str_buffer(buf); + do { + value = strchr(key, ':'); + if (!value) { + break; + } + value_end = strchr(value, '\n'); + if (!value_end) { + break; + } + + /* Calculate field lengths */ + key_len = value - key; + key_filler_width = 20 - key_len; + if (key_filler_width < 0) { + key_filler_width = 0; + } + value_len = value_end - value; + + ast_cli(cli->a->fd, "%.*s%*s%.*s\n", + key_len, key, key_filler_width, "", + value_len, value); + + key = value_end + 1; + } while (*key); + ast_cli(cli->a->fd, "\n"); + + ast_free(buf); + + return -1; +} + +static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_NOTIFIER + ? cli_show_subscription_common(sub_tree, arg) : 0; +} + +static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_SUBSCRIBER + ? cli_show_subscription_common(sub_tree, arg) : 0; +} + +static char *cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + on_subscription_t on_subscription; + struct cli_sub_parms cli; + + switch (cmd) { + case CLI_INIT: + e->command = "pjsip show subscription {inbound|outbound}"; + e->usage = "Usage:\n" + " pjsip show subscription inbound \n" + " pjsip show subscription outbound \n" + " Show active subscription with the dialog call-id\n"; + return NULL; + case CLI_GENERATE: + return cli_complete_subscription_callid(a); + } + + if (a->argc != 5) { + return CLI_SHOWUSAGE; + } + + if (!strcasecmp(a->argv[3], "inbound")) { + on_subscription = cli_show_subscription_inbound; + } else if (!strcasecmp(a->argv[3], "outbound")) { + on_subscription = cli_show_subscription_outbound; + } else { + /* Should never get here */ + ast_assert(0); + return NULL; + } + + /* Find the subscription with the specified call-id */ + cli.a = a; + cli.e = e; + cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */ + for_each_subscription(on_subscription, &cli); + + return CLI_SUCCESS; +} + +#define CLI_SHOW_SUB_FORMAT_HEADER \ + "Endpoint: \n" \ + "Resource: \n" \ + " Expiry: \n" \ + "===========================================================================\n\n" +#define CLI_SHOW_SUB_FORMAT_ENTRY \ + "Endpoint: %s/%s\n" \ + "Resource: %s/%s\n" \ + " Expiry: %8d %s\n\n" + +static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli) +{ + char caller_id[256]; + char callid[256]; + + ast_callerid_merge(caller_id, sizeof(caller_id), + S_COR(sub_tree->endpoint->id.self.name.valid, + sub_tree->endpoint->id.self.name.str, NULL), + S_COR(sub_tree->endpoint->id.self.number.valid, + sub_tree->endpoint->id.self.number.str, NULL), + ""); + + /* Call-id */ + if (sub_tree->dlg) { + ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid)); + } else { + ast_copy_string(callid, "", sizeof(callid)); + } + + ast_str_set(&cli->buf, 0, CLI_SHOW_SUB_FORMAT_ENTRY, + ast_sorcery_object_get_id(sub_tree->endpoint), caller_id, + sub_tree->root->resource, sub_tree->root->handler->event_name, + cli_subscription_expiry(sub_tree), callid); + + if (cli->like) { + if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) { + /* Output line did not match the regex */ + return 0; + } + } + + ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf)); + ++cli->count; + + return 0; +} + +static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_NOTIFIER + ? cli_show_subscriptions_detail(sub_tree, arg) : 0; +} + +static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_SUBSCRIBER + ? cli_show_subscriptions_detail(sub_tree, arg) : 0; +} + +static char *cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + on_subscription_t on_subscription; + struct cli_sub_parms cli; + regex_t like; + const char *regex; + + switch (cmd) { + case CLI_INIT: + e->command = "pjsip show subscriptions {inbound|outbound} [like]"; + e->usage = "Usage:\n" + " pjsip show subscriptions inbound [like ]\n" + " Show active inbound subscriptions\n" + " pjsip show subscriptions outbound [like ]\n" + " Show active outbound subscriptions\n" + "\n" + " The regex selects a subscriptions output that matches.\n" + " i.e., All output lines for a subscription are checked\n" + " as a block by the regex.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 4 && a->argc != 6) { + return CLI_SHOWUSAGE; + } + if (!strcasecmp(a->argv[3], "inbound")) { + on_subscription = cli_show_subscriptions_inbound; + } else if (!strcasecmp(a->argv[3], "outbound")) { + on_subscription = cli_show_subscriptions_outbound; + } else { + /* Should never get here */ + ast_assert(0); + return CLI_SHOWUSAGE; + } + if (a->argc == 6) { + int rc; + + if (strcasecmp(a->argv[4], "like")) { + return CLI_SHOWUSAGE; + } + + /* Setup regular expression */ + memset(&like, 0, sizeof(like)); + cli.like = &like; + regex = a->argv[5]; + rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB); + if (rc) { + char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN); + + regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN); + ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n", + regex, regerr); + return CLI_FAILURE; + } + } else { + cli.like = NULL; + regex = NULL; + } + + cli.a = a; + cli.e = e; + cli.count = 0; + cli.buf = ast_str_create(256); + if (!cli.buf) { + if (cli.like) { + regfree(cli.like); + } + return CLI_FAILURE; + } + + ast_cli(a->fd, CLI_SHOW_SUB_FORMAT_HEADER); + for_each_subscription(on_subscription, &cli); + ast_cli(a->fd, "%d active subscriptions%s%s%s\n", + cli.count, + regex ? " matched \"" : "", + regex ?: "", + regex ? "\"" : ""); + + ast_free(cli.buf); + if (cli.like) { + regfree(cli.like); + } + + return CLI_SUCCESS; +} + +#define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n" +#define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n" + +static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli) +{ + char ep_cid_buf[50]; + char res_evt_buf[50]; + char callid[256]; + + /* Endpoint/CID column */ + snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s", + ast_sorcery_object_get_id(sub_tree->endpoint), + S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str, + S_COR(sub_tree->endpoint->id.self.number.valid, + sub_tree->endpoint->id.self.number.str, ""))); + + /* Resource/Event column */ + snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s", + sub_tree->root->resource, + sub_tree->root->handler->event_name); + + /* Call-id column */ + if (sub_tree->dlg) { + ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid)); + } else { + ast_copy_string(callid, "", sizeof(callid)); + } + + ast_str_set(&cli->buf, 0, CLI_LIST_SUB_FORMAT_ENTRY, + ep_cid_buf, + res_evt_buf, + cli_subscription_expiry(sub_tree), + callid); + + if (cli->like) { + if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) { + /* Output line did not match the regex */ + return 0; + } + } + + ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf)); + ++cli->count; + + return 0; +} + +static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_NOTIFIER + ? cli_list_subscriptions_detail(sub_tree, arg) : 0; +} + +static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg) +{ + return sub_tree->role == AST_SIP_SUBSCRIBER + ? cli_list_subscriptions_detail(sub_tree, arg) : 0; +} + +static char *cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + on_subscription_t on_subscription; + struct cli_sub_parms cli; + regex_t like; + const char *regex; + + switch (cmd) { + case CLI_INIT: + e->command = "pjsip list subscriptions {inbound|outbound} [like]"; + e->usage = "Usage:\n" + " pjsip list subscriptions inbound [like ]\n" + " List active inbound subscriptions\n" + " pjsip list subscriptions outbound [like ]\n" + " List active outbound subscriptions\n" + "\n" + " The regex selects output lines that match.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 4 && a->argc != 6) { + return CLI_SHOWUSAGE; + } + if (!strcasecmp(a->argv[3], "inbound")) { + on_subscription = cli_list_subscriptions_inbound; + } else if (!strcasecmp(a->argv[3], "outbound")) { + on_subscription = cli_list_subscriptions_outbound; + } else { + /* Should never get here */ + ast_assert(0); + return CLI_SHOWUSAGE; + } + if (a->argc == 6) { + int rc; + + if (strcasecmp(a->argv[4], "like")) { + return CLI_SHOWUSAGE; + } + + /* Setup regular expression */ + memset(&like, 0, sizeof(like)); + cli.like = &like; + regex = a->argv[5]; + rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB); + if (rc) { + char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN); + + regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN); + ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n", + regex, regerr); + return CLI_FAILURE; + } + } else { + cli.like = NULL; + regex = NULL; + } + + cli.a = a; + cli.e = e; + cli.count = 0; + cli.buf = ast_str_create(256); + if (!cli.buf) { + if (cli.like) { + regfree(cli.like); + } + return CLI_FAILURE; + } + + ast_cli(a->fd, CLI_LIST_SUB_FORMAT_HEADER, + "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id"); + for_each_subscription(on_subscription, &cli); + ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n", + cli.count, + regex ? " matched \"" : "", + regex ?: "", + regex ? "\"" : ""); + + ast_free(cli.buf); + if (cli.like) { + regfree(cli.like); + } + + return CLI_SUCCESS; +} + +static struct ast_cli_entry cli_commands[] = { + AST_CLI_DEFINE(cli_list_subscriptions_inout, "List active inbound/outbound subscriptions"), + AST_CLI_DEFINE(cli_show_subscription_inout, "Show active subscription details"), + AST_CLI_DEFINE(cli_show_subscriptions_inout, "Show active inbound/outbound subscriptions"), +}; + static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct subscription_persistence *persistence = obj; @@ -4635,6 +5171,8 @@ static int load_module(void) ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM, ami_show_resource_lists); + ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + AST_TEST_REGISTER(resource_tree); AST_TEST_REGISTER(complex_resource_tree); AST_TEST_REGISTER(bad_resource); @@ -4648,6 +5186,16 @@ static int load_module(void) static int unload_module(void) { + AST_TEST_UNREGISTER(resource_tree); + AST_TEST_UNREGISTER(complex_resource_tree); + AST_TEST_UNREGISTER(bad_resource); + AST_TEST_UNREGISTER(bad_branch); + AST_TEST_UNREGISTER(duplicate_resource); + AST_TEST_UNREGISTER(loop); + AST_TEST_UNREGISTER(bad_event); + + ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); + ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND); ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_INBOUND); ast_manager_unregister("PJSIPShowResourceLists"); @@ -4657,14 +5205,6 @@ static int unload_module(void) ast_sched_context_destroy(sched); } - AST_TEST_UNREGISTER(resource_tree); - AST_TEST_UNREGISTER(complex_resource_tree); - AST_TEST_UNREGISTER(bad_resource); - AST_TEST_UNREGISTER(bad_branch); - AST_TEST_UNREGISTER(duplicate_resource); - AST_TEST_UNREGISTER(loop); - AST_TEST_UNREGISTER(bad_event); - return 0; } From 6f3e8c8e01e9b7fc91dea660769ff1f11f32e629 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 20 Jan 2017 21:13:34 -0600 Subject: [PATCH 0989/1578] PJPROJECT logging: Fix detection of max supported log level. The mechanism used for detecting the maximum log level compiled into the linked pjproject did not work. The API call simply stores the requested level into an integer and does no range checking. Asterisk was assuming that there was range checking and limited the new value to the allowable range. To get the actual maximum log level compiled into the linked pjproject we need to get and save off the initial set log level from pjproject. This is the maximum log level supported. * Get and save off the initial log level setting before altering it to the desired level on startup. This has to be done by a macro rather than calling a core function to avoid incorrectly linking pjproject. * Split the initial log level warning messages to warn if the linked pjproject cannot support the requested startup level and if it is too low to get the pjproject buildopts for "pjproject show buildopts". * Adjust the CLI "pjproject set log level" to check the saved max log level and to generate normal output messages instead of a warning message. ASTERISK-26743 #close Change-Id: I40aa76653e2a1dece66c3f8734594b4f0471cfb4 --- include/asterisk/options.h | 27 +++++++++++++++++++++++++++ main/asterisk.c | 1 + main/libasteriskpj.c | 2 +- res/res_pjproject.c | 29 ++++++++++++++++++++--------- res/res_rtp_asterisk.c | 2 +- 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/include/asterisk/options.h b/include/asterisk/options.h index ff35c16c435..05ad6c56010 100644 --- a/include/asterisk/options.h +++ b/include/asterisk/options.h @@ -143,6 +143,33 @@ enum ast_option_flags { */ #define DEFAULT_PJ_LOG_MAX_LEVEL 2 +/*! + * \brief Get maximum log level pjproject was compiled with. + * + * \details + * Determine the maximum log level the pjproject we are running + * with supports. + * + * When pjproject is initially loaded the default log level in + * effect is the maximum log level the library was compiled to + * generate. We must save this value off somewhere before we + * change it to what we want to use as the default level. + * + * \note This must be done before calling pj_init() so the level + * we want to use as the default level is in effect while the + * library initializes. + */ +#define AST_PJPROJECT_INIT_LOG_LEVEL() \ + do { \ + if (ast_pjproject_max_log_level < 0) { \ + ast_pjproject_max_log_level = pj_log_get_level(); \ + } \ + pj_log_set_level(ast_option_pjproject_log_level); \ + } while (0) + +/*! Current linked pjproject maximum logging level */ +extern int ast_pjproject_max_log_level; + /*! Current pjproject logging level */ extern int ast_option_pjproject_log_level; diff --git a/main/asterisk.c b/main/asterisk.c index 338c1f53b94..69183c1f390 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -330,6 +330,7 @@ int ast_verb_sys_level; int option_verbose; /*!< Verbosity level */ int option_debug; /*!< Debug level */ +int ast_pjproject_max_log_level = -1;/* Default to -1 to know if we have read the level from pjproject yet. */ int ast_option_pjproject_log_level; double ast_option_maxload; /*!< Max load avg on system */ int ast_option_maxcalls; /*!< Max number of active calls */ diff --git a/main/libasteriskpj.c b/main/libasteriskpj.c index 0f893a2cf72..40efa9276bf 100644 --- a/main/libasteriskpj.c +++ b/main/libasteriskpj.c @@ -45,7 +45,7 @@ int ast_pj_init(void) { #ifdef HAVE_PJPROJECT_BUNDLED - pj_log_set_level(ast_option_pjproject_log_level); + AST_PJPROJECT_INIT_LOG_LEVEL(); pj_init(); #endif return 0; diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 476defb4168..1d9d73eaab6 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -410,18 +410,22 @@ static char *handle_pjproject_set_log_level(struct ast_cli_entry *e, int cmd, st } /* Update pjproject logging level */ + if (ast_pjproject_max_log_level < level_new) { + level_new = ast_pjproject_max_log_level; + ast_cli(a->fd, + "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d.\n" + "Lowering request to the max supported level.\n", + ast_pjproject_max_log_level); + } level_old = ast_option_pjproject_log_level; if (level_old == level_new) { ast_cli(a->fd, "pjproject log level is still %d.\n", level_old); } else { ast_cli(a->fd, "pjproject log level was %d and is now %d.\n", level_old, level_new); + ast_option_pjproject_log_level = level_new; pj_log_set_level(level_new); } - ast_option_pjproject_log_level = pj_log_get_level(); - if (ast_option_pjproject_log_level != level_new) { - ast_log(LOG_WARNING, "Asterisk built with pjproject PJ_LOG_MAX_LEVEL set too low.\n"); - } return CLI_SUCCESS; } @@ -495,7 +499,7 @@ static int load_module(void) ast_sorcery_load(pjproject_sorcery); - pj_log_set_level(ast_option_pjproject_log_level); + AST_PJPROJECT_INIT_LOG_LEVEL(); pj_init(); decor_orig = pj_log_get_decor(); @@ -512,12 +516,19 @@ static int load_module(void) pj_log_set_decor(0); pj_log_set_level(MAX_PJ_LOG_MAX_LEVEL);/* Set level to guarantee the dump output. */ pj_dump_config(); - pj_log_set_level(ast_option_pjproject_log_level); pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT); pj_log_set_log_func(log_forwarder); - if (!AST_VECTOR_SIZE(&buildopts) - || ast_option_pjproject_log_level != pj_log_get_level()) { - ast_log(LOG_WARNING, "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL set too low.\n"); + if (ast_pjproject_max_log_level < ast_option_pjproject_log_level) { + ast_log(LOG_WARNING, + "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low for startup level: %d.\n", + ast_pjproject_max_log_level, ast_option_pjproject_log_level); + ast_option_pjproject_log_level = ast_pjproject_max_log_level; + } + pj_log_set_level(ast_option_pjproject_log_level); + if (!AST_VECTOR_SIZE(&buildopts)) { + ast_log(LOG_NOTICE, + "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low to get buildopts.\n", + ast_pjproject_max_log_level); } ast_cli_register_multiple(pjproject_cli, ARRAY_LEN(pjproject_cli)); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 4c79f8f5b5a..b86463ebee6 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -5666,7 +5666,7 @@ static int load_module(void) #ifdef HAVE_PJPROJECT pj_lock_t *lock; - pj_log_set_level(ast_option_pjproject_log_level); + AST_PJPROJECT_INIT_LOG_LEVEL(); if (pj_init() != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; } From 36bdd7c1a0f8508312420abffb220d60946b25ff Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 10 Jan 2017 17:48:39 -0600 Subject: [PATCH 0990/1578] Add notes about embedded ast_frame structs holding a format ref. mod_format.h: Note ast_filestream.fr holds a format ref. translate.h: Note ast_trans_pvt.f holds a format ref. Change-Id: I86bda354d725207b41e08920355d7c31b2d7f749 --- include/asterisk/mod_format.h | 6 +++++- include/asterisk/translate.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/asterisk/mod_format.h b/include/asterisk/mod_format.h index bcd31deaad4..7e05a282b58 100644 --- a/include/asterisk/mod_format.h +++ b/include/asterisk/mod_format.h @@ -114,7 +114,11 @@ struct ast_filestream { int lasttimeout; struct ast_channel *owner; FILE *f; - struct ast_frame fr; /*!< frame produced by read, typically */ + /*! + * \brief frame produced by read, typically + * \note This frame holds a fr.subclass.format ref. + */ + struct ast_frame fr; char *buf; /*!< buffer pointed to by ast_frame; */ void *_private; /*!< pointer to private buffer */ const char *orig_chan_name; diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h index 8188eb8ebfe..5c7990945d2 100644 --- a/include/asterisk/translate.h +++ b/include/asterisk/translate.h @@ -208,7 +208,7 @@ struct ast_translator { */ struct ast_trans_pvt { struct ast_translator *t; - struct ast_frame f; /*!< used in frameout */ + struct ast_frame f; /*!< used in frameout. This frame holds a f.subclass.format ref. */ int samples; /*!< samples available in outbuf */ /*! \brief actual space used in outbuf */ int datalen; From d87f81ddb118edb606ed16abbc23acfa97c92419 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 10 Jan 2017 14:03:24 -0600 Subject: [PATCH 0991/1578] chan_oss.c: Fix format ref leak in oss_read(). Change-Id: I0a5d56c7dcf327d60f86a4c25a23571733709fd0 --- channels/chan_oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 0d1e24ab711..3e1e38d37a9 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -725,7 +725,7 @@ static struct ast_frame *oss_read(struct ast_channel *c) return f; /* ok we can build and deliver the frame to the caller */ f->frametype = AST_FRAME_VOICE; - f->subclass.format = ao2_bump(ast_format_slin); + f->subclass.format = ast_format_slin; f->samples = FRAME_SIZE; f->datalen = FRAME_SIZE * 2; f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET; From 56854f22d2509edbd0dfbae592480ff618c79a7b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 10 Jan 2017 12:30:57 -0600 Subject: [PATCH 0992/1578] res_musiconhold.c: Fix format ref leak when parsing MOH config class. Change-Id: Ica8e8e2ce7604c2c61ec55bef07dc675361d2ea5 --- res/res_musiconhold.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 3a751ecce61..70bb0401829 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1058,13 +1058,14 @@ static void moh_parse_options(struct ast_variable *var, struct mohclass *mohclas ast_set_flag(mohclass, MOH_RANDSTART); } } else if (!strcasecmp(var->name, "format")) { + ao2_cleanup(mohclass->format); mohclass->format = ast_format_cache_get(var->value); if (!mohclass->format) { ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); mohclass->format = ao2_bump(ast_format_slin); } - } - } + } + } } static int moh_add_file(struct mohclass *class, const char *filepath) From e922979d49ff6be125bbe8baf78e24ff2e9df280 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 13 Jan 2017 19:08:53 -0600 Subject: [PATCH 0993/1578] stasis_bridge.c: Fix off-nominal stasis control ref leak. Change-Id: Ib17218343a6596832060180e19386da9df150ac8 --- res/stasis/stasis_bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index 95e549a2956..104d319cf98 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -215,6 +215,7 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel */ return -1; } + ao2_cleanup(control); /* * If going into a holding bridge, default the role to participant, if @@ -234,7 +235,6 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel } } - ao2_cleanup(control); if (self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES) { ast_bridge_channel_update_linkedids(bridge_channel, swap); if (ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) { From 2039eb8edf337d459061f020cc663adf4cef00dd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 11 Jan 2017 14:59:24 -0600 Subject: [PATCH 0994/1578] frame.c: Fix off-nominal format ref leaks. * ast_frisolate() could leak frame format refs on allocation failures. * Similified code in ast_frisolate() and code used by ast_frisolate(). Change-Id: I79566d4d36b3d7801bf0c8294fcd3e9a86a2ed6d --- main/frame.c | 69 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/main/frame.c b/main/frame.c index 0175c7226b4..133928bb99e 100644 --- a/main/frame.c +++ b/main/frame.c @@ -82,9 +82,9 @@ static struct ast_frame *ast_frame_header_new(void) if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) { if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) { size_t mallocd_len = f->mallocd_hdr_len; + memset(f, 0, sizeof(*f)); f->mallocd_hdr_len = mallocd_len; - f->mallocd = AST_MALLOCD_HDR; frames->size--; return f; } @@ -139,12 +139,12 @@ static void __frame_free(struct ast_frame *fr, int cache) #endif if (fr->mallocd & AST_MALLOCD_DATA) { - if (fr->data.ptr) + if (fr->data.ptr) { ast_free(fr->data.ptr - fr->offset); + } } if (fr->mallocd & AST_MALLOCD_SRC) { - if (fr->src) - ast_free((void *) fr->src); + ast_free((void *) fr->src); } if (fr->mallocd & AST_MALLOCD_HDR) { if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || @@ -206,14 +206,14 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) return NULL; } out->frametype = fr->frametype; + out->subclass = fr->subclass; if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || (fr->frametype == AST_FRAME_IMAGE)) { - out->subclass.format = ao2_bump(fr->subclass.format); - } else { - memcpy(&out->subclass, &fr->subclass, sizeof(out->subclass)); + ao2_bump(out->subclass.format); } out->datalen = fr->datalen; out->samples = fr->samples; + out->mallocd = AST_MALLOCD_HDR; out->offset = fr->offset; /* Copy the timing data */ ast_copy_flags(out, fr, AST_FLAGS_ALL); @@ -226,47 +226,64 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) out = fr; } - if (!(fr->mallocd & AST_MALLOCD_SRC) && fr->src) { - if (!(out->src = ast_strdup(fr->src))) { - if (out != fr) { - ast_free(out); + if (fr->src) { + /* The original frame has a source string */ + if (!(fr->mallocd & AST_MALLOCD_SRC)) { + /* + * The original frame has a non-malloced source string. + * + * Duplicate the string and put it into the isolated frame + * which may also be the original frame. + */ + newdata = ast_strdup(fr->src); + if (!newdata) { + if (out != fr) { + ast_frame_free(out, 0); + } + return NULL; } - return NULL; + out->src = newdata; + out->mallocd |= AST_MALLOCD_SRC; + } else if (out != fr) { + /* Steal the source string from the original frame. */ + out->src = fr->src; + fr->src = NULL; + fr->mallocd &= ~AST_MALLOCD_SRC; + out->mallocd |= AST_MALLOCD_SRC; } - } else { - out->src = fr->src; - fr->src = NULL; - fr->mallocd &= ~AST_MALLOCD_SRC; } if (!(fr->mallocd & AST_MALLOCD_DATA)) { + /* The original frame has a non-malloced data buffer. */ if (!fr->datalen) { + /* Actually it's just an int so we can simply copy it. */ out->data.uint32 = fr->data.uint32; - out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC; return out; } - if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) { - if (out->src != fr->src) { - ast_free((void *) out->src); - } + /* + * Duplicate the data buffer and put it into the isolated frame + * which may also be the original frame. + */ + newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET); + if (!newdata) { if (out != fr) { - ast_free(out); + ast_frame_free(out, 0); } return NULL; } newdata += AST_FRIENDLY_OFFSET; out->offset = AST_FRIENDLY_OFFSET; - out->datalen = fr->datalen; memcpy(newdata, fr->data.ptr, fr->datalen); out->data.ptr = newdata; - } else { + out->mallocd |= AST_MALLOCD_DATA; + } else if (out != fr) { + /* Steal the data buffer from the original frame. */ out->data = fr->data; memset(&fr->data, 0, sizeof(fr->data)); fr->mallocd &= ~AST_MALLOCD_DATA; + out->mallocd |= AST_MALLOCD_DATA; } - out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA; - return out; } From de28c1b9f183d40a00c4cd87ae57585c9852380e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 10 Jan 2017 13:11:20 -0600 Subject: [PATCH 0995/1578] main/app.c: Memory corruption from early format destruction. * make_silence() created a malloced silence slin frame without adding a slin format ref. When the frame is destroyed it will unref the slin format that never had a ref added. Memory corruption is expected to follow. * Simplified and fixed counting the number of samples in a frame list for make_silence(). * Eliminated an unnecessary RAII_VAR associated with the make_silence() frame. Change-Id: I47de3f9b92635b7f8b4d72309444d6c0aee6f747 --- main/app.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/main/app.c b/main/app.c index f2e3a0fe051..1eb0741ee15 100644 --- a/main/app.c +++ b/main/app.c @@ -1422,22 +1422,20 @@ static struct ast_frame *make_silence(const struct ast_frame *orig) size_t size; size_t datalen; size_t samples = 0; - struct ast_frame *next; if (!orig) { return NULL; } + do { + if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n"); + return NULL; + } - if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n"); - return NULL; - } - - for (next = AST_LIST_NEXT(orig, frame_list); - orig; - orig = next, next = orig ? AST_LIST_NEXT(orig, frame_list) : NULL) { samples += orig->samples; - } + + orig = AST_LIST_NEXT(orig, frame_list); + } while (orig); ast_verb(4, "Silencing %zu samples\n", samples); @@ -1455,7 +1453,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig) silence->samples = samples; silence->datalen = datalen; - silence->subclass.format = ast_format_slin; + silence->subclass.format = ao2_bump(ast_format_slin); return silence; } @@ -1661,14 +1659,13 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, /* It's all good */ res = 0; } else { - RAII_VAR(struct ast_frame *, silence, NULL, ast_frame_dtor); + struct ast_frame *silence = NULL; struct ast_frame *orig = f; if (muted) { silence = make_silence(orig); if (!silence) { - ast_log(LOG_WARNING, - "Error creating silence\n"); + ast_log(LOG_WARNING, "Error creating silence\n"); break; } f = silence; @@ -1679,6 +1676,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, } res = ast_writestream(others[x], f); } + ast_frame_dtor(silence); f = orig; } From 930a24a7304d2c7f1a921bd1686cf40774a60307 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 10 Jan 2017 17:37:38 -0600 Subject: [PATCH 0996/1578] astobj2.c: Add excessive ref count trap. Change-Id: I32e6a589cf9009450e4ff7cb85c07c9d9ef7fe4a --- main/astobj2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/main/astobj2.c b/main/astobj2.c index c8e48bbf5a0..1529e91b000 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -524,6 +524,20 @@ int __ao2_ref(void *user_data, int delta, if (0 < current_value) { /* The object still lives. */ +#define EXCESSIVE_REF_COUNT 100000 + + if (EXCESSIVE_REF_COUNT <= current_value && ret < EXCESSIVE_REF_COUNT) { + char excessive_ref_buf[100]; + + /* We just reached or went over the excessive ref count trigger */ + snprintf(excessive_ref_buf, sizeof(excessive_ref_buf), + "Excessive refcount %d reached on ao2 object %p", + current_value, user_data); + ast_log(__LOG_ERROR, file, line, func, "%s\n", excessive_ref_buf); + + __ast_assert_failed(0, excessive_ref_buf, file, line, func); + } + if (ref_log && tag) { fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"), delta, ast_get_tid(), From ee2b0f2eef41714b1f6be50cda1034e649cba48d Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 24 Jan 2017 21:39:39 +0000 Subject: [PATCH 0997/1578] res_pjsip_endpoint_identifier_ip: Ensure error defaults to 0. When configuring a match using a netmask the error variable was not defaulting to 0. For some people this would cause the code to think an error occurred when adding the match when in reality it added perfectly fine. ASTERISK-26693 Change-Id: I850c250813742bddde65c84e739093c9e01dfe56 --- res/res_pjsip_endpoint_identifier_ip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 63b254da803..116e2d8d71c 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -247,7 +247,7 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va while ((current_string = ast_strip(strsep(&input_string, ",")))) { char *mask = strrchr(current_string, '/'); - int error; + int error = 0; if (ast_strlen_zero(current_string)) { continue; From 20aed30d9aa512584552ecb88e7336342c874b1c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 10 Jan 2017 17:39:02 -0600 Subject: [PATCH 0998/1578] T.140: Fix format ref and memory leaks. * channel.c:ast_sendtext(): Fix T.140 SendText memory leak. * format_compatibility.c: T.140 RED and T.140 were swapped. * res_rtp_asterisk.c:rtp_red_init(): Fix ast_format_t140_red ref leak. * res_rtp_asterisk.c:rtp_red_init(): Fix data race after starting periodic scheduled red_write(). * res_rtp_asterisk.c: Some other minor misc tweaks. Change-Id: Ifa27a2e0f8a966b1cf628607c86fc4374b0b88cb --- main/channel.c | 10 ++++++---- main/format_compatibility.c | 4 ++-- res/res_rtp_asterisk.c | 16 ++++++++-------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/main/channel.c b/main/channel.c index 4f8471743e7..d916b7c05f0 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4887,16 +4887,18 @@ int ast_sendtext(struct ast_channel *chan, const char *text) if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) { struct ast_frame f; + memset(&f, 0, sizeof(f)); f.frametype = AST_FRAME_TEXT; f.src = "DIALPLAN"; f.mallocd = AST_MALLOCD_DATA; f.datalen = strlen(text); f.data.ptr = ast_strdup(text); - f.offset = 0; - f.seqno = 0; - f.subclass.format = ast_format_t140; - res = ast_channel_tech(chan)->write_text(chan, &f); + + if (f.data.ptr) { + res = ast_channel_tech(chan)->write_text(chan, &f); + ast_frfree(&f); + } } else if (ast_channel_tech(chan)->send_text) { res = ast_channel_tech(chan)->send_text(chan, text); } diff --git a/main/format_compatibility.c b/main/format_compatibility.c index 84514ac8cdc..256d3a53cbb 100644 --- a/main/format_compatibility.c +++ b/main/format_compatibility.c @@ -262,10 +262,10 @@ struct ast_format *ast_format_compatibility_bitfield2format(uint64_t bitfield) /*! T.140 RED Text format RFC 4103 */ case AST_FORMAT_T140_RED: - return ast_format_t140; + return ast_format_t140_red; /*! T.140 Text format - ITU T.140, RFC 4103 */ case AST_FORMAT_T140: - return ast_format_t140_red; + return ast_format_t140; } return NULL; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 4c79f8f5b5a..c88c7b58e78 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -230,6 +230,7 @@ struct dtls_details { /*! \brief RTP session description */ struct ast_rtp { int s; + /*! \note The f.subclass.format holds a ref. */ struct ast_frame f; unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET]; unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */ @@ -2765,6 +2766,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) if (rtp->red) { AST_SCHED_DEL(rtp->sched, rtp->red->schedid); ast_free(rtp->red); + rtp->red = NULL; } #ifdef HAVE_PJPROJECT @@ -3485,7 +3487,8 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame return 0; } -static struct ast_frame *red_t140_to_red(struct rtp_red *red) { +static struct ast_frame *red_t140_to_red(struct rtp_red *red) +{ unsigned char *data = red->t140red.data.ptr; int len = 0; int i; @@ -5059,22 +5062,21 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); int x; - if (!(rtp->red = ast_calloc(1, sizeof(*rtp->red)))) { + rtp->red = ast_calloc(1, sizeof(*rtp->red)); + if (!rtp->red) { return -1; } rtp->red->t140.frametype = AST_FRAME_TEXT; - ao2_replace(rtp->red->t140.subclass.format, ast_format_t140_red); + rtp->red->t140.subclass.format = ast_format_t140_red; rtp->red->t140.data.ptr = &rtp->red->buf_data; - rtp->red->t140.ts = 0; rtp->red->t140red = rtp->red->t140; rtp->red->t140red.data.ptr = &rtp->red->t140red_data; - rtp->red->t140red.datalen = 0; + rtp->red->ti = buffer_time; rtp->red->num_gen = generations; rtp->red->hdrlen = generations * 4 + 1; - rtp->red->prev_ts = 0; for (x = 0; x < generations; x++) { rtp->red->pt[x] = payloads[x]; @@ -5084,8 +5086,6 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int rtp->red->t140red_data[x*4] = rtp->red->pt[x] = payloads[x]; /* primary pt */ rtp->red->schedid = ast_sched_add(rtp->sched, generations, red_write, instance); - rtp->red->t140.datalen = 0; - return 0; } From d32bd6386028243d5aca886ea1e8dc31765b7b9b Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 25 Jan 2017 15:26:53 -0600 Subject: [PATCH 0999/1578] Add reload options to CLI/AMI stale object commands. Marking an object as stale in a memory cache is supposed to prime the cache so that the next time the item is retrieved, the stale item is deleted from the cache and a background task is run to re-populate the cache with a fresh version of the object. The problem is, there are some object types out there for which there is no natural reason that they would be retrieved from the backend with any regularity. Outbound PJSIP registrations are a good example of this. At startup, they are read, and an object-specific state is created that refers to the initially-retrieved object for all time. Adding the "reload" option to the CLI/AMI commands gives the cache the opportunity to manually re-retrieve the object from the backend, both storing the new object in the cache and applying the new object's configuration to the module that uses that object. Change-Id: Ieb1fe7270ceed491f057ec5cbf0e097bde96c5c8 --- res/res_sorcery_memory_cache.c | 39 ++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index 7da72bca4ae..5f7ffb64ee8 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -83,6 +83,9 @@ The name of the object to mark as stale. + + If true, then immediately reload the object from the backend cache instead of waiting for the next retrieval + Marks an object as stale within a sorcery memory cache. @@ -1394,10 +1397,8 @@ static void sorcery_memory_cache_load(void *data, const struct ast_sorcery *sorc ast_debug(1, "Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n", cache->name, sorcery, ast_sorcery_get_module(sorcery), type); - if (cache->full_backend_cache) { - cache->sorcery = sorcery; - cache->object_type = ast_strdup(type); - } + cache->sorcery = sorcery; + cache->object_type = ast_strdup(type); } /*! @@ -1870,8 +1871,10 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct case CLI_INIT: e->command = "sorcery memory cache stale"; e->usage = - "Usage: sorcery memory cache stale [object name]\n" - " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n"; + "Usage: sorcery memory cache stale [object name [reload]]\n" + " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n" + " If \"reload\" is specified, then the object is marked stale and immediately\n" + " retrieved from backend storage to repopulate the cache\n"; return NULL; case CLI_GENERATE: if (a->pos == 4) { @@ -1883,7 +1886,7 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct } } - if (a->argc < 5 || a->argc > 6) { + if (a->argc < 5 || a->argc > 7) { return CLI_SHOWUSAGE; } @@ -1907,6 +1910,15 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct if (!mark_object_as_stale_in_cache(cache, a->argv[5])) { ast_cli(a->fd, "Successfully marked object '%s' in memory cache '%s' as stale\n", a->argv[5], a->argv[4]); + if (a->argc == 7 && ast_true(a->argv[6])) { + struct sorcery_memory_cached_object *cached; + + cached = ao2_find(cache->objects, a->argv[5], OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (cached) { + memory_cache_stale_update_object(cache->sorcery, cache, cached); + ao2_ref(cached, -1); + } + } } else { ast_cli(a->fd, "Object '%s' in sorcery memory cache '%s' could not be marked as stale as it was not found\n", a->argv[5], a->argv[4]); @@ -2066,6 +2078,7 @@ static int sorcery_memory_cache_ami_stale_object(struct mansession *s, const str { const char *cache_name = astman_get_header(m, "Cache"); const char *object_name = astman_get_header(m, "Object"); + const char *reload = astman_get_header(m, "Reload"); struct sorcery_memory_cache *cache; int res; @@ -2084,7 +2097,19 @@ static int sorcery_memory_cache_ami_stale_object(struct mansession *s, const str } ao2_rdlock(cache->objects); + res = mark_object_as_stale_in_cache(cache, object_name); + + if (ast_true(reload)) { + struct sorcery_memory_cached_object *cached; + + cached = ao2_find(cache->objects, object_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (cached) { + memory_cache_stale_update_object(cache->sorcery, cache, cached); + ao2_ref(cached, -1); + } + } + ao2_unlock(cache->objects); ao2_ref(cache, -1); From 7fa3de7ae9146f5267f45feb9fbf1c523bcaf7d4 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 26 Jan 2017 13:57:59 +0000 Subject: [PATCH 1000/1578] res_pjsip_endpoint_identifier_ip: Fix memory leak of hosts when resolving. This change adds a missing unreference of the hostname when resolving and also cleans up the iterator. ASTERISK-26735 Change-Id: Ic012ebaf3d89e714eec340b7b0c5e63c66af857a --- res/res_pjsip_endpoint_identifier_ip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 116e2d8d71c..86a5afbdbf0 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -323,9 +323,14 @@ static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj) } else if (results == -1) { ast_log(LOG_ERROR, "An error occurred when adding resolution results of '%s' on '%s'\n", current_string, ast_sorcery_object_get_id(obj)); + ao2_ref(current_string, -1); + ao2_iterator_destroy(&i); return -1; } + + ao2_ref(current_string, -1); } + ao2_iterator_destroy(&i); ao2_ref(identify->hosts, -1); identify->hosts = NULL; From 8270d2436d927e6b5c9988538f665ada51b4f2dc Mon Sep 17 00:00:00 2001 From: kkm Date: Tue, 24 Jan 2017 20:31:38 -0800 Subject: [PATCH 1001/1578] app_queue: Fix queues randomly disappearing on reload With 500+ queues and a reload every minute, a random queue disappears upon reload. The cause is mususe of the 'dead' flag. Namely, all queues were marked dead up front, and then "resurrected" by dropping this flag for those found in the configuration. But a queue marked dead can be removed also when control leaves the app entry point on a PBX thread. With this change, the queue is marked only not found, and at the end of reload only the queues that are still not found are actually marked as dead, so the dead flag is never reset, and set only on positively dead queues. ASTERISK-26755 Change-Id: I3a4537aec9eb8d8aeeaa0193407e3523feb004bf --- apps/app_queue.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index da24c51d62a..344e9c1a5b5 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -9206,33 +9206,22 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, queue_t_unref(q, "Expiring creation reference"); } -static int remove_members_and_mark_unfound(void *obj, void *arg, int flags) +static int mark_unfound(void *obj, void *arg, int flags) { struct call_queue *q = obj; char *queuename = arg; if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { q->found = 0; - } return 0; } -static int mark_dead_and_unfound(void *obj, void *arg, int flags) +static int kill_if_unfound(void *obj, void *arg, int flags) { struct call_queue *q = obj; char *queuename = arg; - if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { + if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { q->dead = 1; - q->found = 0; - } - return 0; -} - -static int kill_dead_queues(void *obj, void *arg, int flags) -{ - struct call_queue *q = obj; - char *queuename = arg; - if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) { return CMP_MATCH; } else { return 0; @@ -9257,7 +9246,6 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena char *cat; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); - const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); if (!(cfg = ast_config_load("queues.conf", config_flags))) { ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); @@ -9272,18 +9260,10 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena /* We've made it here, so it looks like we're doing operations on all queues. */ ao2_lock(queues); - /* Mark all queues as dead for the moment if we're reloading queues. - * For clarity, we could just be reloading members, in which case we don't want to mess - * with the other queue parameters at all*/ - if (queue_reload) { - ao2_callback(queues, OBJ_NODATA | OBJ_NOLOCK, mark_dead_and_unfound, (char *) queuename); - } - - if (member_reload) { - ao2_callback(queues, OBJ_NODATA, remove_members_and_mark_unfound, (char *) queuename); - } + /* Mark non-realtime queues not found at the beginning. */ + ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename); - /* Chug through config file */ + /* Chug through config file. */ cat = NULL; while ((cat = ast_category_browse(cfg, cat)) ) { if (!strcasecmp(cat, "general") && queue_reload) { @@ -9295,9 +9275,9 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena } ast_config_destroy(cfg); - /* Unref all the dead queues if we were reloading queues */ if (queue_reload) { - ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_dead_queues, (char *) queuename); + /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */ + ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_if_unfound, (char *) queuename); } ao2_unlock(queues); return 0; From 138cd8d01944fb5bdff6b47fc641e29d4c0c5139 Mon Sep 17 00:00:00 2001 From: kkm Date: Tue, 24 Jan 2017 17:51:07 -0800 Subject: [PATCH 1002/1578] make_build_h: handle backslashes in external strings LikewiseOpen creates user names with a backslash in them. A gentle massage with sed(1) allows such strings to be inserted into build.h properly quoted. I am also adding the same for host name and other strings used in the script that are more or less user-controlled. ASTERISK-26754 Change-Id: Iac5ef2b67a68ee58f35ddbf86bb818ba6eabecae --- build_tools/make_build_h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build_tools/make_build_h b/build_tools/make_build_h index a7cb6fe2e80..2c8895e7a3e 100755 --- a/build_tools/make_build_h +++ b/build_tools/make_build_h @@ -1,13 +1,13 @@ #!/bin/sh -HOSTNAME=`uname -n` -KERNEL=`uname -r` -MACHINE=`uname -m` +HOSTNAME=`uname -n | sed 's/\\\\/\\\\\\\\/g'` +KERNEL=`uname -r | sed 's/\\\\/\\\\\\\\/g'` +MACHINE=`uname -m | sed 's/\\\\/\\\\\\\\/g'` OS=`uname -s` -USER=`id | awk -F")" '{print $1}'| awk -F"(" '{print $2}'` +USER=`id | awk -F")" '{print $1}'| awk -F"(" '{print $2}' | sed 's/\\\\/\\\\\\\\/g'` DATE=`date -u "+%Y-%m-%d %H:%M:%S"` cat << END /* - * build.h + * build.h * Automatically generated */ #define BUILD_HOSTNAME "${HOSTNAME}" From 178b90af02c9c063268df7269c1bd8c0bff2aa23 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Mon, 23 Jan 2017 16:35:38 +0100 Subject: [PATCH 1003/1578] libastssl/pj: libastssl/pj should have an so_version Issue introduced in b59956a87. In the non-darwin case libastssl/pj should be versioned. This causes the symbol file for this lib to not be generated. Change-Id: Ib07ae8c40252813c488e2c1ac6204fd42816dd4c (cherry picked from commit 54b027916a71f2b83b2050cef5ef704ea5de39b2) --- main/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/Makefile b/main/Makefile index 2b7321d4fe7..4d1b2c41bd2 100644 --- a/main/Makefile +++ b/main/Makefile @@ -205,7 +205,7 @@ ASTSSL_LDLIBS=-L. -lasteriskssl ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin ASTSSL_LIB:=libasteriskssl.so -$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTSSL_LIB) +$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTSSL_LIB).$(ASTSSL_SO_VERSION) $(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskssl\" -DAST_NOT_MODULE $(ASTSSL_LIB).$(ASTSSL_SO_VERSION): LIBS+=$(ASTSSL_LIBS) ifeq ($(GNU_LD),1) @@ -285,7 +285,7 @@ ifeq ($(GNU_LD),1) $(CMD_PREFIX) echo -e "local:\n*;\n};" >> libasteriskpj.exports endif -$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB) $(PJ_LDFLAGS) +$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB).$(ASTPJ_SO_VERSION) $(PJ_LDFLAGS) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" -DAST_NOT_MODULE $(PJ_CFLAGS) $(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lpthread $(RT_LIB) ifeq ($(GNU_LD),1) From ef4deb8ecd52a3c0b0952badc6ec0e5e48231011 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 25 Jan 2017 05:50:43 -0700 Subject: [PATCH 1004/1578] debug_utilities: Add ast_logescalator The escalator works by creating a set of startup commands in cli.conf that set up logger channels and issue the debug commands for the subsystems specified. If asterisk is running when it is executed, the same commands will be issued to the running instance. The original cli.conf is saved before any changes are made and can be restored by executing '$prog --reset'. The log output will be stored in... $astlogdir/message.$uniqueid $astlogdir/debug.$uniqueid $astlogdir/dtmf.$uniqueid $astlogdir/fax.$uniqueid $astlogdir/security.$uniqueid $astlogdir/pjsip_history.$uniqueid $astlogdir/sip_history.$uniqueid Some minor tweaks were made to chan_sip, and res_pjsip_history so their history output could be send to a log channel as packets are captured. A minor tweak was also made to manager so events are output to verbose when "manager set debug on" is issued. Change-Id: I799f8e5013b86dc5282961b27383d134bf09e543 --- channels/chan_sip.c | 12 + contrib/scripts/ast_logescalator | 399 +++++++++++++++++++++++++++++++ main/manager.c | 6 +- res/res_pjsip_history.c | 91 ++++--- 4 files changed, 479 insertions(+), 29 deletions(-) create mode 100755 contrib/scripts/ast_logescalator diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 288933fdddf..3bb6e74b6da 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -613,6 +613,8 @@ ***/ +static int log_level = -1; + static int min_expiry = DEFAULT_MIN_EXPIRY; /*!< Minimum accepted registration time */ static int max_expiry = DEFAULT_MAX_EXPIRY; /*!< Maximum accepted registration time */ static int default_expiry = DEFAULT_DEFAULT_EXPIRY; @@ -3932,6 +3934,9 @@ static __attribute__((format(printf, 2, 0))) void append_history_va(struct sip_p } AST_LIST_INSERT_TAIL(p->history, hist, list); p->history_entries++; + if (log_level != -1) { + ast_log_dynamic_level(log_level, "%s\n", buf); + } } /*! \brief Append to SIP dialog history with arg list */ @@ -35172,6 +35177,10 @@ static int load_module(void) struct sip_peer *bogus_peer; ast_verbose("SIP channel loading...\n"); + log_level = ast_logger_register_level("SIP_HISTORY"); + if (log_level < 0) { + ast_log(LOG_WARNING, "Unable to register history log level\n"); + } if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) { unload_module(); @@ -35572,6 +35581,9 @@ static int unload_module(void) sip_cfg.caps = NULL; STASIS_MESSAGE_TYPE_CLEANUP(session_timeout_type); + if (log_level != -1) { + ast_logger_unregister_level("SIP_HISTORY"); + } return 0; } diff --git a/contrib/scripts/ast_logescalator b/contrib/scripts/ast_logescalator new file mode 100755 index 00000000000..054ef9b9c0f --- /dev/null +++ b/contrib/scripts/ast_logescalator @@ -0,0 +1,399 @@ +#!/usr/bin/env bash +# Turn on extended globbing +shopt -s extglob +# Bail on any error +set -e + +prog=$(basename $0) + +print_help() { +cat < ] [ --sip-debug= ] + [ --iax2-debug= ] + + [ --agi-debug= ] [ --ami-debug= ] + [ --ari-debug= ] [ --cdr-debug= ] + [ --channel-debug= ] [ --rtp-debug= ] + [ --rtcp-debug= ] + + [ --dtmf-debug= ] [ --fax-debug= ] + [ --security-debug= ] + + [ --pjsip-history= ] [ --sip-history= ] + + [ --verbose= ] [ --debug= ] + ] ] + +DESCRIPTION + + Escalates log and/or debug levels on Asterisk subsystems. + + Options: + + --help + Print this help. + + --reset + Resets logging to the pre-escalation state. + + --uniqueid="" + Normally DATEFORMAT from ast_debug_tools.conf is used to make + the log files unique but you can set the unique id to + something else such as the Jira issue. Once any logging + is enabled, the uniqueid is stored in cli.conf so any future + on/off commands will use the same uniqueid. Use the --reset + option to reset it (and everything else). + + --pjsip-debug --sip-debug --iax2-debug --agi-debug --ami-debug + --ari-debug --cdr-debug --channel-debug --rtp-debug --rtcp-debug + Issues the subsystem appropriate command to turn on + or off debugging. These are usually functional debug messages + such as packet dumps as opposed to code level messages and usually + go to the VERBOSE log channel. + + --dtmf-debug --fax-debug --security-debug + These subsystems set up their own log channels so if turned + on, log files will be created in \$astlogdir for them. + + --pjsip-history --sip-history + The pjsip and sip channels have the ability to output an + abbreviated, one-line, packet summary. If enabled, the summaries + will be written to \$astlogdir/pjsip_history.\$UNIQUEID and + \$astlogdir/sip_history.\$UNIQUEID. + + --verbose-level --debug-level + Sets the levels for their respective messages. + +NOTES + + The escalator works by creating a set of startup commands in cli.conf + that set up logger channels and issue the debug commands. If asterisk + is running when $prog is executed, the same commands will be issued + to the running instance. The original cli.conf is saved before any + changes are made and can be restored by executing '$prog --reset'. + + The log output will be stored in... + \$astlogdir/message.\$uniqueid + \$astlogdir/debug.\$uniqueid + \$astlogdir/dtmf.\$uniqueid + \$astlogdir/fax.\$uniqueid + \$astlogdir/security.\$uniqueid + \$astlogdir/pjsip_history.\$uniqueid + \$astlogdir/sip_history.\$uniqueid + +EOF + exit 1 +} + +PJSIP_DEBUG_SPECIFIED=false +PJSIP_HISTORY_SPECIFIED=false +SIP_DEBUG_SPECIFIED=false +SIP_HISTORY_SPECIFIED=false +IAX2_DEBUG_SPECIFIED=false +ARI_DEBUG_SPECIFIED=false +AMI_DEBUG_SPECIFIED=false +AGI_DEBUG_SPECIFIED=false +CDR_DEBUG_SPECIFIED=false +CHANNEL_DEBUG_SPECIFIED=false +RTP_DEBUG_SPECIFIED=false +RTCP_DEBUG_SPECIFIED=false +DTMF_DEBUG_SPECIFIED=false +FAX_DEBUG_SPECIFIED=false +SECURITY_DEBUG_SPECIFIED=false +DEBUG_LEVEL_SPECIFIED=false +VERBOSE_LEVEL_SPECIFIED=false +DEBUGS=false +RESET=false + +declare -A DEBUG_COMMANDS=( +[PJSIP,on]="pjsip set logger on" [PJSIP,off]="pjsip set logger off" +[SIP,on]="sip set debug on" [SIP,off]="sip set debug off" +[IAX2,on]="iax2 set debug on" [IAX2,off]="iax2 set debug off" +[ARI,on]="ari set debug all on" [ARI,off]="ari set debug all off" +[AMI,on]="manager set debug on" [AMI,off]="manager set debug off" +[AGI,on]="agi set debug on" [AGI,off]="agi set debug off" +[CDR,on]="cdr set debug on" [CDR,off]="cdr set debug off" +[CHANNEL,on]="core set debug channel all" [CHANNEL,off]="core set debug channel all off" +[RTP,on]="rtp set debug on" [RTP,on]="rtp set debug off" +[RTCP,on]="rtcp set debug on" [RTCP,off]="rtcp set debug off" +) + +VERBOSE_LEVELS="NOTICE,WARNING,ERROR,VERBOSE" +DEBUG_LEVELS="DEBUG" + +# Read config files from least important to most important +[ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf +[ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf +[ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf + +DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'} +UNIQUEID=$($DATEFORMAT) +UNIQUEID_SPECIFIED=false + +for a in "$@" ; do + case "$a" in + --*-debug=*) + subsystem=${a%-debug=*} + subsystem=${subsystem#--} + flag=${a#*=} + if [[ ${flag,,} =~ ^y(es)?|on ]] ; then + eval ${subsystem^^}_DEBUG=true + else + eval ${subsystem^^}_DEBUG=false + fi + eval ${subsystem^^}_DEBUG_SPECIFIED=true + DEBUGS=true + ;; + --pjsip-history=*) + ;& + --sip-history=*) + subsystem=${a%-history=*} + subsystem=${subsystem#--} + if [[ ${a#*=} =~ ^[Yy].* ]] ; then + eval ${subsystem^^}_HISTORY=true + else + eval ${subsystem^^}_HISTORY=false + fi + eval ${subsystem^^}_HISTORY_SPECIFIED=true + DEBUGS=true + ;; + --verbose=*) + VERBOSE_LEVEL=${a#*=} + VERBOSE_LEVEL_SPECIFIED=true + DEBUGS=true + ;; + --debug=*) + DEBUG_LEVEL=${a#*=} + DEBUG_LEVEL_SPECIFIED=true + DEBUGS=true + ;; + --reset) + RESET=true + ;; + --uniqueid=*) + UNIQUEID=${a#*=} + UNIQUEID_SPECIFIED=true + DEBUGS=true + ;; + --help|*) + print_help + ;; + esac +done + +if $DEBUGS && $RESET ; then + echo "--reset must be specified by itself" + print_help +fi + +if ! $DEBUGS && ! $RESET ; then + echo "No options specified." + print_help +fi + +ASTERISK_IS_RUNNING=false +CONFIG_DIR=/etc/asterisk +LOG_DIR=/var/log/asterisk + +if [ "$(pidof asterisk)" != "" ] ; then + CONFIG_DIR=`asterisk -rx "core show settings" | sed -n -r -e "s/^\s*Configuration\s+directory:\s+(.*)$/\1/gp"` + LOG_DIR=`asterisk -rx "core show settings" | sed -n -r -e "s/^\s*Log\s+directory:\s+(.*)$/\1/gp"` + ASTERISK_IS_RUNNING=true +fi +CLI_CONF="$CONFIG_DIR/cli.conf" + +if [ ! -f "$CLI_CONF" ] ; then + echo "The location of cli.conf could not be determined." + exit 1 +fi + +if $RESET ; then + if [ -f "$CLI_CONF.unescalated" ] ; then + mv "$CLI_CONF.unescalated" "$CLI_CONF" + fi + if $ASTERISK_IS_RUNNING ; then + ( + asterisk -rx "core set verbose 0" + asterisk -rx "core set debug 0" + asterisk -rx "pjsip set logger off" + asterisk -rx "pjsip set history off" + asterisk -rx "sip set debug off" + asterisk -rx "sip set history off" + asterisk -rx "iax2 set debug off" + asterisk -rx "manager set debug off" + asterisk -rx "ari set debug all off" + asterisk -rx "agi set debug off" + asterisk -rx "rtp set debug off" + asterisk -rx "rtcp set debug off" + asterisk -rx "cdr set debug off" + asterisk -rx "core set debug channel all off" + asterisk -rx "logger reload" + ) >/dev/null 2>&1 || : + fi + exit 1 +fi + +if ! grep -q "; --START DEBUG_LOGGING-- ;" $CLI_CONF ; then + VERBOSE_LOG="$LOG_DIR/message.${UNIQUEID}" + DEBUG_LOG="$LOG_DIR/debug.${UNIQUEID}" + PJSIP_HISTORY_LOG="$LOG_DIR/pjsip_history.${UNIQUEID}" + SIP_HISTORY_LOG="$LOG_DIR/sip_history.${UNIQUEID}" + DTMF_LOG="$LOG_DIR/dtmf.${UNIQUEID}" + FAX_LOG="$LOG_DIR/fax.${UNIQUEID}" + SECURITY_LOG="$LOG_DIR/security.${UNIQUEID}" + + cp "$CLI_CONF" "$CLI_CONF.unescalated" + + sed -i -r -e "s/\[startup_commands\]/[startup_commands_original](!)/g" "$CLI_CONF" + + cat >> "$CLI_CONF" <<-EOF + ; --START DEBUG_LOGGING-- ; + + [pjsip_debug](!) + pjsip set logger on = yes + + [sip_debug](!) + sip set debug on = yes + + [iax2_debug](!) + iax2 set debug on = yes + + [ari_debug](!) + ari set debug all on = yes + + [ami_debug](!) + manager set debug on = yes + + [agi_debug](!) + agi set debug on = yes + + [cdr_debug](!) + cdr set debug on = yes + + [channel_debug](!) + core set debug channel all = yes + + [rtp_debug](!) + rtp set debug on = yes + + [rtcp_debug](!) + rtcp set debug on = yes + + [dtmf_debug](!) + logger add channel $DTMF_LOG DTMF = yes + + [fax_debug](!) + logger add channel $FAX_LOG FAX = yes + + [security_debug](!) + logger add channel $SECURITY_LOG SECURITY = yes + + [pjsip_history](!) + logger add channel $PJSIP_HISTORY_LOG PJSIP_HISTORY = yes + pjsip set history on = yes + + [sip_history](!) + logger add channel $SIP_HISTORY_LOG SIP_HISTORY = yes + sip set history on = yes + + [verbose_level](!) + core set verbose 3 = yes + + [debug_level](!) + core set debug 3 = yes + + [log_channels](!) + logger add channel $VERBOSE_LOG NOTICE,WARNING,ERROR,VERBOSE = yes + logger add channel $DEBUG_LOG DEBUG = yes + + [startup_commands](startup_commands_original,log_channels) + + ; --END DEBUG_LOGGING-- ; + EOF + +else + if $UNIQUEID_SPECIFIED ; then + echo "Debug logging is already active. Either rerun $prog without --uniqueid or with --reset to start over." + exit 1 + fi + + VERBOSE_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/message\..+)\s+NOTICE.*@\1@p" "$CLI_CONF") + DEBUG_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/debug\..+)\s+DEBUG.*@\1@p" "$CLI_CONF") + PJSIP_HISTORY_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/pjsip_history\..+)\s+PJSIP.*@\1@p" "$CLI_CONF") + SIP_HISTORY_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/sip_history\..+)\s+SIP.*@\1@p" "$CLI_CONF") + DTMF_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/dtmf\..+)\s+DTMF.*@\1@p" "$CLI_CONF") + FAX_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/fax\..+)\s+FAX.*@\1@p" "$CLI_CONF") + SECURITY_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/security\..+)\s+SECURITY.*@\1@p" "$CLI_CONF") +fi + +for x in PJSIP SIP ARI AMI AGI ARI IAX2 CDR RTP RTCP ; do + if eval \$${x}_DEBUG_SPECIFIED ; then + if eval \$${x}_DEBUG ; then + if $ASTERISK_IS_RUNNING ; then + asterisk -rx "${DEBUG_COMMANDS[$x,on]}" + fi + egrep -q "^\[startup_commands\].*${x,,}_debug.*" "$CLI_CONF" || + sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_debug)/g" "$CLI_CONF" + else + if $ASTERISK_IS_RUNNING ; then + asterisk -rx "${DEBUG_COMMANDS[$x,off]}" + fi + sed -i -r -e "/\[startup_commands\].*${x,,}_debug.*/ s/,${x,,}_debug//g" "$CLI_CONF" + fi + fi +done + +for x in DTMF FAX SECURITY ; do + if eval \$${x}_DEBUG_SPECIFIED ; then + if eval \$${x}_DEBUG ; then + if $ASTERISK_IS_RUNNING ; then + asterisk -rx "$(eval "echo logger add channel \$${x}_LOG ${x}")" >/dev/null 2>&1 + fi + egrep -q "^\[startup_commands\].*${x,,}_debug.*" "$CLI_CONF" || + sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_debug)/g" "$CLI_CONF" + else + if $ASTERISK_IS_RUNNING ; then + asterisk -rx "$(eval "echo logger remove channel \$${x}_LOG")" + fi + sed -i -r -e "/\[startup_commands\].*${x,,}_debug.*/ s/,${x,,}_debug//g" "$CLI_CONF" + fi + fi +done + +for x in PJSIP SIP ; do + if eval \$${x}_HISTORY_SPECIFIED ; then + if eval \$${x}_HISTORY ; then + if $ASTERISK_IS_RUNNING ; then + asterisk -rx "$(eval "echo logger add channel \$${x}_HISTORY_LOG ${x}_HISTORY")" + asterisk -rx "${x,,} set history on" + fi + egrep -q "^\[startup_commands\].*${x,,}_history.*" "$CLI_CONF" || + sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_history)/g" "$CLI_CONF" + else + if $ASTERISK_IS_RUNNING ; then + asterisk -rx "$(eval "echo logger remove channel \$${x}_HISTORY_LOG")" + asterisk -rx "${x,,} set history off" + fi + sed -i -r -e "/\[startup_commands\].*${x,,}_history.*/ s/,${x,,}_history//g" "$CLI_CONF" + fi + fi +done + +for x in VERBOSE DEBUG ; do + if eval \$${x}_LEVEL_SPECIFIED ; then + if $ASTERISK_IS_RUNNING ; then + asterisk -rx "$(eval "echo logger add channel \$${x}_LOG \$${x}_LEVELS")" + asterisk -rx "$(eval "echo core set ${x,,} \$${x}_LEVEL")" + fi + sed -i -r -e "$(eval "echo s/core set ${x,,} .*/core set ${x,,} \$${x}_LEVEL/g")" "$CLI_CONF" + egrep -q "^\[startup_commands\].*${x,,}_level.*" "$CLI_CONF" || + sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_level)/g" "$CLI_CONF" + fi +done diff --git a/main/manager.c b/main/manager.c index f059015c7d4..dfe056438dc 100644 --- a/main/manager.c +++ b/main/manager.c @@ -5889,7 +5889,11 @@ static int match_filter(struct mansession *s, char *eventdata) { int result = 0; - ast_debug(3, "Examining AMI event:\n%s\n", eventdata); + if (manager_debug) { + ast_verbose("<-- Examining AMI event: -->\n%s\n", eventdata); + } else { + ast_debug(3, "Examining AMI event:\n%s\n", eventdata); + } if (!ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) { return 1; /* no filtering means match all */ } else if (ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) { diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c index 41c5bdf6964..853ba319eac 100644 --- a/res/res_pjsip_history.c +++ b/res/res_pjsip_history.c @@ -157,6 +157,9 @@ struct expression_token { char field[]; }; +/*! \brief Log level for history output */ +static int log_level = -1; + /*! * \brief Operator callback for determining equality */ @@ -644,6 +647,41 @@ static struct pjsip_history_entry *pjsip_history_entry_alloc(pjsip_msg *msg) return entry; } +/*! \brief Format single line history entry */ +static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len) +{ + char addr[64]; + + if (entry->transmitted) { + pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3); + } else { + pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3); + } + + if (entry->msg->type == PJSIP_REQUEST_MSG) { + char uri[128]; + + pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri)); + snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s %.*s %s SIP/2.0", + entry->number, + entry->timestamp.tv_sec, + entry->transmitted ? "* ==>" : "* <==", + addr, + (int)pj_strlen(&entry->msg->line.req.method.name), + pj_strbuf(&entry->msg->line.req.method.name), + uri); + } else { + snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s", + entry->number, + entry->timestamp.tv_sec, + entry->transmitted ? "* ==>" : "* <==", + addr, + entry->msg->line.status.code, + (int)pj_strlen(&entry->msg->line.status.reason), + pj_strbuf(&entry->msg->line.status.reason)); + } +} + /*! \brief PJSIP callback when a SIP message is transmitted */ static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata) { @@ -665,6 +703,13 @@ static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata) AST_VECTOR_APPEND(&vector_history, entry); ast_mutex_unlock(&history_lock); + if (log_level != -1) { + char line[256]; + + sprint_list_entry(entry, line, sizeof(line)); + ast_log_dynamic_level(log_level, "%s\n", line); + } + return PJ_SUCCESS; } @@ -698,6 +743,13 @@ static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata) AST_VECTOR_APPEND(&vector_history, entry); ast_mutex_unlock(&history_lock); + if (log_level != -1) { + char line[256]; + + sprint_list_entry(entry, line, sizeof(line)); + ast_log_dynamic_level(log_level, "%s\n", line); + } + return PJ_FALSE; } @@ -1118,38 +1170,12 @@ static void display_entry_list(struct ast_cli_args *a, struct vector_history_t * for (i = 0; i < AST_VECTOR_SIZE(vec); i++) { struct pjsip_history_entry *entry; - char addr[64]; char line[256]; entry = AST_VECTOR_GET(vec, i); + sprint_list_entry(entry, line, sizeof(line)); - if (entry->transmitted) { - pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3); - } else { - pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3); - } - - if (entry->msg->type == PJSIP_REQUEST_MSG) { - char uri[128]; - - pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri)); - snprintf(line, sizeof(line), "%.*s %s SIP/2.0", - (int)pj_strlen(&entry->msg->line.req.method.name), - pj_strbuf(&entry->msg->line.req.method.name), - uri); - } else { - snprintf(line, sizeof(line), "SIP/2.0 %u %.*s", - entry->msg->line.status.code, - (int)pj_strlen(&entry->msg->line.status.reason), - pj_strbuf(&entry->msg->line.status.reason)); - } - - ast_cli(a->fd, "%-5.5d %-10.10ld %-5.5s %-24.24s %s\n", - entry->number, - entry->timestamp.tv_sec, - entry->transmitted ? "* ==>" : "* <==", - addr, - line); + ast_cli(a->fd, "%s\n", line); } } @@ -1319,6 +1345,11 @@ static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); + log_level = ast_logger_register_level("PJSIP_HISTORY"); + if (log_level < 0) { + ast_log(LOG_WARNING, "Unable to register history log level\n"); + } + pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); AST_VECTOR_INIT(&vector_history, HISTORY_INITIAL_SIZE); @@ -1339,6 +1370,10 @@ static int unload_module(void) pj_caching_pool_destroy(&cachingpool); + if (log_level != -1) { + ast_logger_unregister_level("PJSIP_HISTORY"); + } + return 0; } From e252aff9ad9e8448ec0bdcd031b3833dd460d7db Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 31 Jan 2017 11:46:08 -0700 Subject: [PATCH 1005/1578] debug_utilities: Install ast_logescalator to /var/lib/asterisk/scripts Forgot to install it with the original patch Change-Id: I8bdb540a6694971ae5fe21f48d532332c6482e4c --- contrib/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/Makefile b/contrib/Makefile index a6672431133..9512de540ce 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -21,11 +21,13 @@ include $(ASTTOPDIR)/Makefile.rules install: $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts" + $(INSTALL) -m 755 scripts/ast_logescalator "$(DESTDIR)$(ASTDATADIR)/scripts/ast_logescalator" $(INSTALL) -m 755 scripts/ast_loggrabber "$(DESTDIR)$(ASTDATADIR)/scripts/ast_loggrabber" $(INSTALL) -m 755 scripts/ast_coredumper "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper" $(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py" uninstall: + -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_logescalator" -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_loggrabber" -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper" -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py" From 7a16524a83f5955624151d69bf1f9fe2b2211a9a Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 30 Jan 2017 10:02:14 -0500 Subject: [PATCH 1006/1578] res_rtp_asterisk: Swap byte-order when sending signed linear Before Asterisk 13, signed linear was converted into network byte order by a smoother before being sent over the network. We restore this behavior by forcing the creation of a smoother when slinear is in use and setting the appropriate flags so that the byte order conversion is always done. ASTERISK-24858 #close Reported-by: Frankie Chin Change-Id: I868449617d1a7819578f218c8c6b2111ad84f5a9 --- res/res_rtp_asterisk.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index c4608db6cc1..3d124000a5f 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -3630,6 +3630,11 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr /* If no smoother is present see if we have to set one up */ if (!rtp->smoother && ast_format_can_be_smoothed(format)) { unsigned int framing_ms = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(instance)); + int is_slinear = ast_format_cache_is_slinear(format); + + if (!framing_ms && is_slinear) { + framing_ms = ast_format_get_default_ms(format); + } if (framing_ms) { rtp->smoother = ast_smoother_new((framing_ms * ast_format_get_minimum_bytes(format)) / ast_format_get_minimum_ms(format)); @@ -3638,6 +3643,9 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr ast_format_get_name(format), framing_ms, ast_format_get_minimum_bytes(format)); return -1; } + if (is_slinear) { + ast_smoother_set_flags(rtp->smoother, AST_SMOOTHER_FLAG_BE); + } } } From aeea634bc0304736f41f440768f50105844a5dda Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 31 Jan 2017 17:17:50 +0000 Subject: [PATCH 1007/1578] res_pjsip: Handle invocation of callback on outgoing request when error occurs. There are some error cases in PJSIP when sending a request that will result in the callback for the request being invoked. The code did not handle this case and assumed on every error case that the callback was not invoked. The code has been changed to check whether the callback has been invoked and if so to absorb the error and treat it as a success. ASTERISK-26679 ASTERISK-26699 Change-Id: I563982ba204da5aa1428989a11c06dd9087fea91 --- res/res_pjsip.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index a7dd09ee8ed..35c1eeb40a9 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3404,6 +3404,8 @@ struct send_request_wrapper { void (*callback)(void *token, pjsip_event *e); /*! Non-zero when the callback is called. */ unsigned int cb_called; + /*! Non-zero if endpt_send_request_cb() was called. */ + unsigned int send_cb_called; /*! Timeout timer. */ pj_timer_entry *timeout_timer; /*! Original timeout. */ @@ -3421,6 +3423,12 @@ static void endpt_send_request_cb(void *token, pjsip_event *e) struct send_request_wrapper *req_wrapper = token; unsigned int cb_called; + /* + * Needed because we cannot otherwise tell if this callback was + * called when pjsip_endpt_send_request() returns error. + */ + req_wrapper->send_cb_called = 1; + if (e->body.tsx_state.type == PJSIP_EVENT_TIMER) { ast_debug(2, "%p: PJSIP tsx timer expired\n", req_wrapper); @@ -3604,12 +3612,10 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, if (ret_val != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; - /* - * endpt_send_request_cb is not expected to ever be called - * because the request didn't get far enough to attempt - * sending. - */ - ao2_ref(req_wrapper, -1); + if (!req_wrapper->send_cb_called) { + /* endpt_send_request_cb is not expected to ever be called now. */ + ao2_ref(req_wrapper, -1); + } /* Complain of failure to send the request. */ pj_strerror(ret_val, errmsg, sizeof(errmsg)); @@ -3646,6 +3652,13 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, req_wrapper->cb_called = 1; } ao2_unlock(req_wrapper); + } else if (req_wrapper->cb_called) { + /* + * We cannot report any error. The callback has + * already freed any resources associated with + * token. + */ + ret_val = PJ_SUCCESS; } } From bbed75c3ba424b63257e1556b79a80242f3b6e2b Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 1 Feb 2017 13:54:50 -0600 Subject: [PATCH 1008/1578] Update qualifies when AOR configuration changes. Prior to this change, qualifies would only update in the following cases: * A reload of res_pjsip.so was issued. * A dynamic contact was re-registered after its AOR's qualify_frequency had been changed This does not work well if you are using realtime for your AORs. You can update your database to have a new qualify_frequency, but the permanent contacts on that AOR will not have their qualifies updated. And the dynamic contacts on that AOR will not have their qualifies updated until the next registration, which could be a long time. This change seeks to fix this problem by making it so that whenever AOR configuration is applied, the contacts pertaining to that AOR have their qualifies updated. Additions from this patch: * AOR sorcery objects now have an apply handler that calls into a newly added function in the OPTIONS code. This causes all contacts associated with that AOR to re-schedule qualifies. * When it is time to qualify a contact, the OPTIONS code checks to see if the AOR can still be retrieved. If not, then qualification is canceled on the contact. Alterations from this patch: * The registrar code no longer updates contact's qualify_frequence and qualify_timeout. There is no point to this since those values already get updated when the AOR changes. * Reloading res_pjsip.so no longer calls the OPTIONS initialization function. Reloading res_pjsip.so results in re-loading AORs, which results in re-scheduling qualifies. Change-Id: I2e7c3316da28f389c45954f24c4e9389abac1121 --- res/res_pjsip.c | 1 - res/res_pjsip/include/res_pjsip_private.h | 12 ++++++ res/res_pjsip/location.c | 8 +++- res/res_pjsip/pjsip_options.c | 45 ++++++++++++++++++++--- res/res_pjsip_registrar.c | 2 - 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index a7dd09ee8ed..ee78732c9bf 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4368,7 +4368,6 @@ AST_TEST_DEFINE(xml_sanitization_exceeds_buffer) static int reload_configuration_task(void *obj) { ast_res_pjsip_reload_configuration(); - ast_res_pjsip_init_options_handling(1); ast_sip_initialize_dns(); return 0; } diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 0bdb63325af..6ddbd1f269d 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -183,6 +183,18 @@ void ast_sip_destroy_global_headers(void); */ int ast_res_pjsip_init_options_handling(int reload); +/*! + * \internal + * \brief Indicate OPTIONS handling for this AOR needs updating. + * + * When AOR configuration is retrieved, it is possible that the + * qualify frequency has changed. The OPTIONs code needs to update + * its qualifies to reflect these changes. + * + * \param aor The AOR that has been retrieved + */ +void ast_res_pjsip_update_options(struct ast_sip_aor *aor); + /*! * \internal Initialize message IP updating handling. * diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 5abfcabadfc..cfe65b18e37 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1137,6 +1137,12 @@ static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object return status ? 0 : -1; } +static int aor_apply_handler(const struct ast_sorcery *sorcery, void *object) +{ + ast_res_pjsip_update_options(object); + return 0; +} + /*! \brief Initialize sorcery with location support */ int ast_sip_initialize_sorcery_location(void) { @@ -1153,7 +1159,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor"); if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, contact_apply_handler) || - ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, NULL)) { + ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, aor_apply_handler)) { return -1; } diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 6fd3c25757a..51987f4de45 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -518,6 +518,18 @@ static int qualify_contact_task(void *obj) static int qualify_contact_sched(const void *obj) { struct sched_data *data = (struct sched_data *) obj; + struct ast_sip_aor *aor; + + /* This helps us to determine if an AOR has been removed + * from configuration, and if so, stop qualifying the + * contact + */ + aor = ast_sip_location_retrieve_aor(data->contact->aor); + if (!aor) { + ao2_ref(data, -1); + return 0; + } + ao2_ref(aor, -1); ao2_ref(data->contact, +1); if (ast_sip_push_task(NULL, qualify_contact_task, data->contact)) { @@ -1164,12 +1176,10 @@ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) struct ast_sip_aor *aor = obj; struct ao2_container *contacts; - if (aor->permanent_contacts) { - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); - ao2_ref(contacts, -1); - } + contacts = ast_sip_location_retrieve_aor_contacts(aor); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); + ao2_ref(contacts, -1); } return 0; @@ -1496,6 +1506,29 @@ int ast_res_pjsip_init_options_handling(int reload) return 0; } +static int unschedule_for_aor_cb(void *obj, void *arg, int flags) +{ + struct sched_data *data = obj; + struct ast_sip_aor *aor = arg; + + if (!strcmp(ast_sorcery_object_get_id(aor), data->contact->aor)) { + AST_SCHED_DEL_UNREF(sched, data->id, ao2_ref(data, -1)); + } + + return 0; +} + +void ast_res_pjsip_update_options(struct ast_sip_aor *aor) +{ + /* This can happen if an AOR is created and applied before OPTIONs code has been initialized */ + if (!sched_qualifies) { + return; + } + + ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_UNLINK, unschedule_for_aor_cb, aor); + qualify_and_schedule_all_cb(aor, NULL, 0); +} + void ast_res_pjsip_cleanup_options_handling(void) { ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options)); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 2db75388900..d190487ac87 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -456,8 +456,6 @@ static int register_aor_core(pjsip_rx_data *rdata, } contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); - contact_update->qualify_frequency = aor->qualify_frequency; - contact_update->authenticate_qualify = aor->authenticate_qualify; if (path_str) { ast_string_field_set(contact_update, path, ast_str_buffer(path_str)); } From 2849b726b680b907be35459f3cdb96a73fc58fd7 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 1 Feb 2017 16:56:50 -0500 Subject: [PATCH 1009/1578] audiohooks: Muting a hook can mute underlying frames If an audiohook is placed on a channel that does not require transcoding, muting that hook will cause the underlying frames to be muted as well. The original patch is from David Woolley but I have modified slightly. ASTERISK-21094 #close Reported by: David Woolley Patches: ASTERISK-21094-Patch-1.8-1.txt (license #5737) patch uploaded by David Woolley Change-Id: Ib2b68c6283e227cbeb5fa478b2d0f625dae338ed --- main/audiohook.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/main/audiohook.c b/main/audiohook.c index 8a0055e4b46..836ae0496fd 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -156,6 +156,11 @@ int ast_audiohook_destroy(struct ast_audiohook *audiohook) return 0; } +#define SHOULD_MUTE(hook, dir) \ + ((ast_test_flag(hook, AST_AUDIOHOOK_MUTE_READ) && (dir == AST_AUDIOHOOK_DIRECTION_READ)) || \ + (ast_test_flag(hook, AST_AUDIOHOOK_MUTE_WRITE) && (dir == AST_AUDIOHOOK_DIRECTION_WRITE)) || \ + (ast_test_flag(hook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE))) + /*! \brief Writes a frame into the audiohook structure * \param audiohook Audiohook structure * \param direction Direction the audio frame came from @@ -171,7 +176,6 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo int our_factory_ms; int other_factory_samples; int other_factory_ms; - int muteme = 0; /* Update last feeding time to be current */ *rwtime = ast_tvnow(); @@ -197,17 +201,6 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo ast_slinfactory_flush(other_factory); } - /* swap frame data for zeros if mute is required */ - if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) || - (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) || - (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE))) { - muteme = 1; - } - - if (muteme && frame->datalen > 0) { - ast_frame_clear(frame); - } - /* Write frame out to respective factory */ ast_slinfactory_feed(factory, frame); @@ -246,8 +239,11 @@ static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audio return NULL; } - /* If a volume adjustment needs to be applied apply it */ - if (vol) { + if (SHOULD_MUTE(audiohook, direction)) { + /* Swap frame data for zeros if mute is required */ + ast_frame_clear(&frame); + } else if (vol) { + /* If a volume adjustment needs to be applied apply it */ ast_frame_adjust_volume(&frame, vol); } @@ -296,8 +292,12 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho if (usable_read) { if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) { read_buf = buf1; - /* Adjust read volume if need be */ - if (audiohook->options.read_volume) { + + if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ))) { + /* Clear the frame data if we are muting */ + memset(buf1, 0, sizeof(buf1)); + } else if (audiohook->options.read_volume) { + /* Adjust read volume if need be */ adjust_value = abs(audiohook->options.read_volume); for (count = 0; count < samples; count++) { if (audiohook->options.read_volume > 0) { @@ -316,8 +316,12 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho if (usable_write) { if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) { write_buf = buf2; - /* Adjust write volume if need be */ - if (audiohook->options.write_volume) { + + if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE))) { + /* Clear the frame data if we are muting */ + memset(buf2, 0, sizeof(buf2)); + } else if (audiohook->options.write_volume) { + /* Adjust write volume if need be */ adjust_value = abs(audiohook->options.write_volume); for (count = 0; count < samples; count++) { if (audiohook->options.write_volume > 0) { From 7d9b50a7b2b202b3f34236bd951f4aaef79a441c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 1 Feb 2017 17:14:53 -0600 Subject: [PATCH 1010/1578] res_resolver_unbound.c: Fix frequent ref leak caught by excessive ref trap. ASTERISK-26765 Change-Id: I27eb97df7f8d7e624b0b9a61c0fcee4718c86d8d --- res/res_resolver_unbound.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/res/res_resolver_unbound.c b/res/res_resolver_unbound.c index 1877bbcc437..3c78050100e 100644 --- a/res/res_resolver_unbound.c +++ b/res/res_resolver_unbound.c @@ -286,13 +286,21 @@ static void unbound_resolver_callback(void *data, int err, struct ub_result *ub_ ub_resolve_free(ub_result); } +static void unbound_resolver_data_dtor(void *vdoomed) +{ + struct unbound_resolver_data *doomed = vdoomed; + + ao2_cleanup(doomed->resolver); +} + static int unbound_resolver_resolve(struct ast_dns_query *query) { struct unbound_config *cfg = ao2_global_obj_ref(globals); struct unbound_resolver_data *data; int res; - data = ao2_alloc_options(sizeof(*data), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); + data = ao2_alloc_options(sizeof(*data), unbound_resolver_data_dtor, + AO2_ALLOC_OPT_LOCK_NOLOCK); if (!data) { ast_log(LOG_ERROR, "Failed to allocate resolver data for resolution of '%s'\n", ast_dns_query_get_name(query)); From 4c51ad158dd43843cc1d3a865d6189c25da9ac46 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 2 Feb 2017 12:26:12 -0500 Subject: [PATCH 1011/1578] res_odbc: Remove deprecated settings from sample configuration file ASTERISK-26704 #close Reported by: Anthony Messina Change-Id: I976a1f94cf79c5f31e76174c61f5c6a65fd6354f --- configs/samples/res_odbc.conf.sample | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/configs/samples/res_odbc.conf.sample b/configs/samples/res_odbc.conf.sample index 42d89ec0fd8..c69f5563755 100644 --- a/configs/samples/res_odbc.conf.sample +++ b/configs/samples/res_odbc.conf.sample @@ -74,13 +74,11 @@ password => mypass pre-connect => yes ; Certain servers, such as MS SQL Server and Sybase use the TDS protocol, which -; limits the number of active queries per connection to 1. By telling res_odbc -; not to share connections, Asterisk can be made to work with these servers. +; limits the number of active queries per connection to 1. [sqlserver] enabled => no dsn => mickeysoft -share_connections => no -limit => 5 +max_connections => 5 username => oscar password => thegrouch pre-connect => yes From 72e3fc58455e08307a06e57099c8362879688ea0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 31 Jan 2017 16:32:18 -0600 Subject: [PATCH 1012/1578] Frame deferral: Revert API refactoring. There are several issues with deferring frames that are caused by the refactoring. 1) The code deferring frames mishandles adding a deferred frame to the deferred queue. As a result the deferred queue can only be one frame long. 2) Deferrable frames can come directly from the channel driver as well as the read queue. These frames need to be added to the deferred queue. 3) Whoever is deferring frames is really only doing the __ast_read() to collect deferred frames and doesn't care about the returned frames except to detect a hangup event. When frame deferral is completed we must make the normal frame processing see the hangup as a frame anyway. As such, there is no need to have varying hangup frame deferral methods. We also need to be aware of the AST_SOFTHANGUP_ASYNCGOTO hangup that isn't real. That fake hangup is to cause the PBX thread to break out of loops to go execute a new dialplan location. 4) To properly deal with deferrable frames from the channel driver as pointed out by (2) above, means that it is possible to process a dialplan interception routine while frames are deferred because of the AST_CONTROL_READ_ACTION control frame. Deferring frames is not implemented as a re-entrant operation so you could have the unsupported case of two sections of code thinking they have control of the media stream. A worse problem is because of the bad implementation of the AMI PlayDTMF action. It can cause two threads to be deferring frames on the same channel at the same time. (ASTERISK_25940) * Rather than fix all these problems simply revert the API refactoring as there is going to be only autoservice and safe_sleep deferring frames anyway. ASTERISK-26343 ASTERISK-26716 #close Change-Id: I45069c779aa3a35b6c863f65245a6df2c7865496 --- include/asterisk/channel.h | 49 ----------------- main/autoservice.c | 66 ++++++++++++++++++++-- main/channel.c | 106 +++++++++--------------------------- main/channel_internal_api.c | 6 -- 4 files changed, 89 insertions(+), 138 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 1b7246b98b6..9cf313fc433 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -967,16 +967,6 @@ enum { * The channel is executing a subroutine or macro */ AST_FLAG_SUBROUTINE_EXEC = (1 << 27), - /*! - * The channel is currently in an operation where - * frames should be deferred. - */ - AST_FLAG_DEFER_FRAMES = (1 << 28), - /*! - * The channel is currently deferring hangup frames - * in addition to other frame types. - */ - AST_FLAG_DEFER_HANGUP_FRAMES = (1 << 29), }; /*! \brief ast_bridge_config flags */ @@ -4727,43 +4717,4 @@ enum ast_channel_error { */ enum ast_channel_error ast_channel_errno(void); -/*! - * \brief Retrieve the deferred read queue. - */ -struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan); - -/*! - * \brief Start deferring deferrable frames on this channel - * - * Sometimes, a channel gets entered into a mode where a "main" application - * is tasked with servicing frames on the channel, but that application does - * not need to act on those frames. However, it would be imprudent to simply - * drop important frames. This function can be called so that important frames - * will be deferred, rather than placed in the channel frame queue as normal. - * - * Hangups are an interesting frame type. Hangups will always be detectable by - * a reader when a channel is deferring frames. If the defer_hangups parameter - * is non-zero, then the hangup frame will also be duplicated and deferred, so - * that the next reader of the channel will get the hangup frame, too. - * - * \pre chan MUST be locked before calling - * - * \param chan The channel on which frames should be deferred - * \param defer_hangups Defer hangups in addition to other deferrable frames - */ -void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups); - -/*! - * \brief Stop deferring deferrable frames on this channel - * - * When it is time to stop deferring frames on the channel, all deferred frames - * will be queued onto the channel's read queue so that the next servicer of - * the channel can handle those frames as necessary. - * - * \pre chan MUST be locked before calling - * - * \param chan The channel on which to stop deferring frames. - */ -void ast_channel_stop_defer_frames(struct ast_channel *chan); - #endif /* _ASTERISK_CHANNEL_H */ diff --git a/main/autoservice.c b/main/autoservice.c index c3f24276c0e..11c9eab969d 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -59,6 +59,10 @@ struct asent { unsigned int use_count; unsigned int orig_end_dtmf_flag:1; unsigned int ignore_frame_types; + /*! Frames go on at the head of deferred_frames, so we have the frames + * from newest to oldest. As we put them at the head of the readq, we'll + * end up with them in the right order for the channel's readq. */ + AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; AST_LIST_ENTRY(asent) list; }; @@ -73,13 +77,19 @@ static int as_chan_list_state; static void *autoservice_run(void *ign) { ast_callid callid = 0; + struct ast_frame hangup_frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_HANGUP, + }; while (!asexit) { struct ast_channel *mons[MAX_AUTOMONS]; + struct asent *ents[MAX_AUTOMONS]; struct ast_channel *chan; struct asent *as; - int x = 0, ms = 50; + int i, x = 0, ms = 50; struct ast_frame *f = NULL; + struct ast_frame *defer_frame = NULL; AST_LIST_LOCK(&aslist); @@ -94,6 +104,7 @@ static void *autoservice_run(void *ign) AST_LIST_TRAVERSE(&aslist, as, list) { if (!ast_check_hangup(as->chan)) { if (x < MAX_AUTOMONS) { + ents[x] = as; mons[x++] = as->chan; } else { ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n"); @@ -121,9 +132,51 @@ static void *autoservice_run(void *ign) ast_callid_threadassoc_change(callid); f = ast_read(chan); - if (f) { + + if (!f) { + /* No frame means the channel has been hung up. + * A hangup frame needs to be queued here as ast_waitfor() may + * never return again for the condition to be detected outside + * of autoservice. So, we'll leave a HANGUP queued up so the + * thread in charge of this channel will know. */ + + defer_frame = &hangup_frame; + } else if (ast_is_deferrable_frame(f)) { + defer_frame = f; + } else { + /* Can't defer. Discard and continue with next. */ ast_frfree(f); + continue; } + + for (i = 0; i < x; i++) { + struct ast_frame *dup_f; + + if (mons[i] != chan) { + continue; + } + + if (!f) { /* defer_frame == &hangup_frame */ + if ((dup_f = ast_frdup(defer_frame))) { + AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); + } + } else { + if ((dup_f = ast_frisolate(defer_frame))) { + AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); + } + if (dup_f != defer_frame) { + ast_frfree(defer_frame); + } + } + + break; + } + /* The ast_waitfor_n() call will only read frames from + * the channels' file descriptors. If ast_waitfor_n() + * returns non-NULL, then one of the channels in the + * mons array must have triggered the return. It's + * therefore impossible that we got here while (i >= x). + * If we did, we'd need to ast_frfree(f) if (f). */ } ast_callid_threadassoc_change(0); @@ -162,7 +215,6 @@ int ast_autoservice_start(struct ast_channel *chan) as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0; if (!as->orig_end_dtmf_flag) ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); - ast_channel_start_defer_frames(chan, 1); ast_channel_unlock(chan); AST_LIST_LOCK(&aslist); @@ -196,6 +248,7 @@ int ast_autoservice_stop(struct ast_channel *chan) { int res = -1; struct asent *as, *removed = NULL; + struct ast_frame *f; int chan_list_state; AST_LIST_LOCK(&aslist); @@ -247,7 +300,12 @@ int ast_autoservice_stop(struct ast_channel *chan) } ast_channel_lock(chan); - ast_channel_stop_defer_frames(chan); + while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) { + if (!((1 << f->frametype) & as->ignore_frame_types)) { + ast_queue_frame_head(chan, f); + } + ast_frfree(f); + } ast_channel_unlock(chan); ast_free(as); diff --git a/main/channel.c b/main/channel.c index 6e88a290673..7c8d3a98906 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1062,25 +1062,6 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const return tmp; } -void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups) -{ - ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); - ast_set2_flag(ast_channel_flags(chan), defer_hangups, AST_FLAG_DEFER_HANGUP_FRAMES); -} - -void ast_channel_stop_defer_frames(struct ast_channel *chan) -{ - struct ast_frame *f; - - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES); - - /* Move the deferred frames onto the channel read queue, ahead of other queued frames */ - while ((f = AST_LIST_REMOVE_HEAD(ast_channel_deferred_readq(chan), frame_list))) { - ast_queue_frame_head(chan, f); - ast_frfree(f); - } -} - static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after) { struct ast_frame *f; @@ -1545,18 +1526,19 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c int res = 0; struct timeval start; int ms; + AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; + + AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); /* If no other generator is present, start silencegen while waiting */ if (ast_opt_transmit_silence && !ast_channel_generatordata(chan)) { silgen = ast_channel_start_silence_generator(chan); } - ast_channel_lock(chan); - ast_channel_start_defer_frames(chan, 0); - ast_channel_unlock(chan); - start = ast_tvnow(); while ((ms = ast_remaining_ms(start, timeout_ms))) { + struct ast_frame *dup_f = NULL; + if (cond && ((*cond)(data) == 0)) { break; } @@ -1571,7 +1553,18 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c res = -1; break; } - ast_frfree(f); + + if (!ast_is_deferrable_frame(f)) { + ast_frfree(f); + continue; + } + + if ((dup_f = ast_frisolate(f))) { + if (dup_f != f) { + ast_frfree(f); + } + AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); + } } } @@ -1580,8 +1573,17 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c ast_channel_stop_silence_generator(chan, silgen); } + /* We need to free all the deferred frames, but we only need to + * queue the deferred frames if there was no error and no + * hangup was received + */ ast_channel_lock(chan); - ast_channel_stop_defer_frames(chan); + while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { + if (!res) { + ast_queue_frame_head(chan, f); + } + ast_frfree(f); + } ast_channel_unlock(chan); return res; @@ -3883,36 +3885,6 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) if (!AST_LIST_EMPTY(ast_channel_readq(chan))) { int skip_dtmf = should_skip_dtmf(chan); - if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) { - AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { - if (ast_is_deferrable_frame(f)) { - if(f->frametype == AST_FRAME_CONTROL && - (f->subclass.integer == AST_CONTROL_HANGUP || - f->subclass.integer == AST_CONTROL_END_OF_Q)) { - /* Hangup is a special case. We want to defer the frame, but we also do not - * want to remove it from the frame queue. So rather than just moving the frame - * over, we duplicate it and move the copy to the deferred readq. - * - * The reason for this? This way, whoever calls ast_read() will get a NULL return - * immediately and can tell the channel has hung up and do what it needs to. Also, - * when frame deferral finishes, then whoever calls ast_read() next will also get - * the hangup. - */ - if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_HANGUP_FRAMES)) { - struct ast_frame *dup; - - dup = ast_frdup(f); - AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), dup, frame_list); - } - } else { - AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), f, frame_list); - AST_LIST_REMOVE_CURRENT(frame_list); - } - } - } - AST_LIST_TRAVERSE_SAFE_END; - } - AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) { /* We have to be picky about which frame we pull off of the readq because * there are cases where we want to leave DTMF frames on the queue until @@ -10361,15 +10333,9 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected); } - ast_channel_start_defer_frames(macro_chan, 0); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); - - ast_channel_lock(macro_chan); - ast_channel_stop_defer_frames(macro_chan); - ast_channel_unlock(macro_chan); - if (!retval) { struct ast_party_connected_line saved_connected; @@ -10417,15 +10383,9 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting); } - ast_channel_start_defer_frames(macro_chan, 0); ast_channel_unlock(macro_chan); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); - - ast_channel_lock(macro_chan); - ast_channel_stop_defer_frames(macro_chan); - ast_channel_unlock(macro_chan); - if (!retval) { struct ast_party_redirecting saved_redirecting; @@ -10466,15 +10426,9 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected); } - ast_channel_start_defer_frames(sub_chan, 0); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); - - ast_channel_lock(sub_chan); - ast_channel_stop_defer_frames(sub_chan); - ast_channel_unlock(sub_chan); - if (!retval) { struct ast_party_connected_line saved_connected; @@ -10515,15 +10469,9 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting); } - ast_channel_start_defer_frames(sub_chan, 0); ast_channel_unlock(sub_chan); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); - - ast_channel_lock(sub_chan); - ast_channel_stop_defer_frames(sub_chan); - ast_channel_unlock(sub_chan); - if (!retval) { struct ast_party_redirecting saved_redirecting; diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 691dec0a17f..a0cbe864378 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -221,7 +221,6 @@ struct ast_channel { struct stasis_cp_single *topics; /*!< Topic for all channel's events */ struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */ struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */ - struct ast_readq_list deferred_readq; }; /*! \brief The monotonically increasing integer counter for channel uniqueids */ @@ -1730,8 +1729,3 @@ enum ast_channel_error ast_channel_internal_errno(void) return *error_code; } - -struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan) -{ - return &chan->deferred_readq; -} From 97c308471d2ead6473499b0026b72f8ed7b516eb Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 31 Jan 2017 16:38:49 -0600 Subject: [PATCH 1013/1578] res_agi: Prevent an AGI from eating frames it should not. (Re-do) A dialplan intercept routine is equivalent to an interrupt routine. As such, the routine must be done quickly and you do not have access to the media stream. These restrictions are necessary because the media stream is the responsibility of some other code and interfering with or delaying that processing is bad. A possible future dialplan processing architecture change may allow the interception routine to run in a different thread from the main thread handling the media and remove the execution time restriction. * Made res_agi.c:run_agi() running an AGI in an interception routine run in DeadAGI mode. No touchy channel frames. ASTERISK-25951 ASTERISK-26343 ASTERISK-26716 Change-Id: I638f147ca7a7f2590d7194a8ef4090eb191e4e43 --- include/asterisk/channel.h | 17 +++++++++++++++++ main/channel.c | 38 ++++++++++++++++++++++++++++++++++++++ res/res_agi.c | 10 ++++++---- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 9cf313fc433..e5f792f1f41 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4717,4 +4717,21 @@ enum ast_channel_error { */ enum ast_channel_error ast_channel_errno(void); +/*! + * \brief Am I currently running an intercept dialplan routine. + * \since 13.14.0 + * + * \details + * A dialplan intercept routine is equivalent to an interrupt + * routine. As such, the routine must be done quickly and you + * do not have access to the media stream. These restrictions + * are necessary because the media stream is the responsibility + * of some other code and interfering with or delaying that + * processing is bad. + * + * \retval 0 Not in an intercept routine. + * \retval 1 In an intercept routine. + */ +int ast_channel_get_intercept_mode(void); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/main/channel.c b/main/channel.c index 7c8d3a98906..1c7743a2fff 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10300,6 +10300,36 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen); } +/*! + * Storage to determine if the current thread is running an intercept dialplan routine. + */ +AST_THREADSTORAGE_RAW(in_intercept_routine); + +/*! + * \internal + * \brief Set the current intercept dialplan routine status mode. + * \since 13.14.0 + * + * \param in_intercept_mode New intercept mode. (Non-zero if in intercept mode) + * + * \return Nothing + */ +static void channel_set_intercept_mode(int in_intercept_mode) +{ + int status; + + status = ast_threadstorage_set_ptr(&in_intercept_routine, + in_intercept_mode ? (void *) 1 : (void *) 0); + if (status) { + ast_log(LOG_ERROR, "Failed to set dialplan intercept mode\n"); + } +} + +int ast_channel_get_intercept_mode(void) +{ + return ast_threadstorage_get_ptr(&in_intercept_routine) ? 1 : 0; +} + int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int is_frame) { static int deprecation_warning = 0; @@ -10335,7 +10365,9 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc } ast_channel_unlock(macro_chan); + channel_set_intercept_mode(1); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); + channel_set_intercept_mode(0); if (!retval) { struct ast_party_connected_line saved_connected; @@ -10385,7 +10417,9 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a } ast_channel_unlock(macro_chan); + channel_set_intercept_mode(1); retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args); + channel_set_intercept_mode(0); if (!retval) { struct ast_party_redirecting saved_redirecting; @@ -10428,7 +10462,9 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct } ast_channel_unlock(sub_chan); + channel_set_intercept_mode(1); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); + channel_set_intercept_mode(0); if (!retval) { struct ast_party_connected_line saved_connected; @@ -10471,7 +10507,9 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast } ast_channel_unlock(sub_chan); + channel_set_intercept_mode(1); retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0); + channel_set_intercept_mode(0); if (!retval) { struct ast_party_redirecting saved_redirecting; diff --git a/res/res_agi.c b/res/res_agi.c index 5e047d4c3dc..557f3497152 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -4073,7 +4073,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch break; } } else if (c) { - ami_res = "Command Not Permitted on a dead channel"; + ami_res = "Command Not Permitted on a dead channel or intercept routine"; resultcode = 511; ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res); @@ -4109,6 +4109,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi const char *sighup_str; const char *exit_on_hangup_str; int exit_on_hangup; + /*! Running in an interception routine is like DeadAGI mode. No touchy the channel frames. */ + int in_intercept = ast_channel_get_intercept_mode(); ast_channel_lock(chan); sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); @@ -4143,7 +4145,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi } } ms = -1; - if (dead) { + if (dead || in_intercept) { c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms); } else if (!ast_check_hangup(chan)) { c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms); @@ -4221,10 +4223,10 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi if (agidebug) ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf); - cmd_status = agi_handle_command(chan, agi, buf, dead); + cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept); switch (cmd_status) { case AGI_RESULT_FAILURE: - if (dead || !ast_check_hangup(chan)) { + if (dead || in_intercept || !ast_check_hangup(chan)) { /* The failure was not because of a hangup. */ returnstatus = AGI_RESULT_FAILURE; } From 50029f585ece50a133180410b6c8fff66ad48e72 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 31 Jan 2017 18:28:15 -0600 Subject: [PATCH 1014/1578] channel.c: Fix unbalanced read queue deadlocking local channels. Using the timerfd timing module can cause channel freezing, lingering, or deadlock issues. The problem is because this is the only timing module that uses an associated alert-pipe. When the alert-pipe becomes unbalanced with respect to the number of frames in the read queue bad things can happen. If the alert-pipe has fewer alerts queued than the read queue then nothing might wake up the thread to handle received frames from the channel driver. For local channels this is the only way to wake up the thread to handle received frames. Being unbalanced in the other direction is less of an issue as it will cause unnecessary reads into the channel driver. ASTERISK-26716 is an example of this deadlock which was indirectly fixed by the change that found the need for this patch. * In channel.c:__ast_queue_frame(): Adding frame lists to the read queue did not add the same number of alerts to the alert-pipe. Correspondingly, when there is an exceptionally long queue event, any removed frames did not also remove the corresponding number of alerts from the alert-pipe. ASTERISK-26632 #close Change-Id: Ia98137c5bf6e9d6d202ce0eb36441851875863f6 --- main/channel.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/main/channel.c b/main/channel.c index 1c7743a2fff..23491933650 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1148,6 +1148,9 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in } AST_LIST_REMOVE_CURRENT(frame_list); ast_frfree(cur); + + /* Read from the alert pipe for each flushed frame. */ + ast_channel_internal_alert_read(chan); } } AST_LIST_TRAVERSE_SAFE_END; @@ -1164,9 +1167,13 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in } if (ast_channel_alert_writable(chan)) { - if (ast_channel_alert_write(chan)) { - ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n", - ast_channel_name(chan), queued_frames, strerror(errno)); + /* Write to the alert pipe for each added frame */ + while (new_frames--) { + if (ast_channel_alert_write(chan)) { + ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n", + ast_channel_name(chan), queued_frames, strerror(errno)); + break; + } } } else if (ast_channel_timingfd(chan) > -1) { ast_timer_enable_continuous(ast_channel_timer(chan)); From 2c8d0764de87037ce52656e13b36de5d9876aeaa Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Sat, 21 Jan 2017 07:57:33 +0200 Subject: [PATCH 1015/1578] openssl 1.1 support: use OPENSSL_VERSION_NUMBER Use OPENSSL_VERSION_NUMBER instead of OPENSSL_API_COMPAT to detect the openssl 1.1 API. Change-Id: I4e448f55ef516aedf6ad154037c35577a421a458 --- main/iostream.c | 6 +++--- main/libasteriskssl.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/main/iostream.c b/main/iostream.c index 22cd5985c4a..6187bc2fbb1 100644 --- a/main/iostream.c +++ b/main/iostream.c @@ -465,19 +465,19 @@ int ast_iostream_close(struct ast_iostream *stream) SSL_get_error(stream->ssl, res)); } -#if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L if (!SSL_is_server(stream->ssl)) { #else if (!stream->ssl->server) { #endif /* For client threads, ensure that the error stack is cleared */ -#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L +#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L #if OPENSSL_VERSION_NUMBER >= 0x10000000L ERR_remove_thread_state(NULL); #else ERR_remove_state(0); #endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ -#endif /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */ +#endif /* !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L */ } SSL_free(stream->ssl); diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c index 9905b150c97..36982e2be1b 100644 --- a/main/libasteriskssl.c +++ b/main/libasteriskssl.c @@ -72,7 +72,7 @@ static void ssl_lock(int mode, int n, const char *file, int line) } } -#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L +#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L int SSL_library_init(void) { #if defined(AST_DEVMODE) @@ -114,7 +114,7 @@ void ERR_free_strings(void) { /* we can't allow this to be called, ever */ } -#endif /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */ +#endif /* !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L */ #endif /* HAVE_OPENSSL */ From bc041ca14afb6b5c786955a03c331dc45924ca92 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Sat, 21 Jan 2017 07:59:15 +0200 Subject: [PATCH 1016/1578] tcptls: use TLS_client_method with OpenSSL 1.1 OpenSSL 1.1 introduced TLS_client_method() and deprecated the previous version-specific methods (such as TLSv1_client_method(). Other than being simpler to use and more correct (gain support for TLS newer that TLS1, in our case), the older ones produce a deprecation warning that fails the build in dev-mode. Change-Id: I257b1c8afd09dcb0d96cda3a41cb9f7a15d0ba07 --- main/tcptls.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main/tcptls.c b/main/tcptls.c index b20e04ef8c5..7f1421db8e0 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -324,12 +324,16 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client) cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method()); } else #endif +#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10100000L) + cfg->ssl_ctx = SSL_CTX_new(TLS_client_method()); +#else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) { cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); } else { disable_ssl = 1; cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); } +#endif } else { disable_ssl = 1; cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); From c6c7f1720608031303418012831f8a644345ad18 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Fri, 3 Feb 2017 10:25:33 +0200 Subject: [PATCH 1017/1578] libasteriskssl: do nothing with OpenSSL >= 1.1 OpenSSL 1.1 requires no explicit initialization. The hacks in the library are not needed. They also happen to fail running Asterisk. Change-Id: I3b3efd5d80234a4c45a8ee58dcfe25b15d9ad100 --- main/libasteriskssl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c index 36982e2be1b..0ed05e3dcbf 100644 --- a/main/libasteriskssl.c +++ b/main/libasteriskssl.c @@ -121,10 +121,13 @@ void ERR_free_strings(void) /*! * \internal * \brief Common OpenSSL initialization for all of Asterisk. + * + * Not needed for OpenSSL versions >= 1.1.0 */ int ast_ssl_init(void) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && defined(OPENSSL_VERSION_NUMBER) && \ + OPENSSL_VERSION_NUMBER < 0x10100000L unsigned int i; int (*real_SSL_library_init)(void); void (*real_CRYPTO_set_id_callback)(unsigned long (*)(void)); @@ -189,7 +192,7 @@ int ast_ssl_init(void) startup_complete = 1; -#endif /* HAVE_OPENSSL */ +#endif /* HAVE_OPENSSL and its version < 1.1 */ return 0; } From 7b280e7ccf326de80b183c4fe305b5ecfaa2094a Mon Sep 17 00:00:00 2001 From: Sebastien Duthil Date: Fri, 3 Feb 2017 16:26:23 -0500 Subject: [PATCH 1018/1578] res_ari: fix memory leak for channelvars In ari.conf, when setting the option channelvars, every Stasis channel snapshot would create a list of variable/value that would not be freed when the snapshot is freed, resulting in a often-recurring memory leak. ASTERISK-26767 #close Change-Id: Ia37dd9d68063d7f879193df02ede293e5ded716d --- main/stasis_channels.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main/stasis_channels.c b/main/stasis_channels.c index 4897af89e7e..dd71b865123 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -195,6 +195,7 @@ static void channel_snapshot_dtor(void *obj) ast_string_field_free_memory(snapshot); ao2_cleanup(snapshot->manager_vars); + ao2_cleanup(snapshot->ari_vars); } struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan) From b47cf1a7d6aba11b145b14883e8c607362756001 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 1 Feb 2017 17:56:13 -0600 Subject: [PATCH 1019/1578] res_pjsip: Fix some off nominal tdata leaks. Change-Id: I243a4be5e7fbfe604923764969c4ee04eee89b9d --- res/res_pjsip.c | 1 + res/res_pjsip_mwi.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 82d06dc629d..347c579912e 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3551,6 +3551,7 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, if (!cb && token) { /* Silly. Without a callback we cannot do anything with token. */ + pjsip_tx_data_dec_ref(tdata); return PJ_EINVAL; } diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 925556ed48d..e625df77a72 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -502,6 +502,7 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag body.subtype = MWI_SUBTYPE; body_text = ast_str_create(64); if (!body_text) { + pjsip_tx_data_dec_ref(tdata); return 0; } @@ -517,6 +518,7 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) { ast_log(LOG_WARNING, "Unable to generate SIP MWI NOTIFY body.\n"); ast_free(body_text); + pjsip_tx_data_dec_ref(tdata); return 0; } From b79cc62057a456e68ba68b76d3664faf5fec8fb8 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 6 Feb 2017 17:40:45 +0000 Subject: [PATCH 1020/1578] res_stasis_device_state: Protect the adding/removing of subscriptions. The adding and removing of device state subscriptions did not protect fully against simultaneous manipulation. In particular the subscribe case allowed a small window where two subscriptions could be added for the same device state instead of just one. This change makes the code hold the subscriptions lock for the entirety of each operation to ensure that two are not occurring at the same time. ASTERISK-26770 Change-Id: I3e7f8eb9d09de440c9024d2dd52029f6f20e725b --- res/res_stasis_device_state.c | 39 ++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c index 8b537591075..e16bd8edddd 100644 --- a/res/res_stasis_device_state.c +++ b/res/res_stasis_device_state.c @@ -146,13 +146,13 @@ static struct device_state_subscription *find_device_state_subscription( .device_name = name }; - return ao2_find(device_state_subscriptions, &dummy_sub, OBJ_SEARCH_OBJECT); + return ao2_find(device_state_subscriptions, &dummy_sub, OBJ_SEARCH_OBJECT | OBJ_NOLOCK); } static void remove_device_state_subscription( struct device_state_subscription *sub) { - ao2_unlink(device_state_subscriptions, sub); + ao2_unlink_flags(device_state_subscriptions, sub, OBJ_NOLOCK); } struct ast_json *stasis_app_device_state_to_json( @@ -344,6 +344,17 @@ static int is_subscribed_device_state(struct stasis_app *app, const char *name) return 0; } +static int is_subscribed_device_state_lock(struct stasis_app *app, const char *name) +{ + int is_subscribed; + + ao2_lock(device_state_subscriptions); + is_subscribed = is_subscribed_device_state(app, name); + ao2_unlock(device_state_subscriptions); + + return is_subscribed; +} + static int subscribe_device_state(struct stasis_app *app, void *obj) { struct device_state_subscription *sub = obj; @@ -362,7 +373,10 @@ static int subscribe_device_state(struct stasis_app *app, void *obj) topic = ast_device_state_topic_all(); } + ao2_lock(device_state_subscriptions); + if (is_subscribed_device_state(app, sub->device_name)) { + ao2_unlock(device_state_subscriptions); ast_debug(3, "App %s is already subscribed to %s\n", stasis_app_name(app), sub->device_name); return 0; } @@ -371,6 +385,7 @@ static int subscribe_device_state(struct stasis_app *app, void *obj) sub->sub = stasis_subscribe_pool(topic, device_state_cb, ao2_bump(sub)); if (!sub->sub) { + ao2_unlock(device_state_subscriptions); ast_log(LOG_ERROR, "Unable to subscribe to device %s\n", sub->device_name); /* Reference we added when attempting to stasis_subscribe_pool */ @@ -378,15 +393,25 @@ static int subscribe_device_state(struct stasis_app *app, void *obj) return -1; } - ao2_link(device_state_subscriptions, sub); + ao2_link_flags(device_state_subscriptions, sub, OBJ_NOLOCK); + ao2_unlock(device_state_subscriptions); + return 0; } static int unsubscribe_device_state(struct stasis_app *app, const char *name) { - RAII_VAR(struct device_state_subscription *, sub, - find_device_state_subscription(app, name), ao2_cleanup); - remove_device_state_subscription(sub); + struct device_state_subscription *sub; + + ao2_lock(device_state_subscriptions); + sub = find_device_state_subscription(app, name); + if (sub) { + remove_device_state_subscription(sub); + } + ao2_unlock(device_state_subscriptions); + + ao2_cleanup(sub); + return 0; } @@ -419,7 +444,7 @@ struct stasis_app_event_source device_state_event_source = { .find = find_device_state, .subscribe = subscribe_device_state, .unsubscribe = unsubscribe_device_state, - .is_subscribed = is_subscribed_device_state, + .is_subscribed = is_subscribed_device_state_lock, .to_json = devices_to_json }; From 5422ec140c274a3bad651401db7c82938275b18b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 7 Feb 2017 18:01:03 +0000 Subject: [PATCH 1021/1578] srv: Fix crash when ast_srv_lookup is used and 0 records are returned. When performing an SRV lookup using the ast_srv_lookup function it did not properly handle the situation where 0 records are returned. If this happened it would wrongly assume that at least one record was present. This change fixes the code so it will exit early if an error occurs or if 0 records are returned. ASTERISK-26772 patches: srv_lookup.patch submitted by nappsoft (license 6822) Change-Id: I09b19081c74e0ad11c12bf54a257243b1bcb2351 --- main/srv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/srv.c b/main/srv.c index ef073a51785..cedad7363f2 100644 --- a/main/srv.c +++ b/main/srv.c @@ -209,7 +209,8 @@ int ast_srv_lookup(struct srv_context **context, const char *service, const char } AST_LIST_HEAD_INIT_NOLOCK(&(*context)->entries); - if ((ast_search_dns(*context, service, C_IN, T_SRV, srv_callback)) < 0) { + if (((ast_search_dns(*context, service, C_IN, T_SRV, srv_callback)) < 1) || + AST_LIST_EMPTY(&(*context)->entries)) { ast_free(*context); *context = NULL; return -1; From 46147a8f3013ba7fcf326e1b2d6e1b6c4ad68202 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 8 Feb 2017 11:50:11 -0600 Subject: [PATCH 1022/1578] Revert "Update qualifies when AOR configuration changes." This reverts commit 6492e91392b8fd394193e411c6eb64b45486093f. The change in question was intended to prevent the need to reload in order to update qualifies on contacts when an AOR changes. However, this ended up causing a deadlock instead. Change-Id: I1a835c90a5bb65b6dc3a1e94cddc12a4afc3d71e --- res/res_pjsip.c | 1 + res/res_pjsip/include/res_pjsip_private.h | 12 ------ res/res_pjsip/location.c | 8 +--- res/res_pjsip/pjsip_options.c | 45 +++-------------------- res/res_pjsip_registrar.c | 2 + 5 files changed, 10 insertions(+), 58 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 347c579912e..59777c94ff7 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4382,6 +4382,7 @@ AST_TEST_DEFINE(xml_sanitization_exceeds_buffer) static int reload_configuration_task(void *obj) { ast_res_pjsip_reload_configuration(); + ast_res_pjsip_init_options_handling(1); ast_sip_initialize_dns(); return 0; } diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 6ddbd1f269d..0bdb63325af 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -183,18 +183,6 @@ void ast_sip_destroy_global_headers(void); */ int ast_res_pjsip_init_options_handling(int reload); -/*! - * \internal - * \brief Indicate OPTIONS handling for this AOR needs updating. - * - * When AOR configuration is retrieved, it is possible that the - * qualify frequency has changed. The OPTIONs code needs to update - * its qualifies to reflect these changes. - * - * \param aor The AOR that has been retrieved - */ -void ast_res_pjsip_update_options(struct ast_sip_aor *aor); - /*! * \internal Initialize message IP updating handling. * diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index cfe65b18e37..5abfcabadfc 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1137,12 +1137,6 @@ static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object return status ? 0 : -1; } -static int aor_apply_handler(const struct ast_sorcery *sorcery, void *object) -{ - ast_res_pjsip_update_options(object); - return 0; -} - /*! \brief Initialize sorcery with location support */ int ast_sip_initialize_sorcery_location(void) { @@ -1159,7 +1153,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor"); if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, contact_apply_handler) || - ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, aor_apply_handler)) { + ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, NULL)) { return -1; } diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 51987f4de45..6fd3c25757a 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -518,18 +518,6 @@ static int qualify_contact_task(void *obj) static int qualify_contact_sched(const void *obj) { struct sched_data *data = (struct sched_data *) obj; - struct ast_sip_aor *aor; - - /* This helps us to determine if an AOR has been removed - * from configuration, and if so, stop qualifying the - * contact - */ - aor = ast_sip_location_retrieve_aor(data->contact->aor); - if (!aor) { - ao2_ref(data, -1); - return 0; - } - ao2_ref(aor, -1); ao2_ref(data->contact, +1); if (ast_sip_push_task(NULL, qualify_contact_task, data->contact)) { @@ -1176,10 +1164,12 @@ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) struct ast_sip_aor *aor = obj; struct ao2_container *contacts; - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); - ao2_ref(contacts, -1); + if (aor->permanent_contacts) { + contacts = ast_sip_location_retrieve_aor_contacts(aor); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); + ao2_ref(contacts, -1); + } } return 0; @@ -1506,29 +1496,6 @@ int ast_res_pjsip_init_options_handling(int reload) return 0; } -static int unschedule_for_aor_cb(void *obj, void *arg, int flags) -{ - struct sched_data *data = obj; - struct ast_sip_aor *aor = arg; - - if (!strcmp(ast_sorcery_object_get_id(aor), data->contact->aor)) { - AST_SCHED_DEL_UNREF(sched, data->id, ao2_ref(data, -1)); - } - - return 0; -} - -void ast_res_pjsip_update_options(struct ast_sip_aor *aor) -{ - /* This can happen if an AOR is created and applied before OPTIONs code has been initialized */ - if (!sched_qualifies) { - return; - } - - ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_UNLINK, unschedule_for_aor_cb, aor); - qualify_and_schedule_all_cb(aor, NULL, 0); -} - void ast_res_pjsip_cleanup_options_handling(void) { ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options)); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index d190487ac87..2db75388900 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -456,6 +456,8 @@ static int register_aor_core(pjsip_rx_data *rdata, } contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); + contact_update->qualify_frequency = aor->qualify_frequency; + contact_update->authenticate_qualify = aor->authenticate_qualify; if (path_str) { ast_string_field_set(contact_update, path, ast_str_buffer(path_str)); } From 648d181d2fb62284eb7a2284221b48240a0e876e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 10 Feb 2017 08:35:51 -0700 Subject: [PATCH 1023/1578] configs/samples: Fix placement of 'identify' entry in sorcery.conf The entry for 'identify' was incorrectly placed in the res_pjsip section when it should be in res_pjsip_endpoint_identifier_ip. ASTERISK-26785 #close Change-Id: Ia1372b12a952bfe2df6b1b1e0e725ca306a5d41a --- configs/samples/sorcery.conf.sample | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/samples/sorcery.conf.sample b/configs/samples/sorcery.conf.sample index 7406214fbe3..7e95883854e 100644 --- a/configs/samples/sorcery.conf.sample +++ b/configs/samples/sorcery.conf.sample @@ -64,4 +64,6 @@ test=memory ;auth=realtime,ps_auths ;aor=realtime,ps_aors ;domain_alias=realtime,ps_domain_aliases + +;[res_pjsip_endpoint_identifier_ip] ;identify=realtime,ps_endpoint_id_ips From bab4885f1e923a252209db8b6011cf8a2fcb30c5 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 7 Feb 2017 12:56:41 +0000 Subject: [PATCH 1024/1578] stream: Add media stream definition and API with unit tests. This change adds the media stream definition and API for accessing and using it. Unit tests have also been written which exercise aspects of the API. ASTERISK-26773 Change-Id: I3dbe54065b55aaa51f467e1a3bafd67fb48cac87 --- include/asterisk/stream.h | 182 ++++++++++++++++++++++++++++ main/stream.c | 128 ++++++++++++++++++++ tests/test_stream.c | 245 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 555 insertions(+) create mode 100644 include/asterisk/stream.h create mode 100644 main/stream.c create mode 100644 tests/test_stream.c diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h new file mode 100644 index 00000000000..e73ed3fe7a7 --- /dev/null +++ b/include/asterisk/stream.h @@ -0,0 +1,182 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Media Stream API + * + * \author Joshua Colp + */ + +#ifndef _AST_STREAM_H_ +#define _AST_STREAM_H_ + +#include "asterisk/codec.h" + +/*! + * \brief Forward declaration for a stream, as it is opaque + */ +struct ast_stream; + +/*! + * \brief Forward declaration for a format capability + */ +struct ast_format_cap; + +/*! + * \brief States that a stream may be in + */ +enum ast_stream_state { + /*! + * \brief Set when the stream has been removed + */ + AST_STREAM_STATE_REMOVED = 0, + /*! + * \brief Set when the stream is sending and receiving media + */ + AST_STREAM_STATE_SENDRECV, + /*! + * \brief Set when the stream is sending media only + */ + AST_STREAM_STATE_SENDONLY, + /*! + * \brief Set when the stream is receiving media only + */ + AST_STREAM_STATE_RECVONLY, + /*! + * \brief Set when the stream is not sending OR receiving media + */ + AST_STREAM_STATE_INACTIVE, +}; + +/*! + * \brief Create a new media stream representation + * + * \param name A name for the stream + * \param type The media type the stream is handling + * + * \retval non-NULL success + * \retval NULL failure + * + * \note This is NOT an AO2 object and has no locking. It is expected that a higher level object provides protection. + * + * \note The stream will default to an inactive state until changed. + * + * \since 15 + */ +struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type); + +/*! + * \brief Destroy a media stream representation + * + * \param stream The media stream + * + * \since 15 + */ +void ast_stream_destroy(struct ast_stream *stream); + +/*! + * \brief Get the name of a stream + * + * \param stream The media stream + * + * \return The name of the stream + * + * \since 15 + */ +const char *ast_stream_get_name(const struct ast_stream *stream); + +/*! + * \brief Get the media type of a stream + * + * \param stream The media stream + * + * \return The media type of the stream + * + * \since 15 + */ +enum ast_media_type ast_stream_get_type(const struct ast_stream *stream); + +/*! + * \brief Change the media type of a stream + * + * \param stream The media stream + * \param type The new media type + * + * \since 15 + */ +void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type); + +/*! + * \brief Get the current negotiated formats of a stream + * + * \param stream The media stream + * + * \return The negotiated media formats + * + * \note The reference count is not increased + * + * \since 15 + */ +struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream); + +/*! + * \brief Set the current negotiated formats of a stream + * + * \param stream The media stream + * \param caps The current negotiated formats + * + * \since 15 + */ +void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps); + +/*! + * \brief Get the current state of a stream + * + * \param stream The media stream + * + * \return The state of the stream + * + * \since 15 + */ +enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream); + +/*! + * \brief Set the state of a stream + * + * \param stream The media stream + * \param state The new state that the stream is in + * + * \note Used by stream creator to update internal state + * + * \since 15 + */ +void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state); + +/*! + * \brief Get the number of the stream + * + * \param stream The media stream + * + * \return The number of the stream + * + * \since 15 + */ +unsigned int ast_stream_get_num(const struct ast_stream *stream); + +#endif /* _AST_STREAM_H */ diff --git a/main/stream.c b/main/stream.c new file mode 100644 index 00000000000..fb3dbd5ce5d --- /dev/null +++ b/main/stream.c @@ -0,0 +1,128 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Media Stream API + * + * \author Joshua Colp + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +#include "asterisk/logger.h" +#include "asterisk/stream.h" +#include "asterisk/strings.h" + +struct ast_stream { + /*! + * \brief The type of media the stream is handling + */ + enum ast_media_type type; + + /*! + * \brief Unique number for the stream within the context of the channel it is on + */ + unsigned int num; + + /*! + * \brief Current formats negotiated on the stream + */ + struct ast_format_cap *formats; + + /*! + * \brief The current state of the stream + */ + enum ast_stream_state state; + + /*! + * \brief Name for the stream within the context of the channel it is on + */ + char name[0]; +}; + +struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type) +{ + struct ast_stream *stream; + + stream = ast_calloc(1, sizeof(*stream) + strlen(S_OR(name, "")) + 1); + if (!stream) { + return NULL; + } + + stream->type = type; + stream->state = AST_STREAM_STATE_INACTIVE; + strcpy(stream->name, S_OR(name, "")); + + return stream; +} + +void ast_stream_destroy(struct ast_stream *stream) +{ + if (!stream) { + return; + } + + ao2_cleanup(stream->formats); + ast_free(stream); +} + +const char *ast_stream_get_name(const struct ast_stream *stream) +{ + return stream->name; +} + +enum ast_media_type ast_stream_get_type(const struct ast_stream *stream) +{ + return stream->type; +} + +void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type) +{ + stream->type = type; +} + +struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream) +{ + return stream->formats; +} + +void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps) +{ + ao2_cleanup(stream->formats); + stream->formats = ao2_bump(caps); +} + +enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream) +{ + return stream->state; +} + +void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state) +{ + stream->state = state; +} + +unsigned int ast_stream_get_num(const struct ast_stream *stream) +{ + return stream->num; +} diff --git a/tests/test_stream.c b/tests/test_stream.c new file mode 100644 index 00000000000..fd78dda971a --- /dev/null +++ b/tests/test_stream.c @@ -0,0 +1,245 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Media Stream API Unit Tests + * + * \author Joshua Colp + * + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" + +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/stream.h" +#include "asterisk/format.h" +#include "asterisk/format_cap.h" + +AST_TEST_DEFINE(stream_create) +{ + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_create"; + info->category = "/main/stream/"; + info->summary = "stream create unit test"; + info->description = + "Test that creating a stream results in a stream with the expected values"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_state(stream) != AST_STREAM_STATE_INACTIVE) { + ast_test_status_update(test, "Newly created stream does not have expected inactive stream state\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) { + ast_test_status_update(test, "Newly created stream does not have expected audio media type\n"); + return AST_TEST_FAIL; + } + + if (strcmp(ast_stream_get_name(stream), "test")) { + ast_test_status_update(test, "Newly created stream does not have expected name of test\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_create_no_name) +{ + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_create_no_name"; + info->category = "/main/stream/"; + info->summary = "stream create (without a name) unit test"; + info->description = + "Test that creating a stream with no name works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + stream = ast_stream_create(NULL, AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_set_type) +{ + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_set_type"; + info->category = "/main/stream/"; + info->summary = "stream type setting unit test"; + info->description = + "Test that changing the type of a stream works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) { + ast_test_status_update(test, "Newly created stream does not have expected audio media type\n"); + return AST_TEST_FAIL; + } + + ast_stream_set_type(stream, AST_MEDIA_TYPE_VIDEO); + + if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_VIDEO) { + ast_test_status_update(test, "Changed stream does not have expected video media type\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_set_formats) +{ + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_set_formats"; + info->category = "/main/stream/"; + info->summary = "stream formats setting unit test"; + info->description = + "Test that changing the formats of a stream works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Failed to create a format capabilities structure for testing\n"); + return AST_TEST_FAIL; + } + + stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); + return AST_TEST_FAIL; + } + + ast_stream_set_formats(stream, caps); + + if (ast_stream_get_formats(stream) != caps) { + ast_test_status_update(test, "Changed stream does not have expected formats\n"); + return AST_TEST_FAIL; + } + + ast_stream_set_formats(stream, NULL); + + if (ast_stream_get_formats(stream)) { + ast_test_status_update(test, "Retrieved formats from stream despite removing them\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_set_state) +{ + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_set_state"; + info->category = "/main/stream/"; + info->summary = "stream state setting unit test"; + info->description = + "Test that changing the state of a stream works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_state(stream) != AST_STREAM_STATE_INACTIVE) { + ast_test_status_update(test, "Newly created stream does not have expected inactive stream state\n"); + return AST_TEST_FAIL; + } + + ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV); + + if (ast_stream_get_state(stream) != AST_STREAM_STATE_SENDRECV) { + ast_test_status_update(test, "Changed stream does not have expected sendrecv state\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(stream_create); + AST_TEST_UNREGISTER(stream_create_no_name); + AST_TEST_UNREGISTER(stream_set_type); + AST_TEST_UNREGISTER(stream_set_formats); + AST_TEST_UNREGISTER(stream_set_state); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(stream_create); + AST_TEST_REGISTER(stream_create_no_name); + AST_TEST_REGISTER(stream_set_type); + AST_TEST_REGISTER(stream_set_formats); + AST_TEST_REGISTER(stream_set_state); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Media Stream API test module"); From 16fdb11bc3bb23a2fd645a24a7ba56d9708960ff Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 8 Feb 2017 14:27:18 -0600 Subject: [PATCH 1025/1578] core: Cleanup some channel snapshot staging anomalies. We shouldn't unlock the channel after starting a snapshot staging because another thread may interfere and do its own snapshot staging. * app_dial.c:dial_exec_full() made hold the channel lock while setting up the outgoing channel staging. Made hold the channel lock after the called party answers while updating the caller channel staging. * chan_sip.c:sip_new() completed the channel staging on off-nominal exit. Also we need to use ast_hangup() instead of ast_channel_unref() at that location. * channel.c:__ast_channel_alloc_ap() added a comment about not needing to complete the channel snapshot staging on off-nominal exit paths. * rtp_engine.c:ast_rtp_instance_set_stats_vars() made hold the channel locks while staging the channels for the stats channel variables. Change-Id: Iefb6336893163f6447bad65568722ad5d5d8212a --- apps/app_dial.c | 26 +++++++++++++++----------- channels/chan_sip.c | 4 +++- main/channel.c | 21 ++++++++++++--------- main/rtp_engine.c | 14 ++++++-------- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index 2f5935d19c3..1cb91811fed 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -2541,16 +2541,14 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast continue; } - ast_channel_lock(tc); - ast_channel_stage_snapshot(tc); - ast_channel_unlock(tc); - ast_channel_get_device_name(tc, device_name, sizeof(device_name)); if (!ignore_cc) { ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, device_name); } ast_channel_lock_both(tc, chan); + ast_channel_stage_snapshot(tc); + pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number); /* Setup outgoing SDP to match incoming one */ @@ -2566,7 +2564,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast ast_channel_appl_set(tc, "AppDial"); ast_channel_data_set(tc, "(Outgoing Line)"); - ast_channel_publish_snapshot(tc); memset(ast_channel_whentohangup(tc), 0, sizeof(*ast_channel_whentohangup(tc))); @@ -2791,15 +2788,14 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast } } else { const char *number; + const char *name; int dial_end_raised = 0; int cause = -1; - if (ast_test_flag64(&opts, OPT_CALLER_ANSWER)) + if (ast_test_flag64(&opts, OPT_CALLER_ANSWER)) { ast_answer(chan); + } - strcpy(pa.status, "ANSWER"); - ast_channel_stage_snapshot(chan); - pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); /* Ah ha! Someone answered within the desired timeframe. Of course after this we will always return with -1 so that it is hung up properly after the conversation. */ @@ -2821,10 +2817,10 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast hanguptree(&out_chans, peer, cause >= 0 ? cause : AST_CAUSE_ANSWERED_ELSEWHERE); /* If appropriate, log that we have a destination channel and set the answer time */ - if (ast_channel_name(peer)) - pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer)); ast_channel_lock(peer); + name = ast_strdupa(ast_channel_name(peer)); + number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); if (ast_strlen_zero(number)) { number = NULL; @@ -2832,8 +2828,16 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast number = ast_strdupa(number); } ast_channel_unlock(peer); + ast_channel_lock(chan); + ast_channel_stage_snapshot(chan); + + strcpy(pa.status, "ANSWER"); + pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); + + pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", name); pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number); + ast_channel_stage_snapshot_done(chan); ast_channel_unlock(chan); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 3bb6e74b6da..5da134086e0 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -8141,7 +8141,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit if (!fmt) { ast_log(LOG_WARNING, "No compatible formats could be found for %s\n", ast_channel_name(tmp)); ao2_ref(caps, -1); - tmp = ast_channel_unref(tmp); + ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); + ast_hangup(tmp); return NULL; } } diff --git a/main/channel.c b/main/channel.c index 23491933650..992c940861d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -823,7 +823,12 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_channel_stage_snapshot(tmp); if (!(nativeformats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - /* format capabilities structure allocation failure */ + /* + * Aborting the channel creation. We do not need to complete staging + * the channel snapshot because the channel has not been finalized or + * linked into the channels container yet. Nobody else knows about + * this channel nor will anybody ever know about it. + */ return ast_channel_unref(tmp); } ast_format_cap_append(nativeformats, ast_format_none, 0); @@ -849,6 +854,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char if (!(schedctx = ast_sched_context_create())) { ast_log(LOG_WARNING, "Channel allocation failed: Unable to create schedule context\n"); + /* See earlier channel creation abort comment above. */ return ast_channel_unref(tmp); } ast_channel_sched_set(tmp, schedctx); @@ -863,6 +869,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_channel_caller(tmp)->id.name.valid = 1; ast_channel_caller(tmp)->id.name.str = ast_strdup(cid_name); if (!ast_channel_caller(tmp)->id.name.str) { + /* See earlier channel creation abort comment above. */ return ast_channel_unref(tmp); } } @@ -870,6 +877,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_channel_caller(tmp)->id.number.valid = 1; ast_channel_caller(tmp)->id.number.str = ast_strdup(cid_num); if (!ast_channel_caller(tmp)->id.number.str) { + /* See earlier channel creation abort comment above. */ return ast_channel_unref(tmp); } } @@ -883,6 +891,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char } if (needqueue && ast_channel_internal_alertpipe_init(tmp)) { + /* See earlier channel creation abort comment above. */ return ast_channel_unref(tmp); } @@ -974,20 +983,14 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char if (assignedids && (does_id_conflict(assignedids->uniqueid) || does_id_conflict(assignedids->uniqueid2))) { ast_channel_internal_errno_set(AST_CHANNEL_ERROR_ID_EXISTS); ao2_unlock(channels); - /* This is a bit unorthodox, but we can't just call ast_channel_stage_snapshot_done() - * because that will result in attempting to publish the channel snapshot. That causes - * badness in some places, such as CDRs. So we need to manually clear the flag on the - * channel that says that a snapshot is being cleared. - */ - ast_clear_flag(ast_channel_flags(tmp), AST_FLAG_SNAPSHOT_STAGE); ast_channel_unlock(tmp); + /* See earlier channel creation abort comment above. */ return ast_channel_unref(tmp); } + /* Finalize and link into the channels container. */ ast_channel_internal_finalize(tmp); - ast_atomic_fetchadd_int(&chancount, +1); - ao2_link_flags(channels, tmp, OBJ_NOLOCK); ao2_unlock(channels); diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 3ef2d876bfa..a4654631869 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -1899,16 +1899,16 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in { char quality_buf[AST_MAX_USER_FIELD]; char *quality; - struct ast_channel *bridge = ast_channel_bridge_peer(chan); + struct ast_channel *bridge; - ast_channel_lock(chan); - ast_channel_stage_snapshot(chan); - ast_channel_unlock(chan); + bridge = ast_channel_bridge_peer(chan); if (bridge) { - ast_channel_lock(bridge); + ast_channel_lock_both(chan, bridge); ast_channel_stage_snapshot(bridge); - ast_channel_unlock(bridge); + } else { + ast_channel_lock(chan); } + ast_channel_stage_snapshot(chan); quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)); @@ -1946,11 +1946,9 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in } } - ast_channel_lock(chan); ast_channel_stage_snapshot_done(chan); ast_channel_unlock(chan); if (bridge) { - ast_channel_lock(bridge); ast_channel_stage_snapshot_done(bridge); ast_channel_unlock(bridge); ast_channel_unref(bridge); From 0910773077f065a45e975c1a5914be084d9a4bdc Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 9 Feb 2017 11:01:22 -0500 Subject: [PATCH 1026/1578] manager: Restore Originate failure behavior from Asterisk 11 In Asterisk 11, if the 'Originate' AMI command failed to connect the provided Channel while in extension mode, a 'failed' extension would be looked up and run. This was, I believe, unintentionally removed in 51b6c49. This patch restores that behavior. This also adds an enum for the various 'synchronous' modes in an attempt to make them meaningful. ASTERISK-26115 #close Reported by: Nasir Iqbal Change-Id: I8afbd06725e99610e02adb529137d4800c05345d --- apps/app_originate.c | 10 ++++++---- funcs/func_periodic_hook.c | 4 ++-- include/asterisk/pbx.h | 29 +++++++++++++++++++++-------- main/manager.c | 15 +++++++++++---- main/pbx.c | 2 +- pbx/pbx_spool.c | 10 ++++++---- res/res_clioriginate.c | 8 ++++++-- 7 files changed, 53 insertions(+), 25 deletions(-) diff --git a/apps/app_originate.c b/apps/app_originate.c index cf4ef8ef38c..8edccc720fa 100644 --- a/apps/app_originate.c +++ b/apps/app_originate.c @@ -242,15 +242,17 @@ static int originate_exec(struct ast_channel *chan, const char *data) chantech, chandata, args.arg1, exten, priority); ast_pbx_outgoing_exten_predial(chantech, cap_slin, chandata, - timeout * 1000, args.arg1, exten, priority, &outgoing_status, 1, NULL, - NULL, NULL, NULL, NULL, 0, NULL, predial_callee); + timeout * 1000, args.arg1, exten, priority, &outgoing_status, + AST_OUTGOING_WAIT, NULL, NULL, NULL, NULL, NULL, 0, NULL, + predial_callee); } else if (!strcasecmp(args.type, "app")) { ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n", chantech, chandata, args.arg1, S_OR(args.arg2, "")); ast_pbx_outgoing_app_predial(chantech, cap_slin, chandata, - timeout * 1000, args.arg1, args.arg2, &outgoing_status, 1, NULL, - NULL, NULL, NULL, NULL, NULL, predial_callee); + timeout * 1000, args.arg1, args.arg2, &outgoing_status, + AST_OUTGOING_WAIT, NULL, NULL, NULL, NULL, NULL, NULL, + predial_callee); } else { ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n", args.type); diff --git a/funcs/func_periodic_hook.c b/funcs/func_periodic_hook.c index aae2abc90ec..f8e79b326af 100644 --- a/funcs/func_periodic_hook.c +++ b/funcs/func_periodic_hook.c @@ -181,8 +181,8 @@ static void *hook_launch_thread(void *data) }; ast_pbx_outgoing_exten("Local", NULL, full_exten_name, 60, - arg->context, arg->exten, 1, NULL, 0, NULL, NULL, &chan_name_var, - NULL, NULL, 1, NULL); + arg->context, arg->exten, 1, NULL, AST_OUTGOING_NO_WAIT, + NULL, NULL, &chan_name_var, NULL, NULL, 1, NULL); hook_thread_arg_destroy(arg); diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 386f3c38bc9..008cfd3cbf9 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1144,6 +1144,12 @@ int ast_async_goto(struct ast_channel *chan, const char *context, const char *ex */ int ast_async_goto_by_name(const char *chan, const char *context, const char *exten, int priority); +enum ast_pbx_outgoing_sync { + AST_OUTGOING_NO_WAIT = 0, /*!< Don't wait for originated call to answer */ + AST_OUTGOING_WAIT = 1, /*!< Wait for originated call to answer */ + AST_OUTGOING_WAIT_COMPLETE = 2, /*!< Wait for originated call to answer and hangup */ +}; + /*! * \brief Synchronously or asynchronously make an outbound call and send it to a * particular extension @@ -1157,11 +1163,15 @@ int ast_async_goto_by_name(const char *chan, const char *context, const char *ex * \param priority The destination priority for the outbound channel * \param reason Optional. If provided, the dialed status of the outgoing channel. * Codes are AST_CONTROL_xxx values. Valid only if synchronous is non-zero. - * \param synchronous If zero then don't wait for anything. - * If one then block until the outbound channel answers or the call fails. - * If greater than one then wait for the call to complete or if the call doesn't - * answer and failed@context exists then run a channel named OutgoingSpoolFailed - * at failed@context. + * \param synchronous defined by the ast_pbx_outgoing_sync enum. + * If \c AST_OUTGOING_NO_WAIT then don't wait for anything. + * If \c AST_OUTGOING_WAIT then block until the outbound channel answers or + * the call fails. + * If \c AST_OUTGOING_WAIT_COMPLETE then wait for the call to complete or + * fail. + * If \c AST_OUTGOING_WAIT or \c AST_OUTGOING_WAIT_COMPLETE is specified, + * the call doesn't answer, and \c failed@context exists then run a channel + * named \c OutgoingSpoolFailed at \c failed@context. * \param cid_num The caller ID number to set on the outbound channel * \param cid_name The caller ID name to set on the outbound channel * \param vars Variables to set on the outbound channel @@ -1201,9 +1211,12 @@ int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, * \param appdata Data to pass to the application * \param reason Optional. If provided, the dialed status of the outgoing channel. * Codes are AST_CONTROL_xxx values. Valid only if synchronous is non-zero. - * \param synchronous If zero then don't wait for anything. - * If one then block until the outbound channel answers or the call fails. - * If greater than one then wait for the call to complete. + * \param synchronous defined by the ast_pbx_outgoing_sync enum. + * If \c AST_OUTGOING_NO_WAIT then don't wait for anything. + * If \c AST_OUTGOING_WAIT then block until the outbound channel answers or + * the call fails. + * If \c AST_OUTGOING_WAIT_COMPLETE then wait for the call to complete or + * fail. * \param cid_num The caller ID number to set on the outbound channel * \param cid_name The caller ID name to set on the outbound channel * \param vars Variables to set on the outbound channel diff --git a/main/manager.c b/main/manager.c index dfe056438dc..a25497fd323 100644 --- a/main/manager.c +++ b/main/manager.c @@ -5130,13 +5130,15 @@ static void *fast_originate(void *data) if (!ast_strlen_zero(in->app)) { res = ast_pbx_outgoing_app(in->tech, in->cap, in->data, - in->timeout, in->app, in->appdata, &reason, 1, + in->timeout, in->app, in->appdata, &reason, + AST_OUTGOING_WAIT, S_OR(in->cid_num, NULL), S_OR(in->cid_name, NULL), in->vars, in->account, &chan, &assignedids); } else { res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data, - in->timeout, in->context, in->exten, in->priority, &reason, 1, + in->timeout, in->context, in->exten, in->priority, &reason, + AST_OUTGOING_WAIT, S_OR(in->cid_num, NULL), S_OR(in->cid_name, NULL), in->vars, in->account, &chan, in->early_media, &assignedids); @@ -5607,11 +5609,16 @@ static int action_originate(struct mansession *s, const struct message *m) } } } else if (!ast_strlen_zero(app)) { - res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL, assignedids.uniqueid ? &assignedids : NULL); + res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, + AST_OUTGOING_WAIT, l, n, vars, account, NULL, + assignedids.uniqueid ? &assignedids : NULL); ast_variables_destroy(vars); } else { if (exten && context && pi) { - res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL, bridge_early, assignedids.uniqueid ? &assignedids : NULL); + res = ast_pbx_outgoing_exten(tech, cap, data, to, + context, exten, pi, &reason, AST_OUTGOING_WAIT, + l, n, vars, account, NULL, bridge_early, + assignedids.uniqueid ? &assignedids : NULL); ast_variables_destroy(vars); } else { astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'"); diff --git a/main/pbx.c b/main/pbx.c index 3e35a3a14c5..47e0b0eda0d 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -7876,7 +7876,7 @@ int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, early_media, assignedids, predial_callee); if (res < 0 /* Call failed to get connected for some reason. */ - && 1 < synchronous + && 0 < synchronous && ast_exists_extension(NULL, context, "failed", 1, NULL)) { struct ast_channel *failed; diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c index dcd2ce73421..ba91d66ab8e 100644 --- a/pbx/pbx_spool.c +++ b/pbx/pbx_spool.c @@ -397,15 +397,17 @@ static void *attempt_thread(void *data) int res, reason; if (!ast_strlen_zero(o->app)) { ast_verb(3, "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries); - res = ast_pbx_outgoing_app(o->tech, o->capabilities, o->dest, o->waittime * 1000, - o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, + res = ast_pbx_outgoing_app(o->tech, o->capabilities, o->dest, + o->waittime * 1000, o->app, o->data, &reason, + AST_OUTGOING_WAIT_COMPLETE, o->cid_num, o->cid_name, o->vars, o->account, NULL, NULL); } else { ast_verb(3, "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries); res = ast_pbx_outgoing_exten(o->tech, o->capabilities, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, - 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL, - ast_test_flag(&o->options, SPOOL_FLAG_EARLY_MEDIA), NULL); + AST_OUTGOING_WAIT_COMPLETE, o->cid_num, o->cid_name, + o->vars, o->account, NULL, ast_test_flag(&o->options, SPOOL_FLAG_EARLY_MEDIA), + NULL); } if (res) { ast_log(LOG_NOTICE, "Call failed to go through, reason (%d) %s\n", reason, ast_channel_reason2str(reason)); diff --git a/res/res_clioriginate.c b/res/res_clioriginate.c index 37df8ed6580..3ea89d8c9e1 100644 --- a/res/res_clioriginate.c +++ b/res/res_clioriginate.c @@ -72,7 +72,9 @@ static char *orig_app(int fd, const char *chan, const char *app, const char *app return CLI_FAILURE; } ast_format_cap_append(cap, ast_format_slin, 0); - ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL, NULL); + ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, + &reason, AST_OUTGOING_NO_WAIT, NULL, NULL, NULL, NULL, + NULL, NULL); ao2_ref(cap, -1); return CLI_SUCCESS; @@ -116,7 +118,9 @@ static char *orig_exten(int fd, const char *chan, const char *data) return CLI_FAILURE; } ast_format_cap_append(cap, ast_format_slin, 0); - ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL); + ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, + exten, 1, &reason, AST_OUTGOING_NO_WAIT, NULL, NULL, + NULL, NULL, NULL, 0, NULL); ao2_ref(cap, -1); return CLI_SUCCESS; From ce810a892b5f6605cdbb5586ce72c208714437ed Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sat, 11 Feb 2017 11:26:58 -0600 Subject: [PATCH 1027/1578] pjsip_distributor.c: Fix off-nominal tdata ref leak. Change-Id: I571f371d0956a8039b197b4dbd8af6b18843598d --- res/res_pjsip/pjsip_distributor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index 7412445860a..eabfa4ba9c0 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -729,8 +729,7 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) ao2_ref(unid, -1); } ast_sip_report_auth_success(endpoint, rdata); - pjsip_tx_data_dec_ref(tdata); - return PJ_FALSE; + break; case AST_SIP_AUTHENTICATION_FAILED: log_failed_request(rdata, "Failed to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); @@ -743,6 +742,7 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } + pjsip_tx_data_dec_ref(tdata); } return PJ_FALSE; From 07abb39d6a6f14c0fc518d5ed372167888a13000 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sat, 11 Feb 2017 11:25:30 -0600 Subject: [PATCH 1028/1578] res_pjsip.c: Fix inconsistency between warning and action. The original return value corresponded to AST_SIP_AUTHENTICATION_CHALLENGE but we have no authenticator registered to create the challenge. Change-Id: I62368180d774b497411b80fbaabd0c80841f8512 --- res/res_pjsip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 59777c94ff7..90eb37263cf 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2368,7 +2368,7 @@ enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpo { if (!registered_authenticator) { ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming authentication is successful\n"); - return 0; + return AST_SIP_AUTHENTICATION_SUCCESS; } return registered_authenticator->check_authentication(endpoint, rdata, tdata); } From 89871576b943058b65a7bfbe9df59fbe75f982dd Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 13 Feb 2017 11:05:51 +0000 Subject: [PATCH 1029/1578] channel: Protect flags in ast_waitfor_nandfds operation. The ast_waitfor_nandfds operation will manipulate the flags of channels passed in. This was previously done without the channel lock being held. This could result in incorrect values existing for the flags if another thread manipulated the flags at the same time. This change locks the channel during flag manipulation. ASTERISK-26788 Change-Id: I2c5c8edec17c9bdad4a93291576838cb552ca5ed --- main/channel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main/channel.c b/main/channel.c index 23491933650..2890cf00019 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3130,7 +3130,9 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, fdmap[max].chan = x; /* channel x is linked to this pfds */ max += ast_add_fd(&pfds[max], ast_channel_fd(c[x], y)); } + ast_channel_lock(c[x]); CHECK_BLOCKING(c[x]); + ast_channel_unlock(c[x]); } /* Add the individual fds */ for (x = 0; x < nfds; x++) { @@ -3157,7 +3159,9 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, res = ast_poll(pfds, max, rms); } for (x = 0; x < n; x++) { + ast_channel_lock(c[x]); ast_clear_flag(ast_channel_flags(c[x]), AST_FLAG_BLOCKING); + ast_channel_unlock(c[x]); } if (res < 0) { /* Simulate a timeout if we were interrupted */ if (errno != EINTR) { @@ -3193,12 +3197,14 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, } if (fdmap[x].chan >= 0) { /* this is a channel */ winner = c[fdmap[x].chan]; /* override previous winners */ + ast_channel_lock(winner); if (res & POLLPRI) { ast_set_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION); } else { ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION); } ast_channel_fdno_set(winner, fdmap[x].fdno); + ast_channel_unlock(winner); } else { /* this is an fd */ if (outfd) { *outfd = pfds[x].fd; From 75f8167e6621243c2f5110e00185e6de461d47a9 Mon Sep 17 00:00:00 2001 From: Norbert Varga Date: Fri, 13 Jan 2017 18:21:36 +0100 Subject: [PATCH 1030/1578] chan_pjsip: Multidomain endpoint finding on call When PJSIP tries to call an endpoint with a domain (e.g. 1000@test.com), the user part is stripped down as it would be a trunk with a specified user, and only the host part is called as a PJSIP endpoint and can't be found. This is not correct in the case of a multidomain SIP account, so the stripping after the @ sign is done only if the whole endpoint (in multidomain case 1000@test.com) can't be found. ASTERISK-26248 Change-Id: I3a2dd6f57f3bd042df46b961eccd81d31ab202e6 --- channels/chan_pjsip.c | 57 +++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 4aae15ce972..46c74adf791 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2125,22 +2125,53 @@ static int request(void *obj) AST_NONSTANDARD_APP_ARGS(args, tmp, '/'); - /* If a request user has been specified extract it from the endpoint name portion */ - if ((endpoint_name = strchr(args.endpoint, '@'))) { - request_user = args.endpoint; - *endpoint_name++ = '\0'; + if (ast_sip_get_disable_multi_domain()) { + /* If a request user has been specified extract it from the endpoint name portion */ + if ((endpoint_name = strchr(args.endpoint, '@'))) { + request_user = args.endpoint; + *endpoint_name++ = '\0'; + } else { + endpoint_name = args.endpoint; + } + + if (ast_strlen_zero(endpoint_name)) { + ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); + req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE; + return -1; + } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) { + ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", endpoint_name); + req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; + return -1; + } } else { + /* First try to find an exact endpoint match, for single (user) or multi-domain (user@domain) */ endpoint_name = args.endpoint; - } + if (ast_strlen_zero(endpoint_name)) { + ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); + req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE; + return -1; + } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) { + /* It seems it's not a multi-domain endpoint or single endpoint exact match, + * it's possible that it's a SIP trunk with a specified user (user@trunkname), + * so extract the user before @ sign. + */ + if ((endpoint_name = strchr(args.endpoint, '@'))) { + request_user = args.endpoint; + *endpoint_name++ = '\0'; + } - if (ast_strlen_zero(endpoint_name)) { - ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); - req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE; - return -1; - } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) { - ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", endpoint_name); - req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; - return -1; + if (ast_strlen_zero(endpoint_name)) { + ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); + req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE; + return -1; + } + + if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) { + ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", endpoint_name); + req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; + return -1; + } + } } if (!(session = ast_sip_session_create_outgoing(endpoint, NULL, args.aor, request_user, req_data->caps))) { From 8b72ec312bd9fc439383a24d3f5c29b638758fd3 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 10 Feb 2017 14:45:43 -0700 Subject: [PATCH 1031/1578] stream: Add media stream topology definition and API This change adds the media stream topology definition and API for accessing and using it. Some refactoring of the stream was also done. ASTERISK-26786 Change-Id: Ic930232d24d5ad66dcabc14e9b359e0ff8e7f568 --- include/asterisk/codec.h | 1 + include/asterisk/stream.h | 151 ++++++++++++++++++++++++-- main/format_cap.c | 1 + main/stream.c | 216 +++++++++++++++++++++++++++++++++++++- res/res_pjsip_sdp_rtp.c | 3 +- 5 files changed, 359 insertions(+), 13 deletions(-) diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h index 3873324b143..2ae9551816d 100644 --- a/include/asterisk/codec.h +++ b/include/asterisk/codec.h @@ -33,6 +33,7 @@ enum ast_media_type { AST_MEDIA_TYPE_VIDEO, AST_MEDIA_TYPE_IMAGE, AST_MEDIA_TYPE_TEXT, + AST_MEDIA_TYPE_END, }; struct ast_module; diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index e73ed3fe7a7..cffe6ea4cb1 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -38,6 +38,11 @@ struct ast_stream; */ struct ast_format_cap; +/*! + * \brief The topology of a set of streams + */ +struct ast_stream_topology; + /*! * \brief States that a stream may be in */ @@ -90,12 +95,25 @@ struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type) */ void ast_stream_destroy(struct ast_stream *stream); +/*! + * \brief Create a deep clone of an existing stream + * + * \param stream The existing stream + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 15 + */ +struct ast_stream *ast_stream_clone(const struct ast_stream *stream); + /*! * \brief Get the name of a stream * * \param stream The media stream * - * \return The name of the stream + * \retval non-NULL success + * \retval NULL failure * * \since 15 */ @@ -106,7 +124,7 @@ const char *ast_stream_get_name(const struct ast_stream *stream); * * \param stream The media stream * - * \return The media type of the stream + * \return The media type of the stream (AST_MEDIA_TYPE_UNKNOWN on error) * * \since 15 */ @@ -127,7 +145,8 @@ void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type); * * \param stream The media stream * - * \return The negotiated media formats + * \retval non-NULL success + * \retval NULL failure * * \note The reference count is not increased * @@ -141,6 +160,9 @@ struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream); * \param stream The media stream * \param caps The current negotiated formats * + * \note The new format capabilities structure has its refcount bumped and + * any existing format capabilities structure has its refcount decremented. + * * \since 15 */ void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps); @@ -150,7 +172,7 @@ void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *ca * * \param stream The media stream * - * \return The state of the stream + * \return The state of the stream (AST_STREAM_STATE_UNKNOWN on error) * * \since 15 */ @@ -169,14 +191,129 @@ enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream); void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state); /*! - * \brief Get the number of the stream + * \brief Get the position of the stream in the topology * * \param stream The media stream * - * \return The number of the stream + * \return The position of the stream (-1 on error) + * + * \since 15 + */ +int ast_stream_get_position(const struct ast_stream *stream); + +/*! + * \brief Create a stream topology + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 15 + */ +struct ast_stream_topology *ast_stream_topology_create(void); + +/*! + * \brief Create a deep clone of an existing stream topology + * + * \param topology The existing topology of streams + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 15 + */ +struct ast_stream_topology *ast_stream_topology_clone( + const struct ast_stream_topology *topology); + +/*! + * \brief Destroy a stream topology + * + * \param topology The topology of streams + * + * \note All streams contained within the topology will be destroyed + * + * \since 15 + */ +void ast_stream_topology_destroy(struct ast_stream_topology *topology); + +/*! + * \brief Append a stream to the topology + * + * \param topology The topology of streams + * \param stream The stream to append + * + * \returns the position of the stream in the topology (-1 on error) + * + * \since 15 + */ +int ast_stream_topology_append_stream(struct ast_stream_topology *topology, + struct ast_stream *stream); + +/*! + * \brief Get the number of streams in a topology + * + * \param topology The topology of streams + * + * \return the number of streams (-1 on error) + * + * \since 15 + */ +int ast_stream_topology_get_count(const struct ast_stream_topology *topology); + +/*! + * \brief Get a specific stream from the topology + * + * \param topology The topology of streams + * \param position The topology position to get + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 15 + */ +struct ast_stream *ast_stream_topology_get_stream( + const struct ast_stream_topology *topology, unsigned int position); + +/*! + * \brief Set a specific position in a topology + * + * \param topology The topology of streams + * \param position The topology position to set + * \param stream The stream to put in its place + * + * \retval 0 success + * \retval -1 failure + * + * \note If an existing stream exists it will be destroyed + * + * \note You can overwrite an existing position in the topology or set + * the first unused position. You can't set positions beyond that. + * + * \since 15 + */ +int ast_stream_topology_set_stream(struct ast_stream_topology *topology, + unsigned int position, struct ast_stream *stream); + +/*! + * \brief A helper function that, given a format capabilities structure, + * creates a topology and separates the media types in format_cap into + * separate streams. + * + * \param caps The format capabilities structure + * + * \retval non-NULL success + * \retval NULL failure + * + * \note The format capabilities reference is NOT altered by this function + * since a new format capabilities structure is created for each media type. + * + * \note Each stream will have its name set to the corresponding media type. + * For example: "AST_MEDIA_TYPE_AUDIO". + * + * \note Each stream will be set to the sendrecv state. * * \since 15 */ -unsigned int ast_stream_get_num(const struct ast_stream *stream); +struct ast_stream_topology *ast_stream_topology_create_from_format_cap( + struct ast_format_cap *cap); #endif /* _AST_STREAM_H */ diff --git a/main/format_cap.c b/main/format_cap.c index 1fe342b3107..b0897c001c0 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -268,6 +268,7 @@ int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_ { int idx, res = 0; + /* NOTE: The streams API is dependent on the formats being in "preference" order */ for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) { struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx); diff --git a/main/stream.c b/main/stream.c index fb3dbd5ce5d..0fabfc7387d 100644 --- a/main/stream.c +++ b/main/stream.c @@ -32,6 +32,8 @@ #include "asterisk/logger.h" #include "asterisk/stream.h" #include "asterisk/strings.h" +#include "asterisk/format.h" +#include "asterisk/format_cap.h" struct ast_stream { /*! @@ -40,9 +42,9 @@ struct ast_stream { enum ast_media_type type; /*! - * \brief Unique number for the stream within the context of the channel it is on + * \brief The position of the stream in the topology */ - unsigned int num; + unsigned int position; /*! * \brief Current formats negotiated on the stream @@ -60,6 +62,13 @@ struct ast_stream { char name[0]; }; +struct ast_stream_topology { + /*! + * \brief A vector of all the streams in this topology + */ + AST_VECTOR(, struct ast_stream *) streams; +}; + struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type) { struct ast_stream *stream; @@ -71,11 +80,34 @@ struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type) stream->type = type; stream->state = AST_STREAM_STATE_INACTIVE; - strcpy(stream->name, S_OR(name, "")); + strcpy(stream->name, S_OR(name, "")); /* Safe */ return stream; } +struct ast_stream *ast_stream_clone(const struct ast_stream *stream) +{ + struct ast_stream *new_stream; + size_t stream_size; + + if (!stream) { + return NULL; + } + + stream_size = sizeof(*stream) + strlen(stream->name) + 1; + new_stream = ast_calloc(1, stream_size); + if (!new_stream) { + return NULL; + } + + memcpy(new_stream, stream, stream_size); + if (new_stream->formats) { + ao2_ref(new_stream->formats, +1); + } + + return new_stream; +} + void ast_stream_destroy(struct ast_stream *stream) { if (!stream) { @@ -88,41 +120,215 @@ void ast_stream_destroy(struct ast_stream *stream) const char *ast_stream_get_name(const struct ast_stream *stream) { + ast_assert(stream != NULL); + return stream->name; } enum ast_media_type ast_stream_get_type(const struct ast_stream *stream) { + ast_assert(stream != NULL); + return stream->type; } void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type) { + ast_assert(stream != NULL); + stream->type = type; } struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream) { + ast_assert(stream != NULL); + return stream->formats; } void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps) { + ast_assert(stream != NULL); + ao2_cleanup(stream->formats); stream->formats = ao2_bump(caps); } enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream) { + ast_assert(stream != NULL); + return stream->state; } void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state) { + ast_assert(stream != NULL); + stream->state = state; } -unsigned int ast_stream_get_num(const struct ast_stream *stream) +int ast_stream_get_position(const struct ast_stream *stream) +{ + ast_assert(stream != NULL); + + return stream->position; +} + +#define TOPOLOGY_INITIAL_STREAM_COUNT 2 +struct ast_stream_topology *ast_stream_topology_create(void) +{ + struct ast_stream_topology *topology; + + topology = ast_calloc(1, sizeof(*topology)); + if (!topology) { + return NULL; + } + + if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) { + ast_free(topology); + topology = NULL; + } + + return topology; +} + +struct ast_stream_topology *ast_stream_topology_clone( + const struct ast_stream_topology *topology) +{ + struct ast_stream_topology *new_topology; + int i; + + ast_assert(topology != NULL); + + new_topology = ast_stream_topology_create(); + if (!new_topology) { + return NULL; + } + + for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { + struct ast_stream *stream = + ast_stream_clone(AST_VECTOR_GET(&topology->streams, i)); + + if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) { + ast_stream_destroy(stream); + ast_stream_topology_destroy(new_topology); + return NULL; + } + } + + return new_topology; +} + +void ast_stream_topology_destroy(struct ast_stream_topology *topology) +{ + if (!topology) { + return; + } + + AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_destroy); + AST_VECTOR_FREE(&topology->streams); + ast_free(topology); +} + +int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream) +{ + ast_assert(topology && stream); + + if (AST_VECTOR_APPEND(&topology->streams, stream)) { + return -1; + } + + return AST_VECTOR_SIZE(&topology->streams) - 1; +} + +int ast_stream_topology_get_count(const struct ast_stream_topology *topology) +{ + ast_assert(topology != NULL); + + return AST_VECTOR_SIZE(&topology->streams); +} + +struct ast_stream *ast_stream_topology_get_stream( + const struct ast_stream_topology *topology, unsigned int stream_num) +{ + ast_assert(topology != NULL); + + return AST_VECTOR_GET(&topology->streams, stream_num); +} + +int ast_stream_topology_set_stream(struct ast_stream_topology *topology, + unsigned int position, struct ast_stream *stream) { - return stream->num; + struct ast_stream *existing_stream; + + ast_assert(topology && stream); + + if (position > AST_VECTOR_SIZE(&topology->streams)) { + return -1; + } + + existing_stream = AST_VECTOR_GET(&topology->streams, position); + ast_stream_destroy(existing_stream); + + if (position == AST_VECTOR_SIZE(&topology->streams)) { + AST_VECTOR_APPEND(&topology->streams, stream); + return 0; + } + + stream->position = position; + return AST_VECTOR_REPLACE(&topology->streams, position, stream); +} + +struct ast_stream_topology *ast_stream_topology_create_from_format_cap( + struct ast_format_cap *cap) +{ + struct ast_stream_topology *topology; + enum ast_media_type type; + + ast_assert(cap != NULL); + + topology = ast_stream_topology_create(); + if (!topology) { + return NULL; + } + + for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; type++) { + struct ast_format_cap *new_cap; + struct ast_stream *stream; + + if (!ast_format_cap_has_type(cap, type)) { + continue; + } + + new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!new_cap) { + ast_stream_topology_destroy(topology); + return NULL; + } + + ast_format_cap_set_framing(new_cap, ast_format_cap_get_framing(cap)); + if (ast_format_cap_append_from_cap(new_cap, cap, type)) { + ao2_cleanup(new_cap); + ast_stream_topology_destroy(topology); + return NULL; + } + + stream = ast_stream_create(ast_codec_media_type2str(type), type); + if (!stream) { + ao2_cleanup(new_cap); + ast_stream_topology_destroy(topology); + return NULL; + } + /* We're transferring the initial ref so no bump needed */ + stream->formats = new_cap; + stream->state = AST_STREAM_STATE_SENDRECV; + if (!ast_stream_topology_append_stream(topology, stream)) { + ast_stream_destroy(stream); + ast_stream_topology_destroy(topology); + return NULL; + } + } + + return topology; } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 4d6a1a168b9..e32d2b65f8d 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -87,7 +87,8 @@ static int media_type_to_fdno(enum ast_media_type media_type) case AST_MEDIA_TYPE_VIDEO: return FD_VIDEO; case AST_MEDIA_TYPE_TEXT: case AST_MEDIA_TYPE_UNKNOWN: - case AST_MEDIA_TYPE_IMAGE: break; + case AST_MEDIA_TYPE_IMAGE: + case AST_MEDIA_TYPE_END: break; } return -1; } From 3f9437377809a8c1476a1195474eb3178b2c7934 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sat, 11 Feb 2017 10:57:03 -0500 Subject: [PATCH 1032/1578] cli: Fix various CLI documentation and completion issues * app_minivm: Use built-in completion facilities to complete optional arguments. * app_voicemail: Use built-in completion facilities to complete optional arguments. * app_confbridge: Add missing colons after 'Usage' text. * chan_alsa: Use built-in completion facilities to complete optional arguments. * chan_sip: Use built-in completion facilities to complete optional arguments. Add completions for 'load' for 'sip show user', 'sip show peer', and 'sip qualify peer.' * chan_skinny: Correct and extend completions for 'skinny reset' and 'skinny show line.' * func_odbc: Correct completions for 'odbc read' and 'odbc write' * main/astmm: Use built-in completion facilities to complete arguments for 'memory' commands. * main/bridge: Correct completions for 'bridge kick.' * main/ccss: Use built-in completion facilities to complete arguments for 'cc cancel' command. * main/cli: Add 'all' completion for 'channel request hangup.' Correct completions for 'core set debug channel.' Correct completions for 'core show calls.' * main/pbx_app: Remove redundant completions for 'core show applications.' * main/pbx_hangup_handler: Remove unused completions for 'core show hanguphandlers all.' * res_sorcery_memory_cache: Add completion for 'reload' argument of 'sorcery memory cache stale' and properly implement. Change-Id: Iee58c7392f6fec34ad9d596109117af87697bbca --- apps/app_minivm.c | 8 +++--- apps/app_voicemail.c | 6 ++--- apps/confbridge/conf_config_parser.c | 12 ++++----- channels/chan_alsa.c | 20 ++------------ channels/chan_sip.c | 27 ++++++++++++++----- channels/chan_skinny.c | 40 +++++++++++++++++++--------- funcs/func_odbc.c | 6 +++-- main/astmm.c | 21 +++------------ main/bridge.c | 14 +++++----- main/ccss.c | 9 ++----- main/cli.c | 33 +++++++++++++++++------ main/pbx_app.c | 3 +-- main/pbx_hangup_handler.c | 2 +- res/res_sorcery_memory_cache.c | 14 +++++++++- 14 files changed, 118 insertions(+), 97 deletions(-) diff --git a/apps/app_minivm.c b/apps/app_minivm.c index a060ad1833f..4cc2f47965c 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -3014,11 +3014,9 @@ static char *complete_minivm_show_users(const char *line, const char *word, int struct minivm_account *vmu; const char *domain = ""; - /* 0 - voicemail; 1 - list; 2 - accounts; 3 - for; 4 - */ + /* 0 - minivm; 1 - list; 2 - accounts; 3 - for; 4 - */ if (pos > 4) return NULL; - if (pos == 3) - return (state == 0) ? ast_strdup("for") : NULL; wordlen = strlen(word); AST_LIST_TRAVERSE(&minivm_accounts, vmu, list) { if (!strncasecmp(word, vmu->domain, wordlen)) { @@ -3040,9 +3038,9 @@ static char *handle_minivm_show_users(struct ast_cli_entry *e, int cmd, struct a switch (cmd) { case CLI_INIT: - e->command = "minivm list accounts"; + e->command = "minivm list accounts [for]"; e->usage = - "Usage: minivm list accounts\n" + "Usage: minivm list accounts [for ]\n" " Lists all mailboxes currently set up\n"; return NULL; case CLI_GENERATE: diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 37f8aa96f5b..3016f65ba59 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -12745,11 +12745,9 @@ static char *complete_voicemail_show_users(const char *line, const char *word, i struct ast_vm_user *vmu; const char *context = ""; - /* 0 - show; 1 - voicemail; 2 - users; 3 - for; 4 - */ + /* 0 - voicemail; 1 - show; 2 - users; 3 - for; 4 - */ if (pos > 4) return NULL; - if (pos == 3) - return (state == 0) ? ast_strdup("for") : NULL; wordlen = strlen(word); AST_LIST_TRAVERSE(&users, vmu, list) { if (!strncasecmp(word, vmu->context, wordlen)) { @@ -12772,7 +12770,7 @@ static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struc switch (cmd) { case CLI_INIT: - e->command = "voicemail show users"; + e->command = "voicemail show users [for]"; e->usage = "Usage: voicemail show users [for ]\n" " Lists all mailboxes currently set up\n"; diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 1749b585e7c..29d7b7f53f9 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -1371,7 +1371,7 @@ static char *handle_cli_confbridge_show_user_profiles(struct ast_cli_entry *e, i case CLI_INIT: e->command = "confbridge show profile users"; e->usage = - "Usage confbridge show profile users\n"; + "Usage: confbridge show profile users\n"; return NULL; case CLI_GENERATE: return NULL; @@ -1401,7 +1401,7 @@ static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, in case CLI_INIT: e->command = "confbridge show profile user"; e->usage = - "Usage confbridge show profile user []\n"; + "Usage: confbridge show profile user []\n"; return NULL; case CLI_GENERATE: if (a->pos == 4) { @@ -1522,7 +1522,7 @@ static char *handle_cli_confbridge_show_bridge_profiles(struct ast_cli_entry *e, case CLI_INIT: e->command = "confbridge show profile bridges"; e->usage = - "Usage confbridge show profile bridges\n"; + "Usage: confbridge show profile bridges\n"; return NULL; case CLI_GENERATE: return NULL; @@ -1554,7 +1554,7 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, case CLI_INIT: e->command = "confbridge show profile bridge"; e->usage = - "Usage confbridge show profile bridge \n"; + "Usage: confbridge show profile bridge \n"; return NULL; case CLI_GENERATE: if (a->pos == 4) { @@ -1706,7 +1706,7 @@ static char *handle_cli_confbridge_show_menus(struct ast_cli_entry *e, int cmd, case CLI_INIT: e->command = "confbridge show menus"; e->usage = - "Usage confbridge show profile menus\n"; + "Usage: confbridge show profile menus\n"; return NULL; case CLI_GENERATE: return NULL; @@ -1740,7 +1740,7 @@ static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, s case CLI_INIT: e->command = "confbridge show menu"; e->usage = - "Usage confbridge show menu []\n"; + "Usage: confbridge show menu []\n"; return NULL; case CLI_GENERATE: if (a->pos == 3) { diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index d09dc1c5347..c50b5408e35 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -637,29 +637,13 @@ static struct ast_channel *alsa_request(const char *type, struct ast_format_cap return tmp; } -static char *autoanswer_complete(const char *line, const char *word, int pos, int state) -{ - switch (state) { - case 0: - if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2))) - return ast_strdup("on"); - case 1: - if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3))) - return ast_strdup("off"); - default: - return NULL; - } - - return NULL; -} - static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { char *res = CLI_SUCCESS; switch (cmd) { case CLI_INIT: - e->command = "console autoanswer"; + e->command = "console autoanswer [on|off]"; e->usage = "Usage: console autoanswer [on|off]\n" " Enables or disables autoanswer feature. If used without\n" @@ -667,7 +651,7 @@ static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli " The default value of autoanswer is in 'alsa.conf'.\n"; return NULL; case CLI_GENERATE: - return autoanswer_complete(a->line, a->word, a->pos, a->n); + return NULL; } if ((a->argc != 2) && (a->argc != 3)) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 3bb6e74b6da..7dcb48b2102 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -19585,7 +19585,7 @@ static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_arg switch (cmd) { case CLI_INIT: - e->command = "sip show inuse"; + e->command = "sip show inuse [all]"; e->usage = "Usage: sip show inuse [all]\n" " List all SIP devices usage counters and limits.\n" @@ -19775,7 +19775,7 @@ static char *sip_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_arg switch (cmd) { case CLI_INIT: - e->command = "sip show users"; + e->command = "sip show users [like]"; e->usage = "Usage: sip show users [like ]\n" " Lists all known SIP users.\n" @@ -19914,7 +19914,7 @@ static char *sip_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_arg { switch (cmd) { case CLI_INIT: - e->command = "sip show peers"; + e->command = "sip show peers [like]"; e->usage = "Usage: sip show peers [like ]\n" " Lists all known SIP peers.\n" @@ -20628,7 +20628,12 @@ static char *sip_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args " Option \"load\" forces lookup of peer in realtime storage.\n"; return NULL; case CLI_GENERATE: - return complete_sip_show_peer(a->line, a->word, a->pos, a->n); + if (a->pos == 4) { + static const char * const completions[] = { "load", NULL }; + return ast_cli_complete(a->word, completions, a->n); + } else { + return complete_sip_show_peer(a->line, a->word, a->pos, a->n); + } } return _sip_show_peer(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv); } @@ -20798,7 +20803,12 @@ static char *sip_qualify_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_a " Option \"load\" forces lookup of peer in realtime storage.\n"; return NULL; case CLI_GENERATE: - return complete_sip_show_peer(a->line, a->word, a->pos, a->n); + if (a->pos == 4) { + static const char * const completions[] = { "load", NULL }; + return ast_cli_complete(a->word, completions, a->n); + } else { + return complete_sip_show_peer(a->line, a->word, a->pos, a->n); + } } return _sip_qualify_peer(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv); } @@ -21169,7 +21179,12 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args " Option \"load\" forces lookup of peer in realtime storage.\n"; return NULL; case CLI_GENERATE: - return complete_sip_show_user(a->line, a->word, a->pos, a->n); + if (a->pos == 4) { + static const char * const completions[] = { "load", NULL }; + return ast_cli_complete(a->word, completions, a->n); + } else { + return complete_sip_show_user(a->line, a->word, a->pos, a->n); + } } if (a->argc < 4) diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 0ef01663574..a3a2f87fbe6 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -3921,24 +3921,40 @@ static char *complete_skinny_show_device(const char *line, const char *word, int static char *complete_skinny_reset(const char *line, const char *word, int pos, int state) { - return (pos == 2 ? complete_skinny_devices(word, state) : NULL); + if (pos == 2) { + static const char * const completions[] = { "all", NULL }; + char *ret = ast_cli_complete(word, completions, state); + if (!ret) { + ret = complete_skinny_devices(word, state - 1); + } + return ret; + } else if (pos == 3) { + static const char * const completions[] = { "restart", NULL }; + return ast_cli_complete(word, completions, state); + } + + return NULL; } static char *complete_skinny_show_line(const char *line, const char *word, int pos, int state) { - struct skinny_device *d; - struct skinny_line *l; - int wordlen = strlen(word), which = 0; + if (pos == 3) { + struct skinny_device *d; + struct skinny_line *l; + int wordlen = strlen(word), which = 0; - if (pos != 3) - return NULL; - - AST_LIST_TRAVERSE(&devices, d, list) { - AST_LIST_TRAVERSE(&d->lines, l, list) { - if (!strncasecmp(word, l->name, wordlen) && ++which > state) { - return ast_strdup(l->name); + AST_LIST_TRAVERSE(&devices, d, list) { + AST_LIST_TRAVERSE(&d->lines, l, list) { + if (!strncasecmp(word, l->name, wordlen) && ++which > state) { + return ast_strdup(l->name); + } } } + } else if (pos == 4) { + static const char * const completions[] = { "on", NULL }; + return ast_cli_complete(word, completions, state); + } else if (pos == 5) { + return complete_skinny_devices(word, state); } return NULL; @@ -4580,7 +4596,7 @@ static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct as case CLI_INIT: e->command = "skinny show line"; e->usage = - "Usage: skinny show line [ on ]\n" + "Usage: skinny show line [on ]\n" " List all lineinformation of a specific line known to the Skinny subsystem.\n"; return NULL; case CLI_GENERATE: diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index e014b633c60..06e4a6adab3 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -1417,7 +1417,8 @@ static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args AST_RWLIST_UNLOCK(&queries); return NULL; } else if (a->pos == 4) { - return a->n == 0 ? ast_strdup("exec") : NULL; + static const char * const completions[] = { "exec", NULL }; + return ast_cli_complete(a->word, completions, a->n); } else { return NULL; } @@ -1623,7 +1624,8 @@ static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_arg AST_RWLIST_UNLOCK(&queries); return NULL; } else if (a->pos == 5) { - return a->n == 0 ? ast_strdup("exec") : NULL; + static const char * const completions[] = { "exec", NULL }; + return ast_cli_complete(a->word, completions, a->n); } else { return NULL; } diff --git a/main/astmm.c b/main/astmm.c index 0ad29a6fb8e..9c26f0fa7e3 100644 --- a/main/astmm.c +++ b/main/astmm.c @@ -691,17 +691,12 @@ static char *handle_memory_atexit_list(struct ast_cli_entry *e, int cmd, struct { switch (cmd) { case CLI_INIT: - e->command = "memory atexit list"; + e->command = "memory atexit list {on|off}"; e->usage = "Usage: memory atexit list {on|off}\n" " Enable dumping a list of still allocated memory segments at exit.\n"; return NULL; case CLI_GENERATE: - if (a->pos == 3) { - const char * const options[] = { "off", "on", NULL }; - - return ast_cli_complete(a->word, options, a->n); - } return NULL; } @@ -728,7 +723,7 @@ static char *handle_memory_atexit_summary(struct ast_cli_entry *e, int cmd, stru switch (cmd) { case CLI_INIT: - e->command = "memory atexit summary"; + e->command = "memory atexit summary {off|byline|byfunc|byfile}"; e->usage = "Usage: memory atexit summary {off|byline|byfunc|byfile}\n" " Summary of still allocated memory segments at exit options.\n" @@ -740,11 +735,6 @@ static char *handle_memory_atexit_summary(struct ast_cli_entry *e, int cmd, stru " Note: byline, byfunc, and byfile are cumulative enables.\n"; return NULL; case CLI_GENERATE: - if (a->pos == 3) { - const char * const options[] = { "off", "byline", "byfunc", "byfile", NULL }; - - return ast_cli_complete(a->word, options, a->n); - } return NULL; } @@ -1043,7 +1033,7 @@ static char *handle_memory_backtrace(struct ast_cli_entry *e, int cmd, struct as { switch (cmd) { case CLI_INIT: - e->command = "memory backtrace"; + e->command = "memory backtrace {on|off}"; e->usage = "Usage: memory backtrace {on|off}\n" " Enable dumping an allocation backtrace with memory diagnostics.\n" @@ -1051,11 +1041,6 @@ static char *handle_memory_backtrace(struct ast_cli_entry *e, int cmd, struct as " can be CPU intensive.\n"; return NULL; case CLI_GENERATE: - if (a->pos == 2) { - const char * const options[] = { "off", "on", NULL }; - - return ast_cli_complete(a->word, options, a->n); - } return NULL; } diff --git a/main/bridge.c b/main/bridge.c index 13c01fa2735..b6ba0a2bf78 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -5170,12 +5170,6 @@ static char *complete_bridge_participant(const char *bridge_name, const char *li return NULL; } - if (!state) { - ao2_ref(bridge, -1); - return ast_strdup("all"); - } - state--; - { SCOPED_LOCK(bridge_lock, bridge, ast_bridge_lock, ast_bridge_unlock); @@ -5197,6 +5191,8 @@ static char *complete_bridge_participant(const char *bridge_name, const char *li static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + static const char * const completions[] = { "all", NULL }; + char *complete; struct ast_bridge *bridge; switch (cmd) { @@ -5213,7 +5209,11 @@ static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct return complete_bridge_live(a->word, a->n); } if (a->pos == 3) { - return complete_bridge_participant(a->argv[2], a->line, a->word, a->pos, a->n); + complete = ast_cli_complete(a->word, completions, a->n); + if (!complete) { + complete = complete_bridge_participant(a->argv[2], a->line, a->word, a->pos, a->n - 1); + } + return complete; } return NULL; } diff --git a/main/ccss.c b/main/ccss.c index 6c3e6cbee11..f96d7aa1d6f 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -4566,11 +4566,9 @@ static char *complete_core_id(const char *line, const char *word, int pos, int s static char *handle_cc_kill(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - static const char * const option[] = { "core", "all", NULL }; - switch (cmd) { case CLI_INIT: - e->command = "cc cancel"; + e->command = "cc cancel [core|all]"; e->usage = "Usage: cc cancel can be used in two ways.\n" " 1. 'cc cancel core [core ID]' will cancel the CC transaction with\n" @@ -4578,10 +4576,7 @@ static char *handle_cc_kill(struct ast_cli_entry *e, int cmd, struct ast_cli_arg " 2. 'cc cancel all' will cancel all active CC transactions.\n"; return NULL; case CLI_GENERATE: - if (a->pos == 2) { - return ast_cli_complete(a->word, option, a->n); - } - if (a->pos == 3) { + if (a->pos == 3 && !strcasecmp(a->argv[2], "core")) { return complete_core_id(a->line, a->word, a->pos, a->n); } return NULL; diff --git a/main/cli.c b/main/cli.c index 632883d39f3..ccdbb97c3e4 100644 --- a/main/cli.c +++ b/main/cli.c @@ -916,6 +916,7 @@ static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_arg static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + static const char * const completions[] = { "seconds", NULL }; struct timeval curtime = ast_tvnow(); int showuptime, printsec; @@ -923,7 +924,7 @@ static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_a case CLI_INIT: e->command = "core show calls [uptime]"; e->usage = - "Usage: core show calls [uptime] [seconds]\n" + "Usage: core show calls [uptime [seconds]]\n" " Lists number of currently active calls and total number of calls\n" " processed through PBX since last restart. If 'uptime' is specified\n" " the system uptime is also displayed. If 'seconds' is specified in\n" @@ -933,7 +934,7 @@ static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_a case CLI_GENERATE: if (a->pos != e->args) return NULL; - return a->n == 0 ? ast_strdup("seconds") : NULL; + return ast_cli_complete(a->word, completions, a->n); } /* regular handler */ @@ -1103,7 +1104,9 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - struct ast_channel *c=NULL; + struct ast_channel *c = NULL; + static const char * const completions[] = { "all", NULL }; + char *complete; switch (cmd) { case CLI_INIT: @@ -1116,7 +1119,14 @@ static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_ " will see the hangup request.\n"; return NULL; case CLI_GENERATE: - return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args); + if (a->pos != e->args) { + return NULL; + } + complete = ast_cli_complete(a->word, completions, a->n); + if (!complete) { + complete = ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args); + } + return complete; } if (a->argc != 4) { @@ -1428,6 +1438,8 @@ static int channel_set_debug(void *obj, void *arg, void *data, int flags) static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ast_channel *c = NULL; + static const char * const completions_all[] = { "all", NULL }; + static const char * const completions_off[] = { "off", NULL }; struct channel_set_debug_args args = { .fd = a->fd, }; @@ -1440,10 +1452,15 @@ static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, str " Enables/disables debugging on all or on a specific channel.\n"; return NULL; case CLI_GENERATE: - /* XXX remember to handle the optional "off" */ - if (a->pos != e->args) - return NULL; - return a->n == 0 ? ast_strdup("all") : ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args); + if (a->pos == 4) { + char *complete = ast_cli_complete(a->word, completions_all, a->n); + if (!complete) { + complete = ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args); + } + return complete; + } else if (a->pos == 5) { + return ast_cli_complete(a->word, completions_off, a->n); + } } if (cmd == (CLI_HANDLER + 1000)) { diff --git a/main/pbx_app.c b/main/pbx_app.c index 0c030d12da7..e0609db70e6 100644 --- a/main/pbx_app.c +++ b/main/pbx_app.c @@ -313,7 +313,6 @@ static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct a int like = 0, describing = 0; int total_match = 0; /* Number of matches in like clause */ int total_apps = 0; /* Number of apps registered */ - static const char * const choices[] = { "like", "describing", NULL }; switch (cmd) { case CLI_INIT: @@ -325,7 +324,7 @@ static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct a " If 'describing', will be a substring of the description\n"; return NULL; case CLI_GENERATE: - return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n); + return NULL; } AST_RWLIST_RDLOCK(&apps); diff --git a/main/pbx_hangup_handler.c b/main/pbx_hangup_handler.c index 554cb342f52..84b53d0c1a7 100644 --- a/main/pbx_hangup_handler.c +++ b/main/pbx_hangup_handler.c @@ -258,7 +258,7 @@ static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast " Show hangup handlers for all channels.\n"; return NULL; case CLI_GENERATE: - return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args); + return NULL; } if (a->argc < 4) { diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index 5f7ffb64ee8..bf2347ccdec 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -1866,6 +1866,7 @@ static char *sorcery_memory_cache_expire(struct ast_cli_entry *e, int cmd, struc static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct sorcery_memory_cache *cache; + int reload = 0; switch (cmd) { case CLI_INIT: @@ -1881,6 +1882,9 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct return sorcery_memory_cache_complete_name(a->word, a->n); } else if (a->pos == 5) { return sorcery_memory_cache_complete_object_name(a->argv[4], a->word, a->n); + } else if (a->pos == 6) { + static const char * const completions[] = { "reload", NULL }; + return ast_cli_complete(a->word, completions, a->n); } else { return NULL; } @@ -1890,6 +1894,14 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct return CLI_SHOWUSAGE; } + if (a->argc == 7) { + if (!strcasecmp(a->argv[6], "reload")) { + reload = 1; + } else { + return CLI_SHOWUSAGE; + } + } + cache = ao2_find(caches, a->argv[4], OBJ_SEARCH_KEY); if (!cache) { ast_cli(a->fd, "Specified sorcery memory cache '%s' does not exist\n", a->argv[4]); @@ -1910,7 +1922,7 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct if (!mark_object_as_stale_in_cache(cache, a->argv[5])) { ast_cli(a->fd, "Successfully marked object '%s' in memory cache '%s' as stale\n", a->argv[5], a->argv[4]); - if (a->argc == 7 && ast_true(a->argv[6])) { + if (reload) { struct sorcery_memory_cached_object *cached; cached = ao2_find(cache->objects, a->argv[5], OBJ_SEARCH_KEY | OBJ_NOLOCK); From 6c4657e28ebf9cbe6d952750142d9631ff600657 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 13 Feb 2017 17:00:42 +0000 Subject: [PATCH 1033/1578] stream: Add stream topology unit tests and fix uncovered bugs. This change adds unit tests for the various API calls relating to stream topologies. This includes creation, destruction, inspection, and manipulation. Through this a few bugs were uncovered in the implementation: 1. Creating a topology using a format capabilities would fail as the code considered a return value of 0 from the append stream function to indicate an error which is incorrect. 2. Not all functions which placed a stream into a topology set the position on the stream itself. 3. Appending a stream would cause a frack if the position provided was the last one. This occurred because the existing stream was queried but the index was outside of what the vector was currently at for size. ASTERISK-26786 Change-Id: Id5590e87c8a605deea1a89e53169a9c011d66fa0 --- main/stream.c | 13 +- tests/test_stream.c | 400 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 409 insertions(+), 4 deletions(-) diff --git a/main/stream.c b/main/stream.c index 0fabfc7387d..24844c4abeb 100644 --- a/main/stream.c +++ b/main/stream.c @@ -239,6 +239,8 @@ int ast_stream_topology_append_stream(struct ast_stream_topology *topology, stru return -1; } + stream->position = AST_VECTOR_SIZE(&topology->streams) - 1; + return AST_VECTOR_SIZE(&topology->streams) - 1; } @@ -268,15 +270,18 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, return -1; } - existing_stream = AST_VECTOR_GET(&topology->streams, position); - ast_stream_destroy(existing_stream); + if (position < AST_VECTOR_SIZE(&topology->streams)) { + existing_stream = AST_VECTOR_GET(&topology->streams, position); + ast_stream_destroy(existing_stream); + } + + stream->position = position; if (position == AST_VECTOR_SIZE(&topology->streams)) { AST_VECTOR_APPEND(&topology->streams, stream); return 0; } - stream->position = position; return AST_VECTOR_REPLACE(&topology->streams, position, stream); } @@ -323,7 +328,7 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( /* We're transferring the initial ref so no bump needed */ stream->formats = new_cap; stream->state = AST_STREAM_STATE_SENDRECV; - if (!ast_stream_topology_append_stream(topology, stream)) { + if (ast_stream_topology_append_stream(topology, stream) == -1) { ast_stream_destroy(stream); ast_stream_topology_destroy(topology); return NULL; diff --git a/tests/test_stream.c b/tests/test_stream.c index fd78dda971a..110e4e4b800 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -36,6 +36,7 @@ #include "asterisk/stream.h" #include "asterisk/format.h" #include "asterisk/format_cap.h" +#include "asterisk/format_cache.h" AST_TEST_DEFINE(stream_create) { @@ -222,6 +223,394 @@ AST_TEST_DEFINE(stream_set_state) return AST_TEST_PASS; } +AST_TEST_DEFINE(stream_topology_create) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_create"; + info->category = "/main/stream/"; + info->summary = "stream topology creation unit test"; + info->description = + "Test that creating a stream topology works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_create(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_topology_clone) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, cloned, NULL, ast_stream_topology_destroy); + struct ast_stream *audio_stream, *video_stream; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_clone"; + info->category = "/main/stream/"; + info->summary = "stream topology cloning unit test"; + info->description = + "Test that cloning a stream topology results in a clone with the same contents"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_create(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + if (!audio_stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, audio_stream) == -1) { + ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n"); + ast_stream_destroy(audio_stream); + return AST_TEST_FAIL; + } + + video_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + if (!video_stream) { + ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, video_stream) == -1) { + ast_test_status_update(test, "Failed to append valid video stream to stream topology\n"); + ast_stream_destroy(video_stream); + return AST_TEST_FAIL; + } + + cloned = ast_stream_topology_clone(topology); + if (!cloned) { + ast_test_status_update(test, "Failed to clone a perfectly good stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(cloned) != ast_stream_topology_get_count(topology)) { + ast_test_status_update(test, "Cloned stream topology does not contain same number of streams as original\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_type(ast_stream_topology_get_stream(cloned, 0)) != ast_stream_get_type(ast_stream_topology_get_stream(topology, 0))) { + ast_test_status_update(test, "Cloned audio stream does not contain same type as original\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_type(ast_stream_topology_get_stream(cloned, 1)) != ast_stream_get_type(ast_stream_topology_get_stream(topology, 1))) { + ast_test_status_update(test, "Cloned video stream does not contain same type as original\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_topology_append_stream) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + struct ast_stream *audio_stream, *video_stream; + int position; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_append_stream"; + info->category = "/main/stream/"; + info->summary = "stream topology stream appending unit test"; + info->description = + "Test that appending streams to a stream topology works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_create(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + if (!audio_stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + position = ast_stream_topology_append_stream(topology, audio_stream); + if (position == -1) { + ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n"); + ast_stream_destroy(audio_stream); + return AST_TEST_FAIL; + } else if (position != 0) { + ast_test_status_update(test, "Appended audio stream to stream topology but position is '%d' instead of 0\n", + position); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(topology) != 1) { + ast_test_status_update(test, "Appended an audio stream to the stream topology but stream count is '%d' on it, not 1\n", + ast_stream_topology_get_count(topology)); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_stream(topology, 0) != audio_stream) { + ast_test_status_update(test, "Appended an audio stream to the stream topology but returned stream doesn't match\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_position(audio_stream) != 0) { + ast_test_status_update(test, "Appended audio stream says it is at position '%d' instead of 0\n", + ast_stream_get_position(audio_stream)); + return AST_TEST_FAIL; + } + + video_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + if (!video_stream) { + ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + position = ast_stream_topology_append_stream(topology, video_stream); + if (position == -1) { + ast_test_status_update(test, "Failed to append valid video stream to stream topology\n"); + ast_stream_destroy(video_stream); + return AST_TEST_FAIL; + } else if (position != 1) { + ast_test_status_update(test, "Appended video stream to stream topology but position is '%d' instead of 1\n", + position); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(topology) != 2) { + ast_test_status_update(test, "Appended a video stream to the stream topology but stream count is '%d' on it, not 2\n", + ast_stream_topology_get_count(topology)); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_stream(topology, 1) != video_stream) { + ast_test_status_update(test, "Appended a video stream to the stream topology but returned stream doesn't match\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_position(video_stream) != 1) { + ast_test_status_update(test, "Appended video stream says it is at position '%d' instead of 1\n", + ast_stream_get_position(video_stream)); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_topology_set_stream) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + struct ast_stream *audio_stream, *video_stream; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_set_stream"; + info->category = "/main/stream/"; + info->summary = "stream topology stream setting unit test"; + info->description = + "Test that setting streams at a specific position in a topology works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_create(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + if (!audio_stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_set_stream(topology, 0, audio_stream)) { + ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n"); + ast_stream_destroy(audio_stream); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(topology) != 1) { + ast_test_status_update(test, "Set an audio stream on the stream topology but stream count is '%d' on it, not 1\n", + ast_stream_topology_get_count(topology)); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_stream(topology, 0) != audio_stream) { + ast_test_status_update(test, "Set an audio stream on the stream topology but returned stream doesn't match\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_position(audio_stream) != 0) { + ast_test_status_update(test, "Set audio stream says it is at position '%d' instead of 0\n", + ast_stream_get_position(audio_stream)); + return AST_TEST_FAIL; + } + + video_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + if (!video_stream) { + ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_set_stream(topology, 0, video_stream)) { + ast_test_status_update(test, "Failed to set a video stream to a position where it is permitted\n"); + ast_stream_destroy(video_stream); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(topology) != 1) { + ast_test_status_update(test, "Set a video stream on the stream topology but stream count is '%d' on it, not 1\n", + ast_stream_topology_get_count(topology)); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_stream(topology, 0) != video_stream) { + ast_test_status_update(test, "Set a video stream on the stream topology but returned stream doesn't match\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_position(video_stream) != 0) { + ast_test_status_update(test, "Set video stream says it is at position '%d' instead of 0\n", + ast_stream_get_position(video_stream)); + return AST_TEST_FAIL; + } + + audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + if (!audio_stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_set_stream(topology, 1, audio_stream)) { + ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n"); + ast_stream_destroy(audio_stream); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(topology) != 2) { + ast_test_status_update(test, "Set an audio stream on the stream topology but stream count is '%d' on it, not 2\n", + ast_stream_topology_get_count(topology)); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_stream(topology, 1) != audio_stream) { + ast_test_status_update(test, "Set an audio stream on the stream topology but returned stream doesn't match\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_get_position(audio_stream) != 1) { + ast_test_status_update(test, "Set audio stream says it is at position '%d' instead of 1\n", + ast_stream_get_position(audio_stream)); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(stream_topology_create_from_format_cap) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_create_from_format_cap"; + info->category = "/main/stream/"; + info->summary = "stream topology creation from format capabilities unit test"; + info->description = + "Test that creating a stream topology from format capabilities results in the expected streams"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { + ast_test_status_update(test, "Failed to append a ulaw format to capabilities for stream topology creation\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_alaw, 0)) { + ast_test_status_update(test, "Failed to append an alaw format to capabilities for stream topology creation\n"); + return AST_TEST_FAIL; + } + + topology = ast_stream_topology_create_from_format_cap(caps); + if (!topology) { + ast_test_status_update(test, "Failed to create a stream topology using a perfectly good format capabilities\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(topology) != 1) { + ast_test_status_update(test, "Expected a stream topology with 1 stream but it has %d streams\n", + ast_stream_topology_get_count(topology)); + return AST_TEST_FAIL; + } + + if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)) != AST_MEDIA_TYPE_AUDIO) { + ast_test_status_update(test, "Produced stream topology has a single stream of type %s instead of audio\n", + ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)))); + return AST_TEST_FAIL; + } + + ast_stream_topology_destroy(topology); + topology = NULL; + + ast_format_cap_append(caps, ast_format_h264, 0); + + topology = ast_stream_topology_create_from_format_cap(caps); + if (!topology) { + ast_test_status_update(test, "Failed to create a stream topology using a perfectly good format capabilities\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_count(topology) != 2) { + ast_test_status_update(test, "Expected a stream topology with 2 streams but it has %d streams\n", + ast_stream_topology_get_count(topology)); + return AST_TEST_FAIL; + } + + if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)) != AST_MEDIA_TYPE_AUDIO) { + ast_test_status_update(test, "Produced stream topology has a first stream of type %s instead of audio\n", + ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)))); + return AST_TEST_FAIL; + } + + if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 1)) != AST_MEDIA_TYPE_VIDEO) { + ast_test_status_update(test, "Produced stream topology has a second stream of type %s instead of video\n", + ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 1)))); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -229,6 +618,12 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_set_type); AST_TEST_UNREGISTER(stream_set_formats); AST_TEST_UNREGISTER(stream_set_state); + AST_TEST_UNREGISTER(stream_topology_create); + AST_TEST_UNREGISTER(stream_topology_clone); + AST_TEST_UNREGISTER(stream_topology_clone); + AST_TEST_UNREGISTER(stream_topology_append_stream); + AST_TEST_UNREGISTER(stream_topology_set_stream); + AST_TEST_UNREGISTER(stream_topology_create_from_format_cap); return 0; } @@ -239,6 +634,11 @@ static int load_module(void) AST_TEST_REGISTER(stream_set_type); AST_TEST_REGISTER(stream_set_formats); AST_TEST_REGISTER(stream_set_state); + AST_TEST_REGISTER(stream_topology_create); + AST_TEST_REGISTER(stream_topology_clone); + AST_TEST_REGISTER(stream_topology_append_stream); + AST_TEST_REGISTER(stream_topology_set_stream); + AST_TEST_REGISTER(stream_topology_create_from_format_cap); return AST_MODULE_LOAD_SUCCESS; } From 9f394d074a973ae4270458fe2a2a9f3869cf1817 Mon Sep 17 00:00:00 2001 From: Sebastian Gutierrez Date: Tue, 7 Feb 2017 14:13:09 -0300 Subject: [PATCH 1034/1578] app_queue: reset abandoned in sl for sl2 calculations ASTERISK-26775 #close Change-Id: I86de4b1a699d6edc77fea9b70d839440e4088284 --- apps/app_queue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index 344e9c1a5b5..95f4c0eedfb 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2783,6 +2783,7 @@ static void clear_queue(struct call_queue *q) q->callscompleted = 0; q->callsabandoned = 0; q->callscompletedinsl = 0; + q->callsabandonedinsl = 0; q->talktime = 0; if (q->members) { From 662c9e69fa021887146b887e06cd99cac568701d Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 14 Feb 2017 09:12:31 -0500 Subject: [PATCH 1035/1578] app_record: Add option to prevent silence from being truncated When using Record() with the silence detection feature, the stream is written out to the given file. However, if only 'silence' is detected, this file is then truncated to the first second of the recording. This patch adds the 'u' option to Record() to override that behavior. ASTERISK-18286 #close Reported by: var Patches: app_record-1.8.7.1.diff (license #6184) patch uploaded by var Change-Id: Ia1cd163483235efe2db05e52f39054288553b957 --- CHANGES | 9 +++++++++ apps/app_record.c | 13 +++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 1671d3635d8..79a1840b098 100644 --- a/CHANGES +++ b/CHANGES @@ -79,6 +79,15 @@ app_queue * Add 'QueueUpdate' application which can be used to track outbound calls using app_queue. +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14.3.0 to Asterisk 14.4.0 ------------ +------------------------------------------------------------------------------ + +app_record +------------------ + * Added new 'u' option to Record() application which prevents Asterisk from + truncating silence from the end of recorded files. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/apps/app_record.c b/apps/app_record.c index ede50be2645..0b85ff8a699 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -79,6 +79,9 @@ + @@ -131,6 +134,7 @@ enum { FLAG_HAS_PERCENT = (1 << 7), OPTION_ANY_TERMINATE = (1 << 8), OPTION_OPERATOR_EXIT = (1 << 9), + OPTION_NO_TRUNCATE = (1 << 10), }; AST_APP_OPTIONS(app_opts,{ @@ -141,6 +145,7 @@ AST_APP_OPTIONS(app_opts,{ AST_APP_OPTION('q', OPTION_QUIET), AST_APP_OPTION('s', OPTION_SKIP), AST_APP_OPTION('t', OPTION_STAR_TERMINATE), + AST_APP_OPTION('u', OPTION_NO_TRUNCATE), AST_APP_OPTION('y', OPTION_ANY_TERMINATE), AST_APP_OPTION('x', OPTION_IGNORE_TERMINATE), }); @@ -192,6 +197,7 @@ static int record_exec(struct ast_channel *chan, const char *data) int dspsilence = 0; int silence = 0; /* amount of silence to allow */ int gotsilence = 0; /* did we timeout for silence? */ + int truncate_silence = 1; /* truncate on complete silence recording */ int maxduration = 0; /* max duration of recording in milliseconds */ int gottimeout = 0; /* did we timeout for maxduration exceeded? */ int terminator = '#'; @@ -243,7 +249,10 @@ static int record_exec(struct ast_channel *chan, const char *data) ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", args.silence); } } - + + if (ast_test_flag(&flags, OPTION_NO_TRUNCATE)) + truncate_silence = 0; + if (args.maxduration) { if ((sscanf(args.maxduration, "%30d", &i) == 1) && (i > -1)) /* Convert duration to milliseconds */ @@ -443,7 +452,7 @@ static int record_exec(struct ast_channel *chan, const char *data) } } - if (gotsilence) { + if (gotsilence && truncate_silence) { ast_stream_rewind(s, silence - 1000); ast_truncstream(s); } else if (!gottimeout && f) { From 2b245b12d920e319bdb8112c00c76cc54b0485a4 Mon Sep 17 00:00:00 2001 From: rrittgarn Date: Wed, 25 Jan 2017 16:25:21 -0600 Subject: [PATCH 1036/1578] app_voicemail: VoiceMailPlayMsg did not play database stored messages When attempting to use VoiceMailPlayMsg with a realtime data backend the message is located, but never retrieved. This patch adds the required RETRIEVE and DISPOSE calls that will fetch the message from the database (and IMAP storage as well for that matter). Also, removed extraneous make_file call. ASTERISK-26723 #close Change-Id: I1e122dd53c0f3d7faa10f3c2b7e7e76a47d51b8c --- apps/app_voicemail.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 37f8aa96f5b..39cdf6af3fa 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -11204,7 +11204,6 @@ static int play_message_by_id_helper(struct ast_channel *chan, /* Found the msg, so play it back */ make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg); - make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg); #ifdef IMAP_STORAGE /*IMAP storage stores any prepended message from a forward @@ -11214,6 +11213,8 @@ static int play_message_by_id_helper(struct ast_channel *chan, wait_file(chan, vms, vms->introfn); } #endif + RETRIEVE(vms->curdir,vms->curmsg,vmu->mailbox, vmu->context); + if ((wait_file(chan, vms, vms->fn)) < 0) { ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn); } else { @@ -11225,7 +11226,7 @@ static int play_message_by_id_helper(struct ast_channel *chan, ast_mutex_unlock(&vms->lock); #endif } - + DISPOSE(vms->curdir, vms->curmsg); return 0; } From bf2f091bbb2b099d6ca87e5fdd76efe45a209eb7 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 13 Feb 2017 10:50:47 -0700 Subject: [PATCH 1037/1578] stream: Add stream topology to channel Adds topology set and get to channel. ASTERISK-26790 Change-Id: Ic379ea82a9486fc79dbd8c4d95c29fa3b46424f4 --- include/asterisk/channel.h | 34 +++++++++ include/asterisk/channel_internal.h | 4 ++ include/asterisk/stream.h | 15 ++++ main/channel.c | 9 +++ main/channel_internal_api.c | 103 +++++++++++++++++++++++++++- main/stream.c | 19 +++++ tests/test_voicemail_api.c | 4 +- 7 files changed, 185 insertions(+), 3 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index e5f792f1f41..4170a8af456 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -884,6 +884,10 @@ enum { * world */ AST_CHAN_TP_INTERNAL = (1 << 2), + /*! + * \brief Channels with this particular technology support multiple simultaneous streams + */ + AST_CHAN_TP_MULTISTREAM = (1 << 3), }; /*! \brief ast_channel flags */ @@ -4734,4 +4738,34 @@ enum ast_channel_error ast_channel_errno(void); */ int ast_channel_get_intercept_mode(void); +/*! + * \brief Retrieve the topology of streams on a channel + * + * \param chan The channel to get the stream topology of + * + * \pre chan is locked + * + * \retval non-NULL success + * \retval NULL failure + */ +struct ast_stream_topology *ast_channel_get_stream_topology( + const struct ast_channel *chan); + +/*! + * \brief Set the topology of streams on a channel + * + * \param chan The channel to set the stream topology on + * \param topology The stream topology to set + * + * \pre chan is locked + * + * \note If topology is NULL a new empty topology will be created + * and returned. + * + * \retval non-NULL Success + * \retval NULL failure + */ +struct ast_stream_topology *ast_channel_set_stream_topology( + struct ast_channel *chan, struct ast_stream_topology *topology); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h index 2316e2f24c9..3de2b14aa1c 100644 --- a/include/asterisk/channel_internal.h +++ b/include/asterisk/channel_internal.h @@ -27,3 +27,7 @@ int ast_channel_internal_setup_topics(struct ast_channel *chan); void ast_channel_internal_errno_set(enum ast_channel_error error); enum ast_channel_error ast_channel_internal_errno(void); +void ast_channel_internal_set_stream_topology(struct ast_channel *chan, + struct ast_stream_topology *topology); +void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1, + struct ast_channel *chan2); diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index cffe6ea4cb1..9fb46601352 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -316,4 +316,19 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_format_cap *cap); +/*! + * \brief Gets the first stream of a specific type from the topology + * + * \param topology The topology of streams + * \param type The media type + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 15 + */ +struct ast_stream *ast_stream_topology_get_first_stream_by_type( + const struct ast_stream_topology *topology, + enum ast_media_type type); + #endif /* _AST_STREAM_H */ diff --git a/main/channel.c b/main/channel.c index 23491933650..fa92508ace3 100644 --- a/main/channel.c +++ b/main/channel.c @@ -73,6 +73,7 @@ #include "asterisk/test.h" #include "asterisk/stasis_channels.h" #include "asterisk/max_forwards.h" +#include "asterisk/stream.h" /*** DOCUMENTATION ***/ @@ -806,6 +807,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char struct ast_timer *timer; struct timeval now; const struct ast_channel_tech *channel_tech; + struct ast_stream_topology *topology; /* If shutting down, don't allocate any new channels */ if (ast_shutting_down()) { @@ -886,6 +888,11 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char return ast_channel_unref(tmp); } + if (!(topology = ast_stream_topology_create())) { + return ast_channel_unref(tmp); + } + ast_channel_internal_set_stream_topology(tmp, topology); + /* Always watch the alertpipe */ ast_channel_set_fd(tmp, AST_ALERT_FD, ast_channel_internal_alert_readfd(tmp)); /* And timing pipe */ @@ -7074,6 +7081,8 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann ast_channel_tech(clonechan)->type, ast_channel_name(clonechan)); } + ast_channel_internal_swap_stream_topology(original, clonechan); + /* * Now, at this point, the "clone" channel is totally F'd up. * We mark it as a zombie so nothing tries to touch it. diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index a0cbe864378..235b99604b0 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -46,6 +46,7 @@ #include "asterisk/stasis_channels.h" #include "asterisk/stasis_endpoints.h" #include "asterisk/stringfields.h" +#include "asterisk/stream.h" #include "asterisk/test.h" /*! @@ -221,6 +222,8 @@ struct ast_channel { struct stasis_cp_single *topics; /*!< Topic for all channel's events */ struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */ struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */ + struct ast_stream_topology *stream_topology; /*!< Stream topology */ + struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */ }; /*! \brief The monotonically increasing integer counter for channel uniqueids */ @@ -825,10 +828,57 @@ struct ast_format_cap *ast_channel_nativeformats(const struct ast_channel *chan) { return chan->nativeformats; } -void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value) + +static void channel_set_default_streams(struct ast_channel *chan) +{ + enum ast_media_type type; + + ast_assert(chan != NULL); + + for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; type++) { + if (chan->stream_topology) { + chan->default_streams[type] = + ast_stream_topology_get_first_stream_by_type(chan->stream_topology, type); + } else { + chan->default_streams[type] = NULL; + } + } +} + +void ast_channel_internal_set_stream_topology(struct ast_channel *chan, + struct ast_stream_topology *topology) +{ + ast_stream_topology_destroy(chan->stream_topology); + chan->stream_topology = topology; + channel_set_default_streams(chan); +} + +void ast_channel_nativeformats_set(struct ast_channel *chan, + struct ast_format_cap *value) { + ast_assert(chan != NULL); + ao2_replace(chan->nativeformats, value); + + /* If chan->stream_topology is NULL, the channel is being destroyed + * and topology is destroyed. + */ + if (!chan->stream_topology) { + return; + } + + if (!chan->tech || !(chan->tech->properties & AST_CHAN_TP_MULTISTREAM) || !value) { + struct ast_stream_topology *new_topology; + + if (!value) { + new_topology = ast_stream_topology_create(); + } else { + new_topology = ast_stream_topology_create_from_format_cap(value); + } + ast_channel_internal_set_stream_topology(chan, new_topology); + } } + struct ast_framehook_list *ast_channel_framehooks(const struct ast_channel *chan) { return chan->framehooks; @@ -1637,6 +1687,8 @@ void ast_channel_internal_cleanup(struct ast_channel *chan) stasis_cp_single_unsubscribe(chan->topics); chan->topics = NULL; + + ast_channel_internal_set_stream_topology(chan, NULL); } void ast_channel_internal_finalize(struct ast_channel *chan) @@ -1729,3 +1781,52 @@ enum ast_channel_error ast_channel_internal_errno(void) return *error_code; } + +struct ast_stream_topology *ast_channel_get_stream_topology( + const struct ast_channel *chan) +{ + ast_assert(chan != NULL); + + return chan->stream_topology; +} + +struct ast_stream_topology *ast_channel_set_stream_topology(struct ast_channel *chan, + struct ast_stream_topology *topology) +{ + struct ast_stream_topology *new_topology; + + ast_assert(chan != NULL); + + /* A non-MULTISTREAM channel can't manipulate topology directly */ + ast_assert(chan->tech != NULL && (chan->tech->properties & AST_CHAN_TP_MULTISTREAM)); + + /* Unless the channel is being destroyed, we always want a topology on + * it even if its empty. + */ + if (!topology) { + new_topology = ast_stream_topology_create(); + } else { + new_topology = topology; + } + + if (new_topology) { + ast_channel_internal_set_stream_topology(chan, new_topology); + } + + return new_topology; +} + +void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1, + struct ast_channel *chan2) +{ + struct ast_stream_topology *tmp_topology; + + ast_assert(chan1 != NULL && chan2 != NULL); + + tmp_topology = chan1->stream_topology; + chan1->stream_topology = chan2->stream_topology; + chan2->stream_topology = tmp_topology; + + channel_set_default_streams(chan1); + channel_set_default_streams(chan2); +} diff --git a/main/stream.c b/main/stream.c index 24844c4abeb..5112c959360 100644 --- a/main/stream.c +++ b/main/stream.c @@ -337,3 +337,22 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( return topology; } + +struct ast_stream *ast_stream_topology_get_first_stream_by_type( + const struct ast_stream_topology *topology, + enum ast_media_type type) +{ + int i; + + ast_assert(topology != NULL); + + for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { + struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i); + + if (stream->type == type) { + return stream; + } + } + + return NULL; +} diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c index 802b6bf1b11..e46757263f3 100644 --- a/tests/test_voicemail_api.c +++ b/tests/test_voicemail_api.c @@ -825,12 +825,12 @@ static struct ast_channel *test_vm_api_create_mock_channel(void) } ast_channel_set_writeformat(mock_channel, ast_format_gsm); - native_formats = ast_channel_nativeformats(mock_channel); - ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0); ast_channel_set_rawwriteformat(mock_channel, ast_format_gsm); ast_channel_set_readformat(mock_channel, ast_format_gsm); ast_channel_set_rawreadformat(mock_channel, ast_format_gsm); ast_channel_tech_set(mock_channel, &mock_channel_tech); + native_formats = ast_channel_nativeformats(mock_channel); + ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0); ast_channel_unlock(mock_channel); From 275f469a4d38e4895e2533a09b6afb5a77b09692 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 13 Feb 2017 17:50:41 -0500 Subject: [PATCH 1038/1578] app_voicemail: Allow 'Comedian Mail' branding to be overriden Original patch by John Covert, slight modifications by me. ASTERISK-17428 #close Reported by: John Covert Patches: app_voicemail.c.patch (license #5512) patch uploaded by John Covert Change-Id: Ic3361b0782e5a5397a19ab18eb8550923a9bd6a6 --- CHANGES | 5 +++++ apps/app_voicemail.c | 14 ++++++++++---- configs/samples/voicemail.conf.sample | 7 +++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 79a1840b098..fafaa21412f 100644 --- a/CHANGES +++ b/CHANGES @@ -88,6 +88,11 @@ app_record * Added new 'u' option to Record() application which prevents Asterisk from truncating silence from the end of recorded files. +app_voicemail +------------------ + * The 'Comedian Mail' prompts can now be overriden using the 'vm-login' and + 'vm-newuser' configuration options in voicemail.conf. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 3016f65ba59..af9ffef40fb 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -1034,6 +1034,8 @@ static char listen_control_restart_key[12]; static char listen_control_stop_key[12]; /* custom password sounds */ +static char vm_login[80] = "vm-login"; +static char vm_newuser[80] = "vm-newuser"; static char vm_password[80] = "vm-password"; static char vm_newpassword[80] = "vm-newpassword"; static char vm_passchanged[80] = "vm-passchanged"; @@ -10483,7 +10485,7 @@ static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, st } -static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain) +static int vm_newuser_setup(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain) { int cmd = 0; int duration = 0; @@ -11073,7 +11075,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ adsi_begin(chan, &useadsi); if (!skipuser && useadsi) adsi_login(chan); - if (!silent && !skipuser && ast_streamfile(chan, "vm-login", ast_channel_language(chan))) { + if (!silent && !skipuser && ast_streamfile(chan, vm_login, ast_channel_language(chan))) { ast_log(AST_LOG_WARNING, "Couldn't stream login file\n"); return -1; } @@ -11570,9 +11572,9 @@ static int vm_execmain(struct ast_channel *chan, const char *data) /* Check to see if this is a new user */ if (!strcasecmp(vmu->mailbox, vmu->password) && (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) { - if (ast_play_and_wait(chan, "vm-newuser") == -1) + if (ast_play_and_wait(chan, vm_newuser) == -1) ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n"); - cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain); + cmd = vm_newuser_setup(chan, vmu, &vms, vmfmts, record_gain); if ((cmd == 't') || (cmd == '#')) { /* Timeout */ ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out"); @@ -13989,6 +13991,10 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con } /* load password sounds configuration */ + if ((val = ast_variable_retrieve(cfg, "general", "vm-login"))) + ast_copy_string(vm_login, val, sizeof(vm_login)); + if ((val = ast_variable_retrieve(cfg, "general", "vm-newuser"))) + ast_copy_string(vm_newuser, val, sizeof(vm_newuser)); if ((val = ast_variable_retrieve(cfg, "general", "vm-password"))) ast_copy_string(vm_password, val, sizeof(vm_password)); if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword"))) diff --git a/configs/samples/voicemail.conf.sample b/configs/samples/voicemail.conf.sample index 248e142eb50..1c91ffb34b9 100644 --- a/configs/samples/voicemail.conf.sample +++ b/configs/samples/voicemail.conf.sample @@ -333,6 +333,13 @@ sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside ; The default is "no". ; minpassword=0 ; Enforce minimum password length +; vm-login=custom_sound + ; Customize which sound file is used instead of the default + ; prompt that says: "Comedian Mail. Mailbox?" +; vm-newuser=custom_sound + ; Customize which sound file is used instead of the default + ; prompt that says: "Welcome to Comedian Mail. First, I will + ; guide you through a short setup process." ; vm-password=custom_sound ; Customize which sound file is used instead of the default ; prompt that says: "password" From a9c15a0e4c987d053b0ab43312946719d7655a3f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 14 Feb 2017 18:33:57 +0000 Subject: [PATCH 1039/1578] stream: Add unit tests for channel stream usage. This change adds unit tests cover the following: 1. That retrieving the first media stream of a specific media type from a stream topology retrieves the expected media stream. 2. That setting the native formats of a channel which does not support streams results in the creation of streams on its behalf according to the formats of the channel. 3. That setting a stream topology on a channel which supports streams sets the topology to the provided one. ASTERISK-26790 Change-Id: Ic53176dd3e4532e8c3e97d9e22f8a4b66a2bb755 --- tests/test_stream.c | 248 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) diff --git a/tests/test_stream.c b/tests/test_stream.c index 110e4e4b800..10bf63aa75a 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -37,6 +37,7 @@ #include "asterisk/format.h" #include "asterisk/format_cap.h" #include "asterisk/format_cache.h" +#include "asterisk/channel.h" AST_TEST_DEFINE(stream_create) { @@ -611,6 +612,247 @@ AST_TEST_DEFINE(stream_topology_create_from_format_cap) return AST_TEST_PASS; } +AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + struct ast_stream *first_stream, *second_stream, *third_stream, *fourth_stream; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_get_first_stream_by_type"; + info->category = "/main/stream/"; + info->summary = "stream topology getting first stream by type unit test"; + info->description = + "Test that getting the first stream by type from a topology actually returns the first stream"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_create(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + first_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + if (!first_stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, first_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_destroy(first_stream); + return AST_TEST_FAIL; + } + + second_stream = ast_stream_create("audio2", AST_MEDIA_TYPE_AUDIO); + if (!second_stream) { + ast_test_status_update(test, "Failed to create a second audio stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, second_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_destroy(second_stream); + return AST_TEST_FAIL; + } + + third_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + if (!third_stream) { + ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, third_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_destroy(third_stream); + return AST_TEST_FAIL; + } + + fourth_stream = ast_stream_create("video2", AST_MEDIA_TYPE_VIDEO); + if (!fourth_stream) { + ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, fourth_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_destroy(fourth_stream); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_AUDIO) != first_stream) { + ast_test_status_update(test, "Retrieved first audio stream from topology but it is not the correct one\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_VIDEO) != third_stream) { + ast_test_status_update(test, "Retrieved first video stream from topology but it is not the correct one\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +static const struct ast_channel_tech mock_channel_tech = { +}; + +AST_TEST_DEFINE(stream_topology_create_from_channel_nativeformats) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + struct ast_channel *mock_channel; + enum ast_test_result_state res = AST_TEST_FAIL; + struct ast_str *codec_have_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + struct ast_str *codec_wanted_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_create_from_channel_nativeformats"; + info->category = "/main/stream/"; + info->summary = "stream topology creation from channel native formats unit test"; + info->description = + "Test that creating a stream topology from the setting of channel nativeformats results in the expected streams"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { + ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_alaw, 0)) { + ast_test_status_update(test, "Failed to append an alaw format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_h264, 0)) { + ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"); + if (!mock_channel) { + ast_test_status_update(test, "Failed to create a mock channel for testing\n"); + return AST_TEST_FAIL; + } + + ast_channel_tech_set(mock_channel, &mock_channel_tech); + ast_channel_nativeformats_set(mock_channel, caps); + + if (!ast_channel_get_stream_topology(mock_channel)) { + ast_test_status_update(test, "Set nativeformats with ulaw, alaw, and h264 on channel but it did not create a topology\n"); + goto end; + } + + if (ast_stream_topology_get_count(ast_channel_get_stream_topology(mock_channel)) != 2) { + ast_test_status_update(test, "Set nativeformats on a channel to ulaw, alaw, and h264 and received '%d' streams instead of expected 2\n", + ast_stream_topology_get_count(ast_channel_get_stream_topology(mock_channel))); + goto end; + } + + if (ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0)) != AST_MEDIA_TYPE_AUDIO) { + ast_test_status_update(test, "First stream on channel is of %s when it should be audio\n", + ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0)))); + goto end; + } + + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_VIDEO); + if (!ast_format_cap_identical(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0)), caps)) { + ast_test_status_update(test, "Formats on audio stream of channel are '%s' when they should be '%s'\n", + ast_format_cap_get_names(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0)), &codec_have_buf), + ast_format_cap_get_names(caps, &codec_wanted_buf)); + goto end; + } + + if (ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1)) != AST_MEDIA_TYPE_VIDEO) { + ast_test_status_update(test, "Second stream on channel is of type %s when it should be video\n", + ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1)))); + goto end; + } + + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO); + + if (ast_format_cap_append(caps, ast_format_h264, 0)) { + ast_test_status_update(test, "Failed to append h264 video codec to capabilities for capabilities comparison\n"); + goto end; + } + + if (!ast_format_cap_identical(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1)), caps)) { + ast_test_status_update(test, "Formats on video stream of channel are '%s' when they should be '%s'\n", + ast_format_cap_get_names(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1)), &codec_wanted_buf), + ast_format_cap_get_names(caps, &codec_wanted_buf)); + goto end; + } + + res = AST_TEST_PASS; + +end: + ast_channel_unlock(mock_channel); + ast_hangup(mock_channel); + + return res; +} + +static const struct ast_channel_tech mock_stream_channel_tech = { + .properties = AST_CHAN_TP_MULTISTREAM, +}; + +AST_TEST_DEFINE(stream_topology_channel_set) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + struct ast_channel *mock_channel; + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_channel_set"; + info->category = "/main/stream/"; + info->summary = "stream topology setting on a channel unit test"; + info->description = + "Test that setting a stream topology on a channel works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_create(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"); + if (!mock_channel) { + ast_test_status_update(test, "Failed to create a mock channel for testing\n"); + return AST_TEST_FAIL; + } + + ast_channel_tech_set(mock_channel, &mock_stream_channel_tech); + ast_channel_set_stream_topology(mock_channel, topology); + + if (ast_channel_get_stream_topology(mock_channel) != topology) { + ast_test_status_update(test, "Set an explicit stream topology on a channel but the returned one did not match it\n"); + res = AST_TEST_FAIL; + } + + topology = NULL; + ast_channel_unlock(mock_channel); + ast_hangup(mock_channel); + + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -624,6 +866,9 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_append_stream); AST_TEST_UNREGISTER(stream_topology_set_stream); AST_TEST_UNREGISTER(stream_topology_create_from_format_cap); + AST_TEST_UNREGISTER(stream_topology_get_first_stream_by_type); + AST_TEST_UNREGISTER(stream_topology_create_from_channel_nativeformats); + AST_TEST_UNREGISTER(stream_topology_channel_set); return 0; } @@ -639,6 +884,9 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_append_stream); AST_TEST_REGISTER(stream_topology_set_stream); AST_TEST_REGISTER(stream_topology_create_from_format_cap); + AST_TEST_REGISTER(stream_topology_get_first_stream_by_type); + AST_TEST_REGISTER(stream_topology_create_from_channel_nativeformats); + AST_TEST_REGISTER(stream_topology_channel_set); return AST_MODULE_LOAD_SUCCESS; } From b58de2fab71ad53b5a385476620dc7b45970cfb6 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Thu, 22 Dec 2016 16:42:46 +0100 Subject: [PATCH 1040/1578] Binaural synthesis (confbridge): Adds utils/conf_bridge_binaural_hrir_importer Adds the import tool for converting a HRIR database to hrirs.h ASTERISK-26292 Change-Id: I51eb31b54c23ffd9b544bdc6a09d20c112c8a547 --- build_tools/menuselect-deps.in | 1 + configure | 227 ++++++++++++++------- configure.ac | 4 + include/asterisk/autoconfig.h.in | 9 +- makeopts.in | 3 + utils/Makefile | 9 + utils/conf_bridge_binaural_hrir_importer.c | 148 ++++++++++++++ utils/utils.xml | 5 + 8 files changed, 324 insertions(+), 82 deletions(-) create mode 100644 utils/conf_bridge_binaural_hrir_importer.c diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index 9f1aa708265..ec70be0daa1 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -57,6 +57,7 @@ RESAMPLE=@PBX_RESAMPLE@ FFTW3=@PBX_FFTW3@ RADIUS=@PBX_RADIUS@ LAUNCHD=@PBX_LAUNCHD@ +SNDFILE=@PBX_SNDFILE@ SPANDSP=@PBX_SPANDSP@ SPEEX=@PBX_SPEEX@ SPEEXDSP=@PBX_SPEEXDSP@ diff --git a/configure b/configure index 7e720745e7c..ba8d59357e4 100755 --- a/configure +++ b/configure @@ -835,6 +835,10 @@ PBX_SDL SDL_DIR SDL_INCLUDE SDL_LIB +PBX_SNDFILE +SNDFILE_DIR +SNDFILE_INCLUDE +SNDFILE_LIB PBX_RESAMPLE RESAMPLE_DIR RESAMPLE_INCLUDE @@ -1258,7 +1262,6 @@ COMPRESS FIND PYTHON FLEX -CUT CAT CMP BISON @@ -1345,7 +1348,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1432,6 +1434,7 @@ with_pwlib with_radius with_fftw3 with_resample +with_sndfile with_sdl with_SDL_image with_spandsp @@ -1528,7 +1531,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1781,15 +1783,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1927,7 +1920,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2080,7 +2073,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -2194,6 +2186,7 @@ Optional Packages: --with-radius=PATH use Radius Client files in PATH --with-fftw3=PATH use LIBFFTW3 files in PATH --with-resample=PATH use LIBRESAMPLE files in PATH + --with-sndfile=PATH use libsndfile files in PATH --with-sdl=PATH use Sdl files in PATH --with-SDL_image=PATH use Sdl Image files in PATH --with-spandsp=PATH use SPANDSP files in PATH @@ -6848,47 +6841,6 @@ $as_echo "no" >&6; } fi -# Extract the first word of "cut", so it can be a program name with args. -set dummy cut; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CUT+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $CUT in - [\\/]* | ?:[\\/]*) - ac_cv_path_CUT="$CUT" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CUT="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_CUT" && ac_cv_path_CUT=":" - ;; -esac -fi -CUT=$ac_cv_path_CUT -if test -n "$CUT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CUT" >&5 -$as_echo "$CUT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - # Extract the first word of "flex", so it can be a program name with args. set dummy flex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -9338,7 +9290,7 @@ $as_echo "configuring" >&6; } as_fn_error $? "nm is required to build bundled pjproject" "$LINENO" 5 fi if test "${MD5}" = ":" ; then - as_fn_error $? "md5dum is required to build bundled pjproject" "$LINENO" 5 + as_fn_error $? "md5sum is required to build bundled pjproject" "$LINENO" 5 fi if test "${CAT}" = ":" ; then as_fn_error $? "cat is required to build bundled pjproject" "$LINENO" 5 @@ -12064,6 +12016,38 @@ fi + SNDFILE_DESCRIP="libsndfile" + SNDFILE_OPTION="sndfile" + PBX_SNDFILE=0 + +# Check whether --with-sndfile was given. +if test "${with_sndfile+set}" = set; then : + withval=$with_sndfile; + case ${withval} in + n|no) + USE_SNDFILE=no + # -1 is a magic value used by menuselect to know that the package + # was disabled, other than 'not found' + PBX_SNDFILE=-1 + ;; + y|ye|yes) + ac_mandatory_list="${ac_mandatory_list} SNDFILE" + ;; + *) + SNDFILE_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} SNDFILE" + ;; + esac + +fi + + + + + + + + SDL_DESCRIP="Sdl" SDL_OPTION="sdl" PBX_SDL=0 @@ -14838,7 +14822,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14884,7 +14868,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14908,7 +14892,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14953,7 +14937,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14977,7 +14961,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -17086,21 +17070,6 @@ fi -# https support (in main/http.c) uses funopen on BSD systems, -# fopencookie on linux -for ac_func in funopen fopencookie -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - for ac_func in inet_aton do : ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton" @@ -29413,6 +29382,112 @@ $as_echo "#define HAVE_FFTW 1" >>confdefs.h fi +if test "x${PBX_SNDFILE}" != "x1" -a "${USE_SNDFILE}" != "no"; then + pbxlibdir="" + # if --with-SNDFILE=DIR has been specified, use it. + if test "x${SNDFILE_DIR}" != "x"; then + if test -d ${SNDFILE_DIR}/lib; then + pbxlibdir="-L${SNDFILE_DIR}/lib" + else + pbxlibdir="-L${SNDFILE_DIR}" + fi + fi + pbxfuncname="sf_open" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SNDFILE_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_sndfile_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsndfile" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsndfile... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsndfile ${pbxlibdir} -lsndfile $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SNDFILE_FOUND=yes +else + AST_SNDFILE_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SNDFILE_FOUND}" = "yes"; then + SNDFILE_LIB="${pbxlibdir} -lsndfile -lsndfile" + # if --with-SNDFILE=DIR has been specified, use it. + if test "x${SNDFILE_DIR}" != "x"; then + SNDFILE_INCLUDE="-I${SNDFILE_DIR}/include" + fi + SNDFILE_INCLUDE="${SNDFILE_INCLUDE} " + if test "xsndfile.h" = "x" ; then # no header, assume found + SNDFILE_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SNDFILE_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "sndfile.h" "ac_cv_header_sndfile_h" "$ac_includes_default" +if test "x$ac_cv_header_sndfile_h" = xyes; then : + SNDFILE_HEADER_FOUND=1 +else + SNDFILE_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SNDFILE_HEADER_FOUND}" = "x0" ; then + SNDFILE_LIB="" + SNDFILE_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SNDFILE_LIB="" + fi + PBX_SNDFILE=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SNDFILE 1 +_ACEOF + + fi + fi +fi + + + + + if test "x${PBX_SPANDSP}" != "x1" -a "${USE_SPANDSP}" != "no"; then if test "xminimum version of SpanDSP" != "x"; then diff --git a/configure.ac b/configure.ac index d604d47a590..982412eceb8 100644 --- a/configure.ac +++ b/configure.ac @@ -551,6 +551,7 @@ AST_EXT_LIB_SETUP([PWLIB], [PWlib], [pwlib]) AST_EXT_LIB_SETUP([RADIUS], [Radius Client], [radius]) AST_EXT_LIB_SETUP([FFTW3], [LIBFFTW3], [fftw3]) AST_EXT_LIB_SETUP([RESAMPLE], [LIBRESAMPLE], [resample]) +AST_EXT_LIB_SETUP([SNDFILE], [libsndfile], [sndfile]) AST_EXT_LIB_SETUP([SDL], [Sdl], [sdl]) AST_EXT_LIB_SETUP([SDL_IMAGE], [Sdl Image], [SDL_image]) AST_EXT_LIB_SETUP([SPANDSP], [SPANDSP], [spandsp]) @@ -2284,6 +2285,9 @@ AST_EXT_LIB_CHECK([FFTW3], [fftw3], [fftw_alloc_real], [fftw3.h], [-lfftw3]) if test "$PBX_FFTW3" = "1"; then AC_DEFINE([HAVE_FFTW], 1, [Define 1 if your system has fftw.]) fi +AST_EXT_LIB_CHECK([SNDFILE], [sndfile], [sf_open], [sndfile.h], [-lsndfile]) + + AST_C_COMPILE_CHECK([SPANDSP], [ #if SPANDSP_RELEASE_DATE < 20080516 diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index e8bd8118a21..34684920d22 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -254,9 +254,6 @@ /* Define to 1 if you have the `fmodl' function. */ #undef HAVE_FMODL -/* Define to 1 if you have the `fopencookie' function. */ -#undef HAVE_FOPENCOOKIE - /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK @@ -269,9 +266,6 @@ /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE -/* Define to 1 if you have the `funopen' function. */ -#undef HAVE_FUNOPEN - /* Define to 1 if your GCC C compiler provides atomic operations. */ #undef HAVE_GCC_ATOMICS @@ -828,6 +822,9 @@ /* Define to 1 if you have the `sinl' function. */ #undef HAVE_SINL +/* Define to 1 if you have the libsndfile library. */ +#undef HAVE_SNDFILE + /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET diff --git a/makeopts.in b/makeopts.in index c67e2f2b6ec..6a1164c329b 100644 --- a/makeopts.in +++ b/makeopts.in @@ -380,3 +380,6 @@ TINFO_DIR=@TINFO_DIR@ # if poll is not present, let the makefile know. POLL_AVAILABLE=@HAS_POLL@ TIMERFD_INCLUDE=@TIMERFD_INCLUDE@ + +SNDFILE_INCLUDE=@SNDFILE_INCLUDE@ +SNDFILE_LIB=@SNDFILE_LIB@ diff --git a/utils/Makefile b/utils/Makefile index 97b0e2fe6eb..b6618e19518 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -70,6 +70,10 @@ ifneq ($(filter pbx_ael,$(MENUSELECT_PBX)),) UTILS:=$(filter-out conf2ael,$(UTILS)) endif +ifeq ($(SNDFILE_LIB),) + UTILS:=$(filter-out conf_bridge_binaural_hrir_importer,$(UTILS)) +endif + all: $(UTILS) install: @@ -93,6 +97,7 @@ clean: rm -f db1-ast/.*.d @$(MAKE) -C db1-ast clean + md5.c: $(ASTTOPDIR)/main/md5.c $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@" $(CMD_PREFIX) cp "$<" "$@" @@ -188,6 +193,10 @@ smsq: LIBS+=$(POPT_LIB) streamplayer: streamplayer.o +conf_bridge_binaural_hrir_importer: LIBS+=$(SNDFILE_LIB) +conf_bridge_binaural_hrir_importer: _ASTCFLAGS+=$(SNDFILE_INCLUDE) +conf_bridge_binaural_hrir_importer: conf_bridge_binaural_hrir_importer.o + muted: muted.o muted: LIBS+=$(AUDIO_LIBS) muted: _ASTCFLAGS:=$(filter-out -Werror,$(_ASTCFLAGS)) diff --git a/utils/conf_bridge_binaural_hrir_importer.c b/utils/conf_bridge_binaural_hrir_importer.c new file mode 100644 index 00000000000..5690d86ea7a --- /dev/null +++ b/utils/conf_bridge_binaural_hrir_importer.c @@ -0,0 +1,148 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Digium, Inc. + * + * Frank Haase + * Dennis Guse + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * Converts a Head Related Impulse Response (HRIR) database (a multi-channel wave) into a C header file. + * HRIR for the left ear and HRIR for right ear have to be interleaved. + * No further signal processing is applied (e.g., resampling). + * + * Info messages are printed to stderror and the generated header file to output. + */ + +#include +#include +#include +#include + +int main (int argc, char **argv) +{ + char *hrir_filename; + unsigned int binaural_index_start; + unsigned int binaural_index_end; + + SNDFILE *hrir_file; + SF_INFO hrir_info; + float *hrir_data; + + unsigned int impulse_response_index_start; + unsigned int impulse_response_index_end; + + int j; + int ir_current; + + if(argc != 4) { + puts("HRIR database to C header file converter."); + puts("Usage: conf_bridge_binaural_hrir_importer HRIR.wav INDEX_START INDEX_END > OUTPUT.h"); + puts("Example: conf_bridge_binaural_hrir_importer hrirs.wav 0 180 > ../bridges/bridge_softmix/include/hrirs.h"); + + return -1; + } + + /* Parse arguments */ + hrir_filename = argv[1]; + binaural_index_start = atoi(argv[2]); + binaural_index_end = atoi(argv[3]); + + /* Read HRIR database */ + hrir_file = sf_open(hrir_filename, SFM_READ, &hrir_info); + if(hrir_file == NULL) { + fprintf(stderr, "ERROR: Could not open HRIR database (%s).\n", hrir_filename); + + return -1; + } + fprintf(stderr, "INFO: Opened HRIR database (%s) with: number channels: %d; samplerate: %d; samples per channel: %ld\n", hrir_filename, hrir_info.channels, hrir_info.samplerate, hrir_info.frames); + + hrir_data = (float *)malloc(hrir_info.channels * hrir_info.frames * sizeof(float)); + if(hrir_data == NULL) { + fprintf(stderr, "ERROR: Out of memory!"); + + return -1; + } + + /* Channels are interleaved */ + sf_read_float(hrir_file, hrir_data, hrir_info.channels * hrir_info.frames); + sf_close(hrir_file); + + if(binaural_index_start >= binaural_index_end) { + fprintf(stderr, "ERROR: INDEX_START (%d) must be smaller than INDEX_END (%d).", binaural_index_start, binaural_index_end); + free(hrir_data); + + return -1; + } + + if (binaural_index_end * 2 >= hrir_info.channels) { + fprintf(stderr, "ERROR: END_INDEX (%d) is out of range for HRIR database (%s).\n", binaural_index_end, hrir_filename); + free(hrir_data); + + return -1; + } + + /* Convert indices */ + impulse_response_index_start = 2 * binaural_index_start; + impulse_response_index_end = (binaural_index_end + 1) * 2; + + /* Write header */ + printf("//Used hrirs database: %s\n", hrir_filename); + printf("//Start index in database: %d\n", impulse_response_index_start); + printf("//End index in database: %d\n", impulse_response_index_end); + + printf("#define HRIRS_IMPULSE_LEN %ld\n", hrir_info.frames); + printf("#define HRIRS_IMPULSE_SIZE %d\n", binaural_index_end - binaural_index_start + 1); + printf("#define HRIRS_SAMPLE_RATE %d\n", hrir_info.samplerate); + + printf("float hrirs_left[HRIRS_IMPULSE_SIZE][HRIRS_IMPULSE_LEN] = {\n"); + for (ir_current = impulse_response_index_start; ir_current < impulse_response_index_end; ir_current += 2) { + printf("{"); + + for (j = 0; j < hrir_info.frames - 1; j++) { + printf("%.16f,", hrir_data[ir_current * hrir_info.frames + j]); + } + /* Write last without trailing "," */ + printf("%.16f", hrir_data[ir_current * hrir_info.frames + hrir_info.frames - 1]); + + if (ir_current + 2 < impulse_response_index_end) { + printf("},\n"); + } else { + printf("}};"); + } + } + + printf("\nfloat hrirs_right[HRIRS_IMPULSE_SIZE][HRIRS_IMPULSE_LEN] = {\n"); + for (ir_current = impulse_response_index_start + 1; ir_current < impulse_response_index_end + 1; ir_current += 2) { + printf("{"); + + for (j = 0; j < hrir_info.frames - 1; j++) { + printf("%.16f,", hrir_data[ir_current * hrir_info.frames + j]); + } + /* Write last without trailing "," */ + printf("%.16f", hrir_data[ir_current * hrir_info.frames + hrir_info.frames - 1]); + + if (ir_current + 2 < impulse_response_index_end) { + printf("},\n"); + } else { + printf("}};"); + } + } + + fprintf(stderr, "INFO: Successfully converted: imported %d impulse responses.\n", impulse_response_index_end - impulse_response_index_start); + free(hrir_data); + + return 0; +} diff --git a/utils/utils.xml b/utils/utils.xml index 909406e849c..498929a27d5 100644 --- a/utils/utils.xml +++ b/utils/utils.xml @@ -20,6 +20,11 @@ newt extended + + no + sndfile + extended + no extended From 11886dea82b2d342c946f669144d5afaa667a26a Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 15 Feb 2017 12:03:00 -0500 Subject: [PATCH 1041/1578] res_rtp_asterisk: Use PJ_ICE_MAX_CAND instead of hard-coding 16 pjsip limits the total number of ICE candidates to PJ_ICE_MAX_CAND, which is a compile-time constant. Instead of hard-coding 16 when we enumerate local interfaces, use PJ_ICE_MAX_CAND so that we can potentially collect more interfaces if the compile time options are changed. Tangentially related to ASTERISK~24464 Change-Id: I1b85509e39e33b1fed63c86261fc229ba14bbabd --- res/res_rtp_asterisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 3d124000a5f..5d7adcd4386 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2479,7 +2479,7 @@ static int rtp_address_is_ice_blacklisted(const pj_sockaddr_t *address) static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_sockaddr *addr, int port, int component, int transport) { - pj_sockaddr address[16]; + pj_sockaddr address[PJ_ICE_MAX_CAND]; unsigned int count = PJ_ARRAY_SIZE(address), pos = 0; int basepos = -1; From 4bdf5d329fb10d90d3ba53188834c58f54a5324c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 7 Feb 2017 12:17:12 -0700 Subject: [PATCH 1042/1578] res_pjsip_pubsub: Correctly implement persisted subscriptions This patch fixes 2 original issues and more that those 2 exposed. * When we send a NOTIFY, and the client either doesn't respond or responds with a non OK, pjproject only calls our pubsub_on_evsub_state callback, no others. Since pubsub_on_evsub_state (which does the sub_tree cleanup) does not expect to be called back without the other callbacks being called first, it just returns leaving the sub_tree orphaned. Now pubsub_on_evsub_state checks the event for PJSIP_EVENT_TSX_STATE which is what pjproject will set to tell us that it was the transaction that timed out or failed and not the subscription itself timing our or being terminated by the client. If is TSX_STATE, pubsub_on_evsub_state now does the proper cleanup regardless of the state of the subscription. * When a client renews a subscription, we don't update the persisted subscription with the new expires timestamp. This causes subscription_persistence_recreate to prune the subscription if/when asterisk restarts. Now, pubsub_on_rx_refresh calls subscription_persistence_update to apply the new expires timestamp. This exposed other issues however... * When creating a dialog from rdata (which sub_persistence_recreate does from the packet buffer) there must NOT be a tag on the To header (which there will be when a client refreshes a subscription). If there is one, pjsip_dlg_create_uas will fail. To address this, subscription_persistence_update now accepts a flag that indicates that the original packet buffer must not be updated. New subscribes don't set the flag and renews do. This makes sure that when the rdata is recreated on asterisk startup, it's done from the original subscribe packet which won't have the tag on To. * When creating a dialog from rdata, we were setting the dialog's remote (SUBSCRIBE) cseq to be the same as the local (NOTIFY) cseq. When the client tried to resubscribe after a restart with the correct cseq, we'd reject the request with an Invalid CSeq error. * The acts of creating a dialog and evsub by themselves when recreating a subscription does NOT restart pjproject's subscription timer. The result was that even if we did correctly recreate the subscription, we never removed it if the client happened to go away or send a non-OK response to a NOTIFY. However, there is no pjproject function exposed to just set the timer on an evsub that wasn't created by an incoming subscribe request. To address this, we create our own timer using ast_sip_schedule_task. This timer is used only for re-establishing subscriptions after a restart. An earlier approach was to add support for setting pjproject's timer (via a pjproject patch) and while that patch is still included here, we don't use that call at the moment. While addressing these issues, additional debugging was added and some existing messages made more useful. A few formatting changes were also made to 'pjsip show scheduled tasks' to make displaying the subscription timers a little more friendly. ASTERISK-26696 ASTERISK-26756 Change-Id: I8c605fc1e3923f466a74db087d5ab6f90abce68e --- configure | 123 ++++++++++ configure.ac | 2 + include/asterisk/autoconfig.h.in | 4 + res/res_pjsip/pjsip_scheduler.c | 32 ++- res/res_pjsip_exten_state.c | 5 +- res/res_pjsip_pubsub.c | 231 ++++++++++++++---- third-party/pjproject/configure.m4 | 1 + ...vsub-Add-pjsip_evsub_set_uas_timeout.patch | 84 +++++++ 8 files changed, 420 insertions(+), 62 deletions(-) create mode 100644 third-party/pjproject/patches/0010-evsub-Add-pjsip_evsub_set_uas_timeout.patch diff --git a/configure b/configure index 7e720745e7c..2b25eadb152 100755 --- a/configure +++ b/configure @@ -943,6 +943,10 @@ PBX_POPT POPT_DIR POPT_INCLUDE POPT_LIB +PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT +PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR +PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE +PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB PBX_PJSIP_AUTH_CLT_DEINIT PJSIP_AUTH_CLT_DEINIT_DIR PJSIP_AUTH_CLT_DEINIT_INCLUDE @@ -9399,6 +9403,9 @@ $as_echo "#define HAVE_PJSIP_INV_SESSION_REF 1" >>confdefs.h $as_echo "#define HAVE_PJSIP_AUTH_CLT_DEINIT 1" >>confdefs.h +$as_echo "#define HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT 1" >>confdefs.h + + @@ -11593,6 +11600,18 @@ PBX_PJSIP_AUTH_CLT_DEINIT=0 + +PJSIP_EVSUB_SET_UAS_TIMEOUT_DESCRIP="PJSIP EVSUB Set UAS Timeout support" +PJSIP_EVSUB_SET_UAS_TIMEOUT_OPTION=pjsip +PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR=${PJPROJECT_DIR} + +PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT=0 + + + + + + fi @@ -26705,6 +26724,110 @@ _ACEOF fi + +if test "x${PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT}" != "x1" -a "${USE_PJSIP_EVSUB_SET_UAS_TIMEOUT}" != "no"; then + pbxlibdir="" + # if --with-PJSIP_EVSUB_SET_UAS_TIMEOUT=DIR has been specified, use it. + if test "x${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}" != "x"; then + if test -d ${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}/lib; then + pbxlibdir="-L${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}/lib" + else + pbxlibdir="-L${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}" + fi + fi + pbxfuncname="pjsip_evsub_set_uas_timeout" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS" + as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND=yes +else + AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_PJSIP_EVSUB_SET_UAS_TIMEOUT_FOUND}" = "yes"; then + PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB" + # if --with-PJSIP_EVSUB_SET_UAS_TIMEOUT=DIR has been specified, use it. + if test "x${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}" != "x"; then + PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE="-I${PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR}/include" + fi + PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE="${PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE} $PJPROJECT_CFLAGS" + if test "xpjsip.h" = "x" ; then # no header, assume found + PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default" +if test "x$ac_cv_header_pjsip_h" = xyes; then : + PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND=1 +else + PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${PJSIP_EVSUB_SET_UAS_TIMEOUT_HEADER_FOUND}" = "x0" ; then + PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB="" + PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + PJSIP_EVSUB_SET_UAS_TIMEOUT_LIB="" + fi + PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT 1 +_ACEOF + + fi + fi +fi + + fi fi diff --git a/configure.ac b/configure.ac index d604d47a590..63d2b41532f 100644 --- a/configure.ac +++ b/configure.ac @@ -518,6 +518,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_PROTO], [PJSIP TLS Transport pro AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_GRP_LOCK], [PJSIP EVSUB Group Lock support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_SESSION_REF], [PJSIP INVITE Session Reference Count support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_AUTH_CLT_DEINIT], [pjsip_auth_clt_deinit support], [PJPROJECT], [pjsip]) +AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_SET_UAS_TIMEOUT], [PJSIP EVSUB Set UAS Timeout support], [PJPROJECT], [pjsip]) fi AST_EXT_LIB_SETUP([POPT], [popt], [popt]) @@ -2241,6 +2242,7 @@ if test "$USE_PJPROJECT" != "no" ; then AST_EXT_LIB_CHECK([PJSIP_EVSUB_GRP_LOCK], [pjsip], [pjsip_evsub_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJSIP_INV_SESSION_REF], [pjsip], [pjsip_inv_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJSIP_AUTH_CLT_DEINIT], [pjsip], [pjsip_auth_clt_deinit], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJSIP_EVSUB_SET_UAS_TIMEOUT], [pjsip], [pjsip_evsub_set_uas_timeout], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) fi fi diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index e8bd8118a21..41ba61353a0 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -602,6 +602,10 @@ /* Define to 1 if PJPROJECT has the PJSIP EVSUB Group Lock support feature. */ #undef HAVE_PJSIP_EVSUB_GRP_LOCK +/* Define to 1 if PJPROJECT has the PJSIP EVSUB Set UAS Timeout support + feature. */ +#undef HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT + /* Define to 1 if PJPROJECT has the PJSIP External Resolver Support feature. */ #undef HAVE_PJSIP_EXTERNAL_RESOLVER diff --git a/res/res_pjsip/pjsip_scheduler.c b/res/res_pjsip/pjsip_scheduler.c index 27202c602f1..e4459da6694 100644 --- a/res/res_pjsip/pjsip_scheduler.c +++ b/res/res_pjsip/pjsip_scheduler.c @@ -373,7 +373,7 @@ static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_arg struct ast_tm tm; char queued[32]; char last_start[32]; - char last_end[32]; + char next_start[32]; int datelen; struct timeval now = ast_tvnow(); const char *separator = "======================================"; @@ -397,19 +397,21 @@ static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_arg ast_cli(a->fd, "PJSIP Scheduled Tasks:\n\n"); - ast_cli(a->fd, " %1$-24s %2$-8s %3$-9s %4$-7s %6$-*5$s %7$-*5$s %8$-*5$s\n", + ast_cli(a->fd, " %1$-24s %2$-9s %3$-9s %4$-5s %6$-*5$s %7$-*5$s %8$-*5$s %9$7s\n", "Task Name", "Interval", "Times Run", "State", - datelen, "Queued", "Last Started", "Last Ended"); + datelen, "Queued", "Last Started", "Next Start", "( secs)"); - ast_cli(a->fd, " %1$-24.24s %2$-8.8s %3$-9.9s %4$-7.7s %6$-*5$.*5$s %7$-*5$.*5$s %8$-*5$.*5$s\n", + ast_cli(a->fd, " %1$-24.24s %2$-9.9s %3$-9.9s %4$-5.5s %6$-*5$.*5$s %7$-*5$.*5$s %9$-*8$.*8$s\n", separator, separator, separator, separator, - datelen, separator, separator, separator); + datelen, separator, separator, datelen + 8, separator); ao2_ref(tasks, +1); ao2_rdlock(tasks); i = ao2_iterator_init(tasks, 0); while ((schtd = ao2_iterator_next(&i))) { + int next_run_sec = ast_sip_sched_task_get_next_run(schtd) / 1000; + struct timeval next = ast_tvadd(now, (struct timeval) {next_run_sec, 0}); ast_localtime(&schtd->when_queued, &tm, NULL); ast_strftime(queued, sizeof(queued), log_format, &tm); @@ -421,23 +423,17 @@ static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_arg ast_strftime(last_start, sizeof(last_start), log_format, &tm); } - if (ast_tvzero(schtd->last_end)) { - if (ast_tvzero(schtd->last_start)) { - strcpy(last_end, "not yet started"); - } else { - strcpy(last_end, "running"); - } - } else { - ast_localtime(&schtd->last_end, &tm, NULL); - ast_strftime(last_end, sizeof(last_end), log_format, &tm); - } + ast_localtime(&next, &tm, NULL); + ast_strftime(next_start, sizeof(next_start), log_format, &tm); - ast_cli(a->fd, " %1$-24.24s %2$-8.3f %3$-9d %4$-7s %6$-*5$s %7$-*5$s %8$-*5$s\n", + ast_cli(a->fd, " %1$-24.24s %2$9.3f %3$9d %4$-5s %6$-*5$s %7$-*5$s %8$-*5$s (%9$5d)\n", schtd->name, schtd->interval / 1000.0, schtd->run_count, - schtd->is_running ? "running" : "waiting", - datelen, queued, last_start, last_end); + schtd->is_running ? "run" : "wait", + datelen, queued, last_start, + next_start, + next_run_sec); ao2_cleanup(schtd); } ao2_iterator_destroy(&i); diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 9bb53bfe31c..95a40829e62 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -415,8 +415,9 @@ static int new_subscribe(struct ast_sip_endpoint *endpoint, const char *context = S_OR(endpoint->subscription.context, endpoint->context); if (!ast_exists_extension(NULL, context, resource, PRIORITY_HINT, NULL)) { - ast_log(LOG_NOTICE, "Extension state subscription failed: Extension %s does not exist in context '%s' or has no associated hint\n", - resource, context); + ast_log(LOG_NOTICE, "Endpoint '%s' state subscription failed: " + "Extension '%s' does not exist in context '%s' or has no associated hint\n", + ast_sorcery_object_get_id(endpoint), resource, context); return 404; } diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 42f0dc11ec8..709dc664047 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -392,6 +392,13 @@ enum sip_subscription_tree_state { SIP_SUB_TREE_TERMINATED, }; +static char *sub_tree_state_description[] = { + "Normal", + "TerminatePending", + "TerminateInProgress", + "Terminated" +}; + /*! * \brief A tree of SIP subscriptions * @@ -428,6 +435,11 @@ struct sip_subscription_tree { AST_LIST_ENTRY(sip_subscription_tree) next; /*! Subscription tree state */ enum sip_subscription_tree_state state; + /*! On asterisk restart, this is the task data used + * to restart the expiration timer if pjproject isn't + * capable of restarting the timer. + */ + struct ast_sip_sched_task *expiration_task; }; /*! @@ -482,6 +494,17 @@ static const char *sip_subscription_roles_map[] = { [AST_SIP_NOTIFIER] = "Notifier" }; +enum sip_persistence_update_type { + /*! Called from send request */ + SUBSCRIPTION_PERSISTENCE_SEND_REQUEST = 0, + /*! Subscription created from initial client request */ + SUBSCRIPTION_PERSISTENCE_CREATED, + /*! Subscription recreated by asterisk on startup */ + SUBSCRIPTION_PERSISTENCE_RECREATED, + /*! Subscription created from client refresh */ + SUBSCRIPTION_PERSISTENCE_REFRESHED, +}; + AST_RWLIST_HEAD_STATIC(subscriptions, sip_subscription_tree); AST_RWLIST_HEAD_STATIC(body_generators, ast_sip_pubsub_body_generator); @@ -560,7 +583,7 @@ static struct subscription_persistence *subscription_persistence_create(struct s /*! \brief Function which updates persistence information of a subscription in sorcery */ static void subscription_persistence_update(struct sip_subscription_tree *sub_tree, - pjsip_rx_data *rdata) + pjsip_rx_data *rdata, enum sip_persistence_update_type type) { pjsip_dialog *dlg; @@ -568,6 +591,9 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr return; } + ast_debug(3, "Updating persistence for '%s->%s'\n", + ast_sorcery_object_get_id(sub_tree->endpoint), sub_tree->root->resource); + dlg = sub_tree->dlg; sub_tree->persistence->cseq = dlg->local.cseq; @@ -584,12 +610,15 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr * persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will * only ever have a single SIP message on it, and so we base persistence on that. */ - if (rdata->msg_info.msg_buf) { - ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf, - MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len)); - } else { - ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet, - sizeof(sub_tree->persistence->packet)); + if (type == SUBSCRIPTION_PERSISTENCE_CREATED + || type == SUBSCRIPTION_PERSISTENCE_RECREATED) { + if (rdata->msg_info.msg_buf) { + ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf, + MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len)); + } else { + ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet, + sizeof(sub_tree->persistence->packet)); + } } ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name, sizeof(sub_tree->persistence->src_name)); @@ -986,7 +1015,8 @@ static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct a struct resources visited; if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) { - ast_debug(2, "Subscription to resource %s is not to a list\n", resource); + ast_debug(2, "Subscription '%s->%s' is not to a list\n", + ast_sorcery_object_get_id(endpoint), resource); tree->root = tree_node_alloc(resource, NULL, 0); if (!tree->root) { return 500; @@ -994,7 +1024,8 @@ static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct a return handler->notifier->new_subscribe(endpoint, resource); } - ast_debug(2, "Subscription to resource %s is a list\n", resource); + ast_debug(2, "Subscription '%s->%s' is a list\n", + ast_sorcery_object_get_id(endpoint), resource); if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) { return 500; } @@ -1033,8 +1064,8 @@ static void remove_subscription(struct sip_subscription_tree *obj) if (i == obj) { AST_RWLIST_REMOVE_CURRENT(next); if (i->root) { - ast_debug(2, "Removing subscription to resource %s from list of subscriptions\n", - ast_sip_subscription_get_resource_name(i->root)); + ast_debug(2, "Removing subscription '%s->%s' from list of subscriptions\n", + ast_sorcery_object_get_id(i->endpoint), ast_sip_subscription_get_resource_name(i->root)); } break; } @@ -1045,7 +1076,8 @@ static void remove_subscription(struct sip_subscription_tree *obj) static void destroy_subscription(struct ast_sip_subscription *sub) { - ast_debug(3, "Destroying SIP subscription to resource %s\n", sub->resource); + ast_debug(3, "Destroying SIP subscription from '%s->%s'\n", + ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource); ast_free(sub->body_text); AST_VECTOR_FREE(&sub->children); @@ -1197,7 +1229,10 @@ static void subscription_tree_destructor(void *obj) { struct sip_subscription_tree *sub_tree = obj; - ast_debug(3, "Destroying subscription tree %p\n", sub_tree); + ast_debug(3, "Destroying subscription tree %p '%s->%s'\n", + sub_tree, + sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown", + sub_tree->root ? sub_tree->root->resource : "Unknown"); ao2_cleanup(sub_tree->endpoint); @@ -1213,7 +1248,8 @@ static void subscription_tree_destructor(void *obj) void ast_sip_subscription_destroy(struct ast_sip_subscription *sub) { - ast_debug(3, "Removing subscription %p reference to subscription tree %p\n", sub, sub->tree); + ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n", + sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree); ao2_cleanup(sub->tree); } @@ -1320,7 +1356,6 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag); pjsip_ua_register_dlg(pjsip_ua_instance(), dlg); dlg->local.cseq = persistence->cseq; - dlg->remote.cseq = persistence->cseq; } pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub); @@ -1345,6 +1380,12 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s return sub_tree; } +/*! Wrapper structure for initial_notify_task */ +struct initial_notify_data { + struct sip_subscription_tree *sub_tree; + int expires; +}; + static int initial_notify_task(void *obj); static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state); @@ -1433,9 +1474,12 @@ static int sub_persistence_recreate(void *obj) } pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header); } + expires_header->ivalue = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000); if (expires_header->ivalue <= 0) { /* The subscription expired since we started recreating the subscription. */ + ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n", + persistence->endpoint, persistence->tag); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); ao2_ref(endpoint, -1); return 0; @@ -1456,18 +1500,30 @@ static int sub_persistence_recreate(void *obj) ast_sorcery_delete(ast_sip_get_sorcery(), persistence); } } else { + struct initial_notify_data *ind = ast_malloc(sizeof(*ind)); + + if (!ind) { + pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); + goto error; + } + + ind->sub_tree = ao2_bump(sub_tree); + ind->expires = expires_header->ivalue; + sub_tree->persistence = ao2_bump(persistence); - subscription_persistence_update(sub_tree, rdata); - if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, - ao2_bump(sub_tree))) { + subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_RECREATED); + if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) { /* Could not send initial subscribe NOTIFY */ pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); ao2_ref(sub_tree, -1); + ast_free(ind); } } } else { ast_sorcery_delete(ast_sip_get_sorcery(), persistence); } + +error: resource_tree_destroy(&tree); ao2_ref(endpoint, -1); @@ -1485,6 +1541,8 @@ static int subscription_persistence_recreate(void *obj, void *arg, int flags) /* If this subscription has already expired remove it */ if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) { + ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n", + persistence->endpoint, persistence->tag); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); return 0; } @@ -1814,7 +1872,7 @@ static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, res = internal_pjsip_evsub_send_request(sub_tree, tdata); - subscription_persistence_update(sub_tree, NULL); + subscription_persistence_update(sub_tree, NULL, SUBSCRIPTION_PERSISTENCE_SEND_REQUEST); ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET", "StateText: %s\r\n" @@ -2713,21 +2771,45 @@ static int generate_initial_notify(struct ast_sip_subscription *sub) return res; } +static int pubsub_on_refresh_timeout(void *userdata); + static int initial_notify_task(void * obj) { - struct sip_subscription_tree *sub_tree; + struct initial_notify_data *ind = obj; - sub_tree = obj; - if (generate_initial_notify(sub_tree->root)) { - pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); + if (generate_initial_notify(ind->sub_tree->root)) { + pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE); } else { - send_notify(sub_tree, 1); + send_notify(ind->sub_tree, 1); ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED", "Resource: %s", - sub_tree->root->resource); + ind->sub_tree->root->resource); + } + + if (ind->expires > -1) { + char *name = ast_alloca(strlen("->/ ") + + strlen(ind->sub_tree->persistence->endpoint) + + strlen(ind->sub_tree->root->resource) + + strlen(ind->sub_tree->root->handler->event_name) + + ind->sub_tree->dlg->call_id->id.slen + 1); + + sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint, + ind->sub_tree->root->resource, ind->sub_tree->root->handler->event_name, + (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr); + + ast_debug(3, "Scheduling timer: %s\n", name); + ind->sub_tree->expiration_task = ast_sip_schedule_task(ind->sub_tree->serializer, + ind->expires * 1000, pubsub_on_refresh_timeout, name, + ind->sub_tree, AST_SIP_SCHED_TASK_FIXED | AST_SIP_SCHED_TASK_DATA_AO2); + if (!ind->sub_tree->expiration_task) { + ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n", + ind->expires, name); + } } - ao2_ref(sub_tree, -1); + ao2_ref(ind->sub_tree, -1); + ast_free(ind); + return 0; } @@ -2820,12 +2902,25 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata) pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); } } else { + struct initial_notify_data *ind = ast_malloc(sizeof(*ind)); + + if (!ind) { + pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); + resource_tree_destroy(&tree); + return PJ_TRUE; + } + + ind->sub_tree = ao2_bump(sub_tree); + /* Since this is a normal subscribe, pjproject takes care of the timer */ + ind->expires = -1; + sub_tree->persistence = subscription_persistence_create(sub_tree); - subscription_persistence_update(sub_tree, rdata); + subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_CREATED); sip_subscription_accept(sub_tree, rdata, resp); - if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ao2_bump(sub_tree))) { + if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) { pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); ao2_ref(sub_tree, -1); + ast_free(ind); } } @@ -3360,7 +3455,7 @@ static void set_state_terminated(struct ast_sip_subscription *sub) * send_notify ultimately calls pjsip_evsub_send_request * pjsip_evsub_send_request calls evsub's set_state * set_state calls pubsub_evsub_set_state - * pubsub_evsub_set_state checks state == TERMINATE_IN_PROGRESS + * pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS * removes the subscriptions * cleans up references to evsub * sets state = TERMINATED @@ -3378,6 +3473,15 @@ static void set_state_terminated(struct ast_sip_subscription *sub) * serialized_pubsub_on_refresh_timeout starts * See (1) Above * + * * Transmission failure sending NOTIFY or error response from client + * pjproject transaction timer expires or non OK response + * pjproject locks dialog + * calls pubsub_on_evsub_state with event TSX_STATE + * pubsub_on_evsub_state checks event == TSX_STATE + * removes the subscriptions + * cleans up references to evsub + * sets state = TERMINATED + * pjproject unlocks dialog * * * ast_sip_subscription_notify is called * checks state == NORMAL @@ -3403,25 +3507,41 @@ static void set_state_terminated(struct ast_sip_subscription *sub) * * Although this function is called for every state change, we only care * about the TERMINATED state, and only when we're actually processing the final - * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS). In this case, we do all - * the subscription tree cleanup tasks and decrement the evsub reference. + * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS) OR when a transmission failure + * occurs (PJSIP_EVENT_TSX_STATE). In this case, we do all the subscription tree + * cleanup tasks and decrement the evsub reference. */ static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event) { - struct sip_subscription_tree *sub_tree; + struct sip_subscription_tree *sub_tree = + pjsip_evsub_get_mod_data(evsub, pubsub_module.id); - ast_debug(3, "on_evsub_state called with state %s\n", pjsip_evsub_get_state_name(evsub)); + ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub, + pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree, + (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN")); - if (pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) { + if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) { return; } - sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); - if (!sub_tree || sub_tree->state != SIP_SUB_TREE_TERMINATE_IN_PROGRESS) { - ast_debug(1, "Possible terminate race prevented %p\n", sub_tree); + /* It's easier to write this as what we WANT to process, then negate it. */ + if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS + || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL) + )) { + ast_debug(3, "Do nothing.\n"); return; } + if (sub_tree->expiration_task) { + char task_name[256]; + + ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name)); + ast_debug(3, "Cancelling timer: %s\n", task_name); + ast_sip_sched_task_cancel(sub_tree->expiration_task); + ao2_cleanup(sub_tree->expiration_task); + sub_tree->expiration_task = NULL; + } + remove_subscription(sub_tree); pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL); @@ -3443,16 +3563,17 @@ static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event) ao2_ref(sub_tree, -1); } -static int serialized_pubsub_on_refresh_timeout(void *userdata) +static int pubsub_on_refresh_timeout(void *userdata) { struct sip_subscription_tree *sub_tree = userdata; pjsip_dialog *dlg = sub_tree->dlg; + ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree, + (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN")); + pjsip_dlg_inc_lock(dlg); if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) { - ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree->evsub, sub_tree->state); pjsip_dlg_dec_lock(dlg); - ao2_cleanup(sub_tree); return 0; } @@ -3468,7 +3589,20 @@ static int serialized_pubsub_on_refresh_timeout(void *userdata) "Resource: %s", sub_tree->root->resource); pjsip_dlg_dec_lock(dlg); + + return 0; +} + +static int serialized_pubsub_on_refresh_timeout(void *userdata) +{ + struct sip_subscription_tree *sub_tree = userdata; + + ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree, + (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN")); + + pubsub_on_refresh_timeout(userdata); ao2_cleanup(sub_tree); + return 0; } @@ -3487,11 +3621,23 @@ static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata, struct sip_subscription_tree *sub_tree; sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); + ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree, + (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN")); + if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) { - ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree, sub_tree ? sub_tree->state : -1 ); return; } + if (sub_tree->expiration_task) { + char task_name[256]; + + ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name)); + ast_debug(3, "Cancelling timer: %s\n", task_name); + ast_sip_sched_task_cancel(sub_tree->expiration_task); + ao2_cleanup(sub_tree->expiration_task); + sub_tree->expiration_task = NULL; + } + /* PJSIP will set the evsub's state to terminated before calling into this function * if the Expires value of the incoming SUBSCRIBE is 0. */ @@ -3500,6 +3646,8 @@ static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata, sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING; } + subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_REFRESHED); + if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_refresh_timeout, ao2_bump(sub_tree))) { /* If we can't push the NOTIFY refreshing task...we'll just go with it. */ ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n"); @@ -3577,7 +3725,6 @@ static void pubsub_on_server_timeout(pjsip_evsub *evsub) sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id); if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) { - ast_debug(1, "Possible terminate race prevented %p %d\n", sub_tree, sub_tree ? sub_tree->state : -1 ); return; } diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 8294d8ef933..d5c85317de6 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -62,6 +62,7 @@ AC_DEFUN([_PJPROJECT_CONFIGURE], AC_DEFINE([HAVE_PJSIP_EVSUB_GRP_LOCK], 1, [Define if your system has PJSIP_EVSUB_GRP_LOCK]) AC_DEFINE([HAVE_PJSIP_INV_SESSION_REF], 1, [Define if your system has PJSIP_INV_SESSION_REF]) AC_DEFINE([HAVE_PJSIP_AUTH_CLT_DEINIT], 1, [Define if your system has pjsip_auth_clt_deinit declared.]) + AC_DEFINE([HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT], 1, [Define if your system has pjsip_evsub_set_uas_timeout declared.]) AC_SUBST([PJPROJECT_BUNDLED]) AC_SUBST([PJPROJECT_DIR]) diff --git a/third-party/pjproject/patches/0010-evsub-Add-pjsip_evsub_set_uas_timeout.patch b/third-party/pjproject/patches/0010-evsub-Add-pjsip_evsub_set_uas_timeout.patch new file mode 100644 index 00000000000..a55aa001397 --- /dev/null +++ b/third-party/pjproject/patches/0010-evsub-Add-pjsip_evsub_set_uas_timeout.patch @@ -0,0 +1,84 @@ +From b7af9e6639f29feb4db6d0866c98e552b025ec96 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Mon, 6 Feb 2017 15:39:29 -0700 +Subject: [PATCH] evsub: Add pjsip_evsub_set_uas_timeout. + +A UAS which needs to recreate incoming subscriptions from a persistent +store can call pjsip_dlg_create_uas_and_inc_lock and +pjsip_evsub_create_uas as long as they've persisted the +correct data but since the timer is triggered by an incoming subscribe, +it's never set and the subscription never expires. + +* Add pjsip_evsub_set_uas_timeout which is just a wrapper around + evsub.c:set_timeout(sub, TIMER_TYPE_UAS_TIMEOUT, seconds) + +* Also, fixed copy-paste error in pjsip_sub_state_hdr_print when + printing retry-after parameter. +--- + pjsip/include/pjsip-simple/evsub.h | 14 ++++++++++++++ + pjsip/src/pjsip-simple/evsub.c | 10 ++++++++++ + pjsip/src/pjsip-simple/evsub_msg.c | 2 +- + 3 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/pjsip/include/pjsip-simple/evsub.h b/pjsip/include/pjsip-simple/evsub.h +index 82e0a7c..45e6411 100644 +--- a/pjsip/include/pjsip-simple/evsub.h ++++ b/pjsip/include/pjsip-simple/evsub.h +@@ -511,6 +511,20 @@ PJ_DEF(pj_status_t) pjsip_evsub_add_ref(pjsip_evsub *sub); + PJ_DEF(pj_status_t) pjsip_evsub_dec_ref(pjsip_evsub *sub); + + ++/** ++ * Sets, resets or cancels the UAS subscription timeout. ++ * ++ * If there is an existing timer, it is cancelled before any ++ * other action. ++ * ++ * A timeout of 0 is ignored except that any existing timer ++ * is cancelled. ++ * ++ * @param sub The server subscription instance. ++ * @param seconds The new timeout. ++ */ ++PJ_DEF(void) pjsip_evsub_set_uas_timeout(pjsip_evsub *sub, pj_int32_t seconds); ++ + + PJ_END_DECL + +diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c +index 3fe4b49..6918a8c 100644 +--- a/pjsip/src/pjsip-simple/evsub.c ++++ b/pjsip/src/pjsip-simple/evsub.c +@@ -530,6 +530,16 @@ static void set_timer( pjsip_evsub *sub, int timer_id, + + + /* ++ * Set event subscription UAS timout. ++ */ ++PJ_DEF(void) pjsip_evsub_set_uas_timeout(pjsip_evsub *sub, pj_int32_t seconds) ++{ ++ PJ_ASSERT_RETURN(sub != NULL, PJ_EINVAL); ++ set_timer(sub, TIMER_TYPE_UAS_TIMEOUT, seconds); ++} ++ ++ ++/* + * Destructor. + */ + static void evsub_on_destroy(void *obj) +diff --git a/pjsip/src/pjsip-simple/evsub_msg.c b/pjsip/src/pjsip-simple/evsub_msg.c +index b44a715..b37db1c 100644 +--- a/pjsip/src/pjsip-simple/evsub_msg.c ++++ b/pjsip/src/pjsip-simple/evsub_msg.c +@@ -179,7 +179,7 @@ static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, + } + if (hdr->retry_after >= 0) { + pj_memcpy(p, ";retry-after=", 13); +- p += 9; ++ p += 13; + printed = pj_utoa(hdr->retry_after, p); + p += printed; + } +-- +2.9.3 + From 135bea931ce9188caa18210bce677ffd2a72adbc Mon Sep 17 00:00:00 2001 From: Igor Goncharovsky Date: Thu, 16 Feb 2017 08:09:35 +0300 Subject: [PATCH 1043/1578] chan_unistim: fix char type to have consistent behavior on ARM There is difference exists in behaviour of char type on x86 and ARM. On x86 by default char variable type means signed char, but in ARM unsigned char used. This make binary calculations and negative values works wrong on ARM. This patch change type of char variables used for store negative values and binary calculations to signed char. ASTERISK-26714 Change-Id: Id78716dee9568a58419d4ef63c038affc3dfc7ab --- channels/chan_unistim.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index b8ccdbb2a5f..f82522111e2 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -161,6 +161,7 @@ enum autoprov_extn { #define LED_HEADPHONE_ON 0x011 #define LED_MUTE_OFF 0x018 #define LED_MUTE_ON 0x019 +#define LED_MUTE_BLINK 0x1A #define SIZE_HEADER 6 #define SIZE_MAC_ADDR 17 @@ -357,8 +358,8 @@ struct unistim_subchannel { int softkey; /*! Softkey assigned */ pthread_t ss_thread; /*! unistim_ss thread handle */ int alreadygone; - char ringvolume; - char ringstyle; + signed char ringvolume; + signed char ringstyle; int moh; /*!< Music on hold in progress */ AST_LIST_ENTRY(unistim_subchannel) list; }; @@ -413,13 +414,13 @@ static struct unistim_device { char maintext2[25]; /*!< when the phone is idle, display this string on line 2 */ char titledefault[13]; /*!< title (text before date/time) */ char datetimeformat; /*!< format used for displaying time/date */ - char contrast; /*!< contrast */ + signed char contrast; /*!< contrast */ char country[3]; /*!< country used for dial tone frequency */ struct ast_tone_zone *tz; /*!< Tone zone for res_indications (ring, busy, congestion) */ - char ringvolume; /*!< Ring volume */ - char ringstyle; /*!< Ring melody */ - char cwvolume; /*!< Ring volume on call waiting */ - char cwstyle; /*!< Ring melody on call waiting */ + signed char ringvolume; /*!< Ring volume */ + signed char ringstyle; /*!< Ring melody */ + signed char cwvolume; /*!< Ring volume on call waiting */ + signed char cwstyle; /*!< Ring melody on call waiting */ int interdigit_timer; /*!< Interdigit timer for dialing number by timeout */ int dtmfduration; /*!< DTMF playback duration */ time_t nextdial; /*!< Timer used for dial by timeout */ @@ -443,7 +444,7 @@ static struct unistim_device { int nat; /*!< Used by the obscure ast_rtp_setnat */ enum autoprov_extn extension; /*!< See ifdef EXTENSION for valid values */ char extension_number[11]; /*!< Extension number entered by the user */ - char to_delete; /*!< Used in reload */ + signed char to_delete; /*!< Used in reload */ struct ast_silence_generator *silence_generator; AST_LIST_HEAD(,unistim_subchannel) subs; /*!< pointer to our current connection, channel... */ AST_LIST_HEAD(,unistim_line) lines; @@ -1701,7 +1702,7 @@ send_select_output(struct unistimsession *pte, unsigned char output, unsigned ch } pte->device->output = output; } -static void send_ring(struct unistimsession *pte, char volume, char style) +static void send_ring(struct unistimsession *pte, signed char volume, signed char style) { BUFFSEND; if (unistimdebug) { @@ -4835,7 +4836,7 @@ static int unistim_call(struct ast_channel *ast, const char *dest, int timeout) int res = 0, i; struct unistim_subchannel *sub, *sub_real; struct unistimsession *session; - char ringstyle, ringvolume; + signed char ringstyle, ringvolume; session = channel_to_session(ast); if (!session) { @@ -5438,8 +5439,8 @@ static struct unistim_subchannel *find_subchannel_by_name(const char *dest) if ((*at < '0') || (*at > '7')) { /* ring style */ ast_log(LOG_WARNING, "Invalid ring selection (%s)", at); } else { - char ring_volume = -1; - char ring_style = *at - '0'; + signed char ring_volume = -1; + signed char ring_style = *at - '0'; at++; if ((*at >= '0') && (*at <= '3')) { /* ring volume */ ring_volume = *at - '0'; @@ -6483,7 +6484,7 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var int create = 1; int nbsoftkey, dateformat, timeformat, callhistory, sharpdial, linecnt; char linelabel[AST_MAX_EXTENSION]; - char ringvolume, ringstyle, cwvolume, cwstyle; + signed char ringvolume, ringstyle, cwvolume, cwstyle; /* First, we need to know if we already have this name in our list */ /* Get a lock for the device chained list */ From ac7a34c531a15c4dfb992cf5608e6b9d1e6d7c35 Mon Sep 17 00:00:00 2001 From: Joshua Elson Date: Wed, 15 Feb 2017 13:44:32 -0700 Subject: [PATCH 1044/1578] http: Ensure capath is defined on all http creations ASTERISK-26794 #close Change-Id: I9cbc3b6b6a8aab590f5ccde9c262a98e4d5253a1 --- main/http.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/main/http.c b/main/http.c index 5f57b1eb01c..0db6ee7b66f 100644 --- a/main/http.c +++ b/main/http.c @@ -2056,22 +2056,20 @@ static int __ast_http_load(int reload) http_tls_was_enabled = (reload && http_tls_cfg.enabled); http_tls_cfg.enabled = 0; - if (http_tls_cfg.certfile) { - ast_free(http_tls_cfg.certfile); - } + + ast_free(http_tls_cfg.certfile); http_tls_cfg.certfile = ast_strdup(AST_CERTFILE); - if (http_tls_cfg.pvtfile) { - ast_free(http_tls_cfg.pvtfile); - } + ast_free(http_tls_cfg.capath); + http_tls_cfg.capath = ast_strdup(""); + + ast_free(http_tls_cfg.pvtfile); http_tls_cfg.pvtfile = ast_strdup(""); /* Apply modern intermediate settings according to the Mozilla OpSec team as of July 30th, 2015 but disable TLSv1 */ ast_set_flag(&http_tls_cfg.flags, AST_SSL_DISABLE_TLSV1 | AST_SSL_SERVER_CIPHER_ORDER); - if (http_tls_cfg.cipher) { - ast_free(http_tls_cfg.cipher); - } + ast_free(http_tls_cfg.cipher); http_tls_cfg.cipher = ast_strdup("ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"); AST_RWLIST_WRLOCK(&uri_redirects); @@ -2285,6 +2283,7 @@ static void http_shutdown(void) ast_tcptls_server_stop(&https_desc); } ast_free(http_tls_cfg.certfile); + ast_free(http_tls_cfg.capath); ast_free(http_tls_cfg.pvtfile); ast_free(http_tls_cfg.cipher); From 30aaeec5a1ec994338cb138083af812fc479f205 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 16 Feb 2017 06:46:04 -0500 Subject: [PATCH 1045/1578] res_config_sqlite3: Properly create missing columns when necessary There were two specific issues resolved here: 1) The code that iterated over the required fields (via ast_realtime_require) was broken for the RQ_INTEGER1 field type. Iteration would stop when the first RQ_INTEGER1 (0) field was encountered. 2) sqlite3_changes() was used to try and count the number of rows returned by a SELECT statement. sqlite3_changes() only counts affected rows, so this was always returning the value from the most recent data modification statement. We now separate read-only queries from data modification queries and count rows appropriately in both cases. ASTERISK-23457 #close Reported by: Scott Griepentrog Change-Id: I91ed20494efc3fcfbc2a96ac7646999a49814884 --- res/res_config_sqlite3.c | 181 ++++++++++++++++++++++++++++++++------- 1 file changed, 152 insertions(+), 29 deletions(-) diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index b5c70ec2da4..86af51cae2a 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -113,7 +113,13 @@ AST_THREADSTORAGE(escape_table_buf); AST_THREADSTORAGE(escape_column_buf); AST_THREADSTORAGE(escape_value_buf); -static int realtime_sqlite3_execute_handle(struct realtime_sqlite3_db *db, const char *sql, int (*callback)(void*, int, char **, char **), void *arg, int sync); +typedef int (*callback_t)(void*, int, char **, char **); + +static int realtime_sqlite3_exec_query_with_handle(struct realtime_sqlite3_db *, const char *, callback_t, void *); +static int realtime_sqlite3_exec_query(const char *, const char *, callback_t, void *); +static int realtime_sqlite3_exec_update_with_handle(struct realtime_sqlite3_db *, const char *); +static int realtime_sqlite3_exec_update(const char *, const char *); + void db_start_batch(struct realtime_sqlite3_db *db); void db_stop_batch(struct realtime_sqlite3_db *db); @@ -301,20 +307,20 @@ static void *db_sync_thread(void *data) { struct realtime_sqlite3_db *db = data; ao2_lock(db); - realtime_sqlite3_execute_handle(db, "BEGIN TRANSACTION", NULL, NULL, 0); + realtime_sqlite3_exec_query_with_handle(db, "BEGIN TRANSACTION", NULL, NULL); for (;;) { if (!db->wakeup) { ast_cond_wait(&db->cond, ao2_object_get_lockaddr(db)); } db->wakeup = 0; - if (realtime_sqlite3_execute_handle(db, "COMMIT", NULL, NULL, 0) < 0) { - realtime_sqlite3_execute_handle(db, "ROLLBACK", NULL, NULL, 0); + if (realtime_sqlite3_exec_query_with_handle(db, "COMMIT", NULL, NULL) < 0) { + realtime_sqlite3_exec_query_with_handle(db, "ROLLBACK", NULL, NULL); } if (db->exiting) { ao2_unlock(db); break; } - realtime_sqlite3_execute_handle(db, "BEGIN TRANSACTION", NULL, NULL, 0); + realtime_sqlite3_exec_query_with_handle(db, "BEGIN TRANSACTION", NULL, NULL); ao2_unlock(db); usleep(1000 * db->batch); ao2_lock(db); @@ -525,18 +531,125 @@ struct cfg_entry_args { const char *who_asked; }; -/*! Exeute an SQL statement given the database object +/*! + * Structure passed to row counting SQLite callback. + */ +struct row_counter_args { + callback_t wrapped_callback; + void *wrapped_arg; + int row_count; +}; + +/*! + * \internal + * \brief SQLite3 callback that counts rows of a result set. + * + * \details + * This is used to decorate existing callbacks so that we can count the number + * of rows returned from a SELECT statement and still process each row + * independently. + * + * \param data user data pointer passed in via sqlite3_exec() + * \param num_columns number of columns in the result + * \param values array of pointers to column values + * \param columns array of pointers of to column names + * + * \return the return value of the wrapped callback, or 0 if no wrapped callback + * is provided. + */ +static int row_counter_wrapper(void *arg, int num_columns, char **values, char **columns) +{ + struct row_counter_args *wrapped = arg; + wrapped->row_count++; + if (wrapped->wrapped_callback) { + return wrapped->wrapped_callback(wrapped->wrapped_arg, num_columns, values, columns); + } + return 0; +} + +/*! + * \internal + * \brief Execute a SQL SELECT statement using a database handle + * + * \param db the database handle to use for the query + * \param sql the SQL statement to execute + * \param callback a user defined callback that will be called for each row of + * the result set + * \param arg data to be passed to the user defined callback + * + * \return if successful, the number of rows returned from the provided SELECT + * statement. -1 on failure. + */ +static int realtime_sqlite3_exec_query_with_handle(struct realtime_sqlite3_db *db, const char *sql, callback_t callback, void *arg) +{ + int res = 0; + char *errmsg; + struct row_counter_args wrapper = { + .wrapped_callback = callback, + .wrapped_arg = arg, + .row_count = 0, + }; + + ao2_lock(db); + if (sqlite3_exec(db->handle, sql, row_counter_wrapper, &wrapper, &errmsg) != SQLITE_OK) { + ast_log(LOG_WARNING, "Could not execute '%s': %s\n", sql, errmsg); + sqlite3_free(errmsg); + res = -1; + } + ao2_unlock(db); + + return res == 0 ? wrapper.row_count : res; +} + +/*! + * \internal + * \brief Execute a SQL SELECT statement on the specified database + * + * \param database the name of the database to query + * \param sql the SQL statement to execute + * \param callback a user defined callback that will be called for each row of + * the result set + * \param arg data to be passed to the user defined callback + * + * \return if successful, the number of rows returned from the provided SELECT + * statement. -1 on failure. + */ +static int realtime_sqlite3_exec_query(const char *database, const char *sql, callback_t callback, void *arg) +{ + struct realtime_sqlite3_db *db; + int res; + + if (!(db = find_database(database))) { + ast_log(LOG_WARNING, "Could not find database: %s\n", database); + return -1; + } + + res = realtime_sqlite3_exec_query_with_handle(db, sql, callback, arg); + ao2_ref(db, -1); + + return res; +} + +/*! + * \internal + * \brief Execute a SQL INSERT/UPDATE/DELETE statement using a database handle * - * \retval -1 ERROR - * \retval > -1 Number of rows changed + * \note A database sync operation is always performed after a statement + * is executed. + * + * \param db the database handle to use for the query + * \param sql the SQL statement to execute + * + * \return if successful, the number of rows modified by the provided SQL + * statement. -1 on failure. */ -static int realtime_sqlite3_execute_handle(struct realtime_sqlite3_db *db, const char *sql, int (*callback)(void*, int, char **, char **), void *arg, int sync) +static int realtime_sqlite3_exec_update_with_handle(struct realtime_sqlite3_db *db, const char *sql) { int res = 0; char *errmsg; ao2_lock(db); - if (sqlite3_exec(db->handle, sql, callback, arg, &errmsg) != SQLITE_OK) { + if (sqlite3_exec(db->handle, sql, NULL, NULL, &errmsg) != SQLITE_OK) { ast_log(LOG_WARNING, "Could not execute '%s': %s\n", sql, errmsg); sqlite3_free(errmsg); res = -1; @@ -545,19 +658,25 @@ static int realtime_sqlite3_execute_handle(struct realtime_sqlite3_db *db, const } ao2_unlock(db); - if (sync) { - db_sync(db); - } + db_sync(db); return res; } -/*! Exeute an SQL statement give the database name +/*! + * \internal + * \brief Execute a SQL INSERT/UPDATE/DELETE statement using a database handle + * + * \note A database sync operation is always performed after a statement + * is executed. + * + * \param database the name of the database to query + * \param sql the SQL statement to execute * - * \retval -1 ERROR - * \retval > -1 Number of rows changed + * \return if successful, the number of rows modified by the provided SQL + * statement. -1 on failure. */ -static int realtime_sqlite3_execute(const char *database, const char *sql, int (*callback)(void*, int, char **, char **), void *arg, int sync) +static int realtime_sqlite3_exec_update(const char *database, const char *sql) { struct realtime_sqlite3_db *db; int res; @@ -567,7 +686,7 @@ static int realtime_sqlite3_execute(const char *database, const char *sql, int ( return -1; } - res = realtime_sqlite3_execute_handle(db, sql, callback, arg, sync); + res = realtime_sqlite3_exec_update_with_handle(db, sql); ao2_ref(db, -1); return res; @@ -651,7 +770,7 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char args.flags = flags; args.who_asked = who_asked; - realtime_sqlite3_execute(database, sql, static_realtime_cb, &args, 0); + realtime_sqlite3_exec_query(database, sql, static_realtime_cb, &args); sqlite3_free(sql); @@ -689,7 +808,7 @@ static int realtime_sqlite3_helper(const char *database, const char *table, cons ast_str_append(&sql, 0, "%s", " LIMIT 1"); } - if (realtime_sqlite3_execute(database, ast_str_buffer(sql), is_multi ? append_row_to_cfg : row_to_varlist, arg, 0) < 0) { + if (realtime_sqlite3_exec_query(database, ast_str_buffer(sql), is_multi ? append_row_to_cfg : row_to_varlist, arg) < 0) { ast_free(sql); return -1; } @@ -760,7 +879,7 @@ static int realtime_sqlite3_update(const char *database, const char *table, cons ast_str_append(&sql, 0, " WHERE %s %s", sqlite3_escape_column_op(keyfield), sqlite3_escape_value(entity)); - res = realtime_sqlite3_execute(database, ast_str_buffer(sql), NULL, NULL, 1); + res = realtime_sqlite3_exec_update(database, ast_str_buffer(sql)); ast_free(sql); return res; @@ -811,7 +930,7 @@ static int realtime_sqlite3_update2(const char *database, const char *table, con ast_str_append(&sql, 0, "%s", ast_str_buffer(where_clause)); - res = realtime_sqlite3_execute(database, ast_str_buffer(sql), NULL, NULL, 1); + res = realtime_sqlite3_exec_update(database, ast_str_buffer(sql)); ast_free(sql); ast_free(where_clause); @@ -855,7 +974,7 @@ static int realtime_sqlite3_store(const char *database, const char *table, const ast_str_append(&sql, 0, "%s)", ast_str_buffer(values)); - res = realtime_sqlite3_execute(database, ast_str_buffer(sql), NULL, NULL, 1); + res = realtime_sqlite3_exec_update(database, ast_str_buffer(sql)); ast_free(sql); ast_free(values); @@ -891,7 +1010,7 @@ static int realtime_sqlite3_destroy(const char *database, const char *table, con } } - res = realtime_sqlite3_execute(database, ast_str_buffer(sql), NULL, NULL, 1); + res = realtime_sqlite3_exec_update(database, ast_str_buffer(sql)); ast_free(sql); @@ -944,7 +1063,9 @@ static int handle_missing_table(struct realtime_sqlite3_db *db, const char *tabl return -1; } - while ((column = va_arg(ap, typeof(column))) && (type = va_arg(ap, typeof(type))) && (sz = va_arg(ap, typeof(sz)))) { + while ((column = va_arg(ap, typeof(column)))) { + type = va_arg(ap, typeof(type)); + sz = va_arg(ap, typeof(sz)); if (first) { ast_str_set(&sql, 0, "CREATE TABLE IF NOT EXISTS %s (%s %s", sqlite3_escape_table(table), sqlite3_escape_column(column), get_sqlite_column_type(type)); @@ -956,7 +1077,7 @@ static int handle_missing_table(struct realtime_sqlite3_db *db, const char *tabl ast_str_append(&sql, 0, ")"); - res = realtime_sqlite3_execute_handle(db, ast_str_buffer(sql), NULL, NULL, 1) < 0 ? -1 : 0; + res = realtime_sqlite3_exec_update_with_handle(db, ast_str_buffer(sql)) < 0 ? -1 : 0; ast_free(sql); return res; @@ -981,7 +1102,7 @@ static int handle_missing_column(struct realtime_sqlite3_db *db, const char *tab return -1; } - if (!(res = (realtime_sqlite3_execute_handle(db, sql, NULL, NULL, 1) < 0 ? -1 : 0))) { + if (!(res = (realtime_sqlite3_exec_update_with_handle(db, sql) < 0 ? -1 : 0))) { ast_log(LOG_NOTICE, "Creating column '%s' type %s for table %s\n", column, sqltype, table); } @@ -1059,7 +1180,7 @@ static int realtime_sqlite3_require(const char *database, const char *table, va_ return -1; } - if ((res = realtime_sqlite3_execute_handle(db, sql, add_column_name, columns, 0)) < 0) { + if ((res = realtime_sqlite3_exec_query_with_handle(db, sql, add_column_name, columns)) < 0) { unref_db(&db); ao2_ref(columns, -1); sqlite3_free(sql); @@ -1075,8 +1196,10 @@ static int realtime_sqlite3_require(const char *database, const char *table, va_ sqlite3_free(sql); - while ((column = va_arg(ap, typeof(column))) && (type = va_arg(ap, typeof(type))) && (sz = va_arg(ap, typeof(sz)))) { + while ((column = va_arg(ap, typeof(column)))) { char *found; + type = va_arg(ap, typeof(type)); + sz = va_arg(ap, typeof(sz)); if (!(found = ao2_find(columns, column, OBJ_POINTER | OBJ_UNLINK))) { if (handle_missing_column(db, table, column, type, sz)) { unref_db(&db); From f8f513d363fd10148976c592cbc8be860cda28ab Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 16 Feb 2017 07:28:33 -0700 Subject: [PATCH 1046/1578] stream: Rename creates/destroys to allocs/frees To be consistent with sdp implementation. Change-Id: I714e300939b4188f58ca66ce9d1e84b287009500 --- include/asterisk/stream.h | 8 ++-- main/channel.c | 2 +- main/channel_internal_api.c | 6 +-- main/stream.c | 32 ++++++------- tests/test_stream.c | 96 ++++++++++++++++++------------------- 5 files changed, 72 insertions(+), 72 deletions(-) diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 9fb46601352..edb00b9ebe5 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -84,7 +84,7 @@ enum ast_stream_state { * * \since 15 */ -struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type); +struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type); /*! * \brief Destroy a media stream representation @@ -93,7 +93,7 @@ struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type) * * \since 15 */ -void ast_stream_destroy(struct ast_stream *stream); +void ast_stream_free(struct ast_stream *stream); /*! * \brief Create a deep clone of an existing stream @@ -209,7 +209,7 @@ int ast_stream_get_position(const struct ast_stream *stream); * * \since 15 */ -struct ast_stream_topology *ast_stream_topology_create(void); +struct ast_stream_topology *ast_stream_topology_alloc(void); /*! * \brief Create a deep clone of an existing stream topology @@ -233,7 +233,7 @@ struct ast_stream_topology *ast_stream_topology_clone( * * \since 15 */ -void ast_stream_topology_destroy(struct ast_stream_topology *topology); +void ast_stream_topology_free(struct ast_stream_topology *topology); /*! * \brief Append a stream to the topology diff --git a/main/channel.c b/main/channel.c index fa92508ace3..5e81783581a 100644 --- a/main/channel.c +++ b/main/channel.c @@ -888,7 +888,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char return ast_channel_unref(tmp); } - if (!(topology = ast_stream_topology_create())) { + if (!(topology = ast_stream_topology_alloc())) { return ast_channel_unref(tmp); } ast_channel_internal_set_stream_topology(tmp, topology); diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 235b99604b0..1934eb9a4a6 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -848,7 +848,7 @@ static void channel_set_default_streams(struct ast_channel *chan) void ast_channel_internal_set_stream_topology(struct ast_channel *chan, struct ast_stream_topology *topology) { - ast_stream_topology_destroy(chan->stream_topology); + ast_stream_topology_free(chan->stream_topology); chan->stream_topology = topology; channel_set_default_streams(chan); } @@ -871,7 +871,7 @@ void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_stream_topology *new_topology; if (!value) { - new_topology = ast_stream_topology_create(); + new_topology = ast_stream_topology_alloc(); } else { new_topology = ast_stream_topology_create_from_format_cap(value); } @@ -1804,7 +1804,7 @@ struct ast_stream_topology *ast_channel_set_stream_topology(struct ast_channel * * it even if its empty. */ if (!topology) { - new_topology = ast_stream_topology_create(); + new_topology = ast_stream_topology_alloc(); } else { new_topology = topology; } diff --git a/main/stream.c b/main/stream.c index 5112c959360..aacd33f1734 100644 --- a/main/stream.c +++ b/main/stream.c @@ -69,7 +69,7 @@ struct ast_stream_topology { AST_VECTOR(, struct ast_stream *) streams; }; -struct ast_stream *ast_stream_create(const char *name, enum ast_media_type type) +struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type) { struct ast_stream *stream; @@ -108,7 +108,7 @@ struct ast_stream *ast_stream_clone(const struct ast_stream *stream) return new_stream; } -void ast_stream_destroy(struct ast_stream *stream) +void ast_stream_free(struct ast_stream *stream) { if (!stream) { return; @@ -176,7 +176,7 @@ int ast_stream_get_position(const struct ast_stream *stream) } #define TOPOLOGY_INITIAL_STREAM_COUNT 2 -struct ast_stream_topology *ast_stream_topology_create(void) +struct ast_stream_topology *ast_stream_topology_alloc(void) { struct ast_stream_topology *topology; @@ -201,7 +201,7 @@ struct ast_stream_topology *ast_stream_topology_clone( ast_assert(topology != NULL); - new_topology = ast_stream_topology_create(); + new_topology = ast_stream_topology_alloc(); if (!new_topology) { return NULL; } @@ -211,8 +211,8 @@ struct ast_stream_topology *ast_stream_topology_clone( ast_stream_clone(AST_VECTOR_GET(&topology->streams, i)); if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) { - ast_stream_destroy(stream); - ast_stream_topology_destroy(new_topology); + ast_stream_free(stream); + ast_stream_topology_free(new_topology); return NULL; } } @@ -220,13 +220,13 @@ struct ast_stream_topology *ast_stream_topology_clone( return new_topology; } -void ast_stream_topology_destroy(struct ast_stream_topology *topology) +void ast_stream_topology_free(struct ast_stream_topology *topology) { if (!topology) { return; } - AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_destroy); + AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free); AST_VECTOR_FREE(&topology->streams); ast_free(topology); } @@ -272,7 +272,7 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, if (position < AST_VECTOR_SIZE(&topology->streams)) { existing_stream = AST_VECTOR_GET(&topology->streams, position); - ast_stream_destroy(existing_stream); + ast_stream_free(existing_stream); } stream->position = position; @@ -293,7 +293,7 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( ast_assert(cap != NULL); - topology = ast_stream_topology_create(); + topology = ast_stream_topology_alloc(); if (!topology) { return NULL; } @@ -308,29 +308,29 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!new_cap) { - ast_stream_topology_destroy(topology); + ast_stream_topology_free(topology); return NULL; } ast_format_cap_set_framing(new_cap, ast_format_cap_get_framing(cap)); if (ast_format_cap_append_from_cap(new_cap, cap, type)) { ao2_cleanup(new_cap); - ast_stream_topology_destroy(topology); + ast_stream_topology_free(topology); return NULL; } - stream = ast_stream_create(ast_codec_media_type2str(type), type); + stream = ast_stream_alloc(ast_codec_media_type2str(type), type); if (!stream) { ao2_cleanup(new_cap); - ast_stream_topology_destroy(topology); + ast_stream_topology_free(topology); return NULL; } /* We're transferring the initial ref so no bump needed */ stream->formats = new_cap; stream->state = AST_STREAM_STATE_SENDRECV; if (ast_stream_topology_append_stream(topology, stream) == -1) { - ast_stream_destroy(stream); - ast_stream_topology_destroy(topology); + ast_stream_free(stream); + ast_stream_topology_free(topology); return NULL; } } diff --git a/tests/test_stream.c b/tests/test_stream.c index 10bf63aa75a..5134cfb507c 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -41,7 +41,7 @@ AST_TEST_DEFINE(stream_create) { - RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free); switch (cmd) { case TEST_INIT: @@ -55,7 +55,7 @@ AST_TEST_DEFINE(stream_create) break; } - stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO); if (!stream) { ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); return AST_TEST_FAIL; @@ -81,7 +81,7 @@ AST_TEST_DEFINE(stream_create) AST_TEST_DEFINE(stream_create_no_name) { - RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free); switch (cmd) { case TEST_INIT: @@ -95,7 +95,7 @@ AST_TEST_DEFINE(stream_create_no_name) break; } - stream = ast_stream_create(NULL, AST_MEDIA_TYPE_AUDIO); + stream = ast_stream_alloc(NULL, AST_MEDIA_TYPE_AUDIO); if (!stream) { ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); return AST_TEST_FAIL; @@ -106,7 +106,7 @@ AST_TEST_DEFINE(stream_create_no_name) AST_TEST_DEFINE(stream_set_type) { - RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free); switch (cmd) { case TEST_INIT: @@ -120,7 +120,7 @@ AST_TEST_DEFINE(stream_set_type) break; } - stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO); if (!stream) { ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); return AST_TEST_FAIL; @@ -143,7 +143,7 @@ AST_TEST_DEFINE(stream_set_type) AST_TEST_DEFINE(stream_set_formats) { - RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free); RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); switch (cmd) { @@ -164,7 +164,7 @@ AST_TEST_DEFINE(stream_set_formats) return AST_TEST_FAIL; } - stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO); if (!stream) { ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); return AST_TEST_FAIL; @@ -189,7 +189,7 @@ AST_TEST_DEFINE(stream_set_formats) AST_TEST_DEFINE(stream_set_state) { - RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_destroy); + RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free); switch (cmd) { case TEST_INIT: @@ -203,7 +203,7 @@ AST_TEST_DEFINE(stream_set_state) break; } - stream = ast_stream_create("test", AST_MEDIA_TYPE_AUDIO); + stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO); if (!stream) { ast_test_status_update(test, "Failed to create media stream given proper arguments\n"); return AST_TEST_FAIL; @@ -226,7 +226,7 @@ AST_TEST_DEFINE(stream_set_state) AST_TEST_DEFINE(stream_topology_create) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); switch (cmd) { case TEST_INIT: @@ -240,7 +240,7 @@ AST_TEST_DEFINE(stream_topology_create) break; } - topology = ast_stream_topology_create(); + topology = ast_stream_topology_alloc(); if (!topology) { ast_test_status_update(test, "Failed to create media stream topology\n"); return AST_TEST_FAIL; @@ -251,8 +251,8 @@ AST_TEST_DEFINE(stream_topology_create) AST_TEST_DEFINE(stream_topology_clone) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); - RAII_VAR(struct ast_stream_topology *, cloned, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + RAII_VAR(struct ast_stream_topology *, cloned, NULL, ast_stream_topology_free); struct ast_stream *audio_stream, *video_stream; switch (cmd) { @@ -267,13 +267,13 @@ AST_TEST_DEFINE(stream_topology_clone) break; } - topology = ast_stream_topology_create(); + topology = ast_stream_topology_alloc(); if (!topology) { ast_test_status_update(test, "Failed to create media stream topology\n"); return AST_TEST_FAIL; } - audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); if (!audio_stream) { ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -281,11 +281,11 @@ AST_TEST_DEFINE(stream_topology_clone) if (ast_stream_topology_append_stream(topology, audio_stream) == -1) { ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n"); - ast_stream_destroy(audio_stream); + ast_stream_free(audio_stream); return AST_TEST_FAIL; } - video_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); if (!video_stream) { ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -293,7 +293,7 @@ AST_TEST_DEFINE(stream_topology_clone) if (ast_stream_topology_append_stream(topology, video_stream) == -1) { ast_test_status_update(test, "Failed to append valid video stream to stream topology\n"); - ast_stream_destroy(video_stream); + ast_stream_free(video_stream); return AST_TEST_FAIL; } @@ -323,7 +323,7 @@ AST_TEST_DEFINE(stream_topology_clone) AST_TEST_DEFINE(stream_topology_append_stream) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); struct ast_stream *audio_stream, *video_stream; int position; @@ -339,13 +339,13 @@ AST_TEST_DEFINE(stream_topology_append_stream) break; } - topology = ast_stream_topology_create(); + topology = ast_stream_topology_alloc(); if (!topology) { ast_test_status_update(test, "Failed to create media stream topology\n"); return AST_TEST_FAIL; } - audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); if (!audio_stream) { ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -354,7 +354,7 @@ AST_TEST_DEFINE(stream_topology_append_stream) position = ast_stream_topology_append_stream(topology, audio_stream); if (position == -1) { ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n"); - ast_stream_destroy(audio_stream); + ast_stream_free(audio_stream); return AST_TEST_FAIL; } else if (position != 0) { ast_test_status_update(test, "Appended audio stream to stream topology but position is '%d' instead of 0\n", @@ -379,7 +379,7 @@ AST_TEST_DEFINE(stream_topology_append_stream) return AST_TEST_FAIL; } - video_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); if (!video_stream) { ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -388,7 +388,7 @@ AST_TEST_DEFINE(stream_topology_append_stream) position = ast_stream_topology_append_stream(topology, video_stream); if (position == -1) { ast_test_status_update(test, "Failed to append valid video stream to stream topology\n"); - ast_stream_destroy(video_stream); + ast_stream_free(video_stream); return AST_TEST_FAIL; } else if (position != 1) { ast_test_status_update(test, "Appended video stream to stream topology but position is '%d' instead of 1\n", @@ -418,7 +418,7 @@ AST_TEST_DEFINE(stream_topology_append_stream) AST_TEST_DEFINE(stream_topology_set_stream) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); struct ast_stream *audio_stream, *video_stream; switch (cmd) { @@ -433,13 +433,13 @@ AST_TEST_DEFINE(stream_topology_set_stream) break; } - topology = ast_stream_topology_create(); + topology = ast_stream_topology_alloc(); if (!topology) { ast_test_status_update(test, "Failed to create media stream topology\n"); return AST_TEST_FAIL; } - audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); if (!audio_stream) { ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -447,7 +447,7 @@ AST_TEST_DEFINE(stream_topology_set_stream) if (ast_stream_topology_set_stream(topology, 0, audio_stream)) { ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n"); - ast_stream_destroy(audio_stream); + ast_stream_free(audio_stream); return AST_TEST_FAIL; } @@ -468,7 +468,7 @@ AST_TEST_DEFINE(stream_topology_set_stream) return AST_TEST_FAIL; } - video_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); if (!video_stream) { ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -476,7 +476,7 @@ AST_TEST_DEFINE(stream_topology_set_stream) if (ast_stream_topology_set_stream(topology, 0, video_stream)) { ast_test_status_update(test, "Failed to set a video stream to a position where it is permitted\n"); - ast_stream_destroy(video_stream); + ast_stream_free(video_stream); return AST_TEST_FAIL; } @@ -497,7 +497,7 @@ AST_TEST_DEFINE(stream_topology_set_stream) return AST_TEST_FAIL; } - audio_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); if (!audio_stream) { ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -505,7 +505,7 @@ AST_TEST_DEFINE(stream_topology_set_stream) if (ast_stream_topology_set_stream(topology, 1, audio_stream)) { ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n"); - ast_stream_destroy(audio_stream); + ast_stream_free(audio_stream); return AST_TEST_FAIL; } @@ -531,7 +531,7 @@ AST_TEST_DEFINE(stream_topology_set_stream) AST_TEST_DEFINE(stream_topology_create_from_format_cap) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); switch (cmd) { @@ -580,7 +580,7 @@ AST_TEST_DEFINE(stream_topology_create_from_format_cap) return AST_TEST_FAIL; } - ast_stream_topology_destroy(topology); + ast_stream_topology_free(topology); topology = NULL; ast_format_cap_append(caps, ast_format_h264, 0); @@ -614,7 +614,7 @@ AST_TEST_DEFINE(stream_topology_create_from_format_cap) AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); struct ast_stream *first_stream, *second_stream, *third_stream, *fourth_stream; switch (cmd) { @@ -629,13 +629,13 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) break; } - topology = ast_stream_topology_create(); + topology = ast_stream_topology_alloc(); if (!topology) { ast_test_status_update(test, "Failed to create media stream topology\n"); return AST_TEST_FAIL; } - first_stream = ast_stream_create("audio", AST_MEDIA_TYPE_AUDIO); + first_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); if (!first_stream) { ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -643,11 +643,11 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) if (ast_stream_topology_append_stream(topology, first_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); - ast_stream_destroy(first_stream); + ast_stream_free(first_stream); return AST_TEST_FAIL; } - second_stream = ast_stream_create("audio2", AST_MEDIA_TYPE_AUDIO); + second_stream = ast_stream_alloc("audio2", AST_MEDIA_TYPE_AUDIO); if (!second_stream) { ast_test_status_update(test, "Failed to create a second audio stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -655,11 +655,11 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) if (ast_stream_topology_append_stream(topology, second_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); - ast_stream_destroy(second_stream); + ast_stream_free(second_stream); return AST_TEST_FAIL; } - third_stream = ast_stream_create("video", AST_MEDIA_TYPE_VIDEO); + third_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); if (!third_stream) { ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -667,11 +667,11 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) if (ast_stream_topology_append_stream(topology, third_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); - ast_stream_destroy(third_stream); + ast_stream_free(third_stream); return AST_TEST_FAIL; } - fourth_stream = ast_stream_create("video2", AST_MEDIA_TYPE_VIDEO); + fourth_stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO); if (!fourth_stream) { ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n"); return AST_TEST_FAIL; @@ -679,7 +679,7 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) if (ast_stream_topology_append_stream(topology, fourth_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); - ast_stream_destroy(fourth_stream); + ast_stream_free(fourth_stream); return AST_TEST_FAIL; } @@ -701,7 +701,7 @@ static const struct ast_channel_tech mock_channel_tech = { AST_TEST_DEFINE(stream_topology_create_from_channel_nativeformats) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); struct ast_channel *mock_channel; enum ast_test_result_state res = AST_TEST_FAIL; @@ -810,7 +810,7 @@ static const struct ast_channel_tech mock_stream_channel_tech = { AST_TEST_DEFINE(stream_topology_channel_set) { - RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_destroy); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); struct ast_channel *mock_channel; enum ast_test_result_state res = AST_TEST_PASS; @@ -826,7 +826,7 @@ AST_TEST_DEFINE(stream_topology_channel_set) break; } - topology = ast_stream_topology_create(); + topology = ast_stream_topology_alloc(); if (!topology) { ast_test_status_update(test, "Failed to create media stream topology\n"); return AST_TEST_FAIL; From e93f2a5142d1056dc223c37872c25b2a0d2c6778 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 16 Feb 2017 09:38:06 -0500 Subject: [PATCH 1047/1578] realtime: Fix LIKE escaping in SQL backends The realtime framework allows for components to look up values using a LIKE clause with similar syntax to SQL's. pbx_realtime uses this functionality to search for pattern matching extensions that start with an underscore (_). When passing an underscore to SQL's LIKE clause, it will be interpreted as a wildcard matching a single character and therefore needs to be escaped. It is (for better or for worse) the responsibility of the component that is querying realtime to escape it with a backslash before passing it in. Some RDBMs support escape characters by default, but the SQL92 standard explicitly says that there are no escape characters unless they are specified with an ESCAPE clause, e.g. SELECT * FROM table WHERE column LIKE '\_%' ESCAPE '\' This patch instructs 3 backends - res_config_mysql, res_config_pgsql, and res_config_sqlite3 - to use the ESCAPE clause where appropriate. Looking through documentation and source tarballs, I was able to determine that the ESCAPE clause is supported in: MySQL 5.0.15 (released 2005-10-22 - earliest version available from archives) PostgreSQL 7.1 (released 2001-04-13) SQLite 3.1.0 (released 2005-01-21) The versions of the relevant libraries that we depend on to access MySQL and PostgreSQL will not work on versions that old, and I've added an explicit check in res_config_sqlite3 to only use the ESCAPE clause when we have a sufficiently new version of SQLite3. res_config_odbc already handles the escape characters appropriately, so no changes were required there. ASTERISK-15858 #close Reported by: Humberto Figuera ASTERISK-26057 #close Reported by: Stepan Change-Id: I93117fbb874189ae819f4a31222df7c82cd20efa --- addons/res_config_mysql.c | 54 +++++++++++++++++++++++++++++---------- res/res_config_pgsql.c | 50 ++++++++++++++++++++++++++++-------- res/res_config_sqlite3.c | 38 +++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 24 deletions(-) diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c index bf38a4e69b6..f2ef949fc0c 100644 --- a/addons/res_config_mysql.c +++ b/addons/res_config_mysql.c @@ -303,6 +303,11 @@ static char *decode_chunk(char *chunk) return orig; } +#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE")) + +/* MySQL requires us to escape the escape... yo dawg */ +static char *ESCAPE_CLAUSE = " ESCAPE '\\\\'"; + static struct ast_variable *realtime_mysql(const char *database, const char *table, const struct ast_variable *rt_fields) { struct mysql_conn *dbh; @@ -315,6 +320,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab char *stringp; char *chunk; char *op; + char *escape = ""; const struct ast_variable *field = rt_fields; struct ast_variable *var=NULL, *prev=NULL; @@ -345,20 +351,29 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab /* Create the first part of the query using the first parameter/value pairs we just extracted If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ - if (!strchr(field->name, ' ')) - op = " ="; - else + if (!strchr(field->name, ' ')) { + op = " ="; + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf)); + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape); while ((field = field->next)) { - if (!strchr(field->name, ' ')) - op = " ="; - else + escape = ""; + if (!strchr(field->name, ' ')) { + op = " ="; + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf)); + ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape); } ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", ast_str_buffer(sql)); @@ -416,6 +431,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char char *stringp; char *chunk; char *op; + char *escape = ""; const struct ast_variable *field = rt_fields; struct ast_variable *var = NULL; struct ast_config *cfg = NULL; @@ -462,17 +478,29 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char /* Create the first part of the query using the first parameter/value pairs we just extracted If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ - if (!strchr(field->name, ' ')) + if (!strchr(field->name, ' ')) { op = " ="; - else + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf)); + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape); while ((field = field->next)) { - if (!strchr(field->name, ' ')) op = " ="; else op = ""; + escape = ""; + if (!strchr(field->name, ' ')) { + op = " ="; + } else { + op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf)); + ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape); } if (initfield) { diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 25a482705ae..f0859617dea 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -382,6 +382,9 @@ static struct columns *find_column(struct tables *t, const char *colname) return NULL; } +#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE")) +static char *ESCAPE_CLAUSE = " ESCAPE '\\'"; + static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields) { RAII_VAR(PGresult *, result, NULL, PQclear); @@ -391,6 +394,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab char *stringp; char *chunk; char *op; + char *escape = ""; const struct ast_variable *field = fields; struct ast_variable *var = NULL, *prev = NULL; @@ -418,7 +422,14 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab /* Create the first part of the query using the first parameter/value pairs we just extracted If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ - op = strchr(field->name, ' ') ? "" : " ="; + if (!strchr(field->name, ' ')) { + op = " ="; + } else { + op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(escapebuf, field->value); if (pgresult) { @@ -426,12 +437,17 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab return NULL; } - ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, field->name, op, ast_str_buffer(escapebuf)); + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", tablename, field->name, op, ast_str_buffer(escapebuf), escape); while ((field = field->next)) { - if (!strchr(field->name, ' ')) + escape = ""; + if (!strchr(field->name, ' ')) { op = " ="; - else + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(escapebuf, field->value); if (pgresult) { @@ -439,7 +455,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab return NULL; } - ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf)); + ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape); } /* We now have our complete statement; Lets connect to the server and execute it. */ @@ -505,6 +521,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char char *stringp; char *chunk; char *op; + char *escape = ""; struct ast_variable *var = NULL; struct ast_config *cfg = NULL; struct ast_category *cat = NULL; @@ -543,10 +560,15 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char /* Create the first part of the query using the first parameter/value pairs we just extracted If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ - if (!strchr(field->name, ' ')) + if (!strchr(field->name, ' ')) { op = " ="; - else + escape = ""; + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(escapebuf, field->value); if (pgresult) { @@ -555,12 +577,18 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char return NULL; } - ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(escapebuf)); + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(escapebuf), escape); while ((field = field->next)) { - if (!strchr(field->name, ' ')) + escape = ""; + if (!strchr(field->name, ' ')) { op = " ="; - else + escape = ""; + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(escapebuf, field->value); if (pgresult) { @@ -569,7 +597,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char return NULL; } - ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf)); + ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape); } if (initfield) { diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index b5c70ec2da4..bb3f78e5f25 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -58,6 +58,8 @@ /*** DOCUMENTATION ***/ +static int has_explicit_like_escaping; + static struct ast_config *realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked); static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields); static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields); @@ -658,6 +660,8 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char return config; } +#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE")) + /*! \brief Helper function for single and multi-row realtime load functions */ static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg) { @@ -683,6 +687,15 @@ static int realtime_sqlite3_helper(const char *database, const char *table, cons ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value)); } + + if (has_explicit_like_escaping && IS_SQL_LIKE_CLAUSE(field->name)) { + /* + * The realtime framework is going to pre-escape these + * for us with a backslash. We just need to make sure + * to tell SQLite about it + */ + ast_str_append(&sql, 0, " ESCAPE '\\'"); + } } if (!is_multi) { @@ -1182,6 +1195,29 @@ static int unload_module(void) return 0; } +static void discover_sqlite3_caps(void) +{ + /* + * So we cheat a little bit here. SQLite3 added support for the + * 'ESCAPE' keyword in 3.1.0. They added SQLITE_VERSION_NUMBER + * in 3.1.2. So if we run into 3.1.0 or 3.1.1 in the wild, we + * just treat it like < 3.1.0. + * + * For reference: 3.1.0, 3.1.1, and 3.1.2 were all released + * within 30 days of each other in Jan/Feb 2005, so I don't + * imagine we'll be finding something pre-3.1.2 that often in + * practice. + */ +#if defined(SQLITE_VERSION_NUMBER) + has_explicit_like_escaping = 1; +#else + has_explicit_like_escaping = 0; +#endif + + ast_debug(3, "SQLite3 has 'LIKE ... ESCAPE ...' support? %s\n", + has_explicit_like_escaping ? "Yes" : "No"); +} + /*! * \brief Load the module * @@ -1194,6 +1230,8 @@ static int unload_module(void) */ static int load_module(void) { + discover_sqlite3_caps(); + if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) { return AST_MODULE_LOAD_FAILURE; } From 8851c3e0885cb704a5a6159a51768ea5297e9b10 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 16 Feb 2017 16:30:00 +0000 Subject: [PATCH 1048/1578] build: Execute ldconfig to build cache. On some platforms a multiarch approach is used for libraries. The build system does not take this into account and still places libraries into the lib directory if no --libdir is specified to configure. On initial startup this results in libasteriskssl.so not being found, as it is not in the multiarch lib directory. This change does the minimally invasive thing and executes ldconfig so that the libraries in the lib directory are found and their location cached. By doing so Asterisk starts up fine. ASTERISK-26705 Change-Id: I6d30b6427e9d5e69470e11327c7ff203fa7da519 --- main/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/Makefile b/main/Makefile index 4d1b2c41bd2..331da845c81 100644 --- a/main/Makefile +++ b/main/Makefile @@ -355,7 +355,7 @@ else # Darwin endif endif ifneq ($(LDCONFIG),) - $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" + $(LDCONFIG) endif $(LN) -sf asterisk "$(DESTDIR)$(ASTSBINDIR)/rasterisk" @@ -373,7 +373,7 @@ ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" endif ifneq ($(LDCONFIG),) - $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" + $(LDCONFIG) endif clean:: From 8af634255542672806304fdafd1612dcfc9f35b1 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 7 Feb 2017 09:50:52 -0600 Subject: [PATCH 1049/1578] Add initial SDP options. This is step one of adding an SDP API: defining some configurable settings for SDPs. This is based on options that are currently supported in Asterisk. Change-Id: I1ede91aafed403b12a9ccdfb91a88389baa7e5d7 --- include/asterisk/sdp_options.h | 155 +++++++++++++++++++++++++++++++++ main/sdp_options.c | 120 +++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 include/asterisk/sdp_options.h create mode 100644 main/sdp_options.c diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h new file mode 100644 index 00000000000..52f6f554550 --- /dev/null +++ b/include/asterisk/sdp_options.h @@ -0,0 +1,155 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _ASTERISK_SDP_OPTIONS_H +#define _ASTERISK_SDP_OPTIONS_H + +struct ast_sdp_options; + +/*! + * \since 15.0.0 + * \brief Allocate a new SDP options structure. + * + * This will heap-allocate an SDP options structure and + * initialize it to a set of default values. + * + * \retval NULL Allocation failure + * \retval non-NULL Newly allocated SDP options + */ +struct ast_sdp_options *ast_sdp_options_alloc(void); + +/*! + * \since 15.0.0 + * \brief Free an SDP options structure. + * + * \note This only needs to be called if an error occurs between + * options allocation and a call to ast_sdp_state_alloc() + * Otherwise, the SDP state will take care of freeing the + * options for you. + * + * \param options The options to free + */ +void ast_sdp_options_free(struct ast_sdp_options *options); + +/*! + * \brief ICE options + * + * This is an enum because it is predicted that this eventually + * support a TRICKLE-ICE option. + */ +enum ast_sdp_options_ice { + /*! ICE is not enabled on this session */ + AST_SDP_ICE_DISABLED, + /*! Standard ICE is enabled on this session */ + AST_SDP_ICE_ENABLED_STANDARD, +}; + +/*! + * \since 15.0.0 + * \brief Set ICE options + * + * The default is AST_SDP_ICE_DISABLED + */ +int ast_sdp_options_set_ice(struct ast_sdp_options *options, + enum ast_sdp_options_ice ice_setting); + +/*! + * \since 15.0.0 + * \brief Retrieve ICE options + */ +enum ast_sdp_options_ice ast_sdp_options_get_ice(const struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Enable or disable telephone events. + * + * A non-zero value indicates telephone events are enabled. + * A zero value indicates telephone events are disabled. + * + * The default is 0 + */ +int ast_sdp_options_set_telephone_event(struct ast_sdp_options *options, + int telephone_event_enabled); + +/*! + * \since 15.0.0 + * \brief Retrieve telephone event setting. + * + * \retval 0 Telephone events are currently disabled. + * \retval non-zero Telephone events are currently enabled. + */ +int ast_sdp_options_get_telephone_event(const struct ast_sdp_options *options); + +/*! + * \brief Representation of the SDP + * + * Users of the SDP API set the representation based on what they + * natively handle. This indicates the type of SDP that the API expects + * when being given an SDP, and it indicates the type of SDP that the API + * returns when asked for one. + */ +enum ast_sdp_options_repr { + /*! SDP is represented as a string */ + AST_SDP_REPR_STRING, + /*! SDP is represented as a pjmedia_sdp_session */ + AST_SDP_REPR_PJMEDIA, +}; + +/*! + * \since 15.0.0 + * \brief Set the SDP representation + * + * The default is AST_SDP_REPR_STRING + */ +int ast_sdp_options_set_repr(struct ast_sdp_options *options, + enum ast_sdp_options_repr repr); + +/*! + * \since 15.0.0 + * \brief Get the SDP representation + */ +enum ast_sdp_options_repr ast_sdp_options_get_repr(const struct ast_sdp_options *options); + +/*! + * \brief SDP encryption options + */ +enum ast_sdp_options_encryption { + /*! No encryption */ + AST_SDP_ENCRYPTION_DISABLED, + /*! SRTP SDES encryption */ + AST_SDP_ENCRYPTION_SRTP_SDES, + /*! DTLS encryption */ + AST_SDP_ENCRYPTION_DTLS, +}; + +/*! + * \since 15.0.0 + * \brief Set the SDP encryption + * + * The default is AST_SDP_ENCRYPTION_DISABLED + */ +int ast_sdp_options_set_encryption(struct ast_sdp_options *options, + enum ast_sdp_options_encryption encryption); + +/*! + * \since 15.0.0 + * \brief Get the SDP encryption + */ +enum ast_sdp_options_encryption ast_sdp_options_get_encryption(const struct ast_sdp_options *options); + +#endif /* _ASTERISK_SDP_OPTIONS_H */ diff --git a/main/sdp_options.c b/main/sdp_options.c new file mode 100644 index 00000000000..e18dfa55abf --- /dev/null +++ b/main/sdp_options.c @@ -0,0 +1,120 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include "asterisk.h" + +#include "asterisk/utils.h" +#include "asterisk/sdp_options.h" + +struct ast_sdp_options { + enum ast_sdp_options_ice ice; + int telephone_event; + enum ast_sdp_options_repr repr; + enum ast_sdp_options_encryption encryption; +}; + +#define DEFAULT_ICE AST_SDP_ICE_DISABLED +#define DEFAULT_TELEPHONE_EVENT 0 +#define DEFAULT_REPR AST_SDP_REPR_STRING +#define DEFAULT_ENCRYPTION AST_SDP_ENCRYPTION_DISABLED + +static void set_defaults(struct ast_sdp_options *options) +{ + options->ice = DEFAULT_ICE; + options->telephone_event = DEFAULT_TELEPHONE_EVENT; + options->repr = DEFAULT_REPR; + options->encryption = DEFAULT_ENCRYPTION; +} + +struct ast_sdp_options *ast_sdp_options_alloc(void) +{ + struct ast_sdp_options *options; + + options = ast_calloc(1, sizeof(*options)); + if (!options) { + return NULL; + } + set_defaults(options); + return options; +} + +void ast_sdp_options_free(struct ast_sdp_options *options) +{ + ast_free(options); +} + +int ast_sdp_options_set_ice(struct ast_sdp_options *options, enum ast_sdp_options_ice ice_setting) +{ + ast_assert(options != NULL); + + options->ice = ice_setting; + return 0; +} + +enum ast_sdp_options_ice ast_sdp_options_get_ice(const struct ast_sdp_options *options) +{ + ast_assert(options != NULL); + + return options->ice; +} + +int ast_sdp_options_set_telephone_event(struct ast_sdp_options *options, int telephone_event_enabled) +{ + ast_assert(options != NULL); + + options->telephone_event = telephone_event_enabled; + return 0; +} + +int ast_sdp_options_get_telephone_event(const struct ast_sdp_options *options) +{ + ast_assert(options != NULL); + + return options->telephone_event; +} + +int ast_sdp_options_set_repr(struct ast_sdp_options *options, enum ast_sdp_options_repr repr) +{ + ast_assert(options != NULL); + + options->repr = repr; + return 0; +} + +enum ast_sdp_options_repr ast_sdp_options_get_repr(const struct ast_sdp_options *options) +{ + ast_assert(options != NULL); + + return options->repr; +} + +int ast_sdp_options_set_encryption(struct ast_sdp_options *options, + enum ast_sdp_options_encryption encryption) +{ + ast_assert(options != NULL); + + options->encryption = encryption; + return 0; +} + +enum ast_sdp_options_encryption ast_sdp_options_get_encryption(const struct ast_sdp_options *options) +{ + ast_assert(options != NULL); + + return options->encryption; +} From 5a130b2e1730467cd209d3b3c929ff5f24a2aa02 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 14 Feb 2017 09:54:43 -0600 Subject: [PATCH 1050/1578] Add SDP translator and PJMEDIA implementation. This creates the following: * Asterisk's internal representation of an SDP * An API for translating SDPs from one format to another * An implementation of a translator for PJMEDIA Change-Id: Ie2ecd3cbebe76756577be9b133e84d2ee356d46b --- include/asterisk/sdp_options.h | 2 + include/asterisk/sdp_priv.h | 130 +++++++ include/asterisk/sdp_translator.h | 102 ++++++ main/sdp_repr.c | 111 ++++++ main/sdp_translator.c | 99 +++++ res/res_sdp_translator_pjmedia.c | 577 ++++++++++++++++++++++++++++++ 6 files changed, 1021 insertions(+) create mode 100644 include/asterisk/sdp_priv.h create mode 100644 include/asterisk/sdp_translator.h create mode 100644 main/sdp_repr.c create mode 100644 main/sdp_translator.c create mode 100644 res/res_sdp_translator_pjmedia.c diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index 52f6f554550..a5c2d084e0a 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -108,6 +108,8 @@ enum ast_sdp_options_repr { AST_SDP_REPR_STRING, /*! SDP is represented as a pjmedia_sdp_session */ AST_SDP_REPR_PJMEDIA, + /*! End of the list */ + AST_SDP_REPR_END, }; /*! diff --git a/include/asterisk/sdp_priv.h b/include/asterisk/sdp_priv.h new file mode 100644 index 00000000000..000d1114388 --- /dev/null +++ b/include/asterisk/sdp_priv.h @@ -0,0 +1,130 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/* NOTE: It is unlikely that you need to include this file. You probably will only need + * this if you are an SDP translator, or if you are an inner part of the SDP API + */ + +#ifndef _SDP_PRIV_H +#define _SDP_PRIV_H + +#include "asterisk/vector.h" + +/*! + * \brief Structure representing an SDP attribute + */ +struct ast_sdp_a_line { + /*! Attribute name */ + char *name; + /*! Attribute value. For attributes that have no value, this will be an empty string */ + char *value; +}; + +/*! + * \brief Structure representing an SDP connection + */ +struct ast_sdp_c_line { + /* IP family string (e.g. IP4 or IP6) */ + char *family; + /* Connection address. Can be an IP address or FQDN */ + char *addr; +}; + +/*! + * \brief A collection of SDP attributes + */ +AST_VECTOR(ast_sdp_a_line_vector, struct ast_sdp_a_line); + +/*! + * \brief An SDP media stream + * + * This contains both the m line, as well as its + * constituent a lines. + */ +struct ast_sdp_m_line { + /*! Media type (e.g. "audio" or "video") */ + char *type; + /*! Port number in m line */ + uint16_t port; + /*! Number of ports specified in m line */ + uint16_t port_count; + /*! RTP profile string (e.g. "RTP/AVP") */ + char *profile; + /*! RTP payloads */ + AST_VECTOR(, char *) payloads; + /*! Connection information for this media stream */ + struct ast_sdp_c_line c_line; + /*! The attributes for this media stream */ + struct ast_sdp_a_line_vector a_lines; +}; + +/*! + * \brief SDP time information + */ +struct ast_sdp_t_line { + /*! Session start time */ + uint32_t start; + /*! Session end time */ + uint32_t end; +}; + +/*! + * \brief An SDP + */ +struct ast_sdp { + /*! SDP Origin line */ + struct { + /*! Origin user name */ + char *user; + /*! Origin id */ + uint32_t id; + /*! Origin version */ + uint32_t version; + /*! Origin IP address family (e.g. "IP4" or "IP6") */ + char *family; + /*! Origin address. Can be an IP address or FQDN */ + char *addr; + } o_line; + /*! SDP Session name */ + char *s_line; + /*! SDP top-level connection information */ + struct ast_sdp_c_line c_line; + /*! SDP timing information */ + struct ast_sdp_t_line t_line; + /*! SDP top-level attributes */ + struct ast_sdp_a_line_vector a_lines; + /*! SDP media streams */ + AST_VECTOR(, struct ast_sdp_m_line) m_lines; +}; + +/*! + * \brief Allocate a new SDP. + * + * \note This does not perform any initialization. + * + * \retval NULL FAIL + * \retval non-NULL New SDP + */ +struct ast_sdp *ast_sdp_alloc(void); + +/*! + * \brief Free an SDP and all its constituent parts + */ +void ast_sdp_free(struct ast_sdp *dead); + +#endif /* _SDP_PRIV_H */ diff --git a/include/asterisk/sdp_translator.h b/include/asterisk/sdp_translator.h new file mode 100644 index 00000000000..62a875e0aa3 --- /dev/null +++ b/include/asterisk/sdp_translator.h @@ -0,0 +1,102 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _ASTERISK_SDP_TRANSLATOR_H +#define _ASTERISK_SDP_TRANSLATOR_H + +#include "asterisk/sdp_options.h" + +struct sdp; + +/*! + * \brief SDP translator operations + */ +struct ast_sdp_translator_ops { + /*! The SDP representation on which this translator operates */ + enum ast_sdp_options_repr repr; + /*! Allocate new translator private data for a translator */ + void *(*translator_new)(void); + /*! Free translator private data */ + void (*translator_free)(void *translator_priv); + /*! Convert the channel-native SDP into an internal Asterisk SDP */ + struct ast_sdp *(*to_sdp)(void *repr_sdp, void *translator_priv); + /*! Convert an internal Asterisk SDP into a channel-native SDP */ + void *(*from_sdp)(struct ast_sdp *sdp, void *translator_priv); +}; + +/*! + * \brief An SDP translator + * + * An SDP translator is responsible for converting between Asterisk's internal + * representation of an SDP and the representation that is native to the channel + * driver. Translators are allocated per-use. + */ +struct ast_sdp_translator { + /*! The operations this translator uses */ + struct ast_sdp_translator_ops *ops; + /*! Private data this translator uses */ + void *translator_priv; +}; + +/*! + * \brief Register an SDP translator + * \param ops The SDP operations defined by this translator + * \retval 0 Success + * \retval -1 FAIL + */ +int ast_sdp_register_translator(struct ast_sdp_translator_ops *ops); + +/*! + * \brief Unregister an SDP translator + */ +void ast_sdp_unregister_translator(struct ast_sdp_translator_ops *ops); + +/*! + * \brief Allocate a new SDP translator + * \param Representation corresponding to the translator_ops to use + * \retval NULL FAIL + * \retval non-NULL New SDP translator + */ +struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_repr repr); + +/*! + * \brief Free an SDP translator + */ +void ast_sdp_translator_free(struct ast_sdp_translator *translator); + +/*! + * \brief Translate a native SDP to internal Asterisk SDP + * + * \param translator The translator to use when translating + * \param native_sdp The SDP from the channel driver + * \retval NULL FAIL + * \retval Non-NULL The translated SDP + */ +struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, void *native_sdp); + +/*! + * \brief Translate an internal Asterisk SDP to a native SDP + * + * \param translator The translator to use when translating + * \param ast_sdp The Asterisk SDP to translate + * \retval NULL FAIL + * \retval non-NULL The translated SDP + */ +void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, struct ast_sdp *ast_sdp); + +#endif /* _ASTERISK_SDP_TRANSLATOR_H */ diff --git a/main/sdp_repr.c b/main/sdp_repr.c new file mode 100644 index 00000000000..6df243b0e12 --- /dev/null +++ b/main/sdp_repr.c @@ -0,0 +1,111 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include "asterisk.h" +#include "asterisk/sdp_priv.h" +#include "asterisk/utils.h" + +struct ast_sdp *ast_sdp_alloc(void) +{ + struct ast_sdp *new_sdp; + + new_sdp = ast_calloc(1, sizeof *new_sdp); + return new_sdp; +} + +static void free_o_line(struct ast_sdp *dead) +{ + ast_free(dead->o_line.user); + ast_free(dead->o_line.family); + ast_free(dead->o_line.addr); +} + +static void free_s_line(struct ast_sdp *dead) +{ + ast_free(dead->s_line); +} + +static void free_c_line(struct ast_sdp_c_line *c_line) +{ + ast_free(c_line->family); + ast_free(c_line->addr); +} + +static void free_t_line(struct ast_sdp_t_line *t_line) +{ + return; +} + +static void free_a_line(struct ast_sdp_a_line *a_line) +{ + ast_free(a_line->name); + ast_free(a_line->value); +} + +static void free_a_lines(struct ast_sdp_a_line_vector *a_lines) +{ + int i; + + for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { + free_a_line(AST_VECTOR_GET_ADDR(a_lines, i)); + } + AST_VECTOR_FREE(a_lines); +} + +static void free_m_line(struct ast_sdp_m_line *m_line) +{ + int i; + + ast_free(m_line->type); + ast_free(m_line->profile); + free_c_line(&m_line->c_line); + + for (i = 0; i < AST_VECTOR_SIZE(&m_line->payloads); ++i) { + ast_free(AST_VECTOR_GET(&m_line->payloads, i)); + } + AST_VECTOR_FREE(&m_line->payloads); + + free_a_lines(&m_line->a_lines); +} + +static void free_m_lines(struct ast_sdp *dead) +{ + int i; + + for (i = 0; i < AST_VECTOR_SIZE(&dead->m_lines); ++i) { + free_m_line(AST_VECTOR_GET_ADDR(&dead->m_lines, i)); + } + + AST_VECTOR_FREE(&dead->m_lines); +} + +void ast_sdp_free(struct ast_sdp *dead) +{ + if (!dead) { + return; + } + + free_o_line(dead); + free_s_line(dead); + free_c_line(&dead->c_line); + free_t_line(&dead->t_line); + free_a_lines(&dead->a_lines); + free_m_lines(dead); + ast_free(dead); +} + diff --git a/main/sdp_translator.c b/main/sdp_translator.c new file mode 100644 index 00000000000..5426ae95420 --- /dev/null +++ b/main/sdp_translator.c @@ -0,0 +1,99 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include "asterisk.h" +#include "asterisk/sdp_options.h" +#include "asterisk/sdp_translator.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/lock.h" + +AST_RWLOCK_DEFINE_STATIC(registered_ops_lock); +static struct ast_sdp_translator_ops *registered_ops[AST_SDP_REPR_END]; + +int ast_sdp_register_translator(struct ast_sdp_translator_ops *ops) +{ + SCOPED_WRLOCK(lock, ®istered_ops_lock); + + if (ops->repr >= AST_SDP_REPR_END) { + ast_log(LOG_ERROR, "SDP translator has unrecognized representation\n"); + return -1; + } + + if (registered_ops[ops->repr] != NULL) { + ast_log(LOG_ERROR, "SDP_translator with this representation already registered\n"); + return -1; + } + + registered_ops[ops->repr] = ops; + ast_log(LOG_NOTICE, "Placed ops %p at slot %d\n", ops, ops->repr); + return 0; +} + +void ast_sdp_unregister_translator(struct ast_sdp_translator_ops *ops) +{ + SCOPED_WRLOCK(lock, ®istered_ops_lock); + + if (ops->repr >= AST_SDP_REPR_END) { + return; + } + + registered_ops[ops->repr] = NULL; +} + +struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_repr repr) +{ + struct ast_sdp_translator *translator; + SCOPED_RDLOCK(lock, ®istered_ops_lock); + + if (registered_ops[repr] == NULL) { + ast_log(LOG_NOTICE, "No registered SDP translator with representation %d\n", repr); + return NULL; + } + + translator = ast_calloc(1, sizeof(*translator)); + if (!translator) { + return NULL; + } + + translator->ops = registered_ops[repr]; + + translator->translator_priv = translator->ops->translator_new(); + if (!translator->translator_priv) { + ast_free(translator); + return NULL; + } + + return translator; +} + +void ast_sdp_translator_free(struct ast_sdp_translator *translator) +{ + translator->ops->translator_free(translator->translator_priv); + ast_free(translator); +} + +struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, void *native_sdp) +{ + return translator->ops->to_sdp(native_sdp, translator->translator_priv); +} + +void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, struct ast_sdp *ast_sdp) +{ + return translator->ops->from_sdp(ast_sdp, translator->translator_priv); +} diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c new file mode 100644 index 00000000000..141b97617c3 --- /dev/null +++ b/res/res_sdp_translator_pjmedia.c @@ -0,0 +1,577 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include "asterisk.h" +#include "asterisk/sdp_translator.h" +#include "asterisk/sdp_options.h" +#include "asterisk/sdp_priv.h" +#include "asterisk/vector.h" +#include "asterisk/netsock2.h" +#include "asterisk/utils.h" +#include "asterisk/config.h" +#include "asterisk/test.h" +#include "asterisk/module.h" +#ifdef HAVE_PJPROJECT +#include +#include +#endif + +/*** MODULEINFO + pjproject + core + ***/ + +static pj_caching_pool sdp_caching_pool; + + +static void *pjmedia_new(void) +{ + pj_pool_t *pool; + + pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia sdp translator", 1024, 1024, NULL); + + return pool; +} + +static void pjmedia_free(void *translator_priv) +{ + pj_pool_t *pool = translator_priv; + + pj_pool_release(pool); +} + +static void copy_pj_str(char *dest, const pj_str_t *src, size_t size) +{ + memcpy(dest, pj_strbuf(src), size); + dest[size] = '\0'; +} + +static void dup_pj_str(char **dest, const pj_str_t *src) +{ + *dest = ast_malloc(pj_strlen(src) + 1); + copy_pj_str(*dest, src, pj_strlen(src)); +} + +static void pjmedia_copy_o_line(struct ast_sdp *new_sdp, struct pjmedia_sdp_session * pjmedia_sdp) +{ + dup_pj_str(&new_sdp->o_line.user, &pjmedia_sdp->origin.user); + new_sdp->o_line.id = pjmedia_sdp->origin.id; + new_sdp->o_line.version = pjmedia_sdp->origin.version; + dup_pj_str(&new_sdp->o_line.family, &pjmedia_sdp->origin.addr_type); + dup_pj_str(&new_sdp->o_line.addr, &pjmedia_sdp->origin.addr); +} + +static void pjmedia_copy_s_line(struct ast_sdp *new_sdp, struct pjmedia_sdp_session *pjmedia_sdp) +{ + dup_pj_str(&new_sdp->s_line, &pjmedia_sdp->name); +} + +static void pjmedia_copy_t_line(struct ast_sdp_t_line *new_t_line, struct pjmedia_sdp_session *pjmedia_sdp) +{ + new_t_line->start = pjmedia_sdp->time.start; + new_t_line->end = pjmedia_sdp->time.stop; +} + +static void pjmedia_copy_c_line(struct ast_sdp_c_line *new_c_line, struct pjmedia_sdp_conn *conn) +{ + /* It's perfectly reasonable for a c line not to be present, especially within a media description */ + if (!conn) { + return; + } + + dup_pj_str(&new_c_line->family, &conn->addr_type); + dup_pj_str(&new_c_line->addr, &conn->addr); +} + +static void pjmedia_copy_m_line(struct ast_sdp_m_line *new_m_line, struct pjmedia_sdp_media *pjmedia_m_line) +{ + int i; + + dup_pj_str(&new_m_line->type, &pjmedia_m_line->desc.media); + new_m_line->port = pjmedia_m_line->desc.port; + new_m_line->port_count = pjmedia_m_line->desc.port_count; + dup_pj_str(&new_m_line->profile, &pjmedia_m_line->desc.transport); + pjmedia_copy_c_line(&new_m_line->c_line, pjmedia_m_line->conn); + + AST_VECTOR_INIT(&new_m_line->payloads, pjmedia_m_line->desc.fmt_count); + for (i = 0; i < pjmedia_m_line->desc.fmt_count; ++i) { + ++new_m_line->payloads.current; + dup_pj_str(AST_VECTOR_GET_ADDR(&new_m_line->payloads, i), &pjmedia_m_line->desc.fmt[i]); + } +} + +static void pjmedia_copy_a_lines(struct ast_sdp_a_line_vector *new_a_lines, pjmedia_sdp_attr **attr, unsigned int attr_count) +{ + int i; + + AST_VECTOR_INIT(new_a_lines, attr_count); + + for (i = 0; i < attr_count; ++i) { + struct ast_sdp_a_line *a_line; + + ++new_a_lines->current; + a_line = AST_VECTOR_GET_ADDR(new_a_lines, i); + dup_pj_str(&a_line->name, &attr[i]->name); + dup_pj_str(&a_line->value, &attr[i]->value); + } +} + +static void pjmedia_copy_m_lines(struct ast_sdp *new_sdp, struct pjmedia_sdp_session *pjmedia_sdp) +{ + int i; + + AST_VECTOR_INIT(&new_sdp->m_lines, pjmedia_sdp->media_count); + + for (i = 0; i < pjmedia_sdp->media_count; ++i) { + ++new_sdp->m_lines.current; + + pjmedia_copy_m_line(AST_VECTOR_GET_ADDR(&new_sdp->m_lines, i), pjmedia_sdp->media[i]); + pjmedia_copy_a_lines(&AST_VECTOR_GET_ADDR(&new_sdp->m_lines, i)->a_lines, pjmedia_sdp->media[i]->attr, pjmedia_sdp->media[i]->attr_count); + } +} + +static struct ast_sdp *pjmedia_to_sdp(void *in, void *translator_priv) +{ + struct pjmedia_sdp_session *pjmedia_sdp = in; + + struct ast_sdp *new_sdp = ast_sdp_alloc(); + + pjmedia_copy_o_line(new_sdp, pjmedia_sdp); + pjmedia_copy_s_line(new_sdp, pjmedia_sdp); + pjmedia_copy_t_line(&new_sdp->t_line, pjmedia_sdp); + pjmedia_copy_c_line(&new_sdp->c_line, pjmedia_sdp->conn); + pjmedia_copy_a_lines(&new_sdp->a_lines, pjmedia_sdp->attr, pjmedia_sdp->attr_count); + pjmedia_copy_m_lines(new_sdp, pjmedia_sdp); + + return new_sdp; +} + +static void copy_o_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp *sdp) +{ + pjmedia_sdp->origin.id = sdp->o_line.id; + pjmedia_sdp->origin.version = sdp->o_line.version; + pj_strdup2(pool, &pjmedia_sdp->origin.user, sdp->o_line.user); + pj_strdup2(pool, &pjmedia_sdp->origin.addr_type, sdp->o_line.family); + pj_strdup2(pool, &pjmedia_sdp->origin.addr, sdp->o_line.addr); + pj_strdup2(pool, &pjmedia_sdp->origin.net_type, "IN"); +} + +static void copy_s_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp *sdp) +{ + pj_strdup2(pool, &pjmedia_sdp->name, sdp->s_line); +} + +static void copy_t_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp_t_line *t_line) +{ + pjmedia_sdp->time.start = t_line->start; + pjmedia_sdp->time.stop = t_line->end; +} + +static void copy_c_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_conn **conn, struct ast_sdp_c_line *c_line) +{ + pjmedia_sdp_conn *local_conn; + local_conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); + pj_strdup2(pool, &local_conn->addr_type, c_line->family); + pj_strdup2(pool, &local_conn->addr, c_line->addr); + pj_strdup2(pool, &local_conn->net_type, "IN"); + + *conn = local_conn; +} + +static void copy_a_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp_a_line_vector *a_lines) +{ + int i; + + for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { + pjmedia_sdp_attr *attr; + pj_str_t value; + + pj_strdup2(pool, &value, AST_VECTOR_GET(a_lines, i).value); + attr = pjmedia_sdp_attr_create(pool, AST_VECTOR_GET(a_lines, i).name, &value); + pjmedia_sdp_session_add_attr(pjmedia_sdp, attr); + } +} + +static void copy_a_lines_pjmedia_media(pj_pool_t *pool, pjmedia_sdp_media *media, struct ast_sdp_a_line_vector *a_lines) +{ + int i; + + for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { + pjmedia_sdp_attr *attr; + pj_str_t value; + + pj_strdup2(pool, &value, AST_VECTOR_GET(a_lines, i).value); + attr = pjmedia_sdp_attr_create(pool, AST_VECTOR_GET(a_lines, i).name, &value); + pjmedia_sdp_media_add_attr(media, attr); + } +} + +static void copy_m_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_media *media, struct ast_sdp_m_line *m_line) +{ + int i; + + media->desc.port = m_line->port; + media->desc.port_count = m_line->port_count; + pj_strdup2(pool, &media->desc.transport, m_line->profile); + pj_strdup2(pool, &media->desc.media, m_line->type); + + for (i = 0; i < AST_VECTOR_SIZE(&m_line->payloads); ++i) { + pj_strdup2(pool, &media->desc.fmt[i], AST_VECTOR_GET(&m_line->payloads, i)); + ++media->desc.fmt_count; + } + if (m_line->c_line.addr) { + copy_c_line_pjmedia(pool, &media->conn, &m_line->c_line); + } + copy_a_lines_pjmedia_media(pool, media, &m_line->a_lines); +} + +static void copy_m_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp *sdp) +{ + int i; + + for (i = 0; i < AST_VECTOR_SIZE(&sdp->m_lines); ++i) { + pjmedia_sdp_media *media; + + media = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); + copy_m_line_pjmedia(pool, media, AST_VECTOR_GET_ADDR(&sdp->m_lines, i)); + pjmedia_sdp->media[pjmedia_sdp->media_count] = media; + ++pjmedia_sdp->media_count; + } +} + +static void *sdp_to_pjmedia(struct ast_sdp *sdp, void *translator_priv) +{ + pj_pool_t *pool = translator_priv; + pjmedia_sdp_session *pjmedia_sdp; + + pjmedia_sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session); + copy_o_line_pjmedia(pool, pjmedia_sdp, sdp); + copy_s_line_pjmedia(pool, pjmedia_sdp, sdp); + copy_t_line_pjmedia(pool, pjmedia_sdp, &sdp->t_line); + copy_c_line_pjmedia(pool, &pjmedia_sdp->conn, &sdp->c_line); + copy_a_lines_pjmedia(pool, pjmedia_sdp, &sdp->a_lines); + copy_m_lines_pjmedia(pool, pjmedia_sdp, sdp); + return pjmedia_sdp; +} + +static struct ast_sdp_translator_ops pjmedia_translator = { + .repr = AST_SDP_REPR_PJMEDIA, + .translator_new = pjmedia_new, + .translator_free = pjmedia_free, + .to_sdp = pjmedia_to_sdp, + .from_sdp = sdp_to_pjmedia, +}; + +#ifdef TEST_FRAMEWORK + +static int verify_s_line(char *s_line, char *expected) +{ + return strcmp(s_line, expected) == 0; +} + +static int verify_c_line(struct ast_sdp_c_line *c_line, char *family, char *addr) +{ + return strcmp(c_line->family, family) == 0 && strcmp(c_line->addr, addr) == 0; +} + +static int verify_t_line(struct ast_sdp_t_line *t_line, uint32_t start, uint32_t end) +{ + return t_line->start == start && t_line->end == end; +} + +static int verify_m_line(struct ast_sdp *sdp, int index, char *type, int port, int port_count, char *profile, ...) +{ + struct ast_sdp_m_line *m_line; + int res; + va_list ap; + int i; + + m_line = AST_VECTOR_GET_ADDR(&sdp->m_lines, index); + + res = strcmp(m_line->type, type) == 0; + res |= m_line->port == port; + res |= m_line->port_count == port_count; + res |= strcmp(m_line->profile, profile) == 0; + + va_start(ap, profile); + for (i = 0; i < AST_VECTOR_SIZE(&m_line->payloads); ++i) { + char *payload; + + payload = va_arg(ap, char *); + if (!payload) { + res = -1; + break; + } + res |= strcmp(AST_VECTOR_GET(&m_line->payloads, i), payload) == 0; + } + va_end(ap); + return res; +} + +static int verify_a_line(struct ast_sdp *sdp, int m_index, int a_index, char *name, char *value) +{ + struct ast_sdp_m_line *m_line; + struct ast_sdp_a_line *a_line; + + m_line = AST_VECTOR_GET_ADDR(&sdp->m_lines, m_index); + a_line = AST_VECTOR_GET_ADDR(&m_line->a_lines, a_index); + + return strcmp(a_line->name, name) == 0 && strcmp(a_line->value, value) == 0; +} + +AST_TEST_DEFINE(pjmedia_to_sdp_test) +{ + struct ast_sdp_translator *translator; + pj_pool_t *pool; + char *sdp_str = + "v=0\r\n" + "o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com\r\n" + "s= \r\n" + "c=IN IP4 host.atlanta.example.com\r\n" + "t=0 0\r\n" + "m=audio 49170 RTP/AVP 0 8 97\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:97 iLBC/8000\r\n" + "a=sendrecv\r\n" + "m=video 51372 RTP/AVP 31 32\r\n" + "a=rtpmap:31 H261/90000\r\n" + "a=rtpmap:32 MPV/90000\r\n"; + pjmedia_sdp_session *pjmedia_sdp; + struct ast_sdp *sdp = NULL; + pj_status_t status; + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "pjmedia_to_sdp"; + info->category = "/main/sdp/"; + info->summary = "PJMEDIA to SDP unit test"; + info->description = + "Ensures PJMEDIA SDPs are translated correctly"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia to sdp test", 1024, 1024, NULL); + + translator = ast_sdp_translator_new(AST_SDP_REPR_PJMEDIA); + if (!translator) { + ast_test_status_update(test, "Failed to create SDP translator\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + + status = pjmedia_sdp_parse(pool, sdp_str, strlen(sdp_str), &pjmedia_sdp); + if (status != PJ_SUCCESS) { + ast_test_status_update(test, "Error parsing SDP\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + + sdp = ast_sdp_translator_to_sdp(translator, pjmedia_sdp); + + if (strcmp(sdp->o_line.user, "alice")) { + ast_test_status_update(test, "Unexpected SDP user '%s'\n", sdp->o_line.user); + res = AST_TEST_FAIL; + goto cleanup; + } else if (sdp->o_line.id != 2890844526u) { + ast_test_status_update(test, "Unexpected SDP id '%u'\n", sdp->o_line.id); + res = AST_TEST_FAIL; + goto cleanup; + } else if (sdp->o_line.version != 2890844526u) { + ast_test_status_update(test, "Unexpected SDP version '%u'\n", sdp->o_line.version); + res = AST_TEST_FAIL; + goto cleanup; + } else if (strcmp(sdp->o_line.family, "IP4")) { + ast_test_status_update(test, "Unexpected address family '%s'\n", sdp->o_line.family); + res = AST_TEST_FAIL; + goto cleanup; + } else if (strcmp(sdp->o_line.addr, "host.atlanta.example.com")) { + ast_test_status_update(test, "Unexpected address '%s'\n", sdp->o_line.addr); + res = AST_TEST_FAIL; + goto cleanup; + } + + if (!verify_s_line(sdp->s_line, " ")) { + ast_test_status_update(test, "Bad s line\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_c_line(&sdp->c_line, "IP4", "host.atlanta.example.com")) { + ast_test_status_update(test, "Bad c line\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_t_line(&sdp->t_line, 0, 0)) { + ast_test_status_update(test, "Bad t line\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + + if (!verify_m_line(sdp, 0, "audio", 49170, 1, "RTP/AVP", "0", "8", "97", NULL)) { + ast_test_status_update(test, "Bad m line 1\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_a_line(sdp, 0, 0, "rtpmap", "0 PCMU/8000")) { + ast_test_status_update(test, "Bad a line 1\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_a_line(sdp, 0, 1, "rtpmap", "8 PCMA/8000")) { + ast_test_status_update(test, "Bad a line 2\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_a_line(sdp, 0, 2, "rtpmap", "97 iLBC/8000")) { + ast_test_status_update(test, "Bad a line 3\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_a_line(sdp, 0, 3, "sendrecv", "")) { + ast_test_status_update(test, "Bad a line 3\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_m_line(sdp, 1, "video", 51372, 1, "RTP/AVP", "31", "32", NULL)) { + ast_test_status_update(test, "Bad m line 2\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_a_line(sdp, 1, 0, "rtpmap", "31 H261/90000")) { + ast_test_status_update(test, "Bad a line 4\n"); + res = AST_TEST_FAIL; + goto cleanup; + } else if (!verify_a_line(sdp, 1, 1, "rtpmap", "32 MPV/90000")) { + ast_test_status_update(test, "Bad a line 5\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + +cleanup: + ast_sdp_free(sdp); + ast_sdp_translator_free(translator); + pj_pool_release(pool); + return res; +} + +AST_TEST_DEFINE(sdp_to_pjmedia_test) +{ + struct ast_sdp_translator *translator; + char *sdp_str = + "v=0\r\n" + "o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com\r\n" + "s= \r\n" + "c=IN IP4 host.atlanta.example.com\r\n" + "t=0 0\r\n" + "m=audio 49170 RTP/AVP 0 8 97\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:97 iLBC/8000\r\n" + "a=sendrecv\r\n" + "m=video 51372 RTP/AVP 31 32\r\n" + "a=rtpmap:31 H261/90000\r\n" + "a=rtpmap:32 MPV/90000\r\n\r\n"; + pj_pool_t *pool; + pjmedia_sdp_session *pjmedia_sdp_orig; + pjmedia_sdp_session *pjmedia_sdp_dup; + struct ast_sdp *sdp = NULL; + pj_status_t status; + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "sdp_to_pjmedia"; + info->category = "/main/sdp/"; + info->summary = "SDP to PJMEDIA unit test"; + info->description = + "Ensures PJMEDIA SDPs are translated correctly"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia to sdp test", 1024, 1024, NULL); + + translator = ast_sdp_translator_new(AST_SDP_REPR_PJMEDIA); + if (!translator) { + ast_test_status_update(test, "Failed to create SDP translator\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + + status = pjmedia_sdp_parse(pool, sdp_str, strlen(sdp_str), &pjmedia_sdp_orig); + if (status != PJ_SUCCESS) { + ast_test_status_update(test, "Error parsing SDP\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + + sdp = ast_sdp_translator_to_sdp(translator, pjmedia_sdp_orig); + pjmedia_sdp_dup = ast_sdp_translator_from_sdp(translator, sdp); + + if ((status = pjmedia_sdp_session_cmp(pjmedia_sdp_orig, pjmedia_sdp_dup, 0)) != PJ_SUCCESS) { + char buf[2048]; + char errbuf[256]; + ast_test_status_update(test, "SDPs aren't equal\n"); + pjmedia_sdp_print(pjmedia_sdp_orig, buf, sizeof(buf)); + ast_log(LOG_NOTICE, "Original SDP is %s\n", buf); + pjmedia_sdp_print(pjmedia_sdp_dup, buf, sizeof(buf)); + ast_log(LOG_NOTICE, "New SDP is %s\n", buf); + pjmedia_strerror(status, errbuf, sizeof(errbuf)); + ast_log(LOG_NOTICE, "PJMEDIA says %d: '%s'\n", status, errbuf); + res = AST_TEST_FAIL; + goto cleanup; + } + +cleanup: + ast_sdp_free(sdp); + ast_sdp_translator_free(translator); + pj_pool_release(pool); + return res; +} + +#endif /* TEST_FRAMEWORK */ + +static int load_module(void) +{ + if (ast_sdp_register_translator(&pjmedia_translator)) { + return AST_MODULE_LOAD_DECLINE; + } + pj_caching_pool_init(&sdp_caching_pool, NULL, 1024 * 1024); + AST_TEST_REGISTER(pjmedia_to_sdp_test); + AST_TEST_REGISTER(sdp_to_pjmedia_test); + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + ast_sdp_unregister_translator(&pjmedia_translator); + pj_caching_pool_destroy(&sdp_caching_pool); + AST_TEST_UNREGISTER(pjmedia_to_sdp_test); + AST_TEST_REGISTER(sdp_to_pjmedia_test); + return 0; +} + +static int reload_module(void) +{ + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJMEDIA SDP Translator", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .reload = reload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND, +); From dbc359801483e0b793661d5c39166a44538d9785 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 17 Feb 2017 14:58:28 -0600 Subject: [PATCH 1051/1578] Remove extra ast_iostream_close() calls. When AMI encounters an error at the beginning of a session, it would explicitly call ast_iostream_close() on its tcptls session's iostream. It then would jump to a label where it would shut down the tcptls session instance. The tcptls session instance would again attempt to close the iostream. Under normal circumstances, this might go by unnoticed. However, when MALLOC_DEBUG is enabled, all fields on the iostream get set to 0xdeaddead when the iostream is freed. Thus a second call to ast_iostream_close() after the iostream has been freed would reslt in an attempt to call SSL_shutdown on 0xdeaddead, which would crash and burn horribly. The fix here is to not directly close the iostream from the dangerous scenarios. The specific scenarios are: * Exceeding the configured authlimit * Failing to build a mansession on a new connection Change-Id: I908f98d516afd5a263bd36b072221008a4731acd --- main/manager.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/main/manager.c b/main/manager.c index a25497fd323..f11c8dca4ec 100644 --- a/main/manager.c +++ b/main/manager.c @@ -6629,7 +6629,6 @@ static void *session_do(void *data) struct ast_sockaddr ser_remote_address_tmp; if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) { - ast_iostream_close(ser->stream); ast_atomic_fetchadd_int(&unauth_sessions, -1); goto done; } @@ -6638,7 +6637,6 @@ static void *session_do(void *data) session = build_mansession(&ser_remote_address_tmp); if (session == NULL) { - ast_iostream_close(ser->stream); ast_atomic_fetchadd_int(&unauth_sessions, -1); goto done; } From 0b427f9b595c28a91e51c8dd6f7a7f0c9cac4d60 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 17 Feb 2017 16:57:54 -0600 Subject: [PATCH 1052/1578] tcptls.c: Add some missing allocation failure checks. * Fix tcptls_session ref and fd leak in ast_tcptls_server_root(). Change-Id: I0ddf01cd3c10d3b6666d7bf68d4e206a37f4fbdb --- main/tcptls.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/main/tcptls.c b/main/tcptls.c index 7f1421db8e0..1377dd72d93 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -240,20 +240,23 @@ void *ast_tcptls_server_root(void *data) } tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); if (!tcptls_session) { - ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); - if (close(fd)) { - ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); - } + close(fd); continue; } tcptls_session->overflow_buf = ast_str_create(128); + if (!tcptls_session->overflow_buf) { + ao2_ref(tcptls_session, -1); + close(fd); + continue; + } flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); tcptls_session->stream = ast_iostream_from_fd(&fd); if (!tcptls_session->stream) { - ast_log(LOG_WARNING, "No memory for new session iostream\n"); + ao2_ref(tcptls_session, -1); + close(fd); continue; } @@ -265,7 +268,6 @@ void *ast_tcptls_server_root(void *data) /* This thread is now the only place that controls the single ref to tcptls_session */ if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { ast_log(LOG_ERROR, "Unable to launch helper thread: %s\n", strerror(errno)); - ast_tcptls_close_session_file(tcptls_session); ao2_ref(tcptls_session, -1); } } @@ -561,11 +563,15 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s } } - if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) { + tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); + if (!tcptls_session) { goto error; } tcptls_session->overflow_buf = ast_str_create(128); + if (!tcptls_session->overflow_buf) { + goto error; + } tcptls_session->client = 1; tcptls_session->stream = ast_iostream_from_fd(&fd); if (!tcptls_session->stream) { @@ -584,9 +590,7 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s error: close(desc->accept_fd); desc->accept_fd = -1; - if (tcptls_session) { - ao2_ref(tcptls_session, -1); - } + ao2_cleanup(tcptls_session); return NULL; } From 51e3b11989812875bc4703b064bdb0ab9c979ebb Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 17 Feb 2017 18:06:47 -0500 Subject: [PATCH 1053/1578] pjproject-bundled: Fix checksum verification when using cURL ASTERISK-26802 #close Reported by: Michael L. Young Change-Id: Iad293080f55d4d69ab615717a15211d916eed613 --- configure | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 2b25eadb152..148d1110133 100755 --- a/configure +++ b/configure @@ -7966,7 +7966,7 @@ if test "${WGET}" != ":" ; then DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" - DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\"" + DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar" DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)' else # Extract the first word of "fetch", so it can be a program name with args. diff --git a/configure.ac b/configure.ac index 63d2b41532f..5a504986c8c 100644 --- a/configure.ac +++ b/configure.ac @@ -297,7 +297,7 @@ if test "${WGET}" != ":" ; then DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" - DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\"" + DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar" DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)' else AC_PATH_PROG([FETCH], [fetch], [:]) From 44abe214d24f772b9d66a96d592aa15c17c7c429 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 15 Feb 2017 12:55:19 -0500 Subject: [PATCH 1054/1578] res_config_sqlite3: Fix crash when loading with invalid config When ast_config_load() fails with CONFIG_STATUS_FILEINVALID, it has already destroyed the ast_config struct for us. Trying to do it again results in a crash. Change-Id: If6a5c0ca718ad428e01a1fb25beb209a9ac18bc6 --- res/res_config_sqlite3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index b5c70ec2da4..f2a6b00dbb0 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -1125,6 +1125,8 @@ static int parse_config(int reload) if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "%s config file '%s'\n", config == CONFIG_STATUS_FILEMISSING ? "Missing" : "Invalid", config_filename); + ast_mutex_unlock(&config_lock); + return 0; } else { const char *cat; struct realtime_sqlite3_db *db; From d6d86f1c09f041ef00c1d106d924cf918172974a Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 20 Feb 2017 06:27:38 -0500 Subject: [PATCH 1055/1578] res_config_ldap: Fix erroneous LDAP_MOD_REPLACE in LDAP modify We always treat the first change of our modification batch as a replacement when it sometimes is actually a delete. So we have to pass the correct arguments to the OpenLDAP library. ASTERISK-26580 #close Reported by: Nicholas John Koch Patches: res_config_ldap.c-11.24.1.patch (license #6833) patch uploaded by Nicholas John Koch Change-Id: I0741d25de07c9539f1edc6eff3696165dfb64fbe --- res/res_config_ldap.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 5e95853d462..a8a8fe696ae 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -1292,12 +1292,15 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */ ldap_mods = ldap_memcalloc(sizeof(LDAPMod *), mods_size); ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod)); - - ldap_mods[0]->mod_op = LDAP_MOD_REPLACE; ldap_mods[0]->mod_type = ldap_strdup(newparam); - ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2); - ldap_mods[0]->mod_values[0] = ldap_strdup(field->value); + if (strlen(field->value) == 0) { + ldap_mods[0]->mod_op = LDAP_MOD_DELETE; + } else { + ldap_mods[0]->mod_op = LDAP_MOD_REPLACE; + ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2); + ldap_mods[0]->mod_values[0] = ldap_strdup(field->value); + } while ((field = field->next)) { newparam = convert_attribute_name_to_ldap(table_config, field->name); From dd3efdf52585cde5f0c6035268d16b9ba010ad5e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 20 Feb 2017 06:30:31 -0500 Subject: [PATCH 1056/1578] res_config_ldap: Fix configuration inheritance from _general The "_general" configuration section allows administrators to provide both general configuration options (host, port, url, etc.) as well as a global realtime-to-LDAP-attribute mapping that is a fallback if one of the later sections do not override it. This neglected to exclude the general configuration options from the mapping. As an example, during my testing, chan_sip requested 'port' from realtime, and because I did not have it defined, it pulled in the 'port' configuration option from "_general." We now filter those out explicitly. Change-Id: I1fc61560bf96b8ba623063cfb7e0a49c4690d778 --- res/res_config_ldap.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index a8a8fe696ae..9ad43295d59 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -1684,6 +1684,21 @@ static int reload(void) return 0; } +static int config_can_be_inherited(const char *key) +{ + int i; + static const char * const config[] = { + "basedn", "host", "pass", "port", "protocol", "url", "user", "version", NULL + }; + + for (i = 0; config[i]; i++) { + if (!strcasecmp(key, config[i])) { + return 0; + } + } + return 1; +} + /*! \brief parse the configuration file */ static int parse_config(void) @@ -1774,7 +1789,9 @@ static int parse_config(void) if (!strcasecmp(var->name, "additionalFilter")) { table_config->additional_filter = ast_strdup(var->value); } else { - ldap_table_config_add_attribute(table_config, var->name, var->value); + if (!is_general || config_can_be_inherited(var->name)) { + ldap_table_config_add_attribute(table_config, var->name, var->value); + } } } } From ef0944395ecc53eed8d469480a417fcb21afc252 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 20 Feb 2017 06:45:54 -0500 Subject: [PATCH 1057/1578] res_config_ldap: Make memory allocation more consistent The code in update_ldap() and update2_ldap() was using both Asterisk's memory allocation routines as well as OpenLDAP's. I've changed it so that everything that is passed to OpenLDAP's functions are allocated with their routines. Change-Id: Iafec9c1fd8ea49ccc496d6316769a6a426daa804 --- res/res_config_ldap.c | 81 +++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 9ad43295d59..5362e924920 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -422,7 +422,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf * value in \a variable_value; otherwise, we keep \a vars static and increase the length of the linked list of variables in the array element. * This memory must be freed outside of this function. */ - vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1); + vars = ast_calloc(tot_count + 1, sizeof(struct ast_variable *)); ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); @@ -926,13 +926,8 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p } } - if (filter) { - ast_free(filter); - } - - if (clean_basedn) { - ast_free(clean_basedn); - } + ast_free(filter); + ast_free(clean_basedn); ast_mutex_unlock(&ldap_lock); @@ -1136,7 +1131,7 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name * first, and since the data could easily exceed stack size, this is * allocated from the heap. */ - if (!(categories = ast_calloc(sizeof(*categories), vars_count))) { + if (!(categories = ast_calloc(vars_count, sizeof(*categories)))) { return NULL; } @@ -1290,7 +1285,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a } mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */ - ldap_mods = ldap_memcalloc(sizeof(LDAPMod *), mods_size); + ldap_mods = ldap_memcalloc(mods_size, sizeof(LDAPMod *)); ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod)); ldap_mods[0]->mod_type = ldap_strdup(newparam); @@ -1298,7 +1293,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a ldap_mods[0]->mod_op = LDAP_MOD_DELETE; } else { ldap_mods[0]->mod_op = LDAP_MOD_REPLACE; - ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2); + ldap_mods[0]->mod_values = ldap_memcalloc(2, sizeof(char *)); ldap_mods[0]->mod_values[0] = ldap_strdup(field->value); } @@ -1312,7 +1307,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2)); strcat(ldap_mods[i]->mod_values[0], ";"); strcat(ldap_mods[i]->mod_values[0], field->value); - mod_exists = 1; + mod_exists = 1; break; } } @@ -1321,22 +1316,19 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a if (!mod_exists) { mods_size++; ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size); - ldap_mods[mods_size - 1] = NULL; - ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod)); - - ldap_mods[mods_size - 2]->mod_type = ldap_memcalloc(sizeof(char), strlen(newparam) + 1); - strcpy(ldap_mods[mods_size - 2]->mod_type, newparam); + ldap_mods[mods_size - 2]->mod_type = ldap_strdup(newparam); if (strlen(field->value) == 0) { ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE; } else { ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE; - - ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(sizeof(char *), 2); - ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(field->value) + 1); - strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value); + ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(2, sizeof(char *)); + ldap_mods[mods_size - 2]->mod_values[0] = ldap_strdup(field->value); } + + /* NULL terminate */ + ldap_mods[mods_size - 1] = NULL; } } /* freeing ldap_mods further down */ @@ -1369,7 +1361,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a ast_free(filter); ast_free(clean_basedn); ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 0); + ldap_mods_free(ldap_mods, 1); return -1; } /* Ready to update */ @@ -1399,7 +1391,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a ast_free(filter); ast_free(clean_basedn); ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 0); + ldap_mods_free(ldap_mods, 1); return num_entries; } @@ -1479,16 +1471,12 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct } mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */ - ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size); - ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod)); - + ldap_mods = ldap_memcalloc(mods_size, sizeof(LDAPMod *)); + ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod)); ldap_mods[0]->mod_op = LDAP_MOD_REPLACE; - ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1); - strcpy(ldap_mods[0]->mod_type, newparam); - - ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2); - ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1); - strcpy(ldap_mods[0]->mod_values[0], field->value); + ldap_mods[0]->mod_type = ldap_strdup(newparam); + ldap_mods[0]->mod_values = ldap_memcalloc(2, sizeof(char *)); + ldap_mods[0]->mod_values[0] = ldap_strdup(field->value); while ((field = field->next)) { newparam = convert_attribute_name_to_ldap(table_config, field->name); @@ -1508,18 +1496,15 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct /* create new mod */ if (!mod_exists) { mods_size++; - ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size); - ldap_mods[mods_size - 1] = NULL; - ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod)); - + ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size); + ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod)); ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE; + ldap_mods[mods_size - 2]->mod_type = ldap_strdup(newparam); + ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(2, sizeof(char *)); + ldap_mods[mods_size - 2]->mod_values[0] = ldap_strdup(field->value); - ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1); - strcpy(ldap_mods[mods_size - 2]->mod_type, newparam); - - ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2); - ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1); - strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value); + /* NULL terminate */ + ldap_mods[mods_size - 1] = NULL; } } /* freeing ldap_mods further down */ @@ -1553,7 +1538,7 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct ast_free(filter); ast_free(clean_basedn); ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 0); + ldap_mods_free(ldap_mods, 1); return -1; } /* Ready to update */ @@ -1575,14 +1560,10 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct } ast_mutex_unlock(&ldap_lock); - if (filter) { - ast_free(filter); - } - if (clean_basedn) { - ast_free(clean_basedn); - } + ast_free(filter); + ast_free(clean_basedn); ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 0); + ldap_mods_free(ldap_mods, 1); return num_entries; } From 9f392574f933e4c2d4e5e6b11c6baf02e227630d Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 20 Feb 2017 06:49:17 -0500 Subject: [PATCH 1058/1578] res_config_ldap: Remove extraneous line numbers from log messages Extraneous line numbers were being output in many log messages. These have been removed. Change-Id: Ice9efa3d252ee87f37fa8f5ea852fda482675431 --- res/res_config_ldap.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 5362e924920..c1b61b4e28d 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -190,7 +190,7 @@ static int semicolon_count_var(struct ast_variable *var) return 0; } - ast_debug(2, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value); + ast_debug(2, "semicolon_count_var: %s\n", var_value->value); return semicolon_count_str(var_value->value); } @@ -330,7 +330,7 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config for (v = values; *v; v++) { value = *v; valptr = value->bv_val; - ast_debug(2, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, valptr); + ast_debug(2, "attribute_name: %s LDAP value: %s\n", attribute_name, valptr); if (is_realmed_password_attribute) { if (!strncasecmp(valptr, "{md5}", 5)) { valptr += 5; @@ -467,7 +467,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf delim_value = ast_strdup(valptr); if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) { - ast_debug(4, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value); + ast_debug(4, "is delimited %d times: %s\n", delim_tot_count, delim_value); is_delimited = 1; } } @@ -477,11 +477,11 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf /* for non-Static RealTime, first */ for (i = pos; !ast_strlen_zero(valptr + i); i++) { - ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i); + ast_debug(4, "DELIM pos: %d i: %d\n", pos, i); if (delim_value[i] == ';') { delim_value[i] = '\0'; - ast_debug(2, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos); + ast_debug(2, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos); if (prev) { prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name); @@ -499,9 +499,9 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf } } if (ast_strlen_zero(valptr + i)) { - ast_debug(4, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i, delim_count); + ast_debug(4, "DELIM pos: %d i: %d delim_count: %d\n", pos, i, delim_count); /* Last delimited value */ - ast_debug(4, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos); + ast_debug(4, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos); if (prev) { prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name); if (prev->next) { @@ -517,14 +517,14 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf ast_free(delim_value); delim_value = NULL; - ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i); + ast_debug(4, "DELIM pos: %d i: %d\n", pos, i); } else { /* not delimited */ if (delim_value) { ast_free(delim_value); delim_value = NULL; } - ast_debug(2, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, valptr); + ast_debug(2, "attribute_name: %s value: %s\n", attribute_name, valptr); if (prev) { prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name); @@ -548,7 +548,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf const struct ast_variable *tmpdebug = variable_named(var, "variable_name"); const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value"); if (tmpdebug && tmpdebug2) { - ast_debug(3, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value, tmpdebug2->value); + ast_debug(3, "Added to vars - %s = %s\n", tmpdebug->value, tmpdebug2->value); } } vars[entry_index++] = var; @@ -559,7 +559,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf } while (delim_count <= delim_tot_count && static_table_config == table_config); if (static_table_config != table_config) { - ast_debug(3, "LINE(%d) Added to vars - non static\n", __LINE__); + ast_debug(3, "Added to vars - non static\n"); vars[entry_index++] = var; prev = NULL; @@ -1244,7 +1244,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a } if (!attribute || !lookup) { - ast_log(LOG_WARNING, "LINE(%d): search parameters are empty.\n", __LINE__); + ast_log(LOG_WARNING, "Search parameters are empty.\n"); return -1; } ast_mutex_lock(&ldap_lock); @@ -1280,7 +1280,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a * one parameter/value pair and delimit them with a semicolon */ newparam = convert_attribute_name_to_ldap(table_config, field->name); if (!newparam) { - ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__); + ast_log(LOG_WARNING, "Need at least one parameter to modify.\n"); return -1; } @@ -1366,12 +1366,12 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a } /* Ready to update */ if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) { - ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries); + ast_debug(3, "Modifying %s=%s hits: %d\n", attribute, lookup, num_entries); for (i = 0; option_debug > 2 && i < mods_size - 1; i++) { if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) { - ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]); + ast_debug(3, "%s=%s\n", ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]); } else { - ast_debug(3, "LINE(%d) deleting %s \n", __LINE__, ldap_mods[i]->mod_type); + ast_debug(3, "deleting %s\n", ldap_mods[i]->mod_type); } } ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); @@ -1464,7 +1464,7 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct field = update_fields; newparam = convert_attribute_name_to_ldap(table_config, field->name); if (!newparam) { - ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__); + ast_log(LOG_WARNING, "Need at least one parameter to modify.\n"); ast_free(filter); ast_free(clean_basedn); return -1; @@ -1544,7 +1544,7 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct /* Ready to update */ if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) { for (i = 0; option_debug > 2 && i < mods_size - 1; i++) { - ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]); + ast_debug(3, "%s=%s\n", ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]); } ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); From e84353b8a8107b370d5e7ec9c9536642d877c8e8 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 20 Feb 2017 06:53:47 -0500 Subject: [PATCH 1059/1578] res_config_ldap: Don't try to delete non-existent attributes OpenLDAP will raise an error when we try to delete an LDAP attribute that doesn't exist. We need to filter out LDAP_MOD_DELETE requests based on which attributes the current LDAP entry actually has. There is of course a small window of opportunity for this to still fail, but it is much less likely now. Change-Id: I3fe1b04472733e43151563aaf9f8b49980273e6b --- res/res_config_ldap.c | 106 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index c1b61b4e28d..f6abe6379d0 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -1212,6 +1212,90 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name return cfg; } +/*! + * \internal + * \brief Remove LDAP_MOD_DELETE modifications that will not succeed + * + * \details + * A LDAP_MOD_DELETE operation will fail if the LDAP entry does not already have + * the corresponding attribute. Because we may be updating multiple LDAP entries + * in a single call to update_ldap(), we may need our own copy of the + * modifications array for each one. + * + * \note + * This function dynamically allocates memory. If it returns a non-NULL pointer, + * it is up to the caller to free it with ldap_mods_free() + * + * \returns an LDAPMod * if modifications needed to be removed, NULL otherwise. + */ +static LDAPMod **massage_mods_for_entry(LDAPMessage *entry, LDAPMod **mods, size_t count) +{ + size_t i; + int remove[count]; + size_t remove_count = 0; + + for (i = 0; i < count; i++) { + BerElement *ber = NULL; + char *attribute; + int exists = 0; + + if (mods[i]->mod_op != LDAP_MOD_DELETE) { + continue; + } + + /* If we are deleting something, it has to exist */ + attribute = ldap_first_attribute(ldapConn, entry, &ber); + while (attribute) { + if (!strcasecmp(attribute, mods[i]->mod_type)) { + /* OK, we have the attribute */ + exists = 1; + ldap_memfree(attribute); + break; + } + + ldap_memfree(attribute); + attribute = ldap_next_attribute(ldapConn, entry, ber); + } + + if (!exists) { + remove[remove_count++] = i; + } + } + + if (remove_count) { + size_t k, remove_index; + LDAPMod **x = ldap_memcalloc(count - remove_count + 1, sizeof(LDAPMod *)); + for (i = 0, k = 0; i < count; i++) { + int skip = 0; + /* Is this one we have to remove? */ + for (remove_index = 0; !skip && remove_index < remove_count; remove_index++) { + skip = (remove[remove_index] == i); + } + + if (skip) { + ast_debug(3, "Skipping %s deletion because it doesn't exist\n", + mods[i]->mod_type); + continue; + } + + x[k] = ldap_memcalloc(1, sizeof(LDAPMod)); + x[k]->mod_op = mods[i]->mod_op; + x[k]->mod_type = ldap_strdup(mods[i]->mod_type); + if (mods[i]->mod_values) { + x[k]->mod_values = ldap_memcalloc(2, sizeof(char *)); + x[k]->mod_values[0] = ldap_strdup(mods[i]->mod_values[0]); + } + k++; + } + /* NULL terminate */ + x[k] = NULL; + return x; + } + + return NULL; +} + + /* \brief Function to update a set of values in ldap static mode */ static int update_ldap(const char *basedn, const char *table_name, const char *attribute, @@ -1376,12 +1460,30 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a } ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); - for (i = 0; ldap_entry; i++) { + for (i = 0; ldap_entry; i++) { + LDAPMod **working = ldap_mods; + LDAPMod **massaged = massage_mods_for_entry(ldap_entry, ldap_mods, mods_size - 1); + + if (massaged) { + /* Did we massage everything out of the list? */ + if (massaged[0] == NULL) { + ast_debug(3, "Nothing left to modify - skipping\n"); + ldap_mods_free(massaged, 1); + continue; + } + working = massaged; + } + dn = ldap_get_dn(ldapConn, ldap_entry); - if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) { + if ((error = ldap_modify_ext_s(ldapConn, dn, working, NULL, NULL)) != LDAP_SUCCESS) { ast_log(LOG_ERROR, "Couldn't modify '%s'='%s', dn:%s because %s\n", attribute, lookup, dn, ldap_err2string(error)); } + + if (massaged) { + ldap_mods_free(massaged, 1); + } + ldap_memfree(dn); ldap_entry = ldap_next_entry(ldapConn, ldap_entry); } From ffa7d697661ac37879f438841ae9af057b2baa55 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 20 Feb 2017 07:04:25 -0700 Subject: [PATCH 1060/1578] pjproject cli: Add object count after object lists When listing a container, we now print the number of objects in the container at the end of the list. Change-Id: I791cbc3ee9da9a2af9adc655164b5d32953df812 --- res/res_pjsip/pjsip_cli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/res_pjsip/pjsip_cli.c b/res/res_pjsip/pjsip_cli.c index e6433f43587..56ec191edd1 100644 --- a/res/res_pjsip/pjsip_cli.c +++ b/res/res_pjsip/pjsip_cli.c @@ -221,6 +221,8 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_ return CLI_SUCCESS; } ao2_callback(container, OBJ_NODATA, formatter_entry->print_body, &context); + ast_str_append(&context.output_buffer, 0, "\nObjects found: %d\n", ao2_container_count(container)); + } else { if (ast_strlen_zero(object_id)) { ast_free(context.output_buffer); From 7739b0b3aebcbec892f954650d7406013f4b622f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 20 Feb 2017 11:19:55 -0600 Subject: [PATCH 1061/1578] Revert "build: Execute ldconfig to build cache." This reverts commit 8851c3e0885cb704a5a6159a51768ea5297e9b10. Change-Id: I124380be5e3bd57da978428a2a93604336ccd0db --- main/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/Makefile b/main/Makefile index 331da845c81..4d1b2c41bd2 100644 --- a/main/Makefile +++ b/main/Makefile @@ -355,7 +355,7 @@ else # Darwin endif endif ifneq ($(LDCONFIG),) - $(LDCONFIG) + $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" endif $(LN) -sf asterisk "$(DESTDIR)$(ASTSBINDIR)/rasterisk" @@ -373,7 +373,7 @@ ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" endif ifneq ($(LDCONFIG),) - $(LDCONFIG) + $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" endif clean:: From b18f1bfb13a9cd20ea16d07d8ed78e2669282cc4 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 20 Feb 2017 07:28:23 -0500 Subject: [PATCH 1062/1578] app_voicemail: vm_authenticate accesses uninitialized memory vm_authenticate doesn't always set the passed ast_vm_user argument, so we initialize to 0 before passing it in. ASTERISK-25893 #close Reported by: Filip Jenicek Change-Id: Ia3cc0128f93d352ed9add8d5c2f0f7232c2cbe4a --- apps/app_voicemail.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 91e81042942..1d7ffc042a4 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -11190,7 +11190,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ return -1; } if (vmu && !skipuser) { - memcpy(res_vmu, vmu, sizeof(struct ast_vm_user)); + *res_vmu = *vmu; } return 0; } @@ -11352,8 +11352,8 @@ static int vm_execmain(struct ast_channel *chan, const char *data) int box; int useadsi = 0; int skipuser = 0; - struct vm_state vms; - struct ast_vm_user *vmu = NULL, vmus; + struct vm_state vms = {{0}}; + struct ast_vm_user *vmu = NULL, vmus = {{0}}; char *context = NULL; int silentexit = 0; struct ast_flags flags = { 0 }; @@ -11366,12 +11366,8 @@ static int vm_execmain(struct ast_channel *chan, const char *data) #endif /* Add the vm_state to the active list and keep it active */ - memset(&vms, 0, sizeof(vms)); - vms.lastmsg = -1; - memset(&vmus, 0, sizeof(vmus)); - ast_test_suite_event_notify("START", "Message: vm_execmain started"); if (ast_channel_state(chan) != AST_STATE_UP) { ast_debug(1, "Before ast_answer\n"); @@ -12664,7 +12660,7 @@ static struct ast_custom_function vm_info_acf = { static int vmauthenticate(struct ast_channel *chan, const char *data) { char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = ""; - struct ast_vm_user vmus; + struct ast_vm_user vmus = {{0}}; char *options = NULL; int silent = 0, skipuser = 0; int res = -1; From 54812f18b5b55fb4d3349b0a8776c1c508e5c83b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 6 Feb 2017 14:26:30 -0600 Subject: [PATCH 1063/1578] pjsip_distributor.c: Update some debug messages to get transaction name. * Removed overloaded unmatched response ignore. We obviously sent the request so we shouldn't ignore it because it isn't new work. ASTERISK-26669 ASTERISK-26738 Change-Id: I55fb5cadc83a8e6699b347c6dc7fa32c5a617d37 --- res/res_pjsip/pjsip_distributor.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index eabfa4ba9c0..39d31651e7c 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -120,12 +120,12 @@ static struct ast_taskprocessor *find_request_serializer(pjsip_rx_data *rdata) tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); if (!tsx) { - ast_debug(1, "Could not find %.*s transaction for %d response.\n", - (int) pj_strlen(&rdata->msg_info.cseq->method.name), - pj_strbuf(&rdata->msg_info.cseq->method.name), - rdata->msg_info.msg->line.status.code); + ast_debug(1, "Could not find transaction for %s.\n", + pjsip_rx_data_get_info(rdata)); return NULL; } + ast_debug(3, "Found transaction %s for %s.\n", + tsx->obj_name, pjsip_rx_data_get_info(rdata)); if (tsx->last_tx) { const char *serializer_name; @@ -402,21 +402,14 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) if (serializer) { /* We have a serializer so we know where to send the message. */ } else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) { - ast_debug(3, "No dialog serializer for response %s. Using request transaction as basis\n", + ast_debug(3, "No dialog serializer for %s. Using request transaction as basis.\n", pjsip_rx_data_get_info(rdata)); serializer = find_request_serializer(rdata); if (!serializer) { - if (ast_taskprocessor_alert_get()) { - /* We're overloaded, ignore the unmatched response. */ - ast_debug(3, "Taskprocessor overload alert: Ignoring unmatched '%s'.\n", - pjsip_rx_data_get_info(rdata)); - return PJ_TRUE; - } - /* - * Pick a serializer for the unmatched response. Maybe - * the stack can figure out what it is for, or we really - * should just toss it regardless. + * Pick a serializer for the unmatched response. + * We couldn't determine what serializer originally + * sent the request or the serializer is gone. */ serializer = ast_sip_get_distributor_serializer(rdata); } @@ -760,7 +753,7 @@ static int distribute(void *data) .start_mod = &distributor_mod, .idx_after_start = 1, }; - pj_bool_t handled; + pj_bool_t handled = PJ_FALSE; pjsip_rx_data *rdata = data; int is_request = rdata->msg_info.msg->type == PJSIP_REQUEST_MSG; int is_ack = is_request ? rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD : 0; From bf78c3c9c38ca07c39c65e4c34669061b899ae0a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 20 Feb 2017 13:38:58 -0600 Subject: [PATCH 1064/1578] pjproject: Increase SENDER_WIDTH column size for 64-bit system logs. ASTERISK-26669 ASTERISK-26738 Change-Id: Ibae6fc8cae69a1f04df0c577c4c11200499d6fe0 --- ...rt-Increase-SENDER_WIDTH-column-size.patch | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 third-party/pjproject/patches/0011-r5554-svn-backport-Increase-SENDER_WIDTH-column-size.patch diff --git a/third-party/pjproject/patches/0011-r5554-svn-backport-Increase-SENDER_WIDTH-column-size.patch b/third-party/pjproject/patches/0011-r5554-svn-backport-Increase-SENDER_WIDTH-column-size.patch new file mode 100644 index 00000000000..4c53337a314 --- /dev/null +++ b/third-party/pjproject/patches/0011-r5554-svn-backport-Increase-SENDER_WIDTH-column-size.patch @@ -0,0 +1,77 @@ +From df1ceb301c8a17969c467e3cf00246cfc28d1732 Mon Sep 17 00:00:00 2001 +From: Richard Mudgett +Date: Mon, 20 Feb 2017 12:19:05 -0600 +Subject: [PATCH 1/5] r5554 svn backport Increase SENDER_WIDTH column size for + 64-bit systems. + +Re #1994 (misc): Make the log's sender and thread width a compile-time configurable setting. + +Thanks to Richard Mudgett for the suggestion. +--- + pjlib/include/pj/config.h | 27 +++++++++++++++++++++++++++ + pjlib/src/pj/log.c | 4 ++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h +index 079d69b..3523f50 100644 +--- a/pjlib/include/pj/config.h ++++ b/pjlib/include/pj/config.h +@@ -442,6 +442,33 @@ + #endif + + /** ++ * Log sender width. ++ * ++ * Default: 22 (for 64-bit machines), 14 otherwise ++ */ ++#ifndef PJ_LOG_SENDER_WIDTH ++# if PJ_HAS_STDINT_H ++# include ++# if (UINTPTR_MAX == 0xffffffffffffffff) ++# define PJ_LOG_SENDER_WIDTH 22 ++# else ++# define PJ_LOG_SENDER_WIDTH 14 ++# endif ++# else ++# define PJ_LOG_SENDER_WIDTH 14 ++# endif ++#endif ++ ++/** ++ * Log thread name width. ++ * ++ * Default: 12 ++ */ ++#ifndef PJ_LOG_THREAD_WIDTH ++# define PJ_LOG_THREAD_WIDTH 12 ++#endif ++ ++/** + * Colorfull terminal (for logging etc). + * + * Default: 1 +diff --git a/pjlib/src/pj/log.c b/pjlib/src/pj/log.c +index 293ad46..cf7ac37 100644 +--- a/pjlib/src/pj/log.c ++++ b/pjlib/src/pj/log.c +@@ -380,7 +380,7 @@ PJ_DEF(void) pj_log( const char *sender, int level, + pre += pj_utoa_pad(ptime.msec, pre, 3, '0'); + } + if (log_decor & PJ_LOG_HAS_SENDER) { +- enum { SENDER_WIDTH = 14 }; ++ enum { SENDER_WIDTH = PJ_LOG_SENDER_WIDTH }; + pj_size_t sender_len = strlen(sender); + if (pre!=log_buffer) *pre++ = ' '; + if (sender_len <= SENDER_WIDTH) { +@@ -395,7 +395,7 @@ PJ_DEF(void) pj_log( const char *sender, int level, + } + } + if (log_decor & PJ_LOG_HAS_THREAD_ID) { +- enum { THREAD_WIDTH = 12 }; ++ enum { THREAD_WIDTH = PJ_LOG_THREAD_WIDTH }; + const char *thread_name = pj_thread_get_name(pj_thread_this()); + pj_size_t thread_len = strlen(thread_name); + *pre++ = ' '; +-- +2.7.4 + From 7f83bcd63d63763e9bae5142b218665c21a33c6b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 13 Feb 2017 17:11:06 -0600 Subject: [PATCH 1065/1578] pjproject: Fixes to resolve DNS SRV crashes. * Re #1945 (misc): Don't trigger SRV complete callback when there is a parse error. * srv_resolver.c: Don't try to send query if already considered resolved. ** In resolve_hostnames() don't try to resolve a query that is already considered resolved. ** In resolve_hostnames() fix DNS typo in comments. ** In build_server_entries() move a common expression assigning to cnt earlier. * sip_transport.c: Fix tdata object name to actually contain the pointer. It helps if the logs referencing a tdata object buffer actually have a name that includes the correct pointer as part of the name. Also since the tdata has its own pool it helps if any logs referencing the pool have the same name as the tdata object. This change brings tdata logging in line with how tsx objects are named. ASTERISK-26669 #close ASTERISK-26738 #close Change-Id: I56af2ded25476b3e870ca586ee69ed6954ef75af --- ...-t-trigger-SRV-complete-callback-whe.patch | 59 +++++++++ ...kport-Fix-to-resolve-DNS-SRV-crashes.patch | 112 ++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch create mode 100644 third-party/pjproject/patches/0013-r5559-svn-backport-Fix-to-resolve-DNS-SRV-crashes.patch diff --git a/third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch b/third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch new file mode 100644 index 00000000000..e65556f22bd --- /dev/null +++ b/third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch @@ -0,0 +1,59 @@ +From 783de8956190c47a70ffefed56a1a2b21a62b235 Mon Sep 17 00:00:00 2001 +From: Riza Sulistyo +Date: Mon, 23 Jan 2017 01:34:12 +0000 +Subject: [PATCH 2/5] Re #1945 (misc): Don't trigger SRV complete callback when + there is a parse error. + +git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@5536 74dad513-b988-da41-8d7b-12977e46ad98 +--- + pjlib-util/src/pjlib-util/srv_resolver.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/pjlib-util/src/pjlib-util/srv_resolver.c b/pjlib-util/src/pjlib-util/srv_resolver.c +index 8a4a599..8a2f7e1 100644 +--- a/pjlib-util/src/pjlib-util/srv_resolver.c ++++ b/pjlib-util/src/pjlib-util/srv_resolver.c +@@ -652,6 +652,7 @@ static void dns_callback(void *user_data, + + } else if (query_job->dns_state == PJ_DNS_TYPE_A) { + pj_bool_t is_type_a, srv_completed; ++ pj_dns_addr_record rec; + + /* Clear outstanding job */ + if (common->type == PJ_DNS_TYPE_A) { +@@ -668,15 +669,26 @@ static void dns_callback(void *user_data, + + is_type_a = (common->type == PJ_DNS_TYPE_A); + ++ /* Parse response */ ++ if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) { ++ status = pj_dns_parse_addr_response(pkt, &rec); ++ if (status!=PJ_SUCCESS) { ++ char errmsg[PJ_ERR_MSG_SIZE]; ++ ++ PJ_LOG(4,(query_job->objname, ++ "DNS %s record parse error for '%.*s'." ++ " Err=%d (%s)", ++ (is_type_a ? "A" : "AAAA"), ++ (int)query_job->domain_part.slen, ++ query_job->domain_part.ptr, ++ status, ++ pj_strerror(status,errmsg,sizeof(errmsg)).ptr)); ++ } ++ } ++ + /* Check that we really have answer */ + if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) { + char addr[PJ_INET6_ADDRSTRLEN]; +- pj_dns_addr_record rec; +- +- /* Parse response */ +- status = pj_dns_parse_addr_response(pkt, &rec); +- if (status != PJ_SUCCESS) +- goto on_error; + + pj_assert(rec.addr_count != 0); + +-- +2.7.4 + diff --git a/third-party/pjproject/patches/0013-r5559-svn-backport-Fix-to-resolve-DNS-SRV-crashes.patch b/third-party/pjproject/patches/0013-r5559-svn-backport-Fix-to-resolve-DNS-SRV-crashes.patch new file mode 100644 index 00000000000..dc03cbc209b --- /dev/null +++ b/third-party/pjproject/patches/0013-r5559-svn-backport-Fix-to-resolve-DNS-SRV-crashes.patch @@ -0,0 +1,112 @@ +From d9d52f005f6d0242ea84e7c59ad6b25f052c8485 Mon Sep 17 00:00:00 2001 +From: Richard Mudgett +Date: Mon, 20 Feb 2017 12:05:32 -0600 +Subject: [PATCH 3/5] r5559 svn backport Fix to resolve DNS SRV crashes. + +Re #1994 (misc): Don't try to resolve a DNS SRV query that is already considered resolved. +Thanks to Richard Mudgett for the patch. + +srv_resolver.c: Don't try to send query if already considered resolved. + +* In resolve_hostnames() don't try to resolve a query that is already +considered resolved. + +* In resolve_hostnames() fix DNS typo in comments. + +* In build_server_entries() move a common expression assigning to cnt +earlier. + +sip_transport.c: Fix tdata object name to actually contain the pointer. + +It helps if the logs referencing a tdata object buffer actually have +a name that includes the correct pointer as part of the name. Also +since the tdata has its own pool it helps if any logs referencing the +pool have the same name as the tdata object. This change brings tdata +logging in line with how tsx objects are named. +--- + pjlib-util/src/pjlib-util/srv_resolver.c | 18 +++++++++++++----- + pjsip/src/pjsip/sip_transport.c | 3 ++- + 2 files changed, 15 insertions(+), 6 deletions(-) + +diff --git a/pjlib-util/src/pjlib-util/srv_resolver.c b/pjlib-util/src/pjlib-util/srv_resolver.c +index 8a2f7e1..84ad3f6 100644 +--- a/pjlib-util/src/pjlib-util/srv_resolver.c ++++ b/pjlib-util/src/pjlib-util/srv_resolver.c +@@ -407,8 +407,9 @@ static void build_server_entries(pj_dns_srv_async_query *query_job, + for (i=0; isrv_cnt; ++i) { + pj_in_addr addr; + pj_in6_addr addr6; ++ unsigned cnt = query_job->srv[i].addr_cnt; + +- if (query_job->srv[i].addr_cnt != 0) { ++ if (cnt != 0) { + /* IP address already resolved */ + continue; + } +@@ -417,7 +418,6 @@ static void build_server_entries(pj_dns_srv_async_query *query_job, + pj_inet_pton(pj_AF_INET(), &query_job->srv[i].target_name, + &addr) == PJ_SUCCESS) + { +- unsigned cnt = query_job->srv[i].addr_cnt; + pj_sockaddr_init(pj_AF_INET(), &query_job->srv[i].addr[cnt], + NULL, query_job->srv[i].port); + query_job->srv[i].addr[cnt].ipv4.sin_addr = addr; +@@ -427,7 +427,6 @@ static void build_server_entries(pj_dns_srv_async_query *query_job, + pj_inet_pton(pj_AF_INET6(), &query_job->srv[i].target_name, + &addr6) == PJ_SUCCESS) + { +- unsigned cnt = query_job->srv[i].addr_cnt; + pj_sockaddr_init(pj_AF_INET6(), &query_job->srv[i].addr[cnt], + NULL, query_job->srv[i].port); + query_job->srv[i].addr[cnt].ipv6.sin6_addr = addr6; +@@ -480,6 +479,15 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job) + for (i=0; isrv_cnt; ++i) { + struct srv_target *srv = &query_job->srv[i]; + ++ if (srv->addr_cnt != 0) { ++ /* ++ * This query is already counted as resolved because of the ++ * additional records in the SRV response or the target name ++ * is an IP address exception in build_server_entries(). ++ */ ++ continue; ++ } ++ + PJ_LOG(5, (query_job->objname, + "Starting async DNS A query_job for %.*s", + (int)srv->target_name.slen, +@@ -493,7 +501,7 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job) + + status = PJ_SUCCESS; + +- /* Start DNA A record query */ ++ /* Start DNS A record query */ + if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY) == 0) + { + if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0) { +@@ -511,7 +519,7 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job) + &srv->common, &srv->q_a); + } + +- /* Start DNA AAAA record query */ ++ /* Start DNS AAAA record query */ + if (status == PJ_SUCCESS && + (query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0) + { +diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c +index d672a6d..6dd14d1 100644 +--- a/pjsip/src/pjsip/sip_transport.c ++++ b/pjsip/src/pjsip/sip_transport.c +@@ -422,7 +422,8 @@ PJ_DEF(pj_status_t) pjsip_tx_data_create( pjsip_tpmgr *mgr, + tdata = PJ_POOL_ZALLOC_T(pool, pjsip_tx_data); + tdata->pool = pool; + tdata->mgr = mgr; +- pj_memcpy(tdata->obj_name, pool->obj_name, PJ_MAX_OBJ_NAME); ++ pj_ansi_snprintf(tdata->obj_name, sizeof(tdata->obj_name), "tdta%p", tdata); ++ pj_memcpy(pool->obj_name, tdata->obj_name, sizeof(pool->obj_name)); + + status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt); + if (status != PJ_SUCCESS) { +-- +2.7.4 + From 0b660c99897228bf7c786ce9d52ac43e302c3745 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sun, 1 Jan 2017 08:02:17 -0600 Subject: [PATCH 1066/1578] res_pjsip: Update authentication realm documentation. Using the same auth section for inbound and outbound authentication is not recommended. There is a difference in meaning for an empty realm setting between inbound and outbound authentication uses. An empty inbound auth realm represents the global section's default_realm value when the authentication object is used to challenge an incoming request. An empty outgoing auth realm is treated as a don't care wildcard when the authentication object is used to respond to an incoming authentication challenge. ASTERISK-26799 Change-Id: Id3952f7cfa1b6683b9954f2c5d2352d2f11059ce --- configs/samples/pjsip.conf.sample | 20 +++++++++-- res/res_pjsip.c | 51 +++++++++++++++++++++++---- res/res_pjsip_outbound_publish.c | 13 ++++++- res/res_pjsip_outbound_registration.c | 13 ++++++- 4 files changed, 86 insertions(+), 11 deletions(-) diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 6595423c990..323100b00fb 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -12,6 +12,12 @@ ; If you want to see more detail please check the documentation sources ; mentioned at the top of this file. +; ============================================================================ +; NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE +; +; This file does not maintain the complete option documentation. +; ============================================================================ + ; Documentation ; ; The official documentation is at http://wiki.asterisk.org @@ -765,6 +771,14 @@ ;==========================AUTH SECTION OPTIONS========================= ;[auth] ; SYNOPSIS: Authentication type +; +; Note: Using the same auth section for inbound and outbound +; authentication is not recommended. There is a difference in +; meaning for an empty realm setting between inbound and outbound +; authentication uses. Look to the CLI config help +; "config show help res_pjsip auth realm" or on the wiki for the +; difference. +; ;auth_type=userpass ; Authentication type (default: "userpass") ;nonce_lifetime=32 ; Lifetime of a nonce associated with this ; authentication config (default: "32") @@ -959,9 +973,9 @@ ; From header username will be set to this value if ; there is no better option (such as CallerID or ; endpoint/from_user) to be used -;default_realm=asterisk ; When Asterisk generates a challenge, the realm will be - ; set to this value if there is no better option (such as - ; auth/realm) to be used +;default_realm=asterisk ; When Asterisk generates a challenge, the digest realm + ; will be set to this value if there is no better option + ; (such as auth/realm) to be used. ; Asterisk Task Processor Queue Size ; On heavy loaded system with DB storage you may need to increase diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 90eb37263cf..4dead21f5bb 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -112,9 +112,15 @@ This is a comma-delimited list of auth sections defined in pjsip.conf to be used to verify inbound connection attempts. - Endpoints without an authentication object - configured will allow connections without vertification. - + Endpoints without an authentication object + configured will allow connections without verification. + + Using the same auth section for inbound and outbound + authentication is not recommended. There is a difference in + meaning for an empty realm setting between inbound and outbound + authentication uses. See the auth realm description for details. + + CallerID information for the endpoint @@ -329,7 +335,18 @@ Default Music On Hold class - Authentication object used for outbound requests + Authentication object(s) used for outbound requests + + This is a comma-delimited list of auth + sections defined in pjsip.conf used to respond + to outbound connection authentication challenges. + + Using the same auth section for inbound and outbound + authentication is not recommended. There is a difference in + meaning for an empty realm setting between inbound and outbound + authentication uses. See the auth realm description for details. + + Proxy through which to send requests, a full SIP URI must be provided @@ -967,8 +984,30 @@ PlainText password used for authentication. Only used when auth_type is userpass. - + SIP realm for endpoint + + The treatment of this value depends upon how the authentication + object is used. + + When used as an inbound authentication object, the realm is sent + as part of the challenge so the peer can know which key to use + when responding. An empty value will use the + global section's + default_realm value when issuing a challenge. + + When used as an outbound authentication object, the realm is + matched with the received challenge realm to determine which + authentication object to use when responding to the challenge. An + empty value matches any challenging realm when determining + which authentication object matches a received challenge. + + + Using the same auth section for inbound and outbound + authentication is not recommended. There is a difference in + meaning for an empty realm setting between inbound and outbound + authentication uses. + Must be 'auth' @@ -1512,7 +1551,7 @@ used. - When Asterisk generates an challenge, the digest will be + When Asterisk generates a challenge, the digest realm will be set to this value if there is no better option (such as auth/realm) to be used. diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 87680480c8f..53eb6aca78a 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -55,7 +55,18 @@ Expiration time for publications in seconds - Authentication object to be used for outbound publishes. + Authentication object(s) to be used for outbound publishes. + + This is a comma-delimited list of auth + sections defined in pjsip.conf used to respond + to outbound authentication challenges. + + Using the same auth section for inbound and outbound + authentication is not recommended. There is a difference in + meaning for an empty realm setting between inbound and outbound + authentication uses. See the auth realm description for details. + + SIP URI of the outbound proxy used to send publishes diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index d486ccd639d..137f3a83287 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -82,7 +82,18 @@ Maximum number of registration attempts. - Authentication object to be used for outbound registrations. + Authentication object(s) to be used for outbound registrations. + + This is a comma-delimited list of auth + sections defined in pjsip.conf used to respond + to outbound authentication challenges. + + Using the same auth section for inbound and outbound + authentication is not recommended. There is a difference in + meaning for an empty realm setting between inbound and outbound + authentication uses. See the auth realm description for details. + + Outbound Proxy used to send registrations From 6400f5f309a47e66b94c9befecd862ccd2b73aee Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sat, 4 Feb 2017 20:17:36 -0600 Subject: [PATCH 1067/1578] res_pjsip: Update artificial auth whenever default_realm changes. There was code attempting to update the artificial authentication object whenever the default_realm changed. However, once the artificial authentication object was created it would never get updated. The artificial authentication object would require a system restart for a change to the default_realm to take effect. ASTERISK-26799 Change-Id: Id59036e9529c2d3ed728af2ed904dc36e7094802 --- res/res_pjsip/pjsip_distributor.c | 84 ++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index eabfa4ba9c0..d043063bf82 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -43,7 +43,6 @@ struct ast_sched_context *prune_context; /* From the auth/realm realtime column size */ #define MAX_REALM_LENGTH 40 -static char default_realm[MAX_REALM_LENGTH + 1]; #define DEFAULT_SUSPECTS_BUCKETS 53 @@ -462,35 +461,54 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) return PJ_TRUE; } -static struct ast_sip_auth *artificial_auth; +static struct ast_sip_auth *alloc_artificial_auth(char *default_realm) +{ + struct ast_sip_auth *fake_auth; + + fake_auth = ast_sorcery_alloc(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, + "artificial"); + if (!fake_auth) { + return NULL; + } + + ast_string_field_set(fake_auth, realm, default_realm); + ast_string_field_set(fake_auth, auth_user, ""); + ast_string_field_set(fake_auth, auth_pass, ""); + fake_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL; + + return fake_auth; +} + +static AO2_GLOBAL_OBJ_STATIC(artificial_auth); static int create_artificial_auth(void) { - if (!(artificial_auth = ast_sorcery_alloc( - ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, "artificial"))) { + char default_realm[MAX_REALM_LENGTH + 1]; + struct ast_sip_auth *fake_auth; + + ast_sip_get_default_realm(default_realm, sizeof(default_realm)); + fake_auth = alloc_artificial_auth(default_realm); + if (!fake_auth) { ast_log(LOG_ERROR, "Unable to create artificial auth\n"); return -1; } - ast_string_field_set(artificial_auth, realm, default_realm); - ast_string_field_set(artificial_auth, auth_user, ""); - ast_string_field_set(artificial_auth, auth_pass, ""); - artificial_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL; + ao2_global_obj_replace_unref(artificial_auth, fake_auth); + ao2_ref(fake_auth, -1); return 0; } struct ast_sip_auth *ast_sip_get_artificial_auth(void) { - ao2_ref(artificial_auth, +1); - return artificial_auth; + return ao2_global_obj_ref(artificial_auth); } static struct ast_sip_endpoint *artificial_endpoint = NULL; static int create_artificial_endpoint(void) { - if (!(artificial_endpoint = ast_sorcery_alloc( - ast_sip_get_sorcery(), "endpoint", NULL))) { + artificial_endpoint = ast_sorcery_alloc(ast_sip_get_sorcery(), "endpoint", NULL); + if (!artificial_endpoint) { return -1; } @@ -968,20 +986,40 @@ static int clean_task(const void *data) static void global_loaded(const char *object_type) { - char *identifier_order = ast_sip_get_endpoint_identifier_order(); - char *io_copy = identifier_order ? ast_strdupa(identifier_order) : NULL; - char *identify_method; - - ast_free(identifier_order); - using_auth_username = 0; - while ((identify_method = ast_strip(strsep(&io_copy, ",")))) { - if (!strcmp(identify_method, "auth_username")) { - using_auth_username = 1; - break; + char default_realm[MAX_REALM_LENGTH + 1]; + struct ast_sip_auth *fake_auth; + char *identifier_order; + + /* Update using_auth_username */ + identifier_order = ast_sip_get_endpoint_identifier_order(); + if (identifier_order) { + char *identify_method; + char *io_copy = ast_strdupa(identifier_order); + int new_using = 0; + + ast_free(identifier_order); + while ((identify_method = ast_strip(strsep(&io_copy, ",")))) { + if (!strcmp(identify_method, "auth_username")) { + new_using = 1; + break; + } } + using_auth_username = new_using; } + /* Update default_realm of artificial_auth */ ast_sip_get_default_realm(default_realm, sizeof(default_realm)); + fake_auth = ast_sip_get_artificial_auth(); + if (!fake_auth || strcmp(fake_auth->realm, default_realm)) { + ao2_cleanup(fake_auth); + + fake_auth = alloc_artificial_auth(default_realm); + if (fake_auth) { + ao2_global_obj_replace_unref(artificial_auth, fake_auth); + ao2_ref(fake_auth, -1); + } + } + ast_sip_get_unidentified_request_thresholds(&unidentified_count, &unidentified_period, &unidentified_prune_interval); /* Clean out the old task, if any */ @@ -1114,7 +1152,7 @@ void ast_sip_destroy_distributor(void) internal_sip_unregister_service(&endpoint_mod); internal_sip_unregister_service(&distributor_mod); - ao2_cleanup(artificial_auth); + ao2_global_obj_release(artificial_auth); ao2_cleanup(artificial_endpoint); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer); From 6f15500ced186fa9a3fc50404c93903953018164 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sun, 8 Jan 2017 20:32:17 -0600 Subject: [PATCH 1068/1578] res_pjsip_authenticator_digest.c: Fix sorcery's immutable contract violation. The inbound authentication object is supposed to be immutable when it is stored in sorcery. However, the immutable property is violated if the authentication object does not have a realm set. The immutable contract violation has a different effect depending upon what sorcery back end is used. If it is the config file back end you would get the same object back until res_pjsip is reloaded. If it is the real-time or AstDB back end you would get a new object on each query. If it is cached you would get the same object back until it is refreshed from the database. Once an inbound authentication object has its realm set it may or may not get updated again if the default_realm changes. If the same authentication object is used for inbound and outbound authentication then the immutable violation can make it very hard to determine why the outbound authentication now fails. The only diagnostic message is a complaint about no realms matching when it had worked earlier. It fails because of the difference in behaviour for an empty realm setting between inbound and outbound authentication objects. * Fixed the sorcery object immutable violation by creating a new object and setting the default_realm on it instead. The new object is a shallow copy for speed. * The auth_store thread storage no longer holds an auth ref. It interferes with the shallow copy and never needed a ref anyway. ASTERISK-26799 #close Change-Id: I2328a52f61b78ed5fbba38180b7f183ee7e08956 --- res/res_pjsip_authenticator_digest.c | 105 +++++++++++++++++++-------- 1 file changed, 73 insertions(+), 32 deletions(-) diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c index 4bc35c5ff6b..ef57e3754ef 100644 --- a/res/res_pjsip_authenticator_digest.c +++ b/res/res_pjsip_authenticator_digest.c @@ -87,46 +87,46 @@ static void auth_store_cleanup(void *data) AST_THREADSTORAGE_CUSTOM(auth_store, NULL, auth_store_cleanup); /*! - * \brief Store authentication information in thread-local storage + * \brief Store shallow copy authentication information in thread-local storage */ -static int store_auth(struct ast_sip_auth *auth) +static int store_auth(const struct ast_sip_auth *auth) { - struct ast_sip_auth **pointing; + const struct ast_sip_auth **pointing; + pointing = ast_threadstorage_get(&auth_store, sizeof(pointing)); - if (!pointing || *pointing) { + if (!pointing) { return -1; } - ao2_ref(auth, +1); *pointing = auth; return 0; } /*! - * \brief Remove authentication information from thread-local storage + * \brief Remove shallow copy authentication information from thread-local storage */ static int remove_auth(void) { struct ast_sip_auth **pointing; + pointing = ast_threadstorage_get(&auth_store, sizeof(pointing)); if (!pointing) { return -1; } - ao2_cleanup(*pointing); *pointing = NULL; return 0; } /*! - * \brief Retrieve authentication information from thread-local storage + * \brief Retrieve shallow copy authentication information from thread-local storage */ -static struct ast_sip_auth *get_auth(void) +static const struct ast_sip_auth *get_auth(void) { struct ast_sip_auth **auth; + auth = ast_threadstorage_get(&auth_store, sizeof(auth)); - if (auth && *auth) { - ao2_ref(*auth, +1); + if (auth) { return *auth; } return NULL; @@ -150,7 +150,9 @@ static struct ast_sip_auth *get_auth(void) static pj_status_t digest_lookup(pj_pool_t *pool, const pj_str_t *realm, const pj_str_t *acc_name, pjsip_cred_info *info) { - RAII_VAR(struct ast_sip_auth *, auth, get_auth(), ao2_cleanup); + const struct ast_sip_auth *auth; + + auth = get_auth(); if (!auth) { return PJSIP_SC_FORBIDDEN; } @@ -312,7 +314,7 @@ enum digest_verify_result { * \return CMP_MATCH on successful authentication * \return 0 on failed authentication */ -static int verify(struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool) +static int verify(const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool) { pj_status_t authed; int response_code; @@ -329,9 +331,7 @@ static int verify(struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *po setup_auth_srv(pool, &auth_server, auth->realm); store_auth(auth); - authed = pjsip_auth_srv_verify(&auth_server, rdata, &response_code); - remove_auth(); if (authed == PJ_SUCCESS) { @@ -389,47 +389,88 @@ static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint pjsip_rx_data *rdata, pjsip_tx_data *tdata) { struct ast_sip_auth **auths; + struct ast_sip_auth **auths_shallow; enum digest_verify_result *verify_res; + struct ast_sip_endpoint *artificial_endpoint; enum ast_sip_check_auth_result res; - int i; + int idx; + int is_artificial; int failures = 0; size_t auth_size; - RAII_VAR(struct ast_sip_endpoint *, artificial_endpoint, - ast_sip_get_artificial_endpoint(), ao2_cleanup); - auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths); + ast_assert(0 < auth_size); auths = ast_alloca(auth_size * sizeof(*auths)); verify_res = ast_alloca(auth_size * sizeof(*verify_res)); - if (!auths) { + artificial_endpoint = ast_sip_get_artificial_endpoint(); + if (!artificial_endpoint) { + /* Should not happen except possibly if we are shutting down. */ return AST_SIP_AUTHENTICATION_ERROR; } - if (endpoint == artificial_endpoint) { + is_artificial = endpoint == artificial_endpoint; + ao2_ref(artificial_endpoint, -1); + if (is_artificial) { + ast_assert(auth_size == 1); auths[0] = ast_sip_get_artificial_auth(); - } else if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) { - res = AST_SIP_AUTHENTICATION_ERROR; - goto cleanup; + if (!auths[0]) { + /* Should not happen except possibly if we are shutting down. */ + return AST_SIP_AUTHENTICATION_ERROR; + } + } else { + memset(auths, 0, auth_size * sizeof(*auths)); + if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) { + res = AST_SIP_AUTHENTICATION_ERROR; + goto cleanup; + } } - for (i = 0; i < auth_size; ++i) { - if (ast_strlen_zero(auths[i]->realm)) { - ast_string_field_set(auths[i], realm, default_realm); + /* Setup shallow copy of auths */ + if (ast_strlen_zero(default_realm)) { + auths_shallow = auths; + } else { + /* + * Set default realm on a shallow copy of the authentication + * objects that don't have a realm set. + */ + auths_shallow = ast_alloca(auth_size * sizeof(*auths_shallow)); + for (idx = 0; idx < auth_size; ++idx) { + if (ast_strlen_zero(auths[idx]->realm)) { + /* + * Make a shallow copy and set the default realm on it. + * + * The stack allocation is OK here. Normally this will + * loop one time. If you have multiple auths then you + * shouldn't need more auths than the normal complement + * of fingers and toes. Otherwise, you should check + * your sanity for setting up your system up that way. + */ + auths_shallow[idx] = ast_alloca(sizeof(**auths_shallow)); + memcpy(auths_shallow[idx], auths[idx], sizeof(**auths_shallow)); + *((char **) (&auths_shallow[idx]->realm)) = default_realm; + ast_debug(3, "Using default realm '%s' on incoming auth '%s'.\n", + default_realm, ast_sorcery_object_get_id(auths_shallow[idx])); + } else { + auths_shallow[idx] = auths[idx]; + } } - verify_res[i] = verify(auths[i], rdata, tdata->pool); - if (verify_res[i] == AUTH_SUCCESS) { + } + + for (idx = 0; idx < auth_size; ++idx) { + verify_res[idx] = verify(auths_shallow[idx], rdata, tdata->pool); + if (verify_res[idx] == AUTH_SUCCESS) { res = AST_SIP_AUTHENTICATION_SUCCESS; goto cleanup; } - if (verify_res[i] == AUTH_FAIL) { + if (verify_res[idx] == AUTH_FAIL) { failures++; } } - for (i = 0; i < auth_size; ++i) { - challenge(auths[i]->realm, tdata, rdata, verify_res[i] == AUTH_STALE); + for (idx = 0; idx < auth_size; ++idx) { + challenge(auths_shallow[idx]->realm, tdata, rdata, verify_res[idx] == AUTH_STALE); } if (failures == auth_size) { From 28c8e4f58f0f38792c7c79a05bd07788ebf15332 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 16 Feb 2017 16:30:00 +0000 Subject: [PATCH 1069/1578] build: Execute ldconfig to build cache. On some platforms a multiarch approach is used for libraries. The build system does not take this into account and still places libraries into the lib directory if no --libdir is specified to configure. On initial startup this results in libasteriskssl.so not being found, as it is not in the multiarch lib directory. This change does the minimally invasive thing and executes ldconfig so that the libraries in the lib directory are found and their location cached. By doing so Asterisk starts up fine. If DESTDIR is specified, however, the old logic is executed as the install process may not have permission to alter the ldconfig cache. ASTERISK-26705 Change-Id: If4eca46ac510c6fea5568256280ffdb3888d7bb4 --- main/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main/Makefile b/main/Makefile index 4d1b2c41bd2..3c371c6685e 100644 --- a/main/Makefile +++ b/main/Makefile @@ -355,7 +355,11 @@ else # Darwin endif endif ifneq ($(LDCONFIG),) +ifneq ($(DESTDIR),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" +else + $(LDCONFIG) +endif endif $(LN) -sf asterisk "$(DESTDIR)$(ASTSBINDIR)/rasterisk" @@ -373,7 +377,11 @@ ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" endif ifneq ($(LDCONFIG),) +ifneq ($(DESTDIR),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" +else + $(LDCONFIG) +endif endif clean:: From 6e6c96d713be2b745c4e033b6e5710dea72088df Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 21 Feb 2017 09:56:54 -0500 Subject: [PATCH 1070/1578] realtime: Centralize some common realtime backend code All of the realtime backends create artificial ast_categorys to pass back into the core as query results. These categories have no filename or line number information associated with them and the backends differ slightly on how they create them. So create a couple helper macros to help make things more consistent. Also updated the call sites to remove redundant error messages about memory allocation failure. Note that res_config_ldap sets the category filename to the 'table name' but that is not read by anything in the core, so I've dropped it. Change-Id: I3a1fd91e0c807dea1ce3b643b0a6fe5be9002897 --- addons/res_config_mysql.c | 7 +++---- include/asterisk/config.h | 12 ++++++++++++ res/res_config_curl.c | 7 +++++-- res/res_config_ldap.c | 6 ++---- res/res_config_odbc.c | 6 ++---- res/res_config_pgsql.c | 9 ++++++--- res/res_config_sqlite.c | 8 +++----- res/res_config_sqlite3.c | 7 ++++--- 8 files changed, 37 insertions(+), 25 deletions(-) diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c index f2ef949fc0c..b080d118b86 100644 --- a/addons/res_config_mysql.c +++ b/addons/res_config_mysql.c @@ -523,9 +523,8 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char while ((row = mysql_fetch_row(result))) { var = NULL; - cat = ast_category_new("", "", -1); + cat = ast_category_new_anonymous(); if (!cat) { - ast_log(LOG_WARNING, "Out of memory!\n"); continue; } for (i = 0; i < numFields; i++) { @@ -934,8 +933,8 @@ static struct ast_config *config_mysql(const char *database, const char *table, } if (strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) { - if (!(cur_cat = ast_category_new(row[0], "", -1))) { - ast_log(LOG_WARNING, "Out of memory!\n"); + cur_cat = ast_category_new_dynamic(row[0]); + if (!cur_cat) { break; } strcpy(last, row[0]); diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 4944a3af202..f57966b0bab 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -833,6 +833,18 @@ const char *ast_config_option(struct ast_config *cfg, const char *cat, const cha */ struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno); +/*! + * \brief Create a category that is not backed by a file + * + * \param name name of new category + */ +#define ast_category_new_dynamic(name) ast_category_new(name, "", -1) + +/*! + * \brief Create a nameless category that is not backed by a file + */ +#define ast_category_new_anonymous() ast_category_new_dynamic("") + /*! * \brief Create a category making it a template * diff --git a/res/res_config_curl.c b/res/res_config_curl.c index 9ad7a6e3db7..06a6aef89e9 100644 --- a/res/res_config_curl.c +++ b/res/res_config_curl.c @@ -182,7 +182,8 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse continue; } - if (!(cat = ast_category_new("", "", 99999))) { + cat = ast_category_new_anonymous(); + if (!cat) { continue; } @@ -569,8 +570,10 @@ static struct ast_config *config_curl(const char *url, const char *unused, const } if (!cat || strcmp(category, cur_cat) || last_cat_metric != cat_metric) { - if (!(cat = ast_category_new(category, "", 99999))) + cat = ast_category_new_dynamic(category); + if (!cat) { break; + } cur_cat = category; last_cat_metric = cat_metric; ast_category_append(cfg, cat); diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 5e95853d462..7bbac0ce0f3 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -1043,10 +1043,8 @@ static struct ast_config *realtime_multi_ldap(const char *basedn, struct ast_variable **p = vars; while (*p) { - struct ast_category *cat = NULL; - cat = ast_category_new("", table_name, -1); + struct ast_category *cat = ast_category_new_anonymous(); if (!cat) { - ast_log(LOG_ERROR, "Unable to create a new category!\n"); break; } else { struct ast_variable *var = *p; @@ -1195,7 +1193,7 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name if (!last_category || strcmp(last_category, categories[i].name) || last_category_metric != categories[i].metric) { - cur_cat = ast_category_new(categories[i].name, table_name, -1); + cur_cat = ast_category_new_dynamic(categories[i].name); if (!cur_cat) { break; } diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 5a25b6b5a0b..114708325ee 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -407,9 +407,8 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql)); continue; } - cat = ast_category_new("","",99999); + cat = ast_category_new_anonymous(); if (!cat) { - ast_log(LOG_WARNING, "Out of memory!\n"); continue; } for (x=0;xcat_name || strcmp(args->cat_name, argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY])) { - args->cat = ast_category_new(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY], "", 99999); - + args->cat = ast_category_new_dynamic(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY]); if (!args->cat) { - ast_log(LOG_WARNING, "Unable to allocate category\n"); return 1; } @@ -1086,8 +1084,8 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv, char **colum return 1; } - if (!(cat = ast_category_new(cat_name, "", 99999))) { - ast_log(LOG_WARNING, "Unable to allocate category\n"); + cat = ast_category_new_dynamic(cat_name); + if (!cat) { return 1; } diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index 8c514b07ca1..087843a6805 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -503,7 +503,8 @@ static int append_row_to_cfg(void *arg, int num_columns, char **values, char **c struct ast_category *cat; int i; - if (!(cat = ast_category_new("", "", 99999))) { + cat = ast_category_new_anonymous(); + if (!cat) { return SQLITE_ABORT; } @@ -723,8 +724,8 @@ static int static_realtime_cb(void *arg, int num_columns, char **values, char ** } if (!args->cat_name || strcmp(args->cat_name, values[COL_CATEGORY])) { - if (!(args->cat = ast_category_new(values[COL_CATEGORY], "", 99999))) { - ast_log(LOG_WARNING, "Unable to allocate category\n"); + args->cat = ast_category_new_dynamic(values[COL_CATEGORY]); + if (!args->cat) { return SQLITE_ABORT; } From ab04a018e45d81c28e834cc6036f891dce7921e3 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 21 Feb 2017 11:47:28 -0500 Subject: [PATCH 1071/1578] realtime: Fix ast_load_realtime_multientry handling ast_load_realtime_multientry() returns an ast_config structure whose ast_categorys are keyed with the empty strings. Several modules were giving semantic meaning to the category names causing problems at runtime. * app_directory: Treated the category name as the mailbox name, and would fail to direct calls to the appropriate extension after an entry was chosen. * app_queue: Queues, queue members, and queue rules were all affected and needed to be updated. * pbx_realtime: Pattern matching would never succeed because the extension entered by the user was always compared to the empty string. Change-Id: Ie7e44986344b0b76ea8f6ddb5879f5040c6ca8a7 --- apps/app_directory.c | 18 ++++++------ apps/app_queue.c | 65 ++++++++++++++++++++++++-------------------- pbx/pbx_realtime.c | 13 +++++---- 3 files changed, 52 insertions(+), 44 deletions(-) diff --git a/apps/app_directory.c b/apps/app_directory.c index 642b9b23a08..dd80c346750 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -464,7 +464,7 @@ static struct ast_config *realtime_directory(char *context) struct ast_config *rtdata = NULL; struct ast_category *cat; struct ast_variable *var; - char *mailbox; + char *category = NULL; const char *fullname; const char *hidefromdir, *searchcontexts = NULL; struct ast_flags config_flags = { 0 }; @@ -505,13 +505,12 @@ static struct ast_config *realtime_directory(char *context) return cfg; } - mailbox = NULL; - while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) { - struct ast_variable *alias; - const char *ctx = ast_variable_retrieve(rtdata, mailbox, "context"); + while ((category = ast_category_browse(rtdata, category))) { + const char *mailbox = ast_variable_retrieve(rtdata, category, "mailbox"); + const char *ctx = ast_variable_retrieve(rtdata, category, "context"); - fullname = ast_variable_retrieve(rtdata, mailbox, "fullname"); - hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir"); + fullname = ast_variable_retrieve(rtdata, category, "fullname"); + hidefromdir = ast_variable_retrieve(rtdata, category, "hidefromdir"); if (ast_true(hidefromdir)) { /* Skip hidden */ continue; @@ -519,8 +518,9 @@ static struct ast_config *realtime_directory(char *context) /* password,Full Name,email,pager,options */ ast_str_set(&tmp, 0, "no-password,%s,,,", S_OR(fullname, "")); - if (ast_variable_retrieve(rtdata, mailbox, "alias")) { - for (alias = ast_variable_browse(rtdata, mailbox); alias; alias = alias->next) { + if (ast_variable_retrieve(rtdata, category, "alias")) { + struct ast_variable *alias; + for (alias = ast_variable_browse(rtdata, category); alias; alias = alias->next) { if (!strcasecmp(alias->name, "alias")) { ast_str_append(&tmp, 0, "|alias=%s", alias->value); } diff --git a/apps/app_queue.c b/apps/app_queue.c index 95f4c0eedfb..204b4b2deb9 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2914,13 +2914,19 @@ static int load_realtime_rules(void) ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n"); return 0; } - while ((rulecat = ast_category_browse(cfg, rulecat)) && !ast_strlen_zero(rulecat)) { - const char *timestr, *maxstr, *minstr; + while ((rulecat = ast_category_browse(cfg, rulecat))) { + const char *timestr, *maxstr, *minstr, *rule_name; int penaltychangetime, rule_exists = 0, inserted = 0; int max_penalty = 0, min_penalty = 0, min_relative = 0, max_relative = 0; struct penalty_rule *new_penalty_rule = NULL; + + rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name"); + if (ast_strlen_zero(rule_name)) { + continue; + } + AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { - if (!(strcasecmp(rl_iter->name, rulecat))) { + if (!(strcasecmp(rl_iter->name, rule_name))) { rule_exists = 1; new_rl = rl_iter; break; @@ -2931,13 +2937,13 @@ static int load_realtime_rules(void) ast_config_destroy(cfg); return -1; } - ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); + ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name)); AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); } timestr = ast_variable_retrieve(cfg, rulecat, "time"); if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) { ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n", - (ast_strlen_zero(timestr) ? "invalid value" : timestr), rulecat); + (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name); continue; } if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) { @@ -3272,7 +3278,7 @@ static void member_remove_from_queue(struct call_queue *queue, struct member *me * Search for member in queue, if found update penalty/paused state, * if no member exists create one flag it as a RT member and add to queue member list. */ -static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config) +static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config) { struct member *m; struct ao2_iterator mem_iter; @@ -3282,11 +3288,12 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc int ringinuse = q->ringinuse; const char *config_val; - const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid"); - const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface); - const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface); - const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty"); - const char *paused_str = ast_variable_retrieve(member_config, interface, "paused"); + const char *interface = ast_variable_retrieve(member_config, category, "interface"); + const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid"); + const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface); + const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface); + const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty"); + const char *paused_str = ast_variable_retrieve(member_config, category, "paused"); if (ast_strlen_zero(rt_uniqueid)) { ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL")); @@ -3309,7 +3316,7 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc } } - if ((config_val = ast_variable_retrieve(member_config, interface, realtime_ringinuse_field))) { + if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) { if (ast_true(config_val)) { ringinuse = 1; } else if (ast_false(config_val)) { @@ -3425,7 +3432,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as }; struct member *m; struct ao2_iterator mem_iter; - char *interface = NULL; + char *category = NULL; const char *tmp_name; char *tmp; char tmpbuf[64]; /* Must be longer than the longest queue param name. */ @@ -3526,8 +3533,8 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as } ao2_iterator_destroy(&mem_iter); - while ((interface = ast_category_browse(member_config, interface))) { - rt_handle_member_record(q, interface, member_config); + while ((category = ast_category_browse(member_config, category))) { + rt_handle_member_record(q, category, member_config); } /* Delete all realtime members that have been deleted in DB. */ @@ -3636,7 +3643,7 @@ static void update_realtime_members(struct call_queue *q) { struct ast_config *member_config = NULL; struct member *m; - char *interface = NULL; + char *category = NULL; struct ao2_iterator mem_iter; if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { @@ -3669,8 +3676,8 @@ static void update_realtime_members(struct call_queue *q) } ao2_iterator_destroy(&mem_iter); - while ((interface = ast_category_browse(member_config, interface))) { - rt_handle_member_record(q, interface, member_config); + while ((category = ast_category_browse(member_config, category))) { + rt_handle_member_record(q, category, member_config); } /* Delete all realtime members that have been deleted in DB. */ @@ -7471,12 +7478,11 @@ static int set_member_value(const char *queuename, const char *interface, int pr if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */ if (ast_check_realtime("queues")) { - char *name; queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); if (queue_config) { - for (name = ast_category_browse(queue_config, NULL); - !ast_strlen_zero(name); - name = ast_category_browse(queue_config, name)) { + char *category = NULL; + while ((category = ast_category_browse(queue_config, category))) { + const char *name = ast_variable_retrieve(queue_config, category, "name"); if ((q = find_load_queue_rt_friendly(name))) { foundqueue++; foundinterface += set_member_value_help_members(q, interface, property, value); @@ -9381,9 +9387,10 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * * which have not yet been added to the in-core container */ struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); - char *queuename; if (cfg) { - for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { + char *category = NULL; + while ((category = ast_category_browse(cfg, category))) { + const char *queuename = ast_variable_retrieve(cfg, category, "name"); if ((q = find_load_queue_rt_friendly(queuename))) { queue_t_unref(q, "Done with temporary pointer"); } @@ -9452,7 +9459,8 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * ast_str_set(&out, 0, " %s", mem->membername); if (strcasecmp(mem->membername, mem->interface)) { ast_str_append(&out, 0, " (%s", mem->interface); - if (!ast_strlen_zero(mem->state_interface)) { + if (!ast_strlen_zero(mem->state_interface) + && strcmp(mem->state_interface, mem->interface)) { ast_str_append(&out, 0, " from %s", mem->state_interface); } ast_str_append(&out, 0, ")"); @@ -11044,14 +11052,13 @@ static int queues_data_provider_get(const struct ast_data_search *search, struct ao2_iterator i; struct call_queue *queue, *queue_realtime = NULL; struct ast_config *cfg; - char *queuename; /* load realtime queues. */ cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); if (cfg) { - for (queuename = ast_category_browse(cfg, NULL); - !ast_strlen_zero(queuename); - queuename = ast_category_browse(cfg, queuename)) { + char *category = NULL; + while ((category = ast_category_browse(cfg, category))) { + const char *queuename = ast_variable_retrieve(cfg, category, "name"); if ((queue = find_load_queue_rt_friendly(queuename))) { queue_unref(queue); } diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c index 08c90aa62f7..6f5d13738f5 100644 --- a/pbx/pbx_realtime.c +++ b/pbx/pbx_realtime.c @@ -189,25 +189,26 @@ static struct ast_variable *realtime_switch_common(const char *table, const char if (!var && !ast_test_flag(&flags, OPTION_PATTERNS_DISABLED)) { cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL); if (cfg) { - char *cat = ast_category_browse(cfg, NULL); + char *cat = NULL; + + while ((cat = ast_category_browse(cfg, cat))) { + const char *realtime_exten = ast_variable_retrieve(cfg, cat, "exten"); - while(cat) { switch(mode) { case MODE_MATCHMORE: - match = ast_extension_close(cat, exten, 1); + match = ast_extension_close(realtime_exten, exten, 1); break; case MODE_CANMATCH: - match = ast_extension_close(cat, exten, 0); + match = ast_extension_close(realtime_exten, exten, 0); break; case MODE_MATCH: default: - match = ast_extension_match(cat, exten); + match = ast_extension_match(realtime_exten, exten); } if (match) { var = ast_category_detach_variables(ast_category_get(cfg, cat, NULL)); break; } - cat = ast_category_browse(cfg, cat); } ast_config_destroy(cfg); } From a738772edd5279b1d0bfd3b49bb4cc6c010db5d1 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 15 Feb 2017 14:43:36 -0600 Subject: [PATCH 1072/1578] Add initial SDP state code. This establishes the basic allocation/destruction of an SDP state object, plus some of the simpler getter methods involved. Subsequent tasks will deal with adding a state machine, creating SDPs from capabilities and options, and merging SDPs into a joint SDP. Change-Id: Ie3757ce186f04b65e9d1883f5aace53f24e53709 --- include/asterisk/sdp_state.h | 58 +++++++++++++++++++ main/sdp_state.c | 107 +++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 include/asterisk/sdp_state.h create mode 100644 main/sdp_state.c diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h new file mode 100644 index 00000000000..b5e44179ee6 --- /dev/null +++ b/include/asterisk/sdp_state.h @@ -0,0 +1,58 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _ASTERISK_SDP_STATE_H +#define _ASTERISK_SDP_STATE_H + +struct ast_sdp_state; +struct ast_sdp_options; +struct ast_stream_topology; + +/*! + * \brief Allocate a new SDP state + * + * SDP state keeps tabs on everything SDP-related for a media session. + * Most SDP operations will require the state to be provided. + * Ownership of the SDP options is taken on by the SDP state. + * A good strategy is to call this during session creation. + */ +struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, struct ast_sdp_options *options); + +/*! + * \brief Free the SDP state. + * + * A good strategy is to call this during session destruction + */ +void ast_sdp_state_free(struct ast_sdp_state *sdp_state); + +/*! + * \brief Get the associated RTP instance for a particular stream on the SDP state. + * + * Stream numbers correspond to the streams in the topology of the associated channel + */ +struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sdp_state, int stream_index); + +/*! + * \brief Get the joint negotiated streams based on local and remote capabilities. + * + * If this is called prior to receiving a remote SDP, then this will just mirror + * the local configured endpoint capabilities. + */ +struct ast_stream_topology *ast_sdp_state_get_joint_topology(struct ast_sdp_state *sdp_state); + +#endif /* _ASTERISK_SDP_STATE_H */ diff --git a/main/sdp_state.c b/main/sdp_state.c new file mode 100644 index 00000000000..04de6e385a9 --- /dev/null +++ b/main/sdp_state.c @@ -0,0 +1,107 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include "asterisk.h" +#include "asterisk/sdp_state.h" +#include "asterisk/sdp_options.h" +#include "asterisk/sdp_translator.h" +#include "asterisk/sdp_priv.h" +#include "asterisk/vector.h" +#include "asterisk/utils.h" +#include "asterisk/stream.h" + +struct ast_sdp_state { + /*! Local capabilities, learned through configuration */ + struct ast_stream_topology *local_capabilities; + /*! Remote capabilities, learned through remote SDP */ + struct ast_stream_topology *remote_capabilities; + /*! Joint capabilities. The combined local and remote capabilities. */ + struct ast_stream_topology *joint_capabilities; + /*! Local SDP. Generated via the options and local capabilities. */ + struct ast_sdp *local_sdp; + /*! Remote SDP. Received directly from a peer. */ + struct ast_sdp *remote_sdp; + /*! Joint SDP. The merged local and remote SDPs. */ + struct ast_sdp *joint_sdp; + /*! SDP options. Configured options beyond media capabilities. */ + struct ast_sdp_options *options; + /*! Translator that puts SDPs into the expected representation */ + struct ast_sdp_translator *translator; + /*! RTP instance for each media stream */ + AST_VECTOR(, struct ast_rtp_instance *) rtp; +}; + +struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, struct ast_sdp_options *options) +{ + struct ast_sdp_state *sdp_state; + + sdp_state = ast_calloc(1, sizeof(*sdp_state)); + if (!sdp_state) { + return NULL; + } + + sdp_state->options = options; + + sdp_state->translator = ast_sdp_translator_new(ast_sdp_options_get_repr(sdp_state->options)); + if (!sdp_state->translator) { + ast_sdp_state_free(sdp_state); + return NULL; + } + + sdp_state->local_capabilities = ast_stream_topology_clone(streams); + if (!sdp_state->local_capabilities) { + ast_sdp_state_free(sdp_state); + return NULL; + } + + return sdp_state; +} + +void ast_sdp_state_free(struct ast_sdp_state *sdp_state) +{ + if (!sdp_state) { + return; + } + + ast_stream_topology_free(sdp_state->local_capabilities); + ast_stream_topology_free(sdp_state->remote_capabilities); + ast_stream_topology_free(sdp_state->joint_capabilities); + ast_sdp_free(sdp_state->local_sdp); + ast_sdp_free(sdp_state->remote_sdp); + ast_sdp_free(sdp_state->joint_sdp); + ast_sdp_options_free(sdp_state->options); + ast_sdp_translator_free(sdp_state->translator); +} + +struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sdp_state, int stream_index) +{ + if (stream_index >= AST_VECTOR_SIZE(&sdp_state->rtp)) { + return NULL; + } + + return AST_VECTOR_GET(&sdp_state->rtp, stream_index); +} + +struct ast_stream_topology *ast_sdp_state_get_joint_topology(struct ast_sdp_state *sdp_state) +{ + if (sdp_state->joint_capabilities) { + return sdp_state->joint_capabilities; + } else { + return sdp_state->local_capabilities; + } +} From fc70ca9499c26329950f044838209c6bade3f54c Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 21 Feb 2017 16:09:47 -0500 Subject: [PATCH 1073/1578] pbx_dundi: DUNDi weight parameter not processed correctly The DUNDi weight field is not always converted from network byte order to host byte order. This can result in incorrect weight values and incorrect selection of DUNDi destinations. ASTERISK-18731 #close Reported by: Peter Racz Patches: dundi_weight.patch (license #6290) patch uploaded by Peter Racz Change-Id: Iba3e1a700ff539db57211a7bbc26f7b22ea9a1be --- pbx/pbx_dundi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index 50a91605e58..58086aa81a4 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -992,9 +992,9 @@ static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies sizeof(trans->parent->dr[trans->parent->respcount].tech)); trans->parent->respcount++; ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); - } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) { + } else if (trans->parent->dr[z].weight > ntohs(ies->answers[x]->weight)) { /* Update weight if appropriate */ - trans->parent->dr[z].weight = ies->answers[x]->weight; + trans->parent->dr[z].weight = ntohs(ies->answers[x]->weight); } } else ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n", @@ -1762,9 +1762,9 @@ static int handle_command_response(struct dundi_transaction *trans, struct dundi sizeof(trans->parent->dr[trans->parent->respcount].tech)); trans->parent->respcount++; ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); - } else if (trans->parent->dr[z].weight > ies.answers[x]->weight) { + } else if (trans->parent->dr[z].weight > ntohs(ies.answers[x]->weight)) { /* Update weight if appropriate */ - trans->parent->dr[z].weight = ies.answers[x]->weight; + trans->parent->dr[z].weight = ntohs(ies.answers[x]->weight); } } else ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n", From f58aefba5be6ab8ada6899ff50c6148830032814 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 22 Feb 2017 14:32:23 +0000 Subject: [PATCH 1074/1578] core: Show streams in "core show channel". The "core show channel" CLI command will now output the streams present on the channel with their details. ASTERISK-26811 Change-Id: I9c95b57aa09415005f0677a1949a0feb07e4987a --- include/asterisk/stream.h | 11 +++++++++++ main/cli.c | 19 +++++++++++++++++++ main/stream.c | 18 ++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index edb00b9ebe5..48ee883224e 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -190,6 +190,17 @@ enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream); */ void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state); +/*! + * \brief Convert the state of a stream into a string + * + * \param state The stream state + * + * \return The state of the stream in string format + * + * \since 15 + */ +const char *ast_stream_state2str(enum ast_stream_state state); + /*! * \brief Get the position of the stream in the topology * diff --git a/main/cli.c b/main/cli.c index ccdbb97c3e4..06f2d55b2bb 100644 --- a/main/cli.c +++ b/main/cli.c @@ -61,6 +61,7 @@ #include "asterisk/stasis_channels.h" #include "asterisk/stasis_bridges.h" #include "asterisk/vector.h" +#include "asterisk/stream.h" /*! * \brief List of restrictions per user. @@ -1542,6 +1543,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar struct ast_bridge *bridge; ast_callid callid; char callid_buf[32]; + int stream_num; switch (cmd) { case CLI_INIT: @@ -1668,6 +1670,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar S_OR(ast_channel_data(chan), "(Empty)"), S_OR(callid_buf, "(None)") ); + ast_str_append(&output, 0, " Variables:\n"); AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) { @@ -1679,6 +1682,22 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_str_append(&output, 0, " CDR Variables:\n%s\n", ast_str_buffer(obuf)); } + ast_str_append(&output, 0, " -- Streams --\n"); + for (stream_num = 0; stream_num < ast_stream_topology_get_count(ast_channel_get_stream_topology(chan)); stream_num++) { + struct ast_stream *stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num); + + ast_str_append(&output, 0, + "Name: %s\n" + " Type: %s\n" + " State: %s\n" + " Formats: %s\n", + ast_stream_get_name(stream), + ast_codec_media_type2str(ast_stream_get_type(stream)), + ast_stream_state2str(ast_stream_get_state(stream)), + ast_format_cap_get_names(ast_stream_get_formats(stream), &codec_buf) + ); + } + ast_channel_unlock(chan); ast_cli(a->fd, "%s", ast_str_buffer(output)); diff --git a/main/stream.c b/main/stream.c index aacd33f1734..8bee2fdd0a9 100644 --- a/main/stream.c +++ b/main/stream.c @@ -168,6 +168,24 @@ void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state stream->state = state; } +const char *ast_stream_state2str(enum ast_stream_state state) +{ + switch (state) { + case AST_STREAM_STATE_REMOVED: + return "removed"; + case AST_STREAM_STATE_SENDRECV: + return "sendrecv"; + case AST_STREAM_STATE_SENDONLY: + return "sendonly"; + case AST_STREAM_STATE_RECVONLY: + return "recvonly"; + case AST_STREAM_STATE_INACTIVE: + return "inactive"; + default: + return ""; + } +} + int ast_stream_get_position(const struct ast_stream *stream) { ast_assert(stream != NULL); From 15ed7af0278f459c69b0d0fd9168e3bc34ccb6a2 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 21 Feb 2017 11:47:41 -0500 Subject: [PATCH 1075/1578] pbx_realtime: Prevent premature extension matching The patterns provided by pbx_realtime were checked in the order in which they were returned from the realtime backend. If there was overlap between multiple patterns, the first one to correctly match was chosen even though it may not have been the best match. We now sort the patterns descending by their length and compare in that order. There may be cases where this still results in a sub-optimal match, but this patch should improve the overall behavior. ASTERISK-18271 #close Reported by: Charlie Smurthwaite Change-Id: I56d9ac15810eb1775966b669c3028e32cc7bd809 --- pbx/pbx_realtime.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c index 6f5d13738f5..10a147b14b1 100644 --- a/pbx/pbx_realtime.c +++ b/pbx/pbx_realtime.c @@ -141,6 +141,13 @@ static void *cleanup(void *unused) return NULL; } +static int extension_length_comparator(struct ast_category *p, struct ast_category *q) +{ + const char *extenp = S_OR(ast_variable_find(p, "exten"), ""); + const char *extenq = S_OR(ast_variable_find(q, "exten"), ""); + + return strlen(extenp) - strlen(extenq); +} /* Realtime switch looks up extensions in the supplied realtime table. @@ -191,6 +198,9 @@ static struct ast_variable *realtime_switch_common(const char *table, const char if (cfg) { char *cat = NULL; + /* Sort so that longer patterns are checked first */ + ast_config_sort_categories(cfg, 1, extension_length_comparator); + while ((cat = ast_category_browse(cfg, cat))) { const char *realtime_exten = ast_variable_retrieve(cfg, cat, "exten"); From ced73d5b799ab7f8ab7610d632f10be25ff6ff0f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 22 Feb 2017 11:12:54 -0600 Subject: [PATCH 1076/1578] Revert "build: Execute ldconfig to build cache." This reverts commit 28c8e4f58f0f38792c7c79a05bd07788ebf15332. Change-Id: Ie2e1aaf61fd49045994974a4581545ac8348fe4c --- main/Makefile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/main/Makefile b/main/Makefile index 3c371c6685e..4d1b2c41bd2 100644 --- a/main/Makefile +++ b/main/Makefile @@ -355,11 +355,7 @@ else # Darwin endif endif ifneq ($(LDCONFIG),) -ifneq ($(DESTDIR),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" -else - $(LDCONFIG) -endif endif $(LN) -sf asterisk "$(DESTDIR)$(ASTSBINDIR)/rasterisk" @@ -377,11 +373,7 @@ ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" endif ifneq ($(LDCONFIG),) -ifneq ($(DESTDIR),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" -else - $(LDCONFIG) -endif endif clean:: From 66a35e24519d44fae92965739f4ffc874718d6fb Mon Sep 17 00:00:00 2001 From: "Michael L. Young" Date: Wed, 22 Feb 2017 14:08:05 -0500 Subject: [PATCH 1077/1578] build_tools: Fix download_externals to allow the use of curl or wget Not sure if this is really a bug versus an improvement. I can see it being viewed as a bug though by some. The current build_tools/download_externals file depends on wget in order to download external modules. The current build system is able to discover which tool to use for fetching remote files - either wget or curl. This patch takes advantage of this capability by modifying the two calls to the wget binary to instead use what was discovered by the build system. ASTERISK-26812 #close Change-Id: If9411a2554f009274d377445613ae91192d948a1 --- build_tools/download_externals | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_tools/download_externals b/build_tools/download_externals index d2e2e4fffa3..b0a414ed1fd 100755 --- a/build_tools/download_externals +++ b/build_tools/download_externals @@ -103,7 +103,7 @@ version_convert() { echo ${v} } -${WGET} -q -O ${tmpdir}/${variant_manifest} ${remote_url}/${variant_manifest} || { +${DOWNLOAD_TO_STDOUT} ${remote_url}/${variant_manifest} > ${tmpdir}/${variant_manifest} || { echo "${full_name}: Unable to fetch ${remote_url}/${variant_manifest}" exit 1 } @@ -188,7 +188,7 @@ fi if [[ ${need_download} = 1 ]] ; then echo "${full_name}: Downloading ${remote_url}/${tarball}" - ${WGET} -q -O ${cache_dir}/${tarball} ${remote_url}/${tarball} || { + ${DOWNLOAD_TO_STDOUT} ${remote_url}/${tarball} > ${cache_dir}/${tarball} || { echo "${full_name}: Unable to fetch ${remote_url}/${tarball}" exit 1 } From e57961db846ae72250d72829f32d92492079a050 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 22 Feb 2017 09:53:25 -0500 Subject: [PATCH 1078/1578] res_config_ldap: Various code improvements The initial motivation for this patch was to properly handle memory allocation failures - we weren't checking the return values from the various LDAP library allocation functions. In the process, because update_ldap() and update2_ldap() were substantially the same code, they've been consolidated. Change-Id: Iebcfe404177cc6860ee5087976fe97812221b822 --- res/res_config_ldap.c | 761 ++++++++++++++++++++++-------------------- 1 file changed, 390 insertions(+), 371 deletions(-) diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 8ad9e131920..8f24a8dc364 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -754,6 +754,47 @@ static void append_var_and_value_to_filter(struct ast_str **filter, ast_str_append(filter, 0, "(%s=%s)", name, value); } +/*! + * \internal + * \brief Create an LDAP filter using search fields + * + * \param config the \c ldap_table_config for this search + * \param fields the \c ast_variable criteria to include + * + * \returns an \c ast_str pointer on success, NULL otherwise. + */ +static struct ast_str *create_lookup_filter(struct ldap_table_config *config, const struct ast_variable *fields) +{ + struct ast_str *filter; + const struct ast_variable *field; + + filter = ast_str_create(80); + if (!filter) { + return NULL; + } + + /* + * Create the filter with the table additional filter and the + * parameter/value pairs we were given + */ + ast_str_append(&filter, 0, "(&"); + if (config && config->additional_filter) { + ast_str_append(&filter, 0, "%s", config->additional_filter); + } + if (config != base_table_config + && base_table_config + && base_table_config->additional_filter) { + ast_str_append(&filter, 0, "%s", base_table_config->additional_filter); + } + /* Append the lookup fields */ + for (field = fields; field; field = field->next) { + append_var_and_value_to_filter(&filter, config, field->name, field->value); + } + ast_str_append(&filter, 0, ")"); + + return filter; +} + /*! \brief LDAP base function * \return a null terminated array of ast_variable (one per entry) or NULL if no entry is found or if an error occured * caller should free the returned array and ast_variables @@ -780,16 +821,9 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p return NULL; } - if (!(filter = ast_str_create(80))) { - ast_log(LOG_ERROR, "Can't initialize data structures.n"); - ast_free(clean_basedn); - return NULL; - } - if (!field) { ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter" " and 1 value to search on.\n"); - ast_free(filter); ast_free(clean_basedn); return NULL; } @@ -799,7 +833,6 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p /* We now have our complete statement; Lets connect to the server and execute it. */ if (!ldap_reconnect()) { ast_mutex_unlock(&ldap_lock); - ast_free(filter); ast_free(clean_basedn); return NULL; } @@ -808,30 +841,16 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p if (!table_config) { ast_log(LOG_WARNING, "No table named '%s'.\n", table_name); ast_mutex_unlock(&ldap_lock); - ast_free(filter); ast_free(clean_basedn); return NULL; } - ast_str_append(&filter, 0, "(&"); - - if (table_config && table_config->additional_filter) { - ast_str_append(&filter, 0, "%s", table_config->additional_filter); - } - if (table_config != base_table_config && base_table_config && - base_table_config->additional_filter) { - ast_str_append(&filter, 0, "%s", base_table_config->additional_filter); - } - - /* Create the first part of the query using the first parameter/value pairs we just extracted. - * If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat - */ - - append_var_and_value_to_filter(&filter, table_config, field->name, field->value); - while ((field = field->next)) { - append_var_and_value_to_filter(&filter, table_config, field->name, field->value); + filter = create_lookup_filter(table_config, fields); + if (!filter) { + ast_mutex_unlock(&ldap_lock); + ast_free(clean_basedn); + return NULL; } - ast_str_append(&filter, 0, ")"); do { /* freeing ldap_result further down */ @@ -1212,315 +1231,283 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name /*! * \internal - * \brief Remove LDAP_MOD_DELETE modifications that will not succeed - * - * \details - * A LDAP_MOD_DELETE operation will fail if the LDAP entry does not already have - * the corresponding attribute. Because we may be updating multiple LDAP entries - * in a single call to update_ldap(), we may need our own copy of the - * modifications array for each one. + * \brief Create an LDAP modification structure (LDAPMod) * - * \note - * This function dynamically allocates memory. If it returns a non-NULL pointer, - * it is up to the caller to free it with ldap_mods_free() + * \param attribute the name of the LDAP attribute to modify + * \param new_value the new value of the LDAP attribute * - * \returns an LDAPMod * if modifications needed to be removed, NULL otherwise. + * \returns an LDAPMod * if successful, NULL otherwise. */ -static LDAPMod **massage_mods_for_entry(LDAPMessage *entry, LDAPMod **mods, size_t count) +static LDAPMod *ldap_mod_create(const char *attribute, const char *new_value) { - size_t i; - int remove[count]; - size_t remove_count = 0; - - for (i = 0; i < count; i++) { - BerElement *ber = NULL; - char *attribute; - int exists = 0; - - if (mods[i]->mod_op != LDAP_MOD_DELETE) { - continue; - } - - /* If we are deleting something, it has to exist */ - attribute = ldap_first_attribute(ldapConn, entry, &ber); - while (attribute) { - if (!strcasecmp(attribute, mods[i]->mod_type)) { - /* OK, we have the attribute */ - exists = 1; - ldap_memfree(attribute); - break; - } + LDAPMod *mod; + char *type; - ldap_memfree(attribute); - attribute = ldap_next_attribute(ldapConn, entry, ber); - } + mod = ldap_memcalloc(1, sizeof(LDAPMod)); + type = ldap_strdup(attribute); - if (!exists) { - remove[remove_count++] = i; - } + if (!(mod && type)) { + ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n"); + ldap_memfree(type); + ldap_memfree(mod); + return NULL; } - if (remove_count) { - size_t k, remove_index; - LDAPMod **x = ldap_memcalloc(count - remove_count + 1, sizeof(LDAPMod *)); - for (i = 0, k = 0; i < count; i++) { - int skip = 0; - /* Is this one we have to remove? */ - for (remove_index = 0; !skip && remove_index < remove_count; remove_index++) { - skip = (remove[remove_index] == i); - } + mod->mod_type = type; - if (skip) { - ast_debug(3, "Skipping %s deletion because it doesn't exist\n", - mods[i]->mod_type); - continue; - } + if (strlen(new_value)) { + char **values, *value; + values = ldap_memcalloc(2, sizeof(char *)); + value = ldap_strdup(new_value); - x[k] = ldap_memcalloc(1, sizeof(LDAPMod)); - x[k]->mod_op = mods[i]->mod_op; - x[k]->mod_type = ldap_strdup(mods[i]->mod_type); - if (mods[i]->mod_values) { - x[k]->mod_values = ldap_memcalloc(2, sizeof(char *)); - x[k]->mod_values[0] = ldap_strdup(mods[i]->mod_values[0]); - } - k++; + if (!(values && value)) { + ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n"); + ldap_memfree(value); + ldap_memfree(values); + ldap_memfree(type); + ldap_memfree(mod); + return NULL; } - /* NULL terminate */ - x[k] = NULL; - return x; + + mod->mod_op = LDAP_MOD_REPLACE; + mod->mod_values = values; + mod->mod_values[0] = value; + } else { + mod->mod_op = LDAP_MOD_DELETE; } - return NULL; + return mod; } - -/* \brief Function to update a set of values in ldap static mode +/*! + * \internal + * \brief Append a value to an existing LDAP modification structure + * + * \param src the LDAPMod to update + * \param new_value the new value to append to the LDAPMod + * + * \returns the \c src original passed in if successful, NULL otherwise. */ -static int update_ldap(const char *basedn, const char *table_name, const char *attribute, - const char *lookup, const struct ast_variable *fields) +static LDAPMod *ldap_mod_append(LDAPMod *src, const char *new_value) { - int error = 0; - LDAPMessage *ldap_entry = NULL; - LDAPMod **ldap_mods; - const char *newparam; - const struct ast_variable *field = fields; - char *dn; - int num_entries = 0; - int i = 0; - int mods_size = 0; - int mod_exists = 0; - struct ldap_table_config *table_config = NULL; - char *clean_basedn = NULL; - struct ast_str *filter = NULL; - int tries = 0; - int result = 0; - LDAPMessage *ldap_result_msg = NULL; + char *new_buffer; - if (!table_name) { - ast_log(LOG_ERROR, "No table_name specified.\n"); - return -1; - } - - if (!(filter = ast_str_create(80))) { - return -1; + if (src->mod_op != LDAP_MOD_REPLACE) { + return src; } - if (!attribute || !lookup) { - ast_log(LOG_WARNING, "Search parameters are empty.\n"); - return -1; - } - ast_mutex_lock(&ldap_lock); + new_buffer = ldap_memrealloc( + src->mod_values[0], + strlen(src->mod_values[0]) + strlen(new_value) + sizeof(";")); - /* We now have our complete statement; Lets connect to the server and execute it. */ - if (!ldap_reconnect()) { - ast_mutex_unlock(&ldap_lock); - return -1; + if (!new_buffer) { + ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n"); + return NULL; } - table_config = table_config_for_table_name(table_name); - if (!table_config) { - ast_log(LOG_ERROR, "No table named '%s'.\n", table_name); - ast_mutex_unlock(&ldap_lock); - return -1; - } + strcat(new_buffer, ";"); + strcat(new_buffer, new_value); - clean_basedn = cleaned_basedn(NULL, basedn); + src->mod_values[0] = new_buffer; - /* Create the filter with the table additional filter and the parameter/value pairs we were given */ - ast_str_append(&filter, 0, "(&"); - if (table_config && table_config->additional_filter) { - ast_str_append(&filter, 0, "%s", table_config->additional_filter); - } - if (table_config != base_table_config && base_table_config && base_table_config->additional_filter) { - ast_str_append(&filter, 0, "%s", base_table_config->additional_filter); - } - append_var_and_value_to_filter(&filter, table_config, attribute, lookup); - ast_str_append(&filter, 0, ")"); + return src; +} - /* Create the modification array with the parameter/value pairs we were given, - * if there are several parameters with the same name, we collect them into - * one parameter/value pair and delimit them with a semicolon */ - newparam = convert_attribute_name_to_ldap(table_config, field->name); - if (!newparam) { - ast_log(LOG_WARNING, "Need at least one parameter to modify.\n"); - return -1; +/*! + * \internal + * \brief Duplicates an LDAP modification structure + * + * \param src the LDAPMod to duplicate + * + * \returns a deep copy of \c src if successful, NULL otherwise. + */ +static LDAPMod *ldap_mod_duplicate(const LDAPMod *src) +{ + LDAPMod *mod; + char *type, **values = NULL; + + mod = ldap_memcalloc(1, sizeof(LDAPMod)); + type = ldap_strdup(src->mod_type); + + if (!(mod && type)) { + ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n"); + ldap_memfree(type); + ldap_memfree(mod); + return NULL; } - mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */ - ldap_mods = ldap_memcalloc(mods_size, sizeof(LDAPMod *)); - ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod)); - ldap_mods[0]->mod_type = ldap_strdup(newparam); + if (src->mod_op == LDAP_MOD_REPLACE) { + char *value; - if (strlen(field->value) == 0) { - ldap_mods[0]->mod_op = LDAP_MOD_DELETE; - } else { - ldap_mods[0]->mod_op = LDAP_MOD_REPLACE; - ldap_mods[0]->mod_values = ldap_memcalloc(2, sizeof(char *)); - ldap_mods[0]->mod_values[0] = ldap_strdup(field->value); - } - - while ((field = field->next)) { - newparam = convert_attribute_name_to_ldap(table_config, field->name); - mod_exists = 0; - - for (i = 0; i < mods_size - 1; i++) { - if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) { - /* We have the parameter allready, adding the value as a semicolon delimited value */ - ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2)); - strcat(ldap_mods[i]->mod_values[0], ";"); - strcat(ldap_mods[i]->mod_values[0], field->value); - mod_exists = 1; - break; - } + values = ldap_memcalloc(2, sizeof(char *)); + value = ldap_strdup(src->mod_values[0]); + + if (!(values && value)) { + ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n"); + ldap_memfree(value); + ldap_memfree(values); + ldap_memfree(type); + ldap_memfree(mod); + return NULL; } - /* create new mod */ - if (!mod_exists) { - mods_size++; - ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size); - ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod)); - ldap_mods[mods_size - 2]->mod_type = ldap_strdup(newparam); + values[0] = value; + } - if (strlen(field->value) == 0) { - ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE; - } else { - ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE; - ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(2, sizeof(char *)); - ldap_mods[mods_size - 2]->mod_values[0] = ldap_strdup(field->value); - } + mod->mod_op = src->mod_op; + mod->mod_type = type; + mod->mod_values = values; + return mod; +} - /* NULL terminate */ - ldap_mods[mods_size - 1] = NULL; +/*! + * \internal + * \brief Search for an existing LDAP modification structure + * + * \param modifications a NULL terminated array of LDAP modification structures + * \param lookup the attribute name to search for + * + * \returns an LDAPMod * if successful, NULL otherwise. + */ +static LDAPMod *ldap_mod_find(LDAPMod **modifications, const char *lookup) +{ + size_t i; + for (i = 0; modifications[i]; i++) { + if (modifications[i]->mod_op == LDAP_MOD_REPLACE && + !strcasecmp(modifications[i]->mod_type, lookup)) { + return modifications[i]; } } - /* freeing ldap_mods further down */ + return NULL; +} - do { - /* freeing ldap_result further down */ - result = ldap_search_ext_s(ldapConn, clean_basedn, - LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, - &ldap_result_msg); - if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) { - ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1); - tries++; - if (tries < 3) { - usleep(500000L * tries); - if (ldapConn) { - ldap_unbind_ext_s(ldapConn, NULL, NULL); - ldapConn = NULL; - } - if (!ldap_reconnect()) - break; - } +/*! + * \internal + * \brief Determine if an LDAP entry has the specified attribute + * + * \param entry the LDAP entry to examine + * \param lookup the attribute name to search for + * + * \returns 1 if the attribute was found, 0 otherwise. + */ +static int ldap_entry_has_attribute(LDAPMessage *entry, const char *lookup) +{ + BerElement *ber = NULL; + char *attribute; + + attribute = ldap_first_attribute(ldapConn, entry, &ber); + while (attribute) { + if (!strcasecmp(attribute, lookup)) { + ldap_memfree(attribute); + ber_free(ber, 0); + return 1; } - } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result)); + ldap_memfree(attribute); + attribute = ldap_next_attribute(ldapConn, entry, ber); + } + ber_free(ber, 0); + return 0; +} - if (result != LDAP_SUCCESS) { - ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result)); - ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter)); +/*! + * \internal + * \brief Remove LDAP_MOD_DELETE modifications that will not succeed + * + * \details + * A LDAP_MOD_DELETE operation will fail if the LDAP entry does not already have + * the corresponding attribute. Because we may be updating multiple LDAP entries + * in a single call to update_ldap(), we may need our own copy of the + * modifications array for each one. + * + * \note + * This function dynamically allocates memory. If it returns a non-NULL pointer, + * it is up to the caller to free it with ldap_mods_free() + * + * \returns an LDAPMod * if modifications needed to be removed, NULL otherwise. + */ +static LDAPMod **massage_mods_for_entry(LDAPMessage *entry, LDAPMod **mods) +{ + size_t k, i, remove_count; + LDAPMod **copies; - ast_mutex_unlock(&ldap_lock); - ast_free(filter); - ast_free(clean_basedn); - ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 1); - return -1; - } - /* Ready to update */ - if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) { - ast_debug(3, "Modifying %s=%s hits: %d\n", attribute, lookup, num_entries); - for (i = 0; option_debug > 2 && i < mods_size - 1; i++) { - if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) { - ast_debug(3, "%s=%s\n", ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]); - } else { - ast_debug(3, "deleting %s\n", ldap_mods[i]->mod_type); - } + for (i = remove_count = 0; mods[i]; i++) { + if (mods[i]->mod_op == LDAP_MOD_DELETE + && !ldap_entry_has_attribute(entry, mods[i]->mod_type)) { + remove_count++; } - ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); - - for (i = 0; ldap_entry; i++) { - LDAPMod **working = ldap_mods; - LDAPMod **massaged = massage_mods_for_entry(ldap_entry, ldap_mods, mods_size - 1); - - if (massaged) { - /* Did we massage everything out of the list? */ - if (massaged[0] == NULL) { - ast_debug(3, "Nothing left to modify - skipping\n"); - ldap_mods_free(massaged, 1); - continue; - } - working = massaged; - } + } - dn = ldap_get_dn(ldapConn, ldap_entry); - if ((error = ldap_modify_ext_s(ldapConn, dn, working, NULL, NULL)) != LDAP_SUCCESS) { - ast_log(LOG_ERROR, "Couldn't modify '%s'='%s', dn:%s because %s\n", - attribute, lookup, dn, ldap_err2string(error)); - } + if (!remove_count) { + return NULL; + } - if (massaged) { - ldap_mods_free(massaged, 1); - } + copies = ldap_memcalloc(i - remove_count + 1, sizeof(LDAPMod *)); + if (!copies) { + ast_log(LOG_ERROR, "Memory allocation failure massaging LDAP modification\n"); + return NULL; + } - ldap_memfree(dn); - ldap_entry = ldap_next_entry(ldapConn, ldap_entry); + for (i = k = 0; mods[i]; i++) { + if (mods[i]->mod_op != LDAP_MOD_DELETE + || ldap_entry_has_attribute(entry, mods[i]->mod_type)) { + copies[k] = ldap_mod_duplicate(mods[i]); + if (!copies[k]) { + ast_log(LOG_ERROR, "Memory allocation failure massaging LDAP modification\n"); + ldap_mods_free(copies, 1); + return NULL; + } + k++; + } else { + ast_debug(3, "Skipping %s deletion because it doesn't exist\n", + mods[i]->mod_type); } } - ast_mutex_unlock(&ldap_lock); - ast_free(filter); - ast_free(clean_basedn); - ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 1); - return num_entries; + return copies; +} + +/*! + * \internal + * \brief Count the number of variables in an ast_variables list + * + * \param vars the list of variables to count + * + * \returns the number of variables in the specified list + */ +static size_t variables_count(const struct ast_variable *vars) +{ + const struct ast_variable *var; + size_t count = 0; + for (var = vars; var; var = var->next) { + count++; + } + return count; } static int update2_ldap(const char *basedn, const char *table_name, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields) { - int error = 0; - LDAPMessage *ldap_entry = NULL; - LDAPMod **ldap_mods; - const char *newparam; const struct ast_variable *field; - char *dn; - int num_entries = 0; - int i = 0; - int mods_size = 0; - int mod_exists = 0; struct ldap_table_config *table_config = NULL; char *clean_basedn = NULL; struct ast_str *filter = NULL; + int search_result = 0; + int res = -1; int tries = 0; - int result = 0; + size_t update_count, update_index, entry_count; + + LDAPMessage *ldap_entry = NULL; + LDAPMod **modifications; LDAPMessage *ldap_result_msg = NULL; if (!table_name) { ast_log(LOG_ERROR, "No table_name specified.\n"); - return -1; - } + return res; + } - if (!(filter = ast_str_create(80))) { - return -1; + update_count = variables_count(update_fields); + if (!update_count) { + ast_log(LOG_WARNING, "Need at least one parameter to modify.\n"); + return res; } ast_mutex_lock(&ldap_lock); @@ -1528,93 +1515,40 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct /* We now have our complete statement; Lets connect to the server and execute it. */ if (!ldap_reconnect()) { ast_mutex_unlock(&ldap_lock); - ast_free(filter); - return -1; + return res; } table_config = table_config_for_table_name(table_name); if (!table_config) { ast_log(LOG_ERROR, "No table named '%s'.\n", table_name); ast_mutex_unlock(&ldap_lock); - ast_free(filter); - return -1; + return res; } clean_basedn = cleaned_basedn(NULL, basedn); - /* Create the filter with the table additional filter and the parameter/value pairs we were given */ - ast_str_append(&filter, 0, "(&"); - if (table_config && table_config->additional_filter) { - ast_str_append(&filter, 0, "%s", table_config->additional_filter); - } - if (table_config != base_table_config && base_table_config - && base_table_config->additional_filter) { - ast_str_append(&filter, 0, "%s", base_table_config->additional_filter); - } - - /* Get multiple lookup keyfields and values */ - for (field = lookup_fields; field; field = field->next) { - append_var_and_value_to_filter(&filter, table_config, field->name, field->value); - } - ast_str_append(&filter, 0, ")"); - - /* Create the modification array with the parameter/value pairs we were given, - * if there are several parameters with the same name, we collect them into - * one parameter/value pair and delimit them with a semicolon */ - field = update_fields; - newparam = convert_attribute_name_to_ldap(table_config, field->name); - if (!newparam) { - ast_log(LOG_WARNING, "Need at least one parameter to modify.\n"); - ast_free(filter); + filter = create_lookup_filter(table_config, lookup_fields); + if (!filter) { + ast_mutex_unlock(&ldap_lock); ast_free(clean_basedn); - return -1; + return res; } - mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */ - ldap_mods = ldap_memcalloc(mods_size, sizeof(LDAPMod *)); - ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod)); - ldap_mods[0]->mod_op = LDAP_MOD_REPLACE; - ldap_mods[0]->mod_type = ldap_strdup(newparam); - ldap_mods[0]->mod_values = ldap_memcalloc(2, sizeof(char *)); - ldap_mods[0]->mod_values[0] = ldap_strdup(field->value); - - while ((field = field->next)) { - newparam = convert_attribute_name_to_ldap(table_config, field->name); - mod_exists = 0; - - for (i = 0; i < mods_size - 1; i++) { - if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) { - /* We have the parameter allready, adding the value as a semicolon delimited value */ - ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2)); - strcat(ldap_mods[i]->mod_values[0], ";"); - strcat(ldap_mods[i]->mod_values[0], field->value); - mod_exists = 1; - break; - } - } - - /* create new mod */ - if (!mod_exists) { - mods_size++; - ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size); - ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod)); - ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE; - ldap_mods[mods_size - 2]->mod_type = ldap_strdup(newparam); - ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(2, sizeof(char *)); - ldap_mods[mods_size - 2]->mod_values[0] = ldap_strdup(field->value); - - /* NULL terminate */ - ldap_mods[mods_size - 1] = NULL; - } - } - /* freeing ldap_mods further down */ + /* + * Find LDAP records that match our lookup filter. If there are none, then + * we don't go through the hassle of building our modifications list. + */ do { - /* freeing ldap_result further down */ - result = ldap_search_ext_s(ldapConn, clean_basedn, - LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, - &ldap_result_msg); - if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) { + search_result = ldap_search_ext_s( + ldapConn, + clean_basedn, + LDAP_SCOPE_SUBTREE, + ast_str_buffer(filter), + NULL, 0, NULL, NULL, NULL, + LDAP_NO_LIMIT, + &ldap_result_msg); + if (search_result != LDAP_SUCCESS && is_ldap_connect_error(search_result)) { ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1); tries++; if (tries < 3) { @@ -1628,43 +1562,128 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct } } } - } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result)); + } while (search_result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(search_result)); - if (result != LDAP_SUCCESS) { - ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result)); + if (search_result != LDAP_SUCCESS) { + ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(search_result)); ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter)); + goto early_bailout; + } - ast_mutex_unlock(&ldap_lock); - ast_free(filter); - ast_free(clean_basedn); - ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 1); - return -1; + entry_count = ldap_count_entries(ldapConn, ldap_result_msg); + if (!entry_count) { + /* Nothing found, nothing to update */ + res = 0; + goto early_bailout; + } + + /* We need to NULL terminate, so we allocate one more than we need */ + modifications = ldap_memcalloc(update_count + 1, sizeof(LDAPMod *)); + if (!modifications) { + ast_log(LOG_ERROR, "Memory allocation failure\n"); + goto early_bailout; } + + /* + * Create the modification array with the parameter/value pairs we were given, + * if there are several parameters with the same name, we collect them into + * one parameter/value pair and delimit them with a semicolon + */ + for (field = update_fields, update_index = 0; field; field = field->next) { + LDAPMod *mod; + + const char *ldap_attribute_name = convert_attribute_name_to_ldap( + table_config, + field->name); + + /* See if we already have it */ + mod = ldap_mod_find(modifications, ldap_attribute_name); + if (mod) { + mod = ldap_mod_append(mod, field->value); + if (!mod) { + goto late_bailout; + } + } else { + mod = ldap_mod_create(ldap_attribute_name, field->value); + if (!mod) { + goto late_bailout; + } + modifications[update_index++] = mod; + } + } + /* Ready to update */ - if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) { - for (i = 0; option_debug > 2 && i < mods_size - 1; i++) { - ast_debug(3, "%s=%s\n", ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]); + ast_debug(3, "Modifying %zu matched entries\n", entry_count); + if (option_debug > 2) { + size_t i; + for (i = 0; modifications[i]; i++) { + if (modifications[i]->mod_op != LDAP_MOD_DELETE) { + ast_debug(3, "%s => %s\n", modifications[i]->mod_type, + modifications[i]->mod_values[0]); + } else { + ast_debug(3, "deleting %s\n", modifications[i]->mod_type); + } } + } - ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); + for (ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); + ldap_entry; + ldap_entry = ldap_next_entry(ldapConn, ldap_entry)) { + int error; + LDAPMod **massaged, **working; + + char *dn = ldap_get_dn(ldapConn, ldap_entry); + if (!dn) { + ast_log(LOG_ERROR, "Memory allocation failure\n"); + goto late_bailout; + } - for (i = 0; ldap_entry; i++) { - dn = ldap_get_dn(ldapConn, ldap_entry); - if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) { - ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error)); + working = modifications; + + massaged = massage_mods_for_entry(ldap_entry, modifications); + if (massaged) { + /* Did we massage everything out of the list? */ + if (!massaged[0]) { + ast_debug(3, "Nothing left to modify - skipping\n"); + ldap_mods_free(massaged, 1); + ldap_memfree(dn); + continue; } - ldap_memfree(dn); - ldap_entry = ldap_next_entry(ldapConn, ldap_entry); + working = massaged; + } + + if ((error = ldap_modify_ext_s(ldapConn, dn, working, NULL, NULL)) != LDAP_SUCCESS) { + ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error)); } + + if (massaged) { + ldap_mods_free(massaged, 1); + } + + ldap_memfree(dn); } - ast_mutex_unlock(&ldap_lock); + res = entry_count; + +late_bailout: + ldap_mods_free(modifications, 1); + +early_bailout: + ldap_msgfree(ldap_result_msg); ast_free(filter); ast_free(clean_basedn); - ldap_msgfree(ldap_result_msg); - ldap_mods_free(ldap_mods, 1); - return num_entries; + ast_mutex_unlock(&ldap_lock); + + return res; +} + +static int update_ldap(const char *basedn, const char *table_name, const char *attribute, const char *lookup, const struct ast_variable *fields) +{ + int res; + struct ast_variable *lookup_fields = ast_variable_new(attribute, lookup, ""); + res = update2_ldap(basedn, table_name, lookup_fields, fields); + ast_variables_destroy(lookup_fields); + return res; } static struct ast_config_engine ldap_engine = { From 094c26aa689664177e156d17bf5e9ab67c442a53 Mon Sep 17 00:00:00 2001 From: frahaase Date: Fri, 12 Aug 2016 18:23:18 +0200 Subject: [PATCH 1079/1578] Binaural synthesis (confbridge): Adds binaural synthesis to bridge_softmix. Adds binaural synthesis to bridge_softmix (via convolution using libfftw3). Binaural synthesis is conducted at 48kHz. For a conference, only one spatial representation is rendered. The default rendering is applied for mono-capable channels. ASTERISK-26292 Change-Id: Iecdb381b6adc17c961049658678f6219adae1ddf --- apps/app_confbridge.c | 1 + bridges/Makefile | 8 + bridges/bridge_softmix.c | 330 +- .../bridge_softmix/bridge_softmix_binaural.c | 579 + .../include/bridge_softmix_internal.h | 425 + bridges/bridge_softmix/include/hrirs.h | 50730 ++++++++++++++++ .../include/hrirs_configuration.h | 63 + bridges/bridges.xml | 8 + configure | 40 +- configure.ac | 12 +- include/asterisk/autoconfig.h.in | 7 +- include/asterisk/bridge.h | 10 + include/asterisk/bridge_channel.h | 11 + main/bridge.c | 7 + menuselect/menuselect.c | 8 +- menuselect/menuselect.h | 3 +- utils/.gitignore | 1 + utils/Makefile | 11 +- utils/conf_bridge_binaural_hrir_importer.c | 61 +- utils/conf_bridge_binaural_hrir_importer.h | 46 + utils/utils.xml | 13 +- 21 files changed, 52191 insertions(+), 183 deletions(-) create mode 100644 bridges/bridge_softmix/bridge_softmix_binaural.c create mode 100644 bridges/bridge_softmix/include/bridge_softmix_internal.h create mode 100644 bridges/bridge_softmix/include/hrirs.h create mode 100644 bridges/bridge_softmix/include/hrirs_configuration.h create mode 100644 bridges/bridges.xml create mode 100644 utils/conf_bridge_binaural_hrir_importer.h diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index d6229b93f65..c7c76ff6bc5 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1475,6 +1475,7 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen ast_bridge_set_internal_sample_rate(conference->bridge, conference->b_profile.internal_sample_rate); /* Set the internal mixing interval on the bridge from the bridge profile */ ast_bridge_set_mixing_interval(conference->bridge, conference->b_profile.mix_interval); + ast_bridge_set_binaural_active(conference->bridge, ast_test_flag(&conference->b_profile, BRIDGE_OPT_BINAURAL_ACTIVE)); if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) { ast_bridge_set_talker_src_video_mode(conference->bridge); diff --git a/bridges/Makefile b/bridges/Makefile index d887ae1f2c8..1baf267bacc 100644 --- a/bridges/Makefile +++ b/bridges/Makefile @@ -14,7 +14,15 @@ MODULE_PREFIX=bridge MENUSELECT_CATEGORY=BRIDGES MENUSELECT_DESCRIPTION=Bridging Modules +MODULE_EXCLUDE=binaural_rendering_in_bridge_softmix all: _all +ifeq ($(findstring binaural_rendering_in_bridge_softmix,$(MENUSELECT_BRIDGES)),) +bridge_softmix.o bridge_softmix/bridge_softmix_binaural.o: _ASTCFLAGS+=-DBINAURAL_RENDERING +bridge_softmix.so: LIBS+=$(FFTW3_LIB) +endif + include $(ASTTOPDIR)/Makefile.moddir_rules + +$(call MOD_ADD_C,bridge_softmix,$(wildcard bridge_softmix/*.c)) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index a0b14749716..7bac4fcb2a3 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -31,29 +31,8 @@ core ***/ -#include "asterisk.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "asterisk/module.h" -#include "asterisk/channel.h" -#include "asterisk/bridge.h" -#include "asterisk/bridge_technology.h" -#include "asterisk/frame.h" -#include "asterisk/options.h" -#include "asterisk/logger.h" -#include "asterisk/slinfactory.h" -#include "asterisk/astobj2.h" -#include "asterisk/timing.h" -#include "asterisk/translate.h" - -#define MAX_DATALEN 8096 + +#include "bridge_softmix/include/bridge_softmix_internal.h" /*! The minimum sample rate of the bridge. */ #define SOFTMIX_MIN_SAMPLE_RATE 8000 /* 8 kHz sample rate */ @@ -75,71 +54,6 @@ #define DEFAULT_SOFTMIX_SILENCE_THRESHOLD 2500 #define DEFAULT_SOFTMIX_TALKING_THRESHOLD 160 -#define DEFAULT_ENERGY_HISTORY_LEN 150 - -struct video_follow_talker_data { - /*! audio energy history */ - int energy_history[DEFAULT_ENERGY_HISTORY_LEN]; - /*! The current slot being used in the history buffer, this - * increments and wraps around */ - int energy_history_cur_slot; - /*! The current energy sum used for averages. */ - int energy_accum; - /*! The current energy average */ - int energy_average; -}; - -/*! \brief Structure which contains per-channel mixing information */ -struct softmix_channel { - /*! Lock to protect this structure */ - ast_mutex_t lock; - /*! Factory which contains audio read in from the channel */ - struct ast_slinfactory factory; - /*! Frame that contains mixed audio to be written out to the channel */ - struct ast_frame write_frame; - /*! Current expected read slinear format. */ - struct ast_format *read_slin_format; - /*! DSP for detecting silence */ - struct ast_dsp *dsp; - /*! - * \brief TRUE if a channel is talking. - * - * \note This affects how the channel's audio is mixed back to - * it. - */ - unsigned int talking:1; - /*! TRUE if the channel provided audio for this mixing interval */ - unsigned int have_audio:1; - /*! Buffer containing final mixed audio from all sources */ - short final_buf[MAX_DATALEN]; - /*! Buffer containing only the audio from the channel */ - short our_buf[MAX_DATALEN]; - /*! Data pertaining to talker mode for video conferencing */ - struct video_follow_talker_data video_talker; -}; - -struct softmix_bridge_data { - struct ast_timer *timer; - /*! - * \brief Bridge pointer passed to the softmix mixing thread. - * - * \note Does not need a reference because the bridge will - * always exist while the mixing thread exists even if the - * bridge is no longer actively using the softmix technology. - */ - struct ast_bridge *bridge; - /*! Lock for signaling the mixing thread. */ - ast_mutex_t lock; - /*! Condition, used if we need to wake up the mixing thread. */ - ast_cond_t cond; - /*! Thread handling the mixing */ - pthread_t thread; - unsigned int internal_rate; - unsigned int internal_mixing_interval; - /*! TRUE if the mixing thread should stop */ - unsigned int stop:1; -}; - struct softmix_stats { /*! Each index represents a sample rate used above the internal rate. */ unsigned int sample_rates[16]; @@ -155,12 +69,6 @@ struct softmix_stats { unsigned int locked_rate; }; -struct softmix_mixing_array { - unsigned int max_num_entries; - unsigned int used_entries; - int16_t **buffers; -}; - struct softmix_translate_helper_entry { int num_times_requested; /*!< Once this entry is no longer requested, free the trans_pvt and re-init if it was usable. */ @@ -263,14 +171,14 @@ static int16_t *softmix_process_read_audio(struct softmix_channel *sc, unsigned */ static void softmix_process_write_audio(struct softmix_translate_helper *trans_helper, struct ast_format *raw_write_fmt, - struct softmix_channel *sc) + struct softmix_channel *sc, unsigned int default_sample_size) { struct softmix_translate_helper_entry *entry = NULL; int i; /* If we provided audio that was not determined to be silence, * then take it out while in slinear format. */ - if (sc->have_audio && sc->talking) { + if (sc->have_audio && sc->talking && !sc->binaural) { for (i = 0; i < sc->write_frame.samples; i++) { ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]); } @@ -285,6 +193,13 @@ static void softmix_process_write_audio(struct softmix_translate_helper *trans_h /* do not do any special write translate optimization if we had to make * a special mix for them to remove their own audio. */ return; + } else if (sc->have_audio && sc->talking && sc->binaural > 0) { + /* + * Binaural audio requires special saturated substract since we have two + * audio signals per channel now. + */ + softmix_process_write_binaural_audio(sc, default_sample_size); + return; } /* Attempt to optimize channels using the same translation path/codec. Build a list of entries @@ -293,6 +208,9 @@ static void softmix_process_write_audio(struct softmix_translate_helper *trans_h multiple channels (>=2) using the same codec make sure resources are allocated only when needed and released when not (see also softmix_translate_helper_cleanup */ AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) { + if (sc->binaural != 0) { + continue; + } if (ast_format_cmp(entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) { entry->num_times_requested++; } else { @@ -351,12 +269,18 @@ static void softmix_translate_helper_cleanup(struct softmix_translate_helper *tr AST_LIST_TRAVERSE_SAFE_END; } -static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset) +static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset, int set_binaural, int binaural_pos_id, int is_announcement) { struct softmix_channel *sc = bridge_channel->tech_pvt; struct ast_format *slin_format; int setup_fail; +#ifdef BINAURAL_RENDERING + if (interval != BINAURAL_MIXING_INTERVAL) { + interval = BINAURAL_MIXING_INTERVAL; + } +#endif + /* The callers have already ensured that sc is never NULL. */ ast_assert(sc != NULL); @@ -381,6 +305,26 @@ static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_ch sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval); sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval); + /* We will store the rate here cause we need to set the data again when a channel is unsuspended */ + sc->rate = rate; + + /* If the channel will contain binaural data we will set a identifier in the channel + * if set_binaural == -1 this is just a sample rate update, will ignore it. */ + if (set_binaural == 1) { + sc->binaural = 1; + } else if (set_binaural == 0) { + sc->binaural = 0; + } + + /* Setting the binaural position. This doesn't require a change of the overlaying channel infos + * and doesn't have to be done if we just updating sample rates. */ + if (binaural_pos_id != -1) { + sc->binaural_pos = binaural_pos_id; + } + if (is_announcement != -1) { + sc->is_announcement = is_announcement; + } + /* * NOTE: The read_slin_format does not hold a reference because it * will always be a signed linear format. @@ -395,7 +339,13 @@ static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_ch setup_fail |= ast_set_read_format_path(bridge_channel->chan, ast_channel_rawreadformat(bridge_channel->chan), slin_format); ast_channel_unlock(bridge_channel->chan); - setup_fail |= ast_set_write_format(bridge_channel->chan, slin_format); + + /* If channel contains binaural data we will set it here for the trans_pvt. */ + if (set_binaural == 1 || (set_binaural == -1 && sc->binaural == 1)) { + setup_fail |= ast_set_write_format_interleaved_stereo(bridge_channel->chan, slin_format); + } else if (set_binaural == 0) { + setup_fail |= ast_set_write_format(bridge_channel->chan, slin_format); + } /* set up new DSP. This is on the read side only right before the read frame enters the smoother. */ sc->dsp = ast_dsp_new_with_rate(rate); @@ -435,6 +385,16 @@ static void softmix_poke_thread(struct softmix_bridge_data *softmix_data) /*! \brief Function called when a channel is unsuspended from the bridge */ static void softmix_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { +#ifdef BINAURAL_RENDERING + struct softmix_channel *sc = bridge_channel->tech_pvt; + if (sc->binaural) { + /* Restore some usefull data if it was a binaural channel */ + struct ast_format *slin_format; + + slin_format = ast_format_cache_get_slin_by_rate(sc->rate); + ast_set_write_format_interleaved_stereo(bridge_channel->chan, slin_format); + } +#endif if (bridge->tech_pvt) { softmix_poke_thread(bridge->tech_pvt); } @@ -445,6 +405,15 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan { struct softmix_channel *sc; struct softmix_bridge_data *softmix_data; + int set_binaural = 0; + /* + * If false, the channel will be convolved, but since it is a non stereo channel, output + * will be mono. + */ + int skip_binaural_output = 1; + int pos_id; + int is_announcement = 0; + int samplerate_change; softmix_data = bridge->tech_pvt; if (!softmix_data) { @@ -456,6 +425,32 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan return -1; } + samplerate_change = softmix_data->internal_rate; + pos_id = -1; + if (bridge->softmix.binaural_active) { + if (strncmp(ast_channel_name(bridge_channel->chan), "CBAnn", 5) != 0) { + set_binaural = ast_format_get_channel_count(bridge_channel->write_format) > 1 ? 1 : 0; + if (set_binaural) { + softmix_data->internal_rate = samplerate_change; + } + skip_binaural_output = 0; + } else { + is_announcement = 1; + } + if (set_binaural) { + softmix_data->convolve.binaural_active = 1; + } + if (!skip_binaural_output) { + pos_id = set_binaural_data_join(&softmix_data->convolve, softmix_data->default_sample_size); + if (pos_id == -1) { + ast_log(LOG_ERROR, "Bridge %s: Failed to join channel %s. " + "Could not allocate enough memory.\n", bridge->uniqueid, + ast_channel_name(bridge_channel->chan)); + return -1; + } + } + } + /* Can't forget the lock */ ast_mutex_init(&sc->lock); @@ -466,7 +461,7 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan softmix_data->internal_mixing_interval ? softmix_data->internal_mixing_interval : DEFAULT_SOFTMIX_INTERVAL, - bridge_channel, 0); + bridge_channel, 0, set_binaural, pos_id, is_announcement); softmix_poke_thread(softmix_data); return 0; @@ -475,11 +470,23 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan /*! \brief Function called when a channel leaves the bridge */ static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { - struct softmix_channel *sc = bridge_channel->tech_pvt; + + struct softmix_channel *sc; + struct softmix_bridge_data *softmix_data; + softmix_data = bridge->tech_pvt; + sc = bridge_channel->tech_pvt; if (!sc) { return; } + + if (bridge->softmix.binaural_active) { + if (sc->binaural) { + set_binaural_data_leave(&softmix_data->convolve, sc->binaural_pos, + softmix_data->default_sample_size); + } + } + bridge_channel->tech_pvt = NULL; /* Drop mutex lock */ @@ -793,10 +800,15 @@ static void gather_softmix_stats(struct softmix_stats *stats, * \retval 0, no changes to internal rate * \retval 1, internal rate was changed, update all the channels on the next mixing iteration. */ -static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct softmix_bridge_data *softmix_data) +static unsigned int analyse_softmix_stats(struct softmix_stats *stats, + struct softmix_bridge_data *softmix_data, int binaural_active) { int i; + if (binaural_active) { + stats->locked_rate = SOFTMIX_BINAURAL_SAMPLE_RATE; + } + /* * Re-adjust the internal bridge sample rate if * 1. The bridge's internal sample rate is locked in at a sample @@ -868,7 +880,8 @@ static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct so return 0; } -static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array, unsigned int starting_num_entries) +static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array, + unsigned int starting_num_entries, unsigned int binaural_active) { memset(mixing_array, 0, sizeof(*mixing_array)); mixing_array->max_num_entries = starting_num_entries; @@ -876,23 +889,45 @@ static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array, ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure.\n"); return -1; } + if (binaural_active) { + if (!(mixing_array->chan_pairs = ast_calloc(mixing_array->max_num_entries, + sizeof(struct convolve_channel_pair *)))) { + ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure.\n"); + return -1; + } + } return 0; } -static void softmix_mixing_array_destroy(struct softmix_mixing_array *mixing_array) +static void softmix_mixing_array_destroy(struct softmix_mixing_array *mixing_array, + unsigned int binaural_active) { ast_free(mixing_array->buffers); + if (binaural_active) { + ast_free(mixing_array->chan_pairs); + } } -static int softmix_mixing_array_grow(struct softmix_mixing_array *mixing_array, unsigned int num_entries) +static int softmix_mixing_array_grow(struct softmix_mixing_array *mixing_array, + unsigned int num_entries, unsigned int binaural_active) { int16_t **tmp; + /* give it some room to grow since memory is cheap but allocations can be expensive */ mixing_array->max_num_entries = num_entries; if (!(tmp = ast_realloc(mixing_array->buffers, (mixing_array->max_num_entries * sizeof(int16_t *))))) { ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure.\n"); return -1; } + if (binaural_active) { + struct convolve_channel_pair **tmp2; + if (!(tmp2 = ast_realloc(mixing_array->chan_pairs, + (mixing_array->max_num_entries * sizeof(struct convolve_channel_pair *))))) { + ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure.\n"); + return -1; + } + mixing_array->chan_pairs = tmp2; + } mixing_array->buffers = tmp; return 0; } @@ -911,6 +946,10 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) struct ast_timer *timer; struct softmix_translate_helper trans_helper; int16_t buf[MAX_DATALEN]; +#ifdef BINAURAL_RENDERING + int16_t bin_buf[MAX_DATALEN]; + int16_t ann_buf[MAX_DATALEN]; +#endif unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */ int timingfd; int update_all_rates = 0; /* set this when the internal sample rate has changed */ @@ -924,7 +963,8 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval)); /* Give the mixing array room to grow, memory is cheap but allocations are expensive. */ - if (softmix_mixing_array_init(&mixing_array, bridge->num_channels + 10)) { + if (softmix_mixing_array_init(&mixing_array, bridge->num_channels + 10, + bridge->softmix.binaural_active)) { goto softmix_cleanup; } @@ -952,7 +992,8 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) /* Grow the mixing array buffer as participants are added. */ if (mixing_array.max_num_entries < bridge->num_channels - && softmix_mixing_array_grow(&mixing_array, bridge->num_channels + 5)) { + && softmix_mixing_array_grow(&mixing_array, bridge->num_channels + 5, + bridge->softmix.binaural_active)) { goto softmix_cleanup; } @@ -971,6 +1012,10 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) softmix_translate_helper_change_rate(&trans_helper, softmix_data->internal_rate); } +#ifdef BINAURAL_RENDERING + check_binaural_position_change(bridge, softmix_data, bridge_channel); +#endif + /* Go through pulling audio from each factory that has it available */ AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { struct softmix_channel *sc = bridge_channel->tech_pvt; @@ -982,7 +1027,8 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) /* Update the sample rate to match the bridge's native sample rate if necessary. */ if (update_all_rates) { - set_softmix_bridge_data(softmix_data->internal_rate, softmix_data->internal_mixing_interval, bridge_channel, 1); + set_softmix_bridge_data(softmix_data->internal_rate, + softmix_data->internal_mixing_interval, bridge_channel, 1, -1, -1, -1); } /* If stat_iteration_counter is 0, then collect statistics during this mixing interation */ @@ -998,12 +1044,16 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) /* Try to get audio from the factory if available */ ast_mutex_lock(&sc->lock); if ((mixing_array.buffers[mixing_array.used_entries] = softmix_process_read_audio(sc, softmix_samples))) { +#ifdef BINAURAL_RENDERING + add_binaural_mixing(bridge, softmix_data, softmix_samples, &mixing_array, sc, + ast_channel_name(bridge_channel->chan)); +#endif mixing_array.used_entries++; } ast_mutex_unlock(&sc->lock); } - /* mix it like crazy */ + /* mix it like crazy (non binaural channels)*/ memset(buf, 0, softmix_datalen); for (idx = 0; idx < mixing_array.used_entries; ++idx) { for (x = 0; x < softmix_samples; ++x) { @@ -1011,6 +1061,10 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) } } +#ifdef BINAURAL_RENDERING + binaural_mixing(bridge, softmix_data, &mixing_array, bin_buf, ann_buf); +#endif + /* Next step go through removing the channel's own audio and creating a good frame... */ AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { struct softmix_channel *sc = bridge_channel->tech_pvt; @@ -1025,12 +1079,22 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) /* Make SLINEAR write frame from local buffer */ ao2_t_replace(sc->write_frame.subclass.format, cur_slin, "Replace softmix channel slin format"); - sc->write_frame.datalen = softmix_datalen; - sc->write_frame.samples = softmix_samples; - memcpy(sc->final_buf, buf, softmix_datalen); - +#ifdef BINAURAL_RENDERING + if (bridge->softmix.binaural_active && softmix_data->convolve.binaural_active + && sc->binaural) { + create_binaural_frame(bridge_channel, sc, bin_buf, ann_buf, softmix_datalen, + softmix_samples, buf); + } else +#endif + { + sc->write_frame.datalen = softmix_datalen; + sc->write_frame.samples = softmix_samples; + memcpy(sc->final_buf, buf, softmix_datalen); + } /* process the softmix channel's new write audio */ - softmix_process_write_audio(&trans_helper, ast_channel_rawwriteformat(bridge_channel->chan), sc); + softmix_process_write_audio(&trans_helper, + ast_channel_rawwriteformat(bridge_channel->chan), sc, + softmix_data->default_sample_size); ast_mutex_unlock(&sc->lock); @@ -1040,7 +1104,8 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) update_all_rates = 0; if (!stat_iteration_counter) { - update_all_rates = analyse_softmix_stats(&stats, softmix_data); + update_all_rates = analyse_softmix_stats(&stats, softmix_data, + bridge->softmix.binaural_active); stat_iteration_counter = SOFTMIX_STAT_INTERVAL; } stat_iteration_counter--; @@ -1071,7 +1136,7 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) softmix_cleanup: softmix_translate_helper_destroy(&trans_helper); - softmix_mixing_array_destroy(&mixing_array); + softmix_mixing_array_destroy(&mixing_array, bridge->softmix.binaural_active); return res; } @@ -1109,6 +1174,32 @@ static void *softmix_mixing_thread(void *data) continue; } + if (bridge->softmix.binaural_active && !softmix_data->binaural_init) { +#ifndef BINAURAL_RENDERING + ast_bridge_lock(bridge); + bridge->softmix.binaural_active = 0; + ast_bridge_unlock(bridge); + ast_log(LOG_WARNING, "Bridge: %s: Binaural rendering active by config but not " + "compiled.\n", bridge->uniqueid); +#else + /* Set and init binaural data if binaural is activated in the configuration. */ + softmix_data->internal_rate = SOFTMIX_BINAURAL_SAMPLE_RATE; + softmix_data->default_sample_size = SOFTMIX_SAMPLES(softmix_data->internal_rate, + softmix_data->internal_mixing_interval); + /* If init for binaural processing fails we will fall back to mono audio processing. */ + if (init_convolve_data(&softmix_data->convolve, softmix_data->default_sample_size) + == -1) { + ast_bridge_lock(bridge); + bridge->softmix.binaural_active = 0; + ast_bridge_unlock(bridge); + ast_log(LOG_ERROR, "Bridge: %s: Unable to allocate memory for " + "binaural processing, Will only process mono audio.\n", + bridge->uniqueid); + } + softmix_data->binaural_init = 1; +#endif + } + if (softmix_mixing_loop(bridge)) { /* * A mixing error occurred. Sleep and try again later so we @@ -1160,6 +1251,11 @@ static int softmix_bridge_create(struct ast_bridge *bridge) softmix_data->internal_rate = SOFTMIX_MIN_SAMPLE_RATE; softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL; +#ifdef BINAURAL_RENDERING + softmix_data->default_sample_size = SOFTMIX_SAMPLES(softmix_data->internal_rate, + softmix_data->internal_mixing_interval); +#endif + bridge->tech_pvt = softmix_data; /* Start the mixing thread. */ @@ -1219,7 +1315,9 @@ static void softmix_bridge_destroy(struct ast_bridge *bridge) ast_debug(1, "Bridge %s: Waiting for mixing thread to die.\n", bridge->uniqueid); pthread_join(thread, NULL); } - +#ifdef BINAURAL_RENDERING + free_convolve_data(&softmix_data->convolve); +#endif softmix_bridge_data_destroy(softmix_data); bridge->tech_pvt = NULL; } diff --git a/bridges/bridge_softmix/bridge_softmix_binaural.c b/bridges/bridge_softmix/bridge_softmix_binaural.c new file mode 100644 index 00000000000..128e4640e6c --- /dev/null +++ b/bridges/bridge_softmix/bridge_softmix_binaural.c @@ -0,0 +1,579 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Frank Haase, Dennis Guse + * + * Frank Haase + * Dennis Guse + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Multi-party software based binaural mixing + * + * \author Frank Haase + * \author Dennis Guse + * + * \ingroup bridges + */ + +#include "include/bridge_softmix_internal.h" + +#ifdef BINAURAL_RENDERING + #include "include/hrirs_configuration.h" +#endif + +/*! The number of prealloced channels when a bridge will be created. */ +#define CONVOLVE_CHANNEL_PREALLOC 3 +/*! Max size of the convolve buffer. */ +#define CONVOLVE_MAX_BUFFER 4096 +/*! The default sample size in an binaural environment with a two-channel + * codec at 48kHz is 960 samples. + */ +#define CONVOLUTION_SAMPLE_SIZE 960 + +#ifdef BINAURAL_RENDERING + #if SOFTMIX_BINAURAL_SAMPLE_RATE != HRIRS_SAMPLE_RATE + #error HRIRs are required to be SOFTMIX_BINAURAL_SAMPLE_RATE Hz. Please adjust hrirs.h accordingly. + #endif + #if CONVOLUTION_SAMPLE_SIZE < HRIRS_IMPULSE_LEN + #error HRIRS_IMPULSE_LEN cannot be longer than CONVOLUTION_SAMPLE_SIZE. Please adjust hrirs.h accordingly. + #endif +#endif + +void reset_channel_pair(struct convolve_channel_pair *channel_pair, + unsigned int default_sample_size) +{ + memset(channel_pair->chan_left.overlap_add, 0, sizeof(float) * default_sample_size); + memset(channel_pair->chan_right.overlap_add, 0, sizeof(float) * default_sample_size); +} + +void random_binaural_pos_change(struct softmix_bridge_data *softmix_data) +{ + /* + * We perform a shuffle of all channels, even the ones that aren't used at the + * moment of shuffling now. This has the efect that new members will be placed + * randomly too. + */ + unsigned int i; + unsigned int j; + struct convolve_channel_pair *tmp; + + if (softmix_data->convolve.chan_size < 2) { + return; + } + + srand(time(NULL)); + for (i = softmix_data->convolve.chan_size - 1; i > 0; i--) { + j = rand() % (i + 1); + tmp = softmix_data->convolve.cchan_pair[i]; + reset_channel_pair(tmp, softmix_data->default_sample_size); + softmix_data->convolve.cchan_pair[i] = softmix_data->convolve.cchan_pair[j]; + softmix_data->convolve.cchan_pair[j] = tmp; + } +} + +int do_convolve(struct convolve_channel *chan, int16_t *in_samples, + unsigned int in_sample_size, unsigned int hrtf_length) +{ +#ifdef BINAURAL_RENDERING + unsigned int i; + + if (in_sample_size != CONVOLUTION_SAMPLE_SIZE) { + return -1; + } + + /* FFT setting real part */ + for (i = 0; i < CONVOLUTION_SAMPLE_SIZE; i++) { + chan->fftw_in[i] = in_samples[i] * (FLT_MAX / SHRT_MAX); + } + + for (i = CONVOLUTION_SAMPLE_SIZE; i < hrtf_length; i++) { + chan->fftw_in[i] = 0; + } + fftw_execute(chan->fftw_plan); + + /* Imaginary mulitplication (frequency space). */ + /* First FFTW result has never an imaginary part. */ + chan->fftw_in[0] = chan->fftw_out[0] * chan->hrtf[0]; + for (i = 1; i < (hrtf_length / 2); i++) { + /* Real part */ + chan->fftw_in[i] = (chan->fftw_out[i] * chan->hrtf[i]) - + (chan->fftw_out[hrtf_length - i] * chan->hrtf[hrtf_length - i]); + /* Imaginary part */ + chan->fftw_in[hrtf_length - i] = (chan->fftw_out[i] * chan->hrtf[hrtf_length - i]) + + (chan->fftw_out[hrtf_length - i] * chan->hrtf[i]); + } + + /* The last (if even) FFTW result has never an imaginary part. */ + if (hrtf_length % 2 == 0) { + chan->fftw_in[hrtf_length / 2] = chan->fftw_out[hrtf_length / 2] * + chan->hrtf[hrtf_length / 2]; + } + + /* iFFT */ + fftw_execute(chan->fftw_plan_inverse); + /* Remove signal increase due to iFFT. */ + for (i = 0; i < hrtf_length; i++) { + chan->fftw_out[i] = chan->fftw_out[i] / (hrtf_length / 2); + } + + /* Save the block for overlapp add in the next itteration. */ + for (i = 0; i < in_sample_size; i++) { + chan->overlap_add[i] += chan->fftw_out[i]; + } + + /* Copy real part to the output, ignore the complex part. */ + for (i = 0; i < in_sample_size; i++) { + chan->out_data[i] = chan->overlap_add[i] * (SHRT_MAX / FLT_MAX); + chan->overlap_add[i] = chan->fftw_out[i + in_sample_size]; + } +#endif + return 0; +} + +struct convolve_channel_pair *do_convolve_pair(struct convolve_data *data, + unsigned int pos_id, int16_t *in_samples, unsigned int in_sample_size, + const char *channel_name) +{ + struct convolve_channel_pair *chan_pair; + + /* If a position has no active member we will not convolve. */ + if (data->pos_ids[pos_id] != 1) { + ast_log(LOG_ERROR, "Channel %s: Channel pair has no active member! (pos id = %d)\n", + channel_name, pos_id); + return NULL; + } + + chan_pair = data->cchan_pair[pos_id]; + if (do_convolve(&chan_pair->chan_left, in_samples, in_sample_size, data->hrtf_length)) { + ast_log(LOG_ERROR, "Channel %s: Binaural processing failed.", channel_name); + return NULL; + } + + if (do_convolve(&chan_pair->chan_right, in_samples, in_sample_size, data->hrtf_length)) { + ast_log(LOG_ERROR, "Channel %s: Binaural processing failed.", channel_name); + return NULL; + } + + return chan_pair; +} + +float *get_hrir(unsigned int chan_pos, unsigned int chan_side) +{ +#ifdef BINAURAL_RENDERING + if (chan_side == HRIRS_CHANNEL_LEFT) { + return hrirs_left[ast_binaural_positions[chan_pos]]; + } else if (chan_side == HRIRS_CHANNEL_RIGHT) { + return hrirs_right[ast_binaural_positions[chan_pos]]; + } +#else + ast_log(LOG_ERROR, "Requesting data for the binaural conference feature without " + "it beeing active.\n"); +#endif + + return NULL; +} + +int init_convolve_channel(struct convolve_channel *channel, unsigned int hrtf_len, + unsigned int chan_pos, unsigned int chan_side, unsigned int default_sample_size) +{ +#ifdef BINAURAL_RENDERING + unsigned int j; + float *hrir; + + /* Prepare FFTW. */ + channel->fftw_in = fftw_alloc_real(hrtf_len + 1); + if (channel->fftw_in == NULL) { + return -1; + } + + channel->fftw_out = fftw_alloc_real(hrtf_len + 1); + if (channel->fftw_out == NULL) { + fftw_free(channel->fftw_in); + return -1; + } + + memset(channel->fftw_in, 0, sizeof(double) * (hrtf_len + 1)); + memset(channel->fftw_out, 0, sizeof(double) * (hrtf_len + 1)); + + channel->fftw_plan = fftw_plan_r2r_1d(hrtf_len, channel->fftw_in, channel->fftw_out, + FFTW_R2HC, FFTW_PATIENT); + channel->fftw_plan_inverse = fftw_plan_r2r_1d(hrtf_len, channel->fftw_in, channel->fftw_out, + FFTW_HC2R, FFTW_PATIENT); + channel->out_data = ast_calloc(CONVOLVE_MAX_BUFFER, sizeof(int16_t)); + if (channel->out_data == NULL) { + fftw_free(channel->fftw_in); + fftw_free(channel->fftw_out); + return -1; + } + + /* Reuse positions if all positions are already used. */ + chan_pos = chan_pos % HRIRS_IMPULSE_SIZE; + + /* Get HRTF for the channels spatial position. */ + hrir = get_hrir(chan_pos, chan_side); + if (hrir == NULL) { + fftw_free(channel->fftw_in); + fftw_free(channel->fftw_out); + ast_free(channel->out_data); + return -1; + } + + for (j = 0; j < HRIRS_IMPULSE_LEN; j++) { + channel->fftw_in[j] = hrir[j]; + } + + for (j = HRIRS_IMPULSE_LEN; j < hrtf_len; j++) { + channel->fftw_in[j] = 0; + } + + fftw_execute(channel->fftw_plan); + channel->hrtf = fftw_alloc_real(hrtf_len); + if (channel->hrtf == NULL) { + fftw_free(channel->fftw_in); + fftw_free(channel->fftw_out); + ast_free(channel->out_data); + return -1; + } + + for (j = 0; j < hrtf_len; j++) { + channel->hrtf[j] = channel->fftw_out[j]; + } + channel->overlap_add = ast_calloc(default_sample_size, sizeof(float)); + + return 0; +#endif + return -1; +} + +int init_convolve_channel_pair(struct convolve_channel_pair *cchan_pair, + unsigned int hrtf_len, unsigned int chan_pos, unsigned int default_sample_size) +{ +#ifdef BINAURAL_RENDERING + unsigned int hrirs_pos = chan_pos * 2; + int success = 0; + + ast_debug(3, "Binaural pos for the new channel pair will be L: %d R: %d (pos id = %d)\n", + hrirs_pos, hrirs_pos + 1, chan_pos); + success = init_convolve_channel(&cchan_pair->chan_left, hrtf_len, chan_pos, HRIRS_CHANNEL_LEFT, + default_sample_size); + if (success == -1) { + return success; + } + + success = init_convolve_channel(&cchan_pair->chan_right, hrtf_len, chan_pos, + HRIRS_CHANNEL_RIGHT, default_sample_size); + if (success == -1) { + free_convolve_channel(&cchan_pair->chan_left); + } + + return success; +#else + ast_log(LOG_ERROR, "Requesting data for the binaural conference feature " + "without it beeing active.\n"); + + return -1; +#endif +} + +int init_convolve_data(struct convolve_data *data, unsigned int default_sample_size) +{ + unsigned int i; + unsigned int j; + int success; + success = 0; + + data->pos_ids = ast_calloc(sizeof(int), sizeof(int) * CONVOLVE_CHANNEL_PREALLOC); + if (data->pos_ids == NULL) { + return -1; + } + data->chan_size = CONVOLVE_CHANNEL_PREALLOC; + data->number_channels = 0; + data->cchan_pair = ast_malloc(sizeof(struct convolve_channel_pair *) * + CONVOLVE_CHANNEL_PREALLOC); + if (data->cchan_pair == NULL) { + ast_free(data->pos_ids); + return -1; + } + + for (i = 0; i < CONVOLVE_CHANNEL_PREALLOC; i++) { + data->cchan_pair[i] = ast_malloc(sizeof(struct convolve_channel_pair)); + if (data->cchan_pair[i] == NULL) { + ast_free(data->pos_ids); + for (j = 0; j < i; j++) { + ast_free(data->cchan_pair[j]); + } + ast_free(data->cchan_pair); + return -1; + } + } + + data->hrtf_length = (default_sample_size * 2) - 1; + for (i = 0; i < CONVOLVE_CHANNEL_PREALLOC; i++) { + success = init_convolve_channel_pair(data->cchan_pair[i], data->hrtf_length, i, + default_sample_size); + if (success == -1) { + ast_free(data->pos_ids); + for (j = 0; j < i; j++) { + free_convolve_channel_pair(data->cchan_pair[j]); + } + for (j = 0; j < CONVOLVE_CHANNEL_PREALLOC; j++) { + ast_free(data->cchan_pair[j]); + } + return -1; + } + } + + return success; +} + +void free_convolve_channel(struct convolve_channel *cchan) +{ +#ifdef BINAURAL_RENDERING + fftw_free(cchan->fftw_out); + fftw_free(cchan->fftw_in); + fftw_free(cchan->hrtf); + ast_free(cchan->overlap_add); + ast_free(cchan->out_data); + fftw_destroy_plan(cchan->fftw_plan); + fftw_destroy_plan(cchan->fftw_plan_inverse); +#endif +} + +void free_convolve_channel_pair(struct convolve_channel_pair *cchan_pair) +{ + free_convolve_channel(&cchan_pair->chan_left); + free_convolve_channel(&cchan_pair->chan_right); +} + +void free_convolve_data(struct convolve_data *data) +{ + unsigned int i; + ast_free(data->pos_ids); + for (i = 0; i < data->chan_size; i++) { + free_convolve_channel_pair(data->cchan_pair[i]); + ast_free(data->cchan_pair[i]); + } + ast_free(data->cchan_pair); +} + +int set_binaural_data_join(struct convolve_data *data, unsigned int default_sample_size) +{ + struct convolve_channel_pair **cchan_pair_tmp; + unsigned int i; + int *pos_ids_tmp; + + /* Raise the number of input channels. */ + data->number_channels++; + /* We realloc another channel pair if we are out of prealloced ones. */ + /* We have prealloced one at the beginning of a conference and if a member leaves. */ + if (data->chan_size < data->number_channels) { + data->chan_size += 1; + + pos_ids_tmp = ast_realloc(data->pos_ids, data->chan_size * sizeof(int)); + if (pos_ids_tmp) { + data->pos_ids = pos_ids_tmp; + } else { + goto binaural_join_fails; + } + + data->pos_ids[data->chan_size - 1] = 0; + cchan_pair_tmp = ast_realloc(data->cchan_pair, + data->chan_size * sizeof(struct convolve_channel_pair *)); + if (cchan_pair_tmp) { + data->cchan_pair = cchan_pair_tmp; + } else { + goto binaural_join_fails; + } + + data->cchan_pair[data->chan_size - 1] = ast_malloc(sizeof(struct convolve_channel_pair)); + if (data->cchan_pair[data->chan_size - 1] == NULL) { + goto binaural_join_fails; + } + + i = init_convolve_channel_pair(data->cchan_pair[data->chan_size - 1], data->hrtf_length, + data->chan_size - 1, default_sample_size); + if (i == -1) { + goto binaural_join_fails; + } + } + + for (i = 0; i < data->chan_size; i++) { + if (data->pos_ids[i] == 0) { + data->pos_ids[i] = 1; + break; + } + } + + return i; + +binaural_join_fails: + data->number_channels--; + data->chan_size -= 1; + + return -1; +} + +void set_binaural_data_leave(struct convolve_data *data, unsigned int pos, + unsigned int default_sample_size) +{ + if (pos >= data->chan_size || data->pos_ids[pos] == 0) { + return; + } + + reset_channel_pair(data->cchan_pair[pos], default_sample_size); + data->number_channels--; + data->pos_ids[pos] = 0; +} + +void softmix_process_write_binaural_audio(struct softmix_channel *sc, + unsigned int default_sample_size) +{ + unsigned int i; + + if (sc->write_frame.samples % default_sample_size != 0) { + return; + } + + /* If binaural is suspended, the source audio (mono) will be removed. */ + if (sc->binaural_suspended) { + for (i = 0; i < default_sample_size; i++) { + ast_slinear_saturated_subtract(&sc->final_buf[i * 2], &sc->our_buf[i]); + ast_slinear_saturated_subtract(&sc->final_buf[(i * 2) + 1], &sc->our_buf[i]); + } + return; + } + + /* If binaural is NOT suspended, the source audio (binaural) will be removed. */ + for (i = 0; i < default_sample_size; i++) { + ast_slinear_saturated_subtract(&sc->final_buf[i * 2], + &sc->our_chan_pair->chan_left.out_data[i]); + ast_slinear_saturated_subtract(&sc->final_buf[(i * 2) + 1], + &sc->our_chan_pair->chan_right.out_data[i]); + } +} + +void check_binaural_position_change(struct ast_bridge *bridge, + struct softmix_bridge_data *softmix_data, struct ast_bridge_channel *bridge_channel) +{ + unsigned int pos_change; + + /* + * We only check binaural things if binaural is activated by the config + * and at least one binaural channel joined. + */ + if (!(bridge->softmix.binaural_active && softmix_data->convolve.binaural_active)) { + return; + } + /* + * Before we pull any audio, we must check if any channel requests a + * change of binaural positions. + */ + pos_change = 0; + AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { + if (!bridge_channel->binaural_pos_change) { + continue; + } + ast_bridge_channel_lock_bridge(bridge_channel); + bridge_channel->binaural_pos_change = 0; + ast_bridge_unlock(bridge_channel->bridge); + pos_change = 1; + } + + if (pos_change) { + random_binaural_pos_change(softmix_data); + } +} + +void add_binaural_mixing(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, + unsigned int softmix_samples, struct softmix_mixing_array *mixing_array, + struct softmix_channel *sc, const char *channel_name) +{ + struct convolve_channel_pair *pair; + + pair = NULL; + /* We only check binaural things if at least one binaural channel joined. */ + if (!(bridge->softmix.binaural_active && softmix_data->convolve.binaural_active + && (softmix_samples % CONVOLUTION_SAMPLE_SIZE) == 0)) { + return; + } + + if (!sc->is_announcement) { + pair = do_convolve_pair(&softmix_data->convolve, sc->binaural_pos, + mixing_array->buffers[mixing_array->used_entries], softmix_samples, channel_name); + } + sc->our_chan_pair = pair; + mixing_array->chan_pairs[mixing_array->used_entries] = pair; +} + +void binaural_mixing(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, + struct softmix_mixing_array *mixing_array, int16_t *bin_buf, int16_t *ann_buf) +{ + unsigned int idx; + unsigned int x; + + if (!(bridge->softmix.binaural_active && softmix_data->convolve.binaural_active)) { + return; + } + /* mix it like crazy (binaural channels) */ + memset(bin_buf, 0, MAX_DATALEN); + memset(ann_buf, 0, MAX_DATALEN); + + for (idx = 0; idx < mixing_array->used_entries; idx++) { + if (mixing_array->chan_pairs[idx] == NULL) { + for (x = 0; x < softmix_data->default_sample_size; x++) { + ast_slinear_saturated_add(bin_buf + (x * 2), mixing_array->buffers[idx] + x); + ast_slinear_saturated_add(bin_buf + (x * 2) + 1, mixing_array->buffers[idx] + x); + ann_buf[x * 2] = mixing_array->buffers[idx][x]; + ann_buf[(x * 2) + 1] = mixing_array->buffers[idx][x]; + } + } else { + for (x = 0; x < softmix_data->default_sample_size; x++) { + ast_slinear_saturated_add(bin_buf + (x * 2), + mixing_array->chan_pairs[idx]->chan_left.out_data + x); + ast_slinear_saturated_add(bin_buf + (x * 2) + 1, + mixing_array->chan_pairs[idx]->chan_right.out_data + x); + } + } + } +} + +void create_binaural_frame(struct ast_bridge_channel *bridge_channel, + struct softmix_channel *sc, int16_t *bin_buf, int16_t *ann_buf, + unsigned int softmix_datalen, unsigned int softmix_samples, int16_t *buf) +{ + unsigned int i; + + sc->write_frame.datalen = softmix_datalen * 2; + sc->write_frame.samples = softmix_samples * 2; + if (!bridge_channel->binaural_suspended) { + sc->binaural_suspended = 0; + if (sc->is_announcement) { + memcpy(sc->final_buf, ann_buf, softmix_datalen * 2); + } else { + memcpy(sc->final_buf, bin_buf, softmix_datalen * 2); + } + return; + } + + /* + * Mark that binaural output is suspended, since we use two channel audio + * we copy the same signals into both channels. + */ + sc->binaural_suspended = 1; + for (i = 0; i < softmix_samples; i++) { + sc->final_buf[i * 2] = buf[i]; + sc->final_buf[(i * 2) + 1] = buf[i]; + } +} diff --git a/bridges/bridge_softmix/include/bridge_softmix_internal.h b/bridges/bridge_softmix/include/bridge_softmix_internal.h new file mode 100644 index 00000000000..9daae4ce8a0 --- /dev/null +++ b/bridges/bridge_softmix/include/bridge_softmix_internal.h @@ -0,0 +1,425 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * Joshua Colp + * David Vossel + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Multi-party software based channel mixing (header) + * + * \author Joshua Colp + * \author David Vossel + * + * \ingroup bridges + */ + +#ifndef _ASTERISK_BRIDGE_SOFTMIX_INTERNAL_H +#define _ASTERISK_BRIDGE_SOFTMIX_INTERNAL_H + +#include "asterisk.h" +#include +#include +#include +#include +#include +#include +#include + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/bridge.h" +#include "asterisk/bridge_technology.h" +#include "asterisk/frame.h" +#include "asterisk/options.h" +#include "asterisk/logger.h" +#include "asterisk/slinfactory.h" +#include "asterisk/astobj2.h" +#include "asterisk/timing.h" +#include "asterisk/translate.h" + +#ifdef BINAURAL_RENDERING +#include +#endif + +#if defined(__Darwin__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__) +#include +#else +#include +#endif + +#define MAX_DATALEN 8096 +#define DEFAULT_ENERGY_HISTORY_LEN 150 + +/*! Setting the sample rate to 48000 by default if binaural is activated. */ +#define SOFTMIX_BINAURAL_SAMPLE_RATE 48000 +/*! We only support 20 ms interval length with binaural data at the moment. */ +#define BINAURAL_MIXING_INTERVAL 20 + +struct convolve_channel { + /*! The head related transfer function used for convolving */ + double *hrtf; + /*! Input signals for fftw */ + double *fftw_in; + /*! Output signals from the fftw */ + double *fftw_out; + /*! Signals for overlap add */ + float *overlap_add; + /*! The resulting data after the convolution */ + int16_t *out_data; +#ifdef BINAURAL_RENDERING + /*! The fftw plan for binaural signaling */ + fftw_plan fftw_plan; + /*! The inverse fftw plan for binaural signaling */ + fftw_plan fftw_plan_inverse; +#endif +}; + +struct convolve_channel_pair { + /*! The left channel of a stereo channel pair */ + struct convolve_channel chan_left; + /*! The right channel of a stereo channel pair */ + struct convolve_channel chan_right; +}; + +struct convolve_data { + /*! A count of all channels potentialy having input data for the conference. */ + int number_channels; + /*! Will set to true if there is at least one binaural output. + * Only if set to true data will be convolved. */ + int binaural_active; + /*! The length of the head related transfer function */ + unsigned int hrtf_length; + /*! Number of channels available for convolving. + * We do not delete a channel when a member leaves, cause we can reuse it for the next one. */ + int chan_size; + /*! The positions of the single channels in the virtual room */ + int *pos_ids; + /*! Each channel has a stereo pair of channels for the convolution */ + struct convolve_channel_pair **cchan_pair; +}; + +struct video_follow_talker_data { + /*! audio energy history */ + int energy_history[DEFAULT_ENERGY_HISTORY_LEN]; + /*! The current slot being used in the history buffer, this + * increments and wraps around */ + int energy_history_cur_slot; + /*! The current energy sum used for averages. */ + int energy_accum; + /*! The current energy average */ + int energy_average; +}; + +/*! \brief Structure which contains per-channel mixing information */ +struct softmix_channel { + /*! Lock to protect this structure */ + ast_mutex_t lock; + /*! Factory which contains audio read in from the channel */ + struct ast_slinfactory factory; + /*! Frame that contains mixed audio to be written out to the channel */ + struct ast_frame write_frame; + /*! Current expected read slinear format. */ + struct ast_format *read_slin_format; + /*! DSP for detecting silence */ + struct ast_dsp *dsp; + /*! + * \brief TRUE if a channel is talking. + * + * \note This affects how the channel's audio is mixed back to + * it. + */ + unsigned int talking:1; + /*! TRUE if the channel provided audio for this mixing interval */ + unsigned int have_audio:1; + /*! We set binaural also as channel data, to have better tracking. + * It is also present in transpvt. + */ + unsigned int binaural:1; + /*! TRUE if this is an announcement channel (data will not be convolved) */ + unsigned int is_announcement:1; + /*! The position of the channel in the virtual room represented by an id + * This ID has to be set even if the channel has no binaural output! + */ + unsigned int binaural_pos; + /*! The channel pair for this channel */ + struct convolve_channel_pair *our_chan_pair; + /*! Marks the channel for suspending all binaural activity on the output */ + unsigned int binaural_suspended:1; + /*! Channel sample rate, stored to retrieve it after unsuspending the channel */ + int rate; + /*! Buffer containing final mixed audio from all sources */ + short final_buf[MAX_DATALEN]; + /*! Buffer containing only the audio from the channel */ + short our_buf[MAX_DATALEN]; + /*! Data pertaining to talker mode for video conferencing */ + struct video_follow_talker_data video_talker; +}; + +struct softmix_bridge_data { + struct ast_timer *timer; + /*! + * \brief Bridge pointer passed to the softmix mixing thread. + * + * \note Does not need a reference because the bridge will + * always exist while the mixing thread exists even if the + * bridge is no longer actively using the softmix technology. + */ + struct ast_bridge *bridge; + /*! Lock for signaling the mixing thread. */ + ast_mutex_t lock; + /*! Condition, used if we need to wake up the mixing thread. */ + ast_cond_t cond; + /*! Thread handling the mixing */ + pthread_t thread; + unsigned int internal_rate; + unsigned int internal_mixing_interval; + /*! TRUE if the mixing thread should stop */ + unsigned int stop:1; + /*! The default sample size (e.g. using Opus at 48khz and 20 ms mixing + * interval, sample size is 960) */ + unsigned int default_sample_size; + /*! All data needed for binaural signaling */ + struct convolve_data convolve; + /*! TRUE if the first attempt to init binaural rendering data was done + * (does not guarantee success) + */ + unsigned int binaural_init; +}; + +struct softmix_mixing_array { + unsigned int max_num_entries; + unsigned int used_entries; + int16_t **buffers; + /*! Stereo channel pairs used to store convolved binaural signals */ + struct convolve_channel_pair **chan_pairs; +}; + +/*! + * \brief Deletes left over signals on a channel that it can be reused. + * + * \param channel_pair The channel pair which contains the left and right audio channel. + * \param default_sample_size The sample size which the channel pair uses. + */ +void reset_channel_pair(struct convolve_channel_pair *channel_pair, + unsigned int default_sample_size); + +/*! + * \brief Randomly changes the virtual positions of conference participants. + * + * \param softmix_data The structure containing all position informations. + */ +void random_binaural_pos_change(struct softmix_bridge_data *softmix_data); + +/*! + * \brief Binaural convolving of audio data for a channel. + * + * \param chan The channel that will contain the binaural audio data as result. + * \param in_samples The audio data which will be convolved. + * \param in_sample_size The size of the audio data. + * \param hrtf_length The length of the head related transfer function used to convolve the audio. + * + * \retval 0 success + * \retval -1 failure + */ +int do_convolve(struct convolve_channel *chan, int16_t *in_samples, + unsigned int in_sample_size, unsigned int hrtf_length); + +/*! + * \brief Binaural convolving of audio data for a channel pair (left and right channel). + * + * \param data Contains the left and right audio channel. + * \param pos_id The position the channel has in the virtual enviroment. + * \param in_samples The audio data which will be convolved for both channels. + * \param in_sample_size The size of the audio data. + * \param channel_name The name of the channel + * + * \retval The channel pair with convolved audio on success. + * \retval NULL failure + */ +struct convolve_channel_pair *do_convolve_pair(struct convolve_data *data, + unsigned int pos_id, int16_t *in_samples, unsigned int in_sample_size, + const char *channel_name); + +/*! + * \brief Provides a head related impulse response for the given position in the virtual + * enviroment. + * + * \param chan_pos The position of the channel in the virtual enviroment. + * \param chan_side 0 for the left audio channel, 1 for the right. + * + * \retval The hrir for the given position in the virtual room for either the left or right + * channels. + * \retval NULL on failure. + * + */ +float *get_hrir(unsigned int chan_pos, unsigned int chan_side); + +/*! + * \brief Initializes all data needed for binaural audio processing. + * + * \param channel The channel used for binaural audio processing. + * \param hrtf_len The length of the head related impulse response used for binaural processing. + * \param chan_pos The position of the channel in the virtual enviroment. + * \param chan_side 0 for the left audio channel, 1 for the right. + * \param default_sample_size The default size of audio samples. + * + * \retval 0 on success + * \retval -1 on failure + */ +int init_convolve_channel(struct convolve_channel *channel, unsigned int hrtf_len, + unsigned int chan_pos, unsigned int chan_side, unsigned int default_sample_size); + +/*! + * \brief Initializies all data needed for binaural audio processing of a channel pair + * (left and right). + * + * \param cchan_pair The channel pair used for binaural audio processing. + * \param hrtf_len The length of the head related impulse response used for binaural processing. + * \param chan_pos The position of the channel in the virtual enviroment. + * \param default_sample_size The default size of audio samples. + * + * \retval 0 on success + * \retval -1 on failure + */ +int init_convolve_channel_pair(struct convolve_channel_pair *cchan_pair, + unsigned int hrtf_len, unsigned int chan_pos, unsigned int default_sample_size); + +/*! + * \brief Preinits a specific number of channels (CONVOVLE_CHANNEL_PREALLOC) + * at the beginning of a conference. + * + * \param data Contains all channels and data needed for binaural processing + * (e.g. head related transfer functions). + * \param default_sample_size The default size of audio samples. + * + * \retval 0 on success + * \retval -1 on failure + */ +int init_convolve_data(struct convolve_data *data, unsigned int default_sample_size); + +/*! + * \brief Frees all data needed for binaural processing by an audio channel. + * + * \param cchan The channel to clean up. + */ +void free_convolve_channel(struct convolve_channel *cchan); + +/*! + * \brief Frees all data needed for binaural processing by a pair of audio channels + * (left and right). + * + * \param cchan_pair The channel pair to clean up. + */ +void free_convolve_channel_pair(struct convolve_channel_pair *cchan_pair); + +/*! + * \brief Frees all channels and data needed for binaural audio processing. + * + * \param data Contains all channels and data for the cleanup process. + */ +void free_convolve_data(struct convolve_data *data); + +/*! + * \brief Joins a channel into a virtual enviroment build with the help of binaural sythesis. + * + * \param data Contains all channels and data needed for binaural processing + * (e.g. head related transfer functions). + * \param default_sample_size The default size of audio samples. + * + * \retval The position of the channel in the virtual enviroment. + * \retval -1 on failure + */ +int set_binaural_data_join(struct convolve_data *data, unsigned int default_sample_size); + +/*! + * \brief Removes a channel from the binaural conference bridge. Marks the position in + * the virtual room as unused that it can be reused by the next channel which enters the + * conference. + * + * \param data Contains all channels and data needed for binaural processing + * (e.g. head related transfer functions). + * \param pos The position of the channel in the virtual enviroment. + * \param default_sample_size The default size of audio samples. + */ +void set_binaural_data_leave(struct convolve_data *data, unsigned int pos, + unsigned int default_sample_size); + +/*! + * \brief Writes the binaural audio to a channel. + * + * \param sc The softmix channel. + * \param default_sample_size The default size of audio samples. + */ +void softmix_process_write_binaural_audio(struct softmix_channel *sc, + unsigned int default_sample_size); + +/*! + * \brief Checks if a position change in the virual enviroment is requested by one of + * the participants. + * + * \param bridge The conference bridge. + * \param softmix_data The data used by the softmix bridge. + * \param bridge_channel The bridge channel. + */ +void check_binaural_position_change(struct ast_bridge *bridge, + struct softmix_bridge_data *softmix_data, struct ast_bridge_channel *bridge_channel); + +/*! + * \brief Processes audio data with the binaural synthesis and adds the result to the mixing array. + * + * \param bridge The conference bridge needed to check if binaural processing is active or not. + * \param softmix_data Contains all data for the softmix bridge and for the binaural processing. + * \param softmix_samples The sample size. + * \param mixing_array The array which holds all audio data for mixing. + * \param sc The channel which contains the audio data to process. + * \param channel_name The name of the channel + */ +void add_binaural_mixing(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, + unsigned int softmix_samples, struct softmix_mixing_array *mixing_array, + struct softmix_channel *sc, const char *channel_name); + +/*! + * \brief Mixes all binaural audio data contained in the mixing array. + * + * \param bridge The conference bridge needed to check if binaural processing is active or not. + * \param softmix_data Contains all data for the softmix bridge and for the binaural processing. + * \param mixing_array The array which holds all audio data for mixing. + * \param bin_buf The buffer that will contain the mixing results. + * \param ann_buf The buffer that will contain mixed announcements in an interleaved format. + */ +void binaural_mixing(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, + struct softmix_mixing_array *mixing_array, int16_t *bin_buf, int16_t *ann_buf); + +/*! + * \brief Creates a frame out of binaural audio data. + * + * \param bridge_channel Contains the information if binaural processing is active or not. + * If active binaural audio data will be copied, if not mono data will be provided in an + * interleaved format. + * \param sc The softmix channel holding all informations for the process. + * \param bin_buf The buffer that contains all mixing results. + * \param ann_buf The buffer that contains mixed announcements in an interleaved format. + * \param softmix_datalen The size of the audio data. + * \param softmix_samples The number of audio samples. + * \param buf The buffer that contains all mono mixing results, used if binaural processing is + * inactive. + */ +void create_binaural_frame(struct ast_bridge_channel *bridge_channel, + struct softmix_channel *sc, int16_t *bin_buf, int16_t *ann_buf, + unsigned int softmix_datalen, unsigned int softmix_samples, int16_t *buf); + +#endif /* _ASTERISK_BRIDGE_SOFTMIX_INTERNAL_H */ diff --git a/bridges/bridge_softmix/include/hrirs.h b/bridges/bridge_softmix/include/hrirs.h new file mode 100644 index 00000000000..457896e92bc --- /dev/null +++ b/bridges/bridge_softmix/include/hrirs.h @@ -0,0 +1,50730 @@ +/* Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Frank Haase, Dennis Guse + * + * Frank Haase + * Dennis Guse + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * Copyright (c) 2001 The Regents of the University of California. All Rights Reserved. + * + * The HRIRs used here are obtained from The CIPIC HRTF Database + * (http://interface.cipic.ucdavis.edu/CIL_html/CIL_HRTF_database.htm) + * Note that the above mentioned material is Copyright (c) 2001 The + * Regents of the University of California. All Rights Reserved. + * + * Download the file + * http://interface.cipic.ucdavis.edu/data/special_kemar_hrir.tar and + * uncompress it in the folder where this Matlab script resides. Finally, + * run the script. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Multi-party software binaural channel HRIRS + * + * \author Frank Haase + * \author Dennis Guse + * + * \ingroup bridges + */ + +/* + * This file was created with command: + * $ conf_bridge_binaural_hrir_importer sounds/hrirs_48k.wav 0 180 + */ +#define HRIRS_IMPULSE_LEN 557 +#define HRIRS_IMPULSE_SIZE 181 +#define HRIRS_SAMPLE_RATE 48000 + +float hrirs_left[HRIRS_IMPULSE_SIZE][HRIRS_IMPULSE_LEN] = { +{-0.0000610351562500, 0.0002441406250000, -0.0001220703125000, 0.0000915527343750, +-0.0003051757812500, 0.0003967285156250, -0.0000305175781250, 0.0001220703125000, +0.0002136230468750, -0.0003356933593750, 0.0000000000000000, -0.0001220703125000, +0.0002746582031250, -0.0001220703125000, 0.0004272460937500, -0.0003662109375000, +0.0001525878906250, -0.0001220703125000, 0.0000305175781250, 0.0002441406250000, +0.0002441406250000, 0.0000305175781250, -0.0003662109375000, 0.0001831054687500, +-0.0004577636718750, 0.0003356933593750, -0.0002136230468750, 0.0000915527343750, +-0.0004272460937500, -0.0001220703125000, -0.0005493164062500, 0.0000305175781250, +0.0002441406250000, -0.0001220703125000, 0.0001525878906250, -0.0002441406250000, +0.0001220703125000, -0.0000610351562500, 0.0007629394531250, 0.0000610351562500, +0.0006408691406250, -0.0000610351562500, 0.0000610351562500, 0.0000915527343750, +0.0003967285156250, 0.0002136230468750, 0.0000610351562500, 0.0000610351562500, +-0.0007324218750000, -0.0000305175781250, -0.0003051757812500, 0.0000305175781250, +-0.0004272460937500, -0.0000610351562500, -0.0008544921875000, -0.0001220703125000, +-0.0003051757812500, -0.0000610351562500, 0.0001831054687500, 0.0000305175781250, +-0.0002441406250000, -0.0000305175781250, 0.0006103515625000, 0.0000610351562500, +0.0007934570312500, 0.0001220703125000, 0.0004272460937500, 0.0000610351562500, +0.0005798339843750, 0.0000000000000000, 0.0007934570312500, 0.0000305175781250, +-0.0002441406250000, -0.0000305175781250, -0.0000610351562500, -0.0000915527343750, +-0.0001831054687500, -0.0000305175781250, -0.0008850097656250, 0.0000000000000000, +-0.0006713867187500, -0.0000305175781250, -0.0004577636718750, 0.0000305175781250, +-0.0008239746093750, 0.0000305175781250, -0.0003356933593750, 0.0000305175781250, +0.0002441406250000, 0.0000000000000000, -0.0002136230468750, 0.0000305175781250, +0.0007324218750000, 0.0000000000000000, 0.0007629394531250, -0.0000305175781250, +0.0005798339843750, 0.0000000000000000, 0.0009155273437500, 0.0000305175781250, +0.0009765625000000, 0.0000000000000000, 0.0002746582031250, 0.0000000000000000, +0.0005798339843750, 0.0000305175781250, 0.0002136230468750, 0.0000000000000000, +-0.0005187988281250, 0.0000000000000000, -0.0000915527343750, 0.0000000000000000, +-0.0008544921875000, 0.0000000000000000, -0.0009155273437500, -0.0000305175781250, +-0.0008239746093750, 0.0000000000000000, -0.0012207031250000, 0.0000305175781250, +-0.0011291503906250, 0.0000000000000000, -0.0007019042968750, 0.0000305175781250, +-0.0009765625000000, 0.0000000000000000, -0.0005493164062500, 0.0000305175781250, +0.0000305175781250, 0.0000000000000000, -0.0004577636718750, 0.0000000000000000, +0.0006713867187500, -0.0000305175781250, 0.0005187988281250, -0.0000305175781250, +0.0007019042968750, -0.0000305175781250, 0.0014648437500000, 0.0000000000000000, +0.0010681152343750, 0.0000000000000000, 0.0014953613281250, 0.0000000000000000, +0.0016784667968750, 0.0000000000000000, 0.0014038085937500, 0.0000305175781250, +0.0014648437500000, 0.0000000000000000, 0.0016174316406250, 0.0000000000000000, +0.0009155273437500, 0.0000000000000000, 0.0011901855468750, 0.0000000000000000, +0.0008544921875000, -0.0000305175781250, 0.0002441406250000, 0.0000000000000000, +0.0007324218750000, 0.0000305175781250, -0.0003662109375000, 0.0000000000000000, +-0.0000915527343750, -0.0000305175781250, -0.0003356933593750, 0.0000000000000000, +-0.0011291503906250, 0.0000000000000000, -0.0006103515625000, 0.0000000000000000, +-0.0014038085937500, 0.0000000000000000, -0.0012817382812500, 0.0000000000000000, +-0.0013122558593750, 0.0000305175781250, -0.0017395019531250, 0.0000000000000000, +-0.0014648437500000, 0.0000000000000000, -0.0017700195312500, 0.0000000000000000, +-0.0017395019531250, 0.0000000000000000, -0.0017089843750000, 0.0000000000000000, +-0.0018615722656250, -0.0000305175781250, -0.0017089843750000, 0.0000000000000000, +-0.0018005371093750, -0.0000305175781250, -0.0017395019531250, 0.0000000000000000, +-0.0016784667968750, 0.0000305175781250, -0.0017395019531250, -0.0000305175781250, +-0.0016479492187500, 0.0000305175781250, -0.0015258789062500, 0.0000000000000000, +-0.0014953613281250, 0.0000000000000000, -0.0013732910156250, 0.0000000000000000, +-0.0011901855468750, 0.0000000000000000, -0.0011291503906250, 0.0000000000000000, +-0.0008544921875000, 0.0000000000000000, -0.0008850097656250, 0.0000000000000000, +-0.0006408691406250, 0.0000000000000000, -0.0003051757812500, 0.0000000000000000, +-0.0003967285156250, -0.0000305175781250, 0.0001831054687500, 0.0000000000000000, +0.0001220703125000, -0.0000305175781250, 0.0003662109375000, 0.0000000000000000, +0.0008544921875000, -0.0000305175781250, 0.0006713867187500, 0.0000000000000000, +0.0011291503906250, 0.0000305175781250, 0.0011901855468750, 0.0000000000000000, +0.0010986328125000, 0.0000000000000000, 0.0012512207031250, 0.0000000000000000, +0.0012817382812500, 0.0000000000000000, 0.0009765625000000, -0.0000305175781250, +0.0010986328125000, 0.0000000000000000, 0.0007934570312500, 0.0000000000000000, +0.0003967285156250, 0.0000000000000000, 0.0005798339843750, -0.0000305175781250, +-0.0002136230468750, 0.0000000000000000, -0.0001831054687500, 0.0000305175781250, +-0.0003051757812500, 0.0000000000000000, -0.0008544921875000, 0.0000000000000000, +-0.0006408691406250, 0.0000305175781250, -0.0008239746093750, 0.0000000000000000, +-0.0009765625000000, 0.0000305175781250, -0.0007019042968750, 0.0000000000000000, +-0.0005187988281250, 0.0000000000000000, -0.0006713867187500, -0.0000305175781250, +0.0000610351562500, 0.0000000000000000, 0.0000000000000000, 0.0000000000000000, +0.0001525878906250, 0.0000000000000000, 0.0006408691406250, 0.0000305175781250, +0.0004882812500000, 0.0000305175781250, 0.0005187988281250, 0.0000000000000000, +0.0007019042968750, 0.0000000000000000, 0.0004272460937500, 0.0000000000000000, +0.0001220703125000, -0.0000305175781250, 0.0003051757812500, -0.0000305175781250, +-0.0002746582031250, 0.0000000000000000, -0.0003662109375000, 0.0000000000000000, +-0.0002441406250000, 0.0000000000000000, -0.0004882812500000, 0.0000000000000000, +-0.0004882812500000, 0.0000000000000000, -0.0000610351562500, -0.0000305175781250, +-0.0001525878906250, 0.0000000000000000, -0.0000305175781250, 0.0000000000000000, +0.0003662109375000, -0.0000305175781250, 0.0002136230468750, -0.0000610351562500, +0.0001831054687500, 0.0000000000000000, 0.0003356933593750, -0.0000305175781250, +0.0001220703125000, 0.0000000000000000, -0.0001525878906250, 0.0000610351562500, +0.0000305175781250, 0.0000305175781250, -0.0001831054687500, 0.0000000000000000, +-0.0003356933593750, 0.0000610351562500, -0.0001220703125000, 0.0000000000000000, +0.0000000000000000, -0.0000610351562500, -0.0001220703125000, -0.0000305175781250, +0.0001525878906250, 0.0000000000000000, 0.0002441406250000, -0.0000610351562500, +0.0001220703125000, 0.0000000000000000, 0.0000915527343750, 0.0000610351562500, +0.0001831054687500, 0.0000000000000000, -0.0001220703125000, 0.0000000000000000, +-0.0001220703125000, 0.0000610351562500, -0.0000610351562500, 0.0000000000000000, +-0.0001525878906250, -0.0000610351562500, -0.0001831054687500, -0.0000305175781250, +0.0000305175781250, 0.0000000000000000, 0.0000610351562500, -0.0000305175781250, +0.0000305175781250, 0.0000000000000000, 0.0001220703125000, 0.0000610351562500, +0.0000915527343750, 0.0000610351562500, -0.0000915527343750, -0.0000305175781250, +-0.0000610351562500, 0.0000305175781250, 0.0000000000000000, 0.0000000000000000, +-0.0000610351562500, -0.0000915527343750, -0.0000915527343750, -0.0000610351562500, +0.0000610351562500, 0.0000000000000000, 0.0000610351562500, -0.0000305175781250, +0.0000305175781250, -0.0000305175781250, 0.0000610351562500, 0.0000915527343750, +0.0000915527343750, 0.0000610351562500, -0.0000610351562500, -0.0000305175781250, +-0.0000610351562500, 0.0000305175781250, 0.0000000000000000, 0.0000000000000000, +-0.0000610351562500, -0.0001525878906250, -0.0000610351562500, -0.0000915527343750, +0.0000610351562500, 0.0000305175781250, 0.0000915527343750, -0.0000610351562500, +0.0000000000000000, 0.0000000000000000, 0.0000610351562500, 0.0002136230468750, +0.0000915527343750, 0.0001220703125000, -0.0000610351562500, 0.0000305175781250, +-0.0000305175781250, 0.0001220703125000, -0.0000305175781250, 0.0000305175781250, +-0.0000305175781250, -0.0002441406250000, -0.0000610351562500, -0.0000915527343750, +0.0000305175781250, -0.0001525878906250, 0.0000305175781250, -0.0002746582031250, +0.0000305175781250, -0.0000610351562500, 0.0000610351562500, 0.0001831054687500, +0.0000610351562500, 0.0000000000000000, -0.0000305175781250, 0.0002136230468750, +-0.0000305175781250, 0.0003662109375000, -0.0000305175781250, 0.0001525878906250, +-0.0000305175781250, 0.0000610351562500, -0.0000305175781250, 0.0002136230468750, +0.0000000000000000, -0.0002441406250000, 0.0000000000000000, -0.0003051757812500, +0.0000000000000000, -0.0001525878906250, 0.0000305175781250, -0.0003356933593750, +0.0000305175781250, -0.0003662109375000, 0.0000000000000000, 0.0000915527343750, +0.0000305175781250, -0.0000305175781250, 0.0000000000000000, 0.0000915527343750, +-0.0000610351562500, 0.0004882812500000, 0.0000000000000000, 0.0003662109375000, +0.0000000000000000, 0.0003051757812500, 0.0000000000000000, 0.0004882812500000, +0.0000000000000000, 0.0001831054687500, 0.0000000000000000, -0.0001220703125000, +0.0000000000000000, 0.0000610351562500, 0.0000000000000000, -0.0004882812500000, +0.0000000000000000, -0.0005798339843750, 0.0000000000000000, -0.0004882812500000, +0.0000000000000000, -0.0006408691406250, 0.0000000000000000, -0.0006408691406250, +0.0000000000000000, -0.0001525878906250, 0.0000000000000000, -0.0002746582031250, +0.0000000000000000, 0.0000000000000000, 0.0000000000000000, 0.0005187988281250, +0.0000305175781250, 0.0003051757812500, 0.0000000000000000, 0.0007629394531250, +0.0000000000000000, 0.0008850097656250, 0.0000000000000000, 0.0007324218750000, +-0.0000305175781250, 0.0008850097656250, -0.0000305175781250, 0.0009460449218750, +0.0000000000000000, 0.0005493164062500, 0.0000000000000000, 0.0006408691406250, +-0.0000305175781250, 0.0003967285156250, 0.0000000000000000, -0.0000610351562500, +0.0000305175781250, 0.0001220703125000, -0.0000305175781250, -0.0004882812500000, +0.0000000000000000, -0.0004882812500000, 0.0000000000000000, -0.0006713867187500, +0.0000000000000000, -0.0011291503906250, 0.0000000000000000, -0.0009765625000000, +0.0000000000000000, -0.0013122558593750, -0.0000305175781250, -0.0013732910156250, +0.0000000000000000, -0.0013732910156250, 0.0000000000000000, -0.0015258789062500, +0.0000000000000000, -0.0015258789062500, 0.0000000000000000, -0.0015258789062500, +0.0000000000000000, -0.0014953613281250, 0.0000000000000000, -0.0014648437500000, +0.0000000000000000, -0.0014648437500000, 0.0000000000000000, -0.0014343261718750, +0.0000000000000000, -0.0014343261718750, 0.0000000000000000, -0.0013427734375000, +0.0000305175781250, -0.0013427734375000, -0.0000305175781250, -0.0013732910156250, +0.0000000000000000, -0.0012817382812500, 0.0000000000000000, -0.0014343261718750, +0.0000000000000000, -0.0013732910156250, 0.0000305175781250, -0.0013732910156250, +0.0000000000000000, -0.0014953613281250, 0.0000305175781250, -0.0014343261718750, +0.0000000000000000, -0.0016174316406250, 0.0000000000000000, -0.0015563964843750, +0.0000000000000000}, +{-0.0000915527343750, 0.0001525878906250, 0.0000000000000000, 0.0000000000000000, +-0.0000305175781250, -0.0001831054687500, -0.0000915527343750, -0.0000915527343750, +0.0000610351562500, -0.0000915527343750, 0.0000915527343750, -0.0002441406250000, +0.0000305175781250, -0.0000305175781250, 0.0000305175781250, 0.0002136230468750, +0.0000610351562500, 0.0000000000000000, -0.0000305175781250, 0.0001831054687500, +-0.0000610351562500, 0.0003356933593750, 0.0000000000000000, 0.0001220703125000, +-0.0000305175781250, -0.0000305175781250, -0.0000610351562500, 0.0001220703125000, +0.0000000000000000, -0.0002746582031250, 0.0000305175781250, -0.0003662109375000, +0.0000000000000000, -0.0001831054687500, 0.0000305175781250, -0.0002746582031250, +0.0000610351562500, -0.0003356933593750, -0.0000305175781250, 0.0001525878906250, +-0.0000305175781250, 0.0000915527343750, 0.0000000000000000, 0.0001220703125000, +-0.0000305175781250, 0.0004882812500000, -0.0000305175781250, 0.0003967285156250, +0.0000000000000000, 0.0001220703125000, 0.0000000000000000, 0.0002746582031250, +0.0000000000000000, 0.0000305175781250, 0.0000305175781250, -0.0004577636718750, +0.0000610351562500, -0.0001831054687500, 0.0000000000000000, -0.0004577636718750, +-0.0000305175781250, -0.0006408691406250, 0.0000000000000000, -0.0003051757812500, +0.0000000000000000, -0.0001525878906250, 0.0000000000000000, -0.0003356933593750, +0.0000000000000000, 0.0003662109375000, 0.0000000000000000, 0.0003967285156250, +0.0000000000000000, 0.0004272460937500, 0.0000305175781250, 0.0008239746093750, +0.0000305175781250, 0.0007019042968750, 0.0000000000000000, 0.0004882812500000, +0.0000000000000000, 0.0007019042968750, 0.0000000000000000, 0.0003051757812500, +-0.0000305175781250, -0.0001831054687500, 0.0000000000000000, 0.0001220703125000, +0.0000305175781250, -0.0006408691406250, -0.0000305175781250, -0.0007019042968750, +0.0000000000000000, -0.0007324218750000, 0.0000000000000000, -0.0011291503906250, +0.0000000000000000, -0.0010375976562500, -0.0000305175781250, -0.0009765625000000, +0.0000000000000000, -0.0010986328125000, 0.0000000000000000, -0.0008544921875000, +0.0000000000000000, -0.0005493164062500, -0.0000305175781250, -0.0007019042968750, +0.0000000000000000, -0.0000915527343750, 0.0000000000000000, -0.0001220703125000, +0.0000305175781250, 0.0001525878906250, 0.0000000000000000, 0.0007019042968750, +0.0000000000000000, 0.0005187988281250, 0.0000000000000000, 0.0010681152343750, +0.0000000000000000, 0.0011291503906250, 0.0000000000000000, 0.0012512207031250, +-0.0000305175781250, 0.0015563964843750, -0.0000305175781250, 0.0015258789062500, +0.0000000000000000, 0.0016784667968750, 0.0000000000000000, 0.0017089843750000, +0.0000000000000000, 0.0017395019531250, 0.0000000000000000, 0.0018310546875000, +0.0000000000000000, 0.0017700195312500, -0.0000305175781250, 0.0018005371093750, +0.0000000000000000, 0.0018310546875000, -0.0000305175781250, 0.0018005371093750, +0.0000000000000000, 0.0018310546875000, -0.0000305175781250, 0.0018005371093750, +-0.0000305175781250, 0.0019226074218750, 0.0000000000000000, 0.0018615722656250, +0.0000000000000000, 0.0018615722656250, -0.0000305175781250, 0.0019531250000000, +0.0000000000000000, 0.0019226074218750, 0.0000000000000000, 0.0020141601562500, +0.0000305175781250, 0.0019836425781250, 0.0000000000000000, 0.0019836425781250, +0.0000305175781250, 0.0020446777343750, 0.0000000000000000, 0.0020141601562500, +-0.0000305175781250, 0.0019226074218750, 0.0000000000000000, 0.0020141601562500, +0.0000000000000000, 0.0018615722656250, 0.0000000000000000, 0.0017089843750000, +-0.0000305175781250, 0.0018310546875000, 0.0000000000000000, 0.0011596679687500, +0.0000000000000000, 0.0014953613281250, 0.0000000000000000, 0.0010681152343750, +0.0000305175781250, 0.0003662109375000, 0.0000000000000000, 0.0008850097656250, +0.0000000000000000, -0.0004577636718750, 0.0000000000000000, -0.0002441406250000, +0.0000000000000000, -0.0004272460937500, 0.0000000000000000, -0.0014648437500000, +-0.0000305175781250, -0.0009765625000000, 0.0000000000000000, -0.0015563964843750, +0.0000000000000000, -0.0018005371093750, 0.0000000000000000, -0.0014038085937500, +0.0000000000000000, -0.0014343261718750, 0.0000305175781250, -0.0016479492187500, +-0.0000305175781250, -0.0004882812500000, -0.0000305175781250, -0.0008239746093750, +0.0000000000000000, -0.0002746582031250, 0.0000000000000000, 0.0007934570312500, +0.0000000000000000, 0.0001831054687500, 0.0000305175781250, 0.0011901855468750, +0.0000305175781250, 0.0013427734375000, 0.0000000000000000, 0.0010375976562500, +0.0000000000000000, 0.0013427734375000, 0.0000305175781250, 0.0014038085937500, +-0.0000305175781250, 0.0005493164062500, -0.0000305175781250, 0.0008239746093750, +0.0000000000000000, 0.0003967285156250, 0.0000000000000000, -0.0005493164062500, +-0.0000305175781250, -0.0001220703125000, 0.0000305175781250, -0.0008544921875000, +0.0000305175781250, -0.0010681152343750, -0.0000305175781250, -0.0007629394531250, +0.0000000000000000, -0.0008850097656250, 0.0000000000000000, -0.0010070800781250, +0.0000000000000000, -0.0000915527343750, -0.0000305175781250, -0.0002746582031250, +0.0000000000000000, 0.0000000000000000, 0.0000000000000000, 0.0007629394531250, +-0.0000305175781250, 0.0004577636718750, 0.0000305175781250, 0.0005798339843750, +0.0000305175781250, 0.0008544921875000, 0.0000000000000000, 0.0004882812500000, +0.0000000000000000, 0.0001220703125000, 0.0000305175781250, 0.0004272460937500, +-0.0000305175781250, -0.0003662109375000, -0.0000610351562500, -0.0003967285156250, +-0.0000305175781250, -0.0003051757812500, -0.0000305175781250, -0.0006713867187500, +-0.0000610351562500, -0.0006103515625000, 0.0000610351562500, -0.0001525878906250, +0.0000610351562500, -0.0003662109375000, 0.0000305175781250, -0.0000915527343750, +0.0000915527343750, 0.0005187988281250, 0.0000915527343750, 0.0002136230468750, +-0.0000610351562500, 0.0004272460937500, -0.0000305175781250, 0.0006713867187500, +-0.0000305175781250, 0.0002746582031250, -0.0001220703125000, -0.0000305175781250, +-0.0000915527343750, 0.0002746582031250, 0.0000000000000000, -0.0004272460937500, +-0.0000305175781250, -0.0006408691406250, 0.0000305175781250, -0.0002746582031250, +0.0001831054687500, -0.0003356933593750, 0.0000915527343750, -0.0005493164062500, +0.0000305175781250, 0.0003356933593750, 0.0000915527343750, 0.0003356933593750, +0.0000000000000000, 0.0001525878906250, -0.0002136230468750, 0.0005493164062500, +-0.0000915527343750, 0.0006103515625000, -0.0001220703125000, -0.0001220703125000, +-0.0002746582031250, 0.0000000000000000, -0.0000610351562500, 0.0000305175781250, +0.0002136230468750, -0.0006408691406250, 0.0001220703125000, 0.0005187988281250, +-0.0003051757812500, -0.0002136230468750, -0.0003051757812500, 0.0001220703125000, +-0.0000915527343750, 0.0000000000000000, -0.0000915527343750, -0.0004577636718750, +-0.0002746582031250, -0.0004272460937500, 0.0003051757812500, 0.0000610351562500, +0.0003356933593750, -0.0000915527343750, 0.0001831054687500, -0.0000305175781250, +0.0005187988281250, 0.0004272460937500, 0.0005187988281250, 0.0003662109375000, +-0.0001525878906250, 0.0000000000000000, 0.0000000000000000, 0.0001831054687500, +-0.0001220703125000, 0.0000610351562500, -0.0007934570312500, -0.0003051757812500, +-0.0005493164062500, -0.0001831054687500, -0.0001220703125000, -0.0000305175781250, +-0.0005187988281250, -0.0001831054687500, -0.0000915527343750, -0.0000610351562500, +0.0007019042968750, 0.0002441406250000, 0.0002441406250000, 0.0001220703125000, +0.0005187988281250, 0.0000610351562500, 0.0009460449218750, 0.0001831054687500, +0.0003051757812500, 0.0000610351562500, -0.0002441406250000, -0.0001525878906250, +0.0003051757812500, -0.0000915527343750, -0.0006713867187500, -0.0000305175781250, +-0.0008850097656250, -0.0001525878906250, -0.0004272460937500, -0.0000305175781250, +-0.0005798339843750, 0.0001220703125000, -0.0008239746093750, 0.0000610351562500, +0.0003662109375000, 0.0000610351562500, 0.0002136230468750, 0.0000915527343750, +0.0002441406250000, 0.0000305175781250, 0.0010375976562500, -0.0000915527343750, +0.0008544921875000, -0.0000305175781250, 0.0003051757812500, -0.0000610351562500, +0.0007324218750000, -0.0000915527343750, 0.0002746582031250, -0.0000610351562500, +-0.0006103515625000, 0.0000610351562500, -0.0000915527343750, 0.0000000000000000, +-0.0007629394531250, 0.0000610351562500, -0.0010375976562500, 0.0000915527343750, +-0.0005798339843750, 0.0000305175781250, -0.0006408691406250, -0.0000610351562500, +-0.0008850097656250, -0.0000305175781250, 0.0002746582031250, 0.0000000000000000, +0.0000610351562500, -0.0000610351562500, 0.0002441406250000, -0.0000305175781250, +0.0011291503906250, 0.0000305175781250, 0.0007324218750000, 0.0000000000000000, +0.0008850097656250, 0.0000000000000000, 0.0012512207031250, 0.0000305175781250, +0.0007629394531250, 0.0000000000000000, 0.0004272460937500, -0.0000305175781250, +0.0007934570312500, -0.0000305175781250, -0.0003356933593750, 0.0000000000000000, +-0.0001525878906250, -0.0000305175781250, -0.0003967285156250, 0.0000000000000000, +-0.0012512207031250, 0.0000305175781250, -0.0007934570312500, 0.0000305175781250, +-0.0013427734375000, 0.0000000000000000, -0.0015258789062500, 0.0000000000000000, +-0.0011596679687500, 0.0000000000000000, -0.0011596679687500, -0.0000305175781250, +-0.0013427734375000, -0.0000305175781250, -0.0003662109375000, 0.0000000000000000, +-0.0007629394531250, 0.0000000000000000, -0.0003051757812500, -0.0000305175781250, +0.0006713867187500, 0.0000000000000000, 0.0000000000000000, 0.0000305175781250, +0.0013122558593750, 0.0000000000000000, 0.0011901855468750, 0.0000000000000000, +0.0012817382812500, 0.0000000000000000, 0.0020751953125000, 0.0000000000000000, +0.0016784667968750, 0.0000000000000000, 0.0020141601562500, 0.0000000000000000, +0.0021667480468750, 0.0000305175781250, 0.0019531250000000, 0.0000000000000000, +0.0018920898437500, 0.0000000000000000, 0.0020751953125000, 0.0000000000000000, +0.0013732910156250, 0.0000000000000000, 0.0017089843750000, 0.0000000000000000, +0.0014038085937500, 0.0000000000000000, 0.0007324218750000, -0.0000305175781250, +0.0012512207031250, 0.0000000000000000, 0.0003662109375000, -0.0000305175781250, +0.0005493164062500, 0.0000000000000000, 0.0003967285156250, 0.0000000000000000, +-0.0001831054687500, 0.0000000000000000, 0.0003356933593750, 0.0000000000000000, +-0.0002746582031250, -0.0000305175781250, -0.0001220703125000, 0.0000000000000000, +-0.0001525878906250, 0.0000000000000000, -0.0004577636718750, -0.0000305175781250, +-0.0001220703125000, -0.0000305175781250, -0.0004577636718750, 0.0000000000000000, +-0.0003662109375000, 0.0000000000000000, -0.0002746582031250, 0.0000000000000000, +-0.0003967285156250, -0.0000305175781250, -0.0002136230468750, 0.0000000000000000, +-0.0001525878906250, 0.0000000000000000, -0.0000305175781250, 0.0000000000000000, +0.0001220703125000, 0.0000305175781250, 0.0002441406250000, 0.0000000000000000, +0.0003662109375000, 0.0000000000000000, 0.0006408691406250, 0.0000000000000000, +0.0006713867187500, 0.0000000000000000, 0.0008544921875000, 0.0000000000000000, +0.0011291503906250, 0.0000000000000000, 0.0010681152343750, 0.0000000000000000, +0.0014648437500000, 0.0000000000000000, 0.0014648437500000, 0.0000305175781250, +0.0014648437500000, 0.0000000000000000, 0.0016784667968750, -0.0000305175781250, +0.0016174316406250}, +{-0.0010986328125000, 0.0001525878906250, -0.0006408691406250, 0.0000610351562500, +-0.0005798339843750, 0.0000000000000000, -0.0010375976562500, 0.0000610351562500, +-0.0004272460937500, 0.0000610351562500, 0.0002441406250000, -0.0000610351562500, +-0.0003051757812500, -0.0000610351562500, 0.0007324218750000, -0.0000305175781250, +0.0009155273437500, -0.0000610351562500, 0.0005798339843750, -0.0000305175781250, +0.0009765625000000, 0.0000915527343750, 0.0010375976562500, 0.0000305175781250, +0.0000610351562500, 0.0000305175781250, 0.0003967285156250, 0.0000305175781250, +0.0000000000000000, 0.0000305175781250, -0.0010070800781250, -0.0000610351562500, +-0.0004577636718750, -0.0000305175781250, -0.0010681152343750, 0.0000000000000000, +-0.0013732910156250, -0.0000305175781250, -0.0009460449218750, 0.0000000000000000, +-0.0009460449218750, 0.0000305175781250, -0.0011596679687500, 0.0000305175781250, +-0.0001220703125000, 0.0000000000000000, -0.0003967285156250, 0.0000000000000000, +-0.0000305175781250, 0.0000000000000000, 0.0008850097656250, 0.0000000000000000, +0.0003662109375000, -0.0000305175781250, 0.0012817382812500, 0.0000305175781250, +0.0014038085937500, 0.0000000000000000, 0.0012207031250000, 0.0000000000000000, +0.0015563964843750, 0.0000000000000000, 0.0015258789062500, 0.0000305175781250, +0.0008850097656250, 0.0000000000000000, 0.0012817382812500, 0.0000000000000000, +0.0007324218750000, 0.0000305175781250, -0.0000610351562500, 0.0000000000000000, +0.0006103515625000, -0.0000305175781250, -0.0008239746093750, 0.0000305175781250, +-0.0006408691406250, 0.0000000000000000, -0.0009460449218750, -0.0000305175781250, +-0.0019531250000000, 0.0000000000000000, -0.0013732910156250, 0.0000000000000000, +-0.0021972656250000, -0.0000305175781250, -0.0022888183593750, 0.0000000000000000, +-0.0021362304687500, 0.0000000000000000, -0.0024719238281250, 0.0000305175781250, +-0.0024414062500000, 0.0000000000000000, -0.0021667480468750, 0.0000000000000000, +-0.0024108886718750, 0.0000000000000000, -0.0021362304687500, 0.0000000000000000, +-0.0017700195312500, 0.0000000000000000, -0.0021362304687500, 0.0000000000000000, +-0.0013427734375000, 0.0000000000000000, -0.0015869140625000, -0.0000305175781250, +-0.0013732910156250, 0.0000000000000000, -0.0008544921875000, 0.0000305175781250, +-0.0013732910156250, 0.0000000000000000, -0.0007629394531250, 0.0000000000000000, +-0.0009155273437500, 0.0000000000000000, -0.0008850097656250, 0.0000000000000000, +-0.0005187988281250, 0.0000000000000000, -0.0008544921875000, 0.0000000000000000, +-0.0005187988281250, 0.0000000000000000, -0.0006408691406250, 0.0000000000000000, +-0.0007019042968750, 0.0000000000000000, -0.0004882812500000, 0.0000000000000000, +-0.0007324218750000, 0.0000000000000000, -0.0007324218750000, 0.0000000000000000, +-0.0008544921875000, 0.0000000000000000, -0.0010070800781250, 0.0000305175781250, +-0.0010986328125000, 0.0000000000000000, -0.0012207031250000, 0.0000000000000000, +-0.0014648437500000, 0.0000305175781250, -0.0014648437500000, 0.0000305175781250, +-0.0016174316406250, 0.0000305175781250, -0.0017700195312500, 0.0000000000000000, +-0.0017395019531250, 0.0000000000000000, -0.0018615722656250, 0.0000000000000000, +-0.0019226074218750, 0.0000000000000000, -0.0018310546875000, 0.0000305175781250, +-0.0018310546875000, 0.0000000000000000, -0.0018615722656250, 0.0000305175781250, +-0.0013732910156250, 0.0000305175781250, -0.0014953613281250, 0.0000305175781250, +-0.0011291503906250, 0.0000000000000000, -0.0005187988281250, 0.0000000000000000, +-0.0008544921875000, 0.0000000000000000, 0.0001525878906250, -0.0000305175781250, +0.0001220703125000, 0.0000000000000000, 0.0003051757812500, -0.0000305175781250, +0.0010070800781250, 0.0000000000000000, 0.0007629394531250, -0.0000610351562500, +0.0011596679687500, 0.0000000000000000, 0.0013122558593750, 0.0000305175781250, +0.0010375976562500, 0.0000000000000000, 0.0009765625000000, -0.0000305175781250, +0.0010986328125000, 0.0000000000000000, 0.0003356933593750, 0.0000000000000000, +0.0004577636718750, 0.0000000000000000, 0.0000915527343750, 0.0000305175781250, +-0.0005493164062500, 0.0000000000000000, -0.0002746582031250, 0.0000610351562500, +-0.0007934570312500, 0.0000000000000000, -0.0009765625000000, 0.0000305175781250, +-0.0007324218750000, 0.0000305175781250, -0.0007019042968750, -0.0000610351562500, +-0.0008239746093750, 0.0000000000000000, -0.0000610351562500, 0.0000000000000000, +-0.0001525878906250, 0.0000000000000000, 0.0000000000000000, 0.0000305175781250, +0.0006103515625000, 0.0000000000000000, 0.0004272460937500, 0.0000305175781250, +0.0004577636718750, 0.0000000000000000, 0.0006713867187500, 0.0000000000000000, +0.0003356933593750, 0.0000610351562500, 0.0000000000000000, -0.0000305175781250, +0.0002136230468750, 0.0000000000000000, -0.0003356933593750, 0.0000000000000000, +-0.0004272460937500, -0.0000610351562500, -0.0002441406250000, 0.0000000000000000, +-0.0003967285156250, 0.0000000000000000, -0.0004882812500000, 0.0000000000000000, +0.0000915527343750, 0.0000305175781250, 0.0000610351562500, 0.0000915527343750, +0.0000305175781250, 0.0000305175781250, 0.0003967285156250, 0.0000000000000000, +0.0003051757812500, 0.0000305175781250, 0.0000000000000000, -0.0000610351562500, +0.0001525878906250, -0.0000915527343750, 0.0000305175781250, -0.0000305175781250, +-0.0003051757812500, -0.0000305175781250, -0.0001831054687500, -0.0000305175781250, +-0.0001525878906250, 0.0000305175781250, -0.0002441406250000, 0.0000915527343750, +-0.0000610351562500, 0.0000000000000000, 0.0002136230468750, 0.0000000000000000, +0.0000610351562500, 0.0000305175781250, 0.0001525878906250, -0.0000305175781250, +0.0003356933593750, -0.0000915527343750, 0.0000915527343750, 0.0000000000000000, +-0.0001220703125000, 0.0000305175781250, 0.0000305175781250, -0.0000305175781250, +-0.0001220703125000, 0.0000305175781250, -0.0002136230468750, 0.0000610351562500, +-0.0000915527343750, 0.0000000000000000, 0.0000610351562500, -0.0000305175781250, +0.0000610351562500, 0.0000000000000000, 0.0000305175781250, -0.0000610351562500, +0.0001220703125000, -0.0000915527343750, 0.0000305175781250, -0.0000305175781250, +-0.0000915527343750, 0.0000000000000000, 0.0000610351562500, 0.0000305175781250, +-0.0000610351562500, 0.0000915527343750, -0.0001525878906250, 0.0001220703125000, +0.0000000000000000, 0.0000610351562500, 0.0000915527343750, 0.0000000000000000, +0.0000000000000000, 0.0000305175781250, 0.0000305175781250, -0.0000610351562500, +0.0001220703125000, -0.0001220703125000, 0.0000000000000000, -0.0000305175781250, +-0.0000915527343750, 0.0000610351562500, 0.0000305175781250, 0.0000000000000000, +-0.0000610351562500, 0.0001220703125000, -0.0001220703125000, 0.0001831054687500, +-0.0000305175781250, 0.0000000000000000, 0.0000915527343750, -0.0000610351562500, +-0.0000305175781250, 0.0000305175781250, 0.0000610351562500, -0.0002136230468750, +0.0001220703125000, -0.0002746582031250, 0.0000610351562500, -0.0000915527343750, +-0.0000305175781250, -0.0000305175781250, 0.0000305175781250, -0.0002136230468750, +-0.0000305175781250, 0.0002441406250000, -0.0000915527343750, 0.0002746582031250, +-0.0000305175781250, 0.0001525878906250, 0.0000305175781250, 0.0002746582031250, +-0.0000305175781250, 0.0003356933593750, 0.0000305175781250, -0.0001831054687500, +0.0000610351562500, -0.0001220703125000, 0.0000305175781250, -0.0001220703125000, +-0.0000305175781250, -0.0004882812500000, 0.0000305175781250, -0.0003662109375000, +-0.0000305175781250, -0.0000610351562500, -0.0000610351562500, -0.0002441406250000, +-0.0000305175781250, -0.0000305175781250, 0.0000000000000000, 0.0004577636718750, +-0.0000610351562500, 0.0002136230468750, 0.0000305175781250, 0.0003356933593750, +0.0000610351562500, 0.0005493164062500, 0.0000610351562500, 0.0001831054687500, +0.0000000000000000, -0.0000915527343750, 0.0000305175781250, 0.0001831054687500, +-0.0000305175781250, -0.0004882812500000, -0.0000305175781250, -0.0005798339843750, +-0.0000305175781250, -0.0003967285156250, 0.0000000000000000, -0.0006103515625000, +-0.0000305175781250, -0.0006713867187500, 0.0000000000000000, -0.0000610351562500, +0.0000305175781250, -0.0002136230468750, 0.0000000000000000, 0.0001220703125000, +0.0000000000000000, 0.0007019042968750, 0.0000305175781250, 0.0004882812500000, +0.0000000000000000, 0.0007629394531250, 0.0000000000000000, 0.0009460449218750, +-0.0000305175781250, 0.0006713867187500, 0.0000000000000000, 0.0005493164062500, +-0.0000305175781250, 0.0007019042968750, 0.0000000000000000, -0.0000915527343750, +0.0000000000000000, 0.0000305175781250, 0.0000000000000000, -0.0002746582031250, +0.0000610351562500, -0.0009155273437500, 0.0000000000000000, -0.0006713867187500, +0.0000000000000000, -0.0011596679687500, 0.0000000000000000, -0.0012512207031250, +0.0000000000000000, -0.0011901855468750, 0.0000000000000000, -0.0013732910156250, +0.0000000000000000, -0.0013122558593750, 0.0000000000000000, -0.0010375976562500, +-0.0000305175781250, -0.0011291503906250, -0.0000305175781250, -0.0008239746093750, +0.0000000000000000, -0.0004577636718750, 0.0000305175781250, -0.0005798339843750, +0.0000000000000000, 0.0000305175781250, 0.0000000000000000, 0.0001525878906250, +0.0000000000000000, 0.0003051757812500, 0.0000000000000000, 0.0007324218750000, +0.0000305175781250, 0.0006713867187500, 0.0000000000000000, 0.0010070800781250, +0.0000000000000000, 0.0010986328125000, 0.0000000000000000, 0.0011901855468750, +-0.0000305175781250, 0.0013732910156250, 0.0000000000000000, 0.0013427734375000, +0.0000000000000000, 0.0014953613281250, 0.0000000000000000, 0.0015869140625000, +0.0000000000000000, 0.0015563964843750, 0.0000000000000000, 0.0016174316406250, +0.0000000000000000, 0.0016784667968750, 0.0000000000000000, 0.0016479492187500, +0.0000000000000000, 0.0017089843750000, 0.0000000000000000, 0.0016784667968750, +0.0000000000000000, 0.0016479492187500, 0.0000000000000000, 0.0016784667968750, +0.0000000000000000, 0.0015258789062500, 0.0000000000000000, 0.0016479492187500, +0.0000000000000000, 0.0015563964843750, 0.0000305175781250, 0.0014038085937500, +0.0000000000000000, 0.0015563964843750, 0.0000000000000000, 0.0010375976562500, +0.0000305175781250, 0.0012207031250000, 0.0000305175781250, 0.0009765625000000, +-0.0000305175781250, 0.0005187988281250, 0.0000000000000000, 0.0008850097656250, +-0.0000305175781250, -0.0001831054687500, 0.0000000000000000, 0.0000915527343750, +0.0000000000000000, -0.0002441406250000, 0.0000000000000000, -0.0010986328125000, +0.0000000000000000, -0.0005493164062500, -0.0000305175781250, -0.0016479492187500, +0.0000305175781250, -0.0016174316406250, -0.0000305175781250, -0.0014648437500000, +-0.0000305175781250, -0.0020141601562500, -0.0000305175781250, -0.0019226074218750, +0.0000305175781250, -0.0014343261718750, 0.0000000000000000, -0.0018310546875000, +0.0000305175781250, -0.0012207031250000, 0.0000000000000000, -0.0004272460937500, +0.0000000000000000, -0.0010070800781250, 0.0000000000000000, 0.0005493164062500, +0.0000000000000000, 0.0003967285156250, 0.0000000000000000, 0.0005798339843750, +-0.0000305175781250, 0.0016784667968750, 0.0000000000000000, 0.0012207031250000, +0.0000000000000000, 0.0013122558593750, 0.0000000000000000, 0.0016784667968750, +0.0000305175781250, 0.0010986328125000, 0.0000000000000000, 0.0006408691406250, +0.0000305175781250, 0.0010681152343750, 0.0000000000000000, -0.0003356933593750, +-0.0000305175781250}, +{-0.0000305175781250, 0.0002746582031250, -0.0000610351562500, 0.0004577636718750, +0.0000000000000000, 0.0000610351562500, 0.0000000000000000, -0.0005187988281250, +-0.0000305175781250, -0.0002136230468750, 0.0000000000000000, -0.0008239746093750, +0.0000000000000000, -0.0010070800781250, -0.0000305175781250, -0.0008239746093750, +0.0000305175781250, -0.0008850097656250, 0.0000000000000000, -0.0009765625000000, +0.0000000000000000, -0.0003356933593750, 0.0000000000000000, -0.0004577636718750, +0.0000000000000000, -0.0001220703125000, 0.0000000000000000, 0.0005493164062500, +0.0000000000000000, 0.0002746582031250, -0.0000305175781250, 0.0009765625000000, +0.0000305175781250, 0.0010681152343750, -0.0000305175781250, 0.0010986328125000, +-0.0000305175781250, 0.0014343261718750, 0.0000305175781250, 0.0013427734375000, +-0.0000305175781250, 0.0013427734375000, 0.0000000000000000, 0.0014343261718750, +0.0000000000000000, 0.0011901855468750, 0.0000000000000000, 0.0009765625000000, +0.0000000000000000, 0.0010375976562500, -0.0000305175781250, 0.0005187988281250, +0.0000000000000000, 0.0004577636718750, 0.0000000000000000, 0.0002746582031250, +0.0000305175781250, -0.0001220703125000, 0.0000305175781250, -0.0000610351562500, +0.0000000000000000, -0.0004577636718750, 0.0000000000000000, -0.0006103515625000, +0.0000000000000000, -0.0007019042968750, 0.0000305175781250, -0.0009460449218750, +0.0000000000000000, -0.0008850097656250, 0.0000000000000000, -0.0010986328125000, +0.0000000000000000, -0.0012512207031250, 0.0000305175781250, -0.0012207031250000, +0.0000000000000000, -0.0012817382812500, 0.0000305175781250, -0.0013427734375000, +0.0000000000000000, -0.0012817382812500, 0.0000000000000000, -0.0013427734375000, +0.0000000000000000, -0.0012817382812500, 0.0000000000000000, -0.0012207031250000, +0.0000000000000000, -0.0012817382812500, 0.0000000000000000, -0.0010986328125000, +-0.0000305175781250, -0.0012207031250000, 0.0000000000000000, -0.0010375976562500, +-0.0000305175781250, -0.0008239746093750, 0.0000000000000000, -0.0010375976562500, +0.0000000000000000, -0.0003967285156250, 0.0000000000000000, -0.0005798339843750, +0.0000000000000000, -0.0002746582031250, 0.0000000000000000, 0.0003051757812500, +0.0000305175781250, -0.0001525878906250, 0.0000000000000000, 0.0008544921875000, +0.0000000000000000, 0.0006408691406250, 0.0000000000000000, 0.0009155273437500, +-0.0000305175781250, 0.0017089843750000, 0.0000000000000000, 0.0012207031250000, +0.0000000000000000, 0.0018615722656250, 0.0000000000000000, 0.0020141601562500, +0.0000000000000000, 0.0016479492187500, 0.0000305175781250, 0.0018615722656250, +0.0000000000000000, 0.0020141601562500, -0.0000305175781250, 0.0009765625000000, +0.0000000000000000, 0.0013732910156250, -0.0000305175781250, 0.0007324218750000, +-0.0000305175781250, -0.0003662109375000, -0.0000305175781250, 0.0003051757812500, +0.0000000000000000, -0.0011596679687500, -0.0000305175781250, -0.0011596679687500, +0.0000610351562500, -0.0010070800781250, 0.0000305175781250, -0.0018920898437500, +0.0000305175781250, -0.0016784667968750, 0.0000000000000000, -0.0011901855468750, +0.0000000000000000, -0.0016174316406250, -0.0000305175781250, -0.0009460449218750, +0.0000000000000000, -0.0000915527343750, 0.0000000000000000, -0.0007019042968750, +0.0000000000000000, 0.0007019042968750, 0.0000000000000000, 0.0007629394531250, +0.0000000000000000, 0.0006713867187500, 0.0000305175781250, 0.0014038085937500, +0.0000305175781250, 0.0012512207031250, 0.0000000000000000, 0.0007934570312500, +0.0000000000000000, 0.0010986328125000, 0.0000000000000000, 0.0005798339843750, +-0.0000305175781250, -0.0002136230468750, -0.0000305175781250, 0.0002136230468750, +0.0000305175781250, -0.0007629394531250, 0.0000000000000000, -0.0009460449218750, +0.0000000000000000, -0.0006408691406250, 0.0000610351562500, -0.0009460449218750, +0.0000305175781250, -0.0010375976562500, -0.0000305175781250, -0.0000915527343750, +0.0000000000000000, -0.0003051757812500, 0.0000000000000000, -0.0000915527343750, +-0.0000610351562500, 0.0006713867187500, -0.0000610351562500, 0.0003967285156250, +0.0000305175781250, 0.0005493164062500, -0.0000305175781250, 0.0008239746093750, +-0.0000305175781250, 0.0004272460937500, 0.0000915527343750, 0.0001525878906250, +0.0000305175781250, 0.0003967285156250, 0.0000000000000000, -0.0003662109375000, +0.0000305175781250, -0.0004577636718750, 0.0000305175781250, -0.0003356933593750, +-0.0000915527343750, -0.0006408691406250, -0.0000305175781250, -0.0006408691406250, +-0.0000305175781250, 0.0000000000000000, -0.0000915527343750, -0.0002136230468750, +-0.0000305175781250, 0.0000000000000000, 0.0001220703125000, 0.0007629394531250, +0.0000610351562500, 0.0004272460937500, 0.0000915527343750, 0.0003967285156250, +0.0001525878906250, 0.0007629394531250, 0.0000610351562500, 0.0002441406250000, +-0.0000610351562500, -0.0004272460937500, 0.0000305175781250, 0.0000000000000000, +-0.0001525878906250, -0.0004577636718750, -0.0002136230468750, -0.0008239746093750, +-0.0000610351562500, -0.0002441406250000, 0.0000000000000000, 0.0001220703125000, +-0.0001220703125000, -0.0003051757812500, 0.0002136230468750, 0.0004577636718750, +0.0002441406250000, 0.0006713867187500, 0.0001525878906250, 0.0003051757812500, +0.0001831054687500, 0.0001831054687500, -0.0003051757812500, -0.0003356933593750, +0.0002136230468750, 0.0004577636718750, -0.0000915527343750, 0.0005798339843750, +0.0000915527343750, 0.0002136230468750, 0.0005187988281250, 0.0000610351562500, +0.0003967285156250, 0.0003967285156250, 0.0000000000000000, -0.0003051757812500, +0.0003356933593750, -0.0005187988281250, -0.0000305175781250, -0.0001525878906250, +-0.0006408691406250, -0.0001525878906250, -0.0003051757812500, -0.0003356933593750, +-0.0003967285156250, 0.0002441406250000, -0.0007934570312500, 0.0003051757812500, +-0.0002136230468750, 0.0000915527343750, 0.0003967285156250, 0.0002441406250000, +-0.0001220703125000, 0.0003662109375000, 0.0007019042968750, -0.0000915527343750, +0.0010070800781250, -0.0001525878906250, 0.0003662109375000, -0.0000305175781250, +0.0002746582031250, -0.0002136230468750, 0.0007019042968750, -0.0002441406250000, +-0.0006103515625000, 0.0001525878906250, -0.0007019042968750, 0.0001525878906250, +-0.0003356933593750, 0.0000000000000000, -0.0008850097656250, 0.0001831054687500, +-0.0009765625000000, 0.0002136230468750, 0.0001831054687500, -0.0000610351562500, +-0.0001220703125000, -0.0000305175781250, 0.0001220703125000, 0.0000305175781250, +0.0012207031250000, -0.0001525878906250, 0.0007934570312500, -0.0001831054687500, +0.0004882812500000, 0.0000305175781250, 0.0010375976562500, 0.0000305175781250, +0.0003662109375000, 0.0000305175781250, -0.0005493164062500, 0.0001525878906250, +0.0000610351562500, 0.0000915527343750, -0.0009460449218750, -0.0000305175781250, +-0.0012512207031250, -0.0000305175781250, -0.0006713867187500, 0.0000000000000000, +-0.0007324218750000, -0.0000915527343750, -0.0010375976562500, -0.0000915527343750, +0.0003356933593750, 0.0000000000000000, 0.0001220703125000, 0.0000000000000000, +0.0002746582031250, 0.0000000000000000, 0.0013122558593750, 0.0000610351562500, +0.0008850097656250, 0.0000610351562500, 0.0007019042968750, -0.0000305175781250, +0.0012512207031250, 0.0000000000000000, 0.0005187988281250, 0.0000000000000000, +-0.0002136230468750, -0.0000305175781250, 0.0004272460937500, -0.0000610351562500, +-0.0009155273437500, 0.0000305175781250, -0.0008850097656250, 0.0000000000000000, +-0.0007934570312500, 0.0000305175781250, -0.0015563964843750, 0.0000305175781250, +-0.0014038085937500, 0.0000000000000000, -0.0010375976562500, -0.0000305175781250, +-0.0013732910156250, -0.0000305175781250, -0.0008544921875000, 0.0000305175781250, +-0.0001831054687500, 0.0000305175781250, -0.0007019042968750, 0.0000000000000000, +0.0007324218750000, 0.0000000000000000, 0.0005493164062500, 0.0000000000000000, +0.0007629394531250, 0.0000000000000000, 0.0017395019531250, 0.0000000000000000, +0.0012207031250000, 0.0000000000000000, 0.0016479492187500, 0.0000000000000000, +0.0018920898437500, 0.0000305175781250, 0.0014953613281250, 0.0000305175781250, +0.0013427734375000, 0.0000000000000000, 0.0016479492187500, 0.0000305175781250, +0.0004882812500000, 0.0000000000000000, 0.0008850097656250, 0.0000305175781250, +0.0003356933593750, 0.0000000000000000, -0.0007629394531250, 0.0000000000000000, +0.0000305175781250, -0.0000305175781250, -0.0015563964843750, 0.0000000000000000, +-0.0014038085937500, 0.0000305175781250, -0.0015258789062500, 0.0000305175781250, +-0.0025329589843750, -0.0000305175781250, -0.0020141601562500, 0.0000000000000000, +-0.0027465820312500, 0.0000000000000000, -0.0028076171875000, 0.0000000000000000, +-0.0027160644531250, 0.0000000000000000, -0.0030517578125000, 0.0000000000000000, +-0.0029907226562500, 0.0000000000000000, -0.0028381347656250, 0.0000305175781250, +-0.0029907226562500, 0.0000000000000000, -0.0028381347656250, 0.0000000000000000, +-0.0026550292968750, 0.0000000000000000, -0.0028686523437500, 0.0000000000000000, +-0.0025634765625000, 0.0000000000000000, -0.0026855468750000, 0.0000000000000000, +-0.0026245117187500, 0.0000000000000000, -0.0023498535156250, 0.0000305175781250, +-0.0025939941406250, -0.0000305175781250, -0.0022888183593750, 0.0000000000000000, +-0.0024108886718750, 0.0000305175781250, -0.0023803710937500, 0.0000305175781250, +-0.0022277832031250, 0.0000000000000000, -0.0024108886718750, 0.0000305175781250, +-0.0023193359375000, 0.0000000000000000, -0.0024108886718750, -0.0000305175781250, +-0.0024719238281250, 0.0000000000000000, -0.0024414062500000, 0.0000305175781250, +-0.0025024414062500, -0.0000305175781250, -0.0024414062500000, 0.0000000000000000, +-0.0024719238281250, 0.0000000000000000, -0.0024108886718750, 0.0000000000000000, +-0.0023193359375000, -0.0000305175781250, -0.0023803710937500, -0.0000305175781250, +-0.0019226074218750, -0.0000610351562500, -0.0020751953125000, -0.0000305175781250, +-0.0017700195312500, 0.0000000000000000, -0.0012512207031250, 0.0000000000000000, +-0.0014953613281250, 0.0000000000000000, -0.0005187988281250, 0.0000305175781250, +-0.0006103515625000, 0.0000305175781250, -0.0002441406250000, 0.0000305175781250, +0.0005798339843750, 0.0000000000000000, 0.0002746582031250, 0.0000000000000000, +0.0010375976562500, -0.0000610351562500, 0.0011901855468750, -0.0000610351562500, +0.0010986328125000, 0.0000000000000000, 0.0014953613281250, -0.0000305175781250, +0.0014038085937500, 0.0000000000000000, 0.0010375976562500, 0.0000305175781250, +0.0012817382812500, 0.0000305175781250, 0.0008544921875000, 0.0000305175781250, +0.0002441406250000, 0.0000000000000000, 0.0005493164062500, 0.0000000000000000, +-0.0004272460937500, 0.0000000000000000, -0.0004577636718750, 0.0000000000000000, +-0.0005798339843750, -0.0000305175781250, -0.0012207031250000, 0.0000305175781250, +-0.0010070800781250, 0.0000000000000000, -0.0008239746093750, -0.0000305175781250, +-0.0010986328125000, 0.0000305175781250, -0.0006408691406250, 0.0000000000000000, +-0.0001220703125000, 0.0000000000000000, -0.0004882812500000, 0.0000000000000000, +0.0004272460937500, 0.0000305175781250, 0.0005493164062500, 0.0000000000000000, +0.0003967285156250, 0.0000000000000000, 0.0007934570312500, 0.0000000000000000, +0.0007324218750000, -0.0000610351562500, 0.0002441406250000, 0.0000305175781250, +0.0003967285156250, 0.0000610351562500, 0.0001220703125000, 0.0000000000000000, +-0.0004577636718750}, +{-0.0017089843750000, 0.0000305175781250, -0.0020446777343750, 0.0000305175781250, +-0.0021362304687500, 0.0000000000000000, -0.0012817382812500, 0.0000000000000000, +-0.0017395019531250, 0.0000000000000000, -0.0011291503906250, 0.0000000000000000, +-0.0002441406250000, 0.0000305175781250, -0.0009765625000000, 0.0000305175781250, +0.0007629394531250, 0.0000000000000000, 0.0004577636718750, 0.0000305175781250, +0.0007934570312500, 0.0000305175781250, 0.0019531250000000, -0.0000305175781250, +0.0011901855468750, 0.0000000000000000, 0.0024108886718750, 0.0000000000000000, +0.0023498535156250, 0.0000305175781250, 0.0023498535156250, 0.0000000000000000, +0.0030212402343750, 0.0000305175781250, 0.0027160644531250, 0.0000305175781250, +0.0030212402343750, 0.0000000000000000, 0.0031127929687500, 0.0000000000000000, +0.0029907226562500, -0.0000305175781250, 0.0030822753906250, -0.0000305175781250, +0.0030822753906250, 0.0000305175781250, 0.0029602050781250, 0.0000305175781250, +0.0030212402343750, 0.0000000000000000, 0.0029296875000000, 0.0000305175781250, +0.0028381347656250, 0.0000000000000000, 0.0029907226562500, 0.0000000000000000, +0.0027770996093750, 0.0000000000000000, 0.0028076171875000, 0.0000305175781250, +0.0027770996093750, 0.0000305175781250, 0.0026855468750000, 0.0000000000000000, +0.0028076171875000, 0.0000000000000000, 0.0026855468750000, 0.0000000000000000, +0.0027465820312500, 0.0000000000000000, 0.0026550292968750, 0.0000000000000000, +0.0025939941406250, 0.0000000000000000, 0.0026245117187500, 0.0000000000000000, +0.0024719238281250, -0.0000305175781250, 0.0025024414062500, 0.0000000000000000, +0.0023193359375000, 0.0000000000000000, 0.0020751953125000, -0.0000305175781250, +0.0021362304687500, -0.0000305175781250, 0.0014953613281250, -0.0000305175781250, +0.0016479492187500, 0.0000000000000000, 0.0012817382812500, 0.0000000000000000, +0.0005798339843750, 0.0000000000000000, 0.0008239746093750, 0.0000305175781250, +-0.0002136230468750, -0.0000305175781250, -0.0001831054687500, 0.0000000000000000, +-0.0004577636718750, 0.0000305175781250, -0.0012207031250000, 0.0000000000000000, +-0.0010070800781250, -0.0000305175781250, -0.0014953613281250, 0.0000000000000000, +-0.0016479492187500, -0.0000305175781250, -0.0014648437500000, 0.0000000000000000, +-0.0014953613281250, 0.0000000000000000, -0.0015869140625000, 0.0000305175781250, +-0.0008544921875000, 0.0000305175781250, -0.0010070800781250, 0.0000305175781250, +-0.0006103515625000, 0.0000000000000000, 0.0001220703125000, -0.0000305175781250, +-0.0002136230468750, 0.0000305175781250, 0.0007019042968750, 0.0000305175781250, +0.0008544921875000, 0.0000610351562500, 0.0007629394531250, 0.0000000000000000, +0.0011596679687500, 0.0000000000000000, 0.0010986328125000, 0.0000000000000000, +0.0005798339843750, -0.0000305175781250, 0.0008239746093750, 0.0000000000000000, +0.0003967285156250, 0.0000000000000000, -0.0003051757812500, -0.0000305175781250, +0.0000305175781250, -0.0000305175781250, -0.0007019042968750, 0.0000305175781250, +-0.0008850097656250, 0.0000305175781250, -0.0006103515625000, 0.0000000000000000, +-0.0007934570312500, 0.0000000000000000, -0.0008544921875000, 0.0000000000000000, +-0.0000610351562500, -0.0000305175781250, -0.0001525878906250, 0.0000000000000000, +0.0000305175781250, 0.0000000000000000, 0.0006713867187500, -0.0000610351562500, +0.0004272460937500, -0.0000305175781250, 0.0003662109375000, 0.0000915527343750, +0.0006408691406250, 0.0000000000000000, 0.0002441406250000, 0.0000000000000000, +-0.0001831054687500, 0.0000305175781250, 0.0000915527343750, 0.0000305175781250, +-0.0003051757812500, -0.0000305175781250, -0.0005187988281250, 0.0000000000000000, +-0.0002746582031250, 0.0000305175781250, -0.0000915527343750, -0.0000305175781250, +-0.0002746582031250, -0.0000305175781250, 0.0002136230468750, 0.0000305175781250, +0.0003356933593750, 0.0000305175781250, 0.0001220703125000, 0.0000000000000000, +0.0002746582031250, 0.0000610351562500, 0.0003356933593750, 0.0000915527343750, +-0.0001220703125000, 0.0000000000000000, -0.0001220703125000, 0.0000000000000000, +-0.0000915527343750, 0.0000000000000000, -0.0003356933593750, -0.0000610351562500, +-0.0003356933593750, -0.0000915527343750, 0.0000915527343750, 0.0000610351562500, +-0.0000915527343750, 0.0000000000000000, -0.0000610351562500, -0.0000305175781250, +0.0002746582031250, 0.0000610351562500, 0.0002136230468750, 0.0000610351562500, +-0.0000305175781250, -0.0000610351562500, 0.0000915527343750, -0.0000305175781250, +0.0000610351562500, 0.0000000000000000, -0.0002136230468750, -0.0000915527343750, +-0.0001831054687500, -0.0000915527343750, 0.0000610351562500, 0.0000610351562500, +-0.0000610351562500, 0.0000305175781250, -0.0000610351562500, 0.0000000000000000, +0.0001831054687500, 0.0000915527343750, 0.0001220703125000, 0.0001220703125000, +0.0000000000000000, 0.0000000000000000, 0.0000610351562500, -0.0000305175781250, +0.0000610351562500, 0.0000000000000000, -0.0001525878906250, -0.0000915527343750, +-0.0001220703125000, -0.0001220703125000, 0.0000915527343750, 0.0000610351562500, +0.0000000000000000, 0.0000610351562500, 0.0000000000000000, 0.0000000000000000, +0.0001831054687500, 0.0000915527343750, 0.0000915527343750, 0.0001220703125000, +0.0000000000000000, -0.0001525878906250, 0.0000915527343750, -0.0000915527343750, +0.0000305175781250, -0.0000610351562500, -0.0001525878906250, -0.0002441406250000, +-0.0000915527343750, -0.0002441406250000, 0.0000000000000000, 0.0001220703125000, +-0.0000305175781250, 0.0000305175781250, 0.0000000000000000, 0.0000610351562500, +0.0001220703125000, 0.0003662109375000, 0.0000915527343750, 0.0002746582031250, +0.0000000000000000, -0.0001220703125000, 0.0000305175781250, 0.0001525878906250, +0.0000000000000000, 0.0000000000000000, -0.0000610351562500, -0.0004882812500000, +-0.0000610351562500, -0.0002746582031250, 0.0000000000000000, -0.0001831054687500, +0.0000000000000000, -0.0004272460937500, -0.0000305175781250, -0.0001220703125000, +0.0000610351562500, 0.0003051757812500, 0.0000305175781250, 0.0000305175781250, +0.0000305175781250, 0.0003356933593750, 0.0000610351562500, 0.0005798339843750, +0.0000000000000000, 0.0002441406250000, -0.0000305175781250, 0.0000610351562500, +-0.0000305175781250, 0.0002746582031250, -0.0000305175781250, -0.0004272460937500, +-0.0000610351562500, -0.0004882812500000, 0.0000000000000000, -0.0003662109375000, +0.0000610351562500, -0.0006408691406250, 0.0000305175781250, -0.0006713867187500, +0.0000000000000000, -0.0000610351562500, 0.0000305175781250, -0.0002136230468750, +0.0000000000000000, 0.0000610351562500, -0.0000305175781250, 0.0007324218750000, +-0.0000305175781250, 0.0004577636718750, 0.0000000000000000, 0.0005798339843750, +-0.0000305175781250, 0.0008850097656250, 0.0000000000000000, 0.0004882812500000, +0.0000305175781250, 0.0001220703125000, 0.0000000000000000, 0.0003662109375000, +0.0000305175781250, -0.0005493164062500, 0.0000000000000000, -0.0005493164062500, +0.0000000000000000, -0.0006713867187500, 0.0000000000000000, -0.0012512207031250, +0.0000000000000000, -0.0010681152343750, -0.0000305175781250, -0.0009460449218750, +0.0000000000000000, -0.0012207031250000, -0.0000305175781250, -0.0008544921875000, +0.0000305175781250, -0.0004577636718750, 0.0000000000000000, -0.0006713867187500, +0.0000000000000000, 0.0003051757812500, 0.0000305175781250, 0.0002441406250000, +0.0000000000000000, 0.0005187988281250, -0.0000305175781250, 0.0012207031250000, +0.0000000000000000, 0.0009765625000000, 0.0000000000000000, 0.0015258789062500, +0.0000000000000000, 0.0015869140625000, 0.0000000000000000, 0.0015258789062500, +0.0000000000000000, 0.0017395019531250, 0.0000000000000000, 0.0017089843750000, +0.0000305175781250, 0.0016174316406250, 0.0000000000000000, 0.0015869140625000, +0.0000000000000000, 0.0014343261718750, 0.0000000000000000, 0.0011901855468750, +0.0000305175781250, 0.0012817382812500, 0.0000000000000000, 0.0009460449218750, +0.0000000000000000, 0.0008239746093750, 0.0000305175781250, 0.0007019042968750, +0.0000000000000000, 0.0004882812500000, 0.0000000000000000, 0.0005187988281250, +0.0000000000000000, 0.0003356933593750, 0.0000000000000000, 0.0001220703125000, +0.0000000000000000, 0.0001525878906250, -0.0000305175781250, 0.0001220703125000, +0.0000000000000000, -0.0000305175781250, 0.0000305175781250, 0.0001831054687500, +0.0000000000000000, 0.0000610351562500, 0.0000000000000000, 0.0001220703125000, +0.0000000000000000, 0.0002746582031250, 0.0000000000000000, 0.0001525878906250, +0.0000000000000000, 0.0005187988281250, 0.0000000000000000, 0.0003662109375000, +0.0000000000000000, 0.0005493164062500, 0.0000000000000000, 0.0008850097656250, +0.0000000000000000, 0.0005798339843750, 0.0000000000000000, 0.0012817382812500, +0.0000000000000000, 0.0011291503906250, 0.0000000000000000, 0.0013122558593750, +-0.0000305175781250, 0.0018310546875000, 0.0000000000000000, 0.0014953613281250, +0.0000000000000000, 0.0021667480468750, 0.0000000000000000, 0.0021362304687500, +-0.0000305175781250, 0.0019836425781250, 0.0000000000000000, 0.0023803710937500, +0.0000000000000000, 0.0023193359375000, -0.0000305175781250, 0.0018005371093750, +0.0000000000000000, 0.0021972656250000, -0.0000305175781250, 0.0015563964843750, +0.0000000000000000, 0.0008544921875000, -0.0000305175781250, 0.0014953613281250, +0.0000000000000000, -0.0002746582031250, 0.0000000000000000, -0.0000610351562500, +-0.0000305175781250, -0.0003967285156250, -0.0000610351562500, -0.0016784667968750, +0.0000305175781250, -0.0011291503906250, 0.0000000000000000, -0.0018005371093750, +-0.0000305175781250, -0.0020751953125000, 0.0000000000000000, -0.0015258789062500, +0.0000000000000000, -0.0014953613281250, 0.0000000000000000, -0.0018310546875000, +0.0000000000000000, -0.0003356933593750, 0.0000305175781250, -0.0006713867187500, +0.0000000000000000, -0.0001525878906250, -0.0000305175781250, 0.0011596679687500, +0.0000000000000000, 0.0004882812500000, 0.0000000000000000, 0.0013427734375000, +-0.0000305175781250, 0.0016784667968750, 0.0000000000000000, 0.0011596679687500, +0.0000305175781250, 0.0010986328125000, 0.0000305175781250, 0.0013732910156250, +-0.0000305175781250, 0.0000610351562500, 0.0000000000000000, 0.0002441406250000, +-0.0000305175781250, -0.0000915527343750, -0.0000610351562500, -0.0010986328125000, +-0.0000305175781250, -0.0007019042968750, 0.0000000000000000, -0.0010070800781250, +0.0000000000000000, -0.0014038085937500, 0.0000000000000000, -0.0007934570312500, +0.0000610351562500, -0.0003967285156250, 0.0000305175781250, -0.0007629394531250, +0.0000610351562500, 0.0003662109375000, 0.0000305175781250, 0.0004577636718750, +0.0000305175781250, 0.0003051757812500, -0.0000305175781250, 0.0008544921875000, +-0.0000610351562500, 0.0007934570312500, 0.0000000000000000, 0.0003051757812500, +-0.0000915527343750, 0.0005493164062500, 0.0000000000000000, 0.0001525878906250, +0.0000915527343750, -0.0005493164062500, 0.0000000000000000, -0.0001220703125000, +0.0000915527343750, -0.0006408691406250, 0.0001220703125000, -0.0008850097656250, +0.0000610351562500, -0.0004882812500000, -0.0000305175781250, -0.0003356933593750, +0.0000000000000000, -0.0005798339843750, -0.0000915527343750, 0.0003967285156250, +-0.0001525878906250, 0.0003967285156250, -0.0000305175781250, 0.0002746582031250, +-0.0000305175781250, 0.0008544921875000, -0.0000915527343750, 0.0007629394531250, +0.0001525878906250}, +{-0.0000305175781250, -0.0013122558593750, -0.0000305175781250, -0.0011291503906250, +0.0000000000000000, -0.0009765625000000, 0.0000000000000000, -0.0009765625000000, +0.0000305175781250, -0.0009765625000000, 0.0000305175781250, -0.0008239746093750, +0.0000000000000000, -0.0010681152343750, -0.0000305175781250, -0.0009460449218750, +0.0000000000000000, -0.0009765625000000, 0.0000000000000000, -0.0011901855468750, +0.0000305175781250, -0.0010986328125000, 0.0000000000000000, -0.0013732910156250, +0.0000000000000000, -0.0012512207031250, 0.0000000000000000, -0.0014343261718750, +0.0000000000000000, -0.0017089843750000, 0.0000000000000000, -0.0014343261718750, +0.0000000000000000, -0.0021057128906250, -0.0000305175781250, -0.0019836425781250, +0.0000000000000000, -0.0020446777343750, 0.0000305175781250, -0.0024414062500000, +0.0000000000000000, -0.0022277832031250, 0.0000000000000000, -0.0024719238281250, +0.0000000000000000, -0.0026245117187500, 0.0000305175781250, -0.0023803710937500, +0.0000000000000000, -0.0023803710937500, 0.0000305175781250, -0.0025329589843750, +-0.0000305175781250, -0.0014648437500000, 0.0000000000000000, -0.0018920898437500, +-0.0000305175781250, -0.0013427734375000, 0.0000000000000000, -0.0002441406250000, +0.0000000000000000, -0.0010681152343750, 0.0000000000000000, 0.0007324218750000, +0.0000000000000000, 0.0007324218750000, -0.0000305175781250, 0.0008239746093750, +0.0000000000000000, 0.0019836425781250, 0.0000000000000000, 0.0015258789062500, +0.0000000000000000, 0.0016479492187500, 0.0000000000000000, 0.0020751953125000, +0.0000000000000000, 0.0013122558593750, 0.0000000000000000, 0.0008239746093750, +-0.0000305175781250, 0.0013427734375000, 0.0000000000000000, -0.0004272460937500, +0.0000000000000000, -0.0001831054687500, 0.0000000000000000, -0.0004577636718750, +0.0000000000000000, -0.0017700195312500, 0.0000000000000000, -0.0012207031250000, +0.0000000000000000, -0.0015258789062500, 0.0000000000000000, -0.0019226074218750, +0.0000000000000000, -0.0012817382812500, -0.0000305175781250, -0.0008239746093750, +0.0000000000000000, -0.0012207031250000, -0.0000305175781250, 0.0002136230468750, +-0.0000305175781250, 0.0001831054687500, -0.0000305175781250, 0.0003356933593750, +0.0000305175781250, 0.0013122558593750, 0.0000305175781250, 0.0010375976562500, +0.0000305175781250, 0.0007934570312500, 0.0000610351562500, 0.0012207031250000, +0.0000000000000000, 0.0006408691406250, -0.0000610351562500, -0.0001525878906250, +-0.0000305175781250, 0.0002746582031250, -0.0000305175781250, -0.0007019042968750, +-0.0000915527343750, -0.0008850097656250, 0.0000305175781250, -0.0006408691406250, +0.0000915527343750, -0.0009155273437500, 0.0000000000000000, -0.0009460449218750, +0.0000610351562500, -0.0001220703125000, 0.0000915527343750, -0.0003662109375000, +0.0000000000000000, -0.0000610351562500, -0.0000305175781250, 0.0006713867187500, +0.0000305175781250, 0.0003662109375000, -0.0000915527343750, 0.0005493164062500, +-0.0001220703125000, 0.0008544921875000, 0.0000000000000000, 0.0003356933593750, +0.0000000000000000, -0.0000610351562500, -0.0000915527343750, 0.0003662109375000, +0.0001220703125000, -0.0005798339843750, 0.0001525878906250, -0.0007324218750000, +0.0000610351562500, -0.0004272460937500, 0.0000305175781250, -0.0007324218750000, +0.0001831054687500, -0.0008544921875000, -0.0000915527343750, 0.0002746582031250, +-0.0001220703125000, 0.0001220703125000, -0.0000610351562500, 0.0001220703125000, +-0.0002136230468750, 0.0009460449218750, -0.0001831054687500, 0.0007629394531250, +0.0000610351562500, -0.0000305175781250, 0.0000305175781250, 0.0003356933593750, +0.0000610351562500, 0.0000610351562500, 0.0003356933593750, -0.0009155273437500, +0.0002746582031250, -0.0005493164062500, 0.0000000000000000, -0.0003051757812500, +0.0001220703125000, -0.0007019042968750, -0.0000305175781250, -0.0003356933593750, +-0.0004882812500000, 0.0007629394531250, 0.0001220703125000, -0.0003967285156250, +0.0002441406250000, -0.0001525878906250, 0.0005493164062500, -0.0007019042968750, +0.0000915527343750, -0.0001831054687500, -0.0003356933593750, 0.0006103515625000, +0.0000610351562500, 0.0002746582031250, -0.0004577636718750, 0.0001831054687500, +-0.0007629394531250, 0.0006103515625000, -0.0002746582031250, 0.0001525878906250, +-0.0000915527343750, -0.0004272460937500, -0.0004272460937500, -0.0001220703125000, +0.0006408691406250, -0.0002441406250000, 0.0007324218750000, -0.0005798339843750, +0.0003356933593750, -0.0001831054687500, 0.0007324218750000, 0.0002746582031250, +0.0009155273437500, 0.0000000000000000, -0.0003967285156250, 0.0001831054687500, +-0.0001525878906250, 0.0004272460937500, -0.0002441406250000, 0.0001525878906250, +-0.0012817382812500, -0.0001525878906250, -0.0010070800781250, 0.0000915527343750, +-0.0001525878906250, -0.0001220703125000, -0.0007019042968750, -0.0003051757812500, +-0.0001525878906250, -0.0000610351562500, 0.0010986328125000, 0.0000915527343750, +0.0005493164062500, -0.0000915527343750, 0.0007019042968750, 0.0001220703125000, +0.0012817382812500, 0.0002746582031250, 0.0004577636718750, 0.0000610351562500, +-0.0003967285156250, -0.0000305175781250, 0.0003356933593750, 0.0000915527343750, +-0.0010375976562500, -0.0001220703125000, -0.0013427734375000, -0.0001831054687500, +-0.0007019042968750, -0.0000305175781250, -0.0009460449218750, 0.0000610351562500, +-0.0012512207031250, -0.0000610351562500, 0.0003967285156250, 0.0001220703125000, +0.0001831054687500, 0.0001220703125000, 0.0002441406250000, 0.0000610351562500, +0.0013732910156250, 0.0000610351562500, 0.0009765625000000, 0.0000610351562500, +0.0006408691406250, -0.0000610351562500, 0.0011901855468750, -0.0001220703125000, +0.0004272460937500, -0.0000305175781250, -0.0004882812500000, 0.0000000000000000, +0.0002136230468750, -0.0000610351562500, -0.0011291503906250, 0.0000610351562500, +-0.0013122558593750, 0.0000915527343750, -0.0009460449218750, 0.0000610351562500, +-0.0014343261718750, 0.0000000000000000, -0.0015258789062500, 0.0000305175781250, +-0.0003662109375000, -0.0000305175781250, -0.0007934570312500, 0.0000000000000000, +-0.0003051757812500, -0.0000305175781250, 0.0008239746093750, 0.0000305175781250, +0.0002136230468750, 0.0000000000000000, 0.0013122558593750, 0.0000305175781250, +0.0014343261718750, 0.0000305175781250, 0.0012207031250000, 0.0000305175781250, +0.0016479492187500, 0.0000000000000000, 0.0016479492187500, 0.0000000000000000, +0.0008239746093750, 0.0000000000000000, 0.0012207031250000, -0.0000305175781250, +0.0006103515625000, 0.0000000000000000, -0.0003356933593750, 0.0000000000000000, +0.0003662109375000, 0.0000000000000000, -0.0012512207031250, 0.0000305175781250, +-0.0010986328125000, 0.0000305175781250, -0.0012512207031250, 0.0000305175781250, +-0.0023193359375000, 0.0000000000000000, -0.0018005371093750, 0.0000000000000000, +-0.0021362304687500, -0.0000305175781250, -0.0024719238281250, 0.0000000000000000, +-0.0019836425781250, 0.0000305175781250, -0.0018310546875000, 0.0000305175781250, +-0.0022583007812500, 0.0000610351562500, -0.0009460449218750, 0.0000000000000000, +-0.0013732910156250, 0.0000000000000000, -0.0008544921875000, 0.0000000000000000, +0.0001831054687500, 0.0000000000000000, -0.0006408691406250, -0.0000305175781250, +0.0010070800781250, 0.0000000000000000, 0.0007019042968750, 0.0000610351562500, +0.0009460449218750, 0.0000000000000000, 0.0020751953125000, 0.0000000000000000, +0.0014038085937500, 0.0000305175781250, 0.0023498535156250, -0.0000305175781250, +0.0022583007812500, 0.0000000000000000, 0.0022583007812500, 0.0000000000000000, +0.0027770996093750, 0.0000000000000000, 0.0024414062500000, 0.0000000000000000, +0.0028076171875000, 0.0000305175781250, 0.0027160644531250, 0.0000305175781250, +0.0026855468750000, 0.0000000000000000, 0.0028381347656250, 0.0000305175781250, +0.0026855468750000, -0.0000305175781250, 0.0027465820312500, -0.0000305175781250, +0.0027160644531250, 0.0000000000000000, 0.0026550292968750, 0.0000305175781250, +0.0027160644531250, 0.0000000000000000, 0.0026245117187500, 0.0000000000000000, +0.0025024414062500, 0.0000000000000000, 0.0024719238281250, 0.0000000000000000, +0.0023193359375000, -0.0000305175781250, 0.0021667480468750, -0.0000305175781250, +0.0021057128906250, 0.0000000000000000, 0.0016784667968750, 0.0000305175781250, +0.0017089843750000, -0.0000305175781250, 0.0014038085937500, -0.0000305175781250, +0.0009460449218750, 0.0000000000000000, 0.0010986328125000, -0.0000305175781250, +0.0002136230468750, 0.0000000000000000, 0.0003051757812500, 0.0000000000000000, +-0.0000610351562500, 0.0000305175781250, -0.0007934570312500, 0.0000000000000000, +-0.0005493164062500, 0.0000000000000000, -0.0013427734375000, 0.0000305175781250, +-0.0014343261718750, 0.0000000000000000, -0.0014343261718750, 0.0000000000000000, +-0.0018920898437500, -0.0000305175781250, -0.0018005371093750, 0.0000000000000000, +-0.0015869140625000, -0.0000305175781250, -0.0018005371093750, 0.0000000000000000, +-0.0013732910156250, 0.0000305175781250, -0.0008544921875000, 0.0000305175781250, +-0.0011596679687500, 0.0000000000000000, 0.0000000000000000, 0.0000305175781250, +-0.0000610351562500, 0.0000000000000000, 0.0002136230468750, -0.0000305175781250, +0.0010070800781250, 0.0000000000000000, 0.0007019042968750, 0.0000000000000000, +0.0011291503906250, 0.0000305175781250, 0.0013732910156250, 0.0000000000000000, +0.0009765625000000, -0.0000305175781250, 0.0008544921875000, 0.0000305175781250, +0.0010375976562500, 0.0000305175781250, -0.0000305175781250, -0.0000305175781250, +0.0000915527343750, 0.0000305175781250, -0.0001831054687500, 0.0000000000000000, +-0.0010070800781250, -0.0000305175781250, -0.0006713867187500, -0.0000305175781250, +-0.0008239746093750, 0.0000000000000000, -0.0011596679687500, -0.0000305175781250, +-0.0007019042968750, 0.0000305175781250, -0.0002746582031250, 0.0000305175781250, +-0.0005798339843750, 0.0000305175781250, 0.0003356933593750, 0.0000000000000000, +0.0004272460937500, 0.0000000000000000, 0.0003051757812500, 0.0000305175781250, +0.0007019042968750, -0.0000610351562500, 0.0006713867187500, -0.0000610351562500, +0.0000915527343750, 0.0000000000000000, 0.0002746582031250, 0.0000305175781250, +0.0000915527343750, 0.0000000000000000, -0.0006103515625000, 0.0000610351562500, +-0.0003051757812500, 0.0000610351562500, -0.0002746582031250, -0.0000305175781250, +-0.0005798339843750, 0.0000305175781250, -0.0002136230468750, 0.0000000000000000, +0.0002136230468750, -0.0000610351562500, -0.0000915527343750, 0.0000000000000000, +0.0003051757812500, 0.0000000000000000, 0.0005187988281250, -0.0000610351562500, +0.0001525878906250, 0.0000000000000000, -0.0000305175781250, 0.0001220703125000, +0.0001831054687500, 0.0000610351562500, -0.0002746582031250, 0.0000610351562500, +-0.0003967285156250, 0.0000915527343750, -0.0001831054687500, 0.0000305175781250, +-0.0002136230468750, -0.0000915527343750, -0.0003051757812500, -0.0000305175781250, +0.0001831054687500, -0.0000305175781250, 0.0002136230468750, -0.0000915527343750, +0.0000915527343750, -0.0000305175781250, 0.0002441406250000, 0.0001220703125000, +0.0003051757812500, 0.0000305175781250, -0.0001220703125000, 0.0000000000000000, +-0.0000915527343750, 0.0000610351562500, 0.0000000000000000, 0.0000305175781250, +-0.0001525878906250, -0.0001220703125000, -0.0001525878906250, -0.0001220703125000, +0.0001220703125000, 0.0000000000000000, 0.0000915527343750, -0.0000610351562500, +0.0000305175781250}, +{-0.0020446777343750, 0.0000305175781250, -0.0018615722656250, 0.0000000000000000, +-0.0016479492187500, -0.0000305175781250, -0.0015563964843750, 0.0000305175781250, +-0.0011596679687500, 0.0000000000000000, -0.0011901855468750, 0.0000000000000000, +-0.0008239746093750, 0.0000000000000000, -0.0003967285156250, 0.0000000000000000, +-0.0005187988281250, 0.0000000000000000, 0.0003662109375000, -0.0000305175781250, +0.0003051757812500, 0.0000000000000000, 0.0005798339843750, 0.0000000000000000, +0.0012207031250000, 0.0000305175781250, 0.0010070800781250, 0.0000000000000000, +0.0015869140625000, 0.0000305175781250, 0.0016784667968750, 0.0000000000000000, +0.0015258789062500, 0.0000305175781250, 0.0017089843750000, 0.0000000000000000, +0.0018005371093750, -0.0000305175781250, 0.0012207031250000, -0.0000305175781250, +0.0014038085937500, 0.0000305175781250, 0.0009460449218750, 0.0000305175781250, +0.0002746582031250, 0.0000000000000000, 0.0006103515625000, 0.0000000000000000, +-0.0005493164062500, -0.0000305175781250, -0.0005187988281250, 0.0000000000000000, +-0.0006713867187500, -0.0000610351562500, -0.0014038085937500, 0.0000000000000000, +-0.0011901855468750, 0.0000305175781250, -0.0011901855468750, 0.0000305175781250, +-0.0014953613281250, 0.0000000000000000, -0.0010375976562500, 0.0000000000000000, +-0.0006103515625000, -0.0000305175781250, -0.0009155273437500, 0.0000000000000000, +0.0002441406250000, 0.0000000000000000, 0.0002746582031250, -0.0000305175781250, +0.0003051757812500, 0.0000000000000000, 0.0010986328125000, 0.0000305175781250, +0.0008544921875000, 0.0000305175781250, 0.0006713867187500, 0.0000305175781250, +0.0009460449218750, 0.0000000000000000, 0.0004882812500000, -0.0000305175781250, +-0.0001220703125000, 0.0000000000000000, 0.0001831054687500, 0.0000000000000000, +-0.0006103515625000, 0.0000000000000000, -0.0007934570312500, -0.0000610351562500, +-0.0005187988281250, 0.0000305175781250, -0.0006713867187500, 0.0000610351562500, +-0.0007629394531250, 0.0000000000000000, 0.0000305175781250, 0.0000610351562500, +-0.0000915527343750, 0.0000610351562500, 0.0000000000000000, 0.0000000000000000, +0.0006408691406250, -0.0000610351562500, 0.0004577636718750, -0.0000305175781250, +0.0001831054687500, 0.0000000000000000, 0.0004577636718750, -0.0000610351562500, +0.0001525878906250, 0.0000000000000000, -0.0004272460937500, 0.0000610351562500, +-0.0001220703125000, 0.0000305175781250, -0.0003051757812500, 0.0000610351562500, +-0.0005493164062500, 0.0000610351562500, -0.0001831054687500, 0.0000305175781250, +0.0001525878906250, -0.0000915527343750, -0.0001220703125000, -0.0000305175781250, +0.0002746582031250, -0.0000305175781250, 0.0004882812500000, -0.0001220703125000, +0.0001220703125000, 0.0000000000000000, 0.0000000000000000, 0.0001220703125000, +0.0002441406250000, -0.0000305175781250, -0.0002136230468750, 0.0000305175781250, +-0.0003662109375000, 0.0001220703125000, -0.0001220703125000, 0.0000000000000000, +-0.0001220703125000, -0.0000915527343750, -0.0002441406250000, -0.0000305175781250, +0.0001525878906250, -0.0000610351562500, 0.0001831054687500, -0.0000915527343750, +0.0000610351562500, -0.0000305175781250, 0.0000915527343750, 0.0000915527343750, +0.0000610351562500, 0.0000610351562500, -0.0001525878906250, 0.0000305175781250, +-0.0001525878906250, 0.0000610351562500, 0.0000000000000000, 0.0000000000000000, +-0.0000305175781250, -0.0001220703125000, -0.0001831054687500, -0.0000305175781250, +0.0001220703125000, 0.0000000000000000, 0.0001525878906250, -0.0001220703125000, +0.0000000000000000, -0.0000305175781250, 0.0000610351562500, 0.0001220703125000, +0.0001220703125000, 0.0000610351562500, -0.0000915527343750, 0.0000305175781250, +-0.0001525878906250, 0.0001220703125000, -0.0000305175781250, 0.0000000000000000, +-0.0000305175781250, -0.0002136230468750, -0.0001220703125000, -0.0001220703125000, +0.0001220703125000, -0.0000915527343750, 0.0001525878906250, -0.0001831054687500, +0.0000610351562500, 0.0000000000000000, 0.0000305175781250, 0.0002746582031250, +0.0001220703125000, 0.0000610351562500, -0.0000915527343750, 0.0001220703125000, +-0.0001220703125000, 0.0003356933593750, -0.0000305175781250, 0.0000305175781250, +-0.0000610351562500, -0.0003662109375000, -0.0000915527343750, -0.0000915527343750, +0.0000915527343750, -0.0002746582031250, 0.0001220703125000, -0.0005493164062500, +0.0000000000000000, -0.0001831054687500, 0.0000915527343750, 0.0000915527343750, +0.0001220703125000, -0.0001525878906250, -0.0000610351562500, 0.0003356933593750, +-0.0000610351562500, 0.0005187988281250, 0.0000000000000000, 0.0002136230468750, +-0.0000610351562500, 0.0002746582031250, -0.0000915527343750, 0.0004272460937500, +0.0000915527343750, -0.0003662109375000, 0.0000305175781250, -0.0003356933593750, +0.0000000000000000, -0.0002136230468750, 0.0000610351562500, -0.0007019042968750, +0.0000915527343750, -0.0006713867187500, 0.0000000000000000, -0.0001220703125000, +-0.0000305175781250, -0.0003356933593750, 0.0000000000000000, 0.0000000000000000, +-0.0000305175781250, 0.0006408691406250, -0.0000305175781250, 0.0003051757812500, +0.0000000000000000, 0.0005493164062500, 0.0000000000000000, 0.0007934570312500, +0.0000000000000000, 0.0003356933593750, 0.0000305175781250, -0.0000305175781250, +0.0000305175781250, 0.0002441406250000, -0.0000305175781250, -0.0006408691406250, +0.0000000000000000, -0.0007629394531250, -0.0000305175781250, -0.0007019042968750, +-0.0000305175781250, -0.0010986328125000, 0.0000000000000000, -0.0010070800781250, +-0.0000305175781250, -0.0004882812500000, 0.0000000000000000, -0.0007324218750000, +0.0000000000000000, -0.0002746582031250, 0.0000305175781250, 0.0003662109375000, +0.0000305175781250, 0.0000610351562500, 0.0000305175781250, 0.0008544921875000, +0.0000305175781250, 0.0010070800781250, 0.0000000000000000, 0.0009155273437500, +-0.0000305175781250, 0.0012512207031250, 0.0000000000000000, 0.0012207031250000, +0.0000305175781250, 0.0008544921875000, 0.0000305175781250, 0.0010375976562500, +0.0000305175781250, 0.0006713867187500, 0.0000000000000000, 0.0001525878906250, +0.0000000000000000, 0.0003967285156250, 0.0000000000000000, -0.0004577636718750, +0.0000000000000000, -0.0004577636718750, 0.0000000000000000, -0.0007324218750000, +-0.0000305175781250, -0.0013122558593750, 0.0000305175781250, -0.0011596679687500, +0.0000000000000000, -0.0017089843750000, 0.0000305175781250, -0.0017700195312500, +0.0000610351562500, -0.0018310546875000, 0.0000305175781250, -0.0021057128906250, +0.0000305175781250, -0.0019836425781250, -0.0000305175781250, -0.0020751953125000, +0.0000305175781250, -0.0020446777343750, 0.0000305175781250, -0.0020141601562500, +0.0000000000000000, -0.0020751953125000, -0.0000305175781250, -0.0020141601562500, +0.0000000000000000, -0.0019836425781250, -0.0000305175781250, -0.0018615722656250, +0.0000000000000000, -0.0018615722656250, 0.0000000000000000, -0.0018615722656250, +0.0000305175781250, -0.0017700195312500, 0.0000000000000000, -0.0019531250000000, +0.0000305175781250, -0.0018920898437500, 0.0000000000000000, -0.0018920898437500, +-0.0000305175781250, -0.0020751953125000, 0.0000000000000000, -0.0019836425781250, +0.0000000000000000, -0.0021972656250000, 0.0000305175781250, -0.0021057128906250, +0.0000000000000000, -0.0021972656250000, -0.0000610351562500, -0.0024108886718750, +0.0000305175781250, -0.0022277832031250, 0.0000305175781250, -0.0024108886718750, +0.0000000000000000, -0.0025024414062500, 0.0000000000000000, -0.0024414062500000, +0.0000305175781250, -0.0024719238281250, 0.0000000000000000, -0.0025024414062500, +0.0000000000000000, -0.0020141601562500, 0.0000000000000000, -0.0023498535156250, +-0.0000305175781250, -0.0018310546875000, 0.0000000000000000, -0.0012817382812500, +0.0000000000000000, -0.0018005371093750, -0.0000305175781250, -0.0002136230468750, +0.0000000000000000, -0.0005798339843750, 0.0000305175781250, -0.0001220703125000, +0.0000000000000000, 0.0011596679687500, 0.0000000000000000, 0.0004272460937500, +-0.0000305175781250, 0.0016174316406250, -0.0000305175781250, 0.0018615722656250, +0.0000000000000000, 0.0014648437500000, -0.0000305175781250, 0.0018920898437500, +0.0000000000000000, 0.0019531250000000, 0.0000000000000000, 0.0008544921875000, +0.0000305175781250, 0.0013427734375000, 0.0000000000000000, 0.0006408691406250, +0.0000000000000000, -0.0006408691406250, 0.0000305175781250, 0.0001220703125000, +-0.0000305175781250, -0.0014038085937500, -0.0000305175781250, -0.0014648437500000, +0.0000000000000000, -0.0012512207031250, 0.0000305175781250, -0.0019226074218750, +0.0000000000000000, -0.0018310546875000, 0.0000305175781250, -0.0010070800781250, +0.0000305175781250, -0.0014038085937500, 0.0000000000000000, -0.0007934570312500, +0.0000000000000000, 0.0003051757812500, 0.0000305175781250, -0.0002441406250000, +-0.0000305175781250, 0.0009765625000000, -0.0000305175781250, 0.0012207031250000, +0.0000000000000000, 0.0009155273437500, 0.0000305175781250, 0.0012512207031250, +-0.0000305175781250, 0.0013122558593750, 0.0000305175781250, 0.0002136230468750, +0.0000610351562500, 0.0005493164062500, 0.0000305175781250, 0.0001220703125000, +0.0000000000000000, -0.0010070800781250, 0.0000610351562500, -0.0005493164062500, +-0.0000610351562500, -0.0009155273437500, -0.0000915527343750, -0.0012817382812500, +-0.0000305175781250, -0.0007629394531250, 0.0000000000000000, -0.0003662109375000, +-0.0000915527343750, -0.0007629394531250, 0.0000915527343750, 0.0003356933593750, +0.0000915527343750, 0.0003356933593750, 0.0000305175781250, 0.0002746582031250, +0.0000610351562500, 0.0008850097656250, 0.0000915527343750, 0.0007629394531250, +-0.0000915527343750, 0.0002746582031250, -0.0000915527343750, 0.0006103515625000, +-0.0000305175781250, 0.0001220703125000, -0.0001220703125000, -0.0006713867187500, +-0.0001525878906250, -0.0002746582031250, 0.0000915527343750, -0.0006713867187500, +0.0000305175781250, -0.0010375976562500, 0.0000305175781250, -0.0004882812500000, +0.0001831054687500, -0.0001220703125000, 0.0001831054687500, -0.0005187988281250, +-0.0000305175781250, 0.0006408691406250, 0.0000305175781250, 0.0008239746093750, +-0.0000305175781250, 0.0003356933593750, -0.0002441406250000, 0.0006103515625000, +-0.0001831054687500, 0.0008544921875000, -0.0000610351562500, -0.0004882812500000, +-0.0001525878906250, -0.0004272460937500, 0.0000000000000000, -0.0002441406250000, +0.0003356933593750, -0.0009155273437500, 0.0001220703125000, -0.0009460449218750, +0.0001831054687500, 0.0001220703125000, 0.0003662109375000, -0.0000915527343750, +0.0001525878906250, -0.0000915527343750, -0.0003051757812500, 0.0010070800781250, +-0.0002441406250000, -0.0008850097656250, 0.0004882812500000, 0.0003051757812500, +0.0004882812500000, -0.0001831054687500, 0.0001525878906250, -0.0000305175781250, +0.0001220703125000, 0.0007934570312500, 0.0003967285156250, 0.0006713867187500, +-0.0005493164062500, -0.0001220703125000, -0.0005493164062500, 0.0001525878906250, +-0.0003051757812500, 0.0000610351562500, -0.0007629394531250, -0.0007324218750000, +-0.0007934570312500, -0.0005187988281250, 0.0002746582031250, -0.0000610351562500, +0.0000305175781250, -0.0002746582031250, 0.0001831054687500, -0.0000915527343750, +0.0011291503906250, 0.0005798339843750, 0.0008239746093750, 0.0003356933593750, +0.0001831054687500, 0.0000915527343750, 0.0007324218750000, 0.0003662109375000, +0.0000915527343750, 0.0001525878906250, -0.0012207031250000, -0.0003662109375000, +-0.0004882812500000}, +{0.0000000000000000, -0.0015869140625000, 0.0000000000000000, -0.0018615722656250, +-0.0000305175781250, -0.0004577636718750, 0.0000000000000000, -0.0008239746093750, +0.0000305175781250, -0.0002136230468750, 0.0000305175781250, 0.0010986328125000, +0.0000000000000000, 0.0004272460937500, 0.0000305175781250, 0.0014953613281250, +0.0000305175781250, 0.0017700195312500, 0.0000000000000000, 0.0012817382812500, +0.0000000000000000, 0.0015563964843750, 0.0000305175781250, 0.0017089843750000, +-0.0000305175781250, 0.0003662109375000, -0.0000305175781250, 0.0007629394531250, +0.0000000000000000, 0.0002441406250000, 0.0000000000000000, -0.0009765625000000, +0.0000000000000000, -0.0004577636718750, 0.0000305175781250, -0.0012817382812500, +0.0000305175781250, -0.0016174316406250, 0.0000305175781250, -0.0011596679687500, +0.0000000000000000, -0.0010986328125000, 0.0000610351562500, -0.0013427734375000, +-0.0000305175781250, 0.0000305175781250, -0.0000610351562500, -0.0001525878906250, +-0.0000305175781250, 0.0000610351562500, -0.0000305175781250, 0.0011291503906250, +-0.0000610351562500, 0.0007934570312500, 0.0000915527343750, 0.0006713867187500, +0.0000610351562500, 0.0010986328125000, 0.0000305175781250, 0.0004882812500000, +0.0000305175781250, -0.0001525878906250, 0.0000610351562500, 0.0003356933593750, +-0.0000610351562500, -0.0006408691406250, -0.0000610351562500, -0.0007629394531250, +-0.0000305175781250, -0.0005798339843750, -0.0000915527343750, -0.0009765625000000, +-0.0000915527343750, -0.0009155273437500, 0.0000610351562500, -0.0001525878906250, +0.0000000000000000, -0.0004272460937500, 0.0000305175781250, -0.0000610351562500, +0.0001831054687500, 0.0008239746093750, 0.0001220703125000, 0.0004272460937500, +-0.0000610351562500, 0.0005187988281250, 0.0000000000000000, 0.0009765625000000, +-0.0000305175781250, 0.0003051757812500, -0.0002441406250000, -0.0003967285156250, +-0.0001831054687500, 0.0001831054687500, -0.0000305175781250, -0.0007629394531250, +-0.0001525878906250, -0.0011901855468750, 0.0000000000000000, -0.0004882812500000, +0.0002746582031250, -0.0003051757812500, 0.0000915527343750, -0.0007629394531250, +0.0001525878906250, 0.0006103515625000, 0.0002746582031250, 0.0007629394531250, +0.0000305175781250, 0.0003051757812500, -0.0002441406250000, 0.0007324218750000, +-0.0000610351562500, 0.0008850097656250, -0.0002746582031250, -0.0003967285156250, +-0.0004882812500000, -0.0003051757812500, -0.0002136230468750, -0.0001525878906250, +0.0001525878906250, -0.0009460449218750, 0.0003662109375000, 0.0008850097656250, +-0.0005493164062500, -0.0005187988281250, -0.0003662109375000, -0.0001525878906250, +-0.0001525878906250, -0.0000915527343750, -0.0004272460937500, -0.0007019042968750, +-0.0006103515625000, -0.0007324218750000, 0.0003662109375000, 0.0002136230468750, +0.0002746582031250, 0.0001220703125000, 0.0002441406250000, 0.0000610351562500, +0.0009765625000000, 0.0006103515625000, 0.0007934570312500, 0.0006408691406250, +-0.0000915527343750, -0.0001220703125000, 0.0003662109375000, 0.0000610351562500, +-0.0000610351562500, 0.0000610351562500, -0.0012817382812500, -0.0005798339843750, +-0.0007019042968750, -0.0004882812500000, -0.0005187988281250, 0.0000000000000000, +-0.0011901855468750, -0.0001525878906250, -0.0003662109375000, -0.0000610351562500, +0.0007934570312500, 0.0004272460937500, 0.0000000000000000, 0.0003051757812500, +0.0008850097656250, 0.0000000000000000, 0.0014953613281250, 0.0001831054687500, +0.0005187988281250, 0.0000610351562500, 0.0000305175781250, -0.0003356933593750, +0.0007324218750000, -0.0001831054687500, -0.0009765625000000, -0.0000305175781250, +-0.0011596679687500, -0.0001525878906250, -0.0006713867187500, -0.0000610351562500, +-0.0013122558593750, 0.0002441406250000, -0.0014038085937500, 0.0001525878906250, +0.0002441406250000, 0.0000305175781250, -0.0001831054687500, 0.0001220703125000, +0.0000915527343750, 0.0000305175781250, 0.0014953613281250, -0.0001525878906250, +0.0009765625000000, -0.0001220703125000, 0.0006103515625000, -0.0000305175781250, +0.0012512207031250, -0.0001220703125000, 0.0004577636718750, -0.0000610351562500, +-0.0006103515625000, 0.0001220703125000, 0.0001525878906250, 0.0000610351562500, +-0.0011291503906250, 0.0000000000000000, -0.0014038085937500, 0.0000915527343750, +-0.0009155273437500, 0.0000305175781250, -0.0011901855468750, -0.0001220703125000, +-0.0014343261718750, 0.0000000000000000, 0.0000610351562500, 0.0000000000000000, +-0.0003356933593750, -0.0000610351562500, 0.0000305175781250, 0.0000000000000000, +0.0014038085937500, 0.0000915527343750, 0.0007629394531250, 0.0000610351562500, +0.0011291503906250, -0.0000305175781250, 0.0016174316406250, 0.0000305175781250, +0.0010375976562500, 0.0000305175781250, 0.0007324218750000, -0.0000610351562500, +0.0011596679687500, -0.0000610351562500, -0.0003051757812500, 0.0000000000000000, +-0.0000610351562500, -0.0000305175781250, -0.0003967285156250, 0.0000000000000000, +-0.0014648437500000, 0.0000915527343750, -0.0009460449218750, 0.0000610351562500, +-0.0016479492187500, 0.0000000000000000, -0.0019226074218750, 0.0000000000000000, +-0.0014648437500000, -0.0000305175781250, -0.0014953613281250, -0.0000305175781250, +-0.0017700195312500, -0.0000305175781250, -0.0005187988281250, 0.0000305175781250, +-0.0009765625000000, 0.0000000000000000, -0.0003967285156250, 0.0000305175781250, +0.0007324218750000, 0.0000305175781250, -0.0000915527343750, 0.0000305175781250, +0.0014648437500000, -0.0000305175781250, 0.0013732910156250, 0.0000000000000000, +0.0014038085937500, 0.0000000000000000, 0.0022583007812500, 0.0000000000000000, +0.0019531250000000, 0.0000305175781250, 0.0020751953125000, 0.0000305175781250, +0.0023498535156250, 0.0000305175781250, 0.0019836425781250, 0.0000305175781250, +0.0018005371093750, 0.0000000000000000, 0.0021362304687500, 0.0000000000000000, +0.0011596679687500, -0.0000305175781250, 0.0014953613281250, 0.0000305175781250, +0.0011901855468750, 0.0000305175781250, 0.0003356933593750, 0.0000000000000000, +0.0009155273437500, 0.0000305175781250, -0.0001525878906250, 0.0000305175781250, +0.0000610351562500, 0.0000305175781250, -0.0000915527343750, 0.0000305175781250, +-0.0007629394531250, 0.0000000000000000, -0.0001831054687500, 0.0000000000000000, +-0.0008850097656250, -0.0000305175781250, -0.0007629394531250, -0.0000305175781250, +-0.0007324218750000, 0.0000305175781250, -0.0011596679687500, 0.0000305175781250, +-0.0007324218750000, 0.0000305175781250, -0.0011596679687500, 0.0000000000000000, +-0.0010375976562500, 0.0000000000000000, -0.0009765625000000, 0.0000305175781250, +-0.0011596679687500, 0.0000305175781250, -0.0009155273437500, 0.0000000000000000, +-0.0008544921875000, 0.0000000000000000, -0.0008544921875000, 0.0000000000000000, +-0.0006103515625000, 0.0000000000000000, -0.0004272460937500, 0.0000000000000000, +-0.0002441406250000, -0.0000305175781250, 0.0000915527343750, 0.0000000000000000, +0.0000610351562500, 0.0000000000000000, 0.0004272460937500, 0.0000305175781250, +0.0007324218750000, 0.0000000000000000, 0.0007324218750000, 0.0000000000000000, +0.0012817382812500, 0.0000305175781250, 0.0013122558593750, 0.0000305175781250, +0.0013427734375000, 0.0000000000000000, 0.0017395019531250, 0.0000000000000000, +0.0016784667968750, 0.0000000000000000, 0.0016784667968750, -0.0000305175781250, +0.0018310546875000, 0.0000000000000000, 0.0014953613281250, 0.0000305175781250, +0.0012512207031250, -0.0000610351562500, 0.0014648437500000, -0.0000610351562500, +0.0004577636718750, 0.0000000000000000, 0.0005798339843750, 0.0000000000000000, +0.0002441406250000, 0.0000000000000000, -0.0005798339843750, 0.0000305175781250, +-0.0002746582031250, 0.0000305175781250, -0.0010986328125000, 0.0000305175781250, +-0.0012207031250000, 0.0000000000000000, -0.0011291503906250, 0.0000000000000000, +-0.0014343261718750, 0.0000610351562500, -0.0014038085937500, 0.0000000000000000, +-0.0007934570312500, 0.0000305175781250, -0.0010070800781250, 0.0000305175781250, +-0.0005493164062500, 0.0000000000000000, 0.0002441406250000, 0.0000000000000000, +-0.0001831054687500, 0.0000000000000000, 0.0007629394531250, -0.0000305175781250, +0.0009460449218750, 0.0000000000000000, 0.0007019042968750, 0.0000305175781250, +0.0009765625000000, 0.0000305175781250, 0.0010070800781250, 0.0000000000000000, +0.0001831054687500, 0.0000305175781250, 0.0003967285156250, 0.0000305175781250, +0.0000305175781250, -0.0000305175781250, -0.0007324218750000, -0.0000305175781250, +-0.0004577636718750, 0.0000000000000000, -0.0007019042968750, -0.0000305175781250, +-0.0010070800781250, -0.0000610351562500, -0.0005798339843750, 0.0000000000000000, +-0.0002441406250000, 0.0000305175781250, -0.0005798339843750, -0.0000305175781250, +0.0003967285156250, 0.0000915527343750, 0.0005187988281250, 0.0000915527343750, +0.0002441406250000, 0.0000000000000000, 0.0005798339843750, -0.0000305175781250, +0.0006103515625000, 0.0000305175781250, -0.0000915527343750, -0.0000915527343750, +0.0000000000000000, -0.0000915527343750, -0.0000610351562500, 0.0000000000000000, +-0.0006408691406250, 0.0000305175781250, -0.0004577636718750, -0.0000305175781250, +-0.0001220703125000, 0.0000305175781250, -0.0003662109375000, 0.0000915527343750, +-0.0000915527343750, 0.0000305175781250, 0.0004272460937500, 0.0000000000000000, +0.0001831054687500, 0.0000610351562500, 0.0001525878906250, -0.0000915527343750, +0.0004272460937500, -0.0001220703125000, 0.0001220703125000, -0.0000305175781250, +-0.0003051757812500, 0.0000000000000000, -0.0000305175781250, -0.0000915527343750, +-0.0002441406250000, 0.0000610351562500, -0.0004882812500000, 0.0001525878906250, +-0.0002136230468750, 0.0000305175781250, 0.0000915527343750, 0.0000000000000000, +-0.0000915527343750, 0.0000610351562500, 0.0001525878906250, -0.0000915527343750, +0.0003051757812500, -0.0001220703125000, 0.0001220703125000, 0.0000000000000000, +-0.0000915527343750, 0.0000305175781250, -0.0000915527343750, 0.0000000000000000, +-0.0000915527343750, 0.0000610351562500, -0.0002441406250000, 0.0001220703125000, +-0.0000915527343750, 0.0000000000000000, 0.0000915527343750, -0.0000305175781250, +-0.0000610351562500, -0.0000305175781250, 0.0000915527343750, -0.0000915527343750, +0.0002136230468750, -0.0001525878906250, 0.0000305175781250, 0.0000000000000000, +-0.0001220703125000, 0.0000610351562500, 0.0000610351562500, -0.0000305175781250, +-0.0000915527343750, 0.0000915527343750, -0.0002441406250000, 0.0001831054687500, +-0.0000610351562500, 0.0000000000000000, 0.0001220703125000, -0.0001220703125000, +-0.0000305175781250, -0.0000305175781250, 0.0000915527343750, -0.0002136230468750, +0.0002136230468750, -0.0003051757812500, 0.0000610351562500, -0.0000610351562500, +-0.0000915527343750, 0.0001220703125000, 0.0000305175781250, -0.0000915527343750, +-0.0000915527343750, 0.0002441406250000, -0.0001831054687500, 0.0004272460937500, +-0.0000610351562500, 0.0000915527343750, 0.0000610351562500, -0.0000610351562500, +-0.0000610351562500, 0.0001831054687500, 0.0000610351562500, -0.0003662109375000, +0.0001831054687500, -0.0004882812500000, 0.0000610351562500, -0.0002746582031250, +-0.0000305175781250, -0.0003356933593750, 0.0000305175781250, -0.0004577636718750, +-0.0000610351562500, 0.0002746582031250, -0.0001220703125000, 0.0002136230468750, +-0.0000305175781250, 0.0001525878906250, 0.0000305175781250, 0.0005798339843750, +-0.0000610351562500, 0.0005187988281250, 0.0000610351562500, -0.0000305175781250, +0.0000915527343750}, +{-0.0009765625000000, 0.0000305175781250, -0.0012512207031250, 0.0000305175781250, +-0.0008544921875000, 0.0000000000000000, -0.0009155273437500, 0.0000000000000000, +-0.0010986328125000, 0.0000305175781250, -0.0000915527343750, -0.0000305175781250, +-0.0001831054687500, -0.0000305175781250, 0.0000305175781250, 0.0000000000000000, +0.0008239746093750, 0.0000000000000000, 0.0005493164062500, -0.0000610351562500, +0.0005798339843750, 0.0000610351562500, 0.0008544921875000, 0.0000610351562500, +0.0003662109375000, 0.0000000000000000, -0.0001525878906250, 0.0000305175781250, +0.0002136230468750, 0.0000000000000000, -0.0005187988281250, 0.0000000000000000, +-0.0007324218750000, -0.0000305175781250, -0.0004577636718750, 0.0000000000000000, +-0.0005493164062500, -0.0000305175781250, -0.0007019042968750, -0.0000610351562500, +0.0001525878906250, 0.0000305175781250, 0.0001525878906250, 0.0000915527343750, +0.0000000000000000, 0.0000305175781250, 0.0004882812500000, 0.0000305175781250, +0.0004577636718750, 0.0000915527343750, -0.0000610351562500, -0.0000915527343750, +0.0000915527343750, -0.0000915527343750, -0.0000305175781250, -0.0000305175781250, +-0.0006103515625000, -0.0000305175781250, -0.0004272460937500, -0.0000915527343750, +-0.0001525878906250, 0.0000915527343750, -0.0003356933593750, 0.0001220703125000, +-0.0001525878906250, 0.0000305175781250, 0.0003662109375000, 0.0000610351562500, +0.0001220703125000, 0.0001525878906250, 0.0001525878906250, -0.0000610351562500, +0.0003662109375000, -0.0001220703125000, 0.0000915527343750, 0.0000000000000000, +-0.0002746582031250, -0.0000305175781250, -0.0000305175781250, -0.0001220703125000, +-0.0001831054687500, 0.0000610351562500, -0.0003967285156250, 0.0000915527343750, +-0.0001525878906250, 0.0000305175781250, 0.0001831054687500, -0.0000305175781250, +0.0001220703125000, -0.0000305175781250, 0.0000000000000000, -0.0000915527343750, +0.0001831054687500, -0.0001525878906250, 0.0000610351562500, -0.0000610351562500, +-0.0002136230468750, -0.0000305175781250, 0.0000000000000000, -0.0000610351562500, +-0.0000610351562500, 0.0000915527343750, -0.0002441406250000, 0.0001525878906250, +-0.0000610351562500, 0.0000000000000000, 0.0001831054687500, -0.0000305175781250, +0.0000305175781250, 0.0000610351562500, 0.0000610351562500, -0.0001220703125000, +0.0001831054687500, -0.0002136230468750, 0.0000305175781250, -0.0000610351562500, +-0.0001831054687500, 0.0000000000000000, -0.0000305175781250, -0.0001220703125000, +-0.0000610351562500, 0.0001525878906250, -0.0001831054687500, 0.0002746582031250, +-0.0000305175781250, 0.0000610351562500, 0.0002136230468750, 0.0000000000000000, +0.0000000000000000, 0.0001220703125000, 0.0000305175781250, -0.0003356933593750, +0.0001831054687500, -0.0003967285156250, 0.0000610351562500, -0.0002136230468750, +-0.0001525878906250, -0.0002441406250000, -0.0000305175781250, -0.0003967285156250, +-0.0000610351562500, 0.0003051757812500, -0.0001525878906250, 0.0002441406250000, +-0.0000305175781250, 0.0001220703125000, 0.0000915527343750, 0.0004882812500000, +0.0000000000000000, 0.0004882812500000, 0.0000610351562500, -0.0002136230468750, +0.0001525878906250, -0.0000915527343750, 0.0000305175781250, -0.0001220703125000, +-0.0000610351562500, -0.0007019042968750, 0.0000000000000000, -0.0005187988281250, +-0.0000610351562500, -0.0002441406250000, -0.0000915527343750, -0.0005493164062500, +-0.0000305175781250, -0.0001831054687500, 0.0000305175781250, 0.0004272460937500, +0.0000000000000000, 0.0000610351562500, 0.0000305175781250, 0.0004272460937500, +0.0000915527343750, 0.0007019042968750, 0.0000000000000000, 0.0002746582031250, +0.0000000000000000, -0.0000610351562500, 0.0000610351562500, 0.0003051757812500, +-0.0000305175781250, -0.0005187988281250, -0.0000610351562500, -0.0006408691406250, +0.0000000000000000, -0.0005187988281250, 0.0000305175781250, -0.0008239746093750, +-0.0000305175781250, -0.0008239746093750, 0.0000305175781250, -0.0001831054687500, +0.0000610351562500, -0.0003051757812500, 0.0000305175781250, 0.0000000000000000, +0.0000305175781250, 0.0006713867187500, 0.0000305175781250, 0.0003662109375000, +-0.0000305175781250, 0.0007324218750000, -0.0000305175781250, 0.0009765625000000, +0.0000000000000000, 0.0006408691406250, 0.0000000000000000, 0.0004882812500000, +-0.0000305175781250, 0.0006408691406250, 0.0000000000000000, -0.0001220703125000, +0.0000000000000000, -0.0000610351562500, -0.0000305175781250, -0.0002441406250000, +0.0000000000000000, -0.0007629394531250, 0.0000305175781250, -0.0006103515625000, +-0.0000305175781250, -0.0009155273437500, -0.0000305175781250, -0.0010681152343750, +0.0000000000000000, -0.0009460449218750, -0.0000305175781250, -0.0009460449218750, +0.0000000000000000, -0.0009460449218750, 0.0000610351562500, -0.0006103515625000, +0.0000000000000000, -0.0007019042968750, 0.0000000000000000, -0.0004577636718750, +0.0000000000000000, -0.0000305175781250, 0.0000305175781250, -0.0001831054687500, +0.0000000000000000, 0.0003967285156250, -0.0000305175781250, 0.0004577636718750, +0.0000000000000000, 0.0005187988281250, 0.0000000000000000, 0.0008850097656250, +0.0000000000000000, 0.0007934570312500, 0.0000000000000000, 0.0010070800781250, +0.0000000000000000, 0.0010375976562500, 0.0000305175781250, 0.0010375976562500, +0.0000305175781250, 0.0010681152343750, 0.0000000000000000, 0.0010681152343750, +0.0000000000000000, 0.0010375976562500, 0.0000000000000000, 0.0010681152343750, +0.0000305175781250, 0.0010681152343750, 0.0000000000000000, 0.0009765625000000, +0.0000000000000000, 0.0010070800781250, 0.0000305175781250, 0.0010070800781250, +-0.0000305175781250, 0.0010070800781250, 0.0000000000000000, 0.0010375976562500, +-0.0000305175781250, 0.0010681152343750, 0.0000305175781250, 0.0010070800781250, +-0.0000305175781250, 0.0011291503906250, 0.0000000000000000, 0.0010986328125000, +-0.0000305175781250, 0.0011596679687500, 0.0000000000000000, 0.0012207031250000, +0.0000000000000000, 0.0011901855468750, 0.0000000000000000, 0.0011596679687500, +0.0000305175781250, 0.0012817382812500, 0.0000000000000000, 0.0010986328125000, +-0.0000610351562500, 0.0009765625000000, 0.0000000000000000, 0.0011596679687500, +0.0000000000000000, 0.0004882812500000, 0.0000000000000000, 0.0007629394531250, +0.0000305175781250, 0.0004272460937500, 0.0000000000000000, -0.0002746582031250, +-0.0000305175781250, 0.0002746582031250, 0.0000000000000000, -0.0008850097656250, +0.0000000000000000, -0.0007629394531250, 0.0000000000000000, -0.0007934570312500, +-0.0000610351562500, -0.0014953613281250, 0.0000000000000000, -0.0012817382812500, +0.0000000000000000, -0.0011596679687500, -0.0000305175781250, -0.0014953613281250, +0.0000305175781250, -0.0010070800781250, 0.0000000000000000, -0.0004882812500000, +-0.0000305175781250, -0.0009155273437500, 0.0000000000000000, 0.0004577636718750, +0.0000000000000000, 0.0002746582031250, 0.0000000000000000, 0.0004882812500000, +-0.0000305175781250, 0.0015563964843750, 0.0000305175781250, 0.0011291503906250, +0.0000000000000000, 0.0012512207031250, 0.0000305175781250, 0.0016479492187500, +0.0000000000000000, 0.0009765625000000, 0.0000610351562500, 0.0004882812500000, +0.0000610351562500, 0.0009765625000000, -0.0000610351562500, -0.0005493164062500, +-0.0000305175781250, -0.0004577636718750, 0.0000000000000000, -0.0005493164062500, +-0.0000305175781250, -0.0015563964843750, -0.0000610351562500, -0.0012817382812500, +0.0000000000000000, -0.0011291503906250, 0.0000000000000000, -0.0015258789062500, +0.0000000000000000, -0.0008544921875000, 0.0000610351562500, -0.0001831054687500, +0.0000305175781250, -0.0006408691406250, -0.0000610351562500, 0.0007019042968750, +0.0000000000000000, 0.0008239746093750, 0.0000000000000000, 0.0005493164062500, +-0.0001220703125000, 0.0011291503906250, -0.0000915527343750, 0.0010986328125000, +0.0000610351562500, 0.0002441406250000, 0.0000000000000000, 0.0004882812500000, +0.0000000000000000, 0.0001220703125000, 0.0000915527343750, -0.0007934570312500, +0.0001220703125000, -0.0003662109375000, 0.0000305175781250, -0.0007629394531250, +0.0000305175781250, -0.0010986328125000, 0.0000000000000000, -0.0006408691406250, +-0.0001525878906250, -0.0003967285156250, -0.0000915527343750, -0.0007019042968750, +-0.0000610351562500, 0.0003356933593750, -0.0000915527343750, 0.0003356933593750, +0.0000000000000000, 0.0002746582031250, 0.0001831054687500, 0.0009155273437500, +0.0000915527343750, 0.0007934570312500, 0.0000610351562500, 0.0000610351562500, +0.0001831054687500, 0.0004577636718750, 0.0000000000000000, -0.0000305175781250, +-0.0001525878906250, -0.0010681152343750, -0.0000305175781250, -0.0005187988281250, +-0.0001525878906250, -0.0006713867187500, -0.0003051757812500, -0.0012512207031250, +-0.0000915527343750, -0.0004272460937500, 0.0000915527343750, 0.0004882812500000, +-0.0000610351562500, -0.0001831054687500, 0.0002136230468750, 0.0006713867187500, +0.0003356933593750, 0.0011596679687500, 0.0001220703125000, 0.0003356933593750, +0.0000915527343750, -0.0001220703125000, 0.0002136230468750, 0.0005187988281250, +-0.0003356933593750, -0.0007324218750000, -0.0003967285156250, -0.0010070800781250, +-0.0001831054687500, -0.0004882812500000, -0.0003051757812500, -0.0003967285156250, +0.0004577636718750, 0.0005798339843750, -0.0003662109375000, -0.0007629394531250, +0.0000915527343750, -0.0008544921875000, -0.0001525878906250, -0.0003051757812500, +-0.0008239746093750, -0.0002441406250000, -0.0006408691406250, -0.0006408691406250, +0.0000000000000000, 0.0004577636718750, -0.0004577636718750, 0.0007019042968750, +-0.0000305175781250, 0.0001831054687500, 0.0009155273437500, 0.0003356933593750, +0.0004882812500000, 0.0006103515625000, 0.0005187988281250, -0.0003662109375000, +0.0010681152343750, -0.0005187988281250, 0.0002441406250000, -0.0001525878906250, +-0.0006713867187500, -0.0004272460937500, 0.0000610351562500, -0.0005187988281250, +-0.0010070800781250, 0.0002136230468750, -0.0015258789062500, 0.0003051757812500, +-0.0006103515625000, 0.0000610351562500, -0.0002136230468750, 0.0003356933593750, +-0.0009460449218750, 0.0003967285156250, 0.0009155273437500, -0.0001220703125000, +0.0010681152343750, -0.0001525878906250, 0.0004577636718750, -0.0000305175781250, +0.0010375976562500, -0.0003356933593750, 0.0013122558593750, -0.0003356933593750, +-0.0004882812500000, 0.0001220703125000, -0.0001525878906250, 0.0001220703125000, +-0.0003051757812500, 0.0000305175781250, -0.0017089843750000, 0.0002441406250000, +-0.0012817382812500, 0.0002441406250000, -0.0005798339843750, -0.0000915527343750, +-0.0012512207031250, -0.0000305175781250, -0.0004577636718750, 0.0000000000000000, +0.0009155273437500, -0.0001831054687500, 0.0000915527343750, -0.0002136230468750, +0.0009765625000000, 0.0000610351562500, 0.0015258789062500, 0.0000000000000000, +0.0007324218750000, 0.0000305175781250, 0.0003662109375000, 0.0001831054687500, +0.0009155273437500, 0.0001525878906250, -0.0006713867187500, -0.0000305175781250, +-0.0006408691406250, 0.0000305175781250, -0.0005798339843750, 0.0000000000000000, +-0.0015258789062500, -0.0000915527343750, -0.0012817382812500, -0.0000915527343750, +-0.0006408691406250, 0.0000610351562500, -0.0011901855468750, 0.0000305175781250, +-0.0005187988281250, 0.0000000000000000, 0.0005187988281250, 0.0000915527343750, +-0.0001831054687500, 0.0000915527343750, 0.0009765625000000, -0.0000305175781250, +0.0012207031250000, -0.0000305175781250, 0.0008850097656250, -0.0000305175781250, +0.0012512207031250}, +{0.0000000000000000, 0.0004577636718750, 0.0001525878906250, -0.0000305175781250, +0.0000610351562500, 0.0003356933593750, 0.0000610351562500, -0.0006713867187500, +0.0001525878906250, -0.0007629394531250, 0.0000305175781250, -0.0005187988281250, +-0.0001525878906250, -0.0008850097656250, -0.0000305175781250, -0.0009460449218750, +-0.0001220703125000, 0.0001525878906250, -0.0002441406250000, -0.0001831054687500, +-0.0000915527343750, 0.0000915527343750, 0.0001220703125000, 0.0011291503906250, +-0.0000610351562500, 0.0007629394531250, 0.0001831054687500, 0.0003662109375000, +0.0003051757812500, 0.0009460449218750, 0.0000610351562500, 0.0002136230468750, +0.0000305175781250, -0.0009765625000000, 0.0001220703125000, -0.0003662109375000, +-0.0003051757812500, -0.0006103515625000, -0.0003356933593750, -0.0013122558593750, +-0.0001220703125000, -0.0004272460937500, -0.0002441406250000, 0.0004882812500000, +-0.0003356933593750, -0.0002441406250000, 0.0002136230468750, 0.0007019042968750, +0.0002136230468750, 0.0011901855468750, 0.0001525878906250, 0.0004882812500000, +0.0005187988281250, -0.0001525878906250, -0.0004577636718750, -0.0003662109375000, +0.0000915527343750, 0.0006713867187500, -0.0003967285156250, 0.0010375976562500, +0.0000000000000000, 0.0003051757812500, 0.0007934570312500, -0.0002136230468750, +0.0004272460937500, 0.0003051757812500, 0.0002136230468750, -0.0005798339843750, +0.0007019042968750, -0.0009765625000000, 0.0000610351562500, -0.0003356933593750, +-0.0008239746093750, -0.0000305175781250, -0.0002441406250000, -0.0004577636718750, +-0.0008239746093750, 0.0004272460937500, -0.0013427734375000, 0.0007019042968750, +-0.0004882812500000, 0.0002136230468750, 0.0000915527343750, 0.0001831054687500, +-0.0005798339843750, 0.0004882812500000, 0.0009155273437500, -0.0003051757812500, +0.0012512207031250, -0.0004272460937500, 0.0004577636718750, -0.0001525878906250, +0.0007324218750000, -0.0002136230468750, 0.0011901855468750, -0.0004272460937500, +-0.0007629394531250, 0.0002136230468750, -0.0006713867187500, 0.0003356933593750, +-0.0004577636718750, 0.0000610351562500, -0.0015258789062500, 0.0002136230468750, +-0.0014343261718750, 0.0003356933593750, 0.0000305175781250, -0.0001831054687500, +-0.0005493164062500, -0.0002136230468750, -0.0000915527343750, -0.0000610351562500, +0.0014343261718750, -0.0002136230468750, 0.0007934570312500, -0.0003051757812500, +0.0007324218750000, 0.0001525878906250, 0.0014343261718750, 0.0001525878906250, +0.0005493164062500, 0.0000610351562500, -0.0005798339843750, 0.0001525878906250, +0.0002441406250000, 0.0002441406250000, -0.0010986328125000, -0.0000915527343750, +-0.0014648437500000, -0.0000915527343750, -0.0007934570312500, -0.0000305175781250, +-0.0008239746093750, -0.0001220703125000, -0.0012207031250000, -0.0001831054687500, +0.0002441406250000, 0.0000610351562500, 0.0000305175781250, 0.0000915527343750, +0.0001525878906250, 0.0000000000000000, 0.0012512207031250, 0.0000915527343750, +0.0008544921875000, 0.0001220703125000, 0.0006408691406250, -0.0000305175781250, +0.0011901855468750, -0.0000610351562500, 0.0005187988281250, 0.0000000000000000, +-0.0002746582031250, -0.0000610351562500, 0.0003662109375000, -0.0000915527343750, +-0.0007934570312500, 0.0000305175781250, -0.0009155273437500, 0.0000915527343750, +-0.0006713867187500, 0.0000000000000000, -0.0011291503906250, 0.0000305175781250, +-0.0011291503906250, 0.0000305175781250, -0.0005187988281250, -0.0000305175781250, +-0.0007629394531250, -0.0000305175781250, -0.0004272460937500, -0.0000305175781250, +0.0002746582031250, 0.0000000000000000, -0.0001525878906250, -0.0000305175781250, +0.0006408691406250, 0.0000000000000000, 0.0007324218750000, 0.0000610351562500, +0.0005798339843750, 0.0000000000000000, 0.0009155273437500, -0.0000305175781250, +0.0008850097656250, 0.0000305175781250, 0.0003051757812500, -0.0000305175781250, +0.0006713867187500, -0.0000610351562500, 0.0002136230468750, 0.0000000000000000, +-0.0005187988281250, 0.0000305175781250, 0.0000000000000000, 0.0000000000000000, +-0.0010986328125000, 0.0000000000000000, -0.0010681152343750, 0.0000305175781250, +-0.0010375976562500, 0.0000000000000000, -0.0016784667968750, 0.0000000000000000, +-0.0014343261718750, 0.0000000000000000, -0.0012817382812500, 0.0000000000000000, +-0.0016784667968750, 0.0000305175781250, -0.0011901855468750, 0.0000305175781250, +-0.0007019042968750, 0.0000000000000000, -0.0012512207031250, 0.0000610351562500, +0.0002136230468750, -0.0000305175781250, -0.0003051757812500, 0.0000000000000000, +0.0001525878906250, 0.0000305175781250, 0.0014343261718750, -0.0000305175781250, +0.0004882812500000, 0.0000000000000000, 0.0019836425781250, 0.0000000000000000, +0.0018005371093750, 0.0000305175781250, 0.0019531250000000, -0.0000305175781250, +0.0027770996093750, 0.0000000000000000, 0.0021362304687500, -0.0000305175781250, +0.0029602050781250, 0.0000000000000000, 0.0028076171875000, 0.0000000000000000, +0.0028381347656250, 0.0000305175781250, 0.0032958984375000, 0.0000000000000000, +0.0028686523437500, 0.0000000000000000, 0.0032653808593750, 0.0000000000000000, +0.0031127929687500, 0.0000305175781250, 0.0029907226562500, 0.0000305175781250, +0.0031127929687500, 0.0000000000000000, 0.0028686523437500, 0.0000000000000000, +0.0026245117187500, 0.0000305175781250, 0.0025329589843750, 0.0000000000000000, +0.0021972656250000, 0.0000000000000000, 0.0018005371093750, 0.0000000000000000, +0.0016174316406250, 0.0000000000000000, 0.0009460449218750, 0.0000000000000000, +0.0009765625000000, -0.0000305175781250, 0.0004272460937500, 0.0000000000000000, +-0.0002441406250000, 0.0000000000000000, -0.0000915527343750, 0.0000000000000000, +-0.0010681152343750, 0.0000305175781250, -0.0010681152343750, 0.0000305175781250, +-0.0012512207031250, 0.0000305175781250, -0.0019226074218750, 0.0000000000000000, +-0.0017700195312500, -0.0000305175781250, -0.0018920898437500, 0.0000305175781250, +-0.0021057128906250, 0.0000000000000000, -0.0017700195312500, 0.0000000000000000, +-0.0015869140625000, 0.0000000000000000, -0.0017700195312500, -0.0000305175781250, +-0.0007934570312500, -0.0000305175781250, -0.0009155273437500, -0.0000305175781250, +-0.0005187988281250, 0.0000000000000000, 0.0003356933593750, 0.0000000000000000, +0.0000305175781250, 0.0000000000000000, 0.0008239746093750, 0.0000305175781250, +0.0009155273437500, 0.0000305175781250, 0.0007324218750000, -0.0000305175781250, +0.0009460449218750, 0.0000305175781250, 0.0009765625000000, 0.0000305175781250, +0.0002746582031250, -0.0000305175781250, 0.0004272460937500, -0.0000305175781250, +0.0000305175781250, 0.0000000000000000, -0.0007019042968750, 0.0000000000000000, +-0.0003662109375000, -0.0000305175781250, -0.0008544921875000, 0.0000305175781250, +-0.0011291503906250, 0.0000305175781250, -0.0006408691406250, 0.0000305175781250, +-0.0004272460937500, 0.0000305175781250, -0.0007324218750000, 0.0000305175781250, +0.0002441406250000, -0.0000305175781250, 0.0003051757812500, -0.0000305175781250, +0.0003051757812500, 0.0000000000000000, 0.0008850097656250, -0.0000305175781250, +0.0007934570312500, -0.0000915527343750, 0.0002441406250000, 0.0000305175781250, +0.0005493164062500, 0.0000000000000000, 0.0001220703125000, 0.0000000000000000, +-0.0006408691406250, 0.0000305175781250, -0.0002441406250000, 0.0000305175781250, +-0.0006103515625000, -0.0000305175781250, -0.0009460449218750, -0.0000305175781250, +-0.0004882812500000, -0.0000305175781250, -0.0001525878906250, -0.0000915527343750, +-0.0004882812500000, -0.0000610351562500, 0.0003662109375000, 0.0000915527343750, +0.0005493164062500, 0.0000305175781250, 0.0001831054687500, 0.0000305175781250, +0.0003051757812500, 0.0001220703125000, 0.0004577636718750, 0.0000915527343750, +-0.0003051757812500, -0.0000610351562500, -0.0003356933593750, -0.0000305175781250, +-0.0001525878906250, -0.0000305175781250, -0.0005187988281250, -0.0001220703125000, +-0.0005187988281250, -0.0000915527343750, 0.0000610351562500, 0.0000610351562500, +-0.0000305175781250, 0.0000305175781250, -0.0000305175781250, 0.0000000000000000, +0.0004272460937500, 0.0001525878906250, 0.0003662109375000, 0.0000915527343750, +-0.0000305175781250, -0.0000915527343750, 0.0001220703125000, -0.0000305175781250, +0.0000000000000000, 0.0000000000000000, -0.0004577636718750, -0.0001525878906250, +-0.0002746582031250, -0.0001220703125000, -0.0000610351562500, 0.0000610351562500, +-0.0002136230468750, 0.0000305175781250, -0.0001220703125000, 0.0000305175781250, +0.0003051757812500, 0.0000915527343750, 0.0002136230468750, 0.0000610351562500, +-0.0001220703125000, -0.0001525878906250, 0.0000610351562500, -0.0000610351562500, +0.0000000000000000, -0.0000305175781250, -0.0002746582031250, -0.0001831054687500, +-0.0001831054687500, -0.0001220703125000, 0.0000305175781250, 0.0000610351562500, +-0.0001220703125000, 0.0000915527343750, -0.0000610351562500, 0.0000000000000000, +0.0002441406250000, 0.0001220703125000, 0.0001525878906250, 0.0001220703125000, +-0.0000610351562500, -0.0001525878906250, 0.0000305175781250, -0.0001525878906250, +-0.0000305175781250, -0.0000610351562500, -0.0002746582031250, -0.0001831054687500, +-0.0001831054687500, -0.0002441406250000, 0.0000305175781250, 0.0001525878906250, +-0.0001220703125000, 0.0001831054687500, -0.0000610351562500, 0.0000305175781250, +0.0001831054687500, 0.0002441406250000, 0.0001525878906250, 0.0002441406250000, +0.0000000000000000, -0.0002746582031250, 0.0000915527343750, -0.0002136230468750, +0.0000305175781250, -0.0001525878906250, -0.0002441406250000, -0.0005187988281250, +-0.0001220703125000, -0.0004882812500000, 0.0000000000000000, 0.0000610351562500, +-0.0001220703125000, -0.0000915527343750, -0.0000305175781250, 0.0000000000000000, +0.0002136230468750, 0.0005798339843750, 0.0000915527343750, 0.0003967285156250, +0.0000000000000000, 0.0000610351562500, 0.0000610351562500, 0.0003662109375000, +0.0000000000000000, 0.0000610351562500, -0.0001220703125000, -0.0005798339843750, +-0.0000610351562500, -0.0002441406250000, 0.0000000000000000, -0.0004272460937500, +-0.0000915527343750, -0.0007019042968750, -0.0000610351562500, -0.0003356933593750, +0.0001220703125000, 0.0000000000000000, 0.0000000000000000, -0.0002746582031250, +0.0000000000000000, 0.0003356933593750, 0.0000610351562500, 0.0005187988281250, +0.0000305175781250, 0.0002441406250000, -0.0000610351562500, 0.0003356933593750, +0.0000000000000000, 0.0004882812500000, 0.0000000000000000, -0.0002136230468750, +-0.0000305175781250, -0.0001525878906250, -0.0000305175781250, -0.0001831054687500, +0.0000305175781250, -0.0006713867187500, 0.0000000000000000, -0.0005493164062500, +0.0000305175781250, -0.0003051757812500, 0.0000305175781250, -0.0004577636718750, +0.0000305175781250, -0.0002441406250000, -0.0000305175781250, 0.0002136230468750, +-0.0000305175781250, 0.0000305175781250, -0.0000305175781250, 0.0003051757812500, +-0.0000305175781250, 0.0004272460937500, 0.0000000000000000, 0.0002136230468750, +0.0000000000000000, 0.0001220703125000, -0.0000305175781250, 0.0002746582031250, +0.0000000000000000, -0.0001831054687500, 0.0000000000000000, -0.0001831054687500, +0.0000000000000000, -0.0001831054687500, 0.0000305175781250, -0.0003662109375000, +0.0000305175781250, -0.0003356933593750, 0.0000000000000000, -0.0001525878906250, +-0.0000610351562500, -0.0002746582031250, 0.0000000000000000, -0.0000305175781250, +0.0000000000000000, 0.0003051757812500, -0.0000305175781250, 0.0001525878906250, +0.0000305175781250}, +{-0.0005187988281250, -0.0001220703125000, 0.0000610351562500, 0.0000000000000000, +-0.0000610351562500, -0.0000610351562500, -0.0000305175781250, 0.0000000000000000, +0.0003967285156250, 0.0001525878906250, 0.0003356933593750, 0.0000915527343750, +-0.0000610351562500, -0.0000610351562500, 0.0000610351562500, 0.0000000000000000, +0.0000305175781250, 0.0000000000000000, -0.0003967285156250, -0.0001220703125000, +-0.0003051757812500, -0.0001220703125000, 0.0001220703125000, 0.0000610351562500, +-0.0000305175781250, -0.0000305175781250, -0.0000915527343750, -0.0000610351562500, +0.0002136230468750, 0.0001220703125000, 0.0001831054687500, 0.0001220703125000, +-0.0001220703125000, -0.0001220703125000, -0.0000915527343750, -0.0000610351562500, +0.0000000000000000, -0.0000610351562500, -0.0002136230468750, -0.0002136230468750, +-0.0002441406250000, -0.0001831054687500, 0.0000610351562500, 0.0000610351562500, +-0.0000305175781250, 0.0000305175781250, -0.0000305175781250, -0.0000305175781250, +0.0002136230468750, 0.0001220703125000, 0.0002136230468750, 0.0001525878906250, +-0.0000610351562500, -0.0002136230468750, -0.0000305175781250, -0.0001220703125000, +0.0000000000000000, -0.0001220703125000, -0.0002441406250000, -0.0003967285156250, +-0.0002136230468750, -0.0003967285156250, 0.0000610351562500, 0.0000915527343750, +0.0000305175781250, -0.0000305175781250, -0.0000305175781250, 0.0000000000000000, +0.0002136230468750, 0.0004882812500000, 0.0001525878906250, 0.0003356933593750, +-0.0000305175781250, -0.0000610351562500, 0.0000000000000000, 0.0001831054687500, +0.0000610351562500, -0.0000305175781250, -0.0001525878906250, -0.0006408691406250, +-0.0001220703125000, -0.0003967285156250, 0.0000305175781250, -0.0003051757812500, +-0.0000610351562500, -0.0005798339843750, 0.0000000000000000, -0.0002441406250000, +0.0001525878906250, 0.0002746582031250, 0.0001220703125000, -0.0000610351562500, +0.0000000000000000, 0.0003662109375000, 0.0000305175781250, 0.0006103515625000, +0.0000305175781250, 0.0002441406250000, -0.0000915527343750, 0.0000915527343750, +-0.0000915527343750, 0.0002746582031250, 0.0000000000000000, -0.0003051757812500, +-0.0000305175781250, -0.0003967285156250, 0.0000000000000000, -0.0002136230468750, +0.0000915527343750, -0.0003967285156250, 0.0000305175781250, -0.0004882812500000, +0.0000000000000000, -0.0000305175781250, 0.0000915527343750, -0.0000610351562500, +0.0000305175781250, 0.0000000000000000, -0.0000305175781250, 0.0003356933593750, +-0.0000305175781250, 0.0002746582031250, 0.0000000000000000, 0.0000305175781250, +-0.0000305175781250, 0.0001220703125000, 0.0000000000000000, 0.0000000000000000, +0.0000610351562500, -0.0003051757812500, 0.0000000000000000, -0.0002441406250000, +0.0000305175781250, -0.0000305175781250, 0.0000305175781250, -0.0002136230468750, +0.0000000000000000, 0.0001220703125000, -0.0000305175781250, 0.0005798339843750, +0.0000000000000000, 0.0003051757812500, -0.0000305175781250, 0.0008850097656250, +-0.0000610351562500, 0.0010681152343750, -0.0000305175781250, 0.0007629394531250, +0.0000610351562500, 0.0008544921875000, 0.0000000000000000, 0.0008850097656250, +0.0000000000000000, -0.0001525878906250, 0.0000305175781250, 0.0000610351562500, +0.0000000000000000, -0.0005493164062500, 0.0000000000000000, -0.0016784667968750, +-0.0000305175781250, -0.0012817382812500, 0.0000305175781250, -0.0026245117187500, +-0.0000305175781250, -0.0027160644531250, 0.0000305175781250, -0.0030822753906250, +0.0000000000000000, -0.0039978027343750, 0.0000000000000000, -0.0036621093750000, +0.0000000000000000, -0.0042114257812500, 0.0000000000000000, -0.0043029785156250, +0.0000000000000000, -0.0042114257812500, 0.0000000000000000, -0.0043029785156250, +0.0000305175781250, -0.0040893554687500, 0.0000000000000000, -0.0038146972656250, +-0.0000305175781250, -0.0034484863281250, 0.0000000000000000, -0.0032043457031250, +0.0000000000000000, -0.0031127929687500, 0.0000000000000000, -0.0029296875000000, +0.0000305175781250, -0.0022888183593750, 0.0000000000000000, -0.0017089843750000, +0.0000000000000000, -0.0017395019531250, 0.0000000000000000, -0.0015563964843750, +-0.0000305175781250, -0.0010681152343750, -0.0000305175781250, -0.0017395019531250, +0.0000000000000000, -0.0014343261718750, -0.0000305175781250, -0.0016479492187500, +0.0000000000000000, -0.0022583007812500, 0.0000000000000000, -0.0018920898437500, +0.0000000000000000, -0.0029907226562500, 0.0000000000000000, -0.0025024414062500, +0.0000000000000000, -0.0033264160156250, 0.0000000000000000, -0.0046386718750000, +0.0000000000000000, -0.0035705566406250, 0.0000000000000000, -0.0054626464843750, +0.0000305175781250, -0.0054321289062500, 0.0000305175781250, -0.0054626464843750, +0.0000305175781250, -0.0066223144531250, -0.0000305175781250, -0.0061340332031250, +0.0000000000000000, -0.0061340332031250, 0.0000000000000000, -0.0067749023437500, +0.0000000000000000, -0.0057983398437500, 0.0000000000000000, -0.0051574707031250, +0.0000000000000000, -0.0058898925781250, 0.0000305175781250, -0.0030212402343750, +0.0000000000000000, -0.0038452148437500, 0.0000000000000000, -0.0028991699218750, +0.0000305175781250, -0.0003967285156250, -0.0000305175781250, -0.0018005371093750, +0.0000000000000000, 0.0010375976562500, 0.0000610351562500, 0.0011901855468750, +0.0000000000000000, 0.0009765625000000, -0.0000610351562500, 0.0023193359375000, +0.0000305175781250, 0.0019836425781250, 0.0000000000000000, 0.0014038085937500, +0.0000000000000000, 0.0019226074218750, 0.0000610351562500, 0.0013122558593750, +0.0000305175781250, 0.0002746582031250, 0.0000000000000000, 0.0008544921875000, +0.0000000000000000, -0.0001220703125000, 0.0000305175781250, -0.0003967285156250, +0.0000305175781250, -0.0000610351562500, 0.0000305175781250, -0.0002136230468750, +0.0000000000000000, -0.0003356933593750, -0.0000305175781250, 0.0001525878906250, +-0.0000305175781250, 0.0001220703125000, -0.0000305175781250, 0.0001220703125000, +0.0000305175781250, 0.0004882812500000, 0.0000000000000000, 0.0004272460937500, +0.0000305175781250, 0.0000610351562500, 0.0000915527343750, 0.0003051757812500, +0.0000000000000000, -0.0000305175781250, -0.0000610351562500, -0.0005798339843750, +0.0000000000000000, -0.0002441406250000, -0.0000305175781250, -0.0005798339843750, +-0.0000610351562500, -0.0008850097656250, 0.0000305175781250, -0.0004577636718750, +0.0000915527343750, -0.0002746582031250, 0.0000000000000000, -0.0005187988281250, +0.0000610351562500, 0.0003356933593750, 0.0001220703125000, 0.0003967285156250, +0.0000000000000000, 0.0003051757812500, -0.0000915527343750, 0.0007324218750000, +0.0000000000000000, 0.0006408691406250, -0.0000610351562500, 0.0002136230468750, +-0.0002136230468750, 0.0005187988281250, -0.0000610351562500, 0.0001220703125000, +0.0000610351562500, -0.0004882812500000, -0.0000305175781250, -0.0001525878906250, +0.0001525878906250, -0.0007324218750000, 0.0002136230468750, -0.0010070800781250, +0.0000305175781250, -0.0004882812500000, 0.0000000000000000, -0.0003662109375000, +0.0000915527343750, -0.0007019042968750, -0.0001831054687500, 0.0005493164062500, +-0.0002746582031250, 0.0005493164062500, -0.0001220703125000, 0.0003356933593750, +-0.0000915527343750, 0.0010070800781250, -0.0001831054687500, 0.0010070800781250, +0.0001831054687500, -0.0002136230468750, 0.0001525878906250, 0.0001220703125000, +0.0000305175781250, -0.0001220703125000, 0.0003051757812500, -0.0013732910156250, +0.0002441406250000, -0.0010070800781250, -0.0001831054687500, -0.0001831054687500, +-0.0000915527343750, -0.0007934570312500, -0.0001525878906250, -0.0002136230468750, +-0.0004882812500000, 0.0012512207031250, -0.0003967285156250, 0.0005798339843750, +0.0000305175781250, 0.0004272460937500, -0.0002136230468750, 0.0010986328125000, +-0.0000610351562500, 0.0004882812500000, 0.0006408691406250, -0.0010681152343750, +-0.0002136230468750, 0.0004272460937500, -0.0003662109375000, 0.0003051757812500, +-0.0007934570312500, 0.0010375976562500, -0.0001220703125000, 0.0002441406250000, +0.0004882812500000, -0.0008850097656250, -0.0000305175781250, -0.0003051757812500, +0.0005798339843750, -0.0003967285156250, 0.0010375976562500, -0.0009460449218750, +0.0003356933593750, -0.0003051757812500, 0.0000000000000000, 0.0005798339843750, +0.0004882812500000, 0.0000610351562500, -0.0009460449218750, 0.0003662109375000, +-0.0011596679687500, 0.0007934570312500, -0.0005187988281250, 0.0003051757812500, +-0.0008850097656250, -0.0003356933593750, -0.0011901855468750, 0.0001220703125000, +0.0006103515625000, -0.0003051757812500, 0.0004272460937500, -0.0007019042968750, +0.0002746582031250, -0.0002441406250000, 0.0014343261718750, 0.0001831054687500, +0.0013122558593750, -0.0001831054687500, -0.0000915527343750, 0.0002746582031250, +0.0004882812500000, 0.0005187988281250, 0.0000610351562500, 0.0001220703125000, +-0.0015258789062500, -0.0000915527343750, -0.0008850097656250, 0.0001525878906250, +-0.0006103515625000, -0.0002136230468750, -0.0013427734375000, -0.0004272460937500, +-0.0004577636718750, -0.0001525878906250, 0.0007324218750000, 0.0000305175781250, +-0.0000610351562500, -0.0001831054687500, 0.0008544921875000, 0.0001525878906250, +0.0013732910156250, 0.0003356933593750, 0.0005493164062500, 0.0000915527343750, +0.0002441406250000, 0.0000000000000000, 0.0007629394531250, 0.0001220703125000, +-0.0006408691406250, -0.0001220703125000, -0.0007934570312500, -0.0002441406250000, +-0.0003662109375000, -0.0000610351562500, -0.0007934570312500, 0.0000305175781250, +-0.0009155273437500, -0.0000610351562500, -0.0000305175781250, 0.0000915527343750, +-0.0002136230468750, 0.0001831054687500, -0.0000915527343750, 0.0000610351562500, +0.0005493164062500, -0.0000305175781250, 0.0003051757812500, 0.0001220703125000, +0.0001525878906250, -0.0000610351562500, 0.0005187988281250, -0.0001220703125000, +0.0001525878906250, -0.0000610351562500, -0.0003967285156250, 0.0000305175781250, +0.0000000000000000, -0.0000610351562500, -0.0003967285156250, 0.0000915527343750, +-0.0007324218750000, 0.0000915527343750, -0.0001831054687500, 0.0000305175781250, +0.0000915527343750, 0.0000000000000000, -0.0003356933593750, 0.0000305175781250, +0.0009765625000000, -0.0000305175781250, 0.0008544921875000, -0.0000915527343750, +0.0008850097656250, 0.0000000000000000, 0.0017700195312500, 0.0000610351562500, +0.0014953613281250, 0.0000000000000000, 0.0010681152343750, 0.0000000000000000, +0.0017395019531250, 0.0000305175781250, 0.0006713867187500, 0.0000610351562500, +-0.0002746582031250, -0.0000610351562500, 0.0007324218750000, -0.0000305175781250, +-0.0025634765625000, 0.0000000000000000, -0.0016784667968750, -0.0000610351562500, +-0.0026550292968750, 0.0000000000000000, -0.0054321289062500, 0.0000305175781250, +-0.0036926269531250, 0.0000305175781250, -0.0059814453125000, 0.0000000000000000, +-0.0065612792968750, 0.0000305175781250, -0.0054321289062500, 0.0000000000000000, +-0.0061035156250000, -0.0000305175781250, -0.0067749023437500, 0.0000000000000000, +-0.0031433105468750, 0.0000000000000000, -0.0050354003906250, 0.0000000000000000, +-0.0028991699218750, 0.0000000000000000, 0.0005187988281250, 0.0000305175781250, +-0.0026245117187500, 0.0000000000000000, 0.0049133300781250, 0.0000000000000000, +0.0027770996093750, 0.0000000000000000, 0.0046691894531250, -0.0000305175781250, +0.0104675292968750, -0.0000305175781250, 0.0065307617187500, 0.0000000000000000, +0.0132446289062500, 0.0000305175781250, 0.0121765136718750, 0.0000610351562500, +0.0129089355468750}, +{-0.0010070800781250, 0.0006713867187500, -0.0003967285156250, 0.0001831054687500, +-0.0004577636718750, -0.0008850097656250, -0.0008239746093750, -0.0003967285156250, +0.0006713867187500, -0.0003051757812500, 0.0006713867187500, -0.0007934570312500, +0.0003662109375000, -0.0003051757812500, 0.0011291503906250, 0.0005493164062500, +0.0012207031250000, 0.0001220703125000, -0.0003662109375000, 0.0002136230468750, +0.0000000000000000, 0.0006408691406250, -0.0001831054687500, 0.0001525878906250, +-0.0015869140625000, -0.0003967285156250, -0.0011596679687500, -0.0000305175781250, +-0.0002746582031250, -0.0002441406250000, -0.0010070800781250, -0.0005187988281250, +-0.0003356933593750, -0.0001525878906250, 0.0011596679687500, 0.0002441406250000, +0.0004577636718750, -0.0000610351562500, 0.0006103515625000, 0.0002136230468750, +0.0012817382812500, 0.0004272460937500, 0.0004882812500000, 0.0001220703125000, +-0.0003662109375000, -0.0002136230468750, 0.0003051757812500, 0.0000305175781250, +-0.0007629394531250, -0.0002136230468750, -0.0011596679687500, -0.0003662109375000, +-0.0004882812500000, -0.0000915527343750, -0.0003051757812500, 0.0001525878906250, +-0.0007629394531250, -0.0000610351562500, 0.0003051757812500, 0.0000610351562500, +0.0005187988281250, 0.0002441406250000, 0.0000915527343750, 0.0000610351562500, +0.0002441406250000, -0.0001220703125000, 0.0004882812500000, 0.0000305175781250, +-0.0003051757812500, -0.0000915527343750, -0.0003967285156250, -0.0002136230468750, +-0.0000915527343750, -0.0000610351562500, -0.0003662109375000, 0.0000610351562500, +-0.0004882812500000, 0.0000000000000000, 0.0005798339843750, 0.0000305175781250, +0.0002136230468750, 0.0001525878906250, 0.0006103515625000, 0.0000000000000000, +0.0017395019531250, -0.0000610351562500, 0.0011291503906250, 0.0000000000000000, +0.0008544921875000, 0.0000305175781250, 0.0017395019531250, -0.0001220703125000, +0.0004577636718750, -0.0000305175781250, -0.0008239746093750, 0.0000610351562500, +0.0003051757812500, 0.0000305175781250, -0.0030212402343750, 0.0000610351562500, +-0.0028686523437500, 0.0000610351562500, -0.0028991699218750, 0.0000305175781250, +-0.0049743652343750, -0.0000610351562500, -0.0042114257812500, -0.0000305175781250, +-0.0028686523437500, 0.0000000000000000, -0.0046386718750000, -0.0000305175781250, +-0.0017395019531250, -0.0000305175781250, 0.0011901855468750, 0.0000610351562500, +-0.0016174316406250, 0.0000305175781250, 0.0069274902343750, -0.0000305175781250, +0.0049743652343750, 0.0000610351562500, 0.0070190429687500, 0.0000305175781250, +0.0138854980468750, -0.0000610351562500, 0.0098876953125000, -0.0000305175781250, +0.0144348144531250, 0.0000305175781250, 0.0164794921875000, 0.0000000000000000, +0.0124206542968750, 0.0000000000000000, 0.0130004882812500, 0.0000305175781250, +0.0159301757812500, 0.0000610351562500, 0.0016479492187500, 0.0000000000000000, +0.0086059570312500, 0.0000305175781250, -0.0003662109375000, 0.0000305175781250, +-0.0138854980468750, 0.0000000000000000, -0.0011596679687500, 0.0000305175781250, +-0.0329895019531250, 0.0000305175781250, -0.0226135253906250, 0.0000305175781250, +-0.0323791503906250, 0.0000610351562500, -0.0581665039062500, 0.0000610351562500, +-0.0392761230468750, 0.0000610351562500, -0.0732727050781250, 0.0000610351562500, +-0.0659484863281250, 0.0000610351562500, -0.0714721679687500, 0.0000305175781250, +-0.0931091308593750, 0.0000610351562500, -0.0736083984375000, 0.0000305175781250, +-0.0965881347656250, 0.0000915527343750, -0.0910034179687500, 0.0000305175781250, +-0.0900573730468750, 0.0000305175781250, -0.1019897460937500, 0.0000610351562500, +-0.0890197753906250, 0.0000305175781250, -0.0983581542968750, 0.0000610351562500, +-0.0944213867187500, 0.0000610351562500, -0.0891418457031250, 0.0000610351562500, +-0.0917968750000000, 0.0000915527343750, -0.0848999023437500, 0.0000610351562500, +-0.0762634277343750, 0.0000915527343750, -0.0733032226562500, 0.0000610351562500, +-0.0650939941406250, 0.0000610351562500, -0.0552368164062500, 0.0000610351562500, +-0.0518798828125000, 0.0000305175781250, -0.0380554199218750, 0.0000000000000000, +-0.0373229980468750, 0.0000305175781250, -0.0285949707031250, 0.0000305175781250, +-0.0160217285156250, 0.0000305175781250, -0.0191650390625000, 0.0000305175781250, +-0.0023803710937500, 0.0000915527343750, -0.0025939941406250, 0.0000305175781250, +0.0005187988281250, 0.0000305175781250, 0.0119018554687500, 0.0000000000000000, +0.0089416503906250, 0.0000305175781250, 0.0142822265625000, 0.0000000000000000, +0.0163879394531250, 0.0000000000000000, 0.0142211914062500, 0.0000000000000000, +0.0147399902343750, 0.0000305175781250, 0.0156250000000000, -0.0000305175781250, +0.0092773437500000, 0.0000000000000000, 0.0104675292968750, -0.0000305175781250, +0.0072937011718750, 0.0000000000000000, 0.0010986328125000, 0.0000305175781250, +0.0036010742187500, 0.0000305175781250, -0.0028076171875000, 0.0000305175781250, +-0.0035400390625000, 0.0000305175781250, -0.0029907226562500, 0.0000305175781250, +-0.0057678222656250, 0.0000000000000000, -0.0053405761718750, -0.0000610351562500, +-0.0034179687500000, 0.0000305175781250, -0.0043334960937500, -0.0000305175781250, +-0.0026550292968750, 0.0000000000000000, 0.0000305175781250, 0.0000610351562500, +-0.0013122558593750, 0.0000000000000000, 0.0012817382812500, 0.0000000000000000, +0.0019531250000000, -0.0000305175781250, 0.0011596679687500, -0.0000305175781250, +0.0016174316406250, -0.0000305175781250, 0.0018615722656250, 0.0000000000000000, +0.0002136230468750, 0.0000610351562500, 0.0003356933593750, -0.0000610351562500, +0.0000915527343750, 0.0000305175781250, -0.0010681152343750, 0.0000915527343750, +-0.0007629394531250, 0.0000305175781250, -0.0003967285156250, 0.0000000000000000, +-0.0007629394531250, 0.0000610351562500, -0.0002441406250000, 0.0000305175781250, +0.0006408691406250, -0.0000915527343750, 0.0002136230468750, -0.0000305175781250, +0.0003967285156250, 0.0000000000000000, 0.0007934570312500, -0.0000610351562500, +0.0002746582031250, 0.0000000000000000, -0.0003356933593750, 0.0000610351562500, +0.0000610351562500, 0.0000305175781250, -0.0004577636718750, 0.0000305175781250, +-0.0007934570312500, 0.0000915527343750, -0.0003356933593750, 0.0000305175781250, +0.0000000000000000, -0.0001220703125000, -0.0003051757812500, 0.0000000000000000, +0.0002746582031250, -0.0000915527343750, 0.0004882812500000, -0.0001525878906250, +0.0001525878906250, -0.0000305175781250, 0.0000305175781250, 0.0000915527343750, +0.0002746582031250, 0.0000000000000000, -0.0003662109375000, 0.0000305175781250, +-0.0004882812500000, 0.0001831054687500, -0.0002136230468750, 0.0000305175781250, +-0.0003356933593750, -0.0001525878906250, -0.0005187988281250, 0.0000000000000000, +0.0002136230468750, -0.0001220703125000, 0.0002746582031250, -0.0002136230468750, +0.0000610351562500, -0.0000915527343750, 0.0002441406250000, 0.0001220703125000, +0.0003662109375000, 0.0000305175781250, -0.0002441406250000, -0.0000305175781250, +-0.0002441406250000, 0.0000915527343750, -0.0001220703125000, 0.0000305175781250, +-0.0002746582031250, -0.0002136230468750, -0.0002136230468750, -0.0001525878906250, +0.0001525878906250, 0.0000000000000000, 0.0001220703125000, -0.0000915527343750, +-0.0000305175781250, -0.0000305175781250, 0.0001220703125000, 0.0001220703125000, +0.0002136230468750, 0.0000610351562500, -0.0001831054687500, -0.0000305175781250, +-0.0002136230468750, 0.0000915527343750, -0.0000610351562500, 0.0000000000000000, +-0.0001525878906250, -0.0002441406250000, -0.0002441406250000, -0.0001525878906250, +0.0001525878906250, 0.0000000000000000, 0.0001525878906250, -0.0001525878906250, +0.0000000000000000, -0.0000610351562500, 0.0000915527343750, 0.0001831054687500, +0.0001525878906250, 0.0001525878906250, -0.0001525878906250, -0.0000610351562500, +-0.0002746582031250, 0.0000305175781250, -0.0001220703125000, -0.0000915527343750, +-0.0001220703125000, -0.0004577636718750, -0.0002441406250000, -0.0003051757812500, +0.0000915527343750, -0.0000915527343750, 0.0001525878906250, -0.0003356933593750, +0.0000305175781250, -0.0000915527343750, 0.0000915527343750, 0.0003662109375000, +0.0001525878906250, 0.0001525878906250, -0.0000915527343750, 0.0001525878906250, +-0.0001525878906250, 0.0003967285156250, -0.0000610351562500, 0.0000610351562500, +-0.0000915527343750, -0.0003356933593750, -0.0001525878906250, -0.0000915527343750, +0.0000915527343750, -0.0003051757812500, 0.0001220703125000, -0.0005187988281250, +0.0000305175781250, -0.0002441406250000, 0.0000915527343750, -0.0000305175781250, +0.0001220703125000, -0.0002136230468750, -0.0000305175781250, 0.0000610351562500, +-0.0000610351562500, 0.0002136230468750, 0.0000305175781250, 0.0000305175781250, +-0.0000610351562500, 0.0000000000000000, -0.0000915527343750, 0.0000610351562500, +0.0000305175781250, 0.0000610351562500, 0.0000305175781250, -0.0001525878906250, +0.0000305175781250, 0.0001220703125000, 0.0000610351562500, 0.0003967285156250, +0.0000610351562500, 0.0002441406250000, -0.0000305175781250, 0.0004577636718750, +0.0000000000000000, 0.0007019042968750, 0.0000000000000000, 0.0000915527343750, +-0.0000610351562500, -0.0002746582031250, -0.0000610351562500, 0.0000915527343750, +0.0000305175781250, -0.0014953613281250, -0.0000305175781250, -0.0016479492187500, +0.0000000000000000, -0.0013427734375000, 0.0000305175781250, -0.0022583007812500, +0.0000305175781250, -0.0021667480468750, -0.0000305175781250, 0.0005798339843750, +0.0000305175781250, -0.0004272460937500, 0.0000000000000000, 0.0015563964843750, +0.0000000000000000, 0.0051879882812500, 0.0000000000000000, 0.0034179687500000, +0.0000000000000000, 0.0059509277343750, 0.0000000000000000, 0.0077819824218750, +0.0000000000000000, 0.0041198730468750, 0.0000610351562500, 0.0031127929687500, +0.0000305175781250, 0.0046997070312500, 0.0000000000000000, -0.0105590820312500, +0.0000000000000000, -0.0063781738281250, 0.0000000000000000, -0.0167846679687500, +-0.0000305175781250, -0.0333862304687500, 0.0000000000000000, -0.0262756347656250, +0.0000000000000000, -0.0551147460937500, -0.0000305175781250, -0.0534973144531250, +-0.0000305175781250, -0.0661315917968750, 0.0000305175781250, -0.0904235839843750, +0.0000305175781250, -0.0820312500000000, 0.0000000000000000, -0.1137084960937500, +0.0000305175781250, -0.1163330078125000, 0.0000000000000000, -0.1253051757812500, +-0.0000305175781250, -0.1463012695312500, 0.0000305175781250, -0.1408081054687500, +0.0000305175781250, -0.1610412597656250, -0.0000305175781250, -0.1639709472656250, +0.0000000000000000, -0.1705322265625000, 0.0000000000000000, -0.1831970214843750, +0.0000000000000000, -0.1787719726562500, 0.0000305175781250, -0.1934814453125000, +0.0000000000000000, -0.1973876953125000, 0.0000305175781250, -0.1996154785156250, +0.0000305175781250, -0.2065124511718750, 0.0000000000000000, -0.2060852050781250, +0.0000000000000000, -0.2098999023437500, 0.0000000000000000, -0.2114868164062500, +-0.0000305175781250, -0.2106933593750000, -0.0000305175781250, -0.2119140625000000, +0.0000000000000000, -0.2128906250000000, 0.0000000000000000, -0.2082824707031250, +-0.0000305175781250, -0.2135314941406250, 0.0000000000000000, -0.2075500488281250, +-0.0000305175781250, -0.2004699707031250, -0.0000305175781250, -0.2072753906250000, +-0.0000305175781250, -0.1828918457031250, 0.0000000000000000, -0.1912536621093750, +-0.0000305175781250, -0.1777038574218750, 0.0000305175781250, -0.1558227539062500, +0.0000000000000000}, +{-0.0000610351562500, -0.0003662109375000, -0.0001831054687500, -0.0001525878906250, +0.0001220703125000, -0.0002746582031250, 0.0001831054687500, -0.0004577636718750, +0.0000305175781250, -0.0001831054687500, 0.0000610351562500, 0.0001831054687500, +0.0001220703125000, -0.0000610351562500, -0.0001220703125000, 0.0000915527343750, +-0.0002136230468750, 0.0002746582031250, -0.0000305175781250, 0.0000915527343750, +-0.0000610351562500, -0.0000610351562500, -0.0001220703125000, 0.0000305175781250, +0.0000915527343750, 0.0001525878906250, 0.0000915527343750, -0.0000305175781250, +0.0000305175781250, 0.0001525878906250, 0.0000610351562500, 0.0004577636718750, +0.0000915527343750, 0.0002746582031250, -0.0000610351562500, -0.0000915527343750, +-0.0000610351562500, 0.0003356933593750, -0.0000305175781250, -0.0003662109375000, +-0.0000610351562500, -0.0014038085937500, -0.0000915527343750, -0.0007324218750000, +0.0000305175781250, -0.0013122558593750, 0.0000610351562500, -0.0021667480468750, +0.0000305175781250, -0.0004577636718750, 0.0000305175781250, 0.0007019042968750, +0.0000610351562500, -0.0004882812500000, -0.0000305175781250, 0.0037841796875000, +-0.0000610351562500, 0.0045776367187500, 0.0000000000000000, 0.0024108886718750, +-0.0000305175781250, 0.0044250488281250, -0.0000305175781250, 0.0047302246093750, +0.0000000000000000, -0.0105590820312500, 0.0000000000000000, -0.0035095214843750, +0.0000000000000000, -0.0202026367187500, 0.0000305175781250, -0.0411376953125000, +0.0000000000000000, -0.0286254882812500, 0.0000000000000000, -0.0752868652343750, +0.0000000000000000, -0.0705261230468750, 0.0000000000000000, -0.0866088867187500, +-0.0000305175781250, -0.1245422363281250, -0.0000305175781250, -0.1097106933593750, +0.0000000000000000, -0.1471252441406250, 0.0000305175781250, -0.1509399414062500, +0.0000305175781250, -0.1511535644531250, 0.0000305175781250, -0.1688842773437500, +0.0000305175781250, -0.1636962890625000, 0.0000000000000000, -0.1610412597656250, +0.0000305175781250, -0.1652526855468750, 0.0000305175781250, -0.1506042480468750, +0.0000000000000000, -0.1370239257812500, 0.0000305175781250, -0.1420288085937500, +0.0000000000000000, -0.1075439453125000, 0.0000305175781250, -0.1041259765625000, +0.0000305175781250, -0.0880737304687500, 0.0000610351562500, -0.0588989257812500, +0.0000610351562500, -0.0616149902343750, 0.0000610351562500, -0.0301513671875000, +0.0000305175781250, -0.0196228027343750, 0.0000610351562500, -0.0055847167968750, +0.0000000000000000, 0.0146179199218750, 0.0000000000000000, 0.0137329101562500, +0.0000305175781250, 0.0403747558593750, 0.0000610351562500, 0.0588073730468750, +0.0000915527343750, 0.0590820312500000, 0.0000305175781250, 0.0661621093750000, +0.0000000000000000, 0.0796508789062500, 0.0000305175781250, 0.0625000000000000, +0.0000000000000000, 0.0734863281250000, 0.0000305175781250, 0.0671081542968750, +0.0000000000000000, 0.0506591796875000, 0.0000000000000000, 0.0628662109375000, +0.0000305175781250, 0.0254821777343750, 0.0000610351562500, 0.0442810058593750, +0.0000305175781250, 0.0216979980468750, 0.0000000000000000, -0.0166015625000000, +0.0000000000000000, 0.0140991210937500, 0.0000000000000000, -0.0665588378906250, +0.0000000000000000, -0.0498657226562500, 0.0000305175781250, -0.0735778808593750, +0.0000305175781250, -0.1333007812500000, 0.0000305175781250, -0.0943603515625000, +0.0000305175781250, -0.1772460937500000, 0.0000305175781250, -0.1656494140625000, +0.0000305175781250, -0.1785583496093750, 0.0000000000000000, -0.2352600097656250, +0.0000305175781250, -0.2043457031250000, 0.0000000000000000, -0.2447814941406250, +-0.0000305175781250, -0.2521362304687500, 0.0000000000000000, -0.2363586425781250, +0.0000000000000000, -0.2489929199218750, 0.0000305175781250, -0.2535705566406250, +0.0000000000000000, -0.2068786621093750, 0.0000000000000000, -0.2268066406250000, +0.0000305175781250, -0.1941833496093750, -0.0000305175781250, -0.1424560546875000, +-0.0000305175781250, -0.1766662597656250, 0.0000305175781250, -0.0900573730468750, +0.0000000000000000, -0.1002197265625000, 0.0000000000000000, -0.0833740234375000, +0.0000305175781250, -0.0214233398437500, 0.0000305175781250, -0.0494079589843750, +-0.0000305175781250, -0.0059204101562500, -0.0000305175781250, -0.0004882812500000, +-0.0000305175781250, -0.0041198730468750, 0.0000000000000000, 0.0137023925781250, +-0.0000305175781250, 0.0091552734375000, 0.0000305175781250, 0.0067138671875000, +0.0000305175781250, 0.0104370117187500, 0.0000000000000000, 0.0064086914062500, +0.0000305175781250, 0.0003356933593750, 0.0000610351562500, 0.0033264160156250, +-0.0000610351562500, -0.0024108886718750, -0.0000915527343750, -0.0038146972656250, +-0.0000305175781250, -0.0023193359375000, -0.0000610351562500, -0.0035705566406250, +-0.0000915527343750, -0.0038452148437500, 0.0000915527343750, -0.0009765625000000, +0.0001220703125000, -0.0013732910156250, 0.0000305175781250, -0.0007934570312500, +0.0000305175781250, 0.0014038085937500, 0.0000915527343750, 0.0006103515625000, +-0.0000610351562500, 0.0009155273437500, -0.0000915527343750, 0.0015258789062500, +-0.0000305175781250, 0.0007629394531250, -0.0000915527343750, 0.0000915527343750, +-0.0001220703125000, 0.0006103515625000, 0.0000915527343750, -0.0003051757812500, +0.0001220703125000, -0.0005798339843750, 0.0000305175781250, -0.0001525878906250, +0.0000915527343750, -0.0001525878906250, 0.0001525878906250, -0.0003662109375000, +-0.0001220703125000, 0.0002746582031250, -0.0000610351562500, 0.0005187988281250, +-0.0000305175781250, 0.0000915527343750, -0.0002441406250000, 0.0000000000000000, +-0.0002136230468750, 0.0003051757812500, 0.0000305175781250, -0.0005798339843750, +-0.0000915527343750, -0.0007629394531250, 0.0000000000000000, -0.0002746582031250, +0.0003051757812500, -0.0003967285156250, 0.0001831054687500, -0.0006713867187500, +0.0000000000000000, 0.0006408691406250, 0.0001525878906250, 0.0007934570312500, +-0.0000305175781250, 0.0003051757812500, -0.0004272460937500, 0.0007629394531250, +-0.0002136230468750, 0.0010375976562500, -0.0001831054687500, -0.0006713867187500, +-0.0004882812500000, -0.0006103515625000, -0.0000915527343750, -0.0003051757812500, +0.0003051757812500, -0.0011901855468750, 0.0000000000000000, -0.0012207031250000, +0.0002746582031250, 0.0002441406250000, 0.0005493164062500, -0.0000305175781250, +0.0002136230468750, -0.0000305175781250, -0.0002746582031250, 0.0013732910156250, +-0.0004577636718750, -0.0011901855468750, 0.0005493164062500, 0.0004577636718750, +0.0004577636718750, -0.0001831054687500, 0.0001525878906250, -0.0000305175781250, +0.0003662109375000, 0.0009765625000000, 0.0006103515625000, 0.0008850097656250, +-0.0005187988281250, -0.0002746582031250, -0.0004882812500000, 0.0000000000000000, +-0.0003356933593750, -0.0000305175781250, -0.0010681152343750, -0.0010070800781250, +-0.0009460449218750, -0.0008544921875000, 0.0001525878906250, 0.0000610351562500, +-0.0002746582031250, -0.0002746582031250, 0.0000305175781250, -0.0001525878906250, +0.0011901855468750, 0.0007934570312500, 0.0007629394531250, 0.0005493164062500, +0.0002441406250000, 0.0000000000000000, 0.0008544921875000, 0.0003356933593750, +0.0002441406250000, 0.0001220703125000, -0.0010070800781250, -0.0006408691406250, +-0.0003051757812500, -0.0004272460937500, -0.0004882812500000, -0.0000610351562500, +-0.0011291503906250, -0.0003356933593750, -0.0004577636718750, -0.0001831054687500, +0.0004272460937500, 0.0004272460937500, -0.0001525878906250, 0.0002746582031250, +0.0001831054687500, 0.0000305175781250, 0.0006408691406250, 0.0003051757812500, +0.0002136230468750, 0.0000915527343750, -0.0003356933593750, -0.0003967285156250, +0.0000915527343750, -0.0002441406250000, 0.0000610351562500, -0.0000915527343750, +-0.0004882812500000, -0.0002441406250000, 0.0002746582031250, -0.0000610351562500, +0.0012817382812500, 0.0003051757812500, 0.0004882812500000, 0.0001525878906250, +0.0007934570312500, 0.0000305175781250, 0.0019531250000000, 0.0001831054687500, +-0.0000305175781250, 0.0000610351562500, -0.0017089843750000, -0.0002136230468750, +0.0001220703125000, -0.0000915527343750, -0.0033874511718750, -0.0000610351562500, +-0.0043945312500000, -0.0001831054687500, -0.0019531250000000, -0.0000610351562500, +-0.0025024414062500, 0.0001831054687500, -0.0039062500000000, 0.0000915527343750, +0.0045776367187500, -0.0000305175781250, 0.0023193359375000, 0.0000915527343750, +0.0037536621093750, 0.0000305175781250, 0.0117492675781250, -0.0001525878906250, +0.0082702636718750, -0.0001220703125000, 0.0037841796875000, 0.0000000000000000, +0.0124816894531250, -0.0000610351562500, -0.0030822753906250, 0.0000000000000000, +-0.0153198242187500, 0.0001220703125000, -0.0018615722656250, 0.0000915527343750, +-0.0572814941406250, 0.0000305175781250, -0.0406799316406250, 0.0000305175781250, +-0.0684204101562500, 0.0000305175781250, -0.1190490722656250, 0.0000000000000000, +-0.0856933593750000, 0.0000305175781250, -0.1685485839843750, 0.0000610351562500, +-0.1604614257812500, 0.0000305175781250, -0.1736755371093750, 0.0000305175781250, +-0.2297058105468750, 0.0000305175781250, -0.2012939453125000, 0.0001220703125000, +-0.2296447753906250, -0.0000305175781250, -0.2447814941406250, 0.0000000000000000, +-0.2177124023437500, 0.0000000000000000, -0.2159423828125000, -0.0000610351562500, +-0.2339172363281250, 0.0000000000000000, -0.1503295898437500, -0.0000305175781250, +-0.1871032714843750, -0.0000305175781250, -0.1301879882812500, -0.0000915527343750, +-0.0468139648437500, -0.0000915527343750, -0.1203308105468750, -0.0000305175781250, +0.0575866699218750, -0.0000915527343750, 0.0165100097656250, -0.0001525878906250, +0.0634155273437500, -0.0001220703125000, 0.1908264160156250, -0.0000915527343750, +0.0997924804687500, -0.0000915527343750, 0.2805786132812500, -0.0000915527343750, +0.2435607910156250, -0.0000915527343750, 0.2745361328125000, -0.0001220703125000, +0.4007873535156250, -0.0001831054687500, 0.3213806152343750, -0.0001525878906250, +0.4457092285156250, -0.0001525878906250, 0.4286804199218750, -0.0001220703125000, +0.4397583007812500, -0.0001525878906250, 0.5110778808593750, -0.0001220703125000, +0.4535217285156250, -0.0001525878906250, 0.5212707519531250, -0.0000915527343750, +0.5078430175781250, -0.0001220703125000, 0.5019531250000000, -0.0001220703125000, +0.5344543457031250, -0.0001220703125000, 0.5009460449218750, -0.0001220703125000, +0.5220336914062500, -0.0001220703125000, 0.5114746093750000, -0.0001525878906250, +0.4958496093750000, -0.0000915527343750, 0.5010375976562500, -0.0001220703125000, +0.4836120605468750, -0.0001525878906250, 0.4528503417968750, -0.0000915527343750, +0.4474487304687500, -0.0001525878906250, 0.4190063476562500, -0.0001525878906250, +0.3813476562500000, -0.0001525878906250, 0.3710327148437500, -0.0001220703125000, +0.3111267089843750, -0.0001220703125000, 0.3122863769531250, -0.0001220703125000, +0.2676391601562500, -0.0001220703125000, 0.2079772949218750, -0.0001220703125000, +0.2244262695312500, -0.0001525878906250, 0.1175231933593750, -0.0001220703125000, +0.1272888183593750, -0.0000915527343750, 0.0883789062500000, -0.0000915527343750, +0.0020141601562500, -0.0000610351562500, 0.0303344726562500, -0.0000915527343750, +-0.0708618164062500, -0.0000915527343750, -0.0721435546875000, -0.0000305175781250, +-0.0913696289062500, -0.0000305175781250, -0.1585083007812500, -0.0000305175781250, +-0.1396789550781250, -0.0000305175781250, -0.1784973144531250, 0.0000000000000000, +-0.1894836425781250}, +{0.0083007812500000, -0.0000305175781250, 0.0116271972656250, 0.0000915527343750, +0.0025634765625000, 0.0000305175781250, 0.0041503906250000, -0.0001831054687500, +0.0093078613281250, -0.0001525878906250, -0.0322570800781250, 0.0000305175781250, +-0.0124206542968750, -0.0000305175781250, -0.0438537597656250, 0.0000000000000000, +-0.0908203125000000, 0.0001831054687500, -0.0549011230468750, 0.0001220703125000, +-0.1434326171875000, 0.0000000000000000, -0.1344909667968750, 0.0000305175781250, +-0.1454772949218750, 0.0000305175781250, -0.2061157226562500, -0.0000610351562500, +-0.1795043945312500, -0.0000915527343750, -0.1961364746093750, 0.0000305175781250, +-0.2187194824218750, 0.0000305175781250, -0.1791687011718750, 0.0000000000000000, +-0.1627502441406250, 0.0000610351562500, -0.1898498535156250, 0.0000915527343750, +-0.0513305664062500, -0.0000915527343750, -0.0980834960937500, -0.0001220703125000, +-0.0146179199218750, -0.0000915527343750, 0.1170959472656250, -0.0001525878906250, +0.0196228027343750, -0.0001525878906250, 0.2698974609375000, -0.0000610351562500, +0.2206420898437500, -0.0000915527343750, 0.2865600585937500, -0.0000915527343750, +0.4734191894531250, -0.0000610351562500, 0.3590087890625000, -0.0000915527343750, +0.5651550292968750, -0.0001220703125000, 0.5540771484375000, -0.0001525878906250, +0.5686340332031250, -0.0001525878906250, 0.6908264160156250, -0.0000305175781250, +0.6331481933593750, -0.0000915527343750, 0.6972656250000000, 0.0000000000000000, +0.7143249511718750, -0.0000305175781250, 0.6896362304687500, 0.0000305175781250, +0.7058410644531250, 0.0000915527343750, 0.7147827148437500, 0.0000610351562500, +0.6542968750000000, 0.0000610351562500, 0.6873168945312500, 0.0000610351562500, +0.6541442871093750, 0.0000610351562500, 0.5924072265625000, 0.0001220703125000, +0.6428527832031250, 0.0001220703125000, 0.5401306152343750, 0.0000915527343750, +0.5627136230468750, 0.0001220703125000, 0.5421752929687500, 0.0001220703125000, +0.4743957519531250, 0.0001220703125000, 0.5333557128906250, 0.0001220703125000, +0.4571838378906250, 0.0001831054687500, 0.4742126464843750, 0.0001220703125000, +0.4725341796875000, 0.0001220703125000, 0.4301147460937500, 0.0001525878906250, +0.4719848632812500, 0.0001525878906250, 0.4333496093750000, 0.0001220703125000, +0.4460754394531250, 0.0001525878906250, 0.4577636718750000, 0.0001831054687500, +0.4414367675781250, 0.0001831054687500, 0.4655761718750000, 0.0001220703125000, +0.4785156250000000, 0.0001525878906250, 0.4913330078125000, 0.0001220703125000, +0.5095520019531250, 0.0000915527343750, 0.5263061523437500, 0.0000915527343750, +0.5427246093750000, 0.0001220703125000, 0.5643310546875000, 0.0000915527343750, +0.5682678222656250, 0.0000915527343750, 0.5830383300781250, 0.0000305175781250, +0.6027526855468750, 0.0000610351562500, 0.5990905761718750, 0.0000610351562500, +0.6097717285156250, -0.0000305175781250, 0.6153259277343750, 0.0000610351562500, +0.6008300781250000, 0.0000305175781250, 0.5996093750000000, -0.0000305175781250, +0.6055603027343750, 0.0000000000000000, 0.5392150878906250, -0.0000610351562500, +0.5599975585937500, -0.0000610351562500, 0.5082397460937500, -0.0000305175781250, +0.4350280761718750, -0.0000610351562500, 0.4738769531250000, -0.0000610351562500, +0.3220214843750000, -0.0000915527343750, 0.3400878906250000, -0.0000610351562500, +0.2742614746093750, -0.0000610351562500, 0.1441345214843750, -0.0000915527343750, +0.1986694335937500, -0.0001220703125000, 0.0292358398437500, -0.0001220703125000, +0.0314941406250000, -0.0001220703125000, 0.0014038085937500, -0.0000610351562500, +-0.1085510253906250, -0.0000305175781250, -0.0688171386718750, -0.0001220703125000, +-0.1364746093750000, 0.0000305175781250, -0.1553344726562500, 0.0000305175781250, +-0.1380920410156250, -0.0000305175781250, -0.1545104980468750, 0.0000000000000000, +-0.1577758789062500, 0.0000305175781250, -0.1083679199218750, -0.0000305175781250, +-0.1213684082031250, -0.0000610351562500, -0.0967407226562500, -0.0000305175781250, +-0.0484619140625000, 0.0000610351562500, -0.0718383789062500, -0.0000305175781250, +-0.0201416015625000, 0.0000610351562500, -0.0151062011718750, 0.0000915527343750, +-0.0152893066406250, 0.0000305175781250, 0.0088806152343750, 0.0000000000000000, +0.0026245117187500, -0.0000305175781250, 0.0029296875000000, -0.0000610351562500, +0.0068969726562500, -0.0000915527343750, 0.0031127929687500, 0.0000000000000000, +-0.0019226074218750, -0.0000305175781250, 0.0005187988281250, -0.0000610351562500, +-0.0016784667968750, 0.0000915527343750, -0.0033569335937500, 0.0000915527343750, +-0.0014648437500000, 0.0000000000000000, -0.0000305175781250, -0.0000305175781250, +-0.0011901855468750, 0.0000915527343750, 0.0007934570312500, -0.0001220703125000, +0.0014953613281250, -0.0001220703125000, 0.0005187988281250, -0.0000305175781250, +0.0003051757812500, 0.0000000000000000, 0.0008239746093750, -0.0001220703125000, +-0.0003356933593750, 0.0000610351562500, -0.0007324218750000, 0.0001525878906250, +-0.0001831054687500, 0.0000000000000000, -0.0001831054687500, 0.0000000000000000, +-0.0004577636718750, 0.0001220703125000, 0.0002441406250000, -0.0001220703125000, +0.0004577636718750, -0.0001525878906250, 0.0000915527343750, -0.0000305175781250, +0.0000305175781250, -0.0000610351562500, 0.0002441406250000, -0.0001831054687500, +-0.0003051757812500, 0.0000610351562500, -0.0005187988281250, 0.0001220703125000, +-0.0001831054687500, 0.0000000000000000, -0.0000610351562500, 0.0000000000000000, +-0.0003051757812500, 0.0000915527343750, 0.0002136230468750, -0.0001220703125000, +0.0003356933593750, -0.0001831054687500, 0.0000610351562500, -0.0000305175781250, +-0.0000915527343750, 0.0000000000000000, -0.0000915527343750, -0.0000305175781250, +-0.0001525878906250, 0.0000000000000000, -0.0003356933593750, 0.0000915527343750, +-0.0001220703125000, -0.0000305175781250, 0.0000915527343750, -0.0001220703125000, +-0.0001220703125000, 0.0000305175781250, 0.0000915527343750, -0.0001220703125000, +0.0002746582031250, -0.0002441406250000, 0.0000305175781250, -0.0000915527343750, +-0.0001831054687500, 0.0000610351562500, 0.0000000000000000, -0.0000610351562500, +-0.0001220703125000, 0.0000000000000000, -0.0003662109375000, 0.0001220703125000, +-0.0000915527343750, -0.0000610351562500, 0.0001525878906250, -0.0002441406250000, +-0.0000610351562500, -0.0001525878906250, 0.0000915527343750, -0.0000915527343750, +0.0003051757812500, -0.0002136230468750, 0.0000305175781250, -0.0000915527343750, +-0.0002136230468750, 0.0002136230468750, -0.0000305175781250, 0.0000915527343750, +-0.0001220703125000, 0.0000305175781250, -0.0003051757812500, 0.0002136230468750, +-0.0000915527343750, 0.0000000000000000, 0.0001220703125000, -0.0003051757812500, +-0.0000610351562500, -0.0001220703125000, 0.0000915527343750, 0.0000915527343750, +0.0002441406250000, -0.0001220703125000, 0.0000305175781250, -0.0000305175781250, +-0.0001525878906250, 0.0004272460937500, 0.0000000000000000, 0.0002746582031250, +-0.0000610351562500, -0.0006103515625000, -0.0002441406250000, -0.0002746582031250, +-0.0000915527343750, -0.0002746582031250, 0.0000610351562500, -0.0013732910156250, +-0.0000305175781250, -0.0011291503906250, 0.0000915527343750, 0.0010375976562500, +0.0001831054687500, 0.0002136230468750, 0.0000610351562500, 0.0005493164062500, +-0.0000305175781250, 0.0038452148437500, 0.0000610351562500, 0.0026855468750000, +-0.0000610351562500, -0.0050964355468750, -0.0001525878906250, 0.0025024414062500, +-0.0000610351562500, -0.0142211914062500, 0.0000000000000000, -0.0303955078125000, +-0.0000305175781250, -0.0166015625000000, 0.0000305175781250, -0.0654907226562500, +0.0001220703125000, -0.0609436035156250, 0.0000610351562500, -0.0723876953125000, +0.0000305175781250, -0.1112365722656250, 0.0000610351562500, -0.0959167480468750, +-0.0000305175781250, -0.1021118164062500, -0.0000915527343750, -0.1207885742187500, +-0.0000610351562500, -0.0810241699218750, -0.0000305175781250, -0.0541992187500000, +-0.0000610351562500, -0.0758056640625000, 0.0000305175781250, 0.0495300292968750, +0.0000305175781250, 0.0273437500000000, 0.0000000000000000, 0.0885925292968750, +0.0000305175781250, 0.2033386230468750, 0.0000610351562500, 0.1488342285156250, +-0.0000610351562500, 0.2929077148437500, -0.0000610351562500, 0.2959899902343750, +0.0000000000000000, 0.3153991699218750, 0.0000000000000000, 0.4041442871093750, +-0.0000305175781250, 0.3754577636718750, 0.0000610351562500, 0.4122314453125000, +0.0000305175781250, 0.4290466308593750, 0.0000305175781250, 0.4094238281250000, +0.0000305175781250, 0.4059753417968750, 0.0000000000000000, 0.4099121093750000, +-0.0000305175781250, 0.3624267578125000, -0.0000610351562500, 0.3666381835937500, +0.0000000000000000, 0.3320922851562500, -0.0000305175781250, 0.2805175781250000, +-0.0000305175781250, 0.2956848144531250, 0.0000000000000000, 0.2190856933593750, +0.0000000000000000, 0.2077331542968750, 0.0000000000000000, 0.1836242675781250, +0.0000000000000000, 0.1311645507812500, 0.0000305175781250, 0.1366882324218750, +0.0000000000000000, 0.0901489257812500, -0.0000305175781250, 0.0741882324218750, +0.0000000000000000, 0.0563659667968750, 0.0000000000000000, 0.0293884277343750, +-0.0000305175781250, 0.0315856933593750, 0.0000000000000000, -0.0009155273437500, +0.0000000000000000, -0.0235290527343750, 0.0000000000000000, -0.0231628417968750, +0.0000305175781250, -0.0302124023437500, 0.0000305175781250, -0.0454406738281250, +-0.0000610351562500, -0.0256347656250000, -0.0000305175781250, -0.0380554199218750, +0.0000000000000000, -0.0289611816406250, 0.0000000000000000, -0.0097961425781250, +-0.0000610351562500, -0.0252380371093750, -0.0000305175781250, 0.0234680175781250, +0.0000000000000000, -0.0022583007812500, 0.0000000000000000, 0.0271911621093750, +0.0000000000000000, 0.0764770507812500, -0.0000305175781250, 0.0380554199218750, +0.0000000000000000, 0.1557006835937500, -0.0000610351562500, 0.1248779296875000, +-0.0000305175781250, 0.1725463867187500, 0.0000000000000000, 0.2669677734375000, +-0.0000305175781250, 0.2007751464843750, 0.0000000000000000, 0.3692321777343750, +0.0000000000000000, 0.3299560546875000, -0.0000305175781250, 0.3825683593750000, +0.0000305175781250, 0.5145263671875000, 0.0000000000000000, 0.4292602539062500, +0.0000000000000000, 0.6030883789062500, -0.0000305175781250, 0.5871887207031250, +0.0000000000000000, 0.5936889648437500, 0.0000000000000000, 0.7033996582031250, +0.0000000000000000, 0.6585083007812500, 0.0000000000000000, 0.6726074218750000, +0.0000305175781250, 0.7183532714843750, 0.0000305175781250, 0.6428833007812500, +0.0000000000000000, 0.5941772460937500, -0.0000305175781250, 0.6524047851562500, +0.0000610351562500, 0.4279785156250000, 0.0000305175781250, 0.4888610839843750, +0.0000610351562500, 0.3830566406250000, 0.0000915527343750, 0.1737365722656250, +0.0000915527343750, 0.2944335937500000, 0.0000305175781250, 0.0174255371093750, +0.0000610351562500, 0.0299987792968750, 0.0000305175781250, -0.0063476562500000, +-0.0000610351562500, -0.1809692382812500, 0.0000000000000000, -0.1044616699218750, +0.0000610351562500, -0.1994018554687500, 0.0000000000000000, -0.2271423339843750, +0.0000000000000000, -0.1939697265625000, 0.0000305175781250, -0.2118225097656250, +0.0000305175781250, -0.2202758789062500, -0.0000610351562500, -0.1451721191406250, +-0.0000305175781250, -0.1622009277343750, -0.0000305175781250, -0.1290283203125000, +-0.0000915527343750}, +{-0.0000305175781250, 0.3160400390625000, 0.0000000000000000, 0.3126220703125000, +-0.0000610351562500, 0.3286132812500000, 0.0000000000000000, 0.2206115722656250, +0.0000305175781250, 0.2425537109375000, 0.0000000000000000, 0.1859436035156250, +-0.0000305175781250, 0.0814514160156250, 0.0000000000000000, 0.1233520507812500, +-0.0000305175781250, -0.0210571289062500, -0.0000610351562500, -0.0212097167968750, +-0.0000305175781250, -0.0508728027343750, 0.0000000000000000, -0.1446228027343750, +0.0000000000000000, -0.1138305664062500, 0.0000305175781250, -0.1896362304687500, +0.0000305175781250, -0.1954650878906250, 0.0000000000000000, -0.2021789550781250, +0.0000000000000000, -0.2429199218750000, 0.0000305175781250, -0.2324523925781250, +0.0000000000000000, -0.2580261230468750, 0.0000000000000000, -0.2601013183593750, +0.0000610351562500, -0.2605590820312500, 0.0000000000000000, -0.2698669433593750, +0.0000000000000000, -0.2619018554687500, 0.0000305175781250, -0.2692871093750000, +0.0000305175781250, -0.2641296386718750, 0.0000305175781250, -0.2657775878906250, +0.0000305175781250, -0.2727050781250000, 0.0000000000000000, -0.2640380859375000, +0.0000305175781250, -0.2704162597656250, 0.0000305175781250, -0.2625427246093750, +0.0000305175781250, -0.2679748535156250, 0.0000305175781250, -0.2770385742187500, +0.0000305175781250, -0.2648315429687500, 0.0000000000000000, -0.2878417968750000, +0.0000305175781250, -0.2834472656250000, 0.0000305175781250, -0.2873229980468750, +0.0000305175781250, -0.3028564453125000, 0.0000305175781250, -0.2961425781250000, +0.0000000000000000, -0.3211669921875000, 0.0000000000000000, -0.3146362304687500, +0.0000305175781250, -0.3257141113281250, 0.0000000000000000, -0.3464355468750000, +0.0000000000000000, -0.3313293457031250, 0.0000305175781250, -0.3673095703125000, +0.0000305175781250, -0.3642578125000000, 0.0000000000000000, -0.3645019531250000, +0.0000305175781250, -0.3868103027343750, 0.0000305175781250, -0.3794250488281250, +0.0000000000000000, -0.3788452148437500, -0.0000610351562500, -0.3941650390625000, +-0.0000305175781250, -0.3692016601562500, 0.0000000000000000, -0.3576660156250000, +0.0000305175781250, -0.3786315917968750, 0.0000305175781250, -0.2630920410156250, +0.0000000000000000, -0.3168029785156250, -0.0000305175781250, -0.2381591796875000, +-0.0000610351562500, -0.1211242675781250, -0.0000610351562500, -0.2143859863281250, +-0.0000305175781250, 0.0605773925781250, -0.0000610351562500, 0.0011291503906250, +-0.0000305175781250, 0.1068420410156250, 0.0000000000000000, 0.3385925292968750, +-0.0000305175781250, 0.2033996582031250, 0.0000000000000000, 0.4976806640625000, +0.0000000000000000, 0.4801940917968750, -0.0000305175781250, 0.4971923828125000, +-0.0000610351562500, 0.6837768554687500, -0.0000305175781250, 0.6147460937500000, +0.0000000000000000, 0.6313171386718750, 0.0000000000000000, 0.6900024414062500, +-0.0000305175781250, 0.5909729003906250, 0.0000610351562500, 0.5202026367187500, +0.0000305175781250, 0.5898437500000000, 0.0000000000000000, 0.3266601562500000, +0.0000610351562500, 0.3740234375000000, 0.0000000000000000, 0.2809143066406250, +-0.0000915527343750, 0.0599365234375000, -0.0000305175781250, 0.1621093750000000, +0.0000305175781250, -0.0723266601562500, -0.0000305175781250, -0.0885620117187500, +0.0000000000000000, -0.0924987792968750, 0.0001220703125000, -0.2107849121093750, +0.0000915527343750, -0.1747741699218750, 0.0000000000000000, -0.1756591796875000, +0.0000305175781250, -0.2087402343750000, 0.0000000000000000, -0.1649169921875000, +-0.0001831054687500, -0.1201477050781250, -0.0001525878906250, -0.1507873535156250, +-0.0000305175781250, -0.0588989257812500, -0.0000915527343750, -0.0612792968750000, +-0.0000305175781250, -0.0518493652343750, 0.0001220703125000, 0.0028991699218750, +0.0000915527343750, -0.0177001953125000, 0.0000000000000000, 0.0032348632812500, +0.0000915527343750, 0.0121765136718750, -0.0000305175781250, 0.0037231445312500, +-0.0002136230468750, 0.0038452148437500, -0.0001220703125000, 0.0070800781250000, +-0.0001220703125000, -0.0018005371093750, -0.0002136230468750, -0.0032348632812500, +-0.0000610351562500, -0.0008544921875000, 0.0001831054687500, -0.0028686523437500, +0.0000000000000000, -0.0036926269531250, 0.0001220703125000, 0.0004882812500000, +0.0002441406250000, 0.0004577636718750, 0.0000000000000000, -0.0002441406250000, +-0.0001831054687500, 0.0015563964843750, 0.0000000000000000, 0.0016174316406250, +-0.0003051757812500, -0.0003356933593750, -0.0004272460937500, -0.0003051757812500, +-0.0001831054687500, 0.0001525878906250, -0.0000305175781250, -0.0006713867187500, +-0.0002441406250000, -0.0008544921875000, 0.0002441406250000, 0.0004882812500000, +0.0003662109375000, 0.0005493164062500, 0.0001831054687500, 0.0000000000000000, +0.0002441406250000, 0.0003662109375000, 0.0003662109375000, 0.0007019042968750, +-0.0003356933593750, -0.0007019042968750, -0.0003356933593750, -0.0007629394531250, +-0.0002136230468750, -0.0003051757812500, -0.0006103515625000, -0.0005798339843750, +0.0004272460937500, 0.0007324218750000, -0.0000610351562500, -0.0007324218750000, +0.0003662109375000, -0.0006103515625000, 0.0000000000000000, -0.0001525878906250, +-0.0006408691406250, -0.0003051757812500, -0.0003356933593750, -0.0006408691406250, +-0.0002441406250000, 0.0005187988281250, -0.0005493164062500, 0.0007324218750000, +-0.0001525878906250, 0.0001525878906250, 0.0003356933593750, 0.0003051757812500, +-0.0000305175781250, 0.0006713867187500, 0.0003662109375000, -0.0005187988281250, +0.0004882812500000, -0.0007324218750000, 0.0003662109375000, -0.0002136230468750, +0.0003662109375000, -0.0004577636718750, 0.0003662109375000, -0.0007019042968750, +0.0003662109375000, 0.0003356933593750, 0.0004882812500000, 0.0003967285156250, +-0.0000610351562500, 0.0000610351562500, -0.0002746582031250, 0.0003662109375000, +0.0001831054687500, 0.0005493164062500, -0.0018615722656250, -0.0003051757812500, +-0.0019836425781250, -0.0003356933593750, -0.0008239746093750, -0.0001220703125000, +-0.0018615722656250, -0.0004272460937500, -0.0025634765625000, -0.0005187988281250, +0.0037841796875000, 0.0002136230468750, 0.0023803710937500, 0.0002441406250000, +0.0017089843750000, 0.0000610351562500, 0.0090637207031250, 0.0003051757812500, +0.0071716308593750, 0.0003356933593750, -0.0144653320312500, -0.0002441406250000, +0.0032043457031250, -0.0002136230468750, -0.0295715332031250, -0.0000610351562500, +-0.0657653808593750, -0.0002441406250000, -0.0347595214843750, -0.0003356933593750, +-0.1291503906250000, 0.0001220703125000, -0.1205139160156250, 0.0001525878906250, +-0.1248168945312500, 0.0000305175781250, -0.1901245117187500, 0.0001831054687500, +-0.1668395996093750, 0.0002441406250000, -0.1335144042968750, -0.0001831054687500, +-0.1834716796875000, -0.0001831054687500, -0.1004333496093750, -0.0000915527343750, +-0.0203247070312500, -0.0002441406250000, -0.0961608886718750, -0.0002441406250000, +0.1483764648437500, -0.0000305175781250, 0.0954589843750000, 0.0000000000000000, +0.1718750000000000, -0.0000610351562500, 0.3688659667968750, 0.0000000000000000, +0.2542724609375000, 0.0000305175781250, 0.4536437988281250, -0.0001220703125000, +0.4649353027343750, -0.0001525878906250, 0.4519653320312500, -0.0000610351562500, +0.5510559082031250, -0.0000305175781250, 0.5249328613281250, -0.0001220703125000, +0.4800720214843750, 0.0001220703125000, 0.5305175781250000, 0.0001525878906250, +0.4505310058593750, 0.0000915527343750, 0.3665161132812500, 0.0001220703125000, +0.4372253417968750, 0.0001831054687500, 0.1932678222656250, 0.0000915527343750, +0.2441711425781250, 0.0000610351562500, 0.1556396484375000, 0.0000915527343750, +-0.0392150878906250, 0.0001525878906250, 0.0824584960937500, 0.0001525878906250, +-0.1699523925781250, 0.0001220703125000, -0.1471557617187500, 0.0001831054687500, +-0.1752624511718750, 0.0001220703125000, -0.3342285156250000, 0.0000305175781250, +-0.2558288574218750, 0.0000915527343750, -0.3575134277343750, 0.0000305175781250, +-0.3742675781250000, 0.0000305175781250, -0.3543090820312500, -0.0000305175781250, +-0.3918457031250000, 0.0000000000000000, -0.3932189941406250, 0.0000610351562500, +-0.3603820800781250, -0.0000610351562500, -0.3801574707031250, 0.0000000000000000, +-0.3604431152343750, -0.0000305175781250, -0.3271789550781250, -0.0000915527343750, +-0.3571777343750000, -0.0000610351562500, -0.2940368652343750, -0.0000305175781250, +-0.3093261718750000, -0.0000610351562500, -0.2996215820312500, -0.0000305175781250, +-0.2549133300781250, 0.0000000000000000, -0.2824401855468750, -0.0000305175781250, +-0.2401428222656250, -0.0000305175781250, -0.2429199218750000, -0.0000305175781250, +-0.2402648925781250, -0.0000305175781250, -0.2182006835937500, 0.0000000000000000, +-0.2340393066406250, -0.0000305175781250, -0.2107849121093750, 0.0000000000000000, +-0.2144165039062500, -0.0000305175781250, -0.2143554687500000, 0.0000000000000000, +-0.2019348144531250, 0.0000000000000000, -0.2109985351562500, -0.0000305175781250, +-0.1992492675781250, 0.0000000000000000, -0.2037963867187500, -0.0000305175781250, +-0.2044677734375000, 0.0000000000000000, -0.1965026855468750, -0.0000305175781250, +-0.2038574218750000, -0.0000305175781250, -0.2048645019531250, 0.0000000000000000, +-0.2093811035156250, -0.0000610351562500, -0.2155456542968750, -0.0000610351562500, +-0.2205200195312500, 0.0000000000000000, -0.2306213378906250, -0.0000305175781250, +-0.2446594238281250, -0.0000305175781250, -0.2445678710937500, -0.0000610351562500, +-0.2603759765625000, -0.0000305175781250, -0.2777099609375000, -0.0000610351562500, +-0.2731018066406250, -0.0000610351562500, -0.3054199218750000, 0.0000000000000000, +-0.3032226562500000, -0.0000305175781250, -0.3119812011718750, -0.0000305175781250, +-0.3390197753906250, -0.0000305175781250, -0.3319091796875000, -0.0000305175781250, +-0.3377685546875000, -0.0000305175781250, -0.3494262695312500, -0.0000305175781250, +-0.3274230957031250, 0.0000000000000000, -0.3177795410156250, 0.0000305175781250, +-0.3349304199218750, -0.0000305175781250, -0.2527770996093750, 0.0000915527343750, +-0.2767333984375000, 0.0000915527343750, -0.2135925292968750, 0.0000915527343750, +-0.1224365234375000, 0.0000915527343750, -0.1685791015625000, 0.0000915527343750, +0.0170593261718750, 0.0000610351562500, -0.0044555664062500, 0.0000610351562500, +0.0632934570312500, 0.0000915527343750, 0.2150573730468750, 0.0000915527343750, +0.1500854492187500, 0.0000610351562500, 0.3133850097656250, 0.0000915527343750, +0.3303527832031250, 0.0001525878906250, 0.3320312500000000, 0.0000610351562500, +0.4168090820312500, 0.0000610351562500, 0.3965454101562500, 0.0000610351562500, +0.3557739257812500, -0.0000915527343750, 0.3990478515625000, -0.0000915527343750, +0.3243713378906250, -0.0000610351562500, 0.2373657226562500, -0.0001220703125000, +0.2948303222656250, -0.0000915527343750, 0.1031188964843750, 0.0000000000000000, +0.1145935058593750, -0.0000610351562500, 0.0716247558593750, -0.0000915527343750, +-0.0651245117187500, 0.0000000000000000, -0.0120849609375000, -0.0000305175781250, +-0.0935363769531250, -0.0000610351562500, -0.1192626953125000, -0.0000610351562500, +-0.0914611816406250, 0.0000000000000000, -0.1026306152343750, -0.0000610351562500, +-0.1116943359375000, -0.0000915527343750, -0.0538330078125000, 0.0000610351562500, +-0.0621948242187500, 0.0000610351562500, -0.0488891601562500, 0.0000000000000000, +-0.0049133300781250, 0.0000610351562500, -0.0220642089843750, 0.0000915527343750, +-0.0011291503906250}, +{-0.2001037597656250, 0.0000305175781250, -0.2456665039062500, 0.0000305175781250, +-0.2269592285156250, 0.0000000000000000, -0.2497253417968750, 0.0000305175781250, +-0.2909240722656250, 0.0000610351562500, -0.2571411132812500, 0.0000610351562500, +-0.3307495117187500, 0.0000305175781250, -0.3139343261718750, 0.0000915527343750, +-0.3263854980468750, 0.0000610351562500, -0.3778686523437500, 0.0000610351562500, +-0.3444824218750000, 0.0000305175781250, -0.3950805664062500, 0.0000610351562500, +-0.3894653320312500, 0.0000915527343750, -0.3923339843750000, 0.0000610351562500, +-0.4198608398437500, 0.0000610351562500, -0.3983459472656250, 0.0000610351562500, +-0.4223632812500000, 0.0000305175781250, -0.4167175292968750, 0.0000000000000000, +-0.4132690429687500, 0.0000305175781250, -0.4241027832031250, 0.0000610351562500, +-0.4111633300781250, 0.0000305175781250, -0.4167175292968750, 0.0000915527343750, +-0.4142761230468750, 0.0000915527343750, -0.4050598144531250, 0.0000305175781250, +-0.4025268554687500, 0.0000610351562500, -0.3982543945312500, 0.0000915527343750, +-0.3796081542968750, 0.0000610351562500, -0.3769836425781250, 0.0000305175781250, +-0.3611145019531250, 0.0000610351562500, -0.3398742675781250, 0.0000610351562500, +-0.3381042480468750, 0.0000610351562500, -0.3048400878906250, 0.0000915527343750, +-0.3048400878906250, 0.0000610351562500, -0.2859802246093750, 0.0000915527343750, +-0.2561340332031250, 0.0000915527343750, -0.2636413574218750, 0.0000915527343750, +-0.2211914062500000, 0.0000610351562500, -0.2213745117187500, 0.0000305175781250, +-0.2101745605468750, 0.0000610351562500, -0.1787109375000000, 0.0000305175781250, +-0.1869506835937500, 0.0000305175781250, -0.1699523925781250, 0.0000305175781250, +-0.1628417968750000, 0.0000610351562500, -0.1697998046875000, -0.0000305175781250, +-0.1674804687500000, -0.0000305175781250, -0.1642150878906250, 0.0000000000000000, +-0.1912536621093750, -0.0000305175781250, -0.1862792968750000, -0.0000305175781250, +-0.2048034667968750, -0.0000305175781250, -0.2355651855468750, -0.0000610351562500, +-0.2236633300781250, -0.0000610351562500, -0.2579040527343750, 0.0000305175781250, +-0.2665405273437500, -0.0000305175781250, -0.2499389648437500, 0.0000305175781250, +-0.2595825195312500, 0.0000610351562500, -0.2648315429687500, 0.0000000000000000, +-0.1848449707031250, 0.0000305175781250, -0.2168579101562500, 0.0000000000000000, +-0.1430358886718750, 0.0000305175781250, -0.0445251464843750, 0.0000305175781250, +-0.1026000976562500, 0.0000305175781250, 0.1078491210937500, 0.0000610351562500, +0.0925903320312500, 0.0001220703125000, 0.1409606933593750, 0.0000915527343750, +0.2926940917968750, 0.0000915527343750, 0.2304077148437500, 0.0001220703125000, +0.3198547363281250, -0.0000305175781250, 0.3576965332031250, -0.0000305175781250, +0.3060607910156250, -0.0000305175781250, 0.3072509765625000, -0.0001220703125000, +0.3303833007812500, -0.0001220703125000, 0.1734008789062500, -0.0000610351562500, +0.2041931152343750, -0.0000915527343750, 0.1385803222656250, -0.0000305175781250, +-0.0032653808593750, 0.0000610351562500, 0.0639038085937500, -0.0000305175781250, +-0.0621948242187500, -0.0000610351562500, -0.0830383300781250, -0.0000305175781250, +-0.0627441406250000, -0.0000610351562500, -0.1054382324218750, -0.0001525878906250, +-0.1021728515625000, -0.0001525878906250, -0.0579833984375000, 0.0000305175781250, +-0.0721435546875000, 0.0000000000000000, -0.0534973144531250, 0.0000000000000000, +-0.0098571777343750, 0.0001525878906250, -0.0296936035156250, 0.0001220703125000, +-0.0032653808593750, -0.0000915527343750, 0.0046997070312500, 0.0000305175781250, +-0.0018310546875000, 0.0000000000000000, 0.0020751953125000, -0.0001831054687500, +0.0031738281250000, -0.0001525878906250, -0.0011901855468750, 0.0000305175781250, +-0.0020751953125000, -0.0000610351562500, -0.0005798339843750, -0.0000610351562500, +-0.0009155273437500, 0.0001220703125000, -0.0016479492187500, 0.0001220703125000, +0.0003967285156250, -0.0000915527343750, 0.0009155273437500, 0.0000000000000000, +0.0000915527343750, -0.0000305175781250, 0.0002441406250000, -0.0001525878906250, +0.0006103515625000, -0.0001525878906250, -0.0003051757812500, -0.0000305175781250, +-0.0005187988281250, 0.0000000000000000, -0.0001525878906250, -0.0000305175781250, +0.0000610351562500, 0.0000000000000000, 0.0000915527343750, 0.0000000000000000, +0.0000305175781250, -0.0000915527343750, 0.0002441406250000, -0.0000915527343750, +0.0000305175781250, -0.0000305175781250, -0.0002441406250000, -0.0000305175781250, +-0.0000305175781250, -0.0000610351562500, -0.0000305175781250, -0.0000305175781250, +-0.0002136230468750, 0.0000610351562500, -0.0000915527343750, -0.0000610351562500, +0.0002136230468750, -0.0002136230468750, 0.0000915527343750, -0.0000915527343750, +-0.0000610351562500, 0.0000305175781250, 0.0001220703125000, -0.0001220703125000, +0.0000000000000000, -0.0000305175781250, -0.0003662109375000, 0.0004882812500000, +-0.0002441406250000, 0.0003356933593750, 0.0000305175781250, -0.0003967285156250, +-0.0001525878906250, -0.0000915527343750, -0.0000915527343750, -0.0002441406250000, +0.0002746582031250, -0.0012817382812500, 0.0001525878906250, -0.0010375976562500, +-0.0000610351562500, 0.0008239746093750, 0.0000305175781250, 0.0006713867187500, +0.0000000000000000, -0.0012512207031250, -0.0003356933593750, 0.0013732910156250, +-0.0002441406250000, 0.0017089843750000, 0.0000000000000000, -0.0172729492187500, +-0.0001220703125000, -0.0062866210937500, -0.0000610351562500, -0.0245971679687500, +0.0002441406250000, -0.0531311035156250, 0.0001831054687500, -0.0346069335937500, +-0.0000610351562500, -0.0681152343750000, 0.0000305175781250, -0.0812072753906250, +0.0000000000000000, -0.0521545410156250, -0.0002136230468750, -0.0534667968750000, +-0.0001220703125000, -0.0691528320312500, 0.0000000000000000, 0.0423583984375000, +-0.0000915527343750, 0.0096130371093750, -0.0000305175781250, 0.0644226074218750, +0.0001525878906250, 0.1773071289062500, 0.0000610351562500, 0.1179504394531250, +-0.0000305175781250, 0.2245483398437500, 0.0000610351562500, 0.2477722167968750, +0.0000305175781250, 0.2131958007812500, -0.0001525878906250, 0.2416687011718750, +-0.0000915527343750, 0.2512207031250000, 0.0000000000000000, 0.1430969238281250, +-0.0000915527343750, 0.1734313964843750, -0.0000305175781250, 0.1118774414062500, +0.0000915527343750, -0.0021362304687500, 0.0000000000000000, 0.0509948730468750, +0.0000000000000000, -0.0784606933593750, 0.0000305175781250, -0.0925292968750000, +0.0000305175781250, -0.0905456542968750, -0.0000610351562500, -0.1496887207031250, +0.0000000000000000, -0.1355285644531250, -0.0000305175781250, -0.1242065429687500, +-0.0000610351562500, -0.1368408203125000, 0.0000000000000000, -0.1196899414062500, +0.0000610351562500, -0.0927124023437500, -0.0000305175781250, -0.1052856445312500, +0.0000000000000000, -0.0922851562500000, 0.0000610351562500, -0.0808105468750000, +0.0000000000000000, -0.1021728515625000, 0.0000000000000000, -0.1127014160156250, +0.0000000000000000, -0.1018371582031250, -0.0000610351562500, -0.1681213378906250, +-0.0000305175781250, -0.1567077636718750, 0.0000000000000000, -0.1877136230468750, +0.0000305175781250, -0.2489318847656250, -0.0000610351562500, -0.2255249023437500, +0.0000000000000000, -0.3018798828125000, 0.0000610351562500, -0.3034973144531250, +0.0000000000000000, -0.3244018554687500, -0.0000305175781250, -0.3774719238281250, +0.0000305175781250, -0.3603515625000000, 0.0000000000000000, -0.4088134765625000, +0.0000000000000000, -0.4148559570312500, -0.0000305175781250, -0.4212951660156250, +0.0000305175781250, -0.4463806152343750, 0.0000305175781250, -0.4386291503906250, +0.0000305175781250, -0.4553527832031250, 0.0000305175781250, -0.4555358886718750, +0.0000305175781250, -0.4572143554687500, 0.0000000000000000, -0.4656372070312500, +0.0000305175781250, -0.4591979980468750, 0.0000305175781250, -0.4642639160156250, +0.0000000000000000, -0.4611511230468750, 0.0000305175781250, -0.4618530273437500, +0.0000610351562500, -0.4657287597656250, 0.0000000000000000, -0.4599304199218750, +0.0000305175781250, -0.4658508300781250, 0.0000000000000000, -0.4637756347656250, +0.0000000000000000, -0.4625549316406250, 0.0000305175781250, -0.4663085937500000, +0.0000305175781250, -0.4649963378906250, 0.0000610351562500, -0.4661865234375000, +0.0000000000000000, -0.4649963378906250, 0.0000000000000000, -0.4659729003906250, +-0.0000610351562500, -0.4685974121093750, -0.0000305175781250, -0.4644165039062500, +0.0000000000000000, -0.4575195312500000, 0.0000305175781250, -0.4629211425781250, +0.0000000000000000, -0.4503784179687500, 0.0000000000000000, -0.4405822753906250, +0.0000000000000000, -0.4501953125000000, -0.0000305175781250, -0.4033203125000000, +0.0000000000000000, -0.4237670898437500, 0.0000000000000000, -0.3912353515625000, +0.0000000000000000, -0.3445739746093750, -0.0000305175781250, -0.3835144042968750, +0.0000305175781250, -0.2720031738281250, 0.0000000000000000, -0.2980957031250000, +0.0000000000000000, -0.2668762207031250, 0.0000000000000000, -0.1777343750000000, +0.0000000000000000, -0.2302551269531250, 0.0000000000000000, -0.1427917480468750, +-0.0000610351562500, -0.1268615722656250, 0.0000000000000000, -0.1479797363281250, +0.0000305175781250, -0.1158752441406250, -0.0000305175781250, -0.1124572753906250, +0.0000305175781250, -0.1892089843750000, 0.0000610351562500, -0.1513366699218750, +0.0000305175781250, -0.2055664062500000, -0.0000305175781250, -0.3009948730468750, +0.0000305175781250, -0.2425537109375000, -0.0000305175781250, -0.3538513183593750, +-0.0000305175781250, -0.3682556152343750, 0.0000000000000000, -0.3323059082031250, +0.0000305175781250, -0.3754272460937500, 0.0000305175781250, -0.3802185058593750, +0.0000305175781250, -0.2324218750000000, 0.0000305175781250, -0.3004150390625000, +-0.0000305175781250, -0.1752319335937500, -0.0001220703125000, 0.0083312988281250, +-0.0000305175781250, -0.0997314453125000, -0.0000610351562500, 0.2403564453125000, +-0.0001220703125000, 0.2265319824218750, -0.0000610351562500, 0.2843322753906250, +0.0000305175781250, 0.5127868652343750, -0.0000305175781250, 0.4230957031250000, +0.0000305175781250, 0.5095825195312500, 0.0000915527343750, 0.5771179199218750, +0.0000000000000000, 0.4806518554687500, -0.0000915527343750, 0.4392089843750000, +-0.0000610351562500, 0.4960632324218750, -0.0000610351562500, 0.2311401367187500, +-0.0001525878906250, 0.2761840820312500, -0.0000610351562500, 0.1903686523437500, +0.0000915527343750, -0.0231018066406250, 0.0000305175781250, 0.0830688476562500, +0.0000610351562500, -0.1060791015625000, 0.0002136230468750, -0.1308288574218750, +0.0000000000000000, -0.1053161621093750, -0.0000915527343750, -0.1790771484375000, +0.0000305175781250, -0.1687316894531250, -0.0001831054687500, -0.1098632812500000, +-0.0003051757812500, -0.1367492675781250, -0.0001220703125000, -0.1009216308593750, +-0.0000305175781250, -0.0315551757812500, -0.0001525878906250, -0.0671997070312500, +0.0001831054687500, -0.0086669921875000, 0.0002746582031250, 0.0016784667968750, +0.0000610351562500, -0.0078735351562500, 0.0000915527343750, 0.0098876953125000, +0.0002136230468750, 0.0086059570312500, -0.0002136230468750, -0.0005187988281250, +-0.0002441406250000, 0.0003967285156250, -0.0000915527343750, 0.0010070800781250, +-0.0003356933593750, -0.0036621093750000, -0.0003356933593750, -0.0032653808593750, +0.0001220703125000, 0.0001525878906250, 0.0000305175781250, -0.0003662109375000, +0.0000610351562500}, +{0.0000000000000000, 0.0528259277343750, 0.0000305175781250, 0.0470886230468750, +0.0000305175781250, 0.0380249023437500, 0.0000305175781250, 0.0481262207031250, +0.0000305175781250, 0.0220031738281250, 0.0000610351562500, 0.0362548828125000, +0.0000305175781250, 0.0167846679687500, 0.0000305175781250, -0.0118103027343750, +0.0000000000000000, 0.0115966796875000, 0.0000000000000000, -0.0602416992187500, +0.0000305175781250, -0.0401306152343750, 0.0000305175781250, -0.0737915039062500, +0.0000000000000000, -0.1332092285156250, 0.0000000000000000, -0.0887145996093750, +0.0000305175781250, -0.2080078125000000, 0.0000305175781250, -0.1773071289062500, +0.0000305175781250, -0.2211914062500000, 0.0000305175781250, -0.3193359375000000, +0.0000610351562500, -0.2548217773437500, 0.0000305175781250, -0.3966369628906250, +0.0000000000000000, -0.3810729980468750, 0.0000000000000000, -0.3933410644531250, +0.0000305175781250, -0.4866943359375000, -0.0000305175781250, -0.4445495605468750, +0.0000000000000000, -0.4738159179687500, 0.0000610351562500, -0.5079956054687500, +0.0000305175781250, -0.4566040039062500, -0.0000305175781250, -0.4304809570312500, +0.0000305175781250, -0.4668273925781250, -0.0000610351562500, -0.3184204101562500, +-0.0000610351562500, -0.3529968261718750, -0.0000305175781250, -0.3026123046875000, +0.0000000000000000, -0.1724853515625000, -0.0000305175781250, -0.2399291992187500, +0.0000000000000000, -0.1406555175781250, 0.0000610351562500, -0.1161193847656250, +0.0000000000000000, -0.1522827148437500, -0.0000305175781250, -0.1300048828125000, +0.0000305175781250, -0.1176452636718750, -0.0000610351562500, -0.2128295898437500, +-0.0001220703125000, -0.1897888183593750, 0.0000000000000000, -0.2167968750000000, +0.0000610351562500, -0.3056335449218750, 0.0000305175781250, -0.2711486816406250, +0.0000305175781250, -0.2866516113281250, 0.0000915527343750, -0.3374023437500000, +0.0000000000000000, -0.2471618652343750, -0.0001220703125000, -0.1833190917968750, +0.0000000000000000, -0.2445068359375000, -0.0000610351562500, 0.0302124023437500, +-0.0001525878906250, -0.0245971679687500, 0.0000000000000000, 0.0776367187500000, +0.0000610351562500, 0.3213500976562500, -0.0000915527343750, 0.2100524902343750, +0.0000915527343750, 0.4246520996093750, 0.0001831054687500, 0.4639282226562500, +0.0000000000000000, 0.4107055664062500, -0.0000915527343750, 0.4804687500000000, +0.0000305175781250, 0.4879455566406250, -0.0000915527343750, 0.3202209472656250, +-0.0002136230468750, 0.3880004882812500, -0.0000915527343750, 0.2796630859375000, +0.0000000000000000, 0.0898132324218750, -0.0001220703125000, 0.1987915039062500, +0.0001525878906250, -0.0452575683593750, 0.0002136230468750, -0.0586547851562500, +0.0000915527343750, -0.0528259277343750, 0.0000610351562500, -0.1733093261718750, +0.0001831054687500, -0.1405029296875000, -0.0001525878906250, -0.1148986816406250, +-0.0002136230468750, -0.1494750976562500, -0.0000915527343750, -0.1076965332031250, +-0.0002441406250000, -0.0477600097656250, -0.0003051757812500, -0.0832824707031250, +0.0000915527343750, -0.0145263671875000, 0.0000000000000000, -0.0041809082031250, +0.0000305175781250, -0.0126342773437500, 0.0003356933593750, 0.0104064941406250, +0.0002746582031250, 0.0073852539062500, 0.0000000000000000, -0.0004577636718750, +0.0001220703125000, 0.0014648437500000, 0.0000000000000000, 0.0015563964843750, +-0.0003967285156250, -0.0032043457031250, -0.0002136230468750, -0.0026855468750000, +-0.0002746582031250, -0.0000610351562500, -0.0004577636718750, -0.0006103515625000, +-0.0002441406250000, -0.0007934570312500, 0.0001525878906250, 0.0013427734375000, +0.0005798339843750, -0.0021362304687500, -0.0007934570312500, 0.0002136230468750, +-0.0000305175781250, -0.0009460449218750, -0.0005187988281250, -0.0007019042968750, +-0.0018005371093750, 0.0008239746093750, -0.0013732910156250, 0.0007324218750000, +0.0001220703125000, -0.0001831054687500, -0.0012207031250000, -0.0001525878906250, +0.0004882812500000, 0.0001831054687500, 0.0041503906250000, -0.0000610351562500, +0.0018005371093750, -0.0002441406250000, -0.0009460449218750, 0.0003051757812500, +0.0071411132812500, 0.0005493164062500, -0.0115356445312500, 0.0001525878906250, +-0.0235900878906250, -0.0001831054687500, -0.0089721679687500, 0.0001831054687500, +-0.0773315429687500, -0.0003051757812500, -0.0614013671875000, -0.0005798339843750, +-0.0820922851562500, -0.0001525878906250, -0.1470031738281250, 0.0001525878906250, +-0.1143493652343750, -0.0002136230468750, -0.1154174804687500, 0.0002441406250000, +-0.1648559570312500, 0.0005187988281250, -0.0726318359375000, 0.0000915527343750, +-0.0046997070312500, -0.0002441406250000, -0.0813293457031250, 0.0001220703125000, +0.1817626953125000, -0.0003356933593750, 0.1334533691406250, -0.0006103515625000, +0.1945800781250000, -0.0001831054687500, 0.4058227539062500, 0.0000610351562500, +0.3057556152343750, -0.0002136230468750, 0.3971862792968750, 0.0002136230468750, +0.4656982421875000, 0.0004272460937500, 0.3595275878906250, 0.0001525878906250, +0.3187866210937500, 0.0000000000000000, 0.3898620605468750, 0.0001525878906250, +0.1112365722656250, -0.0000915527343750, 0.1606140136718750, -0.0002441406250000, +0.1003723144531250, -0.0000305175781250, -0.1098937988281250, 0.0000915527343750, +-0.0086669921875000, 0.0000000000000000, -0.1309509277343750, 0.0001525878906250, +-0.1651611328125000, 0.0003051757812500, -0.1265869140625000, 0.0000915527343750, +-0.1473999023437500, -0.0001220703125000, -0.1604003906250000, 0.0000610351562500, +-0.1155395507812500, -0.0001220703125000, -0.1138000488281250, -0.0002136230468750, +-0.1340637207031250, -0.0000915527343750, -0.1160583496093750, 0.0000610351562500, +-0.1098937988281250, -0.0000915527343750, -0.1979064941406250, 0.0000610351562500, +-0.1583251953125000, 0.0001831054687500, -0.2145385742187500, 0.0000915527343750, +-0.3107299804687500, -0.0000305175781250, -0.2479553222656250, 0.0000000000000000, +-0.3994750976562500, 0.0000305175781250, -0.3879394531250000, -0.0000610351562500, +-0.4044494628906250, 0.0000000000000000, -0.5013732910156250, 0.0001525878906250, +-0.4574890136718750, 0.0000610351562500, -0.4937133789062500, -0.0000305175781250, +-0.5205993652343750, 0.0000610351562500, -0.4716491699218750, 0.0000000000000000, +-0.4578247070312500, -0.0001220703125000, -0.4895935058593750, -0.0000610351562500, +-0.3429260253906250, -0.0000915527343750, -0.3951416015625000, -0.0000915527343750, +-0.3190002441406250, -0.0000915527343750, -0.1810302734375000, -0.0000305175781250, +-0.2805786132812500, -0.0000610351562500, -0.0618591308593750, -0.0001220703125000, +-0.0928955078125000, -0.0001220703125000, -0.0481262207031250, -0.0001220703125000, +0.1025390625000000, -0.0001525878906250, 0.0127563476562500, -0.0001220703125000, +0.1568908691406250, -0.0000610351562500, 0.1549377441406250, -0.0000915527343750, +0.1506347656250000, -0.0000610351562500, 0.2230834960937500, -0.0000305175781250, +0.1913146972656250, 0.0000000000000000, 0.2135620117187500, 0.0000000000000000, +0.2278442382812500, -0.0000610351562500, 0.2105712890625000, 0.0000000000000000, +0.2072753906250000, 0.0000305175781250, 0.2190246582031250, -0.0000305175781250, +0.1828918457031250, 0.0001220703125000, 0.1951599121093750, 0.0000915527343750, +0.1875000000000000, 0.0000610351562500, 0.1611938476562500, 0.0000915527343750, +0.1855773925781250, 0.0000610351562500, 0.1651306152343750, 0.0000610351562500, +0.1701049804687500, 0.0000305175781250, 0.1755676269531250, 0.0000610351562500, +0.1682434082031250, 0.0000915527343750, 0.1816406250000000, 0.0000610351562500, +0.1833190917968750, 0.0000610351562500, 0.1856079101562500, 0.0000915527343750, +0.1967773437500000, 0.0001220703125000, 0.2041625976562500, 0.0000610351562500, +0.2052612304687500, 0.0000610351562500, 0.2240600585937500, 0.0000305175781250, +0.2306213378906250, 0.0000000000000000, 0.2355346679687500, 0.0000305175781250, +0.2451477050781250, 0.0000305175781250, 0.2449340820312500, 0.0000000000000000, +0.2442321777343750, 0.0000305175781250, 0.2476806640625000, 0.0000000000000000, +0.2374877929687500, 0.0000000000000000, 0.2293395996093750, -0.0000305175781250, +0.2312927246093750, 0.0000305175781250, 0.1931152343750000, -0.0000915527343750, +0.2011108398437500, -0.0000610351562500, 0.1736450195312500, -0.0000610351562500, +0.1340942382812500, -0.0000610351562500, 0.1482238769531250, -0.0000610351562500, +0.0606384277343750, -0.0000915527343750, 0.0712890625000000, -0.0000915527343750, +0.0292053222656250, -0.0000915527343750, -0.0485229492187500, -0.0000915527343750, +-0.0185852050781250, -0.0000610351562500, -0.1276550292968750, -0.0000915527343750, +-0.1251831054687500, -0.0000915527343750, -0.1550598144531250, -0.0000610351562500, +-0.2356262207031250, -0.0000915527343750, -0.2099609375000000, -0.0001220703125000, +-0.2709655761718750, -0.0000610351562500, -0.2831726074218750, -0.0000610351562500, +-0.2724914550781250, -0.0000305175781250, -0.2929992675781250, 0.0000610351562500, +-0.2933654785156250, -0.0000305175781250, -0.2572937011718750, 0.0000000000000000, +-0.2698364257812500, 0.0000305175781250, -0.2458496093750000, 0.0000000000000000, +-0.2037658691406250, -0.0000305175781250, -0.2255859375000000, -0.0000305175781250, +-0.1834716796875000, 0.0000000000000000, -0.1760559082031250, -0.0000305175781250, +-0.1854553222656250, 0.0000000000000000, -0.1739501953125000, 0.0000305175781250, +-0.1731262207031250, 0.0000305175781250, -0.1912231445312500, 0.0000000000000000, +-0.1958618164062500, 0.0000000000000000, -0.1826782226562500, 0.0000000000000000, +-0.1916809082031250, -0.0000915527343750, -0.1978759765625000, -0.0000610351562500, +-0.1051025390625000, -0.0000305175781250, -0.1430053710937500, -0.0000305175781250, +-0.0636596679687500, 0.0000000000000000, 0.0529479980468750, 0.0001220703125000, +-0.0168762207031250, 0.0000915527343750, 0.1709594726562500, 0.0000000000000000, +0.1765747070312500, 0.0000915527343750, 0.1740112304687500, 0.0000000000000000, +0.2771606445312500, -0.0001525878906250, 0.2509155273437500, -0.0000610351562500, +0.1946105957031250, -0.0000610351562500, 0.2444152832031250, -0.0001831054687500, +0.1677551269531250, -0.0000915527343750, 0.0620117187500000, 0.0001220703125000, +0.1288757324218750, -0.0000305175781250, -0.0208740234375000, 0.0000000000000000, +-0.0341186523437500, 0.0000305175781250, -0.0244445800781250, -0.0000610351562500, +-0.0908203125000000, -0.0002136230468750, -0.0773315429687500, -0.0001525878906250, +-0.0500488281250000, -0.0000610351562500, -0.0672302246093750, -0.0001220703125000, +-0.0480346679687500, -0.0000610351562500, -0.0106201171875000, 0.0000915527343750, +-0.0283813476562500, 0.0000000000000000, -0.0036926269531250, 0.0000000000000000, +0.0034179687500000, 0.0000305175781250, -0.0025024414062500, 0.0000000000000000, +0.0012512207031250, -0.0000915527343750, 0.0021972656250000, -0.0000610351562500, +-0.0010375976562500, 0.0000000000000000, -0.0018615722656250, -0.0000305175781250, +-0.0006408691406250, -0.0000610351562500, -0.0001220703125000, -0.0000915527343750, +-0.0000915527343750, -0.0001220703125000, 0.0001831054687500, -0.0000610351562500, +0.0005798339843750, -0.0001525878906250, 0.0002136230468750, -0.0000610351562500, +-0.0002441406250000, 0.0002136230468750, 0.0001525878906250, 0.0000000000000000, +-0.0000305175781250, -0.0000915527343750, -0.0003967285156250, 0.0002441406250000, +-0.0001220703125000, -0.0002746582031250, 0.0002136230468750, -0.0011291503906250, +0.0000305175781250}, +{-0.0187377929687500, 0.0000305175781250, -0.0278625488281250, 0.0000305175781250, +0.0157470703125000, 0.0000610351562500, 0.0114746093750000, 0.0000305175781250, +0.0299072265625000, 0.0000915527343750, 0.0667724609375000, 0.0000915527343750, +0.0557250976562500, 0.0000610351562500, 0.1102905273437500, 0.0000305175781250, +0.1088867187500000, 0.0000610351562500, 0.1247558593750000, 0.0000610351562500, +0.1678161621093750, 0.0000000000000000, 0.1584472656250000, 0.0000610351562500, +0.1877441406250000, 0.0000305175781250, 0.1969909667968750, 0.0000000000000000, +0.1871643066406250, -0.0000305175781250, 0.1961975097656250, 0.0000305175781250, +0.2004699707031250, 0.0000000000000000, 0.1478271484375000, -0.0000610351562500, +0.1674194335937500, 0.0000000000000000, 0.1211242675781250, -0.0000305175781250, +0.0554199218750000, -0.0001525878906250, 0.0885925292968750, -0.0001220703125000, +-0.0364685058593750, -0.0000915527343750, -0.0316162109375000, -0.0001220703125000, +-0.0658874511718750, -0.0001220703125000, -0.1574401855468750, 0.0000000000000000, +-0.1218566894531250, -0.0000610351562500, -0.1852111816406250, -0.0000305175781250, +-0.2024230957031250, 0.0000000000000000, -0.1836242675781250, -0.0000305175781250, +-0.1949462890625000, -0.0000610351562500, -0.2005004882812500, -0.0000610351562500, +-0.1634521484375000, 0.0000000000000000, -0.1676635742187500, -0.0000610351562500, +-0.1638488769531250, -0.0000610351562500, -0.1377563476562500, 0.0000305175781250, +-0.1460876464843750, 0.0000305175781250, -0.1544189453125000, 0.0000000000000000, +-0.1492004394531250, 0.0000305175781250, -0.1526489257812500, 0.0000000000000000, +-0.1718139648437500, -0.0000915527343750, -0.1679687500000000, -0.0000610351562500, +-0.1212158203125000, -0.0000610351562500, -0.1570129394531250, -0.0001220703125000, +-0.0887145996093750, -0.0000305175781250, -0.0065002441406250, 0.0001220703125000, +-0.0629882812500000, 0.0000000000000000, 0.1187133789062500, 0.0000610351562500, +0.1120300292968750, 0.0001525878906250, 0.1240539550781250, 0.0000305175781250, +0.2398986816406250, -0.0001220703125000, 0.2024841308593750, -0.0000305175781250, +0.1757202148437500, -0.0001220703125000, 0.2240600585937500, -0.0002136230468750, +0.1516418457031250, -0.0001220703125000, 0.0632324218750000, 0.0000305175781250, +0.1197509765625000, -0.0000915527343750, -0.0185852050781250, -0.0000305175781250, +-0.0261230468750000, 0.0000915527343750, -0.0173339843750000, 0.0000000000000000, +-0.0820617675781250, -0.0001220703125000, -0.0689392089843750, -0.0000610351562500, +-0.0430908203125000, 0.0000000000000000, -0.0588073730468750, -0.0000305175781250, +-0.0416259765625000, -0.0000915527343750, -0.0074462890625000, 0.0000305175781250, +-0.0236816406250000, 0.0000000000000000, -0.0030822753906250, -0.0000915527343750, +0.0032348632812500, -0.0001220703125000, -0.0018920898437500, 0.0000000000000000, +0.0000000000000000, 0.0001525878906250, -0.0004577636718750, 0.0001220703125000, +-0.0006713867187500, -0.0000915527343750, -0.0015258789062500, 0.0001831054687500, +-0.0008239746093750, -0.0001525878906250, 0.0003662109375000, -0.0008544921875000, +-0.0005187988281250, -0.0003967285156250, 0.0000915527343750, -0.0003967285156250, +0.0006408691406250, -0.0010375976562500, 0.0002136230468750, -0.0004577636718750, +-0.0003051757812500, 0.0017700195312500, -0.0000610351562500, 0.0005798339843750, +0.0000610351562500, -0.0067749023437500, -0.0002136230468750, 0.0007019042968750, +-0.0001220703125000, -0.0141906738281250, 0.0002746582031250, -0.0317077636718750, +0.0001831054687500, -0.0184020996093750, -0.0001525878906250, -0.0494079589843750, +-0.0000610351562500, -0.0585937500000000, 0.0000000000000000, -0.0352478027343750, +-0.0002136230468750, -0.0401611328125000, -0.0002441406250000, -0.0519104003906250, +0.0001525878906250, 0.0455627441406250, 0.0001220703125000, 0.0185546875000000, +0.0000000000000000, 0.0565185546875000, 0.0001220703125000, 0.1526794433593750, +0.0002136230468750, 0.1051330566406250, -0.0001525878906250, 0.1467285156250000, +-0.0001831054687500, 0.1838684082031250, -0.0000610351562500, 0.1257934570312500, +-0.0001525878906250, 0.0939025878906250, -0.0002136230468750, 0.1327819824218750, +0.0000915527343750, -0.0029602050781250, 0.0001220703125000, 0.0051574707031250, +0.0000000000000000, -0.0043640136718750, 0.0000610351562500, -0.0876770019531250, +0.0001525878906250, -0.0593261718750000, -0.0001220703125000, -0.0652160644531250, +-0.0001220703125000, -0.0815734863281250, -0.0000305175781250, -0.0699768066406250, +-0.0001220703125000, -0.0498962402343750, -0.0001831054687500, -0.0581970214843750, +0.0000305175781250, -0.0788574218750000, 0.0000305175781250, -0.0553588867187500, +0.0000000000000000, -0.0979003906250000, 0.0000610351562500, -0.1484375000000000, +0.0000610351562500, -0.1116943359375000, -0.0000915527343750, -0.1999511718750000, +-0.0000610351562500, -0.2080993652343750, -0.0000305175781250, -0.1964721679687500, +-0.0001220703125000, -0.2372436523437500, -0.0001525878906250, -0.2311706542968750, +0.0000305175781250, -0.1656799316406250, 0.0000000000000000, -0.1914367675781250, +0.0000000000000000, -0.1305236816406250, 0.0000610351562500, -0.0425720214843750, +0.0000915527343750, -0.0853881835937500, -0.0000305175781250, 0.0467834472656250, +0.0000000000000000, 0.0530700683593750, -0.0000305175781250, 0.0631408691406250, +-0.0000610351562500, 0.1363525390625000, -0.0000610351562500, 0.1148071289062500, +0.0000000000000000, 0.1255493164062500, -0.0000305175781250, 0.1427001953125000, +-0.0000610351562500, 0.1213989257812500, 0.0000610351562500, 0.1026916503906250, +0.0000305175781250, 0.1137084960937500, 0.0000000000000000, 0.0704956054687500, +0.0000000000000000, 0.0690307617187500, 0.0000000000000000, 0.0680236816406250, +-0.0000305175781250, 0.0440063476562500, -0.0000305175781250, 0.0495605468750000, +0.0000000000000000, 0.0594482421875000, 0.0000000000000000, 0.0502624511718750, +-0.0000610351562500, 0.0711975097656250, 0.0000000000000000, 0.0946350097656250, +0.0000305175781250, 0.0823364257812500, 0.0000000000000000, 0.1326904296875000, +0.0000305175781250, 0.1344299316406250, -0.0000305175781250, 0.1549987792968750, +0.0000305175781250, 0.1965637207031250, 0.0000305175781250, 0.1879577636718750, +0.0000610351562500, 0.2285461425781250, 0.0000305175781250, 0.2389831542968750, +0.0000000000000000, 0.2552795410156250, 0.0000610351562500, 0.2826232910156250, +0.0000000000000000, 0.2796630859375000, 0.0000305175781250, 0.3113098144531250, +0.0000305175781250, 0.3281250000000000, 0.0000610351562500, 0.3324279785156250, +0.0000305175781250, 0.3466186523437500, 0.0000610351562500, 0.3581542968750000, +0.0000305175781250, 0.3496398925781250, 0.0000305175781250, 0.3609619140625000, +0.0000000000000000, 0.3584594726562500, 0.0000305175781250, 0.3488159179687500, +0.0000305175781250, 0.3590087890625000, 0.0000305175781250, 0.3311462402343750, +0.0000305175781250, 0.3513793945312500, 0.0000915527343750, 0.3295898437500000, +0.0000000000000000, 0.2968750000000000, 0.0000000000000000, 0.3278503417968750, +0.0000305175781250, 0.2469482421875000, 0.0000610351562500, 0.2674865722656250, +0.0000305175781250, 0.2398071289062500, 0.0000000000000000, 0.1769409179687500, +0.0000000000000000, 0.2233276367187500, 0.0000305175781250, 0.1314697265625000, +0.0000000000000000, 0.1445922851562500, 0.0000000000000000, 0.1315002441406250, +0.0000000000000000, 0.0692138671875000, 0.0000305175781250, 0.1054382324218750, +-0.0000305175781250, 0.0658874511718750, -0.0000305175781250, 0.0545349121093750, +0.0000000000000000, 0.0804748535156250, -0.0000305175781250, 0.0772705078125000, +0.0000000000000000, 0.0650634765625000, 0.0000305175781250, 0.1280212402343750, +-0.0000305175781250, 0.1166992187500000, 0.0000305175781250, 0.1311950683593750, +0.0000305175781250, 0.1864013671875000, 0.0000305175781250, 0.1654968261718750, +0.0000000000000000, 0.1624145507812500, 0.0000000000000000, 0.1978454589843750, +0.0000305175781250, 0.1249389648437500, 0.0000000000000000, 0.0736083984375000, +-0.0000305175781250, 0.1309204101562500, 0.0000915527343750, -0.0929870605468750, +0.0000915527343750, -0.0434570312500000, 0.0000610351562500, -0.1288146972656250, +0.0000305175781250, -0.3221130371093750, 0.0000915527343750, -0.2140808105468750, +-0.0000610351562500, -0.4138183593750000, -0.0000305175781250, -0.4318847656250000, +0.0000000000000000, -0.4111633300781250, 0.0000000000000000, -0.5028076171875000, +-0.0000610351562500, -0.4894409179687500, 0.0000000000000000, -0.4224548339843750, +0.0000610351562500, -0.4605407714843750, -0.0000305175781250, -0.3949890136718750, +-0.0000305175781250, -0.2984619140625000, 0.0000305175781250, -0.3547668457031250, +-0.0000915527343750, -0.2211303710937500, -0.0001831054687500, -0.2138671875000000, +-0.0000915527343750, -0.2175598144531250, -0.0001220703125000, -0.1530761718750000, +-0.0001525878906250, -0.1700134277343750, 0.0000610351562500, -0.1825866699218750, +0.0000305175781250, -0.1734924316406250, 0.0000000000000000, -0.1737670898437500, +0.0000305175781250, -0.1962585449218750, 0.0001220703125000, -0.1933898925781250, +-0.0001831054687500, -0.1287536621093750, -0.0001525878906250, -0.1780395507812500, +-0.0001220703125000, -0.0871582031250000, -0.0002136230468750, 0.0207519531250000, +-0.0002441406250000, -0.0588378906250000, 0.0000000000000000, 0.1953735351562500, +-0.0000305175781250, 0.1750793457031250, 0.0000000000000000, 0.2132873535156250, +0.0001831054687500, 0.3937072753906250, 0.0001525878906250, 0.3231506347656250, +-0.0000305175781250, 0.3395385742187500, 0.0000610351562500, 0.4090881347656250, +-0.0000915527343750, 0.3016052246093750, -0.0002746582031250, 0.2118530273437500, +-0.0001525878906250, 0.2918701171875000, -0.0001831054687500, 0.0376892089843750, +-0.0003356933593750, 0.0480346679687500, -0.0000915527343750, 0.0221557617187500, +0.0000610351562500, -0.1379089355468750, -0.0000610351562500, -0.0812072753906250, +0.0003662109375000, -0.1026611328125000, 0.0004577636718750, -0.1426391601562500, +0.0002441406250000, -0.0964355468750000, 0.0003967285156250, -0.0543212890625000, +0.0004882812500000, -0.0871582031250000, -0.0006713867187500, -0.0187988281250000, +-0.0004882812500000, -0.0120239257812500, -0.0004577636718750, -0.0210266113281250, +-0.0016174316406250, 0.0140380859375000, 0.0024108886718750, -0.0847473144531250, +-0.0150756835937500, -0.0074157714843750, 0.0045471191406250, -0.0197143554687500, +-0.0243225097656250, -0.0163879394531250, -0.0504760742187500, 0.0079345703125000, +-0.0275268554687500, 0.0038757324218750, -0.0924072265625000, -0.0003662109375000, +-0.0920410156250000, 0.0015563964843750, -0.0841064453125000, 0.0012512207031250, +-0.1257019042968750, -0.0019226074218750, -0.1171569824218750, -0.0015563964843750, +-0.0330200195312500, 0.0000000000000000, -0.0915832519531250, -0.0001831054687500, +0.0117492675781250, -0.0004272460937500, 0.1453552246093750, 0.0003051757812500, +0.0478515625000000, 0.0003967285156250, 0.2974548339843750, -0.0001525878906250, +0.2997741699218750, -0.0003051757812500, 0.2778320312500000, 0.0000305175781250, +0.4158325195312500, 0.0000915527343750, 0.3887939453125000, -0.0001831054687500, +0.2364807128906250, 0.0001831054687500, 0.3381042480468750, 0.0003662109375000, +0.1950073242187500, 0.0000610351562500, -0.0309448242187500, -0.0001525878906250, +0.1176147460937500, 0.0000610351562500, -0.1513061523437500, -0.0000915527343750, +-0.1828918457031250}, +{-0.0000610351562500, 0.1758422851562500, -0.0000305175781250, 0.1729125976562500, +-0.0000305175781250, 0.1650085449218750, -0.0001220703125000, 0.2125854492187500, +-0.0000610351562500, 0.2018432617187500, 0.0000000000000000, 0.1256408691406250, +0.0000305175781250, 0.1765136718750000, -0.0000305175781250, 0.0843200683593750, +0.0000000000000000, -0.0334777832031250, 0.0000305175781250, 0.0430603027343750, +-0.0001220703125000, -0.2059326171875000, -0.0001220703125000, -0.1896057128906250, +-0.0000610351562500, -0.2392578125000000, -0.0001220703125000, -0.4133300781250000, +-0.0001220703125000, -0.3414611816406250, 0.0000000000000000, -0.4272460937500000, +0.0000305175781250, -0.4696350097656250, -0.0000305175781250, -0.4138793945312500, +0.0000915527343750, -0.4044189453125000, 0.0000610351562500, -0.4314575195312500, +-0.0001525878906250, -0.2937316894531250, -0.0001220703125000, -0.3164062500000000, +-0.0000610351562500, -0.2788085937500000, -0.0001831054687500, -0.1691894531250000, +-0.0001525878906250, -0.2179260253906250, 0.0000305175781250, -0.1504211425781250, +-0.0000305175781250, -0.1341247558593750, -0.0000305175781250, -0.1491699218750000, +0.0001525878906250, -0.1388244628906250, 0.0001525878906250, -0.1364135742187500, +-0.0000305175781250, -0.1232910156250000, 0.0000610351562500, -0.1515502929687500, +-0.0000305175781250, -0.0877075195312500, -0.0002136230468750, -0.0379333496093750, +-0.0001525878906250, -0.0882568359375000, -0.0001525878906250, 0.1231079101562500, +-0.0002746582031250, 0.0842590332031250, -0.0000915527343750, 0.1418151855468750, +0.0000610351562500, 0.3206481933593750, -0.0000915527343750, 0.2403869628906250, +0.0003356933593750, 0.3129882812500000, 0.0003967285156250, 0.3784790039062500, +0.0001831054687500, 0.2777709960937500, 0.0003051757812500, 0.2221069335937500, +0.0003967285156250, 0.2878417968750000, -0.0006408691406250, 0.0474548339843750, +-0.0004882812500000, 0.0697631835937500, -0.0003662109375000, 0.0397338867187500, +-0.0012207031250000, -0.1218261718750000, -0.0010681152343750, -0.0603942871093750, +0.0010986328125000, -0.0947265625000000, 0.0003356933593750, -0.1301574707031250, +0.0004272460937500, -0.0946960449218750, 0.0031127929687500, -0.0442504882812500, +-0.0288696289062500, -0.0435791015625000, -0.0953063964843750, -0.0894165039062500, +-0.0848999023437500, -0.1177062988281250, -0.0709533691406250, -0.0782775878906250, +-0.0991210937500000, -0.0449218750000000, -0.1044006347656250, -0.0707702636718750, +0.0138549804687500, -0.0144653320312500, -0.0425720214843750, -0.0082702636718750, +0.0484313964843750, -0.0140075683593750, 0.1950378417968750, 0.0065917968750000, +0.1004333496093750, 0.0032348632812500, 0.3073120117187500, -0.0006408691406250, +0.3326416015625000, 0.0008544921875000, 0.2768859863281250, 0.0008544921875000, +0.3580627441406250, -0.0015563964843750, 0.3654785156250000, -0.0014038085937500, +0.1401367187500000, 0.0002441406250000, 0.2308349609375000, 0.0001220703125000, +0.1054382324218750, -0.0001831054687500, -0.1473693847656250, 0.0003967285156250, +0.0004272460937500, 0.0004882812500000, -0.2015686035156250, -0.0000915527343750, +-0.2761840820312500, -0.0001831054687500, -0.1613464355468750, 0.0000305175781250, +-0.1620788574218750, 0.0000305175781250, -0.2288818359375000, -0.0000305175781250, +0.0150756835937500, 0.0000000000000000, -0.0097045898437500, 0.0001220703125000, +-0.0114440917968750, 0.0000000000000000, 0.1535949707031250, -0.0003051757812500, +0.1080627441406250, -0.0001831054687500, -0.0261230468750000, 0.0000000000000000, +0.0833435058593750, -0.0002136230468750, -0.0762023925781250, -0.0000305175781250, +-0.3026123046875000, 0.0004272460937500, -0.1456298828125000, 0.0001525878906250, +-0.4718627929687500, 0.0000000000000000, -0.5018310546875000, 0.0002441406250000, +-0.4371032714843750, 0.0000610351562500, -0.5710754394531250, -0.0003356933593750, +-0.5664672851562500, -0.0001831054687500, -0.3495178222656250, -0.0001525878906250, +-0.4533691406250000, -0.0003051757812500, -0.3105773925781250, -0.0001831054687500, +-0.0610656738281250, 0.0000610351562500, -0.2210693359375000, 0.0000000000000000, +0.1013793945312500, -0.0000915527343750, 0.1062927246093750, -0.0000305175781250, +0.0965270996093750, -0.0001220703125000, 0.2626647949218750, -0.0002441406250000, +0.2107238769531250, -0.0002441406250000, 0.1876831054687500, 0.0000305175781250, +0.2439575195312500, -0.0000610351562500, 0.1757202148437500, -0.0000305175781250, +0.0971374511718750, 0.0002136230468750, 0.1595764160156250, 0.0001525878906250, +0.0044250488281250, -0.0000305175781250, 0.0111389160156250, 0.0000305175781250, +0.0062561035156250, 0.0000305175781250, -0.0892028808593750, -0.0000915527343750, +-0.0552062988281250, -0.0000610351562500, -0.0307922363281250, 0.0000305175781250, +-0.0833740234375000, 0.0000000000000000, 0.0093383789062500, -0.0000610351562500, +0.0870666503906250, -0.0000610351562500, 0.0036010742187500, 0.0000305175781250, +0.2753601074218750, -0.0001525878906250, 0.2035217285156250, -0.0001831054687500, +0.3020019531250000, -0.0001525878906250, 0.5280456542968750, -0.0001525878906250, +0.3830566406250000, -0.0001831054687500, 0.6717834472656250, -0.0000610351562500, +0.6470336914062500, -0.0000305175781250, 0.6855773925781250, -0.0000915527343750, +0.8690795898437500, -0.0000915527343750, 0.7750854492187500, -0.0000610351562500, +0.9118041992187500, -0.0000610351562500, 0.9224243164062500, -0.0000915527343750, +0.9091796875000000, -0.0000305175781250, 0.9695434570312500, 0.0000305175781250, +0.9526977539062500, 0.0000000000000000, 0.9431152343750000, 0.0000610351562500, +0.9671325683593750, 0.0000610351562500, 0.9442138671875000, 0.0000610351562500, +0.9173889160156250, 0.0000305175781250, 0.9448242187500000, 0.0000000000000000, +0.8828735351562500, 0.0000915527343750, 0.8976440429687500, 0.0000610351562500, +0.8855285644531250, 0.0000915527343750, 0.8445434570312500, 0.0000915527343750, +0.8799743652343750, 0.0000915527343750, 0.8346252441406250, 0.0000610351562500, +0.8443298339843750, 0.0000610351562500, 0.8459777832031250, 0.0000915527343750, +0.8236389160156250, 0.0001220703125000, 0.8484497070312500, 0.0000915527343750, +0.8296813964843750, 0.0000915527343750, 0.8383483886718750, 0.0000915527343750, +0.8470458984375000, 0.0000915527343750, 0.8410644531250000, 0.0001220703125000, +0.8560180664062500, 0.0001220703125000, 0.8645324707031250, 0.0000915527343750, +0.8780517578125000, 0.0000915527343750, 0.8859863281250000, 0.0000915527343750, +0.8934326171875000, 0.0000915527343750, 0.9101562500000000, 0.0000305175781250, +0.9073791503906250, 0.0000915527343750, 0.9143066406250000, 0.0000610351562500, +0.9155883789062500, 0.0000305175781250, 0.9130859375000000, 0.0000305175781250, +0.9202270507812500, 0.0000610351562500, 0.9031982421875000, 0.0000000000000000, +0.9080810546875000, -0.0000305175781250, 0.8924560546875000, -0.0000305175781250, +0.8757019042968750, 0.0000000000000000, 0.8854980468750000, -0.0000305175781250, +0.8171081542968750, -0.0000610351562500, 0.8363647460937500, -0.0000305175781250, +0.7861328125000000, -0.0000610351562500, 0.7148132324218750, -0.0001220703125000, +0.7514648437500000, -0.0001220703125000, 0.5904846191406250, -0.0001220703125000, +0.6167907714843750, -0.0001525878906250, 0.5299072265625000, -0.0001525878906250, +0.3802185058593750, -0.0001220703125000, 0.4478759765625000, -0.0001525878906250, +0.2103576660156250, -0.0001220703125000, 0.2240905761718750, -0.0000610351562500, +0.1663208007812500, -0.0000915527343750, -0.0021362304687500, -0.0000915527343750, +0.0660705566406250, -0.0000915527343750, -0.0659484863281250, -0.0000610351562500, +-0.0900573730468750, -0.0000610351562500, -0.0708312988281250, -0.0000305175781250, +-0.1179809570312500, 0.0000610351562500, -0.1122436523437500, 0.0000000000000000, +-0.0492248535156250, 0.0000610351562500, -0.0683593750000000, 0.0001220703125000, +-0.0349426269531250, 0.0000610351562500, 0.0335083007812500, 0.0000000000000000, +0.0036621093750000, 0.0000610351562500, 0.0481567382812500, 0.0000000000000000, +0.0713195800781250, -0.0000915527343750, 0.0396423339843750, -0.0000305175781250, +0.0327148437500000, 0.0000000000000000, 0.0506591796875000, -0.0000610351562500, +-0.0364685058593750, 0.0000305175781250, -0.0280761718750000, 0.0000915527343750, +-0.0444641113281250, 0.0000305175781250, -0.1081542968750000, -0.0000305175781250, +-0.0844116210937500, 0.0000000000000000, -0.0963439941406250, -0.0000610351562500, +-0.1134643554687500, -0.0001220703125000, -0.0941162109375000, 0.0000000000000000, +-0.0748291015625000, 0.0000305175781250, -0.0880432128906250, -0.0000305175781250, +-0.0720214843750000, 0.0000610351562500, -0.0622863769531250, 0.0001525878906250, +-0.0756835937500000, 0.0000305175781250, -0.0863037109375000, -0.0000305175781250, +-0.0763854980468750, 0.0000610351562500, -0.0767517089843750, -0.0000305175781250, +-0.1005554199218750, -0.0000915527343750, -0.0520629882812500, 0.0000000000000000, +-0.0139465332031250, 0.0000915527343750, -0.0503540039062500, 0.0000305175781250, +0.0881958007812500, 0.0000305175781250, 0.0761413574218750, 0.0000915527343750, +0.0884399414062500, 0.0000305175781250, 0.1856994628906250, 0.0000000000000000, +0.1547241210937500, 0.0000000000000000, 0.1275329589843750, 0.0000610351562500, +0.1705627441406250, 0.0001831054687500, 0.1088256835937500, -0.0001831054687500, +0.0302429199218750, -0.0004272460937500, 0.0828857421875000, -0.0000915527343750, +-0.0282897949218750, -0.0007324218750000, -0.0394592285156250, -0.0011291503906250, +-0.0234985351562500, -0.0003356933593750, -0.0654602050781250, 0.0010681152343750, +-0.0569458007812500, 0.0005493164062500, -0.0162048339843750, -0.0027770996093750, +-0.0313415527343750, 0.0018310546875000, -0.0281677246093750, -0.0062866210937500, +0.0023498535156250, -0.0135192871093750, -0.0090637207031250, -0.0063171386718750, +-0.0018920898437500, -0.0368347167968750, 0.0030822753906250, -0.0369873046875000, +0.0000000000000000, -0.0309448242187500, -0.0014953613281250, -0.0506286621093750, +-0.0004882812500000, -0.0492248535156250, -0.0003662109375000, 0.0068664550781250, +-0.0013122558593750, -0.0201416015625000, -0.0007629394531250, 0.0222473144531250, +0.0005187988281250, 0.0990295410156250, 0.0001525878906250, 0.0575866699218750, +-0.0001220703125000, 0.1185607910156250, 0.0001525878906250, 0.1456909179687500, +0.0001220703125000, 0.1010742187500000, -0.0003356933593750, 0.0918884277343750, +-0.0003051757812500, 0.1170349121093750, 0.0001220703125000, 0.0115966796875000, +0.0000610351562500, 0.0187683105468750, -0.0000610351562500, 0.0149230957031250, +0.0000915527343750, -0.0492553710937500, 0.0002136230468750, -0.0314636230468750, +-0.0001525878906250, -0.0239257812500000, -0.0002136230468750, -0.0355834960937500, +-0.0000305175781250, -0.0348815917968750, -0.0000610351562500, -0.0158386230468750, +-0.0001525878906250, -0.0185241699218750, 0.0000915527343750, -0.0669555664062500, +0.0002136230468750, -0.0441589355468750, 0.0000305175781250, -0.0760192871093750, +0.0000305175781250, -0.1395568847656250, 0.0000915527343750, -0.1051635742187500, +-0.0000915527343750, -0.1394653320312500, -0.0001831054687500, -0.1674804687500000, +-0.0000305175781250, -0.1213073730468750, 0.0000000000000000, -0.0968322753906250, +-0.0001220703125000, -0.1271667480468750, 0.0000610351562500, -0.0195922851562500, +0.0001831054687500, -0.0253601074218750, 0.0000305175781250, -0.0111083984375000, +0.0000305175781250}, +{-0.0924377441406250, 0.0000000000000000, -0.0733337402343750, 0.0000305175781250, +-0.0946960449218750, 0.0000610351562500, -0.0184631347656250, -0.0000610351562500, +-0.0101623535156250, -0.0000610351562500, -0.0209960937500000, 0.0000000000000000, +0.0116577148437500, -0.0000610351562500, 0.0119018554687500, -0.0000610351562500, +-0.0420227050781250, 0.0000610351562500, -0.0243530273437500, 0.0001220703125000, +-0.0462341308593750, 0.0000000000000000, -0.1026611328125000, 0.0000000000000000, +-0.0778503417968750, 0.0000305175781250, -0.0959777832031250, -0.0000610351562500, +-0.1144104003906250, -0.0001220703125000, -0.0895385742187500, 0.0000000000000000, +-0.0700073242187500, 0.0000915527343750, -0.0865783691406250, -0.0000305175781250, +-0.0538330078125000, -0.0000305175781250, -0.0457153320312500, 0.0000610351562500, +-0.0559387207031250, 0.0000305175781250, -0.0547485351562500, -0.0000305175781250, +-0.0498352050781250, -0.0000610351562500, -0.0467224121093750, 0.0000305175781250, +-0.0660705566406250, 0.0001220703125000, -0.0240478515625000, -0.0001831054687500, +0.0094604492187500, -0.0002136230468750, -0.0242919921875000, 0.0000305175781250, +0.0968322753906250, -0.0007324218750000, 0.0910339355468750, -0.0010070800781250, +0.0946044921875000, -0.0001831054687500, 0.1725158691406250, 0.0001525878906250, +0.1505432128906250, -0.0007324218750000, 0.1065979003906250, 0.0000305175781250, +0.1447753906250000, 0.0027465820312500, 0.0974121093750000, -0.0043945312500000, +-0.0034484863281250, -0.0098571777343750, 0.0032958984375000, -0.0091552734375000, +-0.0500793457031250, -0.0370483398437500, -0.0523376464843750, -0.0286865234375000, +-0.0335083007812500, -0.0271606445312500, -0.0511779785156250, -0.0520019531250000, +-0.0585632324218750, -0.0452880859375000, -0.0188598632812500, -0.0104370117187500, +-0.0238342285156250, -0.0354919433593750, -0.0213623046875000, 0.0075378417968750, +0.0035705566406250, 0.0688781738281250, -0.0043945312500000, 0.0294799804687500, +-0.0014648437500000, 0.1062622070312500, 0.0022277832031250, 0.1256103515625000, +0.0003356933593750, 0.0918579101562500, -0.0018005371093750, 0.1035461425781250, +-0.0011596679687500, 0.1189880371093750, -0.0002441406250000, 0.0297241210937500, +-0.0008544921875000, 0.0398254394531250, -0.0006408691406250, 0.0297241210937500, +0.0004577636718750, -0.0324707031250000, 0.0002746582031250, -0.0130920410156250, +-0.0001831054687500, -0.0112304687500000, -0.0000915527343750, -0.0220947265625000, +0.0000000000000000, -0.0216064453125000, -0.0002441406250000, -0.0061035156250000, +-0.0003051757812500, -0.0073242187500000, 0.0000305175781250, -0.0555725097656250, +0.0001525878906250, -0.0328979492187500, -0.0000305175781250, -0.0622253417968750, +-0.0000305175781250, -0.1257934570312500, 0.0000610351562500, -0.0935668945312500, +-0.0001525878906250, -0.1173400878906250, -0.0002136230468750, -0.1461181640625000, +-0.0000915527343750, -0.1018066406250000, -0.0000305175781250, -0.0710754394531250, +-0.0001525878906250, -0.1032104492187500, 0.0000305175781250, -0.0098266601562500, +0.0001831054687500, -0.0072937011718750, -0.0000305175781250, -0.0144348144531250, +-0.0000610351562500, 0.0308532714843750, 0.0000000000000000, 0.0234375000000000, +-0.0001220703125000, -0.0046081542968750, -0.0002136230468750, 0.0063781738281250, +-0.0000915527343750, -0.0019531250000000, 0.0000305175781250, -0.0368041992187500, +-0.0000915527343750, -0.0249938964843750, 0.0000610351562500, 0.0121154785156250, +0.0001220703125000, -0.0244140625000000, 0.0000000000000000, 0.0505371093750000, +0.0000000000000000, 0.1333618164062500, 0.0000610351562500, 0.0809936523437500, +-0.0000305175781250, 0.2818908691406250, -0.0000915527343750, 0.2692565917968750, +-0.0000610351562500, 0.3267822265625000, 0.0000305175781250, 0.4776916503906250, +-0.0000305175781250, 0.4168701171875000, 0.0000610351562500, 0.5252685546875000, +0.0000915527343750, 0.5495910644531250, 0.0000305175781250, 0.5221557617187500, +0.0000610351562500, 0.5501403808593750, 0.0000915527343750, 0.5527038574218750, +-0.0000305175781250, 0.4828796386718750, -0.0000305175781250, 0.5009460449218750, +0.0000305175781250, 0.4580688476562500, 0.0000000000000000, 0.3840942382812500, +-0.0000305175781250, 0.4128112792968750, 0.0000305175781250, 0.3078308105468750, +0.0000915527343750, 0.3061523437500000, 0.0000305175781250, 0.2855529785156250, +0.0000305175781250, 0.2178955078125000, 0.0000305175781250, 0.2356262207031250, +0.0000000000000000, 0.1813964843750000, 0.0000000000000000, 0.1755371093750000, +0.0000305175781250, 0.1612854003906250, 0.0000000000000000, 0.1248779296875000, +0.0000000000000000, 0.1304626464843750, 0.0000000000000000, 0.0942382812500000, +0.0000610351562500, 0.0851135253906250, 0.0000305175781250, 0.0755004882812500, +0.0000305175781250, 0.0533752441406250, 0.0000610351562500, 0.0531616210937500, +-0.0000305175781250, 0.0402526855468750, 0.0000000000000000, 0.0287475585937500, +0.0000000000000000, 0.0240478515625000, -0.0000305175781250, 0.0184631347656250, +0.0000000000000000, 0.0142211914062500, 0.0000610351562500, 0.0197143554687500, +0.0000610351562500, 0.0024108886718750, 0.0000000000000000, 0.0110473632812500, +0.0000000000000000, 0.0244445800781250, 0.0000305175781250, 0.0058593750000000, +0.0000000000000000, 0.0514526367187500, 0.0000000000000000, 0.0375671386718750, +0.0000000000000000, 0.0542907714843750, -0.0000305175781250, 0.0919189453125000, +0.0000000000000000, 0.0656127929687500, 0.0000000000000000, 0.1246337890625000, +0.0000000000000000, 0.1111145019531250, 0.0000000000000000, 0.1311950683593750, +0.0000305175781250, 0.1790771484375000, 0.0000000000000000, 0.1503906250000000, +-0.0000305175781250, 0.2189636230468750, 0.0000000000000000, 0.2096557617187500, +0.0000305175781250, 0.2281494140625000, 0.0000305175781250, 0.2757263183593750, +0.0000000000000000, 0.2457885742187500, -0.0000305175781250, 0.3085937500000000, +0.0000000000000000, 0.2979125976562500, -0.0000305175781250, 0.3155822753906250, +-0.0000305175781250, 0.3591003417968750, -0.0000305175781250, 0.3312072753906250, +0.0000000000000000, 0.4077758789062500, -0.0000610351562500, 0.3858337402343750, +-0.0000305175781250, 0.4205322265625000, 0.0000000000000000, 0.4835815429687500, +0.0000000000000000, 0.4373474121093750, 0.0000000000000000, 0.5700073242187500, +0.0000000000000000, 0.5420532226562500, -0.0000305175781250, 0.5945739746093750, +-0.0000915527343750, 0.7084960937500000, -0.0000610351562500, 0.6417846679687500, +-0.0000305175781250, 0.7787780761718750, -0.0000610351562500, 0.7788391113281250, +-0.0000305175781250, 0.7649230957031250, 0.0000305175781250, 0.8406982421875000, +0.0000000000000000, 0.8235168457031250, 0.0000000000000000, 0.7478027343750000, +0.0000305175781250, 0.8016662597656250, 0.0000000000000000, 0.7060241699218750, +-0.0000610351562500, 0.5867614746093750, -0.0000305175781250, 0.6701049804687500, +0.0000610351562500, 0.4246520996093750, 0.0000000000000000, 0.4506530761718750, +0.0000305175781250, 0.3981628417968750, 0.0001220703125000, 0.2196350097656250, +0.0000915527343750, 0.2942504882812500, -0.0000305175781250, 0.1739501953125000, +0.0000000000000000, 0.1506958007812500, 0.0000000000000000, 0.1691284179687500, +-0.0001220703125000, 0.1334838867187500, -0.0001220703125000, 0.1389770507812500, +-0.0000305175781250, 0.1570129394531250, -0.0000610351562500, 0.1614074707031250, +-0.0000610351562500, 0.1450805664062500, 0.0000610351562500, 0.1536865234375000, +0.0000000000000000, 0.1634521484375000, -0.0000305175781250, 0.0534057617187500, +0.0000610351562500, 0.1001892089843750, -0.0000305175781250, 0.0117492675781250, +-0.0001525878906250, -0.1180725097656250, -0.0000915527343750, -0.0320434570312500, +-0.0001220703125000, -0.2635803222656250, -0.0002136230468750, -0.2528686523437500, +-0.0001220703125000, -0.2724914550781250, -0.0000305175781250, -0.4216918945312500, +-0.0000915527343750, -0.3670959472656250, 0.0002136230468750, -0.3641662597656250, +0.0002441406250000, -0.4231262207031250, 0.0000610351562500, -0.3353576660156250, +0.0001220703125000, -0.2477111816406250, 0.0002441406250000, -0.3161315917968750, +-0.0004882812500000, -0.1352233886718750, -0.0004272460937500, -0.1350097656250000, +-0.0002746582031250, -0.1349182128906250, -0.0007324218750000, -0.0391540527343750, +-0.0007629394531250, -0.0661926269531250, 0.0008544921875000, -0.0688476562500000, +0.0008850097656250, -0.0611572265625000, -0.0006408691406250, -0.0499877929687500, +0.0015869140625000, -0.0642395019531250, 0.0016174316406250, -0.0708312988281250, +-0.0146484375000000, 0.0538330078125000, -0.0046081542968750, 0.0025024414062500, +-0.0246582031250000, 0.0769958496093750, -0.0505371093750000, 0.2253112792968750, +-0.0319824218750000, 0.1415710449218750, -0.0785217285156250, 0.2505493164062500, +-0.0848083496093750, 0.2936706542968750, -0.0669860839843750, 0.2296447753906250, +-0.0739440917968750, 0.1891174316406250, 0.1296691894531250, 0.1123352050781250, +0.2735900878906250, 0.2359619140625000, 0.2972717285156250, 0.2599487304687500, +0.2092590332031250, 0.1910400390625000, 0.1994628906250000, 0.1734619140625000, +0.2606201171875000, 0.2186889648437500, -0.0165405273437500, 0.0360412597656250, +0.0311889648437500, 0.0531921386718750, -0.0245666503906250, 0.0317687988281250, +-0.2474670410156250, -0.0921630859375000, -0.1540222167968750, -0.0492553710937500, +-0.1788024902343750, -0.0618896484375000, -0.2746276855468750, -0.0915832519531250, +-0.1338195800781250, -0.0600891113281250, -0.0028686523437500, -0.0275878906250000, +-0.1159973144531250, -0.0492858886718750, 0.1441345214843750, -0.0088195800781250, +0.1800231933593750, -0.0019836425781250, 0.0877685546875000, -0.0077514648437500, +0.1762695312500000, 0.0040588378906250, 0.2073974609375000, 0.0028076171875000, +-0.1308898925781250, -0.0004272460937500, -0.0194396972656250, -0.0001525878906250, +-0.1567077636718750, 0.0003356933593750, -0.4968872070312500, -0.0007629394531250, +-0.3207092285156250, -0.0009155273437500, -0.5058288574218750, 0.0000305175781250, +-0.6077880859375000, 0.0002746582031250, -0.4500732421875000, -0.0000610351562500, +-0.4114990234375000, -0.0000915527343750, -0.5037536621093750, 0.0000915527343750, +-0.1015319824218750, -0.0001220703125000, -0.1683654785156250, -0.0003051757812500, +-0.0827636718750000, -0.0001220703125000, 0.2221984863281250, 0.0000915527343750, +0.0833740234375000, -0.0000610351562500, 0.2283935546875000, -0.0001220703125000, +0.2940368652343750, 0.0000000000000000, 0.2145385742187500, -0.0000305175781250, +0.2067871093750000, -0.0001525878906250, 0.2510375976562500, -0.0001525878906250, +0.1177062988281250, 0.0000305175781250, 0.1247863769531250, 0.0000000000000000, +0.1294860839843750, -0.0000305175781250, 0.0515136718750000, 0.0001831054687500, +0.0729370117187500, 0.0001831054687500, 0.1216125488281250, -0.0001220703125000, +0.0713500976562500, -0.0000915527343750, 0.1474609375000000, -0.0000610351562500, +0.2345275878906250, -0.0002746582031250, 0.1615295410156250, -0.0002746582031250, +0.3753356933593750, -0.0000305175781250, 0.3368530273437500, 0.0000000000000000, +0.4011840820312500, -0.0000915527343750, 0.5679931640625000, -0.0000610351562500, +0.4786682128906250, 0.0000305175781250, 0.6627807617187500, -0.0001525878906250, +0.6630554199218750, -0.0002136230468750, 0.6695861816406250, -0.0000915527343750, +0.7725524902343750, -0.0000915527343750, 0.7329101562500000, -0.0001525878906250, +0.7465515136718750}, +{-0.0005798339843750, -0.3108825683593750, 0.0007629394531250, -0.3648681640625000, +0.0009460449218750, -0.4243164062500000, -0.0008239746093750, -0.3346252441406250, +0.0008239746093750, -0.2791442871093750, 0.0012512207031250, -0.3408813476562500, +-0.0143432617187500, -0.1370544433593750, -0.0048522949218750, -0.1429748535156250, +-0.0228271484375000, -0.1310424804687500, -0.0473632812500000, -0.0095520019531250, +-0.0300292968750000, -0.0460510253906250, -0.0688171386718750, -0.0469970703125000, +-0.0787048339843750, -0.0275268554687500, -0.0531005859375000, -0.0293579101562500, +-0.0636596679687500, -0.0567932128906250, -0.0745239257812500, -0.0539855957031250, +0.0472106933593750, 0.0350341796875000, 0.0094909667968750, -0.0060729980468750, +0.0549011230468750, 0.0425415039062500, 0.2493591308593750, 0.2209472656250000, +0.2226257324218750, -0.0434570312500000, -0.0920715332031250, 0.0476989746093750, +0.0332946777343750, -0.0287475585937500, -0.0459594726562500, 0.0578918457031250, +-0.2491760253906250, 0.1772155761718750, -0.1765136718750000, 0.1119689941406250, +-0.1326599121093750, 0.1967468261718750, -0.2265625000000000, 0.2427978515625000, +-0.1006469726562500, 0.1677551269531250, 0.0587463378906250, 0.1419677734375000, +-0.0548095703125000, 0.1878967285156250, 0.1592712402343750, 0.0194702148437500, +0.2184448242187500, 0.0302124023437500, 0.0982971191406250, 0.0194091796875000, +0.1278076171875000, -0.0850219726562500, 0.1889343261718750, -0.0520019531250000, +-0.1893005371093750, -0.0525817871093750, -0.0994262695312500, -0.0771484375000000, +-0.2052307128906250, -0.0512390136718750, -0.5395812988281250, -0.0191955566406250, +-0.3821105957031250, -0.0381469726562500, -0.4755249023437500, -0.0064392089843750, +-0.6070556640625000, 0.0000915527343750, -0.4131774902343750, -0.0053710937500000, +-0.2805175781250000, 0.0026855468750000, -0.4293518066406250, 0.0023803710937500, +-0.0100708007812500, -0.0005493164062500, -0.0466613769531250, -0.0007934570312500, +-0.0089721679687500, -0.0000305175781250, 0.2623596191406250, -0.0004577636718750, +0.1594543457031250, -0.0008544921875000, 0.2152709960937500, 0.0000305175781250, +0.2806091308593750, 0.0003356933593750, 0.2106628417968750, 0.0000610351562500, +0.1579589843750000, 0.0000000000000000, 0.2079467773437500, 0.0000915527343750, +0.1057128906250000, -0.0000610351562500, 0.0912780761718750, -0.0001525878906250, +0.1239013671875000, -0.0000305175781250, 0.0921020507812500, 0.0000915527343750, +0.0836791992187500, 0.0000305175781250, 0.1821899414062500, -0.0001831054687500, +0.1429138183593750, -0.0000915527343750, 0.2030334472656250, -0.0000305175781250, +0.3031921386718750, -0.0002136230468750, 0.2377014160156250, -0.0002136230468750, +0.4121704101562500, 0.0000000000000000, 0.3858337402343750, 0.0000000000000000, +0.4335021972656250, -0.0001220703125000, 0.5626525878906250, 0.0000000000000000, +0.4908447265625000, 0.0000305175781250, 0.6326293945312500, -0.0001525878906250, +0.6347351074218750, -0.0001831054687500, 0.6338195800781250, -0.0000610351562500, +0.7112426757812500, -0.0000915527343750, 0.6859741210937500, -0.0001525878906250, +0.6744995117187500, 0.0000610351562500, 0.7051696777343750, 0.0001220703125000, +0.6531982421875000, 0.0000000000000000, 0.6072082519531250, 0.0000000000000000, +0.6472473144531250, 0.0000610351562500, 0.4976501464843750, -0.0000305175781250, +0.5300598144531250, -0.0000915527343750, 0.4682617187500000, 0.0000610351562500, +0.3478698730468750, 0.0000610351562500, 0.4258422851562500, -0.0000305175781250, +0.2342834472656250, 0.0000610351562500, 0.2681884765625000, 0.0001525878906250, +0.2074890136718750, 0.0000305175781250, 0.0644226074218750, 0.0000000000000000, +0.1543579101562500, 0.0000305175781250, -0.0498046875000000, 0.0000610351562500, +-0.0177612304687500, 0.0000000000000000, -0.0734252929687500, 0.0000305175781250, +-0.2216491699218750, 0.0000915527343750, -0.1313781738281250, 0.0000915527343750, +-0.3152770996093750, 0.0000305175781250, -0.2975463867187500, 0.0000915527343750, +-0.3227844238281250, 0.0000610351562500, -0.4385375976562500, -0.0000305175781250, +-0.3763732910156250, 0.0000000000000000, -0.4769287109375000, 0.0000000000000000, +-0.4782104492187500, 0.0000610351562500, -0.4771118164062500, 0.0000610351562500, +-0.5298156738281250, 0.0000000000000000, -0.5107727050781250, 0.0000305175781250, +-0.5236206054687500, -0.0000305175781250, -0.5336303710937500, -0.0000305175781250, +-0.5214538574218750, 0.0000305175781250, -0.5184020996093750, -0.0000305175781250, +-0.5277404785156250, 0.0000000000000000, -0.4983215332031250, 0.0000305175781250, +-0.5080566406250000, 0.0000305175781250, -0.4951477050781250, 0.0000000000000000, +-0.4705200195312500, 0.0000305175781250, -0.4904785156250000, 0.0000610351562500, +-0.4471130371093750, 0.0000305175781250, -0.4572753906250000, 0.0000305175781250, +-0.4469299316406250, -0.0000305175781250, -0.4150390625000000, 0.0000000000000000, +-0.4376525878906250, 0.0000305175781250, -0.4032592773437500, 0.0000305175781250, +-0.4099426269531250, 0.0000000000000000, -0.4055175781250000, 0.0000000000000000, +-0.3834838867187500, 0.0000000000000000, -0.4017639160156250, 0.0000000000000000, +-0.3817749023437500, -0.0000610351562500, -0.3836364746093750, -0.0000305175781250, +-0.3861083984375000, 0.0000000000000000, -0.3776855468750000, -0.0000305175781250, +-0.3828125000000000, -0.0000305175781250, -0.3716430664062500, 0.0000000000000000, +-0.3740234375000000, 0.0000610351562500, -0.3623657226562500, 0.0000305175781250, +-0.3507385253906250, 0.0000610351562500, -0.3580932617187500, 0.0000610351562500, +-0.3125915527343750, 0.0000000000000000, -0.3250732421875000, 0.0000305175781250, +-0.2967224121093750, 0.0000610351562500, -0.2507629394531250, 0.0000610351562500, +-0.2764282226562500, 0.0000305175781250, -0.1992492675781250, 0.0000610351562500, +-0.2055358886718750, 0.0000610351562500, -0.1876220703125000, 0.0000305175781250, +-0.1327819824218750, 0.0000610351562500, -0.1558532714843750, 0.0000610351562500, +-0.1101684570312500, 0.0000305175781250, -0.1090087890625000, -0.0000305175781250, +-0.0961608886718750, 0.0000305175781250, -0.0700988769531250, 0.0000000000000000, +-0.0819702148437500, -0.0000305175781250, -0.0164794921875000, 0.0000915527343750, +-0.0387268066406250, 0.0000915527343750, 0.0201721191406250, 0.0000610351562500, +0.0946350097656250, 0.0000915527343750, 0.0495605468750000, 0.0000915527343750, +0.2416076660156250, -0.0000305175781250, 0.2158813476562500, 0.0000305175781250, +0.2807922363281250, 0.0000610351562500, 0.4392395019531250, 0.0000305175781250, +0.3680419921875000, 0.0000000000000000, 0.4974975585937500, 0.0000305175781250, +0.5352478027343750, 0.0000305175781250, 0.4835815429687500, -0.0000305175781250, +0.5119323730468750, -0.0000610351562500, 0.5302734375000000, -0.0000305175781250, +0.3385925292968750, -0.0001525878906250, 0.3936157226562500, -0.0001525878906250, +0.2852478027343750, -0.0000915527343750, 0.0853271484375000, -0.0001525878906250, +0.1892395019531250, -0.0001831054687500, -0.0310668945312500, -0.0000610351562500, +-0.0538940429687500, -0.0000610351562500, -0.0349121093750000, -0.0000915527343750, +-0.1270751953125000, -0.0000915527343750, -0.1098022460937500, -0.0000305175781250, +-0.0683288574218750, -0.0000610351562500, -0.0867309570312500, -0.0000915527343750, +-0.0727539062500000, -0.0001220703125000, -0.0257873535156250, -0.0000305175781250, +-0.0416564941406250, -0.0000305175781250, -0.0598144531250000, -0.0005798339843750, +-0.0377807617187500, -0.0004882812500000, -0.0651245117187500, -0.0002136230468750, +-0.1104431152343750, -0.0007019042968750, -0.0866699218750000, -0.0008544921875000, +-0.1103515625000000, 0.0007629394531250, -0.1286621093750000, 0.0012512207031250, +-0.1022338867187500, -0.0018615722656250, -0.0860900878906250, -0.0007934570312500, +-0.1033325195312500, 0.0010070800781250, -0.0571899414062500, -0.0179748535156250, +-0.0547180175781250, -0.0105895996093750, -0.0546569824218750, -0.0200805664062500, +-0.0376892089843750, -0.0440673828125000, -0.0424499511718750, -0.0314025878906250, +-0.0124816894531250, -0.0288696289062500, -0.0305175781250000, -0.0488281250000000, +0.0045776367187500, -0.0141601562500000, 0.0694274902343750, 0.0300292968750000, +0.0678710937500000, 0.0227050781250000, 0.1416931152343750, 0.0971069335937500, +0.1363220214843750, 0.0832214355468750, 0.1088867187500000, 0.0736694335937500, +0.1439208984375000, 0.1224975585937500, 0.1524047851562500, 0.1145019531250000, +0.0537109375000000, 0.0643310546875000, 0.0845336914062500, 0.0853576660156250, +0.0518493652343750, 0.0590209960937500, -0.0408935546875000, -0.0000915527343750, +0.0040283203125000, 0.0263366699218750, -0.0414123535156250, 0.0006408691406250, +-0.0643005371093750, -0.0127258300781250, -0.0384826660156250, -0.0052490234375000, +-0.0313720703125000, 0.0021057128906250, -0.0448913574218750, -0.0015869140625000, +-0.0099792480468750, -0.0347290039062500, -0.0075988769531250, -0.0136413574218750, +-0.0104675292968750, -0.0461730957031250, 0.0036621093750000, -0.1016235351562500, +0.0011291503906250, -0.0703430175781250, -0.0009460449218750, -0.1095886230468750, +0.0001525878906250, -0.1315612792968750, 0.0001525878906250, -0.0980224609375000, +-0.0014038085937500, -0.0840454101562500, -0.0014038085937500, -0.1065368652343750, +-0.0001525878906250, -0.0480346679687500, -0.0002441406250000, -0.0419921875000000, +-0.0003967285156250, -0.0556945800781250, 0.0001525878906250, -0.0370788574218750, +0.0002136230468750, -0.0329284667968750, -0.0002136230468750, -0.0610656738281250, +-0.0002441406250000, -0.0681152343750000, -0.0000610351562500, -0.0395507812500000, +-0.0000915527343750, -0.0449523925781250, -0.0001831054687500, -0.0603332519531250, +0.0000305175781250, 0.0742187500000000, 0.0001220703125000, 0.0301818847656250, +0.0000000000000000, 0.1061096191406250, -0.0000915527343750, 0.2490234375000000, +0.0000610351562500, 0.1718444824218750, -0.0000915527343750, 0.3338928222656250, +-0.0001831054687500, 0.3500366210937500, -0.0000610351562500, 0.3376770019531250, +0.0000610351562500, 0.4102783203125000, -0.0000610351562500, 0.3961181640625000, +0.0000000000000000, 0.3518676757812500, 0.0000915527343750, 0.3813781738281250, +-0.0000305175781250, 0.3280944824218750, -0.0001220703125000, 0.2565002441406250, +-0.0000305175781250, 0.2941284179687500, -0.0000915527343750, 0.1663513183593750, +-0.0001831054687500, 0.1713867187500000, -0.0000305175781250, 0.1346740722656250, +0.0000305175781250, 0.0450439453125000, -0.0000610351562500, 0.0809631347656250, +0.0000305175781250, -0.0210876464843750, 0.0000610351562500, -0.0188903808593750, +0.0000000000000000, -0.0461120605468750, 0.0000000000000000, -0.1149597167968750, +0.0000305175781250, -0.0856018066406250, -0.0000305175781250, -0.1666870117187500, +-0.0000915527343750, -0.1665344238281250, 0.0000000000000000, -0.1855773925781250, +0.0000610351562500, -0.2409667968750000, -0.0000305175781250, -0.2201232910156250, +0.0000305175781250, -0.2632446289062500, 0.0000610351562500, -0.2703552246093750, +0.0000610351562500, -0.2690429687500000, -0.0000610351562500, -0.2863769531250000, +0.0000305175781250, -0.2810974121093750, 0.0000000000000000, -0.2762451171875000, +-0.0000305175781250, -0.2801513671875000, 0.0000305175781250, -0.2651062011718750, +0.0000915527343750, -0.2492980957031250, 0.0000000000000000, -0.2545166015625000, +0.0000610351562500, -0.2243652343750000, 0.0000915527343750, -0.2183227539062500, +0.0000305175781250}, +{-0.0603637695312500, 0.0606689453125000, -0.0570678710937500, 0.0610046386718750, +-0.0403747558593750, 0.1234741210937500, -0.0387573242187500, 0.1129150390625000, +0.0286254882812500, 0.0632934570312500, -0.0102539062500000, 0.0929565429687500, +0.0227661132812500, 0.0717163085937500, 0.0971984863281250, 0.0140991210937500, +0.0457763671875000, 0.0413513183593750, 0.1307067871093750, 0.0025634765625000, +0.1504516601562500, -0.0105895996093750, 0.1108703613281250, -0.0009460449218750, +0.1275329589843750, -0.0007019042968750, 0.1464233398437500, -0.0051879882812500, +0.0373535156250000, -0.0262451171875000, 0.0596618652343750, -0.0065917968750000, +0.0369567871093750, -0.0407104492187500, -0.0514221191406250, -0.0883178710937500, +-0.0159301757812500, -0.0579223632812500, -0.0392456054687500, -0.1113891601562500, +-0.0606079101562500, -0.1285095214843750, -0.0375061035156250, -0.1009216308593750, +-0.0214233398437500, -0.1009521484375000, -0.0361938476562500, -0.1149597167968750, +-0.0067138671875000, -0.0612792968750000, -0.0031127929687500, -0.0590820312500000, +-0.0070190429687500, -0.0682678222656250, 0.0028991699218750, -0.0478820800781250, +0.0017089843750000, -0.0457763671875000, -0.0007629394531250, -0.0618896484375000, +-0.0003662109375000, -0.0708923339843750, -0.0000305175781250, -0.0377807617187500, +-0.0010375976562500, -0.0332946777343750, -0.0012207031250000, -0.0540466308593750, +-0.0000915527343750, 0.0910034179687500, -0.0000305175781250, 0.0503845214843750, +-0.0003051757812500, 0.1168518066406250, 0.0000305175781250, 0.2573242187500000, +0.0001525878906250, 0.1818847656250000, -0.0001831054687500, 0.3161926269531250, +-0.0002441406250000, 0.3392944335937500, -0.0000915527343750, 0.3106384277343750, +-0.0000610351562500, 0.3538208007812500, -0.0001525878906250, 0.3550415039062500, +-0.0000305175781250, 0.2843933105468750, 0.0000305175781250, 0.3102722167968750, +-0.0000305175781250, 0.2601318359375000, -0.0001525878906250, 0.1817016601562500, +-0.0000610351562500, 0.2274780273437500, -0.0001525878906250, 0.1068115234375000, +-0.0002441406250000, 0.1127929687500000, -0.0001525878906250, 0.0799255371093750, +0.0000305175781250, -0.0038452148437500, -0.0000915527343750, 0.0329589843750000, +-0.0000915527343750, -0.0661010742187500, 0.0000000000000000, -0.0656127929687500, +-0.0000915527343750, -0.0878906250000000, -0.0001831054687500, -0.1544799804687500, +-0.0000915527343750, -0.1278076171875000, -0.0000610351562500, -0.1786804199218750, +-0.0001831054687500, -0.1873779296875000, -0.0000915527343750, -0.1784057617187500, +0.0000305175781250, -0.1965332031250000, -0.0000610351562500, -0.1948547363281250, +-0.0000610351562500, -0.1659851074218750, 0.0000000000000000, -0.1768798828125000, +-0.0000305175781250, -0.1524353027343750, -0.0000915527343750, -0.1155395507812500, +-0.0000610351562500, -0.1303100585937500, -0.0000915527343750, -0.0678710937500000, +-0.0000915527343750, -0.0670776367187500, -0.0000305175781250, -0.0557556152343750, +-0.0000305175781250, -0.0147399902343750, -0.0000305175781250, -0.0249633789062500, +-0.0000305175781250, -0.0041198730468750, 0.0000000000000000, 0.0035400390625000, +-0.0000610351562500, -0.0034790039062500, -0.0000305175781250, 0.0004272460937500, +-0.0000305175781250, 0.0052185058593750, -0.0000305175781250, -0.0151672363281250, +-0.0000610351562500, -0.0097351074218750, -0.0000610351562500, -0.0226440429687500, +-0.0000305175781250, -0.0453491210937500, -0.0000305175781250, -0.0367736816406250, +-0.0000610351562500, -0.0687561035156250, -0.0000305175781250, -0.0691833496093750, +-0.0000305175781250, -0.0789184570312500, -0.0000610351562500, -0.1008300781250000, +-0.0000610351562500, -0.0932617187500000, -0.0000610351562500, -0.1209411621093750, +-0.0000610351562500, -0.1241149902343750, -0.0000305175781250, -0.1290588378906250, +-0.0000305175781250, -0.1446838378906250, -0.0000610351562500, -0.1427612304687500, +0.0000000000000000, -0.1587829589843750, -0.0000305175781250, -0.1578369140625000, +-0.0000305175781250, -0.1651000976562500, -0.0000305175781250, -0.1777648925781250, +-0.0000305175781250, -0.1710815429687500, 0.0000000000000000, -0.1881713867187500, +0.0000000000000000, -0.1882629394531250, 0.0000000000000000, -0.1938171386718750, +0.0000000000000000, -0.2069702148437500, 0.0000000000000000, -0.2039794921875000, +-0.0000305175781250, -0.2175903320312500, 0.0000305175781250, -0.2176818847656250, +-0.0000305175781250, -0.2265014648437500, 0.0000000000000000, -0.2385559082031250, +0.0000000000000000, -0.2338562011718750, -0.0000915527343750, -0.2576293945312500, +-0.0000915527343750, -0.2524108886718750, -0.0000305175781250, -0.2656860351562500, +-0.0000915527343750, -0.2885131835937500, -0.0000610351562500, -0.2783813476562500, +-0.0000305175781250, -0.3191223144531250, -0.0000610351562500, -0.3118591308593750, +-0.0000305175781250, -0.3230590820312500, -0.0000305175781250, -0.3559570312500000, +-0.0000305175781250, -0.3399658203125000, -0.0000915527343750, -0.3631591796875000, +-0.0001220703125000, -0.3739013671875000, -0.0000915527343750, -0.3549499511718750, +-0.0000610351562500, -0.3566284179687500, -0.0000915527343750, -0.3683166503906250, +-0.0000305175781250, -0.2950744628906250, 0.0000305175781250, -0.3241882324218750, +-0.0000305175781250, -0.2683715820312500, -0.0000610351562500, -0.1877136230468750, +-0.0000305175781250, -0.2430419921875000, -0.0000610351562500, -0.0823669433593750, +-0.0001525878906250, -0.1079406738281250, -0.0000915527343750, -0.0522460937500000, +0.0000000000000000, 0.0711059570312500, -0.0000610351562500, 0.0015869140625000, +0.0000305175781250, 0.1760864257812500, 0.0000610351562500, 0.1555480957031250, +0.0000305175781250, 0.2110595703125000, -0.0000610351562500, 0.3431396484375000, +0.0000305175781250, 0.2767333984375000, -0.0000915527343750, 0.4466857910156250, +-0.0001220703125000, 0.4412536621093750, -0.0000610351562500, 0.4703979492187500, +-0.0000610351562500, 0.5823974609375000, -0.0000915527343750, 0.5355224609375000, +0.0000915527343750, 0.5959472656250000, 0.0000915527343750, 0.6173706054687500, +0.0000610351562500, 0.5903320312500000, 0.0001831054687500, 0.5982971191406250, +0.0001831054687500, 0.6102600097656250, -0.0001831054687500, 0.5385131835937500, +-0.0000915527343750, 0.5610351562500000, -0.0000610351562500, 0.5170288085937500, +-0.0003967285156250, 0.4487609863281250, -0.0003662109375000, 0.4931640625000000, +0.0005187988281250, 0.3550109863281250, 0.0006103515625000, 0.3804016113281250, +-0.0007629394531250, 0.3309631347656250, 0.0005187988281250, 0.2160339355468750, +0.0008850097656250, 0.2766723632812500, -0.0118103027343750, 0.1479187011718750, +-0.0042724609375000, 0.1417846679687500, -0.0186767578125000, 0.1415710449218750, +-0.0385437011718750, 0.0809936523437500, -0.0241394042968750, 0.1002807617187500, +-0.0523986816406250, 0.0739135742187500, -0.0619506835937500, 0.0835571289062500, +-0.0382385253906250, 0.0457763671875000, -0.0428161621093750, 0.0177612304687500, +-0.0552673339843750, 0.0503845214843750, 0.0478820800781250, -0.1168823242187500, +0.0130920410156250, -0.0768432617187500, 0.0668029785156250, -0.1484375000000000, +0.1809692382812500, -0.3118591308593750, 0.1198120117187500, -0.2284851074218750, +0.1936645507812500, -0.3299560546875000, 0.2398376464843750, -0.3833923339843750, +0.1556396484375000, -0.2956237792968750, 0.1265258789062500, -0.2704772949218750, +0.1790466308593750, -0.3250427246093750, -0.0526428222656250, -0.1226806640625000, +-0.0312194824218750, -0.1373901367187500, -0.0366516113281250, -0.1355285644531250, +-0.2461547851562500, 0.0400390625000000, 0.0039062500000000, -0.2932739257812500, +0.1537780761718750, -0.0610961914062500, 0.2085266113281250, -0.1352539062500000, +0.0702819824218750, -0.0910644531250000, 0.0177307128906250, 0.0338439941406250, +0.1182861328125000, -0.0017395019531250, -0.2425537109375000, -0.0117797851562500, +-0.2084350585937500, 0.0092468261718750, -0.2385864257812500, 0.0050354003906250, +-0.4871215820312500, -0.0282592773437500, -0.4005737304687500, -0.0231933593750000, +-0.3400878906250000, 0.0533447265625000, -0.4581909179687500, 0.0166625976562500, +-0.2872924804687500, 0.0615844726562500, -0.0836791992187500, 0.1614074707031250, +-0.2298278808593750, 0.1115722656250000, 0.1080322265625000, 0.1468505859375000, +0.1210632324218750, 0.1906738281250000, 0.1000976562500000, 0.1253356933593750, +0.2607727050781250, 0.0773315429687500, 0.2251586914062500, 0.1234436035156250, +0.1763610839843750, -0.0053710937500000, 0.2153625488281250, -0.0080871582031250, +0.1872863769531250, -0.0042419433593750, 0.1163940429687500, -0.0697021484375000, +0.1482543945312500, -0.0548095703125000, 0.1411132812500000, -0.0360107421875000, +0.1137695312500000, -0.0505371093750000, 0.1495971679687500, -0.0350341796875000, +0.1818847656250000, -0.0059204101562500, 0.1551208496093750, -0.0194702148437500, +0.2324523925781250, -0.0026245117187500, 0.2192687988281250, 0.0028991699218750, +0.2503051757812500, -0.0013122558593750, 0.3050231933593750, 0.0005798339843750, +0.2706909179687500, 0.0012207031250000, 0.4072570800781250, -0.0003051757812500, +0.3674316406250000, -0.0008850097656250, 0.4372863769531250, -0.0002746582031250, +0.5701599121093750, 0.0000000000000000, 0.4858703613281250, -0.0002441406250000, +0.6530151367187500, 0.0000000000000000, 0.6670532226562500, 0.0002136230468750, +0.6310119628906250, 0.0000610351562500, 0.7058410644531250, -0.0000610351562500, +0.7026367187500000, -0.0000610351562500, 0.5528564453125000, 0.0000610351562500, +0.6349487304687500, 0.0000610351562500, 0.5113830566406250, 0.0000000000000000, +0.3264770507812500, 0.0000610351562500, 0.4577636718750000, 0.0001220703125000, +0.1369323730468750, -0.0000305175781250, 0.1669311523437500, -0.0000610351562500, +0.1141052246093750, 0.0000305175781250, -0.0982971191406250, 0.0000915527343750, +-0.0013122558593750, 0.0000000000000000, -0.1686096191406250, 0.0000305175781250, +-0.1759643554687500, 0.0000915527343750, -0.1829833984375000, 0.0000000000000000, +-0.2682800292968750, -0.0000915527343750, -0.2325439453125000, -0.0000305175781250, +-0.2824707031250000, -0.0000610351562500, -0.2871093750000000, -0.0000915527343750, +-0.2875061035156250, -0.0000305175781250, -0.3121032714843750, 0.0000305175781250, +-0.3025512695312500, 0.0000305175781250, -0.3114013671875000, -0.0000305175781250, +-0.3173828125000000, 0.0000000000000000, -0.3142089843750000, -0.0000610351562500, +-0.3144531250000000, -0.0000915527343750, -0.3181762695312500, -0.0000915527343750, +-0.3121948242187500, -0.0000305175781250, -0.3122558593750000, -0.0000610351562500, +-0.3116149902343750, -0.0000305175781250, -0.3067932128906250, 0.0000610351562500, +-0.3059997558593750, 0.0000610351562500, -0.3039855957031250, -0.0000305175781250, +-0.3025817871093750, -0.0000305175781250, -0.2998962402343750, 0.0000000000000000, +-0.2963562011718750, 0.0000000000000000, -0.2941589355468750, 0.0000000000000000, +-0.2900695800781250, 0.0000610351562500, -0.2878417968750000, 0.0001220703125000, +-0.2817687988281250, 0.0000610351562500, -0.2777099609375000, 0.0000305175781250, +-0.2781677246093750, 0.0000305175781250, -0.2630004882812500, 0.0000000000000000, +-0.2662963867187500, 0.0000000000000000, -0.2539978027343750, 0.0000305175781250, +-0.2375183105468750, 0.0000305175781250, -0.2452392578125000, 0.0000305175781250, +-0.2116088867187500, 0.0000305175781250, -0.2178955078125000, 0.0000305175781250, +-0.2012939453125000, 0.0000305175781250, -0.1720275878906250, 0.0000305175781250, +-0.1882019042968750}, +{0.2118225097656250, -0.0136718750000000, 0.1962280273437500, -0.0140380859375000, +0.1408691406250000, 0.0647888183593750, 0.1605834960937500, 0.0368957519531250, +0.1566772460937500, 0.0690917968750000, 0.1090087890625000, 0.1566772460937500, +0.1226501464843750, 0.1175842285156250, 0.1613159179687500, 0.1268005371093750, +0.1355285644531250, 0.1672058105468750, 0.1660461425781250, 0.1080017089843750, +0.2200012207031250, 0.0505065917968750, 0.1897888183593750, 0.0946655273437500, +0.2463073730468750, -0.0148010253906250, 0.2379455566406250, -0.0236816406250000, +0.2675781250000000, -0.0135192871093750, 0.3056030273437500, -0.0597229003906250, +0.2740173339843750, -0.0526428222656250, 0.4207458496093750, -0.0270996093750000, +0.3740234375000000, -0.0372314453125000, 0.4507751464843750, -0.0272827148437500, +0.6018066406250000, -0.0013732910156250, 0.5105590820312500, -0.0117492675781250, +0.6709594726562500, -0.0015258789062500, 0.7063293457031250, 0.0028686523437500, +0.6325378417968750, -0.0001525878906250, 0.6725158691406250, 0.0001525878906250, +0.7025146484375000, 0.0006408691406250, 0.4535217285156250, -0.0000305175781250, +0.5443420410156250, -0.0005493164062500, 0.4093627929687500, -0.0001220703125000, +0.1555786132812500, 0.0003356933593750, 0.3118896484375000, 0.0001220703125000, +-0.0139160156250000, 0.0001220703125000, -0.0099182128906250, 0.0002746582031250, +-0.0221862792968750, 0.0001831054687500, -0.2009277343750000, 0.0000305175781250, +-0.1327209472656250, 0.0000305175781250, -0.1970214843750000, 0.0000305175781250, +-0.2190246582031250, 0.0000915527343750, -0.2084350585937500, 0.0000000000000000, +-0.2209472656250000, -0.0000305175781250, -0.2208251953125000, 0.0000000000000000, +-0.2389526367187500, -0.0000305175781250, -0.2253112792968750, -0.0001220703125000, +-0.2509155273437500, -0.0000305175781250, -0.2798156738281250, 0.0000915527343750, +-0.2557373046875000, 0.0000305175781250, -0.3327636718750000, 0.0000305175781250, +-0.3203735351562500, 0.0000915527343750, -0.3408203125000000, 0.0000000000000000, +-0.3985595703125000, -0.0000915527343750, -0.3667602539062500, 0.0000000000000000, +-0.4176025390625000, 0.0000610351562500, -0.4205017089843750, 0.0000000000000000, +-0.4105834960937500, 0.0000000000000000, -0.4321289062500000, 0.0000610351562500, +-0.4277954101562500, 0.0000610351562500, -0.4018859863281250, -0.0000610351562500, +-0.4188537597656250, -0.0000305175781250, -0.3907165527343750, -0.0000610351562500, +-0.3562622070312500, -0.0001220703125000, -0.3843994140625000, -0.0000915527343750, +-0.3037719726562500, -0.0000610351562500, -0.3224182128906250, -0.0000610351562500, +-0.2960815429687500, -0.0000915527343750, -0.2349548339843750, -0.0000915527343750, +-0.2761840820312500, -0.0000610351562500, -0.1838989257812500, -0.0001220703125000, +-0.2023620605468750, -0.0001220703125000, -0.1808471679687500, -0.0000915527343750, +-0.1141662597656250, -0.0000610351562500, -0.1560363769531250, -0.0000915527343750, +-0.0773925781250000, -0.0000305175781250, -0.0887451171875000, 0.0000000000000000, +-0.0746154785156250, -0.0000305175781250, -0.0236206054687500, -0.0000915527343750, +-0.0592956542968750, -0.0000305175781250, -0.0043029785156250, -0.0000610351562500, +-0.0125427246093750, -0.0000915527343750, -0.0080871582031250, -0.0000610351562500, +0.0251159667968750, -0.0000610351562500, 0.0027160644531250, -0.0000610351562500, +0.0329895019531250, -0.0000915527343750, 0.0284729003906250, -0.0000610351562500, +0.0291137695312500, -0.0000610351562500, 0.0463867187500000, -0.0001220703125000, +0.0343017578125000, -0.0000610351562500, 0.0484313964843750, -0.0000915527343750, +0.0449523925781250, -0.0000915527343750, 0.0463256835937500, -0.0001220703125000, +0.0550231933593750, -0.0001220703125000, 0.0464172363281250, -0.0001525878906250, +0.0575256347656250, -0.0001220703125000, 0.0561523437500000, -0.0000915527343750, +0.0553283691406250, -0.0000610351562500, 0.0609741210937500, -0.0000610351562500, +0.0577697753906250, -0.0000610351562500, 0.0620422363281250, -0.0000915527343750, +0.0597534179687500, -0.0000915527343750, 0.0635070800781250, -0.0000610351562500, +0.0668640136718750, -0.0000610351562500, 0.0625305175781250, -0.0000915527343750, +0.0853881835937500, -0.0000610351562500, 0.0772705078125000, -0.0000305175781250, +0.0928344726562500, -0.0000305175781250, 0.1176452636718750, -0.0000305175781250, +0.1037292480468750, -0.0000305175781250, 0.1499938964843750, 0.0000000000000000, +0.1476135253906250, 0.0000000000000000, 0.1603088378906250, -0.0000610351562500, +0.1957702636718750, -0.0000915527343750, 0.1819763183593750, -0.0000305175781250, +0.2008666992187500, -0.0000610351562500, 0.2115173339843750, -0.0000915527343750, +0.1894836425781250, -0.0000915527343750, 0.1824340820312500, -0.0000610351562500, +0.1915283203125000, -0.0000915527343750, 0.1213073730468750, -0.0000915527343750, +0.1347045898437500, -0.0001220703125000, 0.0965881347656250, -0.0000915527343750, +0.0281982421875000, -0.0001525878906250, 0.0592041015625000, -0.0001525878906250, +-0.0258789062500000, -0.0001220703125000, -0.0330810546875000, -0.0000915527343750, +-0.0324401855468750, -0.0000915527343750, -0.0733642578125000, -0.0001220703125000, +-0.0647277832031250, -0.0000610351562500, -0.0595397949218750, -0.0001220703125000, +-0.0713195800781250, -0.0001220703125000, -0.0586547851562500, -0.0000915527343750, +-0.0414428710937500, -0.0000610351562500, -0.0530700683593750, -0.0001525878906250, +-0.0297851562500000, -0.0002136230468750, -0.0315551757812500, -0.0000915527343750, +-0.0227355957031250, -0.0001831054687500, -0.0122070312500000, -0.0005187988281250, +-0.0216674804687500, -0.0003967285156250, 0.0413818359375000, 0.0000305175781250, +0.0115356445312500, -0.0003051757812500, 0.0735168457031250, -0.0001220703125000, +0.1561279296875000, 0.0013427734375000, 0.1024475097656250, 0.0006103515625000, +0.2796325683593750, -0.0042419433593750, 0.2715454101562500, 0.0007629394531250, +0.2845153808593750, -0.0086975097656250, 0.4034118652343750, -0.0194396972656250, +0.3645935058593750, -0.0101013183593750, 0.3181152343750000, -0.0311584472656250, +0.3832702636718750, -0.0363464355468750, 0.2771911621093750, -0.0204467773437500, +0.1506042480468750, -0.0252075195312500, 0.2355651855468750, -0.0337524414062500, +0.0089416503906250, 0.0332336425781250, 0.0066528320312500, 0.0133972167968750, +0.0076904296875000, 0.0353393554687500, -0.1124267578125000, 0.0996398925781250, +-0.0805969238281250, 0.0671081542968750, -0.0675659179687500, 0.0837402343750000, +-0.0889892578125000, 0.1117858886718750, -0.0744018554687500, 0.0733337402343750, +-0.0403442382812500, 0.0406188964843750, -0.0523376464843750, 0.0704040527343750, +-0.0683898925781250, 0.0064392089843750, -0.0518493652343750, -0.0002136230468750, +-0.0663146972656250, 0.0078430175781250, -0.1066589355468750, -0.0120544433593750, +-0.1015625000000000, -0.0105590820312500, -0.0849304199218750, -0.0212707519531250, +-0.1003417968750000, -0.0078430175781250, -0.0890502929687500, -0.0293884277343750, +-0.0649719238281250, -0.0541076660156250, -0.0801086425781250, -0.0334777832031250, +-0.0572814941406250, -0.0984191894531250, -0.0572204589843750, -0.1036376953125000, +-0.0457763671875000, -0.0908508300781250, -0.0363464355468750, -0.1171569824218750, +-0.0482177734375000, -0.1185302734375000, 0.0260620117187500, -0.0721130371093750, +-0.0001525878906250, -0.0812072753906250, 0.0357360839843750, -0.0747985839843750, +0.1181640625000000, -0.0384826660156250, 0.0743713378906250, -0.0475769042968750, +0.1187744140625000, -0.0502014160156250, 0.1502990722656250, -0.0504455566406250, +0.1014099121093750, -0.0319213867187500, 0.0788269042968750, -0.0334167480468750, +0.1125183105468750, -0.0449218750000000, 0.0079345703125000, 0.0632934570312500, +0.0130615234375000, 0.0274353027343750, 0.0100402832031250, 0.0859069824218750, +-0.0516967773437500, 0.2008972167968750, -0.0335693359375000, 0.1374511718750000, +-0.0300903320312500, 0.2487182617187500, -0.0446777343750000, 0.2668151855468750, +-0.0297851562500000, 0.2431335449218750, -0.0090332031250000, 0.2800292968750000, +-0.0206298828125000, 0.2806701660156250, -0.0030822753906250, 0.2212219238281250, +0.0009460449218750, 0.2435913085937500, -0.0026245117187500, 0.2076110839843750, +0.0011291503906250, 0.1471862792968750, 0.0013122558593750, 0.1826782226562500, +-0.0005493164062500, 0.0822143554687500, -0.0007324218750000, 0.0928955078125000, +-0.0002136230468750, 0.0657043457031250, -0.0003967285156250, -0.0097656250000000, +-0.0007324218750000, 0.0261230468750000, -0.0000305175781250, -0.0380859375000000, +0.0000915527343750, -0.0497436523437500, -0.0000610351562500, -0.0340270996093750, +-0.0000610351562500, -0.0550842285156250, 0.0000305175781250, -0.0568847656250000, +-0.0000610351562500, -0.0080261230468750, -0.0001220703125000, -0.0224304199218750, +-0.0000305175781250, 0.0092163085937500, 0.0001220703125000, 0.0643615722656250, +-0.0000305175781250, 0.0397033691406250, -0.0000305175781250, 0.1037292480468750, +0.0000915527343750, 0.1130065917968750, 0.0000305175781250, 0.1100158691406250, +-0.0000610351562500, 0.1377563476562500, 0.0000000000000000, 0.1337890625000000, +0.0000000000000000, 0.1172485351562500, -0.0000915527343750, 0.1274414062500000, +-0.0000610351562500, 0.1090393066406250, 0.0000305175781250, 0.0824584960937500, +0.0000305175781250, 0.0967712402343750, -0.0000305175781250, 0.0623168945312500, +0.0000305175781250, 0.0603027343750000, -0.0000305175781250, 0.0609741210937500, +-0.0000610351562500, 0.0437622070312500, -0.0000610351562500, 0.0484619140625000, +0.0000000000000000, 0.0541687011718750, -0.0000305175781250, 0.0495300292968750, +-0.0000610351562500, 0.0591735839843750, -0.0000305175781250, 0.0718383789062500, +0.0000000000000000, 0.0680236816406250, -0.0000610351562500, 0.0887451171875000, +-0.0000610351562500, 0.0903625488281250, -0.0000610351562500, 0.0955505371093750, +-0.0001525878906250, 0.1107788085937500, -0.0000915527343750, 0.1090393066406250, +-0.0000610351562500, 0.1139221191406250, -0.0000610351562500, 0.1198120117187500, +-0.0000610351562500, 0.1173095703125000, 0.0000000000000000, 0.1151428222656250, +0.0000000000000000, 0.1176757812500000, -0.0000610351562500, 0.1060180664062500, +0.0000000000000000, 0.1091918945312500, -0.0000610351562500, 0.1035766601562500, +-0.0000610351562500, 0.0923461914062500, -0.0000915527343750, 0.0976562500000000, +-0.0000610351562500, 0.0821228027343750, -0.0000610351562500, 0.0827026367187500, +-0.0000915527343750, 0.0780639648437500, -0.0000915527343750, 0.0676879882812500, +-0.0000915527343750, 0.0731811523437500, -0.0001525878906250, 0.0596618652343750, +-0.0001220703125000, 0.0615844726562500, -0.0000610351562500, 0.0566406250000000, +-0.0000915527343750, 0.0466613769531250, -0.0001220703125000, 0.0534057617187500, +-0.0000610351562500, 0.0382080078125000, -0.0000610351562500, 0.0412597656250000, +-0.0000610351562500, 0.0370788574218750, -0.0000610351562500, 0.0263061523437500, +-0.0000915527343750, 0.0321655273437500, -0.0000610351562500, 0.0108032226562500, +-0.0000915527343750, 0.0161743164062500, -0.0000610351562500, 0.0032348632812500, +0.0000610351562500, -0.0150451660156250, 0.0000000000000000, -0.0018005371093750, +-0.0000305175781250, -0.0494079589843750, -0.0000305175781250, -0.0325317382812500, +0.0000000000000000, -0.0585632324218750, 0.0000000000000000, -0.1021118164062500, +-0.0000305175781250, -0.0697326660156250, 0.0000000000000000, -0.1598205566406250, +0.0000305175781250}, +{-0.0241088867187500, 0.1052856445312500, -0.0354003906250000, 0.1170043945312500, +-0.0246582031250000, 0.0935058593750000, -0.0049438476562500, 0.0232849121093750, +-0.0148620605468750, 0.0571594238281250, -0.0021057128906250, 0.0099487304687500, +0.0014343261718750, -0.0071411132812500, -0.0016784667968750, 0.0197143554687500, +0.0005493164062500, 0.0182495117187500, 0.0009765625000000, 0.0055236816406250, +-0.0004882812500000, 0.0735778808593750, -0.0007934570312500, 0.0628662109375000, +-0.0003051757812500, 0.0848999023437500, -0.0002746582031250, 0.1426696777343750, +-0.0005493164062500, 0.1171569824218750, -0.0000915527343750, 0.1470642089843750, +0.0000610351562500, 0.1622009277343750, -0.0000915527343750, 0.1417846679687500, +-0.0001220703125000, 0.1351318359375000, -0.0000610351562500, 0.1439819335937500, +-0.0000610351562500, 0.1023254394531250, -0.0000915527343750, 0.1021728515625000, +-0.0000915527343750, 0.0958862304687500, 0.0000610351562500, 0.0688171386718750, +0.0000000000000000, 0.0771179199218750, -0.0000305175781250, 0.0768127441406250, +0.0000305175781250, 0.0679016113281250, 0.0000305175781250, 0.0797424316406250, +-0.0000610351562500, 0.0924377441406250, -0.0000305175781250, 0.0837402343750000, +0.0000000000000000, 0.1064758300781250, -0.0000305175781250, 0.1086730957031250, +0.0000000000000000, 0.1072082519531250, 0.0000305175781250, 0.1184082031250000, +0.0000000000000000, 0.1157226562500000, -0.0000610351562500, 0.1006774902343750, +0.0000000000000000, 0.1076965332031250, 0.0000000000000000, 0.0928344726562500, +-0.0000915527343750, 0.0710449218750000, -0.0000610351562500, 0.0792236328125000, +0.0000000000000000, 0.0426025390625000, -0.0000610351562500, 0.0424499511718750, +-0.0000610351562500, 0.0279235839843750, 0.0000000000000000, -0.0018310546875000, +0.0000000000000000, 0.0065307617187500, -0.0000610351562500, -0.0233764648437500, +-0.0000305175781250, -0.0295715332031250, -0.0000610351562500, -0.0317993164062500, +-0.0001220703125000, -0.0461120605468750, -0.0001220703125000, -0.0462341308593750, +-0.0000610351562500, -0.0495605468750000, -0.0001220703125000, -0.0544128417968750, +-0.0001220703125000, -0.0548095703125000, -0.0001220703125000, -0.0542297363281250, +-0.0000915527343750, -0.0568847656250000, -0.0001220703125000, -0.0551757812500000, +-0.0001220703125000, -0.0570373535156250, -0.0000610351562500, -0.0592041015625000, +-0.0001220703125000, -0.0581359863281250, -0.0001220703125000, -0.0582885742187500, +-0.0000915527343750, -0.0612487792968750, -0.0000915527343750, -0.0590820312500000, +-0.0000610351562500, -0.0628356933593750, -0.0000610351562500, -0.0673217773437500, +-0.0000305175781250, -0.0640563964843750, -0.0000305175781250, -0.0756225585937500, +-0.0000305175781250, -0.0747375488281250, -0.0000305175781250, -0.0774230957031250, +-0.0000305175781250, -0.0852661132812500, -0.0000305175781250, -0.0810241699218750, +0.0000000000000000, -0.0869445800781250, 0.0000610351562500, -0.0906372070312500, +0.0000000000000000, -0.0874938964843750, -0.0000305175781250, -0.0880432128906250, +0.0000000000000000, -0.0905151367187500, 0.0000000000000000, -0.0763549804687500, +-0.0000305175781250, -0.0836181640625000, 0.0000000000000000, -0.0747070312500000, +0.0000610351562500, -0.0592346191406250, 0.0000305175781250, -0.0705261230468750, +0.0000915527343750, -0.0436706542968750, 0.0000305175781250, -0.0460205078125000, +0.0000610351562500, -0.0494995117187500, 0.0000305175781250, -0.0332336425781250, +0.0000305175781250, -0.0370788574218750, 0.0001220703125000, -0.0546875000000000, +0.0001220703125000, -0.0361328125000000, 0.0001220703125000, -0.0671997070312500, +0.0001525878906250, -0.0989379882812500, 0.0001525878906250, -0.0697631835937500, +0.0001220703125000, -0.1678771972656250, 0.0001831054687500, -0.1428833007812500, +0.0001220703125000, -0.1870727539062500, 0.0000610351562500, -0.2765502929687500, +0.0001220703125000, -0.2247314453125000, 0.0000915527343750, -0.3427124023437500, +0.0000610351562500, -0.3390502929687500, 0.0000915527343750, -0.3481140136718750, +0.0001831054687500, -0.4196166992187500, 0.0001525878906250, -0.3893737792968750, +0.0000915527343750, -0.4016723632812500, 0.0001831054687500, -0.4269714355468750, +0.0000610351562500, -0.3870544433593750, -0.0002136230468750, -0.3589172363281250, +-0.0000610351562500, -0.3862609863281250, 0.0001525878906250, -0.2825317382812500, +0.0000000000000000, -0.2941894531250000, -0.0001525878906250, -0.2705078125000000, +0.0007934570312500, -0.1939697265625000, 0.0005187988281250, -0.2289428710937500, +-0.0046081542968750, -0.1925048828125000, -0.0001525878906250, -0.1823425292968750, +-0.0088500976562500, -0.1885986328125000, -0.0189208984375000, -0.1914672851562500, +-0.0110168457031250, -0.1928405761718750, -0.0330505371093750, -0.1350708007812500, +-0.0368957519531250, -0.1833801269531250, -0.0245361328125000, -0.0851135253906250, +-0.0333862304687500, 0.0185241699218750, -0.0382385253906250, -0.0673217773437500, +0.0267944335937500, 0.2223815917968750, 0.0025634765625000, 0.1786804199218750, +0.0400085449218750, 0.2517700195312500, 0.1159667968750000, 0.4779663085937500, +0.0748901367187500, 0.3754272460937500, 0.1268005371093750, 0.5231323242187500, +0.1592407226562500, 0.5637512207031250, 0.1007385253906250, 0.5187072753906250, +0.0804443359375000, 0.5458984375000000, 0.1196899414062500, 0.5578002929687500, +-0.0356750488281250, 0.4752502441406250, -0.0218811035156250, 0.4927062988281250, +-0.0296630859375000, 0.4655151367187500, -0.1366271972656250, 0.4005126953125000, +-0.1047973632812500, 0.4323120117187500, -0.0500183105468750, 0.3558044433593750, +-0.1061096191406250, 0.3677978515625000, -0.0330810546875000, 0.3298339843750000, +0.0859680175781250, 0.2677917480468750, 0.0160217285156250, 0.3080139160156250, +0.0896606445312500, 0.1765136718750000, 0.1525573730468750, 0.1936950683593750, +0.0406799316406250, 0.1615295410156250, -0.0169067382812500, 0.0634765625000000, +0.0597229003906250, 0.1101989746093750, -0.2232360839843750, 0.0382080078125000, +-0.2106018066406250, 0.0317993164062500, -0.1996765136718750, 0.0279846191406250, +-0.4184875488281250, -0.0307617187500000, -0.1030273437500000, 0.1120605468750000, +0.1310729980468750, 0.0146179199218750, 0.1035461425781250, 0.0373229980468750, +0.0939941406250000, 0.0086364746093750, 0.1488647460937500, -0.0256042480468750, +0.1511535644531250, -0.0042724609375000, 0.1187438964843750, -0.1103515625000000, +0.1132507324218750, -0.0816040039062500, 0.1348876953125000, -0.1268005371093750, +0.1313781738281250, -0.2378234863281250, 0.1167907714843750, -0.1826477050781250, +0.1878662109375000, -0.2218933105468750, 0.1793823242187500, -0.2705688476562500, +0.1853332519531250, -0.1955566406250000, 0.2313842773437500, -0.1417541503906250, +0.2180480957031250, -0.1957702636718750, 0.2300109863281250, -0.0458984375000000, +0.2204284667968750, -0.0397949218750000, 0.2609863281250000, -0.0486145019531250, +0.2786865234375000, 0.0198364257812500, 0.2444458007812500, 0.0072326660156250, +0.4303894042968750, -0.0078125000000000, 0.3760986328125000, -0.0068664550781250, +0.4510498046875000, 0.0105285644531250, 0.6351318359375000, 0.0066223144531250, +0.5361328125000000, -0.0062866210937500, 0.6375427246093750, 0.0742187500000000, +0.7049255371093750, 0.0633239746093750, 0.5873718261718750, 0.0714721679687500, +0.5516662597656250, 0.1343688964843750, 0.6246337890625000, 0.1157226562500000, +0.2774658203125000, 0.0798645019531250, 0.3533020019531250, 0.1117553710937500, +0.2402648925781250, 0.0683898925781250, -0.0520629882812500, 0.0004272460937500, +0.0974731445312500, 0.0395507812500000, -0.1437072753906250, -0.0249023437500000, +-0.1803283691406250, -0.0402221679687500, -0.1431884765625000, -0.0237731933593750, +-0.2233276367187500, -0.0370788574218750, -0.2166748046875000, -0.0404663085937500, +-0.1895446777343750, -0.0143432617187500, -0.1892395019531250, -0.0167236328125000, +-0.2099304199218750, -0.0143127441406250, -0.1995239257812500, 0.0020446777343750, +-0.1872253417968750, -0.0025634765625000, -0.2919616699218750, -0.0003967285156250, +-0.2531433105468750, 0.0015869140625000, -0.3067016601562500, 0.0004577636718750, +-0.4155883789062500, -0.0003662109375000, -0.3504028320312500, -0.0001525878906250, +-0.4616699218750000, 0.0000610351562500, -0.4792480468750000, -0.0000610351562500, +-0.4532775878906250, -0.0000610351562500, -0.4932556152343750, 0.0001525878906250, +-0.4952087402343750, 0.0001525878906250, -0.4126892089843750, 0.0000305175781250, +-0.4499816894531250, 0.0000305175781250, -0.3914489746093750, 0.0000305175781250, +-0.2987670898437500, 0.0000305175781250, -0.3596496582031250, 0.0000305175781250, +-0.2041015625000000, -0.0000305175781250, -0.2167968750000000, 0.0000305175781250, +-0.1918029785156250, 0.0000000000000000, -0.0908203125000000, -0.0000305175781250, +-0.1401672363281250, -0.0000610351562500, -0.0711364746093750, 0.0000610351562500, +-0.0613708496093750, 0.0000915527343750, -0.0688171386718750, 0.0000610351562500, +-0.0421447753906250, 0.0001220703125000, -0.0468750000000000, 0.0000610351562500, +-0.0478515625000000, 0.0000000000000000, -0.0443420410156250, -0.0000305175781250, +-0.0451965332031250, 0.0000305175781250, -0.0476684570312500, 0.0000000000000000, +-0.0444335937500000, 0.0000000000000000, -0.0399475097656250, -0.0000305175781250, +-0.0429687500000000, 0.0000000000000000, -0.0357360839843750, -0.0000305175781250, +-0.0278930664062500, -0.0000915527343750, -0.0333251953125000, -0.0000305175781250, +-0.0168151855468750, -0.0000610351562500, -0.0190429687500000, -0.0000915527343750, +-0.0154113769531250, -0.0000610351562500, -0.0037536621093750, -0.0000610351562500, +-0.0100708007812500, -0.0000610351562500, -0.0007019042968750, -0.0000610351562500, +-0.0007324218750000, -0.0000610351562500, -0.0021972656250000, -0.0000915527343750, +0.0015563964843750, -0.0001525878906250, -0.0010070800781250, -0.0001220703125000, +-0.0039367675781250, -0.0001220703125000, -0.0035400390625000, -0.0001525878906250, +-0.0057067871093750, -0.0001220703125000, -0.0093994140625000, -0.0001220703125000, +-0.0094909667968750, -0.0001220703125000, -0.0119934082031250, -0.0000915527343750, +-0.0120849609375000, -0.0001220703125000, -0.0134277343750000, -0.0001220703125000, +-0.0152587890625000, -0.0001220703125000, -0.0148925781250000, -0.0001220703125000, +-0.0201110839843750, -0.0000915527343750, -0.0189514160156250, -0.0000915527343750, +-0.0239562988281250, -0.0001220703125000, -0.0294189453125000, -0.0000915527343750, +-0.0256652832031250, -0.0000915527343750, -0.0409240722656250, -0.0001220703125000, +-0.0380249023437500, -0.0001220703125000, -0.0432434082031250, -0.0000915527343750, +-0.0556640625000000, -0.0001220703125000, -0.0487365722656250, -0.0001220703125000, +-0.0612792968750000, -0.0001220703125000, -0.0621032714843750, -0.0000610351562500, +-0.0604858398437500, -0.0000610351562500, -0.0659179687500000, -0.0000610351562500, +-0.0627136230468750, -0.0001220703125000, -0.0533142089843750, -0.0000610351562500, +-0.0582275390625000, -0.0000610351562500, -0.0474548339843750, -0.0000610351562500, +-0.0333251953125000, 0.0000000000000000, -0.0396423339843750, -0.0000610351562500, +-0.0124816894531250, -0.0000610351562500, -0.0153808593750000, 0.0000000000000000, +-0.0063781738281250, -0.0000305175781250, 0.0157470703125000, -0.0000305175781250, +0.0072021484375000, -0.0000305175781250, 0.0266113281250000, 0.0000000000000000, +0.0281372070312500, 0.0000000000000000, 0.0305480957031250, -0.0000305175781250, +0.0403137207031250}, +{-0.4284362792968750, -0.0089111328125000, -0.4179382324218750, 0.0020446777343750, +-0.4476928710937500, -0.0005187988281250, -0.3241882324218750, -0.0004272460937500, +-0.3546142578125000, 0.0006408691406250, -0.3118591308593750, 0.0002441406250000, +-0.2063293457031250, -0.0003662109375000, -0.2622375488281250, -0.0003967285156250, +-0.1539916992187500, 0.0000305175781250, -0.1499938964843750, 0.0000000000000000, +-0.1481018066406250, -0.0000610351562500, -0.0926208496093750, 0.0000915527343750, +-0.1123046875000000, 0.0001220703125000, -0.0971984863281250, 0.0000000000000000, +-0.0897216796875000, -0.0000305175781250, -0.0926208496093750, 0.0000000000000000, +-0.0932006835937500, 0.0000610351562500, -0.0921020507812500, 0.0000305175781250, +-0.0765380859375000, 0.0000000000000000, -0.0885009765625000, 0.0000000000000000, +-0.0660705566406250, 0.0000305175781250, -0.0409545898437500, 0.0000000000000000, +-0.0622558593750000, -0.0000610351562500, 0.0013732910156250, 0.0000305175781250, +-0.0100708007812500, 0.0000610351562500, 0.0056762695312500, -0.0000305175781250, +0.0528564453125000, 0.0000000000000000, 0.0253601074218750, 0.0000305175781250, +0.0670776367187500, 0.0000000000000000, 0.0708312988281250, -0.0000915527343750, +0.0647583007812500, -0.0000305175781250, 0.0810852050781250, 0.0000305175781250, +0.0761718750000000, -0.0000305175781250, 0.0657043457031250, 0.0000000000000000, +0.0739135742187500, 0.0000305175781250, 0.0604248046875000, 0.0000000000000000, +0.0441589355468750, -0.0000610351562500, 0.0567932128906250, -0.0000305175781250, +0.0226745605468750, 0.0000305175781250, 0.0304870605468750, 0.0000000000000000, +0.0206298828125000, -0.0000305175781250, -0.0049133300781250, 0.0000305175781250, +0.0127258300781250, 0.0000305175781250, -0.0188598632812500, 0.0000000000000000, +-0.0131225585937500, -0.0000305175781250, -0.0191040039062500, 0.0000000000000000, +-0.0399475097656250, 0.0000000000000000, -0.0247192382812500, 0.0000000000000000, +-0.0505981445312500, 0.0000000000000000, -0.0459289550781250, 0.0000305175781250, +-0.0485839843750000, -0.0000305175781250, -0.0654907226562500, -0.0000305175781250, +-0.0545349121093750, 0.0000000000000000, -0.0672607421875000, -0.0000610351562500, +-0.0651245117187500, -0.0000610351562500, -0.0644836425781250, -0.0000610351562500, +-0.0702209472656250, 0.0000000000000000, -0.0628662109375000, -0.0000915527343750, +-0.0672607421875000, 0.0000000000000000, -0.0654296875000000, 0.0000305175781250, +-0.0637817382812500, 0.0000000000000000, -0.0653381347656250, 0.0000000000000000, +-0.0631713867187500, 0.0000000000000000, -0.0671997070312500, 0.0000305175781250, +-0.0643005371093750, 0.0000000000000000, -0.0691223144531250, 0.0000000000000000, +-0.0747375488281250, 0.0000305175781250, -0.0695495605468750, 0.0000305175781250, +-0.0869445800781250, 0.0000305175781250, -0.0840454101562500, 0.0000610351562500, +-0.0907897949218750, 0.0000610351562500, -0.1058654785156250, 0.0000305175781250, +-0.0990905761718750, 0.0000000000000000, -0.1153869628906250, 0.0000000000000000, +-0.1176147460937500, 0.0000305175781250, -0.1156311035156250, 0.0000305175781250, +-0.1223754882812500, 0.0000305175781250, -0.1203308105468750, 0.0000000000000000, +-0.1077575683593750, 0.0000305175781250, -0.1142883300781250, 0.0000610351562500, +-0.0983276367187500, 0.0000305175781250, -0.0786132812500000, 0.0000000000000000, +-0.0885620117187500, -0.0000305175781250, -0.0468139648437500, 0.0000305175781250, +-0.0490112304687500, 0.0000305175781250, -0.0349731445312500, -0.0000305175781250, +-0.0036010742187500, -0.0000915527343750, -0.0161132812500000, -0.0000305175781250, +0.0173645019531250, -0.0001220703125000, 0.0168457031250000, -0.0003051757812500, +0.0245666503906250, 0.0000915527343750, 0.0445556640625000, 0.0004882812500000, +0.0346374511718750, 0.0000305175781250, 0.0657653808593750, -0.0002746582031250, +0.0618286132812500, 0.0015258789062500, 0.0734252929687500, -0.0030212402343750, +0.0992126464843750, -0.0057067871093750, 0.0867919921875000, -0.0018615722656250, +0.1148986816406250, -0.0175170898437500, 0.1179809570312500, -0.0151367187500000, +0.1143493652343750, -0.0147705078125000, 0.1264953613281250, -0.0277709960937500, +0.1250915527343750, -0.0242309570312500, 0.1107482910156250, -0.0043029785156250, +0.1161804199218750, -0.0205383300781250, 0.1094970703125000, 0.0054626464843750, +0.0925903320312500, 0.0407409667968750, 0.0991516113281250, 0.0143432617187500, +0.0965881347656250, 0.0664367675781250, 0.0877685546875000, 0.0748596191406250, +0.1016845703125000, 0.0569152832031250, 0.1137084960937500, 0.0722045898437500, +0.1024475097656250, 0.0784301757812500, 0.1315917968750000, 0.0248413085937500, +0.1315612792968750, 0.0374145507812500, 0.1323547363281250, 0.0269775390625000, +0.1454772949218750, -0.0170593261718750, 0.1408386230468750, -0.0008850097656250, +0.1562194824218750, -0.0112609863281250, 0.1452331542968750, -0.0161743164062500, +0.1701354980468750, -0.0207824707031250, 0.1966857910156250, -0.0205993652343750, +0.1739501953125000, -0.0149230957031250, 0.2472534179687500, -0.0563049316406250, +0.2499084472656250, -0.0459594726562500, 0.2356262207031250, -0.0545349121093750, +0.2765502929687500, -0.0935668945312500, 0.2743835449218750, -0.0793457031250000, +0.1729736328125000, -0.0654907226562500, 0.2206726074218750, -0.0832214355468750, +0.1558227539062500, -0.0644531250000000, -0.0025634765625000, -0.0231323242187500, +0.0102844238281250, -0.0303649902343750, -0.0726623535156250, -0.0321044921875000, +-0.0746154785156250, -0.0218811035156250, -0.0479431152343750, -0.0294494628906250, +-0.0764160156250000, -0.0465393066406250, -0.0862121582031250, -0.0365905761718750, +-0.0416564941406250, -0.0171508789062500, -0.0390625000000000, -0.0461730957031250, +-0.0533447265625000, 0.0100708007812500, -0.0390930175781250, 0.0686950683593750, +-0.0319213867187500, 0.0231018066406250, -0.0705566406250000, 0.1616821289062500, +-0.0685119628906250, 0.1582031250000000, -0.0616455078125000, 0.1694030761718750, +-0.0813293457031250, 0.2538452148437500, -0.0816345214843750, 0.2272949218750000, +-0.0541076660156250, 0.2390136718750000, -0.0596313476562500, 0.2600402832031250, +-0.0571289062500000, 0.2301025390625000, -0.0383605957031250, 0.2093811035156250, +-0.0430603027343750, 0.2283935546875000, -0.0374755859375000, 0.1506652832031250, +-0.0439453125000000, 0.1637878417968750, -0.0226745605468750, 0.1405944824218750, +-0.0086059570312500, 0.0762939453125000, -0.0272216796875000, 0.1072998046875000, +0.0475463867187500, 0.0698547363281250, 0.0377197265625000, 0.0520935058593750, +0.0480957031250000, 0.0787963867187500, 0.1063537597656250, 0.0848388671875000, +0.0863037109375000, 0.0695190429687500, 0.0729370117187500, 0.1255493164062500, +0.0993652343750000, 0.1257629394531250, 0.0640258789062500, 0.1188049316406250, +0.0191345214843750, 0.1476440429687500, 0.0502014160156250, 0.1437683105468750, +-0.0123291015625000, 0.1031799316406250, -0.0181274414062500, 0.1193542480468750, +-0.0088806152343750, 0.0956115722656250, -0.0330810546875000, 0.0476989746093750, +-0.0309143066406250, 0.0701293945312500, -0.0140686035156250, 0.0359497070312500, +-0.0200195312500000, 0.0240783691406250, -0.0154113769531250, 0.0365295410156250, +-0.0004272460937500, 0.0345458984375000, -0.0067749023437500, 0.0284118652343750, +-0.0007934570312500, 0.0454101562500000, 0.0016174316406250, 0.0496520996093750, +-0.0002441406250000, 0.0361022949218750, 0.0001220703125000, 0.0372314453125000, +0.0005798339843750, 0.0419616699218750, -0.0000610351562500, -0.0121154785156250, +-0.0004272460937500, -0.0014343261718750, -0.0001220703125000, -0.0333862304687500, +0.0001220703125000, -0.0892333984375000, -0.0001525878906250, -0.0657348632812500, +0.0000915527343750, -0.1308898925781250, 0.0001831054687500, -0.1382446289062500, +0.0001220703125000, -0.1371154785156250, 0.0000305175781250, -0.1678466796875000, +0.0000610351562500, -0.1620178222656250, 0.0000610351562500, -0.1500549316406250, +0.0000305175781250, -0.1612243652343750, 0.0000305175781250, -0.1440429687500000, +0.0001525878906250, -0.1209411621093750, 0.0001220703125000, -0.1335144042968750, +0.0000610351562500, -0.0931091308593750, 0.0000610351562500, -0.0937805175781250, +0.0001220703125000, -0.0881347656250000, 0.0000610351562500, -0.0631103515625000, +0.0000305175781250, -0.0721740722656250, 0.0000915527343750, -0.0600891113281250, +0.0000610351562500, -0.0560607910156250, 0.0000610351562500, -0.0603332519531250, +0.0001220703125000, -0.0596923828125000, 0.0000915527343750, -0.0598449707031250, +0.0000305175781250, -0.0684204101562500, 0.0000610351562500, -0.0700073242187500, +0.0000610351562500, -0.0750122070312500, 0.0000915527343750, -0.0831909179687500, +0.0000610351562500, -0.0821228027343750, 0.0001220703125000, -0.0849609375000000, +0.0001525878906250, -0.0895996093750000, 0.0001220703125000, -0.0876770019531250, +0.0001525878906250, -0.0865173339843750, 0.0001220703125000, -0.0901184082031250, +0.0000610351562500, -0.0795288085937500, 0.0000610351562500, -0.0855712890625000, +0.0000610351562500, -0.0792541503906250, 0.0000610351562500, -0.0677490234375000, +0.0000610351562500, -0.0767517089843750, 0.0000610351562500, -0.0553283691406250, +0.0000610351562500, -0.0595703125000000, 0.0000610351562500, -0.0532836914062500, +0.0000610351562500, -0.0366210937500000, 0.0000610351562500, -0.0456237792968750, +0.0000305175781250, -0.0241394042968750, 0.0000305175781250, -0.0275573730468750, +0.0000305175781250, -0.0194396972656250, 0.0000305175781250, -0.0030212402343750, +0.0000000000000000, -0.0139160156250000, 0.0000305175781250, 0.0130920410156250, +0.0000305175781250, 0.0105590820312500, 0.0000000000000000, 0.0168151855468750, +0.0000000000000000, 0.0362854003906250, 0.0000305175781250, 0.0267333984375000, +0.0000000000000000, 0.0415344238281250, -0.0000305175781250, 0.0457153320312500, +-0.0000305175781250, 0.0378112792968750, 0.0000305175781250, 0.0422363281250000, +0.0000000000000000, 0.0470886230468750, 0.0000305175781250, 0.0170593261718750, +0.0000305175781250, 0.0307006835937500, -0.0000305175781250, 0.0098266601562500, +-0.0000610351562500, -0.0206909179687500, -0.0000305175781250, 0.0050354003906250, +-0.0000915527343750, -0.0606384277343750, -0.0001220703125000, -0.0492248535156250, +-0.0000610351562500, -0.0693664550781250, -0.0000610351562500, -0.1198730468750000, +-0.0001220703125000, -0.0923156738281250, -0.0000305175781250, -0.1556396484375000, +0.0000305175781250, -0.1515808105468750, -0.0000305175781250, -0.1555786132812500, +-0.0000915527343750, -0.1962890625000000, -0.0000305175781250, -0.1804199218750000, +-0.0001831054687500, -0.1807556152343750, -0.0003051757812500, -0.1957397460937500, +-0.0000610351562500, -0.1750183105468750, 0.0003356933593750, -0.1539611816406250, +-0.0000915527343750, -0.1712036132812500, -0.0011291503906250, -0.1334838867187500, +0.0012207031250000, -0.1273803710937500, -0.0045166015625000, -0.1427612304687500, +-0.0086975097656250, -0.1282043457031250, -0.0037536621093750, -0.1232299804687500, +-0.0218505859375000, -0.1958618164062500, -0.0213623046875000, -0.1654663085937500, +-0.0180664062500000, -0.2230529785156250, -0.0310058593750000, -0.3142089843750000, +-0.0296936035156250, -0.2606811523437500, 0.0056152343750000, -0.3840942382812500, +-0.0145874023437500, -0.3972778320312500, 0.0166015625000000, -0.3778076171875000, +0.0679626464843750, -0.4322509765625000, 0.0368041992187500, -0.4298095703125000, +0.0930480957031250}, +{0.0000305175781250, -0.1015930175781250, 0.0000305175781250, -0.1217346191406250, +0.0000305175781250, -0.1207580566406250, 0.0000305175781250, -0.1257629394531250, +0.0000610351562500, -0.1407470703125000, 0.0000000000000000, -0.1361999511718750, +0.0000305175781250, -0.1431579589843750, 0.0000000000000000, -0.1467590332031250, +0.0000000000000000, -0.1415405273437500, 0.0000000000000000, -0.1405944824218750, +0.0000000000000000, -0.1427612304687500, 0.0000915527343750, -0.1254577636718750, +0.0000610351562500, -0.1278991699218750, 0.0000915527343750, -0.1177978515625000, +0.0000915527343750, -0.1007995605468750, 0.0000915527343750, -0.1071166992187500, +0.0000915527343750, -0.0836486816406250, 0.0000915527343750, -0.0821228027343750, +0.0000915527343750, -0.0738525390625000, 0.0000610351562500, -0.0574340820312500, +0.0000305175781250, -0.0635070800781250, 0.0000610351562500, -0.0454406738281250, +0.0000915527343750, -0.0404663085937500, 0.0000610351562500, -0.0373229980468750, +0.0000915527343750, -0.0287170410156250, 0.0001220703125000, -0.0286560058593750, +0.0000305175781250, -0.0205078125000000, 0.0000610351562500, -0.0201416015625000, +0.0000610351562500, -0.0164794921875000, 0.0000305175781250, -0.0104064941406250, +0.0000610351562500, -0.0131530761718750, 0.0000610351562500, -0.0059204101562500, +0.0000305175781250, -0.0032958984375000, 0.0000305175781250, -0.0036010742187500, +0.0000915527343750, -0.0012512207031250, 0.0000915527343750, -0.0007019042968750, +0.0000000000000000, -0.0035095214843750, 0.0000000000000000, -0.0010986328125000, +0.0000000000000000, 0.0003356933593750, 0.0000610351562500, -0.0013122558593750, +0.0000000000000000, 0.0012817382812500, 0.0000610351562500, 0.0061645507812500, +0.0000915527343750, 0.0044250488281250, 0.0000305175781250, 0.0101318359375000, +0.0000610351562500, 0.0176086425781250, 0.0000610351562500, 0.0140380859375000, +-0.0000305175781250, 0.0229187011718750, 0.0000000000000000, 0.0262451171875000, +0.0000000000000000, 0.0223388671875000, -0.0000305175781250, 0.0237121582031250, +-0.0000305175781250, 0.0271301269531250, 0.0000305175781250, 0.0149230957031250, +0.0000305175781250, 0.0193481445312500, 0.0000305175781250, 0.0161743164062500, +0.0000305175781250, 0.0068969726562500, 0.0000610351562500, 0.0123596191406250, +-0.0001525878906250, -0.0040283203125000, -0.0001525878906250, 0.0036621093750000, +0.0000610351562500, -0.0160522460937500, 0.0000610351562500, -0.0349426269531250, +-0.0001525878906250, -0.0156555175781250, -0.0002441406250000, -0.0872802734375000, +0.0010986328125000, -0.0701293945312500, -0.0025939941406250, -0.1009216308593750, +-0.0043640136718750, -0.1661376953125000, -0.0015563964843750, -0.1295471191406250, +-0.0165100097656250, -0.2010498046875000, -0.0140075683593750, -0.2058410644531250, +-0.0149536132812500, -0.1995849609375000, -0.0289306640625000, -0.2328796386718750, +-0.0245056152343750, -0.2264404296875000, -0.0042724609375000, -0.2083129882812500, +-0.0221252441406250, -0.2154541015625000, 0.0086669921875000, -0.2066650390625000, +0.0492248535156250, -0.1817321777343750, 0.0205078125000000, -0.1904296875000000, +0.0787353515625000, -0.2085266113281250, 0.0906066894531250, -0.1816101074218750, +0.0643310546875000, -0.2269897460937500, 0.0782470703125000, -0.2780761718750000, +0.0888977050781250, -0.2413635253906250, 0.0001831054687500, -0.3574523925781250, +0.0184326171875000, -0.3595275878906250, 0.0000000000000000, -0.3544311523437500, +-0.0780029296875000, -0.4187622070312500, -0.0495605468750000, -0.4061889648437500, +-0.0330200195312500, -0.3527832031250000, -0.0698242187500000, -0.3901977539062500, +-0.0226440429687500, -0.3392944335937500, 0.0447692871093750, -0.2561950683593750, +0.0023193359375000, -0.3047180175781250, 0.0507812500000000, -0.2121276855468750, +0.0902099609375000, -0.2005615234375000, 0.0186157226562500, -0.2124023437500000, +-0.0171203613281250, -0.1844177246093750, 0.0335998535156250, -0.1886901855468750, +-0.1434631347656250, -0.1760864257812500, -0.1351318359375000, -0.1986694335937500, +-0.1335449218750000, -0.1411132812500000, -0.2425537109375000, -0.1025390625000000, +-0.2151794433593750, -0.1486816406250000, -0.1432800292968750, 0.0677795410156250, +-0.2011413574218750, 0.0163269042968750, -0.1225280761718750, 0.1138305664062500, +0.0023193359375000, 0.3174133300781250, -0.0702514648437500, 0.2093200683593750, +0.0594787597656250, 0.4132385253906250, 0.0825805664062500, 0.4404296875000000, +0.0595092773437500, 0.4037170410156250, 0.0953979492187500, 0.4764099121093750, +0.0968017578125000, 0.4725646972656250, 0.0812683105468750, 0.3892822265625000, +0.0748291015625000, 0.4141845703125000, 0.0931396484375000, 0.3951416015625000, +0.1153564453125000, 0.2831420898437500, 0.1792297363281250, 0.4488220214843750, +0.2096862792968750, 0.3499450683593750, 0.1744995117187500, 0.4035644531250000, +0.2399902343750000, 0.3583068847656250, 0.2838134765625000, 0.2793273925781250, +0.2338562011718750, 0.3116149902343750, 0.4234924316406250, 0.2590332031250000, +0.3952636718750000, 0.2630615234375000, 0.4280090332031250, 0.2352905273437500, +0.5784606933593750, 0.1968383789062500, 0.5160217285156250, 0.2259826660156250, +0.5041198730468750, 0.1121215820312500, 0.5878906250000000, 0.1304321289062500, +0.4498901367187500, 0.1025390625000000, 0.3240356445312500, 0.0140075683593750, +0.4326477050781250, 0.0520935058593750, 0.0811157226562500, -0.0076599121093750, +0.1235961914062500, -0.0093994140625000, 0.0539245605468750, -0.0265502929687500, +-0.1949768066406250, -0.0601196289062500, -0.0804443359375000, -0.0372009277343750, +-0.2401123046875000, -0.1206970214843750, -0.2733764648437500, -0.1113281250000000, +-0.2471313476562500, -0.1193237304687500, -0.2943420410156250, -0.1838684082031250, +-0.2917175292968750, -0.1635437011718750, -0.2751770019531250, -0.1295471191406250, +-0.2772827148437500, -0.1639404296875000, -0.2879333496093750, -0.1140136718750000, +-0.2801818847656250, -0.0408325195312500, -0.2750244140625000, -0.0848693847656250, +-0.3259887695312500, -0.0106201171875000, -0.3076477050781250, 0.0067443847656250, +-0.3344726562500000, -0.0104370117187500, -0.3896179199218750, 0.0016479492187500, +-0.3595886230468750, 0.0059509277343750, -0.4084777832031250, 0.0048828125000000, +-0.4218750000000000, -0.0083007812500000, -0.3983459472656250, 0.0167846679687500, +-0.4069824218750000, 0.0415344238281250, -0.4166259765625000, 0.0215454101562500, +-0.3434448242187500, 0.0704040527343750, -0.3672790527343750, 0.0805053710937500, +-0.3300781250000000, 0.0603332519531250, -0.2585449218750000, 0.0705261230468750, +-0.2998657226562500, 0.0794982910156250, -0.2064208984375000, 0.0194091796875000, +-0.2117309570312500, 0.0280151367187500, -0.1974182128906250, 0.0169067382812500, +-0.1401367187500000, -0.0288696289062500, -0.1680297851562500, -0.0127868652343750, +-0.1141967773437500, -0.0194091796875000, -0.1177673339843750, -0.0303955078125000, +-0.1044311523437500, -0.0192871093750000, -0.0700988769531250, -0.0079345703125000, +-0.0892028808593750, -0.0149230957031250, -0.0301208496093750, -0.0026550292968750, +-0.0413818359375000, -0.0000305175781250, -0.0174865722656250, -0.0021972656250000, +0.0337524414062500, 0.0006713867187500, 0.0045166015625000, 0.0005798339843750, +0.0610961914062500, -0.0001525878906250, 0.0683288574218750, -0.0003051757812500, +0.0568847656250000, -0.0000915527343750, 0.0789184570312500, 0.0000305175781250, +0.0794372558593750, -0.0000915527343750, 0.0436706542968750, 0.0000000000000000, +0.0604858398437500, 0.0001220703125000, 0.0411987304687500, 0.0000610351562500, +0.0021362304687500, 0.0000000000000000, 0.0265502929687500, 0.0000000000000000, +-0.0145568847656250, 0.0000000000000000, -0.0180664062500000, 0.0000305175781250, +-0.0129699707031250, 0.0000000000000000, -0.0303649902343750, -0.0000305175781250, +-0.0279846191406250, 0.0000000000000000, -0.0206604003906250, 0.0000000000000000, +-0.0268249511718750, -0.0000610351562500, -0.0217590332031250, 0.0000000000000000, +-0.0130310058593750, 0.0000610351562500, -0.0206298828125000, 0.0000305175781250, +-0.0065917968750000, 0.0000000000000000, -0.0091857910156250, 0.0000305175781250, +-0.0075683593750000, 0.0000305175781250, 0.0020446777343750, -0.0000610351562500, +-0.0034790039062500, -0.0000305175781250, 0.0031127929687500, 0.0000610351562500, +0.0038146972656250, 0.0000915527343750, 0.0017089843750000, 0.0000305175781250, +0.0041198730468750, 0.0000610351562500, 0.0046081542968750, 0.0000610351562500, +0.0011596679687500, 0.0000000000000000, 0.0033874511718750, 0.0000305175781250, +-0.0002746582031250, 0.0000610351562500, -0.0053100585937500, 0.0000305175781250, +-0.0017089843750000, 0.0000000000000000, -0.0111694335937500, 0.0000610351562500, +-0.0098266601562500, 0.0000610351562500, -0.0134582519531250, 0.0000305175781250, +-0.0202636718750000, 0.0000000000000000, -0.0159606933593750, 0.0000610351562500, +-0.0297241210937500, 0.0000305175781250, -0.0273437500000000, 0.0000305175781250, +-0.0341186523437500, 0.0000305175781250, -0.0466308593750000, 0.0000610351562500, +-0.0415344238281250, 0.0000305175781250, -0.0627746582031250, 0.0000305175781250, +-0.0595703125000000, 0.0000915527343750, -0.0690307617187500, 0.0000305175781250, +-0.0867309570312500, -0.0000305175781250, -0.0783386230468750, 0.0000305175781250, +-0.1073303222656250, 0.0000000000000000, -0.1034545898437500, 0.0000000000000000, +-0.1127929687500000, 0.0000000000000000, -0.1354064941406250, 0.0000000000000000, +-0.1256103515625000, 0.0000305175781250, -0.1538391113281250, 0.0001220703125000, +-0.1528930664062500, 0.0000610351562500, -0.1574096679687500, 0.0000915527343750, +-0.1760559082031250, 0.0000610351562500, -0.1687316894531250, 0.0000305175781250, +-0.1761474609375000, 0.0000610351562500, -0.1806030273437500, 0.0001525878906250, +-0.1725158691406250, 0.0000305175781250, -0.1693420410156250, 0.0000000000000000, +-0.1725158691406250, 0.0000915527343750, -0.1509094238281250, -0.0000305175781250, +-0.1526794433593750, -0.0000915527343750, -0.1489257812500000, 0.0000305175781250, +-0.1323547363281250, 0.0000915527343750, -0.1372375488281250, -0.0000610351562500, +-0.1396484375000000, 0.0001831054687500, -0.1308593750000000, 0.0008239746093750, +-0.1436157226562500, -0.0012512207031250, -0.1576232910156250, -0.0017089843750000, +-0.1464843750000000, -0.0001525878906250, -0.1740722656250000, -0.0098571777343750, +-0.1755371093750000, -0.0067749023437500, -0.1719665527343750, -0.0100402832031250, +-0.1847534179687500, -0.0207824707031250, -0.1827087402343750, -0.0154113769531250, +-0.1675109863281250, -0.0118408203125000, -0.1748962402343750, -0.0223083496093750, +-0.1590270996093750, -0.0033874511718750, -0.1385803222656250, 0.0140380859375000, +-0.1498413085937500, -0.0029602050781250, -0.1052246093750000, 0.0439453125000000, +-0.1113586425781250, 0.0421752929687500, -0.0913085937500000, 0.0384521484375000, +-0.0538940429687500, 0.0658264160156250, -0.0727844238281250, 0.0606384277343750, +-0.0182800292968750, 0.0354309082031250, -0.0218200683593750, 0.0505676269531250, +-0.0079040527343750, 0.0326843261718750, 0.0303039550781250, -0.0019226074218750, +0.0138244628906250, 0.0176086425781250, 0.0532531738281250, -0.0069580078125000, +0.0543518066406250, -0.0144042968750000, 0.0559997558593750, -0.0090942382812500, +0.0778808593750000, -0.0103759765625000, 0.0706481933593750, -0.0118713378906250, +0.0719909667968750, -0.0252380371093750, 0.0772094726562500, -0.0146179199218750, +0.0725708007812500}, +{-0.0320129394531250, 0.0000915527343750, -0.0352783203125000, 0.0001220703125000, +-0.0534973144531250, 0.0001220703125000, -0.0441894531250000, 0.0001220703125000, +-0.0591735839843750, 0.0000915527343750, -0.0591125488281250, 0.0000610351562500, +-0.0593566894531250, 0.0000915527343750, -0.0671081542968750, 0.0001220703125000, +-0.0631408691406250, 0.0000915527343750, -0.0667114257812500, 0.0000915527343750, +-0.0669555664062500, 0.0001831054687500, -0.0649414062500000, 0.0001831054687500, +-0.0652770996093750, 0.0001220703125000, -0.0655517578125000, 0.0001831054687500, +-0.0643920898437500, 0.0001525878906250, -0.0640869140625000, 0.0001220703125000, +-0.0642700195312500, 0.0000610351562500, -0.0639038085937500, 0.0000915527343750, +-0.0636901855468750, 0.0000610351562500, -0.0649108886718750, 0.0001220703125000, +-0.0645751953125000, 0.0001220703125000, -0.0650024414062500, 0.0001220703125000, +-0.0654907226562500, 0.0001220703125000, -0.0645446777343750, 0.0000915527343750, +-0.0672302246093750, 0.0000915527343750, -0.0665588378906250, 0.0000610351562500, +-0.0673522949218750, 0.0001220703125000, -0.0693969726562500, 0.0001525878906250, +-0.0678710937500000, 0.0000915527343750, -0.0706481933593750, 0.0001220703125000, +-0.0706176757812500, 0.0001525878906250, -0.0707397460937500, 0.0001220703125000, +-0.0715332031250000, 0.0001220703125000, -0.0710449218750000, 0.0000915527343750, +-0.0759582519531250, 0.0001220703125000, -0.0729064941406250, 0.0001220703125000, +-0.0788879394531250, 0.0000305175781250, -0.0852661132812500, 0.0000305175781250, +-0.0802307128906250, 0.0000305175781250, -0.1025085449218750, -0.0001831054687500, +-0.0974731445312500, -0.0001831054687500, -0.1092834472656250, -0.0000915527343750, +-0.1314086914062500, -0.0001525878906250, -0.1213989257812500, -0.0002136230468750, +-0.1509094238281250, 0.0000915527343750, -0.1517944335937500, 0.0004577636718750, +-0.1535644531250000, -0.0009155273437500, -0.1701049804687500, -0.0009460449218750, +-0.1651000976562500, 0.0000000000000000, -0.1661071777343750, -0.0071716308593750, +-0.1690673828125000, -0.0041809082031250, -0.1685485839843750, -0.0079345703125000, +-0.1649169921875000, -0.0167236328125000, -0.1650695800781250, -0.0115051269531250, +-0.1757507324218750, -0.0129089355468750, -0.1685485839843750, -0.0205688476562500, +-0.1781005859375000, -0.0057373046875000, -0.1940612792968750, 0.0045471191406250, +-0.1836853027343750, -0.0080871582031250, -0.2025146484375000, 0.0328979492187500, +-0.2052612304687500, 0.0288085937500000, -0.2009582519531250, 0.0302429199218750, +-0.2068786621093750, 0.0583496093750000, -0.2063903808593750, 0.0496826171875000, +-0.1960754394531250, 0.0363464355468750, -0.2001953125000000, 0.0512390136718750, +-0.1898803710937500, 0.0332641601562500, -0.1784667968750000, 0.0058898925781250, +-0.1860961914062500, 0.0241088867187500, -0.1506042480468750, -0.0035705566406250, +-0.1592102050781250, -0.0093383789062500, -0.1399536132812500, -0.0034484863281250, +-0.1065979003906250, -0.0085449218750000, -0.1241149902343750, -0.0100708007812500, +-0.0672302246093750, -0.0148925781250000, -0.0740661621093750, -0.0070495605468750, +-0.0558471679687500, -0.0213623046875000, -0.0125427246093750, -0.0381164550781250, +-0.0342407226562500, -0.0242919921875000, 0.0149536132812500, -0.0494079589843750, +0.0157165527343750, -0.0558776855468750, 0.0209960937500000, -0.0440673828125000, +0.0500183105468750, -0.0452880859375000, 0.0389709472656250, -0.0523681640625000, +0.0505065917968750, -0.0357360839843750, 0.0546875000000000, -0.0294799804687500, +0.0517272949218750, -0.0440673828125000, 0.0508117675781250, -0.0484619140625000, +0.0515136718750000, -0.0360717773437500, 0.0620422363281250, -0.0592346191406250, +0.0515441894531250, -0.0724182128906250, 0.0715637207031250, -0.0374450683593750, +0.0924377441406250, -0.0295715332031250, 0.0749206542968750, -0.0535888671875000, +0.1334838867187500, 0.0655212402343750, 0.1236267089843750, 0.0408020019531250, +0.1412353515625000, 0.0756530761718750, 0.1935424804687500, 0.1927795410156250, +0.1917724609375000, 0.1756286621093750, 0.2616577148437500, 0.2245178222656250, +0.2360534667968750, 0.2233581542968750, 0.2457580566406250, 0.2126770019531250, +0.3069763183593750, 0.2373657226562500, 0.2762756347656250, 0.2344360351562500, +0.2791748046875000, 0.2033691406250000, 0.3201904296875000, 0.2171936035156250, +0.2460632324218750, 0.1901550292968750, 0.1917419433593750, 0.1505737304687500, +0.2543640136718750, 0.1741027832031250, 0.0468750000000000, 0.1136779785156250, +0.0718688964843750, 0.1099243164062500, 0.0448303222656250, 0.1134643554687500, +-0.1022033691406250, 0.0853271484375000, -0.0462036132812500, 0.0893859863281250, +-0.0721130371093750, 0.0983276367187500, -0.1073303222656250, 0.0978393554687500, +-0.0711059570312500, 0.0880126953125000, -0.0365295410156250, 0.0914001464843750, +-0.0613708496093750, 0.0968322753906250, -0.0325012207031250, 0.0467834472656250, +-0.0165405273437500, 0.0587158203125000, -0.0363769531250000, 0.0426330566406250, +-0.0466003417968750, -0.0035400390625000, -0.0340576171875000, 0.0160217285156250, +-0.0544128417968750, -0.0001525878906250, -0.0636901855468750, -0.0111389160156250, +-0.0488586425781250, -0.0030517578125000, -0.0437927246093750, 0.0054321289062500, +-0.0535583496093750, -0.0005187988281250, -0.0283813476562500, -0.0191345214843750, +-0.0267028808593750, 0.0003356933593750, -0.0285949707031250, -0.0358276367187500, +-0.0207519531250000, -0.0768127441406250, -0.0218200683593750, -0.0463562011718750, +-0.0095825195312500, -0.1367492675781250, -0.0201416015625000, -0.1331787109375000, +0.0003662109375000, -0.1414184570312500, 0.0244445800781250, -0.1973571777343750, +0.0043029785156250, -0.1772460937500000, 0.0521240234375000, -0.1869812011718750, +0.0543518066406250, -0.2007141113281250, 0.0444335937500000, -0.1811523437500000, +0.0659179687500000, -0.1658020019531250, 0.0656738281250000, -0.1787414550781250, +0.0298461914062500, -0.1466979980468750, 0.0450134277343750, -0.1437377929687500, +0.0287475585937500, -0.1463623046875000, -0.0093078613281250, -0.1330871582031250, +0.0116577148437500, -0.1353149414062500, -0.0144042968750000, -0.1416015625000000, +-0.0212097167968750, -0.1399841308593750, -0.0123291015625000, -0.1400756835937500, +-0.0168762207031250, -0.1462097167968750, -0.0198364257812500, -0.1452331542968750, +-0.0067443847656250, -0.1326599121093750, -0.0083007812500000, -0.1387329101562500, +-0.0074768066406250, -0.1253356933593750, 0.0005493164062500, -0.1066894531250000, +-0.0021972656250000, -0.1163330078125000, -0.0005798339843750, -0.0869445800781250, +0.0005493164062500, -0.0859985351562500, -0.0000610351562500, -0.0830078125000000, +-0.0003051757812500, -0.0655517578125000, -0.0000915527343750, -0.0702209472656250, +-0.0000305175781250, -0.0665893554687500, -0.0001831054687500, -0.0632324218750000, +-0.0000915527343750, -0.0663146972656250, 0.0001525878906250, -0.0686035156250000, +0.0000610351562500, -0.0673522949218750, 0.0001831054687500, -0.0730285644531250, +0.0001831054687500, -0.0729980468750000, 0.0001831054687500, -0.0755310058593750, +0.0002136230468750, -0.0803527832031250, 0.0002136230468750, -0.0788879394531250, +0.0001831054687500, -0.0840454101562500, 0.0002136230468750, -0.0849609375000000, +0.0001831054687500, -0.0841369628906250, 0.0001220703125000, -0.0857849121093750, +0.0001831054687500, -0.0859069824218750, 0.0001525878906250, -0.0834045410156250, +0.0000915527343750, -0.0841674804687500, 0.0000915527343750, -0.0816955566406250, +0.0000915527343750, -0.0783691406250000, 0.0000915527343750, -0.0797424316406250, +0.0000305175781250, -0.0736083984375000, 0.0000610351562500, -0.0728149414062500, +0.0000610351562500, -0.0715637207031250, 0.0000610351562500, -0.0678405761718750, +0.0000610351562500, -0.0682067871093750, 0.0000305175781250, -0.0666198730468750, +0.0000305175781250, -0.0659790039062500, 0.0000610351562500, -0.0654602050781250, +0.0000610351562500, -0.0646667480468750, 0.0000305175781250, -0.0646972656250000, +0.0000610351562500, -0.0635070800781250, 0.0000610351562500, -0.0644836425781250, +0.0000610351562500, -0.0628051757812500, 0.0000915527343750, -0.0612487792968750, +0.0000915527343750, -0.0607604980468750, 0.0000000000000000, -0.0485229492187500, +0.0000305175781250, -0.0541381835937500, 0.0000305175781250, -0.0420532226562500, +0.0000305175781250, -0.0266113281250000, -0.0000305175781250, -0.0377502441406250, +0.0000000000000000, -0.0057067871093750, 0.0000000000000000, -0.0106506347656250, +0.0000000000000000, -0.0023803710937500, 0.0000610351562500, 0.0211181640625000, +0.0000305175781250, 0.0097045898437500, 0.0000000000000000, 0.0368652343750000, +0.0000305175781250, 0.0305786132812500, -0.0000305175781250, 0.0463562011718750, +-0.0000915527343750, 0.0687866210937500, -0.0000915527343750, 0.0505065917968750, +0.0001220703125000, 0.1111450195312500, 0.0002441406250000, 0.1013488769531250, +-0.0005187988281250, 0.1140441894531250, -0.0000915527343750, 0.1635437011718750, +0.0001525878906250, 0.1424560546875000, -0.0066833496093750, 0.1504211425781250, +-0.0033264160156250, 0.1726074218750000, -0.0087890625000000, 0.1369934082031250, +-0.0190429687500000, 0.1095886230468750, -0.0127258300781250, 0.1372070312500000, +-0.0157470703125000, 0.0527648925781250, -0.0256958007812500, 0.0601806640625000, +-0.0050964355468750, 0.0495300292968750, 0.0091552734375000, -0.0059814453125000, +-0.0070190429687500, 0.0150146484375000, 0.0481567382812500, -0.0082092285156250, +0.0466308593750000, -0.0133972167968750, 0.0412292480468750, -0.0120849609375000, +0.0743713378906250, -0.0173645019531250, 0.0696105957031250, -0.0132141113281250, +0.0244140625000000, -0.0297851562500000, 0.0467529296875000, -0.0192565917968750, +0.0189208984375000, -0.0417480468750000, -0.0415039062500000, -0.0648803710937500, +-0.0116271972656250, -0.0450744628906250, -0.0303344726562500, -0.1250610351562500, +-0.0563354492187500, -0.1080932617187500, -0.0202331542968750, -0.1371459960937500, +0.0115051269531250, -0.2084960937500000, -0.0157470703125000, -0.1752319335937500, +0.0341491699218750, -0.2363586425781250, 0.0563354492187500, -0.2457275390625000, +0.0114440917968750, -0.2362976074218750, 0.0029907226562500, -0.2564086914062500, +0.0318603515625000, -0.2551879882812500, -0.0949096679687500, -0.2445373535156250, +-0.0840759277343750, -0.2431335449218750, -0.0899047851562500, -0.2500610351562500, +-0.1762390136718750, -0.2482299804687500, -0.1523132324218750, -0.2447509765625000, +-0.1082763671875000, -0.2745666503906250, -0.1504516601562500, -0.2700500488281250, +-0.0915222167968750, -0.2725219726562500, -0.0049438476562500, -0.2963256835937500, +-0.0588684082031250, -0.2904663085937500, 0.0387573242187500, -0.2760314941406250, +0.0536499023437500, -0.2923889160156250, 0.0399780273437500, -0.2688293457031250, +0.0700988769531250, -0.2396545410156250, 0.0682983398437500, -0.2611694335937500, +0.0685729980468750, -0.1998901367187500, 0.0611877441406250, -0.2068176269531250, +0.0837707519531250, -0.1916503906250000, 0.1009521484375000, -0.1491088867187500, +0.0831604003906250, -0.1697387695312500, 0.1427307128906250, -0.1200256347656250, +0.1407775878906250, -0.1311645507812500, 0.1442871093750000, -0.0951232910156250, +0.1755371093750000, -0.0542602539062500, 0.1655273437500000, -0.0878295898437500, +0.1899108886718750, 0.0676574707031250, 0.1776428222656250, 0.0289916992187500, +0.2082519531250000, 0.0807189941406250, 0.2831726074218750, 0.3150939941406250, +0.4269409179687500}, +{-0.0000610351562500, -0.0066833496093750, -0.0000915527343750, -0.0082397460937500, +-0.0000915527343750, -0.0084228515625000, -0.0000610351562500, -0.0087280273437500, +-0.0000305175781250, -0.0069580078125000, -0.0000305175781250, -0.0075073242187500, +-0.0000610351562500, -0.0091552734375000, 0.0000000000000000, 0.0037536621093750, +0.0000915527343750, -0.0028381347656250, 0.0000305175781250, 0.0072631835937500, +0.0000305175781250, 0.0242614746093750, 0.0000305175781250, 0.0131225585937500, +0.0000610351562500, 0.0325622558593750, 0.0000305175781250, 0.0376586914062500, +-0.0000610351562500, 0.0304260253906250, 0.0003967285156250, 0.0338745117187500, +0.0002136230468750, 0.0382080078125000, -0.0032348632812500, 0.0223693847656250, +-0.0006103515625000, 0.0196228027343750, -0.0057678222656250, 0.0325622558593750, +-0.0125732421875000, 0.0282287597656250, -0.0075988769531250, 0.0217895507812500, +-0.0164489746093750, 0.0802307128906250, -0.0219726562500000, 0.0603027343750000, +-0.0087890625000000, 0.0881042480468750, -0.0054931640625000, 0.1505126953125000, +-0.0144348144531250, 0.1177673339843750, 0.0318298339843750, 0.1575927734375000, +0.0243530273437500, 0.1748352050781250, 0.0302429199218750, 0.1487426757812500, +0.0685424804687500, 0.1437072753906250, 0.0556335449218750, 0.1566467285156250, +0.0341186523437500, 0.1045837402343750, 0.0570678710937500, 0.1112976074218750, +0.0263366699218750, 0.0979919433593750, -0.0214843750000000, 0.0609741210937500, +0.0082702636718750, 0.0777893066406250, -0.0272521972656250, 0.0375366210937500, +-0.0487976074218750, 0.0393066406250000, -0.0165100097656250, 0.0314025878906250, +-0.0002136230468750, 0.0058593750000000, -0.0227050781250000, 0.0186157226562500, +0.0275878906250000, -0.0070800781250000, 0.0407104492187500, -0.0026245117187500, +0.0090942382812500, -0.0148620605468750, 0.0145568847656250, -0.0328674316406250, +0.0313415527343750, -0.0201110839843750, -0.0708618164062500, -0.0822448730468750, +-0.0558166503906250, -0.0644226074218750, -0.0687255859375000, -0.0978698730468750, +-0.1482849121093750, -0.1586914062500000, -0.1222229003906250, -0.1221008300781250, +-0.0950927734375000, -0.2061157226562500, -0.1321716308593750, -0.2056579589843750, +-0.0820312500000000, -0.2085571289062500, -0.0124511718750000, -0.2552795410156250, +-0.0551452636718750, -0.2394409179687500, 0.0296325683593750, -0.2492980957031250, +0.0408020019531250, -0.2570800781250000, 0.0315856933593750, -0.2480468750000000, +0.0601196289062500, -0.2431335449218750, 0.0563964843750000, -0.2482910156250000, +0.0599975585937500, -0.2374572753906250, 0.0527648925781250, -0.2377624511718750, +0.0724792480468750, -0.2374267578125000, 0.0895996093750000, -0.2317810058593750, +0.0733032226562500, -0.2341308593750000, 0.1263427734375000, -0.2322998046875000, +0.1228942871093750, -0.2356567382812500, 0.1276245117187500, -0.2278137207031250, +0.1573791503906250, -0.2249450683593750, 0.1475219726562500, -0.2317810058593750, +0.1755676269531250, -0.1867675781250000, 0.1591491699218750, -0.2017517089843750, +0.2025146484375000, -0.1761169433593750, 0.2437133789062500, -0.1296081542968750, +0.2056274414062500, -0.1569213867187500, 0.3550415039062500, -0.0964965820312500, +0.3406982421875000, -0.1009216308593750, 0.3468322753906250, -0.0876464843750000, +0.4879455566406250, -0.0166320800781250, 0.2804870605468750, -0.1459655761718750, +-0.0443725585937500, -0.0640563964843750, 0.0705871582031250, -0.0933227539062500, +-0.0208435058593750, -0.0542297363281250, -0.2004394531250000, -0.0153808593750000, +-0.1227722167968750, -0.0430297851562500, -0.2338256835937500, 0.0939025878906250, +-0.2531738281250000, 0.0529479980468750, -0.2400817871093750, 0.1249084472656250, +-0.2808837890625000, 0.2701110839843750, -0.2713623046875000, 0.1908569335937500, +-0.2500915527343750, 0.3189697265625000, -0.2668457031250000, 0.3504333496093750, +-0.2476196289062500, 0.3070983886718750, -0.2112426757812500, 0.3298645019531250, +-0.2314758300781250, 0.3446655273437500, -0.2162475585937500, 0.2617797851562500, +-0.1929016113281250, 0.2711181640625000, -0.2364501953125000, 0.2572937011718750, +-0.2623596191406250, 0.2043457031250000, -0.2268371582031250, 0.2240600585937500, +-0.3414916992187500, 0.1788024902343750, -0.3336181640625000, 0.1894226074218750, +-0.3349609375000000, 0.1587219238281250, -0.4097595214843750, 0.1131896972656250, +-0.3888549804687500, 0.1441955566406250, -0.3445434570312500, 0.0537414550781250, +-0.3872070312500000, 0.0574951171875000, -0.3265075683593750, 0.0462951660156250, +-0.2442932128906250, -0.0075378417968750, -0.2998046875000000, 0.0130310058593750, +-0.1638488769531250, -0.0263977050781250, -0.1662902832031250, -0.0207824707031250, +-0.1558837890625000, -0.0411071777343750, -0.0801696777343750, -0.0769653320312500, +-0.1076660156250000, -0.0529174804687500, -0.0589904785156250, -0.1027832031250000, +-0.0626220703125000, -0.1130371093750000, -0.0401000976562500, -0.0936584472656250, +-0.0038452148437500, -0.1064758300781250, -0.0299987792968750, -0.1141967773437500, +0.0498962402343750, -0.0502624511718750, 0.0380859375000000, -0.0625915527343750, +0.0546264648437500, -0.0474853515625000, 0.1125793457031250, 0.0059204101562500, +0.0844421386718750, -0.0130004882812500, 0.1262817382812500, -0.0000305175781250, +0.1325378417968750, 0.0079650878906250, 0.1235351562500000, 0.0062561035156250, +0.1403503417968750, 0.0024719238281250, 0.1392211914062500, 0.0015258789062500, +0.1076660156250000, 0.0287780761718750, 0.1262207031250000, 0.0200500488281250, +0.1004333496093750, 0.0287780761718750, 0.0569763183593750, 0.0588989257812500, +0.0845336914062500, 0.0477905273437500, 0.0350036621093750, 0.0390319824218750, +0.0284423828125000, 0.0548706054687500, 0.0374755859375000, 0.0325622558593750, +0.0209960937500000, 0.0024108886718750, 0.0214233398437500, 0.0207519531250000, +0.0351867675781250, -0.0121154785156250, 0.0333251953125000, -0.0192871093750000, +0.0321655273437500, -0.0104370117187500, 0.0401000976562500, -0.0172729492187500, +0.0390014648437500, -0.0195312500000000, 0.0308227539062500, -0.0059204101562500, +0.0346374511718750, -0.0066833496093750, 0.0308532714843750, -0.0063171386718750, +0.0207519531250000, 0.0011901855468750, 0.0249938964843750, -0.0007324218750000, +0.0241088867187500, -0.0002746582031250, 0.0204772949218750, 0.0004882812500000, +0.0252685546875000, 0.0002136230468750, 0.0315246582031250, -0.0000610351562500, +0.0285644531250000, -0.0000610351562500, 0.0314941406250000, 0.0000915527343750, +0.0375976562500000, 0.0000915527343750, 0.0299072265625000, 0.0000305175781250, +0.0268859863281250, 0.0000915527343750, 0.0365295410156250, 0.0000915527343750, +0.0083923339843750, 0.0000305175781250, 0.0192871093750000, 0.0000915527343750, +0.0095825195312500, 0.0000610351562500, -0.0150146484375000, 0.0000610351562500, +0.0027160644531250, 0.0000610351562500, -0.0282897949218750, 0.0001220703125000, +-0.0230407714843750, 0.0000305175781250, -0.0263977050781250, 0.0000610351562500, +-0.0446777343750000, 0.0000610351562500, -0.0294494628906250, 0.0000305175781250, +-0.0469055175781250, 0.0000915527343750, -0.0432739257812500, 0.0001220703125000, +-0.0425109863281250, 0.0001220703125000, -0.0514221191406250, 0.0001220703125000, +-0.0422363281250000, 0.0000915527343750, -0.0498046875000000, 0.0000915527343750, +-0.0473022460937500, 0.0001220703125000, -0.0444946289062500, 0.0000915527343750, +-0.0474548339843750, 0.0000915527343750, -0.0425109863281250, 0.0001220703125000, +-0.0384826660156250, 0.0001220703125000, -0.0364379882812500, 0.0001220703125000, +-0.0309143066406250, 0.0000610351562500, -0.0254516601562500, 0.0000305175781250, +-0.0231018066406250, 0.0000610351562500, -0.0131530761718750, 0.0000305175781250, +-0.0139465332031250, 0.0000305175781250, -0.0056152343750000, 0.0000000000000000, +0.0051879882812500, 0.0000000000000000, 0.0014038085937500, 0.0000305175781250, +0.0202026367187500, -0.0001220703125000, 0.0192565917968750, -0.0000610351562500, +0.0222473144531250, -0.0000610351562500, 0.0357666015625000, -0.0001525878906250, +0.0321655273437500, -0.0001525878906250, 0.0339355468750000, 0.0000610351562500, +0.0388183593750000, 0.0000915527343750, 0.0306701660156250, -0.0003356933593750, +0.0250549316406250, 0.0000610351562500, 0.0306396484375000, 0.0001831054687500, +0.0060424804687500, -0.0033874511718750, 0.0111694335937500, -0.0012512207031250, +-0.0007324218750000, -0.0046386718750000, -0.0239562988281250, -0.0098876953125000, +-0.0136108398437500, -0.0059204101562500, -0.0428771972656250, -0.0114135742187500, +-0.0428161621093750, -0.0147094726562500, -0.0468444824218750, -0.0071105957031250, +-0.0644226074218750, -0.0057678222656250, -0.0584411621093750, -0.0111694335937500, +-0.0719299316406250, 0.0155944824218750, -0.0725708007812500, 0.0084228515625000, +-0.0732421875000000, 0.0158996582031250, -0.0809936523437500, 0.0404052734375000, +-0.0778503417968750, 0.0285644531250000, -0.0756530761718750, 0.0347290039062500, +-0.0799255371093750, 0.0449523925781250, -0.0737609863281250, 0.0304260253906250, +-0.0644836425781250, 0.0191345214843750, -0.0699157714843750, 0.0309753417968750, +-0.0675354003906250, 0.0039367675781250, -0.0582580566406250, 0.0027770996093750, +-0.0796508789062500, 0.0052795410156250, -0.0942382812500000, -0.0059814453125000, +-0.0802917480468750, -0.0044555664062500, -0.1448974609375000, -0.0052795410156250, +-0.1387939453125000, -0.0022277832031250, -0.1529235839843750, -0.0114746093750000, +-0.2002868652343750, -0.0177307128906250, -0.1819763183593750, -0.0092163085937500, +-0.2021179199218750, -0.0360412597656250, -0.2097167968750000, -0.0343627929687500, +-0.2033081054687500, -0.0335083007812500, -0.2048645019531250, -0.0491638183593750, +-0.2058715820312500, -0.0458068847656250, -0.1986389160156250, -0.0396728515625000, +-0.2003479003906250, -0.0418701171875000, -0.1944580078125000, -0.0447082519531250, +-0.1877441406250000, -0.0402221679687500, -0.1917114257812500, -0.0380554199218750, +-0.1691894531250000, -0.0536193847656250, -0.1762084960937500, -0.0545349121093750, +-0.1592712402343750, -0.0420227050781250, -0.1352233886718750, -0.0507507324218750, +-0.1499938964843750, -0.0563049316406250, -0.1005249023437500, 0.0174865722656250, +-0.1086425781250000, -0.0131530761718750, -0.0915527343750000, 0.0324096679687500, +-0.0523681640625000, 0.1140136718750000, -0.0725402832031250, 0.0619201660156250, +-0.0226440429687500, 0.1635437011718750, -0.0252685546875000, 0.1689453125000000, +-0.0164184570312500, 0.1694335937500000, 0.0160522460937500, 0.2198486328125000, +0.0012207031250000, 0.2029418945312500, 0.0267333984375000, 0.2097473144531250, +0.0275878906250000, 0.2224731445312500, 0.0302124023437500, 0.2022399902343750, +0.0434875488281250, 0.1837158203125000, 0.0429687500000000, 0.1853332519531250, +0.0733032226562500, 0.1293945312500000, 0.0573730468750000, 0.1478576660156250, +0.0725097656250000, 0.1401062011718750, 0.1020507812500000, 0.0932312011718750, +0.0808715820312500, 0.1100769042968750, 0.1386413574218750, 0.0938720703125000, +0.1264343261718750, 0.0858764648437500, 0.1499938964843750, 0.0874633789062500, +0.1962585449218750, 0.0892944335937500, 0.1658325195312500, 0.0884704589843750, +0.2456665039062500, 0.0612182617187500, 0.2401428222656250, 0.0740356445312500, +0.2419128417968750, 0.0517883300781250, 0.2987976074218750, 0.0139160156250000, +0.2802429199218750, 0.0338134765625000, 0.2299499511718750, -0.0025634765625000, +0.2796630859375000}, +{-0.0432434082031250, -0.0022888183593750, -0.0473937988281250, -0.0005798339843750, +-0.0372924804687500, -0.0035400390625000, -0.0195922851562500, -0.0074768066406250, +-0.0276184082031250, -0.0042419433593750, -0.0001831054687500, -0.0101623535156250, +-0.0009460449218750, -0.0120239257812500, 0.0059509277343750, -0.0069580078125000, +0.0264282226562500, -0.0079345703125000, 0.0195617675781250, -0.0110168457031250, +0.0300598144531250, 0.0093688964843750, 0.0356750488281250, 0.0025329589843750, +0.0284118652343750, 0.0109252929687500, 0.0267639160156250, 0.0316772460937500, +0.0299072265625000, 0.0202026367187500, 0.0073852539062500, 0.0314941406250000, +0.0125427246093750, 0.0391540527343750, -0.0004577636718750, 0.0276489257812500, +-0.0216674804687500, 0.0228576660156250, -0.0098876953125000, 0.0312500000000000, +-0.0452880859375000, 0.0073852539062500, -0.0448608398437500, 0.0085144042968750, +-0.0473937988281250, 0.0086975097656250, -0.0699157714843750, -0.0043029785156250, +-0.0626220703125000, -0.0010986328125000, -0.0559997558593750, -0.0028381347656250, +-0.0661315917968750, -0.0017395019531250, -0.0505065917968750, -0.0082092285156250, +-0.0284118652343750, -0.0118713378906250, -0.0408325195312500, -0.0058593750000000, +-0.0243835449218750, -0.0294494628906250, -0.0105590820312500, -0.0256958007812500, +-0.0390625000000000, -0.0278930664062500, -0.0544433593750000, -0.0450744628906250, +-0.0361938476562500, -0.0393676757812500, -0.1084289550781250, -0.0384826660156250, +-0.1024780273437500, -0.0420532226562500, -0.1158752441406250, -0.0412902832031250, +-0.1649780273437500, -0.0364685058593750, -0.1460876464843750, -0.0368957519531250, +-0.1759033203125000, -0.0463256835937500, -0.1808471679687500, -0.0445861816406250, +-0.1784667968750000, -0.0395812988281250, -0.1895141601562500, -0.0493469238281250, +-0.1864318847656250, -0.0499877929687500, -0.1863403320312500, -0.0024414062500000, +-0.1887207031250000, -0.0284729003906250, -0.1843872070312500, 0.0131225585937500, +-0.1821899414062500, 0.0764465332031250, -0.1844482421875000, 0.0358886718750000, +-0.1664123535156250, 0.1365661621093750, -0.1744689941406250, 0.1320495605468750, +-0.1587829589843750, 0.1416320800781250, -0.1372680664062500, 0.2015991210937500, +-0.1516418457031250, 0.1759033203125000, -0.1051940917968750, 0.2061767578125000, +-0.1121826171875000, 0.2174377441406250, -0.0961608886718750, 0.1997680664062500, +-0.0603942871093750, 0.2029113769531250, -0.0798950195312500, 0.2110900878906250, +-0.0330505371093750, 0.1577453613281250, -0.0361633300781250, 0.1712951660156250, +-0.0287475585937500, 0.1532592773437500, 0.0066833496093750, 0.0956420898437500, +0.0041198730468750, 0.1042785644531250, 0.0281066894531250, 0.0869750976562500, +0.0200195312500000, 0.0849609375000000, 0.0267639160156250, 0.0874328613281250, +0.0447998046875000, 0.0833129882812500, 0.0332946777343750, 0.0822143554687500, +0.0688781738281250, 0.0632019042968750, 0.0593566894531250, 0.0753784179687500, +0.0767517089843750, 0.0511779785156250, 0.1079406738281250, 0.0184326171875000, +0.0869445800781250, 0.0394592285156250, 0.1424255371093750, -0.0089416503906250, +0.1307678222656250, -0.0133361816406250, 0.1541442871093750, -0.0125427246093750, +0.2007751464843750, -0.0312805175781250, 0.1714172363281250, -0.0273437500000000, +0.2428894042968750, -0.0469360351562500, 0.2447204589843750, -0.0354919433593750, +0.2360229492187500, -0.0615844726562500, 0.2788391113281250, -0.0928344726562500, +0.2718811035156250, -0.0702819824218750, 0.1941223144531250, -0.1405334472656250, +0.2425537109375000, -0.1378479003906250, 0.1672668457031250, -0.1424865722656250, +0.0541381835937500, -0.1849670410156250, 0.1292114257812500, -0.1715698242187500, +-0.0305175781250000, -0.1764526367187500, -0.0422668457031250, -0.1851806640625000, +-0.0287475585937500, -0.1760864257812500, -0.1002502441406250, -0.1696166992187500, +-0.0871887207031250, -0.1752014160156250, -0.0520629882812500, -0.1516113281250000, +-0.0688476562500000, -0.1610412597656250, -0.0561218261718750, -0.1453247070312500, +-0.0175781250000000, -0.1190490722656250, -0.0322875976562500, -0.1375732421875000, +-0.0299377441406250, -0.1000061035156250, -0.0190734863281250, -0.0962829589843750, +-0.0271606445312500, -0.1020202636718750, -0.0402526855468750, -0.0874938964843750, +-0.0337219238281250, -0.0883178710937500, -0.0310668945312500, -0.0998229980468750, +-0.0390930175781250, -0.0974731445312500, -0.0297241210937500, -0.0969543457031250, +-0.0171203613281250, -0.1057739257812500, -0.0257263183593750, -0.1047363281250000, +-0.0119934082031250, -0.0928039550781250, -0.0107727050781250, -0.0987854003906250, +-0.0096740722656250, -0.0885925292968750, -0.0050964355468750, -0.0720825195312500, +-0.0077819824218750, -0.0803527832031250, 0.0095520019531250, -0.0596313476562500, +0.0017700195312500, -0.0576782226562500, 0.0117492675781250, -0.0548095703125000, +0.0319213867187500, -0.0437622070312500, 0.0188293457031250, -0.0476379394531250, +0.0365905761718750, -0.0392150878906250, 0.0432434082031250, -0.0390014648437500, +0.0312500000000000, -0.0370788574218750, 0.0311279296875000, -0.0310058593750000, +0.0384216308593750, -0.0334472656250000, 0.0086669921875000, -0.0314025878906250, +0.0135803222656250, -0.0288696289062500, 0.0089416503906250, -0.0336303710937500, +-0.0129089355468750, -0.0371093750000000, -0.0039062500000000, -0.0344848632812500, +-0.0100708007812500, -0.0454711914062500, -0.0152282714843750, -0.0451049804687500, +-0.0097351074218750, -0.0456848144531250, -0.0063476562500000, -0.0514526367187500, +-0.0098571777343750, -0.0488891601562500, -0.0024719238281250, -0.0499877929687500, +-0.0018615722656250, -0.0493774414062500, -0.0025634765625000, -0.0464172363281250, +0.0003051757812500, -0.0442810058593750, -0.0003356933593750, -0.0429687500000000, +-0.0004577636718750, -0.0399475097656250, -0.0002136230468750, -0.0365905761718750, +-0.0002441406250000, -0.0360107421875000, -0.0004272460937500, -0.0350646972656250, +-0.0004272460937500, -0.0317077636718750, -0.0003051757812500, -0.0337829589843750, +-0.0003356933593750, -0.0305480957031250, -0.0002441406250000, -0.0302429199218750, +-0.0002136230468750, -0.0324401855468750, -0.0002746582031250, -0.0293273925781250, +-0.0001220703125000, -0.0328674316406250, -0.0001525878906250, -0.0288085937500000, +-0.0001220703125000, -0.0307617187500000, -0.0000610351562500, -0.0354614257812500, +-0.0001220703125000, -0.0304870605468750, -0.0000610351562500, -0.0400085449218750, +-0.0000915527343750, -0.0380554199218750, -0.0000610351562500, -0.0396423339843750, +-0.0000305175781250, -0.0464172363281250, -0.0000305175781250, -0.0431213378906250, +-0.0000305175781250, -0.0510253906250000, 0.0000000000000000, -0.0481262207031250, +-0.0000305175781250, -0.0515441894531250, -0.0000305175781250, -0.0588684082031250, +0.0000000000000000, -0.0540771484375000, -0.0002136230468750, -0.0663452148437500, +-0.0001831054687500, -0.0637207031250000, -0.0002136230468750, -0.0681762695312500, +-0.0002441406250000, -0.0767211914062500, -0.0002441406250000, -0.0711059570312500, +-0.0006713867187500, -0.0926818847656250, 0.0000915527343750, -0.0823059082031250, +-0.0021362304687500, -0.1008300781250000, -0.0035705566406250, -0.1256713867187500, +-0.0019226074218750, -0.1053161621093750, -0.0107421875000000, -0.1638793945312500, +-0.0102539062500000, -0.1560363769531250, -0.0097351074218750, -0.1595764160156250, +-0.0173645019531250, -0.2009582519531250, -0.0157775878906250, -0.1852111816406250, +0.0028686523437500, -0.1756591796875000, -0.0078735351562500, -0.1991882324218750, +0.0089721679687500, -0.1645507812500000, 0.0380859375000000, -0.1283569335937500, +0.0214843750000000, -0.1588134765625000, 0.0412292480468750, -0.0741577148437500, +0.0559692382812500, -0.0852355957031250, 0.0313415527343750, -0.0668334960937500, +0.0182495117187500, -0.0078125000000000, 0.0359191894531250, -0.0357971191406250, +-0.0153808593750000, 0.0256042480468750, -0.0197448730468750, 0.0170593261718750, +-0.0063171386718750, 0.0416564941406250, -0.0251464843750000, 0.0920715332031250, +-0.0290832519531250, 0.0609130859375000, 0.0128784179687500, 0.1262207031250000, +0.0088500976562500, 0.1330871582031250, 0.0012817382812500, 0.1231079101562500, +0.0283813476562500, 0.1491394042968750, 0.0280151367187500, 0.1484069824218750, +-0.0284729003906250, 0.1230773925781250, -0.0069885253906250, 0.1243896484375000, +-0.0319213867187500, 0.1296081542968750, -0.0968017578125000, 0.1165771484375000, +-0.0678405761718750, 0.1151428222656250, -0.0782165527343750, 0.1435546875000000, +-0.1052551269531250, 0.1406250000000000, -0.0681762695312500, 0.1406555175781250, +-0.0337524414062500, 0.1616210937500000, -0.0609741210937500, 0.1589965820312500, +0.0083312988281250, 0.1353454589843750, 0.0122985839843750, 0.1517333984375000, +0.0094604492187500, 0.1264038085937500, 0.0394897460937500, 0.0914611816406250, +0.0334777832031250, 0.1157531738281250, 0.0404052734375000, 0.0522766113281250, +0.0360412597656250, 0.0591430664062500, 0.0509338378906250, 0.0430908203125000, +0.0650939941406250, 0.0001831054687500, 0.0520324707031250, 0.0222778320312500, +0.0950622558593750, -0.0378417968750000, 0.0923461914062500, -0.0254211425781250, +0.0987243652343750, -0.0550842285156250, 0.1245422363281250, -0.1069030761718750, +0.1156921386718750, -0.0737304687500000, 0.1444091796875000, -0.1673583984375000, +0.1310729980468750, -0.1546020507812500, 0.1659240722656250, -0.1781616210937500, +0.2026062011718750, -0.2509460449218750, 0.1707458496093750, -0.2160034179687500, +0.2867736816406250, -0.2619934082031250, 0.2736816406250000, -0.2829895019531250, +0.2872009277343750, -0.2501220703125000, 0.3753051757812500, -0.2448120117187500, +0.3430175781250000, -0.2636108398437500, 0.3091125488281250, -0.1840209960937500, +0.3626098632812500, -0.1905822753906250, 0.2693786621093750, -0.1889648437500000, +0.1705322265625000, -0.1382751464843750, 0.2453002929687500, -0.1506958007812500, +0.0149536132812500, -0.1689147949218750, 0.0257568359375000, -0.1574707031250000, +0.0114746093750000, -0.1626281738281250, -0.2003479003906250, -0.1940917968750000, +-0.2117309570312500, -0.1367187500000000, -0.1857910156250000, -0.1623229980468750, +-0.2113342285156250, -0.1455688476562500, -0.1856689453125000, -0.1512756347656250, +-0.1480712890625000, -0.1809082031250000, -0.1708374023437500, -0.1771850585937500, +-0.1562500000000000, -0.1291198730468750, -0.1322021484375000, -0.1534729003906250, +-0.1741943359375000, -0.1226806640625000, -0.2003479003906250, -0.0626525878906250, +-0.1680908203125000, -0.0922851562500000, -0.2830505371093750, -0.0327758789062500, +-0.2731628417968750, -0.0376892089843750, -0.2780151367187500, -0.0108032226562500, +-0.3563232421875000, 0.0273437500000000, -0.3321838378906250, -0.0016784667968750, +-0.2918395996093750, 0.1260375976562500, -0.3343200683593750, 0.0991210937500000, +-0.2737121582031250, 0.1425170898437500, -0.1928100585937500, 0.2576904296875000, +-0.2494506835937500, 0.2028503417968750, -0.1259460449218750, 0.2650451660156250, +-0.1245422363281250, 0.2955322265625000, -0.1142578125000000, 0.2557983398437500, +-0.0508728027343750, 0.2449340820312500, -0.0751647949218750, 0.2657165527343750, +-0.0086669921875000, 0.1965637207031250, -0.0271606445312500, 0.1993408203125000, +0.0133361816406250, 0.1895446777343750, 0.0787963867187500, 0.1515197753906250, +0.0341186523437500, 0.1669616699218750, 0.1540222167968750, 0.1183166503906250, +0.1496887207031250, 0.1306762695312500, 0.1507873535156250, 0.1032409667968750, +0.2231140136718750}, +{-0.0170593261718750, 0.0215148925781250, -0.0707092285156250, 0.1256713867187500, +-0.0402832031250000, 0.0727233886718750, -0.0702209472656250, 0.1642761230468750, +-0.0934143066406250, 0.1889343261718750, -0.0598144531250000, 0.1575622558593750, +-0.0405578613281250, 0.1695556640625000, -0.0633239746093750, 0.1809692382812500, +-0.0002441406250000, 0.1284179687500000, -0.0004882812500000, 0.1285400390625000, +-0.0011291503906250, 0.1324462890625000, 0.0300292968750000, 0.1064758300781250, +0.0222167968750000, 0.1106872558593750, 0.0318908691406250, 0.1314086914062500, +0.0294799804687500, 0.1243591308593750, 0.0413208007812500, 0.1323242187500000, +0.0534362792968750, 0.1546020507812500, 0.0426940917968750, 0.1459655761718750, +0.0808105468750000, 0.1460571289062500, 0.0778808593750000, 0.1599426269531250, +0.0845642089843750, 0.1360473632812500, 0.1083068847656250, 0.1174316406250000, +0.0994873046875000, 0.1370544433593750, 0.1263732910156250, 0.0684509277343750, +0.1150512695312500, 0.0802307128906250, 0.1465454101562500, 0.0568237304687500, +0.1804504394531250, 0.0037231445312500, 0.1519470214843750, 0.0329589843750000, +0.2535095214843750, -0.0362548828125000, 0.2426147460937500, -0.0264587402343750, +0.2538146972656250, -0.0517883300781250, 0.3294982910156250, -0.1029968261718750, +0.3020324707031250, -0.0726013183593750, 0.2768859863281250, -0.1672973632812500, +0.3245849609375000, -0.1531372070312500, 0.2445068359375000, -0.1829833984375000, +0.1605224609375000, -0.2620239257812500, 0.2243347167968750, -0.2221984863281250, +0.0238952636718750, -0.2718505859375000, 0.0405883789062500, -0.2971801757812500, +0.0006103515625000, -0.2551574707031250, -0.1369628906250000, -0.2438354492187500, +-0.0778503417968750, -0.2705078125000000, -0.1749267578125000, -0.1752014160156250, +-0.1909179687500000, -0.1793212890625000, -0.1770324707031250, -0.1846313476562500, +-0.2233581542968750, -0.1135559082031250, -0.1650085449218750, -0.2692565917968750, +-0.1531677246093750, -0.1472167968750000, -0.1300659179687500, -0.1773071289062500, +-0.1738891601562500, -0.1700744628906250, -0.2019042968750000, -0.1181945800781250, +-0.1693725585937500, -0.1256103515625000, -0.2754516601562500, -0.1580505371093750, +-0.2689208984375000, -0.1515808105468750, -0.2714538574218750, -0.1469421386718750, +-0.3398132324218750, -0.1721191406250000, -0.3194580078125000, -0.1715393066406250, +-0.2844543457031250, -0.1141357421875000, -0.3194580078125000, -0.1359252929687500, +-0.2674255371093750, -0.1082458496093750, -0.1980285644531250, -0.0481262207031250, +-0.2433776855468750, -0.0767822265625000, -0.1354675292968750, -0.0201416015625000, +-0.1387023925781250, -0.0263977050781250, -0.1206970214843750, 0.0033264160156250, +-0.0603332519531250, 0.0450439453125000, -0.0888977050781250, 0.0137939453125000, +0.0026245117187500, 0.1341247558593750, -0.0213928222656250, 0.1144409179687500, +0.0299987792968750, 0.1449279785156250, 0.1206054687500000, 0.2451477050781250, +0.0627746582031250, 0.2030029296875000, 0.1876525878906250, 0.2363281250000000, +0.1914062500000000, 0.2652893066406250, 0.1813354492187500, 0.2286376953125000, +0.2456665039062500, 0.2049865722656250, 0.2312927246093750, 0.2279052734375000, +0.1817016601562500, 0.1666870117187500, 0.2142944335937500, 0.1671447753906250, +0.1744079589843750, 0.1580810546875000, 0.1017150878906250, 0.1259765625000000, +0.1451110839843750, 0.1402282714843750, 0.0937500000000000, 0.0910644531250000, +0.0684509277343750, 0.1018371582031250, 0.1047363281250000, 0.0795593261718750, +0.1181945800781250, 0.0336303710937500, 0.0932006835937500, 0.0579223632812500, +0.1373596191406250, 0.0065002441406250, 0.1562194824218750, 0.0042724609375000, +0.1199645996093750, 0.0000915527343750, 0.1130371093750000, -0.0250549316406250, +0.1378479003906250, -0.0151062011718750, 0.0481567382812500, -0.0447998046875000, +0.0618286132812500, -0.0406799316406250, 0.0469970703125000, -0.0483703613281250, +-0.0132751464843750, -0.0756835937500000, 0.0146789550781250, -0.0646057128906250, +-0.0346679687500000, -0.0602722167968750, -0.0338745117187500, -0.0764770507812500, +-0.0383605957031250, -0.0524597167968750, -0.0700683593750000, -0.0238952636718750, +-0.0579833984375000, -0.0431518554687500, -0.0651855468750000, -0.0028991699218750, +-0.0751342773437500, 0.0032348632812500, -0.0646057128906250, -0.0034484863281250, +-0.0569458007812500, 0.0072326660156250, -0.0652465820312500, 0.0075378417968750, +-0.0422668457031250, 0.0090637207031250, -0.0465393066406250, 0.0029296875000000, +-0.0400085449218750, 0.0147399902343750, -0.0224609375000000, 0.0279846191406250, +-0.0339965820312500, 0.0169677734375000, -0.0191955566406250, 0.0354309082031250, +-0.0165710449218750, 0.0435485839843750, -0.0232849121093750, 0.0286254882812500, +-0.0209655761718750, 0.0247802734375000, -0.0196838378906250, 0.0339660644531250, +-0.0321655273437500, -0.0000915527343750, -0.0283203125000000, 0.0006408691406250, +-0.0358581542968750, 0.0006408691406250, -0.0472106933593750, -0.0183715820312500, +-0.0385437011718750, -0.0140075683593750, -0.0603942871093750, -0.0090026855468750, +-0.0553894042968750, -0.0130920410156250, -0.0615539550781250, -0.0091552734375000, +-0.0778808593750000, -0.0013732910156250, -0.0669860839843750, -0.0046081542968750, +-0.0896301269531250, -0.0009460449218750, -0.0872192382812500, 0.0003967285156250, +-0.0905456542968750, -0.0004882812500000, -0.1063537597656250, -0.0001220703125000, +-0.0993347167968750, -0.0000610351562500, -0.1076965332031250, -0.0001831054687500, +-0.1111755371093750, -0.0002441406250000, -0.1068725585937500, -0.0002136230468750, +-0.1074523925781250, -0.0001220703125000, -0.1100463867187500, -0.0001220703125000, +-0.0998840332031250, -0.0002136230468750, -0.1024475097656250, -0.0001831054687500, +-0.0984497070312500, -0.0001831054687500, -0.0899963378906250, -0.0002441406250000, +-0.0953674316406250, -0.0002136230468750, -0.0840454101562500, -0.0001525878906250, +-0.0856323242187500, -0.0001831054687500, -0.0825195312500000, -0.0001831054687500, +-0.0746459960937500, -0.0001525878906250, -0.0798339843750000, -0.0001831054687500, +-0.0683898925781250, 0.0000000000000000, -0.0696716308593750, -0.0000305175781250, +-0.0674133300781250, -0.0000915527343750, -0.0593872070312500, 0.0001831054687500, +-0.0625915527343750, 0.0000610351562500, -0.0542907714843750, -0.0009155273437500, +-0.0553283691406250, 0.0001220703125000, -0.0519409179687500, -0.0017700195312500, +-0.0460205078125000, -0.0037231445312500, -0.0496520996093750, -0.0017700195312500, +-0.0353698730468750, -0.0071411132812500, -0.0391235351562500, -0.0071716308593750, +-0.0311584472656250, -0.0056152343750000, -0.0174865722656250, -0.0087585449218750, +-0.0249938964843750, -0.0088500976562500, -0.0007629394531250, 0.0011291503906250, +-0.0034484863281250, -0.0042724609375000, 0.0034790039062500, 0.0037841796875000, +0.0220336914062500, 0.0169982910156250, 0.0138244628906250, 0.0079345703125000, +0.0304565429687500, 0.0231323242187500, 0.0326232910156250, 0.0262145996093750, +0.0276184082031250, 0.0204162597656250, 0.0328979492187500, 0.0241394042968750, +0.0326232910156250, 0.0266723632812500, 0.0158081054687500, 0.0115966796875000, +0.0201110839843750, 0.0150756835937500, 0.0112609863281250, 0.0120849609375000, +-0.0060119628906250, 0.0001831054687500, 0.0008239746093750, 0.0051574707031250, +-0.0160827636718750, 0.0002746582031250, -0.0179748535156250, -0.0005187988281250, +-0.0190429687500000, -0.0027770996093750, -0.0280151367187500, -0.0044860839843750, +-0.0248413085937500, -0.0018615722656250, -0.0223083496093750, -0.0165710449218750, +-0.0267028808593750, -0.0120849609375000, -0.0179748535156250, -0.0175476074218750, +-0.0088195800781250, -0.0321044921875000, -0.0147399902343750, -0.0248413085937500, +0.0054321289062500, -0.0316162109375000, 0.0085754394531250, -0.0351562500000000, +0.0051269531250000, -0.0321044921875000, 0.0140075683593750, -0.0304260253906250, +0.0149536132812500, -0.0320434570312500, -0.0065612792968750, -0.0343017578125000, +-0.0011596679687500, -0.0314941406250000, -0.0056152343750000, -0.0330810546875000, +-0.0259399414062500, -0.0400695800781250, -0.0193176269531250, -0.0368347167968750, +-0.0107421875000000, -0.0223999023437500, -0.0167236328125000, -0.0374755859375000, +-0.0118713378906250, -0.0090942382812500, 0.0023803710937500, 0.0199584960937500, +-0.0020446777343750, -0.0052795410156250, -0.0111083984375000, 0.0762634277343750, +-0.0006408691406250, 0.0629272460937500, -0.0170593261718750, 0.0861206054687500, +-0.0358581542968750, 0.1484680175781250, -0.0222778320312500, 0.1158447265625000, +-0.0690307617187500, 0.1782836914062500, -0.0619201660156250, 0.1813964843750000, +-0.0786437988281250, 0.1765747070312500, -0.1179809570312500, 0.2094116210937500, +-0.0992431640625000, 0.2014465332031250, -0.1349792480468750, 0.1726074218750000, +-0.1378173828125000, 0.1952209472656250, -0.1373901367187500, 0.1625671386718750, +-0.1533813476562500, 0.1159057617187500, -0.1484375000000000, 0.1501464843750000, +-0.1561889648437500, 0.0851440429687500, -0.1572265625000000, 0.0787658691406250, +-0.1559143066406250, 0.0847167968750000, -0.1604309082031250, 0.0603637695312500, +-0.1597290039062500, 0.0639953613281250, -0.1489562988281250, 0.0576782226562500, +-0.1559143066406250, 0.0650024414062500, -0.1433410644531250, 0.0465393066406250, +-0.1228027343750000, 0.0223388671875000, -0.1222229003906250, 0.0255126953125000, +-0.0809936523437500, -0.0244140625000000, -0.0972595214843750, -0.0112304687500000, +-0.0871582031250000, -0.0135192871093750, -0.0533142089843750, -0.0491943359375000, +-0.0722656250000000, -0.0386352539062500, -0.0314331054687500, -0.0513305664062500, +-0.0353393554687500, -0.0494689941406250, -0.0266418457031250, -0.0630798339843750, +-0.0000915527343750, -0.0750122070312500, -0.0148315429687500, -0.0627441406250000, +0.0191955566406250, -0.1190490722656250, 0.0134277343750000, -0.1094970703125000, +0.0256652832031250, -0.1260986328125000, 0.0518188476562500, -0.1736145019531250, +0.0362548828125000, -0.1535034179687500, 0.0800476074218750, -0.1789855957031250, +0.0733642578125000, -0.1887207031250000, 0.0874938964843750, -0.1769409179687500, +0.1195068359375000, -0.1773986816406250, 0.1009521484375000, -0.1817626953125000, +0.1498718261718750, -0.1589355468750000, 0.1415405273437500, -0.1642761230468750, +0.1593933105468750, -0.1526489257812500, 0.2007751464843750, -0.1338195800781250, +0.1771850585937500, -0.1456298828125000, 0.2181701660156250, -0.1039428710937500, +0.2316284179687500, -0.1099243164062500, 0.2047729492187500, -0.1021728515625000, +0.2124633789062500, -0.0682373046875000, 0.2264404296875000, -0.0797119140625000, +0.1165466308593750, -0.0771484375000000, 0.1522521972656250, -0.0668640136718750, +0.0998535156250000, -0.0718688964843750, -0.0114135742187500, -0.0835571289062500, +0.0500793457031250, -0.0770874023437500, -0.0503845214843750, -0.0623779296875000, +-0.0679321289062500, -0.0737915039062500, -0.0433959960937500, -0.0560913085937500, +-0.0715942382812500, -0.0287475585937500, -0.0756835937500000, -0.0437622070312500, +-0.0353698730468750, -0.0175476074218750, -0.0414123535156250, -0.0105895996093750, +-0.0401611328125000, -0.0171203613281250, -0.0142517089843750, -0.0122375488281250, +-0.0212402343750000, -0.0096740722656250, -0.0259704589843750, -0.0178833007812500, +-0.0205993652343750, -0.0194396972656250, -0.0220031738281250, -0.0134582519531250, +-0.0300903320312500, -0.0144348144531250, -0.0278930664062500, -0.0163269042968750, +-0.0196533203125000}, +{-0.0095214843750000, -0.0146484375000000, -0.0112304687500000, 0.0530395507812500, +-0.0105285644531250, 0.0381774902343750, -0.0069885253906250, 0.0635070800781250, +-0.0061340332031250, 0.1203613281250000, -0.0090332031250000, 0.0881652832031250, +-0.0016479492187500, 0.1566467285156250, 0.0017089843750000, 0.1563720703125000, +-0.0036926269531250, 0.1584167480468750, -0.0052490234375000, 0.1990356445312500, +-0.0013427734375000, 0.1842346191406250, -0.0124511718750000, 0.1747131347656250, +-0.0091552734375000, 0.1960144042968750, -0.0191040039062500, 0.1636352539062500, +-0.0292358398437500, 0.1278381347656250, -0.0207214355468750, 0.1557312011718750, +-0.0628051757812500, 0.0860900878906250, -0.0527648925781250, 0.0855102539062500, +-0.0686035156250000, 0.0888061523437500, -0.1067199707031250, 0.0556945800781250, +-0.0883178710937500, 0.0634460449218750, -0.1214904785156250, 0.0597229003906250, +-0.1245727539062500, 0.0627136230468750, -0.1250000000000000, 0.0464477539062500, +-0.1397705078125000, 0.0365905761718750, -0.1344909667968750, 0.0510559082031250, +-0.1444702148437500, -0.0057983398437500, -0.1448364257812500, 0.0016174316406250, +-0.1435852050781250, -0.0061340332031250, -0.1509399414062500, -0.0510559082031250, +-0.1492614746093750, -0.0450134277343750, -0.1307983398437500, -0.0532531738281250, +-0.1425781250000000, -0.0511779785156250, -0.1310729980468750, -0.0589904785156250, +-0.1109008789062500, -0.0652770996093750, -0.1255798339843750, -0.0584106445312500, +-0.0847167968750000, -0.1064147949218750, -0.0911254882812500, -0.0942077636718750, +-0.0798950195312500, -0.1152954101562500, -0.0502929687500000, -0.1620788574218750, +-0.0668029785156250, -0.1387939453125000, -0.0293579101562500, -0.1744689941406250, +-0.0330810546875000, -0.1838989257812500, -0.0238342285156250, -0.1722106933593750, +0.0015258789062500, -0.1788635253906250, -0.0118713378906250, -0.1816711425781250, +0.0231933593750000, -0.1545715332031250, 0.0170593261718750, -0.1610412597656250, +0.0312500000000000, -0.1490478515625000, 0.0592346191406250, -0.1253051757812500, +0.0415954589843750, -0.1370239257812500, 0.0858459472656250, -0.1040344238281250, +0.0799255371093750, -0.1087036132812500, 0.0924987792968750, -0.0960388183593750, +0.1243896484375000, -0.0682067871093750, 0.1075134277343750, -0.0834045410156250, +0.1515808105468750, -0.0560302734375000, 0.1452636718750000, -0.0513610839843750, +0.1585998535156250, -0.0553894042968750, 0.1955871582031250, -0.0484924316406250, +0.1771850585937500, -0.0475158691406250, 0.1998291015625000, -0.0386352539062500, +0.2163696289062500, -0.0465393066406250, 0.1821899414062500, -0.0331115722656250, +0.1724853515625000, -0.0144348144531250, 0.1954040527343750, -0.0273132324218750, +0.0812683105468750, -0.0044250488281250, 0.1106872558593750, 0.0007324218750000, +0.0696411132812500, -0.0059814453125000, -0.0349426269531250, -0.0028076171875000, +0.0184020996093750, -0.0002746582031250, -0.0522766113281250, -0.0039672851562500, +-0.0714111328125000, -0.0092773437500000, -0.0469970703125000, 0.0023193359375000, +-0.0581970214843750, 0.0093688964843750, -0.0665283203125000, 0.0000915527343750, +-0.0293884277343750, 0.0321350097656250, -0.0325622558593750, 0.0292358398437500, +-0.0339965820312500, 0.0356445312500000, -0.0135192871093750, 0.0597229003906250, +-0.0179443359375000, 0.0506591796875000, -0.0229492187500000, 0.0557250976562500, +-0.0194702148437500, 0.0645446777343750, -0.0189514160156250, 0.0491943359375000, +-0.0244750976562500, 0.0370483398437500, -0.0238952636718750, 0.0464172363281250, +-0.0146789550781250, 0.0128173828125000, -0.0190734863281250, 0.0125427246093750, +-0.0146789550781250, 0.0086975097656250, -0.0044860839843750, -0.0112609863281250, +-0.0097351074218750, -0.0050354003906250, -0.0017700195312500, -0.0105285644531250, +-0.0018005371093750, -0.0148620605468750, 0.0007934570312500, -0.0093688964843750, +0.0050659179687500, -0.0067749023437500, 0.0012817382812500, -0.0093078613281250, +0.0151977539062500, 0.0051574707031250, 0.0124511718750000, 0.0025634765625000, +0.0151062011718750, 0.0091552734375000, 0.0272521972656250, 0.0225830078125000, +0.0222167968750000, 0.0171508789062500, 0.0200805664062500, 0.0320434570312500, +0.0266723632812500, 0.0326538085937500, 0.0174865722656250, 0.0342712402343750, +0.0072326660156250, 0.0427856445312500, 0.0157470703125000, 0.0398559570312500, +-0.0023193359375000, 0.0429687500000000, -0.0027160644531250, 0.0438232421875000, +-0.0012817382812500, 0.0420837402343750, -0.0099792480468750, 0.0418090820312500, +-0.0080566406250000, 0.0416564941406250, -0.0052490234375000, 0.0386352539062500, +-0.0074768066406250, 0.0380554199218750, -0.0053710937500000, 0.0360717773437500, +-0.0012512207031250, 0.0333251953125000, -0.0033569335937500, 0.0333862304687500, +-0.0005493164062500, 0.0297546386718750, 0.0000305175781250, 0.0280761718750000, +-0.0003967285156250, 0.0265808105468750, 0.0003356933593750, 0.0249938964843750, +0.0002136230468750, 0.0251770019531250, 0.0001525878906250, 0.0225524902343750, +0.0002136230468750, 0.0233459472656250, -0.0000610351562500, 0.0201416015625000, +0.0000000000000000, 0.0173950195312500, 0.0000915527343750, 0.0204467773437500, +-0.0023193359375000, 0.0104064941406250, -0.0008850097656250, 0.0123901367187500, +-0.0038452148437500, 0.0094909667968750, -0.0077209472656250, 0.0009155273437500, +-0.0049133300781250, 0.0043640136718750, -0.0109863281250000, -0.0020446777343750, +-0.0135192871093750, -0.0034484863281250, -0.0069580078125000, -0.0030212402343750, +-0.0069274902343750, -0.0046386718750000, -0.0106811523437500, -0.0046081542968750, +0.0160827636718750, -0.0077209472656250, 0.0107421875000000, -0.0047302246093750, +0.0168151855468750, -0.0096435546875000, 0.0417480468750000, -0.0148925781250000, +0.0332336425781250, -0.0101623535156250, 0.0245666503906250, -0.0268554687500000, +0.0365905761718750, -0.0216674804687500, 0.0183410644531250, -0.0274047851562500, +-0.0084228515625000, -0.0414733886718750, 0.0072937011718750, -0.0324401855468750, +-0.0067138671875000, -0.0516662597656250, -0.0198974609375000, -0.0514526367187500, +-0.0029907226562500, -0.0520629882812500, 0.0122375488281250, -0.0643310546875000, +-0.0004882812500000, -0.0608215332031250, 0.0107421875000000, -0.0553894042968750, +0.0263366699218750, -0.0619812011718750, -0.0002746582031250, -0.0522766113281250, +-0.0205383300781250, -0.0405883789062500, 0.0004577636718750, -0.0498657226562500, +-0.0513610839843750, -0.0280456542968750, -0.0582275390625000, -0.0310363769531250, +-0.0423278808593750, -0.0248718261718750, -0.0580749511718750, -0.0075683593750000, +-0.0633239746093750, -0.0178833007812500, -0.0180053710937500, -0.0079345703125000, +-0.0267944335937500, 0.0039978027343750, -0.0180969238281250, -0.0221252441406250, +0.0163269042968750, -0.0375976562500000, 0.0034484863281250, -0.0195617675781250, +0.0184936523437500, -0.0892028808593750, 0.0201721191406250, -0.0960998535156250, +0.0264892578125000, -0.0773315429687500, 0.0348205566406250, -0.1069335937500000, +0.0274047851562500, -0.1136169433593750, 0.0567321777343750, -0.0253906250000000, +0.0523681640625000, -0.0517578125000000, 0.0585327148437500, -0.0179443359375000, +0.0792846679687500, 0.0665893554687500, 0.0712585449218750, 0.0300903320312500, +0.0924682617187500, 0.0951232910156250, 0.0856628417968750, 0.1028747558593750, +0.1073608398437500, 0.0994873046875000, 0.1299133300781250, 0.1283874511718750, +0.1104431152343750, 0.1201171875000000, 0.1891174316406250, 0.1105651855468750, +0.1777343750000000, 0.1227111816406250, 0.1921997070312500, 0.1076660156250000, +0.2556152343750000, 0.0843200683593750, 0.2303466796875000, 0.0985412597656250, +0.2253112792968750, 0.0814819335937500, 0.2597351074218750, 0.0728759765625000, +0.2004699707031250, 0.0838623046875000, 0.1472473144531250, 0.0887756347656250, +0.1937255859375000, 0.0831298828125000, 0.0442504882812500, 0.0968933105468750, +0.0614624023437500, 0.1031799316406250, 0.0268554687500000, 0.0900268554687500, +-0.0800781250000000, 0.0902404785156250, -0.0313110351562500, 0.0988464355468750, +-0.1223449707031250, 0.0451660156250000, -0.1304016113281250, 0.0628662109375000, +-0.1287841796875000, 0.0325012207031250, -0.1717834472656250, -0.0226745605468750, +-0.1587524414062500, 0.0087890625000000, -0.1589355468750000, -0.0664978027343750, +-0.1692810058593750, -0.0607910156250000, -0.1560058593750000, -0.0795898437500000, +-0.1391601562500000, -0.1272583007812500, -0.1499328613281250, -0.1007995605468750, +-0.1436157226562500, -0.1806030273437500, -0.1295166015625000, -0.1689453125000000, +-0.1529846191406250, -0.1829528808593750, -0.1945190429687500, -0.2794799804687500, +-0.2567749023437500, -0.1045227050781250, -0.2362670898437500, -0.1960449218750000, +-0.2692871093750000, -0.1592407226562500, -0.2286987304687500, -0.1919555664062500, +-0.1848449707031250, -0.2559814453125000, -0.2142028808593750, -0.2287902832031250, +-0.1399841308593750, -0.2347412109375000, -0.1477050781250000, -0.2653808593750000, +-0.1213684082031250, -0.2173461914062500, -0.0712585449218750, -0.1712036132812500, +-0.1009216308593750, -0.2088623046875000, 0.0099487304687500, -0.1230468750000000, +-0.0143737792968750, -0.1119689941406250, 0.0331726074218750, -0.1287536621093750, +0.1355285644531250, -0.1018676757812500, 0.0786132812500000, -0.0996398925781250, +0.1739501953125000, -0.1281738281250000, 0.1957092285156250, -0.1319580078125000, +0.1601257324218750, -0.1153869628906250, 0.1822814941406250, -0.1215515136718750, +0.1976928710937500, -0.1312561035156250, 0.1036376953125000, -0.0705261230468750, +0.1240844726562500, -0.0829467773437500, 0.1044311523437500, -0.0645751953125000, +0.0282287597656250, -0.0162963867187500, 0.0602722167968750, -0.0373229980468750, +0.0393676757812500, 0.0132141113281250, 0.0186462402343750, 0.0030517578125000, +0.0462646484375000, 0.0354003906250000, 0.0624694824218750, 0.0820922851562500, +0.0442504882812500, 0.0487060546875000, 0.1031799316406250, 0.1494445800781250, +0.1027221679687500, 0.1454467773437500, 0.0941467285156250, 0.1496887207031250, +0.1282958984375000, 0.2120666503906250, 0.1245117187500000, 0.1932373046875000, +0.0619812011718750, 0.1792297363281250, 0.0896911621093750, 0.1993103027343750, +0.0598144531250000, 0.1745605468750000, -0.0127868652343750, 0.1398010253906250, +0.0228271484375000, 0.1593933105468750, -0.0067749023437500, 0.1154479980468750, +-0.0252380371093750, 0.1166076660156250, -0.0121154785156250, 0.1057739257812500, +-0.0024108886718750, 0.0795898437500000, -0.0090637207031250, 0.0936889648437500, +-0.0205383300781250, 0.0462036132812500, -0.0073242187500000, 0.0529785156250000, +-0.0216064453125000, 0.0396118164062500, -0.0463562011718750, 0.0022888183593750, +-0.0317993164062500, 0.0191955566406250, -0.0508422851562500, -0.0110168457031250, +-0.0562744140625000, -0.0118103027343750, -0.0515441894531250, -0.0178527832031250, +-0.0563659667968750, -0.0352478027343750, -0.0567626953125000, -0.0256347656250000, +-0.0432128906250000, -0.0508728027343750, -0.0518798828125000, -0.0531005859375000, +-0.0395202636718750, -0.0461120605468750, -0.0191650390625000, -0.0576477050781250, +-0.0332946777343750, -0.0592346191406250, -0.0139160156250000, -0.0261230468750000, +-0.0074768066406250, -0.0356445312500000, -0.0183105468750000, -0.0246582031250000, +-0.0178527832031250, 0.0068359375000000, -0.0130004882812500, -0.0065002441406250, +-0.0375366210937500, 0.0052490234375000, -0.0327758789062500, 0.0106811523437500, +-0.0420532226562500}, +{-0.1488037109375000, 0.0900268554687500, -0.1390380859375000, 0.0805358886718750, +-0.1278991699218750, 0.0834350585937500, -0.1361083984375000, 0.0891418457031250, +-0.1340637207031250, 0.0383300781250000, -0.1204833984375000, 0.0578308105468750, +-0.1478881835937500, 0.0262451171875000, -0.1683959960937500, -0.0291137695312500, +-0.1472167968750000, 0.0047607421875000, -0.2224731445312500, -0.0701293945312500, +-0.2181091308593750, -0.0682067871093750, -0.2179870605468750, -0.0743713378906250, +-0.2815246582031250, -0.1452941894531250, -0.2016296386718750, 0.0112304687500000, +-0.1210327148437500, -0.0814514160156250, -0.1589050292968750, -0.0516662597656250, +-0.1122436523437500, -0.0823059082031250, -0.0593566894531250, -0.1286315917968750, +-0.0947570800781250, -0.1052246093750000, 0.0245056152343750, -0.1766052246093750, +0.0028076171875000, -0.1683044433593750, 0.0419921875000000, -0.1797790527343750, +0.1428527832031250, -0.2362976074218750, 0.0904846191406250, -0.2143859863281250, +0.1668701171875000, -0.2037658691406250, 0.1932373046875000, -0.2324218750000000, +0.1535949707031250, -0.1901855468750000, 0.1577758789062500, -0.1394958496093750, +0.1777954101562500, -0.1752624511718750, 0.0826721191406250, -0.1066894531250000, +0.0964965820312500, -0.0934753417968750, 0.0856933593750000, -0.1106567382812500, +0.0180358886718750, -0.0957946777343750, 0.0430603027343750, -0.0907287597656250, +0.0425109863281250, -0.1102600097656250, 0.0224609375000000, -0.1179504394531250, +0.0442199707031250, -0.0980224609375000, 0.0700683593750000, -0.0940246582031250, +0.0525817871093750, -0.1073303222656250, 0.0828247070312500, -0.0468139648437500, +0.0850219726562500, -0.0552978515625000, 0.0830688476562500, -0.0404663085937500, +0.0991210937500000, 0.0018310546875000, 0.0931091308593750, -0.0167541503906250, +0.0733032226562500, 0.0326538085937500, 0.0932312011718750, 0.0210266113281250, +0.0586242675781250, 0.0518493652343750, 0.0162658691406250, 0.1007995605468750, +0.0481262207031250, 0.0679016113281250, -0.0248107910156250, 0.1490173339843750, +-0.0280761718750000, 0.1533508300781250, -0.0291137695312500, 0.1478271484375000, +-0.0613098144531250, 0.1880798339843750, -0.0507202148437500, 0.1809082031250000, +-0.0800170898437500, 0.1530456542968750, -0.0724182128906250, 0.1684265136718750, +-0.0828857421875000, 0.1484375000000000, -0.1138305664062500, 0.1122131347656250, +-0.0966186523437500, 0.1298217773437500, -0.0942687988281250, 0.0917968750000000, +-0.1158447265625000, 0.0939025878906250, -0.0841979980468750, 0.0820007324218750, +-0.0515441894531250, 0.0569152832031250, -0.0797729492187500, 0.0718994140625000, +-0.0190734863281250, 0.0269775390625000, -0.0186767578125000, 0.0310363769531250, +-0.0192260742187500, 0.0230407714843750, 0.0114746093750000, -0.0075988769531250, +-0.0003662109375000, 0.0045471191406250, 0.0002136230468750, -0.0173950195312500, +0.0119628906250000, -0.0164184570312500, -0.0101013183593750, -0.0237121582031250, +-0.0270690917968750, -0.0402526855468750, -0.0098266601562500, -0.0305175781250000, +-0.0647277832031250, -0.0488891601562500, -0.0600891113281250, -0.0548095703125000, +-0.0673217773437500, -0.0420532226562500, -0.1019287109375000, -0.0425109863281250, +-0.0861511230468750, -0.0500183105468750, -0.1040039062500000, -0.0137023925781250, +-0.1094360351562500, -0.0174865722656250, -0.1007385253906250, -0.0141601562500000, +-0.1041564941406250, 0.0099182128906250, -0.1077270507812500, 0.0029907226562500, +-0.0834350585937500, 0.0061340332031250, -0.0950622558593750, 0.0070800781250000, +-0.0769042968750000, 0.0115966796875000, -0.0512390136718750, 0.0142211914062500, +-0.0732421875000000, 0.0095825195312500, -0.0180358886718750, 0.0288696289062500, +-0.0291748046875000, 0.0296630859375000, -0.0156860351562500, 0.0252075195312500, +0.0239868164062500, 0.0345458984375000, -0.0021667480468750, 0.0353698730468750, +0.0433654785156250, 0.0121765136718750, 0.0378112792968750, 0.0178527832031250, +0.0418395996093750, 0.0101013183593750, 0.0692749023437500, -0.0115966796875000, +0.0528869628906250, -0.0031738281250000, 0.0766906738281250, -0.0106811523437500, +0.0729980468750000, -0.0158996582031250, 0.0767822265625000, -0.0104370117187500, +0.0922546386718750, -0.0071411132812500, 0.0811157226562500, -0.0098876953125000, +0.0997924804687500, -0.0031433105468750, 0.0976562500000000, -0.0020141601562500, +0.0973205566406250, -0.0031738281250000, 0.1074829101562500, -0.0010681152343750, +0.1015014648437500, -0.0009460449218750, 0.1053466796875000, -0.0036926269531250, +0.1047973632812500, -0.0028381347656250, 0.1028137207031250, -0.0034484863281250, +0.1033935546875000, -0.0061645507812500, 0.1015625000000000, -0.0049743652343750, +0.1014709472656250, -0.0032958984375000, 0.1002197265625000, -0.0061340332031250, +0.0991821289062500, -0.0012207031250000, 0.0986328125000000, 0.0034484863281250, +0.0955505371093750, -0.0012817382812500, 0.0909423828125000, 0.0115356445312500, +0.0924072265625000, 0.0105895996093750, 0.0834045410156250, 0.0106506347656250, +0.0745239257812500, 0.0185546875000000, 0.0778503417968750, 0.0160217285156250, +0.0560302734375000, 0.0134582519531250, 0.0580749511718750, 0.0167846679687500, +0.0506896972656250, 0.0128173828125000, 0.0332641601562500, 0.0070495605468750, +0.0388793945312500, 0.0109558105468750, 0.0208435058593750, 0.0045471191406250, +0.0198364257812500, 0.0039672851562500, 0.0173645019531250, 0.0035705566406250, +0.0065612792968750, 0.0011901855468750, 0.0087280273437500, 0.0022583007812500, +0.0022888183593750, -0.0040588378906250, 0.0013122558593750, -0.0010375976562500, +-0.0000610351562500, -0.0059204101562500, -0.0033264160156250, -0.0137634277343750, +-0.0024719238281250, -0.0082092285156250, -0.0089111328125000, -0.0186462402343750, +-0.0080871582031250, -0.0194702148437500, -0.0105895996093750, -0.0184631347656250, +-0.0167846679687500, -0.0225524902343750, -0.0147399902343750, -0.0217895507812500, +-0.0169372558593750, -0.0226440429687500, -0.0199279785156250, -0.0218200683593750, +-0.0170593261718750, -0.0239562988281250, -0.0162658691406250, -0.0265808105468750, +-0.0188903808593750, -0.0238647460937500, -0.0046691894531250, -0.0256958007812500, +-0.0114440917968750, -0.0303649902343750, 0.0010375976562500, -0.0190124511718750, +0.0186462402343750, -0.0139160156250000, 0.0067138671875000, -0.0223388671875000, +0.0417785644531250, 0.0191040039062500, 0.0388488769531250, 0.0055541992187500, +0.0466918945312500, 0.0290527343750000, 0.0736083984375000, 0.0695495605468750, +0.0617065429687500, 0.0433044433593750, 0.0676269531250000, 0.1090698242187500, +0.0798034667968750, 0.1021423339843750, 0.0601501464843750, 0.1132812500000000, +0.0432739257812500, 0.1597900390625000, 0.0571899414062500, 0.1380004882812500, +0.0201416015625000, 0.1585388183593750, 0.0184631347656250, 0.1728515625000000, +0.0153808593750000, 0.1491394042968750, -0.0034484863281250, 0.1404418945312500, +0.0040283203125000, 0.1565856933593750, -0.0075378417968750, 0.0973815917968750, +-0.0131835937500000, 0.1050720214843750, -0.0017700195312500, 0.0977783203125000, +0.0018920898437500, 0.0567626953125000, -0.0069885253906250, 0.0718688964843750, +0.0147094726562500, 0.0611572265625000, 0.0204162597656250, 0.0567321777343750, +0.0082092285156250, 0.0527038574218750, 0.0084838867187500, 0.0527343750000000, +0.0157775878906250, 0.0570373535156250, -0.0083007812500000, 0.0144653320312500, +-0.0085449218750000, 0.0299072265625000, -0.0065917968750000, 0.0102233886718750, +-0.0160522460937500, -0.0341186523437500, -0.0146179199218750, -0.0094604492187500, +-0.0191345214843750, -0.0428771972656250, -0.0131530761718750, -0.0502319335937500, +-0.0257568359375000, -0.0490722656250000, -0.0375061035156250, -0.0563049316406250, +-0.0263366699218750, -0.0534667968750000, -0.0642395019531250, -0.0835266113281250, +-0.0592651367187500, -0.0696411132812500, -0.0662841796875000, -0.0914611816406250, +-0.0979003906250000, -0.1390991210937500, -0.0952148437500000, -0.1315307617187500, +-0.1109619140625000, -0.1639099121093750, -0.1069946289062500, -0.1622314453125000, +-0.1089782714843750, -0.1551208496093750, -0.1198120117187500, -0.1706848144531250, +-0.1135559082031250, -0.1693420410156250, -0.1255187988281250, -0.1500549316406250, +-0.1258544921875000, -0.1559753417968750, -0.1228942871093750, -0.1430053710937500, +-0.1292419433593750, -0.1231079101562500, -0.1287231445312500, -0.1338195800781250, +-0.1136169433593750, -0.1007690429687500, -0.1219787597656250, -0.1027221679687500, +-0.1082153320312500, -0.0966186523437500, -0.0886230468750000, -0.0760803222656250, +-0.1019592285156250, -0.0835876464843750, -0.0658569335937500, -0.0571899414062500, +-0.0703430175781250, -0.0643005371093750, -0.0600585937500000, -0.0469055175781250, +-0.0344238281250000, -0.0170898437500000, -0.0485229492187500, -0.0346069335937500, +-0.0145874023437500, -0.0016479492187500, -0.0196533203125000, 0.0058593750000000, +-0.0089416503906250, -0.0022277832031250, 0.0161743164062500, 0.0046081542968750, +0.0015869140625000, 0.0076293945312500, 0.0382385253906250, -0.0012817382812500, +0.0333862304687500, -0.0021667480468750, 0.0459594726562500, -0.0002441406250000, +0.0740356445312500, -0.0039062500000000, 0.0587463378906250, -0.0033874511718750, +0.0968017578125000, 0.0079650878906250, 0.0928039550781250, -0.0002136230468750, +0.1028442382812500, 0.0161132812500000, 0.1293029785156250, 0.0357360839843750, +0.1151733398437500, 0.0208129882812500, 0.1493530273437500, 0.0592041015625000, +0.1473693847656250, 0.0612182617187500, 0.1484069824218750, 0.0561523437500000, +0.1720581054687500, 0.0736389160156250, 0.1639404296875000, 0.0711669921875000, +0.1485900878906250, 0.0509338378906250, 0.1696777343750000, 0.0585937500000000, +0.1324157714843750, 0.0461425781250000, 0.0959167480468750, 0.0223388671875000, +0.1296691894531250, 0.0334167480468750, 0.0239257812500000, 0.0150146484375000, +0.0398864746093750, 0.0106201171875000, 0.0238952636718750, 0.0122985839843750, +-0.0519714355468750, 0.0061035156250000, -0.0179748535156250, 0.0065612792968750, +-0.0462646484375000, 0.0097351074218750, -0.0621643066406250, 0.0074462890625000, +-0.0434570312500000, 0.0090332031250000, -0.0381469726562500, 0.0134887695312500, +-0.0491638183593750, 0.0113525390625000, -0.0221557617187500, 0.0115051269531250, +-0.0212402343750000, 0.0121459960937500, -0.0241394042968750, 0.0110778808593750, +-0.0126953125000000, 0.0088806152343750, -0.0140991210937500, 0.0090026855468750, +-0.0171508789062500, 0.0141601562500000, -0.0170288085937500, 0.0102233886718750, +-0.0143737792968750, 0.0178527832031250, -0.0151672363281250, 0.0269775390625000, +-0.0171203613281250, 0.0212707519531250, -0.0065612792968750, 0.0433349609375000, +-0.0087890625000000, 0.0417175292968750, -0.0062866210937500, 0.0475158691406250, +0.0018005371093750, 0.0639038085937500, -0.0019226074218750, 0.0583801269531250, +0.0044250488281250, 0.0722045898437500, 0.0036621093750000, 0.0737304687500000, +0.0064697265625000, 0.0746459960937500, 0.0112609863281250, 0.0818481445312500, +0.0072937011718750, 0.0799255371093750, 0.0165710449218750, 0.0809936523437500, +0.0166015625000000, 0.0824279785156250, 0.0149536132812500, 0.0793151855468750, +0.0200500488281250, 0.0761413574218750, 0.0195617675781250, 0.0770263671875000, +0.0110473632812500, 0.0733642578125000, 0.0152893066406250, 0.0713500976562500, +0.0095214843750000, 0.0711975097656250, -0.0010375976562500, 0.0699462890625000, +0.0050354003906250}, +{-0.0961303710937500, -0.1283874511718750, -0.0844421386718750, -0.1358642578125000, +-0.1016235351562500, -0.1091918945312500, -0.1016235351562500, -0.1133117675781250, +-0.1033935546875000, -0.1016540527343750, -0.1128234863281250, -0.0785217285156250, +-0.1074523925781250, -0.0904541015625000, -0.1177062988281250, -0.0618591308593750, +-0.1186218261718750, -0.0642395019531250, -0.1149597167968750, -0.0502319335937500, +-0.1195678710937500, -0.0280456542968750, -0.1202392578125000, -0.0417480468750000, +-0.1032409667968750, 0.0052185058593750, -0.1109008789062500, 0.0056152343750000, +-0.0981445312500000, 0.0013122558593750, -0.0787353515625000, 0.0259704589843750, +-0.0916748046875000, 0.0238342285156250, -0.0575561523437500, 0.0031433105468750, +-0.0624084472656250, 0.0082397460937500, -0.0526428222656250, 0.0086364746093750, +-0.0282897949218750, -0.0071105957031250, -0.0421142578125000, -0.0047302246093750, +-0.0085144042968750, 0.0093688964843750, -0.0128479003906250, 0.0004577636718750, +-0.0010681152343750, 0.0141601562500000, 0.0242919921875000, 0.0339660644531250, +0.0097656250000000, 0.0205383300781250, 0.0476684570312500, 0.0533447265625000, +0.0429382324218750, 0.0554809570312500, 0.0535888671875000, 0.0487976074218750, +0.0808105468750000, 0.0628662109375000, 0.0659790039062500, 0.0621032714843750, +0.1005249023437500, 0.0364379882812500, 0.0969543457031250, 0.0450134277343750, +0.1052246093750000, 0.0325012207031250, 0.1296081542968750, 0.0052490234375000, +0.1170654296875000, 0.0180969238281250, 0.1434020996093750, -0.0001831054687500, +0.1442565917968750, -0.0060424804687500, 0.1393127441406250, -0.0024719238281250, +0.1541137695312500, -0.0053100585937500, 0.1522827148437500, -0.0061340332031250, +0.1224365234375000, -0.0051879882812500, 0.1439208984375000, -0.0054626464843750, +0.1084289550781250, -0.0052185058593750, 0.0632934570312500, -0.0058288574218750, +0.0993652343750000, -0.0067443847656250, 0.0075073242187500, 0.0000915527343750, +0.0174560546875000, -0.0038146972656250, 0.0092773437500000, 0.0040283203125000, +-0.0510559082031250, 0.0131835937500000, -0.0258483886718750, 0.0067138671875000, +-0.0417480468750000, 0.0325317382812500, -0.0558776855468750, 0.0274658203125000, +-0.0400390625000000, 0.0383605957031250, -0.0302429199218750, 0.0609436035156250, +-0.0409545898437500, 0.0485534667968750, -0.0192260742187500, 0.0741271972656250, +-0.0169982910156250, 0.0755615234375000, -0.0202331542968750, 0.0725097656250000, +-0.0127868652343750, 0.0841369628906250, -0.0130920410156250, 0.0805053710937500, +-0.0153808593750000, 0.0676574707031250, -0.0163269042968750, 0.0737304687500000, +-0.0127258300781250, 0.0597229003906250, -0.0117492675781250, 0.0407104492187500, +-0.0146179199218750, 0.0486755371093750, -0.0039062500000000, 0.0150146484375000, +-0.0053405761718750, 0.0160522460937500, -0.0039062500000000, 0.0038757324218750, +0.0029296875000000, -0.0224609375000000, -0.0000305175781250, -0.0137634277343750, +0.0052795410156250, -0.0419616699218750, 0.0042114257812500, -0.0458679199218750, +0.0066528320312500, -0.0509948730468750, 0.0113220214843750, -0.0671997070312500, +0.0077209472656250, -0.0637512207031250, 0.0137329101562500, -0.0737609863281250, +0.0148620605468750, -0.0763549804687500, 0.0113220214843750, -0.0792236328125000, +0.0126647949218750, -0.0851135253906250, 0.0143127441406250, -0.0835571289062500, +0.0023193359375000, -0.0878601074218750, 0.0053710937500000, -0.0916137695312500, +0.0019836425781250, -0.0884704589843750, -0.0090942382812500, -0.0879211425781250, +-0.0036010742187500, -0.0915222167968750, -0.0043334960937500, -0.0784301757812500, +-0.0104980468750000, -0.0829467773437500, 0.0001525878906250, -0.0775756835937500, +0.0093383789062500, -0.0659179687500000, 0.0011596679687500, -0.0734558105468750, +0.0253601074218750, -0.0566406250000000, 0.0268554687500000, -0.0609741210937500, +0.0218811035156250, -0.0522460937500000, 0.0329284667968750, -0.0375366210937500, +0.0329284667968750, -0.0471496582031250, 0.0092773437500000, -0.0141296386718750, +0.0156555175781250, -0.0204772949218750, 0.0095214843750000, -0.0104980468750000, +-0.0136413574218750, 0.0159301757812500, -0.0058593750000000, 0.0016479492187500, +-0.0003051757812500, 0.0259094238281250, -0.0085449218750000, 0.0262145996093750, +-0.0023498535156250, 0.0278015136718750, 0.0141906738281250, 0.0401000976562500, +0.0083007812500000, 0.0342712402343750, -0.0056457519531250, 0.0467529296875000, +0.0056762695312500, 0.0452575683593750, -0.0115966796875000, 0.0466003417968750, +-0.0402832031250000, 0.0561218261718750, -0.0248107910156250, 0.0516052246093750, +-0.0365600585937500, 0.0491943359375000, -0.0496520996093750, 0.0581970214843750, +-0.0323486328125000, 0.0426025390625000, -0.0182495117187500, 0.0290832519531250, +-0.0301208496093750, 0.0422058105468750, -0.0033264160156250, -0.0028991699218750, +-0.0007019042968750, 0.0040588378906250, -0.0007629394531250, -0.0081787109375000, +0.0090332031250000, -0.0428771972656250, 0.0060424804687500, -0.0265197753906250, +0.0195312500000000, -0.0574035644531250, 0.0145263671875000, -0.0609436035156250, +0.0234985351562500, -0.0568847656250000, 0.0396118164062500, -0.0701904296875000, +0.0305175781250000, -0.0692138671875000, 0.0486145019531250, -0.0559692382812500, +0.0475769042968750, -0.0589294433593750, 0.0556945800781250, -0.0603942871093750, +0.0660705566406250, -0.0487670898437500, 0.0576477050781250, -0.0491638183593750, +0.1008605957031250, -0.0729980468750000, 0.0879516601562500, -0.0649414062500000, +0.1102905273437500, -0.0746154785156250, 0.1571655273437500, -0.1005249023437500, +0.1320190429687500, -0.0913696289062500, 0.1640014648437500, -0.0998229980468750, +0.1801452636718750, -0.1030883789062500, 0.1527404785156250, -0.1072692871093750, +0.1478576660156250, -0.1129150390625000, 0.1626586914062500, -0.1078186035156250, +0.0805664062500000, -0.1132202148437500, 0.0980224609375000, -0.1263732910156250, +0.0659179687500000, -0.1004333496093750, -0.0054016113281250, -0.0804138183593750, +0.0300598144531250, -0.1030883789062500, -0.0456848144531250, -0.0475769042968750, +-0.0483093261718750, -0.0418395996093750, -0.0534362792968750, -0.0520019531250000, +-0.0948486328125000, -0.0366821289062500, -0.0799865722656250, -0.0353698730468750, +-0.0962219238281250, -0.0347595214843750, -0.1032409667968750, -0.0482482910156250, +-0.0980224609375000, -0.0219421386718750, -0.0977172851562500, 0.0019836425781250, +-0.1014099121093750, -0.0207214355468750, -0.1060791015625000, 0.0410766601562500, +-0.0971679687500000, 0.0383605957031250, -0.1165466308593750, 0.0448608398437500, +-0.1334533691406250, 0.0816955566406250, -0.1175537109375000, 0.0670471191406250, +-0.1720886230468750, 0.0870666503906250, -0.1674194335937500, 0.0928344726562500, +-0.1731262207031250, 0.0865173339843750, -0.2104187011718750, 0.0909423828125000, +-0.1968688964843750, 0.0928955078125000, -0.1952514648437500, 0.0778808593750000, +-0.2086486816406250, 0.0800476074218750, -0.1876220703125000, 0.0796508789062500, +-0.1679687500000000, 0.0693054199218750, -0.1828002929687500, 0.0718078613281250, +-0.1306457519531250, 0.0767822265625000, -0.1390380859375000, 0.0758972167968750, +-0.1207885742187500, 0.0725097656250000, -0.0464782714843750, 0.0726623535156250, +0.0785522460937500, 0.0678710937500000, 0.1388549804687500, 0.0690307617187500, +0.1553039550781250, 0.0703735351562500, 0.1174011230468750, 0.0621948242187500, +0.1020507812500000, 0.0644226074218750, 0.1303405761718750, 0.0700988769531250, +0.0500183105468750, 0.0205078125000000, 0.0500183105468750, 0.0390319824218750, +0.0546569824218750, 0.0103149414062500, 0.0123901367187500, -0.0437011718750000, +0.0209045410156250, -0.0142822265625000, 0.0473632812500000, -0.0801086425781250, +0.0324707031250000, -0.0773010253906250, 0.0454711914062500, -0.0908508300781250, +0.0799255371093750, -0.1316528320312500, 0.0657958984375000, -0.1100769042968750, +0.0696105957031250, -0.1612243652343750, 0.0812072753906250, -0.1625366210937500, +0.0692443847656250, -0.1577758789062500, 0.0535888671875000, -0.1865539550781250, +0.0625915527343750, -0.1809692382812500, 0.0582275390625000, -0.1443176269531250, +0.0513916015625000, -0.1641540527343750, 0.0514831542968750, -0.1371154785156250, +0.0627441406250000, -0.0862731933593750, 0.0591735839843750, -0.1124572753906250, +0.0052490234375000, -0.0761718750000000, 0.0390930175781250, -0.0641174316406250, +-0.0116271972656250, -0.0771179199218750, -0.0934448242187500, -0.0775756835937500, +-0.0419006347656250, -0.0719299316406250, -0.1327209472656250, -0.0717773437500000, +-0.1503601074218750, -0.0844421386718750, -0.1272583007812500, -0.0617370605468750, +-0.1518554687500000, -0.0404052734375000, -0.1560974121093750, -0.0584411621093750, +-0.1047058105468750, -0.0067443847656250, -0.1222534179687500, -0.0096435546875000, +-0.0987854003906250, 0.0003356933593750, -0.0476989746093750, 0.0306701660156250, +-0.0776367187500000, 0.0164489746093750, -0.0361633300781250, 0.0619201660156250, +-0.0218811035156250, 0.0519409179687500, -0.0480957031250000, 0.0730895996093750, +-0.0456237792968750, 0.1181640625000000, -0.0303344726562500, 0.0952148437500000, +-0.1009521484375000, 0.1347351074218750, -0.0874023437500000, 0.1465454101562500, +-0.0984191894531250, 0.1293334960937500, -0.1534423828125000, 0.1338195800781250, +-0.1312255859375000, 0.1416931152343750, -0.1356201171875000, 0.1004028320312500, +-0.1553649902343750, 0.1069641113281250, -0.1293029785156250, 0.0964355468750000, +-0.1095581054687500, 0.0664672851562500, -0.1296081542968750, 0.0792541503906250, +-0.0529785156250000, 0.0470886230468750, -0.0703125000000000, 0.0517272949218750, +-0.0421142578125000, 0.0391845703125000, 0.0228881835937500, 0.0121765136718750, +-0.0132446289062500, 0.0270080566406250, 0.0587158203125000, -0.0040588378906250, +0.0590209960937500, -0.0050964355468750, 0.0633850097656250, -0.0065612792968750, +0.1029663085937500, -0.0214233398437500, 0.0855712890625000, -0.0156860351562500, +0.1011352539062500, -0.0307006835937500, 0.1098632812500000, -0.0285949707031250, +0.0984497070312500, -0.0315551757812500, 0.0973205566406250, -0.0454101562500000, +0.1044921875000000, -0.0401611328125000, 0.0747070312500000, -0.0333557128906250, +0.0840148925781250, -0.0426940917968750, 0.0693969726562500, -0.0289611816406250, +0.0429382324218750, -0.0099487304687500, 0.0617675781250000, -0.0214233398437500, +0.0171508789062500, -0.0004882812500000, 0.0238342285156250, 0.0039367675781250, +0.0130615234375000, 0.0008544921875000, -0.0187377929687500, 0.0046997070312500, +-0.0009765625000000, 0.0046691894531250, -0.0373840332031250, 0.0126342773437500, +-0.0363159179687500, 0.0078735351562500, -0.0416259765625000, 0.0156860351562500, +-0.0642395019531250, 0.0299682617187500, -0.0543212890625000, 0.0227050781250000, +-0.0713195800781250, 0.0285644531250000, -0.0722351074218750, 0.0366821289062500, +-0.0742492675781250, 0.0243530273437500, -0.0838317871093750, 0.0141601562500000, +-0.0809020996093750, 0.0225219726562500, -0.0916442871093750, -0.0014953613281250, +-0.0921020507812500, -0.0041198730468750, -0.0940856933593750, -0.0010375976562500, +-0.1014709472656250, -0.0107727050781250, -0.0997924804687500, -0.0105590820312500, +-0.1014709472656250, -0.0000915527343750, -0.1041564941406250, -0.0038146972656250, +-0.1014404296875000, 0.0000610351562500, -0.0991516113281250, 0.0104370117187500, +-0.1016235351562500, 0.0056152343750000, -0.0955505371093750, 0.0103149414062500, +-0.0962829589843750}, +{0.0200805664062500, -0.1491088867187500, 0.0488281250000000, -0.1536560058593750, +-0.0033264160156250, -0.1438598632812500, -0.0695190429687500, -0.1605834960937500, +-0.0188903808593750, -0.1614990234375000, -0.1239624023437500, -0.1174621582031250, +-0.1365356445312500, -0.1321716308593750, -0.1119995117187500, -0.1116027832031250, +-0.1476745605468750, -0.0642395019531250, -0.1522521972656250, -0.0866699218750000, +-0.0946655273437500, -0.0627441406250000, -0.1069641113281250, -0.0518188476562500, +-0.0971374511718750, -0.0602111816406250, -0.0526428222656250, -0.0640258789062500, +-0.0710754394531250, -0.0601806640625000, -0.0668029785156250, -0.0488891601562500, +-0.0494384765625000, -0.0616149902343750, -0.0762329101562500, -0.0413818359375000, +-0.0983886718750000, -0.0155944824218750, -0.0759277343750000, -0.0329589843750000, +-0.1331176757812500, 0.0125427246093750, -0.1331481933593750, 0.0101318359375000, +-0.1286010742187500, 0.0200805664062500, -0.1603698730468750, 0.0476684570312500, +-0.1544799804687500, 0.0343933105468750, -0.1244201660156250, 0.0782470703125000, +-0.1477661132812500, 0.0710144042968750, -0.1166992187500000, 0.0854797363281250, +-0.0710449218750000, 0.1245117187500000, -0.1039733886718750, 0.1065063476562500, +-0.0320434570312500, 0.1253356933593750, -0.0359191894531250, 0.1388549804687500, +-0.0263366699218750, 0.1197509765625000, 0.0183105468750000, 0.1099243164062500, +-0.0020751953125000, 0.1215209960937500, 0.0292968750000000, 0.0820007324218750, +0.0331420898437500, 0.0853881835937500, 0.0321655273437500, 0.0763854980468750, +0.0447082519531250, 0.0509643554687500, 0.0401611328125000, 0.0627136230468750, +0.0478820800781250, 0.0297241210937500, 0.0480651855468750, 0.0347595214843750, +0.0486145019531250, 0.0240783691406250, 0.0543518066406250, -0.0028076171875000, +0.0530395507812500, 0.0108947753906250, 0.0502319335937500, -0.0136108398437500, +0.0551757812500000, -0.0153503417968750, 0.0482482910156250, -0.0172729492187500, +0.0413818359375000, -0.0287170410156250, 0.0480041503906250, -0.0234680175781250, +0.0248107910156250, -0.0379638671875000, 0.0301208496093750, -0.0380859375000000, +0.0213623046875000, -0.0357055664062500, 0.0017700195312500, -0.0446777343750000, +0.0128784179687500, -0.0439453125000000, -0.0112915039062500, -0.0249938964843750, +-0.0096130371093750, -0.0317993164062500, -0.0140075683593750, -0.0229492187500000, +-0.0288696289062500, -0.0015258789062500, -0.0205688476562500, -0.0104064941406250, +-0.0373535156250000, -0.0027770996093750, -0.0347595214843750, 0.0015563964843750, +-0.0390014648437500, 0.0002136230468750, -0.0510559082031250, -0.0017395019531250, +-0.0432128906250000, -0.0014953613281250, -0.0571594238281250, 0.0110473632812500, +-0.0560607910156250, 0.0060729980468750, -0.0576782226562500, 0.0132751464843750, +-0.0660095214843750, 0.0291442871093750, -0.0610656738281250, 0.0222473144531250, +-0.0678405761718750, 0.0280151367187500, -0.0662841796875000, 0.0328979492187500, +-0.0686035156250000, 0.0255432128906250, -0.0734558105468750, 0.0203247070312500, +-0.0691528320312500, 0.0239257812500000, -0.0800781250000000, 0.0116882324218750, +-0.0780944824218750, 0.0115661621093750, -0.0805969238281250, 0.0104370117187500, +-0.0890197753906250, 0.0037231445312500, -0.0845947265625000, 0.0061950683593750, +-0.0904541015625000, 0.0035095214843750, -0.0910644531250000, 0.0031127929687500, +-0.0900573730468750, 0.0031433105468750, -0.0914611816406250, 0.0024719238281250, +-0.0905761718750000, 0.0031127929687500, -0.0927734375000000, 0.0000000000000000, +-0.0907592773437500, 0.0016784667968750, -0.0930786132812500, -0.0016174316406250, +-0.0965881347656250, -0.0056762695312500, -0.0936279296875000, -0.0022277832031250, +-0.1002502441406250, -0.0112915039062500, -0.1001892089843750, -0.0104980468750000, +-0.1001586914062500, -0.0114746093750000, -0.1038818359375000, -0.0172119140625000, +-0.1024780273437500, -0.0148315429687500, -0.1012268066406250, -0.0173645019531250, +-0.1030883789062500, -0.0178222656250000, -0.1007995605468750, -0.0180664062500000, +-0.0983886718750000, -0.0190734863281250, -0.1003417968750000, -0.0182189941406250, +-0.0917968750000000, -0.0202636718750000, -0.0950622558593750, -0.0209960937500000, +-0.0856933593750000, -0.0181884765625000, -0.0751037597656250, -0.0189208984375000, +-0.0817871093750000, -0.0203857421875000, -0.0508728027343750, -0.0053100585937500, +-0.0559692382812500, -0.0131530761718750, -0.0420532226562500, 0.0009155273437500, +-0.0147399902343750, 0.0189514160156250, -0.0273742675781250, 0.0049438476562500, +0.0078430175781250, 0.0491027832031250, 0.0084533691406250, 0.0392761230468750, +0.0135498046875000, 0.0555419921875000, 0.0360717773437500, 0.0927429199218750, +0.0286560058593750, 0.0705871582031250, 0.0349731445312500, 0.1129150390625000, +0.0420532226562500, 0.1159973144531250, 0.0304870605468750, 0.1098937988281250, +0.0246887207031250, 0.1295471191406250, 0.0316467285156250, 0.1271667480468750, +-0.0055847167968750, 0.1043701171875000, 0.0002136230468750, 0.1162414550781250, +-0.0109558105468750, 0.1017761230468750, -0.0431213378906250, 0.0734863281250000, +-0.0306396484375000, 0.0896606445312500, -0.0424499511718750, 0.0658264160156250, +-0.0502624511718750, 0.0615539550781250, -0.0426940917968750, 0.0640563964843750, +-0.0406188964843750, 0.0586242675781250, -0.0437316894531250, 0.0592041015625000, +-0.0218505859375000, 0.0445251464843750, -0.0287475585937500, 0.0559082031250000, +-0.0172729492187500, 0.0350952148437500, 0.0074768066406250, 0.0097656250000000, +-0.0047607421875000, 0.0304260253906250, 0.0083007812500000, -0.0209655761718750, +0.0129089355468750, -0.0201110839843750, 0.0132446289062500, -0.0219421386718750, +0.0148315429687500, -0.0494384765625000, 0.0115966796875000, -0.0407409667968750, +0.0249328613281250, -0.0539550781250000, 0.0257873535156250, -0.0502319335937500, +0.0213623046875000, -0.0650939941406250, 0.0249633789062500, -0.0798034667968750, +0.0273742675781250, -0.0657653808593750, 0.0206604003906250, -0.1184692382812500, +0.0174865722656250, -0.1108703613281250, 0.0225524902343750, -0.1173400878906250, +0.0250854492187500, -0.1555786132812500, 0.0214538574218750, -0.1407775878906250, +0.0282287597656250, -0.1443481445312500, 0.0307006835937500, -0.1564941406250000, +0.0274658203125000, -0.1433410644531250, 0.0271606445312500, -0.1300659179687500, +0.0292358398437500, -0.1398620605468750, 0.0252990722656250, -0.1158752441406250, +0.0257873535156250, -0.1192016601562500, 0.0238647460937500, -0.1071472167968750, +0.0214538574218750, -0.0841369628906250, 0.0211181640625000, -0.0867309570312500, +0.0049438476562500, -0.0408020019531250, 0.0128479003906250, -0.0568237304687500, +0.0064086914062500, -0.0481567382812500, -0.0078735351562500, -0.0086364746093750, +0.0018920898437500, -0.0231018066406250, -0.0253601074218750, 0.0055236816406250, +-0.0188598632812500, 0.0075073242187500, -0.0299377441406250, 0.0144653320312500, +-0.0529479980468750, 0.0325317382812500, -0.0379943847656250, 0.0227661132812500, +-0.0701904296875000, 0.0375061035156250, -0.0685424804687500, 0.0466308593750000, +-0.0715332031250000, 0.0306091308593750, -0.0910034179687500, 0.0214538574218750, +-0.0829162597656250, 0.0336303710937500, -0.0942077636718750, 0.0114440917968750, +-0.0951232910156250, 0.0024414062500000, -0.0962524414062500, 0.0166931152343750, +-0.1026000976562500, 0.0220947265625000, -0.0994262695312500, 0.0130004882812500, +-0.1022949218750000, 0.0284118652343750, -0.1057739257812500, 0.0343017578125000, +-0.0995178222656250, 0.0268554687500000, -0.0971984863281250, 0.0252380371093750, +-0.1024780273437500, 0.0285949707031250, -0.0811462402343750, 0.0180053710937500, +-0.0874633789062500, 0.0198974609375000, -0.0772705078125000, 0.0144348144531250, +-0.0575561523437500, 0.0049743652343750, -0.0690307617187500, 0.0111999511718750, +-0.0395202636718750, -0.0012817382812500, -0.0440979003906250, -0.0009155273437500, +-0.0341491699218750, -0.0030822753906250, -0.0124206542968750, -0.0104980468750000, +-0.0255432128906250, -0.0057067871093750, 0.0099182128906250, -0.0124816894531250, +0.0035705566406250, -0.0154724121093750, 0.0162353515625000, -0.0091857910156250, +0.0448913574218750, -0.0082702636718750, 0.0283508300781250, -0.0119628906250000, +0.0642700195312500, 0.0066833496093750, 0.0612487792968750, 0.0017700195312500, +0.0680541992187500, 0.0124511718750000, 0.0913696289062500, 0.0320739746093750, +0.0793151855468750, 0.0208740234375000, 0.1048583984375000, 0.0396118164062500, +0.1028747558593750, 0.0461120605468750, 0.1065368652343750, 0.0349731445312500, +0.1236267089843750, 0.0357055664062500, 0.1152648925781250, 0.0405273437500000, +0.1239013671875000, 0.0066223144531250, 0.1289978027343750, 0.0128784179687500, +0.1170043945312500, -0.0039978027343750, 0.1159057617187500, -0.0354614257812500, +0.1235351562500000, -0.0212097167968750, 0.0788574218750000, -0.0602722167968750, +0.0960083007812500, -0.0609436035156250, 0.0694274902343750, -0.0672912597656250, +0.0223999023437500, -0.0912475585937500, 0.0536804199218750, -0.0822448730468750, +-0.0120849609375000, -0.0970153808593750, -0.0123596191406250, -0.1001586914062500, +-0.0110778808593750, -0.0970153808593750, -0.0459289550781250, -0.1012878417968750, +-0.0353393554687500, -0.1006164550781250, -0.0320739746093750, -0.0927429199218750, +-0.0412292480468750, -0.0954284667968750, -0.0315856933593750, -0.0908203125000000, +-0.0179138183593750, -0.0830383300781250, -0.0261230468750000, -0.0873718261718750, +-0.0148010253906250, -0.0755615234375000, -0.0114440917968750, -0.0773620605468750, +-0.0144653320312500, -0.0749816894531250, -0.0130920410156250, -0.0671081542968750, +-0.0119628906250000, -0.0719909667968750, -0.0123291015625000, -0.0638122558593750, +-0.0144958496093750, -0.0652160644531250, -0.0106506347656250, -0.0641174316406250, +-0.0077819824218750, -0.0593261718750000, -0.0110168457031250, -0.0630187988281250, +-0.0001831054687500, -0.0554199218750000, -0.0025939941406250, -0.0578918457031250, +0.0025024414062500, -0.0553894042968750, 0.0118408203125000, -0.0485839843750000, +0.0064086914062500, -0.0533142089843750, 0.0224914550781250, -0.0474548339843750, +0.0213012695312500, -0.0467529296875000, 0.0233764648437500, -0.0495910644531250, +0.0351562500000000, -0.0487670898437500, 0.0302124023437500, -0.0484619140625000, +0.0263977050781250, -0.0522155761718750, 0.0342407226562500, -0.0517883300781250, +0.0216674804687500, -0.0514831542968750, 0.0071105957031250, -0.0532531738281250, +0.0178222656250000, -0.0521850585937500, -0.0058898925781250, -0.0513000488281250, +-0.0095825195312500, -0.0521240234375000, -0.0028686523437500, -0.0502319335937500, +-0.0083618164062500, -0.0493774414062500, -0.0105590820312500, -0.0510864257812500, +-0.0005187988281250, -0.0422363281250000, 0.0033264160156250, -0.0470275878906250, +-0.0073852539062500, -0.0395507812500000, -0.0100402832031250, -0.0296020507812500, +-0.0025634765625000, -0.0381469726562500, -0.0325622558593750, -0.0131530761718750, +-0.0330200195312500, -0.0211791992187500, -0.0286560058593750, -0.0084838867187500, +-0.0434265136718750, 0.0140686035156250, -0.0428466796875000, -0.0027465820312500, +-0.0220031738281250, 0.0379943847656250, -0.0270385742187500, 0.0328063964843750, +-0.0193481445312500, 0.0349121093750000, -0.0007934570312500, 0.0620727539062500, +-0.0082397460937500, 0.0504760742187500, 0.0058593750000000, 0.0494995117187500, +0.0050354003906250, 0.0596923828125000, 0.0113830566406250, 0.0444335937500000, +0.0225830078125000}, +{-0.0252990722656250, 0.0202331542968750, -0.0032958984375000, 0.0437316894531250, +-0.0176391601562500, 0.0331420898437500, 0.0190429687500000, 0.0414123535156250, +0.0128784179687500, 0.0498352050781250, 0.0234375000000000, 0.0346374511718750, +0.0509338378906250, 0.0271606445312500, 0.0351562500000000, 0.0371704101562500, +0.0689086914062500, -0.0057067871093750, 0.0659790039062500, 0.0009460449218750, +0.0716247558593750, -0.0133972167968750, 0.0934143066406250, -0.0491943359375000, +0.0822143554687500, -0.0339660644531250, 0.1025390625000000, -0.0635986328125000, +0.1019287109375000, -0.0671081542968750, 0.1027832031250000, -0.0672912597656250, +0.1151123046875000, -0.0798645019531250, 0.1100158691406250, -0.0758972167968750, +0.1107482910156250, -0.0834655761718750, 0.1179504394531250, -0.0830078125000000, +0.1040039062500000, -0.0849914550781250, 0.0957031250000000, -0.0906982421875000, +0.1066284179687500, -0.0882568359375000, 0.0590515136718750, -0.0940246582031250, +0.0729370117187500, -0.0942077636718750, 0.0518798828125000, -0.0950012207031250, +0.0076293945312500, -0.0988464355468750, 0.0343627929687500, -0.0975036621093750, +-0.0170898437500000, -0.0975646972656250, -0.0203552246093750, -0.0996704101562500, +-0.0158691406250000, -0.0959472656250000, -0.0392761230468750, -0.0929565429687500, +-0.0341796875000000, -0.0952148437500000, -0.0247497558593750, -0.0836181640625000, +-0.0309753417968750, -0.0853881835937500, -0.0252990722656250, -0.0797119140625000, +-0.0131225585937500, -0.0695495605468750, -0.0191650390625000, -0.0741271972656250, +-0.0119323730468750, -0.0583801269531250, -0.0101623535156250, -0.0589294433593750, +-0.0101013183593750, -0.0527038574218750, -0.0083923339843750, -0.0402832031250000, +-0.0089416503906250, -0.0458068847656250, -0.0007019042968750, -0.0324707031250000, +-0.0037536621093750, -0.0315551757812500, 0.0012512207031250, -0.0299682617187500, +0.0111083984375000, -0.0228881835937500, 0.0056152343750000, -0.0254211425781250, +0.0124206542968750, -0.0196838378906250, 0.0152587890625000, -0.0197448730468750, +0.0099792480468750, -0.0173034667968750, 0.0082397460937500, -0.0126647949218750, +0.0108642578125000, -0.0148620605468750, 0.0022277832031250, -0.0094604492187500, +0.0003051757812500, -0.0076293945312500, 0.0046081542968750, -0.0104370117187500, +0.0034790039062500, -0.0093994140625000, 0.0007629394531250, -0.0074157714843750, +0.0124206542968750, -0.0180664062500000, 0.0143737792968750, -0.0132446289062500, +0.0068664550781250, -0.0184936523437500, 0.0101623535156250, -0.0288391113281250, +0.0143432617187500, -0.0215454101562500, -0.0179138183593750, -0.0382385253906250, +-0.0118103027343750, -0.0347290039062500, -0.0176391601562500, -0.0394592285156250, +-0.0450744628906250, -0.0519104003906250, -0.0358886718750000, -0.0438842773437500, +-0.0302429199218750, -0.0610351562500000, -0.0407409667968750, -0.0588684082031250, +-0.0277404785156250, -0.0617065429687500, -0.0090942382812500, -0.0740661621093750, +-0.0186462402343750, -0.0675659179687500, 0.0014648437500000, -0.0735168457031250, +0.0022888183593750, -0.0802001953125000, 0.0065612792968750, -0.0690917968750000, +0.0176391601562500, -0.0656433105468750, 0.0119018554687500, -0.0750427246093750, +0.0296936035156250, -0.0350952148437500, 0.0286865234375000, -0.0468750000000000, +0.0312805175781250, -0.0298156738281250, 0.0418090820312500, 0.0085144042968750, +0.0382995605468750, -0.0122070312500000, 0.0513000488281250, 0.0256042480468750, +0.0449829101562500, 0.0288696289062500, 0.0607299804687500, 0.0251159667968750, +0.0783996582031250, 0.0419921875000000, 0.0637207031250000, 0.0386962890625000, +0.1106262207031250, 0.0295410156250000, 0.1081848144531250, 0.0371704101562500, +0.1084289550781250, 0.0250244140625000, 0.1387023925781250, 0.0102539062500000, +0.1306762695312500, 0.0211181640625000, 0.1104431152343750, -0.0118408203125000, +0.1280517578125000, -0.0085754394531250, 0.1006774902343750, -0.0138854980468750, +0.0651245117187500, -0.0392150878906250, 0.0897216796875000, -0.0298461914062500, +0.0257568359375000, -0.0273742675781250, 0.0291442871093750, -0.0376892089843750, +0.0168151855468750, -0.0231323242187500, -0.0255737304687500, -0.0052185058593750, +-0.0068054199218750, -0.0161437988281250, -0.0383300781250000, 0.0062561035156250, +-0.0418090820312500, 0.0122680664062500, -0.0418090820312500, -0.0004577636718750, +-0.0550231933593750, 0.0047607421875000, -0.0511169433593750, 0.0099487304687500, +-0.0639343261718750, -0.0456848144531250, -0.0592956542968750, -0.0320434570312500, +-0.0715332031250000, -0.0498352050781250, -0.0865478515625000, -0.1002502441406250, +-0.0750122070312500, -0.0794982910156250, -0.1119384765625000, -0.1048889160156250, +-0.1090087890625000, -0.1107482910156250, -0.1134948730468750, -0.1100769042968750, +-0.1385498046875000, -0.1221008300781250, -0.1293945312500000, -0.1173095703125000, +-0.1337585449218750, -0.1045837402343750, -0.1408691406250000, -0.1218566894531250, +-0.1307067871093750, -0.0931091308593750, -0.1243896484375000, -0.0558776855468750, +-0.1304321289062500, -0.0827636718750000, -0.1010742187500000, -0.0399169921875000, +-0.1120910644531250, -0.0281677246093750, -0.0863647460937500, -0.0437927246093750, +-0.0550842285156250, -0.0423583984375000, -0.0781555175781250, -0.0356750488281250, +0.0112304687500000, -0.0429077148437500, -0.0042419433593750, -0.0555114746093750, +0.0224609375000000, -0.0333557128906250, 0.0980529785156250, -0.0167541503906250, +0.0628967285156250, -0.0339050292968750, 0.1038513183593750, 0.0202026367187500, +0.1250000000000000, 0.0164794921875000, 0.0943603515625000, 0.0207824707031250, +0.0849914550781250, 0.0535888671875000, 0.1032409667968750, 0.0420532226562500, +0.0437927246093750, 0.0540771484375000, 0.0425720214843750, 0.0555725097656250, +0.0513610839843750, 0.0577392578125000, 0.0188293457031250, 0.0704040527343750, +0.0774230957031250, 0.0460205078125000, 0.0827331542968750, 0.0557556152343750, +0.0911560058593750, 0.0527038574218750, 0.0814819335937500, 0.0599975585937500, +0.0704956054687500, 0.0660095214843750, 0.0772399902343750, 0.0603027343750000, +0.0690307617187500, 0.0783691406250000, 0.0678100585937500, 0.0801696777343750, +0.0632629394531250, 0.0739746093750000, 0.0621948242187500, 0.0799865722656250, +0.0653686523437500, 0.0827636718750000, 0.0253295898437500, 0.0636901855468750, +0.0418701171875000, 0.0658874511718750, 0.0135803222656250, 0.0646972656250000, +-0.0352172851562500, 0.0528259277343750, -0.0071411132812500, 0.0558166503906250, +-0.0635986328125000, 0.0539855957031250, -0.0693054199218750, 0.0582580566406250, +-0.0635375976562500, 0.0445556640625000, -0.0883483886718750, 0.0364685058593750, +-0.0858459472656250, 0.0475463867187500, -0.0690307617187500, -0.0036926269531250, +-0.0744018554687500, 0.0075378417968750, -0.0790405273437500, -0.0111389160156250, +-0.0633850097656250, -0.0554199218750000, -0.0630187988281250, -0.0339050292968750, +-0.1070861816406250, -0.0793457031250000, -0.0916137695312500, -0.0788269042968750, +-0.1029663085937500, -0.0865783691406250, -0.1489257812500000, -0.1155395507812500, +-0.1321411132812500, -0.1015930175781250, -0.1213684082031250, -0.1200866699218750, +-0.1433715820312500, -0.1293640136718750, -0.1143188476562500, -0.1119689941406250, +-0.0812377929687500, -0.1080932617187500, -0.1066894531250000, -0.1189270019531250, +-0.0335083007812500, -0.0715942382812500, -0.0401611328125000, -0.0769348144531250, +-0.0349426269531250, -0.0695800781250000, 0.0121154785156250, -0.0360717773437500, +-0.0051879882812500, -0.0480041503906250, 0.0010070800781250, -0.0393371582031250, +0.0081787109375000, -0.0358886718750000, 0.0051269531250000, -0.0343627929687500, +0.0007934570312500, -0.0349731445312500, 0.0015258789062500, -0.0381164550781250, +0.0086975097656250, -0.0108337402343750, 0.0032653808593750, -0.0206604003906250, +0.0107727050781250, -0.0051879882812500, 0.0216369628906250, 0.0241699218750000, +0.0130920410156250, 0.0084228515625000, 0.0299072265625000, 0.0437316894531250, +0.0310363769531250, 0.0413818359375000, 0.0271606445312500, 0.0516052246093750, +0.0346374511718750, 0.0756225585937500, 0.0339660644531250, 0.0623168945312500, +0.0173339843750000, 0.0982666015625000, 0.0271301269531250, 0.0982055664062500, +0.0105895996093750, 0.0967407226562500, -0.0118103027343750, 0.1177978515625000, +0.0049438476562500, 0.1133422851562500, -0.0372619628906250, 0.0965881347656250, +-0.0327453613281250, 0.1066589355468750, -0.0425415039062500, 0.0929565429687500, +-0.0711669921875000, 0.0701904296875000, -0.0545349121093750, 0.0828857421875000, +-0.0833129882812500, 0.0545043945312500, -0.0843200683593750, 0.0563659667968750, +-0.0803527832031250, 0.0477905273437500, -0.0944213867187500, 0.0285339355468750, +-0.0912475585937500, 0.0393371582031250, -0.0777893066406250, 0.0088806152343750, +-0.0874633789062500, 0.0111999511718750, -0.0708923339843750, 0.0055847167968750, +-0.0513000488281250, -0.0146484375000000, -0.0672302246093750, -0.0063171386718750, +-0.0208740234375000, -0.0238952636718750, -0.0285949707031250, -0.0231628417968750, +-0.0175781250000000, -0.0271606445312500, 0.0162353515625000, -0.0407409667968750, +-0.0022888183593750, -0.0346679687500000, 0.0299987792968750, -0.0365600585937500, +0.0296936035156250, -0.0449218750000000, 0.0305786132812500, -0.0311584472656250, +0.0476684570312500, -0.0186462402343750, 0.0401000976562500, -0.0291442871093750, +0.0489196777343750, -0.0007934570312500, 0.0499572753906250, 0.0012817382812500, +0.0484619140625000, -0.0009460449218750, 0.0521240234375000, 0.0110168457031250, +0.0513000488281250, 0.0093994140625000, 0.0496826171875000, 0.0063476562500000, +0.0518493652343750, 0.0061035156250000, 0.0482482910156250, 0.0091552734375000, +0.0440368652343750, 0.0098876953125000, 0.0470581054687500, 0.0080261230468750, +0.0389099121093750, 0.0157470703125000, 0.0393981933593750, 0.0171813964843750, +0.0383300781250000, 0.0139465332031250, 0.0335693359375000, 0.0163879394531250, +0.0355834960937500, 0.0182800292968750, 0.0313110351562500, 0.0046691894531250, +0.0324401855468750, 0.0083618164062500, 0.0303039550781250, 0.0030822753906250, +0.0263977050781250, -0.0098571777343750, 0.0281982421875000, -0.0038146972656250, +0.0189514160156250, -0.0125427246093750, 0.0206604003906250, -0.0145263671875000, +0.0158691406250000, -0.0129394531250000, 0.0074462890625000, -0.0149536132812500, +0.0111389160156250, -0.0147705078125000, -0.0030822753906250, -0.0144653320312500, +-0.0007324218750000, -0.0143432617187500, -0.0078125000000000, -0.0139160156250000, +-0.0199890136718750, -0.0143737792968750, -0.0142211914062500, -0.0142822265625000, +-0.0384521484375000, -0.0090332031250000, -0.0348510742187500, -0.0132141113281250, +-0.0444641113281250, -0.0048217773437500, -0.0651245117187500, 0.0033264160156250, +-0.0555419921875000, -0.0044250488281250, -0.0787658691406250, 0.0237426757812500, +-0.0795898437500000, 0.0156860351562500, -0.0817871093750000, 0.0300598144531250, +-0.0947570800781250, 0.0561218261718750, -0.0904235839843750, 0.0388183593750000, +-0.0976867675781250, 0.0793762207031250, -0.0987548828125000, 0.0771179199218750, +-0.0975646972656250, 0.0794982910156250, -0.1014099121093750, 0.1050720214843750, +-0.1004333496093750, 0.0954284667968750, -0.0910034179687500, 0.0952453613281250, +-0.0969543457031250, 0.1053771972656250, -0.0856018066406250, 0.0926208496093750, +-0.0717163085937500, 0.0791320800781250, -0.0819702148437500, 0.0904846191406250, +-0.0509948730468750}, +{0.0028076171875000, 0.0270080566406250, -0.0358581542968750, 0.0575866699218750, +-0.0330505371093750, 0.0546569824218750, -0.0387573242187500, 0.0648498535156250, +-0.0629882812500000, 0.0882873535156250, -0.0520935058593750, 0.0751647949218750, +-0.0720214843750000, 0.1017456054687500, -0.0714416503906250, 0.1059570312500000, +-0.0726013183593750, 0.0973510742187500, -0.0856323242187500, 0.1056518554687500, +-0.0801696777343750, 0.1082458496093750, -0.0772094726562500, 0.0813293457031250, +-0.0843505859375000, 0.0883789062500000, -0.0737609863281250, 0.0781555175781250, +-0.0629882812500000, 0.0545043945312500, -0.0717468261718750, 0.0655822753906250, +-0.0434265136718750, 0.0403442382812500, -0.0478210449218750, 0.0425720214843750, +-0.0391235351562500, 0.0348815917968750, -0.0168151855468750, 0.0159912109375000, +-0.0274658203125000, 0.0257263183593750, -0.0046997070312500, 0.0041198730468750, +-0.0031127929687500, 0.0029602050781250, -0.0009765625000000, 0.0014343261718750, +0.0120544433593750, -0.0089721679687500, 0.0086975097656250, -0.0055541992187500, +0.0138244628906250, -0.0174255371093750, 0.0175476074218750, -0.0156860351562500, +0.0157165527343750, -0.0195312500000000, 0.0155029296875000, -0.0310974121093750, +0.0174865722656250, -0.0263671875000000, 0.0117492675781250, -0.0251464843750000, +0.0133056640625000, -0.0317077636718750, 0.0122375488281250, -0.0216674804687500, +0.0075378417968750, -0.0094299316406250, 0.0100097656250000, -0.0165710449218750, +0.0076599121093750, -0.0013732910156250, 0.0068664550781250, 0.0021972656250000, +0.0085144042968750, -0.0015869140625000, 0.0092468261718750, 0.0011596679687500, +0.0087280273437500, 0.0023803710937500, 0.0091247558593750, -0.0023803710937500, +0.0105895996093750, -0.0028076171875000, 0.0088806152343750, -0.0012512207031250, +0.0072631835937500, -0.0021362304687500, 0.0087585449218750, -0.0024108886718750, +0.0041503906250000, 0.0006408691406250, 0.0045471191406250, 0.0014648437500000, +0.0045776367187500, -0.0004577636718750, 0.0022583007812500, 0.0000610351562500, +0.0035705566406250, 0.0012512207031250, 0.0025024414062500, -0.0068359375000000, +0.0028381347656250, -0.0050964355468750, 0.0026245117187500, -0.0072937011718750, +0.0020141601562500, -0.0145874023437500, 0.0030822753906250, -0.0112915039062500, +0.0018310546875000, -0.0118713378906250, 0.0018005371093750, -0.0160827636718750, +0.0023803710937500, -0.0083923339843750, 0.0023803710937500, -0.0033874511718750, +0.0023803710937500, -0.0093078613281250, 0.0018310546875000, 0.0150756835937500, +0.0037231445312500, 0.0079040527343750, 0.0001831054687500, 0.0211791992187500, +-0.0020141601562500, 0.0439758300781250, 0.0007934570312500, 0.0284729003906250, +-0.0148620605468750, 0.0660705566406250, -0.0101928710937500, 0.0627746582031250, +-0.0205078125000000, 0.0674133300781250, -0.0376892089843750, 0.0928344726562500, +-0.0291748046875000, 0.0817871093750000, -0.0554809570312500, 0.0885925292968750, +-0.0539855957031250, 0.0967102050781250, -0.0620422363281250, 0.0858764648437500, +-0.0812072753906250, 0.0787048339843750, -0.0729980468750000, 0.0871582031250000, +-0.0955200195312500, 0.0661926269531250, -0.0972290039062500, 0.0669555664062500, +-0.0965576171875000, 0.0669250488281250, -0.1094055175781250, 0.0562438964843750, +-0.1070861816406250, 0.0592956542968750, -0.0931701660156250, 0.0533142089843750, +-0.1034240722656250, 0.0572204589843750, -0.0852050781250000, 0.0461120605468750, +-0.0618286132812500, 0.0369873046875000, -0.0775146484375000, 0.0474243164062500, +-0.0339355468750000, 0.0076904296875000, -0.0338745117187500, 0.0162048339843750, +-0.0302734375000000, 0.0044250488281250, -0.0052795410156250, -0.0289306640625000, +-0.0140380859375000, -0.0125732421875000, -0.0072326660156250, -0.0364990234375000, +-0.0029296875000000, -0.0400390625000000, -0.0093688964843750, -0.0400695800781250, +-0.0128173828125000, -0.0479431152343750, -0.0094299316406250, -0.0454406738281250, +-0.0174560546875000, -0.0643615722656250, -0.0216064453125000, -0.0543823242187500, +-0.0142211914062500, -0.0720214843750000, -0.0108642578125000, -0.0976562500000000, +-0.0163269042968750, -0.0787048339843750, -0.0033874511718750, -0.1188964843750000, +-0.0019531250000000, -0.1221008300781250, -0.0029296875000000, -0.1146545410156250, +0.0016174316406250, -0.1324157714843750, -0.0007019042968750, -0.1317749023437500, +-0.0030212402343750, -0.1033325195312500, 0.0016784667968750, -0.1167297363281250, +-0.0079650878906250, -0.0993652343750000, -0.0196533203125000, -0.0665893554687500, +-0.0117797851562500, -0.0841064453125000, -0.0217895507812500, -0.0430603027343750, +-0.0278625488281250, -0.0458984375000000, -0.0210266113281250, -0.0344543457031250, +-0.0179443359375000, -0.0078430175781250, -0.0219116210937500, -0.0241394042968750, +-0.0090026855468750, 0.0185852050781250, -0.0122070312500000, 0.0155029296875000, +-0.0054626464843750, 0.0198059082031250, 0.0061950683593750, 0.0487365722656250, +-0.0012512207031250, 0.0380554199218750, 0.0190429687500000, 0.0390319824218750, +0.0177001953125000, 0.0472717285156250, 0.0186462402343750, 0.0403137207031250, +0.0335388183593750, 0.0281372070312500, 0.0308837890625000, 0.0304565429687500, +0.0227966308593750, 0.0297851562500000, 0.0266723632812500, 0.0288391113281250, +0.0273437500000000, 0.0265502929687500, 0.0198974609375000, 0.0267333984375000, +0.0208435058593750, 0.0283203125000000, 0.0295410156250000, 0.0140686035156250, +0.0252990722656250, 0.0150146484375000, 0.0283813476562500, 0.0174560546875000, +0.0389404296875000, 0.0098266601562500, 0.0342102050781250, 0.0091247558593750, +0.0308227539062500, 0.0180358886718750, 0.0379028320312500, 0.0180358886718750, +0.0270080566406250, 0.0169067382812500, 0.0150146484375000, 0.0184326171875000, +0.0243835449218750, 0.0189208984375000, 0.0000610351562500, 0.0284729003906250, +0.0014343261718750, 0.0238647460937500, -0.0021667480468750, 0.0281982421875000, +-0.0160827636718750, 0.0427246093750000, -0.0094604492187500, 0.0376586914062500, +-0.0267028808593750, 0.0263061523437500, -0.0220336914062500, 0.0343322753906250, +-0.0308532714843750, 0.0279846191406250, -0.0472106933593750, 0.0105895996093750, +-0.0362854003906250, 0.0166015625000000, -0.0605468750000000, 0.0162658691406250, +-0.0601501464843750, 0.0108947753906250, -0.0626831054687500, 0.0168762207031250, +-0.0772094726562500, 0.0237121582031250, -0.0716247558593750, 0.0179443359375000, +-0.0788574218750000, 0.0258178710937500, -0.0801696777343750, 0.0316772460937500, +-0.0788574218750000, 0.0178222656250000, -0.0820312500000000, 0.0111083984375000, +-0.0815734863281250, 0.0205078125000000, -0.0760803222656250, -0.0132141113281250, +-0.0807800292968750, -0.0114135742187500, -0.0721130371093750, -0.0179443359375000, +-0.0625915527343750, -0.0391235351562500, -0.0709228515625000, -0.0308227539062500, +-0.0475769042968750, -0.0533447265625000, -0.0517578125000000, -0.0520935058593750, +-0.0450439453125000, -0.0583190917968750, -0.0282287597656250, -0.0751342773437500, +-0.0381164550781250, -0.0678405761718750, -0.0136108398437500, -0.0815429687500000, +-0.0190429687500000, -0.0835266113281250, -0.0090942382812500, -0.0835876464843750, +0.0108032226562500, -0.0900268554687500, -0.0026245117187500, -0.0885620117187500, +0.0307922363281250, -0.0881652832031250, 0.0249023437500000, -0.0918579101562500, +0.0336608886718750, -0.0842285156250000, 0.0582885742187500, -0.0783081054687500, +0.0437927246093750, -0.0834655761718750, 0.0715332031250000, -0.0597839355468750, +0.0699462890625000, -0.0629272460937500, 0.0731201171875000, -0.0540466308593750, +0.0899047851562500, -0.0345153808593750, 0.0816040039062500, -0.0433654785156250, +0.0940856933593750, -0.0229797363281250, 0.0959167480468750, -0.0214538574218750, +0.0928955078125000, -0.0212402343750000, 0.0981445312500000, -0.0106811523437500, +0.0978393554687500, -0.0135498046875000, 0.0852661132812500, -0.0157775878906250, +0.0938720703125000, -0.0118408203125000, 0.0785217285156250, -0.0172424316406250, +0.0604858398437500, -0.0238037109375000, 0.0752868652343750, -0.0195312500000000, +0.0292053222656250, -0.0315246582031250, 0.0367736816406250, -0.0300292968750000, +0.0258178710937500, -0.0323486328125000, -0.0087280273437500, -0.0401306152343750, +0.0095825195312500, -0.0356140136718750, -0.0156860351562500, -0.0434875488281250, +-0.0201110839843750, -0.0425415039062500, -0.0147094726562500, -0.0420227050781250, +-0.0227355957031250, -0.0460510253906250, -0.0232849121093750, -0.0428161621093750, +-0.0158081054687500, -0.0414733886718750, -0.0182800292968750, -0.0409240722656250, +-0.0169067382812500, -0.0379638671875000, -0.0110168457031250, -0.0350952148437500, +-0.0133666992187500, -0.0350341796875000, -0.0094909667968750, -0.0329284667968750, +-0.0090942382812500, -0.0302124023437500, -0.0090942382812500, -0.0301208496093750, +-0.0064086914062500, -0.0310363769531250, -0.0072631835937500, -0.0297241210937500, +-0.0114440917968750, -0.0291442871093750, -0.0078430175781250, -0.0303955078125000, +-0.0142822265625000, -0.0282592773437500, -0.0233764648437500, -0.0256347656250000, +-0.0174255371093750, -0.0278625488281250, -0.0260925292968750, -0.0261230468750000, +-0.0318603515625000, -0.0243225097656250, -0.0216979980468750, -0.0277709960937500, +-0.0173034667968750, -0.0292663574218750, -0.0239868164062500, -0.0268249511718750, +0.0018005371093750, -0.0373229980468750, -0.0001525878906250, -0.0330810546875000, +0.0037231445312500, -0.0407409667968750, 0.0203247070312500, -0.0515747070312500, +0.0146179199218750, -0.0431518554687500, 0.0257568359375000, -0.0683898925781250, +0.0261535644531250, -0.0642700195312500, 0.0283813476562500, -0.0695800781250000, +0.0360412597656250, -0.0890502929687500, 0.0335388183593750, -0.0791625976562500, +0.0384216308593750, -0.0865783691406250, 0.0380554199218750, -0.0934143066406250, +0.0440063476562500, -0.0832519531250000, 0.0471496582031250, -0.0783081054687500, +0.0430297851562500, -0.0856018066406250, 0.0738220214843750, -0.0598754882812500, +0.0650024414062500, -0.0632019042968750, 0.0791625976562500, -0.0587463378906250, +0.1116638183593750, -0.0407104492187500, 0.0958251953125000, -0.0480346679687500, +0.1135253906250000, -0.0376281738281250, 0.1254272460937500, -0.0377502441406250, +0.1069030761718750, -0.0340576171875000, 0.0999145507812500, -0.0282897949218750, +0.1113586425781250, -0.0329895019531250, 0.0628662109375000, -0.0127258300781250, +0.0717773437500000, -0.0167236328125000, 0.0552062988281250, -0.0098266601562500, +0.0154113769531250, 0.0073852539062500, 0.0354309082031250, -0.0004882812500000, +-0.0039672851562500, 0.0156860351562500, -0.0053405761718750, 0.0143737792968750, +-0.0081481933593750, 0.0201416015625000, -0.0286865234375000, 0.0340881347656250, +-0.0209350585937500, 0.0267944335937500, -0.0367126464843750, 0.0344848632812500, +-0.0342102050781250, 0.0424194335937500, -0.0435180664062500, 0.0303039550781250, +-0.0574645996093750, 0.0209655761718750, -0.0477600097656250, 0.0301208496093750, +-0.0774536132812500, 0.0122680664062500, -0.0741577148437500, 0.0102844238281250, +-0.0795593261718750, 0.0116271972656250, -0.1013793945312500, 0.0044860839843750, +-0.0925598144531250, 0.0071105957031250, -0.1011352539062500, 0.0111694335937500, +-0.1062011718750000, 0.0049743652343750, -0.1001586914062500, 0.0166015625000000, +-0.0990600585937500, 0.0320129394531250, -0.1017456054687500, 0.0211791992187500, +-0.0845031738281250, 0.0286865234375000, -0.0924377441406250, 0.0411682128906250, +-0.0732421875000000}, +{0.0875854492187500, -0.0082092285156250, 0.0702819824218750, -0.0073852539062500, +0.0483093261718750, -0.0046081542968750, 0.0654296875000000, -0.0046386718750000, +0.0165405273437500, -0.0015258789062500, 0.0230102539062500, -0.0015563964843750, +0.0141906738281250, -0.0001831054687500, -0.0211486816406250, 0.0025634765625000, +-0.0046691894531250, 0.0012512207031250, -0.0217590332031250, 0.0015869140625000, +-0.0280456542968750, 0.0025939941406250, -0.0206298828125000, 0.0001525878906250, +-0.0210876464843750, -0.0018615722656250, -0.0242004394531250, -0.0005493164062500, +-0.0166320800781250, -0.0051879882812500, -0.0146789550781250, -0.0058898925781250, +-0.0202331542968750, -0.0060119628906250, -0.0207824707031250, -0.0077819824218750, +-0.0176086425781250, -0.0077209472656250, -0.0303955078125000, -0.0096435546875000, +-0.0313110351562500, -0.0086975097656250, -0.0268554687500000, -0.0113525390625000, +-0.0321044921875000, -0.0148925781250000, -0.0335693359375000, -0.0126953125000000, +-0.0131530761718750, -0.0155944824218750, -0.0191955566406250, -0.0180053710937500, +-0.0102539062500000, -0.0161743164062500, 0.0092163085937500, -0.0157165527343750, +-0.0002746582031250, -0.0183410644531250, 0.0191040039062500, -0.0142517089843750, +0.0189514160156250, -0.0156250000000000, 0.0229797363281250, -0.0150756835937500, +0.0351867675781250, -0.0122985839843750, 0.0293884277343750, -0.0148010253906250, +0.0429077148437500, -0.0114440917968750, 0.0429077148437500, -0.0091552734375000, +0.0454101562500000, -0.0151062011718750, 0.0523376464843750, -0.0151367187500000, +0.0494995117187500, -0.0109558105468750, 0.0661315917968750, -0.0380859375000000, +0.0606384277343750, -0.0266723632812500, 0.0744323730468750, -0.0402221679687500, +0.0957031250000000, -0.0681457519531250, 0.0827636718750000, -0.0490722656250000, +0.1068420410156250, -0.0795593261718750, 0.1138916015625000, -0.0833435058593750, +0.1019592285156250, -0.0762329101562500, 0.1051025390625000, -0.0867309570312500, +0.1101989746093750, -0.0867004394531250, 0.0733337402343750, -0.0704650878906250, +0.0823669433593750, -0.0757141113281250, 0.0660705566406250, -0.0675048828125000, +0.0330200195312500, -0.0536499023437500, 0.0505371093750000, -0.0615844726562500, +0.0103149414062500, -0.0320739746093750, 0.0110778808593750, -0.0415649414062500, +0.0061035156250000, -0.0220947265625000, -0.0177612304687500, 0.0100097656250000, +-0.0080871582031250, -0.0107421875000000, -0.0256958007812500, 0.0354614257812500, +-0.0244140625000000, 0.0374755859375000, -0.0318603515625000, 0.0372924804687500, +-0.0445556640625000, 0.0600891113281250, -0.0359802246093750, 0.0538024902343750, +-0.0638427734375000, 0.0567016601562500, -0.0602416992187500, 0.0600280761718750, +-0.0668640136718750, 0.0531005859375000, -0.0887145996093750, 0.0514526367187500, +-0.0793762207031250, 0.0563659667968750, -0.0899353027343750, 0.0318908691406250, +-0.0942687988281250, 0.0344543457031250, -0.0897216796875000, 0.0344848632812500, +-0.0907287597656250, 0.0198364257812500, -0.0918884277343750, 0.0234375000000000, +-0.0792541503906250, 0.0251159667968750, -0.0859069824218750, 0.0248413085937500, +-0.0699768066406250, 0.0252075195312500, -0.0540771484375000, 0.0248718261718750, +-0.0671386718750000, 0.0256958007812500, -0.0097656250000000, 0.0332946777343750, +-0.0211791992187500, 0.0327758789062500, -0.0004577636718750, 0.0278930664062500, +0.0509948730468750, 0.0332641601562500, 0.0265197753906250, 0.0372619628906250, +0.0614013671875000, 0.0092468261718750, 0.0749511718750000, 0.0135192871093750, +0.0571899414062500, 0.0104980468750000, 0.0571899414062500, -0.0070800781250000, +0.0679016113281250, -0.0018920898437500, 0.0341491699218750, -0.0177001953125000, +0.0338439941406250, -0.0101318359375000, 0.0393981933593750, -0.0275878906250000, +0.0235595703125000, -0.0513305664062500, 0.0246582031250000, -0.0344848632812500, +0.0466613769531250, -0.0718688964843750, 0.0390930175781250, -0.0765991210937500, +0.0467834472656250, -0.0741882324218750, 0.0690612792968750, -0.0899963378906250, +0.0596008300781250, -0.0862731933593750, 0.0640869140625000, -0.0754699707031250, +0.0701599121093750, -0.0871276855468750, 0.0631103515625000, -0.0686950683593750, +0.0570678710937500, -0.0442504882812500, 0.0615234375000000, -0.0623474121093750, +0.0514221191406250, -0.0320739746093750, 0.0523681640625000, -0.0258789062500000, +0.0477294921875000, -0.0346679687500000, 0.0323791503906250, -0.0289916992187500, +-0.0241394042968750, -0.0646972656250000, -0.0511779785156250, -0.0248718261718750, +-0.0505371093750000, -0.0262145996093750, -0.0488891601562500, -0.0310058593750000, +-0.0520019531250000, -0.0281066894531250, -0.0535278320312500, -0.0255126953125000, +-0.0571899414062500, -0.0235290527343750, -0.0496826171875000, -0.0329589843750000, +-0.0667419433593750, -0.0163879394531250, -0.0804138183593750, 0.0008850097656250, +-0.0652160644531250, -0.0134277343750000, -0.1163635253906250, 0.0206298828125000, +-0.1156005859375000, 0.0225219726562500, -0.1109619140625000, 0.0208740234375000, +-0.1400756835937500, 0.0348815917968750, -0.1364440917968750, 0.0314941406250000, +-0.1040954589843750, 0.0373840332031250, -0.1215515136718750, 0.0348815917968750, +-0.0963745117187500, 0.0408630371093750, -0.0583190917968750, 0.0502014160156250, +-0.0835571289062500, 0.0438232421875000, -0.0114440917968750, 0.0520019531250000, +-0.0209655761718750, 0.0575561523437500, -0.0052795410156250, 0.0481567382812500, +0.0481872558593750, 0.0435791015625000, 0.0238342285156250, 0.0499877929687500, +0.0596008300781250, 0.0302124023437500, 0.0638427734375000, 0.0304260253906250, +0.0613708496093750, 0.0295715332031250, 0.0780334472656250, 0.0204162597656250, +0.0721130371093750, 0.0233459472656250, 0.0606689453125000, 0.0119628906250000, +0.0721130371093750, 0.0180969238281250, 0.0574340820312500, 0.0045776367187500, +0.0337829589843750, -0.0120544433593750, 0.0480346679687500, 0.0005187988281250, +0.0296325683593750, -0.0361022949218750, 0.0234985351562500, -0.0335998535156250, +0.0332336425781250, -0.0403442382812500, 0.0315856933593750, -0.0642700195312500, +0.0285644531250000, -0.0539855957031250, 0.0583801269531250, -0.0742797851562500, +0.0494079589843750, -0.0752258300781250, 0.0581970214843750, -0.0747070312500000, +0.0895385742187500, -0.0870056152343750, 0.0755310058593750, -0.0838317871093750, +0.0642700195312500, -0.0720520019531250, 0.0858154296875000, -0.0819396972656250, +0.0541687011718750, -0.0656433105468750, 0.0186462402343750, -0.0434875488281250, +0.0474548339843750, -0.0579528808593750, -0.0246582031250000, -0.0252380371093750, +-0.0202636718750000, -0.0229187011718750, -0.0264892578125000, -0.0243835449218750, +-0.0696105957031250, -0.0114746093750000, -0.0520019531250000, -0.0145263671875000, +-0.0739440917968750, -0.0059204101562500, -0.0804443359375000, -0.0112304687500000, +-0.0696105957031250, 0.0005798339843750, -0.0737915039062500, 0.0146179199218750, +-0.0783081054687500, 0.0039062500000000, -0.0466308593750000, 0.0354003906250000, +-0.0547790527343750, 0.0323181152343750, -0.0429382324218750, 0.0399475097656250, +-0.0158386230468750, 0.0608215332031250, -0.0311279296875000, 0.0504150390625000, +-0.0027465820312500, 0.0786132812500000, -0.0030822753906250, 0.0752868652343750, +-0.0036621093750000, 0.0816650390625000, 0.0118103027343750, 0.1042785644531250, +0.0064392089843750, 0.0944824218750000, 0.0051574707031250, 0.0998535156250000, +0.0104370117187500, 0.1083679199218750, 0.0030822753906250, 0.0959472656250000, +-0.0038452148437500, 0.0863647460937500, 0.0027770996093750, 0.0946960449218750, +-0.0150756835937500, 0.0679931640625000, -0.0112915039062500, 0.0704040527343750, +-0.0153503417968750, 0.0628051757812500, -0.0275573730468750, 0.0446166992187500, +-0.0187683105468750, 0.0538024902343750, -0.0337524414062500, 0.0280761718750000, +-0.0309753417968750, 0.0302734375000000, -0.0310668945312500, 0.0238342285156250, +-0.0399475097656250, 0.0054931640625000, -0.0340576171875000, 0.0136718750000000, +-0.0381774902343750, -0.0044250488281250, -0.0376892089843750, -0.0028686523437500, +-0.0351562500000000, -0.0090026855468750, -0.0347595214843750, -0.0227661132812500, +-0.0323791503906250, -0.0153808593750000, -0.0313720703125000, -0.0326843261718750, +-0.0291748046875000, -0.0350036621093750, -0.0290832519531250, -0.0313415527343750, +-0.0287475585937500, -0.0375976562500000, -0.0261535644531250, -0.0379333496093750, +-0.0311584472656250, -0.0255432128906250, -0.0289306640625000, -0.0285949707031250, +-0.0296936035156250, -0.0239868164062500, -0.0339355468750000, -0.0126342773437500, +-0.0305786132812500, -0.0171508789062500, -0.0319519042968750, -0.0093994140625000, +-0.0317687988281250, -0.0086975097656250, -0.0302429199218750, -0.0068969726562500, +-0.0289611816406250, -0.0039672851562500, -0.0269775390625000, -0.0063476562500000, +-0.0269470214843750, 0.0071105957031250, -0.0257873535156250, 0.0008239746093750, +-0.0236511230468750, 0.0119628906250000, -0.0230407714843750, 0.0275268554687500, +-0.0220947265625000, 0.0156860351562500, -0.0164184570312500, 0.0480041503906250, +-0.0181274414062500, 0.0440673828125000, -0.0141296386718750, 0.0498657226562500, +-0.0071716308593750, 0.0726623535156250, -0.0093994140625000, 0.0613403320312500, +-0.0018615722656250, 0.0734863281250000, -0.0004882812500000, 0.0785217285156250, +-0.0012207031250000, 0.0714721679687500, 0.0020446777343750, 0.0711059570312500, +0.0026550292968750, 0.0750122070312500, -0.0007934570312500, 0.0616760253906250, +0.0003662109375000, 0.0631713867187500, -0.0004577636718750, 0.0621948242187500, +-0.0032958984375000, 0.0539855957031250, -0.0017395019531250, 0.0571289062500000, +-0.0034484863281250, 0.0538940429687500, -0.0030517578125000, 0.0552062988281250, +-0.0034179687500000, 0.0499572753906250, -0.0040283203125000, 0.0469055175781250, +-0.0028381347656250, 0.0517578125000000, -0.0073852539062500, 0.0262756347656250, +-0.0048217773437500, 0.0351257324218750, -0.0098571777343750, 0.0221862792968750, +-0.0145874023437500, -0.0036315917968750, -0.0096740722656250, 0.0119628906250000, +-0.0307922363281250, -0.0181579589843750, -0.0245666503906250, -0.0191955566406250, +-0.0365295410156250, -0.0198974609375000, -0.0578613281250000, -0.0344543457031250, +-0.0456542968750000, -0.0297851562500000, -0.0772094726562500, -0.0405273437500000, +-0.0791320800781250, -0.0368347167968750, -0.0773620605468750, -0.0478515625000000, +-0.0953674316406250, -0.0597229003906250, -0.0921630859375000, -0.0489501953125000, +-0.0688476562500000, -0.0860900878906250, -0.0820007324218750, -0.0797119140625000, +-0.0622253417968750, -0.0853576660156250, -0.0292663574218750, -0.1145629882812500, +-0.0473022460937500, -0.1020812988281250, -0.0106201171875000, -0.1015014648437500, +-0.0058288574218750, -0.1160888671875000, -0.0110168457031250, -0.0943603515625000, +0.0025024414062500, -0.0744018554687500, 0.0007629394531250, -0.0929870605468750, +-0.0120849609375000, -0.0426330566406250, -0.0084533691406250, -0.0458068847656250, +-0.0123596191406250, -0.0401000976562500, -0.0245666503906250, -0.0092468261718750, +-0.0200195312500000, -0.0205078125000000, -0.0207519531250000, -0.0002136230468750, +-0.0280761718750000, -0.0021972656250000, -0.0148315429687500, 0.0076293945312500, +-0.0023193359375000, 0.0240478515625000, -0.0138549804687500, 0.0121154785156250, +0.0087280273437500, 0.0411071777343750, 0.0157165527343750, 0.0430908203125000, +0.0040893554687500, 0.0350952148437500, 0.0039978027343750, 0.0468444824218750, +0.0096435546875000}, +{-0.0319213867187500, -0.0075073242187500, -0.0404052734375000, -0.0013427734375000, +-0.0225830078125000, -0.0154724121093750, -0.0254516601562500, -0.0144958496093750, +-0.0214233398437500, -0.0190124511718750, -0.0090332031250000, -0.0303039550781250, +-0.0169982910156250, -0.0247802734375000, -0.0032043457031250, -0.0335388183593750, +-0.0039978027343750, -0.0372924804687500, -0.0046691894531250, -0.0305480957031250, +0.0024719238281250, -0.0304870605468750, -0.0012207031250000, -0.0340881347656250, +-0.0013122558593750, -0.0117187500000000, -0.0015563964843750, -0.0183410644531250, +-0.0039062500000000, -0.0060424804687500, -0.0062255859375000, 0.0154724121093750, +-0.0079040527343750, 0.0022888183593750, -0.0100402832031250, 0.0348205566406250, +-0.0106201171875000, 0.0313110351562500, -0.0130004882812500, 0.0377502441406250, +-0.0152893066406250, 0.0597839355468750, -0.0154724121093750, 0.0480041503906250, +-0.0209045410156250, 0.0672912597656250, -0.0205688476562500, 0.0692138671875000, +-0.0217285156250000, 0.0663146972656250, -0.0262451171875000, 0.0744628906250000, +-0.0254516601562500, 0.0734863281250000, -0.0247192382812500, 0.0668640136718750, +-0.0269775390625000, 0.0703430175781250, -0.0239257812500000, 0.0663452148437500, +-0.0204772949218750, 0.0585021972656250, -0.0232238769531250, 0.0628967285156250, +-0.0158996582031250, 0.0549926757812500, -0.0156250000000000, 0.0558776855468750, +-0.0147399902343750, 0.0515136718750000, -0.0103454589843750, 0.0463256835937500, +-0.0109863281250000, 0.0507812500000000, -0.0083618164062500, 0.0297851562500000, +-0.0083618164062500, 0.0369262695312500, -0.0060729980468750, 0.0253906250000000, +-0.0029907226562500, 0.0040893554687500, -0.0041809082031250, 0.0177612304687500, +0.0001525878906250, -0.0106201171875000, 0.0012817382812500, -0.0103149414062500, +0.0005187988281250, -0.0118408203125000, 0.0026855468750000, -0.0269775390625000, +0.0032348632812500, -0.0213012695312500, -0.0036315917968750, -0.0323791503906250, +0.0009155273437500, -0.0301818847656250, -0.0079040527343750, -0.0377502441406250, +-0.0181579589843750, -0.0470886230468750, -0.0102539062500000, -0.0393981933593750, +-0.0363464355468750, -0.0687255859375000, -0.0324401855468750, -0.0618591308593750, +-0.0430908203125000, -0.0711059570312500, -0.0653076171875000, -0.0974731445312500, +-0.0537719726562500, -0.0833740234375000, -0.0785827636718750, -0.0948791503906250, +-0.0837402343750000, -0.1062622070312500, -0.0734558105468750, -0.0876770019531250, +-0.0791931152343750, -0.0786132812500000, -0.0830078125000000, -0.0931396484375000, +-0.0500793457031250, -0.0460510253906250, -0.0559387207031250, -0.0530090332031250, +-0.0469055175781250, -0.0439147949218750, -0.0203857421875000, -0.0095520019531250, +-0.0312194824218750, -0.0242614746093750, -0.0152893066406250, -0.0035705566406250, +-0.0114135742187500, -0.0010070800781250, -0.0149230957031250, 0.0032043457031250, +-0.0109558105468750, 0.0122375488281250, -0.0106811523437500, 0.0055847167968750, +-0.0167541503906250, 0.0314941406250000, -0.0153198242187500, 0.0269775390625000, +-0.0171508789062500, 0.0286254882812500, -0.0253906250000000, 0.0496826171875000, +-0.0230712890625000, 0.0433959960937500, -0.0089721679687500, 0.0298156738281250, +-0.0174560546875000, 0.0418090820312500, -0.0104675292968750, 0.0289916992187500, +0.0086975097656250, 0.0053405761718750, 0.0008850097656250, 0.0199890136718750, +0.0053405761718750, 0.0074157714843750, 0.0096435546875000, -0.0022277832031250, +0.0024719238281250, 0.0100402832031250, 0.0001831054687500, 0.0178222656250000, +0.0040588378906250, 0.0093078613281250, -0.0214538574218750, 0.0263366699218750, +-0.0175476074218750, 0.0292968750000000, -0.0180358886718750, 0.0262756347656250, +-0.0386047363281250, 0.0298461914062500, -0.0355224609375000, 0.0289611816406250, +-0.0166625976562500, 0.0286254882812500, -0.0269165039062500, 0.0292053222656250, +-0.0193176269531250, 0.0258789062500000, -0.0011901855468750, 0.0251770019531250, +-0.0127563476562500, 0.0267639160156250, 0.0120544433593750, 0.0091857910156250, +0.0124206542968750, 0.0111694335937500, 0.0114746093750000, 0.0097045898437500, +0.0235290527343750, -0.0032348632812500, 0.0202941894531250, -0.0008850097656250, +0.0220642089843750, 0.0038146972656250, 0.0228576660156250, 0.0007324218750000, +0.0221862792968750, 0.0010375976562500, 0.0226440429687500, 0.0075683593750000, +0.0228576660156250, 0.0058593750000000, 0.0214843750000000, -0.0062866210937500, +0.0201721191406250, -0.0000610351562500, 0.0249633789062500, -0.0101623535156250, +0.0270996093750000, -0.0263977050781250, 0.0231933593750000, -0.0177001953125000, +0.0364685058593750, -0.0401306152343750, 0.0373535156250000, -0.0415649414062500, +0.0322875976562500, -0.0400085449218750, 0.0383605957031250, -0.0497436523437500, +0.0405578613281250, -0.0489196777343750, 0.0170898437500000, -0.0496826171875000, +0.0245971679687500, -0.0481872558593750, 0.0151977539062500, -0.0517578125000000, +-0.0082397460937500, -0.0541381835937500, 0.0028991699218750, -0.0511474609375000, +-0.0114440917968750, -0.0669250488281250, -0.0143127441406250, -0.0618286132812500, +-0.0136718750000000, -0.0658874511718750, -0.0167846679687500, -0.0821228027343750, +-0.0148620605468750, -0.0749511718750000, -0.0273132324218750, -0.0704650878906250, +-0.0216369628906250, -0.0780639648437500, -0.0305786132812500, -0.0685424804687500, +-0.0462036132812500, -0.0548706054687500, -0.0361938476562500, -0.0625000000000000, +-0.0526733398437500, -0.0490722656250000, -0.0542602539062500, -0.0468139648437500, +-0.0525207519531250, -0.0459899902343750, -0.0586853027343750, -0.0410766601562500, +-0.0571289062500000, -0.0424804687500000, -0.0581665039062500, -0.0318603515625000, +-0.0592346191406250, -0.0339355468750000, -0.0566101074218750, -0.0281982421875000, +-0.0563964843750000, -0.0168762207031250, -0.0579223632812500, -0.0208435058593750, +-0.0467529296875000, -0.0101013183593750, -0.0520019531250000, -0.0068969726562500, +-0.0436096191406250, -0.0086364746093750, -0.0311279296875000, -0.0045776367187500, +-0.0405578613281250, -0.0036926269531250, -0.0165100097656250, -0.0156860351562500, +-0.0202026367187500, -0.0103149414062500, -0.0136413574218750, -0.0191345214843750, +0.0037231445312500, -0.0334472656250000, -0.0059509277343750, -0.0248718261718750, +0.0162048339843750, -0.0464172363281250, 0.0131835937500000, -0.0453491210937500, +0.0191650390625000, -0.0484008789062500, 0.0350952148437500, -0.0623474121093750, +0.0258789062500000, -0.0561523437500000, 0.0455932617187500, -0.0619506835937500, +0.0438537597656250, -0.0650634765625000, 0.0476684570312500, -0.0586853027343750, +0.0605163574218750, -0.0559082031250000, 0.0536499023437500, -0.0576782226562500, +0.0673217773437500, -0.0419616699218750, 0.0667114257812500, -0.0431518554687500, +0.0677795410156250, -0.0362854003906250, 0.0765686035156250, -0.0223693847656250, +0.0723266601562500, -0.0262756347656250, 0.0718688964843750, -0.0121154785156250, +0.0768737792968750, -0.0097656250000000, 0.0668640136718750, -0.0060119628906250, +0.0598754882812500, 0.0029602050781250, 0.0671997070312500, 0.0016174316406250, +0.0355224609375000, 0.0083007812500000, 0.0432434082031250, 0.0110778808593750, +0.0303955078125000, 0.0112304687500000, 0.0020141601562500, 0.0143127441406250, +0.0178833007812500, 0.0155334472656250, -0.0112304687500000, 0.0102233886718750, +-0.0130004882812500, 0.0147705078125000, -0.0084228515625000, 0.0102539062500000, +-0.0204772949218750, 0.0032653808593750, -0.0176696777343750, 0.0098266601562500, +-0.0063781738281250, -0.0046691894531250, -0.0120544433593750, -0.0014343261718750, +-0.0034790039062500, -0.0052490234375000, 0.0104675292968750, -0.0160827636718750, +0.0024108886718750, -0.0088500976562500, 0.0209960937500000, -0.0224914550781250, +0.0211181640625000, -0.0209045410156250, 0.0227355957031250, -0.0229492187500000, +0.0328369140625000, -0.0315246582031250, 0.0292053222656250, -0.0267333984375000, +0.0369873046875000, -0.0367431640625000, 0.0345458984375000, -0.0355834960937500, +0.0431213378906250, -0.0361633300781250, 0.0516052246093750, -0.0422363281250000, +0.0440979003906250, -0.0390319824218750, 0.0760803222656250, -0.0421752929687500, +0.0715332031250000, -0.0415649414062500, 0.0775756835937500, -0.0433654785156250, +0.1030883789062500, -0.0451354980468750, 0.0933227539062500, -0.0419616699218750, +0.0935668945312500, -0.0518798828125000, 0.1030578613281250, -0.0493164062500000, +0.0856628417968750, -0.0492248535156250, 0.0702514648437500, -0.0567626953125000, +0.0820007324218750, -0.0533142089843750, 0.0429992675781250, -0.0483398437500000, +0.0461730957031250, -0.0543212890625000, 0.0370178222656250, -0.0458679199218750, +0.0101318359375000, -0.0344238281250000, 0.0217285156250000, -0.0423278808593750, +-0.0036315917968750, -0.0263977050781250, -0.0032348632812500, -0.0263366699218750, +-0.0091552734375000, -0.0234985351562500, -0.0244750976562500, -0.0149230957031250, +-0.0164489746093750, -0.0196228027343750, -0.0414123535156250, -0.0055236816406250, +-0.0370788574218750, -0.0057373046875000, -0.0452575683593750, -0.0074462890625000, +-0.0664367675781250, 0.0010986328125000, -0.0559997558593750, 0.0002441406250000, +-0.0724487304687500, -0.0133056640625000, -0.0755920410156250, -0.0094299316406250, +-0.0724487304687500, -0.0107116699218750, -0.0774536132812500, -0.0249023437500000, +-0.0772705078125000, -0.0224609375000000, -0.0723266601562500, -0.0046386718750000, +-0.0758666992187500, -0.0149536132812500, -0.0667114257812500, 0.0008544921875000, +-0.0596008300781250, 0.0261535644531250, -0.0664062500000000, 0.0132446289062500, +-0.0301513671875000, 0.0491333007812500, -0.0407714843750000, 0.0482177734375000, +-0.0234375000000000, 0.0510559082031250, 0.0131835937500000, 0.0752563476562500, +-0.0058593750000000, 0.0682067871093750, 0.0298156738281250, 0.0607910156250000, +0.0379638671875000, 0.0711669921875000, 0.0273132324218750, 0.0579833984375000, +0.0352172851562500, 0.0396423339843750, 0.0391540527343750, 0.0510253906250000, +0.0163269042968750, 0.0258178710937500, 0.0174865722656250, 0.0259704589843750, +0.0197753906250000, 0.0249023437500000, 0.0070495605468750, 0.0092468261718750, +0.0085449218750000, 0.0150146484375000, 0.0236511230468750, 0.0219421386718750, +0.0178833007812500, 0.0160522460937500, 0.0249023437500000, 0.0201721191406250, +0.0416870117187500, 0.0327148437500000, 0.0342712402343750, 0.0289611816406250, +0.0409851074218750, 0.0226440429687500, 0.0450744628906250, 0.0299377441406250, +0.0408630371093750, 0.0198669433593750, 0.0388183593750000, 0.0068969726562500, +0.0405883789062500, 0.0156860351562500, 0.0353393554687500, -0.0090332031250000, +0.0374450683593750, -0.0068054199218750, 0.0308837890625000, -0.0115661621093750, +0.0261230468750000, -0.0312805175781250, 0.0313720703125000, -0.0236816406250000, +-0.0007019042968750, -0.0206604003906250, 0.0072021484375000, -0.0251464843750000, +-0.0054931640625000, -0.0295104980468750, -0.0365295410156250, -0.0216674804687500, +-0.0220642089843750, -0.0186157226562500, -0.0400085449218750, -0.0606079101562500, +-0.0473327636718750, -0.0509643554687500, -0.0426330566406250, -0.0558166503906250, +-0.0434570312500000, -0.1054077148437500, -0.0632324218750000, -0.0149536132812500, +-0.1024475097656250, -0.0679931640625000, -0.1012573242187500, -0.0497436523437500, +-0.0938110351562500, -0.0602111816406250, -0.0998840332031250, -0.0930786132812500, +-0.1048583984375000, -0.0845642089843750, -0.0812072753906250, -0.0662231445312500, +-0.0879821777343750}, +{0.0831909179687500, -0.0287170410156250, 0.0911560058593750, -0.0327148437500000, +0.0785217285156250, -0.0246582031250000, 0.0715637207031250, -0.0182495117187500, +0.0785217285156250, -0.0251770019531250, 0.0477600097656250, -0.0051574707031250, +0.0507812500000000, -0.0067749023437500, 0.0400390625000000, -0.0068664550781250, +0.0159301757812500, 0.0058288574218750, 0.0267944335937500, 0.0023803710937500, +0.0034790039062500, -0.0031127929687500, 0.0024108886718750, 0.0040893554687500, +-0.0008544921875000, -0.0043029785156250, -0.0129394531250000, -0.0161132812500000, +-0.0079956054687500, -0.0074157714843750, -0.0257873535156250, -0.0244750976562500, +-0.0217285156250000, -0.0225830078125000, -0.0307006835937500, -0.0266113281250000, +-0.0474243164062500, -0.0379943847656250, -0.0375366210937500, -0.0308227539062500, +-0.0592651367187500, -0.0458374023437500, -0.0596923828125000, -0.0472106933593750, +-0.0598144531250000, -0.0417480468750000, -0.0711364746093750, -0.0473937988281250, +-0.0676879882812500, -0.0489807128906250, -0.0692138671875000, -0.0295104980468750, +-0.0720825195312500, -0.0342407226562500, -0.0663452148437500, -0.0277709960937500, +-0.0647888183593750, -0.0107421875000000, -0.0684204101562500, -0.0172119140625000, +-0.0430603027343750, -0.0033569335937500, -0.0525207519531250, -0.0052795410156250, +-0.0343322753906250, 0.0028076171875000, -0.0040893554687500, 0.0155639648437500, +-0.0222778320312500, 0.0065307617187500, 0.0137023925781250, 0.0260314941406250, +0.0186157226562500, 0.0274658203125000, 0.0115661621093750, 0.0272216796875000, +0.0239562988281250, 0.0350646972656250, 0.0244140625000000, 0.0326538085937500, +0.0086059570312500, 0.0401916503906250, 0.0114440917968750, 0.0390625000000000, +0.0117187500000000, 0.0415649414062500, 0.0000000000000000, 0.0485229492187500, +0.0022583007812500, 0.0453796386718750, 0.0149230957031250, 0.0477905273437500, +0.0087585449218750, 0.0508728027343750, 0.0158691406250000, 0.0450439453125000, +0.0315551757812500, 0.0426025390625000, 0.0242614746093750, 0.0470581054687500, +0.0324096679687500, 0.0280456542968750, 0.0361022949218750, 0.0310363769531250, +0.0323486328125000, 0.0260925292968750, 0.0314941406250000, 0.0117187500000000, +0.0329589843750000, 0.0187683105468750, 0.0292663574218750, 0.0074768066406250, +0.0302734375000000, 0.0053710937500000, 0.0257263183593750, 0.0091247558593750, +0.0231933593750000, 0.0066223144531250, 0.0266723632812500, 0.0055541992187500, +0.0021057128906250, 0.0122680664062500, 0.0095520019531250, 0.0149536132812500, +-0.0026550292968750, 0.0069885253906250, -0.0289001464843750, 0.0070495605468750, +-0.0158386230468750, 0.0130004882812500, -0.0343322753906250, -0.0204772949218750, +-0.0404663085937500, -0.0183105468750000, -0.0352478027343750, -0.0132446289062500, +-0.0347900390625000, -0.0307617187500000, -0.0374145507812500, -0.0313415527343750, +-0.0477294921875000, -0.0149230957031250, -0.0382385253906250, -0.0136718750000000, +-0.0517272949218750, -0.0234680175781250, -0.0885620117187500, -0.0266113281250000, +-0.1034545898437500, -0.0217285156250000, -0.0621032714843750, -0.0182189941406250, +-0.0774230957031250, -0.0136413574218750, -0.0676269531250000, -0.0254516601562500, +-0.0472106933593750, -0.0305786132812500, -0.0549926757812500, -0.0228881835937500, +-0.0323181152343750, -0.0615539550781250, -0.0407104492187500, -0.0575256347656250, +-0.0227050781250000, -0.0591125488281250, 0.0030517578125000, -0.0875854492187500, +-0.0148925781250000, -0.0808105468750000, 0.0381774902343750, -0.0590209960937500, +0.0331420898437500, -0.0733642578125000, 0.0426025390625000, -0.0573120117187500, +0.0821533203125000, -0.0251464843750000, 0.0649414062500000, -0.0415954589843750, +0.0684204101562500, -0.0238037109375000, 0.0859680175781250, -0.0170898437500000, +0.0631103515625000, -0.0217285156250000, 0.0405578613281250, -0.0222778320312500, +0.0604858398437500, -0.0214538574218750, 0.0207214355468750, -0.0130004882812500, +0.0149841308593750, -0.0191955566406250, 0.0264892578125000, -0.0109252929687500, +0.0148010253906250, 0.0037536621093750, 0.0116882324218750, -0.0042724609375000, +0.0393066406250000, 0.0072021484375000, 0.0329589843750000, 0.0099792480468750, +0.0393981933593750, 0.0088195800781250, 0.0624694824218750, 0.0105590820312500, +0.0534973144531250, 0.0100402832031250, 0.0613403320312500, 0.0188903808593750, +0.0666198730468750, 0.0156860351562500, 0.0596618652343750, 0.0198669433593750, +0.0607299804687500, 0.0309448242187500, 0.0639343261718750, 0.0263061523437500, +0.0265808105468750, 0.0255737304687500, 0.0417785644531250, 0.0314941406250000, +0.0220031738281250, 0.0235900878906250, -0.0213928222656250, 0.0149536132812500, +0.0014953613281250, 0.0212707519531250, -0.0251770019531250, 0.0046081542968750, +-0.0345458984375000, 0.0063476562500000, -0.0276489257812500, 0.0010681152343750, +-0.0292968750000000, -0.0098571777343750, -0.0299072265625000, -0.0032653808593750, +-0.0295410156250000, -0.0251464843750000, -0.0254211425781250, -0.0211486816406250, +-0.0307312011718750, -0.0288085937500000, -0.0355529785156250, -0.0475463867187500, +-0.0291442871093750, -0.0386657714843750, -0.0420532226562500, -0.0559082031250000, +-0.0430908203125000, -0.0572814941406250, -0.0393676757812500, -0.0577392578125000, +-0.0448303222656250, -0.0664672851562500, -0.0448913574218750, -0.0633239746093750, +-0.0281372070312500, -0.0646362304687500, -0.0364990234375000, -0.0690612792968750, +-0.0239868164062500, -0.0598449707031250, -0.0022888183593750, -0.0539855957031250, +-0.0158691406250000, -0.0607604980468750, 0.0061340332031250, -0.0330810546875000, +0.0111999511718750, -0.0367126464843750, 0.0043334960937500, -0.0314025878906250, +0.0087280273437500, -0.0115356445312500, 0.0103454589843750, -0.0195922851562500, +-0.0030517578125000, -0.0083923339843750, 0.0011596679687500, -0.0081176757812500, +-0.0057983398437500, -0.0035400390625000, -0.0183410644531250, 0.0030517578125000, +-0.0102844238281250, -0.0021972656250000, -0.0287170410156250, 0.0194091796875000, +-0.0273742675781250, 0.0155029296875000, -0.0298767089843750, 0.0227966308593750, +-0.0413208007812500, 0.0403747558593750, -0.0355834960937500, 0.0323791503906250, +-0.0437622070312500, 0.0530395507812500, -0.0442810058593750, 0.0514526367187500, +-0.0437316894531250, 0.0572204589843750, -0.0476379394531250, 0.0731811523437500, +-0.0465698242187500, 0.0655517578125000, -0.0466613769531250, 0.0762939453125000, +-0.0484008789062500, 0.0810546875000000, -0.0469055175781250, 0.0738220214843750, +-0.0455322265625000, 0.0723876953125000, -0.0474548339843750, 0.0762634277343750, +-0.0423278808593750, 0.0595703125000000, -0.0443725585937500, 0.0612487792968750, +-0.0419921875000000, 0.0571289062500000, -0.0376281738281250, 0.0452880859375000, +-0.0416564941406250, 0.0499572753906250, -0.0333557128906250, 0.0386962890625000, +-0.0354003906250000, 0.0376892089843750, -0.0328674316406250, 0.0372924804687500, +-0.0265502929687500, 0.0303955078125000, -0.0311889648437500, 0.0310974121093750, +-0.0223388671875000, 0.0349121093750000, -0.0235900878906250, 0.0303955078125000, +-0.0223999023437500, 0.0351257324218750, -0.0168457031250000, 0.0420837402343750, +-0.0202331542968750, 0.0359802246093750, -0.0143737792968750, 0.0462341308593750, +-0.0156555175781250, 0.0462646484375000, -0.0151672363281250, 0.0448608398437500, +-0.0111694335937500, 0.0492553710937500, -0.0137939453125000, 0.0476989746093750, +-0.0112915039062500, 0.0460815429687500, -0.0106811523437500, 0.0466308593750000, +-0.0122680664062500, 0.0476074218750000, -0.0125122070312500, 0.0465698242187500, +-0.0119934082031250, 0.0461730957031250, -0.0129394531250000, 0.0516662597656250, +-0.0138244628906250, 0.0509948730468750, -0.0109558105468750, 0.0501708984375000, +-0.0096435546875000, 0.0547790527343750, -0.0111083984375000, 0.0543823242187500, +-0.0018005371093750, 0.0435485839843750, -0.0033874511718750, 0.0502014160156250, +0.0007324218750000, 0.0393371582031250, 0.0090942382812500, 0.0241699218750000, +0.0057373046875000, 0.0351867675781250, 0.0158081054687500, 0.0090942382812500, +0.0159301757812500, 0.0107727050781250, 0.0179748535156250, 0.0075683593750000, +0.0245666503906250, -0.0082092285156250, 0.0222778320312500, -0.0010986328125000, +0.0271301269531250, -0.0135192871093750, 0.0286254882812500, -0.0121765136718750, +0.0250854492187500, -0.0177917480468750, 0.0255737304687500, -0.0269470214843750, +0.0269775390625000, -0.0205383300781250, 0.0138549804687500, -0.0429992675781250, +0.0173034667968750, -0.0380554199218750, 0.0114135742187500, -0.0466308593750000, +-0.0016479492187500, -0.0659179687500000, 0.0046691894531250, -0.0545654296875000, +-0.0050964355468750, -0.0749511718750000, -0.0083007812500000, -0.0776672363281250, +-0.0027160644531250, -0.0707702636718750, -0.0030212402343750, -0.0784912109375000, +-0.0054321289062500, -0.0802001953125000, 0.0091857910156250, -0.0547180175781250, +0.0095825195312500, -0.0655212402343750, 0.0084838867187500, -0.0513916015625000, +0.0173950195312500, -0.0234985351562500, 0.0169677734375000, -0.0400085449218750, +0.0027160644531250, -0.0097351074218750, 0.0110168457031250, -0.0084838867187500, +-0.0037231445312500, -0.0072631835937500, -0.0230712890625000, 0.0075073242187500, +-0.0099487304687500, 0.0021057128906250, -0.0528259277343750, 0.0143737792968750, +-0.0512390136718750, 0.0119018554687500, -0.0509643554687500, 0.0177001953125000, +-0.0771789550781250, 0.0291748046875000, -0.0709838867187500, 0.0212707519531250, +-0.0559997558593750, 0.0330505371093750, -0.0644836425781250, 0.0379333496093750, +-0.0548706054687500, 0.0282592773437500, -0.0348510742187500, 0.0267944335937500, +-0.0436401367187500, 0.0335083007812500, -0.0324707031250000, 0.0103759765625000, +-0.0288391113281250, 0.0109558105468750, -0.0295410156250000, 0.0148010253906250, +-0.0275878906250000, 0.0030822753906250, -0.0291748046875000, 0.0038452148437500, +-0.0249633789062500, 0.0200500488281250, -0.0249023437500000, 0.0139770507812500, +-0.0229797363281250, 0.0193176269531250, -0.0217590332031250, 0.0360107421875000, +-0.0234375000000000, 0.0283508300781250, -0.0074462890625000, 0.0301513671875000, +-0.0095214843750000, 0.0377502441406250, -0.0098571777343750, 0.0275573730468750, +-0.0003356933593750, 0.0178833007812500, -0.0011901855468750, 0.0257568359375000, +0.0007934570312500, 0.0060119628906250, -0.0014953613281250, 0.0061340332031250, +0.0006103515625000, 0.0032348632812500, 0.0089111328125000, -0.0108032226562500, +0.0064392089843750, -0.0095520019531250, -0.0098876953125000, -0.0155029296875000, +-0.0013122558593750, -0.0167541503906250, -0.0059204101562500, -0.0123901367187500, +-0.0219421386718750, -0.0131835937500000, -0.0141601562500000, -0.0172119140625000, +-0.0262451171875000, -0.0078735351562500, -0.0293884277343750, -0.0052490234375000, +-0.0232238769531250, -0.0133972167968750, -0.0263061523437500, -0.0134887695312500, +-0.0299682617187500, -0.0093688964843750, -0.0088195800781250, -0.0374755859375000, +-0.0134582519531250, -0.0339050292968750, -0.0097961425781250, -0.0363464355468750, +0.0061035156250000, -0.0570678710937500, 0.0002746582031250, -0.0529785156250000, +0.0103149414062500, -0.0485534667968750, 0.0093383789062500, -0.0533752441406250, +0.0133666992187500, -0.0475463867187500, 0.0222778320312500, -0.0401306152343750, +0.0168457031250000, -0.0456237792968750, 0.0235900878906250, -0.0296936035156250, +0.0267639160156250, -0.0290222167968750, 0.0225524902343750, -0.0320739746093750, +0.0206298828125000}, +{0.0028381347656250, -0.0111999511718750, 0.0036010742187500, -0.0215454101562500, +0.0023193359375000, -0.0154113769531250, 0.0088195800781250, -0.0346069335937500, +0.0075378417968750, -0.0309448242187500, 0.0105895996093750, -0.0379333496093750, +0.0169372558593750, -0.0540161132812500, 0.0141906738281250, -0.0448303222656250, +0.0195922851562500, -0.0615844726562500, 0.0223083496093750, -0.0626525878906250, +0.0186462402343750, -0.0599060058593750, 0.0183715820312500, -0.0677795410156250, +0.0209960937500000, -0.0662536621093750, 0.0090332031250000, -0.0545959472656250, +0.0114746093750000, -0.0630798339843750, 0.0071105957031250, -0.0501403808593750, +-0.0036315917968750, -0.0323791503906250, 0.0015869140625000, -0.0457763671875000, +-0.0054016113281250, -0.0158386230468750, -0.0086364746093750, -0.0171203613281250, +-0.0037536621093750, -0.0136108398437500, -0.0018920898437500, 0.0039978027343750, +-0.0046081542968750, -0.0033874511718750, 0.0024414062500000, 0.0117492675781250, +0.0045776367187500, 0.0108642578125000, 0.0020446777343750, 0.0141296386718750, +0.0037841796875000, 0.0244445800781250, 0.0045166015625000, 0.0190429687500000, +-0.0074462890625000, 0.0286865234375000, -0.0003662109375000, 0.0301208496093750, +-0.0149230957031250, 0.0267333984375000, -0.0343017578125000, 0.0303955078125000, +-0.0203857421875000, 0.0314331054687500, -0.0490417480468750, 0.0185546875000000, +-0.0548095703125000, 0.0223083496093750, -0.0460815429687500, 0.0203552246093750, +-0.0520629882812500, 0.0085449218750000, -0.0551757812500000, 0.0126647949218750, +-0.0384521484375000, 0.0174865722656250, -0.0391540527343750, 0.0118103027343750, +-0.0399475097656250, 0.0180969238281250, -0.0310363769531250, 0.0287170410156250, +-0.0320129394531250, 0.0226135253906250, -0.0351257324218750, 0.0301513671875000, +-0.0333251953125000, 0.0346374511718750, -0.0350646972656250, 0.0264892578125000, +-0.0388488769531250, 0.0244750976562500, -0.0357055664062500, 0.0305175781250000, +-0.0350952148437500, 0.0076904296875000, -0.0412292480468750, 0.0111999511718750, +-0.0305786132812500, 0.0053710937500000, -0.0185546875000000, -0.0123596191406250, +-0.0277404785156250, -0.0048522949218750, -0.0149230957031250, -0.0170288085937500, +-0.0115051269531250, -0.0192565917968750, -0.0118713378906250, -0.0181579589843750, +-0.0079956054687500, -0.0234069824218750, -0.0082397460937500, -0.0229492187500000, +-0.0035095214843750, -0.0179748535156250, -0.0027770996093750, -0.0202331542968750, +-0.0063476562500000, -0.0216979980468750, -0.0064697265625000, -0.0170593261718750, +-0.0047912597656250, -0.0180664062500000, -0.0127868652343750, -0.0309448242187500, +-0.0108642578125000, -0.0260009765625000, -0.0167846679687500, -0.0339660644531250, +-0.0254516601562500, -0.0498962402343750, -0.0190124511718750, -0.0415344238281250, +-0.0303039550781250, -0.0473327636718750, -0.0354309082031250, -0.0554504394531250, +-0.0269775390625000, -0.0460205078125000, -0.0249633789062500, -0.0369567871093750, +-0.0309753417968750, -0.0433349609375000, -0.0134277343750000, -0.0296936035156250, +-0.0146789550781250, -0.0306091308593750, -0.0110473632812500, -0.0264587402343750, +-0.0010070800781250, -0.0139465332031250, -0.0066528320312500, -0.0197448730468750, +0.0106201171875000, -0.0229492187500000, 0.0074768066406250, -0.0137634277343750, +0.0113830566406250, -0.0265197753906250, 0.0258789062500000, -0.0430297851562500, +0.0195617675781250, -0.0309753417968750, 0.0227661132812500, -0.0472717285156250, +0.0270385742187500, -0.0561828613281250, 0.0226745605468750, -0.0420227050781250, +0.0179748535156250, -0.0368957519531250, 0.0213317871093750, -0.0462341308593750, +0.0211486816406250, -0.0156860351562500, 0.0169067382812500, -0.0187377929687500, +0.0224914550781250, -0.0147094726562500, 0.0302734375000000, 0.0068359375000000, +0.0252075195312500, -0.0021972656250000, 0.0258178710937500, -0.0038452148437500, +0.0338134765625000, 0.0050659179687500, 0.0205078125000000, -0.0059204101562500, +0.0083312988281250, -0.0205383300781250, 0.0200805664062500, -0.0119628906250000, +-0.0074157714843750, -0.0246887207031250, -0.0076599121093750, -0.0303039550781250, +-0.0057983398437500, -0.0213317871093750, -0.0182800292968750, -0.0201416015625000, +-0.0154724121093750, -0.0254821777343750, -0.0173034667968750, -0.0018920898437500, +-0.0155639648437500, -0.0050659179687500, -0.0211181640625000, 0.0018005371093750, +-0.0253906250000000, 0.0203247070312500, -0.0197448730468750, 0.0129699707031250, +-0.0379943847656250, 0.0287475585937500, -0.0351867675781250, 0.0301513671875000, +-0.0373535156250000, 0.0304260253906250, -0.0500488281250000, 0.0379638671875000, +-0.0446777343750000, 0.0358581542968750, -0.0484924316406250, 0.0390930175781250, +-0.0513000488281250, 0.0387573242187500, -0.0478515625000000, 0.0403747558593750, +-0.0462646484375000, 0.0431823730468750, -0.0479431152343750, 0.0415344238281250, +-0.0412902832031250, 0.0466308593750000, -0.0431213378906250, 0.0461425781250000, +-0.0397338867187500, 0.0469360351562500, -0.0343933105468750, 0.0503234863281250, +-0.0385131835937500, 0.0491027832031250, -0.0259094238281250, 0.0518798828125000, +-0.0298767089843750, 0.0520935058593750, -0.0234069824218750, 0.0519104003906250, +-0.0121154785156250, 0.0537414550781250, -0.0199279785156250, 0.0533142089843750, +0.0024414062500000, 0.0499877929687500, -0.0014953613281250, 0.0526428222656250, +0.0065917968750000, 0.0473632812500000, 0.0242309570312500, 0.0413513183593750, +0.0142517089843750, 0.0453796386718750, 0.0402832031250000, 0.0304565429687500, +0.0368957519531250, 0.0324707031250000, 0.0442504882812500, 0.0270080566406250, +0.0633544921875000, 0.0151977539062500, 0.0530700683593750, 0.0212402343750000, +0.0751953125000000, 0.0068969726562500, 0.0744628906250000, 0.0075073242187500, +0.0773010253906250, 0.0047607421875000, 0.0912475585937500, -0.0047302246093750, +0.0856018066406250, -0.0000610351562500, 0.0932312011718750, -0.0067138671875000, +0.0946960449218750, -0.0086669921875000, 0.0934448242187500, -0.0069885253906250, +0.0957336425781250, -0.0084228515625000, 0.0953674316406250, -0.0092468261718750, +0.0950317382812500, -0.0068359375000000, 0.0953063964843750, -0.0079956054687500, +0.0956726074218750, -0.0060424804687500, 0.0961303710937500, -0.0039062500000000, +0.0961608886718750, -0.0061035156250000, 0.0948791503906250, 0.0030822753906250, +0.0987854003906250, -0.0004577636718750, 0.0910644531250000, 0.0040893554687500, +0.0857543945312500, 0.0134887695312500, 0.0923461914062500, 0.0081176757812500, +0.0627746582031250, 0.0207519531250000, 0.0693054199218750, 0.0198364257812500, +0.0572814941406250, 0.0225524902343750, 0.0307922363281250, 0.0310668945312500, +0.0436706542968750, 0.0269470214843750, 0.0146484375000000, 0.0363159179687500, +0.0133666992187500, 0.0369873046875000, 0.0100097656250000, 0.0357360839843750, +-0.0061035156250000, 0.0411071777343750, -0.0007324218750000, 0.0407409667968750, +-0.0137023925781250, 0.0307922363281250, -0.0122375488281250, 0.0376281738281250, +-0.0196533203125000, 0.0289306640625000, -0.0309143066406250, 0.0155639648437500, +-0.0238342285156250, 0.0256958007812500, -0.0458679199218750, 0.0032043457031250, +-0.0448913574218750, 0.0043640136718750, -0.0473327636718750, 0.0017700195312500, +-0.0611877441406250, -0.0117797851562500, -0.0565490722656250, -0.0062561035156250, +-0.0615844726562500, -0.0164184570312500, -0.0638122558593750, -0.0155334472656250, +-0.0615539550781250, -0.0169982910156250, -0.0625915527343750, -0.0253601074218750, +-0.0629272460937500, -0.0213623046875000, -0.0530090332031250, -0.0173034667968750, +-0.0597534179687500, -0.0240783691406250, -0.0459899902343750, -0.0138549804687500, +-0.0297546386718750, 0.0003662109375000, -0.0422058105468750, -0.0091552734375000, +-0.0071105957031250, 0.0014648437500000, -0.0077514648437500, 0.0109863281250000, +-0.0077514648437500, -0.0077819824218750, 0.0122985839843750, -0.0172729492187500, +0.0071716308593750, -0.0042114257812500, 0.0019531250000000, -0.0539245605468750, +0.0070495605468750, -0.0503540039062500, 0.0034179687500000, -0.0581970214843750, +-0.0062561035156250, -0.0917053222656250, -0.0024719238281250, -0.0786132812500000, +0.0008850097656250, -0.0893859863281250, -0.0041503906250000, -0.1022338867187500, +0.0028381347656250, -0.0776062011718750, 0.0126953125000000, -0.0657653808593750, +0.0071411132812500, -0.0824584960937500, 0.0173950195312500, -0.0051574707031250, +0.0195617675781250, -0.0138854980468750, 0.0179443359375000, -0.0050354003906250, +0.0205383300781250, 0.0491333007812500, 0.0205688476562500, 0.0317077636718750, +0.0197143554687500, 0.0352478027343750, 0.0200805664062500, 0.0469970703125000, +0.0180969238281250, 0.0358581542968750, 0.0177307128906250, 0.0234985351562500, +0.0187683105468750, 0.0314025878906250, 0.0061950683593750, 0.0155944824218750, +0.0114746093750000, 0.0120544433593750, 0.0013122558593750, 0.0191650390625000, +-0.0148315429687500, 0.0149536132812500, -0.0052795410156250, 0.0122680664062500, +-0.0260314941406250, 0.0407409667968750, -0.0279846191406250, 0.0353698730468750, +-0.0274353027343750, 0.0354309082031250, -0.0355834960937500, 0.0591430664062500, +-0.0340576171875000, 0.0547485351562500, -0.0410461425781250, 0.0274047851562500, +-0.0356750488281250, 0.0419006347656250, -0.0489501953125000, 0.0205688476562500, +-0.0626525878906250, -0.0173950195312500, -0.0508728027343750, 0.0044250488281250, +-0.0864562988281250, -0.0230712890625000, -0.0883483886718750, -0.0368652343750000, +-0.0808715820312500, -0.0182495117187500, -0.0971984863281250, -0.0101013183593750, +-0.0978698730468750, -0.0213928222656250, -0.0640258789062500, -0.0007019042968750, +-0.0724792480468750, 0.0044250488281250, -0.0687866210937500, -0.0019531250000000, +-0.0296630859375000, -0.0000305175781250, -0.0190734863281250, -0.0288696289062500, +0.0272216796875000, 0.0052185058593750, 0.0047302246093750, -0.0003356933593750, +0.0194396972656250, -0.0050659179687500, 0.0544433593750000, 0.0060424804687500, +0.0421447753906250, 0.0092773437500000, 0.0374145507812500, -0.0198059082031250, +0.0491943359375000, -0.0173950195312500, 0.0384521484375000, -0.0142517089843750, +0.0203552246093750, -0.0299072265625000, 0.0300903320312500, -0.0295104980468750, +0.0217285156250000, -0.0177612304687500, 0.0150451660156250, -0.0164794921875000, +0.0252380371093750, -0.0253906250000000, 0.0325012207031250, -0.0240478515625000, +0.0253601074218750, -0.0177612304687500, 0.0362854003906250, -0.0459899902343750, +0.0423889160156250, -0.0470581054687500, 0.0326232910156250, -0.0409851074218750, +0.0286865234375000, -0.0540771484375000, 0.0356140136718750, -0.0556030273437500, +0.0157470703125000, -0.0286560058593750, 0.0151672363281250, -0.0356750488281250, +0.0220336914062500, -0.0292358398437500, 0.0136413574218750, -0.0057067871093750, +0.0111389160156250, -0.0146179199218750, 0.0364685058593750, -0.0093078613281250, +0.0333251953125000, -0.0061645507812500, 0.0276184082031250, -0.0065612792968750, +0.0475463867187500, -0.0077514648437500, 0.0466918945312500, -0.0089721679687500, +-0.0109252929687500, 0.0019226074218750, 0.0148925781250000, -0.0006408691406250, +-0.0190124511718750, 0.0011596679687500, -0.0866088867187500, 0.0106201171875000, +-0.0493774414062500, 0.0076599121093750, -0.1096801757812500, 0.0057678222656250, +-0.1200866699218750, 0.0077514648437500, -0.1069946289062500, 0.0070800781250000, +-0.1266479492187500, 0.0034790039062500, -0.1256713867187500, 0.0040588378906250, +-0.0898132324218750}, +{0.0063476562500000, -0.0281677246093750, 0.0167846679687500, -0.0606994628906250, +0.0180969238281250, -0.0568237304687500, 0.0174255371093750, -0.0658874511718750, +0.0213317871093750, -0.0929565429687500, 0.0205078125000000, -0.0801391601562500, +0.0213928222656250, -0.0871887207031250, 0.0216674804687500, -0.1051940917968750, +0.0203552246093750, -0.0736389160156250, 0.0210876464843750, -0.0482177734375000, +0.0214233398437500, -0.0734863281250000, 0.0127563476562500, -0.0063171386718750, +0.0172424316406250, -0.0047607421875000, 0.0086975097656250, -0.0042724609375000, +-0.0032653808593750, 0.0289001464843750, 0.0044860839843750, 0.0187377929687500, +-0.0162048339843750, 0.0252685546875000, -0.0160522460937500, 0.0315856933593750, +-0.0187683105468750, 0.0233154296875000, -0.0307006835937500, 0.0186462402343750, +-0.0264587402343750, 0.0246582031250000, -0.0374145507812500, 0.0097045898437500, +-0.0346069335937500, 0.0046997070312500, -0.0430297851562500, 0.0186462402343750, +-0.0540771484375000, 0.0220336914062500, -0.0457763671875000, 0.0117187500000000, +-0.0717468261718750, 0.0389099121093750, -0.0713500976562500, 0.0439147949218750, +-0.0704650878906250, 0.0363159179687500, -0.0869140625000000, 0.0451965332031250, +-0.0832824707031250, 0.0462951660156250, -0.0648803710937500, 0.0114440917968750, +-0.0757446289062500, 0.0252990722656250, -0.0609436035156250, 0.0086669921875000, +-0.0343627929687500, -0.0310058593750000, -0.0488586425781250, -0.0117492675781250, +-0.0275268554687500, -0.0295104980468750, -0.0236206054687500, -0.0393981933593750, +-0.0229492187500000, -0.0275878906250000, -0.0088195800781250, -0.0170288085937500, +0.0242309570312500, -0.0065612792968750, 0.0290222167968750, -0.0319213867187500, +0.0399780273437500, -0.0396728515625000, 0.0267333984375000, -0.0195312500000000, +0.0114440917968750, -0.0086364746093750, 0.0222778320312500, -0.0235290527343750, +0.0165100097656250, 0.0084228515625000, 0.0070190429687500, 0.0184936523437500, +0.0189208984375000, -0.0005493164062500, 0.0309448242187500, -0.0025634765625000, +0.0220031738281250, 0.0091247558593750, 0.0361938476562500, -0.0254516601562500, +0.0429992675781250, -0.0294799804687500, 0.0305480957031250, -0.0210876464843750, +0.0268859863281250, -0.0301208496093750, 0.0357360839843750, -0.0330200195312500, +0.0093383789062500, -0.0220031738281250, 0.0078735351562500, -0.0179748535156250, +0.0131835937500000, -0.0280761718750000, 0.0022888183593750, -0.0313415527343750, +0.0021972656250000, -0.0242309570312500, 0.0204772949218750, -0.0453796386718750, +0.0155334472656250, -0.0491333007812500, 0.0161743164062500, -0.0401916503906250, +0.0351257324218750, -0.0451965332031250, 0.0297546386718750, -0.0498657226562500, +-0.0042419433593750, -0.0222167968750000, 0.0216064453125000, -0.0257568359375000, +-0.0182800292968750, -0.0226440429687500, -0.0755920410156250, -0.0037536621093750, +-0.0362854003906250, -0.0098571777343750, -0.1159057617187500, -0.0073242187500000, +-0.1239929199218750, -0.0059509277343750, -0.1140441894531250, -0.0037536621093750, +-0.1460266113281250, -0.0029296875000000, -0.1408081054687500, -0.0056152343750000, +-0.1157836914062500, 0.0063171386718750, -0.1310119628906250, 0.0055236816406250, +-0.1084289550781250, 0.0052185058593750, -0.0736389160156250, 0.0126342773437500, +-0.0968627929687500, 0.0112304687500000, -0.0534362792968750, 0.0068359375000000, +-0.0479431152343750, 0.0084838867187500, -0.0548400878906250, 0.0079956054687500, +-0.0419616699218750, 0.0038146972656250, -0.0424804687500000, 0.0046997070312500, +-0.0398254394531250, 0.0079345703125000, -0.0440063476562500, 0.0073547363281250, +-0.0366516113281250, 0.0072937011718750, -0.0282897949218750, 0.0100402832031250, +-0.0350952148437500, 0.0098876953125000, -0.0167236328125000, 0.0050048828125000, +-0.0173339843750000, 0.0075378417968750, -0.0174560546875000, 0.0038146972656250, +-0.0072631835937500, -0.0015869140625000, -0.0099792480468750, 0.0016174316406250, +-0.0099182128906250, -0.0115661621093750, -0.0080871582031250, -0.0075683593750000, +-0.0097961425781250, -0.0156250000000000, -0.0118408203125000, -0.0294189453125000, +-0.0097656250000000, -0.0209350585937500, -0.0108642578125000, -0.0407714843750000, +-0.0140686035156250, -0.0406188964843750, -0.0075683593750000, -0.0420532226562500, +-0.0028686523437500, -0.0531616210937500, -0.0081787109375000, -0.0488891601562500, +0.0077209472656250, -0.0544128417968750, 0.0066223144531250, -0.0560607910156250, +0.0082397460937500, -0.0531311035156250, 0.0176696777343750, -0.0548095703125000, +0.0137939453125000, -0.0557861328125000, 0.0196838378906250, -0.0428161621093750, +0.0191040039062500, -0.0473632812500000, 0.0207824707031250, -0.0400695800781250, +0.0247802734375000, -0.0256652832031250, 0.0217285156250000, -0.0328369140625000, +0.0281372070312500, -0.0196838378906250, 0.0270996093750000, -0.0186767578125000, +0.0273437500000000, -0.0162963867187500, 0.0311584472656250, -0.0106811523437500, +0.0286254882812500, -0.0140380859375000, 0.0301513671875000, 0.0032653808593750, +0.0306091308593750, -0.0024414062500000, 0.0283813476562500, 0.0090026855468750, +0.0277404785156250, 0.0276489257812500, 0.0284423828125000, 0.0168457031250000, +0.0239868164062500, 0.0473632812500000, 0.0247497558593750, 0.0449523925781250, +0.0225830078125000, 0.0524291992187500, 0.0187988281250000, 0.0749511718750000, +0.0210266113281250, 0.0653991699218750, 0.0155639648437500, 0.0816345214843750, +0.0162048339843750, 0.0866088867187500, 0.0146484375000000, 0.0811462402343750, +0.0107421875000000, 0.0842895507812500, 0.0133056640625000, 0.0868835449218750, +0.0093688964843750, 0.0724487304687500, 0.0095214843750000, 0.0758361816406250, +0.0097351074218750, 0.0709838867187500, 0.0077819824218750, 0.0593566894531250, +0.0091857910156250, 0.0656127929687500, 0.0101013183593750, 0.0527343750000000, +0.0092773437500000, 0.0547180175781250, 0.0122070312500000, 0.0492858886718750, +0.0146484375000000, 0.0399780273437500, 0.0130310058593750, 0.0473327636718750, +0.0204772949218750, 0.0262756347656250, 0.0197143554687500, 0.0305786132812500, +0.0211791992187500, 0.0242004394531250, 0.0264892578125000, 0.0075073242187500, +0.0241699218750000, 0.0171813964843750, 0.0262145996093750, -0.0003356933593750, +0.0270996093750000, 0.0002441406250000, 0.0256042480468750, -0.0025939941406250, +0.0251159667968750, -0.0122070312500000, 0.0252380371093750, -0.0068969726562500, +0.0222473144531250, -0.0234985351562500, 0.0230102539062500, -0.0194396972656250, +0.0202941894531250, -0.0274047851562500, 0.0169372558593750, -0.0432739257812500, +0.0188598632812500, -0.0336608886718750, 0.0113525390625000, -0.0515747070312500, +0.0122375488281250, -0.0538635253906250, 0.0106811523437500, -0.0498657226562500, +0.0051574707031250, -0.0559082031250000, 0.0077514648437500, -0.0557861328125000, +0.0057983398437500, -0.0456542968750000, 0.0043334960937500, -0.0489196777343750, +0.0072326660156250, -0.0435791015625000, 0.0089416503906250, -0.0344543457031250, +0.0073852539062500, -0.0403137207031250, 0.0127868652343750, -0.0250244140625000, +0.0131225585937500, -0.0291137695312500, 0.0127563476562500, -0.0229187011718750, +0.0156860351562500, -0.0097045898437500, 0.0149841308593750, -0.0180358886718750, +0.0103149414062500, 0.0020446777343750, 0.0136108398437500, 0.0000915527343750, +0.0072326660156250, 0.0046386718750000, -0.0009765625000000, 0.0192565917968750, +0.0045471191406250, 0.0119934082031250, -0.0091552734375000, 0.0221557617187500, +-0.0104675292968750, 0.0255737304687500, -0.0090332031250000, 0.0212402343750000, +-0.0150146484375000, 0.0219726562500000, -0.0135192871093750, 0.0245666503906250, +-0.0059204101562500, 0.0182800292968750, -0.0097045898437500, 0.0181884765625000, +-0.0018005371093750, 0.0189819335937500, 0.0102539062500000, 0.0167236328125000, +0.0035095214843750, 0.0172119140625000, 0.0137329101562500, 0.0167236328125000, +0.0194702148437500, 0.0165405273437500, 0.0111694335937500, 0.0175781250000000, +0.0084228515625000, 0.0177917480468750, 0.0132446289062500, 0.0169372558593750, +-0.0071716308593750, 0.0190429687500000, -0.0018920898437500, 0.0198364257812500, +-0.0111999511718750, 0.0174255371093750, -0.0310974121093750, 0.0175170898437500, +-0.0193481445312500, 0.0188903808593750, -0.0339660644531250, 0.0092163085937500, +-0.0386962890625000, 0.0136413574218750, -0.0335083007812500, 0.0051574707031250, +-0.0340270996093750, -0.0071105957031250, -0.0347290039062500, 0.0009460449218750, +-0.0285034179687500, -0.0205383300781250, -0.0271911621093750, -0.0211181640625000, +-0.0307617187500000, -0.0206604003906250, -0.0300903320312500, -0.0315246582031250, +-0.0267028808593750, -0.0292968750000000, -0.0341186523437500, -0.0290222167968750, +-0.0340576171875000, -0.0314636230468750, -0.0348815917968750, -0.0296936035156250, +-0.0390014648437500, -0.0270080566406250, -0.0364074707031250, -0.0289001464843750, +-0.0367736816406250, -0.0264587402343750, -0.0395202636718750, -0.0262756347656250, +-0.0366821289062500, -0.0272216796875000, -0.0324707031250000, -0.0266418457031250, +-0.0334472656250000, -0.0269775390625000, -0.0295410156250000, -0.0296936035156250, +-0.0315551757812500, -0.0301208496093750, -0.0296630859375000, -0.0277099609375000, +-0.0247802734375000, -0.0276794433593750, -0.0278015136718750, -0.0292968750000000, +-0.0263061523437500, -0.0225830078125000, -0.0239562988281250, -0.0232543945312500, +-0.0252075195312500, -0.0218505859375000, -0.0288085937500000, -0.0162658691406250, +-0.0278320312500000, -0.0181274414062500, -0.0184020996093750, -0.0201721191406250, +-0.0226135253906250, -0.0183715820312500, -0.0210266113281250, -0.0185241699218750, +-0.0105285644531250, -0.0189819335937500, -0.0137939453125000, -0.0192871093750000, +-0.0201416015625000, -0.0315551757812500, -0.0160522460937500, -0.0257568359375000, +-0.0213317871093750, -0.0305786132812500, -0.0309753417968750, -0.0465698242187500, +-0.0264587402343750, -0.0406799316406250, -0.0328063964843750, -0.0370788574218750, +-0.0359191894531250, -0.0433044433593750, -0.0315551757812500, -0.0366516113281250, +-0.0317687988281250, -0.0256652832031250, -0.0348205566406250, -0.0313110351562500, +-0.0197143554687500, -0.0263061523437500, -0.0248413085937500, -0.0236206054687500, +-0.0162658691406250, -0.0244750976562500, -0.0007324218750000, -0.0238647460937500, +-0.0100097656250000, -0.0238037109375000, 0.0115661621093750, -0.0263061523437500, +0.0115356445312500, -0.0258178710937500, 0.0110473632812500, -0.0212097167968750, +0.0227355957031250, -0.0220336914062500, 0.0195922851562500, -0.0246887207031250, +0.0171508789062500, -0.0051879882812500, 0.0196838378906250, -0.0077209472656250, +0.0195617675781250, -0.0029907226562500, 0.0157470703125000, 0.0114440917968750, +0.0163574218750000, 0.0061035156250000, 0.0227050781250000, 0.0164489746093750, +0.0213317871093750, 0.0169372558593750, 0.0202636718750000, 0.0191955566406250, +0.0259399414062500, 0.0254821777343750, 0.0260925292968750, 0.0226135253906250, +0.0128784179687500, 0.0303344726562500, 0.0199279785156250, 0.0311889648437500, +0.0121765136718750, 0.0306701660156250, -0.0037841796875000, 0.0343017578125000, +0.0060729980468750, 0.0343322753906250, -0.0075683593750000, 0.0319519042968750, +-0.0088195800781250, 0.0326843261718750, -0.0079345703125000, 0.0314636230468750, +-0.0123291015625000, 0.0290832519531250, -0.0103454589843750, 0.0299682617187500, +-0.0189819335937500, 0.0267333984375000, -0.0148620605468750, 0.0262756347656250, +-0.0212402343750000}, +{0.0133361816406250, 0.0090637207031250, 0.0029602050781250, 0.0033264160156250, +-0.0039672851562500, -0.0058288574218750, 0.0043640136718750, -0.0001525878906250, +-0.0263671875000000, -0.0182800292968750, -0.0248718261718750, -0.0170288085937500, +-0.0242309570312500, -0.0187377929687500, -0.0415954589843750, -0.0312805175781250, +-0.0370788574218750, -0.0281066894531250, -0.0310974121093750, -0.0285339355468750, +-0.0363159179687500, -0.0309143066406250, -0.0293273925781250, -0.0298461914062500, +-0.0170898437500000, -0.0282592773437500, -0.0231628417968750, -0.0292358398437500, +-0.0208740234375000, -0.0265808105468750, -0.0141296386718750, -0.0276794433593750, +-0.0209350585937500, -0.0267944335937500, -0.0285339355468750, -0.0243835449218750, +-0.0226135253906250, -0.0258789062500000, -0.0334777832031250, -0.0228576660156250, +-0.0351562500000000, -0.0230712890625000, -0.0310058593750000, -0.0223999023437500, +-0.0312194824218750, -0.0209655761718750, -0.0306396484375000, -0.0214233398437500, +-0.0284729003906250, -0.0145568847656250, -0.0282592773437500, -0.0168151855468750, +-0.0277404785156250, -0.0178833007812500, -0.0271301269531250, -0.0126037597656250, +-0.0276184082031250, -0.0127258300781250, -0.0240478515625000, -0.0162963867187500, +-0.0233459472656250, -0.0150451660156250, -0.0259094238281250, -0.0169677734375000, +-0.0252380371093750, -0.0208129882812500, -0.0226440429687500, -0.0182800292968750, +-0.0298461914062500, -0.0187377929687500, -0.0312194824218750, -0.0187988281250000, +-0.0263061523437500, -0.0225830078125000, -0.0268249511718750, -0.0238952636718750, +-0.0300903320312500, -0.0192260742187500, -0.0178222656250000, -0.0292053222656250, +-0.0181579589843750, -0.0313415527343750, -0.0195617675781250, -0.0285034179687500, +-0.0130615234375000, -0.0291748046875000, -0.0140991210937500, -0.0297851562500000, +-0.0218505859375000, -0.0295410156250000, -0.0181274414062500, -0.0290222167968750, +-0.0240783691406250, -0.0280151367187500, -0.0346679687500000, -0.0289611816406250, +-0.0289611816406250, -0.0289916992187500, -0.0366821289062500, -0.0186157226562500, +-0.0414733886718750, -0.0219116210937500, -0.0340881347656250, -0.0189514160156250, +-0.0319213867187500, -0.0091857910156250, -0.0368652343750000, -0.0113525390625000, +-0.0158996582031250, -0.0031738281250000, -0.0206298828125000, -0.0053100585937500, +-0.0129699707031250, -0.0007629394531250, 0.0046691894531250, 0.0085754394531250, +-0.0053405761718750, 0.0044860839843750, 0.0142211914062500, 0.0118713378906250, +0.0152587890625000, 0.0119628906250000, 0.0135192871093750, 0.0158386230468750, +0.0224914550781250, 0.0217590332031250, 0.0207519531250000, 0.0179748535156250, +0.0186767578125000, 0.0279541015625000, 0.0192565917968750, 0.0289611816406250, +0.0210571289062500, 0.0271301269531250, 0.0204772949218750, 0.0315246582031250, +0.0192871093750000, 0.0314941406250000, 0.0256042480468750, 0.0226440429687500, +0.0264587402343750, 0.0250854492187500, 0.0224914550781250, 0.0218200683593750, +0.0245056152343750, 0.0131225585937500, 0.0270690917968750, 0.0162963867187500, +0.0110778808593750, 0.0128479003906250, 0.0163879394531250, 0.0108947753906250, +0.0108642578125000, 0.0124206542968750, -0.0037841796875000, 0.0130004882812500, +0.0043945312500000, 0.0122985839843750, -0.0069580078125000, 0.0136413574218750, +-0.0079345703125000, 0.0145874023437500, -0.0079345703125000, 0.0125122070312500, +-0.0122375488281250, 0.0119323730468750, -0.0099182128906250, 0.0130920410156250, +-0.0168457031250000, 0.0047302246093750, -0.0139770507812500, 0.0067443847656250, +-0.0179138183593750, 0.0023498535156250, -0.0253295898437500, -0.0061035156250000, +-0.0200805664062500, -0.0025634765625000, -0.0300292968750000, -0.0128479003906250, +-0.0306091308593750, -0.0133666992187500, -0.0290527343750000, -0.0153198242187500, +-0.0330200195312500, -0.0220031738281250, -0.0322875976562500, -0.0204772949218750, +-0.0293579101562500, -0.0246887207031250, -0.0302734375000000, -0.0263671875000000, +-0.0294494628906250, -0.0255737304687500, -0.0273742675781250, -0.0267639160156250, +-0.0281982421875000, -0.0278625488281250, -0.0252990722656250, -0.0247497558593750, +-0.0281066894531250, -0.0258178710937500, -0.0222167968750000, -0.0244750976562500, +-0.0173034667968750, -0.0212402343750000, -0.0226440429687500, -0.0226135253906250, +0.0003051757812500, -0.0193481445312500, -0.0055847167968750, -0.0193176269531250, +0.0046997070312500, -0.0177917480468750, 0.0260009765625000, -0.0155334472656250, +0.0140991210937500, -0.0166015625000000, 0.0385131835937500, -0.0111083984375000, +0.0397644042968750, -0.0108032226562500, 0.0385742187500000, -0.0097656250000000, +0.0502624511718750, -0.0060729980468750, 0.0464477539062500, -0.0067749023437500, +0.0417480468750000, -0.0054931640625000, 0.0460510253906250, -0.0042419433593750, +0.0389404296875000, -0.0050964355468750, 0.0300292968750000, -0.0052795410156250, +0.0354614257812500, -0.0041198730468750, 0.0201110839843750, -0.0073852539062500, +0.0209350585937500, -0.0056152343750000, 0.0174560546875000, -0.0068359375000000, +0.0080566406250000, -0.0101928710937500, 0.0125122070312500, -0.0078430175781250, +-0.0017700195312500, -0.0111999511718750, 0.0016784667968750, -0.0109558105468750, +-0.0071716308593750, -0.0107116699218750, -0.0212402343750000, -0.0126647949218750, +-0.0126037597656250, -0.0118103027343750, -0.0377807617187500, -0.0110473632812500, +-0.0352783203125000, -0.0135803222656250, -0.0400085449218750, -0.0092773437500000, +-0.0570373535156250, -0.0064086914062500, -0.0490722656250000, -0.0110168457031250, +-0.0628967285156250, 0.0048217773437500, -0.0644836425781250, 0.0005493164062500, +-0.0610046386718750, 0.0046691894531250, -0.0669860839843750, 0.0176086425781250, +-0.0661315917968750, 0.0102844238281250, -0.0495605468750000, 0.0206604003906250, +-0.0570068359375000, 0.0220947265625000, -0.0443115234375000, 0.0207824707031250, +-0.0229797363281250, 0.0246887207031250, -0.0349121093750000, 0.0235290527343750, +-0.0118103027343750, 0.0215148925781250, -0.0080566406250000, 0.0238342285156250, +-0.0115051269531250, 0.0188903808593750, -0.0046691894531250, 0.0146789550781250, +-0.0048522949218750, 0.0192565917968750, -0.0062561035156250, 0.0046997070312500, +-0.0078430175781250, 0.0064697265625000, -0.0034790039062500, 0.0041198730468750, +-0.0006713867187500, -0.0052795410156250, -0.0038146972656250, -0.0014648437500000, +0.0079956054687500, -0.0114440917968750, 0.0068664550781250, -0.0088195800781250, +0.0087585449218750, -0.0148010253906250, 0.0164489746093750, -0.0252380371093750, +0.0133666992187500, -0.0184326171875000, 0.0191040039062500, -0.0318603515625000, +0.0193481445312500, -0.0355834960937500, 0.0192871093750000, -0.0278015136718750, +0.0226745605468750, -0.0265808105468750, 0.0213012695312500, -0.0316162109375000, +0.0190429687500000, -0.0241394042968750, 0.0220031738281250, -0.0170288085937500, +0.0164184570312500, -0.0295715332031250, 0.0106506347656250, -0.0391845703125000, +0.0146789550781250, -0.0299682617187500, -0.0011596679687500, -0.0504455566406250, +0.0009460449218750, -0.0523681640625000, -0.0044250488281250, -0.0529479980468750, +-0.0164794921875000, -0.0612487792968750, -0.0106201171875000, -0.0572814941406250, +-0.0261535644531250, -0.0636901855468750, -0.0249938964843750, -0.0694885253906250, +-0.0293579101562500, -0.0556945800781250, -0.0405578613281250, -0.0482788085937500, +-0.0350646972656250, -0.0593261718750000, -0.0473327636718750, -0.0289916992187500, +-0.0480957031250000, -0.0273742675781250, -0.0481872558593750, -0.0281982421875000, +-0.0549621582031250, -0.0160217285156250, -0.0534667968750000, -0.0188598632812500, +-0.0512084960937500, -0.0098266601562500, -0.0550537109375000, -0.0138244628906250, +-0.0487365722656250, -0.0072326660156250, -0.0433654785156250, 0.0048217773437500, +-0.0486450195312500, -0.0010070800781250, -0.0257873535156250, 0.0131225585937500, +-0.0314636230468750, 0.0097961425781250, -0.0219726562500000, 0.0192565917968750, +-0.0009460449218750, 0.0370178222656250, -0.0118713378906250, 0.0269775390625000, +0.0098876953125000, 0.0333862304687500, 0.0106811523437500, 0.0396728515625000, +0.0127563476562500, 0.0366516113281250, 0.0253601074218750, 0.0330810546875000, +0.0198669433593750, 0.0340576171875000, 0.0226135253906250, 0.0323181152343750, +0.0274353027343750, 0.0332336425781250, 0.0213623046875000, 0.0317077636718750, +0.0106506347656250, 0.0271606445312500, 0.0171203613281250, 0.0327453613281250, +0.0308227539062500, 0.0265197753906250, 0.0311584472656250, 0.0259094238281250, +0.0268554687500000, 0.0229187011718750, 0.0276184082031250, 0.0256652832031250, +0.0314941406250000, 0.0280151367187500, 0.0225524902343750, -0.0024414062500000, +0.0208435058593750, 0.0063476562500000, 0.0243530273437500, -0.0008850097656250, +0.0237426757812500, -0.0312194824218750, 0.0213012695312500, -0.0203552246093750, +0.0232543945312500, -0.0112304687500000, 0.0277404785156250, -0.0225830078125000, +0.0174560546875000, -0.0121154785156250, 0.0116271972656250, 0.0093994140625000, +0.0193786621093750, 0.0000610351562500, -0.0138854980468750, 0.0017089843750000, +-0.0078125000000000, 0.0109558105468750, -0.0179138183593750, -0.0002441406250000, +-0.0421752929687500, -0.0138549804687500, -0.0294189453125000, -0.0050964355468750, +-0.0658569335937500, -0.0169372558593750, -0.0606079101562500, -0.0220947265625000, +-0.0700073242187500, -0.0165710449218750, -0.0979309082031250, -0.0143737792968750, +-0.0844116210937500, -0.0176086425781250, -0.1081542968750000, -0.0170593261718750, +-0.1105041503906250, -0.0120544433593750, -0.1076660156250000, -0.0202331542968750, +-0.1210632324218750, -0.0299377441406250, -0.1176147460937500, -0.0232238769531250, +-0.0896911621093750, -0.0305786132812500, -0.1078491210937500, -0.0375366210937500, +-0.0806884765625000, -0.0265197753906250, -0.0375366210937500, -0.0190734863281250, +-0.0645446777343750, -0.0272827148437500, -0.0160522460937500, -0.0066528320312500, +-0.0083312988281250, -0.0053405761718750, -0.0176391601562500, -0.0071105957031250, +-0.0029296875000000, 0.0008239746093750, -0.0030517578125000, -0.0007324218750000, +-0.0166625976562500, 0.0000305175781250, -0.0117492675781250, -0.0019226074218750, +-0.0185852050781250, 0.0027465820312500, -0.0327453613281250, 0.0074157714843750, +-0.0236206054687500, 0.0030822753906250, -0.0313415527343750, 0.0134582519531250, +-0.0377197265625000, 0.0151367187500000, -0.0278320312500000, 0.0119628906250000, +-0.0228271484375000, 0.0147705078125000, -0.0292968750000000, 0.0161437988281250, +-0.0064086914062500, 0.0085754394531250, -0.0116577148437500, 0.0096435546875000, +-0.0035400390625000, 0.0087585449218750, 0.0154418945312500, 0.0040893554687500, +0.0047302246093750, 0.0058288574218750, 0.0270996093750000, 0.0020141601562500, +0.0275573730468750, 0.0032958984375000, 0.0267944335937500, 0.0003967285156250, +0.0393981933593750, -0.0037536621093750, 0.0360107421875000, -0.0008544921875000, +0.0278625488281250, -0.0098266601562500, 0.0344238281250000, -0.0079345703125000, +0.0267333984375000, -0.0125122070312500, 0.0143737792968750, -0.0197448730468750, +0.0225830078125000, -0.0147705078125000, 0.0072021484375000, -0.0318298339843750, +0.0079345703125000, -0.0289916992187500, 0.0065612792968750, -0.0338134765625000, +-0.0025024414062500, -0.0477905273437500, 0.0021057128906250, -0.0413513183593750, +-0.0033264160156250, -0.0506896972656250, -0.0047607421875000, -0.0533447265625000, +-0.0027160644531250, -0.0501403808593750, -0.0042419433593750, -0.0527648925781250, +-0.0052185058593750}, +{0.0122375488281250, 0.0424194335937500, 0.0158081054687500, 0.0371704101562500, +0.0130004882812500, 0.0368347167968750, 0.0093078613281250, 0.0415649414062500, +0.0152587890625000, 0.0361022949218750, 0.0251770019531250, 0.0243225097656250, +0.0340270996093750, 0.0370788574218750, 0.0282287597656250, 0.0306091308593750, +0.0267944335937500, 0.0401611328125000, 0.0303955078125000, 0.0329895019531250, +0.0328979492187500, 0.0198974609375000, 0.0298156738281250, 0.0249023437500000, +0.0311889648437500, 0.0243835449218750, 0.0381164550781250, 0.0238952636718750, +0.0225830078125000, 0.0180358886718750, 0.0120849609375000, 0.0169982910156250, +0.0244140625000000, 0.0223999023437500, -0.0198974609375000, -0.0029602050781250, +-0.0158081054687500, -0.0003662109375000, -0.0208129882812500, -0.0008239746093750, +-0.0501403808593750, -0.0174865722656250, -0.0397644042968750, -0.0132141113281250, +-0.0466613769531250, -0.0053710937500000, -0.0474853515625000, -0.0101928710937500, +-0.0554809570312500, -0.0057678222656250, -0.0611267089843750, 0.0056152343750000, +-0.0529479980468750, 0.0012207031250000, -0.0838928222656250, -0.0010986328125000, +-0.0800476074218750, 0.0046997070312500, -0.0850524902343750, -0.0024108886718750, +-0.1085815429687500, -0.0129394531250000, -0.0982055664062500, -0.0068664550781250, +-0.0950622558593750, -0.0132446289062500, -0.1117248535156250, -0.0172424316406250, +-0.0809020996093750, -0.0132446289062500, -0.0530700683593750, -0.0099487304687500, +-0.0797729492187500, -0.0126647949218750, -0.0090942382812500, -0.0145568847656250, +-0.0053710937500000, -0.0107116699218750, -0.0146484375000000, -0.0154113769531250, +0.0158691406250000, -0.0239257812500000, 0.0128479003906250, -0.0197448730468750, +-0.0123901367187500, -0.0175781250000000, -0.0020141601562500, -0.0244750976562500, +-0.0117797851562500, -0.0149536132812500, -0.0379333496093750, -0.0031127929687500, +-0.0251464843750000, -0.0113220214843750, -0.0350341796875000, 0.0043029785156250, +-0.0451660156250000, 0.0069885253906250, -0.0272216796875000, 0.0036315917968750, +-0.0173950195312500, 0.0071105957031250, -0.0312194824218750, 0.0074768066406250, +0.0088195800781250, 0.0060729980468750, 0.0071105957031250, 0.0040588378906250, +0.0071716308593750, 0.0075988769531250, 0.0290527343750000, 0.0109558105468750, +0.0218505859375000, 0.0080261230468750, 0.0220336914062500, 0.0131225585937500, +0.0282897949218750, 0.0155029296875000, 0.0205688476562500, 0.0115051269531250, +0.0132751464843750, 0.0103454589843750, 0.0195922851562500, 0.0128479003906250, +0.0012512207031250, 0.0035400390625000, 0.0027465820312500, 0.0047607421875000, +0.0007324218750000, 0.0022277832031250, -0.0122375488281250, -0.0041503906250000, +-0.0072326660156250, -0.0008544921875000, -0.0047607421875000, -0.0101928710937500, +-0.0112915039062500, -0.0086669921875000, -0.0033569335937500, -0.0112915039062500, +0.0062255859375000, -0.0186462402343750, -0.0014343261718750, -0.0148010253906250, +0.0150146484375000, -0.0212097167968750, 0.0130004882812500, -0.0218200683593750, +0.0156555175781250, -0.0221557617187500, 0.0261230468750000, -0.0254211425781250, +0.0199584960937500, -0.0242919921875000, 0.0304565429687500, -0.0262145996093750, +0.0301208496093750, -0.0277099609375000, 0.0309753417968750, -0.0256347656250000, +0.0370788574218750, -0.0252685546875000, 0.0342407226562500, -0.0274047851562500, +0.0383300781250000, -0.0202026367187500, 0.0390930175781250, -0.0223083496093750, +0.0381164550781250, -0.0192871093750000, 0.0401916503906250, -0.0140380859375000, +0.0409240722656250, -0.0178833007812500, 0.0363769531250000, -0.0031738281250000, +0.0398559570312500, -0.0079040527343750, 0.0368347167968750, 0.0009155273437500, +0.0315856933593750, 0.0162658691406250, 0.0362548828125000, 0.0068359375000000, +0.0254211425781250, 0.0290527343750000, 0.0283508300781250, 0.0291442871093750, +0.0249023437500000, 0.0303344726562500, 0.0166320800781250, 0.0422058105468750, +0.0231933593750000, 0.0378417968750000, 0.0109558105468750, 0.0432434082031250, +0.0136413574218750, 0.0440063476562500, 0.0106811523437500, 0.0435485839843750, +0.0022277832031250, 0.0458068847656250, 0.0084533691406250, 0.0451354980468750, +-0.0044250488281250, 0.0457458496093750, -0.0016784667968750, 0.0462951660156250, +-0.0045776367187500, 0.0451660156250000, -0.0140075683593750, 0.0451354980468750, +-0.0079345703125000, 0.0455627441406250, -0.0173645019531250, 0.0396118164062500, +-0.0163574218750000, 0.0429382324218750, -0.0159912109375000, 0.0357055664062500, +-0.0205688476562500, 0.0275268554687500, -0.0168151855468750, 0.0334777832031250, +-0.0183715820312500, 0.0100708007812500, -0.0183410644531250, 0.0147094726562500, +-0.0163879394531250, 0.0060119628906250, -0.0156860351562500, -0.0144042968750000, +-0.0150451660156250, -0.0039672851562500, -0.0130310058593750, -0.0221862792968750, +-0.0131530761718750, -0.0258178710937500, -0.0116271972656250, -0.0211181640625000, +-0.0097961425781250, -0.0256958007812500, -0.0104370117187500, -0.0270996093750000, +-0.0056762695312500, -0.0198059082031250, -0.0065917968750000, -0.0199890136718750, +-0.0051574707031250, -0.0206604003906250, -0.0011291503906250, -0.0182189941406250, +-0.0030822753906250, -0.0186462402343750, -0.0010986328125000, -0.0159606933593750, +-0.0007629394531250, -0.0205688476562500, -0.0016784667968750, -0.0115966796875000, +-0.0018920898437500, -0.0029907226562500, -0.0023193359375000, -0.0117492675781250, +-0.0028381347656250, 0.0119323730468750, -0.0033569335937500, 0.0111694335937500, +-0.0030517578125000, 0.0114135742187500, -0.0028076171875000, 0.0252075195312500, +-0.0032958984375000, 0.0210876464843750, -0.0021667480468750, 0.0188293457031250, +-0.0021057128906250, 0.0234985351562500, -0.0017395019531250, 0.0185852050781250, +-0.0014038085937500, 0.0110778808593750, -0.0014953613281250, 0.0164184570312500, +0.0028076171875000, 0.0127563476562500, 0.0010070800781250, 0.0085449218750000, +0.0048217773437500, 0.0145263671875000, 0.0104980468750000, 0.0194396972656250, +0.0070495605468750, 0.0142211914062500, 0.0153503417968750, 0.0196533203125000, +0.0157470703125000, 0.0234680175781250, 0.0152282714843750, 0.0177307128906250, +0.0196228027343750, 0.0146179199218750, 0.0185852050781250, 0.0183410644531250, +0.0142211914062500, 0.0076599121093750, 0.0173034667968750, 0.0094604492187500, +0.0132751464843750, 0.0041198730468750, 0.0068664550781250, -0.0043334960937500, +0.0108337402343750, 0.0017700195312500, 0.0021972656250000, -0.0154113769531250, +0.0028686523437500, -0.0143432617187500, 0.0004272460937500, -0.0158081054687500, +-0.0063781738281250, -0.0266418457031250, -0.0030212402343750, -0.0230712890625000, +-0.0064392089843750, -0.0257873535156250, -0.0085449218750000, -0.0283813476562500, +-0.0067443847656250, -0.0262756347656250, -0.0066223144531250, -0.0247497558593750, +-0.0073242187500000, -0.0268554687500000, -0.0005187988281250, -0.0252685546875000, +-0.0021667480468750, -0.0238342285156250, -0.0032653808593750, -0.0251770019531250, +0.0031738281250000, -0.0279846191406250, 0.0030822753906250, -0.0271301269531250, +-0.0098571777343750, -0.0196228027343750, -0.0058593750000000, -0.0246582031250000, +-0.0122375488281250, -0.0200500488281250, -0.0252380371093750, -0.0093994140625000, +-0.0182800292968750, -0.0149536132812500, -0.0297241210937500, -0.0092773437500000, +-0.0356140136718750, -0.0074768066406250, -0.0256652832031250, -0.0086669921875000, +-0.0216369628906250, -0.0073852539062500, -0.0285339355468750, -0.0073852539062500, +-0.0103454589843750, -0.0088195800781250, -0.0079040527343750, -0.0080566406250000, +-0.0136108398437500, -0.0110168457031250, -0.0102539062500000, -0.0138244628906250, +-0.0107421875000000, -0.0125122070312500, -0.0233459472656250, -0.0214538574218750, +-0.0209960937500000, -0.0210266113281250, -0.0198059082031250, -0.0177307128906250, +-0.0264282226562500, -0.0202636718750000, -0.0241699218750000, -0.0211791992187500, +-0.0218200683593750, -0.0166320800781250, -0.0249023437500000, -0.0142211914062500, +-0.0209350585937500, -0.0189819335937500, -0.0143737792968750, -0.0202636718750000, +-0.0185241699218750, -0.0161437988281250, -0.0186462402343750, -0.0300903320312500, +-0.0138244628906250, -0.0300292968750000, -0.0190429687500000, -0.0301818847656250, +-0.0260009765625000, -0.0379638671875000, -0.0213317871093750, -0.0352172851562500, +-0.0266723632812500, -0.0315246582031250, -0.0285644531250000, -0.0392456054687500, +-0.0263977050781250, -0.0247802734375000, -0.0265808105468750, -0.0090942382812500, +-0.0269775390625000, -0.0209350585937500, -0.0232849121093750, 0.0075683593750000, +-0.0247802734375000, 0.0100097656250000, -0.0210266113281250, 0.0072631835937500, +-0.0166625976562500, 0.0188293457031250, -0.0204162597656250, 0.0178833007812500, +-0.0098571777343750, 0.0156555175781250, -0.0089416503906250, 0.0155639648437500, +-0.0127563476562500, 0.0172729492187500, -0.0088195800781250, 0.0182189941406250, +-0.0074462890625000, 0.0173034667968750, -0.0223388671875000, 0.0184631347656250, +-0.0197753906250000, 0.0177307128906250, -0.0212707519531250, 0.0202636718750000, +-0.0331115722656250, 0.0233764648437500, -0.0300598144531250, 0.0206604003906250, +-0.0249938964843750, 0.0213928222656250, -0.0310668945312500, 0.0239562988281250, +-0.0226135253906250, 0.0213317871093750, -0.0122070312500000, 0.0179138183593750, +-0.0202331542968750, 0.0200195312500000, 0.0005798339843750, 0.0178833007812500, +-0.0023803710937500, 0.0173339843750000, 0.0014953613281250, 0.0177917480468750, +0.0162658691406250, 0.0182495117187500, 0.0090026855468750, 0.0182189941406250, +0.0192565917968750, 0.0132751464843750, 0.0206604003906250, 0.0165405273437500, +0.0192565917968750, 0.0106201171875000, 0.0224304199218750, 0.0021667480468750, +0.0217590332031250, 0.0069580078125000, 0.0241394042968750, -0.0059204101562500, +0.0233459472656250, -0.0072021484375000, 0.0242614746093750, -0.0074462890625000, +0.0273437500000000, -0.0139465332031250, 0.0260620117187500, -0.0120849609375000, +0.0241699218750000, -0.0097045898437500, 0.0274353027343750, -0.0118103027343750, +0.0231323242187500, -0.0077819824218750, 0.0178833007812500, -0.0025024414062500, +0.0222167968750000, -0.0050964355468750, 0.0122375488281250, 0.0014038085937500, +0.0135498046875000, 0.0024719238281250, 0.0114135742187500, 0.0019226074218750, +0.0050659179687500, 0.0046691894531250, 0.0086975097656250, 0.0046386718750000, +-0.0009765625000000, 0.0021362304687500, 0.0005798339843750, 0.0035705566406250, +-0.0020141601562500, 0.0011291503906250, -0.0097351074218750, -0.0025329589843750, +-0.0054626464843750, -0.0008850097656250, -0.0100708007812500, -0.0075683593750000, +-0.0119934082031250, -0.0077514648437500, -0.0074768066406250, -0.0104370117187500, +-0.0059509277343750, -0.0162353515625000, -0.0068359375000000, -0.0149841308593750, +0.0047302246093750, -0.0189819335937500, 0.0037841796875000, -0.0216369628906250, +0.0079956054687500, -0.0204467773437500, 0.0174255371093750, -0.0210571289062500, +0.0137329101562500, -0.0232543945312500, 0.0198974609375000, -0.0177612304687500, +0.0216674804687500, -0.0204467773437500, 0.0194702148437500, -0.0185852050781250, +0.0202636718750000, -0.0137023925781250, 0.0213012695312500, -0.0174865722656250, +0.0181274414062500, -0.0099792480468750, 0.0176696777343750, -0.0122070312500000, +0.0184631347656250, -0.0103149414062500, 0.0178222656250000, -0.0046081542968750, +0.0177612304687500, -0.0088500976562500, 0.0189208984375000, -0.0015258789062500, +0.0190124511718750}, +{-0.0155639648437500, -0.0321044921875000, -0.0168762207031250, -0.0363464355468750, +-0.0197753906250000, -0.0279541015625000, -0.0131530761718750, -0.0234069824218750, +-0.0119323730468750, -0.0292663574218750, -0.0233764648437500, 0.0016784667968750, +-0.0223693847656250, -0.0017395019531250, -0.0216979980468750, 0.0006713867187500, +-0.0282592773437500, 0.0215454101562500, -0.0272827148437500, 0.0159912109375000, +-0.0224914550781250, 0.0164184570312500, -0.0244750976562500, 0.0208129882812500, +-0.0223083496093750, 0.0169677734375000, -0.0176391601562500, 0.0121765136718750, +-0.0196533203125000, 0.0152587890625000, -0.0139465332031250, 0.0100402832031250, +-0.0156860351562500, 0.0098876953125000, -0.0117797851562500, 0.0105285644531250, +-0.0051269531250000, 0.0066528320312500, -0.0097045898437500, 0.0072021484375000, +-0.0032653808593750, 0.0158691406250000, 0.0007324218750000, 0.0127258300781250, +-0.0068359375000000, 0.0145874023437500, -0.0101623535156250, 0.0229492187500000, +-0.0048828125000000, 0.0205993652343750, -0.0212402343750000, 0.0215759277343750, +-0.0215759277343750, 0.0238952636718750, -0.0194396972656250, 0.0196533203125000, +-0.0275573730468750, 0.0174865722656250, -0.0270996093750000, 0.0205688476562500, +-0.0177612304687500, 0.0061340332031250, -0.0230102539062500, 0.0090026855468750, +-0.0156555175781250, 0.0029296875000000, -0.0043029785156250, -0.0107727050781250, +-0.0120849609375000, -0.0040283203125000, 0.0079650878906250, -0.0134582519531250, +0.0057983398437500, -0.0175781250000000, 0.0085449218750000, -0.0122985839843750, +0.0218505859375000, -0.0115051269531250, 0.0158691406250000, -0.0140991210937500, +0.0232543945312500, -0.0030517578125000, 0.0243225097656250, -0.0033264160156250, +0.0237731933593750, -0.0018310546875000, 0.0265197753906250, 0.0055847167968750, +0.0255126953125000, 0.0031433105468750, 0.0271606445312500, 0.0012817382812500, +0.0278625488281250, 0.0046691894531250, 0.0261840820312500, -0.0017700195312500, +0.0262451171875000, -0.0085754394531250, 0.0273437500000000, -0.0044250488281250, +0.0208740234375000, -0.0189819335937500, 0.0229797363281250, -0.0184936523437500, +0.0209655761718750, -0.0226135253906250, 0.0150451660156250, -0.0330505371093750, +0.0185241699218750, -0.0292358398437500, 0.0160827636718750, -0.0391235351562500, +0.0143737792968750, -0.0398864746093750, 0.0179748535156250, -0.0404357910156250, +0.0202331542968750, -0.0455932617187500, 0.0191040039062500, -0.0438842773437500, +0.0265808105468750, -0.0443420410156250, 0.0270080566406250, -0.0453796386718750, +0.0281066894531250, -0.0421752929687500, 0.0331115722656250, -0.0395812988281250, +0.0324707031250000, -0.0404968261718750, 0.0316467285156250, -0.0330810546875000, +0.0343627929687500, -0.0332031250000000, 0.0316772460937500, -0.0296020507812500, +0.0279846191406250, -0.0235900878906250, 0.0307617187500000, -0.0256652832031250, +0.0242309570312500, -0.0171203613281250, 0.0246276855468750, -0.0176391601562500, +0.0229492187500000, -0.0144348144531250, 0.0186157226562500, -0.0077209472656250, +0.0209350585937500, -0.0108032226562500, 0.0150756835937500, -0.0036926269531250, +0.0156250000000000, -0.0032653808593750, 0.0130615234375000, -0.0030212402343750, +0.0083618164062500, 0.0003051757812500, 0.0110168457031250, -0.0006713867187500, +0.0038452148437500, 0.0015563964843750, 0.0035400390625000, 0.0009155273437500, +0.0033569335937500, 0.0019226074218750, -0.0008239746093750, 0.0037231445312500, +-0.0002441406250000, 0.0018310546875000, 0.0003662109375000, 0.0048522949218750, +-0.0015869140625000, 0.0041809082031250, 0.0004272460937500, 0.0046386718750000, +0.0028381347656250, 0.0066833496093750, 0.0007934570312500, 0.0051879882812500, +0.0070190429687500, 0.0075378417968750, 0.0046386718750000, 0.0083007812500000, +0.0103454589843750, 0.0062255859375000, 0.0173950195312500, 0.0067443847656250, +0.0126037597656250, 0.0079040527343750, 0.0323486328125000, -0.0010986328125000, +0.0303649902343750, 0.0026855468750000, 0.0343017578125000, -0.0025634765625000, +0.0499877929687500, -0.0121459960937500, 0.0451965332031250, -0.0056457519531250, +0.0463867187500000, -0.0179748535156250, 0.0516357421875000, -0.0184326171875000, +0.0465698242187500, -0.0168151855468750, 0.0408630371093750, -0.0230102539062500, +0.0453796386718750, -0.0219116210937500, 0.0374145507812500, -0.0158996582031250, +0.0372924804687500, -0.0210266113281250, 0.0359802246093750, -0.0137023925781250, +0.0322265625000000, -0.0036621093750000, 0.0351562500000000, -0.0110168457031250, +0.0274658203125000, 0.0064086914062500, 0.0291442871093750, 0.0043334960937500, +0.0267944335937500, 0.0072021484375000, 0.0204772949218750, 0.0192565917968750, +0.0236511230468750, 0.0136413574218750, 0.0169677734375000, 0.0213623046875000, +0.0176696777343750, 0.0232543945312500, 0.0148925781250000, 0.0211791992187500, +0.0099487304687500, 0.0238037109375000, 0.0132446289062500, 0.0240478515625000, +0.0038146972656250, 0.0155029296875000, 0.0049438476562500, 0.0199584960937500, +0.0023193359375000, 0.0122985839843750, -0.0041503906250000, 0.0005798339843750, +-0.0006408691406250, 0.0068969726562500, -0.0100097656250000, -0.0120849609375000, +-0.0084228515625000, -0.0126953125000000, -0.0125122070312500, -0.0122985839843750, +-0.0209045410156250, -0.0230407714843750, -0.0162658691406250, -0.0207824707031250, +-0.0256652832031250, -0.0122680664062500, -0.0267944335937500, -0.0150756835937500, +-0.0256958007812500, -0.0132751464843750, -0.0292968750000000, -0.0052490234375000, +-0.0290222167968750, -0.0068359375000000, -0.0271911621093750, -0.0068969726562500, +-0.0281982421875000, -0.0052795410156250, -0.0268249511718750, -0.0083007812500000, +-0.0253906250000000, -0.0083007812500000, -0.0267333984375000, -0.0064697265625000, +-0.0189819335937500, -0.0271606445312500, -0.0227661132812500, -0.0187683105468750, +-0.0150451660156250, -0.0290527343750000, -0.0052185058593750, -0.0533447265625000, +-0.0124206542968750, -0.0421752929687500, 0.0100402832031250, -0.0555114746093750, +0.0080566406250000, -0.0618896484375000, 0.0117187500000000, -0.0513305664062500, +0.0280761718750000, -0.0491638183593750, 0.0216674804687500, -0.0555114746093750, +0.0236816406250000, -0.0317382812500000, 0.0291748046875000, -0.0346984863281250, +0.0231018066406250, -0.0290527343750000, 0.0157775878906250, -0.0105895996093750, +0.0209655761718750, -0.0190429687500000, 0.0176696777343750, -0.0150146484375000, +0.0126953125000000, -0.0103454589843750, 0.0194702148437500, -0.0099792480468750, +0.0258178710937500, -0.0122985839843750, 0.0211181640625000, -0.0140686035156250, +0.0312194824218750, -0.0064392089843750, 0.0326538085937500, -0.0067749023437500, +0.0316162109375000, -0.0041809082031250, 0.0353393554687500, 0.0011596679687500, +0.0349121093750000, -0.0025024414062500, 0.0321655273437500, 0.0003967285156250, +0.0321044921875000, 0.0022583007812500, 0.0349426269531250, 0.0050354003906250, +0.0369873046875000, 0.0085449218750000, 0.0302429199218750, 0.0109252929687500, +-0.0203857421875000, 0.0046691894531250, -0.0021972656250000, 0.0013122558593750, +-0.0128479003906250, 0.0107116699218750, -0.0408020019531250, 0.0150146484375000, +-0.0309448242187500, 0.0082702636718750, -0.0335693359375000, 0.0322875976562500, +-0.0401611328125000, 0.0326232910156250, -0.0339050292968750, 0.0288085937500000, +-0.0252075195312500, 0.0399475097656250, -0.0298767089843750, 0.0397338867187500, +-0.0325927734375000, 0.0262756347656250, -0.0235290527343750, 0.0297546386718750, +-0.0382690429687500, 0.0262451171875000, -0.0552368164062500, 0.0144653320312500, +-0.0409851074218750, 0.0191040039062500, -0.0614318847656250, 0.0166625976562500, +-0.0698547363281250, 0.0149536132812500, -0.0590209960937500, 0.0142822265625000, +-0.0573120117187500, 0.0154418945312500, -0.0622863769531250, 0.0164184570312500, +-0.0412902832031250, 0.0039672851562500, -0.0453796386718750, 0.0072021484375000, +-0.0385742187500000, 0.0047302246093750, -0.0196533203125000, -0.0071716308593750, +-0.0285034179687500, -0.0034179687500000, -0.0220031738281250, 0.0012207031250000, +-0.0150451660156250, -0.0025634765625000, -0.0203247070312500, 0.0004272460937500, +-0.0279541015625000, 0.0086364746093750, -0.0235290527343750, 0.0058898925781250, +-0.0137329101562500, 0.0019226074218750, -0.0219726562500000, 0.0051879882812500, +-0.0136413574218750, 0.0025939941406250, 0.0016479492187500, -0.0041198730468750, +-0.0063171386718750, -0.0018310546875000, 0.0121765136718750, -0.0012207031250000, +0.0114440917968750, -0.0027465820312500, 0.0121765136718750, -0.0028991699218750, +0.0239868164062500, -0.0006713867187500, 0.0202026367187500, -0.0008544921875000, +0.0165405273437500, -0.0072021484375000, 0.0217895507812500, -0.0061340332031250, +0.0168457031250000, -0.0060729980468750, 0.0068054199218750, -0.0118103027343750, +0.0114746093750000, -0.0113830566406250, 0.0118103027343750, -0.0018615722656250, +0.0064697265625000, -0.0059204101562500, 0.0108337402343750, -0.0012817382812500, +0.0162963867187500, 0.0101318359375000, 0.0117187500000000, 0.0051574707031250, +0.0232849121093750, 0.0087890625000000, 0.0214843750000000, 0.0117492675781250, +0.0224304199218750, 0.0092163085937500, 0.0314941406250000, 0.0066833496093750, +0.0280456542968750, 0.0079956054687500, 0.0237731933593750, 0.0099792480468750, +0.0303955078125000, 0.0072326660156250, 0.0191345214843750, 0.0108642578125000, +0.0070495605468750, 0.0158386230468750, 0.0172424316406250, 0.0127258300781250, +-0.0081176757812500, 0.0200195312500000, -0.0084533691406250, 0.0191650390625000, +-0.0081481933593750, 0.0217590332031250, -0.0204162597656250, 0.0268859863281250, +-0.0166015625000000, 0.0232543945312500, -0.0189514160156250, 0.0322265625000000, +-0.0203857421875000, 0.0314331054687500, -0.0186157226562500, 0.0317077636718750, +-0.0187683105468750, 0.0371704101562500, -0.0196533203125000, 0.0350646972656250, +-0.0144653320312500, 0.0351562500000000, -0.0163574218750000, 0.0362243652343750, +-0.0132446289062500, 0.0343322753906250, -0.0081176757812500, 0.0329895019531250, +-0.0116882324218750, 0.0338134765625000, -0.0026855468750000, 0.0279846191406250, +-0.0036315917968750, 0.0297851562500000, -0.0017700195312500, 0.0255737304687500, +0.0046081542968750, 0.0191650390625000, 0.0017089843750000, 0.0229492187500000, +0.0073852539062500, 0.0122680664062500, 0.0079956054687500, 0.0134582519531250, +0.0088500976562500, 0.0101013183593750, 0.0119628906250000, 0.0020446777343750, +0.0111083984375000, 0.0063476562500000, 0.0142517089843750, -0.0026855468750000, +0.0152587890625000, -0.0035705566406250, 0.0146789550781250, -0.0017395019531250, +0.0163879394531250, -0.0053710937500000, 0.0178527832031250, -0.0049133300781250, +0.0142517089843750, 0.0021667480468750, 0.0166625976562500, 0.0009155273437500, +0.0145874023437500, 0.0031127929687500, 0.0105590820312500, 0.0095214843750000, +0.0141601562500000, 0.0077209472656250, 0.0082397460937500, 0.0089721679687500, +0.0094604492187500, 0.0106811523437500, 0.0084838867187500, 0.0101318359375000, +0.0049133300781250, 0.0086975097656250, 0.0080566406250000, 0.0098266601562500, +0.0014953613281250, 0.0134887695312500, 0.0038757324218750, 0.0103454589843750, +0.0015258789062500, 0.0171508789062500, -0.0043029785156250, 0.0245971679687500, +-0.0001831054687500, 0.0192260742187500, -0.0079345703125000, 0.0366516113281250, +-0.0072631835937500, 0.0355834960937500, -0.0085144042968750, 0.0371093750000000, +-0.0130310058593750}, +{-0.0055236816406250, 0.0062255859375000, 0.0169982910156250, -0.0058288574218750, +0.0054321289062500, -0.0032043457031250, 0.0108642578125000, 0.0017700195312500, +0.0184326171875000, -0.0004882812500000, 0.0136413574218750, -0.0001831054687500, +0.0069274902343750, 0.0048217773437500, 0.0097656250000000, 0.0040283203125000, +0.0104675292968750, -0.0012817382812500, 0.0071411132812500, 0.0001831054687500, +0.0122680664062500, -0.0004882812500000, 0.0166931152343750, -0.0050048828125000, +0.0123596191406250, -0.0041809082031250, 0.0274353027343750, -0.0026855468750000, +0.0243835449218750, -0.0028991699218750, 0.0273742675781250, -0.0047912597656250, +0.0403137207031250, -0.0045166015625000, 0.0343933105468750, -0.0031433105468750, +0.0326232910156250, -0.0104675292968750, 0.0379638671875000, -0.0112609863281250, +0.0331726074218750, -0.0082092285156250, 0.0262145996093750, -0.0114135742187500, +0.0298461914062500, -0.0130615234375000, 0.0202941894531250, 0.0020751953125000, +0.0226135253906250, -0.0022888183593750, 0.0170898437500000, 0.0032653808593750, +0.0079345703125000, 0.0172119140625000, 0.0140380859375000, 0.0107421875000000, +-0.0021667480468750, 0.0220947265625000, -0.0020751953125000, 0.0215759277343750, +-0.0016784667968750, 0.0249328613281250, -0.0104675292968750, 0.0319213867187500, +-0.0090637207031250, 0.0270996093750000, -0.0078430175781250, 0.0421142578125000, +-0.0079040527343750, 0.0404052734375000, -0.0105285644531250, 0.0428161621093750, +-0.0108642578125000, 0.0534057617187500, -0.0085144042968750, 0.0489196777343750, +-0.0169982910156250, 0.0533447265625000, -0.0154724121093750, 0.0546569824218750, +-0.0169677734375000, 0.0534973144531250, -0.0227661132812500, 0.0544433593750000, +-0.0195312500000000, 0.0541381835937500, -0.0239868164062500, 0.0523986816406250, +-0.0238037109375000, 0.0538940429687500, -0.0234375000000000, 0.0505676269531250, +-0.0255737304687500, 0.0475769042968750, -0.0242004394531250, 0.0502014160156250, +-0.0242614746093750, 0.0386962890625000, -0.0248107910156250, 0.0419311523437500, +-0.0229797363281250, 0.0350341796875000, -0.0218811035156250, 0.0242919921875000, +-0.0228271484375000, 0.0313415527343750, -0.0176086425781250, 0.0099487304687500, +-0.0192260742187500, 0.0129699707031250, -0.0167541503906250, 0.0071105957031250, +-0.0119934082031250, -0.0090942382812500, -0.0151672363281250, -0.0011291503906250, +-0.0087280273437500, -0.0169677734375000, -0.0097656250000000, -0.0167541503906250, +-0.0079650878906250, -0.0190734863281250, -0.0038146972656250, -0.0286254882812500, +-0.0071411132812500, -0.0239257812500000, 0.0013732910156250, -0.0313110351562500, +-0.0009460449218750, -0.0321350097656250, 0.0019836425781250, -0.0299072265625000, +0.0094604492187500, -0.0321655273437500, 0.0045166015625000, -0.0314941406250000, +0.0107421875000000, -0.0253295898437500, 0.0114135742187500, -0.0278320312500000, +0.0086364746093750, -0.0217590332031250, 0.0096130371093750, -0.0143127441406250, +0.0091857910156250, -0.0190429687500000, 0.0035400390625000, -0.0017089843750000, +0.0037231445312500, -0.0050048828125000, 0.0008850097656250, 0.0026855468750000, +-0.0040893554687500, 0.0178833007812500, -0.0031433105468750, 0.0097045898437500, +-0.0090637207031250, 0.0298767089843750, -0.0087585449218750, 0.0299072265625000, +-0.0112304687500000, 0.0325012207031250, -0.0159606933593750, 0.0439147949218750, +-0.0139770507812500, 0.0391540527343750, -0.0195922851562500, 0.0494079589843750, +-0.0195922851562500, 0.0472106933593750, -0.0202026367187500, 0.0516662597656250, +-0.0235290527343750, 0.0610961914062500, -0.0224304199218750, 0.0545654296875000, +-0.0246582031250000, 0.0637512207031250, -0.0244140625000000, 0.0673522949218750, +-0.0249633789062500, 0.0600585937500000, -0.0260620117187500, 0.0591735839843750, +-0.0247497558593750, 0.0632629394531250, -0.0280456542968750, 0.0447692871093750, +-0.0268249511718750, 0.0484008789062500, -0.0282287597656250, 0.0433349609375000, +-0.0313720703125000, 0.0286865234375000, -0.0290832519531250, 0.0361938476562500, +-0.0328674316406250, 0.0253601074218750, -0.0332336425781250, 0.0231628417968750, +-0.0326232910156250, 0.0250244140625000, -0.0345458984375000, 0.0223388671875000, +-0.0345764160156250, 0.0215759277343750, -0.0323486328125000, 0.0186157226562500, +-0.0337829589843750, 0.0220336914062500, -0.0321960449218750, 0.0150146484375000, +-0.0298156738281250, 0.0072326660156250, -0.0314331054687500, 0.0135192871093750, +-0.0240173339843750, -0.0009765625000000, -0.0262756347656250, -0.0010375976562500, +-0.0203552246093750, -0.0026245117187500, -0.0115966796875000, -0.0102539062500000, +-0.0166320800781250, -0.0066833496093750, -0.0021972656250000, -0.0145874023437500, +-0.0016174316406250, -0.0150756835937500, -0.0012512207031250, -0.0130310058593750, +0.0061340332031250, -0.0166015625000000, 0.0040893554687500, -0.0174865722656250, +0.0046386718750000, -0.0112915039062500, 0.0050048828125000, -0.0123596191406250, +0.0046386718750000, -0.0130310058593750, 0.0043640136718750, -0.0098876953125000, +0.0038757324218750, -0.0106506347656250, 0.0043029785156250, -0.0107727050781250, +0.0045471191406250, -0.0115966796875000, 0.0030517578125000, -0.0110168457031250, +0.0026855468750000, -0.0101928710937500, 0.0037231445312500, -0.0111999511718750, +-0.0007629394531250, -0.0087585449218750, 0.0005798339843750, -0.0100097656250000, +-0.0028991699218750, -0.0078430175781250, -0.0073242187500000, -0.0040588378906250, +-0.0033874511718750, -0.0066223144531250, -0.0133666992187500, -0.0043640136718750, +-0.0157775878906250, -0.0024414062500000, -0.0104675292968750, -0.0044555664062500, +-0.0109863281250000, -0.0060424804687500, -0.0137939453125000, -0.0049438476562500, +-0.0029907226562500, -0.0073242187500000, -0.0038757324218750, -0.0061645507812500, +-0.0033569335937500, -0.0105590820312500, 0.0048522949218750, -0.0149841308593750, +0.0025024414062500, -0.0101013183593750, -0.0072021484375000, -0.0166625976562500, +-0.0022583007812500, -0.0187377929687500, -0.0071105957031250, -0.0180969238281250, +-0.0185852050781250, -0.0186157226562500, -0.0136718750000000, -0.0169982910156250, +-0.0210876464843750, -0.0178222656250000, -0.0236511230468750, -0.0187072753906250, +-0.0194702148437500, -0.0191040039062500, -0.0183105468750000, -0.0182800292968750, +-0.0182189941406250, -0.0180358886718750, -0.0089721679687500, -0.0241394042968750, +-0.0111694335937500, -0.0230102539062500, -0.0122070312500000, -0.0215759277343750, +-0.0057678222656250, -0.0249328613281250, -0.0057678222656250, -0.0244140625000000, +-0.0104370117187500, -0.0187988281250000, -0.0103759765625000, -0.0213623046875000, +-0.0079650878906250, -0.0167236328125000, -0.0076293945312500, -0.0108947753906250, +-0.0094299316406250, -0.0151367187500000, -0.0120239257812500, 0.0015563964843750, +-0.0090332031250000, 0.0013732910156250, -0.0084533691406250, -0.0021057128906250, +-0.0136413574218750, 0.0055847167968750, -0.0137023925781250, 0.0069885253906250, +-0.0028076171875000, -0.0012817382812500, -0.0050659179687500, -0.0004272460937500, +-0.0049743652343750, -0.0031738281250000, 0.0034790039062500, -0.0090637207031250, +0.0021057128906250, -0.0051574707031250, -0.0042419433593750, -0.0093078613281250, +-0.0003662109375000, -0.0136718750000000, -0.0052795410156250, -0.0057678222656250, +-0.0142211914062500, -0.0008544921875000, -0.0088500976562500, -0.0070190429687500, +-0.0159301757812500, 0.0107421875000000, -0.0191040039062500, 0.0126953125000000, +-0.0141906738281250, 0.0061340332031250, -0.0130615234375000, 0.0114746093750000, +-0.0160217285156250, 0.0146789550781250, -0.0064086914062500, -0.0037536621093750, +-0.0072021484375000, -0.0010681152343750, -0.0057373046875000, -0.0051574707031250, +-0.0002136230468750, -0.0190734863281250, -0.0030822753906250, -0.0124511718750000, +0.0033874511718750, -0.0170898437500000, 0.0032653808593750, -0.0227355957031250, +0.0018615722656250, -0.0142517089843750, 0.0053710937500000, -0.0076293945312500, +0.0052490234375000, -0.0137634277343750, -0.0014343261718750, 0.0000000000000000, +0.0014038085937500, 0.0025024414062500, -0.0022277832031250, -0.0023193359375000, +-0.0099182128906250, 0.0015563964843750, -0.0060119628906250, 0.0032653808593750, +-0.0126342773437500, -0.0127258300781250, -0.0146484375000000, -0.0090332031250000, +-0.0107421875000000, -0.0157775878906250, -0.0119018554687500, -0.0309753417968750, +-0.0143737792968750, -0.0245971679687500, -0.0019226074218750, -0.0366821289062500, +-0.0067443847656250, -0.0390319824218750, -0.0007324218750000, -0.0370178222656250, +0.0112915039062500, -0.0406494140625000, 0.0032653808593750, -0.0404357910156250, +0.0201416015625000, -0.0361328125000000, 0.0185241699218750, -0.0366821289062500, +0.0227661132812500, -0.0360107421875000, 0.0341491699218750, -0.0328674316406250, +0.0281372070312500, -0.0336303710937500, 0.0444030761718750, -0.0341491699218750, +0.0429992675781250, -0.0333557128906250, 0.0461730957031250, -0.0337524414062500, +0.0580444335937500, -0.0349426269531250, 0.0534362792968750, -0.0346374511718750, +0.0592346191406250, -0.0345153808593750, 0.0617675781250000, -0.0352783203125000, +0.0596313476562500, -0.0339965820312500, 0.0596923828125000, -0.0329284667968750, +0.0605163574218750, -0.0338439941406250, 0.0576171875000000, -0.0297241210937500, +0.0590820312500000, -0.0307006835937500, 0.0553588867187500, -0.0276184082031250, +0.0520935058593750, -0.0231323242187500, 0.0547180175781250, -0.0254211425781250, +0.0386047363281250, -0.0169982910156250, 0.0431518554687500, -0.0169982910156250, +0.0338134765625000, -0.0147094726562500, 0.0173950195312500, -0.0087585449218750, +0.0261230468750000, -0.0106201171875000, 0.0025634765625000, -0.0061035156250000, +0.0040588378906250, -0.0049438476562500, -0.0019531250000000, -0.0040283203125000, +-0.0182800292968750, -0.0015869140625000, -0.0107727050781250, -0.0020446777343750, +-0.0279235839843750, -0.0003356933593750, -0.0285034179687500, 0.0009460449218750, +-0.0302429199218750, 0.0009765625000000, -0.0401611328125000, 0.0014038085937500, +-0.0366821289062500, 0.0022583007812500, -0.0410766601562500, 0.0010681152343750, +-0.0435791015625000, 0.0021667480468750, -0.0402832031250000, 0.0009460449218750, +-0.0404968261718750, -0.0005187988281250, -0.0421447753906250, 0.0009460449218750, +-0.0285034179687500, -0.0050964355468750, -0.0344848632812500, -0.0033264160156250, +-0.0240478515625000, -0.0060424804687500, -0.0079040527343750, -0.0117797851562500, +-0.0185546875000000, -0.0087585449218750, 0.0079040527343750, -0.0161743164062500, +0.0071411132812500, -0.0160522460937500, 0.0100708007812500, -0.0180664062500000, +0.0254211425781250, -0.0229187011718750, 0.0191955566406250, -0.0207824707031250, +0.0304260253906250, -0.0274047851562500, 0.0288391113281250, -0.0272827148437500, +0.0330810546875000, -0.0282897949218750, 0.0414123535156250, -0.0330200195312500, +0.0357666015625000, -0.0315856933593750, 0.0525817871093750, -0.0314636230468750, +0.0506896972656250, -0.0341796875000000, 0.0550231933593750, -0.0308227539062500, +0.0672607421875000, -0.0280151367187500, 0.0610351562500000, -0.0313110351562500, +0.0718994140625000, -0.0204162597656250, 0.0737915039062500, -0.0224609375000000, +0.0708923339843750, -0.0195007324218750, 0.0748291015625000, -0.0107421875000000, +0.0751037597656250, -0.0147094726562500, 0.0636291503906250, -0.0072326660156250, +0.0682983398437500, -0.0073547363281250, 0.0598449707031250, -0.0076599121093750, +0.0469360351562500, -0.0028381347656250, 0.0546875000000000, -0.0043029785156250, +0.0320739746093750}, +{0.0039367675781250, -0.0260314941406250, -0.0057678222656250, -0.0333862304687500, +-0.0038452148437500, -0.0355834960937500, -0.0064697265625000, -0.0344848632812500, +-0.0148315429687500, -0.0361938476562500, -0.0109863281250000, -0.0361022949218750, +-0.0132751464843750, -0.0350036621093750, -0.0175170898437500, -0.0354003906250000, +-0.0093078613281250, -0.0354003906250000, -0.0048828125000000, -0.0343017578125000, +-0.0110473632812500, -0.0345764160156250, 0.0147094726562500, -0.0361633300781250, +0.0089416503906250, -0.0357666015625000, 0.0175476074218750, -0.0355834960937500, +0.0392456054687500, -0.0369567871093750, 0.0279235839843750, -0.0365295410156250, +0.0479736328125000, -0.0328369140625000, 0.0488586425781250, -0.0341186523437500, +0.0495300292968750, -0.0303344726562500, 0.0594787597656250, -0.0252380371093750, +0.0552673339843750, -0.0273132324218750, 0.0606994628906250, -0.0183410644531250, +0.0624084472656250, -0.0188903808593750, 0.0584106445312500, -0.0154724121093750, +0.0589599609375000, -0.0084838867187500, 0.0603637695312500, -0.0115051269531250, +0.0469360351562500, -0.0030822753906250, 0.0506591796875000, -0.0028076171875000, +0.0433654785156250, -0.0027465820312500, 0.0299377441406250, 0.0016784667968750, +0.0362548828125000, 0.0004577636718750, 0.0166625976562500, 0.0002136230468750, +0.0181884765625000, 0.0011901855468750, 0.0113220214843750, -0.0006408691406250, +-0.0030212402343750, -0.0026550292968750, 0.0042114257812500, -0.0019531250000000, +-0.0162658691406250, -0.0053405761718750, -0.0144958496093750, -0.0056457519531250, +-0.0195617675781250, -0.0067749023437500, -0.0342102050781250, -0.0088500976562500, +-0.0276489257812500, -0.0081176757812500, -0.0416564941406250, -0.0117492675781250, +-0.0424499511718750, -0.0120849609375000, -0.0431823730468750, -0.0129089355468750, +-0.0511169433593750, -0.0149841308593750, -0.0483398437500000, -0.0144958496093750, +-0.0477294921875000, -0.0162658691406250, -0.0516662597656250, -0.0162963867187500, +-0.0447998046875000, -0.0162353515625000, -0.0389404296875000, -0.0170898437500000, +-0.0440673828125000, -0.0166931152343750, -0.0248413085937500, -0.0166931152343750, +-0.0270080566406250, -0.0171203613281250, -0.0234375000000000, -0.0171813964843750, +-0.0102539062500000, -0.0169067382812500, -0.0159912109375000, -0.0169067382812500, +-0.0073547363281250, -0.0172119140625000, -0.0075988769531250, -0.0177612304687500, +-0.0041503906250000, -0.0172119140625000, 0.0009765625000000, -0.0173950195312500, +-0.0034790039062500, -0.0184631347656250, 0.0132446289062500, -0.0148315429687500, +0.0087585449218750, -0.0164489746093750, 0.0155944824218750, -0.0159912109375000, +0.0303344726562500, -0.0127563476562500, 0.0218200683593750, -0.0151367187500000, +0.0415649414062500, -0.0160827636718750, 0.0406188964843750, -0.0142822265625000, +0.0425720214843750, -0.0176696777343750, 0.0545654296875000, -0.0208740234375000, +0.0492248535156250, -0.0179748535156250, 0.0537414550781250, -0.0254821777343750, +0.0562744140625000, -0.0254821777343750, 0.0529479980468750, -0.0255737304687500, +0.0517272949218750, -0.0297546386718750, 0.0529174804687500, -0.0285034179687500, +0.0463867187500000, -0.0282287597656250, 0.0474853515625000, -0.0294799804687500, +0.0439147949218750, -0.0260620117187500, 0.0388488769531250, -0.0244750976562500, +0.0422058105468750, -0.0269775390625000, 0.0291137695312500, -0.0138244628906250, +0.0319213867187500, -0.0165405273437500, 0.0264892578125000, -0.0131225585937500, +0.0146789550781250, -0.0018920898437500, 0.0203247070312500, -0.0068359375000000, +0.0068359375000000, -0.0036926269531250, 0.0077514648437500, -0.0001220703125000, +0.0040588378906250, -0.0043945312500000, -0.0053710937500000, -0.0092468261718750, +-0.0006103515625000, -0.0060729980468750, -0.0117492675781250, -0.0048522949218750, +-0.0128784179687500, -0.0114440917968750, -0.0108032226562500, -0.0007324218750000, +-0.0156860351562500, 0.0104675292968750, -0.0157775878906250, 0.0021667480468750, +-0.0066833496093750, 0.0266723632812500, -0.0102844238281250, 0.0262145996093750, +-0.0065002441406250, 0.0247802734375000, 0.0029602050781250, 0.0394592285156250, +-0.0013732910156250, 0.0368652343750000, 0.0047302246093750, 0.0229187011718750, +0.0056762695312500, 0.0307006835937500, 0.0063476562500000, 0.0197448730468750, +0.0086059570312500, 0.0012512207031250, 0.0071105957031250, 0.0113830566406250, +0.0133972167968750, -0.0115356445312500, 0.0124816894531250, -0.0107116699218750, +0.0132141113281250, -0.0136413574218750, 0.0179138183593750, -0.0299377441406250, +0.0166015625000000, -0.0236206054687500, 0.0169067382812500, -0.0193786621093750, +0.0171203613281250, -0.0257263183593750, 0.0185852050781250, -0.0211181640625000, +0.0195007324218750, -0.0093383789062500, 0.0183715820312500, -0.0138854980468750, +0.0221557617187500, -0.0210266113281250, 0.0221862792968750, -0.0122070312500000, +0.0223083496093750, -0.0228271484375000, 0.0244750976562500, -0.0405273437500000, +0.0234985351562500, -0.0315551757812500, 0.0223693847656250, -0.0441894531250000, +0.0260009765625000, -0.0465698242187500, 0.0168151855468750, -0.0445861816406250, +0.0104370117187500, -0.0521850585937500, 0.0177307128906250, -0.0514526367187500, +-0.0115966796875000, -0.0293884277343750, -0.0082702636718750, -0.0385742187500000, +-0.0138854980468750, -0.0269470214843750, -0.0355529785156250, -0.0020446777343750, +-0.0261840820312500, -0.0154724121093750, -0.0307312011718750, 0.0020751953125000, +-0.0383605957031250, 0.0080261230468750, -0.0300903320312500, 0.0022888183593750, +-0.0150451660156250, 0.0024414062500000, -0.0149230957031250, -0.0150146484375000, +-0.0234375000000000, 0.0062255859375000, -0.0227355957031250, 0.0035705566406250, +-0.0256958007812500, -0.0001831054687500, -0.0252380371093750, 0.0041198730468750, +-0.0226745605468750, 0.0075683593750000, -0.0467834472656250, -0.0010681152343750, +-0.0375061035156250, -0.0048828125000000, -0.0499267578125000, 0.0012512207031250, +-0.0777893066406250, 0.0046081542968750, -0.0625915527343750, 0.0006408691406250, +-0.0755310058593750, 0.0067138671875000, -0.0874023437500000, 0.0092468261718750, +-0.0688781738281250, 0.0055541992187500, -0.0600585937500000, 0.0044860839843750, +-0.0723876953125000, 0.0070495605468750, -0.0202026367187500, 0.0021972656250000, +-0.0282287597656250, -0.0007629394531250, -0.0182800292968750, 0.0060424804687500, +0.0204162597656250, 0.0101013183593750, 0.0043334960937500, 0.0050354003906250, +0.0228881835937500, 0.0154113769531250, 0.0290527343750000, 0.0186462402343750, +0.0229492187500000, 0.0139160156250000, 0.0252075195312500, 0.0135192871093750, +0.0271606445312500, 0.0163269042968750, 0.0195922851562500, 0.0112304687500000, +0.0187683105468750, 0.0093688964843750, 0.0234069824218750, 0.0116577148437500, +0.0216064453125000, 0.0130920410156250, 0.0182495117187500, 0.0115661621093750, +0.0319824218750000, 0.0084533691406250, 0.0310974121093750, 0.0130310058593750, +0.0335388183593750, 0.0053100585937500, 0.0415649414062500, -0.0043945312500000, +0.0369262695312500, 0.0025024414062500, 0.0447692871093750, -0.0109252929687500, +0.0478820800781250, -0.0133361816406250, 0.0411071777343750, -0.0100708007812500, +0.0397644042968750, -0.0133056640625000, 0.0442199707031250, -0.0139770507812500, +0.0288391113281250, -0.0088195800781250, 0.0289001464843750, -0.0089111328125000, +0.0307617187500000, -0.0092163085937500, 0.0249023437500000, -0.0073242187500000, +0.0245971679687500, -0.0075073242187500, 0.0205688476562500, -0.0052795410156250, +0.0263061523437500, -0.0081787109375000, 0.0168151855468750, -0.0025939941406250, +0.0057373046875000, 0.0031127929687500, 0.0152282714843750, -0.0022888183593750, +-0.0061035156250000, 0.0123291015625000, -0.0051269531250000, 0.0112915039062500, +-0.0068664550781250, 0.0131225585937500, -0.0191345214843750, 0.0213928222656250, +-0.0139160156250000, 0.0177612304687500, -0.0207519531250000, 0.0278015136718750, +-0.0224304199218750, 0.0246582031250000, -0.0191040039062500, 0.0311584472656250, +-0.0213317871093750, 0.0421142578125000, -0.0226745605468750, 0.0350036621093750, +-0.0091857910156250, 0.0507812500000000, -0.0139465332031250, 0.0515136718750000, +-0.0079345703125000, 0.0504760742187500, 0.0052795410156250, 0.0576477050781250, +-0.0026245117187500, 0.0558471679687500, 0.0092773437500000, 0.0549011230468750, +0.0099792480468750, 0.0564575195312500, 0.0089721679687500, 0.0544433593750000, +0.0145263671875000, 0.0529479980468750, 0.0127868652343750, 0.0545959472656250, +0.0109252929687500, 0.0459899902343750, 0.0135803222656250, 0.0496520996093750, +0.0094604492187500, 0.0433044433593750, 0.0055541992187500, 0.0333557128906250, +0.0097656250000000, 0.0400390625000000, -0.0018615722656250, 0.0229797363281250, +0.0013122558593750, 0.0245666503906250, -0.0027465820312500, 0.0203552246093750, +-0.0121154785156250, 0.0091857910156250, -0.0055236816406250, 0.0152282714843750, +-0.0192871093750000, -0.0009155273437500, -0.0177612304687500, 0.0018005371093750, +-0.0185241699218750, -0.0041503906250000, -0.0268554687500000, -0.0168762207031250, +-0.0228271484375000, -0.0095214843750000, -0.0267944335937500, -0.0284118652343750, +-0.0267639160156250, -0.0265197753906250, -0.0264587402343750, -0.0309143066406250, +-0.0279541015625000, -0.0446777343750000, -0.0267028808593750, -0.0385437011718750, +-0.0291748046875000, -0.0493469238281250, -0.0288696289062500, -0.0512390136718750, +-0.0279846191406250, -0.0497131347656250, -0.0291748046875000, -0.0538024902343750, +-0.0289306640625000, -0.0535583496093750, -0.0260314941406250, -0.0493469238281250, +-0.0271301269531250, -0.0514831542968750, -0.0245361328125000, -0.0475463867187500, +-0.0210266113281250, -0.0422973632812500, -0.0230407714843750, -0.0456542968750000, +-0.0162963867187500, -0.0348815917968750, -0.0168457031250000, -0.0373840332031250, +-0.0149230957031250, -0.0313415527343750, -0.0097351074218750, -0.0222167968750000, +-0.0111389160156250, -0.0283508300781250, -0.0053710937500000, -0.0058593750000000, +-0.0051879882812500, -0.0107116699218750, -0.0029907226562500, -0.0021057128906250, +0.0014953613281250, 0.0177612304687500, 0.0003967285156250, 0.0075988769531250, +0.0062561035156250, 0.0269470214843750, 0.0062561035156250, 0.0283203125000000, +0.0079345703125000, 0.0289916992187500, 0.0122070312500000, 0.0380249023437500, +0.0113830566406250, 0.0351867675781250, 0.0153808593750000, 0.0430908203125000, +0.0160827636718750, 0.0430297851562500, 0.0165405273437500, 0.0451049804687500, +0.0190429687500000, 0.0507507324218750, 0.0190124511718750, 0.0485534667968750, +0.0183715820312500, 0.0527648925781250, 0.0195007324218750, 0.0535278320312500, +0.0173339843750000, 0.0506591796875000, 0.0151672363281250, 0.0523071289062500, +0.0163574218750000, 0.0530395507812500, 0.0092468261718750, 0.0382080078125000, +0.0106506347656250, 0.0444335937500000, 0.0058898925781250, 0.0350036621093750, +-0.0008850097656250, 0.0177307128906250, 0.0027770996093750, 0.0275573730468750, +-0.0118103027343750, 0.0089416503906250, -0.0102844238281250, 0.0080871582031250, +-0.0138244628906250, 0.0059509277343750, -0.0250854492187500, -0.0036315917968750, +-0.0205383300781250, 0.0009155273437500, -0.0253906250000000, -0.0092468261718750, +-0.0275268554687500, -0.0101013183593750, -0.0256347656250000, -0.0087890625000000, +-0.0252990722656250, -0.0130004882812500, -0.0258178710937500, -0.0129394531250000, +-0.0245666503906250, -0.0111389160156250, -0.0240173339843750, -0.0116882324218750, +-0.0244140625000000}, +{0.0091552734375000, 0.0265808105468750, 0.0049438476562500, 0.0287780761718750, +0.0011901855468750, 0.0327453613281250, 0.0047607421875000, 0.0304870605468750, +-0.0040283203125000, 0.0318908691406250, -0.0025024414062500, 0.0345458984375000, +-0.0045166015625000, 0.0313720703125000, -0.0107421875000000, 0.0284118652343750, +-0.0070800781250000, 0.0310974121093750, -0.0137329101562500, 0.0257568359375000, +-0.0140380859375000, 0.0260925292968750, -0.0141906738281250, 0.0247802734375000, +-0.0178222656250000, 0.0223083496093750, -0.0169372558593750, 0.0243530273437500, +-0.0175170898437500, 0.0150451660156250, -0.0192565917968750, 0.0184326171875000, +-0.0173950195312500, 0.0123596191406250, -0.0167541503906250, 0.0023498535156250, +-0.0193176269531250, 0.0086669921875000, -0.0109252929687500, -0.0075073242187500, +-0.0138854980468750, -0.0063781738281250, -0.0111694335937500, -0.0091247558593750, +-0.0035400390625000, -0.0195312500000000, -0.0079345703125000, -0.0148315429687500, +-0.0009765625000000, -0.0233764648437500, -0.0013427734375000, -0.0236206054687500, +-0.0011291503906250, -0.0247192382812500, 0.0020141601562500, -0.0295104980468750, +-0.0004882812500000, -0.0276489257812500, 0.0034484863281250, -0.0329284667968750, +0.0021972656250000, -0.0326843261718750, 0.0029602050781250, -0.0336303710937500, +0.0059509277343750, -0.0371093750000000, 0.0036621093750000, -0.0357055664062500, +0.0070190429687500, -0.0383300781250000, 0.0066223144531250, -0.0383911132812500, +0.0063781738281250, -0.0385742187500000, 0.0079956054687500, -0.0407714843750000, +0.0068359375000000, -0.0403442382812500, 0.0078735351562500, -0.0382385253906250, +0.0071716308593750, -0.0417175292968750, 0.0070495605468750, -0.0359497070312500, +0.0078125000000000, -0.0300598144531250, 0.0065612792968750, -0.0354309082031250, +0.0063476562500000, -0.0191040039062500, 0.0071411132812500, -0.0208740234375000, +0.0050964355468750, -0.0175170898437500, 0.0033874511718750, -0.0063171386718750, +0.0043334960937500, -0.0107421875000000, -0.0008544921875000, 0.0004577636718750, +-0.0003051757812500, -0.0001831054687500, -0.0021362304687500, 0.0036621093750000, +-0.0064697265625000, 0.0119018554687500, -0.0048522949218750, 0.0082092285156250, +-0.0084838867187500, 0.0204467773437500, -0.0092773437500000, 0.0189514160156250, +-0.0084533691406250, 0.0224914550781250, -0.0097351074218750, 0.0320434570312500, +-0.0101928710937500, 0.0268554687500000, -0.0068969726562500, 0.0332031250000000, +-0.0079040527343750, 0.0362854003906250, -0.0058288574218750, 0.0311279296875000, +-0.0020141601562500, 0.0297851562500000, -0.0033569335937500, 0.0334777832031250, +0.0008544921875000, 0.0242004394531250, 0.0018920898437500, 0.0240478515625000, +0.0021362304687500, 0.0238952636718750, 0.0043945312500000, 0.0202636718750000, +0.0045776367187500, 0.0214538574218750, 0.0038452148437500, 0.0145568847656250, +0.0059814453125000, 0.0174865722656250, 0.0018005371093750, 0.0126647949218750, +-0.0014343261718750, 0.0039367675781250, 0.0019226074218750, 0.0089111328125000, +-0.0127563476562500, 0.0004272460937500, -0.0105590820312500, -0.0009460449218750, +-0.0153808593750000, -0.0010070800781250, -0.0278320312500000, -0.0043334960937500, +-0.0225219726562500, -0.0032958984375000, -0.0307922363281250, -0.0065002441406250, +-0.0335693359375000, -0.0070495605468750, -0.0310363769531250, -0.0071411132812500, +-0.0320739746093750, -0.0084838867187500, -0.0327453613281250, -0.0085754394531250, +-0.0278930664062500, -0.0100708007812500, -0.0289001464843750, -0.0097351074218750, +-0.0261535644531250, -0.0085144042968750, -0.0219421386718750, -0.0097656250000000, +-0.0247802734375000, -0.0103149414062500, -0.0173034667968750, -0.0030822753906250, +-0.0191345214843750, -0.0045776367187500, -0.0148620605468750, -0.0032958984375000, +-0.0083312988281250, 0.0028991699218750, -0.0131225585937500, 0.0010986328125000, +0.0012207031250000, 0.0007324218750000, -0.0010070800781250, 0.0034179687500000, +0.0032653808593750, -0.0002441406250000, 0.0153808593750000, -0.0041198730468750, +0.0090942382812500, -0.0005187988281250, 0.0139160156250000, -0.0072631835937500, +0.0187683105468750, -0.0076904296875000, 0.0130310058593750, -0.0066528320312500, +0.0090026855468750, -0.0089721679687500, 0.0122070312500000, -0.0082397460937500, +-0.0007324218750000, -0.0080261230468750, 0.0008239746093750, -0.0053405761718750, +0.0000000000000000, -0.0114440917968750, -0.0092468261718750, -0.0169372558593750, +-0.0070800781250000, -0.0103759765625000, -0.0054931640625000, -0.0187988281250000, +-0.0076904296875000, -0.0206298828125000, -0.0048522949218750, -0.0220947265625000, +-0.0003356933593750, -0.0256042480468750, -0.0031127929687500, -0.0221557617187500, +-0.0032653808593750, -0.0248107910156250, -0.0003967285156250, -0.0283203125000000, +-0.0021972656250000, -0.0232543945312500, -0.0043029785156250, -0.0174865722656250, +-0.0040588378906250, -0.0188293457031250, -0.0151367187500000, -0.0121459960937500, +-0.0094299316406250, -0.0125732421875000, -0.0119018554687500, -0.0130615234375000, +-0.0236511230468750, -0.0100097656250000, -0.0184631347656250, -0.0107727050781250, +-0.0206298828125000, -0.0091552734375000, -0.0266418457031250, -0.0092163085937500, +-0.0158691406250000, -0.0082397460937500, -0.0075073242187500, -0.0067443847656250, +-0.0171508789062500, -0.0081481933593750, 0.0040283203125000, -0.0075988769531250, +0.0059814453125000, -0.0047302246093750, 0.0026855468750000, -0.0084228515625000, +0.0113220214843750, -0.0141601562500000, 0.0102844238281250, -0.0114135742187500, +-0.0015869140625000, -0.0101318359375000, 0.0028686523437500, -0.0133056640625000, +-0.0006408691406250, -0.0104675292968750, -0.0139770507812500, -0.0067443847656250, +-0.0090637207031250, -0.0092163085937500, -0.0033264160156250, 0.0001220703125000, +-0.0100097656250000, -0.0016479492187500, -0.0043640136718750, 0.0000000000000000, +0.0080261230468750, 0.0083007812500000, 0.0025024414062500, 0.0042724609375000, +0.0038757324218750, -0.0007019042968750, 0.0079345703125000, 0.0057983398437500, +0.0047912597656250, -0.0035400390625000, 0.0007324218750000, -0.0173034667968750, +0.0027770996093750, -0.0099182128906250, -0.0016479492187500, -0.0226440429687500, +-0.0003356933593750, -0.0252380371093750, -0.0044860839843750, -0.0242309570312500, +-0.0094299316406250, -0.0287780761718750, -0.0051574707031250, -0.0281066894531250, +-0.0173645019531250, -0.0260314941406250, -0.0172119140625000, -0.0268859863281250, +-0.0163574218750000, -0.0277404785156250, -0.0232849121093750, -0.0265502929687500, +-0.0219726562500000, -0.0261840820312500, -0.0161132812500000, -0.0285644531250000, +-0.0202636718750000, -0.0290832519531250, -0.0143737792968750, -0.0270996093750000, +-0.0055847167968750, -0.0274658203125000, -0.0115051269531250, -0.0284118652343750, +0.0011596679687500, -0.0200195312500000, 0.0014648437500000, -0.0219116210937500, +0.0020446777343750, -0.0186462402343750, 0.0088195800781250, -0.0104980468750000, +0.0067749023437500, -0.0136413574218750, 0.0101318359375000, -0.0090942382812500, +0.0107727050781250, -0.0072937011718750, 0.0104370117187500, -0.0084838867187500, +0.0119018554687500, -0.0079956054687500, 0.0117797851562500, -0.0076293945312500, +0.0101623535156250, -0.0099487304687500, 0.0111389160156250, -0.0096435546875000, +0.0100097656250000, -0.0105895996093750, 0.0076293945312500, -0.0128479003906250, +0.0086975097656250, -0.0119628906250000, 0.0075683593750000, -0.0118408203125000, +0.0060729980468750, -0.0131530761718750, 0.0068359375000000, -0.0107116699218750, +0.0072021484375000, -0.0083618164062500, 0.0049133300781250, -0.0098571777343750, +0.0053710937500000, -0.0038757324218750, 0.0054016113281250, -0.0040893554687500, +0.0024108886718750, -0.0025024414062500, 0.0006103515625000, 0.0019836425781250, +0.0010986328125000, 0.0009765625000000, -0.0047302246093750, 0.0049743652343750, +-0.0045471191406250, 0.0058593750000000, -0.0075073242187500, 0.0068054199218750, +-0.0118408203125000, 0.0095520019531250, -0.0100708007812500, 0.0098266601562500, +-0.0195312500000000, 0.0108032226562500, -0.0181579589843750, 0.0121154785156250, +-0.0217285156250000, 0.0117492675781250, -0.0299377441406250, 0.0113525390625000, +-0.0258483886718750, 0.0119323730468750, -0.0312500000000000, 0.0096740722656250, +-0.0335083007812500, 0.0101318359375000, -0.0297241210937500, 0.0088806152343750, +-0.0289001464843750, 0.0066528320312500, -0.0307922363281250, 0.0075683593750000, +-0.0236816406250000, 0.0040588378906250, -0.0229797363281250, 0.0038146972656250, +-0.0231628417968750, 0.0033874511718750, -0.0195617675781250, 0.0013122558593750, +-0.0198059082031250, 0.0016174316406250, -0.0224914550781250, 0.0014038085937500, +-0.0207824707031250, 0.0008850097656250, -0.0224609375000000, 0.0013122558593750, +-0.0263061523437500, 0.0017395019531250, -0.0242004394531250, 0.0014038085937500, +-0.0255432128906250, 0.0030517578125000, -0.0273132324218750, 0.0026550292968750, +-0.0245056152343750, 0.0035095214843750, -0.0227050781250000, 0.0050659179687500, +-0.0244750976562500, 0.0040588378906250, -0.0169982910156250, 0.0057678222656250, +-0.0180053710937500, 0.0059204101562500, -0.0156555175781250, 0.0061035156250000, +-0.0097656250000000, 0.0073852539062500, -0.0126647949218750, 0.0072021484375000, +-0.0079040527343750, 0.0067443847656250, -0.0069885253906250, 0.0086669921875000, +-0.0087585449218750, 0.0056762695312500, -0.0084228515625000, 0.0036926269531250, +-0.0083312988281250, 0.0069885253906250, -0.0101013183593750, -0.0045166015625000, +-0.0118408203125000, -0.0014038085937500, -0.0098571777343750, -0.0046691894531250, +-0.0091247558593750, -0.0141906738281250, -0.0115051269531250, -0.0089111328125000, +-0.0047302246093750, -0.0176391601562500, -0.0055541992187500, -0.0186462402343750, +-0.0047302246093750, -0.0184936523437500, -0.0007019042968750, -0.0222473144531250, +-0.0028076171875000, -0.0209655761718750, 0.0007324218750000, -0.0225219726562500, +-0.0002441406250000, -0.0235290527343750, 0.0018615722656250, -0.0202636718750000, +0.0053100585937500, -0.0192871093750000, 0.0027160644531250, -0.0217895507812500, +0.0093994140625000, -0.0122070312500000, 0.0083007812500000, -0.0130004882812500, +0.0109558105468750, -0.0117797851562500, 0.0156250000000000, -0.0051879882812500, +0.0122985839843750, -0.0073242187500000, 0.0230407714843750, -0.0064392089843750, +0.0208435058593750, -0.0046081542968750, 0.0240478515625000, -0.0064697265625000, +0.0335998535156250, -0.0085144042968750, 0.0288391113281250, -0.0075683593750000, +0.0322570800781250, -0.0097351074218750, 0.0361022949218750, -0.0091552734375000, +0.0310058593750000, -0.0111999511718750, 0.0272827148437500, -0.0149230957031250, +0.0307312011718750, -0.0124511718750000, 0.0215759277343750, -0.0100708007812500, +0.0218811035156250, -0.0156860351562500, 0.0208435058593750, -0.0057373046875000, +0.0163574218750000, 0.0049743652343750, 0.0184631347656250, -0.0031433105468750, +0.0101623535156250, 0.0184326171875000, 0.0126647949218750, 0.0203552246093750, +0.0088195800781250, 0.0165710449218750, -0.0000610351562500, 0.0254516601562500, +0.0048828125000000, 0.0252685546875000, 0.0002136230468750, 0.0113525390625000, +-0.0029907226562500, 0.0156555175781250, 0.0004882812500000, 0.0119323730468750, +0.0032653808593750, -0.0011291503906250, 0.0006713867187500, 0.0028381347656250, +0.0005798339843750, -0.0013427734375000, 0.0044860839843750, -0.0013732910156250, +-0.0023193359375000, -0.0028076171875000, -0.0088500976562500, -0.0066528320312500, +-0.0035705566406250}, +{-0.0247192382812500, -0.0147705078125000, -0.0262451171875000, -0.0127563476562500, +-0.0227050781250000, -0.0169677734375000, -0.0225219726562500, -0.0168762207031250, +-0.0212402343750000, -0.0177917480468750, -0.0187988281250000, -0.0202941894531250, +-0.0199890136718750, -0.0187377929687500, -0.0169067382812500, -0.0222167968750000, +-0.0162658691406250, -0.0213623046875000, -0.0167541503906250, -0.0226135253906250, +-0.0155334472656250, -0.0254821777343750, -0.0154418945312500, -0.0236206054687500, +-0.0177307128906250, -0.0278320312500000, -0.0166931152343750, -0.0274047851562500, +-0.0172119140625000, -0.0277709960937500, -0.0195922851562500, -0.0305175781250000, +-0.0184326171875000, -0.0293273925781250, -0.0177001953125000, -0.0304565429687500, +-0.0185852050781250, -0.0307922363281250, -0.0170898437500000, -0.0299987792968750, +-0.0149841308593750, -0.0299682617187500, -0.0161437988281250, -0.0300292968750000, +-0.0145263671875000, -0.0279541015625000, -0.0133056640625000, -0.0283203125000000, +-0.0155334472656250, -0.0269775390625000, -0.0167236328125000, -0.0249023437500000, +-0.0152893066406250, -0.0255737304687500, -0.0207519531250000, -0.0216369628906250, +-0.0209045410156250, -0.0228576660156250, -0.0204162597656250, -0.0195007324218750, +-0.0233154296875000, -0.0154113769531250, -0.0234069824218750, -0.0186157226562500, +-0.0204467773437500, -0.0081481933593750, -0.0213623046875000, -0.0097961425781250, +-0.0214233398437500, -0.0075683593750000, -0.0194396972656250, -0.0001525878906250, +-0.0204467773437500, -0.0040283203125000, -0.0218200683593750, 0.0021057128906250, +-0.0221862792968750, 0.0032653808593750, -0.0214233398437500, 0.0018310546875000, +-0.0222473144531250, 0.0039062500000000, -0.0236511230468750, 0.0039062500000000, +-0.0187683105468750, -0.0006408691406250, -0.0209350585937500, 0.0023498535156250, +-0.0178222656250000, -0.0036010742187500, -0.0131225585937500, -0.0108642578125000, +-0.0165100097656250, -0.0050964355468750, -0.0039978027343750, -0.0192260742187500, +-0.0075683593750000, -0.0192565917968750, -0.0010070800781250, -0.0190124511718750, +0.0115356445312500, -0.0263977050781250, 0.0040283203125000, -0.0239562988281250, +0.0187377929687500, -0.0223693847656250, 0.0197753906250000, -0.0245056152343750, +0.0190734863281250, -0.0214233398437500, 0.0255432128906250, -0.0173645019531250, +0.0240783691406250, -0.0189819335937500, 0.0259399414062500, -0.0129699707031250, +0.0256042480468750, -0.0137023925781250, 0.0270385742187500, -0.0109252929687500, +0.0297241210937500, -0.0045471191406250, 0.0279846191406250, -0.0076293945312500, +0.0284423828125000, -0.0076293945312500, 0.0314331054687500, -0.0048522949218750, +0.0263671875000000, -0.0065917968750000, 0.0221557617187500, -0.0113830566406250, +0.0265502929687500, -0.0098266601562500, 0.0141906738281250, -0.0029296875000000, +0.0146179199218750, -0.0082092285156250, 0.0137939453125000, -0.0013427734375000, +0.0075378417968750, 0.0106201171875000, 0.0097961425781250, 0.0040588378906250, +0.0022583007812500, 0.0130004882812500, 0.0056762695312500, 0.0173645019531250, +-0.0020751953125000, 0.0099487304687500, -0.0125427246093750, 0.0072937011718750, +-0.0051574707031250, 0.0124816894531250, -0.0234069824218750, 0.0010375976562500, +-0.0242309570312500, -0.0007019042968750, -0.0234680175781250, -0.0007629394531250, +-0.0319519042968750, -0.0041809082031250, -0.0299072265625000, -0.0021057128906250, +-0.0299682617187500, -0.0066223144531250, -0.0307312011718750, -0.0070800781250000, +-0.0302124023437500, -0.0081176757812500, -0.0301513671875000, -0.0109558105468750, +-0.0299987792968750, -0.0093688964843750, -0.0259094238281250, -0.0090637207031250, +-0.0278015136718750, -0.0068664550781250, -0.0239562988281250, -0.0182800292968750, +-0.0181274414062500, -0.0244750976562500, -0.0212707519531250, -0.0144653320312500, +-0.0140991210937500, -0.0444946289062500, -0.0117797851562500, -0.0450439453125000, +-0.0166931152343750, -0.0444946289062500, -0.0157775878906250, -0.0604248046875000, +-0.0125732421875000, -0.0557250976562500, -0.0295410156250000, -0.0459594726562500, +-0.0253601074218750, -0.0530700683593750, -0.0323486328125000, -0.0466003417968750, +-0.0588378906250000, -0.0236511230468750, -0.0693664550781250, -0.0574645996093750, +-0.0451354980468750, -0.0393981933593750, -0.0618896484375000, -0.0517578125000000, +-0.0458984375000000, -0.0417480468750000, -0.0238037109375000, -0.0230102539062500, +-0.0364074707031250, -0.0296630859375000, -0.0070190429687500, -0.0247802734375000, +-0.0086364746093750, -0.0234069824218750, -0.0026550292968750, -0.0220336914062500, +0.0157165527343750, -0.0190124511718750, 0.0062866210937500, -0.0208740234375000, +0.0290527343750000, -0.0177001953125000, 0.0306701660156250, -0.0187683105468750, +0.0267639160156250, -0.0144042968750000, 0.0373535156250000, -0.0090026855468750, +0.0366821289062500, -0.0133666992187500, 0.0191650390625000, -0.0086975097656250, +0.0245056152343750, -0.0058288574218750, 0.0226745605468750, -0.0080261230468750, +0.0064697265625000, -0.0096130371093750, 0.0099182128906250, -0.0086975097656250, +0.0177001953125000, -0.0092468261718750, 0.0122375488281250, -0.0092468261718750, +0.0187683105468750, -0.0104675292968750, 0.0302429199218750, -0.0109863281250000, +0.0228576660156250, -0.0097351074218750, 0.0314331054687500, -0.0144958496093750, +0.0373840332031250, -0.0141601562500000, 0.0257568359375000, -0.0142211914062500, +0.0224304199218750, -0.0176696777343750, 0.0306091308593750, -0.0165710449218750, +-0.0076293945312500, -0.0120849609375000, -0.0034179687500000, -0.0155029296875000, +-0.0041198730468750, -0.0091857910156250, -0.0282897949218750, -0.0010681152343750, +-0.0225830078125000, -0.0064697265625000, -0.0201721191406250, 0.0073547363281250, +-0.0250854492187500, 0.0075988769531250, -0.0202026367187500, 0.0081481933593750, +-0.0136718750000000, 0.0153503417968750, -0.0184631347656250, 0.0129394531250000, +-0.0099792480468750, 0.0149841308593750, -0.0084533691406250, 0.0160217285156250, +-0.0127258300781250, 0.0143432617187500, -0.0100402832031250, 0.0143432617187500, +-0.0077514648437500, 0.0151672363281250, -0.0235900878906250, 0.0098876953125000, +-0.0203552246093750, 0.0112915039062500, -0.0211181640625000, 0.0093078613281250, +-0.0328979492187500, 0.0041809082031250, -0.0295104980468750, 0.0065612792968750, +-0.0255126953125000, 0.0039062500000000, -0.0299682617187500, 0.0032653808593750, +-0.0248413085937500, 0.0028686523437500, -0.0176391601562500, 0.0025634765625000, +-0.0224914550781250, 0.0033264160156250, -0.0103454589843750, -0.0033569335937500, +-0.0111999511718750, -0.0010070800781250, -0.0095214843750000, -0.0043640136718750, +-0.0011596679687500, -0.0115661621093750, -0.0049133300781250, -0.0078430175781250, +-0.0031127929687500, -0.0136718750000000, 0.0006103515625000, -0.0143127441406250, +-0.0048828125000000, -0.0146484375000000, -0.0090026855468750, -0.0171508789062500, +-0.0041503906250000, -0.0157470703125000, -0.0163574218750000, -0.0193481445312500, +-0.0144042968750000, -0.0192260742187500, -0.0165100097656250, -0.0185241699218750, +-0.0245971679687500, -0.0204162597656250, -0.0197753906250000, -0.0202941894531250, +-0.0271911621093750, -0.0172424316406250, -0.0274658203125000, -0.0177307128906250, +-0.0265197753906250, -0.0174255371093750, -0.0300598144531250, -0.0152587890625000, +-0.0291748046875000, -0.0155944824218750, -0.0269470214843750, -0.0154724121093750, +-0.0285034179687500, -0.0160827636718750, -0.0267639160156250, -0.0140686035156250, +-0.0243530273437500, -0.0126342773437500, -0.0266418457031250, -0.0142517089843750, +-0.0216979980468750, -0.0085449218750000, -0.0240783691406250, -0.0087280273437500, +-0.0222473144531250, -0.0083618164062500, -0.0179443359375000, -0.0049133300781250, +-0.0219726562500000, -0.0057373046875000, -0.0146789550781250, -0.0057678222656250, +-0.0165100097656250, -0.0046997070312500, -0.0152282714843750, -0.0058898925781250, +-0.0105285644531250, -0.0068054199218750, -0.0147399902343750, -0.0059509277343750, +-0.0086669921875000, -0.0109252929687500, -0.0104980468750000, -0.0096435546875000, +-0.0092468261718750, -0.0120544433593750, -0.0048522949218750, -0.0171813964843750, +-0.0087585449218750, -0.0147399902343750, -0.0025939941406250, -0.0190429687500000, +-0.0036621093750000, -0.0196838378906250, -0.0035095214843750, -0.0198669433593750, +0.0000610351562500, -0.0212097167968750, -0.0023803710937500, -0.0208129882812500, +-0.0002746582031250, -0.0252075195312500, -0.0010986328125000, -0.0232238769531250, +-0.0015869140625000, -0.0265502929687500, -0.0006713867187500, -0.0323181152343750, +-0.0025939941406250, -0.0285949707031250, -0.0024108886718750, -0.0333557128906250, +-0.0024719238281250, -0.0346679687500000, -0.0038757324218750, -0.0325317382812500, +-0.0048828125000000, -0.0326538085937500, -0.0050354003906250, -0.0332336425781250, +-0.0065002441406250, -0.0310363769531250, -0.0068664550781250, -0.0309143066406250, +-0.0071716308593750, -0.0316772460937500, -0.0078735351562500, -0.0311279296875000, +-0.0081176757812500, -0.0308532714843750, -0.0088500976562500, -0.0325927734375000, +-0.0087585449218750, -0.0328674316406250, -0.0089416503906250, -0.0308532714843750, +-0.0094299316406250, -0.0314025878906250, -0.0089111328125000, -0.0324707031250000, +-0.0088500976562500, -0.0222167968750000, -0.0083923339843750, -0.0254516601562500, +-0.0080871582031250, -0.0215759277343750, -0.0077209472656250, -0.0113220214843750, +-0.0068054199218750, -0.0156555175781250, -0.0066223144531250, -0.0095520019531250, +-0.0064697265625000, -0.0086669921875000, -0.0062255859375000, -0.0065917968750000, +-0.0058898925781250, -0.0035095214843750, -0.0057983398437500, -0.0058288574218750, +-0.0073852539062500, 0.0033264160156250, -0.0067749023437500, 0.0024108886718750, +-0.0078125000000000, 0.0030212402343750, -0.0101318359375000, 0.0086669921875000, +-0.0094909667968750, 0.0064697265625000, -0.0101318359375000, 0.0082092285156250, +-0.0109558105468750, 0.0083618164062500, -0.0099792480468750, 0.0083618164062500, +-0.0095520019531250, 0.0095825195312500, -0.0099487304687500, 0.0092163085937500, +-0.0053100585937500, 0.0085754394531250, -0.0054321289062500, 0.0096435546875000, +-0.0058288574218750, 0.0085449218750000, -0.0025329589843750, 0.0070495605468750, +-0.0024414062500000, 0.0079956054687500, -0.0076599121093750, 0.0041198730468750, +-0.0054321289062500, 0.0054626464843750, -0.0087585449218750, 0.0032653808593750, +-0.0143737792968750, -0.0009460449218750, -0.0110168457031250, 0.0015869140625000, +-0.0204162597656250, -0.0028076171875000, -0.0198669433593750, -0.0023803710937500, +-0.0207824707031250, -0.0051269531250000, -0.0270690917968750, -0.0082702636718750, +-0.0242614746093750, -0.0049743652343750, -0.0223999023437500, -0.0148925781250000, +-0.0262756347656250, -0.0133972167968750, -0.0193481445312500, -0.0156555175781250, +-0.0108947753906250, -0.0229797363281250, -0.0161132812500000, -0.0184326171875000, +-0.0070190429687500, -0.0219116210937500, -0.0054016113281250, -0.0243835449218750, +-0.0045166015625000, -0.0227050781250000, -0.0007019042968750, -0.0209350585937500, +-0.0027160644531250, -0.0209350585937500, 0.0000610351562500, -0.0214233398437500, +0.0008239746093750, -0.0223388671875000, 0.0004577636718750, -0.0209960937500000, +0.0016784667968750, -0.0195617675781250, 0.0018005371093750, -0.0202331542968750, +-0.0009765625000000, -0.0174865722656250, 0.0002136230468750, -0.0198364257812500, +-0.0014038085937500, -0.0162048339843750, -0.0047302246093750, -0.0106506347656250, +-0.0031738281250000, -0.0143432617187500, -0.0063781738281250, -0.0089721679687500, +-0.0081176757812500}, +{-0.0051879882812500, -0.0100708007812500, -0.0047607421875000, -0.0091552734375000, +-0.0037536621093750, -0.0118103027343750, -0.0042419433593750, -0.0138854980468750, +-0.0035095214843750, -0.0113830566406250, -0.0016479492187500, -0.0195007324218750, +-0.0015869140625000, -0.0180053710937500, 0.0003967285156250, -0.0200500488281250, +0.0024719238281250, -0.0259094238281250, 0.0021667480468750, -0.0229492187500000, +0.0073242187500000, -0.0300903320312500, 0.0062255859375000, -0.0291442871093750, +0.0088195800781250, -0.0321044921875000, 0.0137939453125000, -0.0380249023437500, +0.0111694335937500, -0.0348510742187500, 0.0160522460937500, -0.0428466796875000, +0.0166931152343750, -0.0424194335937500, 0.0155029296875000, -0.0436401367187500, +0.0172729492187500, -0.0489807128906250, 0.0170898437500000, -0.0464477539062500, +0.0130004882812500, -0.0473327636718750, 0.0150146484375000, -0.0498352050781250, +0.0108337402343750, -0.0463256835937500, 0.0054626464843750, -0.0430908203125000, +0.0087890625000000, -0.0458679199218750, -0.0035400390625000, -0.0401916503906250, +-0.0023193359375000, -0.0398559570312500, -0.0056762695312500, -0.0386352539062500, +-0.0152893066406250, -0.0363769531250000, -0.0115356445312500, -0.0375366210937500, +-0.0181884765625000, -0.0274047851562500, -0.0200500488281250, -0.0310974121093750, +-0.0184020996093750, -0.0256958007812500, -0.0204162597656250, -0.0150756835937500, +-0.0209655761718750, -0.0211791992187500, -0.0146179199218750, -0.0086059570312500, +-0.0170593261718750, -0.0093078613281250, -0.0129394531250000, -0.0063171386718750, +-0.0057373046875000, 0.0017700195312500, -0.0097656250000000, -0.0028076171875000, +0.0002136230468750, 0.0079040527343750, 0.0003051757812500, 0.0080261230468750, +0.0001831054687500, 0.0086059570312500, 0.0057678222656250, 0.0150146484375000, +0.0042114257812500, 0.0132446289062500, 0.0019836425781250, 0.0138549804687500, +0.0034179687500000, 0.0157470703125000, 0.0019531250000000, 0.0135498046875000, +-0.0006713867187500, 0.0115966796875000, 0.0004272460937500, 0.0134582519531250, +-0.0038757324218750, 0.0088806152343750, -0.0027465820312500, 0.0089721679687500, +-0.0043029785156250, 0.0078125000000000, -0.0081787109375000, 0.0057373046875000, +-0.0061340332031250, 0.0065917968750000, -0.0100097656250000, -0.0036315917968750, +-0.0090332031250000, 0.0012207031250000, -0.0107421875000000, -0.0057678222656250, +-0.0137023925781250, -0.0184936523437500, -0.0114440917968750, -0.0109863281250000, +-0.0186767578125000, -0.0255432128906250, -0.0176391601562500, -0.0260925292968750, +-0.0170288085937500, -0.0242919921875000, -0.0226745605468750, -0.0313415527343750, +-0.0216674804687500, -0.0306396484375000, -0.0132446289062500, -0.0249023437500000, +-0.0155029296875000, -0.0255432128906250, -0.0128479003906250, -0.0265197753906250, +-0.0054931640625000, -0.0249633789062500, -0.0078735351562500, -0.0248107910156250, +-0.0023803710937500, -0.0214233398437500, -0.0015869140625000, -0.0230712890625000, +-0.0025939941406250, -0.0217590332031250, -0.0005798339843750, -0.0188903808593750, +-0.0001220703125000, -0.0205383300781250, -0.0018005371093750, -0.0135803222656250, +-0.0014343261718750, -0.0151672363281250, -0.0005493164062500, -0.0129394531250000, +-0.0012512207031250, -0.0072021484375000, -0.0017089843750000, -0.0101928710937500, +0.0006408691406250, -0.0042724609375000, 0.0010375976562500, -0.0046386718750000, +0.0003662109375000, -0.0027770996093750, 0.0002746582031250, 0.0036010742187500, +-0.0007629394531250, 0.0022583007812500, -0.0034790039062500, -0.0012817382812500, +-0.0029602050781250, 0.0025329589843750, -0.0009155273437500, -0.0000610351562500, +-0.0017700195312500, -0.0067443847656250, -0.0041809082031250, -0.0036621093750000, +-0.0011291503906250, -0.0057983398437500, 0.0032653808593750, -0.0095214843750000, +-0.0064086914062500, -0.0036010742187500, -0.0131225585937500, 0.0015563964843750, +-0.0050964355468750, -0.0034484863281250, -0.0252990722656250, 0.0046081542968750, +-0.0263366699218750, 0.0065002441406250, -0.0237426757812500, 0.0048828125000000, +-0.0325927734375000, 0.0070800781250000, -0.0319519042968750, 0.0062561035156250, +-0.0247802734375000, 0.0001831054687500, -0.0272827148437500, 0.0031433105468750, +-0.0235595703125000, -0.0010681152343750, -0.0161743164062500, -0.0090026855468750, +-0.0205688476562500, -0.0053405761718750, -0.0151062011718750, -0.0136413574218750, +-0.0124511718750000, -0.0141906738281250, -0.0161743164062500, -0.0138549804687500, +-0.0172424316406250, -0.0177917480468750, -0.0148620605468750, -0.0170288085937500, +-0.0212707519531250, -0.0166625976562500, -0.0217285156250000, -0.0182189941406250, +-0.0202026367187500, -0.0151062011718750, -0.0226745605468750, -0.0119018554687500, +-0.0231018066406250, -0.0149230957031250, -0.0183715820312500, -0.0113525390625000, +-0.0205688476562500, -0.0092468261718750, -0.0158996582031250, -0.0111999511718750, +-0.0098266601562500, -0.0121154785156250, -0.0140380859375000, -0.0115661621093750, +-0.0017700195312500, -0.0153808593750000, -0.0022583007812500, -0.0144348144531250, +-0.0015258789062500, -0.0155944824218750, 0.0061950683593750, -0.0200500488281250, +0.0038146972656250, -0.0185852050781250, 0.0030822753906250, -0.0153198242187500, +0.0058593750000000, -0.0189208984375000, 0.0028686523437500, -0.0130004882812500, +-0.0004882812500000, -0.0057067871093750, 0.0024108886718750, -0.0111083984375000, +-0.0048217773437500, 0.0015563964843750, -0.0037231445312500, 0.0022277832031250, +-0.0059204101562500, 0.0015563964843750, -0.0115661621093750, 0.0072937011718750, +-0.0085754394531250, 0.0057983398437500, -0.0147705078125000, 0.0038757324218750, +-0.0153503417968750, 0.0044860839843750, -0.0160827636718750, 0.0028991699218750, +-0.0195312500000000, 0.0000915527343750, -0.0191955566406250, 0.0008544921875000, +-0.0226135253906250, 0.0009765625000000, -0.0221252441406250, -0.0009460449218750, +-0.0254516601562500, 0.0019836425781250, -0.0290222167968750, 0.0046386718750000, +-0.0268554687500000, 0.0022888183593750, -0.0368652343750000, 0.0102844238281250, +-0.0352478027343750, 0.0094909667968750, -0.0387573242187500, 0.0112304687500000, +-0.0469970703125000, 0.0171203613281250, -0.0430297851562500, 0.0146789550781250, +-0.0509338378906250, 0.0179748535156250, -0.0514831542968750, 0.0184936523437500, +-0.0516052246093750, 0.0169982910156250, -0.0555725097656250, 0.0172119140625000, +-0.0540771484375000, 0.0168151855468750, -0.0537719726562500, 0.0141296386718750, +-0.0557250976562500, 0.0144348144531250, -0.0516662597656250, 0.0118103027343750, +-0.0486755371093750, 0.0087585449218750, -0.0516052246093750, 0.0100708007812500, +-0.0392761230468750, 0.0036315917968750, -0.0420532226562500, 0.0037536621093750, +-0.0375061035156250, 0.0015258789062500, -0.0273132324218750, -0.0033264160156250, +-0.0331726074218750, -0.0014953613281250, -0.0209960937500000, -0.0063476562500000, +-0.0216979980468750, -0.0066833496093750, -0.0198669433593750, -0.0075378417968750, +-0.0120544433593750, -0.0103454589843750, -0.0155334472656250, -0.0090942382812500, +-0.0094299316406250, -0.0108642578125000, -0.0087585449218750, -0.0110473632812500, +-0.0083923339843750, -0.0106201171875000, -0.0054016113281250, -0.0110778808593750, +-0.0064086914062500, -0.0107727050781250, -0.0042114257812500, -0.0109558105468750, +-0.0038757324218750, -0.0108032226562500, -0.0040588378906250, -0.0104370117187500, +-0.0028076171875000, -0.0104370117187500, -0.0029907226562500, -0.0101623535156250, +-0.0054321289062500, -0.0089111328125000, -0.0036315917968750, -0.0093383789062500, +-0.0065307617187500, -0.0086364746093750, -0.0103149414062500, -0.0074462890625000, +-0.0076293945312500, -0.0081176757812500, -0.0157165527343750, -0.0062255859375000, +-0.0145263671875000, -0.0074157714843750, -0.0176086425781250, -0.0053405761718750, +-0.0236511230468750, -0.0035095214843750, -0.0204772949218750, -0.0059509277343750, +-0.0317382812500000, 0.0034484863281250, -0.0299682617187500, 0.0001220703125000, +-0.0341186523437500, 0.0037231445312500, -0.0440063476562500, 0.0127563476562500, +-0.0397644042968750, 0.0072326660156250, -0.0487670898437500, 0.0152893066406250, +-0.0502624511718750, 0.0164794921875000, -0.0497436523437500, 0.0143432617187500, +-0.0535278320312500, 0.0173034667968750, -0.0529174804687500, 0.0175170898437500, +-0.0503234863281250, 0.0113220214843750, -0.0529479980468750, 0.0149230957031250, +-0.0483398437500000, 0.0092773437500000, -0.0435180664062500, 0.0009460449218750, +-0.0477294921875000, 0.0064392089843750, -0.0343627929687500, -0.0083312988281250, +-0.0359191894531250, -0.0065612792968750, -0.0339050292968750, -0.0089416503906250, +-0.0250244140625000, -0.0201416015625000, -0.0289611816406250, -0.0158386230468750, +-0.0233154296875000, -0.0178833007812500, -0.0234375000000000, -0.0215454101562500, +-0.0214843750000000, -0.0174560546875000, -0.0178222656250000, -0.0142822265625000, +-0.0202636718750000, -0.0173339843750000, -0.0118408203125000, -0.0071105957031250, +-0.0130310058593750, -0.0084228515625000, -0.0110473632812500, -0.0070495605468750, +-0.0047302246093750, 0.0007019042968750, -0.0072631835937500, -0.0014953613281250, +-0.0022583007812500, -0.0000610351562500, -0.0025634765625000, 0.0031433105468750, +-0.0001525878906250, -0.0038452148437500, 0.0038452148437500, -0.0078430175781250, +0.0011901855468750, -0.0025024414062500, 0.0084228515625000, -0.0236511230468750, +0.0087890625000000, -0.0229187011718750, 0.0073852539062500, -0.0223083496093750, +0.0107727050781250, -0.0349731445312500, 0.0106811523437500, -0.0324707031250000, +0.0037231445312500, -0.0230712890625000, 0.0060119628906250, -0.0288391113281250, +0.0035095214843750, -0.0202941894531250, -0.0033264160156250, -0.0075378417968750, +-0.0004577636718750, -0.0151977539062500, -0.0034790039062500, 0.0056152343750000, +-0.0036926269531250, 0.0047912597656250, -0.0048522949218750, 0.0059814453125000, +-0.0059204101562500, 0.0191650390625000, -0.0040588378906250, 0.0147705078125000, +-0.0123901367187500, 0.0126342773437500, -0.0104064941406250, 0.0198669433593750, +-0.0128173828125000, 0.0069885253906250, -0.0201110839843750, -0.0074157714843750, +-0.0166931152343750, 0.0036010742187500, -0.0203857421875000, -0.0143432617187500, +-0.0209045410156250, -0.0189819335937500, -0.0218505859375000, -0.0129394531250000, +-0.0223693847656250, -0.0162353515625000, -0.0211181640625000, -0.0185241699218750, +-0.0330505371093750, -0.0037231445312500, -0.0283203125000000, -0.0018005371093750, +-0.0356445312500000, -0.0096130371093750, -0.0489807128906250, -0.0074462890625000, +-0.0413513183593750, -0.0032043457031250, -0.0581054687500000, -0.0222778320312500, +-0.0588073730468750, -0.0193176269531250, -0.0580444335937500, -0.0242004394531250, +-0.0668640136718750, -0.0397644042968750, -0.0643615722656250, -0.0337524414062500, +-0.0580444335937500, -0.0392761230468750, -0.0635070800781250, -0.0410156250000000, +-0.0558471679687500, -0.0424194335937500, -0.0350646972656250, -0.0475769042968750, +-0.0257263183593750, -0.0495605468750000, 0.0020446777343750, -0.0490417480468750, +-0.0069580078125000, -0.0501403808593750, -0.0042114257812500, -0.0525512695312500, +0.0092468261718750, -0.0521850585937500, 0.0074462890625000, -0.0496826171875000, +0.0058898925781250, -0.0556640625000000, 0.0059814453125000, -0.0581970214843750, +0.0065917968750000, -0.0529479980468750, 0.0061645507812500, -0.0527954101562500, +0.0054016113281250, -0.0552978515625000, 0.0094299316406250, -0.0335388183593750, +0.0080871582031250, -0.0387878417968750, 0.0090332031250000, -0.0349731445312500, +0.0133666992187500}, +{-0.0500488281250000, -0.0057983398437500, -0.0503540039062500, -0.0038452148437500, +-0.0509338378906250, -0.0056762695312500, -0.0459594726562500, 0.0012207031250000, +-0.0471191406250000, -0.0001220703125000, -0.0454711914062500, 0.0023803710937500, +-0.0411682128906250, 0.0083923339843750, -0.0432128906250000, 0.0055541992187500, +-0.0401611328125000, 0.0110778808593750, -0.0403442382812500, 0.0117187500000000, +-0.0389404296875000, 0.0099792480468750, -0.0371093750000000, 0.0124511718750000, +-0.0387878417968750, 0.0129394531250000, -0.0317687988281250, 0.0053100585937500, +-0.0334167480468750, 0.0080261230468750, -0.0307312011718750, 0.0030822753906250, +-0.0243225097656250, -0.0051269531250000, -0.0271911621093750, -0.0003356933593750, +-0.0208740234375000, -0.0122680664062500, -0.0213012695312500, -0.0125732421875000, +-0.0189819335937500, -0.0120849609375000, -0.0144653320312500, -0.0187988281250000, +-0.0171508789062500, -0.0178527832031250, -0.0087280273437500, -0.0144958496093750, +-0.0090637207031250, -0.0175781250000000, -0.0086364746093750, -0.0118713378906250, +-0.0032958984375000, -0.0043640136718750, -0.0048522949218750, -0.0095214843750000, +-0.0057678222656250, -0.0008239746093750, -0.0046386718750000, 0.0035705566406250, +-0.0049133300781250, -0.0035095214843750, -0.0070190429687500, -0.0057678222656250, +-0.0068054199218750, -0.0012817382812500, -0.0031738281250000, -0.0184020996093750, +-0.0047912597656250, -0.0179748535156250, -0.0028686523437500, -0.0175781250000000, +0.0016174316406250, -0.0271301269531250, -0.0003051757812500, -0.0247192382812500, +0.0018005371093750, -0.0199279785156250, 0.0028381347656250, -0.0252685546875000, +0.0020751953125000, -0.0162658691406250, 0.0025024414062500, -0.0057067871093750, +0.0029296875000000, -0.0130920410156250, -0.0002136230468750, 0.0085144042968750, +0.0021362304687500, 0.0079040527343750, -0.0023803710937500, 0.0077209472656250, +-0.0067443847656250, 0.0224304199218750, -0.0028076171875000, 0.0192260742187500, +-0.0197143554687500, 0.0028381347656250, -0.0148620605468750, 0.0112304687500000, +-0.0235290527343750, 0.0007019042968750, -0.0405883789062500, -0.0198974609375000, +-0.0307617187500000, -0.0083007812500000, -0.0490722656250000, -0.0231323242187500, +-0.0513305664062500, -0.0317993164062500, -0.0502929687500000, -0.0198669433593750, +-0.0574340820312500, -0.0120239257812500, -0.0551757812500000, -0.0194091796875000, +-0.0561218261718750, -0.0100708007812500, -0.0585632324218750, -0.0039062500000000, +-0.0530395507812500, -0.0146789550781250, -0.0502929687500000, -0.0189819335937500, +-0.0541992187500000, -0.0110778808593750, -0.0352172851562500, -0.0386657714843750, +-0.0381469726562500, -0.0382385253906250, -0.0353393554687500, -0.0367431640625000, +-0.0138854980468750, -0.0564575195312500, -0.0080871582031250, -0.0227966308593750, +-0.0017089843750000, -0.0522766113281250, 0.0003051757812500, -0.0455017089843750, +0.0005187988281250, -0.0468444824218750, -0.0019836425781250, -0.0583190917968750, +-0.0031433105468750, -0.0572204589843750, 0.0071716308593750, -0.0531005859375000, +0.0059509277343750, -0.0540771484375000, 0.0043945312500000, -0.0533447265625000, +0.0113220214843750, -0.0502624511718750, 0.0103759765625000, -0.0510864257812500, +-0.0027160644531250, -0.0517272949218750, 0.0027465820312500, -0.0536193847656250, +-0.0047912597656250, -0.0456542968750000, -0.0201416015625000, -0.0412902832031250, +-0.0120849609375000, -0.0482177734375000, -0.0232543945312500, -0.0270690917968750, +-0.0295104980468750, -0.0265197753906250, -0.0191955566406250, -0.0274047851562500, +-0.0145263671875000, -0.0178222656250000, -0.0223083496093750, -0.0199279785156250, +-0.0072631835937500, -0.0191650390625000, -0.0057983398437500, -0.0195617675781250, +-0.0076293945312500, -0.0159606933593750, -0.0007324218750000, -0.0145874023437500, +-0.0024414062500000, -0.0175170898437500, -0.0132446289062500, -0.0004577636718750, +-0.0054626464843750, -0.0033569335937500, -0.0170288085937500, -0.0005187988281250, +-0.0357971191406250, 0.0131835937500000, -0.0234985351562500, 0.0085754394531250, +-0.0361633300781250, 0.0073547363281250, -0.0450439453125000, 0.0113525390625000, +-0.0355224609375000, 0.0076293945312500, -0.0288391113281250, 0.0018920898437500, +-0.0350036621093750, 0.0047607421875000, -0.0269470214843750, 0.0002441406250000, +-0.0247802734375000, 0.0003967285156250, -0.0256347656250000, -0.0016174316406250, +-0.0240783691406250, -0.0044860839843750, -0.0243835449218750, -0.0019836425781250, +-0.0213623046875000, -0.0106506347656250, -0.0227355957031250, -0.0098266601562500, +-0.0203552246093750, -0.0101013183593750, -0.0167541503906250, -0.0156250000000000, +-0.0187988281250000, -0.0139160156250000, -0.0115966796875000, -0.0125122070312500, +-0.0135192871093750, -0.0129699707031250, -0.0111694335937500, -0.0131530761718750, +-0.0047302246093750, -0.0113220214843750, -0.0081787109375000, -0.0108337402343750, +-0.0036926269531250, -0.0164794921875000, -0.0033569335937500, -0.0140380859375000, +-0.0028076171875000, -0.0172424316406250, -0.0004272460937500, -0.0233154296875000, +-0.0019226074218750, -0.0200500488281250, -0.0001525878906250, -0.0292663574218750, +0.0009155273437500, -0.0276184082031250, -0.0014038085937500, -0.0314636230468750, +-0.0021667480468750, -0.0392456054687500, -0.0004272460937500, -0.0345764160156250, +-0.0061645507812500, -0.0444030761718750, -0.0061035156250000, -0.0449829101562500, +-0.0051269531250000, -0.0440673828125000, -0.0080871582031250, -0.0481567382812500, +-0.0079956054687500, -0.0473022460937500, -0.0037841796875000, -0.0468750000000000, +-0.0054931640625000, -0.0468750000000000, -0.0039978027343750, -0.0476684570312500, +0.0000000000000000, -0.0481567382812500, -0.0022583007812500, -0.0474548339843750, +0.0004882812500000, -0.0486145019531250, 0.0003662109375000, -0.0497741699218750, +0.0005187988281250, -0.0477600097656250, 0.0015563964843750, -0.0468139648437500, +0.0002136230468750, -0.0483703613281250, 0.0023193359375000, -0.0422058105468750, +0.0016479492187500, -0.0437316894531250, 0.0018310546875000, -0.0407409667968750, +0.0033569335937500, -0.0355529785156250, 0.0021972656250000, -0.0388488769531250, +0.0032958984375000, -0.0288391113281250, 0.0036010742187500, -0.0304870605468750, +0.0032348632812500, -0.0271911621093750, 0.0036926269531250, -0.0193481445312500, +0.0039062500000000, -0.0236206054687500, 0.0028686523437500, -0.0137634277343750, +0.0035705566406250, -0.0145874023437500, 0.0024719238281250, -0.0121459960937500, +0.0012512207031250, -0.0051269531250000, 0.0027160644531250, -0.0084533691406250, +-0.0006713867187500, -0.0015563964843750, 0.0002746582031250, -0.0007629394531250, +-0.0012512207031250, -0.0008544921875000, -0.0042724609375000, 0.0024719238281250, +-0.0020141601562500, 0.0020141601562500, -0.0061645507812500, 0.0017700195312500, +-0.0059509277343750, 0.0032348632812500, -0.0057678222656250, 0.0009155273437500, +-0.0079956054687500, -0.0007934570312500, -0.0070495605468750, 0.0010070800781250, +-0.0068969726562500, -0.0079650878906250, -0.0070190429687500, -0.0055541992187500, +-0.0063781738281250, -0.0104675292968750, -0.0054931640625000, -0.0192565917968750, +-0.0053405761718750, -0.0141906738281250, -0.0053405761718750, -0.0269775390625000, +-0.0046691894531250, -0.0263977050781250, -0.0052185058593750, -0.0284118652343750, +-0.0057678222656250, -0.0366210937500000, -0.0049438476562500, -0.0335083007812500, +-0.0072021484375000, -0.0396423339843750, -0.0069274902343750, -0.0393371582031250, +-0.0078430175781250, -0.0415344238281250, -0.0098266601562500, -0.0456542968750000, +-0.0088806152343750, -0.0427246093750000, -0.0107116699218750, -0.0509338378906250, +-0.0117492675781250, -0.0506896972656250, -0.0104064941406250, -0.0497741699218750, +-0.0107116699218750, -0.0543212890625000, -0.0123291015625000, -0.0537719726562500, +-0.0072631835937500, -0.0495300292968750, -0.0093078613281250, -0.0517578125000000, +-0.0067138671875000, -0.0493469238281250, -0.0017700195312500, -0.0451660156250000, +-0.0050964355468750, -0.0479736328125000, 0.0032043457031250, -0.0395507812500000, +0.0023193359375000, -0.0422363281250000, 0.0039978027343750, -0.0376586914062500, +0.0100097656250000, -0.0290222167968750, 0.0072631835937500, -0.0343322753906250, +0.0111083984375000, -0.0227966308593750, 0.0126953125000000, -0.0223999023437500, +0.0102539062500000, -0.0211181640625000, 0.0105590820312500, -0.0147399902343750, +0.0116882324218750, -0.0166625976562500, 0.0031127929687500, -0.0108947753906250, +0.0057983398437500, -0.0113525390625000, 0.0004577636718750, -0.0082702636718750, +-0.0091247558593750, -0.0037231445312500, -0.0040893554687500, -0.0067749023437500, +-0.0138244628906250, 0.0025329589843750, -0.0161437988281250, 0.0025024414062500, +-0.0141906738281250, 0.0011901855468750, -0.0166931152343750, 0.0068664550781250, +-0.0165100097656250, 0.0064086914062500, -0.0104675292968750, -0.0034179687500000, +-0.0126037597656250, 0.0022888183593750, -0.0086364746093750, -0.0037231445312500, +-0.0008544921875000, -0.0163574218750000, -0.0045166015625000, -0.0090332031250000, +-0.0018615722656250, -0.0181579589843750, 0.0015563964843750, -0.0205993652343750, +-0.0032043457031250, -0.0169372558593750, -0.0068969726562500, -0.0190429687500000, +-0.0039367675781250, -0.0202636718750000, -0.0144653320312500, -0.0082092285156250, +-0.0151062011718750, -0.0095520019531250, -0.0133666992187500, -0.0132751464843750, +-0.0180053710937500, -0.0075073242187500, -0.0187072753906250, -0.0054931640625000, +-0.0138549804687500, -0.0142211914062500, -0.0150146484375000, -0.0143737792968750, +-0.0124816894531250, -0.0156860351562500, -0.0086669921875000, -0.0204467773437500, +-0.0120544433593750, -0.0175781250000000, -0.0043334960937500, -0.0178222656250000, +-0.0040283203125000, -0.0219726562500000, -0.0048522949218750, -0.0160522460937500, +-0.0024414062500000, -0.0096740722656250, -0.0034484863281250, -0.0153198242187500, +-0.0013122558593750, -0.0064392089843750, -0.0021362304687500, -0.0036926269531250, +-0.0008239746093750, -0.0068359375000000, 0.0021057128906250, -0.0070800781250000, +0.0004882812500000, -0.0058593750000000, 0.0007934570312500, -0.0057983398437500, +0.0025634765625000, -0.0071716308593750, 0.0016479492187500, -0.0053100585937500, +-0.0002441406250000, -0.0032348632812500, 0.0010681152343750, -0.0035705566406250, +0.0021362304687500, 0.0038146972656250, 0.0017395019531250, 0.0019836425781250, +0.0012512207031250, 0.0020751953125000, 0.0024108886718750, 0.0070495605468750, +0.0025024414062500, 0.0054931640625000, -0.0033874511718750, 0.0066528320312500, +-0.0018310546875000, 0.0072326660156250, -0.0021362304687500, 0.0073547363281250, +-0.0057983398437500, 0.0081176757812500, -0.0055541992187500, 0.0073547363281250, +-0.0113830566406250, 0.0050048828125000, -0.0072631835937500, 0.0076904296875000, +-0.0136413574218750, 0.0041198730468750, -0.0231018066406250, -0.0013732910156250, +-0.0166625976562500, 0.0013427734375000, -0.0306091308593750, -0.0054931640625000, +-0.0318298339843750, -0.0052185058593750, -0.0298767089843750, -0.0053100585937500, +-0.0356750488281250, -0.0096130371093750, -0.0346374511718750, -0.0087280273437500, +-0.0283203125000000, -0.0075683593750000, -0.0326843261718750, -0.0075073242187500, +-0.0260925292968750, -0.0081787109375000, -0.0155334472656250, -0.0079040527343750, +-0.0221862792968750, -0.0074157714843750, -0.0132141113281250, -0.0108642578125000, +-0.0101318359375000, -0.0104370117187500, -0.0131530761718750, -0.0086364746093750, +-0.0132141113281250, -0.0108642578125000, -0.0115356445312500, -0.0119018554687500, +-0.0108337402343750}, +{0.0037231445312500, -0.0288696289062500, 0.0023193359375000, -0.0265808105468750, +0.0025024414062500, -0.0259399414062500, 0.0028076171875000, -0.0252380371093750, +0.0021362304687500, -0.0242614746093750, 0.0023498535156250, -0.0244750976562500, +0.0036010742187500, -0.0198669433593750, 0.0035705566406250, -0.0217285156250000, +0.0035400390625000, -0.0189819335937500, 0.0051574707031250, -0.0132751464843750, +0.0052490234375000, -0.0166320800781250, 0.0002136230468750, -0.0138244628906250, +0.0030517578125000, -0.0106201171875000, -0.0010986328125000, -0.0151062011718750, +-0.0078125000000000, -0.0178833007812500, -0.0039367675781250, -0.0135498046875000, +-0.0140075683593750, -0.0226135253906250, -0.0140686035156250, -0.0230407714843750, +-0.0131225585937500, -0.0198364257812500, -0.0186462402343750, -0.0230407714843750, +-0.0176086425781250, -0.0234375000000000, -0.0115051269531250, -0.0138244628906250, +-0.0136413574218750, -0.0178222656250000, -0.0111083984375000, -0.0106201171875000, +-0.0046997070312500, 0.0022277832031250, -0.0073547363281250, -0.0064086914062500, +-0.0049438476562500, -0.0016174316406250, -0.0024719238281250, 0.0058593750000000, +-0.0069580078125000, -0.0014038085937500, -0.0105590820312500, -0.0098266601562500, +-0.0073547363281250, -0.0051574707031250, -0.0126037597656250, -0.0118713378906250, +-0.0151672363281250, -0.0137023925781250, -0.0131530761718750, -0.0108337402343750, +-0.0132446289062500, -0.0127563476562500, -0.0140686035156250, -0.0144958496093750, +-0.0063476562500000, -0.0045776367187500, -0.0096740722656250, -0.0052795410156250, +-0.0065307617187500, -0.0072937011718750, 0.0021667480468750, -0.0021362304687500, +-0.0022277832031250, -0.0017700195312500, 0.0011291503906250, -0.0093994140625000, +0.0028381347656250, -0.0096130371093750, -0.0002746582031250, -0.0058593750000000, +-0.0017089843750000, -0.0077209472656250, -0.0003662109375000, -0.0101623535156250, +-0.0036621093750000, -0.0017395019531250, -0.0043945312500000, -0.0026245117187500, +-0.0044860839843750, -0.0006408691406250, -0.0055847167968750, 0.0068054199218750, +-0.0050659179687500, 0.0057067871093750, -0.0048217773437500, 0.0064697265625000, +-0.0047302246093750, 0.0067138671875000, -0.0051879882812500, 0.0067749023437500, +-0.0051269531250000, 0.0072631835937500, -0.0044860839843750, 0.0068969726562500, +-0.0065917968750000, 0.0070495605468750, -0.0060729980468750, 0.0077819824218750, +-0.0061035156250000, 0.0054626464843750, -0.0081176757812500, 0.0042114257812500, +-0.0078125000000000, 0.0061035156250000, -0.0052795410156250, -0.0003967285156250, +-0.0043029785156250, -0.0004577636718750, -0.0090332031250000, -0.0011596679687500, +-0.0103149414062500, -0.0041809082031250, -0.0063476562500000, -0.0025939941406250, +-0.0195007324218750, -0.0068054199218750, -0.0188903808593750, -0.0070190429687500, +-0.0184326171875000, -0.0071411132812500, -0.0256958007812500, -0.0087280273437500, +-0.0239868164062500, -0.0077514648437500, -0.0217590332031250, -0.0103149414062500, +-0.0237121582031250, -0.0110473632812500, -0.0201416015625000, -0.0087585449218750, +-0.0169372558593750, -0.0086059570312500, -0.0202941894531250, -0.0097961425781250, +-0.0085754394531250, -0.0024414062500000, -0.0093688964843750, -0.0042114257812500, +-0.0090942382812500, -0.0025329589843750, -0.0015563964843750, 0.0046997070312500, +-0.0034484863281250, 0.0025024414062500, -0.0061950683593750, 0.0003356933593750, +-0.0039367675781250, 0.0025939941406250, -0.0049743652343750, 0.0010681152343750, +-0.0090637207031250, -0.0021667480468750, -0.0080871582031250, -0.0002746582031250, +-0.0071716308593750, -0.0028991699218750, -0.0075378417968750, -0.0037231445312500, +-0.0090026855468750, -0.0003662109375000, -0.0087280273437500, 0.0005493164062500, +-0.0079345703125000, -0.0011291503906250, -0.0140991210937500, 0.0068664550781250, +-0.0124816894531250, 0.0072021484375000, -0.0150146484375000, 0.0073242187500000, +-0.0210876464843750, 0.0118713378906250, -0.0181884765625000, 0.0114746093750000, +-0.0220031738281250, 0.0090026855468750, -0.0235595703125000, 0.0108032226562500, +-0.0230712890625000, 0.0095825195312500, -0.0235900878906250, 0.0064697265625000, +-0.0242919921875000, 0.0081481933593750, -0.0257568359375000, 0.0061645507812500, +-0.0241394042968750, 0.0063171386718750, -0.0278320312500000, 0.0062866210937500, +-0.0309143066406250, 0.0053710937500000, -0.0273742675781250, 0.0062255859375000, +-0.0381469726562500, 0.0052490234375000, -0.0364074707031250, 0.0054321289062500, +-0.0373229980468750, 0.0047302246093750, -0.0447387695312500, 0.0038146972656250, +-0.0414733886718750, 0.0042419433593750, -0.0421752929687500, 0.0007629394531250, +-0.0440368652343750, 0.0016479492187500, -0.0412597656250000, -0.0006103515625000, +-0.0388488769531250, -0.0041809082031250, -0.0402526855468750, -0.0025329589843750, +-0.0351867675781250, -0.0088806152343750, -0.0357360839843750, -0.0088195800781250, +-0.0335083007812500, -0.0102233886718750, -0.0293884277343750, -0.0145874023437500, +-0.0314941406250000, -0.0131530761718750, -0.0256652832031250, -0.0151977539062500, +-0.0254821777343750, -0.0159912109375000, -0.0253601074218750, -0.0145874023437500, +-0.0222778320312500, -0.0143127441406250, -0.0228271484375000, -0.0149230957031250, +-0.0216064453125000, -0.0116577148437500, -0.0213317871093750, -0.0121459960937500, +-0.0203247070312500, -0.0104980468750000, -0.0192871093750000, -0.0077514648437500, +-0.0197448730468750, -0.0090637207031250, -0.0170593261718750, -0.0045471191406250, +-0.0171203613281250, -0.0048828125000000, -0.0165405273437500, -0.0032653808593750, +-0.0148315429687500, 0.0002136230468750, -0.0154113769531250, -0.0015563964843750, +-0.0139160156250000, 0.0025024414062500, -0.0144042968750000, 0.0032653808593750, +-0.0133972167968750, 0.0032653808593750, -0.0117492675781250, 0.0048217773437500, +-0.0130310058593750, 0.0046386718750000, -0.0109863281250000, 0.0046997070312500, +-0.0106811523437500, 0.0048828125000000, -0.0122985839843750, 0.0048522949218750, +-0.0120544433593750, 0.0046691894531250, -0.0116882324218750, 0.0044860839843750, +-0.0173645019531250, 0.0047302246093750, -0.0160827636718750, 0.0050659179687500, +-0.0184326171875000, 0.0045471191406250, -0.0235290527343750, 0.0043945312500000, +-0.0210571289062500, 0.0047607421875000, -0.0258178710937500, 0.0025634765625000, +-0.0258483886718750, 0.0037231445312500, -0.0265808105468750, 0.0019531250000000, +-0.0293273925781250, -0.0005187988281250, -0.0277099609375000, 0.0016174316406250, +-0.0299377441406250, -0.0036010742187500, -0.0303649902343750, -0.0032958984375000, +-0.0289611816406250, -0.0028076171875000, -0.0286254882812500, -0.0058898925781250, +-0.0288391113281250, -0.0050048828125000, -0.0271911621093750, -0.0021972656250000, +-0.0261230468750000, -0.0044555664062500, -0.0270996093750000, -0.0008239746093750, +-0.0271301269531250, 0.0036621093750000, -0.0256042480468750, -0.0000305175781250, +-0.0288696289062500, 0.0094909667968750, -0.0285644531250000, 0.0089111328125000, +-0.0286254882812500, 0.0097656250000000, -0.0302124023437500, 0.0157165527343750, +-0.0292358398437500, 0.0135803222656250, -0.0300903320312500, 0.0157165527343750, +-0.0298461914062500, 0.0171508789062500, -0.0298767089843750, 0.0143127441406250, +-0.0307617187500000, 0.0139465332031250, -0.0301513671875000, 0.0160522460937500, +-0.0290222167968750, 0.0065917968750000, -0.0297851562500000, 0.0087280273437500, +-0.0283813476562500, 0.0055236816406250, -0.0261840820312500, -0.0026855468750000, +-0.0272827148437500, 0.0016784667968750, -0.0263061523437500, -0.0042724609375000, +-0.0255737304687500, -0.0066223144531250, -0.0262145996093750, -0.0031738281250000, +-0.0268859863281250, -0.0025329589843750, -0.0263366699218750, -0.0041503906250000, +-0.0254821777343750, 0.0014038085937500, -0.0263977050781250, 0.0019531250000000, +-0.0250549316406250, 0.0017089843750000, -0.0228576660156250, 0.0048217773437500, +-0.0238037109375000, 0.0042724609375000, -0.0223388671875000, -0.0011291503906250, +-0.0219421386718750, 0.0020446777343750, -0.0214233398437500, -0.0018615722656250, +-0.0210876464843750, -0.0094604492187500, -0.0213012695312500, -0.0057373046875000, +-0.0167236328125000, -0.0128173828125000, -0.0177307128906250, -0.0139465332031250, +-0.0170593261718750, -0.0130310058593750, -0.0124206542968750, -0.0154724121093750, +-0.0137939453125000, -0.0148620605468750, -0.0188293457031250, -0.0126647949218750, +-0.0153198242187500, -0.0146789550781250, -0.0197143554687500, -0.0115051269531250, +-0.0281677246093750, -0.0071105957031250, -0.0239868164062500, -0.0096435546875000, +-0.0278930664062500, -0.0026245117187500, -0.0307922363281250, -0.0018920898437500, +-0.0277404785156250, -0.0042724609375000, -0.0261840820312500, -0.0024414062500000, +-0.0279541015625000, -0.0005187988281250, -0.0215454101562500, -0.0023498535156250, +-0.0227355957031250, -0.0051269531250000, -0.0214538574218750, -0.0024108886718750, +-0.0160827636718750, 0.0009765625000000, -0.0179748535156250, -0.0000305175781250, +-0.0170288085937500, 0.0054931640625000, -0.0169677734375000, 0.0053710937500000, +-0.0142822265625000, 0.0025939941406250, -0.0126647949218750, 0.0054321289062500, +-0.0151062011718750, 0.0079956054687500, -0.0072021484375000, -0.0017700195312500, +-0.0070800781250000, -0.0003051757812500, -0.0075988769531250, -0.0052795410156250, +-0.0048217773437500, -0.0127868652343750, -0.0053710937500000, -0.0064697265625000, +-0.0013122558593750, -0.0188598632812500, -0.0029602050781250, -0.0204467773437500, +-0.0027770996093750, -0.0184631347656250, 0.0027770996093750, -0.0238952636718750, +0.0089111328125000, -0.0018920898437500, -0.0021667480468750, -0.0256042480468750, +0.0023803710937500, -0.0236206054687500, -0.0035400390625000, -0.0213928222656250, +-0.0122375488281250, -0.0241394042968750, -0.0074157714843750, -0.0252380371093750, +-0.0112915039062500, -0.0291442871093750, -0.0159606933593750, -0.0238342285156250, +-0.0091247558593750, -0.0324707031250000, -0.0043945312500000, -0.0437622070312500, +-0.0104370117187500, -0.0358581542968750, 0.0024719238281250, -0.0510864257812500, +0.0050048828125000, -0.0557250976562500, 0.0001525878906250, -0.0466613769531250, +0.0028076171875000, -0.0469360351562500, 0.0047607421875000, -0.0521545410156250, +-0.0081481933593750, -0.0313110351562500, -0.0074462890625000, -0.0327148437500000, +-0.0042114257812500, -0.0315246582031250, -0.0095520019531250, -0.0188903808593750, +-0.0116882324218750, -0.0227050781250000, -0.0086364746093750, -0.0221557617187500, +-0.0045166015625000, -0.0216674804687500, -0.0116577148437500, -0.0193481445312500, +-0.0180053710937500, -0.0182495117187500, -0.0124206542968750, -0.0207824707031250, +-0.0238952636718750, -0.0135192871093750, -0.0249633789062500, -0.0126953125000000, +-0.0242614746093750, -0.0134887695312500, -0.0287780761718750, -0.0114135742187500, +-0.0267944335937500, -0.0114746093750000, -0.0257873535156250, -0.0089721679687500, +-0.0307922363281250, -0.0108032226562500, -0.0202636718750000, -0.0073852539062500, +-0.0102233886718750, -0.0023803710937500, -0.0192260742187500, -0.0054931640625000, +0.0003051757812500, -0.0003356933593750, 0.0019531250000000, 0.0017089843750000, +0.0003051757812500, -0.0015563964843750, 0.0090332031250000, -0.0016784667968750, +0.0070800781250000, 0.0001831054687500, 0.0002441406250000, -0.0089416503906250, +0.0049743652343750, -0.0072937011718750, -0.0004577636718750, -0.0097656250000000, +-0.0110168457031250, -0.0166015625000000, -0.0048828125000000, -0.0134887695312500, +-0.0095214843750000, -0.0210266113281250, -0.0150451660156250, -0.0197448730468750, +-0.0065307617187500}, +{-0.0231933593750000, -0.0039672851562500, -0.0281066894531250, -0.0057983398437500, +-0.0330810546875000, -0.0086059570312500, -0.0289916992187500, -0.0069274902343750, +-0.0354614257812500, -0.0120544433593750, -0.0385437011718750, -0.0113830566406250, +-0.0334472656250000, -0.0117492675781250, -0.0318908691406250, -0.0160827636718750, +-0.0351867675781250, -0.0148010253906250, -0.0250549316406250, -0.0111389160156250, +-0.0260620117187500, -0.0144958496093750, -0.0231018066406250, -0.0077209472656250, +-0.0165710449218750, 0.0008850097656250, -0.0207214355468750, -0.0053710937500000, +-0.0090942382812500, 0.0031738281250000, -0.0098266601562500, 0.0057983398437500, +-0.0086975097656250, 0.0056762695312500, -0.0018310546875000, 0.0081787109375000, +-0.0041198730468750, 0.0062866210937500, 0.0024108886718750, 0.0039672851562500, +0.0017700195312500, 0.0066833496093750, 0.0021057128906250, 0.0054931640625000, +0.0063781738281250, 0.0011596679687500, 0.0051879882812500, 0.0020446777343750, +0.0060424804687500, 0.0010375976562500, 0.0049438476562500, -0.0006713867187500, +0.0078735351562500, 0.0046081542968750, 0.0111083984375000, 0.0094299316406250, +0.0076599121093750, 0.0042114257812500, 0.0111083984375000, 0.0044860839843750, +0.0143127441406250, 0.0115966796875000, 0.0101318359375000, 0.0029907226562500, +0.0036621093750000, -0.0160827636718750, 0.0005798339843750, 0.0124816894531250, +0.0035095214843750, 0.0027770996093750, -0.0005798339843750, 0.0150146484375000, +0.0036926269531250, 0.0017395019531250, 0.0094909667968750, -0.0168151855468750, +0.0057983398437500, -0.0073852539062500, 0.0083007812500000, -0.0174560546875000, +0.0112609863281250, -0.0214843750000000, 0.0066833496093750, -0.0183410644531250, +0.0041809082031250, -0.0179443359375000, 0.0076904296875000, -0.0194396972656250, +-0.0047912597656250, -0.0222778320312500, -0.0046386718750000, -0.0173950195312500, +-0.0038452148437500, -0.0250854492187500, -0.0107727050781250, -0.0359802246093750, +-0.0093383789062500, -0.0286254882812500, -0.0027465820312500, -0.0350952148437500, +-0.0044250488281250, -0.0419311523437500, -0.0086059570312500, -0.0318908691406250, +-0.0036926269531250, -0.0242919921875000, -0.0003967285156250, -0.0319213867187500, +-0.0211486816406250, -0.0158691406250000, -0.0185241699218750, -0.0126647949218750, +-0.0191650390625000, -0.0176391601562500, -0.0326843261718750, -0.0154418945312500, +-0.0286560058593750, -0.0137634277343750, -0.0246582031250000, -0.0183105468750000, +-0.0299377441406250, -0.0199584960937500, -0.0221557617187500, -0.0177307128906250, +-0.0134582519531250, -0.0172424316406250, -0.0202026367187500, -0.0182800292968750, +0.0009765625000000, -0.0146484375000000, 0.0011291503906250, -0.0147094726562500, +-0.0021057128906250, -0.0140686035156250, 0.0073852539062500, -0.0119018554687500, +0.0073852539062500, -0.0127563476562500, 0.0014038085937500, -0.0103759765625000, +0.0030212402343750, -0.0107421875000000, 0.0009765625000000, -0.0097351074218750, +-0.0043640136718750, -0.0073547363281250, -0.0011596679687500, -0.0085754394531250, +-0.0019531250000000, -0.0077209472656250, -0.0062866210937500, -0.0057983398437500, +0.0007629394531250, -0.0090942382812500, 0.0066833496093750, -0.0113830566406250, +0.0001831054687500, -0.0087890625000000, 0.0155334472656250, -0.0180358886718750, +0.0165100097656250, -0.0168151855468750, 0.0129699707031250, -0.0188293457031250, +0.0189819335937500, -0.0252380371093750, 0.0195922851562500, -0.0222778320312500, +0.0098266601562500, -0.0282592773437500, 0.0127563476562500, -0.0281677246093750, +0.0097351074218750, -0.0288085937500000, 0.0015563964843750, -0.0327758789062500, +0.0055236816406250, -0.0311889648437500, -0.0028991699218750, -0.0313415527343750, +-0.0028076171875000, -0.0328063964843750, -0.0028686523437500, -0.0306396484375000, +-0.0082397460937500, -0.0283508300781250, -0.0067138671875000, -0.0297851562500000, +-0.0032958984375000, -0.0264282226562500, -0.0065612792968750, -0.0260620117187500, +-0.0024414062500000, -0.0255737304687500, 0.0033264160156250, -0.0241088867187500, +-0.0011596679687500, -0.0248107910156250, 0.0078430175781250, -0.0215148925781250, +0.0071411132812500, -0.0222167968750000, 0.0076599121093750, -0.0215454101562500, +0.0129089355468750, -0.0186767578125000, 0.0104370117187500, -0.0198669433593750, +0.0131225585937500, -0.0202941894531250, 0.0137939453125000, -0.0199584960937500, +0.0130310058593750, -0.0202941894531250, 0.0138549804687500, -0.0216064453125000, +0.0142822265625000, -0.0217285156250000, 0.0125122070312500, -0.0191345214843750, +0.0137939453125000, -0.0200805664062500, 0.0122375488281250, -0.0191345214843750, +0.0104675292968750, -0.0161743164062500, 0.0128479003906250, -0.0173034667968750, +0.0065917968750000, -0.0167236328125000, 0.0087890625000000, -0.0157470703125000, +0.0065002441406250, -0.0166015625000000, 0.0010070800781250, -0.0174255371093750, +0.0046997070312500, -0.0167846679687500, -0.0029296875000000, -0.0180969238281250, +-0.0017089843750000, -0.0178833007812500, -0.0032958984375000, -0.0184936523437500, +-0.0084228515625000, -0.0196228027343750, -0.0050964355468750, -0.0189514160156250, +-0.0114440917968750, -0.0203857421875000, -0.0102844238281250, -0.0207824707031250, +-0.0115051269531250, -0.0204162597656250, -0.0157470703125000, -0.0209655761718750, +-0.0128479003906250, -0.0212097167968750, -0.0183410644531250, -0.0192565917968750, +-0.0173645019531250, -0.0203552246093750, -0.0181884765625000, -0.0188903808593750, +-0.0219421386718750, -0.0166015625000000, -0.0196228027343750, -0.0183715820312500, +-0.0224609375000000, -0.0141296386718750, -0.0221557617187500, -0.0143737792968750, +-0.0220031738281250, -0.0137939453125000, -0.0234375000000000, -0.0107116699218750, +-0.0219726562500000, -0.0114746093750000, -0.0216064453125000, -0.0109252929687500, +-0.0225219726562500, -0.0099792480468750, -0.0197143554687500, -0.0104980468750000, +-0.0175170898437500, -0.0111083984375000, -0.0191040039062500, -0.0108032226562500, +-0.0119018554687500, -0.0119934082031250, -0.0129394531250000, -0.0119934082031250, +-0.0109863281250000, -0.0125122070312500, -0.0054931640625000, -0.0137939453125000, +-0.0075988769531250, -0.0137634277343750, -0.0021362304687500, -0.0140380859375000, +-0.0019836425781250, -0.0148620605468750, -0.0016479492187500, -0.0146484375000000, +0.0017089843750000, -0.0137023925781250, 0.0007629394531250, -0.0141906738281250, +0.0000000000000000, -0.0158081054687500, 0.0013732910156250, -0.0140075683593750, +-0.0006103515625000, -0.0159606933593750, -0.0031738281250000, -0.0186767578125000, +-0.0016174316406250, -0.0164489746093750, -0.0050659179687500, -0.0224914550781250, +-0.0055847167968750, -0.0208740234375000, -0.0058593750000000, -0.0231628417968750, +-0.0076599121093750, -0.0288391113281250, -0.0073242187500000, -0.0257263183593750, +-0.0076904296875000, -0.0302124023437500, -0.0086364746093750, -0.0314025878906250, +-0.0070800781250000, -0.0313720703125000, -0.0061035156250000, -0.0319519042968750, +-0.0071716308593750, -0.0315551757812500, -0.0015258789062500, -0.0371398925781250, +-0.0026550292968750, -0.0346374511718750, -0.0001220703125000, -0.0374755859375000, +0.0052795410156250, -0.0440979003906250, 0.0028991699218750, -0.0403747558593750, +0.0068664550781250, -0.0434875488281250, 0.0079956054687500, -0.0463256835937500, +0.0071105957031250, -0.0403137207031250, 0.0080261230468750, -0.0377197265625000, +0.0080871582031250, -0.0419006347656250, 0.0058898925781250, -0.0249938964843750, +0.0063171386718750, -0.0279541015625000, 0.0049438476562500, -0.0236816406250000, +0.0033569335937500, -0.0104370117187500, 0.0047607421875000, -0.0172119140625000, +-0.0008850097656250, -0.0105895996093750, -0.0003051757812500, -0.0068359375000000, +-0.0001220703125000, -0.0104675292968750, -0.0033569335937500, -0.0136108398437500, +-0.0028076171875000, -0.0115356445312500, -0.0028991699218750, -0.0065612792968750, +-0.0020141601562500, -0.0105895996093750, -0.0037231445312500, -0.0078430175781250, +-0.0055541992187500, -0.0010681152343750, -0.0039062500000000, -0.0042419433593750, +-0.0065612792968750, 0.0026550292968750, -0.0064086914062500, 0.0027465820312500, +-0.0068969726562500, 0.0021362304687500, -0.0089416503906250, 0.0049133300781250, +-0.0078735351562500, 0.0043029785156250, -0.0072326660156250, 0.0061340332031250, +-0.0076293945312500, 0.0039062500000000, -0.0078430175781250, 0.0086364746093750, +-0.0073547363281250, 0.0137023925781250, -0.0067443847656250, 0.0079956054687500, +-0.0072326660156250, 0.0155334472656250, -0.0077819824218750, 0.0189819335937500, +-0.0063781738281250, 0.0151367187500000, -0.0060424804687500, 0.0141906738281250, +-0.0072021484375000, 0.0154418945312500, -0.0014038085937500, 0.0070800781250000, +-0.0016479492187500, 0.0093688964843750, -0.0035400390625000, 0.0067443847656250, +-0.0017089843750000, -0.0022583007812500, -0.0030212402343750, -0.0009460449218750, +-0.0099487304687500, -0.0045776367187500, -0.0082092285156250, -0.0044555664062500, +-0.0071105957031250, -0.0032043457031250, -0.0117492675781250, -0.0047302246093750, +-0.0111083984375000, -0.0050659179687500, -0.0045166015625000, -0.0029296875000000, +-0.0067443847656250, -0.0027465820312500, -0.0055847167968750, -0.0036315917968750, +0.0009155273437500, -0.0024719238281250, -0.0006103515625000, -0.0021667480468750, +-0.0025939941406250, -0.0082397460937500, -0.0022583007812500, -0.0074157714843750, +0.0022583007812500, -0.0070190429687500, 0.0021972656250000, -0.0107727050781250, +-0.0017395019531250, -0.0102844238281250, 0.0139465332031250, -0.0077209472656250, +0.0146179199218750, -0.0095825195312500, 0.0112915039062500, -0.0057067871093750, +0.0181884765625000, -0.0003051757812500, 0.0188293457031250, -0.0037841796875000, +0.0050659179687500, 0.0000305175781250, 0.0090332031250000, 0.0022583007812500, +0.0063476562500000, 0.0007629394531250, -0.0057373046875000, 0.0000610351562500, +-0.0016174316406250, 0.0011596679687500, -0.0032653808593750, 0.0007629394531250, +-0.0063171386718750, -0.0004882812500000, -0.0027465820312500, 0.0029602050781250, +0.0009765625000000, 0.0061950683593750, -0.0020751953125000, 0.0036926269531250, +-0.0007629394531250, 0.0074768066406250, 0.0024108886718750, 0.0090942382812500, +-0.0018310546875000, 0.0084838867187500, -0.0054016113281250, 0.0089416503906250, +-0.0023498535156250, 0.0089416503906250, -0.0131225585937500, 0.0079040527343750, +-0.0116271972656250, 0.0085449218750000, -0.0135192871093750, 0.0083618164062500, +-0.0211791992187500, 0.0068664550781250, -0.0184020996093750, 0.0072631835937500, +-0.0238037109375000, 0.0085449218750000, -0.0237121582031250, 0.0082092285156250, +-0.0242919921875000, 0.0079956054687500, -0.0278930664062500, 0.0094909667968750, +-0.0265197753906250, 0.0095825195312500, -0.0275268554687500, 0.0046386718750000, +-0.0281677246093750, 0.0066833496093750, -0.0277099609375000, 0.0030212402343750, +-0.0275573730468750, -0.0034790039062500, -0.0278015136718750, -0.0003356933593750, +-0.0267639160156250, -0.0060729980468750, -0.0270996093750000, -0.0073547363281250, +-0.0258483886718750, -0.0062866210937500, -0.0247802734375000, -0.0077819824218750, +-0.0254516601562500, -0.0075378417968750, -0.0200195312500000, -0.0050354003906250, +-0.0215454101562500, -0.0055236816406250, -0.0192871093750000, -0.0038452148437500, +-0.0134887695312500, -0.0010681152343750, -0.0161437988281250, -0.0021667480468750, +-0.0146789550781250, 0.0001525878906250, -0.0119018554687500, 0.0007324218750000, +-0.0148925781250000, 0.0004577636718750, -0.0175781250000000, 0.0012817382812500, +-0.0142211914062500}, +{-0.0069580078125000, 0.0146789550781250, -0.0042419433593750, 0.0100402832031250, +-0.0108947753906250, 0.0185241699218750, -0.0116271972656250, 0.0188293457031250, +-0.0096435546875000, 0.0172119140625000, -0.0113525390625000, 0.0216369628906250, +-0.0116271972656250, 0.0216674804687500, -0.0076904296875000, 0.0153198242187500, +-0.0079650878906250, 0.0174865722656250, -0.0076293945312500, 0.0132141113281250, +-0.0049133300781250, 0.0070495605468750, -0.0050354003906250, 0.0117187500000000, +-0.0059814453125000, 0.0001220703125000, -0.0064392089843750, -0.0007019042968750, +-0.0043029785156250, 0.0003356933593750, -0.0019836425781250, -0.0046997070312500, +-0.0022583007812500, -0.0040588378906250, -0.0007324218750000, -0.0016784667968750, +-0.0003967285156250, -0.0024719238281250, -0.0008239746093750, -0.0030517578125000, +-0.0006713867187500, -0.0012512207031250, -0.0002746582031250, -0.0011291503906250, +0.0004272460937500, -0.0049133300781250, -0.0013427734375000, -0.0033264160156250, +0.0021057128906250, -0.0061035156250000, 0.0058593750000000, -0.0111999511718750, +0.0025024414062500, -0.0081481933593750, 0.0082397460937500, -0.0104064941406250, +0.0099487304687500, -0.0123596191406250, 0.0077819824218750, -0.0102539062500000, +0.0069885253906250, -0.0090942382812500, 0.0084228515625000, -0.0098876953125000, +0.0122375488281250, -0.0035400390625000, 0.0083312988281250, -0.0043945312500000, +0.0126647949218750, -0.0041503906250000, 0.0209960937500000, -0.0002136230468750, +0.0166320800781250, -0.0006713867187500, 0.0190734863281250, 0.0018005371093750, +0.0236816406250000, 0.0007019042968750, 0.0163269042968750, 0.0026245117187500, +0.0107727050781250, 0.0061340332031250, 0.0166320800781250, 0.0044860839843750, +0.0008544921875000, 0.0078430175781250, 0.0015563964843750, 0.0088195800781250, +0.0003356933593750, 0.0071716308593750, -0.0099792480468750, 0.0072937011718750, +-0.0068969726562500, 0.0085754394531250, -0.0053405761718750, 0.0069580078125000, +-0.0075073242187500, 0.0061035156250000, -0.0075988769531250, 0.0069885253906250, +-0.0048828125000000, 0.0078430175781250, -0.0050354003906250, 0.0075988769531250, +-0.0101318359375000, 0.0070800781250000, -0.0076599121093750, 0.0080261230468750, +-0.0114440917968750, 0.0064086914062500, -0.0181579589843750, 0.0050354003906250, +-0.0141296386718750, 0.0063781738281250, -0.0195922851562500, 0.0004577636718750, +-0.0208129882812500, 0.0016174316406250, -0.0205078125000000, -0.0005187988281250, +-0.0219726562500000, -0.0059509277343750, -0.0213012695312500, -0.0033569335937500, +-0.0233459472656250, -0.0053100585937500, -0.0231018066406250, -0.0075683593750000, +-0.0229492187500000, -0.0040893554687500, -0.0242309570312500, -0.0012512207031250, +-0.0237121582031250, -0.0033569335937500, -0.0225219726562500, 0.0018310546875000, +-0.0234375000000000, 0.0029296875000000, -0.0217590332031250, 0.0020446777343750, +-0.0194702148437500, 0.0036010742187500, -0.0206909179687500, 0.0036926269531250, +-0.0174255371093750, 0.0003662109375000, -0.0178833007812500, 0.0016174316406250, +-0.0154113769531250, -0.0011901855468750, -0.0126647949218750, -0.0053100585937500, +-0.0148010253906250, -0.0029907226562500, -0.0058288574218750, -0.0087585449218750, +-0.0071716308593750, -0.0087890625000000, -0.0059204101562500, -0.0093688964843750, +0.0010986328125000, -0.0126342773437500, -0.0010070800781250, -0.0113830566406250, +-0.0021057128906250, -0.0133361816406250, 0.0011596679687500, -0.0138549804687500, +-0.0020141601562500, -0.0130615234375000, -0.0066223144531250, -0.0134887695312500, +-0.0033569335937500, -0.0136413574218750, -0.0077514648437500, -0.0106506347656250, +-0.0086059570312500, -0.0113830566406250, -0.0075378417968750, -0.0095520019531250, +-0.0083923339843750, -0.0063781738281250, -0.0084228515625000, -0.0078735351562500, +-0.0085754394531250, -0.0042114257812500, -0.0079345703125000, -0.0038452148437500, +-0.0090026855468750, -0.0036621093750000, -0.0099182128906250, -0.0020751953125000, +-0.0090026855468750, -0.0024108886718750, -0.0120849609375000, -0.0012207031250000, +-0.0114440917968750, -0.0014038085937500, -0.0130004882812500, -0.0003967285156250, +-0.0156860351562500, 0.0008544921875000, -0.0140075683593750, 0.0001220703125000, +-0.0187377929687500, 0.0028381347656250, -0.0182189941406250, 0.0023498535156250, +-0.0194702148437500, 0.0035705566406250, -0.0229187011718750, 0.0056762695312500, +-0.0211791992187500, 0.0042724609375000, -0.0241088867187500, 0.0079956054687500, +-0.0248718261718750, 0.0074462890625000, -0.0236511230468750, 0.0079650878906250, +-0.0244750976562500, 0.0104675292968750, -0.0249633789062500, 0.0091247558593750, +-0.0200500488281250, 0.0105285644531250, -0.0218505859375000, 0.0105590820312500, +-0.0187988281250000, 0.0103454589843750, -0.0134887695312500, 0.0108032226562500, +-0.0166931152343750, 0.0102844238281250, -0.0094299316406250, 0.0103454589843750, +-0.0094604492187500, 0.0101928710937500, -0.0088195800781250, 0.0093994140625000, +-0.0047607421875000, 0.0090637207031250, -0.0064086914062500, 0.0088500976562500, +-0.0037841796875000, 0.0061950683593750, -0.0036010742187500, 0.0072326660156250, +-0.0036315917968750, 0.0044250488281250, -0.0022277832031250, 0.0010681152343750, +-0.0025329589843750, 0.0034484863281250, -0.0022277832031250, -0.0041503906250000, +-0.0018310546875000, -0.0028991699218750, -0.0018005371093750, -0.0046997070312500, +-0.0015258789062500, -0.0103454589843750, -0.0015563964843750, -0.0071716308593750, +-0.0024719238281250, -0.0119018554687500, -0.0011291503906250, -0.0133972167968750, +-0.0034790039062500, -0.0116882324218750, -0.0057067871093750, -0.0128784179687500, +-0.0034790039062500, -0.0138244628906250, -0.0109558105468750, -0.0081481933593750, +-0.0098266601562500, -0.0110168457031250, -0.0118408203125000, -0.0064086914062500, +-0.0172119140625000, 0.0008850097656250, -0.0144653320312500, -0.0041809082031250, +-0.0211486816406250, 0.0057983398437500, -0.0202026367187500, 0.0063171386718750, +-0.0223388671875000, 0.0055236816406250, -0.0275573730468750, 0.0103149414062500, +-0.0245971679687500, 0.0089111328125000, -0.0299072265625000, 0.0053710937500000, +-0.0304260253906250, 0.0078125000000000, -0.0296020507812500, 0.0043945312500000, +-0.0314025878906250, -0.0009765625000000, -0.0311889648437500, 0.0016174316406250, +-0.0314331054687500, -0.0059204101562500, -0.0302124023437500, -0.0058288574218750, +-0.0330810546875000, -0.0062866210937500, -0.0354919433593750, -0.0113830566406250, +-0.0329895019531250, -0.0099487304687500, -0.0403442382812500, -0.0067443847656250, +-0.0406799316406250, -0.0094909667968750, -0.0391845703125000, -0.0056762695312500, +-0.0426635742187500, 0.0002136230468750, -0.0426940917968750, -0.0034484863281250, +-0.0361328125000000, 0.0024414062500000, -0.0385437011718750, 0.0042724609375000, +-0.0351867675781250, 0.0007934570312500, -0.0285339355468750, 0.0010681152343750, +-0.0319213867187500, 0.0025024414062500, -0.0234680175781250, -0.0077819824218750, +-0.0250244140625000, -0.0062866210937500, -0.0200805664062500, -0.0069274902343750, +-0.0124206542968750, -0.0142822265625000, -0.0178527832031250, -0.0126953125000000, +-0.0034179687500000, -0.0110778808593750, -0.0021057128906250, -0.0130615234375000, +-0.0051879882812500, -0.0102539062500000, -0.0003356933593750, -0.0066223144531250, +0.0005798339843750, -0.0087585449218750, -0.0041198730468750, -0.0036926269531250, +-0.0055236816406250, -0.0049438476562500, -0.0022277832031250, -0.0022888183593750, +-0.0021057128906250, 0.0041809082031250, -0.0042114257812500, 0.0011596679687500, +0.0057067871093750, -0.0004272460937500, 0.0040893554687500, 0.0006408691406250, +0.0054626464843750, 0.0032348632812500, 0.0135498046875000, 0.0026855468750000, +0.0107727050781250, 0.0008850097656250, 0.0072021484375000, 0.0103149414062500, +0.0102233886718750, 0.0088500976562500, 0.0079345703125000, 0.0091857910156250, +0.0010681152343750, 0.0171203613281250, 0.0036621093750000, 0.0159606933593750, +0.0102844238281250, 0.0080566406250000, 0.0051879882812500, 0.0092163085937500, +0.0096130371093750, 0.0111083984375000, 0.0257263183593750, 0.0069580078125000, +0.0281982421875000, 0.0187072753906250, 0.0118408203125000, 0.0205383300781250, +0.0166931152343750, 0.0225830078125000, 0.0169067382812500, 0.0209045410156250, +0.0106811523437500, 0.0182189941406250, 0.0099487304687500, 0.0188598632812500, +0.0098876953125000, 0.0189514160156250, 0.0133972167968750, 0.0187683105468750, +0.0069274902343750, 0.0185241699218750, 0.0012207031250000, 0.0199890136718750, +0.0065002441406250, 0.0190429687500000, -0.0105895996093750, 0.0079956054687500, +-0.0092163085937500, 0.0150146484375000, -0.0104370117187500, 0.0054321289062500, +-0.0210266113281250, -0.0120849609375000, -0.0168151855468750, -0.0029907226562500, +-0.0184326171875000, -0.0157470703125000, -0.0216369628906250, -0.0183410644531250, +-0.0184326171875000, -0.0178527832031250, -0.0140991210937500, -0.0217895507812500, +-0.0162048339843750, -0.0198364257812500, -0.0173339843750000, -0.0234985351562500, +-0.0163879394531250, -0.0243835449218750, -0.0138549804687500, -0.0219726562500000, +-0.0148010253906250, -0.0221862792968750, -0.0163879394531250, -0.0236816406250000, +-0.0038452148437500, -0.0182495117187500, -0.0071411132812500, -0.0180053710937500, +-0.0031738281250000, -0.0185546875000000, 0.0074462890625000, -0.0158691406250000, +0.0025939941406250, -0.0165405273437500, 0.0139160156250000, -0.0200805664062500, +0.0144348144531250, -0.0172729492187500, 0.0103454589843750, -0.0220031738281250, +0.0151367187500000, -0.0289916992187500, 0.0170898437500000, -0.0244140625000000, +0.0042724609375000, -0.0303955078125000, 0.0060119628906250, -0.0335693359375000, +0.0043640136718750, -0.0289306640625000, -0.0037536621093750, -0.0270385742187500, +-0.0002136230468750, -0.0296936035156250, -0.0048522949218750, -0.0220336914062500, +-0.0065917968750000, -0.0218200683593750, -0.0030212402343750, -0.0215148925781250, +-0.0034790039062500, -0.0182189941406250, -0.0058288574218750, -0.0193176269531250, +0.0050354003906250, -0.0153503417968750, 0.0025329589843750, -0.0167846679687500, +0.0042724609375000, -0.0140380859375000, 0.0128479003906250, -0.0093994140625000, +0.0090332031250000, -0.0121765136718750, 0.0105590820312500, -0.0065307617187500, +0.0130615234375000, -0.0060729980468750, 0.0100402832031250, -0.0061950683593750, +0.0079040527343750, -0.0039978027343750, 0.0097045898437500, -0.0047607421875000, +0.0019226074218750, -0.0029296875000000, 0.0041809082031250, -0.0031433105468750, +0.0001831054687500, -0.0029296875000000, -0.0077209472656250, -0.0014953613281250, +-0.0028076171875000, -0.0020446777343750, -0.0108642578125000, -0.0021362304687500, +-0.0127868652343750, -0.0019531250000000, -0.0097351074218750, -0.0021057128906250, +-0.0111999511718750, -0.0027160644531250, -0.0123901367187500, -0.0028686523437500, +-0.0051269531250000, -0.0025024414062500, -0.0074157714843750, -0.0024414062500000, +-0.0045471191406250, -0.0032653808593750, 0.0020446777343750, -0.0032348632812500, +-0.0018615722656250, -0.0026245117187500, 0.0049743652343750, -0.0058898925781250, +0.0052490234375000, -0.0049743652343750, 0.0050964355468750, -0.0062255859375000, +0.0084533691406250, -0.0089721679687500, 0.0073242187500000, -0.0073242187500000, +0.0074157714843750, -0.0112915039062500, 0.0084838867187500, -0.0105590820312500, +0.0072326660156250, -0.0118408203125000, 0.0062561035156250, -0.0150756835937500, +0.0074462890625000, -0.0131530761718750, 0.0036315917968750, -0.0165100097656250, +0.0050659179687500}, +{0.0160522460937500, 0.0253601074218750, 0.0165405273437500, 0.0183105468750000, +0.0111389160156250, 0.0210876464843750, 0.0103759765625000, 0.0322570800781250, +0.0153198242187500, 0.0303344726562500, -0.0032653808593750, 0.0224609375000000, +-0.0020751953125000, 0.0263977050781250, -0.0025329589843750, 0.0216979980468750, +-0.0137634277343750, 0.0108032226562500, -0.0104370117187500, 0.0156860351562500, +-0.0071716308593750, 0.0163879394531250, -0.0096740722656250, 0.0132446289062500, +-0.0088806152343750, 0.0111999511718750, -0.0039672851562500, 0.0156555175781250, +-0.0050354003906250, 0.0173645019531250, -0.0106201171875000, -0.0028076171875000, +-0.0068969726562500, 0.0025024414062500, -0.0108337402343750, -0.0048828125000000, +-0.0211486816406250, -0.0234069824218750, -0.0159912109375000, -0.0146789550781250, +-0.0078125000000000, -0.0275878906250000, -0.0168762207031250, -0.0305786132812500, +-0.0058593750000000, -0.0267639160156250, 0.0117492675781250, -0.0294189453125000, +0.0009155273437500, -0.0302734375000000, 0.0162963867187500, -0.0241394042968750, +0.0212402343750000, -0.0238952636718750, 0.0140991210937500, -0.0250244140625000, +0.0157165527343750, -0.0229187011718750, 0.0184631347656250, -0.0225219726562500, +-0.0010681152343750, -0.0242004394531250, 0.0033874511718750, -0.0246887207031250, +-0.0000610351562500, -0.0244750976562500, -0.0169982910156250, -0.0238037109375000, +-0.0111999511718750, -0.0240478515625000, -0.0093078613281250, -0.0290222167968750, +-0.0145568847656250, -0.0270996093750000, -0.0086364746093750, -0.0287475585937500, +-0.0018005371093750, -0.0350341796875000, -0.0070495605468750, -0.0329895019531250, +0.0071411132812500, -0.0289611816406250, 0.0060119628906250, -0.0331726074218750, +0.0059509277343750, -0.0275573730468750, 0.0149536132812500, -0.0190124511718750, +0.0122985839843750, -0.0238342285156250, 0.0081176757812500, -0.0141601562500000, +0.0118713378906250, -0.0136108398437500, 0.0076293945312500, -0.0126953125000000, +0.0006408691406250, -0.0083312988281250, 0.0049438476562500, -0.0104370117187500, +-0.0024719238281250, -0.0030822753906250, -0.0029907226562500, -0.0046691894531250, +-0.0031738281250000, -0.0018615722656250, -0.0065917968750000, 0.0049743652343750, +-0.0050354003906250, 0.0015869140625000, -0.0070495605468750, 0.0071411132812500, +-0.0081176757812500, 0.0081176757812500, -0.0057067871093750, 0.0072021484375000, +-0.0050659179687500, 0.0088500976562500, -0.0068054199218750, 0.0084838867187500, +-0.0011901855468750, 0.0073242187500000, -0.0011901855468750, 0.0078735351562500, +-0.0016479492187500, 0.0063171386718750, 0.0011901855468750, 0.0045166015625000, +0.0007324218750000, 0.0057678222656250, -0.0009765625000000, 0.0025024414062500, +0.0005798339843750, 0.0023803710937500, -0.0011291503906250, 0.0027160644531250, +-0.0033874511718750, 0.0016479492187500, -0.0012207031250000, 0.0018310546875000, +-0.0063171386718750, 0.0007019042968750, -0.0053405761718750, 0.0020141601562500, +-0.0064392089843750, -0.0004577636718750, -0.0101318359375000, -0.0030212402343750, +-0.0079345703125000, -0.0007019042968750, -0.0114746093750000, -0.0075378417968750, +-0.0116882324218750, -0.0069885253906250, -0.0113525390625000, -0.0083618164062500, +-0.0131835937500000, -0.0126647949218750, -0.0129394531250000, -0.0107421875000000, +-0.0115661621093750, -0.0162353515625000, -0.0130615234375000, -0.0156555175781250, +-0.0113830566406250, -0.0173645019531250, -0.0090942382812500, -0.0219421386718750, +-0.0111694335937500, -0.0200195312500000, -0.0062561035156250, -0.0228576660156250, +-0.0072937011718750, -0.0240478515625000, -0.0062255859375000, -0.0231323242187500, +-0.0029602050781250, -0.0232238769531250, -0.0055236816406250, -0.0237731933593750, +-0.0017395019531250, -0.0229797363281250, -0.0028686523437500, -0.0225219726562500, +-0.0018005371093750, -0.0232238769531250, 0.0010375976562500, -0.0234069824218750, +-0.0015563964843750, -0.0227661132812500, 0.0030822753906250, -0.0237731933593750, +0.0022888183593750, -0.0241394042968750, 0.0029296875000000, -0.0229492187500000, +0.0061645507812500, -0.0227661132812500, 0.0040893554687500, -0.0234985351562500, +0.0061950683593750, -0.0200195312500000, 0.0059509277343750, -0.0211791992187500, +0.0049438476562500, -0.0193481445312500, 0.0054626464843750, -0.0164489746093750, +0.0048522949218750, -0.0185852050781250, 0.0030517578125000, -0.0112915039062500, +0.0035095214843750, -0.0132446289062500, 0.0021362304687500, -0.0100097656250000, +0.0001831054687500, -0.0029602050781250, 0.0010070800781250, -0.0067138671875000, +-0.0024414062500000, 0.0001831054687500, -0.0018310546875000, 0.0012817382812500, +-0.0027770996093750, 0.0007324218750000, -0.0056457519531250, 0.0036315917968750, +-0.0042419433593750, 0.0033264160156250, -0.0056152343750000, 0.0018615722656250, +-0.0062866210937500, 0.0038452148437500, -0.0054321289062500, 0.0012817382812500, +-0.0051879882812500, -0.0022583007812500, -0.0054626464843750, 0.0005187988281250, +-0.0041198730468750, -0.0046997070312500, -0.0039367675781250, -0.0056457519531250, +-0.0039672851562500, -0.0053405761718750, -0.0031433105468750, -0.0065307617187500, +-0.0030822753906250, -0.0065917968750000, -0.0042724609375000, -0.0105895996093750, +-0.0032653808593750, -0.0084838867187500, -0.0047912597656250, -0.0115356445312500, +-0.0066833496093750, -0.0171508789062500, -0.0050354003906250, -0.0141906738281250, +-0.0100402832031250, -0.0191650390625000, -0.0095825195312500, -0.0191650390625000, +-0.0104980468750000, -0.0208740234375000, -0.0142211914062500, -0.0240783691406250, +-0.0130310058593750, -0.0213928222656250, -0.0141296386718750, -0.0262756347656250, +-0.0153198242187500, -0.0279235839843750, -0.0133666992187500, -0.0249328613281250, +-0.0123901367187500, -0.0246887207031250, -0.0136718750000000, -0.0267333984375000, +-0.0077819824218750, -0.0218200683593750, -0.0088195800781250, -0.0222473144531250, +-0.0064697265625000, -0.0208435058593750, -0.0016784667968750, -0.0166625976562500, +-0.0042419433593750, -0.0195007324218750, 0.0016174316406250, -0.0212707519531250, +0.0014038085937500, -0.0172119140625000, 0.0022277832031250, -0.0208435058593750, +0.0057983398437500, -0.0282287597656250, 0.0040283203125000, -0.0245666503906250, +0.0066223144531250, -0.0228271484375000, 0.0063476562500000, -0.0279235839843750, +0.0071411132812500, -0.0198364257812500, 0.0090332031250000, -0.0114135742187500, +0.0075378417968750, -0.0182189941406250, 0.0100097656250000, -0.0007629394531250, +0.0107116699218750, -0.0007019042968750, 0.0091857910156250, 0.0001220703125000, +0.0094299316406250, 0.0101013183593750, 0.0103454589843750, 0.0063476562500000, +0.0062255859375000, 0.0055236816406250, 0.0069274902343750, 0.0086975097656250, +0.0054321289062500, 0.0075988769531250, 0.0024108886718750, 0.0043029785156250, +0.0042419433593750, 0.0051574707031250, -0.0003356933593750, 0.0033569335937500, +0.0003662109375000, 0.0042724609375000, -0.0014343261718750, 0.0036315917968750, +-0.0051269531250000, 0.0020751953125000, -0.0025634765625000, 0.0032958984375000, +-0.0072631835937500, -0.0007324218750000, -0.0075073242187500, -0.0009460449218750, +-0.0078430175781250, 0.0008544921875000, -0.0105895996093750, 0.0003967285156250, +-0.0091247558593750, -0.0006408691406250, -0.0071716308593750, -0.0000305175781250, +-0.0093383789062500, 0.0013427734375000, -0.0065917968750000, 0.0002746582031250, +-0.0012817382812500, -0.0014953613281250, -0.0013427734375000, -0.0010070800781250, +0.0032653808593750, -0.0016174316406250, 0.0021667480468750, -0.0018615722656250, +0.0016784667968750, -0.0019836425781250, 0.0048217773437500, -0.0015563964843750, +0.0047302246093750, -0.0008544921875000, 0.0035705566406250, -0.0032653808593750, +0.0029602050781250, -0.0024414062500000, 0.0058898925781250, -0.0029907226562500, +0.0067749023437500, -0.0052185058593750, 0.0045166015625000, -0.0036315917968750, +0.0144958496093750, -0.0027465820312500, 0.0135803222656250, -0.0038146972656250, +0.0120544433593750, -0.0031738281250000, 0.0181579589843750, -0.0010070800781250, +0.0178527832031250, -0.0008850097656250, 0.0086669921875000, -0.0014343261718750, +0.0111694335937500, -0.0011596679687500, 0.0099792480468750, -0.0016784667968750, +0.0018005371093750, -0.0020141601562500, 0.0033874511718750, -0.0008544921875000, +0.0060119628906250, -0.0027465820312500, 0.0049133300781250, -0.0036621093750000, +0.0032348632812500, -0.0014343261718750, 0.0050048828125000, -0.0002746582031250, +0.0058898925781250, -0.0016174316406250, -0.0019226074218750, 0.0018615722656250, +0.0001831054687500, 0.0025939941406250, -0.0010070800781250, 0.0009460449218750, +-0.0071716308593750, 0.0016479492187500, -0.0052185058593750, 0.0027465820312500, +-0.0088500976562500, -0.0021972656250000, -0.0078735351562500, -0.0023803710937500, +-0.0096130371093750, -0.0011901855468750, -0.0138244628906250, -0.0032653808593750, +-0.0118408203125000, -0.0033874511718750, -0.0137939453125000, 0.0014038085937500, +-0.0149230957031250, -0.0001220703125000, -0.0131530761718750, 0.0017089843750000, +-0.0126647949218750, 0.0067443847656250, -0.0139160156250000, 0.0045166015625000, +-0.0098266601562500, 0.0046691894531250, -0.0092773437500000, 0.0069580078125000, +-0.0105590820312500, 0.0031127929687500, -0.0094909667968750, -0.0003662109375000, +-0.0086364746093750, 0.0024719238281250, -0.0109863281250000, -0.0063781738281250, +-0.0106811523437500, -0.0065917968750000, -0.0103759765625000, -0.0065307617187500, +-0.0115356445312500, -0.0112304687500000, -0.0109558105468750, -0.0103149414062500, +-0.0093383789062500, -0.0090637207031250, -0.0099792480468750, -0.0099487304687500, +-0.0087585449218750, -0.0089111328125000, -0.0065002441406250, -0.0070800781250000, +-0.0071411132812500, -0.0079650878906250, -0.0056457519531250, -0.0062561035156250, +-0.0054931640625000, -0.0058288574218750, -0.0044250488281250, -0.0070190429687500, +-0.0032348632812500, -0.0069580078125000, -0.0042114257812500, -0.0066223144531250, +-0.0014953613281250, -0.0101013183593750, -0.0013427734375000, -0.0095825195312500, +-0.0015563964843750, -0.0104675292968750, -0.0006103515625000, -0.0133056640625000, +-0.0007629394531250, -0.0123596191406250, -0.0003051757812500, -0.0136718750000000, +-0.0008850097656250, -0.0138549804687500, -0.0001525878906250, -0.0136718750000000, +0.0010986328125000, -0.0140075683593750, -0.0000915527343750, -0.0133666992187500, +-0.0004882812500000, -0.0125732421875000, 0.0013732910156250, -0.0126953125000000, +-0.0025024414062500, -0.0107116699218750, -0.0058593750000000, -0.0089416503906250, +-0.0028686523437500, -0.0094909667968750, -0.0129699707031250, -0.0052795410156250, +-0.0119934082031250, -0.0050659179687500, -0.0137329101562500, -0.0037231445312500, +-0.0205078125000000, -0.0006713867187500, -0.0178222656250000, -0.0014648437500000, +-0.0217590332031250, 0.0003967285156250, -0.0223693847656250, 0.0012512207031250, +-0.0223999023437500, 0.0011596679687500, -0.0243225097656250, 0.0018310546875000, +-0.0236206054687500, 0.0022277832031250, -0.0238647460937500, 0.0011901855468750, +-0.0247192382812500, 0.0020141601562500, -0.0231323242187500, 0.0016479492187500, +-0.0219726562500000, 0.0006408691406250, -0.0231628417968750, 0.0018615722656250, +-0.0190734863281250, 0.0004577636718750, -0.0194091796875000, 0.0008239746093750, +-0.0189208984375000, 0.0007324218750000, -0.0162963867187500, -0.0001220703125000, +-0.0171813964843750, 0.0005798339843750, -0.0160522460937500, -0.0006408691406250, +-0.0159912109375000, -0.0002136230468750, -0.0158691406250000, -0.0003967285156250, +-0.0155334472656250}, +{0.0081176757812500, -0.0011596679687500, 0.0014953613281250, -0.0016479492187500, +0.0081481933593750, -0.0014343261718750, -0.0032043457031250, 0.0000915527343750, +-0.0068664550781250, 0.0005187988281250, -0.0029296875000000, -0.0009765625000000, +-0.0028381347656250, -0.0011596679687500, -0.0047607421875000, -0.0000610351562500, +-0.0031433105468750, -0.0039062500000000, -0.0004272460937500, -0.0038757324218750, +-0.0051269531250000, -0.0029296875000000, -0.0090942382812500, -0.0050048828125000, +-0.0048217773437500, -0.0051879882812500, -0.0115661621093750, -0.0003662109375000, +-0.0135498046875000, -0.0016174316406250, -0.0118408203125000, -0.0002441406250000, +-0.0124816894531250, 0.0041503906250000, -0.0127258300781250, 0.0021057128906250, +-0.0111999511718750, 0.0024414062500000, -0.0114135742187500, 0.0043945312500000, +-0.0119628906250000, 0.0008850097656250, -0.0113830566406250, -0.0026550292968750, +-0.0106811523437500, -0.0003967285156250, -0.0110778808593750, -0.0052185058593750, +-0.0123291015625000, -0.0062255859375000, -0.0097351074218750, -0.0053710937500000, +-0.0073547363281250, -0.0067749023437500, -0.0092468261718750, -0.0071716308593750, +-0.0048522949218750, -0.0051574707031250, -0.0045166015625000, -0.0052185058593750, +-0.0041809082031250, -0.0057067871093750, -0.0017089843750000, -0.0045471191406250, +-0.0021362304687500, -0.0045776367187500, -0.0019836425781250, -0.0079650878906250, +-0.0010681152343750, -0.0073242187500000, -0.0010375976562500, -0.0087585449218750, +-0.0014038085937500, -0.0118103027343750, -0.0012512207031250, -0.0105590820312500, +-0.0016479492187500, -0.0130615234375000, -0.0009460449218750, -0.0136108398437500, +-0.0023193359375000, -0.0129394531250000, -0.0038452148437500, -0.0139160156250000, +-0.0025329589843750, -0.0140380859375000, -0.0047607421875000, -0.0107116699218750, +-0.0052795410156250, -0.0116577148437500, -0.0046081542968750, -0.0097045898437500, +-0.0049743652343750, -0.0059204101562500, -0.0053405761718750, -0.0072021484375000, +-0.0047912597656250, -0.0036926269531250, -0.0046386718750000, -0.0028991699218750, +-0.0051879882812500, -0.0026245117187500, -0.0054321289062500, -0.0009765625000000, +-0.0053710937500000, -0.0009460449218750, -0.0063476562500000, -0.0006408691406250, +-0.0062866210937500, 0.0000305175781250, -0.0074768066406250, -0.0008544921875000, +-0.0083618164062500, -0.0014038085937500, -0.0080261230468750, -0.0004882812500000, +-0.0134277343750000, -0.0032958984375000, -0.0117187500000000, -0.0028686523437500, +-0.0151977539062500, -0.0034790039062500, -0.0212097167968750, -0.0056457519531250, +-0.0176391601562500, -0.0047607421875000, -0.0246276855468750, -0.0065002441406250, +-0.0254821777343750, -0.0069274902343750, -0.0239257812500000, -0.0067443847656250, +-0.0262145996093750, -0.0072937011718750, -0.0263061523437500, -0.0074157714843750, +-0.0227050781250000, -0.0071105957031250, -0.0233459472656250, -0.0078735351562500, +-0.0225219726562500, -0.0079040527343750, -0.0196228027343750, -0.0074462890625000, +-0.0207214355468750, -0.0081787109375000, -0.0199279785156250, -0.0083007812500000, +-0.0191345214843750, -0.0083618164062500, -0.0199584960937500, -0.0085754394531250, +-0.0206298828125000, -0.0089111328125000, -0.0199890136718750, -0.0089721679687500, +-0.0209045410156250, -0.0082092285156250, -0.0211791992187500, -0.0089111328125000, +-0.0208435058593750, -0.0082092285156250, -0.0211791992187500, -0.0071716308593750, +-0.0212707519531250, -0.0081787109375000, -0.0195312500000000, -0.0061645507812500, +-0.0205078125000000, -0.0065307617187500, -0.0187988281250000, -0.0059204101562500, +-0.0162658691406250, -0.0045471191406250, -0.0180358886718750, -0.0056152343750000, +-0.0142211914062500, -0.0027160644531250, -0.0140075683593750, -0.0032958984375000, +-0.0144042968750000, -0.0031738281250000, -0.0130004882812500, -0.0010681152343750, +-0.0134887695312500, -0.0020141601562500, -0.0130615234375000, -0.0020751953125000, +-0.0134887695312500, -0.0011596679687500, -0.0131225585937500, -0.0024108886718750, +-0.0126037597656250, -0.0031127929687500, -0.0132141113281250, -0.0016784667968750, +-0.0111389160156250, -0.0069885253906250, -0.0118408203125000, -0.0051879882812500, +-0.0101928710937500, -0.0077819824218750, -0.0079345703125000, -0.0130615234375000, +-0.0094299316406250, -0.0101013183593750, -0.0038757324218750, -0.0168457031250000, +-0.0039062500000000, -0.0163574218750000, -0.0036010742187500, -0.0157470703125000, +0.0000000000000000, -0.0198059082031250, -0.0007324218750000, -0.0186767578125000, +-0.0024414062500000, -0.0156250000000000, -0.0007629394531250, -0.0177001953125000, +-0.0029296875000000, -0.0149230957031250, -0.0062255859375000, -0.0106506347656250, +-0.0042419433593750, -0.0135803222656250, -0.0082702636718750, -0.0075988769531250, +-0.0084838867187500, -0.0072021484375000, -0.0090026855468750, -0.0075988769531250, +-0.0111999511718750, -0.0051879882812500, -0.0102539062500000, -0.0057373046875000, +-0.0123901367187500, -0.0048217773437500, -0.0125427246093750, -0.0048217773437500, +-0.0119628906250000, -0.0056152343750000, -0.0131225585937500, -0.0054931640625000, +-0.0131835937500000, -0.0050048828125000, -0.0099182128906250, -0.0067749023437500, +-0.0112915039062500, -0.0077819824218750, -0.0096740722656250, -0.0053710937500000, +-0.0056457519531250, -0.0047607421875000, -0.0076293945312500, -0.0064392089843750, +-0.0072326660156250, 0.0024414062500000, -0.0054321289062500, 0.0018310546875000, +-0.0076904296875000, 0.0014648437500000, -0.0099487304687500, 0.0065612792968750, +-0.0085449218750000, 0.0052795410156250, -0.0137939453125000, 0.0014343261718750, +-0.0129089355468750, 0.0036926269531250, -0.0149536132812500, 0.0009765625000000, +-0.0200195312500000, -0.0043334960937500, -0.0177917480468750, -0.0024719238281250, +-0.0201721191406250, -0.0077514648437500, -0.0218811035156250, -0.0063171386718750, +-0.0193786621093750, -0.0090942382812500, -0.0189514160156250, -0.0156555175781250, +-0.0204162597656250, -0.0127563476562500, -0.0099182128906250, -0.0139465332031250, +-0.0132446289062500, -0.0172729492187500, -0.0087280273437500, -0.0115661621093750, +0.0017089843750000, -0.0064697265625000, -0.0035095214843750, -0.0116882324218750, +0.0054931640625000, -0.0038146972656250, 0.0069274902343750, -0.0011596679687500, +0.0053100585937500, -0.0025024414062500, 0.0075683593750000, -0.0025939941406250, +0.0078125000000000, -0.0032653808593750, 0.0093383789062500, 0.0002746582031250, +0.0071411132812500, -0.0019226074218750, 0.0099792480468750, 0.0033264160156250, +0.0151062011718750, 0.0096130371093750, 0.0121765136718750, 0.0043029785156250, +0.0115051269531250, 0.0133056640625000, 0.0142517089843750, 0.0152282714843750, +0.0121154785156250, 0.0136718750000000, 0.0059204101562500, 0.0167846679687500, +-0.0104980468750000, 0.0014343261718750, -0.0126953125000000, 0.0128784179687500, +-0.0158081054687500, 0.0109558105468750, -0.0108032226562500, 0.0099182128906250, +-0.0059814453125000, 0.0124511718750000, -0.0095214843750000, 0.0132446289062500, +-0.0047912597656250, 0.0127868652343750, -0.0037231445312500, 0.0112915039062500, +-0.0035095214843750, 0.0140686035156250, -0.0021972656250000, 0.0167236328125000, +-0.0027465820312500, 0.0140991210937500, 0.0015869140625000, 0.0185546875000000, +-0.0003662109375000, 0.0221557617187500, 0.0031127929687500, 0.0148620605468750, +0.0083007812500000, 0.0099792480468750, 0.0048522949218750, 0.0157165527343750, +0.0144653320312500, 0.0045776367187500, 0.0150146484375000, 0.0030517578125000, +0.0112915039062500, 0.0027770996093750, 0.0150451660156250, -0.0008850097656250, +0.0170288085937500, 0.0008239746093750, 0.0051574707031250, -0.0057373046875000, +0.0077209472656250, -0.0026550292968750, 0.0041198730468750, -0.0101928710937500, +-0.0061035156250000, -0.0189514160156250, -0.0010986328125000, -0.0117797851562500, +-0.0053405761718750, -0.0332641601562500, -0.0090942382812500, -0.0336608886718750, +-0.0047302246093750, -0.0316162109375000, -0.0019836425781250, -0.0426025390625000, +-0.0054016113281250, -0.0413818359375000, 0.0017700195312500, -0.0312500000000000, +0.0032653808593750, -0.0342407226562500, 0.0010375976562500, -0.0321350097656250, +0.0015258789062500, -0.0235595703125000, 0.0023803710937500, -0.0262756347656250, +0.0030517578125000, -0.0242919921875000, 0.0025329589843750, -0.0242309570312500, +0.0005187988281250, -0.0228271484375000, 0.0011596679687500, -0.0210876464843750, +0.0027465820312500, -0.0228271484375000, -0.0054321289062500, -0.0180053710937500, +-0.0039367675781250, -0.0180053710937500, -0.0055236816406250, -0.0184326171875000, +-0.0109558105468750, -0.0162353515625000, -0.0082702636718750, -0.0165405273437500, +-0.0150451660156250, -0.0169982910156250, -0.0136413574218750, -0.0176391601562500, +-0.0148010253906250, -0.0156860351562500, -0.0203857421875000, -0.0150146484375000, +-0.0177001953125000, -0.0166320800781250, -0.0179138183593750, -0.0087890625000000, +-0.0203857421875000, -0.0101318359375000, -0.0165710449218750, -0.0083312988281250, +-0.0131835937500000, -0.0021362304687500, -0.0161437988281250, -0.0045471191406250, +-0.0075683593750000, -0.0011596679687500, -0.0085754394531250, -0.0007934570312500, +-0.0060424804687500, -0.0001220703125000, -0.0000305175781250, 0.0016479492187500, +-0.0035705566406250, 0.0005798339843750, 0.0044250488281250, 0.0035705566406250, +0.0047302246093750, 0.0036010742187500, 0.0039978027343750, 0.0033874511718750, +0.0080261230468750, 0.0049743652343750, 0.0073852539062500, 0.0047912597656250, +0.0046081542968750, 0.0041503906250000, 0.0067138671875000, 0.0045471191406250, +0.0037841796875000, 0.0043334960937500, 0.0000610351562500, 0.0038452148437500, +0.0032043457031250, 0.0040283203125000, -0.0051879882812500, 0.0026245117187500, +-0.0032653808593750, 0.0033874511718750, -0.0062255859375000, 0.0018005371093750, +-0.0127563476562500, -0.0003662109375000, -0.0081481933593750, 0.0010070800781250, +-0.0168151855468750, -0.0029296875000000, -0.0157775878906250, -0.0028686523437500, +-0.0165405273437500, -0.0038146972656250, -0.0215148925781250, -0.0062866210937500, +-0.0184326171875000, -0.0052185058593750, -0.0238037109375000, -0.0090637207031250, +-0.0226135253906250, -0.0085449218750000, -0.0234069824218750, -0.0101623535156250, +-0.0272827148437500, -0.0133361816406250, -0.0248107910156250, -0.0115966796875000, +-0.0274963378906250, -0.0161743164062500, -0.0275268554687500, -0.0156860351562500, +-0.0263977050781250, -0.0165710449218750, -0.0268554687500000, -0.0197448730468750, +-0.0262451171875000, -0.0183105468750000, -0.0243835449218750, -0.0204467773437500, +-0.0243225097656250, -0.0209960937500000, -0.0229492187500000, -0.0207214355468750, +-0.0210571289062500, -0.0213317871093750, -0.0215148925781250, -0.0214843750000000, +-0.0188598632812500, -0.0215759277343750, -0.0187377929687500, -0.0220947265625000, +-0.0176391601562500, -0.0214538574218750, -0.0155639648437500, -0.0213317871093750, +-0.0159606933593750, -0.0222473144531250, -0.0128173828125000, -0.0184631347656250, +-0.0128173828125000, -0.0197448730468750, -0.0111694335937500, -0.0180358886718750, +-0.0084533691406250, -0.0142822265625000, -0.0093383789062500, -0.0162353515625000, +-0.0060424804687500, -0.0126647949218750, -0.0060729980468750, -0.0119323730468750, +-0.0046386718750000, -0.0122680664062500, -0.0021057128906250, -0.0105895996093750, +-0.0028991699218750, -0.0102844238281250, 0.0014648437500000, -0.0122985839843750, +0.0014343261718750, -0.0114746093750000, 0.0028381347656250, -0.0118408203125000, +0.0061645507812500, -0.0145263671875000, 0.0054626464843750, -0.0139770507812500, +0.0086975097656250}, +{0.0054016113281250, -0.0322265625000000, -0.0002136230468750, -0.0231933593750000, +0.0058288574218750, -0.0230407714843750, -0.0017089843750000, -0.0226745605468750, +-0.0133666992187500, -0.0184326171875000, -0.0060424804687500, -0.0199584960937500, +-0.0189819335937500, -0.0172729492187500, -0.0202026367187500, -0.0174865722656250, +-0.0185852050781250, -0.0170898437500000, -0.0241394042968750, -0.0152587890625000, +-0.0227050781250000, -0.0161132812500000, -0.0169067382812500, -0.0145263671875000, +-0.0210876464843750, -0.0142211914062500, -0.0153198242187500, -0.0150451660156250, +-0.0063476562500000, -0.0149230957031250, -0.0123596191406250, -0.0145874023437500, +-0.0014038085937500, -0.0161743164062500, -0.0002136230468750, -0.0169372558593750, +-0.0021057128906250, -0.0151367187500000, 0.0020751953125000, -0.0147705078125000, +0.0019531250000000, -0.0159912109375000, -0.0021667480468750, -0.0099792480468750, +0.0000610351562500, -0.0107421875000000, -0.0036315917968750, -0.0095214843750000, +-0.0080871582031250, -0.0051269531250000, -0.0042114257812500, -0.0067138671875000, +-0.0169372558593750, -0.0043945312500000, -0.0144042968750000, -0.0042419433593750, +-0.0176086425781250, -0.0037841796875000, -0.0271911621093750, -0.0022888183593750, +-0.0216064453125000, -0.0029907226562500, -0.0298461914062500, -0.0017395019531250, +-0.0294189453125000, -0.0012817382812500, -0.0296325683593750, -0.0018920898437500, +-0.0341491699218750, -0.0020141601562500, -0.0319213867187500, -0.0018005371093750, +-0.0349731445312500, -0.0029907226562500, -0.0350952148437500, -0.0029602050781250, +-0.0346069335937500, -0.0034484863281250, -0.0359497070312500, -0.0042419433593750, +-0.0355224609375000, -0.0038452148437500, -0.0351562500000000, -0.0049743652343750, +-0.0352783203125000, -0.0052795410156250, -0.0346984863281250, -0.0048828125000000, +-0.0341491699218750, -0.0052185058593750, -0.0344238281250000, -0.0054321289062500, +-0.0330810546875000, -0.0043945312500000, -0.0336608886718750, -0.0041198730468750, +-0.0326843261718750, -0.0050048828125000, -0.0312194824218750, -0.0048828125000000, +-0.0325012207031250, -0.0042114257812500, -0.0303039550781250, -0.0079345703125000, +-0.0301818847656250, -0.0070190429687500, -0.0299377441406250, -0.0086975097656250, +-0.0288696289062500, -0.0120544433593750, -0.0294799804687500, -0.0106201171875000, +-0.0284118652343750, -0.0152282714843750, -0.0284423828125000, -0.0151672363281250, +-0.0282592773437500, -0.0159301757812500, -0.0274353027343750, -0.0192565917968750, +-0.0275573730468750, -0.0181884765625000, -0.0265197753906250, -0.0182189941406250, +-0.0267028808593750, -0.0196533203125000, -0.0260925292968750, -0.0175476074218750, +-0.0251159667968750, -0.0151977539062500, -0.0254211425781250, -0.0169067382812500, +-0.0236206054687500, -0.0131225585937500, -0.0238647460937500, -0.0123291015625000, +-0.0231933593750000, -0.0132446289062500, -0.0216674804687500, -0.0118408203125000, +-0.0219116210937500, -0.0113525390625000, -0.0190124511718750, -0.0147399902343750, +-0.0190734863281250, -0.0131835937500000, -0.0181579589843750, -0.0149841308593750, +-0.0158081054687500, -0.0190124511718750, -0.0162353515625000, -0.0167236328125000, +-0.0146179199218750, -0.0193481445312500, -0.0139465332031250, -0.0214843750000000, +-0.0140380859375000, -0.0187988281250000, -0.0133056640625000, -0.0174560546875000, +-0.0124511718750000, -0.0198669433593750, -0.0126342773437500, -0.0145568847656250, +-0.0119934082031250, -0.0146179199218750, -0.0110778808593750, -0.0143737792968750, +-0.0109558105468750, -0.0116271972656250, -0.0103454589843750, -0.0127258300781250, +-0.0082397460937500, -0.0109558105468750, -0.0086364746093750, -0.0101623535156250, +-0.0060424804687500, -0.0117187500000000, -0.0030212402343750, -0.0117492675781250, +-0.0042114257812500, -0.0100097656250000, 0.0011596679687500, -0.0139465332031250, +0.0007629394531250, -0.0149841308593750, 0.0023193359375000, -0.0114746093750000, +0.0061950683593750, -0.0116577148437500, 0.0043640136718750, -0.0143127441406250, +0.0076599121093750, -0.0042114257812500, 0.0084533691406250, -0.0047607421875000, +0.0073852539062500, -0.0056762695312500, 0.0081481933593750, -0.0007324218750000, +0.0082702636718750, -0.0012817382812500, 0.0048217773437500, -0.0017395019531250, +0.0061035156250000, -0.0017395019531250, 0.0040283203125000, -0.0025024414062500, +-0.0003662109375000, -0.0019531250000000, 0.0018005371093750, -0.0011596679687500, +-0.0001220703125000, -0.0066528320312500, -0.0018615722656250, -0.0070800781250000, +-0.0003051757812500, -0.0029602050781250, 0.0009460449218750, -0.0040283203125000, +-0.0000305175781250, -0.0075988769531250, 0.0021972656250000, 0.0021972656250000, +0.0029907226562500, 0.0024108886718750, 0.0020751953125000, 0.0010375976562500, +0.0025024414062500, 0.0052490234375000, 0.0030212402343750, 0.0044860839843750, +-0.0001831054687500, 0.0003662109375000, 0.0010986328125000, 0.0028686523437500, +-0.0011596679687500, -0.0018615722656250, -0.0051269531250000, -0.0078430175781250, +-0.0025939941406250, -0.0028686523437500, -0.0062255859375000, -0.0126342773437500, +-0.0087280273437500, -0.0153503417968750, -0.0035095214843750, -0.0103759765625000, +-0.0007324218750000, -0.0098876953125000, -0.0047302246093750, -0.0127868652343750, +0.0045776367187500, -0.0088195800781250, 0.0057373046875000, -0.0068969726562500, +0.0048217773437500, -0.0095520019531250, 0.0081787109375000, -0.0102233886718750, +0.0072937011718750, -0.0082092285156250, 0.0047607421875000, -0.0135192871093750, +0.0061645507812500, -0.0151977539062500, 0.0044860839843750, -0.0115051269531250, +0.0008239746093750, -0.0114135742187500, 0.0024719238281250, -0.0135803222656250, +0.0021362304687500, -0.0033874511718750, 0.0005187988281250, -0.0052185058593750, +0.0021362304687500, -0.0039367675781250, 0.0045776367187500, 0.0039672851562500, +0.0034790039062500, 0.0016174316406250, 0.0032653808593750, 0.0016784667968750, +0.0043334960937500, 0.0036315917968750, 0.0036926269531250, 0.0009460449218750, +0.0020446777343750, -0.0030822753906250, 0.0022277832031250, -0.0023803710937500, +0.0024414062500000, -0.0038452148437500, 0.0016479492187500, -0.0044860839843750, +0.0022888183593750, -0.0036926269531250, 0.0036010742187500, -0.0039367675781250, +0.0025939941406250, -0.0043640136718750, 0.0020751953125000, -0.0007934570312500, +0.0031433105468750, -0.0021057128906250, 0.0017089843750000, -0.0001220703125000, +0.0000915527343750, 0.0039062500000000, 0.0011596679687500, 0.0017700195312500, +-0.0032043457031250, 0.0053100585937500, -0.0023803710937500, 0.0067749023437500, +-0.0043945312500000, 0.0044250488281250, -0.0083923339843750, 0.0034179687500000, +-0.0056762695312500, 0.0046691894531250, -0.0079650878906250, 0.0024414062500000, +-0.0106201171875000, 0.0017395019531250, -0.0073242187500000, 0.0021667480468750, +-0.0040893554687500, 0.0015258789062500, -0.0066528320312500, 0.0014343261718750, +-0.0042724609375000, 0.0035400390625000, -0.0019531250000000, 0.0032043457031250, +-0.0050048828125000, 0.0022277832031250, -0.0075683593750000, 0.0033569335937500, +-0.0050354003906250, 0.0036315917968750, -0.0072631835937500, -0.0009155273437500, +-0.0087890625000000, 0.0001220703125000, -0.0084533691406250, -0.0012512207031250, +-0.0082397460937500, -0.0055541992187500, -0.0083007812500000, -0.0041503906250000, +-0.0078430175781250, -0.0052490234375000, -0.0072021484375000, -0.0060119628906250, +-0.0090332031250000, -0.0057983398437500, -0.0103149414062500, -0.0059814453125000, +-0.0082702636718750, -0.0062561035156250, -0.0111083984375000, -0.0055541992187500, +-0.0117492675781250, -0.0053405761718750, -0.0101928710937500, -0.0068969726562500, +-0.0108947753906250, -0.0075073242187500, -0.0112609863281250, -0.0065612792968750, +-0.0046081542968750, -0.0100097656250000, -0.0064697265625000, -0.0106811523437500, +-0.0054016113281250, -0.0094909667968750, 0.0003356933593750, -0.0104064941406250, +-0.0013122558593750, -0.0110473632812500, -0.0009765625000000, -0.0064697265625000, +0.0000610351562500, -0.0076293945312500, -0.0008544921875000, -0.0057067871093750, +-0.0018615722656250, -0.0010681152343750, -0.0009155273437500, -0.0028991699218750, +-0.0014953613281250, -0.0003662109375000, -0.0025024414062500, 0.0006103515625000, +-0.0014343261718750, -0.0007934570312500, -0.0002136230468750, -0.0012512207031250, +-0.0014343261718750, -0.0009155273437500, -0.0014953613281250, -0.0032348632812500, +-0.0001831054687500, -0.0032958984375000, -0.0019531250000000, -0.0045471191406250, +-0.0039367675781250, -0.0063476562500000, -0.0026245117187500, -0.0054931640625000, +-0.0065917968750000, -0.0079956054687500, -0.0058898925781250, -0.0082092285156250, +-0.0078735351562500, -0.0086975097656250, -0.0114440917968750, -0.0104370117187500, +-0.0093994140625000, -0.0105285644531250, -0.0150451660156250, -0.0118408203125000, +-0.0149230957031250, -0.0121459960937500, -0.0158691406250000, -0.0133666992187500, +-0.0195312500000000, -0.0147094726562500, -0.0182495117187500, -0.0147094726562500, +-0.0202941894531250, -0.0178527832031250, -0.0212402343750000, -0.0176086425781250, +-0.0202941894531250, -0.0198974609375000, -0.0204772949218750, -0.0231323242187500, +-0.0211486816406250, -0.0220031738281250, -0.0179748535156250, -0.0269165039062500, +-0.0188293457031250, -0.0267944335937500, -0.0178222656250000, -0.0285339355468750, +-0.0149230957031250, -0.0321044921875000, -0.0163574218750000, -0.0304870605468750, +-0.0149841308593750, -0.0343933105468750, -0.0142517089843750, -0.0342712402343750, +-0.0153503417968750, -0.0351562500000000, -0.0156860351562500, -0.0374450683593750, +-0.0150146484375000, -0.0358581542968750, -0.0173034667968750, -0.0384826660156250, +-0.0167846679687500, -0.0378417968750000, -0.0173950195312500, -0.0378112792968750, +-0.0192871093750000, -0.0388488769531250, -0.0181579589843750, -0.0368652343750000, +-0.0189514160156250, -0.0382995605468750, -0.0195312500000000, -0.0369262695312500, +-0.0183410644531250, -0.0369262695312500, -0.0176391601562500, -0.0378112792968750, +-0.0182495117187500, -0.0359191894531250, -0.0161743164062500, -0.0390014648437500, +-0.0157470703125000, -0.0372924804687500, -0.0164794921875000, -0.0371398925781250, +-0.0158386230468750, -0.0390319824218750, -0.0153198242187500, -0.0365295410156250, +-0.0179443359375000, -0.0379943847656250, -0.0173645019531250, -0.0383300781250000, +-0.0178527832031250, -0.0366210937500000, -0.0200195312500000, -0.0365600585937500, +-0.0191955566406250, -0.0375366210937500, -0.0195922851562500, -0.0344543457031250, +-0.0199890136718750, -0.0347290039062500, -0.0192260742187500, -0.0341796875000000, +-0.0188903808593750, -0.0318908691406250, -0.0191650390625000, -0.0324707031250000, +-0.0169067382812500, -0.0318908691406250, -0.0176086425781250, -0.0314941406250000, +-0.0161743164062500, -0.0320739746093750, -0.0136108398437500, -0.0325622558593750, +-0.0152893066406250, -0.0324096679687500, -0.0131225585937500, -0.0332336425781250, +-0.0124206542968750, -0.0336914062500000, -0.0137023925781250, -0.0323791503906250, +-0.0141906738281250, -0.0321655273437500, -0.0139465332031250, -0.0332641601562500, +-0.0149841308593750, -0.0286254882812500, -0.0160522460937500, -0.0309143066406250, +-0.0149536132812500, -0.0269470214843750, -0.0142517089843750, -0.0217895507812500, +-0.0154418945312500, -0.0265502929687500, -0.0123596191406250, -0.0144653320312500, +-0.0128173828125000, -0.0164184570312500, -0.0120544433593750, -0.0135192871093750, +-0.0101928710937500, -0.0044860839843750, -0.0114746093750000, -0.0091552734375000, +-0.0074157714843750, -0.0009460449218750, -0.0086669921875000, 0.0001831054687500, +-0.0064392089843750}, +{-0.0028686523437500, -0.0099792480468750, -0.0033569335937500, -0.0104370117187500, +-0.0047607421875000, -0.0111083984375000, -0.0043945312500000, -0.0118713378906250, +-0.0043945312500000, -0.0127563476562500, -0.0045471191406250, -0.0126037597656250, +-0.0057067871093750, -0.0139160156250000, -0.0061950683593750, -0.0151977539062500, +-0.0054626464843750, -0.0146789550781250, -0.0093383789062500, -0.0175170898437500, +-0.0086975097656250, -0.0173339843750000, -0.0101623535156250, -0.0188903808593750, +-0.0131835937500000, -0.0209655761718750, -0.0118408203125000, -0.0193176269531250, +-0.0165405273437500, -0.0235900878906250, -0.0161132812500000, -0.0225524902343750, +-0.0172424316406250, -0.0231018066406250, -0.0208435058593750, -0.0259399414062500, +-0.0193481445312500, -0.0238037109375000, -0.0212097167968750, -0.0256347656250000, +-0.0220947265625000, -0.0256347656250000, -0.0211791992187500, -0.0238342285156250, +-0.0212097167968750, -0.0232849121093750, -0.0215759277343750, -0.0225524902343750, +-0.0190734863281250, -0.0195007324218750, -0.0199890136718750, -0.0181884765625000, +-0.0182800292968750, -0.0160827636718750, -0.0156250000000000, -0.0132446289062500, +-0.0173950195312500, -0.0123901367187500, -0.0131225585937500, -0.0103149414062500, +-0.0131530761718750, -0.0077514648437500, -0.0130615234375000, -0.0060119628906250, +-0.0106201171875000, -0.0045776367187500, -0.0112609863281250, -0.0026245117187500, +-0.0111999511718750, -0.0007934570312500, -0.0105285644531250, 0.0015563964843750, +-0.0109558105468750, 0.0022888183593750, -0.0115661621093750, 0.0030517578125000, +-0.0110778808593750, 0.0054321289062500, -0.0118103027343750, 0.0034790039062500, +-0.0115661621093750, 0.0057983398437500, -0.0117797851562500, 0.0058898925781250, +-0.0122070312500000, 0.0044555664062500, -0.0116577148437500, 0.0074462890625000, +-0.0131225585937500, 0.0045166015625000, -0.0126647949218750, 0.0072631835937500, +-0.0130920410156250, 0.0064697265625000, -0.0142211914062500, 0.0039062500000000, +-0.0134277343750000, 0.0077514648437500, -0.0147094726562500, 0.0016174316406250, +-0.0144042968750000, 0.0038757324218750, -0.0147705078125000, 0.0014953613281250, +-0.0157470703125000, -0.0035095214843750, -0.0148925781250000, 0.0009460449218750, +-0.0160522460937500, -0.0084838867187500, -0.0161743164062500, -0.0065002441406250, +-0.0155029296875000, -0.0083923339843750, -0.0155029296875000, -0.0148620605468750, +-0.0158691406250000, -0.0104064941406250, -0.0151977539062500, -0.0182800292968750, +-0.0147705078125000, -0.0168762207031250, -0.0161743164062500, -0.0173339843750000, +-0.0170288085937500, -0.0223083496093750, -0.0162658691406250, -0.0197448730468750, +-0.0195617675781250, -0.0237426757812500, -0.0198059082031250, -0.0228576660156250, +-0.0196533203125000, -0.0245666503906250, -0.0212707519531250, -0.0280761718750000, +-0.0214538574218750, -0.0254821777343750, -0.0205688476562500, -0.0303344726562500, +-0.0212402343750000, -0.0292358398437500, -0.0209655761718750, -0.0304565429687500, +-0.0205078125000000, -0.0342712402343750, -0.0210876464843750, -0.0318908691406250, +-0.0180358886718750, -0.0354309082031250, -0.0198974609375000, -0.0364379882812500, +-0.0167541503906250, -0.0350036621093750, -0.0125122070312500, -0.0360107421875000, +-0.0157775878906250, -0.0363769531250000, -0.0074768066406250, -0.0304260253906250, +-0.0080261230468750, -0.0335693359375000, -0.0065917968750000, -0.0278930664062500, +-0.0010986328125000, -0.0198059082031250, -0.0035095214843750, -0.0249023437500000, +-0.0001220703125000, -0.0101623535156250, 0.0008850097656250, -0.0112609863281250, +-0.0003967285156250, -0.0088500976562500, 0.0002746582031250, 0.0016174316406250, +0.0006713867187500, -0.0024414062500000, -0.0026855468750000, 0.0003356933593750, +-0.0013732910156250, 0.0030822753906250, -0.0040588378906250, 0.0003662109375000, +-0.0081481933593750, -0.0018005371093750, -0.0054016113281250, 0.0000000000000000, +-0.0117187500000000, -0.0032348632812500, -0.0133666992187500, -0.0034790039062500, +-0.0098571777343750, -0.0037841796875000, -0.0101623535156250, -0.0053405761718750, +-0.0123291015625000, -0.0041809082031250, -0.0050659179687500, -0.0048522949218750, +-0.0041198730468750, -0.0057067871093750, -0.0056457519531250, -0.0040283203125000, +-0.0034179687500000, -0.0032348632812500, -0.0028381347656250, -0.0043334960937500, +-0.0058898925781250, 0.0014038085937500, -0.0055236816406250, 0.0013732910156250, +-0.0057067871093750, -0.0004577636718750, -0.0075378417968750, 0.0013427734375000, +-0.0068664550781250, 0.0021667480468750, -0.0076904296875000, 0.0000915527343750, +-0.0073547363281250, 0.0002441406250000, -0.0086059570312500, -0.0017395019531250, +-0.0098266601562500, -0.0039367675781250, -0.0085449218750000, -0.0018920898437500, +-0.0124206542968750, -0.0046081542968750, -0.0119934082031250, -0.0053100585937500, +-0.0133361816406250, -0.0057067871093750, -0.0160827636718750, -0.0066223144531250, +-0.0143127441406250, -0.0061340332031250, -0.0182495117187500, -0.0089111328125000, +-0.0182800292968750, -0.0072631835937500, -0.0187072753906250, -0.0100097656250000, +-0.0206604003906250, -0.0152282714843750, -0.0194091796875000, -0.0125122070312500, +-0.0218200683593750, -0.0124816894531250, -0.0227966308593750, -0.0156860351562500, +-0.0204162597656250, -0.0114440917968750, -0.0180358886718750, -0.0026550292968750, +-0.0119323730468750, -0.0128173828125000, -0.0070190429687500, -0.0141296386718750, +-0.0066833496093750, -0.0184326171875000, -0.0093078613281250, -0.0147094726562500, +-0.0097961425781250, -0.0091857910156250, -0.0074157714843750, -0.0115051269531250, +-0.0120849609375000, -0.0098571777343750, -0.0144958496093750, -0.0083618164062500, +-0.0095825195312500, -0.0102844238281250, -0.0083007812500000, -0.0128479003906250, +-0.0118713378906250, -0.0109252929687500, 0.0020751953125000, -0.0050354003906250, +0.0013122558593750, -0.0095214843750000, 0.0006713867187500, -0.0054016113281250, +0.0086364746093750, 0.0045166015625000, 0.0068969726562500, 0.0005187988281250, +0.0017395019531250, 0.0021972656250000, 0.0037536621093750, 0.0056457519531250, +0.0044250488281250, 0.0003051757812500, -0.0007629394531250, -0.0043945312500000, +-0.0011901855468750, 0.0000610351562500, 0.0085449218750000, -0.0065002441406250, +0.0068969726562500, -0.0097045898437500, 0.0064392089843750, -0.0053405761718750, +0.0125732421875000, -0.0029296875000000, 0.0114440917968750, -0.0054016113281250, +0.0076599121093750, -0.0020446777343750, 0.0108642578125000, 0.0000305175781250, +0.0058898925781250, -0.0032348632812500, -0.0003662109375000, -0.0043334960937500, +0.0045166015625000, -0.0022888183593750, -0.0086669921875000, -0.0123596191406250, +-0.0092773437500000, -0.0108032226562500, -0.0057983398437500, -0.0123901367187500, +-0.0110778808593750, -0.0198669433593750, -0.0122680664062500, -0.0171508789062500, +-0.0032653808593750, -0.0187377929687500, -0.0041198730468750, -0.0199890136718750, +-0.0049743652343750, -0.0192565917968750, 0.0006103515625000, -0.0187072753906250, +-0.0003967285156250, -0.0189208984375000, -0.0086669921875000, -0.0191345214843750, +-0.0031127929687500, -0.0193481445312500, -0.0115356445312500, -0.0183410644531250, +-0.0231323242187500, -0.0179443359375000, -0.0140380859375000, -0.0188293457031250, +-0.0346069335937500, -0.0158691406250000, -0.0344238281250000, -0.0152893066406250, +-0.0338134765625000, -0.0169677734375000, -0.0446472167968750, -0.0166625976562500, +-0.0412597656250000, -0.0156250000000000, -0.0396118164062500, -0.0196838378906250, +-0.0429077148437500, -0.0197753906250000, -0.0389099121093750, -0.0192260742187500, +-0.0341796875000000, -0.0208129882812500, -0.0376586914062500, -0.0209045410156250, +-0.0279235839843750, -0.0201416015625000, -0.0296630859375000, -0.0199890136718750, +-0.0266113281250000, -0.0205688476562500, -0.0188903808593750, -0.0209655761718750, +-0.0235290527343750, -0.0206909179687500, -0.0156555175781250, -0.0208129882812500, +-0.0159912109375000, -0.0216979980468750, -0.0153503417968750, -0.0205993652343750, +-0.0114135742187500, -0.0194091796875000, -0.0140991210937500, -0.0205383300781250, +-0.0088500976562500, -0.0184326171875000, -0.0111694335937500, -0.0184631347656250, +-0.0089721679687500, -0.0180664062500000, -0.0040588378906250, -0.0171508789062500, +-0.0078735351562500, -0.0177307128906250, 0.0009155273437500, -0.0147094726562500, +-0.0010681152343750, -0.0154724121093750, 0.0009765625000000, -0.0141601562500000, +0.0073547363281250, -0.0110778808593750, 0.0033264160156250, -0.0123596191406250, +0.0112915039062500, -0.0099182128906250, 0.0098571777343750, -0.0096435546875000, +0.0112915039062500, -0.0093383789062500, 0.0166931152343750, -0.0081787109375000, +0.0133056640625000, -0.0087585449218750, 0.0191955566406250, -0.0070190429687500, +0.0191040039062500, -0.0071716308593750, 0.0195312500000000, -0.0070495605468750, +0.0229187011718750, -0.0061340332031250, 0.0218200683593750, -0.0065917968750000, +0.0250244140625000, -0.0058288574218750, 0.0246582031250000, -0.0064697265625000, +0.0252685546875000, -0.0051574707031250, 0.0278015136718750, -0.0037841796875000, +0.0273437500000000, -0.0050964355468750, 0.0291442871093750, -0.0008850097656250, +0.0295410156250000, -0.0009155273437500, 0.0299072265625000, -0.0010070800781250, +0.0307312011718750, 0.0015563964843750, 0.0304870605468750, 0.0011901855468750, +0.0318298339843750, -0.0008850097656250, 0.0321044921875000, 0.0010070800781250, +0.0322265625000000, -0.0015869140625000, 0.0329895019531250, -0.0049133300781250, +0.0332946777343750, -0.0022277832031250, 0.0338745117187500, -0.0100402832031250, +0.0344848632812500, -0.0090332031250000, 0.0345458984375000, -0.0109252929687500, +0.0346984863281250, -0.0172729492187500, 0.0346984863281250, -0.0149230957031250, +0.0323181152343750, -0.0174560546875000, 0.0335998535156250, -0.0193176269531250, +0.0316162109375000, -0.0184020996093750, 0.0287475585937500, -0.0176696777343750, +0.0303955078125000, -0.0186462402343750, 0.0238952636718750, -0.0192565917968750, +0.0253906250000000, -0.0182189941406250, 0.0230712890625000, -0.0198059082031250, +0.0173034667968750, -0.0216064453125000, 0.0195922851562500, -0.0202636718750000, +0.0121154785156250, -0.0231628417968750, 0.0122070312500000, -0.0227661132812500, +0.0091552734375000, -0.0227966308593750, 0.0030822753906250, -0.0250549316406250, +0.0054321289062500, -0.0240783691406250, -0.0010986328125000, -0.0216369628906250, +-0.0021057128906250, -0.0244140625000000, -0.0033569335937500, -0.0204467773437500, +-0.0071716308593750, -0.0153198242187500, -0.0068664550781250, -0.0194091796875000, +-0.0108642578125000, -0.0111083984375000, -0.0108032226562500, -0.0109863281250000, +-0.0114440917968750, -0.0104370117187500, -0.0139160156250000, -0.0065612792968750, +-0.0131530761718750, -0.0081787109375000, -0.0144042968750000, -0.0017700195312500, +-0.0149536132812500, -0.0034179687500000, -0.0140991210937500, -0.0015563964843750, +-0.0141601562500000, 0.0047912597656250, -0.0146484375000000, 0.0021667480468750, +-0.0118103027343750, 0.0022583007812500, -0.0123596191406250, 0.0033264160156250, +-0.0107116699218750, 0.0051269531250000, -0.0081481933593750, 0.0046691894531250, +-0.0095825195312500, 0.0025634765625000, -0.0051269531250000, 0.0092163085937500, +-0.0050659179687500, 0.0095520019531250, -0.0040893554687500, 0.0079040527343750, +-0.0010986328125000, 0.0102844238281250, -0.0020141601562500, 0.0107116699218750, +-0.0000305175781250, 0.0068054199218750, 0.0010070800781250, 0.0084533691406250, +0.0000610351562500, 0.0058898925781250, 0.0000305175781250, 0.0019836425781250, +0.0006713867187500}, +{0.0142517089843750, -0.0208740234375000, 0.0137023925781250, -0.0218811035156250, +0.0115966796875000, -0.0191040039062500, 0.0126647949218750, -0.0193786621093750, +0.0111389160156250, -0.0182495117187500, 0.0088195800781250, -0.0161743164062500, +0.0107116699218750, -0.0173950195312500, 0.0068664550781250, -0.0133056640625000, +0.0079040527343750, -0.0136718750000000, 0.0070190429687500, -0.0129394531250000, +0.0045166015625000, -0.0101928710937500, 0.0070495605468750, -0.0113830566406250, +0.0027770996093750, -0.0095825195312500, 0.0037841796875000, -0.0097045898437500, +0.0035095214843750, -0.0090942382812500, 0.0007324218750000, -0.0079956054687500, +0.0022583007812500, -0.0089416503906250, -0.0005493164062500, -0.0057983398437500, +0.0002136230468750, -0.0064086914062500, -0.0002136230468750, -0.0050659179687500, +-0.0022583007812500, -0.0021057128906250, -0.0010070800781250, -0.0034484863281250, +-0.0029296875000000, -0.0004882812500000, -0.0026855468750000, 0.0003967285156250, +-0.0021667480468750, -0.0002441406250000, -0.0025939941406250, 0.0008850097656250, +-0.0019226074218750, 0.0014038085937500, -0.0025024414062500, -0.0018005371093750, +-0.0019836425781250, -0.0002136230468750, -0.0022277832031250, -0.0023803710937500, +-0.0027160644531250, -0.0064086914062500, -0.0016784667968750, -0.0041503906250000, +-0.0024414062500000, -0.0087585449218750, -0.0020446777343750, -0.0096740722656250, +-0.0018005371093750, -0.0093078613281250, -0.0020141601562500, -0.0107727050781250, +-0.0008544921875000, -0.0110778808593750, 0.0000305175781250, -0.0123901367187500, +-0.0002746582031250, -0.0114135742187500, 0.0013427734375000, -0.0137634277343750, +0.0029602050781250, -0.0164794921875000, 0.0028381347656250, -0.0146179199218750, +0.0073852539062500, -0.0193786621093750, 0.0066223144531250, -0.0190124511718750, +0.0091552734375000, -0.0196838378906250, 0.0137023925781250, -0.0225219726562500, +0.0123596191406250, -0.0207519531250000, 0.0191040039062500, -0.0229187011718750, +0.0188293457031250, -0.0240478515625000, 0.0209960937500000, -0.0217895507812500, +0.0263061523437500, -0.0213623046875000, 0.0241088867187500, -0.0231628417968750, +0.0270690917968750, -0.0172424316406250, 0.0284118652343750, -0.0182800292968750, +0.0269165039062500, -0.0171203613281250, 0.0272216796875000, -0.0131530761718750, +0.0280151367187500, -0.0150756835937500, 0.0230712890625000, -0.0102539062500000, +0.0242919921875000, -0.0115051269531250, 0.0205993652343750, -0.0087890625000000, +0.0152893066406250, -0.0039672851562500, 0.0180664062500000, -0.0072937011718750, +0.0081176757812500, -0.0006103515625000, 0.0091247558593750, 0.0004272460937500, +0.0056457519531250, -0.0012207031250000, -0.0020141601562500, 0.0001220703125000, +0.0018005371093750, 0.0010986328125000, -0.0068969726562500, 0.0019836425781250, +-0.0068359375000000, -0.0003356933593750, -0.0082397460937500, 0.0023803710937500, +-0.0132141113281250, 0.0065917968750000, -0.0104370117187500, 0.0039672851562500, +-0.0152893066406250, 0.0059509277343750, -0.0155639648437500, 0.0074462890625000, +-0.0154418945312500, 0.0065002441406250, -0.0180664062500000, 0.0061950683593750, +-0.0170593261718750, 0.0066223144531250, -0.0149230957031250, 0.0038452148437500, +-0.0166931152343750, 0.0054931640625000, -0.0139160156250000, 0.0029602050781250, +-0.0101013183593750, -0.0012512207031250, -0.0123901367187500, 0.0019836425781250, +-0.0065917968750000, -0.0011596679687500, -0.0066528320312500, -0.0025634765625000, +-0.0062866210937500, -0.0019836425781250, -0.0027770996093750, -0.0015869140625000, +-0.0038146972656250, -0.0009765625000000, -0.0041503906250000, -0.0027770996093750, +-0.0030822753906250, -0.0021057128906250, -0.0042419433593750, -0.0046997070312500, +-0.0059814453125000, -0.0070800781250000, -0.0050964355468750, -0.0043334960937500, +-0.0065917968750000, -0.0100708007812500, -0.0071105957031250, -0.0106811523437500, +-0.0050048828125000, -0.0110473632812500, -0.0048828125000000, -0.0134582519531250, +-0.0064086914062500, -0.0119323730468750, 0.0007934570312500, -0.0129089355468750, +0.0001525878906250, -0.0135803222656250, 0.0000305175781250, -0.0133056640625000, +0.0041198730468750, -0.0130920410156250, 0.0030212402343750, -0.0129699707031250, +0.0020751953125000, -0.0131835937500000, 0.0025939941406250, -0.0126647949218750, +0.0025939941406250, -0.0130310058593750, 0.0018310546875000, -0.0144348144531250, +0.0014953613281250, -0.0138854980468750, 0.0013427734375000, -0.0108947753906250, +0.0021972656250000, -0.0120544433593750, 0.0003051757812500, -0.0107116699218750, +-0.0021972656250000, -0.0069580078125000, -0.0021667480468750, -0.0072631835937500, +-0.0060119628906250, -0.0048522949218750, -0.0050048828125000, -0.0053100585937500, +-0.0053710937500000, -0.0048828125000000, -0.0081787109375000, -0.0035095214843750, +-0.0069885253906250, -0.0042114257812500, -0.0086669921875000, -0.0008239746093750, +-0.0085144042968750, -0.0018005371093750, -0.0094299316406250, -0.0001220703125000, +-0.0106811523437500, 0.0034484863281250, -0.0096435546875000, 0.0013732910156250, +-0.0137329101562500, 0.0035095214843750, -0.0134277343750000, 0.0044555664062500, +-0.0126647949218750, 0.0031433105468750, -0.0140686035156250, 0.0029907226562500, +-0.0142211914062500, 0.0033264160156250, -0.0153808593750000, -0.0002136230468750, +-0.0139465332031250, 0.0003967285156250, -0.0162658691406250, 0.0001525878906250, +-0.0192565917968750, -0.0025939941406250, -0.0166015625000000, -0.0020751953125000, +-0.0201416015625000, -0.0018005371093750, -0.0227050781250000, -0.0022888183593750, +-0.0178527832031250, -0.0019226074218750, -0.0152282714843750, -0.0015258789062500, +-0.0188293457031250, -0.0018005371093750, -0.0089416503906250, -0.0001525878906250, +-0.0080871582031250, -0.0010070800781250, -0.0110168457031250, 0.0005493164062500, +-0.0080261230468750, 0.0033569335937500, -0.0060729980468750, 0.0015869140625000, +-0.0097045898437500, 0.0019836425781250, -0.0120544433593750, 0.0044555664062500, +-0.0081481933593750, 0.0009765625000000, -0.0055236816406250, -0.0024719238281250, +-0.0084228515625000, 0.0002136230468750, -0.0025939941406250, -0.0077514648437500, +-0.0018615722656250, -0.0069885253906250, -0.0042419433593750, -0.0087585449218750, +-0.0026855468750000, -0.0147705078125000, -0.0014648437500000, -0.0123901367187500, +-0.0069274902343750, -0.0153503417968750, -0.0066528320312500, -0.0164184570312500, +-0.0065917968750000, -0.0159301757812500, -0.0093994140625000, -0.0162658691406250, +-0.0085449218750000, -0.0162658691406250, -0.0086975097656250, -0.0165405273437500, +-0.0097351074218750, -0.0157775878906250, -0.0086364746093750, -0.0153198242187500, +-0.0072937011718750, -0.0156250000000000, -0.0085754394531250, -0.0144348144531250, +-0.0087280273437500, -0.0113220214843750, -0.0079040527343750, -0.0117187500000000, +-0.0089111328125000, -0.0069274902343750, -0.0102844238281250, -0.0019226074218750, +-0.0098876953125000, -0.0036315917968750, -0.0115051269531250, 0.0068969726562500, +-0.0112609863281250, 0.0064697265625000, -0.0118713378906250, 0.0093078613281250, +-0.0133972167968750, 0.0168151855468750, -0.0128173828125000, 0.0140686035156250, +-0.0135803222656250, 0.0194396972656250, -0.0138854980468750, 0.0206298828125000, +-0.0139465332031250, 0.0196533203125000, -0.0141906738281250, 0.0208740234375000, +-0.0139770507812500, 0.0201110839843750, -0.0138244628906250, 0.0176696777343750, +-0.0143127441406250, 0.0177612304687500, -0.0132141113281250, 0.0156250000000000, +-0.0120239257812500, 0.0126953125000000, -0.0128479003906250, 0.0129089355468750, +-0.0110168457031250, 0.0083312988281250, -0.0104980468750000, 0.0083312988281250, +-0.0109558105468750, 0.0058593750000000, -0.0105895996093750, 0.0015563964843750, +-0.0101318359375000, 0.0028686523437500, -0.0108947753906250, -0.0010986328125000, +-0.0107116699218750, -0.0019226074218750, -0.0106506347656250, -0.0025634765625000, +-0.0112609863281250, -0.0046386718750000, -0.0110778808593750, -0.0042419433593750, +-0.0105590820312500, -0.0052490234375000, -0.0111083984375000, -0.0059204101562500, +-0.0098571777343750, -0.0068969726562500, -0.0087585449218750, -0.0077514648437500, +-0.0097961425781250, -0.0077819824218750, -0.0065002441406250, -0.0096435546875000, +-0.0068664550781250, -0.0091552734375000, -0.0065002441406250, -0.0097045898437500, +-0.0042724609375000, -0.0111083984375000, -0.0051574707031250, -0.0101318359375000, +-0.0051574707031250, -0.0120849609375000, -0.0043029785156250, -0.0116271972656250, +-0.0052795410156250, -0.0117797851562500, -0.0062866210937500, -0.0132141113281250, +-0.0054016113281250, -0.0128479003906250, -0.0075988769531250, -0.0143737792968750, +-0.0073852539062500, -0.0138854980468750, -0.0075683593750000, -0.0138244628906250, +-0.0089721679687500, -0.0146789550781250, -0.0083312988281250, -0.0139770507812500, +-0.0089721679687500, -0.0147094726562500, -0.0088500976562500, -0.0149841308593750, +-0.0093078613281250, -0.0139770507812500, -0.0095214843750000, -0.0140380859375000, +-0.0090332031250000, -0.0147399902343750, -0.0122680664062500, -0.0111999511718750, +-0.0109863281250000, -0.0131225585937500, -0.0131530761718750, -0.0094909667968750, +-0.0169372558593750, -0.0050964355468750, -0.0149230957031250, -0.0087890625000000, +-0.0195617675781250, 0.0022888183593750, -0.0197753906250000, -0.0008850097656250, +-0.0200805664062500, 0.0036010742187500, -0.0225219726562500, 0.0132751464843750, +-0.0215759277343750, 0.0067138671875000, -0.0220336914062500, 0.0190734863281250, +-0.0230407714843750, 0.0192871093750000, -0.0213623046875000, 0.0209350585937500, +-0.0204162597656250, 0.0280761718750000, -0.0215148925781250, 0.0246276855468750, +-0.0163269042968750, 0.0295104980468750, -0.0172119140625000, 0.0301208496093750, +-0.0156555175781250, 0.0278015136718750, -0.0116577148437500, 0.0291748046875000, +-0.0137023925781250, 0.0298156738281250, -0.0100708007812500, 0.0236206054687500, +-0.0098266601562500, 0.0258789062500000, -0.0100097656250000, 0.0217895507812500, +-0.0081176757812500, 0.0148620605468750, -0.0086669921875000, 0.0192871093750000, +-0.0095520019531250, 0.0106506347656250, -0.0088500976562500, 0.0111083984375000, +-0.0100708007812500, 0.0090637207031250, -0.0118713378906250, 0.0043334960937500, +-0.0108642578125000, 0.0078430175781250, -0.0120239257812500, -0.0019531250000000, +-0.0128479003906250, 0.0008544921875000, -0.0121154785156250, -0.0038452148437500, +-0.0117492675781250, -0.0125122070312500, -0.0122375488281250, -0.0066528320312500, +-0.0107727050781250, -0.0218505859375000, -0.0113525390625000, -0.0209045410156250, +-0.0098266601562500, -0.0227661132812500, -0.0079040527343750, -0.0332336425781250, +-0.0093688964843750, -0.0292968750000000, -0.0054931640625000, -0.0293579101562500, +-0.0053100585937500, -0.0338439941406250, -0.0047607421875000, -0.0263061523437500, +-0.0027770996093750, -0.0201110839843750, -0.0037536621093750, -0.0257568359375000, +-0.0010070800781250, -0.0055236816406250, 0.0000305175781250, -0.0077819824218750, +-0.0028381347656250, -0.0041198730468750, -0.0032043457031250, 0.0107116699218750, +-0.0009765625000000, 0.0049743652343750, -0.0091247558593750, 0.0102233886718750, +-0.0093078613281250, 0.0148010253906250, -0.0079650878906250, 0.0097351074218750, +-0.0115356445312500, 0.0057983398437500, -0.0114440917968750, 0.0091247558593750, +-0.0073852539062500, 0.0028991699218750, -0.0083618164062500, 0.0024719238281250, +-0.0075683593750000, 0.0029602050781250, -0.0034790039062500, -0.0008239746093750, +-0.0050354003906250, -0.0007019042968750, -0.0100097656250000, 0.0038146972656250, +-0.0067749023437500}, +{-0.0079345703125000, 0.0120544433593750, -0.0084228515625000, 0.0121154785156250, +-0.0075988769531250, 0.0121459960937500, -0.0065917968750000, 0.0129394531250000, +-0.0074462890625000, 0.0128784179687500, -0.0059509277343750, 0.0135803222656250, +-0.0057678222656250, 0.0138854980468750, -0.0061950683593750, 0.0138854980468750, +-0.0057678222656250, 0.0141296386718750, -0.0056457519531250, 0.0145568847656250, +-0.0067749023437500, 0.0148925781250000, -0.0065002441406250, 0.0149536132812500, +-0.0069274902343750, 0.0153808593750000, -0.0076293945312500, 0.0157775878906250, +-0.0072021484375000, 0.0157470703125000, -0.0095825195312500, 0.0173034667968750, +-0.0085754394531250, 0.0178833007812500, -0.0106201171875000, 0.0167846679687500, +-0.0136108398437500, 0.0171203613281250, -0.0116577148437500, 0.0184020996093750, +-0.0165710449218750, 0.0141601562500000, -0.0166320800781250, 0.0165100097656250, +-0.0166625976562500, 0.0134582519531250, -0.0192260742187500, 0.0088806152343750, +-0.0184326171875000, 0.0131835937500000, -0.0182800292968750, 0.0038452148437500, +-0.0189208984375000, 0.0063171386718750, -0.0174560546875000, 0.0049438476562500, +-0.0162353515625000, -0.0021667480468750, -0.0168151855468750, 0.0016784667968750, +-0.0132141113281250, -0.0031127929687500, -0.0135803222656250, -0.0039978027343750, +-0.0125122070312500, -0.0025024414062500, -0.0096740722656250, -0.0038452148437500, +-0.0107727050781250, -0.0035705566406250, -0.0085449218750000, 0.0005187988281250, +-0.0082397460937500, -0.0016784667968750, -0.0085449218750000, 0.0026245117187500, +-0.0076904296875000, 0.0084228515625000, -0.0079040527343750, 0.0044860839843750, +-0.0088500976562500, 0.0145263671875000, -0.0080871582031250, 0.0135498046875000, +-0.0094299316406250, 0.0143432617187500, -0.0111389160156250, 0.0208435058593750, +-0.0099182128906250, 0.0178222656250000, -0.0130004882812500, 0.0183410644531250, +-0.0133972167968750, 0.0198059082031250, -0.0130004882812500, 0.0187683105468750, +-0.0140686035156250, 0.0172729492187500, -0.0141906738281250, 0.0178527832031250, +-0.0138244628906250, 0.0171813964843750, -0.0136413574218750, 0.0169982910156250, +-0.0140686035156250, 0.0172729492187500, -0.0147399902343750, 0.0177917480468750, +-0.0143737792968750, 0.0175781250000000, -0.0125427246093750, 0.0151367187500000, +-0.0140991210937500, 0.0183105468750000, -0.0117187500000000, 0.0127258300781250, +-0.0083007812500000, 0.0075073242187500, -0.0102539062500000, 0.0125732421875000, +-0.0050964355468750, -0.0069580078125000, -0.0048522949218750, -0.0030822753906250, +-0.0052490234375000, -0.0088500976562500, -0.0022888183593750, -0.0249633789062500, +-0.0029296875000000, -0.0164794921875000, -0.0067138671875000, -0.0281677246093750, +-0.0050964355468750, -0.0320434570312500, -0.0062255859375000, -0.0254516601562500, +-0.0109863281250000, -0.0261535644531250, -0.0094909667968750, -0.0289306640625000, +-0.0053405761718750, -0.0108947753906250, -0.0080566406250000, -0.0145568847656250, +-0.0052490234375000, -0.0088806152343750, 0.0008544921875000, 0.0071411132812500, +-0.0018310546875000, 0.0010375976562500, 0.0011291503906250, 0.0091552734375000, +0.0029602050781250, 0.0117797851562500, -0.0008850097656250, 0.0081176757812500, +-0.0024108886718750, 0.0095520019531250, 0.0004272460937500, 0.0117492675781250, +-0.0074157714843750, 0.0021057128906250, -0.0086669921875000, 0.0014953613281250, +-0.0072326660156250, 0.0020751953125000, -0.0086669921875000, -0.0017395019531250, +-0.0091552734375000, -0.0007324218750000, -0.0114135742187500, 0.0006103515625000, +-0.0095214843750000, 0.0000000000000000, -0.0122375488281250, -0.0023498535156250, +-0.0176391601562500, -0.0015869140625000, -0.0148620605468750, 0.0003356933593750, +-0.0137634277343750, -0.0098571777343750, -0.0172119140625000, -0.0087280273437500, +-0.0135192871093750, -0.0092773437500000, -0.0042419433593750, -0.0189819335937500, +0.0008239746093750, -0.0040893554687500, -0.0058593750000000, -0.0143432617187500, +-0.0039978027343750, -0.0107116699218750, -0.0029296875000000, -0.0119323730468750, +-0.0061645507812500, -0.0177307128906250, -0.0072326660156250, -0.0166320800781250, +0.0002441406250000, -0.0128173828125000, -0.0005187988281250, -0.0144348144531250, +-0.0012512207031250, -0.0146179199218750, 0.0036010742187500, -0.0102844238281250, +0.0029602050781250, -0.0105895996093750, -0.0037536621093750, -0.0191955566406250, +-0.0013122558593750, -0.0173339843750000, -0.0036621093750000, -0.0174865722656250, +-0.0105590820312500, -0.0250244140625000, -0.0076293945312500, -0.0233459472656250, +-0.0092468261718750, -0.0128479003906250, -0.0114135742187500, -0.0192871093750000, +-0.0091552734375000, -0.0105590820312500, -0.0055236816406250, 0.0054626464843750, +-0.0076904296875000, -0.0032043457031250, -0.0144958496093750, 0.0067749023437500, +-0.0082397460937500, 0.0108337402343750, -0.0153198242187500, 0.0065307617187500, +-0.0280456542968750, 0.0061645507812500, -0.0205078125000000, 0.0078735351562500, +-0.0295410156250000, 0.0020751953125000, -0.0331726074218750, 0.0012817382812500, +-0.0276794433593750, 0.0028381347656250, -0.0283813476562500, 0.0019836425781250, +-0.0304260253906250, 0.0010375976562500, -0.0111694335937500, 0.0002441406250000, +-0.0176086425781250, 0.0020751953125000, -0.0087890625000000, 0.0001525878906250, +0.0111083984375000, -0.0032043457031250, 0.0010681152343750, -0.0018310546875000, +0.0162658691406250, -0.0035095214843750, 0.0185241699218750, -0.0032348632812500, +0.0168762207031250, -0.0052795410156250, 0.0229187011718750, -0.0067138671875000, +0.0213928222656250, -0.0048522949218750, 0.0180969238281250, -0.0129089355468750, +0.0201416015625000, -0.0116882324218750, 0.0185546875000000, -0.0132141113281250, +0.0148010253906250, -0.0196838378906250, 0.0172119140625000, -0.0173339843750000, +0.0155639648437500, -0.0184326171875000, 0.0146789550781250, -0.0196533203125000, +0.0150451660156250, -0.0192871093750000, 0.0154113769531250, -0.0182189941406250, +0.0155029296875000, -0.0182495117187500, 0.0136718750000000, -0.0215148925781250, +0.0147094726562500, -0.0206298828125000, 0.0141296386718750, -0.0209960937500000, +0.0121765136718750, -0.0240173339843750, 0.0128784179687500, -0.0234375000000000, +0.0114135742187500, -0.0217285156250000, 0.0114135742187500, -0.0224304199218750, +0.0107421875000000, -0.0223388671875000, 0.0094299316406250, -0.0205078125000000, +0.0100402832031250, -0.0206604003906250, 0.0086975097656250, -0.0229187011718750, +0.0075683593750000, -0.0221862792968750, 0.0091247558593750, -0.0223388671875000, +0.0100402832031250, -0.0242309570312500, 0.0086669921875000, -0.0237731933593750, +0.0119934082031250, -0.0227050781250000, 0.0114135742187500, -0.0232543945312500, +0.0115356445312500, -0.0229492187500000, 0.0137939453125000, -0.0218200683593750, +0.0127868652343750, -0.0221862792968750, 0.0124816894531250, -0.0218200683593750, +0.0136413574218750, -0.0222167968750000, 0.0115966796875000, -0.0213928222656250, +0.0101318359375000, -0.0206298828125000, 0.0121154785156250, -0.0216369628906250, +0.0066833496093750, -0.0189208984375000, 0.0082092285156250, -0.0192565917968750, +0.0064392089843750, -0.0184936523437500, 0.0023803710937500, -0.0167236328125000, +0.0058288574218750, -0.0175781250000000, -0.0010070800781250, -0.0141906738281250, +0.0008850097656250, -0.0146179199218750, -0.0006103515625000, -0.0133056640625000, +-0.0057067871093750, -0.0101623535156250, -0.0021667480468750, -0.0112609863281250, +-0.0075378417968750, -0.0091552734375000, -0.0063476562500000, -0.0082397460937500, +-0.0069580078125000, -0.0087280273437500, -0.0100097656250000, -0.0084533691406250, +-0.0067138671875000, -0.0079345703125000, -0.0110473632812500, -0.0089721679687500, +-0.0095520019531250, -0.0090332031250000, -0.0104675292968750, -0.0088806152343750, +-0.0135498046875000, -0.0096130371093750, -0.0104675292968750, -0.0098571777343750, +-0.0148620605468750, -0.0088195800781250, -0.0137023925781250, -0.0093688964843750, +-0.0133666992187500, -0.0093383789062500, -0.0158691406250000, -0.0083007812500000, +-0.0136413574218750, -0.0087890625000000, -0.0137939453125000, -0.0093688964843750, +-0.0133056640625000, -0.0089111328125000, -0.0116882324218750, -0.0094604492187500, +-0.0107116699218750, -0.0102844238281250, -0.0100402832031250, -0.0097045898437500, +-0.0072326660156250, -0.0108642578125000, -0.0072631835937500, -0.0103149414062500, +-0.0050354003906250, -0.0111694335937500, -0.0022888183593750, -0.0127563476562500, +-0.0031433105468750, -0.0116271972656250, 0.0021057128906250, -0.0128479003906250, +0.0016174316406250, -0.0137939453125000, 0.0032043457031250, -0.0125427246093750, +0.0072326660156250, -0.0118713378906250, 0.0057678222656250, -0.0128479003906250, +0.0087585449218750, -0.0109558105468750, 0.0094909667968750, -0.0112915039062500, +0.0086975097656250, -0.0102844238281250, 0.0094299316406250, -0.0089111328125000, +0.0098876953125000, -0.0101928710937500, 0.0080566406250000, -0.0063781738281250, +0.0081481933593750, -0.0063781738281250, 0.0072326660156250, -0.0064697265625000, +0.0056152343750000, -0.0043640136718750, 0.0059509277343750, -0.0047302246093750, +0.0030517578125000, -0.0053100585937500, 0.0032043457031250, -0.0043029785156250, +0.0032348632812500, -0.0060119628906250, 0.0013122558593750, -0.0080261230468750, +0.0015258789062500, -0.0061035156250000, 0.0028381347656250, -0.0084838867187500, +0.0016174316406250, -0.0104980468750000, 0.0036621093750000, -0.0071411132812500, +0.0061340332031250, -0.0051269531250000, 0.0044250488281250, -0.0079956054687500, +0.0101318359375000, -0.0024414062500000, 0.0098266601562500, -0.0017395019531250, +0.0109863281250000, -0.0023498535156250, 0.0148010253906250, -0.0001220703125000, +0.0130310058593750, -0.0006103515625000, 0.0145568847656250, -0.0026245117187500, +0.0156555175781250, -0.0010375976562500, 0.0140991210937500, -0.0034484863281250, +0.0139160156250000, -0.0072937011718750, 0.0148010253906250, -0.0044860839843750, +0.0083312988281250, -0.0059509277343750, 0.0106201171875000, -0.0091857910156250, +0.0054016113281250, -0.0046386718750000, -0.0022888183593750, 0.0001525878906250, +0.0025939941406250, -0.0037231445312500, -0.0088500976562500, 0.0007629394531250, +-0.0087890625000000, 0.0033264160156250, -0.0098266601562500, -0.0008239746093750, +-0.0163574218750000, -0.0022583007812500, -0.0139160156250000, 0.0006103515625000, +-0.0181579589843750, -0.0082702636718750, -0.0194396972656250, -0.0092163085937500, +-0.0168457031250000, -0.0071105957031250, -0.0173950195312500, -0.0096435546875000, +-0.0189514160156250, -0.0101318359375000, -0.0112304687500000, -0.0064697265625000, +-0.0124206542968750, -0.0075988769531250, -0.0102844238281250, -0.0068969726562500, +-0.0041198730468750, -0.0035705566406250, -0.0067749023437500, -0.0045776367187500, +-0.0040893554687500, -0.0043640136718750, -0.0030517578125000, -0.0040588378906250, +-0.0034179687500000, -0.0053710937500000, -0.0030212402343750, -0.0061645507812500, +-0.0032958984375000, -0.0051574707031250, -0.0029296875000000, -0.0066833496093750, +-0.0032348632812500, -0.0071716308593750, -0.0026245117187500, -0.0079956054687500, +-0.0016174316406250, -0.0090942382812500, -0.0023803710937500, -0.0079956054687500, +-0.0026855468750000, -0.0078430175781250, -0.0015869140625000, -0.0095214843750000, +-0.0035095214843750, -0.0077209472656250, -0.0062255859375000, -0.0047302246093750, +-0.0062255859375000, -0.0054931640625000, -0.0103759765625000, -0.0035400390625000, +-0.0097045898437500, -0.0034179687500000, -0.0085449218750000, -0.0042724609375000, +-0.0108337402343750}, +{-0.0090026855468750, -0.0102539062500000, -0.0097045898437500, -0.0093994140625000, +-0.0110168457031250, -0.0093383789062500, -0.0106506347656250, -0.0097656250000000, +-0.0117797851562500, -0.0097045898437500, -0.0119323730468750, -0.0092468261718750, +-0.0115966796875000, -0.0094604492187500, -0.0130004882812500, -0.0099182128906250, +-0.0119934082031250, -0.0084228515625000, -0.0125427246093750, -0.0087585449218750, +-0.0127563476562500, -0.0081481933593750, -0.0125732421875000, -0.0072326660156250, +-0.0135498046875000, -0.0080566406250000, -0.0112915039062500, -0.0044860839843750, +-0.0122070312500000, -0.0053710937500000, -0.0103149414062500, -0.0045776367187500, +-0.0075683593750000, -0.0012817382812500, -0.0092163085937500, -0.0024414062500000, +-0.0033874511718750, -0.0027770996093750, -0.0039978027343750, -0.0013732910156250, +-0.0024719238281250, -0.0028076171875000, 0.0019226074218750, -0.0044555664062500, +0.0004882812500000, -0.0032043457031250, 0.0047607421875000, -0.0078430175781250, +0.0048217773437500, -0.0071716308593750, 0.0046386718750000, -0.0072326660156250, +0.0070800781250000, -0.0111389160156250, 0.0067138671875000, -0.0104370117187500, +0.0050964355468750, -0.0060424804687500, 0.0062255859375000, -0.0083312988281250, +0.0042114257812500, -0.0071716308593750, 0.0014038085937500, -0.0020751953125000, +0.0027465820312500, -0.0037231445312500, -0.0021667480468750, -0.0041503906250000, +-0.0021667480468750, -0.0025024414062500, -0.0016784667968750, -0.0046691894531250, +-0.0040893554687500, -0.0069580078125000, -0.0033874511718750, -0.0052185058593750, +-0.0011901855468750, -0.0101013183593750, -0.0027770996093750, -0.0103454589843750, +0.0004272460937500, -0.0086669921875000, 0.0043945312500000, -0.0110778808593750, +0.0019226074218750, -0.0119018554687500, 0.0099487304687500, -0.0037841796875000, +0.0099487304687500, -0.0053100585937500, 0.0098571777343750, -0.0057373046875000, +0.0146179199218750, -0.0001831054687500, 0.0134582519531250, -0.0010375976562500, +0.0093994140625000, -0.0047912597656250, 0.0117797851562500, -0.0027160644531250, +0.0080871582031250, -0.0052795410156250, 0.0024414062500000, -0.0108947753906250, +0.0053710937500000, -0.0081787109375000, -0.0031738281250000, -0.0075988769531250, +-0.0022583007812500, -0.0103454589843750, -0.0059509277343750, -0.0076599121093750, +-0.0133056640625000, -0.0041198730468750, -0.0093688964843750, -0.0066833496093750, +-0.0163269042968750, -0.0007934570312500, -0.0183715820312500, -0.0004272460937500, +-0.0161437988281250, -0.0010681152343750, -0.0173950195312500, 0.0011596679687500, +-0.0179443359375000, 0.0002746582031250, -0.0122985839843750, -0.0006408691406250, +-0.0138854980468750, 0.0006103515625000, -0.0111694335937500, -0.0007934570312500, +-0.0057678222656250, -0.0032958984375000, -0.0088195800781250, -0.0024108886718750, +-0.0021667480468750, -0.0047302246093750, -0.0012817382812500, -0.0049133300781250, +-0.0027465820312500, -0.0039672851562500, -0.0007934570312500, -0.0049133300781250, +-0.0007019042968750, -0.0057983398437500, -0.0028991699218750, -0.0036315917968750, +-0.0025634765625000, -0.0033264160156250, -0.0034179687500000, -0.0040588378906250, +-0.0052490234375000, -0.0039367675781250, -0.0051879882812500, -0.0043945312500000, +-0.0089416503906250, -0.0065917968750000, -0.0073547363281250, -0.0060119628906250, +-0.0086364746093750, -0.0062255859375000, -0.0125427246093750, -0.0079040527343750, +-0.0102539062500000, -0.0074462890625000, -0.0106506347656250, -0.0076599121093750, +-0.0136108398437500, -0.0081176757812500, -0.0092468261718750, -0.0080566406250000, +-0.0046386718750000, -0.0079956054687500, -0.0085144042968750, -0.0080261230468750, +-0.0027770996093750, -0.0063171386718750, -0.0007019042968750, -0.0075988769531250, +-0.0028076171875000, -0.0065002441406250, -0.0028686523437500, -0.0035705566406250, +-0.0021362304687500, -0.0048828125000000, -0.0041809082031250, -0.0055541992187500, +-0.0044860839843750, -0.0041809082031250, -0.0032653808593750, -0.0070190429687500, +-0.0031127929687500, -0.0094299316406250, -0.0039672851562500, -0.0072021484375000, +-0.0033264160156250, -0.0153503417968750, -0.0018310546875000, -0.0152282714843750, +-0.0041809082031250, -0.0148925781250000, -0.0063781738281250, -0.0196228027343750, +-0.0041503906250000, -0.0187683105468750, -0.0075073242187500, -0.0152893066406250, +-0.0097351074218750, -0.0180664062500000, -0.0057983398437500, -0.0144042968750000, +-0.0030822753906250, -0.0088195800781250, -0.0061340332031250, -0.0120544433593750, +-0.0025939941406250, -0.0028076171875000, -0.0004882812500000, -0.0034179687500000, +-0.0038146972656250, -0.0012817382812500, -0.0048217773437500, 0.0051879882812500, +-0.0024414062500000, 0.0024108886718750, -0.0111999511718750, 0.0080871582031250, +-0.0108642578125000, 0.0089416503906250, -0.0093688964843750, 0.0079956054687500, +-0.0132751464843750, 0.0101318359375000, -0.0134277343750000, 0.0100402832031250, +-0.0118103027343750, 0.0070800781250000, -0.0118103027343750, 0.0081481933593750, +-0.0123901367187500, 0.0061035156250000, -0.0118103027343750, 0.0025024414062500, +-0.0119323730468750, 0.0041809082031250, -0.0154418945312500, 0.0006408691406250, +-0.0144042968750000, -0.0002746582031250, -0.0148925781250000, 0.0011596679687500, +-0.0181274414062500, 0.0007934570312500, -0.0175170898437500, 0.0003051757812500, +-0.0170898437500000, 0.0044860839843750, -0.0178222656250000, 0.0046691894531250, +-0.0170898437500000, 0.0056457519531250, -0.0162963867187500, 0.0086669921875000, +-0.0168762207031250, 0.0082702636718750, -0.0142211914062500, 0.0084228515625000, +-0.0147399902343750, 0.0098571777343750, -0.0142517089843750, 0.0085449218750000, +-0.0123901367187500, 0.0070495605468750, -0.0131835937500000, 0.0084838867187500, +-0.0108337402343750, 0.0051574707031250, -0.0114746093750000, 0.0053710937500000, +-0.0104980468750000, 0.0049743652343750, -0.0081787109375000, 0.0029602050781250, +-0.0093078613281250, 0.0039978027343750, -0.0075073242187500, 0.0035400390625000, +-0.0073547363281250, 0.0033264160156250, -0.0067749023437500, 0.0044250488281250, +-0.0057067871093750, 0.0051879882812500, -0.0065002441406250, 0.0050048828125000, +-0.0043029785156250, 0.0066223144531250, -0.0040893554687500, 0.0069274902343750, +-0.0045776367187500, 0.0083007812500000, -0.0038146972656250, 0.0100708007812500, +-0.0036010742187500, 0.0100708007812500, -0.0045471191406250, 0.0133056640625000, +-0.0043640136718750, 0.0140686035156250, -0.0039978027343750, 0.0151977539062500, +-0.0042724609375000, 0.0175170898437500, -0.0042419433593750, 0.0177612304687500, +-0.0038757324218750, 0.0184936523437500, -0.0035400390625000, 0.0200805664062500, +-0.0043029785156250, 0.0200195312500000, -0.0045776367187500, 0.0197448730468750, +-0.0039062500000000, 0.0211181640625000, -0.0062255859375000, 0.0197448730468750, +-0.0059509277343750, 0.0210876464843750, -0.0062866210937500, 0.0209960937500000, +-0.0078430175781250, 0.0199279785156250, -0.0071716308593750, 0.0215759277343750, +-0.0083007812500000, 0.0190429687500000, -0.0083923339843750, 0.0204467773437500, +-0.0087280273437500, 0.0197448730468750, -0.0094604492187500, 0.0177917480468750, +-0.0092773437500000, 0.0199584960937500, -0.0106201171875000, 0.0156555175781250, +-0.0107421875000000, 0.0178527832031250, -0.0107727050781250, 0.0168762207031250, +-0.0115966796875000, 0.0134277343750000, -0.0115051269531250, 0.0166015625000000, +-0.0106506347656250, 0.0111694335937500, -0.0111694335937500, 0.0121459960937500, +-0.0103454589843750, 0.0108947753906250, -0.0091552734375000, 0.0072631835937500, +-0.0097351074218750, 0.0094299316406250, -0.0077209472656250, 0.0026245117187500, +-0.0078735351562500, 0.0041503906250000, -0.0071105957031250, 0.0026855468750000, +-0.0053405761718750, -0.0021972656250000, -0.0059509277343750, 0.0008239746093750, +-0.0048828125000000, -0.0048522949218750, -0.0043029785156250, -0.0048522949218750, +-0.0047302246093750, -0.0042419433593750, -0.0046691894531250, -0.0076599121093750, +-0.0042724609375000, -0.0073852539062500, -0.0053405761718750, -0.0039672851562500, +-0.0047607421875000, -0.0065307617187500, -0.0057373046875000, -0.0023193359375000, +-0.0068664550781250, 0.0026245117187500, -0.0057983398437500, -0.0014953613281250, +-0.0093688964843750, 0.0111389160156250, -0.0087890625000000, 0.0082702636718750, +-0.0094909667968750, 0.0113830566406250, -0.0121765136718750, 0.0217285156250000, +-0.0111083984375000, 0.0164489746093750, -0.0124206542968750, 0.0230407714843750, +-0.0126647949218750, 0.0244445800781250, -0.0127563476562500, 0.0223999023437500, +-0.0130615234375000, 0.0239562988281250, -0.0127563476562500, 0.0245971679687500, +-0.0145568847656250, 0.0213012695312500, -0.0141296386718750, 0.0215759277343750, +-0.0144042968750000, 0.0212097167968750, -0.0163269042968750, 0.0201110839843750, +-0.0158691406250000, 0.0206909179687500, -0.0140380859375000, 0.0153808593750000, +-0.0151977539062500, 0.0173645019531250, -0.0143432617187500, 0.0147094726562500, +-0.0116882324218750, 0.0090332031250000, -0.0126342773437500, 0.0124206542968750, +-0.0130004882812500, 0.0076599121093750, -0.0120849609375000, 0.0064697265625000, +-0.0129699707031250, 0.0074157714843750, -0.0144653320312500, 0.0061035156250000, +-0.0137023925781250, 0.0059509277343750, -0.0145568847656250, 0.0080871582031250, +-0.0155334472656250, 0.0068359375000000, -0.0135192871093750, 0.0088500976562500, +-0.0127563476562500, 0.0114440917968750, -0.0140991210937500, 0.0092468261718750, +-0.0064086914062500, 0.0153503417968750, -0.0081176757812500, 0.0148925781250000, +-0.0057067871093750, 0.0142822265625000, 0.0009765625000000, 0.0185241699218750, +-0.0018920898437500, 0.0181274414062500, 0.0031738281250000, 0.0121154785156250, +0.0036926269531250, 0.0161743164062500, 0.0021667480468750, 0.0086059570312500, +0.0048217773437500, -0.0011596679687500, 0.0050048828125000, 0.0058898925781250, +-0.0035705566406250, -0.0108947753906250, -0.0017700195312500, -0.0101928710937500, +-0.0026550292968750, -0.0135803222656250, -0.0089111328125000, -0.0252990722656250, +-0.0072631835937500, -0.0191650390625000, -0.0089721679687500, -0.0213928222656250, +-0.0101013183593750, -0.0265502929687500, -0.0074768066406250, -0.0197753906250000, +-0.0068969726562500, -0.0133361816406250, -0.0087280273437500, -0.0178222656250000, +-0.0005798339843750, -0.0052795410156250, -0.0010986328125000, -0.0037231445312500, +-0.0012207031250000, -0.0073852539062500, 0.0033569335937500, -0.0042114257812500, +0.0023498535156250, -0.0025024414062500, 0.0016479492187500, -0.0084533691406250, +0.0024414062500000, -0.0089721679687500, 0.0014953613281250, -0.0075378417968750, +-0.0007934570312500, -0.0093994140625000, 0.0051269531250000, -0.0077209472656250, +-0.0088806152343750, -0.0087585449218750, -0.0025634765625000, -0.0093688964843750, +-0.0078735351562500, -0.0069274902343750, -0.0174560546875000, -0.0057678222656250, +-0.0130615234375000, -0.0075683593750000, -0.0184326171875000, -0.0020751953125000, +-0.0192871093750000, -0.0012207031250000, -0.0191650390625000, -0.0043945312500000, +-0.0210876464843750, -0.0035705566406250, -0.0200805664062500, -0.0015563964843750, +-0.0226135253906250, -0.0094604492187500, -0.0226440429687500, -0.0099182128906250, +-0.0214538574218750, -0.0091247558593750, -0.0229187011718750, -0.0122985839843750, +-0.0229187011718750, -0.0118713378906250, -0.0159301757812500, -0.0102539062500000, +-0.0196533203125000, -0.0106811523437500, -0.0112915039062500, -0.0112609863281250, +-0.0011901855468750, -0.0111083984375000, -0.0094604492187500, -0.0104675292968750, +0.0102539062500000}, +{-0.0071105957031250, 0.0089721679687500, -0.0105590820312500, -0.0025329589843750, +-0.0108032226562500, -0.0017700195312500, -0.0107421875000000, -0.0018310546875000, +-0.0121459960937500, -0.0090637207031250, -0.0115966796875000, -0.0066833496093750, +-0.0127563476562500, -0.0052795410156250, -0.0124206542968750, -0.0081481933593750, +-0.0129394531250000, -0.0037231445312500, -0.0142211914062500, 0.0008850097656250, +-0.0133666992187500, -0.0029296875000000, -0.0137329101562500, 0.0074157714843750, +-0.0144958496093750, 0.0061950683593750, -0.0133056640625000, 0.0092468261718750, +-0.0121459960937500, 0.0166625976562500, -0.0131225585937500, 0.0127258300781250, +-0.0122375488281250, 0.0228881835937500, -0.0112609863281250, 0.0229797363281250, +-0.0125427246093750, 0.0220947265625000, -0.0137023925781250, 0.0272521972656250, +-0.0127563476562500, 0.0260620117187500, -0.0140991210937500, 0.0221252441406250, +-0.0146789550781250, 0.0244140625000000, -0.0143127441406250, 0.0217285156250000, +-0.0144042968750000, 0.0165710449218750, -0.0145263671875000, 0.0188598632812500, +-0.0131225585937500, 0.0133361816406250, -0.0143127441406250, 0.0138244628906250, +-0.0113525390625000, 0.0120849609375000, -0.0085754394531250, 0.0081176757812500, +-0.0112304687500000, 0.0101623535156250, -0.0035095214843750, 0.0042114257812500, +-0.0035095214843750, 0.0039672851562500, -0.0036926269531250, 0.0051879882812500, +0.0003967285156250, 0.0024719238281250, -0.0008544921875000, 0.0020446777343750, +-0.0023193359375000, 0.0060424804687500, 0.0001831054687500, 0.0052185058593750, +-0.0044555664062500, 0.0075073242187500, -0.0103759765625000, 0.0116882324218750, +-0.0061950683593750, 0.0095520019531250, -0.0097045898437500, 0.0115356445312500, +-0.0128479003906250, 0.0132446289062500, -0.0098876953125000, 0.0106506347656250, +-0.0076293945312500, 0.0106811523437500, -0.0092468261718750, 0.0118713378906250, +-0.0040893554687500, -0.0033264160156250, -0.0049133300781250, 0.0009765625000000, +-0.0032043457031250, -0.0046997070312500, 0.0010375976562500, -0.0192260742187500, +-0.0009765625000000, -0.0123291015625000, 0.0031127929687500, -0.0212402343750000, +0.0026550292968750, -0.0256652832031250, 0.0043945312500000, -0.0191955566406250, +0.0082702636718750, -0.0166625976562500, 0.0058288574218750, -0.0204772949218750, +0.0069885253906250, -0.0115661621093750, 0.0096130371093750, -0.0110473632812500, +0.0065307617187500, -0.0119323730468750, 0.0004882812500000, -0.0065612792968750, +-0.0120544433593750, -0.0219421386718750, -0.0196228027343750, -0.0101928710937500, +-0.0203247070312500, -0.0137634277343750, -0.0183105468750000, -0.0122070312500000, +-0.0177612304687500, -0.0068664550781250, -0.0187988281250000, -0.0079650878906250, +-0.0169982910156250, -0.0068359375000000, -0.0174560546875000, -0.0077514648437500, +-0.0151367187500000, -0.0045166015625000, -0.0138854980468750, -0.0011596679687500, +-0.0156860351562500, -0.0045776367187500, -0.0033569335937500, 0.0002746582031250, +-0.0065307617187500, 0.0028686523437500, -0.0017395019531250, -0.0012817382812500, +0.0103759765625000, -0.0029296875000000, 0.0049743652343750, -0.0004882812500000, +0.0114746093750000, -0.0094604492187500, 0.0151062011718750, -0.0092163085937500, +0.0090942382812500, -0.0087890625000000, 0.0077209472656250, -0.0136413574218750, +0.0122985839843750, -0.0128784179687500, -0.0024108886718750, -0.0110778808593750, +-0.0019226074218750, -0.0124511718750000, -0.0007629394531250, -0.0098571777343750, +-0.0084533691406250, -0.0070190429687500, -0.0067138671875000, -0.0093383789062500, +-0.0018310546875000, -0.0028381347656250, -0.0053100585937500, -0.0032348632812500, +-0.0007324218750000, -0.0020141601562500, 0.0062255859375000, 0.0022277832031250, +0.0021667480468750, -0.0000305175781250, 0.0137329101562500, 0.0022277832031250, +0.0133972167968750, 0.0038757324218750, 0.0143127441406250, 0.0016479492187500, +0.0205383300781250, -0.0000610351562500, 0.0183715820312500, 0.0013732910156250, +0.0247497558593750, -0.0003051757812500, 0.0232543945312500, -0.0010681152343750, +0.0240173339843750, -0.0006103515625000, 0.0294189453125000, -0.0005798339843750, +0.0272521972656250, -0.0007629394531250, 0.0263366699218750, -0.0002136230468750, +0.0281982421875000, 0.0001220703125000, 0.0249023437500000, -0.0014038085937500, +0.0225219726562500, -0.0015869140625000, 0.0249633789062500, -0.0005798339843750, +0.0137939453125000, -0.0065612792968750, 0.0172119140625000, -0.0056762695312500, +0.0121765136718750, -0.0065917968750000, 0.0014038085937500, -0.0108642578125000, +0.0078735351562500, -0.0093383789062500, -0.0030517578125000, -0.0107727050781250, +-0.0047607421875000, -0.0111389160156250, -0.0021362304687500, -0.0110168457031250, +-0.0060119628906250, -0.0115966796875000, -0.0064697265625000, -0.0113525390625000, +0.0009460449218750, -0.0112304687500000, -0.0021972656250000, -0.0115356445312500, +0.0025024414062500, -0.0113525390625000, 0.0100097656250000, -0.0108947753906250, +0.0046997070312500, -0.0111083984375000, 0.0188293457031250, -0.0120239257812500, +0.0171203613281250, -0.0113830566406250, 0.0194702148437500, -0.0124511718750000, +0.0289611816406250, -0.0142211914062500, 0.0242309570312500, -0.0133056640625000, +0.0309143066406250, -0.0146179199218750, 0.0314331054687500, -0.0152282714843750, +0.0303955078125000, -0.0145568847656250, 0.0333557128906250, -0.0142211914062500, +0.0327758789062500, -0.0144653320312500, 0.0308532714843750, -0.0142211914062500, +0.0325012207031250, -0.0136108398437500, 0.0306091308593750, -0.0140380859375000, +0.0280456542968750, -0.0145568847656250, 0.0304870605468750, -0.0140075683593750, +0.0254211425781250, -0.0142822265625000, 0.0263671875000000, -0.0143127441406250, +0.0252380371093750, -0.0141906738281250, 0.0219116210937500, -0.0140380859375000, +0.0244750976562500, -0.0139770507812500, 0.0194091796875000, -0.0150146484375000, +0.0204162597656250, -0.0147705078125000, 0.0191345214843750, -0.0152282714843750, +0.0154418945312500, -0.0164184570312500, 0.0178833007812500, -0.0162353515625000, +0.0135803222656250, -0.0162658691406250, 0.0139770507812500, -0.0168151855468750, +0.0132446289062500, -0.0164794921875000, 0.0104370117187500, -0.0159606933593750, +0.0121154785156250, -0.0163574218750000, 0.0094604492187500, -0.0152587890625000, +0.0095825195312500, -0.0156250000000000, 0.0100097656250000, -0.0148010253906250, +0.0089721679687500, -0.0134887695312500, 0.0093688964843750, -0.0142211914062500, +0.0092468261718750, -0.0122985839843750, 0.0092773437500000, -0.0119934082031250, +0.0096435546875000, -0.0122985839843750, 0.0097961425781250, -0.0116882324218750, +0.0102233886718750, -0.0115356445312500, 0.0111083984375000, -0.0114746093750000, +0.0110473632812500, -0.0121154785156250, 0.0117187500000000, -0.0106811523437500, +0.0126342773437500, -0.0095520019531250, 0.0123596191406250, -0.0107116699218750, +0.0131835937500000, -0.0071411132812500, 0.0136413574218750, -0.0077209472656250, +0.0138549804687500, -0.0064086914062500, 0.0140380859375000, -0.0036621093750000, +0.0144348144531250, -0.0054016113281250, 0.0162353515625000, -0.0011291503906250, +0.0158691406250000, -0.0008544921875000, 0.0174560546875000, -0.0015258789062500, +0.0197143554687500, 0.0004882812500000, 0.0193176269531250, 0.0007324218750000, +0.0234069824218750, -0.0016479492187500, 0.0231018066406250, -0.0010681152343750, +0.0247802734375000, -0.0012817382812500, 0.0283508300781250, -0.0027770996093750, +0.0268554687500000, -0.0022888183593750, 0.0292053222656250, -0.0037536621093750, +0.0303344726562500, -0.0037231445312500, 0.0292968750000000, -0.0032653808593750, +0.0295410156250000, -0.0043640136718750, 0.0299682617187500, -0.0047912597656250, +0.0261840820312500, -0.0016784667968750, 0.0274353027343750, -0.0019836425781250, +0.0240173339843750, -0.0035095214843750, 0.0195007324218750, -0.0020446777343750, +0.0220642089843750, -0.0011291503906250, 0.0120849609375000, -0.0062561035156250, +0.0129394531250000, -0.0057373046875000, 0.0099182128906250, -0.0060729980468750, +0.0024719238281250, -0.0090332031250000, 0.0061035156250000, -0.0083618164062500, +0.0006103515625000, -0.0110473632812500, -0.0012817382812500, -0.0105895996093750, +0.0011291503906250, -0.0108337402343750, 0.0009155273437500, -0.0135803222656250, +-0.0001525878906250, -0.0129089355468750, 0.0042419433593750, -0.0096435546875000, +0.0042724609375000, -0.0111999511718750, 0.0048522949218750, -0.0108337402343750, +0.0076599121093750, -0.0071411132812500, 0.0069885253906250, -0.0077514648437500, +0.0071105957031250, -0.0099487304687500, 0.0075988769531250, -0.0085144042968750, +0.0061035156250000, -0.0105590820312500, 0.0049743652343750, -0.0142517089843750, +0.0058288574218750, -0.0118408203125000, 0.0032043457031250, -0.0118103027343750, +0.0026550292968750, -0.0151062011718750, 0.0036621093750000, -0.0109558105468750, +0.0031433105468750, -0.0062866210937500, 0.0025634765625000, -0.0097045898437500, +0.0055847167968750, -0.0014953613281250, 0.0051879882812500, -0.0010681152343750, +0.0059814453125000, -0.0023193359375000, 0.0084228515625000, 0.0007324218750000, +0.0074157714843750, 0.0007934570312500, 0.0079956054687500, 0.0005493164062500, +0.0096130371093750, 0.0003662109375000, 0.0068664550781250, 0.0000000000000000, +0.0046691894531250, -0.0003662109375000, 0.0064697265625000, -0.0001831054687500, +-0.0013732910156250, 0.0009460449218750, 0.0005187988281250, 0.0010070800781250, +-0.0032348632812500, -0.0004272460937500, -0.0101928710937500, -0.0008239746093750, +-0.0061645507812500, 0.0003662109375000, -0.0179748535156250, -0.0017395019531250, +-0.0175476074218750, -0.0018310546875000, -0.0172424316406250, -0.0017700195312500, +-0.0244140625000000, -0.0028686523437500, -0.0226745605468750, -0.0028076171875000, +-0.0174560546875000, -0.0026855468750000, -0.0208740234375000, -0.0026550292968750, +-0.0165710449218750, -0.0026855468750000, -0.0075378417968750, -0.0027465820312500, +-0.0087280273437500, -0.0028381347656250, -0.0013427734375000, -0.0026550292968750, +-0.0021972656250000, -0.0027465820312500, -0.0039367675781250, -0.0028686523437500, +-0.0000915527343750, -0.0022583007812500, -0.0000305175781250, -0.0022888183593750, +-0.0042724609375000, -0.0058288574218750, -0.0030517578125000, -0.0036621093750000, +-0.0040283203125000, -0.0070800781250000, -0.0075988769531250, -0.0120849609375000, +-0.0060729980468750, -0.0086975097656250, -0.0063781738281250, -0.0171508789062500, +-0.0080871582031250, -0.0179443359375000, -0.0051879882812500, -0.0163574218750000, +-0.0026550292968750, -0.0194091796875000, -0.0050659179687500, -0.0192565917968750, +0.0007324218750000, -0.0152893066406250, 0.0006713867187500, -0.0168151855468750, +0.0010375976562500, -0.0138244628906250, 0.0046997070312500, -0.0092163085937500, +0.0032958984375000, -0.0122985839843750, 0.0015258789062500, -0.0061950683593750, +0.0034484863281250, -0.0058898925781250, 0.0006713867187500, -0.0054321289062500, +-0.0032043457031250, -0.0023193359375000, -0.0005798339843750, -0.0034484863281250, +-0.0049743652343750, -0.0015563964843750, -0.0054016113281250, -0.0009765625000000, +-0.0059814453125000, -0.0013427734375000, -0.0083312988281250, -0.0008544921875000, +-0.0066528320312500, -0.0005798339843750, -0.0072326660156250, -0.0010070800781250, +-0.0094909667968750, -0.0014343261718750, -0.0070190429687500, -0.0000305175781250, +-0.0039062500000000, 0.0007019042968750, -0.0060424804687500, -0.0002441406250000, +-0.0027465820312500, 0.0039062500000000, -0.0015258789062500, 0.0030822753906250, +-0.0049133300781250}, +{0.0245666503906250, -0.0124816894531250, 0.0201721191406250, -0.0104064941406250, +0.0142822265625000, -0.0105590820312500, 0.0176696777343750, -0.0120239257812500, +0.0086059570312500, -0.0093994140625000, 0.0078735351562500, -0.0081176757812500, +0.0075988769531250, -0.0100402832031250, 0.0028686523437500, -0.0106811523437500, +0.0038452148437500, -0.0095825195312500, 0.0039672851562500, -0.0136413574218750, +0.0024414062500000, -0.0136718750000000, 0.0050659179687500, -0.0121154785156250, +0.0075378417968750, -0.0142211914062500, 0.0053710937500000, -0.0151672363281250, +0.0106811523437500, -0.0080871582031250, 0.0108947753906250, -0.0095520019531250, +0.0102233886718750, -0.0081176757812500, 0.0126342773437500, -0.0024719238281250, +0.0122680664062500, -0.0047607421875000, 0.0099792480468750, -0.0036315917968750, +0.0105895996093750, -0.0024719238281250, 0.0098876953125000, -0.0021362304687500, +0.0079956054687500, -0.0023498535156250, 0.0089721679687500, -0.0033264160156250, +0.0080261230468750, -0.0027160644531250, 0.0078430175781250, -0.0021667480468750, +0.0075073242187500, -0.0018920898437500, 0.0074462890625000, -0.0017089843750000, +0.0081787109375000, -0.0022583007812500, 0.0052490234375000, -0.0042419433593750, +0.0062866210937500, -0.0031433105468750, 0.0043029785156250, -0.0026855468750000, +0.0014038085937500, -0.0046997070312500, 0.0033874511718750, -0.0046997070312500, +-0.0028991699218750, -0.0021667480468750, -0.0014648437500000, -0.0029907226562500, +-0.0054016113281250, -0.0021667480468750, -0.0115966796875000, 0.0003356933593750, +-0.0074768066406250, -0.0006713867187500, -0.0176696777343750, 0.0003662109375000, +-0.0178833007812500, 0.0007934570312500, -0.0168457031250000, 0.0000915527343750, +-0.0226135253906250, 0.0002136230468750, -0.0213623046875000, -0.0001831054687500, +-0.0123596191406250, -0.0046081542968750, -0.0178222656250000, -0.0015563964843750, +-0.0136413574218750, -0.0051574707031250, -0.0035400390625000, -0.0109252929687500, +-0.0102539062500000, -0.0066833496093750, -0.0013732910156250, -0.0171813964843750, +0.0014038085937500, -0.0178833007812500, -0.0021667480468750, -0.0167541503906250, +-0.0018005371093750, -0.0217285156250000, -0.0000915527343750, -0.0208740234375000, +-0.0035400390625000, -0.0148620605468750, -0.0044555664062500, -0.0171508789062500, +-0.0033264160156250, -0.0143127441406250, -0.0037841796875000, -0.0078430175781250, +-0.0041503906250000, -0.0102844238281250, -0.0018615722656250, -0.0046081542968750, +-0.0021972656250000, -0.0043640136718750, -0.0015563964843750, -0.0046081542968750, +-0.0001831054687500, -0.0018615722656250, -0.0011901855468750, -0.0021972656250000, +0.0014953613281250, -0.0016784667968750, 0.0017089843750000, -0.0014953613281250, +0.0006408691406250, -0.0011596679687500, 0.0018615722656250, -0.0008239746093750, +0.0020446777343750, -0.0008544921875000, -0.0036926269531250, 0.0004577636718750, +-0.0016174316406250, -0.0000915527343750, -0.0038146972656250, 0.0013732910156250, +-0.0096740722656250, 0.0030822753906250, -0.0072326660156250, 0.0020751953125000, +-0.0112304687500000, 0.0071105957031250, -0.0126342773437500, 0.0071105957031250, +-0.0097351074218750, 0.0072021484375000, -0.0096435546875000, 0.0100402832031250, +-0.0117187500000000, 0.0096130371093750, -0.0054931640625000, 0.0094299316406250, +-0.0057067871093750, 0.0097351074218750, -0.0055541992187500, 0.0092773437500000, +-0.0017395019531250, 0.0086669921875000, -0.0032348632812500, 0.0091552734375000, +-0.0056762695312500, 0.0092163085937500, -0.0031738281250000, 0.0080566406250000, +-0.0050048828125000, 0.0103149414062500, -0.0093383789062500, 0.0122680664062500, +-0.0072631835937500, 0.0105590820312500, -0.0090026855468750, 0.0169067382812500, +-0.0093688964843750, 0.0163879394531250, -0.0090942382812500, 0.0177612304687500, +-0.0097656250000000, 0.0226745605468750, -0.0093688964843750, 0.0209960937500000, +-0.0084228515625000, 0.0220031738281250, -0.0086059570312500, 0.0235290527343750, +-0.0090026855468750, 0.0207214355468750, -0.0085449218750000, 0.0184631347656250, +-0.0079650878906250, 0.0197143554687500, -0.0088806152343750, 0.0126647949218750, +-0.0089111328125000, 0.0130004882812500, -0.0088195800781250, 0.0110473632812500, +-0.0090942382812500, 0.0058593750000000, -0.0087585449218750, 0.0076293945312500, +-0.0089111328125000, 0.0043640136718750, -0.0093994140625000, 0.0032043457031250, +-0.0080871582031250, 0.0039062500000000, -0.0070190429687500, 0.0029907226562500, +-0.0081787109375000, 0.0025939941406250, -0.0059814453125000, 0.0053405761718750, +-0.0053710937500000, 0.0044555664062500, -0.0062866210937500, 0.0052795410156250, +-0.0061950683593750, 0.0076599121093750, -0.0056762695312500, 0.0063171386718750, +-0.0066528320312500, 0.0076293945312500, -0.0069885253906250, 0.0079345703125000, +-0.0064697265625000, 0.0071716308593750, -0.0064086914062500, 0.0070190429687500, +-0.0068054199218750, 0.0069885253906250, -0.0056457519531250, 0.0059509277343750, +-0.0058288574218750, 0.0055236816406250, -0.0057373046875000, 0.0044860839843750, +-0.0049133300781250, 0.0031738281250000, -0.0052795410156250, 0.0030212402343750, +-0.0052185058593750, 0.0017395019531250, -0.0049133300781250, 0.0009460449218750, +-0.0055236816406250, 0.0000610351562500, -0.0060424804687500, -0.0010070800781250, +-0.0056152343750000, -0.0014953613281250, -0.0068664550781250, -0.0032653808593750, +-0.0068359375000000, -0.0045471191406250, -0.0069885253906250, -0.0048828125000000, +-0.0077819824218750, -0.0056152343750000, -0.0073547363281250, -0.0066833496093750, +-0.0073852539062500, -0.0062255859375000, -0.0076904296875000, -0.0071411132812500, +-0.0072631835937500, -0.0071411132812500, -0.0068359375000000, -0.0067138671875000, +-0.0070800781250000, -0.0078430175781250, -0.0063781738281250, -0.0065612792968750, +-0.0063171386718750, -0.0077819824218750, -0.0063781738281250, -0.0068969726562500, +-0.0062255859375000, -0.0052795410156250, -0.0062255859375000, -0.0071716308593750, +-0.0058898925781250, -0.0035095214843750, -0.0063781738281250, -0.0045776367187500, +-0.0055847167968750, -0.0036621093750000, -0.0046997070312500, -0.0010070800781250, +-0.0055847167968750, -0.0031433105468750, -0.0038757324218750, 0.0012512207031250, +-0.0038146972656250, 0.0005187988281250, -0.0045166015625000, 0.0006713867187500, +-0.0042419433593750, 0.0035095214843750, -0.0042419433593750, 0.0022277832031250, +-0.0055847167968750, 0.0035400390625000, -0.0057067871093750, 0.0040893554687500, +-0.0055541992187500, 0.0033569335937500, -0.0061340332031250, 0.0031738281250000, +-0.0062866210937500, 0.0034179687500000, -0.0055541992187500, 0.0025939941406250, +-0.0055236816406250, 0.0019531250000000, -0.0057983398437500, 0.0030517578125000, +-0.0055236816406250, 0.0032043457031250, -0.0053100585937500, 0.0021362304687500, +-0.0065307617187500, 0.0059814453125000, -0.0060729980468750, 0.0041503906250000, +-0.0065917968750000, 0.0071105957031250, -0.0075988769531250, 0.0116577148437500, +-0.0068969726562500, 0.0081787109375000, -0.0084533691406250, 0.0164184570312500, +-0.0081481933593750, 0.0158386230468750, -0.0086364746093750, 0.0169372558593750, +-0.0098266601562500, 0.0223388671875000, -0.0089721679687500, 0.0197753906250000, +-0.0106506347656250, 0.0218200683593750, -0.0106506347656250, 0.0231323242187500, +-0.0105285644531250, 0.0211181640625000, -0.0114440917968750, 0.0208129882812500, +-0.0111999511718750, 0.0216369628906250, -0.0105285644531250, 0.0142822265625000, +-0.0109252929687500, 0.0167846679687500, -0.0104980468750000, 0.0116882324218750, +-0.0098571777343750, 0.0029907226562500, -0.0101013183593750, 0.0077819824218750, +-0.0082397460937500, -0.0016784667968750, -0.0093383789062500, -0.0034484863281250, +-0.0069885253906250, -0.0014343261718750, -0.0039978027343750, -0.0044250488281250, +-0.0063476562500000, -0.0045776367187500, -0.0009155273437500, 0.0010070800781250, +0.0002136230468750, -0.0011291503906250, -0.0025939941406250, 0.0021057128906250, +-0.0021972656250000, 0.0072937011718750, -0.0007324218750000, 0.0034484863281250, +-0.0062255859375000, 0.0133972167968750, -0.0059509277343750, 0.0121765136718750, +-0.0078430175781250, 0.0135192871093750, -0.0118103027343750, 0.0209655761718750, +-0.0094299316406250, 0.0180053710937500, -0.0130004882812500, 0.0180053710937500, +-0.0145874023437500, 0.0207214355468750, -0.0129699707031250, 0.0170593261718750, +-0.0126342773437500, 0.0135498046875000, -0.0131530761718750, 0.0162353515625000, +-0.0099182128906250, 0.0069274902343750, -0.0116271972656250, 0.0077514648437500, +-0.0082397460937500, 0.0056457519531250, -0.0033569335937500, -0.0007324218750000, +-0.0065307617187500, 0.0024414062500000, 0.0003662109375000, -0.0020446777343750, +0.0012512207031250, -0.0042724609375000, -0.0003051757812500, -0.0013427734375000, +0.0029296875000000, -0.0008544921875000, 0.0028381347656250, -0.0020141601562500, +-0.0064086914062500, 0.0072021484375000, -0.0022583007812500, 0.0048522949218750, +-0.0076599121093750, 0.0068664550781250, -0.0192260742187500, 0.0159606933593750, +-0.0136108398437500, 0.0132446289062500, -0.0199584960937500, 0.0101928710937500, +-0.0227355957031250, 0.0147399902343750, -0.0194396972656250, 0.0081787109375000, +-0.0177307128906250, -0.0074768066406250, -0.0023498535156250, 0.0111694335937500, +0.0138244628906250, 0.0096740722656250, 0.0112609863281250, 0.0182800292968750, +0.0116577148437500, 0.0087890625000000, 0.0179443359375000, -0.0026855468750000, +0.0170593261718750, 0.0040893554687500, 0.0086669921875000, -0.0076599121093750, +0.0144958496093750, -0.0098876953125000, 0.0064086914062500, -0.0076904296875000, +-0.0062561035156250, -0.0103759765625000, 0.0023193359375000, -0.0102844238281250, +-0.0142822265625000, -0.0103759765625000, -0.0174865722656250, -0.0099182128906250, +-0.0114440917968750, -0.0094604492187500, -0.0155944824218750, -0.0098876953125000, +-0.0176086425781250, -0.0099487304687500, -0.0006103515625000, -0.0078735351562500, +-0.0046386718750000, -0.0087280273437500, 0.0001220703125000, -0.0075683593750000, +0.0151062011718750, -0.0044250488281250, 0.0088195800781250, -0.0059509277343750, +0.0144653320312500, -0.0081787109375000, 0.0173645019531250, -0.0056152343750000, +0.0148315429687500, -0.0087890625000000, 0.0144348144531250, -0.0140991210937500, +0.0154418945312500, -0.0112609863281250, 0.0122985839843750, -0.0144653320312500, +0.0125427246093750, -0.0176391601562500, 0.0118103027343750, -0.0119018554687500, +0.0100708007812500, -0.0083618164062500, 0.0108337402343750, -0.0128173828125000, +0.0070800781250000, -0.0010375976562500, 0.0084228515625000, -0.0004577636718750, +0.0049438476562500, -0.0012817382812500, 0.0003967285156250, 0.0040283203125000, +0.0042114257812500, 0.0028076171875000, -0.0034790039062500, 0.0000000000000000, +-0.0047912597656250, 0.0014038085937500, -0.0024719238281250, 0.0003967285156250, +-0.0043640136718750, -0.0029296875000000, -0.0048522949218750, -0.0020141601562500, +0.0001525878906250, -0.0012512207031250, -0.0023193359375000, -0.0016479492187500, +0.0019531250000000, -0.0020446777343750, 0.0078125000000000, -0.0015869140625000, +0.0032043457031250, -0.0011901855468750, 0.0153808593750000, -0.0020446777343750, +0.0144042968750000, -0.0026245117187500, 0.0155639648437500, -0.0019226074218750, +0.0230407714843750, -0.0010986328125000, 0.0198974609375000, -0.0016784667968750, +0.0238647460937500, -0.0023498535156250, 0.0243225097656250, -0.0011596679687500, +0.0243530273437500, -0.0029296875000000, 0.0261230468750000, -0.0052490234375000, +0.0252380371093750}, +{-0.0120239257812500, -0.0025329589843750, -0.0101928710937500, -0.0055236816406250, +-0.0104980468750000, 0.0045471191406250, -0.0120544433593750, 0.0039367675781250, +-0.0102844238281250, 0.0051574707031250, -0.0084533691406250, 0.0114746093750000, +-0.0098266601562500, 0.0092468261718750, -0.0063171386718750, 0.0123596191406250, +-0.0054016113281250, 0.0135192871093750, -0.0075073242187500, 0.0121765136718750, +-0.0071105957031250, 0.0121765136718750, -0.0058593750000000, 0.0122375488281250, +-0.0121154785156250, 0.0094909667968750, -0.0104370117187500, 0.0107116699218750, +-0.0129394531250000, 0.0086059570312500, -0.0186767578125000, 0.0054626464843750, +-0.0153808593750000, 0.0069274902343750, -0.0207519531250000, -0.0005798339843750, +-0.0226745605468750, 0.0002136230468750, -0.0189514160156250, 0.0011901855468750, +-0.0188903808593750, -0.0041198730468750, -0.0207824707031250, -0.0037231445312500, +-0.0099182128906250, 0.0042114257812500, -0.0127258300781250, 0.0012207031250000, +-0.0086059570312500, 0.0048522949218750, 0.0083007812500000, 0.0188598632812500, +0.0136108398437500, -0.0021362304687500, 0.0010375976562500, 0.0049133300781250, +0.0097961425781250, -0.0009765625000000, 0.0010986328125000, 0.0032043457031250, +-0.0116882324218750, 0.0120849609375000, -0.0040588378906250, 0.0092163085937500, +-0.0124206542968750, 0.0083923339843750, -0.0173950195312500, 0.0123901367187500, +-0.0099182128906250, 0.0063781738281250, -0.0076599121093750, -0.0003356933593750, +-0.0124206542968750, 0.0043334960937500, 0.0071411132812500, -0.0065917968750000, +0.0048828125000000, -0.0063171386718750, 0.0074462890625000, -0.0072021484375000, +0.0212097167968750, -0.0135498046875000, 0.0161437988281250, -0.0109863281250000, +0.0172729492187500, -0.0130920410156250, 0.0215759277343750, -0.0136108398437500, +0.0165100097656250, -0.0132751464843750, 0.0110778808593750, -0.0143432617187500, +0.0150146484375000, -0.0140075683593750, 0.0081787109375000, -0.0118408203125000, +0.0077209472656250, -0.0126037597656250, 0.0069580078125000, -0.0119934082031250, +0.0037841796875000, -0.0098571777343750, 0.0054931640625000, -0.0105895996093750, +0.0005187988281250, -0.0105285644531250, 0.0014038085937500, -0.0098266601562500, +-0.0003662109375000, -0.0106201171875000, -0.0044555664062500, -0.0124511718750000, +-0.0020446777343750, -0.0117187500000000, -0.0061950683593750, -0.0075988769531250, +-0.0074462890625000, -0.0104370117187500, -0.0043640136718750, -0.0067138671875000, +-0.0046691894531250, -0.0000610351562500, -0.0068969726562500, -0.0038452148437500, +0.0019226074218750, 0.0018310546875000, 0.0004577636718750, 0.0037536621093750, +0.0024719238281250, 0.0006713867187500, 0.0083923339843750, 0.0005187988281250, +0.0053710937500000, 0.0022277832031250, 0.0131835937500000, -0.0028381347656250, +0.0120544433593750, -0.0039062500000000, 0.0140380859375000, -0.0018920898437500, +0.0203247070312500, -0.0022888183593750, 0.0179138183593750, -0.0033569335937500, +0.0220947265625000, -0.0005798339843750, 0.0225830078125000, -0.0000305175781250, +0.0228576660156250, -0.0005493164062500, 0.0249023437500000, -0.0001525878906250, +0.0237426757812500, -0.0002136230468750, 0.0241394042968750, -0.0003967285156250, +0.0257263183593750, -0.0002746582031250, 0.0229492187500000, -0.0008850097656250, +0.0215148925781250, -0.0010986328125000, 0.0238342285156250, -0.0006103515625000, +0.0140075683593750, -0.0032348632812500, 0.0173034667968750, -0.0025634765625000, +0.0123291015625000, -0.0035400390625000, 0.0036926269531250, -0.0060119628906250, +0.0101013183593750, -0.0046997070312500, -0.0073852539062500, -0.0060119628906250, +-0.0037536621093750, -0.0065612792968750, -0.0086975097656250, -0.0056457519531250, +-0.0221557617187500, -0.0053100585937500, -0.0138549804687500, -0.0056457519531250, +-0.0278930664062500, -0.0045776367187500, -0.0275268554687500, -0.0043334960937500, +-0.0271911621093750, -0.0047302246093750, -0.0344238281250000, -0.0045471191406250, +-0.0311279296875000, -0.0045166015625000, -0.0321655273437500, -0.0061645507812500, +-0.0339965820312500, -0.0055847167968750, -0.0311889648437500, -0.0070495605468750, +-0.0301208496093750, -0.0091247558593750, -0.0329589843750000, -0.0079040527343750, +-0.0252380371093750, -0.0112915039062500, -0.0281982421875000, -0.0115661621093750, +-0.0249328613281250, -0.0113830566406250, -0.0182800292968750, -0.0127868652343750, +-0.0237426757812500, -0.0125427246093750, -0.0114746093750000, -0.0124511718750000, +-0.0149841308593750, -0.0123901367187500, -0.0121765136718750, -0.0126647949218750, +-0.0028991699218750, -0.0128173828125000, -0.0093383789062500, -0.0124511718750000, +0.0010375976562500, -0.0135192871093750, -0.0009460449218750, -0.0133666992187500, +0.0004882812500000, -0.0134887695312500, 0.0069274902343750, -0.0141296386718750, +0.0015258789062500, -0.0138854980468750, 0.0092468261718750, -0.0139160156250000, +0.0072937011718750, -0.0143432617187500, 0.0080871582031250, -0.0136718750000000, +0.0126953125000000, -0.0132141113281250, 0.0081787109375000, -0.0138244628906250, +0.0144042968750000, -0.0117797851562500, 0.0125427246093750, -0.0122985839843750, +0.0126037597656250, -0.0115051269531250, 0.0162048339843750, -0.0097045898437500, +0.0122680664062500, -0.0107421875000000, 0.0146179199218750, -0.0083923339843750, +0.0133056640625000, -0.0080871582031250, 0.0118103027343750, -0.0083007812500000, +0.0123291015625000, -0.0072021484375000, 0.0099792480468750, -0.0070495605468750, +0.0083007812500000, -0.0070800781250000, 0.0084228515625000, -0.0075073242187500, +0.0056457519531250, -0.0060424804687500, 0.0029296875000000, -0.0049438476562500, +0.0031433105468750, -0.0060729980468750, -0.0032653808593750, -0.0030212402343750, +-0.0028076171875000, -0.0028076171875000, -0.0061035156250000, -0.0034484863281250, +-0.0119018554687500, -0.0025329589843750, -0.0104064941406250, -0.0024719238281250, +-0.0184020996093750, -0.0030517578125000, -0.0182800292968750, -0.0032348632812500, +-0.0202331542968750, -0.0029907226562500, -0.0259094238281250, -0.0028686523437500, +-0.0240173339843750, -0.0030822753906250, -0.0266418457031250, -0.0032653808593750, +-0.0278625488281250, -0.0029602050781250, -0.0265197753906250, -0.0031433105468750, +-0.0267639160156250, -0.0035400390625000, -0.0273132324218750, -0.0033264160156250, +-0.0229492187500000, -0.0044250488281250, -0.0241088867187500, -0.0035400390625000, +-0.0216369628906250, -0.0055236816406250, -0.0170898437500000, -0.0078735351562500, +-0.0192260742187500, -0.0057678222656250, -0.0139465332031250, -0.0092773437500000, +-0.0137023925781250, -0.0103759765625000, -0.0133361816406250, -0.0081787109375000, +-0.0106201171875000, -0.0079650878906250, -0.0117492675781250, -0.0093078613281250, +-0.0104064941406250, -0.0059204101562500, -0.0107421875000000, -0.0051574707031250, +-0.0088195800781250, -0.0063476562500000, -0.0074462890625000, -0.0057678222656250, +-0.0090637207031250, -0.0053100585937500, -0.0005493164062500, -0.0081787109375000, +-0.0027770996093750, -0.0075988769531250, 0.0020141601562500, -0.0083312988281250, +0.0106506347656250, -0.0112609863281250, 0.0061950683593750, -0.0104370117187500, +0.0171508789062500, -0.0089416503906250, 0.0181274414062500, -0.0103149414062500, +0.0172424316406250, -0.0092163085937500, 0.0223388671875000, -0.0069885253906250, +0.0211486816406250, -0.0081787109375000, 0.0165405273437500, -0.0055847167968750, +0.0188903808593750, -0.0055541992187500, 0.0150451660156250, -0.0056152343750000, +0.0085449218750000, -0.0045166015625000, 0.0117492675781250, -0.0053710937500000, +0.0058593750000000, -0.0057067871093750, 0.0043945312500000, -0.0044860839843750, +0.0053100585937500, -0.0057678222656250, 0.0038146972656250, -0.0079956054687500, +0.0037231445312500, -0.0072021484375000, 0.0046691894531250, -0.0078125000000000, +0.0042419433593750, -0.0079650878906250, 0.0048217773437500, -0.0068969726562500, +0.0059814453125000, -0.0073547363281250, 0.0053100585937500, -0.0083312988281250, +0.0055236816406250, -0.0038452148437500, 0.0062561035156250, -0.0041809082031250, +0.0053100585937500, -0.0042419433593750, 0.0039978027343750, -0.0016174316406250, +0.0046997070312500, -0.0025634765625000, 0.0043640136718750, -0.0043029785156250, +0.0039672851562500, -0.0021667480468750, 0.0043029785156250, -0.0058288574218750, +0.0047302246093750, -0.0097351074218750, 0.0046997070312500, -0.0063781738281250, +0.0050964355468750, -0.0160217285156250, 0.0048828125000000, -0.0158996582031250, +0.0054931640625000, -0.0155029296875000, 0.0072326660156250, -0.0214843750000000, +0.0069580078125000, -0.0201110839843750, 0.0035400390625000, -0.0127258300781250, +0.0068664550781250, -0.0175476074218750, 0.0027160644531250, -0.0137023925781250, +-0.0021667480468750, -0.0048522949218750, 0.0033569335937500, -0.0096435546875000, +-0.0102844238281250, 0.0003051757812500, -0.0098876953125000, 0.0016784667968750, +-0.0086059570312500, 0.0002746582031250, -0.0153198242187500, 0.0038757324218750, +-0.0139465332031250, 0.0039367675781250, -0.0115356445312500, 0.0021057128906250, +-0.0128479003906250, 0.0022583007812500, -0.0119018554687500, 0.0024414062500000, +-0.0100708007812500, 0.0014648437500000, -0.0114440917968750, 0.0017395019531250, +-0.0073547363281250, 0.0031738281250000, -0.0084838867187500, 0.0025634765625000, +-0.0067138671875000, 0.0033569335937500, -0.0029907226562500, 0.0050354003906250, +-0.0054321289062500, 0.0043640136718750, -0.0012817382812500, 0.0058288574218750, +-0.0007934570312500, 0.0062561035156250, -0.0014953613281250, 0.0052490234375000, +0.0000305175781250, 0.0055236816406250, -0.0000610351562500, 0.0063476562500000, +-0.0015869140625000, 0.0031738281250000, -0.0014953613281250, 0.0035400390625000, +-0.0013122558593750, 0.0036315917968750, -0.0017395019531250, 0.0010375976562500, +-0.0019836425781250, 0.0018310546875000, -0.0034179687500000, 0.0069274902343750, +-0.0021057128906250, 0.0041503906250000, -0.0046386718750000, 0.0079040527343750, +-0.0077819824218750, 0.0151062011718750, -0.0051879882812500, 0.0114135742187500, +-0.0093994140625000, 0.0169982910156250, -0.0112609863281250, 0.0191650390625000, +-0.0074768066406250, 0.0159301757812500, -0.0065002441406250, 0.0158081054687500, +-0.0090026855468750, 0.0172424316406250, -0.0012512207031250, 0.0092468261718750, +-0.0019836425781250, 0.0100708007812500, -0.0010681152343750, 0.0074157714843750, +0.0045166015625000, 0.0008544921875000, 0.0024108886718750, 0.0032958984375000, +0.0008544921875000, -0.0004577636718750, 0.0036621093750000, -0.0021667480468750, +0.0020446777343750, -0.0014038085937500, -0.0017395019531250, -0.0018920898437500, +0.0000305175781250, -0.0028686523437500, -0.0015563964843750, -0.0026550292968750, +-0.0014648437500000, -0.0025634765625000, -0.0020141601562500, -0.0048522949218750, +-0.0031127929687500, -0.0062866210937500, -0.0021057128906250, -0.0058288574218750, +-0.0045776367187500, -0.0112609863281250, -0.0038757324218750, -0.0107727050781250, +-0.0051574707031250, -0.0129089355468750, -0.0076599121093750, -0.0175781250000000, +-0.0057983398437500, -0.0157775878906250, -0.0081787109375000, -0.0193786621093750, +-0.0087585449218750, -0.0203552246093750, -0.0082092285156250, -0.0193786621093750, +-0.0085144042968750, -0.0199584960937500, -0.0085144042968750, -0.0195922851562500, +-0.0095214843750000, -0.0158081054687500, -0.0092163085937500, -0.0162048339843750, +-0.0090942382812500, -0.0131225585937500, -0.0099182128906250, -0.0086059570312500, +-0.0098571777343750, -0.0094299316406250, -0.0088500976562500, -0.0034790039062500, +-0.0090026855468750}, +{0.0030517578125000, -0.0162353515625000, 0.0031738281250000, -0.0160522460937500, +0.0034484863281250, -0.0157470703125000, 0.0033264160156250, -0.0208129882812500, +0.0030822753906250, -0.0197448730468750, 0.0041809082031250, -0.0141296386718750, +0.0040588378906250, -0.0173339843750000, 0.0043640136718750, -0.0130004882812500, +0.0048828125000000, -0.0034790039062500, 0.0048828125000000, -0.0041503906250000, +0.0079650878906250, 0.0038452148437500, 0.0067749023437500, 0.0028381347656250, +0.0072326660156250, 0.0017700195312500, 0.0101623535156250, 0.0062561035156250, +0.0085449218750000, 0.0056152343750000, 0.0071411132812500, 0.0033264160156250, +0.0106811523437500, 0.0043029785156250, 0.0052490234375000, 0.0036315917968750, +-0.0003051757812500, 0.0012207031250000, 0.0050964355468750, 0.0020446777343750, +-0.0074157714843750, 0.0023193359375000, -0.0062561035156250, 0.0015869140625000, +-0.0078430175781250, 0.0024108886718750, -0.0161437988281250, 0.0034790039062500, +-0.0122985839843750, 0.0027160644531250, -0.0155639648437500, 0.0037841796875000, +-0.0184020996093750, 0.0041198730468750, -0.0146789550781250, 0.0037841796875000, +-0.0127258300781250, 0.0038757324218750, -0.0155029296875000, 0.0039062500000000, +-0.0072631835937500, 0.0032043457031250, -0.0085754394531250, 0.0032043457031250, +-0.0069580078125000, 0.0039062500000000, -0.0011596679687500, 0.0032958984375000, +-0.0043640136718750, 0.0027465820312500, 0.0003662109375000, 0.0077819824218750, +0.0014953613281250, 0.0057373046875000, -0.0001220703125000, 0.0087890625000000, +0.0007629394531250, 0.0151062011718750, 0.0012817382812500, 0.0116882324218750, +-0.0010681152343750, 0.0148925781250000, -0.0007324218750000, 0.0180664062500000, +-0.0013427734375000, 0.0131225585937500, -0.0027770996093750, 0.0100097656250000, +-0.0020446777343750, 0.0133972167968750, -0.0048828125000000, 0.0018615722656250, +-0.0046081542968750, 0.0025024414062500, -0.0037841796875000, 0.0010070800781250, +-0.0056762695312500, -0.0065917968750000, -0.0058593750000000, -0.0040893554687500, +-0.0017089843750000, -0.0064392089843750, -0.0030822753906250, -0.0075683593750000, +-0.0011291503906250, -0.0070190429687500, 0.0028381347656250, -0.0068969726562500, +0.0004882812500000, -0.0070495605468750, 0.0049133300781250, -0.0089416503906250, +0.0059509277343750, -0.0080871582031250, 0.0035400390625000, -0.0103759765625000, +0.0040588378906250, -0.0134887695312500, 0.0058288574218750, -0.0118408203125000, +0.0011291503906250, -0.0157165527343750, 0.0014648437500000, -0.0164184570312500, +0.0013122558593750, -0.0148925781250000, -0.0010070800781250, -0.0155639648437500, +0.0000610351562500, -0.0151062011718750, -0.0023803710937500, -0.0093383789062500, +-0.0018310546875000, -0.0105285644531250, -0.0028686523437500, -0.0056762695312500, +-0.0048217773437500, 0.0010070800781250, -0.0034179687500000, -0.0019531250000000, +-0.0080566406250000, 0.0089721679687500, -0.0072326660156250, 0.0092163085937500, +-0.0075683593750000, 0.0127258300781250, -0.0107727050781250, 0.0210876464843750, +-0.0096130371093750, 0.0191955566406250, -0.0096740722656250, 0.0261840820312500, +-0.0100708007812500, 0.0276184082031250, -0.0102233886718750, 0.0282897949218750, +-0.0099487304687500, 0.0317077636718750, -0.0096435546875000, 0.0316467285156250, +-0.0108032226562500, 0.0327148437500000, -0.0108642578125000, 0.0333557128906250, +-0.0107421875000000, 0.0335693359375000, -0.0112304687500000, 0.0337829589843750, +-0.0113220214843750, 0.0335998535156250, -0.0111999511718750, 0.0335388183593750, +-0.0111999511718750, 0.0332336425781250, -0.0112609863281250, 0.0335693359375000, +-0.0112915039062500, 0.0339660644531250, -0.0112915039062500, 0.0336303710937500, +-0.0110473632812500, 0.0336303710937500, -0.0113525390625000, 0.0337524414062500, +-0.0107116699218750, 0.0337829589843750, -0.0101623535156250, 0.0337829589843750, +-0.0108032226562500, 0.0338745117187500, -0.0089111328125000, 0.0339355468750000, +-0.0092163085937500, 0.0339965820312500, -0.0087890625000000, 0.0340270996093750, +-0.0075073242187500, 0.0341796875000000, -0.0080871582031250, 0.0340270996093750, +-0.0067138671875000, 0.0334167480468750, -0.0067749023437500, 0.0336303710937500, +-0.0065307617187500, 0.0331420898437500, -0.0055847167968750, 0.0324707031250000, +-0.0059814453125000, 0.0329589843750000, -0.0058593750000000, 0.0318603515625000, +-0.0053710937500000, 0.0317687988281250, -0.0061950683593750, 0.0308837890625000, +-0.0068969726562500, 0.0299987792968750, -0.0062866210937500, 0.0303649902343750, +-0.0077514648437500, 0.0271606445312500, -0.0077819824218750, 0.0279846191406250, +-0.0077514648437500, 0.0270996093750000, -0.0082702636718750, 0.0245666503906250, +-0.0081176757812500, 0.0263061523437500, -0.0086059570312500, 0.0243225097656250, +-0.0083312988281250, 0.0242309570312500, -0.0087280273437500, 0.0243225097656250, +-0.0095214843750000, 0.0236816406250000, -0.0091247558593750, 0.0238342285156250, +-0.0096740722656250, 0.0223083496093750, -0.0100097656250000, 0.0229492187500000, +-0.0098571777343750, 0.0210571289062500, -0.0099182128906250, 0.0194702148437500, +-0.0100708007812500, 0.0212707519531250, -0.0095520019531250, 0.0136413574218750, +-0.0099487304687500, 0.0160827636718750, -0.0092468261718750, 0.0112915039062500, +-0.0085449218750000, 0.0038452148437500, -0.0091857910156250, 0.0089416503906250, +-0.0066223144531250, -0.0055847167968750, -0.0070495605468750, -0.0021667480468750, +-0.0060729980468750, -0.0074462890625000, -0.0041198730468750, -0.0200195312500000, +-0.0051269531250000, -0.0128173828125000, -0.0017395019531250, -0.0263366699218750, +-0.0024108886718750, -0.0268859863281250, -0.0012207031250000, -0.0253601074218750, +0.0016174316406250, -0.0318908691406250, 0.0000305175781250, -0.0303955078125000, +0.0027160644531250, -0.0253906250000000, 0.0028686523437500, -0.0291442871093750, +0.0031738281250000, -0.0233459472656250, 0.0045166015625000, -0.0154113769531250, +0.0039672851562500, -0.0205993652343750, 0.0061340332031250, -0.0067443847656250, +0.0057983398437500, -0.0065002441406250, 0.0060119628906250, -0.0070190429687500, +0.0079650878906250, 0.0000305175781250, 0.0073242187500000, -0.0015563964843750, +0.0049438476562500, -0.0041503906250000, 0.0066833496093750, -0.0025939941406250, +0.0049743652343750, -0.0029602050781250, 0.0014343261718750, -0.0064086914062500, +0.0028991699218750, -0.0055847167968750, -0.0012207031250000, -0.0003051757812500, +-0.0002441406250000, -0.0029296875000000, -0.0025329589843750, 0.0005187988281250, +-0.0071105957031250, 0.0073242187500000, -0.0046081542968750, 0.0039367675781250, +-0.0071105957031250, 0.0090942382812500, -0.0075683593750000, 0.0108642578125000, +-0.0092773437500000, 0.0090332031250000, -0.0104370117187500, 0.0097961425781250, +-0.0084533691406250, 0.0103454589843750, -0.0160522460937500, 0.0052185058593750, +-0.0152282714843750, 0.0065917968750000, -0.0160217285156250, 0.0049438476562500, +-0.0218811035156250, 0.0001525878906250, -0.0199584960937500, 0.0018615722656250, +-0.0164489746093750, -0.0012512207031250, -0.0199584960937500, -0.0018005371093750, +-0.0154113769531250, -0.0008850097656250, -0.0085144042968750, -0.0018310546875000, +-0.0128479003906250, -0.0021057128906250, -0.0050048828125000, 0.0000000000000000, +-0.0041503906250000, -0.0002746582031250, -0.0044860839843750, 0.0005798339843750, +-0.0017089843750000, 0.0019531250000000, -0.0028381347656250, 0.0012817382812500, +-0.0000305175781250, 0.0050659179687500, -0.0001220703125000, 0.0031127929687500, +0.0002136230468750, 0.0071105957031250, 0.0031738281250000, 0.0129394531250000, +0.0022583007812500, 0.0091857910156250, -0.0039978027343750, 0.0162353515625000, +-0.0007019042968750, 0.0174865722656250, -0.0030517578125000, 0.0149841308593750, +-0.0145568847656250, 0.0162658691406250, -0.0027160644531250, 0.0057983398437500, +0.0156250000000000, 0.0165405273437500, 0.0113220214843750, 0.0158996582031250, +0.0112915039062500, 0.0137329101562500, 0.0190734863281250, 0.0166931152343750, +0.0190734863281250, 0.0179138183593750, 0.0096435546875000, 0.0046386718750000, +0.0128173828125000, 0.0082397460937500, 0.0099182128906250, 0.0046997070312500, +0.0008544921875000, -0.0079956054687500, 0.0046997070312500, -0.0033264160156250, +0.0021057128906250, -0.0026855468750000, -0.0000305175781250, -0.0068359375000000, +0.0012512207031250, -0.0021667480468750, 0.0023193359375000, 0.0046081542968750, +0.0017089843750000, 0.0004577636718750, 0.0016784667968750, 0.0023193359375000, +0.0025634765625000, 0.0061950683593750, 0.0015869140625000, 0.0019226074218750, +-0.0003356933593750, -0.0025024414062500, 0.0007629394531250, 0.0004882812500000, +0.0032348632812500, -0.0060424804687500, 0.0007019042968750, -0.0056762695312500, +0.0030212402343750, -0.0071411132812500, 0.0073852539062500, -0.0112915039062500, +0.0049133300781250, -0.0093383789062500, 0.0087890625000000, -0.0153808593750000, +0.0089721679687500, -0.0144653320312500, 0.0088500976562500, -0.0155334472656250, +0.0108337402343750, -0.0208435058593750, 0.0100708007812500, -0.0187988281250000, +0.0093994140625000, -0.0163574218750000, 0.0101928710937500, -0.0192260742187500, +0.0102844238281250, -0.0149536132812500, 0.0087890625000000, -0.0094604492187500, +0.0086975097656250, -0.0129699707031250, 0.0121154785156250, -0.0043029785156250, +0.0119934082031250, -0.0043334960937500, 0.0091247558593750, -0.0036010742187500, +0.0106506347656250, 0.0008850097656250, 0.0121154785156250, -0.0009460449218750, +-0.0014038085937500, 0.0036010742187500, 0.0036315917968750, 0.0033874511718750, +-0.0036926269531250, 0.0029907226562500, -0.0175476074218750, 0.0060424804687500, +-0.0089111328125000, 0.0055847167968750, -0.0263671875000000, 0.0022277832031250, +-0.0267333984375000, 0.0033264160156250, -0.0254821777343750, 0.0022888183593750, +-0.0342407226562500, -0.0010375976562500, -0.0316162109375000, 0.0000610351562500, +-0.0272521972656250, -0.0002746582031250, -0.0315856933593750, -0.0010375976562500, +-0.0258178710937500, -0.0003356933593750, -0.0185241699218750, 0.0005187988281250, +-0.0239868164062500, 0.0000915527343750, -0.0082092285156250, 0.0003051757812500, +-0.0112609863281250, 0.0007934570312500, -0.0060729980468750, 0.0002746582031250, +0.0063781738281250, -0.0003051757812500, -0.0010986328125000, 0.0001220703125000, +0.0138244628906250, -0.0005493164062500, 0.0136108398437500, -0.0005187988281250, +0.0134887695312500, -0.0010986328125000, 0.0211486816406250, -0.0015258789062500, +0.0181884765625000, -0.0010070800781250, 0.0202941894531250, -0.0036926269531250, +0.0211486816406250, -0.0032958984375000, 0.0202636718750000, -0.0037841796875000, +0.0202636718750000, -0.0059204101562500, 0.0203247070312500, -0.0051879882812500, +0.0202026367187500, -0.0056762695312500, 0.0196228027343750, -0.0059509277343750, +0.0208129882812500, -0.0057373046875000, 0.0216369628906250, -0.0057067871093750, +0.0209350585937500, -0.0057067871093750, 0.0246887207031250, -0.0054321289062500, +0.0234375000000000, -0.0054626464843750, 0.0250244140625000, -0.0053710937500000, +0.0281372070312500, -0.0050354003906250, 0.0258178710937500, -0.0050659179687500, +0.0313415527343750, -0.0058593750000000, 0.0299072265625000, -0.0055541992187500, +0.0314331054687500, -0.0061035156250000, 0.0359191894531250, -0.0073242187500000, +0.0332031250000000, -0.0068969726562500, 0.0384521484375000, -0.0071105957031250, +0.0374145507812500, -0.0076599121093750, 0.0381469726562500, -0.0071716308593750, +0.0415344238281250}, +{-0.0022888183593750, 0.0101013183593750, 0.0016479492187500, 0.0141906738281250, +-0.0008850097656250, 0.0156860351562500, 0.0019226074218750, 0.0023803710937500, +0.0031127929687500, 0.0046386718750000, 0.0024108886718750, 0.0028686523437500, +0.0019531250000000, -0.0072631835937500, 0.0021057128906250, -0.0037536621093750, +0.0049743652343750, -0.0014038085937500, 0.0025939941406250, -0.0043640136718750, +0.0065917968750000, -0.0026855468750000, 0.0121459960937500, 0.0021972656250000, +0.0078735351562500, 0.0009460449218750, 0.0136413574218750, 0.0005493164062500, +0.0156860351562500, 0.0020446777343750, 0.0133056640625000, 0.0002746582031250, +0.0134582519531250, -0.0015563964843750, 0.0146179199218750, 0.0001525878906250, +0.0114440917968750, -0.0047302246093750, 0.0118103027343750, -0.0038757324218750, +0.0111083984375000, -0.0067138671875000, 0.0090942382812500, -0.0107421875000000, +0.0102233886718750, -0.0075988769531250, 0.0079345703125000, -0.0169372558593750, +0.0083007812500000, -0.0171203613281250, 0.0058898925781250, -0.0157165527343750, +0.0048522949218750, -0.0204162597656250, 0.0067749023437500, -0.0197448730468750, +-0.0075073242187500, -0.0126342773437500, -0.0024414062500000, -0.0158386230468750, +-0.0091552734375000, -0.0111999511718750, -0.0239257812500000, -0.0025329589843750, +-0.0153198242187500, -0.0070495605468750, -0.0279235839843750, 0.0005493164062500, +-0.0308837890625000, 0.0015258789062500, -0.0256958007812500, 0.0013122558593750, +-0.0288391113281250, 0.0043029785156250, -0.0311279296875000, 0.0031433105468750, +-0.0162658691406250, 0.0047302246093750, -0.0209350585937500, 0.0055236816406250, +-0.0153503417968750, 0.0041809082031250, -0.0019226074218750, 0.0038146972656250, +-0.0095825195312500, 0.0047607421875000, 0.0037841796875000, 0.0015258789062500, +0.0039367675781250, 0.0016479492187500, 0.0041809082031250, 0.0016479492187500, +0.0108947753906250, -0.0003051757812500, 0.0082702636718750, 0.0002136230468750, +0.0128479003906250, 0.0009460449218750, 0.0127868652343750, 0.0003662109375000, +0.0130004882812500, 0.0006713867187500, 0.0155639648437500, 0.0018615722656250, +0.0145263671875000, 0.0014038085937500, 0.0163269042968750, 0.0000000000000000, +0.0156860351562500, 0.0006713867187500, 0.0180358886718750, -0.0002441406250000, +0.0200195312500000, -0.0020446777343750, 0.0174560546875000, -0.0011901855468750, +0.0261535644531250, -0.0025024414062500, 0.0236816406250000, -0.0024719238281250, +0.0270996093750000, -0.0030212402343750, 0.0344543457031250, -0.0039062500000000, +0.0291748046875000, -0.0032043457031250, 0.0384216308593750, -0.0050964355468750, +0.0378112792968750, -0.0051574707031250, 0.0386047363281250, -0.0048828125000000, +0.0442199707031250, -0.0057373046875000, 0.0415039062500000, -0.0055541992187500, +0.0449829101562500, -0.0050048828125000, 0.0457458496093750, -0.0051879882812500, +0.0446166992187500, -0.0048217773437500, 0.0456237792968750, -0.0043334960937500, +0.0455322265625000, -0.0046386718750000, 0.0423583984375000, -0.0037231445312500, +0.0445251464843750, -0.0038757324218750, 0.0423889160156250, -0.0037841796875000, +0.0386047363281250, -0.0030517578125000, 0.0416564941406250, -0.0033569335937500, +0.0357971191406250, -0.0036315917968750, 0.0370788574218750, -0.0034179687500000, +0.0359497070312500, -0.0037841796875000, 0.0320129394531250, -0.0043945312500000, +0.0352478027343750, -0.0040893554687500, 0.0306701660156250, -0.0045471191406250, +0.0319824218750000, -0.0044860839843750, 0.0316772460937500, -0.0045776367187500, +0.0290527343750000, -0.0047912597656250, 0.0317382812500000, -0.0045471191406250, +0.0281066894531250, -0.0052795410156250, 0.0292053222656250, -0.0051879882812500, +0.0292968750000000, -0.0054016113281250, 0.0272827148437500, -0.0059509277343750, +0.0295410156250000, -0.0057373046875000, 0.0280151367187500, -0.0066528320312500, +0.0289001464843750, -0.0064086914062500, 0.0293579101562500, -0.0070495605468750, +0.0287170410156250, -0.0080566406250000, 0.0303649902343750, -0.0074768066406250, +0.0297851562500000, -0.0087890625000000, 0.0301208496093750, -0.0089721679687500, +0.0306701660156250, -0.0089721679687500, 0.0306396484375000, -0.0095214843750000, +0.0311889648437500, -0.0093383789062500, 0.0315246582031250, -0.0091247558593750, +0.0316772460937500, -0.0093078613281250, 0.0319213867187500, -0.0092468261718750, +0.0323486328125000, -0.0087280273437500, 0.0326232910156250, -0.0087890625000000, +0.0320129394531250, -0.0097961425781250, 0.0323486328125000, -0.0091857910156250, +0.0319213867187500, -0.0097045898437500, 0.0313415527343750, -0.0110168457031250, +0.0318603515625000, -0.0103454589843750, 0.0298767089843750, -0.0111083984375000, +0.0301208496093750, -0.0114135742187500, 0.0301513671875000, -0.0105895996093750, +0.0291137695312500, -0.0105285644531250, 0.0300598144531250, -0.0107727050781250, +0.0306701660156250, -0.0072631835937500, 0.0303955078125000, -0.0083312988281250, +0.0320434570312500, -0.0068359375000000, 0.0334472656250000, -0.0031738281250000, +0.0325622558593750, -0.0048522949218750, 0.0362548828125000, -0.0032653808593750, +0.0364990234375000, -0.0020751953125000, 0.0368652343750000, -0.0035705566406250, +0.0394592285156250, -0.0043640136718750, 0.0388793945312500, -0.0034179687500000, +0.0357971191406250, -0.0065612792968750, 0.0382385253906250, -0.0067443847656250, +0.0331420898437500, -0.0054931640625000, 0.0273437500000000, -0.0065307617187500, +0.0309753417968750, -0.0071105957031250, 0.0169677734375000, -0.0031127929687500, +0.0187377929687500, -0.0038146972656250, 0.0136413574218750, -0.0028381347656250, +0.0024719238281250, 0.0003967285156250, 0.0078735351562500, -0.0009765625000000, +-0.0051879882812500, -0.0003967285156250, -0.0050659179687500, 0.0004882812500000, +-0.0062561035156250, 0.0001831054687500, -0.0137939453125000, -0.0001220703125000, +-0.0104370117187500, -0.0003967285156250, -0.0128479003906250, -0.0024719238281250, +-0.0140991210937500, -0.0010070800781250, -0.0120849609375000, -0.0027465820312500, +-0.0111694335937500, -0.0055236816406250, -0.0117187500000000, -0.0040283203125000, +-0.0095825195312500, -0.0104675292968750, -0.0097351074218750, -0.0090942382812500, +-0.0075988769531250, -0.0099792480468750, -0.0055541992187500, -0.0149841308593750, +-0.0069580078125000, -0.0133972167968750, -0.0000610351562500, -0.0163574218750000, +-0.0011901855468750, -0.0166015625000000, 0.0017395019531250, -0.0151672363281250, +0.0079345703125000, -0.0163879394531250, 0.0049438476562500, -0.0169372558593750, +0.0099487304687500, -0.0113525390625000, 0.0110778808593750, -0.0136718750000000, +0.0088500976562500, -0.0099792480468750, 0.0094909667968750, -0.0037841796875000, +0.0103454589843750, -0.0080871582031250, 0.0060119628906250, 0.0003967285156250, +0.0062255859375000, 0.0014038085937500, 0.0050048828125000, -0.0005493164062500, +0.0021667480468750, 0.0024108886718750, 0.0034484863281250, 0.0031433105468750, +0.0005493164062500, 0.0000000000000000, 0.0003356933593750, 0.0001525878906250, +0.0006713867187500, -0.0002136230468750, -0.0009765625000000, -0.0023193359375000, +-0.0010681152343750, -0.0020141601562500, 0.0009155273437500, -0.0018310546875000, +-0.0002441406250000, -0.0023498535156250, 0.0005798339843750, -0.0017700195312500, +0.0028076171875000, -0.0009460449218750, 0.0011901855468750, -0.0015258789062500, +0.0025024414062500, -0.0003356933593750, 0.0036926269531250, 0.0000305175781250, +0.0024108886718750, 0.0000610351562500, 0.0012207031250000, 0.0001220703125000, +0.0023193359375000, 0.0000000000000000, 0.0016174316406250, 0.0017089843750000, +0.0000610351562500, 0.0008544921875000, 0.0021972656250000, 0.0029907226562500, +0.0046386718750000, 0.0057373046875000, 0.0027160644531250, 0.0037536621093750, +0.0039367675781250, 0.0086975097656250, 0.0071716308593750, 0.0092468261718750, +0.0012207031250000, 0.0086975097656250, -0.0031433105468750, 0.0105285644531250, +0.0020751953125000, 0.0102844238281250, -0.0111694335937500, 0.0096435546875000, +-0.0107116699218750, 0.0111083984375000, -0.0101928710937500, 0.0083923339843750, +-0.0170288085937500, 0.0060119628906250, -0.0146789550781250, 0.0084838867187500, +-0.0135192871093750, 0.0007629394531250, -0.0157165527343750, 0.0015563964843750, +-0.0119934082031250, 0.0005187988281250, -0.0088500976562500, -0.0048522949218750, +-0.0123596191406250, -0.0030212402343750, -0.0019226074218750, -0.0047912597656250, +-0.0034790039062500, -0.0053405761718750, -0.0024414062500000, -0.0055847167968750, +0.0047302246093750, -0.0061340332031250, 0.0018005371093750, -0.0056457519531250, +0.0032958984375000, -0.0082092285156250, 0.0052795410156250, -0.0078125000000000, +0.0020141601562500, -0.0075378417968750, -0.0001220703125000, -0.0096435546875000, +0.0025024414062500, -0.0090332031250000, -0.0035705566406250, -0.0041198730468750, +-0.0043640136718750, -0.0069580078125000, -0.0021667480468750, -0.0010681152343750, +-0.0037536621093750, 0.0068359375000000, -0.0048217773437500, 0.0023193359375000, +0.0000000000000000, 0.0159301757812500, -0.0007629394531250, 0.0163269042968750, +-0.0003051757812500, 0.0178833007812500, 0.0027465820312500, 0.0257873535156250, +0.0014038085937500, 0.0234985351562500, 0.0027465820312500, 0.0260009765625000, +0.0033569335937500, 0.0267639160156250, 0.0018920898437500, 0.0259399414062500, +0.0014648437500000, 0.0258178710937500, 0.0025939941406250, 0.0249633789062500, +0.0000610351562500, 0.0244445800781250, -0.0000610351562500, 0.0239257812500000, +-0.0001525878906250, 0.0239868164062500, -0.0009765625000000, 0.0241088867187500, +-0.0005493164062500, 0.0237121582031250, -0.0028991699218750, 0.0246276855468750, +-0.0020141601562500, 0.0241088867187500, -0.0032958984375000, 0.0237731933593750, +-0.0055541992187500, 0.0240783691406250, -0.0040893554687500, 0.0234680175781250, +-0.0079956054687500, 0.0237426757812500, -0.0074768066406250, 0.0230712890625000, +-0.0081176757812500, 0.0227355957031250, -0.0109252929687500, 0.0227355957031250, +-0.0096130371093750, 0.0216369628906250, -0.0110778808593750, 0.0214843750000000, +-0.0114440917968750, 0.0209655761718750, -0.0110168457031250, 0.0194091796875000, +-0.0113525390625000, 0.0183105468750000, -0.0112915039062500, 0.0179748535156250, +-0.0104980468750000, 0.0163574218750000, -0.0107727050781250, 0.0155029296875000, +-0.0103454589843750, 0.0144958496093750, -0.0095214843750000, 0.0130004882812500, +-0.0099487304687500, 0.0124206542968750, -0.0093383789062500, 0.0122680664062500, +-0.0092773437500000, 0.0112304687500000, -0.0091857910156250, 0.0107421875000000, +-0.0089721679687500, 0.0105895996093750, -0.0090942382812500, 0.0098266601562500, +-0.0085144042968750, 0.0098876953125000, -0.0084838867187500, 0.0086975097656250, +-0.0085754394531250, 0.0089721679687500, -0.0082702636718750, 0.0093383789062500, +-0.0082702636718750, 0.0077819824218750, -0.0084228515625000, 0.0102844238281250, +-0.0084838867187500, 0.0089721679687500, -0.0081481933593750, 0.0098876953125000, +-0.0080871582031250, 0.0118408203125000, -0.0083312988281250, 0.0096130371093750, +-0.0075683593750000, 0.0139160156250000, -0.0075073242187500, 0.0120544433593750, +-0.0077209472656250, 0.0133666992187500, -0.0073242187500000, 0.0168151855468750, +-0.0072631835937500, 0.0138549804687500, -0.0080871582031250, 0.0196838378906250, +-0.0078735351562500, 0.0183715820312500, -0.0080261230468750, 0.0198059082031250, +-0.0086975097656250, 0.0240173339843750, -0.0083618164062500, 0.0213928222656250, +-0.0086364746093750}, +{0.0004272460937500, -0.0009765625000000, -0.0076599121093750, -0.0043945312500000, +-0.0072326660156250, -0.0044860839843750, -0.0072021484375000, -0.0046997070312500, +-0.0115661621093750, -0.0065917968750000, -0.0092163085937500, -0.0059814453125000, +-0.0090026855468750, -0.0067443847656250, -0.0110778808593750, -0.0079040527343750, +-0.0077819824218750, -0.0056152343750000, -0.0046081542968750, -0.0046081542968750, +-0.0075683593750000, -0.0059814453125000, -0.0012817382812500, 0.0026855468750000, +-0.0015258789062500, 0.0003356933593750, -0.0018615722656250, 0.0053405761718750, +0.0016784667968750, 0.0144042968750000, 0.0003051757812500, 0.0095214843750000, +-0.0024719238281250, 0.0198059082031250, -0.0005187988281250, 0.0210266113281250, +-0.0024719238281250, 0.0203857421875000, -0.0068969726562500, 0.0245971679687500, +-0.0047302246093750, 0.0234375000000000, -0.0051574707031250, 0.0215454101562500, +-0.0073852539062500, 0.0218200683593750, -0.0047912597656250, 0.0202636718750000, +-0.0021362304687500, 0.0176086425781250, -0.0043945312500000, 0.0177307128906250, +-0.0001220703125000, 0.0174255371093750, -0.0001525878906250, 0.0159301757812500, +-0.0003662109375000, 0.0159606933593750, 0.0019531250000000, 0.0167236328125000, +0.0010070800781250, 0.0157775878906250, -0.0002136230468750, 0.0157165527343750, +0.0008239746093750, 0.0161437988281250, 0.0000000000000000, 0.0146789550781250, +-0.0020751953125000, 0.0136413574218750, -0.0013122558593750, 0.0140991210937500, +-0.0020141601562500, 0.0098571777343750, -0.0021362304687500, 0.0100097656250000, +-0.0025634765625000, 0.0081481933593750, -0.0028991699218750, 0.0044555664062500, +-0.0024719238281250, 0.0053100585937500, -0.0047912597656250, 0.0016479492187500, +-0.0040893554687500, 0.0010375976562500, -0.0052795410156250, 0.0002746582031250, +-0.0075683593750000, -0.0019531250000000, -0.0061950683593750, -0.0018005371093750, +-0.0086975097656250, -0.0026550292968750, -0.0087890625000000, -0.0036010742187500, +-0.0086059570312500, -0.0031433105468750, -0.0095825195312500, -0.0030517578125000, +-0.0091552734375000, -0.0039062500000000, -0.0094604492187500, -0.0018920898437500, +-0.0094909667968750, -0.0025939941406250, -0.0089721679687500, -0.0024719238281250, +-0.0089721679687500, -0.0010375976562500, -0.0092163085937500, -0.0019531250000000, +-0.0078735351562500, -0.0006408691406250, -0.0079345703125000, -0.0007324218750000, +-0.0080566406250000, -0.0005187988281250, -0.0072631835937500, 0.0000610351562500, +-0.0073547363281250, -0.0005493164062500, -0.0079345703125000, 0.0007629394531250, +-0.0077209472656250, 0.0005798339843750, -0.0077819824218750, 0.0004272460937500, +-0.0082702636718750, 0.0010681152343750, -0.0080566406250000, 0.0010070800781250, +-0.0079956054687500, 0.0016784667968750, -0.0080261230468750, 0.0012512207031250, +-0.0080261230468750, 0.0018005371093750, -0.0078735351562500, 0.0024719238281250, +-0.0078430175781250, 0.0015563964843750, -0.0084533691406250, 0.0028991699218750, +-0.0082702636718750, 0.0027160644531250, -0.0083618164062500, 0.0032043457031250, +-0.0089111328125000, 0.0041809082031250, -0.0086975097656250, 0.0036010742187500, +-0.0081481933593750, 0.0054321289062500, -0.0084533691406250, 0.0052185058593750, +-0.0079345703125000, 0.0055236816406250, -0.0070190429687500, 0.0067749023437500, +-0.0073242187500000, 0.0062561035156250, -0.0063476562500000, 0.0071411132812500, +-0.0061645507812500, 0.0068054199218750, -0.0061340332031250, 0.0076599121093750, +-0.0055847167968750, 0.0084533691406250, -0.0056457519531250, 0.0077514648437500, +-0.0059814453125000, 0.0116882324218750, -0.0057678222656250, 0.0102233886718750, +-0.0059509277343750, 0.0126342773437500, -0.0065002441406250, 0.0165710449218750, +-0.0062255859375000, 0.0137023925781250, -0.0057067871093750, 0.0202636718750000, +-0.0063171386718750, 0.0193786621093750, -0.0053405761718750, 0.0208740234375000, +-0.0041809082031250, 0.0254211425781250, -0.0049743652343750, 0.0227661132812500, +-0.0028381347656250, 0.0275268554687500, -0.0031127929687500, 0.0275878906250000, +-0.0024108886718750, 0.0267028808593750, -0.0010070800781250, 0.0290832519531250, +-0.0019836425781250, 0.0288085937500000, 0.0004272460937500, 0.0255432128906250, +0.0003051757812500, 0.0269165039062500, 0.0005493164062500, 0.0245361328125000, +0.0022277832031250, 0.0207519531250000, 0.0015563964843750, 0.0230712890625000, +0.0011596679687500, 0.0179138183593750, 0.0020141601562500, 0.0181579589843750, +0.0004577636718750, 0.0178527832031250, -0.0010986328125000, 0.0145568847656250, +0.0001831054687500, 0.0155029296875000, -0.0032653808593750, 0.0151977539062500, +-0.0030517578125000, 0.0148010253906250, -0.0042724609375000, 0.0147094726562500, +-0.0064697265625000, 0.0154113769531250, -0.0052490234375000, 0.0154418945312500, +-0.0100097656250000, 0.0109863281250000, -0.0098876953125000, 0.0136108398437500, +-0.0089721679687500, 0.0100097656250000, -0.0117187500000000, 0.0039672851562500, +-0.0116882324218750, 0.0077209472656250, -0.0068054199218750, -0.0009765625000000, +-0.0082397460937500, -0.0003662109375000, -0.0056762695312500, -0.0028991699218750, +-0.0009765625000000, -0.0083007812500000, -0.0035095214843750, -0.0045776367187500, +0.0018920898437500, -0.0146179199218750, 0.0025939941406250, -0.0139160156250000, +0.0018920898437500, -0.0142211914062500, 0.0039672851562500, -0.0210876464843750, +0.0037231445312500, -0.0190429687500000, 0.0019226074218750, -0.0155944824218750, +0.0033874511718750, -0.0193176269531250, 0.0012207031250000, -0.0131530761718750, +-0.0015258789062500, -0.0054016113281250, 0.0007324218750000, -0.0102844238281250, +-0.0055847167968750, 0.0030517578125000, -0.0058593750000000, 0.0032653808593750, +-0.0040283203125000, 0.0030822753906250, -0.0071411132812500, 0.0096435546875000, +-0.0078735351562500, 0.0078430175781250, 0.0000915527343750, 0.0085754394531250, +-0.0026855468750000, 0.0092468261718750, 0.0011291503906250, 0.0086364746093750, +0.0096740722656250, 0.0082397460937500, 0.0051269531250000, 0.0081787109375000, +0.0104370117187500, 0.0073242187500000, 0.0137023925781250, 0.0083312988281250, +0.0085449218750000, 0.0066833496093750, 0.0066833496093750, 0.0045776367187500, +0.0101623535156250, 0.0061950683593750, -0.0025329589843750, 0.0030822753906250, +-0.0025329589843750, 0.0021972656250000, -0.0015258789062500, 0.0041198730468750, +-0.0097045898437500, 0.0050964355468750, -0.0010681152343750, 0.0037536621093750, +0.0011901855468750, 0.0025939941406250, 0.0012817382812500, 0.0013122558593750, +0.0014953613281250, 0.0032653808593750, 0.0008544921875000, 0.0053100585937500, +0.0006103515625000, 0.0039367675781250, 0.0055847167968750, 0.0049133300781250, +0.0034179687500000, 0.0069885253906250, 0.0058898925781250, 0.0034790039062500, +0.0114135742187500, 0.0000610351562500, 0.0083007812500000, 0.0030822753906250, +0.0120849609375000, -0.0013427734375000, 0.0138549804687500, -0.0034179687500000, +0.0119018554687500, 0.0005798339843750, 0.0119018554687500, 0.0015563964843750, +0.0127868652343750, -0.0014038085937500, 0.0071716308593750, 0.0085449218750000, +0.0089416503906250, 0.0086975097656250, 0.0066223144531250, 0.0078125000000000, +0.0016174316406250, 0.0125122070312500, 0.0038757324218750, 0.0117187500000000, +-0.0038757324218750, 0.0085754394531250, -0.0018310546875000, 0.0105895996093750, +-0.0056152343750000, 0.0073547363281250, -0.0133666992187500, 0.0021667480468750, +-0.0089721679687500, 0.0052185058593750, -0.0165405273437500, 0.0013427734375000, +-0.0176086425781250, 0.0005187988281250, -0.0160827636718750, 0.0004882812500000, +-0.0187988281250000, -0.0006713867187500, -0.0185241699218750, 0.0002746582031250, +-0.0135498046875000, -0.0015869140625000, -0.0165710449218750, -0.0014038085937500, +-0.0106811523437500, -0.0023803710937500, -0.0030517578125000, -0.0036010742187500, +-0.0086364746093750, -0.0025939941406250, 0.0037841796875000, -0.0072937011718750, +0.0039367675781250, -0.0062255859375000, 0.0045166015625000, -0.0083312988281250, +0.0111083984375000, -0.0127258300781250, 0.0087890625000000, -0.0100402832031250, +0.0115356445312500, -0.0138244628906250, 0.0123291015625000, -0.0156555175781250, +0.0122375488281250, -0.0121765136718750, 0.0129089355468750, -0.0111083984375000, +0.0131225585937500, -0.0132141113281250, 0.0163574218750000, -0.0050659179687500, +0.0141906738281250, -0.0057373046875000, 0.0180053710937500, -0.0042419433593750, +0.0229492187500000, 0.0012512207031250, 0.0191345214843750, -0.0010070800781250, +0.0283203125000000, 0.0022583007812500, 0.0278930664062500, 0.0029907226562500, +0.0282897949218750, 0.0025024414062500, 0.0338745117187500, 0.0034790039062500, +0.0320129394531250, 0.0032958984375000, 0.0325622558593750, 0.0026550292968750, +0.0340270996093750, 0.0032653808593750, 0.0316162109375000, 0.0020751953125000, +0.0303955078125000, 0.0007324218750000, 0.0322875976562500, 0.0018005371093750, +0.0237426757812500, -0.0009765625000000, 0.0263366699218750, -0.0010681152343750, +0.0226440429687500, -0.0009155273437500, 0.0150146484375000, -0.0019836425781250, +0.0199890136718750, -0.0017395019531250, 0.0104370117187500, -0.0020141601562500, +0.0114440917968750, -0.0017089843750000, 0.0107116699218750, -0.0023498535156250, +0.0047302246093750, -0.0032348632812500, 0.0076293945312500, -0.0025939941406250, +0.0040893554687500, -0.0037536621093750, 0.0035400390625000, -0.0040893554687500, +0.0041503906250000, -0.0036315917968750, 0.0026855468750000, -0.0036621093750000, +0.0025024414062500, -0.0039062500000000, 0.0028686523437500, -0.0034179687500000, +0.0024414062500000, -0.0032653808593750, 0.0028686523437500, -0.0034790039062500, +0.0034790039062500, -0.0035400390625000, 0.0028991699218750, -0.0034484863281250, +0.0041198730468750, -0.0034179687500000, 0.0039062500000000, -0.0034790039062500, +0.0037536621093750, -0.0033874511718750, 0.0044555664062500, -0.0032043457031250, +0.0040588378906250, -0.0031738281250000, 0.0036621093750000, -0.0028991699218750, +0.0043945312500000, -0.0029296875000000, 0.0036010742187500, -0.0027160644531250, +0.0027160644531250, -0.0023803710937500, 0.0036621093750000, -0.0025634765625000, +0.0014953613281250, -0.0024108886718750, 0.0019836425781250, -0.0021972656250000, +0.0010681152343750, -0.0026550292968750, -0.0007934570312500, -0.0029296875000000, +0.0003662109375000, -0.0026550292968750, -0.0018615722656250, -0.0035095214843750, +-0.0016174316406250, -0.0036010742187500, -0.0020141601562500, -0.0034790039062500, +-0.0035095214843750, -0.0038452148437500, -0.0028991699218750, -0.0038757324218750, +-0.0046691894531250, -0.0040893554687500, -0.0044250488281250, -0.0038146972656250, +-0.0049438476562500, -0.0044860839843750, -0.0063171386718750, -0.0052185058593750, +-0.0057067871093750, -0.0046386718750000, -0.0073242187500000, -0.0062255859375000, +-0.0072937011718750, -0.0061340332031250, -0.0076293945312500, -0.0067749023437500, +-0.0084838867187500, -0.0077819824218750, -0.0081787109375000, -0.0070495605468750, +-0.0102233886718750, -0.0097351074218750, -0.0100097656250000, -0.0093688964843750, +-0.0111694335937500, -0.0094604492187500, -0.0130310058593750, -0.0112915039062500, +-0.0122375488281250, -0.0107421875000000, -0.0149230957031250, -0.0108642578125000, +-0.0146789550781250, -0.0110473632812500, -0.0150451660156250, -0.0107727050781250, +-0.0170593261718750, -0.0108032226562500, -0.0161743164062500, -0.0108032226562500, +-0.0153808593750000, -0.0092468261718750, -0.0165710449218750, -0.0098266601562500, +-0.0145568847656250}, +{0.0164794921875000, -0.0076293945312500, 0.0188293457031250, -0.0081176757812500, +0.0242309570312500, -0.0097656250000000, 0.0211791992187500, -0.0089721679687500, +0.0255126953125000, -0.0085449218750000, 0.0267639160156250, -0.0098571777343750, +0.0251159667968750, -0.0079650878906250, 0.0259704589843750, -0.0057983398437500, +0.0267028808593750, -0.0073547363281250, 0.0222473144531250, -0.0032348632812500, +0.0239868164062500, -0.0031738281250000, 0.0219116210937500, -0.0030822753906250, +0.0177307128906250, -0.0008850097656250, 0.0203857421875000, -0.0013732910156250, +0.0135192871093750, -0.0009460449218750, 0.0146179199218750, -0.0008239746093750, +0.0125732421875000, -0.0004882812500000, 0.0073852539062500, -0.0000305175781250, +0.0105590820312500, -0.0003051757812500, 0.0047912597656250, -0.0000305175781250, +0.0047302246093750, 0.0004577636718750, 0.0040283203125000, -0.0002136230468750, +0.0010375976562500, -0.0008239746093750, 0.0027160644531250, -0.0002441406250000, +-0.0007629394531250, -0.0009765625000000, -0.0001525878906250, -0.0013427734375000, +-0.0011596679687500, -0.0010070800781250, -0.0037231445312500, -0.0006713867187500, +-0.0018005371093750, -0.0009460449218750, -0.0046386718750000, -0.0015563964843750, +-0.0041503906250000, -0.0009460449218750, -0.0050659179687500, -0.0018310546875000, +-0.0072631835937500, -0.0031433105468750, -0.0057678222656250, -0.0023193359375000, +-0.0089721679687500, -0.0035400390625000, -0.0084533691406250, -0.0039062500000000, +-0.0088500976562500, -0.0035400390625000, -0.0109558105468750, -0.0036926269531250, +-0.0093994140625000, -0.0037231445312500, -0.0110778808593750, -0.0031433105468750, +-0.0111694335937500, -0.0032043457031250, -0.0108642578125000, -0.0028686523437500, +-0.0115966796875000, -0.0022277832031250, -0.0113525390625000, -0.0026245117187500, +-0.0107727050781250, -0.0018920898437500, -0.0111999511718750, -0.0017395019531250, +-0.0106201171875000, -0.0021362304687500, -0.0097961425781250, -0.0020751953125000, +-0.0101928710937500, -0.0018615722656250, -0.0089416503906250, -0.0028991699218750, +-0.0093078613281250, -0.0028076171875000, -0.0091552734375000, -0.0029907226562500, +-0.0084228515625000, -0.0036926269531250, -0.0089721679687500, -0.0033874511718750, +-0.0077819824218750, -0.0038452148437500, -0.0079650878906250, -0.0037841796875000, +-0.0078430175781250, -0.0041503906250000, -0.0072631835937500, -0.0045166015625000, +-0.0079650878906250, -0.0041809082031250, -0.0072937011718750, -0.0051269531250000, +-0.0075073242187500, -0.0051269531250000, -0.0076599121093750, -0.0049743652343750, +-0.0073242187500000, -0.0051574707031250, -0.0076293945312500, -0.0051269531250000, +-0.0072937011718750, -0.0058593750000000, -0.0075073242187500, -0.0051879882812500, +-0.0075073242187500, -0.0061950683593750, -0.0071411132812500, -0.0076904296875000, +-0.0073547363281250, -0.0066223144531250, -0.0071716308593750, -0.0081176757812500, +-0.0072631835937500, -0.0084533691406250, -0.0071105957031250, -0.0083923339843750, +-0.0068664550781250, -0.0086669921875000, -0.0071411132812500, -0.0084533691406250, +-0.0070190429687500, -0.0090942382812500, -0.0068664550781250, -0.0091857910156250, +-0.0075073242187500, -0.0085144042968750, -0.0080261230468750, -0.0085754394531250, +-0.0079040527343750, -0.0090026855468750, -0.0092163085937500, -0.0072326660156250, +-0.0090942382812500, -0.0074157714843750, -0.0100097656250000, -0.0072021484375000, +-0.0115356445312500, -0.0061340332031250, -0.0115356445312500, -0.0066833496093750, +-0.0137329101562500, -0.0064086914062500, -0.0138244628906250, -0.0059204101562500, +-0.0143127441406250, -0.0072021484375000, -0.0159606933593750, -0.0082092285156250, +-0.0153503417968750, -0.0071105957031250, -0.0144042968750000, -0.0086975097656250, +-0.0158691406250000, -0.0099182128906250, -0.0137939453125000, -0.0075378417968750, +-0.0115966796875000, -0.0061950683593750, -0.0131530761718750, -0.0080566406250000, +-0.0059204101562500, -0.0033264160156250, -0.0069885253906250, -0.0028076171875000, +-0.0046997070312500, -0.0040588378906250, 0.0011291503906250, -0.0022888183593750, +-0.0012512207031250, -0.0019226074218750, 0.0040283203125000, -0.0061645507812500, +0.0047912597656250, -0.0050048828125000, 0.0048217773437500, -0.0066528320312500, +0.0068359375000000, -0.0103454589843750, 0.0064086914062500, -0.0081787109375000, +0.0083618164062500, -0.0119934082031250, 0.0078735351562500, -0.0128479003906250, +0.0086364746093750, -0.0108947753906250, 0.0101623535156250, -0.0111389160156250, +0.0091552734375000, -0.0119323730468750, 0.0120849609375000, -0.0082092285156250, +0.0110778808593750, -0.0097656250000000, 0.0126647949218750, -0.0063781738281250, +0.0160827636718750, -0.0016174316406250, 0.0142211914062500, -0.0051574707031250, +0.0162048339843750, 0.0015563964843750, 0.0179748535156250, 0.0022888183593750, +0.0154418945312500, 0.0011901855468750, 0.0138854980468750, 0.0041198730468750, +0.0152893066406250, 0.0041503906250000, 0.0089416503906250, 0.0002746582031250, +0.0101623535156250, 0.0014648437500000, 0.0071411132812500, 0.0003662109375000, +0.0010986328125000, -0.0032653808593750, 0.0039978027343750, -0.0016784667968750, +-0.0021972656250000, -0.0018615722656250, -0.0027160644531250, -0.0028991699218750, +-0.0025939941406250, -0.0023498535156250, -0.0051574707031250, -0.0014953613281250, +-0.0042114257812500, -0.0017700195312500, -0.0060119628906250, -0.0009460449218750, +-0.0065612792968750, -0.0010070800781250, -0.0047912597656250, -0.0007629394531250, +-0.0049743652343750, -0.0004577636718750, -0.0060119628906250, -0.0008850097656250, +0.0007934570312500, 0.0011291503906250, -0.0007019042968750, 0.0007629394531250, +0.0007019042968750, 0.0011901855468750, 0.0069274902343750, 0.0030517578125000, +0.0060119628906250, 0.0032043457031250, 0.0076293945312500, 0.0050354003906250, +0.0081787109375000, 0.0040283203125000, 0.0066833496093750, 0.0052490234375000, +0.0066223144531250, 0.0077819824218750, 0.0076904296875000, 0.0061035156250000, +0.0043640136718750, 0.0071411132812500, 0.0051574707031250, 0.0090332031250000, +0.0038452148437500, 0.0062561035156250, 0.0013732910156250, 0.0039367675781250, +0.0033874511718750, 0.0058898925781250, -0.0012207031250000, -0.0001831054687500, +-0.0013122558593750, -0.0002136230468750, -0.0004882812500000, -0.0001220703125000, +-0.0024719238281250, -0.0028076171875000, -0.0024414062500000, -0.0022277832031250, +-0.0015258789062500, -0.0043334960937500, -0.0018615722656250, -0.0037231445312500, +-0.0010681152343750, -0.0042114257812500, 0.0001831054687500, -0.0068054199218750, +-0.0004882812500000, -0.0060424804687500, 0.0002441406250000, -0.0047302246093750, +0.0009155273437500, -0.0070800781250000, 0.0004272460937500, -0.0027770996093750, +-0.0003051757812500, 0.0013427734375000, 0.0001220703125000, -0.0024414062500000, +0.0018615722656250, 0.0093688964843750, 0.0007629394531250, 0.0080566406250000, +0.0016784667968750, 0.0098876953125000, 0.0041809082031250, 0.0182495117187500, +0.0029296875000000, 0.0148925781250000, 0.0025024414062500, 0.0172424316406250, +0.0040893554687500, 0.0191955566406250, 0.0017395019531250, 0.0168457031250000, +-0.0005493164062500, 0.0155334472656250, 0.0018005371093750, 0.0166625976562500, +-0.0032348632812500, 0.0123291015625000, -0.0025634765625000, 0.0122375488281250, +-0.0034790039062500, 0.0119323730468750, -0.0065917968750000, 0.0095214843750000, +-0.0043029785156250, 0.0097961425781250, -0.0081787109375000, 0.0086975097656250, +-0.0080871582031250, 0.0090942382812500, -0.0080566406250000, 0.0072326660156250, +-0.0100097656250000, 0.0054931640625000, -0.0092773437500000, 0.0066833496093750, +-0.0109558105468750, 0.0009765625000000, -0.0116271972656250, 0.0017700195312500, +-0.0106811523437500, -0.0000610351562500, -0.0111389160156250, -0.0047912597656250, +-0.0122680664062500, -0.0029907226562500, -0.0086975097656250, -0.0063171386718750, +-0.0099487304687500, -0.0072937011718750, -0.0083923339843750, -0.0066223144531250, +-0.0048828125000000, -0.0071716308593750, -0.0070495605468750, -0.0071411132812500, +-0.0034484863281250, -0.0059204101562500, -0.0033264160156250, -0.0061340332031250, +-0.0032043457031250, -0.0053710937500000, -0.0013122558593750, -0.0042114257812500, +-0.0021972656250000, -0.0049743652343750, -0.0020141601562500, -0.0039672851562500, +-0.0014038085937500, -0.0036315917968750, -0.0020446777343750, -0.0039672851562500, +-0.0028686523437500, -0.0036926269531250, -0.0024414062500000, -0.0035400390625000, +-0.0024108886718750, -0.0046997070312500, -0.0030822753906250, -0.0044555664062500, +-0.0025024414062500, -0.0048828125000000, -0.0016784667968750, -0.0057983398437500, +-0.0022583007812500, -0.0054321289062500, -0.0021057128906250, -0.0066528320312500, +-0.0014038085937500, -0.0065002441406250, -0.0024719238281250, -0.0065307617187500, +-0.0034484863281250, -0.0070800781250000, -0.0024719238281250, -0.0066833496093750, +-0.0048217773437500, -0.0072021484375000, -0.0046386718750000, -0.0066833496093750, +-0.0047607421875000, -0.0061645507812500, -0.0059814453125000, -0.0058288574218750, +-0.0054626464843750, -0.0051574707031250, -0.0066833496093750, -0.0056152343750000, +-0.0064086914062500, -0.0046997070312500, -0.0066833496093750, -0.0046386718750000, +-0.0077514648437500, -0.0049743652343750, -0.0072021484375000, -0.0037231445312500, +-0.0076904296875000, -0.0045471191406250, -0.0079956054687500, -0.0036621093750000, +-0.0076904296875000, -0.0036621093750000, -0.0075073242187500, -0.0044250488281250, +-0.0077209472656250, -0.0033264160156250, -0.0072326660156250, -0.0045471191406250, +-0.0072326660156250, -0.0039672851562500, -0.0069580078125000, -0.0040893554687500, +-0.0065307617187500, -0.0048828125000000, -0.0067443847656250, -0.0039062500000000, +-0.0060119628906250, -0.0052185058593750, -0.0060424804687500, -0.0044250488281250, +-0.0058898925781250, -0.0048828125000000, -0.0054016113281250, -0.0061950683593750, +-0.0055847167968750, -0.0049133300781250, -0.0052795410156250, -0.0070800781250000, +-0.0052490234375000, -0.0067749023437500, -0.0052185058593750, -0.0071411132812500, +-0.0050659179687500, -0.0085449218750000, -0.0051574707031250, -0.0077209472656250, +-0.0042114257812500, -0.0093078613281250, -0.0047302246093750, -0.0093688964843750, +-0.0036010742187500, -0.0087585449218750, -0.0020751953125000, -0.0094909667968750, +-0.0029602050781250, -0.0094909667968750, -0.0005798339843750, -0.0073852539062500, +-0.0002441406250000, -0.0087585449218750, -0.0004577636718750, -0.0070800781250000, +0.0005187988281250, -0.0045166015625000, 0.0004577636718750, -0.0065002441406250, +-0.0004577636718750, -0.0011291503906250, 0.0001220703125000, -0.0020141601562500, +-0.0007629394531250, -0.0003356933593750, -0.0018310546875000, 0.0037841796875000, +-0.0009460449218750, 0.0014648437500000, -0.0039978027343750, 0.0062561035156250, +-0.0033569335937500, 0.0061340332031250, -0.0042724609375000, 0.0058288574218750, +-0.0068664550781250, 0.0081176757812500, -0.0056152343750000, 0.0072631835937500, +-0.0074462890625000, 0.0075073242187500, -0.0077819824218750, 0.0076904296875000, +-0.0077819824218750, 0.0074157714843750, -0.0084533691406250, 0.0071105957031250, +-0.0081787109375000, 0.0074157714843750, -0.0085754394531250, 0.0079650878906250, +-0.0088195800781250, 0.0068969726562500, -0.0084228515625000, 0.0087280273437500, +-0.0082702636718750, 0.0107727050781250, -0.0085754394531250, 0.0092773437500000, +-0.0076293945312500, 0.0137023925781250, -0.0078735351562500, 0.0138549804687500, +-0.0068969726562500, 0.0140075683593750, -0.0056152343750000, 0.0162963867187500, +-0.0064392089843750}, +{-0.0022583007812500, -0.0025024414062500, -0.0040893554687500, -0.0024414062500000, +-0.0018005371093750, -0.0017395019531250, -0.0016174316406250, -0.0018310546875000, +-0.0018920898437500, -0.0007934570312500, -0.0007934570312500, 0.0004577636718750, +-0.0010070800781250, 0.0002136230468750, -0.0013732910156250, 0.0030212402343750, +-0.0011901855468750, 0.0031738281250000, -0.0010681152343750, 0.0040893554687500, +-0.0014343261718750, 0.0062255859375000, -0.0014648437500000, 0.0060424804687500, +-0.0009155273437500, 0.0078735351562500, -0.0009460449218750, 0.0085449218750000, +-0.0014038085937500, 0.0090026855468750, -0.0012512207031250, 0.0101928710937500, +-0.0010681152343750, 0.0106201171875000, -0.0033874511718750, 0.0109558105468750, +-0.0026245117187500, 0.0118408203125000, -0.0035705566406250, 0.0118103027343750, +-0.0058288574218750, 0.0115661621093750, -0.0046386718750000, 0.0121765136718750, +-0.0064392089843750, 0.0110168457031250, -0.0065917968750000, 0.0113220214843750, +-0.0066528320312500, 0.0108947753906250, -0.0075073242187500, 0.0100708007812500, +-0.0070495605468750, 0.0108032226562500, -0.0075683593750000, 0.0093383789062500, +-0.0077209472656250, 0.0091857910156250, -0.0071105957031250, 0.0094299316406250, +-0.0068969726562500, 0.0089721679687500, -0.0072021484375000, 0.0090332031250000, +-0.0061035156250000, 0.0091247558593750, -0.0061035156250000, 0.0090026855468750, +-0.0061645507812500, 0.0092163085937500, -0.0056762695312500, 0.0093994140625000, +-0.0057067871093750, 0.0093078613281250, -0.0058593750000000, 0.0102233886718750, +-0.0058593750000000, 0.0099182128906250, -0.0057373046875000, 0.0101623535156250, +-0.0058593750000000, 0.0110473632812500, -0.0059204101562500, 0.0105285644531250, +-0.0049743652343750, 0.0110473632812500, -0.0054626464843750, 0.0110168457031250, +-0.0045166015625000, 0.0106201171875000, -0.0032958984375000, 0.0108337402343750, +-0.0041503906250000, 0.0105590820312500, -0.0020141601562500, 0.0091552734375000, +-0.0019226074218750, 0.0099792480468750, -0.0020446777343750, 0.0083007812500000, +-0.0010070800781250, 0.0065307617187500, -0.0011596679687500, 0.0079956054687500, +-0.0018005371093750, 0.0021057128906250, -0.0015258789062500, 0.0038757324218750, +-0.0019836425781250, 0.0015258789062500, -0.0027160644531250, -0.0036315917968750, +-0.0022888183593750, -0.0004577636718750, -0.0036926269531250, -0.0068359375000000, +-0.0032348632812500, -0.0066833496093750, -0.0038146972656250, -0.0073547363281250, +-0.0053100585937500, -0.0112304687500000, -0.0043945312500000, -0.0093688964843750, +-0.0051879882812500, -0.0104064941406250, -0.0057678222656250, -0.0115661621093750, +-0.0049133300781250, -0.0092163085937500, -0.0044250488281250, -0.0079345703125000, +-0.0049743652343750, -0.0094299316406250, -0.0042419433593750, -0.0034790039062500, +-0.0037841796875000, -0.0048828125000000, -0.0043334960937500, -0.0024414062500000, +-0.0045776367187500, 0.0027465820312500, -0.0042724609375000, -0.0002746582031250, +-0.0053405761718750, 0.0054626464843750, -0.0050659179687500, 0.0055847167968750, +-0.0059509277343750, 0.0058898925781250, -0.0070190429687500, 0.0087280273437500, +-0.0061035156250000, 0.0073547363281250, -0.0083923339843750, 0.0092163085937500, +-0.0083923339843750, 0.0093078613281250, -0.0083618164062500, 0.0088806152343750, +-0.0094909667968750, 0.0096130371093750, -0.0092163085937500, 0.0096435546875000, +-0.0083923339843750, 0.0096435546875000, -0.0093383789062500, 0.0090942382812500, +-0.0074462890625000, 0.0104064941406250, -0.0057983398437500, 0.0113525390625000, +-0.0072021484375000, 0.0101318359375000, -0.0006713867187500, 0.0138854980468750, +-0.0022583007812500, 0.0137634277343750, 0.0007629394531250, 0.0136108398437500, +0.0071411132812500, 0.0156860351562500, 0.0038452148437500, 0.0150451660156250, +0.0096130371093750, 0.0135803222656250, 0.0108337402343750, 0.0139770507812500, +0.0092468261718750, 0.0139770507812500, 0.0110778808593750, 0.0128479003906250, +0.0115661621093750, 0.0130310058593750, 0.0063781738281250, 0.0141601562500000, +0.0074768066406250, 0.0135192871093750, 0.0062561035156250, 0.0149841308593750, +0.0022583007812500, 0.0172119140625000, 0.0042419433593750, 0.0160217285156250, +0.0019531250000000, 0.0171813964843750, 0.0007019042968750, 0.0191955566406250, +0.0027160644531250, 0.0143432617187500, 0.0037536621093750, 0.0119934082031250, +0.0024414062500000, 0.0155334472656250, 0.0047302246093750, -0.0010681152343750, +0.0047607421875000, 0.0014038085937500, 0.0046386718750000, -0.0030517578125000, +0.0056762695312500, -0.0166931152343750, 0.0052490234375000, -0.0108642578125000, +0.0049133300781250, -0.0158081054687500, 0.0051574707031250, -0.0196838378906250, +0.0045471191406250, -0.0153503417968750, 0.0034790039062500, -0.0127868652343750, +0.0041198730468750, -0.0154418945312500, 0.0054626464843750, -0.0083618164062500, +0.0040588378906250, -0.0078430175781250, 0.0052490234375000, -0.0081787109375000, +0.0093994140625000, -0.0036315917968750, 0.0068359375000000, -0.0161743164062500, +-0.0043640136718750, -0.0116882324218750, 0.0005798339843750, -0.0134582519531250, +-0.0028991699218750, -0.0107727050781250, -0.0099487304687500, -0.0081481933593750, +-0.0072021484375000, -0.0098876953125000, -0.0119323730468750, -0.0017395019531250, +-0.0122375488281250, -0.0031127929687500, -0.0122680664062500, -0.0012817382812500, +-0.0148620605468750, 0.0057373046875000, -0.0138854980468750, 0.0032043457031250, +-0.0129394531250000, 0.0030212402343750, -0.0155639648437500, 0.0051269531250000, +-0.0096740722656250, 0.0037536621093750, -0.0050354003906250, 0.0007019042968750, +-0.0094909667968750, 0.0016784667968750, 0.0078430175781250, 0.0039978027343750, +0.0052795410156250, 0.0022583007812500, 0.0082702636718750, 0.0039978027343750, +0.0219116210937500, 0.0076293945312500, 0.0168151855468750, 0.0059509277343750, +0.0178833007812500, 0.0078125000000000, 0.0216064453125000, 0.0089721679687500, +0.0181274414062500, 0.0063781738281250, 0.0140686035156250, 0.0049438476562500, +0.0168151855468750, 0.0068969726562500, 0.0126037597656250, 0.0034179687500000, +0.0113525390625000, 0.0018310546875000, 0.0127868652343750, 0.0040588378906250, +0.0120544433593750, 0.0049743652343750, 0.0114746093750000, 0.0037231445312500, +0.0149841308593750, 0.0071411132812500, 0.0139465332031250, 0.0073242187500000, +0.0149230957031250, 0.0072631835937500, 0.0180358886718750, 0.0091857910156250, +0.0166931152343750, 0.0087890625000000, 0.0190429687500000, 0.0064697265625000, +0.0188903808593750, 0.0077819824218750, 0.0187683105468750, 0.0057373046875000, +0.0202026367187500, 0.0030517578125000, 0.0194396972656250, 0.0046691894531250, +0.0178833007812500, -0.0025939941406250, 0.0193481445312500, -0.0009765625000000, +0.0170288085937500, -0.0033874511718750, 0.0142517089843750, -0.0100708007812500, +0.0158996582031250, -0.0070495605468750, 0.0087280273437500, -0.0103149414062500, +0.0108337402343750, -0.0119323730468750, 0.0064392089843750, -0.0097961425781250, +-0.0007019042968750, -0.0092163085937500, 0.0042114257812500, -0.0102233886718750, +-0.0068664550781250, -0.0063781738281250, -0.0059814453125000, -0.0065002441406250, +-0.0072326660156250, -0.0063781738281250, -0.0140991210937500, -0.0043334960937500, +-0.0110168457031250, -0.0048828125000000, -0.0150146484375000, -0.0043640136718750, +-0.0155639648437500, -0.0043334960937500, -0.0145568847656250, -0.0041503906250000, +-0.0161437988281250, -0.0036010742187500, -0.0158386230468750, -0.0039978027343750, +-0.0125427246093750, -0.0041198730468750, -0.0141906738281250, -0.0037841796875000, +-0.0115661621093750, -0.0040893554687500, -0.0074768066406250, -0.0046997070312500, +-0.0100708007812500, -0.0044555664062500, -0.0041198730468750, -0.0037841796875000, +-0.0047302246093750, -0.0041809082031250, -0.0038757324218750, -0.0036926269531250, +0.0001831054687500, -0.0027465820312500, -0.0017089843750000, -0.0030822753906250, +0.0012512207031250, -0.0024719238281250, 0.0014648437500000, -0.0025024414062500, +0.0015258789062500, -0.0019226074218750, 0.0032348632812500, -0.0013122558593750, +0.0031127929687500, -0.0018005371093750, 0.0032043457031250, -0.0000610351562500, +0.0037841796875000, 0.0001220703125000, 0.0033264160156250, -0.0002746582031250, +0.0031127929687500, 0.0004577636718750, 0.0037841796875000, 0.0005493164062500, +0.0013732910156250, -0.0009460449218750, 0.0026855468750000, -0.0006103515625000, +0.0018310546875000, -0.0011596679687500, -0.0003662109375000, -0.0024414062500000, +0.0015563964843750, -0.0019226074218750, -0.0013122558593750, -0.0029602050781250, +-0.0009155273437500, -0.0029602050781250, -0.0011596679687500, -0.0031127929687500, +-0.0026855468750000, -0.0037231445312500, -0.0013122558593750, -0.0034179687500000, +-0.0031738281250000, -0.0040893554687500, -0.0028076171875000, -0.0039367675781250, +-0.0025634765625000, -0.0042419433593750, -0.0033874511718750, -0.0047912597656250, +-0.0026550292968750, -0.0043334960937500, -0.0031433105468750, -0.0051879882812500, +-0.0030822753906250, -0.0050659179687500, -0.0028076171875000, -0.0053100585937500, +-0.0028686523437500, -0.0058898925781250, -0.0023803710937500, -0.0055541992187500, +-0.0019226074218750, -0.0066833496093750, -0.0018005371093750, -0.0066223144531250, +-0.0009765625000000, -0.0064697265625000, -0.0002746582031250, -0.0071105957031250, +-0.0001220703125000, -0.0070495605468750, 0.0017700195312500, -0.0065307617187500, +0.0014648437500000, -0.0065307617187500, 0.0028076171875000, -0.0070190429687500, +0.0046386718750000, -0.0071716308593750, 0.0038146972656250, -0.0066223144531250, +0.0076293945312500, -0.0072937011718750, 0.0073547363281250, -0.0079040527343750, +0.0087585449218750, -0.0065307617187500, 0.0116271972656250, -0.0057373046875000, +0.0101928710937500, -0.0068054199218750, 0.0135498046875000, -0.0039367675781250, +0.0135498046875000, -0.0040588378906250, 0.0134277343750000, -0.0039978027343750, +0.0154113769531250, -0.0023193359375000, 0.0149536132812500, -0.0030822753906250, +0.0133666992187500, -0.0033874511718750, 0.0144348144531250, -0.0024108886718750, +0.0126953125000000, -0.0042114257812500, 0.0104370117187500, -0.0060729980468750, +0.0120849609375000, -0.0045166015625000, 0.0075073242187500, -0.0072937011718750, +0.0080871582031250, -0.0079345703125000, 0.0067749023437500, -0.0070495605468750, +0.0031738281250000, -0.0073547363281250, 0.0047912597656250, -0.0076904296875000, +0.0015869140625000, -0.0072631835937500, 0.0014648437500000, -0.0067749023437500, +0.0014038085937500, -0.0074768066406250, -0.0000915527343750, -0.0079650878906250, +0.0006408691406250, -0.0074462890625000, -0.0005798339843750, -0.0092468261718750, +-0.0004577636718750, -0.0093994140625000, -0.0011291503906250, -0.0089416503906250, +-0.0020141601562500, -0.0095825195312500, -0.0012817382812500, -0.0097656250000000, +-0.0040588378906250, -0.0090332031250000, -0.0035705566406250, -0.0094299316406250, +-0.0045166015625000, -0.0081787109375000, -0.0069885253906250, -0.0068359375000000, +-0.0060424804687500, -0.0079650878906250, -0.0075378417968750, -0.0061950683593750, +-0.0080871582031250, -0.0058898925781250, -0.0070190429687500, -0.0050048828125000, +-0.0072021484375000, -0.0039062500000000, -0.0075683593750000, -0.0051879882812500, +-0.0026550292968750, -0.0029602050781250, -0.0038452148437500, -0.0026245117187500, +-0.0017089843750000, -0.0024719238281250, 0.0030517578125000, -0.0015563964843750, +0.0009155273437500, -0.0020751953125000, 0.0045471191406250, -0.0016479492187500, +0.0051879882812500}, +{-0.0054321289062500, -0.0034484863281250, -0.0056152343750000, -0.0035400390625000, +-0.0053100585937500, -0.0030212402343750, -0.0054931640625000, -0.0024108886718750, +-0.0056457519531250, -0.0028381347656250, -0.0044860839843750, -0.0018310546875000, +-0.0051879882812500, -0.0015258789062500, -0.0044555664062500, -0.0018615722656250, +-0.0031738281250000, -0.0017089843750000, -0.0044250488281250, -0.0015258789062500, +-0.0027770996093750, -0.0023803710937500, -0.0026855468750000, -0.0021362304687500, +-0.0027465820312500, -0.0027160644531250, -0.0023498535156250, -0.0035095214843750, +-0.0031738281250000, -0.0029602050781250, -0.0023803710937500, -0.0047607421875000, +-0.0028686523437500, -0.0045471191406250, -0.0026245117187500, -0.0048217773437500, +-0.0019836425781250, -0.0061035156250000, -0.0030517578125000, -0.0055847167968750, +-0.0020446777343750, -0.0061950683593750, -0.0026550292968750, -0.0063781738281250, +-0.0027160644531250, -0.0061645507812500, -0.0020446777343750, -0.0062866210937500, +-0.0028686523437500, -0.0062866210937500, -0.0023498535156250, -0.0057983398437500, +-0.0028991699218750, -0.0058593750000000, -0.0029602050781250, -0.0059509277343750, +-0.0025939941406250, -0.0055236816406250, -0.0033874511718750, -0.0055847167968750, +-0.0028991699218750, -0.0065612792968750, -0.0029602050781250, -0.0062866210937500, +-0.0030822753906250, -0.0061340332031250, -0.0031433105468750, -0.0069274902343750, +-0.0034484863281250, -0.0069274902343750, -0.0026550292968750, -0.0053710937500000, +-0.0032348632812500, -0.0061340332031250, -0.0026550292968750, -0.0052185058593750, +-0.0016784667968750, -0.0035095214843750, -0.0023498535156250, -0.0046386718750000, +-0.0000915527343750, -0.0025024414062500, -0.0007934570312500, -0.0023193359375000, +0.0007629394531250, -0.0030822753906250, 0.0032348632812500, -0.0021057128906250, +0.0018920898437500, -0.0019531250000000, 0.0063476562500000, -0.0050048828125000, +0.0059814453125000, -0.0039672851562500, 0.0073547363281250, -0.0050964355468750, +0.0110168457031250, -0.0080871582031250, 0.0099182128906250, -0.0066223144531250, +0.0132751464843750, -0.0084838867187500, 0.0135803222656250, -0.0088500976562500, +0.0132751464843750, -0.0084838867187500, 0.0147094726562500, -0.0090942382812500, +0.0143127441406250, -0.0090332031250000, 0.0125122070312500, -0.0078430175781250, +0.0134582519531250, -0.0083618164062500, 0.0117797851562500, -0.0080566406250000, +0.0094604492187500, -0.0070495605468750, 0.0108642578125000, -0.0075683593750000, +0.0060119628906250, -0.0065612792968750, 0.0062255859375000, -0.0066833496093750, +0.0055847167968750, -0.0069580078125000, 0.0024108886718750, -0.0065307617187500, +0.0034179687500000, -0.0063781738281250, 0.0022888183593750, -0.0059509277343750, +0.0017700195312500, -0.0062866210937500, 0.0016479492187500, -0.0061645507812500, +0.0014038085937500, -0.0056152343750000, 0.0014038085937500, -0.0054931640625000, +-0.0000915527343750, -0.0046081542968750, 0.0004577636718750, -0.0054016113281250, +-0.0008239746093750, -0.0046386718750000, -0.0027160644531250, -0.0029602050781250, +-0.0013732910156250, -0.0036010742187500, -0.0041503906250000, -0.0021362304687500, +-0.0046081542968750, -0.0022277832031250, -0.0038146972656250, -0.0025329589843750, +-0.0049133300781250, -0.0016784667968750, -0.0051879882812500, -0.0016479492187500, +-0.0017395019531250, -0.0024414062500000, -0.0030212402343750, -0.0026550292968750, +-0.0011596679687500, -0.0016479492187500, 0.0024719238281250, -0.0017089843750000, +0.0004577636718750, -0.0024719238281250, 0.0048828125000000, 0.0021667480468750, +0.0051574707031250, 0.0015869140625000, 0.0050659179687500, 0.0019836425781250, +0.0072631835937500, 0.0048828125000000, 0.0068054199218750, 0.0038757324218750, +0.0063476562500000, 0.0046691894531250, 0.0061340332031250, 0.0053405761718750, +0.0076293945312500, 0.0050659179687500, 0.0081481933593750, 0.0044250488281250, +0.0068664550781250, 0.0046081542968750, 0.0113220214843750, 0.0068054199218750, +0.0113830566406250, 0.0056152343750000, 0.0108947753906250, 0.0068664550781250, +0.0132141113281250, 0.0101928710937500, 0.0128479003906250, 0.0085449218750000, +0.0096130371093750, 0.0074157714843750, 0.0114440917968750, 0.0098266601562500, +0.0090332031250000, 0.0066833496093750, 0.0041198730468750, 0.0012817382812500, +0.0047607421875000, 0.0020751953125000, -0.0010375976562500, -0.0019226074218750, +0.0004882812500000, -0.0020446777343750, 0.0003051757812500, -0.0007324218750000, +-0.0037841796875000, -0.0021362304687500, -0.0020141601562500, -0.0025329589843750, +-0.0024108886718750, 0.0007934570312500, -0.0042724609375000, -0.0003662109375000, +-0.0018615722656250, 0.0017089843750000, 0.0003051757812500, 0.0049133300781250, +-0.0018920898437500, 0.0026855468750000, 0.0031433105468750, 0.0093078613281250, +0.0028991699218750, 0.0090026855468750, 0.0034790039062500, 0.0088806152343750, +0.0062866210937500, 0.0128479003906250, 0.0047912597656250, 0.0119628906250000, +0.0068054199218750, 0.0105590820312500, 0.0068054199218750, 0.0115661621093750, +0.0076904296875000, 0.0103759765625000, 0.0093688964843750, 0.0084228515625000, +0.0079040527343750, 0.0095520019531250, 0.0086364746093750, 0.0075683593750000, +0.0106506347656250, 0.0073242187500000, 0.0070800781250000, 0.0072631835937500, +0.0043640136718750, 0.0067749023437500, 0.0074157714843750, 0.0068969726562500, +-0.0006103515625000, 0.0037536621093750, -0.0000610351562500, 0.0053710937500000, +-0.0005798339843750, 0.0027465820312500, -0.0052795410156250, -0.0018005371093750, +-0.0033569335937500, 0.0006713867187500, -0.0052795410156250, -0.0035705566406250, +-0.0058288574218750, -0.0048522949218750, -0.0053100585937500, -0.0035095214843750, +-0.0057067871093750, -0.0040283203125000, -0.0057678222656250, -0.0043640136718750, +-0.0058593750000000, -0.0018005371093750, -0.0057678222656250, -0.0024108886718750, +-0.0055236816406250, -0.0010681152343750, -0.0057067871093750, 0.0016174316406250, +-0.0058898925781250, 0.0003662109375000, -0.0043640136718750, 0.0018920898437500, +-0.0052795410156250, 0.0024719238281250, -0.0037231445312500, 0.0024414062500000, +-0.0013427734375000, 0.0024719238281250, -0.0032653808593750, 0.0025024414062500, +-0.0015258789062500, 0.0047607421875000, -0.0005798339843750, 0.0038757324218750, +-0.0016479492187500, 0.0059204101562500, -0.0015869140625000, 0.0089416503906250, +-0.0013427734375000, 0.0075378417968750, -0.0056762695312500, 0.0120239257812500, +-0.0032653808593750, 0.0125122070312500, -0.0059509277343750, 0.0126037597656250, +-0.0112915039062500, 0.0148010253906250, -0.0078125000000000, 0.0140686035156250, +-0.0126342773437500, 0.0128479003906250, -0.0134582519531250, 0.0136413574218750, +-0.0118713378906250, 0.0117492675781250, -0.0134887695312500, 0.0094909667968750, +-0.0136108398437500, 0.0104980468750000, -0.0085754394531250, 0.0060729980468750, +-0.0106811523437500, 0.0061340332031250, -0.0084533691406250, 0.0045471191406250, +-0.0033264160156250, 0.0008544921875000, -0.0063781738281250, 0.0016479492187500, +-0.0018310546875000, -0.0009155273437500, -0.0015258789062500, -0.0017089843750000, +-0.0019836425781250, -0.0018615722656250, -0.0000610351562500, -0.0028991699218750, +-0.0006408691406250, -0.0031433105468750, -0.0010375976562500, -0.0034790039062500, +-0.0005493164062500, -0.0037231445312500, -0.0010681152343750, -0.0039367675781250, +-0.0018920898437500, -0.0041503906250000, -0.0014343261718750, -0.0039978027343750, +-0.0021057128906250, -0.0038757324218750, -0.0021667480468750, -0.0039367675781250, +-0.0022277832031250, -0.0038452148437500, -0.0023803710937500, -0.0037841796875000, +-0.0022277832031250, -0.0038452148437500, -0.0029907226562500, -0.0034179687500000, +-0.0026245117187500, -0.0033874511718750, -0.0031433105468750, -0.0034484863281250, +-0.0040588378906250, -0.0034179687500000, -0.0034484863281250, -0.0036010742187500, +-0.0046997070312500, -0.0038757324218750, -0.0046386718750000, -0.0037841796875000, +-0.0048522949218750, -0.0039062500000000, -0.0056762695312500, -0.0041809082031250, +-0.0053100585937500, -0.0039978027343750, -0.0061340332031250, -0.0038757324218750, +-0.0062561035156250, -0.0038757324218750, -0.0059814453125000, -0.0036621093750000, +-0.0062561035156250, -0.0034790039062500, -0.0064392089843750, -0.0036315917968750, +-0.0055541992187500, -0.0039062500000000, -0.0058898925781250, -0.0036621093750000, +-0.0057678222656250, -0.0035095214843750, -0.0050048828125000, -0.0037536621093750, +-0.0053710937500000, -0.0036010742187500, -0.0053100585937500, -0.0030517578125000, +-0.0051269531250000, -0.0032958984375000, -0.0054016113281250, -0.0032043457031250, +-0.0057678222656250, -0.0026550292968750, -0.0056457519531250, -0.0029907226562500, +-0.0054931640625000, -0.0032043457031250, -0.0058593750000000, -0.0026855468750000, +-0.0052795410156250, -0.0032958984375000, -0.0046691894531250, -0.0040588378906250, +-0.0050354003906250, -0.0034179687500000, -0.0034790039062500, -0.0047607421875000, +-0.0038757324218750, -0.0047912597656250, -0.0026245117187500, -0.0044555664062500, +-0.0010375976562500, -0.0052185058593750, -0.0021362304687500, -0.0052795410156250, +0.0016174316406250, -0.0037841796875000, 0.0015563964843750, -0.0047607421875000, +0.0014038085937500, -0.0028991699218750, 0.0036010742187500, -0.0008544921875000, +0.0031433105468750, -0.0028381347656250, 0.0010986328125000, 0.0028381347656250, +0.0024108886718750, 0.0013122558593750, 0.0004577636718750, 0.0030822753906250, +-0.0024108886718750, 0.0080566406250000, -0.0006713867187500, 0.0052795410156250, +-0.0056457519531250, 0.0094299316406250, -0.0050048828125000, 0.0103454589843750, +-0.0063781738281250, 0.0083312988281250, -0.0103149414062500, 0.0093994140625000, +-0.0083007812500000, 0.0102539062500000, -0.0103454589843750, 0.0034484863281250, +-0.0117187500000000, 0.0058288574218750, -0.0091857910156250, 0.0021362304687500, +-0.0080261230468750, -0.0050659179687500, -0.0097045898437500, -0.0011596679687500, +-0.0041198730468750, -0.0094299316406250, -0.0045166015625000, -0.0102844238281250, +-0.0034790039062500, -0.0086669921875000, 0.0002136230468750, -0.0121765136718750, +-0.0012512207031250, -0.0120849609375000, 0.0016479492187500, -0.0058288574218750, +0.0016479492187500, -0.0083923339843750, 0.0018005371093750, -0.0048217773437500, +0.0037841796875000, 0.0021362304687500, 0.0031738281250000, -0.0015869140625000, +0.0019836425781250, 0.0055236816406250, 0.0034179687500000, 0.0057067871093750, +0.0014038085937500, 0.0056152343750000, -0.0012207031250000, 0.0089721679687500, +0.0006713867187500, 0.0075988769531250, -0.0044555664062500, 0.0087890625000000, +-0.0051269531250000, 0.0091857910156250, -0.0029907226562500, 0.0081787109375000, +-0.0044250488281250, 0.0080261230468750, -0.0056152343750000, 0.0086975097656250, +0.0005798339843750, 0.0075378417968750, -0.0002136230468750, 0.0063781738281250, +0.0011291503906250, 0.0080261230468750, 0.0058288574218750, 0.0095825195312500, +0.0037536621093750, 0.0082092285156250, 0.0039672851562500, 0.0095825195312500, +0.0052490234375000, 0.0102233886718750, 0.0051574707031250, 0.0093383789062500, +0.0036621093750000, 0.0087890625000000, 0.0035095214843750, 0.0092773437500000, +0.0068359375000000, 0.0089721679687500, 0.0055847167968750, 0.0081481933593750, +0.0072326660156250, 0.0096130371093750, 0.0113525390625000, 0.0108032226562500, +0.0093383789062500, 0.0095825195312500, 0.0090942382812500, 0.0131835937500000, +0.0116882324218750, 0.0137023925781250, 0.0076599121093750, 0.0122375488281250, +0.0036010742187500}, +{-0.0059814453125000, -0.0038146972656250, -0.0064086914062500, -0.0048217773437500, +-0.0061950683593750, -0.0042419433593750, -0.0061340332031250, -0.0050964355468750, +-0.0062561035156250, -0.0048217773437500, -0.0061950683593750, -0.0051574707031250, +-0.0060424804687500, -0.0058898925781250, -0.0060729980468750, -0.0051269531250000, +-0.0057983398437500, -0.0060729980468750, -0.0061035156250000, -0.0060729980468750, +-0.0054321289062500, -0.0058898925781250, -0.0048217773437500, -0.0064086914062500, +-0.0053100585937500, -0.0061645507812500, -0.0033569335937500, -0.0047607421875000, +-0.0036926269531250, -0.0053100585937500, -0.0027465820312500, -0.0046691894531250, +-0.0011901855468750, -0.0032348632812500, -0.0020446777343750, -0.0039978027343750, +0.0007019042968750, -0.0022583007812500, 0.0005493164062500, -0.0020751953125000, +0.0007019042968750, -0.0022583007812500, 0.0026855468750000, -0.0013732910156250, +0.0019531250000000, -0.0014343261718750, 0.0008239746093750, -0.0027160644531250, +0.0020446777343750, -0.0018005371093750, -0.0000610351562500, -0.0027160644531250, +-0.0025939941406250, -0.0043640136718750, -0.0009765625000000, -0.0031738281250000, +-0.0057678222656250, -0.0062255859375000, -0.0055236816406250, -0.0058593750000000, +-0.0063781738281250, -0.0057678222656250, -0.0096130371093750, -0.0078735351562500, +-0.0080871582031250, -0.0073242187500000, -0.0100708007812500, -0.0059204101562500, +-0.0108642578125000, -0.0077514648437500, -0.0091552734375000, -0.0049438476562500, +-0.0090332031250000, -0.0019531250000000, -0.0098266601562500, -0.0046691894531250, +-0.0048217773437500, 0.0031738281250000, -0.0056457519531250, 0.0022583007812500, +-0.0044250488281250, 0.0035095214843750, -0.0003356933593750, 0.0094299316406250, +-0.0018310546875000, 0.0072326660156250, -0.0002746582031250, 0.0083923339843750, +0.0004577636718750, 0.0107421875000000, -0.0000915527343750, 0.0071411132812500, +-0.0000610351562500, 0.0045776367187500, 0.0000915527343750, 0.0072937011718750, +-0.0007629394531250, -0.0014648437500000, -0.0001220703125000, -0.0007629394531250, +-0.0011901855468750, -0.0019226074218750, -0.0025329589843750, -0.0077819824218750, +-0.0014953613281250, -0.0056152343750000, -0.0042114257812500, -0.0072631835937500, +-0.0041503906250000, -0.0086364746093750, -0.0046081542968750, -0.0066528320312500, +-0.0066833496093750, -0.0061950683593750, -0.0057678222656250, -0.0075683593750000, +-0.0041198730468750, -0.0015563964843750, -0.0058898925781250, -0.0033569335937500, +-0.0039062500000000, -0.0008239746093750, -0.0004272460937500, 0.0051574707031250, +-0.0020446777343750, 0.0018310546875000, 0.0015258789062500, 0.0060119628906250, +0.0014648437500000, 0.0076293945312500, 0.0017089843750000, 0.0067749023437500, +0.0035095214843750, 0.0068664550781250, 0.0029907226562500, 0.0068054199218750, +0.0056457519531250, 0.0078430175781250, 0.0046081542968750, 0.0076904296875000, +0.0056762695312500, 0.0077209472656250, 0.0089111328125000, 0.0081481933593750, +0.0075683593750000, 0.0079956054687500, 0.0080871582031250, 0.0079650878906250, +0.0097045898437500, 0.0083312988281250, 0.0068054199218750, 0.0074768066406250, +0.0047302246093750, 0.0068359375000000, 0.0069274902343750, 0.0075683593750000, +-0.0001525878906250, 0.0051574707031250, -0.0000305175781250, 0.0046691894531250, +-0.0001831054687500, 0.0062561035156250, -0.0040893554687500, 0.0055541992187500, +-0.0031738281250000, 0.0047302246093750, -0.0039978027343750, 0.0115966796875000, +-0.0042114257812500, 0.0105590820312500, -0.0038146972656250, 0.0099792480468750, +-0.0040283203125000, 0.0155944824218750, 0.0087890625000000, 0.0034790039062500, +0.0168457031250000, 0.0129089355468750, 0.0157165527343750, 0.0109558105468750, +0.0143737792968750, 0.0104980468750000, 0.0168457031250000, 0.0142211914062500, +0.0177612304687500, 0.0143737792968750, 0.0108642578125000, 0.0075683593750000, +0.0118103027343750, 0.0095520019531250, 0.0114135742187500, 0.0075988769531250, +0.0066223144531250, 0.0015258789062500, 0.0079040527343750, 0.0038757324218750, +0.0094604492187500, 0.0008544921875000, 0.0076904296875000, 0.0008850097656250, +0.0092468261718750, 0.0000305175781250, 0.0123901367187500, -0.0018005371093750, +0.0108337402343750, -0.0004272460937500, 0.0115966796875000, -0.0045166015625000, +0.0130310058593750, -0.0046386718750000, 0.0105895996093750, -0.0035400390625000, +0.0082702636718750, -0.0057678222656250, 0.0103454589843750, -0.0059814453125000, +0.0082702636718750, -0.0000915527343750, 0.0071105957031250, -0.0016784667968750, +0.0074157714843750, -0.0006713867187500, 0.0080261230468750, 0.0049133300781250, +0.0078430175781250, 0.0033569335937500, 0.0044555664062500, 0.0009155273437500, +0.0060424804687500, 0.0023193359375000, 0.0035400390625000, 0.0014953613281250, +-0.0003051757812500, -0.0015869140625000, 0.0019531250000000, -0.0008239746093750, +-0.0054931640625000, 0.0003051757812500, -0.0044860839843750, -0.0009765625000000, +-0.0061035156250000, 0.0007934570312500, -0.0122375488281250, 0.0035705566406250, +-0.0095520019531250, 0.0018310546875000, -0.0099487304687500, 0.0028686523437500, +-0.0123596191406250, 0.0042419433593750, -0.0087585449218750, 0.0026855468750000, +-0.0050964355468750, 0.0011291503906250, -0.0079650878906250, 0.0021362304687500, +-0.0023193359375000, 0.0003662109375000, -0.0014038085937500, 0.0002746582031250, +-0.0029602050781250, 0.0000915527343750, -0.0009155273437500, -0.0007324218750000, +-0.0001525878906250, -0.0002746582031250, -0.0053405761718750, -0.0013427734375000, +-0.0036010742187500, -0.0011901855468750, -0.0045471191406250, -0.0017700195312500, +-0.0091857910156250, -0.0027160644531250, -0.0072631835937500, -0.0020751953125000, +-0.0074462890625000, -0.0042419433593750, -0.0090942382812500, -0.0037841796875000, +-0.0069885253906250, -0.0049438476562500, -0.0050354003906250, -0.0068969726562500, +-0.0066833496093750, -0.0056762695312500, -0.0021057128906250, -0.0095520019531250, +-0.0028381347656250, -0.0095214843750000, -0.0017395019531250, -0.0092468261718750, +0.0017395019531250, -0.0115661621093750, -0.0002136230468750, -0.0113220214843750, +0.0025939941406250, -0.0090637207031250, 0.0032653808593750, -0.0101013183593750, +0.0023193359375000, -0.0087890625000000, 0.0028686523437500, -0.0062255859375000, +0.0029907226562500, -0.0075988769531250, 0.0012817382812500, -0.0046691894531250, +0.0015563964843750, -0.0047607421875000, 0.0011901855468750, -0.0042419433593750, +-0.0001525878906250, -0.0023193359375000, 0.0004577636718750, -0.0032348632812500, +0.0001220703125000, -0.0019836425781250, -0.0003051757812500, -0.0015258789062500, +0.0003967285156250, -0.0023498535156250, 0.0006408691406250, -0.0024108886718750, +-0.0000915527343750, -0.0019836425781250, 0.0019531250000000, -0.0036315917968750, +0.0014953613281250, -0.0035095214843750, 0.0019226074218750, -0.0037841796875000, +0.0033264160156250, -0.0047607421875000, 0.0023803710937500, -0.0042724609375000, +0.0041198730468750, -0.0056457519531250, 0.0037231445312500, -0.0053710937500000, +0.0038757324218750, -0.0059509277343750, 0.0049133300781250, -0.0072021484375000, +0.0040283203125000, -0.0065307617187500, 0.0054016113281250, -0.0072631835937500, +0.0051269531250000, -0.0076293945312500, 0.0051574707031250, -0.0071411132812500, +0.0059509277343750, -0.0069580078125000, 0.0052490234375000, -0.0072937011718750, +0.0059204101562500, -0.0064086914062500, 0.0057983398437500, -0.0065307617187500, +0.0056762695312500, -0.0063171386718750, 0.0059204101562500, -0.0056457519531250, +0.0054016113281250, -0.0059204101562500, 0.0055541992187500, -0.0053100585937500, +0.0057678222656250, -0.0051574707031250, 0.0053100585937500, -0.0053710937500000, +0.0050354003906250, -0.0052185058593750, 0.0050659179687500, -0.0051269531250000, +0.0039367675781250, -0.0055847167968750, 0.0040588378906250, -0.0058288574218750, +0.0032653808593750, -0.0051574707031250, 0.0019836425781250, -0.0050659179687500, +0.0021667480468750, -0.0056457519531250, 0.0004577636718750, -0.0033569335937500, +0.0003967285156250, -0.0039062500000000, -0.0003356933593750, -0.0033264160156250, +-0.0015869140625000, -0.0013732910156250, -0.0011291503906250, -0.0024108886718750, +-0.0031127929687500, -0.0018005371093750, -0.0030212402343750, -0.0007629394531250, +-0.0035705566406250, -0.0027160644531250, -0.0050354003906250, -0.0037841796875000, +-0.0043945312500000, -0.0023193359375000, -0.0056762695312500, -0.0074157714843750, +-0.0059204101562500, -0.0069274902343750, -0.0056762695312500, -0.0073242187500000, +-0.0062866210937500, -0.0107727050781250, -0.0064392089843750, -0.0094909667968750, +-0.0054626464843750, -0.0091247558593750, -0.0058898925781250, -0.0108337402343750, +-0.0054931640625000, -0.0084228515625000, -0.0047302246093750, -0.0059204101562500, +-0.0056762695312500, -0.0082702636718750, -0.0044250488281250, -0.0032043457031250, +-0.0045776367187500, -0.0029296875000000, -0.0045471191406250, -0.0039672851562500, +-0.0037231445312500, -0.0021057128906250, -0.0040283203125000, -0.0022277832031250, +-0.0036621093750000, -0.0039978027343750, -0.0039062500000000, -0.0037536621093750, +-0.0039978027343750, -0.0041809082031250, -0.0039978027343750, -0.0054016113281250, +-0.0039367675781250, -0.0047302246093750, -0.0025329589843750, -0.0052795410156250, +-0.0033874511718750, -0.0058593750000000, -0.0017395019531250, -0.0049743652343750, +0.0005187988281250, -0.0042724609375000, -0.0010070800781250, -0.0048522949218750, +0.0025939941406250, -0.0035400390625000, 0.0026550292968750, -0.0038757324218750, +0.0028686523437500, -0.0031127929687500, 0.0047912597656250, -0.0018005371093750, +0.0041503906250000, -0.0027160644531250, 0.0048828125000000, -0.0013427734375000, +0.0051879882812500, -0.0014038085937500, 0.0046997070312500, -0.0008850097656250, +0.0045166015625000, 0.0001220703125000, 0.0046081542968750, -0.0006103515625000, +0.0036926269531250, 0.0010681152343750, 0.0035095214843750, 0.0007019042968750, +0.0035095214843750, 0.0014648437500000, 0.0030517578125000, 0.0030822753906250, +0.0030822753906250, 0.0021667480468750, 0.0042419433593750, 0.0039672851562500, +0.0039367675781250, 0.0045166015625000, 0.0037841796875000, 0.0033569335937500, +0.0046997070312500, 0.0031738281250000, 0.0045471191406250, 0.0042419433593750, +0.0027465820312500, 0.0035095214843750, 0.0034790039062500, 0.0025024414062500, +0.0023803710937500, 0.0035400390625000, 0.0001220703125000, 0.0046691894531250, +0.0012207031250000, 0.0039367675781250, 0.0002136230468750, 0.0052490234375000, +-0.0005493164062500, 0.0061645507812500, 0.0008239746093750, 0.0042419433593750, +0.0018310546875000, 0.0036926269531250, 0.0010681152343750, 0.0053405761718750, +0.0028686523437500, -0.0007934570312500, 0.0026855468750000, -0.0000305175781250, +0.0034790039062500, 0.0003967285156250, 0.0048217773437500, -0.0037231445312500, +0.0039672851562500, -0.0030822753906250, 0.0069580078125000, 0.0005798339843750, +0.0062866210937500, -0.0013732910156250, 0.0072631835937500, 0.0012512207031250, +0.0102844238281250, 0.0072326660156250, 0.0100097656250000, 0.0067138671875000, +0.0128173828125000, 0.0098876953125000, 0.0124511718750000, 0.0095214843750000, +0.0113220214843750, 0.0094909667968750, 0.0128173828125000, 0.0114135742187500, +0.0131225585937500, 0.0107421875000000, 0.0092773437500000, 0.0111389160156250, +0.0106506347656250, 0.0117187500000000, 0.0087890625000000, 0.0104064941406250, +0.0054321289062500, 0.0097961425781250, 0.0077819824218750, 0.0108642578125000, +0.0014343261718750}, +{0.0053710937500000, -0.0018920898437500, 0.0044555664062500, -0.0055236816406250, +0.0047607421875000, -0.0045471191406250, 0.0044250488281250, -0.0056762695312500, +0.0037231445312500, -0.0090637207031250, 0.0043945312500000, -0.0075073242187500, +0.0026855468750000, -0.0086669921875000, 0.0031433105468750, -0.0099792480468750, +0.0024414062500000, -0.0080566406250000, 0.0008239746093750, -0.0070190429687500, +0.0015869140625000, -0.0086669921875000, -0.0004272460937500, -0.0037536621093750, +-0.0004577636718750, -0.0043945312500000, -0.0007629394531250, -0.0041503906250000, +-0.0021057128906250, -0.0008544921875000, -0.0019531250000000, -0.0019836425781250, +-0.0029296875000000, -0.0028381347656250, -0.0031433105468750, -0.0018310546875000, +-0.0031738281250000, -0.0028076171875000, -0.0036926269531250, -0.0045471191406250, +-0.0035400390625000, -0.0037841796875000, -0.0029296875000000, -0.0045776367187500, +-0.0031433105468750, -0.0048217773437500, -0.0031738281250000, -0.0045166015625000, +-0.0026550292968750, -0.0047912597656250, -0.0028686523437500, -0.0047912597656250, +-0.0035400390625000, -0.0036010742187500, -0.0029602050781250, -0.0038146972656250, +-0.0038146972656250, -0.0038146972656250, -0.0050964355468750, -0.0032653808593750, +-0.0042724609375000, -0.0033569335937500, -0.0055541992187500, -0.0023803710937500, +-0.0060424804687500, -0.0029907226562500, -0.0051879882812500, -0.0021972656250000, +-0.0052795410156250, -0.0010986328125000, -0.0058288574218750, -0.0018310546875000, +-0.0033569335937500, 0.0012512207031250, -0.0041809082031250, 0.0005798339843750, +-0.0027465820312500, 0.0011901855468750, -0.0002746582031250, 0.0036010742187500, +-0.0019836425781250, 0.0025329589843750, 0.0013427734375000, 0.0035400390625000, +0.0012817382812500, 0.0039978027343750, 0.0012512207031250, 0.0034790039062500, +0.0030822753906250, 0.0034484863281250, 0.0025024414062500, 0.0036926269531250, +0.0026245117187500, 0.0031433105468750, 0.0028381347656250, 0.0031433105468750, +0.0030212402343750, 0.0038757324218750, 0.0031433105468750, 0.0039672851562500, +0.0030212402343750, 0.0032348632812500, 0.0036621093750000, 0.0035400390625000, +0.0039062500000000, 0.0046691894531250, 0.0036315917968750, 0.0030212402343750, +0.0036926269531250, 0.0016784667968750, 0.0039062500000000, 0.0030822753906250, +0.0022277832031250, -0.0012817382812500, 0.0028991699218750, -0.0006713867187500, +0.0021362304687500, -0.0006713867187500, 0.0001525878906250, -0.0036010742187500, +0.0012512207031250, -0.0024719238281250, 0.0002441406250000, -0.0002136230468750, +-0.0003967285156250, -0.0025634765625000, 0.0009765625000000, 0.0006408691406250, +0.0014038085937500, 0.0053100585937500, 0.0004272460937500, 0.0023498535156250, +0.0040588378906250, 0.0084228515625000, 0.0036315917968750, 0.0087585449218750, +0.0043945312500000, 0.0082397460937500, 0.0071411132812500, 0.0109252929687500, +0.0066528320312500, 0.0105590820312500, 0.0086364746093750, 0.0095825195312500, +0.0078735351562500, 0.0099487304687500, 0.0086364746093750, 0.0095520019531250, +0.0104675292968750, 0.0088195800781250, 0.0089416503906250, 0.0091857910156250, +0.0107421875000000, 0.0074157714843750, 0.0115966796875000, 0.0080871582031250, +0.0100097656250000, 0.0070800781250000, 0.0094909667968750, 0.0050659179687500, +0.0105895996093750, 0.0061340332031250, 0.0077514648437500, 0.0038146972656250, +0.0083312988281250, 0.0040588378906250, 0.0067749023437500, 0.0031127929687500, +0.0046691894531250, 0.0009460449218750, 0.0065002441406250, 0.0020751953125000, +-0.0000305175781250, 0.0005493164062500, 0.0014343261718750, 0.0000000000000000, +-0.0007019042968750, 0.0003356933593750, -0.0068969726562500, 0.0000305175781250, +-0.0039367675781250, -0.0001220703125000, -0.0056457519531250, 0.0005493164062500, +-0.0082397460937500, 0.0000915527343750, -0.0046081542968750, 0.0006103515625000, +-0.0018005371093750, 0.0013427734375000, -0.0048828125000000, 0.0005798339843750, +0.0017395019531250, 0.0025024414062500, 0.0018005371093750, 0.0021972656250000, +0.0013732910156250, 0.0029296875000000, 0.0042419433593750, 0.0042724609375000, +0.0031433105468750, 0.0033569335937500, 0.0034484863281250, 0.0066528320312500, +0.0039062500000000, 0.0067443847656250, 0.0030517578125000, 0.0061950683593750, +0.0024719238281250, 0.0079040527343750, 0.0030212402343750, 0.0078430175781250, +0.0018310546875000, 0.0050354003906250, 0.0021362304687500, 0.0062866210937500, +0.0013122558593750, 0.0037536621093750, 0.0002441406250000, -0.0001831054687500, +0.0011596679687500, 0.0018920898437500, -0.0010986328125000, -0.0027465820312500, +-0.0003967285156250, -0.0036621093750000, -0.0009155273437500, -0.0032348632812500, +-0.0027465820312500, -0.0049438476562500, -0.0015563964843750, -0.0048522949218750, +-0.0032653808593750, -0.0034484863281250, -0.0031738281250000, -0.0036010742187500, +-0.0025329589843750, -0.0033264160156250, -0.0035400390625000, -0.0021362304687500, +-0.0036926269531250, -0.0020446777343750, -0.0015258789062500, -0.0026245117187500, +-0.0019226074218750, -0.0021057128906250, -0.0018310546875000, -0.0018920898437500, +-0.0003967285156250, -0.0023193359375000, -0.0009155273437500, -0.0019226074218750, +-0.0003967285156250, -0.0011291503906250, 0.0004272460937500, -0.0014953613281250, +-0.0017089843750000, -0.0004272460937500, -0.0028686523437500, 0.0008544921875000, +-0.0009155273437500, 0.0001525878906250, -0.0058593750000000, 0.0025939941406250, +-0.0058898925781250, 0.0025024414062500, -0.0057678222656250, 0.0035095214843750, +-0.0081176757812500, 0.0054931640625000, -0.0074462890625000, 0.0048828125000000, +-0.0077514648437500, 0.0072326660156250, -0.0080566406250000, 0.0073852539062500, +-0.0074768066406250, 0.0076599121093750, -0.0072021484375000, 0.0090637207031250, +-0.0073852539062500, 0.0086059570312500, -0.0064086914062500, 0.0087890625000000, +-0.0065002441406250, 0.0091247558593750, -0.0059814453125000, 0.0085754394531250, +-0.0052185058593750, 0.0080871582031250, -0.0057067871093750, 0.0083312988281250, +-0.0040893554687500, 0.0074462890625000, -0.0043334960937500, 0.0072631835937500, +-0.0040588378906250, 0.0072326660156250, -0.0028991699218750, 0.0067443847656250, +-0.0034179687500000, 0.0065307617187500, -0.0025634765625000, 0.0065917968750000, +-0.0027770996093750, 0.0061950683593750, -0.0022888183593750, 0.0061035156250000, +-0.0014648437500000, 0.0061950683593750, -0.0022277832031250, 0.0058898925781250, +-0.0007324218750000, 0.0060119628906250, -0.0006713867187500, 0.0054626464843750, +-0.0011596679687500, 0.0057373046875000, -0.0005798339843750, 0.0061035156250000, +-0.0005187988281250, 0.0051574707031250, -0.0017395019531250, 0.0062255859375000, +-0.0015869140625000, 0.0060424804687500, -0.0015258789062500, 0.0061340332031250, +-0.0023193359375000, 0.0067443847656250, -0.0021972656250000, 0.0065002441406250, +-0.0016784667968750, 0.0072326660156250, -0.0016784667968750, 0.0069885253906250, +-0.0016784667968750, 0.0068664550781250, -0.0013732910156250, 0.0072021484375000, +-0.0012817382812500, 0.0069580078125000, -0.0012817382812500, 0.0071411132812500, +-0.0013427734375000, 0.0069885253906250, -0.0010681152343750, 0.0073852539062500, +-0.0007934570312500, 0.0077514648437500, -0.0010375976562500, 0.0072326660156250, +-0.0010681152343750, 0.0084838867187500, -0.0007019042968750, 0.0082092285156250, +-0.0016479492187500, 0.0085449218750000, -0.0025024414062500, 0.0096435546875000, +-0.0019836425781250, 0.0090026855468750, -0.0043945312500000, 0.0093994140625000, +-0.0043334960937500, 0.0096740722656250, -0.0047912597656250, 0.0090942382812500, +-0.0063781738281250, 0.0088195800781250, -0.0058898925781250, 0.0091552734375000, +-0.0066223144531250, 0.0077819824218750, -0.0069885253906250, 0.0082397460937500, +-0.0066528320312500, 0.0074157714843750, -0.0067138671875000, 0.0060119628906250, +-0.0068664550781250, 0.0069580078125000, -0.0055236816406250, 0.0045776367187500, +-0.0059509277343750, 0.0047302246093750, -0.0049743652343750, 0.0046691894531250, +-0.0034484863281250, 0.0030517578125000, -0.0041809082031250, 0.0033874511718750, +-0.0019226074218750, 0.0038757324218750, -0.0019226074218750, 0.0032958984375000, +-0.0016784667968750, 0.0039062500000000, -0.0002441406250000, 0.0050048828125000, +-0.0006713867187500, 0.0042724609375000, -0.0002136230468750, 0.0049438476562500, +-0.0000915527343750, 0.0055847167968750, 0.0000915527343750, 0.0039978027343750, +0.0003356933593750, 0.0035705566406250, 0.0001831054687500, 0.0047302246093750, +0.0008239746093750, -0.0009460449218750, 0.0008544921875000, 0.0002441406250000, +0.0012817382812500, -0.0014648437500000, 0.0019836425781250, -0.0064392089843750, +0.0018005371093750, -0.0040283203125000, 0.0027465820312500, -0.0066833496093750, +0.0030517578125000, -0.0082092285156250, 0.0023498535156250, -0.0065307617187500, +0.0021362304687500, -0.0065002441406250, 0.0028381347656250, -0.0073547363281250, +0.0025939941406250, -0.0016479492187500, 0.0013122558593750, -0.0031738281250000, +0.0032043457031250, -0.0006408691406250, 0.0050964355468750, 0.0050659179687500, +0.0036621093750000, 0.0020141601562500, 0.0068664550781250, 0.0054626464843750, +0.0068664550781250, 0.0080261230468750, 0.0063171386718750, 0.0037536621093750, +0.0084838867187500, 0.0018310546875000, 0.0083618164062500, 0.0047302246093750, +0.0033874511718750, -0.0063171386718750, 0.0052490234375000, -0.0061340332031250, +0.0028381347656250, -0.0063781738281250, -0.0024108886718750, -0.0126953125000000, +0.0004882812500000, -0.0111083984375000, -0.0037536621093750, -0.0103759765625000, +-0.0048828125000000, -0.0124816894531250, -0.0033874511718750, -0.0083312988281250, +-0.0039978027343750, -0.0047302246093750, -0.0043640136718750, -0.0081176757812500, +-0.0015869140625000, 0.0019836425781250, -0.0025329589843750, 0.0021057128906250, +-0.0008544921875000, 0.0018615722656250, 0.0015869140625000, 0.0068969726562500, +-0.0000305175781250, 0.0059204101562500, 0.0064392089843750, 0.0059509277343750, +0.0050354003906250, 0.0061340332031250, 0.0075683593750000, 0.0069885253906250, +0.0133361816406250, 0.0074768066406250, 0.0104370117187500, 0.0065002441406250, +0.0159912109375000, 0.0082702636718750, 0.0174560546875000, 0.0089721679687500, +0.0151062011718750, 0.0077209472656250, 0.0148620605468750, 0.0067443847656250, +0.0075988769531250, 0.0068359375000000, 0.0119323730468750, 0.0090942382812500, +0.0096740722656250, 0.0089416503906250, 0.0115661621093750, 0.0082092285156250, +0.0155639648437500, 0.0084533691406250, 0.0137023925781250, 0.0088806152343750, +0.0112304687500000, 0.0070190429687500, 0.0140991210937500, 0.0066833496093750, +0.0110473632812500, 0.0077209472656250, 0.0059509277343750, 0.0075683593750000, +0.0089721679687500, 0.0068054199218750, 0.0041503906250000, 0.0087280273437500, +0.0034790039062500, 0.0089416503906250, 0.0033874511718750, 0.0081787109375000, +0.0015869140625000, 0.0088195800781250, 0.0024108886718750, 0.0091247558593750, +-0.0000305175781250, 0.0058288574218750, 0.0005798339843750, 0.0066528320312500, +-0.0017395019531250, 0.0055541992187500, -0.0044555664062500, 0.0029602050781250, +-0.0018615722656250, 0.0043640136718750, -0.0068664550781250, 0.0010681152343750, +-0.0084228515625000, 0.0016784667968750, -0.0058898925781250, 0.0003051757812500, +-0.0058898925781250, -0.0026855468750000, -0.0073852539062500, -0.0008850097656250, +-0.0032653808593750, -0.0036010742187500, -0.0026855468750000, -0.0045471191406250, +-0.0041809082031250}, +{0.0000915527343750, 0.0093078613281250, 0.0001525878906250, 0.0080261230468750, +0.0012817382812500, 0.0056762695312500, 0.0010681152343750, 0.0071105957031250, +0.0017089843750000, 0.0041503906250000, 0.0015563964843750, 0.0036010742187500, +0.0020751953125000, 0.0045471191406250, 0.0027770996093750, 0.0037536621093750, +0.0024414062500000, 0.0033569335937500, 0.0038146972656250, 0.0051574707031250, +0.0039062500000000, 0.0052795410156250, 0.0039062500000000, 0.0045471191406250, +0.0048217773437500, 0.0054016113281250, 0.0048217773437500, 0.0057067871093750, +0.0036926269531250, 0.0021667480468750, 0.0039978027343750, 0.0035705566406250, +0.0043640136718750, 0.0010986328125000, 0.0032958984375000, -0.0027770996093750, +0.0031127929687500, -0.0003356933593750, 0.0057067871093750, -0.0072021484375000, +0.0055847167968750, -0.0072326660156250, 0.0051269531250000, -0.0069580078125000, +0.0066223144531250, -0.0111389160156250, 0.0066223144531250, -0.0102844238281250, +0.0036315917968750, -0.0063476562500000, 0.0055236816406250, -0.0090026855468750, +0.0021667480468750, -0.0051879882812500, -0.0029602050781250, 0.0012207031250000, +0.0003967285156250, -0.0023498535156250, -0.0043945312500000, 0.0032043457031250, +-0.0058898925781250, 0.0056152343750000, -0.0038146972656250, 0.0018615722656250, +-0.0042419433593750, 0.0009155273437500, -0.0051269531250000, 0.0029296875000000, +-0.0006103515625000, -0.0044250488281250, -0.0012207031250000, -0.0033569335937500, +-0.0002136230468750, -0.0057678222656250, 0.0026855468750000, -0.0120849609375000, +0.0013122558593750, -0.0086364746093750, 0.0055847167968750, -0.0100708007812500, +0.0044250488281250, -0.0137634277343750, 0.0066528320312500, -0.0082092285156250, +0.0108642578125000, -0.0031433105468750, 0.0081481933593750, -0.0073547363281250, +0.0129089355468750, 0.0030212402343750, 0.0141906738281250, 0.0036315917968750, +0.0124511718750000, 0.0028076171875000, 0.0134277343750000, 0.0072021484375000, +0.0142517089843750, 0.0065917968750000, 0.0090332031250000, 0.0063781738281250, +0.0093383789062500, 0.0064086914062500, 0.0103454589843750, 0.0070190429687500, +0.0074462890625000, 0.0079345703125000, 0.0119323730468750, 0.0066833496093750, +0.0111389160156250, 0.0056762695312500, 0.0139465332031250, 0.0052185058593750, +0.0100097656250000, 0.0068969726562500, 0.0058898925781250, 0.0076599121093750, +0.0091552734375000, 0.0062255859375000, 0.0045166015625000, 0.0096130371093750, +0.0032043457031250, 0.0104370117187500, 0.0044860839843750, 0.0085449218750000, +0.0042419433593750, 0.0086059570312500, 0.0038757324218750, 0.0097045898437500, +0.0026855468750000, 0.0059204101562500, 0.0041503906250000, 0.0055847167968750, +0.0019531250000000, 0.0067749023437500, -0.0013732910156250, 0.0055236816406250, +0.0005493164062500, 0.0050048828125000, -0.0030212402343750, 0.0086364746093750, +-0.0035705566406250, 0.0085449218750000, -0.0022277832031250, 0.0079956054687500, +-0.0032653808593750, 0.0099487304687500, -0.0041198730468750, 0.0098266601562500, +-0.0010375976562500, 0.0064392089843750, -0.0003356933593750, 0.0076904296875000, +-0.0029296875000000, 0.0062561035156250, -0.0028991699218750, 0.0029602050781250, +-0.0011291503906250, 0.0045471191406250, -0.0080566406250000, 0.0010986328125000, +-0.0072631835937500, 0.0014038085937500, -0.0080261230468750, 0.0002746582031250, +-0.0130004882812500, -0.0023498535156250, -0.0112609863281250, -0.0008850097656250, +-0.0106201171875000, -0.0038146972656250, -0.0130310058593750, -0.0044250488281250, +-0.0092163085937500, -0.0027160644531250, -0.0054016113281250, -0.0032653808593750, +-0.0086364746093750, -0.0041198730468750, -0.0003967285156250, 0.0011291503906250, +-0.0005798339843750, 0.0005493164062500, -0.0006713867187500, 0.0010070800781250, +0.0037231445312500, 0.0044555664062500, 0.0021667480468750, 0.0035095214843750, +0.0017700195312500, 0.0037231445312500, 0.0029907226562500, 0.0042114257812500, +0.0016784667968750, 0.0039062500000000, -0.0003662109375000, 0.0034790039062500, +0.0009155273437500, 0.0036926269531250, 0.0007019042968750, 0.0035400390625000, +-0.0011291503906250, 0.0035705566406250, 0.0012817382812500, 0.0032958984375000, +0.0038146972656250, 0.0032348632812500, 0.0016174316406250, 0.0034179687500000, +0.0057983398437500, 0.0020141601562500, 0.0062561035156250, 0.0022277832031250, +0.0056762695312500, 0.0020751953125000, 0.0072021484375000, 0.0012817382812500, +0.0070800781250000, 0.0014648437500000, 0.0060424804687500, 0.0003356933593750, +0.0065917968750000, 0.0010986328125000, 0.0061950683593750, -0.0004272460937500, +0.0053100585937500, -0.0023498535156250, 0.0058288574218750, -0.0010070800781250, +0.0042724609375000, -0.0043029785156250, 0.0043945312500000, -0.0043945312500000, +0.0042419433593750, -0.0043945312500000, 0.0032043457031250, -0.0059204101562500, +0.0036315917968750, -0.0053710937500000, 0.0033264160156250, -0.0062255859375000, +0.0028991699218750, -0.0061340332031250, 0.0030517578125000, -0.0061645507812500, +0.0031738281250000, -0.0068054199218750, 0.0028381347656250, -0.0065612792968750, +0.0029907226562500, -0.0059509277343750, 0.0027770996093750, -0.0064086914062500, +0.0027770996093750, -0.0058288574218750, 0.0030517578125000, -0.0047607421875000, +0.0028381347656250, -0.0053100585937500, 0.0029296875000000, -0.0045166015625000, +0.0031433105468750, -0.0044250488281250, 0.0026855468750000, -0.0043029785156250, +0.0024719238281250, -0.0039367675781250, 0.0027465820312500, -0.0043334960937500, +0.0012817382812500, -0.0032653808593750, 0.0018005371093750, -0.0033569335937500, +0.0011291503906250, -0.0034790039062500, -0.0001525878906250, -0.0028686523437500, +0.0008544921875000, -0.0029602050781250, -0.0014648437500000, -0.0032348632812500, +-0.0009765625000000, -0.0031127929687500, -0.0014343261718750, -0.0032958984375000, +-0.0030212402343750, -0.0036010742187500, -0.0017089843750000, -0.0036315917968750, +-0.0034790039062500, -0.0036926269531250, -0.0031127929687500, -0.0038757324218750, +-0.0032043457031250, -0.0037841796875000, -0.0042114257812500, -0.0037536621093750, +-0.0031127929687500, -0.0039978027343750, -0.0042724609375000, -0.0034179687500000, +-0.0040893554687500, -0.0035400390625000, -0.0039978027343750, -0.0036010742187500, +-0.0043945312500000, -0.0031738281250000, -0.0037231445312500, -0.0033569335937500, +-0.0041809082031250, -0.0040283203125000, -0.0038757324218750, -0.0035095214843750, +-0.0035400390625000, -0.0045471191406250, -0.0036315917968750, -0.0057983398437500, +-0.0031127929687500, -0.0049438476562500, -0.0028991699218750, -0.0068054199218750, +-0.0027465820312500, -0.0072631835937500, -0.0022888183593750, -0.0065917968750000, +-0.0019836425781250, -0.0070190429687500, -0.0020446777343750, -0.0073852539062500, +-0.0013732910156250, -0.0056762695312500, -0.0011291503906250, -0.0062255859375000, +-0.0012207031250000, -0.0055236816406250, -0.0010070800781250, -0.0040893554687500, +-0.0009460449218750, -0.0050659179687500, -0.0012817382812500, -0.0028991699218750, +-0.0010681152343750, -0.0028991699218750, -0.0012512207031250, -0.0030517578125000, +-0.0016174316406250, -0.0018310546875000, -0.0013122558593750, -0.0020751953125000, +-0.0018920898437500, -0.0028991699218750, -0.0017395019531250, -0.0024719238281250, +-0.0018005371093750, -0.0030212402343750, -0.0020751953125000, -0.0040283203125000, +-0.0015869140625000, -0.0034179687500000, -0.0017395019531250, -0.0043640136718750, +-0.0018615722656250, -0.0043640136718750, -0.0013732910156250, -0.0041198730468750, +-0.0009765625000000, -0.0046386718750000, -0.0012512207031250, -0.0044860839843750, +-0.0007019042968750, -0.0028991699218750, -0.0003662109375000, -0.0035705566406250, +-0.0001525878906250, -0.0027770996093750, 0.0001220703125000, -0.0013122558593750, +0.0000305175781250, -0.0021362304687500, 0.0004272460937500, 0.0004882812500000, +0.0006103515625000, -0.0003051757812500, 0.0003967285156250, 0.0007019042968750, +0.0003356933593750, 0.0032653808593750, 0.0003356933593750, 0.0020141601562500, +-0.0006103515625000, 0.0041503906250000, -0.0005493164062500, 0.0044860839843750, +-0.0007324218750000, 0.0038452148437500, -0.0013122558593750, 0.0045471191406250, +-0.0010681152343750, 0.0046997070312500, -0.0013427734375000, 0.0035400390625000, +-0.0014038085937500, 0.0035400390625000, -0.0011596679687500, 0.0039062500000000, +-0.0010986328125000, 0.0034179687500000, -0.0013122558593750, 0.0030822753906250, +-0.0005187988281250, 0.0045776367187500, -0.0001220703125000, 0.0047912597656250, +-0.0012817382812500, 0.0035095214843750, -0.0017700195312500, 0.0035095214843750, +-0.0010070800781250, 0.0042419433593750, -0.0040893554687500, 0.0008544921875000, +-0.0042724609375000, 0.0012817382812500, -0.0043640136718750, 0.0011901855468750, +-0.0060729980468750, -0.0015869140625000, -0.0056457519531250, -0.0008544921875000, +-0.0051574707031250, 0.0016479492187500, -0.0058288574218750, 0.0000610351562500, +-0.0048217773437500, 0.0021667480468750, -0.0034484863281250, 0.0057067871093750, +-0.0041503906250000, 0.0036010742187500, -0.0023193359375000, 0.0075378417968750, +-0.0021057128906250, 0.0075683593750000, -0.0017089843750000, 0.0077514648437500, +-0.0008544921875000, 0.0099792480468750, -0.0012512207031250, 0.0087890625000000, +0.0005798339843750, 0.0087585449218750, 0.0003967285156250, 0.0096130371093750, +0.0007019042968750, 0.0084228515625000, 0.0022583007812500, 0.0073242187500000, +0.0017700195312500, 0.0082092285156250, 0.0004577636718750, 0.0053405761718750, +0.0013122558593750, 0.0054016113281250, 0.0011596679687500, 0.0052795410156250, +-0.0007019042968750, 0.0036315917968750, -0.0002746582031250, 0.0036315917968750, +0.0019531250000000, 0.0019226074218750, 0.0004272460937500, 0.0029602050781250, +0.0015563964843750, 0.0018920898437500, 0.0041503906250000, -0.0003051757812500, +0.0024108886718750, 0.0010375976562500, 0.0049133300781250, -0.0008544921875000, +0.0050048828125000, -0.0016479492187500, 0.0053405761718750, -0.0010681152343750, +0.0063781738281250, -0.0012512207031250, 0.0053710937500000, -0.0013732910156250, +0.0072937011718750, -0.0003356933593750, 0.0075683593750000, -0.0006408691406250, +0.0071716308593750, -0.0003356933593750, 0.0077819824218750, 0.0003662109375000, +0.0077514648437500, -0.0000305175781250, 0.0072937011718750, 0.0017395019531250, +0.0074768066406250, 0.0010986328125000, 0.0075683593750000, 0.0021972656250000, +0.0072631835937500, 0.0042419433593750, 0.0070495605468750, 0.0029907226562500, +0.0069885253906250, 0.0051574707031250, 0.0079345703125000, 0.0061950683593750, +0.0056457519531250, 0.0042114257812500, 0.0043029785156250, 0.0038146972656250, +0.0064086914062500, 0.0051879882812500, -0.0007324218750000, -0.0003662109375000, +0.0004272460937500, 0.0007629394531250, -0.0001220703125000, -0.0009765625000000, +-0.0050964355468750, -0.0058288574218750, -0.0032043457031250, -0.0036010742187500, +-0.0033264160156250, -0.0058593750000000, -0.0048522949218750, -0.0074157714843750, +-0.0028991699218750, -0.0054931640625000, -0.0010681152343750, -0.0045776367187500, +-0.0030517578125000, -0.0057067871093750, 0.0003356933593750, -0.0020751953125000, +0.0005187988281250, -0.0019836425781250, 0.0005187988281250, -0.0021362304687500, +0.0016784667968750, -0.0002136230468750, 0.0008239746093750, -0.0002441406250000, +0.0026855468750000, -0.0008239746093750, 0.0023193359375000, -0.0004882812500000, +0.0029296875000000, -0.0001220703125000, 0.0046386718750000, -0.0003662109375000, +0.0034790039062500}, +{0.0010681152343750, 0.0033874511718750, 0.0010375976562500, 0.0036315917968750, +0.0001831054687500, 0.0034790039062500, 0.0006713867187500, 0.0033264160156250, +0.0000305175781250, 0.0032958984375000, -0.0012207031250000, 0.0036926269531250, +-0.0004272460937500, 0.0036621093750000, -0.0010681152343750, 0.0014648437500000, +-0.0018005371093750, 0.0023498535156250, -0.0007934570312500, 0.0019531250000000, +0.0002136230468750, -0.0003051757812500, -0.0005798339843750, 0.0004272460937500, +0.0003967285156250, 0.0012207031250000, 0.0012512207031250, -0.0002441406250000, +-0.0005187988281250, 0.0019836425781250, -0.0015869140625000, 0.0045471191406250, +-0.0004882812500000, 0.0025939941406250, -0.0045471191406250, 0.0071716308593750, +-0.0044250488281250, 0.0069885253906250, -0.0049743652343750, 0.0070190429687500, +-0.0078125000000000, 0.0094604492187500, -0.0068664550781250, 0.0086059570312500, +-0.0060119628906250, 0.0093994140625000, -0.0073547363281250, 0.0097351074218750, +-0.0057678222656250, 0.0084838867187500, -0.0034790039062500, 0.0082397460937500, +-0.0048522949218750, 0.0091247558593750, -0.0019226074218750, 0.0062866210937500, +-0.0017700195312500, 0.0066528320312500, -0.0017395019531250, 0.0055847167968750, +-0.0003967285156250, 0.0034179687500000, -0.0008544921875000, 0.0047302246093750, +0.0000915527343750, 0.0025329589843750, 0.0004272460937500, 0.0025024414062500, +-0.0000610351562500, 0.0019836425781250, -0.0004882812500000, 0.0005187988281250, +-0.0005798339843750, 0.0005798339843750, -0.0006713867187500, -0.0022888183593750, +-0.0008544921875000, -0.0017395019531250, -0.0004577636718750, -0.0010681152343750, +-0.0003662109375000, -0.0027160644531250, -0.0007629394531250, -0.0028991699218750, +0.0016174316406250, -0.0014343261718750, 0.0007629394531250, -0.0016784667968750, +0.0016784667968750, -0.0010070800781250, 0.0038757324218750, -0.0000610351562500, +0.0025939941406250, -0.0008239746093750, 0.0051269531250000, 0.0013122558593750, +0.0048217773437500, 0.0008544921875000, 0.0050048828125000, 0.0015563964843750, +0.0066223144531250, 0.0035095214843750, 0.0060119628906250, 0.0025024414062500, +0.0073547363281250, 0.0033264160156250, 0.0071716308593750, 0.0043029785156250, +0.0071716308593750, 0.0027465820312500, 0.0080871582031250, 0.0018310546875000, +0.0078735351562500, 0.0029907226562500, 0.0075378417968750, -0.0016174316406250, +0.0076293945312500, -0.0009460449218750, 0.0076904296875000, -0.0015563964843750, +0.0075378417968750, -0.0049438476562500, 0.0073852539062500, -0.0037536621093750, +0.0067443847656250, -0.0046081542968750, 0.0078125000000000, -0.0054931640625000, +0.0058593750000000, -0.0041503906250000, 0.0041503906250000, -0.0032958984375000, +0.0062866210937500, -0.0041809082031250, 0.0009460449218750, -0.0011901855468750, +0.0018005371093750, -0.0012207031250000, 0.0010681152343750, -0.0009460449218750, +-0.0027770996093750, 0.0009765625000000, -0.0008850097656250, 0.0005798339843750, +-0.0017089843750000, 0.0003662109375000, -0.0029602050781250, 0.0010375976562500, +-0.0018920898437500, 0.0010681152343750, -0.0010070800781250, 0.0004882812500000, +-0.0017089843750000, 0.0007629394531250, 0.0004882812500000, 0.0016174316406250, +-0.0003967285156250, 0.0017395019531250, 0.0003051757812500, 0.0016784667968750, +0.0022277832031250, 0.0023498535156250, 0.0008850097656250, 0.0025329589843750, +0.0038146972656250, 0.0010070800781250, 0.0035400390625000, 0.0015258789062500, +0.0032348632812500, 0.0005493164062500, 0.0049438476562500, -0.0013732910156250, +0.0046081542968750, -0.0005798339843750, 0.0037231445312500, -0.0020446777343750, +0.0043640136718750, -0.0025024414062500, 0.0030822753906250, -0.0024719238281250, +0.0016479492187500, -0.0026245117187500, 0.0030517578125000, -0.0023193359375000, +0.0006713867187500, -0.0030517578125000, 0.0004882812500000, -0.0023498535156250, +0.0006103515625000, -0.0027770996093750, -0.0002441406250000, -0.0036621093750000, +0.0003662109375000, -0.0027160644531250, -0.0006408691406250, -0.0045776367187500, +-0.0005187988281250, -0.0041503906250000, -0.0004577636718750, -0.0046997070312500, +-0.0007324218750000, -0.0060729980468750, -0.0005187988281250, -0.0050354003906250, +-0.0018920898437500, -0.0073242187500000, -0.0012207031250000, -0.0068664550781250, +-0.0019531250000000, -0.0072326660156250, -0.0035705566406250, -0.0089416503906250, +-0.0027770996093750, -0.0080566406250000, -0.0043640136718750, -0.0095825195312500, +-0.0042419433593750, -0.0095520019531250, -0.0043945312500000, -0.0094299316406250, +-0.0055236816406250, -0.0101928710937500, -0.0049438476562500, -0.0099182128906250, +-0.0047302246093750, -0.0094909667968750, -0.0054321289062500, -0.0101623535156250, +-0.0043029785156250, -0.0096740722656250, -0.0030822753906250, -0.0089111328125000, +-0.0039367675781250, -0.0096130371093750, -0.0019531250000000, -0.0082092285156250, +-0.0018615722656250, -0.0082397460937500, -0.0017395019531250, -0.0081176757812500, +-0.0006408691406250, -0.0074462890625000, -0.0010375976562500, -0.0079650878906250, +-0.0006408691406250, -0.0072937011718750, -0.0004272460937500, -0.0070495605468750, +-0.0005798339843750, -0.0072326660156250, -0.0005798339843750, -0.0071411132812500, +-0.0004577636718750, -0.0069274902343750, -0.0006103515625000, -0.0068664550781250, +-0.0007629394531250, -0.0070800781250000, -0.0003967285156250, -0.0068054199218750, +-0.0001831054687500, -0.0065307617187500, -0.0005493164062500, -0.0068969726562500, +-0.0002746582031250, -0.0062561035156250, 0.0000000000000000, -0.0064086914062500, +-0.0008544921875000, -0.0061950683593750, -0.0013122558593750, -0.0057983398437500, +-0.0007629394531250, -0.0062255859375000, -0.0029602050781250, -0.0055541992187500, +-0.0026855468750000, -0.0057373046875000, -0.0033264160156250, -0.0054626464843750, +-0.0049438476562500, -0.0049133300781250, -0.0042114257812500, -0.0052795410156250, +-0.0059204101562500, -0.0039672851562500, -0.0060119628906250, -0.0045776367187500, +-0.0056457519531250, -0.0037231445312500, -0.0063476562500000, -0.0026245117187500, +-0.0061950683593750, -0.0036315917968750, -0.0051269531250000, -0.0000610351562500, +-0.0053100585937500, -0.0009765625000000, -0.0047912597656250, 0.0001525878906250, +-0.0037841796875000, 0.0028991699218750, -0.0040893554687500, 0.0011901855468750, +-0.0029296875000000, 0.0051269531250000, -0.0031127929687500, 0.0045166015625000, +-0.0025024414062500, 0.0057067871093750, -0.0014648437500000, 0.0088195800781250, +-0.0021362304687500, 0.0069885253906250, -0.0005798339843750, 0.0102844238281250, +-0.0007324218750000, 0.0104675292968750, -0.0003051757812500, 0.0099182128906250, +0.0005798339843750, 0.0113220214843750, 0.0000305175781250, 0.0111083984375000, +0.0024108886718750, 0.0095520019531250, 0.0017089843750000, 0.0102539062500000, +0.0028076171875000, 0.0090637207031250, 0.0052795410156250, 0.0071411132812500, +0.0039367675781250, 0.0084533691406250, 0.0057678222656250, 0.0065307617187500, +0.0063781738281250, 0.0061340332031250, 0.0056457519531250, 0.0064086914062500, +0.0058593750000000, 0.0061035156250000, 0.0061340332031250, 0.0062561035156250, +0.0046691894531250, 0.0053100585937500, 0.0047912597656250, 0.0057067871093750, +0.0046997070312500, 0.0052185058593750, 0.0037231445312500, 0.0039978027343750, +0.0037536621093750, 0.0046386718750000, 0.0031127929687500, 0.0039367675781250, +0.0035705566406250, 0.0038757324218750, 0.0025634765625000, 0.0034179687500000, +0.0011596679687500, 0.0027160644531250, 0.0020141601562500, 0.0029907226562500, +0.0009765625000000, 0.0018310546875000, 0.0002746582031250, 0.0013732910156250, +0.0008544921875000, 0.0016784667968750, 0.0008850097656250, 0.0015563964843750, +0.0007324218750000, 0.0010681152343750, 0.0037841796875000, 0.0015258789062500, +0.0025939941406250, 0.0020141601562500, 0.0042114257812500, 0.0003662109375000, +0.0076599121093750, -0.0005798339843750, 0.0061645507812500, 0.0006408691406250, +0.0090942382812500, -0.0032653808593750, 0.0093383789062500, -0.0030517578125000, +0.0091247558593750, -0.0030822753906250, 0.0104675292968750, -0.0055236816406250, +0.0102844238281250, -0.0050659179687500, 0.0097351074218750, -0.0049743652343750, +0.0101928710937500, -0.0053405761718750, 0.0092773437500000, -0.0042419433593750, +0.0082092285156250, -0.0040588378906250, 0.0090942382812500, -0.0049743652343750, +0.0074462890625000, 0.0003356933593750, 0.0076904296875000, -0.0000610351562500, +0.0075683593750000, -0.0005187988281250, 0.0062561035156250, 0.0027770996093750, +0.0068359375000000, 0.0022583007812500, 0.0079650878906250, -0.0014953613281250, +0.0071105957031250, 0.0001525878906250, 0.0082092285156250, -0.0016479492187500, +0.0101928710937500, -0.0063476562500000, 0.0089111328125000, -0.0043029785156250, +0.0085144042968750, -0.0038757324218750, 0.0100708007812500, -0.0061950683593750, +0.0086364746093750, -0.0036621093750000, 0.0047912597656250, 0.0022888183593750, +0.0042419433593750, -0.0011291503906250, 0.0033874511718750, -0.0019226074218750, +0.0043029785156250, -0.0039367675781250, 0.0027160644531250, -0.0014038085937500, +0.0013732910156250, 0.0011901855468750, 0.0026855468750000, -0.0007629394531250, +-0.0009460449218750, 0.0019226074218750, -0.0014343261718750, 0.0028381347656250, +-0.0006713867187500, 0.0023498535156250, -0.0021057128906250, 0.0022277832031250, +-0.0025939941406250, 0.0021667480468750, -0.0001831054687500, 0.0047302246093750, +-0.0002441406250000, 0.0033569335937500, -0.0013122558593750, 0.0049743652343750, +-0.0006103515625000, 0.0085144042968750, -0.0002136230468750, 0.0065917968750000, +-0.0026855468750000, 0.0070800781250000, -0.0020446777343750, 0.0089721679687500, +-0.0027160644531250, 0.0063476562500000, -0.0052490234375000, 0.0033264160156250, +-0.0042419433593750, 0.0054016113281250, -0.0031738281250000, 0.0029907226562500, +-0.0040588378906250, 0.0014038085937500, -0.0036315917968750, 0.0036926269531250, +-0.0021362304687500, 0.0052185058593750, -0.0025024414062500, 0.0037536621093750, +-0.0025024414062500, 0.0061950683593750, -0.0023193359375000, 0.0072631835937500, +-0.0015258789062500, 0.0061340332031250, -0.0012512207031250, 0.0058898925781250, +-0.0018920898437500, 0.0066833496093750, -0.0001831054687500, 0.0049438476562500, +-0.0002136230468750, 0.0049743652343750, 0.0003967285156250, 0.0048828125000000, +0.0016174316406250, 0.0043640136718750, 0.0009155273437500, 0.0046691894531250, +0.0020446777343750, 0.0022888183593750, 0.0024719238281250, 0.0034179687500000, +0.0018615722656250, 0.0018615722656250, 0.0018005371093750, -0.0013122558593750, +0.0023193359375000, 0.0003967285156250, 0.0016784667968750, -0.0016174316406250, +0.0015563964843750, -0.0028991699218750, 0.0015258789062500, -0.0013122558593750, +0.0010986328125000, -0.0006408691406250, 0.0012817382812500, -0.0015258789062500, +0.0020446777343750, 0.0016174316406250, 0.0008544921875000, 0.0014648437500000, +0.0031127929687500, 0.0016784667968750, 0.0052795410156250, 0.0034179687500000, +0.0030822753906250, 0.0028076171875000, 0.0086059570312500, 0.0038452148437500, +0.0082702636718750, 0.0037231445312500, 0.0081787109375000, 0.0041503906250000, +0.0114746093750000, 0.0052795410156250, 0.0105285644531250, 0.0047607421875000, +0.0097351074218750, 0.0047607421875000, 0.0112915039062500, 0.0054931640625000, +0.0087585449218750, 0.0045166015625000, 0.0065612792968750, 0.0034179687500000, +0.0088806152343750, 0.0041809082031250, 0.0010375976562500, 0.0025024414062500, +0.0028991699218750}, +{0.0071411132812500, -0.0004882812500000, 0.0065307617187500, -0.0005493164062500, +0.0075988769531250, -0.0014343261718750, 0.0083923339843750, -0.0015869140625000, +0.0074157714843750, -0.0006408691406250, 0.0086059570312500, -0.0033264160156250, +0.0091247558593750, -0.0039672851562500, 0.0084838867187500, -0.0026245117187500, +0.0085144042968750, -0.0029602050781250, 0.0086669921875000, -0.0036621093750000, +0.0063781738281250, -0.0000305175781250, 0.0070800781250000, -0.0008544921875000, +0.0061645507812500, -0.0002441406250000, 0.0039062500000000, 0.0029907226562500, +0.0050659179687500, 0.0018310546875000, 0.0041503906250000, 0.0007934570312500, +0.0033874511718750, 0.0018920898437500, 0.0038757324218750, 0.0005798339843750, +0.0045166015625000, -0.0031738281250000, 0.0014343261718750, 0.0011596679687500, +-0.0032958984375000, 0.0010070800781250, -0.0028991699218750, 0.0033569335937500, +-0.0024719238281250, 0.0007934570312500, -0.0037231445312500, -0.0027770996093750, +-0.0040588378906250, -0.0009765625000000, -0.0021362304687500, -0.0014343261718750, +-0.0025939941406250, -0.0032043457031250, -0.0026245117187500, -0.0012817382812500, +-0.0012207031250000, 0.0012207031250000, -0.0015869140625000, -0.0002136230468750, +-0.0023803710937500, 0.0018920898437500, -0.0020446777343750, 0.0022888183593750, +-0.0015869140625000, 0.0022277832031250, -0.0016784667968750, 0.0025329589843750, +-0.0018310546875000, 0.0022888183593750, -0.0018615722656250, 0.0049438476562500, +-0.0013122558593750, 0.0039062500000000, -0.0016479492187500, 0.0048217773437500, +-0.0019226074218750, 0.0078735351562500, -0.0015869140625000, 0.0065002441406250, +-0.0043640136718750, 0.0060729980468750, -0.0039367675781250, 0.0074462890625000, +-0.0032348632812500, 0.0059509277343750, -0.0052490234375000, 0.0036621093750000, +-0.0054016113281250, 0.0048217773437500, -0.0009765625000000, 0.0042114257812500, +-0.0023498535156250, 0.0033874511718750, -0.0005798339843750, 0.0042114257812500, +0.0037841796875000, 0.0051269531250000, 0.0017700195312500, 0.0046386718750000, +0.0043945312500000, 0.0053100585937500, 0.0053710937500000, 0.0057067871093750, +0.0041503906250000, 0.0052795410156250, 0.0043640136718750, 0.0051269531250000, +0.0051269531250000, 0.0054626464843750, 0.0028076171875000, 0.0047607421875000, +0.0022888183593750, 0.0047607421875000, 0.0035095214843750, 0.0044860839843750, +0.0031738281250000, 0.0043334960937500, 0.0026855468750000, 0.0046997070312500, +0.0061035156250000, 0.0025329589843750, 0.0049438476562500, 0.0031127929687500, +0.0063476562500000, 0.0021972656250000, 0.0095520019531250, -0.0002746582031250, +0.0074462890625000, 0.0007629394531250, 0.0098266601562500, -0.0002746582031250, +0.0112304687500000, -0.0010681152343750, 0.0084228515625000, 0.0000305175781250, +0.0076904296875000, 0.0006713867187500, 0.0096435546875000, -0.0000915527343750, +0.0014343261718750, 0.0018310546875000, 0.0032653808593750, 0.0019226074218750, +0.0010681152343750, 0.0020446777343750, -0.0053710937500000, 0.0028381347656250, +-0.0021362304687500, 0.0025634765625000, -0.0078735351562500, 0.0038452148437500, +-0.0083618164062500, 0.0036621093750000, -0.0081176757812500, 0.0038757324218750, +-0.0110473632812500, 0.0049743652343750, -0.0102233886718750, 0.0046997070312500, +-0.0086669921875000, 0.0039672851562500, -0.0105285644531250, 0.0045166015625000, +-0.0080566406250000, 0.0038452148437500, -0.0051269531250000, 0.0028381347656250, +-0.0079040527343750, 0.0033874511718750, -0.0021667480468750, 0.0019836425781250, +-0.0029907226562500, 0.0021972656250000, -0.0024414062500000, 0.0013732910156250, +0.0010681152343750, 0.0001525878906250, -0.0010070800781250, 0.0009765625000000, +0.0015563964843750, -0.0014343261718750, 0.0016784667968750, -0.0013732910156250, +0.0013122558593750, -0.0014648437500000, 0.0024108886718750, -0.0028381347656250, +0.0018005371093750, -0.0023498535156250, 0.0015869140625000, -0.0028686523437500, +0.0018615722656250, -0.0028381347656250, 0.0010986328125000, -0.0031738281250000, +0.0006103515625000, -0.0036315917968750, 0.0010681152343750, -0.0033569335937500, +-0.0010070800781250, -0.0039672851562500, -0.0004577636718750, -0.0041809082031250, +-0.0012817382812500, -0.0039062500000000, -0.0031127929687500, -0.0040283203125000, +-0.0018615722656250, -0.0041503906250000, -0.0038452148437500, -0.0034790039062500, +-0.0039367675781250, -0.0035705566406250, -0.0038757324218750, -0.0034179687500000, +-0.0047302246093750, -0.0030212402343750, -0.0042419433593750, -0.0032348632812500, +-0.0041198730468750, -0.0025024414062500, -0.0040893554687500, -0.0027160644531250, +-0.0035705566406250, -0.0024414062500000, -0.0031738281250000, -0.0017089843750000, +-0.0032958984375000, -0.0021667480468750, -0.0024414062500000, -0.0016784667968750, +-0.0022583007812500, -0.0015563964843750, -0.0018920898437500, -0.0018615722656250, +-0.0014343261718750, -0.0019226074218750, -0.0016479492187500, -0.0018615722656250, +-0.0005493164062500, -0.0025939941406250, -0.0005187988281250, -0.0026855468750000, +-0.0000610351562500, -0.0025329589843750, 0.0007934570312500, -0.0029602050781250, +0.0007324218750000, -0.0030822753906250, 0.0020751953125000, -0.0018310546875000, +0.0018920898437500, -0.0023803710937500, 0.0025024414062500, -0.0019531250000000, +0.0037536621093750, -0.0005798339843750, 0.0033264160156250, -0.0012207031250000, +0.0046997070312500, -0.0008850097656250, 0.0049743652343750, -0.0002441406250000, +0.0050048828125000, -0.0011596679687500, 0.0057678222656250, -0.0018310546875000, +0.0056762695312500, -0.0010986328125000, 0.0054931640625000, -0.0030822753906250, +0.0058593750000000, -0.0032043457031250, 0.0052795410156250, -0.0025329589843750, +0.0047607421875000, -0.0033264160156250, 0.0051879882812500, -0.0035705566406250, +0.0032958984375000, -0.0010681152343750, 0.0034484863281250, -0.0018615722656250, +0.0025634765625000, -0.0006103515625000, 0.0007629394531250, 0.0018615722656250, +0.0011596679687500, 0.0004272460937500, -0.0015258789062500, 0.0029602050781250, +-0.0014953613281250, 0.0033874511718750, -0.0022277832031250, 0.0027160644531250, +-0.0042724609375000, 0.0033874511718750, -0.0038146972656250, 0.0035705566406250, +-0.0050354003906250, 0.0024719238281250, -0.0055236816406250, 0.0026855468750000, +-0.0052185058593750, 0.0025939941406250, -0.0054626464843750, 0.0017395019531250, +-0.0055541992187500, 0.0019836425781250, -0.0037536621093750, 0.0021667480468750, +-0.0041503906250000, 0.0021667480468750, -0.0036926269531250, 0.0016784667968750, +-0.0020141601562500, 0.0014343261718750, -0.0024414062500000, 0.0019531250000000, +-0.0023803710937500, 0.0004272460937500, -0.0019836425781250, 0.0004882812500000, +-0.0019226074218750, 0.0007324218750000, -0.0019531250000000, -0.0000915527343750, +-0.0020141601562500, 0.0000000000000000, -0.0018920898437500, 0.0009460449218750, +-0.0016479492187500, 0.0003967285156250, -0.0019226074218750, 0.0015869140625000, +-0.0022583007812500, 0.0028991699218750, -0.0019836425781250, 0.0016784667968750, +-0.0020446777343750, 0.0045166015625000, -0.0019226074218750, 0.0044555664062500, +-0.0019836425781250, 0.0049438476562500, -0.0019531250000000, 0.0065307617187500, +-0.0016784667968750, 0.0056152343750000, -0.0026245117187500, 0.0073242187500000, +-0.0024719238281250, 0.0076599121093750, -0.0021362304687500, 0.0074157714843750, +-0.0026550292968750, 0.0082092285156250, -0.0026855468750000, 0.0080566406250000, +-0.0013732910156250, 0.0063781738281250, -0.0018005371093750, 0.0071716308593750, +-0.0011291503906250, 0.0061950683593750, 0.0001831054687500, 0.0041809082031250, +-0.0005187988281250, 0.0054321289062500, 0.0006713867187500, 0.0034484863281250, +0.0014648437500000, 0.0030212402343750, -0.0005798339843750, 0.0031738281250000, +-0.0014648437500000, 0.0028686523437500, -0.0000305175781250, 0.0032348632812500, +-0.0049743652343750, 0.0017700195312500, -0.0049743652343750, 0.0020751953125000, +-0.0047302246093750, 0.0015563964843750, -0.0073852539062500, 0.0003356933593750, +-0.0069580078125000, 0.0010681152343750, -0.0052185058593750, -0.0002136230468750, +-0.0061950683593750, -0.0004272460937500, -0.0051574707031250, 0.0004272460937500, +-0.0025939941406250, 0.0007629394531250, -0.0033264160156250, 0.0008239746093750, +-0.0029296875000000, 0.0021972656250000, -0.0025939941406250, 0.0022583007812500, +-0.0024108886718750, 0.0019836425781250, -0.0025634765625000, 0.0023803710937500, +-0.0027160644531250, 0.0024414062500000, -0.0011901855468750, 0.0022583007812500, +-0.0013427734375000, 0.0028381347656250, -0.0014953613281250, 0.0013732910156250, +-0.0007934570312500, 0.0003662109375000, -0.0007324218750000, 0.0016174316406250, +-0.0006713867187500, -0.0031433105468750, -0.0010070800781250, -0.0028381347656250, +-0.0003356933593750, -0.0027465820312500, 0.0000915527343750, -0.0057678222656250, +-0.0005187988281250, -0.0054321289062500, 0.0020141601562500, -0.0031127929687500, +0.0018005371093750, -0.0040588378906250, 0.0016479492187500, -0.0030822753906250, +0.0028991699218750, -0.0006103515625000, 0.0027465820312500, -0.0018310546875000, +0.0032958984375000, -0.0011291503906250, 0.0027160644531250, -0.0003662109375000, +0.0036010742187500, -0.0009460449218750, 0.0046081542968750, -0.0017700195312500, +0.0036926269531250, -0.0013122558593750, 0.0063476562500000, 0.0000915527343750, +0.0061340332031250, -0.0008239746093750, 0.0062561035156250, 0.0006408691406250, +0.0078735351562500, 0.0031433105468750, 0.0073242187500000, 0.0019531250000000, +0.0076599121093750, 0.0034790039062500, 0.0077514648437500, 0.0046081542968750, +0.0076904296875000, 0.0035095214843750, 0.0078735351562500, 0.0029296875000000, +0.0078735351562500, 0.0037536621093750, 0.0072937011718750, 0.0009155273437500, +0.0083923339843750, 0.0017395019531250, 0.0063781738281250, 0.0005493164062500, +0.0044860839843750, -0.0021667480468750, 0.0064086914062500, -0.0005798339843750, +0.0009765625000000, -0.0026550292968750, 0.0021972656250000, -0.0030822753906250, +0.0007324218750000, -0.0030517578125000, -0.0038757324218750, -0.0035705566406250, +-0.0013122558593750, -0.0032653808593750, -0.0030212402343750, -0.0049438476562500, +-0.0044250488281250, -0.0041198730468750, -0.0027770996093750, -0.0053100585937500, +-0.0020141601562500, -0.0074157714843750, -0.0032043457031250, -0.0060729980468750, +0.0006103515625000, -0.0089111328125000, -0.0002136230468750, -0.0089416503906250, +0.0001831054687500, -0.0085449218750000, 0.0028381347656250, -0.0094909667968750, +0.0015563964843750, -0.0088806152343750, 0.0032348632812500, -0.0079650878906250, +0.0033874511718750, -0.0078430175781250, 0.0028381347656250, -0.0069580078125000, +0.0033874511718750, -0.0057983398437500, 0.0035095214843750, -0.0058288574218750, +0.0026855468750000, -0.0047607421875000, 0.0029602050781250, -0.0044860839843750, +0.0025024414062500, -0.0040283203125000, 0.0017395019531250, -0.0033264160156250, +0.0024108886718750, -0.0033874511718750, 0.0014343261718750, -0.0028381347656250, +0.0013122558593750, -0.0030517578125000, 0.0014038085937500, -0.0028991699218750, +0.0013122558593750, -0.0025939941406250, 0.0014648437500000, -0.0032043457031250, +-0.0000305175781250, -0.0026245117187500, 0.0006713867187500, -0.0031433105468750, +0.0000915527343750, -0.0032043457031250, -0.0015869140625000, -0.0028076171875000, +-0.0007324218750000, -0.0036315917968750, -0.0016784667968750, -0.0034179687500000, +-0.0018005371093750, -0.0030517578125000, -0.0019531250000000, -0.0030822753906250, +-0.0024719238281250}, +{-0.0048217773437500, 0.0021972656250000, -0.0065917968750000, 0.0044860839843750, +-0.0064697265625000, 0.0040588378906250, -0.0044250488281250, 0.0024108886718750, +-0.0053710937500000, 0.0032043457031250, -0.0051879882812500, 0.0025024414062500, +-0.0034179687500000, 0.0011596679687500, -0.0039672851562500, 0.0020141601562500, +-0.0026245117187500, -0.0018005371093750, -0.0029907226562500, -0.0011901855468750, +-0.0021057128906250, -0.0018920898437500, -0.0006103515625000, -0.0050659179687500, +-0.0015869140625000, -0.0038757324218750, -0.0001220703125000, -0.0031738281250000, +0.0004272460937500, -0.0046386718750000, -0.0001525878906250, -0.0029602050781250, +-0.0000610351562500, -0.0002441406250000, 0.0003356933593750, -0.0015258789062500, +-0.0004882812500000, -0.0001831054687500, -0.0009155273437500, 0.0007934570312500, +-0.0001220703125000, -0.0002136230468750, 0.0001525878906250, -0.0008850097656250, +-0.0004577636718750, -0.0001831054687500, 0.0013122558593750, -0.0010375976562500, +0.0011291503906250, -0.0017700195312500, 0.0011596679687500, -0.0001525878906250, +0.0021057128906250, 0.0009765625000000, 0.0018310546875000, -0.0000305175781250, +0.0029602050781250, 0.0028991699218750, 0.0021362304687500, 0.0035705566406250, +0.0035095214843750, 0.0024719238281250, 0.0052490234375000, 0.0031433105468750, +0.0036621093750000, 0.0038757324218750, 0.0066528320312500, 0.0010375976562500, +0.0065917968750000, 0.0014038085937500, 0.0064086914062500, 0.0010070800781250, +0.0079040527343750, -0.0005798339843750, 0.0073852539062500, 0.0003051757812500, +0.0074462890625000, -0.0013122558593750, 0.0075988769531250, -0.0012512207031250, +0.0073547363281250, -0.0012512207031250, 0.0074462890625000, -0.0020446777343750, +0.0075683593750000, -0.0018005371093750, 0.0059204101562500, -0.0032653808593750, +0.0068054199218750, -0.0027160644531250, 0.0050354003906250, -0.0036621093750000, +0.0032043457031250, -0.0054931640625000, 0.0052185058593750, -0.0044250488281250, +-0.0008850097656250, -0.0056762695312500, -0.0001220703125000, -0.0061035156250000, +-0.0002441406250000, -0.0049438476562500, -0.0040283203125000, -0.0045471191406250, +-0.0025634765625000, -0.0047302246093750, -0.0029907226562500, -0.0024108886718750, +-0.0040283203125000, -0.0018615722656250, -0.0023803710937500, -0.0009765625000000, +-0.0010681152343750, 0.0006408691406250, -0.0023803710937500, 0.0005493164062500, +0.0007324218750000, 0.0012512207031250, 0.0004272460937500, 0.0014648437500000, +0.0010070800781250, 0.0015258789062500, 0.0029602050781250, 0.0015258789062500, +0.0017700195312500, 0.0012512207031250, 0.0036010742187500, 0.0020446777343750, +0.0036010742187500, 0.0011901855468750, 0.0036621093750000, 0.0017395019531250, +0.0047302246093750, 0.0025329589843750, 0.0042114257812500, 0.0010681152343750, +0.0039062500000000, 0.0033264160156250, 0.0045166015625000, 0.0024414062500000, +0.0038757324218750, 0.0027160644531250, 0.0028076171875000, 0.0044250488281250, +0.0033264160156250, 0.0031127929687500, 0.0024414062500000, 0.0050048828125000, +0.0027770996093750, 0.0046081542968750, 0.0017700195312500, 0.0047912597656250, +0.0007629394531250, 0.0059814453125000, 0.0018615722656250, 0.0050354003906250, +-0.0011291503906250, 0.0060729980468750, -0.0008850097656250, 0.0063476562500000, +-0.0011901855468750, 0.0061950683593750, -0.0029907226562500, 0.0065002441406250, +-0.0022888183593750, 0.0065307617187500, -0.0032958984375000, 0.0066833496093750, +-0.0033264160156250, 0.0064086914062500, -0.0033264160156250, 0.0064392089843750, +-0.0038452148437500, 0.0065917968750000, -0.0036315917968750, 0.0062866210937500, +-0.0035400390625000, 0.0064086914062500, -0.0038146972656250, 0.0060729980468750, +-0.0034790039062500, 0.0061340332031250, -0.0030517578125000, 0.0061340332031250, +-0.0032958984375000, 0.0054931640625000, -0.0027160644531250, 0.0062866210937500, +-0.0025634765625000, 0.0057067871093750, -0.0027160644531250, 0.0057373046875000, +-0.0025634765625000, 0.0063171386718750, -0.0024719238281250, 0.0054931640625000, +-0.0027160644531250, 0.0063781738281250, -0.0027160644531250, 0.0057983398437500, +-0.0025024414062500, 0.0057983398437500, -0.0025024414062500, 0.0063476562500000, +-0.0024719238281250, 0.0054321289062500, -0.0019226074218750, 0.0060424804687500, +-0.0019531250000000, 0.0058288574218750, -0.0016784667968750, 0.0053100585937500, +-0.0012512207031250, 0.0054626464843750, -0.0014038085937500, 0.0052490234375000, +-0.0006103515625000, 0.0039062500000000, -0.0007324218750000, 0.0043029785156250, +-0.0001525878906250, 0.0035095214843750, 0.0007019042968750, 0.0022888183593750, +0.0002441406250000, 0.0030517578125000, 0.0017700195312500, 0.0010986328125000, +0.0017700195312500, 0.0012512207031250, 0.0019531250000000, 0.0007934570312500, +0.0028991699218750, -0.0005187988281250, 0.0026550292968750, 0.0001525878906250, +0.0030212402343750, -0.0010375976562500, 0.0032653808593750, -0.0013427734375000, +0.0029296875000000, -0.0008544921875000, 0.0029296875000000, -0.0009765625000000, +0.0032348632812500, -0.0010681152343750, 0.0016479492187500, 0.0003662109375000, +0.0021667480468750, 0.0002746582031250, 0.0015258789062500, 0.0007324218750000, +0.0001525878906250, 0.0020141601562500, 0.0009155273437500, 0.0016784667968750, +-0.0007324218750000, 0.0020751953125000, -0.0006713867187500, 0.0027770996093750, +-0.0009155273437500, 0.0018920898437500, -0.0021362304687500, 0.0014648437500000, +-0.0016784667968750, 0.0023193359375000, -0.0014648437500000, -0.0008850097656250, +-0.0023193359375000, -0.0003662109375000, -0.0010681152343750, -0.0009765625000000, +0.0001831054687500, -0.0033874511718750, -0.0009460449218750, -0.0027465820312500, +0.0021972656250000, -0.0042114257812500, 0.0020751953125000, -0.0043029785156250, +0.0025329589843750, -0.0040283203125000, 0.0045471191406250, -0.0048522949218750, +0.0039367675781250, -0.0043029785156250, 0.0047302246093750, -0.0015258789062500, +0.0049743652343750, -0.0034179687500000, 0.0054321289062500, -0.0001220703125000, +0.0056762695312500, 0.0045471191406250, 0.0051269531250000, 0.0017700195312500, +0.0075988769531250, 0.0083923339843750, 0.0073547363281250, 0.0089111328125000, +0.0076904296875000, 0.0089111328125000, 0.0091552734375000, 0.0119934082031250, +0.0084838867187500, 0.0111694335937500, 0.0096130371093750, 0.0118103027343750, +0.0097351074218750, 0.0123596191406250, 0.0095825195312500, 0.0111083984375000, +0.0100097656250000, 0.0106201171875000, 0.0097656250000000, 0.0112915039062500, +0.0093383789062500, 0.0074462890625000, 0.0100097656250000, 0.0082702636718750, +0.0088500976562500, 0.0061950683593750, 0.0077209472656250, 0.0024414062500000, +0.0086364746093750, 0.0044250488281250, 0.0046997070312500, 0.0007324218750000, +0.0053710937500000, 0.0004882812500000, 0.0050354003906250, 0.0004577636718750, +0.0018920898437500, -0.0013122558593750, 0.0025939941406250, -0.0004882812500000, +0.0032958984375000, -0.0004577636718750, 0.0024108886718750, -0.0012207031250000, +0.0034484863281250, -0.0005493164062500, 0.0051269531250000, 0.0000305175781250, +0.0038757324218750, -0.0005187988281250, 0.0041809082031250, 0.0024719238281250, +0.0056762695312500, 0.0021667480468750, 0.0026245117187500, 0.0015563964843750, +0.0000305175781250, 0.0034790039062500, 0.0024108886718750, 0.0036926269531250, +-0.0036926269531250, -0.0002441406250000, -0.0045471191406250, 0.0009460449218750, +-0.0029602050781250, 0.0003967285156250, -0.0046691894531250, -0.0045776367187500, +-0.0003356933593750, 0.0034484863281250, -0.0005187988281250, -0.0023193359375000, +-0.0004272460937500, -0.0003662109375000, -0.0003662109375000, -0.0005798339843750, +-0.0005493164062500, -0.0036315917968750, -0.0007934570312500, -0.0034790039062500, +-0.0003051757812500, -0.0005187988281250, 0.0003051757812500, -0.0011596679687500, +-0.0008239746093750, -0.0010375976562500, -0.0011596679687500, 0.0010681152343750, +-0.0003967285156250, 0.0005187988281250, -0.0052795410156250, -0.0003662109375000, +-0.0045471191406250, 0.0000000000000000, -0.0043029785156250, 0.0000915527343750, +-0.0079956054687500, -0.0009460449218750, -0.0076904296875000, -0.0008850097656250, +-0.0034790039062500, 0.0015258789062500, -0.0059204101562500, 0.0009155273437500, +-0.0023498535156250, 0.0013427734375000, 0.0034790039062500, 0.0033569335937500, +-0.0003051757812500, 0.0027770996093750, 0.0063171386718750, 0.0029296875000000, +0.0075073242187500, 0.0030212402343750, 0.0066223144531250, 0.0032348632812500, +0.0084533691406250, 0.0031738281250000, 0.0083007812500000, 0.0028686523437500, +0.0088500976562500, 0.0044250488281250, 0.0085449218750000, 0.0039978027343750, +0.0087585449218750, 0.0046386718750000, 0.0095825195312500, 0.0061645507812500, +0.0092468261718750, 0.0053405761718750, 0.0090637207031250, 0.0055541992187500, +0.0096130371093750, 0.0063781738281250, 0.0081176757812500, 0.0052185058593750, +0.0073242187500000, 0.0039062500000000, 0.0084228515625000, 0.0046691894531250, +0.0022583007812500, 0.0040893554687500, 0.0038452148437500, 0.0035095214843750, +0.0016174316406250, 0.0040283203125000, -0.0038757324218750, 0.0046691894531250, +-0.0010681152343750, 0.0043945312500000, -0.0057678222656250, 0.0040588378906250, +-0.0066833496093750, 0.0043945312500000, -0.0049743652343750, 0.0040283203125000, +-0.0065307617187500, 0.0032348632812500, -0.0072631835937500, 0.0036010742187500, +-0.0014038085937500, 0.0037231445312500, -0.0034790039062500, 0.0033874511718750, +-0.0015869140625000, 0.0036621093750000, 0.0039978027343750, 0.0043334960937500, +0.0011291503906250, 0.0040893554687500, 0.0039367675781250, 0.0032653808593750, +0.0051879882812500, 0.0038757324218750, 0.0035095214843750, 0.0031433105468750, +0.0034179687500000, 0.0017395019531250, 0.0043029785156250, 0.0023803710937500, +0.0003967285156250, 0.0016174316406250, 0.0012817382812500, 0.0012512207031250, +-0.0001525878906250, 0.0013427734375000, -0.0033874511718750, 0.0012512207031250, +-0.0015869140625000, 0.0013122558593750, -0.0045166015625000, 0.0012207031250000, +-0.0053100585937500, 0.0010375976562500, -0.0043334960937500, 0.0014953613281250, +-0.0050048828125000, 0.0018005371093750, -0.0054626464843750, 0.0015563964843750, +-0.0031127929687500, 0.0025329589843750, -0.0039672851562500, 0.0026855468750000, +-0.0030517578125000, 0.0025329589843750, -0.0008850097656250, 0.0028381347656250, +-0.0023498535156250, 0.0029296875000000, 0.0001220703125000, 0.0025939941406250, +0.0000610351562500, 0.0026855468750000, -0.0001220703125000, 0.0025024414062500, +0.0011596679687500, 0.0023498535156250, 0.0007324218750000, 0.0024719238281250, +0.0007019042968750, 0.0013427734375000, 0.0011901855468750, 0.0016784667968750, +0.0006103515625000, 0.0010375976562500, 0.0001220703125000, -0.0003662109375000, +0.0006713867187500, 0.0002441406250000, -0.0009765625000000, -0.0006713867187500, +-0.0004882812500000, -0.0010375976562500, -0.0006408691406250, -0.0008239746093750, +-0.0018005371093750, -0.0008850097656250, -0.0011291503906250, -0.0010375976562500, +-0.0019226074218750, -0.0010375976562500, -0.0016784667968750, -0.0009460449218750, +-0.0015258789062500, -0.0012207031250000, -0.0017700195312500, -0.0015563964843750, +-0.0013427734375000, -0.0013732910156250, -0.0016784667968750, -0.0019226074218750, +-0.0013427734375000, -0.0019531250000000, -0.0014343261718750, -0.0019836425781250, +-0.0017700195312500, -0.0022583007812500, -0.0011596679687500, -0.0021667480468750, +-0.0018615722656250}, +{0.0006408691406250, -0.0003967285156250, 0.0072021484375000, -0.0003051757812500, +0.0071411132812500, -0.0001220703125000, 0.0074768066406250, 0.0002441406250000, +0.0110778808593750, 0.0003356933593750, 0.0101013183593750, 0.0000000000000000, +0.0119018554687500, 0.0015869140625000, 0.0118103027343750, 0.0013732910156250, +0.0119323730468750, 0.0016479492187500, 0.0137023925781250, 0.0027770996093750, +0.0130920410156250, 0.0022888183593750, 0.0105590820312500, 0.0024719238281250, +0.0126037597656250, 0.0025939941406250, 0.0090332031250000, 0.0025634765625000, +0.0045166015625000, 0.0022583007812500, 0.0076599121093750, 0.0022583007812500, +-0.0006103515625000, 0.0039367675781250, -0.0002441406250000, 0.0033264160156250, +-0.0007629394531250, 0.0038146972656250, -0.0060424804687500, 0.0056457519531250, +-0.0042419433593750, 0.0048828125000000, -0.0036926269531250, 0.0039978027343750, +-0.0056762695312500, 0.0046386718750000, -0.0034179687500000, 0.0041503906250000, +-0.0009460449218750, 0.0027160644531250, -0.0030212402343750, 0.0030517578125000, +0.0020141601562500, 0.0033874511718750, 0.0016174316406250, 0.0031433105468750, +0.0016174316406250, 0.0032348632812500, 0.0048522949218750, 0.0038146972656250, +0.0037841796875000, 0.0037536621093750, 0.0023803710937500, 0.0030517578125000, +0.0039672851562500, 0.0032348632812500, 0.0018310546875000, 0.0032653808593750, +-0.0011901855468750, 0.0026550292968750, 0.0008239746093750, 0.0026855468750000, +-0.0025634765625000, 0.0039672851562500, -0.0030212402343750, 0.0036315917968750, +-0.0024108886718750, 0.0035705566406250, -0.0037231445312500, 0.0046691894531250, +-0.0037231445312500, 0.0046081542968750, -0.0024108886718750, 0.0030517578125000, +-0.0030822753906250, 0.0035705566406250, -0.0018615722656250, 0.0029296875000000, +-0.0001525878906250, 0.0013427734375000, -0.0016174316406250, 0.0019531250000000, +0.0010681152343750, 0.0011291503906250, 0.0013427734375000, 0.0008850097656250, +0.0002136230468750, 0.0010375976562500, 0.0010070800781250, 0.0007629394531250, +0.0013427734375000, 0.0007934570312500, -0.0018005371093750, 0.0012512207031250, +-0.0006103515625000, 0.0010070800781250, -0.0023498535156250, 0.0013427734375000, +-0.0054016113281250, 0.0019836425781250, -0.0031433105468750, 0.0016784667968750, +-0.0077209472656250, 0.0020141601562500, -0.0073547363281250, 0.0022583007812500, +-0.0077209472656250, 0.0019531250000000, -0.0104675292968750, 0.0016479492187500, +-0.0089721679687500, 0.0018310546875000, -0.0104064941406250, 0.0016784667968750, +-0.0108337402343750, 0.0014648437500000, -0.0099487304687500, 0.0016784667968750, +-0.0100708007812500, 0.0019836425781250, -0.0103759765625000, 0.0017700195312500, +-0.0081481933593750, 0.0016784667968750, -0.0090637207031250, 0.0018920898437500, +-0.0079040527343750, 0.0014953613281250, -0.0057678222656250, 0.0009765625000000, +-0.0072631835937500, 0.0012512207031250, -0.0041809082031250, 0.0003662109375000, +-0.0045776367187500, 0.0005187988281250, -0.0039978027343750, 0.0000610351562500, +-0.0020446777343750, -0.0006713867187500, -0.0033874511718750, -0.0002441406250000, +-0.0011901855468750, -0.0015258789062500, -0.0016784667968750, -0.0016174316406250, +-0.0014648437500000, -0.0016174316406250, -0.0001220703125000, -0.0022583007812500, +-0.0012207031250000, -0.0021667480468750, -0.0000305175781250, -0.0017089843750000, +-0.0003051757812500, -0.0020141601562500, -0.0005187988281250, -0.0016174316406250, +0.0000305175781250, -0.0010375976562500, -0.0005493164062500, -0.0014038085937500, +-0.0004882812500000, -0.0008239746093750, -0.0008239746093750, -0.0007019042968750, +-0.0009460449218750, -0.0007934570312500, -0.0009460449218750, -0.0005798339843750, +-0.0014648437500000, -0.0005798339843750, -0.0013427734375000, -0.0005798339843750, +-0.0014038085937500, -0.0007324218750000, -0.0017395019531250, -0.0002136230468750, +-0.0018005371093750, -0.0000610351562500, -0.0018920898437500, -0.0004882812500000, +-0.0027160644531250, 0.0017700195312500, -0.0024719238281250, 0.0012512207031250, +-0.0028686523437500, 0.0017395019531250, -0.0036926269531250, 0.0036010742187500, +-0.0032043457031250, 0.0028076171875000, -0.0038146972656250, 0.0035705566406250, +-0.0039978027343750, 0.0039367675781250, -0.0035400390625000, 0.0034179687500000, +-0.0034179687500000, 0.0035705566406250, -0.0033569335937500, 0.0038757324218750, +-0.0021362304687500, 0.0018615722656250, -0.0022277832031250, 0.0024108886718750, +-0.0015869140625000, 0.0021972656250000, -0.0004272460937500, 0.0005493164062500, +-0.0006713867187500, 0.0010681152343750, 0.0006103515625000, 0.0011901855468750, +0.0007019042968750, 0.0007934570312500, 0.0007629394531250, 0.0011901855468750, +0.0014343261718750, 0.0016784667968750, 0.0013427734375000, 0.0013732910156250, +0.0014343261718750, 0.0021667480468750, 0.0014343261718750, 0.0020446777343750, +0.0016174316406250, 0.0022583007812500, 0.0016784667968750, 0.0028991699218750, +0.0015258789062500, 0.0026245117187500, 0.0030212402343750, 0.0031738281250000, +0.0021667480468750, 0.0030212402343750, 0.0036010742187500, 0.0036010742187500, +0.0056457519531250, 0.0042114257812500, 0.0041503906250000, 0.0036010742187500, +0.0074768066406250, 0.0046997070312500, 0.0075378417968750, 0.0048828125000000, +0.0075683593750000, 0.0044555664062500, 0.0094604492187500, 0.0047912597656250, +0.0089111328125000, 0.0048828125000000, 0.0079345703125000, 0.0027465820312500, +0.0090637207031250, 0.0033569335937500, 0.0075378417968750, 0.0027465820312500, +0.0053405761718750, 0.0007629394531250, 0.0066528320312500, 0.0016174316406250, +0.0036315917968750, 0.0008544921875000, 0.0036621093750000, 0.0001831054687500, +0.0034179687500000, 0.0010986328125000, 0.0016479492187500, 0.0016784667968750, +0.0023193359375000, 0.0010070800781250, 0.0021057128906250, 0.0020446777343750, +0.0018310546875000, 0.0022277832031250, 0.0016174316406250, 0.0015563964843750, +0.0016784667968750, 0.0016479492187500, 0.0018615722656250, 0.0019836425781250, +-0.0002441406250000, 0.0006713867187500, 0.0002441406250000, 0.0006713867187500, +-0.0007629394531250, 0.0008239746093750, -0.0031127929687500, -0.0000610351562500, +-0.0021362304687500, 0.0000305175781250, -0.0024719238281250, 0.0021362304687500, +-0.0037231445312500, 0.0014648437500000, -0.0021667480468750, 0.0014343261718750, +-0.0005798339843750, 0.0030517578125000, -0.0018005371093750, 0.0027465820312500, +0.0011291503906250, 0.0024719238281250, 0.0015869140625000, 0.0027770996093750, +0.0003356933593750, 0.0020446777343750, 0.0008544921875000, 0.0016479492187500, +0.0015258789062500, 0.0021057128906250, -0.0014953613281250, -0.0014953613281250, +-0.0013122558593750, -0.0007324218750000, -0.0013122558593750, -0.0009155273437500, +-0.0030517578125000, -0.0037841796875000, -0.0028381347656250, -0.0034484863281250, +-0.0023498535156250, -0.0028381347656250, -0.0022277832031250, -0.0035095214843750, +-0.0028991699218750, -0.0023498535156250, -0.0030212402343750, -0.0012512207031250, +-0.0023803710937500, -0.0023498535156250, -0.0042114257812500, 0.0012207031250000, +-0.0043029785156250, 0.0012207031250000, -0.0042419433593750, 0.0011291503906250, +-0.0050964355468750, 0.0032653808593750, -0.0047912597656250, 0.0029602050781250, +-0.0046386718750000, 0.0017700195312500, -0.0051574707031250, 0.0022583007812500, +-0.0044250488281250, 0.0021972656250000, -0.0038146972656250, 0.0014038085937500, +-0.0044860839843750, 0.0017395019531250, -0.0018615722656250, 0.0015869140625000, +-0.0025024414062500, 0.0016174316406250, -0.0015563964843750, 0.0017089843750000, +0.0008544921875000, 0.0016174316406250, -0.0004272460937500, 0.0017700195312500, +0.0012817382812500, 0.0021057128906250, 0.0018005371093750, 0.0019836425781250, +0.0011291503906250, 0.0021667480468750, 0.0011596679687500, 0.0027770996093750, +0.0014038085937500, 0.0026855468750000, 0.0008850097656250, 0.0015258789062500, +0.0006408691406250, 0.0022888183593750, 0.0008850097656250, 0.0014038085937500, +0.0010070800781250, -0.0000305175781250, 0.0008850097656250, 0.0009765625000000, +0.0009460449218750, -0.0014038085937500, 0.0007019042968750, -0.0017395019531250, +0.0010986328125000, -0.0009460449218750, 0.0012207031250000, -0.0016784667968750, +0.0006408691406250, -0.0019836425781250, 0.0025939941406250, 0.0004272460937500, +0.0017089843750000, -0.0002136230468750, 0.0026245117187500, 0.0010375976562500, +0.0046691894531250, 0.0036010742187500, 0.0033874511718750, 0.0024108886718750, +0.0055847167968750, 0.0043640136718750, 0.0056762695312500, 0.0053710937500000, +0.0050048828125000, 0.0044555664062500, 0.0057983398437500, 0.0043334960937500, +0.0059814453125000, 0.0051269531250000, 0.0053405761718750, 0.0032348632812500, +0.0053710937500000, 0.0027160644531250, 0.0048217773437500, 0.0033264160156250, +0.0045776367187500, 0.0025634765625000, 0.0052185058593750, 0.0017700195312500, +0.0028991699218750, 0.0041809082031250, 0.0033569335937500, 0.0028991699218750, +0.0028686523437500, 0.0034179687500000, 0.0012817382812500, 0.0055236816406250, +0.0022583007812500, 0.0038146972656250, 0.0004577636718750, 0.0051269531250000, +0.0004272460937500, 0.0050964355468750, 0.0007629394531250, 0.0040893554687500, +0.0001220703125000, 0.0041198730468750, 0.0003356933593750, 0.0038757324218750, +0.0008239746093750, 0.0021972656250000, 0.0005798339843750, 0.0022888183593750, +0.0008239746093750, 0.0013732910156250, 0.0012817382812500, -0.0002136230468750, +0.0010070800781250, 0.0003662109375000, 0.0015258789062500, -0.0012817382812500, +0.0010986328125000, -0.0014953613281250, 0.0017700195312500, -0.0014648437500000, +0.0025939941406250, -0.0022583007812500, 0.0016479492187500, -0.0020751953125000, +0.0030517578125000, -0.0017700195312500, 0.0032653808593750, -0.0019226074218750, +0.0028076171875000, -0.0014343261718750, 0.0030822753906250, -0.0006713867187500, +0.0030822753906250, -0.0007629394531250, 0.0023803710937500, 0.0000000000000000, +0.0027160644531250, 0.0002746582031250, 0.0021362304687500, 0.0004272460937500, +0.0014038085937500, 0.0008850097656250, 0.0020141601562500, 0.0009460449218750, +0.0003662109375000, 0.0009155273437500, 0.0006103515625000, 0.0013122558593750, +0.0001831054687500, 0.0014038085937500, -0.0010070800781250, 0.0012512207031250, +-0.0003356933593750, 0.0014953613281250, -0.0019836425781250, 0.0014953613281250, +-0.0018310546875000, 0.0018615722656250, -0.0018005371093750, 0.0018005371093750, +-0.0028076171875000, 0.0017089843750000, -0.0024414062500000, 0.0022888183593750, +-0.0019836425781250, 0.0018310546875000, -0.0024108886718750, 0.0020751953125000, +-0.0017089843750000, 0.0020446777343750, -0.0008850097656250, 0.0017700195312500, +-0.0013732910156250, 0.0021667480468750, -0.0001220703125000, 0.0014343261718750, +-0.0001525878906250, 0.0018005371093750, 0.0001525878906250, 0.0017700195312500, +0.0009765625000000, 0.0012817382812500, 0.0005798339843750, 0.0018005371093750, +0.0015869140625000, 0.0011596679687500, 0.0016479492187500, 0.0015869140625000, +0.0017395019531250, 0.0010070800781250, 0.0023803710937500, 0.0003662109375000, +0.0021667480468750, 0.0012207031250000, 0.0023498535156250, -0.0010375976562500, +0.0024108886718750, -0.0003662109375000, 0.0023498535156250, -0.0011901855468750, +0.0024108886718750, -0.0032348632812500, 0.0023498535156250, -0.0020751953125000, +0.0018615722656250, -0.0045776367187500, 0.0020446777343750, -0.0043029785156250, +0.0016174316406250}, +{0.0007324218750000, 0.0008544921875000, 0.0006713867187500, 0.0019836425781250, +0.0001831054687500, 0.0051269531250000, 0.0002441406250000, 0.0037841796875000, +0.0004272460937500, 0.0055236816406250, 0.0001525878906250, 0.0063171386718750, +0.0006713867187500, 0.0051879882812500, 0.0009155273437500, 0.0049133300781250, +0.0002746582031250, 0.0054321289062500, 0.0020751953125000, 0.0030517578125000, +0.0013427734375000, 0.0026550292968750, 0.0023498535156250, 0.0030212402343750, +0.0043334960937500, 0.0018005371093750, 0.0028991699218750, 0.0010681152343750, +0.0046997070312500, 0.0030212402343750, 0.0050659179687500, 0.0019226074218750, +0.0050048828125000, 0.0019836425781250, 0.0056152343750000, 0.0036010742187500, +0.0052490234375000, 0.0023803710937500, 0.0047912597656250, 0.0023498535156250, +0.0055236816406250, 0.0023193359375000, 0.0048522949218750, 0.0013122558593750, +0.0036621093750000, 0.0005493164062500, 0.0042419433593750, 0.0006103515625000, +0.0030822753906250, -0.0000305175781250, 0.0032348632812500, -0.0005493164062500, +0.0028076171875000, -0.0002746582031250, 0.0019226074218750, -0.0001831054687500, +0.0025024414062500, -0.0006408691406250, 0.0012207031250000, 0.0006408691406250, +0.0014343261718750, 0.0003662109375000, 0.0013427734375000, 0.0010986328125000, +0.0005187988281250, 0.0023498535156250, 0.0010375976562500, 0.0018920898437500, +0.0005187988281250, 0.0038146972656250, 0.0005493164062500, 0.0038452148437500, +0.0007324218750000, 0.0042724609375000, 0.0003967285156250, 0.0055236816406250, +0.0004577636718750, 0.0050354003906250, 0.0014038085937500, 0.0057067871093750, +0.0007934570312500, 0.0059204101562500, 0.0014343261718750, 0.0054931640625000, +0.0025939941406250, 0.0056152343750000, 0.0017700195312500, 0.0057373046875000, +0.0028076171875000, 0.0047607421875000, 0.0029907226562500, 0.0048522949218750, +0.0025329589843750, 0.0044555664062500, 0.0029296875000000, 0.0036315917968750, +0.0029296875000000, 0.0038452148437500, 0.0016784667968750, 0.0027160644531250, +0.0020751953125000, 0.0030212402343750, 0.0015563964843750, 0.0024108886718750, +0.0002746582031250, 0.0014648437500000, 0.0008850097656250, 0.0021972656250000, +0.0000000000000000, 0.0004882812500000, -0.0000915527343750, 0.0006713867187500, +-0.0001525878906250, 0.0003051757812500, -0.0004577636718750, -0.0007934570312500, +-0.0001831054687500, -0.0001220703125000, -0.0008850097656250, -0.0013427734375000, +-0.0007324218750000, -0.0012207031250000, -0.0007019042968750, -0.0013122558593750, +-0.0012512207031250, -0.0020751953125000, -0.0010070800781250, -0.0016174316406250, +-0.0004272460937500, -0.0020141601562500, -0.0008544921875000, -0.0021057128906250, +-0.0001525878906250, -0.0018920898437500, 0.0008239746093750, -0.0019836425781250, +0.0002441406250000, -0.0020751953125000, 0.0017089843750000, -0.0015258789062500, +0.0017395019531250, -0.0018615722656250, 0.0018615722656250, -0.0010986328125000, +0.0028076171875000, -0.0003356933593750, 0.0023803710937500, -0.0010681152343750, +0.0025939941406250, 0.0010986328125000, 0.0028686523437500, 0.0006713867187500, +0.0023803710937500, 0.0010681152343750, 0.0019836425781250, 0.0025634765625000, +0.0023193359375000, 0.0015869140625000, 0.0016174316406250, 0.0027160644531250, +0.0014343261718750, 0.0028076171875000, 0.0017089843750000, 0.0022277832031250, +0.0015258789062500, 0.0025024414062500, 0.0014343261718750, 0.0025329589843750, +0.0022277832031250, 0.0009155273437500, 0.0018920898437500, 0.0016174316406250, +0.0025024414062500, 0.0001220703125000, 0.0033874511718750, -0.0018310546875000, +0.0028381347656250, -0.0003662109375000, 0.0042419433593750, -0.0042114257812500, +0.0042724609375000, -0.0036621093750000, 0.0043029785156250, -0.0038146972656250, +0.0050048828125000, -0.0064392089843750, 0.0047607421875000, -0.0053100585937500, +0.0045776367187500, -0.0050048828125000, 0.0046691894531250, -0.0059204101562500, +0.0048217773437500, -0.0043029785156250, 0.0046386718750000, -0.0025024414062500, +0.0045471191406250, -0.0035400390625000, 0.0056762695312500, -0.0004882812500000, +0.0054931640625000, -0.0000915527343750, 0.0057678222656250, -0.0001525878906250, +0.0067443847656250, 0.0014343261718750, 0.0064086914062500, 0.0015258789062500, +0.0063476562500000, 0.0006408691406250, 0.0068054199218750, 0.0015869140625000, +0.0061950683593750, 0.0006408691406250, 0.0056152343750000, -0.0011291503906250, +0.0061340332031250, -0.0000305175781250, 0.0044860839843750, -0.0013732910156250, +0.0047302246093750, -0.0028686523437500, 0.0041809082031250, -0.0007324218750000, +0.0028991699218750, 0.0006103515625000, 0.0034179687500000, -0.0012207031250000, +0.0015869140625000, 0.0042419433593750, 0.0016784667968750, 0.0045166015625000, +0.0012817382812500, 0.0037841796875000, 0.0000305175781250, 0.0063171386718750, +0.0006103515625000, 0.0062866210937500, 0.0000610351562500, 0.0036315917968750, +-0.0003967285156250, 0.0046081542968750, 0.0003356933593750, 0.0034484863281250, +0.0012207031250000, 0.0010070800781250, 0.0006408691406250, 0.0023803710937500, +-0.0003662109375000, 0.0004272460937500, 0.0007934570312500, -0.0003051757812500, +-0.0004882812500000, 0.0017089843750000, -0.0027770996093750, 0.0018310546875000, +-0.0014648437500000, 0.0007629394531250, -0.0032348632812500, 0.0074157714843750, +-0.0043334960937500, 0.0056457519531250, -0.0023498535156250, 0.0084838867187500, +-0.0013732910156250, 0.0152893066406250, -0.0029296875000000, 0.0119628906250000, +0.0001525878906250, 0.0147399902343750, 0.0006408691406250, 0.0174560546875000, +-0.0002746582031250, 0.0133666992187500, 0.0002136230468750, 0.0106506347656250, +0.0003967285156250, 0.0133972167968750, -0.0005187988281250, 0.0060424804687500, +-0.0007019042968750, 0.0054016113281250, -0.0010375976562500, 0.0060119628906250, +-0.0014953613281250, 0.0033264160156250, -0.0011596679687500, 0.0037841796875000, +-0.0011291503906250, 0.0030517578125000, -0.0016479492187500, 0.0035095214843750, +-0.0017395019531250, 0.0023498535156250, -0.0013732910156250, -0.0003051757812500, +-0.0024108886718750, 0.0037536621093750, 0.0016784667968750, 0.0042724609375000, +-0.0011901855468750, 0.0055847167968750, 0.0016784667968750, 0.0031738281250000, +0.0058593750000000, 0.0014343261718750, 0.0037231445312500, 0.0033569335937500, +0.0067443847656250, -0.0017089843750000, 0.0071411132812500, -0.0023498535156250, +0.0076293945312500, -0.0004882812500000, 0.0088806152343750, -0.0017089843750000, +0.0079956054687500, -0.0025634765625000, 0.0107421875000000, 0.0013427734375000, +0.0104064941406250, 0.0016784667968750, 0.0106506347656250, 0.0002136230468750, +0.0132751464843750, 0.0012817382812500, 0.0125122070312500, 0.0020751953125000, +0.0091552734375000, -0.0019836425781250, 0.0119323730468750, -0.0019226074218750, +0.0075683593750000, -0.0017089843750000, 0.0016479492187500, -0.0037231445312500, +0.0059509277343750, -0.0034790039062500, -0.0033874511718750, -0.0024414062500000, +-0.0044250488281250, -0.0028991699218750, -0.0022583007812500, -0.0026245117187500, +-0.0056457519531250, -0.0014953613281250, -0.0060119628906250, -0.0017700195312500, +-0.0005798339843750, -0.0020446777343750, -0.0021667480468750, -0.0021057128906250, +-0.0006713867187500, -0.0017089843750000, 0.0041198730468750, -0.0017089843750000, +0.0018310546875000, -0.0021972656250000, 0.0039062500000000, -0.0007019042968750, +0.0051879882812500, -0.0007019042968750, 0.0033264160156250, -0.0011901855468750, +0.0024414062500000, -0.0007324218750000, 0.0036621093750000, -0.0005187988281250, +0.0008544921875000, -0.0013122558593750, 0.0007324218750000, -0.0017395019531250, +0.0011291503906250, -0.0008239746093750, 0.0000000000000000, -0.0004272460937500, +0.0002746582031250, -0.0012207031250000, 0.0013427734375000, 0.0007324218750000, +0.0007629394531250, 0.0007019042968750, 0.0011901855468750, 0.0006103515625000, +0.0026855468750000, 0.0015563964843750, 0.0019836425781250, 0.0012512207031250, +0.0007629394531250, 0.0013732910156250, 0.0023193359375000, 0.0014038085937500, +0.0001220703125000, 0.0015563964843750, -0.0025939941406250, 0.0017395019531250, +-0.0003662109375000, 0.0014648437500000, -0.0049743652343750, 0.0022888183593750, +-0.0048217773437500, 0.0024108886718750, -0.0050964355468750, 0.0021667480468750, +-0.0077209472656250, 0.0022583007812500, -0.0065307617187500, 0.0024414062500000, +-0.0075988769531250, 0.0021362304687500, -0.0079650878906250, 0.0018310546875000, +-0.0071105957031250, 0.0023193359375000, -0.0071411132812500, 0.0027160644531250, +-0.0074157714843750, 0.0022888183593750, -0.0045166015625000, 0.0030212402343750, +-0.0051574707031250, 0.0032653808593750, -0.0040893554687500, 0.0028381347656250, +-0.0014038085937500, 0.0028076171875000, -0.0025634765625000, 0.0029296875000000, +-0.0007629394531250, 0.0022583007812500, -0.0001831054687500, 0.0022277832031250, +-0.0005798339843750, 0.0021057128906250, 0.0000610351562500, 0.0017089843750000, +0.0003967285156250, 0.0018310546875000, -0.0007934570312500, 0.0015869140625000, +-0.0000915527343750, 0.0015563964843750, -0.0006103515625000, 0.0016174316406250, +-0.0017700195312500, 0.0015258789062500, -0.0006713867187500, 0.0015563964843750, +-0.0023498535156250, 0.0017089843750000, -0.0020751953125000, 0.0017700195312500, +-0.0022277832031250, 0.0016784667968750, -0.0032348632812500, 0.0017395019531250, +-0.0024414062500000, 0.0019226074218750, -0.0036010742187500, 0.0011901855468750, +-0.0034179687500000, 0.0013732910156250, -0.0033264160156250, 0.0012207031250000, +-0.0039367675781250, 0.0006713867187500, -0.0035400390625000, 0.0008544921875000, +-0.0033569335937500, 0.0005187988281250, -0.0036621093750000, 0.0005493164062500, +-0.0031738281250000, 0.0003662109375000, -0.0027465820312500, 0.0000000000000000, +-0.0030517578125000, 0.0002441406250000, -0.0020751953125000, 0.0000000000000000, +-0.0021972656250000, -0.0001831054687500, -0.0018310546875000, 0.0000610351562500, +-0.0010070800781250, 0.0002136230468750, -0.0015563964843750, 0.0000610351562500, +-0.0004882812500000, 0.0002746582031250, -0.0005187988281250, 0.0004577636718750, +-0.0003662109375000, 0.0003356933593750, 0.0002746582031250, 0.0003051757812500, +0.0000000000000000, 0.0003662109375000, 0.0005798339843750, 0.0005187988281250, +0.0007019042968750, 0.0001220703125000, 0.0006408691406250, 0.0009155273437500, +0.0010070800781250, 0.0016479492187500, 0.0010070800781250, 0.0009765625000000, +0.0010070800781250, 0.0025024414062500, 0.0011596679687500, 0.0027770996093750, +0.0010986328125000, 0.0021972656250000, 0.0010070800781250, 0.0024719238281250, +0.0011596679687500, 0.0028076171875000, 0.0012207031250000, 0.0017700195312500, +0.0013427734375000, 0.0018310546875000, 0.0017700195312500, 0.0017700195312500, +0.0019836425781250, 0.0013122558593750, 0.0018920898437500, 0.0015563964843750, +0.0031433105468750, 0.0008544921875000, 0.0028991699218750, 0.0007629394531250, +0.0033264160156250, 0.0013122558593750, 0.0044555664062500, 0.0010986328125000, +0.0040588378906250, 0.0006408691406250, 0.0043640136718750, 0.0025329589843750, +0.0047912597656250, 0.0020141601562500, 0.0043334960937500, 0.0027160644531250, +0.0040588378906250, 0.0042114257812500, 0.0043029785156250, 0.0032348632812500, +0.0027465820312500, 0.0051269531250000, 0.0032653808593750, 0.0051879882812500, +0.0021362304687500, 0.0048828125000000, 0.0003356933593750, 0.0057373046875000, +0.0013427734375000}, +{-0.0036010742187500, 0.0013122558593750, -0.0045776367187500, 0.0012512207031250, +-0.0019531250000000, 0.0008544921875000, -0.0020141601562500, 0.0006408691406250, +-0.0020141601562500, 0.0010681152343750, -0.0005798339843750, 0.0013427734375000, +-0.0008544921875000, 0.0010070800781250, -0.0008850097656250, 0.0018920898437500, +-0.0003356933593750, 0.0019836425781250, -0.0009155273437500, 0.0019531250000000, +-0.0012512207031250, 0.0021667480468750, -0.0006713867187500, 0.0020751953125000, +-0.0029602050781250, 0.0025024414062500, -0.0021667480468750, 0.0022888183593750, +-0.0026245117187500, 0.0024719238281250, -0.0046691894531250, 0.0030212402343750, +-0.0034484863281250, 0.0026550292968750, -0.0043029785156250, 0.0029602050781250, +-0.0046691894531250, 0.0030212402343750, -0.0037536621093750, 0.0029602050781250, +-0.0035705566406250, 0.0029296875000000, -0.0039978027343750, 0.0028991699218750, +-0.0019226074218750, 0.0028991699218750, -0.0024719238281250, 0.0029296875000000, +-0.0014648437500000, 0.0026550292968750, 0.0003662109375000, 0.0025939941406250, +-0.0009155273437500, 0.0028076171875000, 0.0019226074218750, 0.0019226074218750, +0.0015258789062500, 0.0020141601562500, 0.0020446777343750, 0.0019226074218750, +0.0039062500000000, 0.0013732910156250, 0.0027160644531250, 0.0015258789062500, +0.0045776367187500, 0.0011291503906250, 0.0044860839843750, 0.0012512207031250, +0.0043029785156250, 0.0009765625000000, 0.0051879882812500, 0.0005493164062500, +0.0048522949218750, 0.0008239746093750, 0.0047607421875000, 0.0003051757812500, +0.0048522949218750, 0.0001831054687500, 0.0045776367187500, 0.0004272460937500, +0.0043334960937500, 0.0003662109375000, 0.0045166015625000, 0.0002746582031250, +0.0041809082031250, 0.0007324218750000, 0.0041198730468750, 0.0007324218750000, +0.0042419433593750, 0.0007934570312500, 0.0041503906250000, 0.0010375976562500, +0.0040588378906250, 0.0010070800781250, 0.0043640136718750, 0.0011291503906250, +0.0045166015625000, 0.0010681152343750, 0.0044555664062500, 0.0012512207031250, +0.0045776367187500, 0.0014038085937500, 0.0046997070312500, 0.0012512207031250, +0.0046081542968750, 0.0015563964843750, 0.0047302246093750, 0.0015869140625000, +0.0046691894531250, 0.0013427734375000, 0.0045776367187500, 0.0013732910156250, +0.0047912597656250, 0.0016174316406250, 0.0044250488281250, 0.0009155273437500, +0.0045776367187500, 0.0009460449218750, 0.0042419433593750, 0.0014038085937500, +0.0038452148437500, 0.0012817382812500, 0.0042114257812500, 0.0010986328125000, +0.0030822753906250, 0.0017700195312500, 0.0032958984375000, 0.0019531250000000, +0.0029296875000000, 0.0018005371093750, 0.0019836425781250, 0.0016479492187500, +0.0024108886718750, 0.0017700195312500, 0.0013427734375000, 0.0023193359375000, +0.0013732910156250, 0.0016174316406250, 0.0014038085937500, 0.0024108886718750, +0.0007629394531250, 0.0034179687500000, 0.0007934570312500, 0.0025634765625000, +0.0009460449218750, 0.0044250488281250, 0.0006408691406250, 0.0041198730468750, +0.0010986328125000, 0.0044555664062500, 0.0015869140625000, 0.0059814453125000, +0.0012512207031250, 0.0051574707031250, 0.0026550292968750, 0.0053710937500000, +0.0025329589843750, 0.0059814453125000, 0.0029296875000000, 0.0052185058593750, +0.0040893554687500, 0.0043945312500000, 0.0037536621093750, 0.0049133300781250, +0.0043334960937500, 0.0039978027343750, 0.0048217773437500, 0.0039367675781250, +0.0043334960937500, 0.0034484863281250, 0.0043640136718750, 0.0028991699218750, +0.0047302246093750, 0.0034179687500000, 0.0022277832031250, 0.0018310546875000, +0.0031433105468750, 0.0018005371093750, 0.0016479492187500, 0.0018920898437500, +-0.0011291503906250, 0.0010986328125000, 0.0003662109375000, 0.0012817382812500, +-0.0030212402343750, 0.0017395019531250, -0.0032348632812500, 0.0012817382812500, +-0.0031127929687500, 0.0019226074218750, -0.0046997070312500, 0.0028381347656250, +-0.0042724609375000, 0.0022888183593750, -0.0037231445312500, 0.0030212402343750, +-0.0043945312500000, 0.0033569335937500, -0.0031127929687500, 0.0027770996093750, +-0.0017700195312500, 0.0025329589843750, -0.0028076171875000, 0.0028991699218750, +-0.0003356933593750, 0.0022583007812500, -0.0000915527343750, 0.0022583007812500, +-0.0007629394531250, 0.0017395019531250, -0.0002136230468750, 0.0014953613281250, +0.0000610351562500, 0.0020141601562500, -0.0000915527343750, -0.0005493164062500, +-0.0007934570312500, 0.0001525878906250, 0.0007019042968750, -0.0006103515625000, +0.0020446777343750, -0.0026245117187500, 0.0010375976562500, -0.0016784667968750, +0.0043640136718750, -0.0043945312500000, 0.0043029785156250, -0.0039672851562500, +0.0047302246093750, -0.0040283203125000, 0.0071716308593750, -0.0062255859375000, +0.0063171386718750, -0.0058593750000000, 0.0055236816406250, -0.0042114257812500, +0.0067749023437500, -0.0048522949218750, 0.0051879882812500, -0.0044555664062500, +0.0029907226562500, -0.0031127929687500, 0.0043334960937500, -0.0037231445312500, +0.0012817382812500, -0.0024108886718750, 0.0009155273437500, -0.0026550292968750, +0.0010986328125000, -0.0024108886718750, -0.0000305175781250, -0.0011291503906250, +0.0003356933593750, -0.0014038085937500, 0.0000305175781250, -0.0013732910156250, +-0.0001831054687500, -0.0015258789062500, 0.0002441406250000, -0.0008850097656250, +0.0007019042968750, -0.0001220703125000, 0.0007629394531250, -0.0001831054687500, +0.0007324218750000, 0.0009460449218750, 0.0009460449218750, 0.0008239746093750, +0.0004882812500000, 0.0004272460937500, 0.0002746582031250, 0.0009155273437500, +0.0006408691406250, 0.0012512207031250, -0.0013122558593750, 0.0004577636718750, +-0.0007934570312500, 0.0003662109375000, -0.0011901855468750, 0.0003662109375000, +-0.0028076171875000, 0.0001525878906250, -0.0019836425781250, 0.0003662109375000, +-0.0027160644531250, 0.0001220703125000, -0.0029907226562500, -0.0001220703125000, +-0.0025634765625000, 0.0002136230468750, -0.0022277832031250, 0.0004577636718750, +-0.0025329589843750, 0.0001220703125000, -0.0036010742187500, 0.0009155273437500, +-0.0028686523437500, 0.0009765625000000, -0.0039062500000000, 0.0011596679687500, +-0.0058898925781250, 0.0013732910156250, -0.0049438476562500, 0.0013427734375000, +-0.0059204101562500, 0.0031127929687500, -0.0065002441406250, 0.0026550292968750, +-0.0062561035156250, 0.0027160644531250, -0.0062866210937500, 0.0043029785156250, +-0.0063476562500000, 0.0040283203125000, -0.0059814453125000, 0.0030517578125000, +-0.0063781738281250, 0.0035705566406250, -0.0054931640625000, 0.0028686523437500, +-0.0048522949218750, 0.0014953613281250, -0.0058288574218750, 0.0019226074218750, +-0.0021972656250000, 0.0008544921875000, -0.0031127929687500, 0.0007324218750000, +-0.0021972656250000, 0.0003967285156250, 0.0008239746093750, -0.0003356933593750, +-0.0007324218750000, -0.0001525878906250, 0.0008850097656250, -0.0009460449218750, +0.0015258789062500, -0.0014648437500000, 0.0010375976562500, -0.0013122558593750, +0.0011596679687500, -0.0015258789062500, 0.0012817382812500, -0.0019226074218750, +0.0010375976562500, -0.0009155273437500, 0.0010681152343750, -0.0014648437500000, +0.0013122558593750, -0.0008544921875000, 0.0013732910156250, 0.0001831054687500, +0.0012512207031250, -0.0005493164062500, 0.0014038085937500, 0.0019531250000000, +0.0012817382812500, 0.0016784667968750, 0.0017089843750000, 0.0025634765625000, +0.0020751953125000, 0.0047912597656250, 0.0015563964843750, 0.0037841796875000, +0.0025024414062500, 0.0049133300781250, 0.0022888183593750, 0.0055541992187500, +0.0026245117187500, 0.0047607421875000, 0.0034179687500000, 0.0044250488281250, +0.0028991699218750, 0.0048828125000000, 0.0029296875000000, 0.0033264160156250, +0.0034179687500000, 0.0034790039062500, 0.0031433105468750, 0.0032958984375000, +0.0025329589843750, 0.0021667480468750, 0.0027160644531250, 0.0025634765625000, +0.0028686523437500, 0.0025939941406250, 0.0025024414062500, 0.0020446777343750, +0.0028686523437500, 0.0025329589843750, 0.0033569335937500, 0.0028991699218750, +0.0029907226562500, 0.0020446777343750, 0.0031433105468750, 0.0033874511718750, +0.0036926269531250, 0.0028381347656250, 0.0030212402343750, 0.0029296875000000, +0.0024719238281250, 0.0038757324218750, 0.0031433105468750, 0.0029907226562500, +0.0014953613281250, 0.0038757324218750, 0.0018920898437500, 0.0035705566406250, +0.0014953613281250, 0.0032348632812500, 0.0001525878906250, 0.0036010742187500, +0.0009765625000000, 0.0031127929687500, -0.0000915527343750, 0.0028686523437500, +-0.0002441406250000, 0.0031738281250000, 0.0000305175781250, 0.0024108886718750, +-0.0002441406250000, 0.0018005371093750, -0.0002136230468750, 0.0025329589843750, +0.0005493164062500, 0.0008850097656250, 0.0002746582031250, 0.0007934570312500, +0.0007019042968750, 0.0004882812500000, 0.0016784667968750, -0.0003051757812500, +0.0011596679687500, 0.0002136230468750, 0.0017395019531250, -0.0007629394531250, +0.0019531250000000, -0.0007934570312500, 0.0017700195312500, -0.0009765625000000, +0.0016784667968750, -0.0014953613281250, 0.0018615722656250, -0.0012207031250000, +0.0018310546875000, -0.0017395019531250, 0.0018310546875000, -0.0016174316406250, +0.0018920898437500, -0.0017700195312500, 0.0019836425781250, -0.0021972656250000, +0.0020446777343750, -0.0020751953125000, 0.0017395019531250, -0.0022888183593750, +0.0019531250000000, -0.0024108886718750, 0.0018005371093750, -0.0022888183593750, +0.0014038085937500, -0.0024108886718750, 0.0016174316406250, -0.0025634765625000, +0.0013122558593750, -0.0018615722656250, 0.0011901855468750, -0.0021362304687500, +0.0014953613281250, -0.0019531250000000, 0.0015563964843750, -0.0013732910156250, +0.0014038085937500, -0.0018615722656250, 0.0024414062500000, -0.0010986328125000, +0.0022277832031250, -0.0011596679687500, 0.0026550292968750, -0.0012512207031250, +0.0035400390625000, -0.0006713867187500, 0.0032043457031250, -0.0008239746093750, +0.0043640136718750, -0.0018005371093750, 0.0042724609375000, -0.0011291503906250, +0.0046386718750000, -0.0021362304687500, 0.0054931640625000, -0.0034484863281250, +0.0050964355468750, -0.0023803710937500, 0.0055541992187500, -0.0050048828125000, +0.0059204101562500, -0.0047912597656250, 0.0054016113281250, -0.0051269531250000, +0.0050659179687500, -0.0069580078125000, 0.0054321289062500, -0.0063171386718750, +0.0048522949218750, -0.0066528320312500, 0.0046691894531250, -0.0075683593750000, +0.0048522949218750, -0.0062255859375000, 0.0049438476562500, -0.0053710937500000, +0.0049133300781250, -0.0064697265625000, 0.0043945312500000, -0.0026855468750000, +0.0048217773437500, -0.0033569335937500, 0.0042114257812500, -0.0021667480468750, +0.0032348632812500, 0.0008850097656250, 0.0038146972656250, -0.0008239746093750, +0.0028991699218750, 0.0014953613281250, 0.0027465820312500, 0.0018920898437500, +0.0028076171875000, 0.0010375976562500, 0.0025329589843750, 0.0015258789062500, +0.0024719238281250, 0.0015563964843750, 0.0022277832031250, -0.0001525878906250, +0.0024108886718750, 0.0002441406250000, 0.0018005371093750, -0.0004272460937500, +0.0011901855468750, -0.0020141601562500, 0.0016479492187500, -0.0010986328125000, +-0.0000915527343750, -0.0016479492187500, 0.0001220703125000, -0.0019531250000000, +-0.0005798339843750, -0.0007019042968750, -0.0019531250000000, 0.0002441406250000, +-0.0011901855468750, -0.0002441406250000, -0.0033569335937500, 0.0010681152343750, +-0.0033569335937500}, +{0.0024414062500000, 0.0014953613281250, 0.0023498535156250, 0.0012512207031250, +0.0022888183593750, 0.0007324218750000, 0.0028381347656250, 0.0000915527343750, +0.0028381347656250, 0.0000000000000000, 0.0021667480468750, -0.0007019042968750, +0.0026245117187500, -0.0009155273437500, 0.0022888183593750, -0.0012207031250000, +0.0014953613281250, -0.0017700195312500, 0.0021667480468750, -0.0018310546875000, +0.0012817382812500, -0.0019531250000000, 0.0013732910156250, -0.0022277832031250, +0.0015258789062500, -0.0024414062500000, 0.0011596679687500, -0.0024414062500000, +0.0013122558593750, -0.0023803710937500, 0.0010070800781250, -0.0024719238281250, +0.0011901855468750, -0.0022888183593750, 0.0011596679687500, -0.0021057128906250, +0.0007934570312500, -0.0021667480468750, 0.0009460449218750, -0.0020141601562500, +0.0014648437500000, -0.0018005371093750, 0.0012817382812500, -0.0019531250000000, +0.0015869140625000, -0.0019226074218750, 0.0022583007812500, -0.0017700195312500, +0.0019531250000000, -0.0020141601562500, 0.0025634765625000, -0.0021362304687500, +0.0025329589843750, -0.0021667480468750, 0.0026245117187500, -0.0024719238281250, +0.0029296875000000, -0.0027465820312500, 0.0027770996093750, -0.0028991699218750, +0.0028686523437500, -0.0031433105468750, 0.0030822753906250, -0.0034484863281250, +0.0027465820312500, -0.0036926269531250, 0.0025024414062500, -0.0038146972656250, +0.0027770996093750, -0.0039978027343750, 0.0023803710937500, -0.0040588378906250, +0.0022888183593750, -0.0041809082031250, 0.0025939941406250, -0.0043334960937500, +0.0025634765625000, -0.0044860839843750, 0.0025024414062500, -0.0044555664062500, +0.0034790039062500, -0.0041503906250000, 0.0031433105468750, -0.0046997070312500, +0.0037231445312500, -0.0042419433593750, 0.0046997070312500, -0.0037536621093750, +0.0041809082031250, -0.0045166015625000, 0.0051879882812500, -0.0021972656250000, +0.0053405761718750, -0.0031433105468750, 0.0050354003906250, -0.0024108886718750, +0.0051574707031250, -0.0004272460937500, 0.0052185058593750, -0.0020751953125000, +0.0046691894531250, 0.0002441406250000, 0.0046386718750000, 0.0000305175781250, +0.0046691894531250, -0.0004882812500000, 0.0045166015625000, 0.0005493164062500, +0.0044860839843750, 0.0000915527343750, 0.0041198730468750, -0.0009460449218750, +0.0044860839843750, -0.0004272460937500, 0.0039062500000000, -0.0016784667968750, +0.0032043457031250, -0.0032958984375000, 0.0037536621093750, -0.0025939941406250, +0.0025939941406250, -0.0052185058593750, 0.0026245117187500, -0.0053710937500000, +0.0025939941406250, -0.0054016113281250, 0.0020446777343750, -0.0068664550781250, +0.0022583007812500, -0.0064392089843750, 0.0015869140625000, -0.0054016113281250, +0.0017395019531250, -0.0065002441406250, 0.0012512207031250, -0.0050048828125000, +0.0005493164062500, -0.0030822753906250, 0.0010070800781250, -0.0046081542968750, +-0.0003662109375000, -0.0008239746093750, -0.0003051757812500, -0.0012207031250000, +-0.0005493164062500, -0.0007629394531250, -0.0013122558593750, 0.0017395019531250, +-0.0009460449218750, 0.0004272460937500, -0.0020751953125000, 0.0010375976562500, +-0.0018310546875000, 0.0019836425781250, -0.0021362304687500, 0.0008239746093750, +-0.0033264160156250, -0.0001525878906250, -0.0028076171875000, 0.0009155273437500, +-0.0024414062500000, -0.0002746582031250, -0.0030822753906250, -0.0003967285156250, +-0.0027160644531250, 0.0000915527343750, -0.0017089843750000, -0.0001220703125000, +-0.0020446777343750, -0.0000915527343750, -0.0022277832031250, 0.0007629394531250, +-0.0021057128906250, 0.0003967285156250, -0.0026550292968750, 0.0007324218750000, +-0.0030212402343750, 0.0016784667968750, -0.0026855468750000, 0.0011596679687500, +-0.0038452148437500, 0.0011596679687500, -0.0042114257812500, 0.0018615722656250, +-0.0037536621093750, 0.0000000000000000, -0.0037231445312500, -0.0017089843750000, +-0.0039672851562500, -0.0004882812500000, -0.0033264160156250, -0.0041198730468750, +-0.0035095214843750, -0.0042114257812500, -0.0031127929687500, -0.0031127929687500, +-0.0025939941406250, -0.0047912597656250, -0.0031738281250000, -0.0048217773437500, +-0.0013732910156250, -0.0005798339843750, -0.0019531250000000, -0.0018310546875000, +-0.0009155273437500, 0.0003051757812500, 0.0004272460937500, 0.0048522949218750, +-0.0007629394531250, 0.0027465820312500, 0.0046386718750000, 0.0054931640625000, +0.0036621093750000, 0.0066223144531250, 0.0045471191406250, 0.0057983398437500, +0.0086975097656250, 0.0058288574218750, 0.0071716308593750, 0.0061950683593750, +0.0085144042968750, 0.0067749023437500, 0.0093688964843750, 0.0060424804687500, +0.0084533691406250, 0.0071105957031250, 0.0075073242187500, 0.0097656250000000, +0.0029907226562500, 0.0053405761718750, 0.0008239746093750, 0.0059814453125000, +0.0017089843750000, 0.0045471191406250, 0.0004882812500000, 0.0062255859375000, +-0.0009765625000000, 0.0086669921875000, 0.0000915527343750, 0.0074462890625000, +-0.0017700195312500, 0.0074157714843750, -0.0021667480468750, 0.0087585449218750, +-0.0018005371093750, 0.0076293945312500, -0.0022277832031250, 0.0057983398437500, +-0.0021667480468750, 0.0067443847656250, -0.0018310546875000, 0.0058593750000000, +-0.0016784667968750, 0.0051879882812500, -0.0024108886718750, 0.0057678222656250, +-0.0027465820312500, 0.0064086914062500, -0.0020141601562500, 0.0058898925781250, +-0.0033569335937500, 0.0049743652343750, -0.0039672851562500, 0.0061035156250000, +-0.0028076171875000, 0.0044860839843750, -0.0026855468750000, 0.0023193359375000, +-0.0033569335937500, 0.0037841796875000, 0.0008544921875000, 0.0000610351562500, +-0.0000915527343750, -0.0000610351562500, 0.0002441406250000, 0.0002441406250000, +0.0036621093750000, -0.0014038085937500, 0.0025024414062500, -0.0011901855468750, +0.0007019042968750, -0.0010681152343750, 0.0023498535156250, -0.0010375976562500, +0.0003356933593750, -0.0014343261718750, -0.0030212402343750, -0.0017700195312500, +-0.0010986328125000, -0.0014648437500000, -0.0039978027343750, -0.0021057128906250, +-0.0049743652343750, -0.0024108886718750, -0.0033569335937500, -0.0019836425781250, +-0.0034179687500000, -0.0018615722656250, -0.0044860839843750, -0.0022583007812500, +-0.0008239746093750, -0.0016784667968750, -0.0011291503906250, -0.0016174316406250, +-0.0010681152343750, -0.0018310546875000, 0.0009765625000000, -0.0017395019531250, +0.0001525878906250, -0.0017395019531250, 0.0001525878906250, -0.0019226074218750, +0.0011291503906250, -0.0019836425781250, -0.0003051757812500, -0.0017089843750000, +-0.0015258789062500, -0.0016174316406250, -0.0001525878906250, -0.0017700195312500, +-0.0033874511718750, -0.0010375976562500, -0.0034790039062500, -0.0009765625000000, +-0.0026245117187500, -0.0012207031250000, -0.0039062500000000, -0.0012512207031250, +-0.0039367675781250, -0.0011291503906250, -0.0015869140625000, -0.0008544921875000, +-0.0023498535156250, -0.0013122558593750, -0.0012512207031250, -0.0006408691406250, +0.0009460449218750, 0.0003356933593750, -0.0003051757812500, -0.0003051757812500, +0.0019531250000000, 0.0003967285156250, 0.0020141601562500, 0.0007019042968750, +0.0021057128906250, 0.0004577636718750, 0.0034790039062500, 0.0003356933593750, +0.0028381347656250, 0.0004577636718750, 0.0023193359375000, 0.0007629394531250, +0.0033569335937500, 0.0005187988281250, 0.0018005371093750, 0.0009765625000000, +0.0003051757812500, 0.0017089843750000, 0.0019836425781250, 0.0012512207031250, +-0.0018310546875000, 0.0021667480468750, -0.0010681152343750, 0.0021667480468750, +-0.0017089843750000, 0.0022277832031250, -0.0042419433593750, 0.0027465820312500, +-0.0024719238281250, 0.0025329589843750, -0.0046997070312500, 0.0028686523437500, +-0.0046386718750000, 0.0029296875000000, -0.0043029785156250, 0.0028686523437500, +-0.0052795410156250, 0.0030517578125000, -0.0047607421875000, 0.0030517578125000, +-0.0046997070312500, 0.0026245117187500, -0.0047302246093750, 0.0027160644531250, +-0.0043640136718750, 0.0027465820312500, -0.0041198730468750, 0.0025329589843750, +-0.0041198730468750, 0.0026245117187500, -0.0029602050781250, 0.0026550292968750, +-0.0033569335937500, 0.0026550292968750, -0.0027465820312500, 0.0025024414062500, +-0.0016479492187500, 0.0024108886718750, -0.0025939941406250, 0.0025329589843750, +-0.0011291503906250, 0.0022888183593750, -0.0012207031250000, 0.0022583007812500, +-0.0012207031250000, 0.0023803710937500, -0.0004577636718750, 0.0024108886718750, +-0.0008239746093750, 0.0023498535156250, -0.0006713867187500, 0.0024108886718750, +-0.0004577636718750, 0.0025634765625000, -0.0007629394531250, 0.0022888183593750, +-0.0008850097656250, 0.0021362304687500, -0.0005493164062500, 0.0023498535156250, +-0.0013427734375000, 0.0017700195312500, -0.0010986328125000, 0.0018615722656250, +-0.0013732910156250, 0.0017089843750000, -0.0019836425781250, 0.0012207031250000, +-0.0014038085937500, 0.0014953613281250, -0.0024414062500000, 0.0013427734375000, +-0.0023193359375000, 0.0010986328125000, -0.0024719238281250, 0.0014648437500000, +-0.0032043457031250, 0.0018310546875000, -0.0028686523437500, 0.0015258789062500, +-0.0033569335937500, 0.0018310546875000, -0.0033569335937500, 0.0020446777343750, +-0.0033874511718750, 0.0018920898437500, -0.0036315917968750, 0.0017089843750000, +-0.0035400390625000, 0.0017700195312500, -0.0036621093750000, 0.0022888183593750, +-0.0038757324218750, 0.0017089843750000, -0.0039672851562500, 0.0023803710937500, +-0.0041503906250000, 0.0032043457031250, -0.0043334960937500, 0.0024414062500000, +-0.0042114257812500, 0.0044250488281250, -0.0043029785156250, 0.0041809082031250, +-0.0039672851562500, 0.0042114257812500, -0.0036621093750000, 0.0056457519531250, +-0.0037536621093750, 0.0051574707031250, -0.0027465820312500, 0.0043029785156250, +-0.0027770996093750, 0.0051269531250000, -0.0021667480468750, 0.0041809082031250, +-0.0012817382812500, 0.0026855468750000, -0.0015258789062500, 0.0035705566406250, +0.0002441406250000, 0.0020141601562500, 0.0000305175781250, 0.0017395019531250, +0.0004272460937500, 0.0019226074218750, 0.0017700195312500, 0.0013122558593750, +0.0012817382812500, 0.0014343261718750, 0.0016479492187500, 0.0017395019531250, +0.0020751953125000, 0.0014953613281250, 0.0015869140625000, 0.0017089843750000, +0.0014038085937500, 0.0021972656250000, 0.0018310546875000, 0.0019226074218750, +0.0003051757812500, 0.0020751953125000, 0.0006408691406250, 0.0020141601562500, +0.0004272460937500, 0.0025024414062500, -0.0007629394531250, 0.0029296875000000, +-0.0003051757812500, 0.0024108886718750, -0.0007324218750000, 0.0033569335937500, +-0.0008544921875000, 0.0035705566406250, -0.0006713867187500, 0.0030212402343750, +-0.0007324218750000, 0.0031738281250000, -0.0007324218750000, 0.0034179687500000, +-0.0001831054687500, 0.0014953613281250, -0.0002746582031250, 0.0022583007812500, +-0.0001525878906250, 0.0008239746093750, 0.0002441406250000, -0.0014038085937500, +0.0000610351562500, 0.0001831054687500, -0.0002136230468750, -0.0029296875000000, +-0.0000610351562500, -0.0032043457031250, -0.0001220703125000, -0.0027160644531250, +-0.0006713867187500, -0.0037841796875000, -0.0007934570312500, -0.0037231445312500, +-0.0001220703125000, -0.0032958984375000, -0.0004272460937500, -0.0033874511718750, +-0.0003967285156250, -0.0030822753906250, 0.0001220703125000, -0.0030212402343750, +-0.0001220703125000, -0.0033569335937500, 0.0003662109375000, -0.0009460449218750, +0.0004882812500000, -0.0012817382812500, 0.0002746582031250, -0.0020751953125000, +0.0003356933593750}, +{-0.0036010742187500, 0.0034179687500000, -0.0039978027343750, 0.0039672851562500, +-0.0036315917968750, 0.0037231445312500, -0.0042724609375000, 0.0038146972656250, +-0.0039672851562500, 0.0040588378906250, -0.0042724609375000, 0.0036010742187500, +-0.0049438476562500, 0.0031738281250000, -0.0043640136718750, 0.0034790039062500, +-0.0053710937500000, 0.0022277832031250, -0.0050048828125000, 0.0023498535156250, +-0.0052185058593750, 0.0021972656250000, -0.0058593750000000, 0.0014648437500000, +-0.0051574707031250, 0.0017395019531250, -0.0061340332031250, 0.0016174316406250, +-0.0058288574218750, 0.0014648437500000, -0.0058593750000000, 0.0018005371093750, +-0.0063781738281250, 0.0020141601562500, -0.0057373046875000, 0.0018005371093750, +-0.0063781738281250, 0.0025024414062500, -0.0060119628906250, 0.0025634765625000, +-0.0058593750000000, 0.0024108886718750, -0.0061035156250000, 0.0026855468750000, +-0.0054931640625000, 0.0027465820312500, -0.0056152343750000, 0.0025329589843750, +-0.0054016113281250, 0.0023498535156250, -0.0049438476562500, 0.0027160644531250, +-0.0047302246093750, 0.0028076171875000, -0.0043945312500000, 0.0023803710937500, +-0.0034179687500000, 0.0034179687500000, -0.0036010742187500, 0.0032043457031250, +-0.0031433105468750, 0.0033264160156250, -0.0023193359375000, 0.0040893554687500, +-0.0028991699218750, 0.0036315917968750, -0.0019836425781250, 0.0034790039062500, +-0.0019836425781250, 0.0040588378906250, -0.0021972656250000, 0.0031738281250000, +-0.0018920898437500, 0.0022583007812500, -0.0020141601562500, 0.0031127929687500, +-0.0022888183593750, 0.0014343261718750, -0.0021667480468750, 0.0013427734375000, +-0.0024719238281250, 0.0015563964843750, -0.0027770996093750, 0.0007629394531250, +-0.0025939941406250, 0.0009460449218750, -0.0032958984375000, 0.0015869140625000, +-0.0031433105468750, 0.0012207031250000, -0.0032043457031250, 0.0014953613281250, +-0.0037231445312500, 0.0021362304687500, -0.0033874511718750, 0.0018005371093750, +-0.0035705566406250, 0.0021972656250000, -0.0036621093750000, 0.0023193359375000, +-0.0033264160156250, 0.0021972656250000, -0.0032348632812500, 0.0021667480468750, +-0.0034179687500000, 0.0021972656250000, -0.0019836425781250, 0.0029602050781250, +-0.0020446777343750, 0.0027160644531250, -0.0018310546875000, 0.0026550292968750, +-0.0007934570312500, 0.0033264160156250, -0.0009155273437500, 0.0032348632812500, +-0.0007934570312500, 0.0019836425781250, -0.0004577636718750, 0.0026550292968750, +-0.0008544921875000, 0.0014953613281250, -0.0010986328125000, -0.0001525878906250, +-0.0007934570312500, 0.0008850097656250, -0.0016174316406250, -0.0021057128906250, +-0.0016479492187500, -0.0018920898437500, -0.0013732910156250, -0.0020751953125000, +-0.0017395019531250, -0.0039978027343750, -0.0018310546875000, -0.0033569335937500, +-0.0004577636718750, -0.0027465820312500, -0.0008544921875000, -0.0034484863281250, +-0.0003662109375000, -0.0026855468750000, 0.0009155273437500, -0.0014343261718750, +0.0004272460937500, -0.0021667480468750, 0.0012512207031250, -0.0009765625000000, +0.0014343261718750, -0.0010986328125000, 0.0008544921875000, -0.0006408691406250, +0.0008850097656250, 0.0005798339843750, 0.0011291503906250, -0.0003051757812500, +-0.0002441406250000, -0.0013732910156250, -0.0003356933593750, -0.0000305175781250, +-0.0000610351562500, -0.0014648437500000, -0.0005493164062500, -0.0040588378906250, +-0.0006408691406250, -0.0028381347656250, -0.0001831054687500, -0.0037841796875000, +-0.0001525878906250, -0.0047607421875000, -0.0002136230468750, -0.0035095214843750, +-0.0001220703125000, -0.0027160644531250, -0.0000610351562500, -0.0036315917968750, +0.0000000000000000, -0.0007934570312500, -0.0002441406250000, -0.0009765625000000, +0.0004882812500000, -0.0012207031250000, 0.0011901855468750, 0.0002136230468750, +0.0006713867187500, -0.0001525878906250, 0.0015258789062500, -0.0006713867187500, +0.0018920898437500, -0.0001831054687500, 0.0013122558593750, -0.0010986328125000, +0.0010986328125000, -0.0029296875000000, 0.0013427734375000, -0.0027160644531250, +-0.0002441406250000, -0.0018005371093750, 0.0000915527343750, -0.0026550292968750, +0.0003662109375000, -0.0018615722656250, -0.0003967285156250, -0.0007934570312500, +-0.0004882812500000, -0.0018005371093750, -0.0004882812500000, 0.0015869140625000, +0.0000000000000000, 0.0012207031250000, -0.0008544921875000, 0.0015869140625000, +-0.0018615722656250, 0.0040588378906250, -0.0010375976562500, 0.0032958984375000, +-0.0025024414062500, 0.0026855468750000, -0.0028991699218750, 0.0037536621093750, +-0.0023193359375000, 0.0025939941406250, -0.0025024414062500, 0.0008239746093750, +-0.0027770996093750, 0.0017395019531250, -0.0020446777343750, 0.0002746582031250, +-0.0018310546875000, -0.0002136230468750, -0.0018615722656250, 0.0005187988281250, +-0.0017700195312500, 0.0003967285156250, -0.0016479492187500, -0.0001220703125000, +-0.0013427734375000, 0.0010986328125000, -0.0015563964843750, 0.0011291503906250, +-0.0011596679687500, 0.0002136230468750, -0.0005493164062500, 0.0000610351562500, +-0.0009155273437500, 0.0003051757812500, -0.0000915527343750, -0.0010375976562500, +0.0001525878906250, -0.0013427734375000, -0.0007629394531250, -0.0008544921875000, +-0.0008544921875000, -0.0010681152343750, -0.0001525878906250, -0.0014343261718750, +-0.0024108886718750, -0.0005798339843750, -0.0020446777343750, -0.0003051757812500, +-0.0026855468750000, -0.0005798339843750, -0.0045166015625000, -0.0004272460937500, +-0.0035400390625000, -0.0003051757812500, -0.0045776367187500, -0.0012512207031250, +-0.0050048828125000, -0.0014038085937500, -0.0044555664062500, -0.0015258789062500, +-0.0044860839843750, -0.0022888183593750, -0.0047607421875000, -0.0022583007812500, +-0.0034484863281250, -0.0013122558593750, -0.0039062500000000, -0.0017700195312500, +-0.0030822753906250, -0.0009460449218750, -0.0018615722656250, 0.0003967285156250, +-0.0028686523437500, -0.0003662109375000, -0.0002746582031250, 0.0006408691406250, +-0.0006408691406250, 0.0007629394531250, -0.0002441406250000, 0.0001220703125000, +0.0015563964843750, -0.0001220703125000, 0.0005798339843750, -0.0004882812500000, +0.0017089843750000, -0.0012817382812500, 0.0019836425781250, -0.0019836425781250, +0.0015563964843750, -0.0023803710937500, 0.0016784667968750, -0.0027770996093750, +0.0018310546875000, -0.0032043457031250, 0.0012207031250000, -0.0032043457031250, +0.0013732910156250, -0.0034484863281250, 0.0011596679687500, -0.0034179687500000, +0.0007629394531250, -0.0031433105468750, 0.0011291503906250, -0.0034179687500000, +0.0000000000000000, -0.0035400390625000, 0.0004272460937500, -0.0030212402343750, +-0.0000305175781250, -0.0036010742187500, -0.0012207031250000, -0.0039672851562500, +-0.0004577636718750, -0.0029296875000000, -0.0007629394531250, -0.0050354003906250, +-0.0012512207031250, -0.0039672851562500, -0.0004882812500000, -0.0043334960937500, +0.0000610351562500, -0.0059509277343750, -0.0003356933593750, -0.0044555664062500, +0.0010681152343750, -0.0065917968750000, 0.0008544921875000, -0.0059204101562500, +0.0012512207031250, -0.0061035156250000, 0.0023193359375000, -0.0074462890625000, +0.0017700195312500, -0.0061340332031250, 0.0030517578125000, -0.0078430175781250, +0.0030517578125000, -0.0076599121093750, 0.0031738281250000, -0.0070800781250000, +0.0039062500000000, -0.0077514648437500, 0.0038146972656250, -0.0075378417968750, +0.0038146972656250, -0.0071716308593750, 0.0040588378906250, -0.0072326660156250, +0.0040283203125000, -0.0069885253906250, 0.0039062500000000, -0.0063781738281250, +0.0039978027343750, -0.0061645507812500, 0.0037231445312500, -0.0060119628906250, +0.0039367675781250, -0.0053710937500000, 0.0035705566406250, -0.0054931640625000, +0.0031433105468750, -0.0056457519531250, 0.0034790039062500, -0.0048522949218750, +0.0028381347656250, -0.0057983398437500, 0.0028076171875000, -0.0051879882812500, +0.0029907226562500, -0.0050354003906250, 0.0027770996093750, -0.0054931640625000, +0.0028991699218750, -0.0047302246093750, 0.0032348632812500, -0.0052490234375000, +0.0031127929687500, -0.0046081542968750, 0.0034179687500000, -0.0047912597656250, +0.0038757324218750, -0.0052185058593750, 0.0036315917968750, -0.0041809082031250, +0.0042724609375000, -0.0056762695312500, 0.0043945312500000, -0.0050964355468750, +0.0041198730468750, -0.0051269531250000, 0.0043334960937500, -0.0061645507812500, +0.0044250488281250, -0.0052490234375000, 0.0033874511718750, -0.0057373046875000, +0.0036621093750000, -0.0057678222656250, 0.0031738281250000, -0.0054016113281250, +0.0022277832031250, -0.0054931640625000, 0.0026855468750000, -0.0054626464843750, +0.0021667480468750, -0.0049743652343750, 0.0020141601562500, -0.0050964355468750, +0.0020141601562500, -0.0048217773437500, 0.0019531250000000, -0.0043640136718750, +0.0020446777343750, -0.0046386718750000, 0.0014343261718750, -0.0038146972656250, +0.0016174316406250, -0.0036315917968750, 0.0014648437500000, -0.0036315917968750, +0.0008850097656250, -0.0032348632812500, 0.0011291503906250, -0.0032958984375000, +0.0008239746093750, -0.0039062500000000, 0.0007324218750000, -0.0038146972656250, +0.0004882812500000, -0.0042114257812500, 0.0001525878906250, -0.0050659179687500, +0.0003051757812500, -0.0049438476562500, -0.0004577636718750, -0.0051879882812500, +-0.0006713867187500, -0.0056762695312500, -0.0004577636718750, -0.0050354003906250, +-0.0006713867187500, -0.0047302246093750, -0.0009155273437500, -0.0054931640625000, +-0.0003967285156250, -0.0029296875000000, -0.0004577636718750, -0.0036621093750000, +-0.0004882812500000, -0.0030822753906250, -0.0002441406250000, -0.0009155273437500, +-0.0003967285156250, -0.0018615722656250, -0.0003662109375000, -0.0002441406250000, +-0.0001831054687500, -0.0000610351562500, -0.0002136230468750, -0.0004272460937500, +-0.0003356933593750, 0.0002746582031250, -0.0003356933593750, 0.0002746582031250, +0.0000000000000000, -0.0011596679687500, 0.0000000000000000, -0.0004272460937500, +-0.0003051757812500, -0.0014038085937500, -0.0002441406250000, -0.0032653808593750, +-0.0000610351562500, -0.0022888183593750, -0.0015258789062500, -0.0041503906250000, +-0.0014953613281250, -0.0043334960937500, -0.0014648437500000, -0.0038757324218750, +-0.0022583007812500, -0.0044250488281250, -0.0021972656250000, -0.0040283203125000, +-0.0016784667968750, -0.0026245117187500, -0.0022583007812500, -0.0028076171875000, +-0.0013427734375000, -0.0018310546875000, -0.0000305175781250, -0.0003051757812500, +-0.0009765625000000, -0.0010375976562500, 0.0002136230468750, -0.0000915527343750, +0.0003051757812500, 0.0003356933593750, 0.0009155273437500, -0.0002441406250000, +0.0015258789062500, -0.0004272460937500, 0.0007629394531250, -0.0001525878906250, +0.0039367675781250, -0.0007934570312500, 0.0036010742187500, -0.0009765625000000, +0.0037231445312500, -0.0007629394531250, 0.0059204101562500, -0.0007324218750000, +0.0055236816406250, -0.0008850097656250, 0.0054931640625000, -0.0013732910156250, +0.0063476562500000, -0.0003967285156250, 0.0047607421875000, -0.0017089843750000, +0.0036621093750000, -0.0031738281250000, 0.0053710937500000, -0.0018310546875000, +0.0010986328125000, -0.0057067871093750, 0.0011291503906250, -0.0059814453125000, +0.0011901855468750, -0.0045471191406250, -0.0007324218750000, -0.0059509277343750, +0.0000610351562500, -0.0063781738281250, -0.0009765625000000, -0.0012512207031250, +-0.0008544921875000, -0.0023193359375000, -0.0008239746093750, -0.0013122558593750, +-0.0018615722656250, 0.0051574707031250, -0.0022583007812500, -0.0054016113281250, +-0.0019531250000000}, +{0.0028686523437500, 0.0016479492187500, 0.0021972656250000, 0.0010375976562500, +0.0020446777343750, 0.0015563964843750, 0.0020141601562500, 0.0012207031250000, +0.0017395019531250, 0.0007324218750000, 0.0016479492187500, 0.0015869140625000, +0.0016784667968750, -0.0004882812500000, 0.0015869140625000, 0.0002136230468750, +0.0015258789062500, -0.0003051757812500, 0.0016479492187500, -0.0019836425781250, +0.0015563964843750, -0.0009765625000000, 0.0011596679687500, -0.0028686523437500, +0.0012512207031250, -0.0025634765625000, 0.0009460449218750, -0.0030212402343750, +0.0004272460937500, -0.0043640136718750, 0.0005798339843750, -0.0036621093750000, +0.0003356933593750, -0.0054626464843750, 0.0003356933593750, -0.0055236816406250, +0.0002746582031250, -0.0052795410156250, 0.0001525878906250, -0.0059509277343750, +0.0003356933593750, -0.0055541992187500, -0.0002441406250000, -0.0046386718750000, +-0.0001831054687500, -0.0048217773437500, -0.0001220703125000, -0.0040588378906250, +-0.0004577636718750, -0.0029602050781250, -0.0003662109375000, -0.0034179687500000, +0.0000305175781250, -0.0027160644531250, -0.0001525878906250, -0.0022277832031250, +0.0000610351562500, -0.0028991699218750, 0.0004882812500000, -0.0029907226562500, +0.0003051757812500, -0.0022583007812500, 0.0007629394531250, -0.0041198730468750, +0.0006713867187500, -0.0036926269531250, 0.0006408691406250, -0.0036621093750000, +0.0010375976562500, -0.0048522949218750, 0.0008850097656250, -0.0044250488281250, +0.0003967285156250, -0.0047912597656250, 0.0006713867187500, -0.0051269531250000, +0.0003051757812500, -0.0042724609375000, -0.0002746582031250, -0.0040588378906250, +-0.0000610351562500, -0.0045471191406250, -0.0008239746093750, -0.0012817382812500, +-0.0007934570312500, -0.0022277832031250, -0.0007934570312500, -0.0012817382812500, +-0.0012817382812500, 0.0018005371093750, -0.0012207031250000, 0.0005187988281250, +-0.0008239746093750, 0.0010070800781250, -0.0010375976562500, 0.0021667480468750, +-0.0007934570312500, 0.0002136230468750, -0.0005493164062500, -0.0012207031250000, +-0.0006713867187500, 0.0002136230468750, 0.0007019042968750, -0.0041198730468750, +0.0002746582031250, -0.0038452148437500, 0.0007324218750000, -0.0036926269531250, +0.0019226074218750, -0.0059814453125000, 0.0014648437500000, -0.0049438476562500, +0.0026550292968750, -0.0035400390625000, 0.0025634765625000, -0.0046081542968750, +0.0025634765625000, -0.0030212402343750, 0.0036926269531250, -0.0004882812500000, +0.0034179687500000, -0.0020751953125000, 0.0018615722656250, 0.0001831054687500, +0.0029296875000000, 0.0008850097656250, 0.0019226074218750, -0.0001220703125000, +-0.0001525878906250, -0.0000915527343750, 0.0008850097656250, 0.0003662109375000, +-0.0014343261718750, -0.0013427734375000, -0.0009155273437500, -0.0013427734375000, +-0.0013732910156250, -0.0011596679687500, -0.0033569335937500, -0.0018615722656250, +-0.0023803710937500, -0.0016174316406250, -0.0030212402343750, -0.0014648437500000, +-0.0032653808593750, -0.0009765625000000, -0.0031127929687500, -0.0019836425781250, +-0.0032958984375000, -0.0026855468750000, -0.0032043457031250, -0.0017700195312500, +-0.0026855468750000, -0.0044860839843750, -0.0029296875000000, -0.0044555664062500, +-0.0027160644531250, -0.0039672851562500, -0.0018920898437500, -0.0054626464843750, +-0.0025939941406250, -0.0011901855468750, -0.0036010742187500, -0.0051269531250000, +-0.0033264160156250, -0.0037536621093750, -0.0031127929687500, -0.0039062500000000, +-0.0036315917968750, -0.0061035156250000, -0.0037841796875000, -0.0059814453125000, +-0.0021057128906250, -0.0031433105468750, -0.0023498535156250, -0.0038452148437500, +-0.0025939941406250, -0.0032348632812500, -0.0018005371093750, -0.0008239746093750, +-0.0020446777343750, -0.0015563964843750, -0.0032348632812500, -0.0013122558593750, +-0.0029602050781250, -0.0011901855468750, -0.0031433105468750, -0.0004577636718750, +-0.0046691894531250, -0.0002441406250000, -0.0044250488281250, -0.0009765625000000, +-0.0019531250000000, 0.0018005371093750, -0.0032043457031250, 0.0017395019531250, +-0.0017700195312500, 0.0015869140625000, 0.0012817382812500, 0.0029907226562500, +-0.0004882812500000, 0.0025329589843750, 0.0005493164062500, 0.0013122558593750, +0.0019531250000000, 0.0020446777343750, 0.0000915527343750, 0.0013122558593750, +-0.0016174316406250, -0.0006408691406250, -0.0000610351562500, 0.0001220703125000, +-0.0020751953125000, 0.0007629394531250, -0.0029296875000000, -0.0001831054687500, +-0.0011901855468750, 0.0007019042968750, -0.0007324218750000, 0.0024108886718750, +-0.0018920898437500, 0.0016174316406250, 0.0013122558593750, 0.0018615722656250, +0.0015258789062500, 0.0024719238281250, 0.0007934570312500, 0.0017089843750000, +0.0021667480468750, 0.0007629394531250, 0.0022888183593750, 0.0012512207031250, +-0.0004272460937500, 0.0009460449218750, 0.0004577636718750, 0.0007019042968750, +-0.0004272460937500, 0.0008544921875000, -0.0028076171875000, 0.0010681152343750, +-0.0015258789062500, 0.0009765625000000, -0.0036926269531250, 0.0004577636718750, +-0.0036926269531250, 0.0006103515625000, -0.0035705566406250, 0.0003662109375000, +-0.0049133300781250, -0.0002746582031250, -0.0045166015625000, -0.0000915527343750, +-0.0034179687500000, 0.0002746582031250, -0.0041198730468750, 0.0001525878906250, +-0.0035705566406250, -0.0000305175781250, -0.0019226074218750, 0.0003051757812500, +-0.0025634765625000, 0.0004272460937500, -0.0023193359375000, -0.0009155273437500, +-0.0015563964843750, -0.0007324218750000, -0.0023803710937500, -0.0006103515625000, +-0.0031127929687500, -0.0015258789062500, -0.0021667480468750, -0.0014343261718750, +-0.0042724609375000, -0.0004882812500000, -0.0039367675781250, -0.0007629394531250, +-0.0042724609375000, -0.0005187988281250, -0.0057678222656250, 0.0003051757812500, +-0.0048828125000000, 0.0000610351562500, -0.0053710937500000, 0.0000610351562500, +-0.0060119628906250, 0.0001525878906250, -0.0047912597656250, 0.0000915527343750, +-0.0041809082031250, -0.0000915527343750, -0.0052185058593750, -0.0000610351562500, +-0.0018005371093750, -0.0000305175781250, -0.0028076171875000, -0.0000610351562500, +-0.0016174316406250, -0.0000915527343750, 0.0011291503906250, -0.0001220703125000, +-0.0008544921875000, -0.0000915527343750, 0.0026245117187500, 0.0001525878906250, +0.0022583007812500, -0.0001525878906250, 0.0023803710937500, 0.0004577636718750, +0.0044860839843750, 0.0010681152343750, 0.0033874511718750, 0.0006408691406250, +0.0043945312500000, 0.0017700195312500, 0.0046386718750000, 0.0018615722656250, +0.0040893554687500, 0.0018310546875000, 0.0043334960937500, 0.0023193359375000, +0.0043945312500000, 0.0022277832031250, 0.0028381347656250, 0.0023803710937500, +0.0033874511718750, 0.0024108886718750, 0.0027465820312500, 0.0023803710937500, +0.0013122558593750, 0.0024719238281250, 0.0021362304687500, 0.0025329589843750, +0.0004272460937500, 0.0025024414062500, 0.0003967285156250, 0.0024108886718750, +0.0001831054687500, 0.0027160644531250, -0.0008239746093750, 0.0029296875000000, +-0.0004882812500000, 0.0027160644531250, -0.0013122558593750, 0.0035705566406250, +-0.0014343261718750, 0.0035705566406250, -0.0015869140625000, 0.0036926269531250, +-0.0021667480468750, 0.0041809082031250, -0.0021972656250000, 0.0040893554687500, +-0.0026855468750000, 0.0040893554687500, -0.0030517578125000, 0.0042724609375000, +-0.0031738281250000, 0.0040283203125000, -0.0035095214843750, 0.0037231445312500, +-0.0038757324218750, 0.0039062500000000, -0.0034179687500000, 0.0036010742187500, +-0.0038757324218750, 0.0033874511718750, -0.0037231445312500, 0.0035400390625000, +-0.0032653808593750, 0.0036315917968750, -0.0036926269531250, 0.0033569335937500, +-0.0026245117187500, 0.0036926269531250, -0.0030517578125000, 0.0038452148437500, +-0.0026245117187500, 0.0035095214843750, -0.0016174316406250, 0.0036315917968750, +-0.0024414062500000, 0.0037536621093750, -0.0014343261718750, 0.0023498535156250, +-0.0015258789062500, 0.0029296875000000, -0.0011596679687500, 0.0021667480468750, +-0.0004882812500000, 0.0006713867187500, -0.0009765625000000, 0.0016174316406250, +0.0001220703125000, 0.0000610351562500, -0.0001525878906250, -0.0000305175781250, +-0.0003051757812500, 0.0002136230468750, 0.0001525878906250, -0.0004577636718750, +-0.0003356933593750, -0.0003356933593750, -0.0005493164062500, 0.0001831054687500, +-0.0005798339843750, 0.0000000000000000, -0.0009765625000000, 0.0001220703125000, +-0.0013427734375000, 0.0006408691406250, -0.0013427734375000, 0.0005493164062500, +-0.0019836425781250, 0.0006713867187500, -0.0019836425781250, 0.0007019042968750, +-0.0020751953125000, 0.0006408691406250, -0.0023193359375000, 0.0007629394531250, +-0.0021972656250000, 0.0008239746093750, -0.0023498535156250, 0.0005798339843750, +-0.0021362304687500, 0.0008239746093750, -0.0021057128906250, 0.0002746582031250, +-0.0021057128906250, -0.0001831054687500, -0.0018310546875000, 0.0003662109375000, +-0.0023803710937500, -0.0010375976562500, -0.0020141601562500, -0.0009155273437500, +-0.0024108886718750, -0.0011901855468750, -0.0033264160156250, -0.0019531250000000, +-0.0029296875000000, -0.0014648437500000, -0.0039062500000000, -0.0027465820312500, +-0.0041503906250000, -0.0027770996093750, -0.0041198730468750, -0.0023803710937500, +-0.0044250488281250, -0.0029602050781250, -0.0043945312500000, -0.0029907226562500, +-0.0039978027343750, -0.0011291503906250, -0.0041503906250000, -0.0016479492187500, +-0.0037536621093750, -0.0013427734375000, -0.0031433105468750, 0.0003662109375000, +-0.0033264160156250, -0.0002136230468750, -0.0028076171875000, -0.0010375976562500, +-0.0025024414062500, -0.0001525878906250, -0.0027770996093750, -0.0009155273437500, +-0.0028381347656250, -0.0023803710937500, -0.0025634765625000, -0.0017089843750000, +-0.0035400390625000, -0.0029907226562500, -0.0036010742187500, -0.0029296875000000, +-0.0030517578125000, -0.0027465820312500, -0.0033874511718750, -0.0036010742187500, +-0.0035400390625000, -0.0035400390625000, -0.0010681152343750, -0.0021972656250000, +-0.0016479492187500, -0.0025329589843750, -0.0010375976562500, -0.0021972656250000, +0.0010375976562500, -0.0009765625000000, 0.0001831054687500, -0.0013122558593750, +0.0005798339843750, -0.0013427734375000, 0.0010070800781250, -0.0010070800781250, +0.0004882812500000, -0.0011291503906250, 0.0001220703125000, -0.0014038085937500, +0.0004577636718750, -0.0011901855468750, -0.0004272460937500, -0.0014038085937500, +-0.0005187988281250, -0.0014343261718750, -0.0003662109375000, -0.0016174316406250, +-0.0004882812500000, -0.0019836425781250, -0.0005187988281250, -0.0016479492187500, +-0.0008850097656250, -0.0006408691406250, -0.0005798339843750, -0.0014343261718750, +-0.0012207031250000, -0.0008850097656250, -0.0023193359375000, 0.0008850097656250, +-0.0022888183593750, 0.0007934570312500, -0.0036926269531250, 0.0012512207031250, +-0.0036926269531250, 0.0013427734375000, -0.0028991699218750, 0.0007324218750000, +-0.0032653808593750, 0.0006408691406250, -0.0036315917968750, 0.0010986328125000, +-0.0015869140625000, -0.0003356933593750, -0.0019226074218750, -0.0004882812500000, +-0.0013732910156250, -0.0004272460937500, 0.0001525878906250, -0.0010986328125000, +-0.0007019042968750, -0.0009765625000000, -0.0001220703125000, -0.0003356933593750, +0.0002746582031250, -0.0009155273437500, 0.0000915527343750, -0.0005493164062500, +0.0001525878906250, 0.0002136230468750, 0.0001220703125000, -0.0005798339843750, +-0.0003356933593750, 0.0002746582031250, 0.0000305175781250, 0.0003662109375000, +-0.0008544921875000}, +{-0.0059509277343750, 0.0001831054687500, -0.0050354003906250, 0.0004882812500000, +-0.0037841796875000, 0.0005493164062500, -0.0044555664062500, 0.0003662109375000, +-0.0025329589843750, 0.0005798339843750, -0.0026855468750000, 0.0008239746093750, +-0.0023193359375000, 0.0005493164062500, -0.0010681152343750, 0.0004577636718750, +-0.0015869140625000, 0.0007019042968750, -0.0004882812500000, -0.0003051757812500, +-0.0006408691406250, 0.0002136230468750, -0.0006103515625000, -0.0004882812500000, +-0.0000610351562500, -0.0016784667968750, -0.0004882812500000, -0.0008544921875000, +0.0000305175781250, -0.0022277832031250, 0.0000305175781250, -0.0023498535156250, +-0.0003051757812500, -0.0022277832031250, -0.0001525878906250, -0.0027770996093750, +-0.0000305175781250, -0.0026245117187500, -0.0007934570312500, -0.0027160644531250, +-0.0005187988281250, -0.0026245117187500, -0.0007324218750000, -0.0027465820312500, +-0.0012512207031250, -0.0031433105468750, -0.0005798339843750, -0.0028381347656250, +-0.0012817382812500, -0.0023193359375000, -0.0013122558593750, -0.0028381347656250, +-0.0011596679687500, -0.0020446777343750, -0.0013732910156250, -0.0007629394531250, +-0.0013427734375000, -0.0015258789062500, -0.0016174316406250, -0.0008850097656250, +-0.0014648437500000, -0.0001831054687500, -0.0019226074218750, -0.0013122558593750, +-0.0023803710937500, -0.0021057128906250, -0.0019226074218750, -0.0011901855468750, +-0.0030212402343750, -0.0028381347656250, -0.0028686523437500, -0.0032348632812500, +-0.0028686523437500, -0.0027770996093750, -0.0036010742187500, -0.0028381347656250, +-0.0033264160156250, -0.0029602050781250, -0.0033264160156250, -0.0028686523437500, +-0.0034790039062500, -0.0029296875000000, -0.0035095214843750, -0.0025634765625000, +-0.0034179687500000, -0.0021362304687500, -0.0032653808593750, -0.0024414062500000, +-0.0027160644531250, -0.0019836425781250, -0.0031433105468750, -0.0018005371093750, +-0.0022888183593750, -0.0017700195312500, -0.0011596679687500, -0.0017395019531250, +-0.0017700195312500, -0.0016174316406250, -0.0006713867187500, -0.0009155273437500, +-0.0005798339843750, -0.0011291503906250, -0.0005493164062500, -0.0008544921875000, +-0.0000610351562500, -0.0000610351562500, -0.0003662109375000, -0.0003967285156250, +0.0000000000000000, -0.0005187988281250, 0.0002136230468750, -0.0002136230468750, +-0.0001831054687500, 0.0000000000000000, -0.0004577636718750, -0.0001831054687500, +-0.0002441406250000, -0.0004272460937500, -0.0005493164062500, -0.0000915527343750, +-0.0006103515625000, 0.0005493164062500, -0.0005798339843750, 0.0003051757812500, +-0.0003356933593750, -0.0002746582031250, -0.0003051757812500, -0.0001220703125000, +-0.0023193359375000, -0.0007324218750000, -0.0010375976562500, -0.0003967285156250, +-0.0018005371093750, -0.0004272460937500, -0.0041503906250000, -0.0010681152343750, +-0.0026855468750000, -0.0008850097656250, -0.0038452148437500, -0.0007934570312500, +-0.0046386718750000, -0.0009765625000000, -0.0032348632812500, -0.0008850097656250, +-0.0025329589843750, -0.0007629394531250, -0.0033569335937500, -0.0012207031250000, +-0.0007934570312500, -0.0006103515625000, -0.0007019042968750, -0.0009155273437500, +-0.0010070800781250, -0.0010986328125000, -0.0000915527343750, -0.0006713867187500, +-0.0002441406250000, -0.0010986328125000, 0.0000915527343750, -0.0018005371093750, +-0.0001525878906250, -0.0014038085937500, 0.0001525878906250, -0.0023193359375000, +0.0009460449218750, -0.0035705566406250, 0.0004882812500000, -0.0029602050781250, +-0.0002136230468750, -0.0041503906250000, 0.0008544921875000, -0.0050354003906250, +-0.0004272460937500, -0.0038757324218750, -0.0024108886718750, -0.0036621093750000, +-0.0008850097656250, -0.0051574707031250, -0.0021362304687500, -0.0015258789062500, +-0.0028991699218750, -0.0022277832031250, -0.0018005371093750, -0.0024719238281250, +-0.0010681152343750, 0.0000000000000000, -0.0015563964843750, -0.0004882812500000, +-0.0002746582031250, -0.0017700195312500, -0.0000915527343750, -0.0005187988281250, +-0.0002136230468750, -0.0009765625000000, 0.0005187988281250, -0.0024719238281250, +0.0006713867187500, -0.0011596679687500, -0.0000610351562500, -0.0023498535156250, +0.0002136230468750, -0.0025939941406250, -0.0000305175781250, -0.0019226074218750, +-0.0004882812500000, -0.0018310546875000, -0.0000305175781250, -0.0018920898437500, +-0.0010681152343750, -0.0012817382812500, -0.0007934570312500, -0.0006408691406250, +-0.0012512207031250, -0.0011291503906250, -0.0020751953125000, -0.0011596679687500, +-0.0013427734375000, -0.0000915527343750, -0.0028381347656250, -0.0024719238281250, +-0.0026245117187500, -0.0012207031250000, -0.0028076171875000, -0.0015258789062500, +-0.0037536621093750, -0.0033569335937500, -0.0031127929687500, -0.0014343261718750, +-0.0037841796875000, -0.0026855468750000, -0.0037841796875000, -0.0020446777343750, +-0.0034790039062500, -0.0015563964843750, -0.0036010742187500, -0.0019226074218750, +-0.0033874511718750, -0.0007934570312500, -0.0029296875000000, -0.0014343261718750, +-0.0031738281250000, -0.0008850097656250, -0.0025939941406250, -0.0009765625000000, +-0.0019836425781250, -0.0017089843750000, -0.0024414062500000, -0.0012207031250000, +-0.0011596679687500, -0.0024414062500000, -0.0014648437500000, -0.0023803710937500, +-0.0011596679687500, -0.0028381347656250, -0.0003051757812500, -0.0038757324218750, +-0.0008850097656250, -0.0036010742187500, 0.0006713867187500, -0.0045166015625000, +0.0002441406250000, -0.0049133300781250, 0.0005187988281250, -0.0047912597656250, +0.0019226074218750, -0.0051879882812500, 0.0011901855468750, -0.0056457519531250, +0.0012817382812500, -0.0047912597656250, 0.0017700195312500, -0.0055847167968750, +0.0011291503906250, -0.0051574707031250, 0.0003051757812500, -0.0043029785156250, +0.0009155273437500, -0.0056457519531250, 0.0000610351562500, -0.0039367675781250, +-0.0002441406250000, -0.0042114257812500, 0.0003356933593750, -0.0040893554687500, +0.0003967285156250, -0.0029907226562500, 0.0000000000000000, -0.0033569335937500, +0.0015869140625000, -0.0023193359375000, 0.0013122558593750, -0.0025634765625000, +0.0016479492187500, -0.0023193359375000, 0.0027770996093750, -0.0015869140625000, +0.0021972656250000, -0.0020751953125000, 0.0028686523437500, -0.0012817382812500, +0.0030822753906250, -0.0013427734375000, 0.0028381347656250, -0.0013732910156250, +0.0030212402343750, -0.0011901855468750, 0.0031127929687500, -0.0015869140625000, +0.0025939941406250, -0.0011596679687500, 0.0026855468750000, -0.0018005371093750, +0.0024108886718750, -0.0016784667968750, 0.0019531250000000, -0.0014343261718750, +0.0021057128906250, -0.0025939941406250, 0.0012512207031250, -0.0014038085937500, +0.0013122558593750, -0.0022583007812500, 0.0010375976562500, -0.0023803710937500, +0.0004577636718750, -0.0016784667968750, 0.0006103515625000, -0.0031127929687500, +-0.0001831054687500, -0.0020141601562500, 0.0000305175781250, -0.0026855468750000, +-0.0005187988281250, -0.0033264160156250, -0.0013427734375000, -0.0027160644531250, +-0.0007629394531250, -0.0033874511718750, -0.0020751953125000, -0.0038146972656250, +-0.0021057128906250, -0.0034179687500000, -0.0018310546875000, -0.0039978027343750, +-0.0022277832031250, -0.0044555664062500, -0.0021667480468750, -0.0035705566406250, +-0.0016174316406250, -0.0048522949218750, -0.0016479492187500, -0.0043334960937500, +-0.0014648437500000, -0.0041198730468750, -0.0011596679687500, -0.0048522949218750, +-0.0012512207031250, -0.0040283203125000, -0.0006103515625000, -0.0034484863281250, +-0.0008544921875000, -0.0038146972656250, -0.0004577636718750, -0.0023498535156250, +0.0003051757812500, -0.0010986328125000, -0.0002136230468750, -0.0020446777343750, +0.0004272460937500, 0.0006103515625000, 0.0005187988281250, 0.0003967285156250, +0.0002136230468750, 0.0003662109375000, 0.0002441406250000, 0.0020141601562500, +0.0001831054687500, 0.0015869140625000, -0.0003356933593750, 0.0007019042968750, +-0.0001831054687500, 0.0017089843750000, -0.0008239746093750, 0.0002746582031250, +-0.0015258789062500, -0.0015869140625000, -0.0010375976562500, -0.0002136230468750, +-0.0025939941406250, -0.0037231445312500, -0.0026245117187500, -0.0037536621093750, +-0.0023193359375000, -0.0042724609375000, -0.0029602050781250, -0.0065002441406250, +-0.0029296875000000, -0.0057983398437500, -0.0018310546875000, -0.0067138671875000, +-0.0020446777343750, -0.0071716308593750, -0.0017089843750000, -0.0062255859375000, +-0.0008239746093750, -0.0057067871093750, -0.0011596679687500, -0.0060119628906250, +-0.0003662109375000, -0.0042114257812500, -0.0007019042968750, -0.0033874511718750, +-0.0000915527343750, -0.0034179687500000, 0.0007934570312500, -0.0028686523437500, +0.0000305175781250, -0.0025024414062500, 0.0021972656250000, -0.0032653808593750, +0.0022888183593750, -0.0035095214843750, 0.0016479492187500, -0.0027465820312500, +0.0025939941406250, -0.0026550292968750, 0.0027770996093750, -0.0029296875000000, +0.0005798339843750, -0.0003356933593750, 0.0011596679687500, -0.0008544921875000, +0.0002441406250000, -0.0004272460937500, -0.0017700195312500, 0.0016174316406250, +-0.0008239746093750, 0.0006713867187500, -0.0023193359375000, 0.0002746582031250, +-0.0028076171875000, 0.0017089843750000, -0.0021057128906250, 0.0000610351562500, +-0.0022583007812500, -0.0017395019531250, -0.0027465820312500, -0.0000305175781250, +-0.0019226074218750, -0.0047302246093750, -0.0012817382812500, -0.0046386718750000, +-0.0027770996093750, -0.0043945312500000, -0.0039978027343750, -0.0070800781250000, +-0.0028381347656250, -0.0064086914062500, -0.0045166015625000, -0.0047607421875000, +-0.0050659179687500, -0.0059509277343750, -0.0044860839843750, -0.0039367675781250, +-0.0045776367187500, -0.0010986328125000, -0.0047302246093750, -0.0030517578125000, +-0.0033569335937500, 0.0001220703125000, -0.0033874511718750, 0.0010986328125000, +-0.0036926269531250, -0.0005798339843750, -0.0031433105468750, -0.0004577636718750, +-0.0030212402343750, 0.0004272460937500, -0.0039062500000000, -0.0030212402343750, +-0.0040588378906250, -0.0029907226562500, -0.0037536621093750, -0.0021667480468750, +-0.0038757324218750, -0.0037231445312500, -0.0046691894531250, -0.0006408691406250, +-0.0045471191406250, -0.0045471191406250, -0.0051574707031250, -0.0048828125000000, +-0.0042419433593750, -0.0032653808593750, -0.0038757324218750, -0.0029296875000000, +-0.0046691894531250, -0.0041198730468750, -0.0007629394531250, -0.0014953613281250, +-0.0013732910156250, -0.0008850097656250, -0.0010070800781250, -0.0021972656250000, +0.0019836425781250, -0.0021362304687500, 0.0012207031250000, -0.0015563964843750, +0.0004272460937500, -0.0039672851562500, 0.0019836425781250, -0.0043640136718750, +0.0002136230468750, -0.0036315917968750, -0.0022888183593750, -0.0042114257812500, +-0.0003662109375000, -0.0046081542968750, -0.0029907226562500, -0.0022888183593750, +-0.0038452148437500, -0.0027465820312500, -0.0022888183593750, -0.0021667480468750, +-0.0021972656250000, -0.0002746582031250, -0.0029907226562500, -0.0010681152343750, +0.0000000000000000, -0.0008850097656250, 0.0000610351562500, -0.0005798339843750, +-0.0003356933593750, -0.0003356933593750, 0.0010375976562500, -0.0005187988281250, +0.0010375976562500, -0.0010070800781250, -0.0008850097656250, 0.0011596679687500, +-0.0000305175781250, 0.0009765625000000, -0.0006103515625000, 0.0009155273437500, +-0.0025939941406250, 0.0021972656250000, -0.0014648437500000, 0.0020141601562500, +-0.0017089843750000, 0.0011596679687500, -0.0022277832031250, 0.0013122558593750, +-0.0015258789062500, 0.0013732910156250, -0.0004882812500000, 0.0008850097656250, +-0.0008544921875000}, +{-0.0008544921875000, 0.0016174316406250, -0.0018310546875000, 0.0015258789062500, +-0.0007629394531250, -0.0007934570312500, -0.0007019042968750, -0.0002441406250000, +-0.0007324218750000, -0.0018615722656250, -0.0003662109375000, -0.0045166015625000, +-0.0006408691406250, -0.0032958984375000, 0.0004882812500000, -0.0060729980468750, +0.0003051757812500, -0.0064392089843750, 0.0003356933593750, -0.0058288574218750, +0.0012817382812500, -0.0064392089843750, 0.0010375976562500, -0.0060119628906250, +0.0001220703125000, -0.0043945312500000, 0.0004882812500000, -0.0046691894531250, +0.0000915527343750, -0.0039062500000000, -0.0011901855468750, -0.0024108886718750, +-0.0009155273437500, -0.0029602050781250, -0.0004272460937500, -0.0015869140625000, +-0.0009460449218750, -0.0010986328125000, -0.0006103515625000, -0.0007934570312500, +0.0001831054687500, -0.0002441406250000, -0.0003051757812500, -0.0003356933593750, +-0.0000915527343750, -0.0000610351562500, 0.0003051757812500, 0.0000610351562500, +-0.0004272460937500, -0.0000610351562500, -0.0008239746093750, 0.0000915527343750, +-0.0003356933593750, 0.0001831054687500, -0.0031127929687500, -0.0013122558593750, +-0.0029602050781250, -0.0004577636718750, -0.0024719238281250, -0.0015563964843750, +-0.0038757324218750, -0.0034179687500000, -0.0040588378906250, -0.0021667480468750, +-0.0027770996093750, -0.0045471191406250, -0.0028991699218750, -0.0045776367187500, +-0.0029602050781250, -0.0045166015625000, -0.0022888183593750, -0.0058593750000000, +-0.0025634765625000, -0.0053100585937500, -0.0031433105468750, -0.0041503906250000, +-0.0028381347656250, -0.0052490234375000, -0.0032653808593750, -0.0036010742187500, +-0.0042724609375000, -0.0010681152343750, -0.0039672851562500, -0.0026550292968750, +-0.0043029785156250, -0.0004882812500000, -0.0045471191406250, 0.0005493164062500, +-0.0046081542968750, -0.0011596679687500, -0.0047302246093750, -0.0028381347656250, +-0.0048217773437500, -0.0037231445312500, -0.0012512207031250, -0.0022277832031250, +-0.0027160644531250, -0.0012512207031250, -0.0014953613281250, -0.0025634765625000, +0.0011291503906250, -0.0039367675781250, 0.0000610351562500, -0.0029602050781250, +-0.0007324218750000, -0.0038452148437500, 0.0008850097656250, -0.0048522949218750, +-0.0004272460937500, -0.0034179687500000, -0.0028686523437500, -0.0022888183593750, +-0.0014648437500000, -0.0034790039062500, -0.0029602050781250, -0.0013427734375000, +-0.0036621093750000, -0.0007934570312500, -0.0022888183593750, -0.0018920898437500, +-0.0017700195312500, -0.0018615722656250, -0.0026245117187500, -0.0013427734375000, +-0.0007019042968750, -0.0030212402343750, -0.0003051757812500, -0.0032958984375000, +-0.0010375976562500, -0.0024108886718750, -0.0006408691406250, -0.0027465820312500, +-0.0000610351562500, -0.0032653808593750, -0.0011901855468750, 0.0002746582031250, +-0.0014343261718750, -0.0001831054687500, -0.0007324218750000, -0.0001525878906250, +-0.0006713867187500, 0.0019531250000000, -0.0009460449218750, 0.0014953613281250, +0.0001525878906250, 0.0013427734375000, 0.0004272460937500, 0.0012817382812500, +-0.0001831054687500, 0.0015258789062500, 0.0000915527343750, 0.0016784667968750, +0.0004882812500000, 0.0013732910156250, -0.0025024414062500, 0.0022277832031250, +-0.0016784667968750, 0.0024108886718750, -0.0029602050781250, 0.0020751953125000, +-0.0060729980468750, 0.0022277832031250, -0.0044860839843750, 0.0023193359375000, +-0.0058288574218750, 0.0014648437500000, -0.0072631835937500, 0.0016479492187500, +-0.0054931640625000, 0.0014343261718750, -0.0045166015625000, 0.0007019042968750, +-0.0059204101562500, 0.0009765625000000, -0.0015869140625000, 0.0008239746093750, +-0.0026855468750000, 0.0006408691406250, -0.0013732910156250, 0.0009460449218750, +0.0022277832031250, 0.0011901855468750, -0.0001220703125000, 0.0010681152343750, +0.0026550292968750, 0.0014343261718750, 0.0032653808593750, 0.0013122558593750, +0.0021362304687500, 0.0015258789062500, 0.0022888183593750, 0.0019226074218750, +0.0023498535156250, 0.0016479492187500, 0.0008239746093750, 0.0016784667968750, +0.0005187988281250, 0.0020141601562500, 0.0005187988281250, 0.0013427734375000, +-0.0002136230468750, 0.0007019042968750, -0.0004272460937500, 0.0011596679687500, +0.0000305175781250, -0.0003051757812500, -0.0005187988281250, -0.0003967285156250, +-0.0001525878906250, -0.0004577636718750, 0.0003662109375000, -0.0012207031250000, +-0.0002441406250000, -0.0010070800781250, 0.0013732910156250, -0.0012512207031250, +0.0010375976562500, -0.0013122558593750, 0.0012512207031250, -0.0013732910156250, +0.0025024414062500, -0.0015563964843750, 0.0018920898437500, -0.0014343261718750, +0.0019836425781250, -0.0016174316406250, 0.0023498535156250, -0.0016784667968750, +0.0017089843750000, -0.0015563964843750, 0.0012817382812500, -0.0015258789062500, +0.0017395019531250, -0.0015563964843750, -0.0000610351562500, -0.0014038085937500, +0.0005798339843750, -0.0014343261718750, -0.0002136230468750, -0.0013732910156250, +-0.0017700195312500, -0.0013122558593750, -0.0005187988281250, -0.0013427734375000, +-0.0028991699218750, -0.0010375976562500, -0.0024414062500000, -0.0010681152343750, +-0.0028076171875000, -0.0010375976562500, -0.0043334960937500, -0.0007934570312500, +-0.0030822753906250, -0.0008544921875000, -0.0048522949218750, -0.0006713867187500, +-0.0044860839843750, -0.0007019042968750, -0.0044860839843750, -0.0004577636718750, +-0.0054626464843750, -0.0001831054687500, -0.0047302246093750, -0.0002746582031250, +-0.0053100585937500, 0.0003967285156250, -0.0051269531250000, 0.0003356933593750, +-0.0050354003906250, 0.0004882812500000, -0.0052795410156250, 0.0008850097656250, +-0.0049133300781250, 0.0008239746093750, -0.0049743652343750, 0.0010986328125000, +-0.0048828125000000, 0.0010375976562500, -0.0046691894531250, 0.0012512207031250, +-0.0045776367187500, 0.0016174316406250, -0.0044555664062500, 0.0014038085937500, +-0.0044860839843750, 0.0018005371093750, -0.0043029785156250, 0.0020141601562500, +-0.0041809082031250, 0.0018920898437500, -0.0041503906250000, 0.0019836425781250, +-0.0039978027343750, 0.0021667480468750, -0.0039062500000000, 0.0017700195312500, +-0.0037231445312500, 0.0019226074218750, -0.0037536621093750, 0.0018615722656250, +-0.0038146972656250, 0.0016784667968750, -0.0035095214843750, 0.0018310546875000, +-0.0039672851562500, 0.0015869140625000, -0.0038452148437500, 0.0017089843750000, +-0.0038146972656250, 0.0014953613281250, -0.0040588378906250, 0.0011901855468750, +-0.0039367675781250, 0.0014648437500000, -0.0042419433593750, 0.0009460449218750, +-0.0040588378906250, 0.0009155273437500, -0.0041198730468750, 0.0009460449218750, +-0.0043334960937500, 0.0008239746093750, -0.0041503906250000, 0.0009155273437500, +-0.0043029785156250, 0.0000610351562500, -0.0042419433593750, 0.0004882812500000, +-0.0042419433593750, 0.0000000000000000, -0.0043029785156250, -0.0009155273437500, +-0.0042419433593750, -0.0003051757812500, -0.0043334960937500, -0.0017700195312500, +-0.0045166015625000, -0.0014648437500000, -0.0046386718750000, -0.0018615722656250, +-0.0047912597656250, -0.0031127929687500, -0.0050964355468750, -0.0024719238281250, +-0.0051574707031250, -0.0029602050781250, -0.0055236816406250, -0.0032653808593750, +-0.0056762695312500, -0.0029602050781250, -0.0057983398437500, -0.0028381347656250, +-0.0062866210937500, -0.0029296875000000, -0.0058898925781250, -0.0024719238281250, +-0.0062866210937500, -0.0024719238281250, -0.0060729980468750, -0.0025024414062500, +-0.0057983398437500, -0.0023498535156250, -0.0061645507812500, -0.0022888183593750, +-0.0041198730468750, -0.0020446777343750, -0.0048522949218750, -0.0020751953125000, +-0.0034179687500000, -0.0018920898437500, -0.0012207031250000, -0.0015869140625000, +-0.0027160644531250, -0.0017700195312500, 0.0007019042968750, -0.0017700195312500, +0.0004272460937500, -0.0014953613281250, 0.0002746582031250, -0.0019226074218750, +0.0021667480468750, -0.0022888183593750, 0.0014038085937500, -0.0019836425781250, +0.0011596679687500, -0.0027160644531250, 0.0017395019531250, -0.0027465820312500, +0.0009765625000000, -0.0026855468750000, 0.0000915527343750, -0.0028076171875000, +0.0007019042968750, -0.0027160644531250, -0.0005187988281250, -0.0034484863281250, +-0.0007629394531250, -0.0034790039062500, -0.0005493164062500, -0.0027465820312500, +-0.0007934570312500, -0.0028991699218750, -0.0006103515625000, -0.0034790039062500, +-0.0003967285156250, -0.0011901855468750, 0.0002441406250000, -0.0014038085937500, +-0.0004272460937500, -0.0010986328125000, -0.0010986328125000, 0.0003662109375000, +-0.0003051757812500, -0.0001525878906250, -0.0026550292968750, 0.0007629394531250, +-0.0027465820312500, 0.0009155273437500, -0.0029602050781250, 0.0009155273437500, +-0.0044250488281250, 0.0014343261718750, -0.0038757324218750, 0.0013122558593750, +-0.0030822753906250, 0.0007324218750000, -0.0037536621093750, 0.0012512207031250, +-0.0030212402343750, 0.0004272460937500, -0.0014343261718750, -0.0007019042968750, +-0.0020446777343750, 0.0002136230468750, -0.0021057128906250, -0.0009765625000000, +-0.0015563964843750, -0.0012207031250000, -0.0020751953125000, -0.0007629394531250, +-0.0029296875000000, -0.0011901855468750, -0.0026855468750000, -0.0015258789062500, +-0.0025634765625000, 0.0003356933593750, -0.0029907226562500, 0.0000915527343750, +-0.0022583007812500, -0.0003662109375000, -0.0012512207031250, 0.0002441406250000, +-0.0014038085937500, 0.0001220703125000, 0.0001831054687500, 0.0001525878906250, +-0.0002746582031250, 0.0000915527343750, -0.0003967285156250, -0.0000915527343750, +0.0006103515625000, -0.0003356933593750, 0.0001831054687500, -0.0006713867187500, +-0.0002136230468750, -0.0009765625000000, 0.0002441406250000, -0.0009765625000000, +-0.0004882812500000, -0.0014038085937500, -0.0014343261718750, -0.0018615722656250, +-0.0008544921875000, -0.0015563964843750, -0.0023193359375000, -0.0019836425781250, +-0.0023803710937500, -0.0022583007812500, -0.0021057128906250, -0.0021362304687500, +-0.0028686523437500, -0.0021972656250000, -0.0028076171875000, -0.0025329589843750, +-0.0018615722656250, -0.0021057128906250, -0.0019226074218750, -0.0025939941406250, +-0.0016784667968750, -0.0024719238281250, -0.0008850097656250, -0.0019226074218750, +-0.0010070800781250, -0.0024719238281250, -0.0008544921875000, -0.0021362304687500, +-0.0007629394531250, -0.0017395019531250, -0.0004577636718750, -0.0015563964843750, +-0.0002136230468750, -0.0012207031250000, -0.0004882812500000, -0.0005798339843750, +0.0001220703125000, -0.0005493164062500, 0.0003662109375000, -0.0001220703125000, +-0.0000915527343750, 0.0003967285156250, 0.0000915527343750, 0.0007324218750000, +0.0006103515625000, 0.0008544921875000, -0.0007934570312500, 0.0004882812500000, +-0.0003662109375000, 0.0010681152343750, -0.0007629394531250, 0.0007324218750000, +-0.0020751953125000, 0.0002746582031250, -0.0010986328125000, 0.0011901855468750, +-0.0012512207031250, 0.0001525878906250, -0.0017700195312500, 0.0009155273437500, +-0.0013732910156250, 0.0010070800781250, -0.0007324218750000, 0.0004882812500000, +-0.0009460449218750, 0.0015258789062500, -0.0008239746093750, 0.0004577636718750, +-0.0006103515625000, 0.0015258789062500, -0.0012207031250000, 0.0008239746093750, +-0.0017700195312500, -0.0005493164062500, -0.0014038085937500, 0.0009460449218750, +-0.0021362304687500, -0.0021667480468750, -0.0025634765625000, -0.0020446777343750, +-0.0023193359375000, -0.0025634765625000, -0.0023803710937500, -0.0049133300781250, +-0.0027465820312500, -0.0042114257812500, -0.0018920898437500, -0.0047607421875000, +-0.0023193359375000}, +{-0.0005187988281250, -0.0019226074218750, -0.0001525878906250, -0.0027770996093750, +-0.0006408691406250, -0.0019226074218750, -0.0010375976562500, 0.0002136230468750, +-0.0008544921875000, -0.0006408691406250, -0.0011901855468750, 0.0004882812500000, +-0.0011596679687500, 0.0009155273437500, -0.0009765625000000, 0.0007324218750000, +-0.0006408691406250, 0.0010986328125000, -0.0002136230468750, 0.0010070800781250, +-0.0011596679687500, 0.0007629394531250, -0.0007629394531250, 0.0010375976562500, +-0.0014343261718750, 0.0004272460937500, -0.0026550292968750, -0.0001525878906250, +-0.0020446777343750, 0.0003051757812500, -0.0039672851562500, -0.0015563964843750, +-0.0040893554687500, -0.0015258789062500, -0.0036926269531250, -0.0011291503906250, +-0.0043640136718750, -0.0020141601562500, -0.0043945312500000, -0.0019836425781250, +-0.0029907226562500, -0.0007019042968750, -0.0031127929687500, -0.0013427734375000, +-0.0031127929687500, -0.0003967285156250, -0.0022888183593750, 0.0014038085937500, +-0.0025024414062500, 0.0003662109375000, -0.0028076171875000, 0.0004272460937500, +-0.0027465820312500, 0.0012207031250000, -0.0027465820312500, 0.0007629394531250, +-0.0031738281250000, 0.0000000000000000, -0.0030517578125000, 0.0003051757812500, +-0.0011291503906250, -0.0005798339843750, -0.0023193359375000, -0.0004272460937500, +-0.0014343261718750, -0.0006408691406250, 0.0007019042968750, -0.0014038085937500, +-0.0008544921875000, -0.0010375976562500, 0.0010986328125000, -0.0015563964843750, +0.0014038085937500, -0.0018615722656250, 0.0005798339843750, -0.0013427734375000, +0.0008544921875000, -0.0010375976562500, 0.0009765625000000, -0.0017395019531250, +0.0000610351562500, -0.0011901855468750, 0.0000610351562500, -0.0011596679687500, +-0.0004882812500000, -0.0019226074218750, -0.0010681152343750, -0.0023803710937500, +-0.0005798339843750, -0.0022583007812500, -0.0020751953125000, -0.0028076171875000, +-0.0018310546875000, -0.0030212402343750, -0.0021362304687500, -0.0026245117187500, +-0.0032958984375000, -0.0023803710937500, -0.0024719238281250, -0.0021667480468750, +-0.0025939941406250, -0.0007324218750000, -0.0030517578125000, -0.0003967285156250, +-0.0022583007812500, -0.0001831054687500, -0.0014953613281250, 0.0006103515625000, +-0.0019836425781250, 0.0007019042968750, -0.0006713867187500, 0.0003356933593750, +-0.0006103515625000, 0.0004272460937500, -0.0004882812500000, 0.0002441406250000, +0.0002136230468750, -0.0000610351562500, 0.0000000000000000, 0.0003662109375000, +0.0001220703125000, 0.0002136230468750, 0.0003662109375000, 0.0005187988281250, +0.0001831054687500, 0.0006408691406250, 0.0000915527343750, 0.0009155273437500, +0.0002441406250000, 0.0015258789062500, -0.0010681152343750, 0.0003051757812500, +-0.0009155273437500, 0.0011291503906250, -0.0007629394531250, 0.0002746582031250, +-0.0015563964843750, -0.0011596679687500, -0.0016479492187500, 0.0000915527343750, +-0.0014343261718750, -0.0028991699218750, -0.0016479492187500, -0.0028991699218750, +-0.0016174316406250, -0.0030822753906250, -0.0014343261718750, -0.0050964355468750, +-0.0018005371093750, -0.0049438476562500, -0.0018615722656250, -0.0046997070312500, +-0.0019531250000000, -0.0058593750000000, -0.0019226074218750, -0.0052185058593750, +-0.0020141601562500, -0.0042114257812500, -0.0023803710937500, -0.0056457519531250, +-0.0015258789062500, -0.0037536621093750, -0.0021057128906250, -0.0042724609375000, +-0.0015258789062500, -0.0044250488281250, -0.0004577636718750, -0.0035095214843750, +-0.0014953613281250, -0.0044250488281250, 0.0000305175781250, -0.0036010742187500, +-0.0000915527343750, -0.0041198730468750, -0.0003356933593750, -0.0038146972656250, +0.0002746582031250, -0.0030822753906250, -0.0001831054687500, -0.0040893554687500, +-0.0000305175781250, -0.0028686523437500, -0.0002136230468750, -0.0032958984375000, +-0.0003356933593750, -0.0030517578125000, -0.0002746582031250, -0.0021972656250000, +-0.0004882812500000, -0.0030517578125000, -0.0007629394531250, -0.0019531250000000, +-0.0007324218750000, -0.0022888183593750, -0.0009460449218750, -0.0019836425781250, +-0.0012512207031250, -0.0012817382812500, -0.0012207031250000, -0.0021362304687500, +-0.0010986328125000, -0.0011596679687500, -0.0014648437500000, -0.0012512207031250, +-0.0010986328125000, -0.0015258789062500, -0.0006713867187500, -0.0009765625000000, +-0.0011596679687500, -0.0008850097656250, -0.0003967285156250, -0.0017089843750000, +-0.0002441406250000, -0.0014648437500000, -0.0006103515625000, -0.0018005371093750, +-0.0004577636718750, -0.0025329589843750, -0.0002746582031250, -0.0021057128906250, +-0.0010070800781250, -0.0027465820312500, -0.0008850097656250, -0.0033569335937500, +-0.0010070800781250, -0.0031433105468750, -0.0015869140625000, -0.0031738281250000, +-0.0012207031250000, -0.0038452148437500, -0.0014343261718750, -0.0032348632812500, +-0.0016479492187500, -0.0037231445312500, -0.0013427734375000, -0.0038452148437500, +-0.0010986328125000, -0.0034790039062500, -0.0013122558593750, -0.0040893554687500, +-0.0008239746093750, -0.0036010742187500, -0.0008239746093750, -0.0036010742187500, +-0.0008239746093750, -0.0036010742187500, -0.0005187988281250, -0.0032348632812500, +-0.0006408691406250, -0.0033264160156250, -0.0004882812500000, -0.0031433105468750, +-0.0005187988281250, -0.0028076171875000, -0.0004577636718750, -0.0026245117187500, +-0.0003967285156250, -0.0024414062500000, -0.0004577636718750, -0.0020141601562500, +-0.0003356933593750, -0.0016174316406250, -0.0003356933593750, -0.0014648437500000, +-0.0004272460937500, -0.0007324218750000, -0.0003662109375000, -0.0002746582031250, +-0.0004577636718750, -0.0005493164062500, -0.0007629394531250, 0.0006713867187500, +-0.0007629394531250, 0.0004882812500000, -0.0010070800781250, 0.0007934570312500, +-0.0012817382812500, 0.0015563964843750, -0.0011291503906250, 0.0008239746093750, +-0.0021362304687500, 0.0014343261718750, -0.0018920898437500, 0.0011596679687500, +-0.0021667480468750, 0.0007934570312500, -0.0029296875000000, 0.0009460449218750, +-0.0024719238281250, 0.0005187988281250, -0.0032043457031250, 0.0004577636718750, +-0.0031127929687500, 0.0002441406250000, -0.0031738281250000, 0.0000915527343750, +-0.0036315917968750, 0.0001220703125000, -0.0032348632812500, -0.0001220703125000, +-0.0031127929687500, -0.0001525878906250, -0.0034179687500000, -0.0001831054687500, +-0.0025634765625000, -0.0001220703125000, -0.0018310546875000, -0.0000305175781250, +-0.0023803710937500, 0.0000610351562500, -0.0003967285156250, 0.0003051757812500, +-0.0004882812500000, 0.0004882812500000, -0.0003356933593750, 0.0006713867187500, +0.0009155273437500, 0.0009155273437500, 0.0006103515625000, 0.0009155273437500, +0.0005798339843750, 0.0005798339843750, 0.0008544921875000, 0.0010375976562500, +0.0007324218750000, 0.0001525878906250, 0.0005493164062500, -0.0007629394531250, +0.0006713867187500, 0.0000305175781250, 0.0006103515625000, -0.0019226074218750, +0.0006103515625000, -0.0018005371093750, 0.0004882812500000, -0.0017395019531250, +0.0003356933593750, -0.0028991699218750, 0.0004577636718750, -0.0025329589843750, +0.0005493164062500, -0.0021057128906250, 0.0002136230468750, -0.0027770996093750, +0.0007629394531250, -0.0020446777343750, 0.0013732910156250, -0.0010070800781250, +0.0008850097656250, -0.0020141601562500, 0.0016174316406250, -0.0017089843750000, +0.0019836425781250, -0.0008239746093750, 0.0013732910156250, -0.0021362304687500, +0.0010070800781250, -0.0031127929687500, 0.0013427734375000, -0.0017395019531250, +0.0008544921875000, -0.0043640136718750, 0.0004882812500000, -0.0043945312500000, +0.0008239746093750, -0.0041503906250000, 0.0011596679687500, -0.0054321289062500, +0.0007934570312500, -0.0049133300781250, 0.0005798339843750, -0.0041809082031250, +0.0009460449218750, -0.0048522949218750, 0.0001525878906250, -0.0036315917968750, +-0.0007324218750000, -0.0021057128906250, -0.0001525878906250, -0.0030822753906250, +-0.0018310546875000, -0.0005187988281250, -0.0014648437500000, -0.0007019042968750, +-0.0017395019531250, -0.0003051757812500, -0.0030822753906250, 0.0016784667968750, +-0.0025024414062500, 0.0010070800781250, -0.0031127929687500, 0.0003662109375000, +-0.0028686523437500, 0.0017700195312500, -0.0034179687500000, 0.0000610351562500, +-0.0041809082031250, -0.0022583007812500, -0.0034179687500000, -0.0005798339843750, +-0.0047912597656250, -0.0025939941406250, -0.0051879882812500, -0.0031738281250000, +-0.0041198730468750, -0.0025634765625000, -0.0040588378906250, -0.0027465820312500, +-0.0046691894531250, -0.0028991699218750, -0.0019836425781250, -0.0035705566406250, +-0.0022277832031250, -0.0030212402343750, -0.0023498535156250, -0.0037841796875000, +-0.0001831054687500, -0.0058898925781250, -0.0029602050781250, -0.0021057128906250, +-0.0036621093750000, -0.0032958984375000, -0.0039367675781250, -0.0019226074218750, +-0.0027160644531250, -0.0034790039062500, -0.0020141601562500, -0.0056762695312500, +-0.0027770996093750, -0.0045166015625000, -0.0010986328125000, -0.0050964355468750, +-0.0004272460937500, -0.0061340332031250, -0.0011901855468750, -0.0046997070312500, +-0.0013427734375000, -0.0032653808593750, -0.0007934570312500, -0.0043334960937500, +-0.0017700195312500, -0.0030212402343750, -0.0019836425781250, -0.0021972656250000, +-0.0008239746093750, -0.0031433105468750, -0.0005187988281250, -0.0039367675781250, +-0.0010986328125000, -0.0033264160156250, 0.0014648437500000, -0.0038452148437500, +0.0015563964843750, -0.0048522949218750, 0.0007019042968750, -0.0036010742187500, +0.0018310546875000, -0.0024414062500000, 0.0018920898437500, -0.0035705566406250, +-0.0020141601562500, -0.0013122558593750, -0.0010986328125000, -0.0008239746093750, +-0.0020751953125000, -0.0014343261718750, -0.0057067871093750, -0.0011596679687500, +-0.0046081542968750, -0.0008544921875000, -0.0043640136718750, -0.0005798339843750, +-0.0060424804687500, -0.0011291503906250, -0.0044555664062500, -0.0003662109375000, +-0.0022277832031250, 0.0007019042968750, -0.0037536621093750, 0.0001525878906250, +-0.0009460449218750, 0.0012512207031250, -0.0001525878906250, 0.0015258789062500, +-0.0013427734375000, 0.0010375976562500, -0.0009155273437500, 0.0011596679687500, +0.0000000000000000, 0.0014343261718750, -0.0024719238281250, 0.0006103515625000, +-0.0020751953125000, 0.0003967285156250, -0.0018310546875000, 0.0009765625000000, +-0.0029296875000000, 0.0009460449218750, -0.0021972656250000, 0.0005493164062500, +-0.0019226074218750, 0.0020141601562500, -0.0020446777343750, 0.0022277832031250, +-0.0009765625000000, 0.0016479492187500, 0.0000305175781250, 0.0018920898437500, +-0.0003051757812500, 0.0021667480468750, 0.0012817382812500, 0.0008544921875000, +0.0020751953125000, 0.0008239746093750, 0.0013122558593750, 0.0010375976562500, +0.0017089843750000, 0.0006713867187500, 0.0028381347656250, 0.0006713867187500, +-0.0000915527343750, 0.0009155273437500, 0.0013427734375000, 0.0010681152343750, +0.0004882812500000, 0.0007934570312500, -0.0018920898437500, 0.0005493164062500, +0.0003967285156250, 0.0007324218750000, -0.0032348632812500, 0.0005798339843750, +-0.0020751953125000, 0.0003662109375000, -0.0024414062500000, 0.0004882812500000, +-0.0048522949218750, 0.0007324218750000, -0.0025939941406250, 0.0005798339843750, +-0.0045166015625000, 0.0000610351562500, -0.0041809082031250, 0.0004272460937500, +-0.0032958984375000, -0.0000915527343750, -0.0036315917968750, -0.0010070800781250, +-0.0028381347656250, -0.0004882812500000, -0.0027465820312500, -0.0012207031250000, +-0.0021362304687500, -0.0014648437500000, -0.0019836425781250, -0.0013122558593750, +-0.0019531250000000}, +{-0.0031127929687500, -0.0007019042968750, -0.0041503906250000, 0.0014343261718750, +-0.0039672851562500, 0.0008544921875000, -0.0024108886718750, -0.0003967285156250, +-0.0030212402343750, 0.0007019042968750, -0.0025939941406250, -0.0003051757812500, +-0.0009765625000000, -0.0024108886718750, -0.0015869140625000, -0.0012512207031250, +-0.0021972656250000, -0.0021667480468750, -0.0016479492187500, -0.0027770996093750, +-0.0021667480468750, -0.0022277832031250, -0.0038452148437500, -0.0015563964843750, +-0.0025024414062500, -0.0018615722656250, -0.0015869140625000, -0.0014038085937500, +-0.0014343261718750, -0.0022277832031250, -0.0017395019531250, -0.0018310546875000, +-0.0016479492187500, -0.0004882812500000, -0.0011596679687500, -0.0007934570312500, +-0.0020141601562500, -0.0028686523437500, -0.0024108886718750, -0.0017395019531250, +-0.0014953613281250, -0.0029602050781250, -0.0010681152343750, -0.0057983398437500, +-0.0015563964843750, -0.0044555664062500, 0.0004577636718750, -0.0047912597656250, +0.0005187988281250, -0.0059509277343750, 0.0000000000000000, -0.0046386718750000, +0.0007934570312500, -0.0030517578125000, 0.0007019042968750, -0.0039978027343750, +-0.0008850097656250, -0.0028381347656250, -0.0007629394531250, -0.0023498535156250, +-0.0012817382812500, -0.0030212402343750, -0.0028381347656250, -0.0034484863281250, +-0.0025634765625000, -0.0031433105468750, -0.0021057128906250, -0.0032958984375000, +-0.0028686523437500, -0.0039367675781250, -0.0024414062500000, -0.0031127929687500, +-0.0012207031250000, -0.0020141601562500, -0.0016479492187500, -0.0025634765625000, +-0.0016479492187500, -0.0016174316406250, -0.0005187988281250, -0.0012817382812500, +-0.0015258789062500, -0.0014343261718750, -0.0026550292968750, -0.0013427734375000, +-0.0011901855468750, -0.0012512207031250, -0.0035705566406250, -0.0011596679687500, +-0.0034179687500000, -0.0014038085937500, -0.0025939941406250, -0.0007934570312500, +-0.0034790039062500, -0.0002441406250000, -0.0032958984375000, -0.0007934570312500, +-0.0014038085937500, 0.0002136230468750, -0.0013732910156250, 0.0006103515625000, +-0.0011291503906250, 0.0001831054687500, 0.0000610351562500, 0.0000305175781250, +0.0000305175781250, 0.0003356933593750, -0.0000915527343750, 0.0003051757812500, +0.0007629394531250, -0.0003051757812500, -0.0002136230468750, 0.0004882812500000, +-0.0010070800781250, 0.0016174316406250, 0.0003051757812500, 0.0009155273437500, +-0.0031127929687500, 0.0014343261718750, -0.0022583007812500, 0.0021057128906250, +-0.0025634765625000, 0.0011901855468750, -0.0047302246093750, 0.0004272460937500, +-0.0031433105468750, 0.0010986328125000, -0.0044555664062500, 0.0001220703125000, +-0.0037841796875000, -0.0002136230468750, -0.0037231445312500, 0.0002746582031250, +-0.0043029785156250, 0.0003662109375000, -0.0028381347656250, 0.0001220703125000, +-0.0045776367187500, 0.0005493164062500, -0.0033874511718750, 0.0006103515625000, +-0.0031738281250000, 0.0004272460937500, -0.0041503906250000, 0.0004272460937500, +-0.0026245117187500, 0.0004882812500000, -0.0039978027343750, 0.0005187988281250, +-0.0029296875000000, 0.0003051757812500, -0.0032043457031250, 0.0004272460937500, +-0.0043334960937500, 0.0007324218750000, -0.0027160644531250, 0.0004882812500000, +-0.0046691894531250, 0.0001831054687500, -0.0040283203125000, 0.0004882812500000, +-0.0038146972656250, 0.0001220703125000, -0.0048828125000000, -0.0005187988281250, +-0.0037536621093750, -0.0001525878906250, -0.0043640136718750, -0.0006408691406250, +-0.0044860839843750, -0.0006408691406250, -0.0039062500000000, -0.0006713867187500, +-0.0039062500000000, -0.0009155273437500, -0.0041198730468750, -0.0007324218750000, +-0.0029602050781250, -0.0010681152343750, -0.0035095214843750, -0.0010681152343750, +-0.0028686523437500, -0.0009765625000000, -0.0018005371093750, -0.0011596679687500, +-0.0029296875000000, -0.0010681152343750, -0.0012817382812500, -0.0010375976562500, +-0.0016784667968750, -0.0009765625000000, -0.0016479492187500, -0.0010375976562500, +-0.0006408691406250, -0.0010681152343750, -0.0012207031250000, -0.0010375976562500, +-0.0007019042968750, -0.0010681152343750, -0.0006408691406250, -0.0010681152343750, +-0.0005493164062500, -0.0009765625000000, -0.0002441406250000, -0.0009460449218750, +-0.0005798339843750, -0.0008544921875000, 0.0000000000000000, -0.0006408691406250, +-0.0002136230468750, -0.0007019042968750, -0.0000915527343750, -0.0005187988281250, +0.0003051757812500, -0.0001525878906250, -0.0000610351562500, -0.0003051757812500, +0.0005187988281250, -0.0000610351562500, 0.0002441406250000, 0.0001525878906250, +0.0003051757812500, -0.0001525878906250, 0.0007324218750000, -0.0003051757812500, +0.0001525878906250, 0.0000000000000000, 0.0004882812500000, -0.0007629394531250, +0.0002136230468750, -0.0006713867187500, -0.0001525878906250, -0.0007629394531250, +-0.0001525878906250, -0.0012817382812500, -0.0005187988281250, -0.0010070800781250, +-0.0009460449218750, -0.0014648437500000, -0.0008850097656250, -0.0014038085937500, +-0.0013427734375000, -0.0013732910156250, -0.0018615722656250, -0.0015258789062500, +-0.0016784667968750, -0.0013732910156250, -0.0028686523437500, -0.0012207031250000, +-0.0025329589843750, -0.0012512207031250, -0.0028076171875000, -0.0013122558593750, +-0.0037231445312500, -0.0012207031250000, -0.0031433105468750, -0.0010986328125000, +-0.0039672851562500, -0.0010681152343750, -0.0039062500000000, -0.0012817382812500, +-0.0040588378906250, -0.0009460449218750, -0.0045776367187500, -0.0006103515625000, +-0.0042724609375000, -0.0008544921875000, -0.0049133300781250, -0.0003967285156250, +-0.0046081542968750, -0.0003662109375000, -0.0045471191406250, -0.0002441406250000, +-0.0047912597656250, 0.0000915527343750, -0.0041809082031250, -0.0001525878906250, +-0.0043334960937500, -0.0003967285156250, -0.0041198730468750, 0.0000000000000000, +-0.0038452148437500, -0.0003051757812500, -0.0038452148437500, -0.0008850097656250, +-0.0035400390625000, -0.0005798339843750, -0.0036315917968750, -0.0006408691406250, +-0.0032958984375000, -0.0007324218750000, -0.0035400390625000, -0.0010375976562500, +-0.0037841796875000, -0.0010070800781250, -0.0032348632812500, -0.0008239746093750, +-0.0045166015625000, -0.0024108886718750, -0.0045471191406250, -0.0020141601562500, +-0.0043945312500000, -0.0022888183593750, -0.0052490234375000, -0.0037536621093750, +-0.0054626464843750, -0.0032958984375000, -0.0045776367187500, -0.0027465820312500, +-0.0052490234375000, -0.0033264160156250, -0.0048828125000000, -0.0027465820312500, +-0.0036926269531250, -0.0017089843750000, -0.0041503906250000, -0.0022583007812500, +-0.0032958984375000, -0.0007629394531250, -0.0025329589843750, -0.0008850097656250, +-0.0022277832031250, -0.0007629394531250, -0.0018310546875000, 0.0003662109375000, +-0.0014648437500000, 0.0001220703125000, -0.0018005371093750, -0.0001831054687500, +-0.0013427734375000, 0.0001220703125000, -0.0019226074218750, -0.0003051757812500, +-0.0027160644531250, -0.0007019042968750, -0.0021362304687500, -0.0002746582031250, +-0.0032043457031250, -0.0018005371093750, -0.0033569335937500, -0.0015563964843750, +-0.0029907226562500, -0.0017089843750000, -0.0036010742187500, -0.0027770996093750, +-0.0039672851562500, -0.0023193359375000, -0.0027770996093750, -0.0024719238281250, +-0.0028076171875000, -0.0028686523437500, -0.0025939941406250, -0.0020446777343750, +-0.0017700195312500, -0.0014343261718750, -0.0020751953125000, -0.0020446777343750, +-0.0023193359375000, -0.0001831054687500, -0.0020751953125000, -0.0000915527343750, +-0.0025024414062500, -0.0000305175781250, -0.0032653808593750, 0.0010070800781250, +-0.0028686523437500, 0.0006408691406250, -0.0026550292968750, -0.0001220703125000, +-0.0032043457031250, 0.0004882812500000, -0.0025939941406250, 0.0000610351562500, +-0.0016174316406250, -0.0010070800781250, -0.0020141601562500, -0.0006713867187500, +-0.0014038085937500, -0.0018310546875000, -0.0011291503906250, -0.0016174316406250, +-0.0010986328125000, -0.0012207031250000, -0.0010070800781250, -0.0014038085937500, +-0.0009155273437500, -0.0009155273437500, -0.0001220703125000, -0.0003356933593750, +-0.0004577636718750, -0.0003356933593750, -0.0003662109375000, -0.0004882812500000, +0.0002746582031250, -0.0002441406250000, 0.0000305175781250, -0.0003356933593750, +0.0006103515625000, -0.0021972656250000, 0.0003967285156250, -0.0016174316406250, +0.0009765625000000, -0.0024414062500000, 0.0017700195312500, -0.0043945312500000, +0.0010070800781250, -0.0033874511718750, 0.0021362304687500, -0.0036010742187500, +0.0025939941406250, -0.0040893554687500, 0.0015258789062500, -0.0032348632812500, +0.0011291503906250, -0.0023498535156250, 0.0018005371093750, -0.0025329589843750, +0.0000610351562500, -0.0014953613281250, -0.0001831054687500, -0.0011596679687500, +0.0000000000000000, -0.0015869140625000, -0.0007629394531250, -0.0015563964843750, +-0.0010070800781250, -0.0011596679687500, -0.0004577636718750, -0.0017089843750000, +-0.0002746582031250, -0.0019531250000000, -0.0012817382812500, -0.0016174316406250, +-0.0017700195312500, -0.0010070800781250, -0.0010375976562500, -0.0007629394531250, +-0.0032958984375000, -0.0016784667968750, -0.0035705566406250, -0.0007934570312500, +-0.0027770996093750, -0.0015563964843750, -0.0035095214843750, -0.0029907226562500, +-0.0040283203125000, -0.0018005371093750, -0.0017700195312500, -0.0036315917968750, +-0.0022888183593750, -0.0039062500000000, -0.0020446777343750, -0.0034484863281250, +-0.0004272460937500, -0.0040283203125000, -0.0011901855468750, -0.0042114257812500, +-0.0008850097656250, -0.0037231445312500, -0.0008544921875000, -0.0042724609375000, +-0.0010375976562500, -0.0040588378906250, -0.0010375976562500, -0.0037536621093750, +-0.0010986328125000, -0.0047302246093750, -0.0008239746093750, -0.0041198730468750, +-0.0012512207031250, -0.0047607421875000, -0.0007324218750000, -0.0049438476562500, +0.0001525878906250, -0.0047607421875000, -0.0003051757812500, -0.0056457519531250, +-0.0000305175781250, -0.0044555664062500, 0.0003967285156250, -0.0049743652343750, +-0.0000305175781250, -0.0045471191406250, -0.0002746582031250, -0.0034179687500000, +0.0001831054687500, -0.0041503906250000, -0.0009155273437500, -0.0028991699218750, +-0.0007629394531250, -0.0028991699218750, -0.0006103515625000, -0.0031738281250000, +-0.0011901855468750, -0.0028991699218750, -0.0010986328125000, -0.0032043457031250, +-0.0009460449218750, -0.0035705566406250, -0.0011901855468750, -0.0037231445312500, +-0.0008850097656250, -0.0038757324218750, -0.0005798339843750, -0.0042419433593750, +-0.0010070800781250, -0.0043945312500000, 0.0002746582031250, -0.0036926269531250, +0.0000915527343750, -0.0042419433593750, 0.0003356933593750, -0.0038757324218750, +0.0013427734375000, -0.0031738281250000, 0.0009460449218750, -0.0040283203125000, +0.0011596679687500, -0.0025024414062500, 0.0014343261718750, -0.0026245117187500, +0.0011291503906250, -0.0024108886718750, 0.0009460449218750, -0.0014038085937500, +0.0011596679687500, -0.0017089843750000, 0.0002441406250000, -0.0007629394531250, +0.0004577636718750, -0.0009155273437500, 0.0000000000000000, -0.0006713867187500, +-0.0008239746093750, -0.0001220703125000, -0.0003051757812500, -0.0006713867187500, +-0.0016174316406250, 0.0000915527343750, -0.0017089843750000, 0.0000305175781250, +-0.0014953613281250, 0.0000000000000000, -0.0020751953125000, 0.0000915527343750, +-0.0020751953125000, -0.0006713867187500, -0.0015258789062500, -0.0001220703125000, +-0.0016479492187500, -0.0001831054687500, -0.0015869140625000, -0.0007629394531250, +-0.0012207031250000, -0.0008544921875000, -0.0013122558593750, -0.0009765625000000, +-0.0014038085937500}, +{-0.0006103515625000, -0.0026550292968750, -0.0006103515625000, -0.0038452148437500, +-0.0007629394531250, -0.0041503906250000, -0.0002136230468750, -0.0035095214843750, +0.0002441406250000, -0.0033569335937500, 0.0000610351562500, -0.0034484863281250, +0.0011596679687500, -0.0026245117187500, 0.0010375976562500, -0.0023498535156250, +0.0011901855468750, -0.0022888183593750, 0.0021057128906250, -0.0018310546875000, +0.0019836425781250, -0.0017089843750000, 0.0014343261718750, -0.0022583007812500, +0.0018920898437500, -0.0018920898437500, 0.0014038085937500, -0.0020446777343750, +0.0003662109375000, -0.0028076171875000, 0.0008544921875000, -0.0025329589843750, +0.0002746582031250, -0.0025634765625000, -0.0003662109375000, -0.0021972656250000, +0.0000305175781250, -0.0027160644531250, 0.0004272460937500, -0.0033569335937500, +-0.0001831054687500, -0.0026855468750000, -0.0004272460937500, -0.0034484863281250, +0.0001831054687500, -0.0037536621093750, -0.0010986328125000, -0.0034484863281250, +-0.0025024414062500, -0.0034790039062500, -0.0015258789062500, -0.0036010742187500, +-0.0031738281250000, -0.0030822753906250, -0.0036926269531250, -0.0032958984375000, +-0.0029602050781250, -0.0036621093750000, -0.0030822753906250, -0.0037841796875000, +-0.0035400390625000, -0.0041198730468750, -0.0018310546875000, -0.0044555664062500, +-0.0020141601562500, -0.0049743652343750, -0.0017700195312500, -0.0050964355468750, +-0.0007019042968750, -0.0053405761718750, -0.0011596679687500, -0.0056762695312500, +-0.0008850097656250, -0.0048522949218750, -0.0006713867187500, -0.0053710937500000, +-0.0006103515625000, -0.0048522949218750, -0.0007934570312500, -0.0038146972656250, +-0.0010070800781250, -0.0044860839843750, 0.0001831054687500, -0.0032958984375000, +-0.0000915527343750, -0.0030822753906250, 0.0000305175781250, -0.0032958984375000, +0.0009460449218750, -0.0029296875000000, 0.0004882812500000, -0.0029296875000000, +0.0003662109375000, -0.0031738281250000, 0.0009155273437500, -0.0034484863281250, +0.0003662109375000, -0.0030822753906250, -0.0003662109375000, -0.0029296875000000, +0.0003051757812500, -0.0033264160156250, -0.0005187988281250, -0.0018005371093750, +-0.0006103515625000, -0.0023498535156250, -0.0003662109375000, -0.0017089843750000, +-0.0005798339843750, -0.0003967285156250, -0.0004577636718750, -0.0014953613281250, +-0.0001525878906250, 0.0002136230468750, -0.0002441406250000, -0.0001525878906250, +0.0000915527343750, -0.0000305175781250, 0.0004577636718750, 0.0011596679687500, +0.0002136230468750, 0.0002136230468750, 0.0007324218750000, 0.0003356933593750, +0.0008850097656250, 0.0005187988281250, 0.0006408691406250, 0.0003356933593750, +0.0007324218750000, -0.0001220703125000, 0.0009155273437500, -0.0004577636718750, +0.0002136230468750, -0.0002441406250000, 0.0004272460937500, -0.0011901855468750, +0.0002746582031250, -0.0012207031250000, -0.0002441406250000, -0.0010070800781250, +0.0001220703125000, -0.0021362304687500, -0.0003967285156250, -0.0011291503906250, +-0.0003051757812500, -0.0020141601562500, -0.0004272460937500, -0.0023498535156250, +-0.0007629394531250, -0.0018005371093750, -0.0004882812500000, -0.0028686523437500, +-0.0010070800781250, -0.0025024414062500, -0.0010070800781250, -0.0025024414062500, +-0.0009460449218750, -0.0031127929687500, -0.0011596679687500, -0.0031738281250000, +-0.0010986328125000, -0.0028381347656250, -0.0012207031250000, -0.0034179687500000, +-0.0011291503906250, -0.0028991699218750, -0.0012512207031250, -0.0028686523437500, +-0.0014038085937500, -0.0033264160156250, -0.0012207031250000, -0.0028076171875000, +-0.0014343261718750, -0.0033264160156250, -0.0014648437500000, -0.0034179687500000, +-0.0012207031250000, -0.0033569335937500, -0.0012207031250000, -0.0037536621093750, +-0.0013427734375000, -0.0039672851562500, -0.0005493164062500, -0.0037841796875000, +-0.0007324218750000, -0.0042724609375000, -0.0004577636718750, -0.0043334960937500, +0.0001525878906250, -0.0041809082031250, -0.0000915527343750, -0.0048217773437500, +0.0003662109375000, -0.0044250488281250, 0.0004577636718750, -0.0048828125000000, +0.0004577636718750, -0.0048828125000000, 0.0006408691406250, -0.0046081542968750, +0.0006103515625000, -0.0052795410156250, 0.0005493164062500, -0.0044860839843750, +0.0006103515625000, -0.0046691894531250, 0.0007019042968750, -0.0043029785156250, +0.0006408691406250, -0.0034179687500000, 0.0006408691406250, -0.0036621093750000, +0.0011291503906250, -0.0022583007812500, 0.0010681152343750, -0.0022583007812500, +0.0013122558593750, -0.0016479492187500, 0.0018005371093750, -0.0003967285156250, +0.0016479492187500, -0.0007019042968750, 0.0016174316406250, 0.0001525878906250, +0.0018615722656250, 0.0008544921875000, 0.0014953613281250, 0.0005187988281250, +0.0010681152343750, 0.0005493164062500, 0.0013122558593750, 0.0010375976562500, +0.0005493164062500, -0.0003967285156250, 0.0006103515625000, 0.0000915527343750, +0.0005493164062500, -0.0006408691406250, 0.0001220703125000, -0.0020446777343750, +0.0003967285156250, -0.0012512207031250, 0.0003662109375000, -0.0030517578125000, +0.0002746582031250, -0.0030822753906250, 0.0006103515625000, -0.0029907226562500, +0.0010070800781250, -0.0041198730468750, 0.0009155273437500, -0.0040283203125000, +0.0008544921875000, -0.0035400390625000, 0.0012207031250000, -0.0039062500000000, +0.0010375976562500, -0.0036621093750000, 0.0005798339843750, -0.0030212402343750, +0.0008850097656250, -0.0030517578125000, 0.0007934570312500, -0.0021362304687500, +0.0007934570312500, -0.0020141601562500, 0.0006713867187500, -0.0019226074218750, +0.0007324218750000, -0.0012207031250000, 0.0009155273437500, -0.0012817382812500, +-0.0002746582031250, -0.0020446777343750, 0.0000610351562500, -0.0014038085937500, +-0.0004272460937500, -0.0019226074218750, -0.0014343261718750, -0.0029296875000000, +-0.0007629394531250, -0.0019836425781250, -0.0023193359375000, -0.0025939941406250, +-0.0023193359375000, -0.0024108886718750, -0.0021972656250000, -0.0019531250000000, +-0.0029907226562500, -0.0019836425781250, -0.0027465820312500, -0.0019226074218750, +-0.0024108886718750, -0.0018310546875000, -0.0024108886718750, -0.0011596679687500, +-0.0020751953125000, -0.0018920898437500, -0.0015869140625000, -0.0024108886718750, +-0.0016174316406250, -0.0014038085937500, -0.0014038085937500, -0.0038146972656250, +-0.0013122558593750, -0.0030822753906250, -0.0010070800781250, -0.0028686523437500, +-0.0007934570312500, -0.0043334960937500, -0.0010070800781250, -0.0033874511718750, +-0.0007934570312500, -0.0039978027343750, -0.0008239746093750, -0.0039672851562500, +-0.0009460449218750, -0.0028686523437500, -0.0008239746093750, -0.0023498535156250, +-0.0009460449218750, -0.0024719238281250, -0.0012817382812500, -0.0006713867187500, +-0.0010681152343750, -0.0001220703125000, -0.0015258789062500, -0.0009460449218750, +-0.0021362304687500, -0.0006713867187500, -0.0016174316406250, -0.0000305175781250, +-0.0021057128906250, -0.0027160644531250, -0.0025939941406250, -0.0023193359375000, +-0.0017395019531250, -0.0022583007812500, -0.0009765625000000, -0.0039062500000000, +-0.0014953613281250, -0.0032348632812500, -0.0006103515625000, -0.0023803710937500, +-0.0000610351562500, -0.0030517578125000, -0.0003356933593750, -0.0024414062500000, +-0.0006103515625000, -0.0002441406250000, 0.0002136230468750, -0.0032043457031250, +-0.0001220703125000, -0.0014038085937500, -0.0000305175781250, -0.0022277832031250, +-0.0003662109375000, -0.0016479492187500, -0.0006103515625000, -0.0000610351562500, +-0.0003356933593750, -0.0002746582031250, -0.0015258789062500, -0.0011596679687500, +-0.0018920898437500, -0.0006713867187500, -0.0011596679687500, -0.0008239746093750, +-0.0012207031250000, -0.0018005371093750, -0.0017700195312500, -0.0014648437500000, +0.0003662109375000, -0.0010681152343750, 0.0007324218750000, -0.0009765625000000, +-0.0000915527343750, -0.0014038085937500, 0.0009765625000000, -0.0011291503906250, +0.0020751953125000, -0.0006713867187500, -0.0023498535156250, -0.0029296875000000, +-0.0005798339843750, -0.0023498535156250, -0.0014953613281250, -0.0029907226562500, +-0.0054016113281250, -0.0050964355468750, -0.0027770996093750, -0.0039367675781250, +-0.0034484863281250, -0.0038757324218750, -0.0046386718750000, -0.0046997070312500, +-0.0024414062500000, -0.0038452148437500, -0.0005187988281250, -0.0025024414062500, +-0.0017089843750000, -0.0030822753906250, 0.0007629394531250, -0.0026550292968750, +0.0014038085937500, -0.0021667480468750, 0.0003662109375000, -0.0025634765625000, +0.0008544921875000, -0.0029907226562500, 0.0013732910156250, -0.0026550292968750, +-0.0014953613281250, -0.0021972656250000, -0.0007019042968750, -0.0027465820312500, +-0.0010375976562500, -0.0019531250000000, -0.0031127929687500, -0.0007019042968750, +-0.0019226074218750, -0.0014953613281250, -0.0022888183593750, -0.0009765625000000, +-0.0021667480468750, -0.0006103515625000, -0.0021667480468750, -0.0009765625000000, +-0.0022888183593750, -0.0014953613281250, -0.0016479492187500, -0.0014648437500000, +-0.0025024414062500, -0.0008544921875000, -0.0022277832031250, -0.0013122558593750, +-0.0024108886718750, -0.0010070800781250, -0.0029296875000000, -0.0001831054687500, +-0.0024108886718750, -0.0006103515625000, -0.0039367675781250, -0.0004882812500000, +-0.0036315917968750, -0.0004882812500000, -0.0036315917968750, -0.0002441406250000, +-0.0049438476562500, -0.0001220703125000, -0.0046997070312500, -0.0003967285156250, +-0.0036315917968750, 0.0005798339843750, -0.0047912597656250, 0.0005187988281250, +-0.0037231445312500, 0.0003967285156250, -0.0022277832031250, 0.0009155273437500, +-0.0038146972656250, 0.0009155273437500, -0.0009155273437500, 0.0004272460937500, +-0.0017089843750000, 0.0004882812500000, -0.0013732910156250, 0.0007324218750000, +0.0004882812500000, 0.0005187988281250, -0.0011596679687500, 0.0003662109375000, +0.0004272460937500, 0.0012207031250000, 0.0000000000000000, 0.0011901855468750, +-0.0006103515625000, 0.0010986328125000, -0.0002136230468750, 0.0016479492187500, +-0.0010986328125000, 0.0015869140625000, -0.0011901855468750, 0.0012207031250000, +-0.0019226074218750, 0.0013122558593750, -0.0021972656250000, 0.0012817382812500, +-0.0023803710937500, 0.0010986328125000, -0.0032348632812500, 0.0010986328125000, +-0.0024414062500000, 0.0010070800781250, -0.0033874511718750, 0.0010681152343750, +-0.0032653808593750, 0.0009155273437500, -0.0025939941406250, 0.0006408691406250, +-0.0038146972656250, 0.0007629394531250, -0.0021057128906250, 0.0006103515625000, +-0.0026855468750000, 0.0005187988281250, -0.0027160644531250, 0.0005493164062500, +-0.0016784667968750, 0.0005798339843750, -0.0024108886718750, 0.0005187988281250, +-0.0009460449218750, 0.0003356933593750, -0.0013427734375000, 0.0004882812500000, +-0.0007324218750000, 0.0003356933593750, 0.0004272460937500, 0.0001220703125000, +-0.0005798339843750, 0.0001831054687500, 0.0011596679687500, 0.0000305175781250, +0.0007934570312500, 0.0000610351562500, 0.0008544921875000, -0.0000915527343750, +0.0018615722656250, -0.0002441406250000, 0.0010070800781250, -0.0000915527343750, +0.0020141601562500, -0.0007629394531250, 0.0018310546875000, -0.0005493164062500, +0.0017395019531250, -0.0008239746093750, 0.0023498535156250, -0.0013732910156250, +0.0019226074218750, -0.0009765625000000, 0.0020751953125000, -0.0017700195312500, +0.0022888183593750, -0.0017700195312500, 0.0020141601562500, -0.0017089843750000, +0.0018920898437500, -0.0020141601562500, 0.0020141601562500, -0.0019531250000000, +0.0014648437500000, -0.0019226074218750, 0.0016784667968750, -0.0019531250000000, +0.0014038085937500}, +{0.0002746582031250, -0.0021667480468750, -0.0011291503906250, -0.0024108886718750, +-0.0009460449218750, -0.0044250488281250, -0.0004882812500000, -0.0038757324218750, +-0.0029602050781250, -0.0032043457031250, -0.0024414062500000, -0.0037536621093750, +-0.0024414062500000, -0.0032653808593750, -0.0039672851562500, -0.0021057128906250, +-0.0030212402343750, -0.0025634765625000, -0.0026245117187500, -0.0024414062500000, +-0.0028076171875000, -0.0021667480468750, -0.0024108886718750, -0.0020751953125000, +-0.0015563964843750, -0.0023193359375000, -0.0016479492187500, -0.0024414062500000, +-0.0029907226562500, -0.0011901855468750, -0.0025939941406250, -0.0014648437500000, +-0.0027770996093750, -0.0013122558593750, -0.0041809082031250, -0.0002136230468750, +-0.0041198730468750, -0.0005187988281250, -0.0036010742187500, -0.0010070800781250, +-0.0045166015625000, -0.0008850097656250, -0.0038146972656250, -0.0008544921875000, +-0.0029296875000000, -0.0013122558593750, -0.0041198730468750, -0.0014038085937500, +-0.0013427734375000, -0.0006103515625000, -0.0021667480468750, -0.0009765625000000, +-0.0017089843750000, -0.0007324218750000, 0.0004272460937500, 0.0000305175781250, +-0.0010070800781250, -0.0003967285156250, -0.0003051757812500, 0.0002441406250000, +0.0000610351562500, 0.0002136230468750, -0.0007324218750000, 0.0003662109375000, +-0.0011596679687500, 0.0007019042968750, -0.0009765625000000, 0.0003967285156250, +-0.0023498535156250, 0.0011596679687500, -0.0024108886718750, 0.0011291503906250, +-0.0027465820312500, 0.0010070800781250, -0.0038452148437500, 0.0014038085937500, +-0.0037536621093750, 0.0013732910156250, -0.0038757324218750, 0.0009765625000000, +-0.0047607421875000, 0.0009460449218750, -0.0039367675781250, 0.0011596679687500, +-0.0033874511718750, 0.0010681152343750, -0.0047302246093750, 0.0009155273437500, +-0.0016784667968750, 0.0014648437500000, -0.0027160644531250, 0.0014953613281250, +-0.0019836425781250, 0.0014038085937500, 0.0003662109375000, 0.0016479492187500, +-0.0013427734375000, 0.0016174316406250, 0.0013122558593750, 0.0016174316406250, +0.0010986328125000, 0.0015258789062500, 0.0012817382812500, 0.0015563964843750, +0.0029602050781250, 0.0017700195312500, 0.0021972656250000, 0.0015869140625000, +0.0028381347656250, 0.0015563964843750, 0.0033264160156250, 0.0016784667968750, +0.0030822753906250, 0.0014648437500000, 0.0031127929687500, 0.0011901855468750, +0.0037536621093750, 0.0012817382812500, 0.0036926269531250, 0.0010681152343750, +0.0038146972656250, 0.0010375976562500, 0.0037841796875000, 0.0009460449218750, +0.0036315917968750, 0.0008544921875000, 0.0037536621093750, 0.0008850097656250, +0.0031127929687500, 0.0004882812500000, 0.0032958984375000, 0.0005798339843750, +0.0029907226562500, 0.0002746582031250, 0.0025329589843750, -0.0001525878906250, +0.0031738281250000, 0.0000915527343750, 0.0022583007812500, -0.0006713867187500, +0.0026245117187500, -0.0005798339843750, 0.0024414062500000, -0.0007324218750000, +0.0018005371093750, -0.0012512207031250, 0.0025634765625000, -0.0010375976562500, +0.0013122558593750, -0.0014343261718750, 0.0018310546875000, -0.0014648437500000, +0.0018005371093750, -0.0015258789062500, 0.0010375976562500, -0.0018005371093750, +0.0018920898437500, -0.0016784667968750, 0.0011596679687500, -0.0019226074218750, +0.0016174316406250, -0.0020141601562500, 0.0016784667968750, -0.0019836425781250, +0.0013122558593750, -0.0020751953125000, 0.0021667480468750, -0.0020751953125000, +0.0017395019531250, -0.0017700195312500, 0.0020446777343750, -0.0020141601562500, +0.0023498535156250, -0.0014953613281250, 0.0022277832031250, -0.0010375976562500, +0.0027465820312500, -0.0015258789062500, 0.0030212402343750, -0.0001220703125000, +0.0030212402343750, -0.0003051757812500, 0.0028076171875000, -0.0001220703125000, +0.0028076171875000, 0.0007019042968750, 0.0030212402343750, 0.0002746582031250, +0.0022583007812500, 0.0007934570312500, 0.0027160644531250, 0.0009460449218750, +0.0024108886718750, 0.0005187988281250, 0.0017089843750000, 0.0004577636718750, +0.0024414062500000, 0.0007324218750000, 0.0012817382812500, 0.0001831054687500, +0.0014648437500000, 0.0000000000000000, 0.0013427734375000, 0.0003356933593750, +0.0004577636718750, 0.0004272460937500, 0.0007324218750000, 0.0002136230468750, +-0.0000915527343750, 0.0003967285156250, -0.0001220703125000, 0.0004882812500000, +-0.0005798339843750, 0.0003356933593750, -0.0014343261718750, 0.0002441406250000, +-0.0014648437500000, 0.0003051757812500, -0.0023498535156250, -0.0000610351562500, +-0.0023498535156250, -0.0000610351562500, -0.0024414062500000, -0.0001525878906250, +-0.0027160644531250, -0.0004272460937500, -0.0022583007812500, -0.0003967285156250, +-0.0025634765625000, -0.0004577636718750, -0.0021667480468750, -0.0006103515625000, +-0.0021972656250000, -0.0004272460937500, -0.0025939941406250, -0.0002441406250000, +-0.0024108886718750, -0.0004882812500000, -0.0030822753906250, -0.0003051757812500, +-0.0032653808593750, 0.0000915527343750, -0.0035705566406250, -0.0007324218750000, +-0.0041503906250000, -0.0014953613281250, -0.0043334960937500, -0.0007019042968750, +-0.0048522949218750, -0.0019226074218750, -0.0053405761718750, -0.0022277832031250, +-0.0050048828125000, -0.0018005371093750, -0.0050354003906250, -0.0021057128906250, +-0.0059509277343750, -0.0021667480468750, -0.0042419433593750, -0.0009460449218750, +-0.0045471191406250, -0.0011596679687500, -0.0049438476562500, -0.0012207031250000, +-0.0039978027343750, -0.0003356933593750, -0.0038146972656250, -0.0004272460937500, +-0.0039062500000000, -0.0005798339843750, -0.0038146972656250, -0.0006103515625000, +-0.0033569335937500, -0.0002746582031250, -0.0034484863281250, -0.0001525878906250, +-0.0041503906250000, -0.0004882812500000, -0.0026855468750000, -0.0000610351562500, +-0.0026855468750000, 0.0000305175781250, -0.0028381347656250, -0.0001220703125000, +-0.0020751953125000, 0.0000610351562500, -0.0022888183593750, 0.0000610351562500, +-0.0030822753906250, -0.0007019042968750, -0.0018920898437500, -0.0003967285156250, +-0.0025024414062500, -0.0007324218750000, -0.0040588378906250, -0.0014343261718750, +-0.0030212402343750, -0.0009460449218750, -0.0038146972656250, -0.0018920898437500, +-0.0042724609375000, -0.0019531250000000, -0.0036315917968750, -0.0019836425781250, +-0.0034484863281250, -0.0022583007812500, -0.0037536621093750, -0.0018920898437500, +-0.0028076171875000, -0.0025634765625000, -0.0032348632812500, -0.0028076171875000, +-0.0026550292968750, -0.0025329589843750, -0.0018005371093750, -0.0022888183593750, +-0.0027160644531250, -0.0023498535156250, -0.0009460449218750, -0.0035095214843750, +-0.0014343261718750, -0.0026855468750000, -0.0013732910156250, -0.0027465820312500, +-0.0000305175781250, -0.0035095214843750, -0.0006408691406250, -0.0025329589843750, +-0.0006408691406250, -0.0035400390625000, 0.0000610351562500, -0.0029907226562500, +-0.0008239746093750, -0.0029907226562500, -0.0017700195312500, -0.0035400390625000, +-0.0007934570312500, -0.0026550292968750, -0.0018310546875000, -0.0039672851562500, +-0.0020751953125000, -0.0037231445312500, -0.0014648437500000, -0.0036621093750000, +-0.0012817382812500, -0.0047302246093750, -0.0012817382812500, -0.0045166015625000, +-0.0005187988281250, -0.0035400390625000, -0.0003356933593750, -0.0034790039062500, +-0.0007324218750000, -0.0034790039062500, -0.0006408691406250, -0.0026855468750000, +-0.0002441406250000, -0.0021362304687500, -0.0007324218750000, -0.0029296875000000, +-0.0009155273437500, -0.0019531250000000, -0.0006103515625000, -0.0027160644531250, +-0.0004577636718750, -0.0039062500000000, -0.0005493164062500, -0.0023193359375000, +-0.0003051757812500, -0.0048828125000000, -0.0001831054687500, -0.0049743652343750, +-0.0005493164062500, -0.0046997070312500, -0.0007934570312500, -0.0059814453125000, +-0.0006103515625000, -0.0059204101562500, -0.0014648437500000, -0.0053710937500000, +-0.0014953613281250, -0.0057983398437500, -0.0014953613281250, -0.0056762695312500, +-0.0020751953125000, -0.0052490234375000, -0.0021362304687500, -0.0056457519531250, +-0.0019531250000000, -0.0047912597656250, -0.0021057128906250, -0.0051879882812500, +-0.0018920898437500, -0.0047607421875000, -0.0016479492187500, -0.0040893554687500, +-0.0020446777343750, -0.0050354003906250, -0.0014953613281250, -0.0030822753906250, +-0.0015869140625000, -0.0039367675781250, -0.0010986328125000, -0.0033874511718750, +-0.0004882812500000, -0.0017395019531250, -0.0011291503906250, -0.0029907226562500, +-0.0002136230468750, -0.0011901855468750, -0.0001220703125000, -0.0015258789062500, +-0.0000915527343750, -0.0015869140625000, 0.0001525878906250, -0.0007324218750000, +-0.0000610351562500, -0.0017395019531250, 0.0006408691406250, -0.0011596679687500, +0.0003662109375000, -0.0017700195312500, 0.0007019042968750, -0.0019226074218750, +0.0013732910156250, -0.0015869140625000, 0.0007629394531250, -0.0025329589843750, +0.0014038085937500, -0.0012512207031250, 0.0017089843750000, -0.0017700195312500, +0.0010986328125000, -0.0014038085937500, 0.0009765625000000, -0.0003051757812500, +0.0014038085937500, -0.0010681152343750, 0.0000305175781250, 0.0002136230468750, +0.0003356933593750, 0.0002441406250000, 0.0001220703125000, 0.0001220703125000, +-0.0007629394531250, 0.0007019042968750, -0.0001220703125000, 0.0006103515625000, +-0.0007629394531250, 0.0006103515625000, -0.0006103515625000, 0.0010681152343750, +-0.0003356933593750, 0.0006103515625000, -0.0005493164062500, 0.0004577636718750, +-0.0003356933593750, 0.0012817382812500, 0.0000000000000000, -0.0003051757812500, +-0.0000305175781250, 0.0007324218750000, 0.0002136230468750, 0.0003967285156250, +0.0006103515625000, -0.0008544921875000, 0.0004882812500000, 0.0005798339843750, +0.0008850097656250, -0.0014343261718750, 0.0010070800781250, -0.0003051757812500, +0.0007629394531250, -0.0002746582031250, 0.0007934570312500, -0.0018615722656250, +0.0009765625000000, -0.0004577636718750, 0.0003662109375000, -0.0015869140625000, +0.0004882812500000, -0.0010681152343750, 0.0003967285156250, -0.0003967285156250, +-0.0000305175781250, -0.0008239746093750, 0.0001831054687500, -0.0002441406250000, +-0.0000305175781250, 0.0001525878906250, -0.0001525878906250, 0.0002441406250000, +-0.0000305175781250, 0.0002441406250000, 0.0000000000000000, 0.0005493164062500, +-0.0001220703125000, 0.0008239746093750, -0.0000915527343750, 0.0001831054687500, +-0.0000915527343750, 0.0010375976562500, -0.0001220703125000, 0.0007934570312500, +-0.0001220703125000, 0.0002136230468750, -0.0001831054687500, 0.0014343261718750, +-0.0001525878906250, 0.0000305175781250, -0.0003051757812500, 0.0009155273437500, +-0.0002136230468750, 0.0007934570312500, -0.0000610351562500, -0.0001220703125000, +-0.0002746582031250, 0.0013122558593750, 0.0004882812500000, -0.0004272460937500, +0.0003051757812500, 0.0003967285156250, 0.0008239746093750, 0.0003662109375000, +0.0016784667968750, -0.0007019042968750, 0.0014038085937500, 0.0007629394531250, +0.0022888183593750, -0.0001525878906250, 0.0024414062500000, -0.0000305175781250, +0.0023803710937500, 0.0004272460937500, 0.0026245117187500, 0.0001220703125000, +0.0025634765625000, 0.0001831054687500, 0.0024414062500000, 0.0001525878906250, +0.0022888183593750, 0.0003662109375000, 0.0022888183593750, -0.0000610351562500, +0.0022583007812500, -0.0001831054687500, 0.0020751953125000, 0.0003967285156250, +0.0020751953125000, -0.0008239746093750, 0.0019531250000000, 0.0000000000000000, +0.0019531250000000, -0.0006103515625000, 0.0018615722656250, -0.0018615722656250, +0.0016479492187500}, +{-0.0018615722656250, -0.0015563964843750, -0.0025024414062500, -0.0036010742187500, +-0.0008239746093750, -0.0012512207031250, -0.0011901855468750, -0.0018005371093750, +-0.0012207031250000, -0.0021972656250000, -0.0001220703125000, -0.0012817382812500, +-0.0005187988281250, -0.0025634765625000, -0.0000305175781250, -0.0015563964843750, +0.0000305175781250, -0.0027160644531250, -0.0001220703125000, -0.0024414062500000, +0.0001525878906250, -0.0014953613281250, 0.0002136230468750, -0.0032348632812500, +0.0000915527343750, -0.0007324218750000, 0.0000305175781250, -0.0014953613281250, +-0.0000305175781250, -0.0010986328125000, -0.0001525878906250, 0.0009765625000000, +-0.0001525878906250, -0.0002746582031250, -0.0000915527343750, 0.0009765625000000, +-0.0002441406250000, 0.0013122558593750, -0.0000610351562500, 0.0008544921875000, +0.0002136230468750, 0.0011291503906250, 0.0000305175781250, 0.0011291503906250, +0.0003051757812500, 0.0001220703125000, 0.0005798339843750, 0.0006713867187500, +0.0003967285156250, 0.0001220703125000, 0.0004882812500000, -0.0007934570312500, +0.0008850097656250, 0.0003967285156250, 0.0002441406250000, -0.0012817382812500, +0.0005798339843750, -0.0005493164062500, 0.0005187988281250, -0.0005187988281250, +0.0000305175781250, -0.0012817382812500, 0.0005187988281250, 0.0001220703125000, +0.0002441406250000, -0.0010986328125000, 0.0001831054687500, 0.0000000000000000, +0.0003662109375000, 0.0003051757812500, 0.0003356933593750, -0.0002136230468750, +0.0003967285156250, 0.0014953613281250, 0.0006103515625000, 0.0006408691406250, +0.0006103515625000, 0.0019836425781250, 0.0007934570312500, 0.0025634765625000, +0.0010681152343750, 0.0018005371093750, 0.0010070800781250, 0.0029907226562500, +0.0011596679687500, 0.0031127929687500, 0.0013427734375000, 0.0027465820312500, +0.0011901855468750, 0.0033264160156250, 0.0011291503906250, 0.0041198730468750, +0.0013732910156250, 0.0038452148437500, 0.0008850097656250, 0.0039062500000000, +0.0009460449218750, 0.0047302246093750, 0.0010375976562500, 0.0043334960937500, +0.0007324218750000, 0.0039367675781250, 0.0008239746093750, 0.0051879882812500, +0.0009155273437500, 0.0037231445312500, 0.0007934570312500, 0.0045776367187500, +0.0007629394531250, 0.0046386718750000, 0.0008850097656250, 0.0039062500000000, +0.0007019042968750, 0.0051879882812500, 0.0006408691406250, 0.0038452148437500, +0.0005798339843750, 0.0047607421875000, 0.0006103515625000, 0.0045166015625000, +0.0006103515625000, 0.0036621093750000, 0.0004272460937500, 0.0052795410156250, +0.0008850097656250, 0.0032653808593750, 0.0006103515625000, 0.0044555664062500, +0.0007934570312500, 0.0042419433593750, 0.0012207031250000, 0.0028381347656250, +0.0007934570312500, 0.0046691894531250, 0.0014038085937500, 0.0021362304687500, +0.0015563964843750, 0.0030822753906250, 0.0016479492187500, 0.0027770996093750, +0.0020141601562500, 0.0008239746093750, 0.0020141601562500, 0.0023498535156250, +0.0021972656250000, 0.0005187988281250, 0.0021972656250000, 0.0005798339843750, +0.0022277832031250, 0.0005798339843750, 0.0022277832031250, -0.0004577636718750, +0.0020751953125000, -0.0001525878906250, 0.0026550292968750, -0.0005798339843750, +0.0023498535156250, -0.0006408691406250, 0.0025024414062500, -0.0004577636718750, +0.0030517578125000, -0.0003356933593750, 0.0024719238281250, -0.0001220703125000, +0.0025329589843750, 0.0000305175781250, 0.0025329589843750, 0.0006713867187500, +0.0020751953125000, 0.0003967285156250, 0.0015563964843750, 0.0003356933593750, +0.0014953613281250, 0.0012207031250000, 0.0013427734375000, -0.0009765625000000, +0.0009155273437500, 0.0001220703125000, 0.0008239746093750, -0.0007934570312500, +0.0010375976562500, -0.0029907226562500, 0.0005798339843750, -0.0012512207031250, +-0.0000305175781250, -0.0038757324218750, -0.0001831054687500, -0.0040588378906250, +-0.0003662109375000, -0.0036315917968750, -0.0010681152343750, -0.0046386718750000, +-0.0013732910156250, -0.0043334960937500, -0.0004882812500000, -0.0032043457031250, +-0.0009765625000000, -0.0040588378906250, -0.0008544921875000, -0.0026550292968750, +0.0000915527343750, -0.0010681152343750, -0.0004272460937500, -0.0025939941406250, +-0.0003356933593750, 0.0007324218750000, 0.0001525878906250, 0.0002441406250000, +-0.0001220703125000, 0.0001831054687500, -0.0004882812500000, 0.0021667480468750, +-0.0001220703125000, 0.0011596679687500, -0.0004882812500000, 0.0009765625000000, +-0.0002746582031250, 0.0009155273437500, -0.0004272460937500, 0.0000305175781250, +-0.0006408691406250, -0.0006408691406250, -0.0001220703125000, -0.0006713867187500, +-0.0013427734375000, -0.0018005371093750, -0.0010070800781250, -0.0019531250000000, +-0.0011901855468750, -0.0022583007812500, -0.0023498535156250, -0.0030212402343750, +-0.0018310546875000, -0.0028381347656250, -0.0017700195312500, -0.0023193359375000, +-0.0024719238281250, -0.0029907226562500, -0.0014343261718750, -0.0026245117187500, +-0.0004272460937500, -0.0018615722656250, -0.0014953613281250, -0.0026855468750000, +0.0007629394531250, -0.0018005371093750, 0.0005493164062500, -0.0018310546875000, +0.0003967285156250, -0.0020141601562500, 0.0015563964843750, -0.0020141601562500, +0.0010375976562500, -0.0024414062500000, 0.0014343261718750, -0.0015258789062500, +0.0012512207031250, -0.0027160644531250, 0.0011901855468750, -0.0019531250000000, +0.0013732910156250, -0.0006103515625000, 0.0009155273437500, -0.0025024414062500, +0.0012512207031250, -0.0004272460937500, 0.0010681152343750, -0.0005798339843750, +0.0006103515625000, -0.0016479492187500, 0.0006103515625000, -0.0014648437500000, +0.0004882812500000, -0.0018310546875000, -0.0003356933593750, -0.0030822753906250, +-0.0004577636718750, -0.0041809082031250, -0.0003662109375000, -0.0036315917968750, +-0.0007019042968750, -0.0025634765625000, -0.0007629394531250, -0.0018920898437500, +-0.0029602050781250, -0.0037841796875000, -0.0025024414062500, -0.0046081542968750, +-0.0019226074218750, -0.0037231445312500, -0.0024719238281250, -0.0031127929687500, +-0.0026245117187500, -0.0039367675781250, -0.0003967285156250, -0.0024719238281250, +-0.0011291503906250, -0.0020751953125000, -0.0012207031250000, -0.0027770996093750, +0.0005493164062500, -0.0027770996093750, -0.0002136230468750, -0.0022277832031250, +-0.0018920898437500, -0.0031433105468750, -0.0010070800781250, -0.0034484863281250, +-0.0025939941406250, -0.0025634765625000, -0.0050964355468750, -0.0021667480468750, +-0.0035705566406250, -0.0026550292968750, -0.0052490234375000, -0.0011596679687500, +-0.0059509277343750, -0.0008544921875000, -0.0044250488281250, -0.0015869140625000, +-0.0037231445312500, -0.0012817382812500, -0.0043640136718750, -0.0007019042968750, +-0.0022277832031250, -0.0027160644531250, -0.0016784667968750, -0.0025939941406250, +-0.0021972656250000, -0.0021362304687500, -0.0019836425781250, -0.0029296875000000, +-0.0018920898437500, -0.0027160644531250, -0.0023193359375000, -0.0021972656250000, +-0.0029602050781250, -0.0020446777343750, -0.0026245117187500, -0.0022583007812500, +-0.0025634765625000, -0.0021667480468750, -0.0034179687500000, -0.0020751953125000, +-0.0010986328125000, -0.0029296875000000, -0.0018310546875000, -0.0028076171875000, +-0.0012512207031250, -0.0025939941406250, 0.0011291503906250, -0.0030822753906250, +0.0002136230468750, -0.0029296875000000, 0.0001831054687500, -0.0021057128906250, +0.0018615722656250, -0.0021362304687500, 0.0003662109375000, -0.0018310546875000, +-0.0013427734375000, -0.0010986328125000, 0.0006103515625000, -0.0011596679687500, +-0.0030822753906250, -0.0008544921875000, -0.0024414062500000, -0.0006408691406250, +-0.0025634765625000, -0.0005187988281250, -0.0050048828125000, -0.0002136230468750, +-0.0037536621093750, -0.0001220703125000, -0.0036315917968750, -0.0002136230468750, +-0.0046997070312500, 0.0000610351562500, -0.0029907226562500, -0.0000915527343750, +-0.0013122558593750, -0.0003356933593750, -0.0027160644531250, 0.0000305175781250, +0.0005187988281250, -0.0003662109375000, 0.0005798339843750, -0.0005798339843750, +0.0005187988281250, -0.0001525878906250, 0.0020751953125000, 0.0000305175781250, +0.0014953613281250, -0.0001525878906250, 0.0017089843750000, 0.0007324218750000, +0.0021057128906250, 0.0008239746093750, 0.0014343261718750, 0.0008850097656250, +0.0010070800781250, 0.0013427734375000, 0.0014343261718750, 0.0012817382812500, +-0.0001525878906250, 0.0014343261718750, 0.0000305175781250, 0.0014343261718750, +-0.0001220703125000, 0.0015869140625000, -0.0012207031250000, 0.0017700195312500, +-0.0008239746093750, 0.0016784667968750, -0.0007324218750000, 0.0021972656250000, +-0.0011901855468750, 0.0020446777343750, -0.0003967285156250, 0.0021972656250000, +0.0002441406250000, 0.0026245117187500, -0.0005187988281250, 0.0024108886718750, +0.0013732910156250, 0.0028381347656250, 0.0008544921875000, 0.0028076171875000, +0.0013732910156250, 0.0027465820312500, 0.0026855468750000, 0.0029602050781250, +0.0016174316406250, 0.0029296875000000, 0.0035095214843750, 0.0027770996093750, +0.0029602050781250, 0.0028686523437500, 0.0029602050781250, 0.0026855468750000, +0.0041809082031250, 0.0023498535156250, 0.0030212402343750, 0.0025024414062500, +0.0034484863281250, 0.0021057128906250, 0.0035400390625000, 0.0021362304687500, +0.0034484863281250, 0.0019836425781250, 0.0036010742187500, 0.0017089843750000, +0.0036315917968750, 0.0018615722656250, 0.0038452148437500, 0.0013427734375000, +0.0038452148437500, 0.0014038085937500, 0.0035705566406250, 0.0011901855468750, +0.0036926269531250, 0.0007629394531250, 0.0041198730468750, 0.0009460449218750, +0.0033569335937500, 0.0003356933593750, 0.0037536621093750, 0.0003356933593750, +0.0036315917968750, 0.0001831054687500, 0.0030822753906250, -0.0002441406250000, +0.0036315917968750, -0.0000610351562500, 0.0029296875000000, -0.0004577636718750, +0.0031127929687500, -0.0006103515625000, 0.0030822753906250, -0.0003967285156250, +0.0026550292968750, -0.0004577636718750, 0.0031433105468750, -0.0007324218750000, +0.0025939941406250, 0.0000610351562500, 0.0025329589843750, -0.0002746582031250, +0.0025939941406250, 0.0000000000000000, 0.0022888183593750, 0.0006103515625000, +0.0024414062500000, 0.0001525878906250, 0.0023803710937500, 0.0006103515625000, +0.0023193359375000, 0.0006408691406250, 0.0024414062500000, 0.0005798339843750, +0.0025024414062500, 0.0007629394531250, 0.0024108886718750, 0.0005798339843750, +0.0031433105468750, 0.0006408691406250, 0.0026550292968750, 0.0007324218750000, +0.0028991699218750, 0.0005187988281250, 0.0034790039062500, 0.0004272460937500, +0.0025939941406250, 0.0005493164062500, 0.0035400390625000, 0.0006103515625000, +0.0029296875000000, 0.0003356933593750, 0.0025024414062500, 0.0005187988281250, +0.0028686523437500, 0.0008239746093750, 0.0021667480468750, 0.0005493164062500, +0.0021057128906250, 0.0003967285156250, 0.0021667480468750, 0.0006103515625000, +0.0018920898437500, 0.0002746582031250, 0.0018005371093750, -0.0001831054687500, +0.0021972656250000, 0.0001220703125000, 0.0017700195312500, -0.0005493164062500, +0.0020446777343750, -0.0006408691406250, 0.0024108886718750, -0.0004272460937500, +0.0022888183593750, -0.0006103515625000, 0.0024719238281250, -0.0007934570312500, +0.0031127929687500, -0.0003356933593750, 0.0031127929687500, -0.0003662109375000, +0.0031738281250000, -0.0004577636718750, 0.0036010742187500, -0.0002746582031250, +0.0032958984375000, -0.0003662109375000, 0.0023803710937500, -0.0003662109375000, +0.0028381347656250}, +{-0.0014343261718750, 0.0000305175781250, -0.0013122558593750, -0.0001525878906250, +-0.0007324218750000, 0.0003967285156250, -0.0006103515625000, 0.0006408691406250, +-0.0003051757812500, 0.0004882812500000, 0.0008544921875000, 0.0012817382812500, +0.0009460449218750, 0.0013427734375000, 0.0014648437500000, 0.0014038085937500, +0.0023803710937500, 0.0018005371093750, 0.0023498535156250, 0.0017395019531250, +0.0028686523437500, 0.0021057128906250, 0.0031433105468750, 0.0021057128906250, +0.0028991699218750, 0.0022277832031250, 0.0028381347656250, 0.0025329589843750, +0.0029296875000000, 0.0024719238281250, 0.0021362304687500, 0.0025024414062500, +0.0021972656250000, 0.0025939941406250, 0.0018310546875000, 0.0025939941406250, +0.0011291503906250, 0.0025634765625000, 0.0015258789062500, 0.0025634765625000, +0.0007934570312500, 0.0027770996093750, 0.0005798339843750, 0.0027770996093750, +0.0003662109375000, 0.0026855468750000, -0.0000610351562500, 0.0027770996093750, +-0.0000610351562500, 0.0027770996093750, -0.0001525878906250, 0.0025024414062500, +-0.0003967285156250, 0.0026245117187500, -0.0002746582031250, 0.0023498535156250, +-0.0002136230468750, 0.0020446777343750, -0.0004577636718750, 0.0021972656250000, +-0.0003051757812500, 0.0016784667968750, -0.0001220703125000, 0.0017089843750000, +-0.0000915527343750, 0.0015563964843750, -0.0001220703125000, 0.0010986328125000, +-0.0000305175781250, 0.0012207031250000, 0.0000305175781250, 0.0007934570312500, +-0.0002136230468750, 0.0006408691406250, 0.0000305175781250, 0.0007324218750000, +-0.0000305175781250, 0.0005493164062500, -0.0007934570312500, 0.0004272460937500, +0.0001831054687500, 0.0008544921875000, -0.0003356933593750, 0.0006713867187500, +-0.0003356933593750, 0.0008239746093750, 0.0004577636718750, 0.0011596679687500, +-0.0001831054687500, 0.0008850097656250, 0.0001831054687500, 0.0011596679687500, +0.0002746582031250, 0.0011901855468750, 0.0000915527343750, 0.0010681152343750, +0.0000915527343750, 0.0011901855468750, 0.0000305175781250, 0.0011596679687500, +-0.0000610351562500, 0.0010986328125000, -0.0002746582031250, 0.0010986328125000, +-0.0001220703125000, 0.0009460449218750, 0.0000305175781250, 0.0008544921875000, +-0.0000915527343750, 0.0009155273437500, 0.0002136230468750, 0.0006103515625000, +0.0001831054687500, 0.0005493164062500, 0.0005798339843750, 0.0007019042968750, +0.0008850097656250, 0.0006713867187500, 0.0005798339843750, 0.0004882812500000, +0.0018310546875000, 0.0006408691406250, 0.0011901855468750, 0.0007019042968750, +0.0017700195312500, 0.0003662109375000, 0.0028991699218750, 0.0001525878906250, +0.0016784667968750, 0.0003051757812500, 0.0029602050781250, -0.0003356933593750, +0.0028076171875000, -0.0003662109375000, 0.0023498535156250, -0.0004272460937500, +0.0029296875000000, -0.0007629394531250, 0.0028686523437500, -0.0007629394531250, +0.0022888183593750, -0.0004882812500000, 0.0028381347656250, -0.0007019042968750, +0.0024719238281250, -0.0007324218750000, 0.0018310546875000, -0.0004272460937500, +0.0026855468750000, -0.0004272460937500, 0.0013732910156250, -0.0007324218750000, +0.0018005371093750, -0.0006713867187500, 0.0018920898437500, -0.0006408691406250, +0.0011291503906250, -0.0007019042968750, 0.0018615722656250, -0.0006713867187500, +0.0017700195312500, -0.0010986328125000, 0.0016479492187500, -0.0009460449218750, +0.0018005371093750, -0.0010070800781250, 0.0018920898437500, -0.0015258789062500, +0.0019531250000000, -0.0013732910156250, 0.0017700195312500, -0.0012817382812500, +0.0022277832031250, -0.0014648437500000, 0.0017700195312500, -0.0010681152343750, +0.0015258789062500, -0.0007324218750000, 0.0024108886718750, -0.0011596679687500, +0.0003967285156250, -0.0003662109375000, 0.0012207031250000, -0.0002136230468750, +0.0006713867187500, -0.0006713867187500, -0.0011901855468750, -0.0007324218750000, +0.0000610351562500, -0.0004577636718750, -0.0017395019531250, -0.0012817382812500, +-0.0017700195312500, -0.0011596679687500, -0.0019531250000000, -0.0011291503906250, +-0.0029602050781250, -0.0016174316406250, -0.0025939941406250, -0.0013427734375000, +-0.0036926269531250, -0.0008850097656250, -0.0034790039062500, -0.0009765625000000, +-0.0039978027343750, -0.0008239746093750, -0.0049133300781250, -0.0003051757812500, +-0.0040893554687500, -0.0003967285156250, -0.0052795410156250, -0.0007629394531250, +-0.0049438476562500, -0.0006103515625000, -0.0043640136718750, -0.0006713867187500, +-0.0053100585937500, -0.0010375976562500, -0.0054016113281250, -0.0008544921875000, +-0.0032348632812500, -0.0002746582031250, -0.0040893554687500, -0.0007629394531250, +-0.0034484863281250, -0.0005493164062500, -0.0012207031250000, 0.0001220703125000, +-0.0023498535156250, -0.0003051757812500, -0.0017089843750000, 0.0001831054687500, +-0.0006408691406250, 0.0002746582031250, -0.0018310546875000, -0.0010070800781250, +-0.0028381347656250, -0.0014953613281250, -0.0016784667968750, -0.0007019042968750, +-0.0033874511718750, -0.0026855468750000, -0.0035095214843750, -0.0028686523437500, +-0.0034179687500000, -0.0031127929687500, -0.0032958984375000, -0.0041198730468750, +-0.0021667480468750, -0.0036621093750000, -0.0036621093750000, -0.0038146972656250, +-0.0028991699218750, -0.0038757324218750, -0.0027465820312500, -0.0034484863281250, +-0.0040283203125000, -0.0033569335937500, -0.0031433105468750, -0.0035400390625000, +-0.0023193359375000, -0.0028076171875000, -0.0029296875000000, -0.0023498535156250, +-0.0019836425781250, -0.0025634765625000, -0.0006408691406250, -0.0020141601562500, +-0.0016174316406250, -0.0010375976562500, 0.0000305175781250, -0.0028076171875000, +-0.0002136230468750, -0.0019226074218750, -0.0000915527343750, -0.0018615722656250, +0.0006408691406250, -0.0033874511718750, -0.0002441406250000, -0.0027465820312500, +0.0011901855468750, -0.0030822753906250, 0.0003662109375000, -0.0038757324218750, +0.0006103515625000, -0.0037231445312500, 0.0018920898437500, -0.0039062500000000, +0.0007019042968750, -0.0052795410156250, 0.0011291503906250, -0.0042419433593750, +0.0012817382812500, -0.0053100585937500, 0.0006103515625000, -0.0052795410156250, +0.0003356933593750, -0.0046081542968750, 0.0004272460937500, -0.0059204101562500, +-0.0005187988281250, -0.0035095214843750, -0.0005493164062500, -0.0044555664062500, +-0.0008544921875000, -0.0038452148437500, -0.0014648437500000, -0.0018005371093750, +-0.0011291503906250, -0.0034179687500000, -0.0016174316406250, -0.0016479492187500, +-0.0018920898437500, -0.0020446777343750, -0.0015869140625000, -0.0021972656250000, +-0.0014648437500000, -0.0015869140625000, -0.0016479492187500, -0.0026550292968750, +-0.0008544921875000, -0.0013427734375000, -0.0007019042968750, -0.0020446777343750, +-0.0009460449218750, -0.0017395019531250, -0.0006713867187500, -0.0005493164062500, +-0.0004882812500000, -0.0014648437500000, -0.0011901855468750, 0.0004272460937500, +-0.0007324218750000, 0.0007934570312500, -0.0010070800781250, 0.0008850097656250, +-0.0018615722656250, 0.0020751953125000, -0.0012207031250000, 0.0023803710937500, +-0.0012817382812500, 0.0015258789062500, -0.0013122558593750, 0.0026245117187500, +-0.0011291503906250, 0.0021362304687500, -0.0009155273437500, 0.0010070800781250, +-0.0006713867187500, 0.0024719238281250, -0.0007629394531250, 0.0007934570312500, +-0.0003356933593750, 0.0014953613281250, -0.0005187988281250, 0.0017089843750000, +-0.0007934570312500, 0.0008544921875000, -0.0001220703125000, 0.0020141601562500, +-0.0010681152343750, 0.0012512207031250, -0.0009460449218750, 0.0018310546875000, +-0.0005798339843750, 0.0015869140625000, -0.0009155273437500, 0.0009155273437500, +-0.0008239746093750, 0.0020141601562500, -0.0004272460937500, 0.0003662109375000, +-0.0006103515625000, 0.0010986328125000, -0.0004272460937500, 0.0007324218750000, +-0.0001220703125000, -0.0005493164062500, -0.0004882812500000, 0.0009765625000000, +0.0001220703125000, -0.0005493164062500, -0.0000610351562500, -0.0001831054687500, +0.0000000000000000, -0.0001831054687500, 0.0005187988281250, -0.0009155273437500, +0.0003967285156250, 0.0001220703125000, 0.0005493164062500, -0.0006408691406250, +0.0008239746093750, -0.0001525878906250, 0.0008239746093750, 0.0003967285156250, +0.0007019042968750, 0.0002746582031250, 0.0008850097656250, 0.0007934570312500, +0.0011901855468750, 0.0007934570312500, 0.0008544921875000, 0.0012512207031250, +0.0012512207031250, 0.0013427734375000, 0.0018310546875000, 0.0013427734375000, +0.0012207031250000, 0.0020141601562500, 0.0021667480468750, 0.0014648437500000, +0.0020446777343750, 0.0022583007812500, 0.0020446777343750, 0.0022583007812500, +0.0025939941406250, 0.0018005371093750, 0.0022583007812500, 0.0026855468750000, +0.0025024414062500, 0.0018920898437500, 0.0025939941406250, 0.0024108886718750, +0.0024414062500000, 0.0026245117187500, 0.0025024414062500, 0.0021972656250000, +0.0025024414062500, 0.0028076171875000, 0.0023498535156250, 0.0026550292968750, +0.0024719238281250, 0.0024719238281250, 0.0024108886718750, 0.0026855468750000, +0.0022888183593750, 0.0026550292968750, 0.0024719238281250, 0.0021972656250000, +0.0021972656250000, 0.0025939941406250, 0.0023498535156250, 0.0023498535156250, +0.0022277832031250, 0.0021362304687500, 0.0020446777343750, 0.0022277832031250, +0.0023193359375000, 0.0017700195312500, 0.0018005371093750, 0.0016479492187500, +0.0019836425781250, 0.0014648437500000, 0.0018005371093750, 0.0010681152343750, +0.0013122558593750, 0.0008850097656250, 0.0015258789062500, 0.0007324218750000, +0.0010070800781250, 0.0001220703125000, 0.0007934570312500, 0.0004272460937500, +0.0009155273437500, -0.0000610351562500, 0.0007019042968750, -0.0004882812500000, +0.0004272460937500, 0.0003967285156250, 0.0009155273437500, -0.0006408691406250, +0.0009460449218750, 0.0000915527343750, 0.0007629394531250, 0.0003356933593750, +0.0010375976562500, -0.0001831054687500, 0.0012817382812500, 0.0009155273437500, +0.0006103515625000, 0.0003356933593750, 0.0008544921875000, 0.0010070800781250, +0.0009155273437500, 0.0013427734375000, 0.0004577636718750, 0.0011901855468750, +0.0006408691406250, 0.0020751953125000, 0.0007324218750000, 0.0010986328125000, +0.0007934570312500, 0.0020446777343750, 0.0005493164062500, 0.0014343261718750, +0.0004577636718750, 0.0004882812500000, 0.0006713867187500, 0.0021972656250000, +0.0000000000000000, -0.0008850097656250, 0.0000305175781250, 0.0005187988281250, +0.0000305175781250, -0.0001220703125000, -0.0003051757812500, -0.0024414062500000, +-0.0001525878906250, -0.0000915527343750, -0.0003356933593750, -0.0029602050781250, +-0.0000305175781250, -0.0022583007812500, -0.0002746582031250, -0.0017089843750000, +-0.0006408691406250, -0.0029602050781250, -0.0001831054687500, -0.0016784667968750, +-0.0010375976562500, -0.0016174316406250, -0.0010375976562500, -0.0015563964843750, +-0.0009460449218750, -0.0008850097656250, -0.0012817382812500, -0.0001831054687500, +-0.0012207031250000, 0.0001220703125000, -0.0014648437500000, 0.0000915527343750, +-0.0012817382812500, 0.0004882812500000, -0.0013427734375000, 0.0000000000000000, +-0.0018920898437500, -0.0007629394531250, -0.0018005371093750, -0.0004882812500000, +-0.0013427734375000, -0.0014648437500000, -0.0019531250000000, -0.0024719238281250, +-0.0013732910156250, -0.0020141601562500, -0.0003967285156250, -0.0021972656250000, +-0.0011596679687500, -0.0036010742187500, -0.0002441406250000, -0.0013732910156250, +-0.0001220703125000, -0.0025939941406250, -0.0006713867187500, -0.0021362304687500, +-0.0006713867187500}, +{0.0005187988281250, 0.0032348632812500, 0.0011291503906250, 0.0033874511718750, +0.0007934570312500, 0.0034179687500000, 0.0012817382812500, 0.0034484863281250, +0.0010070800781250, 0.0031738281250000, 0.0011901855468750, 0.0031127929687500, +0.0015258789062500, 0.0031433105468750, 0.0010375976562500, 0.0031127929687500, +0.0021362304687500, 0.0032653808593750, 0.0016784667968750, 0.0030822753906250, +0.0019531250000000, 0.0029602050781250, 0.0028991699218750, 0.0028686523437500, +0.0021667480468750, 0.0025329589843750, 0.0029907226562500, 0.0026855468750000, +0.0029602050781250, 0.0019836425781250, 0.0028381347656250, 0.0022888183593750, +0.0032653808593750, 0.0026550292968750, 0.0031127929687500, 0.0015869140625000, +0.0029602050781250, 0.0028686523437500, 0.0031738281250000, 0.0021667480468750, +0.0029602050781250, 0.0021972656250000, 0.0026855468750000, 0.0030212402343750, +0.0029602050781250, 0.0019531250000000, 0.0024108886718750, 0.0029602050781250, +0.0024719238281250, 0.0023803710937500, 0.0025024414062500, 0.0025939941406250, +0.0022583007812500, 0.0032958984375000, 0.0025329589843750, 0.0021057128906250, +0.0021972656250000, 0.0037841796875000, 0.0022888183593750, 0.0028991699218750, +0.0021362304687500, 0.0029296875000000, 0.0018615722656250, 0.0040893554687500, +0.0020751953125000, 0.0027160644531250, 0.0014953613281250, 0.0035705566406250, +0.0017395019531250, 0.0036010742187500, 0.0015258789062500, 0.0031433105468750, +0.0010375976562500, 0.0036010742187500, 0.0013122558593750, 0.0038452148437500, +0.0006103515625000, 0.0027770996093750, 0.0004577636718750, 0.0039978027343750, +0.0004272460937500, 0.0034484863281250, 0.0000915527343750, 0.0025024414062500, +0.0001220703125000, 0.0044250488281250, 0.0002746582031250, 0.0017700195312500, +0.0004272460937500, 0.0027465820312500, 0.0004272460937500, 0.0025939941406250, +0.0005493164062500, 0.0007934570312500, 0.0007934570312500, 0.0024108886718750, +0.0003051757812500, 0.0007019042968750, 0.0004577636718750, 0.0008850097656250, +0.0003662109375000, 0.0011901855468750, -0.0000305175781250, 0.0003662109375000, +0.0002136230468750, 0.0007324218750000, -0.0000915527343750, 0.0005493164062500, +0.0000610351562500, 0.0007324218750000, -0.0000305175781250, 0.0007019042968750, +-0.0002136230468750, 0.0006713867187500, 0.0001525878906250, 0.0010986328125000, +-0.0006713867187500, -0.0000915527343750, -0.0003662109375000, 0.0008239746093750, +-0.0004577636718750, 0.0000610351562500, -0.0010375976562500, -0.0013122558593750, +-0.0007019042968750, 0.0000610351562500, -0.0012512207031250, -0.0024108886718750, +-0.0011901855468750, -0.0019531250000000, -0.0014343261718750, -0.0018005371093750, +-0.0019226074218750, -0.0033264160156250, -0.0015258789062500, -0.0025024414062500, +-0.0020446777343750, -0.0022277832031250, -0.0020141601562500, -0.0026855468750000, +-0.0018005371093750, -0.0017395019531250, -0.0018310546875000, -0.0003356933593750, +-0.0017700195312500, -0.0006103515625000, -0.0016174316406250, 0.0006713867187500, +-0.0013122558593750, 0.0013122558593750, -0.0014953613281250, 0.0010681152343750, +-0.0016174316406250, 0.0011901855468750, -0.0010986328125000, 0.0014038085937500, +-0.0016784667968750, 0.0004272460937500, -0.0013732910156250, -0.0000915527343750, +-0.0010070800781250, -0.0005798339843750, -0.0010375976562500, -0.0014038085937500, +-0.0007324218750000, -0.0018005371093750, -0.0006408691406250, -0.0023193359375000, +0.0000915527343750, -0.0032348632812500, -0.0002746582031250, -0.0030517578125000, +-0.0008239746093750, -0.0029296875000000, 0.0000610351562500, -0.0038757324218750, +-0.0015563964843750, -0.0016784667968750, -0.0009155273437500, -0.0018005371093750, +-0.0013122558593750, -0.0013427734375000, -0.0025939941406250, 0.0003662109375000, +-0.0013732910156250, -0.0000305175781250, -0.0024108886718750, -0.0006408691406250, +-0.0022888183593750, 0.0001525878906250, -0.0018005371093750, -0.0008544921875000, +-0.0021667480468750, -0.0027770996093750, -0.0019531250000000, -0.0022277832031250, +-0.0014038085937500, -0.0025329589843750, -0.0018005371093750, -0.0038757324218750, +-0.0013427734375000, -0.0026855468750000, -0.0008850097656250, -0.0011901855468750, +-0.0016174316406250, -0.0027160644531250, 0.0001525878906250, -0.0010070800781250, +-0.0004577636718750, -0.0005187988281250, -0.0007934570312500, -0.0014953613281250, +0.0009155273437500, -0.0018615722656250, -0.0023193359375000, -0.0010986328125000, +-0.0030822753906250, -0.0003051757812500, -0.0030517578125000, -0.0000305175781250, +-0.0020751953125000, -0.0010986328125000, -0.0015869140625000, -0.0018005371093750, +-0.0018615722656250, -0.0010070800781250, -0.0003967285156250, -0.0020751953125000, +-0.0001220703125000, -0.0024108886718750, -0.0003051757812500, -0.0017395019531250, +0.0000915527343750, -0.0013732910156250, 0.0000915527343750, -0.0016479492187500, +-0.0000610351562500, -0.0018005371093750, 0.0000000000000000, -0.0011291503906250, +0.0000915527343750, -0.0018615722656250, 0.0002746582031250, -0.0028076171875000, +0.0003967285156250, -0.0019226074218750, 0.0000000000000000, -0.0029602050781250, +0.0007324218750000, -0.0032653808593750, -0.0001831054687500, -0.0024108886718750, +-0.0010375976562500, -0.0021362304687500, 0.0003356933593750, -0.0025634765625000, +-0.0031433105468750, -0.0018005371093750, -0.0026245117187500, -0.0014953613281250, +-0.0023193359375000, -0.0018615722656250, -0.0044555664062500, -0.0020751953125000, +-0.0036621093750000, -0.0019836425781250, -0.0024108886718750, -0.0023498535156250, +-0.0032348632812500, -0.0025024414062500, -0.0019226074218750, -0.0022277832031250, +0.0000915527343750, -0.0020751953125000, -0.0009155273437500, -0.0023498535156250, +0.0013427734375000, -0.0019531250000000, 0.0019836425781250, -0.0015563964843750, +0.0011901855468750, -0.0022583007812500, 0.0016479492187500, -0.0028076171875000, +0.0022277832031250, -0.0020751953125000, 0.0000000000000000, -0.0031127929687500, +0.0001831054687500, -0.0034484863281250, 0.0001831054687500, -0.0029602050781250, +-0.0010070800781250, -0.0027770996093750, -0.0004882812500000, -0.0029296875000000, +-0.0002136230468750, -0.0026550292968750, -0.0007629394531250, -0.0024414062500000, +0.0002441406250000, -0.0024719238281250, 0.0012207031250000, -0.0026245117187500, +0.0003356933593750, -0.0025939941406250, 0.0020751953125000, -0.0019226074218750, +0.0022888183593750, -0.0023498535156250, 0.0018005371093750, -0.0018005371093750, +0.0024719238281250, -0.0008544921875000, 0.0027770996093750, -0.0015258789062500, +0.0013732910156250, -0.0006103515625000, 0.0020141601562500, -0.0004882812500000, +0.0017395019531250, -0.0007629394531250, 0.0005798339843750, -0.0006713867187500, +0.0014953613281250, -0.0007019042968750, 0.0007019042968750, -0.0004882812500000, +0.0007934570312500, -0.0007934570312500, 0.0009460449218750, -0.0003356933593750, +0.0005798339843750, 0.0003051757812500, 0.0009765625000000, -0.0001525878906250, +0.0014343261718750, 0.0006103515625000, 0.0011596679687500, 0.0007324218750000, +0.0018615722656250, 0.0006713867187500, 0.0026245117187500, 0.0008850097656250, +0.0020446777343750, 0.0009765625000000, 0.0030822753906250, 0.0011596679687500, +0.0032958984375000, 0.0010986328125000, 0.0032043457031250, 0.0012512207031250, +0.0036926269531250, 0.0015563964843750, 0.0037841796875000, 0.0015563964843750, +0.0033264160156250, 0.0016174316406250, 0.0039367675781250, 0.0017700195312500, +0.0033874511718750, 0.0018310546875000, 0.0026245117187500, 0.0017700195312500, +0.0035705566406250, 0.0019531250000000, 0.0020446777343750, 0.0018005371093750, +0.0026550292968750, 0.0019836425781250, 0.0020751953125000, 0.0019836425781250, +0.0008850097656250, 0.0018615722656250, 0.0021667480468750, 0.0020751953125000, +-0.0003356933593750, 0.0017395019531250, 0.0008544921875000, 0.0017700195312500, +0.0004272460937500, 0.0019226074218750, -0.0013732910156250, 0.0017395019531250, +0.0007019042968750, 0.0018005371093750, -0.0016174316406250, 0.0020141601562500, +-0.0012817382812500, 0.0020141601562500, -0.0010070800781250, 0.0020751953125000, +-0.0022277832031250, 0.0023193359375000, -0.0014953613281250, 0.0022888183593750, +-0.0019836425781250, 0.0024108886718750, -0.0016479492187500, 0.0024414062500000, +-0.0015563964843750, 0.0025329589843750, -0.0016174316406250, 0.0026245117187500, +-0.0007324218750000, 0.0026550292968750, -0.0015563964843750, 0.0027770996093750, +-0.0009765625000000, 0.0028381347656250, -0.0007324218750000, 0.0027160644531250, +-0.0013427734375000, 0.0027160644531250, -0.0008544921875000, 0.0028076171875000, +-0.0006713867187500, 0.0026245117187500, -0.0008544921875000, 0.0026550292968750, +-0.0006103515625000, 0.0025024414062500, 0.0000000000000000, 0.0022888183593750, +0.0002441406250000, 0.0024719238281250, 0.0002136230468750, 0.0018615722656250, +0.0012207031250000, 0.0020446777343750, 0.0012817382812500, 0.0017700195312500, +0.0010986328125000, 0.0012817382812500, 0.0023803710937500, 0.0016174316406250, +0.0019836425781250, 0.0007324218750000, 0.0023193359375000, 0.0009155273437500, +0.0025939941406250, 0.0007324218750000, 0.0024108886718750, 0.0000610351562500, +0.0029907226562500, 0.0004272460937500, 0.0030517578125000, -0.0003051757812500, +0.0034179687500000, -0.0003051757812500, 0.0034484863281250, -0.0004272460937500, +0.0033874511718750, -0.0009460449218750, 0.0037536621093750, -0.0008239746093750, +0.0035705566406250, -0.0011291503906250, 0.0035095214843750, -0.0011596679687500, +0.0034484863281250, -0.0013427734375000, 0.0032043457031250, -0.0016479492187500, +0.0030517578125000, -0.0012817382812500, 0.0024719238281250, -0.0014038085937500, +0.0024719238281250, -0.0017089843750000, 0.0017395019531250, -0.0012817382812500, +0.0012817382812500, -0.0007934570312500, 0.0018615722656250, -0.0010986328125000, +0.0001525878906250, -0.0009460449218750, 0.0006713867187500, -0.0007324218750000, +0.0006103515625000, -0.0007019042968750, -0.0004272460937500, -0.0008544921875000, +0.0006408691406250, -0.0009155273437500, 0.0000305175781250, -0.0001220703125000, +0.0002746582031250, -0.0002441406250000, 0.0007629394531250, -0.0000915527343750, +0.0007019042968750, 0.0005493164062500, 0.0009155273437500, 0.0004272460937500, +0.0012817382812500, 0.0002136230468750, 0.0012512207031250, 0.0005798339843750, +0.0010070800781250, 0.0000305175781250, 0.0008850097656250, -0.0007934570312500, +0.0007019042968750, -0.0002441406250000, -0.0001831054687500, -0.0008850097656250, +-0.0002746582031250, -0.0014343261718750, -0.0004272460937500, -0.0010070800781250, +-0.0010375976562500, -0.0008544921875000, -0.0010375976562500, -0.0013732910156250, +-0.0003662109375000, -0.0003356933593750, -0.0010375976562500, -0.0005187988281250, +-0.0000305175781250, -0.0006408691406250, 0.0013122558593750, -0.0001831054687500, +0.0000305175781250, -0.0004272460937500, 0.0016174316406250, -0.0001220703125000, +0.0016174316406250, -0.0001525878906250, 0.0007019042968750, -0.0002136230468750, +0.0007019042968750, 0.0000915527343750, 0.0003356933593750, 0.0001831054687500, +-0.0013732910156250, -0.0006103515625000, -0.0011901855468750, -0.0001831054687500, +-0.0020141601562500, -0.0006103515625000, -0.0031433105468750, -0.0013732910156250, +-0.0018920898437500, -0.0007629394531250, -0.0033874511718750, -0.0020751953125000, +-0.0035095214843750, -0.0017395019531250, -0.0032348632812500, -0.0023498535156250, +-0.0036315917968750, -0.0032348632812500, -0.0033874511718750, -0.0018615722656250, +-0.0033874511718750}, +{0.0020751953125000, 0.0023498535156250, 0.0015563964843750, 0.0026550292968750, +0.0021057128906250, 0.0026855468750000, 0.0022583007812500, 0.0026245117187500, +0.0019531250000000, 0.0027160644531250, 0.0025329589843750, 0.0027160644531250, +0.0019531250000000, 0.0026245117187500, 0.0025329589843750, 0.0026855468750000, +0.0025024414062500, 0.0026855468750000, 0.0021972656250000, 0.0025939941406250, +0.0030822753906250, 0.0026550292968750, 0.0024719238281250, 0.0023803710937500, +0.0024719238281250, 0.0025634765625000, 0.0027465820312500, 0.0022888183593750, +0.0023498535156250, 0.0018310546875000, 0.0020141601562500, 0.0022277832031250, +0.0023498535156250, 0.0015563964843750, 0.0022277832031250, 0.0015563964843750, +0.0019226074218750, 0.0014343261718750, 0.0021972656250000, 0.0010375976562500, +0.0026855468750000, 0.0013122558593750, 0.0021057128906250, 0.0004882812500000, +0.0027465820312500, 0.0007629394531250, 0.0021667480468750, 0.0004882812500000, +0.0012512207031250, -0.0001831054687500, 0.0022277832031250, 0.0002746582031250, +0.0006713867187500, -0.0004577636718750, 0.0010375976562500, -0.0004272460937500, +0.0011901855468750, -0.0004272460937500, 0.0003967285156250, -0.0007019042968750, +0.0010375976562500, -0.0004272460937500, 0.0006103515625000, -0.0010986328125000, +0.0006408691406250, -0.0009155273437500, 0.0012817382812500, -0.0007934570312500, +0.0013427734375000, -0.0012512207031250, 0.0011596679687500, -0.0011291503906250, +0.0025634765625000, -0.0009155273437500, 0.0018615722656250, -0.0008850097656250, +0.0022277832031250, -0.0010375976562500, 0.0034790039062500, -0.0011596679687500, +0.0025634765625000, -0.0010375976562500, 0.0033874511718750, -0.0007934570312500, +0.0035400390625000, -0.0010986328125000, 0.0028381347656250, -0.0007629394531250, +0.0029907226562500, -0.0001831054687500, 0.0033569335937500, -0.0005187988281250, +0.0016784667968750, -0.0001831054687500, 0.0024414062500000, 0.0000305175781250, +0.0019531250000000, -0.0000915527343750, 0.0005493164062500, -0.0001220703125000, +0.0017089843750000, -0.0000610351562500, 0.0006408691406250, -0.0003967285156250, +0.0003662109375000, -0.0003662109375000, 0.0009155273437500, -0.0002746582031250, +0.0007934570312500, -0.0004577636718750, 0.0004577636718750, -0.0004577636718750, +0.0010375976562500, -0.0000915527343750, 0.0007934570312500, -0.0004272460937500, +0.0003967285156250, -0.0001525878906250, 0.0004882812500000, 0.0002746582031250, +0.0003051757812500, -0.0001831054687500, -0.0001831054687500, 0.0004577636718750, +-0.0006713867187500, 0.0003356933593750, -0.0001831054687500, 0.0002746582031250, +-0.0003051757812500, 0.0007019042968750, -0.0013732910156250, 0.0004882812500000, +0.0006408691406250, 0.0000610351562500, -0.0004882812500000, 0.0005187988281250, +0.0001831054687500, -0.0001831054687500, 0.0019531250000000, -0.0010986328125000, +0.0000305175781250, -0.0003356933593750, 0.0020751953125000, -0.0018005371093750, +0.0014038085937500, -0.0015258789062500, 0.0003356933593750, -0.0016784667968750, +0.0010681152343750, -0.0025024414062500, 0.0003356933593750, -0.0018920898437500, +-0.0010070800781250, -0.0026855468750000, -0.0006103515625000, -0.0020751953125000, +-0.0011291503906250, -0.0022277832031250, -0.0026245117187500, -0.0032348632812500, +-0.0022888183593750, -0.0024719238281250, -0.0023193359375000, -0.0024719238281250, +-0.0028076171875000, -0.0025329589843750, -0.0024719238281250, -0.0021972656250000, +-0.0018920898437500, -0.0021362304687500, -0.0021972656250000, -0.0024719238281250, +-0.0017089843750000, -0.0019531250000000, -0.0018005371093750, -0.0018920898437500, +-0.0017089843750000, -0.0021667480468750, -0.0015869140625000, -0.0023803710937500, +-0.0022277832031250, -0.0024414062500000, -0.0018615722656250, -0.0019226074218750, +-0.0020446777343750, -0.0018615722656250, -0.0023803710937500, -0.0018920898437500, +-0.0022277832031250, -0.0014038085937500, -0.0023498535156250, -0.0012207031250000, +-0.0033264160156250, -0.0018615722656250, -0.0029296875000000, -0.0016479492187500, +-0.0032653808593750, -0.0018920898437500, -0.0042114257812500, -0.0027465820312500, +-0.0036010742187500, -0.0026855468750000, -0.0037536621093750, -0.0030517578125000, +-0.0039062500000000, -0.0037231445312500, -0.0035400390625000, -0.0036621093750000, +-0.0030212402343750, -0.0036010742187500, -0.0027770996093750, -0.0042724609375000, +-0.0027770996093750, -0.0036621093750000, -0.0020446777343750, -0.0039367675781250, +-0.0019531250000000, -0.0037841796875000, -0.0020446777343750, -0.0029907226562500, +-0.0012512207031250, -0.0030822753906250, -0.0016784667968750, -0.0022583007812500, +-0.0013427734375000, -0.0017395019531250, -0.0008850097656250, -0.0014648437500000, +-0.0010986328125000, -0.0007934570312500, -0.0010681152343750, -0.0003662109375000, +-0.0002746582031250, -0.0008544921875000, -0.0008850097656250, 0.0000000000000000, +0.0000305175781250, -0.0002136230468750, 0.0012817382812500, -0.0009765625000000, +0.0001220703125000, 0.0000610351562500, 0.0016784667968750, -0.0008239746093750, +0.0019531250000000, -0.0004577636718750, 0.0012512207031250, -0.0001220703125000, +0.0014953613281250, -0.0001525878906250, 0.0017089843750000, 0.0007019042968750, +0.0003967285156250, -0.0000610351562500, 0.0003356933593750, 0.0011901855468750, +0.0002136230468750, 0.0007629394531250, -0.0005798339843750, -0.0000610351562500, +-0.0005493164062500, 0.0020141601562500, -0.0003662109375000, -0.0003967285156250, +-0.0006103515625000, 0.0005493164062500, -0.0008239746093750, 0.0007019042968750, +-0.0006408691406250, -0.0008239746093750, -0.0006103515625000, 0.0004577636718750, +-0.0013732910156250, -0.0006408691406250, -0.0014343261718750, -0.0006713867187500, +-0.0016479492187500, -0.0002441406250000, -0.0021972656250000, -0.0003356933593750, +-0.0021667480468750, -0.0001525878906250, -0.0019836425781250, -0.0000610351562500, +-0.0026550292968750, 0.0004882812500000, -0.0021057128906250, 0.0002136230468750, +-0.0014343261718750, -0.0000305175781250, -0.0023193359375000, 0.0007324218750000, +-0.0008544921875000, -0.0006408691406250, -0.0010986328125000, 0.0000610351562500, +-0.0009460449218750, 0.0000305175781250, -0.0000915527343750, -0.0008850097656250, +-0.0006408691406250, 0.0000915527343750, 0.0003967285156250, -0.0008850097656250, +0.0002746582031250, -0.0004882812500000, 0.0001525878906250, -0.0001831054687500, +0.0007324218750000, -0.0007324218750000, 0.0005187988281250, -0.0002136230468750, +0.0005187988281250, 0.0002441406250000, 0.0004882812500000, -0.0002441406250000, +0.0005187988281250, 0.0002136230468750, 0.0005493164062500, 0.0007019042968750, +0.0004272460937500, -0.0003051757812500, 0.0006713867187500, 0.0006103515625000, +0.0006713867187500, 0.0005187988281250, 0.0006408691406250, 0.0007629394531250, +0.0007934570312500, 0.0014038085937500, 0.0007629394531250, 0.0008544921875000, +0.0007629394531250, 0.0017089843750000, 0.0008850097656250, 0.0016784667968750, +0.0009460449218750, 0.0014648437500000, 0.0009155273437500, 0.0020751953125000, +0.0008850097656250, 0.0022888183593750, 0.0011596679687500, 0.0014343261718750, +0.0010375976562500, 0.0018005371093750, 0.0010681152343750, 0.0019531250000000, +0.0012207031250000, 0.0013427734375000, 0.0010681152343750, 0.0016479492187500, +0.0014953613281250, 0.0018615722656250, 0.0012512207031250, 0.0011291503906250, +0.0014953613281250, 0.0013427734375000, 0.0019226074218750, 0.0018005371093750, +0.0014648437500000, 0.0009460449218750, 0.0022583007812500, 0.0017700195312500, +0.0021057128906250, 0.0017089843750000, 0.0020446777343750, 0.0015258789062500, +0.0024414062500000, 0.0020141601562500, 0.0020751953125000, 0.0020446777343750, +0.0022583007812500, 0.0018920898437500, 0.0020751953125000, 0.0022277832031250, +0.0020141601562500, 0.0021667480468750, 0.0021057128906250, 0.0020446777343750, +0.0018310546875000, 0.0026855468750000, 0.0018005371093750, 0.0022583007812500, +0.0019226074218750, 0.0027770996093750, 0.0017089843750000, 0.0029296875000000, +0.0015869140625000, 0.0025939941406250, 0.0018005371093750, 0.0032043457031250, +0.0014038085937500, 0.0029296875000000, 0.0016174316406250, 0.0027160644531250, +0.0015258789062500, 0.0028686523437500, 0.0012817382812500, 0.0026855468750000, +0.0016174316406250, 0.0019836425781250, 0.0011291503906250, 0.0021362304687500, +0.0014343261718750, 0.0014648437500000, 0.0012817382812500, 0.0009765625000000, +0.0008239746093750, 0.0007629394531250, 0.0012512207031250, 0.0000610351562500, +0.0004577636718750, 0.0001525878906250, 0.0005187988281250, -0.0003967285156250, +0.0003051757812500, -0.0003356933593750, -0.0002746582031250, 0.0000915527343750, +0.0000305175781250, -0.0003051757812500, -0.0004272460937500, 0.0009765625000000, +-0.0003051757812500, 0.0008850097656250, -0.0003051757812500, 0.0016174316406250, +-0.0004882812500000, 0.0028991699218750, -0.0001831054687500, 0.0025024414062500, +-0.0007934570312500, 0.0041809082031250, -0.0004577636718750, 0.0042114257812500, +-0.0007324218750000, 0.0045166015625000, -0.0014343261718750, 0.0055541992187500, +-0.0010070800781250, 0.0050659179687500, -0.0018310546875000, 0.0052490234375000, +-0.0018005371093750, 0.0054626464843750, -0.0019531250000000, 0.0046081542968750, +-0.0023498535156250, 0.0041503906250000, -0.0020446777343750, 0.0044555664062500, +-0.0027770996093750, 0.0027160644531250, -0.0027160644531250, 0.0031738281250000, +-0.0026855468750000, 0.0026245117187500, -0.0030212402343750, 0.0013122558593750, +-0.0028381347656250, 0.0023803710937500, -0.0029296875000000, 0.0010375976562500, +-0.0029602050781250, 0.0016479492187500, -0.0026245117187500, 0.0016784667968750, +-0.0024719238281250, 0.0010070800781250, -0.0027770996093750, 0.0018615722656250, +-0.0015869140625000, 0.0002136230468750, -0.0018310546875000, 0.0010681152343750, +-0.0016479492187500, 0.0004272460937500, -0.0008850097656250, -0.0007934570312500, +-0.0013732910156250, 0.0009155273437500, -0.0010070800781250, -0.0013427734375000, +-0.0008544921875000, -0.0006408691406250, -0.0010681152343750, -0.0001525878906250, +-0.0012512207031250, -0.0012207031250000, -0.0013427734375000, -0.0002746582031250, +-0.0009460449218750, -0.0000915527343750, -0.0009460449218750, -0.0002441406250000, +-0.0015563964843750, 0.0005493164062500, -0.0016479492187500, 0.0013122558593750, +-0.0011901855468750, 0.0009460449218750, -0.0019531250000000, 0.0014038085937500, +-0.0018615722656250, 0.0012817382812500, -0.0018920898437500, 0.0004577636718750, +-0.0023803710937500, 0.0000305175781250, -0.0020141601562500, -0.0000610351562500, +-0.0021972656250000, -0.0015869140625000, -0.0021667480468750, -0.0019226074218750, +-0.0020751953125000, -0.0016479492187500, -0.0019836425781250, -0.0020446777343750, +-0.0018005371093750, -0.0020751953125000, -0.0025024414062500, -0.0002136230468750, +-0.0018920898437500, -0.0002136230468750, -0.0021057128906250, 0.0001831054687500, +-0.0030517578125000, 0.0018920898437500, -0.0021362304687500, 0.0018615722656250, +-0.0016174316406250, 0.0007324218750000, -0.0019531250000000, 0.0017700195312500, +-0.0009460449218750, 0.0015563964843750, 0.0011291503906250, -0.0005493164062500, +0.0031738281250000, 0.0032348632812500, 0.0017700195312500, 0.0025024414062500, +0.0022277832031250, 0.0039672851562500, 0.0017395019531250, 0.0032043457031250, +0.0008850097656250, 0.0017089843750000, 0.0011291503906250, 0.0025939941406250, +0.0010681152343750, 0.0022277832031250, 0.0015563964843750, 0.0015563964843750, +0.0003967285156250}, +{0.0007019042968750, -0.0001525878906250, 0.0006103515625000, 0.0006103515625000, +0.0006713867187500, 0.0016479492187500, 0.0008544921875000, 0.0003051757812500, +0.0003356933593750, 0.0027160644531250, 0.0006713867187500, 0.0015869140625000, +0.0003356933593750, 0.0018615722656250, -0.0002746582031250, 0.0033874511718750, +0.0004272460937500, 0.0014038085937500, -0.0007019042968750, 0.0033874511718750, +-0.0005187988281250, 0.0026550292968750, -0.0003662109375000, 0.0021667480468750, +-0.0009765625000000, 0.0030517578125000, -0.0006713867187500, 0.0018615722656250, +-0.0007019042968750, 0.0018920898437500, -0.0007019042968750, 0.0018920898437500, +-0.0009155273437500, 0.0012207031250000, -0.0009460449218750, 0.0008544921875000, +-0.0007019042968750, 0.0010986328125000, -0.0016174316406250, 0.0004272460937500, +-0.0013122558593750, 0.0003967285156250, -0.0014038085937500, 0.0008850097656250, +-0.0020751953125000, 0.0008850097656250, -0.0018005371093750, 0.0009155273437500, +-0.0023498535156250, 0.0022888183593750, -0.0024108886718750, 0.0021362304687500, +-0.0026245117187500, 0.0025329589843750, -0.0030517578125000, 0.0036621093750000, +-0.0030212402343750, 0.0034484863281250, -0.0032958984375000, 0.0042114257812500, +-0.0034484863281250, 0.0046691894531250, -0.0032958984375000, 0.0042724609375000, +-0.0033874511718750, 0.0042419433593750, -0.0035400390625000, 0.0046081542968750, +-0.0025939941406250, 0.0030517578125000, -0.0027465820312500, 0.0035400390625000, +-0.0024108886718750, 0.0030212402343750, -0.0015563964843750, 0.0015869140625000, +-0.0018005371093750, 0.0023193359375000, -0.0015869140625000, 0.0011901855468750, +-0.0013122558593750, 0.0009155273437500, -0.0014343261718750, 0.0009460449218750, +-0.0014953613281250, 0.0006713867187500, -0.0012207031250000, 0.0009155273437500, +-0.0014648437500000, 0.0002136230468750, -0.0011291503906250, 0.0007934570312500, +-0.0009765625000000, 0.0005493164062500, -0.0010375976562500, -0.0003662109375000, +-0.0005187988281250, 0.0003662109375000, -0.0012512207031250, -0.0005798339843750, +-0.0005187988281250, -0.0004577636718750, -0.0006713867187500, -0.0005187988281250, +-0.0013732910156250, -0.0013122558593750, -0.0004272460937500, -0.0010375976562500, +-0.0012512207031250, -0.0005187988281250, -0.0006713867187500, -0.0011291503906250, +-0.0006408691406250, -0.0002136230468750, -0.0011596679687500, 0.0006103515625000, +-0.0002441406250000, -0.0005798339843750, -0.0011901855468750, 0.0015563964843750, +-0.0007019042968750, 0.0009460449218750, -0.0007629394531250, 0.0007019042968750, +-0.0015563964843750, 0.0017089843750000, -0.0008239746093750, 0.0006408691406250, +-0.0006103515625000, 0.0005187988281250, -0.0010681152343750, 0.0003356933593750, +0.0003967285156250, 0.0003356933593750, 0.0018615722656250, 0.0001525878906250, +0.0009155273437500, -0.0002136230468750, 0.0030822753906250, 0.0017700195312500, +0.0035095214843750, 0.0014343261718750, 0.0028381347656250, 0.0015258789062500, +0.0030517578125000, 0.0037231445312500, 0.0011901855468750, 0.0004577636718750, +-0.0005493164062500, 0.0029296875000000, 0.0002441406250000, 0.0022277832031250, +-0.0003662109375000, 0.0026245117187500, -0.0011596679687500, 0.0045166015625000, +-0.0004272460937500, 0.0048828125000000, -0.0023803710937500, 0.0031127929687500, +-0.0021667480468750, 0.0041809082031250, -0.0018615722656250, 0.0040893554687500, +-0.0030517578125000, 0.0022277832031250, -0.0027160644531250, 0.0028381347656250, +-0.0010375976562500, 0.0027770996093750, -0.0016479492187500, 0.0025634765625000, +-0.0007934570312500, 0.0025329589843750, 0.0012207031250000, 0.0025939941406250, +0.0003662109375000, 0.0025329589843750, 0.0004577636718750, 0.0015869140625000, +0.0010681152343750, 0.0016479492187500, 0.0003356933593750, 0.0013732910156250, +-0.0009155273437500, 0.0003356933593750, -0.0004882812500000, 0.0003662109375000, +-0.0001525878906250, 0.0010681152343750, -0.0017700195312500, 0.0007019042968750, +-0.0005798339843750, 0.0007019042968750, 0.0009155273437500, 0.0016174316406250, +-0.0012817382812500, 0.0014953613281250, 0.0011901855468750, 0.0006713867187500, +0.0007934570312500, 0.0011291503906250, -0.0002746582031250, 0.0004577636718750, +0.0005493164062500, -0.0007629394531250, 0.0001831054687500, -0.0000610351562500, +-0.0013427734375000, -0.0008239746093750, -0.0011291503906250, -0.0010070800781250, +-0.0010375976562500, -0.0010375976562500, -0.0021362304687500, -0.0010070800781250, +-0.0017700195312500, -0.0006103515625000, 0.0002746582031250, -0.0017089843750000, +-0.0003662109375000, -0.0014343261718750, 0.0005493164062500, -0.0014953613281250, +0.0026855468750000, -0.0022888183593750, 0.0018310546875000, -0.0020446777343750, +0.0031127929687500, -0.0022277832031250, 0.0036621093750000, -0.0023193359375000, +0.0032348632812500, -0.0023193359375000, 0.0036010742187500, -0.0023193359375000, +0.0039978027343750, -0.0022277832031250, 0.0022277832031250, -0.0026855468750000, +0.0030517578125000, -0.0025024414062500, 0.0024108886718750, -0.0025939941406250, +0.0007629394531250, -0.0031738281250000, 0.0020446777343750, -0.0029296875000000, +0.0009460449218750, -0.0026550292968750, 0.0009460449218750, -0.0029907226562500, +0.0016174316406250, -0.0025634765625000, 0.0015563964843750, -0.0019531250000000, +0.0017395019531250, -0.0023193359375000, 0.0024719238281250, -0.0016174316406250, +0.0024108886718750, -0.0016784667968750, 0.0026550292968750, -0.0014648437500000, +0.0032348632812500, -0.0009765625000000, 0.0028991699218750, -0.0014038085937500, +0.0031738281250000, -0.0003967285156250, 0.0036621093750000, -0.0005493164062500, +0.0029296875000000, -0.0005798339843750, 0.0025939941406250, -0.0000305175781250, +0.0035095214843750, -0.0003051757812500, 0.0013732910156250, -0.0002441406250000, +0.0020751953125000, -0.0003662109375000, 0.0014038085937500, -0.0003662109375000, +-0.0002746582031250, -0.0003662109375000, 0.0010070800781250, -0.0006713867187500, +-0.0011291503906250, -0.0002441406250000, -0.0008544921875000, -0.0004272460937500, +-0.0010681152343750, -0.0004882812500000, -0.0023193359375000, -0.0003051757812500, +-0.0014648437500000, -0.0004882812500000, -0.0029907226562500, -0.0001220703125000, +-0.0027160644531250, -0.0004577636718750, -0.0024719238281250, -0.0001525878906250, +-0.0032043457031250, 0.0002746582031250, -0.0025939941406250, -0.0001525878906250, +-0.0025329589843750, 0.0006103515625000, -0.0028686523437500, 0.0005798339843750, +-0.0024108886718750, 0.0006713867187500, -0.0020751953125000, 0.0009765625000000, +-0.0025939941406250, 0.0007324218750000, -0.0015869140625000, 0.0013427734375000, +-0.0019531250000000, 0.0009460449218750, -0.0016784667968750, 0.0011291503906250, +-0.0010070800781250, 0.0017700195312500, -0.0018005371093750, 0.0012207031250000, +-0.0008850097656250, 0.0018615722656250, -0.0010986328125000, 0.0017700195312500, +-0.0010986328125000, 0.0016174316406250, -0.0004882812500000, 0.0018920898437500, +-0.0008239746093750, 0.0016174316406250, -0.0004882812500000, 0.0015869140625000, +-0.0005187988281250, 0.0015258789062500, -0.0006408691406250, 0.0013732910156250, +-0.0007019042968750, 0.0011901855468750, -0.0008239746093750, 0.0011596679687500, +-0.0009765625000000, 0.0011291503906250, -0.0010070800781250, 0.0010375976562500, +-0.0011291503906250, 0.0008850097656250, -0.0010986328125000, 0.0008544921875000, +-0.0007324218750000, 0.0009155273437500, -0.0012512207031250, 0.0003662109375000, +-0.0009765625000000, 0.0005798339843750, -0.0007934570312500, 0.0003051757812500, +-0.0014648437500000, -0.0002136230468750, -0.0016174316406250, 0.0001220703125000, +-0.0010681152343750, -0.0005798339843750, -0.0020446777343750, -0.0005187988281250, +-0.0017395019531250, -0.0005798339843750, -0.0008850097656250, -0.0009765625000000, +-0.0018920898437500, -0.0006713867187500, -0.0005798339843750, -0.0011291503906250, +-0.0005798339843750, -0.0011901855468750, -0.0005798339843750, -0.0007934570312500, +0.0001831054687500, -0.0007629394531250, 0.0000610351562500, -0.0010070800781250, +0.0007019042968750, -0.0005187988281250, 0.0007019042968750, -0.0002746582031250, +0.0009460449218750, -0.0005798339843750, 0.0015258789062500, -0.0007019042968750, +0.0014953613281250, -0.0003662109375000, 0.0020141601562500, -0.0006408691406250, +0.0023193359375000, -0.0006103515625000, 0.0025024414062500, -0.0005187988281250, +0.0027770996093750, -0.0005493164062500, 0.0028076171875000, -0.0003967285156250, +0.0030517578125000, -0.0004882812500000, 0.0028991699218750, -0.0004882812500000, +0.0027770996093750, -0.0003662109375000, 0.0027465820312500, -0.0002441406250000, +0.0024414062500000, -0.0002746582031250, 0.0023193359375000, -0.0004272460937500, +0.0022277832031250, -0.0002441406250000, 0.0020141601562500, -0.0002746582031250, +0.0020751953125000, -0.0006103515625000, 0.0022888183593750, -0.0003967285156250, +0.0019226074218750, -0.0000610351562500, 0.0028076171875000, -0.0002746582031250, +0.0025329589843750, 0.0002746582031250, 0.0021972656250000, 0.0010375976562500, +0.0037231445312500, 0.0007019042968750, 0.0020751953125000, 0.0010986328125000, +0.0028686523437500, 0.0017700195312500, 0.0026855468750000, 0.0014038085937500, +0.0014343261718750, 0.0011291503906250, 0.0025024414062500, 0.0018615722656250, +0.0006713867187500, 0.0001525878906250, 0.0007934570312500, 0.0008544921875000, +0.0007324218750000, 0.0005493164062500, -0.0003356933593750, -0.0008239746093750, +0.0001525878906250, 0.0000000000000000, -0.0001525878906250, -0.0011901855468750, +-0.0003967285156250, -0.0010681152343750, -0.0000610351562500, -0.0010986328125000, +0.0003051757812500, -0.0016479492187500, 0.0003356933593750, -0.0010070800781250, +0.0005187988281250, -0.0013427734375000, 0.0012817382812500, -0.0010375976562500, +0.0014038085937500, -0.0013122558593750, 0.0010070800781250, -0.0019531250000000, +0.0012817382812500, -0.0014038085937500, 0.0013427734375000, -0.0019836425781250, +0.0013427734375000, -0.0024719238281250, 0.0013427734375000, -0.0024108886718750, +0.0012817382812500, -0.0025939941406250, 0.0015258789062500, -0.0028381347656250, +0.0012817382812500, -0.0018615722656250, 0.0016784667968750, -0.0022888183593750, +0.0013122558593750, -0.0021972656250000, 0.0003967285156250, -0.0015258789062500, +0.0004577636718750, -0.0019226074218750, -0.0000305175781250, -0.0007629394531250, +-0.0009155273437500, -0.0010070800781250, -0.0008544921875000, -0.0010681152343750, +-0.0004272460937500, -0.0002136230468750, -0.0007934570312500, -0.0005798339843750, +-0.0000610351562500, -0.0017089843750000, -0.0005187988281250, -0.0012207031250000, +-0.0006408691406250, -0.0010375976562500, -0.0000610351562500, -0.0016479492187500, +-0.0005798339843750, -0.0014038085937500, -0.0004577636718750, -0.0017089843750000, +-0.0013122558593750, -0.0019836425781250, -0.0010986328125000, -0.0018615722656250, +-0.0006408691406250, -0.0018920898437500, -0.0018920898437500, -0.0020751953125000, +-0.0011901855468750, -0.0016479492187500, -0.0014038085937500, -0.0011291503906250, +-0.0021362304687500, -0.0012207031250000, -0.0024108886718750, -0.0006713867187500, +-0.0028076171875000, 0.0004882812500000, -0.0027465820312500, -0.0007629394531250, +-0.0033569335937500, 0.0003356933593750, -0.0028686523437500, 0.0004577636718750, +-0.0019836425781250, -0.0008239746093750, -0.0027465820312500, -0.0001220703125000, +-0.0017700195312500, -0.0003662109375000, -0.0011291503906250, -0.0011901855468750, +-0.0016479492187500, -0.0003356933593750, -0.0015869140625000, 0.0004272460937500, +-0.0007019042968750}, +{-0.0007019042968750, -0.0007629394531250, -0.0006408691406250, -0.0006408691406250, +-0.0006408691406250, -0.0006408691406250, -0.0005187988281250, -0.0005493164062500, +-0.0003967285156250, -0.0003356933593750, -0.0002136230468750, -0.0003662109375000, +0.0003051757812500, -0.0002746582031250, 0.0006713867187500, -0.0000610351562500, +0.0008850097656250, 0.0001525878906250, 0.0016174316406250, -0.0000610351562500, +0.0021362304687500, -0.0002746582031250, 0.0019531250000000, 0.0001220703125000, +0.0029907226562500, -0.0002136230468750, 0.0029907226562500, -0.0004272460937500, +0.0028076171875000, 0.0000305175781250, 0.0032348632812500, 0.0002136230468750, +0.0030822753906250, -0.0000915527343750, 0.0021667480468750, 0.0007934570312500, +0.0028381347656250, 0.0008850097656250, 0.0020751953125000, 0.0007019042968750, +0.0012512207031250, 0.0011291503906250, 0.0027160644531250, 0.0011596679687500, +0.0006103515625000, 0.0006408691406250, 0.0017395019531250, 0.0009460449218750, +0.0021362304687500, 0.0005493164062500, 0.0010681152343750, 0.0000610351562500, +0.0026855468750000, 0.0006713867187500, 0.0016784667968750, -0.0006103515625000, +0.0022583007812500, -0.0003051757812500, 0.0022888183593750, -0.0002746582031250, +0.0016174316406250, -0.0009155273437500, 0.0022888183593750, -0.0002441406250000, +0.0007324218750000, -0.0006713867187500, 0.0010681152343750, -0.0005798339843750, +0.0009765625000000, -0.0003356933593750, -0.0001831054687500, -0.0003356933593750, +0.0001831054687500, -0.0003662109375000, 0.0003051757812500, -0.0010375976562500, +0.0003051757812500, -0.0009460449218750, 0.0006408691406250, -0.0011291503906250, +0.0013122558593750, -0.0019226074218750, 0.0018005371093750, -0.0021972656250000, +0.0018005371093750, -0.0018615722656250, 0.0022277832031250, -0.0024414062500000, +0.0019226074218750, -0.0017395019531250, 0.0017089843750000, -0.0008850097656250, +0.0022888183593750, -0.0020141601562500, 0.0007934570312500, -0.0006408691406250, +0.0012207031250000, -0.0007934570312500, 0.0012512207031250, -0.0005798339843750, +0.0004882812500000, 0.0002441406250000, 0.0012512207031250, -0.0004882812500000, +0.0006103515625000, 0.0001525878906250, 0.0004577636718750, 0.0004577636718750, +0.0003356933593750, 0.0003967285156250, 0.0002746582031250, -0.0001831054687500, +0.0006408691406250, -0.0012512207031250, -0.0002441406250000, -0.0007019042968750, +-0.0000305175781250, -0.0010681152343750, 0.0002441406250000, -0.0012207031250000, +0.0000000000000000, -0.0010986328125000, 0.0001831054687500, -0.0018005371093750, +-0.0003051757812500, -0.0011901855468750, 0.0002136230468750, -0.0011291503906250, +-0.0000915527343750, -0.0013732910156250, -0.0010986328125000, -0.0007934570312500, +-0.0006408691406250, -0.0002136230468750, -0.0009765625000000, -0.0011901855468750, +-0.0015258789062500, 0.0000305175781250, -0.0014038085937500, 0.0000305175781250, +-0.0013122558593750, -0.0011596679687500, -0.0018920898437500, 0.0000915527343750, +-0.0014038085937500, -0.0002441406250000, -0.0021057128906250, -0.0011291503906250, +-0.0019836425781250, -0.0003662109375000, -0.0016784667968750, 0.0000610351562500, +-0.0027160644531250, -0.0011596679687500, -0.0009460449218750, 0.0007629394531250, +-0.0015869140625000, 0.0005798339843750, -0.0015258789062500, 0.0003662109375000, +0.0000000000000000, 0.0015869140625000, -0.0007019042968750, 0.0016479492187500, +-0.0008239746093750, 0.0010986328125000, 0.0001220703125000, 0.0018005371093750, +-0.0003356933593750, 0.0017395019531250, -0.0011291503906250, 0.0012512207031250, +-0.0000610351562500, 0.0021362304687500, -0.0005493164062500, 0.0016784667968750, +-0.0002746582031250, 0.0019531250000000, 0.0002746582031250, 0.0019836425781250, +0.0003967285156250, 0.0016174316406250, 0.0006103515625000, 0.0017395019531250, +0.0008544921875000, 0.0008850097656250, 0.0014038085937500, 0.0009155273437500, +0.0009155273437500, 0.0003967285156250, 0.0007324218750000, -0.0006103515625000, +0.0015869140625000, -0.0002136230468750, -0.0003662109375000, -0.0005798339843750, +0.0001220703125000, -0.0008544921875000, 0.0002441406250000, -0.0003051757812500, +-0.0010070800781250, 0.0000915527343750, -0.0003967285156250, -0.0003356933593750, +-0.0006103515625000, 0.0004272460937500, -0.0007629394531250, 0.0008850097656250, +-0.0004272460937500, 0.0005798339843750, -0.0001831054687500, 0.0007629394531250, +-0.0003356933593750, 0.0013732910156250, -0.0003967285156250, 0.0000305175781250, +0.0000305175781250, 0.0005798339843750, -0.0000305175781250, 0.0003356933593750, +-0.0002746582031250, -0.0009155273437500, -0.0000305175781250, -0.0003356933593750, +-0.0001525878906250, -0.0007629394531250, -0.0000610351562500, -0.0011901855468750, +-0.0001525878906250, -0.0010070800781250, -0.0003662109375000, -0.0010375976562500, +-0.0002136230468750, -0.0013122558593750, -0.0004882812500000, -0.0007629394531250, +-0.0004577636718750, -0.0010681152343750, -0.0004577636718750, -0.0008850097656250, +-0.0005187988281250, -0.0004882812500000, -0.0004272460937500, -0.0010375976562500, +-0.0004577636718750, -0.0005493164062500, -0.0003662109375000, -0.0004577636718750, +-0.0003356933593750, -0.0010070800781250, -0.0002746582031250, -0.0009765625000000, +-0.0001831054687500, -0.0006103515625000, -0.0003662109375000, -0.0013732910156250, +-0.0000305175781250, -0.0011901855468750, 0.0000000000000000, -0.0014648437500000, +-0.0003051757812500, -0.0021667480468750, -0.0000610351562500, -0.0019836425781250, +-0.0001525878906250, -0.0025634765625000, -0.0001525878906250, -0.0031127929687500, +-0.0000305175781250, -0.0030822753906250, -0.0001525878906250, -0.0034484863281250, +-0.0002136230468750, -0.0043334960937500, -0.0000610351562500, -0.0038757324218750, +-0.0002746582031250, -0.0040283203125000, -0.0001525878906250, -0.0045776367187500, +0.0000915527343750, -0.0046691894531250, -0.0002441406250000, -0.0047912597656250, +0.0001525878906250, -0.0056152343750000, 0.0001220703125000, -0.0052795410156250, +-0.0000305175781250, -0.0052795410156250, 0.0002441406250000, -0.0057678222656250, +0.0002746582031250, -0.0052795410156250, -0.0000305175781250, -0.0052185058593750, +0.0000610351562500, -0.0054016113281250, 0.0000305175781250, -0.0051574707031250, +-0.0001525878906250, -0.0050048828125000, -0.0000915527343750, -0.0054626464843750, +-0.0000610351562500, -0.0049438476562500, 0.0000000000000000, -0.0051879882812500, +0.0001220703125000, -0.0050964355468750, 0.0002136230468750, -0.0048828125000000, +0.0003967285156250, -0.0055541992187500, 0.0002441406250000, -0.0045776367187500, +0.0006408691406250, -0.0055847167968750, 0.0003967285156250, -0.0052185058593750, +0.0001831054687500, -0.0043945312500000, 0.0006713867187500, -0.0060119628906250, +-0.0002746582031250, -0.0040588378906250, 0.0000305175781250, -0.0048217773437500, +-0.0003051757812500, -0.0046386718750000, -0.0010986328125000, -0.0031433105468750, +-0.0004882812500000, -0.0042419433593750, -0.0012512207031250, -0.0027465820312500, +-0.0011596679687500, -0.0028381347656250, -0.0010986328125000, -0.0025939941406250, +-0.0012817382812500, -0.0017089843750000, -0.0007629394531250, -0.0023803710937500, +-0.0017700195312500, -0.0011901855468750, -0.0010070800781250, -0.0017395019531250, +-0.0014953613281250, -0.0015869140625000, -0.0025634765625000, -0.0009155273437500, +-0.0013732910156250, -0.0021362304687500, -0.0029296875000000, -0.0010070800781250, +-0.0025329589843750, -0.0018920898437500, -0.0024108886718750, -0.0018005371093750, +-0.0030822753906250, -0.0010681152343750, -0.0022583007812500, -0.0025634765625000, +-0.0031127929687500, -0.0003662109375000, -0.0027770996093750, -0.0013427734375000, +-0.0025634765625000, -0.0007629394531250, -0.0028991699218750, 0.0012207031250000, +-0.0022888183593750, -0.0003662109375000, -0.0022277832031250, 0.0021667480468750, +-0.0017089843750000, 0.0021362304687500, -0.0014953613281250, 0.0020141601562500, +-0.0014038085937500, 0.0033874511718750, -0.0006408691406250, 0.0030822753906250, +-0.0011596679687500, 0.0032043457031250, -0.0007019042968750, 0.0039672851562500, +-0.0006103515625000, 0.0030822753906250, -0.0009765625000000, 0.0024108886718750, +-0.0002136230468750, 0.0034790039062500, -0.0011596679687500, 0.0009155273437500, +-0.0006408691406250, 0.0012817382812500, -0.0006713867187500, 0.0012207031250000, +-0.0012817382812500, -0.0005493164062500, -0.0005493164062500, 0.0001220703125000, +-0.0014953613281250, 0.0004577636718750, -0.0012512207031250, -0.0001525878906250, +-0.0011291503906250, 0.0005798339843750, -0.0017395019531250, 0.0013122558593750, +-0.0014343261718750, 0.0002441406250000, -0.0013732910156250, 0.0017395019531250, +-0.0016174316406250, 0.0013732910156250, -0.0014038085937500, 0.0011291503906250, +-0.0012512207031250, 0.0019226074218750, -0.0015869140625000, 0.0013732910156250, +-0.0006713867187500, 0.0010986328125000, -0.0010375976562500, 0.0012207031250000, +-0.0001831054687500, 0.0004577636718750, 0.0008544921875000, -0.0002136230468750, +-0.0003051757812500, 0.0003356933593750, 0.0016784667968750, -0.0002136230468750, +0.0015258789062500, -0.0003356933593750, 0.0015258789062500, -0.0000915527343750, +0.0027160644531250, -0.0001220703125000, 0.0022888183593750, -0.0000915527343750, +0.0027160644531250, -0.0003662109375000, 0.0027465820312500, 0.0000610351562500, +0.0027160644531250, -0.0007019042968750, 0.0029602050781250, -0.0016479492187500, +0.0026550292968750, -0.0009155273437500, 0.0020751953125000, -0.0019836425781250, +0.0021972656250000, -0.0030517578125000, 0.0015258789062500, -0.0014953613281250, +0.0006408691406250, -0.0007019042968750, 0.0009765625000000, -0.0022277832031250, +-0.0003662109375000, 0.0013427734375000, 0.0000000000000000, 0.0011596679687500, +-0.0002746582031250, 0.0006408691406250, -0.0021057128906250, 0.0030822753906250, +-0.0009460449218750, -0.0010681152343750, 0.0000000000000000, 0.0025634765625000, +0.0003662109375000, 0.0014038085937500, -0.0000305175781250, 0.0017395019531250, +0.0000000000000000, 0.0030822753906250, 0.0005493164062500, 0.0024719238281250, +-0.0013427734375000, 0.0026245117187500, -0.0011901855468750, 0.0021057128906250, +-0.0009765625000000, 0.0024414062500000, -0.0022277832031250, 0.0031127929687500, +-0.0022888183593750, 0.0025024414062500, -0.0006713867187500, 0.0033569335937500, +-0.0015563964843750, 0.0037231445312500, -0.0006713867187500, 0.0032958984375000, +0.0014038085937500, 0.0033874511718750, 0.0000610351562500, 0.0036010742187500, +0.0009155273437500, 0.0020446777343750, 0.0015563964843750, 0.0023193359375000, +0.0002136230468750, 0.0023193359375000, -0.0006713867187500, 0.0013427734375000, +0.0001525878906250, 0.0015869140625000, -0.0016479492187500, 0.0016479492187500, +-0.0019531250000000, 0.0017089843750000, -0.0011596679687500, 0.0013427734375000, +-0.0010986328125000, 0.0010986328125000, -0.0010070800781250, 0.0014038085937500, +0.0000610351562500, 0.0004272460937500, 0.0005187988281250, 0.0006103515625000, +0.0004882812500000, 0.0006408691406250, 0.0010986328125000, -0.0000305175781250, +0.0015869140625000, 0.0002746582031250, 0.0000000000000000, 0.0007629394531250, +0.0010070800781250, 0.0006103515625000, 0.0002746582031250, 0.0004577636718750, +-0.0016174316406250, 0.0007934570312500, -0.0002136230468750, 0.0007019042968750, +-0.0013732910156250, -0.0000915527343750, -0.0015869140625000, 0.0001525878906250, +-0.0008850097656250, -0.0002746582031250, -0.0006408691406250, -0.0009460449218750, +-0.0003967285156250, -0.0004577636718750, -0.0001525878906250, -0.0010986328125000, +0.0006408691406250}, +{-0.0006103515625000, 0.0021972656250000, -0.0002136230468750, 0.0028991699218750, +-0.0004882812500000, 0.0021362304687500, -0.0015258789062500, 0.0024108886718750, +-0.0007019042968750, 0.0029296875000000, -0.0015869140625000, 0.0004882812500000, +-0.0018615722656250, 0.0012817382812500, -0.0015258789062500, 0.0009155273437500, +-0.0015869140625000, -0.0010986328125000, -0.0016174316406250, -0.0001220703125000, +-0.0015258789062500, -0.0004882812500000, -0.0012817382812500, -0.0013122558593750, +-0.0011901855468750, -0.0006103515625000, -0.0011291503906250, -0.0000610351562500, +-0.0007019042968750, -0.0006103515625000, -0.0003051757812500, 0.0010375976562500, +-0.0001220703125000, 0.0010070800781250, 0.0007324218750000, 0.0008544921875000, +0.0017395019531250, 0.0018310546875000, 0.0016479492187500, 0.0019226074218750, +0.0017395019531250, 0.0012512207031250, 0.0024719238281250, 0.0021667480468750, +0.0023803710937500, 0.0016174316406250, 0.0020141601562500, 0.0006103515625000, +0.0026245117187500, 0.0016479492187500, 0.0023193359375000, 0.0000610351562500, +0.0020751953125000, 0.0001831054687500, 0.0018920898437500, 0.0004272460937500, +0.0017089843750000, -0.0000915527343750, 0.0015563964843750, 0.0003051757812500, +0.0007629394531250, -0.0004882812500000, 0.0010681152343750, 0.0002746582031250, +0.0003967285156250, -0.0003662109375000, -0.0003356933593750, -0.0016479492187500, +0.0005493164062500, -0.0005187988281250, -0.0011596679687500, -0.0013122558593750, +-0.0012207031250000, -0.0019531250000000, -0.0005187988281250, -0.0008850097656250, +-0.0008850097656250, 0.0005493164062500, 0.0005798339843750, -0.0004272460937500, +-0.0011596679687500, -0.0009155273437500, -0.0007324218750000, -0.0015869140625000, +-0.0009155273437500, -0.0002746582031250, -0.0019531250000000, 0.0007019042968750, +-0.0018920898437500, -0.0002136230468750, -0.0004272460937500, 0.0023498535156250, +-0.0012207031250000, 0.0024108886718750, -0.0005493164062500, 0.0023193359375000, +0.0013732910156250, 0.0033874511718750, 0.0006103515625000, 0.0028686523437500, +0.0009155273437500, 0.0028991699218750, 0.0017395019531250, 0.0030212402343750, +0.0007629394531250, 0.0029296875000000, -0.0003662109375000, 0.0027770996093750, +0.0004272460937500, 0.0028076171875000, -0.0007324218750000, 0.0030517578125000, +-0.0013427734375000, 0.0032958984375000, -0.0003051757812500, 0.0024414062500000, +0.0003051757812500, 0.0020751953125000, -0.0002746582031250, 0.0028686523437500, +0.0014648437500000, 0.0010375976562500, 0.0025024414062500, 0.0010681152343750, +0.0014953613281250, 0.0012512207031250, 0.0014953613281250, 0.0003356933593750, +0.0029602050781250, 0.0005493164062500, -0.0001220703125000, 0.0008544921875000, +0.0009155273437500, 0.0006408691406250, 0.0007324218750000, 0.0005187988281250, +-0.0014343261718750, 0.0008239746093750, 0.0000915527343750, 0.0008850097656250, +-0.0004272460937500, 0.0000305175781250, -0.0006103515625000, 0.0000610351562500, +0.0003356933593750, 0.0004272460937500, 0.0010375976562500, 0.0001220703125000, +0.0008544921875000, -0.0001831054687500, 0.0010986328125000, 0.0007629394531250, +0.0019531250000000, 0.0005798339843750, 0.0010681152343750, 0.0002746582031250, +0.0001220703125000, 0.0006408691406250, 0.0009765625000000, 0.0004272460937500, +-0.0012207031250000, -0.0004577636718750, -0.0009460449218750, -0.0003051757812500, +-0.0012512207031250, -0.0004882812500000, -0.0028991699218750, -0.0011596679687500, +-0.0023498535156250, -0.0008850097656250, -0.0027160644531250, -0.0009460449218750, +-0.0036926269531250, -0.0008850097656250, -0.0029907226562500, -0.0010986328125000, +-0.0024108886718750, -0.0011901855468750, -0.0036621093750000, -0.0008850097656250, +-0.0020751953125000, -0.0017700195312500, -0.0023803710937500, -0.0017700195312500, +-0.0028686523437500, -0.0016174316406250, -0.0021667480468750, -0.0019531250000000, +-0.0024414062500000, -0.0020141601562500, -0.0032043457031250, -0.0018310546875000, +-0.0028686523437500, -0.0018005371093750, -0.0034179687500000, -0.0020751953125000, +-0.0042114257812500, -0.0021972656250000, -0.0036926269531250, -0.0021972656250000, +-0.0050964355468750, -0.0025024414062500, -0.0051269531250000, -0.0026550292968750, +-0.0050659179687500, -0.0025329589843750, -0.0058898925781250, -0.0025329589843750, +-0.0058288574218750, -0.0026855468750000, -0.0054626464843750, -0.0024414062500000, +-0.0058593750000000, -0.0024414062500000, -0.0053405761718750, -0.0024108886718750, +-0.0046691894531250, -0.0023193359375000, -0.0051879882812500, -0.0023498535156250, +-0.0038452148437500, -0.0018920898437500, -0.0038757324218750, -0.0020751953125000, +-0.0036315917968750, -0.0018310546875000, -0.0026855468750000, -0.0012512207031250, +-0.0029296875000000, -0.0014953613281250, -0.0019226074218750, -0.0011291503906250, +-0.0015563964843750, -0.0010375976562500, -0.0014343261718750, -0.0010986328125000, +-0.0008850097656250, -0.0010986328125000, -0.0005798339843750, -0.0010375976562500, +-0.0006103515625000, -0.0009460449218750, -0.0002441406250000, -0.0010070800781250, +-0.0002746582031250, -0.0009460449218750, -0.0003356933593750, -0.0008239746093750, +0.0001220703125000, -0.0008544921875000, -0.0003967285156250, -0.0007019042968750, +-0.0002136230468750, -0.0007324218750000, -0.0000915527343750, -0.0005798339843750, +-0.0007934570312500, -0.0004272460937500, -0.0010070800781250, -0.0003662109375000, +-0.0006713867187500, -0.0000610351562500, -0.0008544921875000, 0.0000610351562500, +-0.0009155273437500, 0.0000305175781250, -0.0007019042968750, 0.0001831054687500, +-0.0008544921875000, 0.0003356933593750, -0.0008850097656250, -0.0002136230468750, +-0.0010070800781250, 0.0000305175781250, -0.0010070800781250, -0.0001220703125000, +-0.0010375976562500, -0.0006408691406250, -0.0012817382812500, -0.0004272460937500, +-0.0008544921875000, -0.0005798339843750, -0.0008850097656250, -0.0007019042968750, +-0.0007934570312500, -0.0006103515625000, -0.0003662109375000, -0.0006408691406250, +-0.0002441406250000, -0.0006713867187500, -0.0002746582031250, -0.0005798339843750, +0.0000305175781250, -0.0007629394531250, -0.0000915527343750, -0.0005798339843750, +-0.0002746582031250, -0.0004577636718750, -0.0001525878906250, -0.0007629394531250, +-0.0009765625000000, -0.0004272460937500, -0.0004272460937500, -0.0002746582031250, +-0.0009460449218750, -0.0005798339843750, -0.0013732910156250, -0.0005187988281250, +0.0000305175781250, -0.0001525878906250, -0.0018920898437500, -0.0007019042968750, +-0.0010986328125000, -0.0006408691406250, -0.0007629394531250, -0.0004577636718750, +-0.0023193359375000, -0.0006103515625000, -0.0018005371093750, -0.0004577636718750, +-0.0015869140625000, -0.0005493164062500, -0.0026550292968750, -0.0003356933593750, +-0.0022277832031250, -0.0003662109375000, -0.0014343261718750, -0.0004577636718750, +-0.0024108886718750, -0.0002746582031250, -0.0014343261718750, -0.0004882812500000, +-0.0018005371093750, -0.0003662109375000, -0.0017700195312500, -0.0004272460937500, +-0.0012512207031250, -0.0007324218750000, -0.0020446777343750, -0.0006713867187500, +-0.0010375976562500, -0.0005187988281250, -0.0011901855468750, -0.0008239746093750, +-0.0012512207031250, -0.0005798339843750, -0.0006408691406250, -0.0003356933593750, +-0.0008239746093750, -0.0007019042968750, -0.0006408691406250, 0.0002136230468750, +-0.0004882812500000, -0.0000610351562500, -0.0002136230468750, 0.0001831054687500, +-0.0002136230468750, 0.0009460449218750, -0.0003967285156250, 0.0003967285156250, +0.0004882812500000, 0.0011901855468750, -0.0002441406250000, 0.0010375976562500, +0.0003051757812500, 0.0008544921875000, 0.0011901855468750, 0.0011596679687500, +0.0000610351562500, 0.0009155273437500, 0.0018920898437500, 0.0007019042968750, +0.0014648437500000, 0.0004882812500000, 0.0015258789062500, 0.0006103515625000, +0.0028076171875000, 0.0005798339843750, 0.0023193359375000, 0.0003051757812500, +0.0026855468750000, 0.0007934570312500, 0.0031127929687500, 0.0004882812500000, +0.0031738281250000, 0.0004272460937500, 0.0031433105468750, 0.0006103515625000, +0.0032348632812500, 0.0001831054687500, 0.0030212402343750, -0.0001525878906250, +0.0023803710937500, -0.0003356933593750, 0.0025329589843750, -0.0005187988281250, +0.0025329589843750, -0.0009765625000000, 0.0013732910156250, -0.0013122558593750, +0.0023498535156250, -0.0006713867187500, 0.0017089843750000, -0.0011291503906250, +0.0014953613281250, -0.0008544921875000, 0.0021057128906250, -0.0002441406250000, +0.0012512207031250, -0.0011596679687500, 0.0018005371093750, -0.0007934570312500, +0.0014648437500000, -0.0002136230468750, 0.0014648437500000, -0.0006408691406250, +0.0016479492187500, -0.0010986328125000, 0.0009765625000000, -0.0007019042968750, +0.0024414062500000, -0.0009765625000000, 0.0025024414062500, -0.0004882812500000, +0.0022888183593750, -0.0005493164062500, 0.0034790039062500, -0.0010070800781250, +0.0036926269531250, -0.0003662109375000, 0.0016174316406250, -0.0005798339843750, +0.0034790039062500, -0.0005798339843750, 0.0027770996093750, -0.0001831054687500, +-0.0006713867187500, -0.0001220703125000, -0.0000915527343750, -0.0004577636718750, +-0.0003967285156250, -0.0001525878906250, -0.0006103515625000, -0.0001220703125000, +-0.0003662109375000, -0.0005187988281250, -0.0001525878906250, -0.0005493164062500, +-0.0002136230468750, -0.0000305175781250, -0.0005798339843750, -0.0005187988281250, +0.0000610351562500, -0.0006408691406250, -0.0003662109375000, 0.0003051757812500, +-0.0008544921875000, 0.0004882812500000, 0.0000305175781250, -0.0000305175781250, +-0.0011596679687500, 0.0018005371093750, -0.0005493164062500, 0.0010070800781250, +-0.0006103515625000, 0.0009460449218750, -0.0013732910156250, 0.0018920898437500, +-0.0004272460937500, 0.0007019042968750, -0.0014343261718750, 0.0014648437500000, +-0.0009460449218750, 0.0014648437500000, -0.0008850097656250, 0.0013427734375000, +-0.0017395019531250, 0.0019531250000000, -0.0010375976562500, 0.0021057128906250, +-0.0009460449218750, 0.0018920898437500, -0.0014343261718750, 0.0027770996093750, +-0.0007324218750000, 0.0021362304687500, 0.0000000000000000, 0.0015563964843750, +-0.0008544921875000, 0.0029907226562500, 0.0003662109375000, 0.0004272460937500, +0.0003051757812500, 0.0013122558593750, 0.0001525878906250, 0.0012207031250000, +0.0007324218750000, -0.0006408691406250, 0.0004882812500000, 0.0005187988281250, +0.0002136230468750, -0.0003051757812500, 0.0006103515625000, 0.0001525878906250, +0.0005493164062500, 0.0002746582031250, 0.0001831054687500, 0.0000305175781250, +0.0006103515625000, 0.0010375976562500, 0.0001831054687500, 0.0000915527343750, +0.0006408691406250, 0.0007934570312500, 0.0009155273437500, 0.0005493164062500, +0.0007324218750000, -0.0002746582031250, 0.0011596679687500, 0.0007934570312500, +0.0014953613281250, -0.0010681152343750, 0.0016479492187500, -0.0006103515625000, +0.0015258789062500, -0.0007019042968750, 0.0018920898437500, -0.0017700195312500, +0.0023498535156250, -0.0008239746093750, 0.0008239746093750, -0.0016784667968750, +0.0015869140625000, -0.0013732910156250, 0.0011596679687500, -0.0013122558593750, +-0.0002746582031250, -0.0017089843750000, 0.0007324218750000, -0.0011596679687500, +-0.0003356933593750, -0.0020141601562500, -0.0007324218750000, -0.0014648437500000, +-0.0000915527343750, -0.0017395019531250, -0.0000915527343750, -0.0025329589843750, +-0.0005798339843750, -0.0017089843750000, 0.0002746582031250, -0.0026550292968750, +0.0003356933593750, -0.0026550292968750, 0.0000000000000000, -0.0024719238281250, +0.0000610351562500}, +{0.0029602050781250, -0.0004882812500000, 0.0033264160156250, -0.0004882812500000, +0.0022888183593750, -0.0001831054687500, 0.0029296875000000, -0.0006408691406250, +0.0020141601562500, -0.0003967285156250, 0.0017700195312500, -0.0006408691406250, +0.0019531250000000, -0.0009765625000000, 0.0003662109375000, -0.0003356933593750, +0.0017089843750000, -0.0014038085937500, 0.0017089843750000, -0.0011291503906250, +0.0018615722656250, -0.0008850097656250, 0.0023803710937500, -0.0010375976562500, +0.0014648437500000, -0.0003356933593750, 0.0025329589843750, -0.0007019042968750, +0.0020141601562500, -0.0005187988281250, 0.0022888183593750, -0.0000305175781250, +0.0032653808593750, -0.0000305175781250, 0.0023498535156250, -0.0000610351562500, +0.0035400390625000, 0.0003051757812500, 0.0036926269531250, 0.0003051757812500, +0.0031433105468750, 0.0000305175781250, 0.0027770996093750, -0.0001831054687500, +0.0015563964843750, -0.0006103515625000, 0.0000305175781250, -0.0008850097656250, +0.0007934570312500, -0.0008850097656250, 0.0006408691406250, -0.0002441406250000, +-0.0007629394531250, 0.0000610351562500, -0.0002136230468750, -0.0000305175781250, +-0.0002136230468750, 0.0019531250000000, -0.0005798339843750, 0.0013427734375000, +-0.0004577636718750, 0.0018920898437500, -0.0000915527343750, 0.0030212402343750, +-0.0001525878906250, 0.0013122558593750, -0.0003967285156250, 0.0029296875000000, +0.0001831054687500, 0.0017395019531250, -0.0002746582031250, 0.0017395019531250, +-0.0007019042968750, 0.0030822753906250, 0.0003967285156250, 0.0015258789062500, +-0.0010681152343750, 0.0031433105468750, -0.0002136230468750, 0.0031127929687500, +-0.0003051757812500, 0.0024719238281250, -0.0010375976562500, 0.0030212402343750, +0.0003967285156250, 0.0030212402343750, -0.0014038085937500, 0.0017089843750000, +-0.0007934570312500, 0.0023193359375000, -0.0003967285156250, 0.0018310546875000, +-0.0016174316406250, 0.0005798339843750, -0.0010375976562500, 0.0014038085937500, +0.0000610351562500, 0.0006408691406250, -0.0008239746093750, 0.0004577636718750, +-0.0001525878906250, 0.0005798339843750, 0.0011596679687500, 0.0005187988281250, +-0.0000305175781250, 0.0006103515625000, 0.0013427734375000, -0.0002136230468750, +0.0011596679687500, 0.0002441406250000, 0.0006408691406250, -0.0001220703125000, +0.0009765625000000, -0.0010070800781250, 0.0006103515625000, -0.0004882812500000, +0.0006103515625000, -0.0013427734375000, 0.0004882812500000, -0.0013122558593750, +0.0005493164062500, -0.0013122558593750, 0.0007629394531250, -0.0016174316406250, +0.0009460449218750, -0.0013732910156250, 0.0012512207031250, -0.0014953613281250, +0.0014343261718750, -0.0012207031250000, 0.0018310546875000, -0.0013732910156250, +0.0022583007812500, -0.0014953613281250, 0.0022277832031250, -0.0008850097656250, +0.0022888183593750, -0.0017700195312500, 0.0030212402343750, -0.0016479492187500, +0.0023193359375000, -0.0016784667968750, 0.0017089843750000, -0.0023803710937500, +0.0027465820312500, -0.0021972656250000, 0.0007629394531250, -0.0023193359375000, +0.0013427734375000, -0.0024719238281250, 0.0011901855468750, -0.0020446777343750, +-0.0002136230468750, -0.0017089843750000, 0.0007019042968750, -0.0018615722656250, +0.0001220703125000, -0.0010681152343750, 0.0000000000000000, -0.0009460449218750, +0.0000915527343750, -0.0010986328125000, 0.0000000000000000, -0.0007019042968750, +0.0002746582031250, -0.0006408691406250, -0.0000610351562500, -0.0014648437500000, +0.0001220703125000, -0.0008850097656250, 0.0001831054687500, -0.0014648437500000, +-0.0000610351562500, -0.0023498535156250, 0.0000610351562500, -0.0013427734375000, +0.0002746582031250, -0.0026855468750000, 0.0000610351562500, -0.0025329589843750, +0.0002441406250000, -0.0022888183593750, 0.0004577636718750, -0.0029296875000000, +0.0000915527343750, -0.0026550292968750, 0.0004577636718750, -0.0027465820312500, +0.0003967285156250, -0.0030517578125000, 0.0003051757812500, -0.0031433105468750, +0.0003662109375000, -0.0033569335937500, 0.0002136230468750, -0.0036621093750000, +0.0003967285156250, -0.0034790039062500, 0.0003662109375000, -0.0033264160156250, +0.0002746582031250, -0.0033264160156250, 0.0005493164062500, -0.0031738281250000, +0.0006103515625000, -0.0029907226562500, 0.0001220703125000, -0.0030212402343750, +0.0004882812500000, -0.0027770996093750, 0.0002136230468750, -0.0024719238281250, +-0.0002746582031250, -0.0024414062500000, 0.0003356933593750, -0.0021972656250000, +-0.0005493164062500, -0.0018920898437500, -0.0003051757812500, -0.0018310546875000, +-0.0003051757812500, -0.0017395019531250, -0.0007324218750000, -0.0016479492187500, +-0.0003662109375000, -0.0016784667968750, -0.0006408691406250, -0.0017089843750000, +-0.0006408691406250, -0.0018005371093750, -0.0005187988281250, -0.0018005371093750, +-0.0005798339843750, -0.0018310546875000, -0.0006713867187500, -0.0020446777343750, +-0.0006408691406250, -0.0020751953125000, -0.0007324218750000, -0.0021667480468750, +-0.0008239746093750, -0.0024108886718750, -0.0009155273437500, -0.0024414062500000, +-0.0010681152343750, -0.0024108886718750, -0.0009765625000000, -0.0031738281250000, +-0.0010986328125000, -0.0027770996093750, -0.0010070800781250, -0.0032653808593750, +-0.0008544921875000, -0.0040283203125000, -0.0010681152343750, -0.0031433105468750, +-0.0008544921875000, -0.0045471191406250, -0.0008850097656250, -0.0042114257812500, +-0.0008544921875000, -0.0043029785156250, -0.0007019042968750, -0.0052185058593750, +-0.0009155273437500, -0.0046386718750000, -0.0004882812500000, -0.0050964355468750, +-0.0007629394531250, -0.0054321289062500, -0.0007019042968750, -0.0050659179687500, +-0.0004272460937500, -0.0050354003906250, -0.0008544921875000, -0.0054931640625000, +-0.0004272460937500, -0.0042724609375000, -0.0006713867187500, -0.0046081542968750, +-0.0005187988281250, -0.0041503906250000, -0.0001831054687500, -0.0030517578125000, +-0.0006713867187500, -0.0036010742187500, 0.0002136230468750, -0.0026245117187500, +0.0000915527343750, -0.0023193359375000, 0.0000000000000000, -0.0025634765625000, +0.0004577636718750, -0.0022583007812500, 0.0003051757812500, -0.0019531250000000, +0.0003356933593750, -0.0027160644531250, 0.0004272460937500, -0.0025939941406250, +0.0003967285156250, -0.0026855468750000, 0.0004882812500000, -0.0034790039062500, +0.0005493164062500, -0.0034790039062500, 0.0000305175781250, -0.0032348632812500, +0.0003662109375000, -0.0042724609375000, -0.0000305175781250, -0.0035095214843750, +-0.0008544921875000, -0.0028076171875000, -0.0004882812500000, -0.0043945312500000, +-0.0008544921875000, -0.0016479492187500, -0.0011901855468750, -0.0028686523437500, +-0.0009155273437500, -0.0025329589843750, -0.0007324218750000, -0.0004272460937500, +-0.0009155273437500, -0.0023498535156250, -0.0001525878906250, -0.0006103515625000, +-0.0003662109375000, -0.0003051757812500, -0.0003662109375000, -0.0011291503906250, +0.0002441406250000, -0.0008850097656250, 0.0000000000000000, -0.0008239746093750, +0.0000305175781250, -0.0012817382812500, 0.0001831054687500, -0.0015563964843750, +0.0001220703125000, -0.0010986328125000, 0.0001831054687500, -0.0007629394531250, +0.0004272460937500, -0.0008239746093750, -0.0000305175781250, 0.0002746582031250, +0.0004577636718750, 0.0003967285156250, 0.0000305175781250, 0.0007324218750000, +-0.0005798339843750, 0.0016174316406250, 0.0003662109375000, 0.0017395019531250, +-0.0009765625000000, 0.0021057128906250, -0.0007934570312500, 0.0027465820312500, +-0.0001525878906250, 0.0026550292968750, -0.0006713867187500, 0.0025329589843750, +-0.0008544921875000, 0.0028991699218750, 0.0000915527343750, 0.0014343261718750, +-0.0006103515625000, 0.0015258789062500, -0.0005493164062500, 0.0011291503906250, +0.0003356933593750, -0.0000610351562500, -0.0002441406250000, 0.0004272460937500, +0.0002136230468750, 0.0006103515625000, 0.0003967285156250, 0.0003051757812500, +0.0003967285156250, 0.0011291503906250, 0.0006408691406250, 0.0021972656250000, +0.0007019042968750, 0.0018615722656250, 0.0005493164062500, 0.0019836425781250, +0.0006103515625000, 0.0026245117187500, 0.0004577636718750, 0.0014953613281250, +0.0002746582031250, 0.0002746582031250, 0.0002136230468750, 0.0010375976562500, +-0.0005798339843750, -0.0009460449218750, -0.0005187988281250, -0.0012817382812500, +-0.0005187988281250, -0.0006408691406250, -0.0012817382812500, -0.0009765625000000, +0.0013427734375000, 0.0003051757812500, 0.0000000000000000, -0.0012817382812500, +0.0014038085937500, -0.0013122558593750, 0.0006103515625000, -0.0003051757812500, +-0.0005798339843750, 0.0003356933593750, 0.0008850097656250, 0.0000610351562500, +0.0001220703125000, 0.0005187988281250, -0.0001831054687500, 0.0010375976562500, +0.0009155273437500, 0.0005187988281250, 0.0016479492187500, -0.0001831054687500, +0.0012512207031250, 0.0003967285156250, 0.0017700195312500, 0.0003356933593750, +0.0028076171875000, -0.0001831054687500, 0.0015258789062500, 0.0008850097656250, +0.0007934570312500, 0.0018920898437500, 0.0023803710937500, 0.0010375976562500, +-0.0008239746093750, 0.0023193359375000, -0.0002441406250000, 0.0029602050781250, +0.0001525878906250, 0.0021057128906250, -0.0015258789062500, 0.0018005371093750, +-0.0006713867187500, 0.0021667480468750, 0.0002441406250000, 0.0014343261718750, +0.0000000000000000, 0.0010375976562500, 0.0002746582031250, 0.0010681152343750, +0.0010070800781250, 0.0010986328125000, 0.0007934570312500, 0.0010681152343750, +0.0005493164062500, 0.0010375976562500, 0.0004272460937500, 0.0014648437500000, +0.0000610351562500, 0.0009460449218750, -0.0006103515625000, 0.0002746582031250, +-0.0009765625000000, 0.0008239746093750, -0.0008850097656250, 0.0000610351562500, +-0.0020751953125000, -0.0003967285156250, -0.0012512207031250, 0.0000610351562500, +-0.0005493164062500, 0.0003356933593750, -0.0024108886718750, 0.0000610351562500, +0.0003051757812500, 0.0005798339843750, -0.0006713867187500, 0.0008850097656250, +-0.0009765625000000, 0.0007324218750000, 0.0003662109375000, 0.0007629394531250, +-0.0015258789062500, 0.0010070800781250, -0.0007629394531250, 0.0006713867187500, +-0.0015258789062500, 0.0005798339843750, -0.0024414062500000, 0.0005798339843750, +-0.0024414062500000, 0.0004272460937500, -0.0033569335937500, 0.0003051757812500, +-0.0034179687500000, 0.0000915527343750, -0.0043029785156250, 0.0001525878906250, +-0.0040893554687500, -0.0002136230468750, -0.0037841796875000, -0.0007629394531250, +-0.0049438476562500, -0.0007019042968750, -0.0028991699218750, -0.0009765625000000, +-0.0036621093750000, -0.0011596679687500, -0.0032958984375000, -0.0011596679687500, +-0.0019226074218750, -0.0009765625000000, -0.0033264160156250, -0.0009765625000000, +-0.0014343261718750, -0.0014648437500000, -0.0022888183593750, -0.0009155273437500, +-0.0021362304687500, -0.0013427734375000, -0.0009765625000000, -0.0020446777343750, +-0.0026245117187500, -0.0013122558593750, -0.0012817382812500, -0.0021667480468750, +-0.0018615722656250, -0.0021362304687500, -0.0023803710937500, -0.0018615722656250, +-0.0019226074218750, -0.0021057128906250, -0.0027160644531250, -0.0019531250000000, +-0.0023193359375000, -0.0018920898437500, -0.0028991699218750, -0.0019226074218750, +-0.0028686523437500, -0.0017700195312500, -0.0024414062500000, -0.0016784667968750, +-0.0031127929687500, -0.0018005371093750, -0.0019226074218750, -0.0014038085937500, +-0.0025939941406250, -0.0014038085937500, -0.0021667480468750, -0.0014343261718750, +-0.0011596679687500, -0.0012512207031250, -0.0022583007812500, -0.0012512207031250, +-0.0007934570312500}, +{0.0007629394531250, 0.0010681152343750, 0.0004882812500000, 0.0009765625000000, +0.0004882812500000, 0.0016784667968750, 0.0007019042968750, 0.0007934570312500, +0.0008544921875000, -0.0012207031250000, 0.0005187988281250, -0.0003051757812500, +-0.0016784667968750, -0.0003662109375000, -0.0009460449218750, 0.0003356933593750, +-0.0000915527343750, -0.0004272460937500, -0.0001831054687500, -0.0014038085937500, +-0.0001831054687500, -0.0005493164062500, 0.0007629394531250, -0.0002746582031250, +0.0011291503906250, -0.0006713867187500, 0.0003051757812500, 0.0002136230468750, +-0.0000305175781250, 0.0013427734375000, 0.0004882812500000, 0.0008239746093750, +-0.0013122558593750, 0.0012817382812500, -0.0013427734375000, 0.0019226074218750, +-0.0007629394531250, 0.0013122558593750, -0.0012817382812500, 0.0008544921875000, +-0.0012512207031250, 0.0015869140625000, 0.0001831054687500, 0.0011901855468750, +-0.0000915527343750, 0.0009460449218750, -0.0002441406250000, 0.0013427734375000, +0.0005493164062500, 0.0018615722656250, 0.0001220703125000, 0.0018920898437500, +-0.0010070800781250, 0.0016479492187500, -0.0013427734375000, 0.0021362304687500, +-0.0014343261718750, 0.0017395019531250, -0.0024719238281250, 0.0009155273437500, +-0.0033264160156250, 0.0014038085937500, -0.0016479492187500, 0.0005798339843750, +-0.0030517578125000, 0.0003967285156250, -0.0024108886718750, 0.0007934570312500, +-0.0006408691406250, 0.0009460449218750, -0.0025634765625000, 0.0008239746093750, +-0.0002136230468750, 0.0007324218750000, -0.0006408691406250, 0.0012207031250000, +-0.0014343261718750, 0.0007019042968750, -0.0006408691406250, 0.0000610351562500, +-0.0013732910156250, 0.0005187988281250, -0.0021667480468750, -0.0000305175781250, +-0.0026245117187500, -0.0001831054687500, -0.0028686523437500, 0.0001525878906250, +-0.0033569335937500, 0.0001831054687500, -0.0039062500000000, 0.0001525878906250, +-0.0036315917968750, 0.0006408691406250, -0.0039978027343750, 0.0007629394531250, +-0.0039978027343750, 0.0007019042968750, -0.0035705566406250, 0.0007629394531250, +-0.0038452148437500, 0.0008544921875000, -0.0034484863281250, 0.0004882812500000, +-0.0029602050781250, 0.0006408691406250, -0.0032958984375000, 0.0004882812500000, +-0.0033874511718750, 0.0002136230468750, -0.0027770996093750, 0.0003051757812500, +-0.0037536621093750, -0.0002441406250000, -0.0037231445312500, -0.0002441406250000, +-0.0034790039062500, -0.0005493164062500, -0.0040893554687500, -0.0011291503906250, +-0.0042724609375000, -0.0010681152343750, -0.0035095214843750, -0.0014038085937500, +-0.0043029785156250, -0.0014953613281250, -0.0039367675781250, -0.0015869140625000, +-0.0031127929687500, -0.0016784667968750, -0.0042114257812500, -0.0016174316406250, +-0.0025939941406250, -0.0019531250000000, -0.0029907226562500, -0.0018310546875000, +-0.0027465820312500, -0.0018005371093750, -0.0015563964843750, -0.0019836425781250, +-0.0021667480468750, -0.0018615722656250, -0.0009765625000000, -0.0016174316406250, +-0.0011291503906250, -0.0016784667968750, -0.0009765625000000, -0.0016174316406250, +-0.0002136230468750, -0.0014343261718750, -0.0007019042968750, -0.0014343261718750, +-0.0001525878906250, -0.0014953613281250, -0.0002746582031250, -0.0015563964843750, +-0.0004272460937500, -0.0014343261718750, -0.0002441406250000, -0.0014343261718750, +-0.0005798339843750, -0.0014648437500000, -0.0006713867187500, -0.0011291503906250, +-0.0010681152343750, -0.0011596679687500, -0.0008239746093750, -0.0011901855468750, +-0.0007019042968750, -0.0010681152343750, -0.0015869140625000, -0.0010681152343750, +-0.0006408691406250, -0.0011291503906250, -0.0015258789062500, -0.0011291503906250, +-0.0013427734375000, -0.0011596679687500, -0.0007934570312500, -0.0010986328125000, +-0.0023498535156250, -0.0009765625000000, -0.0004577636718750, -0.0012817382812500, +-0.0015869140625000, -0.0010681152343750, -0.0017395019531250, -0.0012817382812500, +-0.0003662109375000, -0.0016479492187500, -0.0016174316406250, -0.0014038085937500, +-0.0007019042968750, -0.0018005371093750, -0.0010070800781250, -0.0018920898437500, +-0.0011596679687500, -0.0017700195312500, -0.0007019042968750, -0.0018920898437500, +-0.0013122558593750, -0.0018615722656250, -0.0006713867187500, -0.0018005371093750, +-0.0012207031250000, -0.0018005371093750, -0.0011291503906250, -0.0017395019531250, +-0.0007019042968750, -0.0016479492187500, -0.0017700195312500, -0.0015563964843750, +-0.0008544921875000, -0.0012817382812500, -0.0015563964843750, -0.0011596679687500, +-0.0017089843750000, -0.0010070800781250, -0.0012207031250000, -0.0006103515625000, +-0.0022888183593750, -0.0004577636718750, -0.0013427734375000, -0.0003967285156250, +-0.0021667480468750, -0.0000610351562500, -0.0021057128906250, 0.0001220703125000, +-0.0014343261718750, 0.0001525878906250, -0.0027160644531250, 0.0003356933593750, +-0.0014343261718750, 0.0004577636718750, -0.0020446777343750, 0.0005187988281250, +-0.0016784667968750, 0.0006713867187500, -0.0004577636718750, 0.0007629394531250, +-0.0013732910156250, 0.0007324218750000, -0.0000915527343750, 0.0010986328125000, +-0.0003051757812500, 0.0009765625000000, -0.0007324218750000, 0.0009155273437500, +-0.0002441406250000, 0.0011291503906250, -0.0006408691406250, 0.0010375976562500, +-0.0010070800781250, 0.0009765625000000, -0.0004577636718750, 0.0011291503906250, +-0.0011901855468750, 0.0010681152343750, -0.0016174316406250, 0.0010375976562500, +-0.0003356933593750, 0.0012207031250000, -0.0023803710937500, 0.0011596679687500, +-0.0021667480468750, 0.0011291503906250, -0.0018615722656250, 0.0013427734375000, +-0.0031433105468750, 0.0016174316406250, -0.0031127929687500, 0.0015869140625000, +-0.0023803710937500, 0.0013122558593750, -0.0032653808593750, 0.0018005371093750, +-0.0027770996093750, 0.0013732910156250, -0.0020751953125000, 0.0007629394531250, +-0.0036926269531250, 0.0013427734375000, -0.0015563964843750, 0.0003967285156250, +-0.0025329589843750, 0.0006713867187500, -0.0026245117187500, 0.0003967285156250, +-0.0009765625000000, -0.0002746582031250, -0.0022277832031250, 0.0005493164062500, +-0.0015563964843750, -0.0006103515625000, -0.0010375976562500, -0.0004272460937500, +-0.0016784667968750, -0.0003662109375000, -0.0019226074218750, -0.0011596679687500, +-0.0012817382812500, -0.0009155273437500, -0.0021057128906250, -0.0007629394531250, +-0.0018615722656250, -0.0009765625000000, -0.0013427734375000, -0.0010070800781250, +-0.0016479492187500, -0.0006713867187500, -0.0016479492187500, -0.0006103515625000, +-0.0007019042968750, -0.0012512207031250, -0.0006408691406250, -0.0007629394531250, +-0.0011596679687500, -0.0011291503906250, -0.0005187988281250, -0.0018310546875000, +0.0007324218750000, -0.0009765625000000, -0.0004882812500000, -0.0017089843750000, +0.0015563964843750, -0.0014648437500000, 0.0014343261718750, -0.0009765625000000, +0.0003051757812500, -0.0007629394531250, 0.0029602050781250, -0.0001220703125000, +0.0011901855468750, -0.0005187988281250, 0.0018005371093750, 0.0001220703125000, +0.0027770996093750, 0.0007324218750000, 0.0017089843750000, 0.0007934570312500, +0.0016174316406250, 0.0010986328125000, 0.0025939941406250, 0.0008850097656250, +0.0025024414062500, 0.0011596679687500, 0.0019531250000000, 0.0009155273437500, +0.0022277832031250, 0.0003662109375000, 0.0023803710937500, 0.0007629394531250, +0.0010375976562500, -0.0002746582031250, 0.0007019042968750, -0.0000915527343750, +0.0011596679687500, -0.0001831054687500, 0.0004272460937500, -0.0007324218750000, +-0.0004882812500000, -0.0001525878906250, 0.0016174316406250, -0.0001831054687500, +0.0002746582031250, -0.0002136230468750, 0.0004882812500000, 0.0002746582031250, +0.0033569335937500, 0.0009460449218750, 0.0028076171875000, 0.0014648437500000, +0.0018920898437500, 0.0019836425781250, 0.0024719238281250, 0.0017089843750000, +0.0023803710937500, 0.0019531250000000, 0.0017395019531250, 0.0020446777343750, +0.0021972656250000, 0.0011596679687500, 0.0017395019531250, 0.0018310546875000, +0.0018615722656250, 0.0013732910156250, 0.0019226074218750, 0.0011291503906250, +0.0017700195312500, 0.0017395019531250, 0.0019836425781250, 0.0017700195312500, +0.0015258789062500, 0.0021362304687500, 0.0015563964843750, 0.0026550292968750, +0.0016174316406250, 0.0028991699218750, 0.0012207031250000, 0.0031738281250000, +0.0010681152343750, 0.0034484863281250, 0.0015258789062500, 0.0030517578125000, +0.0012207031250000, 0.0034484863281250, 0.0009765625000000, 0.0033569335937500, +0.0013122558593750, 0.0025939941406250, 0.0012207031250000, 0.0027160644531250, +0.0003356933593750, 0.0021972656250000, 0.0006408691406250, 0.0017089843750000, +0.0001525878906250, 0.0015258789062500, -0.0005798339843750, 0.0010681152343750, +0.0000610351562500, 0.0006408691406250, -0.0011596679687500, 0.0011596679687500, +-0.0006713867187500, 0.0004577636718750, -0.0009155273437500, 0.0006408691406250, +-0.0019836425781250, 0.0011291503906250, -0.0009460449218750, 0.0000305175781250, +-0.0014953613281250, 0.0007629394531250, -0.0019531250000000, 0.0001525878906250, +-0.0010681152343750, -0.0003967285156250, -0.0007019042968750, -0.0005187988281250, +-0.0014038085937500, -0.0014953613281250, 0.0005187988281250, -0.0013427734375000, +0.0001220703125000, -0.0020751953125000, 0.0002136230468750, -0.0022888183593750, +0.0012207031250000, -0.0020751953125000, 0.0004577636718750, -0.0029296875000000, +0.0010070800781250, -0.0021057128906250, 0.0007934570312500, -0.0025329589843750, +0.0008239746093750, -0.0023193359375000, 0.0011596679687500, -0.0015869140625000, +0.0007629394531250, -0.0022888183593750, 0.0016479492187500, -0.0014343261718750, +0.0014648437500000, -0.0016479492187500, 0.0019226074218750, -0.0015258789062500, +0.0028076171875000, -0.0011596679687500, 0.0022583007812500, -0.0017395019531250, +0.0028076171875000, -0.0008239746093750, 0.0032958984375000, -0.0015258789062500, +0.0026245117187500, -0.0013427734375000, 0.0022888183593750, -0.0005493164062500, +0.0028991699218750, -0.0016174316406250, 0.0014343261718750, -0.0003967285156250, +0.0018310546875000, -0.0008544921875000, 0.0017395019531250, -0.0008239746093750, +0.0007324218750000, -0.0001831054687500, 0.0013122558593750, -0.0011596679687500, +0.0006408691406250, -0.0001831054687500, 0.0005493164062500, -0.0009765625000000, +0.0005493164062500, -0.0010070800781250, 0.0002136230468750, -0.0004882812500000, +0.0003967285156250, -0.0018920898437500, 0.0000915527343750, -0.0010070800781250, +0.0001220703125000, -0.0017395019531250, 0.0001831054687500, -0.0021667480468750, +-0.0000915527343750, -0.0017395019531250, -0.0001220703125000, -0.0024108886718750, +0.0002136230468750, -0.0021362304687500, 0.0000000000000000, -0.0023193359375000, +0.0001525878906250, -0.0025939941406250, 0.0005798339843750, -0.0024108886718750, +0.0001525878906250, -0.0023498535156250, 0.0006713867187500, -0.0023193359375000, +0.0005798339843750, -0.0022277832031250, 0.0003356933593750, -0.0021057128906250, +0.0005187988281250, -0.0021667480468750, 0.0004272460937500, -0.0022277832031250, +0.0000610351562500, -0.0016174316406250, 0.0002136230468750, -0.0017089843750000, +0.0002136230468750, -0.0015869140625000, 0.0000915527343750, -0.0010070800781250, +0.0003051757812500, -0.0011901855468750, 0.0001525878906250, -0.0011901855468750, +0.0003051757812500, -0.0007629394531250, 0.0001831054687500, -0.0010375976562500, +-0.0000610351562500, -0.0012512207031250, 0.0001831054687500, -0.0006103515625000, +-0.0003662109375000, -0.0015258789062500, -0.0002441406250000, -0.0012207031250000, +-0.0002746582031250}, +{0.0018005371093750, 0.0027160644531250, 0.0020751953125000, 0.0026855468750000, +0.0024414062500000, 0.0025939941406250, 0.0022888183593750, 0.0028991699218750, +0.0021362304687500, 0.0022583007812500, 0.0018920898437500, 0.0016174316406250, +0.0018615722656250, 0.0018005371093750, 0.0016784667968750, 0.0014953613281250, +0.0010986328125000, 0.0005187988281250, 0.0010375976562500, 0.0016174316406250, +0.0011596679687500, 0.0009460449218750, 0.0003967285156250, 0.0008239746093750, +-0.0000915527343750, 0.0018005371093750, 0.0003662109375000, 0.0009765625000000, +-0.0012817382812500, 0.0010375976562500, -0.0009155273437500, 0.0011291503906250, +-0.0010681152343750, 0.0004272460937500, -0.0020446777343750, -0.0001831054687500, +-0.0012207031250000, -0.0002441406250000, -0.0017089843750000, -0.0013427734375000, +-0.0016174316406250, -0.0016784667968750, -0.0010986328125000, -0.0017700195312500, +-0.0010681152343750, -0.0021667480468750, -0.0009765625000000, -0.0023193359375000, +0.0000305175781250, -0.0023498535156250, -0.0003967285156250, -0.0023193359375000, +0.0001220703125000, -0.0024719238281250, 0.0010070800781250, -0.0025634765625000, +0.0002746582031250, -0.0025024414062500, 0.0013427734375000, -0.0028686523437500, +0.0011596679687500, -0.0027160644531250, 0.0009765625000000, -0.0026550292968750, +0.0013122558593750, -0.0029907226562500, 0.0009155273437500, -0.0029602050781250, +0.0012817382812500, -0.0023193359375000, 0.0010681152343750, -0.0026550292968750, +0.0011291503906250, -0.0022277832031250, 0.0014038085937500, -0.0013732910156250, +0.0012512207031250, -0.0019531250000000, 0.0021362304687500, -0.0011596679687500, +0.0021057128906250, -0.0010681152343750, 0.0021667480468750, -0.0011291503906250, +0.0028686523437500, -0.0010375976562500, 0.0028991699218750, -0.0011596679687500, +0.0021972656250000, -0.0008850097656250, 0.0025939941406250, -0.0014038085937500, +0.0021362304687500, -0.0013732910156250, 0.0012817382812500, -0.0013427734375000, +0.0018615722656250, -0.0023193359375000, 0.0008239746093750, -0.0010070800781250, +0.0007019042968750, -0.0022888183593750, 0.0007629394531250, -0.0021362304687500, +0.0002746582031250, -0.0010986328125000, 0.0003356933593750, -0.0028686523437500, +0.0001831054687500, -0.0014648437500000, 0.0001220703125000, -0.0019226074218750, +0.0000305175781250, -0.0021362304687500, -0.0001525878906250, -0.0012512207031250, +-0.0001525878906250, -0.0018615722656250, -0.0001831054687500, -0.0007019042968750, +-0.0003356933593750, -0.0009765625000000, -0.0003051757812500, -0.0011901855468750, +-0.0002746582031250, -0.0005493164062500, -0.0003662109375000, -0.0007019042968750, +-0.0001831054687500, -0.0007629394531250, -0.0005493164062500, -0.0007934570312500, +-0.0003967285156250, -0.0006713867187500, -0.0000915527343750, -0.0007629394531250, +-0.0004882812500000, -0.0011291503906250, -0.0000610351562500, -0.0006713867187500, +-0.0000610351562500, -0.0009155273437500, -0.0001525878906250, -0.0011596679687500, +-0.0000305175781250, -0.0009460449218750, -0.0000305175781250, -0.0010070800781250, +-0.0002136230468750, -0.0014038085937500, -0.0001525878906250, -0.0012817382812500, +-0.0001525878906250, -0.0012817382812500, -0.0002136230468750, -0.0014648437500000, +-0.0002136230468750, -0.0011596679687500, -0.0003356933593750, -0.0013427734375000, +-0.0002441406250000, -0.0012512207031250, -0.0003967285156250, -0.0011596679687500, +-0.0004577636718750, -0.0011901855468750, -0.0002746582031250, -0.0010986328125000, +-0.0007019042968750, -0.0011596679687500, -0.0004272460937500, -0.0010986328125000, +-0.0004577636718750, -0.0009765625000000, -0.0007629394531250, -0.0009765625000000, +-0.0002746582031250, -0.0009460449218750, -0.0005798339843750, -0.0006713867187500, +-0.0004272460937500, -0.0007934570312500, -0.0002746582031250, -0.0007934570312500, +-0.0004577636718750, -0.0006103515625000, -0.0003051757812500, -0.0008239746093750, +-0.0005187988281250, -0.0009765625000000, -0.0006103515625000, -0.0007019042968750, +-0.0006103515625000, -0.0011596679687500, -0.0007629394531250, -0.0014953613281250, +-0.0010070800781250, -0.0008239746093750, -0.0008544921875000, -0.0024414062500000, +-0.0010681152343750, -0.0016174316406250, -0.0010986328125000, -0.0019836425781250, +-0.0009460449218750, -0.0032653808593750, -0.0010375976562500, -0.0019531250000000, +-0.0006103515625000, -0.0035095214843750, -0.0007019042968750, -0.0033264160156250, +-0.0004882812500000, -0.0030822753906250, -0.0002136230468750, -0.0038757324218750, +-0.0004577636718750, -0.0035400390625000, -0.0000915527343750, -0.0036621093750000, +-0.0003967285156250, -0.0038757324218750, -0.0002136230468750, -0.0037536621093750, +0.0000305175781250, -0.0036621093750000, -0.0005493164062500, -0.0038452148437500, +0.0004577636718750, -0.0038452148437500, 0.0000915527343750, -0.0035400390625000, +0.0001831054687500, -0.0039062500000000, 0.0008850097656250, -0.0040283203125000, +0.0003967285156250, -0.0034484863281250, 0.0009765625000000, -0.0051879882812500, +0.0008544921875000, -0.0044860839843750, 0.0010986328125000, -0.0048828125000000, +0.0015869140625000, -0.0063781738281250, 0.0010375976562500, -0.0053100585937500, +0.0015869140625000, -0.0065612792968750, 0.0015869140625000, -0.0066528320312500, +0.0012512207031250, -0.0060119628906250, 0.0013427734375000, -0.0063781738281250, +0.0013427734375000, -0.0064086914062500, 0.0010986328125000, -0.0046997070312500, +0.0011291503906250, -0.0059509277343750, 0.0013427734375000, -0.0050964355468750, +0.0012512207031250, -0.0032653808593750, 0.0010986328125000, -0.0050048828125000, +0.0016479492187500, -0.0026550292968750, 0.0016479492187500, -0.0032043457031250, +0.0015869140625000, -0.0031738281250000, 0.0018005371093750, -0.0019226074218750, +0.0017700195312500, -0.0034179687500000, 0.0014038085937500, -0.0019836425781250, +0.0010986328125000, -0.0025024414062500, 0.0009460449218750, -0.0027465820312500, +0.0006713867187500, -0.0020751953125000, 0.0002441406250000, -0.0027770996093750, +0.0007324218750000, -0.0020141601562500, 0.0008239746093750, -0.0024719238281250, +0.0006408691406250, -0.0028076171875000, 0.0008544921875000, -0.0023498535156250, +0.0012207031250000, -0.0023498535156250, 0.0004882812500000, -0.0014343261718750, +0.0006713867187500, -0.0009765625000000, 0.0003051757812500, -0.0007019042968750, +-0.0005493164062500, -0.0000915527343750, -0.0002441406250000, 0.0003967285156250, +-0.0008239746093750, -0.0000915527343750, -0.0009460449218750, 0.0001831054687500, +-0.0009765625000000, 0.0003051757812500, -0.0010070800781250, -0.0003051757812500, +-0.0007324218750000, -0.0002746582031250, -0.0017700195312500, 0.0007324218750000, +-0.0009765625000000, 0.0001525878906250, -0.0014953613281250, 0.0001525878906250, +-0.0026550292968750, 0.0012512207031250, -0.0013427734375000, 0.0006408691406250, +-0.0025939941406250, -0.0005798339843750, -0.0024108886718750, 0.0000305175781250, +-0.0017089843750000, -0.0004272460937500, -0.0020141601562500, -0.0024719238281250, +-0.0039062500000000, 0.0003051757812500, -0.0015563964843750, -0.0023193359375000, +-0.0034484863281250, -0.0011291503906250, -0.0029296875000000, -0.0017395019531250, +-0.0016174316406250, -0.0037536621093750, -0.0027770996093750, -0.0036621093750000, +-0.0010986328125000, -0.0029602050781250, -0.0010375976562500, -0.0035705566406250, +-0.0012512207031250, -0.0035705566406250, -0.0004272460937500, -0.0025024414062500, +-0.0006713867187500, -0.0025939941406250, -0.0013732910156250, -0.0031738281250000, +-0.0015258789062500, -0.0024414062500000, -0.0016479492187500, -0.0025329589843750, +-0.0024414062500000, -0.0035095214843750, -0.0029296875000000, -0.0029907226562500, +-0.0016174316406250, -0.0018005371093750, -0.0028381347656250, -0.0024719238281250, +-0.0023498535156250, -0.0016479492187500, -0.0007629394531250, 0.0000000000000000, +-0.0024108886718750, -0.0006713867187500, -0.0016479492187500, -0.0000610351562500, +-0.0014038085937500, 0.0004882812500000, -0.0023803710937500, -0.0001525878906250, +-0.0029602050781250, -0.0005187988281250, -0.0028991699218750, 0.0001220703125000, +-0.0034790039062500, -0.0003356933593750, -0.0038757324218750, -0.0005187988281250, +-0.0036621093750000, 0.0001831054687500, -0.0035705566406250, 0.0005493164062500, +-0.0038452148437500, 0.0000305175781250, -0.0028076171875000, 0.0007934570312500, +-0.0027770996093750, 0.0010070800781250, -0.0030822753906250, 0.0007324218750000, +-0.0023193359375000, 0.0007019042968750, -0.0020751953125000, 0.0008239746093750, +-0.0041198730468750, 0.0006408691406250, -0.0028381347656250, 0.0004272460937500, +-0.0035705566406250, 0.0006713867187500, -0.0054321289062500, 0.0009765625000000, +-0.0034790039062500, 0.0006713867187500, -0.0057373046875000, 0.0008544921875000, +-0.0049133300781250, 0.0010375976562500, -0.0043640136718750, 0.0007324218750000, +-0.0054626464843750, 0.0005187988281250, -0.0041503906250000, 0.0008239746093750, +-0.0039062500000000, 0.0006103515625000, -0.0039062500000000, 0.0005187988281250, +-0.0032653808593750, 0.0007324218750000, -0.0025939941406250, 0.0008850097656250, +-0.0025939941406250, 0.0007019042968750, -0.0028076171875000, 0.0004577636718750, +-0.0022583007812500, 0.0006713867187500, -0.0026550292968750, 0.0003356933593750, +-0.0031433105468750, -0.0002441406250000, -0.0024414062500000, -0.0000610351562500, +-0.0038452148437500, -0.0002441406250000, -0.0030517578125000, -0.0004882812500000, +-0.0033569335937500, -0.0004577636718750, -0.0043640136718750, -0.0004577636718750, +-0.0029296875000000, -0.0007324218750000, -0.0041198730468750, -0.0007019042968750, +-0.0038452148437500, -0.0008544921875000, -0.0030212402343750, -0.0009765625000000, +-0.0033569335937500, -0.0010681152343750, -0.0032348632812500, -0.0012207031250000, +-0.0020446777343750, -0.0011596679687500, -0.0022583007812500, -0.0012207031250000, +-0.0017700195312500, -0.0013122558593750, -0.0007934570312500, -0.0012817382812500, +-0.0012512207031250, -0.0012207031250000, -0.0003356933593750, -0.0014648437500000, +-0.0002746582031250, -0.0014648437500000, -0.0000610351562500, -0.0014343261718750, +0.0004272460937500, -0.0014953613281250, 0.0001831054687500, -0.0014953613281250, +0.0010986328125000, -0.0016479492187500, 0.0006408691406250, -0.0015258789062500, +0.0006713867187500, -0.0016784667968750, 0.0011901855468750, -0.0018920898437500, +0.0002746582031250, -0.0015869140625000, 0.0002136230468750, -0.0021057128906250, +0.0000915527343750, -0.0019226074218750, -0.0004577636718750, -0.0019531250000000, +-0.0007629394531250, -0.0022277832031250, -0.0007629394531250, -0.0019226074218750, +-0.0015563964843750, -0.0023193359375000, -0.0012512207031250, -0.0022583007812500, +-0.0015258789062500, -0.0022277832031250, -0.0024719238281250, -0.0024719238281250, +-0.0021667480468750, -0.0022888183593750, -0.0026855468750000, -0.0022583007812500, +-0.0030517578125000, -0.0022888183593750, -0.0029907226562500, -0.0020751953125000, +-0.0033264160156250, -0.0018615722656250, -0.0039672851562500, -0.0018615722656250, +-0.0032348632812500, -0.0014038085937500, -0.0038757324218750, -0.0013122558593750, +-0.0036926269531250, -0.0011596679687500, -0.0031127929687500, -0.0008850097656250, +-0.0039978027343750, -0.0008239746093750, -0.0026550292968750, -0.0007934570312500, +-0.0031433105468750, -0.0007019042968750, -0.0028686523437500, -0.0006103515625000, +-0.0019836425781250, -0.0005187988281250, -0.0028991699218750, -0.0003967285156250, +-0.0013122558593750, -0.0003967285156250, -0.0020751953125000, -0.0002746582031250, +-0.0018615722656250, -0.0001220703125000, -0.0006713867187500, -0.0000610351562500, +-0.0019226074218750}, +{-0.0015869140625000, -0.0004577636718750, -0.0008850097656250, 0.0000610351562500, +-0.0031127929687500, 0.0001831054687500, -0.0021057128906250, -0.0006408691406250, +-0.0027770996093750, -0.0000915527343750, -0.0047302246093750, 0.0009460449218750, +-0.0030517578125000, 0.0002441406250000, -0.0042114257812500, 0.0008544921875000, +-0.0040283203125000, 0.0012207031250000, -0.0034790039062500, 0.0008544921875000, +-0.0036010742187500, 0.0005187988281250, -0.0029602050781250, 0.0006713867187500, +-0.0027770996093750, 0.0006103515625000, -0.0028381347656250, 0.0002441406250000, +-0.0025024414062500, 0.0005187988281250, -0.0023193359375000, 0.0009765625000000, +-0.0027465820312500, 0.0006408691406250, -0.0026855468750000, 0.0008239746093750, +-0.0030212402343750, 0.0010375976562500, -0.0032043457031250, 0.0007934570312500, +-0.0033569335937500, 0.0005493164062500, -0.0038146972656250, 0.0007934570312500, +-0.0034179687500000, 0.0006408691406250, -0.0036926269531250, 0.0004882812500000, +-0.0035705566406250, 0.0005493164062500, -0.0028991699218750, 0.0005798339843750, +-0.0028686523437500, 0.0004882812500000, -0.0023803710937500, 0.0003356933593750, +-0.0018920898437500, 0.0003356933593750, -0.0015563964843750, 0.0002441406250000, +-0.0011901855468750, 0.0000915527343750, -0.0007629394531250, 0.0000305175781250, +-0.0004577636718750, -0.0000610351562500, -0.0001831054687500, -0.0000915527343750, +-0.0000915527343750, -0.0003051757812500, -0.0000305175781250, -0.0004882812500000, +0.0000305175781250, -0.0004272460937500, -0.0004882812500000, -0.0008544921875000, +-0.0002746582031250, -0.0009460449218750, -0.0003967285156250, -0.0009155273437500, +-0.0009460449218750, -0.0010681152343750, -0.0005493164062500, -0.0011596679687500, +-0.0009460449218750, -0.0011901855468750, -0.0011291503906250, -0.0011596679687500, +-0.0008544921875000, -0.0014343261718750, -0.0009460449218750, -0.0014953613281250, +-0.0013122558593750, -0.0013427734375000, -0.0003051757812500, -0.0019531250000000, +-0.0009765625000000, -0.0018005371093750, -0.0012817382812500, -0.0020141601562500, +-0.0007934570312500, -0.0025024414062500, -0.0015869140625000, -0.0021362304687500, +-0.0014648437500000, -0.0027160644531250, -0.0014953613281250, -0.0026855468750000, +-0.0018005371093750, -0.0025939941406250, -0.0018310546875000, -0.0028686523437500, +-0.0016479492187500, -0.0027770996093750, -0.0022888183593750, -0.0026245117187500, +-0.0021057128906250, -0.0026245117187500, -0.0020751953125000, -0.0025939941406250, +-0.0028381347656250, -0.0024414062500000, -0.0031738281250000, -0.0022888183593750, +-0.0027465820312500, -0.0021972656250000, -0.0033569335937500, -0.0021362304687500, +-0.0033264160156250, -0.0019226074218750, -0.0030212402343750, -0.0017395019531250, +-0.0038146972656250, -0.0017089843750000, -0.0030517578125000, -0.0014343261718750, +-0.0036315917968750, -0.0012817382812500, -0.0035400390625000, -0.0012512207031250, +-0.0030517578125000, -0.0011596679687500, -0.0041503906250000, -0.0010986328125000, +-0.0028991699218750, -0.0010681152343750, -0.0035095214843750, -0.0010375976562500, +-0.0035095214843750, -0.0010375976562500, -0.0026855468750000, -0.0010070800781250, +-0.0036315917968750, -0.0009155273437500, -0.0027160644531250, -0.0008239746093750, +-0.0032043457031250, -0.0008544921875000, -0.0031738281250000, -0.0007324218750000, +-0.0027160644531250, -0.0005187988281250, -0.0036315917968750, -0.0004577636718750, +-0.0028381347656250, -0.0003051757812500, -0.0033569335937500, -0.0002136230468750, +-0.0036926269531250, -0.0001220703125000, -0.0032958984375000, -0.0000915527343750, +-0.0039062500000000, -0.0000305175781250, -0.0038452148437500, 0.0001831054687500, +-0.0037841796875000, 0.0001525878906250, -0.0039062500000000, 0.0004577636718750, +-0.0039367675781250, 0.0007324218750000, -0.0037536621093750, 0.0005798339843750, +-0.0035705566406250, 0.0013122558593750, -0.0033569335937500, 0.0015258789062500, +-0.0031127929687500, 0.0015258789062500, -0.0028076171875000, 0.0018005371093750, +-0.0023498535156250, 0.0019226074218750, -0.0025329589843750, 0.0017395019531250, +-0.0024414062500000, 0.0018310546875000, -0.0026550292968750, 0.0018005371093750, +-0.0023803710937500, 0.0017395019531250, -0.0014038085937500, 0.0020446777343750, +-0.0032043457031250, 0.0018310546875000, -0.0019226074218750, 0.0018920898437500, +-0.0025939941406250, 0.0021362304687500, -0.0043029785156250, 0.0021057128906250, +-0.0024414062500000, 0.0019531250000000, -0.0048217773437500, 0.0019531250000000, +-0.0045471191406250, 0.0019531250000000, -0.0038146972656250, 0.0015563964843750, +-0.0048522949218750, 0.0012512207031250, -0.0046386718750000, 0.0013732910156250, +-0.0031127929687500, 0.0005493164062500, -0.0044860839843750, 0.0006408691406250, +-0.0035095214843750, 0.0003967285156250, -0.0019531250000000, -0.0002441406250000, +-0.0042114257812500, -0.0000305175781250, -0.0014343261718750, -0.0003051757812500, +-0.0019226074218750, -0.0007019042968750, -0.0023498535156250, -0.0005493164062500, +-0.0009460449218750, -0.0005493164062500, -0.0016479492187500, -0.0009765625000000, +-0.0014038085937500, -0.0000610351562500, -0.0014953613281250, -0.0006713867187500, +-0.0010986328125000, -0.0007324218750000, -0.0009460449218750, -0.0001831054687500, +-0.0018310546875000, -0.0009155273437500, -0.0001525878906250, -0.0003356933593750, +-0.0010986328125000, -0.0010375976562500, -0.0009765625000000, -0.0012207031250000, +0.0003356933593750, -0.0006408691406250, -0.0011596679687500, -0.0011596679687500, +-0.0004882812500000, -0.0008544921875000, -0.0000610351562500, -0.0011901855468750, +-0.0008544921875000, -0.0008544921875000, -0.0009155273437500, -0.0002136230468750, +0.0000000000000000, -0.0005187988281250, -0.0011596679687500, 0.0000305175781250, +-0.0013427734375000, 0.0005187988281250, -0.0006713867187500, 0.0000915527343750, +-0.0007934570312500, -0.0001220703125000, -0.0008544921875000, 0.0006103515625000, +0.0002136230468750, -0.0004272460937500, 0.0000915527343750, -0.0002441406250000, +-0.0001525878906250, -0.0000915527343750, 0.0004882812500000, -0.0006713867187500, +0.0005187988281250, -0.0004272460937500, -0.0007019042968750, -0.0003662109375000, +0.0000915527343750, -0.0008850097656250, -0.0000915527343750, -0.0007934570312500, +-0.0013732910156250, -0.0004882812500000, -0.0004272460937500, -0.0007324218750000, +0.0000610351562500, -0.0000305175781250, -0.0003967285156250, -0.0004882812500000, +-0.0005493164062500, -0.0000305175781250, -0.0003662109375000, 0.0009155273437500, +-0.0004272460937500, 0.0003051757812500, -0.0002746582031250, 0.0015869140625000, +-0.0002746582031250, 0.0012817382812500, -0.0000915527343750, 0.0008544921875000, +0.0003051757812500, 0.0011901855468750, 0.0002136230468750, 0.0007324218750000, +-0.0000610351562500, 0.0006713867187500, 0.0004577636718750, 0.0003356933593750, +0.0000305175781250, 0.0002441406250000, -0.0004882812500000, 0.0005493164062500, +0.0003051757812500, 0.0003051757812500, -0.0005798339843750, -0.0001831054687500, +-0.0002136230468750, 0.0005798339843750, 0.0000610351562500, 0.0000305175781250, +-0.0003051757812500, -0.0007629394531250, 0.0002746582031250, 0.0003662109375000, +-0.0001525878906250, -0.0014343261718750, -0.0000915527343750, -0.0012512207031250, +-0.0000610351562500, -0.0013122558593750, -0.0004882812500000, -0.0023193359375000, +-0.0005798339843750, -0.0019836425781250, -0.0001220703125000, -0.0030517578125000, +-0.0008239746093750, -0.0024719238281250, -0.0007324218750000, -0.0030517578125000, +-0.0000610351562500, -0.0040283203125000, -0.0007934570312500, -0.0026245117187500, +-0.0004882812500000, -0.0044860839843750, -0.0005187988281250, -0.0039367675781250, +-0.0007934570312500, -0.0034484863281250, -0.0009460449218750, -0.0042419433593750, +-0.0009460449218750, -0.0033874511718750, -0.0007019042968750, -0.0030822753906250, +-0.0012817382812500, -0.0030212402343750, -0.0006103515625000, -0.0025024414062500, +0.0000610351562500, -0.0020141601562500, -0.0007934570312500, -0.0021057128906250, +0.0012207031250000, -0.0018615722656250, 0.0009460449218750, -0.0017089843750000, +0.0008850097656250, -0.0021362304687500, 0.0020446777343750, -0.0023803710937500, +0.0014953613281250, -0.0020141601562500, 0.0014648437500000, -0.0028381347656250, +0.0016784667968750, -0.0029907226562500, 0.0014648437500000, -0.0028381347656250, +0.0010681152343750, -0.0032348632812500, 0.0010681152343750, -0.0033874511718750, +0.0011596679687500, -0.0027770996093750, 0.0009155273437500, -0.0031433105468750, +0.0008544921875000, -0.0029602050781250, 0.0009460449218750, -0.0023803710937500, +0.0007934570312500, -0.0030822753906250, 0.0009460449218750, -0.0028381347656250, +0.0009155273437500, -0.0029907226562500, 0.0008544921875000, -0.0034179687500000, +0.0009460449218750, -0.0035400390625000, 0.0009765625000000, -0.0036621093750000, +0.0009460449218750, -0.0040893554687500, 0.0009765625000000, -0.0041809082031250, +0.0007324218750000, -0.0039978027343750, 0.0007324218750000, -0.0041809082031250, +0.0008239746093750, -0.0043029785156250, 0.0001525878906250, -0.0034790039062500, +0.0002136230468750, -0.0042114257812500, 0.0000305175781250, -0.0038452148437500, +-0.0005493164062500, -0.0030822753906250, -0.0003967285156250, -0.0041809082031250, +-0.0006713867187500, -0.0030517578125000, -0.0007629394531250, -0.0031127929687500, +-0.0010070800781250, -0.0029602050781250, -0.0011291503906250, -0.0020446777343750, +-0.0009460449218750, -0.0023498535156250, -0.0014953613281250, -0.0019226074218750, +-0.0011901855468750, -0.0016784667968750, -0.0012817382812500, -0.0016784667968750, +-0.0017089843750000, -0.0014953613281250, -0.0012207031250000, -0.0013732910156250, +-0.0014953613281250, -0.0015869140625000, -0.0013732910156250, -0.0014343261718750, +-0.0013122558593750, -0.0014648437500000, -0.0014038085937500, -0.0017395019531250, +-0.0011596679687500, -0.0015563964843750, -0.0013732910156250, -0.0014953613281250, +-0.0012207031250000, -0.0017395019531250, -0.0013122558593750, -0.0014648437500000, +-0.0015258789062500, -0.0013122558593750, -0.0012817382812500, -0.0017395019531250, +-0.0015869140625000, -0.0011291503906250, -0.0015869140625000, -0.0013427734375000, +-0.0014953613281250, -0.0013732910156250, -0.0016479492187500, -0.0009460449218750, +-0.0014953613281250, -0.0011596679687500, -0.0014343261718750, -0.0009460449218750, +-0.0016479492187500, -0.0007324218750000, -0.0015258789062500, -0.0008544921875000, +-0.0014953613281250, -0.0007629394531250, -0.0019836425781250, -0.0003662109375000, +-0.0016174316406250, -0.0010986328125000, -0.0019226074218750, -0.0002746582031250, +-0.0021057128906250, -0.0005493164062500, -0.0019531250000000, -0.0011596679687500, +-0.0021362304687500, 0.0001525878906250, -0.0019836425781250, -0.0014343261718750, +-0.0019226074218750, -0.0007629394531250, -0.0017700195312500, -0.0009765625000000, +-0.0015563964843750, -0.0021057128906250, -0.0014648437500000, -0.0010070800781250, +-0.0011596679687500, -0.0024108886718750, -0.0013122558593750, -0.0021057128906250, +-0.0010681152343750, -0.0021972656250000, -0.0008850097656250, -0.0029907226562500, +-0.0015258789062500, -0.0022583007812500, -0.0004882812500000, -0.0032348632812500, +-0.0010681152343750, -0.0028381347656250, -0.0008239746093750, -0.0027160644531250, +0.0000610351562500, -0.0031433105468750, -0.0007629394531250, -0.0025024414062500, +0.0003967285156250, -0.0026855468750000, 0.0003051757812500, -0.0024414062500000, +0.0002136230468750, -0.0022583007812500, 0.0007934570312500, -0.0021972656250000, +0.0004577636718750, -0.0018310546875000, 0.0007324218750000, -0.0024414062500000, +0.0008850097656250}, +{0.0010681152343750, -0.0028991699218750, 0.0009155273437500, -0.0033264160156250, +0.0006408691406250, -0.0033264160156250, 0.0012817382812500, -0.0028686523437500, +0.0007629394531250, -0.0036010742187500, 0.0005798339843750, -0.0031738281250000, +0.0004577636718750, -0.0036926269531250, 0.0003662109375000, -0.0038452148437500, +0.0001831054687500, -0.0035705566406250, 0.0000305175781250, -0.0042419433593750, +0.0001831054687500, -0.0035705566406250, 0.0000610351562500, -0.0038146972656250, +0.0001831054687500, -0.0035705566406250, 0.0004272460937500, -0.0028991699218750, +0.0002136230468750, -0.0032653808593750, 0.0004577636718750, -0.0023193359375000, +0.0006103515625000, -0.0023193359375000, 0.0004882812500000, -0.0022583007812500, +0.0005187988281250, -0.0018310546875000, 0.0005798339843750, -0.0021057128906250, +0.0001220703125000, -0.0018005371093750, 0.0003662109375000, -0.0019531250000000, +0.0000610351562500, -0.0021667480468750, -0.0004272460937500, -0.0021667480468750, +0.0000305175781250, -0.0025024414062500, -0.0006713867187500, -0.0028381347656250, +-0.0005798339843750, -0.0028076171875000, -0.0006408691406250, -0.0028686523437500, +-0.0010070800781250, -0.0030212402343750, -0.0008850097656250, -0.0031433105468750, +-0.0014038085937500, -0.0034484863281250, -0.0010986328125000, -0.0033264160156250, +-0.0013732910156250, -0.0036315917968750, -0.0020141601562500, -0.0039978027343750, +-0.0014648437500000, -0.0036315917968750, -0.0021972656250000, -0.0042114257812500, +-0.0020751953125000, -0.0043334960937500, -0.0020141601562500, -0.0042419433593750, +-0.0023193359375000, -0.0044250488281250, -0.0020141601562500, -0.0043945312500000, +-0.0021972656250000, -0.0043029785156250, -0.0020141601562500, -0.0044860839843750, +-0.0020446777343750, -0.0043334960937500, -0.0021667480468750, -0.0041503906250000, +-0.0018310546875000, -0.0043945312500000, -0.0022888183593750, -0.0042724609375000, +-0.0021362304687500, -0.0042724609375000, -0.0020446777343750, -0.0043945312500000, +-0.0023193359375000, -0.0044250488281250, -0.0022277832031250, -0.0043945312500000, +-0.0020446777343750, -0.0045776367187500, -0.0022888183593750, -0.0043334960937500, +-0.0021972656250000, -0.0043945312500000, -0.0019836425781250, -0.0043945312500000, +-0.0022277832031250, -0.0039367675781250, -0.0020446777343750, -0.0044250488281250, +-0.0021362304687500, -0.0039672851562500, -0.0021057128906250, -0.0036926269531250, +-0.0019836425781250, -0.0038757324218750, -0.0021362304687500, -0.0032348632812500, +-0.0015869140625000, -0.0030517578125000, -0.0018920898437500, -0.0029296875000000, +-0.0015869140625000, -0.0024108886718750, -0.0010986328125000, -0.0020141601562500, +-0.0016479492187500, -0.0019836425781250, -0.0007019042968750, -0.0012207031250000, +-0.0009155273437500, -0.0013122558593750, -0.0008850097656250, -0.0010986328125000, +-0.0002746582031250, -0.0005493164062500, -0.0008239746093750, -0.0008850097656250, +-0.0003051757812500, -0.0004577636718750, -0.0005798339843750, -0.0002746582031250, +-0.0006103515625000, -0.0007019042968750, -0.0004577636718750, -0.0007324218750000, +-0.0008239746093750, -0.0005798339843750, -0.0002746582031250, -0.0017700195312500, +-0.0004577636718750, -0.0012512207031250, -0.0003356933593750, -0.0016784667968750, +0.0001831054687500, -0.0027770996093750, -0.0000915527343750, -0.0018920898437500, +0.0000915527343750, -0.0030517578125000, 0.0003356933593750, -0.0028686523437500, +0.0001525878906250, -0.0027160644531250, -0.0000610351562500, -0.0031433105468750, +0.0002136230468750, -0.0027770996093750, 0.0000000000000000, -0.0029296875000000, +0.0000000000000000, -0.0027770996093750, 0.0000305175781250, -0.0029602050781250, +0.0000000000000000, -0.0030822753906250, 0.0000305175781250, -0.0025634765625000, +-0.0001220703125000, -0.0034790039062500, -0.0002746582031250, -0.0028991699218750, +-0.0001525878906250, -0.0034790039062500, -0.0002441406250000, -0.0043945312500000, +-0.0003967285156250, -0.0034179687500000, 0.0000305175781250, -0.0052490234375000, +-0.0004272460937500, -0.0046386718750000, -0.0002136230468750, -0.0045776367187500, +0.0000610351562500, -0.0057983398437500, -0.0009765625000000, -0.0048217773437500, +0.0002441406250000, -0.0047302246093750, -0.0004272460937500, -0.0047912597656250, +-0.0003967285156250, -0.0042114257812500, 0.0006713867187500, -0.0035400390625000, +-0.0001831054687500, -0.0033264160156250, 0.0004272460937500, -0.0032043457031250, +0.0006713867187500, -0.0026550292968750, 0.0002441406250000, -0.0027770996093750, +0.0000305175781250, -0.0028991699218750, -0.0001525878906250, -0.0022888183593750, +-0.0011901855468750, -0.0031433105468750, -0.0009765625000000, -0.0029296875000000, +-0.0019531250000000, -0.0027465820312500, -0.0032653808593750, -0.0030517578125000, +-0.0023193359375000, -0.0028686523437500, -0.0035400390625000, -0.0030212402343750, +-0.0034484863281250, -0.0030822753906250, -0.0034790039062500, -0.0027465820312500, +-0.0040588378906250, -0.0025329589843750, -0.0037231445312500, -0.0026855468750000, +-0.0043640136718750, -0.0020446777343750, -0.0044555664062500, -0.0013732910156250, +-0.0042419433593750, -0.0016479492187500, -0.0046997070312500, -0.0016174316406250, +-0.0049133300781250, -0.0005187988281250, -0.0032958984375000, -0.0010986328125000, +-0.0049743652343750, -0.0007934570312500, -0.0033874511718750, 0.0002441406250000, +-0.0012512207031250, 0.0006103515625000, -0.0041809082031250, 0.0006408691406250, +0.0003051757812500, 0.0017089843750000, -0.0003051757812500, 0.0020751953125000, +-0.0015258789062500, 0.0018920898437500, 0.0012817382812500, 0.0019531250000000, +-0.0005798339843750, 0.0008239746093750, 0.0012817382812500, 0.0023803710937500, +0.0000610351562500, 0.0024719238281250, 0.0000000000000000, 0.0019531250000000, +0.0009155273437500, 0.0019226074218750, 0.0002441406250000, 0.0021057128906250, +-0.0007019042968750, 0.0005798339843750, -0.0003662109375000, 0.0004272460937500, +-0.0009460449218750, 0.0003967285156250, -0.0023498535156250, -0.0004272460937500, +-0.0020751953125000, -0.0003967285156250, -0.0019226074218750, -0.0002441406250000, +-0.0028076171875000, -0.0005798339843750, -0.0019531250000000, -0.0011291503906250, +-0.0006713867187500, -0.0013427734375000, -0.0017395019531250, -0.0014648437500000, +-0.0007019042968750, -0.0022583007812500, -0.0000915527343750, -0.0026245117187500, +-0.0011291503906250, -0.0022888183593750, -0.0014953613281250, -0.0023193359375000, +-0.0005798339843750, -0.0025939941406250, -0.0023803710937500, -0.0010681152343750, +-0.0025329589843750, -0.0014648437500000, -0.0019531250000000, -0.0010070800781250, +-0.0023803710937500, 0.0001831054687500, -0.0024719238281250, -0.0006713867187500, +-0.0016784667968750, 0.0002441406250000, -0.0017089843750000, -0.0000915527343750, +-0.0018005371093750, 0.0001525878906250, -0.0014648437500000, 0.0006713867187500, +-0.0016174316406250, -0.0003051757812500, -0.0021667480468750, 0.0009765625000000, +-0.0021667480468750, 0.0011596679687500, -0.0025024414062500, 0.0007324218750000, +-0.0033264160156250, 0.0010375976562500, -0.0033569335937500, 0.0011596679687500, +-0.0024719238281250, 0.0003967285156250, -0.0038146972656250, -0.0000305175781250, +-0.0027160644531250, 0.0001525878906250, -0.0011596679687500, -0.0000610351562500, +-0.0030212402343750, -0.0005187988281250, -0.0001831054687500, 0.0003356933593750, +-0.0008239746093750, 0.0002441406250000, -0.0009460449218750, 0.0000000000000000, +0.0007629394531250, 0.0003356933593750, -0.0003356933593750, 0.0003356933593750, +-0.0000305175781250, -0.0002441406250000, 0.0004272460937500, -0.0003356933593750, +-0.0003356933593750, -0.0001525878906250, -0.0008239746093750, -0.0003967285156250, +-0.0002746582031250, -0.0006713867187500, -0.0010375976562500, 0.0001220703125000, +-0.0010986328125000, -0.0000610351562500, -0.0006408691406250, -0.0000610351562500, +-0.0007934570312500, 0.0004272460937500, -0.0007934570312500, 0.0002441406250000, +0.0003051757812500, 0.0002136230468750, -0.0000915527343750, 0.0002746582031250, +0.0003967285156250, 0.0002441406250000, 0.0013732910156250, 0.0002441406250000, +0.0007629394531250, 0.0003356933593750, 0.0017700195312500, 0.0001831054687500, +0.0019836425781250, 0.0003051757812500, 0.0016784667968750, 0.0000915527343750, +0.0021057128906250, -0.0001831054687500, 0.0024719238281250, 0.0000915527343750, +0.0014343261718750, -0.0004882812500000, 0.0018615722656250, -0.0005493164062500, +0.0014343261718750, -0.0007019042968750, 0.0003356933593750, -0.0009155273437500, +0.0008850097656250, -0.0008239746093750, -0.0003967285156250, -0.0013427734375000, +-0.0005493164062500, -0.0011596679687500, -0.0009155273437500, -0.0015258789062500, +-0.0017700195312500, -0.0021362304687500, -0.0018310546875000, -0.0017700195312500, +-0.0028076171875000, -0.0023803710937500, -0.0030212402343750, -0.0024108886718750, +-0.0033874511718750, -0.0023498535156250, -0.0040283203125000, -0.0025024414062500, +-0.0038146972656250, -0.0024719238281250, -0.0042724609375000, -0.0025024414062500, +-0.0044250488281250, -0.0025329589843750, -0.0043334960937500, -0.0025024414062500, +-0.0046081542968750, -0.0025634765625000, -0.0047302246093750, -0.0025939941406250, +-0.0043945312500000, -0.0024108886718750, -0.0049438476562500, -0.0024108886718750, +-0.0048828125000000, -0.0023803710937500, -0.0040588378906250, -0.0022888183593750, +-0.0043334960937500, -0.0023193359375000, -0.0040893554687500, -0.0023193359375000, +-0.0036926269531250, -0.0023498535156250, -0.0038146972656250, -0.0023193359375000, +-0.0036621093750000, -0.0022888183593750, -0.0029907226562500, -0.0023193359375000, +-0.0036010742187500, -0.0021667480468750, -0.0031433105468750, -0.0021362304687500, +-0.0031433105468750, -0.0021057128906250, -0.0036010742187500, -0.0020446777343750, +-0.0032348632812500, -0.0020141601562500, -0.0037841796875000, -0.0019226074218750, +-0.0039978027343750, -0.0019531250000000, -0.0040588378906250, -0.0018615722656250, +-0.0044250488281250, -0.0016784667968750, -0.0046691894531250, -0.0017700195312500, +-0.0047302246093750, -0.0015869140625000, -0.0048828125000000, -0.0015258789062500, +-0.0049743652343750, -0.0014953613281250, -0.0049438476562500, -0.0014343261718750, +-0.0049133300781250, -0.0014648437500000, -0.0045166015625000, -0.0012207031250000, +-0.0046691894531250, -0.0014038085937500, -0.0043945312500000, -0.0010375976562500, +-0.0041503906250000, -0.0005798339843750, -0.0047302246093750, -0.0009155273437500, +-0.0037536621093750, -0.0001525878906250, -0.0041503906250000, 0.0000610351562500, +-0.0042114257812500, -0.0000305175781250, -0.0035705566406250, 0.0001525878906250, +-0.0040588378906250, 0.0003662109375000, -0.0035400390625000, 0.0002136230468750, +-0.0033874511718750, 0.0002441406250000, -0.0034484863281250, 0.0002746582031250, +-0.0031433105468750, 0.0002746582031250, -0.0029296875000000, 0.0003051757812500, +-0.0031433105468750, 0.0004577636718750, -0.0024719238281250, 0.0003356933593750, +-0.0025329589843750, 0.0004272460937500, -0.0027770996093750, 0.0005493164062500, +-0.0018005371093750, 0.0002441406250000, -0.0028076171875000, 0.0002441406250000, +-0.0023498535156250, 0.0003051757812500, -0.0025024414062500, 0.0000000000000000, +-0.0031127929687500, -0.0000305175781250, -0.0021972656250000, 0.0003051757812500, +-0.0034179687500000, -0.0003356933593750, -0.0025939941406250, 0.0003967285156250, +-0.0028076171875000, 0.0000305175781250, -0.0035400390625000, -0.0007019042968750, +-0.0021057128906250, 0.0003967285156250, -0.0037841796875000, -0.0010375976562500, +-0.0029296875000000, -0.0003662109375000, -0.0027160644531250, -0.0003967285156250, +-0.0039062500000000}, +{-0.0005187988281250, -0.0000915527343750, -0.0016479492187500, -0.0001525878906250, +-0.0011291503906250, -0.0000610351562500, -0.0013427734375000, -0.0005187988281250, +-0.0017395019531250, -0.0003051757812500, -0.0014953613281250, -0.0006713867187500, +-0.0013732910156250, -0.0012512207031250, -0.0017700195312500, -0.0008850097656250, +-0.0010070800781250, -0.0016174316406250, -0.0012207031250000, -0.0016174316406250, +-0.0012817382812500, -0.0016784667968750, -0.0008239746093750, -0.0021057128906250, +-0.0011291503906250, -0.0019226074218750, -0.0012207031250000, -0.0022277832031250, +-0.0010375976562500, -0.0022888183593750, -0.0011596679687500, -0.0022888183593750, +-0.0012207031250000, -0.0024414062500000, -0.0009460449218750, -0.0025329589843750, +-0.0010986328125000, -0.0022277832031250, -0.0010070800781250, -0.0023498535156250, +-0.0009765625000000, -0.0022888183593750, -0.0010986328125000, -0.0020446777343750, +-0.0011596679687500, -0.0022277832031250, -0.0010070800781250, -0.0021667480468750, +-0.0009460449218750, -0.0021667480468750, -0.0011291503906250, -0.0022888183593750, +-0.0004882812500000, -0.0023193359375000, 0.0005493164062500, -0.0024719238281250, +-0.0007019042968750, -0.0023803710937500, 0.0003967285156250, -0.0025024414062500, +0.0002746582031250, -0.0025634765625000, -0.0005798339843750, -0.0024719238281250, +0.0011291503906250, -0.0025024414062500, -0.0006713867187500, -0.0024108886718750, +0.0003051757812500, -0.0023803710937500, 0.0002746582031250, -0.0022888183593750, +-0.0008544921875000, -0.0021667480468750, 0.0007934570312500, -0.0021972656250000, +-0.0006103515625000, -0.0021362304687500, -0.0000915527343750, -0.0021057128906250, +0.0001220703125000, -0.0021362304687500, -0.0007324218750000, -0.0022277832031250, +-0.0000305175781250, -0.0021057128906250, -0.0004882812500000, -0.0020141601562500, +-0.0006713867187500, -0.0021972656250000, -0.0003967285156250, -0.0018920898437500, +-0.0005187988281250, -0.0014953613281250, -0.0007629394531250, -0.0018005371093750, +0.0000610351562500, -0.0010681152343750, -0.0003051757812500, -0.0010375976562500, +-0.0003356933593750, -0.0011291503906250, 0.0001220703125000, -0.0007934570312500, +-0.0005493164062500, -0.0008544921875000, -0.0000305175781250, -0.0009765625000000, +-0.0006103515625000, -0.0010375976562500, -0.0009155273437500, -0.0009460449218750, +-0.0009765625000000, -0.0009155273437500, -0.0019836425781250, -0.0010375976562500, +-0.0019226074218750, -0.0007934570312500, -0.0026855468750000, -0.0007324218750000, +-0.0030212402343750, -0.0006713867187500, -0.0029907226562500, -0.0006103515625000, +-0.0037231445312500, -0.0006713867187500, -0.0034484863281250, -0.0004882812500000, +-0.0036621093750000, -0.0005798339843750, -0.0035705566406250, -0.0006713867187500, +-0.0032043457031250, -0.0005798339843750, -0.0033874511718750, -0.0006103515625000, +-0.0026550292968750, -0.0007629394531250, -0.0027770996093750, -0.0004882812500000, +-0.0024414062500000, -0.0007934570312500, -0.0017395019531250, -0.0010070800781250, +-0.0021972656250000, -0.0004577636718750, -0.0013732910156250, -0.0015258789062500, +-0.0011596679687500, -0.0010070800781250, -0.0014953613281250, -0.0009765625000000, +-0.0011291503906250, -0.0015869140625000, -0.0007324218750000, -0.0006713867187500, +-0.0020141601562500, -0.0015869140625000, -0.0010986328125000, -0.0008850097656250, +-0.0015869140625000, -0.0008239746093750, -0.0027160644531250, -0.0013122558593750, +-0.0011901855468750, -0.0003967285156250, -0.0026550292968750, -0.0015563964843750, +-0.0026245117187500, -0.0007629394531250, -0.0019836425781250, -0.0007324218750000, +-0.0025634765625000, -0.0018005371093750, -0.0030517578125000, -0.0008850097656250, +-0.0023803710937500, -0.0013122558593750, -0.0031127929687500, -0.0009765625000000, +-0.0036621093750000, -0.0009765625000000, -0.0033569335937500, -0.0012817382812500, +-0.0038146972656250, -0.0006103515625000, -0.0040588378906250, -0.0013732910156250, +-0.0039672851562500, -0.0013732910156250, -0.0037841796875000, -0.0012817382812500, +-0.0034179687500000, -0.0017089843750000, -0.0029296875000000, -0.0017395019531250, +-0.0028076171875000, -0.0015869140625000, -0.0021667480468750, -0.0022583007812500, +-0.0017700195312500, -0.0019836425781250, -0.0014648437500000, -0.0018615722656250, +-0.0007629394531250, -0.0030212402343750, -0.0015563964843750, -0.0013427734375000, +-0.0009155273437500, -0.0024414062500000, -0.0014343261718750, -0.0023498535156250, +-0.0021972656250000, -0.0011291503906250, -0.0009155273437500, -0.0028076171875000, +-0.0024414062500000, -0.0014648437500000, -0.0020751953125000, -0.0014953613281250, +-0.0016174316406250, -0.0018615722656250, -0.0023498535156250, -0.0014038085937500, +-0.0019836425781250, -0.0014648437500000, -0.0014343261718750, -0.0012817382812500, +-0.0020751953125000, -0.0013732910156250, -0.0018920898437500, -0.0008239746093750, +-0.0004882812500000, -0.0003662109375000, 0.0000610351562500, -0.0009460449218750, +0.0003662109375000, -0.0000915527343750, 0.0002441406250000, -0.0002136230468750, +0.0003051757812500, -0.0007324218750000, 0.0006713867187500, -0.0006713867187500, +0.0007324218750000, -0.0008544921875000, 0.0003051757812500, -0.0019226074218750, +0.0000305175781250, -0.0016479492187500, 0.0000305175781250, -0.0021667480468750, +-0.0003967285156250, -0.0031127929687500, -0.0009765625000000, -0.0022277832031250, +-0.0001831054687500, -0.0033264160156250, -0.0008850097656250, -0.0031127929687500, +-0.0006103515625000, -0.0032958984375000, 0.0000610351562500, -0.0042114257812500, +-0.0011596679687500, -0.0036621093750000, -0.0000610351562500, -0.0045471191406250, +-0.0007019042968750, -0.0046081542968750, -0.0009765625000000, -0.0043640136718750, +-0.0006408691406250, -0.0045166015625000, -0.0016784667968750, -0.0043029785156250, +-0.0006103515625000, -0.0038757324218750, -0.0010375976562500, -0.0037536621093750, +-0.0012817382812500, -0.0032348632812500, -0.0004882812500000, -0.0027160644531250, +-0.0006713867187500, -0.0026550292968750, -0.0011596679687500, -0.0021057128906250, +-0.0003967285156250, -0.0022888183593750, -0.0003662109375000, -0.0019531250000000, +-0.0008850097656250, -0.0017700195312500, -0.0001220703125000, -0.0025024414062500, +-0.0003662109375000, -0.0012817382812500, -0.0001831054687500, -0.0018615722656250, +-0.0001525878906250, -0.0018310546875000, -0.0002136230468750, -0.0009460449218750, +0.0000915527343750, -0.0018310546875000, -0.0010681152343750, -0.0011596679687500, +-0.0005493164062500, -0.0014038085937500, -0.0010375976562500, -0.0015563964843750, +-0.0022583007812500, -0.0014038085937500, -0.0014953613281250, -0.0020751953125000, +-0.0028381347656250, -0.0015258789062500, -0.0029907226562500, -0.0021667480468750, +-0.0027160644531250, -0.0018920898437500, -0.0032348632812500, -0.0013427734375000, +-0.0032958984375000, -0.0025939941406250, -0.0027770996093750, -0.0011596679687500, +-0.0032653808593750, -0.0016784667968750, -0.0027770996093750, -0.0017395019531250, +-0.0021667480468750, -0.0008850097656250, -0.0028076171875000, -0.0017700195312500, +-0.0013732910156250, -0.0014953613281250, -0.0018615722656250, -0.0016784667968750, +-0.0014648437500000, -0.0022277832031250, -0.0003967285156250, -0.0023498535156250, +-0.0013427734375000, -0.0024108886718750, -0.0003967285156250, -0.0027770996093750, +-0.0004882812500000, -0.0028076171875000, -0.0007324218750000, -0.0025329589843750, +-0.0003967285156250, -0.0025329589843750, -0.0007629394531250, -0.0027770996093750, +-0.0008239746093750, -0.0021057128906250, -0.0008544921875000, -0.0023803710937500, +-0.0010070800781250, -0.0021362304687500, -0.0009460449218750, -0.0013732910156250, +-0.0009155273437500, -0.0018920898437500, -0.0011291503906250, -0.0012207031250000, +-0.0007324218750000, -0.0010681152343750, -0.0009460449218750, -0.0013427734375000, +-0.0012817382812500, -0.0012207031250000, -0.0007324218750000, -0.0010070800781250, +-0.0016174316406250, -0.0014648437500000, -0.0012817382812500, -0.0011291503906250, +-0.0014343261718750, -0.0011291503906250, -0.0020751953125000, -0.0014953613281250, +-0.0014343261718750, -0.0010681152343750, -0.0021667480468750, -0.0012512207031250, +-0.0021667480468750, -0.0014343261718750, -0.0021362304687500, -0.0014038085937500, +-0.0025634765625000, -0.0015258789062500, -0.0025939941406250, -0.0016784667968750, +-0.0024414062500000, -0.0016174316406250, -0.0027465820312500, -0.0018005371093750, +-0.0026855468750000, -0.0018310546875000, -0.0025634765625000, -0.0017700195312500, +-0.0030517578125000, -0.0020751953125000, -0.0026245117187500, -0.0019836425781250, +-0.0029907226562500, -0.0022277832031250, -0.0029602050781250, -0.0022277832031250, +-0.0026550292968750, -0.0020751953125000, -0.0032043457031250, -0.0023803710937500, +-0.0026855468750000, -0.0021362304687500, -0.0028381347656250, -0.0021667480468750, +-0.0028076171875000, -0.0021972656250000, -0.0023803710937500, -0.0021667480468750, +-0.0025329589843750, -0.0021972656250000, -0.0022888183593750, -0.0019226074218750, +-0.0020751953125000, -0.0022277832031250, -0.0021057128906250, -0.0018920898437500, +-0.0019836425781250, -0.0016479492187500, -0.0016479492187500, -0.0022277832031250, +-0.0018310546875000, -0.0009460449218750, -0.0016174316406250, -0.0018310546875000, +-0.0014343261718750, -0.0013122558593750, -0.0015258789062500, -0.0001831054687500, +-0.0013427734375000, -0.0017089843750000, -0.0013122558593750, 0.0003662109375000, +-0.0012207031250000, -0.0004577636718750, -0.0011901855468750, -0.0003051757812500, +-0.0012817382812500, 0.0011291503906250, -0.0012207031250000, -0.0003356933593750, +-0.0014038085937500, 0.0012512207031250, -0.0015258789062500, 0.0008239746093750, +-0.0014953613281250, 0.0006713867187500, -0.0014953613281250, 0.0014343261718750, +-0.0016174316406250, 0.0006103515625000, -0.0014648437500000, 0.0009765625000000, +-0.0013732910156250, 0.0005798339843750, -0.0014038085937500, 0.0002746582031250, +-0.0013122558593750, 0.0000915527343750, -0.0012512207031250, -0.0004882812500000, +-0.0014648437500000, -0.0003356933593750, -0.0015563964843750, -0.0009765625000000, +-0.0015563964843750, -0.0008850097656250, -0.0016784667968750, -0.0005798339843750, +-0.0017700195312500, -0.0015563964843750, -0.0014648437500000, -0.0000915527343750, +-0.0016174316406250, -0.0006408691406250, -0.0013427734375000, -0.0002136230468750, +-0.0009765625000000, 0.0011901855468750, -0.0013732910156250, 0.0003356933593750, +-0.0005187988281250, 0.0016479492187500, -0.0008239746093750, 0.0019836425781250, +-0.0006713867187500, 0.0014953613281250, -0.0000305175781250, 0.0018920898437500, +-0.0005798339843750, 0.0023193359375000, -0.0002441406250000, 0.0010375976562500, +-0.0006713867187500, 0.0018310546875000, -0.0007019042968750, 0.0011901855468750, +-0.0007019042968750, -0.0001525878906250, -0.0016479492187500, 0.0010986328125000, +-0.0004577636718750, -0.0007629394531250, -0.0009155273437500, -0.0006408691406250, +-0.0009155273437500, -0.0004577636718750, 0.0001525878906250, -0.0011901855468750, +-0.0002746582031250, -0.0006408691406250, -0.0002441406250000, -0.0012207031250000, +-0.0000915527343750, -0.0005798339843750, -0.0003662109375000, -0.0010681152343750, +-0.0009155273437500, -0.0019531250000000, -0.0011596679687500, -0.0010681152343750, +-0.0011901855468750, -0.0029907226562500, -0.0016479492187500, -0.0021667480468750, +-0.0015563964843750, -0.0025024414062500, -0.0014038085937500, -0.0038757324218750, +-0.0020141601562500, -0.0025024414062500, -0.0012207031250000, -0.0039978027343750, +-0.0017700195312500, -0.0036621093750000, -0.0021057128906250, -0.0033264160156250, +-0.0020446777343750, -0.0039367675781250, -0.0028381347656250, -0.0033264160156250, +-0.0020141601562500}, +{-0.0021057128906250, 0.0000610351562500, -0.0024108886718750, 0.0001525878906250, +-0.0025939941406250, 0.0004272460937500, -0.0023803710937500, 0.0004272460937500, +-0.0025024414062500, 0.0002746582031250, -0.0028686523437500, 0.0005187988281250, +-0.0024719238281250, 0.0003967285156250, -0.0028076171875000, 0.0003662109375000, +-0.0028991699218750, 0.0004272460937500, -0.0025939941406250, 0.0003356933593750, +-0.0030212402343750, 0.0001525878906250, -0.0028381347656250, 0.0002441406250000, +-0.0027465820312500, 0.0000915527343750, -0.0027465820312500, 0.0001220703125000, +-0.0026245117187500, 0.0001831054687500, -0.0025939941406250, -0.0001220703125000, +-0.0022583007812500, 0.0003356933593750, -0.0023803710937500, -0.0000610351562500, +-0.0022583007812500, 0.0001525878906250, -0.0019531250000000, 0.0004882812500000, +-0.0021057128906250, -0.0004272460937500, -0.0019531250000000, 0.0004272460937500, +-0.0017700195312500, -0.0004272460937500, -0.0019531250000000, -0.0006713867187500, +-0.0019531250000000, -0.0003051757812500, -0.0015258789062500, -0.0014953613281250, +-0.0021667480468750, -0.0008544921875000, -0.0018005371093750, -0.0016174316406250, +-0.0017700195312500, -0.0019531250000000, -0.0022277832031250, -0.0016174316406250, +-0.0018005371093750, -0.0025634765625000, -0.0021362304687500, -0.0019836425781250, +-0.0021667480468750, -0.0024108886718750, -0.0020751953125000, -0.0023193359375000, +-0.0022277832031250, -0.0018005371093750, -0.0023193359375000, -0.0022888183593750, +-0.0021057128906250, -0.0012207031250000, -0.0023193359375000, -0.0012817382812500, +-0.0022888183593750, -0.0009765625000000, -0.0020446777343750, -0.0001831054687500, +-0.0021667480468750, -0.0003967285156250, -0.0020446777343750, 0.0002441406250000, +-0.0019531250000000, 0.0003967285156250, -0.0017700195312500, 0.0003051757812500, +-0.0016784667968750, 0.0004577636718750, -0.0016784667968750, 0.0004577636718750, +-0.0012207031250000, 0.0000000000000000, -0.0016174316406250, 0.0000305175781250, +-0.0013122558593750, -0.0002136230468750, -0.0007629394531250, -0.0007324218750000, +-0.0014038085937500, -0.0006408691406250, -0.0008239746093750, -0.0008239746093750, +-0.0008850097656250, -0.0011291503906250, -0.0010681152343750, -0.0009155273437500, +-0.0011291503906250, -0.0007324218750000, -0.0014038085937500, -0.0009765625000000, +-0.0008544921875000, -0.0001220703125000, -0.0015563964843750, -0.0000915527343750, +-0.0012207031250000, 0.0000915527343750, -0.0002136230468750, 0.0007934570312500, +-0.0008239746093750, 0.0006713867187500, -0.0004882812500000, 0.0006713867187500, +0.0002746582031250, 0.0009155273437500, -0.0002136230468750, 0.0005493164062500, +-0.0009155273437500, 0.0000000000000000, -0.0004577636718750, 0.0001525878906250, +-0.0011291503906250, -0.0005187988281250, -0.0015563964843750, -0.0007934570312500, +-0.0013732910156250, -0.0007324218750000, -0.0013427734375000, -0.0010375976562500, +-0.0017089843750000, -0.0015258789062500, -0.0012207031250000, -0.0010681152343750, +-0.0015563964843750, -0.0013732910156250, -0.0016784667968750, -0.0017089843750000, +-0.0017089843750000, -0.0013427734375000, -0.0023803710937500, -0.0013122558593750, +-0.0017089843750000, -0.0017700195312500, -0.0028076171875000, -0.0015563964843750, +-0.0024719238281250, -0.0018920898437500, -0.0015563964843750, -0.0023193359375000, +-0.0028381347656250, -0.0018920898437500, -0.0006408691406250, -0.0031433105468750, +-0.0010375976562500, -0.0030212402343750, -0.0007629394531250, -0.0030212402343750, +0.0006408691406250, -0.0035705566406250, -0.0003967285156250, -0.0030822753906250, +0.0009155273437500, -0.0029296875000000, 0.0004882812500000, -0.0029296875000000, +0.0000610351562500, -0.0027160644531250, 0.0007629394531250, -0.0023193359375000, +0.0002746582031250, -0.0023803710937500, 0.0000915527343750, -0.0030822753906250, +0.0004577636718750, -0.0026550292968750, 0.0003662109375000, -0.0030212402343750, +0.0001525878906250, -0.0040283203125000, 0.0003662109375000, -0.0033874511718750, +-0.0005493164062500, -0.0032043457031250, -0.0002746582031250, -0.0036010742187500, +-0.0005187988281250, -0.0026855468750000, -0.0020141601562500, -0.0008544921875000, +-0.0020751953125000, -0.0028686523437500, -0.0026550292968750, -0.0028076171875000, +-0.0027160644531250, -0.0029907226562500, -0.0031127929687500, -0.0020141601562500, +-0.0039062500000000, -0.0010681152343750, -0.0042114257812500, -0.0014343261718750, +-0.0032653808593750, -0.0008239746093750, -0.0043334960937500, -0.0004272460937500, +-0.0034790039062500, -0.0005798339843750, -0.0018005371093750, -0.0006713867187500, +-0.0031433105468750, -0.0002441406250000, -0.0016174316406250, -0.0000610351562500, +-0.0012817382812500, -0.0001831054687500, -0.0022583007812500, 0.0000610351562500, +-0.0023193359375000, 0.0006713867187500, -0.0021057128906250, 0.0005798339843750, +-0.0033874511718750, 0.0005187988281250, -0.0036621093750000, 0.0010681152343750, +-0.0031738281250000, 0.0006713867187500, -0.0034790039062500, 0.0000000000000000, +-0.0039062500000000, 0.0004272460937500, -0.0018920898437500, -0.0001220703125000, +-0.0020751953125000, -0.0007629394531250, -0.0020141601562500, -0.0003356933593750, +-0.0007019042968750, 0.0000305175781250, -0.0008239746093750, -0.0006103515625000, +-0.0009765625000000, -0.0000915527343750, -0.0007324218750000, 0.0001220703125000, +-0.0005798339843750, -0.0002746582031250, -0.0008850097656250, -0.0004577636718750, +-0.0009765625000000, -0.0001831054687500, -0.0002136230468750, -0.0001831054687500, +-0.0007324218750000, -0.0005493164062500, -0.0003051757812500, 0.0001525878906250, +0.0006103515625000, 0.0007934570312500, -0.0001220703125000, 0.0001525878906250, +0.0010070800781250, 0.0014648437500000, 0.0014953613281250, 0.0012817382812500, +0.0011291503906250, 0.0009460449218750, 0.0014343261718750, 0.0015563964843750, +0.0019836425781250, 0.0015563964843750, 0.0009460449218750, 0.0008544921875000, +0.0014343261718750, 0.0011291503906250, 0.0013122558593750, 0.0010375976562500, +0.0003662109375000, 0.0005493164062500, 0.0009460449218750, 0.0007324218750000, +0.0007324218750000, 0.0004577636718750, -0.0000305175781250, 0.0005187988281250, +0.0007629394531250, 0.0004272460937500, 0.0011901855468750, 0.0002441406250000, +-0.0000305175781250, 0.0003662109375000, 0.0020751953125000, 0.0000610351562500, +0.0014038085937500, 0.0000305175781250, 0.0013732910156250, 0.0000305175781250, +0.0025939941406250, -0.0000610351562500, 0.0015563964843750, -0.0000305175781250, +0.0021362304687500, -0.0002441406250000, 0.0019226074218750, -0.0001220703125000, +0.0015563964843750, -0.0003051757812500, 0.0016784667968750, -0.0005493164062500, +0.0010681152343750, -0.0003051757812500, 0.0008544921875000, -0.0007019042968750, +0.0004272460937500, -0.0005493164062500, 0.0000305175781250, -0.0006408691406250, +-0.0003662109375000, -0.0008544921875000, -0.0009155273437500, -0.0005187988281250, +-0.0008239746093750, -0.0011596679687500, -0.0014343261718750, -0.0009765625000000, +-0.0013427734375000, -0.0010681152343750, -0.0011291503906250, -0.0015258789062500, +-0.0018920898437500, -0.0012207031250000, -0.0007019042968750, -0.0014648437500000, +-0.0014038085937500, -0.0014648437500000, -0.0011291503906250, -0.0014953613281250, +-0.0000305175781250, -0.0016174316406250, -0.0010070800781250, -0.0014953613281250, +0.0004272460937500, -0.0016784667968750, 0.0002136230468750, -0.0017395019531250, +0.0003356933593750, -0.0017395019531250, 0.0012817382812500, -0.0018615722656250, +0.0007019042968750, -0.0018615722656250, 0.0014953613281250, -0.0019226074218750, +0.0015258789062500, -0.0019531250000000, 0.0014343261718750, -0.0020141601562500, +0.0018920898437500, -0.0021057128906250, 0.0020446777343750, -0.0021362304687500, +0.0014953613281250, -0.0021667480468750, 0.0027770996093750, -0.0022583007812500, +0.0024719238281250, -0.0022277832031250, 0.0014648437500000, -0.0021362304687500, +0.0027160644531250, -0.0021667480468750, 0.0012207031250000, -0.0021057128906250, +0.0016479492187500, -0.0020141601562500, 0.0016784667968750, -0.0020446777343750, +0.0008239746093750, -0.0020751953125000, 0.0014648437500000, -0.0019226074218750, +0.0006713867187500, -0.0019836425781250, 0.0012817382812500, -0.0020141601562500, +0.0011596679687500, -0.0019531250000000, 0.0007934570312500, -0.0020751953125000, +0.0020141601562500, -0.0021362304687500, 0.0007019042968750, -0.0018615722656250, +0.0019226074218750, -0.0020446777343750, 0.0017700195312500, -0.0020141601562500, +0.0008239746093750, -0.0017395019531250, 0.0026245117187500, -0.0020141601562500, +0.0006408691406250, -0.0017089843750000, 0.0014953613281250, -0.0018005371093750, +0.0014038085937500, -0.0018005371093750, -0.0001220703125000, -0.0016174316406250, +0.0010681152343750, -0.0017700195312500, -0.0001220703125000, -0.0018920898437500, +-0.0004272460937500, -0.0018920898437500, -0.0005187988281250, -0.0018920898437500, +-0.0013427734375000, -0.0019226074218750, -0.0016174316406250, -0.0021057128906250, +-0.0017089843750000, -0.0019226074218750, -0.0023193359375000, -0.0019836425781250, +-0.0021057128906250, -0.0020141601562500, -0.0019226074218750, -0.0019531250000000, +-0.0027770996093750, -0.0020751953125000, -0.0018615722656250, -0.0020751953125000, +-0.0025329589843750, -0.0020141601562500, -0.0023803710937500, -0.0022277832031250, +-0.0017395019531250, -0.0022888183593750, -0.0029296875000000, -0.0021057128906250, +-0.0014343261718750, -0.0026550292968750, -0.0022888183593750, -0.0022888183593750, +-0.0021667480468750, -0.0025024414062500, -0.0009460449218750, -0.0031127929687500, +-0.0021057128906250, -0.0025634765625000, -0.0009765625000000, -0.0032958984375000, +-0.0008544921875000, -0.0033264160156250, -0.0012817382812500, -0.0031127929687500, +-0.0008239746093750, -0.0032958984375000, -0.0007629394531250, -0.0031433105468750, +-0.0015563964843750, -0.0030212402343750, -0.0011596679687500, -0.0031738281250000, +-0.0014343261718750, -0.0027770996093750, -0.0022583007812500, -0.0025939941406250, +-0.0018005371093750, -0.0032348632812500, -0.0024108886718750, -0.0021667480468750, +-0.0024108886718750, -0.0026245117187500, -0.0022888183593750, -0.0025634765625000, +-0.0023803710937500, -0.0019531250000000, -0.0021362304687500, -0.0026550292968750, +-0.0023803710937500, -0.0017089843750000, -0.0018310546875000, -0.0018920898437500, +-0.0019226074218750, -0.0020141601562500, -0.0022888183593750, -0.0014953613281250, +-0.0013427734375000, -0.0016784667968750, -0.0018005371093750, -0.0012512207031250, +-0.0020446777343750, -0.0016784667968750, -0.0012817382812500, -0.0014038085937500, +-0.0016479492187500, -0.0009765625000000, -0.0030517578125000, -0.0016174316406250, +-0.0011291503906250, -0.0007934570312500, -0.0032958984375000, -0.0015258789062500, +-0.0028991699218750, -0.0015563964843750, -0.0009765625000000, -0.0012512207031250, +-0.0038146972656250, -0.0026550292968750, -0.0007629394531250, -0.0011291503906250, +-0.0018310546875000, -0.0021057128906250, -0.0021362304687500, -0.0024108886718750, +-0.0002441406250000, -0.0014343261718750, -0.0018310546875000, -0.0025329589843750, +-0.0013732910156250, -0.0017395019531250, -0.0012512207031250, -0.0018310546875000, +-0.0016174316406250, -0.0018920898437500, -0.0015869140625000, -0.0015563964843750, +-0.0017395019531250, -0.0018310546875000, -0.0016479492187500, -0.0008544921875000, +-0.0010375976562500, -0.0012512207031250, -0.0018005371093750, -0.0010681152343750, +-0.0017089843750000, -0.0002136230468750, 0.0001525878906250, -0.0009460449218750, +-0.0029602050781250, -0.0006713867187500, -0.0009460449218750, -0.0004882812500000, +-0.0005798339843750}, +{-0.0002136230468750, -0.0017700195312500, -0.0003967285156250, -0.0016174316406250, +-0.0006713867187500, -0.0016174316406250, -0.0000915527343750, -0.0017395019531250, +-0.0009155273437500, -0.0015258789062500, -0.0003356933593750, -0.0017089843750000, +-0.0006103515625000, -0.0016479492187500, -0.0011291503906250, -0.0014953613281250, +0.0001525878906250, -0.0017395019531250, -0.0012207031250000, -0.0015869140625000, +-0.0003662109375000, -0.0017089843750000, -0.0002441406250000, -0.0017700195312500, +-0.0012512207031250, -0.0017395019531250, 0.0000000000000000, -0.0019531250000000, +-0.0007629394531250, -0.0019531250000000, -0.0007324218750000, -0.0019531250000000, +-0.0003662109375000, -0.0019836425781250, -0.0007019042968750, -0.0019836425781250, +-0.0007324218750000, -0.0020141601562500, -0.0001525878906250, -0.0020141601562500, +-0.0008239746093750, -0.0020446777343750, -0.0003356933593750, -0.0021667480468750, +0.0003356933593750, -0.0022277832031250, -0.0007324218750000, -0.0022888183593750, +0.0006103515625000, -0.0027770996093750, 0.0001220703125000, -0.0025939941406250, +0.0000305175781250, -0.0029296875000000, 0.0007629394531250, -0.0034179687500000, +-0.0001831054687500, -0.0030822753906250, 0.0005798339843750, -0.0038146972656250, +-0.0002136230468750, -0.0038452148437500, -0.0003356933593750, -0.0037841796875000, +-0.0000305175781250, -0.0041809082031250, -0.0014038085937500, -0.0041198730468750, +-0.0002441406250000, -0.0039367675781250, -0.0008850097656250, -0.0041503906250000, +-0.0009155273437500, -0.0039367675781250, 0.0000000000000000, -0.0038146972656250, +-0.0009155273437500, -0.0042114257812500, 0.0000915527343750, -0.0031433105468750, +0.0001831054687500, -0.0039978027343750, 0.0001831054687500, -0.0037231445312500, +0.0007934570312500, -0.0027465820312500, 0.0007019042968750, -0.0038757324218750, +0.0007629394531250, -0.0027465820312500, 0.0010070800781250, -0.0032958984375000, +0.0007019042968750, -0.0030517578125000, 0.0004882812500000, -0.0021057128906250, +0.0007019042968750, -0.0028686523437500, -0.0004272460937500, -0.0016784667968750, +0.0000915527343750, -0.0017089843750000, -0.0006103515625000, -0.0014038085937500, +-0.0017395019531250, -0.0008239746093750, -0.0005798339843750, -0.0014953613281250, +-0.0023498535156250, -0.0004882812500000, -0.0020141601562500, -0.0009460449218750, +-0.0010986328125000, -0.0010986328125000, -0.0016174316406250, -0.0007934570312500, +-0.0018920898437500, -0.0015869140625000, -0.0016784667968750, -0.0009460449218750, +-0.0028381347656250, -0.0015869140625000, -0.0027160644531250, -0.0015869140625000, +-0.0027770996093750, -0.0009460449218750, -0.0048217773437500, -0.0018310546875000, +-0.0027770996093750, -0.0016784667968750, -0.0046081542968750, -0.0016174316406250, +-0.0040588378906250, -0.0017700195312500, -0.0022888183593750, -0.0019226074218750, +-0.0050048828125000, -0.0021667480468750, -0.0013732910156250, -0.0017700195312500, +-0.0024719238281250, -0.0017395019531250, -0.0026245117187500, -0.0016174316406250, +-0.0005798339843750, -0.0012207031250000, -0.0025024414062500, -0.0012207031250000, +-0.0009765625000000, -0.0012207031250000, -0.0013122558593750, -0.0010681152343750, +-0.0018615722656250, -0.0011596679687500, -0.0010070800781250, -0.0013427734375000, +-0.0013122558593750, -0.0011291503906250, -0.0019531250000000, -0.0015869140625000, +-0.0004882812500000, -0.0016174316406250, -0.0010375976562500, -0.0019836425781250, +-0.0028076171875000, -0.0023803710937500, -0.0015869140625000, -0.0021362304687500, +-0.0014038085937500, -0.0034179687500000, -0.0018005371093750, -0.0031433105468750, +-0.0013732910156250, -0.0028991699218750, -0.0010681152343750, -0.0036315917968750, +-0.0016174316406250, -0.0033569335937500, -0.0002136230468750, -0.0030822753906250, +-0.0006103515625000, -0.0035400390625000, -0.0005493164062500, -0.0036315917968750, +0.0002746582031250, -0.0034790039062500, -0.0003967285156250, -0.0041809082031250, +-0.0003356933593750, -0.0040588378906250, -0.0001831054687500, -0.0042114257812500, +-0.0004577636718750, -0.0042114257812500, -0.0006713867187500, -0.0041503906250000, +-0.0005187988281250, -0.0043640136718750, -0.0003967285156250, -0.0033569335937500, +-0.0001525878906250, -0.0036926269531250, -0.0002136230468750, -0.0031738281250000, +-0.0001220703125000, -0.0023193359375000, 0.0003967285156250, -0.0031738281250000, +0.0000305175781250, -0.0018615722656250, 0.0000305175781250, -0.0024414062500000, +0.0003051757812500, -0.0025329589843750, 0.0000610351562500, -0.0018005371093750, +-0.0003356933593750, -0.0026855468750000, 0.0004577636718750, -0.0017089843750000, +0.0000000000000000, -0.0021362304687500, -0.0000915527343750, -0.0018310546875000, +0.0004882812500000, -0.0009765625000000, -0.0000915527343750, -0.0017089843750000, +-0.0002136230468750, -0.0002746582031250, -0.0000305175781250, -0.0005187988281250, +-0.0005493164062500, -0.0004272460937500, -0.0009155273437500, 0.0002441406250000, +-0.0004577636718750, -0.0003967285156250, -0.0015563964843750, 0.0003662109375000, +-0.0009765625000000, -0.0000305175781250, -0.0010986328125000, 0.0000610351562500, +-0.0017395019531250, 0.0007019042968750, -0.0006713867187500, 0.0000610351562500, +-0.0019836425781250, 0.0009155273437500, -0.0012817382812500, 0.0006103515625000, +-0.0014038085937500, 0.0003967285156250, -0.0024414062500000, 0.0010070800781250, +-0.0015563964843750, 0.0005187988281250, -0.0027770996093750, 0.0002746582031250, +-0.0024719238281250, 0.0004882812500000, -0.0026550292968750, 0.0001525878906250, +-0.0033874511718750, -0.0003356933593750, -0.0027160644531250, 0.0000305175781250, +-0.0037536621093750, -0.0003662109375000, -0.0036315917968750, -0.0005493164062500, +-0.0033569335937500, -0.0002136230468750, -0.0039062500000000, -0.0001831054687500, +-0.0036010742187500, -0.0003967285156250, -0.0030212402343750, 0.0002136230468750, +-0.0031738281250000, 0.0001831054687500, -0.0027160644531250, 0.0001525878906250, +-0.0020141601562500, 0.0006408691406250, -0.0023498535156250, 0.0006713867187500, +-0.0015869140625000, 0.0003967285156250, -0.0016479492187500, 0.0009460449218750, +-0.0016174316406250, 0.0007019042968750, -0.0011901855468750, 0.0003356933593750, +-0.0012817382812500, 0.0011901855468750, -0.0010375976562500, 0.0003662109375000, +-0.0009155273437500, 0.0008544921875000, -0.0009460449218750, 0.0009765625000000, +-0.0008544921875000, 0.0005798339843750, -0.0007629394531250, 0.0011901855468750, +-0.0011291503906250, 0.0007019042968750, -0.0009155273437500, 0.0007934570312500, +-0.0010070800781250, 0.0007934570312500, -0.0013122558593750, 0.0005187988281250, +-0.0010681152343750, 0.0007019042968750, -0.0014038085937500, 0.0005493164062500, +-0.0010681152343750, 0.0005798339843750, -0.0012817382812500, 0.0005187988281250, +-0.0015869140625000, 0.0004577636718750, -0.0009765625000000, 0.0007629394531250, +-0.0020446777343750, 0.0003051757812500, -0.0015258789062500, 0.0006713867187500, +-0.0016479492187500, 0.0007629394531250, -0.0024108886718750, 0.0005187988281250, +-0.0014038085937500, 0.0010681152343750, -0.0024414062500000, 0.0008850097656250, +-0.0020141601562500, 0.0012512207031250, -0.0019226074218750, 0.0014343261718750, +-0.0025634765625000, 0.0013427734375000, -0.0018310546875000, 0.0015869140625000, +-0.0025024414062500, 0.0017089843750000, -0.0023193359375000, 0.0015869140625000, +-0.0022277832031250, 0.0016784667968750, -0.0025634765625000, 0.0016784667968750, +-0.0022277832031250, 0.0014038085937500, -0.0026245117187500, 0.0017395019531250, +-0.0024414062500000, 0.0014343261718750, -0.0024414062500000, 0.0013427734375000, +-0.0027160644531250, 0.0014343261718750, -0.0025329589843750, 0.0009460449218750, +-0.0026550292968750, 0.0008850097656250, -0.0027770996093750, 0.0006408691406250, +-0.0026245117187500, 0.0004882812500000, -0.0025939941406250, 0.0003967285156250, +-0.0026855468750000, 0.0002441406250000, -0.0025634765625000, 0.0003051757812500, +-0.0025329589843750, 0.0001831054687500, -0.0025939941406250, 0.0001831054687500, +-0.0025329589843750, 0.0001220703125000, -0.0025329589843750, -0.0000305175781250, +-0.0026245117187500, 0.0005187988281250, -0.0024414062500000, 0.0002441406250000, +-0.0025024414062500, 0.0006713867187500, -0.0025634765625000, 0.0011901855468750, +-0.0021362304687500, 0.0006713867187500, -0.0023498535156250, 0.0017700195312500, +-0.0021972656250000, 0.0015869140625000, -0.0018615722656250, 0.0015869140625000, +-0.0018920898437500, 0.0021362304687500, -0.0019226074218750, 0.0018005371093750, +-0.0013732910156250, 0.0020751953125000, -0.0015563964843750, 0.0020751953125000, +-0.0016174316406250, 0.0019226074218750, -0.0013122558593750, 0.0018920898437500, +-0.0015258789062500, 0.0017395019531250, -0.0015869140625000, 0.0016174316406250, +-0.0015258789062500, 0.0013427734375000, -0.0015258789062500, 0.0014343261718750, +-0.0016174316406250, 0.0013122558593750, -0.0016479492187500, 0.0007934570312500, +-0.0013122558593750, 0.0018615722656250, -0.0014038085937500, 0.0010986328125000, +-0.0012817382812500, 0.0014648437500000, -0.0008239746093750, 0.0025024414062500, +-0.0007019042968750, 0.0014343261718750, -0.0009765625000000, 0.0027770996093750, +-0.0006408691406250, 0.0025329589843750, -0.0005798339843750, 0.0022277832031250, +-0.0010070800781250, 0.0028381347656250, -0.0010375976562500, 0.0022888183593750, +-0.0008544921875000, 0.0018005371093750, -0.0009460449218750, 0.0026855468750000, +-0.0012207031250000, 0.0018310546875000, -0.0011596679687500, 0.0005798339843750, +-0.0010375976562500, 0.0016784667968750, -0.0018310546875000, -0.0000305175781250, +-0.0017395019531250, 0.0000915527343750, -0.0018310546875000, 0.0001525878906250, +-0.0024108886718750, -0.0005493164062500, -0.0024414062500000, 0.0001831054687500, +-0.0022583007812500, -0.0003662109375000, -0.0025939941406250, -0.0008850097656250, +-0.0025939941406250, -0.0006408691406250, -0.0020446777343750, -0.0006103515625000, +-0.0019226074218750, -0.0010986328125000, -0.0018920898437500, -0.0010070800781250, +-0.0016479492187500, -0.0007324218750000, -0.0010986328125000, -0.0009765625000000, +-0.0009765625000000, -0.0012207031250000, -0.0013427734375000, -0.0012512207031250, +-0.0002746582031250, -0.0021057128906250, -0.0006408691406250, -0.0026550292968750, +-0.0009460449218750, -0.0028076171875000, -0.0002746582031250, -0.0032958984375000, +-0.0005493164062500, -0.0037841796875000, -0.0012817382812500, -0.0028381347656250, +-0.0008239746093750, -0.0032348632812500, -0.0010986328125000, -0.0028991699218750, +-0.0019531250000000, -0.0016479492187500, -0.0015258789062500, -0.0020446777343750, +-0.0019531250000000, -0.0021362304687500, -0.0022583007812500, -0.0016479492187500, +-0.0023193359375000, -0.0021667480468750, -0.0025329589843750, -0.0031127929687500, +-0.0027465820312500, -0.0028686523437500, -0.0029296875000000, -0.0029907226562500, +-0.0031433105468750, -0.0036621093750000, -0.0034790039062500, -0.0033569335937500, +-0.0038452148437500, -0.0023498535156250, -0.0049438476562500, -0.0046997070312500, +-0.0029296875000000, -0.0036315917968750, -0.0035400390625000, -0.0047607421875000, +-0.0035705566406250, -0.0040283203125000, -0.0027160644531250, -0.0026245117187500, +-0.0025634765625000, -0.0033264160156250, -0.0031433105468750, -0.0031433105468750, +-0.0027770996093750, -0.0025939941406250, -0.0023803710937500, -0.0029296875000000, +-0.0026550292968750, -0.0034484863281250, -0.0024719238281250, -0.0029602050781250, +-0.0014038085937500, -0.0027160644531250, -0.0013427734375000, -0.0031738281250000, +-0.0012207031250000, -0.0024414062500000, -0.0003356933593750, -0.0014648437500000, +-0.0001525878906250}, +{-0.0015258789062500, 0.0030822753906250, -0.0014953613281250, 0.0033874511718750, +-0.0011596679687500, 0.0026245117187500, -0.0010070800781250, 0.0024414062500000, +-0.0010681152343750, 0.0023498535156250, -0.0010375976562500, 0.0019531250000000, +-0.0010070800781250, 0.0019226074218750, -0.0013122558593750, 0.0021057128906250, +-0.0014038085937500, 0.0018615722656250, -0.0014038085937500, 0.0020751953125000, +-0.0015869140625000, 0.0023498535156250, -0.0016479492187500, 0.0020446777343750, +-0.0012207031250000, 0.0027160644531250, -0.0014953613281250, 0.0027465820312500, +-0.0013427734375000, 0.0027160644531250, -0.0007629394531250, 0.0031433105468750, +-0.0010375976562500, 0.0029907226562500, -0.0007934570312500, 0.0027160644531250, +-0.0004577636718750, 0.0028076171875000, -0.0006713867187500, 0.0026550292968750, +-0.0008850097656250, 0.0021972656250000, -0.0007324218750000, 0.0021057128906250, +-0.0010375976562500, 0.0020446777343750, -0.0012817382812500, 0.0014648437500000, +-0.0012817382812500, 0.0016479492187500, -0.0012817382812500, 0.0018005371093750, +-0.0013427734375000, 0.0010986328125000, -0.0015869140625000, 0.0022888183593750, +-0.0013122558593750, 0.0021972656250000, -0.0014648437500000, 0.0021972656250000, +-0.0018920898437500, 0.0031127929687500, -0.0017089843750000, 0.0029296875000000, +-0.0020141601562500, 0.0026245117187500, -0.0020751953125000, 0.0029296875000000, +-0.0022277832031250, 0.0024414062500000, -0.0024414062500000, 0.0017700195312500, +-0.0022583007812500, 0.0021362304687500, -0.0027465820312500, 0.0012207031250000, +-0.0025329589843750, 0.0011596679687500, -0.0024414062500000, 0.0011291503906250, +-0.0027160644531250, 0.0004272460937500, -0.0021057128906250, 0.0002441406250000, +-0.0017395019531250, 0.0006408691406250, -0.0020751953125000, 0.0000305175781250, +-0.0015563964843750, 0.0002441406250000, -0.0009155273437500, 0.0009765625000000, +-0.0017395019531250, 0.0005493164062500, -0.0016479492187500, 0.0006408691406250, +-0.0014343261718750, 0.0007629394531250, -0.0020141601562500, -0.0000305175781250, +-0.0023803710937500, -0.0005493164062500, -0.0018615722656250, -0.0005798339843750, +-0.0023803710937500, -0.0028076171875000, -0.0025939941406250, -0.0027160644531250, +-0.0023498535156250, -0.0032653808593750, -0.0024719238281250, -0.0048522949218750, +-0.0028991699218750, -0.0041198730468750, -0.0028991699218750, -0.0041809082031250, +-0.0031433105468750, -0.0042114257812500, -0.0035095214843750, -0.0037231445312500, +-0.0038146972656250, -0.0032653808593750, -0.0042114257812500, -0.0032653808593750, +-0.0041198730468750, -0.0037841796875000, -0.0048828125000000, -0.0036621093750000, +-0.0046691894531250, -0.0038452148437500, -0.0033874511718750, -0.0047607421875000, +-0.0040893554687500, -0.0042114257812500, -0.0043640136718750, -0.0061340332031250, +-0.0041503906250000, -0.0053405761718750, -0.0038452148437500, -0.0049133300781250, +-0.0035095214843750, -0.0057067871093750, -0.0032348632812500, -0.0056762695312500, +-0.0027160644531250, -0.0039367675781250, -0.0021362304687500, -0.0042114257812500, +-0.0021362304687500, -0.0038452148437500, -0.0019226074218750, -0.0023803710937500, +-0.0010375976562500, -0.0028381347656250, -0.0019226074218750, -0.0028381347656250, +-0.0012817382812500, -0.0024108886718750, -0.0007324218750000, -0.0027770996093750, +-0.0009460449218750, -0.0034179687500000, -0.0001525878906250, -0.0031433105468750, +0.0006408691406250, -0.0026245117187500, 0.0011596679687500, -0.0028991699218750, +0.0015563964843750, -0.0025329589843750, 0.0024414062500000, -0.0015869140625000, +0.0030212402343750, -0.0018310546875000, 0.0016784667968750, -0.0022277832031250, +0.0029907226562500, -0.0017395019531250, 0.0022583007812500, -0.0019226074218750, +0.0003662109375000, -0.0026245117187500, 0.0018920898437500, -0.0020751953125000, +0.0003051757812500, -0.0016479492187500, 0.0000915527343750, -0.0021057128906250, +0.0007934570312500, -0.0014648437500000, 0.0005187988281250, -0.0006103515625000, +0.0006408691406250, -0.0013122558593750, 0.0019531250000000, -0.0008239746093750, +0.0017700195312500, -0.0007019042968750, 0.0020751953125000, -0.0010681152343750, +0.0030822753906250, -0.0013122558593750, 0.0027160644531250, -0.0012512207031250, +0.0023803710937500, -0.0010070800781250, 0.0026550292968750, -0.0012817382812500, +0.0024414062500000, -0.0007629394531250, 0.0018920898437500, 0.0000610351562500, +0.0020141601562500, -0.0001525878906250, 0.0015563964843750, 0.0003967285156250, +0.0014648437500000, 0.0007629394531250, 0.0015258789062500, 0.0005798339843750, +0.0013122558593750, 0.0004882812500000, 0.0013122558593750, 0.0007324218750000, +0.0018310546875000, 0.0004577636718750, 0.0016174316406250, 0.0007324218750000, +0.0017395019531250, 0.0008239746093750, 0.0022277832031250, 0.0008850097656250, +0.0020751953125000, 0.0012817382812500, 0.0019531250000000, 0.0007324218750000, +0.0021057128906250, 0.0011291503906250, 0.0018005371093750, 0.0007934570312500, +0.0013122558593750, 0.0001525878906250, 0.0013732910156250, 0.0007629394531250, +0.0008239746093750, -0.0001831054687500, 0.0006103515625000, 0.0000610351562500, +0.0004882812500000, 0.0000915527343750, 0.0002136230468750, -0.0003967285156250, +0.0001831054687500, 0.0001525878906250, 0.0003051757812500, -0.0005493164062500, +0.0000305175781250, -0.0003356933593750, 0.0004882812500000, -0.0002441406250000, +0.0009155273437500, -0.0005798339843750, 0.0005187988281250, -0.0003051757812500, +0.0016784667968750, -0.0003662109375000, 0.0015563964843750, -0.0002136230468750, +0.0018005371093750, -0.0002441406250000, 0.0027160644531250, -0.0003051757812500, +0.0023803710937500, -0.0000305175781250, 0.0028686523437500, -0.0003662109375000, +0.0032348632812500, -0.0002136230468750, 0.0030212402343750, -0.0001525878906250, +0.0030822753906250, -0.0003051757812500, 0.0035095214843750, -0.0000305175781250, +0.0027770996093750, -0.0001831054687500, 0.0033569335937500, -0.0000305175781250, +0.0033874511718750, -0.0000610351562500, 0.0029296875000000, -0.0001831054687500, +0.0037231445312500, -0.0000305175781250, 0.0029907226562500, -0.0003356933593750, +0.0034790039062500, -0.0001831054687500, 0.0036010742187500, -0.0002746582031250, +0.0031127929687500, -0.0004882812500000, 0.0038146972656250, -0.0001525878906250, +0.0034790039062500, -0.0006103515625000, 0.0032653808593750, -0.0003662109375000, +0.0034484863281250, -0.0004272460937500, 0.0036010742187500, -0.0008544921875000, +0.0035095214843750, -0.0005798339843750, 0.0035705566406250, -0.0008850097656250, +0.0036621093750000, -0.0008239746093750, 0.0036010742187500, -0.0008239746093750, +0.0035400390625000, -0.0010070800781250, 0.0035400390625000, -0.0008544921875000, +0.0034484863281250, -0.0010375976562500, 0.0034179687500000, -0.0009765625000000, +0.0033264160156250, -0.0009765625000000, 0.0032653808593750, -0.0011291503906250, +0.0032958984375000, -0.0010070800781250, 0.0032043457031250, -0.0011901855468750, +0.0032348632812500, -0.0011291503906250, 0.0032043457031250, -0.0011901855468750, +0.0031433105468750, -0.0013427734375000, 0.0032653808593750, -0.0012207031250000, +0.0032043457031250, -0.0012817382812500, 0.0033569335937500, -0.0013732910156250, +0.0033569335937500, -0.0013732910156250, 0.0034790039062500, -0.0013427734375000, +0.0039367675781250, -0.0015258789062500, 0.0034484863281250, -0.0015869140625000, +0.0042724609375000, -0.0017089843750000, 0.0043029785156250, -0.0018615722656250, +0.0039978027343750, -0.0019226074218750, 0.0051574707031250, -0.0020446777343750, +0.0041503906250000, -0.0022888183593750, 0.0045166015625000, -0.0022277832031250, +0.0045471191406250, -0.0025329589843750, 0.0037841796875000, -0.0028991699218750, +0.0040588378906250, -0.0027770996093750, 0.0037536621093750, -0.0032958984375000, +0.0030822753906250, -0.0035095214843750, 0.0032043457031250, -0.0035095214843750, +0.0031433105468750, -0.0037231445312500, 0.0022277832031250, -0.0040588378906250, +0.0028991699218750, -0.0036926269531250, 0.0023498535156250, -0.0041198730468750, +0.0022888183593750, -0.0040588378906250, 0.0024719238281250, -0.0038757324218750, +0.0014343261718750, -0.0045776367187500, 0.0025024414062500, -0.0037536621093750, +0.0015563964843750, -0.0043334960937500, 0.0017395019531250, -0.0043029785156250, +0.0026245117187500, -0.0036621093750000, 0.0012512207031250, -0.0043334960937500, +0.0029296875000000, -0.0034179687500000, 0.0024719238281250, -0.0036315917968750, +0.0021972656250000, -0.0032348632812500, 0.0032043457031250, -0.0023803710937500, +0.0025024414062500, -0.0029907226562500, 0.0023193359375000, -0.0021057128906250, +0.0026550292968750, -0.0021362304687500, 0.0021667480468750, -0.0022888183593750, +0.0017089843750000, -0.0021362304687500, 0.0022277832031250, -0.0024719238281250, +0.0012817382812500, -0.0020141601562500, 0.0014648437500000, -0.0022277832031250, +0.0016174316406250, -0.0022583007812500, 0.0012207031250000, -0.0018920898437500, +0.0015563964843750, -0.0021362304687500, 0.0010375976562500, -0.0020141601562500, +0.0016784667968750, -0.0017395019531250, 0.0010375976562500, -0.0021057128906250, +0.0003967285156250, -0.0021667480468750, 0.0019226074218750, -0.0015563964843750, +0.0002441406250000, -0.0023193359375000, 0.0008544921875000, -0.0015869140625000, +0.0007324218750000, -0.0015869140625000, -0.0006713867187500, -0.0019836425781250, +0.0000305175781250, -0.0008239746093750, -0.0010986328125000, -0.0019226074218750, +-0.0018310546875000, -0.0007019042968750, -0.0018920898437500, -0.0007934570312500, +-0.0018615722656250, -0.0019836425781250, -0.0020141601562500, -0.0005493164062500, +-0.0022888183593750, -0.0018310546875000, -0.0018615722656250, -0.0018920898437500, +-0.0020751953125000, -0.0014648437500000, -0.0026550292968750, -0.0018005371093750, +-0.0021362304687500, -0.0017700195312500, -0.0025024414062500, -0.0018005371093750, +-0.0030517578125000, -0.0014953613281250, -0.0024108886718750, -0.0018920898437500, +-0.0022583007812500, -0.0021057128906250, -0.0031738281250000, -0.0015563964843750, +-0.0010681152343750, -0.0026550292968750, -0.0020141601562500, -0.0021972656250000, +-0.0020446777343750, -0.0020141601562500, -0.0005798339843750, -0.0026550292968750, +-0.0022583007812500, -0.0021972656250000, -0.0029602050781250, -0.0027770996093750, +-0.0024414062500000, -0.0025939941406250, -0.0022583007812500, -0.0025024414062500, +-0.0023498535156250, -0.0030212402343750, -0.0018310546875000, -0.0028991699218750, +-0.0017395019531250, -0.0027770996093750, -0.0012512207031250, -0.0027770996093750, +-0.0012817382812500, -0.0024414062500000, -0.0010375976562500, -0.0021057128906250, +-0.0000915527343750, -0.0021057128906250, -0.0010070800781250, -0.0014648437500000, +-0.0002441406250000, -0.0018310546875000, 0.0000610351562500, -0.0012207031250000, +-0.0007019042968750, -0.0007019042968750, -0.0000610351562500, -0.0018920898437500, +-0.0001525878906250, -0.0001220703125000, -0.0001831054687500, -0.0010681152343750, +-0.0000305175781250, -0.0011291503906250, -0.0000610351562500, 0.0000915527343750, +-0.0000915527343750, -0.0012207031250000, 0.0003051757812500, 0.0000305175781250, +0.0002746582031250, -0.0002441406250000, 0.0002136230468750, -0.0002746582031250, +0.0006103515625000, 0.0003051757812500, 0.0007019042968750, -0.0003356933593750, +0.0002136230468750, 0.0011901855468750, 0.0006103515625000, 0.0001525878906250, +0.0004272460937500, 0.0009765625000000, -0.0004577636718750, 0.0024108886718750, +-0.0003967285156250, 0.0003662109375000, -0.0004272460937500, 0.0029296875000000, +-0.0011291503906250}, +{0.0040283203125000, -0.0030822753906250, 0.0031738281250000, -0.0034179687500000, +0.0029296875000000, -0.0032653808593750, 0.0034179687500000, -0.0025939941406250, +0.0020141601562500, -0.0031738281250000, 0.0028991699218750, -0.0021667480468750, +0.0018310546875000, -0.0023498535156250, 0.0018005371093750, -0.0024108886718750, +0.0026245117187500, -0.0019226074218750, 0.0011901855468750, -0.0023193359375000, +0.0028686523437500, -0.0019531250000000, 0.0024108886718750, -0.0024414062500000, +0.0022583007812500, -0.0022277832031250, 0.0033569335937500, -0.0018615722656250, +0.0027465820312500, -0.0027465820312500, 0.0028991699218750, -0.0017089843750000, +0.0034179687500000, -0.0021362304687500, 0.0029296875000000, -0.0022888183593750, +0.0026245117187500, -0.0018310546875000, 0.0031433105468750, -0.0024719238281250, +0.0017700195312500, -0.0020141601562500, 0.0024414062500000, -0.0021667480468750, +0.0013732910156250, -0.0023803710937500, -0.0000915527343750, -0.0019531250000000, +0.0018920898437500, -0.0018310546875000, -0.0002441406250000, -0.0020446777343750, +0.0007934570312500, -0.0014038085937500, 0.0010681152343750, -0.0015563964843750, +-0.0000610351562500, -0.0018005371093750, 0.0015258789062500, -0.0007934570312500, +-0.0000305175781250, -0.0020446777343750, 0.0003051757812500, -0.0015869140625000, +0.0001525878906250, -0.0013732910156250, -0.0010681152343750, -0.0021362304687500, +-0.0005798339843750, -0.0015869140625000, -0.0015563964843750, -0.0015258789062500, +-0.0010070800781250, -0.0015869140625000, -0.0009155273437500, -0.0017089843750000, +-0.0014648437500000, -0.0015563964843750, -0.0005798339843750, -0.0012817382812500, +-0.0010375976562500, -0.0021362304687500, -0.0005187988281250, -0.0015869140625000, +-0.0005493164062500, -0.0019226074218750, -0.0011596679687500, -0.0026855468750000, +-0.0005493164062500, -0.0016174316406250, -0.0010070800781250, -0.0025634765625000, +-0.0016174316406250, -0.0023193359375000, -0.0008850097656250, -0.0020446777343750, +-0.0010681152343750, -0.0026855468750000, -0.0036010742187500, -0.0027160644531250, +-0.0035095214843750, -0.0025329589843750, -0.0032348632812500, -0.0026550292968750, +-0.0034179687500000, -0.0026550292968750, -0.0032653808593750, -0.0023498535156250, +-0.0028076171875000, -0.0021362304687500, -0.0028686523437500, -0.0023803710937500, +-0.0028076171875000, -0.0018310546875000, -0.0021362304687500, -0.0016479492187500, +-0.0017089843750000, -0.0018005371093750, -0.0017089843750000, -0.0011901855468750, +-0.0005493164062500, -0.0006713867187500, 0.0000915527343750, -0.0009765625000000, +0.0000915527343750, -0.0004272460937500, 0.0005798339843750, 0.0001831054687500, +0.0012512207031250, -0.0005798339843750, 0.0003967285156250, 0.0002136230468750, +0.0007324218750000, 0.0000305175781250, 0.0007629394531250, 0.0000610351562500, +0.0001525878906250, 0.0005187988281250, 0.0004577636718750, 0.0001831054687500, +0.0001525878906250, 0.0010375976562500, 0.0000610351562500, 0.0006408691406250, +-0.0000915527343750, 0.0012512207031250, -0.0002746582031250, 0.0021667480468750, +-0.0002136230468750, 0.0012207031250000, -0.0007629394531250, 0.0028686523437500, +-0.0005187988281250, 0.0024414062500000, -0.0006103515625000, 0.0022277832031250, +-0.0009155273437500, 0.0029602050781250, -0.0002746582031250, 0.0021362304687500, +-0.0007934570312500, 0.0022277832031250, -0.0008544921875000, 0.0019226074218750, +-0.0006103515625000, 0.0017089843750000, -0.0008544921875000, 0.0016174316406250, +-0.0010070800781250, 0.0012207031250000, -0.0002136230468750, 0.0015869140625000, +-0.0008239746093750, 0.0014343261718750, -0.0004272460937500, 0.0015869140625000, +0.0004272460937500, 0.0019226074218750, -0.0006408691406250, 0.0016174316406250, +0.0001220703125000, 0.0020141601562500, 0.0000305175781250, 0.0021057128906250, +-0.0003967285156250, 0.0019531250000000, -0.0003356933593750, 0.0019836425781250, +-0.0004577636718750, 0.0021057128906250, -0.0004577636718750, 0.0021057128906250, +-0.0006408691406250, 0.0020751953125000, -0.0005493164062500, 0.0024414062500000, +-0.0003662109375000, 0.0027770996093750, -0.0004577636718750, 0.0026855468750000, +-0.0004882812500000, 0.0033874511718750, -0.0002746582031250, 0.0035705566406250, +-0.0007324218750000, 0.0034484863281250, -0.0009765625000000, 0.0038452148437500, +-0.0006408691406250, 0.0040893554687500, -0.0017089843750000, 0.0033569335937500, +-0.0015563964843750, 0.0039367675781250, -0.0016174316406250, 0.0036010742187500, +-0.0023498535156250, 0.0027770996093750, -0.0020751953125000, 0.0036621093750000, +-0.0021362304687500, 0.0023193359375000, -0.0024414062500000, 0.0026855468750000, +-0.0022583007812500, 0.0025634765625000, -0.0021057128906250, 0.0017700195312500, +-0.0024108886718750, 0.0025024414062500, -0.0018920898437500, 0.0014953613281250, +-0.0021667480468750, 0.0017700195312500, -0.0019226074218750, 0.0019226074218750, +-0.0015258789062500, 0.0014343261718750, -0.0020446777343750, 0.0021362304687500, +-0.0012207031250000, 0.0021057128906250, -0.0014038085937500, 0.0022277832031250, +-0.0012817382812500, 0.0025939941406250, -0.0006713867187500, 0.0028076171875000, +-0.0010070800781250, 0.0028381347656250, -0.0004577636718750, 0.0035705566406250, +-0.0007019042968750, 0.0036010742187500, -0.0005798339843750, 0.0040283203125000, +-0.0001831054687500, 0.0046081542968750, -0.0007629394531250, 0.0043640136718750, +-0.0002441406250000, 0.0050964355468750, -0.0004272460937500, 0.0050354003906250, +-0.0005187988281250, 0.0051269531250000, -0.0002441406250000, 0.0055236816406250, +-0.0005493164062500, 0.0051879882812500, -0.0003662109375000, 0.0055541992187500, +-0.0004577636718750, 0.0054626464843750, -0.0004882812500000, 0.0054016113281250, +-0.0004272460937500, 0.0055541992187500, -0.0006713867187500, 0.0052795410156250, +-0.0003967285156250, 0.0054626464843750, -0.0006713867187500, 0.0052185058593750, +-0.0006408691406250, 0.0051879882812500, -0.0005187988281250, 0.0053100585937500, +-0.0009460449218750, 0.0048522949218750, -0.0007629394531250, 0.0051574707031250, +-0.0009460449218750, 0.0049133300781250, -0.0010375976562500, 0.0048522949218750, +-0.0009460449218750, 0.0050048828125000, -0.0011901855468750, 0.0047912597656250, +-0.0010375976562500, 0.0047912597656250, -0.0011596679687500, 0.0048522949218750, +-0.0012207031250000, 0.0046386718750000, -0.0010986328125000, 0.0044860839843750, +-0.0011291503906250, 0.0046081542968750, -0.0008544921875000, 0.0039672851562500, +-0.0008850097656250, 0.0040588378906250, -0.0005798339843750, 0.0035400390625000, +-0.0001831054687500, 0.0028991699218750, -0.0003967285156250, 0.0032043457031250, +0.0000610351562500, 0.0021972656250000, 0.0000610351562500, 0.0023193359375000, +-0.0001220703125000, 0.0022277832031250, -0.0001220703125000, 0.0015563964843750, +-0.0002441406250000, 0.0019226074218750, -0.0003967285156250, 0.0015869140625000, +-0.0004272460937500, 0.0012817382812500, -0.0005493164062500, 0.0016479492187500, +-0.0006713867187500, 0.0017089843750000, -0.0005798339843750, 0.0013122558593750, +-0.0006408691406250, 0.0025634765625000, -0.0006103515625000, 0.0020141601562500, +-0.0005187988281250, 0.0024719238281250, -0.0004577636718750, 0.0035705566406250, +-0.0003967285156250, 0.0027160644531250, -0.0003662109375000, 0.0036315917968750, +-0.0002746582031250, 0.0036010742187500, -0.0002746582031250, 0.0032653808593750, +-0.0004272460937500, 0.0035400390625000, -0.0005493164062500, 0.0033264160156250, +-0.0003662109375000, 0.0028381347656250, -0.0007934570312500, 0.0027160644531250, +-0.0007324218750000, 0.0026855468750000, -0.0003967285156250, 0.0022888183593750, +-0.0009460449218750, 0.0021667480468750, -0.0006103515625000, 0.0021972656250000, +-0.0007324218750000, 0.0019836425781250, -0.0010375976562500, 0.0021972656250000, +-0.0012207031250000, 0.0024719238281250, -0.0016174316406250, 0.0022277832031250, +-0.0017089843750000, 0.0031433105468750, -0.0021667480468750, 0.0026245117187500, +-0.0022888183593750, 0.0027770996093750, -0.0021667480468750, 0.0036010742187500, +-0.0024414062500000, 0.0029296875000000, -0.0019531250000000, 0.0029296875000000, +-0.0018310546875000, 0.0029907226562500, -0.0016479492187500, 0.0024719238281250, +-0.0014038085937500, 0.0021057128906250, -0.0014038085937500, 0.0020446777343750, +-0.0009460449218750, 0.0015563964843750, -0.0013427734375000, 0.0017395019531250, +-0.0014648437500000, 0.0016479492187500, -0.0012207031250000, 0.0011291503906250, +-0.0016174316406250, 0.0013732910156250, -0.0021667480468750, 0.0014648437500000, +-0.0016479492187500, 0.0012817382812500, -0.0023803710937500, 0.0015869140625000, +-0.0031433105468750, 0.0018615722656250, -0.0018005371093750, 0.0015563964843750, +-0.0034179687500000, 0.0016479492187500, -0.0029296875000000, 0.0020446777343750, +-0.0029296875000000, 0.0014038085937500, -0.0038146972656250, 0.0008850097656250, +-0.0028686523437500, 0.0015258789062500, -0.0040588378906250, 0.0003356933593750, +-0.0034179687500000, -0.0000915527343750, -0.0032958984375000, 0.0002746582031250, +-0.0039062500000000, -0.0000305175781250, -0.0029602050781250, -0.0007324218750000, +-0.0039672851562500, -0.0001831054687500, -0.0033264160156250, -0.0002136230468750, +-0.0035705566406250, -0.0012512207031250, -0.0044250488281250, -0.0014038085937500, +-0.0033264160156250, -0.0009460449218750, -0.0046691894531250, -0.0035705566406250, +-0.0042419433593750, -0.0027770996093750, -0.0036315917968750, -0.0028991699218750, +-0.0043640136718750, -0.0058288574218750, -0.0011291503906250, -0.0020141601562500, +-0.0039672851562500, -0.0041809082031250, -0.0021972656250000, -0.0031127929687500, +-0.0022277832031250, -0.0035705566406250, -0.0032653808593750, -0.0045166015625000, +-0.0020751953125000, -0.0037536621093750, -0.0017395019531250, -0.0045776367187500, +-0.0013427734375000, -0.0039062500000000, -0.0006408691406250, -0.0042114257812500, +0.0000915527343750, -0.0048522949218750, 0.0008239746093750, -0.0035400390625000, +0.0002136230468750, -0.0053710937500000, 0.0011901855468750, -0.0046691894531250, +0.0010681152343750, -0.0042724609375000, 0.0000000000000000, -0.0052185058593750, +0.0009460449218750, -0.0042724609375000, 0.0007324218750000, -0.0039672851562500, +0.0002746582031250, -0.0038452148437500, 0.0012512207031250, -0.0035095214843750, +0.0019531250000000, -0.0032958984375000, 0.0012207031250000, -0.0031127929687500, +0.0024108886718750, -0.0029907226562500, 0.0028076171875000, -0.0030212402343750, +0.0021057128906250, -0.0027770996093750, 0.0019226074218750, -0.0025024414062500, +0.0023193359375000, -0.0025634765625000, 0.0017089843750000, -0.0020751953125000, +0.0012817382812500, -0.0017395019531250, 0.0020141601562500, -0.0019531250000000, +0.0020446777343750, -0.0017395019531250, 0.0012817382812500, -0.0011291503906250, +0.0032958984375000, -0.0021972656250000, 0.0025329589843750, -0.0017089843750000, +0.0028381347656250, -0.0014038085937500, 0.0044860839843750, -0.0020446777343750, +0.0033264160156250, -0.0016479492187500, 0.0037536621093750, -0.0011596679687500, +0.0040588378906250, -0.0013427734375000, 0.0032958984375000, -0.0010681152343750, +0.0027465820312500, -0.0006408691406250, 0.0029602050781250, -0.0008239746093750, +0.0019226074218750, -0.0006713867187500, 0.0018310546875000, -0.0006408691406250, +0.0019531250000000, -0.0005187988281250, 0.0014648437500000, -0.0002746582031250, +0.0014038085937500, -0.0002441406250000, 0.0023193359375000, 0.0003356933593750, +0.0018005371093750, 0.0004882812500000, 0.0022583007812500, 0.0004882812500000, +0.0032653808593750}, +{-0.0016784667968750, 0.0014953613281250, -0.0017089843750000, 0.0024719238281250, +-0.0019836425781250, 0.0018615722656250, -0.0016784667968750, 0.0023498535156250, +-0.0015563964843750, 0.0024108886718750, -0.0021972656250000, 0.0021362304687500, +-0.0021667480468750, 0.0022583007812500, -0.0013122558593750, 0.0023498535156250, +-0.0030517578125000, 0.0017395019531250, -0.0020446777343750, 0.0016784667968750, +-0.0022583007812500, 0.0019836425781250, -0.0035705566406250, 0.0017089843750000, +-0.0021362304687500, 0.0012207031250000, -0.0035400390625000, 0.0021972656250000, +-0.0028381347656250, 0.0015563964843750, -0.0028076171875000, 0.0017395019531250, +-0.0034179687500000, 0.0029602050781250, -0.0018920898437500, 0.0022888183593750, +-0.0034179687500000, 0.0023193359375000, -0.0025634765625000, 0.0030517578125000, +-0.0027160644531250, 0.0018005371093750, -0.0038146972656250, 0.0007324218750000, +-0.0025634765625000, 0.0015258789062500, -0.0041809082031250, -0.0010681152343750, +-0.0036315917968750, -0.0011291503906250, -0.0034179687500000, -0.0010681152343750, +-0.0039672851562500, -0.0023803710937500, -0.0027160644531250, -0.0020141601562500, +-0.0034179687500000, -0.0021362304687500, -0.0022277832031250, -0.0020446777343750, +-0.0020446777343750, -0.0023193359375000, -0.0035705566406250, -0.0028686523437500, +-0.0014953613281250, -0.0028381347656250, -0.0018005371093750, -0.0026855468750000, +-0.0012512207031250, -0.0027465820312500, -0.0009460449218750, -0.0031433105468750, +-0.0005187988281250, -0.0033569335937500, 0.0001831054687500, -0.0031738281250000, +-0.0004577636718750, -0.0041198730468750, 0.0004882812500000, -0.0041809082031250, +0.0005798339843750, -0.0039672851562500, -0.0002136230468750, -0.0042724609375000, +0.0007324218750000, -0.0042419433593750, 0.0008850097656250, -0.0035400390625000, +0.0006408691406250, -0.0030517578125000, 0.0013427734375000, -0.0035705566406250, +0.0021667480468750, -0.0033569335937500, 0.0018920898437500, -0.0023193359375000, +0.0021667480468750, -0.0043640136718750, 0.0028686523437500, -0.0035400390625000, +0.0021362304687500, -0.0033874511718750, 0.0014648437500000, -0.0046691894531250, +0.0023193359375000, -0.0034790039062500, 0.0012817382812500, -0.0039367675781250, +0.0007629394531250, -0.0038757324218750, 0.0018005371093750, -0.0036010742187500, +0.0020751953125000, -0.0036010742187500, 0.0012512207031250, -0.0032043457031250, +0.0032653808593750, -0.0033264160156250, 0.0028686523437500, -0.0030822753906250, +0.0027160644531250, -0.0028991699218750, 0.0038146972656250, -0.0029602050781250, +0.0030822753906250, -0.0027770996093750, 0.0028076171875000, -0.0024414062500000, +0.0027770996093750, -0.0021362304687500, 0.0020141601562500, -0.0020446777343750, +0.0011901855468750, -0.0018310546875000, 0.0013122558593750, -0.0012512207031250, +0.0010375976562500, -0.0017700195312500, 0.0005187988281250, -0.0013427734375000, +0.0011291503906250, -0.0011291503906250, 0.0017089843750000, -0.0015563964843750, +0.0011901855468750, -0.0013122558593750, 0.0024414062500000, -0.0010375976562500, +0.0024414062500000, -0.0012512207031250, 0.0025329589843750, -0.0010070800781250, +0.0032958984375000, -0.0007629394531250, 0.0029602050781250, -0.0009765625000000, +0.0029296875000000, -0.0005187988281250, 0.0031738281250000, -0.0005493164062500, +0.0026245117187500, -0.0003662109375000, 0.0020751953125000, 0.0000305175781250, +0.0023803710937500, -0.0001831054687500, 0.0016174316406250, 0.0002746582031250, +0.0014038085937500, 0.0003967285156250, 0.0015869140625000, 0.0002136230468750, +0.0013427734375000, 0.0003356933593750, 0.0011901855468750, 0.0005798339843750, +0.0020446777343750, 0.0005187988281250, 0.0016479492187500, 0.0005187988281250, +0.0020446777343750, 0.0008544921875000, 0.0028686523437500, 0.0010681152343750, +0.0021972656250000, 0.0009765625000000, 0.0034790039062500, 0.0010681152343750, +0.0033874511718750, 0.0012817382812500, 0.0032348632812500, 0.0008850097656250, +0.0039672851562500, 0.0004882812500000, 0.0037536621093750, 0.0009155273437500, +0.0035400390625000, 0.0001220703125000, 0.0038146972656250, 0.0001525878906250, +0.0034484863281250, 0.0003051757812500, 0.0030517578125000, 0.0000305175781250, +0.0035400390625000, 0.0002746582031250, 0.0025329589843750, 0.0002136230468750, +0.0027160644531250, 0.0002441406250000, 0.0026245117187500, 0.0002441406250000, +0.0018310546875000, 0.0002136230468750, 0.0022583007812500, 0.0002441406250000, +0.0016784667968750, 0.0002441406250000, 0.0014953613281250, 0.0002136230468750, +0.0015258789062500, 0.0002441406250000, 0.0011901855468750, 0.0002746582031250, +0.0009460449218750, 0.0003356933593750, 0.0011291503906250, 0.0002136230468750, +0.0007019042968750, 0.0003051757812500, 0.0007629394531250, 0.0002746582031250, +0.0009460449218750, 0.0001831054687500, 0.0003356933593750, 0.0003356933593750, +0.0009765625000000, 0.0003356933593750, 0.0006103515625000, 0.0002746582031250, +0.0007629394531250, 0.0003051757812500, 0.0010681152343750, 0.0003662109375000, +0.0000610351562500, 0.0002746582031250, 0.0011901855468750, 0.0002441406250000, +0.0005187988281250, 0.0002441406250000, 0.0006103515625000, 0.0001831054687500, +0.0014038085937500, 0.0000915527343750, 0.0004882812500000, 0.0000915527343750, +0.0015869140625000, 0.0001220703125000, 0.0010681152343750, 0.0000000000000000, +0.0011291503906250, -0.0001220703125000, 0.0017395019531250, -0.0000915527343750, +0.0008239746093750, -0.0002746582031250, 0.0017395019531250, -0.0002441406250000, +0.0012817382812500, -0.0003967285156250, 0.0012512207031250, -0.0005187988281250, +0.0018310546875000, -0.0004882812500000, 0.0011291503906250, -0.0006103515625000, +0.0018005371093750, -0.0007934570312500, 0.0015869140625000, -0.0007324218750000, +0.0015563964843750, -0.0009765625000000, 0.0019836425781250, -0.0012207031250000, +0.0014648437500000, -0.0011901855468750, 0.0019226074218750, -0.0015869140625000, +0.0019226074218750, -0.0017395019531250, 0.0019226074218750, -0.0017700195312500, +0.0022888183593750, -0.0020446777343750, 0.0022277832031250, -0.0021972656250000, +0.0025634765625000, -0.0020446777343750, 0.0027465820312500, -0.0022583007812500, +0.0029602050781250, -0.0022583007812500, 0.0035095214843750, -0.0021362304687500, +0.0038757324218750, -0.0024108886718750, 0.0040283203125000, -0.0018920898437500, +0.0048217773437500, -0.0022277832031250, 0.0050048828125000, -0.0020141601562500, +0.0049133300781250, -0.0014648437500000, 0.0056457519531250, -0.0019836425781250, +0.0051574707031250, -0.0012512207031250, 0.0050659179687500, -0.0012817382812500, +0.0050964355468750, -0.0013122558593750, 0.0047912597656250, -0.0009765625000000, +0.0045776367187500, -0.0011596679687500, 0.0045166015625000, -0.0008544921875000, +0.0042419433593750, -0.0011596679687500, 0.0041198730468750, -0.0010375976562500, +0.0039978027343750, -0.0007934570312500, 0.0035705566406250, -0.0013427734375000, +0.0039062500000000, -0.0005187988281250, 0.0032653808593750, -0.0011901855468750, +0.0032958984375000, -0.0010986328125000, 0.0036010742187500, -0.0005798339843750, +0.0026550292968750, -0.0018005371093750, 0.0035095214843750, -0.0007629394531250, +0.0030212402343750, -0.0017089843750000, 0.0028076171875000, -0.0018310546875000, +0.0033264160156250, -0.0012512207031250, 0.0025939941406250, -0.0025939941406250, +0.0025939941406250, -0.0013427734375000, 0.0028076171875000, -0.0019836425781250, +0.0019836425781250, -0.0021057128906250, 0.0015563964843750, -0.0011901855468750, +0.0021057128906250, -0.0019836425781250, 0.0006713867187500, -0.0014343261718750, +0.0012207031250000, -0.0015258789062500, 0.0014343261718750, -0.0014953613281250, +0.0010375976562500, -0.0012817382812500, 0.0019836425781250, -0.0016784667968750, +0.0011901855468750, -0.0010375976562500, 0.0024719238281250, -0.0014343261718750, +0.0021972656250000, -0.0012817382812500, 0.0014953613281250, -0.0007629394531250, +0.0034179687500000, -0.0013427734375000, 0.0011596679687500, -0.0007019042968750, +0.0025329589843750, -0.0007019042968750, 0.0027770996093750, -0.0008239746093750, +0.0008544921875000, -0.0003356933593750, 0.0019226074218750, -0.0002136230468750, +0.0012817382812500, -0.0010375976562500, 0.0010681152343750, -0.0004577636718750, +0.0010070800781250, -0.0007324218750000, 0.0008544921875000, -0.0015869140625000, +0.0008544921875000, -0.0008239746093750, -0.0002136230468750, -0.0014038085937500, +0.0001831054687500, -0.0020751953125000, -0.0003356933593750, -0.0016784667968750, +-0.0014953613281250, -0.0015869140625000, -0.0006713867187500, -0.0025024414062500, +-0.0014648437500000, -0.0015563964843750, -0.0015563964843750, -0.0022277832031250, +-0.0011596679687500, -0.0024719238281250, -0.0015869140625000, -0.0014343261718750, +-0.0022888183593750, -0.0017089843750000, -0.0021057128906250, -0.0025939941406250, +-0.0021057128906250, -0.0022583007812500, -0.0022888183593750, -0.0018310546875000, +-0.0023498535156250, -0.0020751953125000, -0.0023803710937500, -0.0016479492187500, +-0.0020446777343750, -0.0004882812500000, -0.0024108886718750, -0.0008850097656250, +-0.0021667480468750, -0.0003662109375000, -0.0016784667968750, 0.0004882812500000, +-0.0022888183593750, -0.0004272460937500, -0.0019836425781250, 0.0007629394531250, +-0.0020141601562500, 0.0005187988281250, -0.0021667480468750, 0.0007324218750000, +-0.0021667480468750, 0.0017395019531250, -0.0021667480468750, 0.0013732910156250, +-0.0021057128906250, 0.0022277832031250, -0.0018310546875000, 0.0024719238281250, +-0.0018615722656250, 0.0024108886718750, -0.0016784667968750, 0.0026550292968750, +-0.0010986328125000, 0.0025024414062500, -0.0017700195312500, 0.0024414062500000, +-0.0014648437500000, 0.0022583007812500, -0.0014343261718750, 0.0022583007812500, +-0.0019836425781250, 0.0022888183593750, -0.0016784667968750, 0.0019531250000000, +-0.0011901855468750, 0.0021362304687500, -0.0014648437500000, 0.0023498535156250, +-0.0011901855468750, 0.0018615722656250, -0.0005187988281250, 0.0019531250000000, +-0.0007629394531250, 0.0027465820312500, -0.0008239746093750, 0.0012512207031250, +-0.0004882812500000, 0.0023498535156250, -0.0007324218750000, 0.0023498535156250, +-0.0010375976562500, 0.0013122558593750, -0.0005493164062500, 0.0027160644531250, +-0.0008544921875000, 0.0019531250000000, -0.0009155273437500, 0.0025329589843750, +-0.0005798339843750, 0.0028076171875000, -0.0005187988281250, 0.0025329589843750, +-0.0005798339843750, 0.0034790039062500, 0.0000915527343750, 0.0026245117187500, +0.0000610351562500, 0.0033264160156250, 0.0002136230468750, 0.0030517578125000, +0.0005798339843750, 0.0022583007812500, 0.0003967285156250, 0.0034484863281250, +0.0005493164062500, 0.0017700195312500, 0.0007019042968750, 0.0024108886718750, +0.0005187988281250, 0.0023498535156250, 0.0005187988281250, 0.0011596679687500, +0.0007629394531250, 0.0022888183593750, 0.0003051757812500, 0.0015258789062500, +0.0007019042968750, 0.0017700195312500, 0.0005798339843750, 0.0022888183593750, +0.0002441406250000, 0.0021667480468750, 0.0009460449218750, 0.0024414062500000, +0.0000915527343750, 0.0027770996093750, 0.0004272460937500, 0.0028076171875000, +0.0002136230468750, 0.0027770996093750, -0.0005187988281250, 0.0028686523437500, +0.0000915527343750, 0.0028076171875000, -0.0009460449218750, 0.0027160644531250, +-0.0007629394531250, 0.0026245117187500, -0.0008544921875000, 0.0025634765625000, +-0.0016784667968750, 0.0024414062500000, -0.0013122558593750, 0.0024414062500000, +-0.0016479492187500}, +{0.0018920898437500, -0.0003662109375000, 0.0010375976562500, -0.0011596679687500, +0.0008544921875000, -0.0012207031250000, 0.0009765625000000, -0.0009765625000000, +0.0002746582031250, -0.0013732910156250, 0.0000000000000000, -0.0018005371093750, +0.0003662109375000, -0.0011596679687500, -0.0004272460937500, -0.0017395019531250, +-0.0005798339843750, -0.0017700195312500, -0.0001525878906250, -0.0014648437500000, +-0.0010070800781250, -0.0023193359375000, -0.0009765625000000, -0.0014343261718750, +-0.0010681152343750, -0.0023193359375000, -0.0017089843750000, -0.0024108886718750, +-0.0014648437500000, -0.0011596679687500, -0.0006713867187500, -0.0014648437500000, +-0.0018615722656250, -0.0010070800781250, -0.0013732910156250, -0.0012207031250000, +-0.0014038085937500, -0.0006713867187500, -0.0021667480468750, 0.0000305175781250, +-0.0014343261718750, -0.0006103515625000, -0.0021667480468750, 0.0010375976562500, +-0.0018920898437500, 0.0002441406250000, -0.0017395019531250, 0.0004882812500000, +-0.0022277832031250, 0.0017700195312500, -0.0019531250000000, 0.0007324218750000, +-0.0019226074218750, 0.0019836425781250, -0.0022888183593750, 0.0021667480468750, +-0.0022888183593750, 0.0019836425781250, -0.0020751953125000, 0.0025024414062500, +-0.0023193359375000, 0.0026245117187500, -0.0026245117187500, 0.0024414062500000, +-0.0024108886718750, 0.0026245117187500, -0.0026245117187500, 0.0025634765625000, +-0.0028991699218750, 0.0023803710937500, -0.0024108886718750, 0.0026245117187500, +-0.0026855468750000, 0.0025329589843750, -0.0024719238281250, 0.0026245117187500, +-0.0021972656250000, 0.0022277832031250, -0.0023803710937500, 0.0020751953125000, +-0.0023498535156250, 0.0024719238281250, -0.0020141601562500, 0.0011291503906250, +-0.0025634765625000, 0.0018920898437500, -0.0019531250000000, 0.0017700195312500, +-0.0013122558593750, 0.0008239746093750, -0.0022583007812500, 0.0021057128906250, +-0.0006103515625000, 0.0014953613281250, -0.0007324218750000, 0.0018310546875000, +-0.0008850097656250, 0.0021057128906250, 0.0000305175781250, 0.0020446777343750, +-0.0002136230468750, 0.0028076171875000, -0.0004882812500000, 0.0018615722656250, +-0.0001220703125000, 0.0026550292968750, -0.0002441406250000, 0.0022583007812500, +-0.0007629394531250, 0.0013122558593750, -0.0003967285156250, 0.0026550292968750, +-0.0004577636718750, 0.0007934570312500, -0.0007019042968750, 0.0016784667968750, +-0.0003356933593750, 0.0018005371093750, 0.0000000000000000, 0.0007934570312500, +-0.0003662109375000, 0.0022277832031250, 0.0004272460937500, 0.0015258789062500, +0.0003662109375000, 0.0019836425781250, 0.0002441406250000, 0.0024108886718750, +0.0007019042968750, 0.0021972656250000, 0.0006103515625000, 0.0028076171875000, +0.0003662109375000, 0.0025634765625000, 0.0006408691406250, 0.0028991699218750, +0.0004577636718750, 0.0029602050781250, 0.0003051757812500, 0.0027160644531250, +0.0007629394531250, 0.0029296875000000, 0.0001220703125000, 0.0024719238281250, +0.0005798339843750, 0.0024414062500000, 0.0003662109375000, 0.0024414062500000, +-0.0001525878906250, 0.0021057128906250, 0.0006103515625000, 0.0021362304687500, +-0.0005798339843750, 0.0022277832031250, -0.0001525878906250, 0.0020751953125000, +-0.0003662109375000, 0.0023193359375000, -0.0012207031250000, 0.0025329589843750, +-0.0004882812500000, 0.0022583007812500, -0.0012817382812500, 0.0029602050781250, +-0.0012207031250000, 0.0025024414062500, -0.0009460449218750, 0.0027770996093750, +-0.0013427734375000, 0.0034484863281250, -0.0012817382812500, 0.0025024414062500, +-0.0010375976562500, 0.0032348632812500, -0.0013427734375000, 0.0029602050781250, +-0.0011596679687500, 0.0025634765625000, -0.0009460449218750, 0.0027160644531250, +-0.0014953613281250, 0.0024414062500000, -0.0008544921875000, 0.0020446777343750, +-0.0012207031250000, 0.0019836425781250, -0.0010986328125000, 0.0017089843750000, +-0.0006103515625000, 0.0013122558593750, -0.0012207031250000, 0.0014038085937500, +-0.0003051757812500, 0.0010375976562500, -0.0005187988281250, 0.0009765625000000, +-0.0004577636718750, 0.0009155273437500, 0.0000305175781250, 0.0007934570312500, +-0.0002746582031250, 0.0009155273437500, 0.0001525878906250, 0.0007324218750000, +0.0000915527343750, 0.0008850097656250, 0.0000610351562500, 0.0009460449218750, +0.0003051757812500, 0.0009765625000000, 0.0001220703125000, 0.0012207031250000, +0.0001831054687500, 0.0012512207031250, 0.0001220703125000, 0.0013732910156250, +0.0001525878906250, 0.0015563964843750, 0.0002746582031250, 0.0016479492187500, +0.0000610351562500, 0.0017089843750000, 0.0004882812500000, 0.0017700195312500, +0.0003356933593750, 0.0020141601562500, 0.0004272460937500, 0.0020446777343750, +0.0006713867187500, 0.0020446777343750, 0.0003662109375000, 0.0024108886718750, +0.0006408691406250, 0.0021972656250000, 0.0003967285156250, 0.0025634765625000, +0.0002441406250000, 0.0026855468750000, 0.0003051757812500, 0.0025939941406250, +-0.0001220703125000, 0.0030517578125000, -0.0001525878906250, 0.0030212402343750, +-0.0002136230468750, 0.0032653808593750, -0.0004577636718750, 0.0033874511718750, +-0.0005493164062500, 0.0034179687500000, -0.0004272460937500, 0.0039062500000000, +-0.0005493164062500, 0.0034484863281250, -0.0004577636718750, 0.0039672851562500, +-0.0003356933593750, 0.0038757324218750, -0.0002746582031250, 0.0035400390625000, +-0.0001525878906250, 0.0042114257812500, -0.0001220703125000, 0.0032043457031250, +0.0000915527343750, 0.0036315917968750, 0.0000305175781250, 0.0035095214843750, +-0.0000915527343750, 0.0027465820312500, 0.0001220703125000, 0.0034179687500000, +-0.0000305175781250, 0.0027465820312500, -0.0000305175781250, 0.0028991699218750, +-0.0000915527343750, 0.0031738281250000, -0.0001220703125000, 0.0029602050781250, +-0.0001525878906250, 0.0032653808593750, -0.0006713867187500, 0.0036315917968750, +-0.0003662109375000, 0.0037231445312500, -0.0009765625000000, 0.0041503906250000, +-0.0017395019531250, 0.0046691894531250, -0.0012207031250000, 0.0046386718750000, +-0.0025024414062500, 0.0047302246093750, -0.0023498535156250, 0.0052795410156250, +-0.0025024414062500, 0.0049743652343750, -0.0030822753906250, 0.0046386718750000, +-0.0023803710937500, 0.0051879882812500, -0.0032653808593750, 0.0038146972656250, +-0.0024719238281250, 0.0043945312500000, -0.0024414062500000, 0.0038757324218750, +-0.0029907226562500, 0.0027160644531250, -0.0018615722656250, 0.0037536621093750, +-0.0023803710937500, 0.0022277832031250, -0.0022277832031250, 0.0024719238281250, +-0.0018615722656250, 0.0027160644531250, -0.0020141601562500, 0.0021057128906250, +-0.0020446777343750, 0.0027160644531250, -0.0025634765625000, 0.0027770996093750, +-0.0019531250000000, 0.0030212402343750, -0.0026550292968750, 0.0031433105468750, +-0.0034484863281250, 0.0032653808593750, -0.0021362304687500, 0.0035705566406250, +-0.0034179687500000, 0.0031127929687500, -0.0030517578125000, 0.0033264160156250, +-0.0025634765625000, 0.0029602050781250, -0.0028686523437500, 0.0024108886718750, +-0.0024414062500000, 0.0027160644531250, -0.0024108886718750, 0.0016479492187500, +-0.0019531250000000, 0.0016784667968750, -0.0018615722656250, 0.0017089843750000, +-0.0021667480468750, 0.0011291503906250, -0.0018005371093750, 0.0012207031250000, +-0.0018310546875000, 0.0014038085937500, -0.0026855468750000, 0.0007629394531250, +-0.0023803710937500, 0.0010681152343750, -0.0021667480468750, 0.0015258789062500, +-0.0033874511718750, 0.0006713867187500, -0.0025024414062500, 0.0014953613281250, +-0.0029296875000000, 0.0010986328125000, -0.0031433105468750, 0.0010986328125000, +-0.0025329589843750, 0.0014343261718750, -0.0029296875000000, 0.0008544921875000, +-0.0025329589843750, 0.0022277832031250, -0.0024108886718750, 0.0014648437500000, +-0.0021972656250000, 0.0021057128906250, -0.0018920898437500, 0.0034484863281250, +-0.0017700195312500, 0.0020446777343750, -0.0010986328125000, 0.0032653808593750, +-0.0011596679687500, 0.0032348632812500, -0.0008850097656250, 0.0020751953125000, +-0.0000305175781250, 0.0014953613281250, 0.0012512207031250, 0.0019226074218750, +0.0044555664062500, 0.0037231445312500, 0.0030822753906250, 0.0030517578125000, +0.0038452148437500, 0.0022277832031250, 0.0056457519531250, 0.0019226074218750, +0.0046997070312500, 0.0014343261718750, 0.0047302246093750, 0.0006103515625000, +0.0050659179687500, 0.0000000000000000, 0.0041503906250000, -0.0003967285156250, +0.0029907226562500, -0.0007324218750000, 0.0031738281250000, -0.0011901855468750, +0.0023803710937500, -0.0019226074218750, 0.0015258789062500, -0.0017700195312500, +0.0021057128906250, -0.0025024414062500, 0.0024719238281250, -0.0036010742187500, +0.0014953613281250, -0.0030517578125000, 0.0029602050781250, -0.0035400390625000, +0.0028076171875000, -0.0040588378906250, 0.0022583007812500, -0.0032958984375000, +0.0028076171875000, -0.0026855468750000, 0.0026245117187500, -0.0032348632812500, +0.0015869140625000, -0.0018615722656250, 0.0016174316406250, -0.0014953613281250, +0.0015563964843750, -0.0019531250000000, 0.0009155273437500, -0.0016784667968750, +0.0009765625000000, -0.0011901855468750, 0.0017395019531250, -0.0025939941406250, +0.0015563964843750, -0.0023498535156250, 0.0018615722656250, -0.0024108886718750, +0.0027465820312500, -0.0032043457031250, 0.0026245117187500, -0.0027770996093750, +0.0023803710937500, -0.0032653808593750, 0.0032653808593750, -0.0028991699218750, +0.0024108886718750, -0.0030822753906250, 0.0014648437500000, -0.0035095214843750, +0.0028076171875000, -0.0028686523437500, 0.0008544921875000, -0.0037841796875000, +0.0010070800781250, -0.0037231445312500, 0.0014953613281250, -0.0033264160156250, +0.0007324218750000, -0.0035095214843750, 0.0011291503906250, -0.0032653808593750, +0.0012817382812500, -0.0025939941406250, 0.0012817382812500, -0.0025024414062500, +0.0016174316406250, -0.0022888183593750, 0.0020141601562500, -0.0019226074218750, +0.0021972656250000, -0.0019836425781250, 0.0020751953125000, -0.0017700195312500, +0.0029907226562500, -0.0019226074218750, 0.0024108886718750, -0.0016174316406250, +0.0018005371093750, -0.0013122558593750, 0.0032043457031250, -0.0017395019531250, +0.0008544921875000, -0.0007629394531250, 0.0017089843750000, -0.0009460449218750, +0.0015563964843750, -0.0007629394531250, 0.0000610351562500, -0.0001525878906250, +0.0015869140625000, -0.0005798339843750, 0.0000000000000000, 0.0001525878906250, +0.0006408691406250, 0.0000305175781250, 0.0007324218750000, 0.0000915527343750, +-0.0000915527343750, 0.0005798339843750, 0.0011291503906250, 0.0004577636718750, +0.0004882812500000, 0.0006713867187500, 0.0009155273437500, 0.0006713867187500, +0.0014343261718750, 0.0009460449218750, 0.0013732910156250, 0.0011291503906250, +0.0018615722656250, 0.0008850097656250, 0.0020141601562500, 0.0015563964843750, +0.0023193359375000, 0.0013122558593750, 0.0023803710937500, 0.0011291503906250, +0.0023803710937500, 0.0015258789062500, 0.0025939941406250, 0.0011901855468750, +0.0022583007812500, 0.0010375976562500, 0.0023498535156250, 0.0010681152343750, +0.0021362304687500, 0.0008850097656250, 0.0017089843750000, 0.0007324218750000, +0.0019836425781250, 0.0007629394531250, 0.0012207031250000, 0.0007324218750000, +0.0012207031250000, 0.0007629394531250, 0.0010375976562500, 0.0007324218750000, +0.0005493164062500, 0.0007324218750000, 0.0006408691406250, 0.0007629394531250, +0.0001220703125000, 0.0006408691406250, 0.0000915527343750, 0.0006408691406250, +-0.0000305175781250}, +{0.0065002441406250, 0.0025024414062500, 0.0054321289062500, 0.0029907226562500, +0.0046997070312500, 0.0036926269531250, 0.0051269531250000, 0.0026245117187500, +0.0039062500000000, 0.0034484863281250, 0.0032958984375000, 0.0032653808593750, +0.0037231445312500, 0.0025634765625000, 0.0036010742187500, 0.0023193359375000, +0.0028991699218750, 0.0018310546875000, 0.0036926269531250, 0.0014343261718750, +0.0035705566406250, 0.0007324218750000, 0.0028381347656250, 0.0004272460937500, +0.0026855468750000, 0.0003662109375000, 0.0025634765625000, -0.0002746582031250, +0.0015869140625000, -0.0006408691406250, 0.0009765625000000, -0.0007019042968750, +0.0013122558593750, -0.0012207031250000, 0.0010681152343750, -0.0017700195312500, +0.0002746582031250, -0.0016784667968750, 0.0024414062500000, -0.0021057128906250, +0.0017395019531250, -0.0023803710937500, 0.0018615722656250, -0.0020446777343750, +0.0035705566406250, -0.0018310546875000, 0.0026855468750000, -0.0019226074218750, +0.0026550292968750, -0.0012817382812500, 0.0030517578125000, -0.0010375976562500, +0.0023498535156250, -0.0013122558593750, 0.0015869140625000, -0.0012817382812500, +0.0020446777343750, -0.0011901855468750, 0.0014038085937500, -0.0019531250000000, +0.0010375976562500, -0.0019531250000000, 0.0016479492187500, -0.0021362304687500, +0.0018615722656250, -0.0025329589843750, 0.0014953613281250, -0.0023498535156250, +0.0027465820312500, -0.0028686523437500, 0.0029907226562500, -0.0026245117187500, +0.0026855468750000, -0.0029602050781250, 0.0031433105468750, -0.0035400390625000, +0.0034179687500000, -0.0029907226562500, 0.0023193359375000, -0.0037841796875000, +0.0028991699218750, -0.0037231445312500, 0.0023803710937500, -0.0032348632812500, +0.0012817382812500, -0.0032958984375000, 0.0021972656250000, -0.0032958984375000, +0.0007934570312500, -0.0024414062500000, 0.0007324218750000, -0.0025939941406250, +0.0010375976562500, -0.0022888183593750, 0.0005798339843750, -0.0016784667968750, +0.0007629394531250, -0.0021362304687500, 0.0010375976562500, -0.0012207031250000, +0.0012512207031250, -0.0015258789062500, 0.0013427734375000, -0.0013122558593750, +0.0015869140625000, -0.0005798339843750, 0.0021362304687500, -0.0011291503906250, +0.0017089843750000, -0.0003051757812500, 0.0024414062500000, -0.0005187988281250, +0.0024108886718750, -0.0003967285156250, 0.0021057128906250, 0.0001525878906250, +0.0031127929687500, -0.0002441406250000, 0.0016784667968750, 0.0003662109375000, +0.0025939941406250, 0.0003356933593750, 0.0023803710937500, 0.0004272460937500, +0.0011901855468750, 0.0007934570312500, 0.0025024414062500, 0.0005798339843750, +0.0010681152343750, 0.0010681152343750, 0.0013427734375000, 0.0009460449218750, +0.0014648437500000, 0.0010681152343750, 0.0007324218750000, 0.0014343261718750, +0.0013122558593750, 0.0009155273437500, 0.0007934570312500, 0.0013732910156250, +0.0008239746093750, 0.0011596679687500, 0.0009765625000000, 0.0009460449218750, +0.0008239746093750, 0.0010986328125000, 0.0010375976562500, 0.0008850097656250, +0.0012512207031250, 0.0007629394531250, 0.0012207031250000, 0.0006408691406250, +0.0013732910156250, 0.0007019042968750, 0.0016784667968750, 0.0007324218750000, +0.0015258789062500, 0.0005493164062500, 0.0017700195312500, 0.0007934570312500, +0.0018920898437500, 0.0007934570312500, 0.0018920898437500, 0.0007324218750000, +0.0020446777343750, 0.0007629394531250, 0.0021362304687500, 0.0006713867187500, +0.0021362304687500, 0.0007019042968750, 0.0022888183593750, 0.0005798339843750, +0.0022888183593750, 0.0006103515625000, 0.0023193359375000, 0.0007019042968750, +0.0026245117187500, 0.0004272460937500, 0.0024719238281250, 0.0007324218750000, +0.0024414062500000, 0.0005187988281250, 0.0025939941406250, 0.0004272460937500, +0.0025329589843750, 0.0005493164062500, 0.0024108886718750, 0.0003051757812500, +0.0028076171875000, 0.0003051757812500, 0.0023803710937500, 0.0002136230468750, +0.0025024414062500, -0.0000305175781250, 0.0027770996093750, -0.0001220703125000, +0.0021972656250000, -0.0002441406250000, 0.0029296875000000, -0.0003967285156250, +0.0024414062500000, -0.0004272460937500, 0.0025634765625000, -0.0007019042968750, +0.0029907226562500, -0.0009155273437500, 0.0022277832031250, -0.0007934570312500, +0.0030517578125000, -0.0011901855468750, 0.0024108886718750, -0.0011596679687500, +0.0024719238281250, -0.0011901855468750, 0.0030212402343750, -0.0013427734375000, +0.0019226074218750, -0.0012512207031250, 0.0030212402343750, -0.0011291503906250, +0.0025024414062500, -0.0011596679687500, 0.0022888183593750, -0.0010375976562500, +0.0029602050781250, -0.0008850097656250, 0.0022583007812500, -0.0009765625000000, +0.0025024414062500, -0.0006103515625000, 0.0025024414062500, -0.0005187988281250, +0.0021362304687500, -0.0003967285156250, 0.0020446777343750, -0.0001525878906250, +0.0020141601562500, -0.0000610351562500, 0.0018005371093750, 0.0000915527343750, +0.0018920898437500, 0.0001220703125000, 0.0018310546875000, 0.0003356933593750, +0.0018310546875000, 0.0004577636718750, 0.0022583007812500, 0.0002136230468750, +0.0019836425781250, 0.0007019042968750, 0.0026550292968750, 0.0003051757812500, +0.0026245117187500, 0.0002746582031250, 0.0025634765625000, 0.0004577636718750, +0.0035705566406250, -0.0003051757812500, 0.0025634765625000, 0.0000305175781250, +0.0029907226562500, -0.0003967285156250, 0.0029907226562500, -0.0007324218750000, +0.0022277832031250, -0.0004577636718750, 0.0028686523437500, -0.0006408691406250, +0.0021362304687500, -0.0009460449218750, 0.0021362304687500, -0.0003662109375000, +0.0023193359375000, -0.0006408691406250, 0.0018920898437500, -0.0008850097656250, +0.0018920898437500, 0.0000915527343750, 0.0024108886718750, -0.0011291503906250, +0.0018920898437500, -0.0001831054687500, 0.0024719238281250, -0.0002746582031250, +0.0031433105468750, -0.0011901855468750, 0.0020751953125000, 0.0002441406250000, +0.0040588378906250, -0.0012512207031250, 0.0032043457031250, -0.0006713867187500, +0.0035095214843750, -0.0006408691406250, 0.0049743652343750, -0.0016174316406250, +0.0033874511718750, -0.0007934570312500, 0.0050964355468750, -0.0012817382812500, +0.0046081542968750, -0.0013427734375000, 0.0036621093750000, -0.0009460449218750, +0.0039367675781250, -0.0009155273437500, 0.0035400390625000, -0.0007934570312500, +0.0037841796875000, -0.0006103515625000, 0.0032653808593750, -0.0004272460937500, +0.0035705566406250, -0.0005493164062500, 0.0042114257812500, -0.0006713867187500, +0.0034484863281250, -0.0005187988281250, 0.0041503906250000, -0.0007324218750000, +0.0041503906250000, -0.0010375976562500, 0.0035400390625000, -0.0010375976562500, +0.0036926269531250, -0.0010986328125000, 0.0039367675781250, -0.0014038085937500, +0.0027465820312500, -0.0011901855468750, 0.0024414062500000, -0.0017089843750000, +0.0024719238281250, -0.0017700195312500, 0.0020751953125000, -0.0016479492187500, +0.0021362304687500, -0.0021972656250000, 0.0022277832031250, -0.0015258789062500, +0.0021362304687500, -0.0018310546875000, 0.0018615722656250, -0.0018920898437500, +0.0016784667968750, -0.0012817382812500, 0.0014648437500000, -0.0015563964843750, +0.0006103515625000, -0.0012207031250000, 0.0003967285156250, -0.0010986328125000, +-0.0000915527343750, -0.0006408691406250, -0.0006103515625000, -0.0003051757812500, +0.0000915527343750, -0.0002136230468750, -0.0003051757812500, 0.0019226074218750, +-0.0002441406250000, 0.0010070800781250, -0.0001525878906250, 0.0010070800781250, +-0.0001831054687500, 0.0024108886718750, -0.0000305175781250, 0.0014648437500000, +-0.0007934570312500, 0.0019226074218750, -0.0002746582031250, 0.0022277832031250, +-0.0007324218750000, 0.0020751953125000, -0.0014953613281250, 0.0021972656250000, +-0.0007324218750000, 0.0025024414062500, -0.0019531250000000, 0.0027465820312500, +-0.0015258789062500, 0.0027160644531250, -0.0014648437500000, 0.0026550292968750, +-0.0022888183593750, 0.0028686523437500, -0.0016784667968750, 0.0028991699218750, +-0.0019836425781250, 0.0022583007812500, -0.0024108886718750, 0.0025939941406250, +-0.0017700195312500, 0.0021972656250000, -0.0016174316406250, 0.0016479492187500, +-0.0024108886718750, 0.0024108886718750, -0.0006713867187500, 0.0013122558593750, +-0.0012207031250000, 0.0020446777343750, -0.0012817382812500, 0.0021057128906250, +0.0000000000000000, 0.0014648437500000, -0.0005798339843750, 0.0025939941406250, +-0.0007324218750000, 0.0012512207031250, -0.0000915527343750, 0.0018005371093750, +-0.0005798339843750, 0.0016784667968750, -0.0012207031250000, 0.0005187988281250, +-0.0007019042968750, 0.0012817382812500, -0.0016479492187500, 0.0007934570312500, +-0.0018005371093750, 0.0004577636718750, -0.0015563964843750, 0.0007934570312500, +-0.0018005371093750, 0.0009155273437500, -0.0019836425781250, 0.0007629394531250, +-0.0010986328125000, 0.0010986328125000, -0.0016174316406250, 0.0013732910156250, +-0.0012207031250000, 0.0013732910156250, -0.0003967285156250, 0.0015563964843750, +-0.0013122558593750, 0.0018310546875000, -0.0000915527343750, 0.0014648437500000, +-0.0002136230468750, 0.0018310546875000, -0.0003662109375000, 0.0019531250000000, +0.0003051757812500, 0.0017089843750000, 0.0001220703125000, 0.0021972656250000, +-0.0000915527343750, 0.0024108886718750, -0.0000305175781250, 0.0023498535156250, +-0.0001220703125000, 0.0027770996093750, -0.0004882812500000, 0.0031433105468750, +-0.0006103515625000, 0.0028991699218750, -0.0003051757812500, 0.0030822753906250, +-0.0009155273437500, 0.0032043457031250, -0.0008239746093750, 0.0027770996093750, +-0.0004272460937500, 0.0025939941406250, -0.0012817382812500, 0.0028686523437500, +-0.0005493164062500, 0.0019531250000000, -0.0009765625000000, 0.0021667480468750, +-0.0010070800781250, 0.0022583007812500, -0.0005798339843750, 0.0017700195312500, +-0.0011291503906250, 0.0020446777343750, -0.0003662109375000, 0.0019836425781250, +-0.0005798339843750, 0.0018310546875000, -0.0004577636718750, 0.0021667480468750, +0.0001525878906250, 0.0023498535156250, -0.0003051757812500, 0.0020141601562500, +-0.0000915527343750, 0.0026550292968750, 0.0000915527343750, 0.0023498535156250, +-0.0003356933593750, 0.0022888183593750, -0.0005493164062500, 0.0025329589843750, +-0.0002746582031250, 0.0021667480468750, -0.0008544921875000, 0.0024719238281250, +-0.0008850097656250, 0.0022888183593750, -0.0007629394531250, 0.0021972656250000, +-0.0009460449218750, 0.0024108886718750, -0.0008850097656250, 0.0022583007812500, +-0.0007019042968750, 0.0023498535156250, -0.0012512207031250, 0.0021972656250000, +-0.0009765625000000, 0.0021667480468750, -0.0005798339843750, 0.0022277832031250, +-0.0012817382812500, 0.0019836425781250, -0.0003051757812500, 0.0022888183593750, +-0.0007324218750000, 0.0019836425781250, -0.0006103515625000, 0.0018920898437500, +0.0000305175781250, 0.0021362304687500, -0.0007629394531250, 0.0017395019531250, +0.0001831054687500, 0.0020446777343750, -0.0002441406250000, 0.0017089843750000, +-0.0001525878906250, 0.0017089843750000, 0.0004882812500000, 0.0019226074218750, +-0.0002441406250000, 0.0014038085937500, 0.0006408691406250, 0.0018920898437500, +0.0003662109375000, 0.0015869140625000, 0.0003967285156250, 0.0015258789062500, +0.0008544921875000, 0.0018615722656250, 0.0003051757812500, 0.0014648437500000, +0.0006713867187500, 0.0017395019531250, 0.0005798339843750, 0.0015563964843750, +0.0003967285156250, 0.0016174316406250, 0.0006103515625000, 0.0018005371093750, +0.0004272460937500}, +{-0.0014343261718750, 0.0008239746093750, -0.0014953613281250, 0.0017700195312500, +-0.0012512207031250, 0.0007019042968750, -0.0017089843750000, 0.0010986328125000, +-0.0012817382812500, 0.0010681152343750, -0.0007934570312500, 0.0003356933593750, +-0.0014953613281250, 0.0010681152343750, -0.0001525878906250, 0.0006408691406250, +-0.0000610351562500, 0.0005798339843750, -0.0002441406250000, 0.0009765625000000, +0.0005493164062500, 0.0010986328125000, 0.0006103515625000, 0.0010681152343750, +-0.0000915527343750, 0.0011291503906250, 0.0002441406250000, 0.0014648437500000, +-0.0000915527343750, 0.0012817382812500, -0.0009460449218750, 0.0010375976562500, +-0.0005798339843750, 0.0015869140625000, -0.0011291503906250, 0.0012207031250000, +-0.0012207031250000, 0.0012512207031250, -0.0011596679687500, 0.0017089843750000, +-0.0013427734375000, 0.0016784667968750, -0.0013427734375000, 0.0016174316406250, +-0.0013122558593750, 0.0024414062500000, -0.0014038085937500, 0.0022888183593750, +-0.0011901855468750, 0.0025329589843750, -0.0010070800781250, 0.0032043457031250, +-0.0012207031250000, 0.0027465820312500, -0.0007629394531250, 0.0032653808593750, +-0.0006408691406250, 0.0032653808593750, -0.0007019042968750, 0.0027465820312500, +-0.0005187988281250, 0.0027465820312500, -0.0004577636718750, 0.0026855468750000, +-0.0006408691406250, 0.0019226074218750, -0.0007019042968750, 0.0020446777343750, +-0.0005187988281250, 0.0018615722656250, -0.0006713867187500, 0.0014038085937500, +-0.0010375976562500, 0.0017700195312500, -0.0003051757812500, 0.0018005371093750, +-0.0008544921875000, 0.0016479492187500, -0.0008239746093750, 0.0022583007812500, +-0.0002746582031250, 0.0025634765625000, -0.0010070800781250, 0.0021667480468750, +-0.0003967285156250, 0.0031127929687500, -0.0006713867187500, 0.0026855468750000, +-0.0006713867187500, 0.0027770996093750, -0.0002746582031250, 0.0033264160156250, +-0.0007934570312500, 0.0024414062500000, -0.0000915527343750, 0.0027770996093750, +-0.0003662109375000, 0.0025024414062500, -0.0004272460937500, 0.0020446777343750, +0.0001525878906250, 0.0019836425781250, -0.0002441406250000, 0.0017089843750000, +-0.0003356933593750, 0.0013122558593750, -0.0001220703125000, 0.0013122558593750, +-0.0004272460937500, 0.0011901855468750, -0.0007019042968750, 0.0008850097656250, +-0.0004882812500000, 0.0010681152343750, -0.0007934570312500, 0.0009460449218750, +-0.0009765625000000, 0.0009155273437500, -0.0008544921875000, 0.0009460449218750, +-0.0009765625000000, 0.0009460449218750, -0.0011901855468750, 0.0008850097656250, +-0.0007324218750000, 0.0008850097656250, -0.0011291503906250, 0.0006713867187500, +-0.0008544921875000, 0.0007629394531250, -0.0003662109375000, 0.0007019042968750, +-0.0009765625000000, 0.0003662109375000, 0.0000000000000000, 0.0006408691406250, +-0.0003662109375000, 0.0003356933593750, -0.0001831054687500, 0.0001525878906250, +0.0004882812500000, 0.0001831054687500, -0.0002136230468750, -0.0002441406250000, +0.0006408691406250, -0.0004272460937500, 0.0003662109375000, -0.0005798339843750, +0.0003662109375000, -0.0009765625000000, 0.0007934570312500, -0.0012512207031250, +0.0001831054687500, -0.0013427734375000, 0.0006408691406250, -0.0018310546875000, +0.0005187988281250, -0.0017700195312500, 0.0003356933593750, -0.0020751953125000, +0.0005187988281250, -0.0024108886718750, 0.0003356933593750, -0.0021057128906250, +0.0005493164062500, -0.0027465820312500, 0.0004577636718750, -0.0025634765625000, +0.0005493164062500, -0.0025634765625000, 0.0007019042968750, -0.0029602050781250, +0.0005187988281250, -0.0025939941406250, 0.0007629394531250, -0.0026855468750000, +0.0006103515625000, -0.0027770996093750, 0.0005493164062500, -0.0025329589843750, +0.0006103515625000, -0.0023498535156250, 0.0003051757812500, -0.0023803710937500, +0.0005798339843750, -0.0017700195312500, 0.0002136230468750, -0.0019226074218750, +0.0000000000000000, -0.0015563964843750, 0.0001831054687500, -0.0009155273437500, +-0.0003356933593750, -0.0010681152343750, -0.0004882812500000, -0.0005187988281250, +-0.0007324218750000, 0.0000305175781250, -0.0011596679687500, 0.0000000000000000, +-0.0013732910156250, 0.0002136230468750, -0.0015258789062500, 0.0008850097656250, +-0.0020751953125000, 0.0001525878906250, -0.0018615722656250, 0.0009460449218750, +-0.0021667480468750, 0.0006408691406250, -0.0025024414062500, -0.0001220703125000, +-0.0018615722656250, 0.0010681152343750, -0.0025024414062500, -0.0004882812500000, +-0.0019531250000000, 0.0001831054687500, -0.0017395019531250, 0.0001831054687500, +-0.0020141601562500, -0.0007629394531250, -0.0010986328125000, 0.0003967285156250, +-0.0013732910156250, -0.0003051757812500, -0.0011901855468750, 0.0000305175781250, +-0.0009155273437500, 0.0003967285156250, -0.0010070800781250, 0.0002136230468750, +-0.0010681152343750, 0.0007629394531250, -0.0011901855468750, 0.0009155273437500, +-0.0011291503906250, 0.0011596679687500, -0.0015563964843750, 0.0013427734375000, +-0.0018005371093750, 0.0015563964843750, -0.0012512207031250, 0.0018310546875000, +-0.0021057128906250, 0.0013732910156250, -0.0017395019531250, 0.0015258789062500, +-0.0013732910156250, 0.0014038085937500, -0.0016784667968750, 0.0007324218750000, +-0.0013122558593750, 0.0008239746093750, -0.0010375976562500, 0.0012207031250000, +-0.0011291503906250, 0.0005798339843750, -0.0007019042968750, 0.0013122558593750, +-0.0004272460937500, 0.0020751953125000, -0.0008239746093750, 0.0009155273437500, +0.0004577636718750, 0.0028991699218750, -0.0003967285156250, 0.0023498535156250, +0.0000610351562500, 0.0024108886718750, 0.0009460449218750, 0.0036010742187500, +-0.0008239746093750, 0.0026550292968750, 0.0006713867187500, 0.0033874511718750, +-0.0002136230468750, 0.0032958984375000, -0.0000305175781250, 0.0026855468750000, +0.0011901855468750, 0.0025939941406250, -0.0001831054687500, 0.0025939941406250, +0.0017089843750000, 0.0022277832031250, 0.0015563964843750, 0.0021667480468750, +0.0017700195312500, 0.0024108886718750, 0.0031433105468750, 0.0024108886718750, +0.0027770996093750, 0.0025024414062500, 0.0040588378906250, 0.0034484863281250, +0.0038146972656250, 0.0031738281250000, 0.0044860839843750, 0.0037536621093750, +0.0054321289062500, 0.0046691894531250, 0.0044250488281250, 0.0038452148437500, +0.0066528320312500, 0.0045166015625000, 0.0057983398437500, 0.0041503906250000, +0.0062255859375000, 0.0040283203125000, 0.0079345703125000, 0.0040283203125000, +0.0064086914062500, 0.0032653808593750, 0.0075073242187500, 0.0051879882812500, +0.0076904296875000, 0.0041503906250000, 0.0067443847656250, 0.0043640136718750, +0.0063781738281250, 0.0072326660156250, 0.0063171386718750, 0.0046081542968750, +0.0044860839843750, 0.0070495605468750, 0.0050659179687500, 0.0054321289062500, +0.0042724609375000, 0.0061340332031250, 0.0029296875000000, 0.0078430175781250, +0.0032043457031250, 0.0066833496093750, 0.0024108886718750, 0.0069580078125000, +0.0015563964843750, 0.0072631835937500, 0.0021057128906250, 0.0064697265625000, +0.0021972656250000, 0.0057067871093750, 0.0011291503906250, 0.0058898925781250, +0.0031127929687500, 0.0053100585937500, 0.0024108886718750, 0.0050048828125000, +0.0022277832031250, 0.0048828125000000, 0.0033569335937500, 0.0048522949218750, +0.0022888183593750, 0.0046997070312500, 0.0020751953125000, 0.0036621093750000, +0.0018005371093750, 0.0039672851562500, 0.0014343261718750, 0.0032653808593750, +0.0009460449218750, 0.0019226074218750, 0.0006103515625000, 0.0023498535156250, +0.0016479492187500, 0.0016784667968750, 0.0009155273437500, 0.0010681152343750, +0.0014038085937500, 0.0012817382812500, 0.0027465820312500, 0.0014953613281250, +0.0018005371093750, 0.0010070800781250, 0.0027465820312500, 0.0011596679687500, +0.0028381347656250, 0.0012817382812500, 0.0024719238281250, 0.0006408691406250, +0.0025939941406250, 0.0000915527343750, 0.0024414062500000, 0.0003356933593750, +0.0019226074218750, -0.0004882812500000, 0.0017089843750000, -0.0006103515625000, +0.0018005371093750, -0.0005798339843750, 0.0013122558593750, -0.0008544921875000, +0.0008239746093750, -0.0008850097656250, 0.0021667480468750, -0.0010986328125000, +0.0012817382812500, -0.0012817382812500, 0.0017395019531250, -0.0014343261718750, +0.0029296875000000, -0.0018005371093750, 0.0016479492187500, -0.0020446777343750, +0.0033569335937500, -0.0018005371093750, 0.0027465820312500, -0.0021362304687500, +0.0025329589843750, -0.0021057128906250, 0.0034790039062500, -0.0017395019531250, +0.0023498535156250, -0.0020141601562500, 0.0026855468750000, -0.0021057128906250, +0.0023803710937500, -0.0018310546875000, 0.0019836425781250, -0.0020751953125000, +0.0020141601562500, -0.0025024414062500, 0.0014953613281250, -0.0021057128906250, +0.0018310546875000, -0.0022583007812500, 0.0014343261718750, -0.0025634765625000, +0.0014648437500000, -0.0021972656250000, 0.0018920898437500, -0.0019226074218750, +0.0014343261718750, -0.0024108886718750, 0.0018615722656250, -0.0014343261718750, +0.0018920898437500, -0.0018920898437500, 0.0019226074218750, -0.0015563964843750, +0.0022583007812500, -0.0008544921875000, 0.0022277832031250, -0.0017395019531250, +0.0021667480468750, -0.0004272460937500, 0.0024108886718750, -0.0009155273437500, +0.0022277832031250, -0.0007629394531250, 0.0020446777343750, 0.0002746582031250, +0.0023803710937500, -0.0005187988281250, 0.0015869140625000, 0.0003051757812500, +0.0017395019531250, 0.0001831054687500, 0.0016784667968750, 0.0001525878906250, +0.0011291503906250, 0.0005187988281250, 0.0014648437500000, 0.0003356933593750, +0.0011901855468750, 0.0007324218750000, 0.0010375976562500, 0.0007019042968750, +0.0011291503906250, 0.0007934570312500, 0.0010681152343750, 0.0010681152343750, +0.0007629394531250, 0.0008850097656250, 0.0010070800781250, 0.0011596679687500, +0.0007324218750000, 0.0010375976562500, 0.0005187988281250, 0.0010070800781250, +0.0005798339843750, 0.0011901855468750, 0.0003662109375000, 0.0009155273437500, +0.0003967285156250, 0.0010681152343750, 0.0002746582031250, 0.0009460449218750, +0.0002136230468750, 0.0008850097656250, 0.0002746582031250, 0.0008239746093750, +0.0000610351562500, 0.0006103515625000, 0.0000610351562500, 0.0008239746093750, +0.0001220703125000, 0.0005187988281250, -0.0000305175781250, 0.0004882812500000, +-0.0000610351562500, 0.0006103515625000, -0.0000305175781250, 0.0002746582031250, +-0.0002136230468750, 0.0001831054687500, -0.0001220703125000, 0.0000915527343750, +-0.0001525878906250, -0.0000915527343750, -0.0001525878906250, -0.0002136230468750, +0.0001220703125000, -0.0003356933593750, -0.0001831054687500, -0.0004272460937500, +0.0001220703125000, -0.0005187988281250, 0.0002136230468750, -0.0005798339843750, +0.0000610351562500, -0.0006408691406250, 0.0005187988281250, -0.0007324218750000, +0.0001831054687500, -0.0006713867187500, 0.0004882812500000, -0.0007324218750000, +0.0005187988281250, -0.0006713867187500, 0.0003356933593750, -0.0005187988281250, +0.0009155273437500, -0.0006408691406250, 0.0003356933593750, -0.0003356933593750, +0.0009155273437500, -0.0003967285156250, 0.0009155273437500, -0.0002746582031250, +0.0005187988281250, 0.0000305175781250, 0.0012817382812500, -0.0001220703125000, +0.0007324218750000, 0.0001525878906250, 0.0009460449218750, 0.0002746582031250, +0.0010986328125000, 0.0002136230468750, 0.0007324218750000, 0.0002136230468750, +0.0008544921875000, 0.0003051757812500, 0.0009460449218750, 0.0000915527343750, +0.0007934570312500}, +{0.0025024414062500, 0.0000000000000000, 0.0024108886718750, -0.0001525878906250, +0.0023193359375000, -0.0002746582031250, 0.0022277832031250, -0.0006103515625000, +0.0017700195312500, -0.0008544921875000, 0.0022277832031250, -0.0010681152343750, +0.0018005371093750, -0.0014648437500000, 0.0018615722656250, -0.0015258789062500, +0.0021057128906250, -0.0016784667968750, 0.0015258789062500, -0.0021362304687500, +0.0024108886718750, -0.0016174316406250, 0.0020446777343750, -0.0020446777343750, +0.0020141601562500, -0.0020751953125000, 0.0026550292968750, -0.0014648437500000, +0.0022583007812500, -0.0018005371093750, 0.0021972656250000, -0.0016479492187500, +0.0022277832031250, -0.0015869140625000, 0.0021057128906250, -0.0015869140625000, +0.0018615722656250, -0.0017089843750000, 0.0017089843750000, -0.0019226074218750, +0.0018310546875000, -0.0013732910156250, 0.0014343261718750, -0.0017700195312500, +0.0014343261718750, -0.0015563964843750, 0.0015258789062500, -0.0010681152343750, +0.0009460449218750, -0.0016479492187500, 0.0013427734375000, -0.0008850097656250, +0.0008239746093750, -0.0012512207031250, 0.0008850097656250, -0.0010681152343750, +0.0012817382812500, -0.0005187988281250, 0.0006103515625000, -0.0013122558593750, +0.0013732910156250, -0.0000305175781250, 0.0010986328125000, -0.0003662109375000, +0.0010070800781250, -0.0002441406250000, 0.0014343261718750, 0.0005798339843750, +0.0009460449218750, 0.0000915527343750, 0.0011291503906250, 0.0006408691406250, +0.0010681152343750, 0.0006103515625000, 0.0006103515625000, 0.0006103515625000, +0.0005493164062500, 0.0009765625000000, 0.0004882812500000, 0.0007629394531250, +-0.0002136230468750, 0.0011901855468750, -0.0000915527343750, 0.0011596679687500, +-0.0003662109375000, 0.0011596679687500, -0.0007934570312500, 0.0013427734375000, +-0.0003662109375000, 0.0011291503906250, -0.0010375976562500, 0.0012512207031250, +-0.0007629394531250, 0.0010986328125000, -0.0008239746093750, 0.0009765625000000, +-0.0012512207031250, 0.0009765625000000, -0.0006713867187500, 0.0007019042968750, +-0.0012207031250000, 0.0006103515625000, -0.0008850097656250, 0.0004882812500000, +-0.0007934570312500, 0.0002746582031250, -0.0010986328125000, 0.0001525878906250, +-0.0003967285156250, 0.0000610351562500, -0.0009765625000000, 0.0000000000000000, +-0.0005187988281250, -0.0000915527343750, -0.0004272460937500, -0.0002136230468750, +-0.0006408691406250, -0.0002136230468750, 0.0002441406250000, -0.0001831054687500, +-0.0005187988281250, -0.0004882812500000, 0.0001525878906250, -0.0003967285156250, +0.0002441406250000, -0.0004577636718750, -0.0001831054687500, -0.0006408691406250, +0.0007629394531250, -0.0005798339843750, 0.0000000000000000, -0.0004272460937500, +0.0005187988281250, -0.0006103515625000, 0.0007019042968750, -0.0004272460937500, +0.0002746582031250, -0.0002441406250000, 0.0010070800781250, -0.0003967285156250, +0.0005493164062500, 0.0000000000000000, 0.0006713867187500, 0.0000000000000000, +0.0009155273437500, -0.0000305175781250, 0.0007324218750000, 0.0002136230468750, +0.0009155273437500, 0.0002441406250000, 0.0011901855468750, 0.0002746582031250, +0.0010070800781250, 0.0003051757812500, 0.0012512207031250, 0.0003051757812500, +0.0015258789062500, 0.0002746582031250, 0.0010070800781250, 0.0001831054687500, +0.0018615722656250, 0.0001831054687500, 0.0012817382812500, 0.0000305175781250, +0.0014038085937500, -0.0000915527343750, 0.0019226074218750, -0.0000915527343750, +0.0009155273437500, -0.0002746582031250, 0.0018920898437500, -0.0005187988281250, +0.0013427734375000, -0.0003662109375000, 0.0011291503906250, -0.0007019042968750, +0.0016784667968750, -0.0009155273437500, 0.0010070800781250, -0.0002746582031250, +0.0013122558593750, -0.0012207031250000, 0.0010375976562500, -0.0004882812500000, +0.0008850097656250, -0.0004882812500000, 0.0011291503906250, -0.0010681152343750, +0.0008850097656250, 0.0000610351562500, 0.0010986328125000, -0.0010986328125000, +0.0012512207031250, -0.0002746582031250, 0.0013427734375000, -0.0003967285156250, +0.0015563964843750, -0.0012817382812500, 0.0018615722656250, -0.0001525878906250, +0.0018920898437500, -0.0012817382812500, 0.0023498535156250, -0.0010986328125000, +0.0023193359375000, -0.0007934570312500, 0.0021667480468750, -0.0014038085937500, +0.0025939941406250, -0.0012207031250000, 0.0019226074218750, -0.0010070800781250, +0.0021362304687500, -0.0013122558593750, 0.0021972656250000, -0.0010986328125000, +0.0015869140625000, -0.0007934570312500, 0.0019226074218750, -0.0010681152343750, +0.0018005371093750, -0.0003356933593750, 0.0014648437500000, -0.0002441406250000, +0.0018005371093750, -0.0001831054687500, 0.0019531250000000, 0.0002746582031250, +0.0014648437500000, 0.0003051757812500, 0.0023498535156250, 0.0001220703125000, +0.0020446777343750, 0.0004272460937500, 0.0021057128906250, 0.0003967285156250, +0.0028076171875000, -0.0000610351562500, 0.0022277832031250, 0.0001831054687500, +0.0020141601562500, 0.0000000000000000, 0.0023193359375000, -0.0003662109375000, +0.0014343261718750, -0.0000610351562500, 0.0008544921875000, 0.0000305175781250, +0.0018005371093750, -0.0006713867187500, 0.0002441406250000, 0.0002136230468750, +0.0008239746093750, -0.0000610351562500, 0.0010375976562500, -0.0000915527343750, +0.0002136230468750, 0.0003967285156250, 0.0010375976562500, 0.0000305175781250, +0.0006713867187500, 0.0006103515625000, 0.0007934570312500, 0.0006103515625000, +0.0008239746093750, 0.0007324218750000, 0.0002746582031250, 0.0011596679687500, +0.0001525878906250, 0.0010681152343750, 0.0002441406250000, 0.0016174316406250, +-0.0005187988281250, 0.0015563964843750, 0.0000915527343750, 0.0018615722656250, +0.0006408691406250, 0.0022583007812500, -0.0003051757812500, 0.0018310546875000, +0.0020446777343750, 0.0027160644531250, 0.0017089843750000, 0.0025024414062500, +0.0017395019531250, 0.0025939941406250, 0.0038146972656250, 0.0036010742187500, +0.0043334960937500, 0.0032958984375000, 0.0048217773437500, 0.0024414062500000, +0.0046386718750000, 0.0032043457031250, 0.0045166015625000, 0.0028991699218750, +0.0045166015625000, 0.0021972656250000, 0.0041503906250000, 0.0030822753906250, +0.0039978027343750, 0.0015258789062500, 0.0037231445312500, 0.0019531250000000, +0.0034179687500000, 0.0016784667968750, 0.0030822753906250, 0.0006103515625000, +0.0026245117187500, 0.0015869140625000, 0.0023803710937500, 0.0001220703125000, +0.0016174316406250, 0.0006408691406250, 0.0011901855468750, 0.0005798339843750, +0.0010986328125000, -0.0003356933593750, 0.0005187988281250, 0.0007019042968750, +0.0000915527343750, 0.0002441406250000, 0.0003967285156250, 0.0004882812500000, +-0.0002441406250000, 0.0006408691406250, -0.0007324218750000, 0.0003967285156250, +0.0000610351562500, 0.0007324218750000, -0.0008850097656250, 0.0003356933593750, +-0.0005493164062500, 0.0004577636718750, -0.0002136230468750, 0.0003356933593750, +-0.0006408691406250, -0.0000915527343750, -0.0002136230468750, -0.0000305175781250, +0.0000000000000000, -0.0002441406250000, 0.0001220703125000, -0.0005493164062500, +0.0002136230468750, -0.0002441406250000, 0.0003356933593750, 0.0000000000000000, +0.0004882812500000, -0.0001525878906250, 0.0003967285156250, 0.0006408691406250, +0.0007629394531250, 0.0007629394531250, 0.0006408691406250, 0.0007019042968750, +0.0005187988281250, 0.0010986328125000, 0.0010986328125000, 0.0011291503906250, +0.0002136230468750, 0.0008850097656250, 0.0007629394531250, 0.0008239746093750, +0.0004577636718750, 0.0007629394531250, -0.0004882812500000, 0.0006103515625000, +0.0000915527343750, 0.0005187988281250, -0.0008544921875000, 0.0006713867187500, +-0.0010681152343750, 0.0004272460937500, -0.0009155273437500, 0.0005493164062500, +-0.0012817382812500, 0.0007934570312500, -0.0014343261718750, 0.0004577636718750, +-0.0012512207031250, 0.0007934570312500, -0.0014038085937500, 0.0006713867187500, +-0.0014343261718750, 0.0005493164062500, -0.0013122558593750, 0.0006408691406250, +-0.0014038085937500, 0.0003662109375000, -0.0014648437500000, 0.0005798339843750, +-0.0013122558593750, 0.0001831054687500, -0.0013427734375000, 0.0003662109375000, +-0.0013427734375000, 0.0006408691406250, -0.0012207031250000, 0.0000000000000000, +-0.0010681152343750, 0.0010681152343750, -0.0010375976562500, 0.0006103515625000, +-0.0008239746093750, 0.0007324218750000, -0.0006103515625000, 0.0014648437500000, +-0.0007324218750000, 0.0007324218750000, -0.0004577636718750, 0.0015258789062500, +-0.0005493164062500, 0.0013122558593750, -0.0004882812500000, 0.0011291503906250, +-0.0002441406250000, 0.0015258789062500, -0.0003051757812500, 0.0011596679687500, +-0.0000915527343750, 0.0013427734375000, 0.0000305175781250, 0.0012512207031250, +0.0000305175781250, 0.0010681152343750, 0.0001525878906250, 0.0010070800781250, +0.0003356933593750, 0.0008544921875000, 0.0001220703125000, 0.0006103515625000, +0.0003051757812500, 0.0003356933593750, 0.0003356933593750, 0.0001525878906250, +0.0002441406250000, -0.0001220703125000, 0.0004272460937500, -0.0003662109375000, +0.0000610351562500, -0.0004272460937500, 0.0006713867187500, -0.0008544921875000, +0.0004272460937500, -0.0009765625000000, -0.0001220703125000, -0.0010375976562500, +0.0007019042968750, -0.0014648437500000, -0.0002746582031250, -0.0012817382812500, +-0.0000610351562500, -0.0013732910156250, 0.0000305175781250, -0.0014953613281250, +-0.0005493164062500, -0.0013122558593750, -0.0001831054687500, -0.0012817382812500, +-0.0004882812500000, -0.0013122558593750, -0.0004577636718750, -0.0009155273437500, +-0.0004272460937500, -0.0008850097656250, -0.0005493164062500, -0.0008850097656250, +-0.0003356933593750, -0.0003051757812500, -0.0005187988281250, -0.0006408691406250, +-0.0003356933593750, -0.0001831054687500, -0.0000915527343750, -0.0000305175781250, +-0.0000610351562500, -0.0001525878906250, 0.0001831054687500, 0.0004577636718750, +0.0003967285156250, 0.0001525878906250, 0.0005493164062500, 0.0004882812500000, +0.0007629394531250, 0.0006713867187500, 0.0009460449218750, 0.0004577636718750, +0.0010070800781250, 0.0007629394531250, 0.0011596679687500, 0.0007324218750000, +0.0010986328125000, 0.0004882812500000, 0.0010681152343750, 0.0007629394531250, +0.0011596679687500, 0.0007629394531250, 0.0010375976562500, 0.0003662109375000, +0.0009155273437500, 0.0010986328125000, 0.0008850097656250, 0.0006103515625000, +0.0005798339843750, 0.0007934570312500, 0.0003356933593750, 0.0013427734375000, +0.0004272460937500, 0.0005798339843750, -0.0003356933593750, 0.0015563964843750, +-0.0002136230468750, 0.0011291503906250, -0.0005493164062500, 0.0010986328125000, +-0.0010375976562500, 0.0016479492187500, -0.0004882812500000, 0.0009460449218750, +-0.0014343261718750, 0.0014953613281250, -0.0010986328125000, 0.0013732910156250, +-0.0010375976562500, 0.0010681152343750, -0.0016479492187500, 0.0011901855468750, +-0.0010986328125000, 0.0009765625000000, -0.0011901855468750, 0.0005798339843750, +-0.0011901855468750, 0.0007019042968750, -0.0008239746093750, 0.0004882812500000, +-0.0007629394531250, 0.0000000000000000, -0.0008239746093750, 0.0000610351562500, +-0.0003356933593750, 0.0000610351562500, -0.0007629394531250, -0.0003967285156250, +-0.0007324218750000, 0.0000305175781250, -0.0003662109375000, 0.0002441406250000, +-0.0011596679687500, -0.0005187988281250, -0.0007324218750000, 0.0010375976562500, +-0.0008850097656250, 0.0003356933593750, -0.0012207031250000, 0.0007629394531250, +-0.0011596679687500}, +{-0.0012817382812500, 0.0010681152343750, -0.0009460449218750, 0.0018615722656250, +-0.0010375976562500, 0.0012817382812500, -0.0013732910156250, 0.0015869140625000, +-0.0010986328125000, 0.0016174316406250, -0.0010681152343750, 0.0011901855468750, +-0.0012817382812500, 0.0011596679687500, -0.0010681152343750, 0.0011901855468750, +-0.0009765625000000, 0.0004272460937500, -0.0010375976562500, 0.0005798339843750, +-0.0007934570312500, 0.0003967285156250, -0.0004882812500000, -0.0001525878906250, +-0.0005798339843750, 0.0001525878906250, -0.0002136230468750, -0.0004272460937500, +-0.0001525878906250, -0.0004272460937500, -0.0000610351562500, -0.0004882812500000, +0.0002136230468750, -0.0009155273437500, 0.0001525878906250, -0.0007019042968750, +0.0003051757812500, -0.0009155273437500, 0.0005187988281250, -0.0010375976562500, +0.0006103515625000, -0.0008850097656250, 0.0006408691406250, -0.0007324218750000, +0.0008239746093750, -0.0007934570312500, 0.0007019042968750, -0.0003356933593750, +0.0008850097656250, -0.0005493164062500, 0.0007629394531250, -0.0003051757812500, +0.0007019042968750, 0.0001831054687500, 0.0010681152343750, 0.0000000000000000, +0.0003356933593750, 0.0006713867187500, 0.0008239746093750, 0.0008544921875000, +0.0005187988281250, 0.0010375976562500, -0.0001525878906250, 0.0015258789062500, +0.0007324218750000, 0.0016174316406250, -0.0005493164062500, 0.0019531250000000, +-0.0000305175781250, 0.0022583007812500, -0.0000305175781250, 0.0023803710937500, +-0.0007934570312500, 0.0024414062500000, 0.0001525878906250, 0.0026245117187500, +-0.0005798339843750, 0.0025329589843750, -0.0001525878906250, 0.0025329589843750, +0.0001525878906250, 0.0025634765625000, -0.0001220703125000, 0.0023803710937500, +0.0004882812500000, 0.0021972656250000, 0.0003051757812500, 0.0024108886718750, +0.0005493164062500, 0.0019226074218750, 0.0007934570312500, 0.0018615722656250, +0.0007324218750000, 0.0019226074218750, 0.0009765625000000, 0.0011291503906250, +0.0010681152343750, 0.0014953613281250, 0.0011901855468750, 0.0010070800781250, +0.0010681152343750, 0.0006713867187500, 0.0010375976562500, 0.0007934570312500, +0.0012207031250000, 0.0002441406250000, 0.0005187988281250, 0.0001831054687500, +0.0006713867187500, 0.0002136230468750, 0.0003051757812500, -0.0001831054687500, +-0.0003051757812500, -0.0003356933593750, 0.0000610351562500, -0.0001831054687500, +-0.0007934570312500, -0.0005798339843750, -0.0005493164062500, -0.0005493164062500, +-0.0006713867187500, -0.0005493164062500, -0.0012817382812500, -0.0007934570312500, +-0.0005798339843750, -0.0006713867187500, -0.0010986328125000, -0.0005798339843750, +-0.0010070800781250, -0.0007629394531250, -0.0006408691406250, -0.0004882812500000, +-0.0007019042968750, -0.0002441406250000, -0.0006713867187500, -0.0005493164062500, +-0.0002136230468750, 0.0001831054687500, -0.0005187988281250, 0.0000305175781250, +-0.0003051757812500, 0.0001525878906250, -0.0000610351562500, 0.0007629394531250, +-0.0008850097656250, 0.0004577636718750, -0.0001831054687500, 0.0006713867187500, +-0.0006103515625000, 0.0009765625000000, -0.0009765625000000, 0.0007324218750000, +-0.0007019042968750, 0.0006103515625000, -0.0010986328125000, 0.0008544921875000, +-0.0010986328125000, 0.0001525878906250, -0.0012512207031250, 0.0002441406250000, +-0.0009155273437500, 0.0001220703125000, -0.0006408691406250, -0.0004577636718750, +-0.0009460449218750, -0.0002136230468750, 0.0002136230468750, -0.0002746582031250, +-0.0000610351562500, -0.0004882812500000, 0.0002441406250000, -0.0000915527343750, +0.0010070800781250, 0.0002746582031250, 0.0003662109375000, 0.0000000000000000, +0.0014343261718750, 0.0010375976562500, 0.0008239746093750, 0.0010986328125000, +0.0011291503906250, 0.0010681152343750, 0.0019226074218750, 0.0015258789062500, +0.0006713867187500, 0.0013732910156250, 0.0021667480468750, 0.0012207031250000, +0.0015258789062500, 0.0012207031250000, 0.0011901855468750, 0.0011291503906250, +0.0020141601562500, 0.0009155273437500, 0.0013427734375000, 0.0010070800781250, +0.0017089843750000, 0.0013427734375000, 0.0018310546875000, 0.0009155273437500, +0.0018615722656250, 0.0013122558593750, 0.0021667480468750, 0.0017089843750000, +0.0023803710937500, 0.0010375976562500, 0.0030517578125000, 0.0025329589843750, +0.0029907226562500, 0.0021972656250000, 0.0035400390625000, 0.0022583007812500, +0.0041809082031250, 0.0032043457031250, 0.0035400390625000, 0.0026245117187500, +0.0046386718750000, 0.0032958984375000, 0.0040588378906250, 0.0033264160156250, +0.0040588378906250, 0.0028076171875000, 0.0046386718750000, 0.0028076171875000, +0.0036926269531250, 0.0028991699218750, 0.0045776367187500, 0.0024719238281250, +0.0046691894531250, 0.0023498535156250, 0.0042114257812500, 0.0026855468750000, +0.0047912597656250, 0.0028381347656250, 0.0051879882812500, 0.0027770996093750, +0.0037841796875000, 0.0032653808593750, 0.0048828125000000, 0.0038452148437500, +0.0042419433593750, 0.0032043457031250, 0.0025329589843750, 0.0028381347656250, +0.0039062500000000, 0.0037231445312500, 0.0022277832031250, 0.0017700195312500, +0.0017395019531250, 0.0019226074218750, 0.0022583007812500, 0.0023193359375000, +0.0020141601562500, 0.0011291503906250, 0.0004577636718750, 0.0037841796875000, +0.0018310546875000, 0.0014038085937500, 0.0005493164062500, 0.0025939941406250, +0.0009460449218750, 0.0025939941406250, 0.0014648437500000, 0.0016479492187500, +0.0001831054687500, 0.0025024414062500, 0.0021057128906250, 0.0027770996093750, +0.0012817382812500, 0.0030822753906250, 0.0011901855468750, 0.0031738281250000, +0.0025634765625000, 0.0031738281250000, 0.0014648437500000, 0.0034484863281250, +0.0014648437500000, 0.0028381347656250, 0.0018005371093750, 0.0026550292968750, +0.0011291503906250, 0.0028686523437500, 0.0004882812500000, 0.0026550292968750, +0.0010070800781250, 0.0024108886718750, 0.0006408691406250, 0.0035705566406250, +0.0002441406250000, 0.0033264160156250, 0.0010375976562500, 0.0036315917968750, +0.0014953613281250, 0.0045776367187500, 0.0008239746093750, 0.0039978027343750, +0.0022277832031250, 0.0044555664062500, 0.0023803710937500, 0.0043945312500000, +0.0019531250000000, 0.0042114257812500, 0.0022888183593750, 0.0043029785156250, +0.0023803710937500, 0.0039367675781250, 0.0015869140625000, 0.0039062500000000, +0.0017700195312500, 0.0038146972656250, 0.0017089843750000, 0.0032348632812500, +0.0012207031250000, 0.0029296875000000, 0.0016479492187500, 0.0030517578125000, +0.0016784667968750, 0.0014953613281250, 0.0017089843750000, 0.0015869140625000, +0.0020141601562500, 0.0012207031250000, 0.0024414062500000, 0.0001525878906250, +0.0025024414062500, 0.0003967285156250, 0.0021057128906250, 0.0002746582031250, +0.0028076171875000, 0.0000610351562500, 0.0024108886718750, 0.0002441406250000, +0.0017089843750000, 0.0004882812500000, 0.0025634765625000, 0.0003967285156250, +0.0013732910156250, 0.0005187988281250, 0.0017089843750000, 0.0004577636718750, +0.0017089843750000, 0.0005187988281250, 0.0010375976562500, 0.0004577636718750, +0.0017089843750000, 0.0000000000000000, 0.0016174316406250, 0.0005187988281250, +0.0015869140625000, 0.0000000000000000, 0.0020751953125000, -0.0003356933593750, +0.0023803710937500, -0.0000305175781250, 0.0022277832031250, -0.0007019042968750, +0.0025634765625000, -0.0008239746093750, 0.0025024414062500, -0.0012207031250000, +0.0022583007812500, -0.0014648437500000, 0.0021362304687500, -0.0014648437500000, +0.0018005371093750, -0.0016784667968750, 0.0013427734375000, -0.0014648437500000, +0.0010070800781250, -0.0015258789062500, 0.0005187988281250, -0.0014343261718750, +0.0001525878906250, -0.0012512207031250, -0.0001220703125000, -0.0013732910156250, +-0.0005493164062500, -0.0010375976562500, -0.0008239746093750, -0.0012512207031250, +-0.0008239746093750, -0.0009765625000000, -0.0009155273437500, -0.0005493164062500, +-0.0010070800781250, -0.0008850097656250, -0.0007324218750000, -0.0002136230468750, +-0.0006408691406250, -0.0003967285156250, -0.0004882812500000, -0.0003967285156250, +-0.0002746582031250, -0.0000610351562500, -0.0001220703125000, -0.0004577636718750, +-0.0000305175781250, 0.0000000000000000, 0.0002136230468750, -0.0002441406250000, +0.0001831054687500, -0.0001525878906250, 0.0002441406250000, 0.0002136230468750, +0.0005187988281250, -0.0000305175781250, 0.0000915527343750, 0.0003356933593750, +0.0003356933593750, 0.0002136230468750, 0.0003356933593750, 0.0002441406250000, +0.0000610351562500, 0.0004882812500000, 0.0003356933593750, 0.0001831054687500, +-0.0002136230468750, 0.0004882812500000, -0.0001220703125000, 0.0003051757812500, +-0.0003356933593750, 0.0003051757812500, -0.0007629394531250, 0.0005493164062500, +-0.0004882812500000, 0.0003356933593750, -0.0011291503906250, 0.0003051757812500, +-0.0007934570312500, 0.0004577636718750, -0.0009460449218750, 0.0002441406250000, +-0.0013122558593750, 0.0000915527343750, -0.0005798339843750, 0.0004272460937500, +-0.0014343261718750, -0.0001525878906250, -0.0009155273437500, 0.0000305175781250, +-0.0008850097656250, 0.0000305175781250, -0.0014038085937500, -0.0002136230468750, +-0.0006408691406250, 0.0001220703125000, -0.0013732910156250, 0.0000000000000000, +-0.0008850097656250, 0.0001220703125000, -0.0007934570312500, 0.0002746582031250, +-0.0011596679687500, 0.0002136230468750, -0.0003662109375000, 0.0003662109375000, +-0.0009155273437500, 0.0003051757812500, -0.0005493164062500, 0.0004577636718750, +-0.0002746582031250, 0.0004272460937500, -0.0006103515625000, 0.0002441406250000, +-0.0001525878906250, 0.0004577636718750, -0.0000915527343750, 0.0002746582031250, +-0.0001525878906250, 0.0001525878906250, 0.0001220703125000, 0.0002746582031250, +0.0002746582031250, 0.0003051757812500, 0.0001831054687500, 0.0001525878906250, +0.0006408691406250, 0.0002136230468750, 0.0003967285156250, 0.0003356933593750, +0.0004577636718750, 0.0002136230468750, 0.0007324218750000, 0.0002136230468750, +0.0003051757812500, 0.0003356933593750, 0.0006408691406250, -0.0000915527343750, +0.0003967285156250, 0.0001525878906250, 0.0002746582031250, 0.0000305175781250, +0.0003356933593750, -0.0002746582031250, -0.0000610351562500, 0.0002136230468750, +0.0000000000000000, -0.0004272460937500, -0.0004577636718750, -0.0001220703125000, +-0.0004882812500000, -0.0001525878906250, -0.0004577636718750, -0.0004577636718750, +-0.0011901855468750, 0.0001220703125000, -0.0005798339843750, -0.0006103515625000, +-0.0010375976562500, -0.0002136230468750, -0.0010070800781250, -0.0002746582031250, +-0.0005493164062500, -0.0008850097656250, -0.0012512207031250, -0.0002441406250000, +-0.0003662109375000, -0.0007934570312500, -0.0006713867187500, -0.0009460449218750, +-0.0005798339843750, -0.0007324218750000, 0.0000915527343750, -0.0009155273437500, +-0.0003662109375000, -0.0011291503906250, 0.0003051757812500, -0.0006408691406250, +0.0004272460937500, -0.0010070800781250, 0.0003356933593750, -0.0007629394531250, +0.0007019042968750, -0.0001831054687500, 0.0008544921875000, -0.0005187988281250, +0.0006713867187500, 0.0002136230468750, 0.0011596679687500, 0.0005187988281250, +0.0011291503906250, 0.0005493164062500, 0.0010070800781250, 0.0009765625000000, +0.0016784667968750, 0.0012512207031250, 0.0011291503906250, 0.0007934570312500, +0.0016784667968750, 0.0013427734375000, 0.0019226074218750, 0.0011901855468750, +0.0017089843750000, 0.0006103515625000, 0.0024414062500000, 0.0011901855468750, +0.0023193359375000}, +{0.0006408691406250, -0.0007019042968750, -0.0001831054687500, -0.0002136230468750, +-0.0003051757812500, -0.0003356933593750, -0.0006103515625000, -0.0003662109375000, +-0.0011596679687500, -0.0000915527343750, -0.0009765625000000, -0.0003662109375000, +-0.0015563964843750, -0.0001220703125000, -0.0015258789062500, -0.0002136230468750, +-0.0014953613281250, -0.0002136230468750, -0.0017395019531250, -0.0000610351562500, +-0.0016174316406250, -0.0001831054687500, -0.0017395019531250, -0.0001220703125000, +-0.0016174316406250, -0.0001831054687500, -0.0015563964843750, -0.0001525878906250, +-0.0014038085937500, -0.0000305175781250, -0.0011291503906250, -0.0001220703125000, +-0.0011596679687500, 0.0000000000000000, -0.0007934570312500, 0.0001220703125000, +-0.0006103515625000, 0.0001220703125000, -0.0006713867187500, 0.0002136230468750, +-0.0003967285156250, 0.0003662109375000, -0.0003662109375000, 0.0001525878906250, +-0.0003967285156250, 0.0003662109375000, -0.0002441406250000, 0.0003356933593750, +-0.0002441406250000, 0.0002441406250000, -0.0003967285156250, 0.0006103515625000, +-0.0000610351562500, 0.0003051757812500, -0.0002746582031250, 0.0006408691406250, +-0.0002136230468750, 0.0005798339843750, 0.0000915527343750, 0.0003662109375000, +-0.0002441406250000, 0.0008239746093750, 0.0000915527343750, 0.0003662109375000, +0.0000000000000000, 0.0005493164062500, -0.0001220703125000, 0.0006408691406250, +0.0000610351562500, 0.0004272460937500, -0.0001831054687500, 0.0006408691406250, +-0.0002746582031250, 0.0005493164062500, -0.0003662109375000, 0.0005798339843750, +-0.0005187988281250, 0.0005798339843750, -0.0007019042968750, 0.0004882812500000, +-0.0007934570312500, 0.0005798339843750, -0.0009155273437500, 0.0004272460937500, +-0.0010375976562500, 0.0004577636718750, -0.0010986328125000, 0.0003967285156250, +-0.0011901855468750, 0.0003051757812500, -0.0013732910156250, 0.0003356933593750, +-0.0012512207031250, 0.0001525878906250, -0.0014953613281250, 0.0002441406250000, +-0.0014038085937500, 0.0002441406250000, -0.0011291503906250, 0.0001220703125000, +-0.0014343261718750, 0.0002746582031250, -0.0010986328125000, -0.0000305175781250, +-0.0011596679687500, 0.0002746582031250, -0.0011291503906250, 0.0001220703125000, +-0.0009460449218750, -0.0002746582031250, -0.0011291503906250, 0.0001525878906250, +-0.0007934570312500, -0.0005798339843750, -0.0010986328125000, -0.0006408691406250, +-0.0010986328125000, -0.0005798339843750, -0.0008239746093750, -0.0010375976562500, +-0.0012817382812500, -0.0010986328125000, -0.0010681152343750, -0.0008239746093750, +-0.0012817382812500, -0.0011596679687500, -0.0014648437500000, -0.0009765625000000, +-0.0014343261718750, -0.0005493164062500, -0.0017089843750000, -0.0007629394531250, +-0.0015258789062500, -0.0002441406250000, -0.0016784667968750, 0.0000305175781250, +-0.0015869140625000, 0.0002136230468750, -0.0012512207031250, 0.0006408691406250, +-0.0013427734375000, 0.0008850097656250, -0.0008239746093750, 0.0009460449218750, +-0.0005798339843750, 0.0012512207031250, -0.0003662109375000, 0.0011291503906250, +0.0000915527343750, 0.0009765625000000, 0.0002746582031250, 0.0013427734375000, +0.0003662109375000, 0.0006713867187500, 0.0007629394531250, 0.0007934570312500, +0.0007629394531250, 0.0008850097656250, 0.0006408691406250, 0.0004272460937500, +0.0009765625000000, 0.0005798339843750, 0.0007324218750000, 0.0004272460937500, +0.0004882812500000, 0.0003051757812500, 0.0010681152343750, 0.0004272460937500, +0.0010375976562500, 0.0004882812500000, 0.0002441406250000, 0.0003967285156250, +0.0015258789062500, 0.0006713867187500, 0.0006103515625000, 0.0006408691406250, +0.0007324218750000, 0.0008850097656250, 0.0015869140625000, 0.0012817382812500, +0.0001831054687500, 0.0009765625000000, 0.0015258789062500, 0.0014648437500000, +0.0010375976562500, 0.0013122558593750, 0.0007019042968750, 0.0016174316406250, +0.0015869140625000, 0.0020141601562500, 0.0012207031250000, 0.0015258789062500, +0.0014038085937500, 0.0025329589843750, 0.0018005371093750, 0.0024108886718750, +0.0020446777343750, 0.0022583007812500, 0.0024108886718750, 0.0028381347656250, +0.0029907226562500, 0.0029296875000000, 0.0030822753906250, 0.0026245117187500, +0.0038146972656250, 0.0032043457031250, 0.0039062500000000, 0.0029602050781250, +0.0037841796875000, 0.0027160644531250, 0.0045776367187500, 0.0036315917968750, +0.0037231445312500, 0.0025634765625000, 0.0042419433593750, 0.0032348632812500, +0.0043029785156250, 0.0032653808593750, 0.0032043457031250, 0.0019531250000000, +0.0028686523437500, 0.0021362304687500, 0.0021972656250000, 0.0018005371093750, +0.0026550292968750, 0.0017700195312500, 0.0024719238281250, 0.0017700195312500, +0.0020141601562500, 0.0014648437500000, 0.0026550292968750, 0.0013427734375000, +0.0018920898437500, 0.0014648437500000, 0.0022277832031250, 0.0013427734375000, +0.0021667480468750, 0.0014343261718750, 0.0017395019531250, 0.0014648437500000, +0.0024719238281250, 0.0011291503906250, 0.0014648437500000, 0.0012817382812500, +0.0017395019531250, 0.0007324218750000, 0.0020141601562500, 0.0008239746093750, +0.0013122558593750, 0.0010681152343750, 0.0014953613281250, 0.0002136230468750, +0.0024719238281250, 0.0009765625000000, 0.0015563964843750, 0.0004882812500000, +0.0022583007812500, 0.0002441406250000, 0.0034484863281250, 0.0006103515625000, +0.0018920898437500, -0.0000305175781250, 0.0035095214843750, 0.0003051757812500, +0.0032043457031250, 0.0000000000000000, 0.0024719238281250, 0.0000610351562500, +0.0029907226562500, 0.0003051757812500, 0.0025939941406250, -0.0000915527343750, +0.0019531250000000, 0.0007629394531250, 0.0021362304687500, 0.0004272460937500, +0.0016174316406250, 0.0005798339843750, 0.0008544921875000, 0.0012207031250000, +0.0012817382812500, 0.0005798339843750, 0.0002746582031250, 0.0009460449218750, +0.0000305175781250, 0.0007324218750000, -0.0000305175781250, 0.0006408691406250, +-0.0005493164062500, 0.0007629394531250, -0.0006103515625000, 0.0002746582031250, +-0.0003662109375000, 0.0008544921875000, -0.0006408691406250, 0.0004272460937500, +-0.0003967285156250, 0.0006103515625000, 0.0000915527343750, 0.0010986328125000, +-0.0001525878906250, 0.0003967285156250, 0.0002746582031250, 0.0014343261718750, +0.0005798339843750, 0.0008850097656250, 0.0004577636718750, 0.0008850097656250, +0.0005187988281250, 0.0015258789062500, 0.0008544921875000, 0.0005493164062500, +0.0002441406250000, 0.0011901855468750, 0.0005493164062500, 0.0007629394531250, +0.0003051757812500, 0.0006103515625000, -0.0002746582031250, 0.0009155273437500, +0.0001525878906250, 0.0002746582031250, -0.0004272460937500, 0.0007324218750000, +-0.0006103515625000, 0.0003967285156250, -0.0004882812500000, 0.0002441406250000, +-0.0007324218750000, 0.0005798339843750, -0.0010070800781250, 0.0001220703125000, +-0.0002441406250000, 0.0002136230468750, -0.0007934570312500, 0.0002136230468750, +-0.0005798339843750, -0.0000610351562500, 0.0001220703125000, -0.0001220703125000, +-0.0005798339843750, 0.0000305175781250, 0.0001831054687500, -0.0004577636718750, +0.0001525878906250, -0.0002136230468750, -0.0001525878906250, -0.0002441406250000, +0.0000610351562500, -0.0004577636718750, -0.0000305175781250, -0.0000305175781250, +-0.0002746582031250, -0.0001220703125000, -0.0003967285156250, 0.0000915527343750, +-0.0003051757812500, 0.0003662109375000, -0.0003967285156250, 0.0004272460937500, +-0.0006103515625000, 0.0006713867187500, -0.0002441406250000, 0.0008850097656250, +-0.0004272460937500, 0.0008544921875000, -0.0003662109375000, 0.0010070800781250, +-0.0000610351562500, 0.0010986328125000, -0.0002136230468750, 0.0008544921875000, +0.0000915527343750, 0.0010986328125000, 0.0001831054687500, 0.0008850097656250, +0.0002136230468750, 0.0007629394531250, 0.0004577636718750, 0.0008850097656250, +0.0005493164062500, 0.0007019042968750, 0.0005798339843750, 0.0005187988281250, +0.0007629394531250, 0.0004882812500000, 0.0008239746093750, 0.0003967285156250, +0.0008544921875000, 0.0001525878906250, 0.0011291503906250, 0.0001220703125000, +0.0008544921875000, 0.0001220703125000, 0.0011901855468750, 0.0000000000000000, +0.0012207031250000, 0.0001220703125000, 0.0008544921875000, 0.0001831054687500, +0.0012207031250000, -0.0000915527343750, 0.0007934570312500, 0.0004272460937500, +0.0008239746093750, 0.0000305175781250, 0.0007629394531250, 0.0001525878906250, +0.0003662109375000, 0.0004577636718750, 0.0004577636718750, -0.0001831054687500, +0.0000000000000000, 0.0006713867187500, 0.0000000000000000, 0.0002441406250000, +-0.0001831054687500, 0.0002746582031250, -0.0004882812500000, 0.0007629394531250, +-0.0003051757812500, 0.0001220703125000, -0.0008239746093750, 0.0006713867187500, +-0.0007019042968750, 0.0004272460937500, -0.0007629394531250, 0.0002441406250000, +-0.0010375976562500, 0.0005187988281250, -0.0006713867187500, 0.0002746582031250, +-0.0009155273437500, 0.0002441406250000, -0.0007324218750000, 0.0001220703125000, +-0.0005187988281250, 0.0000000000000000, -0.0006103515625000, -0.0001525878906250, +-0.0003051757812500, -0.0003051757812500, -0.0001220703125000, -0.0003662109375000, +-0.0002136230468750, -0.0004577636718750, 0.0000000000000000, -0.0005493164062500, +0.0001220703125000, -0.0005798339843750, -0.0001525878906250, -0.0007934570312500, +0.0003051757812500, -0.0004882812500000, 0.0000000000000000, -0.0007324218750000, +-0.0000305175781250, -0.0005187988281250, 0.0002136230468750, -0.0001525878906250, +-0.0003356933593750, -0.0005187988281250, -0.0002746582031250, 0.0003356933593750, +-0.0002746582031250, 0.0001831054687500, -0.0005493164062500, 0.0001525878906250, +-0.0007019042968750, 0.0007324218750000, -0.0004882812500000, 0.0004272460937500, +-0.0005493164062500, 0.0004882812500000, -0.0006103515625000, 0.0005187988281250, +-0.0002136230468750, 0.0002746582031250, 0.0001525878906250, 0.0000610351562500, +0.0000915527343750, 0.0000305175781250, 0.0006408691406250, -0.0003051757812500, +0.0007324218750000, -0.0005798339843750, 0.0010681152343750, -0.0004272460937500, +0.0013427734375000, -0.0005187988281250, 0.0010375976562500, -0.0009765625000000, +0.0020141601562500, -0.0002441406250000, 0.0016784667968750, -0.0007934570312500, +0.0017700195312500, -0.0004882812500000, 0.0024414062500000, 0.0001831054687500, +0.0017089843750000, -0.0004272460937500, 0.0021057128906250, 0.0006713867187500, +0.0019531250000000, 0.0005798339843750, 0.0015869140625000, 0.0006408691406250, +0.0017089843750000, 0.0011901855468750, 0.0016479492187500, 0.0007629394531250, +0.0014953613281250, 0.0010681152343750, 0.0017395019531250, 0.0008850097656250, +0.0018005371093750, 0.0008544921875000, 0.0018920898437500, 0.0009155273437500, +0.0021972656250000, 0.0005187988281250, 0.0021667480468750, 0.0012207031250000, +0.0022277832031250, 0.0007934570312500, 0.0023498535156250, 0.0010681152343750, +0.0022583007812500, 0.0017395019531250, 0.0018920898437500, 0.0009765625000000, +0.0022277832031250, 0.0021362304687500, 0.0017089843750000, 0.0018615722656250, +0.0013732910156250, 0.0018310546875000, 0.0017700195312500, 0.0025024414062500, +0.0016479492187500, 0.0020751953125000, 0.0009155273437500, 0.0019531250000000, +0.0021057128906250, 0.0026245117187500, 0.0013122558593750, 0.0021972656250000, +0.0003051757812500, 0.0017089843750000, 0.0022583007812500, 0.0024719238281250, +-0.0003662109375000, 0.0013122558593750, 0.0005187988281250, 0.0017089843750000, +0.0008239746093750}, +{0.0011596679687500, -0.0009460449218750, 0.0010681152343750, -0.0007934570312500, +0.0012512207031250, -0.0005493164062500, 0.0012817382812500, -0.0010681152343750, +0.0008544921875000, -0.0006103515625000, 0.0011596679687500, -0.0009155273437500, +0.0008544921875000, -0.0009460449218750, 0.0003662109375000, -0.0007019042968750, +0.0007629394531250, -0.0012512207031250, -0.0002441406250000, -0.0009155273437500, +0.0000000000000000, -0.0010681152343750, -0.0002746582031250, -0.0010681152343750, +-0.0010070800781250, -0.0008239746093750, -0.0004577636718750, -0.0009765625000000, +-0.0013122558593750, -0.0005493164062500, -0.0010681152343750, -0.0006408691406250, +-0.0010070800781250, -0.0003967285156250, -0.0014343261718750, -0.0000305175781250, +-0.0008850097656250, -0.0001525878906250, -0.0009155273437500, 0.0004577636718750, +-0.0010986328125000, 0.0003051757812500, -0.0006103515625000, 0.0005493164062500, +-0.0003356933593750, 0.0010375976562500, -0.0006103515625000, 0.0006408691406250, +0.0003356933593750, 0.0012207031250000, 0.0000610351562500, 0.0012512207031250, +0.0002441406250000, 0.0010375976562500, 0.0007934570312500, 0.0012817382812500, +0.0001525878906250, 0.0013427734375000, 0.0005798339843750, 0.0008239746093750, +0.0004272460937500, 0.0012512207031250, -0.0000305175781250, 0.0009155273437500, +0.0000000000000000, 0.0003051757812500, -0.0000610351562500, 0.0010070800781250, +-0.0002746582031250, -0.0000305175781250, -0.0003051757812500, 0.0002136230468750, +-0.0000915527343750, 0.0003051757812500, 0.0001220703125000, -0.0003051757812500, +0.0001220703125000, 0.0000915527343750, 0.0005187988281250, -0.0000305175781250, +0.0006713867187500, 0.0000610351562500, 0.0008544921875000, 0.0003051757812500, +0.0009460449218750, 0.0003967285156250, 0.0010375976562500, 0.0004882812500000, +0.0015258789062500, 0.0004272460937500, 0.0011596679687500, 0.0007934570312500, +0.0014953613281250, 0.0005187988281250, 0.0020141601562500, 0.0002441406250000, +0.0012512207031250, 0.0007629394531250, 0.0019531250000000, -0.0006713867187500, +0.0015869140625000, -0.0002136230468750, 0.0013122558593750, -0.0006408691406250, +0.0015563964843750, -0.0018005371093750, 0.0009460449218750, -0.0010070800781250, +0.0013122558593750, -0.0021362304687500, 0.0010986328125000, -0.0021057128906250, +0.0010070800781250, -0.0017395019531250, 0.0014038085937500, -0.0021362304687500, +0.0013427734375000, -0.0019531250000000, 0.0015869140625000, -0.0013427734375000, +0.0017700195312500, -0.0015869140625000, 0.0019226074218750, -0.0013122558593750, +0.0019531250000000, -0.0008239746093750, 0.0018615722656250, -0.0012817382812500, +0.0023498535156250, -0.0006713867187500, 0.0018615722656250, -0.0009460449218750, +0.0017700195312500, -0.0009460449218750, 0.0021057128906250, -0.0005798339843750, +0.0015258789062500, -0.0010681152343750, 0.0012512207031250, -0.0003356933593750, +0.0018615722656250, -0.0006713867187500, 0.0007934570312500, -0.0001525878906250, +0.0002746582031250, 0.0005798339843750, 0.0018615722656250, -0.0002746582031250, +-0.0007324218750000, 0.0014648437500000, 0.0005493164062500, 0.0011596679687500, +0.0004882812500000, 0.0014038085937500, -0.0011596679687500, 0.0027465820312500, +0.0007324218750000, 0.0022888183593750, -0.0008850097656250, 0.0026245117187500, +-0.0007629394531250, 0.0034179687500000, -0.0003356933593750, 0.0026245117187500, +-0.0012817382812500, 0.0020446777343750, -0.0012817382812500, 0.0031433105468750, +-0.0011291503906250, 0.0013732910156250, -0.0018005371093750, 0.0019226074218750, +-0.0014648437500000, 0.0019531250000000, -0.0011596679687500, 0.0010986328125000, +-0.0020446777343750, 0.0022583007812500, -0.0006713867187500, 0.0005187988281250, +-0.0010070800781250, 0.0015258789062500, -0.0012817382812500, 0.0013122558593750, +-0.0000915527343750, -0.0015258789062500, -0.0017089843750000, 0.0014038085937500, +-0.0010375976562500, 0.0002746582031250, -0.0015258789062500, 0.0014953613281250, +-0.0009155273437500, 0.0004577636718750, 0.0000915527343750, -0.0007629394531250, +-0.0000915527343750, 0.0004882812500000, 0.0001220703125000, -0.0014038085937500, +0.0011596679687500, -0.0011291503906250, 0.0006713867187500, -0.0007324218750000, +0.0001525878906250, -0.0014953613281250, 0.0012817382812500, -0.0008544921875000, +0.0001220703125000, -0.0006103515625000, 0.0000000000000000, -0.0005798339843750, +0.0007019042968750, -0.0003662109375000, 0.0006103515625000, -0.0000305175781250, +0.0005493164062500, 0.0001525878906250, 0.0014343261718750, 0.0003967285156250, +0.0017395019531250, 0.0003662109375000, 0.0014648437500000, 0.0007934570312500, +0.0017395019531250, 0.0013427734375000, 0.0021667480468750, 0.0011596679687500, +0.0007324218750000, 0.0016784667968750, 0.0010070800781250, 0.0021667480468750, +0.0010986328125000, 0.0019531250000000, 0.0000915527343750, 0.0019836425781250, +0.0004272460937500, 0.0027770996093750, 0.0007019042968750, 0.0018920898437500, +0.0002441406250000, 0.0021667480468750, 0.0005493164062500, 0.0026245117187500, +0.0010375976562500, 0.0023498535156250, 0.0003051757812500, 0.0025939941406250, +0.0007629394531250, 0.0029296875000000, 0.0005187988281250, 0.0028686523437500, +-0.0001220703125000, 0.0027770996093750, -0.0002746582031250, 0.0027770996093750, +-0.0005493164062500, 0.0024414062500000, -0.0010070800781250, 0.0024414062500000, +-0.0013122558593750, 0.0021057128906250, -0.0010375976562500, 0.0021667480468750, +-0.0008544921875000, 0.0022888183593750, -0.0011901855468750, 0.0017395019531250, +-0.0002136230468750, 0.0022583007812500, -0.0003051757812500, 0.0021972656250000, +-0.0001831054687500, 0.0018615722656250, 0.0004882812500000, 0.0020446777343750, +0.0002746582031250, 0.0021667480468750, 0.0003051757812500, 0.0015563964843750, +0.0007019042968750, 0.0018920898437500, 0.0003051757812500, 0.0017395019531250, +-0.0001831054687500, 0.0013122558593750, 0.0002136230468750, 0.0020141601562500, +-0.0007934570312500, 0.0010986328125000, -0.0009155273437500, 0.0013122558593750, +-0.0009765625000000, 0.0013427734375000, -0.0016174316406250, 0.0006408691406250, +-0.0016174316406250, 0.0007934570312500, -0.0015563964843750, 0.0006713867187500, +-0.0019531250000000, 0.0002441406250000, -0.0017395019531250, 0.0002746582031250, +-0.0015258789062500, 0.0002746582031250, -0.0020141601562500, -0.0002746582031250, +-0.0009460449218750, -0.0002136230468750, -0.0012512207031250, -0.0002441406250000, +-0.0009155273437500, -0.0006103515625000, -0.0000305175781250, -0.0006408691406250, +-0.0006408691406250, -0.0004882812500000, 0.0003356933593750, -0.0008544921875000, +0.0003051757812500, -0.0007934570312500, 0.0003051757812500, -0.0007934570312500, +0.0008850097656250, -0.0010070800781250, 0.0005493164062500, -0.0008544921875000, +0.0007629394531250, -0.0011596679687500, 0.0007019042968750, -0.0010375976562500, +0.0004577636718750, -0.0010986328125000, 0.0003967285156250, -0.0013122558593750, +0.0001525878906250, -0.0011596679687500, -0.0000305175781250, -0.0012817382812500, +-0.0003051757812500, -0.0012207031250000, -0.0004577636718750, -0.0011901855468750, +-0.0006103515625000, -0.0011901855468750, -0.0007934570312500, -0.0009765625000000, +-0.0007934570312500, -0.0010070800781250, -0.0010375976562500, -0.0007934570312500, +-0.0010375976562500, -0.0005798339843750, -0.0010070800781250, -0.0005187988281250, +-0.0013122558593750, -0.0003051757812500, -0.0009460449218750, -0.0000915527343750, +-0.0013732910156250, 0.0000610351562500, -0.0011596679687500, 0.0001831054687500, +-0.0009155273437500, 0.0003356933593750, -0.0015869140625000, 0.0004577636718750, +-0.0006408691406250, 0.0005493164062500, -0.0010375976562500, 0.0006408691406250, +-0.0008850097656250, 0.0006713867187500, -0.0001525878906250, 0.0006713867187500, +-0.0008544921875000, 0.0007934570312500, 0.0000915527343750, 0.0007324218750000, +-0.0001525878906250, 0.0008239746093750, -0.0000610351562500, 0.0008239746093750, +0.0005187988281250, 0.0007324218750000, 0.0000000000000000, 0.0008544921875000, +0.0004577636718750, 0.0007629394531250, 0.0004272460937500, 0.0007629394531250, +0.0003051757812500, 0.0007629394531250, 0.0005798339843750, 0.0007019042968750, +0.0005493164062500, 0.0007629394531250, 0.0004272460937500, 0.0006713867187500, +0.0008239746093750, 0.0006713867187500, 0.0007324218750000, 0.0005187988281250, +0.0006103515625000, 0.0003662109375000, 0.0011901855468750, 0.0004272460937500, +0.0004882812500000, 0.0002441406250000, 0.0010070800781250, 0.0001525878906250, +0.0011291503906250, 0.0001831054687500, 0.0007019042968750, 0.0001525878906250, +0.0013732910156250, 0.0001525878906250, 0.0010070800781250, -0.0000610351562500, +0.0013122558593750, 0.0000610351562500, 0.0015258789062500, -0.0000915527343750, +0.0014343261718750, -0.0004272460937500, 0.0017700195312500, -0.0002746582031250, +0.0018005371093750, -0.0004882812500000, 0.0018920898437500, -0.0007629394531250, +0.0020141601562500, -0.0005798339843750, 0.0020141601562500, -0.0005187988281250, +0.0021057128906250, -0.0007934570312500, 0.0021362304687500, -0.0001831054687500, +0.0019836425781250, -0.0003967285156250, 0.0020141601562500, -0.0002746582031250, +0.0018615722656250, 0.0002441406250000, 0.0014953613281250, 0.0001220703125000, +0.0018615722656250, 0.0005493164062500, 0.0014648437500000, 0.0007019042968750, +0.0014648437500000, 0.0008544921875000, 0.0017700195312500, 0.0011291503906250, +0.0012512207031250, 0.0012512207031250, 0.0017089843750000, 0.0014343261718750, +0.0016174316406250, 0.0016174316406250, 0.0015258789062500, 0.0015258789062500, +0.0017700195312500, 0.0013122558593750, 0.0016479492187500, 0.0012512207031250, +0.0015563964843750, 0.0011291503906250, 0.0018005371093750, 0.0005798339843750, +0.0014648437500000, 0.0007019042968750, 0.0012207031250000, 0.0006713867187500, +0.0015563964843750, -0.0002136230468750, 0.0005187988281250, 0.0006713867187500, +0.0007629394531250, -0.0001831054687500, 0.0003662109375000, -0.0001220703125000, +-0.0004577636718750, 0.0006713867187500, 0.0001831054687500, -0.0003662109375000, +-0.0009460449218750, 0.0007324218750000, -0.0006103515625000, 0.0005187988281250, +-0.0003967285156250, 0.0005493164062500, -0.0008239746093750, 0.0011901855468750, +-0.0003662109375000, 0.0007629394531250, -0.0009765625000000, 0.0012817382812500, +-0.0003662109375000, 0.0013732910156250, -0.0006713867187500, 0.0014648437500000, +-0.0014343261718750, 0.0017700195312500, -0.0005187988281250, 0.0016174316406250, +-0.0014648437500000, 0.0019836425781250, -0.0015258789062500, 0.0020751953125000, +-0.0010986328125000, 0.0020141601562500, -0.0013427734375000, 0.0021972656250000, +-0.0014038085937500, 0.0024108886718750, -0.0004882812500000, 0.0021362304687500, +-0.0005187988281250, 0.0025329589843750, -0.0002441406250000, 0.0025329589843750, +0.0003967285156250, 0.0023498535156250, 0.0002136230468750, 0.0028686523437500, +0.0004577636718750, 0.0021972656250000, 0.0005187988281250, 0.0023193359375000, +0.0007934570312500, 0.0023498535156250, 0.0010070800781250, 0.0018615722656250, +0.0009460449218750, 0.0018615722656250, 0.0022277832031250, 0.0016479492187500, +0.0021362304687500, 0.0013732910156250, 0.0025329589843750, 0.0013122558593750, +0.0032958984375000, 0.0010681152343750, 0.0023193359375000, 0.0005798339843750, +0.0019836425781250, 0.0008544921875000, 0.0023803710937500, 0.0004577636718750, +0.0021972656250000, 0.0006713867187500, 0.0018005371093750, 0.0008239746093750, +0.0022277832031250}, +{0.0032348632812500, 0.0002136230468750, 0.0032348632812500, 0.0002441406250000, +0.0029907226562500, 0.0000305175781250, 0.0031433105468750, -0.0000915527343750, +0.0028991699218750, -0.0000610351562500, 0.0027770996093750, -0.0000305175781250, +0.0031127929687500, -0.0000610351562500, 0.0021972656250000, -0.0000610351562500, +0.0027465820312500, 0.0001220703125000, 0.0024108886718750, 0.0000000000000000, +0.0016479492187500, -0.0001831054687500, 0.0025024414062500, 0.0000915527343750, +0.0011901855468750, -0.0003662109375000, 0.0013427734375000, -0.0004577636718750, +0.0012512207031250, -0.0003051757812500, 0.0003662109375000, -0.0006103515625000, +0.0006408691406250, -0.0007019042968750, 0.0002746582031250, -0.0002441406250000, +0.0000000000000000, -0.0006103515625000, 0.0000305175781250, -0.0003356933593750, +-0.0001220703125000, 0.0002136230468750, -0.0003051757812500, -0.0001220703125000, +0.0001220703125000, 0.0006103515625000, -0.0002136230468750, 0.0006408691406250, +0.0000000000000000, 0.0008239746093750, 0.0004882812500000, 0.0013732910156250, +-0.0000915527343750, 0.0012817382812500, 0.0009460449218750, 0.0017395019531250, +0.0006103515625000, 0.0018005371093750, 0.0008850097656250, 0.0018005371093750, +0.0016479492187500, 0.0018920898437500, 0.0008850097656250, 0.0017089843750000, +0.0021057128906250, 0.0015563964843750, 0.0017395019531250, 0.0011901855468750, +0.0018310546875000, 0.0010986328125000, 0.0025329589843750, 0.0008544921875000, +0.0018310546875000, 0.0001831054687500, 0.0025329589843750, 0.0008544921875000, +0.0023193359375000, 0.0001525878906250, 0.0021972656250000, 0.0001220703125000, +0.0026245117187500, 0.0006103515625000, 0.0024414062500000, -0.0003051757812500, +0.0025939941406250, 0.0005187988281250, 0.0028991699218750, 0.0001525878906250, +0.0028991699218750, 0.0001831054687500, 0.0030822753906250, 0.0007324218750000, +0.0034484863281250, 0.0002441406250000, 0.0027770996093750, 0.0008239746093750, +0.0037231445312500, 0.0007934570312500, 0.0031433105468750, 0.0006408691406250, +0.0022888183593750, 0.0010375976562500, 0.0038452148437500, 0.0010681152343750, +0.0018005371093750, 0.0011596679687500, 0.0026550292968750, 0.0011596679687500, +0.0024108886718750, 0.0013122558593750, 0.0010986328125000, 0.0015258789062500, +0.0025634765625000, 0.0014343261718750, 0.0003662109375000, 0.0018310546875000, +0.0009460449218750, 0.0019836425781250, 0.0007934570312500, 0.0019836425781250, +-0.0009155273437500, 0.0022277832031250, -0.0000610351562500, 0.0024414062500000, +-0.0011596679687500, 0.0022583007812500, -0.0011901855468750, 0.0025024414062500, +-0.0010986328125000, 0.0024108886718750, -0.0016479492187500, 0.0020141601562500, +-0.0016174316406250, 0.0022277832031250, -0.0014343261718750, 0.0020141601562500, +-0.0016174316406250, 0.0015869140625000, -0.0014038085937500, 0.0014648437500000, +-0.0011596679687500, 0.0012817382812500, -0.0013732910156250, 0.0008239746093750, +-0.0005187988281250, 0.0008239746093750, -0.0009155273437500, 0.0003662109375000, +-0.0003967285156250, 0.0003051757812500, 0.0006408691406250, 0.0004272460937500, +-0.0000610351562500, 0.0000305175781250, 0.0009155273437500, 0.0003967285156250, +0.0007019042968750, 0.0001220703125000, 0.0005798339843750, 0.0000915527343750, +0.0013732910156250, 0.0002441406250000, 0.0013732910156250, -0.0002746582031250, +0.0012207031250000, 0.0000000000000000, 0.0015258789062500, -0.0004577636718750, +0.0018310546875000, -0.0004882812500000, 0.0016479492187500, -0.0003662109375000, +0.0017700195312500, -0.0010681152343750, 0.0026855468750000, -0.0002136230468750, +0.0023498535156250, -0.0008239746093750, 0.0025634765625000, -0.0007629394531250, +0.0034484863281250, 0.0000000000000000, 0.0029602050781250, -0.0008544921875000, +0.0028381347656250, 0.0001525878906250, 0.0034790039062500, -0.0002441406250000, +0.0029296875000000, -0.0001525878906250, 0.0023803710937500, 0.0005187988281250, +0.0032653808593750, -0.0001525878906250, 0.0018310546875000, 0.0006408691406250, +0.0024108886718750, 0.0005187988281250, 0.0021972656250000, 0.0003967285156250, +0.0011291503906250, 0.0007324218750000, 0.0021667480468750, 0.0004272460937500, +0.0009460449218750, 0.0004882812500000, 0.0007324218750000, 0.0004577636718750, +0.0010070800781250, 0.0002441406250000, 0.0005798339843750, 0.0001220703125000, +0.0003967285156250, 0.0001525878906250, 0.0008544921875000, -0.0002136230468750, +0.0005187988281250, -0.0002746582031250, 0.0006103515625000, -0.0003051757812500, +0.0010070800781250, -0.0004577636718750, 0.0006103515625000, -0.0004577636718750, +0.0010375976562500, -0.0007934570312500, 0.0007629394531250, -0.0007324218750000, +0.0008544921875000, -0.0010375976562500, 0.0012512207031250, -0.0013732910156250, +0.0007629394531250, -0.0012207031250000, 0.0014343261718750, -0.0017700195312500, +0.0012512207031250, -0.0017700195312500, 0.0012207031250000, -0.0016479492187500, +0.0017700195312500, -0.0018310546875000, 0.0014343261718750, -0.0017395019531250, +0.0017395019531250, -0.0012817382812500, 0.0018310546875000, -0.0013427734375000, +0.0017700195312500, -0.0009155273437500, 0.0019531250000000, -0.0002746582031250, +0.0020751953125000, -0.0005187988281250, 0.0018920898437500, 0.0001831054687500, +0.0022583007812500, 0.0001525878906250, 0.0020446777343750, 0.0000610351562500, +0.0018310546875000, 0.0002136230468750, 0.0024719238281250, -0.0001220703125000, +0.0012512207031250, -0.0003051757812500, 0.0018310546875000, -0.0006713867187500, +0.0015258789062500, -0.0008544921875000, 0.0005798339843750, -0.0010681152343750, +0.0013732910156250, -0.0015258789062500, 0.0004272460937500, -0.0011291503906250, +0.0003967285156250, -0.0016174316406250, 0.0006103515625000, -0.0013732910156250, +0.0001831054687500, -0.0008239746093750, 0.0003356933593750, -0.0014343261718750, +0.0003662109375000, -0.0001831054687500, 0.0003051757812500, -0.0004272460937500, +0.0003356933593750, -0.0001525878906250, 0.0003967285156250, 0.0007019042968750, +0.0004272460937500, 0.0001220703125000, 0.0003967285156250, 0.0010681152343750, +0.0005493164062500, 0.0008850097656250, 0.0005798339843750, 0.0007629394531250, +0.0004882812500000, 0.0011291503906250, 0.0006408691406250, 0.0007629394531250, +0.0005798339843750, 0.0009155273437500, 0.0005187988281250, 0.0009155273437500, +0.0005798339843750, 0.0008239746093750, 0.0004882812500000, 0.0007934570312500, +0.0002746582031250, 0.0006408691406250, 0.0004882812500000, 0.0008544921875000, +0.0002136230468750, 0.0007019042968750, 0.0001525878906250, 0.0007324218750000, +0.0002746582031250, 0.0009460449218750, -0.0000915527343750, 0.0008239746093750, +-0.0000610351562500, 0.0008850097656250, -0.0000610351562500, 0.0009765625000000, +-0.0002746582031250, 0.0009460449218750, -0.0003662109375000, 0.0010375976562500, +-0.0002441406250000, 0.0011901855468750, -0.0004577636718750, 0.0010681152343750, +-0.0003662109375000, 0.0012207031250000, -0.0003356933593750, 0.0013427734375000, +-0.0004882812500000, 0.0012207031250000, -0.0001831054687500, 0.0013732910156250, +-0.0004577636718750, 0.0013732910156250, -0.0002746582031250, 0.0012817382812500, +-0.0002136230468750, 0.0014648437500000, -0.0003356933593750, 0.0014648437500000, +-0.0001831054687500, 0.0012512207031250, -0.0001525878906250, 0.0016479492187500, +-0.0003051757812500, 0.0014343261718750, -0.0001831054687500, 0.0014648437500000, +-0.0001525878906250, 0.0017089843750000, -0.0003967285156250, 0.0013427734375000, +0.0000305175781250, 0.0017395019531250, -0.0001220703125000, 0.0016479492187500, +-0.0001831054687500, 0.0015258789062500, 0.0000305175781250, 0.0016784667968750, +-0.0002136230468750, 0.0016174316406250, -0.0001831054687500, 0.0015258789062500, +-0.0002746582031250, 0.0014648437500000, -0.0003051757812500, 0.0012512207031250, +-0.0002136230468750, 0.0010070800781250, -0.0002441406250000, 0.0009155273437500, +0.0002441406250000, 0.0005798339843750, 0.0002441406250000, 0.0001831054687500, +0.0005187988281250, 0.0001525878906250, 0.0010070800781250, -0.0000610351562500, +0.0008850097656250, -0.0005187988281250, 0.0013732910156250, 0.0000000000000000, +0.0013427734375000, -0.0005798339843750, 0.0016479492187500, -0.0002746582031250, +0.0018920898437500, 0.0003051757812500, 0.0014343261718750, -0.0005187988281250, +0.0023498535156250, 0.0009155273437500, 0.0017700195312500, 0.0004882812500000, +0.0016784667968750, 0.0006713867187500, 0.0021972656250000, 0.0017395019531250, +0.0012207031250000, 0.0009765625000000, 0.0017089843750000, 0.0016174316406250, +0.0011596679687500, 0.0017395019531250, 0.0009155273437500, 0.0015258789062500, +0.0011596679687500, 0.0016479492187500, 0.0004272460937500, 0.0016174316406250, +0.0008544921875000, 0.0013427734375000, 0.0006408691406250, 0.0013732910156250, +0.0005493164062500, 0.0011901855468750, 0.0008850097656250, 0.0009155273437500, +0.0006408691406250, 0.0010986328125000, 0.0010986328125000, 0.0010986328125000, +0.0010070800781250, 0.0008239746093750, 0.0012817382812500, 0.0011291503906250, +0.0017089843750000, 0.0015563964843750, 0.0013122558593750, 0.0011596679687500, +0.0019531250000000, 0.0013732910156250, 0.0018920898437500, 0.0016479492187500, +0.0014953613281250, 0.0012512207031250, 0.0016479492187500, 0.0010375976562500, +0.0015563964843750, 0.0014648437500000, 0.0007629394531250, 0.0007629394531250, +0.0015869140625000, 0.0010070800781250, 0.0010681152343750, 0.0009460449218750, +0.0003967285156250, 0.0004272460937500, 0.0019226074218750, 0.0008850097656250, +-0.0000915527343750, 0.0002441406250000, 0.0009765625000000, 0.0003967285156250, +0.0005187988281250, 0.0006103515625000, -0.0012512207031250, 0.0003662109375000, +0.0003662109375000, 0.0004882812500000, -0.0014953613281250, 0.0005493164062500, +-0.0019531250000000, 0.0007019042968750, -0.0015258789062500, 0.0004882812500000, +-0.0024414062500000, 0.0004272460937500, -0.0030517578125000, 0.0007019042968750, +-0.0019836425781250, -0.0007629394531250, -0.0028991699218750, -0.0001525878906250, +-0.0028686523437500, -0.0005187988281250, -0.0019226074218750, -0.0017395019531250, +-0.0029602050781250, -0.0007324218750000, -0.0023803710937500, -0.0011596679687500, +-0.0023193359375000, -0.0009765625000000, -0.0025939941406250, -0.0006713867187500, +-0.0025024414062500, -0.0003051757812500, -0.0024719238281250, 0.0002441406250000, +-0.0019531250000000, -0.0009155273437500, -0.0023193359375000, 0.0000610351562500, +-0.0019531250000000, -0.0000610351562500, -0.0006408691406250, -0.0022277832031250, +-0.0007019042968750, -0.0001831054687500, -0.0010986328125000, -0.0024414062500000, +-0.0005493164062500, -0.0010681152343750, -0.0003356933593750, -0.0016784667968750, +-0.0002136230468750, -0.0032958984375000, 0.0001525878906250, -0.0024719238281250, +-0.0000305175781250, -0.0022583007812500, 0.0005493164062500, -0.0031738281250000, +0.0001220703125000, -0.0022888183593750, -0.0003967285156250, -0.0011596679687500, +0.0004577636718750, -0.0023803710937500, -0.0009155273437500, -0.0010375976562500, +-0.0003356933593750, -0.0008544921875000, -0.0001831054687500, -0.0013427734375000, +-0.0008850097656250, -0.0011596679687500, -0.0000610351562500, -0.0009765625000000, +-0.0003662109375000, -0.0010070800781250, -0.0000305175781250, -0.0009460449218750, +-0.0000915527343750, -0.0005493164062500, -0.0002746582031250, -0.0000915527343750, +0.0001831054687500, 0.0001220703125000, -0.0011291503906250, 0.0000915527343750, +-0.0008850097656250}, +{0.0019531250000000, 0.0006713867187500, 0.0017089843750000, 0.0005493164062500, +0.0018920898437500, 0.0000915527343750, 0.0023803710937500, 0.0000305175781250, +0.0015869140625000, -0.0002441406250000, 0.0021667480468750, -0.0008239746093750, +0.0016784667968750, -0.0009460449218750, 0.0014648437500000, -0.0012207031250000, +0.0017089843750000, -0.0017089843750000, 0.0009765625000000, -0.0017700195312500, +0.0013732910156250, -0.0017395019531250, 0.0010375976562500, -0.0020446777343750, +0.0007629394531250, -0.0019226074218750, 0.0009460449218750, -0.0017395019531250, +0.0006408691406250, -0.0020751953125000, 0.0007629394531250, -0.0016784667968750, +0.0006713867187500, -0.0017700195312500, 0.0008239746093750, -0.0018920898437500, +0.0010375976562500, -0.0016784667968750, 0.0008239746093750, -0.0018310546875000, +0.0011901855468750, -0.0020141601562500, 0.0011291503906250, -0.0020751953125000, +0.0010375976562500, -0.0022277832031250, 0.0010986328125000, -0.0025024414062500, +0.0007629394531250, -0.0026550292968750, 0.0005187988281250, -0.0023498535156250, +0.0006713867187500, -0.0027465820312500, 0.0002441406250000, -0.0024414062500000, +0.0000915527343750, -0.0018920898437500, 0.0008239746093750, -0.0022583007812500, +-0.0003967285156250, -0.0012207031250000, 0.0007019042968750, -0.0011596679687500, +0.0003967285156250, -0.0008850097656250, -0.0008239746093750, -0.0002441406250000, +0.0007934570312500, -0.0003356933593750, -0.0010986328125000, 0.0002136230468750, +-0.0008850097656250, 0.0004882812500000, -0.0007019042968750, 0.0005187988281250, +-0.0020751953125000, 0.0007324218750000, -0.0019226074218750, 0.0009155273437500, +-0.0014038085937500, 0.0007019042968750, -0.0025329589843750, 0.0010375976562500, +-0.0024108886718750, 0.0011901855468750, -0.0016479492187500, 0.0010681152343750, +-0.0027160644531250, 0.0013122558593750, -0.0022277832031250, 0.0017089843750000, +-0.0021972656250000, 0.0019226074218750, -0.0024719238281250, 0.0016174316406250, +-0.0023803710937500, 0.0018005371093750, -0.0023498535156250, 0.0023193359375000, +-0.0022888183593750, 0.0003356933593750, -0.0023193359375000, 0.0011901855468750, +-0.0020446777343750, 0.0007934570312500, -0.0017700195312500, -0.0008850097656250, +-0.0017700195312500, 0.0002441406250000, -0.0013427734375000, -0.0007324218750000, +-0.0011596679687500, -0.0005187988281250, -0.0011901855468750, -0.0003356933593750, +-0.0012207031250000, -0.0012207031250000, 0.0008239746093750, 0.0010986328125000, +0.0000305175781250, 0.0003051757812500, 0.0012512207031250, 0.0006408691406250, +0.0008544921875000, 0.0000305175781250, 0.0000915527343750, -0.0003356933593750, +0.0009460449218750, 0.0003051757812500, -0.0002746582031250, -0.0017395019531250, +-0.0002136230468750, -0.0011901855468750, 0.0000305175781250, -0.0014648437500000, +-0.0003051757812500, -0.0032348632812500, 0.0000305175781250, -0.0024719238281250, +0.0000915527343750, -0.0025024414062500, 0.0005798339843750, -0.0033569335937500, +0.0002136230468750, -0.0027465820312500, 0.0000610351562500, -0.0018615722656250, +0.0009155273437500, -0.0026855468750000, -0.0007019042968750, -0.0016174316406250, +-0.0002136230468750, -0.0017089843750000, -0.0002441406250000, -0.0017089843750000, +-0.0014648437500000, -0.0011901855468750, -0.0008239746093750, -0.0014038085937500, +-0.0005798339843750, -0.0004577636718750, -0.0008544921875000, -0.0004577636718750, +-0.0005187988281250, -0.0001220703125000, 0.0002136230468750, 0.0008239746093750, +0.0002136230468750, 0.0006103515625000, -0.0001220703125000, 0.0006103515625000, +0.0004577636718750, 0.0011596679687500, 0.0000305175781250, 0.0007629394531250, +-0.0006713867187500, 0.0002441406250000, -0.0000305175781250, 0.0008850097656250, +-0.0010986328125000, 0.0002441406250000, -0.0011901855468750, 0.0002746582031250, +-0.0010375976562500, 0.0006408691406250, -0.0016479492187500, 0.0006408691406250, +-0.0015869140625000, 0.0007019042968750, -0.0010070800781250, 0.0010681152343750, +-0.0011901855468750, 0.0014343261718750, -0.0009765625000000, 0.0014953613281250, +-0.0003967285156250, 0.0016479492187500, -0.0005798339843750, 0.0019531250000000, +-0.0002136230468750, 0.0018310546875000, 0.0000610351562500, 0.0019836425781250, +0.0001220703125000, 0.0021057128906250, 0.0003356933593750, 0.0021667480468750, +0.0007934570312500, 0.0023193359375000, 0.0006713867187500, 0.0022277832031250, +0.0008850097656250, 0.0023498535156250, 0.0012512207031250, 0.0021667480468750, +0.0013122558593750, 0.0019531250000000, 0.0012817382812500, 0.0019836425781250, +0.0017700195312500, 0.0015869140625000, 0.0017395019531250, 0.0016174316406250, +0.0015563964843750, 0.0014343261718750, 0.0016784667968750, 0.0012817382812500, +0.0016174316406250, 0.0015563964843750, 0.0008544921875000, 0.0010070800781250, +0.0010375976562500, 0.0014343261718750, 0.0007629394531250, 0.0014343261718750, +0.0000915527343750, 0.0009765625000000, 0.0005798339843750, 0.0016174316406250, +-0.0001525878906250, 0.0011596679687500, 0.0000305175781250, 0.0013427734375000, +0.0000915527343750, 0.0013732910156250, -0.0002746582031250, 0.0010070800781250, +0.0000915527343750, 0.0012207031250000, 0.0000610351562500, 0.0007324218750000, +0.0001220703125000, 0.0007324218750000, 0.0003967285156250, 0.0005187988281250, +0.0006103515625000, 0.0001525878906250, 0.0006713867187500, 0.0002746582031250, +0.0010375976562500, -0.0002441406250000, 0.0010375976562500, -0.0000915527343750, +0.0012512207031250, -0.0003051757812500, 0.0015563964843750, -0.0007019042968750, +0.0013122558593750, -0.0003051757812500, 0.0018615722656250, -0.0007629394531250, +0.0016479492187500, -0.0006408691406250, 0.0017700195312500, -0.0005187988281250, +0.0020751953125000, -0.0007324218750000, 0.0017089843750000, -0.0004882812500000, +0.0023193359375000, -0.0005493164062500, 0.0020751953125000, -0.0005493164062500, +0.0022583007812500, -0.0005798339843750, 0.0026855468750000, -0.0005798339843750, +0.0021972656250000, -0.0005798339843750, 0.0028686523437500, -0.0004272460937500, +0.0026855468750000, -0.0005187988281250, 0.0025939941406250, -0.0004577636718750, +0.0028381347656250, -0.0003356933593750, 0.0025024414062500, -0.0004577636718750, +0.0025634765625000, -0.0002746582031250, 0.0023498535156250, -0.0003662109375000, +0.0022277832031250, -0.0002746582031250, 0.0020751953125000, -0.0001831054687500, +0.0017089843750000, -0.0004272460937500, 0.0018310546875000, -0.0000610351562500, +0.0014343261718750, -0.0003051757812500, 0.0013732910156250, -0.0001525878906250, +0.0013732910156250, 0.0001220703125000, 0.0008544921875000, -0.0003051757812500, +0.0011291503906250, 0.0001525878906250, 0.0006103515625000, 0.0000305175781250, +0.0004882812500000, -0.0000610351562500, 0.0006713867187500, 0.0002441406250000, +-0.0001525878906250, 0.0001831054687500, 0.0002746582031250, 0.0000000000000000, +-0.0003051757812500, 0.0002441406250000, -0.0004272460937500, 0.0000915527343750, +-0.0002441406250000, -0.0002136230468750, -0.0010681152343750, 0.0001220703125000, +-0.0005798339843750, -0.0002746582031250, -0.0010681152343750, -0.0002746582031250, +-0.0013122558593750, -0.0001525878906250, -0.0010375976562500, -0.0003662109375000, +-0.0016784667968750, -0.0002136230468750, -0.0013732910156250, 0.0001220703125000, +-0.0014648437500000, -0.0000305175781250, -0.0015563964843750, 0.0002441406250000, +-0.0013732910156250, 0.0007019042968750, -0.0013427734375000, 0.0004272460937500, +-0.0013427734375000, 0.0009765625000000, -0.0010681152343750, 0.0009765625000000, +-0.0010070800781250, 0.0011291503906250, -0.0009460449218750, 0.0015258789062500, +-0.0006103515625000, 0.0013732910156250, -0.0006103515625000, 0.0018005371093750, +-0.0003662109375000, 0.0015563964843750, -0.0003051757812500, 0.0015563964843750, +-0.0003051757812500, 0.0016479492187500, -0.0000305175781250, 0.0011596679687500, +-0.0002136230468750, 0.0015258789062500, -0.0001220703125000, 0.0008850097656250, +-0.0002746582031250, 0.0008544921875000, -0.0005798339843750, 0.0011291503906250, +-0.0003967285156250, 0.0002746582031250, -0.0010070800781250, 0.0010375976562500, +-0.0012207031250000, 0.0006408691406250, -0.0013122558593750, 0.0003356933593750, +-0.0017089843750000, 0.0007019042968750, -0.0020141601562500, 0.0002136230468750, +-0.0017700195312500, 0.0004882812500000, -0.0021972656250000, 0.0005798339843750, +-0.0021972656250000, 0.0004272460937500, -0.0018310546875000, 0.0006103515625000, +-0.0022583007812500, 0.0009765625000000, -0.0021057128906250, 0.0005798339843750, +-0.0019531250000000, 0.0008239746093750, -0.0023193359375000, 0.0009155273437500, +-0.0024108886718750, 0.0005187988281250, -0.0020446777343750, 0.0007324218750000, +-0.0027465820312500, 0.0008239746093750, -0.0025024414062500, 0.0005187988281250, +-0.0024719238281250, 0.0007629394531250, -0.0030517578125000, 0.0009765625000000, +-0.0026550292968750, 0.0005493164062500, -0.0022888183593750, 0.0012817382812500, +-0.0026245117187500, 0.0011596679687500, -0.0018920898437500, 0.0010070800781250, +-0.0011596679687500, 0.0014038085937500, -0.0018615722656250, 0.0013122558593750, +-0.0000915527343750, 0.0012817382812500, -0.0004882812500000, 0.0012207031250000, +-0.0002441406250000, 0.0011596679687500, 0.0007019042968750, 0.0010986328125000, +-0.0003967285156250, 0.0009460449218750, 0.0008850097656250, 0.0009460449218750, +0.0003051757812500, 0.0004882812500000, 0.0004882812500000, 0.0003356933593750, +0.0014648437500000, 0.0002441406250000, 0.0006713867187500, -0.0001831054687500, +0.0016784667968750, 0.0000000000000000, 0.0018005371093750, -0.0004882812500000, +0.0012512207031250, -0.0004882812500000, 0.0014343261718750, -0.0002746582031250, +0.0016174316406250, -0.0008850097656250, 0.0001525878906250, -0.0004577636718750, +0.0004577636718750, -0.0006713867187500, 0.0001525878906250, -0.0008850097656250, +-0.0010375976562500, -0.0007019042968750, -0.0007324218750000, -0.0007324218750000, +-0.0013122558593750, -0.0002746582031250, -0.0012207031250000, -0.0006408691406250, +-0.0011291503906250, -0.0005798339843750, -0.0015563964843750, -0.0002136230468750, +-0.0013427734375000, -0.0007629394531250, -0.0011901855468750, -0.0002441406250000, +-0.0014038085937500, -0.0004882812500000, -0.0011291503906250, -0.0004272460937500, +-0.0007629394531250, 0.0000000000000000, -0.0009155273437500, -0.0003662109375000, +-0.0003356933593750, 0.0003051757812500, -0.0002746582031250, 0.0002136230468750, +0.0000000000000000, 0.0001525878906250, 0.0003662109375000, 0.0006103515625000, +0.0001831054687500, 0.0005187988281250, 0.0010986328125000, 0.0002746582031250, +0.0007019042968750, 0.0004272460937500, 0.0010986328125000, 0.0002746582031250, +0.0019836425781250, -0.0001220703125000, 0.0012512207031250, 0.0000305175781250, +0.0023498535156250, 0.0000000000000000, 0.0024108886718750, -0.0001831054687500, +0.0021667480468750, -0.0001525878906250, 0.0026245117187500, 0.0000610351562500, +0.0025634765625000, -0.0000305175781250, 0.0021362304687500, -0.0001831054687500, +0.0023193359375000, 0.0000305175781250, 0.0021972656250000, -0.0002746582031250, +0.0018920898437500, -0.0007324218750000, 0.0020141601562500, -0.0004577636718750, +0.0016784667968750, -0.0008544921875000, 0.0016174316406250, -0.0009155273437500, +0.0013732910156250, -0.0005798339843750, 0.0011596679687500, -0.0004882812500000, +0.0014038085937500, -0.0004882812500000, 0.0005798339843750, 0.0000610351562500, +0.0009155273437500, 0.0003356933593750, 0.0007629394531250, 0.0004272460937500, +0.0000915527343750}, +{-0.0002136230468750, 0.0003662109375000, -0.0005187988281250, 0.0006103515625000, +0.0000610351562500, 0.0009765625000000, -0.0007019042968750, 0.0004577636718750, +-0.0004577636718750, 0.0009765625000000, -0.0004882812500000, 0.0009460449218750, +-0.0009765625000000, 0.0003967285156250, -0.0006713867187500, 0.0009155273437500, +-0.0011291503906250, 0.0006408691406250, -0.0010375976562500, 0.0004882812500000, +-0.0010681152343750, 0.0007934570312500, -0.0013427734375000, 0.0007629394531250, +-0.0012207031250000, 0.0004882812500000, -0.0012817382812500, 0.0012207031250000, +-0.0012817382812500, 0.0008850097656250, -0.0014038085937500, 0.0008239746093750, +-0.0013732910156250, 0.0013122558593750, -0.0013732910156250, 0.0008850097656250, +-0.0017089843750000, 0.0012817382812500, -0.0018615722656250, 0.0011596679687500, +-0.0018310546875000, 0.0010681152343750, -0.0021362304687500, 0.0012207031250000, +-0.0025329589843750, 0.0010070800781250, -0.0019836425781250, 0.0010375976562500, +-0.0025329589843750, 0.0008850097656250, -0.0023498535156250, 0.0007629394531250, +-0.0019531250000000, 0.0005798339843750, -0.0028381347656250, 0.0000915527343750, +-0.0016784667968750, 0.0002441406250000, -0.0025329589843750, -0.0002136230468750, +-0.0024414062500000, -0.0002746582031250, -0.0016479492187500, -0.0000610351562500, +-0.0026550292968750, -0.0007324218750000, -0.0012512207031250, -0.0002746582031250, +-0.0018615722656250, -0.0005493164062500, -0.0014648437500000, -0.0007324218750000, +-0.0001220703125000, -0.0005493164062500, -0.0011901855468750, -0.0009765625000000, +0.0002441406250000, -0.0008239746093750, 0.0004577636718750, -0.0010070800781250, +0.0000305175781250, -0.0010986328125000, 0.0007629394531250, -0.0008239746093750, +0.0012207031250000, -0.0006408691406250, 0.0006103515625000, -0.0003356933593750, +0.0008544921875000, -0.0005493164062500, 0.0008850097656250, -0.0006103515625000, +0.0004272460937500, -0.0004272460937500, 0.0005798339843750, -0.0006713867187500, +0.0003662109375000, -0.0003356933593750, 0.0003356933593750, -0.0003662109375000, +0.0000000000000000, -0.0003051757812500, -0.0003051757812500, 0.0000000000000000, +-0.0001220703125000, -0.0000305175781250, -0.0009765625000000, 0.0000000000000000, +-0.0007324218750000, 0.0002136230468750, -0.0006713867187500, 0.0000610351562500, +-0.0011291503906250, -0.0002136230468750, -0.0007629394531250, 0.0000305175781250, +-0.0005493164062500, -0.0000915527343750, -0.0008239746093750, -0.0001831054687500, +-0.0003051757812500, -0.0000610351562500, 0.0000610351562500, 0.0000000000000000, +-0.0005187988281250, -0.0000305175781250, 0.0008239746093750, 0.0000610351562500, +0.0004882812500000, 0.0002746582031250, 0.0007629394531250, 0.0000305175781250, +0.0018615722656250, -0.0001831054687500, 0.0013427734375000, 0.0001220703125000, +0.0019226074218750, -0.0003662109375000, 0.0022583007812500, -0.0002441406250000, +0.0021667480468750, -0.0000305175781250, 0.0021972656250000, -0.0000915527343750, +0.0023803710937500, 0.0000610351562500, 0.0022277832031250, 0.0003662109375000, +0.0021057128906250, 0.0005493164062500, 0.0021362304687500, 0.0005187988281250, +0.0021057128906250, 0.0005798339843750, 0.0017700195312500, 0.0007934570312500, +0.0018005371093750, 0.0001525878906250, 0.0018310546875000, 0.0003662109375000, +0.0013427734375000, 0.0000915527343750, 0.0012207031250000, -0.0005493164062500, +0.0014343261718750, -0.0001525878906250, 0.0003356933593750, -0.0006713867187500, +0.0008239746093750, -0.0006713867187500, 0.0005798339843750, -0.0005493164062500, +-0.0001831054687500, -0.0006408691406250, 0.0005493164062500, -0.0003356933593750, +-0.0001220703125000, -0.0004272460937500, -0.0001831054687500, -0.0000915527343750, +0.0001220703125000, -0.0001831054687500, -0.0001525878906250, -0.0004272460937500, +-0.0002746582031250, 0.0000915527343750, 0.0002746582031250, -0.0008850097656250, +-0.0002746582031250, -0.0005493164062500, 0.0001525878906250, -0.0006713867187500, +0.0007934570312500, -0.0013732910156250, -0.0002441406250000, -0.0007019042968750, +0.0012817382812500, -0.0011596679687500, 0.0008544921875000, -0.0009765625000000, +0.0008239746093750, -0.0005798339843750, 0.0018310546875000, -0.0005187988281250, +0.0011596679687500, -0.0001525878906250, 0.0016174316406250, 0.0001525878906250, +0.0017395019531250, 0.0004577636718750, 0.0015563964843750, 0.0006103515625000, +0.0016174316406250, 0.0007934570312500, 0.0016784667968750, 0.0009765625000000, +0.0013732910156250, 0.0007324218750000, 0.0013732910156250, 0.0008544921875000, +0.0011901855468750, 0.0007324218750000, 0.0007629394531250, 0.0003967285156250, +0.0007629394531250, 0.0004577636718750, 0.0005493164062500, -0.0001220703125000, +0.0001525878906250, -0.0001220703125000, 0.0000915527343750, -0.0003967285156250, +0.0000610351562500, -0.0009155273437500, -0.0003356933593750, -0.0006713867187500, +-0.0000915527343750, -0.0012207031250000, -0.0003051757812500, -0.0011291503906250, +-0.0003967285156250, -0.0010070800781250, -0.0002441406250000, -0.0012512207031250, +-0.0004882812500000, -0.0008850097656250, -0.0002441406250000, -0.0007324218750000, +-0.0003051757812500, -0.0007934570312500, -0.0003356933593750, -0.0005187988281250, +-0.0002746582031250, -0.0001831054687500, -0.0003356933593750, -0.0002136230468750, +-0.0002136230468750, 0.0002441406250000, -0.0003051757812500, 0.0002746582031250, +-0.0003356933593750, 0.0002746582031250, -0.0002746582031250, 0.0005187988281250, +-0.0004577636718750, 0.0004577636718750, -0.0002136230468750, 0.0004577636718750, +-0.0005798339843750, 0.0006103515625000, -0.0004272460937500, 0.0004882812500000, +-0.0002136230468750, 0.0004272460937500, -0.0007629394531250, 0.0004882812500000, +-0.0000305175781250, 0.0001220703125000, -0.0002746582031250, 0.0003967285156250, +-0.0003356933593750, 0.0002136230468750, 0.0000915527343750, -0.0000915527343750, +-0.0003662109375000, 0.0004577636718750, -0.0001220703125000, -0.0004272460937500, +-0.0002136230468750, 0.0000000000000000, -0.0003356933593750, -0.0000610351562500, +-0.0003051757812500, -0.0006103515625000, -0.0003662109375000, 0.0000610351562500, +-0.0001525878906250, -0.0005187988281250, -0.0002136230468750, -0.0002746582031250, +-0.0000610351562500, -0.0000915527343750, 0.0000915527343750, -0.0003967285156250, +-0.0000305175781250, 0.0000305175781250, 0.0003051757812500, -0.0000610351562500, +0.0002441406250000, 0.0000305175781250, 0.0004577636718750, 0.0001831054687500, +0.0006713867187500, 0.0003051757812500, 0.0004577636718750, 0.0005187988281250, +0.0010375976562500, 0.0003356933593750, 0.0006713867187500, 0.0007629394531250, +0.0007629394531250, 0.0005493164062500, 0.0011596679687500, 0.0002441406250000, +0.0003967285156250, 0.0007934570312500, 0.0010986328125000, -0.0003051757812500, +0.0006713867187500, 0.0001220703125000, 0.0005187988281250, -0.0001220703125000, +0.0008850097656250, -0.0010375976562500, 0.0003051757812500, -0.0003967285156250, +0.0005187988281250, -0.0011901855468750, 0.0003662109375000, -0.0012512207031250, +0.0001831054687500, -0.0011291503906250, 0.0003051757812500, -0.0014038085937500, +0.0002136230468750, -0.0012512207031250, 0.0003051757812500, -0.0009460449218750, +0.0005187988281250, -0.0010986328125000, 0.0005493164062500, -0.0007629394531250, +0.0006103515625000, -0.0003356933593750, 0.0009765625000000, -0.0005493164062500, +0.0006103515625000, 0.0000000000000000, 0.0008239746093750, 0.0000610351562500, +0.0006713867187500, -0.0001220703125000, 0.0003967285156250, 0.0000610351562500, +0.0007019042968750, 0.0000610351562500, -0.0000610351562500, -0.0003051757812500, +0.0005798339843750, -0.0002441406250000, 0.0000610351562500, -0.0002441406250000, +-0.0005798339843750, -0.0004272460937500, 0.0008544921875000, -0.0002746582031250, +-0.0012512207031250, -0.0002136230468750, -0.0002746582031250, -0.0000610351562500, +-0.0001831054687500, -0.0000305175781250, -0.0015869140625000, 0.0001525878906250, +-0.0001525878906250, 0.0003967285156250, -0.0009765625000000, 0.0000915527343750, +-0.0011596679687500, 0.0006408691406250, -0.0005187988281250, 0.0003051757812500, +-0.0007934570312500, -0.0000610351562500, -0.0012512207031250, 0.0007629394531250, +-0.0001220703125000, -0.0007324218750000, -0.0007934570312500, -0.0001525878906250, +-0.0007934570312500, -0.0004272460937500, 0.0000915527343750, -0.0016784667968750, +-0.0005798339843750, -0.0008239746093750, 0.0001831054687500, -0.0017089843750000, +0.0002441406250000, -0.0019531250000000, 0.0002441406250000, -0.0015563964843750, +0.0007629394531250, -0.0016784667968750, 0.0007934570312500, -0.0018615722656250, +0.0007324218750000, -0.0014038085937500, 0.0010986328125000, -0.0013427734375000, +0.0009765625000000, -0.0013732910156250, 0.0007629394531250, -0.0012512207031250, +0.0010986328125000, -0.0013427734375000, 0.0008544921875000, -0.0012207031250000, +0.0009155273437500, -0.0016479492187500, 0.0010681152343750, -0.0010070800781250, +0.0011901855468750, -0.0004577636718750, 0.0014648437500000, -0.0012817382812500, +0.0011901855468750, 0.0006103515625000, 0.0017395019531250, 0.0003967285156250, +0.0016174316406250, 0.0002136230468750, 0.0005493164062500, 0.0017700195312500, +0.0015258789062500, -0.0007324218750000, 0.0014648437500000, 0.0010986328125000, +0.0016174316406250, 0.0002136230468750, 0.0015258789062500, 0.0003356933593750, +0.0016174316406250, 0.0011291503906250, 0.0019531250000000, 0.0007324218750000, +0.0013122558593750, 0.0010070800781250, 0.0016174316406250, 0.0006408691406250, +0.0016479492187500, 0.0010375976562500, 0.0010375976562500, 0.0013427734375000, +0.0012207031250000, 0.0005798339843750, 0.0018005371093750, 0.0021667480468750, +0.0013427734375000, 0.0018005371093750, 0.0015258789062500, 0.0015258789062500, +0.0021057128906250, 0.0024108886718750, 0.0014648437500000, 0.0018920898437500, +0.0012207031250000, 0.0012207031250000, 0.0013732910156250, 0.0014648437500000, +0.0005798339843750, 0.0009155273437500, -0.0000915527343750, 0.0000915527343750, +0.0003051757812500, 0.0005187988281250, -0.0004272460937500, -0.0004272460937500, +-0.0006103515625000, -0.0001831054687500, -0.0002441406250000, -0.0002746582031250, +-0.0000305175781250, -0.0007629394531250, 0.0001525878906250, -0.0001525878906250, +0.0004882812500000, -0.0007629394531250, 0.0009765625000000, -0.0007934570312500, +0.0009460449218750, -0.0003662109375000, 0.0009460449218750, -0.0005798339843750, +0.0015258789062500, -0.0007934570312500, 0.0006103515625000, 0.0004272460937500, +0.0010681152343750, -0.0001220703125000, 0.0009460449218750, 0.0000610351562500, +0.0001525878906250, 0.0012207031250000, 0.0006103515625000, 0.0006408691406250, +0.0003356933593750, 0.0007934570312500, 0.0002746582031250, 0.0013122558593750, +0.0002441406250000, 0.0009460449218750, 0.0002441406250000, 0.0006713867187500, +0.0002441406250000, 0.0013427734375000, -0.0002136230468750, 0.0007019042968750, +-0.0002136230468750, 0.0012817382812500, -0.0005493164062500, 0.0014038085937500, +-0.0011291503906250, 0.0011291503906250, -0.0010375976562500, 0.0020446777343750, +-0.0018920898437500, 0.0011596679687500, -0.0020446777343750, 0.0014343261718750, +-0.0020446777343750, 0.0016174316406250, -0.0025329589843750, 0.0010986328125000, +-0.0025939941406250, 0.0013427734375000, -0.0016479492187500, 0.0015869140625000, +-0.0022583007812500, 0.0013427734375000, -0.0015258789062500, 0.0013732910156250, +-0.0003356933593750, 0.0016479492187500, -0.0011291503906250, 0.0014343261718750, +0.0005798339843750}, +{-0.0002746582031250, 0.0001525878906250, 0.0010681152343750, -0.0001831054687500, +0.0007629394531250, 0.0002441406250000, 0.0007629394531250, 0.0003356933593750, +0.0017700195312500, 0.0003051757812500, 0.0013732910156250, 0.0010070800781250, +0.0016784667968750, 0.0002746582031250, 0.0019836425781250, 0.0008239746093750, +0.0019531250000000, 0.0006713867187500, 0.0018920898437500, -0.0001831054687500, +0.0020751953125000, 0.0006103515625000, 0.0022888183593750, 0.0000305175781250, +0.0020751953125000, -0.0003662109375000, 0.0022888183593750, 0.0001220703125000, +0.0026245117187500, 0.0001831054687500, 0.0022888183593750, -0.0003967285156250, +0.0025939941406250, 0.0007324218750000, 0.0028076171875000, 0.0003967285156250, +0.0023193359375000, 0.0002136230468750, 0.0021667480468750, 0.0006408691406250, +0.0026245117187500, 0.0000610351562500, 0.0016479492187500, 0.0001525878906250, +0.0017700195312500, -0.0003051757812500, 0.0019531250000000, -0.0003051757812500, +0.0012817382812500, 0.0003356933593750, 0.0027160644531250, 0.0017395019531250, +0.0020751953125000, 0.0024108886718750, 0.0022583007812500, 0.0015258789062500, +0.0021972656250000, 0.0016784667968750, 0.0018615722656250, 0.0019531250000000, +0.0018310546875000, 0.0010681152343750, 0.0021362304687500, 0.0018005371093750, +0.0019836425781250, 0.0016479492187500, 0.0019531250000000, 0.0013122558593750, +0.0021667480468750, 0.0013732910156250, 0.0018615722656250, 0.0011291503906250, +0.0014953613281250, 0.0011291503906250, 0.0011901855468750, 0.0006713867187500, +0.0008239746093750, 0.0010375976562500, 0.0002136230468750, 0.0013122558593750, +-0.0001525878906250, 0.0005187988281250, 0.0000915527343750, 0.0020751953125000, +-0.0005493164062500, 0.0015563964843750, -0.0003051757812500, 0.0014038085937500, +0.0004882812500000, 0.0023193359375000, -0.0000305175781250, 0.0015563964843750, +0.0004577636718750, 0.0015563964843750, 0.0011901855468750, 0.0015258789062500, +0.0007629394531250, 0.0010681152343750, 0.0004577636718750, 0.0008544921875000, +0.0014343261718750, 0.0010375976562500, 0.0003051757812500, 0.0005187988281250, +0.0005187988281250, 0.0007934570312500, 0.0008239746093750, 0.0007019042968750, +0.0002746582031250, 0.0004272460937500, 0.0005493164062500, 0.0009765625000000, +0.0006408691406250, 0.0002441406250000, 0.0006713867187500, 0.0002136230468750, +0.0005493164062500, 0.0004882812500000, 0.0007324218750000, 0.0000305175781250, +0.0008544921875000, -0.0001831054687500, -0.0001220703125000, 0.0005798339843750, +0.0003662109375000, 0.0001831054687500, 0.0000000000000000, 0.0003051757812500, +-0.0010681152343750, 0.0010375976562500, -0.0003662109375000, 0.0006408691406250, +-0.0010070800781250, 0.0007629394531250, -0.0012512207031250, 0.0010375976562500, +-0.0007019042968750, 0.0008544921875000, -0.0007629394531250, 0.0008850097656250, +-0.0010375976562500, 0.0015258789062500, 0.0005798339843750, 0.0009460449218750, +-0.0000915527343750, 0.0017089843750000, 0.0004882812500000, 0.0016174316406250, +0.0020141601562500, 0.0010986328125000, 0.0008544921875000, 0.0020141601562500, +0.0021057128906250, 0.0010986328125000, 0.0023193359375000, 0.0011596679687500, +0.0018615722656250, 0.0015258789062500, 0.0021667480468750, 0.0010986328125000, +0.0022583007812500, 0.0010070800781250, 0.0013732910156250, 0.0014038085937500, +0.0016479492187500, 0.0011901855468750, 0.0014648437500000, 0.0009460449218750, +0.0008544921875000, 0.0010986328125000, 0.0014648437500000, 0.0008850097656250, +0.0008850097656250, 0.0004882812500000, 0.0009765625000000, 0.0006103515625000, +0.0013427734375000, 0.0004882812500000, 0.0011596679687500, 0.0002136230468750, +0.0012207031250000, 0.0003967285156250, 0.0017700195312500, 0.0002441406250000, +0.0016479492187500, 0.0003662109375000, 0.0018005371093750, 0.0004272460937500, +0.0021972656250000, 0.0002746582031250, 0.0019226074218750, 0.0003967285156250, +0.0024414062500000, 0.0005493164062500, 0.0023498535156250, 0.0002441406250000, +0.0022583007812500, 0.0003967285156250, 0.0025939941406250, 0.0006408691406250, +0.0024108886718750, 0.0001220703125000, 0.0022888183593750, 0.0005187988281250, +0.0024414062500000, 0.0003051757812500, 0.0022583007812500, 0.0001525878906250, +0.0021057128906250, 0.0002746582031250, 0.0023498535156250, 0.0000000000000000, +0.0020141601562500, 0.0000915527343750, 0.0021057128906250, -0.0001220703125000, +0.0022277832031250, -0.0001831054687500, 0.0020751953125000, -0.0001831054687500, +0.0022277832031250, -0.0004577636718750, 0.0023498535156250, -0.0001220703125000, +0.0022583007812500, -0.0004577636718750, 0.0024414062500000, -0.0004272460937500, +0.0026855468750000, -0.0001525878906250, 0.0025634765625000, -0.0007019042968750, +0.0030212402343750, -0.0002136230468750, 0.0029296875000000, -0.0004272460937500, +0.0031127929687500, -0.0005798339843750, 0.0034179687500000, -0.0003356933593750, +0.0032958984375000, -0.0005187988281250, 0.0037536621093750, -0.0006713867187500, +0.0036315917968750, -0.0006408691406250, 0.0038146972656250, -0.0007629394531250, +0.0041198730468750, -0.0009765625000000, 0.0038452148437500, -0.0008850097656250, +0.0043334960937500, -0.0009155273437500, 0.0042724609375000, -0.0010375976562500, +0.0043945312500000, -0.0008239746093750, 0.0048217773437500, -0.0006103515625000, +0.0046997070312500, -0.0007934570312500, 0.0050354003906250, -0.0001220703125000, +0.0051574707031250, -0.0003356933593750, 0.0052185058593750, -0.0000610351562500, +0.0054626464843750, 0.0006103515625000, 0.0056152343750000, 0.0001831054687500, +0.0056152343750000, 0.0008239746093750, 0.0058288574218750, 0.0009460449218750, +0.0056762695312500, 0.0008544921875000, 0.0055541992187500, 0.0010681152343750, +0.0059509277343750, 0.0011291503906250, 0.0051879882812500, 0.0010681152343750, +0.0054626464843750, 0.0010986328125000, 0.0050659179687500, 0.0010986328125000, +0.0043029785156250, 0.0009765625000000, 0.0047302246093750, 0.0009155273437500, +0.0037231445312500, 0.0006408691406250, 0.0036926269531250, 0.0005187988281250, +0.0035095214843750, 0.0003051757812500, 0.0029296875000000, 0.0000305175781250, +0.0031738281250000, -0.0000305175781250, 0.0025634765625000, -0.0001831054687500, +0.0026550292968750, -0.0001525878906250, 0.0025939941406250, -0.0002136230468750, +0.0022277832031250, -0.0002441406250000, 0.0024414062500000, 0.0000610351562500, +0.0023803710937500, -0.0003356933593750, 0.0023803710937500, 0.0001525878906250, +0.0026245117187500, 0.0001831054687500, 0.0027770996093750, -0.0000915527343750, +0.0028076171875000, 0.0007324218750000, 0.0030822753906250, 0.0000915527343750, +0.0031738281250000, 0.0004272460937500, 0.0031127929687500, 0.0007019042968750, +0.0030822753906250, 0.0003356933593750, 0.0031433105468750, 0.0005187988281250, +0.0028991699218750, 0.0008239746093750, 0.0026855468750000, 0.0006103515625000, +0.0027160644531250, 0.0007934570312500, 0.0024414062500000, 0.0010070800781250, +0.0020751953125000, 0.0006103515625000, 0.0025329589843750, 0.0012512207031250, +0.0018005371093750, 0.0009765625000000, 0.0020141601562500, 0.0010681152343750, +0.0025024414062500, 0.0015869140625000, 0.0014038085937500, 0.0011901855468750, +0.0025329589843750, 0.0015258789062500, 0.0021362304687500, 0.0017089843750000, +0.0015258789062500, 0.0014343261718750, 0.0018920898437500, 0.0013732910156250, +0.0015869140625000, 0.0016174316406250, 0.0009765625000000, 0.0011596679687500, +0.0011291503906250, 0.0011901855468750, 0.0007934570312500, 0.0010375976562500, +0.0002136230468750, 0.0006408691406250, 0.0007324218750000, 0.0007324218750000, +0.0001220703125000, 0.0004272460937500, 0.0002441406250000, 0.0003662109375000, +0.0003662109375000, 0.0002441406250000, 0.0002441406250000, 0.0000305175781250, +0.0007629394531250, 0.0001831054687500, 0.0003051757812500, -0.0002746582031250, +0.0003662109375000, -0.0003356933593750, 0.0003662109375000, -0.0002746582031250, +-0.0001220703125000, -0.0004577636718750, -0.0002441406250000, -0.0004577636718750, +-0.0003967285156250, -0.0003662109375000, -0.0009155273437500, -0.0003967285156250, +-0.0010375976562500, -0.0003662109375000, -0.0009460449218750, -0.0003662109375000, +-0.0013732910156250, -0.0004272460937500, -0.0014038085937500, -0.0003356933593750, +-0.0013732910156250, -0.0004577636718750, -0.0016784667968750, -0.0004577636718750, +-0.0018005371093750, -0.0003051757812500, -0.0014343261718750, -0.0002136230468750, +-0.0013732910156250, 0.0000915527343750, -0.0016174316406250, -0.0000305175781250, +-0.0013122558593750, 0.0000000000000000, -0.0010681152343750, 0.0002441406250000, +-0.0013427734375000, 0.0002441406250000, -0.0003662109375000, 0.0002746582031250, +-0.0005187988281250, 0.0003967285156250, -0.0000305175781250, 0.0003356933593750, +0.0007629394531250, 0.0003356933593750, 0.0002136230468750, 0.0006103515625000, +0.0016174316406250, 0.0002441406250000, 0.0012207031250000, 0.0006103515625000, +0.0013427734375000, 0.0004577636718750, 0.0022583007812500, 0.0001525878906250, +0.0016479492187500, 0.0007324218750000, 0.0015869140625000, 0.0002746582031250, +0.0021057128906250, 0.0006713867187500, 0.0014953613281250, 0.0007019042968750, +0.0009765625000000, 0.0004577636718750, 0.0016784667968750, 0.0009460449218750, +0.0006103515625000, 0.0003967285156250, 0.0008544921875000, 0.0007019042968750, +0.0009765625000000, 0.0005187988281250, 0.0004882812500000, 0.0000000000000000, +0.0009765625000000, 0.0004882812500000, 0.0006713867187500, -0.0003662109375000, +0.0007629394531250, -0.0004272460937500, 0.0008850097656250, -0.0004577636718750, +0.0007324218750000, -0.0008544921875000, 0.0008544921875000, -0.0007629394531250, +0.0009460449218750, -0.0007629394531250, 0.0009765625000000, -0.0007934570312500, +0.0012207031250000, -0.0007934570312500, 0.0014648437500000, -0.0006713867187500, +0.0013122558593750, -0.0004272460937500, 0.0018615722656250, -0.0008239746093750, +0.0015869140625000, -0.0004272460937500, 0.0016784667968750, -0.0005187988281250, +0.0019531250000000, -0.0009155273437500, 0.0014038085937500, -0.0003356933593750, +0.0019226074218750, -0.0007324218750000, 0.0015869140625000, -0.0004882812500000, +0.0014038085937500, -0.0003051757812500, 0.0017700195312500, -0.0003967285156250, +0.0013427734375000, 0.0000610351562500, 0.0011291503906250, 0.0000915527343750, +0.0013732910156250, 0.0004577636718750, 0.0008544921875000, 0.0006103515625000, +0.0003662109375000, 0.0007019042968750, 0.0007934570312500, 0.0010681152343750, +-0.0003051757812500, 0.0008239746093750, -0.0001220703125000, 0.0011901855468750, +-0.0001525878906250, 0.0011291503906250, -0.0008850097656250, 0.0008544921875000, +-0.0004577636718750, 0.0012817382812500, -0.0009155273437500, 0.0007019042968750, +-0.0009460449218750, 0.0008544921875000, -0.0007934570312500, 0.0009155273437500, +-0.0010375976562500, 0.0005493164062500, -0.0010681152343750, 0.0007324218750000, +-0.0004882812500000, 0.0009460449218750, -0.0008850097656250, 0.0007019042968750, +-0.0004272460937500, 0.0010070800781250, 0.0003051757812500, 0.0013732910156250, +-0.0003662109375000, 0.0010986328125000, 0.0008544921875000, 0.0016784667968750, +0.0007324218750000, 0.0017395019531250, 0.0006713867187500, 0.0015869140625000, +0.0014648437500000, 0.0018920898437500, 0.0012207031250000, 0.0019836425781250, +0.0010070800781250, 0.0016479492187500, 0.0014343261718750, 0.0020446777343750, +0.0010986328125000}, +{0.0008544921875000, -0.0001220703125000, 0.0005493164062500, -0.0000915527343750, +-0.0000610351562500, -0.0002136230468750, 0.0001831054687500, -0.0000915527343750, +0.0000915527343750, 0.0000000000000000, -0.0001220703125000, 0.0001220703125000, +0.0000000000000000, 0.0001831054687500, 0.0005798339843750, 0.0003662109375000, +0.0009155273437500, 0.0006713867187500, 0.0002746582031250, 0.0006713867187500, +0.0007019042968750, 0.0008239746093750, 0.0002441406250000, 0.0007934570312500, +-0.0007019042968750, 0.0008850097656250, -0.0000610351562500, 0.0011596679687500, +-0.0011291503906250, 0.0006408691406250, -0.0014343261718750, 0.0011901855468750, +-0.0010070800781250, 0.0010681152343750, -0.0013122558593750, 0.0005493164062500, +-0.0015258789062500, 0.0013732910156250, -0.0002746582031250, 0.0005798339843750, +-0.0009155273437500, 0.0009765625000000, -0.0002746582031250, 0.0011901855468750, +0.0009155273437500, 0.0009460449218750, -0.0001831054687500, 0.0016174316406250, +0.0015258789062500, 0.0010681152343750, 0.0015258789062500, 0.0016174316406250, +0.0013732910156250, 0.0013427734375000, 0.0022583007812500, 0.0007324218750000, +0.0022277832031250, 0.0015563964843750, 0.0018920898437500, 0.0002746582031250, +0.0023803710937500, 0.0005798339843750, 0.0021667480468750, 0.0006408691406250, +0.0016479492187500, -0.0001831054687500, 0.0021667480468750, 0.0003051757812500, +0.0014648437500000, 0.0001220703125000, 0.0016479492187500, 0.0002136230468750, +0.0015563964843750, 0.0003051757812500, 0.0011291503906250, 0.0004272460937500, +0.0015869140625000, 0.0007019042968750, 0.0007019042968750, 0.0003662109375000, +0.0010375976562500, 0.0006408691406250, 0.0008544921875000, 0.0006713867187500, +0.0002441406250000, 0.0004272460937500, 0.0008850097656250, 0.0007629394531250, +0.0004882812500000, 0.0005798339843750, 0.0003356933593750, 0.0007629394531250, +0.0007019042968750, 0.0008850097656250, 0.0006408691406250, 0.0009765625000000, +0.0002136230468750, 0.0013122558593750, 0.0010986328125000, 0.0010681152343750, +0.0005187988281250, 0.0016479492187500, 0.0007019042968750, 0.0016174316406250, +0.0014038085937500, 0.0013122558593750, 0.0003356933593750, 0.0021057128906250, +0.0014648437500000, 0.0013122558593750, 0.0010375976562500, 0.0017395019531250, +0.0008544921875000, 0.0018615722656250, 0.0014343261718750, 0.0013122558593750, +0.0008850097656250, 0.0018310546875000, 0.0007324218750000, 0.0014343261718750, +0.0009765625000000, 0.0016479492187500, 0.0005493164062500, 0.0017395019531250, +0.0001525878906250, 0.0015869140625000, 0.0005493164062500, 0.0019531250000000, +-0.0002136230468750, 0.0016784667968750, -0.0000915527343750, 0.0018920898437500, +-0.0000610351562500, 0.0019531250000000, -0.0005493164062500, 0.0018005371093750, +-0.0004272460937500, 0.0020446777343750, -0.0005187988281250, 0.0017089843750000, +-0.0006713867187500, 0.0018005371093750, -0.0005493164062500, 0.0015869140625000, +-0.0004577636718750, 0.0013122558593750, -0.0005798339843750, 0.0016174316406250, +-0.0002441406250000, 0.0008544921875000, -0.0003051757812500, 0.0012207031250000, +-0.0001525878906250, 0.0011291503906250, 0.0001831054687500, 0.0006713867187500, +0.0002136230468750, 0.0013427734375000, 0.0004272460937500, 0.0009155273437500, +0.0005798339843750, 0.0012207031250000, 0.0006103515625000, 0.0016174316406250, +0.0007019042968750, 0.0016174316406250, 0.0007629394531250, 0.0020751953125000, +0.0004882812500000, 0.0024414062500000, 0.0005798339843750, 0.0026550292968750, +0.0004272460937500, 0.0030517578125000, 0.0001220703125000, 0.0034484863281250, +0.0001831054687500, 0.0035400390625000, 0.0000000000000000, 0.0040283203125000, +-0.0002746582031250, 0.0041809082031250, -0.0002136230468750, 0.0043334960937500, +-0.0002441406250000, 0.0046386718750000, -0.0007019042968750, 0.0046081542968750, +-0.0001831054687500, 0.0048828125000000, -0.0005493164062500, 0.0050048828125000, +-0.0005798339843750, 0.0049133300781250, -0.0002136230468750, 0.0049133300781250, +-0.0006408691406250, 0.0049438476562500, -0.0003662109375000, 0.0046081542968750, +-0.0003356933593750, 0.0046997070312500, -0.0003662109375000, 0.0044250488281250, +-0.0002441406250000, 0.0040588378906250, -0.0002441406250000, 0.0041503906250000, +-0.0000305175781250, 0.0033569335937500, -0.0000305175781250, 0.0034790039062500, +0.0000915527343750, 0.0030212402343750, 0.0002746582031250, 0.0022888183593750, +0.0002136230468750, 0.0026550292968750, 0.0003662109375000, 0.0014038085937500, +0.0004577636718750, 0.0015258789062500, 0.0005187988281250, 0.0010681152343750, +0.0005493164062500, 0.0000915527343750, 0.0006103515625000, 0.0005493164062500, +0.0007934570312500, -0.0006713867187500, 0.0006103515625000, -0.0005187988281250, +0.0007629394531250, -0.0008239746093750, 0.0009460449218750, -0.0016479492187500, +0.0005493164062500, -0.0011291503906250, 0.0007629394531250, -0.0019226074218750, +0.0005493164062500, -0.0018920898437500, 0.0003356933593750, -0.0017700195312500, +0.0003967285156250, -0.0021362304687500, 0.0001220703125000, -0.0020446777343750, +0.0000610351562500, -0.0018310546875000, -0.0000305175781250, -0.0020446777343750, +-0.0000610351562500, -0.0018615722656250, 0.0000000000000000, -0.0016479492187500, +-0.0000610351562500, -0.0019226074218750, 0.0000305175781250, -0.0015258789062500, +0.0002746582031250, -0.0015258789062500, 0.0003051757812500, -0.0017089843750000, +0.0003662109375000, -0.0015563964843750, 0.0007019042968750, -0.0015258789062500, +0.0005798339843750, -0.0020446777343750, 0.0007324218750000, -0.0019226074218750, +0.0010070800781250, -0.0022583007812500, 0.0010986328125000, -0.0028381347656250, +0.0010986328125000, -0.0025939941406250, 0.0011291503906250, -0.0033874511718750, +0.0013427734375000, -0.0035705566406250, 0.0011291503906250, -0.0034484863281250, +0.0010681152343750, -0.0037536621093750, 0.0015869140625000, -0.0037231445312500, +0.0008239746093750, -0.0032653808593750, 0.0015563964843750, -0.0034179687500000, +0.0015869140625000, -0.0030212402343750, 0.0010681152343750, -0.0024108886718750, +0.0021362304687500, -0.0027770996093750, 0.0013732910156250, -0.0016479492187500, +0.0014953613281250, -0.0017395019531250, 0.0018615722656250, -0.0015869140625000, +0.0013427734375000, -0.0009155273437500, 0.0011291503906250, -0.0012207031250000, +0.0019836425781250, -0.0006408691406250, 0.0010070800781250, -0.0009155273437500, +0.0013732910156250, -0.0004577636718750, 0.0023803710937500, 0.0001831054687500, +0.0009765625000000, -0.0003967285156250, 0.0023498535156250, 0.0010070800781250, +0.0020751953125000, 0.0008239746093750, 0.0018920898437500, 0.0011901855468750, +0.0026550292968750, 0.0022277832031250, 0.0022888183593750, 0.0018005371093750, +0.0026550292968750, 0.0028686523437500, 0.0025939941406250, 0.0030517578125000, +0.0029296875000000, 0.0028991699218750, 0.0032653808593750, 0.0033874511718750, +0.0028076171875000, 0.0033874511718750, 0.0035705566406250, 0.0027160644531250, +0.0032958984375000, 0.0030517578125000, 0.0032348632812500, 0.0027160644531250, +0.0037231445312500, 0.0018005371093750, 0.0032653808593750, 0.0020751953125000, +0.0034179687500000, 0.0017089843750000, 0.0036621093750000, 0.0011596679687500, +0.0035705566406250, 0.0014343261718750, 0.0036926269531250, 0.0016784667968750, +0.0039978027343750, 0.0010681152343750, 0.0038757324218750, 0.0013732910156250, +0.0040588378906250, 0.0014038085937500, 0.0039672851562500, 0.0009765625000000, +0.0036621093750000, 0.0007324218750000, 0.0038146972656250, 0.0007019042968750, +0.0031127929687500, 0.0005187988281250, 0.0030517578125000, 0.0001220703125000, +0.0031127929687500, 0.0005798339843750, 0.0025939941406250, 0.0014953613281250, +0.0028686523437500, 0.0022277832031250, 0.0018310546875000, 0.0011291503906250, +0.0020446777343750, 0.0010681152343750, 0.0016784667968750, 0.0014038085937500, +0.0008544921875000, 0.0014343261718750, 0.0008544921875000, 0.0012512207031250, +0.0010681152343750, 0.0023498535156250, 0.0003967285156250, 0.0022888183593750, +0.0007019042968750, 0.0024414062500000, 0.0013122558593750, 0.0030212402343750, +0.0004882812500000, 0.0027770996093750, 0.0011901855468750, 0.0031127929687500, +0.0012817382812500, 0.0029296875000000, 0.0007629394531250, 0.0029602050781250, +0.0007019042968750, 0.0031433105468750, 0.0008239746093750, 0.0027160644531250, +0.0005187988281250, 0.0029602050781250, 0.0000915527343750, 0.0027160644531250, +0.0006103515625000, 0.0023498535156250, 0.0008239746093750, 0.0021972656250000, +0.0000915527343750, 0.0018615722656250, 0.0016174316406250, 0.0017395019531250, +0.0012817382812500, 0.0011901855468750, 0.0008544921875000, 0.0012817382812500, +0.0015563964843750, 0.0014038085937500, 0.0011901855468750, 0.0006408691406250, +0.0007324218750000, 0.0015563964843750, 0.0007934570312500, 0.0012817382812500, +0.0008239746093750, 0.0009155273437500, 0.0005493164062500, 0.0012207031250000, +0.0006713867187500, 0.0008239746093750, 0.0015869140625000, 0.0007934570312500, +0.0012817382812500, 0.0006713867187500, 0.0021972656250000, 0.0007019042968750, +0.0034484863281250, 0.0008544921875000, 0.0028381347656250, 0.0008239746093750, +0.0041809082031250, 0.0011596679687500, 0.0045471191406250, 0.0012817382812500, +0.0041809082031250, 0.0012512207031250, 0.0043945312500000, 0.0012817382812500, +0.0045776367187500, 0.0012207031250000, 0.0036315917968750, 0.0011596679687500, +0.0038146972656250, 0.0008850097656250, 0.0035400390625000, 0.0009155273437500, +0.0027465820312500, 0.0008850097656250, 0.0032043457031250, 0.0005493164062500, +0.0029296875000000, 0.0007019042968750, 0.0026245117187500, 0.0005798339843750, +0.0031433105468750, 0.0003356933593750, 0.0035095214843750, 0.0004272460937500, +0.0030822753906250, 0.0004577636718750, 0.0041503906250000, 0.0000610351562500, +0.0040893554687500, 0.0003662109375000, 0.0040283203125000, 0.0003967285156250, +0.0045471191406250, 0.0001831054687500, 0.0043334960937500, 0.0007934570312500, +0.0039978027343750, 0.0003967285156250, 0.0041503906250000, 0.0007324218750000, +0.0036926269531250, 0.0009155273437500, 0.0032653808593750, 0.0006713867187500, +0.0035095214843750, 0.0009765625000000, 0.0025939941406250, 0.0010375976562500, +0.0026245117187500, 0.0009155273437500, 0.0025939941406250, 0.0010375976562500, +0.0020141601562500, 0.0011291503906250, 0.0023498535156250, 0.0009155273437500, +0.0025024414062500, 0.0009765625000000, 0.0023498535156250, 0.0009765625000000, +0.0028076171875000, 0.0007934570312500, 0.0033569335937500, 0.0006408691406250, +0.0032043457031250, 0.0006408691406250, 0.0042114257812500, 0.0006408691406250, +0.0041809082031250, 0.0004882812500000, 0.0046386718750000, 0.0005493164062500, +0.0054321289062500, 0.0006713867187500, 0.0050659179687500, 0.0004577636718750, +0.0058288574218750, 0.0007019042968750, 0.0059814453125000, 0.0004272460937500, +0.0058898925781250, 0.0004577636718750, 0.0061950683593750, 0.0005798339843750, +0.0062255859375000, 0.0000305175781250, 0.0057373046875000, 0.0005187988281250, +0.0060424804687500, 0.0001220703125000, 0.0056457519531250, -0.0000915527343750, +0.0050048828125000, 0.0002136230468750, 0.0054931640625000, -0.0002136230468750, +0.0041809082031250, -0.0001525878906250, 0.0045166015625000, -0.0002746582031250, +0.0040283203125000, -0.0004577636718750, 0.0028991699218750, -0.0005493164062500, +0.0036926269531250}, +{0.0003967285156250, 0.0016784667968750, -0.0001525878906250, 0.0020446777343750, +0.0003051757812500, 0.0021362304687500, -0.0004577636718750, 0.0022888183593750, +-0.0000610351562500, 0.0023498535156250, 0.0008239746093750, 0.0021667480468750, +-0.0001220703125000, 0.0024414062500000, 0.0013427734375000, 0.0026245117187500, +0.0012817382812500, 0.0023193359375000, 0.0011291503906250, 0.0026550292968750, +0.0016784667968750, 0.0030212402343750, 0.0013122558593750, 0.0023803710937500, +0.0014343261718750, 0.0030212402343750, 0.0009155273437500, 0.0027465820312500, +0.0014038085937500, 0.0023193359375000, 0.0018310546875000, 0.0023498535156250, +0.0008544921875000, 0.0018615722656250, 0.0030517578125000, 0.0016784667968750, +0.0024108886718750, 0.0012207031250000, 0.0026550292968750, 0.0011291503906250, +0.0042724609375000, 0.0011596679687500, 0.0033874511718750, 0.0007019042968750, +0.0039672851562500, 0.0009155273437500, 0.0043334960937500, 0.0008544921875000, +0.0035095214843750, 0.0005798339843750, 0.0031433105468750, 0.0005187988281250, +0.0036926269531250, 0.0005187988281250, 0.0021362304687500, 0.0003051757812500, +0.0021362304687500, 0.0002441406250000, 0.0022888183593750, 0.0004882812500000, +0.0014953613281250, 0.0005187988281250, 0.0017395019531250, 0.0004882812500000, +0.0020446777343750, 0.0009155273437500, 0.0016784667968750, 0.0006713867187500, +0.0019836425781250, 0.0007324218750000, 0.0025024414062500, 0.0009460449218750, +0.0021057128906250, 0.0004882812500000, 0.0024108886718750, 0.0009460449218750, +0.0027160644531250, 0.0006408691406250, 0.0020141601562500, 0.0005493164062500, +0.0017395019531250, 0.0008850097656250, 0.0023498535156250, 0.0004272460937500, +0.0005493164062500, 0.0004577636718750, 0.0008544921875000, 0.0006103515625000, +0.0005798339843750, 0.0003356933593750, -0.0007629394531250, 0.0001525878906250, +-0.0001220703125000, 0.0004882812500000, -0.0007019042968750, 0.0000915527343750, +-0.0010986328125000, 0.0003051757812500, -0.0006103515625000, 0.0004577636718750, +-0.0004577636718750, 0.0003967285156250, -0.0007934570312500, 0.0006408691406250, +0.0007629394531250, 0.0006713867187500, 0.0003662109375000, 0.0007019042968750, +0.0009765625000000, 0.0008544921875000, 0.0024414062500000, 0.0009460449218750, +0.0017395019531250, 0.0008544921875000, 0.0030212402343750, 0.0010375976562500, +0.0033264160156250, 0.0010375976562500, 0.0030822753906250, 0.0009765625000000, +0.0036315917968750, 0.0009765625000000, 0.0037536621093750, 0.0009460449218750, +0.0032348632812500, 0.0007629394531250, 0.0037841796875000, 0.0006408691406250, +0.0031433105468750, 0.0006408691406250, 0.0024108886718750, 0.0005187988281250, +0.0033569335937500, 0.0004272460937500, 0.0013122558593750, 0.0006713867187500, +0.0018920898437500, 0.0004882812500000, 0.0015563964843750, 0.0005493164062500, +0.0001525878906250, 0.0007629394531250, 0.0010986328125000, 0.0004577636718750, +-0.0004272460937500, 0.0006103515625000, -0.0003662109375000, 0.0004272460937500, +-0.0003356933593750, 0.0002441406250000, -0.0011901855468750, 0.0002441406250000, +-0.0008850097656250, 0.0000915527343750, -0.0009460449218750, -0.0000915527343750, +-0.0010681152343750, -0.0000305175781250, -0.0007324218750000, -0.0001831054687500, +-0.0005493164062500, -0.0004272460937500, -0.0007629394531250, -0.0002746582031250, +-0.0000610351562500, -0.0005798339843750, -0.0001525878906250, -0.0005798339843750, +0.0000915527343750, -0.0004882812500000, 0.0006408691406250, -0.0005798339843750, +0.0004577636718750, -0.0004882812500000, 0.0010681152343750, -0.0002746582031250, +0.0010681152343750, -0.0003051757812500, 0.0011596679687500, -0.0001831054687500, +0.0014953613281250, 0.0000610351562500, 0.0013427734375000, 0.0000000000000000, +0.0017089843750000, 0.0001220703125000, 0.0016479492187500, 0.0001831054687500, +0.0017089843750000, 0.0001525878906250, 0.0019226074218750, 0.0001220703125000, +0.0018005371093750, 0.0002441406250000, 0.0020141601562500, 0.0001525878906250, +0.0020446777343750, 0.0001220703125000, 0.0020446777343750, 0.0001831054687500, +0.0020751953125000, 0.0001220703125000, 0.0020141601562500, -0.0000915527343750, +0.0022583007812500, -0.0000305175781250, 0.0020141601562500, -0.0002746582031250, +0.0021057128906250, -0.0002746582031250, 0.0023498535156250, -0.0002136230468750, +0.0019531250000000, -0.0003967285156250, 0.0024108886718750, -0.0001220703125000, +0.0023498535156250, -0.0001831054687500, 0.0023193359375000, -0.0001220703125000, +0.0025939941406250, 0.0001220703125000, 0.0024108886718750, 0.0000610351562500, +0.0025939941406250, 0.0001831054687500, 0.0025634765625000, 0.0003051757812500, +0.0025024414062500, 0.0002136230468750, 0.0026245117187500, 0.0002746582031250, +0.0025024414062500, 0.0005187988281250, 0.0025634765625000, 0.0003356933593750, +0.0025329589843750, 0.0003967285156250, 0.0024414062500000, 0.0004577636718750, +0.0024719238281250, 0.0002746582031250, 0.0025024414062500, 0.0001831054687500, +0.0023803710937500, 0.0005187988281250, 0.0024108886718750, 0.0000305175781250, +0.0024108886718750, 0.0001831054687500, 0.0022888183593750, 0.0005493164062500, +0.0022888183593750, -0.0001220703125000, 0.0024719238281250, 0.0007324218750000, +0.0023193359375000, 0.0004577636718750, 0.0024108886718750, 0.0005493164062500, +0.0026550292968750, 0.0011291503906250, 0.0025329589843750, 0.0007324218750000, +0.0027160644531250, 0.0012207031250000, 0.0027465820312500, 0.0014343261718750, +0.0027160644531250, 0.0013427734375000, 0.0027160644531250, 0.0014953613281250, +0.0026855468750000, 0.0017700195312500, 0.0025024414062500, 0.0014648437500000, +0.0024108886718750, 0.0017089843750000, 0.0021362304687500, 0.0017700195312500, +0.0018310546875000, 0.0015258789062500, 0.0018615722656250, 0.0017089843750000, +0.0016174316406250, 0.0014038085937500, 0.0013122558593750, 0.0014648437500000, +0.0015563964843750, 0.0013732910156250, 0.0016784667968750, 0.0011291503906250, +0.0009460449218750, 0.0011596679687500, 0.0011596679687500, 0.0009765625000000, +0.0009460449218750, 0.0010070800781250, 0.0004577636718750, 0.0008850097656250, +0.0002441406250000, 0.0007019042968750, 0.0001220703125000, 0.0009460449218750, +-0.0004272460937500, 0.0005798339843750, -0.0005493164062500, 0.0005798339843750, +-0.0006713867187500, 0.0006713867187500, -0.0007934570312500, 0.0005187988281250, +-0.0005493164062500, 0.0005187988281250, -0.0004272460937500, 0.0004882812500000, +-0.0003051757812500, 0.0005187988281250, 0.0000305175781250, 0.0005798339843750, +0.0003662109375000, 0.0006408691406250, 0.0006103515625000, 0.0006713867187500, +0.0010681152343750, 0.0008239746093750, 0.0011901855468750, 0.0008850097656250, +0.0017089843750000, 0.0010681152343750, 0.0020446777343750, 0.0013732910156250, +0.0017395019531250, 0.0013122558593750, 0.0025329589843750, 0.0016784667968750, +0.0022888183593750, 0.0020446777343750, 0.0022583007812500, 0.0018920898437500, +0.0026550292968750, 0.0018920898437500, 0.0021057128906250, 0.0022888183593750, +0.0022888183593750, 0.0016479492187500, 0.0021057128906250, 0.0021057128906250, +0.0020446777343750, 0.0021057128906250, 0.0019531250000000, 0.0017089843750000, +0.0015258789062500, 0.0022583007812500, 0.0019836425781250, 0.0017700195312500, +0.0017089843750000, 0.0020446777343750, 0.0015258789062500, 0.0020446777343750, +0.0019836425781250, 0.0017395019531250, 0.0018005371093750, 0.0021362304687500, +0.0011596679687500, 0.0014343261718750, 0.0016479492187500, 0.0018310546875000, +0.0010070800781250, 0.0017395019531250, 0.0001220703125000, 0.0010375976562500, +0.0008850097656250, 0.0015563964843750, -0.0003051757812500, 0.0011291503906250, +-0.0004272460937500, 0.0010986328125000, -0.0003356933593750, 0.0012817382812500, +-0.0010070800781250, 0.0011291503906250, -0.0011596679687500, 0.0010375976562500, +-0.0008850097656250, 0.0014038085937500, -0.0014038085937500, 0.0012207031250000, +-0.0010986328125000, 0.0013122558593750, -0.0006103515625000, 0.0015563964843750, +-0.0012512207031250, 0.0012817382812500, 0.0001831054687500, 0.0017395019531250, +-0.0000610351562500, 0.0016174316406250, 0.0001831054687500, 0.0016479492187500, +0.0011901855468750, 0.0019836425781250, 0.0007324218750000, 0.0018310546875000, +0.0013732910156250, 0.0017395019531250, 0.0014648437500000, 0.0018310546875000, +0.0013122558593750, 0.0017700195312500, 0.0015258789062500, 0.0015258789062500, +0.0014343261718750, 0.0015258789062500, 0.0012817382812500, 0.0016174316406250, +0.0015258789062500, 0.0014038085937500, 0.0012512207031250, 0.0014953613281250, +0.0010070800781250, 0.0016479492187500, 0.0014648437500000, 0.0013732910156250, +0.0004882812500000, 0.0015258789062500, 0.0009155273437500, 0.0015869140625000, +0.0007934570312500, 0.0012817382812500, -0.0000915527343750, 0.0011291503906250, +0.0003967285156250, 0.0013427734375000, -0.0000915527343750, 0.0005187988281250, +-0.0003662109375000, 0.0007324218750000, -0.0000915527343750, 0.0004882812500000, +-0.0003051757812500, -0.0003051757812500, -0.0006408691406250, 0.0000610351562500, +0.0001525878906250, -0.0004882812500000, -0.0003356933593750, -0.0005493164062500, +-0.0001220703125000, -0.0004882812500000, 0.0005493164062500, -0.0006103515625000, +-0.0002136230468750, -0.0005187988281250, 0.0007019042968750, -0.0003967285156250, +0.0005493164062500, -0.0003051757812500, 0.0004272460937500, -0.0002441406250000, +0.0010070800781250, -0.0000610351562500, 0.0007324218750000, 0.0001220703125000, +0.0005187988281250, 0.0001525878906250, 0.0007629394531250, 0.0004882812500000, +0.0004577636718750, 0.0005493164062500, -0.0000305175781250, 0.0004882812500000, +0.0003051757812500, 0.0009460449218750, -0.0003662109375000, 0.0004882812500000, +-0.0003967285156250, 0.0007629394531250, -0.0003051757812500, 0.0007934570312500, +-0.0006408691406250, 0.0004577636718750, -0.0006103515625000, 0.0008544921875000, +-0.0005798339843750, 0.0004577636718750, -0.0008239746093750, 0.0005187988281250, +-0.0006408691406250, 0.0005187988281250, -0.0004882812500000, 0.0003051757812500, +-0.0007019042968750, 0.0004272460937500, -0.0000610351562500, 0.0003356933593750, +-0.0002441406250000, 0.0002746582031250, -0.0001220703125000, 0.0002136230468750, +0.0004272460937500, 0.0001831054687500, 0.0003051757812500, 0.0002441406250000, +0.0004882812500000, 0.0001220703125000, 0.0008239746093750, 0.0001525878906250, +0.0006713867187500, 0.0001831054687500, 0.0006103515625000, 0.0001220703125000, +0.0011291503906250, 0.0001525878906250, 0.0003662109375000, 0.0004577636718750, +0.0007629394531250, 0.0003051757812500, 0.0007019042968750, 0.0005187988281250, +0.0001220703125000, 0.0008850097656250, 0.0006713867187500, 0.0006103515625000, +0.0001831054687500, 0.0014648437500000, 0.0001220703125000, 0.0012207031250000, +0.0002136230468750, 0.0015563964843750, 0.0000305175781250, 0.0021667480468750, +0.0000305175781250, 0.0017395019531250, 0.0001525878906250, 0.0028076171875000, +0.0001220703125000, 0.0026855468750000, 0.0002441406250000, 0.0028381347656250, +0.0003356933593750, 0.0035400390625000, 0.0003356933593750, 0.0032043457031250, +0.0006103515625000, 0.0036926269531250, 0.0004272460937500, 0.0038146972656250, +0.0005798339843750, 0.0036926269531250, 0.0007934570312500, 0.0038757324218750, +0.0004577636718750, 0.0040588378906250, 0.0006408691406250, 0.0037841796875000, +0.0005798339843750}, +{-0.0015563964843750, 0.0010681152343750, -0.0019226074218750, 0.0009765625000000, +-0.0013732910156250, 0.0009460449218750, -0.0012512207031250, 0.0009460449218750, +-0.0017395019531250, 0.0006713867187500, -0.0001525878906250, 0.0009460449218750, +-0.0005798339843750, 0.0006408691406250, -0.0001831054687500, 0.0006713867187500, +0.0010681152343750, 0.0010070800781250, 0.0002746582031250, 0.0005493164062500, +0.0012817382812500, 0.0008239746093750, 0.0013732910156250, 0.0006103515625000, +0.0011901855468750, 0.0003662109375000, 0.0016479492187500, 0.0003051757812500, +0.0016479492187500, 0.0000610351562500, 0.0013732910156250, -0.0001831054687500, +0.0018005371093750, -0.0004272460937500, 0.0014343261718750, -0.0005493164062500, +0.0010375976562500, -0.0007019042968750, 0.0017700195312500, -0.0009155273437500, +0.0005493164062500, -0.0006103515625000, 0.0010070800781250, -0.0008850097656250, +0.0009765625000000, -0.0007019042968750, 0.0001220703125000, -0.0002136230468750, +0.0006713867187500, -0.0004882812500000, 0.0001525878906250, 0.0000610351562500, +-0.0000610351562500, 0.0002136230468750, 0.0001525878906250, 0.0002136230468750, +0.0000000000000000, 0.0004882812500000, -0.0002136230468750, 0.0005493164062500, +0.0000610351562500, 0.0006103515625000, -0.0000610351562500, 0.0007934570312500, +-0.0001831054687500, 0.0009155273437500, 0.0000000000000000, 0.0009765625000000, +0.0000305175781250, 0.0010375976562500, -0.0000610351562500, 0.0011901855468750, +0.0001525878906250, 0.0011901855468750, 0.0001220703125000, 0.0012207031250000, +0.0000610351562500, 0.0013427734375000, 0.0003967285156250, 0.0012817382812500, +0.0000000000000000, 0.0013122558593750, 0.0001220703125000, 0.0014343261718750, +0.0001831054687500, 0.0012817382812500, -0.0001220703125000, 0.0011596679687500, +-0.0000915527343750, 0.0012817382812500, -0.0000610351562500, 0.0008239746093750, +-0.0003051757812500, 0.0008544921875000, -0.0002746582031250, 0.0005493164062500, +-0.0001220703125000, 0.0001525878906250, -0.0003356933593750, 0.0002746582031250, +-0.0001525878906250, -0.0003662109375000, -0.0000915527343750, -0.0003662109375000, +-0.0000610351562500, -0.0005187988281250, 0.0000610351562500, -0.0009765625000000, +0.0002136230468750, -0.0009155273437500, 0.0002441406250000, -0.0009155273437500, +0.0003967285156250, -0.0011596679687500, 0.0004577636718750, -0.0008850097656250, +0.0005798339843750, -0.0006408691406250, 0.0007629394531250, -0.0008544921875000, +0.0005798339843750, 0.0000915527343750, 0.0008850097656250, -0.0000305175781250, +0.0008239746093750, 0.0004882812500000, 0.0006408691406250, 0.0014038085937500, +0.0010375976562500, 0.0010070800781250, 0.0004882812500000, 0.0025329589843750, +0.0007324218750000, 0.0023193359375000, 0.0007019042968750, 0.0028076171875000, +0.0004272460937500, 0.0039672851562500, 0.0007324218750000, 0.0033874511718750, +0.0005798339843750, 0.0049133300781250, 0.0004577636718750, 0.0047607421875000, +0.0006408691406250, 0.0049438476562500, 0.0006408691406250, 0.0058593750000000, +0.0004577636718750, 0.0054016113281250, 0.0007019042968750, 0.0060424804687500, +0.0005493164062500, 0.0061645507812500, 0.0003662109375000, 0.0059509277343750, +0.0004272460937500, 0.0061645507812500, 0.0003356933593750, 0.0062561035156250, +0.0002441406250000, 0.0057067871093750, 0.0002746582031250, 0.0060119628906250, +0.0002441406250000, 0.0055847167968750, 0.0002746582031250, 0.0049438476562500, +0.0004272460937500, 0.0053710937500000, 0.0003356933593750, 0.0040893554687500, +0.0005187988281250, 0.0043945312500000, 0.0006103515625000, 0.0038757324218750, +0.0006713867187500, 0.0028381347656250, 0.0010070800781250, 0.0036010742187500, +0.0009155273437500, 0.0021972656250000, 0.0012512207031250, 0.0024414062500000, +0.0013122558593750, 0.0023193359375000, 0.0011596679687500, 0.0014648437500000, +0.0015563964843750, 0.0020141601562500, 0.0011291503906250, 0.0014038085937500, +0.0013732910156250, 0.0014038085937500, 0.0012817382812500, 0.0015563964843750, +0.0009765625000000, 0.0013732910156250, 0.0014648437500000, 0.0015563964843750, +0.0005493164062500, 0.0016479492187500, 0.0011901855468750, 0.0017395019531250, +0.0009765625000000, 0.0017700195312500, 0.0003356933593750, 0.0018920898437500, +0.0014953613281250, 0.0019531250000000, 0.0003662109375000, 0.0016784667968750, +0.0007019042968750, 0.0019836425781250, 0.0010986328125000, 0.0017089843750000, +0.0005187988281250, 0.0013427734375000, 0.0008239746093750, 0.0018005371093750, +0.0013122558593750, 0.0007629394531250, 0.0005798339843750, 0.0011291503906250, +0.0010070800781250, 0.0009155273437500, 0.0015563964843750, 0.0001525878906250, +0.0004272460937500, 0.0007934570312500, 0.0018615722656250, 0.0002746582031250, +0.0012207031250000, 0.0003967285156250, 0.0012512207031250, 0.0007019042968750, +0.0023193359375000, 0.0006713867187500, 0.0014648437500000, 0.0009155273437500, +0.0024414062500000, 0.0009460449218750, 0.0024719238281250, 0.0010375976562500, +0.0023498535156250, 0.0011596679687500, 0.0027770996093750, 0.0010986328125000, +0.0025634765625000, 0.0010986328125000, 0.0028686523437500, 0.0014038085937500, +0.0026550292968750, 0.0009460449218750, 0.0027770996093750, 0.0012817382812500, +0.0030822753906250, 0.0016784667968750, 0.0026550292968750, 0.0009765625000000, +0.0030822753906250, 0.0022888183593750, 0.0032043457031250, 0.0016174316406250, +0.0026855468750000, 0.0019226074218750, 0.0026855468750000, 0.0030517578125000, +0.0031127929687500, 0.0019226074218750, 0.0022277832031250, 0.0035705566406250, +0.0025024414062500, 0.0031738281250000, 0.0024108886718750, 0.0028686523437500, +0.0018005371093750, 0.0037536621093750, 0.0021972656250000, 0.0030822753906250, +0.0017395019531250, 0.0025024414062500, 0.0017395019531250, 0.0026550292968750, +0.0016174316406250, 0.0020446777343750, 0.0013732910156250, 0.0011596679687500, +0.0014953613281250, 0.0014038085937500, 0.0010070800781250, 0.0008544921875000, +0.0011596679687500, 0.0007324218750000, 0.0011596679687500, 0.0007629394531250, +0.0007934570312500, 0.0006713867187500, 0.0010681152343750, 0.0007324218750000, +0.0010986328125000, 0.0003967285156250, 0.0009155273437500, 0.0004577636718750, +0.0010681152343750, 0.0006103515625000, 0.0013427734375000, 0.0005493164062500, +-0.0005187988281250, 0.0012207031250000, -0.0002441406250000, -0.0001525878906250, +-0.0006103515625000, 0.0004272460937500, -0.0002136230468750, 0.0003967285156250, +0.0002441406250000, -0.0003051757812500, -0.0000915527343750, -0.0000305175781250, +0.0007019042968750, 0.0009460449218750, 0.0009765625000000, 0.0005187988281250, +0.0007934570312500, 0.0013122558593750, 0.0009765625000000, 0.0027160644531250, +0.0012207031250000, 0.0021972656250000, 0.0007629394531250, 0.0032043457031250, +0.0007934570312500, 0.0038146972656250, 0.0012512207031250, 0.0034484863281250, +0.0011901855468750, 0.0035095214843750, 0.0009155273437500, 0.0038452148437500, +0.0020446777343750, 0.0030517578125000, 0.0018615722656250, 0.0032043457031250, +0.0015869140625000, 0.0028991699218750, 0.0021972656250000, 0.0023193359375000, +0.0021362304687500, 0.0027160644531250, 0.0007019042968750, 0.0014953613281250, +0.0013427734375000, 0.0017395019531250, 0.0007019042968750, 0.0015869140625000, +-0.0007934570312500, 0.0006103515625000, 0.0000305175781250, 0.0010681152343750, +-0.0007629394531250, 0.0010375976562500, -0.0011901855468750, 0.0005798339843750, +-0.0006103515625000, 0.0011291503906250, -0.0004577636718750, 0.0016784667968750, +-0.0009765625000000, 0.0010986328125000, 0.0001525878906250, 0.0020141601562500, +-0.0001525878906250, 0.0018920898437500, -0.0004272460937500, 0.0015869140625000, +0.0000305175781250, 0.0017089843750000, -0.0004272460937500, 0.0013427734375000, +-0.0012207031250000, 0.0010375976562500, -0.0011291503906250, 0.0007934570312500, +-0.0016174316406250, 0.0006103515625000, -0.0024108886718750, 0.0005493164062500, +-0.0021057128906250, 0.0003356933593750, -0.0025634765625000, 0.0003356933593750, +-0.0026245117187500, 0.0003662109375000, -0.0022583007812500, 0.0002136230468750, +-0.0022277832031250, 0.0001220703125000, -0.0021362304687500, 0.0002441406250000, +-0.0010070800781250, 0.0001220703125000, -0.0012512207031250, -0.0001220703125000, +-0.0006103515625000, 0.0000915527343750, 0.0004882812500000, 0.0000915527343750, +0.0000000000000000, -0.0003967285156250, 0.0012512207031250, 0.0002136230468750, +0.0014038085937500, -0.0002746582031250, 0.0013732910156250, -0.0002136230468750, +0.0020751953125000, 0.0002136230468750, 0.0020141601562500, -0.0004577636718750, +0.0017700195312500, 0.0000610351562500, 0.0022888183593750, 0.0000915527343750, +0.0019226074218750, -0.0001525878906250, 0.0013427734375000, 0.0002136230468750, +0.0019226074218750, 0.0002746582031250, 0.0009765625000000, -0.0000610351562500, +0.0009460449218750, 0.0002441406250000, 0.0011291503906250, 0.0001220703125000, +0.0007019042968750, -0.0002441406250000, 0.0005798339843750, 0.0001831054687500, +0.0010681152343750, -0.0000610351562500, 0.0004882812500000, -0.0001220703125000, +0.0009155273437500, 0.0000915527343750, 0.0014953613281250, 0.0001220703125000, +0.0007629394531250, 0.0000610351562500, 0.0021057128906250, 0.0003051757812500, +0.0016479492187500, 0.0002441406250000, 0.0019226074218750, 0.0001831054687500, +0.0028991699218750, 0.0003967285156250, 0.0021057128906250, 0.0003967285156250, +0.0033569335937500, 0.0001525878906250, 0.0030822753906250, 0.0004882812500000, +0.0030822753906250, 0.0003662109375000, 0.0038146972656250, 0.0000610351562500, +0.0032958984375000, 0.0006103515625000, 0.0035095214843750, 0.0000610351562500, +0.0036621093750000, 0.0002441406250000, 0.0032043457031250, 0.0004272460937500, +0.0030517578125000, 0.0002136230468750, 0.0031738281250000, 0.0005187988281250, +0.0021362304687500, 0.0005187988281250, 0.0023803710937500, 0.0005798339843750, +0.0020141601562500, 0.0007019042968750, 0.0011901855468750, 0.0007019042968750, +0.0017395019531250, 0.0007934570312500, 0.0008239746093750, 0.0007934570312500, +0.0009765625000000, 0.0008544921875000, 0.0009460449218750, 0.0008239746093750, +0.0003662109375000, 0.0008239746093750, 0.0008239746093750, 0.0008850097656250, +0.0003051757812500, 0.0007629394531250, 0.0004882812500000, 0.0007934570312500, +0.0005798339843750, 0.0007324218750000, 0.0003967285156250, 0.0005493164062500, +0.0007019042968750, 0.0005798339843750, 0.0007629394531250, 0.0004272460937500, +0.0008239746093750, 0.0002746582031250, 0.0010986328125000, 0.0002136230468750, +0.0013427734375000, 0.0001525878906250, 0.0014038085937500, 0.0000305175781250, +0.0019531250000000, -0.0000610351562500, 0.0020141601562500, -0.0000915527343750, +0.0023193359375000, -0.0002136230468750, 0.0028381347656250, -0.0002441406250000, +0.0028991699218750, -0.0002136230468750, 0.0032348632812500, -0.0002746582031250, +0.0035095214843750, -0.0003356933593750, 0.0035400390625000, -0.0002441406250000, +0.0036621093750000, -0.0002136230468750, 0.0038757324218750, -0.0003662109375000, +0.0037841796875000, -0.0000915527343750, 0.0039062500000000, -0.0002136230468750, +0.0038757324218750, -0.0001220703125000, 0.0036621093750000, -0.0000610351562500, +0.0038452148437500, -0.0002441406250000, 0.0034790039062500, 0.0000915527343750, +0.0035400390625000, -0.0001831054687500, 0.0034484863281250, -0.0000610351562500, +0.0031127929687500}, +{0.0007629394531250, 0.0002441406250000, 0.0016479492187500, 0.0002136230468750, +0.0016784667968750, 0.0001831054687500, 0.0018615722656250, 0.0000305175781250, +0.0023193359375000, 0.0000915527343750, 0.0022583007812500, 0.0000610351562500, +0.0021362304687500, -0.0001525878906250, 0.0026245117187500, -0.0001220703125000, +0.0020446777343750, -0.0000305175781250, 0.0023193359375000, -0.0004272460937500, +0.0021972656250000, -0.0002441406250000, 0.0017089843750000, 0.0000305175781250, +0.0021057128906250, -0.0005798339843750, 0.0016174316406250, 0.0000610351562500, +0.0014648437500000, -0.0002746582031250, 0.0018005371093750, -0.0003356933593750, +0.0017395019531250, 0.0000305175781250, 0.0015258789062500, -0.0004272460937500, +0.0024414062500000, -0.0000610351562500, 0.0021972656250000, -0.0000305175781250, +0.0025329589843750, -0.0001220703125000, 0.0033569335937500, 0.0001220703125000, +0.0028381347656250, 0.0002746582031250, 0.0037536621093750, -0.0000915527343750, +0.0036621093750000, 0.0002441406250000, 0.0037536621093750, 0.0002746582031250, +0.0043029785156250, -0.0000305175781250, 0.0039672851562500, 0.0003356933593750, +0.0043640136718750, 0.0001831054687500, 0.0042419433593750, 0.0002441406250000, +0.0041809082031250, 0.0002441406250000, 0.0043945312500000, 0.0002136230468750, +0.0041198730468750, 0.0003662109375000, 0.0041503906250000, -0.0000305175781250, +0.0041198730468750, 0.0002136230468750, 0.0039672851562500, 0.0001220703125000, +0.0038757324218750, -0.0001220703125000, 0.0038146972656250, 0.0003662109375000, +0.0037536621093750, -0.0001525878906250, 0.0036621093750000, 0.0001525878906250, +0.0037231445312500, 0.0003051757812500, 0.0037536621093750, 0.0000000000000000, +0.0037536621093750, 0.0003967285156250, 0.0039062500000000, 0.0004272460937500, +0.0039672851562500, 0.0004882812500000, 0.0040588378906250, 0.0007324218750000, +0.0042419433593750, 0.0009155273437500, 0.0042114257812500, 0.0009155273437500, +0.0043029785156250, 0.0011596679687500, 0.0043945312500000, 0.0012207031250000, +0.0042724609375000, 0.0010986328125000, 0.0042114257812500, 0.0010681152343750, +0.0042724609375000, 0.0011596679687500, 0.0038452148437500, 0.0008850097656250, +0.0040283203125000, 0.0009460449218750, 0.0038146972656250, 0.0007934570312500, +0.0034179687500000, 0.0004577636718750, 0.0036621093750000, 0.0005187988281250, +0.0030517578125000, 0.0001525878906250, 0.0031127929687500, 0.0000000000000000, +0.0030212402343750, -0.0000915527343750, 0.0025939941406250, -0.0003051757812500, +0.0028076171875000, -0.0003051757812500, 0.0023803710937500, -0.0003356933593750, +0.0024719238281250, -0.0003662109375000, 0.0025329589843750, -0.0003662109375000, +0.0022888183593750, -0.0003051757812500, 0.0024414062500000, -0.0004272460937500, +0.0024719238281250, -0.0003051757812500, 0.0025024414062500, -0.0003356933593750, +0.0025634765625000, -0.0003356933593750, 0.0026855468750000, -0.0002746582031250, +0.0027160644531250, -0.0003356933593750, 0.0027465820312500, -0.0003051757812500, +0.0028381347656250, -0.0003356933593750, 0.0028686523437500, -0.0002136230468750, +0.0027770996093750, -0.0002136230468750, 0.0028381347656250, -0.0004882812500000, +0.0028381347656250, 0.0000305175781250, 0.0026550292968750, -0.0003051757812500, +0.0027770996093750, -0.0001220703125000, 0.0028381347656250, 0.0003356933593750, +0.0025939941406250, -0.0001525878906250, 0.0030212402343750, 0.0005798339843750, +0.0028076171875000, 0.0005187988281250, 0.0027465820312500, 0.0004882812500000, +0.0030212402343750, 0.0009460449218750, 0.0026855468750000, 0.0008544921875000, +0.0027160644531250, 0.0010375976562500, 0.0026855468750000, 0.0013122558593750, +0.0024414062500000, 0.0012512207031250, 0.0022888183593750, 0.0013427734375000, +0.0023498535156250, 0.0016174316406250, 0.0019226074218750, 0.0012512207031250, +0.0018920898437500, 0.0014648437500000, 0.0018310546875000, 0.0014038085937500, +0.0016479492187500, 0.0010070800781250, 0.0016174316406250, 0.0012207031250000, +0.0017700195312500, 0.0009460449218750, 0.0017089843750000, 0.0008239746093750, +0.0019226074218750, 0.0007629394531250, 0.0021667480468750, 0.0006713867187500, +0.0021667480468750, 0.0005493164062500, 0.0025634765625000, 0.0003662109375000, +0.0026550292968750, 0.0003356933593750, 0.0026550292968750, 0.0001831054687500, +0.0028686523437500, 0.0000305175781250, 0.0029296875000000, 0.0001220703125000, +0.0026245117187500, -0.0000915527343750, 0.0026855468750000, -0.0000610351562500, +0.0026550292968750, 0.0000305175781250, 0.0023193359375000, 0.0000610351562500, +0.0023193359375000, 0.0000915527343750, 0.0025634765625000, 0.0001525878906250, +0.0023803710937500, 0.0003662109375000, 0.0025329589843750, 0.0004577636718750, +0.0027770996093750, 0.0005187988281250, 0.0025634765625000, 0.0007629394531250, +0.0027770996093750, 0.0007629394531250, 0.0028991699218750, 0.0009765625000000, +0.0025939941406250, 0.0010681152343750, 0.0025024414062500, 0.0011596679687500, +0.0027465820312500, 0.0015258789062500, 0.0022888183593750, 0.0012207031250000, +0.0024719238281250, 0.0015258789062500, 0.0025024414062500, 0.0014648437500000, +0.0023193359375000, 0.0012512207031250, 0.0025634765625000, 0.0016479492187500, +0.0023498535156250, 0.0012817382812500, 0.0026245117187500, 0.0015258789062500, +0.0023498535156250, 0.0014038085937500, 0.0019836425781250, 0.0011901855468750, +0.0025329589843750, 0.0016784667968750, 0.0017395019531250, 0.0010986328125000, +0.0018005371093750, 0.0013427734375000, 0.0020446777343750, 0.0014343261718750, +0.0013732910156250, 0.0010375976562500, 0.0007934570312500, 0.0012817382812500, +0.0006713867187500, 0.0012512207031250, 0.0007629394531250, 0.0013122558593750, +0.0004577636718750, 0.0014343261718750, 0.0002441406250000, 0.0015258789062500, +0.0004882812500000, 0.0015869140625000, -0.0001831054687500, 0.0013122558593750, +-0.0001831054687500, 0.0014038085937500, 0.0000915527343750, 0.0012207031250000, +-0.0001220703125000, 0.0007934570312500, -0.0000305175781250, 0.0009460449218750, +0.0006103515625000, 0.0008239746093750, 0.0004882812500000, 0.0005493164062500, +0.0006713867187500, 0.0007324218750000, 0.0010986328125000, 0.0008239746093750, +0.0007934570312500, 0.0004882812500000, 0.0008544921875000, 0.0008544921875000, +0.0009155273437500, 0.0006713867187500, 0.0006713867187500, 0.0006408691406250, +0.0004272460937500, 0.0008239746093750, 0.0004882812500000, 0.0006713867187500, +0.0002136230468750, 0.0007629394531250, 0.0003051757812500, 0.0007934570312500, +0.0002746582031250, 0.0007019042968750, 0.0000305175781250, 0.0007019042968750, +0.0000000000000000, 0.0007324218750000, 0.0001525878906250, 0.0004577636718750, +-0.0000915527343750, 0.0005493164062500, -0.0001220703125000, 0.0003967285156250, +0.0000915527343750, 0.0001220703125000, -0.0000915527343750, 0.0003356933593750, +-0.0003662109375000, 0.0000915527343750, -0.0001525878906250, -0.0000305175781250, +-0.0004272460937500, 0.0002746582031250, -0.0008239746093750, 0.0004577636718750, +-0.0004577636718750, 0.0002746582031250, -0.0008850097656250, 0.0009155273437500, +-0.0010375976562500, 0.0008850097656250, -0.0007324218750000, 0.0011291503906250, +-0.0007629394531250, 0.0015869140625000, -0.0009460449218750, 0.0014953613281250, +0.0000000000000000, 0.0017089843750000, -0.0002746582031250, 0.0019226074218750, +0.0000305175781250, 0.0020446777343750, 0.0009765625000000, 0.0020446777343750, +0.0005187988281250, 0.0020751953125000, 0.0012207031250000, 0.0024414062500000, +0.0014953613281250, 0.0021972656250000, 0.0013732910156250, 0.0024719238281250, +0.0017395019531250, 0.0028381347656250, 0.0019836425781250, 0.0024108886718750, +0.0014648437500000, 0.0029907226562500, 0.0019836425781250, 0.0028686523437500, +0.0017395019531250, 0.0028076171875000, 0.0012207031250000, 0.0031738281250000, +0.0020141601562500, 0.0028686523437500, 0.0008850097656250, 0.0029296875000000, +0.0011596679687500, 0.0028686523437500, 0.0011596679687500, 0.0025939941406250, +0.0004882812500000, 0.0024108886718750, 0.0008544921875000, 0.0022888183593750, +0.0005187988281250, 0.0022277832031250, 0.0005187988281250, 0.0019226074218750, +0.0004577636718750, 0.0020141601562500, 0.0003051757812500, 0.0020446777343750, +0.0004272460937500, 0.0017089843750000, 0.0000610351562500, 0.0025024414062500, +0.0002441406250000, 0.0021362304687500, 0.0002136230468750, 0.0025024414062500, +-0.0000610351562500, 0.0032958984375000, 0.0003051757812500, 0.0028076171875000, +0.0000000000000000, 0.0040588378906250, 0.0003051757812500, 0.0039062500000000, +0.0002746582031250, 0.0041809082031250, 0.0000610351562500, 0.0051269531250000, +0.0004272460937500, 0.0047302246093750, 0.0001220703125000, 0.0055541992187500, +0.0002136230468750, 0.0057067871093750, 0.0002136230468750, 0.0055847167968750, +0.0000000000000000, 0.0058593750000000, 0.0001220703125000, 0.0057983398437500, +0.0000915527343750, 0.0054626464843750, 0.0000000000000000, 0.0055541992187500, +0.0001525878906250, 0.0052795410156250, 0.0002136230468750, 0.0049133300781250, +0.0001831054687500, 0.0049438476562500, 0.0004882812500000, 0.0044860839843750, +0.0004577636718750, 0.0043334960937500, 0.0006713867187500, 0.0040893554687500, +0.0008850097656250, 0.0037231445312500, 0.0008239746093750, 0.0037841796875000, +0.0010681152343750, 0.0032958984375000, 0.0011901855468750, 0.0032348632812500, +0.0011291503906250, 0.0031127929687500, 0.0011901855468750, 0.0026855468750000, +0.0011901855468750, 0.0027465820312500, 0.0010375976562500, 0.0025939941406250, +0.0009460449218750, 0.0024414062500000, 0.0007934570312500, 0.0025329589843750, +0.0006713867187500, 0.0025329589843750, 0.0006408691406250, 0.0022888183593750, +0.0005493164062500, 0.0026550292968750, 0.0004882812500000, 0.0023803710937500, +0.0004272460937500, 0.0025024414062500, 0.0004577636718750, 0.0028076171875000, +0.0004882812500000, 0.0023498535156250, 0.0004882812500000, 0.0029907226562500, +0.0005798339843750, 0.0027770996093750, 0.0006103515625000, 0.0028686523437500, +0.0007019042968750, 0.0033264160156250, 0.0008850097656250, 0.0030517578125000, +0.0007324218750000, 0.0036621093750000, 0.0009460449218750, 0.0035400390625000, +0.0009155273437500, 0.0037231445312500, 0.0007629394531250, 0.0041809082031250, +0.0010681152343750, 0.0038146972656250, 0.0005798339843750, 0.0042724609375000, +0.0008544921875000, 0.0041809082031250, 0.0006103515625000, 0.0042114257812500, +0.0002746582031250, 0.0044250488281250, 0.0008239746093750, 0.0042419433593750, +-0.0001831054687500, 0.0045471191406250, 0.0003662109375000, 0.0045166015625000, +0.0003051757812500, 0.0044555664062500, -0.0003051757812500, 0.0046386718750000, +0.0006408691406250, 0.0045166015625000, 0.0000610351562500, 0.0044860839843750, +0.0002746582031250, 0.0045471191406250, 0.0007019042968750, 0.0043029785156250, +0.0005187988281250, 0.0041503906250000, 0.0006103515625000, 0.0043945312500000, +0.0009460449218750, 0.0036621093750000, 0.0004272460937500, 0.0039367675781250, +0.0007019042968750, 0.0036926269531250, 0.0010681152343750, 0.0031127929687500, +0.0002441406250000, 0.0035705566406250, 0.0012817382812500, 0.0028686523437500, +0.0009460449218750, 0.0028991699218750, 0.0008544921875000, 0.0029602050781250, +0.0016174316406250, 0.0026550292968750, 0.0012207031250000, 0.0028076171875000, +0.0014953613281250}, +{0.0015258789062500, 0.0007324218750000, 0.0010986328125000, 0.0014648437500000, +0.0010070800781250, 0.0013427734375000, 0.0010986328125000, 0.0016479492187500, +0.0009765625000000, 0.0023193359375000, 0.0008544921875000, 0.0019836425781250, +0.0007934570312500, 0.0030212402343750, 0.0009460449218750, 0.0029296875000000, +0.0006103515625000, 0.0031738281250000, 0.0004272460937500, 0.0038757324218750, +0.0008239746093750, 0.0033874511718750, 0.0000305175781250, 0.0042114257812500, +0.0003051757812500, 0.0039672851562500, 0.0003662109375000, 0.0038452148437500, +-0.0001525878906250, 0.0042419433593750, 0.0001831054687500, 0.0037231445312500, +-0.0000610351562500, 0.0038146972656250, -0.0000610351562500, 0.0036010742187500, +0.0000305175781250, 0.0034179687500000, -0.0000915527343750, 0.0033874511718750, +0.0000610351562500, 0.0031738281250000, 0.0000305175781250, 0.0031738281250000, +0.0000610351562500, 0.0030822753906250, 0.0002136230468750, 0.0030212402343750, +0.0002746582031250, 0.0029907226562500, 0.0002136230468750, 0.0028991699218750, +0.0005798339843750, 0.0029296875000000, 0.0003967285156250, 0.0028991699218750, +0.0005187988281250, 0.0028686523437500, 0.0007629394531250, 0.0029602050781250, +0.0003662109375000, 0.0028076171875000, 0.0007934570312500, 0.0029296875000000, +0.0006408691406250, 0.0028381347656250, 0.0005187988281250, 0.0029296875000000, +0.0006713867187500, 0.0030212402343750, 0.0004882812500000, 0.0028076171875000, +0.0004882812500000, 0.0032043457031250, 0.0004882812500000, 0.0029907226562500, +0.0003967285156250, 0.0029602050781250, 0.0003967285156250, 0.0031738281250000, +0.0005187988281250, 0.0028991699218750, 0.0003967285156250, 0.0028686523437500, +0.0004577636718750, 0.0028076171875000, 0.0005187988281250, 0.0026245117187500, +0.0005493164062500, 0.0024719238281250, 0.0006408691406250, 0.0024414062500000, +0.0006408691406250, 0.0022888183593750, 0.0008239746093750, 0.0021362304687500, +0.0008239746093750, 0.0021362304687500, 0.0008239746093750, 0.0019836425781250, +0.0010375976562500, 0.0018615722656250, 0.0007324218750000, 0.0020141601562500, +0.0008544921875000, 0.0017700195312500, 0.0007324218750000, 0.0017395019531250, +0.0006103515625000, 0.0019531250000000, 0.0008239746093750, 0.0017089843750000, +0.0001220703125000, 0.0020751953125000, 0.0005798339843750, 0.0019531250000000, +0.0002746582031250, 0.0019226074218750, -0.0002746582031250, 0.0021972656250000, +0.0005798339843750, 0.0020446777343750, -0.0003662109375000, 0.0019836425781250, +0.0001525878906250, 0.0021362304687500, 0.0003662109375000, 0.0018920898437500, +-0.0002136230468750, 0.0017700195312500, 0.0003662109375000, 0.0020751953125000, +0.0002441406250000, 0.0014038085937500, 0.0000305175781250, 0.0017395019531250, +0.0004272460937500, 0.0015869140625000, 0.0004577636718750, 0.0010375976562500, +-0.0001220703125000, 0.0015869140625000, 0.0009155273437500, 0.0009460449218750, +0.0003051757812500, 0.0011596679687500, 0.0003662109375000, 0.0011901855468750, +0.0011901855468750, 0.0009155273437500, 0.0004577636718750, 0.0014038085937500, +0.0010375976562500, 0.0009765625000000, 0.0012207031250000, 0.0013122558593750, +0.0009765625000000, 0.0012512207031250, 0.0012512207031250, 0.0009460449218750, +0.0014648437500000, 0.0014343261718750, 0.0009765625000000, 0.0007019042968750, +0.0012817382812500, 0.0009155273437500, 0.0012512207031250, 0.0009765625000000, +0.0008544921875000, 0.0004272460937500, 0.0012207031250000, 0.0007019042968750, +0.0006713867187500, 0.0009460449218750, 0.0008850097656250, 0.0006713867187500, +0.0007019042968750, 0.0011596679687500, 0.0003356933593750, 0.0015869140625000, +0.0008544921875000, 0.0011596679687500, 0.0000915527343750, 0.0023498535156250, +0.0005187988281250, 0.0018920898437500, 0.0003967285156250, 0.0021972656250000, +-0.0002136230468750, 0.0030517578125000, 0.0004577636718750, 0.0022888183593750, +-0.0004577636718750, 0.0032043457031250, -0.0002136230468750, 0.0030517578125000, +-0.0003356933593750, 0.0029907226562500, -0.0009155273437500, 0.0034790039062500, +-0.0005798339843750, 0.0029907226562500, -0.0010986328125000, 0.0034790039062500, +-0.0009460449218750, 0.0034179687500000, -0.0010986328125000, 0.0032958984375000, +-0.0014038085937500, 0.0036315917968750, -0.0008544921875000, 0.0035400390625000, +-0.0015869140625000, 0.0029907226562500, -0.0012512207031250, 0.0035705566406250, +-0.0011291503906250, 0.0026245117187500, -0.0016174316406250, 0.0016479492187500, +-0.0011596679687500, 0.0026245117187500, -0.0012817382812500, -0.0000610351562500, +-0.0014038085937500, 0.0005187988281250, -0.0010681152343750, 0.0000915527343750, +-0.0008850097656250, -0.0018005371093750, -0.0010070800781250, -0.0006408691406250, +-0.0007324218750000, -0.0016174316406250, -0.0005798339843750, -0.0017089843750000, +-0.0007324218750000, -0.0010681152343750, -0.0009460449218750, -0.0011291503906250, +-0.0009765625000000, -0.0004272460937500, -0.0011901855468750, -0.0021972656250000, +-0.0005187988281250, -0.0019531250000000, -0.0007934570312500, -0.0018615722656250, +-0.0010070800781250, -0.0022888183593750, -0.0003356933593750, -0.0021667480468750, +-0.0016479492187500, -0.0018920898437500, -0.0012512207031250, -0.0021972656250000, +-0.0011901855468750, -0.0016479492187500, -0.0021057128906250, -0.0011596679687500, +-0.0016479492187500, -0.0017089843750000, -0.0013732910156250, -0.0002746582031250, +-0.0015869140625000, -0.0000915527343750, -0.0011291503906250, -0.0003356933593750, +-0.0003967285156250, 0.0003967285156250, -0.0005187988281250, 0.0005493164062500, +-0.0004577636718750, -0.0005187988281250, 0.0000915527343750, 0.0000915527343750, +-0.0002746582031250, -0.0003051757812500, -0.0008544921875000, -0.0014038085937500, +-0.0003051757812500, -0.0005187988281250, -0.0006408691406250, -0.0013427734375000, +-0.0012207031250000, -0.0013732910156250, -0.0004272460937500, -0.0009765625000000, +0.0000000000000000, -0.0010681152343750, -0.0008850097656250, -0.0009155273437500, +0.0011291503906250, -0.0003662109375000, 0.0005493164062500, -0.0004272460937500, +0.0007324218750000, 0.0000610351562500, 0.0021972656250000, 0.0006408691406250, +0.0012817382812500, 0.0003356933593750, 0.0021972656250000, 0.0015258789062500, +0.0024108886718750, 0.0015563964843750, 0.0021667480468750, 0.0015258789062500, +0.0022888183593750, 0.0021362304687500, 0.0022583007812500, 0.0019836425781250, +0.0021057128906250, 0.0013427734375000, 0.0021057128906250, 0.0015563964843750, +0.0018615722656250, 0.0012207031250000, 0.0015258789062500, 0.0003967285156250, +0.0015563964843750, 0.0006408691406250, 0.0009765625000000, 0.0001831054687500, +0.0007324218750000, -0.0000610351562500, 0.0005187988281250, -0.0000915527343750, +0.0002136230468750, -0.0001831054687500, 0.0000610351562500, -0.0002441406250000, +-0.0001220703125000, -0.0003051757812500, -0.0002441406250000, -0.0002746582031250, +-0.0002136230468750, -0.0002441406250000, -0.0002441406250000, -0.0003051757812500, +-0.0001525878906250, -0.0002441406250000, 0.0002441406250000, -0.0000305175781250, +0.0003662109375000, 0.0000000000000000, 0.0004882812500000, 0.0000610351562500, +0.0008850097656250, 0.0001831054687500, 0.0010986328125000, 0.0001525878906250, +0.0007324218750000, 0.0001831054687500, 0.0012207031250000, -0.0000305175781250, +0.0008239746093750, 0.0000915527343750, 0.0001831054687500, 0.0001831054687500, +0.0007629394531250, -0.0002441406250000, -0.0005493164062500, 0.0003967285156250, +-0.0003356933593750, 0.0001831054687500, -0.0005187988281250, 0.0000000000000000, +-0.0015258789062500, 0.0003662109375000, -0.0010070800781250, 0.0001831054687500, +-0.0015563964843750, -0.0000915527343750, -0.0016174316406250, 0.0001831054687500, +-0.0013122558593750, -0.0000610351562500, -0.0012817382812500, -0.0003662109375000, +-0.0012817382812500, 0.0001525878906250, -0.0005798339843750, -0.0005187988281250, +-0.0006408691406250, -0.0001525878906250, -0.0000915527343750, -0.0001525878906250, +0.0006408691406250, -0.0005798339843750, 0.0004882812500000, 0.0000305175781250, +0.0017395019531250, -0.0003051757812500, 0.0018005371093750, -0.0000610351562500, +0.0022277832031250, 0.0001220703125000, 0.0031738281250000, 0.0000915527343750, +0.0028991699218750, 0.0003662109375000, 0.0038146972656250, 0.0002136230468750, +0.0039672851562500, 0.0004882812500000, 0.0041198730468750, 0.0004577636718750, +0.0046081542968750, 0.0002746582031250, 0.0045166015625000, 0.0006408691406250, +0.0048828125000000, 0.0003051757812500, 0.0049743652343750, 0.0004577636718750, +0.0049438476562500, 0.0004272460937500, 0.0051269531250000, 0.0001220703125000, +0.0052185058593750, 0.0002746582031250, 0.0049743652343750, 0.0001525878906250, +0.0051879882812500, 0.0000610351562500, 0.0049438476562500, 0.0001220703125000, +0.0046691894531250, 0.0001220703125000, 0.0050048828125000, 0.0000000000000000, +0.0040588378906250, 0.0000915527343750, 0.0043640136718750, 0.0000915527343750, +0.0039367675781250, 0.0000915527343750, 0.0030822753906250, 0.0001525878906250, +0.0036621093750000, 0.0001220703125000, 0.0022888183593750, 0.0001525878906250, +0.0025329589843750, 0.0000915527343750, 0.0021057128906250, 0.0000915527343750, +0.0010986328125000, 0.0001220703125000, 0.0017700195312500, 0.0000915527343750, +0.0003356933593750, 0.0001220703125000, 0.0004882812500000, 0.0001220703125000, +0.0001525878906250, 0.0001220703125000, -0.0007629394531250, 0.0000610351562500, +-0.0001525878906250, 0.0000915527343750, -0.0013732910156250, 0.0000610351562500, +-0.0011901855468750, 0.0000000000000000, -0.0013122558593750, 0.0000915527343750, +-0.0020141601562500, 0.0001831054687500, -0.0016784667968750, 0.0000000000000000, +-0.0023193359375000, 0.0003356933593750, -0.0023803710937500, 0.0001831054687500, +-0.0022583007812500, 0.0003051757812500, -0.0025024414062500, 0.0005798339843750, +-0.0024719238281250, 0.0003356933593750, -0.0022583007812500, 0.0007324218750000, +-0.0022583007812500, 0.0007324218750000, -0.0021057128906250, 0.0008239746093750, +-0.0017395019531250, 0.0011901855468750, -0.0018310546875000, 0.0011596679687500, +-0.0012817382812500, 0.0014038085937500, -0.0012817382812500, 0.0015258789062500, +-0.0011901855468750, 0.0014953613281250, -0.0007934570312500, 0.0015869140625000, +-0.0008850097656250, 0.0016174316406250, -0.0008239746093750, 0.0015869140625000, +-0.0007324218750000, 0.0015563964843750, -0.0010681152343750, 0.0014343261718750, +-0.0013732910156250, 0.0013122558593750, -0.0011901855468750, 0.0012512207031250, +-0.0017700195312500, 0.0010375976562500, -0.0017395019531250, 0.0010070800781250, +-0.0017700195312500, 0.0008239746093750, -0.0020751953125000, 0.0006408691406250, +-0.0018920898437500, 0.0006103515625000, -0.0019226074218750, 0.0003356933593750, +-0.0018615722656250, 0.0002746582031250, -0.0018310546875000, 0.0001831054687500, +-0.0018005371093750, 0.0000305175781250, -0.0015869140625000, 0.0001525878906250, +-0.0016479492187500, -0.0001831054687500, -0.0014343261718750, 0.0000915527343750, +-0.0013122558593750, -0.0000610351562500, -0.0013732910156250, -0.0003967285156250, +-0.0010070800781250, 0.0000000000000000, -0.0010070800781250, -0.0004272460937500, +-0.0007934570312500, -0.0003356933593750, -0.0004272460937500, -0.0002441406250000, +-0.0002136230468750, -0.0004272460937500, 0.0000305175781250, -0.0001525878906250, +0.0005187988281250, -0.0003356933593750, 0.0007019042968750, -0.0001525878906250, +0.0009460449218750}, +{0.0025939941406250, 0.0000305175781250, 0.0021362304687500, 0.0001831054687500, +0.0013732910156250, -0.0000915527343750, 0.0020751953125000, 0.0003051757812500, +0.0006408691406250, 0.0002746582031250, 0.0009155273437500, 0.0003662109375000, +0.0006408691406250, 0.0003967285156250, -0.0003662109375000, 0.0003662109375000, +0.0003051757812500, 0.0005187988281250, -0.0007324218750000, 0.0001831054687500, +-0.0005798339843750, 0.0003356933593750, -0.0007019042968750, 0.0001831054687500, +-0.0013732910156250, -0.0001831054687500, -0.0008544921875000, 0.0000000000000000, +-0.0014343261718750, -0.0002746582031250, -0.0013427734375000, -0.0003356933593750, +-0.0011901855468750, -0.0002136230468750, -0.0014648437500000, -0.0002746582031250, +-0.0011291503906250, -0.0003662109375000, -0.0008850097656250, -0.0001525878906250, +-0.0009155273437500, -0.0002441406250000, -0.0003967285156250, -0.0001220703125000, +0.0000305175781250, 0.0001525878906250, -0.0001831054687500, -0.0000305175781250, +0.0009460449218750, 0.0001831054687500, 0.0007324218750000, 0.0002441406250000, +0.0011596679687500, 0.0001525878906250, 0.0020751953125000, 0.0002441406250000, +0.0015869140625000, 0.0003356933593750, 0.0029602050781250, 0.0002441406250000, +0.0027160644531250, 0.0002441406250000, 0.0031127929687500, 0.0003051757812500, +0.0040283203125000, 0.0002136230468750, 0.0034179687500000, 0.0002441406250000, +0.0046081542968750, 0.0003967285156250, 0.0045166015625000, 0.0002746582031250, +0.0046691894531250, 0.0003967285156250, 0.0054321289062500, 0.0006103515625000, +0.0049743652343750, 0.0003356933593750, 0.0053405761718750, 0.0009155273437500, +0.0054626464843750, 0.0007629394531250, 0.0052490234375000, 0.0008850097656250, +0.0052490234375000, 0.0013122558593750, 0.0053100585937500, 0.0011596679687500, +0.0047302246093750, 0.0014648437500000, 0.0049133300781250, 0.0016174316406250, +0.0046997070312500, 0.0016174316406250, 0.0041809082031250, 0.0017089843750000, +0.0045776367187500, 0.0017700195312500, 0.0040588378906250, 0.0016174316406250, +0.0039672851562500, 0.0016479492187500, 0.0042419433593750, 0.0016479492187500, +0.0040893554687500, 0.0014343261718750, 0.0039367675781250, 0.0014343261718750, +0.0045776367187500, 0.0012817382812500, 0.0043640136718750, 0.0012207031250000, +0.0045166015625000, 0.0010375976562500, 0.0050048828125000, 0.0008544921875000, +0.0046691894531250, 0.0008850097656250, 0.0049438476562500, 0.0005798339843750, +0.0050659179687500, 0.0006713867187500, 0.0046081542968750, 0.0005187988281250, +0.0044860839843750, 0.0003051757812500, 0.0045471191406250, 0.0005187988281250, +0.0034179687500000, 0.0001220703125000, 0.0035705566406250, 0.0003967285156250, +0.0030822753906250, 0.0002746582031250, 0.0021667480468750, -0.0000610351562500, +0.0024414062500000, 0.0003356933593750, 0.0011596679687500, -0.0002136230468750, +0.0012512207031250, -0.0001525878906250, 0.0008544921875000, -0.0000915527343750, +-0.0000610351562500, -0.0004577636718750, 0.0004577636718750, -0.0003051757812500, +-0.0005493164062500, -0.0003662109375000, -0.0003967285156250, -0.0003662109375000, +-0.0005493164062500, -0.0004577636718750, -0.0011901855468750, -0.0005187988281250, +-0.0006408691406250, -0.0004577636718750, -0.0014953613281250, -0.0004882812500000, +-0.0012817382812500, -0.0006103515625000, -0.0011901855468750, -0.0004577636718750, +-0.0016174316406250, -0.0002441406250000, -0.0013427734375000, -0.0004272460937500, +-0.0011596679687500, 0.0000305175781250, -0.0012817382812500, 0.0000305175781250, +-0.0009155273437500, 0.0000610351562500, -0.0005493164062500, 0.0003967285156250, +-0.0007629394531250, 0.0003356933593750, -0.0002746582031250, 0.0003662109375000, +-0.0001525878906250, 0.0004882812500000, -0.0001831054687500, 0.0004272460937500, +-0.0000305175781250, 0.0003967285156250, 0.0000915527343750, 0.0004272460937500, +0.0001525878906250, 0.0003356933593750, 0.0000610351562500, 0.0003356933593750, +0.0003356933593750, 0.0001831054687500, 0.0006408691406250, -0.0000305175781250, +0.0004882812500000, 0.0000305175781250, 0.0009155273437500, -0.0002136230468750, +0.0009460449218750, -0.0004577636718750, 0.0009765625000000, -0.0003356933593750, +0.0012207031250000, -0.0001831054687500, 0.0011901855468750, -0.0003051757812500, +0.0010070800781250, -0.0000610351562500, 0.0010070800781250, -0.0002136230468750, +0.0011291503906250, -0.0001831054687500, 0.0010375976562500, -0.0000305175781250, +0.0008544921875000, -0.0002441406250000, 0.0009765625000000, 0.0001525878906250, +0.0008544921875000, -0.0002136230468750, 0.0005798339843750, -0.0000610351562500, +0.0005493164062500, 0.0003662109375000, 0.0006103515625000, -0.0002136230468750, +0.0002441406250000, 0.0004882812500000, 0.0003967285156250, 0.0003662109375000, +0.0003662109375000, 0.0002136230468750, 0.0000915527343750, 0.0004882812500000, +0.0004577636718750, 0.0002136230468750, 0.0000305175781250, 0.0003356933593750, +0.0002441406250000, 0.0002441406250000, -0.0000610351562500, 0.0002746582031250, +-0.0005798339843750, 0.0004577636718750, -0.0001525878906250, 0.0003662109375000, +-0.0011596679687500, 0.0007324218750000, -0.0009155273437500, 0.0007019042968750, +-0.0010375976562500, 0.0006408691406250, -0.0017395019531250, 0.0007629394531250, +-0.0013732910156250, 0.0008850097656250, -0.0014038085937500, 0.0003967285156250, +-0.0017395019531250, 0.0007019042968750, -0.0011901855468750, 0.0004577636718750, +-0.0007934570312500, -0.0000610351562500, -0.0012512207031250, 0.0003356933593750, +0.0001525878906250, -0.0002746582031250, -0.0000915527343750, -0.0001831054687500, +0.0000915527343750, -0.0002441406250000, 0.0011596679687500, -0.0006103515625000, +0.0005187988281250, -0.0003967285156250, 0.0007629394531250, -0.0007934570312500, +0.0010681152343750, -0.0007934570312500, 0.0006103515625000, -0.0008544921875000, +0.0002441406250000, -0.0011291503906250, 0.0006713867187500, -0.0010986328125000, +-0.0000305175781250, -0.0012207031250000, 0.0000000000000000, -0.0014038085937500, +0.0001831054687500, -0.0013427734375000, 0.0000305175781250, -0.0013427734375000, +0.0001831054687500, -0.0014953613281250, 0.0002746582031250, -0.0013122558593750, +0.0003662109375000, -0.0012817382812500, 0.0005493164062500, -0.0012207031250000, +0.0006408691406250, -0.0010375976562500, 0.0007324218750000, -0.0009765625000000, +0.0008850097656250, -0.0006408691406250, 0.0008239746093750, -0.0006408691406250, +0.0009460449218750, -0.0001831054687500, 0.0010986328125000, 0.0002136230468750, +0.0010681152343750, -0.0000305175781250, 0.0013122558593750, 0.0007934570312500, +0.0013732910156250, 0.0007324218750000, 0.0013732910156250, 0.0008239746093750, +0.0015258789062500, 0.0012817382812500, 0.0016174316406250, 0.0009765625000000, +0.0014343261718750, 0.0011901855468750, 0.0016784667968750, 0.0012207031250000, +0.0015869140625000, 0.0011901855468750, 0.0013427734375000, 0.0012512207031250, +0.0016479492187500, 0.0012207031250000, 0.0012207031250000, 0.0013427734375000, +0.0011901855468750, 0.0012207031250000, 0.0011901855468750, 0.0011596679687500, +0.0008544921875000, 0.0011291503906250, 0.0007629394531250, 0.0009460449218750, +0.0007934570312500, 0.0010375976562500, 0.0005187988281250, 0.0007324218750000, +0.0004577636718750, 0.0007324218750000, 0.0006408691406250, 0.0008239746093750, +0.0004272460937500, 0.0004272460937500, 0.0005798339843750, 0.0006408691406250, +0.0007019042968750, 0.0006103515625000, 0.0006103515625000, 0.0003662109375000, +0.0005493164062500, 0.0003662109375000, 0.0006713867187500, 0.0002136230468750, +0.0003967285156250, 0.0001220703125000, 0.0005493164062500, -0.0000305175781250, +0.0004272460937500, -0.0000915527343750, 0.0001220703125000, -0.0000915527343750, +0.0003051757812500, -0.0002136230468750, 0.0000305175781250, -0.0000915527343750, +-0.0000305175781250, -0.0002136230468750, -0.0000610351562500, -0.0000305175781250, +-0.0001831054687500, 0.0002136230468750, -0.0002136230468750, 0.0000000000000000, +-0.0001831054687500, 0.0006713867187500, -0.0003051757812500, 0.0004882812500000, +-0.0001831054687500, 0.0008239746093750, -0.0001220703125000, 0.0013732910156250, +-0.0001831054687500, 0.0010375976562500, 0.0001831054687500, 0.0021057128906250, +0.0001220703125000, 0.0019226074218750, 0.0002136230468750, 0.0023498535156250, +0.0004577636718750, 0.0033569335937500, 0.0004272460937500, 0.0028686523437500, +0.0005493164062500, 0.0041503906250000, 0.0006713867187500, 0.0040588378906250, +0.0006408691406250, 0.0043945312500000, 0.0006408691406250, 0.0052795410156250, +0.0006713867187500, 0.0047607421875000, 0.0004882812500000, 0.0057678222656250, +0.0006103515625000, 0.0056152343750000, 0.0004272460937500, 0.0057678222656250, +0.0002136230468750, 0.0064086914062500, 0.0005187988281250, 0.0060119628906250, +-0.0000915527343750, 0.0065917968750000, 0.0001525878906250, 0.0065612792968750, +0.0001220703125000, 0.0065612792968750, -0.0002136230468750, 0.0069580078125000, +0.0003662109375000, 0.0068359375000000, -0.0000305175781250, 0.0068359375000000, +0.0002746582031250, 0.0070800781250000, 0.0005493164062500, 0.0067749023437500, +0.0003356933593750, 0.0065917968750000, 0.0005187988281250, 0.0069580078125000, +0.0008239746093750, 0.0060729980468750, 0.0004577636718750, 0.0064086914062500, +0.0007324218750000, 0.0062561035156250, 0.0009460449218750, 0.0055236816406250, +0.0001831054687500, 0.0060424804687500, 0.0009155273437500, 0.0054931640625000, +0.0005187988281250, 0.0054931640625000, 0.0003356933593750, 0.0057373046875000, +0.0008239746093750, 0.0056457519531250, 0.0002746582031250, 0.0057067871093750, +0.0004882812500000, 0.0060729980468750, 0.0005798339843750, 0.0062255859375000, +0.0003051757812500, 0.0062866210937500, 0.0003356933593750, 0.0065917968750000, +0.0005798339843750, 0.0067443847656250, 0.0000610351562500, 0.0062866210937500, +0.0002441406250000, 0.0068054199218750, 0.0002441406250000, 0.0061645507812500, +-0.0001220703125000, 0.0054626464843750, 0.0002136230468750, 0.0062255859375000, +-0.0000915527343750, 0.0042114257812500, 0.0001525878906250, 0.0046081542968750, +0.0001220703125000, 0.0042114257812500, -0.0000610351562500, 0.0028381347656250, +0.0003967285156250, 0.0036010742187500, -0.0002746582031250, 0.0021972656250000, +0.0001525878906250, 0.0022888183593750, 0.0000915527343750, 0.0019531250000000, +-0.0003356933593750, 0.0010681152343750, 0.0003051757812500, 0.0016784667968750, +-0.0003051757812500, 0.0001831054687500, 0.0000305175781250, 0.0004882812500000, +0.0000000000000000, 0.0000000000000000, -0.0004577636718750, -0.0011291503906250, +0.0001220703125000, -0.0003662109375000, -0.0007629394531250, -0.0020751953125000, +-0.0004272460937500, -0.0020446777343750, -0.0005187988281250, -0.0021667480468750, +-0.0011901855468750, -0.0031433105468750, -0.0006713867187500, -0.0027160644531250, +-0.0010681152343750, -0.0029602050781250, -0.0012207031250000, -0.0031127929687500, +-0.0009765625000000, -0.0028686523437500, -0.0010070800781250, -0.0026245117187500, +-0.0012512207031250, -0.0026550292968750, -0.0008239746093750, -0.0021667480468750, +-0.0011901855468750, -0.0020446777343750, -0.0011901855468750, -0.0018920898437500, +-0.0009765625000000, -0.0015869140625000, -0.0014953613281250, -0.0014038085937500, +-0.0011596679687500, -0.0008239746093750, -0.0013427734375000, -0.0009460449218750, +-0.0013427734375000, -0.0001525878906250, -0.0010375976562500, 0.0006103515625000, +-0.0011291503906250}, +{-0.0003662109375000, 0.0025634765625000, -0.0003662109375000, 0.0027160644531250, +-0.0000610351562500, 0.0033264160156250, -0.0000305175781250, 0.0032653808593750, +0.0000915527343750, 0.0037536621093750, 0.0003051757812500, 0.0042724609375000, +0.0002746582031250, 0.0039978027343750, 0.0004577636718750, 0.0051879882812500, +0.0005798339843750, 0.0050354003906250, 0.0004882812500000, 0.0053405761718750, +0.0004577636718750, 0.0061950683593750, 0.0005798339843750, 0.0057373046875000, +0.0000610351562500, 0.0065307617187500, 0.0004272460937500, 0.0065307617187500, +0.0001831054687500, 0.0064086914062500, -0.0002746582031250, 0.0066528320312500, +0.0004272460937500, 0.0064697265625000, -0.0003967285156250, 0.0063476562500000, +0.0000000000000000, 0.0062255859375000, 0.0001220703125000, 0.0059204101562500, +-0.0003967285156250, 0.0056457519531250, 0.0001525878906250, 0.0056152343750000, +0.0001220703125000, 0.0052795410156250, -0.0000915527343750, 0.0050048828125000, +0.0003356933593750, 0.0049438476562500, 0.0004577636718750, 0.0047912597656250, +-0.0000915527343750, 0.0046386718750000, 0.0008239746093750, 0.0045471191406250, +0.0002441406250000, 0.0043640136718750, 0.0003356933593750, 0.0042419433593750, +0.0009765625000000, 0.0043029785156250, 0.0000305175781250, 0.0041809082031250, +0.0010070800781250, 0.0037536621093750, 0.0007629394531250, 0.0038757324218750, +0.0005187988281250, 0.0033874511718750, 0.0010681152343750, 0.0028076171875000, +0.0007934570312500, 0.0031738281250000, 0.0006408691406250, 0.0024414062500000, +0.0007934570312500, 0.0023193359375000, 0.0006408691406250, 0.0026245117187500, +0.0003356933593750, 0.0023803710937500, 0.0003967285156250, 0.0023193359375000, +0.0001831054687500, 0.0032653808593750, 0.0001220703125000, 0.0027770996093750, +0.0000305175781250, 0.0034790039062500, -0.0000610351562500, 0.0046386718750000, +0.0000610351562500, 0.0037841796875000, -0.0002746582031250, 0.0053710937500000, +0.0000915527343750, 0.0053100585937500, -0.0000915527343750, 0.0052185058593750, +-0.0003356933593750, 0.0059814453125000, 0.0003051757812500, 0.0055541992187500, +-0.0004272460937500, 0.0054321289062500, -0.0000305175781250, 0.0055541992187500, +-0.0000305175781250, 0.0052490234375000, -0.0004272460937500, 0.0049438476562500, +0.0001525878906250, 0.0051269531250000, -0.0005187988281250, 0.0046691894531250, +-0.0002746582031250, 0.0046997070312500, -0.0003051757812500, 0.0045166015625000, +-0.0007629394531250, 0.0042114257812500, -0.0003967285156250, 0.0044250488281250, +-0.0006408691406250, 0.0039367675781250, -0.0007019042968750, 0.0041809082031250, +-0.0003051757812500, 0.0035400390625000, -0.0002441406250000, 0.0028381347656250, +-0.0003662109375000, 0.0033874511718750, -0.0000610351562500, 0.0015869140625000, +-0.0003662109375000, 0.0019226074218750, -0.0003356933593750, 0.0013122558593750, +-0.0002441406250000, -0.0001525878906250, -0.0007629394531250, 0.0007019042968750, +-0.0001831054687500, -0.0011596679687500, -0.0007629394531250, -0.0010681152343750, +-0.0008544921875000, -0.0011901855468750, -0.0003662109375000, -0.0021362304687500, +-0.0010681152343750, -0.0015869140625000, -0.0007019042968750, -0.0022583007812500, +-0.0007324218750000, -0.0019836425781250, -0.0008239746093750, -0.0022277832031250, +-0.0005798339843750, -0.0028991699218750, -0.0005798339843750, -0.0022583007812500, +-0.0006713867187500, -0.0029296875000000, -0.0006408691406250, -0.0032043457031250, +-0.0006103515625000, -0.0024108886718750, -0.0007324218750000, -0.0016479492187500, +0.0003356933593750, -0.0010681152343750, 0.0002746582031250, -0.0032958984375000, +0.0005187988281250, -0.0034484863281250, 0.0005187988281250, -0.0027160644531250, +0.0002441406250000, -0.0028076171875000, 0.0004577636718750, -0.0034484863281250, +0.0009155273437500, -0.0012512207031250, 0.0007934570312500, -0.0018310546875000, +0.0012207031250000, -0.0014648437500000, 0.0021057128906250, 0.0001525878906250, +0.0019531250000000, -0.0008850097656250, 0.0020751953125000, 0.0004272460937500, +0.0027770996093750, 0.0003356933593750, 0.0021362304687500, 0.0003051757812500, +0.0013732910156250, 0.0011291503906250, 0.0022277832031250, 0.0007324218750000, +0.0003051757812500, 0.0008850097656250, 0.0003662109375000, 0.0013427734375000, +0.0001831054687500, 0.0005187988281250, -0.0010375976562500, 0.0000000000000000, +-0.0006103515625000, 0.0006713867187500, -0.0011291503906250, -0.0011901855468750, +-0.0010375976562500, -0.0010070800781250, -0.0012207031250000, -0.0010986328125000, +-0.0015563964843750, -0.0022277832031250, -0.0010375976562500, -0.0016479492187500, +-0.0015563964843750, -0.0017700195312500, -0.0015563964843750, -0.0018615722656250, +-0.0010375976562500, -0.0014953613281250, -0.0010681152343750, -0.0011596679687500, +-0.0010070800781250, -0.0011596679687500, 0.0001831054687500, -0.0006103515625000, +-0.0000610351562500, -0.0003662109375000, 0.0005493164062500, -0.0002746582031250, +0.0017395019531250, 0.0000000000000000, 0.0011291503906250, 0.0000610351562500, +0.0018920898437500, -0.0002746582031250, 0.0023498535156250, 0.0000000000000000, +0.0017395019531250, -0.0003051757812500, 0.0015869140625000, -0.0008544921875000, +0.0019836425781250, -0.0004882812500000, 0.0007629394531250, -0.0012817382812500, +0.0008544921875000, -0.0013122558593750, 0.0011291503906250, -0.0010070800781250, +0.0004272460937500, -0.0011596679687500, 0.0006103515625000, -0.0011596679687500, +0.0018920898437500, -0.0004272460937500, 0.0009765625000000, -0.0005187988281250, +0.0022277832031250, -0.0002441406250000, 0.0039367675781250, 0.0003967285156250, +0.0023803710937500, 0.0001525878906250, 0.0058288574218750, 0.0006103515625000, +0.0051879882812500, 0.0006103515625000, 0.0055847167968750, 0.0005187988281250, +0.0077514648437500, 0.0007629394531250, 0.0063171386718750, 0.0007324218750000, +0.0077514648437500, 0.0002441406250000, 0.0077819824218750, 0.0005187988281250, +0.0071716308593750, 0.0002441406250000, 0.0075378417968750, -0.0002441406250000, +0.0073852539062500, 0.0001831054687500, 0.0063781738281250, -0.0003356933593750, +0.0067138671875000, -0.0003356933593750, 0.0062255859375000, -0.0001525878906250, +0.0053100585937500, -0.0003356933593750, 0.0057983398437500, -0.0003356933593750, +0.0047912597656250, -0.0002136230468750, 0.0048828125000000, -0.0003967285156250, +0.0047607421875000, -0.0003051757812500, 0.0041809082031250, -0.0001220703125000, +0.0045166015625000, -0.0004272460937500, 0.0039367675781250, 0.0000610351562500, +0.0039367675781250, -0.0000915527343750, 0.0041809082031250, -0.0000610351562500, +0.0038757324218750, 0.0002441406250000, 0.0039062500000000, 0.0000305175781250, +0.0043945312500000, 0.0001220703125000, 0.0041198730468750, 0.0003051757812500, +0.0043945312500000, 0.0002136230468750, 0.0049133300781250, 0.0001220703125000, +0.0044860839843750, 0.0003356933593750, 0.0055541992187500, 0.0000915527343750, +0.0052490234375000, 0.0002441406250000, 0.0056457519531250, 0.0001525878906250, +0.0065612792968750, -0.0000610351562500, 0.0060119628906250, 0.0001525878906250, +0.0071716308593750, -0.0000610351562500, 0.0071105957031250, -0.0000305175781250, +0.0071105957031250, -0.0000915527343750, 0.0077209472656250, -0.0001525878906250, +0.0074157714843750, -0.0001220703125000, 0.0073547363281250, -0.0002136230468750, +0.0075988769531250, -0.0001831054687500, 0.0070800781250000, -0.0001525878906250, +0.0066833496093750, -0.0002136230468750, 0.0068664550781250, -0.0002441406250000, +0.0054626464843750, -0.0001831054687500, 0.0057373046875000, -0.0002441406250000, +0.0050659179687500, -0.0002136230468750, 0.0037841796875000, -0.0000915527343750, +0.0043945312500000, -0.0002441406250000, 0.0028991699218750, 0.0001220703125000, +0.0028076171875000, 0.0000000000000000, 0.0026245117187500, 0.0000915527343750, +0.0017700195312500, 0.0004272460937500, 0.0020141601562500, 0.0002136230468750, +0.0015869140625000, 0.0006103515625000, 0.0013427734375000, 0.0005798339843750, +0.0014953613281250, 0.0007019042968750, 0.0014953613281250, 0.0010375976562500, +0.0013732910156250, 0.0009155273437500, 0.0017700195312500, 0.0012512207031250, +0.0017395019531250, 0.0013427734375000, 0.0018615722656250, 0.0013122558593750, +0.0022277832031250, 0.0014648437500000, 0.0021667480468750, 0.0014648437500000, +0.0022583007812500, 0.0014648437500000, 0.0024108886718750, 0.0015869140625000, +0.0023193359375000, 0.0014648437500000, 0.0021667480468750, 0.0013427734375000, +0.0022888183593750, 0.0014038085937500, 0.0020141601562500, 0.0012207031250000, +0.0018920898437500, 0.0012207031250000, 0.0018615722656250, 0.0011291503906250, +0.0017395019531250, 0.0009155273437500, 0.0016479492187500, 0.0010375976562500, +0.0015563964843750, 0.0007324218750000, 0.0014343261718750, 0.0007324218750000, +0.0013122558593750, 0.0007019042968750, 0.0012207031250000, 0.0004882812500000, +0.0011596679687500, 0.0006103515625000, 0.0008544921875000, 0.0004577636718750, +0.0009155273437500, 0.0006103515625000, 0.0005493164062500, 0.0005187988281250, +0.0001831054687500, 0.0004272460937500, 0.0003967285156250, 0.0007324218750000, +-0.0003967285156250, 0.0002441406250000, -0.0003051757812500, 0.0005493164062500, +-0.0003356933593750, 0.0004577636718750, -0.0008544921875000, 0.0000305175781250, +-0.0007324218750000, 0.0004272460937500, -0.0006408691406250, -0.0000610351562500, +-0.0007934570312500, 0.0000000000000000, -0.0005187988281250, -0.0000305175781250, +-0.0002441406250000, -0.0002441406250000, -0.0004272460937500, 0.0000000000000000, +0.0002746582031250, -0.0002136230468750, 0.0002746582031250, -0.0000610351562500, +0.0005798339843750, 0.0000000000000000, 0.0011901855468750, -0.0000915527343750, +0.0010070800781250, 0.0000915527343750, 0.0016479492187500, 0.0001525878906250, +0.0018310546875000, 0.0002136230468750, 0.0018615722656250, 0.0002441406250000, +0.0021667480468750, 0.0003051757812500, 0.0023498535156250, 0.0004272460937500, +0.0028686523437500, 0.0002441406250000, 0.0028991699218750, 0.0003662109375000, +0.0031738281250000, 0.0002746582031250, 0.0036010742187500, 0.0001220703125000, +0.0034484863281250, 0.0003356933593750, 0.0038452148437500, -0.0002441406250000, +0.0039978027343750, 0.0000000000000000, 0.0039367675781250, -0.0002441406250000, +0.0039367675781250, -0.0007019042968750, 0.0038146972656250, -0.0003356933593750, +0.0034790039062500, -0.0008544921875000, 0.0032043457031250, -0.0009765625000000, +0.0028686523437500, -0.0007629394531250, 0.0025329589843750, -0.0009155273437500, +0.0022277832031250, -0.0010681152343750, 0.0016174316406250, -0.0005187988281250, +0.0016174316406250, -0.0007019042968750, 0.0009155273437500, -0.0007019042968750, +0.0002441406250000, -0.0003356933593750, 0.0006713867187500, -0.0005493164062500, +-0.0008239746093750, -0.0004882812500000, -0.0007019042968750, -0.0005187988281250, +-0.0009460449218750, -0.0004577636718750, -0.0019226074218750, -0.0006103515625000, +-0.0014343261718750, -0.0008239746093750, -0.0015563964843750, -0.0003051757812500, +-0.0016174316406250, -0.0006408691406250, -0.0013732910156250, -0.0007629394531250, +-0.0011596679687500, -0.0004577636718750, -0.0010681152343750, -0.0007019042968750, +-0.0005493164062500, -0.0005798339843750, -0.0003662109375000, -0.0005493164062500, +0.0000000000000000, -0.0006713867187500, 0.0002746582031250, -0.0006103515625000, +0.0000915527343750, -0.0005187988281250, 0.0013122558593750, -0.0008239746093750, +0.0009460449218750}, +{0.0023803710937500, 0.0014343261718750, 0.0021972656250000, 0.0015869140625000, +0.0022583007812500, 0.0014648437500000, 0.0022888183593750, 0.0014343261718750, +0.0021362304687500, 0.0015563964843750, 0.0029296875000000, 0.0012817382812500, +0.0026855468750000, 0.0013732910156250, 0.0030822753906250, 0.0012207031250000, +0.0038452148437500, 0.0008544921875000, 0.0034484863281250, 0.0010681152343750, +0.0042724609375000, 0.0007324218750000, 0.0043640136718750, 0.0007324218750000, +0.0043945312500000, 0.0006713867187500, 0.0048217773437500, 0.0004577636718750, +0.0047302246093750, 0.0006103515625000, 0.0047302246093750, 0.0003967285156250, +0.0048828125000000, 0.0004882812500000, 0.0046691894531250, 0.0003967285156250, +0.0044860839843750, 0.0002746582031250, 0.0046386718750000, 0.0004882812500000, +0.0040283203125000, -0.0000305175781250, 0.0041809082031250, 0.0002136230468750, +0.0038757324218750, 0.0001220703125000, 0.0033874511718750, -0.0002746582031250, +0.0036315917968750, 0.0001831054687500, 0.0030212402343750, -0.0003662109375000, +0.0030822753906250, -0.0002441406250000, 0.0028991699218750, -0.0002441406250000, +0.0024414062500000, -0.0005187988281250, 0.0026550292968750, -0.0002441406250000, +0.0019836425781250, -0.0004882812500000, 0.0020751953125000, -0.0003662109375000, +0.0019226074218750, -0.0003051757812500, 0.0014953613281250, -0.0003662109375000, +0.0016784667968750, -0.0000915527343750, 0.0010681152343750, -0.0003051757812500, +0.0011596679687500, -0.0000610351562500, 0.0008850097656250, 0.0000610351562500, +0.0003356933593750, 0.0000000000000000, 0.0005798339843750, 0.0003662109375000, +0.0000610351562500, 0.0001220703125000, 0.0000305175781250, 0.0003662109375000, +-0.0000915527343750, 0.0003051757812500, -0.0003967285156250, 0.0000305175781250, +-0.0002136230468750, 0.0003967285156250, -0.0004882812500000, -0.0000610351562500, +-0.0004882812500000, 0.0002136230468750, -0.0003356933593750, 0.0000915527343750, +-0.0004577636718750, -0.0002746582031250, -0.0005493164062500, 0.0002136230468750, +0.0001831054687500, -0.0005493164062500, -0.0001220703125000, -0.0003967285156250, +0.0003051757812500, -0.0002441406250000, 0.0009765625000000, -0.0007019042968750, +0.0004577636718750, -0.0005798339843750, 0.0015258789062500, -0.0004577636718750, +0.0010986328125000, -0.0006103515625000, 0.0013732910156250, -0.0004577636718750, +0.0023193359375000, -0.0001831054687500, 0.0016479492187500, -0.0003662109375000, +0.0024719238281250, -0.0002746582031250, 0.0024108886718750, -0.0002746582031250, +0.0021972656250000, -0.0003356933593750, 0.0025329589843750, -0.0003967285156250, +0.0022888183593750, -0.0003967285156250, 0.0020141601562500, -0.0004272460937500, +0.0022888183593750, -0.0005187988281250, 0.0018310546875000, -0.0004882812500000, +0.0012512207031250, -0.0005493164062500, 0.0014038085937500, -0.0007019042968750, +-0.0001525878906250, -0.0005798339843750, 0.0005187988281250, -0.0007019042968750, +0.0000305175781250, -0.0007324218750000, -0.0013427734375000, -0.0006103515625000, +-0.0003967285156250, -0.0007019042968750, -0.0018005371093750, -0.0006713867187500, +-0.0016174316406250, -0.0005493164062500, -0.0013427734375000, -0.0007629394531250, +-0.0019836425781250, -0.0008850097656250, -0.0015563964843750, -0.0006408691406250, +-0.0011901855468750, -0.0011901855468750, -0.0016479492187500, -0.0010375976562500, +-0.0009765625000000, -0.0008850097656250, -0.0003662109375000, -0.0011291503906250, +-0.0010070800781250, -0.0009460449218750, 0.0005798339843750, -0.0005187988281250, +0.0003662109375000, -0.0004882812500000, 0.0005187988281250, -0.0000915527343750, +0.0015258789062500, 0.0004882812500000, 0.0009765625000000, 0.0003967285156250, +0.0015258789062500, 0.0008544921875000, 0.0016174316406250, 0.0011596679687500, +0.0013732910156250, 0.0010375976562500, 0.0015258789062500, 0.0010681152343750, +0.0015869140625000, 0.0014343261718750, 0.0011596679687500, 0.0008850097656250, +0.0014953613281250, 0.0010375976562500, 0.0012512207031250, 0.0010681152343750, +0.0007629394531250, 0.0007629394531250, 0.0012817382812500, 0.0009460449218750, +0.0002746582031250, 0.0010681152343750, 0.0005493164062500, 0.0008544921875000, +0.0003356933593750, 0.0013427734375000, -0.0003356933593750, 0.0017395019531250, +0.0001831054687500, 0.0014038085937500, -0.0007019042968750, 0.0026550292968750, +-0.0004577636718750, 0.0025329589843750, -0.0005798339843750, 0.0029907226562500, +-0.0012207031250000, 0.0039672851562500, -0.0008239746093750, 0.0036621093750000, +-0.0013732910156250, 0.0046691894531250, -0.0015258789062500, 0.0048217773437500, +-0.0012817382812500, 0.0049743652343750, -0.0014648437500000, 0.0055541992187500, +-0.0016479492187500, 0.0054016113281250, -0.0009765625000000, 0.0054931640625000, +-0.0012817382812500, 0.0056152343750000, -0.0009765625000000, 0.0054931640625000, +-0.0003356933593750, 0.0053710937500000, -0.0008544921875000, 0.0054321289062500, +-0.0001525878906250, 0.0052795410156250, -0.0002136230468750, 0.0051574707031250, +-0.0002441406250000, 0.0051879882812500, 0.0001831054687500, 0.0052490234375000, +-0.0001220703125000, 0.0051574707031250, 0.0001525878906250, 0.0052795410156250, +-0.0000305175781250, 0.0052795410156250, 0.0000610351562500, 0.0051879882812500, +0.0002746582031250, 0.0051269531250000, -0.0001220703125000, 0.0050659179687500, +0.0003051757812500, 0.0050964355468750, 0.0001525878906250, 0.0049438476562500, +0.0000915527343750, 0.0049743652343750, 0.0004272460937500, 0.0050964355468750, +0.0002136230468750, 0.0049438476562500, 0.0005493164062500, 0.0050964355468750, +0.0005493164062500, 0.0050354003906250, 0.0005798339843750, 0.0050659179687500, +0.0007629394531250, 0.0051879882812500, 0.0008239746093750, 0.0050354003906250, +0.0007324218750000, 0.0055847167968750, 0.0009155273437500, 0.0053710937500000, +0.0008850097656250, 0.0058593750000000, 0.0008239746093750, 0.0065612792968750, +0.0009155273437500, 0.0061035156250000, 0.0009155273437500, 0.0075683593750000, +0.0008239746093750, 0.0074157714843750, 0.0008544921875000, 0.0078430175781250, +0.0008544921875000, 0.0089111328125000, 0.0007934570312500, 0.0084228515625000, +0.0006408691406250, 0.0093078613281250, 0.0006103515625000, 0.0095214843750000, +0.0005187988281250, 0.0092773437500000, 0.0003356933593750, 0.0095825195312500, +0.0003662109375000, 0.0097351074218750, 0.0002441406250000, 0.0089721679687500, +0.0001831054687500, 0.0092468261718750, 0.0001831054687500, 0.0087585449218750, +0.0002136230468750, 0.0079650878906250, 0.0001525878906250, 0.0084533691406250, +0.0001525878906250, 0.0068054199218750, 0.0002441406250000, 0.0069885253906250, +0.0000915527343750, 0.0065307617187500, 0.0000305175781250, 0.0052795410156250, +0.0001525878906250, 0.0057983398437500, -0.0001525878906250, 0.0044250488281250, +-0.0000305175781250, 0.0044250488281250, -0.0001831054687500, 0.0041198730468750, +-0.0004272460937500, 0.0032653808593750, -0.0001220703125000, 0.0036621093750000, +-0.0006713867187500, 0.0028076171875000, -0.0003967285156250, 0.0028381347656250, +-0.0004577636718750, 0.0026550292968750, -0.0007019042968750, 0.0021362304687500, +-0.0003051757812500, 0.0025329589843750, -0.0004882812500000, 0.0018310546875000, +-0.0003051757812500, 0.0019531250000000, -0.0000305175781250, 0.0019531250000000, +-0.0000305175781250, 0.0016479492187500, 0.0001220703125000, 0.0019226074218750, +0.0004272460937500, 0.0018005371093750, 0.0001525878906250, 0.0018005371093750, +0.0003051757812500, 0.0022583007812500, 0.0005187988281250, 0.0025024414062500, +-0.0000305175781250, 0.0023803710937500, 0.0005798339843750, 0.0033569335937500, +0.0000305175781250, 0.0032653808593750, 0.0000305175781250, 0.0037841796875000, +0.0005187988281250, 0.0046386718750000, -0.0003051757812500, 0.0043029785156250, +0.0003967285156250, 0.0053710937500000, 0.0002441406250000, 0.0055236816406250, +0.0000000000000000, 0.0055236816406250, 0.0003967285156250, 0.0061340332031250, +0.0002136230468750, 0.0062255859375000, 0.0002441406250000, 0.0057678222656250, +0.0003662109375000, 0.0060729980468750, 0.0003967285156250, 0.0057067871093750, +0.0003662109375000, 0.0050964355468750, 0.0004882812500000, 0.0055236816406250, +0.0003051757812500, 0.0047302246093750, 0.0004577636718750, 0.0045471191406250, +0.0003662109375000, 0.0047302246093750, 0.0001525878906250, 0.0044860839843750, +0.0004882812500000, 0.0043334960937500, -0.0000305175781250, 0.0048522949218750, +0.0002441406250000, 0.0044250488281250, 0.0000610351562500, 0.0043945312500000, +-0.0003051757812500, 0.0048522949218750, 0.0002136230468750, 0.0043640136718750, +-0.0007324218750000, 0.0043334960937500, -0.0003967285156250, 0.0044860839843750, +-0.0005798339843750, 0.0039367675781250, -0.0014038085937500, 0.0034790039062500, +-0.0007629394531250, 0.0036621093750000, -0.0016174316406250, 0.0029296875000000, +-0.0015563964843750, 0.0028076171875000, -0.0014648437500000, 0.0026855468750000, +-0.0018005371093750, 0.0023498535156250, -0.0015258789062500, 0.0025329589843750, +-0.0015869140625000, 0.0021667480468750, -0.0015869140625000, 0.0023803710937500, +-0.0014343261718750, 0.0021362304687500, -0.0013732910156250, 0.0019226074218750, +-0.0012817382812500, 0.0023498535156250, -0.0010375976562500, 0.0011291503906250, +-0.0012512207031250, 0.0016784667968750, -0.0007324218750000, 0.0012817382812500, +-0.0002746582031250, 0.0001831054687500, -0.0009460449218750, 0.0010070800781250, +0.0000610351562500, -0.0003967285156250, -0.0000610351562500, -0.0002746582031250, +-0.0002136230468750, -0.0001220703125000, 0.0003967285156250, -0.0009155273437500, +0.0002746582031250, -0.0005187988281250, 0.0001831054687500, 0.0002441406250000, +0.0003662109375000, -0.0002746582031250, 0.0003967285156250, 0.0006713867187500, +0.0003051757812500, 0.0018920898437500, 0.0004577636718750, 0.0010070800781250, +0.0007934570312500, 0.0025024414062500, 0.0006408691406250, 0.0025939941406250, +0.0007019042968750, 0.0023803710937500, 0.0010375976562500, 0.0028381347656250, +0.0008239746093750, 0.0026245117187500, 0.0007019042968750, 0.0030212402343750, +0.0007324218750000, 0.0028686523437500, 0.0007324218750000, 0.0029602050781250, +0.0006408691406250, 0.0036315917968750, 0.0019836425781250, -0.0001220703125000, +0.0017700195312500, 0.0020446777343750, 0.0021667480468750, 0.0010375976562500, +0.0015563964843750, 0.0017700195312500, 0.0010681152343750, 0.0034484863281250, +0.0016784667968750, 0.0028076171875000, 0.0005798339843750, 0.0027465820312500, +0.0005493164062500, 0.0035095214843750, 0.0007629394531250, 0.0025634765625000, +0.0003051757812500, 0.0015563964843750, 0.0002746582031250, 0.0023803710937500, +0.0008239746093750, 0.0004272460937500, 0.0005798339843750, 0.0004882812500000, +0.0006103515625000, 0.0003051757812500, 0.0010375976562500, -0.0008239746093750, +0.0008239746093750, -0.0004882812500000, 0.0011596679687500, -0.0013122558593750, +0.0012512207031250, -0.0015869140625000, 0.0014648437500000, -0.0015563964843750, +0.0018005371093750, -0.0020446777343750, 0.0018615722656250, -0.0022583007812500, +0.0024719238281250, -0.0014648437500000, 0.0028076171875000, -0.0021972656250000, +0.0026855468750000, -0.0015563964843750, 0.0029602050781250, -0.0003662109375000, +0.0034179687500000, -0.0012207031250000, 0.0024719238281250, 0.0003662109375000, +0.0028076171875000, 0.0006103515625000, 0.0028076171875000, 0.0002441406250000, +0.0020446777343750}, +{0.0000610351562500, 0.0016174316406250, -0.0000305175781250, 0.0026245117187500, +0.0000915527343750, 0.0019531250000000, -0.0001525878906250, 0.0026550292968750, +0.0000305175781250, 0.0026550292968750, -0.0000305175781250, 0.0023498535156250, +-0.0001831054687500, 0.0023803710937500, 0.0002441406250000, 0.0022277832031250, +-0.0004272460937500, 0.0018920898437500, 0.0001220703125000, 0.0014953613281250, +-0.0001220703125000, 0.0015869140625000, -0.0007629394531250, 0.0014953613281250, +0.0000000000000000, 0.0009765625000000, -0.0010681152343750, 0.0020446777343750, +-0.0008850097656250, 0.0014038085937500, -0.0008850097656250, 0.0018005371093750, +-0.0015258789062500, 0.0029296875000000, -0.0011291503906250, 0.0018920898437500, +-0.0015563964843750, 0.0031127929687500, -0.0015258789062500, 0.0029907226562500, +-0.0015258789062500, 0.0029296875000000, -0.0016479492187500, 0.0035095214843750, +-0.0014038085937500, 0.0031433105468750, -0.0014648437500000, 0.0035705566406250, +-0.0015869140625000, 0.0035400390625000, -0.0013122558593750, 0.0035400390625000, +-0.0011901855468750, 0.0038452148437500, -0.0014953613281250, 0.0038452148437500, +-0.0007629394531250, 0.0041198730468750, -0.0010375976562500, 0.0043334960937500, +-0.0007934570312500, 0.0042724609375000, -0.0001525878906250, 0.0043945312500000, +-0.0006713867187500, 0.0045776367187500, -0.0001525878906250, 0.0038757324218750, +-0.0001525878906250, 0.0043029785156250, -0.0000915527343750, 0.0036010742187500, +0.0002136230468750, 0.0026550292968750, 0.0000915527343750, 0.0034484863281250, +0.0005187988281250, 0.0010375976562500, 0.0005798339843750, 0.0013122558593750, +0.0007629394531250, 0.0007934570312500, 0.0010681152343750, -0.0010986328125000, +0.0010070800781250, -0.0003051757812500, 0.0013427734375000, -0.0007934570312500, +0.0013427734375000, -0.0014953613281250, 0.0014038085937500, -0.0008544921875000, +0.0015869140625000, -0.0003356933593750, 0.0014953613281250, -0.0010070800781250, +0.0017395019531250, -0.0000305175781250, 0.0017089843750000, -0.0002136230468750, +0.0017395019531250, -0.0001831054687500, 0.0020141601562500, 0.0007629394531250, +0.0014648437500000, 0.0002136230468750, 0.0009155273437500, -0.0007934570312500, +0.0006408691406250, -0.0007324218750000, 0.0010375976562500, -0.0006713867187500, +0.0010986328125000, -0.0011901855468750, 0.0005187988281250, -0.0013427734375000, +0.0014953613281250, 0.0000305175781250, 0.0012207031250000, -0.0005493164062500, +0.0010986328125000, 0.0001220703125000, 0.0014953613281250, 0.0016784667968750, +0.0010070800781250, 0.0007934570312500, 0.0014648437500000, 0.0016479492187500, +0.0010375976562500, 0.0020751953125000, 0.0013732910156250, 0.0014343261718750, +0.0019836425781250, 0.0012512207031250, 0.0013732910156250, 0.0015258789062500, +0.0028076171875000, 0.0004272460937500, 0.0027770996093750, 0.0004882812500000, +0.0027465820312500, 0.0001220703125000, 0.0035705566406250, -0.0006408691406250, +0.0033264160156250, -0.0003356933593750, 0.0032043457031250, -0.0014343261718750, +0.0033569335937500, -0.0015258789062500, 0.0035095214843750, -0.0017700195312500, +0.0033264160156250, -0.0026245117187500, 0.0032348632812500, -0.0024719238281250, +0.0044555664062500, -0.0024414062500000, 0.0040283203125000, -0.0029602050781250, +0.0047912597656250, -0.0023498535156250, 0.0063476562500000, -0.0017089843750000, +0.0057067871093750, -0.0022888183593750, 0.0069274902343750, -0.0008850097656250, +0.0076293945312500, -0.0008239746093750, 0.0069885253906250, -0.0007629394531250, +0.0072326660156250, -0.0000305175781250, 0.0079040527343750, -0.0001831054687500, +0.0051574707031250, -0.0002746582031250, 0.0062561035156250, -0.0000610351562500, +0.0052795410156250, -0.0001220703125000, 0.0027465820312500, -0.0002746582031250, +0.0043029785156250, -0.0000915527343750, 0.0010986328125000, -0.0004272460937500, +0.0013732910156250, -0.0003662109375000, 0.0009765625000000, -0.0003356933593750, +-0.0011291503906250, -0.0006713867187500, -0.0001831054687500, -0.0006408691406250, +-0.0016479492187500, -0.0002746582031250, -0.0017395019531250, -0.0004882812500000, +-0.0017700195312500, -0.0002136230468750, -0.0025634765625000, 0.0002441406250000, +-0.0023193359375000, -0.0000305175781250, -0.0023803710937500, 0.0004272460937500, +-0.0028076171875000, 0.0005493164062500, -0.0022888183593750, 0.0003967285156250, +-0.0020141601562500, 0.0004882812500000, -0.0026550292968750, 0.0005187988281250, +-0.0008850097656250, 0.0002441406250000, -0.0016174316406250, 0.0002136230468750, +-0.0010986328125000, 0.0001831054687500, 0.0001831054687500, 0.0000305175781250, +-0.0010375976562500, 0.0000915527343750, 0.0011596679687500, 0.0000915527343750, +0.0003356933593750, 0.0000305175781250, 0.0007324218750000, 0.0001220703125000, +0.0023498535156250, 0.0001831054687500, 0.0008544921875000, 0.0000610351562500, +0.0025939941406250, 0.0003051757812500, 0.0022583007812500, 0.0002136230468750, +0.0019531250000000, 0.0001831054687500, 0.0027465820312500, 0.0002441406250000, +0.0021057128906250, 0.0000305175781250, 0.0021667480468750, 0.0000610351562500, +0.0023193359375000, -0.0002746582031250, 0.0017700195312500, -0.0003051757812500, +0.0014648437500000, -0.0003051757812500, 0.0017700195312500, -0.0007934570312500, +0.0008544921875000, -0.0004882812500000, 0.0009155273437500, -0.0008544921875000, +0.0007934570312500, -0.0008850097656250, 0.0002441406250000, -0.0006408691406250, +0.0005493164062500, -0.0010681152343750, 0.0003356933593750, -0.0006713867187500, +0.0000000000000000, -0.0008544921875000, 0.0002136230468750, -0.0008850097656250, +0.0002746582031250, -0.0005798339843750, -0.0000610351562500, -0.0007324218750000, +0.0003051757812500, -0.0005798339843750, 0.0001525878906250, -0.0005187988281250, +0.0000915527343750, -0.0004882812500000, 0.0001525878906250, -0.0004272460937500, +-0.0000610351562500, -0.0004577636718750, 0.0001220703125000, -0.0001831054687500, +-0.0000610351562500, -0.0003356933593750, 0.0000610351562500, -0.0002136230468750, +0.0003356933593750, 0.0000305175781250, 0.0000915527343750, -0.0001220703125000, +0.0006408691406250, 0.0002441406250000, 0.0004882812500000, 0.0002746582031250, +0.0007934570312500, 0.0003967285156250, 0.0013427734375000, 0.0006713867187500, +0.0010070800781250, 0.0006103515625000, 0.0019531250000000, 0.0008239746093750, +0.0019836425781250, 0.0008850097656250, 0.0022583007812500, 0.0009765625000000, +0.0029907226562500, 0.0010986328125000, 0.0028991699218750, 0.0010375976562500, +0.0035400390625000, 0.0009765625000000, 0.0036010742187500, 0.0010375976562500, +0.0038452148437500, 0.0010070800781250, 0.0043029785156250, 0.0009155273437500, +0.0041198730468750, 0.0009765625000000, 0.0046081542968750, 0.0009155273437500, +0.0046386718750000, 0.0009155273437500, 0.0046386718750000, 0.0009155273437500, +0.0048522949218750, 0.0008850097656250, 0.0046386718750000, 0.0008544921875000, +0.0044555664062500, 0.0007019042968750, 0.0045471191406250, 0.0007629394531250, +0.0041809082031250, 0.0005798339843750, 0.0037841796875000, 0.0003356933593750, +0.0039672851562500, 0.0004882812500000, 0.0029907226562500, 0.0000915527343750, +0.0031127929687500, 0.0002441406250000, 0.0027770996093750, 0.0000915527343750, +0.0020141601562500, -0.0002746582031250, 0.0024108886718750, 0.0000305175781250, +0.0016479492187500, -0.0004272460937500, 0.0015869140625000, -0.0003662109375000, +0.0017089843750000, -0.0004272460937500, 0.0013732910156250, -0.0006713867187500, +0.0015258789062500, -0.0005187988281250, 0.0017700195312500, -0.0007934570312500, +0.0016479492187500, -0.0008239746093750, 0.0017700195312500, -0.0007934570312500, +0.0020446777343750, -0.0009155273437500, 0.0018310546875000, -0.0009765625000000, +0.0020751953125000, -0.0007629394531250, 0.0021972656250000, -0.0008239746093750, +0.0020141601562500, -0.0007019042968750, 0.0019531250000000, -0.0004272460937500, +0.0019836425781250, -0.0004577636718750, 0.0015563964843750, -0.0002746582031250, +0.0016174316406250, -0.0000915527343750, 0.0013427734375000, -0.0000610351562500, +0.0009460449218750, 0.0000000000000000, 0.0010375976562500, 0.0002136230468750, +0.0005493164062500, 0.0001525878906250, 0.0003967285156250, 0.0003051757812500, +0.0003051757812500, 0.0003051757812500, -0.0000610351562500, 0.0002746582031250, +-0.0002746582031250, 0.0004272460937500, -0.0002136230468750, 0.0002441406250000, +-0.0004272460937500, 0.0003662109375000, -0.0003356933593750, 0.0003356933593750, +-0.0000610351562500, 0.0000610351562500, -0.0003051757812500, 0.0002746582031250, +0.0001220703125000, 0.0002441406250000, 0.0001831054687500, 0.0000915527343750, +0.0001831054687500, 0.0003051757812500, 0.0003967285156250, 0.0005187988281250, +0.0004882812500000, 0.0001831054687500, 0.0003967285156250, 0.0005798339843750, +0.0005493164062500, 0.0004272460937500, 0.0005187988281250, 0.0003662109375000, +0.0004272460937500, 0.0005798339843750, 0.0006103515625000, 0.0001831054687500, +0.0003662109375000, 0.0003051757812500, 0.0004882812500000, 0.0002136230468750, +0.0001831054687500, 0.0000610351562500, -0.0001525878906250, 0.0000610351562500, +0.0000915527343750, -0.0000610351562500, -0.0006713867187500, -0.0001220703125000, +-0.0008544921875000, -0.0001831054687500, -0.0007324218750000, -0.0002441406250000, +-0.0010375976562500, -0.0002746582031250, -0.0011291503906250, -0.0003967285156250, +-0.0007629394531250, -0.0003051757812500, -0.0008544921875000, -0.0003356933593750, +-0.0008850097656250, -0.0004272460937500, -0.0004882812500000, -0.0003356933593750, +-0.0002441406250000, -0.0002746582031250, 0.0002136230468750, -0.0003051757812500, +-0.0001220703125000, -0.0003051757812500, 0.0001525878906250, -0.0001831054687500, +0.0006408691406250, -0.0002136230468750, 0.0001525878906250, -0.0001525878906250, +0.0011291503906250, 0.0003662109375000, 0.0010070800781250, 0.0002746582031250, +0.0007934570312500, 0.0006103515625000, 0.0013732910156250, 0.0012512207031250, +0.0012207031250000, 0.0010681152343750, 0.0007019042968750, 0.0014648437500000, +0.0010070800781250, 0.0016784667968750, 0.0006408691406250, 0.0014648437500000, +0.0000610351562500, 0.0014953613281250, 0.0005493164062500, 0.0016479492187500, +-0.0001220703125000, 0.0010681152343750, -0.0000610351562500, 0.0011291503906250, +-0.0001525878906250, 0.0011596679687500, -0.0005798339843750, 0.0006408691406250, +-0.0002746582031250, 0.0006713867187500, -0.0006713867187500, 0.0010681152343750, +-0.0007324218750000, 0.0007019042968750, -0.0004577636718750, 0.0011596679687500, +-0.0005493164062500, 0.0017395019531250, -0.0007324218750000, 0.0011291503906250, +0.0002136230468750, 0.0026550292968750, -0.0001525878906250, 0.0023803710937500, +0.0001525878906250, 0.0024414062500000, 0.0009765625000000, 0.0034484863281250, +0.0003356933593750, 0.0030212402343750, 0.0013122558593750, 0.0026245117187500, +0.0012817382812500, 0.0030822753906250, 0.0011596679687500, 0.0022888183593750, +0.0016784667968750, 0.0014343261718750, 0.0014343261718750, 0.0020141601562500, +0.0013122558593750, 0.0004882812500000, 0.0014953613281250, 0.0004272460937500, +0.0010986328125000, 0.0003051757812500, 0.0007629394531250, -0.0005493164062500, +0.0010681152343750, -0.0003662109375000, 0.0002441406250000, -0.0007324218750000, +0.0003662109375000, -0.0008544921875000, 0.0002746582031250, -0.0008544921875000, +-0.0003051757812500, -0.0008850097656250, 0.0000000000000000, -0.0008850097656250, +-0.0006103515625000}, +{0.0037536621093750, 0.0000915527343750, 0.0035400390625000, 0.0001525878906250, +0.0034790039062500, 0.0000915527343750, 0.0032043457031250, 0.0001525878906250, +0.0029296875000000, 0.0001220703125000, 0.0030517578125000, 0.0000000000000000, +0.0021362304687500, 0.0003356933593750, 0.0022583007812500, 0.0000915527343750, +0.0018920898437500, 0.0002136230468750, 0.0010375976562500, 0.0005493164062500, +0.0014038085937500, 0.0002136230468750, 0.0005187988281250, 0.0004882812500000, +0.0005187988281250, 0.0003662109375000, 0.0003662109375000, 0.0003662109375000, +-0.0000305175781250, 0.0004577636718750, 0.0002441406250000, 0.0001525878906250, +0.0000000000000000, 0.0003967285156250, 0.0000305175781250, 0.0001220703125000, +0.0000305175781250, 0.0000305175781250, 0.0000305175781250, 0.0002136230468750, +0.0003356933593750, -0.0000610351562500, 0.0000000000000000, -0.0000915527343750, +0.0000000000000000, -0.0001220703125000, 0.0001831054687500, -0.0003356933593750, +0.0001525878906250, -0.0005187988281250, 0.0000915527343750, -0.0004882812500000, +0.0000610351562500, -0.0005798339843750, 0.0001525878906250, -0.0008544921875000, +-0.0000915527343750, -0.0007629394531250, -0.0003356933593750, -0.0007019042968750, +-0.0001525878906250, -0.0009155273437500, -0.0005187988281250, -0.0006713867187500, +-0.0005798339843750, -0.0007934570312500, -0.0004577636718750, -0.0005493164062500, +-0.0005187988281250, -0.0001525878906250, -0.0005493164062500, -0.0002136230468750, +-0.0001220703125000, 0.0005798339843750, -0.0003967285156250, 0.0003356933593750, +-0.0003967285156250, 0.0004882812500000, -0.0000915527343750, 0.0012512207031250, +-0.0003051757812500, 0.0011291503906250, 0.0000915527343750, 0.0012207031250000, +-0.0001831054687500, 0.0015563964843750, -0.0000610351562500, 0.0013122558593750, +0.0003967285156250, 0.0010986328125000, 0.0000000000000000, 0.0014648437500000, +0.0005187988281250, 0.0007629394531250, 0.0005493164062500, 0.0009460449218750, +0.0004272460937500, 0.0009460449218750, 0.0005493164062500, 0.0005493164062500, +0.0005798339843750, 0.0008239746093750, 0.0003051757812500, 0.0007324218750000, +0.0003356933593750, 0.0005493164062500, 0.0003356933593750, 0.0009155273437500, +0.0000915527343750, 0.0011901855468750, 0.0000915527343750, 0.0008544921875000, +-0.0001220703125000, 0.0014648437500000, -0.0000915527343750, 0.0014343261718750, +-0.0002746582031250, 0.0013732910156250, -0.0005187988281250, 0.0017089843750000, +-0.0003662109375000, 0.0014648437500000, -0.0005493164062500, 0.0012817382812500, +-0.0007934570312500, 0.0013732910156250, -0.0005493164062500, 0.0009765625000000, +-0.0003967285156250, 0.0004272460937500, -0.0007324218750000, 0.0005187988281250, +-0.0000305175781250, 0.0002441406250000, -0.0003051757812500, -0.0001831054687500, +-0.0001831054687500, 0.0001831054687500, 0.0004272460937500, 0.0003967285156250, +0.0000000000000000, 0.0000305175781250, 0.0005798339843750, 0.0012207031250000, +0.0004272460937500, 0.0008239746093750, 0.0004272460937500, 0.0013122558593750, +0.0007324218750000, 0.0023193359375000, 0.0004272460937500, 0.0015869140625000, +0.0006103515625000, 0.0032958984375000, 0.0006103515625000, 0.0029907226562500, +0.0003967285156250, 0.0035095214843750, 0.0004272460937500, 0.0048522949218750, +0.0005187988281250, 0.0040893554687500, 0.0000000000000000, 0.0056152343750000, +0.0001525878906250, 0.0057067871093750, 0.0000305175781250, 0.0059814453125000, +-0.0003967285156250, 0.0068969726562500, -0.0001831054687500, 0.0066833496093750, +-0.0005798339843750, 0.0074157714843750, -0.0005493164062500, 0.0075988769531250, +-0.0008239746093750, 0.0077209472656250, -0.0011901855468750, 0.0081176757812500, +-0.0009765625000000, 0.0081176757812500, -0.0016479492187500, 0.0081787109375000, +-0.0016784667968750, 0.0083923339843750, -0.0015563964843750, 0.0083007812500000, +-0.0018920898437500, 0.0083007812500000, -0.0019226074218750, 0.0086059570312500, +-0.0014038085937500, 0.0080261230468750, -0.0017700195312500, 0.0083007812500000, +-0.0013732910156250, 0.0080871582031250, -0.0006713867187500, 0.0076293945312500, +-0.0012817382812500, 0.0081176757812500, -0.0001525878906250, 0.0071411132812500, +-0.0003356933593750, 0.0073547363281250, -0.0002136230468750, 0.0072631835937500, +0.0005493164062500, 0.0065612792968750, 0.0000000000000000, 0.0071411132812500, +0.0004882812500000, 0.0065917968750000, 0.0003662109375000, 0.0067138671875000, +0.0001831054687500, 0.0069274902343750, 0.0003662109375000, 0.0068359375000000, +0.0002136230468750, 0.0070800781250000, 0.0001831054687500, 0.0073242187500000, +0.0002136230468750, 0.0074157714843750, 0.0002136230468750, 0.0076904296875000, +0.0002136230468750, 0.0080261230468750, 0.0003662109375000, 0.0079956054687500, +0.0002441406250000, 0.0081176757812500, 0.0005187988281250, 0.0084533691406250, +0.0003967285156250, 0.0081176757812500, 0.0002441406250000, 0.0079345703125000, +0.0007324218750000, 0.0083007812500000, 0.0000305175781250, 0.0070800781250000, +0.0003967285156250, 0.0075073242187500, 0.0003967285156250, 0.0068969726562500, +-0.0000305175781250, 0.0057373046875000, 0.0004272460937500, 0.0065002441406250, +-0.0000610351562500, 0.0046691894531250, 0.0001525878906250, 0.0048828125000000, +0.0001525878906250, 0.0044860839843750, -0.0000915527343750, 0.0031433105468750, +0.0002746582031250, 0.0038452148437500, 0.0000305175781250, 0.0026550292968750, +0.0001831054687500, 0.0027465820312500, 0.0002441406250000, 0.0027465820312500, +0.0001220703125000, 0.0021362304687500, 0.0003051757812500, 0.0025634765625000, +0.0002441406250000, 0.0027465820312500, 0.0001220703125000, 0.0026550292968750, +0.0002136230468750, 0.0031738281250000, 0.0001831054687500, 0.0036315917968750, +-0.0001525878906250, 0.0036315917968750, 0.0002441406250000, 0.0045166015625000, +-0.0002441406250000, 0.0047302246093750, -0.0001525878906250, 0.0050354003906250, +0.0002746582031250, 0.0057373046875000, -0.0004577636718750, 0.0058288574218750, +0.0002746582031250, 0.0061035156250000, -0.0000305175781250, 0.0065307617187500, +-0.0000915527343750, 0.0065612792968750, 0.0004272460937500, 0.0066223144531250, +0.0000610351562500, 0.0069885253906250, 0.0004882812500000, 0.0065307617187500, +0.0005187988281250, 0.0068054199218750, 0.0004577636718750, 0.0067443847656250, +0.0007019042968750, 0.0062866210937500, 0.0005798339843750, 0.0066528320312500, +0.0005187988281250, 0.0061340332031250, 0.0005493164062500, 0.0061950683593750, +0.0004272460937500, 0.0062255859375000, 0.0002746582031250, 0.0059814453125000, +0.0003662109375000, 0.0061340332031250, -0.0000610351562500, 0.0057678222656250, +0.0001220703125000, 0.0058288574218750, -0.0000915527343750, 0.0055847167968750, +-0.0004577636718750, 0.0052185058593750, 0.0000000000000000, 0.0052795410156250, +-0.0007324218750000, 0.0046386718750000, -0.0005798339843750, 0.0045166015625000, +-0.0006103515625000, 0.0044250488281250, -0.0010681152343750, 0.0040283203125000, +-0.0007019042968750, 0.0039672851562500, -0.0010375976562500, 0.0041503906250000, +-0.0010375976562500, 0.0039062500000000, -0.0009765625000000, 0.0040893554687500, +-0.0011596679687500, 0.0045166015625000, -0.0011291503906250, 0.0042419433593750, +-0.0010070800781250, 0.0047607421875000, -0.0011291503906250, 0.0049133300781250, +-0.0009765625000000, 0.0046691894531250, -0.0007934570312500, 0.0047607421875000, +-0.0009460449218750, 0.0048522949218750, -0.0003967285156250, 0.0038146972656250, +-0.0006103515625000, 0.0039978027343750, -0.0005798339843750, 0.0033874511718750, +-0.0002746582031250, 0.0024108886718750, -0.0007324218750000, 0.0029296875000000, +-0.0003356933593750, 0.0016174316406250, -0.0005798339843750, 0.0016784667968750, +-0.0005798339843750, 0.0015258789062500, -0.0003662109375000, 0.0006713867187500, +-0.0007019042968750, 0.0010375976562500, -0.0000915527343750, 0.0002441406250000, +-0.0001831054687500, 0.0002441406250000, -0.0000305175781250, 0.0001831054687500, +0.0004882812500000, -0.0003051757812500, 0.0002441406250000, -0.0000915527343750, +0.0006103515625000, -0.0002746582031250, 0.0006713867187500, -0.0004272460937500, +0.0007324218750000, -0.0003051757812500, 0.0009460449218750, -0.0003356933593750, +0.0008239746093750, -0.0004272460937500, 0.0012207031250000, 0.0002441406250000, +0.0011291503906250, -0.0001831054687500, 0.0011291503906250, 0.0007629394531250, +0.0013732910156250, 0.0016784667968750, 0.0012512207031250, 0.0007019042968750, +0.0010681152343750, 0.0035095214843750, 0.0011901855468750, 0.0030822753906250, +0.0009155273437500, 0.0032653808593750, 0.0005493164062500, 0.0050964355468750, +0.0007324218750000, 0.0041809082031250, 0.0006103515625000, 0.0044860839843750, +0.0003662109375000, 0.0048217773437500, 0.0006713867187500, 0.0043334960937500, +0.0011901855468750, 0.0037231445312500, 0.0011291503906250, 0.0023803710937500, +0.0018920898437500, 0.0035400390625000, 0.0012512207031250, 0.0035095214843750, +0.0017089843750000, 0.0036315917968750, 0.0021057128906250, 0.0039672851562500, +0.0014038085937500, 0.0038757324218750, 0.0028991699218750, 0.0035400390625000, +0.0024719238281250, 0.0040588378906250, 0.0026855468750000, 0.0032043457031250, +0.0038757324218750, 0.0023498535156250, 0.0030517578125000, 0.0032653808593750, +0.0036621093750000, 0.0006408691406250, 0.0038452148437500, 0.0010070800781250, +0.0035400390625000, 0.0007934570312500, 0.0035705566406250, -0.0009765625000000, +0.0036315917968750, -0.0002746582031250, 0.0036621093750000, -0.0003967285156250, +0.0036315917968750, -0.0009765625000000, 0.0035705566406250, -0.0005798339843750, +0.0036926269531250, -0.0000915527343750, 0.0036926269531250, -0.0005493164062500, +0.0027160644531250, 0.0000305175781250, 0.0031433105468750, -0.0000915527343750, +0.0022888183593750, -0.0001831054687500, 0.0010070800781250, -0.0000305175781250, +0.0018310546875000, -0.0002746582031250, 0.0001831054687500, 0.0000915527343750, +0.0002441406250000, -0.0000915527343750, 0.0003051757812500, -0.0001525878906250, +-0.0005187988281250, 0.0002136230468750, -0.0000305175781250, 0.0000305175781250, +0.0003662109375000, -0.0005493164062500, 0.0001220703125000, -0.0002441406250000, +0.0007934570312500, -0.0007019042968750, 0.0015563964843750, -0.0015869140625000, +0.0011596679687500, -0.0011291503906250, 0.0025329589843750, -0.0015869140625000, +0.0023498535156250, -0.0018615722656250, 0.0029296875000000, -0.0015563964843750, +0.0040283203125000, -0.0014038085937500, 0.0033264160156250, -0.0016174316406250, +0.0053710937500000, -0.0010681152343750, 0.0051269531250000, -0.0010986328125000, +0.0057373046875000, -0.0010070800781250, 0.0072937011718750, -0.0005187988281250, +0.0064697265625000, -0.0006713867187500, 0.0084533691406250, -0.0002136230468750, +0.0083618164062500, -0.0001220703125000, 0.0086059570312500, -0.0002136230468750, +0.0098571777343750, -0.0001525878906250, 0.0093383789062500, -0.0000305175781250, +0.0097351074218750, -0.0005493164062500, 0.0100402832031250, -0.0004272460937500, +0.0097961425781250, -0.0004882812500000, 0.0096435546875000, -0.0009155273437500, +0.0098266601562500, -0.0007019042968750, 0.0098266601562500, -0.0006713867187500, +0.0096435546875000, -0.0008239746093750, 0.0098876953125000, -0.0005187988281250, +0.0099792480468750, -0.0001525878906250, 0.0097351074218750, -0.0003051757812500, +0.0105590820312500, 0.0000000000000000, 0.0101318359375000, 0.0001220703125000, +0.0104980468750000}, +{0.0005187988281250, 0.0024108886718750, 0.0004882812500000, 0.0022583007812500, +0.0004272460937500, 0.0016479492187500, 0.0004882812500000, 0.0017395019531250, +0.0002441406250000, 0.0012817382812500, 0.0003356933593750, 0.0011596679687500, +0.0002136230468750, 0.0007934570312500, -0.0001220703125000, 0.0002746582031250, +0.0000000000000000, 0.0004577636718750, 0.0000000000000000, 0.0000610351562500, +-0.0002746582031250, -0.0003967285156250, 0.0000610351562500, 0.0001831054687500, +0.0003967285156250, 0.0003967285156250, 0.0001831054687500, -0.0003051757812500, +0.0010375976562500, 0.0015869140625000, 0.0009765625000000, 0.0012512207031250, +0.0009460449218750, 0.0014343261718750, 0.0016174316406250, 0.0034790039062500, +0.0019226074218750, 0.0000305175781250, 0.0031738281250000, 0.0007324218750000, +0.0027770996093750, 0.0002746582031250, 0.0030212402343750, 0.0007629394531250, +0.0036315917968750, 0.0014953613281250, 0.0033874511718750, 0.0012207031250000, +0.0032043457031250, 0.0021972656250000, 0.0035400390625000, 0.0021362304687500, +0.0031738281250000, 0.0024719238281250, 0.0026550292968750, 0.0033264160156250, +0.0030517578125000, 0.0029602050781250, 0.0024414062500000, 0.0033569335937500, +0.0026245117187500, 0.0038757324218750, 0.0024108886718750, 0.0032348632812500, +0.0020141601562500, 0.0028686523437500, 0.0025024414062500, 0.0035705566406250, +0.0014038085937500, 0.0016479492187500, 0.0016174316406250, 0.0018920898437500, +0.0013122558593750, 0.0015869140625000, 0.0002136230468750, 0.0002136230468750, +0.0006408691406250, 0.0007629394531250, 0.0006408691406250, 0.0002441406250000, +-0.0000305175781250, -0.0000915527343750, 0.0007629394531250, 0.0001831054687500, +0.0016479492187500, 0.0002441406250000, 0.0010681152343750, -0.0000915527343750, +0.0027465820312500, 0.0001831054687500, 0.0026550292968750, 0.0000000000000000, +0.0030212402343750, -0.0000610351562500, 0.0041198730468750, 0.0000610351562500, +0.0036621093750000, -0.0002441406250000, 0.0048828125000000, 0.0003356933593750, +0.0048522949218750, 0.0001525878906250, 0.0052490234375000, 0.0001220703125000, +0.0059814453125000, 0.0005798339843750, 0.0055541992187500, 0.0004272460937500, +0.0072631835937500, -0.0000915527343750, 0.0069885253906250, 0.0001220703125000, +0.0075683593750000, -0.0001831054687500, 0.0090637207031250, -0.0007629394531250, +0.0084228515625000, -0.0004272460937500, 0.0094604492187500, -0.0009155273437500, +0.0099182128906250, -0.0010070800781250, 0.0096130371093750, -0.0009460449218750, +0.0099487304687500, -0.0010681152343750, 0.0104064941406250, -0.0010375976562500, +0.0095214843750000, -0.0007934570312500, 0.0100402832031250, -0.0008544921875000, +0.0099487304687500, -0.0005798339843750, 0.0092163085937500, -0.0003051757812500, +0.0098876953125000, -0.0004272460937500, 0.0097045898437500, 0.0000000000000000, +0.0095520019531250, 0.0001525878906250, 0.0101013183593750, 0.0000610351562500, +0.0103759765625000, 0.0001525878906250, 0.0101623535156250, 0.0002136230468750, +0.0111389160156250, -0.0003051757812500, 0.0110778808593750, -0.0001525878906250, +0.0111694335937500, -0.0002746582031250, 0.0117797851562500, -0.0007934570312500, +0.0114135742187500, -0.0006103515625000, 0.0115051269531250, -0.0007019042968750, +0.0116271972656250, -0.0008239746093750, 0.0110168457031250, -0.0006713867187500, +0.0106811523437500, -0.0005187988281250, 0.0109252929687500, -0.0006713867187500, +0.0095825195312500, -0.0002441406250000, 0.0097045898437500, -0.0003356933593750, +0.0092468261718750, -0.0002441406250000, 0.0082397460937500, 0.0001525878906250, +0.0087280273437500, -0.0000305175781250, 0.0076904296875000, 0.0001220703125000, +0.0076904296875000, 0.0002441406250000, 0.0074768066406250, 0.0000305175781250, +0.0068969726562500, -0.0000305175781250, 0.0072631835937500, 0.0000915527343750, +0.0067749023437500, -0.0003662109375000, 0.0067138671875000, -0.0003051757812500, +0.0069580078125000, -0.0003662109375000, 0.0067749023437500, -0.0006103515625000, +0.0067138671875000, -0.0005798339843750, 0.0075073242187500, -0.0004272460937500, +0.0070495605468750, -0.0006103515625000, 0.0075683593750000, -0.0003967285156250, +0.0084228515625000, -0.0001525878906250, 0.0076293945312500, -0.0003356933593750, +0.0090942382812500, 0.0002746582031250, 0.0087585449218750, 0.0003051757812500, +0.0089721679687500, 0.0003967285156250, 0.0099182128906250, 0.0008544921875000, +0.0090942382812500, 0.0008544921875000, 0.0101013183593750, 0.0009460449218750, +0.0099487304687500, 0.0011901855468750, 0.0099792480468750, 0.0012207031250000, +0.0105895996093750, 0.0011901855468750, 0.0101928710937500, 0.0013427734375000, +0.0107116699218750, 0.0010986328125000, 0.0107116699218750, 0.0012207031250000, +0.0106506347656250, 0.0010681152343750, 0.0109252929687500, 0.0007629394531250, +0.0107727050781250, 0.0009460449218750, 0.0106201171875000, 0.0004882812500000, +0.0106811523437500, 0.0005493164062500, 0.0103454589843750, 0.0004577636718750, +0.0100708007812500, 0.0001220703125000, 0.0100708007812500, 0.0002136230468750, +0.0091552734375000, -0.0000915527343750, 0.0092773437500000, -0.0000305175781250, +0.0086669921875000, -0.0001220703125000, 0.0077514648437500, -0.0003967285156250, +0.0082092285156250, -0.0002136230468750, 0.0065917968750000, -0.0005798339843750, +0.0066833496093750, -0.0006103515625000, 0.0061340332031250, -0.0005798339843750, +0.0049743652343750, -0.0007629394531250, 0.0054016113281250, -0.0007934570312500, +0.0045471191406250, -0.0008544921875000, 0.0043334960937500, -0.0009765625000000, +0.0045471191406250, -0.0009765625000000, 0.0042724609375000, -0.0010070800781250, +0.0042724609375000, -0.0010681152343750, 0.0049438476562500, -0.0009765625000000, +0.0047912597656250, -0.0010070800781250, 0.0052795410156250, -0.0010375976562500, +0.0060424804687500, -0.0008850097656250, 0.0057067871093750, -0.0009155273437500, +0.0067749023437500, -0.0007324218750000, 0.0069274902343750, -0.0007019042968750, +0.0068969726562500, -0.0007324218750000, 0.0075073242187500, -0.0006408691406250, +0.0075378417968750, -0.0004882812500000, 0.0073242187500000, -0.0006103515625000, +0.0077514648437500, -0.0004577636718750, 0.0073242187500000, -0.0003967285156250, +0.0068969726562500, -0.0004882812500000, 0.0073852539062500, -0.0003356933593750, +0.0061645507812500, -0.0003662109375000, 0.0062866210937500, -0.0003356933593750, +0.0061645507812500, -0.0003356933593750, 0.0052795410156250, -0.0003967285156250, +0.0055541992187500, -0.0003662109375000, 0.0053100585937500, -0.0002746582031250, +0.0051269531250000, -0.0003967285156250, 0.0054016113281250, -0.0002441406250000, +0.0055541992187500, -0.0000610351562500, 0.0055236816406250, -0.0002136230468750, +0.0060424804687500, 0.0000915527343750, 0.0060729980468750, 0.0000610351562500, +0.0062561035156250, 0.0000610351562500, 0.0066528320312500, 0.0002136230468750, +0.0065002441406250, 0.0002136230468750, 0.0065002441406250, 0.0000915527343750, +0.0065917968750000, 0.0000000000000000, 0.0065002441406250, 0.0001220703125000, +0.0064086914062500, 0.0000610351562500, 0.0063171386718750, -0.0001525878906250, +0.0062255859375000, 0.0000000000000000, 0.0061950683593750, -0.0000610351562500, +0.0058898925781250, -0.0003051757812500, 0.0057678222656250, -0.0003662109375000, +0.0058593750000000, -0.0003356933593750, 0.0048217773437500, -0.0007324218750000, +0.0052490234375000, -0.0007324218750000, 0.0045471191406250, -0.0006103515625000, +0.0033874511718750, -0.0008239746093750, 0.0040893554687500, -0.0008239746093750, +0.0025939941406250, -0.0003662109375000, 0.0027465820312500, -0.0006713867187500, +0.0026550292968750, -0.0002441406250000, 0.0018005371093750, 0.0003051757812500, +0.0022583007812500, -0.0001831054687500, 0.0018005371093750, 0.0007629394531250, +0.0018005371093750, 0.0007324218750000, 0.0018310546875000, 0.0006713867187500, +0.0016174316406250, 0.0012207031250000, 0.0018310546875000, 0.0011596679687500, +0.0015258789062500, 0.0010375976562500, 0.0014953613281250, 0.0014038085937500, +0.0014343261718750, 0.0011901855468750, 0.0013732910156250, 0.0006408691406250, +0.0012817382812500, 0.0007629394531250, 0.0009765625000000, 0.0006103515625000, +0.0012817382812500, 0.0004882812500000, 0.0010681152343750, 0.0007324218750000, +0.0007019042968750, 0.0008239746093750, 0.0011291503906250, 0.0007019042968750, +0.0004882812500000, 0.0011596679687500, 0.0006103515625000, 0.0013122558593750, +0.0005493164062500, 0.0013427734375000, 0.0000915527343750, 0.0017089843750000, +0.0002746582031250, 0.0018005371093750, -0.0000305175781250, 0.0015258789062500, +-0.0002746582031250, 0.0018615722656250, -0.0002136230468750, 0.0016479492187500, +-0.0003967285156250, 0.0012207031250000, -0.0005187988281250, 0.0017395019531250, +-0.0000915527343750, 0.0010375976562500, -0.0003662109375000, 0.0012512207031250, +-0.0000915527343750, 0.0014038085937500, 0.0003662109375000, 0.0009460449218750, +-0.0000305175781250, 0.0012207031250000, 0.0007324218750000, 0.0021057128906250, +0.0006713867187500, 0.0018310546875000, 0.0005798339843750, 0.0025024414062500, +0.0008850097656250, 0.0034790039062500, 0.0007324218750000, 0.0029602050781250, +0.0004272460937500, 0.0047912597656250, 0.0007629394531250, 0.0045166015625000, +0.0003051757812500, 0.0048522949218750, -0.0001831054687500, 0.0061340332031250, +0.0003967285156250, 0.0055847167968750, -0.0007019042968750, 0.0064392089843750, +-0.0005493164062500, 0.0065002441406250, -0.0006103515625000, 0.0067138671875000, +-0.0013732910156250, 0.0073242187500000, -0.0009460449218750, 0.0070190429687500, +-0.0010681152343750, 0.0074157714843750, -0.0012817382812500, 0.0075988769531250, +-0.0010070800781250, 0.0074768066406250, -0.0007019042968750, 0.0075378417968750, +-0.0009765625000000, 0.0076293945312500, -0.0004882812500000, 0.0070495605468750, +-0.0004882812500000, 0.0071411132812500, -0.0005187988281250, 0.0070190429687500, +-0.0003051757812500, 0.0065612792968750, -0.0005187988281250, 0.0067443847656250, +-0.0004272460937500, 0.0068359375000000, -0.0005493164062500, 0.0065917968750000, +-0.0005493164062500, 0.0068054199218750, -0.0005187988281250, 0.0071105957031250, +-0.0006713867187500, 0.0068664550781250, -0.0004272460937500, 0.0071716308593750, +-0.0005187988281250, 0.0072631835937500, -0.0004882812500000, 0.0069580078125000, +-0.0003356933593750, 0.0068664550781250, -0.0004272460937500, 0.0070800781250000, +-0.0004272460937500, 0.0063781738281250, -0.0003967285156250, 0.0064392089843750, +-0.0004882812500000, 0.0064086914062500, -0.0004882812500000, 0.0059204101562500, +-0.0004577636718750, 0.0061035156250000, -0.0007934570312500, 0.0063171386718750, +-0.0006408691406250, 0.0060119628906250, -0.0009155273437500, 0.0064697265625000, +-0.0012817382812500, 0.0069274902343750, -0.0010070800781250, 0.0065612792968750, +-0.0016784667968750, 0.0076904296875000, -0.0017089843750000, 0.0076293945312500, +-0.0016174316406250, 0.0079040527343750, -0.0019226074218750, 0.0086669921875000, +-0.0018615722656250, 0.0083923339843750, -0.0013732910156250, 0.0089721679687500, +-0.0016784667968750, 0.0091247558593750, -0.0012817382812500, 0.0090026855468750, +-0.0007019042968750, 0.0092468261718750, -0.0010986328125000, 0.0093078613281250, +0.0000000000000000, 0.0089721679687500, -0.0001220703125000, 0.0091247558593750, +0.0000305175781250, 0.0090026855468750, 0.0007934570312500, 0.0086669921875000, +0.0004882812500000}, +{0.0019531250000000, 0.0004577636718750, 0.0016174316406250, 0.0005798339843750, +0.0009460449218750, 0.0007629394531250, 0.0011291503906250, 0.0007324218750000, +0.0010681152343750, 0.0007934570312500, 0.0006713867187500, 0.0010070800781250, +0.0008850097656250, 0.0010681152343750, 0.0008239746093750, 0.0010681152343750, +0.0008544921875000, 0.0011596679687500, 0.0009460449218750, 0.0011596679687500, +0.0010070800781250, 0.0011291503906250, 0.0010375976562500, 0.0013122558593750, +0.0009765625000000, 0.0012207031250000, 0.0011291503906250, 0.0010681152343750, +0.0010375976562500, 0.0015258789062500, 0.0008850097656250, 0.0018005371093750, +0.0009460449218750, 0.0015869140625000, 0.0004882812500000, 0.0030517578125000, +0.0005493164062500, 0.0026550292968750, 0.0003662109375000, 0.0035400390625000, +-0.0000915527343750, 0.0050659179687500, 0.0000610351562500, 0.0041809082031250, +0.0001220703125000, 0.0061340332031250, -0.0001525878906250, 0.0064086914062500, +0.0001525878906250, 0.0063476562500000, 0.0005493164062500, 0.0072021484375000, +0.0001220703125000, 0.0070495605468750, 0.0009155273437500, 0.0069274902343750, +0.0007629394531250, 0.0073547363281250, 0.0007629394531250, 0.0071105957031250, +0.0012207031250000, 0.0067138671875000, 0.0009765625000000, 0.0071411132812500, +0.0009460449218750, 0.0063171386718750, 0.0011291503906250, 0.0066528320312500, +0.0008239746093750, 0.0063781738281250, 0.0005493164062500, 0.0057678222656250, +0.0008239746093750, 0.0062255859375000, -0.0000305175781250, 0.0050964355468750, +0.0001525878906250, 0.0052490234375000, -0.0000610351562500, 0.0051574707031250, +-0.0007324218750000, 0.0044250488281250, -0.0002136230468750, 0.0047912597656250, +-0.0006713867187500, 0.0045166015625000, -0.0006408691406250, 0.0043334960937500, +-0.0004272460937500, 0.0044860839843750, -0.0004272460937500, 0.0045776367187500, +-0.0004577636718750, 0.0045166015625000, -0.0002441406250000, 0.0043029785156250, +-0.0001831054687500, 0.0043945312500000, -0.0002441406250000, 0.0039062500000000, +-0.0002136230468750, 0.0035095214843750, -0.0001525878906250, 0.0037841796875000, +-0.0003051757812500, 0.0025329589843750, -0.0001831054687500, 0.0025634765625000, +-0.0002136230468750, 0.0023193359375000, -0.0003662109375000, 0.0014648437500000, +-0.0002136230468750, 0.0018005371093750, -0.0003967285156250, 0.0018310546875000, +-0.0003356933593750, 0.0014953613281250, -0.0003967285156250, 0.0019226074218750, +-0.0006103515625000, 0.0023498535156250, -0.0005187988281250, 0.0020751953125000, +-0.0008239746093750, 0.0029296875000000, -0.0007934570312500, 0.0028381347656250, +-0.0008544921875000, 0.0028991699218750, -0.0010375976562500, 0.0034484863281250, +-0.0009765625000000, 0.0032653808593750, -0.0011596679687500, 0.0033569335937500, +-0.0010681152343750, 0.0034790039062500, -0.0011291503906250, 0.0033264160156250, +-0.0013122558593750, 0.0031738281250000, -0.0011901855468750, 0.0032958984375000, +-0.0013732910156250, 0.0029907226562500, -0.0013732910156250, 0.0029602050781250, +-0.0013427734375000, 0.0031127929687500, -0.0013732910156250, 0.0029907226562500, +-0.0013427734375000, 0.0028381347656250, -0.0012207031250000, 0.0036010742187500, +-0.0012207031250000, 0.0031433105468750, -0.0010070800781250, 0.0037231445312500, +-0.0007934570312500, 0.0045776367187500, -0.0007629394531250, 0.0038146972656250, +-0.0003356933593750, 0.0055847167968750, -0.0002136230468750, 0.0052490234375000, +0.0000000000000000, 0.0055541992187500, 0.0003967285156250, 0.0068359375000000, +0.0004882812500000, 0.0062561035156250, 0.0005798339843750, 0.0072937011718750, +0.0008850097656250, 0.0073242187500000, 0.0009155273437500, 0.0072937011718750, +0.0009460449218750, 0.0078430175781250, 0.0011901855468750, 0.0076599121093750, +0.0008850097656250, 0.0076293945312500, 0.0010681152343750, 0.0079040527343750, +0.0010986328125000, 0.0075683593750000, 0.0008239746093750, 0.0072631835937500, +0.0009460449218750, 0.0075378417968750, 0.0008850097656250, 0.0064086914062500, +0.0007629394531250, 0.0067138671875000, 0.0008544921875000, 0.0061950683593750, +0.0008544921875000, 0.0052490234375000, 0.0006408691406250, 0.0058898925781250, +0.0008239746093750, 0.0042724609375000, 0.0007324218750000, 0.0045471191406250, +0.0006408691406250, 0.0042724609375000, 0.0007934570312500, 0.0032043457031250, +0.0006713867187500, 0.0038757324218750, 0.0006103515625000, 0.0029296875000000, +0.0007324218750000, 0.0029907226562500, 0.0005798339843750, 0.0030822753906250, +0.0004272460937500, 0.0025939941406250, 0.0006408691406250, 0.0028991699218750, +0.0002136230468750, 0.0026550292968750, 0.0003051757812500, 0.0026550292968750, +0.0002136230468750, 0.0027770996093750, -0.0000915527343750, 0.0027465820312500, +0.0000915527343750, 0.0028076171875000, -0.0003662109375000, 0.0025634765625000, +-0.0001220703125000, 0.0028381347656250, -0.0002441406250000, 0.0024719238281250, +-0.0005493164062500, 0.0020141601562500, -0.0000610351562500, 0.0023498535156250, +-0.0006103515625000, 0.0014648437500000, -0.0003051757812500, 0.0015869140625000, +-0.0002441406250000, 0.0014038085937500, -0.0005493164062500, 0.0007629394531250, +-0.0000915527343750, 0.0011596679687500, -0.0004882812500000, 0.0009765625000000, +-0.0003967285156250, 0.0008544921875000, -0.0002746582031250, 0.0012512207031250, +-0.0005493164062500, 0.0015563964843750, -0.0003967285156250, 0.0014343261718750, +-0.0003051757812500, 0.0022583007812500, -0.0004272460937500, 0.0023498535156250, +-0.0002746582031250, 0.0024108886718750, -0.0000610351562500, 0.0029296875000000, +-0.0002441406250000, 0.0029296875000000, 0.0000915527343750, 0.0027465820312500, +-0.0000915527343750, 0.0032043457031250, 0.0000000000000000, 0.0030212402343750, +0.0001220703125000, 0.0026245117187500, -0.0003356933593750, 0.0031127929687500, +0.0002441406250000, 0.0023193359375000, -0.0000915527343750, 0.0025634765625000, +-0.0000610351562500, 0.0025024414062500, 0.0002746582031250, 0.0019226074218750, +-0.0002136230468750, 0.0022277832031250, 0.0003051757812500, 0.0019531250000000, +0.0003662109375000, 0.0018920898437500, 0.0002136230468750, 0.0021667480468750, +0.0003967285156250, 0.0021972656250000, 0.0003051757812500, 0.0020751953125000, +0.0002136230468750, 0.0031433105468750, 0.0002746582031250, 0.0026855468750000, +0.0003051757812500, 0.0033569335937500, 0.0002746582031250, 0.0045166015625000, +0.0002746582031250, 0.0037231445312500, 0.0002441406250000, 0.0052185058593750, +0.0003356933593750, 0.0051574707031250, 0.0001525878906250, 0.0052795410156250, +-0.0000610351562500, 0.0060119628906250, 0.0002746582031250, 0.0054321289062500, +0.0001220703125000, 0.0059814453125000, 0.0002746582031250, 0.0057067871093750, +0.0004577636718750, 0.0056152343750000, 0.0004882812500000, 0.0058898925781250, +0.0007019042968750, 0.0056457519531250, 0.0008239746093750, 0.0057067871093750, +0.0009460449218750, 0.0057983398437500, 0.0010986328125000, 0.0054016113281250, +0.0011901855468750, 0.0050659179687500, 0.0012512207031250, 0.0051879882812500, +0.0016784667968750, 0.0046081542968750, 0.0015563964843750, 0.0046081542968750, +0.0020141601562500, 0.0044555664062500, 0.0025939941406250, 0.0042114257812500, +0.0022277832031250, 0.0043334960937500, 0.0032653808593750, 0.0039367675781250, +0.0033569335937500, 0.0041503906250000, 0.0032043457031250, 0.0037231445312500, +0.0036315917968750, 0.0025939941406250, 0.0020446777343750, 0.0042724609375000, +0.0013122558593750, 0.0045166015625000, 0.0012817382812500, 0.0049438476562500, +0.0016479492187500, 0.0043945312500000, 0.0017089843750000, 0.0041503906250000, +0.0015563964843750, 0.0047912597656250, 0.0023498535156250, 0.0029907226562500, +0.0020751953125000, 0.0035095214843750, 0.0024719238281250, 0.0029907226562500, +0.0031433105468750, 0.0014648437500000, 0.0025634765625000, 0.0024414062500000, +0.0040588378906250, 0.0008850097656250, 0.0036926269531250, 0.0009460449218750, +0.0041503906250000, 0.0009765625000000, 0.0054626464843750, 0.0000610351562500, +0.0047607421875000, 0.0004577636718750, 0.0057678222656250, 0.0008239746093750, +0.0058593750000000, 0.0002136230468750, 0.0056762695312500, 0.0010070800781250, +0.0060729980468750, 0.0019836425781250, 0.0062561035156250, 0.0011596679687500, +0.0061950683593750, 0.0030212402343750, 0.0061340332031250, 0.0029907226562500, +0.0067749023437500, 0.0027770996093750, 0.0071411132812500, 0.0036926269531250, +0.0067749023437500, 0.0034484863281250, 0.0083007812500000, 0.0027465820312500, +0.0080871582031250, 0.0031433105468750, 0.0081481933593750, 0.0027160644531250, +0.0090942382812500, 0.0018615722656250, 0.0086975097656250, 0.0021667480468750, +0.0084533691406250, 0.0012817382812500, 0.0087890625000000, 0.0012512207031250, +0.0080261230468750, 0.0010681152343750, 0.0073242187500000, 0.0004882812500000, +0.0079040527343750, 0.0007019042968750, 0.0062866210937500, 0.0002441406250000, +0.0065917968750000, 0.0001220703125000, 0.0063781738281250, 0.0003051757812500, +0.0054321289062500, 0.0003356933593750, 0.0061645507812500, 0.0002746582031250, +0.0050048828125000, 0.0006713867187500, 0.0054626464843750, 0.0007019042968750, +0.0050659179687500, 0.0006408691406250, 0.0042419433593750, 0.0008239746093750, +0.0051879882812500, 0.0008544921875000, 0.0029602050781250, 0.0004882812500000, +0.0038146972656250, 0.0006103515625000, 0.0030517578125000, 0.0003662109375000, +0.0011291503906250, -0.0000305175781250, 0.0027160644531250, 0.0001220703125000, +0.0000915527343750, -0.0004272460937500, 0.0003967285156250, -0.0004272460937500, +0.0003356933593750, -0.0004882812500000, -0.0011901855468750, -0.0009765625000000, +-0.0002746582031250, -0.0008544921875000, -0.0008850097656250, -0.0008239746093750, +-0.0010375976562500, -0.0011596679687500, -0.0006408691406250, -0.0008544921875000, +-0.0007019042968750, -0.0004882812500000, -0.0007324218750000, -0.0009460449218750, +0.0000610351562500, -0.0001831054687500, -0.0001220703125000, -0.0003356933593750, +0.0001831054687500, -0.0003967285156250, 0.0008544921875000, 0.0000305175781250, +0.0003662109375000, -0.0002441406250000, 0.0009155273437500, -0.0000610351562500, +0.0007324218750000, -0.0001220703125000, 0.0007019042968750, -0.0002441406250000, +0.0009460449218750, -0.0002136230468750, 0.0003662109375000, -0.0003356933593750, +0.0013427734375000, -0.0002441406250000, 0.0006103515625000, -0.0005187988281250, +0.0010070800781250, -0.0004882812500000, 0.0018005371093750, -0.0003356933593750, +0.0006103515625000, -0.0005798339843750, 0.0024108886718750, -0.0001220703125000, +0.0017395019531250, -0.0003051757812500, 0.0018005371093750, -0.0001831054687500, +0.0030212402343750, 0.0002441406250000, 0.0020751953125000, 0.0000305175781250, +0.0029602050781250, 0.0003662109375000, 0.0027465820312500, 0.0005493164062500, +0.0025024414062500, 0.0004882812500000, 0.0029296875000000, 0.0005187988281250, +0.0025024414062500, 0.0006103515625000, 0.0023193359375000, 0.0005187988281250, +0.0024414062500000, 0.0005187988281250, 0.0022277832031250, 0.0004882812500000, +0.0018920898437500, 0.0003356933593750, 0.0020751953125000, 0.0003051757812500, +0.0018005371093750, 0.0002136230468750, 0.0017395019531250, 0.0001220703125000, +0.0018920898437500, -0.0000305175781250, 0.0018920898437500, -0.0000610351562500, +0.0018920898437500, -0.0000915527343750, 0.0024414062500000, -0.0001831054687500, +0.0023803710937500}, +{0.0054931640625000, 0.0010070800781250, 0.0050964355468750, 0.0013732910156250, +0.0057373046875000, 0.0010070800781250, 0.0062866210937500, -0.0005798339843750, +0.0058593750000000, 0.0002441406250000, 0.0072326660156250, -0.0003967285156250, +0.0073852539062500, -0.0009460449218750, 0.0071105957031250, 0.0000915527343750, +0.0076904296875000, 0.0006103515625000, 0.0075683593750000, -0.0001220703125000, +0.0066833496093750, 0.0021667480468750, 0.0069580078125000, 0.0019226074218750, +0.0064697265625000, 0.0020446777343750, 0.0054931640625000, 0.0034179687500000, +0.0059814453125000, 0.0028076171875000, 0.0049743652343750, 0.0029602050781250, +0.0048522949218750, 0.0032348632812500, 0.0048828125000000, 0.0027465820312500, +0.0044860839843750, 0.0025329589843750, 0.0044860839843750, 0.0027160644531250, +0.0041503906250000, 0.0015869140625000, 0.0043334960937500, 0.0018005371093750, +0.0039062500000000, 0.0013732910156250, 0.0033569335937500, 0.0004577636718750, +0.0037841796875000, 0.0010070800781250, 0.0026550292968750, 0.0001831054687500, +0.0027770996093750, 0.0000305175781250, 0.0026550292968750, 0.0003356933593750, +0.0019531250000000, 0.0001525878906250, 0.0024108886718750, 0.0001220703125000, +0.0022888183593750, 0.0005493164062500, 0.0020141601562500, 0.0003967285156250, +0.0025634765625000, 0.0004882812500000, 0.0029907226562500, 0.0007324218750000, +0.0026855468750000, 0.0004272460937500, 0.0037841796875000, 0.0004882812500000, +0.0038757324218750, 0.0004272460937500, 0.0040283203125000, 0.0001220703125000, +0.0047912597656250, 0.0000000000000000, 0.0048522949218750, -0.0000610351562500, +0.0048522949218750, -0.0005187988281250, 0.0051879882812500, -0.0005798339843750, +0.0052795410156250, -0.0006408691406250, 0.0051574707031250, -0.0010375976562500, +0.0053710937500000, -0.0009460449218750, 0.0053405761718750, -0.0008239746093750, +0.0053405761718750, -0.0009765625000000, 0.0056457519531250, -0.0007934570312500, +0.0056762695312500, -0.0004272460937500, 0.0054626464843750, -0.0006103515625000, +0.0065002441406250, -0.0001525878906250, 0.0058898925781250, -0.0000915527343750, +0.0065612792968750, -0.0000915527343750, 0.0076599121093750, 0.0001220703125000, +0.0065612792968750, 0.0001220703125000, 0.0085754394531250, 0.0002441406250000, +0.0080871582031250, 0.0002441406250000, 0.0081481933593750, 0.0002136230468750, +0.0094299316406250, 0.0003356933593750, 0.0085144042968750, 0.0003356933593750, +0.0090332031250000, 0.0003967285156250, 0.0090026855468750, 0.0003967285156250, +0.0085144042968750, 0.0004577636718750, 0.0084228515625000, 0.0005798339843750, +0.0083007812500000, 0.0004577636718750, 0.0075378417968750, 0.0006713867187500, +0.0074768066406250, 0.0007629394531250, 0.0070190429687500, 0.0007324218750000, +0.0064392089843750, 0.0007934570312500, 0.0065612792968750, 0.0009155273437500, +0.0056457519531250, 0.0007629394531250, 0.0055236816406250, 0.0008850097656250, +0.0053405761718750, 0.0007629394531250, 0.0047302246093750, 0.0005798339843750, +0.0046997070312500, 0.0007934570312500, 0.0043640136718750, 0.0003662109375000, +0.0041503906250000, 0.0005493164062500, 0.0039367675781250, 0.0004882812500000, +0.0036621093750000, 0.0001525878906250, 0.0035095214843750, 0.0004882812500000, +0.0033874511718750, 0.0000305175781250, 0.0033569335937500, 0.0000915527343750, +0.0033569335937500, 0.0000610351562500, 0.0032653808593750, -0.0002746582031250, +0.0032043457031250, -0.0002136230468750, 0.0036010742187500, -0.0004577636718750, +0.0033874511718750, -0.0004272460937500, 0.0037841796875000, -0.0005187988281250, +0.0043029785156250, -0.0007019042968750, 0.0040588378906250, -0.0006713867187500, +0.0051879882812500, -0.0007934570312500, 0.0051269531250000, -0.0008239746093750, +0.0056152343750000, -0.0008239746093750, 0.0065307617187500, -0.0007629394531250, +0.0062561035156250, -0.0007934570312500, 0.0073547363281250, -0.0007629394531250, +0.0074768066406250, -0.0006713867187500, 0.0076293945312500, -0.0006103515625000, +0.0083312988281250, -0.0005187988281250, 0.0081787109375000, -0.0004577636718750, +0.0083618164062500, -0.0003967285156250, 0.0086364746093750, -0.0003051757812500, +0.0083618164062500, -0.0003051757812500, 0.0081787109375000, -0.0002746582031250, +0.0084533691406250, -0.0001525878906250, 0.0075988769531250, -0.0002441406250000, +0.0078735351562500, -0.0001525878906250, 0.0075683593750000, -0.0000915527343750, +0.0068969726562500, -0.0001831054687500, 0.0074157714843750, -0.0000915527343750, +0.0064086914062500, 0.0000000000000000, 0.0065917968750000, -0.0001525878906250, +0.0064697265625000, -0.0000610351562500, 0.0058288574218750, 0.0000305175781250, +0.0062866210937500, -0.0002136230468750, 0.0057983398437500, 0.0001525878906250, +0.0057983398437500, 0.0000305175781250, 0.0058593750000000, 0.0000000000000000, +0.0057373046875000, 0.0001831054687500, 0.0058593750000000, 0.0000000000000000, +0.0057067871093750, 0.0001525878906250, 0.0058593750000000, 0.0000610351562500, +0.0059509277343750, 0.0000915527343750, 0.0058593750000000, 0.0002441406250000, +0.0061035156250000, 0.0000915527343750, 0.0063171386718750, 0.0002746582031250, +0.0064086914062500, 0.0001220703125000, 0.0067443847656250, 0.0000610351562500, +0.0070800781250000, 0.0001220703125000, 0.0071105957031250, 0.0000000000000000, +0.0077209472656250, -0.0000610351562500, 0.0079040527343750, -0.0001525878906250, +0.0080261230468750, -0.0001525878906250, 0.0084228515625000, -0.0002136230468750, +0.0083923339843750, -0.0003051757812500, 0.0079650878906250, -0.0000305175781250, +0.0083923339843750, -0.0001831054687500, 0.0077819824218750, 0.0000305175781250, +0.0068969726562500, 0.0003662109375000, 0.0074768066406250, 0.0001525878906250, +0.0061035156250000, 0.0007324218750000, 0.0060119628906250, 0.0005187988281250, +0.0058898925781250, 0.0007629394531250, 0.0051574707031250, 0.0012207031250000, +0.0053100585937500, 0.0007629394531250, 0.0050964355468750, 0.0013122558593750, +0.0050354003906250, 0.0012817382812500, 0.0047607421875000, 0.0011291503906250, +0.0046081542968750, 0.0012817382812500, 0.0047607421875000, 0.0012512207031250, +0.0036315917968750, 0.0010070800781250, 0.0038452148437500, 0.0011291503906250, +0.0033569335937500, 0.0010986328125000, 0.0023193359375000, 0.0008850097656250, +0.0027160644531250, 0.0010375976562500, 0.0017395019531250, 0.0012207031250000, +0.0016479492187500, 0.0011901855468750, 0.0017089843750000, 0.0013732910156250, +0.0013732910156250, 0.0016479492187500, 0.0014953613281250, 0.0015563964843750, +0.0014953613281250, 0.0018005371093750, 0.0014648437500000, 0.0017395019531250, +0.0018310546875000, 0.0017089843750000, 0.0020141601562500, 0.0018920898437500, +0.0021362304687500, 0.0019531250000000, 0.0034179687500000, 0.0022888183593750, +0.0028076171875000, 0.0020751953125000, 0.0030517578125000, 0.0024414062500000, +0.0040893554687500, 0.0028991699218750, 0.0032348632812500, 0.0026550292968750, +0.0039978027343750, 0.0037231445312500, 0.0040588378906250, 0.0034179687500000, +0.0033264160156250, 0.0039367675781250, 0.0033569335937500, 0.0048828125000000, +0.0035095214843750, 0.0041198730468750, 0.0020446777343750, 0.0054321289062500, +0.0023193359375000, 0.0054321289062500, 0.0018310546875000, 0.0050354003906250, +0.0007324218750000, 0.0053405761718750, 0.0013427734375000, 0.0051574707031250, +0.0004272460937500, 0.0046997070312500, 0.0003662109375000, 0.0047607421875000, +0.0005493164062500, 0.0043029785156250, 0.0001831054687500, 0.0036621093750000, +0.0003051757812500, 0.0039367675781250, 0.0008544921875000, 0.0032348632812500, +0.0007324218750000, 0.0031738281250000, 0.0009765625000000, 0.0029602050781250, +0.0014648437500000, 0.0025329589843750, 0.0012512207031250, 0.0027770996093750, +0.0014038085937500, 0.0026245117187500, 0.0014648437500000, 0.0025024414062500, +0.0013427734375000, 0.0027770996093750, 0.0011901855468750, 0.0029602050781250, +0.0011291503906250, 0.0028076171875000, 0.0010986328125000, 0.0034790039062500, +0.0008850097656250, 0.0034484863281250, 0.0009155273437500, 0.0036315917968750, +0.0010375976562500, 0.0041503906250000, 0.0008850097656250, 0.0040588378906250, +0.0012207031250000, 0.0043029785156250, 0.0010681152343750, 0.0044250488281250, +0.0012512207031250, 0.0045166015625000, 0.0016784667968750, 0.0045776367187500, +0.0013732910156250, 0.0046081542968750, 0.0018310546875000, 0.0050964355468750, +0.0019836425781250, 0.0048522949218750, 0.0017089843750000, 0.0053100585937500, +0.0019226074218750, 0.0059814453125000, 0.0021362304687500, 0.0054931640625000, +0.0012512207031250, 0.0067749023437500, 0.0017395019531250, 0.0067749023437500, +0.0013732910156250, 0.0070495605468750, 0.0005187988281250, 0.0079345703125000, +0.0012817382812500, 0.0075988769531250, 0.0001525878906250, 0.0081787109375000, +0.0003967285156250, 0.0084228515625000, 0.0004577636718750, 0.0082397460937500, +-0.0001220703125000, 0.0083618164062500, 0.0003356933593750, 0.0084838867187500, +-0.0000305175781250, 0.0077819824218750, 0.0000915527343750, 0.0080261230468750, +0.0001831054687500, 0.0077819824218750, 0.0000610351562500, 0.0071716308593750, +0.0003356933593750, 0.0075988769531250, 0.0002136230468750, 0.0070495605468750, +0.0003051757812500, 0.0070190429687500, 0.0003356933593750, 0.0071105957031250, +0.0002746582031250, 0.0069274902343750, 0.0005187988281250, 0.0069885253906250, +0.0000915527343750, 0.0072631835937500, 0.0003967285156250, 0.0071105957031250, +0.0002441406250000, 0.0072326660156250, -0.0002136230468750, 0.0075378417968750, +0.0001525878906250, 0.0072021484375000, -0.0004882812500000, 0.0073852539062500, +-0.0003051757812500, 0.0074768066406250, -0.0003662109375000, 0.0071411132812500, +-0.0008544921875000, 0.0069580078125000, -0.0004882812500000, 0.0070190429687500, +-0.0009460449218750, 0.0059204101562500, -0.0008544921875000, 0.0061035156250000, +-0.0008239746093750, 0.0054931640625000, -0.0010375976562500, 0.0044555664062500, +-0.0008544921875000, 0.0049743652343750, -0.0008239746093750, 0.0036010742187500, +-0.0008850097656250, 0.0036315917968750, -0.0007019042968750, 0.0034179687500000, +-0.0005493164062500, 0.0025634765625000, -0.0005798339843750, 0.0029907226562500, +-0.0002746582031250, 0.0023803710937500, -0.0004272460937500, 0.0022583007812500, +-0.0001831054687500, 0.0023193359375000, 0.0001220703125000, 0.0020446777343750, +-0.0002136230468750, 0.0022888183593750, 0.0005798339843750, 0.0022583007812500, +0.0003662109375000, 0.0021362304687500, 0.0005493164062500, 0.0023498535156250, +0.0011596679687500, 0.0025024414062500, 0.0007324218750000, 0.0024108886718750, +0.0013732910156250, 0.0030822753906250, 0.0013732910156250, 0.0028076171875000, +0.0012817382812500, 0.0033874511718750, 0.0016479492187500, 0.0040588378906250, +0.0015258789062500, 0.0035400390625000, 0.0013732910156250, 0.0053405761718750, +0.0015563964843750, 0.0049133300781250, 0.0013427734375000, 0.0056762695312500, +0.0010681152343750, 0.0072631835937500, 0.0012817382812500, 0.0062866210937500, +0.0006713867187500, 0.0083923339843750, 0.0008239746093750, 0.0082702636718750, +0.0005798339843750, 0.0085449218750000, 0.0001525878906250, 0.0098266601562500, +0.0004882812500000, 0.0092163085937500, -0.0001220703125000, 0.0100402832031250, +0.0000610351562500, 0.0102233886718750, 0.0000000000000000, 0.0097351074218750, +-0.0003356933593750}, +{0.0010070800781250, 0.0065612792968750, 0.0011291503906250, 0.0068969726562500, +0.0009765625000000, 0.0068054199218750, 0.0008850097656250, 0.0072937011718750, +0.0008850097656250, 0.0072021484375000, 0.0008850097656250, 0.0074768066406250, +0.0007019042968750, 0.0079650878906250, 0.0007324218750000, 0.0076904296875000, +0.0010681152343750, 0.0083312988281250, 0.0008239746093750, 0.0083618164062500, +0.0011596679687500, 0.0083618164062500, 0.0017395019531250, 0.0087280273437500, +0.0013122558593750, 0.0085754394531250, 0.0020751953125000, 0.0085449218750000, +0.0021972656250000, 0.0086364746093750, 0.0020141601562500, 0.0085449218750000, +0.0023803710937500, 0.0083923339843750, 0.0024719238281250, 0.0084838867187500, +0.0017700195312500, 0.0083007812500000, 0.0022583007812500, 0.0081787109375000, +0.0018615722656250, 0.0082397460937500, 0.0010375976562500, 0.0081787109375000, +0.0018005371093750, 0.0080566406250000, 0.0007019042968750, 0.0083923339843750, +0.0008544921875000, 0.0082092285156250, 0.0009460449218750, 0.0083007812500000, +0.0004272460937500, 0.0086059570312500, 0.0007934570312500, 0.0083007812500000, +0.0005798339843750, 0.0085449218750000, 0.0007019042968750, 0.0085449218750000, +0.0007324218750000, 0.0083007812500000, 0.0007019042968750, 0.0083618164062500, +0.0009765625000000, 0.0083312988281250, 0.0006713867187500, 0.0076599121093750, +0.0010070800781250, 0.0079650878906250, 0.0007934570312500, 0.0074157714843750, +0.0004577636718750, 0.0066223144531250, 0.0010070800781250, 0.0071105957031250, +0.0000305175781250, 0.0056762695312500, 0.0003967285156250, 0.0058288574218750, +0.0002746582031250, 0.0055847167968750, -0.0004577636718750, 0.0045471191406250, +0.0001220703125000, 0.0050659179687500, -0.0006103515625000, 0.0043334960937500, +-0.0003967285156250, 0.0043334960937500, -0.0003662109375000, 0.0045166015625000, +-0.0007934570312500, 0.0042419433593750, -0.0004882812500000, 0.0044250488281250, +-0.0007629394531250, 0.0046386718750000, -0.0007629394531250, 0.0044860839843750, +-0.0006103515625000, 0.0047607421875000, -0.0006408691406250, 0.0050354003906250, +-0.0007019042968750, 0.0048828125000000, -0.0003356933593750, 0.0054626464843750, +-0.0005493164062500, 0.0054321289062500, -0.0004272460937500, 0.0055847167968750, +-0.0001525878906250, 0.0059204101562500, -0.0005187988281250, 0.0058593750000000, +0.0000915527343750, 0.0060424804687500, -0.0001831054687500, 0.0061645507812500, +-0.0000610351562500, 0.0061645507812500, 0.0003967285156250, 0.0062255859375000, +-0.0000915527343750, 0.0062561035156250, 0.0005798339843750, 0.0060424804687500, +0.0005493164062500, 0.0062561035156250, 0.0005187988281250, 0.0059814453125000, +0.0009765625000000, 0.0055847167968750, 0.0008544921875000, 0.0058593750000000, +0.0009460449218750, 0.0048828125000000, 0.0010986328125000, 0.0049438476562500, +0.0009765625000000, 0.0046691894531250, 0.0009155273437500, 0.0039672851562500, +0.0010681152343750, 0.0041809082031250, 0.0005493164062500, 0.0036926269531250, +0.0008239746093750, 0.0034179687500000, 0.0006408691406250, 0.0035400390625000, +0.0001831054687500, 0.0033264160156250, 0.0007019042968750, 0.0031433105468750, +-0.0000305175781250, 0.0037841796875000, 0.0002746582031250, 0.0033569335937500, +0.0001831054687500, 0.0038757324218750, -0.0003967285156250, 0.0046386718750000, +0.0001831054687500, 0.0039978027343750, -0.0005798339843750, 0.0055541992187500, +-0.0004882812500000, 0.0053710937500000, -0.0004272460937500, 0.0055847167968750, +-0.0008239746093750, 0.0066528320312500, -0.0006408691406250, 0.0061035156250000, +-0.0006713867187500, 0.0064392089843750, -0.0007934570312500, 0.0067138671875000, +-0.0006713867187500, 0.0061645507812500, -0.0006103515625000, 0.0059204101562500, +-0.0006713867187500, 0.0062561035156250, -0.0003662109375000, 0.0048522949218750, +-0.0004882812500000, 0.0052185058593750, -0.0001831054687500, 0.0047912597656250, +0.0001220703125000, 0.0037536621093750, -0.0003356933593750, 0.0044860839843750, +0.0004577636718750, 0.0036315917968750, 0.0001525878906250, 0.0037536621093750, +0.0001831054687500, 0.0038452148437500, 0.0006408691406250, 0.0036010742187500, +0.0000915527343750, 0.0040283203125000, 0.0007324218750000, 0.0038146972656250, +0.0004882812500000, 0.0042114257812500, 0.0005798339843750, 0.0042419433593750, +0.0010986328125000, 0.0041503906250000, 0.0007324218750000, 0.0046691894531250, +0.0013122558593750, 0.0037536621093750, 0.0012512207031250, 0.0043334960937500, +0.0011901855468750, 0.0039062500000000, 0.0014648437500000, 0.0029602050781250, +0.0012512207031250, 0.0038452148437500, 0.0013732910156250, 0.0023498535156250, +0.0012817382812500, 0.0023193359375000, 0.0013122558593750, 0.0024414062500000, +0.0014038085937500, 0.0017089843750000, 0.0011291503906250, 0.0020446777343750, +0.0015563964843750, 0.0022583007812500, 0.0013732910156250, 0.0018615722656250, +0.0014648437500000, 0.0025024414062500, 0.0017700195312500, 0.0031433105468750, +0.0014038085937500, 0.0025024414062500, 0.0020751953125000, 0.0042114257812500, +0.0018615722656250, 0.0040588378906250, 0.0020446777343750, 0.0039672851562500, +0.0025634765625000, 0.0048217773437500, 0.0020446777343750, 0.0045471191406250, +0.0025329589843750, 0.0043945312500000, 0.0024719238281250, 0.0046386718750000, +0.0020446777343750, 0.0042724609375000, 0.0020141601562500, 0.0038452148437500, +0.0019531250000000, 0.0040893554687500, 0.0011291503906250, 0.0041198730468750, +0.0010986328125000, 0.0039062500000000, 0.0009460449218750, 0.0043334960937500, +0.0002746582031250, 0.0048828125000000, 0.0003051757812500, 0.0047302246093750, +0.0006103515625000, 0.0049438476562500, -0.0000610351562500, 0.0054931640625000, +0.0006408691406250, 0.0051574707031250, 0.0014038085937500, 0.0047302246093750, +0.0004882812500000, 0.0052490234375000, 0.0025634765625000, 0.0048217773437500, +0.0022583007812500, 0.0046691894531250, 0.0023498535156250, 0.0048828125000000, +0.0045166015625000, 0.0048828125000000, 0.0037536621093750, 0.0032958984375000, +0.0031433105468750, 0.0041198730468750, 0.0032043457031250, 0.0035705566406250, +0.0033569335937500, 0.0039367675781250, 0.0032348632812500, 0.0047607421875000, +0.0030212402343750, 0.0043029785156250, 0.0043640136718750, 0.0039978027343750, +0.0039367675781250, 0.0044860839843750, 0.0045471191406250, 0.0035095214843750, +0.0060424804687500, 0.0025634765625000, 0.0052795410156250, 0.0032653808593750, +0.0063171386718750, 0.0015563964843750, 0.0067443847656250, 0.0014343261718750, +0.0060729980468750, 0.0016174316406250, 0.0060119628906250, 0.0008239746093750, +0.0065612792968750, 0.0009765625000000, 0.0050048828125000, 0.0016479492187500, +0.0051269531250000, 0.0012207031250000, 0.0050659179687500, 0.0017395019531250, +0.0041198730468750, 0.0025024414062500, 0.0043029785156250, 0.0019226074218750, +0.0045471191406250, 0.0032653808593750, 0.0039672851562500, 0.0033569335937500, +0.0040283203125000, 0.0031433105468750, 0.0044250488281250, 0.0038757324218750, +0.0039367675781250, 0.0037536621093750, 0.0040283203125000, 0.0025634765625000, +0.0039978027343750, 0.0033874511718750, 0.0038452148437500, 0.0023803710937500, +0.0037231445312500, 0.0006103515625000, 0.0036010742187500, 0.0017089843750000, +0.0041198730468750, -0.0002441406250000, 0.0036926269531250, -0.0005187988281250, +0.0043945312500000, -0.0000915527343750, 0.0052185058593750, -0.0007629394531250, +0.0044555664062500, -0.0007934570312500, 0.0067443847656250, 0.0002136230468750, +0.0063171386718750, -0.0001525878906250, 0.0068969726562500, 0.0003967285156250, +0.0086059570312500, 0.0014038085937500, 0.0075988769531250, 0.0007324218750000, +0.0091857910156250, 0.0019226074218750, 0.0091857910156250, 0.0020141601562500, +0.0091857910156250, 0.0018920898437500, 0.0099792480468750, 0.0024719238281250, +0.0095520019531250, 0.0023498535156250, 0.0099792480468750, 0.0018920898437500, +0.0098876953125000, 0.0022888183593750, 0.0100708007812500, 0.0018310546875000, +0.0104675292968750, 0.0010681152343750, 0.0101928710937500, 0.0016479492187500, +0.0108947753906250, 0.0005493164062500, 0.0109252929687500, 0.0006408691406250, +0.0109863281250000, 0.0007019042968750, 0.0115051269531250, 0.0001525878906250, +0.0115051269531250, 0.0004882812500000, 0.0113220214843750, 0.0004577636718750, +0.0118713378906250, 0.0003967285156250, 0.0113830566406250, 0.0005798339843750, +0.0109252929687500, 0.0007019042968750, 0.0117492675781250, 0.0006103515625000, +0.0101013183593750, 0.0010070800781250, 0.0106201171875000, 0.0009765625000000, +0.0102539062500000, 0.0009765625000000, 0.0090332031250000, 0.0011596679687500, +0.0100402832031250, 0.0010375976562500, 0.0083923339843750, 0.0009460449218750, +0.0087585449218750, 0.0008850097656250, 0.0085754394531250, 0.0008544921875000, +0.0075073242187500, 0.0007934570312500, 0.0083007812500000, 0.0007324218750000, +0.0074157714843750, 0.0008850097656250, 0.0073852539062500, 0.0008239746093750, +0.0076599121093750, 0.0009155273437500, 0.0073547363281250, 0.0011596679687500, +0.0074157714843750, 0.0010681152343750, 0.0079345703125000, 0.0013427734375000, +0.0078125000000000, 0.0013427734375000, 0.0081176757812500, 0.0014953613281250, +0.0086669921875000, 0.0017089843750000, 0.0082702636718750, 0.0014648437500000, +0.0089111328125000, 0.0017700195312500, 0.0089416503906250, 0.0017089843750000, +0.0088806152343750, 0.0015563964843750, 0.0091552734375000, 0.0015258789062500, +0.0090637207031250, 0.0013732910156250, 0.0087890625000000, 0.0010375976562500, +0.0089721679687500, 0.0010070800781250, 0.0085449218750000, 0.0006408691406250, +0.0080871582031250, 0.0003356933593750, 0.0084228515625000, 0.0004272460937500, +0.0074768066406250, -0.0000915527343750, 0.0075683593750000, -0.0000610351562500, +0.0074157714843750, -0.0002746582031250, 0.0067443847656250, -0.0006103515625000, +0.0071105957031250, -0.0003356933593750, 0.0065307617187500, -0.0007629394531250, +0.0065002441406250, -0.0007324218750000, 0.0065307617187500, -0.0006713867187500, +0.0063476562500000, -0.0007629394531250, 0.0064086914062500, -0.0006713867187500, +0.0065002441406250, -0.0005798339843750, 0.0064697265625000, -0.0005798339843750, +0.0065002441406250, -0.0006103515625000, 0.0065917968750000, -0.0005798339843750, +0.0066223144531250, -0.0005493164062500, 0.0065002441406250, -0.0005798339843750, +0.0066223144531250, -0.0004882812500000, 0.0064086914062500, -0.0003356933593750, +0.0061645507812500, -0.0002746582031250, 0.0062561035156250, -0.0003356933593750, +0.0055236816406250, -0.0001831054687500, 0.0055541992187500, -0.0001831054687500, +0.0054016113281250, -0.0001220703125000, 0.0047912597656250, -0.0000610351562500, +0.0048217773437500, -0.0002441406250000, 0.0046997070312500, -0.0000610351562500, +0.0043640136718750, -0.0000915527343750, 0.0047607421875000, -0.0000305175781250, +0.0049743652343750, 0.0001525878906250, 0.0045471191406250, 0.0000305175781250, +0.0059204101562500, 0.0002441406250000, 0.0055236816406250, 0.0001831054687500, +0.0061645507812500, 0.0002136230468750, 0.0074768066406250, 0.0003967285156250, +0.0066528320312500, 0.0003967285156250, 0.0084838867187500, 0.0004577636718750, +0.0084228515625000, 0.0005798339843750, 0.0085144042968750, 0.0006103515625000, +0.0095825195312500, 0.0005798339843750, 0.0091857910156250, 0.0007629394531250, +0.0094909667968750}, +{0.0080871582031250, 0.0014038085937500, 0.0054626464843750, 0.0014953613281250, +0.0060424804687500, 0.0018005371093750, 0.0053100585937500, 0.0014648437500000, +0.0032958984375000, 0.0011596679687500, 0.0046997070312500, 0.0015563964843750, +0.0021667480468750, 0.0008850097656250, 0.0025329589843750, 0.0010070800781250, +0.0023193359375000, 0.0010681152343750, 0.0008239746093750, 0.0007324218750000, +0.0020141601562500, 0.0009155273437500, 0.0006713867187500, 0.0008544921875000, +0.0009460449218750, 0.0007324218750000, 0.0010986328125000, 0.0010070800781250, +0.0005493164062500, 0.0011596679687500, 0.0012207031250000, 0.0010070800781250, +0.0006713867187500, 0.0015563964843750, 0.0009460449218750, 0.0014953613281250, +0.0011901855468750, 0.0015563964843750, 0.0009765625000000, 0.0019836425781250, +0.0014953613281250, 0.0018310546875000, 0.0016174316406250, 0.0018615722656250, +0.0018005371093750, 0.0019531250000000, 0.0020446777343750, 0.0018310546875000, +0.0022583007812500, 0.0017395019531250, 0.0025024414062500, 0.0018615722656250, +0.0024108886718750, 0.0015563964843750, 0.0028076171875000, 0.0016784667968750, +0.0027160644531250, 0.0016174316406250, 0.0025634765625000, 0.0013732910156250, +0.0029907226562500, 0.0015563964843750, 0.0020751953125000, 0.0013122558593750, +0.0025634765625000, 0.0013427734375000, 0.0023498535156250, 0.0013427734375000, +0.0015563964843750, 0.0012817382812500, 0.0022277832031250, 0.0012817382812500, +0.0017395019531250, 0.0013122558593750, 0.0018310546875000, 0.0013122558593750, +0.0021362304687500, 0.0010681152343750, 0.0021972656250000, 0.0009460449218750, +0.0023498535156250, 0.0010070800781250, 0.0031127929687500, 0.0004272460937500, +0.0030212402343750, 0.0005798339843750, 0.0035705566406250, 0.0004577636718750, +0.0043029785156250, 0.0000305175781250, 0.0040283203125000, 0.0002746582031250, +0.0052795410156250, -0.0002136230468750, 0.0051269531250000, -0.0002136230468750, +0.0056152343750000, -0.0002746582031250, 0.0065307617187500, -0.0005798339843750, +0.0060119628906250, -0.0005493164062500, 0.0072631835937500, -0.0006103515625000, +0.0070495605468750, -0.0006713867187500, 0.0072937011718750, -0.0006408691406250, +0.0082397460937500, -0.0006103515625000, 0.0077819824218750, -0.0006103515625000, +0.0087280273437500, -0.0004882812500000, 0.0087890625000000, -0.0004882812500000, +0.0088500976562500, -0.0004882812500000, 0.0094604492187500, -0.0003967285156250, +0.0092468261718750, -0.0003967285156250, 0.0094604492187500, -0.0003356933593750, +0.0096435546875000, -0.0003051757812500, 0.0093688964843750, -0.0002136230468750, +0.0092773437500000, -0.0000610351562500, 0.0094604492187500, -0.0000915527343750, +0.0086669921875000, 0.0001831054687500, 0.0089111328125000, 0.0001525878906250, +0.0083618164062500, 0.0001831054687500, 0.0075378417968750, 0.0003662109375000, +0.0079956054687500, 0.0002746582031250, 0.0066223144531250, 0.0003967285156250, +0.0067443847656250, 0.0004882812500000, 0.0064392089843750, 0.0004882812500000, +0.0054931640625000, 0.0005187988281250, 0.0059204101562500, 0.0005798339843750, +0.0053405761718750, 0.0004577636718750, 0.0052185058593750, 0.0004882812500000, +0.0054016113281250, 0.0004882812500000, 0.0053405761718750, 0.0004272460937500, +0.0054626464843750, 0.0005187988281250, 0.0058593750000000, 0.0004272460937500, +0.0058898925781250, 0.0003967285156250, 0.0061950683593750, 0.0003662109375000, +0.0066833496093750, 0.0003356933593750, 0.0066223144531250, 0.0002746582031250, +0.0069274902343750, 0.0004272460937500, 0.0071411132812500, 0.0003051757812500, +0.0070495605468750, 0.0004272460937500, 0.0070190429687500, 0.0006713867187500, +0.0072021484375000, 0.0004882812500000, 0.0067138671875000, 0.0008850097656250, +0.0068969726562500, 0.0009155273437500, 0.0066528320312500, 0.0009155273437500, +0.0062561035156250, 0.0011596679687500, 0.0065612792968750, 0.0011596679687500, +0.0060729980468750, 0.0010986328125000, 0.0061035156250000, 0.0012512207031250, +0.0062561035156250, 0.0012207031250000, 0.0061035156250000, 0.0010375976562500, +0.0061645507812500, 0.0011901855468750, 0.0065612792968750, 0.0010070800781250, +0.0064086914062500, 0.0010375976562500, 0.0067138671875000, 0.0010681152343750, +0.0072021484375000, 0.0010070800781250, 0.0069274902343750, 0.0010070800781250, +0.0075683593750000, 0.0012817382812500, 0.0076293945312500, 0.0012817382812500, +0.0074768066406250, 0.0012512207031250, 0.0076293945312500, 0.0014648437500000, +0.0075378417968750, 0.0015869140625000, 0.0072021484375000, 0.0011596679687500, +0.0072326660156250, 0.0014343261718750, 0.0068359375000000, 0.0014038085937500, +0.0063781738281250, 0.0009155273437500, 0.0064086914062500, 0.0012207031250000, +0.0054626464843750, 0.0011596679687500, 0.0057678222656250, 0.0010070800781250, +0.0050964355468750, 0.0015258789062500, 0.0040893554687500, 0.0018615722656250, +0.0047607421875000, 0.0014953613281250, 0.0034179687500000, 0.0024719238281250, +0.0033874511718750, 0.0024108886718750, 0.0035705566406250, 0.0024108886718750, +0.0029907226562500, 0.0029602050781250, 0.0031433105468750, 0.0028076171875000, +0.0034790039062500, 0.0028076171875000, 0.0035095214843750, 0.0029602050781250, +0.0034790039062500, 0.0028076171875000, 0.0038146972656250, 0.0025024414062500, +0.0041198730468750, 0.0024414062500000, 0.0037231445312500, 0.0023193359375000, +0.0039672851562500, 0.0022277832031250, 0.0040588378906250, 0.0023498535156250, +0.0037536621093750, 0.0023193359375000, 0.0039367675781250, 0.0019836425781250, +0.0037231445312500, 0.0026550292968750, 0.0039367675781250, 0.0024414062500000, +0.0036926269531250, 0.0025939941406250, 0.0033569335937500, 0.0030517578125000, +0.0037536621093750, 0.0028381347656250, 0.0025329589843750, 0.0037536621093750, +0.0026550292968750, 0.0036315917968750, 0.0024108886718750, 0.0040588378906250, +0.0014648437500000, 0.0047912597656250, 0.0017395019531250, 0.0044860839843750, +0.0013427734375000, 0.0060729980468750, 0.0011596679687500, 0.0059509277343750, +0.0013732910156250, 0.0061950683593750, 0.0012512207031250, 0.0072631835937500, +0.0010681152343750, 0.0069580078125000, 0.0018920898437500, 0.0074157714843750, +0.0015563964843750, 0.0078125000000000, 0.0017700195312500, 0.0074768066406250, +0.0025634765625000, 0.0074157714843750, 0.0020141601562500, 0.0077819824218750, +0.0021972656250000, 0.0072021484375000, 0.0026550292968750, 0.0072631835937500, +0.0019836425781250, 0.0073852539062500, 0.0016174316406250, 0.0071716308593750, +0.0022583007812500, 0.0073547363281250, 0.0004577636718750, 0.0071105957031250, +0.0009155273437500, 0.0073242187500000, 0.0007324218750000, 0.0070800781250000, +-0.0004882812500000, 0.0067443847656250, 0.0002441406250000, 0.0070495605468750, +-0.0000610351562500, 0.0061340332031250, -0.0003967285156250, 0.0062866210937500, +0.0001525878906250, 0.0060424804687500, 0.0004882812500000, 0.0054321289062500, +0.0002746582031250, 0.0057678222656250, 0.0009460449218750, 0.0048217773437500, +0.0010070800781250, 0.0049133300781250, 0.0010681152343750, 0.0044860839843750, +0.0013732910156250, 0.0036926269531250, 0.0013122558593750, 0.0040283203125000, +0.0014038085937500, 0.0028076171875000, 0.0014648437500000, 0.0026550292968750, +0.0014343261718750, 0.0023803710937500, 0.0014038085937500, 0.0015258789062500, +0.0014648437500000, 0.0016174316406250, 0.0015563964843750, 0.0011291503906250, +0.0015869140625000, 0.0008850097656250, 0.0017089843750000, 0.0007629394531250, +0.0019226074218750, 0.0005493164062500, 0.0019531250000000, 0.0004882812500000, +0.0021972656250000, 0.0002441406250000, 0.0024414062500000, 0.0000610351562500, +0.0023193359375000, -0.0000610351562500, 0.0024108886718750, -0.0003051757812500, +0.0027160644531250, -0.0004272460937500, 0.0018920898437500, -0.0003967285156250, +0.0023803710937500, -0.0006713867187500, 0.0020141601562500, -0.0004577636718750, +0.0011901855468750, -0.0002136230468750, 0.0018920898437500, -0.0004882812500000, +0.0007324218750000, 0.0004272460937500, 0.0009460449218750, 0.0001220703125000, +0.0009460449218750, 0.0004882812500000, 0.0003051757812500, 0.0011901855468750, +0.0007324218750000, 0.0006408691406250, 0.0005187988281250, 0.0018005371093750, +0.0004882812500000, 0.0016479492187500, 0.0007019042968750, 0.0018615722656250, +0.0007324218750000, 0.0025939941406250, 0.0007934570312500, 0.0021057128906250, +0.0009155273437500, 0.0030212402343750, 0.0009155273437500, 0.0028686523437500, +0.0009155273437500, 0.0030822753906250, 0.0009460449218750, 0.0037841796875000, +0.0008544921875000, 0.0034179687500000, 0.0007934570312500, 0.0041809082031250, +0.0006713867187500, 0.0041503906250000, 0.0006408691406250, 0.0042724609375000, +0.0005493164062500, 0.0047302246093750, 0.0003051757812500, 0.0046081542968750, +0.0004577636718750, 0.0049133300781250, 0.0002136230468750, 0.0049743652343750, +0.0001525878906250, 0.0050048828125000, 0.0002746582031250, 0.0052185058593750, +0.0000305175781250, 0.0052185058593750, 0.0001525878906250, 0.0052185058593750, +0.0000915527343750, 0.0053405761718750, -0.0000610351562500, 0.0053710937500000, +-0.0000610351562500, 0.0053710937500000, -0.0000915527343750, 0.0054321289062500, +-0.0002136230468750, 0.0054016113281250, -0.0001831054687500, 0.0054321289062500, +-0.0002136230468750, 0.0053710937500000, -0.0002746582031250, 0.0053405761718750, +-0.0002441406250000, 0.0053710937500000, -0.0002441406250000, 0.0051574707031250, +-0.0001525878906250, 0.0050964355468750, -0.0001220703125000, 0.0050354003906250, +-0.0000305175781250, 0.0048522949218750, 0.0000610351562500, 0.0047607421875000, +0.0001220703125000, 0.0047302246093750, 0.0003051757812500, 0.0044250488281250, +0.0003051757812500, 0.0045166015625000, 0.0002746582031250, 0.0045166015625000, +0.0004272460937500, 0.0042114257812500, 0.0002746582031250, 0.0048217773437500, +0.0003356933593750, 0.0043640136718750, 0.0003662109375000, 0.0045471191406250, +0.0002441406250000, 0.0051269531250000, 0.0003356933593750, 0.0044860839843750, +0.0003051757812500, 0.0052490234375000, 0.0002441406250000, 0.0051269531250000, +0.0003356933593750, 0.0050048828125000, 0.0003356933593750, 0.0053405761718750, +0.0002441406250000, 0.0051269531250000, 0.0005798339843750, 0.0049743652343750, +0.0004577636718750, 0.0049743652343750, 0.0005493164062500, 0.0048828125000000, +0.0007324218750000, 0.0047302246093750, 0.0003662109375000, 0.0047302246093750, +0.0006713867187500, 0.0047912597656250, 0.0004577636718750, 0.0046081542968750, +0.0004272460937500, 0.0049438476562500, 0.0006408691406250, 0.0052185058593750, +0.0002746582031250, 0.0050354003906250, 0.0006103515625000, 0.0058288574218750, +0.0005187988281250, 0.0057678222656250, 0.0005493164062500, 0.0059509277343750, +0.0008544921875000, 0.0066223144531250, 0.0007019042968750, 0.0065002441406250, +0.0010070800781250, 0.0067443847656250, 0.0010070800781250, 0.0068054199218750, +0.0011596679687500, 0.0067138671875000, 0.0014953613281250, 0.0067138671875000, +0.0014038085937500, 0.0067443847656250, 0.0018920898437500, 0.0066833496093750, +0.0018920898437500, 0.0065612792968750, 0.0020141601562500, 0.0067443847656250, +0.0023803710937500, 0.0066528320312500, 0.0022888183593750, 0.0064086914062500, +0.0027160644531250, 0.0073852539062500, 0.0028991699218750, 0.0069885253906250, +0.0029296875000000}, +{0.0018005371093750, 0.0030822753906250, 0.0015869140625000, 0.0029907226562500, +0.0010986328125000, 0.0030822753906250, 0.0014648437500000, 0.0029907226562500, +0.0007324218750000, 0.0028686523437500, 0.0008544921875000, 0.0029296875000000, +0.0008239746093750, 0.0026550292968750, 0.0004272460937500, 0.0025024414062500, +0.0007629394531250, 0.0026245117187500, 0.0005798339843750, 0.0019226074218750, +0.0005187988281250, 0.0021057128906250, 0.0007019042968750, 0.0018615722656250, +0.0007629394531250, 0.0012512207031250, 0.0006408691406250, 0.0015869140625000, +0.0008544921875000, 0.0010375976562500, 0.0008239746093750, 0.0009765625000000, +0.0007934570312500, 0.0011596679687500, 0.0008544921875000, 0.0010070800781250, +0.0007324218750000, 0.0010070800781250, 0.0006103515625000, 0.0016479492187500, +0.0005798339843750, 0.0014343261718750, 0.0004272460937500, 0.0019226074218750, +0.0003356933593750, 0.0026550292968750, 0.0002441406250000, 0.0021972656250000, +0.0000610351562500, 0.0036315917968750, 0.0000000000000000, 0.0034179687500000, +-0.0001220703125000, 0.0038757324218750, -0.0003051757812500, 0.0049438476562500, +-0.0002746582031250, 0.0043029785156250, -0.0003967285156250, 0.0057067871093750, +-0.0003662109375000, 0.0055541992187500, -0.0003967285156250, 0.0056762695312500, +-0.0004577636718750, 0.0065307617187500, -0.0003051757812500, 0.0060424804687500, +-0.0004272460937500, 0.0066223144531250, -0.0002441406250000, 0.0066223144531250, +-0.0002136230468750, 0.0063171386718750, -0.0003051757812500, 0.0065002441406250, +0.0000000000000000, 0.0064392089843750, -0.0002441406250000, 0.0055847167968750, +0.0000000000000000, 0.0058593750000000, 0.0000610351562500, 0.0050964355468750, +-0.0000915527343750, 0.0041503906250000, 0.0001831054687500, 0.0046997070312500, +0.0001220703125000, 0.0028686523437500, 0.0001220703125000, 0.0030212402343750, +0.0002746582031250, 0.0025329589843750, 0.0003356933593750, 0.0011291503906250, +0.0003051757812500, 0.0017700195312500, 0.0006103515625000, 0.0007019042968750, +0.0005798339843750, 0.0004272460937500, 0.0006713867187500, 0.0007019042968750, +0.0009155273437500, 0.0004272460937500, 0.0007324218750000, 0.0003356933593750, +0.0009765625000000, 0.0009155273437500, 0.0009155273437500, 0.0007019042968750, +0.0008239746093750, 0.0010375976562500, 0.0008850097656250, 0.0015869140625000, +0.0006408691406250, 0.0012817382812500, 0.0007324218750000, 0.0020446777343750, +0.0006713867187500, 0.0020446777343750, 0.0005798339843750, 0.0021057128906250, +0.0007019042968750, 0.0026245117187500, 0.0006713867187500, 0.0023803710937500, +0.0006408691406250, 0.0027160644531250, 0.0007934570312500, 0.0026855468750000, +0.0009155273437500, 0.0028381347656250, 0.0009155273437500, 0.0031127929687500, +0.0010375976562500, 0.0028991699218750, 0.0012512207031250, 0.0034179687500000, +0.0012512207031250, 0.0034484863281250, 0.0014648437500000, 0.0035705566406250, +0.0016784667968750, 0.0039062500000000, 0.0016479492187500, 0.0038757324218750, +0.0021362304687500, 0.0042419433593750, 0.0021667480468750, 0.0042724609375000, +0.0022583007812500, 0.0043029785156250, 0.0025634765625000, 0.0045471191406250, +0.0025939941406250, 0.0044250488281250, 0.0025024414062500, 0.0043945312500000, +0.0028381347656250, 0.0044250488281250, 0.0025939941406250, 0.0043945312500000, +0.0022888183593750, 0.0042724609375000, 0.0028076171875000, 0.0042724609375000, +0.0019531250000000, 0.0048217773437500, 0.0020141601562500, 0.0044250488281250, +0.0023193359375000, 0.0049133300781250, 0.0019836425781250, 0.0056457519531250, +0.0020751953125000, 0.0051269531250000, 0.0032043457031250, 0.0067138671875000, +0.0027160644531250, 0.0065002441406250, 0.0034179687500000, 0.0067138671875000, +0.0047302246093750, 0.0077514648437500, 0.0039367675781250, 0.0073547363281250, +0.0052490234375000, 0.0078125000000000, 0.0054931640625000, 0.0081481933593750, +0.0051879882812500, 0.0075683593750000, 0.0055541992187500, 0.0073547363281250, +0.0055847167968750, 0.0078430175781250, 0.0047302246093750, 0.0063171386718750, +0.0048828125000000, 0.0064392089843750, 0.0046081542968750, 0.0064697265625000, +0.0038146972656250, 0.0057067871093750, 0.0039978027343750, 0.0060119628906250, +0.0039367675781250, 0.0058898925781250, 0.0034179687500000, 0.0060119628906250, +0.0040893554687500, 0.0057373046875000, 0.0046691894531250, 0.0055236816406250, +0.0039672851562500, 0.0058898925781250, 0.0056457519531250, 0.0046997070312500, +0.0053710937500000, 0.0048828125000000, 0.0053100585937500, 0.0048522949218750, +0.0068359375000000, 0.0036621093750000, 0.0050354003906250, 0.0046997070312500, +0.0039978027343750, 0.0046081542968750, 0.0039978027343750, 0.0043945312500000, +0.0042419433593750, 0.0045471191406250, 0.0041198730468750, 0.0046691894531250, +0.0039367675781250, 0.0043334960937500, 0.0048828125000000, 0.0046997070312500, +0.0046691894531250, 0.0045776367187500, 0.0047302246093750, 0.0043029785156250, +0.0054321289062500, 0.0044555664062500, 0.0052490234375000, 0.0044860839843750, +0.0055541992187500, 0.0035705566406250, 0.0054321289062500, 0.0037841796875000, +0.0059204101562500, 0.0034790039062500, 0.0063171386718750, 0.0025634765625000, +0.0058898925781250, 0.0030212402343750, 0.0076293945312500, 0.0027160644531250, +0.0071716308593750, 0.0023193359375000, 0.0075988769531250, 0.0028381347656250, +0.0091552734375000, 0.0031127929687500, 0.0085144042968750, 0.0026245117187500, +0.0089721679687500, 0.0037536621093750, 0.0096740722656250, 0.0036315917968750, +0.0086975097656250, 0.0037231445312500, 0.0082092285156250, 0.0044555664062500, +0.0090332031250000, 0.0040893554687500, 0.0065612792968750, 0.0042419433593750, +0.0072937011718750, 0.0047912597656250, 0.0064392089843750, 0.0040283203125000, +0.0044250488281250, 0.0034484863281250, 0.0057983398437500, 0.0041809082031250, +0.0031433105468750, 0.0020751953125000, 0.0033874511718750, 0.0024414062500000, +0.0031127929687500, 0.0023193359375000, 0.0015869140625000, 0.0008544921875000, +0.0024414062500000, 0.0014038085937500, 0.0006408691406250, 0.0014953613281250, +0.0007934570312500, 0.0010375976562500, 0.0005798339843750, 0.0015869140625000, +-0.0006713867187500, 0.0022583007812500, -0.0000915527343750, 0.0017395019531250, +-0.0004577636718750, 0.0028076171875000, -0.0009765625000000, 0.0028076171875000, +-0.0002441406250000, 0.0025939941406250, 0.0000610351562500, 0.0029602050781250, +-0.0006103515625000, 0.0029296875000000, 0.0015563964843750, 0.0022583007812500, +0.0009155273437500, 0.0025634765625000, 0.0015563964843750, 0.0019836425781250, +0.0033264160156250, 0.0012207031250000, 0.0019531250000000, 0.0017395019531250, +0.0038146972656250, 0.0005493164062500, 0.0037231445312500, 0.0005493164062500, +0.0036621093750000, 0.0006408691406250, 0.0046386718750000, 0.0000305175781250, +0.0040283203125000, 0.0003051757812500, 0.0045166015625000, 0.0004882812500000, +0.0045776367187500, 0.0004272460937500, 0.0042724609375000, 0.0006713867187500, +0.0043640136718750, 0.0010681152343750, 0.0043334960937500, 0.0010681152343750, +0.0039062500000000, 0.0013732910156250, 0.0040588378906250, 0.0015869140625000, +0.0039367675781250, 0.0015869140625000, 0.0035705566406250, 0.0017395019531250, +0.0037536621093750, 0.0019531250000000, 0.0033874511718750, 0.0016479492187500, +0.0035400390625000, 0.0019531250000000, 0.0033569335937500, 0.0017700195312500, +0.0029296875000000, 0.0013122558593750, 0.0032348632812500, 0.0016784667968750, +0.0028381347656250, 0.0010375976562500, 0.0027160644531250, 0.0010070800781250, +0.0028991699218750, 0.0009765625000000, 0.0028381347656250, 0.0006408691406250, +0.0026550292968750, 0.0007324218750000, 0.0036315917968750, 0.0005798339843750, +0.0031738281250000, 0.0005493164062500, 0.0037841796875000, 0.0005187988281250, +0.0048217773437500, 0.0004272460937500, 0.0040588378906250, 0.0005798339843750, +0.0057678222656250, 0.0003051757812500, 0.0056762695312500, 0.0004882812500000, +0.0058288574218750, 0.0004577636718750, 0.0069885253906250, 0.0002136230468750, +0.0065307617187500, 0.0004882812500000, 0.0068664550781250, 0.0002746582031250, +0.0071105957031250, 0.0002136230468750, 0.0066223144531250, 0.0003051757812500, +0.0065002441406250, 0.0001220703125000, 0.0067443847656250, 0.0001831054687500, +0.0054626464843750, 0.0003662109375000, 0.0057983398437500, 0.0002136230468750, +0.0051574707031250, 0.0002136230468750, 0.0039672851562500, 0.0003967285156250, +0.0046386718750000, 0.0002746582031250, 0.0028991699218750, 0.0002746582031250, +0.0030517578125000, 0.0003662109375000, 0.0026855468750000, 0.0002136230468750, +0.0015563964843750, 0.0002136230468750, 0.0021362304687500, 0.0004882812500000, +0.0013427734375000, -0.0000305175781250, 0.0012207031250000, 0.0003051757812500, +0.0014343261718750, 0.0002136230468750, 0.0011901855468750, -0.0002136230468750, +0.0012817382812500, 0.0001525878906250, 0.0017700195312500, -0.0002441406250000, +0.0015258789062500, -0.0001525878906250, 0.0019226074218750, 0.0000610351562500, +0.0024719238281250, -0.0000610351562500, 0.0021057128906250, 0.0000000000000000, +0.0030517578125000, 0.0001525878906250, 0.0030212402343750, 0.0000915527343750, +0.0032958984375000, 0.0002136230468750, 0.0039672851562500, 0.0003051757812500, +0.0037841796875000, 0.0002746582031250, 0.0043640136718750, 0.0004272460937500, +0.0044250488281250, 0.0004882812500000, 0.0044555664062500, 0.0004272460937500, +0.0046997070312500, 0.0004577636718750, 0.0047302246093750, 0.0005798339843750, +0.0046386718750000, 0.0004577636718750, 0.0047607421875000, 0.0005187988281250, +0.0047607421875000, 0.0005493164062500, 0.0046691894531250, 0.0005493164062500, +0.0047912597656250, 0.0006408691406250, 0.0047912597656250, 0.0005798339843750, +0.0048217773437500, 0.0006103515625000, 0.0048217773437500, 0.0006713867187500, +0.0047607421875000, 0.0007324218750000, 0.0047302246093750, 0.0007324218750000, +0.0046997070312500, 0.0008544921875000, 0.0046691894531250, 0.0009155273437500, +0.0045166015625000, 0.0009765625000000, 0.0043945312500000, 0.0010070800781250, +0.0043945312500000, 0.0010681152343750, 0.0042114257812500, 0.0011596679687500, +0.0040893554687500, 0.0012207031250000, 0.0041198730468750, 0.0012207031250000, +0.0040588378906250, 0.0012512207031250, 0.0039367675781250, 0.0013427734375000, +0.0039978027343750, 0.0011596679687500, 0.0039672851562500, 0.0012207031250000, +0.0039672851562500, 0.0012512207031250, 0.0040588378906250, 0.0010681152343750, +0.0040588378906250, 0.0010986328125000, 0.0038452148437500, 0.0012512207031250, +0.0039672851562500, 0.0011291503906250, 0.0036926269531250, 0.0011596679687500, +0.0033264160156250, 0.0014038085937500, 0.0036621093750000, 0.0012207031250000, +0.0029296875000000, 0.0012512207031250, 0.0031127929687500, 0.0013732910156250, +0.0027770996093750, 0.0011291503906250, 0.0021667480468750, 0.0009460449218750, +0.0026245117187500, 0.0011901855468750, 0.0018920898437500, 0.0008850097656250, +0.0017395019531250, 0.0007934570312500, 0.0019836425781250, 0.0011901855468750, +0.0018310546875000, 0.0013732910156250, 0.0018310546875000, 0.0010070800781250, +0.0026550292968750, 0.0020751953125000, 0.0025329589843750, 0.0020141601562500, +0.0031738281250000, 0.0022277832031250, 0.0040893554687500, 0.0028991699218750, +0.0037231445312500}, +{0.0067138671875000, 0.0002441406250000, 0.0075683593750000, 0.0002441406250000, +0.0057373046875000, 0.0002441406250000, 0.0058898925781250, 0.0002136230468750, +0.0055541992187500, 0.0002136230468750, 0.0043029785156250, 0.0002136230468750, +0.0048522949218750, 0.0000915527343750, 0.0038146972656250, 0.0000915527343750, +0.0037536621093750, 0.0000305175781250, 0.0037231445312500, 0.0000000000000000, +0.0032043457031250, 0.0000305175781250, 0.0034179687500000, 0.0000610351562500, +0.0032958984375000, 0.0000610351562500, 0.0031738281250000, 0.0001220703125000, +0.0032958984375000, 0.0000610351562500, 0.0033569335937500, 0.0000915527343750, +0.0032958984375000, 0.0003051757812500, 0.0034179687500000, 0.0001220703125000, +0.0033264160156250, 0.0002441406250000, 0.0032958984375000, 0.0004577636718750, +0.0032653808593750, 0.0004882812500000, 0.0032043457031250, 0.0004882812500000, +0.0032043457031250, 0.0007629394531250, 0.0031738281250000, 0.0006713867187500, +0.0032043457031250, 0.0007324218750000, 0.0032348632812500, 0.0009155273437500, +0.0030517578125000, 0.0007629394531250, 0.0032348632812500, 0.0009765625000000, +0.0031127929687500, 0.0009765625000000, 0.0032348632812500, 0.0009155273437500, +0.0033874511718750, 0.0010070800781250, 0.0031738281250000, 0.0010070800781250, +0.0037536621093750, 0.0008850097656250, 0.0037231445312500, 0.0009155273437500, +0.0038757324218750, 0.0008239746093750, 0.0043334960937500, 0.0006103515625000, +0.0041809082031250, 0.0007019042968750, 0.0045776367187500, 0.0006408691406250, +0.0047302246093750, 0.0005187988281250, 0.0047912597656250, 0.0006408691406250, +0.0048828125000000, 0.0006408691406250, 0.0050048828125000, 0.0003662109375000, +0.0049133300781250, 0.0008850097656250, 0.0049743652343750, 0.0005798339843750, +0.0049743652343750, 0.0006408691406250, 0.0048828125000000, 0.0010375976562500, +0.0048828125000000, 0.0007019042968750, 0.0050354003906250, 0.0010986328125000, +0.0048828125000000, 0.0010070800781250, 0.0048522949218750, 0.0009460449218750, +0.0050659179687500, 0.0010986328125000, 0.0049133300781250, 0.0009765625000000, +0.0047912597656250, 0.0009460449218750, 0.0048828125000000, 0.0010375976562500, +0.0046691894531250, 0.0009460449218750, 0.0043640136718750, 0.0008239746093750, +0.0043945312500000, 0.0008850097656250, 0.0041503906250000, 0.0010070800781250, +0.0039672851562500, 0.0008239746093750, 0.0040283203125000, 0.0010070800781250, +0.0040283203125000, 0.0012207031250000, 0.0039367675781250, 0.0009765625000000, +0.0042419433593750, 0.0011596679687500, 0.0041503906250000, 0.0012207031250000, +0.0041809082031250, 0.0010681152343750, 0.0044860839843750, 0.0009765625000000, +0.0043334960937500, 0.0010375976562500, 0.0041198730468750, 0.0009155273437500, +0.0042114257812500, 0.0007934570312500, 0.0037536621093750, 0.0010375976562500, +0.0032348632812500, 0.0010986328125000, 0.0034790039062500, 0.0009155273437500, +0.0025024414062500, 0.0018310546875000, 0.0025329589843750, 0.0016174316406250, +0.0020446777343750, 0.0018615722656250, 0.0012207031250000, 0.0026245117187500, +0.0016479492187500, 0.0022277832031250, 0.0006713867187500, 0.0027465820312500, +0.0006408691406250, 0.0028076171875000, 0.0005493164062500, 0.0027465820312500, +-0.0000610351562500, 0.0029296875000000, 0.0001831054687500, 0.0027770996093750, +0.0005798339843750, 0.0026245117187500, 0.0000000000000000, 0.0026855468750000, +0.0007324218750000, 0.0024719238281250, 0.0017089843750000, 0.0022888183593750, +0.0008850097656250, 0.0024108886718750, 0.0027160644531250, 0.0024108886718750, +0.0025634765625000, 0.0022277832031250, 0.0027160644531250, 0.0025634765625000, +0.0038146972656250, 0.0028381347656250, 0.0032958984375000, 0.0024719238281250, +0.0040893554687500, 0.0034790039062500, 0.0041809082031250, 0.0032043457031250, +0.0041809082031250, 0.0034790039062500, 0.0046691894531250, 0.0043945312500000, +0.0047302246093750, 0.0041809082031250, 0.0044555664062500, 0.0048522949218750, +0.0046081542968750, 0.0047607421875000, 0.0043945312500000, 0.0046997070312500, +0.0040588378906250, 0.0050354003906250, 0.0043640136718750, 0.0049438476562500, +0.0036621093750000, 0.0046386718750000, 0.0036621093750000, 0.0047912597656250, +0.0036926269531250, 0.0044250488281250, 0.0034179687500000, 0.0039978027343750, +0.0035095214843750, 0.0043029785156250, 0.0033569335937500, 0.0033569335937500, +0.0035095214843750, 0.0034484863281250, 0.0034179687500000, 0.0030212402343750, +0.0031738281250000, 0.0022888183593750, 0.0034790039062500, 0.0026855468750000, +0.0029602050781250, 0.0015869140625000, 0.0031738281250000, 0.0016479492187500, +0.0030517578125000, 0.0014038085937500, 0.0026855468750000, 0.0006103515625000, +0.0030212402343750, 0.0010070800781250, 0.0026245117187500, 0.0003356933593750, +0.0027160644531250, 0.0001525878906250, 0.0026550292968750, 0.0004882812500000, +0.0024414062500000, 0.0003051757812500, 0.0027160644531250, 0.0001831054687500, +0.0021972656250000, 0.0011901855468750, 0.0023498535156250, 0.0007019042968750, +0.0022277832031250, 0.0012817382812500, 0.0018920898437500, 0.0021972656250000, +0.0021667480468750, 0.0014953613281250, 0.0016174316406250, 0.0033569335937500, +0.0016784667968750, 0.0029602050781250, 0.0016784667968750, 0.0035400390625000, +0.0013122558593750, 0.0049438476562500, 0.0014953613281250, 0.0040893554687500, +0.0014953613281250, 0.0059814453125000, 0.0013732910156250, 0.0058898925781250, +0.0016174316406250, 0.0060729980468750, 0.0017700195312500, 0.0072631835937500, +0.0016479492187500, 0.0067749023437500, 0.0017089843750000, 0.0072021484375000, +0.0018615722656250, 0.0074157714843750, 0.0015563964843750, 0.0070190429687500, +0.0014038085937500, 0.0068054199218750, 0.0014953613281250, 0.0070495605468750, +0.0007324218750000, 0.0064697265625000, 0.0008544921875000, 0.0063171386718750, +0.0006103515625000, 0.0064392089843750, 0.0000305175781250, 0.0061645507812500, +0.0003662109375000, 0.0060729980468750, -0.0002746582031250, 0.0065612792968750, +-0.0002441406250000, 0.0063476562500000, -0.0001525878906250, 0.0065307617187500, +-0.0004577636718750, 0.0070495605468750, -0.0004577636718750, 0.0068054199218750, +-0.0000915527343750, 0.0070800781250000, -0.0004272460937500, 0.0071411132812500, +-0.0000305175781250, 0.0068664550781250, 0.0004577636718750, 0.0068359375000000, +-0.0000915527343750, 0.0069885253906250, 0.0009765625000000, 0.0063171386718750, +0.0007629394531250, 0.0065002441406250, 0.0008544921875000, 0.0062255859375000, +0.0014648437500000, 0.0056762695312500, 0.0010681152343750, 0.0061035156250000, +0.0014953613281250, 0.0052185058593750, 0.0014038085937500, 0.0053710937500000, +0.0014343261718750, 0.0053100585937500, 0.0016784667968750, 0.0046997070312500, +0.0013732910156250, 0.0050659179687500, 0.0017395019531250, 0.0047607421875000, +0.0015258789062500, 0.0047302246093750, 0.0014953613281250, 0.0049743652343750, +0.0017395019531250, 0.0049743652343750, 0.0013427734375000, 0.0050659179687500, +0.0014953613281250, 0.0053100585937500, 0.0014343261718750, 0.0054321289062500, +0.0011901855468750, 0.0053710937500000, 0.0011596679687500, 0.0054321289062500, +0.0011291503906250, 0.0055236816406250, 0.0007934570312500, 0.0050354003906250, +0.0009155273437500, 0.0053710937500000, 0.0007019042968750, 0.0049133300781250, +0.0003356933593750, 0.0043029785156250, 0.0006103515625000, 0.0047912597656250, +0.0002441406250000, 0.0034484863281250, 0.0002746582031250, 0.0035400390625000, +0.0002441406250000, 0.0031738281250000, 0.0000915527343750, 0.0022583007812500, +0.0003051757812500, 0.0027770996093750, 0.0002136230468750, 0.0018310546875000, +0.0002441406250000, 0.0017700195312500, 0.0003356933593750, 0.0019836425781250, +0.0002746582031250, 0.0015869140625000, 0.0003356933593750, 0.0017089843750000, +0.0003051757812500, 0.0021057128906250, 0.0003051757812500, 0.0018920898437500, +0.0003356933593750, 0.0022277832031250, 0.0003356933593750, 0.0027160644531250, +0.0003051757812500, 0.0023193359375000, 0.0003967285156250, 0.0031738281250000, +0.0002746582031250, 0.0029602050781250, 0.0003051757812500, 0.0031738281250000, +0.0003356933593750, 0.0037841796875000, 0.0001525878906250, 0.0033874511718750, +0.0003662109375000, 0.0040893554687500, 0.0002136230468750, 0.0040283203125000, +0.0003356933593750, 0.0040588378906250, 0.0004882812500000, 0.0045166015625000, +0.0002441406250000, 0.0043334960937500, 0.0006408691406250, 0.0047912597656250, +0.0005493164062500, 0.0047302246093750, 0.0005798339843750, 0.0048522949218750, +0.0007629394531250, 0.0051574707031250, 0.0005798339843750, 0.0050354003906250, +0.0008239746093750, 0.0055236816406250, 0.0006713867187500, 0.0055541992187500, +0.0007324218750000, 0.0057678222656250, 0.0009155273437500, 0.0061950683593750, +0.0005798339843750, 0.0061035156250000, 0.0009460449218750, 0.0063781738281250, +0.0008544921875000, 0.0065307617187500, 0.0008544921875000, 0.0063171386718750, +0.0011596679687500, 0.0062255859375000, 0.0010070800781250, 0.0063476562500000, +0.0013427734375000, 0.0053710937500000, 0.0013732910156250, 0.0056152343750000, +0.0014648437500000, 0.0051879882812500, 0.0018005371093750, 0.0042114257812500, +0.0017089843750000, 0.0046081542968750, 0.0017089843750000, 0.0038452148437500, +0.0018920898437500, 0.0035705566406250, 0.0016784667968750, 0.0037536621093750, +0.0014343261718750, 0.0035095214843750, 0.0017089843750000, 0.0033264160156250, +0.0009765625000000, 0.0038757324218750, 0.0011901855468750, 0.0034484863281250, +0.0010070800781250, 0.0037841796875000, 0.0004272460937500, 0.0043640136718750, +0.0008850097656250, 0.0037841796875000, 0.0005187988281250, 0.0049438476562500, +0.0004272460937500, 0.0047607421875000, 0.0008850097656250, 0.0046997070312500, +0.0009460449218750, 0.0054016113281250, 0.0007629394531250, 0.0049743652343750, +0.0022277832031250, 0.0050659179687500, 0.0017395019531250, 0.0050964355468750, +0.0022888183593750, 0.0047912597656250, 0.0036010742187500, 0.0046386718750000, +0.0026550292968750, 0.0047302246093750, 0.0037841796875000, 0.0040893554687500, +0.0039062500000000, 0.0042114257812500, 0.0034484863281250, 0.0039062500000000, +0.0035705566406250, 0.0033874511718750, 0.0035095214843750, 0.0037841796875000, +0.0029602050781250, 0.0029602050781250, 0.0027770996093750, 0.0031433105468750, +0.0028381347656250, 0.0029907226562500, 0.0024108886718750, 0.0024719238281250, +0.0022888183593750, 0.0028381347656250, 0.0032348632812500, 0.0020446777343750, +0.0026550292968750, 0.0020446777343750, 0.0032348632812500, 0.0021972656250000, +0.0043334960937500, 0.0017700195312500, 0.0035095214843750, 0.0018005371093750, +0.0049438476562500, 0.0028991699218750, 0.0049743652343750, 0.0024414062500000, +0.0046691894531250, 0.0033569335937500, 0.0053100585937500, 0.0046691894531250, +0.0052795410156250, 0.0037841796875000, 0.0043640136718750, 0.0056457519531250, +0.0047607421875000, 0.0056457519531250, 0.0043640136718750, 0.0056457519531250, +0.0032958984375000, 0.0065917968750000, 0.0037231445312500, 0.0061035156250000, +0.0031738281250000, 0.0060729980468750, 0.0027465820312500, 0.0062561035156250, +0.0030822753906250, 0.0058288574218750, 0.0034484863281250, 0.0051574707031250, +0.0034790039062500, 0.0050659179687500, 0.0038146972656250, 0.0052185058593750, +0.0033569335937500}, +{-0.0001831054687500, 0.0046691894531250, -0.0000915527343750, 0.0044555664062500, +0.0000000000000000, 0.0046691894531250, -0.0000305175781250, 0.0049743652343750, +0.0000000000000000, 0.0045776367187500, 0.0001220703125000, 0.0052490234375000, +0.0000610351562500, 0.0050964355468750, 0.0001525878906250, 0.0050659179687500, +0.0002441406250000, 0.0054321289062500, 0.0002136230468750, 0.0050964355468750, +0.0004272460937500, 0.0053405761718750, 0.0002746582031250, 0.0054016113281250, +0.0004577636718750, 0.0050964355468750, 0.0006408691406250, 0.0050659179687500, +0.0003356933593750, 0.0051574707031250, 0.0009460449218750, 0.0046081542968750, +0.0007324218750000, 0.0046997070312500, 0.0008544921875000, 0.0045776367187500, +0.0012817382812500, 0.0041198730468750, 0.0009155273437500, 0.0043640136718750, +0.0016174316406250, 0.0040893554687500, 0.0014953613281250, 0.0039672851562500, +0.0015563964843750, 0.0041809082031250, 0.0020751953125000, 0.0043029785156250, +0.0018615722656250, 0.0041809082031250, 0.0019226074218750, 0.0046081542968750, +0.0021362304687500, 0.0045471191406250, 0.0018920898437500, 0.0046081542968750, +0.0016174316406250, 0.0048522949218750, 0.0018920898437500, 0.0046691894531250, +0.0011901855468750, 0.0044250488281250, 0.0012512207031250, 0.0044250488281250, +0.0010986328125000, 0.0040588378906250, 0.0006408691406250, 0.0037231445312500, +0.0007934570312500, 0.0037536621093750, 0.0005493164062500, 0.0032653808593750, +0.0003662109375000, 0.0029296875000000, 0.0007934570312500, 0.0028686523437500, +0.0008850097656250, 0.0025634765625000, 0.0007019042968750, 0.0022277832031250, +0.0018005371093750, 0.0026245117187500, 0.0015563964843750, 0.0021667480468750, +0.0017700195312500, 0.0025024414062500, 0.0026550292968750, 0.0029907226562500, +0.0022277832031250, 0.0024108886718750, 0.0025939941406250, 0.0036926269531250, +0.0027160644531250, 0.0034179687500000, 0.0023498535156250, 0.0036621093750000, +0.0020751953125000, 0.0045166015625000, 0.0021667480468750, 0.0039672851562500, +0.0016174316406250, 0.0046691894531250, 0.0014343261718750, 0.0047912597656250, +0.0015258789062500, 0.0046386718750000, 0.0012512207031250, 0.0048522949218750, +0.0010681152343750, 0.0049438476562500, 0.0020751953125000, 0.0046081542968750, +0.0015258789062500, 0.0047302246093750, 0.0021057128906250, 0.0045471191406250, +0.0032348632812500, 0.0043029785156250, 0.0023498535156250, 0.0045471191406250, +0.0036621093750000, 0.0038757324218750, 0.0037841796875000, 0.0039672851562500, +0.0035400390625000, 0.0035705566406250, 0.0040893554687500, 0.0028991699218750, +0.0041198730468750, 0.0032653808593750, 0.0033874511718750, 0.0021362304687500, +0.0037536621093750, 0.0019531250000000, 0.0034179687500000, 0.0018920898437500, +0.0025939941406250, 0.0011596679687500, 0.0031433105468750, 0.0012512207031250, +0.0026550292968750, 0.0016479492187500, 0.0023193359375000, 0.0010681152343750, +0.0027160644531250, 0.0019531250000000, 0.0028686523437500, 0.0028076171875000, +0.0024719238281250, 0.0019531250000000, 0.0030822753906250, 0.0042419433593750, +0.0031127929687500, 0.0039978027343750, 0.0030822753906250, 0.0039978027343750, +0.0035095214843750, 0.0062561035156250, 0.0036010742187500, 0.0005798339843750, +0.0046386718750000, 0.0028076171875000, 0.0043334960937500, 0.0020141601562500, +0.0042419433593750, 0.0024719238281250, 0.0047912597656250, 0.0036010742187500, +0.0049133300781250, 0.0031433105468750, 0.0032958984375000, 0.0034790039062500, +0.0040893554687500, 0.0034790039062500, 0.0030212402343750, 0.0034790039062500, +0.0010986328125000, 0.0036621093750000, 0.0024414062500000, 0.0035095214843750, +0.0003662109375000, 0.0036926269531250, 0.0000000000000000, 0.0039062500000000, +0.0004882812500000, 0.0034484863281250, -0.0000610351562500, 0.0033264160156250, +-0.0001525878906250, 0.0036010742187500, 0.0007324218750000, 0.0023803710937500, +0.0004272460937500, 0.0025024414062500, 0.0007324218750000, 0.0024414062500000, +0.0014648437500000, 0.0015869140625000, 0.0010375976562500, 0.0018005371093750, +0.0020751953125000, 0.0019836425781250, 0.0017395019531250, 0.0017395019531250, +0.0023193359375000, 0.0019836425781250, 0.0032958984375000, 0.0023498535156250, +0.0025329589843750, 0.0020751953125000, 0.0043029785156250, 0.0021972656250000, +0.0041809082031250, 0.0023803710937500, 0.0045471191406250, 0.0019531250000000, +0.0057373046875000, 0.0016784667968750, 0.0052490234375000, 0.0020141601562500, +0.0061645507812500, 0.0010375976562500, 0.0063476562500000, 0.0012512207031250, +0.0063171386718750, 0.0009460449218750, 0.0066223144531250, 0.0002136230468750, +0.0065307617187500, 0.0007324218750000, 0.0068664550781250, 0.0002441406250000, +0.0066833496093750, 0.0001525878906250, 0.0067443847656250, 0.0006103515625000, +0.0069580078125000, 0.0007629394531250, 0.0066528320312500, 0.0006713867187500, +0.0069580078125000, 0.0015258789062500, 0.0069274902343750, 0.0016174316406250, +0.0067138671875000, 0.0016174316406250, 0.0067443847656250, 0.0021667480468750, +0.0066833496093750, 0.0021057128906250, 0.0061340332031250, 0.0016479492187500, +0.0063476562500000, 0.0018920898437500, 0.0058593750000000, 0.0015869140625000, +0.0051879882812500, 0.0010375976562500, 0.0056457519531250, 0.0014343261718750, +0.0048217773437500, 0.0008544921875000, 0.0046691894531250, 0.0007934570312500, +0.0049743652343750, 0.0009155273437500, 0.0047302246093750, 0.0007019042968750, +0.0046691894531250, 0.0008239746093750, 0.0055847167968750, 0.0009765625000000, +0.0053100585937500, 0.0010070800781250, 0.0056762695312500, 0.0010986328125000, +0.0065612792968750, 0.0013732910156250, 0.0061645507812500, 0.0014953613281250, +0.0069274902343750, 0.0012207031250000, 0.0072021484375000, 0.0015869140625000, +0.0069274902343750, 0.0012817382812500, 0.0070495605468750, 0.0008544921875000, +0.0074157714843750, 0.0013732910156250, 0.0061950683593750, 0.0003051757812500, +0.0068054199218750, 0.0005493164062500, 0.0061645507812500, 0.0004577636718750, +0.0050354003906250, -0.0002746582031250, 0.0060729980468750, 0.0001831054687500, +0.0041198730468750, -0.0001831054687500, 0.0045471191406250, -0.0002746582031250, +0.0043334960937500, -0.0001525878906250, 0.0030517578125000, -0.0003051757812500, +0.0040588378906250, -0.0002136230468750, 0.0032958984375000, -0.0001220703125000, +0.0032653808593750, -0.0001220703125000, 0.0037231445312500, -0.0000915527343750, +0.0036315917968750, 0.0000000000000000, 0.0036926269531250, -0.0000305175781250, +0.0043640136718750, -0.0002136230468750, 0.0042724609375000, -0.0000610351562500, +0.0046386718750000, -0.0001831054687500, 0.0052795410156250, -0.0003967285156250, +0.0050048828125000, -0.0001831054687500, 0.0057983398437500, -0.0004577636718750, +0.0057983398437500, -0.0003356933593750, 0.0057983398437500, -0.0002441406250000, +0.0061950683593750, -0.0003051757812500, 0.0060729980468750, -0.0001831054687500, +0.0058593750000000, 0.0000915527343750, 0.0059814453125000, -0.0000305175781250, +0.0057678222656250, 0.0003662109375000, 0.0054626464843750, 0.0007629394531250, +0.0056152343750000, 0.0004272460937500, 0.0050659179687500, 0.0012817382812500, +0.0051269531250000, 0.0010986328125000, 0.0049438476562500, 0.0012512207031250, +0.0045166015625000, 0.0017395019531250, 0.0046386718750000, 0.0012817382812500, +0.0043029785156250, 0.0017395019531250, 0.0043334960937500, 0.0018310546875000, +0.0042114257812500, 0.0016174316406250, 0.0039978027343750, 0.0016784667968750, +0.0040893554687500, 0.0016784667968750, 0.0037231445312500, 0.0014038085937500, +0.0037536621093750, 0.0014648437500000, 0.0036315917968750, 0.0013122558593750, +0.0033264160156250, 0.0010681152343750, 0.0035400390625000, 0.0011901855468750, +0.0031738281250000, 0.0008850097656250, 0.0032653808593750, 0.0008544921875000, +0.0032348632812500, 0.0009765625000000, 0.0029296875000000, 0.0009460449218750, +0.0030822753906250, 0.0008239746093750, 0.0029296875000000, 0.0011291503906250, +0.0028686523437500, 0.0009765625000000, 0.0029296875000000, 0.0009765625000000, +0.0029602050781250, 0.0011596679687500, 0.0028991699218750, 0.0009765625000000, +0.0029296875000000, 0.0010681152343750, 0.0028991699218750, 0.0010986328125000, +0.0029296875000000, 0.0010070800781250, 0.0028686523437500, 0.0010070800781250, +0.0027770996093750, 0.0011291503906250, 0.0029907226562500, 0.0008850097656250, +0.0027770996093750, 0.0009155273437500, 0.0028076171875000, 0.0009460449218750, +0.0030212402343750, 0.0008239746093750, 0.0027770996093750, 0.0008544921875000, +0.0029296875000000, 0.0009155273437500, 0.0028991699218750, 0.0008239746093750, +0.0027770996093750, 0.0008850097656250, 0.0027770996093750, 0.0009155273437500, +0.0026245117187500, 0.0008544921875000, 0.0025634765625000, 0.0009460449218750, +0.0024108886718750, 0.0009460449218750, 0.0024719238281250, 0.0007629394531250, +0.0024719238281250, 0.0006713867187500, 0.0021972656250000, 0.0006713867187500, +0.0027465820312500, 0.0004882812500000, 0.0025024414062500, 0.0003356933593750, +0.0025024414062500, 0.0005187988281250, 0.0028991699218750, 0.0005493164062500, +0.0025939941406250, 0.0003356933593750, 0.0027160644531250, 0.0011901855468750, +0.0028076171875000, 0.0010070800781250, 0.0025939941406250, 0.0012512207031250, +0.0024108886718750, 0.0019531250000000, 0.0024719238281250, 0.0016479492187500, +0.0022888183593750, 0.0019531250000000, 0.0021667480468750, 0.0021972656250000, +0.0024719238281250, 0.0019226074218750, 0.0027160644531250, 0.0018615722656250, +0.0026245117187500, 0.0020141601562500, 0.0036010742187500, 0.0014953613281250, +0.0036010742187500, 0.0016479492187500, 0.0038452148437500, 0.0015563964843750, +0.0045166015625000, 0.0011291503906250, 0.0043334960937500, 0.0013732910156250, +0.0046691894531250, 0.0012207031250000, 0.0047912597656250, 0.0010681152343750, +0.0048217773437500, 0.0014648437500000, 0.0048522949218750, 0.0015869140625000, +0.0047912597656250, 0.0013122558593750, 0.0047302246093750, 0.0023193359375000, +0.0047912597656250, 0.0020446777343750, 0.0044860839843750, 0.0025329589843750, +0.0042724609375000, 0.0035095214843750, 0.0044860839843750, 0.0030212402343750, +0.0034790039062500, 0.0039062500000000, 0.0037231445312500, 0.0040588378906250, +0.0032653808593750, 0.0038452148437500, 0.0022888183593750, 0.0041503906250000, +0.0028076171875000, 0.0042724609375000, 0.0016174316406250, 0.0037231445312500, +0.0015258789062500, 0.0041198730468750, 0.0014953613281250, 0.0036926269531250, +0.0007629394531250, 0.0028686523437500, 0.0007629394531250, 0.0032653808593750, +0.0007324218750000, 0.0024414062500000, 0.0006713867187500, 0.0027465820312500, +0.0008850097656250, 0.0027160644531250, 0.0010070800781250, 0.0021667480468750, +0.0010375976562500, 0.0024414062500000, 0.0017395019531250, 0.0020141601562500, +0.0016784667968750, 0.0022277832031250, 0.0020446777343750, 0.0021972656250000, +0.0027770996093750, 0.0018310546875000, 0.0025329589843750, 0.0021667480468750, +0.0030212402343750, 0.0021057128906250, 0.0032348632812500, 0.0020141601562500, +0.0029602050781250, 0.0025024414062500, 0.0030517578125000, 0.0028991699218750, +0.0033264160156250, 0.0027770996093750, 0.0025939941406250, 0.0037536621093750, +0.0027465820312500, 0.0038146972656250, 0.0026245117187500, 0.0042114257812500, +0.0021667480468750}, +{0.0053405761718750, 0.0008850097656250, 0.0054626464843750, 0.0008850097656250, +0.0051879882812500, 0.0008239746093750, 0.0056152343750000, 0.0007019042968750, +0.0054626464843750, 0.0007934570312500, 0.0055541992187500, 0.0007019042968750, +0.0058898925781250, 0.0005187988281250, 0.0056457519531250, 0.0006408691406250, +0.0059509277343750, 0.0005493164062500, 0.0058288574218750, 0.0005187988281250, +0.0058288574218750, 0.0004882812500000, 0.0059509277343750, 0.0004882812500000, +0.0057067871093750, 0.0006103515625000, 0.0059509277343750, 0.0005187988281250, +0.0057678222656250, 0.0005493164062500, 0.0057678222656250, 0.0005493164062500, +0.0059509277343750, 0.0004882812500000, 0.0056457519531250, 0.0006103515625000, +0.0058898925781250, 0.0005187988281250, 0.0058288574218750, 0.0004882812500000, +0.0056152343750000, 0.0006713867187500, 0.0057067871093750, 0.0007629394531250, +0.0055236816406250, 0.0006103515625000, 0.0050354003906250, 0.0012512207031250, +0.0050659179687500, 0.0011596679687500, 0.0046997070312500, 0.0013732910156250, +0.0042114257812500, 0.0019531250000000, 0.0042724609375000, 0.0018005371093750, +0.0036010742187500, 0.0018310546875000, 0.0035400390625000, 0.0021972656250000, +0.0034179687500000, 0.0019531250000000, 0.0030517578125000, 0.0016784667968750, +0.0030822753906250, 0.0020446777343750, 0.0027160644531250, 0.0014038085937500, +0.0027465820312500, 0.0014953613281250, 0.0025939941406250, 0.0015563964843750, +0.0022888183593750, 0.0012512207031250, 0.0024719238281250, 0.0014343261718750, +0.0022583007812500, 0.0015258789062500, 0.0021667480468750, 0.0014648437500000, +0.0025024414062500, 0.0017700195312500, 0.0026550292968750, 0.0020141601562500, +0.0025939941406250, 0.0018310546875000, 0.0034790039062500, 0.0026550292968750, +0.0034179687500000, 0.0025634765625000, 0.0037841796875000, 0.0028076171875000, +0.0046081542968750, 0.0034179687500000, 0.0043640136718750, 0.0032043457031250, +0.0050048828125000, 0.0037231445312500, 0.0051269531250000, 0.0037841796875000, +0.0052490234375000, 0.0038146972656250, 0.0055541992187500, 0.0040283203125000, +0.0056152343750000, 0.0040283203125000, 0.0060424804687500, 0.0036621093750000, +0.0059509277343750, 0.0039672851562500, 0.0060424804687500, 0.0036010742187500, +0.0064392089843750, 0.0031127929687500, 0.0062561035156250, 0.0036621093750000, +0.0059204101562500, 0.0025939941406250, 0.0061645507812500, 0.0028686523437500, +0.0056152343750000, 0.0028686523437500, 0.0045166015625000, 0.0021972656250000, +0.0041809082031250, 0.0026245117187500, 0.0026550292968750, 0.0022888183593750, +0.0030822753906250, 0.0023803710937500, 0.0028991699218750, 0.0025634765625000, +0.0018310546875000, 0.0025024414062500, 0.0022583007812500, 0.0027465820312500, +0.0012512207031250, 0.0030212402343750, 0.0012207031250000, 0.0030212402343750, +0.0011291503906250, 0.0033874511718750, 0.0006103515625000, 0.0038452148437500, +0.0009765625000000, 0.0039367675781250, 0.0008850097656250, 0.0046386718750000, +0.0006713867187500, 0.0049133300781250, 0.0012207031250000, 0.0050048828125000, +0.0015869140625000, 0.0054626464843750, 0.0012817382812500, 0.0056762695312500, +0.0020751953125000, 0.0055847167968750, 0.0021362304687500, 0.0059814453125000, +0.0021667480468750, 0.0058898925781250, 0.0024414062500000, 0.0057678222656250, +0.0023193359375000, 0.0061950683593750, 0.0026550292968750, 0.0054626464843750, +0.0026550292968750, 0.0058593750000000, 0.0026245117187500, 0.0053405761718750, +0.0027770996093750, 0.0044860839843750, 0.0027465820312500, 0.0052795410156250, +0.0025634765625000, 0.0033264160156250, 0.0025939941406250, 0.0037536621093750, +0.0025329589843750, 0.0032958984375000, 0.0024414062500000, 0.0017700195312500, +0.0025024414062500, 0.0025329589843750, 0.0022888183593750, 0.0017089843750000, +0.0024108886718750, 0.0014343261718750, 0.0022888183593750, 0.0017089843750000, +0.0020446777343750, 0.0016174316406250, 0.0022583007812500, 0.0015563964843750, +0.0018615722656250, 0.0016174316406250, 0.0018920898437500, 0.0016784667968750, +0.0017089843750000, 0.0015563964843750, 0.0014038085937500, 0.0015258789062500, +0.0016174316406250, 0.0014953613281250, 0.0009460449218750, 0.0012207031250000, +0.0011596679687500, 0.0011596679687500, 0.0008850097656250, 0.0010986328125000, +0.0003967285156250, 0.0009765625000000, 0.0008544921875000, 0.0009460449218750, +-0.0000610351562500, 0.0008239746093750, 0.0001831054687500, 0.0008239746093750, +0.0001831054687500, 0.0007019042968750, -0.0003662109375000, 0.0005493164062500, +-0.0001220703125000, 0.0005493164062500, -0.0000610351562500, 0.0002441406250000, +-0.0003967285156250, 0.0001831054687500, -0.0000305175781250, 0.0000915527343750, +0.0002746582031250, -0.0000305175781250, -0.0002136230468750, -0.0000610351562500, +0.0005798339843750, 0.0001525878906250, 0.0004272460937500, 0.0000305175781250, +0.0003967285156250, 0.0001525878906250, 0.0008239746093750, 0.0004577636718750, +0.0004272460937500, 0.0003356933593750, 0.0008239746093750, 0.0003051757812500, +0.0005493164062500, 0.0004272460937500, 0.0005187988281250, 0.0002746582031250, +0.0007324218750000, 0.0001220703125000, 0.0002441406250000, 0.0002746582031250, +0.0006103515625000, -0.0000915527343750, 0.0002441406250000, -0.0000915527343750, +0.0002441406250000, 0.0000610351562500, 0.0004577636718750, -0.0001220703125000, +-0.0000610351562500, -0.0001220703125000, 0.0005493164062500, 0.0004882812500000, +0.0001831054687500, 0.0003051757812500, 0.0002746582031250, 0.0007019042968750, +0.0007934570312500, 0.0012512207031250, 0.0003356933593750, 0.0009155273437500, +0.0008239746093750, 0.0020446777343750, 0.0008544921875000, 0.0018005371093750, +0.0007934570312500, 0.0022277832031250, 0.0010986328125000, 0.0030517578125000, +0.0011291503906250, 0.0024414062500000, 0.0011291503906250, 0.0038452148437500, +0.0013122558593750, 0.0036010742187500, 0.0012207031250000, 0.0039367675781250, +0.0011291503906250, 0.0049743652343750, 0.0014343261718750, 0.0042724609375000, +0.0009460449218750, 0.0052490234375000, 0.0012207031250000, 0.0051269531250000, +0.0010986328125000, 0.0051574707031250, 0.0007629394531250, 0.0057067871093750, +0.0012512207031250, 0.0053100585937500, 0.0006103515625000, 0.0056152343750000, +0.0008850097656250, 0.0056457519531250, 0.0007934570312500, 0.0054931640625000, +0.0003051757812500, 0.0054931640625000, 0.0007324218750000, 0.0054016113281250, +0.0000610351562500, 0.0051269531250000, 0.0001525878906250, 0.0051269531250000, +0.0000915527343750, 0.0049133300781250, -0.0003662109375000, 0.0046081542968750, +-0.0000915527343750, 0.0046691894531250, -0.0003356933593750, 0.0043029785156250, +-0.0003967285156250, 0.0042724609375000, -0.0002441406250000, 0.0042419433593750, +-0.0002746582031250, 0.0040283203125000, -0.0003967285156250, 0.0041198730468750, +0.0001220703125000, 0.0039672851562500, -0.0001525878906250, 0.0039978027343750, +0.0000610351562500, 0.0040588378906250, 0.0004577636718750, 0.0039978027343750, +-0.0000305175781250, 0.0040893554687500, 0.0007934570312500, 0.0039978027343750, +0.0005493164062500, 0.0039978027343750, 0.0006103515625000, 0.0041198730468750, +0.0011596679687500, 0.0041198730468750, 0.0008239746093750, 0.0041503906250000, +0.0012207031250000, 0.0043640136718750, 0.0013732910156250, 0.0043029785156250, +0.0011901855468750, 0.0045166015625000, 0.0013427734375000, 0.0047607421875000, +0.0015563964843750, 0.0045471191406250, 0.0010986328125000, 0.0048828125000000, +0.0014038085937500, 0.0049438476562500, 0.0012817382812500, 0.0048522949218750, +0.0008544921875000, 0.0048217773437500, 0.0012512207031250, 0.0047607421875000, +0.0008239746093750, 0.0044860839843750, 0.0008239746093750, 0.0044555664062500, +0.0010681152343750, 0.0043945312500000, 0.0010681152343750, 0.0041198730468750, +0.0011596679687500, 0.0041503906250000, 0.0015869140625000, 0.0043029785156250, +0.0017395019531250, 0.0040588378906250, 0.0018310546875000, 0.0042724609375000, +0.0021972656250000, 0.0045166015625000, 0.0024108886718750, 0.0041503906250000, +0.0020141601562500, 0.0046386718750000, 0.0023803710937500, 0.0045471191406250, +0.0021057128906250, 0.0044555664062500, 0.0014343261718750, 0.0046997070312500, +0.0018920898437500, 0.0046386718750000, 0.0010375976562500, 0.0044250488281250, +0.0009460449218750, 0.0045776367187500, 0.0011901855468750, 0.0043640136718750, +0.0009155273437500, 0.0041198730468750, 0.0007629394531250, 0.0042724609375000, +0.0016479492187500, 0.0036621093750000, 0.0014953613281250, 0.0038452148437500, +0.0017089843750000, 0.0033874511718750, 0.0025024414062500, 0.0027160644531250, +0.0022888183593750, 0.0032348632812500, 0.0024719238281250, 0.0020446777343750, +0.0029296875000000, 0.0021362304687500, 0.0025634765625000, 0.0020141601562500, +0.0023803710937500, 0.0013732910156250, 0.0029602050781250, 0.0017089843750000, +0.0020141601562500, 0.0012512207031250, 0.0024108886718750, 0.0012512207031250, +0.0024108886718750, 0.0012512207031250, 0.0018920898437500, 0.0010070800781250, +0.0024108886718750, 0.0012207031250000, 0.0022888183593750, 0.0012512207031250, +0.0022888183593750, 0.0010681152343750, 0.0025329589843750, 0.0014343261718750, +0.0026855468750000, 0.0016479492187500, 0.0028991699218750, 0.0014343261718750, +0.0028381347656250, 0.0025329589843750, 0.0032348632812500, 0.0022583007812500, +0.0031433105468750, 0.0028076171875000, 0.0028991699218750, 0.0037231445312500, +0.0034484863281250, 0.0030517578125000, 0.0030822753906250, 0.0045776367187500, +0.0032653808593750, 0.0043029785156250, 0.0036621093750000, 0.0045471191406250, +0.0037841796875000, 0.0056152343750000, 0.0039978027343750, 0.0048522949218750, +0.0045166015625000, 0.0049133300781250, 0.0048828125000000, 0.0054321289062500, +0.0046081542968750, 0.0046081542968750, 0.0041503906250000, 0.0031433105468750, +0.0021362304687500, 0.0039062500000000, 0.0005187988281250, 0.0054321289062500, +0.0006713867187500, 0.0057678222656250, 0.0011596679687500, 0.0050964355468750, +0.0010375976562500, 0.0049133300781250, 0.0008239746093750, 0.0054016113281250, +0.0018310546875000, 0.0040283203125000, 0.0017395019531250, 0.0042114257812500, +0.0018920898437500, 0.0043334960937500, 0.0025024414062500, 0.0038146972656250, +0.0022277832031250, 0.0040588378906250, 0.0030517578125000, 0.0036926269531250, +0.0027770996093750, 0.0039672851562500, 0.0034790039062500, 0.0037231445312500, +0.0044860839843750, 0.0031433105468750, 0.0038757324218750, 0.0035400390625000, +0.0056152343750000, 0.0032348632812500, 0.0057373046875000, 0.0029602050781250, +0.0056457519531250, 0.0033264160156250, 0.0066223144531250, 0.0036926269531250, +0.0065612792968750, 0.0033569335937500, 0.0061340332031250, 0.0041503906250000, +0.0065917968750000, 0.0043945312500000, 0.0062866210937500, 0.0041198730468750, +0.0057678222656250, 0.0043334960937500, 0.0064086914062500, 0.0046081542968750, +0.0051879882812500, 0.0035705566406250, 0.0058593750000000, 0.0039062500000000, +0.0052795410156250, 0.0035705566406250, 0.0042724609375000, 0.0026245117187500, +0.0054016113281250, 0.0030212402343750, 0.0030212402343750, 0.0021667480468750, +0.0037231445312500, 0.0020446777343750, 0.0030212402343750, 0.0020141601562500, +0.0011291503906250, 0.0015563964843750, 0.0025939941406250, 0.0016174316406250, +0.0003356933593750}, +{0.0019226074218750, 0.0037536621093750, 0.0012207031250000, 0.0039062500000000, +0.0011291503906250, 0.0036621093750000, 0.0014038085937500, 0.0039062500000000, +0.0013122558593750, 0.0042419433593750, 0.0012207031250000, 0.0038146972656250, +0.0018920898437500, 0.0046997070312500, 0.0018005371093750, 0.0045471191406250, +0.0019836425781250, 0.0046997070312500, 0.0025024414062500, 0.0053100585937500, +0.0024108886718750, 0.0049438476562500, 0.0023803710937500, 0.0055541992187500, +0.0028076171875000, 0.0055847167968750, 0.0024719238281250, 0.0055847167968750, +0.0020751953125000, 0.0059509277343750, 0.0026245117187500, 0.0058593750000000, +0.0017700195312500, 0.0056457519531250, 0.0018920898437500, 0.0059509277343750, +0.0021057128906250, 0.0056457519531250, 0.0017089843750000, 0.0051574707031250, +0.0020141601562500, 0.0055847167968750, 0.0022583007812500, 0.0048522949218750, +0.0022583007812500, 0.0049743652343750, 0.0024719238281250, 0.0048522949218750, +0.0028076171875000, 0.0043640136718750, 0.0028076171875000, 0.0046386718750000, +0.0028076171875000, 0.0037231445312500, 0.0031433105468750, 0.0038452148437500, +0.0029602050781250, 0.0034484863281250, 0.0027465820312500, 0.0025939941406250, +0.0031738281250000, 0.0028686523437500, 0.0029602050781250, 0.0019531250000000, +0.0028076171875000, 0.0016174316406250, 0.0031738281250000, 0.0016174316406250, +0.0034179687500000, 0.0012512207031250, 0.0032653808593750, 0.0010375976562500, +0.0037841796875000, 0.0013427734375000, 0.0041503906250000, 0.0009460449218750, +0.0038452148437500, 0.0013122558593750, 0.0040283203125000, 0.0016784667968750, +0.0045166015625000, 0.0010986328125000, 0.0025634765625000, 0.0029296875000000, +0.0032653808593750, 0.0023498535156250, 0.0030212402343750, 0.0028076171875000, +0.0003967285156250, 0.0055236816406250, 0.0010681152343750, 0.0010681152343750, +0.0024719238281250, 0.0024108886718750, 0.0020446777343750, 0.0013122558593750, +0.0024414062500000, 0.0025024414062500, 0.0032348632812500, 0.0040893554687500, +0.0030517578125000, 0.0031738281250000, 0.0036926269531250, 0.0045471191406250, +0.0034484863281250, 0.0048522949218750, 0.0039672851562500, 0.0045471191406250, +0.0046997070312500, 0.0048217773437500, 0.0041809082031250, 0.0048522949218750, +0.0055541992187500, 0.0049133300781250, 0.0057678222656250, 0.0048828125000000, +0.0054626464843750, 0.0049133300781250, 0.0061035156250000, 0.0051269531250000, +0.0062561035156250, 0.0052490234375000, 0.0047302246093750, 0.0046386718750000, +0.0053405761718750, 0.0050659179687500, 0.0046691894531250, 0.0046081542968750, +0.0031738281250000, 0.0037231445312500, 0.0041198730468750, 0.0043334960937500, +0.0025329589843750, 0.0033874511718750, 0.0026245117187500, 0.0031127929687500, +0.0023193359375000, 0.0034790039062500, 0.0013427734375000, 0.0033569335937500, +0.0020446777343750, 0.0030517578125000, 0.0004882812500000, 0.0037841796875000, +0.0007019042968750, 0.0037536621093750, 0.0005798339843750, 0.0036010742187500, +-0.0004882812500000, 0.0039367675781250, 0.0000610351562500, 0.0038757324218750, +-0.0002136230468750, 0.0034790039062500, -0.0004577636718750, 0.0036926269531250, +0.0001831054687500, 0.0033264160156250, 0.0004577636718750, 0.0028686523437500, +0.0001525878906250, 0.0032958984375000, 0.0018310546875000, 0.0022888183593750, +0.0016479492187500, 0.0025329589843750, 0.0019531250000000, 0.0024719238281250, +0.0032653808593750, 0.0018310546875000, 0.0028381347656250, 0.0022583007812500, +0.0034484863281250, 0.0018615722656250, 0.0038452148437500, 0.0018615722656250, +0.0034790039062500, 0.0019531250000000, 0.0034484863281250, 0.0018615722656250, +0.0037841796875000, 0.0020141601562500, 0.0030212402343750, 0.0016784667968750, +0.0031738281250000, 0.0019531250000000, 0.0031433105468750, 0.0017395019531250, +0.0026245117187500, 0.0013122558593750, 0.0028686523437500, 0.0016479492187500, +0.0029296875000000, 0.0010375976562500, 0.0027465820312500, 0.0010070800781250, +0.0032653808593750, 0.0009460449218750, 0.0036010742187500, 0.0005798339843750, +0.0032958984375000, 0.0007019042968750, 0.0044250488281250, 0.0004577636718750, +0.0041198730468750, 0.0004272460937500, 0.0044860839843750, 0.0003967285156250, +0.0054321289062500, 0.0002746582031250, 0.0048522949218750, 0.0002441406250000, +0.0057373046875000, 0.0001525878906250, 0.0056762695312500, 0.0000915527343750, +0.0055847167968750, 0.0000305175781250, 0.0058593750000000, 0.0000305175781250, +0.0055236816406250, 0.0000610351562500, 0.0056457519531250, -0.0003356933593750, +0.0055236816406250, -0.0001831054687500, 0.0052795410156250, -0.0002746582031250, +0.0052490234375000, -0.0006103515625000, 0.0052490234375000, -0.0004272460937500, +0.0046997070312500, -0.0005798339843750, 0.0047607421875000, -0.0007324218750000, +0.0043334960937500, -0.0006408691406250, 0.0038146972656250, -0.0006103515625000, +0.0040283203125000, -0.0008239746093750, 0.0031433105468750, -0.0003662109375000, +0.0031127929687500, -0.0005493164062500, 0.0029907226562500, -0.0003967285156250, +0.0023498535156250, 0.0000610351562500, 0.0024414062500000, -0.0001831054687500, +0.0026245117187500, 0.0000915527343750, 0.0020141601562500, 0.0002136230468750, +0.0025939941406250, 0.0000610351562500, 0.0032653808593750, 0.0000305175781250, +0.0025024414062500, 0.0002441406250000, 0.0040588378906250, -0.0000305175781250, +0.0036621093750000, 0.0000610351562500, 0.0039367675781250, 0.0001220703125000, +0.0050048828125000, -0.0000610351562500, 0.0041503906250000, 0.0000610351562500, +0.0050964355468750, 0.0001220703125000, 0.0050964355468750, 0.0000305175781250, +0.0049133300781250, 0.0002441406250000, 0.0053405761718750, 0.0003662109375000, +0.0051574707031250, 0.0001220703125000, 0.0050354003906250, 0.0005493164062500, +0.0052795410156250, 0.0005187988281250, 0.0051269531250000, 0.0004272460937500, +0.0049133300781250, 0.0006713867187500, 0.0051879882812500, 0.0007019042968750, +0.0047912597656250, 0.0006408691406250, 0.0050048828125000, 0.0007019042968750, +0.0049743652343750, 0.0007934570312500, 0.0047302246093750, 0.0008239746093750, +0.0049743652343750, 0.0007934570312500, 0.0044555664062500, 0.0009460449218750, +0.0046386718750000, 0.0008239746093750, 0.0044555664062500, 0.0008239746093750, +0.0040283203125000, 0.0009155273437500, 0.0043945312500000, 0.0008239746093750, +0.0039367675781250, 0.0008850097656250, 0.0039672851562500, 0.0009155273437500, +0.0039367675781250, 0.0008544921875000, 0.0036926269531250, 0.0008850097656250, +0.0038757324218750, 0.0008239746093750, 0.0037231445312500, 0.0007324218750000, +0.0036926269531250, 0.0007629394531250, 0.0036315917968750, 0.0006408691406250, +0.0035095214843750, 0.0005187988281250, 0.0035400390625000, 0.0007019042968750, +0.0032653808593750, 0.0004272460937500, 0.0032348632812500, 0.0005798339843750, +0.0030212402343750, 0.0004882812500000, 0.0026855468750000, 0.0002746582031250, +0.0027770996093750, 0.0005493164062500, 0.0023193359375000, 0.0003051757812500, +0.0022277832031250, 0.0002746582031250, 0.0021972656250000, 0.0003967285156250, +0.0019531250000000, 0.0003662109375000, 0.0020751953125000, 0.0003356933593750, +0.0022277832031250, 0.0009155273437500, 0.0020751953125000, 0.0007019042968750, +0.0022583007812500, 0.0008850097656250, 0.0025939941406250, 0.0014648437500000, +0.0025329589843750, 0.0010986328125000, 0.0025634765625000, 0.0014953613281250, +0.0027770996093750, 0.0016174316406250, 0.0025939941406250, 0.0014038085937500, +0.0024108886718750, 0.0013122558593750, 0.0026245117187500, 0.0014648437500000, +0.0022583007812500, 0.0010681152343750, 0.0022277832031250, 0.0010070800781250, +0.0023193359375000, 0.0010986328125000, 0.0021667480468750, 0.0009155273437500, +0.0022583007812500, 0.0007629394531250, 0.0026550292968750, 0.0011901855468750, +0.0025939941406250, 0.0008850097656250, 0.0028686523437500, 0.0010986328125000, +0.0033264160156250, 0.0015258789062500, 0.0031738281250000, 0.0010986328125000, +0.0035705566406250, 0.0020751953125000, 0.0036621093750000, 0.0017700195312500, +0.0035095214843750, 0.0021362304687500, 0.0034790039062500, 0.0029296875000000, +0.0036621093750000, 0.0023498535156250, 0.0039367675781250, 0.0032348632812500, +0.0037841796875000, 0.0031738281250000, 0.0041809082031250, 0.0031738281250000, +0.0046386718750000, 0.0036010742187500, 0.0043334960937500, 0.0032653808593750, +0.0050048828125000, 0.0035400390625000, 0.0052490234375000, 0.0035400390625000, +0.0050964355468750, 0.0034484863281250, 0.0052185058593750, 0.0035400390625000, +0.0053710937500000, 0.0035705566406250, 0.0051879882812500, 0.0032348632812500, +0.0051879882812500, 0.0034790039062500, 0.0051879882812500, 0.0031433105468750, +0.0050048828125000, 0.0026245117187500, 0.0050048828125000, 0.0030517578125000, +0.0049133300781250, 0.0025939941406250, 0.0048217773437500, 0.0024719238281250, +0.0046691894531250, 0.0027160644531250, 0.0044555664062500, 0.0026855468750000, +0.0045166015625000, 0.0027160644531250, 0.0040893554687500, 0.0034179687500000, +0.0039062500000000, 0.0032958984375000, 0.0039672851562500, 0.0035705566406250, +0.0038146972656250, 0.0043945312500000, 0.0036315917968750, 0.0044555664062500, +0.0043029785156250, 0.0049743652343750, 0.0040588378906250, 0.0050659179687500, +0.0040893554687500, 0.0049438476562500, 0.0046386718750000, 0.0051269531250000, +0.0045166015625000, 0.0053405761718750, 0.0047912597656250, 0.0044860839843750, +0.0048522949218750, 0.0048217773437500, 0.0050048828125000, 0.0045166015625000, +0.0051574707031250, 0.0037231445312500, 0.0049743652343750, 0.0042419433593750, +0.0054016113281250, 0.0033569335937500, 0.0053405761718750, 0.0033569335937500, +0.0050659179687500, 0.0031433105468750, 0.0051879882812500, 0.0025939941406250, +0.0051879882812500, 0.0028686523437500, 0.0045471191406250, 0.0019531250000000, +0.0046386718750000, 0.0019226074218750, 0.0043334960937500, 0.0017700195312500, +0.0038146972656250, 0.0011596679687500, 0.0040893554687500, 0.0013732910156250, +0.0035705566406250, 0.0009765625000000, 0.0035095214843750, 0.0008239746093750, +0.0034790039062500, 0.0009765625000000, 0.0032348632812500, 0.0008850097656250, +0.0033569335937500, 0.0008850097656250, 0.0032653808593750, 0.0014953613281250, +0.0030517578125000, 0.0012817382812500, 0.0032043457031250, 0.0015869140625000, +0.0032348632812500, 0.0022277832031250, 0.0029296875000000, 0.0019836425781250, +0.0032958984375000, 0.0028686523437500, 0.0030517578125000, 0.0028381347656250, +0.0029602050781250, 0.0030822753906250, 0.0032348632812500, 0.0037841796875000, +0.0029602050781250, 0.0036010742187500, 0.0028076171875000, 0.0041503906250000, +0.0028991699218750, 0.0043334960937500, 0.0026245117187500, 0.0042724609375000, +0.0023193359375000, 0.0044555664062500, 0.0024108886718750, 0.0045471191406250, +0.0022583007812500, 0.0045166015625000, 0.0021057128906250, 0.0046081542968750, +0.0020141601562500, 0.0048522949218750, 0.0019531250000000, 0.0049133300781250, +0.0018920898437500, 0.0050354003906250, 0.0017089843750000, 0.0054626464843750, +0.0016784667968750, 0.0056762695312500, 0.0014953613281250, 0.0059204101562500, +0.0013122558593750, 0.0063171386718750, 0.0014038085937500, 0.0064697265625000, +0.0009155273437500, 0.0062255859375000, 0.0010070800781250, 0.0065917968750000, +0.0007934570312500}, +{0.0034179687500000, 0.0026550292968750, 0.0031738281250000, 0.0027465820312500, +0.0030822753906250, 0.0032348632812500, 0.0032043457031250, 0.0029907226562500, +0.0025939941406250, 0.0031738281250000, 0.0027160644531250, 0.0031738281250000, +0.0025939941406250, 0.0030822753906250, 0.0020751953125000, 0.0032043457031250, +0.0023498535156250, 0.0031127929687500, 0.0022888183593750, 0.0030212402343750, +0.0021362304687500, 0.0031433105468750, 0.0025329589843750, 0.0030822753906250, +0.0027770996093750, 0.0028686523437500, 0.0025939941406250, 0.0030212402343750, +0.0034484863281250, 0.0026245117187500, 0.0031127929687500, 0.0027160644531250, +0.0034484863281250, 0.0028381347656250, 0.0042419433593750, 0.0025939941406250, +0.0037536621093750, 0.0026550292968750, 0.0044860839843750, 0.0030822753906250, +0.0043640136718750, 0.0029602050781250, 0.0046081542968750, 0.0033264160156250, +0.0050964355468750, 0.0038757324218750, 0.0046386718750000, 0.0035400390625000, +0.0054016113281250, 0.0043029785156250, 0.0052795410156250, 0.0043334960937500, +0.0052795410156250, 0.0043029785156250, 0.0054931640625000, 0.0048217773437500, +0.0047912597656250, 0.0048217773437500, 0.0048217773437500, 0.0040588378906250, +0.0047302246093750, 0.0045471191406250, 0.0044860839843750, 0.0041809082031250, +0.0044860839843750, 0.0033874511718750, 0.0042724609375000, 0.0040588378906250, +0.0041503906250000, 0.0029602050781250, 0.0041809082031250, 0.0028991699218750, +0.0041198730468750, 0.0029296875000000, 0.0040588378906250, 0.0024414062500000, +0.0041503906250000, 0.0026245117187500, 0.0041809082031250, 0.0022888183593750, +0.0040893554687500, 0.0023498535156250, 0.0043640136718750, 0.0022277832031250, +0.0046386718750000, 0.0018920898437500, 0.0043640136718750, 0.0019226074218750, +0.0048217773437500, 0.0019531250000000, 0.0048522949218750, 0.0017700195312500, +0.0046691894531250, 0.0019531250000000, 0.0047302246093750, 0.0021057128906250, +0.0047912597656250, 0.0019531250000000, 0.0042419433593750, 0.0027770996093750, +0.0044250488281250, 0.0024414062500000, 0.0041198730468750, 0.0030212402343750, +0.0036315917968750, 0.0039062500000000, 0.0039367675781250, 0.0033264160156250, +0.0032653808593750, 0.0048828125000000, 0.0033569335937500, 0.0047607421875000, +0.0032348632812500, 0.0050659179687500, 0.0027160644531250, 0.0061035156250000, +0.0028991699218750, 0.0056152343750000, 0.0026550292968750, 0.0062866210937500, +0.0023803710937500, 0.0064086914062500, 0.0025024414062500, 0.0061340332031250, +0.0025329589843750, 0.0061950683593750, 0.0022277832031250, 0.0063171386718750, +0.0024719238281250, 0.0060119628906250, 0.0025024414062500, 0.0060729980468750, +0.0022277832031250, 0.0062255859375000, 0.0021972656250000, 0.0061035156250000, +0.0022888183593750, 0.0061340332031250, 0.0017395019531250, 0.0066528320312500, +0.0017700195312500, 0.0066528320312500, 0.0017089843750000, 0.0067443847656250, +0.0012817382812500, 0.0071716308593750, 0.0013732910156250, 0.0071411132812500, +0.0013122558593750, 0.0068969726562500, 0.0011596679687500, 0.0071411132812500, +0.0012207031250000, 0.0069274902343750, 0.0012817382812500, 0.0065307617187500, +0.0010375976562500, 0.0068969726562500, 0.0013732910156250, 0.0063781738281250, +0.0012817382812500, 0.0064086914062500, 0.0012512207031250, 0.0065612792968750, +0.0013427734375000, 0.0065307617187500, 0.0011291503906250, 0.0066833496093750, +0.0011291503906250, 0.0067749023437500, 0.0010681152343750, 0.0069274902343750, +0.0008239746093750, 0.0068664550781250, 0.0006408691406250, 0.0069580078125000, +0.0006103515625000, 0.0071716308593750, 0.0001831054687500, 0.0068054199218750, +0.0000610351562500, 0.0069885253906250, -0.0000305175781250, 0.0069274902343750, +-0.0002441406250000, 0.0066528320312500, -0.0003356933593750, 0.0069580078125000, +-0.0002746582031250, 0.0065307617187500, -0.0003051757812500, 0.0065917968750000, +-0.0002136230468750, 0.0066528320312500, -0.0000305175781250, 0.0064086914062500, +-0.0000305175781250, 0.0065307617187500, 0.0000610351562500, 0.0064086914062500, +0.0002136230468750, 0.0064086914062500, 0.0002441406250000, 0.0063171386718750, +0.0002136230468750, 0.0061340332031250, 0.0003662109375000, 0.0061950683593750, +0.0002136230468750, 0.0060424804687500, 0.0003356933593750, 0.0059204101562500, +0.0003356933593750, 0.0060424804687500, 0.0001220703125000, 0.0061340332031250, +0.0001831054687500, 0.0059814453125000, 0.0000610351562500, 0.0064392089843750, +0.0000000000000000, 0.0064086914062500, 0.0000305175781250, 0.0063476562500000, +0.0000305175781250, 0.0066223144531250, -0.0000305175781250, 0.0065917968750000, +0.0000915527343750, 0.0060729980468750, 0.0000610351562500, 0.0063476562500000, +0.0001220703125000, 0.0057373046875000, 0.0002441406250000, 0.0050048828125000, +0.0000610351562500, 0.0054321289062500, 0.0003662109375000, 0.0036621093750000, +0.0002441406250000, 0.0039978027343750, 0.0004272460937500, 0.0032348632812500, +0.0006713867187500, 0.0017395019531250, 0.0004272460937500, 0.0024719238281250, +0.0009460449218750, 0.0005798339843750, 0.0007934570312500, 0.0007324218750000, +0.0008850097656250, 0.0003967285156250, 0.0012207031250000, -0.0007934570312500, +0.0008850097656250, -0.0001831054687500, 0.0012817382812500, -0.0008239746093750, +0.0011596679687500, -0.0010375976562500, 0.0010375976562500, -0.0005493164062500, +0.0012512207031250, -0.0005187988281250, 0.0011291503906250, -0.0006713867187500, +0.0010070800781250, 0.0005493164062500, 0.0010681152343750, 0.0003356933593750, +0.0009765625000000, 0.0010070800781250, 0.0008850097656250, 0.0021972656250000, +0.0010070800781250, 0.0016479492187500, 0.0009460449218750, 0.0033264160156250, +0.0009460449218750, 0.0032958984375000, 0.0010070800781250, 0.0036621093750000, +0.0010681152343750, 0.0048828125000000, 0.0010681152343750, 0.0043640136718750, +0.0011291503906250, 0.0052490234375000, 0.0011901855468750, 0.0054321289062500, +0.0011291503906250, 0.0053100585937500, 0.0011291503906250, 0.0055847167968750, +0.0012207031250000, 0.0054931640625000, 0.0010070800781250, 0.0050048828125000, +0.0011291503906250, 0.0053100585937500, 0.0010681152343750, 0.0047607421875000, +0.0008850097656250, 0.0039672851562500, 0.0011291503906250, 0.0044555664062500, +0.0012207031250000, 0.0032348632812500, 0.0011291503906250, 0.0032348632812500, +0.0014343261718750, 0.0031738281250000, 0.0018310546875000, 0.0024108886718750, +0.0016174316406250, 0.0026550292968750, 0.0023803710937500, 0.0027465820312500, +0.0023498535156250, 0.0025634765625000, 0.0023803710937500, 0.0027465820312500, +0.0028076171875000, 0.0030212402343750, 0.0026550292968750, 0.0028381347656250, +0.0025329589843750, 0.0031127929687500, 0.0026855468750000, 0.0032043457031250, +0.0024414062500000, 0.0029602050781250, 0.0021362304687500, 0.0029907226562500, +0.0024108886718750, 0.0031433105468750, 0.0019531250000000, 0.0024108886718750, +0.0020751953125000, 0.0026245117187500, 0.0021362304687500, 0.0023498535156250, +0.0018920898437500, 0.0016174316406250, 0.0021057128906250, 0.0020446777343750, +0.0020751953125000, 0.0013122558593750, 0.0020751953125000, 0.0012512207031250, +0.0021362304687500, 0.0011901855468750, 0.0021362304687500, 0.0007629394531250, +0.0022583007812500, 0.0009460449218750, 0.0021667480468750, 0.0005187988281250, +0.0023498535156250, 0.0003967285156250, 0.0022583007812500, 0.0006408691406250, +0.0021362304687500, 0.0006103515625000, 0.0024108886718750, 0.0004577636718750, +0.0025024414062500, 0.0007324218750000, 0.0024414062500000, 0.0007324218750000, +0.0027465820312500, 0.0006713867187500, 0.0031127929687500, 0.0007934570312500, +0.0029602050781250, 0.0007629394531250, 0.0031738281250000, 0.0007019042968750, +0.0035705566406250, 0.0005798339843750, 0.0031433105468750, 0.0009765625000000, +0.0029602050781250, 0.0012207031250000, 0.0035095214843750, 0.0009460449218750, +0.0019226074218750, 0.0029296875000000, 0.0023193359375000, 0.0024108886718750, +0.0020446777343750, 0.0034179687500000, 0.0007629394531250, 0.0054626464843750, +0.0015258789062500, 0.0043945312500000, 0.0011596679687500, 0.0066223144531250, +0.0007629394531250, 0.0067443847656250, 0.0014648437500000, 0.0066528320312500, +0.0018310546875000, 0.0076293945312500, 0.0013122558593750, 0.0071716308593750, +0.0028381347656250, 0.0069885253906250, 0.0026855468750000, 0.0073547363281250, +0.0026855468750000, 0.0066833496093750, 0.0040893554687500, 0.0052795410156250, +0.0054016113281250, 0.0053710937500000, 0.0051574707031250, 0.0063171386718750, +0.0060729980468750, 0.0065002441406250, 0.0051574707031250, 0.0059509277343750, +0.0043029785156250, 0.0058898925781250, 0.0051879882812500, 0.0062866210937500, +0.0030212402343750, 0.0043945312500000, 0.0033264160156250, 0.0048828125000000, +0.0029907226562500, 0.0044860839843750, 0.0015869140625000, 0.0029907226562500, +0.0023193359375000, 0.0038452148437500, 0.0015563964843750, 0.0028686523437500, +0.0013427734375000, 0.0027770996093750, 0.0014953613281250, 0.0028381347656250, +0.0012817382812500, 0.0023803710937500, 0.0011901855468750, 0.0025939941406250, +0.0013732910156250, 0.0022277832031250, 0.0011901855468750, 0.0022277832031250, +0.0013427734375000, 0.0023193359375000, 0.0015563964843750, 0.0020751953125000, +0.0013427734375000, 0.0020446777343750, 0.0022583007812500, 0.0028381347656250, +0.0019531250000000, 0.0026245117187500, 0.0022888183593750, 0.0028381347656250, +0.0030517578125000, 0.0035400390625000, 0.0026550292968750, 0.0032348632812500, +0.0034179687500000, 0.0035095214843750, 0.0032653808593750, 0.0036926269531250, +0.0032958984375000, 0.0034484863281250, 0.0036621093750000, 0.0033264160156250, +0.0032653808593750, 0.0034484863281250, 0.0036926269531250, 0.0031127929687500, +0.0034179687500000, 0.0030517578125000, 0.0034790039062500, 0.0031127929687500, +0.0037536621093750, 0.0028991699218750, 0.0032958984375000, 0.0028991699218750, +0.0044860839843750, 0.0030212402343750, 0.0040893554687500, 0.0029907226562500, +0.0045166015625000, 0.0029907226562500, 0.0055236816406250, 0.0030212402343750, +0.0047912597656250, 0.0030212402343750, 0.0064697265625000, 0.0030212402343750, +0.0062866210937500, 0.0029907226562500, 0.0065002441406250, 0.0030212402343750, +0.0075988769531250, 0.0030822753906250, 0.0070800781250000, 0.0029907226562500, +0.0074462890625000, 0.0029296875000000, 0.0075988769531250, 0.0028991699218750, +0.0073242187500000, 0.0027465820312500, 0.0072937011718750, 0.0026550292968750, +0.0073852539062500, 0.0026855468750000, 0.0068664550781250, 0.0023193359375000, +0.0068969726562500, 0.0023193359375000, 0.0067749023437500, 0.0021057128906250, +0.0064392089843750, 0.0018005371093750, 0.0066833496093750, 0.0018920898437500, +0.0060119628906250, 0.0014038085937500, 0.0063476562500000, 0.0014038085937500, +0.0059204101562500, 0.0012817382812500, 0.0052490234375000, 0.0009155273437500, +0.0059204101562500, 0.0010681152343750, 0.0043945312500000, 0.0008850097656250, +0.0047302246093750, 0.0008544921875000, 0.0045166015625000, 0.0008850097656250, +0.0032958984375000, 0.0008239746093750, 0.0040283203125000, 0.0008850097656250, +0.0036010742187500, 0.0009460449218750, 0.0031433105468750, 0.0008544921875000, +0.0038452148437500, 0.0009765625000000, 0.0041809082031250, 0.0011596679687500, +0.0036010742187500}, +{0.0023193359375000, 0.0000915527343750, 0.0017700195312500, 0.0003967285156250, +0.0030822753906250, 0.0012512207031250, 0.0029296875000000, 0.0007019042968750, +0.0032043457031250, 0.0017089843750000, 0.0039978027343750, 0.0030822753906250, +0.0035400390625000, 0.0023193359375000, 0.0046081542968750, 0.0044250488281250, +0.0046997070312500, 0.0043334960937500, 0.0047607421875000, 0.0044860839843750, +0.0056457519531250, 0.0064392089843750, 0.0046081542968750, 0.0009460449218750, +0.0019531250000000, 0.0027770996093750, 0.0028076171875000, 0.0021057128906250, +0.0026245117187500, 0.0027770996093750, 0.0014648437500000, 0.0038146972656250, +0.0018310546875000, 0.0031738281250000, 0.0021057128906250, 0.0043334960937500, +0.0019836425781250, 0.0043945312500000, 0.0021362304687500, 0.0042114257812500, +0.0025634765625000, 0.0047607421875000, 0.0025939941406250, 0.0046691894531250, +0.0024108886718750, 0.0043029785156250, 0.0026550292968750, 0.0044860839843750, +0.0026855468750000, 0.0043640136718750, 0.0024108886718750, 0.0039367675781250, +0.0025634765625000, 0.0041503906250000, 0.0030822753906250, 0.0038452148437500, +0.0028686523437500, 0.0039672851562500, 0.0032958984375000, 0.0036926269531250, +0.0039672851562500, 0.0034790039062500, 0.0036315917968750, 0.0037841796875000, +0.0041809082031250, 0.0029602050781250, 0.0042114257812500, 0.0030517578125000, +0.0040893554687500, 0.0030212402343750, 0.0040893554687500, 0.0024108886718750, +0.0039978027343750, 0.0025329589843750, 0.0041809082031250, 0.0027160644531250, +0.0038452148437500, 0.0023803710937500, 0.0041809082031250, 0.0027160644531250, +0.0045776367187500, 0.0031738281250000, 0.0040588378906250, 0.0026550292968750, +0.0053710937500000, 0.0034179687500000, 0.0050354003906250, 0.0032958984375000, +0.0053405761718750, 0.0032348632812500, 0.0063781738281250, 0.0036010742187500, +0.0056762695312500, 0.0033264160156250, 0.0063476562500000, 0.0034179687500000, +0.0065002441406250, 0.0033264160156250, 0.0061950683593750, 0.0034179687500000, +0.0063476562500000, 0.0034790039062500, 0.0063171386718750, 0.0032653808593750, +0.0055541992187500, 0.0034790039062500, 0.0059204101562500, 0.0033569335937500, +0.0053710937500000, 0.0032958984375000, 0.0045166015625000, 0.0033569335937500, +0.0051574707031250, 0.0031738281250000, 0.0038146972656250, 0.0032348632812500, +0.0040283203125000, 0.0031738281250000, 0.0037841796875000, 0.0031127929687500, +0.0029907226562500, 0.0031433105468750, 0.0036010742187500, 0.0031433105468750, +0.0024108886718750, 0.0030212402343750, 0.0026550292968750, 0.0031738281250000, +0.0023498535156250, 0.0029907226562500, 0.0014648437500000, 0.0028381347656250, +0.0020751953125000, 0.0030822753906250, 0.0008544921875000, 0.0026245117187500, +0.0008850097656250, 0.0028076171875000, 0.0008850097656250, 0.0026245117187500, +0.0001220703125000, 0.0022583007812500, 0.0003356933593750, 0.0026245117187500, +0.0007629394531250, 0.0017700195312500, 0.0002136230468750, 0.0019836425781250, +0.0010986328125000, 0.0018615722656250, 0.0020446777343750, 0.0013427734375000, +0.0012512207031250, 0.0016174316406250, 0.0033874511718750, 0.0013122558593750, +0.0032653808593750, 0.0013122558593750, 0.0034484863281250, 0.0014038085937500, +0.0047912597656250, 0.0013122558593750, 0.0042114257812500, 0.0014343261718750, +0.0047302246093750, 0.0016174316406250, 0.0050659179687500, 0.0016784667968750, +0.0045471191406250, 0.0017700195312500, 0.0044555664062500, 0.0019836425781250, +0.0049743652343750, 0.0020751953125000, 0.0033264160156250, 0.0020141601562500, +0.0039062500000000, 0.0021057128906250, 0.0035095214843750, 0.0020751953125000, +0.0022583007812500, 0.0019226074218750, 0.0032348632812500, 0.0019531250000000, +0.0020751953125000, 0.0017395019531250, 0.0021057128906250, 0.0016479492187500, +0.0023803710937500, 0.0014953613281250, 0.0019531250000000, 0.0012817382812500, +0.0021667480468750, 0.0012512207031250, 0.0022583007812500, 0.0009765625000000, +0.0023498535156250, 0.0008850097656250, 0.0025329589843750, 0.0007934570312500, +0.0027160644531250, 0.0006713867187500, 0.0027770996093750, 0.0006408691406250, +0.0030517578125000, 0.0006713867187500, 0.0031433105468750, 0.0006103515625000, +0.0032653808593750, 0.0006713867187500, 0.0035705566406250, 0.0007019042968750, +0.0036621093750000, 0.0006713867187500, 0.0038757324218750, 0.0006103515625000, +0.0039978027343750, 0.0006713867187500, 0.0041809082031250, 0.0006408691406250, +0.0043945312500000, 0.0004882812500000, 0.0043640136718750, 0.0004272460937500, +0.0046081542968750, 0.0005493164062500, 0.0046997070312500, 0.0004577636718750, +0.0047607421875000, 0.0004577636718750, 0.0048217773437500, 0.0005798339843750, +0.0048217773437500, 0.0006408691406250, 0.0047302246093750, 0.0006713867187500, +0.0047607421875000, 0.0007324218750000, 0.0046386718750000, 0.0007324218750000, +0.0044860839843750, 0.0007934570312500, 0.0044860839843750, 0.0008850097656250, +0.0041198730468750, 0.0007324218750000, 0.0040893554687500, 0.0008544921875000, +0.0039978027343750, 0.0009460449218750, 0.0036621093750000, 0.0008850097656250, +0.0036926269531250, 0.0009765625000000, 0.0034484863281250, 0.0013122558593750, +0.0033874511718750, 0.0012817382812500, 0.0033874511718750, 0.0014953613281250, +0.0032653808593750, 0.0018920898437500, 0.0032043457031250, 0.0017700195312500, +0.0034790039062500, 0.0019531250000000, 0.0032653808593750, 0.0021057128906250, +0.0035095214843750, 0.0019531250000000, 0.0039367675781250, 0.0018920898437500, +0.0036010742187500, 0.0021362304687500, 0.0043334960937500, 0.0015258789062500, +0.0041503906250000, 0.0017395019531250, 0.0042724609375000, 0.0015869140625000, +0.0047912597656250, 0.0012207031250000, 0.0044250488281250, 0.0014343261718750, +0.0050659179687500, 0.0012207031250000, 0.0049133300781250, 0.0011901855468750, +0.0051269531250000, 0.0013427734375000, 0.0056152343750000, 0.0012817382812500, +0.0052795410156250, 0.0012512207031250, 0.0058593750000000, 0.0016479492187500, +0.0059204101562500, 0.0014953613281250, 0.0058593750000000, 0.0016784667968750, +0.0061035156250000, 0.0021362304687500, 0.0061035156250000, 0.0018615722656250, +0.0057373046875000, 0.0024108886718750, 0.0059204101562500, 0.0024414062500000, +0.0056762695312500, 0.0025024414062500, 0.0051879882812500, 0.0027465820312500, +0.0054321289062500, 0.0027770996093750, 0.0049438476562500, 0.0026855468750000, +0.0047607421875000, 0.0029296875000000, 0.0048828125000000, 0.0028686523437500, +0.0048217773437500, 0.0026550292968750, 0.0046691894531250, 0.0029602050781250, +0.0050964355468750, 0.0025939941406250, 0.0048828125000000, 0.0027465820312500, +0.0050354003906250, 0.0026855468750000, 0.0054626464843750, 0.0023498535156250, +0.0051574707031250, 0.0026855468750000, 0.0055541992187500, 0.0021667480468750, +0.0054931640625000, 0.0023193359375000, 0.0054016113281250, 0.0024414062500000, +0.0055236816406250, 0.0021057128906250, 0.0053405761718750, 0.0023193359375000, +0.0053100585937500, 0.0025024414062500, 0.0052490234375000, 0.0023803710937500, +0.0052490234375000, 0.0027160644531250, 0.0052490234375000, 0.0031433105468750, +0.0051574707031250, 0.0029602050781250, 0.0050659179687500, 0.0036926269531250, +0.0053405761718750, 0.0038146972656250, 0.0050048828125000, 0.0037536621093750, +0.0045776367187500, 0.0041198730468750, 0.0050048828125000, 0.0042724609375000, +0.0042419433593750, 0.0039062500000000, 0.0042419433593750, 0.0041809082031250, +0.0041198730468750, 0.0037841796875000, 0.0036926269531250, 0.0032653808593750, +0.0040283203125000, 0.0037841796875000, 0.0031738281250000, 0.0030212402343750, +0.0032653808593750, 0.0032348632812500, 0.0030212402343750, 0.0031738281250000, +0.0024414062500000, 0.0026550292968750, 0.0028686523437500, 0.0031127929687500, +0.0028381347656250, 0.0026855468750000, 0.0026855468750000, 0.0028076171875000, +0.0032348632812500, 0.0028991699218750, 0.0036315917968750, 0.0026245117187500, +0.0034484863281250, 0.0028381347656250, 0.0045776367187500, 0.0030822753906250, +0.0045776367187500, 0.0030212402343750, 0.0046691894531250, 0.0033874511718750, +0.0053710937500000, 0.0037231445312500, 0.0052490234375000, 0.0035705566406250, +0.0050048828125000, 0.0045471191406250, 0.0054016113281250, 0.0043945312500000, +0.0050048828125000, 0.0048217773437500, 0.0045471191406250, 0.0057067871093750, +0.0050964355468750, 0.0053100585937500, 0.0038146972656250, 0.0061645507812500, +0.0040283203125000, 0.0062561035156250, 0.0038146972656250, 0.0061035156250000, +0.0028991699218750, 0.0064392089843750, 0.0032653808593750, 0.0064697265625000, +0.0030822753906250, 0.0059204101562500, 0.0027160644531250, 0.0061950683593750, +0.0030212402343750, 0.0058288574218750, 0.0032348632812500, 0.0051879882812500, +0.0028076171875000, 0.0056762695312500, 0.0036315917968750, 0.0049133300781250, +0.0034484863281250, 0.0049743652343750, 0.0034484863281250, 0.0050964355468750, +0.0040588378906250, 0.0048217773437500, 0.0038146972656250, 0.0050354003906250, +0.0037536621093750, 0.0050354003906250, 0.0040283203125000, 0.0051574707031250, +0.0038452148437500, 0.0048522949218750, 0.0036315917968750, 0.0046386718750000, +0.0039062500000000, 0.0047912597656250, 0.0034179687500000, 0.0037841796875000, +0.0035095214843750, 0.0039367675781250, 0.0034179687500000, 0.0034484863281250, +0.0030822753906250, 0.0025634765625000, 0.0033569335937500, 0.0030517578125000, +0.0032348632812500, 0.0021057128906250, 0.0032043457031250, 0.0019531250000000, +0.0033569335937500, 0.0020751953125000, 0.0035400390625000, 0.0018310546875000, +0.0036621093750000, 0.0018310546875000, 0.0036926269531250, 0.0017700195312500, +0.0039367675781250, 0.0018310546875000, 0.0038757324218750, 0.0016479492187500, +0.0038146972656250, 0.0014953613281250, 0.0041198730468750, 0.0016174316406250, +0.0035095214843750, 0.0012207031250000, 0.0038757324218750, 0.0011291503906250, +0.0036315917968750, 0.0012817382812500, 0.0030822753906250, 0.0013122558593750, +0.0036315917968750, 0.0013122558593750, 0.0026550292968750, 0.0016174316406250, +0.0029296875000000, 0.0016479492187500, 0.0028686523437500, 0.0016479492187500, +0.0022277832031250, 0.0018005371093750, 0.0027770996093750, 0.0018310546875000, +0.0023498535156250, 0.0017089843750000, 0.0024108886718750, 0.0017089843750000, +0.0025329589843750, 0.0017395019531250, 0.0023803710937500, 0.0016174316406250, +0.0025939941406250, 0.0016479492187500, 0.0024414062500000, 0.0018005371093750, +0.0026245117187500, 0.0018005371093750, 0.0024414062500000, 0.0019836425781250, +0.0021057128906250, 0.0022583007812500, 0.0023498535156250, 0.0021362304687500, +0.0015563964843750, 0.0025024414062500, 0.0016174316406250, 0.0025634765625000, +0.0014343261718750, 0.0024719238281250, 0.0009155273437500, 0.0025329589843750, +0.0010986328125000, 0.0024719238281250, 0.0008544921875000, 0.0021362304687500, +0.0007324218750000, 0.0021362304687500, 0.0007934570312500, 0.0020141601562500, +0.0008239746093750, 0.0016479492187500, 0.0008239746093750, 0.0017395019531250, +0.0009155273437500, 0.0018005371093750, 0.0009765625000000, 0.0015258789062500, +0.0010070800781250, 0.0020141601562500, 0.0010681152343750, 0.0024719238281250, +0.0010986328125000, 0.0020751953125000, 0.0011291503906250, 0.0035400390625000, +0.0011291503906250}, +{0.0026245117187500, 0.0048828125000000, 0.0022277832031250, 0.0047607421875000, +0.0027160644531250, 0.0049438476562500, 0.0027770996093750, 0.0058898925781250, +0.0024414062500000, 0.0054626464843750, 0.0032958984375000, 0.0058593750000000, +0.0031738281250000, 0.0060729980468750, 0.0033569335937500, 0.0057983398437500, +0.0040283203125000, 0.0057373046875000, 0.0037536621093750, 0.0057983398437500, +0.0041809082031250, 0.0051269531250000, 0.0043640136718750, 0.0052490234375000, +0.0040893554687500, 0.0049133300781250, 0.0040283203125000, 0.0042724609375000, +0.0040588378906250, 0.0046081542968750, 0.0035400390625000, 0.0039978027343750, +0.0035400390625000, 0.0039978027343750, 0.0033569335937500, 0.0039062500000000, +0.0028991699218750, 0.0036621093750000, 0.0030517578125000, 0.0038146972656250, +0.0030212402343750, 0.0032043457031250, 0.0026550292968750, 0.0036010742187500, +0.0031127929687500, 0.0031127929687500, 0.0035705566406250, 0.0024719238281250, +0.0031127929687500, 0.0030517578125000, 0.0042419433593750, 0.0014953613281250, +0.0042724609375000, 0.0017089843750000, 0.0043029785156250, 0.0015869140625000, +0.0049743652343750, 0.0005187988281250, 0.0047607421875000, 0.0009765625000000, +0.0048828125000000, 0.0008850097656250, 0.0051574707031250, 0.0006408691406250, +0.0048828125000000, 0.0009460449218750, 0.0046997070312500, 0.0011901855468750, +0.0050048828125000, 0.0009765625000000, 0.0042114257812500, 0.0015869140625000, +0.0044250488281250, 0.0016479492187500, 0.0043640136718750, 0.0017089843750000, +0.0039367675781250, 0.0020446777343750, 0.0042419433593750, 0.0019836425781250, +0.0041503906250000, 0.0021667480468750, 0.0041809082031250, 0.0021972656250000, +0.0043640136718750, 0.0023803710937500, 0.0044860839843750, 0.0026855468750000, +0.0044860839843750, 0.0026245117187500, 0.0046691894531250, 0.0030517578125000, +0.0048522949218750, 0.0033264160156250, 0.0046386718750000, 0.0031433105468750, +0.0046386718750000, 0.0032043457031250, 0.0050048828125000, 0.0034790039062500, +0.0040893554687500, 0.0025329589843750, 0.0046386718750000, 0.0027160644531250, +0.0042114257812500, 0.0025634765625000, 0.0034179687500000, 0.0019531250000000, +0.0043640136718750, 0.0022583007812500, 0.0029296875000000, 0.0020141601562500, +0.0033264160156250, 0.0019226074218750, 0.0032958984375000, 0.0020751953125000, +0.0024108886718750, 0.0021057128906250, 0.0031433105468750, 0.0020446777343750, +0.0024719238281250, 0.0020141601562500, 0.0026855468750000, 0.0020751953125000, +0.0028076171875000, 0.0018920898437500, 0.0025329589843750, 0.0016784667968750, +0.0029296875000000, 0.0018005371093750, 0.0023498535156250, 0.0012207031250000, +0.0027465820312500, 0.0012512207031250, 0.0025329589843750, 0.0011596679687500, +0.0020141601562500, 0.0008544921875000, 0.0025634765625000, 0.0009460449218750, +0.0016174316406250, 0.0012512207031250, 0.0018310546875000, 0.0010681152343750, +0.0018005371093750, 0.0015258789062500, 0.0011291503906250, 0.0021362304687500, +0.0014648437500000, 0.0017395019531250, 0.0011901855468750, 0.0029602050781250, +0.0010375976562500, 0.0028991699218750, 0.0012817382812500, 0.0032043457031250, +0.0013732910156250, 0.0041198730468750, 0.0011901855468750, 0.0036926269531250, +0.0016784667968750, 0.0043640136718750, 0.0015258789062500, 0.0045166015625000, +0.0015258789062500, 0.0045776367187500, 0.0018005371093750, 0.0048522949218750, +0.0016174316406250, 0.0047607421875000, 0.0016174316406250, 0.0051879882812500, +0.0016174316406250, 0.0050048828125000, 0.0014953613281250, 0.0052490234375000, +0.0014953613281250, 0.0056762695312500, 0.0014038085937500, 0.0054016113281250, +0.0015563964843750, 0.0064086914062500, 0.0014953613281250, 0.0062561035156250, +0.0015258789062500, 0.0066528320312500, 0.0016784667968750, 0.0074462890625000, +0.0016784667968750, 0.0071105957031250, 0.0016479492187500, 0.0079040527343750, +0.0018615722656250, 0.0079650878906250, 0.0017089843750000, 0.0080261230468750, +0.0016479492187500, 0.0084838867187500, 0.0019226074218750, 0.0083007812500000, +0.0014343261718750, 0.0080871582031250, 0.0015869140625000, 0.0084533691406250, +0.0016174316406250, 0.0079345703125000, 0.0013122558593750, 0.0073242187500000, +0.0015258789062500, 0.0077819824218750, 0.0015869140625000, 0.0061645507812500, +0.0015869140625000, 0.0063781738281250, 0.0018615722656250, 0.0058593750000000, +0.0021057128906250, 0.0045776367187500, 0.0020446777343750, 0.0052490234375000, +0.0023803710937500, 0.0038757324218750, 0.0024719238281250, 0.0038146972656250, +0.0024719238281250, 0.0036621093750000, 0.0026245117187500, 0.0028991699218750, +0.0026550292968750, 0.0031433105468750, 0.0025634765625000, 0.0028381347656250, +0.0025939941406250, 0.0027160644531250, 0.0025329589843750, 0.0028991699218750, +0.0023498535156250, 0.0029907226562500, 0.0023193359375000, 0.0030212402343750, +0.0024108886718750, 0.0034179687500000, 0.0021972656250000, 0.0034484863281250, +0.0023193359375000, 0.0037231445312500, 0.0025024414062500, 0.0040893554687500, +0.0021972656250000, 0.0040283203125000, 0.0025329589843750, 0.0045166015625000, +0.0025024414062500, 0.0046997070312500, 0.0024719238281250, 0.0047302246093750, +0.0025939941406250, 0.0049743652343750, 0.0025024414062500, 0.0051269531250000, +0.0028381347656250, 0.0048217773437500, 0.0026550292968750, 0.0050659179687500, +0.0028686523437500, 0.0048217773437500, 0.0032043457031250, 0.0044250488281250, +0.0028991699218750, 0.0048217773437500, 0.0035400390625000, 0.0042114257812500, +0.0034179687500000, 0.0042114257812500, 0.0033874511718750, 0.0042724609375000, +0.0037841796875000, 0.0040283203125000, 0.0035095214843750, 0.0041198730468750, +0.0035095214843750, 0.0041809082031250, 0.0037231445312500, 0.0041503906250000, +0.0032958984375000, 0.0042114257812500, 0.0029907226562500, 0.0043334960937500, +0.0032653808593750, 0.0043640136718750, 0.0023498535156250, 0.0041809082031250, +0.0022888183593750, 0.0042724609375000, 0.0023193359375000, 0.0042114257812500, +0.0018310546875000, 0.0040283203125000, 0.0018310546875000, 0.0041198730468750, +0.0023803710937500, 0.0039062500000000, 0.0021057128906250, 0.0038757324218750, +0.0025939941406250, 0.0039978027343750, 0.0032653808593750, 0.0040893554687500, +0.0027770996093750, 0.0039978027343750, 0.0039062500000000, 0.0039367675781250, +0.0038146972656250, 0.0040588378906250, 0.0038757324218750, 0.0038146972656250, +0.0045471191406250, 0.0036010742187500, 0.0043029785156250, 0.0037841796875000, +0.0046997070312500, 0.0036621093750000, 0.0048522949218750, 0.0033874511718750, +0.0047302246093750, 0.0038146972656250, 0.0049438476562500, 0.0043029785156250, +0.0050354003906250, 0.0040283203125000, 0.0043029785156250, 0.0048217773437500, +0.0048217773437500, 0.0050048828125000, 0.0041198730468750, 0.0045166015625000, +0.0031127929687500, 0.0046997070312500, 0.0040283203125000, 0.0050354003906250, +0.0023193359375000, 0.0035705566406250, 0.0022583007812500, 0.0038757324218750, +0.0025634765625000, 0.0037231445312500, 0.0016479492187500, 0.0020141601562500, +0.0032958984375000, 0.0048522949218750, 0.0039367675781250, 0.0037841796875000, +0.0039062500000000, 0.0042114257812500, 0.0036315917968750, 0.0040893554687500, +0.0036010742187500, 0.0035705566406250, 0.0037841796875000, 0.0037841796875000, +0.0039978027343750, 0.0038146972656250, 0.0037536621093750, 0.0038146972656250, +0.0041503906250000, 0.0038757324218750, 0.0046386718750000, 0.0039978027343750, +0.0041809082031250, 0.0039978027343750, 0.0050048828125000, 0.0040893554687500, +0.0050659179687500, 0.0040283203125000, 0.0048217773437500, 0.0041198730468750, +0.0051574707031250, 0.0042724609375000, 0.0050964355468750, 0.0042114257812500, +0.0046997070312500, 0.0042724609375000, 0.0046997070312500, 0.0043945312500000, +0.0046081542968750, 0.0043640136718750, 0.0043029785156250, 0.0043640136718750, +0.0043640136718750, 0.0044860839843750, 0.0040588378906250, 0.0045166015625000, +0.0041198730468750, 0.0043334960937500, 0.0037841796875000, 0.0046997070312500, +0.0033569335937500, 0.0050354003906250, 0.0034484863281250, 0.0048522949218750, +0.0027465820312500, 0.0056152343750000, 0.0027465820312500, 0.0056152343750000, +0.0025024414062500, 0.0055236816406250, 0.0019531250000000, 0.0059509277343750, +0.0021667480468750, 0.0058898925781250, 0.0018615722656250, 0.0052185058593750, +0.0016479492187500, 0.0055236816406250, 0.0019226074218750, 0.0051269531250000, +0.0020141601562500, 0.0042724609375000, 0.0018615722656250, 0.0047302246093750, +0.0022583007812500, 0.0042419433593750, 0.0021972656250000, 0.0040893554687500, +0.0022277832031250, 0.0041503906250000, 0.0023803710937500, 0.0041198730468750, +0.0022583007812500, 0.0039978027343750, 0.0025024414062500, 0.0039062500000000, +0.0025024414062500, 0.0039062500000000, 0.0025024414062500, 0.0038757324218750, +0.0025634765625000, 0.0037841796875000, 0.0025329589843750, 0.0036926269531250, +0.0031433105468750, 0.0037536621093750, 0.0028076171875000, 0.0036010742187500, +0.0032958984375000, 0.0035095214843750, 0.0040283203125000, 0.0034790039062500, +0.0034179687500000, 0.0032958984375000, 0.0050048828125000, 0.0030517578125000, +0.0048828125000000, 0.0028686523437500, 0.0051269531250000, 0.0028076171875000, +0.0061645507812500, 0.0025939941406250, 0.0057373046875000, 0.0024719238281250, +0.0060729980468750, 0.0025634765625000, 0.0063476562500000, 0.0023803710937500, +0.0058288574218750, 0.0023803710937500, 0.0056457519531250, 0.0025634765625000, +0.0059509277343750, 0.0024108886718750, 0.0044860839843750, 0.0026550292968750, +0.0046691894531250, 0.0025939941406250, 0.0043945312500000, 0.0027160644531250, +0.0033264160156250, 0.0030212402343750, 0.0036010742187500, 0.0029296875000000, +0.0033569335937500, 0.0031127929687500, 0.0030517578125000, 0.0032958984375000, +0.0031738281250000, 0.0031433105468750, 0.0032958984375000, 0.0031127929687500, +0.0030822753906250, 0.0032958984375000, 0.0032958984375000, 0.0027160644531250, +0.0032653808593750, 0.0029296875000000, 0.0031738281250000, 0.0027160644531250, +0.0033264160156250, 0.0021972656250000, 0.0031433105468750, 0.0026550292968750, +0.0028991699218750, 0.0019531250000000, 0.0031127929687500, 0.0020751953125000, +0.0027160644531250, 0.0021362304687500, 0.0022583007812500, 0.0018005371093750, +0.0026245117187500, 0.0021667480468750, 0.0019531250000000, 0.0020751953125000, +0.0019226074218750, 0.0022277832031250, 0.0020751953125000, 0.0023193359375000, +0.0018920898437500, 0.0023498535156250, 0.0020446777343750, 0.0024719238281250, +0.0023193359375000, 0.0022888183593750, 0.0023498535156250, 0.0025634765625000, +0.0025634765625000, 0.0023803710937500, 0.0028076171875000, 0.0021362304687500, +0.0027770996093750, 0.0023803710937500, 0.0031433105468750, 0.0016784667968750, +0.0032348632812500, 0.0019531250000000, 0.0033874511718750, 0.0018310546875000, +0.0036010742187500, 0.0013122558593750, 0.0036315917968750, 0.0016784667968750, +0.0036010742187500, 0.0010681152343750, 0.0038452148437500, 0.0013122558593750, +0.0036926269531250, 0.0011291503906250, 0.0035095214843750, 0.0007019042968750, +0.0038146972656250, 0.0012207031250000, 0.0033569335937500, 0.0004272460937500, +0.0036010742187500, 0.0006103515625000, 0.0036315917968750, 0.0007019042968750, +0.0033264160156250}, +{0.0018920898437500, 0.0039062500000000, 0.0019836425781250, 0.0037536621093750, +0.0014648437500000, 0.0037536621093750, 0.0022888183593750, 0.0037841796875000, +0.0020751953125000, 0.0036315917968750, 0.0021667480468750, 0.0039978027343750, +0.0027465820312500, 0.0042419433593750, 0.0023193359375000, 0.0040283203125000, +0.0029296875000000, 0.0048828125000000, 0.0029907226562500, 0.0049438476562500, +0.0028686523437500, 0.0048522949218750, 0.0030822753906250, 0.0052795410156250, +0.0030212402343750, 0.0052490234375000, 0.0031738281250000, 0.0046691894531250, +0.0030517578125000, 0.0047912597656250, 0.0033264160156250, 0.0046386718750000, +0.0036010742187500, 0.0041503906250000, 0.0033569335937500, 0.0042114257812500, +0.0043029785156250, 0.0039062500000000, 0.0039672851562500, 0.0037536621093750, +0.0046081542968750, 0.0036315917968750, 0.0055541992187500, 0.0034179687500000, +0.0048522949218750, 0.0033569335937500, 0.0064392089843750, 0.0032348632812500, +0.0064086914062500, 0.0030517578125000, 0.0064697265625000, 0.0031127929687500, +0.0074462890625000, 0.0032043457031250, 0.0070495605468750, 0.0029296875000000, +0.0070800781250000, 0.0033264160156250, 0.0073547363281250, 0.0031738281250000, +0.0070190429687500, 0.0030822753906250, 0.0066528320312500, 0.0032958984375000, +0.0068359375000000, 0.0030517578125000, 0.0062866210937500, 0.0030822753906250, +0.0062561035156250, 0.0028686523437500, 0.0063171386718750, 0.0028686523437500, +0.0059814453125000, 0.0029907226562500, 0.0059814453125000, 0.0028076171875000, +0.0064697265625000, 0.0029602050781250, 0.0061340332031250, 0.0029907226562500, +0.0063171386718750, 0.0029602050781250, 0.0068969726562500, 0.0029602050781250, +0.0064697265625000, 0.0030212402343750, 0.0065002441406250, 0.0030517578125000, +0.0067138671875000, 0.0030517578125000, 0.0062866210937500, 0.0030822753906250, +0.0059814453125000, 0.0031738281250000, 0.0062866210937500, 0.0031738281250000, +0.0057067871093750, 0.0032653808593750, 0.0057067871093750, 0.0033264160156250, +0.0056762695312500, 0.0032958984375000, 0.0053100585937500, 0.0033569335937500, +0.0054931640625000, 0.0033874511718750, 0.0054321289062500, 0.0032348632812500, +0.0052490234375000, 0.0033264160156250, 0.0054931640625000, 0.0031738281250000, +0.0056762695312500, 0.0029602050781250, 0.0053710937500000, 0.0031433105468750, +0.0060119628906250, 0.0027465820312500, 0.0059204101562500, 0.0027160644531250, +0.0057373046875000, 0.0026855468750000, 0.0060119628906250, 0.0024414062500000, +0.0058898925781250, 0.0023803710937500, 0.0054321289062500, 0.0024108886718750, +0.0055847167968750, 0.0022888183593750, 0.0051574707031250, 0.0023193359375000, +0.0046081542968750, 0.0024108886718750, 0.0049743652343750, 0.0022277832031250, +0.0040283203125000, 0.0023498535156250, 0.0042114257812500, 0.0023193359375000, +0.0039672851562500, 0.0021667480468750, 0.0031738281250000, 0.0021057128906250, +0.0036315917968750, 0.0020446777343750, 0.0028686523437500, 0.0016784667968750, +0.0028991699218750, 0.0017700195312500, 0.0028381347656250, 0.0015258789062500, +0.0023498535156250, 0.0011901855468750, 0.0025329589843750, 0.0015258789062500, +0.0024414062500000, 0.0010070800781250, 0.0022583007812500, 0.0010375976562500, +0.0023193359375000, 0.0010681152343750, 0.0023193359375000, 0.0009155273437500, +0.0021057128906250, 0.0011901855468750, 0.0023193359375000, 0.0010070800781250, +0.0021667480468750, 0.0012207031250000, 0.0022583007812500, 0.0011291503906250, +0.0024108886718750, 0.0009765625000000, 0.0021972656250000, 0.0013732910156250, +0.0028381347656250, 0.0009460449218750, 0.0025939941406250, 0.0011291503906250, +0.0030517578125000, 0.0011596679687500, 0.0037536621093750, 0.0008544921875000, +0.0033264160156250, 0.0011596679687500, 0.0048828125000000, 0.0010375976562500, +0.0046691894531250, 0.0010986328125000, 0.0051574707031250, 0.0012512207031250, +0.0063781738281250, 0.0012512207031250, 0.0058288574218750, 0.0013122558593750, +0.0068969726562500, 0.0017089843750000, 0.0070190429687500, 0.0015563964843750, +0.0068664550781250, 0.0018920898437500, 0.0073547363281250, 0.0023498535156250, +0.0073242187500000, 0.0020141601562500, 0.0067138671875000, 0.0028686523437500, +0.0071105957031250, 0.0027160644531250, 0.0065917968750000, 0.0027770996093750, +0.0058288574218750, 0.0033874511718750, 0.0065002441406250, 0.0029602050781250, +0.0051574707031250, 0.0033569335937500, 0.0053100585937500, 0.0033264160156250, +0.0052490234375000, 0.0032043457031250, 0.0043945312500000, 0.0034179687500000, +0.0048217773437500, 0.0033264160156250, 0.0043945312500000, 0.0032653808593750, +0.0043334960937500, 0.0034179687500000, 0.0044250488281250, 0.0032958984375000, +0.0042724609375000, 0.0032348632812500, 0.0042724609375000, 0.0035095214843750, +0.0045776367187500, 0.0029907226562500, 0.0045471191406250, 0.0032043457031250, +0.0046997070312500, 0.0030822753906250, 0.0049438476562500, 0.0026855468750000, +0.0049438476562500, 0.0029907226562500, 0.0051574707031250, 0.0027770996093750, +0.0053405761718750, 0.0026245117187500, 0.0053100585937500, 0.0028991699218750, +0.0053405761718750, 0.0029907226562500, 0.0054016113281250, 0.0028381347656250, +0.0050354003906250, 0.0034790039062500, 0.0052185058593750, 0.0034179687500000, +0.0050048828125000, 0.0034484863281250, 0.0045471191406250, 0.0039062500000000, +0.0047302246093750, 0.0037231445312500, 0.0040893554687500, 0.0037231445312500, +0.0040893554687500, 0.0038146972656250, 0.0039672851562500, 0.0035400390625000, +0.0035400390625000, 0.0033264160156250, 0.0035705566406250, 0.0034790039062500, +0.0033569335937500, 0.0029907226562500, 0.0031433105468750, 0.0029907226562500, +0.0033874511718750, 0.0030822753906250, 0.0034179687500000, 0.0029602050781250, +0.0031738281250000, 0.0029907226562500, 0.0041198730468750, 0.0030822753906250, +0.0037841796875000, 0.0030212402343750, 0.0040283203125000, 0.0030212402343750, +0.0048522949218750, 0.0030517578125000, 0.0043334960937500, 0.0031433105468750, +0.0048828125000000, 0.0034790039062500, 0.0049743652343750, 0.0033264160156250, +0.0047302246093750, 0.0036621093750000, 0.0047912597656250, 0.0040893554687500, +0.0047912597656250, 0.0038146972656250, 0.0043945312500000, 0.0045776367187500, +0.0044250488281250, 0.0045776367187500, 0.0042114257812500, 0.0044860839843750, +0.0037231445312500, 0.0048522949218750, 0.0037231445312500, 0.0047302246093750, +0.0034790039062500, 0.0043945312500000, 0.0034790039062500, 0.0046691894531250, +0.0035095214843750, 0.0044250488281250, 0.0032653808593750, 0.0039367675781250, +0.0031433105468750, 0.0041809082031250, 0.0038146972656250, 0.0031738281250000, +0.0036010742187500, 0.0032348632812500, 0.0038757324218750, 0.0030517578125000, +0.0046386718750000, 0.0022888183593750, 0.0042114257812500, 0.0025024414062500, +0.0049438476562500, 0.0021057128906250, 0.0049743652343750, 0.0018615722656250, +0.0047607421875000, 0.0020141601562500, 0.0049743652343750, 0.0020141601562500, +0.0048217773437500, 0.0018310546875000, 0.0044860839843750, 0.0020141601562500, +0.0045166015625000, 0.0019531250000000, 0.0043334960937500, 0.0019226074218750, +0.0040588378906250, 0.0020141601562500, 0.0042724609375000, 0.0018615722656250, +0.0039062500000000, 0.0022583007812500, 0.0039672851562500, 0.0019836425781250, +0.0040283203125000, 0.0024108886718750, 0.0038452148437500, 0.0030212402343750, +0.0040283203125000, 0.0023803710937500, 0.0040588378906250, 0.0039672851562500, +0.0042419433593750, 0.0036926269531250, 0.0041503906250000, 0.0040893554687500, +0.0040893554687500, 0.0053405761718750, 0.0043640136718750, 0.0047302246093750, +0.0036315917968750, 0.0056152343750000, 0.0038757324218750, 0.0058288574218750, +0.0037231445312500, 0.0056457519531250, 0.0031127929687500, 0.0059509277343750, +0.0034179687500000, 0.0058898925781250, 0.0032043457031250, 0.0059509277343750, +0.0029602050781250, 0.0059204101562500, 0.0032958984375000, 0.0060119628906250, +0.0034484863281250, 0.0060424804687500, 0.0030517578125000, 0.0059814453125000, +0.0039367675781250, 0.0059814453125000, 0.0036010742187500, 0.0060729980468750, +0.0036926269531250, 0.0057983398437500, 0.0042724609375000, 0.0056762695312500, +0.0037231445312500, 0.0058593750000000, 0.0041198730468750, 0.0052490234375000, +0.0040283203125000, 0.0052490234375000, 0.0037231445312500, 0.0052795410156250, +0.0038146972656250, 0.0049133300781250, 0.0036010742187500, 0.0050354003906250, +0.0032958984375000, 0.0053710937500000, 0.0033569335937500, 0.0050964355468750, +0.0031738281250000, 0.0054931640625000, 0.0028076171875000, 0.0061340332031250, +0.0029907226562500, 0.0057983398437500, 0.0028381347656250, 0.0060729980468750, +0.0027160644531250, 0.0063171386718750, 0.0028991699218750, 0.0059509277343750, +0.0029907226562500, 0.0056457519531250, 0.0028381347656250, 0.0058898925781250, +0.0032043457031250, 0.0054931640625000, 0.0032958984375000, 0.0053710937500000, +0.0032043457031250, 0.0057067871093750, 0.0033264160156250, 0.0057067871093750, +0.0035095214843750, 0.0055541992187500, 0.0028686523437500, 0.0063781738281250, +0.0032653808593750, 0.0062866210937500, 0.0029907226562500, 0.0064697265625000, +0.0023498535156250, 0.0071105957031250, 0.0030212402343750, 0.0068054199218750, +0.0020141601562500, 0.0069274902343750, 0.0022277832031250, 0.0070495605468750, +0.0022277832031250, 0.0067138671875000, 0.0015869140625000, 0.0064392089843750, +0.0020141601562500, 0.0066223144531250, 0.0017700195312500, 0.0058288574218750, +0.0016784667968750, 0.0059204101562500, 0.0018920898437500, 0.0058593750000000, +0.0018615722656250, 0.0053710937500000, 0.0018005371093750, 0.0057373046875000, +0.0021362304687500, 0.0052490234375000, 0.0020751953125000, 0.0054931640625000, +0.0020751953125000, 0.0054321289062500, 0.0023193359375000, 0.0050964355468750, +0.0021362304687500, 0.0054626464843750, 0.0022277832031250, 0.0047912597656250, +0.0022277832031250, 0.0051574707031250, 0.0022583007812500, 0.0048217773437500, +0.0022888183593750, 0.0041503906250000, 0.0021667480468750, 0.0046691894531250, +0.0023498535156250, 0.0035400390625000, 0.0022888183593750, 0.0036926269531250, +0.0023193359375000, 0.0034179687500000, 0.0024414062500000, 0.0025329589843750, +0.0023498535156250, 0.0029907226562500, 0.0025024414062500, 0.0023498535156250, +0.0024414062500000, 0.0021667480468750, 0.0024719238281250, 0.0022583007812500, +0.0025634765625000, 0.0020141601562500, 0.0024414062500000, 0.0020141601562500, +0.0027160644531250, 0.0024108886718750, 0.0026550292968750, 0.0021972656250000, +0.0026855468750000, 0.0023803710937500, 0.0029907226562500, 0.0028076171875000, +0.0028686523437500, 0.0025634765625000, 0.0031127929687500, 0.0030212402343750, +0.0031738281250000, 0.0029907226562500, 0.0031738281250000, 0.0030822753906250, +0.0032958984375000, 0.0033264160156250, 0.0033874511718750, 0.0032653808593750, +0.0032043457031250, 0.0035400390625000, 0.0032348632812500, 0.0034790039062500, +0.0031433105468750, 0.0036010742187500, 0.0030212402343750, 0.0038757324218750, +0.0030212402343750, 0.0036621093750000, 0.0028381347656250, 0.0041198730468750, +0.0027465820312500, 0.0040588378906250, 0.0026550292968750, 0.0042419433593750, +0.0025634765625000, 0.0046081542968750, 0.0024108886718750, 0.0043945312500000, +0.0024719238281250}, +{0.0028686523437500, 0.0052795410156250, 0.0022888183593750, 0.0048522949218750, +0.0022277832031250, 0.0046691894531250, 0.0023498535156250, 0.0047607421875000, +0.0021667480468750, 0.0046386718750000, 0.0021362304687500, 0.0043640136718750, +0.0025329589843750, 0.0048828125000000, 0.0022583007812500, 0.0046081542968750, +0.0024108886718750, 0.0046386718750000, 0.0028686523437500, 0.0050964355468750, +0.0024719238281250, 0.0048217773437500, 0.0030212402343750, 0.0047302246093750, +0.0029602050781250, 0.0047912597656250, 0.0028991699218750, 0.0043945312500000, +0.0031433105468750, 0.0039672851562500, 0.0029907226562500, 0.0041198730468750, +0.0029907226562500, 0.0039062500000000, 0.0029907226562500, 0.0034790039062500, +0.0028991699218750, 0.0039672851562500, 0.0027160644531250, 0.0043334960937500, +0.0027160644531250, 0.0037841796875000, 0.0028381347656250, 0.0051879882812500, +0.0026550292968750, 0.0050048828125000, 0.0028076171875000, 0.0051574707031250, +0.0030822753906250, 0.0061035156250000, 0.0028686523437500, 0.0055541992187500, +0.0032348632812500, 0.0061035156250000, 0.0032653808593750, 0.0061035156250000, +0.0032653808593750, 0.0060424804687500, 0.0034790039062500, 0.0062255859375000, +0.0034790039062500, 0.0060424804687500, 0.0034790039062500, 0.0064086914062500, +0.0036621093750000, 0.0061645507812500, 0.0034179687500000, 0.0066223144531250, +0.0032958984375000, 0.0072021484375000, 0.0035705566406250, 0.0068054199218750, +0.0028381347656250, 0.0080261230468750, 0.0031127929687500, 0.0080566406250000, +0.0029602050781250, 0.0080566406250000, 0.0022277832031250, 0.0087585449218750, +0.0027465820312500, 0.0086059570312500, 0.0022277832031250, 0.0083007812500000, +0.0021972656250000, 0.0086975097656250, 0.0024719238281250, 0.0080566406250000, +0.0024414062500000, 0.0074462890625000, 0.0023803710937500, 0.0079956054687500, +0.0027160644531250, 0.0060424804687500, 0.0027465820312500, 0.0063781738281250, +0.0026855468750000, 0.0055847167968750, 0.0028686523437500, 0.0039672851562500, +0.0028991699218750, 0.0049133300781250, 0.0026245117187500, 0.0026550292968750, +0.0027770996093750, 0.0027770996093750, 0.0026550292968750, 0.0024108886718750, +0.0023498535156250, 0.0009460449218750, 0.0025329589843750, 0.0016479492187500, +0.0024108886718750, 0.0004882812500000, 0.0023193359375000, 0.0005493164062500, +0.0024719238281250, 0.0006408691406250, 0.0026245117187500, 0.0000610351562500, +0.0025939941406250, 0.0003662109375000, 0.0028686523437500, 0.0004577636718750, +0.0029296875000000, 0.0002441406250000, 0.0028991699218750, 0.0005798339843750, +0.0031127929687500, 0.0009460449218750, 0.0031433105468750, 0.0006408691406250, +0.0030517578125000, 0.0016784667968750, 0.0031433105468750, 0.0014953613281250, +0.0031127929687500, 0.0018005371093750, 0.0029907226562500, 0.0026245117187500, +0.0030822753906250, 0.0022888183593750, 0.0029296875000000, 0.0028381347656250, +0.0028991699218750, 0.0029907226562500, 0.0028686523437500, 0.0027465820312500, +0.0027770996093750, 0.0028381347656250, 0.0027465820312500, 0.0029602050781250, +0.0027465820312500, 0.0022888183593750, 0.0026855468750000, 0.0025024414062500, +0.0026855468750000, 0.0021667480468750, 0.0026550292968750, 0.0015258789062500, +0.0025329589843750, 0.0018310546875000, 0.0028991699218750, 0.0011291503906250, +0.0026855468750000, 0.0010375976562500, 0.0028381347656250, 0.0010986328125000, +0.0032653808593750, 0.0008239746093750, 0.0028686523437500, 0.0009155273437500, +0.0034790039062500, 0.0009460449218750, 0.0033874511718750, 0.0009765625000000, +0.0032653808593750, 0.0010375976562500, 0.0036010742187500, 0.0011291503906250, +0.0034179687500000, 0.0011596679687500, 0.0032653808593750, 0.0010375976562500, +0.0032958984375000, 0.0011291503906250, 0.0030212402343750, 0.0010681152343750, +0.0027465820312500, 0.0009155273437500, 0.0027465820312500, 0.0010681152343750, +0.0023803710937500, 0.0007934570312500, 0.0021972656250000, 0.0008239746093750, +0.0023498535156250, 0.0007934570312500, 0.0022277832031250, 0.0005493164062500, +0.0020446777343750, 0.0005493164062500, 0.0028686523437500, 0.0008850097656250, +0.0026550292968750, 0.0005798339843750, 0.0029907226562500, 0.0010986328125000, +0.0038452148437500, 0.0017089843750000, 0.0034179687500000, 0.0012207031250000, +0.0044250488281250, 0.0028381347656250, 0.0045776367187500, 0.0026550292968750, +0.0044860839843750, 0.0030212402343750, 0.0048522949218750, 0.0041503906250000, +0.0048828125000000, 0.0036315917968750, 0.0044555664062500, 0.0045166015625000, +0.0048217773437500, 0.0045166015625000, 0.0043945312500000, 0.0045471191406250, +0.0038452148437500, 0.0050354003906250, 0.0042419433593750, 0.0048522949218750, +0.0031433105468750, 0.0050354003906250, 0.0032958984375000, 0.0050964355468750, +0.0030517578125000, 0.0052185058593750, 0.0021667480468750, 0.0053710937500000, +0.0026245117187500, 0.0052490234375000, 0.0023803710937500, 0.0056762695312500, +0.0020751953125000, 0.0056762695312500, 0.0026550292968750, 0.0057373046875000, +0.0029907226562500, 0.0061035156250000, 0.0026245117187500, 0.0060424804687500, +0.0038146972656250, 0.0055541992187500, 0.0036315917968750, 0.0060424804687500, +0.0037231445312500, 0.0052795410156250, 0.0045166015625000, 0.0043029785156250, +0.0041503906250000, 0.0051269531250000, 0.0043334960937500, 0.0036010742187500, +0.0044250488281250, 0.0034790039062500, 0.0043029785156250, 0.0034790039062500, +0.0042419433593750, 0.0028686523437500, 0.0042419433593750, 0.0032348632812500, +0.0043945312500000, 0.0023803710937500, 0.0042114257812500, 0.0026550292968750, +0.0043029785156250, 0.0025634765625000, 0.0046997070312500, 0.0015258789062500, +0.0034484863281250, 0.0046691894531250, 0.0025024414062500, 0.0021057128906250, +0.0025939941406250, 0.0030517578125000, 0.0025939941406250, 0.0024414062500000, +0.0021972656250000, 0.0010375976562500, 0.0021667480468750, 0.0016479492187500, +0.0025939941406250, 0.0014038085937500, 0.0024108886718750, 0.0009765625000000, +0.0025634765625000, 0.0016784667968750, 0.0029907226562500, 0.0021667480468750, +0.0025634765625000, 0.0016479492187500, 0.0031127929687500, 0.0030212402343750, +0.0029602050781250, 0.0029602050781250, 0.0031738281250000, 0.0029907226562500, +0.0036315917968750, 0.0039062500000000, 0.0032043457031250, 0.0037231445312500, +0.0039978027343750, 0.0036010742187500, 0.0037841796875000, 0.0039978027343750, +0.0037841796875000, 0.0035095214843750, 0.0042724609375000, 0.0031127929687500, +0.0039367675781250, 0.0036621093750000, 0.0040283203125000, 0.0023498535156250, +0.0039672851562500, 0.0025634765625000, 0.0040588378906250, 0.0025634765625000, +0.0040588378906250, 0.0017700195312500, 0.0037536621093750, 0.0022583007812500, +0.0048522949218750, 0.0023193359375000, 0.0044250488281250, 0.0021057128906250, +0.0048217773437500, 0.0026855468750000, 0.0058288574218750, 0.0033569335937500, +0.0051269531250000, 0.0030212402343750, 0.0065002441406250, 0.0036926269531250, +0.0062866210937500, 0.0040588378906250, 0.0064086914062500, 0.0037231445312500, +0.0073852539062500, 0.0037231445312500, 0.0068359375000000, 0.0039062500000000, +0.0072021484375000, 0.0033874511718750, 0.0073852539062500, 0.0034790039062500, +0.0070190429687500, 0.0034179687500000, 0.0068664550781250, 0.0031433105468750, +0.0070800781250000, 0.0032043457031250, 0.0058898925781250, 0.0032958984375000, +0.0062255859375000, 0.0031433105468750, 0.0055847167968750, 0.0032043457031250, +0.0044860839843750, 0.0033569335937500, 0.0050354003906250, 0.0032958984375000, +0.0036010742187500, 0.0034790039062500, 0.0037536621093750, 0.0036010742187500, +0.0034179687500000, 0.0035400390625000, 0.0024414062500000, 0.0036315917968750, +0.0028991699218750, 0.0037536621093750, 0.0019531250000000, 0.0035095214843750, +0.0020141601562500, 0.0037841796875000, 0.0018005371093750, 0.0037231445312500, +0.0010986328125000, 0.0035095214843750, 0.0014343261718750, 0.0037536621093750, +0.0009460449218750, 0.0036010742187500, 0.0008239746093750, 0.0036010742187500, +0.0009765625000000, 0.0037231445312500, 0.0008239746093750, 0.0037536621093750, +0.0008544921875000, 0.0038146972656250, 0.0014038085937500, 0.0036315917968750, +0.0011596679687500, 0.0038146972656250, 0.0016479492187500, 0.0037841796875000, +0.0024108886718750, 0.0036010742187500, 0.0019836425781250, 0.0036621093750000, +0.0027160644531250, 0.0036010742187500, 0.0030822753906250, 0.0036010742187500, +0.0025939941406250, 0.0036010742187500, 0.0025939941406250, 0.0036621093750000, +0.0030822753906250, 0.0037231445312500, 0.0015869140625000, 0.0036315917968750, +0.0021057128906250, 0.0037536621093750, 0.0015869140625000, 0.0036315917968750, +0.0003662109375000, 0.0035095214843750, 0.0012817382812500, 0.0036621093750000, +-0.0001525878906250, 0.0033264160156250, -0.0000915527343750, 0.0033569335937500, +0.0003356933593750, 0.0032348632812500, -0.0003356933593750, 0.0030212402343750, +-0.0001220703125000, 0.0031433105468750, 0.0011596679687500, 0.0029296875000000, +0.0006713867187500, 0.0028991699218750, 0.0017089843750000, 0.0028381347656250, +0.0032348632812500, 0.0027160644531250, 0.0023803710937500, 0.0027770996093750, +0.0045776367187500, 0.0025939941406250, 0.0046081542968750, 0.0026855468750000, +0.0049438476562500, 0.0025634765625000, 0.0062866210937500, 0.0024108886718750, +0.0057678222656250, 0.0025939941406250, 0.0064697265625000, 0.0022277832031250, +0.0068664550781250, 0.0022277832031250, 0.0065002441406250, 0.0022277832031250, +0.0065612792968750, 0.0020446777343750, 0.0068054199218750, 0.0021057128906250, +0.0057067871093750, 0.0021972656250000, 0.0061035156250000, 0.0021972656250000, +0.0054626464843750, 0.0021667480468750, 0.0042724609375000, 0.0021972656250000, +0.0050964355468750, 0.0021972656250000, 0.0029907226562500, 0.0021362304687500, +0.0034179687500000, 0.0022583007812500, 0.0028686523437500, 0.0023498535156250, +0.0012817382812500, 0.0022888183593750, 0.0022277832031250, 0.0023498535156250, +0.0005798339843750, 0.0023498535156250, 0.0005493164062500, 0.0023803710937500, +0.0005187988281250, 0.0023803710937500, -0.0003356933593750, 0.0024108886718750, +0.0000305175781250, 0.0025329589843750, -0.0002136230468750, 0.0024108886718750, +-0.0004272460937500, 0.0025024414062500, -0.0001831054687500, 0.0026245117187500, +-0.0000305175781250, 0.0025634765625000, -0.0002441406250000, 0.0025634765625000, +0.0002136230468750, 0.0027465820312500, 0.0002136230468750, 0.0027160644531250, +0.0003051757812500, 0.0028076171875000, 0.0006408691406250, 0.0029907226562500, +0.0005493164062500, 0.0027770996093750, 0.0007629394531250, 0.0029907226562500, +0.0008544921875000, 0.0029296875000000, 0.0010375976562500, 0.0029602050781250, +0.0012512207031250, 0.0029907226562500, 0.0011596679687500, 0.0028381347656250, +0.0019226074218750, 0.0029296875000000, 0.0017089843750000, 0.0028381347656250, +0.0021667480468750, 0.0028076171875000, 0.0028991699218750, 0.0028076171875000, +0.0024108886718750, 0.0027770996093750, 0.0034484863281250, 0.0026855468750000, +0.0033874511718750, 0.0026855468750000, 0.0032348632812500, 0.0025634765625000, +0.0036621093750000, 0.0023803710937500, 0.0035095214843750, 0.0024108886718750, +0.0032348632812500, 0.0024108886718750, 0.0034790039062500, 0.0021972656250000, +0.0032348632812500}, +{0.0019836425781250, 0.0041198730468750, 0.0020141601562500, 0.0039672851562500, +0.0029296875000000, 0.0038757324218750, 0.0023803710937500, 0.0039367675781250, +0.0023498535156250, 0.0037536621093750, 0.0027160644531250, 0.0038146972656250, +0.0018615722656250, 0.0038146972656250, 0.0011291503906250, 0.0036621093750000, +0.0018005371093750, 0.0038757324218750, -0.0001525878906250, 0.0036621093750000, +0.0000000000000000, 0.0036621093750000, -0.0001220703125000, 0.0036621093750000, +-0.0014343261718750, 0.0035400390625000, -0.0010375976562500, 0.0036621093750000, +-0.0009460449218750, 0.0035400390625000, -0.0015258789062500, 0.0036621093750000, +-0.0007934570312500, 0.0035705566406250, -0.0001525878906250, 0.0035400390625000, +-0.0009765625000000, 0.0037231445312500, 0.0012512207031250, 0.0031738281250000, +0.0007324218750000, 0.0034484863281250, 0.0012207031250000, 0.0032958984375000, +0.0030212402343750, 0.0027770996093750, 0.0020141601562500, 0.0031433105468750, +0.0031433105468750, 0.0025634765625000, 0.0033569335937500, 0.0025634765625000, +0.0027770996093750, 0.0025634765625000, 0.0028991699218750, 0.0022277832031250, +0.0030517578125000, 0.0023498535156250, 0.0019226074218750, 0.0023193359375000, +0.0021667480468750, 0.0021972656250000, 0.0016479492187500, 0.0024414062500000, +0.0006713867187500, 0.0025939941406250, 0.0012817382812500, 0.0024414062500000, +0.0001831054687500, 0.0028991699218750, 0.0000915527343750, 0.0027770996093750, +0.0003356933593750, 0.0027770996093750, -0.0000915527343750, 0.0030517578125000, +0.0000610351562500, 0.0028381347656250, 0.0007629394531250, 0.0029602050781250, +0.0003356933593750, 0.0028381347656250, 0.0010986328125000, 0.0027465820312500, +0.0020141601562500, 0.0027160644531250, 0.0014343261718750, 0.0025939941406250, +0.0032958984375000, 0.0025634765625000, 0.0030822753906250, 0.0025024414062500, +0.0035095214843750, 0.0024414062500000, 0.0047912597656250, 0.0024108886718750, +0.0040893554687500, 0.0024414062500000, 0.0050659179687500, 0.0024719238281250, +0.0051269531250000, 0.0025024414062500, 0.0048828125000000, 0.0026550292968750, +0.0052185058593750, 0.0027465820312500, 0.0049438476562500, 0.0026245117187500, +0.0043945312500000, 0.0028686523437500, 0.0045776367187500, 0.0029296875000000, +0.0040588378906250, 0.0029296875000000, 0.0033874511718750, 0.0031433105468750, +0.0038146972656250, 0.0030822753906250, 0.0027160644531250, 0.0031738281250000, +0.0029602050781250, 0.0032043457031250, 0.0027770996093750, 0.0031738281250000, +0.0020446777343750, 0.0032043457031250, 0.0026245117187500, 0.0031738281250000, +0.0020141601562500, 0.0030517578125000, 0.0022277832031250, 0.0030517578125000, +0.0022583007812500, 0.0029907226562500, 0.0018615722656250, 0.0028991699218750, +0.0022583007812500, 0.0028991699218750, 0.0018920898437500, 0.0026550292968750, +0.0019836425781250, 0.0027465820312500, 0.0021057128906250, 0.0026855468750000, +0.0018615722656250, 0.0023803710937500, 0.0019226074218750, 0.0026550292968750, +0.0022277832031250, 0.0024108886718750, 0.0020141601562500, 0.0023193359375000, +0.0024414062500000, 0.0025939941406250, 0.0029907226562500, 0.0026550292968750, +0.0026245117187500, 0.0025024414062500, 0.0037536621093750, 0.0031738281250000, +0.0036315917968750, 0.0030212402343750, 0.0037536621093750, 0.0031738281250000, +0.0043945312500000, 0.0036926269531250, 0.0040588378906250, 0.0034484863281250, +0.0042114257812500, 0.0035400390625000, 0.0043029785156250, 0.0037231445312500, +0.0041198730468750, 0.0035095214843750, 0.0039978027343750, 0.0033874511718750, +0.0039978027343750, 0.0035400390625000, 0.0036315917968750, 0.0031738281250000, +0.0036926269531250, 0.0032653808593750, 0.0036315917968750, 0.0032043457031250, +0.0033874511718750, 0.0029296875000000, 0.0034484863281250, 0.0031433105468750, +0.0032958984375000, 0.0029296875000000, 0.0032958984375000, 0.0028991699218750, +0.0031738281250000, 0.0030212402343750, 0.0030517578125000, 0.0029907226562500, +0.0032043457031250, 0.0030517578125000, 0.0031433105468750, 0.0032958984375000, +0.0032043457031250, 0.0033569335937500, 0.0032348632812500, 0.0035400390625000, +0.0032653808593750, 0.0038146972656250, 0.0033264160156250, 0.0038452148437500, +0.0028686523437500, 0.0039062500000000, 0.0030212402343750, 0.0040588378906250, +0.0027770996093750, 0.0038757324218750, 0.0023193359375000, 0.0037536621093750, +0.0025634765625000, 0.0039978027343750, 0.0018920898437500, 0.0035095214843750, +0.0018310546875000, 0.0036621093750000, 0.0018615722656250, 0.0035095214843750, +0.0015258789062500, 0.0031127929687500, 0.0016479492187500, 0.0034179687500000, +0.0018920898437500, 0.0029602050781250, 0.0018310546875000, 0.0029602050781250, +0.0020751953125000, 0.0027770996093750, 0.0024108886718750, 0.0023803710937500, +0.0024414062500000, 0.0026550292968750, 0.0028381347656250, 0.0021972656250000, +0.0028686523437500, 0.0021667480468750, 0.0030517578125000, 0.0022888183593750, +0.0034179687500000, 0.0020446777343750, 0.0033874511718750, 0.0020751953125000, +0.0038452148437500, 0.0029296875000000, 0.0036926269531250, 0.0025024414062500, +0.0035095214843750, 0.0028991699218750, 0.0036926269531250, 0.0037841796875000, +0.0035400390625000, 0.0032043457031250, 0.0033874511718750, 0.0042419433593750, +0.0033874511718750, 0.0043945312500000, 0.0032958984375000, 0.0044555664062500, +0.0031433105468750, 0.0050354003906250, 0.0032653808593750, 0.0049438476562500, +0.0036010742187500, 0.0050659179687500, 0.0034484863281250, 0.0053100585937500, +0.0036315917968750, 0.0050964355468750, 0.0041503906250000, 0.0049133300781250, +0.0040588378906250, 0.0052490234375000, 0.0040588378906250, 0.0044250488281250, +0.0044555664062500, 0.0045471191406250, 0.0042114257812500, 0.0044250488281250, +0.0039367675781250, 0.0039367675781250, 0.0043029785156250, 0.0042724609375000, +0.0036315917968750, 0.0038757324218750, 0.0037536621093750, 0.0039062500000000, +0.0037231445312500, 0.0038146972656250, 0.0032348632812500, 0.0037536621093750, +0.0034790039062500, 0.0039367675781250, 0.0036315917968750, 0.0029296875000000, +0.0034179687500000, 0.0033264160156250, 0.0036926269531250, 0.0028991699218750, +0.0041198730468750, 0.0018005371093750, 0.0038452148437500, 0.0022583007812500, +0.0043029785156250, 0.0013732910156250, 0.0044250488281250, 0.0011291503906250, +0.0043334960937500, 0.0012817382812500, 0.0044555664062500, 0.0010070800781250, +0.0045471191406250, 0.0008239746093750, 0.0042419433593750, 0.0010986328125000, +0.0042419433593750, 0.0010681152343750, 0.0042419433593750, 0.0009155273437500, +0.0040283203125000, 0.0010375976562500, 0.0039978027343750, 0.0010070800781250, +0.0042419433593750, 0.0007019042968750, 0.0040588378906250, 0.0007324218750000, +0.0041503906250000, 0.0007019042968750, 0.0044555664062500, 0.0003662109375000, +0.0043334960937500, 0.0003051757812500, 0.0043029785156250, 0.0007324218750000, +0.0044555664062500, 0.0003967285156250, 0.0042114257812500, 0.0008850097656250, +0.0039367675781250, 0.0015258789062500, 0.0041198730468750, 0.0010375976562500, +0.0035705566406250, 0.0021667480468750, 0.0036010742187500, 0.0022583007812500, +0.0036010742187500, 0.0021667480468750, 0.0032653808593750, 0.0027160644531250, +0.0034179687500000, 0.0025939941406250, 0.0032958984375000, 0.0021667480468750, +0.0032653808593750, 0.0023193359375000, 0.0033569335937500, 0.0023193359375000, +0.0034484863281250, 0.0019531250000000, 0.0034790039062500, 0.0020141601562500, +0.0036315917968750, 0.0023498535156250, 0.0036926269531250, 0.0021362304687500, +0.0037231445312500, 0.0024108886718750, 0.0038452148437500, 0.0029602050781250, +0.0039367675781250, 0.0026855468750000, 0.0038146972656250, 0.0031433105468750, +0.0038452148437500, 0.0032653808593750, 0.0038452148437500, 0.0029602050781250, +0.0037536621093750, 0.0029296875000000, 0.0037536621093750, 0.0029907226562500, +0.0037841796875000, 0.0020751953125000, 0.0036926269531250, 0.0022583007812500, +0.0036926269531250, 0.0017395019531250, 0.0037536621093750, 0.0008239746093750, +0.0037231445312500, 0.0012207031250000, 0.0038757324218750, 0.0003662109375000, +0.0037841796875000, 0.0003051757812500, 0.0038452148437500, 0.0003356933593750, +0.0039978027343750, -0.0000305175781250, 0.0038452148437500, 0.0001220703125000, +0.0040588378906250, 0.0000000000000000, 0.0040588378906250, 0.0000305175781250, +0.0039062500000000, 0.0001525878906250, 0.0038757324218750, 0.0000915527343750, +0.0039978027343750, 0.0001525878906250, 0.0035400390625000, 0.0003051757812500, +0.0036621093750000, 0.0002746582031250, 0.0035095214843750, 0.0005493164062500, +0.0032348632812500, 0.0007629394531250, 0.0034484863281250, 0.0006408691406250, +0.0029602050781250, 0.0015869140625000, 0.0030517578125000, 0.0013427734375000, +0.0030212402343750, 0.0019531250000000, 0.0026550292968750, 0.0028686523437500, +0.0028381347656250, 0.0023498535156250, 0.0026550292968750, 0.0040893554687500, +0.0026245117187500, 0.0038452148437500, 0.0026855468750000, 0.0043640136718750, +0.0026855468750000, 0.0057067871093750, 0.0026245117187500, 0.0050048828125000, +0.0027160644531250, 0.0063476562500000, 0.0026550292968750, 0.0065002441406250, +0.0026245117187500, 0.0063171386718750, 0.0026245117187500, 0.0069274902343750, +0.0025634765625000, 0.0068359375000000, 0.0025329589843750, 0.0062866210937500, +0.0024414062500000, 0.0066528320312500, 0.0024414062500000, 0.0060119628906250, +0.0024414062500000, 0.0052185058593750, 0.0024108886718750, 0.0056762695312500, +0.0026550292968750, 0.0039978027343750, 0.0025634765625000, 0.0041503906250000, +0.0027465820312500, 0.0036926269531250, 0.0030517578125000, 0.0025329589843750, +0.0028991699218750, 0.0030822753906250, 0.0032958984375000, 0.0021362304687500, +0.0033874511718750, 0.0019226074218750, 0.0032958984375000, 0.0020446777343750, +0.0035095214843750, 0.0018310546875000, 0.0036010742187500, 0.0018310546875000, +0.0031738281250000, 0.0022583007812500, 0.0034484863281250, 0.0020751953125000, +0.0032653808593750, 0.0025329589843750, 0.0028991699218750, 0.0031433105468750, +0.0032043457031250, 0.0028381347656250, 0.0026550292968750, 0.0035400390625000, +0.0027770996093750, 0.0036315917968750, 0.0027770996093750, 0.0036926269531250, +0.0024719238281250, 0.0040893554687500, 0.0027465820312500, 0.0040283203125000, +0.0028076171875000, 0.0040283203125000, 0.0027770996093750, 0.0041809082031250, +0.0030822753906250, 0.0039978027343750, 0.0033264160156250, 0.0038452148437500, +0.0032348632812500, 0.0039978027343750, 0.0036926269531250, 0.0036010742187500, +0.0038146972656250, 0.0035095214843750, 0.0036621093750000, 0.0035400390625000, +0.0038146972656250, 0.0033569335937500, 0.0039062500000000, 0.0032348632812500, +0.0034790039062500, 0.0035705566406250, 0.0035400390625000, 0.0032653808593750, +0.0034484863281250, 0.0036010742187500, 0.0030212402343750, 0.0040588378906250, +0.0030822753906250, 0.0036926269531250, 0.0029907226562500, 0.0042114257812500, +0.0027770996093750, 0.0043334960937500, 0.0029602050781250, 0.0042419433593750, +0.0031127929687500, 0.0043640136718750, 0.0028686523437500, 0.0043640136718750, +0.0033569335937500, 0.0042724609375000, 0.0032348632812500, 0.0042419433593750, +0.0033569335937500, 0.0042419433593750, 0.0036926269531250, 0.0042114257812500, +0.0034484863281250}, +{0.0037231445312500, 0.0013732910156250, 0.0037536621093750, 0.0015563964843750, +0.0035400390625000, 0.0015258789062500, 0.0036621093750000, 0.0015563964843750, +0.0035400390625000, 0.0014648437500000, 0.0034484863281250, 0.0013122558593750, +0.0036010742187500, 0.0014343261718750, 0.0034790039062500, 0.0010375976562500, +0.0035095214843750, 0.0010986328125000, 0.0036010742187500, 0.0011291503906250, +0.0036010742187500, 0.0009460449218750, 0.0036010742187500, 0.0010986328125000, +0.0036315917968750, 0.0011596679687500, 0.0037841796875000, 0.0011901855468750, +0.0036010742187500, 0.0013122558593750, 0.0034790039062500, 0.0014038085937500, +0.0037231445312500, 0.0015258789062500, 0.0031433105468750, 0.0016784667968750, +0.0033264160156250, 0.0016174316406250, 0.0032043457031250, 0.0017700195312500, +0.0027160644531250, 0.0019226074218750, 0.0030212402343750, 0.0017700195312500, +0.0025939941406250, 0.0021057128906250, 0.0026550292968750, 0.0020751953125000, +0.0026855468750000, 0.0021057128906250, 0.0024414062500000, 0.0023498535156250, +0.0025939941406250, 0.0022583007812500, 0.0024719238281250, 0.0025024414062500, +0.0025329589843750, 0.0025024414062500, 0.0025939941406250, 0.0026245117187500, +0.0025939941406250, 0.0028381347656250, 0.0027160644531250, 0.0028076171875000, +0.0027770996093750, 0.0031433105468750, 0.0027770996093750, 0.0032348632812500, +0.0028381347656250, 0.0032348632812500, 0.0029907226562500, 0.0034790039062500, +0.0029602050781250, 0.0036010742187500, 0.0029602050781250, 0.0033874511718750, +0.0030517578125000, 0.0035705566406250, 0.0029296875000000, 0.0032653808593750, +0.0028686523437500, 0.0029296875000000, 0.0029907226562500, 0.0032958984375000, +0.0026550292968750, 0.0022277832031250, 0.0028381347656250, 0.0024414062500000, +0.0026855468750000, 0.0019226074218750, 0.0024414062500000, 0.0009460449218750, +0.0027770996093750, 0.0015258789062500, 0.0024108886718750, 0.0003356933593750, +0.0025634765625000, 0.0003356933593750, 0.0026855468750000, 0.0003051757812500, +0.0025329589843750, -0.0003967285156250, 0.0028076171875000, -0.0001831054687500, +0.0028381347656250, 0.0000305175781250, 0.0029296875000000, -0.0002441406250000, +0.0031433105468750, 0.0002441406250000, 0.0033874511718750, 0.0007629394531250, +0.0034790039062500, 0.0004272460937500, 0.0036010742187500, 0.0017395019531250, +0.0038757324218750, 0.0015869140625000, 0.0037841796875000, 0.0019226074218750, +0.0036926269531250, 0.0029907226562500, 0.0039978027343750, 0.0025024414062500, +0.0035095214843750, 0.0033264160156250, 0.0036010742187500, 0.0033874511718750, +0.0035095214843750, 0.0032958984375000, 0.0030517578125000, 0.0036010742187500, +0.0031738281250000, 0.0034179687500000, 0.0030517578125000, 0.0034179687500000, +0.0028076171875000, 0.0034179687500000, 0.0028991699218750, 0.0033569335937500, +0.0029907226562500, 0.0032348632812500, 0.0027465820312500, 0.0032043457031250, +0.0032958984375000, 0.0034790039062500, 0.0030822753906250, 0.0032958984375000, +0.0031738281250000, 0.0032958984375000, 0.0036621093750000, 0.0035400390625000, +0.0033264160156250, 0.0034790039062500, 0.0037231445312500, 0.0034484863281250, +0.0036926269531250, 0.0035400390625000, 0.0036010742187500, 0.0035705566406250, +0.0038146972656250, 0.0035400390625000, 0.0038146972656250, 0.0035095214843750, +0.0039062500000000, 0.0036010742187500, 0.0038757324218750, 0.0035705566406250, +0.0040283203125000, 0.0037536621093750, 0.0041503906250000, 0.0038146972656250, +0.0039367675781250, 0.0037536621093750, 0.0042114257812500, 0.0042724609375000, +0.0041503906250000, 0.0041198730468750, 0.0038452148437500, 0.0044555664062500, +0.0039367675781250, 0.0049743652343750, 0.0039672851562500, 0.0046691894531250, +0.0031738281250000, 0.0049438476562500, 0.0033569335937500, 0.0052490234375000, +0.0030517578125000, 0.0045776367187500, 0.0022583007812500, 0.0042724609375000, +0.0026855468750000, 0.0046997070312500, 0.0021972656250000, 0.0027160644531250, +0.0019226074218750, 0.0029907226562500, 0.0023803710937500, 0.0026245117187500, +0.0025634765625000, 0.0011596679687500, 0.0022888183593750, 0.0017700195312500, +0.0032958984375000, 0.0013122558593750, 0.0031738281250000, 0.0008239746093750, +0.0031433105468750, 0.0014038085937500, 0.0039367675781250, 0.0021667480468750, +0.0033264160156250, 0.0030212402343750, 0.0035705566406250, 0.0016174316406250, +0.0032653808593750, 0.0017700195312500, 0.0035705566406250, 0.0017395019531250, +0.0038757324218750, 0.0014343261718750, 0.0035705566406250, 0.0016784667968750, +0.0042724609375000, 0.0014953613281250, 0.0039978027343750, 0.0014343261718750, +0.0042419433593750, 0.0019226074218750, 0.0048522949218750, 0.0020751953125000, +0.0042724609375000, 0.0017700195312500, 0.0054016113281250, 0.0036926269531250, +0.0051574707031250, 0.0031433105468750, 0.0051574707031250, 0.0037841796875000, +0.0058288574218750, 0.0055847167968750, 0.0054931640625000, 0.0047302246093750, +0.0052490234375000, 0.0052490234375000, 0.0055541992187500, 0.0059509277343750, +0.0051269531250000, 0.0049438476562500, 0.0046081542968750, 0.0043334960937500, +0.0049743652343750, 0.0051269531250000, 0.0042114257812500, 0.0028991699218750, +0.0041809082031250, 0.0031433105468750, 0.0039367675781250, 0.0028991699218750, +0.0034790039062500, 0.0014343261718750, 0.0037841796875000, 0.0020446777343750, +0.0028686523437500, 0.0016174316406250, 0.0031738281250000, 0.0010986328125000, +0.0029907226562500, 0.0017395019531250, 0.0022888183593750, 0.0022277832031250, +0.0027770996093750, 0.0016479492187500, 0.0021972656250000, 0.0033569335937500, +0.0022277832031250, 0.0032043457031250, 0.0024719238281250, 0.0034179687500000, +0.0022583007812500, 0.0046081542968750, 0.0023498535156250, 0.0039978027343750, +0.0028076171875000, 0.0041503906250000, 0.0026550292968750, 0.0044250488281250, +0.0029296875000000, 0.0039367675781250, 0.0035095214843750, 0.0034484863281250, +0.0033264160156250, 0.0037536621093750, 0.0039672851562500, 0.0031738281250000, +0.0040283203125000, 0.0030822753906250, 0.0040893554687500, 0.0032043457031250, +0.0045166015625000, 0.0030517578125000, 0.0044555664062500, 0.0031738281250000, +0.0044250488281250, 0.0032958984375000, 0.0046386718750000, 0.0033569335937500, +0.0043640136718750, 0.0033569335937500, 0.0041503906250000, 0.0033874511718750, +0.0044555664062500, 0.0035095214843750, 0.0032958984375000, 0.0034179687500000, +0.0036010742187500, 0.0034790039062500, 0.0032348632812500, 0.0034790039062500, +0.0021972656250000, 0.0033874511718750, 0.0026550292968750, 0.0033874511718750, +0.0021362304687500, 0.0033264160156250, 0.0018005371093750, 0.0032958984375000, +0.0024719238281250, 0.0033264160156250, 0.0026550292968750, 0.0032958984375000, +0.0021667480468750, 0.0032348632812500, 0.0041809082031250, 0.0033264160156250, +0.0037536621093750, 0.0033264160156250, 0.0040893554687500, 0.0032958984375000, +0.0056457519531250, 0.0032348632812500, 0.0049438476562500, 0.0032043457031250, +0.0053100585937500, 0.0030517578125000, 0.0058898925781250, 0.0029907226562500, +0.0050659179687500, 0.0029602050781250, 0.0045166015625000, 0.0028686523437500, +0.0052490234375000, 0.0027160644531250, 0.0032958984375000, 0.0028076171875000, +0.0036621093750000, 0.0025634765625000, 0.0032043457031250, 0.0026245117187500, +0.0016479492187500, 0.0027160644531250, 0.0025329589843750, 0.0024414062500000, +0.0013732910156250, 0.0027465820312500, 0.0010070800781250, 0.0025939941406250, +0.0014038085937500, 0.0026855468750000, 0.0010681152343750, 0.0030517578125000, +0.0007934570312500, 0.0027465820312500, 0.0018005371093750, 0.0032348632812500, +0.0014343261718750, 0.0031127929687500, 0.0016479492187500, 0.0031738281250000, +0.0024414062500000, 0.0034484863281250, 0.0020141601562500, 0.0031738281250000, +0.0025939941406250, 0.0034179687500000, 0.0025329589843750, 0.0034179687500000, +0.0025939941406250, 0.0032653808593750, 0.0029907226562500, 0.0033264160156250, +0.0027465820312500, 0.0032348632812500, 0.0028991699218750, 0.0029602050781250, +0.0030517578125000, 0.0029602050781250, 0.0028076171875000, 0.0029296875000000, +0.0026245117187500, 0.0027770996093750, 0.0027770996093750, 0.0027465820312500, +0.0020751953125000, 0.0026855468750000, 0.0021667480468750, 0.0026550292968750, +0.0018615722656250, 0.0027160644531250, 0.0012512207031250, 0.0027465820312500, +0.0014038085937500, 0.0026550292968750, 0.0007629394531250, 0.0028381347656250, +0.0006713867187500, 0.0028076171875000, 0.0005493164062500, 0.0028991699218750, +0.0000610351562500, 0.0030822753906250, 0.0000610351562500, 0.0029296875000000, +0.0001525878906250, 0.0030822753906250, -0.0001220703125000, 0.0029907226562500, +0.0001525878906250, 0.0028381347656250, 0.0004272460937500, 0.0028686523437500, +0.0002441406250000, 0.0027770996093750, 0.0014038085937500, 0.0027465820312500, +0.0012207031250000, 0.0026550292968750, 0.0018920898437500, 0.0026550292968750, +0.0030822753906250, 0.0026550292968750, 0.0025939941406250, 0.0025634765625000, +0.0043029785156250, 0.0025634765625000, 0.0043640136718750, 0.0026550292968750, +0.0045776367187500, 0.0026550292968750, 0.0055847167968750, 0.0025634765625000, +0.0053405761718750, 0.0025634765625000, 0.0054626464843750, 0.0025939941406250, +0.0057983398437500, 0.0025329589843750, 0.0053100585937500, 0.0027160644531250, +0.0049133300781250, 0.0028076171875000, 0.0052185058593750, 0.0027770996093750, +0.0042419433593750, 0.0032043457031250, 0.0042724609375000, 0.0031433105468750, +0.0042114257812500, 0.0033264160156250, 0.0036621093750000, 0.0037536621093750, +0.0038146972656250, 0.0035705566406250, 0.0039367675781250, 0.0038757324218750, +0.0037536621093750, 0.0039672851562500, 0.0039062500000000, 0.0037841796875000, +0.0041198730468750, 0.0038146972656250, 0.0038452148437500, 0.0039367675781250, +0.0040893554687500, 0.0036010742187500, 0.0039672851562500, 0.0036621093750000, +0.0038757324218750, 0.0036010742187500, 0.0038146972656250, 0.0033569335937500, +0.0036621093750000, 0.0034179687500000, 0.0040283203125000, 0.0032348632812500, +0.0036621093750000, 0.0031738281250000, 0.0040283203125000, 0.0032348632812500, +0.0046386718750000, 0.0031433105468750, 0.0042114257812500, 0.0031127929687500, +0.0052795410156250, 0.0033569335937500, 0.0052795410156250, 0.0032348632812500, +0.0052185058593750, 0.0033874511718750, 0.0058593750000000, 0.0036621093750000, +0.0056457519531250, 0.0034179687500000, 0.0052185058593750, 0.0038146972656250, +0.0055847167968750, 0.0038452148437500, 0.0050964355468750, 0.0037231445312500, +0.0044250488281250, 0.0038146972656250, 0.0047302246093750, 0.0038146972656250, +0.0038452148437500, 0.0035400390625000, 0.0037536621093750, 0.0035095214843750, +0.0036315917968750, 0.0033874511718750, 0.0030822753906250, 0.0031738281250000, +0.0033264160156250, 0.0032043457031250, 0.0028381347656250, 0.0028991699218750, +0.0028076171875000, 0.0029296875000000, 0.0027770996093750, 0.0028381347656250, +0.0026550292968750, 0.0025634765625000, 0.0027465820312500, 0.0027160644531250, +0.0026855468750000, 0.0023498535156250, 0.0025939941406250, 0.0022277832031250, +0.0028991699218750, 0.0023498535156250, 0.0031127929687500, 0.0022583007812500, +0.0028381347656250, 0.0021057128906250, 0.0037536621093750, 0.0027770996093750, +0.0036926269531250}, +{0.0031738281250000, 0.0030212402343750, 0.0032043457031250, 0.0028686523437500, +0.0032348632812500, 0.0029296875000000, 0.0030517578125000, 0.0031127929687500, +0.0029907226562500, 0.0029602050781250, 0.0031127929687500, 0.0031127929687500, +0.0029907226562500, 0.0030517578125000, 0.0030212402343750, 0.0029907226562500, +0.0030822753906250, 0.0030517578125000, 0.0029296875000000, 0.0029907226562500, +0.0031127929687500, 0.0029907226562500, 0.0030517578125000, 0.0030212402343750, +0.0030212402343750, 0.0029907226562500, 0.0031127929687500, 0.0028991699218750, +0.0030822753906250, 0.0028686523437500, 0.0027770996093750, 0.0028381347656250, +0.0030212402343750, 0.0027465820312500, 0.0027465820312500, 0.0027770996093750, +0.0023498535156250, 0.0028076171875000, 0.0027770996093750, 0.0026855468750000, +0.0020751953125000, 0.0028381347656250, 0.0021667480468750, 0.0027465820312500, +0.0021362304687500, 0.0026855468750000, 0.0017089843750000, 0.0027465820312500, +0.0019531250000000, 0.0025024414062500, 0.0020446777343750, 0.0025634765625000, +0.0017395019531250, 0.0024719238281250, 0.0021972656250000, 0.0025329589843750, +0.0026550292968750, 0.0025634765625000, 0.0022888183593750, 0.0025024414062500, +0.0033874511718750, 0.0027465820312500, 0.0032348632812500, 0.0027770996093750, +0.0034484863281250, 0.0029296875000000, 0.0042114257812500, 0.0032043457031250, +0.0039367675781250, 0.0032348632812500, 0.0039062500000000, 0.0032958984375000, +0.0042724609375000, 0.0034790039062500, 0.0038146972656250, 0.0034484863281250, +0.0032958984375000, 0.0034179687500000, 0.0036926269531250, 0.0035400390625000, +0.0024719238281250, 0.0032348632812500, 0.0025939941406250, 0.0033569335937500, +0.0023498535156250, 0.0032653808593750, 0.0014953613281250, 0.0029907226562500, +0.0018310546875000, 0.0032043457031250, 0.0014648437500000, 0.0030517578125000, +0.0013427734375000, 0.0030517578125000, 0.0014038085937500, 0.0031433105468750, +0.0013427734375000, 0.0030822753906250, 0.0013732910156250, 0.0030212402343750, +0.0011291503906250, 0.0032958984375000, 0.0011901855468750, 0.0031738281250000, +0.0010986328125000, 0.0033264160156250, 0.0007934570312500, 0.0035400390625000, +0.0009765625000000, 0.0033264160156250, 0.0011291503906250, 0.0036926269531250, +0.0009460449218750, 0.0036926269531250, 0.0014953613281250, 0.0036010742187500, +0.0019531250000000, 0.0037231445312500, 0.0016784667968750, 0.0036315917968750, +0.0029907226562500, 0.0034790039062500, 0.0029602050781250, 0.0035095214843750, +0.0031433105468750, 0.0034179687500000, 0.0039672851562500, 0.0032043457031250, +0.0037841796875000, 0.0032653808593750, 0.0042419433593750, 0.0030822753906250, +0.0043640136718750, 0.0030822753906250, 0.0043945312500000, 0.0029296875000000, +0.0046081542968750, 0.0027770996093750, 0.0045166015625000, 0.0027770996093750, +0.0044860839843750, 0.0026855468750000, 0.0045776367187500, 0.0024719238281250, +0.0045471191406250, 0.0027160644531250, 0.0044860839843750, 0.0028381347656250, +0.0045776367187500, 0.0026245117187500, 0.0041809082031250, 0.0033569335937500, +0.0045776367187500, 0.0032348632812500, 0.0041503906250000, 0.0033569335937500, +0.0034790039062500, 0.0039062500000000, 0.0040283203125000, 0.0037536621093750, +0.0030822753906250, 0.0039367675781250, 0.0030517578125000, 0.0041809082031250, +0.0032653808593750, 0.0039062500000000, 0.0029907226562500, 0.0037536621093750, +0.0030517578125000, 0.0039672851562500, 0.0036010742187500, 0.0035095214843750, +0.0034484863281250, 0.0034790039062500, 0.0035705566406250, 0.0036010742187500, +0.0041198730468750, 0.0035095214843750, 0.0040283203125000, 0.0034484863281250, +0.0036010742187500, 0.0036010742187500, 0.0039672851562500, 0.0036926269531250, +0.0036315917968750, 0.0035400390625000, 0.0031127929687500, 0.0036621093750000, +0.0036926269531250, 0.0038452148437500, 0.0023498535156250, 0.0034179687500000, +0.0025329589843750, 0.0035400390625000, 0.0023193359375000, 0.0034484863281250, +0.0012817382812500, 0.0031433105468750, 0.0016784667968750, 0.0034179687500000, +0.0011901855468750, 0.0029296875000000, 0.0008850097656250, 0.0030822753906250, +0.0012512207031250, 0.0029907226562500, 0.0013427734375000, 0.0026550292968750, +0.0010681152343750, 0.0030212402343750, 0.0021667480468750, 0.0031127929687500, +0.0019836425781250, 0.0030212402343750, 0.0022583007812500, 0.0035095214843750, +0.0031127929687500, 0.0039978027343750, 0.0026550292968750, 0.0039367675781250, +0.0030517578125000, 0.0046386718750000, 0.0031433105468750, 0.0047607421875000, +0.0030212402343750, 0.0047607421875000, 0.0030822753906250, 0.0051269531250000, +0.0030212402343750, 0.0050964355468750, 0.0030212402343750, 0.0048522949218750, +0.0030212402343750, 0.0049438476562500, 0.0029907226562500, 0.0048217773437500, +0.0029602050781250, 0.0044860839843750, 0.0028686523437500, 0.0046691894531250, +0.0031433105468750, 0.0044555664062500, 0.0028686523437500, 0.0043334960937500, +0.0029602050781250, 0.0044860839843750, 0.0032653808593750, 0.0045166015625000, +0.0030517578125000, 0.0044555664062500, 0.0030517578125000, 0.0043029785156250, +0.0031738281250000, 0.0044250488281250, 0.0028686523437500, 0.0042419433593750, +0.0026245117187500, 0.0039367675781250, 0.0027465820312500, 0.0040283203125000, +0.0021972656250000, 0.0037841796875000, 0.0021667480468750, 0.0036621093750000, +0.0021362304687500, 0.0038757324218750, 0.0018310546875000, 0.0038757324218750, +0.0018615722656250, 0.0036621093750000, 0.0018920898437500, 0.0042419433593750, +0.0017395019531250, 0.0042419433593750, 0.0018005371093750, 0.0043029785156250, +0.0018920898437500, 0.0046386718750000, 0.0016784667968750, 0.0045776367187500, +0.0017700195312500, 0.0042419433593750, 0.0017089843750000, 0.0043945312500000, +0.0017089843750000, 0.0039978027343750, 0.0017395019531250, 0.0033264160156250, +0.0016479492187500, 0.0036621093750000, 0.0020446777343750, 0.0029296875000000, +0.0017700195312500, 0.0027770996093750, 0.0020141601562500, 0.0029296875000000, +0.0024414062500000, 0.0027770996093750, 0.0019226074218750, 0.0027465820312500, +0.0026550292968750, 0.0029907226562500, 0.0024719238281250, 0.0030517578125000, +0.0024108886718750, 0.0030822753906250, 0.0027770996093750, 0.0031738281250000, +0.0024719238281250, 0.0032043457031250, 0.0024414062500000, 0.0031433105468750, +0.0025024414062500, 0.0031127929687500, 0.0023498535156250, 0.0031433105468750, +0.0021972656250000, 0.0030822753906250, 0.0021667480468750, 0.0029907226562500, +0.0021057128906250, 0.0032043457031250, 0.0020446777343750, 0.0030212402343750, +0.0021667480468750, 0.0031433105468750, 0.0022277832031250, 0.0033569335937500, +0.0021057128906250, 0.0031738281250000, 0.0025024414062500, 0.0034790039062500, +0.0024108886718750, 0.0036315917968750, 0.0024108886718750, 0.0034179687500000, +0.0025939941406250, 0.0034484863281250, 0.0024414062500000, 0.0036621093750000, +0.0024108886718750, 0.0029602050781250, 0.0023498535156250, 0.0032348632812500, +0.0022583007812500, 0.0028381347656250, 0.0021972656250000, 0.0021667480468750, +0.0021972656250000, 0.0026855468750000, 0.0021667480468750, 0.0015563964843750, +0.0022277832031250, 0.0016784667968750, 0.0022583007812500, 0.0015258789062500, +0.0023193359375000, 0.0008544921875000, 0.0025024414062500, 0.0012817382812500, +0.0024719238281250, 0.0007629394531250, 0.0027160644531250, 0.0007019042968750, +0.0028076171875000, 0.0009460449218750, 0.0027465820312500, 0.0007934570312500, +0.0029602050781250, 0.0008544921875000, 0.0028991699218750, 0.0011901855468750, +0.0030212402343750, 0.0011596679687500, 0.0030517578125000, 0.0014038085937500, +0.0030212402343750, 0.0016784667968750, 0.0031433105468750, 0.0016174316406250, +0.0030822753906250, 0.0020751953125000, 0.0032043457031250, 0.0021057128906250, +0.0032043457031250, 0.0022583007812500, 0.0031738281250000, 0.0025634765625000, +0.0033264160156250, 0.0025024414062500, 0.0031738281250000, 0.0029296875000000, +0.0033264160156250, 0.0028686523437500, 0.0033264160156250, 0.0029907226562500, +0.0032348632812500, 0.0033264160156250, 0.0035095214843750, 0.0031127929687500, +0.0033569335937500, 0.0033874511718750, 0.0034179687500000, 0.0033874511718750, +0.0035400390625000, 0.0032043457031250, 0.0034790039062500, 0.0032653808593750, +0.0035400390625000, 0.0032348632812500, 0.0035705566406250, 0.0030212402343750, +0.0036010742187500, 0.0029296875000000, 0.0036621093750000, 0.0029602050781250, +0.0036315917968750, 0.0028381347656250, 0.0036315917968750, 0.0026550292968750, +0.0036315917968750, 0.0028381347656250, 0.0036926269531250, 0.0027465820312500, +0.0036010742187500, 0.0028076171875000, 0.0035400390625000, 0.0030212402343750, +0.0036010742187500, 0.0027465820312500, 0.0033264160156250, 0.0028686523437500, +0.0033569335937500, 0.0029296875000000, 0.0032653808593750, 0.0026245117187500, +0.0030822753906250, 0.0024108886718750, 0.0031127929687500, 0.0026245117187500, +0.0031738281250000, 0.0018310546875000, 0.0029602050781250, 0.0019836425781250, +0.0030822753906250, 0.0016174316406250, 0.0032043457031250, 0.0009155273437500, +0.0030212402343750, 0.0012512207031250, 0.0032958984375000, 0.0007019042968750, +0.0032653808593750, 0.0005798339843750, 0.0032653808593750, 0.0008239746093750, +0.0034179687500000, 0.0008239746093750, 0.0033569335937500, 0.0007019042968750, +0.0033264160156250, 0.0014038085937500, 0.0034179687500000, 0.0013122558593750, +0.0034790039062500, 0.0015563964843750, 0.0034484863281250, 0.0021362304687500, +0.0034484863281250, 0.0018615722656250, 0.0036010742187500, 0.0024414062500000, +0.0035705566406250, 0.0024719238281250, 0.0036315917968750, 0.0025024414062500, +0.0038146972656250, 0.0027465820312500, 0.0036926269531250, 0.0025024414062500, +0.0036926269531250, 0.0029602050781250, 0.0038452148437500, 0.0028076171875000, +0.0035400390625000, 0.0030517578125000, 0.0033264160156250, 0.0035095214843750, +0.0035400390625000, 0.0032043457031250, 0.0028686523437500, 0.0040893554687500, +0.0028686523437500, 0.0039978027343750, 0.0027160644531250, 0.0041198730468750, +0.0022277832031250, 0.0046997070312500, 0.0023193359375000, 0.0043640136718750, +0.0024108886718750, 0.0046691894531250, 0.0023498535156250, 0.0047607421875000, +0.0025634765625000, 0.0046081542968750, 0.0029602050781250, 0.0045776367187500, +0.0029602050781250, 0.0047302246093750, 0.0031738281250000, 0.0042419433593750, +0.0033264160156250, 0.0043640136718750, 0.0032043457031250, 0.0042114257812500, +0.0031738281250000, 0.0037841796875000, 0.0034179687500000, 0.0039672851562500, +0.0029296875000000, 0.0037536621093750, 0.0031127929687500, 0.0036621093750000, +0.0031433105468750, 0.0037536621093750, 0.0028686523437500, 0.0038146972656250, +0.0031127929687500, 0.0036621093750000, 0.0031127929687500, 0.0040588378906250, +0.0030517578125000, 0.0040283203125000, 0.0032043457031250, 0.0039062500000000, +0.0035095214843750, 0.0042114257812500, 0.0041809082031250, 0.0040893554687500, +0.0048217773437500, 0.0041198730468750, 0.0048217773437500, 0.0042724609375000, +0.0047302246093750, 0.0039672851562500, 0.0047912597656250, 0.0037841796875000, +0.0048217773437500, 0.0039672851562500, 0.0044860839843750, 0.0033264160156250, +0.0044860839843750, 0.0033569335937500, 0.0044250488281250, 0.0032653808593750, +0.0041809082031250}, +{0.0034179687500000, 0.0016479492187500, 0.0035095214843750, 0.0018615722656250, +0.0033569335937500, 0.0016784667968750, 0.0035400390625000, 0.0023803710937500, +0.0034790039062500, 0.0022277832031250, 0.0034790039062500, 0.0025939941406250, +0.0036315917968750, 0.0031738281250000, 0.0034484863281250, 0.0028381347656250, +0.0036010742187500, 0.0033874511718750, 0.0036010742187500, 0.0034790039062500, +0.0035095214843750, 0.0033874511718750, 0.0035400390625000, 0.0035705566406250, +0.0035705566406250, 0.0035095214843750, 0.0033874511718750, 0.0034790039062500, +0.0033569335937500, 0.0034484863281250, 0.0032348632812500, 0.0033874511718750, +0.0031433105468750, 0.0032958984375000, 0.0031738281250000, 0.0032043457031250, +0.0030822753906250, 0.0032958984375000, 0.0030212402343750, 0.0031433105468750, +0.0030517578125000, 0.0032043457031250, 0.0031127929687500, 0.0033569335937500, +0.0030517578125000, 0.0032348632812500, 0.0032043457031250, 0.0032653808593750, +0.0031433105468750, 0.0033569335937500, 0.0030822753906250, 0.0031738281250000, +0.0031127929687500, 0.0032043457031250, 0.0030822753906250, 0.0031738281250000, +0.0031127929687500, 0.0025634765625000, 0.0030822753906250, 0.0027160644531250, +0.0030822753906250, 0.0024108886718750, 0.0031127929687500, 0.0017700195312500, +0.0031738281250000, 0.0020751953125000, 0.0033569335937500, 0.0016479492187500, +0.0033874511718750, 0.0014648437500000, 0.0034790039062500, 0.0017089843750000, +0.0036926269531250, 0.0017089843750000, 0.0036010742187500, 0.0015869140625000, +0.0035095214843750, 0.0021057128906250, 0.0037841796875000, 0.0020446777343750, +0.0034179687500000, 0.0020446777343750, 0.0030822753906250, 0.0024108886718750, +0.0035705566406250, 0.0022888183593750, 0.0028076171875000, 0.0023193359375000, +0.0029296875000000, 0.0024414062500000, 0.0029602050781250, 0.0021972656250000, +0.0025939941406250, 0.0020446777343750, 0.0027770996093750, 0.0022583007812500, +0.0029296875000000, 0.0017089843750000, 0.0028686523437500, 0.0018310546875000, +0.0031127929687500, 0.0018310546875000, 0.0034790039062500, 0.0014648437500000, +0.0035095214843750, 0.0016479492187500, 0.0035705566406250, 0.0018005371093750, +0.0040283203125000, 0.0016174316406250, 0.0037536621093750, 0.0018310546875000, +0.0035400390625000, 0.0021972656250000, 0.0039978027343750, 0.0019531250000000, +0.0032958984375000, 0.0025939941406250, 0.0032653808593750, 0.0024414062500000, +0.0033264160156250, 0.0028076171875000, 0.0029907226562500, 0.0033874511718750, +0.0031433105468750, 0.0029296875000000, 0.0032348632812500, 0.0040588378906250, +0.0031127929687500, 0.0039062500000000, 0.0032958984375000, 0.0039062500000000, +0.0035400390625000, 0.0046691894531250, 0.0034179687500000, 0.0044250488281250, +0.0038146972656250, 0.0043029785156250, 0.0037841796875000, 0.0044250488281250, +0.0039062500000000, 0.0043029785156250, 0.0044860839843750, 0.0040283203125000, +0.0046997070312500, 0.0025329589843750, 0.0042419433593750, 0.0036621093750000, +0.0044250488281250, 0.0031127929687500, 0.0043640136718750, 0.0035400390625000, +0.0040893554687500, 0.0043029785156250, 0.0040893554687500, 0.0038146972656250, +0.0040893554687500, 0.0044860839843750, 0.0041198730468750, 0.0045166015625000, +0.0039367675781250, 0.0043334960937500, 0.0039367675781250, 0.0045166015625000, +0.0041198730468750, 0.0045471191406250, 0.0035400390625000, 0.0042419433593750, +0.0036926269531250, 0.0042114257812500, 0.0036926269531250, 0.0042419433593750, +0.0032348632812500, 0.0041503906250000, 0.0035705566406250, 0.0040588378906250, +0.0037536621093750, 0.0041198730468750, 0.0034179687500000, 0.0043640136718750, +0.0040588378906250, 0.0038757324218750, 0.0047302246093750, 0.0036010742187500, +0.0043334960937500, 0.0040283203125000, 0.0054626464843750, 0.0024719238281250, +0.0057678222656250, 0.0028686523437500, 0.0055541992187500, 0.0024719238281250, +0.0060119628906250, 0.0010681152343750, 0.0062866210937500, 0.0017700195312500, +0.0056762695312500, 0.0012817382812500, 0.0060729980468750, 0.0007019042968750, +0.0057067871093750, 0.0015258789062500, 0.0049743652343750, 0.0019531250000000, +0.0054931640625000, 0.0013732910156250, 0.0041809082031250, 0.0031738281250000, +0.0044555664062500, 0.0029602050781250, 0.0038757324218750, 0.0032653808593750, +0.0026855468750000, 0.0045471191406250, 0.0033569335937500, 0.0039367675781250, +0.0016784667968750, 0.0042724609375000, 0.0017395019531250, 0.0047912597656250, +0.0016479492187500, 0.0040283203125000, 0.0006103515625000, 0.0035095214843750, +0.0010681152343750, 0.0041809082031250, 0.0009765625000000, 0.0025329589843750, +0.0007324218750000, 0.0025939941406250, 0.0009460449218750, 0.0026550292968750, +0.0012817382812500, 0.0017700195312500, 0.0011901855468750, 0.0019836425781250, +0.0015563964843750, 0.0024108886718750, 0.0016784667968750, 0.0020751953125000, +0.0014038085937500, 0.0026550292968750, 0.0015258789062500, 0.0033569335937500, +0.0017700195312500, 0.0028686523437500, 0.0006408691406250, 0.0038452148437500, +0.0009765625000000, 0.0037841796875000, 0.0006713867187500, 0.0038452148437500, +-0.0003356933593750, 0.0043945312500000, 0.0003051757812500, 0.0041503906250000, +-0.0003662109375000, 0.0042114257812500, -0.0005798339843750, 0.0043029785156250, +-0.0002136230468750, 0.0040283203125000, -0.0002746582031250, 0.0038146972656250, +-0.0005187988281250, 0.0038452148437500, 0.0002746582031250, 0.0036315917968750, +0.0001220703125000, 0.0034484863281250, 0.0003662109375000, 0.0035705566406250, +0.0009765625000000, 0.0035705566406250, 0.0007324218750000, 0.0033569335937500, +0.0012512207031250, 0.0037536621093750, 0.0014038085937500, 0.0036926269531250, +0.0013427734375000, 0.0037231445312500, 0.0015258789062500, 0.0039978027343750, +0.0014953613281250, 0.0038146972656250, 0.0013732910156250, 0.0039062500000000, +0.0013427734375000, 0.0039672851562500, 0.0013427734375000, 0.0037841796875000, +0.0012512207031250, 0.0038146972656250, 0.0011291503906250, 0.0039062500000000, +0.0013427734375000, 0.0034484863281250, 0.0011291503906250, 0.0036315917968750, +0.0012207031250000, 0.0034484863281250, 0.0015258789062500, 0.0030212402343750, +0.0012207031250000, 0.0032653808593750, 0.0014038085937500, 0.0028686523437500, +0.0014648437500000, 0.0028076171875000, 0.0011901855468750, 0.0028381347656250, +0.0010681152343750, 0.0026245117187500, 0.0012512207031250, 0.0025939941406250, +0.0008544921875000, 0.0025634765625000, 0.0008239746093750, 0.0025024414062500, +0.0009155273437500, 0.0024719238281250, 0.0008239746093750, 0.0025024414062500, +0.0007934570312500, 0.0024719238281250, 0.0011596679687500, 0.0024719238281250, +0.0010681152343750, 0.0025329589843750, 0.0012512207031250, 0.0025024414062500, +0.0016174316406250, 0.0024108886718750, 0.0014648437500000, 0.0024719238281250, +0.0021667480468750, 0.0024414062500000, 0.0019531250000000, 0.0024108886718750, +0.0024108886718750, 0.0024414062500000, 0.0031127929687500, 0.0025024414062500, +0.0026855468750000, 0.0023498535156250, 0.0039062500000000, 0.0025634765625000, +0.0037536621093750, 0.0025634765625000, 0.0040588378906250, 0.0025634765625000, +0.0050048828125000, 0.0025939941406250, 0.0046081542968750, 0.0025634765625000, +0.0054931640625000, 0.0025939941406250, 0.0054321289062500, 0.0025634765625000, +0.0054626464843750, 0.0025634765625000, 0.0058898925781250, 0.0025939941406250, +0.0056762695312500, 0.0025939941406250, 0.0056152343750000, 0.0027770996093750, +0.0057373046875000, 0.0026855468750000, 0.0053405761718750, 0.0027465820312500, +0.0050354003906250, 0.0029602050781250, 0.0051574707031250, 0.0028991699218750, +0.0042114257812500, 0.0029602050781250, 0.0044250488281250, 0.0030517578125000, +0.0038757324218750, 0.0031127929687500, 0.0030212402343750, 0.0031433105468750, +0.0036010742187500, 0.0031433105468750, 0.0022277832031250, 0.0030212402343750, +0.0024414062500000, 0.0030517578125000, 0.0022277832031250, 0.0029602050781250, +0.0014038085937500, 0.0028076171875000, 0.0018920898437500, 0.0029296875000000, +0.0012207031250000, 0.0026245117187500, 0.0011901855468750, 0.0026855468750000, +0.0013427734375000, 0.0026550292968750, 0.0011291503906250, 0.0024719238281250, +0.0013732910156250, 0.0024719238281250, 0.0017700195312500, 0.0026550292968750, +0.0016784667968750, 0.0025329589843750, 0.0020751953125000, 0.0026550292968750, +0.0026855468750000, 0.0028991699218750, 0.0025634765625000, 0.0026855468750000, +0.0029602050781250, 0.0030212402343750, 0.0033569335937500, 0.0030212402343750, +0.0030212402343750, 0.0029907226562500, 0.0028991699218750, 0.0031433105468750, +0.0033874511718750, 0.0031433105468750, 0.0022583007812500, 0.0029907226562500, +0.0024414062500000, 0.0030517578125000, 0.0022888183593750, 0.0029907226562500, +0.0015563964843750, 0.0027770996093750, 0.0019226074218750, 0.0029296875000000, +0.0018005371093750, 0.0026550292968750, 0.0015563964843750, 0.0028381347656250, +0.0019226074218750, 0.0027770996093750, 0.0021972656250000, 0.0025634765625000, +0.0019226074218750, 0.0028076171875000, 0.0026245117187500, 0.0026550292968750, +0.0026245117187500, 0.0026550292968750, 0.0025329589843750, 0.0027770996093750, +0.0028686523437500, 0.0026855468750000, 0.0028381347656250, 0.0026855468750000, +0.0026550292968750, 0.0031127929687500, 0.0027770996093750, 0.0029907226562500, +0.0026855468750000, 0.0032958984375000, 0.0024414062500000, 0.0037841796875000, +0.0026855468750000, 0.0033874511718750, 0.0024719238281250, 0.0039062500000000, +0.0025024414062500, 0.0039978027343750, 0.0025939941406250, 0.0038452148437500, +0.0025634765625000, 0.0039367675781250, 0.0025024414062500, 0.0039367675781250, +0.0021667480468750, 0.0038452148437500, 0.0021362304687500, 0.0038146972656250, +0.0020751953125000, 0.0039672851562500, 0.0017395019531250, 0.0040283203125000, +0.0017395019531250, 0.0039062500000000, 0.0020751953125000, 0.0041198730468750, +0.0016784667968750, 0.0039978027343750, 0.0022888183593750, 0.0040283203125000, +0.0029602050781250, 0.0042114257812500, 0.0024108886718750, 0.0040893554687500, +0.0041198730468750, 0.0040588378906250, 0.0039062500000000, 0.0041503906250000, +0.0041809082031250, 0.0040283203125000, 0.0058593750000000, 0.0038757324218750, +0.0058593750000000, 0.0039062500000000, 0.0063171386718750, 0.0039062500000000, +0.0063476562500000, 0.0038146972656250, 0.0061645507812500, 0.0039367675781250, +0.0063171386718750, 0.0040893554687500, 0.0063171386718750, 0.0039978027343750, +0.0057067871093750, 0.0045776367187500, 0.0059204101562500, 0.0045166015625000, +0.0055236816406250, 0.0047607421875000, 0.0050354003906250, 0.0053710937500000, +0.0054321289062500, 0.0050964355468750, 0.0049133300781250, 0.0055236816406250, +0.0047302246093750, 0.0057373046875000, 0.0048522949218750, 0.0054321289062500, +0.0047607421875000, 0.0053710937500000, 0.0046386718750000, 0.0055541992187500, +0.0043334960937500, 0.0046081542968750, 0.0044250488281250, 0.0047302246093750, +0.0039978027343750, 0.0045471191406250, 0.0035705566406250, 0.0038452148437500, +0.0038452148437500, 0.0040588378906250, 0.0030212402343750, 0.0037841796875000, +0.0029907226562500, 0.0038146972656250, 0.0029602050781250, 0.0037841796875000, +0.0025329589843750, 0.0036621093750000, 0.0026245117187500, 0.0039062500000000, +0.0026855468750000}, +{0.0016784667968750, 0.0023803710937500, 0.0015563964843750, 0.0023803710937500, +0.0016479492187500, 0.0023193359375000, 0.0015258789062500, 0.0025024414062500, +0.0013427734375000, 0.0026245117187500, 0.0015563964843750, 0.0025939941406250, +0.0010681152343750, 0.0028686523437500, 0.0011596679687500, 0.0028991699218750, +0.0011596679687500, 0.0029296875000000, 0.0008239746093750, 0.0031433105468750, +0.0010681152343750, 0.0030822753906250, 0.0012207031250000, 0.0030822753906250, +0.0010986328125000, 0.0031738281250000, 0.0015258789062500, 0.0031127929687500, +0.0019836425781250, 0.0029907226562500, 0.0016784667968750, 0.0030822753906250, +0.0022888183593750, 0.0029602050781250, 0.0024108886718750, 0.0029296875000000, +0.0020751953125000, 0.0028381347656250, 0.0021972656250000, 0.0027160644531250, +0.0022277832031250, 0.0027465820312500, 0.0013427734375000, 0.0026245117187500, +0.0015258789062500, 0.0026245117187500, 0.0012817382812500, 0.0027465820312500, +0.0005187988281250, 0.0026550292968750, 0.0007629394531250, 0.0025939941406250, +0.0006103515625000, 0.0030212402343750, 0.0003356933593750, 0.0027770996093750, +0.0006103515625000, 0.0030517578125000, 0.0009765625000000, 0.0035705566406250, +0.0007019042968750, 0.0031738281250000, 0.0014038085937500, 0.0038146972656250, +0.0015258789062500, 0.0038452148437500, 0.0016174316406250, 0.0037536621093750, +0.0020751953125000, 0.0039672851562500, 0.0021057128906250, 0.0039062500000000, +0.0022277832031250, 0.0037841796875000, 0.0023498535156250, 0.0037536621093750, +0.0027160644531250, 0.0037536621093750, 0.0029296875000000, 0.0037231445312500, +0.0028991699218750, 0.0037231445312500, 0.0039367675781250, 0.0036926269531250, +0.0038757324218750, 0.0036926269531250, 0.0039978027343750, 0.0036315917968750, +0.0047302246093750, 0.0036315917968750, 0.0044555664062500, 0.0036926269531250, +0.0042114257812500, 0.0036315917968750, 0.0045166015625000, 0.0036010742187500, +0.0038452148437500, 0.0036010742187500, 0.0031127929687500, 0.0036621093750000, +0.0035095214843750, 0.0037841796875000, 0.0024719238281250, 0.0037231445312500, +0.0022583007812500, 0.0038757324218750, 0.0025024414062500, 0.0039367675781250, +0.0022277832031250, 0.0039062500000000, 0.0024108886718750, 0.0042114257812500, +0.0035705566406250, 0.0042724609375000, 0.0031738281250000, 0.0042724609375000, +0.0035705566406250, 0.0044250488281250, 0.0046386718750000, 0.0046997070312500, +0.0042114257812500, 0.0047607421875000, 0.0053100585937500, 0.0048828125000000, +0.0053710937500000, 0.0051879882812500, 0.0052185058593750, 0.0048828125000000, +0.0058288574218750, 0.0046997070312500, 0.0056457519531250, 0.0051879882812500, +0.0052795410156250, 0.0039978027343750, 0.0055847167968750, 0.0042724609375000, +0.0053100585937500, 0.0041198730468750, 0.0046691894531250, 0.0032653808593750, +0.0048828125000000, 0.0037841796875000, 0.0044555664062500, 0.0033264160156250, +0.0042419433593750, 0.0032348632812500, 0.0043334960937500, 0.0032653808593750, +0.0041809082031250, 0.0032348632812500, 0.0038146972656250, 0.0033569335937500, +0.0040283203125000, 0.0028381347656250, 0.0039978027343750, 0.0031738281250000, +0.0037231445312500, 0.0028991699218750, 0.0036621093750000, 0.0023193359375000, +0.0036010742187500, 0.0028381347656250, 0.0032958984375000, 0.0022583007812500, +0.0032043457031250, 0.0022583007812500, 0.0032043457031250, 0.0024719238281250, +0.0029907226562500, 0.0022888183593750, 0.0030517578125000, 0.0025329589843750, +0.0032653808593750, 0.0026855468750000, 0.0029602050781250, 0.0026855468750000, +0.0032653808593750, 0.0028686523437500, 0.0036621093750000, 0.0031738281250000, +0.0032653808593750, 0.0031433105468750, 0.0038757324218750, 0.0032348632812500, +0.0038146972656250, 0.0034790039062500, 0.0037231445312500, 0.0033264160156250, +0.0039672851562500, 0.0032653808593750, 0.0039672851562500, 0.0036010742187500, +0.0036010742187500, 0.0032348632812500, 0.0037536621093750, 0.0034179687500000, +0.0036010742187500, 0.0035095214843750, 0.0031738281250000, 0.0033569335937500, +0.0033569335937500, 0.0036315917968750, 0.0032958984375000, 0.0036010742187500, +0.0031738281250000, 0.0036926269531250, 0.0033569335937500, 0.0038452148437500, +0.0036010742187500, 0.0039062500000000, 0.0035095214843750, 0.0039367675781250, +0.0038452148437500, 0.0039978027343750, 0.0039367675781250, 0.0041198730468750, +0.0038757324218750, 0.0042724609375000, 0.0039978027343750, 0.0043945312500000, +0.0042114257812500, 0.0044860839843750, 0.0036010742187500, 0.0045776367187500, +0.0039367675781250, 0.0048522949218750, 0.0037231445312500, 0.0047302246093750, +0.0031738281250000, 0.0046691894531250, 0.0036315917968750, 0.0049743652343750, +0.0027770996093750, 0.0040893554687500, 0.0029907226562500, 0.0044250488281250, +0.0029602050781250, 0.0040893554687500, 0.0023498535156250, 0.0032653808593750, +0.0028686523437500, 0.0037536621093750, 0.0024108886718750, 0.0028381347656250, +0.0025329589843750, 0.0028991699218750, 0.0026550292968750, 0.0028991699218750, +0.0024108886718750, 0.0024414062500000, 0.0026245117187500, 0.0026855468750000, +0.0025939941406250, 0.0025634765625000, 0.0025939941406250, 0.0025329589843750, +0.0027465820312500, 0.0026245117187500, 0.0028076171875000, 0.0026550292968750, +0.0027465820312500, 0.0026245117187500, 0.0031738281250000, 0.0025634765625000, +0.0030822753906250, 0.0026855468750000, 0.0031738281250000, 0.0024719238281250, +0.0035095214843750, 0.0022583007812500, 0.0032958984375000, 0.0024108886718750, +0.0036010742187500, 0.0017700195312500, 0.0036010742187500, 0.0018615722656250, +0.0036010742187500, 0.0017089843750000, 0.0037536621093750, 0.0012207031250000, +0.0036010742187500, 0.0014038085937500, 0.0036926269531250, 0.0012207031250000, +0.0036926269531250, 0.0010986328125000, 0.0036926269531250, 0.0012512207031250, +0.0037231445312500, 0.0013427734375000, 0.0036926269531250, 0.0011901855468750, +0.0036621093750000, 0.0019531250000000, 0.0036621093750000, 0.0017700195312500, +0.0036010742187500, 0.0021057128906250, 0.0035095214843750, 0.0028076171875000, +0.0034790039062500, 0.0023498535156250, 0.0034179687500000, 0.0030212402343750, +0.0032958984375000, 0.0031127929687500, 0.0032653808593750, 0.0028381347656250, +0.0031738281250000, 0.0031127929687500, 0.0031127929687500, 0.0032653808593750, +0.0031433105468750, 0.0025634765625000, 0.0031127929687500, 0.0029907226562500, +0.0031127929687500, 0.0027465820312500, 0.0031738281250000, 0.0020446777343750, +0.0030822753906250, 0.0025939941406250, 0.0032043457031250, 0.0016174316406250, +0.0032043457031250, 0.0018005371093750, 0.0031433105468750, 0.0016479492187500, +0.0031433105468750, 0.0010375976562500, 0.0031738281250000, 0.0014648437500000, +0.0031738281250000, 0.0010070800781250, 0.0031738281250000, 0.0009460449218750, +0.0031127929687500, 0.0011291503906250, 0.0030517578125000, 0.0010070800781250, +0.0031433105468750, 0.0010375976562500, 0.0029602050781250, 0.0013732910156250, +0.0029602050781250, 0.0012512207031250, 0.0029907226562500, 0.0015258789062500, +0.0029296875000000, 0.0018920898437500, 0.0029907226562500, 0.0016784667968750, +0.0028991699218750, 0.0023193359375000, 0.0029602050781250, 0.0022888183593750, +0.0029907226562500, 0.0024414062500000, 0.0029296875000000, 0.0028991699218750, +0.0030212402343750, 0.0026245117187500, 0.0030212402343750, 0.0030212402343750, +0.0030212402343750, 0.0030517578125000, 0.0032043457031250, 0.0029907226562500, +0.0032958984375000, 0.0031433105468750, 0.0032653808593750, 0.0031127929687500, +0.0034484863281250, 0.0029602050781250, 0.0035705566406250, 0.0030517578125000, +0.0035705566406250, 0.0028076171875000, 0.0036315917968750, 0.0025634765625000, +0.0037841796875000, 0.0026855468750000, 0.0035705566406250, 0.0021972656250000, +0.0037841796875000, 0.0021667480468750, 0.0036315917968750, 0.0021972656250000, +0.0032958984375000, 0.0018920898437500, 0.0036315917968750, 0.0019226074218750, +0.0030212402343750, 0.0021362304687500, 0.0030517578125000, 0.0021362304687500, +0.0032043457031250, 0.0020751953125000, 0.0028686523437500, 0.0022888183593750, +0.0029296875000000, 0.0023498535156250, 0.0033264160156250, 0.0017395019531250, +0.0031433105468750, 0.0021057128906250, 0.0034179687500000, 0.0017395019531250, +0.0039062500000000, 0.0009765625000000, 0.0036010742187500, 0.0015563964843750, +0.0039062500000000, 0.0006103515625000, 0.0039978027343750, 0.0006408691406250, +0.0038452148437500, 0.0009460449218750, 0.0038452148437500, 0.0004882812500000, +0.0038452148437500, 0.0004882812500000, 0.0038146972656250, 0.0017700195312500, +0.0037536621093750, 0.0012817382812500, 0.0039978027343750, 0.0020751953125000, +0.0041503906250000, 0.0034179687500000, 0.0040283203125000, 0.0026550292968750, +0.0046691894531250, 0.0043640136718750, 0.0044860839843750, 0.0044250488281250, +0.0045471191406250, 0.0045776367187500, 0.0050659179687500, 0.0054931640625000, +0.0047607421875000, 0.0051574707031250, 0.0050354003906250, 0.0056457519531250, +0.0051269531250000, 0.0057373046875000, 0.0049438476562500, 0.0057067871093750, +0.0049438476562500, 0.0061035156250000, 0.0050354003906250, 0.0060424804687500, +0.0046691894531250, 0.0053710937500000, 0.0047607421875000, 0.0059814453125000, +0.0046997070312500, 0.0050354003906250, 0.0043640136718750, 0.0038757324218750, +0.0044250488281250, 0.0049438476562500, 0.0042724609375000, 0.0024414062500000, +0.0041503906250000, 0.0024719238281250, 0.0040893554687500, 0.0026245117187500, +0.0039672851562500, 0.0007629394531250, 0.0039367675781250, 0.0065002441406250, +0.0035400390625000, 0.0049438476562500, 0.0035705566406250, 0.0057067871093750, +0.0037536621093750, 0.0048522949218750, 0.0036621093750000, 0.0036926269531250, +0.0036621093750000, 0.0043945312500000, 0.0046386718750000, 0.0028991699218750, +0.0045166015625000, 0.0031433105468750, 0.0049133300781250, 0.0028686523437500, +0.0058593750000000, 0.0017089843750000, 0.0056152343750000, 0.0022277832031250, +0.0057067871093750, 0.0018005371093750, 0.0063476562500000, 0.0014343261718750, +0.0057678222656250, 0.0021362304687500, 0.0052490234375000, 0.0025024414062500, +0.0059814453125000, 0.0020751953125000, 0.0041503906250000, 0.0035400390625000, +0.0046081542968750, 0.0035095214843750, 0.0041198730468750, 0.0035705566406250, +0.0027160644531250, 0.0043945312500000, 0.0036315917968750, 0.0041809082031250, +0.0022583007812500, 0.0044250488281250, 0.0022888183593750, 0.0045166015625000, +0.0023193359375000, 0.0046386718750000, 0.0015869140625000, 0.0048522949218750, +0.0019836425781250, 0.0047607421875000, 0.0018005371093750, 0.0050354003906250, +0.0014648437500000, 0.0051879882812500, 0.0019836425781250, 0.0049133300781250, +0.0023498535156250, 0.0048522949218750, 0.0019531250000000, 0.0050964355468750, +0.0034790039062500, 0.0042419433593750, 0.0032043457031250, 0.0044555664062500, +0.0035400390625000, 0.0041503906250000, 0.0047302246093750, 0.0033264160156250, +0.0041503906250000, 0.0037231445312500, 0.0046081542968750, 0.0028381347656250, +0.0049743652343750, 0.0026855468750000, 0.0043640136718750, 0.0028381347656250, +0.0040283203125000, 0.0024719238281250, 0.0044860839843750, 0.0023803710937500, +0.0032348632812500, 0.0031738281250000, 0.0033569335937500, 0.0029296875000000, +0.0033264160156250}, +{0.0034484863281250, 0.0024719238281250, 0.0035705566406250, 0.0026550292968750, +0.0039367675781250, 0.0025024414062500, 0.0036621093750000, 0.0024414062500000, +0.0039367675781250, 0.0030517578125000, 0.0039062500000000, 0.0029907226562500, +0.0038757324218750, 0.0030822753906250, 0.0039062500000000, 0.0035705566406250, +0.0037536621093750, 0.0034790039062500, 0.0039367675781250, 0.0033569335937500, +0.0037536621093750, 0.0037231445312500, 0.0039062500000000, 0.0032043457031250, +0.0041809082031250, 0.0027160644531250, 0.0039062500000000, 0.0032653808593750, +0.0046997070312500, 0.0016174316406250, 0.0046691894531250, 0.0018310546875000, +0.0048217773437500, 0.0016784667968750, 0.0053100585937500, 0.0005798339843750, +0.0049743652343750, 0.0010986328125000, 0.0052795410156250, 0.0007629394531250, +0.0052795410156250, 0.0005493164062500, 0.0050659179687500, 0.0009460449218750, +0.0051574707031250, 0.0011596679687500, 0.0050964355468750, 0.0009765625000000, +0.0049438476562500, 0.0016174316406250, 0.0050048828125000, 0.0015563964843750, +0.0050048828125000, 0.0018310546875000, 0.0048828125000000, 0.0022583007812500, +0.0049133300781250, 0.0020141601562500, 0.0046997070312500, 0.0033264160156250, +0.0046997070312500, 0.0028991699218750, 0.0045776367187500, 0.0037536621093750, +0.0044250488281250, 0.0052795410156250, 0.0045166015625000, 0.0043640136718750, +0.0042724609375000, 0.0060119628906250, 0.0043029785156250, 0.0063781738281250, +0.0041503906250000, 0.0058898925781250, 0.0036621093750000, 0.0062255859375000, +0.0043334960937500, 0.0019531250000000, 0.0054321289062500, 0.0051269531250000, +0.0050048828125000, 0.0041503906250000, 0.0051574707031250, 0.0048217773437500, +0.0059204101562500, 0.0063476562500000, 0.0057678222656250, 0.0056457519531250, +0.0051879882812500, 0.0061035156250000, 0.0058898925781250, 0.0062255859375000, +0.0050048828125000, 0.0058288574218750, 0.0039062500000000, 0.0058898925781250, +0.0049133300781250, 0.0059509277343750, 0.0028991699218750, 0.0046081542968750, +0.0030212402343750, 0.0051574707031250, 0.0029296875000000, 0.0042724609375000, +0.0018005371093750, 0.0026245117187500, 0.0024414062500000, 0.0036315917968750, +0.0018310546875000, 0.0021667480468750, 0.0017395019531250, 0.0018310546875000, +0.0019836425781250, 0.0024414062500000, 0.0018310546875000, 0.0021667480468750, +0.0019226074218750, 0.0019531250000000, 0.0023193359375000, 0.0030517578125000, +0.0021362304687500, 0.0028381347656250, 0.0025939941406250, 0.0029907226562500, +0.0031127929687500, 0.0036926269531250, 0.0026855468750000, 0.0034179687500000, +0.0038757324218750, 0.0038757324218750, 0.0037841796875000, 0.0037841796875000, +0.0037841796875000, 0.0039062500000000, 0.0044860839843750, 0.0041809082031250, +0.0042419433593750, 0.0038757324218750, 0.0039367675781250, 0.0043334960937500, +0.0043029785156250, 0.0043029785156250, 0.0037536621093750, 0.0042724609375000, +0.0030517578125000, 0.0045471191406250, 0.0035705566406250, 0.0044555664062500, +0.0026245117187500, 0.0043029785156250, 0.0024414062500000, 0.0045776367187500, +0.0026855468750000, 0.0040588378906250, 0.0023803710937500, 0.0036621093750000, +0.0023498535156250, 0.0040588378906250, 0.0031127929687500, 0.0026245117187500, +0.0028381347656250, 0.0029296875000000, 0.0031433105468750, 0.0026245117187500, +0.0038452148437500, 0.0014953613281250, 0.0034484863281250, 0.0021972656250000, +0.0042114257812500, 0.0017395019531250, 0.0042419433593750, 0.0015563964843750, +0.0041198730468750, 0.0021972656250000, 0.0043945312500000, 0.0024108886718750, +0.0043640136718750, 0.0020751953125000, 0.0041503906250000, 0.0030212402343750, +0.0041503906250000, 0.0030822753906250, 0.0040893554687500, 0.0030212402343750, +0.0039978027343750, 0.0034790039062500, 0.0040893554687500, 0.0035095214843750, +0.0039672851562500, 0.0028686523437500, 0.0040283203125000, 0.0030517578125000, +0.0039672851562500, 0.0027465820312500, 0.0039367675781250, 0.0020751953125000, +0.0041503906250000, 0.0022888183593750, 0.0037231445312500, 0.0017395019531250, +0.0038452148437500, 0.0015563964843750, 0.0037841796875000, 0.0017395019531250, +0.0034179687500000, 0.0016174316406250, 0.0035705566406250, 0.0014343261718750, +0.0035095214843750, 0.0021057128906250, 0.0032653808593750, 0.0019531250000000, +0.0035400390625000, 0.0022277832031250, 0.0037231445312500, 0.0028686523437500, +0.0033569335937500, 0.0025329589843750, 0.0042419433593750, 0.0030212402343750, +0.0038757324218750, 0.0030212402343750, 0.0043029785156250, 0.0029296875000000, +0.0050659179687500, 0.0031127929687500, 0.0044555664062500, 0.0030212402343750, +0.0057373046875000, 0.0029907226562500, 0.0055847167968750, 0.0030822753906250, +0.0056762695312500, 0.0030212402343750, 0.0064697265625000, 0.0029602050781250, +0.0060119628906250, 0.0031127929687500, 0.0065612792968750, 0.0030517578125000, +0.0066528320312500, 0.0030517578125000, 0.0065307617187500, 0.0031127929687500, +0.0067443847656250, 0.0031127929687500, 0.0067749023437500, 0.0030517578125000, +0.0065002441406250, 0.0032958984375000, 0.0067443847656250, 0.0032348632812500, +0.0065307617187500, 0.0031433105468750, 0.0062561035156250, 0.0032043457031250, +0.0066833496093750, 0.0031738281250000, 0.0059509277343750, 0.0030517578125000, +0.0061950683593750, 0.0030822753906250, 0.0059204101562500, 0.0030212402343750, +0.0053100585937500, 0.0029296875000000, 0.0056762695312500, 0.0029296875000000, +0.0046997070312500, 0.0029296875000000, 0.0048217773437500, 0.0028381347656250, +0.0043945312500000, 0.0028991699218750, 0.0035095214843750, 0.0029602050781250, +0.0039672851562500, 0.0028991699218750, 0.0028381347656250, 0.0029907226562500, +0.0028686523437500, 0.0029602050781250, 0.0025024414062500, 0.0028991699218750, +0.0017089843750000, 0.0029602050781250, 0.0019836425781250, 0.0029907226562500, +0.0010986328125000, 0.0027770996093750, 0.0011291503906250, 0.0028381347656250, +0.0008850097656250, 0.0027770996093750, 0.0003356933593750, 0.0026550292968750, +0.0006103515625000, 0.0028076171875000, 0.0000915527343750, 0.0026245117187500, +0.0001525878906250, 0.0025634765625000, 0.0002441406250000, 0.0026550292968750, +0.0000305175781250, 0.0025634765625000, 0.0000610351562500, 0.0025634765625000, +0.0002136230468750, 0.0026245117187500, 0.0001220703125000, 0.0026245117187500, +0.0002136230468750, 0.0027465820312500, 0.0003967285156250, 0.0028686523437500, +0.0002136230468750, 0.0027160644531250, 0.0004272460937500, 0.0030517578125000, +0.0004272460937500, 0.0031433105468750, 0.0004272460937500, 0.0031127929687500, +0.0005493164062500, 0.0031738281250000, 0.0004577636718750, 0.0031738281250000, +0.0006408691406250, 0.0032043457031250, 0.0006713867187500, 0.0032043457031250, +0.0007019042968750, 0.0031738281250000, 0.0007324218750000, 0.0031433105468750, +0.0006713867187500, 0.0031127929687500, 0.0010375976562500, 0.0029602050781250, +0.0008850097656250, 0.0030822753906250, 0.0010070800781250, 0.0028991699218750, +0.0012817382812500, 0.0027465820312500, 0.0010375976562500, 0.0028991699218750, +0.0016479492187500, 0.0025329589843750, 0.0015258789062500, 0.0026550292968750, +0.0016784667968750, 0.0025634765625000, 0.0020446777343750, 0.0022277832031250, +0.0018310546875000, 0.0025329589843750, 0.0021667480468750, 0.0024414062500000, +0.0021057128906250, 0.0023803710937500, 0.0021972656250000, 0.0026855468750000, +0.0024108886718750, 0.0029602050781250, 0.0021972656250000, 0.0028686523437500, +0.0028076171875000, 0.0032958984375000, 0.0026245117187500, 0.0034179687500000, +0.0028381347656250, 0.0034179687500000, 0.0033569335937500, 0.0035705566406250, +0.0030517578125000, 0.0035705566406250, 0.0036010742187500, 0.0034790039062500, +0.0037231445312500, 0.0034790039062500, 0.0036926269531250, 0.0034484863281250, +0.0039062500000000, 0.0032958984375000, 0.0038146972656250, 0.0032653808593750, +0.0036010742187500, 0.0032653808593750, 0.0036010742187500, 0.0032043457031250, +0.0036010742187500, 0.0031433105468750, 0.0034179687500000, 0.0031433105468750, +0.0033874511718750, 0.0030517578125000, 0.0034179687500000, 0.0030212402343750, +0.0033264160156250, 0.0029907226562500, 0.0032958984375000, 0.0030822753906250, +0.0034484863281250, 0.0031127929687500, 0.0033569335937500, 0.0029602050781250, +0.0027465820312500, 0.0033874511718750, 0.0030822753906250, 0.0032958984375000, +0.0025329589843750, 0.0034790039062500, 0.0016479492187500, 0.0039062500000000, +0.0021057128906250, 0.0036621093750000, 0.0009155273437500, 0.0041809082031250, +0.0008239746093750, 0.0042419433593750, 0.0009765625000000, 0.0042419433593750, +0.0005187988281250, 0.0045166015625000, 0.0006713867187500, 0.0044250488281250, +0.0013122558593750, 0.0043334960937500, 0.0011901855468750, 0.0044555664062500, +0.0016174316406250, 0.0041809082031250, 0.0025329589843750, 0.0039062500000000, +0.0028076171875000, 0.0039367675781250, 0.0032958984375000, 0.0033264160156250, +0.0033569335937500, 0.0035095214843750, 0.0032348632812500, 0.0034790039062500, +0.0034484863281250, 0.0029907226562500, 0.0036621093750000, 0.0031433105468750, +0.0031127929687500, 0.0030822753906250, 0.0034179687500000, 0.0029296875000000, +0.0032043457031250, 0.0030517578125000, 0.0027770996093750, 0.0031127929687500, +0.0031433105468750, 0.0029907226562500, 0.0022583007812500, 0.0029907226562500, +0.0021972656250000, 0.0029602050781250, 0.0022888183593750, 0.0029907226562500, +0.0018310546875000, 0.0029602050781250, 0.0019226074218750, 0.0028076171875000, +0.0023803710937500, 0.0033264160156250, 0.0020751953125000, 0.0030517578125000, +0.0025329589843750, 0.0034179687500000, 0.0031127929687500, 0.0040283203125000, +0.0027160644531250, 0.0035705566406250, 0.0033569335937500, 0.0046997070312500, +0.0032043457031250, 0.0046386718750000, 0.0031127929687500, 0.0045776367187500, +0.0033569335937500, 0.0051574707031250, 0.0030517578125000, 0.0050048828125000, +0.0030212402343750, 0.0048217773437500, 0.0029907226562500, 0.0050354003906250, +0.0028991699218750, 0.0045776367187500, 0.0028381347656250, 0.0041503906250000, +0.0027770996093750, 0.0044860839843750, 0.0027160644531250, 0.0033569335937500, +0.0027770996093750, 0.0034484863281250, 0.0026550292968750, 0.0033569335937500, +0.0025634765625000, 0.0026855468750000, 0.0027160644531250, 0.0029602050781250, +0.0023803710937500, 0.0028381347656250, 0.0024719238281250, 0.0025329589843750, +0.0024108886718750, 0.0028686523437500, 0.0021362304687500, 0.0030822753906250, +0.0023803710937500, 0.0027160644531250, 0.0020141601562500, 0.0033569335937500, +0.0020141601562500, 0.0032043457031250, 0.0023193359375000, 0.0032348632812500, +0.0022888183593750, 0.0036926269531250, 0.0022277832031250, 0.0034179687500000, +0.0028686523437500, 0.0036621093750000, 0.0028381347656250, 0.0036621093750000, +0.0029296875000000, 0.0035095214843750, 0.0034179687500000, 0.0035400390625000, +0.0033569335937500, 0.0035095214843750, 0.0031127929687500, 0.0032348632812500, +0.0034790039062500, 0.0032958984375000, 0.0031738281250000, 0.0032348632812500, +0.0027465820312500, 0.0029602050781250, 0.0032043457031250, 0.0030822753906250, +0.0026245117187500, 0.0032653808593750, 0.0026245117187500, 0.0031433105468750, +0.0028686523437500, 0.0034179687500000, 0.0027160644531250, 0.0037536621093750, +0.0027465820312500}, +{0.0016784667968750, 0.0031738281250000, 0.0020446777343750, 0.0031738281250000, +0.0013732910156250, 0.0035400390625000, 0.0014038085937500, 0.0032348632812500, +0.0015869140625000, 0.0034790039062500, 0.0011901855468750, 0.0039672851562500, +0.0012817382812500, 0.0035095214843750, 0.0018005371093750, 0.0040283203125000, +0.0016174316406250, 0.0039672851562500, 0.0019531250000000, 0.0039062500000000, +0.0025329589843750, 0.0041809082031250, 0.0023803710937500, 0.0040588378906250, +0.0031127929687500, 0.0038146972656250, 0.0031738281250000, 0.0039672851562500, +0.0030822753906250, 0.0037231445312500, 0.0033569335937500, 0.0033874511718750, +0.0033264160156250, 0.0036315917968750, 0.0027465820312500, 0.0032348632812500, +0.0029602050781250, 0.0030822753906250, 0.0026550292968750, 0.0032043457031250, +0.0017395019531250, 0.0032348632812500, 0.0015869140625000, 0.0031433105468750, +0.0013122558593750, 0.0031433105468750, 0.0012512207031250, 0.0032348632812500, +0.0014953613281250, 0.0031127929687500, 0.0014953613281250, 0.0031127929687500, +0.0014038085937500, 0.0033874511718750, 0.0020141601562500, 0.0029907226562500, +0.0020141601562500, 0.0030212402343750, 0.0023803710937500, 0.0031127929687500, +0.0029296875000000, 0.0028076171875000, 0.0027465820312500, 0.0028991699218750, +0.0032958984375000, 0.0033264160156250, 0.0036315917968750, 0.0029296875000000, +0.0033569335937500, 0.0034179687500000, 0.0033264160156250, 0.0041198730468750, +0.0034790039062500, 0.0036315917968750, 0.0026245117187500, 0.0044555664062500, +0.0027770996093750, 0.0046081542968750, 0.0027160644531250, 0.0043640136718750, +0.0021362304687500, 0.0046691894531250, 0.0023193359375000, 0.0046691894531250, +0.0024414062500000, 0.0040283203125000, 0.0021362304687500, 0.0041198730468750, +0.0024108886718750, 0.0036926269531250, 0.0026245117187500, 0.0030212402343750, +0.0021972656250000, 0.0032958984375000, 0.0028381347656250, 0.0025024414062500, +0.0027465820312500, 0.0024108886718750, 0.0026550292968750, 0.0024108886718750, +0.0029296875000000, 0.0020141601562500, 0.0026855468750000, 0.0020446777343750, +0.0026855468750000, 0.0022888183593750, 0.0025939941406250, 0.0022277832031250, +0.0025939941406250, 0.0023193359375000, 0.0026245117187500, 0.0025634765625000, +0.0024719238281250, 0.0025939941406250, 0.0026550292968750, 0.0028076171875000, +0.0023803710937500, 0.0028381347656250, 0.0024414062500000, 0.0028991699218750, +0.0026855468750000, 0.0030822753906250, 0.0023193359375000, 0.0029602050781250, +0.0025024414062500, 0.0029296875000000, 0.0025634765625000, 0.0029296875000000, +0.0022888183593750, 0.0027160644531250, 0.0021362304687500, 0.0025939941406250, +0.0022277832031250, 0.0026550292968750, 0.0019226074218750, 0.0022888183593750, +0.0018005371093750, 0.0022888183593750, 0.0019226074218750, 0.0021972656250000, +0.0018310546875000, 0.0019836425781250, 0.0017395019531250, 0.0020141601562500, +0.0023498535156250, 0.0020751953125000, 0.0020141601562500, 0.0017700195312500, +0.0021972656250000, 0.0019531250000000, 0.0028381347656250, 0.0022277832031250, +0.0023193359375000, 0.0017700195312500, 0.0025634765625000, 0.0025939941406250, +0.0026245117187500, 0.0024414062500000, 0.0024414062500000, 0.0023803710937500, +0.0022277832031250, 0.0027465820312500, 0.0021362304687500, 0.0025024414062500, +0.0022277832031250, 0.0026855468750000, 0.0017700195312500, 0.0026855468750000, +0.0020446777343750, 0.0026855468750000, 0.0023193359375000, 0.0027160644531250, +0.0018005371093750, 0.0027770996093750, 0.0028381347656250, 0.0028686523437500, +0.0025024414062500, 0.0028076171875000, 0.0027160644531250, 0.0029602050781250, +0.0036010742187500, 0.0031738281250000, 0.0030212402343750, 0.0030517578125000, +0.0037536621093750, 0.0034484863281250, 0.0037841796875000, 0.0033874511718750, +0.0036621093750000, 0.0034484863281250, 0.0039367675781250, 0.0036621093750000, +0.0038452148437500, 0.0035095214843750, 0.0037231445312500, 0.0038146972656250, +0.0036926269531250, 0.0038757324218750, 0.0035705566406250, 0.0038452148437500, +0.0033264160156250, 0.0039367675781250, 0.0032653808593750, 0.0039367675781250, +0.0031433105468750, 0.0038757324218750, 0.0029296875000000, 0.0038757324218750, +0.0029296875000000, 0.0038146972656250, 0.0028991699218750, 0.0037841796875000, +0.0027160644531250, 0.0037841796875000, 0.0028991699218750, 0.0038452148437500, +0.0026550292968750, 0.0036621093750000, 0.0027465820312500, 0.0038146972656250, +0.0029296875000000, 0.0039978027343750, 0.0026550292968750, 0.0037536621093750, +0.0030212402343750, 0.0043334960937500, 0.0029296875000000, 0.0042114257812500, +0.0029907226562500, 0.0043334960937500, 0.0032348632812500, 0.0046691894531250, +0.0030212402343750, 0.0044250488281250, 0.0032348632812500, 0.0046081542968750, +0.0031433105468750, 0.0046997070312500, 0.0031738281250000, 0.0044250488281250, +0.0033264160156250, 0.0043640136718750, 0.0031433105468750, 0.0044555664062500, +0.0034179687500000, 0.0040283203125000, 0.0032653808593750, 0.0040283203125000, +0.0033569335937500, 0.0039672851562500, 0.0035400390625000, 0.0036926269531250, +0.0032958984375000, 0.0037231445312500, 0.0036621093750000, 0.0038146972656250, +0.0035705566406250, 0.0036315917968750, 0.0036621093750000, 0.0038757324218750, +0.0039062500000000, 0.0041809082031250, 0.0037231445312500, 0.0039367675781250, +0.0040893554687500, 0.0046081542968750, 0.0039367675781250, 0.0044555664062500, +0.0039672851562500, 0.0047607421875000, 0.0043029785156250, 0.0054016113281250, +0.0040893554687500, 0.0049438476562500, 0.0043640136718750, 0.0057678222656250, +0.0043029785156250, 0.0058288574218750, 0.0042114257812500, 0.0058288574218750, +0.0043029785156250, 0.0061950683593750, 0.0041809082031250, 0.0061035156250000, +0.0040588378906250, 0.0064086914062500, 0.0040283203125000, 0.0064392089843750, +0.0039367675781250, 0.0065002441406250, 0.0038146972656250, 0.0067138671875000, +0.0037841796875000, 0.0066528320312500, 0.0037841796875000, 0.0065917968750000, +0.0036621093750000, 0.0067443847656250, 0.0036926269531250, 0.0065002441406250, +0.0037536621093750, 0.0063781738281250, 0.0035400390625000, 0.0067443847656250, +0.0036315917968750, 0.0058288574218750, 0.0035705566406250, 0.0061645507812500, +0.0034484863281250, 0.0058898925781250, 0.0034790039062500, 0.0050964355468750, +0.0033874511718750, 0.0056457519531250, 0.0033264160156250, 0.0046081542968750, +0.0032653808593750, 0.0047607421875000, 0.0032653808593750, 0.0046386718750000, +0.0032653808593750, 0.0039978027343750, 0.0031738281250000, 0.0043945312500000, +0.0034179687500000, 0.0042114257812500, 0.0032958984375000, 0.0042114257812500, +0.0035705566406250, 0.0043945312500000, 0.0038757324218750, 0.0044555664062500, +0.0036010742187500, 0.0046081542968750, 0.0041809082031250, 0.0045776367187500, +0.0041809082031250, 0.0048828125000000, 0.0040588378906250, 0.0045776367187500, +0.0042419433593750, 0.0042724609375000, 0.0041809082031250, 0.0045776367187500, +0.0039672851562500, 0.0032653808593750, 0.0040588378906250, 0.0035095214843750, +0.0040893554687500, 0.0028686523437500, 0.0039062500000000, 0.0015563964843750, +0.0038452148437500, 0.0022277832031250, 0.0039672851562500, 0.0011596679687500, +0.0037536621093750, 0.0008544921875000, 0.0038452148437500, 0.0012817382812500, +0.0039672851562500, 0.0011291503906250, 0.0037536621093750, 0.0008544921875000, +0.0041503906250000, 0.0018920898437500, 0.0040283203125000, 0.0017395019531250, +0.0041198730468750, 0.0017089843750000, 0.0043640136718750, 0.0023193359375000, +0.0041503906250000, 0.0021362304687500, 0.0043945312500000, 0.0019836425781250, +0.0043334960937500, 0.0020446777343750, 0.0042724609375000, 0.0022888183593750, +0.0042724609375000, 0.0022583007812500, 0.0041198730468750, 0.0021057128906250, +0.0044555664062500, 0.0032653808593750, 0.0041809082031250, 0.0030822753906250, +0.0044555664062500, 0.0031127929687500, 0.0048217773437500, 0.0041198730468750, +0.0043640136718750, 0.0039062500000000, 0.0052185058593750, 0.0030212402343750, +0.0050659179687500, 0.0036621093750000, 0.0049438476562500, 0.0031127929687500, +0.0057983398437500, 0.0009460449218750, 0.0034484863281250, 0.0037231445312500, +0.0019226074218750, 0.0041198730468750, 0.0022583007812500, 0.0045776367187500, +0.0023803710937500, 0.0040893554687500, 0.0020751953125000, 0.0035400390625000, +0.0021667480468750, 0.0039672851562500, 0.0025939941406250, 0.0032348632812500, +0.0027160644531250, 0.0032958984375000, 0.0027465820312500, 0.0030822753906250, +0.0030212402343750, 0.0024719238281250, 0.0032348632812500, 0.0028076171875000, +0.0027465820312500, 0.0020751953125000, 0.0030822753906250, 0.0018005371093750, +0.0030822753906250, 0.0023193359375000, 0.0027770996093750, 0.0021972656250000, +0.0031127929687500, 0.0016479492187500, 0.0029296875000000, 0.0036010742187500, +0.0029907226562500, 0.0030822753906250, 0.0029602050781250, 0.0034179687500000, +0.0027770996093750, 0.0050354003906250, 0.0028381347656250, 0.0041503906250000, +0.0025024414062500, 0.0047607421875000, 0.0024414062500000, 0.0052795410156250, +0.0024414062500000, 0.0045471191406250, 0.0021667480468750, 0.0040588378906250, +0.0021972656250000, 0.0046081542968750, 0.0026550292968750, 0.0030212402343750, +0.0023803710937500, 0.0031738281250000, 0.0027465820312500, 0.0031127929687500, +0.0033264160156250, 0.0021972656250000, 0.0028686523437500, 0.0025939941406250, +0.0036315917968750, 0.0023498535156250, 0.0037231445312500, 0.0023193359375000, +0.0035400390625000, 0.0024719238281250, 0.0037536621093750, 0.0025939941406250, +0.0037841796875000, 0.0026245117187500, 0.0032348632812500, 0.0025329589843750, +0.0033874511718750, 0.0026855468750000, 0.0031433105468750, 0.0027465820312500, +0.0026855468750000, 0.0027770996093750, 0.0029296875000000, 0.0028381347656250, +0.0023803710937500, 0.0029602050781250, 0.0024108886718750, 0.0028991699218750, +0.0024108886718750, 0.0030517578125000, 0.0021667480468750, 0.0031738281250000, +0.0023498535156250, 0.0030212402343750, 0.0021057128906250, 0.0032958984375000, +0.0022277832031250, 0.0033569335937500, 0.0021057128906250, 0.0033264160156250, +0.0018920898437500, 0.0035705566406250, 0.0020751953125000, 0.0035400390625000, +0.0014953613281250, 0.0031433105468750, 0.0015869140625000, 0.0034179687500000, +0.0014648437500000, 0.0031738281250000, 0.0010375976562500, 0.0026245117187500, +0.0011596679687500, 0.0028991699218750, 0.0011596679687500, 0.0026245117187500, +0.0007934570312500, 0.0023803710937500, 0.0012207031250000, 0.0027160644531250, +0.0015869140625000, 0.0028686523437500, 0.0010375976562500, 0.0026550292968750, +0.0024719238281250, 0.0034484863281250, 0.0021972656250000, 0.0032653808593750, +0.0025634765625000, 0.0034790039062500, 0.0036315917968750, 0.0040283203125000, +0.0030822753906250, 0.0036621093750000, 0.0038452148437500, 0.0039672851562500, +0.0040588378906250, 0.0041198730468750, 0.0037536621093750, 0.0038452148437500, +0.0039062500000000, 0.0038146972656250, 0.0040588378906250, 0.0039367675781250, +0.0033874511718750, 0.0035705566406250, 0.0036621093750000, 0.0036315917968750, +0.0032348632812500, 0.0036621093750000, 0.0025634765625000, 0.0034484863281250, +0.0030517578125000, 0.0035095214843750, 0.0018920898437500, 0.0036010742187500, +0.0020141601562500}, +{0.0039978027343750, 0.0025329589843750, 0.0043945312500000, 0.0022277832031250, +0.0039367675781250, 0.0024719238281250, 0.0024108886718750, 0.0046691894531250, +0.0021972656250000, 0.0010986328125000, 0.0028381347656250, 0.0024108886718750, +0.0027465820312500, 0.0014343261718750, 0.0026550292968750, 0.0023193359375000, +0.0030212402343750, 0.0036621093750000, 0.0032348632812500, 0.0029602050781250, +0.0025634765625000, 0.0041198730468750, 0.0028991699218750, 0.0041198730468750, +0.0028686523437500, 0.0041503906250000, 0.0023498535156250, 0.0048522949218750, +0.0027465820312500, 0.0044555664062500, 0.0024719238281250, 0.0044555664062500, +0.0025024414062500, 0.0048522949218750, 0.0025939941406250, 0.0041809082031250, +0.0025024414062500, 0.0036315917968750, 0.0025634765625000, 0.0041503906250000, +0.0025329589843750, 0.0029296875000000, 0.0024108886718750, 0.0028076171875000, +0.0025634765625000, 0.0030517578125000, 0.0026855468750000, 0.0024414062500000, +0.0024719238281250, 0.0024414062500000, 0.0031433105468750, 0.0035400390625000, +0.0029296875000000, 0.0029296875000000, 0.0031433105468750, 0.0035400390625000, +0.0038146972656250, 0.0049438476562500, 0.0034790039062500, 0.0041809082031250, +0.0036621093750000, 0.0052490234375000, 0.0039062500000000, 0.0055541992187500, +0.0034790039062500, 0.0050048828125000, 0.0031738281250000, 0.0049743652343750, +0.0034484863281250, 0.0050659179687500, 0.0025024414062500, 0.0041198730468750, +0.0024719238281250, 0.0041198730468750, 0.0025024414062500, 0.0040283203125000, +0.0020446777343750, 0.0035095214843750, 0.0020141601562500, 0.0036315917968750, +0.0023193359375000, 0.0035705566406250, 0.0021057128906250, 0.0035095214843750, +0.0022583007812500, 0.0036010742187500, 0.0025939941406250, 0.0036010742187500, +0.0022888183593750, 0.0035400390625000, 0.0027160644531250, 0.0036621093750000, +0.0025939941406250, 0.0036010742187500, 0.0025939941406250, 0.0036315917968750, +0.0028076171875000, 0.0037231445312500, 0.0026245117187500, 0.0037231445312500, +0.0027160644531250, 0.0036010742187500, 0.0026855468750000, 0.0036621093750000, +0.0027160644531250, 0.0037231445312500, 0.0027770996093750, 0.0036315917968750, +0.0026855468750000, 0.0036315917968750, 0.0032653808593750, 0.0038452148437500, +0.0029907226562500, 0.0038757324218750, 0.0033874511718750, 0.0039367675781250, +0.0040588378906250, 0.0041198730468750, 0.0036010742187500, 0.0042419433593750, +0.0048522949218750, 0.0039367675781250, 0.0047607421875000, 0.0041809082031250, +0.0048522949218750, 0.0039672851562500, 0.0057067871093750, 0.0036315917968750, +0.0052795410156250, 0.0039978027343750, 0.0053100585937500, 0.0034179687500000, +0.0057373046875000, 0.0034484863281250, 0.0050964355468750, 0.0035705566406250, +0.0045776367187500, 0.0033874511718750, 0.0050354003906250, 0.0034790039062500, +0.0035400390625000, 0.0037231445312500, 0.0036621093750000, 0.0037841796875000, +0.0033264160156250, 0.0040588378906250, 0.0021362304687500, 0.0044250488281250, +0.0026550292968750, 0.0043640136718750, 0.0016479492187500, 0.0044860839843750, +0.0016174316406250, 0.0048217773437500, 0.0013732910156250, 0.0045471191406250, +0.0007629394531250, 0.0043640136718750, 0.0010070800781250, 0.0048217773437500, +0.0005187988281250, 0.0039978027343750, 0.0005187988281250, 0.0041503906250000, +0.0005187988281250, 0.0041809082031250, 0.0003051757812500, 0.0036010742187500, +0.0003051757812500, 0.0039367675781250, 0.0007019042968750, 0.0037841796875000, +0.0004882812500000, 0.0037231445312500, 0.0006713867187500, 0.0039062500000000, +0.0010986328125000, 0.0039672851562500, 0.0008239746093750, 0.0038757324218750, +0.0012817382812500, 0.0043029785156250, 0.0011901855468750, 0.0042114257812500, +0.0013427734375000, 0.0042419433593750, 0.0016479492187500, 0.0046081542968750, +0.0013732910156250, 0.0045166015625000, 0.0019226074218750, 0.0045471191406250, +0.0017395019531250, 0.0046386718750000, 0.0019531250000000, 0.0044860839843750, +0.0023803710937500, 0.0044250488281250, 0.0020446777343750, 0.0044860839843750, +0.0029296875000000, 0.0041503906250000, 0.0027160644531250, 0.0041503906250000, +0.0029602050781250, 0.0040893554687500, 0.0035400390625000, 0.0037536621093750, +0.0031738281250000, 0.0037536621093750, 0.0039978027343750, 0.0035705566406250, +0.0039367675781250, 0.0034790039062500, 0.0041198730468750, 0.0034179687500000, +0.0046691894531250, 0.0034179687500000, 0.0044555664062500, 0.0033569335937500, +0.0046997070312500, 0.0032653808593750, 0.0049133300781250, 0.0033874511718750, +0.0047302246093750, 0.0033874511718750, 0.0047607421875000, 0.0033874511718750, +0.0049133300781250, 0.0035400390625000, 0.0045166015625000, 0.0033874511718750, +0.0046691894531250, 0.0034790039062500, 0.0044250488281250, 0.0035095214843750, +0.0040283203125000, 0.0034179687500000, 0.0043334960937500, 0.0034790039062500, +0.0035705566406250, 0.0034790039062500, 0.0037536621093750, 0.0033874511718750, +0.0034179687500000, 0.0035095214843750, 0.0028076171875000, 0.0036010742187500, +0.0032043457031250, 0.0034484863281250, 0.0023193359375000, 0.0035705566406250, +0.0024719238281250, 0.0035400390625000, 0.0023803710937500, 0.0034790039062500, +0.0018005371093750, 0.0034790039062500, 0.0021362304687500, 0.0033874511718750, +0.0019836425781250, 0.0034179687500000, 0.0019226074218750, 0.0031738281250000, +0.0021667480468750, 0.0033569335937500, 0.0024108886718750, 0.0035095214843750, +0.0023803710937500, 0.0032958984375000, 0.0028076171875000, 0.0038146972656250, +0.0029296875000000, 0.0037536621093750, 0.0028991699218750, 0.0037231445312500, +0.0031127929687500, 0.0040588378906250, 0.0032043457031250, 0.0039062500000000, +0.0029296875000000, 0.0039062500000000, 0.0031738281250000, 0.0040283203125000, +0.0030517578125000, 0.0038757324218750, 0.0026855468750000, 0.0036926269531250, +0.0029296875000000, 0.0038452148437500, 0.0025634765625000, 0.0036010742187500, +0.0025939941406250, 0.0035095214843750, 0.0025024414062500, 0.0035095214843750, +0.0022277832031250, 0.0034179687500000, 0.0023803710937500, 0.0033569335937500, +0.0019836425781250, 0.0032348632812500, 0.0020141601562500, 0.0032348632812500, +0.0019226074218750, 0.0032043457031250, 0.0015869140625000, 0.0030517578125000, +0.0016479492187500, 0.0030212402343750, 0.0014953613281250, 0.0031433105468750, +0.0013732910156250, 0.0029907226562500, 0.0014953613281250, 0.0031433105468750, +0.0014648437500000, 0.0033569335937500, 0.0014343261718750, 0.0031738281250000, +0.0018920898437500, 0.0035400390625000, 0.0017395019531250, 0.0035400390625000, +0.0020446777343750, 0.0035400390625000, 0.0025329589843750, 0.0036926269531250, +0.0021667480468750, 0.0035705566406250, 0.0031433105468750, 0.0035705566406250, +0.0029907226562500, 0.0036315917968750, 0.0032958984375000, 0.0035705566406250, +0.0040588378906250, 0.0036010742187500, 0.0036010742187500, 0.0036621093750000, +0.0043334960937500, 0.0033874511718750, 0.0045166015625000, 0.0036010742187500, +0.0042724609375000, 0.0035095214843750, 0.0044555664062500, 0.0033264160156250, +0.0044250488281250, 0.0035705566406250, 0.0034484863281250, 0.0033569335937500, +0.0037231445312500, 0.0033569335937500, 0.0030212402343750, 0.0034790039062500, +0.0017700195312500, 0.0034484863281250, 0.0023193359375000, 0.0034484863281250, +0.0012817382812500, 0.0033569335937500, 0.0008544921875000, 0.0034790039062500, +0.0011901855468750, 0.0035095214843750, 0.0011291503906250, 0.0034790039062500, +0.0011901855468750, 0.0035400390625000, 0.0022888183593750, 0.0038146972656250, +0.0019531250000000, 0.0036315917968750, 0.0021972656250000, 0.0037231445312500, +0.0031127929687500, 0.0040893554687500, 0.0026855468750000, 0.0039062500000000, +0.0035400390625000, 0.0039367675781250, 0.0035705566406250, 0.0041809082031250, +0.0036926269531250, 0.0038146972656250, 0.0041809082031250, 0.0035095214843750, +0.0038146972656250, 0.0038452148437500, 0.0039367675781250, 0.0027770996093750, +0.0039978027343750, 0.0029296875000000, 0.0036926269531250, 0.0027465820312500, +0.0034484863281250, 0.0018615722656250, 0.0036010742187500, 0.0021972656250000, +0.0029907226562500, 0.0017700195312500, 0.0031433105468750, 0.0015563964843750, +0.0031127929687500, 0.0017089843750000, 0.0027465820312500, 0.0017089843750000, +0.0030822753906250, 0.0015869140625000, 0.0028686523437500, 0.0018920898437500, +0.0030822753906250, 0.0018920898437500, 0.0030822753906250, 0.0018310546875000, +0.0030212402343750, 0.0020141601562500, 0.0034179687500000, 0.0019531250000000, +0.0029602050781250, 0.0019531250000000, 0.0031127929687500, 0.0020141601562500, +0.0032348632812500, 0.0018615722656250, 0.0029907226562500, 0.0016784667968750, +0.0030822753906250, 0.0018310546875000, 0.0032958984375000, 0.0015563964843750, +0.0031127929687500, 0.0014038085937500, 0.0033264160156250, 0.0014953613281250, +0.0036926269531250, 0.0014953613281250, 0.0034790039062500, 0.0014648437500000, +0.0038146972656250, 0.0017089843750000, 0.0038757324218750, 0.0017089843750000, +0.0038757324218750, 0.0017700195312500, 0.0040588378906250, 0.0019531250000000, +0.0041503906250000, 0.0019226074218750, 0.0039978027343750, 0.0022583007812500, +0.0040588378906250, 0.0021972656250000, 0.0040893554687500, 0.0024719238281250, +0.0039672851562500, 0.0028381347656250, 0.0038757324218750, 0.0026550292968750, +0.0042114257812500, 0.0033569335937500, 0.0039978027343750, 0.0033569335937500, +0.0042114257812500, 0.0034790039062500, 0.0046997070312500, 0.0039978027343750, +0.0043640136718750, 0.0039367675781250, 0.0048217773437500, 0.0039978027343750, +0.0049438476562500, 0.0043029785156250, 0.0047607421875000, 0.0041809082031250, +0.0049133300781250, 0.0039672851562500, 0.0051269531250000, 0.0043029785156250, +0.0046997070312500, 0.0037841796875000, 0.0049438476562500, 0.0038757324218750, +0.0048828125000000, 0.0039062500000000, 0.0045776367187500, 0.0035400390625000, +0.0049438476562500, 0.0036315917968750, 0.0046691894531250, 0.0035095214843750, +0.0049438476562500, 0.0033874511718750, 0.0049438476562500, 0.0034484863281250, +0.0048522949218750, 0.0033569335937500, 0.0051879882812500, 0.0032348632812500, +0.0047912597656250, 0.0031433105468750, 0.0051269531250000, 0.0031433105468750, +0.0048522949218750, 0.0029907226562500, 0.0043640136718750, 0.0028686523437500, +0.0047912597656250, 0.0028686523437500, 0.0040893554687500, 0.0027160644531250, +0.0040588378906250, 0.0026855468750000, 0.0041198730468750, 0.0026550292968750, +0.0037536621093750, 0.0025329589843750, 0.0037231445312500, 0.0025634765625000, +0.0040893554687500, 0.0025329589843750, 0.0038146972656250, 0.0025024414062500, +0.0039978027343750, 0.0025939941406250, 0.0044555664062500, 0.0026550292968750, +0.0041198730468750, 0.0025939941406250, 0.0046997070312500, 0.0027770996093750, +0.0047302246093750, 0.0027770996093750, 0.0046386718750000, 0.0028686523437500, +0.0048828125000000, 0.0030212402343750, 0.0048522949218750, 0.0028686523437500, +0.0046997070312500, 0.0031738281250000, 0.0048828125000000, 0.0030822753906250, +0.0048217773437500, 0.0032653808593750, 0.0046691894531250, 0.0035400390625000, +0.0046997070312500, 0.0032348632812500, 0.0046997070312500, 0.0039672851562500, +0.0045776367187500, 0.0037231445312500, 0.0046691894531250, 0.0039978027343750, +0.0046997070312500}, +{0.0025024414062500, 0.0018310546875000, 0.0035095214843750, 0.0017395019531250, +0.0027770996093750, 0.0016784667968750, 0.0035705566406250, 0.0018005371093750, +0.0037536621093750, 0.0017700195312500, 0.0033874511718750, 0.0017395019531250, +0.0034179687500000, 0.0018005371093750, 0.0035095214843750, 0.0016174316406250, +0.0028381347656250, 0.0017700195312500, 0.0029296875000000, 0.0016784667968750, +0.0028381347656250, 0.0016174316406250, 0.0024414062500000, 0.0017395019531250, +0.0027160644531250, 0.0016784667968750, 0.0026550292968750, 0.0017395019531250, +0.0027160644531250, 0.0017395019531250, 0.0029602050781250, 0.0019226074218750, +0.0031127929687500, 0.0021057128906250, 0.0031127929687500, 0.0019226074218750, +0.0031738281250000, 0.0024719238281250, 0.0033569335937500, 0.0025024414062500, +0.0033264160156250, 0.0025634765625000, 0.0032653808593750, 0.0028991699218750, +0.0034179687500000, 0.0028076171875000, 0.0033874511718750, 0.0031738281250000, +0.0033264160156250, 0.0032653808593750, 0.0034484863281250, 0.0033264160156250, +0.0035095214843750, 0.0036010742187500, 0.0033569335937500, 0.0036010742187500, +0.0039062500000000, 0.0037536621093750, 0.0036315917968750, 0.0039062500000000, +0.0038146972656250, 0.0039978027343750, 0.0042724609375000, 0.0040283203125000, +0.0038452148437500, 0.0040588378906250, 0.0041503906250000, 0.0040283203125000, +0.0041503906250000, 0.0040588378906250, 0.0039672851562500, 0.0039672851562500, +0.0039672851562500, 0.0038452148437500, 0.0039062500000000, 0.0039062500000000, +0.0038146972656250, 0.0036621093750000, 0.0036621093750000, 0.0035705566406250, +0.0039062500000000, 0.0035095214843750, 0.0040283203125000, 0.0033264160156250, +0.0038452148437500, 0.0033569335937500, 0.0043640136718750, 0.0032958984375000, +0.0044555664062500, 0.0032348632812500, 0.0043334960937500, 0.0032653808593750, +0.0046081542968750, 0.0032958984375000, 0.0047912597656250, 0.0032043457031250, +0.0042114257812500, 0.0032958984375000, 0.0045776367187500, 0.0032653808593750, +0.0044250488281250, 0.0032348632812500, 0.0039367675781250, 0.0032043457031250, +0.0045471191406250, 0.0031433105468750, 0.0038757324218750, 0.0031738281250000, +0.0041198730468750, 0.0031127929687500, 0.0042419433593750, 0.0032043457031250, +0.0039367675781250, 0.0032958984375000, 0.0044860839843750, 0.0031738281250000, +0.0040893554687500, 0.0035095214843750, 0.0044555664062500, 0.0033569335937500, +0.0044555664062500, 0.0034790039062500, 0.0042114257812500, 0.0037841796875000, +0.0046691894531250, 0.0035095214843750, 0.0042114257812500, 0.0039062500000000, +0.0043334960937500, 0.0038146972656250, 0.0044555664062500, 0.0037536621093750, +0.0041809082031250, 0.0039978027343750, 0.0042419433593750, 0.0038757324218750, +0.0046386718750000, 0.0039367675781250, 0.0044555664062500, 0.0038757324218750, +0.0046997070312500, 0.0038757324218750, 0.0051269531250000, 0.0039062500000000, +0.0048522949218750, 0.0039367675781250, 0.0054016113281250, 0.0040893554687500, +0.0053710937500000, 0.0040893554687500, 0.0053100585937500, 0.0041809082031250, +0.0055236816406250, 0.0043334960937500, 0.0054321289062500, 0.0043334960937500, +0.0052185058593750, 0.0042114257812500, 0.0052185058593750, 0.0043945312500000, +0.0050354003906250, 0.0041503906250000, 0.0047607421875000, 0.0038757324218750, +0.0047912597656250, 0.0040283203125000, 0.0046081542968750, 0.0030517578125000, +0.0044250488281250, 0.0032043457031250, 0.0044250488281250, 0.0027160644531250, +0.0043640136718750, 0.0017395019531250, 0.0041503906250000, 0.0022277832031250, +0.0042419433593750, 0.0010681152343750, 0.0041198730468750, 0.0010070800781250, +0.0040283203125000, 0.0009765625000000, 0.0039978027343750, 0.0003051757812500, +0.0038452148437500, 0.0004577636718750, 0.0036621093750000, 0.0005187988281250, +0.0036315917968750, 0.0003356933593750, 0.0035400390625000, 0.0005187988281250, +0.0033874511718750, 0.0008239746093750, 0.0034179687500000, 0.0005798339843750, +0.0032348632812500, 0.0010986328125000, 0.0032958984375000, 0.0009460449218750, +0.0032653808593750, 0.0010986328125000, 0.0031738281250000, 0.0014953613281250, +0.0032653808593750, 0.0012207031250000, 0.0032043457031250, 0.0016479492187500, +0.0032043457031250, 0.0017395019531250, 0.0032958984375000, 0.0016479492187500, +0.0032653808593750, 0.0017700195312500, 0.0032958984375000, 0.0018310546875000, +0.0035400390625000, 0.0018615722656250, 0.0034179687500000, 0.0018920898437500, +0.0036926269531250, 0.0021057128906250, 0.0039672851562500, 0.0021972656250000, +0.0036010742187500, 0.0021362304687500, 0.0043029785156250, 0.0026245117187500, +0.0041809082031250, 0.0026550292968750, 0.0043334960937500, 0.0028381347656250, +0.0048522949218750, 0.0031738281250000, 0.0045471191406250, 0.0030517578125000, +0.0049133300781250, 0.0034790039062500, 0.0049438476562500, 0.0034484863281250, +0.0048522949218750, 0.0036010742187500, 0.0049133300781250, 0.0038757324218750, +0.0048828125000000, 0.0037536621093750, 0.0046386718750000, 0.0042724609375000, +0.0046386718750000, 0.0042419433593750, 0.0045776367187500, 0.0042419433593750, +0.0043945312500000, 0.0046081542968750, 0.0044860839843750, 0.0045166015625000, +0.0044250488281250, 0.0044555664062500, 0.0043945312500000, 0.0046081542968750, +0.0043640136718750, 0.0044860839843750, 0.0043945312500000, 0.0042419433593750, +0.0042724609375000, 0.0043334960937500, 0.0042419433593750, 0.0043945312500000, +0.0041503906250000, 0.0042114257812500, 0.0042114257812500, 0.0043029785156250, +0.0042419433593750, 0.0045166015625000, 0.0040893554687500, 0.0043640136718750, +0.0042724609375000, 0.0043334960937500, 0.0041809082031250, 0.0044860839843750, +0.0041198730468750, 0.0042114257812500, 0.0041809082031250, 0.0040283203125000, +0.0040588378906250, 0.0042419433593750, 0.0042419433593750, 0.0036010742187500, +0.0041809082031250, 0.0036315917968750, 0.0042419433593750, 0.0036010742187500, +0.0043945312500000, 0.0033264160156250, 0.0042419433593750, 0.0034484863281250, +0.0043640136718750, 0.0033569335937500, 0.0043029785156250, 0.0032958984375000, +0.0041198730468750, 0.0033264160156250, 0.0039978027343750, 0.0033264160156250, +0.0039672851562500, 0.0033264160156250, 0.0035095214843750, 0.0031127929687500, +0.0034790039062500, 0.0030517578125000, 0.0033264160156250, 0.0030822753906250, +0.0029907226562500, 0.0029296875000000, 0.0029602050781250, 0.0028381347656250, +0.0030212402343750, 0.0033264160156250, 0.0027160644531250, 0.0030212402343750, +0.0029907226562500, 0.0035400390625000, 0.0033569335937500, 0.0043334960937500, +0.0030517578125000, 0.0037841796875000, 0.0035400390625000, 0.0048828125000000, +0.0037231445312500, 0.0050659179687500, 0.0035095214843750, 0.0046997070312500, +0.0034484863281250, 0.0048828125000000, 0.0034179687500000, 0.0030517578125000, +0.0031433105468750, 0.0047607421875000, 0.0032653808593750, 0.0043945312500000, +0.0033874511718750, 0.0045166015625000, 0.0034790039062500, 0.0052490234375000, +0.0034790039062500, 0.0051574707031250, 0.0032958984375000, 0.0046081542968750, +0.0033874511718750, 0.0048522949218750, 0.0032653808593750, 0.0043945312500000, +0.0028686523437500, 0.0037231445312500, 0.0029602050781250, 0.0042419433593750, +0.0030517578125000, 0.0029602050781250, 0.0027160644531250, 0.0030822753906250, +0.0028076171875000, 0.0029296875000000, 0.0030822753906250, 0.0021057128906250, +0.0026855468750000, 0.0024108886718750, 0.0029602050781250, 0.0022277832031250, +0.0027770996093750, 0.0018615722656250, 0.0027465820312500, 0.0024414062500000, +0.0028076171875000, 0.0028686523437500, 0.0025634765625000, 0.0024108886718750, +0.0030212402343750, 0.0036926269531250, 0.0027160644531250, 0.0037231445312500, +0.0029602050781250, 0.0036926269531250, 0.0035095214843750, 0.0044860839843750, +0.0030212402343750, 0.0042724609375000, 0.0037231445312500, 0.0038452148437500, +0.0036315917968750, 0.0042419433593750, 0.0035400390625000, 0.0039978027343750, +0.0038452148437500, 0.0032958984375000, 0.0035095214843750, 0.0036926269531250, +0.0032958984375000, 0.0036621093750000, 0.0033264160156250, 0.0034790039062500, +0.0030822753906250, 0.0039062500000000, 0.0027160644531250, 0.0042114257812500, +0.0027160644531250, 0.0039367675781250, 0.0025634765625000, 0.0045471191406250, +0.0023498535156250, 0.0046081542968750, 0.0025329589843750, 0.0045776367187500, +0.0025634765625000, 0.0048522949218750, 0.0023803710937500, 0.0049133300781250, +0.0031738281250000, 0.0047912597656250, 0.0028381347656250, 0.0049438476562500, +0.0032043457031250, 0.0046997070312500, 0.0039062500000000, 0.0043029785156250, +0.0033874511718750, 0.0045166015625000, 0.0042724609375000, 0.0040893554687500, +0.0042419433593750, 0.0040893554687500, 0.0040283203125000, 0.0041809082031250, +0.0043945312500000, 0.0040893554687500, 0.0042724609375000, 0.0040588378906250, +0.0036010742187500, 0.0040283203125000, 0.0039062500000000, 0.0043029785156250, +0.0033264160156250, 0.0041198730468750, 0.0024414062500000, 0.0040283203125000, +0.0030212402343750, 0.0041503906250000, 0.0015563964843750, 0.0036926269531250, +0.0016174316406250, 0.0037841796875000, 0.0015258789062500, 0.0035400390625000, +0.0006103515625000, 0.0030822753906250, 0.0009460449218750, 0.0033569335937500, +0.0007629394531250, 0.0030212402343750, 0.0004272460937500, 0.0029602050781250, +0.0007019042968750, 0.0029907226562500, 0.0008850097656250, 0.0029296875000000, +0.0007019042968750, 0.0029602050781250, 0.0012207031250000, 0.0028381347656250, +0.0011596679687500, 0.0028686523437500, 0.0013732910156250, 0.0027160644531250, +0.0016784667968750, 0.0025024414062500, 0.0016174316406250, 0.0025939941406250, +0.0025329589843750, 0.0024414062500000, 0.0022583007812500, 0.0022583007812500, +0.0028686523437500, 0.0024108886718750, 0.0037841796875000, 0.0023803710937500, +0.0032653808593750, 0.0021667480468750, 0.0045166015625000, 0.0027465820312500, +0.0044860839843750, 0.0025329589843750, 0.0046081542968750, 0.0028076171875000, +0.0053405761718750, 0.0033874511718750, 0.0049743652343750, 0.0030212402343750, +0.0052795410156250, 0.0037536621093750, 0.0053405761718750, 0.0037536621093750, +0.0051879882812500, 0.0037536621093750, 0.0052490234375000, 0.0041809082031250, +0.0052185058593750, 0.0040283203125000, 0.0048522949218750, 0.0040283203125000, +0.0050048828125000, 0.0041809082031250, 0.0046386718750000, 0.0039367675781250, +0.0041503906250000, 0.0037841796875000, 0.0044250488281250, 0.0038452148437500, +0.0037841796875000, 0.0033874511718750, 0.0037231445312500, 0.0033569335937500, +0.0036010742187500, 0.0033874511718750, 0.0032043457031250, 0.0032348632812500, +0.0034179687500000, 0.0032653808593750, 0.0030822753906250, 0.0034179687500000, +0.0030822753906250, 0.0033874511718750, 0.0031127929687500, 0.0034790039062500, +0.0029296875000000, 0.0036621093750000, 0.0029907226562500, 0.0035400390625000, +0.0028076171875000, 0.0037231445312500, 0.0027465820312500, 0.0037231445312500, +0.0026550292968750, 0.0037231445312500, 0.0024414062500000, 0.0037841796875000, +0.0024719238281250, 0.0037231445312500, 0.0022583007812500, 0.0038146972656250, +0.0021972656250000, 0.0037231445312500, 0.0021667480468750, 0.0036926269531250, +0.0020141601562500, 0.0037231445312500, 0.0019531250000000, 0.0037231445312500, +0.0020141601562500}, +{0.0008850097656250, 0.0030822753906250, 0.0011901855468750, 0.0027770996093750, +0.0008850097656250, 0.0029602050781250, 0.0012207031250000, 0.0028381347656250, +0.0017089843750000, 0.0023803710937500, 0.0013122558593750, 0.0025329589843750, +0.0021972656250000, 0.0025329589843750, 0.0020751953125000, 0.0023803710937500, +0.0021972656250000, 0.0027770996093750, 0.0028076171875000, 0.0031433105468750, +0.0024414062500000, 0.0028991699218750, 0.0026855468750000, 0.0036315917968750, +0.0028381347656250, 0.0036010742187500, 0.0023803710937500, 0.0036010742187500, +0.0021667480468750, 0.0040283203125000, 0.0024108886718750, 0.0038757324218750, +0.0010375976562500, 0.0037231445312500, 0.0013427734375000, 0.0039978027343750, +0.0007629394531250, 0.0036010742187500, -0.0003967285156250, 0.0032653808593750, +0.0001831054687500, 0.0036621093750000, -0.0012817382812500, 0.0027770996093750, +-0.0013427734375000, 0.0028686523437500, -0.0013427734375000, 0.0028686523437500, +-0.0021057128906250, 0.0023498535156250, -0.0019531250000000, 0.0025634765625000, +-0.0019226074218750, 0.0025329589843750, -0.0022277832031250, 0.0025329589843750, +-0.0018310546875000, 0.0025329589843750, -0.0014648437500000, 0.0026550292968750, +-0.0018920898437500, 0.0027465820312500, -0.0010070800781250, 0.0025939941406250, +-0.0011901855468750, 0.0026245117187500, -0.0008850097656250, 0.0026855468750000, +-0.0002136230468750, 0.0025939941406250, -0.0007629394531250, 0.0025939941406250, +0.0004882812500000, 0.0027770996093750, 0.0001220703125000, 0.0025634765625000, +0.0004882812500000, 0.0027770996093750, 0.0015563964843750, 0.0030212402343750, +0.0008850097656250, 0.0026855468750000, 0.0019836425781250, 0.0032348632812500, +0.0021057128906250, 0.0031433105468750, 0.0019226074218750, 0.0031127929687500, +0.0024719238281250, 0.0033874511718750, 0.0024719238281250, 0.0031127929687500, +0.0021362304687500, 0.0032958984375000, 0.0024108886718750, 0.0031738281250000, +0.0023193359375000, 0.0031127929687500, 0.0020141601562500, 0.0031738281250000, +0.0023498535156250, 0.0029296875000000, 0.0020141601562500, 0.0031433105468750, +0.0021667480468750, 0.0030517578125000, 0.0022888183593750, 0.0030517578125000, +0.0020751953125000, 0.0032043457031250, 0.0022583007812500, 0.0030822753906250, +0.0027465820312500, 0.0033264160156250, 0.0025634765625000, 0.0033264160156250, +0.0030822753906250, 0.0032958984375000, 0.0036926269531250, 0.0034790039062500, +0.0032958984375000, 0.0034790039062500, 0.0045166015625000, 0.0033569335937500, +0.0044555664062500, 0.0035095214843750, 0.0046386718750000, 0.0033874511718750, +0.0054931640625000, 0.0032653808593750, 0.0051269531250000, 0.0033569335937500, +0.0055541992187500, 0.0031127929687500, 0.0056762695312500, 0.0031127929687500, +0.0054016113281250, 0.0031738281250000, 0.0053710937500000, 0.0029907226562500, +0.0054016113281250, 0.0028991699218750, 0.0046997070312500, 0.0031127929687500, +0.0049133300781250, 0.0029602050781250, 0.0044555664062500, 0.0029907226562500, +0.0037536621093750, 0.0031738281250000, 0.0041809082031250, 0.0030212402343750, +0.0028686523437500, 0.0031433105468750, 0.0030517578125000, 0.0031127929687500, +0.0027770996093750, 0.0031127929687500, 0.0019226074218750, 0.0031738281250000, +0.0023803710937500, 0.0030517578125000, 0.0015869140625000, 0.0032043457031250, +0.0016174316406250, 0.0031127929687500, 0.0015869140625000, 0.0032348632812500, +0.0012207031250000, 0.0034179687500000, 0.0014648437500000, 0.0032043457031250, +0.0012512207031250, 0.0037231445312500, 0.0012207031250000, 0.0036926269531250, +0.0013732910156250, 0.0038452148437500, 0.0014038085937500, 0.0041503906250000, +0.0014038085937500, 0.0040283203125000, 0.0016174316406250, 0.0042419433593750, +0.0015563964843750, 0.0042724609375000, 0.0015563964843750, 0.0042419433593750, +0.0016479492187500, 0.0043334960937500, 0.0015563964843750, 0.0043640136718750, +0.0015563964843750, 0.0042419433593750, 0.0014648437500000, 0.0043029785156250, +0.0014648437500000, 0.0042724609375000, 0.0014648437500000, 0.0041809082031250, +0.0013122558593750, 0.0042419433593750, 0.0015869140625000, 0.0040588378906250, +0.0014038085937500, 0.0040893554687500, 0.0015563964843750, 0.0039062500000000, +0.0018310546875000, 0.0036010742187500, 0.0015563964843750, 0.0038146972656250, +0.0019226074218750, 0.0035400390625000, 0.0019836425781250, 0.0034179687500000, +0.0018310546875000, 0.0035400390625000, 0.0019226074218750, 0.0035705566406250, +0.0018615722656250, 0.0033874511718750, 0.0017089843750000, 0.0036010742187500, +0.0016479492187500, 0.0035400390625000, 0.0017089843750000, 0.0034484863281250, +0.0017395019531250, 0.0035400390625000, 0.0016479492187500, 0.0035095214843750, +0.0019531250000000, 0.0033264160156250, 0.0020141601562500, 0.0033569335937500, +0.0020751953125000, 0.0032653808593750, 0.0022583007812500, 0.0030212402343750, +0.0023193359375000, 0.0031433105468750, 0.0021972656250000, 0.0029907226562500, +0.0024414062500000, 0.0029907226562500, 0.0022888183593750, 0.0030822753906250, +0.0020141601562500, 0.0030822753906250, 0.0022583007812500, 0.0031127929687500, +0.0016479492187500, 0.0031127929687500, 0.0017395019531250, 0.0031127929687500, +0.0014953613281250, 0.0030517578125000, 0.0010375976562500, 0.0030212402343750, +0.0012817382812500, 0.0031127929687500, 0.0006103515625000, 0.0030212402343750, +0.0006408691406250, 0.0030822753906250, 0.0007019042968750, 0.0031433105468750, +0.0003356933593750, 0.0031738281250000, 0.0004577636718750, 0.0031433105468750, +0.0006713867187500, 0.0032043457031250, 0.0004272460937500, 0.0032653808593750, +0.0007629394531250, 0.0032958984375000, 0.0011291503906250, 0.0033264160156250, +0.0008239746093750, 0.0032653808593750, 0.0016784667968750, 0.0030212402343750, +0.0014953613281250, 0.0032348632812500, 0.0016174316406250, 0.0028991699218750, +0.0021362304687500, 0.0024414062500000, 0.0017089843750000, 0.0027160644531250, +0.0020141601562500, 0.0019531250000000, 0.0020446777343750, 0.0019226074218750, +0.0017700195312500, 0.0019836425781250, 0.0016784667968750, 0.0016174316406250, +0.0017700195312500, 0.0016479492187500, 0.0014343261718750, 0.0019226074218750, +0.0013732910156250, 0.0017700195312500, 0.0018310546875000, 0.0018005371093750, +0.0019226074218750, 0.0019836425781250, 0.0015563964843750, 0.0017395019531250, +0.0028381347656250, 0.0017700195312500, 0.0027160644531250, 0.0017395019531250, +0.0026855468750000, 0.0017395019531250, 0.0034484863281250, 0.0016784667968750, +0.0032348632812500, 0.0016174316406250, 0.0032348632812500, 0.0018310546875000, +0.0036010742187500, 0.0016784667968750, 0.0032958984375000, 0.0017089843750000, +0.0030212402343750, 0.0018310546875000, 0.0033874511718750, 0.0016784667968750, +0.0025634765625000, 0.0019836425781250, 0.0026245117187500, 0.0019531250000000, +0.0025024414062500, 0.0019836425781250, 0.0018310546875000, 0.0021972656250000, +0.0021362304687500, 0.0020141601562500, 0.0021057128906250, 0.0021362304687500, +0.0017700195312500, 0.0020141601562500, 0.0021362304687500, 0.0019531250000000, +0.0025024414062500, 0.0019531250000000, 0.0021362304687500, 0.0017089843750000, +0.0028686523437500, 0.0018920898437500, 0.0028991699218750, 0.0017089843750000, +0.0026855468750000, 0.0017395019531250, 0.0029602050781250, 0.0018920898437500, +0.0028991699218750, 0.0015869140625000, 0.0025329589843750, 0.0018920898437500, +0.0025634765625000, 0.0018615722656250, 0.0025939941406250, 0.0017700195312500, +0.0023803710937500, 0.0018920898437500, 0.0023498535156250, 0.0017700195312500, +0.0025634765625000, 0.0016479492187500, 0.0023803710937500, 0.0015869140625000, +0.0024719238281250, 0.0014648437500000, 0.0027770996093750, 0.0012207031250000, +0.0025329589843750, 0.0011901855468750, 0.0027160644531250, 0.0010070800781250, +0.0028686523437500, 0.0009460449218750, 0.0026855468750000, 0.0007629394531250, +0.0025939941406250, 0.0006103515625000, 0.0028381347656250, 0.0007019042968750, +0.0024108886718750, 0.0002746582031250, 0.0025634765625000, 0.0003662109375000, +0.0026245117187500, 0.0002136230468750, 0.0024414062500000, -0.0001831054687500, +0.0025634765625000, -0.0000305175781250, 0.0028076171875000, -0.0002441406250000, +0.0026855468750000, -0.0003662109375000, 0.0028991699218750, -0.0003662109375000, +0.0032043457031250, -0.0004272460937500, 0.0029602050781250, -0.0004882812500000, +0.0031433105468750, -0.0002441406250000, 0.0032348632812500, -0.0003967285156250, +0.0031127929687500, -0.0001831054687500, 0.0029907226562500, 0.0001831054687500, +0.0029907226562500, -0.0000915527343750, 0.0030212402343750, 0.0003967285156250, +0.0027160644531250, 0.0004882812500000, 0.0029296875000000, 0.0005187988281250, +0.0030822753906250, 0.0007934570312500, 0.0027160644531250, 0.0007934570312500, +0.0034790039062500, 0.0007629394531250, 0.0031738281250000, 0.0008544921875000, +0.0032958984375000, 0.0008544921875000, 0.0037841796875000, 0.0007324218750000, +0.0032653808593750, 0.0007934570312500, 0.0038146972656250, 0.0009155273437500, +0.0035095214843750, 0.0007934570312500, 0.0034790039062500, 0.0009765625000000, +0.0037536621093750, 0.0011291503906250, 0.0031738281250000, 0.0010681152343750, +0.0037231445312500, 0.0014953613281250, 0.0033569335937500, 0.0014953613281250, +0.0033569335937500, 0.0014953613281250, 0.0037231445312500, 0.0018005371093750, +0.0032043457031250, 0.0016784667968750, 0.0035705566406250, 0.0016784667968750, +0.0034179687500000, 0.0016784667968750, 0.0031738281250000, 0.0015563964843750, +0.0032348632812500, 0.0014648437500000, 0.0030822753906250, 0.0014648437500000, +0.0028381347656250, 0.0014648437500000, 0.0027160644531250, 0.0011596679687500, +0.0026855468750000, 0.0012512207031250, 0.0025329589843750, 0.0014343261718750, +0.0024719238281250, 0.0011596679687500, 0.0026550292968750, 0.0015869140625000, +0.0024414062500000, 0.0014038085937500, 0.0025939941406250, 0.0014953613281250, +0.0028991699218750, 0.0018005371093750, 0.0026245117187500, 0.0015258789062500, +0.0030517578125000, 0.0020446777343750, 0.0030212402343750, 0.0019226074218750, +0.0029907226562500, 0.0021057128906250, 0.0032043457031250, 0.0025024414062500, +0.0031127929687500, 0.0021972656250000, 0.0030517578125000, 0.0028686523437500, +0.0031127929687500, 0.0027465820312500, 0.0029907226562500, 0.0028381347656250, +0.0028991699218750, 0.0032653808593750, 0.0030517578125000, 0.0029907226562500, +0.0028076171875000, 0.0032653808593750, 0.0028686523437500, 0.0033264160156250, +0.0029602050781250, 0.0031433105468750, 0.0028076171875000, 0.0031433105468750, +0.0029907226562500, 0.0031127929687500, 0.0030822753906250, 0.0027160644531250, +0.0029907226562500, 0.0026855468750000, 0.0031738281250000, 0.0025634765625000, +0.0033264160156250, 0.0022888183593750, 0.0032348632812500, 0.0023498535156250, +0.0035400390625000, 0.0020446777343750, 0.0036315917968750, 0.0019531250000000, +0.0036315917968750, 0.0020141601562500, 0.0037841796875000, 0.0018310546875000, +0.0038452148437500, 0.0018005371093750, 0.0036621093750000, 0.0019836425781250, +0.0039367675781250, 0.0019531250000000, 0.0038452148437500, 0.0018920898437500, +0.0036315917968750, 0.0020141601562500, 0.0039672851562500, 0.0020751953125000, +0.0035400390625000, 0.0016784667968750, 0.0036621093750000, 0.0018310546875000, +0.0036926269531250}, +{0.0028686523437500, 0.0007324218750000, 0.0028991699218750, 0.0008544921875000, +0.0032348632812500, 0.0008850097656250, 0.0029602050781250, 0.0008544921875000, +0.0031433105468750, 0.0011901855468750, 0.0030212402343750, 0.0011596679687500, +0.0030212402343750, 0.0013427734375000, 0.0030517578125000, 0.0016174316406250, +0.0027770996093750, 0.0014343261718750, 0.0031738281250000, 0.0018615722656250, +0.0028381347656250, 0.0018920898437500, 0.0029296875000000, 0.0018615722656250, +0.0032958984375000, 0.0021057128906250, 0.0027770996093750, 0.0020141601562500, +0.0032653808593750, 0.0018005371093750, 0.0030517578125000, 0.0018920898437500, +0.0029602050781250, 0.0018005371093750, 0.0032043457031250, 0.0015258789062500, +0.0028686523437500, 0.0017395019531250, 0.0032348632812500, 0.0014343261718750, +0.0029602050781250, 0.0015258789062500, 0.0031433105468750, 0.0014953613281250, +0.0034484863281250, 0.0013732910156250, 0.0030212402343750, 0.0014953613281250, +0.0037536621093750, 0.0010681152343750, 0.0035705566406250, 0.0012817382812500, +0.0036315917968750, 0.0009155273437500, 0.0040893554687500, 0.0003356933593750, +0.0037536621093750, 0.0007324218750000, 0.0039978027343750, -0.0004272460937500, +0.0039672851562500, -0.0003356933593750, 0.0038757324218750, -0.0006103515625000, +0.0038452148437500, -0.0015563964843750, 0.0036926269531250, -0.0011596679687500, +0.0037231445312500, -0.0018005371093750, 0.0035705566406250, -0.0020751953125000, +0.0035400390625000, -0.0017395019531250, 0.0035705566406250, -0.0018005371093750, +0.0034179687500000, -0.0019531250000000, 0.0035705566406250, -0.0009155273437500, +0.0034790039062500, -0.0012512207031250, 0.0034179687500000, -0.0007019042968750, +0.0034790039062500, 0.0002746582031250, 0.0033874511718750, -0.0002746582031250, +0.0032043457031250, 0.0013427734375000, 0.0033264160156250, 0.0011596679687500, +0.0031433105468750, 0.0015258789062500, 0.0028381347656250, 0.0026245117187500, +0.0031127929687500, 0.0020141601562500, 0.0027770996093750, 0.0029602050781250, +0.0028076171875000, 0.0029907226562500, 0.0028381347656250, 0.0029602050781250, +0.0027770996093750, 0.0034179687500000, 0.0028991699218750, 0.0031127929687500, +0.0028686523437500, 0.0033264160156250, 0.0029296875000000, 0.0032043457031250, +0.0030212402343750, 0.0032348632812500, 0.0030212402343750, 0.0033569335937500, +0.0030822753906250, 0.0031738281250000, 0.0031738281250000, 0.0034179687500000, +0.0031738281250000, 0.0032958984375000, 0.0032958984375000, 0.0032958984375000, +0.0033874511718750, 0.0035095214843750, 0.0033874511718750, 0.0033569335937500, +0.0037231445312500, 0.0033264160156250, 0.0037231445312500, 0.0033569335937500, +0.0038146972656250, 0.0032348632812500, 0.0040588378906250, 0.0031433105468750, +0.0040283203125000, 0.0031433105468750, 0.0041809082031250, 0.0028381347656250, +0.0042419433593750, 0.0029602050781250, 0.0042419433593750, 0.0027465820312500, +0.0043334960937500, 0.0023803710937500, 0.0043029785156250, 0.0026245117187500, +0.0043945312500000, 0.0022888183593750, 0.0043640136718750, 0.0021667480468750, +0.0043029785156250, 0.0023803710937500, 0.0043334960937500, 0.0024108886718750, +0.0043029785156250, 0.0023193359375000, 0.0041809082031250, 0.0026855468750000, +0.0042114257812500, 0.0027770996093750, 0.0042114257812500, 0.0026855468750000, +0.0041503906250000, 0.0029296875000000, 0.0041503906250000, 0.0030212402343750, +0.0040893554687500, 0.0023803710937500, 0.0041198730468750, 0.0026550292968750, +0.0039978027343750, 0.0023803710937500, 0.0039062500000000, 0.0015869140625000, +0.0040283203125000, 0.0019836425781250, 0.0039367675781250, 0.0014648437500000, +0.0039062500000000, 0.0011596679687500, 0.0038757324218750, 0.0014648437500000, +0.0037841796875000, 0.0014343261718750, 0.0038452148437500, 0.0012512207031250, +0.0037231445312500, 0.0018920898437500, 0.0036621093750000, 0.0017700195312500, +0.0036010742187500, 0.0018310546875000, 0.0034790039062500, 0.0022277832031250, +0.0034484863281250, 0.0020141601562500, 0.0032348632812500, 0.0021972656250000, +0.0032043457031250, 0.0021667480468750, 0.0030212402343750, 0.0021972656250000, +0.0027465820312500, 0.0023498535156250, 0.0028076171875000, 0.0021362304687500, +0.0025634765625000, 0.0026245117187500, 0.0024108886718750, 0.0024108886718750, +0.0025634765625000, 0.0025939941406250, 0.0025329589843750, 0.0031127929687500, +0.0023803710937500, 0.0027465820312500, 0.0028686523437500, 0.0034179687500000, +0.0027160644531250, 0.0034179687500000, 0.0028991699218750, 0.0032653808593750, +0.0033874511718750, 0.0035705566406250, 0.0030212402343750, 0.0035400390625000, +0.0033264160156250, 0.0031127929687500, 0.0036010742187500, 0.0032653808593750, +0.0032043457031250, 0.0030517578125000, 0.0029602050781250, 0.0026550292968750, +0.0032958984375000, 0.0029296875000000, 0.0023803710937500, 0.0021667480468750, +0.0025024414062500, 0.0021667480468750, 0.0025329589843750, 0.0021362304687500, +0.0019226074218750, 0.0016784667968750, 0.0021972656250000, 0.0016784667968750, +0.0025329589843750, 0.0017089843750000, 0.0024108886718750, 0.0014953613281250, +0.0026245117187500, 0.0017395019531250, 0.0031433105468750, 0.0018615722656250, +0.0029602050781250, 0.0015563964843750, 0.0030212402343750, 0.0028686523437500, +0.0032348632812500, 0.0025634765625000, 0.0031738281250000, 0.0028381347656250, +0.0028686523437500, 0.0045471191406250, 0.0028991699218750, 0.0014953613281250, +0.0033874511718750, 0.0022583007812500, 0.0033569335937500, 0.0018005371093750, +0.0029296875000000, 0.0023803710937500, 0.0028381347656250, 0.0031738281250000, +0.0029907226562500, 0.0028381347656250, 0.0021057128906250, 0.0035400390625000, +0.0022277832031250, 0.0036315917968750, 0.0018920898437500, 0.0034484863281250, +0.0012817382812500, 0.0036621093750000, 0.0015563964843750, 0.0036926269531250, +0.0006408691406250, 0.0031433105468750, 0.0007019042968750, 0.0034790039062500, +0.0004272460937500, 0.0031127929687500, -0.0002746582031250, 0.0025329589843750, +0.0001220703125000, 0.0030517578125000, -0.0004577636718750, 0.0018615722656250, +-0.0005493164062500, 0.0018615722656250, -0.0003356933593750, 0.0018920898437500, +-0.0004577636718750, 0.0011291503906250, -0.0004577636718750, 0.0011901855468750, +0.0000305175781250, 0.0015869140625000, 0.0000000000000000, 0.0010986328125000, +0.0001220703125000, 0.0017700195312500, 0.0005798339843750, 0.0025329589843750, +0.0004577636718750, 0.0018920898437500, 0.0008239746093750, 0.0033569335937500, +0.0008239746093750, 0.0035400390625000, 0.0009460449218750, 0.0031738281250000, +0.0011596679687500, 0.0036010742187500, 0.0010681152343750, 0.0036010742187500, +0.0011291503906250, 0.0029296875000000, 0.0012817382812500, 0.0032043457031250, +0.0010986328125000, 0.0029296875000000, 0.0009765625000000, 0.0022277832031250, +0.0010681152343750, 0.0027160644531250, 0.0002746582031250, 0.0021972656250000, +0.0004882812500000, 0.0021057128906250, 0.0003051757812500, 0.0022583007812500, +-0.0004272460937500, 0.0020751953125000, -0.0001525878906250, 0.0020141601562500, +-0.0002441406250000, 0.0022583007812500, -0.0005798339843750, 0.0022277832031250, +-0.0000610351562500, 0.0023193359375000, 0.0003051757812500, 0.0025329589843750, +-0.0001220703125000, 0.0025329589843750, 0.0013427734375000, 0.0027770996093750, +0.0009765625000000, 0.0027465820312500, 0.0014648437500000, 0.0029602050781250, +0.0026245117187500, 0.0031433105468750, 0.0019226074218750, 0.0028991699218750, +0.0032348632812500, 0.0034790039062500, 0.0031738281250000, 0.0035095214843750, +0.0033264160156250, 0.0036926269531250, 0.0041198730468750, 0.0042114257812500, +0.0037231445312500, 0.0039978027343750, 0.0042724609375000, 0.0043640136718750, +0.0044250488281250, 0.0045471191406250, 0.0041198730468750, 0.0043334960937500, +0.0041503906250000, 0.0042724609375000, 0.0043640136718750, 0.0044555664062500, +0.0032958984375000, 0.0039672851562500, 0.0036621093750000, 0.0040588378906250, +0.0031738281250000, 0.0040283203125000, 0.0022583007812500, 0.0037231445312500, +0.0028686523437500, 0.0038452148437500, 0.0017395019531250, 0.0037841796875000, +0.0016479492187500, 0.0036010742187500, 0.0018615722656250, 0.0037536621093750, +0.0013732910156250, 0.0038452148437500, 0.0014038085937500, 0.0036926269531250, +0.0022277832031250, 0.0039367675781250, 0.0017089843750000, 0.0038146972656250, +0.0021667480468750, 0.0036926269531250, 0.0031738281250000, 0.0038452148437500, +0.0023803710937500, 0.0036926269531250, 0.0035705566406250, 0.0035705566406250, +0.0035095214843750, 0.0036621093750000, 0.0032653808593750, 0.0035705566406250, +0.0038757324218750, 0.0033874511718750, 0.0035400390625000, 0.0035400390625000, +0.0030822753906250, 0.0034179687500000, 0.0034179687500000, 0.0034484863281250, +0.0025329589843750, 0.0034790039062500, 0.0017395019531250, 0.0035095214843750, +0.0024414062500000, 0.0036315917968750, 0.0001831054687500, 0.0036010742187500, +0.0005798339843750, 0.0036926269531250, -0.0000305175781250, 0.0036926269531250, +-0.0017700195312500, 0.0036926269531250, -0.0008239746093750, 0.0037536621093750, +-0.0023498535156250, 0.0036315917968750, -0.0025024414062500, 0.0036926269531250, +-0.0021972656250000, 0.0037231445312500, -0.0028076171875000, 0.0036315917968750, +-0.0026855468750000, 0.0037231445312500, -0.0017089843750000, 0.0037536621093750, +-0.0022583007812500, 0.0037841796875000, -0.0013122558593750, 0.0038452148437500, +-0.0000610351562500, 0.0038452148437500, -0.0010070800781250, 0.0038146972656250, +0.0015869140625000, 0.0039367675781250, 0.0011291503906250, 0.0038452148437500, +0.0018615722656250, 0.0039062500000000, 0.0038146972656250, 0.0040283203125000, +0.0027465820312500, 0.0038452148437500, 0.0045776367187500, 0.0042724609375000, +0.0046386718750000, 0.0041198730468750, 0.0044555664062500, 0.0042419433593750, +0.0053405761718750, 0.0045776367187500, 0.0049133300781250, 0.0042724609375000, +0.0048217773437500, 0.0046691894531250, 0.0049743652343750, 0.0045776367187500, +0.0045471191406250, 0.0045776367187500, 0.0041503906250000, 0.0047607421875000, +0.0043029785156250, 0.0046386718750000, 0.0035705566406250, 0.0047302246093750, +0.0035400390625000, 0.0046997070312500, 0.0032958984375000, 0.0046691894531250, +0.0027465820312500, 0.0046691894531250, 0.0028686523437500, 0.0046081542968750, +0.0025329589843750, 0.0045776367187500, 0.0023498535156250, 0.0046081542968750, +0.0022888183593750, 0.0044860839843750, 0.0021057128906250, 0.0043945312500000, +0.0021362304687500, 0.0043945312500000, 0.0021362304687500, 0.0042724609375000, +0.0020446777343750, 0.0042114257812500, 0.0021057128906250, 0.0042114257812500, +0.0022277832031250, 0.0041198730468750, 0.0020751953125000, 0.0039978027343750, +0.0024719238281250, 0.0041198730468750, 0.0024108886718750, 0.0040893554687500, +0.0025329589843750, 0.0039978027343750, 0.0028076171875000, 0.0041503906250000, +0.0026245117187500, 0.0040893554687500, 0.0027160644531250, 0.0039367675781250, +0.0028076171875000, 0.0039978027343750, 0.0026550292968750, 0.0039062500000000, +0.0025024414062500, 0.0037536621093750, 0.0025329589843750, 0.0038146972656250, +0.0022888183593750, 0.0037536621093750, 0.0022583007812500, 0.0036621093750000, +0.0021057128906250, 0.0036621093750000, 0.0019226074218750, 0.0036315917968750, +0.0019531250000000}, +{0.0032653808593750, 0.0045471191406250, 0.0030517578125000, 0.0044555664062500, +0.0043029785156250, 0.0044860839843750, 0.0040893554687500, 0.0044860839843750, +0.0044250488281250, 0.0045166015625000, 0.0054931640625000, 0.0045471191406250, +0.0050964355468750, 0.0045776367187500, 0.0054016113281250, 0.0046081542968750, +0.0057983398437500, 0.0047302246093750, 0.0053405761718750, 0.0046386718750000, +0.0051269531250000, 0.0045776367187500, 0.0054931640625000, 0.0046997070312500, +0.0040588378906250, 0.0045471191406250, 0.0045471191406250, 0.0045471191406250, +0.0039062500000000, 0.0044555664062500, 0.0026245117187500, 0.0043945312500000, +0.0035095214843750, 0.0044555664062500, 0.0018005371093750, 0.0042419433593750, +0.0018310546875000, 0.0041809082031250, 0.0018005371093750, 0.0041503906250000, +0.0008544921875000, 0.0041198730468750, 0.0011596679687500, 0.0040283203125000, +0.0011596679687500, 0.0040893554687500, 0.0007324218750000, 0.0041198730468750, +0.0011901855468750, 0.0040588378906250, 0.0015563964843750, 0.0041198730468750, +0.0009155273437500, 0.0043029785156250, 0.0020141601562500, 0.0039978027343750, +0.0016784667968750, 0.0042419433593750, 0.0017700195312500, 0.0041503906250000, +0.0024719238281250, 0.0038757324218750, 0.0018615722656250, 0.0041503906250000, +0.0023498535156250, 0.0038452148437500, 0.0022888183593750, 0.0038452148437500, +0.0020751953125000, 0.0039672851562500, 0.0020751953125000, 0.0037841796875000, +0.0019836425781250, 0.0038452148437500, 0.0018005371093750, 0.0039978027343750, +0.0017395019531250, 0.0039062500000000, 0.0017395019531250, 0.0039672851562500, +0.0016479492187500, 0.0041503906250000, 0.0015258789062500, 0.0040283203125000, +0.0018005371093750, 0.0042419433593750, 0.0016784667968750, 0.0042419433593750, +0.0019226074218750, 0.0042724609375000, 0.0022888183593750, 0.0043640136718750, +0.0021362304687500, 0.0043029785156250, 0.0028076171875000, 0.0044250488281250, +0.0028381347656250, 0.0043640136718750, 0.0028381347656250, 0.0043640136718750, +0.0032348632812500, 0.0044555664062500, 0.0031127929687500, 0.0043640136718750, +0.0029907226562500, 0.0043334960937500, 0.0031127929687500, 0.0043334960937500, +0.0028381347656250, 0.0042114257812500, 0.0025024414062500, 0.0041198730468750, +0.0026855468750000, 0.0040893554687500, 0.0021057128906250, 0.0041809082031250, +0.0021362304687500, 0.0040283203125000, 0.0021057128906250, 0.0040893554687500, +0.0017089843750000, 0.0042419433593750, 0.0018615722656250, 0.0040893554687500, +0.0017089843750000, 0.0042114257812500, 0.0016479492187500, 0.0041809082031250, +0.0016174316406250, 0.0040893554687500, 0.0015258789062500, 0.0041198730468750, +0.0015563964843750, 0.0041198730468750, 0.0014648437500000, 0.0039367675781250, +0.0013732910156250, 0.0039978027343750, 0.0015258789062500, 0.0038452148437500, +0.0015563964843750, 0.0036315917968750, 0.0014343261718750, 0.0037231445312500, +0.0021667480468750, 0.0035095214843750, 0.0018920898437500, 0.0035095214843750, +0.0022277832031250, 0.0034484863281250, 0.0028686523437500, 0.0032958984375000, +0.0024719238281250, 0.0033874511718750, 0.0032348632812500, 0.0032348632812500, +0.0032043457031250, 0.0031738281250000, 0.0031738281250000, 0.0031433105468750, +0.0035705566406250, 0.0030822753906250, 0.0032958984375000, 0.0029907226562500, +0.0032348632812500, 0.0030822753906250, 0.0032043457031250, 0.0030212402343750, +0.0029907226562500, 0.0030517578125000, 0.0027770996093750, 0.0031433105468750, +0.0027160644531250, 0.0031433105468750, 0.0025024414062500, 0.0032653808593750, +0.0023803710937500, 0.0032348632812500, 0.0022277832031250, 0.0032958984375000, +0.0020446777343750, 0.0033874511718750, 0.0019531250000000, 0.0034179687500000, +0.0018615722656250, 0.0034790039062500, 0.0017700195312500, 0.0035400390625000, +0.0017395019531250, 0.0034179687500000, 0.0016784667968750, 0.0033569335937500, +0.0015563964843750, 0.0033264160156250, 0.0015563964843750, 0.0029907226562500, +0.0014343261718750, 0.0030822753906250, 0.0014953613281250, 0.0029907226562500, +0.0015869140625000, 0.0027770996093750, 0.0013732910156250, 0.0028991699218750, +0.0017089843750000, 0.0026855468750000, 0.0018005371093750, 0.0028686523437500, +0.0018310546875000, 0.0027770996093750, 0.0019836425781250, 0.0025634765625000, +0.0020751953125000, 0.0027770996093750, 0.0019836425781250, 0.0024414062500000, +0.0021362304687500, 0.0024719238281250, 0.0021972656250000, 0.0025634765625000, +0.0021972656250000, 0.0023498535156250, 0.0023498535156250, 0.0024719238281250, +0.0025024414062500, 0.0026245117187500, 0.0026245117187500, 0.0026550292968750, +0.0026855468750000, 0.0026245117187500, 0.0027465820312500, 0.0027770996093750, +0.0025024414062500, 0.0028076171875000, 0.0020446777343750, 0.0025024414062500, +0.0022277832031250, 0.0027465820312500, 0.0018615722656250, 0.0025634765625000, +0.0011596679687500, 0.0022583007812500, 0.0013427734375000, 0.0024719238281250, +0.0007324218750000, 0.0018310546875000, 0.0006103515625000, 0.0018310546875000, +0.0007019042968750, 0.0017700195312500, 0.0003662109375000, 0.0014038085937500, +0.0003967285156250, 0.0014953613281250, 0.0013122558593750, 0.0014648437500000, +0.0007629394531250, 0.0012817382812500, 0.0010070800781250, 0.0014343261718750, +0.0020141601562500, 0.0016174316406250, 0.0015258789062500, 0.0014648437500000, +0.0018005371093750, 0.0018920898437500, 0.0019836425781250, 0.0019531250000000, +0.0017089843750000, 0.0019836425781250, 0.0017700195312500, 0.0021972656250000, +0.0020446777343750, 0.0021362304687500, 0.0017395019531250, 0.0020141601562500, +0.0016174316406250, 0.0022277832031250, 0.0020751953125000, 0.0021057128906250, +0.0021972656250000, 0.0018310546875000, 0.0020751953125000, 0.0019836425781250, +0.0030212402343750, 0.0019226074218750, 0.0029296875000000, 0.0018005371093750, +0.0032043457031250, 0.0020751953125000, 0.0040283203125000, 0.0022888183593750, +0.0037231445312500, 0.0021057128906250, 0.0039367675781250, 0.0026245117187500, +0.0041809082031250, 0.0027160644531250, 0.0040283203125000, 0.0026855468750000, +0.0039367675781250, 0.0028686523437500, 0.0041503906250000, 0.0028076171875000, +0.0038452148437500, 0.0028686523437500, 0.0039062500000000, 0.0028381347656250, +0.0040588378906250, 0.0029296875000000, 0.0039978027343750, 0.0029602050781250, +0.0039367675781250, 0.0028381347656250, 0.0042724609375000, 0.0032348632812500, +0.0041198730468750, 0.0031127929687500, 0.0041809082031250, 0.0032348632812500, +0.0044250488281250, 0.0034484863281250, 0.0042724609375000, 0.0032653808593750, +0.0042114257812500, 0.0033569335937500, 0.0043945312500000, 0.0033874511718750, +0.0042114257812500, 0.0032958984375000, 0.0039978027343750, 0.0032653808593750, +0.0042724609375000, 0.0032653808593750, 0.0039978027343750, 0.0031738281250000, +0.0040893554687500, 0.0031738281250000, 0.0043334960937500, 0.0032348632812500, +0.0043640136718750, 0.0032348632812500, 0.0044555664062500, 0.0033264160156250, +0.0048217773437500, 0.0035705566406250, 0.0050048828125000, 0.0035095214843750, +0.0049438476562500, 0.0037536621093750, 0.0052795410156250, 0.0039672851562500, +0.0054626464843750, 0.0038452148437500, 0.0050659179687500, 0.0038757324218750, +0.0054626464843750, 0.0039672851562500, 0.0053100585937500, 0.0037841796875000, +0.0048522949218750, 0.0035400390625000, 0.0053710937500000, 0.0035705566406250, +0.0046691894531250, 0.0032958984375000, 0.0048828125000000, 0.0031738281250000, +0.0048217773437500, 0.0031127929687500, 0.0043640136718750, 0.0028991699218750, +0.0048522949218750, 0.0028991699218750, 0.0041503906250000, 0.0030212402343750, +0.0044250488281250, 0.0029296875000000, 0.0042724609375000, 0.0030517578125000, +0.0037231445312500, 0.0032653808593750, 0.0042114257812500, 0.0031433105468750, +0.0034790039062500, 0.0034179687500000, 0.0035705566406250, 0.0034179687500000, +0.0036621093750000, 0.0034179687500000, 0.0033569335937500, 0.0035705566406250, +0.0035705566406250, 0.0035705566406250, 0.0035400390625000, 0.0035095214843750, +0.0035400390625000, 0.0035400390625000, 0.0036010742187500, 0.0035095214843750, +0.0036926269531250, 0.0034484863281250, 0.0037536621093750, 0.0034790039062500, +0.0035400390625000, 0.0034790039062500, 0.0036621093750000, 0.0035095214843750, +0.0035705566406250, 0.0034484863281250, 0.0034790039062500, 0.0034484863281250, +0.0036010742187500, 0.0036010742187500, 0.0034484863281250, 0.0031433105468750, +0.0034179687500000, 0.0032958984375000, 0.0036010742187500, 0.0030212402343750, +0.0036010742187500, 0.0025634765625000, 0.0035095214843750, 0.0028991699218750, +0.0038757324218750, 0.0021667480468750, 0.0038452148437500, 0.0022277832031250, +0.0039672851562500, 0.0021667480468750, 0.0042724609375000, 0.0017089843750000, +0.0042114257812500, 0.0019531250000000, 0.0044860839843750, 0.0016479492187500, +0.0044860839843750, 0.0016174316406250, 0.0045776367187500, 0.0018005371093750, +0.0046997070312500, 0.0018005371093750, 0.0047302246093750, 0.0018310546875000, +0.0048828125000000, 0.0020446777343750, 0.0048828125000000, 0.0020141601562500, +0.0049743652343750, 0.0022277832031250, 0.0050659179687500, 0.0024108886718750, +0.0050048828125000, 0.0022888183593750, 0.0051269531250000, 0.0027770996093750, +0.0050659179687500, 0.0026855468750000, 0.0050354003906250, 0.0028381347656250, +0.0050964355468750, 0.0031738281250000, 0.0049438476562500, 0.0029602050781250, +0.0049743652343750, 0.0033874511718750, 0.0048828125000000, 0.0034179687500000, +0.0048217773437500, 0.0034790039062500, 0.0048217773437500, 0.0037536621093750, +0.0046997070312500, 0.0036621093750000, 0.0046386718750000, 0.0039367675781250, +0.0046691894531250, 0.0040893554687500, 0.0046081542968750, 0.0040588378906250, +0.0045776367187500, 0.0040893554687500, 0.0045471191406250, 0.0042724609375000, +0.0044250488281250, 0.0038146972656250, 0.0044250488281250, 0.0039978027343750, +0.0043640136718750, 0.0038452148437500, 0.0043334960937500, 0.0033569335937500, +0.0043334960937500, 0.0036010742187500, 0.0041198730468750, 0.0033264160156250, +0.0041809082031250, 0.0031127929687500, 0.0040283203125000, 0.0033264160156250, +0.0038146972656250, 0.0034179687500000, 0.0039672851562500, 0.0032653808593750, +0.0035400390625000, 0.0037231445312500, 0.0036315917968750, 0.0037231445312500, +0.0034790039062500, 0.0036621093750000, 0.0032043457031250, 0.0040588378906250, +0.0034790039062500, 0.0040588378906250, 0.0029602050781250, 0.0036315917968750, +0.0031433105468750, 0.0041198730468750, 0.0030822753906250, 0.0036315917968750, +0.0026855468750000, 0.0029907226562500, 0.0029907226562500, 0.0034790039062500, +0.0027465820312500, 0.0024719238281250, 0.0027465820312500, 0.0024108886718750, +0.0028686523437500, 0.0024719238281250, 0.0028991699218750, 0.0020141601562500, +0.0028991699218750, 0.0021972656250000, 0.0027465820312500, 0.0022277832031250, +0.0029907226562500, 0.0021972656250000, 0.0026855468750000, 0.0023498535156250, +0.0023193359375000, 0.0025024414062500, 0.0026245117187500, 0.0024108886718750, +0.0020446777343750, 0.0025634765625000, 0.0019836425781250, 0.0026855468750000, +0.0020141601562500, 0.0025024414062500, 0.0018310546875000, 0.0022888183593750, +0.0019836425781250, 0.0023803710937500, 0.0021667480468750, 0.0021057128906250, +0.0022277832031250}, +{0.0035400390625000, 0.0054321289062500, 0.0037231445312500, 0.0054016113281250, +0.0037841796875000, 0.0053100585937500, 0.0035400390625000, 0.0054321289062500, +0.0038452148437500, 0.0055236816406250, 0.0037231445312500, 0.0051269531250000, +0.0038146972656250, 0.0053710937500000, 0.0039978027343750, 0.0050354003906250, +0.0039978027343750, 0.0046081542968750, 0.0040893554687500, 0.0050659179687500, +0.0041809082031250, 0.0041198730468750, 0.0042419433593750, 0.0043640136718750, +0.0042724609375000, 0.0041198730468750, 0.0043334960937500, 0.0033874511718750, +0.0044250488281250, 0.0039062500000000, 0.0044250488281250, 0.0027770996093750, +0.0044250488281250, 0.0028991699218750, 0.0044860839843750, 0.0027465820312500, +0.0045166015625000, 0.0019531250000000, 0.0045776367187500, 0.0023803710937500, +0.0046386718750000, 0.0017700195312500, 0.0046081542968750, 0.0016784667968750, +0.0046081542968750, 0.0018615722656250, 0.0045776367187500, 0.0017700195312500, +0.0045471191406250, 0.0016784667968750, 0.0044860839843750, 0.0020751953125000, +0.0044860839843750, 0.0020141601562500, 0.0043945312500000, 0.0022583007812500, +0.0042724609375000, 0.0026855468750000, 0.0043029785156250, 0.0025329589843750, +0.0040588378906250, 0.0031433105468750, 0.0040283203125000, 0.0031127929687500, +0.0040588378906250, 0.0034179687500000, 0.0039672851562500, 0.0038757324218750, +0.0040893554687500, 0.0036315917968750, 0.0040893554687500, 0.0043945312500000, +0.0040588378906250, 0.0043334960937500, 0.0042114257812500, 0.0044860839843750, +0.0043029785156250, 0.0049438476562500, 0.0042724609375000, 0.0046997070312500, +0.0043640136718750, 0.0051269531250000, 0.0044250488281250, 0.0051269531250000, +0.0043640136718750, 0.0052185058593750, 0.0043945312500000, 0.0054626464843750, +0.0043334960937500, 0.0052795410156250, 0.0040893554687500, 0.0056152343750000, +0.0041809082031250, 0.0056457519531250, 0.0039978027343750, 0.0056457519531250, +0.0037231445312500, 0.0058898925781250, 0.0039367675781250, 0.0058288574218750, +0.0034790039062500, 0.0055847167968750, 0.0035095214843750, 0.0057373046875000, +0.0034179687500000, 0.0054626464843750, 0.0031738281250000, 0.0050354003906250, +0.0033569335937500, 0.0052490234375000, 0.0031738281250000, 0.0045166015625000, +0.0032348632812500, 0.0044555664062500, 0.0032653808593750, 0.0043334960937500, +0.0031127929687500, 0.0037841796875000, 0.0033264160156250, 0.0038757324218750, +0.0032348632812500, 0.0037841796875000, 0.0032043457031250, 0.0036010742187500, +0.0031433105468750, 0.0036926269531250, 0.0030822753906250, 0.0038452148437500, +0.0031433105468750, 0.0038146972656250, 0.0027770996093750, 0.0037231445312500, +0.0029602050781250, 0.0039062500000000, 0.0026855468750000, 0.0037231445312500, +0.0023193359375000, 0.0034790039062500, 0.0026550292968750, 0.0036926269531250, +0.0020751953125000, 0.0032958984375000, 0.0020141601562500, 0.0032653808593750, +0.0021972656250000, 0.0034179687500000, 0.0020141601562500, 0.0032653808593750, +0.0020446777343750, 0.0032653808593750, 0.0022888183593750, 0.0038146972656250, +0.0024108886718750, 0.0036315917968750, 0.0023193359375000, 0.0038757324218750, +0.0024414062500000, 0.0044860839843750, 0.0027770996093750, 0.0041503906250000, +0.0021362304687500, 0.0044860839843750, 0.0025634765625000, 0.0045776367187500, +0.0023498535156250, 0.0045166015625000, 0.0017700195312500, 0.0047302246093750, +0.0023803710937500, 0.0046081542968750, 0.0018310546875000, 0.0043945312500000, +0.0020141601562500, 0.0046081542968750, 0.0020751953125000, 0.0042419433593750, +0.0019226074218750, 0.0037841796875000, 0.0022583007812500, 0.0040588378906250, +0.0017089843750000, 0.0033264160156250, 0.0021362304687500, 0.0034484863281250, +0.0017700195312500, 0.0031433105468750, 0.0011291503906250, 0.0025634765625000, +0.0017089843750000, 0.0029907226562500, 0.0005187988281250, 0.0019836425781250, +0.0005493164062500, 0.0018615722656250, 0.0006713867187500, 0.0021057128906250, +-0.0001831054687500, 0.0017395019531250, -0.0000915527343750, 0.0042114257812500, +0.0010070800781250, 0.0030822753906250, 0.0004577636718750, 0.0035400390625000, +0.0009765625000000, 0.0030517578125000, 0.0016784667968750, 0.0023193359375000, +0.0011291503906250, 0.0027770996093750, 0.0024719238281250, 0.0020751953125000, +0.0022888183593750, 0.0020446777343750, 0.0025024414062500, 0.0019836425781250, +0.0033569335937500, 0.0015258789062500, 0.0028991699218750, 0.0017395019531250, +0.0034484863281250, 0.0016479492187500, 0.0034484863281250, 0.0017089843750000, +0.0034790039062500, 0.0015258789062500, 0.0037536621093750, 0.0015258789062500, +0.0035400390625000, 0.0018310546875000, 0.0036621093750000, 0.0008239746093750, +0.0037231445312500, 0.0010681152343750, 0.0033569335937500, 0.0010986328125000, +0.0031433105468750, 0.0003662109375000, 0.0033264160156250, 0.0006408691406250, +0.0024719238281250, 0.0010070800781250, 0.0025634765625000, 0.0006408691406250, +0.0023803710937500, 0.0013122558593750, 0.0017089843750000, 0.0020141601562500, +0.0019836425781250, 0.0015258789062500, 0.0019531250000000, 0.0033264160156250, +0.0017395019531250, 0.0033874511718750, 0.0019836425781250, 0.0032958984375000, +0.0022583007812500, 0.0043945312500000, 0.0020446777343750, 0.0042419433593750, +0.0026245117187500, 0.0034790039062500, 0.0025939941406250, 0.0041198730468750, +0.0025329589843750, 0.0032653808593750, 0.0027770996093750, 0.0019531250000000, +0.0027770996093750, 0.0027770996093750, 0.0023803710937500, 0.0012512207031250, +0.0026550292968750, 0.0010681152343750, 0.0024414062500000, 0.0014343261718750, +0.0020446777343750, 0.0008850097656250, 0.0023803710937500, 0.0008239746093750, +0.0013732910156250, 0.0016784667968750, 0.0017700195312500, 0.0014953613281250, +0.0012207031250000, 0.0020141601562500, 0.0003051757812500, 0.0029602050781250, +0.0010375976562500, 0.0026550292968750, -0.0004577636718750, 0.0033264160156250, +-0.0002136230468750, 0.0036926269531250, -0.0004272460937500, 0.0034790039062500, +-0.0014343261718750, 0.0035400390625000, -0.0007629394531250, 0.0037536621093750, +-0.0012512207031250, 0.0032958984375000, -0.0014953613281250, 0.0034790039062500, +-0.0008544921875000, 0.0033264160156250, -0.0006713867187500, 0.0028381347656250, +-0.0009155273437500, 0.0032043457031250, 0.0003356933593750, 0.0028381347656250, +0.0002136230468750, 0.0029296875000000, 0.0003662109375000, 0.0028991699218750, +0.0012817382812500, 0.0026855468750000, 0.0010070800781250, 0.0028076171875000, +0.0010375976562500, 0.0024414062500000, 0.0013427734375000, 0.0025329589843750, +0.0009460449218750, 0.0025329589843750, 0.0005493164062500, 0.0023498535156250, +0.0009155273437500, 0.0025939941406250, 0.0001220703125000, 0.0025634765625000, +0.0001525878906250, 0.0025329589843750, 0.0003356933593750, 0.0027465820312500, +-0.0000305175781250, 0.0029296875000000, 0.0000610351562500, 0.0027465820312500, +0.0006408691406250, 0.0030517578125000, 0.0004272460937500, 0.0030517578125000, +0.0008544921875000, 0.0030212402343750, 0.0015563964843750, 0.0031433105468750, +0.0012207031250000, 0.0030212402343750, 0.0024414062500000, 0.0030212402343750, +0.0023803710937500, 0.0030212402343750, 0.0026245117187500, 0.0029907226562500, +0.0034790039062500, 0.0029602050781250, 0.0032653808593750, 0.0029296875000000, +0.0035705566406250, 0.0030212402343750, 0.0039062500000000, 0.0028991699218750, +0.0036926269531250, 0.0029602050781250, 0.0035705566406250, 0.0030822753906250, +0.0039672851562500, 0.0029602050781250, 0.0032348632812500, 0.0031738281250000, +0.0034790039062500, 0.0031127929687500, 0.0033874511718750, 0.0030822753906250, +0.0029602050781250, 0.0031433105468750, 0.0033874511718750, 0.0030822753906250, +0.0030212402343750, 0.0029907226562500, 0.0031127929687500, 0.0029907226562500, +0.0032043457031250, 0.0029296875000000, 0.0030822753906250, 0.0027160644531250, +0.0033264160156250, 0.0028381347656250, 0.0034179687500000, 0.0026550292968750, +0.0034790039062500, 0.0026550292968750, 0.0036010742187500, 0.0026550292968750, +0.0037841796875000, 0.0025329589843750, 0.0037231445312500, 0.0025329589843750, +0.0039672851562500, 0.0026245117187500, 0.0039672851562500, 0.0025024414062500, +0.0039367675781250, 0.0025939941406250, 0.0040893554687500, 0.0026245117187500, +0.0040893554687500, 0.0024414062500000, 0.0037536621093750, 0.0027160644531250, +0.0039367675781250, 0.0026245117187500, 0.0037536621093750, 0.0025939941406250, +0.0033874511718750, 0.0027465820312500, 0.0036315917968750, 0.0025939941406250, +0.0030517578125000, 0.0026550292968750, 0.0030212402343750, 0.0026550292968750, +0.0029907226562500, 0.0026245117187500, 0.0026855468750000, 0.0026550292968750, +0.0027465820312500, 0.0025939941406250, 0.0030822753906250, 0.0027770996093750, +0.0028381347656250, 0.0028076171875000, 0.0032958984375000, 0.0027465820312500, +0.0038757324218750, 0.0028381347656250, 0.0035705566406250, 0.0028686523437500, +0.0047912597656250, 0.0026855468750000, 0.0048217773437500, 0.0027770996093750, +0.0049743652343750, 0.0027465820312500, 0.0058288574218750, 0.0026245117187500, +0.0055541992187500, 0.0027465820312500, 0.0055236816406250, 0.0025634765625000, +0.0059509277343750, 0.0026245117187500, 0.0054016113281250, 0.0026550292968750, +0.0049133300781250, 0.0025939941406250, 0.0054016113281250, 0.0027465820312500, +0.0040283203125000, 0.0025939941406250, 0.0042114257812500, 0.0027160644531250, +0.0039367675781250, 0.0026855468750000, 0.0030517578125000, 0.0025329589843750, +0.0036010742187500, 0.0027160644531250, 0.0026245117187500, 0.0025634765625000, +0.0027770996093750, 0.0025024414062500, 0.0025939941406250, 0.0026855468750000, +0.0019531250000000, 0.0027465820312500, 0.0024414062500000, 0.0026245117187500, +0.0016479492187500, 0.0028686523437500, 0.0016784667968750, 0.0028991699218750, +0.0016784667968750, 0.0029296875000000, 0.0012207031250000, 0.0031127929687500, +0.0014038085937500, 0.0032043457031250, 0.0015869140625000, 0.0029602050781250, +0.0014343261718750, 0.0032348632812500, 0.0017700195312500, 0.0031433105468750, +0.0021057128906250, 0.0029602050781250, 0.0019531250000000, 0.0033569335937500, +0.0025329589843750, 0.0028686523437500, 0.0025939941406250, 0.0031127929687500, +0.0026855468750000, 0.0029907226562500, 0.0030822753906250, 0.0026245117187500, +0.0030822753906250, 0.0030212402343750, 0.0033264160156250, 0.0025329589843750, +0.0035095214843750, 0.0026245117187500, 0.0034790039062500, 0.0025939941406250, +0.0035095214843750, 0.0023193359375000, 0.0037536621093750, 0.0026245117187500, +0.0036315917968750, 0.0021057128906250, 0.0037231445312500, 0.0022888183593750, +0.0039367675781250, 0.0022583007812500, 0.0039978027343750, 0.0019226074218750, +0.0040893554687500, 0.0021362304687500, 0.0044860839843750, 0.0020141601562500, +0.0042114257812500, 0.0018920898437500, 0.0046691894531250, 0.0019836425781250, +0.0052185058593750, 0.0019836425781250, 0.0047302246093750, 0.0019531250000000, +0.0059204101562500, 0.0019226074218750, 0.0057983398437500, 0.0019531250000000, +0.0057067871093750, 0.0018005371093750, 0.0064086914062500, 0.0016784667968750, +0.0060424804687500, 0.0017700195312500, 0.0056762695312500, 0.0014038085937500, +0.0060119628906250, 0.0014038085937500, 0.0054626464843750, 0.0014648437500000, +0.0044555664062500}, +{0.0026855468750000, 0.0025939941406250, 0.0029602050781250, 0.0026245117187500, +0.0028686523437500, 0.0025024414062500, 0.0029602050781250, 0.0026855468750000, +0.0029907226562500, 0.0025939941406250, 0.0030212402343750, 0.0026855468750000, +0.0030212402343750, 0.0027770996093750, 0.0030517578125000, 0.0027160644531250, +0.0032653808593750, 0.0028686523437500, 0.0031433105468750, 0.0026855468750000, +0.0032958984375000, 0.0028991699218750, 0.0035400390625000, 0.0031127929687500, +0.0033264160156250, 0.0028381347656250, 0.0033569335937500, 0.0032958984375000, +0.0035400390625000, 0.0031127929687500, 0.0031433105468750, 0.0032348632812500, +0.0029602050781250, 0.0036010742187500, 0.0032043457031250, 0.0032653808593750, +0.0022583007812500, 0.0036010742187500, 0.0024719238281250, 0.0036315917968750, +0.0022277832031250, 0.0036010742187500, 0.0014343261718750, 0.0037231445312500, +0.0018920898437500, 0.0036010742187500, 0.0014343261718750, 0.0036010742187500, +0.0014038085937500, 0.0036621093750000, 0.0017700195312500, 0.0036315917968750, +0.0018005371093750, 0.0036315917968750, 0.0018615722656250, 0.0037231445312500, +0.0027160644531250, 0.0035400390625000, 0.0026245117187500, 0.0036315917968750, +0.0029907226562500, 0.0034790039062500, 0.0037536621093750, 0.0032958984375000, +0.0034790039062500, 0.0034790039062500, 0.0038757324218750, 0.0029907226562500, +0.0041198730468750, 0.0030822753906250, 0.0038452148437500, 0.0029907226562500, +0.0037536621093750, 0.0027160644531250, 0.0038452148437500, 0.0028686523437500, +0.0032958984375000, 0.0028076171875000, 0.0032958984375000, 0.0028076171875000, +0.0031738281250000, 0.0028076171875000, 0.0027465820312500, 0.0028686523437500, +0.0028686523437500, 0.0029296875000000, 0.0028076171875000, 0.0028381347656250, +0.0026245117187500, 0.0029602050781250, 0.0026855468750000, 0.0028381347656250, +0.0027160644531250, 0.0027160644531250, 0.0025634765625000, 0.0028991699218750, +0.0025939941406250, 0.0026245117187500, 0.0025024414062500, 0.0026245117187500, +0.0024719238281250, 0.0026550292968750, 0.0024719238281250, 0.0025329589843750, +0.0023498535156250, 0.0025939941406250, 0.0023498535156250, 0.0026855468750000, +0.0023193359375000, 0.0025634765625000, 0.0022277832031250, 0.0027160644531250, +0.0021972656250000, 0.0028686523437500, 0.0022277832031250, 0.0025634765625000, +0.0021667480468750, 0.0028686523437500, 0.0022583007812500, 0.0028076171875000, +0.0020751953125000, 0.0027465820312500, 0.0019226074218750, 0.0028076171875000, +0.0021362304687500, 0.0027465820312500, 0.0014648437500000, 0.0026550292968750, +0.0017700195312500, 0.0027160644531250, 0.0016174316406250, 0.0026550292968750, +0.0010986328125000, 0.0025939941406250, 0.0015869140625000, 0.0025939941406250, +0.0009460449218750, 0.0022888183593750, 0.0007934570312500, 0.0023498535156250, +0.0010375976562500, 0.0022277832031250, 0.0008239746093750, 0.0019836425781250, +0.0007324218750000, 0.0021057128906250, 0.0015563964843750, 0.0017700195312500, +0.0010986328125000, 0.0017089843750000, 0.0017700195312500, 0.0017395019531250, +0.0028381347656250, 0.0015563964843750, 0.0020751953125000, 0.0015258789062500, +0.0039367675781250, 0.0016174316406250, 0.0038452148437500, 0.0014343261718750, +0.0038757324218750, 0.0015869140625000, 0.0051269531250000, 0.0018005371093750, +0.0049743652343750, 0.0015563964843750, 0.0046997070312500, 0.0020446777343750, +0.0050048828125000, 0.0018310546875000, 0.0048522949218750, 0.0018615722656250, +0.0046081542968750, 0.0022277832031250, 0.0049743652343750, 0.0019531250000000, +0.0041809082031250, 0.0020751953125000, 0.0043945312500000, 0.0020751953125000, +0.0040588378906250, 0.0019836425781250, 0.0035095214843750, 0.0018920898437500, +0.0040283203125000, 0.0019226074218750, 0.0028076171875000, 0.0019531250000000, +0.0030212402343750, 0.0018310546875000, 0.0028381347656250, 0.0018615722656250, +0.0020751953125000, 0.0020141601562500, 0.0026245117187500, 0.0018615722656250, +0.0020141601562500, 0.0018310546875000, 0.0018920898437500, 0.0018005371093750, +0.0020446777343750, 0.0017700195312500, 0.0018920898437500, 0.0016174316406250, +0.0018005371093750, 0.0015563964843750, 0.0016174316406250, 0.0016174316406250, +0.0014953613281250, 0.0014953613281250, 0.0013427734375000, 0.0014953613281250, +0.0010681152343750, 0.0015869140625000, 0.0009765625000000, 0.0013732910156250, +0.0008239746093750, 0.0014953613281250, 0.0006408691406250, 0.0014343261718750, +0.0006713867187500, 0.0013427734375000, 0.0006713867187500, 0.0013427734375000, +0.0003662109375000, 0.0012817382812500, 0.0005493164062500, 0.0010070800781250, +0.0005798339843750, 0.0009155273437500, 0.0003967285156250, 0.0009765625000000, +0.0003356933593750, 0.0007629394531250, 0.0002746582031250, 0.0007019042968750, +0.0001831054687500, 0.0010681152343750, -0.0000305175781250, 0.0007019042968750, +0.0002441406250000, 0.0011291503906250, 0.0003356933593750, 0.0016174316406250, +-0.0000610351562500, 0.0010375976562500, 0.0010070800781250, 0.0021667480468750, +0.0006713867187500, 0.0018920898437500, 0.0010070800781250, 0.0019531250000000, +0.0018920898437500, 0.0025939941406250, 0.0013122558593750, 0.0021057128906250, +0.0023193359375000, 0.0025024414062500, 0.0023193359375000, 0.0024414062500000, +0.0022583007812500, 0.0023498535156250, 0.0026855468750000, 0.0025329589843750, +0.0025024414062500, 0.0024108886718750, 0.0023803710937500, 0.0024414062500000, +0.0024108886718750, 0.0025329589843750, 0.0022583007812500, 0.0024414062500000, +0.0020141601562500, 0.0024108886718750, 0.0020141601562500, 0.0025329589843750, +0.0020141601562500, 0.0022583007812500, 0.0017395019531250, 0.0025024414062500, +0.0018920898437500, 0.0023193359375000, 0.0021057128906250, 0.0021057128906250, +0.0016174316406250, 0.0024719238281250, 0.0022888183593750, 0.0017089843750000, +0.0019836425781250, 0.0018615722656250, 0.0019531250000000, 0.0018310546875000, +0.0023498535156250, 0.0012817382812500, 0.0018615722656250, 0.0016174316406250, +0.0023803710937500, 0.0013122558593750, 0.0019836425781250, 0.0012207031250000, +0.0020446777343750, 0.0012817382812500, 0.0023498535156250, 0.0012817382812500, +0.0017089843750000, 0.0012512207031250, 0.0024414062500000, 0.0012207031250000, +0.0020141601562500, 0.0013122558593750, 0.0020141601562500, 0.0010070800781250, +0.0024719238281250, 0.0007629394531250, 0.0018005371093750, 0.0009765625000000, +0.0025024414062500, 0.0001525878906250, 0.0021667480468750, 0.0002136230468750, +0.0021972656250000, 0.0000000000000000, 0.0026245117187500, -0.0007019042968750, +0.0019836425781250, -0.0004577636718750, 0.0025939941406250, -0.0007934570312500, +0.0023193359375000, -0.0010681152343750, 0.0023193359375000, -0.0007324218750000, +0.0027160644531250, -0.0006408691406250, 0.0022888183593750, -0.0009155273437500, +0.0028381347656250, 0.0001525878906250, 0.0025939941406250, -0.0001831054687500, +0.0026550292968750, 0.0003051757812500, 0.0030822753906250, 0.0012817382812500, +0.0026550292968750, 0.0006408691406250, 0.0030212402343750, 0.0022888183593750, +0.0029907226562500, 0.0020751953125000, 0.0029602050781250, 0.0024719238281250, +0.0031433105468750, 0.0036315917968750, 0.0029907226562500, 0.0029907226562500, +0.0031738281250000, 0.0041503906250000, 0.0031738281250000, 0.0041503906250000, +0.0030822753906250, 0.0041503906250000, 0.0032348632812500, 0.0046997070312500, +0.0032043457031250, 0.0044860839843750, 0.0032043457031250, 0.0042419433593750, +0.0032043457031250, 0.0044860839843750, 0.0032348632812500, 0.0040283203125000, +0.0031433105468750, 0.0034790039062500, 0.0030822753906250, 0.0039672851562500, +0.0031738281250000, 0.0026550292968750, 0.0031127929687500, 0.0028381347656250, +0.0031433105468750, 0.0024414062500000, 0.0032653808593750, 0.0014648437500000, +0.0031127929687500, 0.0019226074218750, 0.0032958984375000, 0.0010986328125000, +0.0032043457031250, 0.0010375976562500, 0.0031433105468750, 0.0010070800781250, +0.0032348632812500, 0.0005798339843750, 0.0031738281250000, 0.0007019042968750, +0.0028991699218750, 0.0005798339843750, 0.0030212402343750, 0.0003662109375000, +0.0026855468750000, 0.0006103515625000, 0.0024108886718750, 0.0007324218750000, +0.0026550292968750, 0.0004882812500000, 0.0018615722656250, 0.0011596679687500, +0.0020446777343750, 0.0009765625000000, 0.0018920898437500, 0.0011901855468750, +0.0014038085937500, 0.0017395019531250, 0.0017089843750000, 0.0014038085937500, +0.0013732910156250, 0.0021057128906250, 0.0013732910156250, 0.0019531250000000, +0.0014953613281250, 0.0020751953125000, 0.0014953613281250, 0.0025939941406250, +0.0014953613281250, 0.0022583007812500, 0.0016479492187500, 0.0027160644531250, +0.0016479492187500, 0.0026855468750000, 0.0017089843750000, 0.0026855468750000, +0.0018005371093750, 0.0030212402343750, 0.0017700195312500, 0.0028076171875000, +0.0018310546875000, 0.0028686523437500, 0.0018310546875000, 0.0029907226562500, +0.0019836425781250, 0.0029602050781250, 0.0020446777343750, 0.0029602050781250, +0.0020141601562500, 0.0030517578125000, 0.0023498535156250, 0.0029602050781250, +0.0022277832031250, 0.0032043457031250, 0.0024719238281250, 0.0030517578125000, +0.0028686523437500, 0.0028381347656250, 0.0025634765625000, 0.0031127929687500, +0.0031738281250000, 0.0025024414062500, 0.0032043457031250, 0.0025634765625000, +0.0030212402343750, 0.0024108886718750, 0.0032653808593750, 0.0019531250000000, +0.0032043457031250, 0.0021057128906250, 0.0027465820312500, 0.0017089843750000, +0.0028991699218750, 0.0016479492187500, 0.0026550292968750, 0.0014953613281250, +0.0021667480468750, 0.0012207031250000, 0.0025329589843750, 0.0013122558593750, +0.0021667480468750, 0.0010070800781250, 0.0021972656250000, 0.0009460449218750, +0.0022583007812500, 0.0008850097656250, 0.0021362304687500, 0.0007019042968750, +0.0024108886718750, 0.0007934570312500, 0.0019836425781250, 0.0005798339843750, +0.0023193359375000, 0.0006713867187500, 0.0019836425781250, 0.0004882812500000, +0.0014648437500000, 0.0002441406250000, 0.0019836425781250, 0.0005798339843750, +0.0010375976562500, -0.0003662109375000, 0.0011596679687500, -0.0002746582031250, +0.0011291503906250, 0.0000000000000000, 0.0004882812500000, -0.0004577636718750, +0.0007324218750000, -0.0003662109375000, 0.0008239746093750, 0.0005187988281250, +0.0006103515625000, 0.0003662109375000, 0.0008239746093750, 0.0008544921875000, +0.0010375976562500, 0.0016784667968750, 0.0008239746093750, 0.0012817382812500, +0.0013732910156250, 0.0025329589843750, 0.0012207031250000, 0.0024719238281250, +0.0013122558593750, 0.0024719238281250, 0.0019226074218750, 0.0035095214843750, +0.0030212402343750, 0.0010070800781250, 0.0032653808593750, 0.0015258789062500, +0.0032653808593750, 0.0014953613281250, 0.0029296875000000, 0.0019531250000000, +0.0028991699218750, 0.0022277832031250, 0.0030517578125000, 0.0018310546875000, +0.0022583007812500, 0.0027770996093750, 0.0025329589843750, 0.0026550292968750, +0.0021362304687500, 0.0029602050781250, 0.0014953613281250, 0.0036621093750000, +0.0020141601562500, 0.0031433105468750, 0.0008544921875000, 0.0037536621093750, +0.0010375976562500, 0.0041503906250000, 0.0009460449218750, 0.0035095214843750, +0.0001525878906250, 0.0031433105468750, 0.0005187988281250, 0.0035400390625000, +0.0003967285156250}, +{0.0031433105468750, 0.0005187988281250, 0.0032653808593750, 0.0000915527343750, +0.0031127929687500, -0.0000915527343750, 0.0031738281250000, -0.0000915527343750, +0.0032958984375000, -0.0002441406250000, 0.0030822753906250, -0.0003662109375000, +0.0035095214843750, 0.0000305175781250, 0.0033264160156250, -0.0002746582031250, +0.0033264160156250, 0.0000305175781250, 0.0036621093750000, 0.0005493164062500, +0.0034179687500000, 0.0001220703125000, 0.0035400390625000, 0.0008850097656250, +0.0035400390625000, 0.0008239746093750, 0.0032958984375000, 0.0008850097656250, +0.0031433105468750, 0.0014648437500000, 0.0031738281250000, 0.0012512207031250, +0.0027770996093750, 0.0015869140625000, 0.0026855468750000, 0.0015869140625000, +0.0025634765625000, 0.0018310546875000, 0.0023498535156250, 0.0021362304687500, +0.0023498535156250, 0.0019531250000000, 0.0024414062500000, 0.0026245117187500, +0.0021667480468750, 0.0025024414062500, 0.0023803710937500, 0.0026550292968750, +0.0026550292968750, 0.0031127929687500, 0.0023193359375000, 0.0028686523437500, +0.0028686523437500, 0.0033569335937500, 0.0027465820312500, 0.0032348632812500, +0.0027465820312500, 0.0032958984375000, 0.0030822753906250, 0.0036621093750000, +0.0028686523437500, 0.0034179687500000, 0.0028991699218750, 0.0039672851562500, +0.0029602050781250, 0.0039062500000000, 0.0027770996093750, 0.0040283203125000, +0.0025634765625000, 0.0043640136718750, 0.0027160644531250, 0.0041198730468750, +0.0024414062500000, 0.0043640136718750, 0.0024719238281250, 0.0043029785156250, +0.0024108886718750, 0.0041503906250000, 0.0022888183593750, 0.0042724609375000, +0.0024719238281250, 0.0040893554687500, 0.0018920898437500, 0.0036621093750000, +0.0021667480468750, 0.0037231445312500, 0.0018005371093750, 0.0035095214843750, +0.0011901855468750, 0.0031127929687500, 0.0017089843750000, 0.0032958984375000, +0.0010681152343750, 0.0028686523437500, 0.0009460449218750, 0.0028991699218750, +0.0011596679687500, 0.0027465820312500, 0.0010070800781250, 0.0025634765625000, +0.0008850097656250, 0.0027160644531250, 0.0014953613281250, 0.0019531250000000, +0.0012512207031250, 0.0023803710937500, 0.0015258789062500, 0.0017395019531250, +0.0021362304687500, 0.0007629394531250, 0.0017089843750000, 0.0015563964843750, +0.0024719238281250, 0.0003967285156250, 0.0023193359375000, 0.0002746582031250, +0.0024108886718750, 0.0005493164062500, 0.0028991699218750, 0.0002746582031250, +0.0025024414062500, 0.0003967285156250, 0.0030822753906250, 0.0006103515625000, +0.0029602050781250, 0.0005187988281250, 0.0028686523437500, 0.0007934570312500, +0.0033569335937500, 0.0013732910156250, 0.0034790039062500, 0.0023498535156250, +0.0026245117187500, 0.0019836425781250, 0.0032653808593750, 0.0020751953125000, +0.0024719238281250, 0.0019836425781250, 0.0016784667968750, 0.0018615722656250, +0.0023498535156250, 0.0021362304687500, 0.0009155273437500, 0.0022583007812500, +0.0010986328125000, 0.0022277832031250, 0.0010070800781250, 0.0021667480468750, +0.0000610351562500, 0.0021057128906250, 0.0005187988281250, 0.0021972656250000, +0.0001220703125000, 0.0027465820312500, 0.0001220703125000, 0.0022888183593750, +0.0002441406250000, 0.0027160644531250, 0.0002136230468750, 0.0035400390625000, +0.0004272460937500, 0.0029907226562500, 0.0003967285156250, 0.0035400390625000, +0.0005187988281250, 0.0036010742187500, 0.0005493164062500, 0.0034484863281250, +0.0004577636718750, 0.0036010742187500, 0.0006103515625000, 0.0035095214843750, +0.0006713867187500, 0.0031127929687500, 0.0006103515625000, 0.0031127929687500, +0.0007629394531250, 0.0028686523437500, 0.0009155273437500, 0.0024719238281250, +0.0008850097656250, 0.0025329589843750, 0.0011291503906250, 0.0024414062500000, +0.0011291503906250, 0.0021972656250000, 0.0011291503906250, 0.0023193359375000, +0.0012512207031250, 0.0025329589843750, 0.0013122558593750, 0.0023498535156250, +0.0015563964843750, 0.0023498535156250, 0.0014038085937500, 0.0025939941406250, +0.0020446777343750, 0.0020141601562500, 0.0025634765625000, 0.0014953613281250, +0.0020446777343750, 0.0018615722656250, 0.0040283203125000, 0.0005187988281250, +0.0036010742187500, 0.0004272460937500, 0.0040893554687500, 0.0005187988281250, +0.0057373046875000, -0.0002136230468750, 0.0049133300781250, -0.0002136230468750, +0.0058898925781250, 0.0005493164062500, 0.0062866210937500, -0.0000610351562500, +0.0056762695312500, 0.0007629394531250, 0.0056762695312500, 0.0020141601562500, +0.0060119628906250, 0.0010986328125000, 0.0045166015625000, 0.0026855468750000, +0.0049133300781250, 0.0027770996093750, 0.0044250488281250, 0.0025329589843750, +0.0032348632812500, 0.0031127929687500, 0.0039672851562500, 0.0028991699218750, +0.0034790039062500, 0.0028076171875000, 0.0031433105468750, 0.0028076171875000, +0.0037536621093750, 0.0026245117187500, 0.0040283203125000, 0.0024108886718750, +0.0037841796875000, 0.0025024414062500, 0.0048828125000000, 0.0024719238281250, +0.0048522949218750, 0.0024108886718750, 0.0050354003906250, 0.0025939941406250, +0.0057373046875000, 0.0027465820312500, 0.0054931640625000, 0.0026245117187500, +0.0057067871093750, 0.0031433105468750, 0.0060119628906250, 0.0031738281250000, +0.0056152343750000, 0.0032043457031250, 0.0054321289062500, 0.0035705566406250, +0.0057373046875000, 0.0035095214843750, 0.0046691894531250, 0.0035095214843750, +0.0049743652343750, 0.0035705566406250, 0.0046386718750000, 0.0034484863281250, +0.0038146972656250, 0.0033569335937500, 0.0043334960937500, 0.0034179687500000, +0.0034484863281250, 0.0031738281250000, 0.0034484863281250, 0.0032653808593750, +0.0035095214843750, 0.0031127929687500, 0.0031433105468750, 0.0028991699218750, +0.0032958984375000, 0.0031433105468750, 0.0031433105468750, 0.0027160644531250, +0.0032348632812500, 0.0026855468750000, 0.0030517578125000, 0.0027465820312500, +0.0028686523437500, 0.0025939941406250, 0.0030822753906250, 0.0025939941406250, +0.0024414062500000, 0.0028076171875000, 0.0024719238281250, 0.0026245117187500, +0.0023498535156250, 0.0028076171875000, 0.0018920898437500, 0.0030822753906250, +0.0020446777343750, 0.0027160644531250, 0.0018005371093750, 0.0036010742187500, +0.0015869140625000, 0.0034179687500000, 0.0017395019531250, 0.0035095214843750, +0.0017395019531250, 0.0041198730468750, 0.0013427734375000, 0.0037841796875000, +0.0017395019531250, 0.0041198730468750, 0.0014953613281250, 0.0042419433593750, +0.0013732910156250, 0.0040588378906250, 0.0015869140625000, 0.0041503906250000, +0.0012512207031250, 0.0042419433593750, 0.0012207031250000, 0.0040283203125000, +0.0012207031250000, 0.0040893554687500, 0.0008850097656250, 0.0040893554687500, +0.0006713867187500, 0.0039978027343750, 0.0007019042968750, 0.0039978027343750, +0.0003051757812500, 0.0040588378906250, 0.0003356933593750, 0.0039672851562500, +0.0002441406250000, 0.0041198730468750, 0.0000305175781250, 0.0042114257812500, +0.0000305175781250, 0.0039672851562500, -0.0000915527343750, 0.0043640136718750, +-0.0001220703125000, 0.0042114257812500, -0.0001831054687500, 0.0042724609375000, +-0.0002136230468750, 0.0045166015625000, -0.0001831054687500, 0.0042724609375000, +-0.0004272460937500, 0.0046081542968750, -0.0002746582031250, 0.0045471191406250, +-0.0003051757812500, 0.0044555664062500, -0.0004272460937500, 0.0046386718750000, +-0.0003662109375000, 0.0045166015625000, -0.0005798339843750, 0.0043334960937500, +-0.0005187988281250, 0.0044250488281250, -0.0004577636718750, 0.0041503906250000, +-0.0005187988281250, 0.0039672851562500, -0.0005493164062500, 0.0041503906250000, +-0.0004577636718750, 0.0036926269531250, -0.0004577636718750, 0.0036926269531250, +-0.0004272460937500, 0.0035705566406250, -0.0003051757812500, 0.0033264160156250, +-0.0003051757812500, 0.0034790039062500, -0.0003356933593750, 0.0031738281250000, +-0.0002746582031250, 0.0031738281250000, -0.0003967285156250, 0.0031433105468750, +-0.0005798339843750, 0.0030212402343750, -0.0005798339843750, 0.0030517578125000, +-0.0005798339843750, 0.0030822753906250, -0.0008239746093750, 0.0030212402343750, +-0.0005493164062500, 0.0030822753906250, -0.0003662109375000, 0.0031433105468750, +-0.0007019042968750, 0.0030517578125000, 0.0004577636718750, 0.0031433105468750, +0.0001525878906250, 0.0031738281250000, 0.0006713867187500, 0.0031433105468750, +0.0017700195312500, 0.0030822753906250, 0.0011596679687500, 0.0031738281250000, +0.0022888183593750, 0.0031738281250000, 0.0024108886718750, 0.0030822753906250, +0.0022888183593750, 0.0031433105468750, 0.0026855468750000, 0.0031738281250000, +0.0026550292968750, 0.0030822753906250, 0.0024108886718750, 0.0031738281250000, +0.0025024414062500, 0.0032043457031250, 0.0024414062500000, 0.0031738281250000, +0.0022583007812500, 0.0031127929687500, 0.0023193359375000, 0.0030822753906250, +0.0023193359375000, 0.0031433105468750, 0.0022888183593750, 0.0030517578125000, +0.0023498535156250, 0.0029602050781250, 0.0024108886718750, 0.0029602050781250, +0.0025024414062500, 0.0029907226562500, 0.0023498535156250, 0.0028381347656250, +0.0025024414062500, 0.0028991699218750, 0.0023803710937500, 0.0027770996093750, +0.0021667480468750, 0.0025939941406250, 0.0023803710937500, 0.0025939941406250, +0.0021362304687500, 0.0022888183593750, 0.0019836425781250, 0.0021972656250000, +0.0021362304687500, 0.0021667480468750, 0.0020446777343750, 0.0019531250000000, +0.0019836425781250, 0.0018310546875000, 0.0021057128906250, 0.0019531250000000, +0.0021667480468750, 0.0018615722656250, 0.0020141601562500, 0.0018310546875000, +0.0020141601562500, 0.0018310546875000, 0.0021972656250000, 0.0017395019531250, +0.0015869140625000, 0.0020141601562500, 0.0018005371093750, 0.0019531250000000, +0.0015258789062500, 0.0019836425781250, 0.0008850097656250, 0.0022277832031250, +0.0013122558593750, 0.0021057128906250, 0.0007324218750000, 0.0022583007812500, +0.0005187988281250, 0.0023193359375000, 0.0007019042968750, 0.0022277832031250, +0.0004272460937500, 0.0022277832031250, 0.0000000000000000, 0.0021057128906250, +0.0000915527343750, 0.0019836425781250, 0.0000000000000000, 0.0020446777343750, +0.0001525878906250, 0.0020751953125000, 0.0002441406250000, 0.0020751953125000, +0.0000305175781250, 0.0021362304687500, 0.0014038085937500, 0.0019836425781250, +0.0009765625000000, 0.0020446777343750, 0.0016479492187500, 0.0020446777343750, +0.0030822753906250, 0.0019531250000000, 0.0023803710937500, 0.0021057128906250, +0.0037536621093750, 0.0018310546875000, 0.0041198730468750, 0.0019226074218750, +0.0037841796875000, 0.0019531250000000, 0.0042419433593750, 0.0018310546875000, +0.0045776367187500, 0.0019226074218750, 0.0036315917968750, 0.0019836425781250, +0.0040588378906250, 0.0020446777343750, 0.0037231445312500, 0.0020446777343750, +0.0028991699218750, 0.0021057128906250, 0.0036621093750000, 0.0021972656250000, +0.0029907226562500, 0.0021667480468750, 0.0030212402343750, 0.0022888183593750, +0.0031127929687500, 0.0024414062500000, 0.0029296875000000, 0.0024414062500000, +0.0031738281250000, 0.0025024414062500, 0.0030822753906250, 0.0030212402343750, +0.0031127929687500, 0.0028686523437500, 0.0031738281250000, 0.0033264160156250, +0.0032653808593750, 0.0039367675781250, 0.0034484863281250, 0.0035705566406250, +0.0028991699218750, 0.0042419433593750, 0.0031738281250000, 0.0042724609375000, +0.0029907226562500}, +{0.0014953613281250, 0.0035095214843750, 0.0014038085937500, 0.0033874511718750, +0.0011596679687500, 0.0032043457031250, 0.0012207031250000, 0.0033264160156250, +0.0011901855468750, 0.0031127929687500, 0.0008850097656250, 0.0031738281250000, +0.0012512207031250, 0.0031433105468750, 0.0014953613281250, 0.0030517578125000, +0.0009765625000000, 0.0031738281250000, 0.0024108886718750, 0.0030212402343750, +0.0019836425781250, 0.0030517578125000, 0.0024414062500000, 0.0030517578125000, +0.0036621093750000, 0.0029602050781250, 0.0029907226562500, 0.0029602050781250, +0.0040283203125000, 0.0029602050781250, 0.0041809082031250, 0.0029296875000000, +0.0040283203125000, 0.0029907226562500, 0.0043945312500000, 0.0030212402343750, +0.0043029785156250, 0.0029602050781250, 0.0042114257812500, 0.0029907226562500, +0.0042419433593750, 0.0030212402343750, 0.0042114257812500, 0.0028686523437500, +0.0040588378906250, 0.0028076171875000, 0.0040588378906250, 0.0028381347656250, +0.0039367675781250, 0.0025024414062500, 0.0039062500000000, 0.0025329589843750, +0.0038146972656250, 0.0024719238281250, 0.0037841796875000, 0.0021667480468750, +0.0037536621093750, 0.0021972656250000, 0.0035095214843750, 0.0021057128906250, +0.0035095214843750, 0.0019836425781250, 0.0033569335937500, 0.0020751953125000, +0.0030822753906250, 0.0021057128906250, 0.0030822753906250, 0.0019531250000000, +0.0028991699218750, 0.0020751953125000, 0.0028381347656250, 0.0019531250000000, +0.0027770996093750, 0.0020141601562500, 0.0026245117187500, 0.0020751953125000, +0.0026550292968750, 0.0018310546875000, 0.0024414062500000, 0.0020751953125000, +0.0024719238281250, 0.0020141601562500, 0.0022583007812500, 0.0019531250000000, +0.0019226074218750, 0.0019531250000000, 0.0020446777343750, 0.0018005371093750, +0.0017395019531250, 0.0020141601562500, 0.0015869140625000, 0.0018310546875000, +0.0016174316406250, 0.0018005371093750, 0.0016479492187500, 0.0020751953125000, +0.0014953613281250, 0.0018310546875000, 0.0013427734375000, 0.0021057128906250, +0.0014648437500000, 0.0020141601562500, 0.0013732910156250, 0.0020446777343750, +0.0011596679687500, 0.0021667480468750, 0.0013122558593750, 0.0020751953125000, +0.0009460449218750, 0.0023498535156250, 0.0006408691406250, 0.0021667480468750, +0.0011901855468750, 0.0023498535156250, 0.0012817382812500, 0.0027160644531250, +0.0007019042968750, 0.0025329589843750, 0.0024719238281250, 0.0029907226562500, +0.0019226074218750, 0.0029907226562500, 0.0023803710937500, 0.0030822753906250, +0.0039062500000000, 0.0033874511718750, 0.0030517578125000, 0.0033264160156250, +0.0040283203125000, 0.0033569335937500, 0.0043029785156250, 0.0034484863281250, +0.0040893554687500, 0.0034484863281250, 0.0043334960937500, 0.0033874511718750, +0.0043640136718750, 0.0035400390625000, 0.0037841796875000, 0.0035095214843750, +0.0040588378906250, 0.0034790039062500, 0.0038146972656250, 0.0036010742187500, +0.0033264160156250, 0.0036315917968750, 0.0036926269531250, 0.0036010742187500, +0.0029907226562500, 0.0037231445312500, 0.0030822753906250, 0.0037231445312500, +0.0031738281250000, 0.0036315917968750, 0.0028076171875000, 0.0036315917968750, +0.0029602050781250, 0.0036315917968750, 0.0031433105468750, 0.0032653808593750, +0.0031738281250000, 0.0033264160156250, 0.0032043457031250, 0.0031433105468750, +0.0035400390625000, 0.0028381347656250, 0.0036315917968750, 0.0030822753906250, +0.0032043457031250, 0.0024414062500000, 0.0036010742187500, 0.0024719238281250, +0.0034179687500000, 0.0023498535156250, 0.0028991699218750, 0.0018920898437500, +0.0034790039062500, 0.0021057128906250, 0.0027465820312500, 0.0018615722656250, +0.0028076171875000, 0.0017089843750000, 0.0030517578125000, 0.0018005371093750, +0.0027160644531250, 0.0017700195312500, 0.0028381347656250, 0.0015869140625000, +0.0030517578125000, 0.0018920898437500, 0.0031433105468750, 0.0017395019531250, +0.0030822753906250, 0.0016784667968750, 0.0032653808593750, 0.0019531250000000, +0.0034179687500000, 0.0016784667968750, 0.0029907226562500, 0.0016784667968750, +0.0032348632812500, 0.0017089843750000, 0.0031738281250000, 0.0015563964843750, +0.0027770996093750, 0.0014038085937500, 0.0030822753906250, 0.0014648437500000, +0.0030822753906250, 0.0011901855468750, 0.0029296875000000, 0.0011291503906250, +0.0032653808593750, 0.0012207031250000, 0.0035705566406250, 0.0010375976562500, +0.0033874511718750, 0.0010070800781250, 0.0039978027343750, 0.0012817382812500, +0.0040893554687500, 0.0009460449218750, 0.0041809082031250, 0.0012207031250000, +0.0046691894531250, 0.0015563964843750, 0.0046997070312500, 0.0010375976562500, +0.0046997070312500, 0.0020751953125000, 0.0049743652343750, 0.0017700195312500, +0.0048522949218750, 0.0020751953125000, 0.0046997070312500, 0.0028991699218750, +0.0049438476562500, 0.0023498535156250, 0.0045471191406250, 0.0034179687500000, +0.0046081542968750, 0.0032958984375000, 0.0046081542968750, 0.0035095214843750, +0.0043029785156250, 0.0042114257812500, 0.0045166015625000, 0.0038146972656250, +0.0043945312500000, 0.0045166015625000, 0.0043945312500000, 0.0046081542968750, +0.0043945312500000, 0.0044860839843750, 0.0043029785156250, 0.0047302246093750, +0.0044555664062500, 0.0045776367187500, 0.0042724609375000, 0.0043640136718750, +0.0042724609375000, 0.0044250488281250, 0.0042724609375000, 0.0041198730468750, +0.0041503906250000, 0.0037841796875000, 0.0041809082031250, 0.0039978027343750, +0.0040283203125000, 0.0032043457031250, 0.0040893554687500, 0.0032958984375000, +0.0040588378906250, 0.0029296875000000, 0.0039062500000000, 0.0022583007812500, +0.0039978027343750, 0.0026855468750000, 0.0039062500000000, 0.0015869140625000, +0.0039062500000000, 0.0016784667968750, 0.0039367675781250, 0.0013732910156250, +0.0039062500000000, 0.0005798339843750, 0.0039062500000000, 0.0010375976562500, +0.0039672851562500, 0.0001525878906250, 0.0039978027343750, 0.0001525878906250, +0.0039367675781250, 0.0000610351562500, 0.0039367675781250, -0.0004272460937500, +0.0039062500000000, -0.0002136230468750, 0.0038452148437500, -0.0004882812500000, +0.0038146972656250, -0.0006408691406250, 0.0038146972656250, -0.0005187988281250, +0.0037536621093750, -0.0005493164062500, 0.0037231445312500, -0.0005798339843750, +0.0038452148437500, -0.0000915527343750, 0.0037841796875000, -0.0002746582031250, +0.0039062500000000, 0.0001220703125000, 0.0039978027343750, 0.0006103515625000, +0.0038757324218750, 0.0002746582031250, 0.0041503906250000, 0.0014038085937500, +0.0041198730468750, 0.0012512207031250, 0.0042114257812500, 0.0016174316406250, +0.0043945312500000, 0.0025329589843750, 0.0043029785156250, 0.0020446777343750, +0.0044250488281250, 0.0029602050781250, 0.0044860839843750, 0.0030517578125000, +0.0043640136718750, 0.0030212402343750, 0.0043945312500000, 0.0034790039062500, +0.0044555664062500, 0.0033874511718750, 0.0042114257812500, 0.0030212402343750, +0.0042419433593750, 0.0033569335937500, 0.0041809082031250, 0.0027465820312500, +0.0039672851562500, 0.0021057128906250, 0.0040588378906250, 0.0025939941406250, +0.0038757324218750, 0.0011901855468750, 0.0038146972656250, 0.0012512207031250, +0.0037841796875000, 0.0012207031250000, 0.0036621093750000, 0.0003662109375000, +0.0036926269531250, 0.0007324218750000, 0.0037536621093750, 0.0008850097656250, +0.0037231445312500, 0.0006103515625000, 0.0037231445312500, 0.0010681152343750, +0.0037841796875000, 0.0015869140625000, 0.0037536621093750, 0.0012817382812500, +0.0035400390625000, 0.0020446777343750, 0.0036315917968750, 0.0021667480468750, +0.0034790039062500, 0.0021667480468750, 0.0032653808593750, 0.0025634765625000, +0.0034179687500000, 0.0024719238281250, 0.0030212402343750, 0.0025634765625000, +0.0031738281250000, 0.0025634765625000, 0.0029907226562500, 0.0026855468750000, +0.0026855468750000, 0.0027465820312500, 0.0030212402343750, 0.0026855468750000, +0.0023498535156250, 0.0031738281250000, 0.0024719238281250, 0.0030517578125000, +0.0022277832031250, 0.0032043457031250, 0.0017700195312500, 0.0036621093750000, +0.0021667480468750, 0.0034179687500000, 0.0016784667968750, 0.0036621093750000, +0.0015869140625000, 0.0037841796875000, 0.0017700195312500, 0.0036926269531250, +0.0016174316406250, 0.0036926269531250, 0.0015563964843750, 0.0038146972656250, +0.0020446777343750, 0.0034179687500000, 0.0018005371093750, 0.0034790039062500, +0.0019226074218750, 0.0034179687500000, 0.0023498535156250, 0.0032043457031250, +0.0019836425781250, 0.0031738281250000, 0.0023498535156250, 0.0029296875000000, +0.0022583007812500, 0.0028991699218750, 0.0022277832031250, 0.0028381347656250, +0.0023803710937500, 0.0026550292968750, 0.0021667480468750, 0.0026245117187500, +0.0025634765625000, 0.0025329589843750, 0.0023498535156250, 0.0024719238281250, +0.0025634765625000, 0.0024719238281250, 0.0029296875000000, 0.0025024414062500, +0.0025329589843750, 0.0023498535156250, 0.0031738281250000, 0.0024414062500000, +0.0031127929687500, 0.0023803710937500, 0.0029907226562500, 0.0023193359375000, +0.0033569335937500, 0.0022888183593750, 0.0031433105468750, 0.0021667480468750, +0.0028381347656250, 0.0024719238281250, 0.0030212402343750, 0.0022583007812500, +0.0026245117187500, 0.0023498535156250, 0.0017395019531250, 0.0029907226562500, +0.0002746582031250, 0.0016784667968750, 0.0006713867187500, 0.0030822753906250, +0.0002136230468750, 0.0026550292968750, 0.0008544921875000, 0.0027465820312500, +0.0014953613281250, 0.0033569335937500, 0.0009765625000000, 0.0031433105468750, +0.0021057128906250, 0.0027770996093750, 0.0019531250000000, 0.0029907226562500, +0.0021667480468750, 0.0029907226562500, 0.0028381347656250, 0.0026245117187500, +0.0023803710937500, 0.0026245117187500, 0.0034179687500000, 0.0034484863281250, +0.0032348632812500, 0.0034790039062500, 0.0034790039062500, 0.0034179687500000, +0.0042724609375000, 0.0038146972656250, 0.0037536621093750, 0.0039672851562500, +0.0045166015625000, 0.0035705566406250, 0.0045166015625000, 0.0037231445312500, +0.0045166015625000, 0.0034790039062500, 0.0048522949218750, 0.0029907226562500, +0.0046997070312500, 0.0032348632812500, 0.0051879882812500, 0.0030212402343750, +0.0048828125000000, 0.0026855468750000, 0.0052795410156250, 0.0030212402343750, +0.0058898925781250, 0.0032653808593750, 0.0054626464843750, 0.0029602050781250, +0.0062255859375000, 0.0034484863281250, 0.0063476562500000, 0.0034179687500000, +0.0059814453125000, 0.0033264160156250, 0.0062561035156250, 0.0035095214843750, +0.0063476562500000, 0.0032958984375000, 0.0051574707031250, 0.0030212402343750, +0.0056762695312500, 0.0030212402343750, 0.0048828125000000, 0.0028381347656250, +0.0035095214843750, 0.0025634765625000, 0.0044860839843750, 0.0025329589843750, +0.0024108886718750, 0.0026245117187500, 0.0025939941406250, 0.0024108886718750, +0.0025024414062500, 0.0026245117187500, 0.0013427734375000, 0.0027770996093750, +0.0019531250000000, 0.0024108886718750, 0.0014648437500000, 0.0032653808593750, +0.0014038085937500, 0.0032653808593750, 0.0015563964843750, 0.0029602050781250, +0.0015563964843750, 0.0032043457031250, 0.0017395019531250, 0.0030822753906250, +0.0012817382812500, 0.0022583007812500, 0.0016784667968750, 0.0023193359375000, +0.0013122558593750, 0.0020141601562500, 0.0007629394531250, 0.0012512207031250, +0.0014038085937500}, +{0.0027770996093750, 0.0022277832031250, 0.0025939941406250, 0.0018005371093750, +0.0032958984375000, 0.0028076171875000, 0.0032653808593750, 0.0026550292968750, +0.0032653808593750, 0.0029602050781250, 0.0036621093750000, 0.0038146972656250, +0.0034179687500000, 0.0034484863281250, 0.0033569335937500, 0.0042419433593750, +0.0034179687500000, 0.0043640136718750, 0.0031433105468750, 0.0043640136718750, +0.0029296875000000, 0.0047302246093750, 0.0030212402343750, 0.0045471191406250, +0.0026550292968750, 0.0044250488281250, 0.0025634765625000, 0.0046081542968750, +0.0025634765625000, 0.0042114257812500, 0.0023803710937500, 0.0037841796875000, +0.0023803710937500, 0.0040283203125000, 0.0025024414062500, 0.0032348632812500, +0.0023803710937500, 0.0031433105468750, 0.0023498535156250, 0.0030517578125000, +0.0024414062500000, 0.0027465820312500, 0.0022888183593750, 0.0028076171875000, +0.0020141601562500, 0.0025024414062500, 0.0021362304687500, 0.0025939941406250, +0.0017089843750000, 0.0024414062500000, 0.0012817382812500, 0.0021057128906250, +0.0016174316406250, 0.0022888183593750, 0.0005798339843750, 0.0018615722656250, +0.0005493164062500, 0.0016784667968750, 0.0006408691406250, 0.0019836425781250, +0.0000000000000000, 0.0022583007812500, 0.0006713867187500, 0.0026550292968750, +0.0019836425781250, 0.0019226074218750, 0.0015258789062500, 0.0017700195312500, +0.0019226074218750, 0.0020141601562500, 0.0026245117187500, 0.0020141601562500, +0.0022583007812500, 0.0019226074218750, 0.0031127929687500, 0.0025939941406250, +0.0028991699218750, 0.0025634765625000, 0.0031738281250000, 0.0021667480468750, +0.0038146972656250, 0.0022888183593750, 0.0032958984375000, 0.0024414062500000, +0.0042419433593750, 0.0018005371093750, 0.0040588378906250, 0.0016174316406250, +0.0042419433593750, 0.0019531250000000, 0.0047912597656250, 0.0020141601562500, +0.0043334960937500, 0.0018005371093750, 0.0054626464843750, 0.0026550292968750, +0.0050354003906250, 0.0025329589843750, 0.0053405761718750, 0.0027160644531250, +0.0063476562500000, 0.0034484863281250, 0.0055847167968750, 0.0032043457031250, +0.0065002441406250, 0.0033569335937500, 0.0065917968750000, 0.0035705566406250, +0.0059509277343750, 0.0034790039062500, 0.0060424804687500, 0.0033264160156250, +0.0062255859375000, 0.0033264160156250, 0.0047912597656250, 0.0032043457031250, +0.0050964355468750, 0.0031127929687500, 0.0043640136718750, 0.0031433105468750, +0.0030822753906250, 0.0031127929687500, 0.0037231445312500, 0.0030212402343750, +0.0021057128906250, 0.0034179687500000, 0.0019836425781250, 0.0033264160156250, +0.0019226074218750, 0.0035400390625000, 0.0011901855468750, 0.0040283203125000, +0.0014038085937500, 0.0038146972656250, 0.0008850097656250, 0.0038146972656250, +0.0009155273437500, 0.0039672851562500, 0.0006713867187500, 0.0034790039062500, +0.0002746582031250, 0.0031127929687500, 0.0004882812500000, 0.0032958984375000, +-0.0003356933593750, 0.0025329589843750, -0.0001525878906250, 0.0022583007812500, +-0.0004577636718750, 0.0025634765625000, -0.0011291503906250, 0.0024719238281250, +-0.0006713867187500, 0.0021667480468750, -0.0014038085937500, 0.0031738281250000, +-0.0013732910156250, 0.0028381347656250, -0.0012817382812500, 0.0028991699218750, +-0.0015869140625000, 0.0035705566406250, -0.0013427734375000, 0.0030517578125000, +-0.0014648437500000, 0.0032043457031250, -0.0014648437500000, 0.0032653808593750, +-0.0014953613281250, 0.0028076171875000, -0.0015258789062500, 0.0024414062500000, +-0.0014038085937500, 0.0025329589843750, -0.0020141601562500, 0.0021667480468750, +-0.0017700195312500, 0.0018920898437500, -0.0021362304687500, 0.0020446777343750, +-0.0027465820312500, 0.0019836425781250, -0.0023803710937500, 0.0018005371093750, +-0.0032653808593750, 0.0025634765625000, -0.0034179687500000, 0.0023193359375000, +-0.0031433105468750, 0.0025939941406250, -0.0034484863281250, 0.0033264160156250, +-0.0036010742187500, 0.0030212402343750, -0.0025939941406250, 0.0033569335937500, +-0.0031127929687500, 0.0036010742187500, -0.0024108886718750, 0.0034179687500000, +-0.0013732910156250, 0.0033874511718750, -0.0021057128906250, 0.0035400390625000, +-0.0003051757812500, 0.0031127929687500, -0.0005493164062500, 0.0032043457031250, +-0.0003356933593750, 0.0031127929687500, 0.0009155273437500, 0.0027770996093750, +0.0003662109375000, 0.0031738281250000, 0.0007324218750000, 0.0027770996093750, +0.0011596679687500, 0.0028076171875000, 0.0006103515625000, 0.0030212402343750, +0.0004272460937500, 0.0028991699218750, 0.0007629394531250, 0.0030822753906250, +-0.0005798339843750, 0.0032958984375000, -0.0002746582031250, 0.0032958984375000, +-0.0006103515625000, 0.0035095214843750, -0.0016784667968750, 0.0036621093750000, +-0.0011291503906250, 0.0035705566406250, -0.0018310546875000, 0.0038146972656250, +-0.0021057128906250, 0.0037536621093750, -0.0017089843750000, 0.0037536621093750, +-0.0017395019531250, 0.0037841796875000, -0.0019531250000000, 0.0036621093750000, +-0.0006408691406250, 0.0035095214843750, -0.0009765625000000, 0.0034484863281250, +-0.0003662109375000, 0.0032653808593750, 0.0009155273437500, 0.0030822753906250, +0.0002746582031250, 0.0030212402343750, 0.0018920898437500, 0.0027160644531250, +0.0018615722656250, 0.0027770996093750, 0.0021667480468750, 0.0026245117187500, +0.0031738281250000, 0.0023803710937500, 0.0026855468750000, 0.0025634765625000, +0.0035400390625000, 0.0022888183593750, 0.0036315917968750, 0.0023803710937500, +0.0036010742187500, 0.0021667480468750, 0.0040893554687500, 0.0019531250000000, +0.0040283203125000, 0.0021667480468750, 0.0039672851562500, 0.0017089843750000, +0.0041198730468750, 0.0016784667968750, 0.0038452148437500, 0.0015869140625000, +0.0036315917968750, 0.0012817382812500, 0.0038146972656250, 0.0013732910156250, +0.0031433105468750, 0.0013122558593750, 0.0031433105468750, 0.0012207031250000, +0.0029907226562500, 0.0012817382812500, 0.0024414062500000, 0.0013122558593750, +0.0025024414062500, 0.0012817382812500, 0.0021972656250000, 0.0014648437500000, +0.0019836425781250, 0.0014648437500000, 0.0021057128906250, 0.0015258789062500, +0.0020446777343750, 0.0016784667968750, 0.0018615722656250, 0.0016174316406250, +0.0023498535156250, 0.0018920898437500, 0.0021667480468750, 0.0018310546875000, +0.0024108886718750, 0.0018615722656250, 0.0028991699218750, 0.0020751953125000, +0.0025939941406250, 0.0020141601562500, 0.0031738281250000, 0.0021972656250000, +0.0031433105468750, 0.0021972656250000, 0.0031127929687500, 0.0022583007812500, +0.0034179687500000, 0.0024414062500000, 0.0032653808593750, 0.0023803710937500, +0.0031738281250000, 0.0025024414062500, 0.0032653808593750, 0.0025329589843750, +0.0029907226562500, 0.0024719238281250, 0.0027770996093750, 0.0024719238281250, +0.0028686523437500, 0.0025024414062500, 0.0023498535156250, 0.0024719238281250, +0.0024414062500000, 0.0025024414062500, 0.0021362304687500, 0.0024719238281250, +0.0017089843750000, 0.0024108886718750, 0.0019836425781250, 0.0024414062500000, +0.0012207031250000, 0.0024108886718750, 0.0013427734375000, 0.0024108886718750, +0.0010986328125000, 0.0023498535156250, 0.0005187988281250, 0.0022888183593750, +0.0007934570312500, 0.0024108886718750, 0.0003356933593750, 0.0020446777343750, +0.0002136230468750, 0.0021362304687500, 0.0004272460937500, 0.0020446777343750, +0.0002746582031250, 0.0017395019531250, 0.0002441406250000, 0.0019531250000000, +0.0008850097656250, 0.0016784667968750, 0.0006408691406250, 0.0017089843750000, +0.0010375976562500, 0.0016784667968750, 0.0017395019531250, 0.0015258789062500, +0.0012512207031250, 0.0016784667968750, 0.0021057128906250, 0.0016784667968750, +0.0019531250000000, 0.0016479492187500, 0.0020446777343750, 0.0017395019531250, +0.0025024414062500, 0.0018005371093750, 0.0021667480468750, 0.0018005371093750, +0.0027160644531250, 0.0018920898437500, 0.0025634765625000, 0.0018920898437500, +0.0027160644531250, 0.0019531250000000, 0.0031433105468750, 0.0019531250000000, +0.0028686523437500, 0.0018615722656250, 0.0032348632812500, 0.0018615722656250, +0.0032653808593750, 0.0018005371093750, 0.0032348632812500, 0.0018310546875000, +0.0034179687500000, 0.0018920898437500, 0.0033569335937500, 0.0018310546875000, +0.0036621093750000, 0.0019531250000000, 0.0034790039062500, 0.0018920898437500, +0.0036621093750000, 0.0018615722656250, 0.0040893554687500, 0.0019226074218750, +0.0038452148437500, 0.0018310546875000, 0.0038146972656250, 0.0019531250000000, +0.0040893554687500, 0.0018005371093750, 0.0036621093750000, 0.0019531250000000, +0.0031738281250000, 0.0021972656250000, 0.0033264160156250, 0.0021057128906250, +0.0026855468750000, 0.0027770996093750, 0.0028076171875000, 0.0025024414062500, +0.0028686523437500, 0.0025024414062500, 0.0024719238281250, 0.0029907226562500, +0.0026550292968750, 0.0027160644531250, 0.0024414062500000, 0.0028686523437500, +0.0025329589843750, 0.0028686523437500, 0.0025024414062500, 0.0027770996093750, +0.0023803710937500, 0.0026855468750000, 0.0025939941406250, 0.0025939941406250, +0.0023193359375000, 0.0026855468750000, 0.0020141601562500, 0.0024719238281250, +0.0024108886718750, 0.0024719238281250, 0.0025634765625000, 0.0026245117187500, +0.0020141601562500, 0.0023193359375000, 0.0029907226562500, 0.0026855468750000, +0.0026855468750000, 0.0025024414062500, 0.0025024414062500, 0.0023803710937500, +0.0030517578125000, 0.0025024414062500, 0.0027160644531250, 0.0022888183593750, +0.0028076171875000, 0.0020751953125000, 0.0028076171875000, 0.0020446777343750, +0.0028381347656250, 0.0017700195312500, 0.0028991699218750, 0.0014648437500000, +0.0028686523437500, 0.0014648437500000, 0.0032958984375000, 0.0010070800781250, +0.0030822753906250, 0.0008239746093750, 0.0032348632812500, 0.0007324218750000, +0.0038146972656250, 0.0004882812500000, 0.0036621093750000, 0.0003967285156250, +0.0033874511718750, 0.0004882812500000, 0.0037841796875000, 0.0002746582031250, +0.0033264160156250, 0.0003967285156250, 0.0028076171875000, 0.0006103515625000, +0.0033569335937500, 0.0003967285156250, 0.0022583007812500, 0.0006408691406250, +0.0024108886718750, 0.0007324218750000, 0.0023498535156250, 0.0006408691406250, +0.0017089843750000, 0.0007324218750000, 0.0020751953125000, 0.0008850097656250, +0.0020141601562500, 0.0006408691406250, 0.0018310546875000, 0.0007934570312500, +0.0021362304687500, 0.0007629394531250, 0.0024414062500000, 0.0005798339843750, +0.0023193359375000, 0.0007934570312500, 0.0024414062500000, 0.0006713867187500, +0.0025939941406250, 0.0007324218750000, 0.0025329589843750, 0.0007324218750000, +0.0024414062500000, 0.0006713867187500, 0.0024719238281250, 0.0008544921875000, +0.0023193359375000, 0.0005798339843750, 0.0022888183593750, 0.0007324218750000, +0.0021667480468750, 0.0007324218750000, 0.0019531250000000, 0.0006103515625000, +0.0019531250000000, 0.0006408691406250, 0.0017089843750000, 0.0007019042968750, +0.0015869140625000, 0.0006713867187500, 0.0015563964843750, 0.0008239746093750, +0.0014343261718750, 0.0009460449218750, 0.0012512207031250, 0.0009765625000000, +0.0012207031250000, 0.0011291503906250, 0.0011291503906250, 0.0012207031250000, +0.0010070800781250, 0.0012512207031250, 0.0009155273437500, 0.0013732910156250, +0.0007629394531250, 0.0014648437500000, 0.0006713867187500, 0.0011901855468750, +0.0004882812500000}, +{0.0023803710937500, 0.0019226074218750, 0.0022583007812500, 0.0018005371093750, +0.0022583007812500, 0.0018615722656250, 0.0021972656250000, 0.0018920898437500, +0.0021057128906250, 0.0017395019531250, 0.0021362304687500, 0.0019226074218750, +0.0019531250000000, 0.0017700195312500, 0.0020751953125000, 0.0018310546875000, +0.0021362304687500, 0.0019836425781250, 0.0019226074218750, 0.0018310546875000, +0.0025024414062500, 0.0021362304687500, 0.0023498535156250, 0.0020751953125000, +0.0023193359375000, 0.0019836425781250, 0.0027770996093750, 0.0020446777343750, +0.0028686523437500, 0.0019836425781250, 0.0028381347656250, 0.0018005371093750, +0.0028686523437500, 0.0018005371093750, 0.0028076171875000, 0.0017395019531250, +0.0025939941406250, 0.0015258789062500, 0.0025939941406250, 0.0015869140625000, +0.0026245117187500, 0.0014343261718750, 0.0026245117187500, 0.0013732910156250, +0.0024719238281250, 0.0013732910156250, 0.0025634765625000, 0.0013427734375000, +0.0027465820312500, 0.0013732910156250, 0.0019836425781250, 0.0014038085937500, +0.0024719238281250, 0.0013732910156250, 0.0024108886718750, 0.0013427734375000, +0.0016479492187500, 0.0012512207031250, 0.0019836425781250, 0.0011901855468750, +0.0022583007812500, 0.0010375976562500, 0.0020141601562500, 0.0010986328125000, +0.0023193359375000, 0.0010070800781250, 0.0027465820312500, 0.0007629394531250, +0.0023498535156250, 0.0007934570312500, 0.0027465820312500, 0.0007629394531250, +0.0028991699218750, 0.0006408691406250, 0.0025634765625000, 0.0007934570312500, +0.0025024414062500, 0.0009155273437500, 0.0025634765625000, 0.0006713867187500, +0.0022583007812500, 0.0013427734375000, 0.0022277832031250, 0.0011596679687500, +0.0022888183593750, 0.0013427734375000, 0.0021057128906250, 0.0019226074218750, +0.0020446777343750, 0.0015563964843750, 0.0025024414062500, 0.0020751953125000, +0.0022277832031250, 0.0022277832031250, 0.0023498535156250, 0.0021362304687500, +0.0028381347656250, 0.0023193359375000, 0.0024719238281250, 0.0023498535156250, +0.0025329589843750, 0.0025024414062500, 0.0025939941406250, 0.0025024414062500, +0.0022583007812500, 0.0025634765625000, 0.0021057128906250, 0.0026550292968750, +0.0021972656250000, 0.0026550292968750, 0.0012817382812500, 0.0028381347656250, +0.0014038085937500, 0.0029602050781250, 0.0013427734375000, 0.0028991699218750, +0.0006713867187500, 0.0030212402343750, 0.0008850097656250, 0.0030517578125000, +0.0010681152343750, 0.0028991699218750, 0.0008850097656250, 0.0029907226562500, +0.0012817382812500, 0.0029602050781250, 0.0017089843750000, 0.0027465820312500, +0.0014953613281250, 0.0028381347656250, 0.0020446777343750, 0.0030517578125000, +0.0021667480468750, 0.0029907226562500, 0.0021362304687500, 0.0033874511718750, +0.0023193359375000, 0.0037841796875000, 0.0022888183593750, 0.0036010742187500, +0.0020141601562500, 0.0042419433593750, 0.0021057128906250, 0.0043945312500000, +0.0019531250000000, 0.0043029785156250, 0.0016174316406250, 0.0046081542968750, +0.0016479492187500, 0.0047302246093750, 0.0015258789062500, 0.0041198730468750, +0.0012207031250000, 0.0044860839843750, 0.0013427734375000, 0.0040893554687500, +0.0014038085937500, 0.0033569335937500, 0.0010681152343750, 0.0039062500000000, +0.0013732910156250, 0.0025939941406250, 0.0013122558593750, 0.0028076171875000, +0.0012207031250000, 0.0025024414062500, 0.0012817382812500, 0.0015258789062500, +0.0010681152343750, 0.0020751953125000, 0.0012817382812500, 0.0011291503906250, +0.0010375976562500, 0.0012207031250000, 0.0011291503906250, 0.0010986328125000, +0.0012512207031250, 0.0005493164062500, 0.0008850097656250, 0.0008239746093750, +0.0016784667968750, 0.0001525878906250, 0.0013732910156250, 0.0003662109375000, +0.0015258789062500, 0.0001525878906250, 0.0021362304687500, -0.0003662109375000, +0.0016174316406250, 0.0000305175781250, 0.0024414062500000, -0.0005798339843750, +0.0021972656250000, -0.0005493164062500, 0.0021667480468750, -0.0003051757812500, +0.0026855468750000, -0.0005187988281250, 0.0021972656250000, -0.0003662109375000, +0.0025939941406250, 0.0002136230468750, 0.0025024414062500, 0.0000610351562500, +0.0024719238281250, 0.0004882812500000, 0.0026550292968750, 0.0010986328125000, +0.0023803710937500, 0.0007324218750000, 0.0025634765625000, 0.0016784667968750, +0.0024719238281250, 0.0015869140625000, 0.0025024414062500, 0.0018005371093750, +0.0026855468750000, 0.0023498535156250, 0.0024719238281250, 0.0020751953125000, +0.0026550292968750, 0.0026550292968750, 0.0027160644531250, 0.0025634765625000, +0.0025634765625000, 0.0026855468750000, 0.0025634765625000, 0.0031127929687500, +0.0026550292968750, 0.0029296875000000, 0.0023498535156250, 0.0033569335937500, +0.0024414062500000, 0.0033264160156250, 0.0022888183593750, 0.0034790039062500, +0.0019836425781250, 0.0037536621093750, 0.0022277832031250, 0.0036010742187500, +0.0016784667968750, 0.0039367675781250, 0.0017395019531250, 0.0039367675781250, +0.0015869140625000, 0.0039062500000000, 0.0012817382812500, 0.0041198730468750, +0.0014343261718750, 0.0040893554687500, 0.0011291503906250, 0.0038757324218750, +0.0011291503906250, 0.0039367675781250, 0.0011291503906250, 0.0038452148437500, +0.0009460449218750, 0.0036621093750000, 0.0010375976562500, 0.0036926269531250, +0.0008850097656250, 0.0035095214843750, 0.0009765625000000, 0.0035095214843750, +0.0009765625000000, 0.0033569335937500, 0.0009155273437500, 0.0031738281250000, +0.0010070800781250, 0.0032043457031250, 0.0009460449218750, 0.0028686523437500, +0.0009155273437500, 0.0028381347656250, 0.0010375976562500, 0.0027160644531250, +0.0010375976562500, 0.0025634765625000, 0.0010070800781250, 0.0025939941406250, +0.0011596679687500, 0.0023803710937500, 0.0010986328125000, 0.0023803710937500, +0.0010986328125000, 0.0024108886718750, 0.0011291503906250, 0.0023498535156250, +0.0010681152343750, 0.0022888183593750, 0.0010986328125000, 0.0027160644531250, +0.0009765625000000, 0.0025329589843750, 0.0009460449218750, 0.0028381347656250, +0.0009155273437500, 0.0033569335937500, 0.0007934570312500, 0.0030517578125000, +0.0011901855468750, 0.0037536621093750, 0.0009460449218750, 0.0038146972656250, +0.0013122558593750, 0.0036010742187500, 0.0018005371093750, 0.0038757324218750, +0.0014648437500000, 0.0038757324218750, 0.0023193359375000, 0.0032043457031250, +0.0023803710937500, 0.0033874511718750, 0.0024108886718750, 0.0030517578125000, +0.0028686523437500, 0.0022277832031250, 0.0027160644531250, 0.0025329589843750, +0.0028381347656250, 0.0021972656250000, 0.0029602050781250, 0.0019226074218750, +0.0028686523437500, 0.0021667480468750, 0.0027160644531250, 0.0021667480468750, +0.0028686523437500, 0.0020446777343750, 0.0027465820312500, 0.0024108886718750, +0.0026245117187500, 0.0022888183593750, 0.0027160644531250, 0.0022583007812500, +0.0027160644531250, 0.0025634765625000, 0.0025634765625000, 0.0024414062500000, +0.0028076171875000, 0.0022888183593750, 0.0027465820312500, 0.0023498535156250, +0.0026550292968750, 0.0021057128906250, 0.0028076171875000, 0.0018310546875000, +0.0026550292968750, 0.0019836425781250, 0.0023193359375000, 0.0018615722656250, +0.0024108886718750, 0.0018310546875000, 0.0020751953125000, 0.0018310546875000, +0.0016174316406250, 0.0018310546875000, 0.0018005371093750, 0.0018310546875000, +0.0011901855468750, 0.0021057128906250, 0.0010070800781250, 0.0020751953125000, +0.0010375976562500, 0.0021362304687500, 0.0007934570312500, 0.0023498535156250, +0.0008239746093750, 0.0023193359375000, 0.0013122558593750, 0.0024108886718750, +0.0010681152343750, 0.0023803710937500, 0.0013427734375000, 0.0025024414062500, +0.0018920898437500, 0.0025634765625000, 0.0014953613281250, 0.0024719238281250, +0.0021667480468750, 0.0028686523437500, 0.0022277832031250, 0.0027770996093750, +0.0021362304687500, 0.0028381347656250, 0.0025329589843750, 0.0033569335937500, +0.0033874511718750, 0.0023803710937500, 0.0038452148437500, 0.0030517578125000, +0.0036926269531250, 0.0024414062500000, 0.0035095214843750, 0.0028381347656250, +0.0036926269531250, 0.0034790039062500, 0.0036010742187500, 0.0030517578125000, +0.0032958984375000, 0.0033264160156250, 0.0034179687500000, 0.0035095214843750, +0.0031127929687500, 0.0030517578125000, 0.0028381347656250, 0.0027160644531250, +0.0031127929687500, 0.0028686523437500, 0.0020141601562500, 0.0022888183593750, +0.0025024414062500, 0.0022277832031250, 0.0017700195312500, 0.0021057128906250, +0.0006103515625000, 0.0017395019531250, 0.0015563964843750, 0.0019531250000000, +-0.0002441406250000, 0.0015258789062500, -0.0001831054687500, 0.0016784667968750, +-0.0001525878906250, 0.0014648437500000, -0.0010681152343750, 0.0010070800781250, +-0.0006408691406250, 0.0014343261718750, -0.0004577636718750, 0.0011596679687500, +-0.0006713867187500, 0.0007934570312500, -0.0002746582031250, 0.0014343261718750, +0.0003051757812500, 0.0018920898437500, 0.0002136230468750, 0.0014343261718750, +0.0004882812500000, 0.0029602050781250, 0.0007629394531250, 0.0027770996093750, +0.0007629394531250, 0.0033264160156250, 0.0007934570312500, 0.0046081542968750, +0.0010375976562500, 0.0040283203125000, 0.0007324218750000, 0.0047302246093750, +0.0008544921875000, 0.0050659179687500, 0.0009765625000000, 0.0046386718750000, +0.0007324218750000, 0.0045471191406250, 0.0008239746093750, 0.0046997070312500, +0.0014648437500000, 0.0039062500000000, 0.0012817382812500, 0.0040588378906250, +0.0015869140625000, 0.0039978027343750, 0.0021667480468750, 0.0033874511718750, +0.0018005371093750, 0.0035400390625000, 0.0026245117187500, 0.0039062500000000, +0.0025329589843750, 0.0035705566406250, 0.0025939941406250, 0.0037841796875000, +0.0029907226562500, 0.0043334960937500, 0.0027160644531250, 0.0041503906250000, +0.0028991699218750, 0.0042724609375000, 0.0028076171875000, 0.0045166015625000, +0.0028381347656250, 0.0039672851562500, 0.0028686523437500, 0.0036621093750000, +0.0025634765625000, 0.0040588378906250, 0.0031738281250000, 0.0029907226562500, +0.0028076171875000, 0.0028381347656250, 0.0033264160156250, 0.0028381347656250, +0.0039978027343750, 0.0022888183593750, 0.0033874511718750, 0.0021667480468750, +0.0053405761718750, 0.0023803710937500, 0.0048522949218750, 0.0019836425781250, +0.0054321289062500, 0.0022888183593750, 0.0070800781250000, 0.0026550292968750, +0.0059814453125000, 0.0021362304687500, 0.0073242187500000, 0.0028076171875000, +0.0075683593750000, 0.0027465820312500, 0.0070190429687500, 0.0024108886718750, +0.0073242187500000, 0.0025939941406250, 0.0075073242187500, 0.0025024414062500, +0.0060729980468750, 0.0021362304687500, 0.0064392089843750, 0.0021667480468750, +0.0058593750000000, 0.0020751953125000, 0.0045776367187500, 0.0017395019531250, +0.0054016113281250, 0.0016784667968750, 0.0042724609375000, 0.0020751953125000, +0.0040588378906250, 0.0018005371093750, 0.0045471191406250, 0.0021362304687500, +0.0042724609375000, 0.0026245117187500, 0.0040283203125000, 0.0022277832031250, +0.0050354003906250, 0.0030822753906250, 0.0046386718750000, 0.0029296875000000, +0.0047607421875000, 0.0029296875000000, 0.0054931640625000, 0.0034484863281250, +0.0049133300781250, 0.0032958984375000, 0.0054931640625000, 0.0031738281250000, +0.0055236816406250, 0.0034179687500000, 0.0051574707031250, 0.0032348632812500, +0.0052795410156250}, +{0.0031738281250000, 0.0034179687500000, 0.0026245117187500, 0.0027465820312500, +0.0028991699218750, 0.0030822753906250, 0.0018005371093750, 0.0032348632812500, +0.0018920898437500, 0.0029907226562500, 0.0014953613281250, 0.0032958984375000, +0.0005493164062500, 0.0037536621093750, 0.0010070800781250, 0.0034790039062500, +-0.0003051757812500, 0.0036010742187500, -0.0003051757812500, 0.0038452148437500, +-0.0003051757812500, 0.0034790039062500, -0.0010375976562500, 0.0031433105468750, +-0.0007629394531250, 0.0033264160156250, -0.0007019042968750, 0.0029602050781250, +-0.0009155273437500, 0.0028381347656250, -0.0006713867187500, 0.0028381347656250, +-0.0003967285156250, 0.0027770996093750, -0.0004577636718750, 0.0028381347656250, +-0.0001831054687500, 0.0024108886718750, -0.0001525878906250, 0.0025939941406250, +0.0000000000000000, 0.0023803710937500, 0.0001220703125000, 0.0018920898437500, +0.0001220703125000, 0.0022277832031250, 0.0007629394531250, 0.0018615722656250, +0.0006713867187500, 0.0017089843750000, 0.0010986328125000, 0.0021057128906250, +0.0017089843750000, 0.0019531250000000, 0.0014648437500000, 0.0017089843750000, +0.0026855468750000, 0.0029296875000000, 0.0026245117187500, 0.0025939941406250, +0.0029296875000000, 0.0029602050781250, 0.0038146972656250, 0.0040893554687500, +0.0034179687500000, 0.0035705566406250, 0.0041198730468750, 0.0043029785156250, +0.0042419433593750, 0.0046081542968750, 0.0041503906250000, 0.0043334960937500, +0.0043945312500000, 0.0043945312500000, 0.0043029785156250, 0.0046997070312500, +0.0042724609375000, 0.0038452148437500, 0.0041809082031250, 0.0038757324218750, +0.0041809082031250, 0.0037231445312500, 0.0040283203125000, 0.0032348632812500, +0.0039978027343750, 0.0035705566406250, 0.0044555664062500, 0.0034179687500000, +0.0040893554687500, 0.0032958984375000, 0.0045776367187500, 0.0038146972656250, +0.0052490234375000, 0.0041503906250000, 0.0047302246093750, 0.0038757324218750, +0.0060729980468750, 0.0045471191406250, 0.0058898925781250, 0.0046997070312500, +0.0060424804687500, 0.0045471191406250, 0.0071105957031250, 0.0046386718750000, +0.0066223144531250, 0.0045166015625000, 0.0069580078125000, 0.0043945312500000, +0.0073547363281250, 0.0042419433593750, 0.0066833496093750, 0.0040283203125000, +0.0062561035156250, 0.0037841796875000, 0.0067749023437500, 0.0036926269531250, +0.0050048828125000, 0.0036926269531250, 0.0052490234375000, 0.0034484863281250, +0.0050964355468750, 0.0035095214843750, 0.0039062500000000, 0.0036926269531250, +0.0044860839843750, 0.0034790039062500, 0.0043334960937500, 0.0036926269531250, +0.0039062500000000, 0.0036621093750000, 0.0045471191406250, 0.0035705566406250, +0.0049743652343750, 0.0036010742187500, 0.0045166015625000, 0.0035705566406250, +0.0058593750000000, 0.0031433105468750, 0.0057983398437500, 0.0032653808593750, +0.0058593750000000, 0.0029602050781250, 0.0067138671875000, 0.0025939941406250, +0.0064697265625000, 0.0029296875000000, 0.0065307617187500, 0.0023803710937500, +0.0068054199218750, 0.0024108886718750, 0.0065002441406250, 0.0024719238281250, +0.0062255859375000, 0.0022888183593750, 0.0065612792968750, 0.0024414062500000, +0.0058593750000000, 0.0025329589843750, 0.0060424804687500, 0.0025939941406250, +0.0058898925781250, 0.0027770996093750, 0.0053710937500000, 0.0029296875000000, +0.0056457519531250, 0.0029602050781250, 0.0053100585937500, 0.0032958984375000, +0.0052795410156250, 0.0032653808593750, 0.0052490234375000, 0.0033264160156250, +0.0051574707031250, 0.0035400390625000, 0.0052185058593750, 0.0034790039062500, +0.0046386718750000, 0.0036926269531250, 0.0048828125000000, 0.0037231445312500, +0.0043640136718750, 0.0037536621093750, 0.0036926269531250, 0.0039062500000000, +0.0041198730468750, 0.0039062500000000, 0.0025024414062500, 0.0039672851562500, +0.0028686523437500, 0.0040588378906250, 0.0021667480468750, 0.0040893554687500, +0.0008239746093750, 0.0040283203125000, 0.0016784667968750, 0.0040893554687500, +-0.0002136230468750, 0.0040588378906250, 0.0000915527343750, 0.0041503906250000, +-0.0003356933593750, 0.0040588378906250, -0.0016174316406250, 0.0039062500000000, +-0.0008544921875000, 0.0040588378906250, -0.0021057128906250, 0.0038757324218750, +-0.0021057128906250, 0.0037841796875000, -0.0020446777343750, 0.0037536621093750, +-0.0027465820312500, 0.0036010742187500, -0.0024414062500000, 0.0035705566406250, +-0.0025329589843750, 0.0036621093750000, -0.0027160644531250, 0.0035400390625000, +-0.0023803710937500, 0.0035705566406250, -0.0021972656250000, 0.0036926269531250, +-0.0022277832031250, 0.0036010742187500, -0.0014953613281250, 0.0036315917968750, +-0.0016479492187500, 0.0036315917968750, -0.0012817382812500, 0.0035705566406250, +-0.0005493164062500, 0.0035705566406250, -0.0008850097656250, 0.0033874511718750, +0.0000915527343750, 0.0034484863281250, 0.0000610351562500, 0.0033264160156250, +0.0002136230468750, 0.0032653808593750, 0.0008239746093750, 0.0032653808593750, +0.0006408691406250, 0.0031433105468750, 0.0008239746093750, 0.0031127929687500, +0.0009765625000000, 0.0030517578125000, 0.0008239746093750, 0.0029602050781250, +0.0007629394531250, 0.0030212402343750, 0.0008850097656250, 0.0028991699218750, +0.0005187988281250, 0.0028686523437500, 0.0005493164062500, 0.0028686523437500, +0.0006103515625000, 0.0028076171875000, 0.0004882812500000, 0.0027770996093750, +0.0004577636718750, 0.0028381347656250, 0.0009460449218750, 0.0026550292968750, +0.0007019042968750, 0.0026550292968750, 0.0010375976562500, 0.0026550292968750, +0.0016174316406250, 0.0025329589843750, 0.0012207031250000, 0.0025634765625000, +0.0019836425781250, 0.0025634765625000, 0.0019531250000000, 0.0025024414062500, +0.0019836425781250, 0.0025329589843750, 0.0024108886718750, 0.0025634765625000, +0.0022888183593750, 0.0024108886718750, 0.0023803710937500, 0.0024719238281250, +0.0024414062500000, 0.0023803710937500, 0.0025024414062500, 0.0023803710937500, +0.0025024414062500, 0.0024414062500000, 0.0024108886718750, 0.0022888183593750, +0.0027465820312500, 0.0023803710937500, 0.0026855468750000, 0.0023193359375000, +0.0026855468750000, 0.0022888183593750, 0.0029602050781250, 0.0023498535156250, +0.0029296875000000, 0.0022277832031250, 0.0027160644531250, 0.0023498535156250, +0.0029296875000000, 0.0023193359375000, 0.0026855468750000, 0.0023193359375000, +0.0022888183593750, 0.0023803710937500, 0.0026550292968750, 0.0022277832031250, +0.0021362304687500, 0.0024414062500000, 0.0020141601562500, 0.0023803710937500, +0.0022583007812500, 0.0024108886718750, 0.0021057128906250, 0.0025634765625000, +0.0020141601562500, 0.0024108886718750, 0.0028076171875000, 0.0025634765625000, +0.0025329589843750, 0.0025939941406250, 0.0027770996093750, 0.0023803710937500, +0.0036010742187500, 0.0024108886718750, 0.0032958984375000, 0.0025634765625000, +0.0034790039062500, 0.0020141601562500, 0.0039062500000000, 0.0022583007812500, +0.0034484863281250, 0.0019836425781250, 0.0031738281250000, 0.0014343261718750, +0.0037231445312500, 0.0017700195312500, 0.0025329589843750, 0.0013122558593750, +0.0027160644531250, 0.0012512207031250, 0.0026550292968750, 0.0012512207031250, +0.0015563964843750, 0.0011291503906250, 0.0013122558593750, 0.0013122558593750, +0.0010375976562500, 0.0010070800781250, 0.0009765625000000, 0.0010681152343750, +0.0008850097656250, 0.0010681152343750, 0.0006408691406250, 0.0007934570312500, +0.0004577636718750, 0.0009460449218750, 0.0003967285156250, 0.0009460449218750, +0.0000610351562500, 0.0008239746093750, 0.0004577636718750, 0.0010681152343750, +0.0008239746093750, 0.0013122558593750, 0.0002441406250000, 0.0011901855468750, +0.0016784667968750, 0.0018310546875000, 0.0015258789062500, 0.0018005371093750, +0.0017089843750000, 0.0020751953125000, 0.0028686523437500, 0.0025634765625000, +0.0026855468750000, 0.0023498535156250, 0.0027465820312500, 0.0030822753906250, +0.0032653808593750, 0.0031433105468750, 0.0031127929687500, 0.0032653808593750, +0.0028381347656250, 0.0036315917968750, 0.0032653808593750, 0.0035400390625000, +0.0027465820312500, 0.0036926269531250, 0.0028076171875000, 0.0038146972656250, +0.0028076171875000, 0.0038146972656250, 0.0025634765625000, 0.0038452148437500, +0.0027465820312500, 0.0039062500000000, 0.0026550292968750, 0.0039978027343750, +0.0026855468750000, 0.0039978027343750, 0.0028076171875000, 0.0041198730468750, +0.0029296875000000, 0.0042114257812500, 0.0030212402343750, 0.0041503906250000, +0.0032653808593750, 0.0045776367187500, 0.0033264160156250, 0.0044860839843750, +0.0035095214843750, 0.0044860839843750, 0.0037841796875000, 0.0047912597656250, +0.0038452148437500, 0.0047607421875000, 0.0039672851562500, 0.0046081542968750, +0.0041503906250000, 0.0046386718750000, 0.0041198730468750, 0.0045776367187500, +0.0040283203125000, 0.0044250488281250, 0.0042724609375000, 0.0044860839843750, +0.0041809082031250, 0.0045166015625000, 0.0041503906250000, 0.0043945312500000, +0.0042724609375000, 0.0046081542968750, 0.0044555664062500, 0.0047912597656250, +0.0044250488281250, 0.0047607421875000, 0.0043640136718750, 0.0049438476562500, +0.0046386718750000, 0.0050354003906250, 0.0043640136718750, 0.0048522949218750, +0.0041198730468750, 0.0048522949218750, 0.0045471191406250, 0.0050354003906250, +0.0034484863281250, 0.0042419433593750, 0.0037841796875000, 0.0043945312500000, +0.0035400390625000, 0.0041503906250000, 0.0026245117187500, 0.0034179687500000, +0.0032958984375000, 0.0037536621093750, 0.0027465820312500, 0.0032653808593750, +0.0027160644531250, 0.0030212402343750, 0.0031127929687500, 0.0032043457031250, +0.0031433105468750, 0.0031738281250000, 0.0032958984375000, 0.0029907226562500, +0.0036315917968750, 0.0034179687500000, 0.0038146972656250, 0.0032958984375000, +0.0039367675781250, 0.0032958984375000, 0.0041198730468750, 0.0036010742187500, +0.0043640136718750, 0.0033264160156250, 0.0040283203125000, 0.0035705566406250, +0.0042724609375000, 0.0035095214843750, 0.0042724609375000, 0.0034484863281250, +0.0040588378906250, 0.0035400390625000, 0.0043029785156250, 0.0034484863281250, +0.0039672851562500, 0.0036010742187500, 0.0041503906250000, 0.0035705566406250, +0.0040588378906250, 0.0036621093750000, 0.0038146972656250, 0.0038452148437500, +0.0040893554687500, 0.0038146972656250, 0.0036621093750000, 0.0040588378906250, +0.0038757324218750, 0.0041809082031250, 0.0037536621093750, 0.0039978027343750, +0.0034484863281250, 0.0040588378906250, 0.0038452148437500, 0.0042419433593750, +0.0032653808593750, 0.0033569335937500, 0.0034790039062500, 0.0036926269531250, +0.0034179687500000, 0.0032348632812500, 0.0029602050781250, 0.0023498535156250, +0.0033264160156250, 0.0029907226562500, 0.0030517578125000, 0.0017395019531250, +0.0030212402343750, 0.0017700195312500, 0.0031433105468750, 0.0016784667968750, +0.0030822753906250, 0.0010070800781250, 0.0030822753906250, 0.0012817382812500, +0.0031127929687500, 0.0007629394531250, 0.0031738281250000, 0.0008544921875000, +0.0031738281250000, 0.0007019042968750, 0.0032043457031250, 0.0003051757812500, +0.0031738281250000, 0.0004882812500000, 0.0030212402343750, -0.0000610351562500, +0.0030822753906250, 0.0000610351562500, 0.0029602050781250, -0.0002441406250000, +0.0028076171875000, -0.0007934570312500, 0.0028686523437500, -0.0005187988281250, +0.0027465820312500}, +{0.0034484863281250, 0.0032348632812500, 0.0040283203125000, 0.0032653808593750, +0.0041198730468750, 0.0031433105468750, 0.0040893554687500, 0.0032653808593750, +0.0043029785156250, 0.0034790039062500, 0.0042419433593750, 0.0032958984375000, +0.0039978027343750, 0.0035705566406250, 0.0040283203125000, 0.0035400390625000, +0.0039062500000000, 0.0034484863281250, 0.0035095214843750, 0.0035400390625000, +0.0035095214843750, 0.0034484863281250, 0.0033264160156250, 0.0031738281250000, +0.0031738281250000, 0.0032348632812500, 0.0033264160156250, 0.0030212402343750, +0.0034179687500000, 0.0026855468750000, 0.0032043457031250, 0.0028686523437500, +0.0039062500000000, 0.0024414062500000, 0.0036926269531250, 0.0023803710937500, +0.0038757324218750, 0.0024108886718750, 0.0044555664062500, 0.0022583007812500, +0.0039978027343750, 0.0022583007812500, 0.0043640136718750, 0.0020446777343750, +0.0043334960937500, 0.0021057128906250, 0.0042419433593750, 0.0018615722656250, +0.0043945312500000, 0.0016479492187500, 0.0041198730468750, 0.0018005371093750, +0.0040893554687500, 0.0010375976562500, 0.0040893554687500, 0.0010681152343750, +0.0039978027343750, 0.0007324218750000, 0.0039062500000000, 0.0001220703125000, +0.0038757324218750, 0.0003662109375000, 0.0038452148437500, -0.0004272460937500, +0.0039367675781250, -0.0003967285156250, 0.0037841796875000, -0.0004882812500000, +0.0038146972656250, -0.0010681152343750, 0.0040588378906250, -0.0008850097656250, +0.0034179687500000, -0.0010070800781250, 0.0037841796875000, -0.0010986328125000, +0.0035705566406250, -0.0011291503906250, 0.0029296875000000, -0.0011291503906250, +0.0034179687500000, -0.0011901855468750, 0.0028991699218750, -0.0011291503906250, +0.0028686523437500, -0.0012512207031250, 0.0031127929687500, -0.0011291503906250, +0.0030517578125000, -0.0010070800781250, 0.0031127929687500, -0.0011596679687500, +0.0032348632812500, -0.0006408691406250, 0.0033874511718750, -0.0007934570312500, +0.0033569335937500, -0.0005798339843750, 0.0033874511718750, -0.0001220703125000, +0.0035400390625000, -0.0003662109375000, 0.0032958984375000, 0.0001831054687500, +0.0035400390625000, 0.0001525878906250, 0.0034484863281250, 0.0002746582031250, +0.0033264160156250, 0.0006713867187500, 0.0036315917968750, 0.0004577636718750, +0.0032043457031250, 0.0009460449218750, 0.0034790039062500, 0.0008239746093750, +0.0034484863281250, 0.0009765625000000, 0.0031433105468750, 0.0013427734375000, +0.0035400390625000, 0.0010986328125000, 0.0031433105468750, 0.0018310546875000, +0.0033874511718750, 0.0016784667968750, 0.0032958984375000, 0.0019531250000000, +0.0029907226562500, 0.0026245117187500, 0.0035095214843750, 0.0023498535156250, +0.0028686523437500, 0.0029602050781250, 0.0031738281250000, 0.0032043457031250, +0.0031738281250000, 0.0029602050781250, 0.0027160644531250, 0.0030822753906250, +0.0031738281250000, 0.0032653808593750, 0.0028381347656250, 0.0024108886718750, +0.0028686523437500, 0.0027465820312500, 0.0030822753906250, 0.0022583007812500, +0.0029296875000000, 0.0013427734375000, 0.0029907226562500, 0.0018005371093750, +0.0032348632812500, 0.0002441406250000, 0.0030822753906250, 0.0004577636718750, +0.0032348632812500, -0.0000305175781250, 0.0034179687500000, -0.0011901855468750, +0.0032348632812500, -0.0005798339843750, 0.0033874511718750, -0.0018005371093750, +0.0033569335937500, -0.0018615722656250, 0.0033264160156250, -0.0020141601562500, +0.0034484863281250, -0.0027160644531250, 0.0033264160156250, -0.0024414062500000, +0.0035705566406250, -0.0028076171875000, 0.0034179687500000, -0.0029907226562500, +0.0034790039062500, -0.0027465820312500, 0.0036926269531250, -0.0028381347656250, +0.0035095214843750, -0.0028686523437500, 0.0037841796875000, -0.0021972656250000, +0.0036926269531250, -0.0025024414062500, 0.0035400390625000, -0.0019226074218750, +0.0037231445312500, -0.0010681152343750, 0.0036010742187500, -0.0016174316406250, +0.0034484863281250, 0.0000305175781250, 0.0034484863281250, 0.0000000000000000, +0.0033569335937500, 0.0003051757812500, 0.0032043457031250, 0.0014343261718750, +0.0032653808593750, 0.0010375976562500, 0.0031433105468750, 0.0017700195312500, +0.0032043457031250, 0.0018615722656250, 0.0032043457031250, 0.0018920898437500, +0.0031127929687500, 0.0022583007812500, 0.0031738281250000, 0.0021667480468750, +0.0029296875000000, 0.0021362304687500, 0.0031127929687500, 0.0021972656250000, +0.0029296875000000, 0.0021057128906250, 0.0027160644531250, 0.0020141601562500, +0.0029907226562500, 0.0020751953125000, 0.0022583007812500, 0.0018005371093750, +0.0025024414062500, 0.0018615722656250, 0.0023498535156250, 0.0017700195312500, +0.0018310546875000, 0.0015869140625000, 0.0021972656250000, 0.0017089843750000, +0.0015869140625000, 0.0014648437500000, 0.0016784667968750, 0.0014648437500000, +0.0016479492187500, 0.0014038085937500, 0.0014343261718750, 0.0013122558593750, +0.0015869140625000, 0.0014038085937500, 0.0011596679687500, 0.0012207031250000, +0.0013732910156250, 0.0013122558593750, 0.0011596679687500, 0.0012817382812500, +0.0007019042968750, 0.0010681152343750, 0.0010681152343750, 0.0012512207031250, +0.0001525878906250, 0.0009460449218750, 0.0003051757812500, 0.0010070800781250, +0.0002441406250000, 0.0009155273437500, -0.0003967285156250, 0.0007629394531250, +-0.0000610351562500, 0.0009155273437500, -0.0000610351562500, 0.0006713867187500, +-0.0002746582031250, 0.0007629394531250, 0.0001220703125000, 0.0007019042968750, +0.0004882812500000, 0.0005187988281250, 0.0002441406250000, 0.0007324218750000, +0.0012207031250000, 0.0003967285156250, 0.0011596679687500, 0.0004882812500000, +0.0014343261718750, 0.0004882812500000, 0.0021362304687500, 0.0003051757812500, +0.0018310546875000, 0.0003967285156250, 0.0023193359375000, 0.0004577636718750, +0.0023193359375000, 0.0004272460937500, 0.0024108886718750, 0.0003967285156250, +0.0026245117187500, 0.0003662109375000, 0.0024108886718750, 0.0004882812500000, +0.0031738281250000, 0.0008239746093750, 0.0029907226562500, 0.0004882812500000, +0.0031738281250000, 0.0010375976562500, 0.0036926269531250, 0.0017700195312500, +0.0034179687500000, 0.0012817382812500, 0.0037231445312500, 0.0024414062500000, +0.0038146972656250, 0.0023803710937500, 0.0035095214843750, 0.0024414062500000, +0.0034790039062500, 0.0031127929687500, 0.0034790039062500, 0.0027160644531250, +0.0028076171875000, 0.0030517578125000, 0.0028381347656250, 0.0030822753906250, +0.0027160644531250, 0.0031433105468750, 0.0019836425781250, 0.0035095214843750, +0.0003967285156250, 0.0009765625000000, 0.0007629394531250, 0.0014038085937500, +0.0004272460937500, 0.0008850097656250, 0.0007629394531250, 0.0013427734375000, +0.0011291503906250, 0.0018615722656250, 0.0007934570312500, 0.0014953613281250, +0.0015869140625000, 0.0025329589843750, 0.0014953613281250, 0.0023498535156250, +0.0016784667968750, 0.0025939941406250, 0.0022888183593750, 0.0035400390625000, +0.0020141601562500, 0.0031433105468750, 0.0026855468750000, 0.0035705566406250, +0.0025329589843750, 0.0037231445312500, 0.0028381347656250, 0.0038146972656250, +0.0032958984375000, 0.0040588378906250, 0.0029296875000000, 0.0039978027343750, +0.0039978027343750, 0.0040893554687500, 0.0037536621093750, 0.0043334960937500, +0.0039062500000000, 0.0040588378906250, 0.0047302246093750, 0.0039062500000000, +0.0042419433593750, 0.0042724609375000, 0.0044250488281250, 0.0035095214843750, +0.0045471191406250, 0.0037231445312500, 0.0040893554687500, 0.0035400390625000, +0.0038146972656250, 0.0029602050781250, 0.0039672851562500, 0.0033569335937500, +0.0031127929687500, 0.0027160644531250, 0.0030822753906250, 0.0027465820312500, +0.0028076171875000, 0.0028991699218750, 0.0021362304687500, 0.0027160644531250, +0.0023803710937500, 0.0028076171875000, 0.0016784667968750, 0.0027160644531250, +0.0015563964843750, 0.0029296875000000, 0.0015258789062500, 0.0028991699218750, +0.0011596679687500, 0.0026245117187500, 0.0012207031250000, 0.0027160644531250, +0.0012207031250000, 0.0025024414062500, 0.0010681152343750, 0.0026245117187500, +0.0012207031250000, 0.0023803710937500, 0.0014038085937500, 0.0020446777343750, +0.0011901855468750, 0.0024719238281250, 0.0014648437500000, 0.0024719238281250, +0.0014953613281250, 0.0024108886718750, 0.0012512207031250, 0.0028686523437500, +0.0013732910156250, 0.0032043457031250, 0.0014953613281250, 0.0031738281250000, +0.0004272460937500, 0.0042724609375000, 0.0007629394531250, 0.0043029785156250, +0.0002136230468750, 0.0041503906250000, -0.0007934570312500, 0.0048522949218750, +-0.0002441406250000, 0.0050354003906250, -0.0014648437500000, 0.0039367675781250, +-0.0015563964843750, 0.0043945312500000, -0.0014343261718750, 0.0039367675781250, +-0.0020446777343750, 0.0028076171875000, -0.0020141601562500, 0.0036010742187500, +-0.0017089843750000, 0.0026855468750000, -0.0019226074218750, 0.0025024414062500, +-0.0017089843750000, 0.0029602050781250, -0.0013122558593750, 0.0028076171875000, +-0.0014953613281250, 0.0026855468750000, -0.0012512207031250, 0.0036010742187500, +-0.0010681152343750, 0.0033264160156250, -0.0012817382812500, 0.0035400390625000, +-0.0013122558593750, 0.0042419433593750, -0.0010681152343750, 0.0036315917968750, +-0.0019836425781250, 0.0040893554687500, -0.0016784667968750, 0.0040893554687500, +-0.0018920898437500, 0.0038452148437500, -0.0025634765625000, 0.0037841796875000, +-0.0021057128906250, 0.0036926269531250, -0.0024719238281250, 0.0036926269531250, +-0.0025329589843750, 0.0035400390625000, -0.0023498535156250, 0.0036621093750000, +-0.0023498535156250, 0.0038757324218750, -0.0023193359375000, 0.0036315917968750, +-0.0022583007812500, 0.0042114257812500, -0.0021362304687500, 0.0041503906250000, +-0.0022888183593750, 0.0040893554687500, -0.0022888183593750, 0.0045166015625000, +-0.0021057128906250, 0.0045166015625000, -0.0025939941406250, 0.0041809082031250, +-0.0023803710937500, 0.0044860839843750, -0.0026245117187500, 0.0042114257812500, +-0.0031433105468750, 0.0037841796875000, -0.0027465820312500, 0.0042114257812500, +-0.0032958984375000, 0.0035095214843750, -0.0033264160156250, 0.0036621093750000, +-0.0030822753906250, 0.0036621093750000, -0.0032653808593750, 0.0031738281250000, +-0.0032348632812500, 0.0035095214843750, -0.0023803710937500, 0.0032348632812500, +-0.0026550292968750, 0.0032958984375000, -0.0021362304687500, 0.0032958984375000, +-0.0012817382812500, 0.0032348632812500, -0.0017089843750000, 0.0033264160156250, +-0.0003967285156250, 0.0032043457031250, -0.0004882812500000, 0.0032348632812500, +-0.0002136230468750, 0.0032043457031250, 0.0007019042968750, 0.0031127929687500, +0.0002441406250000, 0.0031127929687500, 0.0010375976562500, 0.0030822753906250, +0.0010681152343750, 0.0030517578125000, 0.0009155273437500, 0.0029602050781250, +0.0012207031250000, 0.0029296875000000, 0.0011291503906250, 0.0029602050781250, +0.0008239746093750, 0.0028381347656250, 0.0009155273437500, 0.0027770996093750, +0.0005187988281250, 0.0028076171875000, -0.0000305175781250, 0.0027770996093750, +0.0001831054687500, 0.0026855468750000, -0.0009155273437500, 0.0027160644531250, +-0.0009155273437500, 0.0026550292968750, -0.0012207031250000, 0.0025634765625000, +-0.0019836425781250, 0.0025329589843750, -0.0018005371093750, 0.0024719238281250, +-0.0022277832031250, 0.0025024414062500, -0.0024414062500000, 0.0023803710937500, +-0.0023193359375000}, +{0.0000305175781250, 0.0033874511718750, -0.0000915527343750, 0.0032043457031250, +0.0003051757812500, 0.0031433105468750, 0.0000915527343750, 0.0034790039062500, +-0.0002441406250000, 0.0025024414062500, -0.0002136230468750, 0.0028381347656250, +-0.0004577636718750, 0.0025024414062500, -0.0008544921875000, 0.0017700195312500, +-0.0007934570312500, 0.0023803710937500, -0.0007934570312500, 0.0016479492187500, +-0.0012207031250000, 0.0015563964843750, -0.0008850097656250, 0.0020141601562500, +-0.0005187988281250, 0.0020141601562500, -0.0010681152343750, 0.0019531250000000, +0.0001831054687500, 0.0024719238281250, -0.0002136230468750, 0.0027160644531250, +-0.0000610351562500, 0.0027465820312500, 0.0008544921875000, 0.0029602050781250, +0.0003356933593750, 0.0030517578125000, 0.0005187988281250, 0.0027160644531250, +0.0007324218750000, 0.0029296875000000, 0.0004272460937500, 0.0027160644531250, +0.0003051757812500, 0.0021972656250000, 0.0004272460937500, 0.0025634765625000, +-0.0002746582031250, 0.0020446777343750, -0.0001525878906250, 0.0018005371093750, +-0.0003051757812500, 0.0021667480468750, -0.0009155273437500, 0.0021362304687500, +-0.0006408691406250, 0.0017089843750000, -0.0009765625000000, 0.0028076171875000, +-0.0011596679687500, 0.0022277832031250, -0.0011596679687500, 0.0024414062500000, +-0.0012512207031250, 0.0034484863281250, -0.0013732910156250, 0.0028381347656250, +-0.0017395019531250, 0.0033569335937500, -0.0015563964843750, 0.0035095214843750, +-0.0021057128906250, 0.0032348632812500, -0.0027160644531250, 0.0033264160156250, +-0.0023193359375000, 0.0034179687500000, -0.0036315917968750, 0.0029296875000000, +-0.0035400390625000, 0.0030517578125000, -0.0037841796875000, 0.0030517578125000, +-0.0046691894531250, 0.0027770996093750, -0.0043029785156250, 0.0029296875000000, +-0.0048522949218750, 0.0027465820312500, -0.0050964355468750, 0.0028686523437500, +-0.0048217773437500, 0.0028991699218750, -0.0049438476562500, 0.0027770996093750, +-0.0051269531250000, 0.0028381347656250, -0.0041503906250000, 0.0028381347656250, +-0.0045776367187500, 0.0028076171875000, -0.0040588378906250, 0.0028381347656250, +-0.0031127929687500, 0.0028076171875000, -0.0037536621093750, 0.0028686523437500, +-0.0024108886718750, 0.0027770996093750, -0.0024719238281250, 0.0027160644531250, +-0.0022888183593750, 0.0027770996093750, -0.0014953613281250, 0.0028076171875000, +-0.0017700195312500, 0.0027770996093750, -0.0010070800781250, 0.0028381347656250, +-0.0010375976562500, 0.0028686523437500, -0.0008239746093750, 0.0028076171875000, +-0.0003662109375000, 0.0027465820312500, -0.0006103515625000, 0.0027160644531250, +0.0000610351562500, 0.0025329589843750, -0.0000915527343750, 0.0025329589843750, +0.0000915527343750, 0.0024108886718750, 0.0006408691406250, 0.0021972656250000, +0.0003662109375000, 0.0021972656250000, 0.0009765625000000, 0.0020446777343750, +0.0010070800781250, 0.0019531250000000, 0.0010070800781250, 0.0018615722656250, +0.0014038085937500, 0.0017700195312500, 0.0012817382812500, 0.0016784667968750, +0.0013427734375000, 0.0017089843750000, 0.0014648437500000, 0.0015258789062500, +0.0011901855468750, 0.0015869140625000, 0.0009155273437500, 0.0016479492187500, +0.0009765625000000, 0.0014648437500000, 0.0001525878906250, 0.0017089843750000, +0.0002746582031250, 0.0015563964843750, -0.0001525878906250, 0.0015563964843750, +-0.0009155273437500, 0.0016784667968750, -0.0006713867187500, 0.0014648437500000, +-0.0013122558593750, 0.0016784667968750, -0.0014343261718750, 0.0016174316406250, +-0.0014343261718750, 0.0016479492187500, -0.0016784667968750, 0.0018920898437500, +-0.0016784667968750, 0.0018005371093750, -0.0014953613281250, 0.0020141601562500, +-0.0016174316406250, 0.0020141601562500, -0.0014038085937500, 0.0020141601562500, +-0.0011596679687500, 0.0021972656250000, -0.0014038085937500, 0.0021972656250000, +-0.0007324218750000, 0.0021362304687500, -0.0009765625000000, 0.0022583007812500, +-0.0007629394531250, 0.0021972656250000, -0.0003051757812500, 0.0021362304687500, +-0.0006713867187500, 0.0022888183593750, 0.0000305175781250, 0.0022277832031250, +-0.0001220703125000, 0.0022583007812500, -0.0000915527343750, 0.0022888183593750, +0.0004272460937500, 0.0022583007812500, 0.0001831054687500, 0.0023193359375000, +0.0003356933593750, 0.0021362304687500, 0.0004577636718750, 0.0022888183593750, +0.0002441406250000, 0.0022583007812500, 0.0002136230468750, 0.0020751953125000, +0.0003356933593750, 0.0022583007812500, -0.0001525878906250, 0.0019226074218750, +-0.0001220703125000, 0.0020751953125000, -0.0001831054687500, 0.0020751953125000, +-0.0005187988281250, 0.0018615722656250, -0.0003662109375000, 0.0020141601562500, +-0.0003051757812500, 0.0019226074218750, -0.0004882812500000, 0.0020141601562500, +-0.0001220703125000, 0.0020141601562500, 0.0001831054687500, 0.0019531250000000, +-0.0000915527343750, 0.0020141601562500, 0.0009460449218750, 0.0018310546875000, +0.0007324218750000, 0.0018615722656250, 0.0009155273437500, 0.0018005371093750, +0.0015869140625000, 0.0016784667968750, 0.0011901855468750, 0.0017700195312500, +0.0016784667968750, 0.0016174316406250, 0.0018005371093750, 0.0016174316406250, +0.0015563964843750, 0.0016784667968750, 0.0017395019531250, 0.0016174316406250, +0.0018615722656250, 0.0016784667968750, 0.0012207031250000, 0.0017089843750000, +0.0014953613281250, 0.0016174316406250, 0.0012512207031250, 0.0017395019531250, +0.0006103515625000, 0.0018615722656250, 0.0009155273437500, 0.0017395019531250, +0.0000915527343750, 0.0023193359375000, 0.0000610351562500, 0.0020751953125000, +-0.0000610351562500, 0.0023193359375000, -0.0006408691406250, 0.0029602050781250, +-0.0006408691406250, 0.0025024414062500, -0.0004882812500000, 0.0032348632812500, +-0.0007934570312500, 0.0032653808593750, -0.0005798339843750, 0.0031433105468750, +0.0000610351562500, 0.0034179687500000, 0.0002136230468750, 0.0032043457031250, +0.0010070800781250, 0.0029296875000000, 0.0008544921875000, 0.0030822753906250, +0.0008850097656250, 0.0028991699218750, 0.0013732910156250, 0.0026550292968750, +0.0011901855468750, 0.0028381347656250, 0.0018005371093750, 0.0022888183593750, +0.0017395019531250, 0.0024414062500000, 0.0019836425781250, 0.0022888183593750, +0.0025634765625000, 0.0018615722656250, 0.0023498535156250, 0.0020141601562500, +0.0027465820312500, 0.0016479492187500, 0.0028076171875000, 0.0017089843750000, +0.0028076171875000, 0.0015869140625000, 0.0028686523437500, 0.0012817382812500, +0.0026245117187500, 0.0014038085937500, 0.0030822753906250, 0.0010070800781250, +0.0028686523437500, 0.0010681152343750, 0.0027770996093750, 0.0007934570312500, +0.0030212402343750, 0.0003662109375000, 0.0028686523437500, 0.0005798339843750, +0.0024719238281250, -0.0000915527343750, 0.0028076171875000, -0.0002136230468750, +0.0025024414062500, -0.0002746582031250, 0.0019531250000000, -0.0006103515625000, +0.0023498535156250, -0.0006103515625000, 0.0019531250000000, -0.0004272460937500, +0.0019531250000000, -0.0006103515625000, 0.0021362304687500, -0.0004882812500000, +0.0020141601562500, -0.0001525878906250, 0.0021667480468750, -0.0003662109375000, +0.0024414062500000, 0.0001525878906250, 0.0022888183593750, 0.0001525878906250, +0.0025024414062500, 0.0002746582031250, 0.0028381347656250, 0.0005493164062500, +0.0025634765625000, 0.0003967285156250, 0.0027160644531250, 0.0006408691406250, +0.0027770996093750, 0.0006713867187500, 0.0026855468750000, 0.0006713867187500, +0.0027770996093750, 0.0007629394531250, 0.0026855468750000, 0.0007629394531250, +0.0024719238281250, 0.0007019042968750, 0.0025024414062500, 0.0008239746093750, +0.0025024414062500, 0.0007324218750000, 0.0023803710937500, 0.0006103515625000, +0.0022277832031250, 0.0007629394531250, 0.0027160644531250, 0.0004882812500000, +0.0023498535156250, 0.0006103515625000, 0.0026550292968750, 0.0005798339843750, +0.0032653808593750, 0.0004272460937500, 0.0026855468750000, 0.0006713867187500, +0.0032958984375000, 0.0004882812500000, 0.0032348632812500, 0.0006408691406250, +0.0030822753906250, 0.0006103515625000, 0.0032043457031250, 0.0004882812500000, +0.0030212402343750, 0.0006713867187500, 0.0030517578125000, 0.0004272460937500, +0.0029296875000000, 0.0005798339843750, 0.0029296875000000, 0.0004577636718750, +0.0030212402343750, 0.0002746582031250, 0.0028686523437500, 0.0005187988281250, +0.0030212402343750, -0.0001220703125000, 0.0030212402343750, 0.0000915527343750, +0.0028686523437500, -0.0001831054687500, 0.0029296875000000, -0.0008239746093750, +0.0029907226562500, -0.0003967285156250, 0.0024719238281250, -0.0012512207031250, +0.0026550292968750, -0.0012512207031250, 0.0024414062500000, -0.0012207031250000, +0.0018920898437500, -0.0016784667968750, 0.0021972656250000, -0.0014953613281250, +0.0015563964843750, -0.0014953613281250, 0.0015869140625000, -0.0015563964843750, +0.0015563964843750, -0.0014343261718750, 0.0012512207031250, -0.0012207031250000, +0.0014038085937500, -0.0014038085937500, 0.0014038085937500, -0.0013122558593750, +0.0013732910156250, -0.0011596679687500, 0.0014648437500000, -0.0013427734375000, +0.0016479492187500, -0.0015563964843750, 0.0016479492187500, -0.0013732910156250, +0.0018310546875000, -0.0018920898437500, 0.0018615722656250, -0.0018310546875000, +0.0018920898437500, -0.0018310546875000, 0.0019836425781250, -0.0021667480468750, +0.0019531250000000, -0.0020751953125000, 0.0019836425781250, -0.0015258789062500, +0.0019531250000000, -0.0018615722656250, 0.0020446777343750, -0.0013122558593750, +0.0020751953125000, -0.0005493164062500, 0.0020446777343750, -0.0009765625000000, +0.0020751953125000, 0.0003356933593750, 0.0021667480468750, 0.0003051757812500, +0.0021667480468750, 0.0005798339843750, 0.0021057128906250, 0.0014648437500000, +0.0021667480468750, 0.0010986328125000, 0.0021667480468750, 0.0017089843750000, +0.0021362304687500, 0.0019226074218750, 0.0022277832031250, 0.0018310546875000, +0.0022888183593750, 0.0020446777343750, 0.0021972656250000, 0.0021362304687500, +0.0024108886718750, 0.0016174316406250, 0.0024108886718750, 0.0018920898437500, +0.0023803710937500, 0.0015869140625000, 0.0025329589843750, 0.0010070800781250, +0.0024108886718750, 0.0014343261718750, 0.0024108886718750, 0.0006103515625000, +0.0024108886718750, 0.0007019042968750, 0.0023193359375000, 0.0005493164062500, +0.0022277832031250, 0.0000305175781250, 0.0022277832031250, 0.0002441406250000, +0.0021362304687500, -0.0001831054687500, 0.0021057128906250, -0.0001220703125000, +0.0020751953125000, -0.0004577636718750, 0.0020141601562500, -0.0008544921875000, +0.0020141601562500, -0.0005798339843750, 0.0018310546875000, -0.0016479492187500, +0.0019226074218750, -0.0015869140625000, 0.0018005371093750, -0.0018920898437500, +0.0016174316406250, -0.0027770996093750, 0.0017395019531250, -0.0025024414062500, +0.0013732910156250, -0.0028686523437500, 0.0014038085937500, -0.0031738281250000, +0.0014648437500000, -0.0029602050781250, 0.0013732910156250, -0.0028991699218750, +0.0013732910156250, -0.0031433105468750, 0.0016174316406250, -0.0022888183593750, +0.0014953613281250, -0.0025634765625000, 0.0016784667968750, -0.0021362304687500, +0.0019531250000000, -0.0013122558593750, 0.0017700195312500, -0.0017395019531250, +0.0020751953125000, -0.0008544921875000, 0.0021057128906250, -0.0008239746093750, +0.0019836425781250, -0.0007934570312500, 0.0020141601562500, -0.0003051757812500, +0.0020446777343750}, +{0.0013122558593750, 0.0015869140625000, 0.0010375976562500, 0.0015563964843750, +0.0012207031250000, 0.0015563964843750, 0.0013122558593750, 0.0016174316406250, +0.0010986328125000, 0.0013732910156250, 0.0010070800781250, 0.0012207031250000, +0.0011596679687500, 0.0013427734375000, 0.0007324218750000, 0.0010375976562500, +0.0008239746093750, 0.0009765625000000, 0.0007934570312500, 0.0010681152343750, +0.0006103515625000, 0.0009765625000000, 0.0008239746093750, 0.0009155273437500, +0.0007629394531250, 0.0011901855468750, 0.0008544921875000, 0.0011596679687500, +0.0008850097656250, 0.0011901855468750, 0.0008850097656250, 0.0014343261718750, +0.0009765625000000, 0.0013122558593750, 0.0005798339843750, 0.0012207031250000, +0.0007324218750000, 0.0013732910156250, 0.0006408691406250, 0.0010375976562500, +0.0002746582031250, 0.0006408691406250, 0.0004882812500000, 0.0008850097656250, +0.0002441406250000, -0.0001831054687500, 0.0002136230468750, -0.0000305175781250, +0.0002746582031250, -0.0003967285156250, 0.0001831054687500, -0.0013427734375000, +0.0001831054687500, -0.0009155273437500, 0.0003967285156250, -0.0017700195312500, +0.0003356933593750, -0.0017395019531250, 0.0004882812500000, -0.0018310546875000, +0.0007934570312500, -0.0023193359375000, 0.0007019042968750, -0.0021057128906250, +0.0008850097656250, -0.0024719238281250, 0.0009765625000000, -0.0025634765625000, +0.0009460449218750, -0.0024414062500000, 0.0009460449218750, -0.0026855468750000, +0.0009765625000000, -0.0026855468750000, 0.0010070800781250, -0.0021057128906250, +0.0009765625000000, -0.0024719238281250, 0.0010375976562500, -0.0019226074218750, +0.0010375976562500, -0.0011596679687500, 0.0010375976562500, -0.0017395019531250, +0.0010681152343750, -0.0000610351562500, 0.0011291503906250, -0.0003967285156250, +0.0010986328125000, 0.0000305175781250, 0.0011291503906250, 0.0013122558593750, +0.0012207031250000, 0.0006713867187500, 0.0010986328125000, 0.0016784667968750, +0.0011291503906250, 0.0018920898437500, 0.0010681152343750, 0.0015869140625000, +0.0009460449218750, 0.0019226074218750, 0.0010375976562500, 0.0019836425781250, +0.0010681152343750, 0.0011596679687500, 0.0010681152343750, 0.0015563964843750, +0.0011596679687500, 0.0010070800781250, 0.0012512207031250, 0.0000000000000000, +0.0012512207031250, 0.0005798339843750, 0.0014343261718750, -0.0006103515625000, +0.0014648437500000, -0.0007324218750000, 0.0014648437500000, -0.0006103515625000, +0.0015869140625000, -0.0010375976562500, 0.0016784667968750, -0.0009765625000000, +0.0015563964843750, -0.0007324218750000, 0.0016479492187500, -0.0008239746093750, +0.0016784667968750, -0.0007019042968750, 0.0015563964843750, -0.0004882812500000, +0.0016479492187500, -0.0005798339843750, 0.0017089843750000, -0.0006103515625000, +0.0017089843750000, -0.0005493164062500, 0.0018005371093750, -0.0006408691406250, +0.0019531250000000, -0.0007934570312500, 0.0018920898437500, -0.0008544921875000, +0.0020141601562500, -0.0008544921875000, 0.0020446777343750, -0.0010681152343750, +0.0019836425781250, -0.0008850097656250, 0.0019836425781250, -0.0007324218750000, +0.0020446777343750, -0.0010681152343750, 0.0018310546875000, -0.0002136230468750, +0.0018920898437500, -0.0004882812500000, 0.0018615722656250, -0.0000610351562500, +0.0017700195312500, 0.0007629394531250, 0.0017700195312500, 0.0002746582031250, +0.0019226074218750, 0.0011901855468750, 0.0018005371093750, 0.0012512207031250, +0.0020141601562500, 0.0012512207031250, 0.0022888183593750, 0.0017700195312500, +0.0020141601562500, 0.0017089843750000, 0.0024414062500000, 0.0015869140625000, +0.0023803710937500, 0.0018310546875000, 0.0023498535156250, 0.0016479492187500, +0.0025939941406250, 0.0013732910156250, 0.0024414062500000, 0.0016479492187500, +0.0024719238281250, 0.0013122558593750, 0.0024108886718750, 0.0013732910156250, +0.0024108886718750, 0.0013427734375000, 0.0024108886718750, 0.0011596679687500, +0.0022277832031250, 0.0013427734375000, 0.0024719238281250, 0.0010681152343750, +0.0023193359375000, 0.0011901855468750, 0.0023193359375000, 0.0010375976562500, +0.0025634765625000, 0.0007934570312500, 0.0024414062500000, 0.0010986328125000, +0.0022583007812500, 0.0006408691406250, 0.0025329589843750, 0.0006713867187500, +0.0022583007812500, 0.0006408691406250, 0.0018310546875000, 0.0002441406250000, +0.0021972656250000, 0.0003967285156250, 0.0013427734375000, 0.0005187988281250, +0.0015258789062500, 0.0002441406250000, 0.0013732910156250, 0.0004272460937500, +0.0007324218750000, 0.0008544921875000, 0.0011596679687500, 0.0005798339843750, +0.0005798339843750, 0.0008239746093750, 0.0005798339843750, 0.0009155273437500, +0.0005187988281250, 0.0006713867187500, 0.0001220703125000, 0.0006408691406250, +0.0002441406250000, 0.0007019042968750, 0.0000610351562500, 0.0002746582031250, +0.0000000000000000, 0.0002441406250000, 0.0001220703125000, 0.0004577636718750, +0.0001831054687500, 0.0003051757812500, 0.0000915527343750, 0.0002136230468750, +0.0006713867187500, 0.0006103515625000, 0.0005798339843750, 0.0005798339843750, +0.0008239746093750, 0.0004577636718750, 0.0017089843750000, 0.0004882812500000, +0.0032348632812500, 0.0010681152343750, 0.0024719238281250, -0.0003662109375000, +0.0031127929687500, 0.0001831054687500, 0.0025329589843750, -0.0000610351562500, +0.0018005371093750, -0.0008850097656250, 0.0024108886718750, -0.0007019042968750, +0.0009460449218750, -0.0003662109375000, 0.0011901855468750, -0.0008850097656250, +0.0008239746093750, -0.0002441406250000, -0.0001525878906250, 0.0005798339843750, +0.0004577636718750, -0.0000915527343750, -0.0004882812500000, 0.0009460449218750, +-0.0005798339843750, 0.0008850097656250, -0.0003662109375000, 0.0009460449218750, +-0.0007324218750000, 0.0016479492187500, -0.0007324218750000, 0.0012207031250000, +-0.0002441406250000, 0.0016784667968750, -0.0004577636718750, 0.0017700195312500, +-0.0001831054687500, 0.0017089843750000, 0.0002746582031250, 0.0018920898437500, +0.0000000000000000, 0.0018920898437500, 0.0007324218750000, 0.0017395019531250, +0.0006713867187500, 0.0020446777343750, 0.0008544921875000, 0.0014953613281250, +0.0014343261718750, 0.0009765625000000, 0.0011901855468750, 0.0015563964843750, +0.0015258789062500, 0.0005493164062500, 0.0016784667968750, 0.0004577636718750, +0.0014343261718750, 0.0007934570312500, 0.0013427734375000, 0.0004577636718750, +0.0014343261718750, 0.0003051757812500, 0.0009765625000000, 0.0011901855468750, +0.0009765625000000, 0.0011291503906250, 0.0008850097656250, 0.0015258789062500, +0.0005187988281250, 0.0023193359375000, 0.0005798339843750, 0.0021362304687500, +0.0008544921875000, 0.0025939941406250, 0.0005493164062500, 0.0028381347656250, +0.0009765625000000, 0.0026550292968750, 0.0015258789062500, 0.0025024414062500, +0.0010986328125000, 0.0025939941406250, 0.0018310546875000, 0.0023803710937500, +0.0018920898437500, 0.0022277832031250, 0.0017395019531250, 0.0020751953125000, +0.0020446777343750, 0.0019226074218750, 0.0020446777343750, 0.0019836425781250, +0.0016174316406250, 0.0021972656250000, 0.0017700195312500, 0.0020141601562500, +0.0015563964843750, 0.0021057128906250, 0.0010681152343750, 0.0025634765625000, +0.0013122558593750, 0.0024719238281250, 0.0010070800781250, 0.0025024414062500, +0.0008850097656250, 0.0026550292968750, 0.0010375976562500, 0.0023193359375000, +0.0010986328125000, 0.0021362304687500, 0.0009460449218750, 0.0025024414062500, +0.0011291503906250, 0.0016784667968750, 0.0011596679687500, 0.0017089843750000, +0.0008239746093750, 0.0018310546875000, 0.0006408691406250, 0.0015258789062500, +0.0007629394531250, 0.0016174316406250, -0.0000610351562500, 0.0017700195312500, +0.0000305175781250, 0.0018920898437500, -0.0002136230468750, 0.0018310546875000, +-0.0008544921875000, 0.0019531250000000, -0.0006408691406250, 0.0021057128906250, +-0.0009460449218750, 0.0015563964843750, -0.0012207031250000, 0.0018310546875000, +-0.0008850097656250, 0.0015869140625000, -0.0007629394531250, 0.0008850097656250, +-0.0009155273437500, 0.0010681152343750, 0.0001525878906250, 0.0005187988281250, +-0.0001831054687500, 0.0002441406250000, 0.0003051757812500, 0.0003051757812500, +0.0013122558593750, 0.0000610351562500, 0.0006713867187500, -0.0000610351562500, +0.0019531250000000, 0.0004882812500000, 0.0018920898437500, 0.0001831054687500, +0.0019836425781250, 0.0003662109375000, 0.0027465820312500, 0.0009460449218750, +0.0023803710937500, 0.0005187988281250, 0.0025329589843750, 0.0009155273437500, +0.0026855468750000, 0.0009155273437500, 0.0023803710937500, 0.0007019042968750, +0.0021362304687500, 0.0007934570312500, 0.0022583007812500, 0.0006713867187500, +0.0014648437500000, 0.0004577636718750, 0.0016174316406250, 0.0004577636718750, +0.0012817382812500, 0.0003356933593750, 0.0006713867187500, 0.0000915527343750, +0.0009460449218750, 0.0000305175781250, -0.0000610351562500, 0.0001525878906250, +0.0000000000000000, -0.0000305175781250, -0.0003356933593750, 0.0001220703125000, +-0.0011901855468750, 0.0003967285156250, -0.0008544921875000, 0.0001831054687500, +-0.0016479492187500, 0.0005493164062500, -0.0017700195312500, 0.0004882812500000, +-0.0017395019531250, 0.0005493164062500, -0.0021362304687500, 0.0007629394531250, +-0.0021972656250000, 0.0006103515625000, -0.0019226074218750, 0.0009460449218750, +-0.0022277832031250, 0.0008239746093750, -0.0018615722656250, 0.0009155273437500, +-0.0014038085937500, 0.0011596679687500, -0.0018005371093750, 0.0010986328125000, +-0.0006408691406250, 0.0012512207031250, -0.0008239746093750, 0.0012817382812500, +-0.0005187988281250, 0.0013122558593750, 0.0003662109375000, 0.0014343261718750, +-0.0000610351562500, 0.0014038085937500, 0.0008850097656250, 0.0015869140625000, +0.0009155273437500, 0.0015563964843750, 0.0008850097656250, 0.0016784667968750, +0.0013732910156250, 0.0018615722656250, 0.0013122558593750, 0.0018005371093750, +0.0014343261718750, 0.0019531250000000, 0.0015869140625000, 0.0020446777343750, +0.0015258789062500, 0.0019836425781250, 0.0014953613281250, 0.0019836425781250, +0.0017700195312500, 0.0021667480468750, 0.0014038085937500, 0.0019531250000000, +0.0016479492187500, 0.0020751953125000, 0.0014953613281250, 0.0021057128906250, +0.0011901855468750, 0.0019836425781250, 0.0015563964843750, 0.0021667480468750, +0.0006103515625000, 0.0019226074218750, 0.0008544921875000, 0.0019836425781250, +0.0004272460937500, 0.0019836425781250, -0.0003662109375000, 0.0018920898437500, +0.0000915527343750, 0.0019836425781250, -0.0009765625000000, 0.0019226074218750, +-0.0010375976562500, 0.0019226074218750, -0.0010070800781250, 0.0018920898437500, +-0.0015563964843750, 0.0018615722656250, -0.0013427734375000, 0.0018615722656250, +-0.0013122558593750, 0.0018005371093750, -0.0014038085937500, 0.0018310546875000, +-0.0010681152343750, 0.0018615722656250, -0.0007629394531250, 0.0018005371093750, +-0.0008850097656250, 0.0017089843750000, -0.0002746582031250, 0.0018920898437500, +-0.0002136230468750, 0.0017700195312500, -0.0000305175781250, 0.0017395019531250, +0.0003967285156250, 0.0018005371093750, 0.0003662109375000, 0.0017089843750000, +0.0006713867187500, 0.0017089843750000, 0.0008544921875000, 0.0017089843750000, +0.0008544921875000, 0.0016784667968750, 0.0010070800781250, 0.0015869140625000, +0.0010375976562500, 0.0015258789062500, 0.0008239746093750, 0.0016174316406250, +0.0010681152343750}, +{0.0012207031250000, 0.0029602050781250, 0.0014343261718750, 0.0026550292968750, +0.0011596679687500, 0.0025939941406250, 0.0011901855468750, 0.0030212402343750, +0.0013732910156250, 0.0025329589843750, 0.0006713867187500, 0.0025329589843750, +0.0009155273437500, 0.0024108886718750, 0.0006713867187500, 0.0023193359375000, +0.0000915527343750, 0.0022888183593750, 0.0004577636718750, 0.0019836425781250, +-0.0001220703125000, 0.0022583007812500, -0.0000915527343750, 0.0020446777343750, +0.0000915527343750, 0.0021057128906250, -0.0001831054687500, 0.0023498535156250, +-0.0001525878906250, 0.0020446777343750, 0.0004272460937500, 0.0023803710937500, +0.0002136230468750, 0.0023498535156250, 0.0006103515625000, 0.0022277832031250, +0.0012512207031250, 0.0023498535156250, 0.0008239746093750, 0.0023498535156250, +0.0018615722656250, 0.0020751953125000, 0.0018310546875000, 0.0021362304687500, +0.0019531250000000, 0.0021972656250000, 0.0026245117187500, 0.0020446777343750, +0.0023498535156250, 0.0021362304687500, 0.0026550292968750, 0.0023498535156250, +0.0028076171875000, 0.0022888183593750, 0.0023803710937500, 0.0024108886718750, +0.0022888183593750, 0.0026550292968750, 0.0024719238281250, 0.0025634765625000, +0.0013732910156250, 0.0028076171875000, 0.0015869140625000, 0.0027770996093750, +0.0010375976562500, 0.0028686523437500, 0.0000610351562500, 0.0030212402343750, +0.0005187988281250, 0.0028381347656250, -0.0009460449218750, 0.0032043457031250, +-0.0008850097656250, 0.0030517578125000, -0.0010986328125000, 0.0031433105468750, +-0.0020141601562500, 0.0034790039062500, -0.0015258789062500, 0.0031738281250000, +-0.0021057128906250, 0.0035400390625000, -0.0020446777343750, 0.0035705566406250, +-0.0019531250000000, 0.0034179687500000, -0.0021362304687500, 0.0034790039062500, +-0.0018615722656250, 0.0034790039062500, -0.0017395019531250, 0.0032348632812500, +-0.0017395019531250, 0.0033264160156250, -0.0014953613281250, 0.0031433105468750, +-0.0012817382812500, 0.0028076171875000, -0.0014038085937500, 0.0029602050781250, +-0.0009460449218750, 0.0024108886718750, -0.0011291503906250, 0.0024719238281250, +-0.0008239746093750, 0.0023193359375000, -0.0003051757812500, 0.0018615722656250, +-0.0006713867187500, 0.0020446777343750, 0.0003051757812500, 0.0016784667968750, +0.0000610351562500, 0.0015869140625000, 0.0003051757812500, 0.0015869140625000, +0.0010375976562500, 0.0013732910156250, 0.0005187988281250, 0.0013122558593750, +0.0010375976562500, 0.0014648437500000, 0.0011291503906250, 0.0011901855468750, +0.0008850097656250, 0.0013732910156250, 0.0009155273437500, 0.0015869140625000, +0.0009155273437500, 0.0012512207031250, 0.0005187988281250, 0.0018615722656250, +0.0006408691406250, 0.0017700195312500, 0.0005798339843750, 0.0018005371093750, +0.0002136230468750, 0.0022277832031250, 0.0003967285156250, 0.0019531250000000, +0.0003356933593750, 0.0022888183593750, 0.0002746582031250, 0.0022888183593750, +0.0004272460937500, 0.0022277832031250, 0.0005493164062500, 0.0023803710937500, +0.0004577636718750, 0.0022277832031250, 0.0007629394531250, 0.0023193359375000, +0.0006103515625000, 0.0022583007812500, 0.0007934570312500, 0.0022277832031250, +0.0010681152343750, 0.0022583007812500, 0.0008239746093750, 0.0020751953125000, +0.0012207031250000, 0.0021057128906250, 0.0011291503906250, 0.0020446777343750, +0.0010070800781250, 0.0019836425781250, 0.0011291503906250, 0.0020141601562500, +0.0011291503906250, 0.0019531250000000, 0.0008544921875000, 0.0022888183593750, +0.0009460449218750, 0.0021057128906250, 0.0007324218750000, 0.0023498535156250, +0.0003967285156250, 0.0028076171875000, 0.0005493164062500, 0.0024414062500000, +0.0001831054687500, 0.0031127929687500, -0.0001220703125000, 0.0030822753906250, +0.0000000000000000, 0.0029907226562500, -0.0000305175781250, 0.0032958984375000, +-0.0003356933593750, 0.0032348632812500, 0.0004272460937500, 0.0030822753906250, +0.0000000000000000, 0.0032043457031250, 0.0004882812500000, 0.0030822753906250, +0.0013732910156250, 0.0028381347656250, 0.0007019042968750, 0.0028991699218750, +0.0021972656250000, 0.0028381347656250, 0.0021972656250000, 0.0027465820312500, +0.0022888183593750, 0.0027465820312500, 0.0031127929687500, 0.0026855468750000, +0.0028991699218750, 0.0026855468750000, 0.0032348632812500, 0.0024108886718750, +0.0034179687500000, 0.0024719238281250, 0.0033569335937500, 0.0022888183593750, +0.0034484863281250, 0.0018920898437500, 0.0036315917968750, 0.0018005371093750, +0.0038146972656250, 0.0017089843750000, 0.0037536621093750, 0.0015869140625000, +0.0037841796875000, 0.0016479492187500, 0.0039672851562500, 0.0016784667968750, +0.0039367675781250, 0.0014648437500000, 0.0038757324218750, 0.0019531250000000, +0.0039062500000000, 0.0017089843750000, 0.0037536621093750, 0.0019531250000000, +0.0036010742187500, 0.0025634765625000, 0.0037231445312500, 0.0021362304687500, +0.0033264160156250, 0.0029907226562500, 0.0034790039062500, 0.0029907226562500, +0.0032348632812500, 0.0029907226562500, 0.0030822753906250, 0.0035095214843750, +0.0034790039062500, 0.0033569335937500, 0.0024719238281250, 0.0034790039062500, +0.0028991699218750, 0.0036315917968750, 0.0024108886718750, 0.0034179687500000, +0.0014343261718750, 0.0032348632812500, 0.0022277832031250, 0.0034179687500000, +0.0010375976562500, 0.0028076171875000, 0.0010070800781250, 0.0029296875000000, +0.0010375976562500, 0.0028076171875000, 0.0004272460937500, 0.0024108886718750, +0.0005798339843750, 0.0026245117187500, 0.0005798339843750, 0.0022583007812500, +0.0003356933593750, 0.0022583007812500, 0.0006103515625000, 0.0022277832031250, +0.0008239746093750, 0.0019836425781250, 0.0004882812500000, 0.0020751953125000, +0.0014038085937500, 0.0019226074218750, 0.0011901855468750, 0.0018615722656250, +0.0014343261718750, 0.0018310546875000, 0.0022583007812500, 0.0017089843750000, +0.0017700195312500, 0.0017089843750000, 0.0021057128906250, 0.0014953613281250, +0.0022583007812500, 0.0014343261718750, 0.0020446777343750, 0.0014953613281250, +0.0020141601562500, 0.0014343261718750, 0.0020751953125000, 0.0013427734375000, +0.0016784667968750, 0.0014343261718750, 0.0017700195312500, 0.0013427734375000, +0.0017089843750000, 0.0013122558593750, 0.0014343261718750, 0.0013427734375000, +0.0016784667968750, 0.0012817382812500, 0.0013427734375000, 0.0011901855468750, +0.0014648437500000, 0.0011291503906250, 0.0015258789062500, 0.0010375976562500, +0.0014343261718750, 0.0009765625000000, 0.0015258789062500, 0.0009765625000000, +0.0014038085937500, 0.0007019042968750, 0.0014648437500000, 0.0006713867187500, +0.0015563964843750, 0.0006103515625000, 0.0015258789062500, 0.0003051757812500, +0.0015563964843750, 0.0003356933593750, 0.0016479492187500, 0.0005798339843750, +0.0016784667968750, 0.0003356933593750, 0.0017089843750000, 0.0006408691406250, +0.0017089843750000, 0.0010986328125000, 0.0017700195312500, 0.0007934570312500, +0.0021057128906250, 0.0013122558593750, 0.0019226074218750, 0.0014343261718750, +0.0022583007812500, 0.0013122558593750, 0.0026550292968750, 0.0015563964843750, +0.0022583007812500, 0.0015258789062500, 0.0031127929687500, 0.0014038085937500, +0.0029602050781250, 0.0014343261718750, 0.0030212402343750, 0.0013732910156250, +0.0034484863281250, 0.0012817382812500, 0.0030212402343750, 0.0013427734375000, +0.0035705566406250, 0.0011596679687500, 0.0032958984375000, 0.0011291503906250, +0.0033874511718750, 0.0010986328125000, 0.0038146972656250, 0.0010070800781250, +0.0034790039062500, 0.0010070800781250, 0.0038146972656250, 0.0009765625000000, +0.0038146972656250, 0.0009155273437500, 0.0036010742187500, 0.0008239746093750, +0.0036621093750000, 0.0007934570312500, 0.0036621093750000, 0.0007324218750000, +0.0032348632812500, 0.0005187988281250, 0.0033264160156250, 0.0005798339843750, +0.0030517578125000, 0.0004577636718750, 0.0025939941406250, 0.0002136230468750, +0.0027465820312500, 0.0001831054687500, 0.0022583007812500, 0.0000000000000000, +0.0021362304687500, -0.0000915527343750, 0.0021057128906250, -0.0002441406250000, +0.0018005371093750, -0.0004272460937500, 0.0018005371093750, -0.0004272460937500, +0.0018005371093750, -0.0006408691406250, 0.0016174316406250, -0.0006408691406250, +0.0015869140625000, -0.0007934570312500, 0.0015563964843750, -0.0010070800781250, +0.0014038085937500, -0.0008850097656250, 0.0014953613281250, -0.0012817382812500, +0.0013427734375000, -0.0011291503906250, 0.0012817382812500, -0.0012817382812500, +0.0013732910156250, -0.0015563964843750, 0.0011596679687500, -0.0012512207031250, +0.0013122558593750, -0.0018005371093750, 0.0012817382812500, -0.0016479492187500, +0.0012817382812500, -0.0017089843750000, 0.0013427734375000, -0.0020751953125000, +0.0012512207031250, -0.0018310546875000, 0.0013732910156250, -0.0019836425781250, +0.0014038085937500, -0.0021667480468750, 0.0014343261718750, -0.0018005371093750, +0.0014343261718750, -0.0016784667968750, 0.0014953613281250, -0.0018615722656250, +0.0016479492187500, -0.0007934570312500, 0.0016479492187500, -0.0009460449218750, +0.0017089843750000, -0.0006713867187500, 0.0018310546875000, 0.0002136230468750, +0.0018615722656250, -0.0001525878906250, 0.0018615722656250, 0.0003967285156250, +0.0019531250000000, 0.0006103515625000, 0.0018920898437500, 0.0005187988281250, +0.0018615722656250, 0.0005798339843750, 0.0020446777343750, 0.0007019042968750, +0.0017700195312500, 0.0003356933593750, 0.0018920898437500, 0.0005187988281250, +0.0018920898437500, 0.0002746582031250, 0.0017700195312500, -0.0001220703125000, +0.0019531250000000, 0.0001525878906250, 0.0018615722656250, -0.0002136230468750, +0.0019226074218750, -0.0003051757812500, 0.0020141601562500, -0.0000915527343750, +0.0020751953125000, -0.0000305175781250, 0.0020446777343750, -0.0000610351562500, +0.0021362304687500, 0.0002136230468750, 0.0021972656250000, 0.0003662109375000, +0.0022888183593750, 0.0003051757812500, 0.0023498535156250, 0.0003662109375000, +0.0023498535156250, 0.0005187988281250, 0.0025329589843750, 0.0002136230468750, +0.0024719238281250, 0.0003967285156250, 0.0025939941406250, 0.0003356933593750, +0.0026855468750000, 0.0000305175781250, 0.0025634765625000, 0.0002746582031250, +0.0028686523437500, 0.0002136230468750, 0.0028381347656250, 0.0001220703125000, +0.0028686523437500, 0.0003356933593750, 0.0030822753906250, 0.0004882812500000, +0.0029907226562500, 0.0003662109375000, 0.0028381347656250, 0.0010070800781250, +0.0029907226562500, 0.0008850097656250, 0.0026855468750000, 0.0010986328125000, +0.0023193359375000, 0.0016174316406250, 0.0025329589843750, 0.0015258789062500, +0.0020141601562500, 0.0018615722656250, 0.0018920898437500, 0.0019836425781250, +0.0018920898437500, 0.0020751953125000, 0.0017089843750000, 0.0021667480468750, +0.0017089843750000, 0.0021972656250000, 0.0016479492187500, 0.0021362304687500, +0.0016174316406250, 0.0021667480468750, 0.0015869140625000, 0.0021972656250000, +0.0015563964843750, 0.0021362304687500, 0.0015258789062500, 0.0019531250000000, +0.0015869140625000, 0.0019226074218750, 0.0014343261718750, 0.0019836425781250, +0.0017395019531250, 0.0016479492187500, 0.0018920898437500, 0.0014038085937500, +0.0016784667968750, 0.0015563964843750, 0.0026855468750000, 0.0008544921875000, +0.0024108886718750, 0.0008850097656250, 0.0027770996093750, 0.0007324218750000, +0.0036621093750000}, +{0.0031738281250000, 0.0009155273437500, 0.0028076171875000, 0.0007629394531250, +0.0031127929687500, 0.0009460449218750, 0.0024414062500000, 0.0003356933593750, +0.0025634765625000, 0.0004882812500000, 0.0025024414062500, 0.0002441406250000, +0.0020751953125000, -0.0002746582031250, 0.0024108886718750, 0.0000000000000000, +0.0019226074218750, -0.0007019042968750, 0.0019836425781250, -0.0006103515625000, +0.0018615722656250, -0.0007934570312500, 0.0015258789062500, -0.0013122558593750, +0.0017395019531250, -0.0011291503906250, 0.0012817382812500, -0.0016174316406250, +0.0012817382812500, -0.0017089843750000, 0.0011901855468750, -0.0016174316406250, +0.0009460449218750, -0.0017700195312500, 0.0011291503906250, -0.0017700195312500, +0.0010070800781250, -0.0015258789062500, 0.0010070800781250, -0.0016174316406250, +0.0011291503906250, -0.0014038085937500, 0.0012207031250000, -0.0010986328125000, +0.0013122558593750, -0.0013122558593750, 0.0014038085937500, -0.0006408691406250, +0.0015563964843750, -0.0008544921875000, 0.0015563964843750, -0.0003051757812500, +0.0016174316406250, 0.0004882812500000, 0.0018005371093750, -0.0000305175781250, +0.0016784667968750, 0.0015258789062500, 0.0018005371093750, 0.0014648437500000, +0.0018615722656250, 0.0018310546875000, 0.0017700195312500, 0.0028686523437500, +0.0019531250000000, 0.0025939941406250, 0.0019226074218750, 0.0032958984375000, +0.0020141601562500, 0.0036010742187500, 0.0020446777343750, 0.0034484863281250, +0.0020141601562500, 0.0037536621093750, 0.0021362304687500, 0.0039062500000000, +0.0020446777343750, 0.0031127929687500, 0.0020751953125000, 0.0035095214843750, +0.0021667480468750, 0.0030212402343750, 0.0021667480468750, 0.0021362304687500, +0.0021972656250000, 0.0027465820312500, 0.0023193359375000, 0.0014343261718750, +0.0022583007812500, 0.0014343261718750, 0.0023193359375000, 0.0014343261718750, +0.0024414062500000, 0.0007629394531250, 0.0023803710937500, 0.0010070800781250, +0.0025634765625000, 0.0009460449218750, 0.0025634765625000, 0.0008544921875000, +0.0025939941406250, 0.0009765625000000, 0.0027160644531250, 0.0010986328125000, +0.0026245117187500, 0.0010986328125000, 0.0026245117187500, 0.0012512207031250, +0.0026245117187500, 0.0012817382812500, 0.0025329589843750, 0.0011901855468750, +0.0024719238281250, 0.0012207031250000, 0.0024719238281250, 0.0011901855468750, +0.0024719238281250, 0.0010681152343750, 0.0023803710937500, 0.0010070800781250, +0.0024108886718750, 0.0010986328125000, 0.0025024414062500, 0.0010375976562500, +0.0024108886718750, 0.0009765625000000, 0.0026550292968750, 0.0013427734375000, +0.0026550292968750, 0.0012817382812500, 0.0026855468750000, 0.0015258789062500, +0.0028686523437500, 0.0019531250000000, 0.0028076171875000, 0.0018005371093750, +0.0029602050781250, 0.0021972656250000, 0.0028991699218750, 0.0023803710937500, +0.0030212402343750, 0.0023803710937500, 0.0030822753906250, 0.0025329589843750, +0.0029907226562500, 0.0025634765625000, 0.0035400390625000, 0.0025329589843750, +0.0034484863281250, 0.0025939941406250, 0.0035400390625000, 0.0025634765625000, +0.0039367675781250, 0.0025329589843750, 0.0038146972656250, 0.0026245117187500, +0.0039672851562500, 0.0023803710937500, 0.0041503906250000, 0.0024719238281250, +0.0038757324218750, 0.0024108886718750, 0.0037536621093750, 0.0022277832031250, +0.0040283203125000, 0.0022888183593750, 0.0032958984375000, 0.0017089843750000, +0.0034179687500000, 0.0018310546875000, 0.0031433105468750, 0.0016784667968750, +0.0025634765625000, 0.0011596679687500, 0.0028991699218750, 0.0013122558593750, +0.0019836425781250, 0.0012207031250000, 0.0019836425781250, 0.0010375976562500, +0.0019226074218750, 0.0011596679687500, 0.0010986328125000, 0.0014953613281250, +0.0016174316406250, 0.0026550292968750, 0.0012817382812500, 0.0022277832031250, +0.0014953613281250, 0.0023803710937500, 0.0014343261718750, 0.0022583007812500, +0.0012512207031250, 0.0020141601562500, 0.0013732910156250, 0.0020751953125000, +0.0014038085937500, 0.0017700195312500, 0.0013427734375000, 0.0019226074218750, +0.0015258789062500, 0.0019531250000000, 0.0015869140625000, 0.0017700195312500, +0.0014953613281250, 0.0019531250000000, 0.0019531250000000, 0.0020446777343750, +0.0018310546875000, 0.0019531250000000, 0.0019836425781250, 0.0021362304687500, +0.0023193359375000, 0.0025024414062500, 0.0021057128906250, 0.0022583007812500, +0.0022888183593750, 0.0023193359375000, 0.0023803710937500, 0.0024108886718750, +0.0022583007812500, 0.0022277832031250, 0.0022888183593750, 0.0019836425781250, +0.0023498535156250, 0.0021057128906250, 0.0020751953125000, 0.0018005371093750, +0.0023498535156250, 0.0018920898437500, 0.0020446777343750, 0.0016479492187500, +0.0017089843750000, 0.0013122558593750, 0.0021362304687500, 0.0017089843750000, +0.0010070800781250, 0.0015258789062500, 0.0012512207031250, 0.0013427734375000, +0.0008850097656250, 0.0016784667968750, -0.0000610351562500, 0.0018615722656250, +0.0004577636718750, 0.0016174316406250, -0.0004882812500000, 0.0025024414062500, +-0.0005493164062500, 0.0022277832031250, -0.0005798339843750, 0.0025634765625000, +-0.0010375976562500, 0.0034790039062500, -0.0008239746093750, 0.0028381347656250, +-0.0012207031250000, 0.0033569335937500, -0.0010681152343750, 0.0036010742187500, +-0.0013122558593750, 0.0030212402343750, -0.0016479492187500, 0.0028686523437500, +-0.0013122558593750, 0.0032043457031250, -0.0024414062500000, 0.0019531250000000, +-0.0021972656250000, 0.0020141601562500, -0.0024414062500000, 0.0017395019531250, +-0.0033874511718750, 0.0008239746093750, -0.0029602050781250, 0.0010070800781250, +-0.0034484863281250, 0.0009765625000000, -0.0037231445312500, 0.0003967285156250, +-0.0032348632812500, 0.0009155273437500, -0.0031738281250000, 0.0014343261718750, +-0.0035705566406250, 0.0007629394531250, -0.0020141601562500, 0.0020751953125000, +-0.0025024414062500, 0.0018920898437500, -0.0018005371093750, 0.0018920898437500, +-0.0003051757812500, 0.0027770996093750, -0.0012207031250000, 0.0025939941406250, +0.0006103515625000, 0.0024719238281250, 0.0006103515625000, 0.0028076171875000, +0.0004882812500000, 0.0025329589843750, 0.0014343261718750, 0.0022583007812500, +0.0010681152343750, 0.0026855468750000, 0.0004882812500000, 0.0020141601562500, +0.0009155273437500, 0.0022583007812500, 0.0001831054687500, 0.0022583007812500, +-0.0009460449218750, 0.0019531250000000, -0.0003662109375000, 0.0023498535156250, +-0.0018310546875000, 0.0019226074218750, -0.0020141601562500, 0.0021057128906250, +-0.0019836425781250, 0.0021057128906250, -0.0028076171875000, 0.0018615722656250, +-0.0028686523437500, 0.0022277832031250, -0.0022888183593750, 0.0017395019531250, +-0.0029602050781250, 0.0018310546875000, -0.0024414062500000, 0.0018310546875000, +-0.0015869140625000, 0.0015869140625000, -0.0024719238281250, 0.0017395019531250, +-0.0007934570312500, 0.0018005371093750, -0.0010681152343750, 0.0015563964843750, +-0.0009765625000000, 0.0017700195312500, 0.0000915527343750, 0.0020446777343750, +-0.0005187988281250, 0.0018310546875000, 0.0000000000000000, 0.0020446777343750, +0.0001220703125000, 0.0021972656250000, -0.0001525878906250, 0.0020446777343750, +-0.0000305175781250, 0.0020141601562500, 0.0000610351562500, 0.0021362304687500, +-0.0006408691406250, 0.0016784667968750, -0.0003356933593750, 0.0018310546875000, +-0.0006408691406250, 0.0016784667968750, -0.0013122558593750, 0.0012512207031250, +-0.0007629394531250, 0.0014648437500000, -0.0015258789062500, 0.0013427734375000, +-0.0015869140625000, 0.0012207031250000, -0.0014038085937500, 0.0013427734375000, +-0.0017395019531250, 0.0014343261718750, -0.0016479492187500, 0.0014038085937500, +-0.0011901855468750, 0.0015258789062500, -0.0014648437500000, 0.0015869140625000, +-0.0009155273437500, 0.0015869140625000, -0.0002136230468750, 0.0016174316406250, +-0.0007934570312500, 0.0017089843750000, 0.0008239746093750, 0.0015563964843750, +0.0003967285156250, 0.0016174316406250, 0.0010375976562500, 0.0016479492187500, +0.0023803710937500, 0.0015869140625000, 0.0015258789062500, 0.0017700195312500, +0.0032958984375000, 0.0015869140625000, 0.0032348632812500, 0.0017395019531250, +0.0033264160156250, 0.0016784667968750, 0.0043640136718750, 0.0015258789062500, +0.0038757324218750, 0.0017700195312500, 0.0041503906250000, 0.0014038085937500, +0.0043945312500000, 0.0015563964843750, 0.0038757324218750, 0.0016174316406250, +0.0035705566406250, 0.0013732910156250, 0.0037536621093750, 0.0016174316406250, +0.0025634765625000, 0.0013732910156250, 0.0027465820312500, 0.0015869140625000, +0.0022277832031250, 0.0014953613281250, 0.0011291503906250, 0.0012512207031250, +0.0016784667968750, 0.0016784667968750, 0.0005493164062500, 0.0013732910156250, +0.0005798339843750, 0.0014343261718750, 0.0004882812500000, 0.0015563964843750, +-0.0000610351562500, 0.0014648437500000, 0.0003051757812500, 0.0016479492187500, +-0.0002746582031250, 0.0016174316406250, -0.0000915527343750, 0.0016784667968750, +-0.0001220703125000, 0.0016784667968750, -0.0004577636718750, 0.0017089843750000, +-0.0000915527343750, 0.0018920898437500, -0.0004882812500000, 0.0016174316406250, +-0.0003662109375000, 0.0018005371093750, -0.0003356933593750, 0.0017089843750000, +-0.0005187988281250, 0.0014648437500000, -0.0003356933593750, 0.0017700195312500, +-0.0006103515625000, 0.0013427734375000, -0.0005187988281250, 0.0014953613281250, +-0.0005798339843750, 0.0015258789062500, -0.0007934570312500, 0.0012817382812500, +-0.0007324218750000, 0.0015258789062500, -0.0009460449218750, 0.0013732910156250, +-0.0009155273437500, 0.0014953613281250, -0.0010375976562500, 0.0015869140625000, +-0.0013427734375000, 0.0015258789062500, -0.0011901855468750, 0.0017089843750000, +-0.0014953613281250, 0.0018005371093750, -0.0015869140625000, 0.0018920898437500, +-0.0014648437500000, 0.0020446777343750, -0.0015258789062500, 0.0021667480468750, +-0.0014648437500000, 0.0021972656250000, -0.0011291503906250, 0.0024414062500000, +-0.0011596679687500, 0.0025024414062500, -0.0007629394531250, 0.0025024414062500, +-0.0003051757812500, 0.0025939941406250, -0.0005187988281250, 0.0026550292968750, +0.0002136230468750, 0.0025939941406250, 0.0002441406250000, 0.0025634765625000, +0.0005187988281250, 0.0025939941406250, 0.0011291503906250, 0.0025329589843750, +0.0008544921875000, 0.0024414062500000, 0.0015563964843750, 0.0024719238281250, +0.0016174316406250, 0.0023803710937500, 0.0016174316406250, 0.0023193359375000, +0.0020446777343750, 0.0023498535156250, 0.0020141601562500, 0.0022888183593750, +0.0017395019531250, 0.0021972656250000, 0.0021057128906250, 0.0021667480468750, +0.0018005371093750, 0.0021972656250000, 0.0012817382812500, 0.0020751953125000, +0.0017395019531250, 0.0020751953125000, 0.0011596679687500, 0.0023193359375000, +0.0011291503906250, 0.0021057128906250, 0.0014038085937500, 0.0023803710937500, +0.0012817382812500, 0.0027465820312500, 0.0013427734375000, 0.0024414062500000, +0.0016174316406250, 0.0031738281250000, 0.0017089843750000, 0.0031433105468750, +0.0015869140625000, 0.0032653808593750, 0.0015258789062500, 0.0038146972656250, +0.0013732910156250, 0.0037536621093750, 0.0007324218750000, 0.0039062500000000, +0.0009155273437500, 0.0039978027343750, 0.0007934570312500, 0.0039978027343750, +0.0003051757812500, 0.0041809082031250, 0.0005187988281250, 0.0043334960937500, +0.0002441406250000}, +{0.0024719238281250, 0.0018310546875000, 0.0023193359375000, 0.0017395019531250, +0.0025939941406250, 0.0016174316406250, 0.0024414062500000, 0.0015869140625000, +0.0022583007812500, 0.0015869140625000, 0.0025329589843750, 0.0014648437500000, +0.0019531250000000, 0.0015258789062500, 0.0021362304687500, 0.0014648437500000, +0.0018615722656250, 0.0014648437500000, 0.0013732910156250, 0.0014953613281250, +0.0017089843750000, 0.0013732910156250, 0.0007019042968750, 0.0016479492187500, +0.0009155273437500, 0.0014343261718750, 0.0004272460937500, 0.0016479492187500, +-0.0004882812500000, 0.0019226074218750, 0.0000305175781250, 0.0016174316406250, +-0.0013122558593750, 0.0021972656250000, -0.0011596679687500, 0.0021362304687500, +-0.0014343261718750, 0.0021667480468750, -0.0023803710937500, 0.0025634765625000, +-0.0018310546875000, 0.0023803710937500, -0.0025024414062500, 0.0025634765625000, +-0.0026245117187500, 0.0025939941406250, -0.0023803710937500, 0.0024108886718750, +-0.0025024414062500, 0.0023193359375000, -0.0024414062500000, 0.0024108886718750, +-0.0019226074218750, 0.0020141601562500, -0.0020446777343750, 0.0020141601562500, +-0.0017395019531250, 0.0018615722656250, -0.0012512207031250, 0.0015258789062500, +-0.0015563964843750, 0.0015869140625000, -0.0007324218750000, 0.0013122558593750, +-0.0007324218750000, 0.0012817382812500, -0.0006713867187500, 0.0013122558593750, +-0.0002441406250000, 0.0012512207031250, -0.0004272460937500, 0.0012207031250000, +-0.0000610351562500, 0.0014038085937500, -0.0000305175781250, 0.0012817382812500, +-0.0000915527343750, 0.0015258789062500, 0.0001831054687500, 0.0018005371093750, +0.0000305175781250, 0.0015869140625000, -0.0003051757812500, 0.0021972656250000, +-0.0001220703125000, 0.0020751953125000, -0.0005493164062500, 0.0022277832031250, +-0.0010986328125000, 0.0026245117187500, -0.0008239746093750, 0.0024108886718750, +-0.0017700195312500, 0.0026855468750000, -0.0018310546875000, 0.0028076171875000, +-0.0017395019531250, 0.0025634765625000, -0.0021972656250000, 0.0026245117187500, +-0.0022583007812500, 0.0027160644531250, -0.0019836425781250, 0.0024414062500000, +-0.0022888183593750, 0.0025634765625000, -0.0020141601562500, 0.0024414062500000, +-0.0016174316406250, 0.0022277832031250, -0.0020141601562500, 0.0024108886718750, +-0.0010986328125000, 0.0020751953125000, -0.0012512207031250, 0.0021057128906250, +-0.0010375976562500, 0.0021057128906250, -0.0003356933593750, 0.0018920898437500, +-0.0006713867187500, 0.0018920898437500, -0.0000610351562500, 0.0020751953125000, +0.0001525878906250, 0.0018310546875000, -0.0000610351562500, 0.0020751953125000, +0.0000000000000000, 0.0024414062500000, 0.0001525878906250, 0.0020751953125000, +-0.0001831054687500, 0.0028381347656250, -0.0002746582031250, 0.0027770996093750, +-0.0000610351562500, 0.0028381347656250, -0.0001220703125000, 0.0033264160156250, +-0.0002441406250000, 0.0031127929687500, 0.0007019042968750, 0.0034179687500000, +0.0004882812500000, 0.0034790039062500, 0.0007324218750000, 0.0033874511718750, +0.0016479492187500, 0.0036010742187500, 0.0014343261718750, 0.0036621093750000, +0.0017089843750000, 0.0033264160156250, 0.0017089843750000, 0.0035705566406250, +0.0016784667968750, 0.0034179687500000, 0.0018005371093750, 0.0031127929687500, +0.0018310546875000, 0.0034179687500000, 0.0017089843750000, 0.0027770996093750, +0.0018920898437500, 0.0029907226562500, 0.0017395019531250, 0.0027770996093750, +0.0014648437500000, 0.0023498535156250, 0.0017395019531250, 0.0027160644531250, +0.0014343261718750, 0.0019226074218750, 0.0012817382812500, 0.0021362304687500, +0.0014648437500000, 0.0018310546875000, 0.0014648437500000, 0.0011901855468750, +0.0012512207031250, 0.0016784667968750, 0.0018920898437500, 0.0006408691406250, +0.0017089843750000, 0.0008239746093750, 0.0018005371093750, 0.0005493164062500, +0.0023193359375000, -0.0001831054687500, 0.0020446777343750, 0.0002746582031250, +0.0024719238281250, -0.0004577636718750, 0.0025329589843750, -0.0003662109375000, +0.0023193359375000, -0.0003662109375000, 0.0024719238281250, -0.0007324218750000, +0.0025939941406250, -0.0005187988281250, 0.0022888183593750, -0.0005798339843750, +0.0022583007812500, -0.0005187988281250, 0.0022888183593750, -0.0003967285156250, +0.0021972656250000, -0.0003051757812500, 0.0022277832031250, -0.0001831054687500, +0.0021362304687500, 0.0000610351562500, 0.0022277832031250, 0.0000915527343750, +0.0020751953125000, 0.0002136230468750, 0.0019531250000000, 0.0003662109375000, +0.0021362304687500, 0.0003356933593750, 0.0016784667968750, 0.0007629394531250, +0.0017700195312500, 0.0006408691406250, 0.0017395019531250, 0.0008850097656250, +0.0014648437500000, 0.0013122558593750, 0.0015869140625000, 0.0011596679687500, +0.0013427734375000, 0.0016479492187500, 0.0013427734375000, 0.0017089843750000, +0.0014953613281250, 0.0018005371093750, 0.0014343261718750, 0.0021667480468750, +0.0013427734375000, 0.0020446777343750, 0.0020141601562500, 0.0020141601562500, +0.0017395019531250, 0.0021972656250000, 0.0021362304687500, 0.0020141601562500, +0.0027770996093750, 0.0017395019531250, 0.0023193359375000, 0.0019226074218750, +0.0033569335937500, 0.0012817382812500, 0.0032043457031250, 0.0013122558593750, +0.0032043457031250, 0.0011901855468750, 0.0038452148437500, 0.0007324218750000, +0.0035705566406250, 0.0009460449218750, 0.0036010742187500, 0.0007934570312500, +0.0037841796875000, 0.0007019042968750, 0.0034179687500000, 0.0007629394531250, +0.0031127929687500, 0.0008544921875000, 0.0033569335937500, 0.0007934570312500, +0.0029907226562500, 0.0008239746093750, 0.0028991699218750, 0.0009155273437500, +0.0028991699218750, 0.0007629394531250, 0.0028076171875000, 0.0006103515625000, +0.0028381347656250, 0.0007629394531250, 0.0028991699218750, 0.0003356933593750, +0.0029296875000000, 0.0004272460937500, 0.0028076171875000, 0.0003051757812500, +0.0027465820312500, -0.0000610351562500, 0.0028381347656250, 0.0001220703125000, +0.0023498535156250, -0.0003662109375000, 0.0023803710937500, -0.0003051757812500, +0.0022583007812500, -0.0005187988281250, 0.0018615722656250, -0.0008544921875000, +0.0020141601562500, -0.0007324218750000, 0.0017395019531250, -0.0012512207031250, +0.0017089843750000, -0.0011596679687500, 0.0017395019531250, -0.0012817382812500, +0.0015869140625000, -0.0015869140625000, 0.0015563964843750, -0.0013732910156250, +0.0017089843750000, -0.0016784667968750, 0.0015563964843750, -0.0016784667968750, +0.0015258789062500, -0.0016174316406250, 0.0016479492187500, -0.0017089843750000, +0.0015258789062500, -0.0016479492187500, 0.0015258789062500, -0.0014648437500000, +0.0014343261718750, -0.0015563964843750, 0.0013732910156250, -0.0012817382812500, +0.0013122558593750, -0.0009765625000000, 0.0012817382812500, -0.0012207031250000, +0.0013122558593750, -0.0000610351562500, 0.0011901855468750, -0.0003967285156250, +0.0012207031250000, 0.0001831054687500, 0.0013122558593750, 0.0011901855468750, +0.0012207031250000, 0.0005493164062500, 0.0012512207031250, 0.0021057128906250, +0.0012512207031250, 0.0019531250000000, 0.0012207031250000, 0.0020751953125000, +0.0012512207031250, 0.0030517578125000, 0.0011901855468750, 0.0026245117187500, +0.0011901855468750, 0.0026550292968750, 0.0011596679687500, 0.0029907226562500, +0.0011596679687500, 0.0023803710937500, 0.0011596679687500, 0.0019226074218750, +0.0010681152343750, 0.0022888183593750, 0.0012512207031250, 0.0006713867187500, +0.0011291503906250, 0.0008544921875000, 0.0012207031250000, 0.0003967285156250, +0.0013732910156250, -0.0009155273437500, 0.0012817382812500, -0.0004272460937500, +0.0014343261718750, -0.0011901855468750, 0.0013732910156250, -0.0014038085937500, +0.0013122558593750, -0.0012817382812500, 0.0013732910156250, -0.0015563964843750, +0.0013427734375000, -0.0015258789062500, 0.0012512207031250, -0.0015869140625000, +0.0012817382812500, -0.0015258789062500, 0.0012207031250000, -0.0014953613281250, +0.0010986328125000, -0.0014953613281250, 0.0011901855468750, -0.0014648437500000, +0.0011596679687500, -0.0013427734375000, 0.0011291503906250, -0.0013122558593750, +0.0011901855468750, -0.0014038085937500, 0.0012817382812500, -0.0014953613281250, +0.0012207031250000, -0.0014038085937500, 0.0014038085937500, -0.0013122558593750, +0.0013427734375000, -0.0015258789062500, 0.0013732910156250, -0.0012512207031250, +0.0014648437500000, -0.0010375976562500, 0.0013732910156250, -0.0012512207031250, +0.0014648437500000, -0.0004272460937500, 0.0014343261718750, -0.0005493164062500, +0.0014038085937500, -0.0003356933593750, 0.0013427734375000, 0.0003662109375000, +0.0013427734375000, 0.0000610351562500, 0.0014648437500000, 0.0004882812500000, +0.0013427734375000, 0.0007019042968750, 0.0015563964843750, 0.0005187988281250, +0.0017700195312500, 0.0005798339843750, 0.0015563964843750, 0.0007019042968750, +0.0020751953125000, 0.0000000000000000, 0.0021057128906250, 0.0002136230468750, +0.0022583007812500, -0.0000305175781250, 0.0025939941406250, -0.0006713867187500, +0.0024719238281250, -0.0003967285156250, 0.0030822753906250, -0.0006408691406250, +0.0030212402343750, -0.0008850097656250, 0.0032043457031250, -0.0006408691406250, +0.0036010742187500, -0.0004882812500000, 0.0033874511718750, -0.0007019042968750, +0.0039672851562500, -0.0003051757812500, 0.0039367675781250, -0.0004272460937500, +0.0037841796875000, -0.0005798339843750, 0.0040588378906250, -0.0003662109375000, +0.0039672851562500, -0.0005187988281250, 0.0034790039062500, -0.0007629394531250, +0.0036926269531250, -0.0008239746093750, 0.0033264160156250, -0.0009460449218750, +0.0027770996093750, -0.0012512207031250, 0.0031127929687500, -0.0012207031250000, +0.0025024414062500, -0.0010070800781250, 0.0024108886718750, -0.0012512207031250, +0.0024414062500000, -0.0009765625000000, 0.0022888183593750, -0.0006408691406250, +0.0023498535156250, -0.0009155273437500, 0.0022277832031250, -0.0003356933593750, +0.0021362304687500, -0.0002441406250000, 0.0021057128906250, -0.0003967285156250, +0.0020446777343750, -0.0002441406250000, 0.0021057128906250, -0.0002136230468750, +0.0018920898437500, -0.0006103515625000, 0.0019836425781250, -0.0006408691406250, +0.0019226074218750, -0.0005493164062500, 0.0017700195312500, -0.0007629394531250, +0.0019531250000000, -0.0008239746093750, 0.0016479492187500, -0.0000915527343750, +0.0017395019531250, -0.0004882812500000, 0.0017395019531250, -0.0002746582031250, +0.0014343261718750, 0.0010070800781250, 0.0021362304687500, -0.0008544921875000, +0.0023498535156250, 0.0003051757812500, 0.0025024414062500, -0.0003662109375000, +0.0023193359375000, 0.0003051757812500, 0.0022277832031250, 0.0012512207031250, +0.0024108886718750, 0.0008239746093750, 0.0019836425781250, 0.0014343261718750, +0.0020141601562500, 0.0015563964843750, 0.0018615722656250, 0.0014038085937500, +0.0014953613281250, 0.0015563964843750, 0.0016174316406250, 0.0014953613281250, +0.0009460449218750, 0.0014343261718750, 0.0010681152343750, 0.0015258789062500, +0.0007629394531250, 0.0015258789062500, 0.0001220703125000, 0.0015869140625000, +0.0004577636718750, 0.0017700195312500, -0.0004577636718750, 0.0015258789062500, +-0.0004577636718750, 0.0016784667968750, -0.0006103515625000, 0.0014953613281250, +-0.0011291503906250, 0.0012512207031250, -0.0009155273437500, 0.0016479492187500, +-0.0009155273437500, 0.0010986328125000, -0.0010375976562500, 0.0010986328125000, +-0.0008544921875000}, +{0.0010986328125000, -0.0003967285156250, 0.0011596679687500, -0.0003051757812500, +0.0014343261718750, 0.0000000000000000, 0.0011291503906250, -0.0001220703125000, +0.0013122558593750, 0.0001525878906250, 0.0011901855468750, 0.0002441406250000, +0.0011291503906250, 0.0001831054687500, 0.0011291503906250, 0.0003051757812500, +0.0009765625000000, 0.0002746582031250, 0.0010681152343750, 0.0000305175781250, +0.0009155273437500, 0.0000305175781250, 0.0010070800781250, 0.0000000000000000, +0.0012207031250000, -0.0002136230468750, 0.0009460449218750, -0.0001831054687500, +0.0014953613281250, -0.0000610351562500, 0.0013732910156250, -0.0002441406250000, +0.0015258789062500, 0.0000305175781250, 0.0020141601562500, 0.0003356933593750, +0.0017395019531250, 0.0002136230468750, 0.0022888183593750, 0.0006713867187500, +0.0022888183593750, 0.0007324218750000, 0.0024719238281250, 0.0007324218750000, +0.0028991699218750, 0.0010070800781250, 0.0027465820312500, 0.0009460449218750, +0.0032348632812500, 0.0009765625000000, 0.0033264160156250, 0.0008850097656250, +0.0032043457031250, 0.0008850097656250, 0.0033569335937500, 0.0008239746093750, +0.0033264160156250, 0.0007019042968750, 0.0029907226562500, 0.0010070800781250, +0.0031433105468750, 0.0007934570312500, 0.0028076171875000, 0.0009155273437500, +0.0023193359375000, 0.0012817382812500, 0.0025329589843750, 0.0010070800781250, +0.0021057128906250, 0.0013427734375000, 0.0018920898437500, 0.0014343261718750, +0.0018310546875000, 0.0011596679687500, 0.0016784667968750, 0.0010986328125000, +0.0016174316406250, 0.0011596679687500, 0.0016174316406250, 0.0006103515625000, +0.0015258789062500, 0.0006103515625000, 0.0014648437500000, 0.0003662109375000, +0.0014648437500000, -0.0000610351562500, 0.0014038085937500, 0.0001220703125000, +0.0013732910156250, -0.0003356933593750, 0.0013732910156250, -0.0003356933593750, +0.0013122558593750, -0.0003662109375000, 0.0012817382812500, -0.0005798339843750, +0.0013122558593750, -0.0004272460937500, 0.0013122558593750, -0.0007324218750000, +0.0013732910156250, -0.0005798339843750, 0.0013427734375000, -0.0006713867187500, +0.0013427734375000, -0.0009155273437500, 0.0014343261718750, -0.0006713867187500, +0.0016784667968750, -0.0009765625000000, 0.0016784667968750, -0.0010375976562500, +0.0018310546875000, -0.0007934570312500, 0.0022277832031250, -0.0006408691406250, +0.0021362304687500, 0.0008239746093750, 0.0011596679687500, 0.0000305175781250, +0.0016479492187500, 0.0004272460937500, 0.0013427734375000, 0.0003967285156250, +0.0007019042968750, -0.0000305175781250, 0.0009765625000000, 0.0000915527343750, +0.0004882812500000, 0.0003967285156250, 0.0004577636718750, 0.0003356933593750, +0.0002746582031250, 0.0004577636718750, -0.0001220703125000, 0.0006713867187500, +-0.0000305175781250, 0.0005798339843750, -0.0005493164062500, 0.0003662109375000, +-0.0005798339843750, 0.0006408691406250, -0.0006713867187500, 0.0003356933593750, +-0.0010375976562500, -0.0001831054687500, -0.0010681152343750, 0.0001831054687500, +-0.0008850097656250, -0.0000610351562500, -0.0012512207031250, -0.0003051757812500, +-0.0010375976562500, 0.0000610351562500, -0.0006103515625000, 0.0003356933593750, +-0.0010681152343750, 0.0001220703125000, -0.0003967285156250, 0.0006713867187500, +-0.0005187988281250, 0.0005798339843750, -0.0005493164062500, 0.0005493164062500, +-0.0001831054687500, 0.0007934570312500, -0.0004882812500000, 0.0006408691406250, +-0.0000610351562500, 0.0007629394531250, -0.0002136230468750, 0.0006103515625000, +-0.0001831054687500, 0.0006103515625000, 0.0001831054687500, 0.0007324218750000, +-0.0000610351562500, 0.0006408691406250, 0.0006408691406250, 0.0007324218750000, +0.0005187988281250, 0.0006713867187500, 0.0007629394531250, 0.0008544921875000, +0.0013732910156250, 0.0009765625000000, 0.0011901855468750, 0.0008544921875000, +0.0018920898437500, 0.0010986328125000, 0.0021057128906250, 0.0011291503906250, +0.0020446777343750, 0.0010070800781250, 0.0022888183593750, 0.0010681152343750, +0.0023803710937500, 0.0009765625000000, 0.0018310546875000, 0.0004272460937500, +0.0022583007812500, 0.0004882812500000, 0.0016784667968750, 0.0003662109375000, +0.0009765625000000, -0.0000610351562500, 0.0015869140625000, 0.0000610351562500, +-0.0000305175781250, 0.0000305175781250, 0.0002441406250000, -0.0000610351562500, +-0.0000305175781250, 0.0003356933593750, -0.0011901855468750, 0.0006103515625000, +-0.0005187988281250, 0.0004577636718750, -0.0012512207031250, 0.0013122558593750, +-0.0014648437500000, 0.0012817382812500, -0.0010681152343750, 0.0013732910156250, +-0.0010681152343750, 0.0020446777343750, -0.0011901855468750, 0.0017700195312500, +-0.0002746582031250, 0.0016479492187500, -0.0004272460937500, 0.0018005371093750, +-0.0002441406250000, 0.0013732910156250, 0.0004577636718750, 0.0009765625000000, +0.0002136230468750, 0.0011291503906250, 0.0003051757812500, 0.0003662109375000, +0.0006103515625000, 0.0003662109375000, 0.0002441406250000, 0.0003051757812500, +-0.0000305175781250, -0.0000915527343750, 0.0004272460937500, 0.0001525878906250, +-0.0006408691406250, 0.0003051757812500, -0.0004882812500000, 0.0001220703125000, +-0.0005187988281250, 0.0003662109375000, -0.0012817382812500, 0.0006408691406250, +-0.0009460449218750, 0.0005187988281250, -0.0008239746093750, 0.0008239746093750, +-0.0011596679687500, 0.0007934570312500, -0.0004882812500000, 0.0005798339843750, +0.0000610351562500, 0.0006408691406250, -0.0004882812500000, 0.0007629394531250, +0.0010986328125000, 0.0003356933593750, 0.0008850097656250, 0.0003356933593750, +0.0011596679687500, 0.0003051757812500, 0.0022888183593750, 0.0000610351562500, +0.0017089843750000, 0.0001525878906250, 0.0025329589843750, 0.0000915527343750, +0.0026550292968750, 0.0000610351562500, 0.0024719238281250, 0.0000305175781250, +0.0027770996093750, 0.0000610351562500, 0.0028076171875000, 0.0000610351562500, +0.0023193359375000, 0.0000000000000000, 0.0025634765625000, -0.0000305175781250, +0.0022277832031250, -0.0001220703125000, 0.0016479492187500, -0.0002441406250000, +0.0020446777343750, -0.0002136230468750, 0.0012817382812500, -0.0002441406250000, +0.0013732910156250, -0.0003662109375000, 0.0011901855468750, -0.0003051757812500, +0.0006713867187500, -0.0001831054687500, 0.0009765625000000, -0.0002441406250000, +0.0002441406250000, -0.0000915527343750, 0.0003967285156250, 0.0000000000000000, +0.0001525878906250, -0.0000305175781250, -0.0004882812500000, 0.0000000000000000, +-0.0000915527343750, 0.0001525878906250, -0.0009155273437500, -0.0001220703125000, +-0.0008239746093750, 0.0001220703125000, -0.0008544921875000, 0.0000305175781250, +-0.0013732910156250, -0.0002746582031250, -0.0010375976562500, 0.0001831054687500, +-0.0012207031250000, -0.0002441406250000, -0.0012817382812500, -0.0000915527343750, +-0.0011291503906250, 0.0000915527343750, -0.0010681152343750, -0.0000305175781250, +-0.0010681152343750, 0.0003356933593750, -0.0007324218750000, 0.0003356933593750, +-0.0008544921875000, 0.0005493164062500, -0.0005798339843750, 0.0006713867187500, +-0.0002136230468750, 0.0007629394531250, -0.0003967285156250, 0.0010070800781250, +0.0002136230468750, 0.0009765625000000, 0.0001220703125000, 0.0013122558593750, +0.0003051757812500, 0.0012512207031250, 0.0007324218750000, 0.0011901855468750, +0.0004882812500000, 0.0017395019531250, 0.0008239746093750, 0.0010681152343750, +0.0008544921875000, 0.0014648437500000, 0.0007934570312500, 0.0013732910156250, +0.0009155273437500, 0.0008850097656250, 0.0007629394531250, 0.0014343261718750, +0.0005493164062500, 0.0007934570312500, 0.0005187988281250, 0.0009155273437500, +0.0002441406250000, 0.0009765625000000, -0.0000610351562500, 0.0006713867187500, +-0.0000915527343750, 0.0010070800781250, -0.0007324218750000, 0.0009155273437500, +-0.0007324218750000, 0.0009765625000000, -0.0010375976562500, 0.0011291503906250, +-0.0016174316406250, 0.0011596679687500, -0.0014038085937500, 0.0012207031250000, +-0.0018920898437500, 0.0015563964843750, -0.0020141601562500, 0.0015563964843750, +-0.0018310546875000, 0.0017089843750000, -0.0018615722656250, 0.0019836425781250, +-0.0019531250000000, 0.0018310546875000, -0.0014648437500000, 0.0021972656250000, +-0.0015563964843750, 0.0021362304687500, -0.0013732910156250, 0.0021667480468750, +-0.0009765625000000, 0.0023498535156250, -0.0010986328125000, 0.0021972656250000, +-0.0006103515625000, 0.0024719238281250, -0.0006408691406250, 0.0023498535156250, +-0.0004577636718750, 0.0023193359375000, 0.0000000000000000, 0.0024719238281250, +-0.0002746582031250, 0.0022277832031250, 0.0004577636718750, 0.0023498535156250, +0.0004272460937500, 0.0021667480468750, 0.0003967285156250, 0.0020141601562500, +0.0008850097656250, 0.0019836425781250, 0.0007934570312500, 0.0018310546875000, +0.0010681152343750, 0.0020141601562500, 0.0010986328125000, 0.0017700195312500, +0.0010070800781250, 0.0019531250000000, 0.0010070800781250, 0.0022583007812500, +0.0010070800781250, 0.0018310546875000, 0.0008850097656250, 0.0024719238281250, +0.0007629394531250, 0.0022888183593750, 0.0008544921875000, 0.0023498535156250, +0.0008850097656250, 0.0027465820312500, 0.0007629394531250, 0.0024414062500000, +0.0010681152343750, 0.0027465820312500, 0.0009460449218750, 0.0028381347656250, +0.0010681152343750, 0.0027160644531250, 0.0013427734375000, 0.0027465820312500, +0.0010986328125000, 0.0028686523437500, 0.0013427734375000, 0.0024414062500000, +0.0013427734375000, 0.0026245117187500, 0.0010375976562500, 0.0024108886718750, +0.0009765625000000, 0.0019531250000000, 0.0009460449218750, 0.0023193359375000, +0.0003967285156250, 0.0016479492187500, 0.0003356933593750, 0.0016784667968750, +0.0001831054687500, 0.0016784667968750, -0.0001525878906250, 0.0012512207031250, +0.0000915527343750, 0.0013427734375000, 0.0003662109375000, 0.0011596679687500, +0.0002136230468750, 0.0011291503906250, 0.0003356933593750, 0.0010070800781250, +0.0006103515625000, 0.0007934570312500, 0.0004577636718750, 0.0008544921875000, +0.0006713867187500, 0.0006713867187500, 0.0005798339843750, 0.0005493164062500, +0.0006408691406250, 0.0007019042968750, 0.0008544921875000, 0.0007934570312500, +0.0006713867187500, 0.0006408691406250, 0.0011596679687500, 0.0012207031250000, +0.0010375976562500, 0.0010681152343750, 0.0012207031250000, 0.0013427734375000, +0.0016174316406250, 0.0019226074218750, 0.0013732910156250, 0.0016174316406250, +0.0017395019531250, 0.0022583007812500, 0.0015563964843750, 0.0023498535156250, +0.0014343261718750, 0.0023193359375000, 0.0015869140625000, 0.0025634765625000, +0.0014038085937500, 0.0025939941406250, 0.0012817382812500, 0.0023193359375000, +0.0011291503906250, 0.0024108886718750, 0.0010070800781250, 0.0022277832031250, +0.0008544921875000, 0.0019226074218750, 0.0007324218750000, 0.0020446777343750, +0.0008544921875000, 0.0017395019531250, 0.0006408691406250, 0.0016479492187500, +0.0007324218750000, 0.0016174316406250, 0.0008239746093750, 0.0014343261718750, +0.0004882812500000, 0.0013732910156250, 0.0010986328125000, 0.0011901855468750, +0.0007629394531250, 0.0011291503906250, 0.0010375976562500, 0.0010070800781250, +0.0016784667968750, 0.0008850097656250, 0.0010375976562500, 0.0008850097656250, +0.0018615722656250, 0.0003967285156250, 0.0017089843750000, 0.0004272460937500, +0.0017089843750000, 0.0002136230468750, 0.0021057128906250, -0.0001831054687500, +0.0018005371093750}, +{0.0000915527343750, 0.0021667480468750, 0.0005187988281250, 0.0024414062500000, +0.0000610351562500, 0.0017700195312500, -0.0000915527343750, 0.0019531250000000, +0.0001525878906250, 0.0018310546875000, 0.0001220703125000, 0.0014038085937500, +0.0000915527343750, 0.0017395019531250, 0.0006103515625000, 0.0013732910156250, +0.0004272460937500, 0.0014648437500000, 0.0006408691406250, 0.0015258789062500, +0.0011291503906250, 0.0013122558593750, 0.0008239746093750, 0.0016174316406250, +0.0013427734375000, 0.0015258789062500, 0.0013122558593750, 0.0015869140625000, +0.0012512207031250, 0.0017700195312500, 0.0014953613281250, 0.0018920898437500, +0.0012817382812500, 0.0019836425781250, 0.0013427734375000, 0.0022583007812500, +0.0013427734375000, 0.0022583007812500, 0.0011291503906250, 0.0024414062500000, +0.0010681152343750, 0.0026550292968750, 0.0011596679687500, 0.0026245117187500, +0.0004882812500000, 0.0027160644531250, 0.0006408691406250, 0.0028686523437500, +0.0003356933593750, 0.0028076171875000, -0.0003356933593750, 0.0027160644531250, +-0.0000305175781250, 0.0028991699218750, -0.0006408691406250, 0.0024719238281250, +-0.0007934570312500, 0.0026245117187500, -0.0006408691406250, 0.0023803710937500, +-0.0007324218750000, 0.0019836425781250, -0.0007934570312500, 0.0022583007812500, +-0.0002136230468750, 0.0016174316406250, -0.0003356933593750, 0.0016479492187500, +-0.0001831054687500, 0.0015563964843750, 0.0003356933593750, 0.0011291503906250, +0.0000610351562500, 0.0013427734375000, 0.0003051757812500, 0.0010681152343750, +0.0003356933593750, 0.0010375976562500, 0.0003051757812500, 0.0009765625000000, +0.0003356933593750, 0.0007934570312500, 0.0003356933593750, 0.0008850097656250, +0.0001831054687500, 0.0008850097656250, 0.0001220703125000, 0.0008239746093750, +0.0002441406250000, 0.0008850097656250, 0.0002441406250000, 0.0009155273437500, +0.0001220703125000, 0.0008544921875000, 0.0003662109375000, 0.0012817382812500, +0.0004577636718750, 0.0011901855468750, 0.0003967285156250, 0.0013427734375000, +0.0004272460937500, 0.0017089843750000, 0.0004882812500000, 0.0015869140625000, +0.0004882812500000, 0.0018615722656250, 0.0003662109375000, 0.0020141601562500, +0.0006408691406250, 0.0018310546875000, 0.0009765625000000, 0.0018920898437500, +0.0007019042968750, 0.0021057128906250, 0.0014648437500000, 0.0014953613281250, +0.0013732910156250, 0.0016784667968750, 0.0016174316406250, 0.0014648437500000, +0.0021972656250000, 0.0009765625000000, 0.0018005371093750, 0.0013122558593750, +0.0024719238281250, 0.0007629394531250, 0.0024414062500000, 0.0007934570312500, +0.0023498535156250, 0.0007629394531250, 0.0027160644531250, 0.0005187988281250, +0.0026245117187500, 0.0007629394531250, 0.0024414062500000, 0.0005187988281250, +0.0025024414062500, 0.0006713867187500, 0.0022583007812500, 0.0006103515625000, +0.0019836425781250, 0.0003967285156250, 0.0021667480468750, 0.0005493164062500, +0.0015563964843750, 0.0001220703125000, 0.0015258789062500, 0.0001525878906250, +0.0015563964843750, 0.0000305175781250, 0.0012207031250000, -0.0003662109375000, +0.0013122558593750, -0.0001525878906250, 0.0015258789062500, -0.0005493164062500, +0.0014953613281250, -0.0005798339843750, 0.0014953613281250, -0.0006103515625000, +0.0016174316406250, -0.0007324218750000, 0.0016784667968750, -0.0007019042968750, +0.0015869140625000, -0.0005493164062500, 0.0016174316406250, -0.0007019042968750, +0.0015563964843750, -0.0005187988281250, 0.0014038085937500, -0.0002746582031250, +0.0013732910156250, -0.0004272460937500, 0.0011901855468750, 0.0000610351562500, +0.0011901855468750, -0.0000305175781250, 0.0009765625000000, 0.0000915527343750, +0.0007019042968750, 0.0005187988281250, 0.0007324218750000, 0.0003356933593750, +0.0003051757812500, 0.0005798339843750, 0.0003662109375000, 0.0006713867187500, +0.0001220703125000, 0.0006713867187500, -0.0002441406250000, 0.0007629394531250, +-0.0000305175781250, 0.0007934570312500, -0.0006408691406250, 0.0006408691406250, +-0.0005493164062500, 0.0007629394531250, -0.0006408691406250, 0.0007324218750000, +-0.0010070800781250, 0.0006408691406250, -0.0007019042968750, 0.0007019042968750, +-0.0009460449218750, 0.0004882812500000, -0.0008850097656250, 0.0005798339843750, +-0.0007934570312500, 0.0006103515625000, -0.0008544921875000, 0.0006408691406250, +-0.0007324218750000, 0.0007019042968750, -0.0005187988281250, 0.0008239746093750, +-0.0006103515625000, 0.0008239746093750, -0.0003051757812500, 0.0009460449218750, +0.0000610351562500, 0.0010986328125000, 0.0000000000000000, 0.0010986328125000, +0.0003356933593750, 0.0013427734375000, 0.0005798339843750, 0.0013427734375000, +0.0004882812500000, 0.0014343261718750, 0.0004882812500000, 0.0016479492187500, +0.0007019042968750, 0.0015563964843750, 0.0003967285156250, 0.0018005371093750, +0.0006103515625000, 0.0018615722656250, 0.0006103515625000, 0.0017395019531250, +0.0003967285156250, 0.0018310546875000, 0.0007629394531250, 0.0018920898437500, +0.0005187988281250, 0.0013732910156250, 0.0007019042968750, 0.0014343261718750, +0.0007934570312500, 0.0012512207031250, 0.0007324218750000, 0.0007934570312500, +0.0009460449218750, 0.0009765625000000, 0.0008239746093750, 0.0007324218750000, +0.0008850097656250, 0.0005187988281250, 0.0009155273437500, 0.0006713867187500, +0.0007934570312500, 0.0007019042968750, 0.0009460449218750, 0.0005493164062500, +0.0008239746093750, 0.0008544921875000, 0.0008239746093750, 0.0008544921875000, +0.0008850097656250, 0.0008239746093750, 0.0008544921875000, 0.0009155273437500, +0.0008544921875000, 0.0008239746093750, 0.0008850097656250, 0.0007324218750000, +0.0009155273437500, 0.0008544921875000, 0.0008239746093750, 0.0007019042968750, +0.0007629394531250, 0.0005187988281250, 0.0007629394531250, 0.0005798339843750, +0.0006713867187500, 0.0004272460937500, 0.0006408691406250, 0.0002441406250000, +0.0007019042968750, 0.0004577636718750, 0.0006713867187500, 0.0004577636718750, +0.0006408691406250, 0.0002441406250000, 0.0008850097656250, 0.0010375976562500, +0.0007324218750000, 0.0007019042968750, 0.0009155273437500, 0.0011901855468750, +0.0011291503906250, 0.0020446777343750, 0.0010375976562500, 0.0014343261718750, +0.0012817382812500, 0.0028686523437500, 0.0013732910156250, 0.0027465820312500, +0.0012512207031250, 0.0029907226562500, 0.0012207031250000, 0.0039062500000000, +0.0013732910156250, 0.0034484863281250, 0.0010986328125000, 0.0038452148437500, +0.0011901855468750, 0.0041198730468750, 0.0010986328125000, 0.0038452148437500, +0.0008544921875000, 0.0037231445312500, 0.0010986328125000, 0.0039367675781250, +0.0008850097656250, 0.0034790039062500, 0.0009460449218750, 0.0035705566406250, +0.0010070800781250, 0.0033874511718750, 0.0009765625000000, 0.0029907226562500, +0.0010986328125000, 0.0031433105468750, 0.0010681152343750, 0.0026245117187500, +0.0012207031250000, 0.0026245117187500, 0.0012817382812500, 0.0023803710937500, +0.0014038085937500, 0.0019226074218750, 0.0016174316406250, 0.0020751953125000, +0.0014648437500000, 0.0016174316406250, 0.0016174316406250, 0.0015258789062500, +0.0016784667968750, 0.0015563964843750, 0.0016479492187500, 0.0013427734375000, +0.0018005371093750, 0.0013122558593750, 0.0016174316406250, 0.0013732910156250, +0.0016784667968750, 0.0012512207031250, 0.0016479492187500, 0.0012817382812500, +0.0014343261718750, 0.0014953613281250, 0.0015563964843750, 0.0013122558593750, +0.0011901855468750, 0.0014648437500000, 0.0012817382812500, 0.0014648437500000, +0.0012207031250000, 0.0013427734375000, 0.0008544921875000, 0.0013122558593750, +0.0009155273437500, 0.0012512207031250, 0.0008544921875000, 0.0008850097656250, +0.0007629394531250, 0.0009460449218750, 0.0007934570312500, 0.0008850097656250, +0.0007934570312500, 0.0006408691406250, 0.0006408691406250, 0.0007324218750000, +0.0009155273437500, 0.0006103515625000, 0.0008544921875000, 0.0006103515625000, +0.0007934570312500, 0.0004577636718750, 0.0008850097656250, 0.0003662109375000, +0.0008239746093750, 0.0004577636718750, 0.0009155273437500, -0.0002136230468750, +0.0008850097656250, -0.0000305175781250, 0.0008850097656250, -0.0003051757812500, +0.0008850097656250, -0.0009155273437500, 0.0009155273437500, -0.0004882812500000, +0.0010070800781250, -0.0014038085937500, 0.0009765625000000, -0.0012512207031250, +0.0009460449218750, -0.0013427734375000, 0.0010375976562500, -0.0019531250000000, +0.0011596679687500, -0.0016784667968750, 0.0011901855468750, -0.0019226074218750, +0.0013122558593750, -0.0021362304687500, 0.0013427734375000, -0.0017395019531250, +0.0014038085937500, -0.0015869140625000, 0.0016479492187500, -0.0018920898437500, +0.0013732910156250, -0.0010070800781250, 0.0016479492187500, -0.0010681152343750, +0.0015563964843750, -0.0010375976562500, 0.0012817382812500, -0.0004882812500000, +0.0016479492187500, -0.0006103515625000, 0.0009765625000000, -0.0005187988281250, +0.0011901855468750, -0.0004577636718750, 0.0011291503906250, -0.0004577636718750, +0.0002746582031250, -0.0004577636718750, 0.0003051757812500, -0.0023193359375000, +-0.0004882812500000, -0.0019531250000000, -0.0000610351562500, -0.0023498535156250, +-0.0003967285156250, -0.0017700195312500, -0.0009155273437500, -0.0012207031250000, +-0.0005187988281250, -0.0015563964843750, -0.0010986328125000, -0.0006408691406250, +-0.0010375976562500, -0.0005493164062500, -0.0009460449218750, -0.0005493164062500, +-0.0011596679687500, 0.0000305175781250, -0.0009765625000000, -0.0000305175781250, +-0.0008850097656250, -0.0002136230468750, -0.0009460449218750, -0.0001220703125000, +-0.0007324218750000, 0.0000305175781250, -0.0006408691406250, 0.0000305175781250, +-0.0006713867187500, 0.0000000000000000, -0.0001525878906250, 0.0002136230468750, +-0.0002441406250000, 0.0002746582031250, -0.0000305175781250, 0.0001525878906250, +0.0004882812500000, 0.0001831054687500, 0.0003356933593750, 0.0002746582031250, +0.0007629394531250, 0.0003356933593750, 0.0009155273437500, 0.0001831054687500, +0.0008239746093750, 0.0002441406250000, 0.0009765625000000, 0.0003662109375000, +0.0011901855468750, 0.0003051757812500, 0.0008850097656250, 0.0007324218750000, +0.0010681152343750, 0.0004882812500000, 0.0009765625000000, 0.0007629394531250, +0.0007629394531250, 0.0012207031250000, 0.0010070800781250, 0.0008239746093750, +0.0004882812500000, 0.0017395019531250, 0.0006713867187500, 0.0015869140625000, +0.0005187988281250, 0.0016174316406250, 0.0000610351562500, 0.0022888183593750, +0.0004882812500000, 0.0020141601562500, -0.0001831054687500, 0.0020751953125000, +-0.0002136230468750, 0.0023803710937500, 0.0000000000000000, 0.0021362304687500, +-0.0002746582031250, 0.0019226074218750, -0.0001525878906250, 0.0023498535156250, +0.0005493164062500, 0.0020446777343750, 0.0002136230468750, 0.0019531250000000, +0.0007019042968750, 0.0020446777343750, 0.0015258789062500, 0.0019226074218750, +0.0009765625000000, 0.0020141601562500, 0.0020751953125000, 0.0021972656250000, +0.0021972656250000, 0.0020446777343750, 0.0019531250000000, 0.0019836425781250, +0.0024414062500000, 0.0022277832031250, 0.0024414062500000, 0.0022583007812500, +0.0016784667968750, 0.0018005371093750, 0.0020751953125000, 0.0018920898437500, +0.0017089843750000, 0.0018005371093750, 0.0008239746093750, 0.0013122558593750, +0.0014038085937500, 0.0014038085937500, 0.0007629394531250, 0.0014343261718750, +0.0005493164062500}, +{0.0002136230468750, 0.0002441406250000, 0.0003356933593750, 0.0002136230468750, +0.0005187988281250, 0.0002136230468750, 0.0004882812500000, 0.0005798339843750, +0.0007019042968750, 0.0004882812500000, 0.0007934570312500, 0.0003356933593750, +0.0009155273437500, 0.0006713867187500, 0.0009765625000000, 0.0002136230468750, +0.0010375976562500, -0.0002136230468750, 0.0011596679687500, 0.0002746582031250, +0.0011291503906250, -0.0010070800781250, 0.0012817382812500, -0.0007629394531250, +0.0011901855468750, -0.0010375976562500, 0.0010375976562500, -0.0020446777343750, +0.0011901855468750, -0.0015258789062500, 0.0008239746093750, -0.0021667480468750, +0.0009155273437500, -0.0023498535156250, 0.0008239746093750, -0.0022583007812500, +0.0006103515625000, -0.0023803710937500, 0.0007629394531250, -0.0024719238281250, +0.0004577636718750, -0.0023803710937500, 0.0005493164062500, -0.0024414062500000, +0.0004882812500000, -0.0024108886718750, -0.0000305175781250, -0.0023193359375000, +-0.0009155273437500, -0.0001831054687500, -0.0004882812500000, -0.0012817382812500, +-0.0008544921875000, -0.0008239746093750, -0.0004577636718750, -0.0013427734375000, +0.0000915527343750, -0.0022583007812500, -0.0002746582031250, -0.0018005371093750, +0.0003662109375000, -0.0020141601562500, 0.0004577636718750, -0.0024108886718750, +0.0004882812500000, -0.0016784667968750, 0.0008239746093750, -0.0011291503906250, +0.0007629394531250, -0.0017089843750000, 0.0008850097656250, -0.0000305175781250, +0.0010986328125000, -0.0000305175781250, 0.0010070800781250, 0.0000305175781250, +0.0010375976562500, 0.0009155273437500, 0.0012817382812500, 0.0006713867187500, +0.0008239746093750, 0.0010986328125000, 0.0011596679687500, 0.0010986328125000, +0.0008850097656250, 0.0010070800781250, 0.0003051757812500, 0.0011596679687500, +0.0008850097656250, 0.0011596679687500, -0.0000915527343750, 0.0008850097656250, +0.0000000000000000, 0.0009460449218750, 0.0000000000000000, 0.0009460449218750, +-0.0005187988281250, 0.0008239746093750, -0.0003051757812500, 0.0009155273437500, +-0.0004272460937500, 0.0007324218750000, -0.0004882812500000, 0.0008544921875000, +-0.0004882812500000, 0.0008544921875000, -0.0004882812500000, 0.0007324218750000, +-0.0004882812500000, 0.0008544921875000, -0.0004882812500000, 0.0009765625000000, +-0.0004577636718750, 0.0008544921875000, -0.0002136230468750, 0.0010375976562500, +-0.0001525878906250, 0.0012207031250000, -0.0001831054687500, 0.0010070800781250, +0.0007019042968750, 0.0016784667968750, 0.0004882812500000, 0.0014953613281250, +0.0010070800781250, 0.0017089843750000, 0.0019531250000000, 0.0021972656250000, +0.0014953613281250, 0.0018310546875000, 0.0023803710937500, 0.0021362304687500, +0.0026245117187500, 0.0022583007812500, 0.0023193359375000, 0.0021667480468750, +0.0025634765625000, 0.0021667480468750, 0.0027160644531250, 0.0020446777343750, +0.0017089843750000, 0.0016479492187500, 0.0020751953125000, 0.0017089843750000, +0.0016784667968750, 0.0016784667968750, 0.0007934570312500, 0.0014038085937500, +0.0013732910156250, 0.0013427734375000, 0.0008850097656250, 0.0017089843750000, +0.0006103515625000, 0.0016174316406250, 0.0010681152343750, 0.0018310546875000, +0.0012512207031250, 0.0022277832031250, 0.0010375976562500, 0.0021667480468750, +0.0019531250000000, 0.0023498535156250, 0.0019531250000000, 0.0025024414062500, +0.0021057128906250, 0.0025329589843750, 0.0026550292968750, 0.0025939941406250, +0.0025024414062500, 0.0025939941406250, 0.0028076171875000, 0.0026550292968750, +0.0028686523437500, 0.0024108886718750, 0.0028686523437500, 0.0025329589843750, +0.0030212402343750, 0.0026550292968750, 0.0030212402343750, 0.0023498535156250, +0.0031738281250000, 0.0032348632812500, 0.0031433105468750, 0.0028381347656250, +0.0032958984375000, 0.0029907226562500, 0.0034484863281250, 0.0037841796875000, +0.0034179687500000, 0.0033264160156250, 0.0037231445312500, 0.0036926269531250, +0.0037841796875000, 0.0038452148437500, 0.0036621093750000, 0.0035705566406250, +0.0038452148437500, 0.0035095214843750, 0.0039672851562500, 0.0036926269531250, +0.0033874511718750, 0.0031127929687500, 0.0036926269531250, 0.0032043457031250, +0.0034179687500000, 0.0031433105468750, 0.0028076171875000, 0.0028381347656250, +0.0031738281250000, 0.0031738281250000, 0.0024414062500000, 0.0029296875000000, +0.0025024414062500, 0.0029907226562500, 0.0022583007812500, 0.0031433105468750, +0.0016784667968750, 0.0031127929687500, 0.0019531250000000, 0.0031433105468750, +0.0014038085937500, 0.0033569335937500, 0.0012817382812500, 0.0032958984375000, +0.0014343261718750, 0.0034179687500000, 0.0012207031250000, 0.0035705566406250, +0.0009765625000000, 0.0034484863281250, 0.0014648437500000, 0.0036010742187500, +0.0012512207031250, 0.0035705566406250, 0.0012817382812500, 0.0035095214843750, +0.0016479492187500, 0.0034790039062500, 0.0013427734375000, 0.0034484863281250, +0.0013427734375000, 0.0031738281250000, 0.0014648437500000, 0.0032348632812500, +0.0011901855468750, 0.0030517578125000, 0.0009155273437500, 0.0028381347656250, +0.0011291503906250, 0.0029907226562500, 0.0005493164062500, 0.0025329589843750, +0.0006408691406250, 0.0025939941406250, 0.0006713867187500, 0.0024414062500000, +0.0003967285156250, 0.0020446777343750, 0.0006408691406250, 0.0022583007812500, +0.0006103515625000, 0.0018005371093750, 0.0006103515625000, 0.0018310546875000, +0.0007019042968750, 0.0018005371093750, 0.0007629394531250, 0.0015563964843750, +0.0008544921875000, 0.0017089843750000, 0.0006408691406250, 0.0015869140625000, +0.0007934570312500, 0.0016479492187500, 0.0006103515625000, 0.0016174316406250, +0.0003356933593750, 0.0015563964843750, 0.0004882812500000, 0.0016784667968750, +0.0001220703125000, 0.0015258789062500, 0.0000915527343750, 0.0016784667968750, +0.0001525878906250, 0.0017089843750000, 0.0000610351562500, 0.0015869140625000, +-0.0000305175781250, 0.0017700195312500, 0.0004272460937500, 0.0017395019531250, +0.0002136230468750, 0.0018920898437500, 0.0004577636718750, 0.0018615722656250, +0.0009460449218750, 0.0019226074218750, 0.0007629394531250, 0.0021667480468750, +0.0013122558593750, 0.0018310546875000, 0.0012817382812500, 0.0020751953125000, +0.0012817382812500, 0.0019531250000000, 0.0016174316406250, 0.0017089843750000, +0.0014343261718750, 0.0021667480468750, 0.0016174316406250, 0.0014648437500000, +0.0015563964843750, 0.0018005371093750, 0.0015563964843750, 0.0016479492187500, +0.0016174316406250, 0.0010986328125000, 0.0015258789062500, 0.0017089843750000, +0.0015563964843750, 0.0010986328125000, 0.0015258789062500, 0.0012817382812500, +0.0014343261718750, 0.0014953613281250, 0.0014343261718750, 0.0012207031250000, +0.0014038085937500, 0.0014953613281250, 0.0010986328125000, 0.0017089843750000, +0.0010681152343750, 0.0016479492187500, 0.0007934570312500, 0.0020141601562500, +0.0004272460937500, 0.0022888183593750, 0.0004577636718750, 0.0022277832031250, +-0.0003356933593750, 0.0029296875000000, -0.0003662109375000, 0.0027465820312500, +-0.0006103515625000, 0.0030517578125000, -0.0012207031250000, 0.0036010742187500, +-0.0011596679687500, 0.0032348632812500, -0.0014648437500000, 0.0037536621093750, +-0.0016784667968750, 0.0036926269531250, -0.0014343261718750, 0.0036315917968750, +-0.0013122558593750, 0.0038146972656250, -0.0014953613281250, 0.0035400390625000, +-0.0007324218750000, 0.0033264160156250, -0.0008239746093750, 0.0034179687500000, +-0.0006408691406250, 0.0029296875000000, -0.0000915527343750, 0.0025634765625000, +-0.0003051757812500, 0.0027160644531250, 0.0002136230468750, 0.0017395019531250, +0.0003051757812500, 0.0018005371093750, 0.0004272460937500, 0.0016479492187500, +0.0007934570312500, 0.0010070800781250, 0.0006713867187500, 0.0011901855468750, +0.0010070800781250, 0.0008239746093750, 0.0011596679687500, 0.0008239746093750, +0.0010681152343750, 0.0008544921875000, 0.0011596679687500, 0.0007324218750000, +0.0013122558593750, 0.0008239746093750, 0.0010986328125000, 0.0008850097656250, +0.0012207031250000, 0.0009155273437500, 0.0012207031250000, 0.0009765625000000, +0.0010986328125000, 0.0010986328125000, 0.0011901855468750, 0.0010986328125000, +0.0012207031250000, 0.0012512207031250, 0.0011901855468750, 0.0013427734375000, +0.0012512207031250, 0.0013427734375000, 0.0013122558593750, 0.0014343261718750, +0.0010986328125000, 0.0016174316406250, 0.0009460449218750, 0.0014648437500000, +0.0010070800781250, 0.0014953613281250, 0.0009765625000000, 0.0014038085937500, +0.0007629394531250, 0.0012207031250000, 0.0007934570312500, 0.0011901855468750, +0.0009155273437500, 0.0008239746093750, 0.0008239746093750, 0.0007934570312500, +0.0008850097656250, 0.0006408691406250, 0.0010681152343750, 0.0004272460937500, +0.0009460449218750, 0.0003967285156250, 0.0006408691406250, 0.0002746582031250, +0.0008850097656250, 0.0001220703125000, 0.0004577636718750, 0.0002441406250000, +-0.0000915527343750, 0.0002136230468750, 0.0003051757812500, 0.0001220703125000, +-0.0004882812500000, 0.0003356933593750, -0.0005493164062500, 0.0003662109375000, +-0.0003051757812500, 0.0003967285156250, -0.0005798339843750, 0.0005187988281250, +-0.0005493164062500, 0.0004882812500000, 0.0000610351562500, 0.0005798339843750, +-0.0002746582031250, 0.0005493164062500, 0.0002136230468750, 0.0005187988281250, +0.0008850097656250, 0.0005187988281250, 0.0002136230468750, 0.0005187988281250, +0.0017089843750000, 0.0006408691406250, 0.0012817382812500, 0.0006408691406250, +0.0016174316406250, 0.0007019042968750, 0.0026855468750000, 0.0007934570312500, +0.0018615722656250, 0.0007629394531250, 0.0029296875000000, 0.0009460449218750, +0.0028991699218750, 0.0009155273437500, 0.0026245117187500, 0.0010375976562500, +0.0030212402343750, 0.0012207031250000, 0.0028686523437500, 0.0011596679687500, +0.0025329589843750, 0.0013122558593750, 0.0026855468750000, 0.0013427734375000, +0.0025024414062500, 0.0012512207031250, 0.0021972656250000, 0.0012512207031250, +0.0024719238281250, 0.0012817382812500, 0.0020751953125000, 0.0010375976562500, +0.0023803710937500, 0.0010681152343750, 0.0024108886718750, 0.0009765625000000, +0.0021972656250000, 0.0007934570312500, 0.0025939941406250, 0.0009155273437500, +0.0025634765625000, 0.0005798339843750, 0.0026855468750000, 0.0005493164062500, +0.0029296875000000, 0.0006103515625000, 0.0030822753906250, 0.0004882812500000, +0.0032348632812500, 0.0004882812500000, 0.0034179687500000, 0.0006408691406250, +0.0035705566406250, 0.0005187988281250, 0.0036926269531250, 0.0007019042968750, +0.0038146972656250, 0.0010070800781250, 0.0039978027343750, 0.0008544921875000, +0.0039978027343750, 0.0011291503906250, 0.0039978027343750, 0.0012207031250000, +0.0040283203125000, 0.0012207031250000, 0.0041198730468750, 0.0013732910156250, +0.0039978027343750, 0.0013427734375000, 0.0041809082031250, 0.0014648437500000, +0.0041503906250000, 0.0015258789062500, 0.0040588378906250, 0.0014953613281250, +0.0042114257812500, 0.0014648437500000, 0.0041198730468750, 0.0014648437500000, +0.0040588378906250, 0.0012817382812500, 0.0041198730468750, 0.0013732910156250, +0.0037536621093750, 0.0011901855468750, 0.0035095214843750, 0.0009155273437500, +0.0037536621093750, 0.0010375976562500, 0.0030517578125000, 0.0006103515625000, +0.0031127929687500, 0.0006103515625000, 0.0030822753906250, 0.0005187988281250, +0.0026550292968750}, +{-0.0005798339843750, 0.0014953613281250, -0.0006713867187500, 0.0013122558593750, +-0.0007019042968750, 0.0014953613281250, -0.0001831054687500, 0.0007934570312500, +-0.0002746582031250, 0.0009765625000000, 0.0000610351562500, 0.0007629394531250, +0.0006713867187500, 0.0001525878906250, 0.0006408691406250, 0.0004272460937500, +0.0010986328125000, -0.0001220703125000, 0.0010070800781250, 0.0000305175781250, +0.0007934570312500, 0.0000915527343750, 0.0009155273437500, -0.0002746582031250, +0.0007629394531250, 0.0000000000000000, 0.0006408691406250, -0.0001220703125000, +0.0004577636718750, -0.0001831054687500, 0.0004882812500000, 0.0000000000000000, +0.0005187988281250, 0.0000610351562500, 0.0002746582031250, -0.0000610351562500, +0.0007629394531250, 0.0003356933593750, 0.0005798339843750, 0.0001525878906250, +0.0007019042968750, 0.0003662109375000, 0.0011291503906250, 0.0007019042968750, +0.0008239746093750, 0.0003967285156250, 0.0012817382812500, 0.0009765625000000, +0.0012512207031250, 0.0008544921875000, 0.0012207031250000, 0.0009460449218750, +0.0013427734375000, 0.0013732910156250, 0.0011291503906250, 0.0010375976562500, +0.0015258789062500, 0.0015869140625000, 0.0013427734375000, 0.0014648437500000, +0.0014343261718750, 0.0014953613281250, 0.0017700195312500, 0.0018615722656250, +0.0014648437500000, 0.0015869140625000, 0.0020751953125000, 0.0018615722656250, +0.0020141601562500, 0.0018005371093750, 0.0021057128906250, 0.0018920898437500, +0.0025634765625000, 0.0020141601562500, 0.0025329589843750, 0.0018310546875000, +0.0028991699218750, 0.0019531250000000, 0.0029907226562500, 0.0020141601562500, +0.0031738281250000, 0.0019226074218750, 0.0035400390625000, 0.0018615722656250, +0.0035705566406250, 0.0018310546875000, 0.0038146972656250, 0.0017089843750000, +0.0041503906250000, 0.0017089843750000, 0.0040283203125000, 0.0015869140625000, +0.0039367675781250, 0.0014953613281250, 0.0042724609375000, 0.0014953613281250, +0.0037231445312500, 0.0013732910156250, 0.0038757324218750, 0.0014343261718750, +0.0037231445312500, 0.0014343261718750, 0.0032043457031250, 0.0013122558593750, +0.0034790039062500, 0.0014343261718750, 0.0029907226562500, 0.0014343261718750, +0.0028076171875000, 0.0014038085937500, 0.0029296875000000, 0.0015258789062500, +0.0028076171875000, 0.0016174316406250, 0.0025634765625000, 0.0015869140625000, +0.0032653808593750, 0.0017700195312500, 0.0029296875000000, 0.0017089843750000, +0.0030517578125000, 0.0017395019531250, 0.0036010742187500, 0.0018310546875000, +0.0031433105468750, 0.0017700195312500, 0.0034790039062500, 0.0019226074218750, +0.0035095214843750, 0.0018920898437500, 0.0033874511718750, 0.0019226074218750, +0.0034790039062500, 0.0020751953125000, 0.0035400390625000, 0.0019836425781250, +0.0031738281250000, 0.0018920898437500, 0.0033264160156250, 0.0020446777343750, +0.0032348632812500, 0.0018310546875000, 0.0031127929687500, 0.0015563964843750, +0.0033874511718750, 0.0018005371093750, 0.0029602050781250, 0.0010681152343750, +0.0031738281250000, 0.0011291503906250, 0.0032043457031250, 0.0010375976562500, +0.0029907226562500, 0.0005493164062500, 0.0033264160156250, 0.0006713867187500, +0.0028076171875000, 0.0004882812500000, 0.0031433105468750, 0.0003356933593750, +0.0029296875000000, 0.0004272460937500, 0.0025634765625000, 0.0004272460937500, +0.0030517578125000, 0.0002746582031250, 0.0023193359375000, 0.0006408691406250, +0.0024719238281250, 0.0005798339843750, 0.0026550292968750, 0.0006408691406250, +0.0022583007812500, 0.0010070800781250, 0.0025329589843750, 0.0007629394531250, +0.0026245117187500, 0.0012207031250000, 0.0026550292968750, 0.0011291503906250, +0.0028076171875000, 0.0014038085937500, 0.0029907226562500, 0.0018005371093750, +0.0030517578125000, 0.0015563964843750, 0.0029907226562500, 0.0022888183593750, +0.0031127929687500, 0.0023193359375000, 0.0031433105468750, 0.0024414062500000, +0.0030517578125000, 0.0029296875000000, 0.0031127929687500, 0.0027770996093750, +0.0029602050781250, 0.0029907226562500, 0.0029602050781250, 0.0031433105468750, +0.0029907226562500, 0.0029907226562500, 0.0028991699218750, 0.0028686523437500, +0.0028686523437500, 0.0029296875000000, 0.0030212402343750, 0.0024414062500000, +0.0029602050781250, 0.0025024414062500, 0.0030212402343750, 0.0023498535156250, +0.0031433105468750, 0.0019531250000000, 0.0030212402343750, 0.0021362304687500, +0.0032348632812500, 0.0017089843750000, 0.0031127929687500, 0.0016784667968750, +0.0031127929687500, 0.0015869140625000, 0.0032348632812500, 0.0012817382812500, +0.0031433105468750, 0.0012817382812500, 0.0030822753906250, 0.0013732910156250, +0.0030212402343750, 0.0011291503906250, 0.0028991699218750, 0.0014648437500000, +0.0028686523437500, 0.0018005371093750, 0.0027465820312500, 0.0014038085937500, +0.0028076171875000, 0.0023498535156250, 0.0027160644531250, 0.0022583007812500, +0.0027770996093750, 0.0024414062500000, 0.0028991699218750, 0.0030822753906250, +0.0027465820312500, 0.0027465820312500, 0.0028991699218750, 0.0030517578125000, +0.0029296875000000, 0.0032348632812500, 0.0028991699218750, 0.0029602050781250, +0.0029602050781250, 0.0028076171875000, 0.0029602050781250, 0.0029907226562500, +0.0028991699218750, 0.0021362304687500, 0.0030212402343750, 0.0022888183593750, +0.0028991699218750, 0.0021972656250000, 0.0027160644531250, 0.0015869140625000, +0.0028381347656250, 0.0017700195312500, 0.0023498535156250, 0.0018615722656250, +0.0024719238281250, 0.0015563964843750, 0.0022888183593750, 0.0019836425781250, +0.0019226074218750, 0.0024719238281250, 0.0020751953125000, 0.0021362304687500, +0.0016479492187500, 0.0031127929687500, 0.0016174316406250, 0.0030517578125000, +0.0015258789062500, 0.0031433105468750, 0.0013122558593750, 0.0037841796875000, +0.0013732910156250, 0.0035400390625000, 0.0009460449218750, 0.0036926269531250, +0.0010375976562500, 0.0037536621093750, 0.0008544921875000, 0.0036010742187500, +0.0004882812500000, 0.0035400390625000, 0.0007934570312500, 0.0036010742187500, +0.0003356933593750, 0.0031127929687500, 0.0004272460937500, 0.0032348632812500, +0.0005187988281250, 0.0030822753906250, 0.0003051757812500, 0.0026550292968750, +0.0003967285156250, 0.0028076171875000, 0.0006408691406250, 0.0025329589843750, +0.0005187988281250, 0.0024414062500000, 0.0007019042968750, 0.0024414062500000, +0.0009155273437500, 0.0023498535156250, 0.0007934570312500, 0.0023803710937500, +0.0012207031250000, 0.0021362304687500, 0.0012207031250000, 0.0022277832031250, +0.0011291503906250, 0.0019531250000000, 0.0013122558593750, 0.0016174316406250, +0.0012512207031250, 0.0017700195312500, 0.0013122558593750, 0.0008850097656250, +0.0012817382812500, 0.0010070800781250, 0.0012207031250000, 0.0007019042968750, +0.0011596679687500, -0.0000305175781250, 0.0010681152343750, 0.0002136230468750, +0.0010375976562500, -0.0003967285156250, 0.0009460449218750, -0.0004882812500000, +0.0008850097656250, -0.0003967285156250, 0.0008850097656250, -0.0005493164062500, +0.0008850097656250, -0.0005493164062500, 0.0006408691406250, -0.0005493164062500, +0.0007934570312500, -0.0005187988281250, 0.0004577636718750, -0.0005798339843750, +0.0000610351562500, -0.0006103515625000, 0.0003051757812500, -0.0005493164062500, +-0.0006713867187500, -0.0006103515625000, -0.0005493164062500, -0.0007019042968750, +-0.0006713867187500, -0.0003662109375000, -0.0013427734375000, -0.0002441406250000, +-0.0010070800781250, -0.0004882812500000, -0.0009155273437500, 0.0004577636718750, +-0.0012207031250000, 0.0002441406250000, -0.0008544921875000, 0.0003967285156250, +0.0000000000000000, 0.0016174316406250, 0.0010986328125000, -0.0011596679687500, +0.0012512207031250, -0.0012817382812500, 0.0014343261718750, -0.0015869140625000, +0.0012817382812500, -0.0010681152343750, 0.0011596679687500, -0.0007019042968750, +0.0013122558593750, -0.0010375976562500, 0.0010375976562500, -0.0000610351562500, +0.0010375976562500, -0.0001525878906250, 0.0010070800781250, -0.0000305175781250, +0.0008239746093750, 0.0007019042968750, 0.0008544921875000, 0.0004882812500000, +0.0009765625000000, 0.0005187988281250, 0.0008239746093750, 0.0007934570312500, +0.0008850097656250, 0.0007019042968750, 0.0010070800781250, 0.0005493164062500, +0.0008850097656250, 0.0007019042968750, 0.0008239746093750, 0.0003662109375000, +0.0008544921875000, 0.0004577636718750, 0.0007019042968750, 0.0003356933593750, +0.0006408691406250, -0.0000305175781250, 0.0006103515625000, 0.0001525878906250, +0.0005493164062500, 0.0001831054687500, 0.0003967285156250, 0.0000000000000000, +0.0006713867187500, 0.0000305175781250, 0.0008544921875000, -0.0000305175781250, +0.0006103515625000, -0.0000610351562500, 0.0015869140625000, 0.0003356933593750, +0.0013122558593750, 0.0000000000000000, 0.0015258789062500, 0.0002746582031250, +0.0022583007812500, 0.0009155273437500, 0.0017395019531250, 0.0005187988281250, +0.0021362304687500, 0.0012512207031250, 0.0021362304687500, 0.0013122558593750, +0.0018005371093750, 0.0014038085937500, 0.0017700195312500, 0.0017700195312500, +0.0017395019531250, 0.0015869140625000, 0.0014648437500000, 0.0017395019531250, +0.0013427734375000, 0.0019531250000000, 0.0014648437500000, 0.0019531250000000, +0.0014038085937500, 0.0019836425781250, 0.0012817382812500, 0.0020141601562500, +0.0018310546875000, 0.0018615722656250, 0.0016479492187500, 0.0019836425781250, +0.0018310546875000, 0.0019226074218750, 0.0023803710937500, 0.0017089843750000, +0.0021057128906250, 0.0019226074218750, 0.0023498535156250, 0.0021972656250000, +0.0025329589843750, 0.0019531250000000, 0.0022583007812500, 0.0023498535156250, +0.0021362304687500, 0.0029907226562500, 0.0023498535156250, 0.0026245117187500, +0.0017700195312500, 0.0030212402343750, 0.0018615722656250, 0.0031433105468750, +0.0019531250000000, 0.0028381347656250, 0.0016479492187500, 0.0028991699218750, +0.0016784667968750, 0.0030212402343750, 0.0023498535156250, 0.0022583007812500, +0.0020751953125000, 0.0024719238281250, 0.0024108886718750, 0.0023193359375000, +0.0031433105468750, 0.0017395019531250, 0.0028076171875000, 0.0022888183593750, +0.0032348632812500, 0.0020141601562500, 0.0035400390625000, 0.0019226074218750, +0.0032043457031250, 0.0021972656250000, 0.0031127929687500, 0.0022583007812500, +0.0035400390625000, 0.0022277832031250, 0.0022583007812500, 0.0024414062500000, +0.0026245117187500, 0.0023193359375000, 0.0021667480468750, 0.0023803710937500, +0.0010375976562500, 0.0025634765625000, 0.0017395019531250, 0.0024108886718750, +0.0006713867187500, 0.0025634765625000, 0.0006408691406250, 0.0024719238281250, +0.0008239746093750, 0.0025329589843750, 0.0004272460937500, 0.0026855468750000, +0.0006103515625000, 0.0025329589843750, 0.0008239746093750, 0.0028991699218750, +0.0007934570312500, 0.0028076171875000, 0.0009460449218750, 0.0028991699218750, +0.0011596679687500, 0.0031738281250000, 0.0010986328125000, 0.0029907226562500, +0.0013427734375000, 0.0032958984375000, 0.0013122558593750, 0.0032043457031250, +0.0014038085937500, 0.0031433105468750, 0.0015869140625000, 0.0032653808593750, +0.0014953613281250, 0.0031738281250000, 0.0015563964843750, 0.0031433105468750, +0.0015869140625000, 0.0031433105468750, 0.0015258789062500, 0.0030212402343750, +0.0014648437500000, 0.0029602050781250, 0.0014343261718750, 0.0028381347656250, +0.0016479492187500}, +{0.0010986328125000, -0.0009460449218750, 0.0009765625000000, 0.0002136230468750, +0.0011596679687500, -0.0003356933593750, 0.0009155273437500, 0.0002441406250000, +0.0006103515625000, 0.0014648437500000, 0.0008544921875000, 0.0006713867187500, +0.0007019042968750, 0.0021667480468750, 0.0004577636718750, 0.0022277832031250, +0.0009155273437500, 0.0019226074218750, 0.0012207031250000, 0.0025329589843750, +0.0008239746093750, 0.0025634765625000, 0.0022277832031250, 0.0017700195312500, +0.0019836425781250, 0.0020446777343750, 0.0021972656250000, 0.0016174316406250, +0.0031738281250000, 0.0008544921875000, 0.0026245117187500, 0.0012207031250000, +0.0027465820312500, 0.0001831054687500, 0.0029296875000000, 0.0001220703125000, +0.0025329589843750, 0.0002136230468750, 0.0021057128906250, -0.0002746582031250, +0.0023498535156250, -0.0002441406250000, 0.0016784667968750, 0.0003967285156250, +0.0014038085937500, 0.0001525878906250, 0.0014953613281250, 0.0005187988281250, +0.0013732910156250, 0.0011901855468750, 0.0011291503906250, 0.0008850097656250, +0.0013427734375000, 0.0018920898437500, 0.0012207031250000, 0.0020446777343750, +0.0011596679687500, 0.0019531250000000, 0.0013427734375000, 0.0023193359375000, +0.0011901855468750, 0.0022583007812500, 0.0008850097656250, 0.0019226074218750, +0.0009460449218750, 0.0020446777343750, 0.0007324218750000, 0.0018615722656250, +0.0003967285156250, 0.0014343261718750, 0.0005798339843750, 0.0014953613281250, +0.0004272460937500, 0.0010375976562500, 0.0001525878906250, 0.0010070800781250, +0.0005493164062500, 0.0011901855468750, 0.0007019042968750, 0.0010375976562500, +0.0003967285156250, 0.0010070800781250, 0.0015563964843750, 0.0013122558593750, +0.0012512207031250, 0.0012817382812500, 0.0014648437500000, 0.0014343261718750, +0.0024414062500000, 0.0018615722656250, 0.0019226074218750, 0.0017395019531250, +0.0021667480468750, 0.0019226074218750, 0.0025634765625000, 0.0021057128906250, +0.0018615722656250, 0.0020141601562500, 0.0014648437500000, 0.0019531250000000, +0.0019531250000000, 0.0022583007812500, 0.0002441406250000, 0.0018310546875000, +0.0006103515625000, 0.0019226074218750, 0.0002136230468750, 0.0020446777343750, +-0.0010986328125000, 0.0018310546875000, -0.0003356933593750, 0.0018310546875000, +-0.0010681152343750, 0.0021667480468750, -0.0013427734375000, 0.0017700195312500, +-0.0008544921875000, 0.0018920898437500, -0.0008239746093750, 0.0022277832031250, +-0.0009765625000000, 0.0017089843750000, 0.0000610351562500, 0.0023193359375000, +-0.0000610351562500, 0.0020141601562500, 0.0001831054687500, 0.0018615722656250, +0.0010375976562500, 0.0021972656250000, 0.0007934570312500, 0.0018615722656250, +0.0012817382812500, 0.0018920898437500, 0.0014648437500000, 0.0018005371093750, +0.0014953613281250, 0.0017089843750000, 0.0017089843750000, 0.0017089843750000, +0.0018005371093750, 0.0016784667968750, 0.0018310546875000, 0.0016479492187500, +0.0019226074218750, 0.0016174316406250, 0.0019531250000000, 0.0016479492187500, +0.0019531250000000, 0.0016784667968750, 0.0019836425781250, 0.0016174316406250, +0.0021057128906250, 0.0018005371093750, 0.0020446777343750, 0.0017089843750000, +0.0021667480468750, 0.0018310546875000, 0.0023498535156250, 0.0019836425781250, +0.0021057128906250, 0.0018310546875000, 0.0024719238281250, 0.0023193359375000, +0.0024414062500000, 0.0021667480468750, 0.0023803710937500, 0.0021972656250000, +0.0025634765625000, 0.0025329589843750, 0.0024719238281250, 0.0022583007812500, +0.0022888183593750, 0.0025329589843750, 0.0022888183593750, 0.0025024414062500, +0.0021362304687500, 0.0024719238281250, 0.0018920898437500, 0.0027160644531250, +0.0018920898437500, 0.0025634765625000, 0.0018615722656250, 0.0027465820312500, +0.0017395019531250, 0.0028991699218750, 0.0018310546875000, 0.0028686523437500, +0.0019226074218750, 0.0029602050781250, 0.0018615722656250, 0.0030822753906250, +0.0021667480468750, 0.0028991699218750, 0.0021667480468750, 0.0030517578125000, +0.0021362304687500, 0.0029907226562500, 0.0022888183593750, 0.0028686523437500, +0.0022888183593750, 0.0029907226562500, 0.0019531250000000, 0.0026855468750000, +0.0020446777343750, 0.0027465820312500, 0.0018005371093750, 0.0026550292968750, +0.0014038085937500, 0.0023803710937500, 0.0015869140625000, 0.0025329589843750, +0.0008850097656250, 0.0022888183593750, 0.0009155273437500, 0.0022888183593750, +0.0008850097656250, 0.0022277832031250, 0.0004272460937500, 0.0020141601562500, +0.0006408691406250, 0.0021667480468750, 0.0007324218750000, 0.0019226074218750, +0.0005798339843750, 0.0020751953125000, 0.0009155273437500, 0.0020141601562500, +0.0012207031250000, 0.0018920898437500, 0.0009765625000000, 0.0021057128906250, +0.0017089843750000, 0.0019226074218750, 0.0016479492187500, 0.0019226074218750, +0.0015869140625000, 0.0020446777343750, 0.0019836425781250, 0.0020751953125000, +0.0018310546875000, 0.0021972656250000, 0.0015869140625000, 0.0022888183593750, +0.0017089843750000, 0.0023498535156250, 0.0013427734375000, 0.0023498535156250, +0.0010070800781250, 0.0024719238281250, 0.0012512207031250, 0.0025024414062500, +0.0007324218750000, 0.0023803710937500, 0.0006713867187500, 0.0025024414062500, +0.0006713867187500, 0.0024108886718750, 0.0004272460937500, 0.0022277832031250, +0.0005798339843750, 0.0023498535156250, 0.0004882812500000, 0.0020141601562500, +0.0005493164062500, 0.0021057128906250, 0.0005493164062500, 0.0019226074218750, +0.0005493164062500, 0.0015869140625000, 0.0007019042968750, 0.0018005371093750, +0.0006103515625000, 0.0013427734375000, 0.0007324218750000, 0.0013122558593750, +0.0008239746093750, 0.0013427734375000, 0.0007934570312500, 0.0011291503906250, +0.0009155273437500, 0.0010986328125000, 0.0010681152343750, 0.0012207031250000, +0.0011291503906250, 0.0009765625000000, 0.0011596679687500, 0.0011596679687500, +0.0012207031250000, 0.0014343261718750, 0.0014038085937500, 0.0010375976562500, +0.0013427734375000, 0.0014343261718750, 0.0014343261718750, 0.0013122558593750, +0.0014648437500000, 0.0011291503906250, 0.0014953613281250, 0.0012817382812500, +0.0015869140625000, 0.0011596679687500, 0.0014648437500000, 0.0010681152343750, +0.0015869140625000, 0.0011596679687500, 0.0017395019531250, 0.0009765625000000, +0.0016784667968750, 0.0008239746093750, 0.0018615722656250, 0.0009765625000000, +0.0021057128906250, 0.0004577636718750, 0.0020751953125000, 0.0006103515625000, +0.0025939941406250, 0.0004272460937500, 0.0030822753906250, -0.0000305175781250, +0.0028381347656250, 0.0002746582031250, 0.0042114257812500, -0.0001220703125000, +0.0040588378906250, -0.0002136230468750, 0.0043334960937500, -0.0000610351562500, +0.0053100585937500, -0.0002136230468750, 0.0049133300781250, -0.0002136230468750, +0.0049438476562500, 0.0001525878906250, 0.0051269531250000, 0.0000000000000000, +0.0046081542968750, 0.0001831054687500, 0.0039367675781250, 0.0005187988281250, +0.0035095214843750, 0.0002136230468750, 0.0025634765625000, 0.0010986328125000, +0.0027770996093750, 0.0007019042968750, 0.0025024414062500, 0.0007019042968750, +0.0017700195312500, 0.0013732910156250, 0.0020446777343750, 0.0008239746093750, +0.0011901855468750, 0.0014953613281250, 0.0011596679687500, 0.0013427734375000, +0.0011901855468750, 0.0013732910156250, 0.0007934570312500, 0.0017395019531250, +0.0009460449218750, 0.0013732910156250, 0.0013732910156250, 0.0017089843750000, +0.0011901855468750, 0.0015563964843750, 0.0016174316406250, 0.0014648437500000, +0.0023803710937500, 0.0016479492187500, 0.0021362304687500, 0.0014343261718750, +0.0025939941406250, 0.0015563964843750, 0.0029296875000000, 0.0014953613281250, +0.0028381347656250, 0.0015258789062500, 0.0028686523437500, 0.0015563964843750, +0.0030212402343750, 0.0014953613281250, 0.0024719238281250, 0.0016174316406250, +0.0026855468750000, 0.0016479492187500, 0.0025329589843750, 0.0014953613281250, +0.0019836425781250, 0.0014953613281250, 0.0022888183593750, 0.0015258789062500, +0.0017700195312500, 0.0013732910156250, 0.0017700195312500, 0.0013732910156250, +0.0017395019531250, 0.0013122558593750, 0.0014343261718750, 0.0011291503906250, +0.0014038085937500, 0.0011596679687500, 0.0011596679687500, 0.0010986328125000, +0.0011901855468750, 0.0010070800781250, 0.0010375976562500, 0.0010375976562500, +0.0007019042968750, 0.0010375976562500, 0.0007629394531250, 0.0009765625000000, +0.0006103515625000, 0.0009155273437500, 0.0005798339843750, 0.0008850097656250, +0.0006408691406250, 0.0007629394531250, 0.0006713867187500, 0.0006408691406250, +0.0007629394531250, 0.0006103515625000, 0.0009765625000000, 0.0006713867187500, +0.0009460449218750, 0.0005187988281250, 0.0013427734375000, 0.0006408691406250, +0.0017395019531250, 0.0007324218750000, 0.0015869140625000, 0.0004882812500000, +0.0024108886718750, 0.0010375976562500, 0.0024414062500000, 0.0008239746093750, +0.0025329589843750, 0.0009765625000000, 0.0030517578125000, 0.0014648437500000, +0.0029296875000000, 0.0010986328125000, 0.0029296875000000, 0.0015258789062500, +0.0029907226562500, 0.0015563964843750, 0.0027160644531250, 0.0013122558593750, +0.0024719238281250, 0.0014343261718750, 0.0025634765625000, 0.0013732910156250, +0.0019226074218750, 0.0006713867187500, 0.0018310546875000, 0.0007629394531250, +0.0016174316406250, 0.0005187988281250, 0.0011596679687500, -0.0000610351562500, +0.0011596679687500, 0.0001525878906250, 0.0010681152343750, 0.0000305175781250, +0.0007934570312500, -0.0002441406250000, 0.0008850097656250, 0.0001525878906250, +0.0010070800781250, 0.0003662109375000, 0.0007629394531250, 0.0000915527343750, +0.0011901855468750, 0.0010375976562500, 0.0010070800781250, 0.0008544921875000, +0.0011291503906250, 0.0012207031250000, 0.0015258789062500, 0.0019531250000000, +0.0012207031250000, 0.0014953613281250, 0.0017700195312500, 0.0025634765625000, +0.0017700195312500, 0.0024108886718750, 0.0018310546875000, 0.0025329589843750, +0.0021972656250000, 0.0032348632812500, 0.0020751953125000, 0.0028991699218750, +0.0022888183593750, 0.0033264160156250, 0.0023803710937500, 0.0034179687500000, +0.0023193359375000, 0.0032958984375000, 0.0024414062500000, 0.0033874511718750, +0.0025024414062500, 0.0033874511718750, 0.0022888183593750, 0.0029296875000000, +0.0024719238281250, 0.0031127929687500, 0.0024108886718750, 0.0028381347656250, +0.0021972656250000, 0.0023193359375000, 0.0024414062500000, 0.0025329589843750, +0.0021667480468750, 0.0018920898437500, 0.0022888183593750, 0.0017700195312500, +0.0022888183593750, 0.0017700195312500, 0.0020141601562500, 0.0014953613281250, +0.0022888183593750, 0.0014648437500000, 0.0019836425781250, 0.0014343261718750, +0.0019836425781250, 0.0014038085937500, 0.0021057128906250, 0.0014343261718750, +0.0019836425781250, 0.0014648437500000, 0.0020446777343750, 0.0014038085937500, +0.0021667480468750, 0.0015258789062500, 0.0021057128906250, 0.0015563964843750, +0.0021667480468750, 0.0015563964843750, 0.0023193359375000, 0.0014953613281250, +0.0022583007812500, 0.0015258789062500, 0.0023193359375000, 0.0015563964843750, +0.0024414062500000, 0.0015258789062500, 0.0023498535156250, 0.0017700195312500, +0.0023498535156250, 0.0019531250000000, 0.0024414062500000, 0.0018005371093750, +0.0024108886718750, 0.0022277832031250, 0.0023803710937500, 0.0022583007812500, +0.0024414062500000}, +{0.0024414062500000, 0.0005798339843750, 0.0024108886718750, 0.0006408691406250, +0.0025634765625000, 0.0007629394531250, 0.0024414062500000, 0.0005798339843750, +0.0024414062500000, 0.0007019042968750, 0.0025939941406250, 0.0007324218750000, +0.0023803710937500, 0.0006103515625000, 0.0023498535156250, 0.0006103515625000, +0.0025939941406250, 0.0005798339843750, 0.0021667480468750, 0.0006103515625000, +0.0023193359375000, 0.0004882812500000, 0.0022583007812500, 0.0006408691406250, +0.0020141601562500, 0.0008544921875000, 0.0022583007812500, 0.0006408691406250, +0.0020446777343750, 0.0010986328125000, 0.0020141601562500, 0.0010375976562500, +0.0021972656250000, 0.0011901855468750, 0.0021362304687500, 0.0014953613281250, +0.0020751953125000, 0.0011901855468750, 0.0024719238281250, 0.0014953613281250, +0.0022583007812500, 0.0016479492187500, 0.0024719238281250, 0.0013732910156250, +0.0028686523437500, 0.0013427734375000, 0.0024719238281250, 0.0014343261718750, +0.0029907226562500, 0.0007629394531250, 0.0028991699218750, 0.0008239746093750, +0.0029602050781250, 0.0005798339843750, 0.0032348632812500, -0.0000305175781250, +0.0029907226562500, 0.0001525878906250, 0.0031433105468750, 0.0000305175781250, +0.0032348632812500, -0.0002746582031250, 0.0030517578125000, 0.0000610351562500, +0.0030212402343750, 0.0003356933593750, 0.0030822753906250, 0.0000610351562500, +0.0026245117187500, 0.0007934570312500, 0.0027160644531250, 0.0007324218750000, +0.0026855468750000, 0.0008239746093750, 0.0023193359375000, 0.0012512207031250, +0.0024414062500000, 0.0010681152343750, 0.0024414062500000, 0.0013427734375000, +0.0023498535156250, 0.0014038085937500, 0.0024414062500000, 0.0014038085937500, +0.0025939941406250, 0.0014953613281250, 0.0024108886718750, 0.0014953613281250, +0.0025329589843750, 0.0014953613281250, 0.0025634765625000, 0.0015258789062500, +0.0025634765625000, 0.0014953613281250, 0.0025939941406250, 0.0014038085937500, +0.0025329589843750, 0.0014648437500000, 0.0025634765625000, 0.0013427734375000, +0.0025634765625000, 0.0012817382812500, 0.0024719238281250, 0.0013122558593750, +0.0024414062500000, 0.0012817382812500, 0.0024414062500000, 0.0013122558593750, +0.0024108886718750, 0.0015563964843750, 0.0024414062500000, 0.0014038085937500, +0.0023803710937500, 0.0016174316406250, 0.0023498535156250, 0.0020141601562500, +0.0023803710937500, 0.0018615722656250, 0.0022888183593750, 0.0024719238281250, +0.0022583007812500, 0.0025634765625000, 0.0022583007812500, 0.0027160644531250, +0.0022888183593750, 0.0030822753906250, 0.0021972656250000, 0.0030212402343750, +0.0022277832031250, 0.0030822753906250, 0.0022277832031250, 0.0032653808593750, +0.0021362304687500, 0.0030212402343750, 0.0021667480468750, 0.0028076171875000, +0.0021057128906250, 0.0029907226562500, 0.0021972656250000, 0.0022583007812500, +0.0021057128906250, 0.0024414062500000, 0.0022583007812500, 0.0021972656250000, +0.0024108886718750, 0.0015869140625000, 0.0022277832031250, 0.0019836425781250, +0.0026245117187500, 0.0011291503906250, 0.0025634765625000, 0.0012207031250000, +0.0026550292968750, 0.0010681152343750, 0.0028991699218750, 0.0004882812500000, +0.0028381347656250, 0.0007934570312500, 0.0028381347656250, 0.0004577636718750, +0.0030212402343750, 0.0003662109375000, 0.0029602050781250, 0.0004272460937500, +0.0028076171875000, 0.0003356933593750, 0.0029602050781250, 0.0003356933593750, +0.0027160644531250, 0.0003967285156250, 0.0026855468750000, 0.0003051757812500, +0.0026550292968750, 0.0004272460937500, 0.0025024414062500, 0.0006103515625000, +0.0026245117187500, 0.0004272460937500, 0.0023498535156250, 0.0008850097656250, +0.0024719238281250, 0.0009155273437500, 0.0024108886718750, 0.0008850097656250, +0.0021972656250000, 0.0011596679687500, 0.0023498535156250, 0.0010375976562500, +0.0021057128906250, 0.0008544921875000, 0.0021972656250000, 0.0010375976562500, +0.0021972656250000, 0.0006103515625000, 0.0020141601562500, 0.0000610351562500, +0.0021057128906250, 0.0003356933593750, 0.0021057128906250, -0.0004272460937500, +0.0020141601562500, -0.0004577636718750, 0.0021972656250000, -0.0004272460937500, +0.0023498535156250, -0.0007934570312500, 0.0022277832031250, -0.0006713867187500, +0.0024719238281250, -0.0003662109375000, 0.0024719238281250, -0.0004882812500000, +0.0023803710937500, -0.0002746582031250, 0.0025024414062500, 0.0000915527343750, +0.0025329589843750, -0.0000305175781250, 0.0022277832031250, 0.0001831054687500, +0.0022277832031250, 0.0003051757812500, 0.0021057128906250, 0.0002746582031250, +0.0018005371093750, 0.0003356933593750, 0.0019531250000000, 0.0003662109375000, +0.0015563964843750, 0.0002746582031250, 0.0015258789062500, 0.0002746582031250, +0.0014343261718750, 0.0003051757812500, 0.0012207031250000, 0.0003051757812500, +0.0012512207031250, 0.0003051757812500, 0.0009765625000000, 0.0006408691406250, +0.0010681152343750, 0.0006408691406250, 0.0008850097656250, 0.0007934570312500, +0.0006713867187500, 0.0011596679687500, 0.0008544921875000, 0.0012512207031250, +0.0003662109375000, 0.0013427734375000, 0.0005493164062500, 0.0015258789062500, +0.0004577636718750, 0.0015563964843750, 0.0000305175781250, 0.0016174316406250, +0.0003051757812500, 0.0017700195312500, -0.0000915527343750, 0.0014648437500000, +-0.0001220703125000, 0.0017089843750000, 0.0000000000000000, 0.0015258789062500, +-0.0002441406250000, 0.0010375976562500, -0.0002441406250000, 0.0013732910156250, +0.0000305175781250, 0.0007019042968750, -0.0001831054687500, 0.0007629394531250, +0.0000305175781250, 0.0006713867187500, 0.0003356933593750, 0.0003662109375000, +0.0000610351562500, 0.0005187988281250, 0.0005187988281250, 0.0002441406250000, +0.0005493164062500, 0.0001831054687500, 0.0004577636718750, 0.0002441406250000, +0.0006408691406250, 0.0001220703125000, 0.0006103515625000, 0.0000305175781250, +0.0004577636718750, 0.0005798339843750, 0.0005493164062500, 0.0002441406250000, +0.0005798339843750, 0.0007019042968750, 0.0004882812500000, 0.0013122558593750, +0.0005493164062500, 0.0008239746093750, 0.0007019042968750, 0.0023498535156250, +0.0006713867187500, 0.0021362304687500, 0.0007629394531250, 0.0024719238281250, +0.0009460449218750, 0.0044555664062500, 0.0010986328125000, 0.0005187988281250, +0.0012207031250000, 0.0009155273437500, 0.0012817382812500, 0.0002136230468750, +0.0012817382812500, 0.0010375976562500, 0.0012817382812500, 0.0018920898437500, +0.0014343261718750, 0.0012817382812500, 0.0017395019531250, 0.0030822753906250, +0.0016174316406250, 0.0028991699218750, 0.0020446777343750, 0.0030822753906250, +0.0025939941406250, 0.0043029785156250, 0.0023193359375000, 0.0038146972656250, +0.0032043457031250, 0.0039978027343750, 0.0032958984375000, 0.0043945312500000, +0.0031738281250000, 0.0037536621093750, 0.0036010742187500, 0.0033569335937500, +0.0036010742187500, 0.0038757324218750, 0.0029602050781250, 0.0020751953125000, +0.0032043457031250, 0.0025024414062500, 0.0028991699218750, 0.0021057128906250, +0.0021972656250000, 0.0006408691406250, 0.0025939941406250, 0.0013732910156250, +0.0019226074218750, 0.0007019042968750, 0.0017395019531250, 0.0005187988281250, +0.0018920898437500, 0.0009155273437500, 0.0018005371093750, 0.0009155273437500, +0.0017395019531250, 0.0007934570312500, 0.0019226074218750, 0.0016479492187500, +0.0018615722656250, 0.0014343261718750, 0.0017089843750000, 0.0015563964843750, +0.0017700195312500, 0.0021667480468750, 0.0016174316406250, 0.0018920898437500, +0.0012817382812500, 0.0022277832031250, 0.0013122558593750, 0.0022888183593750, +0.0012817382812500, 0.0023498535156250, 0.0010070800781250, 0.0025024414062500, +0.0008850097656250, 0.0023498535156250, 0.0013427734375000, 0.0022583007812500, +0.0009460449218750, 0.0022583007812500, 0.0012207031250000, 0.0024108886718750, +0.0017395019531250, 0.0023193359375000, 0.0012512207031250, 0.0019836425781250, +0.0020141601562500, 0.0026550292968750, 0.0019836425781250, 0.0023498535156250, +0.0017395019531250, 0.0026550292968750, 0.0021057128906250, 0.0032653808593750, +0.0019836425781250, 0.0027465820312500, 0.0012817382812500, 0.0036010742187500, +0.0016174316406250, 0.0033874511718750, 0.0011291503906250, 0.0035400390625000, +0.0002746582031250, 0.0040588378906250, 0.0007629394531250, 0.0035400390625000, +-0.0001220703125000, 0.0040893554687500, -0.0002136230468750, 0.0039367675781250, +-0.0001220703125000, 0.0038146972656250, -0.0005187988281250, 0.0041198730468750, +-0.0004882812500000, 0.0038757324218750, -0.0000305175781250, 0.0037536621093750, +-0.0003662109375000, 0.0036010742187500, 0.0001220703125000, 0.0035400390625000, +0.0007629394531250, 0.0035705566406250, 0.0001831054687500, 0.0035705566406250, +0.0014953613281250, 0.0036010742187500, 0.0012512207031250, 0.0036621093750000, +0.0014038085937500, 0.0036315917968750, 0.0022583007812500, 0.0038146972656250, +0.0017089843750000, 0.0041503906250000, 0.0020141601562500, 0.0038757324218750, +0.0021667480468750, 0.0041503906250000, 0.0018310546875000, 0.0041503906250000, +0.0016784667968750, 0.0039672851562500, 0.0018615722656250, 0.0043945312500000, +0.0014648437500000, 0.0039367675781250, 0.0014038085937500, 0.0039978027343750, +0.0014343261718750, 0.0039672851562500, 0.0011901855468750, 0.0037231445312500, +0.0012817382812500, 0.0038146972656250, 0.0012207031250000, 0.0037841796875000, +0.0011901855468750, 0.0036926269531250, 0.0012512207031250, 0.0037536621093750, +0.0012512207031250, 0.0038146972656250, 0.0011596679687500, 0.0037536621093750, +0.0012817382812500, 0.0036926269531250, 0.0012512207031250, 0.0036621093750000, +0.0013122558593750, 0.0034790039062500, 0.0014953613281250, 0.0033569335937500, +0.0014343261718750, 0.0033874511718750, 0.0015869140625000, 0.0028991699218750, +0.0016784667968750, 0.0029602050781250, 0.0016174316406250, 0.0028076171875000, +0.0016174316406250, 0.0024414062500000, 0.0017089843750000, 0.0026855468750000, +0.0015563964843750, 0.0022277832031250, 0.0015869140625000, 0.0022888183593750, +0.0015869140625000, 0.0022583007812500, 0.0015563964843750, 0.0019531250000000, +0.0016174316406250, 0.0020446777343750, 0.0015563964843750, 0.0018920898437500, +0.0016174316406250, 0.0017700195312500, 0.0016174316406250, 0.0017395019531250, +0.0015563964843750, 0.0017089843750000, 0.0015563964843750, 0.0016174316406250, +0.0016479492187500, 0.0015563964843750, 0.0014953613281250, 0.0014343261718750, +0.0017089843750000, 0.0014038085937500, 0.0018615722656250, 0.0013427734375000, +0.0017089843750000, 0.0012512207031250, 0.0021972656250000, 0.0013732910156250, +0.0020141601562500, 0.0012512207031250, 0.0021972656250000, 0.0013122558593750, +0.0025939941406250, 0.0014343261718750, 0.0022888183593750, 0.0013122558593750, +0.0026855468750000, 0.0016174316406250, 0.0026855468750000, 0.0015563964843750, +0.0025939941406250, 0.0016174316406250, 0.0027465820312500, 0.0018615722656250, +0.0027160644531250, 0.0016784667968750, 0.0027465820312500, 0.0018920898437500, +0.0027160644531250, 0.0018005371093750, 0.0027160644531250, 0.0018920898437500, +0.0027160644531250, 0.0020141601562500, 0.0027160644531250, 0.0018005371093750, +0.0026855468750000, 0.0021057128906250, 0.0027465820312500, 0.0019836425781250, +0.0025939941406250, 0.0021362304687500, 0.0024414062500000, 0.0023193359375000, +0.0025329589843750}, +{-0.0006408691406250, 0.0027465820312500, -0.0003356933593750, 0.0028686523437500, +-0.0007934570312500, 0.0023803710937500, -0.0010986328125000, 0.0023498535156250, +-0.0008239746093750, 0.0023193359375000, -0.0007934570312500, 0.0020446777343750, +-0.0010375976562500, 0.0020141601562500, -0.0002746582031250, 0.0018920898437500, +-0.0005493164062500, 0.0018615722656250, -0.0001831054687500, 0.0020446777343750, +0.0006103515625000, 0.0020751953125000, 0.0001525878906250, 0.0020141601562500, +0.0010681152343750, 0.0021667480468750, 0.0010681152343750, 0.0023193359375000, +0.0011596679687500, 0.0021972656250000, 0.0016784667968750, 0.0021362304687500, +0.0014038085937500, 0.0021362304687500, 0.0017089843750000, 0.0017395019531250, +0.0018005371093750, 0.0018615722656250, 0.0016784667968750, 0.0018005371093750, +0.0016784667968750, 0.0014953613281250, 0.0017089843750000, 0.0017089843750000, +0.0015563964843750, 0.0016174316406250, 0.0015258789062500, 0.0016479492187500, +0.0016174316406250, 0.0018920898437500, 0.0016479492187500, 0.0018920898437500, +0.0015563964843750, 0.0018615722656250, 0.0019226074218750, 0.0023803710937500, +0.0018615722656250, 0.0021362304687500, 0.0018920898437500, 0.0023193359375000, +0.0021057128906250, 0.0027770996093750, 0.0019836425781250, 0.0024108886718750, +0.0020751953125000, 0.0030212402343750, 0.0020446777343750, 0.0028381347656250, +0.0019836425781250, 0.0029907226562500, 0.0020141601562500, 0.0034484863281250, +0.0019836425781250, 0.0030517578125000, 0.0018615722656250, 0.0036010742187500, +0.0019531250000000, 0.0035705566406250, 0.0018005371093750, 0.0035705566406250, +0.0016479492187500, 0.0039367675781250, 0.0017395019531250, 0.0037231445312500, +0.0013122558593750, 0.0038757324218750, 0.0013427734375000, 0.0040588378906250, +0.0013122558593750, 0.0039672851562500, 0.0010681152343750, 0.0039367675781250, +0.0011596679687500, 0.0040893554687500, 0.0010681152343750, 0.0041198730468750, +0.0009765625000000, 0.0041198730468750, 0.0010681152343750, 0.0042419433593750, +0.0011291503906250, 0.0043334960937500, 0.0010681152343750, 0.0042724609375000, +0.0014343261718750, 0.0045166015625000, 0.0013122558593750, 0.0044860839843750, +0.0015869140625000, 0.0044860839843750, 0.0019531250000000, 0.0046081542968750, +0.0017395019531250, 0.0045166015625000, 0.0023803710937500, 0.0046997070312500, +0.0023498535156250, 0.0046997070312500, 0.0025024414062500, 0.0046081542968750, +0.0029907226562500, 0.0046997070312500, 0.0027465820312500, 0.0047607421875000, +0.0031433105468750, 0.0044250488281250, 0.0031433105468750, 0.0045776367187500, +0.0030822753906250, 0.0043640136718750, 0.0032348632812500, 0.0040283203125000, +0.0032043457031250, 0.0041809082031250, 0.0030212402343750, 0.0036926269531250, +0.0030822753906250, 0.0036621093750000, 0.0029296875000000, 0.0035095214843750, +0.0026550292968750, 0.0031433105468750, 0.0028381347656250, 0.0032043457031250, +0.0023193359375000, 0.0030212402343750, 0.0023803710937500, 0.0028991699218750, +0.0022583007812500, 0.0028991699218750, 0.0018310546875000, 0.0027160644531250, +0.0020751953125000, 0.0026245117187500, 0.0016479492187500, 0.0028076171875000, +0.0017089843750000, 0.0026550292968750, 0.0017395019531250, 0.0027160644531250, +0.0015869140625000, 0.0028686523437500, 0.0017395019531250, 0.0027160644531250, +0.0017395019531250, 0.0028686523437500, 0.0017700195312500, 0.0028381347656250, +0.0017700195312500, 0.0028076171875000, 0.0018005371093750, 0.0028686523437500, +0.0018615722656250, 0.0027770996093750, 0.0018005371093750, 0.0026855468750000, +0.0017700195312500, 0.0027160644531250, 0.0018920898437500, 0.0025329589843750, +0.0018615722656250, 0.0023803710937500, 0.0018005371093750, 0.0024719238281250, +0.0024414062500000, 0.0022888183593750, 0.0021667480468750, 0.0022277832031250, +0.0024414062500000, 0.0022277832031250, 0.0030517578125000, 0.0021057128906250, +0.0026550292968750, 0.0021667480468750, 0.0032348632812500, 0.0020141601562500, +0.0033264160156250, 0.0020141601562500, 0.0031127929687500, 0.0018615722656250, +0.0033264160156250, 0.0017089843750000, 0.0032958984375000, 0.0017700195312500, +0.0028686523437500, 0.0014953613281250, 0.0029296875000000, 0.0014953613281250, +0.0027770996093750, 0.0014038085937500, 0.0023803710937500, 0.0011596679687500, +0.0025329589843750, 0.0012512207031250, 0.0022277832031250, 0.0009460449218750, +0.0021057128906250, 0.0009460449218750, 0.0022583007812500, 0.0009155273437500, +0.0022277832031250, 0.0007629394531250, 0.0020446777343750, 0.0007019042968750, +0.0023193359375000, 0.0007629394531250, 0.0022277832031250, 0.0005493164062500, +0.0021972656250000, 0.0005798339843750, 0.0022277832031250, 0.0006713867187500, +0.0021057128906250, 0.0003967285156250, 0.0022583007812500, 0.0006408691406250, +0.0021057128906250, 0.0005187988281250, 0.0022583007812500, 0.0006713867187500, +0.0024108886718750, 0.0008239746093750, 0.0021362304687500, 0.0006103515625000, +0.0026245117187500, 0.0013122558593750, 0.0025634765625000, 0.0010375976562500, +0.0024108886718750, 0.0012512207031250, 0.0027160644531250, 0.0018310546875000, +0.0025634765625000, 0.0014343261718750, 0.0022583007812500, 0.0019531250000000, +0.0024108886718750, 0.0020141601562500, 0.0021972656250000, 0.0018005371093750, +0.0018920898437500, 0.0018920898437500, 0.0022277832031250, 0.0019531250000000, +0.0016174316406250, 0.0016784667968750, 0.0017089843750000, 0.0016479492187500, +0.0017700195312500, 0.0016784667968750, 0.0011291503906250, 0.0015563964843750, +0.0007934570312500, 0.0016174316406250, 0.0003356933593750, 0.0016479492187500, +0.0004577636718750, 0.0016174316406250, 0.0003356933593750, 0.0016174316406250, +-0.0001525878906250, 0.0017089843750000, -0.0000305175781250, 0.0017395019531250, +-0.0001831054687500, 0.0015563964843750, -0.0004882812500000, 0.0016174316406250, +-0.0000610351562500, 0.0015258789062500, 0.0002746582031250, 0.0013122558593750, +-0.0001220703125000, 0.0013732910156250, 0.0011291503906250, 0.0008850097656250, +0.0010070800781250, 0.0009155273437500, 0.0013427734375000, 0.0009155273437500, +0.0022888183593750, 0.0006103515625000, 0.0019836425781250, 0.0007629394531250, +0.0028991699218750, 0.0008239746093750, 0.0031433105468750, 0.0007629394531250, +0.0030212402343750, 0.0008850097656250, 0.0033874511718750, 0.0011291503906250, +0.0035400390625000, 0.0010070800781250, 0.0028991699218750, 0.0010375976562500, +0.0033569335937500, 0.0011901855468750, 0.0029907226562500, 0.0011596679687500, +0.0022277832031250, 0.0010681152343750, 0.0027770996093750, 0.0011596679687500, +0.0018310546875000, 0.0010986328125000, 0.0019226074218750, 0.0010986328125000, +0.0018615722656250, 0.0011901855468750, 0.0012207031250000, 0.0011901855468750, +0.0015563964843750, 0.0011291503906250, 0.0013732910156250, 0.0015258789062500, +0.0010986328125000, 0.0014038085937500, 0.0014343261718750, 0.0015258789062500, +0.0015258789062500, 0.0018920898437500, 0.0011596679687500, 0.0016479492187500, +0.0018310546875000, 0.0020751953125000, 0.0016479492187500, 0.0020446777343750, +0.0016174316406250, 0.0018920898437500, 0.0019531250000000, 0.0019531250000000, +0.0016174316406250, 0.0018615722656250, 0.0018005371093750, 0.0016479492187500, +0.0017700195312500, 0.0016784667968750, 0.0015563964843750, 0.0014343261718750, +0.0015563964843750, 0.0011291503906250, 0.0016174316406250, 0.0011596679687500, +0.0010070800781250, 0.0009460449218750, 0.0010986328125000, 0.0007629394531250, +0.0010070800781250, 0.0008850097656250, 0.0005187988281250, 0.0009155273437500, +0.0007019042968750, 0.0008239746093750, 0.0006103515625000, 0.0010986328125000, +0.0003967285156250, 0.0010681152343750, 0.0006713867187500, 0.0010986328125000, +0.0008544921875000, 0.0012817382812500, 0.0004577636718750, 0.0012207031250000, +0.0014953613281250, 0.0012207031250000, 0.0010375976562500, 0.0012207031250000, +0.0015258789062500, 0.0012207031250000, 0.0025024414062500, 0.0012512207031250, +0.0016479492187500, 0.0011596679687500, 0.0032653808593750, 0.0012817382812500, +0.0029602050781250, 0.0012512207031250, 0.0031738281250000, 0.0011596679687500, +0.0043640136718750, 0.0012207031250000, 0.0037231445312500, 0.0011901855468750, +0.0043945312500000, 0.0010986328125000, 0.0045471191406250, 0.0010070800781250, +0.0043640136718750, 0.0010986328125000, 0.0045166015625000, 0.0010681152343750, +0.0045776367187500, 0.0008850097656250, 0.0044250488281250, 0.0013427734375000, +0.0044860839843750, 0.0010986328125000, 0.0043640136718750, 0.0013122558593750, +0.0042724609375000, 0.0018005371093750, 0.0044250488281250, 0.0014343261718750, +0.0041503906250000, 0.0021057128906250, 0.0042114257812500, 0.0021057128906250, +0.0042724609375000, 0.0021057128906250, 0.0041809082031250, 0.0024414062500000, +0.0042114257812500, 0.0022888183593750, 0.0043029785156250, 0.0023193359375000, +0.0042419433593750, 0.0024719238281250, 0.0043334960937500, 0.0021972656250000, +0.0043640136718750, 0.0020141601562500, 0.0042724609375000, 0.0022277832031250, +0.0044860839843750, 0.0014953613281250, 0.0043640136718750, 0.0015563964843750, +0.0044250488281250, 0.0013732910156250, 0.0046691894531250, 0.0008850097656250, +0.0044860839843750, 0.0010986328125000, 0.0048217773437500, 0.0007629394531250, +0.0047912597656250, 0.0007324218750000, 0.0048217773437500, 0.0008544921875000, +0.0050048828125000, 0.0007629394531250, 0.0048522949218750, 0.0007934570312500, +0.0050659179687500, 0.0011901855468750, 0.0051269531250000, 0.0010986328125000, +0.0049438476562500, 0.0013122558593750, 0.0049743652343750, 0.0016479492187500, +0.0050659179687500, 0.0014953613281250, 0.0046386718750000, 0.0018005371093750, +0.0047607421875000, 0.0018615722656250, 0.0045166015625000, 0.0018310546875000, +0.0041198730468750, 0.0019836425781250, 0.0043640136718750, 0.0019836425781250, +0.0036621093750000, 0.0017089843750000, 0.0036621093750000, 0.0019226074218750, +0.0035095214843750, 0.0017700195312500, 0.0030212402343750, 0.0014343261718750, +0.0032653808593750, 0.0016479492187500, 0.0027770996093750, 0.0012817382812500, +0.0028076171875000, 0.0013122558593750, 0.0027465820312500, 0.0012817382812500, +0.0024719238281250, 0.0010986328125000, 0.0026245117187500, 0.0011901855468750, +0.0023498535156250, 0.0010070800781250, 0.0023803710937500, 0.0010375976562500, +0.0023803710937500, 0.0009460449218750, 0.0022583007812500, 0.0007324218750000, +0.0023498535156250, 0.0008239746093750, 0.0021972656250000, 0.0006103515625000, +0.0022888183593750, 0.0005187988281250, 0.0022888183593750, 0.0007019042968750, +0.0021972656250000, 0.0007324218750000, 0.0023803710937500, 0.0005187988281250, +0.0021057128906250, 0.0012512207031250, 0.0022277832031250, 0.0010681152343750, +0.0021972656250000, 0.0013122558593750, 0.0020141601562500, 0.0019226074218750, +0.0021972656250000, 0.0015869140625000, 0.0019836425781250, 0.0020141601562500, +0.0020446777343750, 0.0021362304687500, 0.0020446777343750, 0.0018615722656250, +0.0019531250000000, 0.0018310546875000, 0.0020751953125000, 0.0019531250000000, +0.0018005371093750, 0.0014038085937500, 0.0019226074218750, 0.0014648437500000, +0.0018005371093750, 0.0013427734375000, 0.0015563964843750, 0.0009765625000000, +0.0018005371093750, 0.0011291503906250, 0.0013122558593750, 0.0009460449218750, +0.0014343261718750}, +{0.0031127929687500, 0.0011596679687500, 0.0029602050781250, 0.0013122558593750, +0.0031738281250000, 0.0010681152343750, 0.0038146972656250, 0.0005187988281250, +0.0034484863281250, 0.0008239746093750, 0.0042114257812500, 0.0003662109375000, +0.0041809082031250, 0.0002746582031250, 0.0042114257812500, 0.0003967285156250, +0.0046691894531250, 0.0002746582031250, 0.0044250488281250, 0.0002746582031250, +0.0044555664062500, 0.0005187988281250, 0.0044860839843750, 0.0004577636718750, +0.0042724609375000, 0.0004882812500000, 0.0040893554687500, 0.0005798339843750, +0.0041198730468750, 0.0005493164062500, 0.0038757324218750, 0.0006408691406250, +0.0036926269531250, 0.0005798339843750, 0.0036621093750000, 0.0006103515625000, +0.0035400390625000, 0.0007324218750000, 0.0032653808593750, 0.0005798339843750, +0.0035400390625000, 0.0009155273437500, 0.0032348632812500, 0.0008239746093750, +0.0033264160156250, 0.0009460449218750, 0.0035705566406250, 0.0012512207031250, +0.0031738281250000, 0.0010375976562500, 0.0035400390625000, 0.0013732910156250, +0.0033264160156250, 0.0014953613281250, 0.0032958984375000, 0.0014953613281250, +0.0035705566406250, 0.0016479492187500, 0.0032348632812500, 0.0016784667968750, +0.0036315917968750, 0.0015563964843750, 0.0034484863281250, 0.0016784667968750, +0.0034790039062500, 0.0015869140625000, 0.0037231445312500, 0.0013732910156250, +0.0034179687500000, 0.0015563964843750, 0.0038452148437500, 0.0013427734375000, +0.0036926269531250, 0.0013732910156250, 0.0036926269531250, 0.0014343261718750, +0.0039978027343750, 0.0013732910156250, 0.0036926269531250, 0.0013732910156250, +0.0040283203125000, 0.0014038085937500, 0.0039062500000000, 0.0014343261718750, +0.0038452148437500, 0.0013732910156250, 0.0039978027343750, 0.0013732910156250, +0.0038146972656250, 0.0014648437500000, 0.0038757324218750, 0.0013427734375000, +0.0038452148437500, 0.0014343261718750, 0.0038146972656250, 0.0013732910156250, +0.0038146972656250, 0.0011901855468750, 0.0037536621093750, 0.0013427734375000, +0.0037841796875000, 0.0011291503906250, 0.0037841796875000, 0.0010681152343750, +0.0036926269531250, 0.0012207031250000, 0.0036926269531250, 0.0012207031250000, +0.0037841796875000, 0.0010986328125000, 0.0035400390625000, 0.0016479492187500, +0.0035400390625000, 0.0014648437500000, 0.0033874511718750, 0.0016784667968750, +0.0031738281250000, 0.0021667480468750, 0.0032043457031250, 0.0018920898437500, +0.0028076171875000, 0.0024108886718750, 0.0027770996093750, 0.0024719238281250, +0.0026245117187500, 0.0023803710937500, 0.0022888183593750, 0.0025634765625000, +0.0023193359375000, 0.0025329589843750, 0.0021057128906250, 0.0025939941406250, +0.0019836425781250, 0.0025329589843750, 0.0019226074218750, 0.0027160644531250, +0.0018920898437500, 0.0028686523437500, 0.0018310546875000, 0.0027465820312500, +0.0018920898437500, 0.0030822753906250, 0.0018615722656250, 0.0031127929687500, +0.0018005371093750, 0.0031433105468750, 0.0018615722656250, 0.0033264160156250, +0.0018005371093750, 0.0032653808593750, 0.0017700195312500, 0.0032043457031250, +0.0017395019531250, 0.0033264160156250, 0.0017700195312500, 0.0031127929687500, +0.0018310546875000, 0.0028381347656250, 0.0017395019531250, 0.0029602050781250, +0.0019226074218750, 0.0024719238281250, 0.0018615722656250, 0.0025024414062500, +0.0020751953125000, 0.0023498535156250, 0.0022888183593750, 0.0019531250000000, +0.0021057128906250, 0.0020751953125000, 0.0026550292968750, 0.0019836425781250, +0.0025939941406250, 0.0017700195312500, 0.0025634765625000, 0.0020446777343750, +0.0028381347656250, 0.0022888183593750, 0.0026855468750000, 0.0020446777343750, +0.0024414062500000, 0.0026855468750000, 0.0025634765625000, 0.0025634765625000, +0.0021972656250000, 0.0025634765625000, 0.0018615722656250, 0.0028686523437500, +0.0020751953125000, 0.0027160644531250, 0.0015563964843750, 0.0029296875000000, +0.0014038085937500, 0.0027770996093750, 0.0016174316406250, 0.0029296875000000, +0.0014343261718750, 0.0031738281250000, 0.0012512207031250, 0.0028991699218750, +0.0017089843750000, 0.0035095214843750, 0.0014343261718750, 0.0032958984375000, +0.0016174316406250, 0.0034484863281250, 0.0020446777343750, 0.0040283203125000, +0.0016174316406250, 0.0037536621093750, 0.0021667480468750, 0.0042724609375000, +0.0020751953125000, 0.0043029785156250, 0.0019226074218750, 0.0043029785156250, +0.0021667480468750, 0.0045471191406250, 0.0019836425781250, 0.0044860839843750, +0.0021362304687500, 0.0040283203125000, 0.0019226074218750, 0.0043640136718750, +0.0021362304687500, 0.0037841796875000, 0.0024108886718750, 0.0030212402343750, +0.0021362304687500, 0.0035095214843750, 0.0026855468750000, 0.0024414062500000, +0.0025634765625000, 0.0023193359375000, 0.0025329589843750, 0.0025634765625000, +0.0030822753906250, 0.0022277832031250, 0.0022277832031250, 0.0033264160156250, +0.0021972656250000, 0.0026550292968750, 0.0021667480468750, 0.0027465820312500, +0.0021667480468750, 0.0026550292968750, 0.0020446777343750, 0.0024108886718750, +0.0019226074218750, 0.0024719238281250, 0.0022583007812500, 0.0024719238281250, +0.0020751953125000, 0.0023498535156250, 0.0019836425781250, 0.0023498535156250, +0.0022583007812500, 0.0023803710937500, 0.0021057128906250, 0.0023193359375000, +0.0017395019531250, 0.0025024414062500, 0.0018615722656250, 0.0023803710937500, +0.0014953613281250, 0.0023193359375000, 0.0009155273437500, 0.0026245117187500, +0.0011596679687500, 0.0025939941406250, 0.0007019042968750, 0.0020141601562500, +0.0003356933593750, 0.0023498535156250, 0.0006408691406250, 0.0019836425781250, +0.0007019042968750, 0.0013732910156250, 0.0003662109375000, 0.0017700195312500, +0.0012207031250000, 0.0008239746093750, 0.0009765625000000, 0.0009765625000000, +0.0010681152343750, 0.0007934570312500, 0.0016479492187500, -0.0000305175781250, +0.0013732910156250, 0.0003051757812500, 0.0016784667968750, 0.0002746582031250, +0.0017089843750000, -0.0002441406250000, 0.0015258789062500, 0.0001525878906250, +0.0015563964843750, 0.0005187988281250, 0.0015563964843750, 0.0000000000000000, +0.0011596679687500, 0.0008544921875000, 0.0012207031250000, 0.0007324218750000, +0.0010375976562500, 0.0007324218750000, 0.0006103515625000, 0.0012207031250000, +0.0007019042968750, 0.0009155273437500, 0.0006408691406250, 0.0009155273437500, +0.0005187988281250, 0.0010070800781250, 0.0006408691406250, 0.0009765625000000, +0.0007019042968750, 0.0009155273437500, 0.0005493164062500, 0.0009460449218750, +0.0010681152343750, 0.0007629394531250, 0.0009155273437500, 0.0009155273437500, +0.0011291503906250, 0.0010070800781250, 0.0015563964843750, 0.0007629394531250, +0.0012207031250000, 0.0008544921875000, 0.0018310546875000, 0.0012817382812500, +0.0017089843750000, 0.0010681152343750, 0.0016784667968750, 0.0014648437500000, +0.0020141601562500, 0.0020141601562500, 0.0017700195312500, 0.0015563964843750, +0.0017700195312500, 0.0022888183593750, 0.0017700195312500, 0.0022583007812500, +0.0016479492187500, 0.0021362304687500, 0.0015563964843750, 0.0025329589843750, +0.0015563964843750, 0.0023498535156250, 0.0016479492187500, 0.0021972656250000, +0.0014953613281250, 0.0021972656250000, 0.0015563964843750, 0.0021667480468750, +0.0016784667968750, 0.0021057128906250, 0.0015869140625000, 0.0021667480468750, +0.0016479492187500, 0.0022888183593750, 0.0016784667968750, 0.0021057128906250, +0.0016479492187500, 0.0023193359375000, 0.0016174316406250, 0.0026550292968750, +0.0016174316406250, 0.0024719238281250, 0.0015563964843750, 0.0028991699218750, +0.0015258789062500, 0.0030517578125000, 0.0014953613281250, 0.0028381347656250, +0.0013732910156250, 0.0029602050781250, 0.0013427734375000, 0.0033264160156250, +0.0015258789062500, 0.0027465820312500, 0.0013427734375000, 0.0030517578125000, +0.0014648437500000, 0.0029296875000000, 0.0017089843750000, 0.0023803710937500, +0.0013732910156250, 0.0027770996093750, 0.0020446777343750, 0.0024108886718750, +0.0018310546875000, 0.0022583007812500, 0.0018615722656250, 0.0024414062500000, +0.0022888183593750, 0.0023498535156250, 0.0020141601562500, 0.0022583007812500, +0.0023193359375000, 0.0025024414062500, 0.0022277832031250, 0.0022888183593750, +0.0021667480468750, 0.0024108886718750, 0.0024108886718750, 0.0026245117187500, +0.0022888183593750, 0.0022888183593750, 0.0021972656250000, 0.0025634765625000, +0.0023498535156250, 0.0024108886718750, 0.0021362304687500, 0.0023803710937500, +0.0019226074218750, 0.0025329589843750, 0.0022277832031250, 0.0022888183593750, +0.0017700195312500, 0.0023498535156250, 0.0018615722656250, 0.0023498535156250, +0.0018310546875000, 0.0022583007812500, 0.0015563964843750, 0.0023193359375000, +0.0017395019531250, 0.0022583007812500, 0.0014343261718750, 0.0021667480468750, +0.0014648437500000, 0.0021972656250000, 0.0014343261718750, 0.0021362304687500, +0.0012817382812500, 0.0021362304687500, 0.0013427734375000, 0.0021362304687500, +0.0013122558593750, 0.0020141601562500, 0.0012512207031250, 0.0020141601562500, +0.0013122558593750, 0.0019836425781250, 0.0013427734375000, 0.0018310546875000, +0.0011901855468750, 0.0018920898437500, 0.0015563964843750, 0.0019531250000000, +0.0013732910156250, 0.0017700195312500, 0.0016479492187500, 0.0019836425781250, +0.0020446777343750, 0.0021667480468750, 0.0017395019531250, 0.0019531250000000, +0.0025939941406250, 0.0024719238281250, 0.0025329589843750, 0.0023803710937500, +0.0027160644531250, 0.0025634765625000, 0.0033264160156250, 0.0028991699218750, +0.0030822753906250, 0.0026855468750000, 0.0034790039062500, 0.0031127929687500, +0.0036315917968750, 0.0031127929687500, 0.0034790039062500, 0.0030517578125000, +0.0036010742187500, 0.0032348632812500, 0.0036315917968750, 0.0031738281250000, +0.0032653808593750, 0.0031433105468750, 0.0034790039062500, 0.0032958984375000, +0.0032653808593750, 0.0032043457031250, 0.0028686523437500, 0.0030212402343750, +0.0032043457031250, 0.0032043457031250, 0.0025939941406250, 0.0028381347656250, +0.0027160644531250, 0.0029602050781250, 0.0025024414062500, 0.0028381347656250, +0.0020446777343750, 0.0025939941406250, 0.0024414062500000, 0.0027465820312500, +0.0017395019531250, 0.0024719238281250, 0.0018920898437500, 0.0023803710937500, +0.0017700195312500, 0.0022888183593750, 0.0012817382812500, 0.0021362304687500, +0.0016174316406250, 0.0021362304687500, 0.0011596679687500, 0.0018310546875000, +0.0012512207031250, 0.0018005371093750, 0.0011901855468750, 0.0016784667968750, +0.0008850097656250, 0.0014038085937500, 0.0010681152343750, 0.0014038085937500, +0.0008850097656250, 0.0011291503906250, 0.0007629394531250, 0.0011291503906250, +0.0009765625000000, 0.0010070800781250, 0.0010375976562500, 0.0007019042968750, +0.0009460449218750, 0.0008239746093750, 0.0016479492187500, 0.0007324218750000, +0.0014343261718750, 0.0006713867187500, 0.0018920898437500, 0.0008850097656250, +0.0026245117187500, 0.0010070800781250, 0.0021667480468750, 0.0009460449218750, +0.0032043457031250, 0.0014953613281250, 0.0032653808593750, 0.0013732910156250, +0.0031127929687500, 0.0015869140625000, 0.0035400390625000, 0.0020446777343750, +0.0035095214843750, 0.0017700195312500, 0.0032653808593750, 0.0022277832031250, +0.0033874511718750, 0.0022277832031250, 0.0033264160156250, 0.0022583007812500, +0.0031127929687500}, +{0.0032348632812500, 0.0011596679687500, 0.0030212402343750, 0.0010681152343750, +0.0033264160156250, 0.0010375976562500, 0.0022888183593750, 0.0010681152343750, +0.0025939941406250, 0.0010681152343750, 0.0021057128906250, 0.0011291503906250, +0.0012512207031250, 0.0011596679687500, 0.0018615722656250, 0.0010375976562500, +0.0005187988281250, 0.0012817382812500, 0.0006408691406250, 0.0013732910156250, +0.0005798339843750, 0.0014038085937500, -0.0001831054687500, 0.0015563964843750, +0.0001525878906250, 0.0015563964843750, 0.0001831054687500, 0.0016479492187500, +-0.0000305175781250, 0.0017089843750000, 0.0004577636718750, 0.0018005371093750, +0.0008239746093750, 0.0018310546875000, 0.0006103515625000, 0.0018310546875000, +0.0018920898437500, 0.0018615722656250, 0.0016479492187500, 0.0019226074218750, +0.0021667480468750, 0.0019531250000000, 0.0032958984375000, 0.0019226074218750, +0.0027465820312500, 0.0019226074218750, 0.0037536621093750, 0.0020446777343750, +0.0038146972656250, 0.0021057128906250, 0.0036315917968750, 0.0021362304687500, +0.0040893554687500, 0.0022583007812500, 0.0040283203125000, 0.0023498535156250, +0.0032958984375000, 0.0021972656250000, 0.0036010742187500, 0.0023803710937500, +0.0029602050781250, 0.0023498535156250, 0.0020446777343750, 0.0021667480468750, +0.0025634765625000, 0.0023498535156250, 0.0009765625000000, 0.0020751953125000, +0.0011291503906250, 0.0021972656250000, 0.0007934570312500, 0.0022583007812500, +-0.0003356933593750, 0.0020446777343750, 0.0001831054687500, 0.0022277832031250, +-0.0005187988281250, 0.0020446777343750, -0.0006713867187500, 0.0021972656250000, +-0.0004272460937500, 0.0021972656250000, -0.0005493164062500, 0.0019836425781250, +-0.0006103515625000, 0.0021972656250000, -0.0002441406250000, 0.0019531250000000, +-0.0003051757812500, 0.0021057128906250, -0.0001220703125000, 0.0021362304687500, +0.0002136230468750, 0.0019836425781250, -0.0000305175781250, 0.0021972656250000, +0.0005493164062500, 0.0021972656250000, 0.0003967285156250, 0.0021362304687500, +0.0005798339843750, 0.0022888183593750, 0.0010375976562500, 0.0024108886718750, +0.0006713867187500, 0.0023193359375000, 0.0014648437500000, 0.0026550292968750, +0.0012207031250000, 0.0026550292968750, 0.0014343261718750, 0.0026550292968750, +0.0020446777343750, 0.0028076171875000, 0.0014953613281250, 0.0026855468750000, +0.0023498535156250, 0.0027160644531250, 0.0021972656250000, 0.0027160644531250, +0.0022888183593750, 0.0025329589843750, 0.0027770996093750, 0.0024108886718750, +0.0024414062500000, 0.0023803710937500, 0.0028991699218750, 0.0020751953125000, +0.0027465820312500, 0.0018920898437500, 0.0027160644531250, 0.0018005371093750, +0.0030517578125000, 0.0015258789062500, 0.0027770996093750, 0.0014648437500000, +0.0028991699218750, 0.0013427734375000, 0.0028076171875000, 0.0011901855468750, +0.0027770996093750, 0.0010986328125000, 0.0027465820312500, 0.0010070800781250, +0.0025939941406250, 0.0009460449218750, 0.0029602050781250, 0.0008850097656250, +0.0026550292968750, 0.0008239746093750, 0.0028381347656250, 0.0008850097656250, +0.0032958984375000, 0.0008544921875000, 0.0028381347656250, 0.0008850097656250, +0.0033569335937500, 0.0011901855468750, 0.0033874511718750, 0.0010986328125000, +0.0031433105468750, 0.0012512207031250, 0.0032653808593750, 0.0014648437500000, +0.0032958984375000, 0.0013122558593750, 0.0026550292968750, 0.0016174316406250, +0.0029296875000000, 0.0015258789062500, 0.0025634765625000, 0.0017089843750000, +0.0019226074218750, 0.0020446777343750, 0.0023193359375000, 0.0018005371093750, +0.0013427734375000, 0.0021362304687500, 0.0014953613281250, 0.0021972656250000, +0.0013427734375000, 0.0021057128906250, 0.0006713867187500, 0.0021972656250000, +0.0011596679687500, 0.0022277832031250, 0.0005187988281250, 0.0018310546875000, +0.0004882812500000, 0.0019531250000000, 0.0004882812500000, 0.0017700195312500, +0.0001220703125000, 0.0013427734375000, 0.0002746582031250, 0.0016784667968750, +0.0000610351562500, 0.0013732910156250, -0.0000610351562500, 0.0012817382812500, +-0.0000610351562500, 0.0013732910156250, -0.0000915527343750, 0.0013732910156250, +0.0002746582031250, 0.0013427734375000, 0.0005493164062500, 0.0014343261718750, +0.0003662109375000, 0.0014648437500000, 0.0005493164062500, 0.0013732910156250, +0.0008850097656250, 0.0014343261718750, 0.0006103515625000, 0.0014953613281250, +0.0014038085937500, 0.0013122558593750, 0.0013427734375000, 0.0014038085937500, +0.0013122558593750, 0.0014038085937500, 0.0016784667968750, 0.0012512207031250, +0.0015563964843750, 0.0013732910156250, 0.0015258789062500, 0.0013732910156250, +0.0013732910156250, 0.0012512207031250, 0.0014953613281250, 0.0014648437500000, +0.0015869140625000, 0.0017089843750000, 0.0013122558593750, 0.0016174316406250, +0.0019226074218750, 0.0018920898437500, 0.0019531250000000, 0.0020141601562500, +0.0018615722656250, 0.0019836425781250, 0.0021972656250000, 0.0021362304687500, +0.0022583007812500, 0.0021972656250000, 0.0019531250000000, 0.0019226074218750, +0.0022277832031250, 0.0021972656250000, 0.0019836425781250, 0.0020141601562500, +0.0016174316406250, 0.0017089843750000, 0.0020751953125000, 0.0020446777343750, +0.0013122558593750, 0.0014038085937500, 0.0014648437500000, 0.0015258789062500, +0.0015563964843750, 0.0014343261718750, 0.0010375976562500, 0.0009765625000000, +0.0013122558593750, 0.0012207031250000, 0.0014648437500000, 0.0009460449218750, +0.0013122558593750, 0.0008544921875000, 0.0015563964843750, 0.0010681152343750, +0.0019226074218750, 0.0010986328125000, 0.0016479492187500, 0.0010070800781250, +0.0021667480468750, 0.0013427734375000, 0.0022583007812500, 0.0012512207031250, +0.0020751953125000, 0.0013732910156250, 0.0022583007812500, 0.0016784667968750, +0.0023498535156250, 0.0014343261718750, 0.0020446777343750, 0.0018005371093750, +0.0022277832031250, 0.0018005371093750, 0.0021667480468750, 0.0017700195312500, +0.0019226074218750, 0.0019226074218750, 0.0021667480468750, 0.0018310546875000, +0.0019531250000000, 0.0018615722656250, 0.0019531250000000, 0.0019226074218750, +0.0020446777343750, 0.0018310546875000, 0.0020141601562500, 0.0017395019531250, +0.0020751953125000, 0.0018615722656250, 0.0019531250000000, 0.0015563964843750, +0.0019836425781250, 0.0016174316406250, 0.0019836425781250, 0.0016174316406250, +0.0018920898437500, 0.0014648437500000, 0.0018310546875000, 0.0016174316406250, +0.0018005371093750, 0.0017395019531250, 0.0017700195312500, 0.0015258789062500, +0.0017395019531250, 0.0018615722656250, 0.0017700195312500, 0.0021362304687500, +0.0017089843750000, 0.0017700195312500, 0.0015258789062500, 0.0024719238281250, +0.0015869140625000, 0.0023193359375000, 0.0013732910156250, 0.0023193359375000, +0.0010070800781250, 0.0027160644531250, 0.0011596679687500, 0.0024414062500000, +0.0007934570312500, 0.0026245117187500, 0.0007019042968750, 0.0025329589843750, +0.0007324218750000, 0.0025024414062500, 0.0005187988281250, 0.0025329589843750, +0.0005187988281250, 0.0024108886718750, 0.0005798339843750, 0.0025634765625000, +0.0004272460937500, 0.0025634765625000, 0.0006713867187500, 0.0025024414062500, +0.0009155273437500, 0.0026245117187500, 0.0006103515625000, 0.0026245117187500, +0.0013122558593750, 0.0026550292968750, 0.0012817382812500, 0.0027770996093750, +0.0014038085937500, 0.0026550292968750, 0.0018920898437500, 0.0025939941406250, +0.0016784667968750, 0.0028076171875000, 0.0018920898437500, 0.0021667480468750, +0.0020751953125000, 0.0024719238281250, 0.0018920898437500, 0.0021667480468750, +0.0018005371093750, 0.0014648437500000, 0.0019836425781250, 0.0018920898437500, +0.0014343261718750, 0.0009460449218750, 0.0014953613281250, 0.0010070800781250, +0.0013732910156250, 0.0008239746093750, 0.0010070800781250, 0.0001525878906250, +0.0012207031250000, 0.0003662109375000, 0.0008239746093750, 0.0000000000000000, +0.0008239746093750, -0.0001831054687500, 0.0008239746093750, 0.0000000000000000, +0.0006103515625000, -0.0000305175781250, 0.0007629394531250, -0.0002136230468750, +0.0004882812500000, 0.0004882812500000, 0.0006103515625000, 0.0002136230468750, +0.0005798339843750, 0.0005493164062500, 0.0003967285156250, 0.0012512207031250, +0.0006103515625000, 0.0008850097656250, 0.0004272460937500, 0.0018920898437500, +0.0004882812500000, 0.0018615722656250, 0.0005187988281250, 0.0019836425781250, +0.0003967285156250, 0.0027160644531250, 0.0005798339843750, 0.0024719238281250, +0.0005493164062500, 0.0025634765625000, 0.0005493164062500, 0.0028076171875000, +0.0006408691406250, 0.0025024414062500, 0.0006408691406250, 0.0021972656250000, +0.0006713867187500, 0.0024108886718750, 0.0007324218750000, 0.0017089843750000, +0.0007019042968750, 0.0017700195312500, 0.0007324218750000, 0.0015869140625000, +0.0007934570312500, 0.0009765625000000, 0.0007324218750000, 0.0013122558593750, +0.0009460449218750, 0.0008544921875000, 0.0008544921875000, 0.0007629394531250, +0.0010070800781250, 0.0009460449218750, 0.0011596679687500, 0.0007934570312500, +0.0010986328125000, 0.0008239746093750, 0.0014648437500000, 0.0011291503906250, +0.0014953613281250, 0.0010070800781250, 0.0016174316406250, 0.0011291503906250, +0.0018005371093750, 0.0014343261718750, 0.0017700195312500, 0.0011596679687500, +0.0018920898437500, 0.0014953613281250, 0.0019836425781250, 0.0014953613281250, +0.0020446777343750, 0.0014648437500000, 0.0021362304687500, 0.0015869140625000, +0.0021667480468750, 0.0015563964843750, 0.0022888183593750, 0.0016784667968750, +0.0023498535156250, 0.0016479492187500, 0.0024414062500000, 0.0017395019531250, +0.0025329589843750, 0.0018310546875000, 0.0026245117187500, 0.0017395019531250, +0.0026550292968750, 0.0020751953125000, 0.0027770996093750, 0.0019836425781250, +0.0026855468750000, 0.0021972656250000, 0.0026245117187500, 0.0025329589843750, +0.0027465820312500, 0.0023193359375000, 0.0022583007812500, 0.0028991699218750, +0.0023803710937500, 0.0028381347656250, 0.0022277832031250, 0.0028991699218750, +0.0017089843750000, 0.0032958984375000, 0.0020141601562500, 0.0031127929687500, +0.0015563964843750, 0.0032958984375000, 0.0014343261718750, 0.0033874511718750, +0.0015563964843750, 0.0031433105468750, 0.0014648437500000, 0.0030517578125000, +0.0013427734375000, 0.0032043457031250, 0.0016784667968750, 0.0027465820312500, +0.0015563964843750, 0.0027770996093750, 0.0016479492187500, 0.0027465820312500, +0.0019226074218750, 0.0024414062500000, 0.0018310546875000, 0.0026245117187500, +0.0021057128906250, 0.0025329589843750, 0.0021057128906250, 0.0025024414062500, +0.0021972656250000, 0.0025634765625000, 0.0023498535156250, 0.0026245117187500, +0.0022583007812500, 0.0026245117187500, 0.0023803710937500, 0.0024108886718750, +0.0023803710937500, 0.0025634765625000, 0.0023498535156250, 0.0024414062500000, +0.0024108886718750, 0.0021362304687500, 0.0023803710937500, 0.0022277832031250, +0.0023193359375000, 0.0019836425781250, 0.0022583007812500, 0.0018615722656250, +0.0022583007812500, 0.0019226074218750, 0.0022583007812500, 0.0018310546875000, +0.0022277832031250, 0.0016479492187500, 0.0021057128906250, 0.0021667480468750, +0.0021057128906250, 0.0019226074218750, 0.0020141601562500, 0.0021667480468750, +0.0018920898437500, 0.0027160644531250, 0.0018615722656250, 0.0022888183593750, +0.0017700195312500}, +{0.0017700195312500, 0.0018005371093750, 0.0015563964843750, 0.0011596679687500, +0.0016479492187500, 0.0012207031250000, 0.0015869140625000, 0.0011291503906250, +0.0014038085937500, 0.0006103515625000, 0.0016479492187500, 0.0008544921875000, +0.0012817382812500, 0.0004577636718750, 0.0014343261718750, 0.0003051757812500, +0.0013427734375000, 0.0004577636718750, 0.0011291503906250, 0.0003662109375000, +0.0014648437500000, 0.0002746582031250, 0.0010070800781250, 0.0008239746093750, +0.0011596679687500, 0.0006713867187500, 0.0011596679687500, 0.0009765625000000, +0.0008850097656250, 0.0015869140625000, 0.0011291503906250, 0.0013427734375000, +0.0008544921875000, 0.0020751953125000, 0.0009155273437500, 0.0020446777343750, +0.0009460449218750, 0.0023193359375000, 0.0008239746093750, 0.0028381347656250, +0.0010070800781250, 0.0026245117187500, 0.0007324218750000, 0.0031127929687500, +0.0008850097656250, 0.0031433105468750, 0.0007629394531250, 0.0032348632812500, +0.0005187988281250, 0.0034179687500000, 0.0007934570312500, 0.0033874511718750, +0.0004577636718750, 0.0035400390625000, 0.0005493164062500, 0.0035705566406250, +0.0007324218750000, 0.0036926269531250, 0.0006408691406250, 0.0037841796875000, +0.0006713867187500, 0.0036621093750000, 0.0009460449218750, 0.0040893554687500, +0.0009460449218750, 0.0039978027343750, 0.0012207031250000, 0.0041503906250000, +0.0015869140625000, 0.0045166015625000, 0.0015869140625000, 0.0042724609375000, +0.0018005371093750, 0.0045776367187500, 0.0019836425781250, 0.0045471191406250, +0.0019531250000000, 0.0044860839843750, 0.0020446777343750, 0.0046386718750000, +0.0022583007812500, 0.0045471191406250, 0.0017700195312500, 0.0044860839843750, +0.0019531250000000, 0.0044555664062500, 0.0018920898437500, 0.0043640136718750, +0.0014953613281250, 0.0042114257812500, 0.0017700195312500, 0.0042419433593750, +0.0016479492187500, 0.0041503906250000, 0.0015869140625000, 0.0040588378906250, +0.0017700195312500, 0.0041503906250000, 0.0018920898437500, 0.0040893554687500, +0.0019226074218750, 0.0039672851562500, 0.0020751953125000, 0.0042419433593750, +0.0022583007812500, 0.0041809082031250, 0.0021667480468750, 0.0041198730468750, +0.0021362304687500, 0.0042724609375000, 0.0021972656250000, 0.0041809082031250, +0.0020141601562500, 0.0038452148437500, 0.0018920898437500, 0.0039672851562500, +0.0018920898437500, 0.0036315917968750, 0.0018310546875000, 0.0031738281250000, +0.0017700195312500, 0.0033569335937500, 0.0018005371093750, 0.0026550292968750, +0.0017700195312500, 0.0026245117187500, 0.0018615722656250, 0.0023803710937500, +0.0019836425781250, 0.0018615722656250, 0.0018615722656250, 0.0020141601562500, +0.0021057128906250, 0.0018310546875000, 0.0021057128906250, 0.0016174316406250, +0.0021362304687500, 0.0017395019531250, 0.0022888183593750, 0.0018310546875000, +0.0023193359375000, 0.0017395019531250, 0.0022888183593750, 0.0019531250000000, +0.0023803710937500, 0.0019531250000000, 0.0024108886718750, 0.0019531250000000, +0.0023193359375000, 0.0019836425781250, 0.0024414062500000, 0.0019836425781250, +0.0022888183593750, 0.0021667480468750, 0.0022888183593750, 0.0019836425781250, +0.0021667480468750, 0.0021057128906250, 0.0020751953125000, 0.0024719238281250, +0.0021057128906250, 0.0021667480468750, 0.0016784667968750, 0.0025939941406250, +0.0016479492187500, 0.0026550292968750, 0.0015258789062500, 0.0023803710937500, +0.0010070800781250, 0.0024108886718750, 0.0010681152343750, 0.0018920898437500, +0.0010986328125000, 0.0023193359375000, 0.0010070800781250, 0.0022888183593750, +0.0012207031250000, 0.0022583007812500, 0.0013732910156250, 0.0022888183593750, +0.0012512207031250, 0.0022583007812500, 0.0014038085937500, 0.0024719238281250, +0.0015258789062500, 0.0023803710937500, 0.0014038085937500, 0.0024414062500000, +0.0013122558593750, 0.0026550292968750, 0.0014953613281250, 0.0025024414062500, +0.0012207031250000, 0.0024719238281250, 0.0012817382812500, 0.0024719238281250, +0.0012817382812500, 0.0022277832031250, 0.0010986328125000, 0.0020751953125000, +0.0011901855468750, 0.0022888183593750, 0.0011596679687500, 0.0018310546875000, +0.0011291503906250, 0.0018615722656250, 0.0011291503906250, 0.0018615722656250, +0.0010986328125000, 0.0017395019531250, 0.0011901855468750, 0.0018615722656250, +0.0010986328125000, 0.0014343261718750, 0.0010681152343750, 0.0016784667968750, +0.0011596679687500, 0.0014038085937500, 0.0012512207031250, 0.0008239746093750, +0.0012817382812500, 0.0010681152343750, 0.0014038085937500, 0.0006713867187500, +0.0015258789062500, 0.0004272460937500, 0.0015258789062500, 0.0006103515625000, +0.0016784667968750, 0.0005187988281250, 0.0018310546875000, 0.0003967285156250, +0.0017395019531250, 0.0010375976562500, 0.0020141601562500, 0.0008850097656250, +0.0019226074218750, 0.0011291503906250, 0.0016784667968750, 0.0018615722656250, +0.0020141601562500, 0.0016174316406250, 0.0018920898437500, 0.0015563964843750, +0.0018615722656250, 0.0019226074218750, 0.0020446777343750, 0.0014953613281250, +0.0020446777343750, 0.0010070800781250, 0.0019836425781250, 0.0014343261718750, +0.0022277832031250, 0.0003356933593750, 0.0023193359375000, 0.0003662109375000, +0.0022888183593750, 0.0003662109375000, 0.0024719238281250, -0.0003662109375000, +0.0024719238281250, -0.0002441406250000, 0.0021667480468750, -0.0002136230468750, +0.0023498535156250, -0.0004272460937500, 0.0021057128906250, -0.0003051757812500, +0.0016174316406250, -0.0001220703125000, 0.0019226074218750, -0.0003662109375000, +0.0015258789062500, 0.0001220703125000, 0.0013122558593750, 0.0000915527343750, +0.0015869140625000, 0.0001525878906250, 0.0016174316406250, 0.0005187988281250, +0.0013122558593750, 0.0003662109375000, 0.0023193359375000, 0.0005493164062500, +0.0019836425781250, 0.0006103515625000, 0.0023193359375000, 0.0005798339843750, +0.0032653808593750, 0.0005798339843750, 0.0026855468750000, 0.0005493164062500, +0.0033874511718750, 0.0005798339843750, 0.0036621093750000, 0.0005798339843750, +0.0032043457031250, 0.0007019042968750, 0.0032958984375000, 0.0008239746093750, +0.0035705566406250, 0.0007934570312500, 0.0021667480468750, 0.0010681152343750, +0.0027160644531250, 0.0010375976562500, 0.0021972656250000, 0.0010986328125000, +0.0008544921875000, 0.0012512207031250, 0.0017089843750000, 0.0012512207031250, +0.0003967285156250, 0.0012207031250000, 0.0002746582031250, 0.0012207031250000, +0.0005798339843750, 0.0012512207031250, 0.0000305175781250, 0.0012817382812500, +0.0000610351562500, 0.0013427734375000, 0.0007019042968750, 0.0014648437500000, +0.0003356933593750, 0.0013732910156250, 0.0007629394531250, 0.0015563964843750, +0.0014648437500000, 0.0018615722656250, 0.0009460449218750, 0.0016174316406250, +0.0021362304687500, 0.0021667480468750, 0.0019836425781250, 0.0019836425781250, +0.0020751953125000, 0.0020446777343750, 0.0028686523437500, 0.0024108886718750, +0.0025024414062500, 0.0021362304687500, 0.0026550292968750, 0.0024108886718750, +0.0029296875000000, 0.0023803710937500, 0.0024414062500000, 0.0022888183593750, +0.0021972656250000, 0.0023193359375000, 0.0024719238281250, 0.0022277832031250, +0.0014953613281250, 0.0020751953125000, 0.0016479492187500, 0.0021362304687500, +0.0013732910156250, 0.0021057128906250, 0.0007019042968750, 0.0019836425781250, +0.0010986328125000, 0.0020446777343750, 0.0003662109375000, 0.0020446777343750, +0.0003356933593750, 0.0020141601562500, 0.0004272460937500, 0.0021057128906250, +0.0000305175781250, 0.0021362304687500, 0.0001220703125000, 0.0021057128906250, +0.0003356933593750, 0.0023193359375000, 0.0001525878906250, 0.0022583007812500, +0.0004272460937500, 0.0022888183593750, 0.0007629394531250, 0.0024108886718750, +0.0004577636718750, 0.0023498535156250, 0.0015258789062500, 0.0023803710937500, +0.0011901855468750, 0.0023193359375000, 0.0017395019531250, 0.0023193359375000, +0.0027160644531250, 0.0024108886718750, 0.0021362304687500, 0.0022583007812500, +0.0036926269531250, 0.0025329589843750, 0.0035095214843750, 0.0024108886718750, +0.0038757324218750, 0.0024414062500000, 0.0050048828125000, 0.0026245117187500, +0.0044250488281250, 0.0023803710937500, 0.0054016113281250, 0.0025939941406250, +0.0054321289062500, 0.0025024414062500, 0.0052795410156250, 0.0025329589843750, +0.0056762695312500, 0.0025939941406250, 0.0055847167968750, 0.0024414062500000, +0.0052490234375000, 0.0026550292968750, 0.0054931640625000, 0.0025634765625000, +0.0051269531250000, 0.0025939941406250, 0.0046997070312500, 0.0027465820312500, +0.0050354003906250, 0.0026550292968750, 0.0042724609375000, 0.0027770996093750, +0.0043640136718750, 0.0028686523437500, 0.0042419433593750, 0.0028076171875000, +0.0036621093750000, 0.0028076171875000, 0.0040283203125000, 0.0028381347656250, +0.0036010742187500, 0.0026855468750000, 0.0035705566406250, 0.0027465820312500, +0.0036315917968750, 0.0027160644531250, 0.0034790039062500, 0.0025634765625000, +0.0035705566406250, 0.0026245117187500, 0.0034790039062500, 0.0025329589843750, +0.0035095214843750, 0.0025634765625000, 0.0033264160156250, 0.0025634765625000, +0.0031738281250000, 0.0024414062500000, 0.0033874511718750, 0.0025024414062500, +0.0028686523437500, 0.0024414062500000, 0.0030212402343750, 0.0025024414062500, +0.0028686523437500, 0.0024108886718750, 0.0024414062500000, 0.0023498535156250, +0.0028076171875000, 0.0024414062500000, 0.0022277832031250, 0.0021972656250000, +0.0024108886718750, 0.0023803710937500, 0.0023193359375000, 0.0023498535156250, +0.0018920898437500, 0.0021667480468750, 0.0021972656250000, 0.0023498535156250, +0.0016784667968750, 0.0021972656250000, 0.0017395019531250, 0.0021667480468750, +0.0018005371093750, 0.0022888183593750, 0.0014953613281250, 0.0022888183593750, +0.0016174316406250, 0.0022583007812500, 0.0015563964843750, 0.0024719238281250, +0.0014648437500000, 0.0024108886718750, 0.0015258789062500, 0.0023803710937500, +0.0014343261718750, 0.0025634765625000, 0.0013122558593750, 0.0024414062500000, +0.0014953613281250, 0.0021972656250000, 0.0012207031250000, 0.0024108886718750, +0.0013122558593750, 0.0022277832031250, 0.0015869140625000, 0.0018615722656250, +0.0012207031250000, 0.0020446777343750, 0.0016174316406250, 0.0018005371093750, +0.0014648437500000, 0.0017395019531250, 0.0012817382812500, 0.0018005371093750, +0.0013732910156250, 0.0017395019531250, 0.0012512207031250, 0.0018005371093750, +0.0009155273437500, 0.0018615722656250, 0.0009765625000000, 0.0018310546875000, +0.0007934570312500, 0.0018310546875000, 0.0005493164062500, 0.0018615722656250, +0.0007019042968750, 0.0018615722656250, 0.0007934570312500, 0.0017395019531250, +0.0007934570312500, 0.0017089843750000, 0.0008850097656250, 0.0017395019531250, +0.0011596679687500, 0.0016784667968750, 0.0012207031250000, 0.0017395019531250, +0.0012207031250000, 0.0018920898437500, 0.0013122558593750, 0.0017700195312500, +0.0011291503906250, 0.0019226074218750, 0.0009155273437500, 0.0021972656250000, +0.0010070800781250, 0.0019836425781250, 0.0004577636718750, 0.0022583007812500, +0.0003662109375000, 0.0023498535156250, 0.0003662109375000, 0.0022583007812500, +0.0000915527343750, 0.0023193359375000, 0.0000610351562500, 0.0023803710937500, +0.0003356933593750, 0.0018615722656250, 0.0002136230468750, 0.0021057128906250, +0.0003967285156250}, +{0.0048522949218750, 0.0003967285156250, 0.0045166015625000, 0.0004272460937500, +0.0039367675781250, 0.0001831054687500, 0.0042724609375000, 0.0003051757812500, +0.0034790039062500, 0.0003051757812500, 0.0035400390625000, 0.0003356933593750, +0.0033874511718750, 0.0004577636718750, 0.0028686523437500, 0.0005493164062500, +0.0031738281250000, 0.0005493164062500, 0.0025634765625000, 0.0007324218750000, +0.0026855468750000, 0.0008239746093750, 0.0024719238281250, 0.0008239746093750, +0.0019531250000000, 0.0009155273437500, 0.0022583007812500, 0.0009765625000000, +0.0014953613281250, 0.0009460449218750, 0.0015869140625000, 0.0010681152343750, +0.0012512207031250, 0.0011291503906250, 0.0005798339843750, 0.0011291503906250, +0.0009765625000000, 0.0011901855468750, 0.0000610351562500, 0.0014343261718750, +0.0000305175781250, 0.0013732910156250, -0.0000610351562500, 0.0015869140625000, +-0.0005798339843750, 0.0017700195312500, -0.0004272460937500, 0.0017395019531250, +-0.0006408691406250, 0.0021972656250000, -0.0006408691406250, 0.0022277832031250, +-0.0007324218750000, 0.0024719238281250, -0.0008239746093750, 0.0028076171875000, +-0.0007934570312500, 0.0025939941406250, -0.0010070800781250, 0.0031738281250000, +-0.0010070800781250, 0.0030822753906250, -0.0010681152343750, 0.0030822753906250, +-0.0012207031250000, 0.0034179687500000, -0.0011291503906250, 0.0032043457031250, +-0.0012512207031250, 0.0032653808593750, -0.0012817382812500, 0.0032348632812500, +-0.0011596679687500, 0.0030822753906250, -0.0011291503906250, 0.0029907226562500, +-0.0011596679687500, 0.0029296875000000, -0.0009155273437500, 0.0026550292968750, +-0.0009155273437500, 0.0027160644531250, -0.0008850097656250, 0.0024108886718750, +-0.0007629394531250, 0.0021667480468750, -0.0007019042968750, 0.0024414062500000, +-0.0003662109375000, 0.0019226074218750, -0.0004272460937500, 0.0020141601562500, +-0.0001831054687500, 0.0019226074218750, 0.0001220703125000, 0.0015563964843750, +0.0000610351562500, 0.0018310546875000, 0.0005798339843750, 0.0017089843750000, +0.0005187988281250, 0.0016174316406250, 0.0009460449218750, 0.0019226074218750, +0.0014343261718750, 0.0021057128906250, 0.0011291503906250, 0.0020446777343750, +0.0021667480468750, 0.0023803710937500, 0.0019836425781250, 0.0025329589843750, +0.0022583007812500, 0.0025329589843750, 0.0031127929687500, 0.0025939941406250, +0.0026550292968750, 0.0026855468750000, 0.0032653808593750, 0.0025939941406250, +0.0033874511718750, 0.0027160644531250, 0.0030822753906250, 0.0025939941406250, +0.0031738281250000, 0.0023498535156250, 0.0033264160156250, 0.0025939941406250, +0.0027160644531250, 0.0021972656250000, 0.0028076171875000, 0.0022888183593750, +0.0026550292968750, 0.0022888183593750, 0.0019226074218750, 0.0020141601562500, +0.0016479492187500, 0.0019836425781250, 0.0013427734375000, 0.0018920898437500, +0.0014343261718750, 0.0018920898437500, 0.0014343261718750, 0.0017700195312500, +0.0012817382812500, 0.0016784667968750, 0.0014038085937500, 0.0016174316406250, +0.0013427734375000, 0.0014038085937500, 0.0012512207031250, 0.0012817382812500, +0.0012512207031250, 0.0011901855468750, 0.0013732910156250, 0.0010681152343750, +0.0013122558593750, 0.0010070800781250, 0.0014038085937500, 0.0008850097656250, +0.0015258789062500, 0.0007629394531250, 0.0013732910156250, 0.0007629394531250, +0.0014038085937500, 0.0007629394531250, 0.0015258789062500, 0.0007019042968750, +0.0010070800781250, 0.0009460449218750, 0.0010986328125000, 0.0008850097656250, +0.0010375976562500, 0.0010681152343750, 0.0006103515625000, 0.0013122558593750, +0.0007019042968750, 0.0010986328125000, 0.0007934570312500, 0.0016784667968750, +0.0006103515625000, 0.0015869140625000, 0.0005493164062500, 0.0016784667968750, +0.0005493164062500, 0.0019836425781250, 0.0004272460937500, 0.0018310546875000, +0.0003967285156250, 0.0020751953125000, 0.0001220703125000, 0.0021057128906250, +0.0003356933593750, 0.0020141601562500, 0.0005493164062500, 0.0020751953125000, +0.0001220703125000, 0.0021057128906250, 0.0009155273437500, 0.0019531250000000, +0.0007019042968750, 0.0019836425781250, 0.0007324218750000, 0.0018920898437500, +0.0012817382812500, 0.0017700195312500, 0.0009155273437500, 0.0018615722656250, +0.0012207031250000, 0.0015869140625000, 0.0011291503906250, 0.0015869140625000, +0.0010375976562500, 0.0015258789062500, 0.0010986328125000, 0.0013122558593750, +0.0009765625000000, 0.0013732910156250, 0.0010681152343750, 0.0013732910156250, +0.0010070800781250, 0.0012207031250000, 0.0009460449218750, 0.0013732910156250, +0.0009765625000000, 0.0015258789062500, 0.0009155273437500, 0.0014648437500000, +0.0010070800781250, 0.0017089843750000, 0.0008850097656250, 0.0017089843750000, +0.0009765625000000, 0.0017395019531250, 0.0012207031250000, 0.0019226074218750, +0.0010070800781250, 0.0019531250000000, 0.0014038085937500, 0.0018005371093750, +0.0013427734375000, 0.0018615722656250, 0.0013427734375000, 0.0018310546875000, +0.0015563964843750, 0.0016784667968750, 0.0015869140625000, 0.0018005371093750, +0.0015869140625000, 0.0015258789062500, 0.0016174316406250, 0.0015869140625000, +0.0015563964843750, 0.0015869140625000, 0.0014648437500000, 0.0014343261718750, +0.0014953613281250, 0.0014343261718750, 0.0014038085937500, 0.0014648437500000, +0.0014648437500000, 0.0014038085937500, 0.0013732910156250, 0.0014953613281250, +0.0012512207031250, 0.0016479492187500, 0.0012512207031250, 0.0014953613281250, +0.0014343261718750, 0.0018615722656250, 0.0013732910156250, 0.0017395019531250, +0.0013427734375000, 0.0018310546875000, 0.0015258789062500, 0.0021057128906250, +0.0014343261718750, 0.0019531250000000, 0.0013732910156250, 0.0021972656250000, +0.0014648437500000, 0.0022277832031250, 0.0013122558593750, 0.0021972656250000, +0.0011901855468750, 0.0023193359375000, 0.0013427734375000, 0.0022277832031250, +0.0009765625000000, 0.0022277832031250, 0.0010681152343750, 0.0022583007812500, +0.0009460449218750, 0.0021972656250000, 0.0007019042968750, 0.0021057128906250, +0.0009155273437500, 0.0022277832031250, 0.0006103515625000, 0.0020141601562500, +0.0005798339843750, 0.0020751953125000, 0.0006103515625000, 0.0020141601562500, +0.0004882812500000, 0.0018615722656250, 0.0005798339843750, 0.0019531250000000, +0.0005493164062500, 0.0018615722656250, 0.0005798339843750, 0.0017700195312500, +0.0006408691406250, 0.0018615722656250, 0.0006713867187500, 0.0018310546875000, +0.0006408691406250, 0.0018310546875000, 0.0008544921875000, 0.0020446777343750, +0.0008239746093750, 0.0019531250000000, 0.0009460449218750, 0.0021362304687500, +0.0011596679687500, 0.0024414062500000, 0.0010375976562500, 0.0022583007812500, +0.0013732910156250, 0.0029296875000000, 0.0013427734375000, 0.0028381347656250, +0.0013427734375000, 0.0030517578125000, 0.0015869140625000, 0.0035400390625000, +0.0014648437500000, 0.0033569335937500, 0.0014953613281250, 0.0037841796875000, +0.0015258789062500, 0.0039062500000000, 0.0014648437500000, 0.0037841796875000, +0.0013427734375000, 0.0039672851562500, 0.0014038085937500, 0.0040588378906250, +0.0012817382812500, 0.0033874511718750, 0.0012207031250000, 0.0036315917968750, +0.0012817382812500, 0.0032653808593750, 0.0012817382812500, 0.0025024414062500, +0.0012817382812500, 0.0028686523437500, 0.0014343261718750, 0.0019836425781250, +0.0013732910156250, 0.0020446777343750, 0.0015869140625000, 0.0017089843750000, +0.0018310546875000, 0.0010986328125000, 0.0016174316406250, 0.0014648437500000, +0.0021667480468750, 0.0005798339843750, 0.0021362304687500, 0.0006103515625000, +0.0022277832031250, 0.0005187988281250, 0.0026245117187500, 0.0000000000000000, +0.0024108886718750, 0.0001831054687500, 0.0025329589843750, 0.0001220703125000, +0.0027465820312500, 0.0000000000000000, 0.0024414062500000, 0.0002746582031250, +0.0022888183593750, 0.0004272460937500, 0.0025024414062500, 0.0002441406250000, +0.0017700195312500, 0.0008239746093750, 0.0019226074218750, 0.0007629394531250, +0.0018005371093750, 0.0008544921875000, 0.0012207031250000, 0.0012512207031250, +0.0014648437500000, 0.0010681152343750, 0.0012512207031250, 0.0009765625000000, +0.0010681152343750, 0.0011291503906250, 0.0013122558593750, 0.0008544921875000, +0.0014038085937500, 0.0005493164062500, 0.0011596679687500, 0.0007629394531250, +0.0016784667968750, 0.0002441406250000, 0.0015869140625000, 0.0001831054687500, +0.0016479492187500, 0.0002746582031250, 0.0020141601562500, 0.0001220703125000, +0.0018005371093750, 0.0000305175781250, 0.0020446777343750, 0.0002746582031250, +0.0021057128906250, 0.0001831054687500, 0.0021362304687500, 0.0002136230468750, +0.0022277832031250, 0.0003662109375000, 0.0021362304687500, 0.0001831054687500, +0.0024108886718750, 0.0002746582031250, 0.0023498535156250, 0.0002746582031250, +0.0024108886718750, 0.0000610351562500, 0.0026245117187500, -0.0000915527343750, +0.0025329589843750, -0.0001220703125000, 0.0026245117187500, -0.0002136230468750, +0.0027160644531250, -0.0003356933593750, 0.0025939941406250, -0.0003356933593750, +0.0025634765625000, -0.0004577636718750, 0.0027465820312500, -0.0005187988281250, +0.0024414062500000, -0.0003356933593750, 0.0026550292968750, -0.0006408691406250, +0.0025634765625000, -0.0002746582031250, 0.0022888183593750, 0.0000915527343750, +0.0025329589843750, -0.0003662109375000, 0.0020751953125000, 0.0005493164062500, +0.0022277832031250, 0.0003967285156250, 0.0021057128906250, 0.0005493164062500, +0.0017700195312500, 0.0011901855468750, 0.0020141601562500, 0.0007019042968750, +0.0016174316406250, 0.0015563964843750, 0.0016174316406250, 0.0015869140625000, +0.0015258789062500, 0.0015563964843750, 0.0013122558593750, 0.0019836425781250, +0.0013732910156250, 0.0018005371093750, 0.0011901855468750, 0.0018005371093750, +0.0011291503906250, 0.0018310546875000, 0.0011596679687500, 0.0018310546875000, +0.0011291503906250, 0.0017395019531250, 0.0010681152343750, 0.0017700195312500, +0.0012207031250000, 0.0017395019531250, 0.0011901855468750, 0.0016479492187500, +0.0012512207031250, 0.0017395019531250, 0.0013732910156250, 0.0018005371093750, +0.0009460449218750, 0.0011291503906250, 0.0013122558593750, 0.0019836425781250, +0.0010681152343750, 0.0019531250000000, 0.0012207031250000, 0.0019226074218750, +0.0014953613281250, 0.0021972656250000, 0.0013427734375000, 0.0021362304687500, +0.0017089843750000, 0.0018310546875000, 0.0017089843750000, 0.0020141601562500, +0.0017395019531250, 0.0017700195312500, 0.0019226074218750, 0.0013122558593750, +0.0018920898437500, 0.0017089843750000, 0.0018005371093750, 0.0011596679687500, +0.0019531250000000, 0.0012207031250000, 0.0018920898437500, 0.0012512207031250, +0.0018310546875000, 0.0010375976562500, 0.0019836425781250, 0.0011291503906250, +0.0018615722656250, 0.0012817382812500, 0.0019836425781250, 0.0012512207031250, +0.0019226074218750, 0.0012817382812500, 0.0018920898437500, 0.0014648437500000, +0.0020446777343750, 0.0014648437500000, 0.0016479492187500, 0.0016479492187500, +0.0017089843750000, 0.0015563964843750, 0.0016479492187500, 0.0016174316406250, +0.0013122558593750, 0.0018920898437500, 0.0015258789062500, 0.0018615722656250, +0.0013122558593750, 0.0018920898437500, 0.0013122558593750, 0.0020141601562500, +0.0013427734375000, 0.0019531250000000, 0.0013732910156250, 0.0018920898437500, +0.0014038085937500}, +{0.0019531250000000, 0.0011596679687500, 0.0020751953125000, 0.0007629394531250, +0.0018920898437500, 0.0018310546875000, 0.0020446777343750, 0.0018005371093750, +0.0019226074218750, 0.0018920898437500, 0.0016479492187500, 0.0025634765625000, +0.0018920898437500, 0.0023803710937500, 0.0014038085937500, 0.0024719238281250, +0.0014953613281250, 0.0027160644531250, 0.0014343261718750, 0.0025024414062500, +0.0011291503906250, 0.0022888183593750, 0.0013427734375000, 0.0025024414062500, +0.0012207031250000, 0.0019226074218750, 0.0012207031250000, 0.0020751953125000, +0.0013732910156250, 0.0019531250000000, 0.0014648437500000, 0.0015869140625000, +0.0014038085937500, 0.0018005371093750, 0.0017700195312500, 0.0016174316406250, +0.0017089843750000, 0.0014648437500000, 0.0018005371093750, 0.0015563964843750, +0.0020141601562500, 0.0015258789062500, 0.0018920898437500, 0.0014648437500000, +0.0021362304687500, 0.0014953613281250, 0.0021057128906250, 0.0014343261718750, +0.0020446777343750, 0.0012817382812500, 0.0022277832031250, 0.0011596679687500, +0.0021057128906250, 0.0011596679687500, 0.0020751953125000, 0.0006713867187500, +0.0021667480468750, 0.0007934570312500, 0.0020751953125000, 0.0006408691406250, +0.0019226074218750, 0.0002136230468750, 0.0020446777343750, 0.0003662109375000, +0.0018615722656250, 0.0000305175781250, 0.0018615722656250, 0.0000000000000000, +0.0018310546875000, -0.0000610351562500, 0.0017700195312500, -0.0003051757812500, +0.0018920898437500, -0.0002746582031250, 0.0016174316406250, -0.0002136230468750, +0.0017700195312500, -0.0003662109375000, 0.0015869140625000, -0.0001831054687500, +0.0013122558593750, 0.0000305175781250, 0.0015869140625000, -0.0001220703125000, +0.0010375976562500, 0.0002441406250000, 0.0011291503906250, 0.0002746582031250, +0.0011596679687500, 0.0002746582031250, 0.0008544921875000, 0.0004272460937500, +0.0010681152343750, 0.0003662109375000, 0.0009460449218750, 0.0007324218750000, +0.0008850097656250, 0.0005798339843750, 0.0009460449218750, 0.0008239746093750, +0.0010070800781250, 0.0016479492187500, 0.0016174316406250, -0.0008544921875000, +0.0016479492187500, -0.0004272460937500, 0.0018615722656250, -0.0009765625000000, +0.0017089843750000, -0.0002746582031250, 0.0015869140625000, 0.0004272460937500, +0.0017395019531250, -0.0001220703125000, 0.0013732910156250, 0.0013122558593750, +0.0014648437500000, 0.0010986328125000, 0.0013122558593750, 0.0013732910156250, +0.0009765625000000, 0.0024414062500000, 0.0012512207031250, 0.0019226074218750, +0.0008239746093750, 0.0026855468750000, 0.0009460449218750, 0.0028686523437500, +0.0008544921875000, 0.0026855468750000, 0.0005798339843750, 0.0028686523437500, +0.0008544921875000, 0.0029602050781250, 0.0003662109375000, 0.0026245117187500, +0.0004882812500000, 0.0025634765625000, 0.0005187988281250, 0.0024414062500000, +0.0001831054687500, 0.0022277832031250, 0.0004577636718750, 0.0021972656250000, +0.0004577636718750, 0.0021057128906250, 0.0004272460937500, 0.0019226074218750, +0.0005798339843750, 0.0020141601562500, 0.0007934570312500, 0.0020141601562500, +0.0008544921875000, 0.0018005371093750, 0.0008239746093750, 0.0021362304687500, +0.0009460449218750, 0.0021362304687500, 0.0008850097656250, 0.0020751953125000, +0.0007019042968750, 0.0022583007812500, 0.0008850097656250, 0.0021667480468750, +0.0005798339843750, 0.0021057128906250, 0.0005493164062500, 0.0021057128906250, +0.0007019042968750, 0.0019531250000000, 0.0005493164062500, 0.0018310546875000, +0.0005493164062500, 0.0019531250000000, 0.0012817382812500, 0.0013732910156250, +0.0010375976562500, 0.0014648437500000, 0.0014648437500000, 0.0013427734375000, +0.0022888183593750, 0.0009155273437500, 0.0018920898437500, 0.0011291503906250, +0.0027160644531250, 0.0004272460937500, 0.0028686523437500, 0.0005493164062500, +0.0026550292968750, 0.0003662109375000, 0.0028991699218750, -0.0001220703125000, +0.0029602050781250, 0.0000305175781250, 0.0022277832031250, -0.0003051757812500, +0.0024414062500000, -0.0004272460937500, 0.0020446777343750, -0.0002136230468750, +0.0012817382812500, -0.0002136230468750, 0.0016479492187500, -0.0003356933593750, +0.0008239746093750, 0.0001525878906250, 0.0006408691406250, 0.0002136230468750, +0.0007629394531250, 0.0001525878906250, 0.0003662109375000, 0.0003967285156250, +0.0002746582031250, 0.0004272460937500, 0.0010986328125000, 0.0002441406250000, +0.0006103515625000, 0.0003356933593750, 0.0010681152343750, 0.0002746582031250, +0.0020751953125000, 0.0000000000000000, 0.0013122558593750, 0.0000305175781250, +0.0027160644531250, -0.0000610351562500, 0.0025939941406250, -0.0002441406250000, +0.0025634765625000, -0.0001525878906250, 0.0032958984375000, -0.0001220703125000, +0.0029602050781250, -0.0004272460937500, 0.0025634765625000, 0.0000610351562500, +0.0029296875000000, -0.0002746582031250, 0.0022277832031250, -0.0000915527343750, +0.0014343261718750, 0.0004577636718750, 0.0019531250000000, -0.0000610351562500, +0.0006103515625000, 0.0008239746093750, 0.0005187988281250, 0.0005187988281250, +0.0004882812500000, 0.0006408691406250, -0.0002136230468750, 0.0013122558593750, +-0.0000305175781250, 0.0007324218750000, 0.0001525878906250, 0.0014038085937500, +-0.0001831054687500, 0.0012512207031250, 0.0003967285156250, 0.0013122558593750, +0.0009765625000000, 0.0017089843750000, 0.0004272460937500, 0.0014038085937500, +0.0022277832031250, 0.0018615722656250, 0.0018310546875000, 0.0017700195312500, +0.0023803710937500, 0.0018310546875000, 0.0037841796875000, 0.0021057128906250, +0.0029907226562500, 0.0018615722656250, 0.0043334960937500, 0.0024108886718750, +0.0043640136718750, 0.0021972656250000, 0.0042724609375000, 0.0023498535156250, +0.0047912597656250, 0.0027160644531250, 0.0045776367187500, 0.0023803710937500, +0.0043945312500000, 0.0028076171875000, 0.0045471191406250, 0.0028076171875000, +0.0042114257812500, 0.0027770996093750, 0.0038146972656250, 0.0029907226562500, +0.0040283203125000, 0.0027160644531250, 0.0031127929687500, 0.0029296875000000, +0.0032653808593750, 0.0028991699218750, 0.0028991699218750, 0.0028686523437500, +0.0021057128906250, 0.0029907226562500, 0.0025634765625000, 0.0028686523437500, +0.0013732910156250, 0.0030212402343750, 0.0015258789062500, 0.0029907226562500, +0.0012512207031250, 0.0029602050781250, 0.0003967285156250, 0.0030822753906250, +0.0007934570312500, 0.0029907226562500, 0.0001220703125000, 0.0029296875000000, +-0.0000305175781250, 0.0029296875000000, 0.0001220703125000, 0.0029296875000000, +-0.0000610351562500, 0.0028381347656250, -0.0001525878906250, 0.0027465820312500, +0.0002441406250000, 0.0027465820312500, 0.0000610351562500, 0.0027160644531250, +0.0003051757812500, 0.0026855468750000, 0.0006713867187500, 0.0026245117187500, +0.0003662109375000, 0.0025939941406250, 0.0008544921875000, 0.0025024414062500, +0.0008544921875000, 0.0025634765625000, 0.0008239746093750, 0.0025939941406250, +0.0010375976562500, 0.0024719238281250, 0.0008544921875000, 0.0025024414062500, +0.0007934570312500, 0.0024719238281250, 0.0008239746093750, 0.0024108886718750, +0.0007629394531250, 0.0023498535156250, 0.0006103515625000, 0.0023193359375000, +0.0007324218750000, 0.0022583007812500, 0.0006713867187500, 0.0021972656250000, +0.0005798339843750, 0.0021667480468750, 0.0007629394531250, 0.0021972656250000, +0.0008544921875000, 0.0021972656250000, 0.0007019042968750, 0.0021057128906250, +0.0012817382812500, 0.0022583007812500, 0.0011291503906250, 0.0021972656250000, +0.0012817382812500, 0.0022583007812500, 0.0016784667968750, 0.0023193359375000, +0.0014648437500000, 0.0021667480468750, 0.0015258789062500, 0.0023803710937500, +0.0016174316406250, 0.0022583007812500, 0.0015258789062500, 0.0022583007812500, +0.0014343261718750, 0.0023498535156250, 0.0014648437500000, 0.0021667480468750, +0.0014343261718750, 0.0022583007812500, 0.0013122558593750, 0.0021667480468750, +0.0014038085937500, 0.0020141601562500, 0.0015258789062500, 0.0019531250000000, +0.0013427734375000, 0.0018615722656250, 0.0018005371093750, 0.0015563964843750, +0.0016784667968750, 0.0016479492187500, 0.0017395019531250, 0.0014038085937500, +0.0021057128906250, 0.0010986328125000, 0.0018920898437500, 0.0012817382812500, +0.0020141601562500, 0.0010070800781250, 0.0021057128906250, 0.0010070800781250, +0.0019836425781250, 0.0010681152343750, 0.0019836425781250, 0.0010070800781250, +0.0020141601562500, 0.0010375976562500, 0.0018920898437500, 0.0011901855468750, +0.0019226074218750, 0.0011596679687500, 0.0019531250000000, 0.0013732910156250, +0.0019226074218750, 0.0014953613281250, 0.0019226074218750, 0.0014343261718750, +0.0018615722656250, 0.0016784667968750, 0.0019531250000000, 0.0017089843750000, +0.0017700195312500, 0.0017395019531250, 0.0016784667968750, 0.0018920898437500, +0.0018005371093750, 0.0018310546875000, 0.0011291503906250, 0.0018310546875000, +0.0012817382812500, 0.0018615722656250, 0.0010986328125000, 0.0017700195312500, +0.0005187988281250, 0.0016784667968750, 0.0007324218750000, 0.0017700195312500, +0.0004577636718750, 0.0014953613281250, 0.0002746582031250, 0.0014648437500000, +0.0003051757812500, 0.0013732910156250, 0.0003051757812500, 0.0011901855468750, +0.0002136230468750, 0.0012207031250000, 0.0003967285156250, 0.0010070800781250, +0.0002441406250000, 0.0010070800781250, 0.0004272460937500, 0.0009155273437500, +0.0006713867187500, 0.0006713867187500, 0.0005187988281250, 0.0006408691406250, +0.0015258789062500, 0.0005798339843750, 0.0010986328125000, 0.0005798339843750, +0.0013122558593750, 0.0006103515625000, 0.0021972656250000, 0.0005798339843750, +0.0018310546875000, 0.0005493164062500, 0.0025939941406250, 0.0006103515625000, +0.0027465820312500, 0.0005493164062500, 0.0028076171875000, 0.0006103515625000, +0.0031433105468750, 0.0007324218750000, 0.0030822753906250, 0.0005798339843750, +0.0030517578125000, 0.0010070800781250, 0.0030822753906250, 0.0009155273437500, +0.0028991699218750, 0.0010070800781250, 0.0026855468750000, 0.0013122558593750, +0.0027770996093750, 0.0010375976562500, 0.0025329589843750, 0.0014343261718750, +0.0027160644531250, 0.0013732910156250, 0.0026245117187500, 0.0013427734375000, +0.0023803710937500, 0.0014648437500000, 0.0027160644531250, 0.0012817382812500, +0.0019531250000000, 0.0015563964843750, 0.0022277832031250, 0.0015258789062500, +0.0018920898437500, 0.0014343261718750, 0.0013122558593750, 0.0015869140625000, +0.0018005371093750, 0.0015563964843750, 0.0010986328125000, 0.0015869140625000, +0.0011291503906250, 0.0015258789062500, 0.0011596679687500, 0.0016174316406250, +0.0007324218750000, 0.0017700195312500, 0.0009460449218750, 0.0016479492187500, +0.0007934570312500, 0.0020446777343750, 0.0006713867187500, 0.0019226074218750, +0.0007934570312500, 0.0021362304687500, 0.0008544921875000, 0.0025024414062500, +0.0007019042968750, 0.0023193359375000, 0.0007019042968750, 0.0026245117187500, +0.0008239746093750, 0.0028686523437500, 0.0005187988281250, 0.0027770996093750, +0.0003967285156250, 0.0028076171875000, 0.0005493164062500, 0.0028686523437500, +-0.0000305175781250, 0.0026855468750000, 0.0001220703125000, 0.0027160644531250, +-0.0000305175781250, 0.0026855468750000, -0.0003967285156250, 0.0024719238281250, +-0.0001220703125000, 0.0025329589843750, -0.0005187988281250, 0.0023498535156250, +-0.0004577636718750}, +{0.0018310546875000, 0.0020141601562500, 0.0017089843750000, 0.0018920898437500, +0.0017700195312500, 0.0021057128906250, 0.0016174316406250, 0.0025634765625000, +0.0015563964843750, 0.0021972656250000, 0.0018920898437500, 0.0027160644531250, +0.0018005371093750, 0.0026855468750000, 0.0018310546875000, 0.0025024414062500, +0.0021362304687500, 0.0027160644531250, 0.0020446777343750, 0.0026855468750000, +0.0021972656250000, 0.0024108886718750, 0.0023498535156250, 0.0025329589843750, +0.0023193359375000, 0.0023803710937500, 0.0022888183593750, 0.0021057128906250, +0.0024414062500000, 0.0022277832031250, 0.0023803710937500, 0.0018920898437500, +0.0023803710937500, 0.0019836425781250, 0.0025329589843750, 0.0018310546875000, +0.0025939941406250, 0.0015258789062500, 0.0025634765625000, 0.0017395019531250, +0.0026245117187500, 0.0012207031250000, 0.0027770996093750, 0.0013122558593750, +0.0027160644531250, 0.0013122558593750, 0.0025329589843750, 0.0009765625000000, +0.0028076171875000, 0.0011901855468750, 0.0025634765625000, 0.0010375976562500, +0.0025024414062500, 0.0011596679687500, 0.0024414062500000, 0.0011596679687500, +0.0022277832031250, 0.0011291503906250, 0.0021362304687500, 0.0012512207031250, +0.0016784667968750, 0.0011291503906250, 0.0017395019531250, 0.0011901855468750, +0.0013427734375000, 0.0012207031250000, 0.0005187988281250, 0.0011291503906250, +0.0002136230468750, 0.0010681152343750, -0.0004882812500000, 0.0009765625000000, +-0.0004577636718750, 0.0010070800781250, -0.0003967285156250, 0.0010070800781250, +-0.0009155273437500, 0.0009460449218750, -0.0008239746093750, 0.0009155273437500, +-0.0006408691406250, 0.0010986328125000, -0.0006103515625000, 0.0010375976562500, +-0.0003662109375000, 0.0011596679687500, -0.0001525878906250, 0.0012817382812500, +-0.0000610351562500, 0.0011596679687500, 0.0005493164062500, 0.0014648437500000, +0.0004882812500000, 0.0013427734375000, 0.0008544921875000, 0.0013427734375000, +0.0014343261718750, 0.0015258789062500, 0.0011901855468750, 0.0012207031250000, +0.0016784667968750, 0.0016479492187500, 0.0018005371093750, 0.0015869140625000, +0.0016784667968750, 0.0016174316406250, 0.0017700195312500, 0.0018005371093750, +0.0017089843750000, 0.0016479492187500, 0.0014648437500000, 0.0018920898437500, +0.0014648437500000, 0.0018310546875000, 0.0013427734375000, 0.0018615722656250, +0.0010681152343750, 0.0019531250000000, 0.0010375976562500, 0.0018005371093750, +0.0008850097656250, 0.0022583007812500, 0.0008850097656250, 0.0021667480468750, +0.0007629394531250, 0.0022888183593750, 0.0005798339843750, 0.0026550292968750, +0.0006713867187500, 0.0025329589843750, 0.0003356933593750, 0.0028686523437500, +0.0003356933593750, 0.0029907226562500, 0.0003662109375000, 0.0029296875000000, +0.0002441406250000, 0.0031127929687500, 0.0002136230468750, 0.0032043457031250, +0.0003051757812500, 0.0028991699218750, 0.0003051757812500, 0.0030212402343750, +0.0002746582031250, 0.0029907226562500, 0.0003967285156250, 0.0027770996093750, +0.0004882812500000, 0.0029296875000000, 0.0003967285156250, 0.0027770996093750, +0.0004577636718750, 0.0027465820312500, 0.0005798339843750, 0.0028991699218750, +0.0006713867187500, 0.0029602050781250, 0.0007019042968750, 0.0029296875000000, +0.0011291503906250, 0.0031433105468750, 0.0010375976562500, 0.0030822753906250, +0.0013122558593750, 0.0032348632812500, 0.0017089843750000, 0.0034484863281250, +0.0014648437500000, 0.0033569335937500, 0.0021362304687500, 0.0037231445312500, +0.0020141601562500, 0.0036315917968750, 0.0020446777343750, 0.0037231445312500, +0.0024719238281250, 0.0040283203125000, 0.0022583007812500, 0.0038452148437500, +0.0023193359375000, 0.0040588378906250, 0.0023803710937500, 0.0040283203125000, +0.0021362304687500, 0.0040588378906250, 0.0020141601562500, 0.0041503906250000, +0.0021057128906250, 0.0039978027343750, 0.0019226074218750, 0.0042724609375000, +0.0018005371093750, 0.0041809082031250, 0.0018920898437500, 0.0042724609375000, +0.0018615722656250, 0.0045166015625000, 0.0017700195312500, 0.0043334960937500, +0.0020141601562500, 0.0045776367187500, 0.0018615722656250, 0.0046691894531250, +0.0017700195312500, 0.0045166015625000, 0.0019226074218750, 0.0045776367187500, +0.0018005371093750, 0.0046691894531250, 0.0017395019531250, 0.0042724609375000, +0.0017089843750000, 0.0045166015625000, 0.0016174316406250, 0.0043334960937500, +0.0015563964843750, 0.0039062500000000, 0.0015563964843750, 0.0042419433593750, +0.0014343261718750, 0.0036621093750000, 0.0014038085937500, 0.0037841796875000, +0.0014343261718750, 0.0036315917968750, 0.0013427734375000, 0.0032043457031250, +0.0012207031250000, 0.0034790039062500, 0.0014038085937500, 0.0026855468750000, +0.0012817382812500, 0.0028686523437500, 0.0013732910156250, 0.0024719238281250, +0.0015258789062500, 0.0017395019531250, 0.0013427734375000, 0.0021667480468750, +0.0018005371093750, 0.0010375976562500, 0.0017700195312500, 0.0009765625000000, +0.0018005371093750, 0.0007629394531250, 0.0020446777343750, 0.0000610351562500, +0.0019531250000000, 0.0002136230468750, 0.0018920898437500, 0.0000305175781250, +0.0019531250000000, -0.0002136230468750, 0.0018310546875000, 0.0000305175781250, +0.0017089843750000, 0.0001220703125000, 0.0017089843750000, -0.0000610351562500, +0.0016174316406250, 0.0006713867187500, 0.0015869140625000, 0.0004272460937500, +0.0016174316406250, 0.0007019042968750, 0.0015869140625000, 0.0012817382812500, +0.0015563964843750, 0.0008850097656250, 0.0018005371093750, 0.0017089843750000, +0.0016784667968750, 0.0015869140625000, 0.0017395019531250, 0.0017395019531250, +0.0020446777343750, 0.0023193359375000, 0.0018310546875000, 0.0020141601562500, +0.0021057128906250, 0.0025634765625000, 0.0021057128906250, 0.0024414062500000, +0.0020446777343750, 0.0026550292968750, 0.0021972656250000, 0.0030517578125000, +0.0021972656250000, 0.0027465820312500, 0.0021057128906250, 0.0034484863281250, +0.0021362304687500, 0.0034790039062500, 0.0021362304687500, 0.0034484863281250, +0.0020141601562500, 0.0038146972656250, 0.0020446777343750, 0.0037536621093750, +0.0020751953125000, 0.0035095214843750, 0.0020141601562500, 0.0036621093750000, +0.0020751953125000, 0.0034790039062500, 0.0021362304687500, 0.0031433105468750, +0.0020751953125000, 0.0033264160156250, 0.0021667480468750, 0.0028991699218750, +0.0021972656250000, 0.0028991699218750, 0.0021057128906250, 0.0028991699218750, +0.0020446777343750, 0.0025939941406250, 0.0020446777343750, 0.0027160644531250, +0.0018920898437500, 0.0023803710937500, 0.0018615722656250, 0.0024108886718750, +0.0018005371093750, 0.0023193359375000, 0.0016784667968750, 0.0020141601562500, +0.0016174316406250, 0.0020751953125000, 0.0016784667968750, 0.0015563964843750, +0.0014648437500000, 0.0015563964843750, 0.0015258789062500, 0.0013732910156250, +0.0016479492187500, 0.0009765625000000, 0.0014343261718750, 0.0011596679687500, +0.0016174316406250, 0.0009460449218750, 0.0014953613281250, 0.0008239746093750, +0.0015563964843750, 0.0011291503906250, 0.0016784667968750, 0.0012207031250000, +0.0014648437500000, 0.0011596679687500, 0.0018615722656250, 0.0017089843750000, +0.0017700195312500, 0.0018005371093750, 0.0018005371093750, 0.0018310546875000, +0.0020751953125000, 0.0021667480468750, 0.0019226074218750, 0.0021667480468750, +0.0019531250000000, 0.0019531250000000, 0.0020751953125000, 0.0022888183593750, +0.0018615722656250, 0.0018920898437500, 0.0017089843750000, 0.0013732910156250, +0.0017700195312500, 0.0017700195312500, 0.0013427734375000, 0.0008239746093750, +0.0014038085937500, 0.0009155273437500, 0.0012512207031250, 0.0007934570312500, +0.0009460449218750, 0.0002136230468750, 0.0010375976562500, 0.0005798339843750, +0.0005798339843750, 0.0003051757812500, 0.0005493164062500, 0.0002441406250000, +0.0004272460937500, 0.0003051757812500, 0.0001220703125000, 0.0002136230468750, +0.0003051757812500, 0.0002136230468750, 0.0002441406250000, -0.0000305175781250, +0.0000915527343750, 0.0000915527343750, 0.0002441406250000, 0.0000305175781250, +0.0003356933593750, -0.0002136230468750, 0.0002441406250000, -0.0000305175781250, +0.0007324218750000, 0.0000610351562500, 0.0005493164062500, 0.0000305175781250, +0.0008544921875000, 0.0002136230468750, 0.0013122558593750, 0.0002746582031250, +0.0009765625000000, 0.0001525878906250, 0.0018615722656250, 0.0007934570312500, +0.0017700195312500, 0.0005187988281250, 0.0018615722656250, 0.0008850097656250, +0.0025024414062500, 0.0015869140625000, 0.0021972656250000, 0.0010070800781250, +0.0023498535156250, 0.0017395019531250, 0.0025329589843750, 0.0018310546875000, +0.0023498535156250, 0.0015258789062500, 0.0021057128906250, 0.0014953613281250, +0.0016174316406250, -0.0000610351562500, 0.0015869140625000, 0.0007019042968750, +0.0015869140625000, 0.0004882812500000, 0.0016174316406250, 0.0005798339843750, +0.0016784667968750, 0.0010070800781250, 0.0017089843750000, 0.0008850097656250, +0.0017395019531250, 0.0007629394531250, 0.0017395019531250, 0.0010070800781250, +0.0018310546875000, 0.0007629394531250, 0.0019226074218750, 0.0003967285156250, +0.0019226074218750, 0.0007934570312500, 0.0019531250000000, -0.0000305175781250, +0.0021057128906250, -0.0000305175781250, 0.0020446777343750, -0.0000305175781250, +0.0019836425781250, -0.0004272460937500, 0.0021362304687500, -0.0003662109375000, +0.0016784667968750, 0.0000000000000000, 0.0018615722656250, -0.0001831054687500, +0.0016174316406250, 0.0000915527343750, 0.0011596679687500, 0.0005187988281250, +0.0014648437500000, 0.0003051757812500, 0.0010375976562500, 0.0013122558593750, +0.0008850097656250, 0.0011291503906250, 0.0011291503906250, 0.0014343261718750, +0.0010986328125000, 0.0022583007812500, 0.0010375976562500, 0.0018310546875000, +0.0016479492187500, 0.0023193359375000, 0.0014953613281250, 0.0025024414062500, +0.0018310546875000, 0.0022277832031250, 0.0024414062500000, 0.0021972656250000, +0.0020751953125000, 0.0021667480468750, 0.0026855468750000, 0.0018920898437500, +0.0027160644531250, 0.0017395019531250, 0.0025634765625000, 0.0016784667968750, +0.0027770996093750, 0.0014953613281250, 0.0026550292968750, 0.0013732910156250, +0.0024719238281250, 0.0012512207031250, 0.0025329589843750, 0.0012817382812500, +0.0024108886718750, 0.0011901855468750, 0.0022277832031250, 0.0010681152343750, +0.0023498535156250, 0.0011901855468750, 0.0023498535156250, 0.0011596679687500, +0.0021972656250000, 0.0011291503906250, 0.0025939941406250, 0.0013732910156250, +0.0029602050781250, 0.0015258789062500, 0.0026855468750000, 0.0014343261718750, +0.0036621093750000, 0.0018615722656250, 0.0035705566406250, 0.0018920898437500, +0.0037536621093750, 0.0018920898437500, 0.0044555664062500, 0.0021362304687500, +0.0042114257812500, 0.0020751953125000, 0.0043945312500000, 0.0017089843750000, +0.0046997070312500, 0.0019226074218750, 0.0042114257812500, 0.0016784667968750, +0.0038757324218750, 0.0012207031250000, 0.0043029785156250, 0.0014648437500000, +0.0028991699218750, 0.0009765625000000, 0.0032348632812500, 0.0010070800781250, +0.0028381347656250, 0.0010986328125000, 0.0017089843750000, 0.0009765625000000, +0.0024108886718750, 0.0011291503906250, 0.0015258789062500, 0.0011901855468750, +0.0014038085937500, 0.0012817382812500, 0.0017395019531250, 0.0013732910156250, +0.0015258789062500}, +{0.0012817382812500, 0.0010070800781250, 0.0013732910156250, 0.0008544921875000, +0.0011596679687500, 0.0008850097656250, 0.0015258789062500, 0.0004272460937500, +0.0014038085937500, 0.0005187988281250, 0.0014953613281250, 0.0003051757812500, +0.0017700195312500, -0.0001220703125000, 0.0015563964843750, 0.0000000000000000, +0.0018615722656250, -0.0003356933593750, 0.0018920898437500, -0.0004272460937500, +0.0017700195312500, -0.0003356933593750, 0.0018005371093750, -0.0003967285156250, +0.0018615722656250, -0.0004882812500000, 0.0016479492187500, -0.0001525878906250, +0.0017089843750000, -0.0003051757812500, 0.0017089843750000, -0.0002136230468750, +0.0014953613281250, 0.0003356933593750, 0.0013122558593750, 0.0001831054687500, +0.0015869140625000, -0.0009460449218750, 0.0015258789062500, -0.0006408691406250, +0.0017700195312500, -0.0006408691406250, 0.0020751953125000, -0.0010375976562500, +0.0019836425781250, -0.0008850097656250, 0.0025024414062500, -0.0002136230468750, +0.0024414062500000, -0.0004272460937500, 0.0024719238281250, -0.0000610351562500, +0.0027770996093750, 0.0005493164062500, 0.0026550292968750, 0.0002746582031250, +0.0026855468750000, 0.0008544921875000, 0.0027465820312500, 0.0009765625000000, +0.0025329589843750, 0.0008850097656250, 0.0024108886718750, 0.0010681152343750, +0.0024108886718750, 0.0011901855468750, 0.0022888183593750, 0.0008850097656250, +0.0020141601562500, 0.0009765625000000, 0.0022583007812500, 0.0008239746093750, +0.0024719238281250, 0.0005798339843750, 0.0021057128906250, 0.0007934570312500, +0.0028686523437500, 0.0004577636718750, 0.0027465820312500, 0.0003356933593750, +0.0027770996093750, 0.0007019042968750, 0.0032653808593750, 0.0006408691406250, +0.0030517578125000, 0.0004272460937500, 0.0031433105468750, 0.0013732910156250, +0.0031433105468750, 0.0010375976562500, 0.0029296875000000, 0.0014038085937500, +0.0028381347656250, 0.0021972656250000, 0.0027465820312500, 0.0015869140625000, +0.0023193359375000, 0.0025939941406250, 0.0022277832031250, 0.0025329589843750, +0.0020751953125000, 0.0025634765625000, 0.0017089843750000, 0.0031738281250000, +0.0017089843750000, 0.0028076171875000, 0.0018310546875000, 0.0029296875000000, +0.0015563964843750, 0.0029296875000000, 0.0017700195312500, 0.0025939941406250, +0.0019531250000000, 0.0023498535156250, 0.0017089843750000, 0.0022277832031250, +0.0024719238281250, 0.0019531250000000, 0.0022888183593750, 0.0017089843750000, +0.0024414062500000, 0.0018005371093750, 0.0030822753906250, 0.0018005371093750, +0.0028381347656250, 0.0015563964843750, 0.0028076171875000, 0.0019226074218750, +0.0031127929687500, 0.0017089843750000, 0.0027160644531250, 0.0016784667968750, +0.0023498535156250, 0.0019226074218750, 0.0027770996093750, 0.0016479492187500, +0.0015869140625000, 0.0016479492187500, 0.0017395019531250, 0.0017089843750000, +0.0015563964843750, 0.0013732910156250, 0.0007324218750000, 0.0010986328125000, +0.0010681152343750, 0.0011596679687500, 0.0007019042968750, 0.0005493164062500, +0.0004577636718750, 0.0005798339843750, 0.0007019042968750, 0.0002136230468750, +0.0007324218750000, -0.0003662109375000, 0.0006103515625000, -0.0001525878906250, +0.0012207031250000, -0.0008239746093750, 0.0010375976562500, -0.0009155273437500, +0.0012817382812500, -0.0006713867187500, 0.0018615722656250, -0.0008850097656250, +0.0014343261718750, -0.0009765625000000, 0.0018310546875000, -0.0005187988281250, +0.0019226074218750, -0.0005493164062500, 0.0016479492187500, -0.0004882812500000, +0.0016174316406250, -0.0000915527343750, 0.0016174316406250, -0.0002136230468750, +0.0011291503906250, -0.0002441406250000, 0.0012207031250000, -0.0001220703125000, +0.0009460449218750, -0.0002441406250000, 0.0004882812500000, -0.0004577636718750, +0.0007629394531250, -0.0003051757812500, 0.0002746582031250, -0.0005798339843750, +0.0002136230468750, -0.0006408691406250, 0.0003662109375000, -0.0005493164062500, +0.0002746582031250, -0.0007019042968750, 0.0003356933593750, -0.0007019042968750, +0.0006408691406250, -0.0004577636718750, 0.0007324218750000, -0.0005187988281250, +0.0009460449218750, -0.0004272460937500, 0.0012817382812500, -0.0001525878906250, +0.0012817382812500, -0.0001220703125000, 0.0015869140625000, 0.0001831054687500, +0.0017089843750000, 0.0002441406250000, 0.0017089843750000, 0.0003662109375000, +0.0018615722656250, 0.0005493164062500, 0.0019836425781250, 0.0006103515625000, +0.0017700195312500, 0.0007629394531250, 0.0018310546875000, 0.0007934570312500, +0.0018310546875000, 0.0008544921875000, 0.0016479492187500, 0.0009460449218750, +0.0017395019531250, 0.0008544921875000, 0.0016479492187500, 0.0010681152343750, +0.0016784667968750, 0.0009765625000000, 0.0015258789062500, 0.0010070800781250, +0.0014343261718750, 0.0011596679687500, 0.0014648437500000, 0.0009765625000000, +0.0013122558593750, 0.0010986328125000, 0.0012817382812500, 0.0010375976562500, +0.0013732910156250, 0.0010375976562500, 0.0013427734375000, 0.0011291503906250, +0.0013122558593750, 0.0010375976562500, 0.0016479492187500, 0.0010375976562500, +0.0015869140625000, 0.0010681152343750, 0.0018005371093750, 0.0010375976562500, +0.0021972656250000, 0.0010681152343750, 0.0020141601562500, 0.0010681152343750, +0.0025024414062500, 0.0011291503906250, 0.0026245117187500, 0.0011596679687500, +0.0025024414062500, 0.0010681152343750, 0.0026855468750000, 0.0009765625000000, +0.0027160644531250, 0.0010070800781250, 0.0023193359375000, 0.0008544921875000, +0.0024719238281250, 0.0007934570312500, 0.0021667480468750, 0.0007629394531250, +0.0017089843750000, 0.0006408691406250, 0.0019836425781250, 0.0005493164062500, +0.0012207031250000, 0.0007324218750000, 0.0012512207031250, 0.0006713867187500, +0.0012512207031250, 0.0006408691406250, 0.0007934570312500, 0.0007629394531250, +0.0009155273437500, 0.0007019042968750, 0.0008850097656250, 0.0008239746093750, +0.0006713867187500, 0.0007934570312500, 0.0008544921875000, 0.0009155273437500, +0.0009460449218750, 0.0010681152343750, 0.0007629394531250, 0.0008850097656250, +0.0010681152343750, 0.0012817382812500, 0.0009765625000000, 0.0011901855468750, +0.0010070800781250, 0.0013122558593750, 0.0012207031250000, 0.0015258789062500, +0.0010681152343750, 0.0014648437500000, 0.0014038085937500, 0.0019226074218750, +0.0012817382812500, 0.0018310546875000, 0.0013732910156250, 0.0019531250000000, +0.0016479492187500, 0.0022277832031250, 0.0014038085937500, 0.0019836425781250, +0.0018005371093750, 0.0023193359375000, 0.0017395019531250, 0.0022583007812500, +0.0017700195312500, 0.0020751953125000, 0.0020446777343750, 0.0021362304687500, +0.0019226074218750, 0.0019531250000000, 0.0021057128906250, 0.0015869140625000, +0.0021972656250000, 0.0015563964843750, 0.0021362304687500, 0.0013122558593750, +0.0022277832031250, 0.0008544921875000, 0.0022277832031250, 0.0009765625000000, +0.0018615722656250, 0.0005798339843750, 0.0020751953125000, 0.0005493164062500, +0.0018310546875000, 0.0004882812500000, 0.0013732910156250, 0.0002136230468750, +0.0017395019531250, 0.0003356933593750, 0.0011901855468750, 0.0003051757812500, +0.0011901855468750, 0.0002136230468750, 0.0012512207031250, 0.0004272460937500, +0.0010986328125000, 0.0005187988281250, 0.0011901855468750, 0.0002746582031250, +0.0012207031250000, 0.0008850097656250, 0.0013427734375000, 0.0007019042968750, +0.0015869140625000, 0.0009460449218750, 0.0016479492187500, 0.0014648437500000, +0.0018005371093750, 0.0011901855468750, 0.0020751953125000, 0.0016174316406250, +0.0020751953125000, 0.0016174316406250, 0.0020751953125000, 0.0017395019531250, +0.0022277832031250, 0.0020141601562500, 0.0022277832031250, 0.0018615722656250, +0.0020446777343750, 0.0022277832031250, 0.0020446777343750, 0.0021667480468750, +0.0020141601562500, 0.0021362304687500, 0.0018310546875000, 0.0023498535156250, +0.0018920898437500, 0.0022888183593750, 0.0018615722656250, 0.0022277832031250, +0.0017395019531250, 0.0022277832031250, 0.0018005371093750, 0.0021972656250000, +0.0019226074218750, 0.0021362304687500, 0.0017089843750000, 0.0020751953125000, +0.0017089843750000, 0.0023193359375000, 0.0017395019531250, 0.0021972656250000, +0.0018005371093750, 0.0022277832031250, 0.0018005371093750, 0.0024414062500000, +0.0018920898437500, 0.0023193359375000, 0.0020141601562500, 0.0024719238281250, +0.0019531250000000, 0.0024414062500000, 0.0019531250000000, 0.0023193359375000, +0.0022583007812500, 0.0024108886718750, 0.0022277832031250, 0.0023498535156250, +0.0016479492187500, 0.0021972656250000, 0.0020751953125000, 0.0021362304687500, +0.0015258789062500, 0.0020751953125000, 0.0006713867187500, 0.0019226074218750, +0.0011901855468750, 0.0018920898437500, -0.0001220703125000, 0.0019531250000000, +-0.0001525878906250, 0.0018310546875000, -0.0001831054687500, 0.0019226074218750, +-0.0009155273437500, 0.0019836425781250, -0.0006713867187500, 0.0018310546875000, +-0.0004577636718750, 0.0022277832031250, -0.0007019042968750, 0.0020751953125000, +-0.0002136230468750, 0.0020141601562500, 0.0003662109375000, 0.0021972656250000, +0.0000610351562500, 0.0020751953125000, 0.0012512207031250, 0.0019836425781250, +0.0011901855468750, 0.0019226074218750, 0.0014953613281250, 0.0018310546875000, +0.0023193359375000, 0.0017089843750000, 0.0019836425781250, 0.0015869140625000, +0.0026245117187500, 0.0014953613281250, 0.0027770996093750, 0.0013732910156250, +0.0026245117187500, 0.0013427734375000, 0.0028076171875000, 0.0013122558593750, +0.0028686523437500, 0.0011596679687500, 0.0023803710937500, 0.0013427734375000, +0.0025634765625000, 0.0012512207031250, 0.0023193359375000, 0.0011901855468750, +0.0018005371093750, 0.0013427734375000, 0.0020751953125000, 0.0011901855468750, +0.0014343261718750, 0.0013122558593750, 0.0014343261718750, 0.0012512207031250, +0.0012817382812500, 0.0012512207031250, 0.0009155273437500, 0.0013427734375000, +0.0009460449218750, 0.0012207031250000, 0.0006408691406250, 0.0013122558593750, +0.0006103515625000, 0.0013732910156250, 0.0004882812500000, 0.0012817382812500, +0.0003662109375000, 0.0013732910156250, 0.0004272460937500, 0.0014343261718750, +0.0000610351562500, 0.0012817382812500, 0.0002136230468750, 0.0013732910156250, +0.0001525878906250, 0.0014648437500000, -0.0002136230468750, 0.0014038085937500, +-0.0000305175781250, 0.0015258789062500, -0.0001525878906250, 0.0014648437500000, +-0.0002136230468750, 0.0015869140625000, -0.0001220703125000, 0.0014953613281250, +-0.0000915527343750, 0.0013732910156250, -0.0001525878906250, 0.0016174316406250, +-0.0001525878906250, 0.0011901855468750, -0.0000305175781250, 0.0013122558593750, +-0.0002136230468750, 0.0013122558593750, -0.0003662109375000, 0.0010986328125000, +-0.0003051757812500, 0.0012817382812500, -0.0006408691406250, 0.0010681152343750, +-0.0006408691406250, 0.0010986328125000, -0.0006408691406250, 0.0011596679687500, +-0.0009155273437500, 0.0011291503906250, -0.0008850097656250, 0.0011901855468750, +-0.0008544921875000, 0.0011596679687500, -0.0008239746093750, 0.0012207031250000, +-0.0007324218750000, 0.0010375976562500, -0.0007019042968750, 0.0008850097656250, +-0.0006408691406250, 0.0009460449218750, -0.0007019042968750, 0.0005187988281250, +-0.0004882812500000, 0.0004882812500000, -0.0004882812500000, 0.0004882812500000, +-0.0005187988281250, 0.0001525878906250, -0.0002746582031250, 0.0001831054687500, +-0.0005187988281250}, +{0.0026550292968750, 0.0028381347656250, 0.0025634765625000, 0.0028381347656250, +0.0027160644531250, 0.0029296875000000, 0.0025329589843750, 0.0028076171875000, +0.0022888183593750, 0.0026550292968750, 0.0026245117187500, 0.0028076171875000, +0.0018310546875000, 0.0023803710937500, 0.0019531250000000, 0.0024719238281250, +0.0019226074218750, 0.0022888183593750, 0.0013732910156250, 0.0019531250000000, +0.0017089843750000, 0.0022277832031250, 0.0013427734375000, 0.0019226074218750, +0.0014343261718750, 0.0019226074218750, 0.0013427734375000, 0.0020141601562500, +0.0012512207031250, 0.0020141601562500, 0.0015869140625000, 0.0019836425781250, +0.0011291503906250, 0.0021667480468750, 0.0014648437500000, 0.0021972656250000, +0.0011901855468750, 0.0022277832031250, 0.0007019042968750, 0.0023193359375000, +0.0012817382812500, 0.0022583007812500, 0.0002441406250000, 0.0022583007812500, +0.0003967285156250, 0.0022888183593750, 0.0003051757812500, 0.0021667480468750, +-0.0004882812500000, 0.0019836425781250, -0.0001220703125000, 0.0019836425781250, +-0.0003662109375000, 0.0018615722656250, -0.0006713867187500, 0.0018005371093750, +-0.0002441406250000, 0.0017089843750000, -0.0001220703125000, 0.0016174316406250, +-0.0004577636718750, 0.0015563964843750, 0.0007934570312500, 0.0015563964843750, +0.0005187988281250, 0.0013732910156250, 0.0007934570312500, 0.0014038085937500, +0.0017089843750000, 0.0014648437500000, 0.0012207031250000, 0.0012817382812500, +0.0018005371093750, 0.0015563964843750, 0.0019531250000000, 0.0014343261718750, +0.0016479492187500, 0.0013732910156250, 0.0016784667968750, 0.0015258789062500, +0.0016784667968750, 0.0013122558593750, 0.0010070800781250, 0.0014038085937500, +0.0010986328125000, 0.0014343261718750, 0.0007934570312500, 0.0014038085937500, +0.0001831054687500, 0.0014038085937500, 0.0004272460937500, 0.0013122558593750, +-0.0001525878906250, 0.0015563964843750, -0.0002441406250000, 0.0014343261718750, +-0.0002441406250000, 0.0015869140625000, -0.0005187988281250, 0.0018615722656250, +-0.0005187988281250, 0.0015869140625000, -0.0002746582031250, 0.0021667480468750, +-0.0004577636718750, 0.0020751953125000, -0.0003967285156250, 0.0021057128906250, +-0.0001525878906250, 0.0024414062500000, -0.0003356933593750, 0.0022583007812500, +-0.0002441406250000, 0.0025024414062500, -0.0003662109375000, 0.0025024414062500, +-0.0004577636718750, 0.0025329589843750, -0.0005187988281250, 0.0026245117187500, +-0.0007019042968750, 0.0025024414062500, -0.0006408691406250, 0.0027465820312500, +-0.0008850097656250, 0.0027770996093750, -0.0009155273437500, 0.0027465820312500, +-0.0007629394531250, 0.0029602050781250, -0.0010070800781250, 0.0028991699218750, +-0.0006713867187500, 0.0027770996093750, -0.0007934570312500, 0.0029602050781250, +-0.0007019042968750, 0.0027160644531250, -0.0004272460937500, 0.0024719238281250, +-0.0005798339843750, 0.0027160644531250, -0.0002746582031250, 0.0020446777343750, +-0.0002746582031250, 0.0021362304687500, -0.0002136230468750, 0.0020141601562500, +0.0000000000000000, 0.0014953613281250, -0.0000610351562500, 0.0017089843750000, +0.0001831054687500, 0.0013122558593750, 0.0002136230468750, 0.0012512207031250, +0.0002136230468750, 0.0014038085937500, 0.0003967285156250, 0.0012817382812500, +0.0003356933593750, 0.0012512207031250, 0.0005187988281250, 0.0014343261718750, +0.0005187988281250, 0.0014038085937500, 0.0006103515625000, 0.0014953613281250, +0.0007324218750000, 0.0016174316406250, 0.0007019042968750, 0.0015258789062500, +0.0007934570312500, 0.0018920898437500, 0.0008850097656250, 0.0018310546875000, +0.0009155273437500, 0.0020751953125000, 0.0009765625000000, 0.0025024414062500, +0.0010375976562500, 0.0023193359375000, 0.0010070800781250, 0.0030822753906250, +0.0010986328125000, 0.0030822753906250, 0.0011596679687500, 0.0032348632812500, +0.0012512207031250, 0.0038146972656250, 0.0013122558593750, 0.0036010742187500, +0.0013427734375000, 0.0037536621093750, 0.0013427734375000, 0.0038757324218750, +0.0014038085937500, 0.0035705566406250, 0.0014343261718750, 0.0034179687500000, +0.0014953613281250, 0.0035705566406250, 0.0015869140625000, 0.0026855468750000, +0.0015869140625000, 0.0029296875000000, 0.0015563964843750, 0.0024414062500000, +0.0015869140625000, 0.0015869140625000, 0.0015563964843750, 0.0020141601562500, +0.0014953613281250, 0.0008544921875000, 0.0014953613281250, 0.0008239746093750, +0.0013732910156250, 0.0008544921875000, 0.0012817382812500, 0.0002441406250000, +0.0013122558593750, 0.0004272460937500, 0.0010375976562500, 0.0007934570312500, +0.0010070800781250, 0.0004882812500000, 0.0010070800781250, 0.0008544921875000, +0.0007629394531250, 0.0014648437500000, 0.0007934570312500, 0.0011596679687500, +0.0007324218750000, 0.0019226074218750, 0.0007324218750000, 0.0019531250000000, +0.0007324218750000, 0.0019531250000000, 0.0007019042968750, 0.0024108886718750, +0.0006713867187500, 0.0022277832031250, 0.0005798339843750, 0.0025024414062500, +0.0006408691406250, 0.0025024414062500, 0.0006103515625000, 0.0024719238281250, +0.0005187988281250, 0.0025634765625000, 0.0006408691406250, 0.0024719238281250, +0.0005798339843750, 0.0025939941406250, 0.0005493164062500, 0.0025329589843750, +0.0006713867187500, 0.0025329589843750, 0.0007629394531250, 0.0026550292968750, +0.0006713867187500, 0.0026245117187500, 0.0008850097656250, 0.0024719238281250, +0.0008544921875000, 0.0026855468750000, 0.0008850097656250, 0.0023803710937500, +0.0010375976562500, 0.0020751953125000, 0.0009155273437500, 0.0024108886718750, +0.0010681152343750, 0.0016784667968750, 0.0010070800781250, 0.0018310546875000, +0.0010070800781250, 0.0018005371093750, 0.0011596679687500, 0.0014343261718750, +0.0010070800781250, 0.0016479492187500, 0.0010986328125000, 0.0016174316406250, +0.0011291503906250, 0.0016479492187500, 0.0010375976562500, 0.0015869140625000, +0.0010681152343750, 0.0015869140625000, 0.0010375976562500, 0.0017089843750000, +0.0011901855468750, 0.0014648437500000, 0.0011291503906250, 0.0014038085937500, +0.0013122558593750, 0.0013732910156250, 0.0015258789062500, 0.0012207031250000, +0.0014038085937500, 0.0012512207031250, 0.0017089843750000, 0.0012512207031250, +0.0017089843750000, 0.0011596679687500, 0.0017395019531250, 0.0012207031250000, +0.0019226074218750, 0.0012512207031250, 0.0018920898437500, 0.0012817382812500, +0.0018310546875000, 0.0012817382812500, 0.0019836425781250, 0.0013732910156250, +0.0017700195312500, 0.0012512207031250, 0.0016174316406250, 0.0012817382812500, +0.0018615722656250, 0.0013122558593750, 0.0015258789062500, 0.0007934570312500, +0.0016174316406250, 0.0010375976562500, 0.0016174316406250, 0.0007934570312500, +0.0014953613281250, 0.0002136230468750, 0.0017089843750000, 0.0006408691406250, +0.0017089843750000, 0.0001525878906250, 0.0018005371093750, 0.0000000000000000, +0.0019531250000000, 0.0002441406250000, 0.0019836425781250, 0.0002441406250000, +0.0021057128906250, 0.0001525878906250, 0.0021057128906250, 0.0007324218750000, +0.0022888183593750, 0.0007629394531250, 0.0022888183593750, 0.0010070800781250, +0.0021972656250000, 0.0014038085937500, 0.0024719238281250, 0.0013122558593750, +0.0021667480468750, 0.0020751953125000, 0.0022583007812500, 0.0019531250000000, +0.0022888183593750, 0.0022277832031250, 0.0020141601562500, 0.0032653808593750, +0.0022277832031250, -0.0000305175781250, 0.0021972656250000, 0.0007629394531250, +0.0021362304687500, 0.0001220703125000, 0.0020446777343750, 0.0009155273437500, +0.0018005371093750, 0.0019226074218750, 0.0016784667968750, 0.0012817382812500, +0.0018920898437500, 0.0024719238281250, 0.0015869140625000, 0.0024719238281250, +0.0017700195312500, 0.0024108886718750, 0.0020446777343750, 0.0031433105468750, +0.0016174316406250, 0.0028686523437500, 0.0023193359375000, 0.0023803710937500, +0.0022277832031250, 0.0028686523437500, 0.0021972656250000, 0.0022277832031250, +0.0025939941406250, 0.0014038085937500, 0.0023803710937500, 0.0020751953125000, +0.0025329589843750, 0.0006103515625000, 0.0026245117187500, 0.0007934570312500, +0.0024108886718750, 0.0006408691406250, 0.0023193359375000, -0.0003662109375000, +0.0025329589843750, 0.0002136230468750, 0.0021972656250000, -0.0000305175781250, +0.0023193359375000, -0.0002746582031250, 0.0022888183593750, 0.0002136230468750, +0.0019836425781250, 0.0004577636718750, 0.0022277832031250, 0.0002746582031250, +0.0019226074218750, 0.0013732910156250, 0.0019531250000000, 0.0013427734375000, +0.0020446777343750, 0.0014343261718750, 0.0020141601562500, 0.0022277832031250, +0.0019226074218750, 0.0020751953125000, 0.0020446777343750, 0.0018615722656250, +0.0020751953125000, 0.0021972656250000, 0.0018615722656250, 0.0019226074218750, +0.0018310546875000, 0.0013122558593750, 0.0018920898437500, 0.0017700195312500, +0.0011291503906250, 0.0014343261718750, 0.0012817382812500, 0.0013427734375000, +0.0008850097656250, 0.0017089843750000, 0.0001831054687500, 0.0018310546875000, +0.0005187988281250, 0.0016479492187500, -0.0002441406250000, 0.0023193359375000, +-0.0003662109375000, 0.0022888183593750, -0.0002746582031250, 0.0023193359375000, +-0.0006103515625000, 0.0027770996093750, -0.0006713867187500, 0.0025939941406250, +-0.0001525878906250, 0.0026245117187500, -0.0005187988281250, 0.0028686523437500, +-0.0001831054687500, 0.0025939941406250, 0.0005187988281250, 0.0022583007812500, +0.0000305175781250, 0.0025634765625000, 0.0009765625000000, 0.0017395019531250, +0.0009460449218750, 0.0018005371093750, 0.0008544921875000, 0.0016784667968750, +0.0012512207031250, 0.0010681152343750, 0.0012207031250000, 0.0012207031250000, +0.0010070800781250, 0.0012207031250000, 0.0010986328125000, 0.0009155273437500, +0.0010681152343750, 0.0012817382812500, 0.0008544921875000, 0.0015869140625000, +0.0009765625000000, 0.0011901855468750, 0.0008239746093750, 0.0021057128906250, +0.0008239746093750, 0.0019226074218750, 0.0008544921875000, 0.0020751953125000, +0.0007324218750000, 0.0026855468750000, 0.0007324218750000, 0.0023193359375000, +0.0009155273437500, 0.0025939941406250, 0.0007934570312500, 0.0026855468750000, +0.0008850097656250, 0.0025634765625000, 0.0010681152343750, 0.0025634765625000, +0.0009765625000000, 0.0025939941406250, 0.0009765625000000, 0.0023803710937500, +0.0009765625000000, 0.0022583007812500, 0.0008850097656250, 0.0023498535156250, +0.0008544921875000, 0.0023193359375000, 0.0008850097656250, 0.0022888183593750, +0.0007629394531250, 0.0025939941406250, 0.0007629394531250, 0.0025024414062500, +0.0008850097656250, 0.0026245117187500, 0.0007934570312500, 0.0030212402343750, +0.0007629394531250, 0.0027770996093750, 0.0009765625000000, 0.0031738281250000, +0.0009155273437500, 0.0030822753906250, 0.0010986328125000, 0.0029296875000000, +0.0013122558593750, 0.0029602050781250, 0.0011596679687500, 0.0028686523437500, +0.0015563964843750, 0.0027160644531250, 0.0015563964843750, 0.0027465820312500, +0.0015563964843750, 0.0026245117187500, 0.0017700195312500, 0.0025024414062500, +0.0017395019531250, 0.0026245117187500, 0.0015258789062500, 0.0023803710937500, +0.0016479492187500, 0.0024108886718750, 0.0014648437500000, 0.0024108886718750, +0.0010986328125000, 0.0022888183593750, 0.0012207031250000, 0.0024108886718750, +0.0010070800781250, 0.0022583007812500, 0.0008850097656250, 0.0023498535156250, +0.0010375976562500}}; +float hrirs_right[HRIRS_IMPULSE_SIZE][HRIRS_IMPULSE_LEN] = { +{-0.0016174316406250, -0.0000305175781250, -0.0017700195312500, 0.0000000000000000, +-0.0016784667968750, 0.0000000000000000, -0.0018310546875000, 0.0000000000000000, +-0.0018310546875000, 0.0000000000000000, -0.0017700195312500, 0.0000000000000000, +-0.0018310546875000, 0.0000000000000000, -0.0018615722656250, 0.0000000000000000, +-0.0015869140625000, 0.0000000000000000, -0.0017700195312500, 0.0000000000000000, +-0.0014343261718750, 0.0000000000000000, -0.0010986328125000, 0.0000000000000000, +-0.0014038085937500, 0.0000000000000000, -0.0003051757812500, 0.0000000000000000, +-0.0006103515625000, 0.0000000000000000, -0.0002441406250000, 0.0000000000000000, +0.0006713867187500, 0.0000305175781250, 0.0000915527343750, 0.0000000000000000, +0.0011291503906250, 0.0000000000000000, 0.0012512207031250, 0.0000000000000000, +0.0010681152343750, 0.0000000000000000, 0.0015258789062500, 0.0000000000000000, +0.0014648437500000, 0.0000000000000000, 0.0009155273437500, 0.0000305175781250, +0.0012207031250000, 0.0000000000000000, 0.0007019042968750, -0.0000305175781250, +-0.0000610351562500, 0.0000000000000000, 0.0004272460937500, 0.0000000000000000, +-0.0007019042968750, 0.0000000000000000, -0.0007324218750000, 0.0000000000000000, +-0.0006713867187500, 0.0000305175781250, -0.0012817382812500, 0.0000000000000000, +-0.0011291503906250, 0.0000305175781250, -0.0008239746093750, 0.0000305175781250, +-0.0011291503906250, -0.0000305175781250, -0.0006713867187500, 0.0000000000000000, +-0.0000610351562500, 0.0000000000000000, -0.0004272460937500, -0.0000305175781250, +0.0005187988281250, -0.0000305175781250, 0.0006103515625000, 0.0000000000000000, +0.0005187988281250, 0.0000000000000000, 0.0009765625000000, 0.0000000000000000, +0.0008850097656250, 0.0000000000000000, 0.0003967285156250, 0.0000305175781250, +0.0006103515625000, 0.0000000000000000, 0.0002746582031250, 0.0000000000000000, +-0.0003967285156250, 0.0000000000000000, -0.0000915527343750, -0.0000305175781250, +-0.0005493164062500, -0.0000305175781250, -0.0007324218750000, 0.0000000000000000, +-0.0004577636718750, 0.0000305175781250, -0.0003967285156250, 0.0000000000000000, +-0.0005493164062500, 0.0000305175781250, 0.0000915527343750, 0.0000610351562500, +0.0000610351562500, 0.0000305175781250, 0.0000915527343750, 0.0000000000000000, +0.0005798339843750, 0.0000305175781250, 0.0003967285156250, -0.0000610351562500, +0.0002746582031250, -0.0000915527343750, 0.0005187988281250, -0.0000305175781250, +0.0002136230468750, -0.0000305175781250, -0.0002441406250000, -0.0000610351562500, +0.0000610351562500, 0.0000610351562500, -0.0003967285156250, 0.0000610351562500, +-0.0006103515625000, 0.0000305175781250, -0.0002746582031250, 0.0000610351562500, +-0.0002746582031250, 0.0000915527343750, -0.0004272460937500, -0.0000610351562500, +0.0002746582031250, -0.0000610351562500, 0.0003051757812500, -0.0000305175781250, +0.0001831054687500, -0.0001220703125000, 0.0005187988281250, -0.0001220703125000, +0.0005187988281250, 0.0000000000000000, -0.0001525878906250, -0.0000610351562500, +0.0000000000000000, 0.0000000000000000, -0.0000610351562500, 0.0002136230468750, +-0.0005798339843750, 0.0001525878906250, -0.0004577636718750, 0.0000305175781250, +-0.0000915527343750, 0.0001831054687500, -0.0002746582031250, 0.0000610351562500, +-0.0001525878906250, -0.0002746582031250, 0.0005493164062500, -0.0000305175781250, +-0.0004577636718750, 0.0002441406250000, 0.0000610351562500, 0.0003662109375000, +-0.0003051757812500, 0.0000915527343750, -0.0000610351562500, -0.0000915527343750, +0.0004577636718750, 0.0001525878906250, 0.0003051757812500, -0.0003356933593750, +0.0000610351562500, -0.0004577636718750, 0.0002746582031250, -0.0001831054687500, +0.0000610351562500, -0.0003051757812500, -0.0003967285156250, -0.0004577636718750, +-0.0002136230468750, 0.0003356933593750, -0.0000915527343750, 0.0002441406250000, +-0.0002746582031250, 0.0002136230468750, -0.0000915527343750, 0.0006713867187500, +0.0002441406250000, 0.0006103515625000, 0.0001220703125000, -0.0000305175781250, +0.0000915527343750, 0.0002441406250000, 0.0002746582031250, 0.0000000000000000, +0.0000915527343750, -0.0008239746093750, -0.0001831054687500, -0.0004882812500000, +0.0000000000000000, -0.0003662109375000, -0.0000610351562500, -0.0007934570312500, +-0.0002136230468750, -0.0002136230468750, -0.0000610351562500, 0.0005493164062500, +0.0001220703125000, 0.0000000000000000, 0.0000000000000000, 0.0006408691406250, +0.0000915527343750, 0.0009765625000000, 0.0001831054687500, 0.0004272460937500, +0.0000610351562500, 0.0002746582031250, -0.0000915527343750, 0.0006103515625000, +0.0000000000000000, -0.0005798339843750, -0.0000305175781250, -0.0005798339843750, +-0.0001220703125000, -0.0003662109375000, -0.0000305175781250, -0.0009460449218750, +0.0000610351562500, -0.0009155273437500, 0.0000000000000000, -0.0000305175781250, +0.0000305175781250, -0.0004272460937500, 0.0001220703125000, -0.0000305175781250, +0.0000305175781250, 0.0008544921875000, -0.0000305175781250, 0.0003967285156250, +0.0000000000000000, 0.0007019042968750, -0.0000305175781250, 0.0010986328125000, +-0.0000915527343750, 0.0005493164062500, -0.0000305175781250, 0.0002746582031250, +0.0000305175781250, 0.0006713867187500, 0.0000000000000000, -0.0005187988281250, +0.0000305175781250, -0.0004272460937500, 0.0000610351562500, -0.0004577636718750, +0.0000000000000000, -0.0011901855468750, -0.0000305175781250, -0.0009765625000000, +0.0000000000000000, -0.0007019042968750, 0.0000000000000000, -0.0010375976562500, +-0.0000305175781250, -0.0006103515625000, -0.0000305175781250, 0.0000000000000000, +0.0000000000000000, -0.0004272460937500, 0.0000000000000000, 0.0006408691406250, +0.0000305175781250, 0.0005798339843750, 0.0000000000000000, 0.0006713867187500, +0.0000000000000000, 0.0013732910156250, -0.0000305175781250, 0.0010681152343750, +-0.0000305175781250, 0.0011596679687500, 0.0000000000000000, 0.0014343261718750, +0.0000000000000000, 0.0010070800781250, 0.0000305175781250, 0.0007019042968750, +0.0000305175781250, 0.0010681152343750, 0.0000305175781250, -0.0001525878906250, +0.0000000000000000, 0.0001831054687500, 0.0000000000000000, -0.0002136230468750, +0.0000000000000000, -0.0011901855468750, 0.0000000000000000, -0.0005798339843750, +0.0000000000000000, -0.0015563964843750, 0.0000000000000000, -0.0016174316406250, +0.0000305175781250, -0.0015563964843750, 0.0000000000000000, -0.0020751953125000, +0.0000305175781250, -0.0019226074218750, 0.0000000000000000, -0.0017089843750000, +0.0000000000000000, -0.0019836425781250, 0.0000000000000000, -0.0016479492187500, +0.0000305175781250, -0.0013122558593750, 0.0000000000000000, -0.0016784667968750, +0.0000000000000000, -0.0006713867187500, -0.0000305175781250, -0.0010070800781250, +0.0000000000000000, -0.0007019042968750, 0.0000000000000000, 0.0001220703125000, +0.0000000000000000, -0.0004577636718750, 0.0000000000000000, 0.0005187988281250, +0.0000000000000000, 0.0003051757812500, 0.0000000000000000, 0.0004577636718750, +0.0000000000000000, 0.0010070800781250, 0.0000000000000000, 0.0005187988281250, +0.0000000000000000, 0.0010986328125000, 0.0000000000000000, 0.0009765625000000, +-0.0000305175781250, 0.0009765625000000, 0.0000000000000000, 0.0012512207031250, +0.0000000000000000, 0.0009460449218750, 0.0000305175781250, 0.0012207031250000, +0.0000000000000000, 0.0011291503906250, -0.0000305175781250, 0.0010375976562500, +-0.0000305175781250, 0.0011596679687500, 0.0000000000000000, 0.0009765625000000, +0.0000000000000000, 0.0008850097656250, 0.0000000000000000, 0.0008239746093750, +0.0000000000000000, 0.0006408691406250, -0.0000305175781250, 0.0004882812500000, +0.0000305175781250, 0.0003662109375000, -0.0000305175781250, 0.0000305175781250, +-0.0000305175781250, 0.0000305175781250, 0.0000000000000000, -0.0002136230468750, +0.0000000000000000, -0.0005493164062500, -0.0000305175781250, -0.0004577636718750, +0.0000000000000000, -0.0010070800781250, 0.0000000000000000, -0.0009765625000000, +0.0000000000000000, -0.0010681152343750, 0.0000000000000000, -0.0014343261718750, +0.0000000000000000, -0.0013732910156250, -0.0000305175781250, -0.0014343261718750, +0.0000305175781250, -0.0016174316406250, 0.0000000000000000, -0.0014038085937500, +0.0000000000000000, -0.0012817382812500, -0.0000305175781250, -0.0014038085937500, +-0.0000305175781250, -0.0007324218750000, 0.0000305175781250, -0.0008239746093750, +0.0000000000000000, -0.0005187988281250, 0.0000000000000000, 0.0001525878906250, +0.0000000000000000, -0.0000915527343750, 0.0000000000000000, 0.0006713867187500, +0.0000000000000000, 0.0007324218750000, 0.0000000000000000, 0.0007324218750000, +-0.0000305175781250, 0.0010986328125000, -0.0000305175781250, 0.0010375976562500, +0.0000000000000000, 0.0007629394531250, 0.0000000000000000, 0.0010070800781250, +0.0000000000000000, 0.0006408691406250, 0.0000000000000000, 0.0001831054687500, +0.0000000000000000, 0.0004272460937500, 0.0000000000000000, -0.0003967285156250, +0.0000000000000000, -0.0004577636718750, 0.0000000000000000, -0.0004272460937500, +0.0000000000000000, -0.0008239746093750, -0.0000305175781250, -0.0007629394531250, +0.0000000000000000, -0.0004272460937500, 0.0000000000000000, -0.0006103515625000, +-0.0000305175781250, -0.0003051757812500, 0.0000305175781250, 0.0002136230468750, +0.0000305175781250, -0.0000305175781250, 0.0000000000000000, 0.0004272460937500, +0.0000000000000000, 0.0005798339843750, 0.0000000000000000, 0.0003662109375000, +0.0000000000000000, 0.0003662109375000, -0.0000305175781250, 0.0004577636718750, +0.0000000000000000, -0.0000915527343750, 0.0000000000000000, -0.0000610351562500, +-0.0000305175781250, -0.0000915527343750, -0.0000305175781250, -0.0004577636718750, +0.0000305175781250, -0.0003662109375000, 0.0000000000000000, -0.0001220703125000, +0.0000000000000000, -0.0002746582031250, 0.0000305175781250, -0.0000915527343750, +0.0000000000000000, 0.0003051757812500, -0.0000305175781250, 0.0001220703125000, +0.0000000000000000, 0.0001525878906250, 0.0000000000000000, 0.0003051757812500, +-0.0000305175781250, 0.0001220703125000, -0.0000305175781250, -0.0001525878906250, +0.0000305175781250, 0.0000000000000000, 0.0000305175781250, -0.0001831054687500, +0.0000305175781250, -0.0003051757812500, 0.0000610351562500, -0.0001220703125000, +0.0000305175781250, 0.0000000000000000, -0.0000610351562500, -0.0001220703125000, +0.0000000000000000, 0.0001525878906250, -0.0000305175781250, 0.0002441406250000, +-0.0000610351562500, 0.0000915527343750, -0.0000305175781250, 0.0000610351562500, +0.0000305175781250, 0.0001525878906250, 0.0000000000000000, -0.0000915527343750, +0.0000000000000000, -0.0001220703125000, 0.0000915527343750, -0.0000610351562500, +0.0000000000000000, -0.0000610351562500, -0.0000610351562500, -0.0000305175781250, +-0.0000305175781250, 0.0000610351562500, -0.0000305175781250, 0.0001220703125000, +-0.0000610351562500, 0.0000305175781250, -0.0000305175781250, 0.0000305175781250, +0.0000610351562500, 0.0000915527343750, 0.0000610351562500, -0.0000610351562500, +0.0000305175781250, -0.0000915527343750, 0.0000915527343750, -0.0000305175781250, +0.0000305175781250, -0.0000305175781250, -0.0000610351562500, -0.0000915527343750, +-0.0000305175781250, 0.0000610351562500, 0.0000000000000000, 0.0001220703125000, +-0.0000610351562500, 0.0000305175781250, -0.0000305175781250, 0.0000305175781250, +0.0001220703125000, 0.0000915527343750, 0.0000305175781250, -0.0000610351562500, +0.0000305175781250}, +{0.0000000000000000, 0.0014648437500000, 0.0000000000000000, 0.0015869140625000, +-0.0000305175781250, 0.0012817382812500, 0.0000000000000000, 0.0009460449218750, +0.0000000000000000, 0.0011596679687500, 0.0000000000000000, 0.0003356933593750, +0.0000000000000000, 0.0003967285156250, 0.0000000000000000, 0.0000610351562500, +0.0000305175781250, -0.0006103515625000, 0.0000000000000000, -0.0003356933593750, +-0.0000305175781250, -0.0009460449218750, 0.0000000000000000, -0.0010986328125000, +-0.0000305175781250, -0.0009460449218750, -0.0000305175781250, -0.0011291503906250, +0.0000000000000000, -0.0011901855468750, 0.0000305175781250, -0.0006408691406250, +0.0000000000000000, -0.0007934570312500, 0.0000000000000000, -0.0003967285156250, +0.0000000000000000, 0.0001525878906250, -0.0000305175781250, -0.0001220703125000, +0.0000610351562500, 0.0006103515625000, 0.0000000000000000, 0.0007324218750000, +-0.0000305175781250, 0.0005798339843750, 0.0000000000000000, 0.0007934570312500, +0.0000305175781250, 0.0008239746093750, 0.0000000000000000, 0.0002746582031250, +0.0000000000000000, 0.0003967285156250, 0.0000000000000000, 0.0001525878906250, +0.0000000000000000, -0.0004272460937500, -0.0000305175781250, -0.0002136230468750, +0.0000000000000000, -0.0004577636718750, 0.0000000000000000, -0.0006713867187500, +-0.0000305175781250, -0.0003662109375000, 0.0000000000000000, -0.0001831054687500, +0.0000000000000000, -0.0003967285156250, 0.0000305175781250, 0.0002136230468750, +0.0000000000000000, 0.0002441406250000, 0.0000305175781250, 0.0001831054687500, +0.0000000000000000, 0.0004577636718750, -0.0000305175781250, 0.0004272460937500, +-0.0000305175781250, 0.0000000000000000, -0.0000305175781250, 0.0000915527343750, +-0.0000610351562500, 0.0000000000000000, -0.0000305175781250, -0.0003662109375000, +0.0000305175781250, -0.0002441406250000, 0.0000000000000000, -0.0000915527343750, +0.0000305175781250, -0.0002441406250000, 0.0000610351562500, -0.0000610351562500, +0.0000305175781250, 0.0002746582031250, -0.0000305175781250, 0.0000915527343750, +0.0000000000000000, 0.0001831054687500, -0.0000610351562500, 0.0003662109375000, +-0.0000915527343750, 0.0000915527343750, -0.0000305175781250, -0.0000915527343750, +0.0000610351562500, 0.0000915527343750, -0.0000305175781250, -0.0001220703125000, +0.0000305175781250, -0.0002746582031250, 0.0000915527343750, -0.0001220703125000, +0.0000305175781250, 0.0000000000000000, 0.0000000000000000, -0.0001525878906250, +0.0000305175781250, 0.0001220703125000, -0.0000305175781250, 0.0001831054687500, +-0.0000915527343750, 0.0000610351562500, -0.0000305175781250, 0.0000000000000000, +0.0000915527343750, 0.0000000000000000, 0.0000305175781250, -0.0000610351562500, +0.0000305175781250, -0.0001220703125000, 0.0000610351562500, -0.0000305175781250, +0.0000305175781250, 0.0000000000000000, -0.0000305175781250, -0.0000610351562500, +-0.0000305175781250, 0.0000610351562500, 0.0000000000000000, 0.0001220703125000, +-0.0000915527343750, 0.0000305175781250, 0.0000000000000000, -0.0000305175781250, +0.0001220703125000, 0.0000610351562500, 0.0000000000000000, -0.0000610351562500, +0.0000610351562500, -0.0001220703125000, 0.0001525878906250, -0.0000610351562500, +0.0000000000000000, 0.0000305175781250, -0.0000915527343750, -0.0000305175781250, +-0.0000305175781250, 0.0000915527343750, -0.0000915527343750, 0.0001525878906250, +-0.0001831054687500, 0.0000305175781250, -0.0000305175781250, 0.0000000000000000, +0.0001525878906250, 0.0000305175781250, 0.0000000000000000, -0.0000610351562500, +0.0001220703125000, -0.0000915527343750, 0.0002746582031250, -0.0000305175781250, +0.0000305175781250, 0.0000000000000000, -0.0000915527343750, -0.0000610351562500, +0.0000915527343750, 0.0000305175781250, -0.0002441406250000, 0.0000610351562500, +-0.0003356933593750, 0.0000305175781250, -0.0001220703125000, 0.0000305175781250, +-0.0001220703125000, 0.0000305175781250, -0.0002441406250000, -0.0000610351562500, +0.0002441406250000, -0.0000915527343750, 0.0002746582031250, -0.0000305175781250, +0.0001525878906250, -0.0000305175781250, 0.0003662109375000, -0.0000305175781250, +0.0003967285156250, 0.0000305175781250, -0.0000610351562500, 0.0000305175781250, +0.0000610351562500, 0.0000305175781250, -0.0000610351562500, 0.0000000000000000, +-0.0005187988281250, 0.0000000000000000, -0.0003967285156250, -0.0000305175781250, +-0.0002136230468750, -0.0000305175781250, -0.0004272460937500, 0.0000000000000000, +-0.0000915527343750, -0.0000305175781250, 0.0003051757812500, -0.0000305175781250, +0.0000305175781250, 0.0000305175781250, 0.0004882812500000, 0.0000305175781250, +0.0006408691406250, 0.0000305175781250, 0.0003662109375000, 0.0000305175781250, +0.0003967285156250, 0.0000305175781250, 0.0005187988281250, -0.0000305175781250, +-0.0001831054687500, 0.0000000000000000, -0.0001525878906250, 0.0000000000000000, +-0.0003051757812500, 0.0000000000000000, -0.0008544921875000, -0.0000305175781250, +-0.0006408691406250, 0.0000305175781250, -0.0006408691406250, 0.0000000000000000, +-0.0008544921875000, 0.0000000000000000, -0.0005187988281250, 0.0000305175781250, +-0.0002441406250000, 0.0000305175781250, -0.0004272460937500, 0.0000305175781250, +0.0003662109375000, 0.0000000000000000, 0.0003356933593750, 0.0000000000000000, +0.0004882812500000, 0.0000000000000000, 0.0010986328125000, 0.0000000000000000, +0.0008544921875000, 0.0000000000000000, 0.0010681152343750, 0.0000000000000000, +0.0012512207031250, 0.0000000000000000, 0.0010375976562500, 0.0000305175781250, +0.0009460449218750, 0.0000000000000000, 0.0010375976562500, 0.0000000000000000, +0.0005493164062500, -0.0000305175781250, 0.0005798339843750, 0.0000000000000000, +0.0002746582031250, 0.0000000000000000, -0.0001831054687500, 0.0000000000000000, +-0.0000305175781250, 0.0000000000000000, -0.0006713867187500, 0.0000000000000000, +-0.0007324218750000, 0.0000000000000000, -0.0008850097656250, 0.0000000000000000, +-0.0012512207031250, 0.0000000000000000, -0.0011596679687500, 0.0000000000000000, +-0.0014953613281250, 0.0000000000000000, -0.0015258789062500, 0.0000305175781250, +-0.0015563964843750, 0.0000000000000000, -0.0017089843750000, 0.0000000000000000, +-0.0016784667968750, -0.0000305175781250, -0.0017700195312500, 0.0000000000000000, +-0.0018310546875000, 0.0000000000000000, -0.0018615722656250, 0.0000000000000000, +-0.0018920898437500, 0.0000305175781250, -0.0018920898437500, 0.0000305175781250, +-0.0019226074218750, 0.0000305175781250, -0.0019226074218750, 0.0000000000000000, +-0.0018920898437500, 0.0000305175781250, -0.0019226074218750, 0.0000000000000000, +-0.0019531250000000, -0.0000305175781250, -0.0018920898437500, 0.0000000000000000, +-0.0019531250000000, 0.0000000000000000, -0.0019226074218750, 0.0000000000000000, +-0.0018920898437500, 0.0000000000000000, -0.0019531250000000, 0.0000000000000000, +-0.0016479492187500, -0.0000305175781250, -0.0018005371093750, -0.0000305175781250, +-0.0015258789062500, -0.0000305175781250, -0.0011901855468750, -0.0000305175781250, +-0.0014953613281250, 0.0000000000000000, -0.0006408691406250, 0.0000000000000000, +-0.0009460449218750, -0.0000305175781250, -0.0004577636718750, -0.0000305175781250, +0.0003051757812500, 0.0000000000000000, -0.0002746582031250, -0.0000305175781250, +0.0010070800781250, 0.0000000000000000, 0.0008544921875000, 0.0000000000000000, +0.0009460449218750, 0.0000305175781250, 0.0018310546875000, 0.0000305175781250, +0.0014038085937500, 0.0000000000000000, 0.0015258789062500, 0.0000000000000000, +0.0019226074218750, 0.0000000000000000, 0.0013427734375000, 0.0000000000000000, +0.0009460449218750, 0.0000000000000000, 0.0013732910156250, 0.0000000000000000, +-0.0000305175781250, 0.0000000000000000, 0.0002136230468750, 0.0000000000000000, +-0.0001220703125000, 0.0000000000000000, -0.0012817382812500, 0.0000000000000000, +-0.0007324218750000, 0.0000000000000000, -0.0013427734375000, 0.0000000000000000, +-0.0016174316406250, -0.0000305175781250, -0.0011596679687500, 0.0000000000000000, +-0.0010986328125000, 0.0000000000000000, -0.0013427734375000, 0.0000000000000000, +-0.0001525878906250, 0.0000305175781250, -0.0003662109375000, 0.0000000000000000, +-0.0000915527343750, 0.0000000000000000, 0.0008850097656250, 0.0000000000000000, +0.0005187988281250, -0.0000305175781250, 0.0009155273437500, -0.0000305175781250, +0.0012512207031250, 0.0000000000000000, 0.0007934570312500, -0.0000305175781250, +0.0006103515625000, 0.0000000000000000, 0.0008544921875000, 0.0000610351562500, +-0.0001831054687500, 0.0000610351562500, -0.0001220703125000, 0.0000000000000000, +-0.0002136230468750, 0.0000000000000000, -0.0009155273437500, 0.0000305175781250, +-0.0007019042968750, -0.0000305175781250, -0.0004882812500000, -0.0000610351562500, +-0.0007629394531250, 0.0000000000000000, -0.0003967285156250, -0.0000305175781250, +0.0001220703125000, -0.0000305175781250, -0.0001525878906250, 0.0000610351562500, +0.0004577636718750, 0.0000610351562500, 0.0005493164062500, 0.0000000000000000, +0.0003662109375000, 0.0000610351562500, 0.0006103515625000, 0.0000915527343750, +0.0005798339843750, -0.0000305175781250, 0.0000000000000000, -0.0000305175781250, +0.0001525878906250, -0.0000305175781250, -0.0000305175781250, -0.0001220703125000, +-0.0006713867187500, -0.0000915527343750, -0.0003967285156250, 0.0000305175781250, +-0.0003356933593750, 0.0000000000000000, -0.0006103515625000, 0.0000305175781250, +-0.0002136230468750, 0.0001220703125000, 0.0002746582031250, 0.0000915527343750, +-0.0000610351562500, 0.0000610351562500, 0.0004577636718750, 0.0000915527343750, +0.0007629394531250, -0.0000305175781250, 0.0002746582031250, -0.0001831054687500, +0.0001220703125000, -0.0000305175781250, 0.0004272460937500, -0.0000915527343750, +-0.0004272460937500, -0.0001831054687500, -0.0005187988281250, -0.0000610351562500, +-0.0002136230468750, 0.0001525878906250, -0.0003967285156250, 0.0000305175781250, +-0.0005798339843750, 0.0001525878906250, 0.0002441406250000, 0.0002746582031250, +0.0002441406250000, 0.0001220703125000, 0.0000915527343750, -0.0001220703125000, +0.0006103515625000, -0.0002136230468750, -0.0005798339843750, 0.0003356933593750, +0.0003662109375000, 0.0002441406250000, 0.0001220703125000, 0.0001220703125000, +0.0000610351562500, 0.0002746582031250, 0.0004272460937500, 0.0003662109375000, +0.0004882812500000, -0.0002441406250000, -0.0001525878906250, -0.0001831054687500, +-0.0000915527343750, -0.0001831054687500, -0.0000610351562500, -0.0006408691406250, +-0.0004272460937500, -0.0005187988281250, -0.0003967285156250, 0.0000000000000000, +0.0001220703125000, -0.0003051757812500, 0.0000000000000000, 0.0000000000000000, +-0.0000305175781250, 0.0007629394531250, 0.0003356933593750, 0.0004272460937500, +0.0003051757812500, 0.0003967285156250, 0.0000000000000000, 0.0007934570312500, +0.0001220703125000, 0.0002441406250000, 0.0000610351562500, -0.0004882812500000, +-0.0002746582031250, 0.0000610351562500, -0.0001525878906250, -0.0006408691406250, +-0.0000305175781250, -0.0010375976562500, -0.0000915527343750, -0.0003967285156250, +-0.0000610351562500, -0.0001525878906250, 0.0002136230468750, -0.0006103515625000, +0.0001220703125000, 0.0006408691406250, 0.0000305175781250, 0.0006713867187500, +0.0000915527343750, 0.0003967285156250, 0.0000000000000000, 0.0009460449218750, +-0.0001831054687500, 0.0009460449218750, -0.0000915527343750, -0.0001220703125000, +-0.0000305175781250, 0.0002136230468750, -0.0000915527343750, -0.0000305175781250, +-0.0000305175781250}, +{-0.0002136230468750, 0.0000000000000000, -0.0003356933593750, 0.0000000000000000, +-0.0012817382812500, -0.0000305175781250, -0.0009765625000000, 0.0000000000000000, +-0.0009765625000000, 0.0000000000000000, -0.0013122558593750, 0.0000000000000000, +-0.0007934570312500, 0.0000305175781250, -0.0003051757812500, 0.0000305175781250, +-0.0006713867187500, -0.0000305175781250, 0.0004577636718750, -0.0000305175781250, +0.0005187988281250, -0.0000305175781250, 0.0004272460937500, -0.0000610351562500, +0.0009765625000000, -0.0000610351562500, 0.0009155273437500, 0.0000305175781250, +0.0003356933593750, 0.0000305175781250, 0.0005798339843750, -0.0000305175781250, +0.0002441406250000, 0.0000610351562500, -0.0004577636718750, 0.0000305175781250, +-0.0000610351562500, -0.0000305175781250, -0.0005798339843750, -0.0000305175781250, +-0.0007629394531250, -0.0000305175781250, -0.0004577636718750, -0.0000610351562500, +-0.0004272460937500, -0.0000915527343750, -0.0006103515625000, 0.0000305175781250, +0.0002441406250000, -0.0000305175781250, 0.0001525878906250, 0.0000305175781250, +0.0001525878906250, 0.0001220703125000, 0.0007019042968750, 0.0000610351562500, +0.0005493164062500, 0.0000305175781250, 0.0002136230468750, 0.0000610351562500, +0.0004882812500000, 0.0000000000000000, 0.0001220703125000, -0.0000915527343750, +-0.0005493164062500, -0.0000305175781250, -0.0001831054687500, -0.0000610351562500, +-0.0004577636718750, -0.0001525878906250, -0.0007934570312500, 0.0000000000000000, +-0.0002746582031250, 0.0001831054687500, 0.0001525878906250, 0.0000305175781250, +-0.0002746582031250, 0.0001220703125000, 0.0004577636718750, 0.0002136230468750, +0.0007934570312500, 0.0000610351562500, 0.0002746582031250, -0.0000305175781250, +0.0001831054687500, 0.0000610351562500, 0.0004882812500000, -0.0001831054687500, +-0.0003662109375000, -0.0003051757812500, -0.0004577636718750, -0.0001220703125000, +-0.0002136230468750, -0.0000610351562500, -0.0004272460937500, 0.0002746582031250, +0.0005493164062500, -0.0002746582031250, -0.0004272460937500, -0.0000610351562500, +-0.0003662109375000, -0.0000915527343750, -0.0001220703125000, -0.0004577636718750, +-0.0002746582031250, -0.0003967285156250, -0.0004577636718750, 0.0001220703125000, +0.0002441406250000, -0.0000305175781250, 0.0003051757812500, 0.0001220703125000, +0.0000915527343750, 0.0006713867187500, 0.0003662109375000, 0.0004882812500000, +0.0003967285156250, 0.0001831054687500, -0.0001525878906250, 0.0005798339843750, +-0.0001525878906250, 0.0001220703125000, -0.0000305175781250, -0.0006103515625000, +-0.0003051757812500, -0.0002136230468750, -0.0003356933593750, -0.0005493164062500, +0.0000915527343750, -0.0009460449218750, 0.0000610351562500, -0.0003051757812500, +0.0000305175781250, 0.0001220703125000, 0.0002441406250000, -0.0003967285156250, +0.0002746582031250, 0.0007019042968750, -0.0000305175781250, 0.0009460449218750, +0.0000305175781250, 0.0003967285156250, 0.0000000000000000, 0.0005187988281250, +-0.0002136230468750, 0.0008544921875000, -0.0001525878906250, -0.0004272460937500, +0.0000305175781250, -0.0003051757812500, -0.0000305175781250, -0.0003051757812500, +0.0000000000000000, -0.0011596679687500, 0.0001831054687500, -0.0009765625000000, +0.0001525878906250, -0.0002136230468750, -0.0000305175781250, -0.0006713867187500, +0.0000610351562500, -0.0001525878906250, 0.0000000000000000, 0.0008850097656250, +-0.0001220703125000, 0.0003051757812500, -0.0000915527343750, 0.0007629394531250, +0.0000305175781250, 0.0011596679687500, -0.0000305175781250, 0.0005493164062500, +0.0000305175781250, 0.0001525878906250, 0.0001525878906250, 0.0006713867187500, +0.0000610351562500, -0.0006713867187500, 0.0000000000000000, -0.0006408691406250, +0.0000305175781250, -0.0005187988281250, 0.0000305175781250, -0.0012512207031250, +-0.0001220703125000, -0.0010986328125000, -0.0000610351562500, -0.0004577636718750, +0.0000000000000000, -0.0009155273437500, -0.0000305175781250, -0.0003356933593750, +0.0000000000000000, 0.0005798339843750, 0.0000305175781250, -0.0000610351562500, +0.0000610351562500, 0.0010070800781250, -0.0000305175781250, 0.0011901855468750, +0.0000000000000000, 0.0009155273437500, 0.0000305175781250, 0.0012512207031250, +0.0000000000000000, 0.0013122558593750, -0.0000610351562500, 0.0004882812500000, +0.0000000000000000, 0.0008239746093750, 0.0000000000000000, 0.0003967285156250, +0.0000000000000000, -0.0004577636718750, 0.0000000000000000, 0.0000610351562500, +0.0000000000000000, -0.0011901855468750, -0.0000305175781250, -0.0011596679687500, +0.0000000000000000, -0.0011291503906250, -0.0000305175781250, -0.0018005371093750, +0.0000000000000000, -0.0015869140625000, 0.0000000000000000, -0.0013732910156250, +0.0000000000000000, -0.0017700195312500, 0.0000305175781250, -0.0012512207031250, +0.0000000000000000, -0.0007629394531250, 0.0000305175781250, -0.0012817382812500, +0.0000000000000000, 0.0001525878906250, 0.0000000000000000, -0.0002136230468750, +0.0000000000000000, 0.0002746582031250, 0.0000305175781250, 0.0013732910156250, +0.0000000000000000, 0.0006408691406250, -0.0000305175781250, 0.0019531250000000, +0.0000000000000000, 0.0018615722656250, 0.0000000000000000, 0.0018920898437500, +0.0000305175781250, 0.0026245117187500, 0.0000000000000000, 0.0023193359375000, +0.0000000000000000, 0.0025024414062500, 0.0000000000000000, 0.0027160644531250, +0.0000000000000000, 0.0024719238281250, 0.0000000000000000, 0.0024108886718750, +0.0000000000000000, 0.0025939941406250, -0.0000305175781250, 0.0021057128906250, +0.0000305175781250, 0.0022888183593750, 0.0000305175781250, 0.0021362304687500, +0.0000305175781250, 0.0017700195312500, 0.0000000000000000, 0.0021362304687500, +0.0000000000000000, 0.0016174316406250, 0.0000000000000000, 0.0018005371093750, +-0.0000305175781250, 0.0017395019531250, 0.0000000000000000, 0.0014038085937500, +0.0000305175781250, 0.0017395019531250, 0.0000000000000000, 0.0013732910156250, +0.0000305175781250, 0.0014343261718750, 0.0000305175781250, 0.0015258789062500, +-0.0000305175781250, 0.0013732910156250, 0.0000000000000000, 0.0015869140625000, +0.0000610351562500, 0.0015258789062500, 0.0000610351562500, 0.0016174316406250, +0.0000000000000000, 0.0016784667968750, 0.0000000000000000, 0.0017700195312500, +0.0000305175781250, 0.0018920898437500, 0.0000000000000000, 0.0019531250000000, +0.0000000000000000, 0.0020141601562500, 0.0000000000000000, 0.0020446777343750, +0.0000000000000000, 0.0021362304687500, 0.0000305175781250, 0.0021362304687500, +-0.0000305175781250, 0.0019531250000000, 0.0000000000000000, 0.0020751953125000, +0.0000000000000000, 0.0018310546875000, 0.0000000000000000, 0.0016174316406250, +0.0000000000000000, 0.0017395019531250, 0.0000305175781250, 0.0009460449218750, +0.0000000000000000, 0.0010681152343750, 0.0000000000000000, 0.0007019042968750, +0.0000000000000000, -0.0000610351562500, 0.0000000000000000, 0.0002136230468750, +-0.0000305175781250, -0.0007019042968750, 0.0000000000000000, -0.0007019042968750, +0.0000000000000000, -0.0007934570312500, 0.0000305175781250, -0.0013732910156250, +0.0000000000000000, -0.0012207031250000, 0.0000000000000000, -0.0012207031250000, +0.0000000000000000, -0.0014343261718750, -0.0000305175781250, -0.0010375976562500, +0.0000000000000000, -0.0007629394531250, 0.0000305175781250, -0.0009460449218750, +0.0000305175781250, -0.0000305175781250, 0.0000610351562500, -0.0000610351562500, +0.0000305175781250, 0.0001525878906250, 0.0000000000000000, 0.0008544921875000, +0.0000305175781250, 0.0006103515625000, 0.0000305175781250, 0.0008239746093750, +-0.0000305175781250, 0.0010681152343750, -0.0000305175781250, 0.0007019042968750, +0.0000000000000000, 0.0003662109375000, 0.0000000000000000, 0.0006408691406250, +-0.0000305175781250, -0.0001831054687500, 0.0000305175781250, -0.0002441406250000, +0.0000305175781250, -0.0002441406250000, -0.0000305175781250, -0.0008239746093750, +0.0000000000000000, -0.0006713867187500, 0.0000000000000000, -0.0003967285156250, +0.0000000000000000, -0.0006103515625000, -0.0000305175781250, -0.0002746582031250, +0.0000305175781250, 0.0002441406250000, 0.0000000000000000, -0.0000610351562500, +-0.0000610351562500, 0.0003967285156250, 0.0000305175781250, 0.0006103515625000, +0.0000305175781250, 0.0002746582031250, -0.0000305175781250, 0.0002136230468750, +0.0000305175781250, 0.0003662109375000, 0.0000000000000000, -0.0001831054687500, +-0.0000305175781250, -0.0002136230468750, -0.0000305175781250, -0.0000915527343750, +0.0000000000000000, -0.0003356933593750, 0.0000000000000000, -0.0003356933593750, +-0.0000305175781250, 0.0000610351562500, 0.0000610351562500, 0.0000000000000000, +0.0000610351562500, 0.0000610351562500, 0.0000000000000000, 0.0003662109375000, +0.0000000000000000, 0.0003356933593750, 0.0000305175781250, 0.0000610351562500, +-0.0000610351562500, 0.0001831054687500, -0.0000305175781250, 0.0000305175781250, +0.0000000000000000, -0.0002746582031250, -0.0000305175781250, -0.0001525878906250, +-0.0000610351562500, -0.0000610351562500, 0.0000610351562500, -0.0002136230468750, +0.0000915527343750, -0.0000915527343750, 0.0000000000000000, 0.0001831054687500, +0.0000305175781250, 0.0000305175781250, 0.0000915527343750, 0.0000915527343750, +-0.0000305175781250, 0.0002136230468750, -0.0000915527343750, 0.0000915527343750, +0.0000000000000000, -0.0001220703125000, 0.0000000000000000, -0.0001220703125000, +0.0000000000000000, 0.0000000000000000, 0.0000305175781250, -0.0001220703125000, +0.0000610351562500, -0.0000915527343750, 0.0000610351562500, 0.0001220703125000, +0.0000305175781250, 0.0000305175781250, 0.0000610351562500, 0.0000305175781250, +-0.0000915527343750, 0.0001220703125000, -0.0001220703125000, 0.0000305175781250, +-0.0000610351562500, -0.0001525878906250, -0.0000305175781250, 0.0000000000000000, +-0.0000305175781250, -0.0000305175781250, 0.0001220703125000, -0.0001220703125000, +0.0001220703125000, -0.0000305175781250, 0.0000305175781250, 0.0000915527343750, +0.0000000000000000, 0.0000305175781250, 0.0000610351562500, 0.0000305175781250, +-0.0001220703125000, 0.0001525878906250, -0.0001831054687500, 0.0000915527343750, +-0.0000610351562500, -0.0000915527343750, -0.0000305175781250, -0.0000305175781250, +-0.0001525878906250, 0.0000000000000000, 0.0001831054687500, -0.0001220703125000, +0.0002441406250000, -0.0000610351562500, 0.0000915527343750, 0.0000610351562500, +0.0001220703125000, 0.0000000000000000, 0.0002441406250000, 0.0000305175781250, +-0.0002136230468750, 0.0001220703125000, -0.0001831054687500, 0.0000305175781250, +-0.0000610351562500, -0.0000610351562500, -0.0003662109375000, -0.0000305175781250, +-0.0003967285156250, -0.0000305175781250, 0.0000915527343750, -0.0000610351562500, +-0.0000305175781250, 0.0000000000000000, 0.0000610351562500, 0.0000610351562500, +0.0004882812500000, 0.0000000000000000, 0.0003356933593750, 0.0000610351562500, +0.0001525878906250, 0.0000915527343750, 0.0004272460937500, 0.0000305175781250, +0.0000915527343750, -0.0000305175781250, -0.0003662109375000, 0.0000305175781250, +-0.0001220703125000, -0.0000305175781250, -0.0004882812500000, 0.0000000000000000, +-0.0006408691406250, 0.0000305175781250, -0.0003356933593750, 0.0000000000000000, +-0.0001831054687500, -0.0000305175781250, -0.0003967285156250, 0.0000305175781250, +0.0003356933593750, 0.0000305175781250, 0.0003356933593750, 0.0000305175781250, +0.0003662109375000, 0.0000000000000000, 0.0007324218750000, 0.0000305175781250, +0.0006408691406250}, +{0.0000305175781250, -0.0002441406250000, 0.0000610351562500, -0.0004272460937500, +0.0000305175781250, -0.0006713867187500, -0.0000305175781250, -0.0003356933593750, +0.0000305175781250, 0.0000000000000000, -0.0000610351562500, -0.0003051757812500, +-0.0000305175781250, 0.0003051757812500, 0.0000305175781250, 0.0004272460937500, +0.0000610351562500, 0.0001525878906250, 0.0000305175781250, 0.0002441406250000, +0.0000610351562500, 0.0003662109375000, 0.0000305175781250, -0.0001525878906250, +-0.0000305175781250, -0.0001831054687500, -0.0000305175781250, -0.0000915527343750, +0.0000000000000000, -0.0003356933593750, -0.0000610351562500, -0.0003356933593750, +-0.0000610351562500, 0.0000610351562500, 0.0000610351562500, -0.0000305175781250, +0.0000610351562500, 0.0000000000000000, 0.0000305175781250, 0.0003356933593750, +0.0000610351562500, 0.0002746582031250, 0.0001220703125000, 0.0000610351562500, +0.0000000000000000, 0.0001831054687500, -0.0000305175781250, 0.0000305175781250, +-0.0000305175781250, -0.0002441406250000, -0.0000610351562500, -0.0001220703125000, +-0.0000915527343750, -0.0000610351562500, 0.0000305175781250, -0.0002136230468750, +0.0000610351562500, -0.0000915527343750, 0.0000305175781250, 0.0001831054687500, +0.0000305175781250, 0.0001525878906250, 0.0000305175781250, 0.0000000000000000, +-0.0000610351562500, 0.0000610351562500, -0.0000610351562500, 0.0000305175781250, +0.0000000000000000, -0.0001525878906250, -0.0000305175781250, -0.0000610351562500, +-0.0000305175781250, 0.0000000000000000, 0.0000915527343750, -0.0000915527343750, +0.0000610351562500, -0.0000305175781250, 0.0000000000000000, 0.0001220703125000, +0.0000610351562500, 0.0000915527343750, 0.0001220703125000, 0.0000305175781250, +-0.0000915527343750, 0.0000915527343750, -0.0000915527343750, 0.0000305175781250, +0.0000000000000000, -0.0001220703125000, -0.0000610351562500, -0.0000915527343750, +-0.0000915527343750, -0.0000305175781250, 0.0001525878906250, -0.0000610351562500, +0.0001525878906250, -0.0000305175781250, 0.0000610351562500, 0.0000915527343750, +0.0001220703125000, 0.0000610351562500, 0.0001831054687500, 0.0000305175781250, +-0.0002136230468750, 0.0000915527343750, -0.0001831054687500, 0.0000000000000000, +-0.0000610351562500, -0.0000915527343750, -0.0003051757812500, -0.0000305175781250, +-0.0003051757812500, -0.0000610351562500, 0.0001220703125000, -0.0000915527343750, +0.0000000000000000, -0.0000305175781250, 0.0000610351562500, 0.0000915527343750, +0.0004577636718750, 0.0000305175781250, 0.0003662109375000, 0.0000305175781250, +0.0000305175781250, 0.0000915527343750, 0.0002136230468750, 0.0000305175781250, +0.0000000000000000, -0.0000610351562500, -0.0005187988281250, -0.0000305175781250, +-0.0002441406250000, -0.0000305175781250, -0.0003662109375000, -0.0000610351562500, +-0.0005798339843750, 0.0000000000000000, -0.0002136230468750, 0.0000610351562500, +0.0001220703125000, 0.0000000000000000, -0.0001525878906250, 0.0000000000000000, +0.0004272460937500, 0.0000610351562500, 0.0005493164062500, 0.0000305175781250, +0.0002746582031250, -0.0000305175781250, 0.0003662109375000, 0.0000000000000000, +0.0005187988281250, -0.0000305175781250, -0.0002746582031250, -0.0000610351562500, +-0.0001525878906250, -0.0000305175781250, -0.0002746582031250, 0.0000000000000000, +-0.0008850097656250, -0.0000305175781250, -0.0006713867187500, 0.0000305175781250, +-0.0005493164062500, 0.0000305175781250, -0.0007629394531250, 0.0000305175781250, +-0.0003356933593750, 0.0000000000000000, 0.0001831054687500, 0.0000000000000000, +-0.0001220703125000, 0.0000000000000000, 0.0007019042968750, 0.0000000000000000, +0.0007934570312500, 0.0000000000000000, 0.0007019042968750, 0.0000000000000000, +0.0010681152343750, -0.0000305175781250, 0.0010375976562500, -0.0000305175781250, +0.0006103515625000, 0.0000305175781250, 0.0008239746093750, 0.0000000000000000, +0.0003967285156250, 0.0000000000000000, -0.0001831054687500, 0.0000305175781250, +0.0000915527343750, 0.0000000000000000, -0.0008239746093750, -0.0000305175781250, +-0.0008239746093750, 0.0000000000000000, -0.0009765625000000, 0.0000000000000000, +-0.0015563964843750, 0.0000000000000000, -0.0013732910156250, 0.0000000000000000, +-0.0016174316406250, 0.0000305175781250, -0.0017395019531250, -0.0000305175781250, +-0.0015869140625000, 0.0000000000000000, -0.0015869140625000, 0.0000000000000000, +-0.0015869140625000, 0.0000000000000000, -0.0012207031250000, 0.0000000000000000, +-0.0012207031250000, 0.0000000000000000, -0.0010375976562500, 0.0000000000000000, +-0.0006713867187500, -0.0000305175781250, -0.0007019042968750, 0.0000000000000000, +-0.0003662109375000, 0.0000000000000000, -0.0002441406250000, 0.0000000000000000, +-0.0000915527343750, 0.0000305175781250, 0.0000915527343750, 0.0000000000000000, +0.0001220703125000, -0.0000305175781250, 0.0003356933593750, 0.0000000000000000, +0.0004882812500000, 0.0000000000000000, 0.0004882812500000, 0.0000000000000000, +0.0005187988281250, 0.0000610351562500, 0.0006103515625000, 0.0000000000000000, +0.0004577636718750, 0.0000000000000000, 0.0005493164062500, -0.0000305175781250, +0.0005493164062500, 0.0000305175781250, 0.0004272460937500, 0.0000000000000000, +0.0004882812500000, 0.0000000000000000, 0.0001525878906250, 0.0000000000000000, +0.0003356933593750, 0.0000000000000000, 0.0001831054687500, 0.0000000000000000, +-0.0001220703125000, 0.0000000000000000, 0.0001220703125000, 0.0000000000000000, +-0.0005798339843750, -0.0000305175781250, -0.0004577636718750, -0.0000305175781250, +-0.0006408691406250, 0.0000000000000000, -0.0012207031250000, 0.0000610351562500, +-0.0008239746093750, 0.0000000000000000, -0.0017089843750000, 0.0000000000000000, +-0.0015869140625000, 0.0000000000000000, -0.0016784667968750, 0.0000305175781250, +-0.0022888183593750, 0.0000000000000000, -0.0020141601562500, 0.0000305175781250, +-0.0020751953125000, 0.0000000000000000, -0.0023498535156250, -0.0000305175781250, +-0.0018920898437500, -0.0000305175781250, -0.0016174316406250, -0.0000305175781250, +-0.0019836425781250, 0.0000000000000000, -0.0005187988281250, 0.0000305175781250, +-0.0008850097656250, 0.0000000000000000, -0.0003051757812500, 0.0000000000000000, +0.0009460449218750, 0.0000305175781250, 0.0002441406250000, 0.0000000000000000, +0.0014648437500000, 0.0000305175781250, 0.0015869140625000, 0.0000000000000000, +0.0012817382812500, -0.0000305175781250, 0.0017395019531250, -0.0000305175781250, +0.0018005371093750, 0.0000000000000000, 0.0007324218750000, 0.0000000000000000, +0.0010986328125000, 0.0000000000000000, 0.0004882812500000, 0.0000305175781250, +-0.0006408691406250, 0.0000305175781250, 0.0000305175781250, 0.0000000000000000, +-0.0011291503906250, 0.0000000000000000, -0.0013427734375000, 0.0000000000000000, +-0.0010986328125000, -0.0000305175781250, -0.0014648437500000, -0.0000305175781250, +-0.0014953613281250, 0.0000000000000000, -0.0005798339843750, -0.0000305175781250, +-0.0008544921875000, 0.0000000000000000, -0.0003356933593750, 0.0000610351562500, +0.0006103515625000, 0.0000305175781250, 0.0001525878906250, 0.0000000000000000, +0.0008544921875000, 0.0000000000000000, 0.0011596679687500, 0.0000000000000000, +0.0007324218750000, -0.0000610351562500, 0.0006103515625000, -0.0000305175781250, +0.0008544921875000, 0.0000305175781250, -0.0002136230468750, -0.0000305175781250, +-0.0000915527343750, -0.0000305175781250, -0.0002136230468750, 0.0001220703125000, +-0.0009460449218750, 0.0000305175781250, -0.0006408691406250, 0.0000610351562500, +-0.0004882812500000, 0.0000610351562500, -0.0007934570312500, 0.0000000000000000, +-0.0004272460937500, -0.0001220703125000, 0.0001525878906250, -0.0000610351562500, +-0.0002441406250000, -0.0000305175781250, 0.0004882812500000, -0.0000915527343750, +0.0006408691406250, 0.0000305175781250, 0.0003662109375000, 0.0001220703125000, +0.0005187988281250, 0.0000305175781250, 0.0006713867187500, 0.0000610351562500, +-0.0002136230468750, 0.0001525878906250, -0.0000915527343750, 0.0000610351562500, +-0.0001525878906250, -0.0000610351562500, -0.0008544921875000, 0.0000305175781250, +-0.0006713867187500, -0.0001220703125000, -0.0001831054687500, -0.0001831054687500, +-0.0005798339843750, -0.0000610351562500, -0.0001525878906250, 0.0000000000000000, +0.0007019042968750, -0.0001220703125000, 0.0002746582031250, 0.0001831054687500, +0.0003662109375000, 0.0001831054687500, 0.0008239746093750, 0.0000915527343750, +0.0002441406250000, 0.0001831054687500, -0.0004272460937500, 0.0002136230468750, +0.0000610351562500, -0.0001831054687500, -0.0004882812500000, -0.0001525878906250, +-0.0007934570312500, -0.0000915527343750, -0.0003662109375000, -0.0003662109375000, +0.0001525878906250, 0.0003051757812500, 0.0001525878906250, -0.0000305175781250, +-0.0004272460937500, 0.0002441406250000, -0.0007019042968750, 0.0000000000000000, +-0.0002136230468750, -0.0005798339843750, 0.0001831054687500, -0.0003051757812500, +-0.0001831054687500, -0.0001831054687500, 0.0003662109375000, -0.0004577636718750, +0.0005798339843750, -0.0000915527343750, 0.0001831054687500, 0.0005187988281250, +0.0000000000000000, 0.0000610351562500, 0.0003051757812500, 0.0005493164062500, +-0.0003051757812500, 0.0009155273437500, -0.0004577636718750, 0.0003051757812500, +-0.0001525878906250, -0.0000305175781250, -0.0001220703125000, 0.0004577636718750, +-0.0002746582031250, -0.0006713867187500, 0.0002136230468750, -0.0008850097656250, +0.0003051757812500, -0.0004272460937500, 0.0001220703125000, -0.0006408691406250, +0.0001525878906250, -0.0009155273437500, 0.0002136230468750, 0.0003967285156250, +-0.0001220703125000, 0.0002746582031250, -0.0001525878906250, 0.0002441406250000, +-0.0000305175781250, 0.0010986328125000, -0.0001220703125000, 0.0009765625000000, +-0.0001831054687500, 0.0000915527343750, 0.0001220703125000, 0.0006103515625000, +0.0001525878906250, 0.0000610351562500, 0.0000305175781250, -0.0010986328125000, +0.0001220703125000, -0.0005187988281250, 0.0001525878906250, -0.0007934570312500, +-0.0000610351562500, -0.0013732910156250, -0.0000915527343750, -0.0005798339843750, +-0.0000305175781250, 0.0000915527343750, -0.0000915527343750, -0.0005187988281250, +-0.0001220703125000, 0.0007934570312500, 0.0000610351562500, 0.0009765625000000, +0.0000610351562500, 0.0005798339843750, 0.0000305175781250, 0.0010375976562500, +0.0000915527343750, 0.0011291503906250, 0.0001220703125000, -0.0000915527343750, +-0.0000305175781250, 0.0003051757812500, -0.0000305175781250, -0.0001220703125000, +0.0000000000000000, -0.0012817382812500, -0.0000610351562500, -0.0006408691406250, +-0.0000610351562500, -0.0010681152343750, 0.0000305175781250, -0.0015563964843750, +0.0000305175781250, -0.0008850097656250, 0.0000000000000000, -0.0004882812500000, +0.0000305175781250, -0.0009765625000000, 0.0000610351562500, 0.0005187988281250, +-0.0000305175781250, 0.0003967285156250, -0.0000305175781250, 0.0004882812500000, +0.0000000000000000, 0.0014648437500000, -0.0000610351562500, 0.0010986328125000, +-0.0000305175781250, 0.0011901855468750, 0.0000305175781250, 0.0014953613281250, +0.0000305175781250, 0.0010375976562500, 0.0000305175781250, 0.0007324218750000, +0.0000610351562500, 0.0010986328125000, 0.0000305175781250, -0.0002746582031250, +0.0000000000000000, -0.0000610351562500, -0.0000305175781250, -0.0004882812500000, +0.0000000000000000, -0.0015258789062500, 0.0000000000000000, -0.0009155273437500, +0.0000000000000000, -0.0018310546875000, 0.0000000000000000, -0.0019836425781250, +0.0000305175781250}, +{0.0000000000000000, 0.0001525878906250, 0.0002441406250000, 0.0000610351562500, +-0.0000305175781250, 0.0001220703125000, -0.0008544921875000, 0.0001525878906250, +-0.0005798339843750, -0.0001831054687500, -0.0002136230468750, -0.0001220703125000, +-0.0006103515625000, -0.0000915527343750, -0.0001831054687500, -0.0002746582031250, +0.0007324218750000, -0.0002441406250000, 0.0002441406250000, 0.0000915527343750, +0.0004577636718750, 0.0000305175781250, 0.0008239746093750, 0.0000305175781250, +0.0003967285156250, 0.0004577636718750, -0.0004577636718750, -0.0002441406250000, +0.0001220703125000, -0.0000915527343750, 0.0003356933593750, -0.0003967285156250, +0.0007629394531250, -0.0000305175781250, 0.0002136230468750, 0.0004882812500000, +-0.0003662109375000, 0.0001831054687500, 0.0000000000000000, 0.0003662109375000, +-0.0003051757812500, 0.0006713867187500, -0.0006408691406250, 0.0002136230468750, +-0.0002136230468750, -0.0001831054687500, 0.0002746582031250, 0.0001525878906250, +-0.0001220703125000, -0.0006713867187500, 0.0002746582031250, -0.0008850097656250, +0.0005493164062500, -0.0003662109375000, 0.0001831054687500, -0.0003967285156250, +-0.0000610351562500, -0.0007019042968750, 0.0002136230468750, 0.0005798339843750, +-0.0001831054687500, 0.0005493164062500, -0.0003662109375000, 0.0003356933593750, +-0.0001220703125000, 0.0010070800781250, 0.0000000000000000, 0.0009765625000000, +-0.0001831054687500, -0.0002136230468750, 0.0001831054687500, 0.0001525878906250, +0.0002746582031250, -0.0000915527343750, 0.0000610351562500, -0.0012817382812500, +0.0000305175781250, -0.0008239746093750, 0.0001525878906250, -0.0004882812500000, +-0.0001525878906250, -0.0010375976562500, -0.0002136230468750, -0.0003356933593750, +-0.0000610351562500, 0.0007019042968750, -0.0000305175781250, 0.0000305175781250, +-0.0001220703125000, 0.0009155273437500, 0.0000915527343750, 0.0013732910156250, +0.0001831054687500, 0.0006103515625000, 0.0000610351562500, 0.0003356933593750, +0.0000305175781250, 0.0008544921875000, 0.0001220703125000, -0.0007629394531250, +-0.0000610351562500, -0.0007324218750000, -0.0001220703125000, -0.0005493164062500, +-0.0000305175781250, -0.0013427734375000, -0.0000305175781250, -0.0012512207031250, +-0.0001220703125000, -0.0003967285156250, 0.0000610351562500, -0.0008544921875000, +0.0000610351562500, -0.0002746582031250, 0.0000000000000000, 0.0008544921875000, +0.0000000000000000, 0.0001525878906250, 0.0000610351562500, 0.0011291503906250, +-0.0000305175781250, 0.0014343261718750, -0.0000915527343750, 0.0008850097656250, +-0.0000305175781250, 0.0008544921875000, -0.0000305175781250, 0.0011901855468750, +-0.0000610351562500, -0.0001831054687500, 0.0000610351562500, 0.0000915527343750, +0.0000610351562500, -0.0002746582031250, 0.0000000000000000, -0.0014038085937500, +0.0000000000000000, -0.0008239746093750, 0.0000305175781250, -0.0014953613281250, +0.0000000000000000, -0.0017700195312500, -0.0000305175781250, -0.0013427734375000, +-0.0000305175781250, -0.0013732910156250, 0.0000305175781250, -0.0015563964843750, +-0.0000305175781250, -0.0003662109375000, 0.0000000000000000, -0.0007934570312500, +0.0000610351562500, -0.0001525878906250, 0.0000000000000000, 0.0009460449218750, +-0.0000305175781250, 0.0001831054687500, 0.0000305175781250, 0.0015563964843750, +-0.0000305175781250, 0.0015258789062500, -0.0000305175781250, 0.0014038085937500, +0.0000000000000000, 0.0021667480468750, 0.0000305175781250, 0.0019531250000000, +0.0000000000000000, 0.0017395019531250, 0.0000000000000000, 0.0021362304687500, +0.0000000000000000, 0.0015563964843750, 0.0000000000000000, 0.0009765625000000, +0.0000000000000000, 0.0015869140625000, 0.0000000000000000, -0.0000305175781250, +0.0000000000000000, 0.0003662109375000, 0.0000000000000000, -0.0000610351562500, +0.0000305175781250, -0.0012817382812500, 0.0000305175781250, -0.0004577636718750, +0.0000000000000000, -0.0019836425781250, 0.0000000000000000, -0.0017700195312500, +0.0000305175781250, -0.0019226074218750, 0.0000305175781250, -0.0028686523437500, +-0.0000305175781250, -0.0023498535156250, 0.0000000000000000, -0.0029602050781250, +0.0000000000000000, -0.0029907226562500, 0.0000000000000000, -0.0029907226562500, +0.0000305175781250, -0.0032348632812500, 0.0000305175781250, -0.0030822753906250, +0.0000000000000000, -0.0031738281250000, 0.0000000000000000, -0.0032043457031250, +0.0000000000000000, -0.0032043457031250, 0.0000000000000000, -0.0031738281250000, +0.0000000000000000, -0.0031738281250000, 0.0000000000000000, -0.0030822753906250, +0.0000000000000000, -0.0030822753906250, 0.0000305175781250, -0.0030822753906250, +0.0000305175781250, -0.0029602050781250, -0.0000305175781250, -0.0029907226562500, +0.0000000000000000, -0.0028991699218750, 0.0000000000000000, -0.0029296875000000, +0.0000000000000000, -0.0028381347656250, 0.0000000000000000, -0.0026855468750000, +0.0000000000000000, -0.0026550292968750, 0.0000000000000000, -0.0023193359375000, +0.0000000000000000, -0.0023803710937500, 0.0000000000000000, -0.0021057128906250, +0.0000000000000000, -0.0017089843750000, 0.0000305175781250, -0.0018615722656250, +-0.0000305175781250, -0.0009765625000000, -0.0000305175781250, -0.0010986328125000, +0.0000000000000000, -0.0007324218750000, 0.0000000000000000, 0.0000305175781250, +0.0000000000000000, -0.0002746582031250, 0.0000000000000000, 0.0006713867187500, +-0.0000305175781250, 0.0007324218750000, 0.0000305175781250, 0.0008544921875000, +0.0000000000000000, 0.0015258789062500, 0.0000000000000000, 0.0014038085937500, +0.0000000000000000, 0.0015563964843750, -0.0000305175781250, 0.0017089843750000, +0.0000000000000000, 0.0014038085937500, 0.0000000000000000, 0.0011901855468750, +0.0000000000000000, 0.0013427734375000, 0.0000305175781250, 0.0003662109375000, +0.0000610351562500, 0.0004882812500000, 0.0000000000000000, 0.0001525878906250, +0.0000000000000000, -0.0007324218750000, 0.0000000000000000, -0.0003967285156250, +0.0000610351562500, -0.0010986328125000, 0.0000305175781250, -0.0012207031250000, +-0.0000305175781250, -0.0010375976562500, 0.0000000000000000, -0.0012207031250000, +0.0000000000000000, -0.0012817382812500, -0.0000305175781250, -0.0004272460937500, +-0.0000305175781250, -0.0006713867187500, 0.0000000000000000, -0.0002441406250000, +0.0000305175781250, 0.0006103515625000, 0.0000305175781250, 0.0002441406250000, +0.0000305175781250, 0.0007324218750000, -0.0000305175781250, 0.0009765625000000, +0.0000000000000000, 0.0005798339843750, 0.0000305175781250, 0.0005187988281250, +-0.0000305175781250, 0.0007019042968750, -0.0000305175781250, -0.0002136230468750, +0.0000000000000000, -0.0001831054687500, 0.0000000000000000, -0.0001831054687500, +0.0000305175781250, -0.0008239746093750, 0.0000610351562500, -0.0006408691406250, +0.0000610351562500, -0.0003051757812500, 0.0000305175781250, -0.0005493164062500, +0.0000000000000000, -0.0002441406250000, -0.0000305175781250, 0.0003356933593750, +-0.0000610351562500, 0.0000610351562500, 0.0000000000000000, 0.0003051757812500, +0.0000610351562500, 0.0005798339843750, -0.0000305175781250, 0.0001831054687500, +-0.0000305175781250, -0.0000915527343750, 0.0000915527343750, 0.0001831054687500, +0.0000915527343750, -0.0003356933593750, -0.0000305175781250, -0.0004882812500000, +0.0000000000000000, -0.0002136230468750, 0.0000305175781250, -0.0001831054687500, +-0.0000915527343750, -0.0003051757812500, -0.0000610351562500, 0.0002136230468750, +0.0000305175781250, 0.0002441406250000, 0.0000000000000000, 0.0000915527343750, +0.0000000000000000, 0.0002746582031250, 0.0001220703125000, 0.0003662109375000, +0.0000610351562500, -0.0001220703125000, -0.0000305175781250, -0.0000915527343750, +0.0000610351562500, -0.0000305175781250, 0.0000000000000000, -0.0002746582031250, +-0.0001220703125000, -0.0003051757812500, -0.0000610351562500, 0.0000305175781250, +0.0000610351562500, -0.0000305175781250, -0.0000610351562500, 0.0000000000000000, +0.0000000000000000, 0.0002136230468750, 0.0001220703125000, 0.0001525878906250, +0.0000610351562500, -0.0001220703125000, -0.0000610351562500, -0.0000610351562500, +0.0000305175781250, 0.0000000000000000, 0.0000305175781250, -0.0001220703125000, +-0.0001220703125000, -0.0001220703125000, -0.0000610351562500, 0.0000915527343750, +0.0000610351562500, 0.0000000000000000, 0.0000000000000000, 0.0000000000000000, +0.0000000000000000, 0.0001220703125000, 0.0001525878906250, 0.0001525878906250, +0.0000915527343750, -0.0000305175781250, -0.0000305175781250, 0.0000000000000000, +-0.0000305175781250, 0.0000305175781250, 0.0000000000000000, -0.0000915527343750, +-0.0001831054687500, -0.0001220703125000, -0.0001831054687500, 0.0000610351562500, +0.0000915527343750, 0.0000305175781250, 0.0000000000000000, -0.0000305175781250, +0.0000610351562500, 0.0001525878906250, 0.0002746582031250, 0.0001525878906250, +0.0001831054687500, -0.0000305175781250, -0.0000915527343750, 0.0000000000000000, +0.0000915527343750, 0.0000000000000000, -0.0000305175781250, -0.0001525878906250, +-0.0004272460937500, -0.0000915527343750, -0.0003051757812500, 0.0000000000000000, +-0.0000915527343750, 0.0000000000000000, -0.0003356933593750, 0.0000305175781250, +-0.0000610351562500, 0.0001220703125000, 0.0003967285156250, 0.0001525878906250, +0.0001525878906250, 0.0000000000000000, 0.0002746582031250, 0.0000305175781250, +0.0005187988281250, 0.0000305175781250, 0.0001831054687500, -0.0000915527343750, +-0.0001525878906250, -0.0000305175781250, 0.0001220703125000, -0.0000305175781250, +-0.0004272460937500, -0.0000305175781250, -0.0006103515625000, 0.0000000000000000, +-0.0003051757812500, 0.0000915527343750, -0.0003051757812500, 0.0000610351562500, +-0.0004882812500000, 0.0000000000000000, 0.0002441406250000, 0.0000305175781250, +0.0001831054687500, 0.0000610351562500, 0.0001831054687500, -0.0000305175781250, +0.0006408691406250, 0.0000000000000000, 0.0005798339843750, 0.0000000000000000, +0.0001831054687500, -0.0000305175781250, 0.0004577636718750, 0.0000000000000000, +0.0000305175781250, 0.0000610351562500, -0.0006103515625000, 0.0000305175781250, +-0.0003051757812500, 0.0000305175781250, -0.0008239746093750, 0.0000000000000000, +-0.0010681152343750, 0.0000305175781250, -0.0006408691406250, -0.0000305175781250, +-0.0006408691406250, 0.0000000000000000, -0.0007934570312500, -0.0000305175781250, +0.0001220703125000, -0.0000610351562500, 0.0000610351562500, -0.0000305175781250, +0.0003051757812500, 0.0000305175781250, 0.0010375976562500, 0.0000000000000000, +0.0007934570312500, 0.0000305175781250, 0.0010375976562500, 0.0000000000000000, +0.0012512207031250, 0.0000000000000000, 0.0009155273437500, -0.0000305175781250, +0.0007629394531250, 0.0000000000000000, 0.0009155273437500, 0.0000000000000000, +0.0000000000000000, -0.0000305175781250, 0.0001525878906250, 0.0000000000000000, +-0.0001525878906250, 0.0000000000000000, -0.0009155273437500, 0.0000305175781250, +-0.0006713867187500, 0.0000000000000000, -0.0013732910156250, 0.0000000000000000, +-0.0014648437500000, 0.0000000000000000, -0.0015258789062500, 0.0000000000000000, +-0.0019226074218750, -0.0000305175781250, -0.0018310546875000, 0.0000000000000000, +-0.0019836425781250, -0.0000305175781250, -0.0020141601562500, 0.0000000000000000, +-0.0019226074218750, 0.0000610351562500, -0.0018310546875000, 0.0000000000000000, +-0.0018310546875000, 0.0000305175781250, -0.0016174316406250, 0.0000000000000000, +-0.0015563964843750, 0.0000000000000000, -0.0014648437500000, -0.0000305175781250, +-0.0013122558593750}, +{-0.0000305175781250, 0.0001220703125000, 0.0001525878906250, 0.0001831054687500, +0.0000915527343750, -0.0000915527343750, 0.0000000000000000, -0.0001220703125000, +0.0000610351562500, -0.0000305175781250, 0.0000000000000000, -0.0000915527343750, +-0.0001525878906250, -0.0001220703125000, -0.0000915527343750, 0.0000915527343750, +0.0000305175781250, 0.0001220703125000, -0.0000915527343750, 0.0000305175781250, +-0.0000305175781250, 0.0000915527343750, 0.0002136230468750, 0.0001525878906250, +0.0001525878906250, -0.0000610351562500, 0.0000000000000000, -0.0000915527343750, +0.0000915527343750, -0.0000610351562500, -0.0000305175781250, -0.0000915527343750, +-0.0003051757812500, -0.0001220703125000, -0.0002136230468750, 0.0000610351562500, +-0.0000610351562500, 0.0000610351562500, -0.0002746582031250, 0.0000000000000000, +-0.0000305175781250, 0.0001220703125000, 0.0003662109375000, 0.0001220703125000, +0.0001220703125000, -0.0000610351562500, 0.0001525878906250, 0.0000000000000000, +0.0004272460937500, 0.0000000000000000, 0.0000610351562500, -0.0000915527343750, +-0.0003356933593750, -0.0000610351562500, -0.0000305175781250, 0.0000305175781250, +-0.0004272460937500, 0.0000000000000000, -0.0006103515625000, 0.0000000000000000, +-0.0003051757812500, 0.0000915527343750, -0.0000915527343750, 0.0000915527343750, +-0.0003051757812500, 0.0000000000000000, 0.0003662109375000, -0.0000305175781250, +0.0004272460937500, 0.0000305175781250, 0.0002441406250000, -0.0000305175781250, +0.0004577636718750, -0.0000610351562500, 0.0005493164062500, 0.0000610351562500, +-0.0001525878906250, -0.0000305175781250, 0.0000000000000000, -0.0000305175781250, +-0.0001831054687500, 0.0000610351562500, -0.0008239746093750, 0.0000915527343750, +-0.0005798339843750, 0.0000000000000000, -0.0004882812500000, 0.0000305175781250, +-0.0007629394531250, 0.0000305175781250, -0.0003051757812500, -0.0000305175781250, +0.0002441406250000, -0.0000305175781250, -0.0000610351562500, 0.0000000000000000, +0.0006713867187500, -0.0000305175781250, 0.0008239746093750, -0.0000305175781250, +0.0006408691406250, 0.0000305175781250, 0.0008239746093750, 0.0000305175781250, +0.0008544921875000, 0.0000000000000000, 0.0000000000000000, 0.0000305175781250, +0.0002136230468750, 0.0000000000000000, -0.0001220703125000, -0.0000305175781250, +-0.0009460449218750, 0.0000000000000000, -0.0005493164062500, 0.0000000000000000, +-0.0011901855468750, 0.0000000000000000, -0.0013427734375000, 0.0000000000000000, +-0.0011596679687500, 0.0000000000000000, -0.0012512207031250, 0.0000000000000000, +-0.0012512207031250, 0.0000000000000000, -0.0006103515625000, 0.0000305175781250, +-0.0007629394531250, 0.0000610351562500, -0.0004272460937500, -0.0000305175781250, +0.0001831054687500, -0.0000305175781250, -0.0000305175781250, 0.0000305175781250, +0.0008544921875000, 0.0000000000000000, 0.0008544921875000, 0.0000000000000000, +0.0010375976562500, 0.0000000000000000, 0.0016174316406250, 0.0000305175781250, +0.0014343261718750, 0.0000000000000000, 0.0017700195312500, 0.0000000000000000, +0.0019226074218750, 0.0000305175781250, 0.0018615722656250, 0.0000000000000000, +0.0019836425781250, 0.0000000000000000, 0.0019531250000000, 0.0000000000000000, +0.0018615722656250, 0.0000000000000000, 0.0018615722656250, 0.0000000000000000, +0.0017395019531250, 0.0000000000000000, 0.0016784667968750, 0.0000000000000000, +0.0016479492187500, 0.0000000000000000, 0.0015563964843750, 0.0000000000000000, +0.0014038085937500, 0.0000000000000000, 0.0014038085937500, 0.0000000000000000, +0.0014038085937500, 0.0000000000000000, 0.0012817382812500, 0.0000305175781250, +0.0014343261718750, -0.0000305175781250, 0.0013732910156250, 0.0000000000000000, +0.0014343261718750, 0.0000000000000000, 0.0016174316406250, 0.0000000000000000, +0.0014953613281250, 0.0000000000000000, 0.0017700195312500, 0.0000305175781250, +0.0016784667968750, 0.0000305175781250, 0.0018615722656250, 0.0000000000000000, +0.0020751953125000, 0.0000000000000000, 0.0018615722656250, 0.0000000000000000, +0.0022888183593750, 0.0000000000000000, 0.0022888183593750, 0.0000000000000000, +0.0022277832031250, -0.0000305175781250, 0.0025024414062500, 0.0000000000000000, +0.0023498535156250, 0.0000000000000000, 0.0022888183593750, 0.0000000000000000, +0.0025024414062500, 0.0000000000000000, 0.0021057128906250, -0.0000305175781250, +0.0017700195312500, 0.0000305175781250, 0.0021667480468750, 0.0000000000000000, +0.0007629394531250, 0.0000000000000000, 0.0011901855468750, 0.0000000000000000, +0.0006408691406250, 0.0000000000000000, -0.0006408691406250, -0.0000305175781250, +0.0001831054687500, 0.0000000000000000, -0.0014343261718750, 0.0000305175781250, +-0.0015258789062500, 0.0000000000000000, -0.0014038085937500, -0.0000305175781250, +-0.0021972656250000, 0.0000305175781250, -0.0020141601562500, 0.0000000000000000, +-0.0014648437500000, -0.0000305175781250, -0.0019226074218750, 0.0000000000000000, +-0.0011596679687500, 0.0000000000000000, -0.0002136230468750, 0.0000000000000000, +-0.0009155273437500, 0.0000305175781250, 0.0007934570312500, 0.0000305175781250, +0.0007934570312500, 0.0000305175781250, 0.0008544921875000, 0.0000305175781250, +0.0018920898437500, 0.0000000000000000, 0.0015258789062500, 0.0000000000000000, +0.0011901855468750, -0.0000305175781250, 0.0016479492187500, 0.0000000000000000, +0.0010070800781250, 0.0000305175781250, 0.0001525878906250, 0.0000000000000000, +0.0006713867187500, 0.0000305175781250, -0.0007934570312500, 0.0000610351562500, +-0.0009155273437500, 0.0000305175781250, -0.0007934570312500, -0.0000305175781250, +-0.0014953613281250, 0.0000305175781250, -0.0013427734375000, 0.0000000000000000, +-0.0007019042968750, -0.0000915527343750, -0.0010986328125000, 0.0000000000000000, +-0.0004882812500000, 0.0000000000000000, 0.0004882812500000, 0.0000000000000000, +0.0000000000000000, 0.0000305175781250, 0.0007629394531250, 0.0000610351562500, +0.0010681152343750, 0.0000305175781250, 0.0006103515625000, 0.0000305175781250, +0.0005798339843750, 0.0000305175781250, 0.0007934570312500, -0.0000305175781250, +-0.0002136230468750, -0.0000915527343750, -0.0000610351562500, -0.0000305175781250, +-0.0001831054687500, 0.0000000000000000, -0.0009460449218750, -0.0000610351562500, +-0.0007019042968750, 0.0000915527343750, -0.0005187988281250, 0.0001220703125000, +-0.0009155273437500, 0.0000305175781250, -0.0003356933593750, 0.0000610351562500, +0.0003051757812500, 0.0000915527343750, -0.0001831054687500, -0.0000610351562500, +0.0006713867187500, -0.0000915527343750, 0.0009155273437500, -0.0000610351562500, +0.0004272460937500, -0.0001220703125000, 0.0003967285156250, -0.0001220703125000, +0.0006713867187500, 0.0001220703125000, -0.0005187988281250, 0.0000915527343750, +-0.0005493164062500, 0.0000610351562500, -0.0003051757812500, 0.0002746582031250, +-0.0008850097656250, 0.0002136230468750, -0.0009460449218750, -0.0000610351562500, +0.0002441406250000, 0.0000610351562500, 0.0000000000000000, -0.0000305175781250, +0.0000610351562500, -0.0003356933593750, 0.0010070800781250, -0.0002441406250000, +0.0007629394531250, -0.0000915527343750, 0.0000915527343750, -0.0002441406250000, +0.0004272460937500, -0.0001220703125000, 0.0002441406250000, 0.0004882812500000, +-0.0009460449218750, 0.0000915527343750, 0.0006713867187500, -0.0003967285156250, +-0.0001220703125000, -0.0005493164062500, 0.0004882812500000, -0.0001525878906250, +0.0000915527343750, 0.0000915527343750, -0.0007629394531250, -0.0002441406250000, +-0.0005187988281250, 0.0004882812500000, -0.0001220703125000, 0.0007324218750000, +-0.0004272460937500, 0.0003356933593750, -0.0001220703125000, 0.0004577636718750, +0.0006103515625000, 0.0006408691406250, 0.0003051757812500, -0.0005493164062500, +0.0001220703125000, -0.0004882812500000, 0.0004882812500000, -0.0003356933593750, +0.0002136230468750, -0.0010986328125000, -0.0003662109375000, -0.0010375976562500, +-0.0001525878906250, 0.0000915527343750, -0.0001525878906250, -0.0003356933593750, +-0.0004272460937500, 0.0000305175781250, -0.0001220703125000, 0.0012817382812500, +0.0002746582031250, 0.0007629394531250, 0.0000610351562500, 0.0003662109375000, +0.0001525878906250, 0.0010681152343750, 0.0003967285156250, 0.0002746582031250, +0.0001525878906250, -0.0009460449218750, -0.0001831054687500, -0.0001525878906250, +0.0000000000000000, -0.0009460449218750, -0.0001220703125000, -0.0015258789062500, +-0.0002441406250000, -0.0006408691406250, -0.0000915527343750, -0.0002441406250000, +0.0001220703125000, -0.0008850097656250, -0.0000305175781250, 0.0008544921875000, +0.0000915527343750, 0.0009155273437500, 0.0002441406250000, 0.0005493164062500, +0.0000915527343750, 0.0012512207031250, -0.0000610351562500, 0.0012817382812500, +0.0000305175781250, -0.0001220703125000, -0.0000610351562500, 0.0002441406250000, +-0.0001220703125000, -0.0000915527343750, 0.0000000000000000, -0.0013732910156250, +0.0000915527343750, -0.0007934570312500, 0.0000305175781250, -0.0010070800781250, +0.0000305175781250, -0.0015563964843750, 0.0001220703125000, -0.0007629394531250, +0.0000305175781250, -0.0001525878906250, -0.0000610351562500, -0.0007934570312500, +0.0000305175781250, 0.0008544921875000, -0.0000305175781250, 0.0007934570312500, +-0.0000915527343750, 0.0006713867187500, 0.0000000000000000, 0.0015563964843750, +0.0000610351562500, 0.0013732910156250, 0.0000000000000000, 0.0006408691406250, +0.0000305175781250, 0.0012207031250000, 0.0000915527343750, 0.0005798339843750, +0.0000305175781250, -0.0004577636718750, -0.0000305175781250, 0.0001831054687500, +-0.0000305175781250, -0.0011596679687500, -0.0000305175781250, -0.0011901855468750, +-0.0000610351562500, -0.0011291503906250, 0.0000000000000000, -0.0019226074218750, +0.0000305175781250, -0.0016479492187500, 0.0000000000000000, -0.0013732910156250, +0.0000305175781250, -0.0017700195312500, 0.0000000000000000, -0.0011291503906250, +0.0000305175781250, -0.0004577636718750, -0.0000305175781250, -0.0010681152343750, +-0.0000305175781250, 0.0006103515625000, 0.0000000000000000, 0.0003051757812500, +-0.0000305175781250, 0.0006103515625000, 0.0000000000000000, 0.0018615722656250, +0.0000305175781250, 0.0011596679687500, 0.0000000000000000, 0.0020751953125000, +0.0000000000000000, 0.0022888183593750, 0.0000305175781250, 0.0019226074218750, +0.0000305175781250, 0.0022277832031250, 0.0000305175781250, 0.0023803710937500, +0.0000000000000000, 0.0015258789062500, 0.0000305175781250, 0.0018615722656250, +0.0000000000000000, 0.0014343261718750, -0.0000305175781250, 0.0006408691406250, +0.0000000000000000, 0.0013427734375000, -0.0000305175781250, -0.0002441406250000, +-0.0000305175781250, 0.0001525878906250, 0.0000305175781250, -0.0001220703125000, +0.0000305175781250, -0.0012817382812500, 0.0000000000000000, -0.0006103515625000, +0.0000000000000000, -0.0017089843750000, 0.0000000000000000, -0.0015869140625000, +0.0000305175781250, -0.0016174316406250, 0.0000000000000000, -0.0022583007812500, +0.0000000000000000, -0.0018005371093750, 0.0000000000000000, -0.0023803710937500, +0.0000305175781250, -0.0022277832031250, 0.0000000000000000, -0.0021972656250000, +0.0000000000000000, -0.0025024414062500, 0.0000000000000000, -0.0021972656250000, +0.0000000000000000, -0.0024414062500000, 0.0000000000000000, -0.0023193359375000, +0.0000305175781250, -0.0022583007812500, -0.0000305175781250, -0.0023803710937500, +0.0000000000000000, -0.0022277832031250, 0.0000000000000000, -0.0020751953125000, +0.0000610351562500}, +{-0.0001831054687500, -0.0007934570312500, -0.0000915527343750, -0.0014648437500000, +-0.0002746582031250, -0.0005187988281250, -0.0001220703125000, 0.0004577636718750, +0.0002746582031250, -0.0003967285156250, 0.0001220703125000, 0.0009765625000000, +0.0000610351562500, 0.0013427734375000, 0.0002441406250000, 0.0006103515625000, +0.0000915527343750, 0.0007019042968750, -0.0001831054687500, 0.0010986328125000, +-0.0000305175781250, -0.0007019042968750, -0.0000610351562500, -0.0005493164062500, +-0.0002136230468750, -0.0004272460937500, -0.0000610351562500, -0.0015563964843750, +0.0001525878906250, -0.0013732910156250, 0.0000610351562500, -0.0003662109375000, +0.0000305175781250, -0.0009460449218750, 0.0001525878906250, -0.0003051757812500, +0.0000610351562500, 0.0009765625000000, -0.0001220703125000, 0.0002136230468750, +-0.0000305175781250, 0.0010070800781250, -0.0000610351562500, 0.0014343261718750, +-0.0001220703125000, 0.0007629394531250, -0.0000305175781250, 0.0005798339843750, +0.0000610351562500, 0.0010681152343750, 0.0000610351562500, -0.0006103515625000, +0.0000305175781250, -0.0003967285156250, 0.0000915527343750, -0.0005187988281250, +0.0000305175781250, -0.0016784667968750, -0.0000610351562500, -0.0012817382812500, +-0.0000610351562500, -0.0011291503906250, 0.0000000000000000, -0.0016174316406250, +-0.0000305175781250, -0.0010070800781250, 0.0000000000000000, -0.0002746582031250, +0.0000305175781250, -0.0009155273437500, 0.0000305175781250, 0.0006103515625000, +-0.0000305175781250, 0.0005187988281250, 0.0000000000000000, 0.0006713867187500, +0.0000305175781250, 0.0016784667968750, 0.0000000000000000, 0.0012512207031250, +0.0000000000000000, 0.0014953613281250, 0.0000305175781250, 0.0018615722656250, +-0.0000305175781250, 0.0012817382812500, 0.0000000000000000, 0.0010070800781250, +0.0000305175781250, 0.0014343261718750, 0.0000000000000000, -0.0001525878906250, +0.0000000000000000, 0.0002746582031250, 0.0000000000000000, -0.0001831054687500, +0.0000305175781250, -0.0014648437500000, -0.0000305175781250, -0.0006713867187500, +-0.0000305175781250, -0.0019836425781250, 0.0000000000000000, -0.0020141601562500, +0.0000305175781250, -0.0018920898437500, 0.0000305175781250, -0.0025329589843750, +0.0000305175781250, -0.0024414062500000, 0.0000000000000000, -0.0021057128906250, +0.0000000000000000, -0.0024414062500000, -0.0000305175781250, -0.0020141601562500, +0.0000000000000000, -0.0014953613281250, 0.0000305175781250, -0.0020141601562500, +0.0000000000000000, -0.0007019042968750, -0.0000305175781250, -0.0011291503906250, +0.0000305175781250, -0.0007629394531250, 0.0000305175781250, 0.0002746582031250, +-0.0000305175781250, -0.0004577636718750, 0.0000000000000000, 0.0007019042968750, +-0.0000305175781250, 0.0005798339843750, 0.0000000000000000, 0.0006408691406250, +-0.0000305175781250, 0.0013732910156250, 0.0000305175781250, 0.0007934570312500, +0.0000000000000000, 0.0014343261718750, 0.0000000000000000, 0.0013122558593750, +0.0000000000000000, 0.0013427734375000, 0.0000000000000000, 0.0016174316406250, +0.0000000000000000, 0.0013427734375000, 0.0000000000000000, 0.0016479492187500, +0.0000305175781250, 0.0015563964843750, -0.0000305175781250, 0.0014648437500000, +0.0000305175781250, 0.0016174316406250, 0.0000000000000000, 0.0014343261718750, +0.0000000000000000, 0.0013122558593750, 0.0000000000000000, 0.0012512207031250, +0.0000000000000000, 0.0010375976562500, 0.0000000000000000, 0.0008850097656250, +-0.0000305175781250, 0.0007324218750000, 0.0000000000000000, 0.0003356933593750, +0.0000000000000000, 0.0003662109375000, 0.0000000000000000, 0.0000000000000000, +-0.0000305175781250, -0.0004272460937500, 0.0000000000000000, -0.0003051757812500, +0.0000000000000000, -0.0010070800781250, 0.0000000000000000, -0.0010070800781250, +0.0000000000000000, -0.0011901855468750, 0.0000000000000000, -0.0017700195312500, +0.0000000000000000, -0.0015869140625000, 0.0000305175781250, -0.0018005371093750, +0.0000000000000000, -0.0019836425781250, 0.0000000000000000, -0.0017395019531250, +0.0000305175781250, -0.0016479492187500, -0.0000305175781250, -0.0018005371093750, +0.0000000000000000, -0.0010070800781250, -0.0000305175781250, -0.0011596679687500, +0.0000000000000000, -0.0006713867187500, 0.0000305175781250, 0.0001220703125000, +0.0000305175781250, -0.0002441406250000, 0.0000000000000000, 0.0008239746093750, +0.0000000000000000, 0.0008544921875000, 0.0000305175781250, 0.0007934570312500, +0.0000000000000000, 0.0013427734375000, 0.0000000000000000, 0.0012207031250000, +0.0000000000000000, 0.0009765625000000, 0.0000305175781250, 0.0012512207031250, +0.0000000000000000, 0.0007324218750000, 0.0000000000000000, 0.0000610351562500, +0.0000305175781250, 0.0004577636718750, 0.0000000000000000, -0.0006713867187500, +0.0000000000000000, -0.0007629394531250, 0.0000305175781250, -0.0006713867187500, +0.0000000000000000, -0.0012207031250000, -0.0000305175781250, -0.0011291503906250, +-0.0000305175781250, -0.0005493164062500, 0.0000000000000000, -0.0008544921875000, +-0.0000610351562500, -0.0004272460937500, 0.0000000000000000, 0.0003662109375000, +0.0000610351562500, -0.0000305175781250, 0.0000000000000000, 0.0006103515625000, +0.0000305175781250, 0.0008544921875000, 0.0000915527343750, 0.0004882812500000, +0.0000305175781250, 0.0004272460937500, -0.0000305175781250, 0.0006408691406250, +0.0000000000000000, -0.0002746582031250, 0.0000305175781250, -0.0002441406250000, +-0.0000305175781250, -0.0002136230468750, -0.0000305175781250, -0.0007324218750000, +0.0000305175781250, -0.0006408691406250, 0.0000000000000000, -0.0000915527343750, +0.0000305175781250, -0.0003051757812500, 0.0001220703125000, -0.0001525878906250, +0.0000000000000000, 0.0004882812500000, -0.0000610351562500, 0.0002136230468750, +0.0000610351562500, 0.0001220703125000, -0.0000610351562500, 0.0003662109375000, +-0.0000915527343750, 0.0001220703125000, 0.0000000000000000, -0.0003662109375000, +0.0000610351562500, -0.0001220703125000, -0.0000305175781250, -0.0003051757812500, +0.0000305175781250, -0.0005187988281250, 0.0001525878906250, -0.0001831054687500, +0.0000305175781250, 0.0000915527343750, -0.0000610351562500, -0.0001220703125000, +0.0000610351562500, 0.0002441406250000, -0.0000610351562500, 0.0003967285156250, +-0.0001525878906250, 0.0001220703125000, -0.0000610351562500, 0.0000000000000000, +0.0000000000000000, 0.0002136230468750, -0.0000305175781250, -0.0001831054687500, +0.0000610351562500, -0.0003051757812500, 0.0001220703125000, -0.0001220703125000, +0.0000305175781250, -0.0000305175781250, -0.0000915527343750, -0.0000305175781250, +-0.0000915527343750, 0.0001220703125000, -0.0000305175781250, 0.0001525878906250, +-0.0001220703125000, 0.0000305175781250, -0.0000610351562500, -0.0000305175781250, +0.0000915527343750, 0.0001220703125000, 0.0000305175781250, -0.0001220703125000, +0.0000610351562500, -0.0002136230468750, 0.0001831054687500, -0.0000610351562500, +0.0000305175781250, 0.0000000000000000, -0.0001525878906250, -0.0000915527343750, +-0.0000305175781250, 0.0001525878906250, -0.0000610351562500, 0.0002136230468750, +-0.0001525878906250, 0.0000305175781250, -0.0000305175781250, -0.0000305175781250, +0.0001831054687500, 0.0000915527343750, 0.0000610351562500, -0.0000915527343750, +0.0000915527343750, -0.0001831054687500, 0.0002441406250000, -0.0000305175781250, +0.0000000000000000, 0.0000305175781250, -0.0003051757812500, -0.0000915527343750, +-0.0000915527343750, 0.0000915527343750, -0.0002136230468750, 0.0001831054687500, +-0.0004272460937500, 0.0000305175781250, -0.0001220703125000, 0.0000000000000000, +0.0001220703125000, 0.0000915527343750, -0.0001220703125000, -0.0000915527343750, +0.0003356933593750, -0.0001525878906250, 0.0005187988281250, -0.0000305175781250, +0.0001525878906250, 0.0000000000000000, 0.0000305175781250, -0.0000915527343750, +0.0003051757812500, 0.0000915527343750, -0.0004272460937500, 0.0001220703125000, +-0.0004882812500000, 0.0000305175781250, -0.0003051757812500, 0.0000305175781250, +-0.0005187988281250, 0.0000915527343750, -0.0005798339843750, -0.0000610351562500, +0.0001220703125000, -0.0000915527343750, -0.0000305175781250, 0.0000000000000000, +0.0000610351562500, 0.0000000000000000, 0.0006408691406250, -0.0000610351562500, +0.0004882812500000, 0.0000000000000000, 0.0001831054687500, 0.0000610351562500, +0.0004882812500000, 0.0000000000000000, 0.0000610351562500, 0.0000305175781250, +-0.0005493164062500, 0.0000610351562500, -0.0001831054687500, -0.0000610351562500, +-0.0006713867187500, -0.0000305175781250, -0.0009460449218750, 0.0000000000000000, +-0.0005493164062500, -0.0000305175781250, -0.0003967285156250, -0.0000610351562500, +-0.0006103515625000, 0.0000000000000000, 0.0003051757812500, 0.0000305175781250, +0.0003051757812500, 0.0000000000000000, 0.0003967285156250, 0.0000305175781250, +0.0009765625000000, 0.0000305175781250, 0.0008239746093750, 0.0000000000000000, +0.0006408691406250, 0.0000000000000000, 0.0008850097656250, 0.0000305175781250, +0.0004577636718750, -0.0000305175781250, -0.0001831054687500, -0.0000305175781250, +0.0001831054687500, 0.0000000000000000, -0.0007629394531250, -0.0000305175781250, +-0.0007629394531250, 0.0000000000000000, -0.0008544921875000, 0.0000305175781250, +-0.0013732910156250, 0.0000305175781250, -0.0012207031250000, -0.0000305175781250, +-0.0011901855468750, 0.0000305175781250, -0.0013427734375000, 0.0000305175781250, +-0.0010375976562500, -0.0000305175781250, -0.0007934570312500, -0.0000305175781250, +-0.0008850097656250, 0.0000305175781250, -0.0001525878906250, 0.0000000000000000, +-0.0002441406250000, 0.0000000000000000, 0.0000610351562500, 0.0000000000000000, +0.0006713867187500, 0.0000305175781250, 0.0005187988281250, -0.0000305175781250, +0.0011596679687500, 0.0000000000000000, 0.0012512207031250, 0.0000305175781250, +0.0013427734375000, 0.0000305175781250, 0.0016784667968750, -0.0000305175781250, +0.0015869140625000, 0.0000000000000000, 0.0017395019531250, 0.0000000000000000, +0.0018005371093750, 0.0000305175781250, 0.0018005371093750, 0.0000000000000000, +0.0018615722656250, -0.0000305175781250, 0.0018005371093750, 0.0000000000000000, +0.0017700195312500, 0.0000000000000000, 0.0017395019531250, 0.0000305175781250, +0.0017395019531250, 0.0000305175781250, 0.0017089843750000, 0.0000610351562500, +0.0017395019531250, 0.0000000000000000, 0.0018005371093750, 0.0000000000000000, +0.0017089843750000, 0.0000000000000000, 0.0017395019531250, 0.0000000000000000, +0.0018920898437500, 0.0000305175781250, 0.0018005371093750, -0.0000305175781250, +0.0019531250000000, 0.0000000000000000, 0.0019531250000000, 0.0000000000000000, +0.0019836425781250, -0.0000305175781250, 0.0021057128906250, 0.0000000000000000, +0.0019836425781250, 0.0000000000000000, 0.0020751953125000, 0.0000000000000000, +0.0021057128906250, 0.0000000000000000, 0.0019531250000000, 0.0000000000000000, +0.0018920898437500, 0.0000000000000000, 0.0020141601562500, 0.0000000000000000, +0.0012817382812500, 0.0000000000000000, 0.0016784667968750, 0.0000305175781250, +0.0011596679687500, 0.0000305175781250, 0.0003967285156250, 0.0000305175781250, +0.0010375976562500, -0.0000305175781250, -0.0005798339843750, 0.0000000000000000, +-0.0002746582031250, 0.0000305175781250, -0.0005493164062500, -0.0000305175781250, +-0.0017089843750000, 0.0000000000000000, -0.0010986328125000, 0.0000305175781250, +-0.0018310546875000, 0.0000000000000000, -0.0021362304687500, 0.0000000000000000, +-0.0016479492187500}, +{0.0001831054687500, 0.0000305175781250, -0.0000610351562500, 0.0000000000000000, +-0.0007019042968750, 0.0000305175781250, -0.0004577636718750, -0.0000610351562500, +-0.0004882812500000, -0.0000610351562500, -0.0007629394531250, 0.0000000000000000, +-0.0003051757812500, 0.0000000000000000, 0.0001831054687500, -0.0000305175781250, +-0.0001831054687500, 0.0000305175781250, 0.0005493164062500, 0.0000305175781250, +0.0007324218750000, 0.0000305175781250, 0.0004272460937500, 0.0000000000000000, +0.0005493164062500, 0.0000305175781250, 0.0006408691406250, 0.0000305175781250, +-0.0002136230468750, -0.0000305175781250, -0.0001220703125000, -0.0000305175781250, +-0.0003051757812500, 0.0000000000000000, -0.0010070800781250, -0.0000305175781250, +-0.0007934570312500, 0.0000305175781250, -0.0008544921875000, 0.0000000000000000, +-0.0010986328125000, 0.0000305175781250, -0.0006713867187500, 0.0000000000000000, +-0.0003662109375000, 0.0000305175781250, -0.0006103515625000, 0.0000000000000000, +0.0002746582031250, -0.0000305175781250, 0.0002746582031250, -0.0000305175781250, +0.0004577636718750, -0.0000305175781250, 0.0010375976562500, 0.0000000000000000, +0.0008544921875000, -0.0000305175781250, 0.0010375976562500, 0.0000000000000000, +0.0011901855468750, 0.0000305175781250, 0.0010070800781250, 0.0000000000000000, +0.0009155273437500, 0.0000000000000000, 0.0009460449218750, -0.0000305175781250, +0.0004882812500000, -0.0000305175781250, 0.0004882812500000, 0.0000000000000000, +0.0001831054687500, 0.0000000000000000, -0.0003051757812500, -0.0000305175781250, +-0.0001525878906250, -0.0000305175781250, -0.0007934570312500, 0.0000000000000000, +-0.0008239746093750, 0.0000305175781250, -0.0009765625000000, 0.0000000000000000, +-0.0013122558593750, 0.0000000000000000, -0.0012512207031250, 0.0000000000000000, +-0.0014648437500000, 0.0000305175781250, -0.0015258789062500, 0.0000305175781250, +-0.0015258789062500, 0.0000305175781250, -0.0015869140625000, -0.0000305175781250, +-0.0015869140625000, 0.0000000000000000, -0.0015869140625000, 0.0000305175781250, +-0.0015869140625000, -0.0000305175781250, -0.0015869140625000, -0.0000305175781250, +-0.0015563964843750, -0.0000305175781250, -0.0015258789062500, 0.0000000000000000, +-0.0015869140625000, 0.0000000000000000, -0.0015563964843750, 0.0000000000000000, +-0.0015563964843750, -0.0000305175781250, -0.0016174316406250, 0.0000000000000000, +-0.0016174316406250, 0.0000000000000000, -0.0017089843750000, 0.0000305175781250, +-0.0017089843750000, 0.0000000000000000, -0.0017089843750000, 0.0000000000000000, +-0.0017700195312500, 0.0000000000000000, -0.0017089843750000, 0.0000000000000000, +-0.0016784667968750, 0.0000000000000000, -0.0018005371093750, 0.0000000000000000, +-0.0015563964843750, 0.0000000000000000, -0.0014648437500000, 0.0000305175781250, +-0.0016784667968750, 0.0000000000000000, -0.0008544921875000, 0.0000000000000000, +-0.0011901855468750, 0.0000305175781250, -0.0007019042968750, 0.0000000000000000, +0.0000000000000000, 0.0000000000000000, -0.0005493164062500, 0.0000000000000000, +0.0008239746093750, 0.0000000000000000, 0.0006713867187500, 0.0000000000000000, +0.0007324218750000, 0.0000000000000000, 0.0016784667968750, 0.0000000000000000, +0.0012512207031250, 0.0000000000000000, 0.0014648437500000, -0.0000305175781250, +0.0018615722656250, 0.0000000000000000, 0.0012817382812500, -0.0000305175781250, +0.0008544921875000, -0.0000305175781250, 0.0013122558593750, 0.0000000000000000, +-0.0002441406250000, 0.0000305175781250, 0.0001220703125000, 0.0000305175781250, +-0.0003051757812500, 0.0000915527343750, -0.0016174316406250, 0.0000610351562500, +-0.0010070800781250, 0.0000000000000000, -0.0015869140625000, 0.0000000000000000, +-0.0019226074218750, 0.0000000000000000, -0.0013732910156250, -0.0000305175781250, +-0.0011596679687500, 0.0000000000000000, -0.0015258789062500, 0.0000305175781250, +-0.0000305175781250, 0.0000305175781250, -0.0002441406250000, 0.0000000000000000, +0.0000305175781250, 0.0000305175781250, 0.0012512207031250, 0.0000305175781250, +0.0008544921875000, -0.0000305175781250, 0.0011901855468750, -0.0000305175781250, +0.0015563964843750, 0.0000000000000000, 0.0009155273437500, -0.0000915527343750, +0.0005187988281250, -0.0000305175781250, 0.0009460449218750, 0.0000305175781250, +-0.0005187988281250, 0.0000610351562500, -0.0005187988281250, 0.0000305175781250, +-0.0004882812500000, 0.0000305175781250, -0.0013732910156250, 0.0000915527343750, +-0.0011901855468750, -0.0000305175781250, -0.0006103515625000, -0.0000305175781250, +-0.0009765625000000, 0.0000000000000000, -0.0004882812500000, -0.0000915527343750, +0.0003662109375000, -0.0000305175781250, -0.0000915527343750, 0.0000305175781250, +0.0006713867187500, 0.0000000000000000, 0.0008850097656250, 0.0000305175781250, +0.0004882812500000, 0.0001220703125000, 0.0005798339843750, 0.0000915527343750, +0.0007934570312500, -0.0000305175781250, -0.0002746582031250, 0.0000305175781250, +-0.0000915527343750, 0.0000000000000000, -0.0001831054687500, -0.0001831054687500, +-0.0010375976562500, -0.0001220703125000, -0.0007629394531250, 0.0000000000000000, +-0.0004272460937500, -0.0001220703125000, -0.0008239746093750, -0.0000305175781250, +-0.0002441406250000, 0.0002136230468750, 0.0006103515625000, 0.0000915527343750, +0.0000610351562500, 0.0000915527343750, 0.0007324218750000, 0.0002441406250000, +0.0012207031250000, 0.0000305175781250, 0.0003967285156250, -0.0001831054687500, +-0.0001525878906250, 0.0000000000000000, 0.0004272460937500, -0.0002441406250000, +-0.0007629394531250, -0.0003967285156250, -0.0011596679687500, -0.0001220703125000, +-0.0004577636718750, 0.0000610351562500, -0.0003662109375000, -0.0001220703125000, +-0.0008239746093750, 0.0002746582031250, 0.0005187988281250, 0.0003967285156250, +0.0006408691406250, 0.0001831054687500, 0.0002441406250000, 0.0000915527343750, +0.0006408691406250, -0.0004272460937500, -0.0008850097656250, 0.0003967285156250, +0.0006103515625000, 0.0001220703125000, 0.0004882812500000, 0.0000915527343750, +0.0001525878906250, 0.0005798339843750, 0.0004577636718750, 0.0006103515625000, +0.0007019042968750, -0.0002746582031250, -0.0004272460937500, 0.0000305175781250, +-0.0005187988281250, -0.0001831054687500, -0.0001525878906250, -0.0010986328125000, +-0.0005493164062500, -0.0007629394531250, -0.0006713867187500, -0.0002746582031250, +0.0002746582031250, -0.0008850097656250, 0.0002136230468750, -0.0001831054687500, +0.0000610351562500, 0.0009460449218750, 0.0005187988281250, 0.0003051757812500, +0.0005187988281250, 0.0007324218750000, -0.0001831054687500, 0.0013732910156250, +-0.0000305175781250, 0.0003967285156250, 0.0000000000000000, -0.0003967285156250, +-0.0004577636718750, 0.0004272460937500, -0.0003967285156250, -0.0010375976562500, +0.0000915527343750, -0.0015258789062500, -0.0000305175781250, -0.0006408691406250, +0.0000000000000000, -0.0006103515625000, 0.0003356933593750, -0.0011901855468750, +0.0002746582031250, 0.0006713867187500, -0.0000610351562500, 0.0006103515625000, +0.0000915527343750, 0.0004272460937500, 0.0000305175781250, 0.0014953613281250, +-0.0003051757812500, 0.0012817382812500, -0.0002441406250000, 0.0000000000000000, +0.0000305175781250, 0.0006408691406250, -0.0000610351562500, 0.0000610351562500, +-0.0000305175781250, -0.0014648437500000, 0.0002441406250000, -0.0007324218750000, +0.0001831054687500, -0.0009460449218750, -0.0000305175781250, -0.0016174316406250, +0.0000610351562500, -0.0007324218750000, 0.0000305175781250, 0.0000305175781250, +-0.0001525878906250, -0.0007324218750000, -0.0001220703125000, 0.0008544921875000, +0.0000000000000000, 0.0009460449218750, 0.0000000000000000, 0.0006408691406250, +-0.0000305175781250, 0.0013427734375000, 0.0001220703125000, 0.0013122558593750, +0.0001220703125000, 0.0001831054687500, -0.0000305175781250, 0.0007324218750000, +0.0000305175781250, 0.0001220703125000, 0.0000305175781250, -0.0011596679687500, +-0.0000610351562500, -0.0004272460937500, -0.0000915527343750, -0.0012817382812500, +0.0000305175781250, -0.0016174316406250, 0.0000305175781250, -0.0011596679687500, +0.0000305175781250, -0.0012512207031250, 0.0000610351562500, -0.0014953613281250, +0.0000610351562500, -0.0002441406250000, -0.0000305175781250, -0.0005187988281250, +0.0000000000000000, -0.0001525878906250, 0.0000000000000000, 0.0009460449218750, +0.0000000000000000, 0.0003356933593750, 0.0000000000000000, 0.0013122558593750, +0.0000305175781250, 0.0014953613281250, 0.0000305175781250, 0.0012207031250000, +0.0000000000000000, 0.0015563964843750, 0.0000305175781250, 0.0016479492187500, +0.0000305175781250, 0.0007934570312500, -0.0000305175781250, 0.0011901855468750, +-0.0000305175781250, 0.0006408691406250, 0.0000305175781250, -0.0003356933593750, +0.0000000000000000, 0.0003662109375000, -0.0000305175781250, -0.0010681152343750, +0.0000000000000000, -0.0009460449218750, 0.0000305175781250, -0.0010986328125000, +0.0000000000000000, -0.0020141601562500, 0.0000305175781250, -0.0015563964843750, +0.0000305175781250, -0.0019531250000000, 0.0000305175781250, -0.0021972656250000, +0.0000000000000000, -0.0018920898437500, -0.0000305175781250, -0.0018920898437500, +0.0000305175781250, -0.0021362304687500, 0.0000305175781250, -0.0013122558593750, +-0.0000305175781250, -0.0016784667968750, 0.0000610351562500, -0.0013732910156250, +0.0000305175781250, -0.0006408691406250, 0.0000000000000000, -0.0011596679687500, +0.0000000000000000, -0.0001831054687500, -0.0000610351562500, -0.0003967285156250, +0.0000000000000000, -0.0002136230468750, 0.0000305175781250, 0.0003967285156250, +0.0000000000000000, -0.0001220703125000, 0.0000000000000000, 0.0005798339843750, +-0.0000305175781250, 0.0003967285156250, -0.0000305175781250, 0.0003967285156250, +0.0000000000000000, 0.0007934570312500, 0.0000305175781250, 0.0003967285156250, +0.0000000000000000, 0.0008239746093750, -0.0000305175781250, 0.0007324218750000, +0.0000305175781250, 0.0007019042968750, -0.0000305175781250, 0.0008544921875000, +0.0000000000000000, 0.0006408691406250, 0.0000000000000000, 0.0006408691406250, +0.0000305175781250, 0.0004882812500000, 0.0000000000000000, 0.0002746582031250, +0.0000000000000000, 0.0001525878906250, 0.0000000000000000, -0.0000305175781250, +-0.0000305175781250, -0.0003051757812500, 0.0000000000000000, -0.0003967285156250, +0.0000000000000000, -0.0006713867187500, -0.0000305175781250, -0.0010375976562500, +0.0000305175781250, -0.0009460449218750, 0.0000000000000000, -0.0014343261718750, +-0.0000305175781250, -0.0014343261718750, 0.0000000000000000, -0.0014648437500000, +0.0000000000000000, -0.0018310546875000, 0.0000305175781250, -0.0017700195312500, +0.0000000000000000, -0.0015869140625000, 0.0000000000000000, -0.0017700195312500, +0.0000305175781250, -0.0014343261718750, 0.0000000000000000, -0.0010070800781250, +0.0000000000000000, -0.0012512207031250, -0.0000305175781250, -0.0003662109375000, +-0.0000305175781250, -0.0004272460937500, 0.0000000000000000, -0.0000915527343750, +0.0000000000000000, 0.0006713867187500, 0.0000305175781250, 0.0004272460937500, +0.0000000000000000, 0.0010986328125000, 0.0000000000000000, 0.0011901855468750, +0.0000305175781250, 0.0009460449218750, 0.0000000000000000, 0.0011291503906250, +0.0000305175781250, 0.0012207031250000, 0.0000305175781250, 0.0004577636718750, +0.0000305175781250, 0.0006408691406250, -0.0000305175781250, 0.0001525878906250, +0.0000305175781250, -0.0006408691406250, 0.0000610351562500, -0.0002136230468750, +-0.0000305175781250}, +{-0.0000610351562500, 0.0013122558593750, -0.0000610351562500, 0.0004577636718750, +0.0000000000000000, 0.0007629394531250, 0.0000305175781250, 0.0003051757812500, +0.0000000000000000, -0.0004882812500000, 0.0000305175781250, 0.0000000000000000, +0.0000305175781250, -0.0010681152343750, -0.0000305175781250, -0.0011291503906250, +-0.0000305175781250, -0.0009460449218750, 0.0000305175781250, -0.0014648437500000, +0.0000000000000000, -0.0014038085937500, -0.0000305175781250, -0.0008239746093750, +0.0000610351562500, -0.0011901855468750, 0.0000305175781250, -0.0007019042968750, +0.0000000000000000, 0.0000305175781250, 0.0000000000000000, -0.0005187988281250, +0.0000305175781250, 0.0007629394531250, -0.0000305175781250, 0.0006103515625000, +-0.0000305175781250, 0.0007629394531250, 0.0000000000000000, 0.0016174316406250, +0.0000000000000000, 0.0012207031250000, 0.0000305175781250, 0.0015869140625000, +0.0000305175781250, 0.0018005371093750, 0.0000610351562500, 0.0014953613281250, +0.0000305175781250, 0.0014953613281250, -0.0000305175781250, 0.0016784667968750, +0.0000305175781250, 0.0008239746093750, -0.0000610351562500, 0.0011901855468750, +0.0000305175781250, 0.0008544921875000, 0.0000305175781250, 0.0000610351562500, +-0.0000305175781250, 0.0006408691406250, 0.0000305175781250, -0.0003967285156250, +0.0000000000000000, -0.0001831054687500, 0.0000000000000000, -0.0003051757812500, +0.0000305175781250, -0.0009155273437500, -0.0000305175781250, -0.0004272460937500, +0.0000000000000000, -0.0010986328125000, 0.0000000000000000, -0.0009460449218750, +0.0000305175781250, -0.0010070800781250, 0.0000305175781250, -0.0013427734375000, +0.0000000000000000, -0.0010070800781250, 0.0000000000000000, -0.0014038085937500, +0.0000000000000000, -0.0012207031250000, 0.0000000000000000, -0.0011901855468750, +0.0000000000000000, -0.0014038085937500, 0.0000000000000000, -0.0011596679687500, +0.0000000000000000, -0.0010681152343750, 0.0000305175781250, -0.0009765625000000, +0.0000000000000000, -0.0007629394531250, 0.0000000000000000, -0.0005798339843750, +0.0000000000000000, -0.0003967285156250, 0.0000305175781250, -0.0000305175781250, +0.0000000000000000, 0.0000000000000000, 0.0000000000000000, 0.0003356933593750, +0.0000000000000000, 0.0007324218750000, 0.0000000000000000, 0.0006103515625000, +-0.0000305175781250, 0.0012207031250000, 0.0000000000000000, 0.0012207031250000, +0.0000305175781250, 0.0012512207031250, 0.0000305175781250, 0.0017089843750000, +0.0000000000000000, 0.0016479492187500, 0.0000000000000000, 0.0014648437500000, +0.0000305175781250, 0.0016784667968750, 0.0000000000000000, 0.0013427734375000, +0.0000000000000000, 0.0009460449218750, -0.0000305175781250, 0.0011901855468750, +-0.0000305175781250, 0.0003051757812500, 0.0000000000000000, 0.0003662109375000, +0.0000305175781250, 0.0000305175781250, 0.0000305175781250, -0.0007019042968750, +0.0000000000000000, -0.0004272460937500, 0.0000000000000000, -0.0010070800781250, +-0.0000305175781250, -0.0011901855468750, 0.0000000000000000, -0.0009155273437500, +0.0000000000000000, -0.0010681152343750, 0.0000000000000000, -0.0010986328125000, +0.0000000000000000, -0.0003051757812500, 0.0000305175781250, -0.0004882812500000, +0.0000000000000000, -0.0001220703125000, 0.0000000000000000, 0.0006713867187500, +0.0000305175781250, 0.0003356933593750, 0.0000305175781250, 0.0008544921875000, +-0.0000610351562500, 0.0010681152343750, 0.0000000000000000, 0.0006713867187500, +0.0000000000000000, 0.0005187988281250, 0.0000000000000000, 0.0007629394531250, +-0.0000305175781250, -0.0002746582031250, 0.0000305175781250, -0.0002136230468750, +0.0000305175781250, -0.0003051757812500, 0.0000305175781250, -0.0010375976562500, +0.0000305175781250, -0.0008544921875000, 0.0000305175781250, -0.0005187988281250, +-0.0000305175781250, -0.0008544921875000, 0.0000000000000000, -0.0003967285156250, +0.0000000000000000, 0.0002746582031250, -0.0000305175781250, -0.0000915527343750, +-0.0000610351562500, 0.0005493164062500, 0.0000915527343750, 0.0007629394531250, +0.0000915527343750, 0.0003662109375000, 0.0000000000000000, 0.0002136230468750, +0.0000000000000000, 0.0004882812500000, 0.0000610351562500, -0.0003662109375000, +-0.0000305175781250, -0.0004272460937500, -0.0000305175781250, -0.0002441406250000, +0.0000000000000000, -0.0004882812500000, 0.0000000000000000, -0.0005798339843750, +-0.0000915527343750, 0.0001220703125000, 0.0000305175781250, 0.0000305175781250, +0.0000610351562500, 0.0000305175781250, 0.0000000000000000, 0.0005187988281250, +0.0000915527343750, 0.0004272460937500, 0.0000915527343750, -0.0000305175781250, +-0.0000610351562500, 0.0001525878906250, -0.0000610351562500, 0.0000000000000000, +0.0000000000000000, -0.0005187988281250, -0.0000915527343750, -0.0003967285156250, +-0.0000915527343750, -0.0001220703125000, 0.0001220703125000, -0.0003356933593750, +0.0000610351562500, -0.0001525878906250, 0.0000000000000000, 0.0003356933593750, +0.0000915527343750, 0.0001220703125000, 0.0000915527343750, 0.0000610351562500, +-0.0000610351562500, 0.0002441406250000, -0.0000915527343750, 0.0000915527343750, +-0.0000305175781250, -0.0003051757812500, -0.0000610351562500, -0.0003051757812500, +-0.0000915527343750, 0.0000000000000000, 0.0000610351562500, -0.0001831054687500, +0.0000915527343750, -0.0001525878906250, -0.0000305175781250, 0.0001831054687500, +0.0000305175781250, 0.0000610351562500, 0.0001220703125000, 0.0000000000000000, +-0.0000915527343750, 0.0001831054687500, -0.0001220703125000, 0.0000000000000000, +-0.0000305175781250, -0.0002136230468750, -0.0000915527343750, -0.0000915527343750, +-0.0001220703125000, 0.0000000000000000, 0.0000915527343750, -0.0001831054687500, +0.0001525878906250, -0.0000915527343750, -0.0000305175781250, 0.0002136230468750, +-0.0000305175781250, 0.0000915527343750, 0.0000915527343750, 0.0000305175781250, +-0.0002441406250000, 0.0001525878906250, -0.0003051757812500, 0.0000305175781250, +-0.0000915527343750, -0.0001831054687500, -0.0002136230468750, -0.0000915527343750, +-0.0002746582031250, -0.0000305175781250, 0.0002441406250000, -0.0001525878906250, +0.0002441406250000, -0.0000610351562500, 0.0000305175781250, 0.0001220703125000, +0.0003051757812500, 0.0000915527343750, 0.0003662109375000, 0.0000305175781250, +-0.0003051757812500, 0.0000915527343750, -0.0002136230468750, 0.0000610351562500, +-0.0001525878906250, -0.0001220703125000, -0.0006713867187500, -0.0000610351562500, +-0.0005798339843750, 0.0000000000000000, -0.0000610351562500, -0.0001220703125000, +-0.0002746582031250, -0.0000305175781250, -0.0000610351562500, 0.0000915527343750, +0.0005493164062500, 0.0000000000000000, 0.0003051757812500, 0.0000000000000000, +0.0002136230468750, 0.0001220703125000, 0.0005493164062500, 0.0000000000000000, +0.0001525878906250, -0.0000610351562500, -0.0003967285156250, 0.0000000000000000, +-0.0000305175781250, 0.0000000000000000, -0.0005493164062500, -0.0000915527343750, +-0.0007629394531250, -0.0000305175781250, -0.0003967285156250, 0.0000610351562500, +-0.0003051757812500, 0.0000305175781250, -0.0005187988281250, 0.0000305175781250, +0.0003051757812500, 0.0000610351562500, 0.0002746582031250, 0.0000305175781250, +0.0002746582031250, -0.0000305175781250, 0.0007629394531250, 0.0000000000000000, +0.0006408691406250, -0.0000305175781250, 0.0002441406250000, -0.0000610351562500, +0.0003967285156250, -0.0000305175781250, 0.0000610351562500, 0.0000305175781250, +-0.0004882812500000, 0.0000000000000000, -0.0002441406250000, 0.0000000000000000, +-0.0006713867187500, 0.0000610351562500, -0.0008544921875000, 0.0000000000000000, +-0.0005798339843750, 0.0000000000000000, -0.0005493164062500, 0.0000305175781250, +-0.0006713867187500, -0.0000305175781250, -0.0000915527343750, -0.0000610351562500, +-0.0001525878906250, -0.0000610351562500, -0.0000305175781250, -0.0000305175781250, +0.0004577636718750, 0.0000000000000000, 0.0003051757812500, 0.0000305175781250, +0.0005187988281250, 0.0000305175781250, 0.0005798339843750, 0.0000000000000000, +0.0004882812500000, 0.0000000000000000, 0.0004272460937500, 0.0000000000000000, +0.0004577636718750, 0.0000000000000000, 0.0002136230468750, -0.0000305175781250, +0.0002136230468750, 0.0000000000000000, 0.0000305175781250, -0.0000305175781250, +-0.0003051757812500, 0.0000000000000000, -0.0000915527343750, 0.0000305175781250, +-0.0005187988281250, 0.0000000000000000, -0.0005798339843750, 0.0000305175781250, +-0.0006103515625000, 0.0000000000000000, -0.0008239746093750, 0.0000000000000000, +-0.0007629394531250, 0.0000000000000000, -0.0008544921875000, 0.0000305175781250, +-0.0008850097656250, 0.0000305175781250, -0.0008544921875000, 0.0000305175781250, +-0.0008850097656250, 0.0000000000000000, -0.0008239746093750, 0.0000305175781250, +-0.0007629394531250, 0.0000305175781250, -0.0006713867187500, 0.0000000000000000, +-0.0006713867187500, 0.0000000000000000, -0.0005798339843750, 0.0000305175781250, +-0.0005493164062500, -0.0000305175781250, -0.0006408691406250, 0.0000000000000000, +-0.0005187988281250, 0.0000000000000000, -0.0005493164062500, -0.0000305175781250, +-0.0006103515625000, -0.0000305175781250, -0.0006103515625000, -0.0000305175781250, +-0.0008544921875000, 0.0000000000000000, -0.0007324218750000, 0.0000000000000000, +-0.0007934570312500, 0.0000000000000000, -0.0010375976562500, 0.0000305175781250, +-0.0009155273437500, 0.0000000000000000, -0.0012207031250000, -0.0000305175781250, +-0.0011901855468750, 0.0000000000000000, -0.0010986328125000, 0.0000000000000000, +-0.0011901855468750, 0.0000000000000000, -0.0012512207031250, 0.0000000000000000, +-0.0007934570312500, 0.0000000000000000, -0.0010681152343750, 0.0000000000000000, +-0.0007324218750000, 0.0000000000000000, -0.0002746582031250, 0.0000000000000000, +-0.0006713867187500, 0.0000000000000000, 0.0003356933593750, -0.0000610351562500, +0.0001831054687500, 0.0000305175781250, 0.0001831054687500, 0.0000000000000000, +0.0008850097656250, 0.0000000000000000, 0.0006103515625000, 0.0000000000000000, +0.0006408691406250, 0.0000305175781250, 0.0008850097656250, 0.0000000000000000, +0.0004882812500000, -0.0000305175781250, 0.0001831054687500, 0.0000000000000000, +0.0005187988281250, 0.0000000000000000, -0.0005493164062500, 0.0000305175781250, +-0.0003662109375000, 0.0000305175781250, -0.0004577636718750, 0.0000305175781250, +-0.0013427734375000, 0.0000000000000000, -0.0010070800781250, 0.0000000000000000, +-0.0008850097656250, 0.0000305175781250, -0.0013122558593750, 0.0000305175781250, +-0.0006713867187500, 0.0000000000000000, -0.0000610351562500, 0.0000000000000000, +-0.0006408691406250, 0.0000000000000000, 0.0007019042968750, 0.0000000000000000, +0.0007019042968750, 0.0000000000000000, 0.0006408691406250, 0.0000305175781250, +0.0013427734375000, 0.0000305175781250, 0.0011901855468750, 0.0000000000000000, +0.0006713867187500, 0.0000305175781250, 0.0010375976562500, 0.0000000000000000, +0.0004577636718750, -0.0000610351562500, -0.0004272460937500, -0.0000610351562500, +0.0001220703125000, 0.0000305175781250, -0.0009155273437500, -0.0000305175781250, +-0.0011596679687500, 0.0000000000000000, -0.0007629394531250, 0.0001220703125000, +-0.0010070800781250, 0.0000915527343750, -0.0011596679687500, 0.0000000000000000, +-0.0000305175781250, 0.0000610351562500, -0.0001831054687500, 0.0000000000000000, +-0.0000305175781250, -0.0001220703125000, 0.0007934570312500, -0.0000610351562500, +0.0005798339843750, 0.0000000000000000, 0.0005798339843750, -0.0000915527343750, +0.0009155273437500}, +{0.0007629394531250, 0.0000000000000000, 0.0007324218750000, 0.0000000000000000, +0.0009155273437500, 0.0000000000000000, 0.0013122558593750, -0.0000305175781250, +0.0012207031250000, 0.0000000000000000, 0.0015563964843750, 0.0000000000000000, +0.0015869140625000, 0.0000305175781250, 0.0015869140625000, -0.0000305175781250, +0.0016784667968750, 0.0000000000000000, 0.0015563964843750, 0.0000000000000000, +0.0014953613281250, 0.0000305175781250, 0.0014648437500000, 0.0000000000000000, +0.0013732910156250, 0.0000000000000000, 0.0012512207031250, 0.0000000000000000, +0.0011901855468750, 0.0000305175781250, 0.0009765625000000, 0.0000305175781250, +0.0007629394531250, 0.0000000000000000, 0.0007019042968750, 0.0000305175781250, +0.0005798339843750, -0.0000305175781250, 0.0004272460937500, 0.0000305175781250, +0.0007324218750000, 0.0000000000000000, 0.0005493164062500, 0.0000000000000000, +0.0006103515625000, 0.0000000000000000, 0.0007629394531250, 0.0000000000000000, +0.0006103515625000, -0.0000305175781250, 0.0012512207031250, 0.0000305175781250, +0.0010070800781250, 0.0000000000000000, 0.0012512207031250, -0.0000305175781250, +0.0018310546875000, -0.0000305175781250, 0.0013427734375000, 0.0000000000000000, +0.0022277832031250, 0.0000000000000000, 0.0021667480468750, 0.0000610351562500, +0.0021972656250000, 0.0000305175781250, 0.0027465820312500, 0.0000000000000000, +0.0025024414062500, -0.0000305175781250, 0.0023803710937500, -0.0000305175781250, +0.0026550292968750, 0.0000000000000000, 0.0022277832031250, 0.0000000000000000, +0.0018615722656250, -0.0000305175781250, 0.0022888183593750, 0.0000000000000000, +0.0008850097656250, 0.0000305175781250, 0.0012512207031250, -0.0000305175781250, +0.0009155273437500, 0.0000000000000000, -0.0001525878906250, 0.0000000000000000, +0.0004577636718750, 0.0000000000000000, -0.0004272460937500, -0.0000305175781250, +-0.0006713867187500, 0.0000000000000000, -0.0003967285156250, 0.0000305175781250, +-0.0006713867187500, 0.0000305175781250, -0.0007324218750000, 0.0000000000000000, +-0.0000305175781250, 0.0000610351562500, -0.0001831054687500, 0.0000000000000000, +-0.0000305175781250, -0.0000305175781250, 0.0006408691406250, -0.0000305175781250, +0.0003356933593750, 0.0000000000000000, 0.0003967285156250, -0.0000305175781250, +0.0006713867187500, 0.0000000000000000, 0.0002746582031250, 0.0000610351562500, +-0.0001220703125000, 0.0000305175781250, 0.0002136230468750, 0.0000305175781250, +-0.0006713867187500, 0.0000305175781250, -0.0007324218750000, 0.0000000000000000, +-0.0006713867187500, -0.0000305175781250, -0.0010681152343750, -0.0000305175781250, +-0.0010070800781250, 0.0000000000000000, -0.0004577636718750, 0.0000000000000000, +-0.0007019042968750, 0.0000000000000000, -0.0002441406250000, 0.0000610351562500, +0.0005187988281250, 0.0000305175781250, 0.0000915527343750, 0.0000305175781250, +0.0007934570312500, 0.0000610351562500, 0.0010986328125000, 0.0000000000000000, +0.0006408691406250, -0.0001220703125000, 0.0005187988281250, -0.0000610351562500, +0.0007629394531250, -0.0000610351562500, -0.0003356933593750, -0.0000610351562500, +-0.0002746582031250, -0.0000305175781250, -0.0003356933593750, 0.0001220703125000, +-0.0009765625000000, 0.0000305175781250, -0.0007629394531250, 0.0000915527343750, +-0.0005187988281250, 0.0001525878906250, -0.0007934570312500, 0.0000000000000000, +-0.0003967285156250, -0.0001525878906250, 0.0002136230468750, -0.0000305175781250, +-0.0002441406250000, -0.0000915527343750, 0.0006408691406250, -0.0001831054687500, +0.0008544921875000, -0.0000305175781250, 0.0004272460937500, 0.0000610351562500, +0.0005798339843750, -0.0000305175781250, 0.0007629394531250, 0.0001525878906250, +-0.0004577636718750, 0.0002136230468750, -0.0003051757812500, 0.0000305175781250, +-0.0003662109375000, -0.0000305175781250, -0.0012817382812500, 0.0000915527343750, +-0.0010070800781250, -0.0001831054687500, -0.0001220703125000, -0.0002746582031250, +-0.0006408691406250, -0.0001525878906250, -0.0001220703125000, -0.0001525878906250, +0.0011596679687500, -0.0002441406250000, 0.0005798339843750, 0.0001831054687500, +0.0003356933593750, 0.0001831054687500, 0.0010070800781250, 0.0001220703125000, +0.0002136230468750, 0.0003356933593750, -0.0009765625000000, 0.0003662109375000, +-0.0002136230468750, -0.0002136230468750, -0.0007324218750000, -0.0000915527343750, +-0.0012817382812500, -0.0000915527343750, -0.0006408691406250, -0.0006408691406250, +0.0005187988281250, 0.0003051757812500, -0.0000610351562500, 0.0000610351562500, +-0.0005798339843750, 0.0005493164062500, -0.0011901855468750, 0.0000000000000000, +-0.0003967285156250, -0.0007934570312500, 0.0004882812500000, -0.0003051757812500, +-0.0000610351562500, -0.0005187988281250, 0.0004272460937500, -0.0009765625000000, +0.0009460449218750, -0.0002746582031250, 0.0002746582031250, 0.0003967285156250, +-0.0002746582031250, -0.0002136230468750, 0.0001831054687500, 0.0008544921875000, +-0.0004577636718750, 0.0012512207031250, -0.0008850097656250, 0.0004577636718750, +-0.0003356933593750, 0.0003356933593750, 0.0000610351562500, 0.0008850097656250, +-0.0003356933593750, -0.0009155273437500, 0.0003356933593750, -0.0010375976562500, +0.0006103515625000, -0.0005187988281250, 0.0001831054687500, -0.0012817382812500, +0.0000305175781250, -0.0014343261718750, 0.0003051757812500, 0.0003967285156250, +-0.0002746582031250, 0.0000000000000000, -0.0004577636718750, 0.0000915527343750, +-0.0001525878906250, 0.0015258789062500, -0.0000610351562500, 0.0011596679687500, +-0.0002441406250000, 0.0002136230468750, 0.0002136230468750, 0.0009460449218750, +0.0003051757812500, 0.0002136230468750, 0.0000610351562500, -0.0012207031250000, +0.0000610351562500, -0.0004882812500000, 0.0002136230468750, -0.0010070800781250, +-0.0001525878906250, -0.0016784667968750, -0.0002441406250000, -0.0007324218750000, +-0.0000915527343750, 0.0000610351562500, -0.0000610351562500, -0.0007324218750000, +-0.0001831054687500, 0.0007324218750000, 0.0001525878906250, 0.0010375976562500, +0.0001831054687500, 0.0005493164062500, 0.0000610351562500, 0.0008850097656250, +0.0000915527343750, 0.0010375976562500, 0.0001831054687500, -0.0001220703125000, +-0.0000610351562500, 0.0001525878906250, -0.0001220703125000, -0.0000610351562500, +-0.0000305175781250, -0.0010070800781250, -0.0000305175781250, -0.0006408691406250, +-0.0000915527343750, -0.0006713867187500, 0.0000610351562500, -0.0010070800781250, +0.0000915527343750, -0.0005493164062500, 0.0000305175781250, 0.0000000000000000, +0.0000000000000000, -0.0004577636718750, 0.0000305175781250, 0.0004577636718750, +0.0000000000000000, 0.0005798339843750, -0.0000915527343750, 0.0003051757812500, +-0.0000305175781250, 0.0006103515625000, 0.0000000000000000, 0.0006713867187500, +-0.0000305175781250, 0.0000305175781250, 0.0000305175781250, 0.0002441406250000, +0.0000915527343750, 0.0000305175781250, 0.0000305175781250, -0.0005187988281250, +0.0000000000000000, -0.0002136230468750, 0.0000610351562500, -0.0005798339843750, +-0.0000305175781250, -0.0007629394531250, -0.0000305175781250, -0.0003356933593750, +0.0000000000000000, -0.0002746582031250, 0.0000305175781250, -0.0005798339843750, +0.0000000000000000, 0.0007629394531250, 0.0000000000000000, 0.0003356933593750, +0.0000610351562500, 0.0008239746093750, 0.0000610351562500, 0.0020141601562500, +0.0000000000000000, 0.0012512207031250, 0.0000000000000000, 0.0024719238281250, +-0.0000305175781250, 0.0026855468750000, -0.0000305175781250, 0.0022888183593750, +-0.0000305175781250, 0.0027465820312500, 0.0000305175781250, 0.0028991699218750, +0.0000000000000000, 0.0015258789062500, 0.0000000000000000, 0.0023803710937500, +0.0000305175781250, 0.0014343261718750, 0.0000000000000000, 0.0000610351562500, +0.0000305175781250, 0.0013427734375000, 0.0000000000000000, -0.0018920898437500, +0.0000305175781250, -0.0008850097656250, 0.0000610351562500, -0.0017089843750000, +0.0000610351562500, -0.0042724609375000, 0.0000000000000000, -0.0024719238281250, +0.0000305175781250, -0.0053405761718750, -0.0000305175781250, -0.0049133300781250, +0.0000000000000000, -0.0052185058593750, 0.0000000000000000, -0.0069274902343750, +0.0000000000000000, -0.0056762695312500, -0.0000610351562500, -0.0072631835937500, +0.0000000000000000, -0.0069274902343750, 0.0000000000000000, -0.0068664550781250, +0.0000000000000000, -0.0076904296875000, 0.0000000000000000, -0.0068054199218750, +0.0000000000000000, -0.0074462890625000, 0.0000000000000000, -0.0072326660156250, +0.0000000000000000, -0.0068359375000000, 0.0000000000000000, -0.0070800781250000, +0.0000000000000000, -0.0067138671875000, 0.0000000000000000, -0.0060729980468750, +0.0000305175781250, -0.0058593750000000, 0.0000610351562500, -0.0052185058593750, +0.0000305175781250, -0.0043640136718750, 0.0000305175781250, -0.0040588378906250, +0.0000000000000000, -0.0027770996093750, -0.0000305175781250, -0.0027160644531250, +0.0000000000000000, -0.0017700195312500, 0.0000000000000000, -0.0004577636718750, +0.0000000000000000, -0.0007934570312500, -0.0000305175781250, 0.0012207031250000, +0.0000305175781250, 0.0011901855468750, 0.0000000000000000, 0.0015563964843750, +0.0000000000000000, 0.0029907226562500, 0.0000000000000000, 0.0026855468750000, +0.0000305175781250, 0.0032958984375000, 0.0000000000000000, 0.0036315917968750, +0.0000000000000000, 0.0031738281250000, 0.0000000000000000, 0.0031433105468750, +0.0000000000000000, 0.0033264160156250, -0.0000305175781250, 0.0019226074218750, +0.0000000000000000, 0.0021667480468750, 0.0000000000000000, 0.0014648437500000, +0.0000000000000000, 0.0000915527343750, 0.0000000000000000, 0.0006713867187500, +0.0000305175781250, -0.0007934570312500, 0.0000305175781250, -0.0010070800781250, +0.0000000000000000, -0.0008239746093750, 0.0000000000000000, -0.0014343261718750, +-0.0000305175781250, -0.0013427734375000, -0.0000305175781250, -0.0006103515625000, +0.0000305175781250, -0.0008850097656250, 0.0000305175781250, -0.0004272460937500, +0.0000000000000000, 0.0004577636718750, 0.0000305175781250, 0.0000915527343750, +0.0000000000000000, 0.0006713867187500, -0.0000305175781250, 0.0009765625000000, +0.0000000000000000, 0.0005187988281250, -0.0000305175781250, 0.0003967285156250, +-0.0000305175781250, 0.0005798339843750, -0.0000610351562500, -0.0003662109375000, +0.0000305175781250, -0.0003967285156250, 0.0000000000000000, -0.0003662109375000, +0.0000000000000000, -0.0009155273437500, 0.0000610351562500, -0.0007934570312500, +0.0000305175781250, -0.0002746582031250, 0.0000000000000000, -0.0005187988281250, +0.0000000000000000, -0.0001220703125000, 0.0000000000000000, 0.0006408691406250, +-0.0000305175781250, 0.0002746582031250, -0.0000915527343750, 0.0004577636718750, +0.0000000000000000, 0.0008239746093750, 0.0000000000000000, 0.0003356933593750, +-0.0000305175781250, -0.0002136230468750, 0.0000305175781250, 0.0001525878906250, +0.0000610351562500, -0.0004577636718750, 0.0000000000000000, -0.0007324218750000, +0.0000305175781250, -0.0003356933593750, 0.0000305175781250, -0.0001831054687500, +-0.0000610351562500, -0.0005187988281250, -0.0000915527343750, 0.0002746582031250, +0.0000305175781250, 0.0003967285156250, -0.0000305175781250, 0.0001220703125000, +-0.0000305175781250, 0.0003051757812500, 0.0001525878906250, 0.0004577636718750, +0.0000915527343750, -0.0002746582031250, -0.0000305175781250, -0.0002746582031250, +0.0000610351562500, -0.0001525878906250, 0.0000000000000000, -0.0004882812500000, +-0.0001525878906250}, +{0.0000305175781250, 0.0169067382812500, -0.0000305175781250, 0.0136718750000000, +0.0000305175781250, 0.0174255371093750, 0.0000000000000000, 0.0166015625000000, +-0.0000305175781250, 0.0163574218750000, -0.0000305175781250, 0.0181884765625000, +0.0000000000000000, 0.0160522460937500, 0.0000305175781250, 0.0176086425781250, +0.0000000000000000, 0.0171203613281250, -0.0000305175781250, 0.0161743164062500, +0.0000000000000000, 0.0166625976562500, 0.0000000000000000, 0.0159606933593750, +0.0000305175781250, 0.0142211914062500, 0.0000305175781250, 0.0137329101562500, +0.0000000000000000, 0.0121459960937500, 0.0000000000000000, 0.0101623535156250, +0.0000000000000000, 0.0096130371093750, -0.0000305175781250, 0.0065612792968750, +0.0000000000000000, 0.0064697265625000, 0.0000000000000000, 0.0043640136718750, +0.0000000000000000, 0.0014038085937500, -0.0000305175781250, 0.0021057128906250, +0.0000000000000000, -0.0022277832031250, 0.0000305175781250, -0.0021057128906250, +0.0000000000000000, -0.0030517578125000, 0.0000000000000000, -0.0062255859375000, +0.0000000000000000, -0.0054321289062500, 0.0000000000000000, -0.0068664550781250, +-0.0000305175781250, -0.0075073242187500, -0.0000305175781250, -0.0065917968750000, +0.0000000000000000, -0.0065612792968750, 0.0000000000000000, -0.0069885253906250, +0.0000305175781250, -0.0042114257812500, 0.0000000000000000, -0.0047302246093750, +0.0000000000000000, -0.0033264160156250, 0.0000000000000000, -0.0005798339843750, +-0.0000305175781250, -0.0017089843750000, 0.0000305175781250, 0.0013427734375000, +0.0000305175781250, 0.0016174316406250, 0.0000305175781250, 0.0014038085937500, +-0.0000305175781250, 0.0026855468750000, 0.0000305175781250, 0.0024719238281250, +0.0000000000000000, 0.0015563964843750, -0.0000305175781250, 0.0020141601562500, +0.0000305175781250, 0.0011596679687500, 0.0000000000000000, -0.0002441406250000, +-0.0000610351562500, 0.0004272460937500, -0.0000610351562500, -0.0007934570312500, +0.0000000000000000, -0.0011596679687500, -0.0000305175781250, -0.0006713867187500, +0.0000305175781250, -0.0007629394531250, 0.0000610351562500, -0.0009765625000000, +0.0000610351562500, 0.0001220703125000, -0.0000305175781250, 0.0000915527343750, +0.0000305175781250, 0.0000915527343750, 0.0000000000000000, 0.0008239746093750, +-0.0000610351562500, 0.0006713867187500, -0.0000305175781250, 0.0001220703125000, +0.0000000000000000, 0.0004272460937500, -0.0000305175781250, 0.0000915527343750, +0.0000000000000000, -0.0007324218750000, 0.0000915527343750, -0.0003967285156250, +0.0000305175781250, -0.0004882812500000, -0.0000305175781250, -0.0008544921875000, +0.0000305175781250, -0.0003356933593750, 0.0000000000000000, 0.0002441406250000, +-0.0001220703125000, -0.0001831054687500, -0.0000305175781250, 0.0003967285156250, +0.0000000000000000, 0.0006713867187500, -0.0000305175781250, 0.0001831054687500, +0.0000305175781250, -0.0000305175781250, 0.0001525878906250, 0.0003356933593750, +0.0000610351562500, -0.0003967285156250, -0.0000305175781250, -0.0006103515625000, +0.0000610351562500, -0.0002441406250000, -0.0000610351562500, -0.0003051757812500, +-0.0001831054687500, -0.0004577636718750, -0.0000610351562500, 0.0003051757812500, +0.0000000000000000, 0.0003356933593750, -0.0001525878906250, 0.0001220703125000, +-0.0000305175781250, 0.0003662109375000, 0.0001525878906250, 0.0004272460937500, +0.0000610351562500, -0.0002441406250000, 0.0000000000000000, -0.0002136230468750, +0.0000915527343750, -0.0000915527343750, 0.0000610351562500, -0.0004272460937500, +-0.0001525878906250, -0.0004272460937500, -0.0001220703125000, 0.0000915527343750, +-0.0000305175781250, 0.0000000000000000, -0.0000915527343750, -0.0000305175781250, +-0.0000305175781250, 0.0003051757812500, 0.0001525878906250, 0.0002136230468750, +0.0000915527343750, -0.0002441406250000, -0.0000610351562500, -0.0001525878906250, +0.0000305175781250, -0.0000305175781250, 0.0000000000000000, -0.0002746582031250, +-0.0002136230468750, -0.0002746582031250, -0.0001831054687500, 0.0001220703125000, +-0.0000305175781250, 0.0000305175781250, -0.0000915527343750, -0.0000305175781250, +-0.0000305175781250, 0.0001525878906250, 0.0001525878906250, 0.0002136230468750, +0.0001220703125000, -0.0001525878906250, -0.0000915527343750, -0.0001220703125000, +-0.0000305175781250, -0.0000305175781250, -0.0000915527343750, -0.0002136230468750, +-0.0003356933593750, -0.0002746582031250, -0.0002746582031250, 0.0000915527343750, +0.0000610351562500, 0.0000915527343750, -0.0000610351562500, 0.0000000000000000, +0.0000000000000000, 0.0001525878906250, 0.0003662109375000, 0.0002136230468750, +0.0002441406250000, -0.0001220703125000, -0.0001525878906250, -0.0001220703125000, +0.0000915527343750, -0.0000305175781250, -0.0000915527343750, -0.0002136230468750, +-0.0006103515625000, -0.0002441406250000, -0.0003967285156250, 0.0000610351562500, +-0.0001525878906250, 0.0000305175781250, -0.0004577636718750, 0.0000305175781250, +-0.0001525878906250, 0.0001525878906250, 0.0004272460937500, 0.0001525878906250, +0.0001220703125000, -0.0000610351562500, 0.0002746582031250, -0.0000305175781250, +0.0005187988281250, 0.0000000000000000, 0.0001831054687500, -0.0001220703125000, +-0.0001525878906250, -0.0001220703125000, 0.0000915527343750, 0.0000610351562500, +-0.0003051757812500, 0.0000000000000000, -0.0004577636718750, 0.0000000000000000, +-0.0002136230468750, 0.0000915527343750, -0.0001831054687500, 0.0000915527343750, +-0.0003967285156250, -0.0000305175781250, 0.0000000000000000, 0.0000000000000000, +0.0000915527343750, 0.0000305175781250, 0.0000000000000000, -0.0000915527343750, +0.0001220703125000, -0.0000610351562500, 0.0001525878906250, 0.0000305175781250, +-0.0001525878906250, 0.0000000000000000, -0.0001831054687500, -0.0000305175781250, +-0.0000305175781250, 0.0000610351562500, -0.0000305175781250, 0.0000305175781250, +-0.0001525878906250, 0.0000000000000000, 0.0004577636718750, 0.0000305175781250, +0.0004272460937500, 0.0000305175781250, 0.0003967285156250, -0.0000610351562500, +0.0007934570312500, 0.0000000000000000, 0.0007629394531250, 0.0000000000000000, +-0.0002136230468750, 0.0000000000000000, 0.0002136230468750, -0.0000305175781250, +-0.0006103515625000, 0.0000610351562500, -0.0020141601562500, 0.0000305175781250, +-0.0013122558593750, 0.0000000000000000, -0.0026245117187500, 0.0000305175781250, +-0.0030822753906250, 0.0000000000000000, -0.0022583007812500, 0.0000305175781250, +-0.0023498535156250, 0.0000305175781250, -0.0026245117187500, 0.0000000000000000, +0.0004272460937500, -0.0000305175781250, -0.0003051757812500, 0.0000000000000000, +0.0013732910156250, 0.0000000000000000, 0.0044555664062500, -0.0000305175781250, +0.0032653808593750, 0.0000305175781250, 0.0070800781250000, 0.0000000000000000, +0.0072326660156250, 0.0000000000000000, 0.0077514648437500, 0.0000000000000000, +0.0100097656250000, 0.0000000000000000, 0.0094604492187500, 0.0000000000000000, +0.0102539062500000, 0.0000000000000000, 0.0105895996093750, -0.0000305175781250, +0.0097961425781250, 0.0000000000000000, 0.0092163085937500, 0.0000000000000000, +0.0089111328125000, 0.0000000000000000, 0.0073242187500000, 0.0000000000000000, +0.0063476562500000, 0.0000000000000000, 0.0050048828125000, -0.0000305175781250, +0.0037536621093750, 0.0000305175781250, 0.0035095214843750, -0.0000305175781250, +0.0007629394531250, 0.0000000000000000, -0.0016479492187500, 0.0000000000000000, +-0.0013732910156250, -0.0000305175781250, -0.0018615722656250, 0.0000000000000000, +-0.0040893554687500, 0.0000000000000000, -0.0009765625000000, 0.0000305175781250, +-0.0026245117187500, 0.0000000000000000, -0.0017700195312500, 0.0000000000000000, +0.0010375976562500, 0.0000000000000000, -0.0006408691406250, 0.0000000000000000, +0.0040283203125000, 0.0000305175781250, 0.0021667480468750, 0.0000000000000000, +0.0046081542968750, 0.0000000000000000, 0.0092468261718750, 0.0000305175781250, +0.0057983398437500, -0.0000305175781250, 0.0127868652343750, 0.0000305175781250, +0.0124816894531250, -0.0000305175781250, 0.0124816894531250, 0.0000305175781250, +0.0163574218750000, 0.0000000000000000, 0.0148315429687500, 0.0000000000000000, +0.0155334472656250, 0.0000305175781250, 0.0170288085937500, 0.0000000000000000, +0.0145568847656250, 0.0000000000000000, 0.0131835937500000, -0.0000305175781250, +0.0153198242187500, 0.0000305175781250, 0.0076293945312500, 0.0000305175781250, +0.0098571777343750, 0.0000000000000000, 0.0073242187500000, 0.0000000000000000, +0.0008239746093750, 0.0000305175781250, 0.0046386718750000, -0.0000305175781250, +-0.0027770996093750, -0.0000305175781250, -0.0032348632812500, 0.0000305175781250, +-0.0026855468750000, -0.0000305175781250, -0.0061645507812500, 0.0000000000000000, +-0.0052795410156250, -0.0000305175781250, -0.0040283203125000, 0.0000610351562500, +-0.0052795410156250, 0.0000610351562500, -0.0035705566406250, 0.0000000000000000, +-0.0011291503906250, 0.0000305175781250, -0.0027465820312500, -0.0000305175781250, +0.0004272460937500, -0.0000610351562500, 0.0006408691406250, 0.0000000000000000, +0.0003662109375000, 0.0000610351562500, 0.0018005371093750, 0.0000000000000000, +0.0015258789062500, 0.0000305175781250, 0.0008850097656250, 0.0000915527343750, +0.0012512207031250, 0.0000305175781250, 0.0008544921875000, -0.0000610351562500, +0.0000305175781250, -0.0000305175781250, 0.0004272460937500, -0.0000305175781250, +-0.0001525878906250, -0.0000915527343750, -0.0003967285156250, -0.0000305175781250, +-0.0001220703125000, 0.0000610351562500, 0.0000305175781250, 0.0000000000000000, +-0.0000915527343750, 0.0000610351562500, 0.0001525878906250, 0.0001220703125000, +0.0003051757812500, 0.0000305175781250, 0.0000915527343750, -0.0000305175781250, +0.0000000000000000, 0.0000305175781250, 0.0000915527343750, -0.0000915527343750, +-0.0003051757812500, -0.0001220703125000, -0.0003356933593750, 0.0000000000000000, +-0.0003051757812500, 0.0000305175781250, -0.0004882812500000, -0.0000610351562500, +-0.0004577636718750, 0.0001220703125000, -0.0001220703125000, 0.0001525878906250, +-0.0003051757812500, 0.0000305175781250, -0.0000610351562500, 0.0000000000000000, +0.0004272460937500, 0.0000915527343750, 0.0001525878906250, -0.0001220703125000, +0.0005187988281250, -0.0001831054687500, 0.0007934570312500, -0.0000915527343750, +0.0002746582031250, -0.0000915527343750, 0.0000305175781250, -0.0001831054687500, +0.0004272460937500, 0.0001220703125000, -0.0007629394531250, 0.0001525878906250, +-0.0008239746093750, 0.0000305175781250, -0.0004577636718750, 0.0002441406250000, +-0.0009460449218750, 0.0002136230468750, -0.0010375976562500, -0.0001831054687500, +0.0004272460937500, -0.0000915527343750, 0.0002136230468750, -0.0000915527343750, +0.0001525878906250, -0.0003967285156250, 0.0012512207031250, -0.0003356933593750, +0.0010681152343750, 0.0000000000000000, -0.0002136230468750, -0.0001220703125000, +0.0002136230468750, 0.0000000000000000, -0.0000610351562500, 0.0004882812500000, +-0.0014343261718750, 0.0003051757812500, -0.0010070800781250, 0.0000610351562500, +-0.0003356933593750, 0.0003051757812500, -0.0009155273437500, 0.0000915527343750, +-0.0004272460937500, -0.0007324218750000, 0.0012817382812500, -0.0000305175781250, +-0.0008239746093750, 0.0004577636718750, -0.0000610351562500, 0.0007019042968750, +-0.0009155273437500, 0.0001220703125000, -0.0002746582031250, -0.0002746582031250, +0.0010375976562500, 0.0002441406250000, 0.0005493164062500, -0.0007629394531250, +0.0001525878906250}, +{-0.1732177734375000, 0.0000000000000000, -0.1270751953125000, 0.0000305175781250, +-0.1393432617187500, 0.0000305175781250, -0.1225891113281250, 0.0000305175781250, +-0.0855102539062500, 0.0000000000000000, -0.1110839843750000, -0.0000305175781250, +-0.0522766113281250, 0.0000000000000000, -0.0614929199218750, 0.0000000000000000, +-0.0523986816406250, -0.0000610351562500, -0.0119628906250000, -0.0000305175781250, +-0.0327453613281250, 0.0000305175781250, 0.0000000000000000, 0.0000305175781250, +0.0033569335937500, 0.0000000000000000, 0.0012512207031250, 0.0000305175781250, +0.0157470703125000, 0.0000305175781250, 0.0118103027343750, -0.0000305175781250, +0.0097351074218750, 0.0000000000000000, 0.0136108398437500, 0.0000305175781250, +0.0088195800781250, 0.0000000000000000, 0.0026245117187500, 0.0000305175781250, +0.0067443847656250, 0.0000305175781250, -0.0015563964843750, 0.0000610351562500, +-0.0020446777343750, 0.0000305175781250, -0.0013427734375000, 0.0000000000000000, +-0.0050964355468750, 0.0000000000000000, -0.0042419433593750, -0.0000305175781250, +-0.0028076171875000, -0.0000610351562500, -0.0039672851562500, -0.0000305175781250, +-0.0025634765625000, 0.0000305175781250, -0.0002136230468750, -0.0000305175781250, +-0.0013732910156250, 0.0000305175781250, 0.0008544921875000, 0.0000610351562500, +0.0013122558593750, 0.0000000000000000, 0.0007019042968750, 0.0000000000000000, +0.0012207031250000, 0.0000000000000000, 0.0013732910156250, -0.0000610351562500, +0.0003967285156250, -0.0000915527343750, 0.0004577636718750, 0.0000000000000000, +0.0004272460937500, 0.0000000000000000, -0.0002441406250000, -0.0000305175781250, +-0.0000915527343750, 0.0000610351562500, -0.0001220703125000, 0.0001220703125000, +-0.0002746582031250, 0.0000000000000000, -0.0000915527343750, 0.0000305175781250, +0.0000915527343750, 0.0000915527343750, -0.0000610351562500, -0.0001220703125000, +0.0000915527343750, -0.0001525878906250, 0.0002136230468750, -0.0000915527343750, +-0.0000610351562500, -0.0000915527343750, -0.0003662109375000, -0.0001525878906250, +-0.0001220703125000, 0.0001220703125000, -0.0004882812500000, 0.0001220703125000, +-0.0007324218750000, 0.0000610351562500, -0.0002441406250000, 0.0001525878906250, +0.0000000000000000, 0.0001831054687500, -0.0003051757812500, -0.0001831054687500, +0.0006408691406250, -0.0000915527343750, 0.0007934570312500, -0.0000610351562500, +0.0003356933593750, -0.0003356933593750, 0.0005798339843750, -0.0002746582031250, +0.0008544921875000, 0.0000305175781250, -0.0007019042968750, -0.0000915527343750, +-0.0006408691406250, 0.0000000000000000, -0.0003662109375000, 0.0003356933593750, +-0.0011291503906250, 0.0002441406250000, -0.0011901855468750, 0.0000305175781250, +0.0003967285156250, 0.0002136230468750, 0.0000305175781250, 0.0000000000000000, +0.0000915527343750, -0.0004882812500000, 0.0013122558593750, -0.0002441406250000, +0.0010681152343750, -0.0003356933593750, -0.0000610351562500, -0.0006103515625000, +0.0003967285156250, -0.0002746582031250, 0.0002136230468750, 0.0004577636718750, +-0.0014953613281250, 0.0002441406250000, 0.0010070800781250, -0.0006408691406250, +-0.0002746582031250, -0.0007324218750000, 0.0004882812500000, -0.0002441406250000, +0.0000610351562500, -0.0002136230468750, -0.0011596679687500, -0.0005798339843750, +-0.0008544921875000, 0.0006103515625000, 0.0000000000000000, 0.0007324218750000, +-0.0004577636718750, 0.0003356933593750, -0.0001525878906250, 0.0007629394531250, +0.0009460449218750, 0.0009155273437500, 0.0005798339843750, -0.0004882812500000, +0.0000610351562500, -0.0002746582031250, 0.0005187988281250, -0.0002746582031250, +0.0001525878906250, -0.0014038085937500, -0.0007934570312500, -0.0011291503906250, +-0.0004272460937500, -0.0000610351562500, -0.0001831054687500, -0.0006408691406250, +-0.0005798339843750, -0.0001525878906250, -0.0002136230468750, 0.0013122558593750, +0.0005187988281250, 0.0006713867187500, 0.0001831054687500, 0.0003967285156250, +0.0001220703125000, 0.0011596679687500, 0.0004272460937500, 0.0003662109375000, +0.0001220703125000, -0.0008544921875000, -0.0004272460937500, -0.0000915527343750, +-0.0001220703125000, -0.0006103515625000, -0.0001220703125000, -0.0011596679687500, +-0.0003967285156250, -0.0004577636718750, -0.0001220703125000, 0.0000915527343750, +0.0002746582031250, -0.0003967285156250, 0.0000610351562500, 0.0003356933593750, +0.0000610351562500, 0.0006713867187500, 0.0002441406250000, 0.0001220703125000, +0.0001220703125000, -0.0001220703125000, -0.0002136230468750, 0.0003051757812500, +-0.0000915527343750, -0.0003051757812500, -0.0001525878906250, -0.0007324218750000, +-0.0002441406250000, 0.0000610351562500, -0.0000610351562500, 0.0005493164062500, +0.0001525878906250, -0.0001525878906250, 0.0000610351562500, 0.0012512207031250, +0.0000915527343750, 0.0016479492187500, 0.0001831054687500, 0.0006103515625000, +0.0000305175781250, 0.0007934570312500, -0.0001220703125000, 0.0014648437500000, +-0.0000610351562500, -0.0018005371093750, -0.0000305175781250, -0.0009765625000000, +-0.0001525878906250, -0.0016784667968750, -0.0000305175781250, -0.0046386718750000, +0.0001220703125000, -0.0033569335937500, 0.0000305175781250, -0.0024108886718750, +0.0000000000000000, -0.0044250488281250, 0.0000915527343750, -0.0011291503906250, +0.0000305175781250, 0.0019836425781250, -0.0000915527343750, -0.0010986328125000, +-0.0000305175781250, 0.0079956054687500, 0.0000305175781250, 0.0073547363281250, +-0.0000610351562500, 0.0071105957031250, -0.0000610351562500, 0.0133666992187500, +0.0000305175781250, 0.0115356445312500, 0.0000610351562500, 0.0046386718750000, +0.0000000000000000, 0.0118103027343750, 0.0000305175781250, -0.0021667480468750, +0.0000000000000000, -0.0142211914062500, -0.0000610351562500, -0.0013122558593750, +0.0000000000000000, -0.0486755371093750, 0.0000915527343750, -0.0323791503906250, +0.0000305175781250, -0.0565185546875000, 0.0000305175781250, -0.0997009277343750, +0.0000610351562500, -0.0673522949218750, 0.0000915527343750, -0.1422119140625000, +0.0000610351562500, -0.1279602050781250, 0.0000610351562500, -0.1482849121093750, +0.0000305175781250, -0.2034912109375000, 0.0000305175781250, -0.1672058105468750, +0.0000305175781250, -0.2322082519531250, 0.0000610351562500, -0.2271728515625000, +0.0000610351562500, -0.2299194335937500, 0.0000610351562500, -0.2670593261718750, +0.0000610351562500, -0.2479858398437500, 0.0000610351562500, -0.2685241699218750, +0.0000305175781250, -0.2733459472656250, 0.0000305175781250, -0.2658081054687500, +0.0000000000000000, -0.2714538574218750, 0.0000000000000000, -0.2742309570312500, +0.0000000000000000, -0.2580871582031250, 0.0000305175781250, -0.2659606933593750, +0.0000305175781250, -0.2578735351562500, 0.0000000000000000, -0.2431945800781250, +-0.0000305175781250, -0.2589111328125000, 0.0000000000000000, -0.2380371093750000, +-0.0000610351562500, -0.2438354492187500, -0.0000610351562500, -0.2415771484375000, +-0.0000305175781250, -0.2284240722656250, -0.0000610351562500, -0.2418518066406250, +-0.0000610351562500, -0.2284240722656250, -0.0000305175781250, -0.2324218750000000, +-0.0000305175781250, -0.2352905273437500, -0.0000305175781250, -0.2295227050781250, +-0.0000305175781250, -0.2380065917968750, -0.0000305175781250, -0.2383422851562500, +-0.0000305175781250, -0.2427062988281250, 0.0000000000000000, -0.2452392578125000, +-0.0000305175781250, -0.2455139160156250, 0.0000000000000000, -0.2496643066406250, +-0.0000610351562500, -0.2462158203125000, 0.0000000000000000, -0.2483825683593750, +-0.0000610351562500, -0.2437744140625000, 0.0000000000000000, -0.2384948730468750, +0.0000305175781250, -0.2407226562500000, 0.0000305175781250, -0.2190551757812500, +0.0000305175781250, -0.2237854003906250, 0.0000610351562500, -0.2085876464843750, +0.0000305175781250, -0.1863708496093750, 0.0000305175781250, -0.1955566406250000, +0.0000000000000000, -0.1480712890625000, 0.0000305175781250, -0.1536865234375000, +0.0000610351562500, -0.1338500976562500, 0.0000610351562500, -0.0936584472656250, +0.0000610351562500, -0.1094665527343750, 0.0000305175781250, -0.0586547851562500, +0.0000305175781250, -0.0590820312500000, 0.0000305175781250, -0.0473632812500000, +0.0000305175781250, -0.0124206542968750, 0.0000000000000000, -0.0244750976562500, +0.0000000000000000, 0.0011596679687500, 0.0000305175781250, 0.0049133300781250, +-0.0000305175781250, 0.0029296875000000, 0.0000000000000000, 0.0130615234375000, +0.0000305175781250, 0.0110778808593750, -0.0000305175781250, 0.0072937011718750, +-0.0000305175781250, 0.0097045898437500, 0.0000305175781250, 0.0059204101562500, +0.0000000000000000, -0.0000610351562500, -0.0000305175781250, 0.0028381347656250, +-0.0000305175781250, -0.0026550292968750, 0.0000000000000000, -0.0041503906250000, +-0.0000610351562500, -0.0025939941406250, -0.0000305175781250, -0.0035705566406250, +0.0000915527343750, -0.0039978027343750, 0.0000305175781250, -0.0006713867187500, +0.0000000000000000, -0.0009460449218750, 0.0000610351562500, -0.0004882812500000, +0.0000305175781250, 0.0018615722656250, -0.0000305175781250, 0.0011596679687500, +-0.0000305175781250, 0.0007629394531250, -0.0000610351562500, 0.0014343261718750, +-0.0000610351562500, 0.0006408691406250, 0.0000000000000000, -0.0007019042968750, +0.0000610351562500, -0.0000305175781250, -0.0000610351562500, -0.0005187988281250, +0.0000305175781250, -0.0010681152343750, 0.0001220703125000, -0.0004272460937500, +-0.0000305175781250, 0.0002136230468750, -0.0000915527343750, -0.0002441406250000, +0.0000000000000000, 0.0003662109375000, -0.0000305175781250, 0.0007324218750000, +-0.0001525878906250, 0.0002441406250000, -0.0000305175781250, -0.0000610351562500, +0.0000915527343750, 0.0002441406250000, 0.0000000000000000, -0.0003356933593750, +0.0000610351562500, -0.0005798339843750, 0.0001220703125000, -0.0002136230468750, +0.0000305175781250, -0.0000915527343750, -0.0001220703125000, -0.0003051757812500, +0.0000000000000000, 0.0003051757812500, -0.0000915527343750, 0.0004577636718750, +-0.0001831054687500, 0.0000915527343750, -0.0000610351562500, 0.0001220703125000, +0.0000610351562500, 0.0003356933593750, -0.0000610351562500, -0.0003051757812500, +0.0000610351562500, -0.0004577636718750, 0.0001525878906250, -0.0001831054687500, +0.0000305175781250, -0.0002441406250000, -0.0000610351562500, -0.0004577636718750, +0.0000305175781250, 0.0001220703125000, -0.0001525878906250, 0.0001831054687500, +-0.0001831054687500, 0.0000305175781250, -0.0000610351562500, 0.0001220703125000, +0.0001220703125000, 0.0000305175781250, 0.0000305175781250, -0.0002441406250000, +-0.0000610351562500, -0.0003051757812500, 0.0000915527343750, -0.0000610351562500, +0.0000000000000000, -0.0000915527343750, -0.0002136230468750, -0.0002441406250000, +-0.0000915527343750, 0.0001220703125000, -0.0000915527343750, 0.0002441406250000, +-0.0002441406250000, 0.0000000000000000, -0.0000610351562500, 0.0000000000000000, +0.0001525878906250, 0.0001525878906250, 0.0000305175781250, -0.0001831054687500, +-0.0000610351562500, -0.0003051757812500, 0.0000915527343750, -0.0000915527343750, +-0.0000915527343750, -0.0000610351562500, -0.0003051757812500, -0.0002746582031250, +-0.0001831054687500, 0.0001220703125000, -0.0000305175781250, 0.0002441406250000, +-0.0002136230468750, 0.0000305175781250, -0.0000610351562500, -0.0000305175781250, +0.0003356933593750, 0.0001220703125000, 0.0001220703125000, -0.0001831054687500, +0.0000610351562500, -0.0002441406250000, 0.0002441406250000, -0.0000915527343750, +0.0000000000000000}, +{-0.0000610351562500, -0.1788635253906250, 0.0000000000000000, -0.1888122558593750, +0.0000305175781250, -0.1915283203125000, 0.0000000000000000, -0.1538391113281250, +0.0000610351562500, -0.1652832031250000, 0.0000305175781250, -0.1402587890625000, +0.0000000000000000, -0.0991516113281250, 0.0000000000000000, -0.1190490722656250, +0.0000000000000000, -0.0572814941406250, 0.0000000000000000, -0.0572204589843750, +-0.0000305175781250, -0.0456848144531250, 0.0000305175781250, -0.0059814453125000, +0.0000610351562500, -0.0207824707031250, 0.0000000000000000, 0.0022277832031250, +0.0000305175781250, 0.0083312988281250, 0.0000305175781250, 0.0032958984375000, +0.0000000000000000, 0.0082397460937500, -0.0000305175781250, 0.0086364746093750, +0.0000000000000000, 0.0014953613281250, -0.0000305175781250, 0.0021667480468750, +-0.0000610351562500, 0.0011901855468750, 0.0000000000000000, -0.0038146972656250, +0.0000305175781250, -0.0024108886718750, -0.0000305175781250, -0.0016479492187500, +0.0000305175781250, -0.0030517578125000, 0.0000915527343750, -0.0014953613281250, +0.0000000000000000, 0.0010070800781250, -0.0000305175781250, -0.0002136230468750, +0.0000000000000000, 0.0008239746093750, -0.0000610351562500, 0.0017089843750000, +-0.0001220703125000, 0.0006713867187500, -0.0000305175781250, -0.0001220703125000, +0.0000000000000000, 0.0005187988281250, -0.0000305175781250, -0.0004882812500000, +0.0000610351562500, -0.0009765625000000, 0.0001525878906250, -0.0003356933593750, +0.0000305175781250, -0.0000915527343750, -0.0000610351562500, -0.0005187988281250, +0.0000610351562500, 0.0002136230468750, -0.0000915527343750, 0.0005187988281250, +-0.0001831054687500, 0.0000915527343750, -0.0000610351562500, 0.0000000000000000, +0.0000000000000000, 0.0003051757812500, -0.0000915527343750, -0.0003662109375000, +0.0000915527343750, -0.0005493164062500, 0.0001831054687500, -0.0001525878906250, +0.0000000000000000, -0.0001220703125000, -0.0000610351562500, -0.0003662109375000, +0.0000610351562500, 0.0002441406250000, -0.0001525878906250, 0.0004272460937500, +-0.0002441406250000, 0.0000610351562500, -0.0000610351562500, 0.0000610351562500, +0.0000610351562500, 0.0002441406250000, -0.0001220703125000, -0.0003051757812500, +0.0000305175781250, -0.0003662109375000, 0.0001525878906250, -0.0001525878906250, +0.0000305175781250, -0.0001220703125000, -0.0000915527343750, -0.0000915527343750, +-0.0001220703125000, 0.0001220703125000, -0.0001220703125000, 0.0002136230468750, +-0.0001525878906250, 0.0000000000000000, -0.0000610351562500, -0.0000610351562500, +0.0000915527343750, 0.0001525878906250, -0.0000305175781250, -0.0002136230468750, +0.0000305175781250, -0.0003356933593750, 0.0001525878906250, -0.0000915527343750, +0.0000000000000000, 0.0000305175781250, -0.0002136230468750, -0.0001525878906250, +-0.0000915527343750, 0.0001220703125000, -0.0000915527343750, 0.0002746582031250, +-0.0002136230468750, 0.0000305175781250, -0.0000610351562500, -0.0001220703125000, +0.0001525878906250, 0.0000305175781250, 0.0000305175781250, -0.0002136230468750, +0.0000305175781250, -0.0003662109375000, 0.0001831054687500, -0.0001220703125000, +-0.0000305175781250, 0.0000610351562500, -0.0003051757812500, -0.0001220703125000, +-0.0001525878906250, 0.0001220703125000, -0.0001525878906250, 0.0002441406250000, +-0.0003967285156250, 0.0000610351562500, -0.0001525878906250, -0.0001220703125000, +0.0002136230468750, 0.0000610351562500, 0.0000305175781250, -0.0001525878906250, +0.0000610351562500, -0.0002441406250000, 0.0002441406250000, -0.0000915527343750, +0.0000915527343750, 0.0000610351562500, -0.0001525878906250, -0.0000915527343750, +-0.0000305175781250, 0.0000610351562500, 0.0000915527343750, 0.0002136230468750, +-0.0000915527343750, 0.0000610351562500, 0.0000305175781250, 0.0000000000000000, +0.0003967285156250, 0.0000915527343750, 0.0002746582031250, -0.0000610351562500, +-0.0004882812500000, -0.0001525878906250, -0.0001220703125000, -0.0000305175781250, +-0.0004577636718750, 0.0000305175781250, -0.0015869140625000, -0.0000915527343750, +-0.0012207031250000, 0.0000610351562500, -0.0000610351562500, 0.0001220703125000, +-0.0011596679687500, 0.0000305175781250, 0.0006408691406250, 0.0000305175781250, +0.0036010742187500, 0.0000610351562500, 0.0016784667968750, -0.0000610351562500, +0.0018310546875000, -0.0000915527343750, 0.0059204101562500, 0.0000000000000000, +-0.0036010742187500, -0.0000305175781250, -0.0094909667968750, -0.0000610351562500, +-0.0038452148437500, 0.0000305175781250, -0.0398559570312500, 0.0000305175781250, +-0.0322875976562500, 0.0000000000000000, -0.0533142089843750, 0.0000305175781250, +-0.0901794433593750, 0.0000610351562500, -0.0724487304687500, -0.0000305175781250, +-0.1173400878906250, 0.0000000000000000, -0.1232299804687500, 0.0000000000000000, +-0.1164550781250000, -0.0000305175781250, -0.1358947753906250, -0.0000610351562500, +-0.1337280273437500, 0.0000305175781250, -0.0971679687500000, 0.0000305175781250, +-0.1155700683593750, 0.0000000000000000, -0.0749511718750000, 0.0000000000000000, +-0.0227050781250000, 0.0000610351562500, -0.0484619140625000, 0.0000000000000000, +0.0701599121093750, 0.0000000000000000, 0.0583190917968750, 0.0000000000000000, +0.1020507812500000, -0.0000305175781250, 0.1978759765625000, -0.0000305175781250, +0.1622009277343750, 0.0000000000000000, 0.2756347656250000, 0.0000610351562500, +0.2764587402343750, 0.0000305175781250, 0.3076477050781250, 0.0000305175781250, +0.3871154785156250, 0.0000305175781250, 0.3618774414062500, 0.0000000000000000, +0.4421997070312500, 0.0000000000000000, 0.4496765136718750, 0.0000610351562500, +0.4650268554687500, 0.0000000000000000, 0.5104980468750000, 0.0000000000000000, +0.4947509765625000, 0.0000610351562500, 0.5336914062500000, 0.0000000000000000, +0.5345764160156250, 0.0000305175781250, 0.5450439453125000, 0.0000305175781250, +0.5698547363281250, 0.0000305175781250, 0.5559997558593750, 0.0000305175781250, +0.5819396972656250, 0.0000000000000000, 0.5802612304687500, 0.0000305175781250, +0.5871276855468750, 0.0000305175781250, 0.6038513183593750, 0.0000305175781250, +0.5926208496093750, 0.0000000000000000, 0.6171875000000000, -0.0000305175781250, +0.6148986816406250, 0.0000305175781250, 0.6169738769531250, 0.0000305175781250, +0.6322631835937500, 0.0000305175781250, 0.6273498535156250, 0.0000000000000000, +0.6412353515625000, 0.0000000000000000, 0.6433105468750000, 0.0000305175781250, +0.6436462402343750, 0.0000305175781250, 0.6510620117187500, 0.0000000000000000, +0.6474304199218750, 0.0000000000000000, 0.6364135742187500, 0.0000305175781250, +0.6489868164062500, 0.0000000000000000, 0.6247253417968750, 0.0000000000000000, +0.6054382324218750, 0.0000305175781250, 0.6287841796875000, 0.0000305175781250, +0.5438537597656250, 0.0000000000000000, 0.5796508789062500, 0.0000000000000000, +0.5264892578125000, 0.0000610351562500, 0.4465332031250000, 0.0000305175781250, +0.5121765136718750, 0.0000305175781250, 0.3138122558593750, 0.0000000000000000, +0.3676757812500000, 0.0000000000000000, 0.2991943359375000, -0.0000305175781250, +0.1372375488281250, 0.0000305175781250, 0.2400817871093750, 0.0000000000000000, +0.0099792480468750, 0.0000305175781250, 0.0283508300781250, 0.0000305175781250, +-0.0129699707031250, 0.0000610351562500, -0.1678161621093750, 0.0000305175781250, +-0.0939941406250000, 0.0000000000000000, -0.2091979980468750, 0.0000000000000000, +-0.2213134765625000, 0.0000305175781250, -0.2009582519531250, -0.0000305175781250, +-0.2481079101562500, -0.0000305175781250, -0.2426757812500000, 0.0000610351562500, +-0.1946411132812500, 0.0000000000000000, -0.2182617187500000, 0.0000305175781250, +-0.1806030273437500, 0.0000610351562500, -0.1220703125000000, 0.0000915527343750, +-0.1584167480468750, -0.0000610351562500, -0.0707397460937500, -0.0000305175781250, +-0.0733642578125000, 0.0000000000000000, -0.0624694824218750, -0.0000305175781250, +-0.0075378417968750, -0.0000610351562500, -0.0274963378906250, 0.0000305175781250, +0.0014343261718750, 0.0000610351562500, 0.0091247558593750, 0.0000000000000000, +0.0029602050781250, 0.0000610351562500, 0.0096435546875000, 0.0000915527343750, +0.0099487304687500, -0.0000610351562500, 0.0018920898437500, -0.0000305175781250, +0.0031433105468750, 0.0000000000000000, 0.0018310546875000, -0.0001525878906250, +-0.0040893554687500, -0.0001220703125000, -0.0022277832031250, 0.0000610351562500, +-0.0023193359375000, 0.0000610351562500, -0.0039978027343750, 0.0000000000000000, +-0.0021057128906250, 0.0000915527343750, 0.0001525878906250, 0.0001525878906250, +-0.0013427734375000, -0.0000305175781250, 0.0010375976562500, -0.0000305175781250, +0.0018005371093750, -0.0000305175781250, 0.0007324218750000, -0.0002136230468750, +0.0007629394531250, -0.0002136230468750, 0.0013122558593750, 0.0000000000000000, +-0.0003662109375000, -0.0000610351562500, -0.0005798339843750, 0.0000000000000000, +-0.0000610351562500, 0.0002441406250000, -0.0004577636718750, 0.0001525878906250, +-0.0006713867187500, 0.0000000000000000, 0.0004272460937500, 0.0001220703125000, +0.0005187988281250, 0.0000000000000000, 0.0000610351562500, -0.0003356933593750, +0.0003051757812500, -0.0001831054687500, 0.0006103515625000, -0.0001525878906250, +-0.0007019042968750, -0.0003051757812500, -0.0008544921875000, -0.0000915527343750, +-0.0003051757812500, 0.0002441406250000, -0.0006103515625000, 0.0000305175781250, +-0.0009155273437500, 0.0001831054687500, 0.0007019042968750, 0.0004577636718750, +0.0007629394531250, 0.0001220703125000, 0.0002746582031250, -0.0001831054687500, +0.0008544921875000, 0.0000915527343750, 0.0010681152343750, -0.0004577636718750, +-0.0006103515625000, -0.0006103515625000, -0.0004882812500000, -0.0002746582031250, +-0.0001831054687500, -0.0000610351562500, -0.0012207031250000, 0.0004577636718750, +0.0010070800781250, -0.0005187988281250, -0.0007019042968750, -0.0002746582031250, +-0.0002746582031250, -0.0001831054687500, -0.0001220703125000, -0.0007019042968750, +-0.0008544921875000, -0.0007019042968750, -0.0009765625000000, 0.0002441406250000, +0.0003967285156250, 0.0000305175781250, 0.0002746582031250, 0.0001220703125000, +0.0000610351562500, 0.0009765625000000, 0.0008239746093750, 0.0007629394531250, +0.0008850097656250, 0.0000915527343750, -0.0003051757812500, 0.0005798339843750, +-0.0001525878906250, 0.0000915527343750, -0.0000610351562500, -0.0009155273437500, +-0.0008544921875000, -0.0004577636718750, -0.0007629394531250, -0.0004272460937500, +0.0000915527343750, -0.0009765625000000, -0.0000610351562500, -0.0003662109375000, +-0.0000915527343750, 0.0004272460937500, 0.0005493164062500, -0.0000915527343750, +0.0004577636718750, 0.0001831054687500, -0.0000915527343750, 0.0005493164062500, +0.0000610351562500, 0.0002441406250000, 0.0000000000000000, -0.0002441406250000, +-0.0005493164062500, 0.0000305175781250, -0.0004272460937500, 0.0003967285156250, +0.0000305175781250, 0.0000000000000000, -0.0001525878906250, 0.0003051757812500, +-0.0000610351562500, 0.0012512207031250, 0.0003967285156250, 0.0008239746093750, +0.0002746582031250, -0.0004272460937500, -0.0000915527343750, 0.0008239746093750, +0.0000915527343750, -0.0006713867187500, 0.0000915527343750, -0.0034484863281250, +-0.0003662109375000, -0.0017395019531250, -0.0002746582031250, -0.0021057128906250, +-0.0000305175781250, -0.0047607421875000, -0.0001525878906250, -0.0001220703125000, +-0.0000610351562500, 0.0039672851562500, 0.0002441406250000, -0.0004577636718750, +0.0001831054687500}, +{-0.0602416992187500, -0.0000915527343750, -0.0938110351562500, 0.0000610351562500, +-0.0245056152343750, 0.0000305175781250, -0.0187377929687500, 0.0000000000000000, +-0.0201416015625000, 0.0000915527343750, 0.0121765136718750, 0.0000610351562500, +0.0035095214843750, -0.0000915527343750, 0.0048217773437500, 0.0000000000000000, +0.0102539062500000, -0.0000305175781250, 0.0049743652343750, -0.0001831054687500, +-0.0010070800781250, -0.0000915527343750, 0.0025329589843750, 0.0000305175781250, +-0.0024108886718750, -0.0000915527343750, -0.0045166015625000, 0.0000000000000000, +-0.0020446777343750, 0.0002136230468750, -0.0016784667968750, 0.0000915527343750, +-0.0029602050781250, 0.0000000000000000, 0.0007629394531250, 0.0001220703125000, +0.0012207031250000, -0.0000305175781250, 0.0003051757812500, -0.0002746582031250, +0.0013427734375000, -0.0001525878906250, 0.0016479492187500, -0.0001220703125000, +-0.0003051757812500, -0.0002746582031250, -0.0003356933593750, -0.0000915527343750, +0.0001525878906250, 0.0002441406250000, -0.0006408691406250, 0.0000305175781250, +-0.0008239746093750, 0.0001831054687500, 0.0005493164062500, 0.0003356933593750, +0.0006408691406250, 0.0000305175781250, 0.0001220703125000, -0.0001831054687500, +0.0004577636718750, 0.0000305175781250, 0.0007324218750000, -0.0003662109375000, +-0.0006713867187500, -0.0005187988281250, -0.0007934570312500, -0.0001525878906250, +-0.0001831054687500, -0.0000915527343750, -0.0005798339843750, -0.0003356933593750, +-0.0009460449218750, 0.0003356933593750, 0.0006103515625000, 0.0004577636718750, +0.0006713867187500, 0.0001831054687500, 0.0002746582031250, 0.0003356933593750, +0.0008239746093750, -0.0005493164062500, -0.0009460449218750, 0.0002746582031250, +0.0006713867187500, -0.0001831054687500, 0.0004577636718750, 0.0000305175781250, +0.0001220703125000, 0.0006713867187500, 0.0004882812500000, 0.0005187988281250, +0.0007629394531250, -0.0000915527343750, -0.0006103515625000, 0.0002746582031250, +-0.0007019042968750, 0.0000000000000000, -0.0002136230468750, -0.0008239746093750, +-0.0006408691406250, -0.0004882812500000, -0.0008544921875000, -0.0003662109375000, +0.0003967285156250, -0.0007629394531250, 0.0003967285156250, -0.0003356933593750, +0.0000915527343750, 0.0003662109375000, 0.0006103515625000, -0.0000305175781250, +0.0007629394531250, 0.0002441406250000, -0.0002746582031250, 0.0005187988281250, +-0.0002746582031250, 0.0003051757812500, -0.0000610351562500, 0.0000915527343750, +-0.0006103515625000, 0.0002136230468750, -0.0006103515625000, 0.0005187988281250, +0.0001220703125000, 0.0003662109375000, 0.0000915527343750, 0.0001220703125000, +0.0000000000000000, 0.0005798339843750, 0.0003967285156250, 0.0007324218750000, +0.0004272460937500, -0.0014648437500000, -0.0001220703125000, -0.0007019042968750, +-0.0000610351562500, -0.0010375976562500, -0.0000305175781250, -0.0036926269531250, +-0.0004272460937500, -0.0028381347656250, -0.0003967285156250, 0.0010070800781250, +0.0000915527343750, -0.0018615722656250, -0.0000305175781250, 0.0014953613281250, +0.0000000000000000, 0.0088195800781250, 0.0003051757812500, 0.0043945312500000, +0.0002746582031250, 0.0014038085937500, -0.0000915527343750, 0.0126037597656250, +-0.0000610351562500, -0.0104980468750000, 0.0000000000000000, -0.0263977050781250, +-0.0002136230468750, -0.0069885253906250, -0.0002441406250000, -0.0854797363281250, +0.0000610351562500, -0.0653381347656250, 0.0000000000000000, -0.0930480957031250, +0.0000000000000000, -0.1628723144531250, 0.0001831054687500, -0.1232299804687500, +0.0002136230468750, -0.1783142089843750, -0.0000305175781250, -0.1967163085937500, +-0.0000305175781250, -0.1602478027343750, 0.0000305175781250, -0.1687927246093750, +-0.0001525878906250, -0.1882019042968750, -0.0001525878906250, -0.0605468750000000, +-0.0000305175781250, -0.1136169433593750, -0.0000305175781250, -0.0315551757812500, +-0.0000610351562500, 0.1007995605468750, 0.0000000000000000, 0.0096130371093750, +0.0000000000000000, 0.2584838867187500, -0.0001525878906250, 0.2217102050781250, +-0.0001525878906250, 0.2854309082031250, -0.0000915527343750, 0.4679260253906250, +-0.0001220703125000, 0.3681945800781250, -0.0001220703125000, 0.5502014160156250, +0.0000305175781250, 0.5587158203125000, 0.0000305175781250, 0.5479125976562500, +-0.0000305175781250, 0.6390686035156250, 0.0000610351562500, 0.6114196777343750, +0.0000305175781250, 0.5705566406250000, 0.0000610351562500, 0.6248168945312500, +-0.0000305175781250, 0.5467224121093750, 0.0000305175781250, 0.4653015136718750, +0.0001220703125000, 0.5466918945312500, 0.0000610351562500, 0.3243103027343750, +0.0001831054687500, 0.3807067871093750, 0.0001831054687500, 0.2969055175781250, +0.0001525878906250, 0.1177673339843750, 0.0001525878906250, 0.2469787597656250, +0.0001831054687500, -0.0136108398437500, 0.0001525878906250, 0.0231323242187500, +0.0000915527343750, -0.0147399902343750, 0.0001525878906250, -0.1794738769531250, +0.0001831054687500, -0.0779724121093750, 0.0002136230468750, -0.2492065429687500, +0.0000915527343750, -0.2300109863281250, 0.0001525878906250, -0.2435913085937500, +0.0001220703125000, -0.3493652343750000, 0.0000610351562500, -0.2927551269531250, +0.0000915527343750, -0.3686218261718750, 0.0000915527343750, -0.3653564453125000, +0.0000915527343750, -0.3666381835937500, 0.0000610351562500, -0.4049987792968750, +0.0000610351562500, -0.3789062500000000, 0.0001220703125000, -0.4119262695312500, +0.0000305175781250, -0.4085388183593750, 0.0000610351562500, -0.4041748046875000, +0.0000610351562500, -0.4184265136718750, 0.0000610351562500, -0.4075927734375000, +0.0000610351562500, -0.4136352539062500, 0.0000305175781250, -0.4086303710937500, +0.0000915527343750, -0.4034423828125000, 0.0000610351562500, -0.4063720703125000, +0.0000610351562500, -0.3986511230468750, 0.0000610351562500, -0.3829345703125000, +0.0000610351562500, -0.3847961425781250, 0.0000915527343750, -0.3695068359375000, +0.0000305175781250, -0.3464965820312500, 0.0000915527343750, -0.3403930664062500, +0.0000915527343750, -0.2973937988281250, 0.0000915527343750, -0.3014221191406250, +0.0000915527343750, -0.2619628906250000, 0.0000610351562500, -0.2141113281250000, +0.0001220703125000, -0.2284545898437500, 0.0001220703125000, -0.1188659667968750, +0.0001220703125000, -0.1353759765625000, 0.0001220703125000, -0.0817871093750000, +0.0001525878906250, 0.0155639648437500, 0.0001220703125000, -0.0202636718750000, +0.0001525878906250, 0.1386413574218750, 0.0001220703125000, 0.1271057128906250, +0.0001525878906250, 0.1801147460937500, 0.0001525878906250, 0.3051757812500000, +0.0001220703125000, 0.2618408203125000, 0.0000610351562500, 0.3903808593750000, +0.0000610351562500, 0.3998107910156250, 0.0000610351562500, 0.4124450683593750, +0.0000610351562500, 0.4889526367187500, 0.0000000000000000, 0.4703674316406250, +0.0000610351562500, 0.4694519042968750, 0.0000000000000000, 0.4983215332031250, +0.0000000000000000, 0.4441833496093750, -0.0000305175781250, 0.3994750976562500, +-0.0000610351562500, 0.4323425292968750, -0.0000610351562500, 0.2718505859375000, +-0.0000915527343750, 0.2962036132812500, -0.0000915527343750, 0.2237854003906250, +-0.0000915527343750, 0.0832824707031250, -0.0000915527343750, 0.1499938964843750, +-0.0000915527343750, -0.0229187011718750, -0.0000305175781250, -0.0306396484375000, +-0.0000305175781250, -0.0401306152343750, -0.0000305175781250, -0.1332702636718750, +0.0000000000000000, -0.1034545898437500, 0.0000305175781250, -0.1183776855468750, +-0.0000610351562500, -0.1409912109375000, -0.0000915527343750, -0.1105651855468750, +0.0000000000000000, -0.0869445800781250, -0.0000305175781250, -0.1051940917968750, +-0.0000915527343750, -0.0419311523437500, 0.0000610351562500, -0.0424194335937500, +0.0000915527343750, -0.0351562500000000, 0.0000000000000000, 0.0028381347656250, +0.0000000000000000, -0.0100402832031250, 0.0000915527343750, 0.0014343261718750, +-0.0000610351562500, 0.0077209472656250, -0.0000610351562500, 0.0022277832031250, +-0.0000610351562500, 0.0003356933593750, -0.0000915527343750, 0.0025634765625000, +-0.0000915527343750, -0.0015258789062500, 0.0000915527343750, -0.0029907226562500, +0.0000915527343750, -0.0011291503906250, 0.0000000000000000, -0.0007324218750000, +0.0000610351562500, -0.0016784667968750, 0.0001220703125000, 0.0006103515625000, +-0.0001220703125000, 0.0011901855468750, -0.0001525878906250, 0.0003051757812500, +-0.0000610351562500, 0.0003967285156250, -0.0001220703125000, 0.0007934570312500, +-0.0001525878906250, -0.0003662109375000, 0.0000915527343750, -0.0006103515625000, +0.0000915527343750, -0.0001220703125000, -0.0000305175781250, -0.0001831054687500, +0.0000610351562500, -0.0004577636718750, 0.0000915527343750, 0.0002746582031250, +-0.0001525878906250, 0.0004882812500000, -0.0001525878906250, 0.0000610351562500, +-0.0000305175781250, 0.0000000000000000, -0.0000915527343750, 0.0002441406250000, +-0.0001831054687500, -0.0002136230468750, 0.0000305175781250, -0.0003967285156250, +0.0000915527343750, -0.0001525878906250, -0.0000305175781250, 0.0000305175781250, +0.0000000000000000, 0.0000305175781250, 0.0000000000000000, 0.0000610351562500, +-0.0001220703125000, 0.0002441406250000, -0.0001831054687500, 0.0000305175781250, +-0.0000915527343750, -0.0001831054687500, 0.0000000000000000, 0.0000610351562500, +-0.0000915527343750, -0.0000915527343750, 0.0000610351562500, -0.0003662109375000, +0.0001220703125000, -0.0000915527343750, -0.0000305175781250, 0.0002136230468750, +-0.0001525878906250, 0.0000000000000000, -0.0000610351562500, 0.0000305175781250, +-0.0000610351562500, 0.0002441406250000, -0.0001525878906250, 0.0000000000000000, +-0.0000305175781250, -0.0003051757812500, 0.0001831054687500, -0.0001220703125000, +0.0000610351562500, -0.0001220703125000, -0.0000305175781250, -0.0003051757812500, +0.0001220703125000, -0.0000915527343750, 0.0000000000000000, 0.0002441406250000, +-0.0003356933593750, 0.0000000000000000, -0.0002441406250000, 0.0000915527343750, +0.0000915527343750, 0.0002441406250000, -0.0000610351562500, 0.0000000000000000, +-0.0000610351562500, -0.0002746582031250, 0.0004272460937500, -0.0000915527343750, +0.0003356933593750, -0.0000610351562500, -0.0005798339843750, -0.0002746582031250, +-0.0002746582031250, -0.0001525878906250, -0.0002136230468750, 0.0001525878906250, +-0.0012207031250000, 0.0000305175781250, -0.0010986328125000, 0.0000305175781250, +0.0011596679687500, 0.0001831054687500, 0.0007934570312500, 0.0000610351562500, +-0.0002746582031250, -0.0001831054687500, 0.0026855468750000, -0.0000305175781250, +0.0023193359375000, -0.0000610351562500, -0.0130920410156250, -0.0002136230468750, +-0.0029296875000000, -0.0000610351562500, -0.0221252441406250, 0.0000915527343750, +-0.0466308593750000, -0.0000305175781250, -0.0293579101562500, 0.0000610351562500, +-0.0769348144531250, 0.0000915527343750, -0.0787963867187500, 0.0000305175781250, +-0.0742797851562500, -0.0000305175781250, -0.1016540527343750, 0.0000000000000000, +-0.0967712402343750, -0.0000305175781250, -0.0523376464843750, -0.0000915527343750, +-0.0806579589843750, 0.0000000000000000, -0.0219726562500000, 0.0000305175781250, +0.0503845214843750, -0.0000305175781250, 0.0073547363281250, 0.0000305175781250, +0.1644897460937500, 0.0000915527343750, 0.1576232910156250, 0.0000305175781250, +0.1967163085937500, 0.0000000000000000, 0.3108520507812500, 0.0000000000000000, +0.2666320800781250, -0.0000305175781250, 0.3291625976562500, -0.0000610351562500, +0.3556518554687500}, +{-0.0000915527343750, 0.0062255859375000, -0.0000610351562500, -0.0000915527343750, +0.0000000000000000, 0.0017089843750000, -0.0001525878906250, 0.0034179687500000, +-0.0001525878906250, -0.0012817382812500, 0.0000610351562500, -0.0024414062500000, +0.0000305175781250, -0.0007019042968750, -0.0000305175781250, -0.0009155273437500, +0.0001220703125000, -0.0017395019531250, 0.0001525878906250, 0.0004882812500000, +-0.0001220703125000, 0.0009765625000000, -0.0000610351562500, 0.0001831054687500, +0.0000000000000000, 0.0003662109375000, -0.0002136230468750, 0.0007629394531250, +-0.0002136230468750, -0.0003356933593750, 0.0000305175781250, -0.0005798339843750, +0.0000000000000000, -0.0001220703125000, -0.0000610351562500, -0.0001525878906250, +0.0001220703125000, -0.0003967285156250, 0.0000915527343750, 0.0001525878906250, +-0.0001220703125000, 0.0003662109375000, -0.0000915527343750, 0.0000610351562500, +0.0000000000000000, -0.0001831054687500, -0.0000610351562500, -0.0001220703125000, +-0.0000610351562500, -0.0000915527343750, 0.0000305175781250, -0.0002746582031250, +0.0000610351562500, -0.0001220703125000, -0.0000305175781250, 0.0001831054687500, +-0.0000305175781250, -0.0000610351562500, 0.0000610351562500, 0.0000305175781250, +-0.0000915527343750, 0.0002136230468750, -0.0001831054687500, 0.0000305175781250, +-0.0000610351562500, -0.0003051757812500, 0.0000915527343750, -0.0001220703125000, +-0.0000305175781250, -0.0000610351562500, -0.0000610351562500, -0.0002441406250000, +0.0000915527343750, -0.0000915527343750, -0.0000305175781250, 0.0002441406250000, +-0.0003356933593750, 0.0001220703125000, -0.0001831054687500, 0.0000000000000000, +0.0001220703125000, 0.0001525878906250, -0.0000915527343750, 0.0000000000000000, +0.0000000000000000, -0.0003356933593750, 0.0004882812500000, -0.0001831054687500, +0.0003662109375000, -0.0000305175781250, -0.0005187988281250, -0.0002441406250000, +-0.0002746582031250, -0.0000915527343750, -0.0001831054687500, 0.0002136230468750, +-0.0011596679687500, 0.0001220703125000, -0.0010681152343750, -0.0000305175781250, +0.0010375976562500, 0.0001525878906250, 0.0008239746093750, 0.0000000000000000, +-0.0009765625000000, -0.0002746582031250, 0.0017700195312500, -0.0001220703125000, +0.0019836425781250, -0.0000610351562500, -0.0170593261718750, -0.0001525878906250, +-0.0062255859375000, -0.0000610351562500, -0.0255432128906250, 0.0001220703125000, +-0.0532836914062500, 0.0000305175781250, -0.0340270996093750, 0.0000000000000000, +-0.0753784179687500, 0.0001220703125000, -0.0839538574218750, 0.0000610351562500, +-0.0637512207031250, -0.0001220703125000, -0.0758972167968750, -0.0000915527343750, +-0.0834045410156250, -0.0000305175781250, 0.0018005371093750, -0.0001220703125000, +-0.0303344726562500, -0.0000305175781250, 0.0346374511718750, 0.0000915527343750, +0.1353454589843750, 0.0000305175781250, 0.0736694335937500, 0.0000610351562500, +0.2203063964843750, 0.0001220703125000, 0.2291259765625000, 0.0000305175781250, +0.2276000976562500, -0.0000610351562500, 0.3042602539062500, -0.0000305175781250, +0.2836914062500000, -0.0000610351562500, 0.2469177246093750, -0.0000915527343750, +0.2793579101562500, -0.0000305175781250, 0.2104187011718750, 0.0000305175781250, +0.1311645507812500, -0.0000610351562500, 0.1754455566406250, 0.0000305175781250, +0.0122985839843750, 0.0000610351562500, 0.0175781250000000, 0.0000000000000000, +-0.0180969238281250, 0.0000000000000000, -0.1295166015625000, 0.0000000000000000, +-0.0873718261718750, 0.0000000000000000, -0.1574096679687500, -0.0000610351562500, +-0.1731872558593750, 0.0000000000000000, -0.1615905761718750, 0.0000000000000000, +-0.1830749511718750, 0.0000305175781250, -0.1819458007812500, 0.0000610351562500, +-0.1560974121093750, 0.0000305175781250, -0.1632995605468750, 0.0000000000000000, +-0.1505432128906250, 0.0000000000000000, -0.1236572265625000, 0.0000305175781250, +-0.1334228515625000, 0.0000305175781250, -0.1114807128906250, -0.0000305175781250, +-0.1065368652343750, 0.0000000000000000, -0.1076049804687500, 0.0000000000000000, +-0.0986938476562500, -0.0000305175781250, -0.0987548828125000, 0.0000610351562500, +-0.1041259765625000, 0.0000305175781250, -0.1011352539062500, 0.0000305175781250, +-0.1094970703125000, 0.0000000000000000, -0.1206054687500000, 0.0000305175781250, +-0.1172180175781250, 0.0000000000000000, -0.1343383789062500, -0.0000305175781250, +-0.1370239257812500, 0.0000000000000000, -0.1453247070312500, 0.0000000000000000, +-0.1594238281250000, -0.0000305175781250, -0.1578063964843750, 0.0000305175781250, +-0.1737670898437500, 0.0000000000000000, -0.1806335449218750, 0.0000305175781250, +-0.1841735839843750, 0.0000305175781250, -0.1932067871093750, 0.0000000000000000, +-0.1974487304687500, 0.0000000000000000, -0.1971740722656250, -0.0000305175781250, +-0.2016906738281250, 0.0000000000000000, -0.2017517089843750, 0.0000000000000000, +-0.1996459960937500, 0.0000000000000000, -0.2028198242187500, 0.0000305175781250, +-0.1966552734375000, 0.0000000000000000, -0.2013244628906250, -0.0000305175781250, +-0.1932067871093750, 0.0000000000000000, -0.1835327148437500, 0.0000000000000000, +-0.1948547363281250, -0.0000305175781250, -0.1774902343750000, -0.0000305175781250, +-0.1785583496093750, 0.0000000000000000, -0.1792602539062500, 0.0000305175781250, +-0.1694335937500000, 0.0000305175781250, -0.1757507324218750, 0.0000000000000000, +-0.1827087402343750, 0.0000305175781250, -0.1708374023437500, 0.0000000000000000, +-0.1903381347656250, 0.0000000000000000, -0.2056274414062500, 0.0000305175781250, +-0.1878967285156250, 0.0000000000000000, -0.2621765136718750, -0.0000305175781250, +-0.2353210449218750, 0.0000000000000000, -0.2696838378906250, 0.0000000000000000, +-0.3405761718750000, -0.0000305175781250, -0.2938537597656250, 0.0000000000000000, +-0.3898010253906250, 0.0000610351562500, -0.3955383300781250, 0.0000000000000000, +-0.3806152343750000, -0.0000610351562500, -0.4309997558593750, 0.0000000000000000, +-0.4267578125000000, 0.0000000000000000, -0.3458251953125000, -0.0000610351562500, +-0.4047241210937500, 0.0000000000000000, -0.2902221679687500, 0.0000305175781250, +-0.1623840332031250, 0.0000000000000000, -0.2633361816406250, -0.0000305175781250, +0.0700988769531250, 0.0000000000000000, 0.0109863281250000, 0.0000000000000000, +0.1206970214843750, -0.0000915527343750, 0.3903503417968750, -0.0000610351562500, +0.2450866699218750, -0.0000610351562500, 0.5116577148437500, -0.0000610351562500, +0.5362854003906250, 0.0000000000000000, 0.5067443847656250, 0.0000305175781250, +0.6291809082031250, 0.0000305175781250, 0.6092834472656250, 0.0000000000000000, +0.5044860839843750, 0.0000000000000000, 0.5722961425781250, -0.0000305175781250, +0.4512634277343750, -0.0000915527343750, 0.2902526855468750, -0.0000610351562500, +0.3901062011718750, 0.0000000000000000, 0.0949707031250000, -0.0000610351562500, +0.1124572753906250, 0.0000000000000000, 0.0639953613281250, 0.0000915527343750, +-0.1348571777343750, 0.0000610351562500, -0.0592346191406250, 0.0000000000000000, +-0.1584472656250000, 0.0000915527343750, -0.1935424804687500, -0.0000305175781250, +-0.1521606445312500, -0.0001525878906250, -0.1613464355468750, -0.0000610351562500, +-0.1775817871093750, -0.0000610351562500, -0.0918273925781250, -0.0002136230468750, +-0.1075134277343750, -0.0000610351562500, -0.0841369628906250, 0.0001220703125000, +-0.0153808593750000, 0.0000000000000000, -0.0460205078125000, 0.0000915527343750, +-0.0025634765625000, 0.0002136230468750, 0.0086669921875000, 0.0000305175781250, +-0.0014343261718750, -0.0001831054687500, 0.0075378417968750, 0.0000000000000000, +0.0086975097656250, -0.0002136230468750, -0.0010681152343750, -0.0003356933593750, +-0.0011291503906250, -0.0001220703125000, 0.0003356933593750, -0.0000305175781250, +-0.0036010742187500, -0.0002136230468750, -0.0036010742187500, 0.0002136230468750, +0.0003051757812500, 0.0002746582031250, 0.0000000000000000, 0.0001220703125000, +-0.0003967285156250, 0.0001525878906250, 0.0015869140625000, 0.0002441406250000, +0.0015258789062500, -0.0002746582031250, -0.0003356933593750, -0.0002746582031250, +-0.0001831054687500, -0.0001831054687500, 0.0002746582031250, -0.0004577636718750, +-0.0004882812500000, -0.0004882812500000, -0.0007324218750000, 0.0001220703125000, +0.0004882812500000, -0.0000305175781250, 0.0006103515625000, 0.0000000000000000, +0.0001220703125000, 0.0005798339843750, 0.0003356933593750, -0.0001831054687500, +-0.0006713867187500, -0.0002746582031250, 0.0005187988281250, -0.0004882812500000, +0.0004577636718750, -0.0001525878906250, 0.0000000000000000, 0.0001831054687500, +0.0000610351562500, -0.0000610351562500, 0.0003967285156250, 0.0003967285156250, +-0.0004882812500000, 0.0004882812500000, -0.0007934570312500, 0.0003967285156250, +-0.0002136230468750, 0.0004882812500000, -0.0000915527343750, 0.0005187988281250, +-0.0004882812500000, 0.0000305175781250, 0.0004882812500000, 0.0003356933593750, +0.0007629394531250, -0.0002746582031250, 0.0001831054687500, -0.0011291503906250, +0.0001525878906250, -0.0003967285156250, 0.0005493164062500, -0.0015563964843750, +-0.0003967285156250, -0.0023803710937500, -0.0006713867187500, -0.0002746582031250, +-0.0002136230468750, 0.0004882812500000, -0.0002441406250000, -0.0013427734375000, +-0.0005187988281250, 0.0044250488281250, 0.0003051757812500, 0.0061645507812500, +0.0004272460937500, -0.0014038085937500, 0.0000610351562500, 0.0011901855468750, +0.0001831054687500, 0.0053405761718750, 0.0003967285156250, -0.0375976562500000, +-0.0002746582031250, -0.0163879394531250, -0.0003967285156250, -0.0508728027343750, +-0.0000610351562500, -0.1047668457031250, -0.0001525878906250, -0.0677185058593750, +-0.0003356933593750, -0.1493225097656250, 0.0001525878906250, -0.1591186523437500, +0.0003051757812500, -0.1310119628906250, 0.0000305175781250, -0.1663208007812500, +0.0000915527343750, -0.1718139648437500, 0.0002441406250000, -0.0350952148437500, +-0.0002746582031250, -0.1026306152343750, -0.0003356933593750, 0.0031433105468750, +-0.0001525878906250, 0.1657104492187500, -0.0002136230468750, 0.0512084960937500, +-0.0003356933593750, 0.3208312988281250, 0.0000305175781250, 0.3054199218750000, +0.0000610351562500, 0.3223266601562500, -0.0000305175781250, 0.4883117675781250, +0.0000000000000000, 0.4227294921875000, 0.0000610351562500, 0.4466247558593750, +-0.0000610351562500, 0.5031433105468750, -0.0001525878906250, 0.4203796386718750, +-0.0000305175781250, 0.3656005859375000, 0.0000305175781250, 0.4327392578125000, +-0.0000915527343750, 0.2131347656250000, 0.0001525878906250, 0.2613525390625000, +0.0002136230468750, 0.1885681152343750, 0.0001220703125000, 0.0113830566406250, +0.0000610351562500, 0.1111450195312500, 0.0001220703125000, -0.1012268066406250, +0.0000305175781250, -0.0922241210937500, -0.0000610351562500, -0.1169433593750000, +0.0000305175781250, -0.2468872070312500, 0.0000610351562500, -0.1871643066406250, +0.0000000000000000, -0.2630004882812500, 0.0000610351562500, -0.2810974121093750, +0.0000915527343750, -0.2612304687500000, 0.0000305175781250, -0.2826232910156250, +-0.0000915527343750, -0.2863464355468750, 0.0000305175781250, -0.2443847656250000, +0.0000000000000000, -0.2626342773437500, -0.0000915527343750, -0.2483825683593750, +-0.0000305175781250, -0.2086181640625000, 0.0000305175781250, -0.2345275878906250, +0.0000000000000000, -0.2070007324218750, -0.0000305175781250, -0.1974792480468750, +0.0000305175781250, -0.2130737304687500, 0.0000000000000000, -0.2087402343750000, +0.0000000000000000}, +{-0.0006103515625000, 0.0004577636718750, 0.0013427734375000, 0.0003356933593750, +0.0012512207031250, 0.0000305175781250, -0.0003051757812500, 0.0002441406250000, +-0.0000915527343750, 0.0000915527343750, 0.0002136230468750, -0.0005493164062500, +-0.0005187988281250, -0.0001220703125000, 0.0010070800781250, 0.0005187988281250, +-0.0002746582031250, 0.0004272460937500, 0.0000610351562500, 0.0003051757812500, +0.0002441406250000, 0.0004882812500000, -0.0001831054687500, 0.0005798339843750, +-0.0004272460937500, -0.0003662109375000, 0.0003662109375000, 0.0000000000000000, +0.0005493164062500, -0.0004272460937500, 0.0000305175781250, -0.0016174316406250, +-0.0001220703125000, -0.0009460449218750, 0.0002746582031250, -0.0009460449218750, +-0.0004577636718750, -0.0021057128906250, -0.0007324218750000, 0.0001525878906250, +-0.0002136230468750, 0.0025939941406250, 0.0000305175781250, 0.0003051757812500, +-0.0003662109375000, 0.0026245117187500, 0.0003662109375000, 0.0078430175781250, +0.0006713867187500, -0.0059509277343750, 0.0001525878906250, -0.0101623535156250, +0.0000000000000000, -0.0001525878906250, 0.0003662109375000, -0.0609130859375000, +-0.0003051757812500, -0.0397949218750000, -0.0005493164062500, -0.0712585449218750, +-0.0001525878906250, -0.1373596191406250, -0.0000305175781250, -0.0979003906250000, +-0.0002746582031250, -0.1443176269531250, 0.0002746582031250, -0.1734924316406250, +0.0004882812500000, -0.1144104003906250, 0.0000915527343750, -0.1036071777343750, +-0.0000610351562500, -0.1397399902343750, 0.0002136230468750, 0.0746154785156250, +-0.0003356933593750, 0.0101928710937500, -0.0005493164062500, 0.1067504882812500, +-0.0002136230468750, 0.3122558593750000, -0.0001220703125000, 0.1931152343750000, +-0.0003356933593750, 0.4007568359375000, 0.0001220703125000, 0.4322814941406250, +0.0002441406250000, 0.3775634765625000, 0.0000305175781250, 0.4487304687500000, +0.0000610351562500, 0.4570312500000000, 0.0001525878906250, 0.2973327636718750, +-0.0000915527343750, 0.3659973144531250, -0.0002441406250000, 0.2707519531250000, +-0.0000305175781250, 0.1003723144531250, 0.0000610351562500, 0.2116394042968750, +-0.0000305175781250, -0.0206604003906250, 0.0001831054687500, -0.0113220214843750, +0.0002441406250000, -0.0277404785156250, 0.0000915527343750, -0.1629333496093750, +0.0000000000000000, -0.1050415039062500, 0.0000915527343750, -0.1687927246093750, +-0.0000915527343750, -0.1861572265625000, -0.0001831054687500, -0.1756286621093750, +-0.0000610351562500, -0.1934814453125000, 0.0000000000000000, -0.1937561035156250, +-0.0000915527343750, -0.1913146972656250, 0.0000610351562500, -0.1891479492187500, +0.0000915527343750, -0.1994323730468750, 0.0000000000000000, -0.2012023925781250, +-0.0000305175781250, -0.1934814453125000, 0.0000000000000000, -0.2383422851562500, +0.0000000000000000, -0.2196960449218750, -0.0000610351562500, -0.2556457519531250, +0.0000000000000000, -0.3038024902343750, 0.0001220703125000, -0.2633056640625000, +0.0000610351562500, -0.3670349121093750, 0.0000610351562500, -0.3466186523437500, +0.0000915527343750, -0.3691406250000000, 0.0000610351562500, -0.4454650878906250, +0.0000000000000000, -0.3998107910156250, 0.0000305175781250, -0.4647521972656250, +0.0000305175781250, -0.4701843261718750, -0.0000305175781250, -0.4540100097656250, +0.0000000000000000, -0.4806518554687500, 0.0000305175781250, -0.4784851074218750, +0.0000610351562500, -0.4330749511718750, -0.0000610351562500, -0.4600219726562500, +-0.0000305175781250, -0.4227600097656250, -0.0000305175781250, -0.3711853027343750, +-0.0000915527343750, -0.4151000976562500, -0.0000610351562500, -0.2999267578125000, +-0.0000610351562500, -0.3309936523437500, 0.0000000000000000, -0.2987976074218750, +-0.0000915527343750, -0.2084350585937500, -0.0000915527343750, -0.2677307128906250, +-0.0000610351562500, -0.1611022949218750, -0.0001220703125000, -0.1781616210937500, +-0.0001220703125000, -0.1651306152343750, -0.0001220703125000, -0.0999755859375000, +-0.0000915527343750, -0.1506652832031250, -0.0000915527343750, -0.0920410156250000, +-0.0000915527343750, -0.1023864746093750, -0.0001220703125000, -0.1080627441406250, +-0.0001525878906250, -0.0810241699218750, -0.0000915527343750, -0.1103515625000000, +-0.0000915527343750, -0.0968627929687500, -0.0000915527343750, -0.1033935546875000, +-0.0001220703125000, -0.1210021972656250, -0.0001220703125000, -0.1231689453125000, +-0.0001220703125000, -0.1343078613281250, -0.0001220703125000, -0.1687622070312500, +-0.0000915527343750, -0.1755676269531250, -0.0000610351562500, -0.1989746093750000, +-0.0000915527343750, -0.2328491210937500, -0.0001220703125000, -0.2375183105468750, +-0.0000610351562500, -0.2781982421875000, -0.0000915527343750, -0.2805786132812500, +-0.0000915527343750, -0.3013610839843750, -0.0000610351562500, -0.3349914550781250, +-0.0000610351562500, -0.3263549804687500, -0.0000305175781250, -0.3655395507812500, +-0.0000305175781250, -0.3664855957031250, -0.0000305175781250, -0.3680725097656250, +0.0000000000000000, -0.3916931152343750, 0.0000305175781250, -0.3879699707031250, +-0.0000305175781250, -0.3820190429687500, 0.0000000000000000, -0.3925781250000000, +0.0000000000000000, -0.3741149902343750, 0.0000305175781250, -0.3554382324218750, +0.0000000000000000, -0.3671569824218750, 0.0000000000000000, -0.3097839355468750, +0.0000610351562500, -0.3173828125000000, 0.0000610351562500, -0.2924499511718750, +0.0000305175781250, -0.2423706054687500, 0.0000610351562500, -0.2633361816406250, +0.0000610351562500, -0.2049255371093750, 0.0000000000000000, -0.1999816894531250, +0.0000000000000000, -0.2020874023437500, 0.0000305175781250, -0.1745605468750000, +-0.0000305175781250, -0.1803283691406250, -0.0000305175781250, -0.1916503906250000, +0.0000305175781250, -0.1842346191406250, -0.0000610351562500, -0.1968994140625000, +0.0000000000000000, -0.2193603515625000, 0.0000610351562500, -0.2097473144531250, +0.0000000000000000, -0.2123107910156250, -0.0000305175781250, -0.2350158691406250, +0.0000000000000000, -0.1920166015625000, 0.0000000000000000, -0.1632385253906250, +-0.0000610351562500, -0.1933288574218750, 0.0000000000000000, -0.0401611328125000, +0.0000610351562500, -0.0721740722656250, 0.0000000000000000, 0.0021972656250000, +0.0000305175781250, 0.1486816406250000, 0.0001220703125000, 0.0788574218750000, +0.0000610351562500, 0.2412719726562500, 0.0000000000000000, 0.2653198242187500, +0.0000610351562500, 0.2403869628906250, 0.0000000000000000, 0.3052978515625000, +-0.0001220703125000, 0.3017272949218750, -0.0001220703125000, 0.1968383789062500, +0.0000000000000000, 0.2411193847656250, -0.0001220703125000, 0.1690063476562500, +-0.0000305175781250, 0.0431518554687500, 0.0000915527343750, 0.1099243164062500, +0.0000305175781250, -0.0361022949218750, -0.0000610351562500, -0.0507202148437500, +-0.0000305175781250, -0.0375366210937500, -0.0000305175781250, -0.0989074707031250, +-0.0001831054687500, -0.0877990722656250, -0.0001525878906250, -0.0556030273437500, +0.0000610351562500, -0.0718383789062500, -0.0000915527343750, -0.0517883300781250, +-0.0000610351562500, -0.0115356445312500, 0.0001525878906250, -0.0297546386718750, +0.0000610351562500, -0.0035705566406250, -0.0000610351562500, 0.0032958984375000, +0.0000305175781250, -0.0027770996093750, 0.0000305175781250, 0.0019226074218750, +-0.0002441406250000, 0.0027465820312500, -0.0001220703125000, -0.0011596679687500, +-0.0000305175781250, -0.0020141601562500, -0.0001525878906250, -0.0005493164062500, +-0.0000915527343750, -0.0006408691406250, 0.0000915527343750, -0.0014648437500000, +0.0000610351562500, 0.0003356933593750, -0.0000915527343750, 0.0007629394531250, +-0.0000305175781250, 0.0001220703125000, 0.0000000000000000, -0.0000610351562500, +-0.0000305175781250, -0.0000915527343750, -0.0000610351562500, -0.0000610351562500, +0.0000000000000000, -0.0003967285156250, 0.0000915527343750, -0.0001525878906250, +-0.0000305175781250, 0.0002136230468750, -0.0001831054687500, -0.0000610351562500, +0.0000000000000000, -0.0000305175781250, -0.0000305175781250, 0.0001831054687500, +-0.0001831054687500, 0.0000305175781250, 0.0000000000000000, -0.0003051757812500, +0.0003662109375000, -0.0001525878906250, 0.0001831054687500, 0.0000610351562500, +-0.0003051757812500, -0.0001220703125000, 0.0000915527343750, -0.0000610351562500, +-0.0002746582031250, 0.0002746582031250, -0.0013427734375000, 0.0001831054687500, +-0.0009460449218750, -0.0001220703125000, 0.0004272460937500, -0.0000610351562500, +0.0000610351562500, -0.0000305175781250, -0.0010375976562500, -0.0003356933593750, +0.0017089843750000, -0.0003356933593750, 0.0014648437500000, 0.0000305175781250, +-0.0151062011718750, -0.0000915527343750, -0.0050048828125000, -0.0000915527343750, +-0.0227661132812500, 0.0002441406250000, -0.0491333007812500, 0.0002136230468750, +-0.0308532714843750, -0.0000915527343750, -0.0607910156250000, -0.0000610351562500, +-0.0745544433593750, 0.0000000000000000, -0.0429992675781250, -0.0002441406250000, +-0.0408325195312500, -0.0002441406250000, -0.0589904785156250, 0.0000610351562500, +0.0583190917968750, -0.0000305175781250, 0.0282592773437500, -0.0000610351562500, +0.0741577148437500, 0.0001831054687500, 0.1844482421875000, 0.0001525878906250, +0.1276245117187500, -0.0000610351562500, 0.1999511718750000, 0.0000000000000000, +0.2334899902343750, 0.0000000000000000, 0.1798400878906250, -0.0001831054687500, +0.1707153320312500, -0.0001525878906250, 0.1996459960937500, 0.0000000000000000, +0.0626525878906250, -0.0000610351562500, 0.0840148925781250, -0.0000610351562500, +0.0394287109375000, 0.0001220703125000, -0.0739135742187500, 0.0000915527343750, +-0.0218505859375000, -0.0000305175781250, -0.0999145507812500, 0.0000305175781250, +-0.1212463378906250, 0.0000305175781250, -0.1003417968750000, -0.0000915527343750, +-0.1129455566406250, -0.0000915527343750, -0.1164550781250000, 0.0000000000000000, +-0.0897827148437500, -0.0000915527343750, -0.0850830078125000, 0.0000000000000000, +-0.0967407226562500, 0.0000915527343750, -0.0880432128906250, 0.0000305175781250, +-0.0844726562500000, -0.0000305175781250, -0.1486511230468750, 0.0000305175781250, +-0.1286621093750000, 0.0000000000000000, -0.1735839843750000, -0.0000915527343750, +-0.2462158203125000, -0.0000305175781250, -0.2090759277343750, 0.0000000000000000, +-0.3103332519531250, -0.0000305175781250, -0.3142395019531250, 0.0000000000000000, +-0.3230895996093750, 0.0000305175781250, -0.3815917968750000, 0.0000305175781250, +-0.3625488281250000, 0.0000305175781250, -0.3675842285156250, 0.0000915527343750, +-0.3828125000000000, 0.0000305175781250, -0.3587341308593750, 0.0000000000000000, +-0.3362121582031250, 0.0000000000000000, -0.3448486328125000, 0.0000305175781250, +-0.2865905761718750, 0.0000000000000000, -0.2882995605468750, 0.0000000000000000, +-0.2570495605468750, 0.0000305175781250, -0.2027893066406250, 0.0000305175781250, +-0.2171325683593750, 0.0000610351562500, -0.1494750976562500, 0.0000305175781250, +-0.1375732421875000, 0.0000305175781250, -0.1194152832031250, 0.0000305175781250, +-0.0771789550781250, 0.0000305175781250, -0.0817565917968750, 0.0000000000000000, +-0.0472412109375000, 0.0000000000000000, -0.0355224609375000, 0.0000305175781250, +-0.0216369628906250, 0.0000610351562500, -0.0003356933593750, 0.0000305175781250, +-0.0019836425781250, 0.0000610351562500, 0.0206604003906250, 0.0000610351562500, +0.0346984863281250, 0.0000305175781250, 0.0368652343750000, 0.0000610351562500, +0.0441589355468750, 0.0000305175781250, 0.0524597167968750, 0.0000000000000000, +0.0453491210937500}, +{-0.0006408691406250, -0.0000915527343750, -0.0000305175781250, 0.0000915527343750, +-0.0006713867187500, 0.0000000000000000, -0.0007324218750000, -0.0002746582031250, +0.0019226074218750, -0.0002441406250000, 0.0011596679687500, 0.0000915527343750, +-0.0109252929687500, 0.0000000000000000, -0.0021972656250000, -0.0000610351562500, +-0.0185546875000000, 0.0002136230468750, -0.0410156250000000, 0.0002136230468750, +-0.0255126953125000, -0.0001220703125000, -0.0546569824218750, -0.0001220703125000, +-0.0675354003906250, -0.0000610351562500, -0.0370788574218750, -0.0002746582031250, +-0.0353393554687500, -0.0002746582031250, -0.0541687011718750, 0.0001220703125000, +0.0569763183593750, 0.0000305175781250, 0.0273742675781250, 0.0000000000000000, +0.0666503906250000, 0.0001220703125000, 0.1731262207031250, 0.0001525878906250, +0.1228637695312500, -0.0001525878906250, 0.1707763671875000, -0.0001220703125000, +0.2087402343750000, -0.0000610351562500, 0.1488037109375000, -0.0002441406250000, +0.1203002929687500, -0.0002441406250000, 0.1597290039062500, 0.0000305175781250, +0.0133972167968750, 0.0000000000000000, 0.0273437500000000, -0.0000305175781250, +0.0054931640625000, 0.0000915527343750, -0.0950317382812500, 0.0001525878906250, +-0.0571289062500000, -0.0000915527343750, -0.0894470214843750, -0.0000305175781250, +-0.1093750000000000, 0.0000000000000000, -0.0892028808593750, -0.0001525878906250, +-0.0773315429687500, -0.0001525878906250, -0.0882263183593750, 0.0000305175781250, +-0.0804443359375000, -0.0000305175781250, -0.0635375976562500, -0.0000305175781250, +-0.0983581542968750, 0.0001220703125000, -0.1232910156250000, 0.0000610351562500, +-0.1011352539062500, 0.0000000000000000, -0.1986389160156250, -0.0000305175781250, +-0.1914367675781250, -0.0000305175781250, -0.2163085937500000, -0.0000915527343750, +-0.2919006347656250, -0.0000610351562500, -0.2625732421875000, 0.0000000000000000, +-0.2834777832031250, -0.0000610351562500, -0.3080139160156250, -0.0000610351562500, +-0.2620239257812500, 0.0000915527343750, -0.2329101562500000, 0.0000610351562500, +-0.2574157714843750, 0.0000000000000000, -0.1390686035156250, 0.0000305175781250, +-0.1531677246093750, 0.0000000000000000, -0.1072998046875000, -0.0000305175781250, +-0.0065307617187500, 0.0000000000000000, -0.0426940917968750, -0.0000305175781250, +0.0642395019531250, -0.0000305175781250, 0.0725708007812500, 0.0000000000000000, +0.0829772949218750, 0.0000610351562500, 0.1411132812500000, 0.0000610351562500, +0.1268310546875000, 0.0000000000000000, 0.1528015136718750, 0.0000000000000000, +0.1601257324218750, -0.0000305175781250, 0.1538391113281250, -0.0000610351562500, +0.1596374511718750, 0.0000000000000000, 0.1617431640625000, 0.0000305175781250, +0.1513061523437500, -0.0000305175781250, 0.1523437500000000, 0.0000000000000000, +0.1463928222656250, 0.0000305175781250, 0.1354980468750000, 0.0000000000000000, +0.1372680664062500, -0.0000305175781250, 0.1239318847656250, 0.0000305175781250, +0.1219787597656250, 0.0000305175781250, 0.1158447265625000, 0.0000000000000000, +0.1071166992187500, -0.0000305175781250, 0.1095275878906250, 0.0000000000000000, +0.0902709960937500, 0.0000000000000000, 0.0889587402343750, 0.0000000000000000, +0.0854492187500000, 0.0000000000000000, 0.0754394531250000, 0.0000000000000000, +0.0780029296875000, 0.0000000000000000, 0.0641174316406250, -0.0000305175781250, +0.0654907226562500, 0.0000000000000000, 0.0607604980468750, 0.0000000000000000, +0.0501708984375000, 0.0000000000000000, 0.0565490722656250, -0.0000305175781250, +0.0480346679687500, 0.0000305175781250, 0.0444335937500000, 0.0000610351562500, +0.0481567382812500, 0.0000000000000000, 0.0461120605468750, 0.0000000000000000, +0.0438537597656250, 0.0000000000000000, 0.0603027343750000, 0.0000000000000000, +0.0527343750000000, 0.0000000000000000, 0.0622558593750000, 0.0000000000000000, +0.0797424316406250, 0.0000305175781250, 0.0681152343750000, 0.0000305175781250, +0.0950317382812500, 0.0000000000000000, 0.0936279296875000, 0.0000305175781250, +0.0944519042968750, 0.0000000000000000, 0.1144714355468750, -0.0000305175781250, +0.1077270507812500, 0.0000610351562500, 0.0870361328125000, 0.0000000000000000, +0.1135864257812500, 0.0000000000000000, 0.0704650878906250, 0.0000610351562500, +0.0333251953125000, 0.0000610351562500, 0.0765075683593750, -0.0000305175781250, +-0.0815734863281250, -0.0000305175781250, -0.0341491699218750, 0.0000000000000000, +-0.1152954101562500, -0.0000305175781250, -0.2669067382812500, 0.0000000000000000, +-0.1726074218750000, 0.0000610351562500, -0.3903808593750000, 0.0000915527343750, +-0.3747863769531250, 0.0000305175781250, -0.3897094726562500, 0.0000305175781250, +-0.5310058593750000, 0.0000610351562500, -0.4781188964843750, -0.0000915527343750, +-0.4888000488281250, -0.0000915527343750, -0.5339050292968750, 0.0000000000000000, +-0.4636230468750000, 0.0000610351562500, -0.4058227539062500, -0.0000305175781250, +-0.4553222656250000, 0.0000915527343750, -0.2912902832031250, 0.0000915527343750, +-0.3075866699218750, 0.0000305175781250, -0.2795104980468750, -0.0000305175781250, +-0.1611938476562500, 0.0000305175781250, -0.2052307128906250, -0.0000305175781250, +-0.1661682128906250, -0.0001220703125000, -0.1387634277343750, -0.0000610351562500, +-0.1756591796875000, 0.0000000000000000, -0.1967773437500000, -0.0000305175781250, +-0.1766967773437500, 0.0000915527343750, -0.2356567382812500, 0.0001525878906250, +-0.2520446777343750, 0.0000610351562500, -0.2178649902343750, 0.0000000000000000, +-0.2344665527343750, 0.0000305175781250, -0.2517395019531250, -0.0001220703125000, +-0.0840454101562500, -0.0001525878906250, -0.1432189941406250, -0.0000915527343750, +-0.0336914062500000, -0.0000610351562500, 0.1465759277343750, -0.0001220703125000, +0.0347595214843750, 0.0000610351562500, 0.3022155761718750, 0.0000915527343750, +0.3053588867187500, 0.0000305175781250, 0.3038024902343750, 0.0000610351562500, +0.4550476074218750, 0.0000915527343750, 0.4118652343750000, -0.0001220703125000, +0.3473510742187500, -0.0001525878906250, 0.4221496582031250, -0.0000915527343750, +0.3047180175781250, -0.0002136230468750, 0.1602478027343750, -0.0002441406250000, +0.2597351074218750, 0.0000610351562500, 0.0010070800781250, 0.0000000000000000, +0.0050659179687500, 0.0000000000000000, -0.0057678222656250, 0.0002746582031250, +-0.1555175781250000, 0.0002136230468750, -0.1069946289062500, 0.0000000000000000, +-0.1122741699218750, 0.0000915527343750, -0.1511535644531250, -0.0000610351562500, +-0.1043090820312500, -0.0003356933593750, -0.0532836914062500, -0.0002136230468750, +-0.0872802734375000, -0.0002441406250000, -0.0165405273437500, -0.0004272460937500, +-0.0087585449218750, -0.0001220703125000, -0.0162353515625000, 0.0000915527343750, +0.0100097656250000, -0.0001220703125000, 0.0056762695312500, 0.0004577636718750, +-0.0001525878906250, 0.0004882812500000, 0.0022888183593750, 0.0003356933593750, +0.0021057128906250, 0.0004577636718750, -0.0035095214843750, -0.0012207031250000, +0.0039062500000000, 0.0010986328125000, -0.0003967285156250, -0.0007324218750000, +0.0027465820312500, 0.0003662109375000, 0.0017089843750000, 0.0043945312500000, +-0.0024108886718750, 0.0027160644531250, -0.0018920898437500, -0.0069580078125000, +-0.0000305175781250, 0.0036621093750000, -0.0004272460937500, -0.0176086425781250, +-0.0006103515625000, -0.0372924804687500, 0.0005798339843750, -0.0190429687500000, +0.0006408691406250, -0.0885620117187500, -0.0001525878906250, -0.0801696777343750, +-0.0002136230468750, -0.0868835449218750, 0.0000915527343750, -0.1429443359375000, +0.0000000000000000, -0.1222839355468750, -0.0001525878906250, -0.0770263671875000, +0.0001831054687500, -0.1347045898437500, 0.0004272460937500, -0.0307922363281250, +0.0000305175781250, 0.0747375488281250, -0.0003051757812500, -0.0204162597656250, +0.0000000000000000, 0.2587280273437500, -0.0003051757812500, 0.2368469238281250, +-0.0006103515625000, 0.2540588378906250, -0.0002136230468750, 0.4395446777343750, +0.0001525878906250, 0.3749694824218750, -0.0000915527343750, 0.3348083496093750, +0.0002441406250000, 0.4243774414062500, 0.0004882812500000, 0.2942810058593750, +0.0001220703125000, 0.1514587402343750, -0.0001525878906250, 0.2632751464843750, +0.0000915527343750, -0.0409851074218750, -0.0001220703125000, -0.0304260253906250, +-0.0003356933593750, -0.0339050292968750, -0.0000610351562500, -0.2094421386718750, +0.0002136230468750, -0.1537170410156250, 0.0000000000000000, -0.1254272460937500, +0.0001220703125000, -0.1799621582031250, 0.0003051757812500, -0.1230468750000000, +0.0000915527343750, -0.0356140136718750, -0.0002136230468750, -0.0928955078125000, +-0.0000610351562500, -0.0426635742187500, -0.0000915527343750, 0.0031127929687500, +-0.0003356933593750, -0.0781860351562500, -0.0000610351562500, -0.1147766113281250, +0.0002136230468750, -0.0566101074218750, 0.0000610351562500, -0.2801513671875000, +0.0001525878906250, -0.2333068847656250, 0.0003051757812500, -0.2895507812500000, +0.0001525878906250, -0.4680175781250000, -0.0000610351562500, -0.3750000000000000, +0.0000610351562500, -0.4841613769531250, -0.0000305175781250, -0.5242004394531250, +-0.0001220703125000, -0.4643249511718750, -0.0000305175781250, -0.4760437011718750, +0.0000610351562500, -0.5036010742187500, 0.0000305175781250, -0.3280639648437500, +-0.0000915527343750, -0.3854370117187500, -0.0000305175781250, -0.2917785644531250, +-0.0000305175781250, -0.1244201660156250, -0.0002441406250000, -0.2310180664062500, +-0.0001525878906250, 0.0328063964843750, -0.0000915527343750, 0.0108947753906250, +-0.0001831054687500, 0.0527343750000000, -0.0001220703125000, 0.2251281738281250, +0.0000000000000000, 0.1384582519531250, -0.0000610351562500, 0.2473144531250000, +-0.0000610351562500, 0.2721862792968750, -0.0000305175781250, 0.2324829101562500, +-0.0000305175781250, 0.2603759765625000, -0.0000305175781250, 0.2725830078125000, +-0.0000915527343750, 0.1771240234375000, 0.0000915527343750, 0.2175598144531250, +0.0000305175781250, 0.1583557128906250, 0.0000610351562500, 0.0618286132812500, +0.0000915527343750, 0.1380615234375000, 0.0001220703125000, -0.0220336914062500, +0.0000610351562500, -0.0027160644531250, 0.0000305175781250, -0.0210266113281250, +0.0000610351562500, -0.1211242675781250, 0.0000610351562500, -0.0663452148437500, +0.0000610351562500, -0.1444702148437500, 0.0000610351562500, -0.1477355957031250, +0.0001220703125000, -0.1393432617187500, 0.0000305175781250, -0.1759948730468750, +-0.0000305175781250, -0.1669006347656250, 0.0000000000000000, -0.1611633300781250, +-0.0000305175781250, -0.1735839843750000, -0.0000610351562500, -0.1606140136718750, +0.0000000000000000, -0.1468505859375000, -0.0000305175781250, -0.1655273437500000, +-0.0000915527343750, -0.1379699707031250, -0.0000305175781250, -0.1475524902343750, +0.0000000000000000, -0.1407165527343750, -0.0000305175781250, -0.1206359863281250, +-0.0000915527343750, -0.1410522460937500, 0.0000000000000000, -0.1121826171875000, +-0.0000305175781250, -0.1185913085937500, -0.0000305175781250, -0.1162719726562500, +-0.0000305175781250, -0.0991210937500000, -0.0000305175781250, -0.1137084960937500, +0.0000000000000000, -0.0929565429687500, -0.0000305175781250, -0.0987243652343750, +-0.0000305175781250, -0.0926513671875000, -0.0000305175781250, -0.0748901367187500, +0.0000000000000000, -0.0831604003906250, 0.0000000000000000, -0.0541992187500000, +0.0000000000000000, -0.0565795898437500, 0.0000000000000000, -0.0428161621093750, +0.0000610351562500}, +{-0.0003051757812500, -0.1249389648437500, -0.0000915527343750, -0.2243652343750000, +0.0002441406250000, -0.2242431640625000, 0.0000305175781250, -0.0652770996093750, +0.0000000000000000, -0.1141967773437500, 0.0002441406250000, -0.0751953125000000, +0.0000305175781250, 0.0755004882812500, -0.0003967285156250, 0.0110778808593750, +-0.0002136230468750, -0.0132141113281250, -0.0001220703125000, 0.0736999511718750, +-0.0003356933593750, -0.0614013671875000, -0.0001220703125000, -0.1955871582031250, +0.0003051757812500, -0.0763549804687500, 0.0001220703125000, -0.3868713378906250, +0.0000915527343750, -0.3716125488281250, 0.0002746582031250, -0.3756713867187500, +0.0000610351562500, -0.5619812011718750, -0.0002136230468750, -0.4996032714843750, +-0.0000305175781250, -0.4526062011718750, -0.0000610351562500, -0.5405883789062500, +-0.0002136230468750, -0.4107360839843750, -0.0001220703125000, -0.2736206054687500, +0.0000610351562500, -0.3926696777343750, 0.0000000000000000, -0.0711975097656250, +-0.0000915527343750, -0.1112060546875000, -0.0000305175781250, -0.0523986816406250, +-0.0000305175781250, 0.1732177734375000, -0.0002136230468750, 0.0679931640625000, +-0.0001831054687500, 0.2198181152343750, 0.0000000000000000, 0.2501831054687500, +-0.0001220703125000, 0.2120971679687500, -0.0000610351562500, 0.2607116699218750, +0.0001831054687500, 0.2629699707031250, 0.0001220703125000, 0.1566467285156250, +0.0000305175781250, 0.2008972167968750, 0.0000610351562500, 0.1348266601562500, +0.0000610351562500, 0.0228881835937500, 0.0000000000000000, 0.1008911132812500, +0.0000000000000000, -0.0582275390625000, 0.0001220703125000, -0.0526428222656250, +0.0000915527343750, -0.0474243164062500, 0.0000610351562500, -0.1367492675781250, +0.0000610351562500, -0.1051635742187500, 0.0000610351562500, -0.0786132812500000, +-0.0000915527343750, -0.1271667480468750, -0.0000610351562500, -0.0533142089843750, +-0.0000610351562500, 0.0140991210937500, -0.0001220703125000, -0.0591735839843750, +-0.0000915527343750, 0.1584777832031250, -0.0000915527343750, 0.1027832031250000, +-0.0000915527343750, 0.1751403808593750, -0.0000915527343750, 0.3425903320312500, +-0.0001525878906250, 0.2242431640625000, -0.0001220703125000, 0.4725952148437500, +-0.0001220703125000, 0.4266967773437500, -0.0001525878906250, 0.4716186523437500, +-0.0001831054687500, 0.6446228027343750, -0.0001831054687500, 0.5410766601562500, +-0.0001831054687500, 0.7119750976562500, -0.0001525878906250, 0.6938476562500000, +-0.0000915527343750, 0.7097473144531250, -0.0001525878906250, 0.8084411621093750, +-0.0001525878906250, 0.7380981445312500, -0.0001525878906250, 0.8244934082031250, +-0.0001831054687500, 0.8116455078125000, -0.0001831054687500, 0.8027343750000000, +-0.0001525878906250, 0.8423156738281250, -0.0001525878906250, 0.8046569824218750, +-0.0001525878906250, 0.8206481933593750, -0.0001220703125000, 0.8116760253906250, +-0.0001220703125000, 0.7872009277343750, -0.0001525878906250, 0.7835388183593750, +-0.0001220703125000, 0.7691040039062500, -0.0001525878906250, 0.7163085937500000, +-0.0001220703125000, 0.7120361328125000, -0.0001525878906250, 0.6754455566406250, +-0.0001525878906250, 0.6191101074218750, -0.0001525878906250, 0.6120300292968750, +-0.0001525878906250, 0.5339355468750000, -0.0001525878906250, 0.5338745117187500, +-0.0001220703125000, 0.4855651855468750, -0.0001220703125000, 0.4146118164062500, +-0.0001525878906250, 0.4328918457031250, -0.0001220703125000, 0.3154602050781250, +-0.0001220703125000, 0.3254699707031250, -0.0001220703125000, 0.2801513671875000, +-0.0001220703125000, 0.1854248046875000, -0.0001525878906250, 0.2179870605468750, +-0.0001525878906250, 0.0966491699218750, -0.0000915527343750, 0.1003112792968750, +-0.0000915527343750, 0.0716857910156250, -0.0000915527343750, -0.0145568847656250, +-0.0000610351562500, 0.0127258300781250, -0.0000305175781250, -0.0510559082031250, +-0.0000305175781250, -0.0605773925781250, 0.0000000000000000, -0.0487060546875000, +0.0000000000000000, -0.0713806152343750, -0.0000305175781250, -0.0672302246093750, +0.0000000000000000, -0.0230407714843750, 0.0000000000000000, -0.0385131835937500, +0.0000000000000000, -0.0035095214843750, 0.0000610351562500, 0.0524902343750000, +0.0001220703125000, 0.0281066894531250, 0.0000610351562500, 0.0983886718750000, +0.0000610351562500, 0.1104736328125000, 0.0000915527343750, 0.1035156250000000, +0.0000305175781250, 0.1355590820312500, -0.0000305175781250, 0.1344604492187500, +-0.0000305175781250, 0.0795898437500000, -0.0000610351562500, 0.1065979003906250, +-0.0001525878906250, 0.0598144531250000, -0.0000610351562500, -0.0128479003906250, +-0.0000305175781250, 0.0278625488281250, -0.0000915527343750, -0.0789489746093750, +0.0000000000000000, -0.0842590332031250, 0.0000305175781250, -0.0866088867187500, +-0.0000305175781250, -0.1433715820312500, -0.0000915527343750, -0.1287841796875000, +-0.0000305175781250, -0.1227722167968750, -0.0000610351562500, -0.1361999511718750, +-0.0001220703125000, -0.1231384277343750, -0.0000305175781250, -0.1004333496093750, +0.0000915527343750, -0.1113891601562500, -0.0000305175781250, -0.1098632812500000, +0.0000305175781250, -0.1003723144531250, 0.0001220703125000, -0.1120300292968750, +0.0000000000000000, -0.1309814453125000, -0.0001525878906250, -0.1211547851562500, +-0.0000305175781250, -0.1073303222656250, -0.0000305175781250, -0.1378784179687500, +-0.0001831054687500, -0.0779418945312500, -0.0000305175781250, -0.0223999023437500, +0.0001220703125000, -0.0714416503906250, 0.0000000000000000, 0.0914916992187500, +0.0000915527343750, 0.0831298828125000, 0.0001831054687500, 0.0988464355468750, +0.0000305175781250, 0.2088317871093750, -0.0000610351562500, 0.1732482910156250, +0.0000305175781250, 0.1520080566406250, -0.0000610351562500, 0.1977539062500000, +-0.0000915527343750, 0.1312866210937500, -0.0000610351562500, 0.0516662597656250, +-0.0000610351562500, 0.1056823730468750, -0.0000305175781250, -0.0210571289062500, +-0.0000610351562500, -0.0319824218750000, -0.0000610351562500, -0.0202941894531250, +0.0000305175781250, -0.0737304687500000, 0.0001220703125000, -0.0645446777343750, +-0.0000305175781250, -0.0358886718750000, 0.0000915527343750, -0.0494079589843750, +0.0002746582031250, -0.0377807617187500, -0.0001525878906250, -0.0007934570312500, +-0.0007934570312500, -0.0045776367187500, -0.0005798339843750, -0.0007324218750000, +-0.0003967285156250, 0.0021057128906250, -0.0009765625000000, -0.0001525878906250, +-0.0004272460937500, -0.0011596679687500, 0.0012207031250000, 0.0003051757812500, +0.0000915527343750, -0.0004882812500000, -0.0033569335937500, -0.0016479492187500, +0.0022583007812500, -0.0007629394531250, -0.0101928710937500, 0.0005187988281250, +-0.0217895507812500, -0.0002136230468750, -0.0110778808593750, -0.0000305175781250, +-0.0432739257812500, 0.0003967285156250, -0.0476989746093750, 0.0001525878906250, +-0.0325622558593750, -0.0003662109375000, -0.0458984375000000, -0.0002136230468750, +-0.0514221191406250, 0.0001220703125000, 0.0264282226562500, -0.0000305175781250, +0.0005187988281250, -0.0000610351562500, 0.0403442382812500, 0.0001831054687500, +0.1271972656250000, 0.0002441406250000, 0.0835876464843750, -0.0001525878906250, +0.1298828125000000, -0.0001220703125000, 0.1635742187500000, 0.0000305175781250, +0.1093750000000000, -0.0001525878906250, 0.0838623046875000, -0.0002136230468750, +0.1210327148437500, 0.0001220703125000, -0.0003356933593750, 0.0001525878906250, +0.0072326660156250, 0.0000305175781250, 0.0038146972656250, 0.0000610351562500, +-0.0693969726562500, 0.0001831054687500, -0.0488586425781250, -0.0001220703125000, +-0.0426025390625000, -0.0001831054687500, -0.0554199218750000, -0.0000305175781250, +-0.0505371093750000, -0.0000915527343750, -0.0296936035156250, -0.0001525878906250, +-0.0355529785156250, 0.0001220703125000, -0.0756530761718750, 0.0001831054687500, +-0.0506591796875000, 0.0000610351562500, -0.0878906250000000, 0.0000305175781250, +-0.1503601074218750, 0.0000915527343750, -0.1148071289062500, -0.0000915527343750, +-0.1725158691406250, -0.0001220703125000, -0.1935729980468750, -0.0000305175781250, +-0.1557006835937500, -0.0000305175781250, -0.1562805175781250, -0.0001220703125000, +-0.1766357421875000, 0.0000305175781250, -0.0680847167968750, 0.0000915527343750, +-0.0861511230468750, 0.0000305175781250, -0.0465698242187500, 0.0000610351562500, +0.0489807128906250, 0.0000915527343750, 0.0092163085937500, -0.0000610351562500, +0.0760803222656250, -0.0000305175781250, 0.0956115722656250, 0.0000000000000000, +0.0720214843750000, -0.0000305175781250, 0.0805358886718750, -0.0001220703125000, +0.0871582031250000, 0.0000305175781250, 0.0365600585937500, 0.0000000000000000, +0.0379943847656250, -0.0000305175781250, 0.0345458984375000, 0.0000305175781250, +-0.0007019042968750, 0.0000610351562500, 0.0075988769531250, -0.0000305175781250, +0.0403442382812500, -0.0000610351562500, 0.0156860351562500, -0.0000305175781250, +0.0680541992187500, -0.0000305175781250, 0.1279296875000000, -0.0000610351562500, +0.0937805175781250, 0.0000305175781250, 0.2423706054687500, 0.0000305175781250, +0.2277526855468750, 0.0000305175781250, 0.2803039550781250, 0.0000305175781250, +0.3992614746093750, 0.0000610351562500, 0.3543701171875000, 0.0000000000000000, +0.4866638183593750, 0.0000000000000000, 0.4905395507812500, 0.0000000000000000, +0.5219421386718750, -0.0000305175781250, 0.6093750000000000, -0.0000305175781250, +0.5816040039062500, 0.0000305175781250, 0.6629943847656250, 0.0000000000000000, +0.6705932617187500, 0.0000000000000000, 0.6853637695312500, 0.0000305175781250, +0.7311401367187500, 0.0000305175781250, 0.7156677246093750, -0.0000305175781250, +0.7562866210937500, 0.0000000000000000, 0.7561645507812500, 0.0000000000000000, +0.7693176269531250, 0.0000000000000000, 0.7965087890625000, 0.0000000000000000, +0.7805175781250000, 0.0000000000000000, 0.8152465820312500, 0.0000305175781250, +0.8128356933593750, -0.0000305175781250, 0.8207092285156250, 0.0000305175781250, +0.8433837890625000, 0.0000610351562500, 0.8304443359375000, 0.0000000000000000, +0.8570251464843750, -0.0000305175781250, 0.8562927246093750, 0.0000000000000000, +0.8583984375000000, 0.0000000000000000, 0.8747558593750000, 0.0000000000000000, +0.8709106445312500, 0.0000305175781250, 0.8816223144531250, 0.0000000000000000, +0.8833007812500000, 0.0000305175781250, 0.8848266601562500, 0.0000000000000000, +0.8915710449218750, 0.0000000000000000, 0.8871459960937500, 0.0000000000000000, +0.8769836425781250, 0.0000000000000000, 0.8873901367187500, 0.0000000000000000, +0.8661499023437500, 0.0000000000000000, 0.8491821289062500, 0.0000000000000000, +0.8687438964843750, 0.0000000000000000, 0.7958984375000000, 0.0000305175781250, +0.8279113769531250, -0.0000305175781250, 0.7763366699218750, 0.0000000000000000, +0.7050170898437500, 0.0000305175781250, 0.7658081054687500, 0.0000305175781250, +0.5754089355468750, 0.0000305175781250, 0.6284790039062500, 0.0000305175781250, +0.5559997558593750, 0.0000610351562500, 0.3955383300781250, 0.0000610351562500, +0.4996643066406250, 0.0000000000000000, 0.2691040039062500, 0.0000305175781250, +0.2798767089843750, 0.0000000000000000, 0.2511291503906250, -0.0000305175781250, +0.1046447753906250, -0.0000305175781250, 0.1681213378906250, 0.0000305175781250, +0.1016540527343750, 0.0000305175781250, 0.0730285644531250, 0.0000305175781250, +0.1139526367187500, 0.0000305175781250, 0.1180419921875000, 0.0000610351562500, +0.0971984863281250}, +{0.0612792968750000, 0.0000915527343750, 0.0360717773437500, -0.0000915527343750, +0.0411071777343750, -0.0001220703125000, 0.0611572265625000, -0.0000305175781250, +0.0351867675781250, 0.0000000000000000, 0.0046081542968750, -0.0000915527343750, +0.0217285156250000, 0.0000305175781250, -0.0025024414062500, 0.0000915527343750, +-0.0238647460937500, 0.0000305175781250, 0.0213317871093750, 0.0000610351562500, +0.0420837402343750, 0.0000915527343750, 0.0184631347656250, 0.0000000000000000, +0.1710815429687500, -0.0000610351562500, 0.1402282714843750, 0.0000305175781250, +0.2196350097656250, -0.0000305175781250, 0.3646545410156250, -0.0000305175781250, +0.2949218750000000, 0.0000305175781250, 0.4815368652343750, 0.0000305175781250, +0.4855651855468750, 0.0000305175781250, 0.5118408203125000, 0.0000305175781250, +0.6260070800781250, 0.0000305175781250, 0.5884094238281250, 0.0000000000000000, +0.6441040039062500, -0.0000305175781250, 0.6614379882812500, -0.0000305175781250, +0.6482238769531250, -0.0000610351562500, 0.6572875976562500, -0.0000915527343750, +0.6555480957031250, -0.0000305175781250, 0.6307373046875000, 0.0000000000000000, +0.6321105957031250, 0.0000000000000000, 0.6109008789062500, -0.0000305175781250, +0.5806579589843750, 0.0000000000000000, 0.5874023437500000, -0.0000610351562500, +0.5492858886718750, -0.0000305175781250, 0.5383911132812500, -0.0000305175781250, +0.5296020507812500, -0.0000610351562500, 0.5070800781250000, -0.0000610351562500, +0.5030822753906250, 0.0000000000000000, 0.4913635253906250, 0.0000000000000000, +0.4794921875000000, 0.0000000000000000, 0.4700012207031250, 0.0000000000000000, +0.4624938964843750, -0.0000305175781250, 0.4570312500000000, 0.0000000000000000, +0.4461669921875000, 0.0000000000000000, 0.4331359863281250, -0.0000305175781250, +0.4324645996093750, -0.0000305175781250, 0.4306640625000000, 0.0000000000000000, +0.4191589355468750, 0.0000305175781250, 0.4353332519531250, 0.0000000000000000, +0.4271240234375000, 0.0000000000000000, 0.4329833984375000, -0.0000305175781250, +0.4479064941406250, 0.0000305175781250, 0.4371337890625000, 0.0000000000000000, +0.4647216796875000, 0.0000000000000000, 0.4511718750000000, -0.0000305175781250, +0.4696960449218750, -0.0000305175781250, 0.4992065429687500, 0.0000000000000000, +0.4768981933593750, 0.0000000000000000, 0.5435180664062500, 0.0000305175781250, +0.5283203125000000, 0.0000000000000000, 0.5558776855468750, 0.0000305175781250, +0.6076660156250000, -0.0000305175781250, 0.5704650878906250, 0.0000000000000000, +0.6680908203125000, -0.0000305175781250, 0.6454467773437500, 0.0000000000000000, +0.6796569824218750, 0.0000000000000000, 0.7582092285156250, 0.0000000000000000, +0.7077026367187500, 0.0000000000000000, 0.8167114257812500, 0.0000000000000000, +0.8072509765625000, 0.0000000000000000, 0.8085021972656250, -0.0000305175781250, +0.8770141601562500, -0.0000305175781250, 0.8497924804687500, -0.0000305175781250, +0.8392333984375000, -0.0000610351562500, 0.8822631835937500, 0.0000305175781250, +0.8073425292968750, 0.0000305175781250, 0.7472229003906250, 0.0000305175781250, +0.8092041015625000, -0.0000305175781250, 0.5795593261718750, 0.0000000000000000, +0.6348571777343750, -0.0000305175781250, 0.5415649414062500, -0.0000915527343750, +0.3369445800781250, -0.0001220703125000, 0.4514160156250000, -0.0000305175781250, +0.2242431640625000, -0.0000305175781250, 0.2157287597656250, -0.0000305175781250, +0.2162170410156250, 0.0000305175781250, 0.0987243652343750, 0.0000305175781250, +0.1357727050781250, -0.0000610351562500, 0.1344604492187500, -0.0000305175781250, +0.1085510253906250, -0.0000305175781250, 0.1350402832031250, -0.0000915527343750, +0.1717529296875000, -0.0001220703125000, 0.1546020507812500, 0.0000610351562500, +0.1732482910156250, 0.0000305175781250, 0.2035522460937500, 0.0000000000000000, +0.1457824707031250, 0.0000610351562500, 0.1126098632812500, 0.0001220703125000, +0.1512756347656250, -0.0000305175781250, -0.0388183593750000, 0.0000000000000000, +0.0071411132812500, -0.0000305175781250, -0.0765380859375000, -0.0001220703125000, +-0.2553405761718750, -0.0000915527343750, -0.1682434082031250, 0.0000305175781250, +-0.3586730957031250, 0.0000305175781250, -0.3778076171875000, 0.0000305175781250, +-0.3563232421875000, 0.0001525878906250, -0.4393310546875000, 0.0000915527343750, +-0.4256896972656250, 0.0000305175781250, -0.3467102050781250, 0.0000915527343750, +-0.3928527832031250, 0.0000000000000000, -0.3243408203125000, -0.0001831054687500, +-0.2153320312500000, -0.0000610351562500, -0.2808227539062500, -0.0000610351562500, +-0.1400146484375000, -0.0002136230468750, -0.1276245117187500, -0.0000305175781250, +-0.1395874023437500, 0.0000915527343750, -0.0834655761718750, 0.0000000000000000, +-0.0946655273437500, 0.0002746582031250, -0.0997924804687500, 0.0003356933593750, +-0.1054992675781250, 0.0001525878906250, -0.0717773437500000, 0.0002136230468750, +-0.0650634765625000, 0.0002746582031250, -0.0887451171875000, -0.0005493164062500, +0.0722656250000000, -0.0004272460937500, 0.0286254882812500, -0.0002441406250000, +0.1020202636718750, -0.0009460449218750, 0.2663269042968750, -0.0008850097656250, +0.1826477050781250, 0.0009765625000000, 0.2802124023437500, 0.0008239746093750, +0.3364562988281250, -0.0002441406250000, 0.2459106445312500, 0.0024719238281250, +0.2161560058593750, 0.0021972656250000, 0.2734985351562500, -0.0133666992187500, +0.0598754882812500, -0.0041809082031250, 0.0792236328125000, -0.0187988281250000, +0.0675964355468750, -0.0598449707031250, -0.1351013183593750, -0.0898437500000000, +0.2546997070312500, 0.0638122558593750, 0.0196228027343750, -0.0412292480468750, +0.1033020019531250, 0.0741271972656250, 0.0414428710937500, 0.2287292480468750, +-0.0982971191406250, 0.1336669921875000, -0.0494079589843750, 0.2879333496093750, +-0.0728759765625000, 0.3320007324218750, -0.1058044433593750, 0.2538452148437500, +-0.0688781738281250, 0.2811889648437500, -0.0363159179687500, 0.3157958984375000, +-0.0604248046875000, 0.0527343750000000, -0.0112915039062500, 0.1222839355468750, +-0.0047912597656250, 0.0285949707031250, -0.0108947753906250, -0.2213134765625000, +0.0054321289062500, -0.1006774902343750, 0.0032653808593750, -0.2064208984375000, +-0.0005493164062500, -0.2970581054687500, 0.0002136230468750, -0.1597900390625000, +0.0005493164062500, -0.0856933593750000, -0.0012207031250000, -0.1886596679687500, +-0.0013122558593750, 0.0924987792968750, 0.0000000000000000, 0.1017456054687500, +0.0000915527343750, 0.0462646484375000, -0.0001831054687500, 0.1817932128906250, +0.0001831054687500, 0.1798706054687500, 0.0002441406250000, -0.0692749023437500, +-0.0000305175781250, 0.0472717285156250, -0.0001220703125000, -0.1054077148437500, +0.0000305175781250, -0.4015197753906250, 0.0002441406250000, -0.2299804687500000, +0.0000915527343750, -0.5060424804687500, 0.0000000000000000, -0.5767822265625000, +0.0001831054687500, -0.4562683105468750, 0.0000305175781250, -0.5091857910156250, +-0.0003356933593750, -0.5589599609375000, -0.0002441406250000, -0.2142028808593750, +-0.0001220703125000, -0.3088378906250000, -0.0002746582031250, -0.1871337890625000, +-0.0001220703125000, 0.1196594238281250, 0.0001525878906250, -0.0436096191406250, +0.0000000000000000, 0.1982421875000000, -0.0000915527343750, 0.2453308105468750, +0.0000000000000000, 0.1843261718750000, -0.0000915527343750, 0.2539062500000000, +-0.0002136230468750, 0.2639160156250000, -0.0001831054687500, 0.1428833007812500, +0.0000000000000000, 0.1810302734375000, -0.0000305175781250, 0.1407165527343750, +-0.0000610351562500, 0.0288085937500000, 0.0001525878906250, 0.0871276855468750, +0.0001220703125000, 0.0312805175781250, -0.0001220703125000, -0.0067749023437500, +-0.0000610351562500, 0.0509338378906250, -0.0000610351562500, 0.0638427734375000, +-0.0002441406250000, 0.0266723632812500, -0.0002136230468750, 0.2119445800781250, +-0.0000915527343750, 0.1535339355468750, -0.0000915527343750, 0.2504272460937500, +-0.0001525878906250, 0.4244079589843750, -0.0000610351562500, 0.3130798339843750, +-0.0000305175781250, 0.5958557128906250, -0.0001525878906250, 0.5692749023437500, +-0.0001831054687500, 0.6175537109375000, -0.0000915527343750, 0.8046569824218750, +-0.0000610351562500, 0.7086181640625000, -0.0001220703125000, 0.8397216796875000, +0.0000610351562500, 0.8638610839843750, 0.0000915527343750, 0.8336181640625000, +0.0000000000000000, 0.8776550292968750, 0.0000000000000000, 0.8807373046875000, +0.0000610351562500, 0.8151550292968750, 0.0000305175781250, 0.8493652343750000, +0.0000000000000000, 0.8034057617187500, 0.0000610351562500, 0.7321472167968750, +0.0001220703125000, 0.7888183593750000, 0.0000610351562500, 0.6574401855468750, +0.0000915527343750, 0.6788330078125000, 0.0001525878906250, 0.6506042480468750, +0.0000915527343750, 0.5623168945312500, 0.0000305175781250, 0.6175842285156250, +0.0000305175781250, 0.5054931640625000, 0.0000915527343750, 0.5225219726562500, +0.0000915527343750, 0.4986877441406250, 0.0000610351562500, 0.4208374023437500, +0.0000610351562500, 0.4657897949218750, 0.0000915527343750, 0.3744812011718750, +0.0000610351562500, 0.3867187500000000, 0.0000915527343750, 0.3622436523437500, +0.0000610351562500, 0.2990722656250000, 0.0000305175781250, 0.3403625488281250, +0.0000305175781250, 0.2516784667968750, 0.0000610351562500, 0.2659301757812500, +0.0000610351562500, 0.2476806640625000, 0.0000305175781250, 0.1883850097656250, +0.0000915527343750, 0.2273864746093750, 0.0000610351562500, 0.1565246582031250, +0.0000610351562500, 0.1712646484375000, 0.0000915527343750, 0.1631774902343750, +0.0000610351562500, 0.1168518066406250, 0.0000915527343750, 0.1529846191406250, +0.0000915527343750, 0.1235961914062500, 0.0001525878906250, 0.1274108886718750, +0.0000915527343750, 0.1351928710937500, 0.0001220703125000, 0.1305541992187500, +0.0000610351562500, 0.1572570800781250, 0.0000915527343750, 0.1652832031250000, +0.0000915527343750, 0.1683349609375000, 0.0000610351562500, 0.1965026855468750, +0.0000915527343750, 0.2186279296875000, 0.0001220703125000, 0.2208557128906250, +0.0000915527343750, 0.2784729003906250, 0.0001525878906250, 0.2717285156250000, +0.0001525878906250, 0.3027648925781250, 0.0001220703125000, 0.3553466796875000, +0.0001525878906250, 0.3422241210937500, 0.0001220703125000, 0.4338073730468750, +0.0000915527343750, 0.4260253906250000, 0.0000915527343750, 0.4660644531250000, +0.0001220703125000, 0.5448913574218750, 0.0001220703125000, 0.5209350585937500, +0.0000915527343750, 0.6239929199218750, 0.0001220703125000, 0.6246032714843750, +0.0001220703125000, 0.6495971679687500, 0.0000610351562500, 0.7254638671875000, +0.0000610351562500, 0.7044067382812500, 0.0001220703125000, 0.7341003417968750, +-0.0000305175781250, 0.7616577148437500, -0.0000305175781250, 0.7097167968750000, +-0.0000305175781250, 0.6866760253906250, -0.0000305175781250, 0.7137145996093750, +-0.0000305175781250, 0.5329284667968750, -0.0000305175781250, 0.5761108398437500, +-0.0000305175781250, 0.4655456542968750, -0.0000915527343750, 0.2832641601562500, +-0.0000915527343750, 0.3778381347656250, -0.0000915527343750, 0.1001586914062500, +-0.0001525878906250, 0.1016540527343750, -0.0002136230468750, 0.0676269531250000, +-0.0000915527343750, -0.1023254394531250, -0.0000610351562500, -0.0407714843750000, +-0.0000915527343750, -0.1000061035156250, 0.0000610351562500, -0.1361694335937500, +0.0000610351562500}, +{0.0000000000000000, 0.7776184082031250, 0.0000610351562500, 0.7325134277343750, +0.0000000000000000, 0.7031555175781250, 0.0000305175781250, 0.7392272949218750, +0.0000610351562500, 0.6222534179687500, -0.0000305175781250, 0.6517028808593750, +-0.0000610351562500, 0.6116638183593750, 0.0000000000000000, 0.5172729492187500, +0.0000610351562500, 0.5762634277343750, 0.0000305175781250, 0.4517822265625000, +0.0000305175781250, 0.4699096679687500, 0.0001220703125000, 0.4344177246093750, +0.0000915527343750, 0.3464050292968750, 0.0000305175781250, 0.4016418457031250, +0.0000000000000000, 0.2712707519531250, 0.0000610351562500, 0.2967529296875000, +0.0000000000000000, 0.2587890625000000, 0.0000915527343750, 0.1645507812500000, +0.0001525878906250, 0.2276000976562500, 0.0001220703125000, 0.0842895507812500, +0.0000915527343750, 0.1138610839843750, 0.0001220703125000, 0.0762939453125000, +0.0000610351562500, -0.0307006835937500, 0.0000610351562500, 0.0366516113281250, +0.0000610351562500, -0.0905456542968750, 0.0001525878906250, -0.0709533691406250, +0.0001831054687500, -0.0952453613281250, 0.0001220703125000, -0.1793518066406250, +0.0001220703125000, -0.1199951171875000, 0.0001525878906250, -0.2105407714843750, +0.0000915527343750, -0.1965637207031250, 0.0000610351562500, -0.2053833007812500, +0.0001220703125000, -0.2601928710937500, 0.0000915527343750, -0.2206115722656250, +0.0000610351562500, -0.2760314941406250, 0.0001220703125000, -0.2665405273437500, +0.0001220703125000, -0.2681274414062500, 0.0000610351562500, -0.3010559082031250, +0.0000610351562500, -0.2770996093750000, 0.0000610351562500, -0.2980041503906250, +0.0000000000000000, -0.2968139648437500, -0.0000305175781250, -0.2931213378906250, +0.0000000000000000, -0.2998352050781250, 0.0000305175781250, -0.2883605957031250, +0.0000305175781250, -0.2887573242187500, 0.0000305175781250, -0.2907714843750000, +0.0000305175781250, -0.2737121582031250, 0.0000305175781250, -0.2623901367187500, +0.0000305175781250, -0.2658691406250000, 0.0000610351562500, -0.2238159179687500, +0.0000610351562500, -0.2312927246093750, 0.0000305175781250, -0.2110900878906250, +0.0000610351562500, -0.1734008789062500, 0.0000610351562500, -0.1870727539062500, +0.0000305175781250, -0.1272277832031250, 0.0000610351562500, -0.1327819824218750, +0.0000305175781250, -0.1099548339843750, 0.0000610351562500, -0.0647583007812500, +0.0000915527343750, -0.0854492187500000, 0.0000610351562500, -0.0147399902343750, +0.0000305175781250, -0.0250244140625000, 0.0000305175781250, 0.0166015625000000, +0.0000610351562500, 0.0807800292968750, 0.0000915527343750, 0.0517578125000000, +0.0000610351562500, 0.1881103515625000, 0.0001525878906250, 0.1660461425781250, +0.0001220703125000, 0.2359313964843750, 0.0000915527343750, 0.3612365722656250, +0.0001525878906250, 0.3025512695312500, 0.0001831054687500, 0.4830017089843750, +0.0000610351562500, 0.4883117675781250, 0.0000305175781250, 0.5132141113281250, +0.0000915527343750, 0.6307373046875000, 0.0000305175781250, 0.5940856933593750, +0.0000305175781250, 0.5906372070312500, 0.0000610351562500, 0.6450805664062500, +0.0000305175781250, 0.5508117675781250, 0.0000305175781250, 0.4700012207031250, +-0.0000305175781250, 0.5366516113281250, 0.0000000000000000, 0.2720642089843750, +-0.0001525878906250, 0.3038940429687500, -0.0001831054687500, 0.2207336425781250, +-0.0000915527343750, 0.0084228515625000, -0.0000915527343750, 0.0989074707031250, +-0.0001525878906250, -0.0675964355468750, 0.0000000000000000, -0.1024780273437500, +-0.0000305175781250, -0.0689697265625000, -0.0000305175781250, -0.1146850585937500, +0.0000305175781250, -0.1169433593750000, 0.0000305175781250, -0.0537719726562500, +-0.0000610351562500, -0.0616149902343750, -0.0000610351562500, -0.0574340820312500, +0.0000305175781250, -0.0118103027343750, -0.0000610351562500, -0.0224914550781250, +-0.0000610351562500, -0.0539550781250000, 0.0000000000000000, -0.0323181152343750, +0.0000305175781250, -0.0585937500000000, -0.0000305175781250, -0.1088562011718750, +-0.0000915527343750, -0.0825500488281250, -0.0000915527343750, -0.1050415039062500, +-0.0000305175781250, -0.1245422363281250, -0.0000610351562500, -0.0969238281250000, +-0.0001525878906250, -0.0777587890625000, -0.0000915527343750, -0.0951843261718750, +0.0000000000000000, -0.0519714355468750, -0.0006713867187500, -0.0479736328125000, +-0.0007019042968750, -0.0525512695312500, -0.0001831054687500, -0.0396728515625000, +-0.0004272460937500, -0.0404357910156250, -0.0008544921875000, -0.0248413085937500, +0.0007019042968750, -0.0434875488281250, 0.0021362304687500, -0.0028381347656250, +-0.0031738281250000, 0.0371093750000000, -0.0039062500000000, 0.0014038085937500, +-0.0001220703125000, 0.1106567382812500, -0.0245666503906250, 0.1091003417968750, +-0.0190124511718750, 0.0993652343750000, -0.0232238769531250, 0.1653747558593750, +-0.0513000488281250, 0.1504821777343750, -0.0454711914062500, 0.0468750000000000, +-0.0111999511718750, 0.0990905761718750, -0.0384216308593750, 0.0699462890625000, +-0.0077209472656250, -0.0292053222656250, 0.0422668457031250, 0.0242919921875000, +0.0096740722656250, -0.0412597656250000, 0.0940246582031250, -0.0629577636718750, +0.1047058105468750, -0.0367736816406250, 0.0845642089843750, -0.0421142578125000, +0.1154174804687500, -0.0533447265625000, 0.1192626953125000, -0.0141296386718750, +0.0480346679687500, -0.0151977539062500, 0.0649108886718750, -0.0158996582031250, +0.0469665527343750, 0.0041809082031250, -0.0162048339843750, -0.0006408691406250, +0.0059204101562500, -0.0011596679687500, -0.0037231445312500, 0.0010375976562500, +-0.0158081054687500, 0.0003356933593750, -0.0120239257812500, -0.0016784667968750, +0.0007934570312500, -0.0014038085937500, -0.0017395019531250, -0.0001525878906250, +-0.0449523925781250, -0.0004882812500000, -0.0231933593750000, -0.0005187988281250, +-0.0533447265625000, 0.0003356933593750, -0.1131896972656250, 0.0002441406250000, +-0.0807495117187500, -0.0001831054687500, -0.1094665527343750, -0.0001831054687500, +-0.1349487304687500, 0.0000000000000000, -0.0960998535156250, -0.0001220703125000, +-0.0713195800781250, -0.0002136230468750, -0.0982971191406250, 0.0000305175781250, +-0.0270996093750000, 0.0001525878906250, -0.0198059082031250, -0.0000305175781250, +-0.0341796875000000, -0.0000610351562500, -0.0087890625000000, 0.0000610351562500, +-0.0063476562500000, -0.0000915527343750, -0.0439453125000000, -0.0002441406250000, +-0.0432434082031250, -0.0000305175781250, -0.0283203125000000, 0.0000915527343750, +-0.0498657226562500, -0.0001220703125000, -0.0534362792968750, 0.0000305175781250, +0.0421142578125000, 0.0001220703125000, -0.0008239746093750, 0.0000305175781250, +0.0842895507812500, -0.0000915527343750, 0.2077026367187500, 0.0000000000000000, +0.1299438476562500, -0.0000610351562500, 0.3274230957031250, -0.0001525878906250, +0.3304138183593750, -0.0000305175781250, 0.3473815917968750, 0.0000305175781250, +0.4639892578125000, -0.0000610351562500, 0.4249572753906250, 0.0000305175781250, +0.4411926269531250, 0.0000915527343750, 0.4710693359375000, 0.0000000000000000, +0.4176940917968750, 0.0000000000000000, 0.3775939941406250, 0.0000305175781250, +0.4046936035156250, -0.0000305175781250, 0.2766113281250000, -0.0001220703125000, +0.2877807617187500, -0.0000305175781250, 0.2457580566406250, 0.0000000000000000, +0.1490173339843750, -0.0000305175781250, 0.1897583007812500, 0.0000305175781250, +0.0855407714843750, 0.0000610351562500, 0.0827636718750000, 0.0000305175781250, +0.0599975585937500, 0.0000610351562500, -0.0059814453125000, 0.0000610351562500, +0.0161437988281250, 0.0000000000000000, -0.0556945800781250, -0.0000305175781250, +-0.0556945800781250, 0.0000305175781250, -0.0783081054687500, 0.0000305175781250, +-0.1294860839843750, 0.0000000000000000, -0.1123352050781250, 0.0000915527343750, +-0.1779479980468750, 0.0000915527343750, -0.1767883300781250, 0.0000610351562500, +-0.1963195800781250, 0.0000610351562500, -0.2449035644531250, 0.0000915527343750, +-0.2300109863281250, -0.0000305175781250, -0.2774047851562500, 0.0000305175781250, +-0.2839355468750000, 0.0000610351562500, -0.2936401367187500, 0.0000610351562500, +-0.3207702636718750, 0.0000915527343750, -0.3118896484375000, 0.0000610351562500, +-0.3290100097656250, 0.0000915527343750, -0.3343200683593750, 0.0001220703125000, +-0.3364562988281250, 0.0000915527343750, -0.3441467285156250, 0.0000915527343750, +-0.3421630859375000, 0.0000610351562500, -0.3434753417968750, 0.0000305175781250, +-0.3490600585937500, 0.0000610351562500, -0.3477172851562500, 0.0000610351562500, +-0.3463745117187500, 0.0000610351562500, -0.3519287109375000, 0.0000610351562500, +-0.3428039550781250, 0.0000610351562500, -0.3490295410156250, 0.0000305175781250, +-0.3425292968750000, 0.0000305175781250, -0.3334350585937500, 0.0000305175781250, +-0.3441772460937500, 0.0000305175781250, -0.3162536621093750, 0.0000000000000000, +-0.3299560546875000, 0.0000000000000000, -0.3132324218750000, -0.0000305175781250, +-0.2858276367187500, -0.0000305175781250, -0.3068542480468750, 0.0000000000000000, +-0.2380065917968750, 0.0000000000000000, -0.2598571777343750, -0.0000305175781250, +-0.2234497070312500, 0.0000000000000000, -0.1620178222656250, 0.0000305175781250, +-0.2084045410156250, -0.0000305175781250, -0.0893249511718750, -0.0000610351562500, +-0.1203613281250000, 0.0000000000000000, -0.0773010253906250, 0.0000305175781250, +0.0196533203125000, -0.0000305175781250, -0.0447998046875000, 0.0000610351562500, +0.1012573242187500, 0.0000305175781250, 0.0787658691406250, -0.0000305175781250, +0.1051330566406250, -0.0000305175781250, 0.2055358886718750, 0.0000000000000000, +0.1523437500000000, 0.0000000000000000, 0.2526245117187500, -0.0000610351562500, +0.2462158203125000, 0.0000000000000000, 0.2692565917968750, 0.0000000000000000, +0.3319702148437500, -0.0000305175781250, 0.2944946289062500, 0.0000000000000000, +0.3912658691406250, 0.0000610351562500, 0.3677978515625000, 0.0000000000000000, +0.4180908203125000, -0.0000610351562500, 0.5052185058593750, 0.0000000000000000, +0.4475402832031250, 0.0000000000000000, 0.6027832031250000, -0.0000305175781250, +0.5871276855468750, -0.0000305175781250, 0.6146240234375000, 0.0000000000000000, +0.7244262695312500, 0.0000305175781250, 0.6721801757812500, -0.0000610351562500, +0.7174682617187500, 0.0000000000000000, 0.7516784667968750, -0.0000610351562500, +0.6925048828125000, -0.0001525878906250, 0.6714477539062500, -0.0001220703125000, +0.7080078125000000, -0.0000915527343750, 0.5372009277343750, -0.0001220703125000, +0.5722656250000000, -0.0000610351562500, 0.4974365234375000, 0.0000305175781250, +0.3458557128906250, -0.0000305175781250, 0.4251098632812500, -0.0000610351562500, +0.2461853027343750, 0.0000000000000000, 0.2440795898437500, -0.0000305175781250, +0.2333374023437500, -0.0001525878906250, 0.1335449218750000, -0.0000915527343750, +0.1684570312500000, -0.0001525878906250, 0.1361999511718750, -0.0002136230468750, +0.1248474121093750, -0.0001220703125000, 0.1287231445312500, -0.0000610351562500, +0.1283569335937500, -0.0001220703125000, 0.1294860839843750, 0.0001220703125000, +0.0845031738281250, 0.0001220703125000, 0.1208801269531250, 0.0000000000000000, +0.0482177734375000, 0.0001220703125000, -0.0288085937500000, 0.0001831054687500, +0.0342407226562500, -0.0004272460937500, -0.1912231445312500, -0.0003967285156250, +-0.1619567871093750, -0.0001525878906250, -0.2121582031250000, -0.0005187988281250, +-0.3875427246093750}, +{-0.2116394042968750, 0.0000610351562500, -0.1924133300781250, 0.0000915527343750, +-0.1909179687500000, 0.0000915527343750, -0.1836853027343750, 0.0000305175781250, +-0.1732482910156250, 0.0000915527343750, -0.1737060546875000, 0.0000915527343750, +-0.1745300292968750, 0.0000610351562500, -0.1674499511718750, 0.0000915527343750, +-0.1781005859375000, 0.0000915527343750, -0.1657104492187500, 0.0000610351562500, +-0.1748352050781250, 0.0000610351562500, -0.1908569335937500, 0.0000915527343750, +-0.1758422851562500, 0.0000305175781250, -0.2123718261718750, 0.0000305175781250, +-0.2051391601562500, 0.0000305175781250, -0.2159729003906250, 0.0000000000000000, +-0.2436828613281250, 0.0000000000000000, -0.2282714843750000, 0.0000610351562500, +-0.2674865722656250, 0.0000610351562500, -0.2588195800781250, 0.0000305175781250, +-0.2736511230468750, 0.0000915527343750, -0.3065490722656250, 0.0000305175781250, +-0.2875671386718750, 0.0000305175781250, -0.3344726562500000, 0.0000000000000000, +-0.3294067382812500, 0.0000305175781250, -0.3366088867187500, 0.0000305175781250, +-0.3684692382812500, 0.0000610351562500, -0.3540039062500000, 0.0000305175781250, +-0.3755493164062500, 0.0000610351562500, -0.3833007812500000, 0.0000610351562500, +-0.3706054687500000, 0.0000305175781250, -0.3765563964843750, 0.0000610351562500, +-0.3835144042968750, -0.0000610351562500, -0.3267822265625000, -0.0000610351562500, +-0.3571166992187500, -0.0000305175781250, -0.3096923828125000, -0.0000610351562500, +-0.2459411621093750, -0.0000610351562500, -0.2991027832031250, -0.0000305175781250, +-0.1432189941406250, 0.0000000000000000, -0.1760559082031250, -0.0000305175781250, +-0.1174316406250000, -0.0000915527343750, 0.0109558105468750, -0.0000915527343750, +-0.0654296875000000, -0.0000610351562500, 0.1036071777343750, -0.0001220703125000, +0.0874023437500000, -0.0000610351562500, 0.1236267089843750, 0.0000000000000000, +0.2384338378906250, -0.0000305175781250, 0.1807861328125000, -0.0000305175781250, +0.3045654296875000, 0.0000000000000000, 0.2911071777343750, -0.0000610351562500, +0.3302307128906250, -0.0001525878906250, 0.4199523925781250, -0.0000610351562500, +0.3678894042968750, -0.0000915527343750, 0.5006713867187500, -0.0001525878906250, +0.4874877929687500, -0.0000610351562500, 0.5169982910156250, 0.0000000000000000, +0.6150207519531250, -0.0000305175781250, 0.5720214843750000, 0.0000000000000000, +0.6376647949218750, 0.0000000000000000, 0.6598510742187500, -0.0000610351562500, +0.6285400390625000, -0.0000305175781250, 0.6381835937500000, 0.0000000000000000, +0.6513977050781250, -0.0000610351562500, 0.5512695312500000, -0.0000915527343750, +0.5873413085937500, -0.0000610351562500, 0.5252075195312500, -0.0000305175781250, +0.4201965332031250, -0.0000305175781250, 0.4805297851562500, 0.0001831054687500, +0.3073120117187500, 0.0002136230468750, 0.3219909667968750, 0.0000915527343750, +0.2853088378906250, 0.0002441406250000, 0.1652526855468750, 0.0002441406250000, +0.2211608886718750, -0.0002746582031250, 0.1305847167968750, -0.0002441406250000, +0.1202087402343750, -0.0000915527343750, 0.1282958984375000, -0.0004577636718750, +0.0966796875000000, -0.0004882812500000, 0.1040954589843750, 0.0005798339843750, +0.0798034667968750, 0.0008544921875000, 0.1024169921875000, -0.0008850097656250, +0.0473327636718750, 0.0004577636718750, 0.0013122558593750, 0.0009765625000000, +0.0469055175781250, -0.0137634277343750, -0.1514282226562500, -0.0052795410156250, +-0.1105041503906250, -0.0208740234375000, -0.1728210449218750, -0.0428771972656250, +-0.3471679687500000, -0.0272216796875000, -0.2649536132812500, -0.0603027343750000, +-0.3566589355468750, -0.0698242187500000, -0.4157104492187500, -0.0445251464843750, +-0.3238525390625000, -0.0516662597656250, -0.2862243652343750, -0.0635375976562500, +-0.3431701660156250, 0.0503845214843750, -0.1302185058593750, 0.0135498046875000, +-0.1455993652343750, 0.0757751464843750, -0.1295471191406250, 0.2013549804687500, +0.0048522949218750, 0.1334533691406250, -0.0396728515625000, 0.2241821289062500, +-0.0342712402343750, 0.2681884765625000, -0.0090942382812500, 0.1992797851562500, +-0.0206298828125000, 0.1357727050781250, -0.0522155761718750, -0.1597595214843750, +-0.0311279296875000, -0.0859680175781250, -0.0210571289062500, -0.2081604003906250, +0.0012512207031250, -0.0658569335937500, -0.0085754394531250, 0.1084289550781250, +-0.0441894531250000, -0.0061340332031250, -0.0367736816406250, 0.1486816406250000, +0.0388183593750000, 0.2248229980468750, -0.0033874511718750, 0.0931396484375000, +0.0560302734375000, 0.0711059570312500, 0.1681213378906250, 0.1524963378906250, +0.1075439453125000, -0.2294311523437500, 0.1695556640625000, -0.1683044433593750, +0.2153625488281250, -0.2363891601562500, 0.1450805664062500, -0.5372314453125000, +0.1090087890625000, -0.4170837402343750, 0.1553039550781250, -0.4218444824218750, +0.0059509277343750, -0.5513000488281250, 0.0084228515625000, -0.3617553710937500, +0.0054931640625000, -0.1838073730468750, -0.0778198242187500, -0.3432617187500000, +-0.0542297363281250, 0.0571594238281250, -0.0444946289062500, 0.0534973144531250, +-0.0642089843750000, 0.0516967773437500, -0.0435485839843750, 0.2678527832031250, +-0.0122680664062500, 0.2064208984375000, -0.0282897949218750, 0.1932983398437500, +-0.0041809082031250, 0.2458190917968750, 0.0019531250000000, 0.1962280273437500, +-0.0029907226562500, 0.1234741210937500, 0.0016479492187500, 0.1662902832031250, +0.0019531250000000, 0.1149597167968750, -0.0003967285156250, 0.0890502929687500, +-0.0008850097656250, 0.1289367675781250, -0.0001525878906250, 0.1372985839843750, +-0.0001220703125000, 0.1145935058593750, -0.0004882812500000, 0.2157592773437500, +0.0000000000000000, 0.1920471191406250, 0.0002441406250000, 0.2360839843750000, +0.0000305175781250, 0.3189697265625000, -0.0001220703125000, 0.2682189941406250, +0.0000000000000000, 0.4113464355468750, -0.0000610351562500, 0.3825988769531250, +-0.0000915527343750, 0.4371032714843750, -0.0000915527343750, 0.5561523437500000, +-0.0000305175781250, 0.4847717285156250, 0.0000000000000000, 0.6365661621093750, +-0.0001525878906250, 0.6381225585937500, -0.0001831054687500, 0.6283874511718750, +-0.0000915527343750, 0.7108154296875000, -0.0000915527343750, 0.6886901855468750, +-0.0001831054687500, 0.6308288574218750, 0.0000915527343750, 0.6850280761718750, +0.0001220703125000, 0.6015319824218750, 0.0000305175781250, 0.5023803710937500, +0.0000305175781250, 0.5777893066406250, 0.0000915527343750, 0.3395080566406250, +-0.0000305175781250, 0.3789978027343750, -0.0001220703125000, 0.3032531738281250, +0.0000305175781250, 0.1229553222656250, 0.0000915527343750, 0.2239990234375000, +-0.0000305175781250, -0.0086059570312500, 0.0000610351562500, 0.0099792480468750, +0.0001831054687500, -0.0408325195312500, 0.0000915527343750, -0.1943359375000000, +0.0000000000000000, -0.1087646484375000, 0.0000610351562500, -0.2705383300781250, +0.0000305175781250, -0.2647705078125000, -0.0000305175781250, -0.2802429199218750, +0.0000000000000000, -0.3771362304687500, 0.0000915527343750, -0.3341979980468750, +0.0000915527343750, -0.3938598632812500, 0.0000305175781250, -0.4058227539062500, +0.0000610351562500, -0.3904724121093750, 0.0000305175781250, -0.4119567871093750, +-0.0000610351562500, -0.4180297851562500, -0.0000305175781250, -0.3795776367187500, +0.0000000000000000, -0.4003601074218750, -0.0000305175781250, -0.3776855468750000, +-0.0000610351562500, -0.3388366699218750, 0.0000000000000000, -0.3708496093750000, +0.0000000000000000, -0.2952880859375000, -0.0000915527343750, -0.3127746582031250, +-0.0000610351562500, -0.2931823730468750, 0.0000000000000000, -0.2350463867187500, +-0.0001220703125000, -0.2698974609375000, -0.0000915527343750, -0.2042541503906250, +-0.0000610351562500, -0.2114868164062500, 0.0000000000000000, -0.2003784179687500, +-0.0000305175781250, -0.1584167480468750, -0.0000305175781250, -0.1831970214843750, +0.0000305175781250, -0.1367492675781250, -0.0000610351562500, -0.1412048339843750, +-0.0000915527343750, -0.1368103027343750, -0.0000305175781250, -0.1102600097656250, +-0.0000305175781250, -0.1264648437500000, -0.0000305175781250, -0.0999145507812500, +0.0000305175781250, -0.1057434082031250, 0.0000305175781250, -0.1026306152343750, +0.0000000000000000, -0.0850830078125000, 0.0000000000000000, -0.0983581542968750, +0.0000305175781250, -0.0837707519531250, 0.0000000000000000, -0.0877380371093750, +0.0000000000000000, -0.0856628417968750, -0.0000305175781250, -0.0787048339843750, +0.0000305175781250, -0.0935974121093750, 0.0000305175781250, -0.0807800292968750, +0.0000305175781250, -0.0837402343750000, 0.0000305175781250, -0.0932617187500000, +0.0000305175781250, -0.0914001464843750, 0.0000000000000000, -0.0971374511718750, +0.0000305175781250, -0.1196899414062500, 0.0000000000000000, -0.1117553710937500, +-0.0000305175781250, -0.1314086914062500, -0.0000305175781250, -0.1596679687500000, +0.0000000000000000, -0.1503906250000000, -0.0000305175781250, -0.2065734863281250, +-0.0000305175781250, -0.2032165527343750, -0.0000305175781250, -0.2197875976562500, +0.0000000000000000, -0.2644042968750000, -0.0000305175781250, -0.2508544921875000, +-0.0000305175781250, -0.2771301269531250, -0.0000610351562500, -0.2894897460937500, +-0.0000610351562500, -0.2747192382812500, -0.0000305175781250, -0.2766723632812500, +-0.0000610351562500, -0.2857360839843750, -0.0000305175781250, -0.2294006347656250, +0.0000000000000000, -0.2440795898437500, 0.0000000000000000, -0.2165222167968750, +0.0000000000000000, -0.1624755859375000, 0.0000610351562500, -0.1886901855468750, +0.0000305175781250, -0.1196289062500000, -0.0000305175781250, -0.1187133789062500, +-0.0000305175781250, -0.1099243164062500, -0.0000305175781250, -0.0723876953125000, +-0.0000610351562500, -0.0875244140625000, -0.0000915527343750, -0.0501098632812500, +0.0000000000000000, -0.0610656738281250, -0.0000610351562500, -0.0297546386718750, +-0.0000305175781250, 0.0049438476562500, 0.0000610351562500, -0.0220642089843750, +0.0000610351562500, 0.1109313964843750, -0.0000610351562500, 0.0787048339843750, +-0.0000610351562500, 0.1546936035156250, 0.0000000000000000, 0.2896423339843750, +0.0000000000000000, 0.2206726074218750, 0.0000000000000000, 0.4014892578125000, +0.0000000000000000, 0.4204406738281250, 0.0000915527343750, 0.3998413085937500, +-0.0000305175781250, 0.4854736328125000, -0.0000305175781250, 0.4758605957031250, +-0.0000305175781250, 0.3500671386718750, -0.0001220703125000, 0.4158630371093750, +-0.0001525878906250, 0.3055114746093750, -0.0001220703125000, 0.1343078613281250, +-0.0001525878906250, 0.2324829101562500, -0.0001525878906250, -0.0072021484375000, +-0.0004272460937500, -0.0195617675781250, -0.0003356933593750, -0.0124206542968750, +-0.0003356933593750, -0.1291809082031250, -0.0007324218750000, -0.1003112792968750, +-0.0006408691406250, -0.0754394531250000, 0.0004882812500000, -0.0982055664062500, +0.0003967285156250, -0.0791320800781250, -0.0008544921875000, -0.0342102050781250, +0.0009765625000000, -0.0504150390625000, 0.0011596679687500, -0.0627441406250000, +-0.0125732421875000, -0.0413818359375000, -0.0050048828125000, -0.0672607421875000, +-0.0161743164062500, -0.1076660156250000, -0.0362548828125000, -0.0850219726562500, +-0.0224304199218750, -0.1081237792968750, -0.0328369140625000, -0.1258239746093750, +-0.0495300292968750, -0.1010742187500000, -0.0165710449218750, -0.0859375000000000, +0.0031433105468750, -0.1025085449218750, -0.0227050781250000, -0.0608215332031250, +0.0667114257812500}, +{0.0000610351562500, -0.1401672363281250, 0.0000305175781250, -0.1469726562500000, +0.0000305175781250, -0.1307678222656250, 0.0000305175781250, -0.0943603515625000, +0.0000000000000000, -0.1144104003906250, 0.0000305175781250, -0.0639648437500000, +0.0000305175781250, -0.0674438476562500, 0.0000610351562500, -0.0525207519531250, +0.0000000000000000, -0.0173034667968750, -0.0000305175781250, -0.0355529785156250, +0.0000305175781250, 0.0109252929687500, -0.0000305175781250, 0.0050964355468750, +-0.0000305175781250, 0.0177612304687500, 0.0000305175781250, 0.0507507324218750, +0.0000000000000000, 0.0328369140625000, 0.0000000000000000, 0.0770263671875000, +0.0000305175781250, 0.0721130371093750, 0.0000305175781250, 0.0826416015625000, +0.0000000000000000, 0.1146240234375000, 0.0000305175781250, 0.0964660644531250, +-0.0000305175781250, 0.1196899414062500, -0.0000610351562500, 0.1253662109375000, +-0.0000305175781250, 0.1116333007812500, -0.0000915527343750, 0.1146545410156250, +-0.0001525878906250, 0.1163330078125000, -0.0000915527343750, 0.0707092285156250, +-0.0000610351562500, 0.0847167968750000, -0.0000915527343750, 0.0469665527343750, +-0.0000915527343750, -0.0089416503906250, -0.0000610351562500, 0.0153503417968750, +-0.0000610351562500, -0.0773620605468750, -0.0000915527343750, -0.0768737792968750, +-0.0000915527343750, -0.0953369140625000, -0.0000915527343750, -0.1590270996093750, +-0.0001220703125000, -0.1387939453125000, -0.0001220703125000, -0.1637573242187500, +-0.0000305175781250, -0.1826782226562500, -0.0000610351562500, -0.1618041992187500, +-0.0000610351562500, -0.1539306640625000, 0.0000305175781250, -0.1695251464843750, +0.0000000000000000, -0.1132202148437500, -0.0000610351562500, -0.1215209960937500, +-0.0000305175781250, -0.1074218750000000, -0.0000305175781250, -0.0654296875000000, +-0.0000610351562500, -0.0843505859375000, -0.0000915527343750, -0.0492553710937500, +-0.0000305175781250, -0.0519104003906250, -0.0000305175781250, -0.0357360839843750, +-0.0000305175781250, -0.0151367187500000, -0.0000305175781250, -0.0297546386718750, +-0.0000610351562500, 0.0636901855468750, -0.0000915527343750, 0.0307617187500000, +-0.0000305175781250, 0.1048889160156250, -0.0000305175781250, 0.2140197753906250, +0.0000305175781250, 0.1473083496093750, -0.0000610351562500, 0.3371582031250000, +-0.0003051757812500, 0.3388061523437500, -0.0001525878906250, 0.3389282226562500, +-0.0002441406250000, 0.4520874023437500, -0.0006713867187500, 0.4225158691406250, +-0.0004882812500000, 0.3462524414062500, 0.0001831054687500, 0.4154968261718750, +-0.0001525878906250, 0.3016662597656250, -0.0004272460937500, 0.1542053222656250, +0.0013427734375000, 0.2530822753906250, 0.0008239746093750, 0.0083923339843750, +-0.0075683593750000, -0.0023803710937500, -0.0011901855468750, -0.0007019042968750, +-0.0120239257812500, -0.1245727539062500, -0.0275268554687500, -0.0923156738281250, +-0.0162048339843750, -0.0752563476562500, -0.0335998535156250, -0.0992736816406250, +-0.0442810058593750, -0.0805969238281250, -0.0190734863281250, -0.0399169921875000, +-0.0132446289062500, -0.0556335449218750, -0.0320129394531250, -0.0663452148437500, +0.0488891601562500, -0.0468139648437500, 0.0350036621093750, -0.0695190429687500, +0.0484313964843750, -0.1057434082031250, 0.1140747070312500, -0.0853576660156250, +0.0890502929687500, -0.1014099121093750, 0.0812683105468750, -0.1171875000000000, +0.1081848144531250, -0.0978088378906250, 0.0749816894531250, -0.0759277343750000, +0.0197143554687500, -0.0766601562500000, 0.0289611816406250, -0.0530700683593750, +-0.0031738281250000, -0.0592651367187500, -0.0042114257812500, -0.0504150390625000, +0.0026245117187500, -0.0379028320312500, -0.0065612792968750, -0.0481872558593750, +-0.0085754394531250, 0.0179748535156250, -0.0191955566406250, -0.0098876953125000, +-0.0037231445312500, 0.0298461914062500, -0.0356445312500000, 0.1073913574218750, +-0.0711975097656250, 0.0590515136718750, -0.0435791015625000, 0.1274719238281250, +-0.1066894531250000, 0.1545410156250000, -0.1184692382812500, 0.1083984375000000, +-0.0973510742187500, 0.1045837402343750, -0.1117248535156250, 0.1315917968750000, +-0.1200866699218750, 0.0212707519531250, -0.0686035156250000, 0.0327758789062500, +-0.0712280273437500, 0.0203247070312500, -0.0724792480468750, -0.0544738769531250, +-0.0444335937500000, -0.0277404785156250, -0.0483398437500000, -0.0349731445312500, +-0.0557861328125000, -0.0532836914062500, -0.0625610351562500, -0.0344543457031250, +-0.0323486328125000, -0.0146789550781250, -0.0259399414062500, -0.0281066894531250, +-0.0473937988281250, -0.0048217773437500, 0.0853271484375000, -0.0004882812500000, +0.0457458496093750, -0.0043029785156250, 0.1048889160156250, 0.0019836425781250, +0.2372741699218750, 0.0017089843750000, 0.1702575683593750, -0.0006408691406250, +0.2833862304687500, -0.0006408691406250, 0.3075256347656250, -0.0000915527343750, +0.2770080566406250, -0.0007019042968750, 0.3072204589843750, -0.0009155273437500, +0.3128967285156250, -0.0000610351562500, 0.2372131347656250, 0.0000610351562500, +0.2611083984375000, -0.0001525878906250, 0.2201538085937500, -0.0000305175781250, +0.1464538574218750, 0.0000915527343750, 0.1869812011718750, -0.0000915527343750, +0.0784912109375000, -0.0002136230468750, 0.0867614746093750, -0.0000610351562500, +0.0542907714843750, 0.0000305175781250, -0.0246887207031250, -0.0000305175781250, +0.0148925781250000, 0.0000000000000000, -0.0721130371093750, 0.0000305175781250, +-0.0766906738281250, -0.0000305175781250, -0.0802917480468750, -0.0001525878906250, +-0.1275634765625000, -0.0000610351562500, -0.1112976074218750, -0.0000915527343750, +-0.1087036132812500, -0.0001525878906250, -0.1224670410156250, -0.0000915527343750, +-0.0924987792968750, 0.0000305175781250, -0.0652160644531250, -0.0000305175781250, +-0.0803527832031250, -0.0000610351562500, -0.0079345703125000, -0.0000305175781250, +-0.0100097656250000, -0.0000915527343750, 0.0097045898437500, -0.0001831054687500, +0.0621948242187500, -0.0001220703125000, 0.0429992675781250, -0.0001220703125000, +0.0757751464843750, -0.0001831054687500, 0.0873413085937500, -0.0001220703125000, +0.0760498046875000, -0.0000610351562500, 0.0817871093750000, -0.0000610351562500, +0.0869445800781250, -0.0000915527343750, 0.0520629882812500, -0.0000610351562500, +0.0625000000000000, -0.0001220703125000, 0.0427551269531250, -0.0001831054687500, +0.0072326660156250, -0.0001220703125000, 0.0256347656250000, -0.0000610351562500, +-0.0237121582031250, -0.0001220703125000, -0.0215759277343750, -0.0001220703125000, +-0.0324707031250000, -0.0000305175781250, -0.0641479492187500, -0.0000610351562500, +-0.0482177734375000, -0.0000915527343750, -0.0803527832031250, -0.0000610351562500, +-0.0772705078125000, -0.0000610351562500, -0.0813598632812500, -0.0000915527343750, +-0.0997619628906250, -0.0000915527343750, -0.0880126953125000, -0.0000610351562500, +-0.1109008789062500, -0.0000915527343750, -0.1034240722656250, -0.0000305175781250, +-0.1093139648437500, -0.0000305175781250, -0.1265258789062500, -0.0000610351562500, +-0.1130371093750000, -0.0000305175781250, -0.1399230957031250, -0.0000305175781250, +-0.1296386718750000, -0.0000305175781250, -0.1376037597656250, 0.0000000000000000, +-0.1592102050781250, 0.0000000000000000, -0.1421508789062500, -0.0000305175781250, +-0.1782531738281250, -0.0000305175781250, -0.1720581054687500, -0.0000305175781250, +-0.1798400878906250, -0.0000305175781250, -0.2054443359375000, -0.0000305175781250, +-0.1917724609375000, -0.0000610351562500, -0.2225341796875000, -0.0000610351562500, +-0.2167663574218750, -0.0000915527343750, -0.2281799316406250, -0.0000610351562500, +-0.2526550292968750, -0.0000305175781250, -0.2364807128906250, -0.0001220703125000, +-0.2715148925781250, -0.0000915527343750, -0.2678833007812500, -0.0000915527343750, +-0.2761840820312500, -0.0001220703125000, -0.3000488281250000, -0.0000915527343750, +-0.2865600585937500, -0.0000610351562500, -0.3142089843750000, -0.0000915527343750, +-0.3124084472656250, -0.0000610351562500, -0.3154907226562500, 0.0000000000000000, +-0.3340759277343750, -0.0000305175781250, -0.3279724121093750, -0.0000610351562500, +-0.3368530273437500, -0.0000305175781250, -0.3399963378906250, -0.0000610351562500, +-0.3377075195312500, -0.0000610351562500, -0.3405151367187500, -0.0000915527343750, +-0.3432922363281250, 0.0000000000000000, -0.3376159667968750, 0.0000000000000000, +-0.3376770019531250, -0.0000610351562500, -0.3393249511718750, -0.0000610351562500, +-0.3375549316406250, 0.0000000000000000, -0.3368835449218750, -0.0000610351562500, +-0.3374023437500000, -0.0000610351562500, -0.3385314941406250, -0.0000305175781250, +-0.3340759277343750, -0.0000305175781250, -0.3338317871093750, -0.0000610351562500, +-0.3365478515625000, 0.0000000000000000, -0.3116455078125000, 0.0000305175781250, +-0.3222656250000000, 0.0000305175781250, -0.2979431152343750, 0.0000305175781250, +-0.2685546875000000, 0.0000610351562500, -0.2878417968750000, -0.0000305175781250, +-0.2081909179687500, -0.0000305175781250, -0.2308044433593750, 0.0000305175781250, +-0.1806640625000000, -0.0000305175781250, -0.1056213378906250, -0.0000610351562500, +-0.1515808105468750, 0.0000305175781250, 0.0225830078125000, 0.0000610351562500, +-0.0138854980468750, 0.0000305175781250, 0.0736694335937500, 0.0001525878906250, +0.2312927246093750, 0.0001525878906250, 0.1423034667968750, -0.0001525878906250, +0.3826904296875000, 0.0000000000000000, 0.3702697753906250, -0.0000915527343750, +0.4047241210937500, -0.0004577636718750, 0.5628967285156250, -0.0003356933593750, +0.5027160644531250, 0.0003662109375000, 0.5771789550781250, 0.0003662109375000, +0.6065673828125000, -0.0006103515625000, 0.5727233886718750, 0.0006103515625000, +0.5751342773437500, 0.0007629394531250, 0.5891418457031250, -0.0096130371093750, +0.5247497558593750, -0.0030822753906250, 0.5396423339843750, -0.0153198242187500, +0.5104370117187500, -0.0321655273437500, 0.4576416015625000, -0.0202331542968750, +0.4870605468750000, -0.0454406738281250, 0.3830261230468750, -0.0537719726562500, +0.4068908691406250, -0.0323791503906250, 0.3547363281250000, -0.0364990234375000, +0.2588806152343750, -0.0478820800781250, 0.3156738281250000, 0.0448913574218750, +0.1773681640625000, 0.0151367187500000, 0.1818847656250000, 0.0600585937500000, +0.1693725585937500, 0.1588745117187500, 0.0885314941406250, 0.1060180664062500, +0.1203918457031250, 0.1689758300781250, 0.0762329101562500, 0.2107238769531250, +0.0797729492187500, 0.1352539062500000, 0.0521240234375000, 0.1063232421875000, +0.0236511230468750, 0.1547851562500000, 0.0496520996093750, -0.0480041503906250, +-0.0978088378906250, -0.0314941406250000, -0.0542907714843750, -0.0472717285156250, +-0.1217956542968750, -0.1900024414062500, -0.2718505859375000, -0.1453857421875000, +-0.1892395019531250, -0.0741882324218750, -0.2921752929687500, -0.1417541503906250, +-0.3360900878906250, -0.0700073242187500, -0.2707214355468750, 0.1466369628906250, +-0.2232055664062500, 0.0979919433593750, -0.1776733398437500, -0.2965393066406250, +-0.2817993164062500, -0.1639099121093750, -0.3138122558593750, -0.2261657714843750, +-0.2363891601562500, -0.4462280273437500, -0.2046203613281250, -0.3847351074218750, +-0.2570495605468750, -0.2768554687500000, -0.0695190429687500, -0.3813781738281250, +-0.0782165527343750, -0.2401123046875000, -0.0733642578125000, -0.0373840332031250, +0.0371093750000000, -0.1683044433593750, 0.0079345703125000, 0.1078796386718750, +-0.0056457519531250, 0.1342468261718750, 0.0102539062500000, 0.1021728515625000, +0.0125732421875000}, +{-0.1389160156250000, 0.0000305175781250, -0.1673889160156250, 0.0000000000000000, +-0.2387084960937500, 0.0000305175781250, -0.1954345703125000, -0.0000305175781250, +-0.2885131835937500, 0.0000000000000000, -0.2835693359375000, 0.0000000000000000, +-0.2991333007812500, -0.0000305175781250, -0.3603210449218750, 0.0000000000000000, +-0.3320007324218750, 0.0000915527343750, -0.3716125488281250, 0.0000610351562500, +-0.3787231445312500, 0.0000610351562500, -0.3675842285156250, 0.0000915527343750, +-0.3807983398437500, 0.0000915527343750, -0.3828430175781250, 0.0000305175781250, +-0.3543395996093750, 0.0000305175781250, -0.3661804199218750, 0.0000610351562500, +-0.3440551757812500, 0.0000000000000000, -0.3099060058593750, 0.0000305175781250, +-0.3292541503906250, 0.0001525878906250, -0.2744750976562500, 0.0000915527343750, +-0.2794494628906250, 0.0001220703125000, -0.2683105468750000, 0.0002136230468750, +-0.2311401367187500, 0.0002136230468750, -0.2484741210937500, 0.0000305175781250, +-0.2179565429687500, 0.0001525878906250, -0.2250976562500000, 0.0000610351562500, +-0.2027282714843750, -0.0003051757812500, -0.1810302734375000, -0.0001831054687500, +-0.2011413574218750, 0.0003051757812500, -0.0799255371093750, 0.0002136230468750, +-0.1314086914062500, -0.0002746582031250, -0.0322265625000000, 0.0008544921875000, +0.1110534667968750, 0.0006713867187500, 0.0202941894531250, -0.0068664550781250, +0.3103027343750000, -0.0013732910156250, 0.2864685058593750, -0.0120849609375000, +0.3398742675781250, -0.0256042480468750, 0.5391845703125000, -0.0154113769531250, +0.4531250000000000, -0.0388488769531250, 0.5622863769531250, -0.0452575683593750, +0.5970153808593750, -0.0281066894531250, 0.5563354492187500, -0.0338439941406250, +0.5709838867187500, -0.0423278808593750, 0.5849304199218750, 0.0362243652343750, +0.5076599121093750, 0.0096740722656250, 0.5218505859375000, 0.0521240234375000, +0.4951782226562500, 0.1400756835937500, 0.4367370605468750, 0.0914306640625000, +0.4662780761718750, 0.1457824707031250, 0.3798828125000000, 0.1837158203125000, +0.3994445800781250, 0.1176452636718750, 0.3539123535156250, 0.0922546386718750, +0.2763366699218750, 0.1366271972656250, 0.3257446289062500, -0.0412902832031250, +0.1857299804687500, -0.0234680175781250, 0.1957702636718750, -0.0350341796875000, +0.1704101562500000, -0.1615905761718750, 0.0759277343750000, -0.1224060058593750, +0.1155090332031250, -0.0582275390625000, 0.0541992187500000, -0.1199035644531250, +0.0531616210937500, -0.0327453613281250, 0.0329284667968750, 0.1027221679687500, +0.0014953613281250, 0.0214233398437500, 0.0258789062500000, 0.1159973144531250, +-0.0943908691406250, 0.1781616210937500, -0.0642700195312500, 0.0833435058593750, +-0.1022949218750000, -0.0317382812500000, -0.2817077636718750, -0.3423767089843750, +0.0069885253906250, -0.2142028808593750, -0.1273193359375000, -0.3583679199218750, +-0.0548400878906250, -0.1980590820312500, -0.1316223144531250, 0.0033874511718750, +-0.2510681152343750, -0.1211853027343750, -0.1907958984375000, 0.0964965820312500, +-0.2532653808593750, 0.1308288574218750, -0.3025207519531250, 0.0950317382812500, +-0.2212524414062500, 0.1651916503906250, -0.1772460937500000, 0.1624755859375000, +-0.2317810058593750, 0.1142883300781250, -0.0575256347656250, 0.1197204589843750, +-0.0595703125000000, 0.1320800781250000, -0.0625305175781250, 0.1062927246093750, +0.0297241210937500, 0.1024780273437500, 0.0087280273437500, 0.1645507812500000, +-0.0062866210937500, 0.1476440429687500, 0.0014953613281250, 0.1638183593750000, +0.0122070312500000, 0.2166442871093750, -0.0020141601562500, 0.1958312988281250, +-0.0093688964843750, 0.2255859375000000, 0.0707397460937500, 0.2176818847656250, +0.0507507324218750, 0.2539367675781250, 0.0708923339843750, 0.2793579101562500, +0.1476440429687500, 0.2468566894531250, 0.1194152832031250, 0.4160156250000000, +0.1047668457031250, 0.3613891601562500, 0.1408386230468750, 0.4422607421875000, +0.0877685546875000, 0.6155090332031250, 0.0233764648437500, 0.5154113769531250, +0.0667114257812500, 0.6648254394531250, -0.0222473144531250, 0.7167968750000000, +-0.0354309082031250, 0.6207580566406250, -0.0196228027343750, 0.6337280273437500, +-0.0477905273437500, 0.6828002929687500, -0.0476379394531250, 0.3718261718750000, +-0.0199584960937500, 0.4620666503906250, -0.0250549316406250, 0.3326110839843750, +-0.0198364257812500, 0.0450439453125000, 0.0007629394531250, 0.2060852050781250, +-0.0061950683593750, -0.0831298828125000, -0.0006713867187500, -0.1039428710937500, +0.0024414062500000, -0.0856018066406250, 0.0003967285156250, -0.2138366699218750, +-0.0002746582031250, -0.1824340820312500, 0.0002441406250000, -0.1866149902343750, +0.0000610351562500, -0.1996459960937500, -0.0003051757812500, -0.2030944824218750, +-0.0000915527343750, -0.1923217773437500, 0.0003356933593750, -0.1902465820312500, +0.0001525878906250, -0.2573242187500000, 0.0001220703125000, -0.2225036621093750, +0.0001831054687500, -0.2735595703125000, 0.0002441406250000, -0.3555603027343750, +0.0001220703125000, -0.3004455566406250, 0.0001220703125000, -0.4284362792968750, +0.0001220703125000, -0.4248046875000000, 0.0001831054687500, -0.4283752441406250, +0.0000915527343750, -0.5027465820312500, 0.0000000000000000, -0.4754943847656250, +0.0000305175781250, -0.4732360839843750, 0.0000000000000000, -0.5027770996093750, +0.0000000000000000, -0.4547729492187500, -0.0000305175781250, -0.4167175292968750, +0.0000610351562500, -0.4572143554687500, 0.0000610351562500, -0.3266906738281250, +-0.0000305175781250, -0.3574218750000000, 0.0000000000000000, -0.3123779296875000, +0.0000000000000000, -0.2070922851562500, -0.0001220703125000, -0.2728576660156250, +-0.0000915527343750, -0.1407775878906250, 0.0000000000000000, -0.1525268554687500, +-0.0000305175781250, -0.1317749023437500, -0.0000305175781250, -0.0472412109375000, +0.0000000000000000, -0.0916137695312500, 0.0000610351562500, -0.0141296386718750, +-0.0000610351562500, -0.0156860351562500, -0.0000915527343750, -0.0098266601562500, +-0.0000305175781250, 0.0339965820312500, -0.0000305175781250, 0.0138549804687500, +-0.0000915527343750, 0.0455932617187500, 0.0000000000000000, 0.0496520996093750, +0.0000000000000000, 0.0501708984375000, -0.0000305175781250, 0.0661010742187500, +-0.0000915527343750, 0.0631103515625000, -0.0000305175781250, 0.0682373046875000, +-0.0000915527343750, 0.0725097656250000, -0.0000915527343750, 0.0710144042968750, +-0.0000915527343750, 0.0721130371093750, -0.0000610351562500, 0.0763244628906250, +-0.0000610351562500, 0.0698852539062500, -0.0000610351562500, 0.0749206542968750, +0.0000000000000000, 0.0720520019531250, -0.0000305175781250, 0.0668334960937500, +-0.0000610351562500, 0.0753784179687500, -0.0000610351562500, 0.0594787597656250, +-0.0000610351562500, 0.0650329589843750, -0.0000915527343750, 0.0613403320312500, +-0.0000610351562500, 0.0491027832031250, -0.0000610351562500, 0.0589599609375000, +-0.0000610351562500, 0.0437927246093750, -0.0000610351562500, 0.0481872558593750, +-0.0000610351562500, 0.0465393066406250, -0.0000915527343750, 0.0369873046875000, +-0.0000915527343750, 0.0471801757812500, -0.0000915527343750, 0.0386657714843750, +-0.0000915527343750, 0.0389404296875000, -0.0001220703125000, 0.0442504882812500, +-0.0000915527343750, 0.0436706542968750, -0.0001220703125000, 0.0456237792968750, +-0.0001220703125000, 0.0535888671875000, -0.0000915527343750, 0.0516052246093750, +-0.0000915527343750, 0.0535583496093750, -0.0000915527343750, 0.0610961914062500, +-0.0000915527343750, 0.0602111816406250, -0.0000915527343750, 0.0621337890625000, +-0.0001220703125000, 0.0640563964843750, -0.0000915527343750, 0.0615234375000000, +-0.0000915527343750, 0.0596313476562500, -0.0000915527343750, 0.0615234375000000, +-0.0001220703125000, 0.0565795898437500, -0.0001220703125000, 0.0543212890625000, +-0.0001220703125000, 0.0601806640625000, -0.0000915527343750, 0.0604248046875000, +-0.0000305175781250, 0.0572509765625000, -0.0000610351562500, 0.0820312500000000, +-0.0000305175781250, 0.0736694335937500, -0.0000305175781250, 0.0930175781250000, +-0.0000915527343750, 0.1223754882812500, -0.0000915527343750, 0.1064453125000000, +-0.0000915527343750, 0.1537475585937500, 0.0000000000000000, 0.1557312011718750, +-0.0000915527343750, 0.1600036621093750, -0.0000610351562500, 0.1896667480468750, +0.0000000000000000, 0.1808471679687500, -0.0000305175781250, 0.1708679199218750, +-0.0000610351562500, 0.1871337890625000, -0.0000915527343750, 0.1605529785156250, +-0.0000610351562500, 0.1309814453125000, -0.0000610351562500, 0.1508483886718750, +-0.0000915527343750, 0.0827026367187500, -0.0001525878906250, 0.0852661132812500, +-0.0000915527343750, 0.0721130371093750, -0.0002136230468750, 0.0249328613281250, +-0.0004272460937500, 0.0406494140625000, -0.0002746582031250, 0.0187377929687500, +-0.0001220703125000, 0.0088500976562500, -0.0003967285156250, 0.0171203613281250, +-0.0000610351562500, 0.0170288085937500, 0.0010070800781250, 0.0115661621093750, +0.0003051757812500, 0.0204162597656250, -0.0023193359375000, 0.0199584960937500, +0.0014648437500000, 0.0207824707031250, -0.0062866210937500, 0.0205688476562500, +-0.0134277343750000, 0.0188903808593750, -0.0061035156250000, 0.0507507324218750, +-0.0265502929687500, 0.0260314941406250, -0.0281066894531250, 0.0775756835937500, +-0.0195312500000000, 0.1335449218750000, -0.0299377441406250, 0.0887451171875000, +-0.0323486328125000, 0.2380065917968750, 0.0161437988281250, 0.2300415039062500, +-0.0045166015625000, 0.2433471679687500, 0.0224609375000000, 0.3482666015625000, +0.0805053710937500, 0.3152770996093750, 0.0491027832031250, 0.2698669433593750, +0.0827941894531250, 0.3302307128906250, 0.1049194335937500, 0.2355041503906250, +0.0698852539062500, 0.1200866699218750, 0.0548706054687500, 0.2005004882812500, +0.0810241699218750, -0.0023193359375000, 0.0118408203125000, -0.0112609863281250, +0.0109252929687500, -0.0037841796875000, 0.0148620605468750, -0.1008605957031250, +-0.0170593261718750, -0.0772094726562500, -0.0115356445312500, -0.0573730468750000, +-0.0134582519531250, -0.0737304687500000, -0.0079650878906250, -0.0675354003906250, +-0.0268249511718750, -0.0359802246093750, -0.0470886230468750, -0.0419616699218750, +-0.0437927246093750, -0.0824890136718750, -0.0986022949218750, -0.0653686523437500, +-0.0870666503906250, -0.0669250488281250, -0.0801391601562500, -0.1013793945312500, +-0.1169128417968750, -0.0892333984375000, -0.1110839843750000, -0.0779113769531250, +-0.0742492675781250, -0.0912475585937500, -0.0872497558593750, -0.0783081054687500, +-0.0737609863281250, -0.0552062988281250, -0.0346374511718750, -0.0673217773437500, +-0.0484313964843750, -0.0525207519531250, -0.0450134277343750, -0.0541687011718750, +-0.0387268066406250, -0.0389709472656250, -0.0324707031250000, -0.0299377441406250, +-0.0419006347656250, -0.0439453125000000, -0.0446777343750000, 0.0355834960937500, +0.0336303710937500, 0.0147399902343750, -0.0007324218750000, 0.0432128906250000, +0.0586547851562500, 0.1211547851562500, 0.1578674316406250, 0.0833129882812500, +0.1013488769531250, 0.1057434082031250, 0.2203063964843750, 0.1373901367187500, +0.2330627441406250, 0.0912780761718750, 0.2192993164062500, 0.0570983886718750, +0.2681274414062500, 0.0914001464843750, 0.2614135742187500, 0.0000000000000000, +0.2260437011718750, -0.0014038085937500, 0.2477111816406250, 0.0005187988281250, +0.2149963378906250, -0.0468750000000000, 0.1686706542968750, -0.0353393554687500, +0.1976318359375000}, +{0.0000000000000000, 0.0369262695312500, -0.0000610351562500, 0.0490722656250000, +0.0000305175781250, 0.0450134277343750, 0.0000305175781250, 0.0558166503906250, +0.0000305175781250, 0.0690917968750000, 0.0000000000000000, 0.0603637695312500, +-0.0000610351562500, 0.0989074707031250, -0.0000305175781250, 0.0932312011718750, +0.0000000000000000, 0.1056823730468750, -0.0001220703125000, 0.1376647949218750, +-0.0002441406250000, 0.1232910156250000, -0.0001220703125000, 0.1465759277343750, +-0.0001220703125000, 0.1544189453125000, -0.0003967285156250, 0.1427612304687500, +0.0000000000000000, 0.1452636718750000, 0.0007324218750000, 0.1503906250000000, +0.0001525878906250, 0.1152038574218750, -0.0011291503906250, 0.1216430664062500, +0.0015563964843750, 0.1098327636718750, -0.0044555664062500, 0.0790710449218750, +-0.0090637207031250, 0.0921630859375000, -0.0035400390625000, 0.0755004882812500, +-0.0217590332031250, 0.0676269531250000, -0.0209655761718750, 0.0766906738281250, +-0.0174560546875000, 0.0785217285156250, -0.0301208496093750, 0.0723876953125000, +-0.0286865234375000, 0.0840759277343750, 0.0040283203125000, 0.0847778320312500, +-0.0151367187500000, 0.0825195312500000, 0.0127258300781250, 0.0834960937500000, +0.0593872070312500, 0.0837707519531250, 0.0292053222656250, 0.0972900390625000, +0.0766601562500000, 0.0802612304687500, 0.0917663574218750, 0.1161804199218750, +0.0647888183593750, 0.1502685546875000, 0.0672302246093750, 0.1206665039062500, +0.0821228027343750, 0.2293701171875000, 0.0167846679687500, 0.2218322753906250, +0.0240478515625000, 0.2250976562500000, 0.0211486816406250, 0.3021545410156250, +-0.0190429687500000, 0.2815856933593750, -0.0068054199218750, 0.2173767089843750, +-0.0118103027343750, 0.2718811035156250, -0.0123596191406250, 0.1858520507812500, +-0.0252685546875000, 0.0679626464843750, -0.0306091308593750, 0.1464233398437500, +-0.0183715820312500, -0.0266113281250000, -0.0733642578125000, -0.0384521484375000, +-0.0673217773437500, -0.0198669433593750, -0.0674743652343750, -0.0928955078125000, +-0.1087646484375000, -0.0795593261718750, -0.1021423339843750, -0.0406799316406250, +-0.0631103515625000, -0.0505371093750000, -0.0832824707031250, -0.0603332519531250, +-0.0724182128906250, -0.0384826660156250, -0.0304565429687500, -0.0354614257812500, +-0.0467529296875000, -0.0729980468750000, -0.0377502441406250, -0.0651855468750000, +-0.0268554687500000, -0.0642700195312500, -0.0317993164062500, -0.0917968750000000, +-0.0463867187500000, -0.0867004394531250, -0.0406188964843750, -0.0657653808593750, +0.0065612792968750, -0.0757141113281250, -0.0270996093750000, -0.0684509277343750, +0.0331420898437500, -0.0459899902343750, 0.1149291992187500, -0.0538635253906250, +0.0632629394531250, -0.0454711914062500, 0.1949768066406250, -0.0495605468750000, +0.2001953125000000, -0.0305786132812500, 0.1988525390625000, -0.0198974609375000, +0.2656860351562500, -0.0368347167968750, 0.2473754882812500, 0.0437927246093750, +0.2350158691406250, 0.0275878906250000, 0.2571716308593750, 0.0451965332031250, +0.2250976562500000, 0.1144714355468750, 0.1912231445312500, 0.0865478515625000, +0.2174377441406250, 0.0900573730468750, 0.1311950683593750, 0.1199340820312500, +0.1447143554687500, 0.0784912109375000, 0.1222229003906250, 0.0366821289062500, +0.0527648925781250, 0.0692749023437500, 0.0848083496093750, -0.0084533691406250, +0.0468444824218750, -0.0125427246093750, 0.0272521972656250, -0.0056762695312500, +0.0568542480468750, -0.0402832031250000, 0.0642700195312500, -0.0337524414062500, +0.0471801757812500, -0.0189514160156250, 0.1167602539062500, -0.0275268554687500, +0.1116333007812500, -0.0198364257812500, 0.1166381835937500, -0.0018310546875000, +0.1622314453125000, -0.0100708007812500, 0.1472167968750000, -0.0012817382812500, +0.1371459960937500, 0.0017700195312500, 0.1538696289062500, -0.0006408691406250, +0.1271057128906250, 0.0002746582031250, 0.0943603515625000, 0.0007629394531250, +0.1152954101562500, -0.0002136230468750, 0.0707092285156250, -0.0005798339843750, +0.0626525878906250, -0.0001525878906250, 0.0688476562500000, -0.0000610351562500, +0.0534362792968750, -0.0003051757812500, 0.0531921386718750, -0.0000305175781250, +0.0702209472656250, 0.0000610351562500, 0.0664672851562500, -0.0000305175781250, +0.0697021484375000, -0.0000610351562500, 0.0854797363281250, 0.0000000000000000, +0.0791931152343750, -0.0000305175781250, 0.0645446777343750, -0.0000915527343750, +0.0755004882812500, 0.0000000000000000, 0.0490722656250000, 0.0000305175781250, +0.0198059082031250, 0.0000000000000000, 0.0368041992187500, -0.0000305175781250, +-0.0291137695312500, 0.0000000000000000, -0.0254821777343750, 0.0000305175781250, +-0.0439147949218750, -0.0000305175781250, -0.0939025878906250, -0.0000610351562500, +-0.0775451660156250, 0.0000305175781250, -0.1157531738281250, 0.0000000000000000, +-0.1236572265625000, 0.0000305175781250, -0.1199645996093750, 0.0000915527343750, +-0.1342468261718750, 0.0001220703125000, -0.1338195800781250, 0.0000000000000000, +-0.1206359863281250, 0.0000000000000000, -0.1268310546875000, 0.0000305175781250, +-0.1127624511718750, -0.0000305175781250, -0.0939331054687500, -0.0000305175781250, +-0.1045532226562500, 0.0000000000000000, -0.0717163085937500, 0.0000000000000000, +-0.0718078613281250, 0.0000000000000000, -0.0632019042968750, 0.0000305175781250, +-0.0400695800781250, 0.0000305175781250, -0.0469665527343750, 0.0000000000000000, +-0.0257873535156250, 0.0000000000000000, -0.0241394042968750, 0.0000000000000000, +-0.0189514160156250, 0.0000305175781250, -0.0057373046875000, 0.0000000000000000, +-0.0097351074218750, 0.0000305175781250, 0.0046997070312500, 0.0000305175781250, +0.0057678222656250, 0.0000610351562500, 0.0079650878906250, 0.0000610351562500, +0.0166625976562500, 0.0000610351562500, 0.0157165527343750, 0.0000305175781250, +0.0226745605468750, 0.0000305175781250, 0.0238037109375000, 0.0000305175781250, +0.0245971679687500, 0.0000305175781250, 0.0289001464843750, -0.0000305175781250, +0.0283508300781250, 0.0000000000000000, 0.0262145996093750, 0.0000305175781250, +0.0312500000000000, 0.0000305175781250, 0.0249938964843750, 0.0000000000000000, +0.0199890136718750, 0.0000610351562500, 0.0263977050781250, 0.0000000000000000, +-0.0016784667968750, 0.0000000000000000, 0.0096740722656250, 0.0000000000000000, +-0.0069274902343750, 0.0000305175781250, -0.0338745117187500, 0.0000305175781250, +-0.0123291015625000, 0.0000610351562500, -0.0655822753906250, 0.0000305175781250, +-0.0538940429687500, 0.0000305175781250, -0.0700073242187500, 0.0000000000000000, +-0.1117553710937500, 0.0000305175781250, -0.0840454101562500, 0.0000305175781250, +-0.1301574707031250, 0.0000305175781250, -0.1304931640625000, 0.0000305175781250, +-0.1279296875000000, 0.0000610351562500, -0.1510620117187500, 0.0000305175781250, +-0.1426696777343750, 0.0000000000000000, -0.1405944824218750, 0.0000915527343750, +-0.1504211425781250, 0.0000610351562500, -0.1347045898437500, -0.0000305175781250, +-0.1197814941406250, 0.0000000000000000, -0.1324462890625000, -0.0000305175781250, +-0.0951232910156250, -0.0000610351562500, -0.0993041992187500, 0.0000305175781250, +-0.0992736816406250, 0.0000610351562500, -0.0724792480468750, 0.0000305175781250, +-0.0805664062500000, 0.0000305175781250, -0.1023254394531250, 0.0001220703125000, +-0.0798034667968750, -0.0000305175781250, -0.1219177246093750, -0.0001525878906250, +-0.1642456054687500, -0.0000305175781250, -0.1275329589843750, -0.0000305175781250, +-0.2518615722656250, -0.0002441406250000, -0.2317504882812500, -0.0000305175781250, +-0.2704772949218750, 0.0006713867187500, -0.3747558593750000, 0.0002441406250000, +-0.3290710449218750, -0.0025939941406250, -0.4073486328125000, 0.0009460449218750, +-0.4318542480468750, -0.0067749023437500, -0.3963623046875000, -0.0141296386718750, +-0.4084167480468750, -0.0072631835937500, -0.4237976074218750, -0.0277099609375000, +-0.3128967285156250, -0.0290222167968750, -0.3412475585937500, -0.0215454101562500, +-0.3015747070312500, -0.0329284667968750, -0.1976928710937500, -0.0338745117187500, +-0.2448425292968750, 0.0151977539062500, -0.1879272460937500, -0.0070495605468750, +-0.1679077148437500, 0.0283203125000000, -0.1882019042968750, 0.0923767089843750, +-0.1909790039062500, 0.0556030273437500, -0.1821289062500000, 0.1084594726562500, +-0.1705627441406250, 0.1352539062500000, -0.2109375000000000, 0.0873413085937500, +-0.1275024414062500, 0.0763549804687500, -0.0643615722656250, 0.1063537597656250, +-0.1311340332031250, -0.0251159667968750, 0.1464843750000000, -0.0114135742187500, +0.0954589843750000, -0.0223388671875000, 0.1861267089843750, -0.1175537109375000, +0.4192810058593750, -0.0869750976562500, 0.3058776855468750, -0.0408630371093750, +0.4848327636718750, -0.0887451171875000, 0.5204162597656250, -0.0285949707031250, +0.4790344238281250, 0.0697937011718750, 0.5299987792968750, 0.0109252929687500, +0.5332946777343750, 0.0736999511718750, 0.4500122070312500, 0.1278991699218750, +0.4716491699218750, 0.0307006835937500, 0.4407043457031250, -0.0204162597656250, +0.3677978515625000, 0.0466003417968750, 0.4006347656250000, -0.1944580078125000, +0.3315734863281250, -0.1852416992187500, 0.3373718261718750, -0.1872253417968750, +0.3078002929687500, -0.3369750976562500, 0.2595825195312500, -0.2964782714843750, +0.2931823730468750, -0.1948852539062500, 0.1766357421875000, -0.2647399902343750, +0.1939392089843750, -0.1902770996093750, 0.1752929687500000, 0.0545349121093750, +0.0383605957031250, 0.1257324218750000, 0.2663269042968750, 0.0963134765625000, +0.1318664550781250, 0.0927124023437500, 0.1929931640625000, 0.1187744140625000, +0.1350708007812500, 0.1233215332031250, 0.0391845703125000, 0.1035156250000000, +0.0834655761718750, 0.1723937988281250, 0.0138854980468750, 0.1701965332031250, +0.0099182128906250, 0.1705932617187500, -0.0056152343750000, 0.2062988281250000, +-0.0386047363281250, 0.1976928710937500, -0.0171813964843750, 0.2061462402343750, +-0.1169128417968750, 0.1908569335937500, -0.0934448242187500, 0.2391052246093750, +-0.1242980957031250, 0.2647705078125000, -0.2197265625000000, 0.2261047363281250, +-0.1766662597656250, 0.4245605468750000, -0.1898193359375000, 0.3746337890625000, +-0.2346496582031250, 0.4427185058593750, -0.1673583984375000, 0.6289978027343750, +-0.1045837402343750, 0.5332336425781250, -0.1559448242187500, 0.6039428710937500, +-0.0321960449218750, 0.6885375976562500, -0.0219116210937500, 0.5475769042968750, +-0.0353698730468750, 0.4686584472656250, 0.0127258300781250, 0.5737304687500000, +0.0073852539062500, 0.2088623046875000, -0.0064392089843750, 0.2745666503906250, +-0.0117187500000000, 0.1831054687500000, 0.0120849609375000, -0.1010131835937500, +0.0189514160156250, 0.0356445312500000, 0.0005187988281250, -0.1720581054687500, +0.0778198242187500, -0.2084350585937500, 0.0749206542968750, -0.1780090332031250, +0.0695495605468750, -0.2444458007812500, 0.1152648925781250, -0.2377319335937500, +0.1079406738281250, -0.2222290039062500, 0.0576782226562500, -0.2183227539062500, +0.0805358886718750, -0.2465515136718750, 0.0499267578125000, -0.2504272460937500, +-0.0121765136718750, -0.2299499511718750, 0.0172119140625000, -0.3367919921875000, +-0.0253601074218750, -0.3096008300781250, -0.0395507812500000, -0.3443298339843750, +-0.0235595703125000, -0.4404296875000000, -0.0260314941406250, -0.3915405273437500, +-0.0320129394531250, -0.4444580078125000, -0.0090332031250000, -0.4748229980468750, +-0.0086669921875000}, +{-0.3432617187500000, 0.1123657226562500, -0.3796081542968750, 0.0753784179687500, +-0.3294677734375000, 0.0775146484375000, -0.2298889160156250, 0.0982971191406250, +-0.2838439941406250, -0.0132446289062500, -0.2010803222656250, 0.0017700195312500, +-0.1828918457031250, -0.0108947753906250, -0.2046203613281250, -0.0960998535156250, +-0.1926879882812500, -0.0689697265625000, -0.1875610351562500, -0.0372619628906250, +-0.1853027343750000, -0.0783691406250000, -0.2172851562500000, -0.0236511230468750, +-0.1469116210937500, 0.0596618652343750, -0.1000976562500000, 0.0075988769531250, +-0.1545104980468750, 0.0599060058593750, 0.0913696289062500, 0.1074218750000000, +0.0352783203125000, 0.0250244140625000, 0.1284179687500000, -0.0185852050781250, +0.3468933105468750, 0.0400695800781250, 0.2343139648437500, -0.1667785644531250, +0.4345703125000000, -0.1546325683593750, 0.4700927734375000, -0.1546936035156250, +0.4322814941406250, -0.2856445312500000, 0.4963073730468750, -0.2506103515625000, +0.4949951171875000, -0.1640930175781250, 0.4093627929687500, -0.2278137207031250, +0.4348144531250000, -0.1336669921875000, 0.4026489257812500, 0.0112609863281250, +0.3243103027343750, -0.0740966796875000, 0.3597717285156250, 0.0795593261718750, +0.2975158691406250, 0.1078491210937500, 0.2976074218750000, 0.0754394531250000, +0.2865600585937500, 0.1261901855468750, 0.2199707031250000, 0.0883483886718750, +0.3411865234375000, 0.1689453125000000, 0.2638549804687500, 0.1455688476562500, +0.2892456054687500, 0.1549072265625000, 0.2516784667968750, 0.1893310546875000, +0.2135925292968750, 0.1836853027343750, 0.2423095703125000, 0.1975708007812500, +0.1296997070312500, 0.1785888671875000, 0.1506958007812500, 0.2298583984375000, +0.1173400878906250, 0.2636413574218750, 0.0234985351562500, 0.2205810546875000, +0.0655212402343750, 0.4176330566406250, -0.0009765625000000, 0.3784790039062500, +-0.0043945312500000, 0.4298095703125000, -0.0190429687500000, 0.6021728515625000, +-0.0512695312500000, 0.5237426757812500, -0.0297546386718750, 0.5477600097656250, +-0.1208496093750000, 0.6345520019531250, -0.1052551269531250, 0.4901733398437500, +-0.1244506835937500, 0.3834838867187500, -0.2031250000000000, 0.4978942871093750, +-0.1715698242187500, 0.1206054687500000, -0.1596679687500000, 0.1716308593750000, +-0.1997985839843750, 0.0929260253906250, -0.1412963867187500, -0.1816406250000000, +-0.0716857910156250, -0.0558471679687500, -0.1185302734375000, -0.2279968261718750, +-0.0196228027343750, -0.2613830566406250, -0.0046691894531250, -0.2299194335937500, +-0.0214233398437500, -0.2793579101562500, 0.0065307617187500, -0.2747802734375000, +0.0073852539062500, -0.2540283203125000, -0.0018005371093750, -0.2518310546875000, +-0.0130310058593750, -0.2684326171875000, 0.0147705078125000, -0.2640380859375000, +0.0332336425781250, -0.2544250488281250, 0.0102539062500000, -0.3291015625000000, +0.0753173828125000, -0.3080139160156250, 0.0811157226562500, -0.3372192382812500, +0.0671997070312500, -0.4090881347656250, 0.0941772460937500, -0.3716735839843750, +0.0957946777343750, -0.4129638671875000, 0.0386047363281250, -0.4364013671875000, +0.0552062988281250, -0.4016723632812500, 0.0335388183593750, -0.3952331542968750, +-0.0237121582031250, -0.4178161621093750, -0.0006103515625000, -0.3207397460937500, +-0.0234985351562500, -0.3453674316406250, -0.0366821289062500, -0.3099975585937500, +-0.0223083496093750, -0.2267761230468750, -0.0161437988281250, -0.2731323242187500, +-0.0234985351562500, -0.1826477050781250, -0.0051574707031250, -0.1824645996093750, +-0.0032043457031250, -0.1752624511718750, -0.0050048828125000, -0.1245727539062500, +0.0015258789062500, -0.1437072753906250, 0.0005187988281250, -0.1087646484375000, +-0.0002441406250000, -0.1093444824218750, -0.0000305175781250, -0.0983581542968750, +0.0000915527343750, -0.0778808593750000, -0.0001831054687500, -0.0915832519531250, +-0.0002441406250000, -0.0375671386718750, -0.0000305175781250, -0.0528564453125000, +0.0000915527343750, -0.0240783691406250, 0.0000000000000000, 0.0279541015625000, +-0.0000610351562500, -0.0061645507812500, 0.0000305175781250, 0.0651245117187500, +0.0000000000000000, 0.0643920898437500, -0.0000305175781250, 0.0612792968750000, +-0.0000305175781250, 0.1001892089843750, 0.0000305175781250, 0.0894775390625000, +0.0000000000000000, 0.0772399902343750, 0.0000000000000000, 0.0951232910156250, +0.0000000000000000, 0.0704345703125000, 0.0000305175781250, 0.0432434082031250, +0.0000915527343750, 0.0684814453125000, 0.0000305175781250, 0.0053710937500000, +0.0000610351562500, 0.0161743164062500, 0.0000915527343750, 0.0036010742187500, +0.0000915527343750, -0.0402526855468750, 0.0000305175781250, -0.0157470703125000, +0.0000610351562500, -0.0612182617187500, 0.0000610351562500, -0.0583801269531250, +0.0000610351562500, -0.0632324218750000, 0.0000915527343750, -0.0907592773437500, +0.0000305175781250, -0.0773315429687500, 0.0000610351562500, -0.0988769531250000, +0.0000305175781250, -0.0990295410156250, 0.0000305175781250, -0.1008300781250000, +0.0000305175781250, -0.1133117675781250, 0.0000000000000000, -0.1091918945312500, +-0.0000305175781250, -0.1200866699218750, 0.0000000000000000, -0.1206665039062500, +0.0000305175781250, -0.1221008300781250, 0.0000610351562500, -0.1282653808593750, +0.0000610351562500, -0.1266784667968750, 0.0000305175781250, -0.1330261230468750, +0.0000305175781250, -0.1328430175781250, 0.0000610351562500, -0.1356201171875000, +0.0000610351562500, -0.1410217285156250, 0.0000610351562500, -0.1398925781250000, +0.0000610351562500, -0.1479797363281250, 0.0000610351562500, -0.1490173339843750, +0.0001220703125000, -0.1525268554687500, 0.0000610351562500, -0.1585693359375000, +0.0000610351562500, -0.1566467285156250, 0.0000610351562500, -0.1614379882812500, +0.0000305175781250, -0.1617431640625000, 0.0000610351562500, -0.1607360839843750, +0.0000610351562500, -0.1626281738281250, 0.0000610351562500, -0.1616821289062500, +0.0000305175781250, -0.1559753417968750, 0.0000915527343750, -0.1572570800781250, +0.0000915527343750, -0.1509399414062500, 0.0001220703125000, -0.1435852050781250, +0.0000915527343750, -0.1466064453125000, 0.0001220703125000, -0.1300048828125000, +0.0000915527343750, -0.1304626464843750, 0.0000915527343750, -0.1247558593750000, +0.0000915527343750, -0.1112060546875000, 0.0001220703125000, -0.1147155761718750, +0.0000915527343750, -0.1048889160156250, 0.0000915527343750, -0.1013488769531250, +0.0001220703125000, -0.1065673828125000, 0.0000915527343750, -0.1048889160156250, +0.0000915527343750, -0.1015014648437500, 0.0000915527343750, -0.1223449707031250, +0.0001220703125000, -0.1168823242187500, 0.0001220703125000, -0.1269836425781250, +0.0000305175781250, -0.1480712890625000, -0.0000610351562500, -0.1375732421875000, +0.0000915527343750, -0.1551208496093750, -0.0000610351562500, -0.1607360839843750, +-0.0001220703125000, -0.1495971679687500, 0.0001525878906250, -0.1507568359375000, +0.0003356933593750, -0.1548767089843750, 0.0000000000000000, -0.1171875000000000, +0.0001525878906250, -0.1263732910156250, 0.0012512207031250, -0.1064758300781250, +-0.0018920898437500, -0.0705566406250000, -0.0032043457031250, -0.0887451171875000, +-0.0006713867187500, -0.0382385253906250, -0.0132446289062500, -0.0402526855468750, +-0.0104370117187500, -0.0257873535156250, -0.0123291015625000, 0.0091552734375000, +-0.0245056152343750, -0.0062561035156250, -0.0197753906250000, 0.0375366210937500, +-0.0086364746093750, 0.0349731445312500, -0.0223999023437500, 0.0466003417968750, +0.0002136230468750, 0.0774536132812500, 0.0262451171875000, 0.0627746582031250, +0.0039672851562500, 0.0934753417968750, 0.0549621582031250, 0.0957641601562500, +0.0578002929687500, 0.0942077636718750, 0.0476684570312500, 0.1090393066406250, +0.0708923339843750, 0.1052856445312500, 0.0706176757812500, 0.0979919433593750, +0.0310668945312500, 0.1029663085937500, 0.0462036132812500, 0.0972595214843750, +0.0307922363281250, 0.0847473144531250, -0.0103759765625000, 0.0905761718750000, +0.0089416503906250, 0.0931396484375000, -0.0097045898437500, 0.0830078125000000, +-0.0174255371093750, 0.1014099121093750, -0.0151977539062500, 0.1189270019531250, +-0.0139465332031250, 0.1049804687500000, -0.0136718750000000, 0.1500244140625000, +-0.0403747558593750, 0.1457214355468750, -0.0281372070312500, 0.1537780761718750, +-0.0410766601562500, 0.1824951171875000, -0.0745239257812500, 0.1703491210937500, +-0.0573425292968750, 0.2020568847656250, -0.0599365234375000, 0.1942138671875000, +-0.0776672363281250, 0.2144470214843750, -0.0565185546875000, 0.2474670410156250, +-0.0302734375000000, 0.2252807617187500, -0.0484619140625000, 0.2733764648437500, +-0.0303955078125000, 0.2850036621093750, -0.0172729492187500, 0.2529602050781250, +-0.0328674316406250, 0.2585144042968750, -0.0526123046875000, 0.2462158203125000, +-0.0466613769531250, 0.0684204101562500, -0.0292358398437500, 0.1464538574218750, +-0.0551147460937500, 0.1062316894531250, -0.0160827636718750, -0.0535278320312500, +0.0241088867187500, 0.0291442871093750, -0.0100708007812500, -0.0682067871093750, +0.1240234375000000, -0.1026306152343750, 0.1127014160156250, -0.0629577636718750, +0.1370544433593750, -0.0669860839843750, 0.2310485839843750, -0.0849304199218750, +0.1945190429687500, -0.0385742187500000, 0.2320251464843750, -0.0288085937500000, +0.2531738281250000, -0.0483398437500000, 0.2270202636718750, -0.0432739257812500, +0.2207946777343750, -0.0320129394531250, 0.2334899902343750, -0.0672302246093750, +0.1691284179687500, -0.0715637207031250, 0.1816406250000000, -0.0589294433593750, +0.1570434570312500, -0.0677185058593750, 0.0993652343750000, -0.0740966796875000, +0.1275024414062500, -0.0441589355468750, 0.0859375000000000, -0.0467529296875000, +0.0708007812500000, -0.0468444824218750, 0.0918579101562500, -0.0308837890625000, +0.0915527343750000, -0.0340881347656250, 0.0795593261718750, -0.0278930664062500, +0.1189880371093750, -0.0366821289062500, 0.1218566894531250, -0.0149841308593750, +0.1084594726562500, 0.0030212402343750, 0.1235351562500000, -0.0159301757812500, +0.1271362304687500, 0.0528564453125000, 0.0717163085937500, 0.0469665527343750, +0.0859375000000000, 0.0483703613281250, 0.0659179687500000, 0.0941467285156250, +0.0138854980468750, 0.0812377929687500, 0.0375366210937500, 0.0566406250000000, +0.0133972167968750, 0.0796203613281250, -0.0003662109375000, 0.0501098632812500, +0.0132446289062500, 0.0044860839843750, 0.0205383300781250, 0.0331420898437500, +0.0124206542968750, -0.0151062011718750, 0.0186462402343750, -0.0225830078125000, +0.0311279296875000, -0.0122070312500000, 0.0037231445312500, -0.0268554687500000, +-0.0134277343750000, -0.0274963378906250, 0.0061340332031250, -0.0109252929687500, +-0.0730590820312500, -0.0151977539062500, -0.0640869140625000, -0.0123596191406250, +-0.0879516601562500, 0.0003967285156250, -0.1522216796875000, -0.0047607421875000, +-0.1270446777343750, -0.0006408691406250, -0.1669921875000000, 0.0011901855468750, +-0.1806335449218750, -0.0001220703125000, -0.1655883789062500, -0.0000305175781250, +-0.1694335937500000, 0.0003051757812500, -0.1741943359375000, 0.0000000000000000, +-0.1383666992187500, -0.0003051757812500, -0.1424255371093750, -0.0000610351562500, +-0.1316223144531250, 0.0001831054687500, -0.1029663085937500, 0.0000305175781250, +-0.1147766113281250, 0.0000915527343750, -0.1011657714843750, 0.0001525878906250, +-0.0946655273437500, 0.0000915527343750, -0.1035156250000000, 0.0000000000000000, +-0.1053466796875000}, +{-0.0296630859375000, 0.0650329589843750, -0.0553283691406250, 0.0690307617187500, +-0.0396423339843750, 0.0751647949218750, -0.0549316406250000, 0.0644531250000000, +-0.0673828125000000, 0.0845642089843750, -0.0496215820312500, 0.1041564941406250, +-0.0374450683593750, 0.0879516601562500, -0.0523071289062500, 0.1435241699218750, +-0.0329589843750000, 0.1368713378906250, -0.0212097167968750, 0.1528625488281250, +-0.0394592285156250, 0.1922912597656250, -0.0506286621093750, 0.1725769042968750, +-0.0357360839843750, 0.2251586914062500, -0.0529479980468750, 0.2176513671875000, +-0.0719299316406250, 0.2324218750000000, -0.0316162109375000, 0.2886962890625000, +0.0007934570312500, 0.2821350097656250, -0.0023498535156250, 0.2781372070312500, +0.1221923828125000, 0.3072814941406250, 0.0791931152343750, 0.2548522949218750, +0.1009826660156250, 0.2221679687500000, 0.2064819335937500, 0.2718200683593750, +0.1648254394531250, 0.0795898437500000, 0.2233581542968750, 0.1170959472656250, +0.2415466308593750, 0.0735473632812500, 0.2218933105468750, -0.0805053710937500, +0.2321472167968750, -0.0085754394531250, 0.2369384765625000, -0.0730895996093750, +0.1878356933593750, -0.1109313964843750, 0.2025756835937500, -0.0701293945312500, +0.1759338378906250, -0.0512084960937500, 0.1244506835937500, -0.0742187500000000, +0.1507873535156250, -0.0356445312500000, 0.0988769531250000, -0.0207519531250000, +0.0890502929687500, -0.0421752929687500, 0.1015625000000000, -0.0469970703125000, +0.0881958007812500, -0.0332336425781250, 0.0849914550781250, -0.0615539550781250, +0.1072998046875000, -0.0692443847656250, 0.1099548339843750, -0.0547180175781250, +0.0953369140625000, -0.0557861328125000, 0.1011352539062500, -0.0644226074218750, +0.1091918945312500, -0.0361022949218750, 0.0513000488281250, -0.0356750488281250, +0.0653381347656250, -0.0373535156250000, 0.0490722656250000, -0.0261535644531250, +-0.0033264160156250, -0.0275573730468750, 0.0177612304687500, -0.0190734863281250, +0.0022583007812500, -0.0289306640625000, -0.0110473632812500, -0.0069885253906250, +0.0001831054687500, 0.0144348144531250, 0.0112609863281250, -0.0055541992187500, +0.0025939941406250, 0.0530395507812500, -0.0039978027343750, 0.0513610839843750, +0.0136413574218750, 0.0462036132812500, -0.0202941894531250, 0.0795593261718750, +-0.0525512695312500, 0.0737609863281250, -0.0263061523437500, 0.0411376953125000, +-0.1130371093750000, 0.0597229003906250, -0.1072082519531250, 0.0383605957031250, +-0.1233825683593750, -0.0032043457031250, -0.1845397949218750, 0.0206298828125000, +-0.1604309082031250, -0.0153198242187500, -0.1808166503906250, -0.0224609375000000, +-0.1963500976562500, -0.0124511718750000, -0.1771545410156250, -0.0210571289062500, +-0.1658935546875000, -0.0234375000000000, -0.1758117675781250, -0.0084533691406250, +-0.1406555175781250, -0.0112915039062500, -0.1387939453125000, -0.0097351074218750, +-0.1391906738281250, 0.0004577636718750, -0.1215820312500000, -0.0034790039062500, +-0.1254882812500000, -0.0006103515625000, -0.1337585449218750, 0.0008850097656250, +-0.1290893554687500, -0.0000915527343750, -0.1373596191406250, -0.0002441406250000, +-0.1509094238281250, 0.0000305175781250, -0.1449584960937500, -0.0001220703125000, +-0.1538085937500000, -0.0003967285156250, -0.1587524414062500, -0.0001525878906250, +-0.1503601074218750, 0.0000915527343750, -0.1477661132812500, -0.0000305175781250, +-0.1511230468750000, 0.0000610351562500, -0.1238403320312500, 0.0001525878906250, +-0.1291198730468750, 0.0000915527343750, -0.1156311035156250, 0.0000915527343750, +-0.0907592773437500, 0.0000915527343750, -0.1015625000000000, 0.0000915527343750, +-0.0659484863281250, 0.0000610351562500, -0.0682067871093750, 0.0000305175781250, +-0.0584411621093750, 0.0000305175781250, -0.0331420898437500, 0.0000610351562500, +-0.0440063476562500, 0.0000305175781250, -0.0172424316406250, 0.0000305175781250, +-0.0178833007812500, 0.0000610351562500, -0.0145874023437500, 0.0000305175781250, +0.0004577636718750, 0.0000610351562500, -0.0079345703125000, 0.0000610351562500, +0.0039367675781250, 0.0000610351562500, 0.0026855468750000, 0.0000610351562500, +0.0032348632812500, 0.0000610351562500, 0.0100402832031250, 0.0000610351562500, +0.0053405761718750, 0.0000305175781250, 0.0096130371093750, 0.0000305175781250, +0.0062866210937500, 0.0000915527343750, 0.0079345703125000, 0.0000610351562500, +0.0123596191406250, 0.0000915527343750, 0.0075073242187500, 0.0001220703125000, +0.0173034667968750, 0.0001525878906250, 0.0146179199218750, 0.0000915527343750, +0.0184631347656250, 0.0001220703125000, 0.0261535644531250, 0.0001220703125000, +0.0212097167968750, 0.0001220703125000, 0.0389709472656250, 0.0001220703125000, +0.0328063964843750, 0.0001220703125000, 0.0412597656250000, 0.0000915527343750, +0.0577697753906250, 0.0000915527343750, 0.0464782714843750, 0.0001220703125000, +0.0722045898437500, 0.0000915527343750, 0.0707092285156250, 0.0000915527343750, +0.0729675292968750, 0.0001220703125000, 0.0888061523437500, 0.0001525878906250, +0.0823974609375000, 0.0000305175781250, 0.0890808105468750, 0.0000610351562500, +0.0915222167968750, 0.0000305175781250, 0.0918884277343750, -0.0000305175781250, +0.0936584472656250, 0.0000000000000000, 0.0925903320312500, 0.0000000000000000, +0.0974121093750000, 0.0000610351562500, 0.0976867675781250, 0.0000305175781250, +0.0979003906250000, 0.0000305175781250, 0.1035156250000000, 0.0000610351562500, +0.1025390625000000, -0.0001220703125000, 0.0858764648437500, -0.0000305175781250, +0.0983276367187500, 0.0000000000000000, 0.0763244628906250, -0.0001831054687500, +0.0484924316406250, -0.0002136230468750, 0.0694274902343750, 0.0000915527343750, +0.0162048339843750, 0.0006408691406250, 0.0184631347656250, -0.0012817382812500, +0.0185546875000000, -0.0014038085937500, -0.0114746093750000, -0.0002441406250000, +-0.0023803710937500, -0.0110473632812500, -0.0017395019531250, -0.0075073242187500, +-0.0042419433593750, -0.0118103027343750, -0.0071716308593750, -0.0249633789062500, +-0.0029296875000000, -0.0187072753906250, -0.0021057128906250, -0.0114746093750000, +-0.0388793945312500, -0.0259094238281250, -0.0192871093750000, 0.0006103515625000, +-0.0541687011718750, 0.0276794433593750, -0.1031494140625000, 0.0040283203125000, +-0.0720520019531250, 0.0628051757812500, -0.1680908203125000, 0.0691833496093750, +-0.1617431640625000, 0.0523681640625000, -0.1794738769531250, 0.0759277343750000, +-0.2456665039062500, 0.0803527832031250, -0.2173767089843750, 0.0116271972656250, +-0.2464904785156250, 0.0325622558593750, -0.2611999511718750, 0.0110778808593750, +-0.2441101074218750, -0.0579528808593750, -0.2362365722656250, -0.0292053222656250, +-0.2442321777343750, -0.0320129394531250, -0.2324829101562500, -0.0634155273437500, +-0.2194213867187500, -0.0211791992187500, -0.2456359863281250, 0.0279541015625000, +-0.2605590820312500, -0.0076293945312500, -0.2413940429687500, 0.0411987304687500, +-0.3144836425781250, 0.0729980468750000, -0.3083496093750000, 0.0145874023437500, +-0.3110046386718750, -0.0093078613281250, -0.3616333007812500, 0.0303039550781250, +-0.3479309082031250, -0.1187744140625000, -0.3169555664062500, -0.1102294921875000, +-0.3464355468750000, -0.1130065917968750, -0.3043518066406250, -0.2093200683593750, +-0.2449340820312500, -0.1834106445312500, -0.2840881347656250, -0.1224365234375000, +-0.2040405273437500, -0.1712036132812500, -0.2019042968750000, -0.1066284179687500, +-0.2010192871093750, -0.0043640136718750, -0.1646423339843750, -0.0649108886718750, +-0.1777038574218750, 0.0481872558593750, -0.1457824707031250, 0.0653381347656250, +-0.1645202636718750, 0.0478210449218750, -0.1182556152343750, 0.0814208984375000, +-0.0766906738281250, 0.0798339843750000, -0.1147460937500000, 0.0761718750000000, +0.0744323730468750, 0.0666503906250000, 0.0220031738281250, 0.0901794433593750, +0.1138000488281250, 0.1075439453125000, 0.2979431152343750, 0.0892333984375000, +0.1912841796875000, 0.1536254882812500, 0.3865661621093750, 0.1532592773437500, +0.4109497070312500, 0.1498107910156250, 0.3739929199218750, 0.1950988769531250, +0.4593811035156250, 0.2201843261718750, 0.1722717285156250, 0.4230651855468750, +0.3914184570312500, 0.3414611816406250, 0.3665771484375000, 0.3936462402343750, +0.3535766601562500, 0.5282592773437500, 0.4115905761718750, 0.4785461425781250, +0.4156188964843750, 0.4349365234375000, 0.3278503417968750, 0.5139160156250000, +0.3482360839843750, 0.3896484375000000, 0.3253784179687500, 0.2583923339843750, +0.2547302246093750, 0.3628540039062500, 0.2818298339843750, 0.0412597656250000, +0.2337646484375000, 0.0708923339843750, 0.2398071289062500, 0.0138549804687500, +0.2103271484375000, -0.2048645019531250, 0.1708374023437500, -0.1098327636718750, +0.2015075683593750, -0.2442932128906250, 0.0938110351562500, -0.2712402343750000, +0.1063842773437500, -0.2510986328125000, 0.0841369628906250, -0.2946472167968750, +0.0068664550781250, -0.2902832031250000, 0.0388793945312500, -0.2696228027343750, +-0.0132446289062500, -0.2772827148437500, -0.0120849609375000, -0.2735900878906250, +-0.0307006835937500, -0.2527465820312500, -0.0650024414062500, -0.2601623535156250, +-0.0419006347656250, -0.2781677246093750, -0.1174316406250000, -0.2581787109375000, +-0.1155700683593750, -0.2932434082031250, -0.1129760742187500, -0.3331604003906250, +-0.1610717773437500, -0.3013916015625000, -0.1509094238281250, -0.3838500976562500, +-0.0983886718750000, -0.3840026855468750, -0.1270141601562500, -0.3779296875000000, +-0.0893554687500000, -0.4232177734375000, -0.0171508789062500, -0.4130859375000000, +-0.0538635253906250, -0.3713684082031250, -0.0052490234375000, -0.4017028808593750, +0.0107116699218750, -0.3554992675781250, -0.0021972656250000, -0.2922363281250000, +-0.0001831054687500, -0.3364868164062500, 0.0032348632812500, -0.2247619628906250, +0.0116882324218750, -0.2347106933593750, -0.0019531250000000, -0.2147521972656250, +0.0206909179687500, -0.1415100097656250, 0.0515747070312500, -0.1756286621093750, +0.0323486328125000, -0.1090087890625000, 0.0630493164062500, -0.1109619140625000, +0.0776977539062500, -0.0993957519531250, 0.0531005859375000, -0.0592346191406250, +0.0462646484375000, -0.0791015625000000, 0.0613403320312500, -0.0291442871093750, +0.0036621093750000, -0.0362243652343750, 0.0058288574218750, -0.0180053710937500, +0.0045471191406250, 0.0217590332031250, -0.0290527343750000, -0.0009765625000000, +-0.0204772949218750, 0.0506286621093750, -0.0146789550781250, 0.0520629882812500, +-0.0219726562500000, 0.0481872558593750, -0.0148620605468750, 0.0744934082031250, +-0.0022888183593750, 0.0691833496093750, -0.0079345703125000, 0.0529479980468750, +-0.0012207031250000, 0.0642395019531250, 0.0010681152343750, 0.0530700683593750, +-0.0005493164062500, 0.0303039550781250, 0.0001220703125000, 0.0429077148437500, +0.0003051757812500, 0.0277709960937500, 0.0000305175781250, 0.0222167968750000, +-0.0002441406250000, 0.0286560058593750, -0.0000610351562500, 0.0289306640625000, +0.0001220703125000, 0.0253295898437500, 0.0000305175781250, 0.0304565429687500, +0.0000305175781250, 0.0344543457031250, 0.0000305175781250, 0.0260925292968750, +0.0000610351562500, 0.0235595703125000, 0.0000610351562500, 0.0303955078125000, +0.0000610351562500, 0.0034484863281250, 0.0000915527343750, 0.0108947753906250, +0.0000610351562500, 0.0009765625000000, 0.0000915527343750, -0.0215759277343750, +0.0001220703125000, -0.0070190429687500, 0.0000610351562500, -0.0355224609375000, +0.0001220703125000}, +{-0.0658874511718750, 0.3717346191406250, 0.1075744628906250, 0.4755859375000000, +0.0102844238281250, 0.3322143554687500, 0.1212158203125000, 0.1960144042968750, +0.2739257812500000, 0.3036193847656250, 0.1895141601562500, 0.0127258300781250, +0.3439331054687500, 0.0324707031250000, 0.3726501464843750, -0.0133666992187500, +0.3319702148437500, -0.2019958496093750, 0.3734741210937500, -0.1208190917968750, +0.3821105957031250, -0.2428894042968750, 0.2944641113281250, -0.2648010253906250, +0.3096618652343750, -0.2501220703125000, 0.2915039062500000, -0.2929382324218750, +0.2285461425781250, -0.2834777832031250, 0.2523498535156250, -0.2642211914062500, +0.2066650390625000, -0.2783508300781250, 0.2148437500000000, -0.2647094726562500, +0.1843872070312500, -0.2356567382812500, 0.1422729492187500, -0.2531127929687500, +0.1733093261718750, -0.2492065429687500, 0.0742187500000000, -0.2260437011718750, +0.0831298828125000, -0.2672119140625000, 0.0666198730468750, -0.2998962402343750, +0.0001831054687500, -0.2659606933593750, 0.0260620117187500, -0.3664855957031250, +-0.0189514160156250, -0.3602905273437500, -0.0160522460937500, -0.3601684570312500, +-0.0366516113281250, -0.4244079589843750, -0.0711975097656250, -0.4055480957031250, +-0.0469970703125000, -0.3643798828125000, -0.1131591796875000, -0.4024963378906250, +-0.1171875000000000, -0.3447265625000000, -0.1033630371093750, -0.2694091796875000, +-0.1338500976562500, -0.3215026855468750, -0.1343994140625000, -0.1886901855468750, +-0.0722351074218750, -0.1943969726562500, -0.0911560058593750, -0.1805419921875000, +-0.0665588378906250, -0.1022033691406250, -0.0041503906250000, -0.1341247558593750, +-0.0308227539062500, -0.0829772949218750, -0.0018615722656250, -0.0831298828125000, +0.0104064941406250, -0.0732116699218750, 0.0024414062500000, -0.0437622070312500, +-0.0003051757812500, -0.0606384277343750, 0.0017700195312500, -0.0111694335937500, +0.0200500488281250, -0.0219726562500000, 0.0082702636718750, -0.0018920898437500, +0.0254211425781250, 0.0386962890625000, 0.0576171875000000, 0.0124511718750000, +0.0411071777343750, 0.0759277343750000, 0.0521850585937500, 0.0732116699218750, +0.0691833496093750, 0.0758361816406250, 0.0437316894531250, 0.1163635253906250, +0.0225219726562500, 0.1037292480468750, 0.0407104492187500, 0.0945434570312500, +-0.0066223144531250, 0.1106262207031250, -0.0105285644531250, 0.0886840820312500, +-0.0050964355468750, 0.0615539550781250, -0.0243530273437500, 0.0816040039062500, +-0.0222778320312500, 0.0417175292968750, -0.0097351074218750, 0.0396728515625000, +-0.0134277343750000, 0.0405883789062500, -0.0103454589843750, 0.0229797363281250, +0.0003356933593750, 0.0288391113281250, -0.0035705566406250, 0.0211791992187500, +-0.0006103515625000, 0.0231628417968750, 0.0010375976562500, 0.0182189941406250, +0.0000915527343750, 0.0113830566406250, -0.0000915527343750, 0.0181274414062500, +0.0000305175781250, -0.0011596679687500, 0.0001220703125000, 0.0007934570312500, +-0.0000305175781250, 0.0009155273437500, 0.0000305175781250, -0.0118103027343750, +0.0001831054687500, -0.0082397460937500, 0.0001831054687500, -0.0024414062500000, +0.0000610351562500, -0.0111694335937500, 0.0000610351562500, -0.0024414062500000, +0.0000610351562500, 0.0086975097656250, 0.0001220703125000, -0.0018615722656250, +0.0000915527343750, 0.0246582031250000, 0.0000610351562500, 0.0182189941406250, +0.0000915527343750, 0.0244750976562500, 0.0000915527343750, 0.0447998046875000, +0.0000610351562500, 0.0323791503906250, 0.0000610351562500, 0.0513305664062500, +0.0001525878906250, 0.0494689941406250, 0.0001220703125000, 0.0492553710937500, +0.0001220703125000, 0.0590820312500000, 0.0000915527343750, 0.0520935058593750, +0.0001220703125000, 0.0561828613281250, 0.0000915527343750, 0.0558166503906250, +0.0001220703125000, 0.0530395507812500, 0.0000915527343750, 0.0528869628906250, +0.0001220703125000, 0.0508728027343750, 0.0000915527343750, 0.0489807128906250, +0.0001525878906250, 0.0483398437500000, 0.0001220703125000, 0.0459594726562500, +0.0001220703125000, 0.0440979003906250, 0.0001220703125000, 0.0442810058593750, +0.0001220703125000, 0.0394592285156250, 0.0001220703125000, 0.0383911132812500, +0.0001220703125000, 0.0361633300781250, 0.0001220703125000, 0.0321655273437500, +0.0001525878906250, 0.0306701660156250, 0.0001525878906250, 0.0245971679687500, +0.0001831054687500, 0.0252075195312500, 0.0002136230468750, 0.0184936523437500, +0.0001831054687500, 0.0114440917968750, 0.0001831054687500, 0.0143432617187500, +0.0002136230468750, -0.0049133300781250, 0.0001220703125000, -0.0018615722656250, +0.0001220703125000, -0.0107421875000000, 0.0001220703125000, -0.0281066894531250, +0.0001220703125000, -0.0213012695312500, 0.0001220703125000, -0.0437927246093750, +-0.0000610351562500, -0.0433654785156250, -0.0000610351562500, -0.0466918945312500, +0.0000305175781250, -0.0607604980468750, -0.0000915527343750, -0.0560607910156250, +-0.0001220703125000, -0.0648803710937500, 0.0001220703125000, -0.0648193359375000, +0.0003356933593750, -0.0652770996093750, -0.0004882812500000, -0.0695800781250000, +-0.0002746582031250, -0.0678100585937500, 0.0001831054687500, -0.0747070312500000, +-0.0050048828125000, -0.0714721679687500, -0.0024414062500000, -0.0788574218750000, +-0.0061340332031250, -0.0886230468750000, -0.0130615234375000, -0.0821838378906250, +-0.0083923339843750, -0.1010742187500000, -0.0125427246093750, -0.1018066406250000, +-0.0177917480468750, -0.1056518554687500, -0.0069274902343750, -0.1174926757812500, +-0.0020141601562500, -0.1147155761718750, -0.0107116699218750, -0.1260681152343750, +0.0232238769531250, -0.1236572265625000, 0.0169982910156250, -0.1338500976562500, +0.0224609375000000, -0.1444702148437500, 0.0498962402343750, -0.1357421875000000, +0.0388183593750000, -0.1726989746093750, 0.0366210937500000, -0.1683349609375000, +0.0492248535156250, -0.1794433593750000, 0.0324401855468750, -0.2095336914062500, +0.0132751464843750, -0.1965332031250000, 0.0281677246093750, -0.2114257812500000, +0.0001525878906250, -0.2176208496093750, -0.0030822753906250, -0.2098693847656250, +0.0014038085937500, -0.2084350585937500, -0.0072937011718750, -0.2109069824218750, +-0.0075073242187500, -0.1991271972656250, -0.0088806152343750, -0.2007751464843750, +-0.0035400390625000, -0.1943664550781250, -0.0154418945312500, -0.1859130859375000, +-0.0259704589843750, -0.1908874511718750, -0.0149230957031250, -0.1633605957031250, +-0.0428161621093750, -0.1716918945312500, -0.0447082519531250, -0.1531066894531250, +-0.0391235351562500, -0.1245422363281250, -0.0495605468750000, -0.1417846679687500, +-0.0503234863281250, -0.0887756347656250, -0.0386962890625000, -0.0947875976562500, +-0.0374450683593750, -0.0768127441406250, -0.0455322265625000, -0.0362854003906250, +-0.0441894531250000, -0.0561523437500000, -0.0378417968750000, -0.0057373046875000, +-0.0590515136718750, -0.0083618164062500, -0.0653381347656250, -0.0006713867187500, +-0.0414428710937500, 0.0319824218750000, -0.0440368652343750, 0.0181274414062500, +-0.0596923828125000, 0.0377502441406250, 0.0385742187500000, 0.0406188964843750, +0.0086975097656250, 0.0399780273437500, 0.0544738769531250, 0.0456237792968750, +0.1519470214843750, 0.0431213378906250, 0.0994262695312500, 0.0593566894531250, +0.1915283203125000, 0.0501098632812500, 0.2022094726562500, 0.0665283203125000, +0.1928100585937500, 0.0940551757812500, 0.2324218750000000, 0.0938415527343750, +0.2261352539062500, 0.1529235839843750, 0.2021179199218750, 0.1281738281250000, +0.2184753417968750, 0.1473693847656250, 0.1999206542968750, 0.1968994140625000, +0.1703186035156250, 0.1651611328125000, 0.1885681152343750, 0.2456054687500000, +0.1282348632812500, 0.2361755371093750, 0.1292419433593750, 0.2447204589843750, +0.1238403320312500, 0.3057861328125000, 0.0866394042968750, 0.2801208496093750, +0.0975952148437500, 0.2593383789062500, 0.0943298339843750, 0.3078002929687500, +0.0889892578125000, 0.2264099121093750, 0.0856018066406250, 0.1449279785156250, +0.0898437500000000, 0.2152404785156250, 0.0915222167968750, 0.0130004882812500, +0.0534057617187500, 0.0214538574218750, 0.0656127929687500, 0.0113220214843750, +0.0473022460937500, -0.1109313964843750, 0.0058288574218750, -0.0707397460937500, +0.0245666503906250, -0.0674133300781250, 0.0021667480468750, -0.0974426269531250, +-0.0065002441406250, -0.0691223144531250, -0.0018920898437500, -0.0277099609375000, +-0.0001220703125000, -0.0501708984375000, -0.0025634765625000, -0.0312500000000000, +-0.0270080566406250, -0.0155334472656250, -0.0075683593750000, -0.0323486328125000, +-0.0427551269531250, -0.0463562011718750, -0.0871582031250000, -0.0352172851562500, +-0.0562133789062500, -0.0465087890625000, -0.1411132812500000, -0.0560913085937500, +-0.1398010253906250, -0.0424499511718750, -0.1441955566406250, -0.0330505371093750, +-0.1928100585937500, -0.0430908203125000, -0.1756591796875000, -0.0220947265625000, +-0.1803283691406250, -0.0202941894531250, -0.1920166015625000, -0.0213623046875000, +-0.1758422851562500, -0.0150756835937500, -0.1621093750000000, -0.0162658691406250, +-0.1728515625000000, -0.0013732910156250, -0.1416931152343750, -0.0115051269531250, +-0.1420288085937500, 0.0054321289062500, -0.1387329101562500, 0.0292053222656250, +-0.1202392578125000, 0.0113525390625000, -0.1269531250000000, 0.0479125976562500, +-0.1205749511718750, 0.0520935058593750, -0.1180725097656250, 0.0400390625000000, +-0.1160278320312500, 0.0522460937500000, -0.1141357421875000, 0.0557250976562500, +-0.1155090332031250, 0.0208435058593750, -0.1019897460937500, 0.0323791503906250, +-0.1046142578125000, 0.0214233398437500, -0.0972595214843750, -0.0105590820312500, +-0.0830383300781250, 0.0058898925781250, -0.0887145996093750, -0.0126647949218750, +-0.0765686035156250, -0.0193481445312500, -0.0729675292968750, -0.0115356445312500, +-0.0765991210937500, -0.0126037597656250, -0.0740966796875000, -0.0160217285156250, +-0.0716247558593750, -0.0048522949218750, -0.0806579589843750, -0.0054016113281250, +-0.0799255371093750, -0.0053100585937500, -0.0789489746093750, 0.0007019042968750, +-0.0845031738281250, -0.0010986328125000, -0.0834350585937500, -0.0003662109375000, +-0.0755310058593750, 0.0003967285156250, -0.0789184570312500, 0.0000000000000000, +-0.0714416503906250, -0.0002746582031250, -0.0600280761718750, -0.0001831054687500, +-0.0642395019531250, -0.0000305175781250, -0.0482177734375000, -0.0001525878906250, +-0.0477905273437500, -0.0001220703125000, -0.0448303222656250, 0.0001220703125000, +-0.0343017578125000, 0.0000305175781250, -0.0367431640625000, 0.0000915527343750, +-0.0310058593750000, 0.0001220703125000, -0.0286865234375000, 0.0001220703125000, +-0.0289306640625000, 0.0001525878906250, -0.0273742675781250, 0.0001220703125000, +-0.0272216796875000, 0.0001525878906250, -0.0291442871093750, 0.0001525878906250, +-0.0296936035156250, 0.0001220703125000, -0.0300598144531250, 0.0000915527343750, +-0.0315551757812500, 0.0001220703125000, -0.0319519042968750, 0.0000610351562500, +-0.0307006835937500, 0.0000915527343750, -0.0339355468750000, 0.0000915527343750, +-0.0306396484375000, 0.0000610351562500, -0.0273742675781250, 0.0000305175781250, +-0.0322875976562500, 0.0000305175781250, -0.0205688476562500, -0.0000305175781250, +-0.0231018066406250, -0.0000305175781250, -0.0210266113281250, -0.0000305175781250, +-0.0123901367187500, -0.0000610351562500, -0.0168762207031250, -0.0000610351562500, +-0.0098266601562500, -0.0000610351562500, -0.0101623535156250, -0.0000610351562500, +-0.0105590820312500}, +{-0.0087280273437500, 0.1958618164062500, -0.0060424804687500, 0.0945739746093750, +-0.0147094726562500, 0.1726379394531250, -0.0133361816406250, -0.0152587890625000, +-0.0377807617187500, -0.0160827636718750, -0.0216979980468750, -0.0105285644531250, +-0.0542907714843750, -0.1093444824218750, -0.0944824218750000, -0.0840148925781250, +-0.0641784667968750, -0.0617675781250000, -0.1427307128906250, -0.0848083496093750, +-0.1412963867187500, -0.0636596679687500, -0.1430664062500000, -0.0213623046875000, +-0.1872558593750000, -0.0400695800781250, -0.1737670898437500, -0.0307922363281250, +-0.1758422851562500, -0.0171203613281250, -0.1853332519531250, -0.0296936035156250, +-0.1726379394531250, -0.0443115234375000, -0.1627197265625000, -0.0350646972656250, +-0.1717224121093750, -0.0388488769531250, -0.1406555175781250, -0.0479736328125000, +-0.1468200683593750, -0.0357055664062500, -0.1361083984375000, -0.0234985351562500, +-0.1101074218750000, -0.0335083007812500, -0.1248168945312500, -0.0166931152343750, +-0.1019897460937500, -0.0147399902343750, -0.0986938476562500, -0.0147705078125000, +-0.1014709472656250, -0.0102539062500000, -0.0938415527343750, -0.0122680664062500, +-0.0953674316406250, 0.0047302246093750, -0.0944824218750000, -0.0045471191406250, +-0.0952148437500000, 0.0096740722656250, -0.0929870605468750, 0.0328063964843750, +-0.0912475585937500, 0.0162353515625000, -0.0938720703125000, 0.0427246093750000, +-0.0864257812500000, 0.0480651855468750, -0.0882873535156250, 0.0357971191406250, +-0.0858764648437500, 0.0416870117187500, -0.0796203613281250, 0.0472106933593750, +-0.0829772949218750, 0.0146179199218750, -0.0759887695312500, 0.0226745605468750, +-0.0773925781250000, 0.0148620605468750, -0.0724182128906250, -0.0121765136718750, +-0.0658569335937500, 0.0004272460937500, -0.0698852539062500, -0.0112915039062500, +-0.0507507324218750, -0.0172729492187500, -0.0531311035156250, -0.0107421875000000, +-0.0468444824218750, -0.0092773437500000, -0.0305175781250000, -0.0128173828125000, +-0.0373229980468750, -0.0035400390625000, -0.0295104980468750, -0.0034484863281250, +-0.0238037109375000, -0.0037536621093750, -0.0310058593750000, 0.0006103515625000, +-0.0341186523437500, -0.0004882812500000, -0.0299377441406250, -0.0003662109375000, +-0.0496826171875000, 0.0000610351562500, -0.0466308593750000, -0.0001220703125000, +-0.0552978515625000, -0.0003967285156250, -0.0725708007812500, -0.0003356933593750, +-0.0652160644531250, -0.0001525878906250, -0.0870056152343750, -0.0002746582031250, +-0.0873107910156250, -0.0002136230468750, -0.0928039550781250, -0.0000610351562500, +-0.1069030761718750, -0.0000915527343750, -0.1010131835937500, -0.0000610351562500, +-0.1152038574218750, -0.0000610351562500, -0.1152038574218750, 0.0000000000000000, +-0.1191711425781250, 0.0000000000000000, -0.1284790039062500, 0.0000000000000000, +-0.1233825683593750, 0.0000305175781250, -0.1343078613281250, 0.0000610351562500, +-0.1343383789062500, 0.0000305175781250, -0.1360473632812500, 0.0000305175781250, +-0.1429748535156250, 0.0000305175781250, -0.1409606933593750, 0.0000000000000000, +-0.1480712890625000, 0.0000000000000000, -0.1491088867187500, -0.0000305175781250, +-0.1484069824218750, -0.0000305175781250, -0.1521606445312500, 0.0000000000000000, +-0.1534118652343750, -0.0000610351562500, -0.1496582031250000, -0.0000610351562500, +-0.1535339355468750, -0.0000305175781250, -0.1504821777343750, -0.0000610351562500, +-0.1447143554687500, -0.0000610351562500, -0.1489868164062500, 0.0000000000000000, +-0.1389465332031250, 0.0000305175781250, -0.1396179199218750, 0.0000000000000000, +-0.1398315429687500, 0.0000000000000000, -0.1354370117187500, 0.0000305175781250, +-0.1380004882812500, -0.0000915527343750, -0.1341552734375000, -0.0000915527343750, +-0.1401367187500000, -0.0000915527343750, -0.1295471191406250, 0.0001220703125000, +-0.1233520507812500, 0.0000000000000000, -0.1346740722656250, -0.0011901855468750, +-0.0833435058593750, 0.0003051757812500, -0.1047668457031250, -0.0036926269531250, +-0.0776062011718750, -0.0072326660156250, -0.0244445800781250, -0.0038452148437500, +-0.0606689453125000, -0.0145568847656250, 0.0088500976562500, -0.0162658691406250, +0.0122375488281250, -0.0100402832031250, 0.0075988769531250, -0.0144042968750000, +0.0397644042968750, -0.0168762207031250, 0.0325012207031250, 0.0167846679687500, +0.0284729003906250, 0.0067138671875000, 0.0289306640625000, 0.0197753906250000, +0.0373535156250000, 0.0555725097656250, 0.0357360839843750, 0.0387573242187500, +0.0296630859375000, 0.0405273437500000, 0.0773925781250000, 0.0603942871093750, +0.0638427734375000, 0.0300903320312500, 0.0818481445312500, -0.0014953613281250, +0.1277160644531250, 0.0236206054687500, 0.1053771972656250, -0.0234985351562500, +0.1315002441406250, -0.0366821289062500, 0.1398010253906250, -0.0122680664062500, +0.1325683593750000, -0.0146484375000000, 0.1355895996093750, -0.0292358398437500, +0.1377258300781250, 0.0199584960937500, 0.1373291015625000, 0.0256347656250000, +0.1390075683593750, 0.0046081542968750, 0.1322326660156250, 0.0210876464843750, +0.1315002441406250, 0.0310668945312500, 0.1365661621093750, -0.0500793457031250, +0.0985107421875000, -0.0310974121093750, 0.1112976074218750, -0.0480346679687500, +0.0918273925781250, -0.1198730468750000, 0.0528259277343750, -0.0930175781250000, +0.0730285644531250, -0.0862121582031250, 0.0270385742187500, -0.1183776855468750, +0.0304870605468750, -0.0740356445312500, 0.0184326171875000, -0.0222167968750000, +-0.0095214843750000, -0.0581665039062500, 0.0072937011718750, 0.0187988281250000, +-0.0488891601562500, 0.0274047851562500, -0.0319824218750000, 0.0202941894531250, +-0.0653381347656250, 0.0479431152343750, -0.1213073730468750, 0.0442504882812500, +-0.0862426757812500, 0.0497436523437500, -0.1829223632812500, 0.0439147949218750, +-0.1754455566406250, 0.0615539550781250, -0.1915283203125000, 0.0774230957031250, +-0.2574157714843750, 0.0623779296875000, -0.2285766601562500, 0.1102294921875000, +-0.2601013183593750, 0.1076965332031250, -0.2746276855468750, 0.1132507324218750, +-0.2545166015625000, 0.1402893066406250, -0.2524108886718750, 0.1310729980468750, +-0.2624206542968750, 0.1603393554687500, -0.2145690917968750, 0.1452331542968750, +-0.2193603515625000, 0.1846313476562500, -0.2161865234375000, 0.2245178222656250, +-0.1838378906250000, 0.1894226074218750, -0.1935424804687500, 0.3216552734375000, +-0.2028808593750000, 0.3080444335937500, -0.1947631835937500, 0.3230285644531250, +-0.1968383789062500, 0.4222106933593750, -0.2146301269531250, 0.3867492675781250, +-0.2108154296875000, 0.3457031250000000, -0.1752014160156250, 0.3999023437500000, +-0.1949768066406250, 0.3270568847656250, -0.1744079589843750, 0.1448059082031250, +-0.0983886718750000, -0.0956726074218750, -0.1848449707031250, -0.2249755859375000, +-0.1419372558593750, -0.2082519531250000, -0.1823730468750000, -0.2105102539062500, +-0.1393737792968750, -0.2485656738281250, -0.0824584960937500, -0.2425231933593750, +-0.1137695312500000, -0.2174987792968750, -0.0534667968750000, -0.2332153320312500, +-0.0575561523437500, -0.2136535644531250, -0.0314941406250000, -0.1761169433593750, +0.0053100585937500, -0.1965942382812500, -0.0215148925781250, -0.1771240234375000, +0.1121215820312500, -0.1536254882812500, 0.0761413574218750, -0.1990661621093750, +0.1327209472656250, -0.2243652343750000, 0.2640686035156250, -0.1899108886718750, +0.1967468261718750, -0.3123168945312500, 0.2916564941406250, -0.3009338378906250, +0.3241577148437500, -0.3059387207031250, 0.2821350097656250, -0.3891906738281250, +0.2861938476562500, -0.3626403808593750, 0.3048095703125000, -0.3209228515625000, +0.2288818359375000, -0.3677062988281250, 0.2345275878906250, -0.3035888671875000, +0.2231750488281250, -0.2164001464843750, 0.1780090332031250, -0.2758483886718750, +0.1949157714843750, -0.1473388671875000, 0.1485595703125000, -0.1475219726562500, +0.1602172851562500, -0.1386108398437500, 0.1298828125000000, -0.0707092285156250, +0.0821838378906250, -0.0962219238281250, 0.1134948730468750, -0.0391235351562500, +0.0342407226562500, -0.0504150390625000, 0.0342712402343750, -0.0167541503906250, +0.0278320312500000, 0.0346984863281250, -0.0144042968750000, -0.0011901855468750, +0.0011596679687500, 0.1080017089843750, -0.0329895019531250, 0.0983276367187500, +-0.0274658203125000, 0.1090087890625000, -0.0437622070312500, 0.1816406250000000, +-0.0766906738281250, 0.1537475585937500, -0.0581359863281250, 0.1614685058593750, +-0.0906372070312500, 0.1803894042968750, -0.1034240722656250, 0.1610717773437500, +-0.0799255371093750, 0.1427001953125000, -0.0773315429687500, 0.1572570800781250, +-0.0909423828125000, 0.1260070800781250, -0.0292663574218750, 0.1302795410156250, +-0.0335693359375000, 0.1195373535156250, -0.0288696289062500, 0.0966491699218750, +0.0097961425781250, 0.1124572753906250, -0.0012817382812500, 0.0788269042968750, +0.0013122558593750, 0.0779113769531250, 0.0041809082031250, 0.0795593261718750, +0.0092773437500000, 0.0628662109375000, 0.0091552734375000, 0.0657348632812500, +0.0039367675781250, 0.0662841796875000, 0.0346679687500000, 0.0689392089843750, +0.0316772460937500, 0.0578613281250000, 0.0310058593750000, 0.0525817871093750, +0.0529479980468750, 0.0611267089843750, 0.0491027832031250, 0.0202026367187500, +0.0238647460937500, 0.0301513671875000, 0.0361938476562500, 0.0145263671875000, +0.0210266113281250, -0.0197448730468750, -0.0107727050781250, 0.0015258789062500, +0.0050659179687500, -0.0381774902343750, -0.0131225585937500, -0.0348815917968750, +-0.0213928222656250, -0.0392150878906250, -0.0123901367187500, -0.0619812011718750, +-0.0102844238281250, -0.0486755371093750, -0.0144653320312500, -0.0736694335937500, +-0.0034179687500000, -0.0682373046875000, -0.0023498535156250, -0.0771484375000000, +-0.0033569335937500, -0.0980529785156250, 0.0007324218750000, -0.0841674804687500, +0.0000305175781250, -0.1105346679687500, -0.0002441406250000, -0.1110534667968750, +-0.0000610351562500, -0.1085815429687500, -0.0000305175781250, -0.1212158203125000, +-0.0001525878906250, -0.1179809570312500, -0.0001831054687500, -0.1131896972656250, +-0.0000915527343750, -0.1195678710937500, 0.0000000000000000, -0.1138610839843750, +-0.0000610351562500, -0.1053466796875000, -0.0001525878906250, -0.1127319335937500, +-0.0000915527343750, -0.0981750488281250, -0.0000610351562500, -0.1019897460937500, +-0.0000610351562500, -0.0989379882812500, -0.0000915527343750, -0.0899658203125000, +-0.0000610351562500, -0.0997924804687500, -0.0000610351562500, -0.0858764648437500, +-0.0000915527343750, -0.0910034179687500, -0.0000610351562500, -0.0884399414062500, +-0.0000610351562500, -0.0782470703125000, -0.0000305175781250, -0.0878295898437500, +-0.0000305175781250, -0.0744018554687500, 0.0000000000000000, -0.0778503417968750, +0.0000305175781250, -0.0774841308593750, -0.0000305175781250, -0.0693359375000000, +-0.0000610351562500, -0.0762329101562500, 0.0000305175781250, -0.0701599121093750, +0.0000000000000000, -0.0728759765625000, -0.0000305175781250, -0.0725708007812500, +-0.0000915527343750, -0.0687255859375000, -0.0001220703125000, -0.0743103027343750, +-0.0000610351562500, -0.0690002441406250, -0.0001525878906250, -0.0702514648437500, +-0.0001831054687500, -0.0707397460937500, -0.0001525878906250, -0.0680847167968750, +-0.0002441406250000, -0.0702819824218750, -0.0002746582031250, -0.0659484863281250, +-0.0000915527343750, -0.0674743652343750, -0.0001525878906250, -0.0630798339843750, +-0.0002746582031250, -0.0582885742187500, 0.0000610351562500, -0.0613098144531250, +0.0000610351562500}, +{0.0538024902343750, 0.2014465332031250, 0.0830383300781250, 0.1761169433593750, +0.0185546875000000, 0.2054748535156250, 0.0160827636718750, 0.1738281250000000, +0.0119323730468750, 0.1206665039062500, -0.0193481445312500, 0.1532592773437500, +-0.0076599121093750, 0.1187133789062500, -0.0388488769531250, 0.1029357910156250, +-0.0327453613281250, 0.1208801269531250, -0.0461120605468750, 0.1282348632812500, +-0.0779724121093750, 0.1184082031250000, -0.0624084472656250, 0.1215515136718750, +-0.0766296386718750, 0.1351013183593750, -0.0921020507812500, 0.1159973144531250, +-0.0665588378906250, 0.0986022949218750, -0.0494689941406250, 0.1146850585937500, +-0.0675659179687500, 0.0711364746093750, -0.0134277343750000, 0.0792236328125000, +-0.0117187500000000, 0.0615539550781250, -0.0148315429687500, 0.0295715332031250, +0.0096435546875000, 0.0519104003906250, 0.0054626464843750, -0.0171508789062500, +0.0038452148437500, -0.0056457519531250, 0.0014343261718750, -0.0230712890625000, +0.0117187500000000, -0.0757446289062500, 0.0182495117187500, -0.0494689941406250, +0.0094299316406250, -0.0951232910156250, 0.0371704101562500, -0.0991516113281250, +0.0400390625000000, -0.0968627929687500, 0.0307617187500000, -0.1182861328125000, +0.0405273437500000, -0.1120605468750000, 0.0438842773437500, -0.1065368652343750, +0.0102539062500000, -0.1162719726562500, 0.0172119140625000, -0.1047973632812500, +0.0100402832031250, -0.0917663574218750, -0.0180664062500000, -0.1040039062500000, +-0.0081176757812500, -0.0725708007812500, -0.0120544433593750, -0.0796508789062500, +-0.0186767578125000, -0.0694885253906250, -0.0119934082031250, -0.0453186035156250, +-0.0051269531250000, -0.0623779296875000, -0.0093383789062500, -0.0308227539062500, +-0.0020446777343750, -0.0332641601562500, -0.0003967285156250, -0.0321655273437500, +-0.0015563964843750, -0.0146789550781250, 0.0000610351562500, -0.0238342285156250, +-0.0000305175781250, -0.0133666992187500, -0.0002441406250000, -0.0132446289062500, +-0.0002746582031250, -0.0137023925781250, -0.0002136230468750, -0.0082397460937500, +-0.0000610351562500, -0.0100708007812500, -0.0001525878906250, -0.0065307617187500, +-0.0000305175781250, -0.0054016113281250, -0.0000305175781250, -0.0057983398437500, +-0.0000610351562500, -0.0040588378906250, -0.0000610351562500, -0.0026245117187500, +-0.0000610351562500, -0.0040893554687500, -0.0000610351562500, -0.0021667480468750, +0.0000000000000000, -0.0034484863281250, -0.0000305175781250, -0.0056762695312500, +-0.0000610351562500, -0.0024108886718750, 0.0000000000000000, -0.0052795410156250, +-0.0000305175781250, -0.0054016113281250, -0.0000610351562500, -0.0037841796875000, +-0.0000610351562500, -0.0037536621093750, -0.0000915527343750, -0.0032653808593750, +-0.0001220703125000, -0.0017700195312500, -0.0000915527343750, -0.0006408691406250, +-0.0000610351562500, 0.0004272460937500, -0.0001220703125000, 0.0011596679687500, +-0.0001831054687500, 0.0014343261718750, -0.0001525878906250, 0.0028686523437500, +0.0000305175781250, 0.0025329589843750, -0.0000610351562500, 0.0033264160156250, +-0.0000915527343750, 0.0047607421875000, 0.0002136230468750, 0.0032653808593750, +0.0001525878906250, 0.0025634765625000, -0.0014038085937500, 0.0036010742187500, +-0.0000305175781250, 0.0001831054687500, -0.0025329589843750, -0.0026855468750000, +-0.0054016113281250, -0.0017089843750000, -0.0027770996093750, -0.0126037597656250, +-0.0086364746093750, -0.0111999511718750, -0.0095520019531250, -0.0164184570312500, +-0.0064086914062500, -0.0268554687500000, -0.0087890625000000, -0.0240173339843750, +-0.0102233886718750, -0.0354614257812500, 0.0045471191406250, -0.0374450683593750, +-0.0016784667968750, -0.0366210937500000, 0.0068054199218750, -0.0425415039062500, +0.0235900878906250, -0.0421142578125000, 0.0130615234375000, -0.0303649902343750, +0.0272521972656250, -0.0360412597656250, 0.0324707031250000, -0.0245971679687500, +0.0239868164062500, -0.0079040527343750, 0.0242614746093750, -0.0167541503906250, +0.0293273925781250, 0.0086975097656250, 0.0097961425781250, 0.0101623535156250, +0.0126953125000000, 0.0147094726562500, 0.0110168457031250, 0.0309448242187500, +-0.0020446777343750, 0.0257873535156250, 0.0023193359375000, 0.0310668945312500, +-0.0010986328125000, 0.0380249023437500, -0.0012207031250000, 0.0256652832031250, +-0.0052185058593750, 0.0184936523437500, -0.0075073242187500, 0.0269165039062500, +-0.0034790039062500, -0.0101013183593750, -0.0227050781250000, -0.0058288574218750, +-0.0183715820312500, -0.0136108398437500, -0.0226440429687500, -0.0438232421875000, +-0.0389099121093750, -0.0327148437500000, -0.0319824218750000, -0.0290222167968750, +-0.0353088378906250, -0.0415954589843750, -0.0394287109375000, -0.0266723632812500, +-0.0369567871093750, -0.0033569335937500, -0.0332336425781250, -0.0155334472656250, +-0.0348815917968750, -0.0099792480468750, -0.0396423339843750, 0.0057067871093750, +-0.0368347167968750, -0.0191040039062500, -0.0364685058593750, -0.0398559570312500, +-0.0451049804687500, -0.0223999023437500, -0.0427856445312500, -0.0829162597656250, +-0.0152282714843750, -0.0764465332031250, -0.0357360839843750, -0.0915832519531250, +-0.0003662109375000, -0.1354370117187500, 0.0436096191406250, -0.1153564453125000, +0.0104675292968750, -0.1513671875000000, 0.1043395996093750, -0.1558227539062500, +0.0943908691406250, -0.1549072265625000, 0.1121826171875000, -0.1699829101562500, +0.1771545410156250, -0.1655578613281250, 0.1481628417968750, -0.1698608398437500, +0.1961059570312500, -0.1714782714843750, 0.2030639648437500, -0.1687927246093750, +0.1912231445312500, -0.1705017089843750, 0.2100524902343750, -0.1711730957031250, +0.2104797363281250, -0.1573486328125000, 0.1681518554687500, -0.1648254394531250, +0.1873779296875000, -0.1500549316406250, 0.1587219238281250, -0.1315917968750000, +0.1068420410156250, -0.1450195312500000, 0.1370544433593750, -0.1022033691406250, +0.0859985351562500, -0.1085510253906250, 0.0780639648437500, -0.0963745117187500, +0.0842285156250000, -0.0580139160156250, 0.0700073242187500, -0.0599975585937500, +0.0705566406250000, -0.0205688476562500, 0.0526428222656250, -0.0340576171875000, +0.0666809082031250, -0.0273437500000000, 0.0490112304687500, 0.0028991699218750, +0.0219116210937500, -0.0127258300781250, 0.0397949218750000, 0.0187072753906250, +-0.0144653320312500, 0.0147399902343750, -0.0156555175781250, 0.0255737304687500, +-0.0172729492187500, 0.0477294921875000, -0.0440979003906250, 0.0324096679687500, +-0.0369262695312500, 0.0739746093750000, -0.0509948730468750, 0.0654296875000000, +-0.0450439453125000, 0.0805053710937500, -0.0647888183593750, 0.1136779785156250, +-0.0850219726562500, 0.0948486328125000, -0.0684204101562500, 0.1462402343750000, +-0.1315002441406250, 0.1368408203125000, -0.1255798339843750, 0.1593933105468750, +-0.1362609863281250, 0.2032470703125000, -0.1810302734375000, 0.1751098632812500, +-0.1640014648437500, 0.2345886230468750, -0.1776428222656250, 0.2420349121093750, +-0.1872863769531250, 0.2217712402343750, -0.1773376464843750, 0.2474060058593750, +-0.1732177734375000, 0.2528076171875000, -0.1786193847656250, 0.1578063964843750, +-0.1597595214843750, 0.1996765136718750, -0.1664428710937500, 0.1339416503906250, +-0.1519470214843750, 0.0184936523437500, -0.1319885253906250, 0.0861816406250000, +-0.1468505859375000, -0.0451965332031250, -0.1018676757812500, -0.0606689453125000, +-0.1019287109375000, -0.0393371582031250, -0.1040954589843750, -0.0868225097656250, +-0.0790100097656250, -0.0830993652343750, -0.0823669433593750, -0.0442199707031250, +-0.0967712402343750, -0.0555114746093750, -0.0892639160156250, -0.0484313964843750, +-0.0909118652343750, -0.0151062011718750, -0.1065979003906250, -0.0257568359375000, +-0.1007080078125000, -0.0283203125000000, -0.0849914550781250, -0.0203247070312500, +-0.0942077636718750, -0.0244750976562500, -0.0769348144531250, -0.0353393554687500, +-0.0513916015625000, -0.0313720703125000, -0.0650939941406250, -0.0247802734375000, +-0.0381164550781250, -0.0317993164062500, -0.0318603515625000, -0.0243530273437500, +-0.0343322753906250, -0.0117187500000000, -0.0249328613281250, -0.0195922851562500, +-0.0238342285156250, -0.0083007812500000, -0.0288391113281250, -0.0074768066406250, +-0.0272827148437500, -0.0057373046875000, -0.0247497558593750, -0.0014648437500000, +-0.0273437500000000, -0.0046691894531250, -0.0263671875000000, 0.0119628906250000, +-0.0142517089843750, 0.0060424804687500, -0.0158996582031250, 0.0135192871093750, +-0.0099487304687500, 0.0311279296875000, 0.0018310546875000, 0.0207214355468750, +-0.0015258789062500, 0.0311279296875000, 0.0079040527343750, 0.0380859375000000, +0.0095825195312500, 0.0268249511718750, 0.0115356445312500, 0.0225830078125000, +0.0168457031250000, 0.0306396484375000, 0.0159606933593750, 0.0041503906250000, +0.0209960937500000, 0.0067749023437500, 0.0220031738281250, 0.0045166015625000, +0.0213012695312500, -0.0128784179687500, 0.0230407714843750, -0.0066833496093750, +0.0226745605468750, -0.0081787109375000, 0.0177917480468750, -0.0123901367187500, +0.0190124511718750, -0.0082092285156250, 0.0140686035156250, -0.0039672851562500, +0.0073852539062500, -0.0071105957031250, 0.0100097656250000, -0.0017395019531250, +0.0003967285156250, -0.0010375976562500, -0.0010375976562500, -0.0016784667968750, +-0.0041198730468750, 0.0001525878906250, -0.0108337402343750, -0.0001220703125000, +-0.0101623535156250, -0.0003662109375000, -0.0164184570312500, -0.0002441406250000, +-0.0175476074218750, -0.0002136230468750, -0.0199279785156250, -0.0003662109375000, +-0.0242614746093750, -0.0003662109375000, -0.0235290527343750, -0.0003051757812500, +-0.0280761718750000, -0.0003051757812500, -0.0300292968750000, -0.0002746582031250, +-0.0294189453125000, -0.0002441406250000, -0.0308227539062500, -0.0002746582031250, +-0.0325927734375000, -0.0001831054687500, -0.0301818847656250, -0.0001831054687500, +-0.0306091308593750, -0.0001831054687500, -0.0315856933593750, -0.0001831054687500, +-0.0306091308593750, -0.0001525878906250, -0.0308227539062500, -0.0001525878906250, +-0.0327148437500000, -0.0001831054687500, -0.0334472656250000, -0.0001525878906250, +-0.0328674316406250, -0.0001831054687500, -0.0339050292968750, -0.0001831054687500, +-0.0350952148437500, -0.0002441406250000, -0.0307006835937500, 0.0001220703125000, +-0.0340270996093750, -0.0010681152343750, -0.0313415527343750, -0.0013427734375000, +-0.0272827148437500, -0.0006408691406250, -0.0316772460937500, -0.0068969726562500, +-0.0171203613281250, -0.0050659179687500, -0.0227966308593750, -0.0075988769531250, +-0.0168762207031250, -0.0154113769531250, -0.0022583007812500, -0.0120239257812500, +-0.0132141113281250, -0.0071716308593750, -0.0048217773437500, -0.0154418945312500, +0.0043334960937500, 0.0014038085937500, -0.0151062011718750, 0.0195617675781250, +-0.0227661132812500, 0.0053710937500000, -0.0079650878906250, 0.0372009277343750, +-0.0679931640625000, 0.0447692871093750, -0.0539245605468750, 0.0292358398437500, +-0.0744628906250000, 0.0342407226562500, -0.1273193359375000, 0.0420227050781250, +-0.1004333496093750, -0.0038757324218750, -0.1404724121093750, -0.0005187988281250, +-0.1470031738281250, 0.0010681152343750, -0.1348266601562500, -0.0280151367187500, +-0.1469726562500000, -0.0228271484375000, -0.1489257812500000, 0.0046081542968750, +-0.1203613281250000, -0.0061645507812500, -0.1323852539062500, -0.0008239746093750, +-0.1064453125000000, 0.0305480957031250, -0.0777282714843750, 0.0214233398437500, +-0.1005249023437500, -0.0105895996093750, -0.0001220703125000, 0.0125427246093750, +-0.0281677246093750}, +{0.0074157714843750, -0.0252075195312500, 0.0033874511718750, -0.0194702148437500, +0.0140991210937500, -0.0083312988281250, 0.0374450683593750, -0.0148925781250000, +0.0285949707031250, -0.0050048828125000, 0.0417785644531250, -0.0047607421875000, +0.0491333007812500, -0.0024108886718750, 0.0404663085937500, 0.0022277832031250, +0.0380554199218750, -0.0015258789062500, 0.0433654785156250, 0.0140075683593750, +0.0228576660156250, 0.0097961425781250, 0.0262756347656250, 0.0147094726562500, +0.0187072753906250, 0.0295715332031250, 0.0020141601562500, 0.0220947265625000, +0.0100097656250000, 0.0260314941406250, -0.0109252929687500, 0.0330810546875000, +-0.0108337402343750, 0.0223999023437500, -0.0130310058593750, 0.0143737792968750, +-0.0256347656250000, 0.0228881835937500, -0.0212402343750000, -0.0000915527343750, +-0.0264587402343750, 0.0003662109375000, -0.0286865234375000, 0.0006103515625000, +-0.0252075195312500, -0.0116577148437500, -0.0245361328125000, -0.0079345703125000, +-0.0256042480468750, -0.0067138671875000, -0.0173339843750000, -0.0097656250000000, +-0.0176086425781250, -0.0068054199218750, -0.0133666992187500, -0.0024414062500000, +-0.0057373046875000, -0.0051269531250000, -0.0081176757812500, -0.0012207031250000, +-0.0010070800781250, -0.0005798339843750, 0.0007934570312500, -0.0011596679687500, +0.0015869140625000, -0.0000305175781250, 0.0055847167968750, -0.0001525878906250, +0.0053100585937500, -0.0003662109375000, 0.0031433105468750, -0.0003356933593750, +0.0086059570312500, -0.0003356933593750, 0.0029602050781250, -0.0003967285156250, +-0.0034790039062500, -0.0004272460937500, 0.0036315917968750, -0.0002746582031250, +-0.0145568847656250, -0.0003356933593750, -0.0110473632812500, -0.0002746582031250, +-0.0155944824218750, -0.0001831054687500, -0.0294494628906250, -0.0002441406250000, +-0.0222778320312500, -0.0000610351562500, -0.0361633300781250, 0.0000610351562500, +-0.0350036621093750, -0.0003967285156250, -0.0389099121093750, -0.0002136230468750, +-0.0478515625000000, -0.0000305175781250, -0.0420227050781250, -0.0036621093750000, +-0.0583496093750000, -0.0018920898437500, -0.0551757812500000, -0.0050964355468750, +-0.0611267089843750, -0.0108032226562500, -0.0741882324218750, -0.0073547363281250, +-0.0657653808593750, -0.0102539062500000, -0.0822753906250000, -0.0156555175781250, +-0.0821838378906250, -0.0039978027343750, -0.0815124511718750, 0.0037231445312500, +-0.0919799804687500, -0.0044555664062500, -0.0892333984375000, 0.0278320312500000, +-0.0793457031250000, 0.0286865234375000, -0.0897521972656250, 0.0249938964843750, +-0.0747985839843750, 0.0430908203125000, -0.0571594238281250, 0.0415649414062500, +-0.0730285644531250, 0.0108032226562500, -0.0319519042968750, 0.0209960937500000, +-0.0355529785156250, 0.0111999511718750, -0.0317993164062500, -0.0218811035156250, +-0.0048217773437500, -0.0096130371093750, -0.0156250000000000, -0.0015563964843750, +-0.0117187500000000, -0.0155029296875000, -0.0033569335937500, -0.0018310546875000, +-0.0180358886718750, 0.0250549316406250, -0.0287475585937500, 0.0114746093750000, +-0.0187377929687500, 0.0038146972656250, -0.0508728027343750, 0.0249633789062500, +-0.0451660156250000, -0.0062561035156250, -0.0596008300781250, -0.0453796386718750, +-0.0852966308593750, -0.0179138183593750, -0.0671997070312500, -0.0623168945312500, +-0.1113281250000000, -0.0778503417968750, -0.1163635253906250, -0.0517272949218750, +-0.0981140136718750, -0.0506286621093750, -0.1203308105468750, -0.0657043457031250, +-0.1269836425781250, -0.0102844238281250, -0.0226440429687500, -0.0137023925781250, +-0.0591430664062500, -0.0094604492187500, -0.0009460449218750, 0.0235290527343750, +0.1172180175781250, 0.0135498046875000, 0.0585327148437500, 0.0255432128906250, +0.1476745605468750, 0.0247497558593750, 0.1719055175781250, 0.0330505371093750, +0.1470642089843750, 0.0427551269531250, 0.1625976562500000, 0.0343933105468750, +0.1687927246093750, 0.0679931640625000, 0.1313476562500000, 0.0644226074218750, +0.1358337402343750, 0.0711364746093750, 0.1288146972656250, 0.0933837890625000, +0.1026000976562500, 0.0848083496093750, 0.1141357421875000, 0.1090087890625000, +0.1064758300781250, 0.0993957519531250, 0.0986328125000000, 0.1258850097656250, +0.1089477539062500, 0.1545715332031250, 0.1184692382812500, 0.1303405761718750, +0.1118774414062500, 0.2192993164062500, 0.1189270019531250, 0.2093200683593750, +0.1300964355468750, 0.2224731445312500, 0.1098632812500000, 0.2911682128906250, +0.0985717773437500, 0.2648620605468750, 0.1143188476562500, 0.2468261718750000, +0.0516662597656250, 0.2876281738281250, 0.0666198730468750, 0.2209167480468750, +0.0407104492187500, 0.1538391113281250, -0.0133056640625000, 0.2076110839843750, +0.0169677734375000, 0.0340270996093750, -0.0564575195312500, 0.0534973144531250, +-0.0493164062500000, 0.0149841308593750, -0.0711669921875000, -0.1090087890625000, +-0.1204528808593750, -0.0533447265625000, -0.0929870605468750, -0.1499633789062500, +-0.1819763183593750, -0.1605529785156250, -0.1653442382812500, -0.1542663574218750, +-0.1944274902343750, -0.1969909667968750, -0.2721557617187500, -0.1864929199218750, +-0.2317199707031250, -0.1756286621093750, -0.2748413085937500, -0.1884765625000000, +-0.2990112304687500, -0.1765136718750000, -0.2625122070312500, -0.1406860351562500, +-0.2252197265625000, -0.1572570800781250, -0.2272338867187500, -0.2667541503906250, +-0.2598876953125000, -0.2298278808593750, -0.2879028320312500, -0.2474365234375000, +-0.2376708984375000, -0.3086547851562500, -0.2023925781250000, -0.2915649414062500, +-0.2383422851562500, -0.2627258300781250, -0.1412658691406250, -0.2910461425781250, +-0.1349182128906250, -0.2511596679687500, -0.1497497558593750, -0.1971740722656250, +-0.1109924316406250, -0.2324218750000000, -0.1120300292968750, -0.1445007324218750, +-0.1462097167968750, -0.1487426757812500, -0.1443786621093750, -0.1263732910156250, +-0.1323852539062500, -0.0736389160156250, -0.1495056152343750, -0.1015319824218750, +-0.1547241210937500, -0.0009155273437500, -0.0947570800781250, -0.0269165039062500, +-0.1109924316406250, 0.0237426757812500, -0.0882873535156250, 0.1212768554687500, +-0.0346069335937500, 0.0617370605468750, -0.0592346191406250, 0.1755371093750000, +-0.0063171386718750, 0.1912841796875000, -0.0150146484375000, 0.1645812988281250, +0.0162353515625000, 0.2049865722656250, 0.0606994628906250, 0.2097473144531250, +0.0287170410156250, 0.1356811523437500, 0.1411132812500000, 0.1618041992187500, +0.1303710937500000, 0.1342773437500000, 0.1484680175781250, 0.0605163574218750, +0.2306823730468750, 0.0975036621093750, 0.1995239257812500, 0.0610656738281250, +0.2069702148437500, 0.0362243652343750, 0.2323913574218750, 0.0759582519531250, +0.2008361816406250, 0.0942687988281250, 0.1689758300781250, 0.0659790039062500, +0.1911315917968750, 0.1435241699218750, 0.1393127441406250, 0.1532592773437500, +0.1392822265625000, 0.1217651367187500, 0.1301879882812500, 0.1455383300781250, +0.1028747558593750, 0.1604003906250000, 0.1166381835937500, 0.0568237304687500, +0.0683288574218750, 0.0813903808593750, 0.0778503417968750, 0.0606994628906250, +0.0590209960937500, -0.0236206054687500, 0.0153503417968750, 0.0100097656250000, +0.0361633300781250, -0.0169372558593750, -0.0034484863281250, -0.0317077636718750, +-0.0056457519531250, -0.0230712890625000, -0.0102844238281250, -0.0227661132812500, +-0.0296630859375000, -0.0257568359375000, -0.0204162597656250, -0.0210876464843750, +-0.0493469238281250, -0.0235290527343750, -0.0474853515625000, -0.0188598632812500, +-0.0479431152343750, -0.0113220214843750, -0.0691223144531250, -0.0173034667968750, +-0.0637817382812500, -0.0133361816406250, -0.0426025390625000, -0.0093994140625000, +-0.0564575195312500, -0.0149230957031250, -0.0373229980468750, -0.0193176269531250, +-0.0034790039062500, -0.0155944824218750, -0.0211486816406250, -0.0223388671875000, +0.0034790039062500, -0.0233154296875000, 0.0105895996093750, -0.0251770019531250, +0.0048828125000000, -0.0276489257812500, 0.0067443847656250, -0.0256042480468750, +0.0080566406250000, -0.0369567871093750, 0.0164794921875000, -0.0338134765625000, +0.0095520019531250, -0.0394287109375000, 0.0187072753906250, -0.0501403808593750, +0.0361938476562500, -0.0446166992187500, 0.0271301269531250, -0.0605773925781250, +0.0303344726562500, -0.0594482421875000, 0.0407104492187500, -0.0637512207031250, +0.0249023437500000, -0.0767517089843750, 0.0096740722656250, -0.0724182128906250, +0.0213928222656250, -0.0786437988281250, -0.0065002441406250, -0.0840148925781250, +-0.0103759765625000, -0.0781555175781250, -0.0057678222656250, -0.0762939453125000, +-0.0148620605468750, -0.0821228027343750, -0.0148315429687500, -0.0633239746093750, +-0.0060119628906250, -0.0675354003906250, -0.0072937011718750, -0.0631408691406250, +-0.0060119628906250, -0.0485229492187500, -0.0000305175781250, -0.0565490722656250, +-0.0018310546875000, -0.0463562011718750, -0.0005493164062500, -0.0454406738281250, +0.0002746582031250, -0.0474548339843750, -0.0002136230468750, -0.0446472167968750, +-0.0003662109375000, -0.0465087890625000, -0.0002746582031250, -0.0461425781250000, +-0.0003051757812500, -0.0467834472656250, -0.0003051757812500, -0.0469055175781250, +-0.0003662109375000, -0.0464477539062500, -0.0003662109375000, -0.0475158691406250, +-0.0003356933593750, -0.0468444824218750, -0.0003662109375000, -0.0461730957031250, +-0.0003662109375000, -0.0474548339843750, -0.0003356933593750, -0.0484924316406250, +-0.0002441406250000, -0.0479125976562500, -0.0002746582031250, -0.0496215820312500, +-0.0008544921875000, -0.0506591796875000, -0.0001525878906250, -0.0498352050781250, +-0.0016784667968750, -0.0500488281250000, -0.0029296875000000, -0.0509948730468750, +-0.0014648437500000, -0.0465393066406250, -0.0060729980468750, -0.0477905273437500, +-0.0056762695312500, -0.0466308593750000, -0.0050964355468750, -0.0429687500000000, +-0.0083923339843750, -0.0455017089843750, -0.0077209472656250, -0.0441894531250000, +-0.0013732910156250, -0.0436706542968750, -0.0059509277343750, -0.0457763671875000, +0.0011596679687500, -0.0473022460937500, 0.0111389160156250, -0.0471496582031250, +0.0035095214843750, -0.0487060546875000, 0.0187988281250000, -0.0504760742187500, +0.0202636718750000, -0.0476074218750000, 0.0168457031250000, -0.0471191406250000, +0.0227966308593750, -0.0492858886718750, 0.0232543945312500, -0.0343322753906250, +0.0128173828125000, -0.0405883789062500, 0.0164489746093750, -0.0275878906250000, +0.0127563476562500, -0.0085449218750000, 0.0026855468750000, -0.0192565917968750, +0.0077514648437500, 0.0144348144531250, 0.0018005371093750, 0.0133056640625000, +0.0009155273437500, 0.0172424316406250, -0.0002746582031250, 0.0383300781250000, +-0.0020751953125000, 0.0312500000000000, -0.0003356933593750, 0.0399169921875000, +-0.0115356445312500, 0.0434875488281250, -0.0073852539062500, 0.0376281738281250, +-0.0129089355468750, 0.0379333496093750, -0.0250549316406250, 0.0394287109375000, +-0.0180664062500000, 0.0176696777343750, -0.0270080566406250, 0.0239868164062500, +-0.0297851562500000, 0.0104370117187500, -0.0270996093750000, -0.0132141113281250, +-0.0277709960937500, -0.0009765625000000, -0.0289916992187500, -0.0287780761718750, +-0.0294799804687500, -0.0327453613281250, -0.0273132324218750, -0.0276489257812500, +-0.0297851562500000, -0.0379943847656250, -0.0348510742187500, -0.0381164550781250, +-0.0315246582031250, -0.0206298828125000, -0.0249633789062500, -0.0224304199218750, +-0.0361328125000000, -0.0199890136718750, -0.0141296386718750, -0.0072631835937500, +0.0046386718750000}, +{0.0094909667968750, -0.0625000000000000, 0.0086669921875000, -0.0515136718750000, +0.0075988769531250, -0.0728759765625000, 0.0234985351562500, -0.0729980468750000, +0.0193786621093750, -0.0745544433593750, 0.0223083496093750, -0.0858764648437500, +0.0384826660156250, -0.0801696777343750, 0.0335998535156250, -0.0867919921875000, +0.0216064453125000, -0.0872497558593750, 0.0312194824218750, -0.0855712890625000, +0.0178527832031250, -0.0886230468750000, -0.0043945312500000, -0.0880432128906250, +0.0072326660156250, -0.0836486816406250, -0.0101928710937500, -0.0870056152343750, +-0.0158996582031250, -0.0799865722656250, -0.0097045898437500, -0.0727844238281250, +-0.0108032226562500, -0.0792236328125000, -0.0130004882812500, -0.0596313476562500, +-0.0042114257812500, -0.0623474121093750, -0.0040283203125000, -0.0579528808593750, +-0.0039062500000000, -0.0437927246093750, 0.0003662109375000, -0.0513305664062500, +-0.0006713867187500, -0.0419616699218750, -0.0002441406250000, -0.0421142578125000, +0.0001220703125000, -0.0426940917968750, -0.0000305175781250, -0.0393981933593750, +0.0000000000000000, -0.0431213378906250, -0.0000610351562500, -0.0383300781250000, +-0.0003967285156250, -0.0407714843750000, 0.0001525878906250, -0.0398559570312500, +-0.0010681152343750, -0.0360107421875000, -0.0019531250000000, -0.0404357910156250, +-0.0008544921875000, -0.0372619628906250, -0.0046997070312500, -0.0386657714843750, +-0.0041809082031250, -0.0405883789062500, -0.0043945312500000, -0.0406494140625000, +-0.0075988769531250, -0.0437316894531250, -0.0064392089843750, -0.0438537597656250, +-0.0029907226562500, -0.0457458496093750, -0.0067749023437500, -0.0451660156250000, +-0.0007324218750000, -0.0446777343750000, 0.0063476562500000, -0.0471801757812500, +0.0002441406250000, -0.0399780273437500, 0.0146484375000000, -0.0421752929687500, +0.0147399902343750, -0.0392150878906250, 0.0133056640625000, -0.0325317382812500, +0.0206909179687500, -0.0365905761718750, 0.0193481445312500, -0.0293273925781250, +0.0132446289062500, -0.0284729003906250, 0.0168762207031250, -0.0299377441406250, +0.0127563476562500, -0.0273132324218750, 0.0047912597656250, -0.0281066894531250, +0.0092773437500000, -0.0327453613281250, 0.0030517578125000, -0.0317687988281250, +0.0022583007812500, -0.0347595214843750, 0.0017089843750000, -0.0408020019531250, +-0.0002441406250000, -0.0389099121093750, 0.0010070800781250, -0.0390625000000000, +-0.0073242187500000, -0.0446166992187500, -0.0036926269531250, -0.0360717773437500, +-0.0090026855468750, -0.0286560058593750, -0.0187988281250000, -0.0353088378906250, +-0.0126037597656250, -0.0098876953125000, -0.0224609375000000, -0.0148010253906250, +-0.0242614746093750, -0.0026550292968750, -0.0223388671875000, 0.0193481445312500, +-0.0247192382812500, 0.0069885253906250, -0.0250549316406250, 0.0420532226562500, +-0.0254516601562500, 0.0411682128906250, -0.0239257812500000, 0.0434570312500000, +-0.0264892578125000, 0.0655212402343750, -0.0302124023437500, 0.0579528808593750, +-0.0269775390625000, 0.0534362792968750, -0.0258483886718750, 0.0633239746093750, +-0.0333862304687500, 0.0445251464843750, -0.0170898437500000, 0.0252990722656250, +-0.0063476562500000, 0.0378112792968750, -0.0193481445312500, -0.0068664550781250, +0.0352172851562500, -0.0080566406250000, 0.0196533203125000, -0.0072937011718750, +0.0447387695312500, -0.0296936035156250, 0.0944519042968750, -0.0252685546875000, +0.0640258789062500, -0.0223388671875000, 0.1328735351562500, -0.0253601074218750, +0.1288146972656250, -0.0219116210937500, 0.1360168457031250, -0.0183105468750000, +0.1812744140625000, -0.0203857421875000, 0.1618957519531250, -0.0048522949218750, +0.1688232421875000, -0.0073547363281250, 0.1876525878906250, -0.0066528320312500, +0.1589660644531250, 0.0062866210937500, 0.1368408203125000, 0.0037841796875000, +0.1597595214843750, -0.0079650878906250, 0.0918884277343750, -0.0034179687500000, +0.0957031250000000, -0.0061035156250000, 0.0937500000000000, -0.0174255371093750, +0.0540771484375000, -0.0145874023437500, 0.0652770996093750, -0.0165710449218750, +0.0604858398437500, -0.0132446289062500, 0.0595397949218750, -0.0241088867187500, +0.0490722656250000, -0.0306701660156250, 0.0458984375000000, -0.0216064453125000, +0.0558166503906250, -0.0625000000000000, 0.0044555664062500, -0.0546569824218750, +0.0165710449218750, -0.0668945312500000, 0.0011901855468750, -0.1002197265625000, +-0.0441589355468750, -0.0844116210937500, -0.0239257812500000, -0.1111450195312500, +-0.0469665527343750, -0.1132202148437500, -0.0523376464843750, -0.1136474609375000, +-0.0547790527343750, -0.1278686523437500, -0.0611877441406250, -0.1272888183593750, +-0.0616149902343750, -0.1372070312500000, -0.1064453125000000, -0.1350402832031250, +-0.0851745605468750, -0.1325988769531250, -0.1013793945312500, -0.1394653320312500, +-0.1478576660156250, -0.1381225585937500, -0.1253356933593750, -0.1244812011718750, +-0.1662902832031250, -0.1331176757812500, -0.1744995117187500, -0.1192321777343750, +-0.1646423339843750, -0.1006469726562500, -0.1755981445312500, -0.1142883300781250, +-0.1757812500000000, -0.0755920410156250, -0.1515502929687500, -0.0808715820312500, +-0.1590881347656250, -0.0698852539062500, -0.1444702148437500, -0.0418090820312500, +-0.1190490722656250, -0.0569458007812500, -0.1323242187500000, -0.0225219726562500, +-0.1002807617187500, -0.0263671875000000, -0.1011047363281250, -0.0161132812500000, +-0.0935058593750000, 0.0080871582031250, -0.0744934082031250, -0.0057983398437500, +-0.0842895507812500, 0.0308227539062500, -0.0505371093750000, 0.0242004394531250, +-0.0547180175781250, 0.0376586914062500, -0.0475463867187500, 0.0671997070312500, +-0.0217590332031250, 0.0502624511718750, -0.0312805175781250, 0.0912475585937500, +-0.0187072753906250, 0.0868835449218750, -0.0173034667968750, 0.0982055664062500, +-0.0145874023437500, 0.1272277832031250, -0.0076904296875000, 0.1125793457031250, +-0.0125122070312500, 0.1523742675781250, -0.0026855468750000, 0.1479492187500000, +-0.0003662109375000, 0.1557617187500000, -0.0027160644531250, 0.1868896484375000, +-0.0016784667968750, 0.1726684570312500, 0.0003662109375000, 0.1761169433593750, +0.0049133300781250, 0.1960144042968750, -0.0024719238281250, 0.1566467285156250, +0.0127868652343750, 0.1299133300781250, 0.0280151367187500, 0.1609191894531250, +0.0155029296875000, 0.0473327636718750, 0.0522766113281250, 0.0682678222656250, +0.0528869628906250, 0.0432739257812500, 0.0526428222656250, -0.0448913574218750, +0.0728454589843750, -0.0030822753906250, 0.0679321289062500, -0.0499877929687500, +0.0593566894531250, -0.0674743652343750, 0.0667114257812500, -0.0451049804687500, +0.0538330078125000, -0.0458374023437500, 0.0371398925781250, -0.0569152832031250, +0.0463256835937500, -0.0249938964843750, 0.0183410644531250, -0.0259399414062500, +0.0166625976562500, -0.0283203125000000, 0.0162658691406250, -0.0126342773437500, +0.0016174316406250, -0.0155334472656250, 0.0053100585937500, -0.0195617675781250, +0.0103759765625000, -0.0178527832031250, 0.0065002441406250, -0.0162963867187500, +0.0118408203125000, -0.0193786621093750, 0.0205688476562500, -0.0201721191406250, +0.0163269042968750, -0.0102844238281250, 0.0229187011718750, -0.0134887695312500, +0.0240783691406250, -0.0103149414062500, 0.0226745605468750, -0.0014038085937500, +0.0242614746093750, -0.0056762695312500, 0.0232238769531250, 0.0011596679687500, +0.0204162597656250, 0.0005798339843750, 0.0204162597656250, 0.0035400390625000, +0.0181884765625000, 0.0081787109375000, 0.0151062011718750, 0.0043945312500000, +0.0155944824218750, 0.0168151855468750, 0.0119934082031250, 0.0155639648437500, +0.0112915039062500, 0.0157470703125000, 0.0119323730468750, 0.0242309570312500, +0.0106506347656250, 0.0215454101562500, 0.0101623535156250, 0.0156250000000000, +0.0125427246093750, 0.0213623046875000, 0.0125122070312500, 0.0139770507812500, +0.0140380859375000, 0.0031433105468750, 0.0170898437500000, 0.0108337402343750, +0.0173339843750000, -0.0029907226562500, 0.0200500488281250, -0.0041503906250000, +0.0219726562500000, -0.0021362304687500, 0.0231323242187500, -0.0077209472656250, +0.0240478515625000, -0.0070495605468750, 0.0249328613281250, -0.0037231445312500, +0.0286254882812500, -0.0050659179687500, 0.0294494628906250, -0.0040893554687500, +0.0315246582031250, -0.0008544921875000, 0.0348510742187500, -0.0023193359375000, +0.0344848632812500, -0.0023193359375000, 0.0361328125000000, -0.0007324218750000, +0.0374145507812500, -0.0033874511718750, 0.0355224609375000, -0.0057678222656250, +0.0351257324218750, -0.0037231445312500, 0.0365295410156250, -0.0100708007812500, +0.0284423828125000, -0.0108642578125000, 0.0326843261718750, -0.0081176757812500, +0.0267944335937500, -0.0112609863281250, 0.0176391601562500, -0.0119628906250000, +0.0242004394531250, 0.0056152343750000, 0.0054931640625000, -0.0013122558593750, +0.0091247558593750, 0.0094299316406250, 0.0040893554687500, 0.0317077636718750, +-0.0106201171875000, 0.0204772949218750, -0.0021667480468750, 0.0298767089843750, +-0.0145263671875000, 0.0409545898437500, -0.0166320800781250, 0.0234680175781250, +-0.0135498046875000, 0.0092468261718750, -0.0173950195312500, 0.0214233398437500, +-0.0169067382812500, -0.0071105957031250, -0.0089721679687500, -0.0146179199218750, +-0.0128784179687500, -0.0016174316406250, -0.0078735351562500, -0.0030212402343750, +0.0003662109375000, -0.0107116699218750, -0.0058898925781250, 0.0114440917968750, +0.0089721679687500, 0.0184020996093750, 0.0087585449218750, 0.0011291503906250, +0.0079650878906250, -0.0003662109375000, 0.0175170898437500, 0.0105285644531250, +0.0150756835937500, -0.0381469726562500, 0.0027770996093750, -0.0371704101562500, +0.0115051269531250, -0.0328063964843750, -0.0022888183593750, -0.0595397949218750, +-0.0213928222656250, -0.0560607910156250, -0.0091247558593750, -0.0260314941406250, +-0.0424194335937500, -0.0382690429687500, -0.0391540527343750, -0.0244140625000000, +-0.0477600097656250, 0.0083923339843750, -0.0737304687500000, -0.0062866210937500, +-0.0603637695312500, 0.0126953125000000, -0.0692138671875000, 0.0158081054687500, +-0.0822448730468750, 0.0187988281250000, -0.0643005371093750, 0.0259399414062500, +-0.0476684570312500, 0.0205993652343750, -0.0622253417968750, 0.0440063476562500, +-0.0398254394531250, 0.0392456054687500, -0.0251770019531250, 0.0468139648437500, +-0.0507202148437500, 0.0666198730468750, -0.0671997070312500, 0.0581054687500000, +-0.0498352050781250, 0.0765075683593750, -0.0871582031250000, 0.0718994140625000, +-0.1000671386718750, 0.0880126953125000, -0.0781860351562500, 0.1050109863281250, +-0.0780029296875000, 0.0908508300781250, -0.0918884277343750, 0.1572570800781250, +-0.0397644042968750, 0.1453247070312500, -0.0476074218750000, 0.1631469726562500, +-0.0295104980468750, 0.2213439941406250, 0.0066528320312500, 0.1958923339843750, +-0.0151367187500000, 0.2031555175781250, 0.0545654296875000, 0.2318420410156250, +0.0447998046875000, 0.1837463378906250, 0.0577087402343750, 0.1460266113281250, +0.1124572753906250, 0.1807556152343750, 0.0911560058593750, 0.0560913085937500, +0.1011352539062500, 0.0729675292968750, 0.1159667968750000, 0.0370178222656250, +0.0995788574218750, -0.0581054687500000, 0.0838928222656250, -0.0120239257812500, +0.0949401855468750, -0.0971069335937500, 0.0765380859375000, -0.1035461425781250, +0.0724487304687500, -0.1040344238281250, 0.0791625976562500, -0.1463623046875000, +0.0767517089843750, -0.1333312988281250, 0.0749511718750000, -0.1390075683593750, +0.0861816406250000}, +{0.0683288574218750, -0.0061340332031250, 0.0687866210937500, -0.0069580078125000, +0.0661621093750000, -0.0064697265625000, 0.0655212402343750, -0.0113830566406250, +0.0659790039062500, -0.0100402832031250, 0.0632324218750000, -0.0112304687500000, +0.0651245117187500, -0.0121459960937500, 0.0627746582031250, -0.0103454589843750, +0.0646972656250000, -0.0108032226562500, 0.0675354003906250, -0.0115356445312500, +0.0644226074218750, 0.0001831054687500, 0.0738830566406250, -0.0055541992187500, +0.0718994140625000, 0.0051879882812500, 0.0728759765625000, 0.0218505859375000, +0.0797119140625000, 0.0113525390625000, 0.0758666992187500, 0.0309143066406250, +0.0760192871093750, 0.0373840332031250, 0.0790710449218750, 0.0252075195312500, +0.0740356445312500, 0.0254516601562500, 0.0699157714843750, 0.0323181152343750, +0.0733337402343750, 0.0004272460937500, 0.0601806640625000, 0.0009765625000000, +0.0649414062500000, 0.0042114257812500, 0.0570373535156250, -0.0129699707031250, +0.0445556640625000, -0.0118408203125000, 0.0538940429687500, 0.0066223144531250, +0.0274963378906250, 0.0052185058593750, 0.0337219238281250, 0.0008239746093750, +0.0240783691406250, 0.0127868652343750, 0.0023193359375000, 0.0139465332031250, +0.0158386230468750, -0.0215759277343750, -0.0140686035156250, -0.0127868652343750, +-0.0146789550781250, -0.0201110839843750, -0.0137634277343750, -0.0528869628906250, +-0.0303955078125000, -0.0419311523437500, -0.0270080566406250, -0.0312500000000000, +-0.0199584960937500, -0.0451965332031250, -0.0270996093750000, -0.0285644531250000, +-0.0203857421875000, -0.0029602050781250, -0.0082092285156250, -0.0174865722656250, +-0.0157470703125000, 0.0056762695312500, -0.0042114257812500, 0.0091552734375000, +-0.0019226074218750, 0.0098876953125000, -0.0103149414062500, 0.0176391601562500, +-0.0061950683593750, 0.0139770507812500, -0.0030212402343750, 0.0315856933593750, +-0.0425415039062500, 0.0265808105468750, -0.0282897949218750, 0.0347595214843750, +-0.0494995117187500, 0.0523376464843750, -0.0961303710937500, 0.0436401367187500, +-0.0748901367187500, 0.0608825683593750, -0.1000366210937500, 0.0583496093750000, +-0.1141662597656250, 0.0709533691406250, -0.1004638671875000, 0.0842895507812500, +-0.0926818847656250, 0.0728454589843750, -0.1004638671875000, 0.1275634765625000, +-0.0943908691406250, 0.1144104003906250, -0.0903930664062500, 0.1334838867187500, +-0.0903015136718750, 0.1855163574218750, -0.0952758789062500, 0.1610412597656250, +-0.0963745117187500, 0.1821289062500000, -0.0669555664062500, 0.2046203613281250, +-0.0766296386718750, 0.1664428710937500, -0.0694274902343750, 0.1456298828125000, +-0.0417175292968750, 0.1708679199218750, -0.0507812500000000, 0.0663146972656250, +-0.0438537597656250, 0.0830078125000000, -0.0487670898437500, 0.0505065917968750, +-0.0285644531250000, -0.0318908691406250, -0.0153503417968750, 0.0072937011718750, +-0.0331726074218750, -0.0727233886718750, 0.0425109863281250, -0.0769958496093750, +0.0326538085937500, -0.0801696777343750, 0.0449218750000000, -0.1223449707031250, +0.0993041992187500, -0.1083374023437500, 0.0780944824218750, -0.1181335449218750, +0.0951232910156250, -0.1265563964843750, 0.1055603027343750, -0.1199645996093750, +0.0954589843750000, -0.1144104003906250, 0.0921325683593750, -0.1197814941406250, +0.0972900390625000, -0.1215209960937500, 0.0825805664062500, -0.1103515625000000, +0.0820617675781250, -0.1329650878906250, 0.0845031738281250, -0.1514892578125000, +0.0782775878906250, -0.1336364746093750, 0.0787963867187500, -0.1971740722656250, +0.0872192382812500, -0.1925964355468750, 0.0875549316406250, -0.1983337402343750, +0.0804748535156250, -0.2412719726562500, 0.0859985351562500, -0.2267456054687500, +0.0897216796875000, -0.2182617187500000, 0.0440063476562500, -0.2341613769531250, +0.0608825683593750, -0.2160339355468750, 0.0409851074218750, -0.1702270507812500, +-0.0391540527343750, -0.0952148437500000, 0.0798339843750000, 0.0464782714843750, +0.0242004394531250, -0.0177917480468750, 0.0615539550781250, 0.0410461425781250, +0.0202026367187500, 0.1416931152343750, -0.0340270996093750, 0.0922546386718750, +-0.0036926269531250, 0.1491699218750000, -0.0728149414062500, 0.1781005859375000, +-0.0687866210937500, 0.1383972167968750, -0.0851745605468750, 0.1300659179687500, +-0.1295776367187500, 0.1537780761718750, -0.1064453125000000, 0.0634155273437500, +-0.1695251464843750, 0.0696411132812500, -0.1655578613281250, 0.0679931640625000, +-0.1680603027343750, 0.0124206542968750, -0.2116088867187500, 0.0277099609375000, +-0.1980285644531250, 0.0453796386718750, -0.1732482910156250, 0.0282287597656250, +-0.1977233886718750, 0.0454406738281250, -0.1634216308593750, 0.0775756835937500, +-0.1119384765625000, 0.0602111816406250, -0.1428222656250000, 0.0731811523437500, +-0.0917663574218750, 0.0834045410156250, -0.0786743164062500, 0.0753173828125000, +-0.0941467285156250, 0.0682373046875000, -0.0884399414062500, 0.0721740722656250, +-0.0827026367187500, 0.0714416503906250, -0.0927124023437500, 0.0739746093750000, +-0.1038513183593750, 0.0573730468750000, -0.0816040039062500, 0.0540771484375000, +-0.0679626464843750, 0.0662231445312500, -0.0848388671875000, -0.0146484375000000, +-0.0271301269531250, 0.0065612792968750, -0.0319519042968750, -0.0224304199218750, +-0.0202026367187500, -0.0957641601562500, 0.0158996582031250, -0.0604248046875000, +0.0001220703125000, -0.1188964843750000, 0.0474853515625000, -0.1259460449218750, +0.0369262695312500, -0.1199645996093750, 0.0622253417968750, -0.1459655761718750, +0.1084899902343750, -0.1390686035156250, 0.0817260742187500, -0.1142883300781250, +0.1423645019531250, -0.1366577148437500, 0.1500549316406250, -0.1021728515625000, +0.1381225585937500, -0.0568237304687500, 0.1609497070312500, -0.0920715332031250, +0.1619873046875000, -0.0202636718750000, 0.1248474121093750, -0.0134582519531250, +0.1352844238281250, -0.0295410156250000, 0.1206665039062500, -0.0029907226562500, +0.0873413085937500, -0.0013427734375000, 0.1028442382812500, -0.0404357910156250, +0.0687561035156250, -0.0266723632812500, 0.0722656250000000, -0.0425720214843750, +0.0598754882812500, -0.0779724121093750, 0.0339050292968750, -0.0576477050781250, +0.0487060546875000, -0.0997619628906250, 0.0104064941406250, -0.1006469726562500, +0.0113220214843750, -0.0957946777343750, 0.0074462890625000, -0.1182861328125000, +-0.0144348144531250, -0.1141052246093750, -0.0063781738281250, -0.0889282226562500, +-0.0235290527343750, -0.1049499511718750, -0.0210876464843750, -0.0805053710937500, +-0.0274353027343750, -0.0485839843750000, -0.0431518554687500, -0.0740661621093750, +-0.0342407226562500, -0.0041503906250000, -0.0418701171875000, -0.0193786621093750, +-0.0509033203125000, 0.0023498535156250, -0.0354309082031250, 0.0581054687500000, +-0.0244445800781250, 0.0242309570312500, -0.0356140136718750, 0.0858764648437500, +-0.0043640136718750, 0.0846862792968750, -0.0028991699218750, 0.0862731933593750, +-0.0046997070312500, 0.1208496093750000, 0.0083312988281250, 0.1063537597656250, +0.0061035156250000, 0.1130676269531250, 0.0090637207031250, 0.1215820312500000, +0.0056152343750000, 0.1092834472656250, 0.0142822265625000, 0.1029052734375000, +0.0240478515625000, 0.1113891601562500, 0.0162048339843750, 0.0809936523437500, +0.0323486328125000, 0.0903625488281250, 0.0376892089843750, 0.0784912109375000, +0.0276489257812500, 0.0527954101562500, 0.0274658203125000, 0.0699157714843750, +0.0327758789062500, 0.0310974121093750, 0.0061035156250000, 0.0380249023437500, +0.0083007812500000, 0.0297546386718750, 0.0045471191406250, 0.0025634765625000, +-0.0135498046875000, 0.0208740234375000, -0.0079650878906250, -0.0049133300781250, +-0.0114440917968750, -0.0033264160156250, -0.0143432617187500, -0.0009155273437500, +-0.0113830566406250, -0.0114440917968750, -0.0095825195312500, -0.0028076171875000, +-0.0106201171875000, -0.0080261230468750, -0.0060424804687500, -0.0047912597656250, +-0.0074157714843750, -0.0035095214843750, -0.0039062500000000, -0.0063171386718750, +0.0005798339843750, -0.0000915527343750, -0.0031127929687500, -0.0009155273437500, +0.0078735351562500, 0.0017395019531250, 0.0064392089843750, 0.0065002441406250, +0.0078735351562500, 0.0086975097656250, 0.0158081054687500, 0.0135498046875000, +0.0124206542968750, 0.0249633789062500, 0.0130310058593750, 0.0231933593750000, +0.0160217285156250, 0.0330505371093750, 0.0126037597656250, 0.0466613769531250, +0.0090942382812500, 0.0422973632812500, 0.0120239257812500, 0.0611572265625000, +0.0059204101562500, 0.0613098144531250, 0.0057678222656250, 0.0637207031250000, +0.0053710937500000, 0.0757141113281250, 0.0027770996093750, 0.0727844238281250, +0.0039367675781250, 0.0760803222656250, -0.0012817382812500, 0.0789489746093750, +0.0010681152343750, 0.0754089355468750, -0.0033264160156250, 0.0740661621093750, +-0.0097045898437500, 0.0761108398437500, -0.0048828125000000, 0.0634765625000000, +-0.0154113769531250, 0.0661621093750000, -0.0154418945312500, 0.0582580566406250, +-0.0152587890625000, 0.0451660156250000, -0.0205383300781250, 0.0505676269531250, +-0.0191040039062500, 0.0309143066406250, -0.0206604003906250, 0.0319519042968750, +-0.0203247070312500, 0.0247192382812500, -0.0219421386718750, 0.0097961425781250, +-0.0240478515625000, 0.0162353515625000, -0.0219726562500000, -0.0032958984375000, +-0.0248718261718750, -0.0032958984375000, -0.0274658203125000, -0.0059204101562500, +-0.0202026367187500, -0.0181579589843750, -0.0187683105468750, -0.0142517089843750, +-0.0236816406250000, -0.0195617675781250, 0.0065002441406250, -0.0225524902343750, +-0.0056152343750000, -0.0172424316406250, 0.0152893066406250, -0.0166625976562500, +0.0475463867187500, -0.0200805664062500, 0.0252990722656250, -0.0019836425781250, +0.0851745605468750, -0.0063781738281250, 0.0772094726562500, 0.0027770996093750, +0.0914306640625000, 0.0184020996093750, 0.1362915039062500, 0.0096130371093750, +0.1133117675781250, 0.0406188964843750, 0.1439514160156250, 0.0366821289062500, +0.1546630859375000, 0.0430297851562500, 0.1367187500000000, 0.0684509277343750, +0.1392822265625000, 0.0585632324218750, 0.1495666503906250, 0.0569152832031250, +0.1015930175781250, 0.0650024414062500, 0.1115417480468750, 0.0559997558593750, +0.1004638671875000, 0.0446166992187500, 0.0615234375000000, 0.0500183105468750, +0.0785217285156250, 0.0314636230468750, 0.0621643066406250, 0.0354614257812500, +0.0563964843750000, 0.0266723632812500, 0.0561828613281250, 0.0063476562500000, +0.0557861328125000, 0.0165100097656250, 0.0576171875000000, 0.0136718750000000, +0.0264892578125000, 0.0030212402343750, 0.0420532226562500, 0.0148620605468750, +0.0198974609375000, 0.0315551757812500, -0.0205078125000000, 0.0227050781250000, +0.0028381347656250, 0.0252990722656250, -0.0385131835937500, 0.0358276367187500, +-0.0438537597656250, 0.0232238769531250, -0.0408630371093750, 0.0090942382812500, +-0.0535888671875000, 0.0194396972656250, -0.0513610839843750, 0.0009155273437500, +-0.0719909667968750, -0.0010986328125000, -0.0588684082031250, -0.0015563964843750, +-0.0838623046875000, -0.0077514648437500, -0.1172485351562500, -0.0046081542968750, +-0.0924377441406250, -0.0193176269531250, -0.1463928222656250, -0.0130310058593750, +-0.1508178710937500, -0.0239562988281250, -0.1437683105468750, -0.0456237792968750, +-0.1660461425781250, -0.0448608398437500, -0.1626586914062500, -0.0786437988281250, +-0.1435852050781250, -0.0679016113281250, -0.1524047851562500, -0.0714721679687500, +-0.1456298828125000}, +{0.0130920410156250, -0.0973815917968750, 0.0098571777343750, -0.0945434570312500, +0.0088500976562500, -0.0953063964843750, 0.0110168457031250, -0.0955810546875000, +0.0056762695312500, -0.0962829589843750, 0.0059509277343750, -0.0934448242187500, +0.0054626464843750, -0.0919494628906250, 0.0028381347656250, -0.0927124023437500, +0.0039367675781250, -0.0800476074218750, -0.0001831054687500, -0.0836486816406250, +0.0016784667968750, -0.0747375488281250, -0.0019531250000000, -0.0613708496093750, +-0.0068969726562500, -0.0675354003906250, -0.0028686523437500, -0.0406188964843750, +-0.0127868652343750, -0.0442199707031250, -0.0123291015625000, -0.0328979492187500, +-0.0128173828125000, -0.0106201171875000, -0.0184936523437500, -0.0205688476562500, +-0.0164184570312500, 0.0118408203125000, -0.0185241699218750, 0.0104675292968750, +-0.0186767578125000, 0.0192260742187500, -0.0196533203125000, 0.0430603027343750, +-0.0212097167968750, 0.0340270996093750, -0.0198059082031250, 0.0525817871093750, +-0.0226745605468750, 0.0555725097656250, -0.0241394042968750, 0.0525207519531250, +-0.0195312500000000, 0.0592956542968750, -0.0197143554687500, 0.0578613281250000, +-0.0225524902343750, 0.0466613769531250, -0.0010681152343750, 0.0522155761718750, +-0.0110778808593750, 0.0396728515625000, 0.0061645507812500, 0.0238037109375000, +0.0304565429687500, 0.0330200195312500, 0.0124511718750000, -0.0003967285156250, +0.0646972656250000, 0.0024108886718750, 0.0553283691406250, -0.0061035156250000, +0.0715332031250000, -0.0313415527343750, 0.1137390136718750, -0.0203857421875000, +0.0904541015625000, -0.0335693359375000, 0.1287231445312500, -0.0409851074218750, +0.1354980468750000, -0.0302734375000000, 0.1234741210937500, -0.0259094238281250, +0.1355590820312500, -0.0314636230468750, 0.1388244628906250, -0.0097351074218750, +0.1032714843750000, -0.0132141113281250, 0.1153869628906250, -0.0024414062500000, +0.1020202636718750, 0.0154724121093750, 0.0673217773437500, 0.0035705566406250, +0.0849304199218750, 0.0335083007812500, 0.0635070800781250, 0.0353393554687500, +0.0582275390625000, 0.0314331054687500, 0.0603637695312500, 0.0430297851562500, +0.0575866699218750, 0.0422973632812500, 0.0582580566406250, 0.0406799316406250, +0.0367126464843750, 0.0394897460937500, 0.0502929687500000, 0.0389404296875000, +0.0277099609375000, 0.0419921875000000, -0.0048828125000000, 0.0416564941406250, +0.0180969238281250, 0.0251464843750000, -0.0306396484375000, 0.0287780761718750, +-0.0330810546875000, 0.0278015136718750, -0.0313720703125000, 0.0135192871093750, +-0.0521850585937500, 0.0160217285156250, -0.0479736328125000, 0.0287780761718750, +-0.0625915527343750, 0.0249023437500000, -0.0533752441406250, 0.0256042480468750, +-0.0744934082031250, 0.0371398925781250, -0.0977172851562500, 0.0355529785156250, +-0.0760803222656250, 0.0261535644531250, -0.1331176757812500, 0.0310974121093750, +-0.1323242187500000, 0.0257568359375000, -0.1311645507812500, 0.0150451660156250, +-0.1628112792968750, 0.0207824707031250, -0.1553039550781250, 0.0084533691406250, +-0.1458435058593750, 0.0106201171875000, -0.1545715332031250, 0.0056152343750000, +-0.1457519531250000, -0.0055541992187500, -0.1282653808593750, -0.0054321289062500, +-0.1296691894531250, -0.0312194824218750, -0.1086730957031250, -0.0190429687500000, +-0.1183471679687500, -0.0289306640625000, -0.1072692871093750, -0.0527648925781250, +-0.0857849121093750, -0.0367431640625000, -0.0983581542968750, -0.0717468261718750, +-0.0576782226562500, -0.0693664550781250, -0.0597839355468750, -0.0727233886718750, +-0.0503540039062500, -0.0937194824218750, -0.0242614746093750, -0.0842285156250000, +-0.0349426269531250, -0.0976562500000000, 0.0010375976562500, -0.0979309082031250, +-0.0027770996093750, -0.0996093750000000, 0.0062255859375000, -0.1075134277343750, +0.0378417968750000, -0.1032409667968750, 0.0259094238281250, -0.1094970703125000, +0.0207519531250000, -0.1119689941406250, 0.0340576171875000, -0.1073303222656250, +0.0209655761718750, -0.1083374023437500, -0.0030517578125000, -0.1109313964843750, +0.0083312988281250, -0.0917663574218750, 0.0102233886718750, -0.0989685058593750, +-0.0016479492187500, -0.0874328613281250, 0.0119628906250000, -0.0679016113281250, +0.0297851562500000, -0.0806579589843750, 0.0187988281250000, -0.0493164062500000, +0.0389099121093750, -0.0532531738281250, 0.0414123535156250, -0.0429992675781250, +0.0370178222656250, -0.0203247070312500, 0.0454101562500000, -0.0335083007812500, +0.0447692871093750, 0.0015869140625000, 0.0243225097656250, -0.0040893554687500, +0.0324096679687500, 0.0076599121093750, 0.0215454101562500, 0.0345764160156250, +-0.0008544921875000, 0.0190734863281250, 0.0107727050781250, 0.0561828613281250, +-0.0090026855468750, 0.0520324707031250, -0.0114746093750000, 0.0616760253906250, +-0.0091552734375000, 0.0882568359375000, -0.0162353515625000, 0.0742492675781250, +-0.0146179199218750, 0.1040649414062500, -0.0139465332031250, 0.1016235351562500, +-0.0148010253906250, 0.1069946289062500, -0.0128784179687500, 0.1268615722656250, +-0.0127563476562500, 0.1168823242187500, -0.0134582519531250, 0.1345520019531250, +-0.0004272460937500, 0.1377258300781250, -0.0067443847656250, 0.1288452148437500, +0.0052795410156250, 0.1352844238281250, 0.0236206054687500, 0.1382141113281250, +0.0135192871093750, 0.0997314453125000, 0.0401916503906250, 0.1190185546875000, +0.0420227050781250, 0.0885314941406250, 0.0422668457031250, 0.0427551269531250, +0.0559997558593750, 0.0766601562500000, 0.0516052246093750, -0.0028076171875000, +0.0454101562500000, 0.0013427734375000, 0.0514831542968750, -0.0016784667968750, +0.0368957519531250, -0.0490722656250000, 0.0220642089843750, -0.0317382812500000, +0.0304870605468750, -0.0366516113281250, -0.0083312988281250, -0.0482177734375000, +-0.0045776367187500, -0.0360412597656250, -0.0198364257812500, -0.0241088867187500, +-0.0523681640625000, -0.0332946777343750, -0.0398559570312500, -0.0173034667968750, +-0.0742187500000000, -0.0143737792968750, -0.0779418945312500, -0.0177612304687500, +-0.0803222656250000, -0.0140075683593750, -0.0982971191406250, -0.0133056640625000, +-0.0946655273437500, -0.0144958496093750, -0.0986938476562500, -0.0164794921875000, +-0.1026611328125000, -0.0123901367187500, -0.0982055664062500, -0.0095825195312500, +-0.0953979492187500, -0.0130615234375000, -0.0982971191406250, -0.0029907226562500, +-0.0875244140625000, -0.0040588378906250, -0.0879821777343750, -0.0030517578125000, +-0.0842895507812500, 0.0031738281250000, -0.0755310058593750, 0.0005493164062500, +-0.0780029296875000, 0.0045471191406250, -0.0714111328125000, 0.0039367675781250, +-0.0701904296875000, 0.0059814453125000, -0.0682678222656250, 0.0091857910156250, +-0.0645141601562500, 0.0068054199218750, -0.0654907226562500, 0.0144653320312500, +-0.0592346191406250, 0.0131835937500000, -0.0584106445312500, 0.0160522460937500, +-0.0563049316406250, 0.0225524902343750, -0.0521850585937500, 0.0195312500000000, +-0.0525207519531250, 0.0263977050781250, -0.0468444824218750, 0.0281677246093750, +-0.0480651855468750, 0.0247497558593750, -0.0436096191406250, 0.0272216796875000, +-0.0388183593750000, 0.0286560058593750, -0.0425720214843750, 0.0104370117187500, +-0.0258178710937500, 0.0164794921875000, -0.0299072265625000, 0.0077514648437500, +-0.0219116210937500, -0.0130310058593750, -0.0066528320312500, -0.0032043457031250, +-0.0153198242187500, -0.0090942382812500, 0.0057678222656250, -0.0178222656250000, +0.0029296875000000, -0.0070800781250000, 0.0097961425781250, 0.0046081542968750, +0.0255737304687500, -0.0036926269531250, 0.0163574218750000, 0.0009460449218750, +0.0384216308593750, 0.0117187500000000, 0.0374450683593750, -0.0060729980468750, +0.0379028320312500, -0.0233154296875000, 0.0523986816406250, -0.0103149414062500, +0.0485839843750000, -0.0379943847656250, 0.0421142578125000, -0.0461730957031250, +0.0498657226562500, -0.0328979492187500, 0.0421447753906250, -0.0341186523437500, +0.0292968750000000, -0.0410461425781250, 0.0379943847656250, -0.0131225585937500, +0.0245666503906250, -0.0140991210937500, 0.0212707519531250, -0.0120849609375000, +0.0247192382812500, 0.0026855468750000, 0.0228271484375000, -0.0017700195312500, +0.0211181640625000, 0.0103759765625000, 0.0195922851562500, 0.0070495605468750, +0.0232238769531250, 0.0154418945312500, 0.0148010253906250, 0.0288391113281250, +0.0079650878906250, 0.0202941894531250, 0.0141906738281250, 0.0400695800781250, +-0.0108337402343750, 0.0395202636718750, -0.0053100585937500, 0.0443420410156250, +-0.0167236328125000, 0.0542907714843750, -0.0390319824218750, 0.0484924316406250, +-0.0259399414062500, 0.0801086425781250, -0.0542907714843750, 0.0680236816406250, +-0.0557556152343750, 0.0903625488281250, -0.0556945800781250, 0.1282958984375000, +-0.0693664550781250, 0.1042175292968750, -0.0665588378906250, 0.1469726562500000, +-0.0722961425781250, 0.1582336425781250, -0.0697326660156250, 0.1383361816406250, +-0.0781860351562500, 0.1463012695312500, -0.0879821777343750, 0.1545715332031250, +-0.0799560546875000, 0.0916442871093750, -0.0979309082031250, 0.1101379394531250, +-0.1020507812500000, 0.0821228027343750, -0.0959472656250000, 0.0231933593750000, +-0.0974426269531250, 0.0532226562500000, -0.1016845703125000, -0.0196838378906250, +-0.1018676757812500, -0.0197753906250000, -0.0959777832031250, -0.0277099609375000, +-0.1038208007812500, -0.0705566406250000, -0.1192321777343750, -0.0541992187500000, +-0.1125183105468750, -0.0756835937500000, -0.0941467285156250, -0.0812683105468750, +-0.1133422851562500, -0.0786132812500000, -0.0893554687500000, -0.0833129882812500, +-0.0484619140625000, -0.0832519531250000, -0.0718383789062500, -0.0924072265625000, +-0.0476379394531250, -0.0850524902343750, -0.0368347167968750, -0.1019592285156250, +-0.0424499511718750, -0.1196289062500000, -0.0468750000000000, -0.1055908203125000, +-0.0463867187500000, -0.1523742675781250, -0.0201721191406250, -0.1490173339843750, +-0.0344543457031250, -0.1538696289062500, -0.0147094726562500, -0.1848754882812500, +0.0200195312500000, -0.1734924316406250, 0.0000000000000000, -0.1751708984375000, +0.0405273437500000, -0.1861572265625000, 0.0411682128906250, -0.1704406738281250, +0.0468750000000000, -0.1573486328125000, 0.0696105957031250, -0.1676025390625000, +0.0586853027343750, -0.1236877441406250, 0.0811767578125000, -0.1365051269531250, +0.0832824707031250, -0.1048278808593750, 0.0790710449218750, -0.0617675781250000, +0.0888671875000000, -0.0904235839843750, 0.0888977050781250, 0.0172119140625000, +0.0744018554687500, 0.0038146972656250, 0.0784301757812500, 0.0208435058593750, +0.0772094726562500, 0.1432495117187500, 0.0607299804687500, 0.1198120117187500, +0.0916137695312500, 0.0338134765625000, 0.0726623535156250, 0.0552368164062500, +0.0826110839843750, 0.0531005859375000, 0.0770568847656250, 0.0175476074218750, +0.0628662109375000, 0.0221252441406250, 0.0672302246093750, 0.0545654296875000, +0.0681457519531250, 0.0426940917968750, 0.0699768066406250, 0.0521545410156250, +0.0598144531250000, 0.0844421386718750, 0.0585937500000000, 0.0715026855468750, +0.0661926269531250, 0.0709228515625000, 0.0122985839843750, 0.0812072753906250, +0.0288696289062500, 0.0699462890625000, 0.0028686523437500, 0.0544128417968750, +-0.0500488281250000, 0.0630798339843750, -0.0216369628906250, 0.0546264648437500, +-0.0820312500000000, 0.0493774414062500, -0.0805358886718750, 0.0514831542968750, +-0.0920410156250000, 0.0579833984375000, -0.1294555664062500, 0.0543212890625000, +-0.1104431152343750}, +{0.0291748046875000, 0.0158691406250000, 0.0409240722656250, 0.0352172851562500, +0.0106506347656250, 0.0349121093750000, 0.0127563476562500, 0.0376892089843750, +0.0093078613281250, 0.0471801757812500, -0.0088806152343750, 0.0433349609375000, +-0.0011291503906250, 0.0637207031250000, -0.0149536132812500, 0.0536499023437500, +-0.0149536132812500, 0.0741271972656250, -0.0158081054687500, 0.1026000976562500, +-0.0242919921875000, 0.0825195312500000, -0.0214843750000000, 0.1295471191406250, +-0.0236206054687500, 0.1338500976562500, -0.0260009765625000, 0.1235656738281250, +-0.0230407714843750, 0.1437072753906250, -0.0205688476562500, 0.1442871093750000, +-0.0231628417968750, 0.1029357910156250, -0.0198364257812500, 0.1208801269531250, +-0.0162963867187500, 0.0910644531250000, -0.0249023437500000, 0.0421447753906250, +-0.0276184082031250, 0.0706787109375000, -0.0230102539062500, 0.0014343261718750, +-0.0597534179687500, 0.0042724609375000, -0.0494689941406250, -0.0042419433593750, +-0.0663146972656250, -0.0468139648437500, -0.1050109863281250, -0.0300598144531250, +-0.0872802734375000, -0.0575561523437500, -0.1079101562500000, -0.0623474121093750, +-0.1180725097656250, -0.0610351562500000, -0.1100158691406250, -0.0699462890625000, +-0.1067199707031250, -0.0676574707031250, -0.1103820800781250, -0.0789489746093750, +-0.1119079589843750, -0.0723266601562500, -0.1135253906250000, -0.0867309570312500, +-0.1024475097656250, -0.1037292480468750, -0.1014099121093750, -0.0909423828125000, +-0.1116027832031250, -0.1320190429687500, -0.0614929199218750, -0.1294555664062500, +-0.0661315917968750, -0.1344299316406250, -0.0667724609375000, -0.1618652343750000, +-0.0367431640625000, -0.1517333984375000, -0.0425109863281250, -0.1548461914062500, +-0.0496215820312500, -0.1633300781250000, -0.0520019531250000, -0.1513977050781250, +-0.0386962890625000, -0.1430053710937500, -0.0362854003906250, -0.1502380371093750, +-0.0471801757812500, -0.1141662597656250, 0.0024719238281250, -0.1268615722656250, +-0.0050048828125000, -0.0975341796875000, 0.0054931640625000, -0.0599060058593750, +0.0419311523437500, -0.0862426757812500, 0.0266723632812500, 0.0144042968750000, +0.0500488281250000, -0.0012207031250000, 0.0506591796875000, 0.0282287597656250, +0.0558471679687500, 0.1120300292968750, 0.0692443847656250, 0.0736083984375000, +0.0603637695312500, 0.1167907714843750, 0.0827636718750000, 0.1404113769531250, +0.0833435058593750, 0.1120605468750000, 0.0795593261718750, 0.0860900878906250, +0.0923156738281250, 0.0251770019531250, 0.0606079101562500, 0.0625000000000000, +0.0836486816406250, 0.0404968261718750, 0.0797729492187500, 0.0559082031250000, +0.0776367187500000, 0.0890808105468750, 0.0860900878906250, 0.0771789550781250, +0.0879516601562500, 0.0769348144531250, 0.0699768066406250, 0.0862731933593750, +0.0732116699218750, 0.0773620605468750, 0.0719299316406250, 0.0643920898437500, +0.0594787597656250, 0.0711975097656250, 0.0626525878906250, 0.0656127929687500, +0.0621643066406250, 0.0625915527343750, 0.0649719238281250, 0.0601196289062500, +0.0523986816406250, 0.0625305175781250, 0.0477905273437500, 0.0627746582031250, +0.0577697753906250, 0.0270690917968750, 0.0046997070312500, 0.0472412109375000, +0.0183410644531250, 0.0097656250000000, -0.0044860839843750, -0.0404968261718750, +-0.0534362792968750, -0.0033264160156250, -0.0280761718750000, -0.0940856933593750, +-0.0812072753906250, -0.0987548828125000, -0.0799560546875000, -0.0855102539062500, +-0.0894470214843750, -0.1271667480468750, -0.1229858398437500, -0.1261596679687500, +-0.1068725585937500, -0.0838928222656250, -0.1356506347656250, -0.0945739746093750, +-0.1427001953125000, -0.0949401855468750, -0.1286621093750000, -0.0619812011718750, +-0.1351013183593750, -0.0685424804687500, -0.1413574218750000, -0.0969848632812500, +-0.0931396484375000, -0.0826416015625000, -0.1033935546875000, -0.0985107421875000, +-0.0901489257812500, -0.1321411132812500, -0.0486145019531250, -0.1142883300781250, +-0.0656433105468750, -0.1380310058593750, -0.0512084960937500, -0.1495056152343750, +-0.0442810058593750, -0.1275024414062500, -0.0474853515625000, -0.1244201660156250, +-0.0503234863281250, -0.1398925781250000, -0.0502624511718750, -0.0793151855468750, +-0.0304870605468750, -0.0921630859375000, -0.0422363281250000, -0.0766906738281250, +-0.0234985351562500, -0.0301513671875000, 0.0057373046875000, -0.0549011230468750, +-0.0112609863281250, -0.0147094726562500, 0.0289611816406250, -0.0121765136718750, +0.0270690917968750, -0.0145263671875000, 0.0370788574218750, 0.0030517578125000, +0.0618896484375000, -0.0021057128906250, 0.0485534667968750, 0.0045166015625000, +0.0906982421875000, 0.0036621093750000, 0.0862731933593750, 0.0060424804687500, +0.0931396484375000, 0.0111389160156250, 0.1254577636718750, 0.0078430175781250, +0.1134948730468750, 0.0188293457031250, 0.1127319335937500, 0.0165405273437500, +0.1254882812500000, 0.0198669433593750, 0.1075439453125000, 0.0298461914062500, +0.0882263183593750, 0.0245056152343750, 0.1015625000000000, 0.0263977050781250, +0.0675964355468750, 0.0319213867187500, 0.0695190429687500, 0.0237121582031250, +0.0612792968750000, 0.0179138183593750, 0.0401916503906250, 0.0246582031250000, +0.0515136718750000, 0.0017089843750000, 0.0184020996093750, 0.0088195800781250, +0.0223999023437500, -0.0016174316406250, 0.0144042968750000, -0.0219116210937500, +-0.0105285644531250, -0.0074768066406250, 0.0002441406250000, -0.0385742187500000, +-0.0185546875000000, -0.0337219238281250, -0.0190734863281250, -0.0405578613281250, +-0.0231018066406250, -0.0620727539062500, -0.0345153808593750, -0.0483398437500000, +-0.0282592773437500, -0.0712280273437500, -0.0419311523437500, -0.0711975097656250, +-0.0454406738281250, -0.0699462890625000, -0.0377502441406250, -0.0819091796875000, +-0.0397033691406250, -0.0775146484375000, -0.0436096191406250, -0.0745544433593750, +-0.0192565917968750, -0.0796203613281250, -0.0221862792968750, -0.0728149414062500, +-0.0177917480468750, -0.0649414062500000, -0.0006103515625000, -0.0712280273437500, +-0.0065307617187500, -0.0558776855468750, 0.0006713867187500, -0.0581359863281250, +-0.0001220703125000, -0.0565490722656250, 0.0048522949218750, -0.0475158691406250, +0.0109252929687500, -0.0540161132812500, 0.0054626464843750, -0.0475769042968750, +0.0248718261718750, -0.0489807128906250, 0.0249633789062500, -0.0491027832031250, +0.0241699218750000, -0.0459899902343750, 0.0354309082031250, -0.0504150390625000, +0.0338134765625000, -0.0462341308593750, 0.0237426757812500, -0.0474853515625000, +0.0289001464843750, -0.0498657226562500, 0.0217895507812500, -0.0485534667968750, +0.0088195800781250, -0.0507812500000000, 0.0154113769531250, -0.0575256347656250, +0.0018920898437500, -0.0576171875000000, 0.0010986328125000, -0.0617980957031250, +0.0000610351562500, -0.0689697265625000, -0.0064392089843750, -0.0689392089843750, +-0.0033264160156250, -0.0747375488281250, -0.0094299316406250, -0.0754699707031250, +-0.0087280273437500, -0.0781860351562500, -0.0096740722656250, -0.0822753906250000, +-0.0139160156250000, -0.0813598632812500, -0.0118408203125000, -0.0884399414062500, +-0.0147094726562500, -0.0870361328125000, -0.0150146484375000, -0.0898437500000000, +-0.0152587890625000, -0.0964660644531250, -0.0165100097656250, -0.0938110351562500, +-0.0157470703125000, -0.0994567871093750, -0.0177917480468750, -0.1007690429687500, +-0.0179748535156250, -0.0997619628906250, -0.0165100097656250, -0.1011962890625000, +-0.0178527832031250, -0.1010437011718750, -0.0182495117187500, -0.0983886718750000, +-0.0085144042968750, -0.0986633300781250, -0.0145568847656250, -0.0987548828125000, +-0.0033569335937500, -0.0976562500000000, 0.0094299316406250, -0.0977478027343750, +-0.0013122558593750, -0.0959777832031250, 0.0349731445312500, -0.0982055664062500, +0.0259399414062500, -0.0922546386718750, 0.0416564941406250, -0.0876464843750000, +0.0735168457031250, -0.0916748046875000, 0.0535888671875000, -0.0709533691406250, +0.0964050292968750, -0.0758666992187500, 0.0962524414062500, -0.0648498535156250, +0.0949096679687500, -0.0454101562500000, 0.1188659667968750, -0.0559692382812500, +0.1120300292968750, -0.0254821777343750, 0.1020507812500000, -0.0274353027343750, +0.1135559082031250, -0.0199890136718750, 0.0989074707031250, 0.0014648437500000, +0.0777893066406250, -0.0083923339843750, 0.0922241210937500, 0.0098571777343750, +0.0669860839843750, 0.0147399902343750, 0.0641784667968750, 0.0057067871093750, +0.0663757324218750, 0.0083923339843750, 0.0584716796875000, 0.0124816894531250, +0.0600280761718750, -0.0136718750000000, 0.0494079589843750, -0.0114440917968750, +0.0582275390625000, -0.0160827636718750, 0.0402526855468750, -0.0332946777343750, +0.0211486816406250, -0.0274963378906250, 0.0388183593750000, -0.0395812988281250, +-0.0112609863281250, -0.0417175292968750, -0.0065307617187500, -0.0365600585937500, +-0.0123291015625000, -0.0413513183593750, -0.0449829101562500, -0.0443420410156250, +-0.0325927734375000, -0.0223693847656250, -0.0474548339843750, -0.0251464843750000, +-0.0481872558593750, -0.0252380371093750, -0.0568237304687500, -0.0126647949218750, +-0.0652770996093750, -0.0145263671875000, -0.0561523437500000, -0.0097961425781250, +-0.0989074707031250, -0.0140075683593750, -0.0880737304687500, -0.0057983398437500, +-0.1015930175781250, 0.0058288574218750, -0.1410827636718750, -0.0017395019531250, +-0.1227416992187500, 0.0102844238281250, -0.1403503417968750, 0.0109558105468750, +-0.1522216796875000, 0.0128173828125000, -0.1368713378906250, 0.0184020996093750, +-0.1308898925781250, 0.0145568847656250, -0.1417846679687500, 0.0258483886718750, +-0.1110534667968750, 0.0256042480468750, -0.1152038574218750, 0.0242309570312500, +-0.1035156250000000, 0.0300598144531250, -0.0816650390625000, 0.0294799804687500, +-0.0942077636718750, 0.0242004394531250, -0.0479125976562500, 0.0250244140625000, +-0.0575256347656250, 0.0262756347656250, -0.0409851074218750, 0.0251159667968750, +0.0080566406250000, 0.0262145996093750, 0.0003356933593750, 0.0270690917968750, +0.0244445800781250, 0.0300903320312500, 0.0232238769531250, 0.0246582031250000, +0.0213928222656250, 0.0217285156250000, 0.0337219238281250, 0.0274658203125000, +0.0319824218750000, 0.0081176757812500, 0.0389709472656250, 0.0128784179687500, +0.0384826660156250, 0.0056762695312500, 0.0361328125000000, -0.0094604492187500, +0.0418701171875000, 0.0003356933593750, 0.0418395996093750, -0.0253601074218750, +0.0207214355468750, -0.0198059082031250, 0.0246887207031250, -0.0298767089843750, +0.0255737304687500, -0.0515136718750000, 0.0100708007812500, -0.0383300781250000, +0.0110473632812500, -0.0674133300781250, 0.0240478515625000, -0.0663757324218750, +0.0238647460937500, -0.0694274902343750, 0.0173950195312500, -0.0867004394531250, +0.0199584960937500, -0.0792541503906250, 0.0241394042968750, -0.0900878906250000, +0.0114440917968750, -0.0910949707031250, 0.0076904296875000, -0.0910339355468750, +0.0140380859375000, -0.0967712402343750, 0.0154418945312500, -0.0950622558593750, +0.0108642578125000, -0.0944824218750000, 0.0148925781250000, -0.0988159179687500, +0.0196533203125000, -0.0921936035156250, 0.0140075683593750, -0.0871582031250000, +0.0095825195312500, -0.0929260253906250, 0.0137023925781250, -0.0700683593750000, +0.0008850097656250, -0.0757446289062500, 0.0007934570312500, -0.0669250488281250, +0.0048522949218750, -0.0479431152343750, -0.0024719238281250, -0.0590209960937500, +-0.0036926269531250, -0.0315551757812500, 0.0198669433593750, -0.0366821289062500, +0.0121154785156250}, +{0.0671081542968750, -0.0541687011718750, 0.0661621093750000, -0.0478515625000000, +0.0671386718750000, -0.0263977050781250, 0.0572814941406250, -0.0359191894531250, +0.0595397949218750, -0.0190429687500000, 0.0520019531250000, -0.0190124511718750, +0.0582885742187500, -0.0162963867187500, 0.0435791015625000, -0.0051879882812500, +0.0301513671875000, -0.0104370117187500, 0.0440673828125000, -0.0054931640625000, +-0.0021362304687500, -0.0018920898437500, 0.0055541992187500, -0.0052490234375000, +-0.0035705566406250, -0.0078735351562500, -0.0384826660156250, -0.0059204101562500, +-0.0232543945312500, -0.0075683593750000, -0.0422058105468750, -0.0074157714843750, +-0.0451965332031250, -0.0116882324218750, -0.0483703613281250, -0.0150451660156250, +-0.0549011230468750, -0.0113525390625000, -0.0500793457031250, -0.0208129882812500, +-0.0800476074218750, -0.0244140625000000, -0.0689086914062500, -0.0203247070312500, +-0.0862121582031250, -0.0188903808593750, -0.1196899414062500, -0.0218811035156250, +-0.0993957519531250, -0.0221557617187500, -0.1313171386718750, -0.0209350585937500, +-0.1398010253906250, -0.0180053710937500, -0.1265869140625000, -0.0194702148437500, +-0.1325073242187500, -0.0223388671875000, -0.1385498046875000, -0.0071411132812500, +-0.1038513183593750, -0.0100402832031250, -0.1127014160156250, -0.0066528320312500, +-0.0997314453125000, 0.0036621093750000, -0.0713500976562500, -0.0012512207031250, +-0.0870056152343750, 0.0131225585937500, -0.0460510253906250, 0.0100708007812500, +-0.0531005859375000, 0.0153503417968750, -0.0346679687500000, 0.0286865234375000, +0.0008850097656250, 0.0215148925781250, -0.0209655761718750, 0.0292663574218750, +0.0253295898437500, 0.0332031250000000, 0.0281677246093750, 0.0278015136718750, +0.0239562988281250, 0.0226745605468750, 0.0451049804687500, 0.0234680175781250, +0.0427856445312500, 0.0257873535156250, 0.0361022949218750, 0.0219116210937500, +0.0379638671875000, 0.0252990722656250, 0.0393981933593750, 0.0319213867187500, +0.0366210937500000, 0.0275268554687500, 0.0353393554687500, 0.0289611816406250, +0.0336303710937500, 0.0347595214843750, 0.0378723144531250, 0.0264282226562500, +0.0283813476562500, 0.0198059082031250, 0.0169372558593750, 0.0270080566406250, +0.0249633789062500, 0.0050354003906250, 0.0167541503906250, 0.0084838867187500, +0.0105895996093750, 0.0027770996093750, 0.0151977539062500, -0.0125122070312500, +0.0208740234375000, -0.0042114257812500, 0.0181579589843750, -0.0251159667968750, +0.0114746093750000, -0.0205993652343750, 0.0135498046875000, -0.0299682617187500, +0.0176696777343750, -0.0480346679687500, 0.0127868652343750, -0.0363464355468750, +0.0097351074218750, -0.0632629394531250, 0.0304870605468750, -0.0614624023437500, +0.0308532714843750, -0.0644226074218750, 0.0243835449218750, -0.0812988281250000, +0.0321655273437500, -0.0740966796875000, 0.0354003906250000, -0.0832824707031250, +0.0170898437500000, -0.0849304199218750, 0.0188293457031250, -0.0847167968750000, +0.0186157226562500, -0.0893554687500000, 0.0064697265625000, -0.0880432128906250, +0.0099182128906250, -0.0852355957031250, 0.0201721191406250, -0.0895996093750000, +0.0107727050781250, -0.0819702148437500, 0.0224304199218750, -0.0748901367187500, +0.0429382324218750, -0.0818481445312500, 0.0302429199218750, -0.0589904785156250, +0.0382995605468750, -0.0641174316406250, 0.0487365722656250, -0.0552673339843750, +0.0323181152343750, -0.0363769531250000, 0.0205383300781250, -0.0475769042968750, +0.0307312011718750, -0.0215148925781250, -0.0056152343750000, -0.0264587402343750, +-0.0016784667968750, -0.0164184570312500, -0.0130004882812500, 0.0036010742187500, +-0.0410461425781250, -0.0099182128906250, -0.0282287597656250, 0.0256652832031250, +-0.0539550781250000, 0.0190124511718750, -0.0567321777343750, 0.0287780761718750, +-0.0567626953125000, 0.0557556152343750, -0.0677185058593750, 0.0402526855468750, +-0.0650024414062500, 0.0703735351562500, -0.0728759765625000, 0.0680847167968750, +-0.0717163085937500, 0.0723266601562500, -0.0775146484375000, 0.0910949707031250, +-0.0863647460937500, 0.0812683105468750, -0.0816955566406250, 0.0984497070312500, +-0.0936279296875000, 0.0988464355468750, -0.0951538085937500, 0.0982360839843750, +-0.0923156738281250, 0.1077575683593750, -0.0964355468750000, 0.1044006347656250, +-0.0961608886718750, 0.0993041992187500, -0.0860290527343750, 0.1075744628906250, +-0.0895996093750000, 0.0928039550781250, -0.0798950195312500, 0.0802307128906250, +-0.0669250488281250, 0.0932617187500000, -0.0732421875000000, 0.0440979003906250, +-0.0485229492187500, 0.0556945800781250, -0.0489501953125000, 0.0372619628906250, +-0.0436096191406250, -0.0062866210937500, -0.0267028808593750, 0.0177001953125000, +-0.0318908691406250, -0.0220336914062500, -0.0206604003906250, -0.0282592773437500, +-0.0184326171875000, -0.0197753906250000, -0.0190429687500000, -0.0325012207031250, +-0.0146789550781250, -0.0324401855468750, -0.0150756835937500, -0.0153503417968750, +-0.0162963867187500, -0.0202941894531250, -0.0151367187500000, -0.0151367187500000, +-0.0176391601562500, 0.0004272460937500, -0.0211486816406250, -0.0062255859375000, +-0.0201416015625000, -0.0012207031250000, -0.0247192382812500, 0.0028686523437500, +-0.0268249511718750, -0.0021667480468750, -0.0252380371093750, -0.0054931640625000, +-0.0263061523437500, -0.0023803710937500, -0.0281677246093750, -0.0093078613281250, +-0.0202026367187500, -0.0116271972656250, -0.0245056152343750, -0.0078735351562500, +-0.0201416015625000, -0.0086059570312500, -0.0115051269531250, -0.0109252929687500, +-0.0180969238281250, 0.0018920898437500, -0.0063781738281250, -0.0001220703125000, +-0.0078125000000000, 0.0003967285156250, -0.0057678222656250, 0.0107421875000000, +0.0018615722656250, 0.0078735351562500, -0.0029602050781250, -0.0028686523437500, +0.0047912597656250, 0.0040588378906250, 0.0054931640625000, -0.0055847167968750, +0.0029907226562500, -0.0231933593750000, 0.0061035156250000, -0.0138549804687500, +0.0061035156250000, -0.0217895507812500, -0.0031433105468750, -0.0292358398437500, +0.0010375976562500, -0.0187988281250000, -0.0055236816406250, -0.0110168457031250, +-0.0163574218750000, -0.0174255371093750, -0.0097961425781250, -0.0005187988281250, +-0.0248107910156250, 0.0003662109375000, -0.0242919921875000, 0.0025634765625000, +-0.0267028808593750, 0.0107421875000000, -0.0358276367187500, 0.0077819824218750, +-0.0323791503906250, 0.0207214355468750, -0.0428771972656250, 0.0186157226562500, +-0.0411071777343750, 0.0238037109375000, -0.0460205078125000, 0.0350952148437500, +-0.0545959472656250, 0.0300598144531250, -0.0485839843750000, 0.0416564941406250, +-0.0633239746093750, 0.0388183593750000, -0.0635070800781250, 0.0492553710937500, +-0.0611572265625000, 0.0602111816406250, -0.0699462890625000, 0.0510559082031250, +-0.0687866210937500, 0.0925598144531250, -0.0501708984375000, 0.0864562988281250, +-0.0601501464843750, 0.0945739746093750, -0.0431518554687500, 0.1277770996093750, +-0.0182189941406250, 0.1143493652343750, -0.0340881347656250, 0.1149902343750000, +0.0062255859375000, 0.1300048828125000, 0.0046386718750000, 0.1060791015625000, +0.0105285644531250, 0.0847167968750000, 0.0361022949218750, 0.1028137207031250, +0.0246582031250000, 0.0457763671875000, 0.0370178222656250, 0.0522766113281250, +0.0447082519531250, 0.0382995605468750, 0.0307006835937500, -0.0027770996093750, +0.0267944335937500, 0.0169067382812500, 0.0361328125000000, -0.0188598632812500, +-0.0038757324218750, -0.0217590332031250, -0.0015869140625000, -0.0234985351562500, +-0.0030212402343750, -0.0405273437500000, -0.0279541015625000, -0.0344543457031250, +-0.0213623046875000, -0.0482788085937500, -0.0136108398437500, -0.0447998046875000, +-0.0227966308593750, -0.0554809570312500, -0.0083007812500000, -0.0698547363281250, +0.0098266601562500, -0.0597839355468750, -0.0022888183593750, -0.0934448242187500, +0.0272521972656250, -0.0904235839843750, 0.0352783203125000, -0.0956420898437500, +0.0164184570312500, -0.1192016601562500, 0.0191345214843750, -0.1101074218750000, +0.0304260253906250, -0.1170654296875000, -0.0256042480468750, -0.1227111816406250, +-0.0172424316406250, -0.1151733398437500, -0.0302124023437500, -0.1122131347656250, +-0.0698547363281250, -0.1156921386718750, -0.0534667968750000, -0.0933837890625000, +-0.0960083007812500, -0.1030883789062500, -0.0955505371093750, -0.0789489746093750, +-0.0937805175781250, -0.0521545410156250, -0.1224670410156250, -0.0732116699218750, +-0.1168518066406250, 0.0055236816406250, -0.0803833007812500, -0.0077209472656250, +-0.0995788574218750, 0.0156250000000000, -0.0793457031250000, 0.0812377929687500, +-0.0321655273437500, 0.0503540039062500, -0.0541687011718750, 0.0894470214843750, +-0.0355834960937500, 0.1077575683593750, -0.0239257812500000, 0.0827026367187500, +-0.0345458984375000, 0.0770874023437500, -0.0421142578125000, 0.0916748046875000, +-0.0366210937500000, 0.0443725585937500, -0.0346374511718750, 0.0423583984375000, +-0.0465087890625000, 0.0492248535156250, -0.0256347656250000, 0.0273132324218750, +-0.0065307617187500, 0.0287475585937500, -0.0247802734375000, 0.0595397949218750, +0.0256042480468750, 0.0512084960937500, 0.0244445800781250, 0.0568237304687500, +0.0226745605468750, 0.0957031250000000, 0.0613098144531250, 0.0748901367187500, +-0.0232238769531250, 0.0598449707031250, 0.0326538085937500, 0.0661010742187500, +0.0181579589843750, 0.0553894042968750, 0.0253601074218750, 0.0479125976562500, +0.0492553710937500, 0.0551147460937500, 0.0436096191406250, 0.0129089355468750, +0.0488281250000000, 0.0263977050781250, 0.0474853515625000, 0.0040283203125000, +0.0537719726562500, -0.0409545898437500, 0.0612182617187500, -0.0162353515625000, +0.0546569824218750, -0.0577087402343750, 0.0703735351562500, -0.0680236816406250, +0.0735473632812500, -0.0573425292968750, 0.0656738281250000, -0.0638732910156250, +0.0679321289062500, -0.0675354003906250, 0.0723876953125000, -0.0618896484375000, +0.0532836914062500, -0.0563659667968750, 0.0543212890625000, -0.0701904296875000, +0.0538635253906250, -0.0767211914062500, 0.0437011718750000, -0.0673217773437500, +0.0458374023437500, -0.1109008789062500, 0.0409851074218750, -0.1024169921875000, +0.0462951660156250, -0.1101989746093750, 0.0325622558593750, -0.1494750976562500, +0.0215454101562500, -0.1335754394531250, 0.0329589843750000, -0.1118469238281250, +-0.0150146484375000, -0.1418762207031250, -0.0067749023437500, -0.1007995605468750, +-0.0218505859375000, -0.0459899902343750, -0.0601196289062500, -0.0836486816406250, +-0.0416259765625000, -0.0042419433593750, -0.0788269042968750, -0.0019836425781250, +-0.0787658691406250, -0.0007934570312500, -0.0837097167968750, 0.0400085449218750, +-0.1070861816406250, 0.0249328613281250, -0.0960998535156250, 0.0287170410156250, +-0.1036071777343750, 0.0393981933593750, -0.1135864257812500, 0.0288085937500000, +-0.0961303710937500, 0.0148010253906250, -0.0851745605468750, 0.0228576660156250, +-0.0972595214843750, 0.0234680175781250, -0.0534667968750000, 0.0142822265625000, +-0.0562133789062500, 0.0223999023437500, -0.0524597167968750, 0.0347595214843750, +-0.0251159667968750, 0.0271301269531250, -0.0335388183593750, 0.0355834960937500, +-0.0279541015625000, 0.0394287109375000, -0.0278930664062500, 0.0333251953125000, +-0.0218505859375000, 0.0338745117187500, -0.0183715820312500, 0.0372314453125000, +-0.0246582031250000, 0.0160522460937500, 0.0077209472656250, 0.0244445800781250, +-0.0000915527343750, 0.0104370117187500, 0.0119323730468750, -0.0121765136718750, +0.0402832031250000}, +{0.0227966308593750, -0.0523376464843750, 0.0068054199218750, -0.0683898925781250, +0.0198364257812500, -0.0020141601562500, -0.0145874023437500, -0.0140686035156250, +-0.0096740722656250, 0.0088806152343750, -0.0271301269531250, 0.0671997070312500, +-0.0552673339843750, 0.0388488769531250, -0.0359802246093750, 0.0742492675781250, +-0.0892333984375000, 0.0903015136718750, -0.0922546386718750, 0.0701293945312500, +-0.0829772949218750, 0.0673828125000000, -0.1067810058593750, 0.0794677734375000, +-0.1068725585937500, 0.0404052734375000, -0.0730285644531250, 0.0401306152343750, +-0.0828552246093750, 0.0468444824218750, -0.0714111328125000, 0.0285339355468750, +-0.0406188964843750, 0.0296630859375000, -0.0545349121093750, 0.0568847656250000, +-0.0362243652343750, 0.0491638183593750, -0.0307922363281250, 0.0580749511718750, +-0.0372619628906250, 0.0840454101562500, -0.0369567871093750, 0.0729980468750000, +-0.0341796875000000, 0.0774841308593750, -0.0325927734375000, 0.0848999023437500, +-0.0408630371093750, 0.0785522460937500, -0.0273742675781250, 0.0668029785156250, +0.0011901855468750, 0.0436096191406250, -0.0274658203125000, -0.0031127929687500, +-0.0258789062500000, 0.0218505859375000, -0.0385437011718750, -0.0034179687500000, +-0.0186157226562500, -0.0418395996093750, -0.0016784667968750, -0.0217895507812500, +-0.0164489746093750, -0.0522460937500000, 0.0231628417968750, -0.0610046386718750, +0.0236816406250000, -0.0514221191406250, 0.0226745605468750, -0.0548706054687500, +0.0413513183593750, -0.0600891113281250, 0.0369262695312500, -0.0539550781250000, +0.0419311523437500, -0.0436401367187500, 0.0397644042968750, -0.0665893554687500, +0.0460205078125000, -0.0821838378906250, 0.0544433593750000, -0.0637512207031250, +0.0478515625000000, -0.1180419921875000, 0.0602416992187500, -0.1179809570312500, +0.0649414062500000, -0.1163024902343750, 0.0565185546875000, -0.1468505859375000, +0.0552368164062500, -0.1384582519531250, 0.0603942871093750, -0.1163635253906250, +0.0411376953125000, -0.1403808593750000, 0.0418701171875000, -0.1011657714843750, +0.0414123535156250, -0.0544433593750000, 0.0319519042968750, -0.0917968750000000, +0.0343017578125000, -0.0030822753906250, 0.0263977050781250, -0.0045471191406250, +0.0322875976562500, -0.0025939941406250, 0.0180969238281250, 0.0441894531250000, +0.0042114257812500, 0.0284423828125000, 0.0168457031250000, 0.0478515625000000, +-0.0267639160156250, 0.0515441894531250, -0.0214538574218750, 0.0462036132812500, +-0.0321655273437500, 0.0527648925781250, -0.0636291503906250, 0.0541687011718750, +-0.0489196777343750, 0.0445251464843750, -0.0772094726562500, 0.0439147949218750, +-0.0780029296875000, 0.0472717285156250, -0.0798339843750000, 0.0457458496093750, +-0.0972595214843750, 0.0434570312500000, -0.0909729003906250, 0.0434265136718750, +-0.0885620117187500, 0.0473022460937500, -0.0988464355468750, 0.0444030761718750, +-0.0810852050781250, 0.0387573242187500, -0.0632934570312500, 0.0411682128906250, +-0.0772094726562500, 0.0401000976562500, -0.0379638671875000, 0.0406494140625000, +-0.0376892089843750, 0.0346069335937500, -0.0371093750000000, 0.0324096679687500, +-0.0173645019531250, 0.0366516113281250, -0.0230407714843750, 0.0102233886718750, +-0.0167541503906250, 0.0186462402343750, -0.0197753906250000, 0.0051574707031250, +-0.0100402832031250, -0.0209350585937500, -0.0008239746093750, -0.0063171386718750, +-0.0097045898437500, -0.0399780273437500, 0.0242614746093750, -0.0369873046875000, +0.0192565917968750, -0.0462036132812500, 0.0287170410156250, -0.0698547363281250, +0.0539855957031250, -0.0558471679687500, 0.0422973632812500, -0.0822143554687500, +0.0699768066406250, -0.0854187011718750, 0.0669860839843750, -0.0797424316406250, +0.0747680664062500, -0.0891113281250000, 0.0966491699218750, -0.0889587402343750, +0.0853271484375000, -0.0745849609375000, 0.0992126464843750, -0.0806579589843750, +0.1067810058593750, -0.0707397460937500, 0.0947875976562500, -0.0551757812500000, +0.0907592773437500, -0.0652160644531250, 0.0979919433593750, -0.0386047363281250, +0.0715026855468750, -0.0419311523437500, 0.0736999511718750, -0.0357971191406250, +0.0683898925781250, -0.0173950195312500, 0.0514831542968750, -0.0274353027343750, +0.0583190917968750, -0.0081176757812500, 0.0385742187500000, -0.0098876953125000, +0.0415039062500000, -0.0057373046875000, 0.0335083007812500, 0.0067749023437500, +0.0166015625000000, -0.0006713867187500, 0.0252990722656250, 0.0168151855468750, +0.0055847167968750, 0.0142211914062500, 0.0058898925781250, 0.0186462402343750, +0.0012817382812500, 0.0315856933593750, -0.0106811523437500, 0.0246276855468750, +-0.0046081542968750, 0.0380554199218750, -0.0229492187500000, 0.0384216308593750, +-0.0224304199218750, 0.0385437011718750, -0.0232238769531250, 0.0455932617187500, +-0.0354309082031250, 0.0428466796875000, -0.0321960449218750, 0.0428466796875000, +-0.0252990722656250, 0.0443420410156250, -0.0298767089843750, 0.0417175292968750, +-0.0233154296875000, 0.0393066406250000, -0.0118713378906250, 0.0410766601562500, +-0.0168151855468750, 0.0368652343750000, -0.0088806152343750, 0.0369262695312500, +-0.0066223144531250, 0.0368957519531250, -0.0083312988281250, 0.0352172851562500, +-0.0071105957031250, 0.0361633300781250, -0.0068359375000000, 0.0333557128906250, +-0.0075683593750000, 0.0347290039062500, -0.0081481933593750, 0.0327148437500000, +-0.0068969726562500, 0.0293273925781250, -0.0060729980468750, 0.0316162109375000, +-0.0065612792968750, 0.0260009765625000, -0.0030822753906250, 0.0264282226562500, +-0.0040588378906250, 0.0251464843750000, -0.0014343261718750, 0.0219421386718750, +0.0012207031250000, 0.0238342285156250, -0.0013427734375000, 0.0173339843750000, +0.0104064941406250, 0.0189514160156250, 0.0049438476562500, 0.0153503417968750, +0.0154418945312500, 0.0088500976562500, 0.0287780761718750, 0.0123291015625000, +0.0174865722656250, 0.0025329589843750, 0.0505065917968750, 0.0025634765625000, +0.0453796386718750, 0.0022583007812500, 0.0531616210937500, -0.0032653808593750, +0.0785522460937500, -0.0017700195312500, 0.0658264160156250, -0.0019531250000000, +0.0804748535156250, -0.0024414062500000, 0.0866088867187500, -0.0024108886718750, +0.0783386230468750, -0.0012512207031250, 0.0782470703125000, -0.0009765625000000, +0.0832824707031250, -0.0060424804687500, 0.0667724609375000, -0.0028991699218750, +0.0688171386718750, -0.0087890625000000, 0.0673828125000000, -0.0157165527343750, +0.0572509765625000, -0.0113830566406250, 0.0609741210937500, -0.0323181152343750, +0.0550842285156250, -0.0270385742187500, 0.0575256347656250, -0.0411376953125000, +0.0494689941406250, -0.0630187988281250, 0.0431213378906250, -0.0503234863281250, +0.0508422851562500, -0.0864868164062500, 0.0178222656250000, -0.0871582031250000, +0.0267333984375000, -0.0877380371093750, 0.0134887695312500, -0.1093139648437500, +-0.0171203613281250, -0.1036682128906250, -0.0003051757812500, -0.0909423828125000, +-0.0285644531250000, -0.1044006347656250, -0.0314025878906250, -0.0812988281250000, +-0.0307006835937500, -0.0528869628906250, -0.0417480468750000, -0.0713195800781250, +-0.0390625000000000, -0.0198669433593750, -0.0516357421875000, -0.0191040039062500, +-0.0446472167968750, -0.0180358886718750, -0.0596008300781250, 0.0095825195312500, +-0.0772399902343750, 0.0006103515625000, -0.0618591308593750, -0.0025634765625000, +-0.1031494140625000, 0.0045471191406250, -0.1005859375000000, -0.0045166015625000, +-0.1002197265625000, -0.0180358886718750, -0.1263427734375000, -0.0115661621093750, +-0.1188354492187500, -0.0163879394531250, -0.1036987304687500, -0.0227355957031250, +-0.1190795898437500, -0.0149230957031250, -0.0979919433593750, -0.0091552734375000, +-0.0693359375000000, -0.0145568847656250, -0.0892028808593750, 0.0048522949218750, +-0.0422973632812500, 0.0037841796875000, -0.0431518554687500, 0.0013122558593750, +-0.0375671386718750, 0.0140075683593750, -0.0113220214843750, 0.0128479003906250, +-0.0212402343750000, -0.0088195800781250, 0.0081176757812500, -0.0024108886718750, +0.0018005371093750, -0.0077819824218750, 0.0127258300781250, -0.0275878906250000, +0.0390625000000000, -0.0212707519531250, 0.0231933593750000, -0.0263366699218750, +0.0422058105468750, -0.0314331054687500, 0.0512695312500000, -0.0237731933593750, +0.0388488769531250, -0.0204162597656250, 0.0357666015625000, -0.0260314941406250, +0.0439147949218750, -0.0041809082031250, 0.0228576660156250, -0.0080871582031250, +0.0214233398437500, -0.0026855468750000, 0.0241394042968750, 0.0170898437500000, +0.0174255371093750, 0.0148315429687500, 0.0183410644531250, 0.0266418457031250, +0.0161743164062500, 0.0260925292968750, 0.0190734863281250, 0.0216979980468750, +0.0163574218750000, 0.0258789062500000, 0.0102539062500000, 0.0270385742187500, +0.0145874023437500, 0.0200500488281250, 0.0167846679687500, 0.0183410644531250, +0.0113220214843750, 0.0222167968750000, 0.0175476074218750, 0.0212402343750000, +0.0277709960937500, 0.0184326171875000, 0.0228271484375000, 0.0310058593750000, +0.0257873535156250, 0.0289916992187500, 0.0275268554687500, 0.0295715332031250, +0.0281372070312500, 0.0396728515625000, 0.0289916992187500, 0.0366516113281250, +0.0270080566406250, 0.0266113281250000, 0.0272827148437500, 0.0347290039062500, +0.0317993164062500, 0.0228576660156250, 0.0234375000000000, 0.0057678222656250, +0.0145568847656250, 0.0173339843750000, 0.0218505859375000, -0.0065002441406250, +0.0112304687500000, -0.0064697265625000, 0.0068359375000000, -0.0075378417968750, +0.0100402832031250, -0.0187988281250000, 0.0113220214843750, -0.0136718750000000, +0.0097045898437500, -0.0268554687500000, 0.0054321289062500, -0.0225524902343750, +0.0090637207031250, -0.0316467285156250, 0.0029907226562500, -0.0463256835937500, +-0.0037231445312500, -0.0368347167968750, 0.0005493164062500, -0.0599670410156250, +-0.0224304199218750, -0.0594482421875000, -0.0190734863281250, -0.0604553222656250, +-0.0248718261718750, -0.0732116699218750, -0.0421447753906250, -0.0684814453125000, +-0.0365295410156250, -0.0734863281250000, -0.0538940429687500, -0.0748291015625000, +-0.0498657226562500, -0.0728759765625000, -0.0606079101562500, -0.0747375488281250, +-0.0790100097656250, -0.0748901367187500, -0.0678100585937500, -0.0665893554687500, +-0.0903320312500000, -0.0718383789062500, -0.0941467285156250, -0.0633544921875000, +-0.0890197753906250, -0.0522155761718750, -0.0962219238281250, -0.0610961914062500, +-0.0971679687500000, -0.0370788574218750, -0.0834350585937500, -0.0411071777343750, +-0.0868225097656250, -0.0347290039062500, -0.0796203613281250, -0.0174865722656250, +-0.0669555664062500, -0.0270996093750000, -0.0732421875000000, -0.0038452148437500, +-0.0539245605468750, -0.0084838867187500, -0.0549621582031250, 0.0003051757812500, +-0.0501708984375000, 0.0184936523437500, -0.0364990234375000, 0.0061340332031250, +-0.0423889160156250, 0.0355529785156250, -0.0316467285156250, 0.0312500000000000, +-0.0310058593750000, 0.0377502441406250, -0.0305175781250000, 0.0584716796875000, +-0.0251464843750000, 0.0470275878906250, -0.0272827148437500, 0.0684509277343750, +-0.0239868164062500, 0.0673217773437500, -0.0234069824218750, 0.0702209472656250, +-0.0233459472656250, 0.0833129882812500, -0.0221862792968750, 0.0766906738281250, +-0.0221862792968750, 0.0884704589843750, -0.0190429687500000, 0.0899658203125000, +-0.0198364257812500, 0.0873107910156250, -0.0170898437500000, 0.0932922363281250, +-0.0128479003906250, 0.0931396484375000, -0.0141601562500000, 0.0773925781250000, +-0.0089721679687500}, +{0.0491638183593750, -0.0131835937500000, 0.0239562988281250, -0.0109252929687500, +0.0301513671875000, -0.0167541503906250, 0.0262756347656250, -0.0346984863281250, +0.0052185058593750, -0.0263671875000000, 0.0123596191406250, -0.0289001464843750, +0.0142517089843750, -0.0380554199218750, 0.0087890625000000, -0.0269470214843750, +0.0124206542968750, -0.0121765136718750, 0.0207519531250000, -0.0131530761718750, +0.0195617675781250, 0.0099182128906250, 0.0198974609375000, 0.0023803710937500, +0.0192871093750000, 0.0048828125000000, 0.0229492187500000, 0.0230407714843750, +0.0255432128906250, 0.0146179199218750, 0.0220336914062500, 0.0206909179687500, +0.0305175781250000, 0.0248718261718750, 0.0336914062500000, 0.0207214355468750, +0.0263977050781250, 0.0182495117187500, 0.0234375000000000, 0.0205993652343750, +0.0278930664062500, 0.0181274414062500, 0.0166320800781250, 0.0155639648437500, +0.0149536132812500, 0.0201721191406250, 0.0146484375000000, 0.0224914550781250, +0.0106201171875000, 0.0188903808593750, 0.0118103027343750, 0.0322875976562500, +0.0071105957031250, 0.0315856933593750, 0.0082092285156250, 0.0303344726562500, +0.0059814453125000, 0.0395202636718750, 0.0017700195312500, 0.0383300781250000, +0.0031738281250000, 0.0223083496093750, -0.0060119628906250, 0.0310363769531250, +-0.0019531250000000, 0.0196838378906250, -0.0111389160156250, -0.0010986328125000, +-0.0245666503906250, 0.0112609863281250, -0.0163879394531250, -0.0088195800781250, +-0.0330810546875000, -0.0108947753906250, -0.0339660644531250, -0.0104370117187500, +-0.0371398925781250, -0.0173339843750000, -0.0464172363281250, -0.0147705078125000, +-0.0419006347656250, -0.0272216796875000, -0.0530700683593750, -0.0216064453125000, +-0.0512084960937500, -0.0306701660156250, -0.0596618652343750, -0.0461120605468750, +-0.0694885253906250, -0.0361328125000000, -0.0605773925781250, -0.0564270019531250, +-0.0878601074218750, -0.0570373535156250, -0.0873413085937500, -0.0568847656250000, +-0.0837402343750000, -0.0669250488281250, -0.0976867675781250, -0.0634460449218750, +-0.0956115722656250, -0.0656127929687500, -0.0800476074218750, -0.0671386718750000, +-0.0853881835937500, -0.0644531250000000, -0.0773315429687500, -0.0643920898437500, +-0.0604553222656250, -0.0657958984375000, -0.0676879882812500, -0.0552673339843750, +-0.0558776855468750, -0.0604553222656250, -0.0538024902343750, -0.0521850585937500, +-0.0527648925781250, -0.0397644042968750, -0.0478210449218750, -0.0488586425781250, +-0.0494079589843750, -0.0266723632812500, -0.0420532226562500, -0.0299072265625000, +-0.0425415039062500, -0.0244445800781250, -0.0378112792968750, -0.0093688964843750, +-0.0308532714843750, -0.0183105468750000, -0.0337829589843750, 0.0031738281250000, +-0.0213928222656250, -0.0012817382812500, -0.0210571289062500, 0.0072021484375000, +-0.0186157226562500, 0.0245056152343750, -0.0100402832031250, 0.0133056640625000, +-0.0120849609375000, 0.0412292480468750, -0.0099487304687500, 0.0375976562500000, +-0.0071105957031250, 0.0439147949218750, -0.0099182128906250, 0.0637207031250000, +-0.0114746093750000, 0.0534667968750000, -0.0094909667968750, 0.0725097656250000, +-0.0203552246093750, 0.0727844238281250, -0.0177917480468750, 0.0733947753906250, +-0.0235290527343750, 0.0836486816406250, -0.0346069335937500, 0.0792541503906250, +-0.0301513671875000, 0.0816955566406250, -0.0437316894531250, 0.0846252441406250, +-0.0450744628906250, 0.0788269042968750, -0.0469360351562500, 0.0766601562500000, +-0.0548400878906250, 0.0797424316406250, -0.0532531738281250, 0.0592651367187500, +-0.0567016601562500, 0.0680541992187500, -0.0582275390625000, 0.0532836914062500, +-0.0585632324218750, 0.0311889648437500, -0.0596923828125000, 0.0478210449218750, +-0.0594482421875000, 0.0046997070312500, -0.0598144531250000, 0.0104675292968750, +-0.0602416992187500, 0.0016174316406250, -0.0593566894531250, -0.0302429199218750, +-0.0582580566406250, -0.0157165527343750, -0.0584716796875000, -0.0362548828125000, +-0.0575561523437500, -0.0418395996093750, -0.0551757812500000, -0.0345153808593750, +-0.0579528808593750, -0.0388183593750000, -0.0595703125000000, -0.0411376953125000, +-0.0559997558593750, -0.0222778320312500, -0.0651550292968750, -0.0274353027343750, +-0.0625610351562500, -0.0197143554687500, -0.0658264160156250, -0.0022583007812500, +-0.0733947753906250, -0.0106201171875000, -0.0688171386718750, 0.0065002441406250, +-0.0805969238281250, 0.0068054199218750, -0.0797729492187500, 0.0101928710937500, +-0.0807800292968750, 0.0199279785156250, -0.0890502929687500, 0.0149230957031250, +-0.0860290527343750, 0.0296020507812500, -0.0842590332031250, 0.0280761718750000, +-0.0890502929687500, 0.0321044921875000, -0.0830383300781250, 0.0421142578125000, +-0.0765075683593750, 0.0375366210937500, -0.0822143554687500, 0.0535888671875000, +-0.0664672851562500, 0.0482177734375000, -0.0709533691406250, 0.0609741210937500, +-0.0634460449218750, 0.0796813964843750, -0.0505371093750000, 0.0676879882812500, +-0.0603637695312500, 0.1005859375000000, -0.0321350097656250, 0.1029968261718750, +-0.0366516113281250, 0.0990600585937500, -0.0319824218750000, 0.1151428222656250, +-0.0105895996093750, 0.1130065917968750, -0.0201721191406250, 0.0888671875000000, +-0.0138244628906250, 0.1005554199218750, -0.0060424804687500, 0.0814514160156250, +-0.0156250000000000, 0.0511169433593750, -0.0222473144531250, 0.0683288574218750, +-0.0144958496093750, 0.0235290527343750, -0.0327758789062500, 0.0244140625000000, +-0.0321960449218750, 0.0183410644531250, -0.0331420898437500, -0.0083618164062500, +-0.0422973632812500, 0.0024414062500000, -0.0383300781250000, -0.0170288085937500, +-0.0481262207031250, -0.0166015625000000, -0.0473022460937500, -0.0221557617187500, +-0.0452880859375000, -0.0343627929687500, -0.0540771484375000, -0.0272521972656250, +-0.0529479980468750, -0.0514221191406250, -0.0266723632812500, -0.0472412109375000, +-0.0419921875000000, -0.0545654296875000, -0.0158386230468750, -0.0747070312500000, +0.0238037109375000, -0.0648803710937500, 0.0005187988281250, -0.0793762207031250, +0.0538940429687500, -0.0830078125000000, 0.0578918457031250, -0.0794372558593750, +0.0591430664062500, -0.0830383300781250, 0.0860290527343750, -0.0831909179687500, +0.0768432617187500, -0.0752258300781250, 0.0742492675781250, -0.0802612304687500, +0.0871582031250000, -0.0692749023437500, 0.0672302246093750, -0.0591430664062500, +0.0451660156250000, -0.0675964355468750, 0.0617370605468750, -0.0223388671875000, +0.0276184082031250, -0.0332336425781250, 0.0228576660156250, -0.0133361816406250, +0.0276794433593750, 0.0304565429687500, 0.0170898437500000, 0.0082702636718750, +0.0191040039062500, 0.0428771972656250, 0.0238952636718750, 0.0538940429687500, +0.0198059082031250, 0.0401000976562500, 0.0283203125000000, 0.0434875488281250, +0.0398864746093750, 0.0503234863281250, 0.0314941406250000, 0.0237121582031250, +0.0367736816406250, 0.0244445800781250, 0.0482788085937500, 0.0279235839843750, +0.0308227539062500, 0.0142211914062500, 0.0145874023437500, 0.0163574218750000, +0.0286254882812500, 0.0351257324218750, -0.0008239746093750, 0.0284729003906250, +-0.0028076171875000, 0.0351257324218750, -0.0030822753906250, 0.0540466308593750, +-0.0148925781250000, 0.0458984375000000, -0.0104980468750000, 0.0509033203125000, +-0.0247497558593750, 0.0562133789062500, -0.0220947265625000, 0.0506286621093750, +-0.0274963378906250, 0.0460510253906250, -0.0378723144531250, 0.0489807128906250, +-0.0332336425781250, 0.0407714843750000, -0.0615234375000000, 0.0429382324218750, +-0.0527038574218750, 0.0346069335937500, -0.0642700195312500, 0.0272216796875000, +-0.0966796875000000, 0.0341796875000000, -0.0820617675781250, -0.0014648437500000, +-0.0791625976562500, 0.0048217773437500, -0.0957641601562500, -0.0025634765625000, +-0.0779724121093750, -0.0472106933593750, -0.0350646972656250, -0.0455322265625000, +-0.0857238769531250, -0.0610656738281250, -0.0712280273437500, -0.0450134277343750, +-0.0956420898437500, -0.0645446777343750, -0.0688171386718750, -0.0869750976562500, +-0.0341491699218750, -0.0724792480468750, -0.0538940429687500, -0.1063537597656250, +-0.0249328613281250, -0.1083374023437500, -0.0171203613281250, -0.1053466796875000, +-0.0253906250000000, -0.1239929199218750, -0.0234985351562500, -0.1204223632812500, +-0.0211486816406250, -0.0932617187500000, -0.0172729492187500, -0.1092834472656250, +-0.0258789062500000, -0.0880737304687500, -0.0119323730468750, -0.0519409179687500, +0.0045776367187500, -0.0720825195312500, -0.0080566406250000, -0.0237731933593750, +0.0179748535156250, -0.0312194824218750, 0.0205993652343750, -0.0102233886718750, +0.0187072753906250, 0.0287780761718750, 0.0278930664062500, 0.0031127929687500, +0.0258789062500000, 0.0654602050781250, 0.0321655273437500, 0.0654602050781250, +0.0290527343750000, 0.0642089843750000, 0.0347595214843750, 0.0985107421875000, +0.0450744628906250, 0.0889892578125000, 0.0393066406250000, 0.0772094726562500, +0.0442199707031250, 0.0923156738281250, 0.0503845214843750, 0.0691833496093750, +0.0405883789062500, 0.0406799316406250, 0.0333251953125000, 0.0625915527343750, +0.0405578613281250, 0.0196228027343750, 0.0209045410156250, 0.0115051269531250, +0.0209960937500000, 0.0275878906250000, 0.0189514160156250, 0.0177917480468750, +0.0094299316406250, 0.0123596191406250, 0.0130615234375000, 0.0547790527343750, +-0.0025939941406250, 0.0436706542968750, 0.0033264160156250, 0.0587158203125000, +-0.0083007812500000, 0.0995483398437500, -0.0263671875000000, 0.0781555175781250, +-0.0148620605468750, 0.0857849121093750, -0.0449829101562500, 0.1107482910156250, +-0.0436706542968750, 0.0695800781250000, -0.0483093261718750, 0.0365295410156250, +-0.0671997070312500, 0.0711364746093750, -0.0594482421875000, -0.0190429687500000, +-0.0736083984375000, -0.0161132812500000, -0.0755004882812500, -0.0155639648437500, +-0.0723876953125000, -0.0656433105468750, -0.0794677734375000, -0.0500183105468750, +-0.0792846679687500, -0.0436096191406250, -0.0601806640625000, -0.0584716796875000, +-0.0690002441406250, -0.0421447753906250, -0.0557556152343750, -0.0213012695312500, +-0.0314636230468750, -0.0352478027343750, -0.0442504882812500, -0.0007934570312500, +-0.0203857421875000, -0.0028686523437500, -0.0177612304687500, 0.0000610351562500, +-0.0177307128906250, 0.0223693847656250, -0.0095214843750000, 0.0137329101562500, +-0.0126037597656250, 0.0151672363281250, 0.0037841796875000, 0.0218811035156250, +-0.0034179687500000, 0.0139770507812500, 0.0097351074218750, 0.0076293945312500, +0.0300292968750000, 0.0138244628906250, 0.0168457031250000, -0.0079650878906250, +0.0489196777343750, -0.0009155273437500, 0.0472412109375000, -0.0118408203125000, +0.0538024902343750, -0.0322570800781250, 0.0742492675781250, -0.0179748535156250, +0.0644531250000000, -0.0486450195312500, 0.0876159667968750, -0.0463562011718750, +0.0880737304687500, -0.0503540039062500, 0.0874633789062500, -0.0699462890625000, +0.1011962890625000, -0.0610351562500000, 0.0982360839843750, -0.0731506347656250, +0.0875549316406250, -0.0760498046875000, 0.0950317382812500, -0.0725708007812500, +0.0839233398437500, -0.0762939453125000, 0.0673522949218750, -0.0773010253906250, +0.0769653320312500, -0.0677185058593750, 0.0518188476562500, -0.0727844238281250, +0.0542602539062500, -0.0668029785156250, 0.0458984375000000, -0.0562744140625000, +0.0274353027343750, -0.0637817382812500, 0.0373535156250000, -0.0466003417968750, +0.0116882324218750, -0.0498352050781250, 0.0125732421875000, -0.0446472167968750, +0.0084533691406250}, +{-0.0821533203125000, -0.0753784179687500, -0.0623779296875000, -0.0541992187500000, +-0.0287170410156250, -0.0679626464843750, -0.0476074218750000, -0.0294494628906250, +-0.0231323242187500, -0.0348815917968750, -0.0152587890625000, -0.0188903808593750, +-0.0220642089843750, 0.0092468261718750, -0.0216369628906250, -0.0090332031250000, +-0.0198974609375000, 0.0515136718750000, -0.0140686035156250, 0.0438842773437500, +-0.0216064453125000, 0.0523071289062500, -0.0104064941406250, 0.0985412597656250, +0.0053405761718750, 0.0812683105468750, -0.0049743652343750, 0.0764465332031250, +0.0132446289062500, 0.0964355468750000, 0.0161132812500000, 0.0703430175781250, +0.0144042968750000, 0.0395507812500000, 0.0193481445312500, 0.0625305175781250, +0.0184936523437500, 0.0180053710937500, 0.0260009765625000, 0.0120544433593750, +0.0227966308593750, 0.0255126953125000, 0.0280151367187500, 0.0108032226562500, +0.0391235351562500, 0.0077209472656250, 0.0336608886718750, 0.0492248535156250, +0.0352172851562500, 0.0385742187500000, 0.0417480468750000, 0.0516662597656250, +0.0322570800781250, 0.0886535644531250, 0.0231018066406250, 0.0710754394531250, +0.0302734375000000, 0.0876464843750000, 0.0116271972656250, 0.1034240722656250, +0.0124511718750000, 0.0727233886718750, 0.0087280273437500, 0.0596008300781250, +-0.0015258789062500, 0.0831909179687500, 0.0039367675781250, -0.0030822753906250, +-0.0157165527343750, 0.0067749023437500, -0.0104370117187500, 0.0020751953125000, +-0.0207214355468750, -0.0552978515625000, -0.0405273437500000, -0.0372314453125000, +-0.0296936035156250, -0.0321960449218750, -0.0538024902343750, -0.0488586425781250, +-0.0541381835937500, -0.0303649902343750, -0.0565795898437500, -0.0061645507812500, +-0.0702514648437500, -0.0226440429687500, -0.0648498535156250, 0.0041198730468750, +-0.0733032226562500, 0.0101318359375000, -0.0765686035156250, 0.0037536621093750, +-0.0699462890625000, 0.0114746093750000, -0.0708923339843750, 0.0132751464843750, +-0.0742797851562500, -0.0031127929687500, -0.0476684570312500, 0.0028686523437500, +-0.0549011230468750, -0.0040283203125000, -0.0438842773437500, -0.0205383300781250, +-0.0180664062500000, -0.0115966796875000, -0.0301513671875000, -0.0227966308593750, +-0.0110168457031250, -0.0256042480468750, -0.0091247558593750, -0.0241394042968750, +-0.0068969726562500, -0.0267028808593750, 0.0008239746093750, -0.0261230468750000, +-0.0037536621093750, -0.0289916992187500, 0.0165405273437500, -0.0297241210937500, +0.0109252929687500, -0.0287780761718750, 0.0207519531250000, -0.0300903320312500, +0.0407714843750000, -0.0316772460937500, 0.0304565429687500, -0.0277709960937500, +0.0540771484375000, -0.0292053222656250, 0.0530395507812500, -0.0283203125000000, +0.0585327148437500, -0.0254211425781250, 0.0744934082031250, -0.0280761718750000, +0.0668029785156250, -0.0249328613281250, 0.0824279785156250, -0.0252990722656250, +0.0859985351562500, -0.0263366699218750, 0.0802001953125000, -0.0250244140625000, +0.0841674804687500, -0.0252990722656250, 0.0867614746093750, -0.0271911621093750, +0.0679626464843750, -0.0260925292968750, 0.0721130371093750, -0.0264892578125000, +0.0650939941406250, -0.0280151367187500, 0.0492553710937500, -0.0264892578125000, +0.0565795898437500, -0.0270385742187500, 0.0377502441406250, -0.0266418457031250, +0.0399169921875000, -0.0249023437500000, 0.0326232910156250, -0.0238342285156250, +0.0173034667968750, -0.0227966308593750, 0.0249633789062500, -0.0191040039062500, +0.0051269531250000, -0.0185546875000000, 0.0045166015625000, -0.0161743164062500, +0.0028381347656250, -0.0128784179687500, -0.0083618164062500, -0.0128479003906250, +-0.0047302246093750, -0.0078735351562500, -0.0090942382812500, -0.0077209472656250, +-0.0121765136718750, -0.0050354003906250, -0.0077514648437500, -0.0006713867187500, +-0.0077514648437500, -0.0016784667968750, -0.0113525390625000, 0.0044555664062500, +0.0066833496093750, 0.0059204101562500, -0.0010375976562500, 0.0067749023437500, +0.0114135742187500, 0.0101013183593750, 0.0317687988281250, 0.0111083984375000, +0.0177307128906250, 0.0129699707031250, 0.0496826171875000, 0.0130004882812500, +0.0495605468750000, 0.0155639648437500, 0.0500793457031250, 0.0180053710937500, +0.0678100585937500, 0.0167541503906250, 0.0621948242187500, 0.0225219726562500, +0.0622253417968750, 0.0226745605468750, 0.0664672851562500, 0.0226440429687500, +0.0625000000000000, 0.0260925292968750, 0.0573120117187500, 0.0254821777343750, +0.0605773925781250, 0.0222778320312500, 0.0563659667968750, 0.0241699218750000, +0.0559387207031250, 0.0211181640625000, 0.0543823242187500, 0.0165100097656250, +0.0535583496093750, 0.0188293457031250, 0.0552062988281250, 0.0115661621093750, +0.0412292480468750, 0.0120239257812500, 0.0484008789062500, 0.0095214843750000, +0.0362854003906250, 0.0043640136718750, 0.0185546875000000, 0.0067443847656250, +0.0313720703125000, -0.0021667480468750, 0.0005798339843750, -0.0009155273437500, +0.0022277832031250, -0.0030517578125000, -0.0014343261718750, -0.0103149414062500, +-0.0199890136718750, -0.0067443847656250, -0.0120849609375000, -0.0074157714843750, +-0.0257873535156250, -0.0105285644531250, -0.0248107910156250, -0.0038146972656250, +-0.0302124023437500, 0.0015869140625000, -0.0394592285156250, -0.0023193359375000, +-0.0330810546875000, 0.0132141113281250, -0.0562744140625000, 0.0134887695312500, +-0.0505371093750000, 0.0129089355468750, -0.0597534179687500, 0.0227050781250000, +-0.0809936523437500, 0.0211791992187500, -0.0681762695312500, 0.0082702636718750, +-0.0860290527343750, 0.0169677734375000, -0.0925292968750000, 0.0021667480468750, +-0.0794982910156250, -0.0175781250000000, -0.0803222656250000, -0.0054321289062500, +-0.0882568359375000, -0.0455932617187500, -0.0498352050781250, -0.0413208007812500, +-0.0601501464843750, -0.0504455566406250, -0.0479125976562500, -0.0815734863281250, +-0.0143737792968750, -0.0676269531250000, -0.0314636230468750, -0.0748901367187500, +-0.0054931640625000, -0.0868835449218750, -0.0024414062500000, -0.0692443847656250, +-0.0019531250000000, -0.0538635253906250, 0.0082702636718750, -0.0655212402343750, +0.0044555664062500, -0.0357360839843750, 0.0202026367187500, -0.0337829589843750, +0.0151367187500000, -0.0337219238281250, 0.0224304199218750, -0.0201721191406250, +0.0401611328125000, -0.0232238769531250, 0.0299682617187500, -0.0180358886718750, +0.0339660644531250, -0.0178222656250000, 0.0444335937500000, -0.0169982910156250, +0.0296020507812500, -0.0131225585937500, 0.0157165527343750, -0.0142517089843750, +0.0283508300781250, -0.0145874023437500, 0.0051269531250000, -0.0176086425781250, +-0.0003662109375000, -0.0098876953125000, 0.0104980468750000, -0.0036621093750000, +0.0073547363281250, -0.0115051269531250, 0.0015563964843750, 0.0022277832031250, +0.0256347656250000, 0.0045776367187500, 0.0238342285156250, 0.0042724609375000, +0.0234069824218750, 0.0084838867187500, 0.0379333496093750, 0.0054626464843750, +0.0349121093750000, 0.0078735351562500, 0.0278320312500000, 0.0128784179687500, +0.0322875976562500, 0.0018920898437500, 0.0274658203125000, -0.0121765136718750, +0.0168457031250000, -0.0123596191406250, 0.0172119140625000, -0.0280456542968750, +0.0043945312500000, -0.0283203125000000, 0.0094604492187500, -0.0230712890625000, +0.0054626464843750, -0.0291748046875000, -0.0083618164062500, -0.0308227539062500, +-0.0025939941406250, -0.0128784179687500, -0.0054321289062500, -0.0199279785156250, +-0.0121459960937500, -0.0107727050781250, -0.0053710937500000, 0.0084533691406250, +0.0032348632812500, -0.0027465820312500, -0.0032043457031250, 0.0136108398437500, +-0.0004882812500000, 0.0161132812500000, 0.0072021484375000, 0.0160522460937500, +-0.0083007812500000, 0.0222473144531250, -0.0213623046875000, 0.0194702148437500, +-0.0099487304687500, 0.0253295898437500, -0.0388183593750000, 0.0267333984375000, +-0.0413208007812500, 0.0240173339843750, -0.0403442382812500, 0.0245971679687500, +-0.0531311035156250, 0.0266418457031250, -0.0498657226562500, 0.0231628417968750, +-0.0466003417968750, 0.0208435058593750, -0.0507812500000000, 0.0265502929687500, +-0.0475158691406250, 0.0296630859375000, -0.0402221679687500, 0.0253601074218750, +-0.0433349609375000, 0.0368041992187500, -0.0419921875000000, 0.0403137207031250, +-0.0379638671875000, 0.0321960449218750, -0.0448608398437500, 0.0333862304687500, +-0.0503845214843750, 0.0386352539062500, -0.0438842773437500, 0.0095825195312500, +-0.0570678710937500, 0.0154724121093750, -0.0606994628906250, 0.0097351074218750, +-0.0536193847656250, -0.0128479003906250, -0.0544128417968750, -0.0032348632812500, +-0.0582580566406250, -0.0116271972656250, -0.0420837402343750, -0.0140075683593750, +-0.0453186035156250, -0.0155944824218750, -0.0394897460937500, -0.0171813964843750, +-0.0266723632812500, -0.0140991210937500, -0.0333251953125000, -0.0305175781250000, +-0.0151672363281250, -0.0249633789062500, -0.0166625976562500, -0.0310974121093750, +-0.0115356445312500, -0.0470581054687500, 0.0030212402343750, -0.0386352539062500, +-0.0035400390625000, -0.0510864257812500, 0.0032043457031250, -0.0532226562500000, +0.0080871582031250, -0.0509948730468750, 0.0013427734375000, -0.0548095703125000, +-0.0019531250000000, -0.0543823242187500, 0.0015563964843750, -0.0519714355468750, +-0.0144348144531250, -0.0535888671875000, -0.0126647949218750, -0.0496520996093750, +-0.0183105468750000, -0.0463867187500000, -0.0313415527343750, -0.0497131347656250, +-0.0252380371093750, -0.0351867675781250, -0.0344848632812500, -0.0399169921875000, +-0.0369873046875000, -0.0328369140625000, -0.0324707031250000, -0.0191040039062500, +-0.0330200195312500, -0.0278930664062500, -0.0334777832031250, -0.0084533691406250, +-0.0224609375000000, -0.0110168457031250, -0.0242919921875000, -0.0061340332031250, +-0.0159301757812500, 0.0068969726562500, -0.0038146972656250, -0.0008544921875000, +-0.0083618164062500, 0.0195922851562500, 0.0122375488281250, 0.0157775878906250, +0.0127868652343750, 0.0232849121093750, 0.0174865722656250, 0.0404052734375000, +0.0315856933593750, 0.0304870605468750, 0.0281372070312500, 0.0496826171875000, +0.0361022949218750, 0.0502929687500000, 0.0382995605468750, 0.0497131347656250, +0.0373535156250000, 0.0586547851562500, 0.0395812988281250, 0.0552062988281250, +0.0399780273437500, 0.0568542480468750, 0.0392761230468750, 0.0566711425781250, +0.0398559570312500, 0.0567626953125000, 0.0379333496093750, 0.0579833984375000, +0.0363769531250000, 0.0567016601562500, 0.0371704101562500, 0.0574035644531250, +0.0297851562500000, 0.0587463378906250, 0.0314025878906250, 0.0561218261718750, +0.0271911621093750, 0.0555419921875000, 0.0198669433593750, 0.0579528808593750, +0.0233764648437500, 0.0467529296875000, 0.0132751464843750, 0.0520324707031250, +0.0134277343750000, 0.0456237792968750, 0.0104980468750000, 0.0336303710937500, +0.0040588378906250, 0.0424804687500000, 0.0074462890625000, 0.0256042480468750, +-0.0027465820312500, 0.0254211425781250, -0.0010070800781250, 0.0270690917968750, +-0.0036621093750000, 0.0187988281250000, -0.0108032226562500, 0.0209350585937500, +-0.0063171386718750, 0.0258178710937500, -0.0153808593750000, 0.0216369628906250, +-0.0140075683593750, 0.0298461914062500, -0.0159912109375000, 0.0378112792968750, +-0.0219116210937500, 0.0312194824218750, -0.0179138183593750, 0.0576477050781250, +-0.0267333984375000, 0.0532226562500000, -0.0256652832031250, 0.0611267089843750, +-0.0264892578125000, 0.0837402343750000, -0.0326843261718750, 0.0734863281250000, +-0.0294189453125000}, +{-0.0243225097656250, 0.0236206054687500, -0.0245666503906250, 0.0216369628906250, +-0.0391235351562500, 0.0176696777343750, -0.0337524414062500, 0.0248413085937500, +-0.0380554199218750, 0.0317382812500000, -0.0544738769531250, 0.0257873535156250, +-0.0491943359375000, 0.0348205566406250, -0.0435180664062500, 0.0407714843750000, +-0.0518798828125000, 0.0290222167968750, -0.0405273437500000, 0.0245361328125000, +-0.0268249511718750, 0.0332641601562500, -0.0367126464843750, 0.0025634765625000, +-0.0076293945312500, 0.0057983398437500, -0.0092773437500000, 0.0032958984375000, +-0.0075073242187500, -0.0164489746093750, 0.0108337402343750, -0.0098876953125000, +0.0046691894531250, -0.0148315429687500, 0.0040588378906250, -0.0152893066406250, +0.0097351074218750, -0.0185546875000000, 0.0004272460937500, -0.0212097167968750, +-0.0092163085937500, -0.0172424316406250, -0.0022583007812500, -0.0345458984375000, +-0.0172729492187500, -0.0303955078125000, -0.0203552246093750, -0.0340881347656250, +-0.0172729492187500, -0.0482788085937500, -0.0216674804687500, -0.0417785644531250, +-0.0218811035156250, -0.0481872558593750, -0.0117492675781250, -0.0503845214843750, +-0.0146179199218750, -0.0484924316406250, -0.0066528320312500, -0.0493469238281250, +0.0051879882812500, -0.0496215820312500, -0.0002136230468750, -0.0475769042968750, +0.0187377929687500, -0.0492248535156250, 0.0187988281250000, -0.0453796386718750, +0.0225830078125000, -0.0426025390625000, 0.0344848632812500, -0.0458679199218750, +0.0301208496093750, -0.0306091308593750, 0.0399169921875000, -0.0359802246093750, +0.0403137207031250, -0.0278930664062500, 0.0407409667968750, -0.0128173828125000, +0.0463256835937500, -0.0224304199218750, 0.0442810058593750, -0.0007019042968750, +0.0431213378906250, -0.0023803710937500, 0.0453491210937500, 0.0010070800781250, +0.0423278808593750, 0.0141906738281250, 0.0386657714843750, 0.0072326660156250, +0.0411376953125000, 0.0218200683593750, 0.0354003906250000, 0.0191650390625000, +0.0361328125000000, 0.0244140625000000, 0.0352172851562500, 0.0356750488281250, +0.0320739746093750, 0.0285644531250000, 0.0344543457031250, 0.0473632812500000, +0.0289001464843750, 0.0449829101562500, 0.0311279296875000, 0.0500488281250000, +0.0285034179687500, 0.0641174316406250, 0.0229797363281250, 0.0574035644531250, +0.0269470214843750, 0.0720520019531250, 0.0189819335937500, 0.0715637207031250, +0.0201721191406250, 0.0746765136718750, 0.0186462402343750, 0.0850524902343750, +0.0131835937500000, 0.0804443359375000, 0.0163574218750000, 0.0861206054687500, +0.0106201171875000, 0.0900268554687500, 0.0105590820312500, 0.0840148925781250, +0.0111999511718750, 0.0827331542968750, 0.0083312988281250, 0.0870971679687500, +0.0091247558593750, 0.0672607421875000, 0.0114135742187500, 0.0723876953125000, +0.0099487304687500, 0.0662841796875000, 0.0119934082031250, 0.0483093261718750, +0.0156860351562500, 0.0574645996093750, 0.0137023925781250, 0.0497131347656250, +0.0151062011718750, 0.0439758300781250, 0.0173950195312500, 0.0543823242187500, +0.0152282714843750, 0.0599670410156250, 0.0143737792968750, 0.0534362792968750, +0.0172119140625000, 0.0730895996093750, 0.0098266601562500, 0.0750122070312500, +0.0134582519531250, 0.0699768066406250, 0.0086669921875000, 0.0776977539062500, +0.0018615722656250, 0.0781555175781250, 0.0087585449218750, 0.0560302734375000, +-0.0106506347656250, 0.0639648437500000, -0.0050354003906250, 0.0497741699218750, +-0.0103149414062500, 0.0245971679687500, -0.0267028808593750, 0.0371398925781250, +-0.0162963867187500, 0.0068969726562500, -0.0277404785156250, 0.0057067871093750, +-0.0315551757812500, 0.0020446777343750, -0.0235290527343750, -0.0145568847656250, +-0.0239868164062500, -0.0085449218750000, -0.0285034179687500, -0.0229797363281250, +-0.0093688964843750, -0.0213928222656250, -0.0127563476562500, -0.0275878906250000, +-0.0088806152343750, -0.0394592285156250, 0.0062255859375000, -0.0328063964843750, +0.0006408691406250, -0.0506286621093750, 0.0065612792968750, -0.0508728027343750, +0.0082702636718750, -0.0513610839843750, 0.0068054199218750, -0.0606689453125000, +0.0092468261718750, -0.0577392578125000, 0.0086059570312500, -0.0597229003906250, +0.0003662109375000, -0.0610656738281250, 0.0080566406250000, -0.0586547851562500, +-0.0079345703125000, -0.0592041015625000, -0.0245666503906250, -0.0601196289062500, +-0.0098876953125000, -0.0464782714843750, -0.0512695312500000, -0.0540771484375000, +-0.0492553710937500, -0.0395507812500000, -0.0514831542968750, -0.0198364257812500, +-0.0779418945312500, -0.0342407226562500, -0.0699768066406250, -0.0010070800781250, +-0.0654602050781250, 0.0015258789062500, -0.0747680664062500, -0.0020446777343750, +-0.0588989257812500, 0.0127258300781250, -0.0447692871093750, 0.0110778808593750, +-0.0561218261718750, -0.0005493164062500, -0.0058288574218750, 0.0034179687500000, +-0.0152587890625000, 0.0024108886718750, -0.0003662109375000, -0.0082092285156250, +0.0437927246093750, -0.0052490234375000, 0.0247497558593750, 0.0027770996093750, +0.0409240722656250, -0.0025329589843750, 0.0532226562500000, 0.0048217773437500, +0.0401000976562500, 0.0174560546875000, 0.0310974121093750, 0.0108642578125000, +0.0391540527343750, 0.0207519531250000, 0.0261230468750000, 0.0234680175781250, +0.0217895507812500, 0.0208435058593750, 0.0278320312500000, 0.0220947265625000, +0.0271301269531250, 0.0224609375000000, 0.0242614746093750, 0.0209655761718750, +0.0385437011718750, 0.0215454101562500, 0.0369262695312500, 0.0184936523437500, +0.0385742187500000, 0.0176086425781250, 0.0500488281250000, 0.0193786621093750, +0.0455932617187500, 0.0017395019531250, 0.0341796875000000, 0.0083923339843750, +0.0465393066406250, -0.0025329589843750, 0.0287170410156250, -0.0229492187500000, +0.0027160644531250, -0.0116577148437500, 0.0191345214843750, -0.0320129394531250, +-0.0089721679687500, -0.0364074707031250, -0.0169982910156250, -0.0325317382812500, +-0.0038757324218750, -0.0359497070312500, -0.0055236816406250, -0.0373535156250000, +-0.0126037597656250, -0.0435485839843750, 0.0105285644531250, -0.0347900390625000, +0.0163879394531250, -0.0529479980468750, 0.0017395019531250, -0.0726318359375000, +0.0009155273437500, -0.0564880371093750, 0.0112304687500000, -0.0941467285156250, +-0.0155029296875000, -0.1007690429687500, -0.0184020996093750, -0.0884094238281250, +-0.0125427246093750, -0.0943603515625000, -0.0217285156250000, -0.0470581054687500, +0.0038452148437500, -0.0283813476562500, -0.0159912109375000, -0.0386047363281250, +-0.0086975097656250, -0.0182495117187500, -0.0124206542968750, -0.0032348632812500, +-0.0245056152343750, -0.0201721191406250, -0.0220947265625000, 0.0340270996093750, +-0.0175476074218750, 0.0301818847656250, -0.0174255371093750, 0.0339355468750000, +-0.0256042480468750, 0.0683898925781250, -0.0253295898437500, 0.0565490722656250, +-0.0194091796875000, 0.0560913085937500, -0.0530090332031250, 0.0675964355468750, +-0.0502319335937500, 0.0530090332031250, -0.0483093261718750, 0.0366516113281250, +-0.0703430175781250, 0.0493469238281250, -0.0675354003906250, 0.0275268554687500, +-0.0433044433593750, 0.0229797363281250, -0.0540466308593750, 0.0304260253906250, +-0.0427551269531250, 0.0263061523437500, -0.0149230957031250, 0.0237121582031250, +-0.0274963378906250, 0.0375976562500000, -0.0164184570312500, 0.0377502441406250, +-0.0115356445312500, 0.0348815917968750, -0.0141601562500000, 0.0410461425781250, +-0.0156555175781250, 0.0425109863281250, -0.0158996582031250, 0.0334472656250000, +-0.0056457519531250, 0.0337829589843750, -0.0103759765625000, 0.0385437011718750, +-0.0051879882812500, 0.0359497070312500, 0.0075378417968750, 0.0325927734375000, +0.0015869140625000, 0.0435485839843750, 0.0058898925781250, 0.0500793457031250, +0.0084838867187500, 0.0302429199218750, 0.0079040527343750, 0.0240173339843750, +0.0066833496093750, 0.0389099121093750, 0.0064697265625000, -0.0217590332031250, +0.0144348144531250, -0.0135498046875000, 0.0120849609375000, -0.0235900878906250, +0.0147094726562500, -0.0648803710937500, 0.0236511230468750, -0.0469970703125000, +0.0206604003906250, -0.0741577148437500, 0.0182495117187500, -0.0771484375000000, +0.0231628417968750, -0.0705871582031250, 0.0164184570312500, -0.0812377929687500, +0.0082397460937500, -0.0805664062500000, 0.0137939453125000, -0.0619812011718750, +-0.0008239746093750, -0.0684509277343750, 0.0014648437500000, -0.0593872070312500, +-0.0046386718750000, -0.0423278808593750, -0.0156250000000000, -0.0525207519531250, +-0.0086364746093750, -0.0268554687500000, -0.0312805175781250, -0.0298156738281250, +-0.0283203125000000, -0.0241088867187500, -0.0337829589843750, -0.0057373046875000, +-0.0509033203125000, -0.0150756835937500, -0.0434570312500000, -0.0000305175781250, +-0.0566101074218750, 0.0039978027343750, -0.0576477050781250, -0.0034790039062500, +-0.0575866699218750, -0.0014038085937500, -0.0646972656250000, 0.0028076171875000, +-0.0620422363281250, -0.0145568847656250, -0.0588989257812500, -0.0129394531250000, +-0.0644531250000000, -0.0145874023437500, -0.0542297363281250, -0.0251464843750000, +-0.0440979003906250, -0.0207519531250000, -0.0529174804687500, -0.0249328613281250, +-0.0272216796875000, -0.0270690917968750, -0.0279235839843750, -0.0229492187500000, +-0.0262756347656250, -0.0226135253906250, -0.0121765136718750, -0.0255737304687500, +-0.0166931152343750, -0.0137634277343750, -0.0082702636718750, -0.0175170898437500, +-0.0107116699218750, -0.0129699707031250, -0.0032653808593750, -0.0028076171875000, +0.0059814453125000, -0.0097656250000000, -0.0010375976562500, 0.0028686523437500, +0.0236816406250000, 0.0020751953125000, 0.0206909179687500, 0.0021972656250000, +0.0278625488281250, 0.0090026855468750, 0.0460510253906250, 0.0054321289062500, +0.0376586914062500, 0.0078430175781250, 0.0585021972656250, 0.0092163085937500, +0.0580749511718750, 0.0064697265625000, 0.0611877441406250, 0.0055847167968750, +0.0750732421875000, 0.0068664550781250, 0.0698547363281250, 0.0010681152343750, +0.0738220214843750, 0.0025024414062500, 0.0768127441406250, 0.0001220703125000, +0.0739135742187500, -0.0048828125000000, 0.0709838867187500, -0.0015563964843750, +0.0718994140625000, -0.0064697265625000, 0.0725097656250000, -0.0065002441406250, +0.0691833496093750, -0.0055847167968750, 0.0727844238281250, -0.0076293945312500, +0.0773010253906250, -0.0064086914062500, 0.0731201171875000, -0.0036010742187500, +0.0797424316406250, -0.0049133300781250, 0.0806579589843750, -0.0014038085937500, +0.0772705078125000, 0.0028686523437500, 0.0786437988281250, 0.0006408691406250, +0.0792236328125000, 0.0087585449218750, 0.0694885253906250, 0.0083618164062500, +0.0722351074218750, 0.0106811523437500, 0.0672302246093750, 0.0164184570312500, +0.0578308105468750, 0.0141906738281250, 0.0629272460937500, 0.0204772949218750, +0.0516662597656250, 0.0204467773437500, 0.0520629882812500, 0.0208740234375000, +0.0494995117187500, 0.0249328613281250, 0.0426025390625000, 0.0234375000000000, +0.0461730957031250, 0.0219116210937500, 0.0355529785156250, 0.0240783691406250, +0.0380859375000000, 0.0203247070312500, 0.0329589843750000, 0.0161132812500000, +0.0241394042968750, 0.0188293457031250, 0.0305786132812500, 0.0096740722656250, +0.0142211914062500, 0.0100097656250000, 0.0168762207031250, 0.0086975097656250, +0.0121154785156250, 0.0026245117187500, -0.0001220703125000, 0.0043640136718750, +0.0068054199218750, 0.0020751953125000, -0.0080871582031250, 0.0006103515625000, +-0.0064086914062500}, +{0.0097656250000000, -0.1048889160156250, 0.0078125000000000, -0.0867614746093750, +0.0094909667968750, -0.0467834472656250, 0.0159912109375000, -0.0674438476562500, +0.0141601562500000, -0.0396118164062500, 0.0108642578125000, -0.0339355468750000, +0.0145263671875000, -0.0368652343750000, 0.0093994140625000, -0.0284118652343750, +0.0029602050781250, -0.0303039550781250, 0.0073852539062500, -0.0265197753906250, +-0.0064086914062500, -0.0268249511718750, -0.0031433105468750, -0.0248413085937500, +-0.0104675292968750, -0.0209045410156250, -0.0230712890625000, -0.0228271484375000, +-0.0153198242187500, -0.0209045410156250, -0.0374755859375000, -0.0200500488281250, +-0.0358581542968750, -0.0187988281250000, -0.0393066406250000, -0.0187377929687500, +-0.0538024902343750, -0.0200500488281250, -0.0478210449218750, -0.0126037597656250, +-0.0569152832031250, -0.0144348144531250, -0.0580139160156250, -0.0112915039062500, +-0.0568847656250000, -0.0056457519531250, -0.0617980957031250, -0.0092163085937500, +-0.0606384277343750, 0.0030517578125000, -0.0516357421875000, -0.0001525878906250, +-0.0579833984375000, 0.0042114257812500, -0.0473327636718750, 0.0156860351562500, +-0.0323791503906250, 0.0095825195312500, -0.0421447753906250, 0.0174255371093750, +-0.0200195312500000, 0.0202636718750000, -0.0191040039062500, 0.0159912109375000, +-0.0187377929687500, 0.0169372558593750, -0.0087585449218750, 0.0196533203125000, +-0.0119628906250000, 0.0080261230468750, -0.0028686523437500, 0.0117492675781250, +-0.0060424804687500, 0.0070800781250000, 0.0016784667968750, -0.0035095214843750, +0.0125732421875000, 0.0025939941406250, 0.0057983398437500, -0.0099182128906250, +0.0278015136718750, -0.0095520019531250, 0.0249328613281250, -0.0109863281250000, +0.0338439941406250, -0.0186462402343750, 0.0509948730468750, -0.0155639648437500, +0.0417480468750000, -0.0207824707031250, 0.0693054199218750, -0.0216369628906250, +0.0672607421875000, -0.0216979980468750, 0.0723876953125000, -0.0245361328125000, +0.0917663574218750, -0.0246887207031250, 0.0837707519531250, -0.0250854492187500, +0.0924682617187500, -0.0267639160156250, 0.0957946777343750, -0.0252990722656250, +0.0919799804687500, -0.0242004394531250, 0.0924682617187500, -0.0263061523437500, +0.0937194824218750, -0.0212097167968750, 0.0860900878906250, -0.0230407714843750, +0.0884704589843750, -0.0205688476562500, 0.0845336914062500, -0.0160522460937500, +0.0776977539062500, -0.0195312500000000, 0.0823974609375000, -0.0110168457031250, +0.0708923339843750, -0.0128479003906250, 0.0727233886718750, -0.0103759765625000, +0.0685119628906250, -0.0034484863281250, 0.0599365234375000, -0.0072021484375000, +0.0652770996093750, 0.0003662109375000, 0.0501098632812500, -0.0001831054687500, +0.0537414550781250, 0.0013427734375000, 0.0460205078125000, 0.0059814453125000, +0.0331115722656250, 0.0035705566406250, 0.0422363281250000, 0.0104370117187500, +0.0165100097656250, 0.0096740722656250, 0.0204772949218750, 0.0111999511718750, +0.0143127441406250, 0.0163574218750000, -0.0049743652343750, 0.0143127441406250, +0.0048522949218750, 0.0177612304687500, -0.0104370117187500, 0.0187377929687500, +-0.0117797851562500, 0.0183410644531250, -0.0121765136718750, 0.0196228027343750, +-0.0181579589843750, 0.0199584960937500, -0.0153808593750000, 0.0190429687500000, +-0.0263671875000000, 0.0199584960937500, -0.0220031738281250, 0.0185241699218750, +-0.0300292968750000, 0.0171203613281250, -0.0429382324218750, 0.0184326171875000, +-0.0341186523437500, 0.0126037597656250, -0.0530700683593750, 0.0141601562500000, +-0.0538024902343750, 0.0113830566406250, -0.0519104003906250, 0.0057373046875000, +-0.0608520507812500, 0.0088195800781250, -0.0586547851562500, 0.0025024414062500, +-0.0518798828125000, 0.0018920898437500, -0.0578002929687500, 0.0017089843750000, +-0.0485839843750000, -0.0009155273437500, -0.0378112792968750, 0.0001525878906250, +-0.0469665527343750, -0.0021362304687500, -0.0216064453125000, -0.0016784667968750, +-0.0253601074218750, -0.0013122558593750, -0.0194396972656250, -0.0026855468750000, +-0.0009155273437500, -0.0018615722656250, -0.0098571777343750, -0.0007324218750000, +0.0082397460937500, -0.0008850097656250, 0.0075683593750000, 0.0007934570312500, +0.0105895996093750, 0.0021057128906250, 0.0225830078125000, 0.0014953613281250, +0.0169982910156250, 0.0068664550781250, 0.0238647460937500, 0.0072937011718750, +0.0263061523437500, 0.0050354003906250, 0.0238037109375000, 0.0072937011718750, +0.0247802734375000, 0.0086364746093750, 0.0258483886718750, -0.0010986328125000, +0.0207519531250000, 0.0011291503906250, 0.0224304199218750, -0.0027160644531250, +0.0202026367187500, -0.0094909667968750, 0.0147705078125000, -0.0056457519531250, +0.0180664062500000, -0.0245971679687500, 0.0166015625000000, -0.0205993652343750, +0.0134887695312500, -0.0245666503906250, 0.0179443359375000, -0.0408935546875000, +0.0222167968750000, -0.0350341796875000, 0.0186462402343750, -0.0379943847656250, +0.0246582031250000, -0.0411071777343750, 0.0266418457031250, -0.0375061035156250, +0.0231018066406250, -0.0342102050781250, 0.0243225097656250, -0.0361328125000000, +0.0258789062500000, -0.0346679687500000, 0.0098266601562500, -0.0317993164062500, +0.0162353515625000, -0.0334777832031250, 0.0069885253906250, -0.0354919433593750, +-0.0108642578125000, -0.0341796875000000, -0.0003662109375000, -0.0400390625000000, +-0.0191955566406250, -0.0386352539062500, -0.0222778320312500, -0.0379638671875000, +-0.0207519531250000, -0.0438842773437500, -0.0278930664062500, -0.0437011718750000, +-0.0269165039062500, -0.0321655273437500, -0.0252075195312500, -0.0352172851562500, +-0.0265197753906250, -0.0334167480468750, -0.0256347656250000, -0.0241394042968750, +-0.0226135253906250, -0.0248718261718750, -0.0239868164062500, -0.0173034667968750, +-0.0273742675781250, -0.0197448730468750, -0.0239562988281250, -0.0202636718750000, +-0.0280151367187500, -0.0148620605468750, -0.0343627929687500, -0.0161743164062500, +-0.0302429199218750, -0.0166320800781250, -0.0379028320312500, -0.0178527832031250, +-0.0404052734375000, -0.0157470703125000, -0.0358886718750000, -0.0128173828125000, +-0.0364379882812500, -0.0160827636718750, -0.0390930175781250, -0.0188903808593750, +-0.0259704589843750, -0.0136413574218750, -0.0259704589843750, -0.0205688476562500, +-0.0264587402343750, -0.0315551757812500, -0.0208129882812500, -0.0256042480468750, +-0.0216064453125000, -0.0297241210937500, -0.0174255371093750, -0.0352478027343750, +-0.0144042968750000, -0.0293273925781250, -0.0239868164062500, -0.0248718261718750, +-0.0276489257812500, -0.0294189453125000, -0.0196533203125000, -0.0156555175781250, +-0.0458374023437500, -0.0193481445312500, -0.0473327636718750, -0.0122070312500000, +-0.0410766601562500, 0.0003051757812500, -0.0519409179687500, -0.0083618164062500, +-0.0533447265625000, 0.0122985839843750, -0.0303649902343750, 0.0117797851562500, +-0.0362854003906250, 0.0125732421875000, -0.0314636230468750, 0.0254211425781250, +-0.0122985839843750, 0.0215759277343750, -0.0196533203125000, 0.0188598632812500, +-0.0141906738281250, 0.0227355957031250, -0.0086669921875000, 0.0198059082031250, +-0.0180664062500000, 0.0130310058593750, -0.0243530273437500, 0.0163879394531250, +-0.0165100097656250, 0.0193176269531250, -0.0298767089843750, 0.0156860351562500, +-0.0349121093750000, 0.0191040039062500, -0.0245056152343750, 0.0274353027343750, +-0.0221252441406250, 0.0241394042968750, -0.0275268554687500, 0.0175781250000000, +-0.0036315917968750, 0.0262145996093750, -0.0059509277343750, 0.0149841308593750, +-0.0001220703125000, -0.0003356933593750, 0.0174560546875000, 0.0111083984375000, +0.0106506347656250, -0.0103759765625000, 0.0217285156250000, -0.0116271972656250, +0.0236206054687500, -0.0097351074218750, 0.0242919921875000, -0.0180053710937500, +0.0290832519531250, -0.0158996582031250, 0.0273742675781250, -0.0201416015625000, +0.0322875976562500, -0.0174865722656250, 0.0317993164062500, -0.0223388671875000, +0.0346984863281250, -0.0282287597656250, 0.0388183593750000, -0.0223388671875000, +0.0362548828125000, -0.0367126464843750, 0.0453796386718750, -0.0354614257812500, +0.0444030761718750, -0.0363769531250000, 0.0457458496093750, -0.0451049804687500, +0.0518798828125000, -0.0415039062500000, 0.0492248535156250, -0.0451354980468750, +0.0519714355468750, -0.0465087890625000, 0.0524291992187500, -0.0449218750000000, +0.0505065917968750, -0.0459289550781250, 0.0506896972656250, -0.0465393066406250, +0.0503540039062500, -0.0397949218750000, 0.0445861816406250, -0.0435791015625000, +0.0462341308593750, -0.0360107421875000, 0.0412292480468750, -0.0267333984375000, +0.0343627929687500, -0.0335388183593750, 0.0374755859375000, -0.0109252929687500, +0.0247497558593750, -0.0146789550781250, 0.0255432128906250, -0.0072937011718750, +0.0227661132812500, 0.0096435546875000, 0.0140380859375000, -0.0000915527343750, +0.0171508789062500, 0.0235290527343750, 0.0095520019531250, 0.0199279785156250, +0.0096740722656250, 0.0267639160156250, 0.0078430175781250, 0.0442504882812500, +0.0032043457031250, 0.0340576171875000, 0.0060729980468750, 0.0554809570312500, +0.0004882812500000, 0.0540161132812500, 0.0014953613281250, 0.0568847656250000, +0.0006713867187500, 0.0699157714843750, -0.0028991699218750, 0.0637512207031250, +-0.0003662109375000, 0.0762023925781250, -0.0044555664062500, 0.0736694335937500, +-0.0024414062500000, 0.0790405273437500, -0.0037231445312500, 0.0891418457031250, +-0.0077209472656250, 0.0820312500000000, -0.0045471191406250, 0.1015625000000000, +-0.0083312988281250, 0.1006164550781250, -0.0087585449218750, 0.1008911132812500, +-0.0074157714843750, 0.1141357421875000, -0.0083007812500000, 0.1103515625000000, +-0.0082702636718750, 0.0998840332031250, -0.0058898925781250, 0.1100463867187500, +-0.0063781738281250, 0.0914916992187500, -0.0040893554687500, 0.0706787109375000, +-0.0018310546875000, 0.0862426757812500, -0.0034790039062500, 0.0374145507812500, +0.0046691894531250, 0.0419006347656250, 0.0028076171875000, 0.0314941406250000, +0.0057067871093750, -0.0025634765625000, 0.0131225585937500, 0.0120239257812500, +0.0097045898437500, -0.0143127441406250, 0.0144042968750000, -0.0166931152343750, +0.0157165527343750, -0.0188903808593750, 0.0156250000000000, -0.0320129394531250, +0.0169067382812500, -0.0273132324218750, 0.0170898437500000, -0.0400390625000000, +0.0210876464843750, -0.0400085449218750, 0.0197753906250000, -0.0437316894531250, +0.0212097167968750, -0.0530090332031250, 0.0250549316406250, -0.0490417480468750, +0.0228881835937500, -0.0563354492187500, 0.0239257812500000, -0.0572814941406250, +0.0261535644531250, -0.0570983886718750, 0.0231933593750000, -0.0605468750000000, +0.0210876464843750, -0.0592651367187500, 0.0234680175781250, -0.0570373535156250, +0.0154724121093750, -0.0612487792968750, 0.0176391601562500, -0.0513916015625000, +0.0111083984375000, -0.0436401367187500, 0.0044860839843750, -0.0513916015625000, +0.0106201171875000, -0.0206909179687500, -0.0176696777343750, -0.0248718261718750, +-0.0114440917968750, -0.0194396972656250, -0.0194091796875000, 0.0039367675781250, +-0.0451049804687500, -0.0047912597656250, -0.0331420898437500, -0.0004882812500000, +-0.0367126464843750, 0.0050048828125000, -0.0462646484375000, 0.0008850097656250, +-0.0339965820312500, -0.0040588378906250, -0.0198669433593750, -0.0009155273437500, +-0.0289306640625000, 0.0009765625000000, -0.0208129882812500, -0.0036010742187500, +-0.0103759765625000, 0.0030822753906250, -0.0261535644531250, 0.0116271972656250, +-0.0386047363281250}, +{0.0256958007812500, -0.0319824218750000, 0.0235595703125000, -0.0244750976562500, +0.0234680175781250, -0.0382080078125000, 0.0233459472656250, -0.0392456054687500, +0.0226440429687500, -0.0368652343750000, 0.0217895507812500, -0.0420227050781250, +0.0215454101562500, -0.0412902832031250, 0.0211181640625000, -0.0368957519531250, +0.0187072753906250, -0.0383300781250000, 0.0185241699218750, -0.0357360839843750, +0.0171813964843750, -0.0316467285156250, 0.0148925781250000, -0.0336914062500000, +0.0148315429687500, -0.0253295898437500, 0.0125732421875000, -0.0282897949218750, +0.0121765136718750, -0.0218505859375000, 0.0102844238281250, -0.0130310058593750, +0.0079345703125000, -0.0197753906250000, 0.0082702636718750, -0.0009765625000000, +0.0036315917968750, -0.0037841796875000, 0.0025024414062500, -0.0002441406250000, +0.0017089843750000, 0.0121154785156250, -0.0010986328125000, 0.0051879882812500, +-0.0017395019531250, 0.0191650390625000, -0.0015869140625000, 0.0158691406250000, +-0.0034484863281250, 0.0227966308593750, -0.0042114257812500, 0.0343322753906250, +-0.0034484863281250, 0.0259704589843750, -0.0044555664062500, 0.0527038574218750, +-0.0059814453125000, 0.0479125976562500, -0.0065917968750000, 0.0556640625000000, +-0.0069885253906250, 0.0772705078125000, -0.0076599121093750, 0.0656127929687500, +-0.0079345703125000, 0.0807495117187500, -0.0069274902343750, 0.0862426757812500, +-0.0074462890625000, 0.0767822265625000, -0.0064392089843750, 0.0771179199218750, +-0.0054931640625000, 0.0814819335937500, -0.0061340332031250, 0.0556030273437500, +-0.0006408691406250, 0.0610046386718750, -0.0029296875000000, 0.0500488281250000, +0.0007629394531250, 0.0277404785156250, 0.0064697265625000, 0.0391845703125000, +0.0020751953125000, 0.0113220214843750, 0.0121459960937500, 0.0130310058593750, +0.0101318359375000, 0.0052795410156250, 0.0136413574218750, -0.0133056640625000, +0.0209350585937500, -0.0038146972656250, 0.0153808593750000, -0.0319213867187500, +0.0284729003906250, -0.0286254882812500, 0.0271301269531250, -0.0362854003906250, +0.0271911621093750, -0.0583496093750000, 0.0356750488281250, -0.0485534667968750, +0.0326843261718750, -0.0638732910156250, 0.0302429199218750, -0.0680236816406250, +0.0343017578125000, -0.0642089843750000, 0.0296630859375000, -0.0675048828125000, +0.0236511230468750, -0.0681152343750000, 0.0283508300781250, -0.0603942871093750, +0.0181884765625000, -0.0636596679687500, 0.0185852050781250, -0.0559692382812500, +0.0173339843750000, -0.0473022460937500, 0.0114440917968750, -0.0535583496093750, +0.0140075683593750, -0.0267639160156250, 0.0075378417968750, -0.0307617187500000, +0.0081787109375000, -0.0237731933593750, 0.0080871582031250, -0.0021057128906250, +0.0038146972656250, -0.0114746093750000, 0.0046997070312500, -0.0024719238281250, +0.0049743652343750, 0.0028076171875000, 0.0062561035156250, -0.0025634765625000, +-0.0006408691406250, -0.0053405761718750, -0.0036621093750000, -0.0019226074218750, +0.0017700195312500, -0.0045776367187500, -0.0222473144531250, -0.0081481933593750, +-0.0190124511718750, -0.0018920898437500, -0.0220947265625000, 0.0028991699218750, +-0.0406494140625000, -0.0015869140625000, -0.0348815917968750, 0.0108642578125000, +-0.0304260253906250, 0.0109252929687500, -0.0346374511718750, 0.0117492675781250, +-0.0343627929687500, 0.0184020996093750, -0.0260620117187500, 0.0161437988281250, +-0.0259704589843750, 0.0195312500000000, -0.0418090820312500, 0.0200195312500000, +-0.0376586914062500, 0.0192565917968750, -0.0421142578125000, 0.0212097167968750, +-0.0544433593750000, 0.0206909179687500, -0.0497741699218750, 0.0148925781250000, +-0.0669555664062500, 0.0184936523437500, -0.0640258789062500, 0.0110473632812500, +-0.0667114257812500, 0.0019836425781250, -0.0842285156250000, 0.0081787109375000, +-0.0786132812500000, -0.0107421875000000, -0.0580749511718750, -0.0094299316406250, +-0.0724182128906250, -0.0140075683593750, -0.0552673339843750, -0.0268249511718750, +-0.0235595703125000, -0.0211791992187500, -0.0390625000000000, -0.0348815917968750, +-0.0101318359375000, -0.0334777832031250, -0.0095520019531250, -0.0389099121093750, +-0.0043640136718750, -0.0494079589843750, 0.0131835937500000, -0.0432128906250000, +0.0040283203125000, -0.0599975585937500, 0.0185546875000000, -0.0596618652343750, +0.0227966308593750, -0.0599365234375000, 0.0183105468750000, -0.0706787109375000, +0.0177917480468750, -0.0678100585937500, 0.0199279785156250, -0.0612182617187500, +0.0285034179687500, -0.0691833496093750, 0.0236511230468750, -0.0569152832031250, +0.0265502929687500, -0.0420227050781250, 0.0365600585937500, -0.0528869628906250, +0.0338745117187500, -0.0240478515625000, 0.0409851074218750, -0.0248413085937500, +0.0421752929687500, -0.0213317871093750, 0.0352478027343750, -0.0059814453125000, +0.0379943847656250, -0.0122070312500000, 0.0426330566406250, 0.0097351074218750, +0.0121459960937500, 0.0057067871093750, 0.0195007324218750, 0.0106811523437500, +0.0107727050781250, 0.0398864746093750, -0.0320129394531250, 0.0200805664062500, +0.0315856933593750, 0.0125427246093750, 0.0014648437500000, 0.0070190429687500, +0.0220642089843750, 0.0177612304687500, 0.0007934570312500, 0.0261535644531250, +-0.0331420898437500, 0.0182189941406250, -0.0158996582031250, 0.0323486328125000, +-0.0224914550781250, 0.0381469726562500, -0.0389709472656250, 0.0296020507812500, +-0.0173950195312500, 0.0281982421875000, 0.0072937011718750, 0.0337524414062500, +-0.0093383789062500, 0.0158081054687500, 0.0067138671875000, 0.0155334472656250, +0.0206604003906250, 0.0182800292968750, 0.0022888183593750, 0.0097045898437500, +-0.0116271972656250, 0.0094909667968750, 0.0013122558593750, 0.0191650390625000, +-0.0222167968750000, 0.0186462402343750, -0.0285644531250000, 0.0147094726562500, +-0.0209045410156250, 0.0203552246093750, -0.0225524902343750, 0.0210266113281250, +-0.0260620117187500, -0.0038146972656250, -0.0206604003906250, 0.0113220214843750, +-0.0158081054687500, -0.0171508789062500, -0.0252075195312500, -0.0539245605468750, +-0.0324096679687500, -0.0261535644531250, -0.0255126953125000, -0.0949096679687500, +-0.0394897460937500, -0.0936584472656250, -0.0454711914062500, -0.0949707031250000, +-0.0346679687500000, -0.1334228515625000, -0.0324096679687500, -0.1212768554687500, +-0.0398254394531250, -0.1236572265625000, -0.0140380859375000, -0.1337890625000000, +-0.0146789550781250, -0.1169738769531250, -0.0148315429687500, -0.1060180664062500, +-0.0015869140625000, -0.1188354492187500, -0.0047912597656250, -0.0702514648437500, +-0.0035095214843750, -0.0772399902343750, -0.0043029785156250, -0.0690917968750000, +-0.0006103515625000, -0.0340270996093750, 0.0025329589843750, -0.0482177734375000, +-0.0010986328125000, -0.0325927734375000, 0.0105590820312500, -0.0303344726562500, +0.0110778808593750, -0.0278930664062500, 0.0092468261718750, -0.0199584960937500, +0.0144348144531250, -0.0258483886718750, 0.0145874023437500, -0.0171813964843750, +0.0083007812500000, -0.0150451660156250, 0.0094299316406250, -0.0169982910156250, +0.0091552734375000, -0.0145568847656250, 0.0050964355468750, -0.0141296386718750, +0.0061645507812500, -0.0196533203125000, 0.0066833496093750, -0.0174255371093750, +0.0072021484375000, -0.0179748535156250, 0.0056762695312500, -0.0237426757812500, +0.0050964355468750, -0.0217285156250000, 0.0065002441406250, -0.0169982910156250, +0.0000610351562500, -0.0216674804687500, 0.0018310546875000, -0.0121459960937500, +-0.0016784667968750, -0.0031738281250000, -0.0070800781250000, -0.0115051269531250, +-0.0036926269531250, 0.0174255371093750, -0.0177612304687500, 0.0140075683593750, +-0.0138244628906250, 0.0182800292968750, -0.0212097167968750, 0.0380859375000000, +-0.0349731445312500, 0.0298156738281250, -0.0268249511718750, 0.0387268066406250, +-0.0450744628906250, 0.0414123535156250, -0.0449829101562500, 0.0387268066406250, +-0.0467529296875000, 0.0407714843750000, -0.0572204589843750, 0.0413818359375000, +-0.0527648925781250, 0.0360717773437500, -0.0581665039062500, 0.0392150878906250, +-0.0610046386718750, 0.0346069335937500, -0.0549621582031250, 0.0287170410156250, +-0.0542907714843750, 0.0343322753906250, -0.0577697753906250, 0.0189208984375000, +-0.0361938476562500, 0.0230407714843750, -0.0413513183593750, 0.0175781250000000, +-0.0322570800781250, 0.0054931640625000, -0.0126647949218750, 0.0142211914062500, +-0.0226745605468750, -0.0049438476562500, -0.0021972656250000, -0.0017395019531250, +-0.0031127929687500, -0.0056152343750000, 0.0018310546875000, -0.0191955566406250, +0.0149536132812500, -0.0117797851562500, 0.0078430175781250, -0.0258483886718750, +0.0267333984375000, -0.0249633789062500, 0.0252380371093750, -0.0266418457031250, +0.0302124023437500, -0.0352478027343750, 0.0438537597656250, -0.0308532714843750, +0.0382385253906250, -0.0376281738281250, 0.0531616210937500, -0.0378723144531250, +0.0528869628906250, -0.0376586914062500, 0.0556640625000000, -0.0407409667968750, +0.0663452148437500, -0.0393371582031250, 0.0622253417968750, -0.0410461425781250, +0.0642700195312500, -0.0412597656250000, 0.0694274902343750, -0.0408020019531250, +0.0608825683593750, -0.0415954589843750, 0.0552673339843750, -0.0416259765625000, +0.0617980957031250, -0.0398864746093750, 0.0368652343750000, -0.0405273437500000, +0.0417480468750000, -0.0390014648437500, 0.0332641601562500, -0.0368652343750000, +0.0126647949218750, -0.0373229980468750, 0.0234680175781250, -0.0320129394531250, +0.0034790039062500, -0.0334777832031250, 0.0032653808593750, -0.0284118652343750, +0.0011596679687500, -0.0222167968750000, -0.0090332031250000, -0.0257263183593750, +-0.0037231445312500, -0.0104064941406250, -0.0172119140625000, -0.0123901367187500, +-0.0141601562500000, -0.0079040527343750, -0.0202941894531250, 0.0042724609375000, +-0.0323181152343750, -0.0001831054687500, -0.0245971679687500, 0.0107116699218750, +-0.0419006347656250, 0.0119628906250000, -0.0418395996093750, 0.0122985839843750, +-0.0418395996093750, 0.0179443359375000, -0.0516357421875000, 0.0170288085937500, +-0.0484008789062500, 0.0170593261718750, -0.0454101562500000, 0.0187072753906250, +-0.0493164062500000, 0.0165710449218750, -0.0439758300781250, 0.0143432617187500, +-0.0374145507812500, 0.0159912109375000, -0.0420837402343750, 0.0099792480468750, +-0.0305480957031250, 0.0102844238281250, -0.0334167480468750, 0.0095825195312500, +-0.0273742675781250, 0.0051269531250000, -0.0177612304687500, 0.0062561035156250, +-0.0251770019531250, 0.0074462890625000, -0.0036010742187500, 0.0047302246093750, +-0.0071716308593750, 0.0090942382812500, -0.0013427734375000, 0.0135803222656250, +0.0155639648437500, 0.0100402832031250, 0.0069580078125000, 0.0215454101562500, +0.0210266113281250, 0.0208129882812500, 0.0239257812500000, 0.0212402343750000, +0.0195007324218750, 0.0294799804687500, 0.0234069824218750, 0.0267944335937500, +0.0253601074218750, 0.0195007324218750, 0.0155639648437500, 0.0255737304687500, +0.0166625976562500, 0.0153198242187500, 0.0179748535156250, 0.0013427734375000, +0.0124816894531250, 0.0095214843750000, 0.0128479003906250, -0.0117492675781250, +0.0173950195312500, -0.0136413574218750, 0.0165710449218750, -0.0115661621093750, +0.0159912109375000, -0.0218505859375000, 0.0186767578125000, -0.0204467773437500, +0.0186767578125000, -0.0069274902343750, 0.0168762207031250, -0.0123291015625000, +0.0177307128906250, -0.0063476562500000, 0.0155639648437500, 0.0097961425781250, +0.0137329101562500, 0.0041503906250000, 0.0154418945312500, 0.0066833496093750, +0.0061340332031250}, +{-0.0537414550781250, 0.0000000000000000, -0.0418090820312500, -0.0028076171875000, +-0.0481872558593750, 0.0004577636718750, -0.0365905761718750, 0.0056762695312500, +-0.0208129882812500, 0.0005798339843750, -0.0321350097656250, 0.0119323730468750, +-0.0015869140625000, 0.0085754394531250, -0.0028991699218750, 0.0109252929687500, +0.0008544921875000, 0.0197753906250000, 0.0191650390625000, 0.0139465332031250, +0.0118103027343750, 0.0219421386718750, 0.0242614746093750, 0.0209960937500000, +0.0236511230468750, 0.0203247070312500, 0.0273437500000000, 0.0239868164062500, +0.0358581542968750, 0.0204467773437500, 0.0307617187500000, 0.0205383300781250, +0.0439758300781250, 0.0204467773437500, 0.0433349609375000, 0.0178222656250000, +0.0444641113281250, 0.0158691406250000, 0.0528869628906250, 0.0155639648437500, +0.0496826171875000, 0.0122070312500000, 0.0510559082031250, 0.0116271972656250, +0.0541992187500000, 0.0098571777343750, 0.0493774414062500, 0.0074462890625000, +0.0463562011718750, 0.0075988769531250, 0.0500183105468750, 0.0025634765625000, +0.0357055664062500, 0.0025634765625000, 0.0395202636718750, 0.0001525878906250, +0.0317382812500000, -0.0044555664062500, 0.0183410644531250, -0.0040283203125000, +0.0260314941406250, -0.0092468261718750, 0.0027160644531250, -0.0095825195312500, +0.0058898925781250, -0.0118713378906250, -0.0019226074218750, -0.0160217285156250, +-0.0197448730468750, -0.0149841308593750, -0.0099487304687500, -0.0192871093750000, +-0.0325622558593750, -0.0198059082031250, -0.0318298339843750, -0.0196838378906250, +-0.0338134765625000, -0.0220642089843750, -0.0481872558593750, -0.0221252441406250, +-0.0424194335937500, -0.0202026367187500, -0.0430908203125000, -0.0219726562500000, +-0.0485229492187500, -0.0190429687500000, -0.0406799316406250, -0.0161437988281250, +-0.0328063964843750, -0.0192565917968750, -0.0390625000000000, -0.0092773437500000, +-0.0257873535156250, -0.0112304687500000, -0.0254211425781250, -0.0075683593750000, +-0.0248413085937500, 0.0009765625000000, -0.0196533203125000, -0.0032043457031250, +-0.0224609375000000, 0.0061340332031250, -0.0118713378906250, 0.0065002441406250, +-0.0169677734375000, 0.0069274902343750, -0.0089721679687500, 0.0118103027343750, +0.0042724609375000, 0.0101928710937500, -0.0046997070312500, 0.0115356445312500, +0.0148925781250000, 0.0119323730468750, 0.0154113769531250, 0.0121459960937500, +0.0142822265625000, 0.0123596191406250, 0.0245361328125000, 0.0118103027343750, +0.0224609375000000, 0.0137634277343750, 0.0170898437500000, 0.0130310058593750, +0.0212707519531250, 0.0144653320312500, 0.0188293457031250, 0.0166320800781250, +0.0108032226562500, 0.0150756835937500, 0.0141906738281250, 0.0200195312500000, +0.0165710449218750, 0.0204772949218750, 0.0128784179687500, 0.0190429687500000, +0.0149230957031250, 0.0216369628906250, 0.0208740234375000, 0.0219116210937500, +0.0185546875000000, 0.0127563476562500, 0.0157470703125000, 0.0168762207031250, +0.0187377929687500, 0.0090332031250000, 0.0155029296875000, -0.0024108886718750, +0.0106201171875000, 0.0049743652343750, 0.0132751464843750, -0.0140991210937500, +0.0045471191406250, -0.0155639648437500, 0.0071105957031250, -0.0114440917968750, +0.0014038085937500, -0.0190734863281250, -0.0078125000000000, -0.0196228027343750, +-0.0019226074218750, -0.0064392089843750, -0.0165100097656250, -0.0096130371093750, +-0.0160217285156250, -0.0054321289062500, -0.0184020996093750, 0.0068054199218750, +-0.0283508300781250, 0.0005798339843750, -0.0245056152343750, -0.0000610351562500, +-0.0275878906250000, 0.0087280273437500, -0.0306701660156250, -0.0044250488281250, +-0.0289001464843750, -0.0196228027343750, -0.0269775390625000, -0.0095520019531250, +-0.0282592773437500, -0.0295715332031250, -0.0286560058593750, -0.0329589843750000, +-0.0289611816406250, -0.0282287597656250, -0.0264282226562500, -0.0350952148437500, +-0.0262145996093750, -0.0358581542968750, -0.0291748046875000, -0.0183715820312500, +-0.0197448730468750, -0.0206604003906250, -0.0211791992187500, -0.0204772949218750, +-0.0194396972656250, -0.0077209472656250, -0.0130615234375000, -0.0095214843750000, +-0.0163879394531250, -0.0204162597656250, -0.0114746093750000, -0.0144042968750000, +-0.0111694335937500, -0.0185241699218750, -0.0103454589843750, -0.0338134765625000, +-0.0057983398437500, -0.0303955078125000, -0.0072021484375000, -0.0252990722656250, +-0.0128173828125000, -0.0283508300781250, -0.0078125000000000, -0.0268554687500000, +-0.0109252929687500, -0.0218811035156250, -0.0193481445312500, -0.0236511230468750, +-0.0149230957031250, -0.0198059082031250, -0.0192260742187500, -0.0192260742187500, +-0.0210266113281250, -0.0200195312500000, -0.0181274414062500, -0.0179443359375000, +-0.0162353515625000, -0.0176696777343750, -0.0177307128906250, -0.0231933593750000, +-0.0208740234375000, -0.0206298828125000, -0.0159301757812500, -0.0231323242187500, +-0.0203552246093750, -0.0296630859375000, -0.0289611816406250, -0.0263061523437500, +-0.0250549316406250, -0.0278015136718750, -0.0313415527343750, -0.0306091308593750, +-0.0315856933593750, -0.0260925292968750, -0.0310363769531250, -0.0227661132812500, +-0.0363159179687500, -0.0260314941406250, -0.0354614257812500, -0.0159606933593750, +-0.0224609375000000, -0.0162353515625000, -0.0289611816406250, -0.0175170898437500, +-0.0187988281250000, -0.0116577148437500, -0.0009155273437500, -0.0127868652343750, +-0.0110168457031250, -0.0224914550781250, 0.0033569335937500, -0.0182189941406250, +0.0077819824218750, -0.0238342285156250, 0.0061950683593750, -0.0367126464843750, +0.0084533691406250, -0.0310363769531250, 0.0080261230468750, -0.0325317382812500, +0.0131835937500000, -0.0392150878906250, 0.0128784179687500, -0.0303344726562500, +0.0148620605468750, -0.0224914550781250, 0.0181884765625000, -0.0296936035156250, +0.0166015625000000, -0.0077209472656250, 0.0260009765625000, -0.0116577148437500, +0.0250854492187500, -0.0047607421875000, 0.0242614746093750, 0.0128479003906250, +0.0306396484375000, 0.0028076171875000, 0.0301208496093750, 0.0187072753906250, +0.0219421386718750, 0.0205078125000000, 0.0253601074218750, 0.0178222656250000, +0.0209960937500000, 0.0233154296875000, 0.0114135742187500, 0.0229187011718750, +0.0163269042968750, 0.0217590332031250, 0.0120544433593750, 0.0214538574218750, +0.0096130371093750, 0.0228271484375000, 0.0129394531250000, 0.0236511230468750, +0.0154113769531250, 0.0222778320312500, 0.0140686035156250, 0.0234069824218750, +0.0146789550781250, 0.0255432128906250, 0.0173950195312500, 0.0210266113281250, +0.0125427246093750, 0.0186462402343750, 0.0085449218750000, 0.0229187011718750, +0.0117187500000000, 0.0106201171875000, -0.0024719238281250, 0.0128784179687500, +-0.0005798339843750, 0.0107421875000000, -0.0052490234375000, 0.0022888183593750, +-0.0168762207031250, 0.0066528320312500, -0.0118408203125000, -0.0009765625000000, +-0.0205383300781250, 0.0000305175781250, -0.0223999023437500, -0.0024414062500000, +-0.0205688476562500, -0.0077819824218750, -0.0231323242187500, -0.0040588378906250, +-0.0228271484375000, -0.0144042968750000, -0.0171813964843750, -0.0120544433593750, +-0.0190429687500000, -0.0157165527343750, -0.0148315429687500, -0.0244140625000000, +-0.0084838867187500, -0.0191955566406250, -0.0112915039062500, -0.0294494628906250, +0.0004272460937500, -0.0305480957031250, -0.0007629394531250, -0.0285949707031250, +0.0034790039062500, -0.0329895019531250, 0.0128784179687500, -0.0322265625000000, +0.0087890625000000, -0.0232238769531250, 0.0186157226562500, -0.0271911621093750, +0.0189514160156250, -0.0186462402343750, 0.0200500488281250, -0.0067443847656250, +0.0252075195312500, -0.0131835937500000, 0.0227050781250000, 0.0075683593750000, +0.0275573730468750, 0.0061035156250000, 0.0268554687500000, 0.0101318359375000, +0.0280456542968750, 0.0244750976562500, 0.0311279296875000, 0.0180664062500000, +0.0286865234375000, 0.0252990722656250, 0.0338439941406250, 0.0277099609375000, +0.0319824218750000, 0.0239257812500000, 0.0342102050781250, 0.0239257812500000, +0.0385131835937500, 0.0253906250000000, 0.0346374511718750, 0.0194702148437500, +0.0433044433593750, 0.0190124511718750, 0.0421142578125000, 0.0192260742187500, +0.0428466796875000, 0.0170593261718750, 0.0489196777343750, 0.0169677734375000, +0.0467224121093750, 0.0150146484375000, 0.0484924316406250, 0.0171813964843750, +0.0507507324218750, 0.0126953125000000, 0.0483703613281250, 0.0083618164062500, +0.0469055175781250, 0.0121459960937500, 0.0488891601562500, -0.0021362304687500, +0.0422363281250000, -0.0000305175781250, 0.0440979003906250, -0.0044860839843750, +0.0417175292968750, -0.0154418945312500, 0.0363159179687500, -0.0100708007812500, +0.0395507812500000, -0.0222778320312500, 0.0312805175781250, -0.0206298828125000, +0.0339050292968750, -0.0230407714843750, 0.0294494628906250, -0.0314636230468750, +0.0220031738281250, -0.0263061523437500, 0.0277099609375000, -0.0333862304687500, +0.0119628906250000, -0.0346679687500000, 0.0143432617187500, -0.0295715332031250, +0.0108032226562500, -0.0286865234375000, -0.0006103515625000, -0.0301208496093750, +0.0052490234375000, -0.0227050781250000, -0.0050964355468750, -0.0212097167968750, +-0.0064392089843750, -0.0230407714843750, -0.0052490234375000, -0.0218505859375000, +-0.0097961425781250, -0.0205078125000000, -0.0092468261718750, -0.0220336914062500, +-0.0047912597656250, -0.0245971679687500, -0.0080871582031250, -0.0182495117187500, +-0.0022888183593750, -0.0144958496093750, 0.0050354003906250, -0.0191345214843750, +-0.0007629394531250, -0.0007629394531250, 0.0117492675781250, -0.0033264160156250, +0.0127258300781250, 0.0011291503906250, 0.0103759765625000, 0.0148010253906250, +0.0154418945312500, 0.0089416503906250, 0.0149841308593750, 0.0196533203125000, +0.0078430175781250, 0.0200195312500000, 0.0115661621093750, 0.0206298828125000, +0.0048522949218750, 0.0266723632812500, -0.0039062500000000, 0.0242004394531250, +0.0020751953125000, 0.0249633789062500, -0.0181579589843750, 0.0276489257812500, +-0.0153198242187500, 0.0223388671875000, -0.0211486816406250, 0.0184326171875000, +-0.0392456054687500, 0.0221252441406250, -0.0312194824218750, 0.0085449218750000, +-0.0304260253906250, 0.0111083984375000, -0.0377807617187500, 0.0059814453125000, +-0.0316162109375000, -0.0050048828125000, -0.0188903808593750, 0.0004882812500000, +-0.0236816406250000, -0.0155944824218750, -0.0325927734375000, -0.0142211914062500, +-0.0245056152343750, -0.0186462402343750, -0.0324401855468750, -0.0303955078125000, +-0.0481262207031250, -0.0247192382812500, -0.0411071777343750, -0.0355529785156250, +-0.0530700683593750, -0.0366516113281250, -0.0539245605468750, -0.0360412597656250, +-0.0531921386718750, -0.0409240722656250, -0.0617980957031250, -0.0398254394531250, +-0.0596923828125000, -0.0392150878906250, -0.0409851074218750, -0.0414733886718750, +-0.0500488281250000, -0.0382080078125000, -0.0392761230468750, -0.0359802246093750, +-0.0156250000000000, -0.0388183593750000, -0.0269165039062500, -0.0248413085937500, +-0.0150451660156250, -0.0304565429687500, -0.0099792480468750, -0.0195007324218750, +-0.0120544433593750, -0.0031738281250000, -0.0119323730468750, -0.0143737792968750, +-0.0126953125000000, 0.0138244628906250, -0.0090026855468750, 0.0147705078125000, +-0.0099182128906250, 0.0130615234375000, -0.0037841796875000, 0.0266723632812500, +-0.0016174316406250, 0.0238647460937500, -0.0069580078125000, 0.0196228027343750, +0.0248413085937500, 0.0223083496093750, 0.0215454101562500, 0.0185852050781250, +0.0226745605468750}, +{-0.0027160644531250, 0.0175476074218750, -0.0015869140625000, 0.0175476074218750, +0.0029602050781250, 0.0179443359375000, -0.0005187988281250, 0.0114135742187500, +0.0055236816406250, 0.0127258300781250, 0.0043945312500000, 0.0109558105468750, +0.0047607421875000, 0.0055236816406250, 0.0091247558593750, 0.0076293945312500, +0.0071716308593750, 0.0051269531250000, 0.0087280273437500, 0.0045776367187500, +0.0097045898437500, 0.0041809082031250, 0.0083923339843750, 0.0033264160156250, +0.0074768066406250, 0.0045471191406250, 0.0083618164062500, 0.0031433105468750, +0.0081787109375000, 0.0024414062500000, 0.0063781738281250, 0.0066223144531250, +0.0093383789062500, 0.0093078613281250, 0.0113220214843750, 0.0075683593750000, +0.0082092285156250, 0.0151672363281250, 0.0170898437500000, 0.0181884765625000, +0.0146789550781250, 0.0146789550781250, 0.0163879394531250, 0.0165100097656250, +0.0234680175781250, 0.0200195312500000, 0.0195007324218750, 0.0035705566406250, +0.0233459472656250, 0.0069885253906250, 0.0264587402343750, 0.0034790039062500, +0.0215454101562500, -0.0100402832031250, 0.0196533203125000, -0.0040588378906250, +0.0234069824218750, -0.0068664550781250, 0.0097045898437500, -0.0103454589843750, +0.0130004882812500, -0.0053405761718750, 0.0079956054687500, -0.0021362304687500, +-0.0043640136718750, -0.0050354003906250, 0.0023498535156250, 0.0063476562500000, +-0.0070495605468750, 0.0043029785156250, -0.0096435546875000, 0.0084533691406250, +-0.0065917968750000, 0.0183105468750000, -0.0082397460937500, 0.0132446289062500, +-0.0092163085937500, 0.0211486816406250, -0.0046081542968750, 0.0233154296875000, +-0.0059814453125000, 0.0197448730468750, -0.0047302246093750, 0.0211791992187500, +-0.0004577636718750, 0.0228271484375000, -0.0020446777343750, 0.0129394531250000, +0.0005493164062500, 0.0155639648437500, 0.0021972656250000, 0.0103149414062500, +-0.0011901855468750, 0.0011901855468750, -0.0009765625000000, 0.0063781738281250, +0.0012817382812500, -0.0083618164062500, -0.0163269042968750, -0.0064697265625000, +-0.0130004882812500, -0.0109558105468750, -0.0145874023437500, -0.0226745605468750, +-0.0281066894531250, -0.0172119140625000, -0.0251464843750000, -0.0281677246093750, +-0.0245056152343750, -0.0296020507812500, -0.0233154296875000, -0.0291748046875000, +-0.0292358398437500, -0.0338134765625000, -0.0324707031250000, -0.0328369140625000, +-0.0265808105468750, -0.0328979492187500, -0.0429687500000000, -0.0339660644531250, +-0.0437622070312500, -0.0322265625000000, -0.0435485839843750, -0.0318298339843750, +-0.0507507324218750, -0.0329895019531250, -0.0477600097656250, -0.0235595703125000, +-0.0479125976562500, -0.0285339355468750, -0.0529479980468750, -0.0183410644531250, +-0.0433349609375000, -0.0056457519531250, -0.0350646972656250, -0.0152282714843750, +-0.0425415039062500, 0.0133972167968750, -0.0199279785156250, 0.0118408203125000, +-0.0205688476562500, 0.0133666992187500, -0.0210876464843750, 0.0317687988281250, +-0.0090942382812500, 0.0263061523437500, -0.0108337402343750, 0.0222473144531250, +-0.0079650878906250, 0.0281066894531250, -0.0086669921875000, 0.0231323242187500, +-0.0093994140625000, 0.0129089355468750, -0.0064697265625000, 0.0175170898437500, +-0.0045166015625000, 0.0168151855468750, -0.0051269531250000, 0.0126037597656250, +-0.0107116699218750, 0.0186462402343750, -0.0007324218750000, 0.0245056152343750, +0.0088195800781250, 0.0198059082031250, 0.0014953613281250, 0.0309448242187500, +0.0239562988281250, 0.0332031250000000, 0.0217285156250000, 0.0294494628906250, +0.0235290527343750, 0.0308532714843750, 0.0467529296875000, 0.0330200195312500, +0.0018310546875000, 0.0334472656250000, 0.0314025878906250, 0.0432739257812500, +0.0219116210937500, 0.0253601074218750, 0.0247802734375000, 0.0132446289062500, +0.0407104492187500, 0.0264282226562500, 0.0384826660156250, -0.0187072753906250, +0.0265502929687500, -0.0140075683593750, 0.0310974121093750, -0.0188598632812500, +0.0281982421875000, -0.0501098632812500, 0.0169372558593750, -0.0391540527343750, +0.0203857421875000, -0.0406799316406250, 0.0178833007812500, -0.0473937988281250, +0.0183715820312500, -0.0435485839843750, 0.0149536132812500, -0.0334167480468750, +0.0123291015625000, -0.0364379882812500, 0.0158996582031250, -0.0565795898437500, +0.0019836425781250, -0.0445861816406250, 0.0041503906250000, -0.0572204589843750, +0.0015869140625000, -0.0859375000000000, -0.0097351074218750, -0.0722045898437500, +-0.0051269531250000, -0.0827941894531250, -0.0033569335937500, -0.0941772460937500, +-0.0075683593750000, -0.0744934082031250, -0.0032958984375000, -0.0647888183593750, +0.0046081542968750, -0.0789184570312500, 0.0011596679687500, -0.0241088867187500, +-0.0005187988281250, -0.0306396484375000, 0.0033874511718750, -0.0267639160156250, +-0.0007629394531250, 0.0129394531250000, -0.0081787109375000, 0.0017700195312500, +-0.0046997070312500, -0.0119018554687500, -0.0045471191406250, 0.0002441406250000, +-0.0078430175781250, -0.0087890625000000, -0.0057983398437500, -0.0304565429687500, +-0.0009765625000000, -0.0205078125000000, -0.0029296875000000, -0.0252685546875000, +-0.0073242187500000, -0.0345153808593750, -0.0048828125000000, -0.0200500488281250, +-0.0071716308593750, -0.0100402832031250, -0.0144653320312500, -0.0213317871093750, +-0.0124206542968750, 0.0144958496093750, -0.0062866210937500, 0.0117797851562500, +-0.0119323730468750, 0.0108337402343750, -0.0046386718750000, 0.0334472656250000, +0.0077209472656250, 0.0285949707031250, 0.0010681152343750, 0.0150756835937500, +0.0098876953125000, 0.0233459472656250, 0.0132751464843750, 0.0148620605468750, +0.0093078613281250, -0.0024719238281250, 0.0085144042968750, 0.0066223144531250, +0.0103454589843750, -0.0072326660156250, 0.0078430175781250, -0.0110778808593750, +0.0062561035156250, -0.0054016113281250, 0.0079956054687500, -0.0087585449218750, +0.0097045898437500, -0.0116577148437500, 0.0085449218750000, 0.0066528320312500, +0.0075988769531250, 0.0004577636718750, 0.0099182128906250, 0.0084533691406250, +0.0063781738281250, 0.0268859863281250, 0.0019531250000000, 0.0162353515625000, +0.0049133300781250, 0.0293884277343750, -0.0008239746093750, 0.0345764160156250, +-0.0015869140625000, 0.0275573730468750, -0.0006408691406250, 0.0271301269531250, +-0.0026245117187500, 0.0307006835937500, -0.0024414062500000, 0.0181274414062500, +-0.0003356933593750, 0.0208129882812500, -0.0022583007812500, 0.0169677734375000, +0.0003662109375000, 0.0077819824218750, 0.0037231445312500, 0.0139160156250000, +0.0005493164062500, 0.0018310546875000, 0.0071716308593750, 0.0033874511718750, +0.0070190429687500, 0.0013122558593750, 0.0061340332031250, -0.0067443847656250, +0.0090637207031250, -0.0018615722656250, 0.0081481933593750, -0.0090942382812500, +0.0068664550781250, -0.0092773437500000, 0.0068054199218750, -0.0080566406250000, +0.0065917968750000, -0.0111999511718750, 0.0055541992187500, -0.0101623535156250, +0.0052795410156250, -0.0075988769531250, 0.0067443847656250, -0.0093994140625000, +0.0054626464843750, -0.0070190429687500, 0.0074157714843750, -0.0036010742187500, +0.0092163085937500, -0.0061645507812500, 0.0071716308593750, -0.0004577636718750, +0.0163574218750000, -0.0014953613281250, 0.0142211914062500, -0.0005798339843750, +0.0177001953125000, 0.0031738281250000, 0.0264282226562500, 0.0003051757812500, +0.0229187011718750, 0.0025024414062500, 0.0294799804687500, 0.0025634765625000, +0.0305786132812500, 0.0005187988281250, 0.0307922363281250, 0.0002136230468750, +0.0333251953125000, -0.0003662109375000, 0.0325317382812500, -0.0045471191406250, +0.0359191894531250, -0.0039062500000000, 0.0357666015625000, -0.0065612792968750, +0.0359497070312500, -0.0105895996093750, 0.0386352539062500, -0.0091247558593750, +0.0380554199218750, -0.0158386230468750, 0.0350036621093750, -0.0156860351562500, +0.0379943847656250, -0.0190124511718750, 0.0335388183593750, -0.0245361328125000, +0.0275878906250000, -0.0227355957031250, 0.0319213867187500, -0.0327148437500000, +0.0216674804687500, -0.0317687988281250, 0.0209960937500000, -0.0350341796875000, +0.0214233398437500, -0.0429077148437500, 0.0166320800781250, -0.0396728515625000, +0.0168457031250000, -0.0458068847656250, 0.0160522460937500, -0.0468139648437500, +0.0172119140625000, -0.0456237792968750, 0.0133361816406250, -0.0477905273437500, +0.0104675292968750, -0.0475463867187500, 0.0133666992187500, -0.0435791015625000, +0.0011901855468750, -0.0456237792968750, 0.0006408691406250, -0.0409545898437500, +0.0028381347656250, -0.0354309082031250, -0.0037231445312500, -0.0386962890625000, +-0.0047302246093750, -0.0245056152343750, 0.0080261230468750, -0.0263671875000000, +0.0036926269531250, -0.0212097167968750, 0.0077209472656250, -0.0094604492187500, +0.0201110839843750, -0.0145568847656250, 0.0144348144531250, -0.0030212402343750, +0.0184326171875000, -0.0019836425781250, 0.0220031738281250, -0.0024108886718750, +0.0184326171875000, 0.0028686523437500, 0.0164184570312500, 0.0016479492187500, +0.0195312500000000, 0.0009155273437500, 0.0138854980468750, 0.0022277832031250, +0.0130004882812500, -0.0008544921875000, 0.0164489746093750, -0.0037231445312500, +0.0154724121093750, -0.0019531250000000, 0.0131530761718750, -0.0099792480468750, +0.0215454101562500, -0.0104675292968750, 0.0218505859375000, -0.0095520019531250, +0.0179138183593750, -0.0140991210937500, 0.0205078125000000, -0.0142517089843750, +0.0223388671875000, -0.0059204101562500, 0.0107421875000000, -0.0093078613281250, +0.0131835937500000, -0.0037841796875000, 0.0093078613281250, 0.0065612792968750, +0.0006713867187500, 0.0016174316406250, 0.0050354003906250, 0.0115661621093750, +-0.0094604492187500, 0.0137939453125000, -0.0066833496093750, 0.0106811523437500, +-0.0101318359375000, 0.0129699707031250, -0.0223999023437500, 0.0136413574218750, +-0.0170593261718750, 0.0051574707031250, -0.0207214355468750, 0.0066223144531250, +-0.0236816406250000, 0.0040588378906250, -0.0216369628906250, -0.0029907226562500, +-0.0202636718750000, -0.0002441406250000, -0.0216674804687500, -0.0044250488281250, +-0.0200195312500000, -0.0068359375000000, -0.0195922851562500, -0.0032653808593750, +-0.0211486816406250, -0.0011596679687500, -0.0217895507812500, -0.0043029785156250, +-0.0206604003906250, -0.0026855468750000, -0.0209960937500000, -0.0004882812500000, +-0.0246276855468750, -0.0019836425781250, -0.0178222656250000, -0.0037231445312500, +-0.0115051269531250, -0.0037536621093750, -0.0178222656250000, -0.0086669921875000, +-0.0057373046875000, -0.0063476562500000, -0.0027770996093750, -0.0080566406250000, +-0.0065917968750000, -0.0135192871093750, -0.0050048828125000, -0.0122985839843750, +-0.0034790039062500, -0.0180053710937500, -0.0071105957031250, -0.0160827636718750, +-0.0063476562500000, -0.0191955566406250, -0.0083618164062500, -0.0274353027343750, +-0.0113830566406250, -0.0243530273437500, -0.0089721679687500, -0.0216979980468750, +-0.0152893066406250, -0.0263977050781250, -0.0133666992187500, -0.0214538574218750, +-0.0158081054687500, -0.0100402832031250, -0.0242309570312500, -0.0113220214843750, +-0.0220031738281250, -0.0144958496093750, -0.0171813964843750, -0.0102539062500000, +-0.0192871093750000, -0.0130004882812500, -0.0206604003906250, -0.0183410644531250, +-0.0162963867187500, -0.0151062011718750, -0.0156250000000000, -0.0245361328125000, +-0.0254516601562500, -0.0237731933593750, -0.0221252441406250, -0.0212402343750000, +-0.0255126953125000, -0.0269775390625000, -0.0357360839843750, -0.0275573730468750, +-0.0313720703125000}, +{0.0484924316406250, -0.0103149414062500, 0.0442199707031250, -0.0172119140625000, +0.0425720214843750, -0.0156555175781250, 0.0465087890625000, -0.0180053710937500, +0.0414428710937500, -0.0236511230468750, 0.0339965820312500, -0.0204162597656250, +0.0374755859375000, -0.0284118652343750, 0.0331726074218750, -0.0278625488281250, +0.0298461914062500, -0.0300903320312500, 0.0324096679687500, -0.0360717773437500, +0.0346069335937500, -0.0335693359375000, 0.0317687988281250, -0.0390930175781250, +0.0315551757812500, -0.0399780273437500, 0.0349426269531250, -0.0391540527343750, +0.0293884277343750, -0.0413208007812500, 0.0240478515625000, -0.0412292480468750, +0.0289001464843750, -0.0372314453125000, 0.0170288085937500, -0.0392456054687500, +0.0176086425781250, -0.0350036621093750, 0.0182495117187500, -0.0294189453125000, +0.0114135742187500, -0.0324401855468750, 0.0133361816406250, -0.0205078125000000, +0.0179443359375000, -0.0220336914062500, 0.0147705078125000, -0.0170288085937500, +0.0166931152343750, -0.0070800781250000, 0.0234985351562500, -0.0124206542968750, +0.0205383300781250, -0.0008544921875000, 0.0158996582031250, 0.0009155273437500, +0.0208129882812500, -0.0022277832031250, 0.0144042968750000, 0.0014343261718750, +0.0050048828125000, 0.0022888183593750, 0.0104675292968750, -0.0066223144531250, +-0.0024108886718750, -0.0060424804687500, -0.0010681152343750, -0.0055236816406250, +-0.0054321289062500, -0.0114746093750000, -0.0157165527343750, -0.0111694335937500, +-0.0097351074218750, -0.0032348632812500, -0.0180358886718750, -0.0068054199218750, +-0.0213012695312500, -0.0027465820312500, -0.0171508789062500, 0.0066833496093750, +-0.0167541503906250, 0.0021667480468750, -0.0195617675781250, 0.0072326660156250, +-0.0150756835937500, 0.0101623535156250, -0.0142517089843750, 0.0061035156250000, +-0.0153503417968750, 0.0045471191406250, -0.0146484375000000, 0.0064086914062500, +-0.0148620605468750, -0.0033569335937500, -0.0156860351562500, -0.0020141601562500, +-0.0161743164062500, -0.0039672851562500, -0.0146484375000000, -0.0126037597656250, +-0.0150451660156250, -0.0097351074218750, -0.0164489746093750, -0.0044250488281250, +-0.0072326660156250, -0.0080261230468750, -0.0089416503906250, -0.0061035156250000, +-0.0090026855468750, 0.0009460449218750, -0.0021057128906250, -0.0011901855468750, +-0.0030517578125000, -0.0014648437500000, -0.0072021484375000, 0.0018310546875000, +-0.0059509277343750, -0.0052795410156250, -0.0060119628906250, -0.0118713378906250, +-0.0081481933593750, -0.0057067871093750, -0.0079345703125000, -0.0164489746093750, +-0.0128173828125000, -0.0192260742187500, -0.0107116699218750, -0.0185241699218750, +-0.0118408203125000, -0.0210876464843750, -0.0162353515625000, -0.0200195312500000, +-0.0144958496093750, -0.0213012695312500, -0.0197448730468750, -0.0228881835937500, +-0.0193481445312500, -0.0210571289062500, -0.0172119140625000, -0.0193481445312500, +-0.0172424316406250, -0.0199584960937500, -0.0170898437500000, -0.0148010253906250, +-0.0209655761718750, -0.0151062011718750, -0.0167541503906250, -0.0166931152343750, +-0.0200805664062500, -0.0150451660156250, -0.0271301269531250, -0.0144348144531250, +-0.0223999023437500, -0.0148620605468750, -0.0278930664062500, -0.0139465332031250, +-0.0306396484375000, -0.0182189941406250, -0.0256347656250000, -0.0213623046875000, +-0.0243530273437500, -0.0160522460937500, -0.0264892578125000, -0.0200195312500000, +-0.0128784179687500, -0.0258178710937500, -0.0177307128906250, -0.0169982910156250, +-0.0075988769531250, -0.0082092285156250, 0.0104675292968750, -0.0154113769531250, +0.0006408691406250, -0.0083618164062500, 0.0109558105468750, -0.0023803710937500, +0.0176391601562500, -0.0100708007812500, 0.0117797851562500, -0.0158386230468750, +0.0090637207031250, -0.0103759765625000, 0.0121154785156250, -0.0202636718750000, +0.0016479492187500, -0.0225524902343750, 0.0032348632812500, -0.0185241699218750, +0.0021362304687500, -0.0200805664062500, -0.0057983398437500, -0.0217895507812500, +-0.0024719238281250, -0.0133056640625000, 0.0002441406250000, -0.0143432617187500, +-0.0050964355468750, -0.0132446289062500, 0.0043640136718750, -0.0082092285156250, +0.0159606933593750, -0.0101928710937500, 0.0078430175781250, -0.0041809082031250, +0.0187988281250000, -0.0058898925781250, 0.0246582031250000, -0.0037536621093750, +0.0174865722656250, 0.0028076171875000, 0.0156860351562500, -0.0004882812500000, +0.0195922851562500, -0.0017395019531250, 0.0004272460937500, 0.0028076171875000, +0.0043029785156250, -0.0039672851562500, -0.0013427734375000, -0.0119628906250000, +-0.0184020996093750, -0.0061645507812500, -0.0111389160156250, -0.0170593261718750, +-0.0166625976562500, -0.0193786621093750, -0.0220947265625000, -0.0153503417968750, +-0.0140075683593750, -0.0182495117187500, -0.0087280273437500, -0.0198974609375000, +-0.0140991210937500, -0.0073547363281250, 0.0005187988281250, -0.0124206542968750, +0.0024414062500000, -0.0051879882812500, -0.0007019042968750, 0.0080566406250000, +0.0046691894531250, -0.0005798339843750, 0.0049438476562500, 0.0162658691406250, +-0.0076293945312500, 0.0159606933593750, -0.0038757324218750, 0.0161132812500000, +-0.0123901367187500, 0.0249633789062500, -0.0265808105468750, 0.0214538574218750, +-0.0197753906250000, 0.0246582031250000, -0.0370178222656250, 0.0251464843750000, +-0.0387878417968750, 0.0252380371093750, -0.0381469726562500, 0.0265197753906250, +-0.0458984375000000, 0.0256652832031250, -0.0443725585937500, 0.0287475585937500, +-0.0422668457031250, 0.0278625488281250, -0.0441284179687500, 0.0306091308593750, +-0.0414123535156250, 0.0342407226562500, -0.0375976562500000, 0.0328979492187500, +-0.0393371582031250, 0.0419616699218750, -0.0330505371093750, 0.0412597656250000, +-0.0332946777343750, 0.0440368652343750, -0.0314941406250000, 0.0515747070312500, +-0.0268249511718750, 0.0489501953125000, -0.0285644531250000, 0.0517272949218750, +-0.0245361328125000, 0.0546264648437500, -0.0241088867187500, 0.0514221191406250, +-0.0239868164062500, 0.0495605468750000, -0.0222778320312500, 0.0519409179687500, +-0.0227661132812500, 0.0431213378906250, -0.0215454101562500, 0.0456542968750000, +-0.0221862792968750, 0.0402832031250000, -0.0213928222656250, 0.0317382812500000, +-0.0200195312500000, 0.0369567871093750, -0.0210876464843750, 0.0200500488281250, +-0.0183410644531250, 0.0226745605468750, -0.0186462402343750, 0.0166015625000000, +-0.0178222656250000, 0.0026855468750000, -0.0157165527343750, 0.0096740722656250, +-0.0166931152343750, -0.0059509277343750, -0.0141601562500000, -0.0068664550781250, +-0.0145874023437500, -0.0087585449218750, -0.0142211914062500, -0.0176086425781250, +-0.0121459960937500, -0.0145874023437500, -0.0130310058593750, -0.0199279785156250, +-0.0129089355468750, -0.0214538574218750, -0.0121765136718750, -0.0202331542968750, +-0.0131835937500000, -0.0219726562500000, -0.0143432617187500, -0.0224304199218750, +-0.0137939453125000, -0.0174560546875000, -0.0152587890625000, -0.0210876464843750, +-0.0162048339843750, -0.0149230957031250, -0.0161437988281250, -0.0081481933593750, +-0.0168762207031250, -0.0140991210937500, -0.0178527832031250, 0.0081787109375000, +-0.0161132812500000, 0.0031433105468750, -0.0182800292968750, 0.0123901367187500, +-0.0160827636718750, 0.0328979492187500, -0.0137023925781250, 0.0225524902343750, +-0.0172119140625000, 0.0430603027343750, -0.0077209472656250, 0.0447998046875000, +-0.0103759765625000, 0.0444335937500000, -0.0081787109375000, 0.0531005859375000, +-0.0002136230468750, 0.0505065917968750, -0.0047912597656250, 0.0558166503906250, +-0.0004272460937500, 0.0553283691406250, 0.0015869140625000, 0.0577392578125000, +-0.0021667480468750, 0.0626525878906250, -0.0025024414062500, 0.0599975585937500, +-0.0000915527343750, 0.0642395019531250, -0.0101013183593750, 0.0656433105468750, +-0.0077819824218750, 0.0635681152343750, -0.0109252929687500, 0.0645751953125000, +-0.0198364257812500, 0.0657653808593750, -0.0159912109375000, 0.0581665039062500, +-0.0213317871093750, 0.0621643066406250, -0.0227050781250000, 0.0540466308593750, +-0.0208740234375000, 0.0442810058593750, -0.0228576660156250, 0.0515747070312500, +-0.0233764648437500, 0.0261535644531250, -0.0147094726562500, 0.0302429199218750, +-0.0198669433593750, 0.0221252441406250, -0.0099487304687500, 0.0020446777343750, +0.0020751953125000, 0.0121154785156250, -0.0073547363281250, -0.0087890625000000, +0.0215148925781250, -0.0084533691406250, 0.0187377929687500, -0.0119934082031250, +0.0226440429687500, -0.0251464843750000, 0.0443725585937500, -0.0191345214843750, +0.0370483398437500, -0.0292053222656250, 0.0352478027343750, -0.0312500000000000, +0.0450744628906250, -0.0292968750000000, 0.0275573730468750, -0.0325012207031250, +0.0110168457031250, -0.0328369140625000, 0.0243835449218750, -0.0285644531250000, +-0.0155639648437500, -0.0297546386718750, -0.0162048339843750, -0.0283508300781250, +-0.0146789550781250, -0.0253295898437500, -0.0352172851562500, -0.0268859863281250, +-0.0308227539062500, -0.0200500488281250, -0.0228271484375000, -0.0232849121093750, +-0.0285034179687500, -0.0160827636718750, -0.0206298828125000, -0.0072631835937500, +-0.0087280273437500, -0.0140380859375000, -0.0158386230468750, 0.0068664550781250, +0.0003356933593750, 0.0052490234375000, 0.0047302246093750, 0.0084838867187500, +-0.0069885253906250, 0.0225830078125000, -0.0050048828125000, 0.0169372558593750, +0.0023498535156250, 0.0229797363281250, -0.0368652343750000, 0.0263671875000000, +-0.0310668945312500, 0.0220642089843750, -0.0382080078125000, 0.0205993652343750, +-0.0693969726562500, 0.0237121582031250, -0.0573730468750000, 0.0179138183593750, +-0.0542297363281250, 0.0158081054687500, -0.0668334960937500, 0.0204467773437500, +-0.0513000488281250, 0.0214233398437500, -0.0334167480468750, 0.0182800292968750, +-0.0454711914062500, 0.0277404785156250, -0.0095214843750000, 0.0284423828125000, +-0.0079956054687500, 0.0276489257812500, -0.0141296386718750, 0.0307922363281250, +0.0003051757812500, 0.0303039550781250, 0.0010375976562500, 0.0330810546875000, +-0.0089416503906250, 0.0320434570312500, -0.0097961425781250, 0.0332031250000000, +-0.0064697265625000, 0.0367126464843750, -0.0101013183593750, 0.0350341796875000, +-0.0115356445312500, 0.0349731445312500, 0.0051574707031250, 0.0388183593750000, +0.0029907226562500, 0.0298767089843750, -0.0001831054687500, 0.0140991210937500, +0.0107727050781250, -0.0285034179687500, -0.0048217773437500, -0.0267639160156250, +0.0088500976562500, -0.0343627929687500, 0.0094604492187500, -0.0292663574218750, +0.0067443847656250, -0.0196533203125000, 0.0071716308593750, -0.0231323242187500, +0.0092773437500000, -0.0232238769531250, 0.0061340332031250, -0.0187988281250000, +0.0020141601562500, -0.0251770019531250, 0.0113220214843750, -0.0310668945312500, +0.0176696777343750, -0.0255126953125000, 0.0103454589843750, -0.0411071777343750, +0.0297851562500000, -0.0401000976562500, 0.0314636230468750, -0.0399169921875000, +0.0277709960937500, -0.0487670898437500, 0.0353088378906250, -0.0469360351562500, +0.0353698730468750, -0.0485534667968750, 0.0232543945312500, -0.0466918945312500, +0.0256958007812500, -0.0489501953125000, 0.0250244140625000, -0.0548706054687500, +0.0158691406250000, -0.0512695312500000, 0.0177001953125000, -0.0430908203125000, +0.0226135253906250, -0.0502624511718750, 0.0222167968750000, -0.0394592285156250, +0.0181274414062500, -0.0251159667968750, 0.0202026367187500, -0.0346069335937500, +0.0230407714843750, -0.0085754394531250, 0.0047302246093750, -0.0129699707031250, +0.0066833496093750}, +{-0.0094604492187500, 0.0354919433593750, -0.0057983398437500, 0.0268554687500000, +-0.0106506347656250, 0.0087280273437500, -0.0195312500000000, 0.0186767578125000, +-0.0145263671875000, -0.0064086914062500, -0.0187072753906250, -0.0052490234375000, +-0.0249633789062500, -0.0087280273437500, -0.0125427246093750, -0.0250854492187500, +-0.0052795410156250, -0.0189208984375000, -0.0145568847656250, -0.0270996093750000, +0.0202941894531250, -0.0296020507812500, 0.0177917480468750, -0.0278625488281250, +0.0228271484375000, -0.0300292968750000, 0.0479431152343750, -0.0298767089843750, +0.0387268066406250, -0.0249328613281250, 0.0351257324218750, -0.0285949707031250, +0.0480346679687500, -0.0219726562500000, 0.0286254882812500, -0.0144348144531250, +0.0067443847656250, -0.0205993652343750, 0.0218811035156250, -0.0003051757812500, +-0.0163269042968750, -0.0022583007812500, -0.0185852050781250, 0.0008239746093750, +-0.0170288085937500, 0.0147705078125000, -0.0348510742187500, 0.0092468261718750, +-0.0301818847656250, 0.0152587890625000, -0.0256652832031250, 0.0168457031250000, +-0.0330200195312500, 0.0162658691406250, -0.0208129882812500, 0.0179443359375000, +-0.0051269531250000, 0.0173339843750000, -0.0162963867187500, 0.0184631347656250, +-0.0031127929687500, 0.0185241699218750, 0.0075988769531250, 0.0196228027343750, +-0.0100708007812500, 0.0202941894531250, -0.0199890136718750, 0.0196228027343750, +-0.0072937011718750, 0.0250244140625000, -0.0468750000000000, 0.0240478515625000, +-0.0476379394531250, 0.0247497558593750, -0.0438842773437500, 0.0288696289062500, +-0.0628356933593750, 0.0277404785156250, -0.0597229003906250, 0.0283813476562500, +-0.0461730957031250, 0.0280151367187500, -0.0570983886718750, 0.0300903320312500, +-0.0377807617187500, 0.0328063964843750, -0.0108642578125000, 0.0302124023437500, +-0.0287780761718750, 0.0284118652343750, -0.0012817382812500, 0.0339965820312500, +0.0064086914062500, 0.0230407714843750, -0.0025634765625000, 0.0137329101562500, +0.0006713867187500, 0.0219116210937500, 0.0044860839843750, -0.0112304687500000, +-0.0065612792968750, -0.0074157714843750, -0.0101623535156250, -0.0094909667968750, +-0.0024719238281250, -0.0426940917968750, 0.0040283203125000, -0.0264587402343750, +0.0040893554687500, -0.0204467773437500, 0.0005798339843750, -0.0151672363281250, +-0.0001220703125000, -0.0193176269531250, 0.0021362304687500, -0.0248107910156250, +0.0022888183593750, -0.0224914550781250, 0.0000000000000000, -0.0257873535156250, +0.0073547363281250, -0.0243530273437500, 0.0089721679687500, -0.0292663574218750, +0.0051269531250000, -0.0328063964843750, 0.0043945312500000, -0.0279541015625000, +0.0069885253906250, -0.0489196777343750, 0.0054321289062500, -0.0446777343750000, +0.0015563964843750, -0.0505676269531250, 0.0086364746093750, -0.0684204101562500, +0.0143737792968750, -0.0591735839843750, 0.0088500976562500, -0.0659790039062500, +0.0251770019531250, -0.0766601562500000, 0.0268554687500000, -0.0557556152343750, +0.0224304199218750, -0.0416564941406250, 0.0277099609375000, -0.0577697753906250, +0.0294799804687500, -0.0106811523437500, 0.0185852050781250, -0.0136108398437500, +0.0183715820312500, -0.0087585449218750, 0.0212707519531250, 0.0205688476562500, +0.0180358886718750, 0.0090637207031250, 0.0166931152343750, 0.0187988281250000, +0.0203247070312500, 0.0254211425781250, 0.0236511230468750, 0.0154418945312500, +0.0157775878906250, 0.0094299316406250, 0.0111083984375000, 0.0169677734375000, +0.0172424316406250, 0.0099792480468750, -0.0009765625000000, 0.0022583007812500, +-0.0020446777343750, 0.0124511718750000, 0.0001831054687500, 0.0204772949218750, +-0.0072326660156250, 0.0134582519531250, -0.0069274902343750, 0.0334167480468750, +-0.0029296875000000, 0.0317077636718750, -0.0026550292968750, 0.0335693359375000, +-0.0046386718750000, 0.0473632812500000, -0.0037536621093750, 0.0417480468750000, +-0.0022888183593750, 0.0385437011718750, -0.0086669921875000, 0.0457153320312500, +-0.0089416503906250, 0.0361022949218750, -0.0074157714843750, 0.0230407714843750, +-0.0101013183593750, 0.0321044921875000, -0.0107421875000000, 0.0221862792968750, +-0.0053710937500000, 0.0174255371093750, -0.0062561035156250, 0.0209350585937500, +-0.0058898925781250, 0.0226440429687500, -0.0030822753906250, 0.0210571289062500, +-0.0042114257812500, 0.0181884765625000, -0.0002136230468750, 0.0215148925781250, +-0.0042114257812500, 0.0165100097656250, 0.0040893554687500, 0.0102844238281250, +0.0121765136718750, 0.0146179199218750, 0.0046081542968750, 0.0024108886718750, +0.0304260253906250, 0.0044860839843750, 0.0274047851562500, -0.0007934570312500, +0.0318603515625000, -0.0099487304687500, 0.0497741699218750, -0.0034179687500000, +0.0423278808593750, -0.0229492187500000, 0.0534057617187500, -0.0213317871093750, +0.0538330078125000, -0.0223388671875000, 0.0552673339843750, -0.0347900390625000, +0.0614929199218750, -0.0304870605468750, 0.0580139160156250, -0.0300292968750000, +0.0636291503906250, -0.0340881347656250, 0.0651855468750000, -0.0287475585937500, +0.0621337890625000, -0.0239562988281250, 0.0629577636718750, -0.0287170410156250, +0.0643920898437500, -0.0149536132812500, 0.0550231933593750, -0.0184631347656250, +0.0578918457031250, -0.0134277343750000, 0.0528564453125000, -0.0023498535156250, +0.0445251464843750, -0.0101318359375000, 0.0498657226562500, 0.0054626464843750, +0.0337524414062500, 0.0036010742187500, 0.0368957519531250, 0.0057983398437500, +0.0306701660156250, 0.0158386230468750, 0.0176086425781250, 0.0101013183593750, +0.0252990722656250, 0.0183105468750000, 0.0060424804687500, 0.0188293457031250, +0.0086975097656250, 0.0179443359375000, 0.0021362304687500, 0.0213623046875000, +-0.0122680664062500, 0.0204467773437500, -0.0040283203125000, 0.0213928222656250, +-0.0259704589843750, 0.0215148925781250, -0.0235290527343750, 0.0227355957031250, +-0.0293579101562500, 0.0242309570312500, -0.0456237792968750, 0.0239562988281250, +-0.0375976562500000, 0.0271911621093750, -0.0527648925781250, 0.0280151367187500, +-0.0541076660156250, 0.0281982421875000, -0.0522766113281250, 0.0296325683593750, +-0.0593566894531250, 0.0303649902343750, -0.0579223632812500, 0.0306396484375000, +-0.0498657226562500, 0.0308837890625000, -0.0551452636718750, 0.0322570800781250, +-0.0456237792968750, 0.0332946777343750, -0.0333862304687500, 0.0332336425781250, +-0.0412902832031250, 0.0359497070312500, -0.0169067382812500, 0.0368652343750000, +-0.0185852050781250, 0.0369567871093750, -0.0133972167968750, 0.0380859375000000, +0.0032958984375000, 0.0384521484375000, -0.0033569335937500, 0.0369567871093750, +0.0106506347656250, 0.0378723144531250, 0.0087890625000000, 0.0359191894531250, +0.0159301757812500, 0.0336914062500000, 0.0267639160156250, 0.0348815917968750, +0.0187377929687500, 0.0280151367187500, 0.0450439453125000, 0.0293579101562500, +0.0417785644531250, 0.0252075195312500, 0.0459594726562500, 0.0187988281250000, +0.0652160644531250, 0.0218200683593750, 0.0576477050781250, 0.0087585449218750, +0.0630493164062500, 0.0105285644531250, 0.0676269531250000, 0.0057678222656250, +0.0629272460937500, -0.0049133300781250, 0.0607604980468750, -0.0003356933593750, +0.0640869140625000, -0.0121765136718750, 0.0547180175781250, -0.0124511718750000, +0.0566711425781250, -0.0140991210937500, 0.0535583496093750, -0.0214233398437500, +0.0458068847656250, -0.0191650390625000, 0.0493774414062500, -0.0230712890625000, +0.0393981933593750, -0.0242004394531250, 0.0412902832031250, -0.0237426757812500, +0.0340881347656250, -0.0251464843750000, 0.0249633789062500, -0.0252990722656250, +0.0317687988281250, -0.0237731933593750, 0.0088500976562500, -0.0242614746093750, +0.0112915039062500, -0.0236511230468750, 0.0077209472656250, -0.0216064453125000, +-0.0077514648437500, -0.0221252441406250, -0.0015869140625000, -0.0233154296875000, +-0.0112915039062500, -0.0220947265625000, -0.0118713378906250, -0.0231018066406250, +-0.0124206542968750, -0.0259399414062500, -0.0183715820312500, -0.0249938964843750, +-0.0160522460937500, -0.0238037109375000, -0.0146179199218750, -0.0265197753906250, +-0.0176696777343750, -0.0217590332031250, -0.0146789550781250, -0.0170898437500000, +-0.0098266601562500, -0.0207214355468750, -0.0126953125000000, -0.0071716308593750, +-0.0094299316406250, -0.0090637207031250, -0.0093383789062500, -0.0046386718750000, +-0.0084533691406250, 0.0061340332031250, -0.0067749023437500, 0.0006713867187500, +-0.0089721679687500, 0.0101318359375000, -0.0057983398437500, 0.0120544433593750, +-0.0052490234375000, 0.0093688964843750, -0.0061340332031250, 0.0119018554687500, +-0.0059509277343750, 0.0122070312500000, -0.0057983398437500, 0.0048217773437500, +-0.0033264160156250, 0.0064697265625000, -0.0044555664062500, 0.0043029785156250, +-0.0034790039062500, -0.0020141601562500, -0.0004577636718750, 0.0000305175781250, +-0.0016479492187500, -0.0048217773437500, -0.0016479492187500, -0.0037536621093750, +0.0000000000000000, -0.0056762695312500, -0.0031433105468750, -0.0114746093750000, +-0.0050964355468750, -0.0092468261718750, -0.0026855468750000, -0.0074768066406250, +-0.0142211914062500, -0.0101013183593750, -0.0125122070312500, -0.0064697265625000, +-0.0112915039062500, -0.0020446777343750, -0.0183410644531250, -0.0055236816406250, +-0.0181884765625000, 0.0021972656250000, -0.0147705078125000, 0.0049133300781250, +-0.0129089355468750, 0.0001831054687500, -0.0152587890625000, -0.0000305175781250, +-0.0170898437500000, 0.0027465820312500, -0.0152587890625000, -0.0089416503906250, +-0.0178222656250000, -0.0061950683593750, -0.0166931152343750, -0.0091857910156250, +-0.0192871093750000, -0.0228881835937500, -0.0247192382812500, -0.0206604003906250, +-0.0234985351562500, -0.0112915039062500, -0.0239257812500000, -0.0183410644531250, +-0.0253601074218750, -0.0119018554687500, -0.0226745605468750, 0.0010070800781250, +-0.0213012695312500, -0.0078735351562500, -0.0235900878906250, 0.0021667480468750, +-0.0148010253906250, 0.0083312988281250, -0.0169677734375000, 0.0018310546875000, +-0.0123291015625000, -0.0023803710937500, -0.0028076171875000, 0.0016479492187500, +-0.0085144042968750, -0.0026855468750000, -0.0053405761718750, -0.0040283203125000, +-0.0010375976562500, -0.0041503906250000, -0.0035400390625000, -0.0058593750000000, +-0.0072326660156250, -0.0044860839843750, -0.0064392089843750, -0.0021362304687500, +-0.0081787109375000, -0.0048217773437500, -0.0077819824218750, -0.0012207031250000, +-0.0066223144531250, 0.0049133300781250, -0.0089416503906250, 0.0016479492187500, +-0.0095825195312500, 0.0032958984375000, 0.0007934570312500, 0.0062561035156250, +-0.0009765625000000, 0.0035705566406250, -0.0010375976562500, 0.0014343261718750, +0.0070190429687500, 0.0034484863281250, 0.0054016113281250, -0.0050964355468750, +-0.0042419433593750, -0.0025329589843750, 0.0001831054687500, -0.0060119628906250, +-0.0023803710937500, -0.0151977539062500, -0.0130920410156250, -0.0107727050781250, +-0.0098876953125000, -0.0130004882812500, -0.0094604492187500, -0.0169372558593750, +-0.0115966796875000, -0.0117187500000000, -0.0085144042968750, -0.0073242187500000, +-0.0057983398437500, -0.0113220214843750, -0.0086364746093750, -0.0014953613281250, +-0.0020751953125000, -0.0022583007812500, -0.0004272460937500, -0.0011291503906250, +-0.0052795410156250, 0.0051574707031250, -0.0052185058593750, 0.0023498535156250, +-0.0029602050781250, 0.0047912597656250, -0.0166931152343750, 0.0065612792968750, +-0.0147094726562500, 0.0031433105468750, -0.0194091796875000, 0.0018920898437500, +-0.0309753417968750}, +{-0.0113220214843750, -0.0250549316406250, -0.0107727050781250, -0.0249938964843750, +-0.0116882324218750, -0.0234680175781250, -0.0079650878906250, -0.0254516601562500, +-0.0090332031250000, -0.0220031738281250, -0.0090637207031250, -0.0190734863281250, +-0.0061645507812500, -0.0218811035156250, -0.0065917968750000, -0.0075683593750000, +-0.0063781738281250, -0.0115661621093750, -0.0072326660156250, -0.0050048828125000, +-0.0040283203125000, 0.0092163085937500, -0.0013732910156250, 0.0019836425781250, +-0.0040588378906250, 0.0145874023437500, 0.0023193359375000, 0.0173950195312500, +0.0035705566406250, 0.0122680664062500, 0.0013122558593750, 0.0142517089843750, +0.0031433105468750, 0.0163574218750000, 0.0040588378906250, 0.0062866210937500, +-0.0041198730468750, 0.0066528320312500, -0.0013122558593750, 0.0039978027343750, +-0.0046997070312500, -0.0025329589843750, -0.0132446289062500, 0.0009155273437500, +-0.0083618164062500, -0.0045776367187500, -0.0113830566406250, -0.0066528320312500, +-0.0143432617187500, -0.0039367675781250, -0.0120239257812500, -0.0034790039062500, +-0.0079650878906250, -0.0045471191406250, -0.0086669921875000, 0.0003051757812500, +-0.0160217285156250, 0.0000610351562500, -0.0132446289062500, -0.0004577636718750, +-0.0140075683593750, 0.0027465820312500, -0.0194091796875000, 0.0032653808593750, +-0.0179748535156250, -0.0000305175781250, -0.0247497558593750, 0.0013732910156250, +-0.0233154296875000, -0.0022888183593750, -0.0228271484375000, -0.0078125000000000, +-0.0286560058593750, -0.0074768066406250, -0.0278320312500000, -0.0191955566406250, +-0.0199584960937500, -0.0186767578125000, -0.0242309570312500, -0.0141601562500000, +-0.0214233398437500, -0.0198364257812500, -0.0133972167968750, -0.0213928222656250, +-0.0173645019531250, -0.0019836425781250, -0.0084838867187500, -0.0074462890625000, +-0.0078430175781250, -0.0044555664062500, -0.0093383789062500, 0.0126953125000000, +-0.0057373046875000, 0.0073547363281250, -0.0051269531250000, 0.0049743652343750, +-0.0064392089843750, 0.0096435546875000, -0.0072937011718750, 0.0045166015625000, +-0.0071105957031250, -0.0025634765625000, -0.0057373046875000, 0.0021972656250000, +-0.0049133300781250, -0.0054931640625000, -0.0081787109375000, -0.0086059570312500, +-0.0093994140625000, -0.0017395019531250, -0.0062561035156250, 0.0002441406250000, +-0.0044555664062500, -0.0046691894531250, -0.0067138671875000, 0.0068054199218750, +-0.0046691894531250, 0.0090026855468750, -0.0033874511718750, 0.0050659179687500, +-0.0042114257812500, 0.0069885253906250, -0.0057983398437500, 0.0091247558593750, +-0.0052490234375000, 0.0038452148437500, 0.0001525878906250, 0.0043334960937500, +-0.0025634765625000, 0.0023193359375000, -0.0018615722656250, -0.0005493164062500, +0.0048828125000000, 0.0018615722656250, 0.0034790039062500, -0.0091552734375000, +-0.0028991699218750, -0.0074462890625000, -0.0001525878906250, -0.0083312988281250, +-0.0044250488281250, -0.0168151855468750, -0.0113220214843750, -0.0143127441406250, +-0.0077209472656250, -0.0115356445312500, -0.0201110839843750, -0.0149841308593750, +-0.0197448730468750, -0.0111083984375000, -0.0210266113281250, -0.0051879882812500, +-0.0285644531250000, -0.0090026855468750, -0.0263366699218750, -0.0023498535156250, +-0.0297851562500000, -0.0019226074218750, -0.0303039550781250, -0.0030517578125000, +-0.0303649902343750, -0.0005798339843750, -0.0318603515625000, -0.0011596679687500, +-0.0312194824218750, -0.0023498535156250, -0.0330810546875000, -0.0020751953125000, +-0.0335388183593750, -0.0018920898437500, -0.0325927734375000, -0.0025939941406250, +-0.0332641601562500, -0.0024414062500000, -0.0339050292968750, -0.0008850097656250, +-0.0292358398437500, -0.0010681152343750, -0.0302429199218750, 0.0006713867187500, +-0.0275268554687500, 0.0021667480468750, -0.0230407714843750, 0.0014343261718750, +-0.0251159667968750, 0.0083618164062500, -0.0171203613281250, 0.0049133300781250, +-0.0176086425781250, 0.0115356445312500, -0.0151672363281250, 0.0199279785156250, +-0.0086669921875000, 0.0129089355468750, -0.0108642578125000, 0.0318298339843750, +-0.0075988769531250, 0.0296020507812500, -0.0056152343750000, 0.0316467285156250, +-0.0070190429687500, 0.0442504882812500, -0.0069885253906250, 0.0382690429687500, +-0.0057983398437500, 0.0418395996093750, -0.0099792480468750, 0.0446472167968750, +-0.0087585449218750, 0.0390319824218750, -0.0101013183593750, 0.0362243652343750, +-0.0135498046875000, 0.0381164550781250, -0.0115051269531250, 0.0234985351562500, +-0.0162353515625000, 0.0263977050781250, -0.0159301757812500, 0.0184936523437500, +-0.0162048339843750, 0.0046997070312500, -0.0190734863281250, 0.0117492675781250, +-0.0181274414062500, -0.0072326660156250, -0.0186767578125000, -0.0072937011718750, +-0.0187683105468750, -0.0099487304687500, -0.0184020996093750, -0.0208740234375000, +-0.0180053710937500, -0.0167236328125000, -0.0173339843750000, -0.0269775390625000, +-0.0181274414062500, -0.0259094238281250, -0.0166931152343750, -0.0293884277343750, +-0.0169067382812500, -0.0376586914062500, -0.0181274414062500, -0.0332336425781250, +-0.0168457031250000, -0.0408020019531250, -0.0181884765625000, -0.0423278808593750, +-0.0168762207031250, -0.0387878417968750, -0.0174560546875000, -0.0400085449218750, +-0.0188293457031250, -0.0410461425781250, -0.0171203613281250, -0.0317077636718750, +-0.0203857421875000, -0.0331420898437500, -0.0195007324218750, -0.0313720703125000, +-0.0201721191406250, -0.0242919921875000, -0.0226440429687500, -0.0266723632812500, +-0.0213012695312500, -0.0249633789062500, -0.0243225097656250, -0.0238037109375000, +-0.0233764648437500, -0.0240783691406250, -0.0243530273437500, -0.0252380371093750, +-0.0265197753906250, -0.0251770019531250, -0.0244445800781250, -0.0193481445312500, +-0.0289611816406250, -0.0227050781250000, -0.0275878906250000, -0.0167236328125000, +-0.0292358398437500, -0.0086364746093750, -0.0327758789062500, -0.0141601562500000, +-0.0297241210937500, 0.0014343261718750, -0.0358276367187500, -0.0005187988281250, +-0.0358276367187500, 0.0030822753906250, -0.0341491699218750, 0.0140380859375000, +-0.0372314453125000, 0.0081787109375000, -0.0371704101562500, 0.0180358886718750, +-0.0299072265625000, 0.0182189941406250, -0.0334777832031250, 0.0166931152343750, +-0.0288391113281250, 0.0201110839843750, -0.0205688476562500, 0.0185546875000000, +-0.0260620117187500, 0.0199584960937500, -0.0156250000000000, 0.0190734863281250, +-0.0150756835937500, 0.0203552246093750, -0.0153198242187500, 0.0225219726562500, +-0.0104064941406250, 0.0205078125000000, -0.0117187500000000, 0.0228271484375000, +-0.0098571777343750, 0.0235290527343750, -0.0093078613281250, 0.0225524902343750, +-0.0108947753906250, 0.0226135253906250, -0.0103149414062500, 0.0229187011718750, +-0.0091552734375000, 0.0215759277343750, -0.0155944824218750, 0.0214843750000000, +-0.0144958496093750, 0.0209045410156250, -0.0146789550781250, 0.0199890136718750, +-0.0193786621093750, 0.0201110839843750, -0.0180358886718750, 0.0172729492187500, +-0.0153198242187500, 0.0177917480468750, -0.0177001953125000, 0.0170593261718750, +-0.0146484375000000, 0.0142822265625000, -0.0094299316406250, 0.0148925781250000, +-0.0119628906250000, 0.0157165527343750, -0.0084838867187500, 0.0149841308593750, +-0.0087280273437500, 0.0145568847656250, -0.0043640136718750, 0.0162048339843750, +-0.0014648437500000, 0.0160522460937500, -0.0054016113281250, 0.0094909667968750, +0.0121459960937500, 0.0122375488281250, 0.0093383789062500, 0.0091552734375000, +0.0136413574218750, 0.0012817382812500, 0.0278930664062500, 0.0048828125000000, +0.0216064453125000, 0.0029907226562500, 0.0258178710937500, 0.0003356933593750, +0.0311889648437500, 0.0032043457031250, 0.0234069824218750, 0.0063781738281250, +0.0175170898437500, 0.0046691894531250, 0.0229797363281250, 0.0061035156250000, +0.0090026855468750, 0.0071411132812500, 0.0085144042968750, 0.0070800781250000, +0.0061340332031250, 0.0061035156250000, -0.0002746582031250, 0.0060119628906250, +0.0033874511718750, 0.0111999511718750, -0.0114440917968750, 0.0097961425781250, +-0.0108642578125000, 0.0109252929687500, -0.0111694335937500, 0.0162048339843750, +-0.0191955566406250, 0.0145263671875000, -0.0172729492187500, 0.0114440917968750, +-0.0199890136718750, 0.0148620605468750, -0.0177612304687500, 0.0088806152343750, +-0.0256347656250000, 0.0029907226562500, -0.0326538085937500, 0.0078430175781250, +-0.0244750976562500, -0.0124511718750000, -0.0411376953125000, -0.0084228515625000, +-0.0458068847656250, -0.0141601562500000, -0.0404663085937500, -0.0318603515625000, +-0.0404968261718750, -0.0240783691406250, -0.0418395996093750, -0.0303344726562500, +-0.0407409667968750, -0.0350646972656250, -0.0411376953125000, -0.0283508300781250, +-0.0386047363281250, -0.0247192382812500, -0.0375671386718750, -0.0288391113281250, +-0.0389099121093750, -0.0164794921875000, -0.0253906250000000, -0.0144653320312500, +-0.0300903320312500, -0.0197448730468750, -0.0249023437500000, -0.0196228027343750, +-0.0020446777343750, -0.0199890136718750, -0.0299377441406250, -0.0409545898437500, +-0.0203857421875000, -0.0235900878906250, -0.0305480957031250, -0.0438842773437500, +-0.0153503417968750, -0.0700073242187500, 0.0025024414062500, -0.0534057617187500, +-0.0095825195312500, -0.0775146484375000, 0.0018920898437500, -0.0874328613281250, +0.0102539062500000, -0.0699768066406250, 0.0032043457031250, -0.0682373046875000, +-0.0029296875000000, -0.0787048339843750, 0.0008850097656250, -0.0341186523437500, +-0.0014953613281250, -0.0413208007812500, -0.0044860839843750, -0.0284118652343750, +-0.0003051757812500, 0.0062561035156250, 0.0036621093750000, -0.0108947753906250, +0.0001525878906250, 0.0174255371093750, 0.0031127929687500, 0.0205078125000000, +0.0070495605468750, 0.0207824707031250, 0.0015869140625000, 0.0339660644531250, +-0.0039367675781250, 0.0286560058593750, 0.0006408691406250, 0.0307922363281250, +-0.0027770996093750, 0.0342407226562500, -0.0067138671875000, 0.0310974121093750, +-0.0016174316406250, 0.0279541015625000, 0.0033569335937500, 0.0303344726562500, +-0.0000305175781250, 0.0270385742187500, 0.0048217773437500, 0.0256042480468750, +0.0071411132812500, 0.0282592773437500, 0.0047302246093750, 0.0284729003906250, +0.0037841796875000, 0.0276794433593750, 0.0051574707031250, 0.0375671386718750, +0.0031433105468750, 0.0329284667968750, 0.0026245117187500, 0.0379028320312500, +0.0024414062500000, 0.0521545410156250, 0.0025939941406250, 0.0457153320312500, +0.0028381347656250, 0.0389404296875000, -0.0025024414062500, 0.0479125976562500, +-0.0003662109375000, 0.0370483398437500, -0.0033264160156250, 0.0214233398437500, +-0.0101318359375000, 0.0312805175781250, -0.0068969726562500, 0.0105285644531250, +-0.0086364746093750, 0.0123596191406250, -0.0124206542968750, 0.0061035156250000, +-0.0070190429687500, -0.0080566406250000, -0.0023498535156250, 0.0016784667968750, +-0.0065917968750000, -0.0175170898437500, 0.0044555664062500, -0.0193786621093750, +0.0043029785156250, -0.0153808593750000, 0.0050354003906250, -0.0220642089843750, +0.0104064941406250, -0.0223083496093750, 0.0080566406250000, -0.0149841308593750, +0.0143737792968750, -0.0177917480468750, 0.0123291015625000, -0.0143432617187500, +0.0158386230468750, -0.0077514648437500, 0.0229187011718750, -0.0118103027343750, +0.0188598632812500, -0.0011596679687500, 0.0253906250000000, -0.0025939941406250, +0.0266723632812500, -0.0003051757812500, 0.0253906250000000, 0.0083312988281250, +0.0264892578125000, 0.0043640136718750, 0.0265502929687500, 0.0055541992187500, +0.0282287597656250}, +{-0.0053100585937500, -0.0172424316406250, -0.0079956054687500, -0.0167236328125000, +-0.0074768066406250, -0.0190124511718750, -0.0095520019531250, -0.0275878906250000, +-0.0099487304687500, -0.0234680175781250, -0.0094299316406250, -0.0294189453125000, +-0.0320434570312500, -0.0317077636718750, -0.0238342285156250, -0.0278625488281250, +-0.0308837890625000, -0.0273437500000000, -0.0560607910156250, -0.0290832519531250, +-0.0480346679687500, -0.0207519531250000, -0.0468750000000000, -0.0216369628906250, +-0.0532226562500000, -0.0198059082031250, -0.0453796386718750, -0.0127868652343750, +-0.0360717773437500, -0.0154113769531250, -0.0427246093750000, -0.0178222656250000, +-0.0324401855468750, -0.0142517089843750, -0.0298156738281250, -0.0159912109375000, +-0.0316162109375000, -0.0238342285156250, -0.0288085937500000, -0.0400085449218750, +-0.0368957519531250, -0.0735778808593750, -0.0241394042968750, -0.0708007812500000, +-0.0224914550781250, -0.0628356933593750, -0.0243530273437500, -0.0699462890625000, +-0.0277099609375000, -0.0747070312500000, -0.0268249511718750, -0.0415649414062500, +-0.0124206542968750, -0.0502319335937500, -0.0173950195312500, -0.0383300781250000, +-0.0143737792968750, -0.0090942382812500, -0.0005493164062500, -0.0228576660156250, +-0.0043029785156250, 0.0053405761718750, -0.0023803710937500, 0.0039978027343750, +-0.0002136230468750, 0.0104675292968750, -0.0029296875000000, 0.0299987792968750, +-0.0051879882812500, 0.0202331542968750, -0.0028686523437500, 0.0371704101562500, +-0.0037536621093750, 0.0413208007812500, -0.0063171386718750, 0.0331115722656250, +-0.0041503906250000, 0.0354614257812500, 0.0002441406250000, 0.0404052734375000, +-0.0015258789062500, 0.0239562988281250, -0.0065307617187500, 0.0240173339843750, +-0.0029907226562500, 0.0248718261718750, -0.0060729980468750, 0.0158691406250000, +-0.0138854980468750, 0.0180969238281250, -0.0104980468750000, 0.0265197753906250, +-0.0106811523437500, 0.0203552246093750, -0.0135192871093750, 0.0289916992187500, +-0.0095214843750000, 0.0430297851562500, -0.0053405761718750, 0.0334472656250000, +-0.0080871582031250, 0.0444335937500000, -0.0011596679687500, 0.0545349121093750, +-0.0007629394531250, 0.0350952148437500, -0.0005187988281250, 0.0235595703125000, +0.0028076171875000, 0.0384521484375000, 0.0018310546875000, -0.0015258789062500, +0.0034484863281250, -0.0009765625000000, 0.0034484863281250, -0.0025329589843750, +0.0036621093750000, -0.0237731933593750, 0.0047912597656250, -0.0159606933593750, +0.0043640136718750, -0.0222778320312500, 0.0043334960937500, -0.0263671875000000, +0.0043640136718750, -0.0201416015625000, 0.0046386718750000, -0.0186157226562500, +0.0037231445312500, -0.0231933593750000, 0.0032958984375000, -0.0085754394531250, +0.0083923339843750, -0.0088195800781250, 0.0061340332031250, -0.0113830566406250, +0.0090332031250000, -0.0047302246093750, 0.0155639648437500, -0.0047912597656250, +0.0122680664062500, -0.0105590820312500, 0.0149230957031250, -0.0086669921875000, +0.0173645019531250, -0.0099487304687500, 0.0141601562500000, -0.0144958496093750, +0.0117492675781250, -0.0122070312500000, 0.0139465332031250, -0.0153503417968750, +0.0099792480468750, -0.0154113769531250, 0.0092773437500000, -0.0150756835937500, +0.0096740722656250, -0.0170288085937500, 0.0091247558593750, -0.0161437988281250, +0.0093994140625000, -0.0120239257812500, 0.0058593750000000, -0.0150146484375000, +0.0070800781250000, -0.0105895996093750, 0.0055541992187500, -0.0039672851562500, +0.0014343261718750, -0.0085449218750000, 0.0032653808593750, -0.0003662109375000, +0.0036621093750000, -0.0001525878906250, 0.0022277832031250, -0.0006103515625000, +0.0037231445312500, 0.0032958984375000, 0.0065612792968750, 0.0018005371093750, +0.0055847167968750, 0.0011291503906250, 0.0044555664062500, 0.0029602050781250, +0.0063476562500000, -0.0001831054687500, 0.0041809082031250, -0.0029907226562500, +0.0010681152343750, -0.0001220703125000, 0.0031738281250000, -0.0074768066406250, +-0.0004882812500000, -0.0062561035156250, -0.0002136230468750, -0.0078430175781250, +-0.0011291503906250, -0.0124206542968750, -0.0030822753906250, -0.0090332031250000, +-0.0015258789062500, -0.0163879394531250, -0.0070190429687500, -0.0139465332031250, +-0.0061645507812500, -0.0161743164062500, -0.0078125000000000, -0.0225219726562500, +-0.0122070312500000, -0.0183105468750000, -0.0101928710937500, -0.0244445800781250, +-0.0145263671875000, -0.0242919921875000, -0.0146789550781250, -0.0235900878906250, +-0.0148010253906250, -0.0259094238281250, -0.0168457031250000, -0.0240783691406250, +-0.0162353515625000, -0.0241394042968750, -0.0177612304687500, -0.0237121582031250, +-0.0167541503906250, -0.0228881835937500, -0.0191955566406250, -0.0224609375000000, +-0.0216674804687500, -0.0217590332031250, -0.0196838378906250, -0.0206604003906250, +-0.0281982421875000, -0.0206298828125000, -0.0275573730468750, -0.0190429687500000, +-0.0286865234375000, -0.0173645019531250, -0.0350036621093750, -0.0175476074218750, +-0.0333251953125000, -0.0140380859375000, -0.0323486328125000, -0.0134277343750000, +-0.0346374511718750, -0.0122985839843750, -0.0325927734375000, -0.0097656250000000, +-0.0290832519531250, -0.0094604492187500, -0.0308837890625000, -0.0070190429687500, +-0.0288696289062500, -0.0070190429687500, -0.0281677246093750, -0.0050659179687500, +-0.0274658203125000, -0.0024719238281250, -0.0269165039062500, -0.0033264160156250, +-0.0267944335937500, 0.0010681152343750, -0.0203857421875000, 0.0009460449218750, +-0.0227355957031250, 0.0021362304687500, -0.0179443359375000, 0.0054931640625000, +-0.0107116699218750, 0.0045776367187500, -0.0151977539062500, 0.0070800781250000, +-0.0039672851562500, 0.0075073242187500, -0.0041503906250000, 0.0063476562500000, +-0.0042419433593750, 0.0071411132812500, 0.0020141601562500, 0.0075683593750000, +0.0007934570312500, 0.0032958984375000, 0.0013122558593750, 0.0047607421875000, +0.0010375976562500, 0.0014953613281250, 0.0040283203125000, -0.0032958984375000, +0.0058898925781250, -0.0004882812500000, 0.0032958984375000, -0.0092468261718750, +0.0115356445312500, -0.0083618164062500, 0.0122070312500000, -0.0098266601562500, +0.0101928710937500, -0.0158996582031250, 0.0130615234375000, -0.0129394531250000, +0.0141906738281250, -0.0153808593750000, 0.0102844238281250, -0.0169372558593750, +0.0101928710937500, -0.0139160156250000, 0.0110168457031250, -0.0122070312500000, +0.0101318359375000, -0.0133056640625000, 0.0095520019531250, -0.0076293945312500, +0.0080261230468750, -0.0072326660156250, 0.0093078613281250, -0.0075073242187500, +0.0064086914062500, -0.0042419433593750, 0.0027160644531250, -0.0048522949218750, +0.0046691894531250, -0.0108032226562500, -0.0007629394531250, -0.0077209472656250, +-0.0007019042968750, -0.0128784179687500, -0.0016479492187500, -0.0215759277343750, +-0.0050659179687500, -0.0175476074218750, -0.0033264160156250, -0.0261840820312500, +-0.0043640136718750, -0.0274353027343750, -0.0057983398437500, -0.0265502929687500, +-0.0039367675781250, -0.0301513671875000, -0.0019531250000000, -0.0294494628906250, +-0.0032348632812500, -0.0251464843750000, -0.0027465820312500, -0.0277709960937500, +-0.0012512207031250, -0.0231933593750000, -0.0026550292968750, -0.0172119140625000, +-0.0039978027343750, -0.0213012695312500, -0.0027160644531250, -0.0092163085937500, +-0.0072021484375000, -0.0097351074218750, -0.0059204101562500, -0.0087280273437500, +-0.0067138671875000, -0.0020446777343750, -0.0101013183593750, -0.0040893554687500, +-0.0083618164062500, 0.0032043457031250, -0.0117187500000000, 0.0023803710937500, +-0.0107116699218750, 0.0031127929687500, -0.0106201171875000, 0.0089111328125000, +-0.0122070312500000, 0.0073852539062500, -0.0116882324218750, 0.0061340332031250, +-0.0177001953125000, 0.0087890625000000, -0.0152587890625000, 0.0036926269531250, +-0.0154113769531250, -0.0014648437500000, -0.0206298828125000, 0.0029602050781250, +-0.0200805664062500, -0.0068054199218750, -0.0218505859375000, -0.0085449218750000, +-0.0209350585937500, -0.0067749023437500, -0.0199279785156250, -0.0101928710937500, +-0.0227050781250000, -0.0107116699218750, -0.0234680175781250, -0.0044555664062500, +-0.0149841308593750, -0.0052185058593750, -0.0168151855468750, -0.0065307617187500, +-0.0160522460937500, -0.0035705566406250, -0.0090637207031250, -0.0040588378906250, +-0.0097961425781250, -0.0071411132812500, -0.0102844238281250, -0.0039978027343750, +-0.0111694335937500, -0.0095214843750000, -0.0086059570312500, -0.0155334472656250, +-0.0065917968750000, -0.0092468261718750, -0.0090332031250000, -0.0224304199218750, +-0.0042114257812500, -0.0240478515625000, -0.0024108886718750, -0.0214538574218750, +-0.0060729980468750, -0.0270080566406250, -0.0064086914062500, -0.0267333984375000, +-0.0039672851562500, -0.0142517089843750, -0.0137634277343750, -0.0197448730468750, +-0.0157165527343750, -0.0131530761718750, -0.0106201171875000, 0.0010986328125000, +-0.0116271972656250, -0.0066223144531250, -0.0150146484375000, 0.0045776367187500, +-0.0037231445312500, 0.0094299316406250, -0.0049438476562500, 0.0001525878906250, +-0.0021362304687500, -0.0021972656250000, 0.0067443847656250, 0.0040283203125000, +0.0022888183593750, -0.0140991210937500, 0.0022583007812500, -0.0158386230468750, +0.0076904296875000, -0.0101318359375000, -0.0020141601562500, -0.0158996582031250, +-0.0109863281250000, -0.0185546875000000, -0.0032958984375000, -0.0048522949218750, +-0.0228576660156250, -0.0056457519531250, -0.0248718261718750, -0.0065002441406250, +-0.0219726562500000, 0.0010375976562500, -0.0288696289062500, 0.0001220703125000, +-0.0290527343750000, -0.0048828125000000, -0.0262451171875000, -0.0025329589843750, +-0.0272521972656250, -0.0052185058593750, -0.0261535644531250, -0.0102844238281250, +-0.0235290527343750, -0.0074462890625000, -0.0252990722656250, -0.0146484375000000, +-0.0249328613281250, -0.0136108398437500, -0.0245056152343750, -0.0150146484375000, +-0.0229797363281250, -0.0205993652343750, -0.0233154296875000, -0.0178222656250000, +-0.0248413085937500, -0.0190734863281250, -0.0161743164062500, -0.0214538574218750, +-0.0178833007812500, -0.0162353515625000, -0.0154724121093750, -0.0133056640625000, +-0.0079650878906250, -0.0170593261718750, -0.0114440917968750, -0.0023803710937500, +-0.0097656250000000, -0.0050964355468750, -0.0073852539062500, -0.0012512207031250, +-0.0110473632812500, 0.0105590820312500, -0.0146789550781250, 0.0050354003906250, +-0.0126647949218750, 0.0123291015625000, -0.0159912109375000, 0.0142211914062500, +-0.0181579589843750, 0.0120849609375000, -0.0151977539062500, 0.0137634277343750, +-0.0139160156250000, 0.0141296386718750, -0.0155639648437500, 0.0087585449218750, +-0.0070800781250000, 0.0110778808593750, -0.0085754394531250, 0.0059509277343750, +-0.0045776367187500, -0.0005187988281250, 0.0032043457031250, 0.0037231445312500, +-0.0004272460937500, -0.0121459960937500, 0.0084228515625000, -0.0100402832031250, +0.0090026855468750, -0.0145568847656250, 0.0092163085937500, -0.0276184082031250, +0.0136718750000000, -0.0224914550781250, 0.0122985839843750, -0.0303649902343750, +0.0120849609375000, -0.0338134765625000, 0.0133666992187500, -0.0311584472656250, +0.0112915039062500, -0.0318298339843750, 0.0093994140625000, -0.0339660644531250, +0.0108032226562500, -0.0297546386718750, 0.0049133300781250, -0.0305175781250000, +0.0060424804687500, -0.0307006835937500, 0.0028076171875000, -0.0286865234375000, +-0.0028076171875000, -0.0301818847656250, 0.0000000000000000, -0.0276794433593750, +-0.0082397460937500, -0.0289001464843750, -0.0082397460937500, -0.0276489257812500, +-0.0097045898437500}, +{-0.0076904296875000, -0.0063171386718750, -0.0082397460937500, -0.0053100585937500, +-0.0080261230468750, -0.0057983398437500, -0.0079650878906250, -0.0026550292968750, +0.0003356933593750, -0.0041198730468750, -0.0023498535156250, -0.0053405761718750, +-0.0038146972656250, -0.0014038085937500, 0.0025634765625000, -0.0016784667968750, +0.0019226074218750, -0.0146179199218750, -0.0054321289062500, -0.0095214843750000, +-0.0033264160156250, -0.0137329101562500, -0.0055236816406250, -0.0270996093750000, +-0.0136413574218750, -0.0212402343750000, -0.0109252929687500, -0.0245666503906250, +-0.0045166015625000, -0.0291442871093750, -0.0090942382812500, -0.0234375000000000, +-0.0056457519531250, -0.0191345214843750, 0.0033264160156250, -0.0228576660156250, +-0.0002441406250000, -0.0104064941406250, 0.0043945312500000, -0.0121154785156250, +0.0067138671875000, -0.0104675292968750, 0.0010681152343750, -0.0005493164062500, +-0.0005798339843750, -0.0043334960937500, 0.0027160644531250, -0.0083312988281250, +-0.0125732421875000, -0.0030822753906250, -0.0111389160156250, -0.0093383789062500, +-0.0134582519531250, -0.0193786621093750, -0.0244750976562500, -0.0133056640625000, +-0.0208740234375000, -0.0195007324218750, -0.0218200683593750, -0.0237731933593750, +-0.0239868164062500, -0.0192565917968750, -0.0234985351562500, -0.0167541503906250, +-0.0227355957031250, -0.0195007324218750, -0.0228576660156250, -0.0114440917968750, +-0.0197448730468750, -0.0116882324218750, -0.0212707519531250, -0.0109863281250000, +-0.0202636718750000, -0.0061035156250000, -0.0172424316406250, -0.0075378417968750, +-0.0183410644531250, -0.0060119628906250, -0.0137329101562500, -0.0047912597656250, +-0.0149841308593750, -0.0062255859375000, -0.0142517089843750, -0.0067749023437500, +-0.0097961425781250, -0.0053405761718750, -0.0113830566406250, -0.0087585449218750, +-0.0137634277343750, -0.0079345703125000, -0.0120849609375000, -0.0079956054687500, +-0.0147399902343750, -0.0105285644531250, -0.0194396972656250, -0.0093078613281250, +-0.0174560546875000, -0.0081787109375000, -0.0180358886718750, -0.0101928710937500, +-0.0215454101562500, -0.0062561035156250, -0.0157470703125000, -0.0024719238281250, +-0.0104980468750000, -0.0059814453125000, -0.0149230957031250, 0.0030517578125000, +-0.0010070800781250, 0.0027465820312500, -0.0014038085937500, 0.0011596679687500, +0.0007629394531250, 0.0057067871093750, 0.0095520019531250, 0.0043334960937500, +0.0060119628906250, -0.0032653808593750, 0.0101928710937500, 0.0003967285156250, +0.0115966796875000, -0.0064697265625000, 0.0095825195312500, -0.0164489746093750, +0.0095520019531250, -0.0107421875000000, 0.0099487304687500, -0.0266113281250000, +0.0062255859375000, -0.0255432128906250, 0.0062561035156250, -0.0295410156250000, +0.0053405761718750, -0.0404968261718750, 0.0026550292968750, -0.0355224609375000, +0.0034790039062500, -0.0475769042968750, 0.0028686523437500, -0.0480651855468750, +0.0023498535156250, -0.0480651855468750, 0.0028381347656250, -0.0551147460937500, +0.0032043457031250, -0.0534667968750000, 0.0029296875000000, -0.0497741699218750, +0.0035400390625000, -0.0539245605468750, 0.0034484863281250, -0.0483093261718750, +0.0038452148437500, -0.0411376953125000, 0.0046081542968750, -0.0466003417968750, +0.0044250488281250, -0.0323486328125000, 0.0046081542968750, -0.0339660644531250, +0.0054931640625000, -0.0309753417968750, 0.0047607421875000, -0.0209350585937500, +0.0043029785156250, -0.0258178710937500, 0.0055847167968750, -0.0177917480468750, +0.0025634765625000, -0.0169677734375000, 0.0035095214843750, -0.0176696777343750, +0.0029296875000000, -0.0143737792968750, 0.0006103515625000, -0.0150756835937500, +0.0020751953125000, -0.0152587890625000, 0.0000305175781250, -0.0148925781250000, +0.0003356933593750, -0.0138854980468750, 0.0003662109375000, -0.0138244628906250, +-0.0007934570312500, -0.0142822265625000, 0.0001525878906250, -0.0100402832031250, +-0.0004882812500000, -0.0106811523437500, -0.0004577636718750, -0.0096130371093750, +-0.0003051757812500, -0.0060119628906250, -0.0004272460937500, -0.0073242187500000, +0.0000000000000000, -0.0075683593750000, -0.0000305175781250, -0.0054016113281250, +0.0000915527343750, -0.0085754394531250, 0.0009155273437500, -0.0115356445312500, +0.0011596679687500, -0.0088500976562500, 0.0007324218750000, -0.0172119140625000, +0.0025634765625000, -0.0166320800781250, 0.0026550292968750, -0.0178527832031250, +0.0025634765625000, -0.0235290527343750, 0.0040893554687500, -0.0216979980468750, +0.0040588378906250, -0.0243225097656250, 0.0003662109375000, -0.0245971679687500, +0.0036010742187500, -0.0258789062500000, -0.0007019042968750, -0.0274963378906250, +-0.0062255859375000, -0.0263977050781250, -0.0008544921875000, -0.0327453613281250, +-0.0126953125000000, -0.0322875976562500, -0.0106811523437500, -0.0343017578125000, +-0.0118713378906250, -0.0398864746093750, -0.0199279785156250, -0.0384521484375000, +-0.0158386230468750, -0.0397033691406250, -0.0196228027343750, -0.0418090820312500, +-0.0221557617187500, -0.0395812988281250, -0.0184326171875000, -0.0384826660156250, +-0.0174865722656250, -0.0405578613281250, -0.0200195312500000, -0.0320129394531250, +-0.0093994140625000, -0.0354003906250000, -0.0127258300781250, -0.0295715332031250, +-0.0077819824218750, -0.0202331542968750, 0.0030822753906250, -0.0267333984375000, +-0.0033569335937500, -0.0109558105468750, 0.0046691894531250, -0.0115051269531250, +0.0076293945312500, -0.0103149414062500, 0.0030517578125000, -0.0012207031250000, +0.0032043457031250, -0.0043640136718750, 0.0051574707031250, 0.0006408691406250, +-0.0063476562500000, -0.0000305175781250, -0.0032958984375000, 0.0030822753906250, +-0.0080871582031250, 0.0077819824218750, -0.0186767578125000, 0.0044860839843750, +-0.0137329101562500, 0.0133666992187500, -0.0260314941406250, 0.0133361816406250, +-0.0261840820312500, 0.0132446289062500, -0.0257568359375000, 0.0180358886718750, +-0.0338134765625000, 0.0170898437500000, -0.0320739746093750, 0.0170593261718750, +-0.0218200683593750, 0.0175170898437500, -0.0268554687500000, 0.0180969238281250, +-0.0202941894531250, 0.0186462402343750, -0.0072937011718750, 0.0180664062500000, +-0.0131530761718750, 0.0171203613281250, -0.0025329589843750, 0.0203857421875000, +-0.0019836425781250, 0.0131225585937500, -0.0003967285156250, 0.0075073242187500, +0.0052490234375000, 0.0134277343750000, 0.0019531250000000, -0.0086059570312500, +0.0080871582031250, -0.0060729980468750, 0.0094604492187500, -0.0094299316406250, +0.0073852539062500, -0.0247497558593750, 0.0097045898437500, -0.0187072753906250, +0.0099182128906250, -0.0245971679687500, -0.0022888183593750, -0.0261840820312500, +0.0003967285156250, -0.0258789062500000, 0.0004272460937500, -0.0274658203125000, +-0.0083923339843750, -0.0263977050781250, -0.0072326660156250, -0.0289916992187500, +-0.0054016113281250, -0.0296630859375000, -0.0057983398437500, -0.0268859863281250, +-0.0057678222656250, -0.0264587402343750, -0.0035095214843750, -0.0280761718750000, +-0.0041503906250000, -0.0205688476562500, -0.0137939453125000, -0.0201416015625000, +-0.0114746093750000, -0.0218811035156250, -0.0120544433593750, -0.0177612304687500, +-0.0182189941406250, -0.0176086425781250, -0.0177001953125000, -0.0304565429687500, +-0.0262451171875000, -0.0242614746093750, -0.0223388671875000, -0.0336608886718750, +-0.0283203125000000, -0.0495910644531250, -0.0381164550781250, -0.0402832031250000, +-0.0322570800781250, -0.0613403320312500, -0.0505065917968750, -0.0623168945312500, +-0.0499572753906250, -0.0592651367187500, -0.0477905273437500, -0.0713806152343750, +-0.0601501464843750, -0.0496826171875000, -0.0425720214843750, -0.0186767578125000, +-0.0569458007812500, -0.0314636230468750, -0.0542602539062500, -0.0167846679687500, +-0.0506591796875000, 0.0037231445312500, -0.0559082031250000, -0.0086364746093750, +-0.0589904785156250, 0.0139465332031250, -0.0393676757812500, 0.0161132812500000, +-0.0427246093750000, 0.0153503417968750, -0.0368347167968750, 0.0261840820312500, +-0.0209960937500000, 0.0228881835937500, -0.0288696289062500, 0.0173339843750000, +-0.0202941894531250, 0.0219421386718750, -0.0147094726562500, 0.0167541503906250, +-0.0208129882812500, 0.0060729980468750, -0.0259399414062500, 0.0114440917968750, +-0.0218505859375000, 0.0128479003906250, -0.0202941894531250, 0.0058898925781250, +-0.0251464843750000, 0.0112915039062500, -0.0199584960937500, 0.0223083496093750, +-0.0120239257812500, 0.0171203613281250, -0.0161437988281250, 0.0145874023437500, +-0.0093078613281250, 0.0204772949218750, -0.0079650878906250, 0.0119934082031250, +-0.0096740722656250, 0.0031127929687500, -0.0081176757812500, 0.0105895996093750, +-0.0077514648437500, -0.0101623535156250, -0.0095520019531250, -0.0088500976562500, +-0.0101623535156250, -0.0098876953125000, -0.0091552734375000, -0.0241394042968750, +-0.0088500976562500, -0.0196533203125000, -0.0096435546875000, -0.0115356445312500, +-0.0083312988281250, -0.0169982910156250, -0.0082702636718750, -0.0164184570312500, +-0.0070495605468750, -0.0069274902343750, -0.0068359375000000, -0.0086059570312500, +-0.0075683593750000, -0.0144348144531250, 0.0010986328125000, -0.0120544433593750, +-0.0018615722656250, -0.0157165527343750, 0.0030822753906250, -0.0212402343750000, +0.0131225585937500, -0.0175170898437500, 0.0082702636718750, -0.0281982421875000, +0.0157470703125000, -0.0270690917968750, 0.0184631347656250, -0.0278625488281250, +0.0149230957031250, -0.0364379882812500, 0.0151672363281250, -0.0335388183593750, +0.0169372558593750, -0.0260009765625000, 0.0091552734375000, -0.0324096679687500, +0.0109252929687500, -0.0259399414062500, 0.0075073242187500, -0.0135803222656250, +0.0010986328125000, -0.0206604003906250, 0.0050964355468750, -0.0109863281250000, +-0.0061645507812500, -0.0083923339843750, -0.0050354003906250, -0.0115661621093750, +-0.0068969726562500, -0.0092468261718750, -0.0145874023437500, -0.0081176757812500, +-0.0114440917968750, -0.0163269042968750, -0.0162048339843750, -0.0132141113281250, +-0.0160522460937500, -0.0178222656250000, -0.0179138183593750, -0.0264892578125000, +-0.0208129882812500, -0.0207214355468750, -0.0184631347656250, -0.0302429199218750, +-0.0274658203125000, -0.0320434570312500, -0.0260009765625000, -0.0286560058593750, +-0.0281372070312500, -0.0308837890625000, -0.0350341796875000, -0.0319824218750000, +-0.0319519042968750, -0.0237426757812500, -0.0364074707031250, -0.0265502929687500, +-0.0365905761718750, -0.0226745605468750, -0.0369262695312500, -0.0157470703125000, +-0.0395507812500000, -0.0208435058593750, -0.0380859375000000, -0.0080871582031250, +-0.0382995605468750, -0.0104675292968750, -0.0402221679687500, -0.0069274902343750, +-0.0362243652343750, 0.0030517578125000, -0.0330200195312500, -0.0026550292968750, +-0.0360107421875000, 0.0063171386718750, -0.0262451171875000, 0.0070495605468750, +-0.0265502929687500, 0.0059509277343750, -0.0253295898437500, 0.0096740722656250, +-0.0197753906250000, 0.0086975097656250, -0.0217285156250000, 0.0070495605468750, +-0.0162048339843750, 0.0089111328125000, -0.0175781250000000, 0.0067443847656250, +-0.0140075683593750, 0.0039978027343750, -0.0078735351562500, 0.0063781738281250, +-0.0113525390625000, 0.0002746582031250, -0.0037841796875000, 0.0016479492187500, +-0.0023803710937500, 0.0003051757812500, -0.0043640136718750, -0.0039672851562500, +-0.0025024414062500, -0.0007629394531250, -0.0021362304687500, -0.0046997070312500, +-0.0067443847656250, -0.0039062500000000, -0.0066833496093750, -0.0036926269531250, +-0.0070495605468750, -0.0055847167968750, -0.0096130371093750, -0.0034484863281250, +-0.0091857910156250}, +{-0.0155639648437500, 0.0105590820312500, -0.0213012695312500, 0.0049438476562500, +-0.0242309570312500, 0.0120239257812500, -0.0209655761718750, 0.0013122558593750, +-0.0210876464843750, -0.0141296386718750, -0.0259704589843750, -0.0043029785156250, +-0.0255737304687500, -0.0167541503906250, -0.0160827636718750, -0.0213012695312500, +-0.0205383300781250, -0.0163574218750000, -0.0139465332031250, -0.0177917480468750, +-0.0015258789062500, -0.0203552246093750, -0.0082702636718750, -0.0083618164062500, +0.0007019042968750, -0.0106811523437500, 0.0036621093750000, -0.0103149414062500, +0.0007629394531250, 0.0001220703125000, 0.0009155273437500, -0.0034484863281250, +0.0016784667968750, -0.0181274414062500, 0.0016479492187500, -0.0096130371093750, +0.0007934570312500, -0.0163879394531250, 0.0009765625000000, -0.0359191894531250, +0.0025939941406250, -0.0288085937500000, 0.0025329589843750, -0.0321044921875000, +-0.0013732910156250, -0.0360107421875000, -0.0000610351562500, -0.0327758789062500, +-0.0007019042968750, -0.0308532714843750, -0.0047607421875000, -0.0329284667968750, +-0.0033264160156250, -0.0259704589843750, 0.0000305175781250, -0.0281066894531250, +-0.0018005371093750, -0.0241394042968750, 0.0006103515625000, -0.0165405273437500, +0.0061035156250000, -0.0213928222656250, 0.0042724609375000, -0.0152282714843750, +0.0032348632812500, -0.0123901367187500, 0.0064392089843750, -0.0156555175781250, +0.0019836425781250, -0.0163879394531250, -0.0028076171875000, -0.0144653320312500, +0.0009155273437500, -0.0192871093750000, -0.0097656250000000, -0.0190429687500000, +-0.0079956054687500, -0.0189208984375000, -0.0117797851562500, -0.0220642089843750, +-0.0201110839843750, -0.0211791992187500, -0.0153198242187500, -0.0182800292968750, +-0.0268554687500000, -0.0210571289062500, -0.0266113281250000, -0.0167846679687500, +-0.0272216796875000, -0.0115356445312500, -0.0335388183593750, -0.0159606933593750, +-0.0314331054687500, -0.0050048828125000, -0.0348815917968750, -0.0050659179687500, +-0.0340270996093750, -0.0054016113281250, -0.0369873046875000, 0.0000915527343750, +-0.0407104492187500, -0.0014953613281250, -0.0375671386718750, -0.0017089843750000, +-0.0464782714843750, -0.0007934570312500, -0.0462341308593750, -0.0016784667968750, +-0.0462951660156250, -0.0023803710937500, -0.0513000488281250, -0.0016784667968750, +-0.0498962402343750, -0.0042114257812500, -0.0495605468750000, -0.0025329589843750, +-0.0505981445312500, -0.0050354003906250, -0.0488281250000000, -0.0083923339843750, +-0.0478210449218750, -0.0052795410156250, -0.0488586425781250, -0.0130004882812500, +-0.0409240722656250, -0.0120239257812500, -0.0441284179687500, -0.0129699707031250, +-0.0377502441406250, -0.0178833007812500, -0.0278320312500000, -0.0154418945312500, +-0.0337524414062500, -0.0189819335937500, -0.0196533203125000, -0.0195312500000000, +-0.0190734863281250, -0.0191650390625000, -0.0186767578125000, -0.0207214355468750, +-0.0118713378906250, -0.0206909179687500, -0.0142822265625000, -0.0203247070312500, +-0.0104980468750000, -0.0210876464843750, -0.0114135742187500, -0.0206298828125000, +-0.0090637207031250, -0.0200805664062500, -0.0053710937500000, -0.0213317871093750, +-0.0080566406250000, -0.0197448730468750, -0.0006103515625000, -0.0208740234375000, +-0.0004882812500000, -0.0201110839843750, -0.0011901855468750, -0.0186462402343750, +0.0028686523437500, -0.0205688476562500, 0.0023498535156250, -0.0174560546875000, +-0.0016784667968750, -0.0185241699218750, 0.0006408691406250, -0.0178527832031250, +-0.0021362304687500, -0.0156555175781250, -0.0069274902343750, -0.0177612304687500, +-0.0039062500000000, -0.0146789550781250, -0.0107421875000000, -0.0159301757812500, +-0.0093688964843750, -0.0152587890625000, -0.0129699707031250, -0.0129394531250000, +-0.0188293457031250, -0.0151977539062500, -0.0152587890625000, -0.0119934082031250, +-0.0280761718750000, -0.0125122070312500, -0.0258789062500000, -0.0124816894531250, +-0.0307006835937500, -0.0106506347656250, -0.0413208007812500, -0.0115661621093750, +-0.0356140136718750, -0.0093994140625000, -0.0476379394531250, -0.0096130371093750, +-0.0484313964843750, -0.0086059570312500, -0.0474243164062500, -0.0068054199218750, +-0.0527954101562500, -0.0075683593750000, -0.0520019531250000, -0.0044860839843750, +-0.0503845214843750, -0.0046997070312500, -0.0505371093750000, -0.0029907226562500, +-0.0512390136718750, -0.0004272460937500, -0.0508117675781250, -0.0015563964843750, +-0.0496520996093750, 0.0038757324218750, -0.0502319335937500, 0.0030212402343750, +-0.0520935058593750, 0.0044555664062500, -0.0479431152343750, 0.0086975097656250, +-0.0451354980468750, 0.0064392089843750, -0.0486450195312500, 0.0081787109375000, +-0.0380554199218750, 0.0089111328125000, -0.0400695800781250, 0.0064392089843750, +-0.0363464355468750, 0.0053100585937500, -0.0287475585937500, 0.0054626464843750, +-0.0336914062500000, -0.0011901855468750, -0.0183105468750000, -0.0005187988281250, +-0.0209350585937500, -0.0037231445312500, -0.0158996582031250, -0.0098876953125000, +-0.0030517578125000, -0.0075073242187500, -0.0091552734375000, -0.0122070312500000, +0.0023193359375000, -0.0142822265625000, 0.0038757324218750, -0.0107727050781250, +0.0035705566406250, -0.0102233886718750, 0.0083618164062500, -0.0125427246093750, +0.0075988769531250, -0.0026245117187500, 0.0090942382812500, -0.0032348632812500, +0.0090332031250000, -0.0018310546875000, 0.0101623535156250, 0.0046386718750000, +0.0119628906250000, 0.0022583007812500, 0.0104370117187500, 0.0042419433593750, +0.0107421875000000, 0.0067749023437500, 0.0140380859375000, 0.0017700195312500, +0.0065307617187500, -0.0012512207031250, 0.0015563964843750, 0.0023498535156250, +0.0083007812500000, -0.0093383789062500, -0.0122985839843750, -0.0088806152343750, +-0.0102844238281250, -0.0097656250000000, -0.0126647949218750, -0.0167846679687500, +-0.0260314941406250, -0.0141296386718750, -0.0203552246093750, -0.0145263671875000, +-0.0253295898437500, -0.0156860351562500, -0.0293273925781250, -0.0154418945312500, +-0.0236206054687500, -0.0144958496093750, -0.0190429687500000, -0.0139160156250000, +-0.0234985351562500, -0.0150451660156250, -0.0219116210937500, -0.0169982910156250, +-0.0190734863281250, -0.0137329101562500, -0.0195922851562500, -0.0106811523437500, +-0.0216369628906250, -0.0130615234375000, -0.0221862792968750, -0.0071105957031250, +-0.0218200683593750, -0.0078735351562500, -0.0217895507812500, -0.0054016113281250, +-0.0194396972656250, -0.0000915527343750, -0.0190429687500000, -0.0028076171875000, +-0.0209655761718750, 0.0017089843750000, -0.0111389160156250, 0.0034484863281250, +-0.0132751464843750, 0.0013732910156250, -0.0107421875000000, 0.0012817382812500, +-0.0023803710937500, 0.0032348632812500, -0.0056457519531250, 0.0014953613281250, +-0.0012512207031250, 0.0002441406250000, -0.0004577636718750, 0.0024719238281250, +-0.0022888183593750, 0.0054321289062500, -0.0018005371093750, 0.0052185058593750, +-0.0016784667968750, 0.0041198730468750, -0.0037536621093750, 0.0062561035156250, +-0.0051879882812500, 0.0028076171875000, -0.0026245117187500, -0.0013122558593750, +-0.0014038085937500, 0.0026855468750000, -0.0034484863281250, -0.0015258789062500, +0.0041503906250000, -0.0039367675781250, 0.0036621093750000, -0.0048217773437500, +0.0032653808593750, -0.0032653808593750, 0.0072937011718750, -0.0021667480468750, +0.0067138671875000, -0.0163574218750000, 0.0067138671875000, -0.0112609863281250, +0.0070495605468750, -0.0174865722656250, 0.0046386718750000, -0.0325927734375000, +0.0040283203125000, -0.0249938964843750, 0.0058898925781250, -0.0333251953125000, +-0.0019531250000000, -0.0374450683593750, -0.0011291503906250, -0.0324401855468750, +-0.0036315917968750, -0.0317382812500000, -0.0095520019531250, -0.0343017578125000, +-0.0061645507812500, -0.0225830078125000, -0.0109252929687500, -0.0238037109375000, +-0.0130310058593750, -0.0241088867187500, -0.0108337402343750, -0.0169372558593750, +-0.0106201171875000, -0.0180969238281250, -0.0116882324218750, -0.0198974609375000, +-0.0072631835937500, -0.0194702148437500, -0.0069885253906250, -0.0177001953125000, +-0.0099487304687500, -0.0182800292968750, -0.0091247558593750, -0.0194702148437500, +-0.0070190429687500, -0.0129394531250000, -0.0135498046875000, -0.0134582519531250, +-0.0146484375000000, -0.0132141113281250, -0.0132446289062500, -0.0099182128906250, +-0.0150146484375000, -0.0105285644531250, -0.0148925781250000, -0.0064697265625000, +-0.0105285644531250, -0.0086364746093750, -0.0129394531250000, -0.0041503906250000, +-0.0084228515625000, 0.0021057128906250, -0.0014953613281250, -0.0023193359375000, +-0.0056762695312500, 0.0068054199218750, 0.0010070800781250, 0.0081787109375000, +0.0030517578125000, 0.0046997070312500, 0.0003967285156250, 0.0075683593750000, +0.0008850097656250, 0.0088500976562500, 0.0019531250000000, -0.0025939941406250, +-0.0030517578125000, 0.0015258789062500, -0.0033874511718750, -0.0049438476562500, +-0.0025329589843750, -0.0166625976562500, -0.0049133300781250, -0.0098266601562500, +-0.0050659179687500, -0.0262756347656250, 0.0002746582031250, -0.0256958007812500, +-0.0016479492187500, -0.0281066894531250, 0.0021362304687500, -0.0385742187500000, +0.0083312988281250, -0.0344543457031250, 0.0049133300781250, -0.0412597656250000, +0.0127258300781250, -0.0426025390625000, 0.0134277343750000, -0.0422363281250000, +0.0126037597656250, -0.0449523925781250, 0.0159606933593750, -0.0447387695312500, +0.0152893066406250, -0.0444946289062500, 0.0123596191406250, -0.0451965332031250, +0.0132751464843750, -0.0452575683593750, 0.0105895996093750, -0.0444946289062500, +0.0064392089843750, -0.0446166992187500, 0.0075683593750000, -0.0456542968750000, +0.0029296875000000, -0.0450744628906250, 0.0021667480468750, -0.0451660156250000, +0.0018615722656250, -0.0462341308593750, -0.0003662109375000, -0.0457153320312500, +0.0000610351562500, -0.0452880859375000, 0.0000305175781250, -0.0455627441406250, +-0.0007019042968750, -0.0447387695312500, 0.0004577636718750, -0.0440673828125000, +0.0012817382812500, -0.0440979003906250, 0.0000915527343750, -0.0404052734375000, +0.0031738281250000, -0.0422058105468750, 0.0028076171875000, -0.0378417968750000, +0.0033874511718750, -0.0330505371093750, 0.0056152343750000, -0.0368347167968750, +0.0048522949218750, -0.0240478515625000, 0.0064392089843750, -0.0263061523437500, +0.0068054199218750, -0.0223083496093750, 0.0065917968750000, -0.0122375488281250, +0.0072326660156250, -0.0175170898437500, 0.0072631835937500, -0.0069580078125000, +0.0063476562500000, -0.0068664550781250, 0.0071411132812500, -0.0063781738281250, +0.0065917968750000, -0.0004577636718750, 0.0052490234375000, -0.0027770996093750, +0.0060424804687500, -0.0019226074218750, 0.0050659179687500, -0.0001525878906250, +0.0049438476562500, -0.0025024414062500, 0.0046997070312500, -0.0042419433593750, +0.0043945312500000, -0.0026550292968750, 0.0048522949218750, -0.0078430175781250, +0.0026855468750000, -0.0070495605468750, 0.0036010742187500, -0.0087585449218750, +0.0027770996093750, -0.0122375488281250, 0.0007019042968750, -0.0103454589843750, +0.0021362304687500, -0.0185546875000000, 0.0000000000000000, -0.0158081054687500, +0.0006408691406250, -0.0215454101562500, -0.0003356933593750, -0.0305786132812500, +-0.0018920898437500, -0.0250549316406250, -0.0003356933593750, -0.0400085449218750, +-0.0052795410156250, -0.0396118164062500, -0.0042114257812500, -0.0410156250000000, +-0.0047607421875000, -0.0498962402343750, -0.0086364746093750, -0.0465698242187500, +-0.0068359375000000, -0.0504455566406250, -0.0066528320312500, -0.0519409179687500, +-0.0081787109375000}, +{-0.0034179687500000, -0.0137939453125000, -0.0044250488281250, -0.0097656250000000, +-0.0033264160156250, -0.0042114257812500, 0.0022888183593750, -0.0078125000000000, +0.0002441406250000, -0.0042419433593750, 0.0024719238281250, -0.0022277832031250, +0.0045776367187500, -0.0039978027343750, 0.0009460449218750, -0.0050354003906250, +-0.0013732910156250, -0.0039672851562500, 0.0016174316406250, -0.0047912597656250, +-0.0042419433593750, -0.0057678222656250, -0.0054626464843750, -0.0050659179687500, +-0.0027160644531250, -0.0039062500000000, -0.0034484863281250, -0.0048522949218750, +-0.0045471191406250, -0.0068359375000000, 0.0024414062500000, -0.0041503906250000, +0.0018310546875000, -0.0104370117187500, 0.0036621093750000, -0.0159606933593750, +0.0092163085937500, -0.0111083984375000, 0.0075378417968750, -0.0285949707031250, +0.0096435546875000, -0.0255126953125000, 0.0109252929687500, -0.0304870605468750, +0.0092773437500000, -0.0443725585937500, 0.0086669921875000, -0.0372314453125000, +0.0094909667968750, -0.0477600097656250, 0.0054626464843750, -0.0496826171875000, +0.0057983398437500, -0.0475158691406250, 0.0050964355468750, -0.0505065917968750, +0.0020751953125000, -0.0503234863281250, 0.0028381347656250, -0.0470581054687500, +0.0020446777343750, -0.0484619140625000, 0.0010375976562500, -0.0461425781250000, +0.0018615722656250, -0.0424804687500000, 0.0025939941406250, -0.0447387695312500, +0.0020751953125000, -0.0389404296875000, 0.0041503906250000, -0.0389404296875000, +0.0041198730468750, -0.0385131835937500, 0.0043334960937500, -0.0350341796875000, +0.0053405761718750, -0.0358886718750000, 0.0044860839843750, -0.0350646972656250, +0.0050048828125000, -0.0346069335937500, 0.0043640136718750, -0.0342102050781250, +0.0036010742187500, -0.0337829589843750, 0.0033264160156250, -0.0338134765625000, +0.0023193359375000, -0.0316467285156250, 0.0021667480468750, -0.0317687988281250, +0.0010986328125000, -0.0305786132812500, 0.0004882812500000, -0.0289611816406250, +0.0002441406250000, -0.0296020507812500, -0.0009155273437500, -0.0247802734375000, +-0.0011291503906250, -0.0265502929687500, -0.0021362304687500, -0.0227355957031250, +-0.0032348632812500, -0.0172119140625000, -0.0038757324218750, -0.0210266113281250, +-0.0045166015625000, -0.0111694335937500, -0.0048828125000000, -0.0119323730468750, +-0.0065307617187500, -0.0109252929687500, -0.0062561035156250, -0.0047302246093750, +-0.0054931640625000, -0.0075073242187500, -0.0070495605468750, -0.0054016113281250, +-0.0051574707031250, -0.0042419433593750, -0.0057067871093750, -0.0060424804687500, +-0.0055236816406250, -0.0062561035156250, -0.0043945312500000, -0.0056762695312500, +-0.0053405761718750, -0.0111083984375000, -0.0030517578125000, -0.0089721679687500, +-0.0039062500000000, -0.0130615234375000, -0.0032043457031250, -0.0191040039062500, +-0.0012207031250000, -0.0151672363281250, -0.0024719238281250, -0.0262451171875000, +0.0005187988281250, -0.0256652832031250, -0.0001525878906250, -0.0271911621093750, +0.0015869140625000, -0.0341491699218750, 0.0041198730468750, -0.0314025878906250, +0.0020141601562500, -0.0361022949218750, 0.0083923339843750, -0.0359497070312500, +0.0075378417968750, -0.0368041992187500, 0.0085449218750000, -0.0397033691406250, +0.0133056640625000, -0.0378112792968750, 0.0113525390625000, -0.0407104492187500, +0.0126342773437500, -0.0410766601562500, 0.0140380859375000, -0.0401611328125000, +0.0122375488281250, -0.0405578613281250, 0.0115966796875000, -0.0403137207031250, +0.0130615234375000, -0.0400390625000000, 0.0066223144531250, -0.0397033691406250, +0.0086059570312500, -0.0400390625000000, 0.0059814453125000, -0.0405578613281250, +0.0000000000000000, -0.0399780273437500, 0.0034484863281250, -0.0390625000000000, +-0.0029296875000000, -0.0398864746093750, -0.0026855468750000, -0.0382385253906250, +-0.0016479492187500, -0.0363159179687500, -0.0051879882812500, -0.0375671386718750, +-0.0043334960937500, -0.0339660644531250, 0.0002136230468750, -0.0344543457031250, +-0.0019531250000000, -0.0322570800781250, 0.0012207031250000, -0.0292053222656250, +0.0066833496093750, -0.0310668945312500, 0.0032958984375000, -0.0234069824218750, +0.0089721679687500, -0.0245971679687500, 0.0107727050781250, -0.0229797363281250, +0.0070190429687500, -0.0169372558593750, 0.0071411132812500, -0.0193176269531250, +0.0092163085937500, -0.0174560546875000, -0.0009765625000000, -0.0162658691406250, +0.0006103515625000, -0.0167846679687500, -0.0037841796875000, -0.0174255371093750, +-0.0133056640625000, -0.0172119140625000, -0.0085754394531250, -0.0145874023437500, +-0.0133361816406250, -0.0158386230468750, -0.0169067382812500, -0.0141906738281250, +-0.0129394531250000, -0.0107116699218750, -0.0099487304687500, -0.0122070312500000, +-0.0122070312500000, -0.0096740722656250, -0.0077819824218750, -0.0095825195312500, +-0.0060424804687500, -0.0082397460937500, -0.0085449218750000, -0.0066223144531250, +-0.0090637207031250, -0.0079650878906250, -0.0074768066406250, -0.0024108886718750, +-0.0118408203125000, -0.0022277832031250, -0.0113525390625000, -0.0037536621093750, +-0.0117797851562500, -0.0006713867187500, -0.0152282714843750, -0.0002441406250000, +-0.0141601562500000, -0.0097045898437500, -0.0120544433593750, -0.0062561035156250, +-0.0147094726562500, -0.0117492675781250, -0.0079650878906250, -0.0216979980468750, +-0.0023193359375000, -0.0159912109375000, -0.0086059570312500, -0.0289001464843750, +0.0090637207031250, -0.0291442871093750, 0.0112304687500000, -0.0289916992187500, +0.0070495605468750, -0.0356140136718750, 0.0133666992187500, -0.0341186523437500, +0.0133361816406250, -0.0360107421875000, -0.0035400390625000, -0.0354309082031250, +0.0032043457031250, -0.0371704101562500, -0.0039062500000000, -0.0409851074218750, +-0.0239562988281250, -0.0387268066406250, -0.0165100097656250, -0.0353088378906250, +-0.0189208984375000, -0.0401306152343750, -0.0230712890625000, -0.0327758789062500, +-0.0187072753906250, -0.0234069824218750, -0.0141601562500000, -0.0297241210937500, +-0.0178527832031250, -0.0155334472656250, -0.0173034667968750, -0.0155639648437500, +-0.0118713378906250, -0.0134277343750000, -0.0196533203125000, 0.0007019042968750, +-0.0356140136718750, 0.0013122558593750, -0.0221862792968750, 0.0028076171875000, +-0.0263366699218750, 0.0003662109375000, -0.0196228027343750, 0.0024719238281250, +-0.0314331054687500, 0.0077209472656250, -0.0419006347656250, 0.0057983398437500, +-0.0328063964843750, -0.0039978027343750, -0.0535888671875000, 0.0019226074218750, +-0.0558776855468750, -0.0057983398437500, -0.0522155761718750, -0.0209350585937500, +-0.0602722167968750, -0.0128479003906250, -0.0600891113281250, -0.0193176269531250, +-0.0479736328125000, -0.0265197753906250, -0.0509948730468750, -0.0176696777343750, +-0.0487976074218750, -0.0110778808593750, -0.0398559570312500, -0.0176086425781250, +-0.0426330566406250, -0.0003662109375000, -0.0352478027343750, 0.0014343261718750, +-0.0375061035156250, -0.0048828125000000, -0.0330200195312500, -0.0007934570312500, +-0.0255126953125000, 0.0022888183593750, -0.0303649902343750, -0.0071411132812500, +-0.0169372558593750, -0.0065002441406250, -0.0171508789062500, -0.0106811523437500, +-0.0174560546875000, -0.0168762207031250, -0.0100708007812500, -0.0120239257812500, +-0.0111694335937500, -0.0261230468750000, -0.0114440917968750, -0.0267639160156250, +-0.0127258300781250, -0.0237426757812500, -0.0077514648437500, -0.0294494628906250, +-0.0043945312500000, -0.0307617187500000, -0.0086059570312500, -0.0248107910156250, +0.0042724609375000, -0.0225830078125000, 0.0051269531250000, -0.0265502929687500, +0.0030212402343750, -0.0292053222656250, 0.0085144042968750, -0.0260620117187500, +0.0085449218750000, -0.0247497558593750, 0.0010070800781250, -0.0291137695312500, +0.0032043457031250, -0.0222778320312500, 0.0004272460937500, -0.0151977539062500, +-0.0061340332031250, -0.0209350585937500, -0.0031127929687500, -0.0046386718750000, +-0.0099182128906250, -0.0056762695312500, -0.0086669921875000, -0.0050659179687500, +-0.0119628906250000, 0.0051269531250000, -0.0179138183593750, 0.0015563964843750, +-0.0140075683593750, -0.0005493164062500, -0.0234680175781250, 0.0035705566406250, +-0.0237121582031250, -0.0007019042968750, -0.0230407714843750, -0.0074157714843750, +-0.0272827148437500, -0.0031127929687500, -0.0261535644531250, -0.0070190429687500, +-0.0254821777343750, -0.0092468261718750, -0.0249023437500000, -0.0064697265625000, +-0.0267333984375000, -0.0053405761718750, -0.0273742675781250, -0.0067443847656250, +-0.0255737304687500, -0.0017395019531250, -0.0331420898437500, -0.0031738281250000, +-0.0317382812500000, 0.0002746582031250, -0.0336608886718750, 0.0048828125000000, +-0.0394897460937500, 0.0010986328125000, -0.0368041992187500, 0.0126647949218750, +-0.0422668457031250, 0.0115051269531250, -0.0418395996093750, 0.0122680664062500, +-0.0427856445312500, 0.0199279785156250, -0.0467224121093750, 0.0169372558593750, +-0.0447692871093750, 0.0162048339843750, -0.0458984375000000, 0.0191650390625000, +-0.0477600097656250, 0.0146179199218750, -0.0449829101562500, 0.0101623535156250, +-0.0426940917968750, 0.0139160156250000, -0.0447692871093750, 0.0036926269531250, +-0.0388488769531250, 0.0052185058593750, -0.0391845703125000, 0.0024108886718750, +-0.0383300781250000, -0.0047607421875000, -0.0347900390625000, -0.0002746582031250, +-0.0365600585937500, -0.0092773437500000, -0.0336303710937500, -0.0083923339843750, +-0.0336914062500000, -0.0096130371093750, -0.0339660644531250, -0.0152587890625000, +-0.0330810546875000, -0.0120239257812500, -0.0338439941406250, -0.0169372558593750, +-0.0316467285156250, -0.0169372558593750, -0.0339660644531250, -0.0166015625000000, +-0.0298767089843750, -0.0190429687500000, -0.0255737304687500, -0.0181579589843750, +-0.0293579101562500, -0.0184936523437500, -0.0166625976562500, -0.0190429687500000, +-0.0175781250000000, -0.0188293457031250, -0.0153808593750000, -0.0186462402343750, +-0.0066223144531250, -0.0191040039062500, -0.0095214843750000, -0.0194396972656250, +-0.0046691894531250, -0.0195617675781250, -0.0040283203125000, -0.0200805664062500, +-0.0033569335937500, -0.0206604003906250, -0.0007324218750000, -0.0210266113281250, +-0.0018920898437500, -0.0221557617187500, -0.0008239746093750, -0.0222167968750000, +0.0004882812500000, -0.0234069824218750, -0.0021667480468750, -0.0246887207031250, +-0.0035705566406250, -0.0245361328125000, -0.0018005371093750, -0.0277709960937500, +-0.0097656250000000, -0.0276489257812500, -0.0083923339843750, -0.0293273925781250, +-0.0111389160156250, -0.0322570800781250, -0.0179138183593750, -0.0311889648437500, +-0.0149841308593750, -0.0338745117187500, -0.0212097167968750, -0.0346679687500000, +-0.0214538574218750, -0.0339355468750000, -0.0227966308593750, -0.0346374511718750, +-0.0261230468750000, -0.0348815917968750, -0.0245361328125000, -0.0323486328125000, +-0.0314636230468750, -0.0336914062500000, -0.0294799804687500, -0.0306396484375000, +-0.0324096679687500, -0.0275573730468750, -0.0391540527343750, -0.0300598144531250, +-0.0354003906250000, -0.0191955566406250, -0.0415649414062500, -0.0216979980468750, +-0.0423889160156250, -0.0178527832031250, -0.0422058105468750, -0.0084533691406250, +-0.0450744628906250, -0.0131835937500000, -0.0445556640625000, -0.0037231445312500, +-0.0441589355468750, -0.0037841796875000, -0.0463256835937500, -0.0028686523437500, +-0.0427246093750000, 0.0025329589843750, -0.0395202636718750, 0.0000000000000000, +-0.0430297851562500, 0.0030517578125000, -0.0334167480468750, 0.0036926269531250, +-0.0335998535156250, 0.0027770996093750, -0.0328979492187500, 0.0034484863281250, +-0.0273132324218750}, +{-0.0229187011718750, -0.0007934570312500, -0.0294799804687500, -0.0076293945312500, +-0.0254516601562500, 0.0092163085937500, -0.0334777832031250, 0.0088195800781250, +-0.0341796875000000, 0.0093078613281250, -0.0331115722656250, 0.0181579589843750, +-0.0359802246093750, 0.0146484375000000, -0.0354003906250000, 0.0184631347656250, +-0.0344848632812500, 0.0198059082031250, -0.0341796875000000, 0.0169677734375000, +-0.0348205566406250, 0.0176696777343750, -0.0349426269531250, 0.0189514160156250, +-0.0342407226562500, 0.0083007812500000, -0.0355224609375000, 0.0114135742187500, +-0.0357055664062500, 0.0069580078125000, -0.0350952148437500, -0.0029907226562500, +-0.0351257324218750, 0.0026855468750000, -0.0353393554687500, -0.0066528320312500, +-0.0346679687500000, -0.0075683593750000, -0.0348510742187500, -0.0063781738281250, +-0.0339965820312500, -0.0103759765625000, -0.0335388183593750, -0.0097351074218750, +-0.0342407226562500, -0.0072631835937500, -0.0298767089843750, -0.0093688964843750, +-0.0311279296875000, -0.0066528320312500, -0.0298461914062500, -0.0033874511718750, +-0.0260620117187500, -0.0066528320312500, -0.0280456542968750, 0.0017395019531250, +-0.0263671875000000, -0.0004577636718750, -0.0263977050781250, 0.0020446777343750, +-0.0260009765625000, 0.0084838867187500, -0.0254516601562500, 0.0039978027343750, +-0.0266723632812500, 0.0129699707031250, -0.0223693847656250, 0.0116271972656250, +-0.0230407714843750, 0.0124816894531250, -0.0223693847656250, 0.0182800292968750, +-0.0193481445312500, 0.0151367187500000, -0.0204162597656250, 0.0184020996093750, +-0.0184020996093750, 0.0186462402343750, -0.0189819335937500, 0.0176696777343750, +-0.0170288085937500, 0.0184631347656250, -0.0144348144531250, 0.0178833007812500, +-0.0161437988281250, 0.0168151855468750, -0.0104064941406250, 0.0170593261718750, +-0.0101623535156250, 0.0156555175781250, -0.0105285644531250, 0.0143432617187500, +-0.0077819824218750, 0.0149230957031250, -0.0081481933593750, 0.0115356445312500, +-0.0102233886718750, 0.0123596191406250, -0.0096435546875000, 0.0102233886718750, +-0.0100402832031250, 0.0068969726562500, -0.0119323730468750, 0.0089111328125000, +-0.0115966796875000, 0.0030212402343750, -0.0109863281250000, 0.0036621093750000, +-0.0116577148437500, 0.0021057128906250, -0.0113525390625000, -0.0024108886718750, +-0.0101013183593750, -0.0009765625000000, -0.0107116699218750, -0.0056152343750000, +-0.0124206542968750, -0.0057373046875000, -0.0104675292968750, -0.0072326660156250, +-0.0138244628906250, -0.0109252929687500, -0.0175781250000000, -0.0099487304687500, +-0.0146484375000000, -0.0123901367187500, -0.0228576660156250, -0.0137329101562500, +-0.0224914550781250, -0.0132751464843750, -0.0231933593750000, -0.0137023925781250, +-0.0280151367187500, -0.0150756835937500, -0.0264282226562500, -0.0147399902343750, +-0.0292968750000000, -0.0151062011718750, -0.0301208496093750, -0.0151672363281250, +-0.0295715332031250, -0.0154113769531250, -0.0307006835937500, -0.0162048339843750, +-0.0314025878906250, -0.0135192871093750, -0.0287170410156250, -0.0146484375000000, +-0.0290832519531250, -0.0132446289062500, -0.0292053222656250, -0.0100402832031250, +-0.0273742675781250, -0.0115051269531250, -0.0273742675781250, -0.0080261230468750, +-0.0287780761718750, -0.0079956054687500, -0.0279235839843750, -0.0064392089843750, +-0.0278930664062500, -0.0039367675781250, -0.0287170410156250, -0.0050354003906250, +-0.0280456542968750, 0.0001525878906250, -0.0289306640625000, -0.0003356933593750, +-0.0290527343750000, 0.0010681152343750, -0.0282287597656250, 0.0050354003906250, +-0.0284729003906250, 0.0031127929687500, -0.0291137695312500, 0.0050964355468750, +-0.0267028808593750, 0.0062866210937500, -0.0260009765625000, 0.0045471191406250, +-0.0286560058593750, 0.0037841796875000, -0.0287170410156250, 0.0050048828125000, +-0.0266418457031250, 0.0019531250000000, -0.0346984863281250, 0.0025634765625000, +-0.0333862304687500, 0.0015869140625000, -0.0334777832031250, -0.0006103515625000, +-0.0395507812500000, 0.0009460449218750, -0.0371093750000000, -0.0022583007812500, +-0.0306701660156250, -0.0013732910156250, -0.0359191894531250, -0.0036010742187500, +-0.0273132324218750, -0.0071105957031250, -0.0162048339843750, -0.0045166015625000, +-0.0238647460937500, -0.0088806152343750, -0.0033264160156250, -0.0100097656250000, +-0.0032958984375000, -0.0089111328125000, -0.0070190429687500, -0.0096435546875000, +0.0030517578125000, -0.0095214843750000, 0.0035705566406250, -0.0078125000000000, +-0.0072326660156250, -0.0086059570312500, -0.0072631835937500, -0.0070495605468750, +-0.0044555664062500, -0.0039978027343750, -0.0081176757812500, -0.0054931640625000, +-0.0092773437500000, -0.0065307617187500, -0.0032043457031250, -0.0050048828125000, +-0.0052490234375000, -0.0058288574218750, -0.0028381347656250, -0.0079956054687500, +0.0040283203125000, -0.0075073242187500, 0.0006713867187500, -0.0093994140625000, +0.0000610351562500, -0.0101318359375000, 0.0032043457031250, -0.0075683593750000, +0.0001525878906250, -0.0073242187500000, -0.0057067871093750, -0.0096130371093750, +-0.0027160644531250, -0.0018615722656250, 0.0020141601562500, -0.0026550292968750, +-0.0028076171875000, -0.0022583007812500, 0.0003051757812500, 0.0028991699218750, +0.0086975097656250, 0.0007019042968750, 0.0057373046875000, -0.0028381347656250, +0.0088195800781250, -0.0004577636718750, 0.0102233886718750, -0.0033874511718750, +0.0076904296875000, -0.0105895996093750, 0.0062561035156250, -0.0103149414062500, +0.0063781738281250, -0.0107421875000000, 0.0031127929687500, -0.0120239257812500, +0.0039367675781250, -0.0105285644531250, 0.0031127929687500, -0.0088806152343750, +0.0006103515625000, -0.0103759765625000, 0.0016784667968750, -0.0089111328125000, +-0.0011596679687500, -0.0070495605468750, -0.0013732910156250, -0.0085754394531250, +-0.0015563964843750, -0.0108947753906250, -0.0032958984375000, -0.0087585449218750, +-0.0031433105468750, -0.0048217773437500, -0.0033569335937500, -0.0094299316406250, +-0.0024108886718750, -0.0037536621093750, -0.0047607421875000, 0.0070190429687500, +-0.0073242187500000, 0.0015869140625000, -0.0055847167968750, 0.0011291503906250, +-0.0082397460937500, 0.0072937011718750, -0.0090942382812500, -0.0002746582031250, +-0.0080871582031250, -0.0100097656250000, -0.0091552734375000, -0.0030517578125000, +-0.0093994140625000, -0.0107727050781250, -0.0026855468750000, -0.0144958496093750, +-0.0042419433593750, -0.0105895996093750, -0.0030212402343750, -0.0096435546875000, +0.0028076171875000, -0.0113525390625000, 0.0008850097656250, -0.0041198730468750, +0.0003662109375000, -0.0053710937500000, 0.0030822753906250, -0.0044860839843750, +0.0003967285156250, 0.0012512207031250, -0.0040893554687500, -0.0004882812500000, +-0.0012207031250000, -0.0009460449218750, -0.0008239746093750, 0.0014648437500000, +-0.0030212402343750, -0.0027770996093750, -0.0001525878906250, -0.0065917968750000, +0.0033264160156250, -0.0028381347656250, 0.0017395019531250, -0.0119934082031250, +0.0086669921875000, -0.0119934082031250, 0.0084533691406250, -0.0131835937500000, +0.0086364746093750, -0.0180969238281250, 0.0131225585937500, -0.0160217285156250, +0.0123901367187500, -0.0213317871093750, 0.0101928710937500, -0.0208435058593750, +0.0115356445312500, -0.0226440429687500, 0.0106506347656250, -0.0267333984375000, +0.0080566406250000, -0.0246276855468750, 0.0094299316406250, -0.0297851562500000, +0.0097656250000000, -0.0301818847656250, 0.0095214843750000, -0.0294494628906250, +0.0093994140625000, -0.0318908691406250, 0.0104064941406250, -0.0317687988281250, +0.0109252929687500, -0.0282897949218750, 0.0061645507812500, -0.0299987792968750, +0.0080261230468750, -0.0277099609375000, 0.0047912597656250, -0.0231628417968750, +-0.0007934570312500, -0.0257873535156250, 0.0020141601562500, -0.0230102539062500, +-0.0064392089843750, -0.0205078125000000, -0.0062561035156250, -0.0242919921875000, +-0.0076293945312500, -0.0262451171875000, -0.0131225585937500, -0.0227050781250000, +-0.0110168457031250, -0.0311279296875000, -0.0129089355468750, -0.0307922363281250, +-0.0143432617187500, -0.0294799804687500, -0.0123291015625000, -0.0333862304687500, +-0.0115966796875000, -0.0321655273437500, -0.0126342773437500, -0.0285949707031250, +-0.0063171386718750, -0.0299072265625000, -0.0075073242187500, -0.0273437500000000, +-0.0046081542968750, -0.0231933593750000, 0.0013427734375000, -0.0248107910156250, +-0.0010070800781250, -0.0191040039062500, 0.0052185058593750, -0.0195312500000000, +0.0056762695312500, -0.0175476074218750, 0.0060729980468750, -0.0130920410156250, +0.0091552734375000, -0.0151062011718750, 0.0083312988281250, -0.0105895996093750, +0.0101318359375000, -0.0096435546875000, 0.0099792480468750, -0.0103149414062500, +0.0104370117187500, -0.0088195800781250, 0.0114135742187500, -0.0085754394531250, +0.0102844238281250, -0.0106201171875000, 0.0124816894531250, -0.0098876953125000, +0.0114746093750000, -0.0108947753906250, 0.0119018554687500, -0.0129394531250000, +0.0136108398437500, -0.0119018554687500, 0.0119323730468750, -0.0149230957031250, +0.0132141113281250, -0.0146179199218750, 0.0122985839843750, -0.0160522460937500, +0.0120239257812500, -0.0186157226562500, 0.0126037597656250, -0.0172424316406250, +0.0112304687500000, -0.0210571289062500, 0.0125427246093750, -0.0213623046875000, +0.0118713378906250, -0.0213623046875000, 0.0119323730468750, -0.0233459472656250, +0.0128479003906250, -0.0233459472656250, 0.0119934082031250, -0.0230102539062500, +0.0132751464843750, -0.0236816406250000, 0.0125732421875000, -0.0235290527343750, +0.0130920410156250, -0.0228576660156250, 0.0141906738281250, -0.0232849121093750, +0.0130004882812500, -0.0225830078125000, 0.0154418945312500, -0.0230712890625000, +0.0149536132812500, -0.0217285156250000, 0.0153198242187500, -0.0203552246093750, +0.0170288085937500, -0.0213012695312500, 0.0158386230468750, -0.0169372558593750, +0.0169372558593750, -0.0167846679687500, 0.0177917480468750, -0.0165100097656250, +0.0158386230468750, -0.0136108398437500, 0.0152282714843750, -0.0135498046875000, +0.0164489746093750, -0.0146789550781250, 0.0099182128906250, -0.0134582519531250, +0.0115661621093750, -0.0137329101562500, 0.0089111328125000, -0.0148315429687500, +0.0032043457031250, -0.0137634277343750, 0.0066223144531250, -0.0159606933593750, +0.0004577636718750, -0.0150146484375000, -0.0003356933593750, -0.0164184570312500, +0.0005187988281250, -0.0189208984375000, -0.0017700195312500, -0.0168762207031250, +-0.0015869140625000, -0.0199890136718750, -0.0004577636718750, -0.0201721191406250, +-0.0014953613281250, -0.0198364257812500, 0.0008850097656250, -0.0206604003906250, +0.0030212402343750, -0.0202636718750000, 0.0008239746093750, -0.0223083496093750, +0.0080261230468750, -0.0207824707031250, 0.0075073242187500, -0.0233764648437500, +0.0083007812500000, -0.0269775390625000, 0.0133666992187500, -0.0243530273437500, +0.0113525390625000, -0.0304260253906250, 0.0098266601562500, -0.0304565429687500, +0.0126037597656250, -0.0304260253906250, 0.0086669921875000, -0.0333251953125000, +0.0034484863281250, -0.0322875976562500, 0.0063476562500000, -0.0335998535156250, +-0.0002136230468750, -0.0335388183593750, -0.0007324218750000, -0.0333251953125000, +-0.0013122558593750, -0.0343017578125000, -0.0049438476562500, -0.0337524414062500, +-0.0034790039062500, -0.0308532714843750, -0.0036926269531250, -0.0325012207031250, +-0.0044250488281250, -0.0299682617187500, -0.0042114257812500, -0.0251770019531250, +-0.0032348632812500, -0.0276489257812500, -0.0031433105468750, -0.0264587402343750, +-0.0052795410156250}, +{0.0012512207031250, -0.0181579589843750, -0.0003967285156250, -0.0191955566406250, +0.0003967285156250, -0.0162353515625000, -0.0012207031250000, -0.0157165527343750, +-0.0037536621093750, -0.0167236328125000, -0.0028991699218750, -0.0114440917968750, +-0.0069274902343750, -0.0113525390625000, -0.0073242187500000, -0.0106506347656250, +-0.0083923339843750, -0.0075378417968750, -0.0112609863281250, -0.0083312988281250, +-0.0107727050781250, -0.0070800781250000, -0.0120544433593750, -0.0064697265625000, +-0.0128479003906250, -0.0072631835937500, -0.0125732421875000, -0.0072021484375000, +-0.0126342773437500, -0.0068054199218750, -0.0131530761718750, -0.0100708007812500, +-0.0122070312500000, -0.0088195800781250, -0.0125732421875000, -0.0113220214843750, +-0.0120544433593750, -0.0151062011718750, -0.0113525390625000, -0.0127258300781250, +-0.0120239257812500, -0.0191040039062500, -0.0091247558593750, -0.0188598632812500, +-0.0098266601562500, -0.0201110839843750, -0.0088806152343750, -0.0242309570312500, +-0.0062561035156250, -0.0224609375000000, -0.0075988769531250, -0.0258483886718750, +-0.0056762695312500, -0.0263977050781250, -0.0052490234375000, -0.0260314941406250, +-0.0057373046875000, -0.0275573730468750, -0.0053100585937500, -0.0275268554687500, +-0.0055847167968750, -0.0257263183593750, -0.0065307617187500, -0.0272216796875000, +-0.0062866210937500, -0.0246276855468750, -0.0070495605468750, -0.0217895507812500, +-0.0081481933593750, -0.0242614746093750, -0.0074768066406250, -0.0158996582031250, +-0.0089416503906250, -0.0171813964843750, -0.0091552734375000, -0.0149841308593750, +-0.0092163085937500, -0.0083618164062500, -0.0100708007812500, -0.0111083984375000, +-0.0099487304687500, -0.0066528320312500, -0.0091552734375000, -0.0056152343750000, +-0.0103454589843750, -0.0061645507812500, -0.0085449218750000, -0.0046081542968750, +-0.0069274902343750, -0.0044860839843750, -0.0089111328125000, -0.0055541992187500, +-0.0024719238281250, -0.0043029785156250, -0.0044250488281250, -0.0053710937500000, +-0.0024108886718750, -0.0071411132812500, 0.0027465820312500, -0.0055541992187500, +-0.0009460449218750, -0.0083618164062500, 0.0050354003906250, -0.0083923339843750, +0.0051574707031250, -0.0081481933593750, 0.0050964355468750, -0.0089416503906250, +0.0080871582031250, -0.0084533691406250, 0.0068359375000000, -0.0107727050781250, +0.0076599121093750, -0.0089721679687500, 0.0086975097656250, -0.0121765136718750, +0.0056762695312500, -0.0160217285156250, 0.0040283203125000, -0.0129394531250000, +0.0061950683593750, -0.0216979980468750, -0.0011901855468750, -0.0209045410156250, +-0.0007324218750000, -0.0225219726562500, -0.0011901855468750, -0.0282287597656250, +-0.0057983398437500, -0.0255737304687500, -0.0039367675781250, -0.0313720703125000, +-0.0035400390625000, -0.0305480957031250, -0.0051879882812500, -0.0323486328125000, +-0.0031738281250000, -0.0371398925781250, -0.0003356933593750, -0.0344238281250000, +-0.0014038085937500, -0.0379333496093750, 0.0017395019531250, -0.0393371582031250, +0.0014953613281250, -0.0370788574218750, 0.0022583007812500, -0.0364990234375000, +0.0048522949218750, -0.0377502441406250, 0.0036010742187500, -0.0351257324218750, +0.0028076171875000, -0.0337219238281250, 0.0042114257812500, -0.0364990234375000, +0.0016174316406250, -0.0376281738281250, -0.0011901855468750, -0.0354919433593750, +0.0004882812500000, -0.0411376953125000, -0.0056762695312500, -0.0424804687500000, +-0.0054931640625000, -0.0389404296875000, -0.0063476562500000, -0.0395507812500000, +-0.0102233886718750, -0.0415344238281250, -0.0083923339843750, -0.0306396484375000, +-0.0088195800781250, -0.0322570800781250, -0.0103454589843750, -0.0297546386718750, +-0.0094299316406250, -0.0224609375000000, -0.0076904296875000, -0.0255432128906250, +-0.0080871582031250, -0.0157775878906250, -0.0082702636718750, -0.0185852050781250, +-0.0080871582031250, -0.0128784179687500, -0.0079650878906250, -0.0017700195312500, +-0.0092163085937500, -0.0081176757812500, -0.0089721679687500, 0.0003967285156250, +-0.0015563964843750, 0.0028076171875000, -0.0034179687500000, 0.0015563964843750, +-0.0027160644531250, 0.0029907226562500, 0.0018615722656250, 0.0025634765625000, +0.0011291503906250, 0.0041503906250000, 0.0093383789062500, 0.0028991699218750, +0.0078735351562500, 0.0061645507812500, 0.0072937011718750, 0.0088500976562500, +0.0134582519531250, 0.0056457519531250, 0.0128173828125000, 0.0165710449218750, +0.0069580078125000, 0.0169677734375000, 0.0103454589843750, 0.0136108398437500, +0.0058898925781250, 0.0183715820312500, -0.0044250488281250, 0.0194702148437500, +0.0003662109375000, 0.0059814453125000, 0.0065917968750000, 0.0076293945312500, +0.0009155273437500, 0.0083007812500000, 0.0040283203125000, -0.0026550292968750, +0.0187683105468750, 0.0159912109375000, 0.0062866210937500, 0.0227661132812500, +0.0164794921875000, 0.0279235839843750, 0.0126953125000000, 0.0184020996093750, +0.0126037597656250, 0.0112609863281250, 0.0191955566406250, 0.0183410644531250, +0.0193786621093750, 0.0044555664062500, 0.0074462890625000, 0.0028686523437500, +0.0115051269531250, 0.0035095214843750, 0.0049438476562500, -0.0021057128906250, +-0.0076599121093750, -0.0006408691406250, -0.0006103515625000, -0.0007324218750000, +-0.0123291015625000, -0.0004272460937500, -0.0151367187500000, -0.0028991699218750, +-0.0130920410156250, -0.0033569335937500, -0.0143432617187500, -0.0016784667968750, +-0.0144348144531250, -0.0155334472656250, -0.0213623046875000, -0.0103149414062500, +-0.0181274414062500, -0.0156555175781250, -0.0207214355468750, -0.0315856933593750, +-0.0300903320312500, -0.0248107910156250, -0.0267944335937500, -0.0251770019531250, +-0.0213623046875000, -0.0303955078125000, -0.0264892578125000, -0.0245361328125000, +-0.0215454101562500, -0.0184326171875000, -0.0109558105468750, -0.0229187011718750, +-0.0155944824218750, -0.0103759765625000, -0.0142822265625000, -0.0118103027343750, +-0.0106506347656250, -0.0089416503906250, -0.0148620605468750, 0.0008239746093750, +-0.0193176269531250, -0.0037231445312500, -0.0162353515625000, -0.0017089843750000, +-0.0223388671875000, 0.0000610351562500, -0.0236511230468750, 0.0021057128906250, +-0.0211181640625000, 0.0024108886718750, -0.0220031738281250, -0.0000610351562500, +-0.0232543945312500, 0.0071716308593750, -0.0178527832031250, 0.0074462890625000, +-0.0177612304687500, 0.0080261230468750, -0.0181579589843750, 0.0111999511718750, +-0.0158081054687500, 0.0091857910156250, -0.0160217285156250, 0.0124511718750000, +-0.0164184570312500, 0.0138549804687500, -0.0166320800781250, 0.0102539062500000, +-0.0155334472656250, 0.0099487304687500, -0.0146484375000000, 0.0126342773437500, +-0.0153198242187500, 0.0013427734375000, -0.0139465332031250, 0.0031738281250000, +-0.0130310058593750, 0.0024719238281250, -0.0144653320312500, -0.0057373046875000, +-0.0151367187500000, -0.0032043457031250, -0.0141296386718750, -0.0013427734375000, +-0.0170898437500000, -0.0043640136718750, -0.0171508789062500, -0.0016784667968750, +-0.0172424316406250, 0.0022277832031250, -0.0187072753906250, -0.0005187988281250, +-0.0183410644531250, 0.0064086914062500, -0.0190429687500000, 0.0051269531250000, +-0.0193176269531250, 0.0066833496093750, -0.0184020996093750, 0.0126647949218750, +-0.0186157226562500, 0.0096130371093750, -0.0191345214843750, 0.0098266601562500, +-0.0141601562500000, 0.0128173828125000, -0.0153198242187500, 0.0083923339843750, +-0.0137634277343750, 0.0043334960937500, -0.0091552734375000, 0.0081481933593750, +-0.0111389160156250, -0.0008850097656250, -0.0105285644531250, -0.0000305175781250, +-0.0092468261718750, -0.0006103515625000, -0.0109252929687500, -0.0061340332031250, +-0.0128479003906250, -0.0035400390625000, -0.0119323730468750, -0.0053710937500000, +-0.0133361816406250, -0.0063781738281250, -0.0138854980468750, -0.0048522949218750, +-0.0135803222656250, -0.0044860839843750, -0.0134887695312500, -0.0052185058593750, +-0.0134582519531250, -0.0023498535156250, -0.0139465332031250, -0.0028686523437500, +-0.0134277343750000, -0.0021667480468750, -0.0137634277343750, -0.0003662109375000, +-0.0143432617187500, -0.0016784667968750, -0.0138244628906250, 0.0010070800781250, +-0.0151977539062500, 0.0000000000000000, -0.0144958496093750, 0.0004577636718750, +-0.0156555175781250, 0.0025329589843750, -0.0173645019531250, 0.0009765625000000, +-0.0161743164062500, 0.0029907226562500, -0.0198059082031250, 0.0026855468750000, +-0.0193786621093750, 0.0024108886718750, -0.0208129882812500, 0.0032043457031250, +-0.0239257812500000, 0.0021667480468750, -0.0225830078125000, 0.0023193359375000, +-0.0256958007812500, 0.0019226074218750, -0.0268859863281250, 0.0013122558593750, +-0.0256042480468750, 0.0010070800781250, -0.0264282226562500, 0.0004577636718750, +-0.0274658203125000, -0.0001831054687500, -0.0221252441406250, -0.0004882812500000, +-0.0237121582031250, -0.0014648437500000, -0.0216369628906250, -0.0021972656250000, +-0.0164489746093750, -0.0024108886718750, -0.0189208984375000, -0.0044250488281250, +-0.0151672363281250, -0.0049743652343750, -0.0142517089843750, -0.0058288574218750, +-0.0146484375000000, -0.0074462890625000, -0.0138854980468750, -0.0080566406250000, +-0.0138244628906250, -0.0089416503906250, -0.0120849609375000, -0.0093383789062500, +-0.0132446289062500, -0.0104675292968750, -0.0111999511718750, -0.0113830566406250, +-0.0085449218750000, -0.0115356445312500, -0.0108337402343750, -0.0144348144531250, +-0.0055541992187500, -0.0140686035156250, -0.0065917968750000, -0.0150146484375000, +-0.0052795410156250, -0.0176086425781250, -0.0011291503906250, -0.0169677734375000, +-0.0035705566406250, -0.0182800292968750, -0.0010681152343750, -0.0187377929687500, +0.0007019042968750, -0.0183105468750000, -0.0018005371093750, -0.0186157226562500, +-0.0026855468750000, -0.0186462402343750, -0.0008239746093750, -0.0157775878906250, +-0.0069580078125000, -0.0169372558593750, -0.0049743652343750, -0.0138244628906250, +-0.0081787109375000, -0.0098266601562500, -0.0137939453125000, -0.0121154785156250, +-0.0096740722656250, -0.0046386718750000, -0.0199584960937500, -0.0051574707031250, +-0.0196533203125000, -0.0036926269531250, -0.0202941894531250, 0.0015258789062500, +-0.0259704589843750, -0.0007629394531250, -0.0245056152343750, 0.0015869140625000, +-0.0292663574218750, 0.0031433105468750, -0.0275878906250000, 0.0007324218750000, +-0.0316467285156250, -0.0003662109375000, -0.0377502441406250, 0.0010986328125000, +-0.0335388183593750, -0.0043029785156250, -0.0411987304687500, -0.0042724609375000, +-0.0424194335937500, -0.0036926269531250, -0.0404052734375000, -0.0068054199218750, +-0.0428161621093750, -0.0065002441406250, -0.0426330566406250, -0.0015258789062500, +-0.0361328125000000, -0.0038452148437500, -0.0394897460937500, -0.0003051757812500, +-0.0347595214843750, 0.0060424804687500, -0.0265502929687500, 0.0025939941406250, +-0.0315246582031250, 0.0090332031250000, -0.0222167968750000, 0.0098571777343750, +-0.0222473144531250, 0.0095825195312500, -0.0220336914062500, 0.0123291015625000, +-0.0166931152343750, 0.0112304687500000, -0.0186462402343750, 0.0099487304687500, +-0.0190429687500000, 0.0122070312500000, -0.0191040039062500, 0.0082702636718750, +-0.0161743164062500, 0.0035095214843750, -0.0150756835937500, 0.0069580078125000, +-0.0181579589843750, 0.0014038085937500, -0.0111083984375000, -0.0000915527343750, +-0.0119934082031250, 0.0009460449218750, -0.0081176757812500, 0.0005187988281250, +-0.0025634765625000, 0.0003662109375000, -0.0069580078125000, -0.0020446777343750, +0.0043334960937500, -0.0005798339843750, 0.0029602050781250, -0.0033264160156250, +0.0062561035156250}, +{-0.0165710449218750, 0.0035400390625000, -0.0169982910156250, 0.0000305175781250, +-0.0187377929687500, 0.0025939941406250, -0.0180358886718750, -0.0016174316406250, +-0.0209960937500000, -0.0010070800781250, -0.0206909179687500, -0.0011291503906250, +-0.0217895507812500, -0.0033874511718750, -0.0246276855468750, -0.0014648437500000, +-0.0239562988281250, -0.0033264160156250, -0.0245361328125000, -0.0025329589843750, +-0.0258178710937500, -0.0025939941406250, -0.0248107910156250, -0.0039367675781250, +-0.0236816406250000, -0.0025329589843750, -0.0246582031250000, -0.0041198730468750, +-0.0224609375000000, -0.0040283203125000, -0.0225830078125000, -0.0033874511718750, +-0.0219116210937500, -0.0038757324218750, -0.0206298828125000, -0.0034790039062500, +-0.0211791992187500, -0.0018615722656250, -0.0176086425781250, -0.0020751953125000, +-0.0188903808593750, -0.0006103515625000, -0.0164184570312500, 0.0014953613281250, +-0.0124206542968750, 0.0009460449218750, -0.0148925781250000, 0.0029602050781250, +-0.0095520019531250, 0.0035095214843750, -0.0099792480468750, 0.0033569335937500, +-0.0090026855468750, 0.0040893554687500, -0.0059814453125000, 0.0041503906250000, +-0.0080566406250000, 0.0032958984375000, -0.0023193359375000, 0.0038146972656250, +-0.0032348632812500, 0.0025024414062500, -0.0018615722656250, 0.0013427734375000, +0.0029602050781250, 0.0024108886718750, 0.0010681152343750, -0.0022277832031250, +0.0033569335937500, -0.0013122558593750, 0.0049133300781250, -0.0027770996093750, +0.0033264160156250, -0.0066833496093750, 0.0035400390625000, -0.0051879882812500, +0.0048828125000000, -0.0087890625000000, -0.0026245117187500, -0.0090942382812500, +0.0002746582031250, -0.0100402832031250, -0.0035705566406250, -0.0125427246093750, +-0.0119323730468750, -0.0119018554687500, -0.0077209472656250, -0.0139770507812500, +-0.0151977539062500, -0.0142822265625000, -0.0156860351562500, -0.0140991210937500, +-0.0178833007812500, -0.0150146484375000, -0.0219726562500000, -0.0146789550781250, +-0.0192565917968750, -0.0123901367187500, -0.0283813476562500, -0.0134582519531250, +-0.0279541015625000, -0.0109863281250000, -0.0282897949218750, -0.0075073242187500, +-0.0335083007812500, -0.0091552734375000, -0.0319519042968750, -0.0036010742187500, +-0.0333862304687500, -0.0036315917968750, -0.0337829589843750, -0.0033569335937500, +-0.0323486328125000, -0.0002136230468750, -0.0328674316406250, -0.0012512207031250, +-0.0338439941406250, -0.0012512207031250, -0.0281066894531250, -0.0013122558593750, +-0.0295715332031250, -0.0008544921875000, -0.0281066894531250, -0.0010681152343750, +-0.0237731933593750, -0.0017089843750000, -0.0260314941406250, 0.0019836425781250, +-0.0199890136718750, 0.0005187988281250, -0.0201416015625000, 0.0022277832031250, +-0.0220947265625000, 0.0058288574218750, -0.0197753906250000, 0.0037841796875000, +-0.0187377929687500, 0.0096130371093750, -0.0211791992187500, 0.0089721679687500, +-0.0225830078125000, 0.0090942382812500, -0.0204162597656250, 0.0133666992187500, +-0.0202331542968750, 0.0119934082031250, -0.0211181640625000, 0.0086669921875000, +-0.0102233886718750, 0.0105590820312500, -0.0146789550781250, 0.0083007812500000, +-0.0082702636718750, 0.0036315917968750, 0.0039062500000000, 0.0054626464843750, +-0.0029602050781250, 0.0029602050781250, 0.0115661621093750, 0.0028381347656250, +0.0122680664062500, 0.0019531250000000, 0.0109252929687500, 0.0005798339843750, +0.0174865722656250, 0.0015869140625000, 0.0163574218750000, -0.0039367675781250, +0.0155639648437500, -0.0018310546875000, 0.0173645019531250, -0.0044555664062500, +0.0142211914062500, -0.0108337402343750, 0.0112304687500000, -0.0077819824218750, +0.0140991210937500, -0.0116577148437500, 0.0065002441406250, -0.0133056640625000, +0.0079956054687500, -0.0100097656250000, 0.0055541992187500, -0.0090637207031250, +-0.0017089843750000, -0.0110778808593750, 0.0014038085937500, -0.0046081542968750, +0.0003051757812500, -0.0039062500000000, -0.0013427734375000, -0.0039978027343750, +-0.0006408691406250, -0.0015258789062500, 0.0011291503906250, -0.0014038085937500, +0.0008239746093750, 0.0013427734375000, -0.0032653808593750, 0.0008239746093750, +-0.0006713867187500, 0.0013122558593750, -0.0020446777343750, 0.0028991699218750, +-0.0065917968750000, 0.0021057128906250, -0.0044555664062500, 0.0058288574218750, +-0.0086059570312500, 0.0044860839843750, -0.0086975097656250, 0.0067749023437500, +-0.0076904296875000, 0.0106506347656250, -0.0093383789062500, 0.0077819824218750, +-0.0092468261718750, 0.0128479003906250, -0.0076904296875000, 0.0137634277343750, +-0.0081176757812500, 0.0118713378906250, -0.0055847167968750, 0.0128479003906250, +-0.0031433105468750, 0.0136413574218750, -0.0051879882812500, 0.0101318359375000, +-0.0011596679687500, 0.0088806152343750, -0.0000915527343750, 0.0118103027343750, +0.0003662109375000, 0.0128784179687500, 0.0017700195312500, 0.0103759765625000, +0.0008850097656250, 0.0135803222656250, 0.0026855468750000, 0.0153503417968750, +0.0038452148437500, 0.0122375488281250, 0.0030517578125000, 0.0115051269531250, +0.0023803710937500, 0.0137023925781250, 0.0032043457031250, 0.0045166015625000, +0.0027770996093750, 0.0069885253906250, 0.0021362304687500, 0.0027465820312500, +0.0042724609375000, -0.0056457519531250, 0.0058898925781250, -0.0004272460937500, +0.0041503906250000, -0.0116882324218750, 0.0068664550781250, -0.0134277343750000, +0.0088500976562500, -0.0104980468750000, 0.0060424804687500, -0.0133361816406250, +0.0044555664062500, -0.0142517089843750, 0.0064086914062500, -0.0102539062500000, +0.0000305175781250, -0.0102539062500000, 0.0003356933593750, -0.0111694335937500, +-0.0000305175781250, -0.0090332031250000, -0.0040588378906250, -0.0087890625000000, +-0.0027465820312500, -0.0140686035156250, -0.0016784667968750, -0.0124816894531250, +-0.0031433105468750, -0.0131835937500000, -0.0007019042968750, -0.0174255371093750, +0.0025634765625000, -0.0160217285156250, 0.0005493164062500, -0.0172119140625000, +0.0036315917968750, -0.0174255371093750, 0.0054016113281250, -0.0171508789062500, +0.0021972656250000, -0.0173339843750000, 0.0006408691406250, -0.0170288085937500, +0.0024414062500000, -0.0173034667968750, -0.0049438476562500, -0.0171508789062500, +-0.0049438476562500, -0.0159606933593750, -0.0059509277343750, -0.0158081054687500, +-0.0104370117187500, -0.0161743164062500, -0.0090637207031250, -0.0111083984375000, +-0.0106811523437500, -0.0125122070312500, -0.0116577148437500, -0.0102539062500000, +-0.0102233886718750, -0.0053710937500000, -0.0093688964843750, -0.0074157714843750, +-0.0100708007812500, -0.0027160644531250, -0.0074768066406250, -0.0029907226562500, +-0.0070495605468750, -0.0012817382812500, -0.0072021484375000, 0.0021057128906250, +-0.0061950683593750, -0.0001525878906250, -0.0061340332031250, 0.0043334960937500, +-0.0065612792968750, 0.0053405761718750, -0.0063171386718750, 0.0028381347656250, +-0.0066528320312500, 0.0038757324218750, -0.0070495605468750, 0.0050964355468750, +-0.0069274902343750, -0.0032348632812500, -0.0080871582031250, -0.0012512207031250, +-0.0079345703125000, -0.0034790039062500, -0.0088500976562500, -0.0104370117187500, +-0.0103149414062500, -0.0072326660156250, -0.0097961425781250, -0.0113830566406250, +-0.0110473632812500, -0.0121154785156250, -0.0115661621093750, -0.0120849609375000, +-0.0111999511718750, -0.0136413574218750, -0.0111999511718750, -0.0130004882812500, +-0.0114746093750000, -0.0154113769531250, -0.0105895996093750, -0.0146789550781250, +-0.0104370117187500, -0.0160827636718750, -0.0106201171875000, -0.0184631347656250, +-0.0102844238281250, -0.0170593261718750, -0.0100097656250000, -0.0205993652343750, +-0.0107421875000000, -0.0207824707031250, -0.0104370117187500, -0.0209045410156250, +-0.0107421875000000, -0.0229797363281250, -0.0114440917968750, -0.0224609375000000, +-0.0109558105468750, -0.0214233398437500, -0.0118408203125000, -0.0227050781250000, +-0.0119934082031250, -0.0205383300781250, -0.0115966796875000, -0.0181884765625000, +-0.0118103027343750, -0.0199279785156250, -0.0123291015625000, -0.0141906738281250, +-0.0113830566406250, -0.0146484375000000, -0.0117187500000000, -0.0137939453125000, +-0.0121459960937500, -0.0101623535156250, -0.0118103027343750, -0.0117492675781250, +-0.0118408203125000, -0.0091247558593750, -0.0123596191406250, -0.0092773437500000, +-0.0129089355468750, -0.0086059570312500, -0.0123901367187500, -0.0068664550781250, +-0.0126953125000000, -0.0079956054687500, -0.0133972167968750, -0.0054931640625000, +-0.0093383789062500, -0.0060119628906250, -0.0116271972656250, -0.0053405761718750, +-0.0089721679687500, -0.0035095214843750, -0.0044250488281250, -0.0047302246093750, +-0.0081787109375000, -0.0018310546875000, -0.0008239746093750, -0.0016784667968750, +-0.0019836425781250, -0.0020446777343750, -0.0018310546875000, -0.0004577636718750, +0.0028686523437500, -0.0007019042968750, 0.0006408691406250, -0.0035705566406250, +0.0017700195312500, -0.0019836425781250, 0.0036621093750000, -0.0043334960937500, +0.0010375976562500, -0.0078430175781250, -0.0007629394531250, -0.0054626464843750, +0.0010375976562500, -0.0116271972656250, -0.0062561035156250, -0.0106811523437500, +-0.0047912597656250, -0.0123291015625000, -0.0074157714843750, -0.0169677734375000, +-0.0141601562500000, -0.0142517089843750, -0.0108947753906250, -0.0194702148437500, +-0.0139160156250000, -0.0196533203125000, -0.0160522460937500, -0.0191955566406250, +-0.0123901367187500, -0.0213623046875000, -0.0111694335937500, -0.0208129882812500, +-0.0134887695312500, -0.0209045410156250, -0.0032653808593750, -0.0202026367187500, +-0.0053710937500000, -0.0220336914062500, -0.0028076171875000, -0.0231933593750000, +0.0057678222656250, -0.0215454101562500, 0.0024719238281250, -0.0275878906250000, +0.0069885253906250, -0.0269165039062500, 0.0086059570312500, -0.0275878906250000, +0.0056152343750000, -0.0318603515625000, 0.0058593750000000, -0.0303649902343750, +0.0071716308593750, -0.0306701660156250, -0.0021362304687500, -0.0319213867187500, +-0.0005493164062500, -0.0308227539062500, -0.0032958984375000, -0.0298461914062500, +-0.0117187500000000, -0.0305480957031250, -0.0084838867187500, -0.0270690917968750, +-0.0090332031250000, -0.0289001464843750, -0.0126953125000000, -0.0249633789062500, +-0.0082702636718750, -0.0203247070312500, -0.0035095214843750, -0.0240173339843750, +-0.0074157714843750, -0.0120849609375000, -0.0003051757812500, -0.0130310058593750, +0.0017700195312500, -0.0117797851562500, -0.0030822753906250, -0.0032958984375000, +-0.0036926269531250, -0.0061645507812500, -0.0009460449218750, -0.0087585449218750, +-0.0093994140625000, -0.0060729980468750, -0.0098266601562500, -0.0073852539062500, +-0.0099182128906250, -0.0126953125000000, -0.0143127441406250, -0.0115966796875000, +-0.0133361816406250, -0.0064392089843750, -0.0120849609375000, -0.0089721679687500, +-0.0137634277343750, -0.0065917968750000, -0.0094909667968750, -0.0007629394531250, +-0.0070800781250000, -0.0034484863281250, -0.0112304687500000, 0.0000305175781250, +0.0042419433593750, 0.0012817382812500, 0.0052185058593750, 0.0005187988281250, +0.0022583007812500, -0.0001525878906250, 0.0074462890625000, 0.0003662109375000, +0.0075683593750000, 0.0067138671875000, 0.0028381347656250, 0.0026245117187500, +0.0030517578125000, 0.0093994140625000, 0.0063476562500000, 0.0196533203125000, +0.0044250488281250, 0.0132446289062500, 0.0018005371093750, 0.0255432128906250, +0.0140380859375000, 0.0279846191406250, 0.0136718750000000, 0.0235900878906250, +0.0138244628906250, 0.0251159667968750, 0.0233459472656250, 0.0169677734375000, +0.0102844238281250}, +{-0.0012512207031250, -0.0158691406250000, -0.0005798339843750, -0.0146484375000000, +-0.0024108886718750, -0.0151672363281250, -0.0015563964843750, -0.0142822265625000, +-0.0032348632812500, -0.0130920410156250, -0.0050964355468750, -0.0141601562500000, +-0.0033874511718750, -0.0104980468750000, -0.0098571777343750, -0.0115661621093750, +-0.0079956054687500, -0.0102233886718750, -0.0102233886718750, -0.0067443847656250, +-0.0158996582031250, -0.0087280273437500, -0.0123901367187500, -0.0059204101562500, +-0.0176086425781250, -0.0054321289062500, -0.0178833007812500, -0.0062561035156250, +-0.0172729492187500, -0.0057373046875000, -0.0198974609375000, -0.0057678222656250, +-0.0194091796875000, -0.0066528320312500, -0.0171813964843750, -0.0063171386718750, +-0.0191955566406250, -0.0072021484375000, -0.0162353515625000, -0.0080261230468750, +-0.0122070312500000, -0.0070495605468750, -0.0147705078125000, -0.0099487304687500, +-0.0070800781250000, -0.0094604492187500, -0.0081787109375000, -0.0092468261718750, +-0.0069580078125000, -0.0108642578125000, -0.0011901855468750, -0.0101623535156250, +-0.0038146972656250, -0.0099182128906250, -0.0034179687500000, -0.0096740722656250, +-0.0015869140625000, -0.0104675292968750, -0.0044860839843750, -0.0106506347656250, +-0.0068664550781250, -0.0098266601562500, -0.0046691894531250, -0.0137939453125000, +-0.0104064941406250, -0.0128784179687500, -0.0109863281250000, -0.0143432617187500, +-0.0092773437500000, -0.0178833007812500, -0.0115356445312500, -0.0161743164062500, +-0.0124206542968750, -0.0190734863281250, -0.0074157714843750, -0.0194702148437500, +-0.0089721679687500, -0.0194396972656250, -0.0054321289062500, -0.0206604003906250, +-0.0000915527343750, -0.0202026367187500, -0.0036010742187500, -0.0207214355468750, +0.0054016113281250, -0.0214233398437500, 0.0058288574218750, -0.0199279785156250, +0.0048217773437500, -0.0194396972656250, 0.0096130371093750, -0.0206298828125000, +0.0086364746093750, -0.0145568847656250, 0.0013427734375000, -0.0157470703125000, +0.0041809082031250, -0.0144958496093750, 0.0003967285156250, -0.0093994140625000, +-0.0079956054687500, -0.0114746093750000, -0.0043029785156250, -0.0105285644531250, +-0.0086364746093750, -0.0089416503906250, -0.0112609863281250, -0.0117187500000000, +-0.0089111328125000, -0.0141601562500000, -0.0072326660156250, -0.0121154785156250, +-0.0086364746093750, -0.0154418945312500, -0.0095214843750000, -0.0173034667968750, +-0.0089111328125000, -0.0147399902343750, -0.0088500976562500, -0.0133972167968750, +-0.0099182128906250, -0.0150451660156250, -0.0101623535156250, -0.0115966796875000, +-0.0086059570312500, -0.0119934082031250, -0.0090026855468750, -0.0099792480468750, +-0.0102539062500000, -0.0075378417968750, -0.0099792480468750, -0.0096130371093750, +-0.0084228515625000, -0.0006408691406250, -0.0080261230468750, -0.0034179687500000, +-0.0130920410156250, 0.0021362304687500, -0.0054931640625000, 0.0119934082031250, +0.0034790039062500, 0.0060119628906250, -0.0025024414062500, 0.0166931152343750, +0.0111694335937500, 0.0182800292968750, 0.0122985839843750, 0.0173339843750000, +0.0090026855468750, 0.0209655761718750, 0.0136718750000000, 0.0197753906250000, +0.0151672363281250, 0.0190124511718750, 0.0105895996093750, 0.0204162597656250, +0.0095214843750000, 0.0185546875000000, 0.0115051269531250, 0.0140380859375000, +0.0121459960937500, 0.0094909667968750, 0.0166625976562500, -0.0038452148437500, +0.0108337402343750, 0.0031738281250000, 0.0109863281250000, -0.0012512207031250, +0.0164184570312500, -0.0125122070312500, 0.0170288085937500, -0.0089416503906250, +0.0126647949218750, -0.0046081542968750, 0.0257263183593750, -0.0085754394531250, +0.0272827148437500, -0.0048217773437500, 0.0227966308593750, 0.0030822753906250, +0.0274353027343750, -0.0007324218750000, 0.0291137695312500, -0.0000305175781250, +0.0111083984375000, 0.0039672851562500, 0.0131225585937500, -0.0005187988281250, +0.0145263671875000, -0.0064392089843750, 0.0046997070312500, -0.0023803710937500, +0.0050354003906250, -0.0054626464843750, 0.0071411132812500, -0.0110778808593750, +0.0099182128906250, -0.0001831054687500, 0.0028381347656250, 0.0086059570312500, +-0.0011901855468750, -0.0010375976562500, 0.0040893554687500, 0.0166320800781250, +-0.0185852050781250, 0.0212707519531250, -0.0147094726562500, 0.0134277343750000, +-0.0201721191406250, 0.0158386230468750, -0.0389404296875000, 0.0197448730468750, +-0.0310058593750000, -0.0002746582031250, -0.0352478027343750, 0.0036315917968750, +-0.0406799316406250, -0.0003662109375000, -0.0346374511718750, -0.0166320800781250, +-0.0286560058593750, -0.0097045898437500, -0.0326843261718750, -0.0109252929687500, +-0.0281982421875000, -0.0179748535156250, -0.0261840820312500, -0.0098876953125000, +-0.0270996093750000, -0.0003356933593750, -0.0278015136718750, -0.0068359375000000, +-0.0280761718750000, 0.0034484863281250, -0.0240783691406250, 0.0045471191406250, +-0.0249023437500000, 0.0043029785156250, -0.0250854492187500, 0.0091857910156250, +-0.0220642089843750, 0.0071411132812500, -0.0223693847656250, 0.0046386718750000, +-0.0255126953125000, 0.0080261230468750, -0.0254516601562500, 0.0036621093750000, +-0.0239562988281250, -0.0027465820312500, -0.0258483886718750, 0.0013732910156250, +-0.0266418457031250, -0.0042724609375000, -0.0168457031250000, -0.0056457519531250, +-0.0199890136718750, -0.0047607421875000, -0.0153198242187500, -0.0057373046875000, +-0.0053710937500000, -0.0054321289062500, -0.0103454589843750, -0.0071411132812500, +-0.0018920898437500, -0.0062255859375000, -0.0009765625000000, -0.0070495605468750, +-0.0007934570312500, -0.0091552734375000, 0.0026550292968750, -0.0077819824218750, +0.0011901855468750, -0.0086669921875000, 0.0052185058593750, -0.0089111328125000, +0.0046386718750000, -0.0089721679687500, 0.0053100585937500, -0.0089111328125000, +0.0083312988281250, -0.0082397460937500, 0.0071105957031250, -0.0094299316406250, +0.0079650878906250, -0.0097656250000000, 0.0083007812500000, -0.0083312988281250, +0.0081787109375000, -0.0080871582031250, 0.0084228515625000, -0.0088806152343750, +0.0083007812500000, -0.0051574707031250, 0.0076904296875000, -0.0060424804687500, +0.0086364746093750, -0.0046081542968750, 0.0068969726562500, -0.0016174316406250, +0.0050659179687500, -0.0035705566406250, 0.0065612792968750, 0.0009155273437500, +0.0025329589843750, 0.0002441406250000, 0.0026550292968750, 0.0012512207031250, +0.0022888183593750, 0.0044250488281250, 0.0003662109375000, 0.0024414062500000, +0.0011596679687500, 0.0056457519531250, -0.0025939941406250, 0.0054931640625000, +-0.0010986328125000, 0.0054321289062500, -0.0044860839843750, 0.0071105957031250, +-0.0093688964843750, 0.0062561035156250, -0.0063476562500000, 0.0070495605468750, +-0.0146179199218750, 0.0075073242187500, -0.0146789550781250, 0.0071105957031250, +-0.0155639648437500, 0.0073547363281250, -0.0202636718750000, 0.0078430175781250, +-0.0186157226562500, 0.0065917968750000, -0.0213928222656250, 0.0072021484375000, +-0.0216369628906250, 0.0068969726562500, -0.0219116210937500, 0.0058593750000000, +-0.0232238769531250, 0.0069580078125000, -0.0225524902343750, 0.0065307617187500, +-0.0238647460937500, 0.0065612792968750, -0.0238037109375000, 0.0072631835937500, +-0.0235900878906250, 0.0076293945312500, -0.0242614746093750, 0.0080261230468750, +-0.0241394042968750, 0.0092163085937500, -0.0237426757812500, 0.0093688964843750, +-0.0241088867187500, 0.0102844238281250, -0.0238647460937500, 0.0115356445312500, +-0.0237426757812500, 0.0113220214843750, -0.0242309570312500, 0.0126953125000000, +-0.0222778320312500, 0.0134582519531250, -0.0238952636718750, 0.0136718750000000, +-0.0211181640625000, 0.0143127441406250, -0.0178833007812500, 0.0149230957031250, +-0.0206298828125000, 0.0151367187500000, -0.0123596191406250, 0.0154113769531250, +-0.0131225585937500, 0.0153808593750000, -0.0113830566406250, 0.0155029296875000, +-0.0055541992187500, 0.0158996582031250, -0.0078125000000000, 0.0148620605468750, +-0.0031433105468750, 0.0151672363281250, -0.0020446777343750, 0.0144653320312500, +-0.0032958984375000, 0.0136108398437500, -0.0017089843750000, 0.0139770507812500, +-0.0009155273437500, 0.0104064941406250, -0.0053405761718750, 0.0116577148437500, +-0.0048217773437500, 0.0087890625000000, -0.0047302246093750, 0.0046386718750000, +-0.0078430175781250, 0.0070190429687500, -0.0078125000000000, -0.0008850097656250, +-0.0061645507812500, 0.0001831054687500, -0.0066528320312500, -0.0021057128906250, +-0.0074462890625000, -0.0080871582031250, -0.0067443847656250, -0.0049743652343750, +-0.0063171386718750, -0.0105590820312500, -0.0075073242187500, -0.0107116699218750, +-0.0075683593750000, -0.0098266601562500, -0.0080566406250000, -0.0123901367187500, +-0.0076904296875000, -0.0115661621093750, -0.0070800781250000, -0.0089111328125000, +-0.0135498046875000, -0.0099792480468750, -0.0110778808593750, -0.0082397460937500, +-0.0127563476562500, -0.0051269531250000, -0.0198364257812500, -0.0066833496093750, +-0.0175781250000000, -0.0037536621093750, -0.0156555175781250, -0.0031127929687500, +-0.0182189941406250, -0.0047607421875000, -0.0169982910156250, -0.0045166015625000, +-0.0134887695312500, -0.0041198730468750, -0.0148315429687500, -0.0077514648437500, +-0.0133666992187500, -0.0079650878906250, -0.0122680664062500, -0.0082702636718750, +-0.0162963867187500, -0.0107421875000000, -0.0175476074218750, -0.0103759765625000, +-0.0138854980468750, -0.0075073242187500, -0.0251464843750000, -0.0100708007812500, +-0.0268249511718750, -0.0061950683593750, -0.0208740234375000, -0.0012207031250000, +-0.0231933593750000, -0.0050354003906250, -0.0267333984375000, 0.0048828125000000, +-0.0106811523437500, 0.0043640136718750, -0.0133056640625000, 0.0052185058593750, +-0.0101318359375000, 0.0113220214843750, 0.0019226074218750, 0.0088195800781250, +-0.0030517578125000, 0.0101318359375000, 0.0022888183593750, 0.0116577148437500, +0.0050048828125000, 0.0096435546875000, 0.0003051757812500, 0.0082092285156250, +-0.0009765625000000, 0.0094299316406250, 0.0027465820312500, 0.0059814453125000, +-0.0046386718750000, 0.0066833496093750, -0.0063476562500000, 0.0059204101562500, +-0.0043945312500000, 0.0034790039062500, -0.0050964355468750, 0.0048217773437500, +-0.0049133300781250, 0.0020446777343750, -0.0035705566406250, 0.0028381347656250, +-0.0037231445312500, 0.0012207031250000, -0.0043029785156250, -0.0013427734375000, +-0.0039062500000000, 0.0006713867187500, -0.0030517578125000, -0.0050659179687500, +-0.0025329589843750, -0.0049438476562500, -0.0031433105468750, -0.0041809082031250, +-0.0033874511718750, -0.0068359375000000, -0.0028076171875000, -0.0066223144531250, +-0.0020446777343750, -0.0058593750000000, -0.0004882812500000, -0.0064392089843750, +-0.0019226074218750, -0.0048522949218750, 0.0000305175781250, -0.0028686523437500, +0.0041503906250000, -0.0028076171875000, 0.0034179687500000, 0.0015869140625000, +0.0036621093750000, -0.0000610351562500, 0.0055847167968750, 0.0018615722656250, +0.0032958984375000, 0.0061645507812500, 0.0009765625000000, 0.0030822753906250, +0.0033264160156250, 0.0059509277343750, -0.0014648437500000, 0.0087280273437500, +-0.0018310546875000, 0.0055847167968750, -0.0008239746093750, 0.0025634765625000, +-0.0022888183593750, 0.0052795410156250, -0.0023193359375000, 0.0036926269531250, +-0.0017395019531250, 0.0000305175781250, -0.0010375976562500, 0.0058898925781250, +-0.0014038085937500, 0.0119934082031250, -0.0022277832031250, 0.0065917968750000, +-0.0019836425781250, 0.0112609863281250, -0.0014038085937500, 0.0164184570312500, +-0.0010070800781250}, +{-0.0109252929687500, 0.0092468261718750, -0.0131835937500000, 0.0093688964843750, +-0.0113220214843750, 0.0114135742187500, -0.0068664550781250, 0.0116577148437500, +-0.0091857910156250, 0.0101928710937500, -0.0073242187500000, 0.0119628906250000, +-0.0065002441406250, 0.0100708007812500, -0.0070190429687500, 0.0073852539062500, +-0.0067138671875000, 0.0097045898437500, -0.0068054199218750, 0.0042114257812500, +-0.0085449218750000, 0.0047302246093750, -0.0065307617187500, 0.0030212402343750, +-0.0092163085937500, -0.0010986328125000, -0.0135192871093750, 0.0007019042968750, +-0.0101318359375000, -0.0045776367187500, -0.0114135742187500, -0.0049438476562500, +-0.0150756835937500, -0.0053100585937500, -0.0102539062500000, -0.0084228515625000, +-0.0050354003906250, -0.0076293945312500, -0.0094604492187500, -0.0068359375000000, +-0.0049743652343750, -0.0086669921875000, -0.0025024414062500, -0.0055847167968750, +-0.0051269531250000, -0.0021057128906250, -0.0059204101562500, -0.0048522949218750, +-0.0051879882812500, 0.0011291503906250, -0.0118713378906250, 0.0017089843750000, +-0.0090942382812500, 0.0007629394531250, -0.0122070312500000, 0.0030517578125000, +-0.0213623046875000, 0.0024414062500000, -0.0171508789062500, -0.0008239746093750, +-0.0129089355468750, 0.0000610351562500, -0.0192565917968750, -0.0016784667968750, +-0.0131225585937500, -0.0053100585937500, -0.0025634765625000, -0.0038452148437500, +-0.0086669921875000, -0.0053710937500000, -0.0000610351562500, -0.0073242187500000, +0.0020446777343750, -0.0041198730468750, -0.0007934570312500, -0.0022888183593750, +0.0011901855468750, -0.0046081542968750, 0.0015869140625000, 0.0052795410156250, +-0.0065307617187500, 0.0044250488281250, -0.0036621093750000, 0.0044250488281250, +-0.0055847167968750, 0.0108032226562500, -0.0142822265625000, 0.0095214843750000, +-0.0115661621093750, 0.0064392089843750, -0.0089111328125000, 0.0080261230468750, +-0.0108337402343750, 0.0059204101562500, -0.0096130371093750, 0.0021057128906250, +-0.0061035156250000, 0.0041503906250000, -0.0075378417968750, 0.0010375976562500, +-0.0080566406250000, 0.0003662109375000, -0.0061950683593750, 0.0013732910156250, +-0.0069580078125000, 0.0012207031250000, -0.0096435546875000, 0.0010375976562500, +-0.0089721679687500, 0.0010681152343750, -0.0073242187500000, 0.0023193359375000, +-0.0089416503906250, 0.0004272460937500, -0.0049438476562500, -0.0018920898437500, +-0.0010375976562500, -0.0000610351562500, -0.0047607421875000, -0.0015869140625000, +0.0035400390625000, -0.0026245117187500, 0.0044860839843750, -0.0014953613281250, +0.0032348632812500, -0.0007934570312500, 0.0066528320312500, -0.0007019042968750, +0.0061035156250000, 0.0025939941406250, 0.0003356933593750, 0.0016784667968750, +0.0021972656250000, 0.0017089843750000, 0.0021057128906250, 0.0037841796875000, +-0.0021057128906250, 0.0032958984375000, -0.0009765625000000, 0.0053710937500000, +-0.0014038085937500, 0.0051879882812500, -0.0021667480468750, 0.0037841796875000, +-0.0013732910156250, 0.0050048828125000, -0.0007019042968750, 0.0057678222656250, +-0.0010986328125000, -0.0009155273437500, 0.0008544921875000, 0.0005798339843750, +0.0002746582031250, 0.0002136230468750, 0.0011901855468750, -0.0059204101562500, +0.0038757324218750, -0.0047912597656250, 0.0029907226562500, 0.0022888183593750, +0.0021972656250000, 0.0001220703125000, 0.0030517578125000, 0.0000000000000000, +0.0023498535156250, 0.0064086914062500, 0.0013122558593750, 0.0053405761718750, +0.0018615722656250, -0.0033569335937500, -0.0013732910156250, 0.0000305175781250, +-0.0010681152343750, -0.0014038085937500, -0.0007324218750000, -0.0097961425781250, +-0.0027160644531250, -0.0078430175781250, -0.0026550292968750, -0.0071411132812500, +-0.0007934570312500, -0.0085754394531250, -0.0013122558593750, -0.0079345703125000, +-0.0014953613281250, -0.0052795410156250, 0.0000610351562500, -0.0059509277343750, +-0.0002441406250000, -0.0110778808593750, -0.0027160644531250, -0.0085144042968750, +-0.0018310546875000, -0.0097351074218750, -0.0032958984375000, -0.0153808593750000, +-0.0060424804687500, -0.0133972167968750, -0.0046386718750000, -0.0132446289062500, +-0.0075073242187500, -0.0150451660156250, -0.0088806152343750, -0.0116882324218750, +-0.0068969726562500, -0.0083923339843750, -0.0062866210937500, -0.0114440917968750, +-0.0079040527343750, -0.0070190429687500, -0.0047912597656250, -0.0057983398437500, +-0.0042419433593750, -0.0059814453125000, -0.0056152343750000, -0.0052490234375000, +-0.0052185058593750, -0.0055541992187500, -0.0048217773437500, -0.0024719238281250, +-0.0080261230468750, -0.0032348632812500, -0.0077514648437500, -0.0015563964843750, +-0.0082092285156250, 0.0017089843750000, -0.0107421875000000, -0.0000305175781250, +-0.0101318359375000, 0.0027465820312500, -0.0083923339843750, 0.0039367675781250, +-0.0092163085937500, 0.0015869140625000, -0.0076293945312500, 0.0010070800781250, +-0.0049438476562500, 0.0025939941406250, -0.0057983398437500, -0.0018005371093750, +-0.0034790039062500, -0.0017395019531250, -0.0030517578125000, -0.0021667480468750, +-0.0028686523437500, -0.0043029785156250, -0.0016479492187500, -0.0034179687500000, +-0.0018005371093750, -0.0061645507812500, -0.0023498535156250, -0.0055236816406250, +-0.0015563964843750, -0.0066528320312500, -0.0024414062500000, -0.0091857910156250, +-0.0038146972656250, -0.0079650878906250, -0.0031433105468750, -0.0104980468750000, +-0.0048217773437500, -0.0108032226562500, -0.0053100585937500, -0.0111999511718750, +-0.0055541992187500, -0.0126647949218750, -0.0061950683593750, -0.0122985839843750, +-0.0062866210937500, -0.0137939453125000, -0.0072326660156250, -0.0139465332031250, +-0.0069580078125000, -0.0144958496093750, -0.0075988769531250, -0.0155639648437500, +-0.0086059570312500, -0.0154113769531250, -0.0081787109375000, -0.0164184570312500, +-0.0102233886718750, -0.0166625976562500, -0.0102233886718750, -0.0169372558593750, +-0.0109558105468750, -0.0173034667968750, -0.0126342773437500, -0.0171203613281250, +-0.0122070312500000, -0.0185241699218750, -0.0138244628906250, -0.0178833007812500, +-0.0143737792968750, -0.0187072753906250, -0.0148315429687500, -0.0202636718750000, +-0.0158081054687500, -0.0192565917968750, -0.0162658691406250, -0.0210876464843750, +-0.0171813964843750, -0.0211181640625000, -0.0178222656250000, -0.0209350585937500, +-0.0183410644531250, -0.0218200683593750, -0.0191345214843750, -0.0214843750000000, +-0.0198059082031250, -0.0212097167968750, -0.0197753906250000, -0.0211791992187500, +-0.0208129882812500, -0.0213623046875000, -0.0209655761718750, -0.0213012695312500, +-0.0208740234375000, -0.0209655761718750, -0.0220031738281250, -0.0212097167968750, +-0.0213012695312500, -0.0214233398437500, -0.0222473144531250, -0.0205688476562500, +-0.0224914550781250, -0.0201110839843750, -0.0221557617187500, -0.0205993652343750, +-0.0235290527343750, -0.0185852050781250, -0.0220642089843750, -0.0184631347656250, +-0.0224914550781250, -0.0187988281250000, -0.0223083496093750, -0.0179748535156250, +-0.0209655761718750, -0.0180053710937500, -0.0213623046875000, -0.0190734863281250, +-0.0209960937500000, -0.0190124511718750, -0.0209350585937500, -0.0187988281250000, +-0.0204467773437500, -0.0194702148437500, -0.0204467773437500, -0.0196228027343750, +-0.0209045410156250, -0.0180053710937500, -0.0179748535156250, -0.0188598632812500, +-0.0193481445312500, -0.0173034667968750, -0.0176086425781250, -0.0154418945312500, +-0.0148925781250000, -0.0169067382812500, -0.0170898437500000, -0.0111694335937500, +-0.0103759765625000, -0.0122680664062500, -0.0117797851562500, -0.0104980468750000, +-0.0096740722656250, -0.0056152343750000, -0.0042419433593750, -0.0080566406250000, +-0.0072937011718750, -0.0049743652343750, -0.0019836425781250, -0.0040893554687500, +-0.0020141601562500, -0.0050354003906250, -0.0031738281250000, -0.0046691894531250, +-0.0004882812500000, -0.0045471191406250, -0.0005493164062500, -0.0050659179687500, +-0.0045471191406250, -0.0052490234375000, -0.0027160644531250, -0.0053405761718750, +-0.0049133300781250, -0.0053710937500000, -0.0091552734375000, -0.0054321289062500, +-0.0065002441406250, -0.0066223144531250, -0.0119934082031250, -0.0063476562500000, +-0.0122680664062500, -0.0067443847656250, -0.0122070312500000, -0.0082397460937500, +-0.0148925781250000, -0.0078735351562500, -0.0138549804687500, -0.0061645507812500, +-0.0140380859375000, -0.0077209472656250, -0.0155334472656250, -0.0054016113281250, +-0.0120849609375000, -0.0019836425781250, -0.0092773437500000, -0.0042724609375000, +-0.0120239257812500, -0.0010681152343750, -0.0050964355468750, 0.0002746582031250, +-0.0041198730468750, -0.0016479492187500, -0.0057983398437500, -0.0020141601562500, +-0.0039062500000000, -0.0009155273437500, -0.0033264160156250, -0.0046386718750000, +-0.0061645507812500, -0.0038757324218750, -0.0069580078125000, -0.0064697265625000, +-0.0048828125000000, -0.0093994140625000, -0.0045776367187500, -0.0068359375000000, +-0.0059509277343750, -0.0167541503906250, -0.0010375976562500, -0.0164184570312500, +-0.0014343261718750, -0.0158691406250000, -0.0016784667968750, -0.0219726562500000, +0.0010375976562500, -0.0210876464843750, 0.0007324218750000, -0.0149841308593750, +0.0013122558593750, -0.0182800292968750, 0.0012207031250000, -0.0134582519531250, +-0.0012512207031250, -0.0050048828125000, -0.0007019042968750, -0.0099182128906250, +0.0014038085937500, -0.0028381347656250, -0.0100402832031250, -0.0007934570312500, +-0.0085449218750000, -0.0029602050781250, -0.0106201171875000, -0.0021972656250000, +-0.0198974609375000, -0.0014038085937500, -0.0160522460937500, -0.0029907226562500, +-0.0122375488281250, -0.0041503906250000, -0.0173339843750000, -0.0009460449218750, +-0.0124206542968750, 0.0006103515625000, -0.0037841796875000, -0.0020446777343750, +-0.0079345703125000, 0.0057983398437500, 0.0004272460937500, 0.0077514648437500, +0.0012817382812500, 0.0022583007812500, -0.0011901855468750, 0.0020446777343750, +0.0007324218750000, 0.0057067871093750, 0.0015258789062500, -0.0060119628906250, +0.0008850097656250, -0.0063171386718750, -0.0003051757812500, -0.0064392089843750, +0.0017089843750000, -0.0149230957031250, 0.0052795410156250, -0.0179443359375000, +0.0028076171875000, -0.0133666992187500, -0.0036315917968750, -0.0158691406250000, +-0.0056762695312500, -0.0133361816406250, -0.0003356933593750, -0.0107727050781250, +0.0026245117187500, -0.0124816894531250, -0.0008239746093750, -0.0016479492187500, +0.0087585449218750, -0.0042724609375000, 0.0092163085937500, -0.0018920898437500, +0.0075378417968750, 0.0077514648437500, 0.0119628906250000, 0.0038452148437500, +0.0124206542968750, 0.0044555664062500, 0.0071411132812500, 0.0075073242187500, +0.0072631835937500, 0.0047912597656250, 0.0075683593750000, 0.0008850097656250, +0.0060729980468750, 0.0026245117187500, 0.0067138671875000, 0.0007019042968750, +0.0032348632812500, -0.0004882812500000, 0.0041809082031250, 0.0022277832031250, +0.0027465820312500, 0.0036315917968750, 0.0001220703125000, 0.0010375976562500, +0.0016784667968750, 0.0036315917968750, -0.0057983398437500, 0.0053710937500000, +-0.0043640136718750, 0.0037841796875000, -0.0061035156250000, 0.0021667480468750, +-0.0115356445312500, 0.0026855468750000, -0.0095825195312500, 0.0019836425781250, +-0.0172424316406250, 0.0018005371093750, -0.0144653320312500, 0.0019226074218750, +-0.0199584960937500, 0.0016479492187500, -0.0295715332031250, 0.0016784667968750, +-0.0237121582031250, 0.0030517578125000, -0.0321655273437500, 0.0016174316406250, +-0.0357360839843750, 0.0037536621093750, -0.0303955078125000, 0.0082702636718750, +-0.0291442871093750}, +{-0.0012817382812500, -0.0022277832031250, 0.0019226074218750, -0.0048828125000000, +0.0016479492187500, 0.0001220703125000, -0.0028686523437500, 0.0006713867187500, +-0.0003662109375000, -0.0001220703125000, -0.0041198730468750, 0.0018310546875000, +-0.0108032226562500, 0.0015258789062500, -0.0069274902343750, -0.0001220703125000, +-0.0116882324218750, 0.0006408691406250, -0.0140991210937500, -0.0002746582031250, +-0.0108337402343750, -0.0015258789062500, -0.0094299316406250, -0.0009155273437500, +-0.0113220214843750, -0.0064697265625000, -0.0067443847656250, -0.0040893554687500, +-0.0058898925781250, -0.0078430175781250, -0.0062255859375000, -0.0154418945312500, +-0.0051879882812500, -0.0114135742187500, -0.0054931640625000, -0.0134277343750000, +-0.0039672851562500, -0.0172119140625000, -0.0043945312500000, -0.0126342773437500, +-0.0033569335937500, -0.0077819824218750, -0.0014038085937500, -0.0109863281250000, +-0.0027465820312500, -0.0047912597656250, -0.0030517578125000, -0.0032958984375000, +-0.0025024414062500, -0.0053100585937500, -0.0010375976562500, -0.0042114257812500, +-0.0009460449218750, -0.0032653808593750, -0.0027770996093750, -0.0072021484375000, +-0.0005798339843750, -0.0072937011718750, 0.0013732910156250, -0.0063476562500000, +-0.0014953613281250, -0.0078735351562500, -0.0031127929687500, -0.0080261230468750, +-0.0015563964843750, -0.0051269531250000, -0.0111083984375000, -0.0057678222656250, +-0.0101928710937500, -0.0060119628906250, -0.0100402832031250, -0.0031127929687500, +-0.0162048339843750, -0.0037231445312500, -0.0151672363281250, -0.0115661621093750, +-0.0123596191406250, -0.0086364746093750, -0.0157775878906250, -0.0107421875000000, +-0.0099182128906250, -0.0186157226562500, -0.0026245117187500, -0.0161437988281250, +-0.0081481933593750, -0.0172729492187500, 0.0010070800781250, -0.0180664062500000, +0.0027465820312500, -0.0175170898437500, -0.0005798339843750, -0.0174255371093750, +0.0006103515625000, -0.0211181640625000, -0.0098876953125000, -0.0098571777343750, +-0.0025024414062500, -0.0156250000000000, 0.0005187988281250, -0.0091247558593750, +-0.0039672851562500, 0.0007019042968750, -0.0082397460937500, -0.0050659179687500, +-0.0054321289062500, -0.0016174316406250, -0.0071716308593750, 0.0032348632812500, +-0.0107727050781250, -0.0026245117187500, -0.0037231445312500, -0.0084533691406250, +0.0023193359375000, -0.0038146972656250, -0.0036621093750000, -0.0089111328125000, +0.0062866210937500, -0.0135803222656250, 0.0105895996093750, -0.0061035156250000, +0.0050964355468750, -0.0011291503906250, 0.0035400390625000, -0.0067138671875000, +0.0064392089843750, 0.0074157714843750, -0.0027160644531250, 0.0086669921875000, +-0.0026245117187500, 0.0044250488281250, -0.0018310546875000, 0.0088195800781250, +-0.0066223144531250, 0.0106201171875000, -0.0061035156250000, 0.0027465820312500, +-0.0023193359375000, 0.0013122558593750, -0.0019531250000000, 0.0043640136718750, +-0.0045776367187500, 0.0033874511718750, -0.0042114257812500, 0.0018310546875000, +-0.0024719238281250, 0.0081787109375000, -0.0098266601562500, 0.0072021484375000, +-0.0087585449218750, 0.0080871582031250, -0.0115661621093750, 0.0132446289062500, +-0.0171203613281250, 0.0111389160156250, -0.0137329101562500, 0.0085449218750000, +-0.0215148925781250, 0.0137329101562500, -0.0216979980468750, 0.0040588378906250, +-0.0215148925781250, -0.0061035156250000, -0.0256958007812500, 0.0028381347656250, +-0.0245971679687500, -0.0152282714843750, -0.0225830078125000, -0.0182495117187500, +-0.0242004394531250, -0.0134277343750000, -0.0220947265625000, -0.0183105468750000, +-0.0188598632812500, -0.0194396972656250, -0.0206298828125000, -0.0090026855468750, +-0.0163574218750000, -0.0118408203125000, -0.0162353515625000, -0.0086669921875000, +-0.0165100097656250, 0.0008239746093750, -0.0143127441406250, -0.0038757324218750, +-0.0147705078125000, -0.0013427734375000, -0.0161743164062500, 0.0036315917968750, +-0.0158081054687500, -0.0040283203125000, -0.0158996582031250, -0.0093994140625000, +-0.0171508789062500, -0.0029296875000000, -0.0171813964843750, -0.0216674804687500, +-0.0163269042968750, -0.0187988281250000, -0.0162048339843750, -0.0221252441406250, +-0.0170288085937500, -0.0350646972656250, -0.0170593261718750, -0.0286560058593750, +-0.0165100097656250, -0.0390625000000000, -0.0180664062500000, -0.0389709472656250, +-0.0187988281250000, -0.0386657714843750, -0.0172729492187500, -0.0443115234375000, +-0.0167846679687500, -0.0418395996093750, -0.0178527832031250, -0.0404968261718750, +-0.0142211914062500, -0.0424194335937500, -0.0144958496093750, -0.0395812988281250, +-0.0139465332031250, -0.0360717773437500, -0.0116577148437500, -0.0384826660156250, +-0.0125732421875000, -0.0337829589843750, -0.0101318359375000, -0.0340270996093750, +-0.0105285644531250, -0.0334777832031250, -0.0099182128906250, -0.0309448242187500, +-0.0079040527343750, -0.0322265625000000, -0.0089111328125000, -0.0285644531250000, +-0.0082702636718750, -0.0293579101562500, -0.0078735351562500, -0.0279846191406250, +-0.0080871582031250, -0.0252075195312500, -0.0084228515625000, -0.0272521972656250, +-0.0083312988281250, -0.0232543945312500, -0.0071411132812500, -0.0244140625000000, +-0.0075988769531250, -0.0234069824218750, -0.0070800781250000, -0.0207519531250000, +-0.0057373046875000, -0.0233459472656250, -0.0060729980468750, -0.0180969238281250, +-0.0055236816406250, -0.0202026367187500, -0.0055541992187500, -0.0185241699218750, +-0.0049743652343750, -0.0140991210937500, -0.0043945312500000, -0.0174865722656250, +-0.0049438476562500, -0.0113525390625000, -0.0039672851562500, -0.0131530761718750, +-0.0034790039062500, -0.0119628906250000, -0.0047912597656250, -0.0077209472656250, +-0.0054931640625000, -0.0117187500000000, -0.0048522949218750, -0.0062561035156250, +-0.0080871582031250, -0.0077209472656250, -0.0083618164062500, -0.0075073242187500, +-0.0083007812500000, -0.0043640136718750, -0.0099182128906250, -0.0075683593750000, +-0.0097351074218750, -0.0041198730468750, -0.0093383789062500, -0.0055236816406250, +-0.0091247558593750, -0.0057983398437500, -0.0098571777343750, -0.0039367675781250, +-0.0099182128906250, -0.0068359375000000, -0.0091247558593750, -0.0058288574218750, +-0.0122375488281250, -0.0068054199218750, -0.0108642578125000, -0.0083312988281250, +-0.0126342773437500, -0.0084533691406250, -0.0157470703125000, -0.0094909667968750, +-0.0134582519531250, -0.0110473632812500, -0.0188293457031250, -0.0111083984375000, +-0.0191345214843750, -0.0125427246093750, -0.0187683105468750, -0.0142517089843750, +-0.0217590332031250, -0.0139465332031250, -0.0216979980468750, -0.0171508789062500, +-0.0193481445312500, -0.0171203613281250, -0.0205383300781250, -0.0183105468750000, +-0.0201416015625000, -0.0209350585937500, -0.0179138183593750, -0.0203552246093750, +-0.0188293457031250, -0.0230102539062500, -0.0187072753906250, -0.0231628417968750, +-0.0182189941406250, -0.0229492187500000, -0.0187377929687500, -0.0242309570312500, +-0.0188293457031250, -0.0240478515625000, -0.0181884765625000, -0.0225524902343750, +-0.0199584960937500, -0.0234375000000000, -0.0199890136718750, -0.0220642089843750, +-0.0182800292968750, -0.0204162597656250, -0.0193176269531250, -0.0216674804687500, +-0.0202331542968750, -0.0165100097656250, -0.0113525390625000, -0.0174865722656250, +-0.0143432617187500, -0.0152282714843750, -0.0115966796875000, -0.0108032226562500, +-0.0030517578125000, -0.0128784179687500, -0.0068969726562500, -0.0058898925781250, +-0.0037536621093750, -0.0067443847656250, -0.0025024414062500, -0.0043334960937500, +-0.0018615722656250, 0.0011901855468750, -0.0011901855468750, -0.0013427734375000, +-0.0026245117187500, 0.0049438476562500, 0.0013732910156250, 0.0049438476562500, +0.0021057128906250, 0.0052490234375000, 0.0005187988281250, 0.0091247558593750, +0.0001525878906250, 0.0079040527343750, 0.0015258789062500, 0.0068359375000000, +0.0051574707031250, 0.0083923339843750, 0.0015258789062500, 0.0062561035156250, +0.0044860839843750, 0.0036315917968750, 0.0116577148437500, 0.0053710937500000, +0.0083007812500000, 0.0007324218750000, 0.0085754394531250, 0.0010681152343750, +0.0115051269531250, 0.0001831054687500, 0.0075988769531250, -0.0028381347656250, +0.0040283203125000, -0.0011901855468750, 0.0069274902343750, -0.0036621093750000, +-0.0033264160156250, -0.0039672851562500, -0.0015258789062500, -0.0031127929687500, +-0.0034484863281250, -0.0034179687500000, -0.0121765136718750, -0.0036315917968750, +-0.0087890625000000, -0.0039367675781250, -0.0067443847656250, -0.0027770996093750, +-0.0087890625000000, -0.0040588378906250, -0.0097351074218750, -0.0068664550781250, +-0.0071716308593750, -0.0055541992187500, -0.0060729980468750, -0.0022583007812500, +-0.0114135742187500, -0.0048828125000000, -0.0102233886718750, -0.0021972656250000, +-0.0115966796875000, 0.0028991699218750, -0.0169677734375000, 0.0004577636718750, +-0.0147705078125000, 0.0061645507812500, -0.0111999511718750, 0.0060119628906250, +-0.0142822265625000, 0.0057983398437500, -0.0112609863281250, 0.0091247558593750, +-0.0053710937500000, 0.0080566406250000, -0.0086059570312500, 0.0056457519531250, +-0.0048217773437500, 0.0069274902343750, -0.0028076171875000, 0.0056152343750000, +-0.0045166015625000, 0.0023193359375000, -0.0051879882812500, 0.0034484863281250, +-0.0046386718750000, 0.0037231445312500, -0.0072326660156250, 0.0029602050781250, +-0.0066528320312500, 0.0032958984375000, -0.0067138671875000, 0.0049743652343750, +-0.0089416503906250, 0.0048217773437500, -0.0083007812500000, 0.0016174316406250, +-0.0057373046875000, 0.0034179687500000, -0.0076293945312500, 0.0021667480468750, +-0.0051269531250000, -0.0015258789062500, -0.0015869140625000, 0.0001525878906250, +-0.0042419433593750, -0.0017700195312500, 0.0028381347656250, -0.0025024414062500, +0.0032348632812500, -0.0026245117187500, 0.0025634765625000, -0.0027465820312500, +0.0058288574218750, -0.0028076171875000, 0.0054016113281250, -0.0069885253906250, +0.0028991699218750, -0.0048828125000000, 0.0029907226562500, -0.0076904296875000, +0.0039978027343750, -0.0132751464843750, 0.0030822753906250, -0.0105590820312500, +0.0022583007812500, -0.0151977539062500, 0.0053100585937500, -0.0166931152343750, +0.0052185058593750, -0.0133666992187500, 0.0053710937500000, -0.0131835937500000, +0.0073242187500000, -0.0155029296875000, 0.0065002441406250, -0.0093078613281250, +0.0038757324218750, -0.0083923339843750, 0.0055541992187500, -0.0105285644531250, +0.0034790039062500, -0.0091552734375000, -0.0007019042968750, -0.0076904296875000, +0.0011291503906250, -0.0110473632812500, -0.0004272460937500, -0.0126953125000000, +-0.0018310546875000, -0.0091247558593750, -0.0013122558593750, -0.0070190429687500, +-0.0002746582031250, -0.0097656250000000, -0.0006713867187500, -0.0060729980468750, +-0.0033264160156250, -0.0049133300781250, -0.0024719238281250, -0.0059814453125000, +-0.0036315917968750, -0.0055847167968750, -0.0062561035156250, -0.0050659179687500, +-0.0053710937500000, -0.0068664550781250, -0.0081481933593750, -0.0068054199218750, +-0.0081481933593750, -0.0059509277343750, -0.0076599121093750, -0.0062255859375000, +-0.0092468261718750, -0.0061950683593750, -0.0092468261718750, -0.0058288574218750, +-0.0063171386718750, -0.0062561035156250, -0.0068969726562500, -0.0046081542968750, +-0.0061340332031250, -0.0031433105468750, -0.0036926269531250, -0.0047912597656250, +-0.0047302246093750, -0.0026550292968750, -0.0045471191406250, -0.0018615722656250, +-0.0039672851562500, -0.0025329589843750, -0.0054016113281250, -0.0023803710937500, +-0.0070190429687500, -0.0022583007812500, -0.0068664550781250, -0.0034484863281250, +-0.0087585449218750}, +{0.0049133300781250, -0.0026245117187500, -0.0026855468750000, -0.0014343261718750, +-0.0028076171875000, -0.0031127929687500, -0.0012512207031250, -0.0068054199218750, +-0.0037231445312500, -0.0047607421875000, -0.0042724609375000, -0.0068359375000000, +-0.0061645507812500, -0.0079345703125000, -0.0036010742187500, -0.0066223144531250, +-0.0056762695312500, -0.0059814453125000, -0.0098571777343750, -0.0063476562500000, +-0.0078125000000000, -0.0046997070312500, -0.0126953125000000, -0.0059509277343750, +-0.0130920410156250, -0.0033874511718750, -0.0110168457031250, 0.0000000000000000, +-0.0120849609375000, -0.0024719238281250, -0.0132751464843750, 0.0017395019531250, +-0.0107116699218750, 0.0017089843750000, -0.0097656250000000, 0.0025634765625000, +-0.0104064941406250, 0.0049133300781250, -0.0100708007812500, 0.0033569335937500, +-0.0093688964843750, 0.0072021484375000, -0.0111083984375000, 0.0075378417968750, +-0.0111389160156250, 0.0058898925781250, -0.0113830566406250, 0.0072326660156250, +-0.0119934082031250, 0.0078430175781250, -0.0110473632812500, 0.0025329589843750, +-0.0120544433593750, 0.0033569335937500, -0.0133056640625000, 0.0026245117187500, +-0.0109252929687500, -0.0016174316406250, -0.0086364746093750, -0.0010681152343750, +-0.0085754394531250, -0.0013427734375000, -0.0023193359375000, -0.0013732910156250, +-0.0044860839843750, -0.0023803710937500, -0.0040893554687500, -0.0027160644531250, +0.0009460449218750, -0.0018920898437500, -0.0005798339843750, -0.0064697265625000, +-0.0001525878906250, -0.0056457519531250, 0.0004272460937500, -0.0066223144531250, +0.0003662109375000, -0.0102844238281250, -0.0003967285156250, -0.0086975097656250, +-0.0003967285156250, -0.0090332031250000, 0.0036010742187500, -0.0092468261718750, +0.0021972656250000, -0.0114440917968750, 0.0031433105468750, -0.0120544433593750, +0.0070800781250000, -0.0099182128906250, 0.0057373046875000, -0.0178833007812500, +0.0063171386718750, -0.0174255371093750, 0.0074768066406250, -0.0175476074218750, +0.0051574707031250, -0.0231933593750000, 0.0031738281250000, -0.0217285156250000, +0.0049438476562500, -0.0152587890625000, 0.0013122558593750, -0.0185241699218750, +0.0003967285156250, -0.0159912109375000, 0.0011901855468750, -0.0079345703125000, +0.0005798339843750, -0.0111083984375000, 0.0001831054687500, -0.0121459960937500, +-0.0000305175781250, -0.0093078613281250, 0.0007629394531250, -0.0098571777343750, +-0.0009460449218750, -0.0143737792968750, -0.0032043457031250, -0.0139160156250000, +-0.0018310546875000, -0.0057678222656250, -0.0025024414062500, -0.0082397460937500, +-0.0037231445312500, -0.0067138671875000, -0.0031738281250000, 0.0003967285156250, +-0.0020446777343750, -0.0022277832031250, -0.0021972656250000, -0.0024108886718750, +-0.0023803710937500, 0.0001220703125000, -0.0019226074218750, -0.0024719238281250, +-0.0029296875000000, -0.0061950683593750, -0.0034484863281250, -0.0039978027343750, +-0.0025634765625000, -0.0063171386718750, -0.0072326660156250, -0.0070495605468750, +-0.0064697265625000, -0.0063476562500000, -0.0081176757812500, -0.0069885253906250, +-0.0122680664062500, -0.0071105957031250, -0.0109558105468750, -0.0046997070312500, +-0.0142517089843750, -0.0052795410156250, -0.0151367187500000, -0.0055541992187500, +-0.0154418945312500, -0.0039367675781250, -0.0168762207031250, -0.0040588378906250, +-0.0170288085937500, -0.0046997070312500, -0.0180664062500000, -0.0045166015625000, +-0.0181579589843750, -0.0055541992187500, -0.0186462402343750, -0.0064392089843750, +-0.0192871093750000, -0.0056457519531250, -0.0184326171875000, -0.0089416503906250, +-0.0179748535156250, -0.0087585449218750, -0.0183715820312500, -0.0092468261718750, +-0.0158081054687500, -0.0112304687500000, -0.0138854980468750, -0.0106811523437500, +-0.0150146484375000, -0.0129394531250000, -0.0088500976562500, -0.0126037597656250, +-0.0093383789062500, -0.0132751464843750, -0.0058898925781250, -0.0151367187500000, +0.0001220703125000, -0.0144348144531250, -0.0016479492187500, -0.0155334472656250, +0.0063476562500000, -0.0156860351562500, 0.0065612792968750, -0.0160217285156250, +0.0090026855468750, -0.0165710449218750, 0.0148315429687500, -0.0160217285156250, +0.0134887695312500, -0.0172119140625000, 0.0193176269531250, -0.0173034667968750, +0.0196838378906250, -0.0169677734375000, 0.0209350585937500, -0.0173950195312500, +0.0247802734375000, -0.0172729492187500, 0.0236511230468750, -0.0159606933593750, +0.0254516601562500, -0.0164489746093750, 0.0255432128906250, -0.0153503417968750, +0.0249328613281250, -0.0139770507812500, 0.0253601074218750, -0.0148925781250000, +0.0249023437500000, -0.0113830566406250, 0.0235900878906250, -0.0121459960937500, +0.0232543945312500, -0.0107727050781250, 0.0223693847656250, -0.0077209472656250, +0.0210876464843750, -0.0093688964843750, 0.0208129882812500, -0.0064697265625000, +0.0191040039062500, -0.0058898925781250, 0.0177612304687500, -0.0064392089843750, +0.0178833007812500, -0.0054016113281250, 0.0168762207031250, -0.0053710937500000, +0.0149536132812500, -0.0068359375000000, 0.0175476074218750, -0.0061340332031250, +0.0152282714843750, -0.0068664550781250, 0.0161437988281250, -0.0083007812500000, +0.0187072753906250, -0.0072937011718750, 0.0159301757812500, -0.0092163085937500, +0.0216674804687500, -0.0090332031250000, 0.0188903808593750, -0.0092468261718750, +0.0201721191406250, -0.0103149414062500, 0.0246582031250000, -0.0096130371093750, +0.0199890136718750, -0.0109863281250000, 0.0261840820312500, -0.0107421875000000, +0.0252075195312500, -0.0108947753906250, 0.0263061523437500, -0.0117492675781250, +0.0308532714843750, -0.0111999511718750, 0.0285644531250000, -0.0121765136718750, +0.0331115722656250, -0.0115661621093750, 0.0331115722656250, -0.0128479003906250, +0.0327148437500000, -0.0141296386718750, 0.0350036621093750, -0.0129394531250000, +0.0339660644531250, -0.0176086425781250, 0.0323181152343750, -0.0172729492187500, +0.0342407226562500, -0.0182800292968750, 0.0307312011718750, -0.0216979980468750, +0.0277099609375000, -0.0205078125000000, 0.0317077636718750, -0.0221557617187500, +0.0216064453125000, -0.0227661132812500, 0.0231628417968750, -0.0226745605468750, +0.0195312500000000, -0.0233459472656250, 0.0121765136718750, -0.0234069824218750, +0.0170593261718750, -0.0224609375000000, 0.0048828125000000, -0.0237426757812500, +0.0075683593750000, -0.0217285156250000, 0.0044250488281250, -0.0197143554687500, +-0.0048522949218750, -0.0216674804687500, 0.0007324218750000, -0.0155944824218750, +-0.0099792480468750, -0.0166931152343750, -0.0081176757812500, -0.0149841308593750, +-0.0098876953125000, -0.0102539062500000, -0.0168762207031250, -0.0126342773437500, +-0.0126342773437500, -0.0079345703125000, -0.0220336914062500, -0.0079345703125000, +-0.0204467773437500, -0.0076599121093750, -0.0231323242187500, -0.0048522949218750, +-0.0312500000000000, -0.0058593750000000, -0.0275573730468750, -0.0056457519531250, +-0.0326538085937500, -0.0048522949218750, -0.0346374511718750, -0.0058593750000000, +-0.0318603515625000, -0.0068664550781250, -0.0325012207031250, -0.0062561035156250, +-0.0338134765625000, -0.0086669921875000, -0.0231933593750000, -0.0083923339843750, +-0.0263977050781250, -0.0084838867187500, -0.0203857421875000, -0.0106506347656250, +-0.0094299316406250, -0.0101928710937500, -0.0152587890625000, -0.0068664550781250, +-0.0012817382812500, -0.0083618164062500, -0.0012207031250000, -0.0072021484375000, +-0.0003356933593750, -0.0033874511718750, 0.0079040527343750, -0.0043640136718750, +0.0051269531250000, -0.0039062500000000, 0.0053405761718750, -0.0036010742187500, +0.0083007812500000, -0.0030212402343750, 0.0051574707031250, -0.0022277832031250, +0.0016479492187500, -0.0028076171875000, 0.0044555664062500, -0.0036315917968750, +-0.0012207031250000, -0.0016784667968750, -0.0028991699218750, -0.0048828125000000, +0.0003662109375000, -0.0085449218750000, 0.0010070800781250, -0.0055847167968750, +-0.0009460449218750, -0.0117797851562500, 0.0025939941406250, -0.0124206542968750, +0.0025024414062500, -0.0112304687500000, 0.0025024414062500, -0.0135192871093750, +0.0055541992187500, -0.0137329101562500, 0.0047607421875000, -0.0111694335937500, +-0.0018920898437500, -0.0103454589843750, 0.0008239746093750, -0.0134277343750000, +-0.0021972656250000, -0.0141601562500000, -0.0097961425781250, -0.0118713378906250, +-0.0062255859375000, -0.0197448730468750, -0.0080261230468750, -0.0198059082031250, +-0.0110778808593750, -0.0185546875000000, -0.0084228515625000, -0.0224609375000000, +-0.0043640136718750, -0.0221862792968750, -0.0062866210937500, -0.0154724121093750, +-0.0087280273437500, -0.0173645019531250, -0.0061645507812500, -0.0162963867187500, +-0.0094909667968750, -0.0079040527343750, -0.0185852050781250, -0.0141296386718750, +-0.0088195800781250, -0.0113830566406250, -0.0145874023437500, -0.0140686035156250, +-0.0092468261718750, -0.0103759765625000, -0.0134887695312500, -0.0065612792968750, +-0.0212402343750000, -0.0095214843750000, -0.0184631347656250, -0.0026245117187500, +-0.0202941894531250, -0.0024719238281250, -0.0230102539062500, -0.0025634765625000, +-0.0185546875000000, 0.0009460449218750, -0.0149841308593750, -0.0001220703125000, +-0.0183105468750000, -0.0005798339843750, -0.0114135742187500, -0.0002746582031250, +-0.0116271972656250, 0.0001220703125000, -0.0087585449218750, -0.0005187988281250, +-0.0037231445312500, -0.0007934570312500, -0.0074157714843750, 0.0039672851562500, +-0.0004882812500000, 0.0020141601562500, 0.0003051757812500, 0.0032653808593750, +0.0001220703125000, 0.0093383789062500, 0.0035705566406250, 0.0075683593750000, +0.0022583007812500, 0.0022277832031250, -0.0010986328125000, 0.0051269531250000, +0.0011596679687500, 0.0033874511718750, -0.0003356933593750, -0.0023803710937500, +-0.0053405761718750, -0.0002441406250000, -0.0038452148437500, -0.0030212402343750, +-0.0025939941406250, -0.0030822753906250, -0.0038452148437500, -0.0031738281250000, +-0.0022888183593750, -0.0048828125000000, 0.0005187988281250, -0.0042419433593750, +-0.0010681152343750, -0.0035095214843750, -0.0011901855468750, -0.0027160644531250, +0.0019531250000000, -0.0069580078125000, -0.0040588378906250, -0.0081481933593750, +-0.0096435546875000, -0.0045166015625000, -0.0046081542968750, -0.0202941894531250, +-0.0163269042968750, -0.0170898437500000, -0.0175170898437500, -0.0213623046875000, +-0.0159912109375000, -0.0338134765625000, -0.0201416015625000, -0.0271301269531250, +-0.0198059082031250, -0.0354919433593750, -0.0184020996093750, -0.0384826660156250, +-0.0179443359375000, -0.0332336425781250, -0.0193786621093750, -0.0340881347656250, +-0.0201110839843750, -0.0372009277343750, -0.0188903808593750, -0.0222473144531250, +-0.0209350585937500, -0.0260314941406250, -0.0220642089843750, -0.0214538574218750, +-0.0202026367187500, -0.0090942382812500, -0.0189208984375000, -0.0156250000000000, +-0.0202026367187500, -0.0037841796875000, -0.0189514160156250, -0.0043334960937500, +-0.0173339843750000, -0.0032958984375000, -0.0196838378906250, 0.0034484863281250, +-0.0218505859375000, 0.0001220703125000, -0.0201416015625000, 0.0057678222656250, +-0.0233154296875000, 0.0055236816406250, -0.0243530273437500, 0.0053405761718750, +-0.0232238769531250, 0.0079345703125000, -0.0233154296875000, 0.0066223144531250, +-0.0240478515625000, 0.0094909667968750, -0.0233459472656250, 0.0084838867187500, +-0.0231018066406250, 0.0095520019531250, -0.0235900878906250, 0.0121154785156250, +-0.0240783691406250, 0.0101928710937500, -0.0238647460937500, 0.0133972167968750, +-0.0230407714843750, 0.0135498046875000, -0.0238952636718750, 0.0130004882812500, +-0.0226745605468750}, +{0.0040893554687500, -0.0098876953125000, 0.0016784667968750, -0.0177001953125000, +0.0030212402343750, -0.0146789550781250, 0.0039367675781250, -0.0143432617187500, +-0.0065612792968750, -0.0169067382812500, -0.0036926269531250, -0.0147094726562500, +-0.0057373046875000, -0.0107116699218750, -0.0155029296875000, -0.0125122070312500, +-0.0123901367187500, -0.0134277343750000, -0.0108337402343750, -0.0119018554687500, +-0.0134582519531250, -0.0123596191406250, -0.0118408203125000, -0.0151062011718750, +-0.0060729980468750, -0.0104980468750000, -0.0151062011718750, -0.0015869140625000, +-0.0120849609375000, -0.0015563964843750, -0.0149536132812500, -0.0038452148437500, +-0.0143432617187500, -0.0035400390625000, -0.0104064941406250, -0.0018310546875000, +-0.0110778808593750, -0.0050048828125000, -0.0171813964843750, -0.0069580078125000, +-0.0141906738281250, -0.0035400390625000, -0.0179443359375000, -0.0019226074218750, +-0.0269470214843750, -0.0044860839843750, -0.0228576660156250, 0.0031433105468750, +-0.0213928222656250, 0.0034484863281250, -0.0265502929687500, 0.0018310546875000, +-0.0192871093750000, 0.0051269531250000, -0.0112609863281250, 0.0050964355468750, +-0.0172729492187500, -0.0008544921875000, -0.0010681152343750, 0.0016479492187500, +-0.0004577636718750, -0.0013732910156250, -0.0016784667968750, -0.0089721679687500, +0.0053405761718750, -0.0052490234375000, 0.0040283203125000, -0.0041809082031250, +0.0036621093750000, -0.0069274902343750, 0.0044555664062500, -0.0065307617187500, +0.0028686523437500, -0.0025024414062500, 0.0014953613281250, -0.0028686523437500, +0.0028076171875000, -0.0095520019531250, 0.0004577636718750, -0.0060729980468750, +0.0001831054687500, -0.0109558105468750, -0.0004577636718750, -0.0186462402343750, +-0.0016784667968750, -0.0137634277343750, -0.0006408691406250, -0.0286254882812500, +-0.0015258789062500, -0.0275573730468750, -0.0025634765625000, -0.0264892578125000, +-0.0020446777343750, -0.0358886718750000, -0.0003051757812500, -0.0339965820312500, +-0.0009460449218750, -0.0246276855468750, -0.0068054199218750, -0.0295715332031250, +-0.0034790039062500, -0.0223388671875000, -0.0079956054687500, -0.0112304687500000, +-0.0165100097656250, -0.0184020996093750, -0.0120849609375000, 0.0004272460937500, +-0.0184936523437500, -0.0010681152343750, -0.0203857421875000, 0.0009460449218750, +-0.0184936523437500, 0.0127868652343750, -0.0187377929687500, 0.0077209472656250, +-0.0192565917968750, 0.0137939453125000, -0.0201416015625000, 0.0148315429687500, +-0.0187072753906250, 0.0146789550781250, -0.0204162597656250, 0.0168457031250000, +-0.0235900878906250, 0.0153808593750000, -0.0220336914062500, 0.0178527832031250, +-0.0219116210937500, 0.0180969238281250, -0.0235290527343750, 0.0176696777343750, +-0.0220336914062500, 0.0187683105468750, -0.0193176269531250, 0.0186767578125000, +-0.0205993652343750, 0.0174255371093750, -0.0214538574218750, 0.0181884765625000, +-0.0198364257812500, 0.0173339843750000, -0.0218200683593750, 0.0160827636718750, +-0.0248718261718750, 0.0168762207031250, -0.0233459472656250, 0.0127563476562500, +-0.0252685546875000, 0.0146789550781250, -0.0261230468750000, 0.0119628906250000, +-0.0254211425781250, 0.0072021484375000, -0.0252990722656250, 0.0103759765625000, +-0.0255432128906250, 0.0038146972656250, -0.0249023437500000, 0.0042419433593750, +-0.0252075195312500, 0.0041809082031250, -0.0241394042968750, 0.0002441406250000, +-0.0233154296875000, 0.0014953613281250, -0.0241699218750000, 0.0005493164062500, +-0.0205993652343750, -0.0004577636718750, -0.0210876464843750, 0.0010986328125000, +-0.0202636718750000, 0.0016784667968750, -0.0177001953125000, 0.0002136230468750, +-0.0188598632812500, 0.0040893554687500, -0.0166931152343750, 0.0028381347656250, +-0.0170288085937500, 0.0043029785156250, -0.0161437988281250, 0.0072326660156250, +-0.0145568847656250, 0.0044250488281250, -0.0156860351562500, 0.0097961425781250, +-0.0124206542968750, 0.0087890625000000, -0.0128784179687500, 0.0093994140625000, +-0.0116577148437500, 0.0128784179687500, -0.0089721679687500, 0.0108032226562500, +-0.0101928710937500, 0.0139770507812500, -0.0066223144531250, 0.0138549804687500, +-0.0063476562500000, 0.0140686035156250, -0.0060119628906250, 0.0156555175781250, +-0.0037231445312500, 0.0142517089843750, -0.0039672851562500, 0.0158691406250000, +-0.0042419433593750, 0.0155639648437500, -0.0032043457031250, 0.0151062011718750, +-0.0040588378906250, 0.0158386230468750, -0.0054626464843750, 0.0152893066406250, +-0.0044250488281250, 0.0145568847656250, -0.0065612792968750, 0.0148620605468750, +-0.0070190429687500, 0.0139465332031250, -0.0066528320312500, 0.0130004882812500, +-0.0074462890625000, 0.0133361816406250, -0.0079040527343750, 0.0100708007812500, +-0.0075683593750000, 0.0102844238281250, -0.0072631835937500, 0.0088195800781250, +-0.0088500976562500, 0.0059509277343750, -0.0097045898437500, 0.0067138671875000, +-0.0086975097656250, 0.0032348632812500, -0.0125732421875000, 0.0027770996093750, +-0.0121765136718750, 0.0018005371093750, -0.0126953125000000, -0.0005493164062500, +-0.0148010253906250, -0.0002136230468750, -0.0136413574218750, -0.0017700195312500, +-0.0165100097656250, -0.0027770996093750, -0.0158996582031250, -0.0023498535156250, +-0.0160522460937500, -0.0027160644531250, -0.0185241699218750, -0.0036926269531250, +-0.0178833007812500, -0.0018310546875000, -0.0166625976562500, -0.0029602050781250, +-0.0179443359375000, -0.0012207031250000, -0.0170288085937500, 0.0011291503906250, +-0.0151672363281250, -0.0010986328125000, -0.0162658691406250, 0.0042724609375000, +-0.0134277343750000, 0.0037536621093750, -0.0144958496093750, 0.0058593750000000, +-0.0123901367187500, 0.0101623535156250, -0.0091857910156250, 0.0085754394531250, +-0.0114746093750000, 0.0156250000000000, -0.0056762695312500, 0.0151977539062500, +-0.0057678222656250, 0.0170898437500000, -0.0057373046875000, 0.0222778320312500, +-0.0022583007812500, 0.0200805664062500, -0.0031738281250000, 0.0234069824218750, +-0.0050964355468750, 0.0247497558593750, -0.0040283203125000, 0.0228881835937500, +-0.0035095214843750, 0.0232238769531250, -0.0058593750000000, 0.0241088867187500, +-0.0060729980468750, 0.0170288085937500, -0.0008544921875000, 0.0187377929687500, +-0.0023803710937500, 0.0147399902343750, -0.0016479492187500, 0.0077819824218750, +0.0024719238281250, 0.0112915039062500, 0.0012817382812500, 0.0014038085937500, +0.0032653808593750, 0.0021667480468750, 0.0038757324218750, -0.0009155273437500, +0.0024719238281250, -0.0080871582031250, 0.0030517578125000, -0.0048217773437500, +0.0039367675781250, -0.0147399902343750, -0.0020446777343750, -0.0145263671875000, +-0.0007019042968750, -0.0147094726562500, -0.0003967285156250, -0.0203857421875000, +-0.0049743652343750, -0.0186157226562500, -0.0043029785156250, -0.0181274414062500, +-0.0006713867187500, -0.0197143554687500, -0.0014038085937500, -0.0172424316406250, +-0.0012512207031250, -0.0150146484375000, 0.0014953613281250, -0.0166625976562500, +0.0005798339843750, -0.0095520019531250, -0.0033264160156250, -0.0105590820312500, +-0.0003662109375000, -0.0090026855468750, -0.0036010742187500, -0.0033874511718750, +-0.0102539062500000, -0.0055847167968750, -0.0073242187500000, -0.0036315917968750, +-0.0105590820312500, -0.0024719238281250, -0.0114440917968750, -0.0043334960937500, +-0.0103454589843750, -0.0054321289062500, -0.0109863281250000, -0.0040588378906250, +-0.0116271972656250, -0.0049438476562500, -0.0106811523437500, -0.0067443847656250, +-0.0101013183593750, -0.0042724609375000, -0.0103759765625000, -0.0018920898437500, +-0.0104980468750000, -0.0036926269531250, -0.0105285644531250, 0.0004272460937500, +-0.0121154785156250, 0.0010986328125000, -0.0121459960937500, -0.0004577636718750, +-0.0108642578125000, 0.0004272460937500, -0.0106811523437500, 0.0010681152343750, +-0.0116882324218750, -0.0021667480468750, -0.0104370117187500, -0.0018310546875000, +-0.0102539062500000, -0.0025939941406250, -0.0094909667968750, -0.0052490234375000, +-0.0088195800781250, -0.0050048828125000, -0.0087585449218750, -0.0066528320312500, +-0.0041198730468750, -0.0064086914062500, -0.0063171386718750, -0.0068359375000000, +-0.0050354003906250, -0.0076904296875000, -0.0004882812500000, -0.0069885253906250, +-0.0026855468750000, -0.0100097656250000, 0.0001220703125000, -0.0092468261718750, +0.0008544921875000, -0.0099182128906250, -0.0005798339843750, -0.0125732421875000, +-0.0004272460937500, -0.0116271972656250, -0.0000915527343750, -0.0120849609375000, +-0.0023498535156250, -0.0121765136718750, -0.0020751953125000, -0.0127258300781250, +-0.0035400390625000, -0.0133361816406250, -0.0057678222656250, -0.0127563476562500, +-0.0042724609375000, -0.0131530761718750, -0.0060119628906250, -0.0126953125000000, +-0.0074157714843750, -0.0132446289062500, -0.0057373046875000, -0.0140686035156250, +-0.0050048828125000, -0.0133361816406250, -0.0061950683593750, -0.0148010253906250, +-0.0014953613281250, -0.0147705078125000, -0.0026550292968750, -0.0134277343750000, +-0.0013732910156250, -0.0140075683593750, 0.0029296875000000, -0.0149841308593750, +0.0010070800781250, -0.0104675292968750, 0.0018615722656250, -0.0113830566406250, +0.0040283203125000, -0.0098266601562500, 0.0000000000000000, -0.0053100585937500, +-0.0027770996093750, -0.0074462890625000, 0.0003356933593750, -0.0090026855468750, +-0.0096435546875000, -0.0063476562500000, -0.0097351074218750, -0.0070190429687500, +-0.0101623535156250, -0.0109863281250000, -0.0156250000000000, -0.0103149414062500, +-0.0140075683593750, -0.0079040527343750, -0.0148010253906250, -0.0092773437500000, +-0.0162963867187500, -0.0079650878906250, -0.0141296386718750, -0.0049133300781250, +-0.0122985839843750, -0.0069580078125000, -0.0136718750000000, -0.0068664550781250, +-0.0095214843750000, -0.0049133300781250, -0.0092773437500000, -0.0072326660156250, +-0.0079956054687500, -0.0100097656250000, -0.0053405761718750, -0.0083312988281250, +-0.0056152343750000, -0.0119934082031250, 0.0000915527343750, -0.0120849609375000, +-0.0004882812500000, -0.0120849609375000, 0.0033264160156250, -0.0144348144531250, +0.0094909667968750, -0.0141906738281250, 0.0072631835937500, -0.0128173828125000, +0.0141296386718750, -0.0136108398437500, 0.0152893066406250, -0.0139160156250000, +0.0144348144531250, -0.0128784179687500, 0.0166625976562500, -0.0130920410156250, +0.0158996582031250, -0.0135803222656250, 0.0122680664062500, -0.0137939453125000, +0.0131530761718750, -0.0136108398437500, 0.0100708007812500, -0.0136413574218750, +0.0057067871093750, -0.0137939453125000, 0.0076599121093750, -0.0128479003906250, +0.0017089843750000, -0.0134582519531250, 0.0011291503906250, -0.0122375488281250, +0.0003967285156250, -0.0105590820312500, -0.0030212402343750, -0.0117187500000000, +-0.0021972656250000, -0.0097351074218750, -0.0024719238281250, -0.0091857910156250, +-0.0032043457031250, -0.0094299316406250, -0.0024108886718750, -0.0090942382812500, +-0.0015869140625000, -0.0090332031250000, -0.0018310546875000, -0.0077819824218750, +0.0003356933593750, -0.0080871582031250, 0.0002746582031250, -0.0077819824218750, +0.0016784667968750, -0.0064392089843750, 0.0038757324218750, -0.0068054199218750, +0.0033569335937500, -0.0071105957031250, 0.0060424804687500, -0.0064086914062500, +0.0067749023437500, -0.0070190429687500, 0.0071411132812500, -0.0079040527343750, +0.0081787109375000, -0.0072326660156250, 0.0080566406250000, -0.0082092285156250, +0.0091247558593750, -0.0082397460937500, 0.0092163085937500, -0.0080871582031250, +0.0099487304687500, -0.0085144042968750, 0.0110168457031250, -0.0084533691406250, +0.0105590820312500}, +{-0.0039978027343750, -0.0112304687500000, -0.0041198730468750, -0.0078430175781250, +-0.0055236816406250, -0.0078430175781250, -0.0057067871093750, -0.0090332031250000, +-0.0058593750000000, -0.0077819824218750, -0.0064086914062500, -0.0070190429687500, +-0.0067443847656250, -0.0097961425781250, -0.0078430175781250, -0.0103454589843750, +-0.0078125000000000, -0.0091247558593750, -0.0070495605468750, -0.0092773437500000, +-0.0079345703125000, -0.0097656250000000, -0.0087280273437500, -0.0076293945312500, +-0.0043640136718750, -0.0076293945312500, -0.0054016113281250, -0.0081787109375000, +-0.0041503906250000, -0.0067749023437500, -0.0003051757812500, -0.0061645507812500, +-0.0025329589843750, -0.0090942382812500, -0.0016174316406250, -0.0085144042968750, +0.0007629394531250, -0.0086364746093750, -0.0032958984375000, -0.0111389160156250, +-0.0064392089843750, -0.0103454589843750, -0.0035095214843750, -0.0067749023437500, +-0.0128173828125000, -0.0082397460937500, -0.0122680664062500, -0.0080566406250000, +-0.0123291015625000, -0.0048522949218750, -0.0183410644531250, -0.0054016113281250, +-0.0169677734375000, -0.0062255859375000, -0.0141906738281250, -0.0048828125000000, +-0.0166015625000000, -0.0073852539062500, -0.0134582519531250, -0.0103454589843750, +-0.0090637207031250, -0.0076293945312500, -0.0117797851562500, -0.0095214843750000, +-0.0032958984375000, -0.0112609863281250, -0.0040283203125000, -0.0101928710937500, +-0.0017089843750000, -0.0091552734375000, 0.0045166015625000, -0.0097656250000000, +0.0019226074218750, -0.0092773437500000, 0.0083007812500000, -0.0088806152343750, +0.0083618164062500, -0.0107421875000000, 0.0098266601562500, -0.0115661621093750, +0.0141601562500000, -0.0101928710937500, 0.0120239257812500, -0.0135498046875000, +0.0138244628906250, -0.0139465332031250, 0.0150146484375000, -0.0143127441406250, +0.0121765136718750, -0.0158386230468750, 0.0105590820312500, -0.0151977539062500, +0.0115051269531250, -0.0169067382812500, 0.0051879882812500, -0.0174865722656250, +0.0048522949218750, -0.0164184570312500, 0.0033874511718750, -0.0163879394531250, +-0.0006408691406250, -0.0172729492187500, 0.0007629394531250, -0.0150451660156250, +-0.0011291503906250, -0.0155029296875000, -0.0016174316406250, -0.0144958496093750, +-0.0003662109375000, -0.0127258300781250, -0.0001831054687500, -0.0140380859375000, +-0.0002746582031250, -0.0111999511718750, 0.0022583007812500, -0.0112304687500000, +0.0020751953125000, -0.0108337402343750, 0.0031433105468750, -0.0093383789062500, +0.0054626464843750, -0.0099487304687500, 0.0047912597656250, -0.0074462890625000, +0.0061645507812500, -0.0077514648437500, 0.0068054199218750, -0.0075073242187500, +0.0066833496093750, -0.0055541992187500, 0.0070190429687500, -0.0060729980468750, +0.0072021484375000, -0.0064392089843750, 0.0062255859375000, -0.0059814453125000, +0.0063171386718750, -0.0059509277343750, 0.0050048828125000, -0.0065612792968750, +0.0036926269531250, -0.0064086914062500, 0.0042114257812500, -0.0052795410156250, +0.0007019042968750, -0.0053710937500000, 0.0005187988281250, -0.0054016113281250, +-0.0005798339843750, -0.0045166015625000, -0.0030212402343750, -0.0044555664062500, +-0.0021667480468750, -0.0057678222656250, -0.0043640136718750, -0.0051574707031250, +-0.0045776367187500, -0.0057983398437500, -0.0046081542968750, -0.0071716308593750, +-0.0057067871093750, -0.0064392089843750, -0.0053100585937500, -0.0078125000000000, +-0.0053100585937500, -0.0079345703125000, -0.0056152343750000, -0.0077819824218750, +-0.0056762695312500, -0.0084533691406250, -0.0056152343750000, -0.0083923339843750, +-0.0057983398437500, -0.0074462890625000, -0.0059814453125000, -0.0081787109375000, +-0.0065612792968750, -0.0072937011718750, -0.0064392089843750, -0.0057373046875000, +-0.0062866210937500, -0.0068054199218750, -0.0068359375000000, -0.0065002441406250, +-0.0059509277343750, -0.0053100585937500, -0.0067749023437500, -0.0076293945312500, +-0.0065002441406250, -0.0093383789062500, -0.0055236816406250, -0.0076599121093750, +-0.0064392089843750, -0.0132446289062500, -0.0044250488281250, -0.0131225585937500, +-0.0053100585937500, -0.0132446289062500, -0.0033264160156250, -0.0165100097656250, +-0.0010375976562500, -0.0155944824218750, -0.0030517578125000, -0.0148925781250000, +0.0042419433593750, -0.0158081054687500, 0.0020751953125000, -0.0143432617187500, +0.0050354003906250, -0.0124206542968750, 0.0112304687500000, -0.0131835937500000, +0.0070800781250000, -0.0103759765625000, 0.0166625976562500, -0.0101013183593750, +0.0153808593750000, -0.0094299316406250, 0.0165100097656250, -0.0074768066406250, +0.0232849121093750, -0.0079040527343750, 0.0207214355468750, -0.0069274902343750, +0.0236206054687500, -0.0064697265625000, 0.0252380371093750, -0.0066223144531250, +0.0230102539062500, -0.0064086914062500, 0.0228881835937500, -0.0062561035156250, +0.0244140625000000, -0.0069274902343750, 0.0173339843750000, -0.0063476562500000, +0.0204162597656250, -0.0074768066406250, 0.0168151855468750, -0.0086975097656250, +0.0090637207031250, -0.0076599121093750, 0.0138549804687500, -0.0112915039062500, +0.0063476562500000, -0.0110168457031250, 0.0058593750000000, -0.0113220214843750, +0.0074462890625000, -0.0136108398437500, 0.0046691894531250, -0.0129089355468750, +0.0053100585937500, -0.0134582519531250, 0.0080871582031250, -0.0135192871093750, +0.0079956054687500, -0.0142822265625000, 0.0075378417968750, -0.0148315429687500, +0.0084533691406250, -0.0140686035156250, 0.0088195800781250, -0.0163879394531250, +0.0086975097656250, -0.0170288085937500, 0.0078125000000000, -0.0153808593750000, +0.0090026855468750, -0.0155029296875000, 0.0098876953125000, -0.0166320800781250, +0.0087890625000000, -0.0119018554687500, 0.0133666992187500, -0.0121765136718750, +0.0120849609375000, -0.0118103027343750, 0.0142517089843750, -0.0088500976562500, +0.0189819335937500, -0.0097961425781250, 0.0166320800781250, -0.0094909667968750, +0.0204467773437500, -0.0086059570312500, 0.0223083496093750, -0.0097656250000000, +0.0184020996093750, -0.0114135742187500, 0.0183715820312500, -0.0102539062500000, +0.0210876464843750, -0.0095825195312500, 0.0065917968750000, -0.0120544433593750, +0.0114746093750000, -0.0075073242187500, 0.0035095214843750, -0.0026855468750000, +-0.0118408203125000, -0.0066528320312500, -0.0033264160156250, 0.0018310546875000, +-0.0208435058593750, 0.0027465820312500, -0.0229797363281250, 0.0025329589843750, +-0.0195312500000000, 0.0061035156250000, -0.0260620117187500, 0.0044860839843750, +-0.0263366699218750, 0.0033264160156250, -0.0172424316406250, 0.0058898925781250, +-0.0199890136718750, 0.0021362304687500, -0.0135192871093750, -0.0028686523437500, +-0.0036315917968750, 0.0000610351562500, -0.0101623535156250, -0.0050659179687500, +0.0024414062500000, -0.0050964355468750, 0.0060729980468750, -0.0073242187500000, +0.0022277832031250, -0.0114440917968750, 0.0041503906250000, -0.0086059570312500, +0.0052185058593750, -0.0122680664062500, -0.0039978027343750, -0.0151672363281250, +-0.0027770996093750, -0.0101013183593750, -0.0019531250000000, -0.0069885253906250, +-0.0075073242187500, -0.0107727050781250, -0.0075073242187500, -0.0018310546875000, +-0.0046691894531250, -0.0007629394531250, -0.0046997070312500, -0.0026550292968750, +-0.0060729980468750, 0.0005187988281250, -0.0058898925781250, 0.0007629394531250, +-0.0100402832031250, 0.0002441406250000, -0.0051574707031250, -0.0004577636718750, +-0.0055847167968750, -0.0013732910156250, -0.0074462890625000, -0.0003662109375000, +-0.0065917968750000, 0.0002746582031250, -0.0054016113281250, -0.0072326660156250, +-0.0126037597656250, -0.0047912597656250, -0.0119934082031250, -0.0078735351562500, +-0.0108337402343750, -0.0154418945312500, -0.0151062011718750, -0.0116577148437500, +-0.0154724121093750, -0.0157165527343750, -0.0101013183593750, -0.0174560546875000, +-0.0099182128906250, -0.0164489746093750, -0.0121765136718750, -0.0160522460937500, +-0.0107116699218750, -0.0161743164062500, -0.0096740722656250, -0.0180358886718750, +-0.0158691406250000, -0.0157165527343750, -0.0167541503906250, -0.0202026367187500, +-0.0123901367187500, -0.0260314941406250, -0.0141906738281250, -0.0208740234375000, +-0.0172424316406250, -0.0237731933593750, 0.0004577636718750, -0.0297546386718750, +-0.0020141601562500, -0.0197448730468750, -0.0003662109375000, -0.0119934082031250, +0.0122070312500000, -0.0195617675781250, 0.0081787109375000, 0.0025634765625000, +0.0067138671875000, 0.0004272460937500, 0.0104675292968750, 0.0041503906250000, +0.0061950683593750, 0.0193481445312500, -0.0004577636718750, 0.0124206542968750, +0.0029602050781250, 0.0197753906250000, 0.0011901855468750, 0.0240478515625000, +-0.0005798339843750, 0.0185852050781250, -0.0006103515625000, 0.0161132812500000, +0.0004272460937500, 0.0193786621093750, 0.0009155273437500, 0.0117492675781250, +-0.0032348632812500, 0.0119628906250000, -0.0025329589843750, 0.0112304687500000, +-0.0036315917968750, 0.0065307617187500, -0.0066223144531250, 0.0086364746093750, +-0.0053405761718750, 0.0087890625000000, -0.0086669921875000, 0.0069274902343750, +-0.0081481933593750, 0.0092163085937500, -0.0093994140625000, 0.0119628906250000, +-0.0119628906250000, 0.0099487304687500, -0.0105285644531250, 0.0122680664062500, +-0.0149536132812500, 0.0130920410156250, -0.0149230957031250, 0.0130615234375000, +-0.0149536132812500, 0.0131835937500000, -0.0174560546875000, 0.0128479003906250, +-0.0170593261718750, 0.0156555175781250, -0.0168457031250000, 0.0144042968750000, +-0.0166015625000000, 0.0150146484375000, -0.0178527832031250, 0.0177307128906250, +-0.0184631347656250, 0.0163879394531250, -0.0174255371093750, 0.0164794921875000, +-0.0213012695312500, 0.0173645019531250, -0.0214233398437500, 0.0159912109375000, +-0.0206298828125000, 0.0148315429687500, -0.0221862792968750, 0.0156250000000000, +-0.0222167968750000, 0.0121154785156250, -0.0197448730468750, 0.0135498046875000, +-0.0198974609375000, 0.0103149414062500, -0.0200500488281250, 0.0063476562500000, +-0.0186157226562500, 0.0098266601562500, -0.0186462402343750, 0.0000610351562500, +-0.0199584960937500, 0.0021972656250000, -0.0198669433593750, -0.0000915527343750, +-0.0196533203125000, -0.0073852539062500, -0.0203247070312500, -0.0028686523437500, +-0.0205078125000000, -0.0094299316406250, -0.0198974609375000, -0.0098876953125000, +-0.0198669433593750, -0.0094604492187500, -0.0202331542968750, -0.0126037597656250, +-0.0203857421875000, -0.0118103027343750, -0.0202331542968750, -0.0112915039062500, +-0.0195617675781250, -0.0126953125000000, -0.0203857421875000, -0.0113525390625000, +-0.0186767578125000, -0.0100402832031250, -0.0166320800781250, -0.0116271972656250, +-0.0178527832031250, -0.0069274902343750, -0.0146179199218750, -0.0094604492187500, +-0.0141601562500000, -0.0075988769531250, -0.0140991210937500, -0.0030822753906250, +-0.0127258300781250, -0.0072326660156250, -0.0129089355468750, -0.0016784667968750, +-0.0122985839843750, -0.0031433105468750, -0.0122680664062500, -0.0028076171875000, +-0.0120849609375000, 0.0003967285156250, -0.0117187500000000, -0.0033264160156250, +-0.0120239257812500, -0.0003662109375000, -0.0114440917968750, -0.0016784667968750, +-0.0117492675781250, -0.0022888183593750, -0.0116271972656250, -0.0009155273437500, +-0.0110168457031250, -0.0032348632812500, -0.0115661621093750, -0.0021667480468750, +-0.0111999511718750, -0.0032653808593750, -0.0110473632812500, -0.0042114257812500, +-0.0111999511718750, -0.0041809082031250, -0.0112304687500000, -0.0058593750000000, +-0.0111389160156250, -0.0065612792968750, -0.0103759765625000, -0.0079345703125000, +-0.0104370117187500}, +{-0.0086059570312500, 0.0114746093750000, -0.0117797851562500, 0.0089416503906250, +-0.0067749023437500, 0.0172424316406250, -0.0004577636718750, 0.0164489746093750, +-0.0048828125000000, 0.0112304687500000, 0.0049438476562500, 0.0138244628906250, +0.0061340332031250, 0.0112915039062500, 0.0036315917968750, 0.0057983398437500, +0.0071716308593750, 0.0089416503906250, 0.0078125000000000, 0.0035400390625000, +0.0001831054687500, 0.0019531250000000, 0.0007629394531250, 0.0049438476562500, +0.0014343261718750, 0.0050048828125000, -0.0023193359375000, 0.0034790039062500, +-0.0021667480468750, 0.0086975097656250, -0.0011596679687500, 0.0079956054687500, +-0.0008544921875000, 0.0106811523437500, -0.0015258789062500, 0.0147399902343750, +-0.0015869140625000, 0.0117187500000000, -0.0013427734375000, 0.0198059082031250, +-0.0044860839843750, 0.0192565917968750, -0.0034179687500000, 0.0195007324218750, +-0.0052185058593750, 0.0235595703125000, -0.0087890625000000, 0.0213623046875000, +-0.0070800781250000, 0.0251159667968750, -0.0099182128906250, 0.0249023437500000, +-0.0101623535156250, 0.0238952636718750, -0.0108337402343750, 0.0263366699218750, +-0.0123596191406250, 0.0258789062500000, -0.0114135742187500, 0.0197753906250000, +-0.0141296386718750, 0.0235595703125000, -0.0142517089843750, 0.0183105468750000, +-0.0140991210937500, 0.0101623535156250, -0.0152282714843750, 0.0157165527343750, +-0.0150451660156250, 0.0029907226562500, -0.0155944824218750, 0.0036010742187500, +-0.0150756835937500, 0.0024108886718750, -0.0160217285156250, -0.0053100585937500, +-0.0173950195312500, -0.0018615722656250, -0.0164489746093750, -0.0055847167968750, +-0.0177612304687500, -0.0077819824218750, -0.0183715820312500, -0.0045776367187500, +-0.0173950195312500, -0.0042419433593750, -0.0170288085937500, -0.0066833496093750, +-0.0176696777343750, 0.0027465820312500, -0.0166931152343750, -0.0005493164062500, +-0.0162048339843750, 0.0033874511718750, -0.0172119140625000, 0.0116882324218750, +-0.0177307128906250, 0.0060119628906250, -0.0170898437500000, 0.0190429687500000, +-0.0183410644531250, 0.0171508789062500, -0.0187988281250000, 0.0198364257812500, +-0.0178833007812500, 0.0288391113281250, -0.0174560546875000, 0.0236816406250000, +-0.0178833007812500, 0.0325012207031250, -0.0164184570312500, 0.0320434570312500, +-0.0160217285156250, 0.0323791503906250, -0.0160522460937500, 0.0372009277343750, +-0.0157470703125000, 0.0345153808593750, -0.0155944824218750, 0.0375671386718750, +-0.0152282714843750, 0.0382690429687500, -0.0153808593750000, 0.0373840332031250, +-0.0149536132812500, 0.0382690429687500, -0.0144042968750000, 0.0386657714843750, +-0.0147705078125000, 0.0371093750000000, -0.0143127441406250, 0.0377197265625000, +-0.0145263671875000, 0.0366210937500000, -0.0144348144531250, 0.0352172851562500, +-0.0141906738281250, 0.0367431640625000, -0.0146789550781250, 0.0336914062500000, +-0.0138854980468750, 0.0343627929687500, -0.0140686035156250, 0.0335998535156250, +-0.0140686035156250, 0.0313110351562500, -0.0135498046875000, 0.0328979492187500, +-0.0137023925781250, 0.0308227539062500, -0.0129089355468750, 0.0311279296875000, +-0.0131225585937500, 0.0310974121093750, -0.0124511718750000, 0.0300292968750000, +-0.0111999511718750, 0.0307617187500000, -0.0116577148437500, 0.0296020507812500, +-0.0108642578125000, 0.0301818847656250, -0.0104064941406250, 0.0302734375000000, +-0.0104370117187500, 0.0294799804687500, -0.0105895996093750, 0.0300598144531250, +-0.0104064941406250, 0.0294494628906250, -0.0088195800781250, 0.0293884277343750, +-0.0097351074218750, 0.0291442871093750, -0.0084533691406250, 0.0288391113281250, +-0.0064392089843750, 0.0286254882812500, -0.0077209472656250, 0.0267639160156250, +-0.0044555664062500, 0.0271911621093750, -0.0051574707031250, 0.0259704589843750, +-0.0037536621093750, 0.0238647460937500, -0.0006408691406250, 0.0240783691406250, +-0.0025024414062500, 0.0196838378906250, -0.0005493164062500, 0.0199279785156250, +0.0009460449218750, 0.0168151855468750, -0.0007324218750000, 0.0121154785156250, +-0.0017395019531250, 0.0135192871093750, -0.0004272460937500, 0.0070190429687500, +-0.0033264160156250, 0.0065307617187500, -0.0030517578125000, 0.0044860839843750, +-0.0040283203125000, -0.0000305175781250, -0.0063781738281250, 0.0009765625000000, +-0.0048217773437500, -0.0032043457031250, -0.0064392089843750, -0.0035705566406250, +-0.0082702636718750, -0.0034790039062500, -0.0055541992187500, -0.0056457519531250, +-0.0033874511718750, -0.0051269531250000, -0.0060729980468750, -0.0029296875000000, +-0.0037536621093750, -0.0039672851562500, -0.0016174316406250, -0.0019226074218750, +-0.0045471191406250, 0.0011596679687500, -0.0068359375000000, -0.0002746582031250, +-0.0047607421875000, 0.0045776367187500, -0.0090942382812500, 0.0053100585937500, +-0.0093688964843750, 0.0041503906250000, -0.0097961425781250, 0.0055847167968750, +-0.0122375488281250, 0.0058898925781250, -0.0109863281250000, 0.0023803710937500, +-0.0110473632812500, 0.0032958984375000, -0.0131225585937500, 0.0014648437500000, +-0.0099487304687500, -0.0024414062500000, -0.0063781738281250, -0.0008850097656250, +-0.0094909667968750, -0.0030212402343750, -0.0062255859375000, -0.0043640136718750, +-0.0040283203125000, -0.0015258789062500, -0.0066833496093750, -0.0004272460937500, +-0.0080566406250000, -0.0023498535156250, -0.0064392089843750, 0.0054321289062500, +-0.0117492675781250, 0.0049438476562500, -0.0123291015625000, 0.0052795410156250, +-0.0096435546875000, 0.0100402832031250, -0.0110778808593750, 0.0086975097656250, +-0.0127258300781250, 0.0084533691406250, -0.0052795410156250, 0.0097351074218750, +-0.0067749023437500, 0.0075683593750000, -0.0042419433593750, 0.0059204101562500, +0.0022888183593750, 0.0071716308593750, -0.0010375976562500, -0.0011596679687500, +0.0018920898437500, 0.0008544921875000, 0.0032653808593750, -0.0028686523437500, +0.0020751953125000, -0.0107727050781250, 0.0022583007812500, -0.0070495605468750, +0.0027160644531250, -0.0149536132812500, -0.0004577636718750, -0.0154418945312500, +-0.0007019042968750, -0.0152282714843750, -0.0003051757812500, -0.0195007324218750, +-0.0011596679687500, -0.0180664062500000, -0.0010681152343750, -0.0150451660156250, +-0.0014038085937500, -0.0179138183593750, -0.0016784667968750, -0.0135192871093750, +-0.0018005371093750, -0.0073242187500000, -0.0015869140625000, -0.0110778808593750, +-0.0014343261718750, -0.0041503906250000, -0.0028686523437500, -0.0032653808593750, +-0.0027160644531250, -0.0042724609375000, -0.0033264160156250, -0.0017395019531250, +-0.0048217773437500, -0.0024719238281250, -0.0049743652343750, -0.0052795410156250, +-0.0059509277343750, -0.0037231445312500, -0.0056152343750000, -0.0047607421875000, +-0.0056457519531250, -0.0075378417968750, -0.0065002441406250, -0.0059204101562500, +-0.0062866210937500, -0.0096130371093750, -0.0060119628906250, -0.0101013183593750, +-0.0060424804687500, -0.0083007812500000, -0.0059204101562500, -0.0096435546875000, +-0.0054626464843750, -0.0103759765625000, -0.0057983398437500, -0.0030212402343750, +-0.0072631835937500, -0.0050048828125000, -0.0056762695312500, -0.0034790039062500, +-0.0087890625000000, 0.0029296875000000, -0.0126342773437500, 0.0006408691406250, +-0.0101928710937500, 0.0017700195312500, -0.0162353515625000, 0.0033569335937500, +-0.0162963867187500, 0.0009155273437500, -0.0162658691406250, -0.0010070800781250, +-0.0200195312500000, 0.0008239746093750, -0.0189514160156250, -0.0016784667968750, +-0.0153808593750000, -0.0023803710937500, -0.0181274414062500, -0.0021362304687500, +-0.0145874023437500, -0.0022277832031250, -0.0092163085937500, -0.0022583007812500, +-0.0126342773437500, -0.0053100585937500, -0.0046386718750000, -0.0037841796875000, +-0.0050964355468750, -0.0042724609375000, -0.0035400390625000, -0.0084838867187500, +0.0018005371093750, -0.0078735351562500, -0.0007934570312500, -0.0032348632812500, +0.0029907226562500, -0.0047607421875000, 0.0039672851562500, -0.0044555664062500, +0.0028076171875000, -0.0002746582031250, 0.0035400390625000, -0.0016479492187500, +0.0036315917968750, -0.0056457519531250, 0.0010375976562500, -0.0021057128906250, +0.0016174316406250, -0.0063171386718750, 0.0009460449218750, -0.0140380859375000, +-0.0014953613281250, -0.0096435546875000, -0.0003967285156250, -0.0133972167968750, +0.0003662109375000, -0.0153808593750000, -0.0008544921875000, -0.0140686035156250, +0.0018310546875000, -0.0139160156250000, 0.0048828125000000, -0.0144958496093750, +0.0034179687500000, -0.0133972167968750, 0.0087890625000000, -0.0128784179687500, +0.0094909667968750, -0.0146789550781250, 0.0093383789062500, -0.0155029296875000, +0.0120849609375000, -0.0138854980468750, 0.0119628906250000, -0.0161437988281250, +0.0094299316406250, -0.0170593261718750, 0.0104980468750000, -0.0156250000000000, +0.0092163085937500, -0.0152587890625000, 0.0061645507812500, -0.0158996582031250, +0.0076599121093750, -0.0131835937500000, 0.0072021484375000, -0.0138549804687500, +0.0060729980468750, -0.0127563476562500, 0.0086975097656250, -0.0102539062500000, +0.0107421875000000, -0.0116271972656250, 0.0092468261718750, -0.0100402832031250, +0.0150451660156250, -0.0096130371093750, 0.0149230957031250, -0.0094909667968750, +0.0169372558593750, -0.0090637207031250, 0.0216979980468750, -0.0093688964843750, +0.0205383300781250, -0.0071411132812500, 0.0238037109375000, -0.0075073242187500, +0.0247802734375000, -0.0069274902343750, 0.0244445800781250, -0.0051574707031250, +0.0252685546875000, -0.0057983398437500, 0.0254821777343750, -0.0043640136718750, +0.0252685546875000, -0.0045166015625000, 0.0252380371093750, -0.0039978027343750, +0.0250549316406250, -0.0027770996093750, 0.0247497558593750, -0.0035095214843750, +0.0245056152343750, -0.0025634765625000, 0.0232543945312500, -0.0019226074218750, +0.0230102539062500, -0.0028076171875000, 0.0225219726562500, -0.0030517578125000, +0.0215148925781250, -0.0023498535156250, 0.0212707519531250, -0.0042114257812500, +0.0203857421875000, -0.0040283203125000, 0.0197143554687500, -0.0041809082031250, +0.0193481445312500, -0.0052185058593750, 0.0188903808593750, -0.0047912597656250, +0.0184936523437500, -0.0055847167968750, 0.0185241699218750, -0.0052185058593750, +0.0176696777343750, -0.0061645507812500, 0.0177612304687500, -0.0072021484375000, +0.0180358886718750, -0.0062561035156250, 0.0169372558593750, -0.0097351074218750, +0.0184936523437500, -0.0093383789062500, 0.0180053710937500, -0.0098266601562500, +0.0178527832031250, -0.0123901367187500, 0.0185546875000000, -0.0115356445312500, +0.0180358886718750, -0.0111083984375000, 0.0195922851562500, -0.0123291015625000, +0.0184631347656250, -0.0104980468750000, 0.0187377929687500, -0.0085449218750000, +0.0199584960937500, -0.0100708007812500, 0.0185852050781250, -0.0059509277343750, +0.0210266113281250, -0.0061645507812500, 0.0204162597656250, -0.0057067871093750, +0.0211181640625000, -0.0030212402343750, 0.0227661132812500, -0.0040588378906250, +0.0215148925781250, -0.0031738281250000, 0.0251159667968750, -0.0026550292968750, +0.0245056152343750, -0.0030822753906250, 0.0245361328125000, -0.0032348632812500, +0.0270080566406250, -0.0028991699218750, 0.0258789062500000, -0.0031127929687500, +0.0250854492187500, -0.0031127929687500, 0.0269165039062500, -0.0032348632812500, +0.0237121582031250, -0.0030822753906250, 0.0211791992187500, -0.0029907226562500, +0.0242309570312500, -0.0053100585937500, 0.0143432617187500, -0.0042419433593750, +0.0164184570312500, -0.0059509277343750, 0.0122680664062500, -0.0088806152343750, +0.0039062500000000}, +{0.0053405761718750, -0.0053710937500000, 0.0094604492187500, -0.0026550292968750, +0.0071716308593750, -0.0111694335937500, 0.0115051269531250, -0.0109863281250000, +0.0125427246093750, -0.0102233886718750, 0.0111999511718750, -0.0141296386718750, +0.0120544433593750, -0.0132751464843750, 0.0126037597656250, -0.0127868652343750, +0.0096740722656250, -0.0136108398437500, 0.0099182128906250, -0.0124206542968750, +0.0101013183593750, -0.0106811523437500, 0.0081481933593750, -0.0118103027343750, +0.0085754394531250, -0.0121459960937500, 0.0115661621093750, -0.0108032226562500, +0.0103759765625000, -0.0114135742187500, 0.0138244628906250, -0.0130310058593750, +0.0184326171875000, -0.0123291015625000, 0.0162353515625000, -0.0119934082031250, +0.0227355957031250, -0.0125732421875000, 0.0231933593750000, -0.0115356445312500, +0.0226745605468750, -0.0107116699218750, 0.0256042480468750, -0.0114440917968750, +0.0251464843750000, -0.0083007812500000, 0.0227966308593750, -0.0086364746093750, +0.0242614746093750, -0.0087280273437500, 0.0213623046875000, -0.0068359375000000, +0.0173034667968750, -0.0071105957031250, 0.0190429687500000, -0.0073852539062500, +0.0122375488281250, -0.0073547363281250, 0.0121459960937500, -0.0064392089843750, +0.0109252929687500, -0.0059814453125000, 0.0066223144531250, -0.0066528320312500, +0.0077819824218750, -0.0043640136718750, 0.0055541992187500, -0.0043945312500000, +0.0049133300781250, -0.0043945312500000, 0.0050354003906250, -0.0032653808593750, +0.0042114257812500, -0.0036315917968750, 0.0041809082031250, -0.0035095214843750, +0.0047912597656250, -0.0033874511718750, 0.0045166015625000, -0.0036621093750000, +0.0051269531250000, -0.0037231445312500, 0.0058898925781250, -0.0036621093750000, +0.0053405761718750, -0.0041503906250000, 0.0075073242187500, -0.0038452148437500, +0.0069580078125000, -0.0043945312500000, 0.0072326660156250, -0.0050659179687500, +0.0085754394531250, -0.0044555664062500, 0.0076599121093750, -0.0064392089843750, +0.0086669921875000, -0.0060729980468750, 0.0085449218750000, -0.0066833496093750, +0.0084533691406250, -0.0083007812500000, 0.0086059570312500, -0.0075073242187500, +0.0080261230468750, -0.0088500976562500, 0.0086059570312500, -0.0090332031250000, +0.0076599121093750, -0.0087890625000000, 0.0080566406250000, -0.0093078613281250, +0.0086975097656250, -0.0092163085937500, 0.0070800781250000, -0.0083923339843750, +0.0086669921875000, -0.0088500976562500, 0.0079956054687500, -0.0079345703125000, +0.0076599121093750, -0.0068664550781250, 0.0085754394531250, -0.0077819824218750, +0.0075988769531250, -0.0050659179687500, 0.0075378417968750, -0.0054931640625000, +0.0077514648437500, -0.0049438476562500, 0.0069580078125000, -0.0030212402343750, +0.0064392089843750, -0.0039672851562500, 0.0068054199218750, -0.0022583007812500, +0.0053405761718750, -0.0023193359375000, 0.0049743652343750, -0.0024108886718750, +0.0057067871093750, -0.0013122558593750, 0.0050048828125000, -0.0016784667968750, +0.0043029785156250, -0.0027465820312500, 0.0081481933593750, -0.0018615722656250, +0.0058898925781250, -0.0034484863281250, 0.0088500976562500, -0.0056152343750000, +0.0134887695312500, -0.0043334960937500, 0.0101013183593750, -0.0070800781250000, +0.0181884765625000, -0.0074768066406250, 0.0175781250000000, -0.0072326660156250, +0.0186767578125000, -0.0079956054687500, 0.0239562988281250, -0.0077514648437500, +0.0216064453125000, -0.0084228515625000, 0.0242919921875000, -0.0078125000000000, +0.0257263183593750, -0.0086364746093750, 0.0225830078125000, -0.0097961425781250, +0.0221252441406250, -0.0087890625000000, 0.0245971679687500, -0.0112915039062500, +0.0151062011718750, -0.0111389160156250, 0.0177917480468750, -0.0111083984375000, +0.0136718750000000, -0.0124511718750000, 0.0050354003906250, -0.0119323730468750, +0.0103454589843750, -0.0119018554687500, 0.0004272460937500, -0.0118103027343750, +0.0003356933593750, -0.0122070312500000, -0.0001525878906250, -0.0123901367187500, +-0.0060424804687500, -0.0118713378906250, -0.0039672851562500, -0.0129699707031250, +-0.0040283203125000, -0.0132446289062500, -0.0071105957031250, -0.0126342773437500, +-0.0018615722656250, -0.0125427246093750, 0.0026855468750000, -0.0129699707031250, +-0.0014648437500000, -0.0119323730468750, 0.0114135742187500, -0.0121459960937500, +0.0103759765625000, -0.0116882324218750, 0.0119323730468750, -0.0112609863281250, +0.0200500488281250, -0.0115661621093750, 0.0166931152343750, -0.0071716308593750, +0.0208129882812500, -0.0088500976562500, 0.0209350585937500, -0.0068359375000000, +0.0205383300781250, -0.0015563964843750, 0.0228576660156250, -0.0040283203125000, +0.0219116210937500, -0.0040283203125000, 0.0202026367187500, -0.0018920898437500, +0.0225219726562500, -0.0045166015625000, 0.0175476074218750, -0.0071411132812500, +0.0123596191406250, -0.0054931640625000, 0.0164184570312500, -0.0125732421875000, +0.0057983398437500, -0.0124816894531250, 0.0054016113281250, -0.0108032226562500, +0.0043945312500000, -0.0142822265625000, -0.0017700195312500, -0.0150451660156250, +0.0002746582031250, -0.0097961425781250, -0.0003051757812500, -0.0102844238281250, +-0.0019836425781250, -0.0091552734375000, 0.0008850097656250, -0.0062561035156250, +0.0025329589843750, -0.0078125000000000, 0.0003356933593750, -0.0019226074218750, +0.0098571777343750, -0.0031738281250000, 0.0100402832031250, -0.0004577636718750, +0.0085754394531250, 0.0047912597656250, 0.0135498046875000, 0.0018005371093750, +0.0129394531250000, 0.0087585449218750, 0.0035400390625000, 0.0103149414062500, +0.0090026855468750, 0.0058593750000000, 0.0010375976562500, 0.0071105957031250, +-0.0126953125000000, 0.0097961425781250, -0.0049743652343750, -0.0050964355468750, +-0.0180969238281250, -0.0032043457031250, -0.0201110839843750, -0.0047607421875000, +-0.0163879394531250, -0.0200500488281250, -0.0203247070312500, -0.0210571289062500, +0.0045471191406250, -0.0076293945312500, -0.0151062011718750, -0.0137939453125000, +-0.0147399902343750, -0.0083312988281250, -0.0117797851562500, -0.0002136230468750, +-0.0142517089843750, -0.0046081542968750, -0.0160827636718750, 0.0081787109375000, +-0.0090332031250000, 0.0067138671875000, -0.0086364746093750, 0.0086669921875000, +-0.0096130371093750, 0.0188293457031250, -0.0076904296875000, 0.0148315429687500, +-0.0072937011718750, 0.0124206542968750, -0.0048828125000000, 0.0191955566406250, +-0.0068054199218750, 0.0096740722656250, -0.0046386718750000, -0.0015258789062500, +-0.0000305175781250, 0.0068359375000000, -0.0023193359375000, -0.0120544433593750, +-0.0013732910156250, -0.0134887695312500, 0.0015563964843750, -0.0098571777343750, +-0.0037841796875000, -0.0178833007812500, -0.0084533691406250, -0.0179138183593750, +-0.0041198730468750, -0.0051269531250000, -0.0138244628906250, -0.0092468261718750, +-0.0153198242187500, -0.0036010742187500, -0.0129089355468750, 0.0087280273437500, +-0.0162658691406250, 0.0024414062500000, -0.0165710449218750, 0.0139160156250000, +-0.0077209472656250, 0.0147094726562500, -0.0101318359375000, 0.0146179199218750, +-0.0076904296875000, 0.0198669433593750, 0.0001525878906250, 0.0179138183593750, +-0.0029907226562500, 0.0194091796875000, 0.0003356933593750, 0.0196838378906250, +0.0012512207031250, 0.0200805664062500, 0.0003051757812500, 0.0214233398437500, +0.0009460449218750, 0.0200500488281250, 0.0010681152343750, 0.0177307128906250, +0.0000305175781250, 0.0209350585937500, -0.0003051757812500, 0.0162963867187500, +0.0001220703125000, 0.0104370117187500, 0.0003967285156250, 0.0147094726562500, +0.0000305175781250, 0.0042724609375000, -0.0010070800781250, 0.0053100585937500, +-0.0005187988281250, 0.0035095214843750, -0.0007019042968750, -0.0039978027343750, +-0.0017395019531250, -0.0005493164062500, -0.0016784667968750, -0.0032958984375000, +-0.0022583007812500, -0.0065307617187500, -0.0011291503906250, -0.0016174316406250, +-0.0033264160156250, 0.0010986328125000, -0.0057067871093750, -0.0027465820312500, +-0.0036010742187500, 0.0099792480468750, -0.0081481933593750, 0.0074157714843750, +-0.0087280273437500, 0.0103759765625000, -0.0079040527343750, 0.0200195312500000, +-0.0092773437500000, 0.0151367187500000, -0.0093994140625000, 0.0235900878906250, +-0.0082397460937500, 0.0238342285156250, -0.0082702636718750, 0.0235290527343750, +-0.0085144042968750, 0.0278930664062500, -0.0080871582031250, 0.0263366699218750, +-0.0080871582031250, 0.0254211425781250, -0.0088806152343750, 0.0269775390625000, +-0.0086364746093750, 0.0255737304687500, -0.0091857910156250, 0.0233154296875000, +-0.0098876953125000, 0.0247802734375000, -0.0093688964843750, 0.0229797363281250, +-0.0112304687500000, 0.0227050781250000, -0.0108947753906250, 0.0233154296875000, +-0.0109252929687500, 0.0228881835937500, -0.0122375488281250, 0.0227661132812500, +-0.0117187500000000, 0.0231628417968750, -0.0110473632812500, 0.0228271484375000, +-0.0113525390625000, 0.0230712890625000, -0.0111389160156250, 0.0237731933593750, +-0.0101928710937500, 0.0232543945312500, -0.0103149414062500, 0.0229492187500000, +-0.0117797851562500, 0.0238647460937500, -0.0111083984375000, 0.0224914550781250, +-0.0121154785156250, 0.0213012695312500, -0.0140991210937500, 0.0224304199218750, +-0.0133056640625000, 0.0176086425781250, -0.0150146484375000, 0.0195007324218750, +-0.0151367187500000, 0.0173950195312500, -0.0155639648437500, 0.0129699707031250, +-0.0166320800781250, 0.0161743164062500, -0.0161437988281250, 0.0098266601562500, +-0.0173339843750000, 0.0112915039062500, -0.0176086425781250, 0.0101623535156250, +-0.0171203613281250, 0.0058593750000000, -0.0173339843750000, 0.0091247558593750, +-0.0175781250000000, 0.0043640136718750, -0.0156555175781250, 0.0054321289062500, +-0.0158691406250000, 0.0049438476562500, -0.0153503417968750, 0.0021667480468750, +-0.0138854980468750, 0.0047912597656250, -0.0142822265625000, 0.0011901855468750, +-0.0134582519531250, 0.0021057128906250, -0.0136108398437500, 0.0023498535156250, +-0.0126647949218750, 0.0005493164062500, -0.0117797851562500, 0.0025939941406250, +-0.0126342773437500, 0.0016174316406250, -0.0091552734375000, 0.0021362304687500, +-0.0098571777343750, 0.0028381347656250, -0.0088195800781250, 0.0027770996093750, +-0.0062255859375000, 0.0037231445312500, -0.0076293945312500, 0.0038452148437500, +-0.0041503906250000, 0.0040588378906250, -0.0045471191406250, 0.0044555664062500, +-0.0039062500000000, 0.0048522949218750, -0.0010375976562500, 0.0051574707031250, +-0.0020446777343750, 0.0049133300781250, -0.0020751953125000, 0.0053405761718750, +-0.0008850097656250, 0.0049438476562500, -0.0015869140625000, 0.0044555664062500, +-0.0030517578125000, 0.0052795410156250, -0.0022888183593750, 0.0042724609375000, +-0.0020751953125000, 0.0044250488281250, -0.0025634765625000, 0.0047607421875000, +-0.0025024414062500, 0.0044250488281250, -0.0019836425781250, 0.0046386718750000, +-0.0020141601562500, 0.0052795410156250, -0.0020141601562500, 0.0051879882812500, +-0.0025329589843750, 0.0068054199218750, -0.0019531250000000, 0.0083312988281250, +-0.0008544921875000, 0.0081787109375000, -0.0016174316406250, 0.0127563476562500, +-0.0031433105468750, 0.0120544433593750, -0.0016174316406250, 0.0147399902343750, +-0.0030822753906250, 0.0192260742187500, -0.0060119628906250, 0.0173034667968750, +-0.0046386718750000, 0.0229187011718750, -0.0060424804687500, 0.0235900878906250, +-0.0061645507812500, 0.0236206054687500, -0.0077209472656250, 0.0266113281250000, +-0.0090637207031250, 0.0257568359375000, -0.0075073242187500, 0.0223693847656250, +-0.0115966796875000}, +{-0.0038146972656250, 0.0262145996093750, -0.0069885253906250, 0.0264892578125000, +-0.0074157714843750, 0.0258483886718750, -0.0071411132812500, 0.0257873535156250, +-0.0082702636718750, 0.0259399414062500, -0.0080871582031250, 0.0246582031250000, +-0.0078125000000000, 0.0255737304687500, -0.0077819824218750, 0.0237426757812500, +-0.0077209472656250, 0.0223999023437500, -0.0075378417968750, 0.0246582031250000, +-0.0074462890625000, 0.0169067382812500, -0.0073852539062500, 0.0200195312500000, +-0.0072021484375000, 0.0160522460937500, -0.0074462890625000, 0.0086975097656250, +-0.0075683593750000, 0.0140686035156250, -0.0072631835937500, 0.0009460449218750, +-0.0087890625000000, 0.0038757324218750, -0.0085449218750000, -0.0004272460937500, +-0.0088806152343750, -0.0103454589843750, -0.0101318359375000, -0.0032348632812500, +-0.0098266601562500, -0.0177612304687500, -0.0106201171875000, -0.0151977539062500, +-0.0104980468750000, -0.0173950195312500, -0.0114440917968750, -0.0269165039062500, +-0.0123901367187500, -0.0208129882812500, -0.0116577148437500, -0.0301818847656250, +-0.0144348144531250, -0.0292358398437500, -0.0144042968750000, -0.0293884277343750, +-0.0145263671875000, -0.0348815917968750, -0.0161132812500000, -0.0322265625000000, +-0.0156555175781250, -0.0355529785156250, -0.0157165527343750, -0.0350646972656250, +-0.0158081054687500, -0.0346984863281250, -0.0158386230468750, -0.0363464355468750, +-0.0157470703125000, -0.0351562500000000, -0.0156250000000000, -0.0356445312500000, +-0.0162658691406250, -0.0356445312500000, -0.0162658691406250, -0.0351562500000000, +-0.0158996582031250, -0.0351257324218750, -0.0162963867187500, -0.0350646972656250, +-0.0163879394531250, -0.0344238281250000, -0.0142211914062500, -0.0346374511718750, +-0.0151672363281250, -0.0341796875000000, -0.0136108398437500, -0.0335693359375000, +-0.0111694335937500, -0.0340576171875000, -0.0127258300781250, -0.0331420898437500, +-0.0086975097656250, -0.0333557128906250, -0.0093078613281250, -0.0332031250000000, +-0.0079345703125000, -0.0325012207031250, -0.0045166015625000, -0.0325622558593750, +-0.0061645507812500, -0.0310974121093750, -0.0035400390625000, -0.0313110351562500, +-0.0024108886718750, -0.0301208496093750, -0.0034179687500000, -0.0284423828125000, +-0.0034790039062500, -0.0288391113281250, -0.0026245117187500, -0.0254516601562500, +-0.0032958984375000, -0.0259094238281250, -0.0040283203125000, -0.0244750976562500, +-0.0028686523437500, -0.0213623046875000, -0.0018005371093750, -0.0220947265625000, +-0.0026855468750000, -0.0181884765625000, -0.0018310546875000, -0.0179443359375000, +-0.0014038085937500, -0.0165710449218750, -0.0017089843750000, -0.0135803222656250, +-0.0019226074218750, -0.0139465332031250, -0.0019531250000000, -0.0108337402343750, +-0.0016479492187500, -0.0106201171875000, -0.0014648437500000, -0.0099487304687500, +-0.0024108886718750, -0.0079040527343750, -0.0028076171875000, -0.0081176757812500, +-0.0018310546875000, -0.0065002441406250, -0.0039062500000000, -0.0065612792968750, +-0.0040893554687500, -0.0056762695312500, -0.0041809082031250, -0.0047607421875000, +-0.0046386718750000, -0.0054626464843750, -0.0044860839843750, -0.0015563964843750, +-0.0079956054687500, -0.0029296875000000, -0.0066223144531250, -0.0000610351562500, +-0.0077514648437500, 0.0039978027343750, -0.0118103027343750, 0.0014343261718750, +-0.0102233886718750, 0.0109252929687500, -0.0089416503906250, 0.0095520019531250, +-0.0106201171875000, 0.0124511718750000, -0.0096435546875000, 0.0201721191406250, +-0.0066223144531250, 0.0164184570312500, -0.0075073242187500, 0.0216064453125000, +-0.0088806152343750, 0.0231018066406250, -0.0075683593750000, 0.0205688476562500, +-0.0092163085937500, 0.0210876464843750, -0.0119323730468750, 0.0216064453125000, +-0.0103149414062500, 0.0144042968750000, -0.0120544433593750, 0.0158081054687500, +-0.0140380859375000, 0.0124511718750000, -0.0112915039062500, 0.0054321289062500, +-0.0090942382812500, 0.0087890625000000, -0.0113220214843750, 0.0043945312500000, +-0.0069885253906250, 0.0021972656250000, -0.0067138671875000, 0.0049133300781250, +-0.0068969726562500, 0.0056457519531250, -0.0051574707031250, 0.0039672851562500, +-0.0054321289062500, 0.0090637207031250, -0.0037841796875000, 0.0093383789062500, +-0.0045776367187500, 0.0085754394531250, -0.0049743652343750, 0.0105285644531250, +-0.0032043457031250, 0.0104064941406250, -0.0029296875000000, 0.0090942382812500, +-0.0051269531250000, 0.0098266601562500, -0.0048217773437500, 0.0088806152343750, +-0.0060424804687500, 0.0074462890625000, -0.0080261230468750, 0.0085449218750000, +-0.0061340332031250, 0.0056152343750000, -0.0064697265625000, 0.0060424804687500, +-0.0090026855468750, 0.0057983398437500, -0.0060424804687500, 0.0039062500000000, +-0.0025634765625000, 0.0046997070312500, -0.0050354003906250, 0.0034790039062500, +0.0000610351562500, 0.0035400390625000, 0.0005493164062500, 0.0031738281250000, +-0.0003662109375000, 0.0025939941406250, 0.0016784667968750, 0.0029907226562500, +0.0013427734375000, -0.0001525878906250, -0.0018920898437500, 0.0015563964843750, +0.0002441406250000, -0.0016784667968750, -0.0034484863281250, -0.0069274902343750, +-0.0098571777343750, -0.0060424804687500, -0.0093688964843750, -0.0162963867187500, +-0.0191955566406250, -0.0135803222656250, -0.0167541503906250, -0.0122680664062500, +-0.0158691406250000, -0.0195312500000000, -0.0229187011718750, -0.0178527832031250, +-0.0215454101562500, -0.0108337402343750, -0.0158386230468750, -0.0148925781250000, +-0.0192565917968750, -0.0115356445312500, -0.0141296386718750, -0.0028076171875000, +-0.0057067871093750, -0.0072326660156250, -0.0105285644531250, -0.0044250488281250, +-0.0024414062500000, -0.0029907226562500, -0.0006713867187500, -0.0035400390625000, +-0.0014343261718750, -0.0036926269531250, 0.0009765625000000, -0.0041809082031250, +0.0004882812500000, -0.0018920898437500, 0.0000305175781250, -0.0023803710937500, +0.0004577636718750, -0.0022888183593750, 0.0010070800781250, -0.0004577636718750, +0.0008239746093750, -0.0008239746093750, 0.0007019042968750, -0.0014343261718750, +0.0027770996093750, -0.0014343261718750, 0.0023498535156250, -0.0010986328125000, +0.0036621093750000, -0.0012512207031250, 0.0057678222656250, -0.0016479492187500, +0.0046997070312500, -0.0005493164062500, 0.0073242187500000, 0.0002441406250000, +0.0079040527343750, -0.0023803710937500, 0.0075073242187500, -0.0033874511718750, +0.0086975097656250, -0.0014343261718750, 0.0086975097656250, -0.0090942382812500, +0.0048522949218750, -0.0083618164062500, 0.0056457519531250, -0.0088500976562500, +0.0060119628906250, -0.0144958496093750, 0.0031127929687500, -0.0128479003906250, +0.0034179687500000, -0.0088195800781250, 0.0074462890625000, -0.0119323730468750, +0.0054626464843750, -0.0088806152343750, 0.0089721679687500, -0.0028076171875000, +0.0144042968750000, -0.0060119628906250, 0.0112609863281250, -0.0011596679687500, +0.0184020996093750, 0.0003356933593750, 0.0191650390625000, -0.0023803710937500, +0.0184631347656250, -0.0021667480468750, 0.0216979980468750, -0.0000915527343750, +0.0210266113281250, -0.0044250488281250, 0.0174255371093750, -0.0047912597656250, +0.0187683105468750, -0.0039978027343750, 0.0156555175781250, -0.0048522949218750, +0.0107421875000000, -0.0045166015625000, 0.0126342773437500, -0.0054931640625000, +0.0070495605468750, -0.0049438476562500, 0.0058593750000000, -0.0051879882812500, +0.0053710937500000, -0.0059814453125000, 0.0028381347656250, -0.0054016113281250, +0.0031127929687500, -0.0072937011718750, 0.0024108886718750, -0.0068664550781250, +0.0019226074218750, -0.0066528320312500, 0.0018005371093750, -0.0078430175781250, +0.0016174316406250, -0.0076904296875000, 0.0011596679687500, -0.0073852539062500, +-0.0003356933593750, -0.0071105957031250, -0.0000610351562500, -0.0076904296875000, +-0.0018615722656250, -0.0082092285156250, -0.0039978027343750, -0.0075683593750000, +-0.0037231445312500, -0.0077209472656250, -0.0088195800781250, -0.0083618164062500, +-0.0085754394531250, -0.0079040527343750, -0.0107116699218750, -0.0071411132812500, +-0.0150451660156250, -0.0075988769531250, -0.0138244628906250, -0.0081481933593750, +-0.0181579589843750, -0.0076904296875000, -0.0185546875000000, -0.0079650878906250, +-0.0192871093750000, -0.0087890625000000, -0.0217895507812500, -0.0084533691406250, +-0.0211181640625000, -0.0082397460937500, -0.0229187011718750, -0.0085754394531250, +-0.0230407714843750, -0.0083007812500000, -0.0229187011718750, -0.0078735351562500, +-0.0234680175781250, -0.0083007812500000, -0.0228881835937500, -0.0080566406250000, +-0.0231933593750000, -0.0080566406250000, -0.0228576660156250, -0.0080871582031250, +-0.0223999023437500, -0.0080871582031250, -0.0223083496093750, -0.0081787109375000, +-0.0220336914062500, -0.0075378417968750, -0.0213317871093750, -0.0078735351562500, +-0.0202026367187500, -0.0074462890625000, -0.0208129882812500, -0.0066528320312500, +-0.0208435058593750, -0.0070800781250000, -0.0191040039062500, -0.0060424804687500, +-0.0217590332031250, -0.0058593750000000, -0.0203552246093750, -0.0061035156250000, +-0.0211791992187500, -0.0057678222656250, -0.0233459472656250, -0.0056457519531250, +-0.0212707519531250, -0.0061340332031250, -0.0256652832031250, -0.0060119628906250, +-0.0238952636718750, -0.0060424804687500, -0.0249938964843750, -0.0064697265625000, +-0.0285339355468750, -0.0063171386718750, -0.0254516601562500, -0.0063781738281250, +-0.0297851562500000, -0.0064086914062500, -0.0293579101562500, -0.0066833496093750, +-0.0295715332031250, -0.0068969726562500, -0.0323181152343750, -0.0067138671875000, +-0.0311584472656250, -0.0075378417968750, -0.0322875976562500, -0.0079040527343750, +-0.0331115722656250, -0.0075073242187500, -0.0316772460937500, -0.0077514648437500, +-0.0315856933593750, -0.0082397460937500, -0.0323181152343750, -0.0062866210937500, +-0.0263977050781250, -0.0066833496093750, -0.0289611816406250, -0.0063781738281250, +-0.0252380371093750, -0.0048522949218750, -0.0190124511718750, -0.0055847167968750, +-0.0234985351562500, -0.0052490234375000, -0.0129699707031250, -0.0050354003906250, +-0.0137329101562500, -0.0052490234375000, -0.0114746093750000, -0.0053405761718750, +-0.0045776367187500, -0.0052490234375000, -0.0082397460937500, -0.0058288574218750, +-0.0012207031250000, -0.0054931640625000, -0.0015258789062500, -0.0058593750000000, +-0.0012207031250000, -0.0065612792968750, 0.0025939941406250, -0.0060119628906250, +0.0006103515625000, -0.0067749023437500, 0.0028076171875000, -0.0067443847656250, +0.0025024414062500, -0.0067749023437500, 0.0024108886718750, -0.0071411132812500, +0.0033264160156250, -0.0068664550781250, 0.0025024414062500, -0.0072326660156250, +0.0050659179687500, -0.0073242187500000, 0.0039062500000000, -0.0069885253906250, +0.0056457519531250, -0.0069274902343750, 0.0082397460937500, -0.0070800781250000, +0.0066223144531250, -0.0061035156250000, 0.0141296386718750, -0.0064697265625000, +0.0127868652343750, -0.0053710937500000, 0.0151977539062500, -0.0041809082031250, +0.0221557617187500, -0.0049438476562500, 0.0187377929687500, -0.0010070800781250, +0.0190734863281250, -0.0017089843750000, 0.0229492187500000, -0.0010986328125000, +0.0173034667968750, 0.0025024414062500, 0.0119934082031250, 0.0011291503906250, +0.0163574218750000, -0.0010070800781250, 0.0035705566406250, 0.0006408691406250, +0.0040893554687500, -0.0007019042968750, 0.0025024414062500, -0.0037536621093750, +-0.0055847167968750, -0.0029602050781250, -0.0023803710937500, -0.0064392089843750, +-0.0052490234375000, -0.0052185058593750, -0.0078125000000000, -0.0072631835937500, +-0.0040588378906250}, +{-0.0024719238281250, -0.0093688964843750, -0.0001525878906250, -0.0089111328125000, +0.0043640136718750, -0.0088500976562500, 0.0041198730468750, -0.0103149414062500, +0.0081787109375000, -0.0101623535156250, 0.0099182128906250, -0.0101623535156250, +0.0110473632812500, -0.0111389160156250, 0.0134277343750000, -0.0110168457031250, +0.0141296386718750, -0.0101623535156250, 0.0147705078125000, -0.0107727050781250, +0.0166320800781250, -0.0099792480468750, 0.0174255371093750, -0.0087585449218750, +0.0177612304687500, -0.0095825195312500, 0.0193786621093750, -0.0079956054687500, +0.0190429687500000, -0.0079956054687500, 0.0207214355468750, -0.0078735351562500, +0.0207519531250000, -0.0069885253906250, 0.0202941894531250, -0.0073242187500000, +0.0224914550781250, -0.0065307617187500, 0.0198974609375000, -0.0065002441406250, +0.0217895507812500, -0.0064086914062500, 0.0212402343750000, -0.0059204101562500, +0.0192565917968750, -0.0060424804687500, 0.0222473144531250, -0.0056457519531250, +0.0179748535156250, -0.0054321289062500, 0.0204162597656250, -0.0057678222656250, +0.0189514160156250, -0.0057373046875000, 0.0150451660156250, -0.0054931640625000, +0.0188903808593750, -0.0072326660156250, 0.0123596191406250, -0.0067443847656250, +0.0136718750000000, -0.0074157714843750, 0.0118713378906250, -0.0092163085937500, +0.0073547363281250, -0.0084228515625000, 0.0105285644531250, -0.0089111328125000, +0.0015258789062500, -0.0096435546875000, 0.0043640136718750, -0.0088500976562500, +0.0004577636718750, -0.0081787109375000, -0.0072631835937500, -0.0088500976562500, +-0.0016479492187500, -0.0075683593750000, -0.0155334472656250, -0.0076599121093750, +-0.0129699707031250, -0.0075988769531250, -0.0159912109375000, -0.0069274902343750, +-0.0264587402343750, -0.0074462890625000, -0.0209350585937500, -0.0067138671875000, +-0.0293884277343750, -0.0066528320312500, -0.0304260253906250, -0.0068969726562500, +-0.0293273925781250, -0.0066223144531250, -0.0328979492187500, -0.0066528320312500, +-0.0321044921875000, -0.0066528320312500, -0.0291748046875000, -0.0067443847656250, +-0.0317077636718750, -0.0063476562500000, -0.0270080566406250, -0.0060729980468750, +-0.0220336914062500, -0.0062866210937500, -0.0263977050781250, -0.0052490234375000, +-0.0133361816406250, -0.0054626464843750, -0.0158996582031250, -0.0048217773437500, +-0.0119934082031250, -0.0039062500000000, -0.0014038085937500, -0.0046386718750000, +-0.0070800781250000, -0.0022888183593750, 0.0017089843750000, -0.0025939941406250, +0.0027465820312500, -0.0020141601562500, 0.0014343261718750, -0.0003051757812500, +0.0049133300781250, -0.0010375976562500, 0.0041809082031250, 0.0006103515625000, +0.0005493164062500, 0.0003662109375000, 0.0014648437500000, 0.0014343261718750, +0.0014038085937500, 0.0030822753906250, -0.0019531250000000, 0.0019226074218750, +-0.0010070800781250, 0.0041809082031250, 0.0047912597656250, 0.0050964355468750, +0.0015563964843750, 0.0031127929687500, 0.0058593750000000, 0.0025939941406250, +0.0142822265625000, 0.0040283203125000, 0.0100402832031250, -0.0001525878906250, +0.0151367187500000, -0.0000915527343750, 0.0183715820312500, -0.0016174316406250, +0.0142517089843750, -0.0041198730468750, 0.0127868652343750, -0.0021972656250000, +0.0155029296875000, -0.0078735351562500, 0.0056457519531250, -0.0088195800781250, +0.0070495605468750, -0.0068359375000000, 0.0042114257812500, -0.0076599121093750, +-0.0037536621093750, -0.0088806152343750, 0.0000000000000000, -0.0071716308593750, +-0.0047302246093750, -0.0056152343750000, -0.0075378417968750, -0.0083312988281250, +-0.0047607421875000, -0.0095214843750000, -0.0038452148437500, -0.0073852539062500, +-0.0055847167968750, -0.0161437988281250, 0.0002441406250000, -0.0151062011718750, +-0.0006408691406250, -0.0157470703125000, 0.0008544921875000, -0.0216674804687500, +0.0054016113281250, -0.0197143554687500, 0.0037231445312500, -0.0184631347656250, +0.0074462890625000, -0.0206604003906250, 0.0069885253906250, -0.0178833007812500, +0.0085144042968750, -0.0146484375000000, 0.0115661621093750, -0.0167236328125000, +0.0098876953125000, -0.0088806152343750, 0.0148315429687500, -0.0108947753906250, +0.0158691406250000, -0.0068969726562500, 0.0119323730468750, 0.0003051757812500, +0.0122070312500000, -0.0038146972656250, 0.0145874023437500, 0.0087585449218750, +0.0037841796875000, 0.0093078613281250, 0.0050659179687500, 0.0070190429687500, +0.0044860839843750, 0.0134582519531250, -0.0061950683593750, -0.0085754394531250, +0.0184631347656250, -0.0101928710937500, 0.0036010742187500, -0.0156555175781250, +0.0093688964843750, -0.0060424804687500, 0.0054321289062500, 0.0011291503906250, +-0.0041198730468750, -0.0065307617187500, -0.0010070800781250, 0.0127868652343750, +-0.0000915527343750, 0.0133056640625000, -0.0036621093750000, 0.0125122070312500, +0.0007019042968750, 0.0223693847656250, 0.0072631835937500, 0.0201721191406250, +0.0036926269531250, 0.0154724121093750, 0.0056457519531250, 0.0187377929687500, +0.0092163085937500, 0.0150756835937500, 0.0035095214843750, 0.0083007812500000, +-0.0007629394531250, 0.0117797851562500, 0.0037231445312500, 0.0058593750000000, +-0.0079650878906250, 0.0046081542968750, -0.0082702636718750, 0.0052185058593750, +-0.0082092285156250, 0.0039367675781250, -0.0133361816406250, 0.0039367675781250, +-0.0114135742187500, 0.0007019042968750, -0.0146179199218750, 0.0020141601562500, +-0.0148620605468750, 0.0009765625000000, -0.0148315429687500, -0.0025939941406250, +-0.0165710449218750, -0.0012817382812500, -0.0159301757812500, -0.0020751953125000, +-0.0152587890625000, -0.0030517578125000, -0.0165100097656250, -0.0014953613281250, +-0.0141906738281250, -0.0011596679687500, -0.0114746093750000, -0.0022583007812500, +-0.0133666992187500, 0.0039978027343750, -0.0097045898437500, 0.0024719238281250, +-0.0097351074218750, 0.0034790039062500, -0.0083618164062500, 0.0084838867187500, +-0.0061340332031250, 0.0067138671875000, -0.0077514648437500, 0.0083618164062500, +-0.0022888183593750, 0.0080566406250000, -0.0032958984375000, 0.0104370117187500, +-0.0014648437500000, 0.0127868652343750, 0.0035095214843750, 0.0101928710937500, +0.0010375976562500, 0.0160522460937500, 0.0023498535156250, 0.0169067382812500, +0.0044555664062500, 0.0151367187500000, 0.0018615722656250, 0.0173339843750000, +-0.0010986328125000, 0.0179748535156250, 0.0006103515625000, 0.0111999511718750, +-0.0007629394531250, 0.0146484375000000, -0.0020141601562500, 0.0088195800781250, +-0.0009155273437500, 0.0011596679687500, 0.0001525878906250, 0.0076599121093750, +-0.0004882812500000, -0.0094604492187500, -0.0000915527343750, -0.0065002441406250, +0.0003967285156250, -0.0098876953125000, -0.0002441406250000, -0.0221862792968750, +-0.0007934570312500, -0.0156555175781250, -0.0003356933593750, -0.0265808105468750, +-0.0013122558593750, -0.0269775390625000, -0.0012512207031250, -0.0260009765625000, +-0.0013122558593750, -0.0316162109375000, -0.0016479492187500, -0.0296936035156250, +-0.0012817382812500, -0.0254821777343750, -0.0026550292968750, -0.0299987792968750, +-0.0022583007812500, -0.0232238769531250, -0.0026550292968750, -0.0152893066406250, +-0.0039978027343750, -0.0223083496093750, -0.0033569335937500, -0.0053710937500000, +-0.0039367675781250, -0.0086059570312500, -0.0041503906250000, -0.0055541992187500, +-0.0043029785156250, 0.0062561035156250, -0.0044860839843750, -0.0000915527343750, +-0.0043640136718750, 0.0116882324218750, -0.0054931640625000, 0.0107727050781250, +-0.0053100585937500, 0.0120849609375000, -0.0057983398437500, 0.0191955566406250, +-0.0066833496093750, 0.0152893066406250, -0.0062866210937500, 0.0215148925781250, +-0.0079650878906250, 0.0210266113281250, -0.0076293945312500, 0.0211486816406250, +-0.0084228515625000, 0.0246582031250000, -0.0100708007812500, 0.0228271484375000, +-0.0091552734375000, 0.0250244140625000, -0.0104370117187500, 0.0252075195312500, +-0.0108947753906250, 0.0256042480468750, -0.0104675292968750, 0.0269470214843750, +-0.0104980468750000, 0.0265808105468750, -0.0105895996093750, 0.0288085937500000, +-0.0105590820312500, 0.0279541015625000, -0.0103759765625000, 0.0289611816406250, +-0.0104980468750000, 0.0312500000000000, -0.0108947753906250, 0.0300903320312500, +-0.0108642578125000, 0.0327453613281250, -0.0102539062500000, 0.0325622558593750, +-0.0107421875000000, 0.0329895019531250, -0.0102539062500000, 0.0346679687500000, +-0.0093688964843750, 0.0339660644531250, -0.0099487304687500, 0.0359191894531250, +-0.0089721679687500, 0.0357666015625000, -0.0086975097656250, 0.0363159179687500, +-0.0089111328125000, 0.0375671386718750, -0.0085449218750000, 0.0368957519531250, +-0.0083618164062500, 0.0388793945312500, -0.0087890625000000, 0.0391235351562500, +-0.0087890625000000, 0.0397033691406250, -0.0082397460937500, 0.0409851074218750, +-0.0083312988281250, 0.0406799316406250, -0.0085449218750000, 0.0418090820312500, +-0.0068054199218750, 0.0419006347656250, -0.0071411132812500, 0.0419311523437500, +-0.0070190429687500, 0.0426025390625000, -0.0057678222656250, 0.0423278808593750, +-0.0061340332031250, 0.0413818359375000, -0.0062255859375000, 0.0422363281250000, +-0.0061645507812500, 0.0411071777343750, -0.0060424804687500, 0.0396118164062500, +-0.0061035156250000, 0.0401306152343750, -0.0063171386718750, 0.0354919433593750, +-0.0053100585937500, 0.0365295410156250, -0.0054321289062500, 0.0323181152343750, +-0.0052795410156250, 0.0268859863281250, -0.0044555664062500, 0.0295104980468750, +-0.0046691894531250, 0.0181274414062500, -0.0046997070312500, 0.0191955566406250, +-0.0041809082031250, 0.0142822265625000, -0.0050354003906250, 0.0046081542968750, +-0.0057067871093750, 0.0079040527343750, -0.0049133300781250, -0.0055847167968750, +-0.0080261230468750, -0.0049438476562500, -0.0076599121093750, -0.0081176757812500, +-0.0075378417968750, -0.0174865722656250, -0.0097656250000000, -0.0136413574218750, +-0.0090942382812500, -0.0200805664062500, -0.0066528320312500, -0.0216064453125000, +-0.0078125000000000, -0.0203857421875000, -0.0065307617187500, -0.0221862792968750, +-0.0033264160156250, -0.0219421386718750, -0.0046386718750000, -0.0179138183593750, +-0.0039062500000000, -0.0185241699218750, -0.0026550292968750, -0.0174560546875000, +-0.0042419433593750, -0.0141906738281250, -0.0053710937500000, -0.0148620605468750, +-0.0041809082031250, -0.0131225585937500, -0.0083007812500000, -0.0130310058593750, +-0.0085754394531250, -0.0118408203125000, -0.0072631835937500, -0.0108947753906250, +-0.0087585449218750, -0.0115966796875000, -0.0094604492187500, -0.0051269531250000, +-0.0059509277343750, -0.0069274902343750, -0.0067138671875000, -0.0025024414062500, +-0.0055847167968750, 0.0045166015625000, -0.0024414062500000, 0.0003967285156250, +-0.0040893554687500, 0.0109863281250000, -0.0034790039062500, 0.0113220214843750, +-0.0026855468750000, 0.0114746093750000, -0.0037841796875000, 0.0171813964843750, +-0.0044555664062500, 0.0155944824218750, -0.0037841796875000, 0.0144958496093750, +-0.0066528320312500, 0.0164489746093750, -0.0070190429687500, 0.0138854980468750, +-0.0062561035156250, 0.0105895996093750, -0.0067138671875000, 0.0124511718750000, +-0.0068054199218750, 0.0066223144531250, -0.0070190429687500, 0.0068054199218750, +-0.0076293945312500, 0.0059204101562500, -0.0064086914062500, 0.0017700195312500, +-0.0047912597656250, 0.0031433105468750, -0.0058593750000000, 0.0029907226562500, +-0.0069885253906250, 0.0019226074218750, -0.0051574707031250, 0.0026245117187500, +-0.0082702636718750, 0.0039367675781250, -0.0112915039062500, 0.0034179687500000, +-0.0082702636718750}, +{-0.0065307617187500, 0.0390625000000000, -0.0070495605468750, 0.0423889160156250, +-0.0066223144531250, 0.0419006347656250, -0.0063171386718750, 0.0423583984375000, +-0.0067138671875000, 0.0445556640625000, -0.0068969726562500, 0.0430297851562500, +-0.0065917968750000, 0.0448608398437500, -0.0073547363281250, 0.0448303222656250, +-0.0071105957031250, 0.0441894531250000, -0.0071411132812500, 0.0448913574218750, +-0.0077209472656250, 0.0448913574218750, -0.0074157714843750, 0.0438232421875000, +-0.0073547363281250, 0.0439758300781250, -0.0075988769531250, 0.0431823730468750, +-0.0074157714843750, 0.0419921875000000, -0.0070800781250000, 0.0424194335937500, +-0.0072326660156250, 0.0406494140625000, -0.0077209472656250, 0.0408325195312500, +-0.0074462890625000, 0.0396728515625000, -0.0078430175781250, 0.0378112792968750, +-0.0085144042968750, 0.0389404296875000, -0.0081787109375000, 0.0365905761718750, +-0.0085144042968750, 0.0367431640625000, -0.0087890625000000, 0.0367431640625000, +-0.0083312988281250, 0.0354614257812500, -0.0081176757812500, 0.0363464355468750, +-0.0084533691406250, 0.0365905761718750, -0.0073547363281250, 0.0361328125000000, +-0.0072326660156250, 0.0375671386718750, -0.0074768066406250, 0.0390014648437500, +-0.0069580078125000, 0.0379943847656250, -0.0067749023437500, 0.0400695800781250, +-0.0081481933593750, 0.0407409667968750, -0.0076904296875000, 0.0403442382812500, +-0.0083312988281250, 0.0411376953125000, -0.0097961425781250, 0.0414733886718750, +-0.0088806152343750, 0.0385742187500000, -0.0092773437500000, 0.0400390625000000, +-0.0101928710937500, 0.0361022949218750, -0.0082092285156250, 0.0318908691406250, +-0.0067443847656250, 0.0345458984375000, -0.0081176757812500, 0.0221252441406250, +-0.0037536621093750, 0.0243530273437500, -0.0034790039062500, 0.0184936523437500, +-0.0038757324218750, 0.0075683593750000, -0.0017395019531250, 0.0134277343750000, +-0.0019836425781250, -0.0014343261718750, -0.0040893554687500, -0.0014953613281250, +-0.0029296875000000, -0.0029907226562500, -0.0045471191406250, -0.0112304687500000, +-0.0077514648437500, -0.0076599121093750, -0.0058593750000000, -0.0127563476562500, +-0.0061645507812500, -0.0130920410156250, -0.0080261230468750, -0.0126953125000000, +-0.0058898925781250, -0.0148315429687500, -0.0033874511718750, -0.0137634277343750, +-0.0050659179687500, -0.0142211914062500, -0.0015563964843750, -0.0148010253906250, +-0.0009460449218750, -0.0128479003906250, -0.0022583007812500, -0.0117187500000000, +-0.0017395019531250, -0.0125427246093750, -0.0011901855468750, -0.0075988769531250, +-0.0024414062500000, -0.0083923339843750, -0.0025634765625000, -0.0057373046875000, +-0.0034179687500000, -0.0012817382812500, -0.0044250488281250, -0.0033264160156250, +-0.0036010742187500, 0.0044250488281250, -0.0046386718750000, 0.0039367675781250, +-0.0042724609375000, 0.0056152343750000, -0.0062255859375000, 0.0113830566406250, +-0.0082092285156250, 0.0093688964843750, -0.0062561035156250, 0.0117492675781250, +-0.0094299316406250, 0.0132751464843750, -0.0093383789062500, 0.0107727050781250, +-0.0110778808593750, 0.0096740722656250, -0.0135498046875000, 0.0110473632812500, +-0.0115356445312500, 0.0051269531250000, -0.0162048339843750, 0.0053710937500000, +-0.0159606933593750, 0.0051879882812500, -0.0156250000000000, 0.0017700195312500, +-0.0185852050781250, 0.0024108886718750, -0.0177612304687500, 0.0018615722656250, +-0.0137329101562500, 0.0017395019531250, -0.0171203613281250, 0.0016174316406250, +-0.0114746093750000, 0.0010375976562500, -0.0039367675781250, 0.0011596679687500, +-0.0093688964843750, 0.0021362304687500, 0.0006408691406250, 0.0015258789062500, +0.0018920898437500, 0.0020751953125000, 0.0010375976562500, 0.0036315917968750, +0.0054016113281250, 0.0034179687500000, 0.0047912597656250, 0.0044860839843750, +0.0020446777343750, 0.0041198730468750, 0.0032958984375000, 0.0040893554687500, +0.0028076171875000, 0.0047302246093750, 0.0003662109375000, 0.0045166015625000, +0.0014953613281250, 0.0057373046875000, 0.0007629394531250, 0.0049133300781250, +0.0000915527343750, 0.0055541992187500, 0.0008239746093750, 0.0073852539062500, +0.0014343261718750, 0.0061340332031250, 0.0009765625000000, 0.0055236816406250, +0.0014648437500000, 0.0079040527343750, 0.0015563964843750, 0.0035400390625000, +0.0016784667968750, 0.0002441406250000, 0.0017395019531250, 0.0041503906250000, +0.0017089843750000, -0.0096130371093750, 0.0034179687500000, -0.0076599121093750, +0.0025329589843750, -0.0092468261718750, 0.0039062500000000, -0.0193786621093750, +0.0060119628906250, -0.0159301757812500, 0.0047302246093750, -0.0156860351562500, +0.0085754394531250, -0.0189514160156250, 0.0075378417968750, -0.0150756835937500, +0.0091857910156250, -0.0111694335937500, 0.0131530761718750, -0.0143737792968750, +0.0109558105468750, -0.0056457519531250, 0.0125122070312500, -0.0075683593750000, +0.0149536132812500, -0.0052185058593750, 0.0107116699218750, 0.0021972656250000, +0.0079650878906250, -0.0017395019531250, 0.0112609863281250, 0.0024719238281250, +-0.0001220703125000, 0.0042114257812500, 0.0005798339843750, 0.0021667480468750, +-0.0003662109375000, 0.0021362304687500, -0.0072631835937500, 0.0031127929687500, +-0.0049133300781250, -0.0006713867187500, -0.0067138671875000, 0.0000915527343750, +-0.0075683593750000, -0.0008239746093750, -0.0075073242187500, -0.0042419433593750, +-0.0073852539062500, -0.0026550292968750, -0.0072021484375000, -0.0017700195312500, +-0.0102539062500000, -0.0037536621093750, -0.0091247558593750, -0.0016784667968750, +-0.0103759765625000, 0.0012817382812500, -0.0137939453125000, -0.0006713867187500, +-0.0119628906250000, 0.0027770996093750, -0.0115356445312500, 0.0027770996093750, +-0.0132446289062500, 0.0030517578125000, -0.0083923339843750, 0.0053710937500000, +-0.0039978027343750, 0.0043640136718750, -0.0061035156250000, 0.0029296875000000, +0.0057067871093750, 0.0045166015625000, 0.0059509277343750, 0.0030822753906250, +0.0106811523437500, 0.0003967285156250, 0.0197448730468750, 0.0018615722656250, +0.0166625976562500, -0.0007629394531250, 0.0261230468750000, -0.0004272460937500, +0.0267028808593750, -0.0012207031250000, 0.0274353027343750, -0.0031433105468750, +0.0325012207031250, -0.0019226074218750, 0.0311584472656250, -0.0046691894531250, +0.0333557128906250, -0.0039672851562500, 0.0341186523437500, -0.0054931640625000, +0.0336608886718750, -0.0079650878906250, 0.0337524414062500, -0.0059814453125000, +0.0334167480468750, -0.0101013183593750, 0.0324401855468750, -0.0102539062500000, +0.0320434570312500, -0.0098876953125000, 0.0318298339843750, -0.0117187500000000, +0.0310363769531250, -0.0113220214843750, 0.0306701660156250, -0.0115356445312500, +0.0317687988281250, -0.0116271972656250, 0.0309143066406250, -0.0115661621093750, +0.0314941406250000, -0.0116271972656250, 0.0325927734375000, -0.0116577148437500, +0.0314636230468750, -0.0113525390625000, 0.0338134765625000, -0.0115051269531250, +0.0332946777343750, -0.0113220214843750, 0.0338439941406250, -0.0109558105468750, +0.0352172851562500, -0.0111999511718750, 0.0337829589843750, -0.0103454589843750, +0.0363769531250000, -0.0105590820312500, 0.0351257324218750, -0.0101928710937500, +0.0352783203125000, -0.0094909667968750, 0.0370788574218750, -0.0098876953125000, +0.0352783203125000, -0.0088195800781250, 0.0369567871093750, -0.0089721679687500, +0.0362243652343750, -0.0084838867187500, 0.0365905761718750, -0.0075073242187500, +0.0377502441406250, -0.0081176757812500, 0.0360717773437500, -0.0070495605468750, +0.0386962890625000, -0.0068054199218750, 0.0378417968750000, -0.0072021484375000, +0.0381469726562500, -0.0069885253906250, 0.0398864746093750, -0.0068664550781250, +0.0383300781250000, -0.0075073242187500, 0.0400085449218750, -0.0076599121093750, +0.0394897460937500, -0.0073852539062500, 0.0396423339843750, -0.0073242187500000, +0.0408630371093750, -0.0075073242187500, 0.0394592285156250, -0.0069885253906250, +0.0399169921875000, -0.0066223144531250, 0.0404968261718750, -0.0072937011718750, +0.0392150878906250, -0.0075683593750000, 0.0388488769531250, -0.0069580078125000, +0.0395202636718750, -0.0090332031250000, 0.0353088378906250, -0.0086975097656250, +0.0365905761718750, -0.0091247558593750, 0.0347290039062500, -0.0106506347656250, +0.0308837890625000, -0.0099487304687500, 0.0330200195312500, -0.0109558105468750, +0.0270690917968750, -0.0112304687500000, 0.0275268554687500, -0.0107421875000000, +0.0266418457031250, -0.0108642578125000, 0.0227050781250000, -0.0110473632812500, +0.0242919921875000, -0.0091552734375000, 0.0220642089843750, -0.0098571777343750, +0.0214843750000000, -0.0087280273437500, 0.0216674804687500, -0.0068664550781250, +0.0208740234375000, -0.0079345703125000, 0.0209350585937500, -0.0047607421875000, +0.0213623046875000, -0.0054016113281250, 0.0211791992187500, -0.0039978027343750, +0.0200500488281250, -0.0013427734375000, 0.0205993652343750, -0.0030517578125000, +0.0213012695312500, 0.0010070800781250, 0.0143432617187500, 0.0007934570312500, +0.0179443359375000, 0.0012817382812500, 0.0114746093750000, 0.0036621093750000, +0.0025329589843750, 0.0026550292968750, 0.0088806152343750, 0.0048522949218750, +-0.0090942382812500, 0.0044860839843750, -0.0072937011718750, 0.0056457519531250, +-0.0109863281250000, 0.0077819824218750, -0.0240478515625000, 0.0065002441406250, +-0.0184020996093750, 0.0085449218750000, -0.0257263183593750, 0.0096435546875000, +-0.0288391113281250, 0.0074768066406250, -0.0240173339843750, 0.0067749023437500, +-0.0231628417968750, 0.0083618164062500, -0.0256958007812500, 0.0034484863281250, +-0.0155334472656250, 0.0038452148437500, -0.0160522460937500, 0.0025024414062500, +-0.0151672363281250, -0.0003051757812500, -0.0089721679687500, 0.0011901855468750, +-0.0107421875000000, -0.0058288574218750, -0.0091247558593750, -0.0048522949218750, +-0.0095214843750000, -0.0060424804687500, -0.0075378417968750, -0.0107116699218750, +-0.0057067871093750, -0.0090026855468750, -0.0077514648437500, -0.0141296386718750, +-0.0000915527343750, -0.0131835937500000, -0.0010070800781250, -0.0139160156250000, +0.0007934570312500, -0.0185546875000000, 0.0065612792968750, -0.0169982910156250, +0.0044860839843750, -0.0144348144531250, 0.0078125000000000, -0.0176391601562500, +0.0086364746093750, -0.0123596191406250, 0.0073242187500000, -0.0059814453125000, +0.0078430175781250, -0.0108337402343750, 0.0085144042968750, -0.0006103515625000, +0.0067138671875000, 0.0005798339843750, 0.0065307617187500, -0.0012512207031250, +0.0054016113281250, 0.0027465820312500, 0.0042419433593750, 0.0028686523437500, +0.0053100585937500, -0.0033264160156250, 0.0024414062500000, -0.0014038085937500, +0.0024108886718750, -0.0030822753906250, 0.0022277832031250, -0.0082702636718750, +0.0005798339843750, -0.0058288574218750, 0.0010375976562500, -0.0095825195312500, +0.0010375976562500, -0.0097351074218750, 0.0007019042968750, -0.0100402832031250, +0.0012207031250000, -0.0127868652343750, 0.0012512207031250, -0.0112609863281250, +0.0007019042968750, -0.0074462890625000, 0.0034179687500000, -0.0111694335937500, +0.0026855468750000, -0.0067138671875000, 0.0049438476562500, 0.0062866210937500, +0.0105895996093750, 0.0130004882812500, 0.0033874511718750, 0.0007934570312500, +0.0005798339843750, 0.0067749023437500, -0.0014953613281250, 0.0028381347656250, +0.0028381347656250, -0.0061645507812500, 0.0052795410156250, -0.0026245117187500, +0.0022888183593750, -0.0023193359375000, 0.0131835937500000, -0.0051879882812500, +0.0139160156250000}, +{0.0280151367187500, -0.0085144042968750, 0.0266723632812500, -0.0085449218750000, +0.0278320312500000, -0.0087280273437500, 0.0324707031250000, -0.0083312988281250, +0.0296630859375000, -0.0085754394531250, 0.0339050292968750, -0.0086669921875000, +0.0342102050781250, -0.0082702636718750, 0.0330505371093750, -0.0081176757812500, +0.0346984863281250, -0.0082092285156250, 0.0345153808593750, -0.0073547363281250, +0.0315246582031250, -0.0077819824218750, 0.0328369140625000, -0.0068969726562500, +0.0305175781250000, -0.0058898925781250, 0.0270690917968750, -0.0067749023437500, +0.0292663574218750, -0.0036315917968750, 0.0227966308593750, -0.0042419433593750, +0.0232849121093750, -0.0033569335937500, 0.0222778320312500, -0.0009460449218750, +0.0177001953125000, -0.0022888183593750, 0.0194396972656250, 0.0004272460937500, +0.0186767578125000, 0.0000305175781250, 0.0176086425781250, 0.0012207031250000, +0.0183410644531250, 0.0034484863281250, 0.0192565917968750, 0.0020751953125000, +0.0184326171875000, 0.0055541992187500, 0.0181579589843750, 0.0056457519531250, +0.0197448730468750, 0.0052795410156250, 0.0165405273437500, 0.0072937011718750, +0.0144042968750000, 0.0069885253906250, 0.0169067382812500, 0.0042724609375000, +0.0057067871093750, 0.0055847167968750, 0.0086364746093750, 0.0039367675781250, +0.0027770996093750, 0.0006713867187500, -0.0083312988281250, 0.0021057128906250, +-0.0019531250000000, -0.0020751953125000, -0.0140380859375000, -0.0009155273437500, +-0.0155334472656250, -0.0039062500000000, -0.0141906738281250, -0.0087890625000000, +-0.0186157226562500, -0.0056762695312500, -0.0180969238281250, -0.0111999511718750, +-0.0173034667968750, -0.0123596191406250, -0.0170898437500000, -0.0114440917968750, +-0.0168762207031250, -0.0130004882812500, -0.0171813964843750, -0.0125122070312500, +-0.0170593261718750, -0.0095214843750000, -0.0132446289062500, -0.0116882324218750, +-0.0157470703125000, -0.0081481933593750, -0.0111389160156250, -0.0032043457031250, +-0.0048522949218750, -0.0063476562500000, -0.0087890625000000, 0.0013732910156250, +0.0022583007812500, 0.0018005371093750, 0.0022277832031250, 0.0009765625000000, +0.0033874511718750, 0.0050354003906250, 0.0098266601562500, 0.0047302246093750, +0.0072021484375000, -0.0001525878906250, 0.0085754394531250, 0.0028991699218750, +0.0097961425781250, -0.0015869140625000, 0.0092468261718750, -0.0088195800781250, +0.0087890625000000, -0.0039062500000000, 0.0087585449218750, -0.0111389160156250, +0.0079956054687500, -0.0131225585937500, 0.0084838867187500, -0.0102233886718750, +0.0074768066406250, -0.0115051269531250, 0.0065002441406250, -0.0123291015625000, +0.0075073242187500, -0.0037841796875000, 0.0038757324218750, -0.0064697265625000, +0.0038757324218750, -0.0015563964843750, 0.0041809082031250, 0.0076293945312500, +0.0023498535156250, 0.0023498535156250, 0.0026855468750000, 0.0111083984375000, +0.0036926269531250, 0.0140686035156250, 0.0034790039062500, 0.0106811523437500, +0.0022888183593750, 0.0101013183593750, 0.0016174316406250, -0.0068359375000000, +0.0031127929687500, -0.0048522949218750, 0.0046691894531250, -0.0077819824218750, +0.0066223144531250, -0.0045166015625000, 0.0032043457031250, -0.0003356933593750, +0.0002441406250000, -0.0027160644531250, 0.0026550292968750, 0.0008544921875000, +-0.0020446777343750, 0.0011291503906250, -0.0044555664062500, 0.0016174316406250, +0.0008850097656250, 0.0031127929687500, 0.0032958984375000, 0.0023193359375000, +-0.0004882812500000, 0.0066833496093750, 0.0096130371093750, 0.0047912597656250, +0.0105590820312500, 0.0075683593750000, 0.0081787109375000, 0.0127563476562500, +0.0119628906250000, 0.0096130371093750, 0.0125122070312500, 0.0158996582031250, +0.0045471191406250, 0.0169982910156250, 0.0060119628906250, 0.0141601562500000, +0.0051574707031250, 0.0154418945312500, -0.0003967285156250, 0.0171508789062500, +0.0012207031250000, 0.0109863281250000, -0.0003356933593750, 0.0115051269531250, +-0.0007629394531250, 0.0102539062500000, 0.0002136230468750, 0.0067443847656250, +0.0004272460937500, 0.0083007812500000, 0.0001525878906250, 0.0024108886718750, +-0.0002441406250000, 0.0041198730468750, 0.0008544921875000, 0.0011596679687500, +-0.0002441406250000, -0.0040893554687500, -0.0016784667968750, -0.0010375976562500, +-0.0010070800781250, -0.0117797851562500, -0.0052490234375000, -0.0091857910156250, +-0.0033264160156250, -0.0131225585937500, -0.0069274902343750, -0.0231323242187500, +-0.0126647949218750, -0.0172424316406250, -0.0090637207031250, -0.0219726562500000, +-0.0160217285156250, -0.0258178710937500, -0.0173645019531250, -0.0198059082031250, +-0.0146789550781250, -0.0169677734375000, -0.0165405273437500, -0.0207214355468750, +-0.0174560546875000, -0.0058288574218750, -0.0082092285156250, -0.0086364746093750, +-0.0102539062500000, -0.0049438476562500, -0.0076293945312500, 0.0068359375000000, +0.0002746582031250, 0.0011901855468750, -0.0027770996093750, 0.0083618164062500, +0.0017700195312500, 0.0101623535156250, 0.0024719238281250, 0.0091247558593750, +0.0023803710937500, 0.0106506347656250, 0.0043334960937500, 0.0102844238281250, +0.0037841796875000, 0.0121459960937500, 0.0042419433593750, 0.0104675292968750, +0.0046997070312500, 0.0133056640625000, 0.0039672851562500, 0.0165405273437500, +0.0036010742187500, 0.0137634277343750, 0.0039978027343750, 0.0223083496093750, +0.0016479492187500, 0.0207519531250000, 0.0018920898437500, 0.0237731933593750, +0.0015563964843750, 0.0302734375000000, -0.0001525878906250, 0.0260009765625000, +0.0003051757812500, 0.0353393554687500, -0.0002441406250000, 0.0352478027343750, +-0.0001831054687500, 0.0355224609375000, -0.0008850097656250, 0.0408325195312500, +-0.0014343261718750, 0.0389099121093750, -0.0007324218750000, 0.0387268066406250, +-0.0030822753906250, 0.0408020019531250, -0.0029907226562500, 0.0379028320312500, +-0.0028686523437500, 0.0355224609375000, -0.0040893554687500, 0.0380249023437500, +-0.0037841796875000, 0.0290222167968750, -0.0036010742187500, 0.0313415527343750, +-0.0036010742187500, 0.0278930664062500, -0.0038146972656250, 0.0205688476562500, +-0.0039367675781250, 0.0257263183593750, -0.0037231445312500, 0.0152587890625000, +-0.0041809082031250, 0.0167541503906250, -0.0043029785156250, 0.0151977539062500, +-0.0041198730468750, 0.0084228515625000, -0.0041198730468750, 0.0124816894531250, +-0.0042419433593750, 0.0056457519531250, -0.0039367675781250, 0.0063171386718750, +-0.0039367675781250, 0.0059204101562500, -0.0037841796875000, 0.0017089843750000, +-0.0035400390625000, 0.0035705566406250, -0.0036926269531250, 0.0006103515625000, +-0.0032043457031250, 0.0011901855468750, -0.0031127929687500, 0.0008544921875000, +-0.0031127929687500, -0.0011901855468750, -0.0028076171875000, -0.0000610351562500, +-0.0027465820312500, -0.0020446777343750, -0.0029296875000000, -0.0017700195312500, +-0.0028991699218750, -0.0021362304687500, -0.0028991699218750, -0.0033569335937500, +-0.0028991699218750, -0.0025024414062500, -0.0030517578125000, -0.0047302246093750, +-0.0033264160156250, -0.0042724609375000, -0.0030212402343750, -0.0046081542968750, +-0.0037841796875000, -0.0061035156250000, -0.0046081542968750, -0.0052185058593750, +-0.0040893554687500, -0.0066833496093750, -0.0059814453125000, -0.0065917968750000, +-0.0059814453125000, -0.0068664550781250, -0.0063781738281250, -0.0078125000000000, +-0.0076293945312500, -0.0071716308593750, -0.0071411132812500, -0.0082397460937500, +-0.0082092285156250, -0.0079956054687500, -0.0082702636718750, -0.0074768066406250, +-0.0082702636718750, -0.0077514648437500, -0.0088195800781250, -0.0073242187500000, +-0.0087280273437500, -0.0055236816406250, -0.0092773437500000, -0.0059509277343750, +-0.0087890625000000, -0.0043640136718750, -0.0097045898437500, -0.0021667480468750, +-0.0108032226562500, -0.0026245117187500, -0.0097351074218750, 0.0021667480468750, +-0.0115966796875000, 0.0017089843750000, -0.0119018554687500, 0.0041198730468750, +-0.0115356445312500, 0.0085144042968750, -0.0121459960937500, 0.0072326660156250, +-0.0119323730468750, 0.0128784179687500, -0.0111083984375000, 0.0129089355468750, +-0.0117797851562500, 0.0141296386718750, -0.0100402832031250, 0.0180969238281250, +-0.0082702636718750, 0.0171813964843750, -0.0096740722656250, 0.0198974609375000, +-0.0059814453125000, 0.0202941894531250, -0.0056457519531250, 0.0203857421875000, +-0.0061645507812500, 0.0216064453125000, -0.0046997070312500, 0.0213012695312500, +-0.0047607421875000, 0.0212707519531250, -0.0057983398437500, 0.0211486816406250, +-0.0053710937500000, 0.0216064453125000, -0.0061340332031250, 0.0216674804687500, +-0.0075378417968750, 0.0213317871093750, -0.0065307617187500, 0.0242004394531250, +-0.0068054199218750, 0.0231018066406250, -0.0081176757812500, 0.0255126953125000, +-0.0059509277343750, 0.0291748046875000, -0.0040283203125000, 0.0266113281250000, +-0.0057067871093750, 0.0309753417968750, -0.0009765625000000, 0.0319213867187500, +-0.0010070800781250, 0.0299377441406250, -0.0011291503906250, 0.0312500000000000, +0.0014953613281250, 0.0318603515625000, 0.0009765625000000, 0.0238647460937500, +0.0005493164062500, 0.0267944335937500, 0.0014343261718750, 0.0205688476562500, +-0.0010375976562500, 0.0116271972656250, -0.0025329589843750, 0.0173950195312500, +-0.0001220703125000, 0.0012817382812500, -0.0072937011718750, 0.0023193359375000, +-0.0063781738281250, 0.0002746582031250, -0.0083923339843750, -0.0102539062500000, +-0.0135803222656250, -0.0063171386718750, -0.0101623535156250, -0.0102844238281250, +-0.0145568847656250, -0.0116577148437500, -0.0163879394531250, -0.0111083984375000, +-0.0143127441406250, -0.0122985839843750, -0.0145874023437500, -0.0118408203125000, +-0.0153198242187500, -0.0105590820312500, -0.0089111328125000, -0.0118103027343750, +-0.0113525390625000, -0.0090026855468750, -0.0083007812500000, -0.0061950683593750, +-0.0014648437500000, -0.0081481933593750, -0.0051269531250000, -0.0002136230468750, +0.0007324218750000, -0.0017089843750000, 0.0016174316406250, 0.0012817382812500, +0.0000915527343750, 0.0080566406250000, 0.0019226074218750, 0.0045776367187500, +0.0020141601562500, 0.0104980468750000, -0.0015258789062500, 0.0118408203125000, +-0.0002746582031250, 0.0097351074218750, -0.0010070800781250, 0.0109252929687500, +-0.0043334960937500, 0.0115356445312500, -0.0034179687500000, 0.0062866210937500, +-0.0035095214843750, 0.0074768066406250, -0.0039672851562500, 0.0057373046875000, +-0.0032958984375000, 0.0006103515625000, -0.0027770996093750, 0.0012512207031250, +-0.0028076171875000, -0.0025939941406250, -0.0009460449218750, -0.0019836425781250, +-0.0016784667968750, -0.0014953613281250, -0.0013122558593750, -0.0041198730468750, +0.0001831054687500, -0.0036621093750000, -0.0003662109375000, -0.0008544921875000, +0.0013122558593750, -0.0027160644531250, 0.0004882812500000, -0.0010375976562500, +0.0023498535156250, 0.0030212402343750, 0.0046997070312500, 0.0007324218750000, +0.0029602050781250, 0.0010681152343750, 0.0081176757812500, 0.0031738281250000, +0.0082702636718750, 0.0016174316406250, 0.0075378417968750, -0.0011596679687500, +0.0101928710937500, 0.0002441406250000, 0.0101928710937500, 0.0013122558593750, +0.0063781738281250, -0.0003967285156250, 0.0073547363281250, 0.0014953613281250, +0.0062561035156250, 0.0050964355468750, 0.0035705566406250, 0.0033569335937500, +0.0049133300781250, 0.0023803710937500, 0.0009765625000000, 0.0051879882812500, +0.0018310546875000, 0.0010986328125000, 0.0006103515625000, -0.0034790039062500, +-0.0027160644531250}, +{-0.0090332031250000, -0.0123901367187500, -0.0072326660156250, -0.0136718750000000, +-0.0079956054687500, -0.0078735351562500, -0.0069274902343750, -0.0090026855468750, +-0.0067138671875000, -0.0061035156250000, -0.0069580078125000, -0.0005798339843750, +-0.0065612792968750, -0.0031738281250000, -0.0067138671875000, 0.0043334960937500, +-0.0079956054687500, 0.0043029785156250, -0.0075073242187500, 0.0055236816406250, +-0.0074462890625000, 0.0100097656250000, -0.0089721679687500, 0.0079040527343750, +-0.0086669921875000, 0.0105285644531250, -0.0054626464843750, 0.0113830566406250, +-0.0069885253906250, 0.0110778808593750, -0.0049743652343750, 0.0114135742187500, +-0.0008544921875000, 0.0115051269531250, -0.0030212402343750, 0.0133056640625000, +-0.0007324218750000, 0.0120239257812500, 0.0007324218750000, 0.0144958496093750, +-0.0012817382812500, 0.0176696777343750, -0.0020751953125000, 0.0154724121093750, +-0.0009765625000000, 0.0213928222656250, -0.0061950683593750, 0.0217285156250000, +-0.0043640136718750, 0.0220031738281250, -0.0064697265625000, 0.0251159667968750, +-0.0117492675781250, 0.0237426757812500, -0.0090332031250000, 0.0223693847656250, +-0.0124511718750000, 0.0246276855468750, -0.0129089355468750, 0.0195922851562500, +-0.0116271972656250, 0.0149841308593750, -0.0132446289062500, 0.0187988281250000, +-0.0135498046875000, 0.0061035156250000, -0.0074768066406250, 0.0066528320312500, +-0.0096740722656250, 0.0043945312500000, -0.0064392089843750, -0.0039062500000000, +-0.0000610351562500, -0.0007019042968750, -0.0039367675781250, -0.0064392089843750, +0.0021972656250000, -0.0073242187500000, 0.0036926269531250, -0.0069885253906250, +0.0014343261718750, -0.0094299316406250, 0.0023498535156250, -0.0088500976562500, +0.0031127929687500, -0.0077819824218750, -0.0017700195312500, -0.0086669921875000, +-0.0011596679687500, -0.0069274902343750, -0.0013427734375000, -0.0054321289062500, +-0.0043334960937500, -0.0067443847656250, -0.0032653808593750, 0.0003967285156250, +-0.0032043457031250, -0.0012817382812500, -0.0043334960937500, 0.0017089843750000, +-0.0032348632812500, 0.0085449218750000, -0.0015258789062500, 0.0049743652343750, +-0.0023803710937500, 0.0097351074218750, -0.0016174316406250, 0.0113525390625000, +-0.0015869140625000, 0.0092163085937500, -0.0010986328125000, 0.0093078613281250, +-0.0003356933593750, 0.0089721679687500, -0.0003967285156250, 0.0031127929687500, +0.0017089843750000, 0.0056152343750000, 0.0010070800781250, 0.0043640136718750, +0.0016479492187500, -0.0003967285156250, 0.0030517578125000, 0.0022583007812500, +0.0021972656250000, -0.0026855468750000, 0.0064697265625000, -0.0031738281250000, +0.0057983398437500, -0.0021972656250000, 0.0063171386718750, -0.0044555664062500, +0.0098876953125000, -0.0044555664062500, 0.0087890625000000, -0.0003051757812500, +0.0067443847656250, -0.0017089843750000, 0.0088500976562500, -0.0014648437500000, +0.0057983398437500, 0.0020751953125000, 0.0012512207031250, 0.0013122558593750, +0.0038146972656250, 0.0003662109375000, 0.0000305175781250, 0.0009765625000000, +-0.0004272460937500, 0.0009765625000000, -0.0009155273437500, -0.0001525878906250, +-0.0025329589843750, -0.0000305175781250, -0.0014953613281250, 0.0020751953125000, +-0.0042419433593750, 0.0011291503906250, -0.0041198730468750, 0.0023193359375000, +-0.0046691894531250, 0.0049438476562500, -0.0068969726562500, 0.0034179687500000, +-0.0060729980468750, 0.0033264160156250, -0.0052490234375000, 0.0050964355468750, +-0.0072021484375000, 0.0022888183593750, -0.0038757324218750, -0.0001220703125000, +-0.0009460449218750, 0.0025634765625000, -0.0032348632812500, -0.0040588378906250, +0.0077819824218750, -0.0028381347656250, 0.0059509277343750, -0.0032348632812500, +0.0090026855468750, -0.0076293945312500, 0.0178222656250000, -0.0055541992187500, +0.0139770507812500, -0.0066833496093750, 0.0203552246093750, -0.0075073242187500, +0.0220031738281250, -0.0065612792968750, 0.0195617675781250, -0.0063781738281250, +0.0204772949218750, -0.0071105957031250, 0.0212097167968750, -0.0050964355468750, +0.0167541503906250, -0.0052795410156250, 0.0167846679687500, -0.0066223144531250, +0.0158691406250000, -0.0063781738281250, 0.0126647949218750, -0.0058593750000000, +0.0131225585937500, -0.0076904296875000, 0.0118408203125000, -0.0084228515625000, +0.0111083984375000, -0.0073547363281250, 0.0106201171875000, -0.0074462890625000, +0.0103149414062500, -0.0083007812500000, 0.0101318359375000, -0.0047302246093750, +0.0075378417968750, -0.0055847167968750, 0.0079956054687500, -0.0046386718750000, +0.0054321289062500, -0.0017089843750000, 0.0021667480468750, -0.0033874511718750, +0.0037231445312500, -0.0010070800781250, -0.0015563964843750, -0.0006713867187500, +-0.0016784667968750, -0.0016784667968750, -0.0027160644531250, -0.0011901855468750, +-0.0062561035156250, -0.0007934570312500, -0.0053405761718750, -0.0024414062500000, +-0.0065307617187500, -0.0025939941406250, -0.0077514648437500, -0.0021972656250000, +-0.0067138671875000, -0.0027160644531250, -0.0060119628906250, -0.0029602050781250, +-0.0068969726562500, -0.0026245117187500, -0.0045471191406250, -0.0022888183593750, +-0.0048217773437500, -0.0032348632812500, -0.0043029785156250, -0.0036621093750000, +-0.0025634765625000, -0.0030822753906250, -0.0033874511718750, -0.0056152343750000, +-0.0021057128906250, -0.0052185058593750, -0.0020751953125000, -0.0054626464843750, +-0.0023498535156250, -0.0071716308593750, -0.0019531250000000, -0.0064697265625000, +-0.0022583007812500, -0.0068054199218750, -0.0028381347656250, -0.0068054199218750, +-0.0030517578125000, -0.0068664550781250, -0.0035400390625000, -0.0069580078125000, +-0.0041198730468750, -0.0066223144531250, -0.0042419433593750, -0.0071105957031250, +-0.0047607421875000, -0.0072021484375000, -0.0051269531250000, -0.0068664550781250, +-0.0049743652343750, -0.0068359375000000, -0.0049743652343750, -0.0070495605468750, +-0.0052490234375000, -0.0069580078125000, -0.0044555664062500, -0.0066528320312500, +-0.0049438476562500, -0.0071716308593750, -0.0047912597656250, -0.0075683593750000, +-0.0040893554687500, -0.0071105957031250, -0.0046386718750000, -0.0083312988281250, +-0.0037536621093750, -0.0083312988281250, -0.0037841796875000, -0.0080871582031250, +-0.0037536621093750, -0.0086364746093750, -0.0032653808593750, -0.0085144042968750, +-0.0033264160156250, -0.0075683593750000, -0.0025634765625000, -0.0079345703125000, +-0.0027465820312500, -0.0073852539062500, -0.0021667480468750, -0.0062561035156250, +-0.0014343261718750, -0.0066528320312500, -0.0018920898437500, -0.0058593750000000, +0.0002746582031250, -0.0056457519531250, -0.0006103515625000, -0.0056152343750000, +0.0009155273437500, -0.0053100585937500, 0.0031127929687500, -0.0053405761718750, +0.0011596679687500, -0.0052490234375000, 0.0055847167968750, -0.0052185058593750, +0.0047302246093750, -0.0050659179687500, 0.0054931640625000, -0.0050048828125000, +0.0087280273437500, -0.0050964355468750, 0.0071105957031250, -0.0040588378906250, +0.0094299316406250, -0.0043945312500000, 0.0097045898437500, -0.0036010742187500, +0.0090942382812500, -0.0022277832031250, 0.0096740722656250, -0.0028686523437500, +0.0097351074218750, -0.0016479492187500, 0.0095214843750000, -0.0012817382812500, +0.0094604492187500, -0.0015258789062500, 0.0094909667968750, -0.0013427734375000, +0.0093994140625000, -0.0011596679687500, 0.0092468261718750, -0.0015563964843750, +0.0092468261718750, -0.0013732910156250, 0.0087280273437500, -0.0017089843750000, +0.0104675292968750, -0.0020141601562500, 0.0114440917968750, -0.0017395019531250, +0.0098571777343750, -0.0033264160156250, 0.0149230957031250, -0.0028991699218750, +0.0139160156250000, -0.0036315917968750, 0.0156860351562500, -0.0050964355468750, +0.0198364257812500, -0.0044250488281250, 0.0173645019531250, -0.0064392089843750, +0.0216064453125000, -0.0063171386718750, 0.0222167968750000, -0.0067443847656250, +0.0209350585937500, -0.0080871582031250, 0.0223388671875000, -0.0075988769531250, +0.0227050781250000, -0.0086669921875000, 0.0186462402343750, -0.0087280273437500, +0.0195617675781250, -0.0087585449218750, 0.0184326171875000, -0.0097961425781250, +0.0148620605468750, -0.0093078613281250, 0.0161132812500000, -0.0066833496093750, +0.0145568847656250, -0.0084533691406250, 0.0140380859375000, -0.0059814453125000, +0.0137634277343750, -0.0016479492187500, 0.0131530761718750, -0.0037536621093750, +0.0137939453125000, -0.0000305175781250, 0.0124511718750000, 0.0008850097656250, +0.0125122070312500, 0.0000610351562500, 0.0125732421875000, 0.0009765625000000, +0.0124206542968750, 0.0012207031250000, 0.0125732421875000, 0.0001525878906250, +0.0102233886718750, -0.0000305175781250, 0.0130004882812500, 0.0007019042968750, +0.0076599121093750, 0.0008544921875000, 0.0022583007812500, 0.0005798339843750, +0.0067749023437500, 0.0020751953125000, -0.0087890625000000, 0.0020751953125000, +-0.0076599121093750, 0.0020751953125000, -0.0097045898437500, 0.0023193359375000, +-0.0203552246093750, 0.0023498535156250, -0.0161743164062500, 0.0053405761718750, +-0.0166320800781250, 0.0032348632812500, -0.0209655761718750, 0.0056152343750000, +-0.0143432617187500, 0.0105285644531250, -0.0079040527343750, 0.0079650878906250, +-0.0128173828125000, 0.0106811523437500, 0.0001220703125000, 0.0130004882812500, +0.0006713867187500, 0.0086364746093750, 0.0004272460937500, 0.0066528320312500, +0.0065307617187500, 0.0099182128906250, 0.0051574707031250, -0.0022277832031250, +0.0059509277343750, -0.0014953613281250, 0.0064086914062500, -0.0018005371093750, +0.0062561035156250, -0.0097961425781250, 0.0066528320312500, -0.0078125000000000, +0.0065307617187500, -0.0034790039062500, 0.0054016113281250, -0.0058898925781250, +0.0062561035156250, -0.0048217773437500, 0.0049743652343750, 0.0020141601562500, +0.0014038085937500, 0.0014343261718750, 0.0033874511718750, 0.0043945312500000, +0.0028381347656250, 0.0007934570312500, 0.0043640136718750, 0.0049743652343750, +0.0024414062500000, 0.0104675292968750, 0.0000000000000000, 0.0068054199218750, +0.0015869140625000, 0.0094909667968750, 0.0009765625000000, 0.0122985839843750, +-0.0011291503906250, 0.0086059570312500, 0.0019836425781250, 0.0059509277343750, +0.0052795410156250, 0.0086364746093750, 0.0025939941406250, 0.0018920898437500, +0.0061950683593750, 0.0021057128906250, 0.0084228515625000, 0.0008544921875000, +0.0047302246093750, -0.0026245117187500, 0.0027465820312500, -0.0007324218750000, +0.0056457519531250, -0.0081481933593750, 0.0003662109375000, -0.0063781738281250, +-0.0021667480468750, -0.0100402832031250, 0.0016784667968750, -0.0174255371093750, +0.0029296875000000, -0.0129394531250000, 0.0006103515625000, -0.0185852050781250, +0.0088500976562500, -0.0220336914062500, 0.0083618164062500, -0.0158081054687500, +0.0084228515625000, -0.0134277343750000, 0.0140686035156250, -0.0174560546875000, +0.0128479003906250, -0.0026855468750000, 0.0082092285156250, -0.0047607421875000, +0.0103149414062500, -0.0018920898437500, 0.0082702636718750, 0.0085144042968750, +0.0035095214843750, 0.0039672851562500, 0.0056762695312500, 0.0121459960937500, +0.0008850097656250, 0.0132751464843750, 0.0012817382812500, 0.0114440917968750, +0.0003356933593750, 0.0140075683593750, -0.0028076171875000, 0.0142517089843750, +-0.0012817382812500, 0.0123596191406250, -0.0049743652343750, 0.0117187500000000, +-0.0047302246093750, 0.0135803222656250, -0.0051269531250000, 0.0139465332031250, +-0.0074462890625000, 0.0126342773437500, -0.0065612792968750, 0.0181579589843750, +-0.0079650878906250}, +{0.0157165527343750, -0.0041198730468750, 0.0165100097656250, -0.0037536621093750, +0.0164794921875000, -0.0041809082031250, 0.0161437988281250, -0.0035095214843750, +0.0164794921875000, -0.0034179687500000, 0.0161743164062500, -0.0036621093750000, +0.0144958496093750, -0.0040893554687500, 0.0150756835937500, -0.0025634765625000, +0.0143737792968750, -0.0020141601562500, 0.0123901367187500, -0.0031127929687500, +0.0132446289062500, 0.0029602050781250, 0.0145263671875000, 0.0018615722656250, +0.0130920410156250, 0.0036926269531250, 0.0145568847656250, 0.0086975097656250, +0.0176696777343750, 0.0064086914062500, 0.0162963867187500, 0.0094604492187500, +0.0159301757812500, 0.0104980468750000, 0.0189819335937500, 0.0097656250000000, +0.0130004882812500, 0.0101318359375000, 0.0080871582031250, 0.0099792480468750, +0.0126342773437500, 0.0087585449218750, -0.0048217773437500, 0.0101928710937500, +-0.0023498535156250, 0.0080261230468750, -0.0061035156250000, 0.0053405761718750, +-0.0198364257812500, 0.0073547363281250, -0.0140380859375000, 0.0018615722656250, +-0.0173034667968750, 0.0025634765625000, -0.0217590332031250, 0.0021057128906250, +-0.0154724121093750, -0.0021057128906250, -0.0104064941406250, -0.0007324218750000, +-0.0146484375000000, 0.0001831054687500, -0.0038452148437500, -0.0015258789062500, +-0.0030517578125000, 0.0004577636718750, -0.0030517578125000, 0.0038146972656250, +0.0019531250000000, 0.0019531250000000, 0.0008544921875000, 0.0020751953125000, +0.0020446777343750, 0.0035400390625000, 0.0022277832031250, 0.0029602050781250, +0.0026550292968750, 0.0005493164062500, 0.0043334960937500, 0.0065917968750000, +-0.0051574707031250, 0.0099182128906250, -0.0006103515625000, 0.0112304687500000, +-0.0027770996093750, 0.0067443847656250, -0.0001831054687500, 0.0048217773437500, +0.0039367675781250, 0.0082397460937500, 0.0019836425781250, -0.0014953613281250, +0.0025329589843750, -0.0009155273437500, 0.0044555664062500, -0.0020141601562500, +0.0024108886718750, -0.0075988769531250, -0.0007324218750000, -0.0053405761718750, +0.0009765625000000, -0.0104370117187500, 0.0020446777343750, -0.0095214843750000, +-0.0009155273437500, -0.0121765136718750, 0.0028381347656250, -0.0175170898437500, +0.0083923339843750, -0.0144653320312500, 0.0049133300781250, -0.0173645019531250, +0.0075378417968750, -0.0206298828125000, 0.0104980468750000, -0.0137329101562500, +0.0071716308593750, -0.0105285644531250, 0.0039978027343750, -0.0156250000000000, +0.0060424804687500, 0.0046997070312500, 0.0024108886718750, 0.0022888183593750, +0.0009155273437500, 0.0044555664062500, 0.0036926269531250, 0.0180969238281250, +0.0040588378906250, 0.0131835937500000, 0.0021057128906250, 0.0165710449218750, +0.0091857910156250, 0.0192565917968750, 0.0097351074218750, 0.0167236328125000, +0.0082397460937500, 0.0153808593750000, 0.0105895996093750, 0.0167846679687500, +0.0108642578125000, 0.0126037597656250, 0.0073852539062500, 0.0123596191406250, +0.0086059570312500, 0.0135803222656250, 0.0063781738281250, 0.0116577148437500, +0.0026855468750000, 0.0110168457031250, 0.0048522949218750, 0.0159301757812500, +-0.0006408691406250, 0.0147399902343750, 0.0000610351562500, 0.0159301757812500, +-0.0017395019531250, 0.0196533203125000, -0.0059509277343750, 0.0174255371093750, +-0.0034790039062500, 0.0203857421875000, -0.0076599121093750, 0.0210876464843750, +-0.0085449218750000, 0.0194702148437500, -0.0073242187500000, 0.0195617675781250, +-0.0079956054687500, 0.0201721191406250, -0.0082397460937500, 0.0173339843750000, +-0.0068359375000000, 0.0177917480468750, -0.0067443847656250, 0.0167236328125000, +-0.0067138671875000, 0.0147705078125000, -0.0062255859375000, 0.0159606933593750, +-0.0063781738281250, 0.0113830566406250, -0.0061340332031250, 0.0128479003906250, +-0.0063781738281250, 0.0105285644531250, -0.0057983398437500, 0.0062561035156250, +-0.0051574707031250, 0.0090026855468750, -0.0057067871093750, 0.0012207031250000, +-0.0041503906250000, 0.0026245117187500, -0.0040283203125000, 0.0002746582031250, +-0.0041503906250000, -0.0054931640625000, -0.0036315917968750, -0.0019836425781250, +-0.0035705566406250, -0.0097351074218750, -0.0027160644531250, -0.0091857910156250, +-0.0032043457031250, -0.0103759765625000, -0.0023803710937500, -0.0152893066406250, +-0.0008850097656250, -0.0126647949218750, -0.0016784667968750, -0.0159301757812500, +-0.0007629394531250, -0.0164184570312500, -0.0003051757812500, -0.0154418945312500, +-0.0006713867187500, -0.0164184570312500, -0.0008544921875000, -0.0161743164062500, +-0.0007019042968750, -0.0136413574218750, -0.0005798339843750, -0.0147705078125000, +-0.0007019042968750, -0.0127563476562500, -0.0007324218750000, -0.0099487304687500, +-0.0003967285156250, -0.0119628906250000, -0.0003967285156250, -0.0061950683593750, +-0.0012512207031250, -0.0074157714843750, -0.0010375976562500, -0.0056152343750000, +-0.0012817382812500, -0.0012207031250000, -0.0021972656250000, -0.0039062500000000, +-0.0018920898437500, 0.0021057128906250, -0.0021972656250000, 0.0010375976562500, +-0.0022583007812500, 0.0020751953125000, -0.0024108886718750, 0.0063171386718750, +-0.0026245117187500, 0.0041503906250000, -0.0024414062500000, 0.0079650878906250, +-0.0030517578125000, 0.0071411132812500, -0.0030517578125000, 0.0076904296875000, +-0.0029907226562500, 0.0103759765625000, -0.0032348632812500, 0.0086364746093750, +-0.0031127929687500, 0.0111999511718750, -0.0030517578125000, 0.0107116699218750, +-0.0029602050781250, 0.0107421875000000, -0.0031738281250000, 0.0123291015625000, +-0.0032348632812500, 0.0114135742187500, -0.0030212402343750, 0.0124511718750000, +-0.0042114257812500, 0.0123901367187500, -0.0038146972656250, 0.0122070312500000, +-0.0042724609375000, 0.0126342773437500, -0.0053710937500000, 0.0124206542968750, +-0.0048217773437500, 0.0124816894531250, -0.0058898925781250, 0.0123291015625000, +-0.0057373046875000, 0.0120849609375000, -0.0063171386718750, 0.0120849609375000, +-0.0073242187500000, 0.0119934082031250, -0.0065307617187500, 0.0114135742187500, +-0.0075683593750000, 0.0116271972656250, -0.0080566406250000, 0.0107116699218750, +-0.0071716308593750, 0.0096740722656250, -0.0067749023437500, 0.0101623535156250, +-0.0073852539062500, 0.0079345703125000, -0.0066528320312500, 0.0083618164062500, +-0.0060729980468750, 0.0073852539062500, -0.0066223144531250, 0.0052795410156250, +-0.0072631835937500, 0.0058898925781250, -0.0067443847656250, 0.0032348632812500, +-0.0065307617187500, 0.0032958984375000, -0.0072326660156250, 0.0025634765625000, +-0.0064697265625000, 0.0006408691406250, -0.0054626464843750, 0.0009765625000000, +-0.0061950683593750, -0.0009765625000000, -0.0047607421875000, -0.0009155273437500, +-0.0048217773437500, -0.0013427734375000, -0.0052490234375000, -0.0027465820312500, +-0.0044860839843750, -0.0024414062500000, -0.0046081542968750, -0.0036315917968750, +-0.0069274902343750, -0.0036010742187500, -0.0062255859375000, -0.0041198730468750, +-0.0065307617187500, -0.0048217773437500, -0.0087890625000000, -0.0043945312500000, +-0.0082702636718750, -0.0062255859375000, -0.0063476562500000, -0.0057678222656250, +-0.0073547363281250, -0.0067749023437500, -0.0068359375000000, -0.0086364746093750, +-0.0045166015625000, -0.0074768066406250, -0.0052795410156250, -0.0099182128906250, +-0.0064392089843750, -0.0101318359375000, -0.0050354003906250, -0.0098876953125000, +-0.0069274902343750, -0.0109863281250000, -0.0098266601562500, -0.0106201171875000, +-0.0080566406250000, -0.0091247558593750, -0.0106506347656250, -0.0099182128906250, +-0.0111694335937500, -0.0076904296875000, -0.0107116699218750, -0.0051269531250000, +-0.0118103027343750, -0.0064086914062500, -0.0116271972656250, -0.0012512207031250, +-0.0085754394531250, -0.0019836425781250, -0.0098571777343750, -0.0000305175781250, +-0.0086059570312500, 0.0045471191406250, -0.0058593750000000, 0.0023193359375000, +-0.0070800781250000, 0.0052490234375000, -0.0021667480468750, 0.0063171386718750, +-0.0030517578125000, 0.0057678222656250, -0.0027770996093750, 0.0058593750000000, +0.0009155273437500, 0.0060729980468750, -0.0000305175781250, 0.0075988769531250, +0.0002441406250000, 0.0065612792968750, 0.0011901855468750, 0.0083007812500000, +0.0000000000000000, 0.0109863281250000, -0.0012817382812500, 0.0095825195312500, +-0.0004272460937500, 0.0126342773437500, -0.0016479492187500, 0.0130310058593750, +-0.0020141601562500, 0.0124206542968750, -0.0010375976562500, 0.0137023925781250, +-0.0008850097656250, 0.0135192871093750, -0.0015258789062500, 0.0098571777343750, +-0.0003662109375000, 0.0116882324218750, -0.0000610351562500, 0.0088806152343750, +0.0003967285156250, 0.0041503906250000, 0.0006408691406250, 0.0068359375000000, +0.0000610351562500, 0.0008544921875000, 0.0014648437500000, 0.0012512207031250, +0.0011291503906250, -0.0000915527343750, 0.0017700195312500, -0.0042419433593750, +0.0029907226562500, -0.0021057128906250, 0.0022888183593750, -0.0050354003906250, +0.0038452148437500, -0.0062561035156250, 0.0034790039062500, -0.0040893554687500, +0.0043640136718750, -0.0032958984375000, 0.0061950683593750, -0.0031127929687500, +0.0057983398437500, 0.0027770996093750, 0.0076293945312500, 0.0004577636718750, +0.0078125000000000, 0.0012512207031250, 0.0061035156250000, 0.0062255859375000, +0.0066833496093750, 0.0039367675781250, 0.0078430175781250, 0.0058288574218750, +0.0018310546875000, 0.0067749023437500, 0.0026245117187500, 0.0063781738281250, +0.0012817382812500, 0.0064392089843750, -0.0031738281250000, 0.0063476562500000, +-0.0012512207031250, 0.0064392089843750, -0.0029907226562500, 0.0071716308593750, +-0.0036010742187500, 0.0057678222656250, -0.0033874511718750, 0.0048217773437500, +-0.0042114257812500, 0.0061035156250000, -0.0038146972656250, 0.0018005371093750, +-0.0019531250000000, 0.0027770996093750, -0.0040283203125000, 0.0012817382812500, +-0.0008544921875000, -0.0028381347656250, 0.0029296875000000, -0.0007629394531250, +-0.0000305175781250, -0.0014648437500000, 0.0085754394531250, -0.0028686523437500, +0.0079040527343750, -0.0020751953125000, 0.0087585449218750, -0.0007324218750000, +0.0146789550781250, -0.0012512207031250, 0.0127563476562500, -0.0021972656250000, +0.0131225585937500, -0.0017395019531250, 0.0147399902343750, -0.0014953613281250, +0.0130004882812500, -0.0024719238281250, 0.0109863281250000, -0.0025634765625000, +0.0120544433593750, -0.0007324218750000, 0.0094909667968750, -0.0014038085937500, +0.0091857910156250, -0.0010986328125000, 0.0090332031250000, 0.0004882812500000, +0.0077819824218750, -0.0002746582031250, 0.0079345703125000, -0.0001220703125000, +0.0066833496093750, 0.0005798339843750, 0.0070800781250000, -0.0001831054687500, +0.0049133300781250, -0.0007629394531250, 0.0029907226562500, -0.0002746582031250, +0.0044250488281250, -0.0033874511718750, -0.0016479492187500, -0.0014343261718750, +-0.0012817382812500, -0.0035400390625000, -0.0022888183593750, -0.0072326660156250, +-0.0064086914062500, -0.0044860839843750, -0.0047302246093750, -0.0107727050781250, +-0.0058898925781250, -0.0095520019531250, -0.0066223144531250, -0.0105285644531250, +-0.0050964355468750, -0.0158386230468750, -0.0041503906250000, -0.0136108398437500, +-0.0047607421875000, -0.0137023925781250, -0.0030517578125000, -0.0161743164062500, +-0.0024108886718750, -0.0132751464843750, -0.0025329589843750, -0.0105285644531250, +-0.0021972656250000, -0.0133361816406250, -0.0020141601562500, -0.0062561035156250, +-0.0023193359375000, -0.0070800781250000, -0.0024414062500000, -0.0065612792968750, +-0.0023803710937500}, +{-0.0013732910156250, 0.0049438476562500, -0.0016784667968750, 0.0062255859375000, +-0.0019531250000000, 0.0061035156250000, -0.0015869140625000, 0.0066528320312500, +-0.0011596679687500, 0.0062866210937500, -0.0020446777343750, 0.0074768066406250, +-0.0008239746093750, 0.0085754394531250, 0.0008239746093750, 0.0078125000000000, +-0.0000305175781250, 0.0118103027343750, 0.0027160644531250, 0.0114135742187500, +0.0022277832031250, 0.0111083984375000, 0.0025634765625000, 0.0139160156250000, +0.0046691894531250, 0.0135192871093750, 0.0039367675781250, 0.0102539062500000, +0.0043640136718750, 0.0118408203125000, 0.0043640136718750, 0.0089111328125000, +0.0048522949218750, 0.0048217773437500, 0.0049743652343750, 0.0074768066406250, +0.0045471191406250, 0.0003356933593750, 0.0075683593750000, 0.0007934570312500, +0.0071716308593750, 0.0002746582031250, 0.0068359375000000, -0.0049133300781250, +0.0093078613281250, -0.0040588378906250, 0.0085754394531250, -0.0035095214843750, +0.0032348632812500, -0.0047302246093750, 0.0062255859375000, -0.0028076171875000, +0.0045166015625000, -0.0013122558593750, -0.0012512207031250, -0.0033264160156250, +0.0014648437500000, 0.0028686523437500, -0.0020141601562500, 0.0022888183593750, +-0.0031127929687500, 0.0024719238281250, -0.0019836425781250, 0.0060424804687500, +-0.0025329589843750, 0.0049743652343750, -0.0027770996093750, 0.0063781738281250, +-0.0002746582031250, 0.0059814453125000, -0.0016479492187500, 0.0066528320312500, +0.0013122558593750, 0.0081787109375000, 0.0048828125000000, 0.0073242187500000, +0.0019836425781250, 0.0088806152343750, 0.0093994140625000, 0.0095825195312500, +0.0096130371093750, 0.0073242187500000, 0.0094604492187500, 0.0071716308593750, +0.0133056640625000, 0.0088500976562500, 0.0122985839843750, 0.0009155273437500, +0.0108032226562500, 0.0022888183593750, 0.0125427246093750, 0.0015258789062500, +0.0108337402343750, -0.0039672851562500, 0.0077514648437500, -0.0019226074218750, +0.0093688964843750, -0.0032348632812500, 0.0075683593750000, -0.0036926269531250, +0.0068664550781250, -0.0037536621093750, 0.0070800781250000, -0.0042419433593750, +0.0071105957031250, -0.0039062500000000, 0.0070190429687500, -0.0045471191406250, +0.0043334960937500, -0.0049438476562500, 0.0055541992187500, -0.0044555664062500, +0.0035705566406250, -0.0042724609375000, 0.0003356933593750, -0.0045776367187500, +0.0019836425781250, -0.0032958984375000, -0.0031127929687500, -0.0038757324218750, +-0.0032958984375000, -0.0031433105468750, -0.0032958984375000, -0.0018920898437500, +-0.0061645507812500, -0.0028381347656250, -0.0054321289062500, -0.0006408691406250, +-0.0036926269531250, -0.0006713867187500, -0.0046081542968750, -0.0018310546875000, +-0.0030212402343750, -0.0008544921875000, -0.0003356933593750, -0.0001831054687500, +-0.0012207031250000, -0.0037841796875000, 0.0005187988281250, -0.0021972656250000, +0.0014648437500000, -0.0050354003906250, 0.0008850097656250, -0.0087280273437500, +0.0009460449218750, -0.0049438476562500, 0.0015563964843750, -0.0133361816406250, +0.0007934570312500, -0.0130004882812500, 0.0007934570312500, -0.0121154785156250, +0.0024108886718750, -0.0166320800781250, 0.0029602050781250, -0.0155639648437500, +0.0025939941406250, -0.0126342773437500, 0.0063781738281250, -0.0153808593750000, +0.0061035156250000, -0.0118408203125000, 0.0077209472656250, -0.0068664550781250, +0.0109558105468750, -0.0107727050781250, 0.0097961425781250, -0.0034790039062500, +0.0130920410156250, -0.0035095214843750, 0.0135803222656250, -0.0035705566406250, +0.0133972167968750, 0.0001220703125000, 0.0147705078125000, -0.0013427734375000, +0.0144042968750000, -0.0001525878906250, 0.0131835937500000, 0.0005187988281250, +0.0136718750000000, -0.0002136230468750, 0.0124511718750000, -0.0003662109375000, +0.0107116699218750, 0.0001220703125000, 0.0113525390625000, -0.0012207031250000, +0.0089416503906250, -0.0011596679687500, 0.0088500976562500, -0.0012817382812500, +0.0077514648437500, -0.0019531250000000, 0.0056762695312500, -0.0018005371093750, +0.0062255859375000, -0.0025329589843750, 0.0038452148437500, -0.0021667480468750, +0.0032653808593750, -0.0030822753906250, 0.0027770996093750, -0.0042114257812500, +0.0013122558593750, -0.0032958984375000, 0.0012512207031250, -0.0054626464843750, +0.0010681152343750, -0.0054931640625000, 0.0003356933593750, -0.0053405761718750, +0.0002136230468750, -0.0063171386718750, 0.0002136230468750, -0.0060424804687500, +-0.0003967285156250, -0.0061340332031250, -0.0001220703125000, -0.0060119628906250, +-0.0006408691406250, -0.0060424804687500, -0.0006103515625000, -0.0061645507812500, +-0.0003356933593750, -0.0059814453125000, -0.0011291503906250, -0.0059814453125000, +-0.0005798339843750, -0.0061340332031250, -0.0012207031250000, -0.0059204101562500, +-0.0012207031250000, -0.0057678222656250, -0.0009765625000000, -0.0059509277343750, +-0.0019226074218750, -0.0054321289062500, -0.0009155273437500, -0.0056152343750000, +-0.0020446777343750, -0.0052795410156250, -0.0017395019531250, -0.0047912597656250, +-0.0005798339843750, -0.0051879882812500, -0.0021057128906250, -0.0040588378906250, +-0.0004272460937500, -0.0041503906250000, -0.0009460449218750, -0.0040283203125000, +-0.0007019042968750, -0.0032653808593750, 0.0003356933593750, -0.0036010742187500, +-0.0006103515625000, -0.0038146972656250, 0.0021057128906250, -0.0035095214843750, +0.0008850097656250, -0.0039672851562500, 0.0020446777343750, -0.0046081542968750, +0.0044250488281250, -0.0043029785156250, 0.0023803710937500, -0.0048217773437500, +0.0069580078125000, -0.0048828125000000, 0.0060729980468750, -0.0049133300781250, +0.0065917968750000, -0.0052185058593750, 0.0098876953125000, -0.0049438476562500, +0.0083007812500000, -0.0043640136718750, 0.0098571777343750, -0.0050048828125000, +0.0107727050781250, -0.0034790039062500, 0.0091552734375000, -0.0018920898437500, +0.0089416503906250, -0.0030822753906250, 0.0099792480468750, 0.0003356933593750, +0.0045471191406250, 0.0006408691406250, 0.0068359375000000, 0.0000915527343750, +0.0033569335937500, 0.0015258789062500, -0.0024414062500000, 0.0015563964843750, +0.0017089843750000, -0.0006103515625000, -0.0072937011718750, 0.0003051757812500, +-0.0064392089843750, -0.0013427734375000, -0.0072021484375000, -0.0037841796875000, +-0.0133056640625000, -0.0021972656250000, -0.0105895996093750, -0.0074768066406250, +-0.0111999511718750, -0.0067138671875000, -0.0134277343750000, -0.0079345703125000, +-0.0100097656250000, -0.0122985839843750, -0.0074157714843750, -0.0104370117187500, +-0.0097045898437500, -0.0108947753906250, -0.0004577636718750, -0.0127258300781250, +-0.0022277832031250, -0.0100708007812500, 0.0006103515625000, -0.0078125000000000, +0.0082397460937500, -0.0097656250000000, 0.0041503906250000, -0.0035095214843750, +0.0095825195312500, -0.0045166015625000, 0.0110778808593750, -0.0023803710937500, +0.0094604492187500, 0.0025329589843750, 0.0103149414062500, -0.0000610351562500, +0.0105590820312500, 0.0061950683593750, 0.0090026855468750, 0.0066528320312500, +0.0085449218750000, 0.0058898925781250, 0.0092773437500000, 0.0087890625000000, +0.0091857910156250, 0.0085449218750000, 0.0086669921875000, 0.0051574707031250, +0.0106811523437500, 0.0071411132812500, 0.0105285644531250, 0.0041503906250000, +0.0105590820312500, -0.0011291503906250, 0.0114440917968750, 0.0018920898437500, +0.0109863281250000, -0.0007934570312500, 0.0120544433593750, -0.0031738281250000, +0.0124206542968750, -0.0002136230468750, 0.0117492675781250, 0.0014038085937500, +0.0114440917968750, -0.0005798339843750, 0.0118408203125000, 0.0062561035156250, +0.0119018554687500, 0.0062866210937500, 0.0110778808593750, 0.0049743652343750, +0.0129394531250000, 0.0078430175781250, 0.0148620605468750, 0.0079345703125000, +0.0132446289062500, 0.0055541992187500, 0.0158996582031250, 0.0057067871093750, +0.0177001953125000, 0.0057983398437500, 0.0138854980468750, 0.0040283203125000, +0.0126953125000000, 0.0042419433593750, 0.0150756835937500, 0.0070495605468750, +0.0013732910156250, 0.0060119628906250, 0.0042419433593750, 0.0073242187500000, +-0.0005493164062500, 0.0106506347656250, -0.0126953125000000, 0.0088806152343750, +-0.0069274902343750, 0.0085144042968750, -0.0148010253906250, 0.0104675292968750, +-0.0172119140625000, 0.0083007812500000, -0.0146179199218750, 0.0031738281250000, +-0.0150756835937500, -0.0047302246093750, -0.0017089843750000, -0.0105590820312500, +-0.0111694335937500, -0.0097351074218750, -0.0111389160156250, -0.0093383789062500, +-0.0104370117187500, -0.0114135742187500, -0.0117492675781250, -0.0111694335937500, +-0.0121154785156250, -0.0063476562500000, -0.0104064941406250, -0.0094909667968750, +-0.0111083984375000, -0.0046081542968750, -0.0089721679687500, 0.0023193359375000, +-0.0071105957031250, -0.0023803710937500, -0.0089111328125000, 0.0107116699218750, +-0.0013427734375000, 0.0102539062500000, -0.0020446777343750, 0.0109252929687500, +-0.0012817382812500, 0.0190124511718750, 0.0039062500000000, 0.0165100097656250, +0.0023498535156250, 0.0162658691406250, 0.0023803710937500, 0.0188293457031250, +0.0035095214843750, 0.0155334472656250, 0.0023498535156250, 0.0113830566406250, +0.0008850097656250, 0.0142211914062500, 0.0019531250000000, 0.0108947753906250, +0.0009155273437500, 0.0092773437500000, -0.0005493164062500, 0.0109863281250000, +0.0022888183593750, 0.0113220214843750, 0.0046997070312500, 0.0104980468750000, +0.0023498535156250, 0.0130615234375000, 0.0057678222656250, 0.0124511718750000, +0.0072937011718750, 0.0133056640625000, 0.0057983398437500, 0.0154113769531250, +0.0052490234375000, 0.0140686035156250, 0.0059509277343750, 0.0162963867187500, +0.0043945312500000, 0.0163269042968750, 0.0040893554687500, 0.0169982910156250, +0.0048217773437500, 0.0186767578125000, 0.0045471191406250, 0.0175476074218750, +0.0041809082031250, 0.0183410644531250, 0.0060424804687500, 0.0200805664062500, +0.0064392089843750, 0.0155334472656250, 0.0054321289062500, 0.0128479003906250, +0.0056457519531250, 0.0162963867187500, 0.0061035156250000, 0.0031738281250000, +0.0032653808593750, 0.0056152343750000, 0.0043640136718750, 0.0016479492187500, +0.0017700195312500, -0.0086059570312500, -0.0013427734375000, -0.0030212402343750, +0.0011291503906250, -0.0130920410156250, -0.0068969726562500, -0.0143127441406250, +-0.0061645507812500, -0.0126037597656250, -0.0073242187500000, -0.0162658691406250, +-0.0130004882812500, -0.0160522460937500, -0.0107116699218750, -0.0127868652343750, +-0.0114746093750000, -0.0143127441406250, -0.0134582519531250, -0.0128479003906250, +-0.0105590820312500, -0.0097351074218750, -0.0079650878906250, -0.0115661621093750, +-0.0100402832031250, -0.0072631835937500, -0.0048828125000000, -0.0076293945312500, +-0.0046691894531250, -0.0065307617187500, -0.0046997070312500, -0.0034790039062500, +-0.0022583007812500, -0.0051269531250000, -0.0030822753906250, -0.0026550292968750, +-0.0023193359375000, -0.0018310546875000, -0.0020141601562500, -0.0026550292968750, +-0.0027770996093750, -0.0022583007812500, -0.0028381347656250, -0.0016174316406250, +-0.0024719238281250, -0.0030822753906250, -0.0047302246093750, -0.0026245117187500, +-0.0045471191406250, -0.0028991699218750, -0.0044555664062500, -0.0038452148437500, +-0.0058288574218750, -0.0031127929687500, -0.0055847167968750, -0.0046386718750000, +-0.0044860839843750, -0.0044860839843750, -0.0048828125000000, -0.0046081542968750, +-0.0046081542968750, -0.0054321289062500, -0.0036010742187500, -0.0048522949218750, +-0.0039062500000000}, +{0.0138244628906250, 0.0069274902343750, 0.0141906738281250, -0.0010986328125000, +0.0054016113281250, -0.0014648437500000, 0.0083923339843750, -0.0019836425781250, +0.0049743652343750, -0.0084228515625000, -0.0096130371093750, -0.0046386718750000, +0.0143737792968750, 0.0008544921875000, 0.0062255859375000, -0.0033874511718750, +0.0118713378906250, 0.0020446777343750, 0.0063781738281250, 0.0079650878906250, +-0.0021362304687500, 0.0033264160156250, 0.0018920898437500, 0.0134582519531250, +-0.0032958984375000, 0.0146179199218750, -0.0045471191406250, 0.0130310058593750, +-0.0042114257812500, 0.0169067382812500, -0.0055847167968750, 0.0165710449218750, +-0.0049133300781250, 0.0122375488281250, -0.0065917968750000, 0.0136718750000000, +-0.0068969726562500, 0.0123291015625000, -0.0058898925781250, 0.0080261230468750, +-0.0063781738281250, 0.0095825195312500, -0.0068359375000000, 0.0087585449218750, +-0.0026855468750000, 0.0073242187500000, -0.0037536621093750, 0.0094299316406250, +-0.0022888183593750, 0.0112915039062500, 0.0018615722656250, 0.0093078613281250, +-0.0000305175781250, 0.0111999511718750, 0.0005493164062500, 0.0120849609375000, +0.0024414062500000, 0.0119323730468750, 0.0002746582031250, 0.0118713378906250, +-0.0030212402343750, 0.0116882324218750, -0.0012512207031250, 0.0129699707031250, +0.0000305175781250, 0.0128479003906250, -0.0022888183593750, 0.0128784179687500, +0.0002136230468750, 0.0137023925781250, 0.0043945312500000, 0.0131835937500000, +0.0022888183593750, 0.0121459960937500, 0.0050964355468750, 0.0133361816406250, +0.0063476562500000, 0.0099182128906250, 0.0043945312500000, 0.0076904296875000, +0.0039062500000000, 0.0102844238281250, 0.0050354003906250, -0.0025634765625000, +0.0017089843750000, 0.0001220703125000, 0.0013427734375000, -0.0026245117187500, +0.0020141601562500, -0.0128173828125000, 0.0013122558593750, -0.0080261230468750, +0.0013427734375000, -0.0121154785156250, 0.0011291503906250, -0.0145263671875000, +0.0015869140625000, -0.0112915039062500, 0.0008544921875000, -0.0104370117187500, +0.0001525878906250, -0.0125732421875000, 0.0006713867187500, -0.0056152343750000, +-0.0018005371093750, -0.0060729980468750, -0.0007934570312500, -0.0063171386718750, +-0.0025634765625000, -0.0023193359375000, -0.0054321289062500, -0.0032348632812500, +-0.0036315917968750, -0.0046691894531250, -0.0087280273437500, -0.0035705566406250, +-0.0085144042968750, -0.0047912597656250, -0.0088806152343750, -0.0068054199218750, +-0.0122985839843750, -0.0054626464843750, -0.0112304687500000, -0.0073852539062500, +-0.0100402832031250, -0.0075988769531250, -0.0115661621093750, -0.0073242187500000, +-0.0096740722656250, -0.0080261230468750, -0.0068054199218750, -0.0077209472656250, +-0.0084228515625000, -0.0068054199218750, -0.0052490234375000, -0.0073547363281250, +-0.0051269531250000, -0.0058288574218750, -0.0046997070312500, -0.0043334960937500, +-0.0029907226562500, -0.0057373046875000, -0.0038146972656250, -0.0020141601562500, +-0.0021057128906250, -0.0024414062500000, -0.0018310546875000, -0.0016174316406250, +-0.0024719238281250, 0.0009155273437500, -0.0020446777343750, -0.0004882812500000, +-0.0018615722656250, 0.0019531250000000, -0.0035400390625000, 0.0020141601562500, +-0.0033874511718750, 0.0021667480468750, -0.0036315917968750, 0.0034484863281250, +-0.0047302246093750, 0.0027770996093750, -0.0044555664062500, 0.0035400390625000, +-0.0048828125000000, 0.0036010742187500, -0.0048217773437500, 0.0036315917968750, +-0.0050048828125000, 0.0040588378906250, -0.0052490234375000, 0.0038146972656250, +-0.0049743652343750, 0.0037231445312500, -0.0050964355468750, 0.0039978027343750, +-0.0052185058593750, 0.0036621093750000, -0.0049133300781250, 0.0032348632812500, +-0.0045166015625000, 0.0033569335937500, -0.0046691894531250, 0.0027770996093750, +-0.0047607421875000, 0.0031127929687500, -0.0042724609375000, 0.0026855468750000, +-0.0047912597656250, 0.0019226074218750, -0.0055236816406250, 0.0022277832031250, +-0.0049743652343750, 0.0012817382812500, -0.0058288574218750, 0.0014953613281250, +-0.0059814453125000, 0.0010375976562500, -0.0058898925781250, 0.0000915527343750, +-0.0061340332031250, 0.0003967285156250, -0.0061035156250000, -0.0007934570312500, +-0.0061340332031250, -0.0007629394531250, -0.0061340332031250, -0.0008544921875000, +-0.0059814453125000, -0.0016174316406250, -0.0058898925781250, -0.0015563964843750, +-0.0059814453125000, -0.0016784667968750, -0.0058593750000000, -0.0017089843750000, +-0.0057373046875000, -0.0016479492187500, -0.0059204101562500, -0.0015563964843750, +-0.0061645507812500, -0.0015563964843750, -0.0059204101562500, -0.0015869140625000, +-0.0054321289062500, -0.0015869140625000, -0.0061035156250000, -0.0013732910156250, +-0.0050659179687500, -0.0012512207031250, -0.0038757324218750, -0.0014038085937500, +-0.0049743652343750, -0.0014953613281250, -0.0025634765625000, -0.0016174316406250, +-0.0026855468750000, -0.0019531250000000, -0.0026855468750000, -0.0021362304687500, +-0.0010681152343750, -0.0020751953125000, -0.0017089843750000, -0.0029296875000000, +-0.0031738281250000, -0.0028686523437500, -0.0018005371093750, -0.0031127929687500, +-0.0039978027343750, -0.0037841796875000, -0.0069580078125000, -0.0035400390625000, +-0.0047912597656250, -0.0035705566406250, -0.0088806152343750, -0.0042114257812500, +-0.0092773437500000, -0.0035400390625000, -0.0085449218750000, -0.0028686523437500, +-0.0101928710937500, -0.0034790039062500, -0.0100097656250000, -0.0010681152343750, +-0.0078125000000000, -0.0016784667968750, -0.0090332031250000, -0.0000915527343750, +-0.0075683593750000, 0.0024108886718750, -0.0046997070312500, 0.0008850097656250, +-0.0065917968750000, 0.0051269531250000, -0.0047912597656250, 0.0049743652343750, +-0.0040893554687500, 0.0058898925781250, -0.0050048828125000, 0.0087585449218750, +-0.0051269531250000, 0.0074768066406250, -0.0049438476562500, 0.0097961425781250, +-0.0059814453125000, 0.0103454589843750, -0.0058593750000000, 0.0093688964843750, +-0.0054931640625000, 0.0097045898437500, -0.0060119628906250, 0.0099487304687500, +-0.0061950683593750, 0.0074462890625000, -0.0048217773437500, 0.0076904296875000, +-0.0050354003906250, 0.0066833496093750, -0.0045166015625000, 0.0046081542968750, +-0.0038146972656250, 0.0053710937500000, -0.0046691894531250, 0.0033264160156250, +-0.0023803710937500, 0.0032348632812500, -0.0024719238281250, 0.0033569335937500, +-0.0025329589843750, 0.0022583007812500, -0.0013732910156250, 0.0023803710937500, +-0.0018920898437500, 0.0023803710937500, -0.0016479492187500, 0.0023498535156250, +-0.0013732910156250, 0.0019226074218750, -0.0013732910156250, 0.0017395019531250, +-0.0018920898437500, 0.0018615722656250, -0.0018310546875000, 0.0002746582031250, +0.0005798339843750, 0.0003051757812500, -0.0007324218750000, 0.0001525878906250, +0.0010986328125000, -0.0011291503906250, 0.0046386718750000, -0.0010681152343750, +0.0026855468750000, 0.0001220703125000, 0.0039672851562500, -0.0007629394531250, +0.0052185058593750, 0.0008239746093750, 0.0046386718750000, 0.0029602050781250, +0.0039367675781250, 0.0016174316406250, 0.0043640136718750, 0.0046997070312500, +0.0047302246093750, 0.0052795410156250, 0.0036621093750000, 0.0044250488281250, +0.0053710937500000, 0.0048522949218750, 0.0074768066406250, 0.0051574707031250, +0.0058898925781250, 0.0057373046875000, 0.0078430175781250, 0.0046997070312500, +0.0096130371093750, 0.0065612792968750, 0.0060424804687500, 0.0085754394531250, +0.0040893554687500, 0.0070190429687500, 0.0070495605468750, 0.0113830566406250, +-0.0003051757812500, 0.0115051269531250, -0.0006713867187500, 0.0109863281250000, +0.0003356933593750, 0.0135498046875000, -0.0031127929687500, 0.0130615234375000, +-0.0025024414062500, 0.0084838867187500, 0.0026550292968750, 0.0111389160156250, +0.0003662109375000, 0.0093383789062500, 0.0016174316406250, 0.0048522949218750, +0.0060729980468750, 0.0078125000000000, 0.0039367675781250, 0.0011596679687500, +0.0086059570312500, 0.0017395019531250, 0.0083923339843750, 0.0010681152343750, +0.0090332031250000, -0.0033874511718750, 0.0122985839843750, -0.0014038085937500, +0.0109558105468750, -0.0023803710937500, 0.0107727050781250, -0.0040893554687500, +0.0122070312500000, -0.0020446777343750, 0.0104675292968750, -0.0006408691406250, +0.0082092285156250, -0.0023193359375000, 0.0095214843750000, 0.0031127929687500, +0.0077209472656250, 0.0024719238281250, 0.0074157714843750, 0.0028686523437500, +0.0072021484375000, 0.0063476562500000, 0.0065002441406250, 0.0051269531250000, +0.0067749023437500, 0.0069274902343750, 0.0046691894531250, 0.0069885253906250, +0.0055541992187500, 0.0066833496093750, 0.0032653808593750, 0.0078430175781250, +0.0002746582031250, 0.0074768066406250, 0.0023193359375000, 0.0052795410156250, +-0.0027160644531250, 0.0068969726562500, -0.0035705566406250, 0.0042419433593750, +-0.0018615722656250, 0.0007629394531250, -0.0030822753906250, 0.0036010742187500, +-0.0039672851562500, -0.0025634765625000, 0.0000000000000000, -0.0023193359375000, +-0.0002136230468750, -0.0025329589843750, -0.0000915527343750, -0.0060424804687500, +0.0019531250000000, -0.0045471191406250, 0.0013122558593750, -0.0053710937500000, +0.0021972656250000, -0.0057983398437500, 0.0023803710937500, -0.0057373046875000, +0.0028991699218750, -0.0058898925781250, 0.0031738281250000, -0.0056457519531250, +0.0027770996093750, -0.0059814453125000, 0.0059814453125000, -0.0062561035156250, +0.0049133300781250, -0.0055541992187500, 0.0069580078125000, -0.0055847167968750, +0.0106811523437500, -0.0061950683593750, 0.0085144042968750, -0.0028381347656250, +0.0115966796875000, -0.0033874511718750, 0.0122375488281250, -0.0034484863281250, +0.0106811523437500, -0.0014038085937500, 0.0108642578125000, -0.0018615722656250, +0.0109252929687500, -0.0013732910156250, 0.0071716308593750, -0.0010070800781250, +0.0072631835937500, -0.0027160644531250, 0.0049438476562500, -0.0032348632812500, +0.0013122558593750, -0.0017089843750000, 0.0023803710937500, -0.0066528320312500, +-0.0018920898437500, -0.0061035156250000, -0.0021057128906250, -0.0067749023437500, +-0.0026855468750000, -0.0097045898437500, -0.0050354003906250, -0.0080871582031250, +-0.0042419433593750, -0.0105590820312500, -0.0052490234375000, -0.0110168457031250, +-0.0057067871093750, -0.0095825195312500, -0.0052795410156250, -0.0100402832031250, +-0.0051574707031250, -0.0107116699218750, -0.0050659179687500, -0.0068359375000000, +-0.0046081542968750, -0.0079040527343750, -0.0043334960937500, -0.0066833496093750, +-0.0042419433593750, -0.0034179687500000, -0.0040893554687500, -0.0052795410156250, +-0.0038757324218750, -0.0025939941406250, -0.0040893554687500, -0.0023803710937500, +-0.0039978027343750, -0.0026245117187500, -0.0039978027343750, -0.0015563964843750, +-0.0040588378906250, -0.0019836425781250, -0.0037841796875000, -0.0013427734375000, +-0.0041198730468750, -0.0013732910156250, -0.0037841796875000, -0.0013122558593750, +-0.0038146972656250, -0.0007629394531250, -0.0039978027343750, -0.0009460449218750, +-0.0034179687500000, -0.0014038085937500, -0.0042724609375000, -0.0009155273437500, +-0.0036621093750000, -0.0018310546875000, -0.0033874511718750, -0.0028686523437500, +-0.0039978027343750, -0.0021057128906250, -0.0035400390625000, -0.0041809082031250, +-0.0035095214843750, -0.0041198730468750, -0.0030822753906250, -0.0042724609375000, +-0.0032958984375000, -0.0054931640625000, -0.0034790039062500, -0.0051269531250000, +-0.0027160644531250, -0.0058593750000000, -0.0039978027343750, -0.0059814453125000, +-0.0036315917968750}, +{0.0076293945312500, 0.0027160644531250, 0.0075073242187500, 0.0010681152343750, +0.0072937011718750, -0.0042419433593750, 0.0060729980468750, -0.0016784667968750, +0.0066223144531250, -0.0043640136718750, 0.0036926269531250, -0.0063476562500000, +0.0043945312500000, -0.0032653808593750, 0.0033569335937500, -0.0018615722656250, +0.0006103515625000, -0.0042114257812500, 0.0017089843750000, 0.0021667480468750, +-0.0006408691406250, 0.0016479492187500, -0.0010986328125000, 0.0020446777343750, +-0.0006103515625000, 0.0057983398437500, -0.0015869140625000, 0.0041503906250000, +-0.0018005371093750, 0.0051879882812500, 0.0006103515625000, 0.0057373046875000, +-0.0001831054687500, 0.0050659179687500, -0.0000305175781250, 0.0052490234375000, +0.0019836425781250, 0.0054321289062500, 0.0015563964843750, 0.0027160644531250, +0.0016174316406250, 0.0039672851562500, 0.0011901855468750, 0.0024414062500000, +0.0024414062500000, -0.0004882812500000, 0.0032653808593750, 0.0014038085937500, +0.0022888183593750, -0.0026855468750000, 0.0065917968750000, -0.0023193359375000, +0.0061035156250000, -0.0025634765625000, 0.0071105957031250, -0.0048522949218750, +0.0105590820312500, -0.0037536621093750, 0.0091552734375000, -0.0052490234375000, +0.0094909667968750, -0.0053100585937500, 0.0109252929687500, -0.0050964355468750, +0.0082702636718750, -0.0057983398437500, 0.0057983398437500, -0.0055847167968750, +0.0071716308593750, -0.0046691894531250, 0.0014953613281250, -0.0058288574218750, +0.0011596679687500, -0.0041809082031250, 0.0003662109375000, -0.0018005371093750, +-0.0029907226562500, -0.0034790039062500, -0.0021972656250000, -0.0011291503906250, +-0.0035095214843750, -0.0006713867187500, -0.0038452148437500, -0.0009460449218750, +-0.0037536621093750, 0.0002136230468750, -0.0039367675781250, -0.0002441406250000, +-0.0034790039062500, -0.0029907226562500, -0.0036621093750000, -0.0013427734375000, +-0.0032348632812500, -0.0029907226562500, -0.0030822753906250, -0.0067443847656250, +-0.0032653808593750, -0.0050659179687500, -0.0028686523437500, -0.0075988769531250, +-0.0030517578125000, -0.0076904296875000, -0.0029907226562500, -0.0080871582031250, +-0.0025634765625000, -0.0095214843750000, -0.0023193359375000, -0.0084533691406250, +-0.0021362304687500, -0.0092163085937500, -0.0015869140625000, -0.0098266601562500, +-0.0014343261718750, -0.0085449218750000, -0.0006408691406250, -0.0079956054687500, +0.0002441406250000, -0.0086975097656250, 0.0003051757812500, -0.0054016113281250, +0.0021667480468750, -0.0061645507812500, 0.0020446777343750, -0.0051879882812500, +0.0033569335937500, -0.0025634765625000, 0.0052795410156250, -0.0039672851562500, +0.0045471191406250, -0.0021362304687500, 0.0068054199218750, -0.0018920898437500, +0.0070800781250000, -0.0020141601562500, 0.0076904296875000, -0.0014343261718750, +0.0091857910156250, -0.0017395019531250, 0.0089111328125000, -0.0011596679687500, +0.0097351074218750, -0.0012207031250000, 0.0099792480468750, -0.0014343261718750, +0.0103454589843750, -0.0010986328125000, 0.0108947753906250, -0.0010986328125000, +0.0108032226562500, -0.0022583007812500, 0.0113830566406250, -0.0018005371093750, +0.0115966796875000, -0.0023498535156250, 0.0114135742187500, -0.0035705566406250, +0.0114440917968750, -0.0029602050781250, 0.0115661621093750, -0.0038452148437500, +0.0112609863281250, -0.0039367675781250, 0.0113525390625000, -0.0041503906250000, +0.0110778808593750, -0.0045776367187500, 0.0107421875000000, -0.0042114257812500, +0.0111389160156250, -0.0050048828125000, 0.0100097656250000, -0.0050964355468750, +0.0105590820312500, -0.0045166015625000, 0.0099792480468750, -0.0047302246093750, +0.0088195800781250, -0.0048828125000000, 0.0095520019531250, -0.0032043457031250, +0.0075378417968750, -0.0034790039062500, 0.0081481933593750, -0.0030212402343750, +0.0071411132812500, -0.0016479492187500, 0.0054626464843750, -0.0021667480468750, +0.0067138671875000, -0.0008850097656250, 0.0030212402343750, -0.0010070800781250, +0.0037536621093750, -0.0007324218750000, 0.0031433105468750, 0.0002441406250000, +0.0004882812500000, -0.0003051757812500, 0.0019531250000000, -0.0005187988281250, +-0.0005493164062500, 0.0000305175781250, -0.0009155273437500, -0.0014953613281250, +-0.0003356933593750, -0.0028381347656250, -0.0011291503906250, -0.0019226074218750, +-0.0011901855468750, -0.0054321289062500, -0.0003051757812500, -0.0053405761718750, +-0.0007324218750000, -0.0058898925781250, -0.0002441406250000, -0.0081481933593750, +0.0007019042968750, -0.0072937011718750, 0.0001525878906250, -0.0083618164062500, +0.0013427734375000, -0.0087890625000000, 0.0016479492187500, -0.0080566406250000, +0.0010681152343750, -0.0080566406250000, 0.0014648437500000, -0.0082397460937500, +0.0017700195312500, -0.0058288574218750, -0.0008239746093750, -0.0064697265625000, +0.0003356933593750, -0.0051574707031250, -0.0011901855468750, -0.0025024414062500, +-0.0039672851562500, -0.0037536621093750, -0.0021362304687500, -0.0016784667968750, +-0.0060119628906250, -0.0011291503906250, -0.0062866210937500, -0.0015258789062500, +-0.0056457519531250, -0.0010986328125000, -0.0076293945312500, -0.0009460449218750, +-0.0075073242187500, -0.0009765625000000, -0.0040893554687500, -0.0010375976562500, +-0.0058898925781250, -0.0010986328125000, -0.0028686523437500, -0.0008239746093750, +0.0018005371093750, -0.0006408691406250, -0.0011596679687500, -0.0014648437500000, +0.0045166015625000, -0.0012207031250000, 0.0053405761718750, -0.0012512207031250, +0.0046997070312500, -0.0018615722656250, 0.0071716308593750, -0.0016479492187500, +0.0068969726562500, -0.0025939941406250, 0.0037231445312500, -0.0027465820312500, +0.0057983398437500, -0.0018005371093750, 0.0024108886718750, -0.0021362304687500, +-0.0020446777343750, -0.0029296875000000, 0.0014953613281250, 0.0008850097656250, +-0.0073242187500000, 0.0002136230468750, -0.0075378417968750, 0.0014953613281250, +-0.0069885253906250, 0.0043640136718750, -0.0121154785156250, 0.0025634765625000, +-0.0114135742187500, 0.0062255859375000, -0.0062866210937500, 0.0066833496093750, +-0.0089111328125000, 0.0059204101562500, -0.0061035156250000, 0.0070190429687500, +0.0000305175781250, 0.0068664550781250, -0.0025939941406250, 0.0049743652343750, +0.0033874511718750, 0.0062255859375000, 0.0032348632812500, 0.0043945312500000, +0.0037231445312500, 0.0016174316406250, 0.0075378417968750, 0.0034484863281250, +0.0062561035156250, -0.0004577636718750, 0.0063476562500000, -0.0002136230468750, +0.0071411132812500, -0.0001220703125000, 0.0071411132812500, -0.0025329589843750, +0.0065917968750000, -0.0018920898437500, 0.0065612792968750, -0.0007934570312500, +0.0074462890625000, -0.0018920898437500, 0.0078125000000000, -0.0003662109375000, +0.0062561035156250, 0.0015563964843750, 0.0055541992187500, 0.0004577636718750, +0.0068054199218750, 0.0050964355468750, 0.0033264160156250, 0.0038757324218750, +0.0023803710937500, 0.0059509277343750, 0.0048217773437500, 0.0138244628906250, +0.0065307617187500, 0.0168457031250000, 0.0081176757812500, 0.0107421875000000, +0.0063781738281250, 0.0129699707031250, 0.0052185058593750, 0.0118103027343750, +0.0073547363281250, 0.0079956054687500, 0.0087280273437500, 0.0090942382812500, +0.0071105957031250, 0.0116577148437500, 0.0110778808593750, 0.0100402832031250, +0.0118713378906250, 0.0109863281250000, 0.0097961425781250, 0.0143432617187500, +0.0103454589843750, 0.0130004882812500, 0.0115661621093750, 0.0116577148437500, +0.0062255859375000, 0.0134582519531250, 0.0069885253906250, 0.0109252929687500, +0.0061035156250000, 0.0075988769531250, 0.0025024414062500, 0.0096740722656250, +0.0040588378906250, 0.0043945312500000, 0.0017700195312500, 0.0041503906250000, +0.0021972656250000, 0.0045776367187500, 0.0007934570312500, 0.0025634765625000, +-0.0014038085937500, 0.0025634765625000, 0.0003356933593750, 0.0001220703125000, +-0.0034179687500000, 0.0021362304687500, -0.0042114257812500, -0.0011291503906250, +-0.0021667480468750, -0.0060729980468750, -0.0026245117187500, -0.0030212402343750, +-0.0038757324218750, -0.0078430175781250, 0.0018005371093750, -0.0087890625000000, +0.0019226074218750, -0.0079345703125000, 0.0015563964843750, -0.0092468261718750, +0.0042114257812500, -0.0087890625000000, 0.0037536621093750, -0.0071105957031250, +0.0022888183593750, -0.0080566406250000, 0.0029296875000000, -0.0067138671875000, +0.0022277832031250, -0.0042114257812500, 0.0002136230468750, -0.0057678222656250, +0.0009765625000000, -0.0050048828125000, 0.0021057128906250, -0.0034484863281250, +0.0010986328125000, -0.0052795410156250, 0.0018005371093750, -0.0068359375000000, +0.0038146972656250, -0.0052185058593750, 0.0031433105468750, -0.0088195800781250, +0.0031127929687500, -0.0089721679687500, 0.0036315917968750, -0.0078430175781250, +0.0031127929687500, -0.0094299316406250, 0.0025329589843750, -0.0093078613281250, +0.0028686523437500, -0.0042114257812500, 0.0016174316406250, -0.0062255859375000, +0.0020446777343750, -0.0036315917968750, 0.0010986328125000, 0.0019531250000000, +-0.0000610351562500, -0.0010986328125000, 0.0007934570312500, 0.0032348632812500, +-0.0026855468750000, 0.0040588378906250, -0.0020446777343750, 0.0032653808593750, +-0.0029602050781250, 0.0045776367187500, -0.0058593750000000, 0.0042724609375000, +-0.0046997070312500, 0.0028076171875000, -0.0062866210937500, 0.0030822753906250, +-0.0065002441406250, 0.0019836425781250, -0.0067749023437500, 0.0003967285156250, +-0.0075683593750000, 0.0012207031250000, -0.0069885253906250, -0.0010375976562500, +-0.0079650878906250, -0.0018005371093750, -0.0083923339843750, -0.0004882812500000, +-0.0075683593750000, -0.0008239746093750, -0.0073852539062500, -0.0018005371093750, +-0.0080566406250000, 0.0023803710937500, -0.0060424804687500, 0.0010375976562500, +-0.0062866210937500, 0.0025939941406250, -0.0060729980468750, 0.0061340332031250, +-0.0048522949218750, 0.0037536621093750, -0.0052795410156250, 0.0081176757812500, +-0.0042114257812500, 0.0079650878906250, -0.0043640136718750, 0.0081481933593750, +-0.0040893554687500, 0.0106201171875000, -0.0030517578125000, 0.0094604492187500, +-0.0034790039062500, 0.0106506347656250, -0.0033874511718750, 0.0109252929687500, +-0.0028381347656250, 0.0104370117187500, -0.0036010742187500, 0.0105590820312500, +-0.0043640136718750, 0.0107116699218750, -0.0037536621093750, 0.0098266601562500, +-0.0052490234375000, 0.0103149414062500, -0.0053100585937500, 0.0096130371093750, +-0.0053710937500000, 0.0086364746093750, -0.0061950683593750, 0.0095214843750000, +-0.0059204101562500, 0.0075378417968750, -0.0061950683593750, 0.0077514648437500, +-0.0063781738281250, 0.0073242187500000, -0.0062255859375000, 0.0061645507812500, +-0.0061950683593750, 0.0072326660156250, -0.0063781738281250, 0.0056457519531250, +-0.0059814453125000, 0.0061340332031250, -0.0059509277343750, 0.0059814453125000, +-0.0059204101562500, 0.0050964355468750, -0.0056457519531250, 0.0061645507812500, +-0.0057067871093750, 0.0048217773437500, -0.0057373046875000, 0.0054321289062500, +-0.0057678222656250, 0.0054321289062500, -0.0054321289062500, 0.0045471191406250, +-0.0053710937500000, 0.0055541992187500, -0.0056457519531250, 0.0048522949218750, +-0.0039062500000000, 0.0052795410156250, -0.0043945312500000, 0.0052490234375000, +-0.0037536621093750, 0.0049133300781250, -0.0021362304687500, 0.0057983398437500, +-0.0030517578125000, 0.0051269531250000, -0.0019531250000000, 0.0053710937500000, +-0.0014343261718750, 0.0052795410156250, -0.0024414062500000, 0.0048828125000000, +-0.0025024414062500}, +{-0.0030822753906250, -0.0031738281250000, -0.0031127929687500, -0.0025939941406250, +-0.0036621093750000, -0.0065002441406250, 0.0000000000000000, -0.0055236816406250, +-0.0006713867187500, -0.0071716308593750, 0.0003051757812500, -0.0111694335937500, +0.0034790039062500, -0.0091552734375000, 0.0021667480468750, -0.0101013183593750, +0.0023803710937500, -0.0120544433593750, 0.0029907226562500, -0.0090026855468750, +0.0030212402343750, -0.0068969726562500, 0.0025634765625000, -0.0092773437500000, +0.0024108886718750, -0.0017700195312500, 0.0037536621093750, -0.0027160644531250, +0.0036010742187500, -0.0014343261718750, 0.0036315917968750, 0.0040588378906250, +0.0046691894531250, 0.0016174316406250, 0.0044860839843750, 0.0030517578125000, +0.0037231445312500, 0.0046386718750000, 0.0043334960937500, 0.0030212402343750, +0.0034790039062500, 0.0014953613281250, 0.0022277832031250, 0.0026245117187500, +0.0030517578125000, 0.0014648437500000, 0.0009765625000000, 0.0005798339843750, +0.0014038085937500, 0.0019226074218750, 0.0001525878906250, 0.0024719238281250, +-0.0016479492187500, 0.0013427734375000, -0.0003662109375000, 0.0043334960937500, +-0.0041809082031250, 0.0038146972656250, -0.0041198730468750, 0.0045776367187500, +-0.0041809082031250, 0.0066223144531250, -0.0062561035156250, 0.0052490234375000, +-0.0056152343750000, 0.0080871582031250, -0.0060729980468750, 0.0079650878906250, +-0.0060729980468750, 0.0077209472656250, -0.0061340332031250, 0.0093994140625000, +-0.0065307617187500, 0.0090942382812500, -0.0062561035156250, 0.0079040527343750, +-0.0059814453125000, 0.0088195800781250, -0.0064392089843750, 0.0075683593750000, +-0.0057373046875000, 0.0059509277343750, -0.0047607421875000, 0.0073852539062500, +-0.0053710937500000, 0.0039367675781250, -0.0043945312500000, 0.0046386718750000, +-0.0040283203125000, 0.0036621093750000, -0.0043334960937500, 0.0011901855468750, +-0.0042419433593750, 0.0029907226562500, -0.0042114257812500, -0.0000610351562500, +-0.0043334960937500, 0.0002136230468750, -0.0044555664062500, -0.0002136230468750, +-0.0043945312500000, -0.0021667480468750, -0.0043334960937500, -0.0012207031250000, +-0.0043334960937500, -0.0030212402343750, -0.0045471191406250, -0.0029907226562500, +-0.0045471191406250, -0.0029296875000000, -0.0046081542968750, -0.0037841796875000, +-0.0048217773437500, -0.0034179687500000, -0.0048828125000000, -0.0036621093750000, +-0.0047302246093750, -0.0040893554687500, -0.0046997070312500, -0.0038757324218750, +-0.0048217773437500, -0.0035400390625000, -0.0048217773437500, -0.0038146972656250, +-0.0046997070312500, -0.0036010742187500, -0.0050354003906250, -0.0036315917968750, +-0.0050659179687500, -0.0036621093750000, -0.0050964355468750, -0.0035705566406250, +-0.0053710937500000, -0.0035400390625000, -0.0053100585937500, -0.0036926269531250, +-0.0051269531250000, -0.0037231445312500, -0.0054321289062500, -0.0037536621093750, +-0.0050354003906250, -0.0037841796875000, -0.0046386718750000, -0.0036621093750000, +-0.0050354003906250, -0.0038146972656250, -0.0040283203125000, -0.0039367675781250, +-0.0040893554687500, -0.0039367675781250, -0.0041809082031250, -0.0039367675781250, +-0.0034179687500000, -0.0039062500000000, -0.0035705566406250, -0.0040588378906250, +-0.0045776367187500, -0.0039978027343750, -0.0037231445312500, -0.0039672851562500, +-0.0048522949218750, -0.0041198730468750, -0.0066223144531250, -0.0039978027343750, +-0.0054016113281250, -0.0035705566406250, -0.0071105957031250, -0.0036010742187500, +-0.0078735351562500, -0.0029296875000000, -0.0068664550781250, -0.0022277832031250, +-0.0068664550781250, -0.0024719238281250, -0.0076904296875000, -0.0006103515625000, +-0.0047912597656250, -0.0006713867187500, -0.0056457519531250, 0.0000610351562500, +-0.0046386718750000, 0.0016784667968750, -0.0019836425781250, 0.0013122558593750, +-0.0035095214843750, 0.0021667480468750, -0.0019226074218750, 0.0028076171875000, +-0.0010681152343750, 0.0025939941406250, -0.0023193359375000, 0.0025939941406250, +-0.0027160644531250, 0.0030822753906250, -0.0020141601562500, 0.0025024414062500, +-0.0039367675781250, 0.0028381347656250, -0.0039978027343750, 0.0021362304687500, +-0.0039367675781250, 0.0012512207031250, -0.0048217773437500, 0.0019531250000000, +-0.0044250488281250, 0.0003356933593750, -0.0047302246093750, 0.0003967285156250, +-0.0050659179687500, 0.0002746582031250, -0.0042114257812500, -0.0006408691406250, +-0.0036010742187500, -0.0003356933593750, -0.0043334960937500, -0.0008850097656250, +-0.0031127929687500, -0.0009460449218750, -0.0032348632812500, -0.0012512207031250, +-0.0022888183593750, -0.0016784667968750, -0.0013732910156250, -0.0014648437500000, +-0.0024414062500000, -0.0023803710937500, 0.0007019042968750, -0.0022277832031250, +0.0001831054687500, -0.0025024414062500, 0.0011596679687500, -0.0033569335937500, +0.0036926269531250, -0.0031433105468750, 0.0022277832031250, -0.0037536621093750, +0.0035095214843750, -0.0039367675781250, 0.0043334960937500, -0.0041809082031250, +0.0035095214843750, -0.0045776367187500, 0.0030212402343750, -0.0044860839843750, +0.0035400390625000, -0.0047912597656250, 0.0030822753906250, -0.0051574707031250, +0.0023193359375000, -0.0043640136718750, 0.0033569335937500, -0.0039672851562500, +0.0044250488281250, -0.0047912597656250, 0.0035705566406250, -0.0024108886718750, +0.0046081542968750, -0.0024108886718750, 0.0052490234375000, -0.0021972656250000, +0.0035705566406250, -0.0008544921875000, 0.0030517578125000, -0.0011901855468750, +0.0043945312500000, -0.0004882812500000, -0.0003356933593750, -0.0003356933593750, +-0.0001220703125000, 0.0000000000000000, 0.0002136230468750, 0.0004882812500000, +-0.0023498535156250, 0.0004577636718750, -0.0016174316406250, 0.0012817382812500, +0.0008544921875000, 0.0012207031250000, -0.0007324218750000, 0.0014953613281250, +0.0014038085937500, 0.0024719238281250, 0.0046081542968750, 0.0023498535156250, +0.0022277832031250, 0.0016784667968750, 0.0076599121093750, 0.0024414062500000, +0.0078430175781250, 0.0013427734375000, 0.0075073242187500, -0.0002746582031250, +0.0098876953125000, 0.0009460449218750, 0.0092163085937500, 0.0003662109375000, +0.0086669921875000, -0.0008850097656250, 0.0093994140625000, 0.0008544921875000, +0.0085449218750000, 0.0029296875000000, 0.0067749023437500, 0.0028076171875000, +0.0068664550781250, 0.0059204101562500, 0.0061950683593750, 0.0052185058593750, +0.0063781738281250, 0.0051574707031250, 0.0059204101562500, 0.0068359375000000, +0.0054626464843750, 0.0061645507812500, 0.0060119628906250, 0.0079040527343750, +0.0029907226562500, 0.0074462890625000, 0.0036010742187500, 0.0075683593750000, +0.0029296875000000, 0.0091857910156250, 0.0006408691406250, 0.0086364746093750, +0.0015258789062500, 0.0075378417968750, -0.0002441406250000, 0.0081481933593750, +-0.0006103515625000, 0.0078125000000000, 0.0000915527343750, 0.0066833496093750, +-0.0001525878906250, 0.0070800781250000, -0.0004882812500000, 0.0061645507812500, +0.0006408691406250, 0.0067443847656250, 0.0005493164062500, 0.0051269531250000, +0.0005798339843750, 0.0040588378906250, 0.0009460449218750, 0.0056457519531250, +0.0007934570312500, -0.0014038085937500, 0.0021057128906250, 0.0003051757812500, +0.0011596679687500, -0.0011901855468750, 0.0027160644531250, -0.0072326660156250, +0.0050964355468750, -0.0043945312500000, 0.0035400390625000, -0.0046997070312500, +0.0062561035156250, -0.0070800781250000, 0.0069274902343750, -0.0042419433593750, +0.0057373046875000, -0.0013122558593750, 0.0065917968750000, -0.0038757324218750, +0.0068359375000000, 0.0006103515625000, 0.0011901855468750, 0.0004272460937500, +0.0029296875000000, 0.0000610351562500, 0.0005798339843750, 0.0022277832031250, +-0.0050354003906250, 0.0015258789062500, -0.0025024414062500, 0.0017089843750000, +-0.0063171386718750, 0.0014038085937500, -0.0077819824218750, 0.0020751953125000, +-0.0060119628906250, 0.0028991699218750, -0.0061035156250000, 0.0021972656250000, +-0.0070800781250000, 0.0033874511718750, -0.0036926269531250, 0.0037536621093750, +-0.0034484863281250, 0.0029602050781250, -0.0033569335937500, 0.0032043457031250, +-0.0015258789062500, 0.0039367675781250, -0.0014343261718750, 0.0009765625000000, +-0.0018005371093750, 0.0018310546875000, -0.0014038085937500, 0.0009460449218750, +-0.0011291503906250, -0.0014038085937500, -0.0014648437500000, 0.0003356933593750, +-0.0013427734375000, -0.0016479492187500, 0.0000305175781250, -0.0022888183593750, +-0.0001831054687500, -0.0014038085937500, 0.0011596679687500, -0.0013732910156250, +0.0028381347656250, -0.0016784667968750, 0.0018920898437500, -0.0010681152343750, +0.0042114257812500, -0.0011596679687500, 0.0043029785156250, -0.0008850097656250, +0.0042724609375000, 0.0000000000000000, 0.0054626464843750, -0.0004272460937500, +0.0052185058593750, -0.0023803710937500, 0.0049133300781250, -0.0009155273437500, +0.0054321289062500, -0.0024719238281250, 0.0046386718750000, -0.0054931640625000, +0.0037231445312500, -0.0037536621093750, 0.0042724609375000, -0.0061950683593750, +0.0022583007812500, -0.0065612792968750, 0.0023498535156250, -0.0061340332031250, +0.0017700195312500, -0.0070190429687500, 0.0002136230468750, -0.0068969726562500, +0.0008544921875000, -0.0060424804687500, 0.0001220703125000, -0.0063476562500000, +-0.0000305175781250, -0.0061035156250000, 0.0003356933593750, -0.0051574707031250, +0.0003662109375000, -0.0053710937500000, 0.0003051757812500, -0.0050048828125000, +0.0010375976562500, -0.0050048828125000, 0.0010986328125000, -0.0046386718750000, +0.0014038085937500, -0.0044250488281250, 0.0019531250000000, -0.0047912597656250, +0.0017395019531250, -0.0036926269531250, 0.0025329589843750, -0.0039062500000000, +0.0024108886718750, -0.0035095214843750, 0.0027465820312500, -0.0027465820312500, +0.0034484863281250, -0.0032348632812500, 0.0032043457031250, -0.0016479492187500, +0.0040893554687500, -0.0021667480468750, 0.0041198730468750, -0.0013732910156250, +0.0044250488281250, 0.0002441406250000, 0.0051269531250000, -0.0007934570312500, +0.0048522949218750, 0.0008239746093750, 0.0053405761718750, 0.0011596679687500, +0.0054321289062500, 0.0006713867187500, 0.0054931640625000, 0.0009765625000000, +0.0056762695312500, 0.0011596679687500, 0.0055847167968750, 0.0003356933593750, +0.0056152343750000, 0.0005493164062500, 0.0056762695312500, 0.0003967285156250, +0.0056762695312500, -0.0001831054687500, 0.0057983398437500, 0.0000915527343750, +0.0058593750000000, -0.0008544921875000, 0.0055847167968750, -0.0005187988281250, +0.0061340332031250, -0.0011291503906250, 0.0056457519531250, -0.0021362304687500, +0.0050659179687500, -0.0015563964843750, 0.0058898925781250, -0.0032958984375000, +0.0042419433593750, -0.0032043457031250, 0.0046081542968750, -0.0037536621093750, +0.0045776367187500, -0.0051269531250000, 0.0034790039062500, -0.0046081542968750, +0.0041809082031250, -0.0060119628906250, 0.0039672851562500, -0.0061340332031250, +0.0037536621093750, -0.0062561035156250, 0.0044250488281250, -0.0070800781250000, +0.0047912597656250, -0.0068969726562500, 0.0045166015625000, -0.0066223144531250, +0.0061035156250000, -0.0070800781250000, 0.0057678222656250, -0.0062255859375000, +0.0066528320312500, -0.0053100585937500, 0.0081176757812500, -0.0058593750000000, +0.0074157714843750, -0.0035705566406250, 0.0097351074218750, -0.0039367675781250, +0.0097961425781250, -0.0030822753906250, 0.0093078613281250, -0.0012817382812500, +0.0105285644531250, -0.0022277832031250, 0.0106506347656250, 0.0000305175781250, +0.0084838867187500}, +{-0.0002136230468750, 0.0040588378906250, 0.0012512207031250, 0.0051269531250000, +0.0011291503906250, 0.0038757324218750, 0.0017395019531250, 0.0029296875000000, +0.0032043457031250, 0.0038146972656250, 0.0027465820312500, 0.0008239746093750, +0.0028686523437500, 0.0015563964843750, 0.0033569335937500, 0.0011596679687500, +0.0025024414062500, -0.0011596679687500, 0.0016784667968750, -0.0002746582031250, +0.0019531250000000, -0.0010375976562500, 0.0003356933593750, -0.0010681152343750, +0.0003662109375000, -0.0008850097656250, -0.0000610351562500, -0.0013427734375000, +-0.0011291503906250, -0.0011901855468750, -0.0005493164062500, -0.0003662109375000, +-0.0013122558593750, -0.0002746582031250, -0.0013427734375000, -0.0011596679687500, +-0.0014343261718750, -0.0010986328125000, -0.0018310546875000, -0.0003662109375000, +-0.0014953613281250, -0.0034179687500000, -0.0017089843750000, -0.0028381347656250, +-0.0013732910156250, -0.0035095214843750, -0.0012817382812500, -0.0057678222656250, +-0.0013427734375000, -0.0045471191406250, -0.0008239746093750, -0.0063476562500000, +-0.0009765625000000, -0.0067443847656250, -0.0007324218750000, -0.0058898925781250, +-0.0009155273437500, -0.0061950683593750, -0.0012207031250000, -0.0065917968750000, +-0.0007324218750000, -0.0047607421875000, -0.0014038085937500, -0.0050964355468750, +-0.0015258789062500, -0.0047302246093750, -0.0015563964843750, -0.0034790039062500, +-0.0021972656250000, -0.0040283203125000, -0.0025329589843750, -0.0031127929687500, +-0.0019226074218750, -0.0031433105468750, -0.0024414062500000, -0.0028076171875000, +-0.0022277832031250, -0.0021667480468750, -0.0016479492187500, -0.0024719238281250, +-0.0022888183593750, -0.0014953613281250, -0.0014038085937500, -0.0016784667968750, +-0.0019836425781250, -0.0010986328125000, -0.0017089843750000, -0.0003356933593750, +-0.0008239746093750, -0.0008850097656250, -0.0016479492187500, 0.0008544921875000, +-0.0003662109375000, 0.0007019042968750, -0.0005798339843750, 0.0008239746093750, +-0.0002746582031250, 0.0020141601562500, 0.0005493164062500, 0.0015869140625000, +0.0000000000000000, 0.0011901855468750, 0.0014343261718750, 0.0017395019531250, +0.0009155273437500, 0.0010070800781250, 0.0016174316406250, 0.0000915527343750, +0.0029602050781250, 0.0006713867187500, 0.0019531250000000, -0.0013427734375000, +0.0042114257812500, -0.0009460449218750, 0.0039062500000000, -0.0019226074218750, +0.0045471191406250, -0.0037536621093750, 0.0061950683593750, -0.0027160644531250, +0.0051879882812500, -0.0053405761718750, 0.0072631835937500, -0.0053100585937500, +0.0072326660156250, -0.0056762695312500, 0.0074157714843750, -0.0073242187500000, +0.0086669921875000, -0.0066833496093750, 0.0082702636718750, -0.0074462890625000, +0.0084533691406250, -0.0079040527343750, 0.0090942382812500, -0.0072326660156250, +0.0087280273437500, -0.0069885253906250, 0.0083923339843750, -0.0072937011718750, +0.0089721679687500, -0.0054931640625000, 0.0079956054687500, -0.0057678222656250, +0.0083618164062500, -0.0049438476562500, 0.0077209472656250, -0.0035705566406250, +0.0066528320312500, -0.0042724609375000, 0.0074768066406250, -0.0017089843750000, +0.0057373046875000, -0.0020751953125000, 0.0055847167968750, -0.0015563964843750, +0.0061340332031250, 0.0002746582031250, 0.0055236816406250, -0.0005798339843750, +0.0053405761718750, 0.0007324218750000, 0.0067749023437500, 0.0006408691406250, +0.0065002441406250, 0.0012512207031250, 0.0070190429687500, 0.0021667480468750, +0.0084533691406250, 0.0015258789062500, 0.0079040527343750, 0.0039062500000000, +0.0077514648437500, 0.0036926269531250, 0.0088806152343750, 0.0040588378906250, +0.0072021484375000, 0.0058288574218750, 0.0052490234375000, 0.0052795410156250, +0.0066833496093750, 0.0054626464843750, 0.0037231445312500, 0.0061645507812500, +0.0031738281250000, 0.0051574707031250, 0.0034179687500000, 0.0040283203125000, +0.0024108886718750, 0.0048828125000000, 0.0024108886718750, 0.0041809082031250, +0.0027160644531250, 0.0034790039062500, 0.0025329589843750, 0.0040893554687500, +0.0027160644531250, 0.0050659179687500, 0.0030822753906250, 0.0045471191406250, +0.0027160644531250, 0.0029907226562500, 0.0024719238281250, 0.0042419433593750, +0.0034790039062500, 0.0026245117187500, 0.0011291503906250, 0.0001831054687500, +-0.0004882812500000, 0.0017089843750000, 0.0014648437500000, -0.0021972656250000, +-0.0057678222656250, -0.0026855468750000, -0.0052185058593750, -0.0009765625000000, +-0.0054931640625000, -0.0021667480468750, -0.0103454589843750, -0.0029907226562500, +-0.0089416503906250, 0.0019226074218750, -0.0066833496093750, 0.0010070800781250, +-0.0089416503906250, 0.0028076171875000, -0.0059509277343750, 0.0069274902343750, +-0.0013122558593750, 0.0048828125000000, -0.0039367675781250, 0.0082702636718750, +0.0008544921875000, 0.0086059570312500, 0.0009765625000000, 0.0087890625000000, +0.0005187988281250, 0.0105895996093750, 0.0033874511718750, 0.0098876953125000, +0.0025634765625000, 0.0110778808593750, -0.0025939941406250, 0.0116271972656250, +-0.0001220703125000, 0.0105895996093750, -0.0026245117187500, 0.0107727050781250, +-0.0092468261718750, 0.0117492675781250, -0.0064697265625000, 0.0075378417968750, +-0.0063476562500000, 0.0079650878906250, -0.0097351074218750, 0.0080261230468750, +-0.0048217773437500, 0.0050354003906250, 0.0003967285156250, 0.0058288574218750, +-0.0038146972656250, 0.0096130371093750, 0.0042724609375000, 0.0078125000000000, +0.0054321289062500, 0.0086975097656250, 0.0039672851562500, 0.0145874023437500, +0.0072326660156250, 0.0073547363281250, -0.0020141601562500, 0.0034179687500000, +0.0046081542968750, 0.0039367675781250, 0.0039978027343750, 0.0047607421875000, +0.0032958984375000, 0.0041809082031250, 0.0042419433593750, 0.0035095214843750, +0.0046997070312500, 0.0046997070312500, 0.0047302246093750, 0.0057983398437500, +0.0033264160156250, 0.0034179687500000, 0.0054626464843750, 0.0017700195312500, +0.0081787109375000, 0.0036315917968750, 0.0062866210937500, -0.0008239746093750, +0.0085754394531250, -0.0018310546875000, 0.0101318359375000, -0.0005798339843750, +0.0075378417968750, -0.0013122558593750, 0.0060729980468750, -0.0019226074218750, +0.0079650878906250, 0.0001525878906250, 0.0041198730468750, 0.0002441406250000, +0.0028991699218750, -0.0010681152343750, 0.0050048828125000, -0.0002441406250000, +0.0052490234375000, 0.0004577636718750, 0.0039978027343750, -0.0054016113281250, +0.0079040527343750, -0.0044250488281250, 0.0085144042968750, -0.0048828125000000, +0.0071716308593750, -0.0090637207031250, 0.0081176757812500, -0.0077209472656250, +0.0089111328125000, -0.0070495605468750, 0.0055541992187500, -0.0086059570312500, +0.0058288574218750, -0.0066223144531250, 0.0056152343750000, -0.0043945312500000, +0.0038757324218750, -0.0059814453125000, 0.0044860839843750, -0.0013732910156250, +0.0028991699218750, -0.0014343261718750, 0.0037841796875000, -0.0015869140625000, +0.0018920898437500, 0.0007934570312500, -0.0006103515625000, 0.0004272460937500, +0.0014953613281250, -0.0001220703125000, -0.0021057128906250, 0.0001831054687500, +-0.0032348632812500, -0.0002136230468750, -0.0012207031250000, -0.0010681152343750, +-0.0011596679687500, -0.0006408691406250, -0.0022583007812500, 0.0000610351562500, +0.0016784667968750, -0.0009765625000000, 0.0016784667968750, 0.0006408691406250, +0.0017395019531250, 0.0026550292968750, 0.0038757324218750, 0.0010070800781250, +0.0032958984375000, 0.0038452148437500, 0.0033874511718750, 0.0046691894531250, +0.0035705566406250, 0.0033569335937500, 0.0036315917968750, 0.0035095214843750, +0.0036010742187500, 0.0044250488281250, 0.0034179687500000, 0.0024108886718750, +0.0041503906250000, 0.0021667480468750, 0.0043640136718750, 0.0028381347656250, +0.0037231445312500, 0.0021057128906250, 0.0035705566406250, 0.0018920898437500, +0.0039978027343750, 0.0045776367187500, 0.0025939941406250, 0.0036315917968750, +0.0026245117187500, 0.0050048828125000, 0.0023498535156250, 0.0074768066406250, +0.0018005371093750, 0.0058898925781250, 0.0021057128906250, 0.0098876953125000, +0.0000000000000000, 0.0096435546875000, 0.0008239746093750, 0.0095520019531250, +-0.0004882812500000, 0.0119934082031250, -0.0029602050781250, 0.0111999511718750, +-0.0014953613281250, 0.0099182128906250, -0.0041503906250000, 0.0114135742187500, +-0.0043640136718750, 0.0090332031250000, -0.0044860839843750, 0.0065002441406250, +-0.0057373046875000, 0.0086669921875000, -0.0052185058593750, 0.0018615722656250, +-0.0064392089843750, 0.0032653808593750, -0.0065917968750000, 0.0008544921875000, +-0.0062866210937500, -0.0044555664062500, -0.0068969726562500, -0.0009155273437500, +-0.0069885253906250, -0.0081787109375000, -0.0053710937500000, -0.0074157714843750, +-0.0059204101562500, -0.0081176757812500, -0.0053405761718750, -0.0123901367187500, +-0.0037841796875000, -0.0099792480468750, -0.0044250488281250, -0.0134582519531250, +-0.0034484863281250, -0.0133056640625000, -0.0033874511718750, -0.0133972167968750, +-0.0031738281250000, -0.0152893066406250, -0.0025939941406250, -0.0143737792968750, +-0.0029602050781250, -0.0156860351562500, -0.0021057128906250, -0.0153808593750000, +-0.0020751953125000, -0.0155944824218750, -0.0022583007812500, -0.0165710449218750, +-0.0019836425781250, -0.0160522460937500, -0.0021057128906250, -0.0170288085937500, +-0.0021972656250000, -0.0170898437500000, -0.0023193359375000, -0.0170288085937500, +-0.0023193359375000, -0.0174560546875000, -0.0023498535156250, -0.0174255371093750, +-0.0025329589843750, -0.0172424316406250, -0.0026550292968750, -0.0176391601562500, +-0.0025329589843750, -0.0174255371093750, -0.0028686523437500, -0.0171203613281250, +-0.0032043457031250, -0.0175781250000000, -0.0029907226562500, -0.0169677734375000, +-0.0037231445312500, -0.0170898437500000, -0.0038452148437500, -0.0168762207031250, +-0.0038757324218750, -0.0164489746093750, -0.0043029785156250, -0.0166625976562500, +-0.0043945312500000, -0.0155639648437500, -0.0044860839843750, -0.0157775878906250, +-0.0044860839843750, -0.0150451660156250, -0.0048522949218750, -0.0138549804687500, +-0.0052795410156250, -0.0144348144531250, -0.0050354003906250, -0.0121154785156250, +-0.0048522949218750, -0.0123901367187500, -0.0055847167968750, -0.0113525390625000, +-0.0046081542968750, -0.0094604492187500, -0.0034484863281250, -0.0102539062500000, +-0.0043945312500000, -0.0072937011718750, -0.0028076171875000, -0.0075378417968750, +-0.0023803710937500, -0.0067138671875000, -0.0029602050781250, -0.0045471191406250, +-0.0025939941406250, -0.0053405761718750, -0.0023803710937500, -0.0034179687500000, +-0.0037231445312500, -0.0032043457031250, -0.0034179687500000, -0.0031433105468750, +-0.0036621093750000, -0.0019531250000000, -0.0047302246093750, -0.0020141601562500, +-0.0041809082031250, -0.0021972656250000, -0.0038452148437500, -0.0017395019531250, +-0.0046081542968750, -0.0021057128906250, -0.0030822753906250, -0.0027770996093750, +-0.0016174316406250, -0.0024414062500000, -0.0029602050781250, -0.0032348632812500, +0.0004577636718750, -0.0032958984375000, 0.0002136230468750, -0.0034179687500000, +0.0008544921875000, -0.0039367675781250, 0.0029602050781250, -0.0037841796875000, +0.0017700195312500, -0.0034484863281250, 0.0036315917968750, -0.0040893554687500, +0.0039978027343750, -0.0028076171875000, 0.0037536621093750, -0.0014038085937500, +0.0043029785156250, -0.0024108886718750, 0.0041198730468750, 0.0002136230468750, +0.0038757324218750, 0.0005187988281250, 0.0041198730468750, 0.0001525878906250, +0.0038452148437500}, +{0.0025329589843750, 0.0000915527343750, 0.0019531250000000, -0.0065002441406250, +0.0010375976562500, -0.0026550292968750, 0.0017700195312500, -0.0093383789062500, +-0.0010070800781250, -0.0094604492187500, -0.0005493164062500, -0.0089416503906250, +-0.0012512207031250, -0.0123291015625000, -0.0034790039062500, -0.0114440917968750, +-0.0025939941406250, -0.0109558105468750, -0.0038452148437500, -0.0120239257812500, +-0.0040588378906250, -0.0108642578125000, -0.0041809082031250, -0.0096130371093750, +-0.0047302246093750, -0.0111389160156250, -0.0044860839843750, -0.0081176757812500, +-0.0051879882812500, -0.0088195800781250, -0.0054016113281250, -0.0082702636718750, +-0.0049743652343750, -0.0062561035156250, -0.0050964355468750, -0.0076599121093750, +-0.0052795410156250, -0.0048828125000000, -0.0039062500000000, -0.0057373046875000, +-0.0041198730468750, -0.0051574707031250, -0.0038452148437500, -0.0031433105468750, +-0.0029296875000000, -0.0045776367187500, -0.0033264160156250, -0.0020446777343750, +-0.0027770996093750, -0.0022888183593750, -0.0028381347656250, -0.0020446777343750, +-0.0026855468750000, -0.0005798339843750, -0.0023193359375000, -0.0017395019531250, +-0.0026245117187500, -0.0003051757812500, -0.0020141601562500, -0.0005798339843750, +-0.0020141601562500, -0.0006713867187500, -0.0020446777343750, -0.0000610351562500, +-0.0018310546875000, -0.0007019042968750, -0.0019531250000000, -0.0000305175781250, +-0.0019836425781250, -0.0003967285156250, -0.0020141601562500, -0.0002441406250000, +-0.0021362304687500, 0.0001525878906250, -0.0021972656250000, -0.0007324218750000, +-0.0023193359375000, 0.0001525878906250, -0.0025329589843750, -0.0003051757812500, +-0.0025329589843750, -0.0003967285156250, -0.0029602050781250, 0.0000305175781250, +-0.0034179687500000, -0.0007934570312500, -0.0031738281250000, -0.0004882812500000, +-0.0038757324218750, -0.0005493164062500, -0.0042114257812500, -0.0013122558593750, +-0.0035095214843750, -0.0015563964843750, -0.0033874511718750, -0.0016174316406250, +-0.0039978027343750, -0.0033264160156250, -0.0020751953125000, -0.0031738281250000, +-0.0021667480468750, -0.0041809082031250, -0.0023803710937500, -0.0058288574218750, +-0.0013427734375000, -0.0053710937500000, -0.0015869140625000, -0.0077819824218750, +-0.0027160644531250, -0.0078735351562500, -0.0021057128906250, -0.0082397460937500, +-0.0028381347656250, -0.0099182128906250, -0.0043334960937500, -0.0098876953125000, +-0.0033569335937500, -0.0097351074218750, -0.0040588378906250, -0.0105590820312500, +-0.0047607421875000, -0.0097961425781250, -0.0035095214843750, -0.0089416503906250, +-0.0028076171875000, -0.0098571777343750, -0.0036315917968750, -0.0073547363281250, +-0.0001831054687500, -0.0076599121093750, -0.0007934570312500, -0.0069274902343750, +0.0000000000000000, -0.0049438476562500, 0.0025634765625000, -0.0058288574218750, +0.0013732910156250, -0.0040283203125000, 0.0028076171875000, -0.0039672851562500, +0.0030822753906250, -0.0038452148437500, 0.0027770996093750, -0.0028381347656250, +0.0031738281250000, -0.0031127929687500, 0.0032653808593750, -0.0033264160156250, +0.0030212402343750, -0.0031127929687500, 0.0029602050781250, -0.0032958984375000, +0.0030822753906250, -0.0038452148437500, 0.0032653808593750, -0.0036926269531250, +0.0030212402343750, -0.0028076171875000, 0.0026245117187500, -0.0033874511718750, +0.0030212402343750, -0.0024719238281250, 0.0025024414062500, -0.0009460449218750, +0.0016479492187500, -0.0016479492187500, 0.0022277832031250, -0.0000610351562500, +0.0013122558593750, 0.0001220703125000, 0.0013732910156250, 0.0000915527343750, +0.0010070800781250, 0.0010986328125000, 0.0001525878906250, 0.0010375976562500, +0.0008544921875000, -0.0005493164062500, 0.0014038085937500, 0.0002441406250000, +0.0003967285156250, -0.0007629394531250, 0.0018310546875000, -0.0030212402343750, +0.0035400390625000, -0.0018920898437500, 0.0023803710937500, -0.0021667480468750, +0.0059814453125000, -0.0029907226562500, 0.0055847167968750, -0.0018920898437500, +0.0061645507812500, -0.0005798339843750, 0.0086059570312500, -0.0014343261718750, +0.0075378417968750, -0.0004577636718750, 0.0088806152343750, 0.0002136230468750, +0.0093383789062500, -0.0009765625000000, 0.0086364746093750, -0.0014343261718750, +0.0087890625000000, -0.0008544921875000, 0.0090026855468750, -0.0048522949218750, +0.0064697265625000, -0.0043945312500000, 0.0074768066406250, -0.0046081542968750, +0.0066528320312500, -0.0075988769531250, 0.0041198730468750, -0.0069274902343750, +0.0053100585937500, -0.0054626464843750, 0.0032043457031250, -0.0066223144531250, +0.0033569335937500, -0.0053710937500000, 0.0030822753906250, -0.0030517578125000, +0.0018005371093750, -0.0041503906250000, 0.0022888183593750, -0.0022277832031250, +0.0005493164062500, -0.0021362304687500, 0.0010375976562500, -0.0023193359375000, +0.0003356933593750, -0.0015563964843750, -0.0018920898437500, -0.0018920898437500, +-0.0014038085937500, -0.0018005371093750, -0.0005798339843750, -0.0021362304687500, +-0.0014953613281250, -0.0019531250000000, -0.0010986328125000, -0.0014038085937500, +0.0002441406250000, -0.0016479492187500, -0.0001525878906250, -0.0013122558593750, +0.0005798339843750, -0.0016174316406250, 0.0002441406250000, -0.0006713867187500, +0.0009155273437500, 0.0000000000000000, 0.0020141601562500, -0.0009155273437500, +0.0012512207031250, 0.0018920898437500, 0.0022277832031250, 0.0013427734375000, +0.0030212402343750, 0.0021057128906250, 0.0011291503906250, 0.0043640136718750, +0.0000915527343750, 0.0030212402343750, 0.0014038085937500, 0.0042724609375000, +-0.0030212402343750, 0.0045166015625000, -0.0030517578125000, 0.0048522949218750, +-0.0029296875000000, 0.0052795410156250, -0.0052795410156250, 0.0047607421875000, +-0.0046997070312500, 0.0065002441406250, -0.0031738281250000, 0.0063171386718750, +-0.0041503906250000, 0.0063476562500000, -0.0032958984375000, 0.0073547363281250, +-0.0012817382812500, 0.0070190429687500, -0.0021362304687500, 0.0072937011718750, +-0.0013122558593750, 0.0072937011718750, -0.0010681152343750, 0.0072631835937500, +-0.0008850097656250, 0.0075683593750000, -0.0004882812500000, 0.0074768066406250, +-0.0007934570312500, 0.0070800781250000, 0.0009155273437500, 0.0079345703125000, +0.0008850097656250, 0.0065307617187500, 0.0012207031250000, 0.0054626464843750, +0.0024108886718750, 0.0069885253906250, 0.0022277832031250, 0.0015258789062500, +0.0028991699218750, 0.0027160644531250, 0.0032958984375000, 0.0018920898437500, +0.0027465820312500, -0.0021972656250000, 0.0028991699218750, -0.0004272460937500, +0.0034484863281250, -0.0025329589843750, 0.0004272460937500, -0.0032653808593750, +0.0012207031250000, -0.0018005371093750, 0.0002746582031250, -0.0019836425781250, +-0.0025024414062500, -0.0030517578125000, -0.0014038085937500, 0.0001525878906250, +-0.0028381347656250, -0.0007629394531250, -0.0032348632812500, 0.0003051757812500, +-0.0029296875000000, 0.0030517578125000, -0.0029602050781250, 0.0011596679687500, +-0.0028076171875000, 0.0036315917968750, -0.0036010742187500, 0.0039367675781250, +-0.0026550292968750, 0.0034484863281250, -0.0040893554687500, 0.0043945312500000, +-0.0057067871093750, 0.0041503906250000, -0.0041503906250000, 0.0028381347656250, +-0.0078125000000000, 0.0036621093750000, -0.0073242187500000, 0.0029602050781250, +-0.0078430175781250, 0.0014038085937500, -0.0101318359375000, 0.0021057128906250, +-0.0087890625000000, 0.0004577636718750, -0.0106506347656250, 0.0008239746093750, +-0.0104370117187500, 0.0005798339843750, -0.0101623535156250, -0.0006103515625000, +-0.0109558105468750, 0.0000305175781250, -0.0101928710937500, -0.0006408691406250, +-0.0099182128906250, -0.0003662109375000, -0.0099792480468750, -0.0010070800781250, +-0.0092163085937500, -0.0019531250000000, -0.0086059570312500, -0.0010070800781250, +-0.0087585449218750, -0.0023193359375000, -0.0074157714843750, -0.0025939941406250, +-0.0074768066406250, -0.0023193359375000, -0.0068664550781250, -0.0025329589843750, +-0.0057373046875000, -0.0024719238281250, -0.0061340332031250, -0.0028686523437500, +-0.0049743652343750, -0.0026855468750000, -0.0048828125000000, -0.0025024414062500, +-0.0049743652343750, -0.0028991699218750, -0.0042724609375000, -0.0028076171875000, +-0.0043945312500000, -0.0018310546875000, -0.0047302246093750, -0.0021667480468750, +-0.0044250488281250, -0.0017700195312500, -0.0046081542968750, -0.0007629394531250, +-0.0049743652343750, -0.0012512207031250, -0.0045166015625000, -0.0008239746093750, +-0.0050354003906250, -0.0006103515625000, -0.0048522949218750, -0.0009765625000000, +-0.0048522949218750, -0.0010681152343750, -0.0050354003906250, -0.0008239746093750, +-0.0043945312500000, -0.0020751953125000, -0.0046691894531250, -0.0017700195312500, +-0.0043640136718750, -0.0022277832031250, -0.0042419433593750, -0.0033874511718750, +-0.0043640136718750, -0.0028381347656250, -0.0038146972656250, -0.0035705566406250, +-0.0043945312500000, -0.0038452148437500, -0.0037231445312500, -0.0036621093750000, +-0.0035095214843750, -0.0037536621093750, -0.0038757324218750, -0.0038757324218750, +-0.0032653808593750, -0.0040588378906250, -0.0031738281250000, -0.0039978027343750, +-0.0032653808593750, -0.0039367675781250, -0.0028381347656250, -0.0040893554687500, +-0.0024414062500000, -0.0040893554687500, -0.0027465820312500, -0.0032043457031250, +-0.0024108886718750, -0.0033264160156250, -0.0021667480468750, -0.0030822753906250, +-0.0025329589843750, -0.0022277832031250, -0.0025634765625000, -0.0022888183593750, +-0.0022583007812500, -0.0021972656250000, -0.0037841796875000, -0.0021057128906250, +-0.0033874511718750, -0.0016784667968750, -0.0039672851562500, -0.0014953613281250, +-0.0052795410156250, -0.0017395019531250, -0.0046997070312500, -0.0006103515625000, +-0.0059204101562500, -0.0007324218750000, -0.0063171386718750, -0.0004577636718750, +-0.0058593750000000, 0.0001525878906250, -0.0063781738281250, -0.0000915527343750, +-0.0067138671875000, 0.0010986328125000, -0.0043945312500000, 0.0007324218750000, +-0.0058288574218750, 0.0016479492187500, -0.0035400390625000, 0.0030517578125000, +-0.0004882812500000, 0.0021057128906250, -0.0029296875000000, 0.0039062500000000, +0.0032348632812500, 0.0042419433593750, 0.0023498535156250, 0.0037231445312500, +0.0037231445312500, 0.0042114257812500, 0.0083618164062500, 0.0043029785156250, +0.0059814453125000, 0.0032043457031250, 0.0090026855468750, 0.0034179687500000, +0.0097961425781250, 0.0029296875000000, 0.0090026855468750, 0.0019226074218750, +0.0095520019531250, 0.0023803710937500, 0.0095825195312500, 0.0013427734375000, +0.0086669921875000, 0.0010681152343750, 0.0090637207031250, 0.0010375976562500, +0.0080871582031250, 0.0005187988281250, 0.0068664550781250, 0.0005187988281250, +0.0075378417968750, 0.0006408691406250, 0.0052795410156250, 0.0000610351562500, +0.0052490234375000, 0.0011596679687500, 0.0053405761718750, 0.0021667480468750, +0.0043029785156250, 0.0012207031250000, 0.0044860839843750, 0.0036926269531250, +0.0040588378906250, 0.0036621093750000, 0.0042114257812500, 0.0044250488281250, +0.0032653808593750, 0.0059814453125000, 0.0024108886718750, 0.0050354003906250, +0.0029296875000000, 0.0075378417968750, 0.0010070800781250, 0.0077209472656250, +0.0008239746093750, 0.0078125000000000, 0.0007629394531250, 0.0090026855468750, +-0.0001525878906250, 0.0085449218750000, 0.0000000000000000, 0.0085754394531250, +-0.0003356933593750, 0.0090942382812500, -0.0003662109375000, 0.0083923339843750, +-0.0004272460937500, 0.0075378417968750, -0.0006103515625000, 0.0079650878906250, +-0.0002746582031250}, +{-0.0030517578125000, -0.0020751953125000, -0.0026550292968750, -0.0030212402343750, +-0.0029296875000000, -0.0030822753906250, -0.0027160644531250, -0.0028686523437500, +-0.0022277832031250, -0.0031433105468750, -0.0022277832031250, -0.0032653808593750, +-0.0021972656250000, -0.0026855468750000, -0.0014038085937500, -0.0028076171875000, +-0.0014953613281250, -0.0028076171875000, -0.0012512207031250, -0.0024108886718750, +-0.0007019042968750, -0.0025024414062500, -0.0009460449218750, -0.0028991699218750, +-0.0007019042968750, -0.0026550292968750, -0.0007324218750000, -0.0030517578125000, +-0.0008544921875000, -0.0035705566406250, -0.0009155273437500, -0.0031433105468750, +-0.0009765625000000, -0.0043334960937500, -0.0007629394531250, -0.0043029785156250, +-0.0008850097656250, -0.0040283203125000, -0.0012512207031250, -0.0046386718750000, +-0.0013732910156250, -0.0046081542968750, -0.0014343261718750, -0.0033874511718750, +-0.0019531250000000, -0.0038757324218750, -0.0019531250000000, -0.0032348632812500, +-0.0021972656250000, -0.0018310546875000, -0.0025634765625000, -0.0023803710937500, +-0.0022888183593750, -0.0013732910156250, -0.0023803710937500, -0.0011291503906250, +-0.0025939941406250, -0.0010375976562500, -0.0023193359375000, -0.0005798339843750, +-0.0020751953125000, -0.0006713867187500, -0.0021972656250000, -0.0002441406250000, +-0.0012207031250000, -0.0003356933593750, -0.0014648437500000, 0.0000915527343750, +-0.0012512207031250, 0.0005187988281250, -0.0003356933593750, 0.0003356933593750, +-0.0006408691406250, 0.0015258789062500, -0.0003051757812500, 0.0013122558593750, +0.0003356933593750, 0.0018005371093750, -0.0004272460937500, 0.0029296875000000, +-0.0006713867187500, 0.0024414062500000, 0.0001525878906250, 0.0033874511718750, +-0.0027770996093750, 0.0038452148437500, -0.0017089843750000, 0.0031433105468750, +-0.0027465820312500, 0.0031433105468750, -0.0056152343750000, 0.0036315917968750, +-0.0040893554687500, 0.0015563964843750, -0.0064086914062500, 0.0018920898437500, +-0.0068969726562500, 0.0012817382812500, -0.0060424804687500, -0.0003967285156250, +-0.0069274902343750, 0.0003356933593750, -0.0071716308593750, -0.0011596679687500, +-0.0036621093750000, -0.0014648437500000, -0.0050354003906250, -0.0012512207031250, +-0.0031433105468750, -0.0019531250000000, 0.0007019042968750, -0.0020446777343750, +-0.0012207031250000, -0.0007324218750000, 0.0038757324218750, -0.0015563964843750, +0.0035400390625000, -0.0003356933593750, 0.0048522949218750, 0.0014953613281250, +0.0085449218750000, 0.0003662109375000, 0.0066528320312500, 0.0037841796875000, +0.0094299316406250, 0.0036621093750000, 0.0102539062500000, 0.0036621093750000, +0.0090637207031250, 0.0055236816406250, 0.0093383789062500, 0.0052490234375000, +0.0098876953125000, 0.0058593750000000, 0.0078125000000000, 0.0056152343750000, +0.0079040527343750, 0.0064086914062500, 0.0077819824218750, 0.0074462890625000, +0.0068359375000000, 0.0067749023437500, 0.0072326660156250, 0.0081176757812500, +0.0058593750000000, 0.0081176757812500, 0.0063476562500000, 0.0080566406250000, +0.0050354003906250, 0.0086669921875000, 0.0031127929687500, 0.0085144042968750, +0.0040283203125000, 0.0084838867187500, 0.0007934570312500, 0.0082397460937500, +0.0008850097656250, 0.0084838867187500, 0.0006408691406250, 0.0087280273437500, +-0.0013427734375000, 0.0083618164062500, -0.0006713867187500, 0.0096435546875000, +-0.0011596679687500, 0.0098876953125000, -0.0016784667968750, 0.0083618164062500, +-0.0004577636718750, 0.0081787109375000, 0.0001525878906250, 0.0093994140625000, +-0.0009460449218750, 0.0053405761718750, 0.0010070800781250, 0.0056762695312500, +0.0016174316406250, 0.0050354003906250, 0.0008544921875000, 0.0021667480468750, +0.0010681152343750, 0.0033569335937500, 0.0012207031250000, 0.0036926269531250, +-0.0009765625000000, 0.0025634765625000, -0.0003662109375000, 0.0035705566406250, +-0.0006713867187500, 0.0054931640625000, -0.0029296875000000, 0.0044555664062500, +-0.0023498535156250, 0.0035095214843750, -0.0004882812500000, 0.0050354003906250, +-0.0015869140625000, 0.0031738281250000, -0.0004577636718750, -0.0016784667968750, +0.0035095214843750, -0.0051574707031250, -0.0024414062500000, -0.0020141601562500, +-0.0002441406250000, -0.0032348632812500, -0.0026550292968750, -0.0028381347656250, +-0.0010681152343750, -0.0012817382812500, 0.0026245117187500, -0.0018005371093750, +0.0015563964843750, -0.0016784667968750, -0.0002441406250000, -0.0015869140625000, +0.0009460449218750, -0.0014038085937500, 0.0000000000000000, -0.0012207031250000, +-0.0027465820312500, -0.0012207031250000, -0.0018615722656250, -0.0004577636718750, +-0.0005493164062500, 0.0002441406250000, -0.0018920898437500, -0.0014648437500000, +-0.0004272460937500, -0.0022583007812500, 0.0022277832031250, -0.0006713867187500, +0.0008850097656250, -0.0053405761718750, 0.0022583007812500, -0.0054931640625000, +0.0026855468750000, -0.0052185058593750, 0.0028381347656250, -0.0080566406250000, +0.0029602050781250, -0.0073547363281250, 0.0025634765625000, -0.0027160644531250, +0.0050659179687500, -0.0056457519531250, 0.0044860839843750, -0.0023498535156250, +0.0048522949218750, 0.0042724609375000, 0.0070800781250000, 0.0007629394531250, +0.0063781738281250, 0.0054626464843750, 0.0058288574218750, 0.0067749023437500, +0.0065307617187500, 0.0056152343750000, 0.0057373046875000, 0.0064697265625000, +0.0044860839843750, 0.0067138671875000, 0.0051574707031250, 0.0053100585937500, +0.0042419433593750, 0.0052185058593750, 0.0037536621093750, 0.0059814453125000, +0.0045471191406250, 0.0054321289062500, 0.0050048828125000, 0.0048828125000000, +0.0045166015625000, 0.0081787109375000, 0.0052490234375000, 0.0075378417968750, +0.0057067871093750, 0.0077514648437500, 0.0051269531250000, 0.0103149414062500, +0.0047302246093750, 0.0092163085937500, 0.0050354003906250, 0.0072021484375000, +0.0044555664062500, 0.0094604492187500, 0.0044250488281250, 0.0058593750000000, +0.0043640136718750, 0.0018005371093750, 0.0043640136718750, 0.0053100585937500, +0.0043945312500000, -0.0041198730468750, 0.0032653808593750, -0.0035095214843750, +0.0037231445312500, -0.0034179687500000, 0.0027770996093750, -0.0091857910156250, +0.0010986328125000, -0.0076904296875000, 0.0020446777343750, -0.0063476562500000, +0.0009460449218750, -0.0086364746093750, 0.0003356933593750, -0.0061340332031250, +0.0010070800781250, -0.0029296875000000, 0.0012817382812500, -0.0055236816406250, +0.0009155273437500, 0.0001220703125000, 0.0018615722656250, -0.0005187988281250, +0.0017700195312500, 0.0001220703125000, 0.0021667480468750, 0.0038146972656250, +0.0029296875000000, 0.0018310546875000, 0.0024414062500000, 0.0034484863281250, +0.0037841796875000, 0.0043334960937500, 0.0039062500000000, 0.0027160644531250, +0.0036010742187500, 0.0022583007812500, 0.0040893554687500, 0.0030822753906250, +0.0042114257812500, -0.0000610351562500, 0.0031738281250000, 0.0003967285156250, +0.0033874511718750, -0.0002136230468750, 0.0032043457031250, -0.0025024414062500, +0.0023803710937500, -0.0013732910156250, 0.0027160644531250, -0.0028686523437500, +0.0018005371093750, -0.0033569335937500, 0.0021362304687500, -0.0030212402343750, +0.0013732910156250, -0.0035095214843750, 0.0002441406250000, -0.0038146972656250, +0.0010681152343750, -0.0027160644531250, -0.0008544921875000, -0.0035095214843750, +-0.0009460449218750, -0.0028686523437500, -0.0011291503906250, -0.0017089843750000, +-0.0021362304687500, -0.0029907226562500, -0.0017700195312500, -0.0007324218750000, +-0.0027160644531250, -0.0012817382812500, -0.0026245117187500, -0.0009460449218750, +-0.0028381347656250, 0.0007324218750000, -0.0036621093750000, -0.0003662109375000, +-0.0033569335937500, 0.0009765625000000, -0.0032653808593750, 0.0007324218750000, +-0.0036926269531250, 0.0007629394531250, -0.0030822753906250, 0.0014038085937500, +-0.0023193359375000, 0.0007324218750000, -0.0028991699218750, 0.0015258789062500, +-0.0018005371093750, 0.0012207031250000, -0.0016784667968750, 0.0014953613281250, +-0.0018615722656250, 0.0021667480468750, -0.0015258789062500, 0.0014953613281250, +-0.0015563964843750, 0.0028076171875000, -0.0019836425781250, 0.0026550292968750, +-0.0019836425781250, 0.0026855468750000, -0.0020446777343750, 0.0034790039062500, +-0.0025329589843750, 0.0031127929687500, -0.0024719238281250, 0.0032348632812500, +-0.0020446777343750, 0.0031738281250000, -0.0025024414062500, 0.0027770996093750, +-0.0018310546875000, 0.0025329589843750, -0.0009155273437500, 0.0024414062500000, +-0.0016784667968750, 0.0018615722656250, -0.0003967285156250, 0.0017700195312500, +-0.0001525878906250, 0.0014038085937500, -0.0005493164062500, 0.0008850097656250, +-0.0001831054687500, 0.0009155273437500, -0.0000305175781250, 0.0008850097656250, +-0.0013732910156250, 0.0005798339843750, -0.0010375976562500, 0.0009155273437500, +-0.0011901855468750, 0.0012817382812500, -0.0024719238281250, 0.0010070800781250, +-0.0020446777343750, 0.0021057128906250, -0.0008850097656250, 0.0019226074218750, +-0.0018615722656250, 0.0024414062500000, -0.0006713867187500, 0.0034790039062500, +0.0013122558593750, 0.0029907226562500, 0.0001220703125000, 0.0043029785156250, +0.0024719238281250, 0.0044860839843750, 0.0025329589843750, 0.0048522949218750, +0.0024414062500000, 0.0057067871093750, 0.0036926269531250, 0.0057067871093750, +0.0033874511718750, 0.0067138671875000, 0.0024108886718750, 0.0066833496093750, +0.0030517578125000, 0.0066223144531250, 0.0025634765625000, 0.0071716308593750, +0.0011901855468750, 0.0070800781250000, 0.0018920898437500, 0.0062866210937500, +0.0016174316406250, 0.0066833496093750, 0.0012817382812500, 0.0055236816406250, +0.0014953613281250, 0.0043029785156250, 0.0018615722656250, 0.0050354003906250, +0.0017700195312500, 0.0017700195312500, 0.0009460449218750, 0.0019836425781250, +0.0014038085937500, 0.0014038085937500, 0.0010986328125000, -0.0007629394531250, +0.0000000000000000, 0.0000915527343750, 0.0005187988281250, -0.0010070800781250, +0.0007019042968750, -0.0011901855468750, 0.0000305175781250, -0.0009765625000000, +0.0009460449218750, -0.0014648437500000, 0.0020751953125000, -0.0014038085937500, +0.0014343261718750, -0.0005187988281250, 0.0032653808593750, -0.0006103515625000, +0.0030212402343750, -0.0007934570312500, 0.0034790039062500, -0.0000915527343750, +0.0048828125000000, -0.0000610351562500, 0.0043029785156250, -0.0013427734375000, +0.0051574707031250, -0.0009765625000000, 0.0050964355468750, -0.0013427734375000, +0.0050964355468750, -0.0024719238281250, 0.0057983398437500, -0.0019226074218750, +0.0056762695312500, -0.0026550292968750, 0.0048217773437500, -0.0028381347656250, +0.0054321289062500, -0.0023193359375000, 0.0044555664062500, -0.0023498535156250, +0.0031433105468750, -0.0025939941406250, 0.0041503906250000, -0.0012207031250000, +0.0026855468750000, -0.0014648437500000, 0.0023803710937500, -0.0010986328125000, +0.0027160644531250, 0.0000915527343750, 0.0024719238281250, -0.0003051757812500, +0.0022888183593750, 0.0001525878906250, 0.0023193359375000, 0.0001220703125000, +0.0030517578125000, 0.0002746582031250, 0.0019836425781250, 0.0008544921875000, +0.0007324218750000, 0.0006103515625000, 0.0017395019531250, -0.0006103515625000, +0.0005493164062500, 0.0002441406250000, 0.0001525878906250, -0.0011901855468750, +0.0007019042968750, -0.0031433105468750, 0.0005798339843750, -0.0018310546875000, +0.0005187988281250, -0.0049133300781250, 0.0023498535156250, -0.0051269531250000, +0.0017395019531250}, +{-0.0022888183593750, -0.0016784667968750, -0.0024414062500000, -0.0013427734375000, +-0.0021362304687500, -0.0014953613281250, -0.0019531250000000, -0.0011291503906250, +-0.0022583007812500, -0.0007019042968750, -0.0011596679687500, -0.0006408691406250, +-0.0013122558593750, -0.0002746582031250, -0.0011901855468750, 0.0003051757812500, +-0.0003967285156250, 0.0005493164062500, -0.0006408691406250, 0.0007934570312500, +-0.0005187988281250, 0.0009155273437500, -0.0003051757812500, 0.0011901855468750, +-0.0005493164062500, 0.0014343261718750, -0.0008544921875000, 0.0014648437500000, +-0.0006408691406250, 0.0018005371093750, -0.0005187988281250, 0.0017089843750000, +-0.0011291503906250, 0.0019531250000000, 0.0000305175781250, 0.0024414062500000, +0.0010986328125000, 0.0023193359375000, 0.0000000000000000, 0.0028076171875000, +0.0024719238281250, 0.0029296875000000, 0.0025024414062500, 0.0028381347656250, +0.0025634765625000, 0.0030517578125000, 0.0038146972656250, 0.0031738281250000, +0.0033569335937500, 0.0025939941406250, 0.0034484863281250, 0.0027465820312500, +0.0041198730468750, 0.0024108886718750, 0.0029602050781250, 0.0018920898437500, +0.0019226074218750, 0.0023803710937500, 0.0030517578125000, 0.0018920898437500, +0.0009460449218750, 0.0016174316406250, 0.0006408691406250, 0.0023498535156250, +0.0011291503906250, 0.0025939941406250, 0.0006103515625000, 0.0022277832031250, +0.0005798339843750, 0.0047607421875000, 0.0011596679687500, 0.0043029785156250, +0.0011291503906250, 0.0055236816406250, 0.0010375976562500, 0.0078735351562500, +0.0011291503906250, 0.0065307617187500, 0.0012817382812500, 0.0090026855468750, +0.0015258789062500, 0.0096130371093750, 0.0012817382812500, 0.0085754394531250, +0.0017395019531250, 0.0089111328125000, 0.0021972656250000, 0.0093078613281250, +0.0018310546875000, 0.0069580078125000, 0.0032043457031250, 0.0075073242187500, +0.0029907226562500, 0.0060119628906250, 0.0031127929687500, 0.0036621093750000, +0.0040893554687500, 0.0050048828125000, 0.0037231445312500, 0.0012512207031250, +0.0041503906250000, 0.0009460449218750, 0.0045166015625000, 0.0014038085937500, +0.0038452148437500, -0.0000915527343750, 0.0034179687500000, 0.0000305175781250, +0.0038757324218750, 0.0010070800781250, 0.0026855468750000, 0.0009155273437500, +0.0027770996093750, 0.0009155273437500, 0.0024719238281250, 0.0016174316406250, +0.0014343261718750, 0.0014648437500000, 0.0018310546875000, 0.0003662109375000, +0.0017700195312500, 0.0009460449218750, 0.0013122558593750, -0.0000610351562500, +0.0017395019531250, -0.0017395019531250, 0.0021057128906250, -0.0008850097656250, +0.0016174316406250, -0.0019836425781250, 0.0020141601562500, -0.0027160644531250, +0.0024719238281250, -0.0016174316406250, 0.0018310546875000, -0.0010070800781250, +0.0014038085937500, -0.0017089843750000, 0.0019836425781250, 0.0002441406250000, +0.0001525878906250, 0.0005187988281250, -0.0001831054687500, 0.0001525878906250, +0.0009460449218750, 0.0007324218750000, 0.0008850097656250, 0.0006408691406250, +0.0001831054687500, -0.0001525878906250, 0.0021667480468750, 0.0002136230468750, +0.0020141601562500, -0.0003967285156250, 0.0024719238281250, -0.0014953613281250, +0.0038452148437500, -0.0010070800781250, 0.0030517578125000, -0.0024414062500000, +0.0037536621093750, -0.0022583007812500, 0.0045471191406250, -0.0025329589843750, +0.0027160644531250, -0.0036926269531250, 0.0006408691406250, -0.0036315917968750, +0.0006713867187500, -0.0053100585937500, -0.0020751953125000, -0.0050354003906250, +-0.0013427734375000, -0.0046386718750000, -0.0017700195312500, -0.0054626464843750, +-0.0040283203125000, -0.0054626464843750, -0.0030517578125000, -0.0046386718750000, +-0.0032348632812500, -0.0048828125000000, -0.0044250488281250, -0.0043029785156250, +-0.0026245117187500, -0.0036315917968750, -0.0007019042968750, -0.0042419433593750, +-0.0021972656250000, -0.0018920898437500, 0.0007629394531250, -0.0024719238281250, +0.0016479492187500, -0.0016479492187500, 0.0006713867187500, 0.0004882812500000, +0.0009460449218750, -0.0006408691406250, 0.0014953613281250, 0.0007019042968750, +0.0003051757812500, 0.0012207031250000, 0.0000915527343750, 0.0006713867187500, +0.0006408691406250, 0.0005493164062500, 0.0005187988281250, 0.0007629394531250, +0.0003967285156250, 0.0001525878906250, 0.0017089843750000, -0.0000915527343750, +0.0018310546875000, 0.0004577636718750, 0.0018920898437500, 0.0006713867187500, +0.0026245117187500, 0.0001831054687500, 0.0025939941406250, 0.0013427734375000, +0.0020446777343750, 0.0013122558593750, 0.0024414062500000, 0.0013427734375000, +0.0021362304687500, 0.0016784667968750, 0.0014343261718750, 0.0013122558593750, +0.0017700195312500, 0.0030517578125000, 0.0008239746093750, 0.0020141601562500, +0.0014038085937500, 0.0031127929687500, 0.0004577636718750, 0.0052490234375000, +-0.0009460449218750, 0.0036926269531250, 0.0000305175781250, 0.0061645507812500, +-0.0019531250000000, 0.0062255859375000, -0.0022583007812500, 0.0059814453125000, +-0.0021362304687500, 0.0070495605468750, -0.0030822753906250, 0.0065612792968750, +-0.0029296875000000, 0.0063171386718750, -0.0016784667968750, 0.0068969726562500, +-0.0023803710937500, 0.0063781738281250, -0.0008544921875000, 0.0057983398437500, +0.0013732910156250, 0.0060729980468750, 0.0003967285156250, 0.0040588378906250, +0.0028991699218750, 0.0052185058593750, 0.0038452148437500, 0.0033264160156250, +0.0033874511718750, 0.0003662109375000, 0.0040588378906250, 0.0024414062500000, +0.0045166015625000, -0.0012207031250000, 0.0034179687500000, -0.0011291503906250, +0.0033569335937500, -0.0007324218750000, 0.0037536621093750, -0.0025329589843750, +0.0029907226562500, -0.0018615722656250, 0.0023498535156250, -0.0007629394531250, +0.0040588378906250, -0.0014343261718750, 0.0027160644531250, -0.0005493164062500, +0.0035705566406250, 0.0009155273437500, 0.0054626464843750, 0.0000610351562500, +0.0035095214843750, 0.0021057128906250, 0.0065002441406250, 0.0018005371093750, +0.0059509277343750, 0.0021057128906250, 0.0056457519531250, 0.0033569335937500, +0.0072021484375000, 0.0024719238281250, 0.0061035156250000, 0.0042419433593750, +0.0063781738281250, 0.0041503906250000, 0.0065307617187500, 0.0036315917968750, +0.0055236816406250, 0.0045471191406250, 0.0049133300781250, 0.0045166015625000, +0.0051574707031250, 0.0030517578125000, 0.0031127929687500, 0.0033874511718750, +0.0034484863281250, 0.0029602050781250, 0.0023193359375000, 0.0018920898437500, +0.0003356933593750, 0.0023803710937500, 0.0012817382812500, 0.0009155273437500, +-0.0009155273437500, 0.0013732910156250, -0.0012207031250000, 0.0006103515625000, +-0.0016479492187500, -0.0008850097656250, -0.0029296875000000, 0.0000610351562500, +-0.0026550292968750, -0.0018615722656250, -0.0033569335937500, -0.0017395019531250, +-0.0036315917968750, -0.0019226074218750, -0.0038757324218750, -0.0030212402343750, +-0.0042724609375000, -0.0024414062500000, -0.0041503906250000, -0.0033264160156250, +-0.0044860839843750, -0.0033264160156250, -0.0047607421875000, -0.0032043457031250, +-0.0046997070312500, -0.0036926269531250, -0.0046691894531250, -0.0035400390625000, +-0.0048828125000000, -0.0029907226562500, -0.0048828125000000, -0.0034179687500000, +-0.0048828125000000, -0.0026550292968750, -0.0048217773437500, -0.0017089843750000, +-0.0048217773437500, -0.0023803710937500, -0.0048522949218750, -0.0005798339843750, +-0.0047607421875000, -0.0004882812500000, -0.0047607421875000, -0.0004882812500000, +-0.0048522949218750, 0.0004577636718750, -0.0047302246093750, 0.0003356933593750, +-0.0044250488281250, 0.0000610351562500, -0.0047302246093750, 0.0002746582031250, +-0.0048828125000000, 0.0005187988281250, -0.0045166015625000, 0.0003356933593750, +-0.0046081542968750, 0.0003051757812500, -0.0049438476562500, 0.0012817382812500, +-0.0036315917968750, 0.0010375976562500, -0.0041503906250000, 0.0014038085937500, +-0.0036010742187500, 0.0022583007812500, -0.0024414062500000, 0.0019531250000000, +-0.0032958984375000, 0.0026245117187500, -0.0012817382812500, 0.0027160644531250, +-0.0016784667968750, 0.0026245117187500, -0.0010986328125000, 0.0030212402343750, +0.0003662109375000, 0.0029907226562500, -0.0006103515625000, 0.0018920898437500, +0.0008239746093750, 0.0023193359375000, 0.0011596679687500, 0.0016479492187500, +0.0006408691406250, 0.0002746582031250, 0.0009460449218750, 0.0010070800781250, +0.0009460449218750, -0.0002136230468750, -0.0004882812500000, -0.0003967285156250, +-0.0001831054687500, -0.0001525878906250, -0.0006713867187500, -0.0006408691406250, +-0.0018615722656250, -0.0005493164062500, -0.0013427734375000, 0.0001831054687500, +-0.0017089843750000, -0.0003356933593750, -0.0021972656250000, 0.0006103515625000, +-0.0011291503906250, 0.0018920898437500, -0.0006408691406250, 0.0009460449218750, +-0.0014038085937500, 0.0028381347656250, 0.0014038085937500, 0.0029602050781250, +0.0010681152343750, 0.0027770996093750, 0.0014648437500000, 0.0036315917968750, +0.0034179687500000, 0.0035400390625000, 0.0026550292968750, 0.0036010742187500, +0.0037231445312500, 0.0035400390625000, 0.0041809082031250, 0.0037841796875000, +0.0029296875000000, 0.0037536621093750, 0.0029296875000000, 0.0036010742187500, +0.0038146972656250, 0.0053710937500000, -0.0012817382812500, 0.0046386718750000, +0.0000305175781250, 0.0057678222656250, -0.0013732910156250, 0.0079040527343750, +-0.0064086914062500, 0.0067443847656250, -0.0043029785156250, 0.0086669921875000, +-0.0038757324218750, 0.0089721679687500, -0.0061950683593750, 0.0089416503906250, +-0.0024719238281250, 0.0097656250000000, 0.0012817382812500, 0.0095214843750000, +-0.0015258789062500, 0.0090026855468750, 0.0068054199218750, 0.0095520019531250, +0.0062866210937500, 0.0083923339843750, 0.0079956054687500, 0.0072937011718750, +0.0138244628906250, 0.0083923339843750, 0.0112915039062500, 0.0052490234375000, +0.0146789550781250, 0.0052490234375000, 0.0161437988281250, 0.0053100585937500, +0.0136108398437500, 0.0038146972656250, 0.0133666992187500, 0.0043945312500000, +0.0145568847656250, 0.0046081542968750, 0.0078125000000000, 0.0038452148437500, +0.0087890625000000, 0.0043029785156250, 0.0072631835937500, 0.0055541992187500, +0.0021667480468750, 0.0050659179687500, 0.0043029785156250, 0.0034790039062500, +0.0014038085937500, 0.0043334960937500, 0.0008850097656250, 0.0025634765625000, +0.0009460449218750, 0.0003662109375000, 0.0001831054687500, 0.0018310546875000, +0.0007019042968750, -0.0025939941406250, -0.0014343261718750, -0.0027160644531250, +-0.0017089843750000, -0.0022888183593750, -0.0003662109375000, -0.0046997070312500, +-0.0007324218750000, -0.0046081542968750, -0.0015869140625000, -0.0014648437500000, +0.0019836425781250, -0.0021667480468750, 0.0020446777343750, -0.0022583007812500, +0.0011901855468750, 0.0006103515625000, 0.0027770996093750, -0.0009155273437500, +-0.0030517578125000, -0.0007019042968750, 0.0007324218750000, -0.0003967285156250, +0.0001831054687500, -0.0013427734375000, -0.0002441406250000, -0.0017089843750000, +0.0008239746093750, -0.0009460449218750, 0.0010986328125000, -0.0040588378906250, +-0.0012512207031250, -0.0039978027343750, -0.0009460449218750, -0.0039367675781250, +-0.0009460449218750, -0.0060119628906250, -0.0025329589843750, -0.0054321289062500, +-0.0021972656250000, -0.0024414062500000, -0.0011901855468750, -0.0047607421875000, +-0.0018310546875000, -0.0015563964843750, -0.0012817382812500, 0.0035400390625000, +0.0002441406250000}, +{-0.0046386718750000, 0.0008544921875000, -0.0063171386718750, 0.0012207031250000, +-0.0054931640625000, 0.0007629394531250, -0.0061950683593750, 0.0005187988281250, +-0.0068054199218750, 0.0007934570312500, -0.0056457519531250, 0.0008544921875000, +-0.0051269531250000, 0.0007629394531250, -0.0058288574218750, 0.0014953613281250, +-0.0026855468750000, 0.0012207031250000, -0.0034179687500000, 0.0018920898437500, +-0.0026550292968750, 0.0027770996093750, 0.0000305175781250, 0.0021667480468750, +-0.0011291503906250, 0.0038757324218750, 0.0002136230468750, 0.0038146972656250, +0.0008544921875000, 0.0038757324218750, -0.0000610351562500, 0.0049438476562500, +-0.0002136230468750, 0.0045776367187500, 0.0004577636718750, 0.0045471191406250, +-0.0014648437500000, 0.0047607421875000, -0.0013122558593750, 0.0047607421875000, +-0.0011291503906250, 0.0045776367187500, -0.0022277832031250, 0.0045776367187500, +-0.0020751953125000, 0.0051574707031250, -0.0011291503906250, 0.0048217773437500, +-0.0022583007812500, 0.0054016113281250, -0.0002746582031250, 0.0062866210937500, +0.0017395019531250, 0.0057373046875000, -0.0003662109375000, 0.0068359375000000, +0.0049743652343750, 0.0070800781250000, 0.0053710937500000, 0.0067138671875000, +0.0044555664062500, 0.0069274902343750, 0.0071716308593750, 0.0071105957031250, +0.0072937011718750, 0.0064392089843750, 0.0017395019531250, 0.0066833496093750, +0.0035705566406250, 0.0060119628906250, 0.0017395019531250, 0.0052795410156250, +-0.0036315917968750, 0.0058593750000000, -0.0010375976562500, 0.0038757324218750, +-0.0027465820312500, 0.0039978027343750, -0.0043945312500000, 0.0039367675781250, +-0.0014648437500000, 0.0025024414062500, 0.0000305175781250, 0.0028991699218750, +-0.0015258789062500, 0.0043945312500000, 0.0064392089843750, 0.0039367675781250, +0.0050048828125000, 0.0039978027343750, 0.0078735351562500, 0.0053100585937500, +0.0149230957031250, 0.0050048828125000, 0.0114440917968750, 0.0032653808593750, +0.0160522460937500, 0.0045776367187500, 0.0181579589843750, 0.0025024414062500, +0.0144653320312500, -0.0007934570312500, 0.0134887695312500, 0.0012207031250000, +0.0155639648437500, -0.0016479492187500, 0.0073547363281250, -0.0024108886718750, +0.0076599121093750, -0.0018310546875000, 0.0070495605468750, -0.0024719238281250, +0.0022277832031250, -0.0024719238281250, 0.0035705566406250, -0.0014038085937500, +0.0026245117187500, -0.0019226074218750, 0.0027770996093750, -0.0011901855468750, +0.0012512207031250, 0.0002441406250000, -0.0003356933593750, -0.0007629394531250, +0.0011596679687500, -0.0005493164062500, -0.0023193359375000, -0.0000305175781250, +-0.0027465820312500, -0.0002441406250000, -0.0015869140625000, -0.0009460449218750, +-0.0023498535156250, -0.0014038085937500, 0.0020141601562500, -0.0032348632812500, +-0.0023498535156250, -0.0026245117187500, -0.0020751953125000, -0.0025024414062500, +-0.0013427734375000, -0.0038146972656250, -0.0021972656250000, -0.0038452148437500, +-0.0026550292968750, -0.0005798339843750, 0.0005187988281250, -0.0018310546875000, +0.0002136230468750, 0.0001525878906250, -0.0002136230468750, 0.0035400390625000, +0.0017700195312500, 0.0014343261718750, 0.0016479492187500, 0.0067749023437500, +-0.0013427734375000, 0.0065917968750000, -0.0004272460937500, 0.0074462890625000, +-0.0008544921875000, 0.0105590820312500, -0.0036315917968750, 0.0090637207031250, +-0.0029602050781250, 0.0127868652343750, -0.0018615722656250, 0.0129394531250000, +-0.0025634765625000, 0.0126037597656250, -0.0021972656250000, 0.0147094726562500, +-0.0009765625000000, 0.0140380859375000, -0.0013427734375000, 0.0105590820312500, +-0.0010375976562500, 0.0136413574218750, -0.0009460449218750, 0.0087280273437500, +-0.0007934570312500, 0.0021667480468750, -0.0008239746093750, 0.0069885253906250, +-0.0010681152343750, -0.0029602050781250, 0.0006103515625000, -0.0038757324218750, +0.0002441406250000, -0.0024414062500000, 0.0003356933593750, -0.0067138671875000, +0.0017395019531250, -0.0062866210937500, 0.0012817382812500, -0.0020141601562500, +0.0006408691406250, -0.0040893554687500, 0.0009460449218750, -0.0015869140625000, +0.0011596679687500, 0.0034790039062500, 0.0005493164062500, 0.0005493164062500, +0.0003356933593750, 0.0042114257812500, 0.0022277832031250, 0.0054321289062500, +0.0019836425781250, 0.0038757324218750, 0.0018005371093750, 0.0043029785156250, +0.0028076171875000, 0.0048522949218750, 0.0026550292968750, 0.0013122558593750, +0.0020141601562500, 0.0020141601562500, 0.0019836425781250, 0.0011291503906250, +0.0021972656250000, -0.0018310546875000, 0.0019836425781250, -0.0003967285156250, +0.0018615722656250, -0.0011901855468750, 0.0027770996093750, -0.0024108886718750, +0.0026550292968750, -0.0010681152343750, 0.0026550292968750, 0.0001525878906250, +0.0032958984375000, -0.0008850097656250, 0.0032348632812500, 0.0007629394531250, +0.0025329589843750, 0.0012207031250000, 0.0026550292968750, 0.0002746582031250, +0.0028991699218750, 0.0004577636718750, 0.0025329589843750, 0.0009765625000000, +0.0023803710937500, -0.0017089843750000, 0.0035095214843750, -0.0007324218750000, +0.0034790039062500, -0.0022277832031250, 0.0032043457031250, -0.0046691894531250, +0.0036926269531250, -0.0027770996093750, 0.0037536621093750, -0.0075073242187500, +0.0028076171875000, -0.0070800781250000, 0.0029602050781250, -0.0073242187500000, +0.0027160644531250, -0.0102233886718750, 0.0020141601562500, -0.0090332031250000, +0.0021972656250000, -0.0091247558593750, 0.0015563964843750, -0.0100402832031250, +0.0015869140625000, -0.0084533691406250, 0.0014343261718750, -0.0072937011718750, +0.0008239746093750, -0.0084533691406250, 0.0010375976562500, -0.0045776367187500, +0.0010070800781250, -0.0053100585937500, 0.0007629394531250, -0.0041503906250000, +0.0010681152343750, -0.0012207031250000, 0.0014343261718750, -0.0029602050781250, +0.0012207031250000, 0.0003967285156250, 0.0016784667968750, 0.0001831054687500, +0.0017395019531250, 0.0005493164062500, 0.0016784667968750, 0.0027465820312500, +0.0019226074218750, 0.0018920898437500, 0.0018615722656250, 0.0035400390625000, +0.0018920898437500, 0.0038757324218750, 0.0021057128906250, 0.0038452148437500, +0.0017395019531250, 0.0046386718750000, 0.0015258789062500, 0.0048217773437500, +0.0018615722656250, 0.0046997070312500, 0.0007019042968750, 0.0052185058593750, +0.0008544921875000, 0.0052185058593750, 0.0005798339843750, 0.0050048828125000, +-0.0002746582031250, 0.0056457519531250, 0.0000610351562500, 0.0051574707031250, +-0.0005798339843750, 0.0054931640625000, -0.0006408691406250, 0.0054931640625000, +-0.0006408691406250, 0.0051879882812500, -0.0009460449218750, 0.0057373046875000, +-0.0008850097656250, 0.0052795410156250, -0.0007019042968750, 0.0054626464843750, +-0.0008850097656250, 0.0056152343750000, -0.0006103515625000, 0.0053405761718750, +-0.0002441406250000, 0.0056457519531250, -0.0004882812500000, 0.0055847167968750, +0.0000610351562500, 0.0057373046875000, 0.0001831054687500, 0.0059204101562500, +0.0000915527343750, 0.0059204101562500, 0.0001525878906250, 0.0060424804687500, +0.0001831054687500, 0.0061645507812500, 0.0008544921875000, 0.0062255859375000, +0.0002441406250000, 0.0063171386718750, 0.0010070800781250, 0.0064086914062500, +0.0021972656250000, 0.0062866210937500, 0.0013122558593750, 0.0061645507812500, +0.0024719238281250, 0.0063476562500000, 0.0028991699218750, 0.0056762695312500, +0.0025329589843750, 0.0051269531250000, 0.0026245117187500, 0.0053710937500000, +0.0026550292968750, 0.0030212402343750, 0.0021057128906250, 0.0035705566406250, +0.0025024414062500, 0.0021057128906250, 0.0018920898437500, -0.0002746582031250, +0.0008850097656250, 0.0008239746093750, 0.0017395019531250, -0.0022277832031250, +0.0010986328125000, -0.0023193359375000, 0.0004577636718750, -0.0027160644531250, +0.0013122558593750, -0.0045166015625000, 0.0018310546875000, -0.0039978027343750, +0.0012512207031250, -0.0048828125000000, 0.0028991699218750, -0.0051879882812500, +0.0025634765625000, -0.0046691894531250, 0.0030212402343750, -0.0046691894531250, +0.0043334960937500, -0.0047607421875000, 0.0036010742187500, -0.0037231445312500, +0.0044555664062500, -0.0039062500000000, 0.0048217773437500, -0.0032348632812500, +0.0043945312500000, -0.0022888183593750, 0.0042419433593750, -0.0028381347656250, +0.0044860839843750, -0.0010681152343750, 0.0047912597656250, -0.0011596679687500, +0.0044555664062500, -0.0007019042968750, 0.0044250488281250, 0.0003051757812500, +0.0050354003906250, -0.0002136230468750, 0.0049743652343750, 0.0014343261718750, +0.0037536621093750, 0.0008544921875000, 0.0044555664062500, 0.0018005371093750, +0.0033264160156250, 0.0033569335937500, 0.0015563964843750, 0.0022583007812500, +0.0026855468750000, 0.0052185058593750, 0.0012817382812500, 0.0050964355468750, +0.0005187988281250, 0.0054626464843750, 0.0015563964843750, 0.0074157714843750, +0.0018920898437500, 0.0068054199218750, 0.0012207031250000, 0.0076293945312500, +0.0029296875000000, 0.0079345703125000, 0.0032958984375000, 0.0072937011718750, +0.0022583007812500, 0.0074157714843750, 0.0023498535156250, 0.0077819824218750, +0.0029907226562500, 0.0053710937500000, 0.0010070800781250, 0.0057678222656250, +0.0009765625000000, 0.0052490234375000, 0.0010681152343750, 0.0034179687500000, +0.0001220703125000, 0.0040588378906250, 0.0002746582031250, 0.0024414062500000, +0.0009155273437500, 0.0026855468750000, 0.0004272460937500, 0.0018920898437500, +0.0011291503906250, 0.0004272460937500, 0.0023803710937500, 0.0010375976562500, +0.0014953613281250, -0.0016479492187500, 0.0005798339843750, -0.0016174316406250, +0.0018310546875000, -0.0016784667968750, 0.0008544921875000, -0.0035095214843750, +-0.0012512207031250, -0.0032348632812500, -0.0002441406250000, -0.0017395019531250, +-0.0017089843750000, -0.0028076171875000, -0.0016479492187500, -0.0011291503906250, +-0.0025024414062500, 0.0015869140625000, -0.0039367675781250, -0.0001220703125000, +-0.0027770996093750, 0.0014038085937500, -0.0032043457031250, 0.0025634765625000, +-0.0042114257812500, 0.0010681152343750, -0.0030212402343750, -0.0004882812500000, +-0.0014038085937500, -0.0004577636718750, -0.0012512207031250, -0.0021362304687500, +0.0011901855468750, -0.0021972656250000, 0.0003967285156250, -0.0016174316406250, +0.0006103515625000, -0.0019226074218750, 0.0025939941406250, -0.0022277832031250, +0.0019226074218750, -0.0022888183593750, 0.0024414062500000, -0.0017700195312500, +0.0029907226562500, -0.0025634765625000, 0.0024108886718750, -0.0035705566406250, +0.0019226074218750, -0.0029907226562500, 0.0023803710937500, -0.0046997070312500, +0.0019531250000000, -0.0047302246093750, 0.0019226074218750, -0.0047912597656250, +0.0016174316406250, -0.0057983398437500, 0.0013427734375000, -0.0055847167968750, +0.0017700195312500, -0.0052185058593750, 0.0012817382812500, -0.0056457519531250, +0.0009765625000000, -0.0049438476562500, 0.0016784667968750, -0.0043640136718750, +0.0020446777343750, -0.0049743652343750, 0.0014648437500000, -0.0022888183593750, +0.0022277832031250, -0.0031738281250000, 0.0031127929687500, -0.0021057128906250, +0.0014953613281250, 0.0005798339843750, 0.0002746582031250, -0.0009765625000000, +0.0017700195312500, 0.0009155273437500, -0.0011291503906250, 0.0012817382812500, +-0.0014343261718750, 0.0006713867187500, -0.0005493164062500, 0.0010375976562500, +-0.0014648437500000, 0.0012512207031250, -0.0015258789062500, 0.0005798339843750, +0.0018615722656250}, +{0.0056762695312500, -0.0014953613281250, 0.0049438476562500, -0.0014343261718750, +0.0049743652343750, -0.0021972656250000, 0.0050659179687500, -0.0042114257812500, +0.0047912597656250, -0.0033264160156250, 0.0046081542968750, -0.0046081542968750, +0.0042419433593750, -0.0050659179687500, 0.0047607421875000, -0.0043640136718750, +0.0037536621093750, -0.0041809082031250, 0.0025634765625000, -0.0044250488281250, +0.0034179687500000, -0.0028991699218750, 0.0013122558593750, -0.0030822753906250, +0.0011596679687500, -0.0024108886718750, 0.0017089843750000, -0.0011596679687500, +0.0008850097656250, -0.0017700195312500, 0.0007324218750000, 0.0000305175781250, +0.0024108886718750, -0.0001831054687500, 0.0021057128906250, 0.0002441406250000, +0.0022583007812500, 0.0015563964843750, 0.0035400390625000, 0.0009460449218750, +0.0031738281250000, 0.0017395019531250, 0.0021667480468750, 0.0015563964843750, +0.0027465820312500, 0.0025634765625000, 0.0024108886718750, 0.0034790039062500, +0.0013427734375000, 0.0025024414062500, 0.0017395019531250, 0.0058898925781250, +0.0013122558593750, 0.0061035156250000, 0.0013427734375000, 0.0057678222656250, +0.0010681152343750, 0.0073852539062500, 0.0007324218750000, 0.0071105957031250, +0.0010681152343750, 0.0058593750000000, 0.0001220703125000, 0.0066223144531250, +0.0004272460937500, 0.0054016113281250, -0.0009765625000000, 0.0035705566406250, +-0.0023498535156250, 0.0045776367187500, -0.0009155273437500, 0.0020751953125000, +-0.0037536621093750, 0.0021057128906250, -0.0042724609375000, 0.0013122558593750, +-0.0036621093750000, -0.0004882812500000, -0.0041198730468750, 0.0003356933593750, +-0.0042114257812500, -0.0017395019531250, -0.0042724609375000, -0.0019531250000000, +-0.0044555664062500, -0.0014648437500000, -0.0034484863281250, -0.0025024414062500, +-0.0030822753906250, -0.0025939941406250, -0.0040283203125000, 0.0003051757812500, +-0.0012512207031250, -0.0003662109375000, -0.0009460449218750, -0.0001525878906250, +-0.0007629394531250, 0.0024719238281250, 0.0005187988281250, 0.0019836425781250, +0.0006103515625000, -0.0001831054687500, 0.0017089843750000, 0.0011901855468750, +0.0015258789062500, 0.0004272460937500, 0.0014648437500000, -0.0019531250000000, +0.0023193359375000, -0.0006408691406250, 0.0022583007812500, -0.0019531250000000, +0.0015258789062500, -0.0024414062500000, 0.0018920898437500, -0.0022277832031250, +0.0017089843750000, -0.0023498535156250, 0.0009765625000000, -0.0022888183593750, +0.0012207031250000, -0.0031127929687500, 0.0008239746093750, -0.0027160644531250, +0.0007324218750000, -0.0036926269531250, 0.0008544921875000, -0.0050048828125000, +0.0006713867187500, -0.0040893554687500, 0.0005798339843750, -0.0058593750000000, +0.0011291503906250, -0.0061950683593750, 0.0011291503906250, -0.0058898925781250, +0.0007934570312500, -0.0065002441406250, 0.0011291503906250, -0.0065917968750000, +0.0014038085937500, -0.0061035156250000, -0.0003662109375000, -0.0064697265625000, +-0.0003662109375000, -0.0056762695312500, 0.0005187988281250, -0.0051269531250000, +-0.0000915527343750, -0.0059509277343750, -0.0006103515625000, -0.0028076171875000, +0.0024414062500000, -0.0036926269531250, 0.0018310546875000, -0.0025939941406250, +0.0023498535156250, 0.0002746582031250, 0.0047302246093750, -0.0013732910156250, +0.0037231445312500, 0.0007324218750000, 0.0041503906250000, 0.0012512207031250, +0.0046386718750000, 0.0005493164062500, 0.0039672851562500, 0.0009460449218750, +0.0034179687500000, 0.0012207031250000, 0.0036010742187500, 0.0003967285156250, +0.0021972656250000, 0.0003662109375000, 0.0021057128906250, 0.0004577636718750, +0.0017700195312500, 0.0001525878906250, 0.0004272460937500, 0.0002136230468750, +0.0003356933593750, 0.0006408691406250, 0.0009155273437500, 0.0002746582031250, +-0.0000305175781250, 0.0007019042968750, 0.0001525878906250, 0.0012207031250000, +0.0010070800781250, 0.0007324218750000, 0.0001220703125000, 0.0028076171875000, +0.0001525878906250, 0.0022583007812500, 0.0002746582031250, 0.0025939941406250, +-0.0000610351562500, 0.0042114257812500, -0.0004882812500000, 0.0035095214843750, +-0.0003967285156250, 0.0047302246093750, 0.0003051757812500, 0.0048217773437500, +-0.0002136230468750, 0.0042419433593750, 0.0007019042968750, 0.0045776367187500, +0.0019836425781250, 0.0049133300781250, 0.0012512207031250, 0.0037231445312500, +0.0032043457031250, 0.0037231445312500, 0.0034179687500000, 0.0036315917968750, +0.0034179687500000, 0.0030822753906250, 0.0043334960937500, 0.0032653808593750, +0.0042419433593750, 0.0027160644531250, 0.0044860839843750, 0.0029296875000000, +0.0046997070312500, 0.0025634765625000, 0.0047302246093750, 0.0020751953125000, +0.0046997070312500, 0.0026855468750000, 0.0046691894531250, 0.0015258789062500, +0.0043334960937500, 0.0017089843750000, 0.0042724609375000, 0.0017395019531250, +0.0039367675781250, 0.0010681152343750, 0.0034790039062500, 0.0015258789062500, +0.0034179687500000, 0.0008544921875000, 0.0027770996093750, 0.0008850097656250, +0.0026245117187500, 0.0010681152343750, 0.0025024414062500, 0.0007629394531250, +0.0021057128906250, 0.0006713867187500, 0.0019836425781250, 0.0010681152343750, +0.0019531250000000, 0.0008544921875000, 0.0020141601562500, 0.0009765625000000, +0.0018920898437500, 0.0012512207031250, 0.0019836425781250, 0.0009155273437500, +0.0021667480468750, 0.0014648437500000, 0.0015869140625000, 0.0014343261718750, +0.0018310546875000, 0.0012817382812500, 0.0013122558593750, 0.0015258789062500, +0.0006103515625000, 0.0015563964843750, 0.0009765625000000, 0.0010681152343750, +-0.0003967285156250, 0.0012512207031250, -0.0001525878906250, 0.0011291503906250, +-0.0006408691406250, 0.0007629394531250, -0.0018310546875000, 0.0010375976562500, +-0.0011596679687500, 0.0004882812500000, -0.0024719238281250, 0.0006408691406250, +-0.0024719238281250, 0.0005187988281250, -0.0026550292968750, 0.0000915527343750, +-0.0033569335937500, 0.0005187988281250, -0.0029907226562500, 0.0003051757812500, +-0.0037841796875000, 0.0001831054687500, -0.0034484863281250, 0.0005798339843750, +-0.0037231445312500, 0.0007629394531250, -0.0043640136718750, 0.0005493164062500, +-0.0040588378906250, 0.0014343261718750, -0.0050964355468750, 0.0013122558593750, +-0.0048217773437500, 0.0014953613281250, -0.0050354003906250, 0.0021972656250000, +-0.0057983398437500, 0.0019226074218750, -0.0052490234375000, 0.0021972656250000, +-0.0060424804687500, 0.0021972656250000, -0.0060424804687500, 0.0023803710937500, +-0.0059204101562500, 0.0026245117187500, -0.0063476562500000, 0.0025024414062500, +-0.0061645507812500, 0.0030822753906250, -0.0054626464843750, 0.0030517578125000, +-0.0058898925781250, 0.0033874511718750, -0.0048522949218750, 0.0038452148437500, +-0.0036926269531250, 0.0035705566406250, -0.0044555664062500, 0.0043334960937500, +-0.0015563964843750, 0.0042724609375000, -0.0020751953125000, 0.0043640136718750, +-0.0010375976562500, 0.0048522949218750, 0.0014343261718750, 0.0046081542968750, +0.0000610351562500, 0.0045776367187500, 0.0025634765625000, 0.0048217773437500, +0.0030212402343750, 0.0045776367187500, 0.0023193359375000, 0.0041809082031250, +0.0034484863281250, 0.0043640136718750, 0.0038757324218750, 0.0047912597656250, +0.0012512207031250, 0.0044555664062500, 0.0023498535156250, 0.0048217773437500, +0.0008544921875000, 0.0056457519531250, -0.0020751953125000, 0.0053710937500000, +-0.0002746582031250, 0.0053100585937500, -0.0032348632812500, 0.0057373046875000, +-0.0037536621093750, 0.0053100585937500, -0.0030517578125000, 0.0047302246093750, +-0.0037536621093750, 0.0051879882812500, -0.0035095214843750, 0.0041503906250000, +-0.0020141601562500, 0.0042724609375000, -0.0020751953125000, 0.0036926269531250, +-0.0008544921875000, 0.0027770996093750, 0.0011596679687500, 0.0032958984375000, +0.0008239746093750, 0.0014953613281250, 0.0016479492187500, 0.0016784667968750, +0.0024108886718750, 0.0011291503906250, 0.0014038085937500, -0.0002441406250000, +0.0004577636718750, 0.0003662109375000, 0.0010681152343750, -0.0012207031250000, +-0.0002441406250000, -0.0010681152343750, -0.0012207031250000, -0.0015563964843750, +-0.0002441406250000, -0.0027465820312500, 0.0002746582031250, -0.0020751953125000, +-0.0007019042968750, -0.0030212402343750, 0.0012512207031250, -0.0028076171875000, +0.0011596679687500, -0.0037231445312500, 0.0012512207031250, -0.0049133300781250, +0.0022888183593750, -0.0038757324218750, 0.0018615722656250, -0.0050048828125000, +0.0027160644531250, -0.0059814453125000, 0.0030822753906250, -0.0046691894531250, +0.0031127929687500, -0.0040283203125000, 0.0035095214843750, -0.0049133300781250, +0.0036621093750000, -0.0013122558593750, 0.0032043457031250, -0.0016479492187500, +0.0030517578125000, -0.0019226074218750, 0.0039672851562500, 0.0002441406250000, +0.0038146972656250, -0.0000915527343750, 0.0032043457031250, -0.0014953613281250, +0.0082092285156250, -0.0012207031250000, 0.0070495605468750, -0.0010986328125000, +0.0086059570312500, -0.0019836425781250, 0.0133972167968750, -0.0021667480468750, +0.0112915039062500, -0.0015563964843750, 0.0113220214843750, -0.0014648437500000, +0.0136108398437500, -0.0016479492187500, 0.0105895996093750, -0.0016174316406250, +0.0070800781250000, -0.0017395019531250, 0.0095214843750000, -0.0020141601562500, +0.0048522949218750, -0.0020446777343750, 0.0040283203125000, -0.0018310546875000, +0.0052185058593750, -0.0018615722656250, 0.0040588378906250, 0.0048828125000000, +0.0086669921875000, 0.0086059570312500, 0.0054931640625000, 0.0083923339843750, +0.0051879882812500, 0.0077514648437500, 0.0061950683593750, 0.0080261230468750, +0.0066833496093750, 0.0085449218750000, 0.0059204101562500, 0.0088500976562500, +0.0058898925781250, 0.0082397460937500, 0.0077819824218750, 0.0086059570312500, +0.0047302246093750, 0.0100097656250000, 0.0013427734375000, 0.0095520019531250, +0.0039978027343750, 0.0074157714843750, -0.0007324218750000, 0.0097351074218750, +-0.0018615722656250, 0.0059509277343750, -0.0001831054687500, 0.0012207031250000, +-0.0005798339843750, 0.0049438476562500, -0.0014038085937500, -0.0025024414062500, +0.0000915527343750, -0.0032958984375000, 0.0008239746093750, -0.0019226074218750, +-0.0003967285156250, -0.0049743652343750, -0.0010375976562500, -0.0049438476562500, +-0.0003356933593750, -0.0007934570312500, -0.0024108886718750, -0.0020141601562500, +-0.0026550292968750, -0.0014648437500000, -0.0022888183593750, 0.0020446777343750, +-0.0030517578125000, 0.0010070800781250, -0.0030822753906250, 0.0010375976562500, +-0.0020751953125000, 0.0019226074218750, -0.0019531250000000, 0.0014343261718750, +-0.0024719238281250, 0.0005798339843750, -0.0023193359375000, 0.0011596679687500, +-0.0020141601562500, 0.0007019042968750, -0.0029296875000000, 0.0003967285156250, +-0.0032348632812500, 0.0009460449218750, -0.0026245117187500, 0.0013122558593750, +-0.0025329589843750, 0.0009155273437500, -0.0030517578125000, 0.0011596679687500, +-0.0018920898437500, 0.0018310546875000, -0.0017395019531250, 0.0011901855468750, +-0.0018920898437500, 0.0006408691406250, -0.0017395019531250, 0.0012817382812500, +-0.0018310546875000, -0.0010681152343750, -0.0012817382812500, -0.0002136230468750, +-0.0018310546875000, -0.0014953613281250, -0.0011291503906250, -0.0041198730468750, +-0.0000610351562500, -0.0024414062500000, -0.0007934570312500, -0.0044250488281250, +0.0008850097656250, -0.0052185058593750, 0.0009765625000000, -0.0038146972656250, +0.0006713867187500}, +{0.0014343261718750, -0.0032653808593750, 0.0009765625000000, -0.0042724609375000, +0.0009765625000000, -0.0041809082031250, 0.0010070800781250, -0.0042724609375000, +0.0002441406250000, -0.0043640136718750, 0.0004577636718750, -0.0039978027343750, +-0.0001525878906250, -0.0039672851562500, -0.0010986328125000, -0.0044860839843750, +-0.0007019042968750, -0.0030517578125000, -0.0022583007812500, -0.0030822753906250, +-0.0026855468750000, -0.0030517578125000, -0.0017700195312500, -0.0025024414062500, +-0.0019226074218750, -0.0028686523437500, -0.0022277832031250, -0.0028076171875000, +0.0012512207031250, -0.0025024414062500, 0.0004272460937500, -0.0027160644531250, +0.0016174316406250, -0.0032958984375000, 0.0047302246093750, -0.0031127929687500, +0.0033569335937500, -0.0022888183593750, 0.0051574707031250, -0.0028686523437500, +0.0054626464843750, -0.0024414062500000, 0.0056152343750000, -0.0012207031250000, +0.0061340332031250, -0.0017089843750000, 0.0057678222656250, -0.0013427734375000, +0.0082397460937500, -0.0018310546875000, 0.0074768066406250, -0.0007019042968750, +0.0083007812500000, 0.0002746582031250, 0.0108337402343750, -0.0006408691406250, +0.0096130371093750, 0.0027770996093750, 0.0098571777343750, 0.0021972656250000, +0.0109558105468750, 0.0030822753906250, 0.0093994140625000, 0.0076599121093750, +0.0063781738281250, 0.0087890625000000, 0.0080871582031250, 0.0057067871093750, +0.0090026855468750, 0.0067749023437500, 0.0100708007812500, 0.0063476562500000, +0.0084533691406250, 0.0051879882812500, 0.0068054199218750, 0.0055236816406250, +0.0080566406250000, 0.0037231445312500, 0.0069580078125000, 0.0049438476562500, +0.0060729980468750, 0.0032653808593750, 0.0067749023437500, 0.0008239746093750, +0.0079040527343750, 0.0026550292968750, 0.0074157714843750, -0.0019836425781250, +0.0054321289062500, -0.0021362304687500, 0.0070800781250000, -0.0012512207031250, +0.0047607421875000, -0.0031738281250000, 0.0010986328125000, -0.0032043457031250, +0.0033874511718750, -0.0014953613281250, -0.0000610351562500, -0.0018920898437500, +-0.0008544921875000, -0.0017089843750000, -0.0003662109375000, -0.0003356933593750, +-0.0012207031250000, -0.0005798339843750, -0.0010375976562500, -0.0015869140625000, +-0.0007629394531250, -0.0012512207031250, -0.0006408691406250, -0.0006713867187500, +-0.0011901855468750, -0.0014038085937500, -0.0015563964843750, -0.0016784667968750, +-0.0010986328125000, 0.0010986328125000, -0.0024414062500000, 0.0006103515625000, +-0.0025939941406250, 0.0008239746093750, -0.0022888183593750, 0.0029907226562500, +-0.0027160644531250, 0.0025329589843750, -0.0028076171875000, 0.0012817382812500, +-0.0025024414062500, 0.0024108886718750, -0.0024414062500000, 0.0006103515625000, +-0.0027160644531250, -0.0017395019531250, -0.0028686523437500, 0.0000305175781250, +-0.0027160644531250, -0.0034179687500000, -0.0027160644531250, -0.0038146972656250, +-0.0031433105468750, -0.0032348632812500, -0.0025634765625000, -0.0045471191406250, +-0.0018920898437500, -0.0043945312500000, -0.0023803710937500, -0.0031127929687500, +-0.0012817382812500, -0.0040283203125000, -0.0013122558593750, -0.0026245117187500, +-0.0013122558593750, -0.0006713867187500, -0.0008544921875000, -0.0023803710937500, +-0.0009765625000000, 0.0003051757812500, -0.0007934570312500, 0.0010986328125000, +-0.0010681152343750, -0.0003051757812500, -0.0004577636718750, -0.0000610351562500, +0.0001525878906250, 0.0007324218750000, -0.0004577636718750, -0.0021362304687500, +0.0006713867187500, -0.0016784667968750, 0.0008850097656250, -0.0018310546875000, +0.0005187988281250, -0.0036621093750000, 0.0005798339843750, -0.0028686523437500, +0.0006408691406250, -0.0032348632812500, 0.0007629394531250, -0.0035705566406250, +0.0003662109375000, -0.0029602050781250, 0.0009460449218750, -0.0028686523437500, +0.0016479492187500, -0.0032348632812500, 0.0011901855468750, -0.0010070800781250, +0.0021972656250000, -0.0018615722656250, 0.0021972656250000, -0.0005798339843750, +0.0023193359375000, 0.0017089843750000, 0.0028686523437500, 0.0000915527343750, +0.0025329589843750, 0.0028076171875000, 0.0032653808593750, 0.0028076171875000, +0.0032043457031250, 0.0025939941406250, 0.0032653808593750, 0.0039672851562500, +0.0037841796875000, 0.0035400390625000, 0.0036010742187500, 0.0032348632812500, +0.0034179687500000, 0.0040588378906250, 0.0035095214843750, 0.0031738281250000, +0.0033264160156250, 0.0024414062500000, 0.0030822753906250, 0.0035705566406250, +0.0032043457031250, 0.0009155273437500, 0.0026855468750000, 0.0019531250000000, +0.0028991699218750, 0.0013122558593750, 0.0024719238281250, -0.0007629394531250, +0.0018615722656250, 0.0009765625000000, 0.0022583007812500, -0.0018310546875000, +0.0010986328125000, -0.0011901855468750, 0.0010070800781250, -0.0016784667968750, +0.0011291503906250, -0.0037841796875000, 0.0006103515625000, -0.0024108886718750, +0.0007019042968750, -0.0043029785156250, 0.0011291503906250, -0.0040588378906250, +0.0010070800781250, -0.0040588378906250, 0.0011901855468750, -0.0050048828125000, +0.0014648437500000, -0.0041198730468750, 0.0013732910156250, -0.0050659179687500, +0.0017089843750000, -0.0046691894531250, 0.0016784667968750, -0.0046081542968750, +0.0017395019531250, -0.0051879882812500, 0.0020141601562500, -0.0044555664062500, +0.0018615722656250, -0.0052490234375000, 0.0017700195312500, -0.0049133300781250, +0.0019226074218750, -0.0047607421875000, 0.0017089843750000, -0.0052795410156250, +0.0014648437500000, -0.0048217773437500, 0.0016479492187500, -0.0048522949218750, +0.0009765625000000, -0.0047607421875000, 0.0011291503906250, -0.0046081542968750, +0.0010070800781250, -0.0045471191406250, 0.0003662109375000, -0.0042419433593750, +0.0007324218750000, -0.0042114257812500, 0.0008239746093750, -0.0043029785156250, +0.0005798339843750, -0.0037536621093750, 0.0008239746093750, -0.0033874511718750, +0.0011901855468750, -0.0034790039062500, 0.0010986328125000, -0.0018615722656250, +0.0015563964843750, -0.0021972656250000, 0.0011901855468750, -0.0015258789062500, +0.0020141601562500, -0.0001220703125000, 0.0027770996093750, -0.0006713867187500, +0.0018920898437500, 0.0009460449218750, 0.0039367675781250, 0.0011291503906250, +0.0036315917968750, 0.0015258789062500, 0.0039978027343750, 0.0026245117187500, +0.0052795410156250, 0.0024414062500000, 0.0044555664062500, 0.0031127929687500, +0.0056152343750000, 0.0032348632812500, 0.0059204101562500, 0.0029602050781250, +0.0051269531250000, 0.0029907226562500, 0.0051879882812500, 0.0030212402343750, +0.0056152343750000, 0.0022583007812500, 0.0037231445312500, 0.0022888183593750, +0.0039062500000000, 0.0020751953125000, 0.0036621093750000, 0.0014038085937500, +0.0025024414062500, 0.0015258789062500, 0.0029296875000000, 0.0015563964843750, +0.0021362304687500, 0.0014038085937500, 0.0021362304687500, 0.0016479492187500, +0.0020751953125000, 0.0019226074218750, 0.0014648437500000, 0.0018920898437500, +0.0015869140625000, 0.0023498535156250, 0.0017700195312500, 0.0026855468750000, +0.0015563964843750, 0.0024108886718750, 0.0017089843750000, 0.0025329589843750, +0.0018920898437500, 0.0028381347656250, 0.0018005371093750, 0.0014038085937500, +0.0027770996093750, 0.0019531250000000, 0.0024108886718750, 0.0010375976562500, +0.0026550292968750, -0.0005798339843750, 0.0036010742187500, 0.0003356933593750, +0.0032348632812500, -0.0019836425781250, 0.0032958984375000, -0.0019836425781250, +0.0036621093750000, -0.0021362304687500, 0.0029907226562500, -0.0036926269531250, +0.0026245117187500, -0.0031433105468750, 0.0029907226562500, -0.0021667480468750, +0.0006103515625000, -0.0032348632812500, 0.0015258789062500, -0.0020141601562500, +0.0001831054687500, 0.0001525878906250, -0.0025939941406250, -0.0011596679687500, +-0.0009765625000000, -0.0000915527343750, -0.0035095214843750, 0.0005187988281250, +-0.0036926269531250, 0.0000610351562500, -0.0038146972656250, -0.0002441406250000, +-0.0049743652343750, 0.0000000000000000, -0.0042114257812500, 0.0002746582031250, +-0.0047912597656250, -0.0002136230468750, -0.0057983398437500, 0.0009460449218750, +-0.0042114257812500, 0.0019836425781250, -0.0027160644531250, 0.0011901855468750, +-0.0040893554687500, 0.0046386718750000, -0.0022888183593750, 0.0046386718750000, +-0.0018615722656250, 0.0045776367187500, -0.0023498535156250, 0.0066833496093750, +-0.0021362304687500, 0.0062866210937500, -0.0021972656250000, 0.0046081542968750, +-0.0026245117187500, 0.0056762695312500, -0.0025329589843750, 0.0043334960937500, +-0.0026550292968750, 0.0018920898437500, -0.0032653808593750, 0.0030517578125000, +-0.0032348632812500, 0.0010986328125000, -0.0015258789062500, 0.0009460449218750, +-0.0023193359375000, 0.0013122558593750, -0.0018310546875000, 0.0010070800781250, +0.0003051757812500, 0.0012817382812500, -0.0000915527343750, 0.0006713867187500, +-0.0003662109375000, 0.0013122558593750, 0.0000915527343750, 0.0007629394531250, +-0.0000915527343750, -0.0005187988281250, -0.0007324218750000, 0.0002136230468750, +-0.0006408691406250, -0.0007019042968750, -0.0006103515625000, -0.0008239746093750, +-0.0005798339843750, -0.0010681152343750, -0.0005798339843750, -0.0014953613281250, +-0.0008239746093750, -0.0009155273437500, -0.0007629394531250, -0.0024414062500000, +0.0001525878906250, -0.0021972656250000, -0.0004272460937500, -0.0022277832031250, +0.0007019042968750, -0.0033874511718750, 0.0023803710937500, -0.0030517578125000, +0.0014038085937500, -0.0018005371093750, 0.0035095214843750, -0.0022888183593750, +0.0039062500000000, -0.0023193359375000, 0.0036621093750000, -0.0012207031250000, +0.0045166015625000, -0.0014038085937500, 0.0043029785156250, -0.0032653808593750, +0.0026245117187500, -0.0025939941406250, 0.0034790039062500, -0.0033264160156250, +0.0026550292968750, -0.0052185058593750, 0.0004577636718750, -0.0044250488281250, +0.0014648437500000, -0.0054931640625000, 0.0008850097656250, -0.0057373046875000, +0.0003662109375000, -0.0056457519531250, 0.0003967285156250, -0.0060424804687500, +0.0005798339843750, -0.0058288574218750, 0.0004272460937500, -0.0056152343750000, +-0.0008850097656250, -0.0063476562500000, -0.0005187988281250, -0.0050354003906250, +-0.0011596679687500, -0.0039672851562500, -0.0028076171875000, -0.0051269531250000, +-0.0025329589843750, -0.0012512207031250, -0.0020141601562500, -0.0018920898437500, +-0.0032348632812500, -0.0013122558593750, -0.0017089843750000, 0.0014343261718750, +0.0001525878906250, 0.0002441406250000, -0.0012817382812500, 0.0017089843750000, +0.0020751953125000, 0.0020751953125000, 0.0019836425781250, 0.0017395019531250, +0.0021362304687500, 0.0021362304687500, 0.0039978027343750, 0.0020751953125000, +0.0032653808593750, 0.0018920898437500, 0.0032958984375000, 0.0020751953125000, +0.0037536621093750, 0.0018310546875000, 0.0028686523437500, 0.0014038085937500, +0.0020446777343750, 0.0016174316406250, 0.0026245117187500, 0.0014038085937500, +0.0013732910156250, 0.0012817382812500, 0.0010986328125000, 0.0013732910156250, +0.0016784667968750, 0.0013427734375000, 0.0015563964843750, 0.0012512207031250, +0.0012817382812500, 0.0016174316406250, 0.0026550292968750, 0.0015869140625000, +0.0023803710937500, 0.0015258789062500, 0.0026855468750000, 0.0017089843750000, +0.0036621093750000, 0.0018005371093750, 0.0029602050781250, 0.0017395019531250, +0.0032043457031250, 0.0016174316406250, 0.0031127929687500, 0.0018310546875000, +0.0026550292968750, 0.0020141601562500, 0.0024414062500000, 0.0017700195312500, +0.0022277832031250}, +{-0.0008850097656250, 0.0005798339843750, -0.0006408691406250, 0.0003967285156250, +-0.0029296875000000, -0.0001525878906250, -0.0026550292968750, 0.0011596679687500, +-0.0027770996093750, 0.0021667480468750, -0.0043029785156250, 0.0013122558593750, +-0.0038757324218750, 0.0043640136718750, -0.0034484863281250, 0.0047302246093750, +-0.0044250488281250, 0.0038452148437500, -0.0029602050781250, 0.0049133300781250, +-0.0012207031250000, 0.0053100585937500, -0.0028076171875000, 0.0024108886718750, +-0.0002746582031250, 0.0030212402343750, -0.0000610351562500, 0.0023193359375000, +-0.0006408691406250, -0.0003051757812500, 0.0000610351562500, 0.0004882812500000, +-0.0002746582031250, 0.0008544921875000, -0.0015563964843750, 0.0003967285156250, +-0.0014648437500000, 0.0000305175781250, -0.0012207031250000, 0.0004577636718750, +-0.0017395019531250, 0.0007324218750000, -0.0018310546875000, -0.0013122558593750, +-0.0011291503906250, -0.0009765625000000, -0.0018005371093750, -0.0009765625000000, +-0.0005187988281250, -0.0023193359375000, 0.0010070800781250, -0.0019836425781250, +-0.0001831054687500, -0.0017700195312500, 0.0030212402343750, -0.0017700195312500, +0.0032958984375000, -0.0021667480468750, 0.0028686523437500, -0.0021972656250000, +0.0042724609375000, -0.0015869140625000, 0.0043945312500000, -0.0025329589843750, +0.0024719238281250, -0.0028991699218750, 0.0030212402343750, -0.0019226074218750, +0.0022277832031250, -0.0015563964843750, 0.0004882812500000, -0.0022583007812500, +0.0014038085937500, -0.0006408691406250, 0.0005798339843750, -0.0003356933593750, +-0.0002136230468750, -0.0009765625000000, 0.0005493164062500, -0.0006103515625000, +0.0012207031250000, -0.0004272460937500, 0.0003051757812500, -0.0025634765625000, +0.0003051757812500, -0.0019226074218750, 0.0008239746093750, -0.0025939941406250, +-0.0003356933593750, -0.0046081542968750, -0.0016784667968750, -0.0038146972656250, +-0.0010681152343750, -0.0052185058593750, -0.0019836425781250, -0.0052490234375000, +-0.0030822753906250, -0.0049743652343750, -0.0019531250000000, -0.0056762695312500, +-0.0010681152343750, -0.0056152343750000, -0.0020446777343750, -0.0044250488281250, +0.0004882812500000, -0.0051879882812500, 0.0005798339843750, -0.0038757324218750, +0.0004882812500000, -0.0021667480468750, 0.0017089843750000, -0.0034484863281250, +0.0013122558593750, -0.0003356933593750, 0.0007324218750000, -0.0006713867187500, +0.0010986328125000, -0.0002441406250000, 0.0005798339843750, 0.0017700195312500, +-0.0003051757812500, 0.0007934570312500, 0.0002136230468750, 0.0017395019531250, +-0.0002746582031250, 0.0019531250000000, -0.0005493164062500, 0.0016479492187500, +0.0001525878906250, 0.0019531250000000, 0.0005798339843750, 0.0020141601562500, +0.0003356933593750, 0.0013732910156250, 0.0015869140625000, 0.0014038085937500, +0.0015258789062500, 0.0014953613281250, 0.0015258789062500, 0.0012512207031250, +0.0021362304687500, 0.0012207031250000, 0.0015563964843750, 0.0011291503906250, +0.0012512207031250, 0.0012512207031250, 0.0012207031250000, 0.0011291503906250, +0.0005187988281250, 0.0010375976562500, -0.0000915527343750, 0.0012512207031250, +0.0000915527343750, 0.0004272460937500, -0.0009460449218750, 0.0006103515625000, +-0.0009460449218750, 0.0006103515625000, -0.0011596679687500, 0.0000915527343750, +-0.0017089843750000, 0.0002441406250000, -0.0013427734375000, 0.0002746582031250, +-0.0018920898437500, 0.0000610351562500, -0.0014648437500000, 0.0006408691406250, +-0.0016174316406250, 0.0010375976562500, -0.0021057128906250, 0.0006103515625000, +-0.0014953613281250, 0.0021667480468750, -0.0021667480468750, 0.0021057128906250, +-0.0017700195312500, 0.0023193359375000, -0.0015563964843750, 0.0033264160156250, +-0.0019836425781250, 0.0030822753906250, -0.0015869140625000, 0.0030517578125000, +-0.0015258789062500, 0.0035400390625000, -0.0017700195312500, 0.0031433105468750, +-0.0017395019531250, 0.0025024414062500, -0.0018005371093750, 0.0030212402343750, +-0.0023498535156250, 0.0024719238281250, -0.0018310546875000, 0.0024414062500000, +-0.0021362304687500, 0.0025939941406250, -0.0021057128906250, 0.0025024414062500, +-0.0017395019531250, 0.0026245117187500, -0.0021972656250000, 0.0024719238281250, +-0.0017700195312500, 0.0025634765625000, -0.0021972656250000, 0.0026855468750000, +-0.0020141601562500, 0.0026245117187500, -0.0015258789062500, 0.0025939941406250, +-0.0021362304687500, 0.0027160644531250, -0.0015869140625000, 0.0028076171875000, +-0.0015869140625000, 0.0027770996093750, -0.0016174316406250, 0.0027160644531250, +-0.0013122558593750, 0.0028076171875000, -0.0014343261718750, 0.0031127929687500, +-0.0017089843750000, 0.0028381347656250, -0.0014038085937500, 0.0032043457031250, +-0.0013732910156250, 0.0037536621093750, -0.0015258789062500, 0.0034790039062500, +-0.0012817382812500, 0.0040893554687500, -0.0012512207031250, 0.0042724609375000, +-0.0012512207031250, 0.0042419433593750, -0.0011901855468750, 0.0043945312500000, +-0.0011596679687500, 0.0044555664062500, -0.0013122558593750, 0.0043945312500000, +-0.0016174316406250, 0.0044250488281250, -0.0014343261718750, 0.0042724609375000, +-0.0018310546875000, 0.0041198730468750, -0.0023498535156250, 0.0041809082031250, +-0.0020751953125000, 0.0035705566406250, -0.0032958984375000, 0.0035400390625000, +-0.0032043457031250, 0.0034484863281250, -0.0033569335937500, 0.0030212402343750, +-0.0042114257812500, 0.0030212402343750, -0.0039062500000000, 0.0028381347656250, +-0.0039062500000000, 0.0028686523437500, -0.0045471191406250, 0.0026245117187500, +-0.0039978027343750, 0.0023498535156250, -0.0035400390625000, 0.0024414062500000, +-0.0044555664062500, 0.0019226074218750, -0.0024108886718750, 0.0018615722656250, +-0.0031433105468750, 0.0019226074218750, -0.0024414062500000, 0.0017700195312500, +-0.0006103515625000, 0.0016479492187500, -0.0018920898437500, 0.0015869140625000, +0.0000915527343750, 0.0018310546875000, 0.0000610351562500, 0.0011901855468750, +-0.0003051757812500, 0.0007934570312500, 0.0006103515625000, 0.0012207031250000, +0.0002136230468750, -0.0003356933593750, -0.0011596679687500, -0.0002136230468750, +-0.0005493164062500, -0.0004577636718750, -0.0014953613281250, -0.0015563964843750, +-0.0033264160156250, -0.0011596679687500, -0.0025329589843750, -0.0018310546875000, +-0.0040283203125000, -0.0020141601562500, -0.0043945312500000, -0.0019226074218750, +-0.0039978027343750, -0.0022277832031250, -0.0044555664062500, -0.0020446777343750, +-0.0045776367187500, -0.0017395019531250, -0.0028381347656250, -0.0020141601562500, +-0.0034179687500000, -0.0014038085937500, -0.0026855468750000, -0.0006408691406250, +-0.0009460449218750, -0.0011901855468750, -0.0015869140625000, -0.0009765625000000, +-0.0004577636718750, -0.0003356933593750, 0.0001220703125000, -0.0012512207031250, +0.0000000000000000, -0.0022277832031250, 0.0001831054687500, -0.0017395019531250, +0.0004272460937500, -0.0028991699218750, -0.0000610351562500, -0.0032348632812500, +0.0000000000000000, -0.0029602050781250, -0.0000305175781250, -0.0034484863281250, +-0.0004882812500000, -0.0037536621093750, -0.0003967285156250, -0.0018920898437500, +0.0001831054687500, -0.0021362304687500, -0.0002136230468750, -0.0022277832031250, +0.0000915527343750, -0.0011596679687500, 0.0010681152343750, -0.0014038085937500, +0.0006713867187500, -0.0010375976562500, 0.0003051757812500, -0.0016174316406250, +0.0011901855468750, -0.0002746582031250, -0.0007324218750000, 0.0008239746093750, +-0.0022888183593750, -0.0003356933593750, -0.0004882812500000, 0.0037536621093750, +-0.0050048828125000, 0.0029296875000000, -0.0053405761718750, 0.0045471191406250, +-0.0044250488281250, 0.0083923339843750, -0.0065917968750000, 0.0063476562500000, +-0.0064086914062500, 0.0075683593750000, -0.0011596679687500, 0.0093383789062500, +-0.0030212402343750, 0.0075378417968750, -0.0007019042968750, 0.0058593750000000, +0.0050048828125000, 0.0072021484375000, 0.0025939941406250, 0.0039062500000000, +0.0049743652343750, 0.0042114257812500, 0.0064086914062500, 0.0041503906250000, +0.0052795410156250, 0.0012512207031250, 0.0044250488281250, -0.0013427734375000, +0.0020141601562500, -0.0021057128906250, 0.0036315917968750, -0.0020751953125000, +0.0046691894531250, -0.0016479492187500, 0.0037231445312500, -0.0016479492187500, +0.0022583007812500, -0.0020751953125000, 0.0028686523437500, -0.0018920898437500, +0.0044250488281250, -0.0010070800781250, 0.0035400390625000, -0.0021972656250000, +0.0044250488281250, -0.0035400390625000, 0.0067749023437500, -0.0025024414062500, +0.0059204101562500, -0.0044250488281250, 0.0056152343750000, -0.0051574707031250, +0.0068359375000000, -0.0034790039062500, 0.0056457519531250, -0.0034484863281250, +0.0036315917968750, -0.0047302246093750, 0.0046997070312500, -0.0002746582031250, +0.0042724609375000, -0.0006713867187500, 0.0033874511718750, -0.0006408691406250, +0.0042419433593750, 0.0022583007812500, 0.0053710937500000, 0.0013122558593750, +0.0046691894531250, -0.0005493164062500, 0.0047912597656250, 0.0010070800781250, +0.0058593750000000, -0.0007629394531250, 0.0038757324218750, -0.0040283203125000, +0.0019531250000000, -0.0022277832031250, 0.0034790039062500, -0.0037231445312500, +0.0002441406250000, -0.0050048828125000, -0.0003051757812500, -0.0034790039062500, +0.0001831054687500, -0.0025634765625000, -0.0007934570312500, -0.0035705566406250, +-0.0008850097656250, -0.0001831054687500, -0.0005187988281250, -0.0003967285156250, +-0.0002441406250000, -0.0004272460937500, -0.0005187988281250, 0.0016174316406250, +-0.0007629394531250, 0.0011596679687500, -0.0005493164062500, 0.0000915527343750, +-0.0006408691406250, 0.0007019042968750, -0.0008850097656250, 0.0000305175781250, +-0.0007324218750000, -0.0011291503906250, -0.0003662109375000, -0.0003356933593750, +-0.0005798339843750, -0.0016479492187500, -0.0008850097656250, -0.0018005371093750, +-0.0004882812500000, -0.0009155273437500, -0.0010986328125000, -0.0011596679687500, +-0.0019531250000000, -0.0013732910156250, -0.0013122558593750, 0.0010681152343750, +-0.0018310546875000, 0.0007934570312500, -0.0023803710937500, 0.0006103515625000, +-0.0016784667968750, 0.0022277832031250, -0.0010070800781250, 0.0021972656250000, +-0.0016174316406250, 0.0003356933593750, -0.0009765625000000, 0.0014343261718750, +-0.0007019042968750, 0.0003051757812500, -0.0009460449218750, -0.0018310546875000, +-0.0011291503906250, -0.0004577636718750, -0.0010681152343750, -0.0033874511718750, +-0.0007019042968750, -0.0031433105468750, -0.0010070800781250, -0.0035400390625000, +-0.0006713867187500, -0.0053100585937500, -0.0001220703125000, -0.0040588378906250, +-0.0003662109375000, -0.0053405761718750, 0.0000000000000000, -0.0056457519531250, +0.0000305175781250, -0.0048217773437500, 0.0001220703125000, -0.0048522949218750, +0.0003356933593750, -0.0049133300781250, 0.0002746582031250, -0.0036315917968750, +0.0009765625000000, -0.0037536621093750, 0.0008239746093750, -0.0034790039062500, +0.0010681152343750, -0.0025634765625000, 0.0017700195312500, -0.0028381347656250, +0.0014648437500000, -0.0024108886718750, 0.0017700195312500, -0.0021667480468750, +0.0018615722656250, -0.0023803710937500, 0.0018615722656250, -0.0024414062500000, +0.0019226074218750, -0.0022888183593750, 0.0018920898437500, -0.0029296875000000, +0.0022277832031250, -0.0027160644531250, 0.0020751953125000, -0.0029602050781250, +0.0023803710937500, -0.0035095214843750, 0.0027465820312500, -0.0031433105468750, +0.0025939941406250, -0.0038452148437500, 0.0032958984375000, -0.0036010742187500, +0.0032348632812500}, +{-0.0010681152343750, -0.0014648437500000, -0.0034484863281250, -0.0023193359375000, +-0.0018615722656250, -0.0026855468750000, 0.0017700195312500, -0.0017395019531250, +0.0007324218750000, -0.0038452148437500, 0.0003967285156250, -0.0043029785156250, +0.0010375976562500, -0.0033264160156250, 0.0011291503906250, -0.0038146972656250, +0.0003356933593750, -0.0042419433593750, 0.0003967285156250, -0.0010986328125000, +0.0028076171875000, -0.0018310546875000, 0.0021057128906250, -0.0019226074218750, +0.0026245117187500, 0.0004272460937500, 0.0051574707031250, -0.0002136230468750, +0.0045471191406250, -0.0020446777343750, 0.0032653808593750, -0.0011291503906250, +0.0040893554687500, -0.0020141601562500, 0.0032653808593750, -0.0042419433593750, +0.0014343261718750, -0.0032043457031250, 0.0022888183593750, -0.0026855468750000, +0.0021362304687500, -0.0040283203125000, 0.0013427734375000, -0.0025329589843750, +0.0023803710937500, -0.0003662109375000, 0.0037536621093750, -0.0017395019531250, +0.0028686523437500, 0.0001220703125000, 0.0028991699218750, 0.0007934570312500, +0.0039062500000000, -0.0000305175781250, 0.0025329589843750, 0.0000000000000000, +0.0008850097656250, 0.0003662109375000, 0.0019226074218750, -0.0006103515625000, +0.0000915527343750, -0.0006103515625000, -0.0005187988281250, -0.0002746582031250, +0.0001525878906250, -0.0007629394531250, 0.0002136230468750, -0.0009460449218750, +0.0000000000000000, 0.0003967285156250, 0.0001220703125000, 0.0003051757812500, +0.0004272460937500, 0.0002746582031250, 0.0001831054687500, 0.0010070800781250, +-0.0002746582031250, 0.0009155273437500, -0.0000915527343750, 0.0008544921875000, +-0.0000610351562500, 0.0012512207031250, -0.0003051757812500, 0.0004577636718750, +-0.0001525878906250, 0.0001831054687500, 0.0003662109375000, 0.0010375976562500, +0.0002136230468750, -0.0023803710937500, -0.0006103515625000, -0.0015869140625000, +-0.0001220703125000, -0.0023803710937500, -0.0005798339843750, -0.0052490234375000, +-0.0018005371093750, -0.0038452148437500, -0.0013122558593750, -0.0048522949218750, +-0.0010375976562500, -0.0053710937500000, -0.0015869140625000, -0.0046997070312500, +-0.0011291503906250, -0.0045166015625000, -0.0003356933593750, -0.0047912597656250, +-0.0006713867187500, -0.0038452148437500, -0.0005493164062500, -0.0037231445312500, +-0.0004272460937500, -0.0036621093750000, -0.0004577636718750, -0.0031433105468750, +-0.0005798339843750, -0.0031433105468750, -0.0005798339843750, -0.0032348632812500, +-0.0001831054687500, -0.0028991699218750, -0.0003051757812500, -0.0034179687500000, +-0.0001831054687500, -0.0039367675781250, 0.0002136230468750, -0.0033264160156250, +0.0001220703125000, -0.0046997070312500, 0.0002136230468750, -0.0044555664062500, +0.0002136230468750, -0.0046997070312500, 0.0004272460937500, -0.0055847167968750, +0.0006103515625000, -0.0050659179687500, 0.0004272460937500, -0.0054626464843750, +0.0012512207031250, -0.0058288574218750, 0.0011596679687500, -0.0053100585937500, +0.0013122558593750, -0.0052490234375000, 0.0018920898437500, -0.0056762695312500, +0.0017395019531250, -0.0043029785156250, 0.0020751953125000, -0.0049743652343750, +0.0020141601562500, -0.0044250488281250, 0.0022583007812500, -0.0032653808593750, +0.0025939941406250, -0.0044250488281250, 0.0024414062500000, -0.0024414062500000, +0.0029602050781250, -0.0030212402343750, 0.0029602050781250, -0.0025634765625000, +0.0030212402343750, -0.0010986328125000, 0.0033569335937500, -0.0020446777343750, +0.0032348632812500, -0.0005187988281250, 0.0034484863281250, -0.0008850097656250, +0.0035705566406250, -0.0008544921875000, 0.0033874511718750, 0.0000000000000000, +0.0034179687500000, -0.0008544921875000, 0.0035400390625000, -0.0002441406250000, +0.0031127929687500, -0.0004577636718750, 0.0030822753906250, -0.0006103515625000, +0.0030822753906250, -0.0003356933593750, 0.0028076171875000, -0.0008544921875000, +0.0029296875000000, -0.0005187988281250, 0.0029602050781250, -0.0007934570312500, +0.0029296875000000, -0.0009460449218750, 0.0029602050781250, -0.0007629394531250, +0.0031127929687500, -0.0011596679687500, 0.0029907226562500, -0.0010681152343750, +0.0028991699218750, -0.0012512207031250, 0.0028991699218750, -0.0014953613281250, +0.0029602050781250, -0.0015869140625000, 0.0027160644531250, -0.0018615722656250, +0.0026550292968750, -0.0021972656250000, 0.0031738281250000, -0.0021667480468750, +0.0028991699218750, -0.0026245117187500, 0.0031127929687500, -0.0031433105468750, +0.0036621093750000, -0.0028991699218750, 0.0033874511718750, -0.0032653808593750, +0.0036621093750000, -0.0033874511718750, 0.0039367675781250, -0.0033874511718750, +0.0032653808593750, -0.0036315917968750, 0.0029907226562500, -0.0038146972656250, +0.0035705566406250, -0.0034484863281250, 0.0014038085937500, -0.0039062500000000, +0.0018920898437500, -0.0035400390625000, 0.0014343261718750, -0.0030212402343750, +-0.0002441406250000, -0.0037231445312500, 0.0005493164062500, -0.0023498535156250, +-0.0001831054687500, -0.0024414062500000, -0.0006713867187500, -0.0021667480468750, +0.0000915527343750, -0.0011596679687500, 0.0003662109375000, -0.0016174316406250, +-0.0000915527343750, -0.0011596679687500, 0.0012207031250000, -0.0005798339843750, +0.0011901855468750, -0.0012512207031250, 0.0012817382812500, -0.0015258789062500, +0.0019836425781250, -0.0009155273437500, 0.0017089843750000, -0.0028076171875000, +0.0021057128906250, -0.0024719238281250, 0.0021667480468750, -0.0031127929687500, +0.0021667480468750, -0.0046691894531250, 0.0025024414062500, -0.0039062500000000, +0.0023498535156250, -0.0053405761718750, 0.0017395019531250, -0.0059204101562500, +0.0023498535156250, -0.0053100585937500, 0.0014953613281250, -0.0053710937500000, +0.0002746582031250, -0.0057373046875000, 0.0010375976562500, -0.0041503906250000, +-0.0010070800781250, -0.0041809082031250, -0.0007629394531250, -0.0036010742187500, +-0.0012512207031250, -0.0022583007812500, -0.0028076171875000, -0.0026550292968750, +-0.0020446777343750, -0.0017089843750000, -0.0028686523437500, -0.0012512207031250, +-0.0034484863281250, -0.0017395019531250, -0.0023498535156250, -0.0017395019531250, +-0.0017395019531250, -0.0013427734375000, -0.0025634765625000, -0.0028381347656250, +-0.0005187988281250, -0.0027160644531250, -0.0003662109375000, -0.0025024414062500, +-0.0007324218750000, -0.0034484863281250, -0.0000305175781250, -0.0032348632812500, +-0.0000305175781250, -0.0015258789062500, -0.0005798339843750, -0.0021972656250000, +-0.0002136230468750, -0.0010681152343750, -0.0013122558593750, 0.0009765625000000, +-0.0023498535156250, -0.0001525878906250, -0.0011901855468750, 0.0007934570312500, +-0.0033874511718750, 0.0015258789062500, -0.0041198730468750, 0.0005493164062500, +-0.0029602050781250, -0.0002746582031250, -0.0028991699218750, 0.0002441406250000, +-0.0035705566406250, -0.0005493164062500, -0.0014953613281250, -0.0008239746093750, +-0.0014953613281250, -0.0006408691406250, -0.0014648437500000, -0.0006408691406250, +-0.0003967285156250, -0.0006713867187500, -0.0007629394531250, -0.0006713867187500, +-0.0008850097656250, -0.0004577636718750, -0.0004272460937500, -0.0009155273437500, +-0.0008850097656250, -0.0013122558593750, -0.0014648437500000, -0.0008239746093750, +-0.0011291503906250, -0.0016174316406250, -0.0027770996093750, -0.0017089843750000, +-0.0028381347656250, -0.0016784667968750, -0.0018920898437500, -0.0021362304687500, +-0.0019836425781250, -0.0019836425781250, -0.0018005371093750, -0.0008544921875000, +0.0007629394531250, -0.0012207031250000, -0.0002136230468750, -0.0012207031250000, +0.0003356933593750, -0.0004272460937500, 0.0025634765625000, -0.0006103515625000, +0.0014343261718750, -0.0001525878906250, 0.0020446777343750, -0.0001831054687500, +0.0028381347656250, -0.0005187988281250, 0.0018615722656250, -0.0001831054687500, +0.0009765625000000, 0.0000305175781250, 0.0016784667968750, -0.0010986328125000, +0.0002441406250000, -0.0007324218750000, -0.0001525878906250, -0.0012207031250000, +0.0002441406250000, -0.0022888183593750, -0.0001220703125000, -0.0016784667968750, +-0.0003662109375000, -0.0026855468750000, 0.0005187988281250, -0.0028381347656250, +0.0003051757812500, -0.0025634765625000, 0.0002441406250000, -0.0028991699218750, +0.0008239746093750, -0.0028381347656250, 0.0004882812500000, -0.0015869140625000, +-0.0000610351562500, -0.0018920898437500, 0.0001220703125000, -0.0016479492187500, +-0.0002746582031250, -0.0006103515625000, -0.0007934570312500, -0.0008850097656250, +-0.0004882812500000, -0.0007629394531250, -0.0013732910156250, -0.0007629394531250, +-0.0011291503906250, -0.0004272460937500, -0.0013732910156250, -0.0000305175781250, +-0.0023803710937500, -0.0003662109375000, -0.0021362304687500, -0.0003662109375000, +-0.0021667480468750, 0.0002136230468750, -0.0030822753906250, -0.0005493164062500, +-0.0024108886718750, -0.0012817382812500, -0.0018005371093750, -0.0006103515625000, +-0.0030212402343750, -0.0029602050781250, -0.0008239746093750, -0.0026245117187500, +-0.0011291503906250, -0.0028076171875000, -0.0010986328125000, -0.0043029785156250, +0.0003967285156250, -0.0037231445312500, -0.0001525878906250, -0.0039672851562500, +-0.0007629394531250, -0.0043334960937500, -0.0002746582031250, -0.0038452148437500, +-0.0011291503906250, -0.0034790039062500, -0.0025939941406250, -0.0037231445312500, +-0.0021972656250000, -0.0025634765625000, -0.0033569335937500, -0.0029296875000000, +-0.0042114257812500, -0.0022277832031250, -0.0037841796875000, -0.0010375976562500, +-0.0036926269531250, -0.0017089843750000, -0.0044860839843750, 0.0000000000000000, +-0.0034179687500000, -0.0002136230468750, -0.0031433105468750, -0.0001220703125000, +-0.0036315917968750, 0.0010986328125000, -0.0032043457031250, 0.0006408691406250, +-0.0026855468750000, 0.0004882812500000, -0.0044555664062500, 0.0007324218750000, +-0.0034484863281250, 0.0005187988281250, -0.0042724609375000, 0.0000305175781250, +-0.0058898925781250, 0.0002136230468750, -0.0042419433593750, 0.0003662109375000, +-0.0069580078125000, 0.0002441406250000, -0.0062866210937500, 0.0001831054687500, +-0.0062255859375000, 0.0005798339843750, -0.0077514648437500, 0.0007934570312500, +-0.0064392089843750, -0.0004272460937500, -0.0070800781250000, -0.0000305175781250, +-0.0070495605468750, -0.0000305175781250, -0.0064697265625000, -0.0010681152343750, +-0.0060729980468750, -0.0007019042968750, -0.0054016113281250, -0.0000610351562500, +-0.0049438476562500, -0.0005798339843750, -0.0046081542968750, 0.0001831054687500, +-0.0039672851562500, 0.0013122558593750, -0.0032958984375000, 0.0005493164062500, +-0.0029602050781250, 0.0022583007812500, -0.0024414062500000, 0.0021972656250000, +-0.0022277832031250, 0.0025634765625000, -0.0017089843750000, 0.0036315917968750, +-0.0010375976562500, 0.0031433105468750, -0.0010681152343750, 0.0039672851562500, +-0.0008544921875000, 0.0041198730468750, -0.0003662109375000, 0.0038757324218750, +-0.0003662109375000, 0.0039978027343750, -0.0004272460937500, 0.0040588378906250, +-0.0000915527343750, 0.0038146972656250, -0.0006408691406250, 0.0037231445312500, +-0.0001220703125000, 0.0037841796875000, -0.0000915527343750, 0.0038452148437500, +-0.0005187988281250, 0.0037536621093750, 0.0002136230468750, 0.0036926269531250, +0.0001831054687500, 0.0038452148437500, 0.0004272460937500, 0.0036926269531250, +0.0005798339843750, 0.0036010742187500, 0.0007934570312500, 0.0037231445312500, +0.0013122558593750, 0.0032043457031250, 0.0010375976562500, 0.0034484863281250, +0.0014038085937500, 0.0031127929687500, 0.0014648437500000, 0.0025329589843750, +0.0012207031250000}, +{-0.0003051757812500, -0.0018005371093750, -0.0002746582031250, -0.0008544921875000, +-0.0001525878906250, -0.0026855468750000, -0.0015869140625000, -0.0031433105468750, +-0.0012817382812500, -0.0020751953125000, -0.0020141601562500, -0.0021362304687500, +-0.0035095214843750, -0.0027465820312500, -0.0028381347656250, -0.0006713867187500, +-0.0033874511718750, -0.0005187988281250, -0.0046386718750000, -0.0008544921875000, +-0.0032653808593750, -0.0001220703125000, -0.0022888183593750, -0.0000610351562500, +-0.0041809082031250, -0.0000915527343750, -0.0006408691406250, 0.0001220703125000, +-0.0008239746093750, 0.0000000000000000, -0.0013427734375000, -0.0001220703125000, +0.0004882812500000, 0.0001831054687500, 0.0002136230468750, -0.0004882812500000, +-0.0008239746093750, 0.0000000000000000, 0.0002441406250000, -0.0007324218750000, +-0.0007629394531250, -0.0018005371093750, -0.0026245117187500, -0.0010375976562500, +-0.0015258789062500, -0.0025939941406250, -0.0029907226562500, -0.0025024414062500, +-0.0036010742187500, -0.0024414062500000, -0.0029296875000000, -0.0032043457031250, +-0.0028686523437500, -0.0028381347656250, -0.0032043457031250, -0.0031433105468750, +-0.0022583007812500, -0.0030212402343750, -0.0017395019531250, -0.0028991699218750, +-0.0022888183593750, -0.0030822753906250, -0.0019226074218750, -0.0029602050781250, +-0.0010681152343750, -0.0029296875000000, -0.0036621093750000, -0.0029296875000000, +-0.0023193359375000, -0.0024719238281250, -0.0030212402343750, -0.0022888183593750, +-0.0052490234375000, -0.0026245117187500, -0.0031433105468750, -0.0011291503906250, +-0.0052490234375000, -0.0014343261718750, -0.0045776367187500, -0.0011596679687500, +-0.0039978027343750, -0.0000915527343750, -0.0047607421875000, -0.0006408691406250, +-0.0034179687500000, 0.0000000000000000, -0.0035095214843750, -0.0000915527343750, +-0.0029907226562500, 0.0001220703125000, -0.0024414062500000, 0.0006408691406250, +-0.0021972656250000, 0.0000915527343750, -0.0016784667968750, 0.0007629394531250, +-0.0016479492187500, 0.0010681152343750, -0.0014343261718750, 0.0005187988281250, +-0.0014343261718750, 0.0003356933593750, -0.0016174316406250, 0.0008544921875000, +-0.0013427734375000, 0.0000305175781250, -0.0017700195312500, -0.0000915527343750, +-0.0019226074218750, 0.0003662109375000, -0.0020751953125000, 0.0002441406250000, +-0.0025329589843750, 0.0000610351562500, -0.0025939941406250, 0.0012817382812500, +-0.0026245117187500, 0.0009765625000000, -0.0031127929687500, 0.0013122558593750, +-0.0032958984375000, 0.0022888183593750, -0.0032348632812500, 0.0018005371093750, +-0.0034790039062500, 0.0026245117187500, -0.0036010742187500, 0.0025024414062500, +-0.0036315917968750, 0.0026550292968750, -0.0036315917968750, 0.0032348632812500, +-0.0038146972656250, 0.0028381347656250, -0.0040893554687500, 0.0034179687500000, +-0.0039367675781250, 0.0033874511718750, -0.0039978027343750, 0.0034790039062500, +-0.0037231445312500, 0.0037536621093750, -0.0034179687500000, 0.0035400390625000, +-0.0037231445312500, 0.0036926269531250, -0.0032958984375000, 0.0038452148437500, +-0.0034790039062500, 0.0034790039062500, -0.0035400390625000, 0.0032653808593750, +-0.0034484863281250, 0.0034790039062500, -0.0038452148437500, 0.0024719238281250, +-0.0034484863281250, 0.0026245117187500, -0.0039367675781250, 0.0021667480468750, +-0.0039978027343750, 0.0013122558593750, -0.0036621093750000, 0.0017395019531250, +-0.0042724609375000, 0.0005798339843750, -0.0035400390625000, 0.0004272460937500, +-0.0042114257812500, 0.0004882812500000, -0.0038452148437500, -0.0000915527343750, +-0.0030517578125000, -0.0000610351562500, -0.0041198730468750, -0.0000610351562500, +-0.0025024414062500, -0.0000610351562500, -0.0025024414062500, -0.0003356933593750, +-0.0021972656250000, -0.0005493164062500, -0.0010681152343750, -0.0003967285156250, +-0.0012207031250000, -0.0007934570312500, -0.0004272460937500, -0.0010375976562500, +-0.0001525878906250, -0.0009155273437500, 0.0001525878906250, -0.0009765625000000, +0.0007934570312500, -0.0010681152343750, 0.0007934570312500, -0.0007019042968750, +0.0007629394531250, -0.0008544921875000, 0.0014038085937500, -0.0006103515625000, +0.0003967285156250, -0.0002441406250000, -0.0003356933593750, -0.0005187988281250, +0.0006103515625000, 0.0006103515625000, -0.0026855468750000, 0.0004577636718750, +-0.0016784667968750, 0.0005493164062500, -0.0025024414062500, 0.0013732910156250, +-0.0051574707031250, 0.0010986328125000, -0.0033874511718750, 0.0009155273437500, +-0.0054931640625000, 0.0013122558593750, -0.0056762695312500, 0.0008850097656250, +-0.0049743652343750, 0.0004577636718750, -0.0056152343750000, 0.0009460449218750, +-0.0054626464843750, -0.0002136230468750, -0.0046691894531250, 0.0001220703125000, +-0.0045471191406250, -0.0002441406250000, -0.0043945312500000, -0.0013122558593750, +-0.0038146972656250, -0.0006408691406250, -0.0034484863281250, -0.0013122558593750, +-0.0035400390625000, -0.0015869140625000, -0.0028686523437500, -0.0012207031250000, +-0.0035095214843750, -0.0011901855468750, -0.0041198730468750, -0.0013122558593750, +-0.0030822753906250, -0.0009155273437500, -0.0050354003906250, -0.0011596679687500, +-0.0051879882812500, -0.0009460449218750, -0.0043029785156250, -0.0006408691406250, +-0.0052490234375000, -0.0009155273437500, -0.0055541992187500, 0.0001831054687500, +-0.0017089843750000, -0.0002746582031250, -0.0026855468750000, 0.0006408691406250, +-0.0012512207031250, 0.0021972656250000, 0.0023193359375000, 0.0012207031250000, +0.0003967285156250, 0.0024414062500000, 0.0017700195312500, 0.0031127929687500, +0.0028381347656250, 0.0022277832031250, 0.0005798339843750, 0.0019226074218750, +-0.0004882812500000, 0.0023803710937500, 0.0008850097656250, 0.0002136230468750, +-0.0040893554687500, 0.0007934570312500, -0.0035400390625000, -0.0002441406250000, +-0.0034790039062500, -0.0024414062500000, -0.0066223144531250, -0.0011291503906250, +-0.0055541992187500, -0.0025329589843750, -0.0043029785156250, -0.0033264160156250, +-0.0056762695312500, -0.0028381347656250, -0.0037231445312500, -0.0023193359375000, +-0.0009460449218750, -0.0025329589843750, -0.0026245117187500, -0.0039367675781250, +0.0003051757812500, -0.0033874511718750, 0.0009765625000000, -0.0036926269531250, +-0.0001831054687500, -0.0049133300781250, 0.0002746582031250, -0.0044555664062500, +0.0006408691406250, -0.0046691894531250, -0.0018615722656250, -0.0050659179687500, +-0.0017395019531250, -0.0042419433593750, -0.0013732910156250, -0.0035705566406250, +-0.0025024414062500, -0.0041809082031250, -0.0022888183593750, -0.0030212402343750, +-0.0014038085937500, -0.0025939941406250, -0.0014953613281250, -0.0030212402343750, +-0.0019836425781250, -0.0030517578125000, -0.0017700195312500, -0.0041809082031250, +-0.0040283203125000, -0.0035095214843750, -0.0012207031250000, -0.0038146972656250, +-0.0013732910156250, -0.0038146972656250, -0.0026245117187500, -0.0034179687500000, +-0.0023803710937500, -0.0036315917968750, -0.0014953613281250, -0.0043640136718750, +-0.0049743652343750, -0.0046691894531250, -0.0051574707031250, -0.0039978027343750, +-0.0044555664062500, -0.0040893554687500, -0.0059509277343750, -0.0046691894531250, +-0.0060729980468750, -0.0015869140625000, -0.0030822753906250, -0.0023498535156250, +-0.0037231445312500, -0.0012817382812500, -0.0033569335937500, 0.0019226074218750, +-0.0011291503906250, 0.0006103515625000, -0.0017700195312500, 0.0005493164062500, +-0.0009765625000000, 0.0021057128906250, -0.0010070800781250, 0.0001220703125000, +-0.0007934570312500, -0.0021362304687500, -0.0003967285156250, -0.0003051757812500, +-0.0006408691406250, -0.0030517578125000, 0.0006408691406250, -0.0040893554687500, +0.0003051757812500, -0.0019836425781250, 0.0003051757812500, -0.0015258789062500, +0.0015258789062500, -0.0027465820312500, 0.0013122558593750, 0.0014343261718750, +-0.0000305175781250, 0.0014953613281250, 0.0003051757812500, 0.0008239746093750, +0.0004882812500000, 0.0028991699218750, -0.0006103515625000, 0.0028076171875000, +-0.0006103515625000, -0.0004577636718750, 0.0012512207031250, 0.0009460449218750, +0.0007324218750000, -0.0003051757812500, 0.0011291503906250, -0.0036621093750000, +0.0027770996093750, -0.0018005371093750, 0.0022277832031250, -0.0027160644531250, +0.0020751953125000, -0.0035400390625000, 0.0024414062500000, -0.0028381347656250, +0.0021362304687500, -0.0021972656250000, 0.0016784667968750, -0.0024414062500000, +0.0018920898437500, -0.0020141601562500, 0.0016174316406250, -0.0017395019531250, +0.0016174316406250, -0.0021972656250000, 0.0012817382812500, -0.0021057128906250, +0.0010681152343750, -0.0016784667968750, 0.0013122558593750, -0.0038452148437500, +0.0001220703125000, -0.0029602050781250, 0.0001220703125000, -0.0037231445312500, +0.0002136230468750, -0.0060424804687500, -0.0004577636718750, -0.0046997070312500, +-0.0004272460937500, -0.0053100585937500, -0.0000305175781250, -0.0061645507812500, +-0.0000305175781250, -0.0049133300781250, -0.0003051757812500, -0.0041809082031250, +-0.0002136230468750, -0.0050354003906250, -0.0000305175781250, -0.0014343261718750, +-0.0007019042968750, -0.0024108886718750, -0.0007629394531250, -0.0009460449218750, +-0.0005798339843750, 0.0020446777343750, -0.0007629394531250, -0.0000610351562500, +-0.0008850097656250, 0.0041809082031250, -0.0002136230468750, 0.0039367675781250, +-0.0003356933593750, 0.0036621093750000, -0.0003662109375000, 0.0058593750000000, +0.0000610351562500, 0.0047912597656250, 0.0000305175781250, 0.0043029785156250, +-0.0002441406250000, 0.0049133300781250, -0.0002746582031250, 0.0036315917968750, +-0.0001220703125000, 0.0023803710937500, -0.0001525878906250, 0.0032043457031250, +-0.0003051757812500, 0.0001220703125000, -0.0000610351562500, 0.0005493164062500, +0.0000305175781250, -0.0003967285156250, -0.0000610351562500, -0.0026550292968750, +-0.0001220703125000, -0.0012817382812500, -0.0000305175781250, -0.0037231445312500, +0.0003967285156250, -0.0035095214843750, 0.0000610351562500, -0.0035705566406250, +0.0005187988281250, -0.0050048828125000, 0.0013122558593750, -0.0043334960937500, +0.0009155273437500, -0.0052490234375000, 0.0013732910156250, -0.0054626464843750, +0.0016479492187500, -0.0053710937500000, 0.0015869140625000, -0.0057983398437500, +0.0015869140625000, -0.0059509277343750, 0.0016479492187500, -0.0057067871093750, +0.0020751953125000, -0.0060424804687500, 0.0019226074218750, -0.0058288574218750, +0.0022277832031250, -0.0056457519531250, 0.0027465820312500, -0.0062561035156250, +0.0025634765625000, -0.0054016113281250, 0.0031433105468750, -0.0058593750000000, +0.0032043457031250, -0.0057373046875000, 0.0033569335937500, -0.0051269531250000, +0.0037536621093750, -0.0058898925781250, 0.0036315917968750, -0.0050964355468750, +0.0038146972656250, -0.0053710937500000, 0.0039062500000000, -0.0055236816406250, +0.0039367675781250, -0.0051574707031250, 0.0039062500000000, -0.0057373046875000, +0.0038452148437500, -0.0055847167968750, 0.0040283203125000, -0.0058898925781250, +0.0039978027343750, -0.0061950683593750, 0.0038452148437500, -0.0063171386718750, +0.0039672851562500, -0.0066833496093750, 0.0040588378906250, -0.0067749023437500, +0.0032653808593750, -0.0069885253906250, 0.0036926269531250, -0.0071411132812500, +0.0030212402343750, -0.0071105957031250, 0.0020446777343750, -0.0073547363281250, +0.0027770996093750, -0.0076904296875000, 0.0012207031250000, -0.0074768066406250, +0.0013122558593750, -0.0070800781250000, 0.0012512207031250, -0.0069885253906250, +0.0003967285156250, -0.0068054199218750, 0.0007324218750000, -0.0056762695312500, +0.0003356933593750}, +{0.0009460449218750, -0.0018310546875000, 0.0013427734375000, -0.0007324218750000, +0.0012817382812500, -0.0020446777343750, 0.0012512207031250, -0.0039978027343750, +0.0014648437500000, -0.0026550292968750, 0.0015258789062500, -0.0053100585937500, +0.0015258789062500, -0.0053710937500000, 0.0015869140625000, -0.0050048828125000, +0.0016479492187500, -0.0063781738281250, 0.0016784667968750, -0.0059509277343750, +0.0016174316406250, -0.0039978027343750, 0.0014648437500000, -0.0054016113281250, +0.0017395019531250, -0.0032958984375000, 0.0011901855468750, -0.0003662109375000, +0.0005798339843750, -0.0025939941406250, 0.0010375976562500, 0.0016174316406250, +-0.0000915527343750, 0.0015563964843750, -0.0002746582031250, 0.0015563964843750, +-0.0000610351562500, 0.0037231445312500, -0.0003662109375000, 0.0027770996093750, +-0.0004577636718750, 0.0035400390625000, -0.0001525878906250, 0.0037231445312500, +-0.0001220703125000, 0.0030212402343750, -0.0003662109375000, 0.0030212402343750, +-0.0004272460937500, 0.0031433105468750, -0.0002746582031250, 0.0010070800781250, +-0.0009460449218750, 0.0014648437500000, -0.0010070800781250, 0.0007934570312500, +-0.0008850097656250, -0.0009765625000000, -0.0011901855468750, -0.0001525878906250, +-0.0011291503906250, -0.0013732910156250, -0.0008544921875000, -0.0016174316406250, +-0.0008850097656250, -0.0013427734375000, -0.0008544921875000, -0.0017700195312500, +-0.0007324218750000, -0.0018615722656250, -0.0007324218750000, -0.0011596679687500, +-0.0006408691406250, -0.0014343261718750, -0.0007629394531250, -0.0011901855468750, +-0.0005798339843750, -0.0006103515625000, -0.0003051757812500, -0.0009765625000000, +-0.0004577636718750, -0.0003051757812500, -0.0003967285156250, -0.0003967285156250, +-0.0002746582031250, -0.0003662109375000, -0.0003051757812500, -0.0000610351562500, +-0.0004272460937500, -0.0003356933593750, -0.0004272460937500, 0.0000000000000000, +0.0001831054687500, -0.0000610351562500, -0.0000610351562500, -0.0003051757812500, +0.0003356933593750, -0.0003051757812500, 0.0010986328125000, -0.0004272460937500, +0.0007934570312500, -0.0008239746093750, 0.0013732910156250, -0.0006713867187500, +0.0014648437500000, -0.0009765625000000, 0.0015869140625000, -0.0014038085937500, +0.0018920898437500, -0.0010681152343750, 0.0018005371093750, -0.0018310546875000, +0.0021667480468750, -0.0016784667968750, 0.0021667480468750, -0.0017089843750000, +0.0023193359375000, -0.0021362304687500, 0.0025329589843750, -0.0016784667968750, +0.0024719238281250, -0.0019531250000000, 0.0030517578125000, -0.0017700195312500, +0.0029602050781250, -0.0015869140625000, 0.0031127929687500, -0.0017089843750000, +0.0036926269531250, -0.0013732910156250, 0.0034790039062500, -0.0015258789062500, +0.0034790039062500, -0.0013732910156250, 0.0039062500000000, -0.0012817382812500, +0.0033264160156250, -0.0013427734375000, 0.0028381347656250, -0.0011291503906250, +0.0033874511718750, -0.0013732910156250, 0.0019226074218750, -0.0012207031250000, +0.0020751953125000, -0.0014038085937500, 0.0020141601562500, -0.0016784667968750, +0.0011901855468750, -0.0014953613281250, 0.0015869140625000, -0.0022888183593750, +0.0009765625000000, -0.0020751953125000, 0.0009460449218750, -0.0027160644531250, +0.0010986328125000, -0.0034179687500000, 0.0007324218750000, -0.0028991699218750, +0.0007934570312500, -0.0046997070312500, 0.0010070800781250, -0.0042419433593750, +0.0010681152343750, -0.0046997070312500, 0.0007324218750000, -0.0062255859375000, +0.0008239746093750, -0.0054626464843750, 0.0011291503906250, -0.0067138671875000, +-0.0001220703125000, -0.0070190429687500, 0.0002441406250000, -0.0068054199218750, +-0.0004272460937500, -0.0072326660156250, -0.0015563964843750, -0.0072937011718750, +-0.0006408691406250, -0.0062255859375000, -0.0025329589843750, -0.0068054199218750, +-0.0024719238281250, -0.0058593750000000, -0.0024414062500000, -0.0044555664062500, +-0.0033569335937500, -0.0054321289062500, -0.0030212402343750, -0.0026855468750000, +-0.0030822753906250, -0.0030517578125000, -0.0030822753906250, -0.0020141601562500, +-0.0030822753906250, 0.0001831054687500, -0.0030517578125000, -0.0010375976562500, +-0.0029907226562500, 0.0013427734375000, -0.0030822753906250, 0.0014953613281250, +-0.0032043457031250, 0.0012512207031250, -0.0027770996093750, 0.0022277832031250, +-0.0024719238281250, 0.0018615722656250, -0.0028076171875000, 0.0012817382812500, +-0.0015869140625000, 0.0018310546875000, -0.0015258789062500, 0.0011596679687500, +-0.0018005371093750, 0.0001831054687500, -0.0012512207031250, 0.0009460449218750, +-0.0012207031250000, -0.0002441406250000, -0.0024108886718750, -0.0003662109375000, +-0.0021362304687500, -0.0001831054687500, -0.0021667480468750, -0.0005798339843750, +-0.0031433105468750, -0.0005493164062500, -0.0029602050781250, -0.0003967285156250, +-0.0024108886718750, -0.0000610351562500, -0.0024108886718750, -0.0008239746093750, +-0.0029296875000000, -0.0012207031250000, -0.0030517578125000, -0.0003051757812500, +-0.0026245117187500, -0.0025024414062500, -0.0026550292968750, -0.0024108886718750, +-0.0031127929687500, -0.0024108886718750, -0.0025634765625000, -0.0037841796875000, +-0.0019836425781250, -0.0035705566406250, -0.0023803710937500, -0.0033874511718750, +-0.0011901855468750, -0.0036926269531250, -0.0011596679687500, -0.0029602050781250, +-0.0007324218750000, -0.0021667480468750, 0.0001831054687500, -0.0026855468750000, +-0.0002136230468750, -0.0014953613281250, 0.0006408691406250, -0.0010681152343750, +0.0009155273437500, -0.0015563964843750, 0.0005493164062500, -0.0015869140625000, +0.0006408691406250, -0.0012512207031250, 0.0010375976562500, -0.0015869140625000, +0.0000915527343750, -0.0019531250000000, 0.0001525878906250, -0.0015563964843750, +-0.0001220703125000, -0.0011596679687500, -0.0004882812500000, -0.0014343261718750, +0.0002136230468750, -0.0008239746093750, -0.0007629394531250, -0.0007629394531250, +-0.0011596679687500, -0.0007934570312500, -0.0006408691406250, -0.0006103515625000, +-0.0003356933593750, -0.0006713867187500, -0.0005187988281250, -0.0002746582031250, +-0.0006408691406250, -0.0001525878906250, -0.0006713867187500, -0.0008544921875000, +-0.0006103515625000, -0.0007629394531250, -0.0006103515625000, -0.0002441406250000, +-0.0007629394531250, -0.0027160644531250, -0.0005493164062500, -0.0023193359375000, +-0.0010070800781250, -0.0024719238281250, -0.0010375976562500, -0.0042419433593750, +-0.0006713867187500, -0.0034179687500000, -0.0011596679687500, -0.0028686523437500, +-0.0015563964843750, -0.0036926269531250, -0.0012512207031250, -0.0025939941406250, +-0.0018920898437500, -0.0009155273437500, -0.0028381347656250, -0.0017700195312500, +-0.0023498535156250, -0.0008850097656250, -0.0033874511718750, -0.0005493164062500, +-0.0037841796875000, -0.0005493164062500, -0.0033569335937500, -0.0004882812500000, +-0.0037231445312500, -0.0005187988281250, -0.0043029785156250, 0.0006103515625000, +-0.0022583007812500, 0.0005493164062500, -0.0029602050781250, 0.0001831054687500, +-0.0029296875000000, 0.0010986328125000, -0.0012817382812500, 0.0014648437500000, +-0.0018615722656250, -0.0007934570312500, -0.0021057128906250, 0.0001220703125000, +-0.0008850097656250, -0.0003356933593750, -0.0014343261718750, -0.0024414062500000, +-0.0024108886718750, -0.0014953613281250, -0.0008850097656250, -0.0018615722656250, +-0.0013427734375000, -0.0023498535156250, -0.0013122558593750, -0.0014343261718750, +-0.0008239746093750, -0.0007629394531250, -0.0006713867187500, -0.0013732910156250, +-0.0004577636718750, -0.0001831054687500, -0.0002441406250000, 0.0004577636718750, +0.0002746582031250, -0.0001220703125000, -0.0000305175781250, -0.0001220703125000, +-0.0000915527343750, 0.0003356933593750, 0.0009460449218750, -0.0011291503906250, +-0.0007324218750000, -0.0007324218750000, 0.0003051757812500, -0.0008850097656250, +0.0001220703125000, -0.0019531250000000, -0.0009765625000000, -0.0016174316406250, +0.0007019042968750, -0.0022583007812500, -0.0009460449218750, -0.0022277832031250, +0.0000000000000000, -0.0022888183593750, 0.0000305175781250, -0.0027160644531250, +-0.0010681152343750, -0.0025939941406250, 0.0003662109375000, -0.0029602050781250, +-0.0015563964843750, -0.0029602050781250, -0.0011291503906250, -0.0028991699218750, +-0.0014648437500000, -0.0031433105468750, -0.0029907226562500, -0.0031127929687500, +-0.0023193359375000, -0.0029907226562500, -0.0034790039062500, -0.0031127929687500, +-0.0039367675781250, -0.0028991699218750, -0.0039062500000000, -0.0026855468750000, +-0.0044250488281250, -0.0028381347656250, -0.0046997070312500, -0.0020446777343750, +-0.0043334960937500, -0.0023193359375000, -0.0049438476562500, -0.0018005371093750, +-0.0046081542968750, -0.0009460449218750, -0.0041198730468750, -0.0016174316406250, +-0.0047607421875000, -0.0003662109375000, -0.0033874511718750, -0.0005493164062500, +-0.0037536621093750, -0.0003662109375000, -0.0037841796875000, 0.0003662109375000, +-0.0029907226562500, -0.0003662109375000, -0.0034179687500000, 0.0007324218750000, +-0.0028991699218750, 0.0006408691406250, -0.0030822753906250, 0.0004577636718750, +-0.0031738281250000, 0.0009155273437500, -0.0031433105468750, 0.0007019042968750, +-0.0036010742187500, 0.0005798339843750, -0.0031433105468750, 0.0007019042968750, +-0.0032958984375000, 0.0005798339843750, -0.0032958984375000, 0.0003662109375000, +-0.0029907226562500, 0.0005798339843750, -0.0033569335937500, 0.0007629394531250, +-0.0031127929687500, 0.0005493164062500, -0.0029907226562500, 0.0008544921875000, +-0.0030212402343750, 0.0013732910156250, -0.0029907226562500, 0.0010986328125000, +-0.0029907226562500, 0.0014648437500000, -0.0027465820312500, 0.0016174316406250, +-0.0032958984375000, 0.0014038085937500, -0.0030212402343750, 0.0014343261718750, +-0.0025939941406250, 0.0015563964843750, -0.0033264160156250, 0.0007934570312500, +-0.0022888183593750, 0.0009460449218750, -0.0026550292968750, 0.0007629394531250, +-0.0025939941406250, 0.0002136230468750, -0.0020141601562500, 0.0003967285156250, +-0.0027160644531250, 0.0001525878906250, -0.0019226074218750, 0.0001220703125000, +-0.0022583007812500, -0.0001220703125000, -0.0022277832031250, -0.0002746582031250, +-0.0017089843750000, -0.0001220703125000, -0.0021972656250000, -0.0010681152343750, +-0.0016479492187500, -0.0009765625000000, -0.0017395019531250, -0.0011291503906250, +-0.0017395019531250, -0.0017700195312500, -0.0014343261718750, -0.0014343261718750, +-0.0016479492187500, -0.0018005371093750, -0.0010375976562500, -0.0017395019531250, +-0.0014953613281250, -0.0017395019531250, -0.0013122558593750, -0.0019836425781250, +-0.0006713867187500, -0.0018005371093750, -0.0013427734375000, -0.0016784667968750, +-0.0009155273437500, -0.0019531250000000, -0.0006408691406250, -0.0016174316406250, +-0.0013122558593750, -0.0012512207031250, -0.0014038085937500, -0.0016174316406250, +-0.0008544921875000, -0.0011901855468750, -0.0029602050781250, -0.0011596679687500, +-0.0020751953125000, -0.0014038085937500, -0.0025634765625000, -0.0014648437500000, +-0.0043640136718750, -0.0014953613281250, -0.0028991699218750, -0.0018310546875000, +-0.0042114257812500, -0.0018920898437500, -0.0043945312500000, -0.0020446777343750, +-0.0033874511718750, -0.0022277832031250, -0.0036315917968750, -0.0022277832031250, +-0.0040893554687500, -0.0028686523437500, -0.0016479492187500, -0.0028381347656250, +-0.0024108886718750, -0.0028076171875000, -0.0014343261718750, -0.0033569335937500, +0.0008544921875000, -0.0034484863281250, -0.0003662109375000, -0.0021057128906250, +0.0014648437500000, -0.0029296875000000, 0.0019531250000000, -0.0023498535156250, +0.0012817382812500}, +{-0.0059204101562500, -0.0022583007812500, -0.0052185058593750, -0.0015869140625000, +-0.0046386718750000, -0.0021362304687500, -0.0059204101562500, -0.0014038085937500, +-0.0038452148437500, -0.0017089843750000, -0.0044250488281250, -0.0015563964843750, +-0.0043334960937500, -0.0009155273437500, -0.0029907226562500, -0.0014343261718750, +-0.0040283203125000, -0.0010070800781250, -0.0030212402343750, -0.0008850097656250, +-0.0031433105468750, -0.0012207031250000, -0.0031738281250000, -0.0014038085937500, +-0.0025329589843750, -0.0013732910156250, -0.0028991699218750, -0.0015563964843750, +-0.0031127929687500, -0.0018310546875000, -0.0029602050781250, -0.0015869140625000, +-0.0031433105468750, -0.0014953613281250, -0.0036315917968750, -0.0018920898437500, +-0.0036621093750000, -0.0005493164062500, -0.0037841796875000, -0.0010375976562500, +-0.0035095214843750, -0.0007324218750000, -0.0034179687500000, 0.0004882812500000, +-0.0034179687500000, -0.0002441406250000, -0.0028686523437500, 0.0005493164062500, +-0.0028991699218750, 0.0007019042968750, -0.0026550292968750, 0.0004272460937500, +-0.0023193359375000, 0.0006103515625000, -0.0021972656250000, 0.0007324218750000, +-0.0022888183593750, 0.0000610351562500, -0.0020751953125000, 0.0002441406250000, +-0.0017700195312500, 0.0000305175781250, -0.0013732910156250, -0.0005798339843750, +-0.0014343261718750, -0.0002136230468750, -0.0017089843750000, -0.0006713867187500, +-0.0008239746093750, -0.0007629394531250, -0.0013427734375000, -0.0005798339843750, +-0.0010681152343750, -0.0006408691406250, -0.0001831054687500, -0.0006713867187500, +-0.0011596679687500, -0.0003356933593750, -0.0003356933593750, -0.0003967285156250, +-0.0003662109375000, -0.0003967285156250, -0.0005493164062500, -0.0001525878906250, +-0.0001525878906250, -0.0002136230468750, -0.0001220703125000, -0.0004882812500000, +-0.0001831054687500, -0.0003662109375000, 0.0001525878906250, -0.0003967285156250, +-0.0000305175781250, -0.0006713867187500, 0.0000000000000000, -0.0005798339843750, +0.0006103515625000, -0.0006408691406250, -0.0004577636718750, -0.0006713867187500, +0.0003356933593750, -0.0006713867187500, 0.0001525878906250, -0.0007019042968750, +-0.0007324218750000, -0.0006408691406250, 0.0004882812500000, -0.0009155273437500, +-0.0008239746093750, -0.0008850097656250, -0.0006408691406250, -0.0010986328125000, +-0.0004577636718750, -0.0014648437500000, -0.0013427734375000, -0.0013122558593750, +-0.0011596679687500, -0.0018005371093750, -0.0010070800781250, -0.0018005371093750, +-0.0015869140625000, -0.0019836425781250, -0.0011596679687500, -0.0023193359375000, +-0.0006408691406250, -0.0021362304687500, -0.0012512207031250, -0.0028381347656250, +-0.0000915527343750, -0.0028076171875000, -0.0000915527343750, -0.0030212402343750, +-0.0002746582031250, -0.0034179687500000, 0.0003967285156250, -0.0032348632812500, +0.0004272460937500, -0.0037841796875000, -0.0001831054687500, -0.0039062500000000, +0.0005493164062500, -0.0037536621093750, 0.0000305175781250, -0.0041503906250000, +-0.0008850097656250, -0.0041198730468750, 0.0000305175781250, -0.0029602050781250, +-0.0018310546875000, -0.0035705566406250, -0.0018005371093750, -0.0024719238281250, +-0.0018920898437500, -0.0006713867187500, -0.0030822753906250, -0.0016784667968750, +-0.0027465820312500, 0.0002441406250000, -0.0026245117187500, 0.0004272460937500, +-0.0032958984375000, 0.0001220703125000, -0.0024719238281250, 0.0006713867187500, +-0.0017700195312500, 0.0003662109375000, -0.0026855468750000, 0.0003356933593750, +-0.0002441406250000, 0.0000610351562500, -0.0007629394531250, 0.0001220703125000, +-0.0004882812500000, 0.0003356933593750, 0.0012512207031250, 0.0000000000000000, +0.0000610351562500, 0.0000305175781250, -0.0000915527343750, 0.0002746582031250, +0.0007324218750000, -0.0001220703125000, -0.0011901855468750, -0.0007629394531250, +-0.0028686523437500, -0.0004272460937500, -0.0015563964843750, -0.0002746582031250, +-0.0053710937500000, -0.0009765625000000, -0.0048522949218750, -0.0003051757812500, +-0.0045471191406250, 0.0006713867187500, -0.0066223144531250, -0.0000305175781250, +-0.0057067871093750, 0.0009155273437500, -0.0049133300781250, 0.0010986328125000, +-0.0054626464843750, 0.0008239746093750, -0.0041809082031250, 0.0009460449218750, +-0.0027160644531250, 0.0008544921875000, -0.0033569335937500, 0.0005187988281250, +-0.0005798339843750, 0.0007934570312500, -0.0005798339843750, 0.0000305175781250, +-0.0007629394531250, -0.0008544921875000, 0.0005187988281250, -0.0002136230468750, +0.0002746582031250, -0.0009155273437500, 0.0001525878906250, -0.0012512207031250, +0.0008544921875000, -0.0014648437500000, -0.0001831054687500, -0.0014038085937500, +-0.0010986328125000, -0.0010986328125000, 0.0000000000000000, -0.0023193359375000, +-0.0027160644531250, -0.0022583007812500, -0.0025634765625000, -0.0026245117187500, +-0.0024719238281250, -0.0033569335937500, -0.0036621093750000, -0.0029296875000000, +-0.0032348632812500, -0.0041198730468750, -0.0044250488281250, -0.0040588378906250, +-0.0039672851562500, -0.0042419433593750, -0.0045166015625000, -0.0051574707031250, +-0.0059814453125000, -0.0048217773437500, -0.0051879882812500, -0.0051879882812500, +-0.0050048828125000, -0.0055541992187500, -0.0057983398437500, -0.0047912597656250, +-0.0046081542968750, -0.0037231445312500, -0.0020141601562500, -0.0010681152343750, +-0.0045166015625000, -0.0012817382812500, -0.0049133300781250, -0.0002746582031250, +-0.0059204101562500, -0.0016784667968750, -0.0045471191406250, -0.0031433105468750, +-0.0030517578125000, -0.0017089843750000, -0.0039367675781250, -0.0025329589843750, +-0.0028686523437500, -0.0036621093750000, -0.0021667480468750, -0.0023498535156250, +-0.0031127929687500, -0.0010986328125000, -0.0037231445312500, -0.0019836425781250, +-0.0030517578125000, -0.0005798339843750, -0.0039062500000000, 0.0000610351562500, +-0.0046691894531250, -0.0009155273437500, -0.0034484863281250, -0.0011596679687500, +-0.0026245117187500, -0.0002746582031250, -0.0036010742187500, -0.0017089843750000, +-0.0016174316406250, -0.0021362304687500, -0.0013122558593750, -0.0007629394531250, +-0.0019226074218750, -0.0004882812500000, -0.0014343261718750, -0.0012512207031250, +-0.0010681152343750, 0.0014953613281250, -0.0016784667968750, 0.0020141601562500, +-0.0023803710937500, 0.0005187988281250, -0.0007019042968750, 0.0009460449218750, +0.0005187988281250, 0.0018005371093750, -0.0007629394531250, -0.0028991699218750, +0.0019226074218750, -0.0021972656250000, 0.0024719238281250, -0.0030822753906250, +0.0018310546875000, -0.0069274902343750, 0.0023498535156250, -0.0057678222656250, +0.0025024414062500, -0.0055847167968750, 0.0015258789062500, -0.0075378417968750, +0.0015563964843750, -0.0052490234375000, 0.0017700195312500, -0.0027770996093750, +0.0014038085937500, -0.0050964355468750, 0.0013427734375000, -0.0005187988281250, +0.0020751953125000, -0.0003967285156250, 0.0019531250000000, -0.0005187988281250, +0.0018615722656250, 0.0015869140625000, 0.0024414062500000, 0.0006103515625000, +0.0024414062500000, 0.0008850097656250, 0.0012207031250000, 0.0012512207031250, +0.0014343261718750, 0.0004577636718750, 0.0013122558593750, -0.0001831054687500, +0.0003662109375000, 0.0003356933593750, 0.0005798339843750, -0.0004577636718750, +0.0010375976562500, -0.0012817382812500, 0.0008239746093750, -0.0000610351562500, +0.0010681152343750, 0.0005493164062500, 0.0015869140625000, -0.0007629394531250, +0.0013427734375000, 0.0021972656250000, 0.0016174316406250, 0.0017395019531250, +0.0016174316406250, 0.0018920898437500, 0.0015258789062500, 0.0036621093750000, +0.0016479492187500, 0.0026245117187500, 0.0016479492187500, 0.0030822753906250, +0.0008850097656250, 0.0033569335937500, 0.0012512207031250, 0.0025634765625000, +0.0004577636718750, 0.0022888183593750, -0.0006103515625000, 0.0025634765625000, +0.0000000000000000, 0.0001220703125000, -0.0013427734375000, 0.0007934570312500, +-0.0014953613281250, -0.0002441406250000, -0.0014038085937500, -0.0024719238281250, +-0.0018920898437500, -0.0011291503906250, -0.0018005371093750, -0.0032958984375000, +-0.0018920898437500, -0.0032348632812500, -0.0019226074218750, -0.0031433105468750, +-0.0018920898437500, -0.0041198730468750, -0.0020141601562500, -0.0034790039062500, +-0.0020751953125000, -0.0039062500000000, -0.0016784667968750, -0.0038146972656250, +-0.0018005371093750, -0.0033874511718750, -0.0018005371093750, -0.0032653808593750, +-0.0015869140625000, -0.0029907226562500, -0.0016174316406250, -0.0026550292968750, +-0.0016479492187500, -0.0024108886718750, -0.0017700195312500, -0.0021057128906250, +-0.0015563964843750, -0.0018615722656250, -0.0013427734375000, -0.0016174316406250, +-0.0015563964843750, -0.0010375976562500, -0.0010375976562500, -0.0009765625000000, +-0.0009155273437500, -0.0007324218750000, -0.0009155273437500, -0.0003051757812500, +-0.0007019042968750, -0.0003356933593750, -0.0006408691406250, -0.0000610351562500, +-0.0003967285156250, 0.0000915527343750, -0.0005798339843750, 0.0000610351562500, +-0.0002746582031250, 0.0000610351562500, 0.0002136230468750, 0.0002746582031250, +-0.0000610351562500, 0.0000610351562500, 0.0005493164062500, 0.0001831054687500, +0.0007019042968750, 0.0001525878906250, 0.0005493164062500, -0.0000610351562500, +0.0007324218750000, 0.0001831054687500, 0.0008239746093750, -0.0000915527343750, +0.0005798339843750, 0.0000305175781250, 0.0006713867187500, 0.0000610351562500, +0.0007629394531250, -0.0000610351562500, 0.0006408691406250, 0.0002136230468750, +0.0007019042968750, -0.0000305175781250, 0.0010681152343750, 0.0001831054687500, +0.0010681152343750, 0.0001831054687500, 0.0010986328125000, 0.0000610351562500, +0.0014648437500000, 0.0003051757812500, 0.0014038085937500, 0.0001220703125000, +0.0011291503906250, 0.0002746582031250, 0.0013122558593750, 0.0000915527343750, +0.0011596679687500, -0.0000915527343750, 0.0008239746093750, 0.0000915527343750, +0.0010070800781250, -0.0012512207031250, 0.0005493164062500, -0.0007324218750000, +0.0008239746093750, -0.0013427734375000, 0.0002746582031250, -0.0024414062500000, +-0.0003967285156250, -0.0015563964843750, 0.0002746582031250, -0.0036926269531250, +-0.0011901855468750, -0.0033569335937500, -0.0010070800781250, -0.0036621093750000, +-0.0013427734375000, -0.0051269531250000, -0.0022888183593750, -0.0043334960937500, +-0.0016174316406250, -0.0052490234375000, -0.0025939941406250, -0.0052490234375000, +-0.0027770996093750, -0.0049743652343750, -0.0023498535156250, -0.0054016113281250, +-0.0024414062500000, -0.0052795410156250, -0.0025939941406250, -0.0049133300781250, +-0.0020751953125000, -0.0052795410156250, -0.0019531250000000, -0.0049743652343750, +-0.0019531250000000, -0.0045166015625000, -0.0017395019531250, -0.0051269531250000, +-0.0018310546875000, -0.0039978027343750, -0.0019226074218750, -0.0046691894531250, +-0.0017700195312500, -0.0045776367187500, -0.0018310546875000, -0.0036926269531250, +-0.0020446777343750, -0.0046691894531250, -0.0018615722656250, -0.0040283203125000, +-0.0016479492187500, -0.0039978027343750, -0.0017395019531250, -0.0043029785156250, +-0.0016479492187500, -0.0040588378906250, -0.0012817382812500, -0.0038757324218750, +-0.0014038085937500, -0.0039062500000000, -0.0019531250000000, -0.0040588378906250, +-0.0014953613281250, -0.0031738281250000, -0.0020751953125000, -0.0026855468750000, +-0.0030822753906250, -0.0034790039062500, -0.0024719238281250, -0.0015258789062500, +-0.0032958984375000, -0.0018310546875000, -0.0035400390625000, -0.0017089843750000, +-0.0032958984375000, -0.0003662109375000, -0.0036621093750000, -0.0010986328125000, +-0.0036315917968750}, +{-0.0013732910156250, -0.0011596679687500, -0.0014343261718750, -0.0018310546875000, +-0.0017089843750000, -0.0011901855468750, -0.0016174316406250, -0.0014038085937500, +-0.0015563964843750, -0.0019836425781250, -0.0018005371093750, -0.0009765625000000, +-0.0017395019531250, -0.0025939941406250, -0.0015563964843750, -0.0021972656250000, +-0.0014953613281250, -0.0023193359375000, -0.0015563964843750, -0.0034484863281250, +-0.0015258789062500, -0.0027465820312500, -0.0014953613281250, -0.0037231445312500, +-0.0014953613281250, -0.0037536621093750, -0.0015869140625000, -0.0038146972656250, +-0.0013122558593750, -0.0043334960937500, -0.0010681152343750, -0.0042419433593750, +-0.0012512207031250, -0.0044860839843750, -0.0007324218750000, -0.0046691894531250, +-0.0006408691406250, -0.0046386718750000, -0.0006408691406250, -0.0046997070312500, +-0.0003967285156250, -0.0049438476562500, -0.0003967285156250, -0.0048217773437500, +-0.0003356933593750, -0.0049743652343750, -0.0002746582031250, -0.0049438476562500, +-0.0002136230468750, -0.0049133300781250, -0.0001831054687500, -0.0051269531250000, +-0.0001525878906250, -0.0048522949218750, 0.0000000000000000, -0.0050659179687500, +0.0000000000000000, -0.0049743652343750, 0.0000305175781250, -0.0047607421875000, +0.0002441406250000, -0.0051879882812500, 0.0002136230468750, -0.0046386718750000, +0.0001525878906250, -0.0049438476562500, 0.0003356933593750, -0.0047912597656250, +0.0001831054687500, -0.0042724609375000, 0.0000610351562500, -0.0045776367187500, +0.0002746582031250, -0.0039672851562500, 0.0000915527343750, -0.0039978027343750, +0.0001831054687500, -0.0038452148437500, 0.0000305175781250, -0.0033874511718750, +0.0000000000000000, -0.0036010742187500, 0.0001831054687500, -0.0030822753906250, +-0.0006408691406250, -0.0031127929687500, -0.0003967285156250, -0.0029907226562500, +-0.0006103515625000, -0.0025634765625000, -0.0012512207031250, -0.0026550292968750, +-0.0008239746093750, -0.0025024414062500, -0.0017089843750000, -0.0022583007812500, +-0.0015258789062500, -0.0025939941406250, -0.0015563964843750, -0.0026245117187500, +-0.0022277832031250, -0.0021362304687500, -0.0019226074218750, -0.0031433105468750, +-0.0016174316406250, -0.0025329589843750, -0.0018005371093750, -0.0028991699218750, +-0.0016784667968750, -0.0037841796875000, -0.0013122558593750, -0.0028686523437500, +-0.0013732910156250, -0.0043640136718750, -0.0010375976562500, -0.0040893554687500, +-0.0010681152343750, -0.0040588378906250, -0.0012207031250000, -0.0051269531250000, +-0.0010681152343750, -0.0045776367187500, -0.0009155273437500, -0.0049438476562500, +-0.0014038085937500, -0.0054626464843750, -0.0014038085937500, -0.0049743652343750, +-0.0012512207031250, -0.0048828125000000, -0.0013732910156250, -0.0057373046875000, +-0.0014343261718750, -0.0038146972656250, -0.0013732910156250, -0.0044555664062500, +-0.0010986328125000, -0.0043640136718750, -0.0018615722656250, -0.0029602050781250, +-0.0024108886718750, -0.0038146972656250, -0.0016784667968750, -0.0032653808593750, +-0.0034179687500000, -0.0025634765625000, -0.0035400390625000, -0.0029602050781250, +-0.0030517578125000, -0.0031127929687500, -0.0035705566406250, -0.0022888183593750, +-0.0037536621093750, -0.0029907226562500, -0.0026245117187500, -0.0031127929687500, +-0.0030517578125000, -0.0029296875000000, -0.0021057128906250, -0.0032653808593750, +-0.0008239746093750, -0.0033874511718750, -0.0018615722656250, -0.0028076171875000, +-0.0000610351562500, -0.0032653808593750, 0.0004577636718750, -0.0027160644531250, +0.0000000000000000, -0.0017700195312500, 0.0003662109375000, -0.0024414062500000, +0.0006103515625000, -0.0015258789062500, 0.0001525878906250, -0.0016174316406250, +0.0003356933593750, -0.0017700195312500, 0.0000610351562500, -0.0011291503906250, +-0.0003967285156250, -0.0011901855468750, -0.0001220703125000, -0.0015258789062500, +-0.0015869140625000, -0.0007019042968750, -0.0012817382812500, -0.0010070800781250, +-0.0016479492187500, -0.0021057128906250, -0.0029602050781250, -0.0018615722656250, +-0.0023803710937500, -0.0027465820312500, -0.0020446777343750, -0.0025939941406250, +-0.0029296875000000, -0.0028686523437500, -0.0018005371093750, -0.0036621093750000, +-0.0003967285156250, -0.0033569335937500, -0.0012207031250000, -0.0034790039062500, +0.0009155273437500, -0.0036926269531250, 0.0012817382812500, -0.0032348632812500, +0.0002136230468750, -0.0029296875000000, 0.0005493164062500, -0.0031127929687500, +0.0013122558593750, -0.0021362304687500, -0.0003051757812500, -0.0023498535156250, +-0.0000610351562500, -0.0021667480468750, -0.0005798339843750, -0.0013427734375000, +-0.0019836425781250, -0.0015563964843750, -0.0013427734375000, -0.0013427734375000, +-0.0016784667968750, -0.0015563964843750, -0.0017700195312500, -0.0009460449218750, +-0.0013427734375000, -0.0005493164062500, -0.0011901855468750, -0.0012207031250000, +-0.0011596679687500, 0.0012207031250000, -0.0003356933593750, 0.0006408691406250, +-0.0003051757812500, 0.0007019042968750, -0.0010681152343750, 0.0025329589843750, +-0.0011291503906250, 0.0017700195312500, -0.0009765625000000, 0.0007629394531250, +-0.0030212402343750, 0.0013732910156250, -0.0030517578125000, 0.0009460449218750, +-0.0028381347656250, -0.0003662109375000, -0.0037536621093750, -0.0000915527343750, +-0.0034484863281250, -0.0006103515625000, -0.0024414062500000, -0.0005493164062500, +-0.0023803710937500, -0.0010681152343750, -0.0017395019531250, -0.0014038085937500, +-0.0006103515625000, -0.0009155273437500, -0.0007629394531250, -0.0031433105468750, +-0.0007934570312500, -0.0026855468750000, -0.0003967285156250, -0.0026855468750000, +-0.0006713867187500, -0.0042724609375000, -0.0013122558593750, -0.0036315917968750, +-0.0010986328125000, -0.0024414062500000, -0.0009155273437500, -0.0032348632812500, +-0.0006103515625000, -0.0022888183593750, -0.0004272460937500, -0.0006408691406250, +-0.0000610351562500, -0.0014953613281250, 0.0004882812500000, -0.0003051757812500, +-0.0007629394531250, -0.0002136230468750, 0.0003051757812500, -0.0004577636718750, +-0.0005187988281250, -0.0001220703125000, -0.0021972656250000, -0.0003967285156250, +-0.0008850097656250, -0.0001220703125000, -0.0033874511718750, -0.0001831054687500, +-0.0033569335937500, -0.0006103515625000, -0.0033569335937500, -0.0007629394531250, +-0.0050048828125000, -0.0007934570312500, -0.0048217773437500, -0.0009765625000000, +-0.0042724609375000, -0.0010681152343750, -0.0054626464843750, -0.0012207031250000, +-0.0048522949218750, -0.0013427734375000, -0.0038146972656250, -0.0012207031250000, +-0.0052795410156250, -0.0011901855468750, -0.0035400390625000, -0.0012817382812500, +-0.0040893554687500, -0.0012207031250000, -0.0043640136718750, -0.0011596679687500, +-0.0035400390625000, -0.0012817382812500, -0.0045166015625000, -0.0009155273437500, +-0.0039062500000000, -0.0010986328125000, -0.0042419433593750, -0.0010681152343750, +-0.0041198730468750, -0.0008239746093750, -0.0034484863281250, -0.0010986328125000, +-0.0039978027343750, -0.0003967285156250, -0.0032653808593750, -0.0008544921875000, +-0.0033874511718750, -0.0005798339843750, -0.0030822753906250, 0.0002441406250000, +-0.0025024414062500, -0.0004272460937500, -0.0030517578125000, 0.0002441406250000, +-0.0025939941406250, 0.0002746582031250, -0.0027465820312500, 0.0002136230468750, +-0.0031433105468750, 0.0003967285156250, -0.0032653808593750, 0.0001831054687500, +-0.0035400390625000, 0.0005187988281250, -0.0034484863281250, 0.0004272460937500, +-0.0039367675781250, 0.0002441406250000, -0.0041809082031250, 0.0003967285156250, +-0.0039367675781250, 0.0004272460937500, -0.0041503906250000, -0.0003662109375000, +-0.0043334960937500, -0.0001525878906250, -0.0044860839843750, -0.0005187988281250, +-0.0046691894531250, -0.0013427734375000, -0.0048522949218750, -0.0009765625000000, +-0.0050048828125000, -0.0014343261718750, -0.0050659179687500, -0.0016479492187500, +-0.0051574707031250, -0.0016479492187500, -0.0049743652343750, -0.0016174316406250, +-0.0048522949218750, -0.0016479492187500, -0.0050048828125000, -0.0018005371093750, +-0.0045776367187500, -0.0017089843750000, -0.0048828125000000, -0.0017089843750000, +-0.0048522949218750, -0.0018310546875000, -0.0043640136718750, -0.0017700195312500, +-0.0047912597656250, -0.0015869140625000, -0.0046386718750000, -0.0017089843750000, +-0.0043334960937500, -0.0015258789062500, -0.0047302246093750, -0.0013427734375000, +-0.0049133300781250, -0.0015563964843750, -0.0042419433593750, -0.0010681152343750, +-0.0048522949218750, -0.0011596679687500, -0.0045166015625000, -0.0010681152343750, +-0.0044250488281250, -0.0007019042968750, -0.0047607421875000, -0.0008544921875000, +-0.0042419433593750, -0.0004882812500000, -0.0044860839843750, -0.0004577636718750, +-0.0040588378906250, -0.0005493164062500, -0.0040283203125000, -0.0004272460937500, +-0.0042419433593750, -0.0004272460937500, -0.0036010742187500, -0.0005798339843750, +-0.0038757324218750, -0.0006408691406250, -0.0038757324218750, -0.0005798339843750, +-0.0036010742187500, -0.0005798339843750, -0.0036926269531250, -0.0007629394531250, +-0.0036926269531250, -0.0007324218750000, -0.0032348632812500, -0.0006713867187500, +-0.0035705566406250, -0.0008544921875000, -0.0034179687500000, -0.0010070800781250, +-0.0031127929687500, -0.0008850097656250, -0.0035400390625000, -0.0014038085937500, +-0.0025024414062500, -0.0012817382812500, -0.0030517578125000, -0.0015258789062500, +-0.0024414062500000, -0.0020141601562500, -0.0015869140625000, -0.0017395019531250, +-0.0027160644531250, -0.0019531250000000, -0.0006713867187500, -0.0022277832031250, +-0.0013427734375000, -0.0016479492187500, -0.0010681152343750, -0.0012512207031250, +0.0003356933593750, -0.0014953613281250, -0.0007019042968750, -0.0001525878906250, +0.0005493164062500, 0.0000000000000000, 0.0004577636718750, 0.0000610351562500, +0.0000610351562500, 0.0007934570312500, 0.0005493164062500, 0.0006713867187500, +0.0003662109375000, 0.0003051757812500, -0.0002441406250000, 0.0005798339843750, +0.0001220703125000, 0.0003051757812500, -0.0003051757812500, -0.0001831054687500, +-0.0009460449218750, 0.0001525878906250, -0.0001525878906250, -0.0001220703125000, +-0.0007934570312500, -0.0002746582031250, -0.0007629394531250, 0.0001831054687500, +-0.0003051757812500, 0.0004882812500000, -0.0000915527343750, 0.0004272460937500, +0.0001525878906250, 0.0010375976562500, 0.0000000000000000, 0.0012817382812500, +0.0005187988281250, 0.0013427734375000, 0.0002441406250000, 0.0015563964843750, +-0.0001220703125000, 0.0016479492187500, 0.0007019042968750, 0.0018005371093750, +-0.0010681152343750, 0.0019836425781250, -0.0008239746093750, 0.0016784667968750, +-0.0012817382812500, 0.0014953613281250, -0.0027770996093750, 0.0018310546875000, +-0.0024108886718750, 0.0008239746093750, -0.0030517578125000, 0.0007934570312500, +-0.0038452148437500, 0.0009765625000000, -0.0037841796875000, 0.0006713867187500, +-0.0035095214843750, 0.0007019042968750, -0.0037231445312500, 0.0003356933593750, +-0.0036010742187500, 0.0007019042968750, -0.0036010742187500, -0.0001831054687500, +-0.0035400390625000, -0.0010681152343750, -0.0034179687500000, -0.0003051757812500, +-0.0033569335937500, -0.0022277832031250, -0.0031127929687500, -0.0024108886718750, +-0.0031738281250000, -0.0022583007812500, -0.0030517578125000, -0.0028381347656250, +-0.0028381347656250, -0.0025329589843750, -0.0030517578125000, -0.0025634765625000, +-0.0027465820312500, -0.0025939941406250, -0.0027465820312500, -0.0026245117187500, +-0.0025329589843750, -0.0023803710937500, -0.0026245117187500, -0.0021972656250000, +-0.0028686523437500, -0.0034179687500000, -0.0007019042968750, -0.0031738281250000, +-0.0011901855468750}, +{-0.0018615722656250, -0.0013427734375000, -0.0013732910156250, -0.0013427734375000, +-0.0016784667968750, -0.0014648437500000, -0.0023193359375000, -0.0014038085937500, +-0.0013122558593750, -0.0012817382812500, -0.0020751953125000, -0.0014343261718750, +-0.0017395019531250, -0.0011901855468750, -0.0015258789062500, -0.0008544921875000, +-0.0018920898437500, -0.0011291503906250, -0.0013427734375000, -0.0006103515625000, +-0.0010986328125000, -0.0006103515625000, -0.0014038085937500, -0.0005493164062500, +-0.0008850097656250, -0.0002441406250000, -0.0005493164062500, -0.0004882812500000, +-0.0013732910156250, -0.0002136230468750, 0.0000915527343750, -0.0001831054687500, +-0.0004882812500000, -0.0003051757812500, -0.0005187988281250, -0.0002746582031250, +0.0005493164062500, -0.0002746582031250, -0.0001220703125000, -0.0003051757812500, +0.0002441406250000, -0.0003356933593750, 0.0006713867187500, -0.0003356933593750, +0.0003662109375000, -0.0002746582031250, 0.0003356933593750, -0.0002441406250000, +0.0008850097656250, -0.0003051757812500, -0.0003662109375000, -0.0003967285156250, +0.0003051757812500, -0.0001525878906250, -0.0002136230468750, -0.0000305175781250, +-0.0014648437500000, -0.0002136230468750, -0.0004577636718750, 0.0003967285156250, +-0.0022277832031250, 0.0003967285156250, -0.0025024414062500, 0.0004577636718750, +-0.0025329589843750, 0.0008544921875000, -0.0035400390625000, 0.0007324218750000, +-0.0036621093750000, 0.0007324218750000, -0.0032043457031250, 0.0009460449218750, +-0.0038757324218750, 0.0007019042968750, -0.0033569335937500, 0.0005187988281250, +-0.0025634765625000, 0.0006713867187500, -0.0032348632812500, 0.0000610351562500, +-0.0017395019531250, 0.0002136230468750, -0.0018615722656250, 0.0002136230468750, +-0.0019226074218750, -0.0002441406250000, -0.0009460449218750, 0.0001525878906250, +-0.0011901855468750, 0.0005493164062500, -0.0016174316406250, 0.0005187988281250, +-0.0009765625000000, 0.0007019042968750, -0.0010986328125000, 0.0012512207031250, +-0.0017395019531250, 0.0012817382812500, -0.0014343261718750, 0.0013122558593750, +-0.0017395019531250, 0.0014648437500000, -0.0018310546875000, 0.0014953613281250, +-0.0018310546875000, 0.0015869140625000, -0.0020446777343750, 0.0016784667968750, +-0.0020751953125000, 0.0009765625000000, -0.0017395019531250, 0.0013122558593750, +-0.0017089843750000, 0.0009460449218750, -0.0014648437500000, 0.0001220703125000, +-0.0010681152343750, 0.0005187988281250, -0.0011901855468750, -0.0003356933593750, +-0.0014648437500000, -0.0000305175781250, -0.0010986328125000, -0.0006103515625000, +-0.0018615722656250, -0.0014648437500000, -0.0028381347656250, -0.0006713867187500, +-0.0024719238281250, -0.0025329589843750, -0.0042724609375000, -0.0023803710937500, +-0.0039367675781250, -0.0022888183593750, -0.0041809082031250, -0.0035705566406250, +-0.0055236816406250, -0.0031433105468750, -0.0047607421875000, -0.0024108886718750, +-0.0048828125000000, -0.0025634765625000, -0.0051574707031250, -0.0021667480468750, +-0.0040893554687500, -0.0014343261718750, -0.0032958984375000, -0.0016784667968750, +-0.0038146972656250, -0.0011596679687500, -0.0015258789062500, -0.0007934570312500, +-0.0014953613281250, -0.0013427734375000, -0.0016784667968750, -0.0017395019531250, +-0.0004577636718750, -0.0013732910156250, -0.0005493164062500, -0.0018920898437500, +-0.0021057128906250, -0.0023803710937500, -0.0018920898437500, -0.0019531250000000, +-0.0019531250000000, -0.0014953613281250, -0.0031127929687500, -0.0019836425781250, +-0.0029296875000000, -0.0021972656250000, -0.0013427734375000, -0.0016174316406250, +-0.0017700195312500, -0.0023803710937500, -0.0015869140625000, -0.0034790039062500, +-0.0001831054687500, -0.0028686523437500, -0.0006103515625000, -0.0030822753906250, +-0.0011596679687500, -0.0036621093750000, -0.0005493164062500, -0.0031127929687500, +-0.0010070800781250, -0.0018920898437500, -0.0027160644531250, -0.0000610351562500, +-0.0011291503906250, -0.0009765625000000, -0.0014953613281250, -0.0008239746093750, +-0.0007019042968750, -0.0007324218750000, -0.0010375976562500, -0.0010070800781250, +-0.0019531250000000, -0.0012207031250000, -0.0017395019531250, -0.0003356933593750, +-0.0009765625000000, -0.0002136230468750, -0.0010986328125000, -0.0006408691406250, +-0.0014343261718750, -0.0006408691406250, -0.0008239746093750, -0.0004272460937500, +-0.0005187988281250, -0.0012512207031250, -0.0034484863281250, -0.0017089843750000, +-0.0025939941406250, -0.0010681152343750, -0.0031433105468750, -0.0009765625000000, +-0.0057983398437500, -0.0015869140625000, -0.0048217773437500, 0.0001831054687500, +-0.0043334960937500, 0.0005493164062500, -0.0051879882812500, -0.0002441406250000, +-0.0040283203125000, 0.0004882812500000, -0.0023193359375000, 0.0011291503906250, +-0.0032653808593750, -0.0022277832031250, -0.0025939941406250, -0.0007629394531250, +-0.0018310546875000, -0.0015563964843750, -0.0025939941406250, -0.0044555664062500, +-0.0034179687500000, -0.0023193359375000, -0.0028381347656250, -0.0036621093750000, +-0.0030822753906250, -0.0041198730468750, -0.0034484863281250, -0.0026550292968750, +-0.0025634765625000, -0.0022277832031250, -0.0018615722656250, -0.0027160644531250, +-0.0023498535156250, -0.0001831054687500, -0.0011291503906250, -0.0003356933593750, +-0.0007629394531250, -0.0005493164062500, -0.0011901855468750, 0.0008544921875000, +-0.0011596679687500, 0.0006713867187500, -0.0008544921875000, -0.0007324218750000, +-0.0010681152343750, -0.0002136230468750, -0.0015258789062500, -0.0006713867187500, +-0.0009765625000000, -0.0019226074218750, -0.0002136230468750, -0.0012207031250000, +-0.0007019042968750, -0.0026855468750000, -0.0002136230468750, -0.0025939941406250, +-0.0000305175781250, -0.0025634765625000, -0.0002136230468750, -0.0034484863281250, +-0.0005187988281250, -0.0031433105468750, -0.0004882812500000, -0.0027465820312500, +0.0002746582031250, -0.0028076171875000, 0.0000305175781250, -0.0030822753906250, +0.0001831054687500, -0.0027465820312500, 0.0009765625000000, -0.0023803710937500, +0.0007629394531250, -0.0038146972656250, 0.0002746582031250, -0.0035095214843750, +0.0005798339843750, -0.0037536621093750, 0.0003967285156250, -0.0050354003906250, +-0.0003051757812500, -0.0047607421875000, -0.0000305175781250, -0.0048828125000000, +0.0002746582031250, -0.0056152343750000, -0.0000610351562500, -0.0050964355468750, +0.0003051757812500, -0.0046081542968750, 0.0008850097656250, -0.0054931640625000, +0.0006103515625000, -0.0037841796875000, 0.0009460449218750, -0.0045166015625000, +0.0010070800781250, -0.0038146972656250, 0.0009155273437500, -0.0023193359375000, +0.0010070800781250, -0.0036926269531250, 0.0008850097656250, -0.0012512207031250, +0.0008544921875000, -0.0017089843750000, 0.0009155273437500, -0.0014038085937500, +0.0007019042968750, 0.0000305175781250, 0.0005493164062500, -0.0010681152343750, +0.0007019042968750, 0.0004882812500000, 0.0001831054687500, 0.0001831054687500, +0.0002746582031250, 0.0000305175781250, 0.0002441406250000, 0.0006103515625000, +-0.0001220703125000, -0.0000915527343750, 0.0000305175781250, 0.0004272460937500, +0.0000000000000000, 0.0001525878906250, -0.0000915527343750, -0.0000915527343750, +-0.0001525878906250, 0.0001831054687500, -0.0002136230468750, -0.0002746582031250, +-0.0001220703125000, -0.0008850097656250, -0.0003662109375000, -0.0004882812500000, +-0.0003051757812500, -0.0010986328125000, -0.0003051757812500, -0.0017700195312500, +-0.0004577636718750, -0.0010986328125000, -0.0003356933593750, -0.0022583007812500, +-0.0006408691406250, -0.0019531250000000, -0.0006408691406250, -0.0019531250000000, +-0.0005798339843750, -0.0025329589843750, -0.0007934570312500, -0.0021362304687500, +-0.0007629394531250, -0.0026550292968750, -0.0007629394531250, -0.0025634765625000, +-0.0007019042968750, -0.0026245117187500, -0.0007629394531250, -0.0028991699218750, +-0.0007934570312500, -0.0026245117187500, -0.0006103515625000, -0.0027770996093750, +-0.0010070800781250, -0.0026550292968750, -0.0008544921875000, -0.0025329589843750, +-0.0009765625000000, -0.0025939941406250, -0.0013122558593750, -0.0025939941406250, +-0.0010070800781250, -0.0025329589843750, -0.0014038085937500, -0.0025634765625000, +-0.0013122558593750, -0.0024719238281250, -0.0014343261718750, -0.0024414062500000, +-0.0016479492187500, -0.0025024414062500, -0.0014038085937500, -0.0022277832031250, +-0.0017395019531250, -0.0024108886718750, -0.0017395019531250, -0.0023498535156250, +-0.0016784667968750, -0.0020446777343750, -0.0018005371093750, -0.0022888183593750, +-0.0018005371093750, -0.0025329589843750, -0.0017700195312500, -0.0021972656250000, +-0.0019226074218750, -0.0022583007812500, -0.0014953613281250, -0.0023498535156250, +-0.0013122558593750, -0.0017700195312500, -0.0016174316406250, -0.0023193359375000, +-0.0003051757812500, -0.0017395019531250, -0.0005187988281250, -0.0018615722656250, +-0.0002746582031250, -0.0023193359375000, 0.0006103515625000, -0.0016784667968750, +0.0001525878906250, -0.0029602050781250, 0.0009155273437500, -0.0025634765625000, +0.0009155273437500, -0.0030517578125000, 0.0004882812500000, -0.0040893554687500, +0.0007324218750000, -0.0030822753906250, 0.0008850097656250, -0.0047302246093750, +0.0000610351562500, -0.0043029785156250, 0.0000610351562500, -0.0042724609375000, +0.0000915527343750, -0.0050964355468750, -0.0002136230468750, -0.0042724609375000, +-0.0001220703125000, -0.0048828125000000, -0.0008544921875000, -0.0045471191406250, +-0.0004882812500000, -0.0042724609375000, -0.0010986328125000, -0.0045166015625000, +-0.0021667480468750, -0.0040893554687500, -0.0015563964843750, -0.0040588378906250, +-0.0022888183593750, -0.0038452148437500, -0.0027465820312500, -0.0038757324218750, +-0.0021667480468750, -0.0040283203125000, -0.0018920898437500, -0.0038757324218750, +-0.0022277832031250, -0.0042419433593750, -0.0014038085937500, -0.0043945312500000, +-0.0014038085937500, -0.0042419433593750, -0.0011596679687500, -0.0044250488281250, +-0.0007019042968750, -0.0048217773437500, -0.0010986328125000, -0.0042724609375000, +-0.0002136230468750, -0.0042724609375000, 0.0000000000000000, -0.0043334960937500, +-0.0005187988281250, -0.0039062500000000, -0.0005187988281250, -0.0034790039062500, +-0.0002441406250000, -0.0025939941406250, -0.0013732910156250, -0.0024108886718750, +-0.0010986328125000, -0.0018615722656250, -0.0015258789062500, -0.0009155273437500, +-0.0027160644531250, -0.0010986328125000, -0.0021057128906250, -0.0017700195312500, +-0.0022583007812500, -0.0008239746093750, -0.0027465820312500, -0.0018615722656250, +-0.0021362304687500, -0.0034179687500000, -0.0014953613281250, -0.0020751953125000, +-0.0018310546875000, -0.0043640136718750, -0.0008239746093750, -0.0049438476562500, +-0.0009155273437500, -0.0043640136718750, -0.0005798339843750, -0.0045471191406250, +0.0002746582031250, -0.0038757324218750, -0.0000610351562500, -0.0029907226562500, +0.0003051757812500, -0.0035095214843750, 0.0003967285156250, -0.0032348632812500, +0.0000000000000000, -0.0021362304687500, -0.0000305175781250, -0.0024414062500000, +0.0003051757812500, -0.0025634765625000, -0.0007019042968750, -0.0025329589843750, +-0.0007324218750000, -0.0021057128906250, -0.0010070800781250, -0.0020751953125000, +-0.0015258789062500, -0.0024108886718750, -0.0009460449218750, -0.0006408691406250, +-0.0010375976562500, -0.0006103515625000, -0.0013122558593750, -0.0007934570312500, +-0.0011901855468750, 0.0003967285156250, -0.0008544921875000, 0.0007019042968750, +-0.0008544921875000, -0.0007324218750000, -0.0016784667968750, -0.0000610351562500, +-0.0014343261718750, -0.0000915527343750, -0.0021362304687500, -0.0012207031250000, +-0.0031738281250000}, +{-0.0019226074218750, 0.0009155273437500, -0.0019531250000000, 0.0012207031250000, +-0.0018310546875000, 0.0003662109375000, -0.0018920898437500, 0.0005493164062500, +-0.0018920898437500, 0.0001831054687500, -0.0018005371093750, -0.0005493164062500, +-0.0018615722656250, -0.0003051757812500, -0.0018005371093750, -0.0014648437500000, +-0.0012207031250000, -0.0012817382812500, -0.0015563964843750, -0.0017395019531250, +-0.0010375976562500, -0.0025939941406250, -0.0003051757812500, -0.0018920898437500, +-0.0008239746093750, -0.0031127929687500, 0.0002441406250000, -0.0027770996093750, +0.0001220703125000, -0.0025329589843750, 0.0003051757812500, -0.0031127929687500, +0.0011291503906250, -0.0027160644531250, 0.0005798339843750, -0.0025939941406250, +0.0007629394531250, -0.0026245117187500, 0.0010681152343750, -0.0024108886718750, +0.0007019042968750, -0.0021667480468750, 0.0004272460937500, -0.0022277832031250, +0.0005798339843750, -0.0022277832031250, 0.0004272460937500, -0.0018615722656250, +0.0004577636718750, -0.0021972656250000, 0.0001220703125000, -0.0024414062500000, +-0.0002441406250000, -0.0018920898437500, 0.0000915527343750, -0.0029296875000000, +-0.0007934570312500, -0.0025024414062500, -0.0008239746093750, -0.0027770996093750, +-0.0007934570312500, -0.0037231445312500, -0.0012207031250000, -0.0030517578125000, +-0.0012207031250000, -0.0039672851562500, -0.0010375976562500, -0.0042114257812500, +-0.0010986328125000, -0.0039978027343750, -0.0010986328125000, -0.0042724609375000, +-0.0010070800781250, -0.0044860839843750, -0.0010070800781250, -0.0041503906250000, +-0.0006713867187500, -0.0043640136718750, -0.0008544921875000, -0.0043640136718750, +-0.0007629394531250, -0.0042114257812500, -0.0000915527343750, -0.0045166015625000, +-0.0003356933593750, -0.0035400390625000, -0.0012512207031250, -0.0042419433593750, +-0.0007629394531250, -0.0041503906250000, -0.0011596679687500, -0.0030822753906250, +-0.0022583007812500, -0.0038452148437500, -0.0017395019531250, -0.0040893554687500, +-0.0022888183593750, -0.0036621093750000, -0.0026855468750000, -0.0033874511718750, +-0.0018615722656250, -0.0036315917968750, -0.0013732910156250, -0.0035095214843750, +-0.0020446777343750, -0.0022888183593750, -0.0007324218750000, -0.0027160644531250, +-0.0005187988281250, -0.0025634765625000, -0.0007324218750000, -0.0012207031250000, +-0.0004577636718750, -0.0015258789062500, -0.0003967285156250, -0.0024414062500000, +-0.0001831054687500, -0.0012817382812500, -0.0002746582031250, -0.0024108886718750, +-0.0002441406250000, -0.0041503906250000, 0.0000000000000000, -0.0023803710937500, +-0.0001525878906250, -0.0044860839843750, -0.0001525878906250, -0.0049133300781250, +0.0001220703125000, -0.0038146972656250, -0.0003356933593750, -0.0039367675781250, +-0.0007324218750000, -0.0043029785156250, -0.0003662109375000, -0.0027160644531250, +-0.0014038085937500, -0.0026550292968750, -0.0010986328125000, -0.0028381347656250, +-0.0010681152343750, -0.0025024414062500, -0.0017395019531250, -0.0024719238281250, +-0.0015563964843750, -0.0019531250000000, -0.0018615722656250, -0.0022583007812500, +-0.0013122558593750, -0.0016784667968750, -0.0016174316406250, -0.0003662109375000, +-0.0028991699218750, -0.0003051757812500, -0.0033874511718750, -0.0003662109375000, +-0.0038452148437500, 0.0002746582031250, -0.0035400390625000, -0.0003356933593750, +-0.0035705566406250, -0.0007324218750000, -0.0038757324218750, 0.0003662109375000, +-0.0035400390625000, -0.0018615722656250, -0.0033874511718750, -0.0015258789062500, +-0.0031738281250000, -0.0011596679687500, -0.0030822753906250, -0.0021362304687500, +-0.0028381347656250, -0.0015258789062500, -0.0023193359375000, -0.0010375976562500, +-0.0027770996093750, -0.0009765625000000, -0.0021057128906250, -0.0004882812500000, +-0.0025939941406250, 0.0000000000000000, -0.0033264160156250, -0.0002136230468750, +-0.0024414062500000, 0.0005493164062500, -0.0040588378906250, 0.0006713867187500, +-0.0041503906250000, 0.0007934570312500, -0.0037841796875000, 0.0012207031250000, +-0.0040283203125000, 0.0009460449218750, -0.0037231445312500, 0.0008544921875000, +-0.0039672851562500, 0.0012817382812500, -0.0037231445312500, 0.0008850097656250, +-0.0033874511718750, 0.0002136230468750, -0.0032958984375000, 0.0005187988281250, +-0.0031738281250000, -0.0002441406250000, -0.0032043457031250, -0.0003051757812500, +-0.0027160644531250, -0.0004882812500000, -0.0031738281250000, -0.0008850097656250, +-0.0037841796875000, -0.0006713867187500, -0.0033874511718750, -0.0018005371093750, +-0.0047302246093750, -0.0016174316406250, -0.0051269531250000, -0.0018920898437500, +-0.0050354003906250, -0.0028686523437500, -0.0056762695312500, -0.0023803710937500, +-0.0061340332031250, -0.0024108886718750, -0.0052795410156250, -0.0029602050781250, +-0.0058288574218750, -0.0023803710937500, -0.0054321289062500, -0.0016784667968750, +-0.0044555664062500, -0.0019836425781250, -0.0050354003906250, -0.0008850097656250, +-0.0039672851562500, -0.0010070800781250, -0.0038452148437500, -0.0010986328125000, +-0.0038757324218750, -0.0004882812500000, -0.0034484863281250, -0.0006103515625000, +-0.0035705566406250, -0.0004882812500000, -0.0030822753906250, -0.0008850097656250, +-0.0035095214843750, -0.0002746582031250, -0.0029907226562500, 0.0002746582031250, +-0.0023193359375000, -0.0004577636718750, -0.0029296875000000, 0.0011596679687500, +-0.0010986328125000, 0.0010070800781250, -0.0013122558593750, 0.0008850097656250, +-0.0010681152343750, 0.0019836425781250, 0.0000915527343750, 0.0017089843750000, +-0.0005187988281250, 0.0010986328125000, -0.0000305175781250, 0.0016479492187500, +-0.0001525878906250, 0.0011596679687500, -0.0003662109375000, 0.0002746582031250, +-0.0003967285156250, 0.0009765625000000, -0.0006713867187500, -0.0002746582031250, +-0.0006713867187500, -0.0000610351562500, -0.0010986328125000, -0.0002136230468750, +-0.0011596679687500, -0.0010681152343750, -0.0010681152343750, -0.0005798339843750, +-0.0016174316406250, -0.0008544921875000, -0.0011291503906250, -0.0010986328125000, +-0.0016174316406250, -0.0005798339843750, -0.0014343261718750, -0.0002746582031250, +-0.0009155273437500, -0.0005493164062500, -0.0014648437500000, 0.0004577636718750, +-0.0004882812500000, 0.0005493164062500, -0.0006713867187500, 0.0004577636718750, +-0.0005798339843750, 0.0010070800781250, 0.0000305175781250, 0.0010986328125000, +-0.0004882812500000, 0.0005187988281250, 0.0002136230468750, 0.0008239746093750, +0.0000000000000000, 0.0005798339843750, -0.0001525878906250, 0.0000000000000000, +0.0004577636718750, 0.0003662109375000, 0.0004577636718750, -0.0003662109375000, +-0.0001525878906250, -0.0002746582031250, 0.0004882812500000, -0.0003356933593750, +0.0004272460937500, -0.0008239746093750, 0.0000610351562500, -0.0005493164062500, +0.0010375976562500, -0.0007629394531250, 0.0007934570312500, -0.0008544921875000, +0.0008544921875000, -0.0008239746093750, 0.0011901855468750, -0.0008544921875000, +0.0011291503906250, -0.0008850097656250, 0.0010681152343750, -0.0008239746093750, +0.0014038085937500, -0.0007934570312500, 0.0013732910156250, -0.0007629394531250, +0.0012207031250000, -0.0007019042968750, 0.0014038085937500, -0.0006713867187500, +0.0014038085937500, -0.0004577636718750, 0.0009765625000000, -0.0005187988281250, +0.0012512207031250, -0.0002441406250000, 0.0011291503906250, 0.0001220703125000, +0.0008239746093750, -0.0000305175781250, 0.0013122558593750, 0.0005798339843750, +0.0007324218750000, 0.0006713867187500, 0.0010986328125000, 0.0008544921875000, +0.0007629394531250, 0.0012512207031250, 0.0002746582031250, 0.0012817382812500, +0.0008850097656250, 0.0018005371093750, -0.0007934570312500, 0.0016174316406250, +-0.0001525878906250, 0.0018615722656250, -0.0008239746093750, 0.0024414062500000, +-0.0021972656250000, 0.0020751953125000, -0.0009460449218750, 0.0025024414062500, +-0.0032958984375000, 0.0026245117187500, -0.0025634765625000, 0.0023193359375000, +-0.0027160644531250, 0.0022583007812500, -0.0043029785156250, 0.0023498535156250, +-0.0029296875000000, 0.0018615722656250, -0.0039062500000000, 0.0019226074218750, +-0.0039672851562500, 0.0016174316406250, -0.0032348632812500, 0.0012512207031250, +-0.0034790039062500, 0.0014953613281250, -0.0033264160156250, 0.0007934570312500, +-0.0018310546875000, 0.0007934570312500, -0.0024719238281250, 0.0010375976562500, +-0.0014953613281250, 0.0008544921875000, 0.0000610351562500, 0.0008239746093750, +-0.0012817382812500, 0.0011901855468750, 0.0010375976562500, 0.0013427734375000, +0.0007019042968750, 0.0010070800781250, 0.0004882812500000, 0.0009460449218750, +0.0016784667968750, 0.0011901855468750, 0.0008239746093750, 0.0005187988281250, +0.0005493164062500, 0.0004272460937500, 0.0004272460937500, 0.0005798339843750, +-0.0002746582031250, 0.0006103515625000, -0.0009460449218750, 0.0005493164062500, +-0.0011291503906250, -0.0000305175781250, -0.0022277832031250, 0.0004577636718750, +-0.0025024414062500, -0.0002441406250000, -0.0024108886718750, -0.0012512207031250, +-0.0028076171875000, -0.0004882812500000, -0.0028991699218750, -0.0017700195312500, +-0.0019226074218750, -0.0020141601562500, -0.0021667480468750, -0.0017700195312500, +-0.0021057128906250, -0.0021667480468750, -0.0012817382812500, -0.0021057128906250, +-0.0013732910156250, -0.0017395019531250, -0.0020446777343750, -0.0018615722656250, +-0.0012512207031250, -0.0017700195312500, -0.0015869140625000, -0.0014038085937500, +-0.0023193359375000, -0.0015258789062500, -0.0011596679687500, -0.0015563964843750, +-0.0017700195312500, -0.0014648437500000, -0.0020141601562500, -0.0014953613281250, +-0.0016784667968750, -0.0015563964843750, -0.0013427734375000, -0.0014953613281250, +-0.0010986328125000, -0.0011596679687500, -0.0014648437500000, -0.0010681152343750, +-0.0010681152343750, -0.0013732910156250, -0.0007629394531250, -0.0013427734375000, +-0.0008239746093750, -0.0010375976562500, -0.0007019042968750, -0.0018005371093750, +-0.0017700195312500, -0.0017395019531250, -0.0014953613281250, -0.0015869140625000, +-0.0021667480468750, -0.0019836425781250, -0.0032043457031250, -0.0017395019531250, +-0.0023193359375000, -0.0009155273437500, -0.0032043457031250, -0.0011901855468750, +-0.0033264160156250, -0.0004272460937500, -0.0025634765625000, 0.0006103515625000, +-0.0022888183593750, 0.0000610351562500, -0.0024108886718750, 0.0013122558593750, +-0.0014038085937500, 0.0018615722656250, -0.0010681152343750, 0.0010986328125000, +-0.0016174316406250, 0.0010681152343750, -0.0012817382812500, 0.0018310546875000, +-0.0005187988281250, 0.0002746582031250, -0.0029296875000000, 0.0002746582031250, +-0.0021667480468750, 0.0006103515625000, -0.0018920898437500, -0.0000915527343750, +-0.0041809082031250, 0.0001831054687500, -0.0007629394531250, -0.0003662109375000, +-0.0031433105468750, -0.0004272460937500, -0.0026245117187500, -0.0004577636718750, +-0.0021057128906250, -0.0007324218750000, -0.0028381347656250, -0.0007934570312500, +-0.0031127929687500, 0.0000000000000000, -0.0007324218750000, 0.0002441406250000, +-0.0009460449218750, -0.0003967285156250, -0.0007934570312500, 0.0000000000000000, +0.0008239746093750, 0.0007324218750000, 0.0003356933593750, -0.0023803710937500, +-0.0003356933593750, -0.0010681152343750, -0.0000305175781250, -0.0020751953125000, +-0.0001831054687500, -0.0053100585937500, -0.0008544921875000, -0.0035400390625000, +-0.0006408691406250, -0.0037841796875000, -0.0005493164062500, -0.0053100585937500, +-0.0004272460937500, -0.0032653808593750, -0.0007629394531250, -0.0011596679687500, +-0.0007019042968750, -0.0030822753906250, -0.0002441406250000, -0.0002746582031250, +-0.0027465820312500}, +{-0.0006713867187500, 0.0021057128906250, -0.0031433105468750, 0.0019836425781250, +-0.0026245117187500, 0.0018005371093750, -0.0028686523437500, 0.0019226074218750, +-0.0048828125000000, 0.0018310546875000, -0.0040893554687500, 0.0012512207031250, +-0.0042724609375000, 0.0011596679687500, -0.0052795410156250, 0.0011596679687500, +-0.0039672851562500, 0.0008544921875000, -0.0030212402343750, 0.0006408691406250, +-0.0045776367187500, 0.0009460449218750, -0.0008544921875000, 0.0010375976562500, +-0.0016784667968750, 0.0002441406250000, -0.0009765625000000, -0.0001220703125000, +0.0015869140625000, 0.0003051757812500, -0.0000915527343750, -0.0013427734375000, +0.0019836425781250, -0.0016479492187500, 0.0017395019531250, -0.0013122558593750, +0.0008544921875000, -0.0018615722656250, 0.0013122558593750, -0.0020141601562500, +0.0007324218750000, -0.0009155273437500, -0.0004272460937500, -0.0011596679687500, +-0.0003662109375000, -0.0011596679687500, -0.0009155273437500, -0.0003967285156250, +-0.0020751953125000, -0.0006408691406250, -0.0021362304687500, -0.0012512207031250, +-0.0021667480468750, -0.0007934570312500, -0.0027160644531250, -0.0010070800781250, +-0.0026855468750000, -0.0017089843750000, -0.0023498535156250, -0.0012512207031250, +-0.0024414062500000, -0.0013122558593750, -0.0022583007812500, -0.0014038085937500, +-0.0021057128906250, -0.0014038085937500, -0.0018005371093750, -0.0011291503906250, +-0.0016479492187500, -0.0010681152343750, -0.0018615722656250, -0.0019226074218750, +-0.0014648437500000, -0.0014343261718750, -0.0015258789062500, -0.0016479492187500, +-0.0012512207031250, -0.0026245117187500, -0.0010681152343750, -0.0020141601562500, +-0.0017089843750000, -0.0014038085937500, -0.0008544921875000, -0.0018920898437500, +-0.0022583007812500, -0.0006408691406250, -0.0018920898437500, 0.0008239746093750, +-0.0006103515625000, 0.0000305175781250, -0.0023498535156250, 0.0019836425781250, +-0.0010681152343750, 0.0023498535156250, -0.0012207031250000, 0.0020446777343750, +-0.0020751953125000, 0.0027465820312500, -0.0019226074218750, 0.0027770996093750, +-0.0020446777343750, 0.0016174316406250, -0.0027465820312500, 0.0019531250000000, +-0.0032653808593750, 0.0018920898437500, -0.0028381347656250, 0.0010375976562500, +-0.0029296875000000, 0.0011596679687500, -0.0037231445312500, 0.0008850097656250, +-0.0015258789062500, 0.0009155273437500, -0.0017089843750000, 0.0005798339843750, +-0.0023193359375000, -0.0001525878906250, -0.0010375976562500, -0.0006713867187500, +-0.0048522949218750, -0.0009155273437500, -0.0012512207031250, -0.0003051757812500, +-0.0019836425781250, -0.0008850097656250, -0.0026245117187500, -0.0012207031250000, +-0.0020446777343750, -0.0005798339843750, -0.0020751953125000, -0.0025939941406250, +-0.0028991699218750, -0.0021362304687500, -0.0036010742187500, -0.0020446777343750, +-0.0024719238281250, -0.0036926269531250, -0.0020141601562500, -0.0032958984375000, +-0.0032043457031250, -0.0025024414062500, 0.0000000000000000, -0.0036010742187500, +-0.0000610351562500, -0.0028076171875000, -0.0006103515625000, -0.0014038085937500, +0.0007934570312500, -0.0028991699218750, 0.0005798339843750, -0.0018310546875000, +-0.0008239746093750, -0.0016174316406250, -0.0004882812500000, -0.0028076171875000, +-0.0006713867187500, -0.0032653808593750, -0.0017395019531250, -0.0029296875000000, +-0.0013427734375000, -0.0041809082031250, -0.0007934570312500, -0.0046691894531250, +-0.0006713867187500, -0.0040588378906250, -0.0012207031250000, -0.0039978027343750, +-0.0011901855468750, -0.0042419433593750, -0.0004272460937500, -0.0028076171875000, +-0.0026550292968750, -0.0031127929687500, -0.0023803710937500, -0.0028381347656250, +-0.0025024414062500, -0.0018615722656250, -0.0038757324218750, -0.0027160644531250, +-0.0032043457031250, -0.0024414062500000, -0.0028381347656250, -0.0030212402343750, +-0.0030517578125000, -0.0032043457031250, -0.0025024414062500, -0.0036621093750000, +-0.0016784667968750, -0.0046997070312500, -0.0017089843750000, -0.0021667480468750, +-0.0013427734375000, -0.0037841796875000, -0.0010986328125000, -0.0028686523437500, +-0.0008850097656250, -0.0000610351562500, -0.0006103515625000, -0.0020751953125000, +-0.0006103515625000, 0.0002136230468750, -0.0003662109375000, 0.0005493164062500, +0.0000305175781250, -0.0001525878906250, -0.0003051757812500, 0.0006103515625000, +-0.0007019042968750, 0.0005493164062500, -0.0002441406250000, -0.0012512207031250, +-0.0009155273437500, -0.0007019042968750, -0.0010986328125000, -0.0015563964843750, +-0.0007324218750000, -0.0036926269531250, -0.0008544921875000, -0.0029907226562500, +-0.0010986328125000, -0.0036926269531250, -0.0000915527343750, -0.0048522949218750, +-0.0003662109375000, -0.0038757324218750, -0.0000610351562500, -0.0032958984375000, +0.0008544921875000, -0.0046691894531250, 0.0003967285156250, -0.0017089843750000, +0.0010070800781250, -0.0027770996093750, 0.0010070800781250, -0.0020141601562500, +0.0009765625000000, 0.0003051757812500, 0.0012207031250000, -0.0015869140625000, +0.0010681152343750, 0.0015258789062500, 0.0013732910156250, 0.0012512207031250, +0.0013732910156250, 0.0011596679687500, 0.0014343261718750, 0.0029296875000000, +0.0015869140625000, 0.0021362304687500, 0.0014648437500000, 0.0019836425781250, +0.0016784667968750, 0.0026550292968750, 0.0014648437500000, 0.0019226074218750, +0.0017395019531250, 0.0012207031250000, 0.0021667480468750, 0.0021362304687500, +0.0017700195312500, 0.0005187988281250, 0.0024719238281250, 0.0008850097656250, +0.0024719238281250, 0.0008239746093750, 0.0022888183593750, -0.0001525878906250, +0.0025024414062500, 0.0005798339843750, 0.0025024414062500, -0.0005187988281250, +0.0023193359375000, -0.0005187988281250, 0.0023193359375000, 0.0000305175781250, +0.0021972656250000, -0.0001831054687500, 0.0020446777343750, -0.0004577636718750, +0.0021362304687500, -0.0000610351562500, 0.0016174316406250, -0.0002441406250000, +0.0017700195312500, -0.0003051757812500, 0.0015869140625000, 0.0000305175781250, +0.0010681152343750, -0.0000915527343750, 0.0013732910156250, 0.0005493164062500, +0.0007934570312500, 0.0005187988281250, 0.0008239746093750, 0.0006408691406250, +0.0006103515625000, 0.0011291503906250, 0.0002136230468750, 0.0010986328125000, +0.0004577636718750, 0.0010986328125000, -0.0000915527343750, 0.0013427734375000, +-0.0001220703125000, 0.0012512207031250, -0.0002746582031250, 0.0012512207031250, +-0.0006408691406250, 0.0015563964843750, -0.0005493164062500, 0.0008239746093750, +-0.0010375976562500, 0.0012207031250000, -0.0010375976562500, 0.0010681152343750, +-0.0011291503906250, 0.0004882812500000, -0.0014953613281250, 0.0010070800781250, +-0.0014343261718750, 0.0002441406250000, -0.0014648437500000, 0.0002441406250000, +-0.0017089843750000, 0.0002136230468750, -0.0013732910156250, -0.0002136230468750, +-0.0011291503906250, -0.0000915527343750, -0.0015258789062500, -0.0003967285156250, +-0.0002136230468750, -0.0005187988281250, -0.0005493164062500, -0.0004882812500000, +-0.0003356933593750, -0.0007324218750000, 0.0006408691406250, -0.0006713867187500, +0.0000610351562500, 0.0003967285156250, 0.0005187988281250, -0.0002441406250000, +0.0005798339843750, 0.0000915527343750, 0.0004577636718750, 0.0009460449218750, +0.0006103515625000, -0.0000915527343750, 0.0005493164062500, 0.0013427734375000, +0.0001525878906250, 0.0011901855468750, 0.0003051757812500, 0.0012207031250000, +0.0003662109375000, 0.0022583007812500, 0.0000915527343750, 0.0021057128906250, +0.0000305175781250, 0.0028381347656250, 0.0005493164062500, 0.0033569335937500, +0.0005187988281250, 0.0034484863281250, 0.0003356933593750, 0.0038452148437500, +0.0005187988281250, 0.0041503906250000, 0.0005187988281250, 0.0039062500000000, +0.0001525878906250, 0.0042724609375000, 0.0001525878906250, 0.0039672851562500, +0.0000000000000000, 0.0034179687500000, -0.0003662109375000, 0.0036010742187500, +-0.0002746582031250, 0.0021362304687500, -0.0000915527343750, 0.0023193359375000, +-0.0004577636718750, 0.0010681152343750, -0.0002441406250000, -0.0006408691406250, +0.0001831054687500, 0.0001220703125000, -0.0001831054687500, -0.0023803710937500, +0.0001831054687500, -0.0022583007812500, 0.0002746582031250, -0.0024414062500000, +-0.0000915527343750, -0.0037231445312500, -0.0001220703125000, -0.0029602050781250, +0.0001525878906250, -0.0035095214843750, -0.0010681152343750, -0.0036315917968750, +-0.0009155273437500, -0.0032958984375000, -0.0008239746093750, -0.0033264160156250, +-0.0015869140625000, -0.0035095214843750, -0.0015258789062500, -0.0034790039062500, +-0.0014038085937500, -0.0033874511718750, -0.0013427734375000, -0.0041503906250000, +-0.0010070800781250, -0.0048217773437500, -0.0007324218750000, -0.0045471191406250, +-0.0008850097656250, -0.0055236816406250, -0.0007324218750000, -0.0061340332031250, +-0.0004272460937500, -0.0061950683593750, -0.0005493164062500, -0.0063171386718750, +-0.0008850097656250, -0.0063171386718750, -0.0007629394531250, -0.0053405761718750, +-0.0003356933593750, -0.0050048828125000, -0.0004272460937500, -0.0046691894531250, +-0.0005493164062500, -0.0040283203125000, -0.0003967285156250, -0.0038146972656250, +-0.0003662109375000, -0.0032958984375000, -0.0003967285156250, -0.0039672851562500, +-0.0003967285156250, -0.0037841796875000, -0.0006408691406250, -0.0028381347656250, +-0.0007324218750000, -0.0032958984375000, -0.0005798339843750, -0.0030822753906250, +-0.0014038085937500, -0.0025024414062500, -0.0012512207031250, -0.0028076171875000, +-0.0015258789062500, -0.0030212402343750, -0.0023193359375000, -0.0023803710937500, +-0.0018005371093750, -0.0033264160156250, -0.0020446777343750, -0.0032043457031250, +-0.0021057128906250, -0.0030822753906250, -0.0020446777343750, -0.0035400390625000, +-0.0023193359375000, -0.0032348632812500, -0.0022888183593750, -0.0033264160156250, +-0.0017395019531250, -0.0036315917968750, -0.0015563964843750, -0.0030822753906250, +-0.0022583007812500, -0.0030517578125000, -0.0025329589843750, -0.0037231445312500, +-0.0020751953125000, -0.0010070800781250, -0.0031127929687500, -0.0022583007812500, +-0.0027770996093750, -0.0021057128906250, -0.0028686523437500, -0.0001525878906250, +-0.0034790039062500, -0.0015258789062500, -0.0026855468750000, 0.0003356933593750, +-0.0036621093750000, -0.0000915527343750, -0.0034179687500000, -0.0003662109375000, +-0.0034179687500000, 0.0007019042968750, -0.0043334960937500, 0.0000000000000000, +-0.0041198730468750, -0.0004577636718750, -0.0037841796875000, -0.0002746582031250, +-0.0043334960937500, -0.0005798339843750, -0.0036010742187500, -0.0011596679687500, +-0.0020141601562500, -0.0010375976562500, -0.0021667480468750, -0.0011291503906250, +-0.0024108886718750, -0.0010681152343750, -0.0007019042968750, -0.0008239746093750, +-0.0014953613281250, -0.0005798339843750, -0.0028381347656250, -0.0005798339843750, +-0.0010681152343750, -0.0012817382812500, -0.0039062500000000, -0.0008544921875000, +-0.0036315917968750, -0.0010681152343750, -0.0033874511718750, -0.0019836425781250, +-0.0052185058593750, -0.0015563964843750, -0.0050048828125000, -0.0014953613281250, +-0.0047302246093750, -0.0019836425781250, -0.0054321289062500, -0.0015258789062500, +-0.0055236816406250, -0.0008239746093750, -0.0052795410156250, -0.0013732910156250, +-0.0059509277343750, -0.0011291503906250, -0.0056762695312500, -0.0008850097656250, +-0.0063171386718750, -0.0015258789062500, -0.0057067871093750, -0.0019836425781250, +-0.0051269531250000, -0.0017089843750000, -0.0061645507812500, -0.0021362304687500, +-0.0035095214843750, -0.0026855468750000, -0.0045166015625000, -0.0021362304687500, +-0.0037231445312500}, +{-0.0002136230468750, 0.0016479492187500, -0.0005187988281250, 0.0002441406250000, +-0.0007629394531250, 0.0012817382812500, -0.0005493164062500, -0.0013427734375000, +-0.0009460449218750, -0.0009765625000000, -0.0011596679687500, -0.0013122558593750, +-0.0010986328125000, -0.0030212402343750, -0.0012512207031250, -0.0021667480468750, +-0.0012207031250000, -0.0029907226562500, -0.0009460449218750, -0.0032348632812500, +-0.0010681152343750, -0.0027770996093750, -0.0009765625000000, -0.0027465820312500, +-0.0005187988281250, -0.0030822753906250, -0.0004577636718750, -0.0031433105468750, +-0.0006103515625000, -0.0028686523437500, -0.0004272460937500, -0.0037536621093750, +-0.0006103515625000, -0.0046386718750000, -0.0007934570312500, -0.0040893554687500, +-0.0004577636718750, -0.0057067871093750, -0.0010681152343750, -0.0056762695312500, +-0.0010681152343750, -0.0054016113281250, -0.0008544921875000, -0.0058898925781250, +-0.0010681152343750, -0.0052490234375000, -0.0011596679687500, -0.0044555664062500, +-0.0010070800781250, -0.0046997070312500, -0.0007629394531250, -0.0036010742187500, +-0.0010986328125000, -0.0027160644531250, -0.0014038085937500, -0.0041503906250000, +-0.0011596679687500, -0.0023498535156250, -0.0019836425781250, -0.0018005371093750, +-0.0018920898437500, -0.0026245117187500, -0.0014343261718750, -0.0024414062500000, +-0.0015869140625000, -0.0019226074218750, -0.0017395019531250, -0.0031127929687500, +-0.0012207031250000, -0.0029602050781250, -0.0013122558593750, -0.0027465820312500, +-0.0009765625000000, -0.0032653808593750, -0.0003662109375000, -0.0030822753906250, +-0.0008239746093750, -0.0030822753906250, -0.0017700195312500, -0.0028076171875000, +-0.0012817382812500, -0.0031127929687500, -0.0015869140625000, -0.0037231445312500, +-0.0029296875000000, -0.0031738281250000, -0.0034179687500000, -0.0027770996093750, +-0.0043640136718750, -0.0036926269531250, -0.0041503906250000, -0.0025939941406250, +-0.0040283203125000, -0.0014038085937500, -0.0045166015625000, -0.0027770996093750, +-0.0042724609375000, -0.0001525878906250, -0.0040893554687500, -0.0005187988281250, +-0.0044250488281250, -0.0004272460937500, -0.0038757324218750, 0.0008850097656250, +-0.0032348632812500, -0.0003051757812500, -0.0036315917968750, 0.0008850097656250, +-0.0024414062500000, 0.0005493164062500, -0.0011901855468750, 0.0002136230468750, +-0.0019836425781250, 0.0006408691406250, -0.0020751953125000, 0.0000305175781250, +-0.0003051757812500, 0.0002441406250000, -0.0029602050781250, 0.0001831054687500, +-0.0022583007812500, -0.0000915527343750, -0.0021972656250000, -0.0001220703125000, +-0.0039672851562500, -0.0001831054687500, -0.0030822753906250, 0.0000305175781250, +-0.0034790039062500, -0.0000305175781250, -0.0045166015625000, -0.0005187988281250, +-0.0043640136718750, -0.0006713867187500, -0.0042114257812500, -0.0005798339843750, +-0.0053405761718750, -0.0017395019531250, -0.0046997070312500, -0.0017089843750000, +-0.0057983398437500, -0.0016174316406250, -0.0054321289062500, -0.0024414062500000, +-0.0048522949218750, -0.0025024414062500, -0.0064697265625000, -0.0014953613281250, +-0.0032958984375000, -0.0019226074218750, -0.0047607421875000, -0.0016479492187500, +-0.0040893554687500, -0.0006408691406250, -0.0015563964843750, -0.0012207031250000, +-0.0040893554687500, -0.0012512207031250, -0.0014953613281250, -0.0010070800781250, +-0.0021667480468750, -0.0012512207031250, -0.0026855468750000, -0.0016479492187500, +-0.0016174316406250, -0.0015563964843750, -0.0028381347656250, -0.0014038085937500, +-0.0020751953125000, -0.0018920898437500, -0.0028381347656250, -0.0011596679687500, +-0.0020751953125000, -0.0003356933593750, -0.0010681152343750, -0.0010986328125000, +-0.0024108886718750, -0.0002746582031250, 0.0005798339843750, 0.0001220703125000, +0.0001525878906250, -0.0002441406250000, 0.0003662109375000, -0.0001525878906250, +0.0023498535156250, 0.0000915527343750, 0.0015258789062500, -0.0009765625000000, +0.0017089843750000, -0.0005798339843750, 0.0025329589843750, -0.0005493164062500, +0.0016784667968750, -0.0013122558593750, 0.0010070800781250, -0.0008850097656250, +0.0020141601562500, -0.0008544921875000, 0.0000915527343750, -0.0009460449218750, +0.0005187988281250, -0.0004882812500000, 0.0005493164062500, -0.0001525878906250, +-0.0004882812500000, -0.0003967285156250, 0.0005187988281250, 0.0002746582031250, +0.0000000000000000, 0.0001220703125000, 0.0003051757812500, 0.0002746582031250, +0.0003051757812500, 0.0007934570312500, 0.0000000000000000, 0.0004882812500000, +0.0007934570312500, 0.0007019042968750, 0.0006103515625000, 0.0009155273437500, +0.0008544921875000, 0.0007019042968750, 0.0010070800781250, 0.0006103515625000, +0.0013122558593750, 0.0009460449218750, 0.0021667480468750, 0.0004272460937500, +0.0011291503906250, 0.0004882812500000, 0.0022583007812500, 0.0006713867187500, +0.0018615722656250, 0.0004882812500000, 0.0009155273437500, 0.0005187988281250, +0.0027465820312500, 0.0008850097656250, 0.0006713867187500, 0.0010375976562500, +0.0016479492187500, 0.0011901855468750, 0.0016784667968750, 0.0014038085937500, +0.0003356933593750, 0.0014038085937500, 0.0018005371093750, 0.0016784667968750, +0.0006103515625000, 0.0017395019531250, 0.0006713867187500, 0.0018005371093750, +0.0004882812500000, 0.0020141601562500, 0.0000915527343750, 0.0020751953125000, +0.0010375976562500, 0.0020141601562500, -0.0003967285156250, 0.0022583007812500, +0.0006103515625000, 0.0020751953125000, 0.0003967285156250, 0.0018005371093750, +-0.0007324218750000, 0.0020446777343750, 0.0010070800781250, 0.0015869140625000, +-0.0003051757812500, 0.0014953613281250, 0.0002441406250000, 0.0015869140625000, +0.0004882812500000, 0.0015258789062500, -0.0001831054687500, 0.0015258789062500, +0.0006408691406250, 0.0016784667968750, -0.0000305175781250, 0.0018615722656250, +0.0003967285156250, 0.0016784667968750, 0.0003967285156250, 0.0015869140625000, +0.0000000000000000, 0.0017700195312500, 0.0008544921875000, 0.0012512207031250, +0.0003356933593750, 0.0011901855468750, 0.0007019042968750, 0.0011596679687500, +0.0010986328125000, 0.0007324218750000, 0.0010986328125000, 0.0005798339843750, +0.0014953613281250, 0.0009765625000000, 0.0018310546875000, 0.0006103515625000, +0.0023498535156250, 0.0007629394531250, 0.0025329589843750, 0.0013122558593750, +0.0028381347656250, 0.0010986328125000, 0.0034790039062500, 0.0016784667968750, +0.0029602050781250, 0.0017700195312500, 0.0035400390625000, 0.0019226074218750, +0.0033569335937500, 0.0023193359375000, 0.0026855468750000, 0.0022277832031250, +0.0033264160156250, 0.0023193359375000, 0.0017395019531250, 0.0024414062500000, +0.0022277832031250, 0.0021362304687500, 0.0014953613281250, 0.0018615722656250, +0.0001525878906250, 0.0019226074218750, 0.0011596679687500, 0.0015258789062500, +-0.0010681152343750, 0.0012512207031250, -0.0004272460937500, 0.0013732910156250, +-0.0005187988281250, 0.0013427734375000, -0.0017700195312500, 0.0010986328125000, +-0.0004882812500000, 0.0007934570312500, -0.0012512207031250, 0.0010375976562500, +-0.0006408691406250, 0.0004577636718750, -0.0003662109375000, -0.0004272460937500, +-0.0004882812500000, -0.0001831054687500, 0.0006713867187500, -0.0004272460937500, +-0.0006103515625000, -0.0010681152343750, 0.0004577636718750, -0.0006103515625000, +0.0002441406250000, 0.0000000000000000, -0.0008544921875000, -0.0006103515625000, +0.0004272460937500, -0.0000915527343750, -0.0016174316406250, 0.0002441406250000, +-0.0010375976562500, -0.0002136230468750, -0.0014343261718750, -0.0005187988281250, +-0.0031433105468750, -0.0001831054687500, -0.0020141601562500, -0.0006408691406250, +-0.0030212402343750, -0.0007019042968750, -0.0042114257812500, -0.0004272460937500, +-0.0029602050781250, -0.0004577636718750, -0.0025634765625000, -0.0004272460937500, +-0.0040588378906250, -0.0005798339843750, -0.0002746582031250, -0.0004272460937500, +-0.0013732910156250, -0.0006713867187500, -0.0010070800781250, -0.0011291503906250, +0.0015258789062500, -0.0009460449218750, -0.0003967285156250, -0.0010375976562500, +0.0011291503906250, -0.0015869140625000, 0.0011291503906250, -0.0010986328125000, +0.0000610351562500, -0.0006103515625000, 0.0002136230468750, -0.0013732910156250, +0.0001220703125000, -0.0002441406250000, -0.0016174316406250, -0.0004882812500000, +-0.0012817382812500, -0.0004272460937500, -0.0018310546875000, 0.0001525878906250, +-0.0032348632812500, -0.0005187988281250, -0.0025329589843750, -0.0000915527343750, +-0.0032043457031250, -0.0002136230468750, -0.0031433105468750, -0.0002136230468750, +-0.0029296875000000, -0.0000915527343750, -0.0030212402343750, -0.0007019042968750, +-0.0027160644531250, 0.0001831054687500, -0.0025634765625000, 0.0000000000000000, +-0.0021972656250000, -0.0003051757812500, -0.0022888183593750, 0.0001220703125000, +-0.0024719238281250, -0.0000610351562500, -0.0019531250000000, -0.0008544921875000, +-0.0019836425781250, -0.0004272460937500, -0.0024108886718750, -0.0007324218750000, +-0.0016784667968750, -0.0014648437500000, -0.0007019042968750, -0.0007324218750000, +-0.0012817382812500, -0.0012512207031250, -0.0007019042968750, -0.0007019042968750, +0.0000000000000000, -0.0010070800781250, -0.0011901855468750, -0.0025024414062500, +-0.0031738281250000, -0.0019836425781250, -0.0012207031250000, 0.0002441406250000, +-0.0027160644531250, -0.0008850097656250, -0.0012817382812500, -0.0004272460937500, +-0.0023193359375000, 0.0011291503906250, -0.0040893554687500, 0.0002136230468750, +-0.0030517578125000, -0.0015869140625000, -0.0041503906250000, -0.0002136230468750, +-0.0044250488281250, -0.0021667480468750, -0.0035705566406250, -0.0052490234375000, +-0.0032653808593750, -0.0033264160156250, -0.0034179687500000, -0.0057067871093750, +-0.0027465820312500, -0.0066223144531250, -0.0021972656250000, -0.0047607421875000, +-0.0025024414062500, -0.0041809082031250, -0.0028381347656250, -0.0050659179687500, +-0.0024414062500000, -0.0019531250000000, -0.0028381347656250, -0.0017700195312500, +-0.0031738281250000, -0.0024108886718750, -0.0025024414062500, -0.0014343261718750, +-0.0021057128906250, -0.0013122558593750, -0.0027465820312500, -0.0025329589843750, +-0.0018005371093750, -0.0030212402343750, -0.0013427734375000, -0.0022583007812500, +-0.0021057128906250, -0.0022888183593750, -0.0025024414062500, -0.0031127929687500, +-0.0020446777343750, -0.0008850097656250, -0.0030212402343750, -0.0007934570312500, +-0.0033874511718750, -0.0010986328125000, -0.0029907226562500, 0.0003967285156250, +-0.0031433105468750, 0.0007934570312500, -0.0035095214843750, -0.0012817382812500, +-0.0022888183593750, 0.0005798339843750, -0.0025329589843750, -0.0008850097656250, +-0.0027465820312500, -0.0037231445312500, -0.0020446777343750, -0.0010681152343750, +-0.0021972656250000, -0.0041198730468750, -0.0029296875000000, -0.0046691894531250, +-0.0029296875000000, -0.0034179687500000, -0.0025939941406250, -0.0039367675781250, +-0.0028686523437500, -0.0042114257812500, -0.0029907226562500, -0.0020751953125000, +-0.0016174316406250, -0.0028686523437500, -0.0018005371093750, -0.0020751953125000, +-0.0015869140625000, -0.0001525878906250, -0.0004272460937500, -0.0014038085937500, +-0.0006408691406250, 0.0003051757812500, -0.0003967285156250, 0.0009765625000000, +-0.0000610351562500, 0.0000000000000000, -0.0000610351562500, 0.0000610351562500, +-0.0000610351562500, 0.0008239746093750, 0.0002136230468750, -0.0011596679687500, +0.0001831054687500, -0.0007629394531250, 0.0004882812500000, -0.0007934570312500, +0.0003051757812500, -0.0019531250000000, 0.0000000000000000, -0.0011596679687500, +0.0004272460937500}, +{-0.0003662109375000, -0.0004577636718750, -0.0022277832031250, -0.0008544921875000, +0.0000305175781250, -0.0008544921875000, 0.0000000000000000, -0.0008239746093750, +-0.0009155273437500, -0.0007324218750000, -0.0000915527343750, -0.0003356933593750, +0.0000000000000000, -0.0005493164062500, -0.0014648437500000, 0.0000000000000000, +-0.0009155273437500, -0.0004272460937500, -0.0017395019531250, -0.0007934570312500, +-0.0034179687500000, 0.0003051757812500, -0.0025329589843750, -0.0019836425781250, +-0.0038757324218750, -0.0010681152343750, -0.0045471191406250, -0.0012512207031250, +-0.0036926269531250, -0.0028076171875000, -0.0032043457031250, -0.0013122558593750, +-0.0036315917968750, -0.0022277832031250, -0.0025634765625000, -0.0018310546875000, +-0.0018005371093750, -0.0015258789062500, -0.0023498535156250, -0.0018310546875000, +-0.0024414062500000, -0.0010986328125000, -0.0015258789062500, -0.0021362304687500, +-0.0025939941406250, -0.0019226074218750, -0.0023498535156250, -0.0013427734375000, +-0.0017089843750000, -0.0016174316406250, -0.0018310546875000, -0.0000610351562500, +-0.0013122558593750, -0.0014648437500000, -0.0021972656250000, -0.0000915527343750, +-0.0019836425781250, -0.0021057128906250, -0.0016784667968750, -0.0042724609375000, +-0.0016174316406250, -0.0025329589843750, -0.0016784667968750, -0.0048522949218750, +-0.0018005371093750, -0.0056152343750000, -0.0013427734375000, -0.0040893554687500, +-0.0021362304687500, -0.0039062500000000, -0.0031738281250000, -0.0046081542968750, +-0.0024108886718750, -0.0016784667968750, -0.0032348632812500, -0.0019836425781250, +-0.0037841796875000, -0.0020446777343750, -0.0030822753906250, -0.0004882812500000, +-0.0026550292968750, -0.0011596679687500, -0.0031433105468750, -0.0016479492187500, +-0.0019531250000000, -0.0017395019531250, -0.0018310546875000, -0.0016784667968750, +-0.0023498535156250, -0.0020446777343750, -0.0021667480468750, -0.0025634765625000, +-0.0020446777343750, -0.0009155273437500, -0.0025634765625000, -0.0010070800781250, +-0.0028991699218750, -0.0016479492187500, -0.0025634765625000, -0.0007934570312500, +-0.0022583007812500, -0.0004272460937500, -0.0025329589843750, -0.0026855468750000, +-0.0021667480468750, -0.0018005371093750, -0.0018310546875000, -0.0023498535156250, +-0.0021972656250000, -0.0045166015625000, -0.0023498535156250, -0.0034484863281250, +-0.0019836425781250, -0.0036926269531250, -0.0030822753906250, -0.0048217773437500, +-0.0030212402343750, -0.0030212402343750, -0.0026855468750000, -0.0017089843750000, +-0.0030822753906250, -0.0034790039062500, -0.0031738281250000, 0.0003662109375000, +-0.0025939941406250, 0.0001220703125000, -0.0024108886718750, -0.0002746582031250, +-0.0026245117187500, 0.0014953613281250, -0.0026245117187500, 0.0006713867187500, +-0.0024414062500000, 0.0003051757812500, -0.0025939941406250, 0.0006713867187500, +-0.0028381347656250, -0.0000610351562500, -0.0023193359375000, -0.0008544921875000, +-0.0018920898437500, -0.0002441406250000, -0.0021972656250000, -0.0011291503906250, +-0.0010681152343750, -0.0016479492187500, -0.0009155273437500, -0.0009460449218750, +-0.0010070800781250, -0.0007934570312500, -0.0004272460937500, -0.0013732910156250, +-0.0004272460937500, 0.0003356933593750, -0.0006408691406250, 0.0003662109375000, +-0.0006408691406250, 0.0004272460937500, -0.0003356933593750, 0.0015258789062500, +-0.0002136230468750, 0.0015869140625000, -0.0003356933593750, 0.0017089843750000, +0.0002136230468750, 0.0023803710937500, 0.0002136230468750, 0.0021972656250000, +0.0001525878906250, 0.0021362304687500, 0.0002746582031250, 0.0029296875000000, +0.0002746582031250, 0.0013122558593750, 0.0007934570312500, 0.0021972656250000, +0.0005187988281250, 0.0017700195312500, 0.0009460449218750, 0.0003356933593750, +0.0017700195312500, 0.0015258789062500, 0.0013427734375000, 0.0001525878906250, +0.0018005371093750, 0.0001831054687500, 0.0021057128906250, 0.0005187988281250, +0.0018920898437500, -0.0000915527343750, 0.0018310546875000, 0.0000915527343750, +0.0020446777343750, 0.0007019042968750, 0.0019531250000000, 0.0003051757812500, +0.0019836425781250, 0.0008544921875000, 0.0020751953125000, 0.0016174316406250, +0.0021667480468750, 0.0009765625000000, 0.0022583007812500, 0.0024414062500000, +0.0022277832031250, 0.0022888183593750, 0.0023498535156250, 0.0026245117187500, +0.0023803710937500, 0.0036621093750000, 0.0023803710937500, 0.0031127929687500, +0.0026550292968750, 0.0037841796875000, 0.0023498535156250, 0.0040893554687500, +0.0026245117187500, 0.0037536621093750, 0.0024414062500000, 0.0039367675781250, +0.0020751953125000, 0.0044860839843750, 0.0024108886718750, 0.0035705566406250, +0.0017700195312500, 0.0043029785156250, 0.0018005371093750, 0.0045166015625000, +0.0018310546875000, 0.0034790039062500, 0.0014648437500000, 0.0037231445312500, +0.0015869140625000, 0.0039672851562500, 0.0018920898437500, 0.0036621093750000, +0.0016479492187500, 0.0038146972656250, 0.0018005371093750, 0.0041198730468750, +0.0021972656250000, 0.0036926269531250, 0.0019226074218750, 0.0042724609375000, +0.0022277832031250, 0.0040283203125000, 0.0022583007812500, 0.0040283203125000, +0.0021667480468750, 0.0044250488281250, 0.0023193359375000, 0.0039978027343750, +0.0021972656250000, 0.0043334960937500, 0.0021057128906250, 0.0047607421875000, +0.0022277832031250, 0.0045166015625000, 0.0020446777343750, 0.0046081542968750, +0.0017700195312500, 0.0052490234375000, 0.0019226074218750, 0.0043945312500000, +0.0014953613281250, 0.0049133300781250, 0.0015563964843750, 0.0047607421875000, +0.0014343261718750, 0.0039978027343750, 0.0011901855468750, 0.0046081542968750, +0.0013732910156250, 0.0036010742187500, 0.0010070800781250, 0.0038146972656250, +0.0010681152343750, 0.0036621093750000, 0.0007934570312500, 0.0029602050781250, +0.0004272460937500, 0.0034179687500000, 0.0006408691406250, 0.0023803710937500, +-0.0002441406250000, 0.0025024414062500, -0.0002746582031250, 0.0024108886718750, +-0.0004272460937500, 0.0015869140625000, -0.0010070800781250, 0.0016479492187500, +-0.0008544921875000, 0.0015258789062500, -0.0010681152343750, 0.0011291503906250, +-0.0013122558593750, 0.0010681152343750, -0.0011291503906250, 0.0011291503906250, +-0.0008544921875000, 0.0008544921875000, -0.0012207031250000, 0.0007934570312500, +-0.0009765625000000, 0.0010681152343750, -0.0008850097656250, 0.0007934570312500, +-0.0009460449218750, 0.0008850097656250, -0.0010070800781250, 0.0018310546875000, +-0.0010375976562500, 0.0008544921875000, -0.0006713867187500, 0.0016479492187500, +-0.0006408691406250, 0.0017089843750000, -0.0008544921875000, 0.0010375976562500, +-0.0008239746093750, 0.0020141601562500, -0.0005798339843750, 0.0012207031250000, +-0.0010070800781250, 0.0014343261718750, -0.0010986328125000, 0.0016174316406250, +-0.0008850097656250, 0.0011596679687500, -0.0009155273437500, 0.0014648437500000, +-0.0009460449218750, 0.0008239746093750, -0.0003356933593750, 0.0008239746093750, +-0.0003967285156250, 0.0006713867187500, -0.0003967285156250, 0.0003051757812500, +0.0000915527343750, 0.0006103515625000, -0.0000305175781250, 0.0004577636718750, +-0.0008544921875000, 0.0007019042968750, -0.0005798339843750, 0.0008850097656250, +-0.0007629394531250, 0.0009460449218750, -0.0015869140625000, 0.0013122558593750, +-0.0014038085937500, 0.0005798339843750, -0.0011596679687500, 0.0011596679687500, +-0.0016174316406250, 0.0006103515625000, -0.0011596679687500, -0.0004272460937500, +-0.0004577636718750, 0.0001831054687500, -0.0009460449218750, -0.0018005371093750, +-0.0003356933593750, -0.0017700195312500, -0.0000915527343750, -0.0022583007812500, +-0.0003051757812500, -0.0035095214843750, -0.0003662109375000, -0.0028686523437500, +-0.0002441406250000, -0.0042114257812500, -0.0002746582031250, -0.0036315917968750, +-0.0003662109375000, -0.0039367675781250, -0.0001525878906250, -0.0045471191406250, +0.0001220703125000, -0.0027160644531250, -0.0002136230468750, -0.0044860839843750, +-0.0002136230468750, -0.0051879882812500, 0.0000610351562500, -0.0041503906250000, +-0.0003662109375000, -0.0040588378906250, -0.0006713867187500, -0.0045776367187500, +-0.0006408691406250, -0.0025329589843750, -0.0025024414062500, -0.0026855468750000, +-0.0017089843750000, -0.0028076171875000, -0.0022888183593750, -0.0012817382812500, +-0.0040893554687500, -0.0012512207031250, -0.0031127929687500, -0.0026855468750000, +-0.0041809082031250, -0.0016479492187500, -0.0039672851562500, -0.0021972656250000, +-0.0034484863281250, -0.0038146972656250, -0.0033874511718750, -0.0024719238281250, +-0.0024414062500000, -0.0032653808593750, -0.0016784667968750, -0.0028381347656250, +-0.0017700195312500, -0.0029602050781250, -0.0021362304687500, -0.0035095214843750, +-0.0020141601562500, -0.0024108886718750, -0.0017089843750000, -0.0036621093750000, +-0.0025024414062500, -0.0032958984375000, -0.0020141601562500, -0.0026245117187500, +-0.0022277832031250, -0.0029602050781250, -0.0028686523437500, -0.0025634765625000, +-0.0021667480468750, -0.0015258789062500, -0.0028381347656250, -0.0014648437500000, +-0.0031738281250000, -0.0010681152343750, -0.0031738281250000, -0.0003356933593750, +-0.0036010742187500, -0.0005493164062500, -0.0041809082031250, -0.0001220703125000, +-0.0038757324218750, -0.0005187988281250, -0.0050659179687500, -0.0000915527343750, +-0.0049133300781250, 0.0001220703125000, -0.0043334960937500, -0.0009765625000000, +-0.0057678222656250, 0.0012207031250000, -0.0039367675781250, 0.0006408691406250, +-0.0046081542968750, 0.0005798339843750, -0.0043029785156250, 0.0021362304687500, +-0.0027465820312500, 0.0013427734375000, -0.0037841796875000, 0.0009765625000000, +-0.0026245117187500, 0.0015869140625000, -0.0025939941406250, 0.0007934570312500, +-0.0026245117187500, -0.0003356933593750, -0.0020446777343750, 0.0002441406250000, +-0.0023498535156250, -0.0009155273437500, -0.0014343261718750, -0.0009765625000000, +-0.0014953613281250, -0.0008544921875000, -0.0010986328125000, -0.0012207031250000, +-0.0001525878906250, -0.0010375976562500, -0.0002136230468750, -0.0012207031250000, +0.0004882812500000, -0.0010375976562500, 0.0011901855468750, -0.0011596679687500, +0.0011596679687500, -0.0012512207031250, 0.0015258789062500, -0.0007629394531250, +0.0022277832031250, -0.0013732910156250, 0.0011596679687500, -0.0012512207031250, +0.0022888183593750, -0.0013427734375000, 0.0016784667968750, -0.0015869140625000, +0.0004272460937500, -0.0010681152343750, 0.0021972656250000, -0.0017395019531250, +0.0000000000000000, -0.0015869140625000, 0.0012817382812500, -0.0012207031250000, +0.0013732910156250, -0.0013122558593750, 0.0001525878906250, -0.0010070800781250, +0.0022888183593750, -0.0008850097656250, 0.0002746582031250, -0.0005187988281250, +0.0013732910156250, -0.0004272460937500, 0.0013122558593750, -0.0003051757812500, +-0.0001525878906250, 0.0000610351562500, 0.0014343261718750, -0.0005798339843750, +-0.0003662109375000, -0.0000305175781250, 0.0002136230468750, -0.0003051757812500, +-0.0000610351562500, -0.0010986328125000, -0.0012207031250000, -0.0003967285156250, +0.0003356933593750, -0.0011596679687500, -0.0008850097656250, -0.0011596679687500, +-0.0001831054687500, -0.0008239746093750, 0.0004272460937500, -0.0009765625000000, +0.0001525878906250, -0.0009155273437500, 0.0013427734375000, -0.0005187988281250, +0.0010070800781250, -0.0006103515625000, 0.0018615722656250, -0.0003967285156250, +0.0021667480468750, -0.0001220703125000, 0.0018920898437500, -0.0003051757812500, +0.0027160644531250, 0.0005187988281250, 0.0028381347656250, 0.0003662109375000, +0.0029602050781250}, +{-0.0038146972656250, -0.0034484863281250, -0.0037841796875000, -0.0030517578125000, +-0.0031738281250000, -0.0028686523437500, -0.0036010742187500, -0.0031127929687500, +-0.0030822753906250, -0.0021972656250000, -0.0025024414062500, -0.0016784667968750, +-0.0027160644531250, -0.0021057128906250, -0.0024414062500000, -0.0021667480468750, +-0.0019836425781250, -0.0017700195312500, -0.0024719238281250, -0.0029907226562500, +-0.0024719238281250, -0.0023193359375000, -0.0026855468750000, -0.0026245117187500, +-0.0026245117187500, -0.0036926269531250, -0.0022888183593750, -0.0026245117187500, +-0.0024414062500000, -0.0041503906250000, -0.0021667480468750, -0.0036315917968750, +-0.0022583007812500, -0.0032653808593750, -0.0022888183593750, -0.0038757324218750, +-0.0022277832031250, -0.0029296875000000, -0.0026855468750000, -0.0028076171875000, +-0.0028076171875000, -0.0025939941406250, -0.0032043457031250, -0.0021057128906250, +-0.0034179687500000, -0.0016479492187500, -0.0037841796875000, -0.0013122558593750, +-0.0045471191406250, -0.0011291503906250, -0.0037841796875000, -0.0006408691406250, +-0.0043945312500000, -0.0007934570312500, -0.0043334960937500, -0.0010375976562500, +-0.0036621093750000, -0.0005798339843750, -0.0042724609375000, -0.0006103515625000, +-0.0032958984375000, -0.0014648437500000, -0.0033874511718750, -0.0005798339843750, +-0.0032653808593750, 0.0002136230468750, -0.0026550292968750, -0.0009765625000000, +-0.0029296875000000, 0.0014648437500000, -0.0018920898437500, 0.0011901855468750, +-0.0019836425781250, 0.0007019042968750, -0.0015869140625000, 0.0019836425781250, +-0.0004272460937500, 0.0018005371093750, -0.0004272460937500, 0.0005187988281250, +-0.0003662109375000, 0.0010375976562500, 0.0006103515625000, 0.0004882812500000, +0.0002136230468750, -0.0008239746093750, -0.0002136230468750, -0.0001831054687500, +0.0012207031250000, -0.0007934570312500, -0.0003356933593750, -0.0010375976562500, +0.0009765625000000, -0.0007629394531250, 0.0007324218750000, -0.0007324218750000, +-0.0002746582031250, -0.0008239746093750, 0.0018615722656250, -0.0011901855468750, +-0.0003356933593750, -0.0007324218750000, 0.0010070800781250, -0.0010070800781250, +0.0009765625000000, -0.0017700195312500, -0.0002746582031250, -0.0013732910156250, +0.0019531250000000, -0.0016174316406250, -0.0005798339843750, -0.0017700195312500, +0.0009765625000000, -0.0015869140625000, 0.0006408691406250, -0.0017395019531250, +-0.0014038085937500, -0.0018310546875000, 0.0010070800781250, -0.0012207031250000, +-0.0014038085937500, -0.0012817382812500, -0.0007324218750000, -0.0012817382812500, +-0.0001831054687500, -0.0008850097656250, -0.0011291503906250, -0.0008544921875000, +0.0003356933593750, -0.0006103515625000, -0.0004272460937500, -0.0004882812500000, +0.0005798339843750, -0.0004577636718750, 0.0008239746093750, -0.0002441406250000, +0.0004882812500000, -0.0000915527343750, 0.0019531250000000, -0.0004272460937500, +0.0009765625000000, -0.0002136230468750, 0.0019226074218750, -0.0002746582031250, +0.0020141601562500, -0.0006103515625000, 0.0013427734375000, -0.0003967285156250, +0.0025024414062500, -0.0003051757812500, 0.0010375976562500, -0.0003662109375000, +0.0015869140625000, -0.0001525878906250, 0.0015258789062500, 0.0000000000000000, +0.0003967285156250, -0.0001220703125000, 0.0008239746093750, 0.0003051757812500, +0.0000305175781250, 0.0000915527343750, 0.0000915527343750, 0.0002441406250000, +0.0000610351562500, 0.0005187988281250, -0.0006103515625000, 0.0002746582031250, +-0.0003967285156250, 0.0009765625000000, -0.0002746582031250, 0.0009155273437500, +-0.0007324218750000, 0.0009765625000000, -0.0004272460937500, 0.0013427734375000, +0.0001525878906250, 0.0011901855468750, -0.0001525878906250, 0.0016479492187500, +0.0003356933593750, 0.0014038085937500, 0.0004272460937500, 0.0017089843750000, +0.0004272460937500, 0.0021667480468750, 0.0004272460937500, 0.0017089843750000, +0.0002746582031250, 0.0026550292968750, 0.0010681152343750, 0.0025634765625000, +0.0002441406250000, 0.0025634765625000, 0.0004577636718750, 0.0031127929687500, +0.0011596679687500, 0.0027770996093750, 0.0000000000000000, 0.0028991699218750, +0.0006408691406250, 0.0029602050781250, 0.0004272460937500, 0.0028076171875000, +0.0001525878906250, 0.0026855468750000, 0.0004272460937500, 0.0026245117187500, +0.0000915527343750, 0.0024414062500000, 0.0003356933593750, 0.0024414062500000, +0.0002136230468750, 0.0022583007812500, 0.0000000000000000, 0.0021057128906250, +0.0000305175781250, 0.0021362304687500, -0.0000305175781250, 0.0021057128906250, +-0.0006103515625000, 0.0020751953125000, -0.0003662109375000, 0.0021057128906250, +-0.0006103515625000, 0.0022277832031250, -0.0012207031250000, 0.0023193359375000, +-0.0007324218750000, 0.0017700195312500, -0.0010375976562500, 0.0021972656250000, +-0.0014038085937500, 0.0018920898437500, -0.0009155273437500, 0.0012512207031250, +-0.0007629394531250, 0.0018310546875000, -0.0014343261718750, 0.0010681152343750, +0.0001220703125000, 0.0010681152343750, -0.0005187988281250, 0.0011596679687500, +0.0000610351562500, 0.0007629394531250, 0.0015869140625000, 0.0007629394531250, +0.0006103515625000, 0.0007324218750000, 0.0026550292968750, 0.0006713867187500, +0.0028991699218750, 0.0004882812500000, 0.0031127929687500, 0.0005493164062500, +0.0043334960937500, 0.0007629394531250, 0.0042419433593750, 0.0000915527343750, +0.0044250488281250, 0.0004882812500000, 0.0048217773437500, 0.0003051757812500, +0.0045166015625000, -0.0003051757812500, 0.0041809082031250, 0.0001525878906250, +0.0043334960937500, -0.0003662109375000, 0.0033569335937500, -0.0003051757812500, +0.0032348632812500, -0.0002746582031250, 0.0027770996093750, -0.0005798339843750, +0.0018920898437500, -0.0003356933593750, 0.0018920898437500, -0.0010070800781250, +0.0016174316406250, -0.0007019042968750, 0.0012512207031250, -0.0009765625000000, +0.0010681152343750, -0.0016479492187500, 0.0011291503906250, -0.0011596679687500, +0.0010681152343750, -0.0018005371093750, 0.0006713867187500, -0.0017700195312500, +0.0010681152343750, -0.0017395019531250, 0.0006713867187500, -0.0019531250000000, +0.0002746582031250, -0.0017089843750000, 0.0011596679687500, -0.0018920898437500, +-0.0007019042968750, -0.0017089843750000, 0.0001220703125000, -0.0020446777343750, +-0.0005187988281250, -0.0023193359375000, -0.0021972656250000, -0.0018005371093750, +-0.0006408691406250, -0.0026245117187500, -0.0019836425781250, -0.0025634765625000, +-0.0015258789062500, -0.0020751953125000, -0.0006713867187500, -0.0021972656250000, +-0.0008239746093750, -0.0020446777343750, -0.0000610351562500, -0.0009460449218750, +0.0007324218750000, -0.0009460449218750, 0.0009460449218750, -0.0008239746093750, +0.0011596679687500, 0.0000305175781250, 0.0016784667968750, -0.0000610351562500, +0.0017089843750000, -0.0008544921875000, 0.0007934570312500, -0.0007019042968750, +0.0013122558593750, -0.0008544921875000, 0.0004272460937500, -0.0015563964843750, +-0.0010986328125000, -0.0015563964843750, -0.0005798339843750, -0.0018005371093750, +-0.0027160644531250, -0.0023803710937500, -0.0031433105468750, -0.0021362304687500, +-0.0028991699218750, -0.0020141601562500, -0.0037536621093750, -0.0028381347656250, +-0.0036315917968750, -0.0015563964843750, -0.0015869140625000, -0.0021972656250000, +-0.0015563964843750, -0.0020446777343750, -0.0010070800781250, -0.0011596679687500, +0.0009155273437500, -0.0021362304687500, 0.0009155273437500, -0.0008544921875000, +-0.0003356933593750, -0.0010986328125000, 0.0006408691406250, -0.0013732910156250, +-0.0000915527343750, -0.0005798339843750, -0.0021972656250000, -0.0010375976562500, +-0.0012512207031250, -0.0018920898437500, -0.0010986328125000, -0.0014038085937500, +-0.0021667480468750, -0.0018615722656250, -0.0014648437500000, -0.0034484863281250, +0.0005493164062500, 0.0000305175781250, 0.0007629394531250, 0.0018920898437500, +0.0006408691406250, 0.0017700195312500, -0.0000305175781250, 0.0014343261718750, +0.0003356933593750, 0.0017395019531250, 0.0009460449218750, 0.0018615722656250, +0.0001220703125000, 0.0011596679687500, -0.0005493164062500, 0.0009155273437500, +0.0001525878906250, 0.0012512207031250, -0.0008544921875000, 0.0015563964843750, +-0.0024414062500000, 0.0014343261718750, -0.0015563964843750, 0.0008850097656250, +-0.0018310546875000, 0.0021972656250000, -0.0023498535156250, 0.0005493164062500, +-0.0018310546875000, -0.0012512207031250, -0.0010681152343750, 0.0008850097656250, +-0.0012817382812500, -0.0032958984375000, -0.0013427734375000, -0.0029907226562500, +-0.0006408691406250, -0.0023498535156250, -0.0012207031250000, -0.0044555664062500, +-0.0021972656250000, -0.0035705566406250, -0.0013427734375000, -0.0015869140625000, +-0.0015869140625000, -0.0021362304687500, -0.0021972656250000, -0.0011291503906250, +-0.0014343261718750, 0.0012817382812500, -0.0006408691406250, 0.0008239746093750, +-0.0011901855468750, 0.0012207031250000, -0.0006408691406250, 0.0024108886718750, +-0.0003662109375000, 0.0016479492187500, -0.0011596679687500, 0.0007019042968750, +-0.0016479492187500, 0.0018310546875000, -0.0012512207031250, -0.0000610351562500, +-0.0023193359375000, -0.0001525878906250, -0.0027770996093750, 0.0003051757812500, +-0.0023193359375000, -0.0005493164062500, -0.0022583007812500, -0.0007324218750000, +-0.0026550292968750, 0.0007324218750000, -0.0025634765625000, 0.0002136230468750, +-0.0022583007812500, 0.0004882812500000, -0.0027160644531250, 0.0015869140625000, +-0.0032348632812500, 0.0008850097656250, -0.0029296875000000, 0.0018920898437500, +-0.0032043457031250, 0.0018310546875000, -0.0033569335937500, 0.0014343261718750, +-0.0030212402343750, 0.0017395019531250, -0.0027770996093750, 0.0016479492187500, +-0.0028686523437500, 0.0009765625000000, -0.0023803710937500, 0.0008239746093750, +-0.0023803710937500, 0.0012512207031250, -0.0021057128906250, 0.0009155273437500, +-0.0018310546875000, 0.0004272460937500, -0.0020446777343750, 0.0024719238281250, +-0.0009460449218750, 0.0015563964843750, -0.0010986328125000, 0.0021057128906250, +-0.0008239746093750, 0.0038146972656250, 0.0001525878906250, 0.0025329589843750, +-0.0001220703125000, 0.0040893554687500, -0.0000915527343750, 0.0038757324218750, +0.0002746582031250, 0.0036926269531250, 0.0000915527343750, 0.0044860839843750, +-0.0002136230468750, 0.0039062500000000, 0.0001525878906250, 0.0037841796875000, +-0.0000305175781250, 0.0041198730468750, 0.0000000000000000, 0.0032653808593750, +0.0002136230468750, 0.0025939941406250, 0.0003051757812500, 0.0031433105468750, +0.0003662109375000, 0.0013122558593750, 0.0005187988281250, 0.0016784667968750, +0.0006103515625000, 0.0013122558593750, 0.0007934570312500, 0.0000305175781250, +0.0009155273437500, 0.0008850097656250, 0.0009155273437500, -0.0003356933593750, +0.0013732910156250, -0.0002136230468750, 0.0014343261718750, 0.0000000000000000, +0.0013427734375000, -0.0005493164062500, 0.0015869140625000, -0.0002136230468750, +0.0016784667968750, -0.0001220703125000, 0.0013732910156250, -0.0001525878906250, +0.0013732910156250, -0.0001525878906250, 0.0014953613281250, -0.0001220703125000, +0.0013122558593750, 0.0000915527343750, 0.0012512207031250, 0.0000305175781250, +0.0015869140625000, 0.0002746582031250, 0.0014343261718750, 0.0005798339843750, +0.0015563964843750, 0.0006408691406250, 0.0018615722656250, 0.0007629394531250, +0.0016479492187500, 0.0009765625000000, 0.0020751953125000, 0.0009460449218750, +0.0021057128906250, 0.0009460449218750, 0.0021972656250000, 0.0014648437500000, +0.0024414062500000}, +{0.0015869140625000, -0.0003967285156250, 0.0020446777343750, 0.0008544921875000, +0.0018615722656250, -0.0027160644531250, 0.0005798339843750, -0.0024719238281250, +0.0008544921875000, -0.0018920898437500, 0.0005187988281250, -0.0037536621093750, +-0.0007629394531250, -0.0033569335937500, -0.0004577636718750, -0.0010681152343750, +-0.0001831054687500, -0.0017700195312500, -0.0008850097656250, -0.0008239746093750, +-0.0003356933593750, 0.0017089843750000, 0.0008850097656250, 0.0008850097656250, +0.0003051757812500, 0.0006408691406250, 0.0002136230468750, 0.0019226074218750, +0.0010070800781250, 0.0009460449218750, 0.0004882812500000, -0.0007934570312500, +-0.0003356933593750, 0.0003356933593750, 0.0002746582031250, -0.0005493164062500, +-0.0004577636718750, -0.0016784667968750, -0.0005798339843750, -0.0005493164062500, +-0.0004272460937500, 0.0000000000000000, -0.0004272460937500, -0.0015258789062500, +-0.0004882812500000, 0.0013427734375000, -0.0012512207031250, 0.0005798339843750, +-0.0007019042968750, 0.0001831054687500, -0.0011901855468750, 0.0018920898437500, +-0.0024719238281250, 0.0009460449218750, -0.0018920898437500, 0.0005798339843750, +-0.0023498535156250, 0.0005798339843750, -0.0026855468750000, 0.0006713867187500, +-0.0025939941406250, 0.0003356933593750, -0.0025024414062500, -0.0000610351562500, +-0.0025939941406250, 0.0009765625000000, -0.0028991699218750, 0.0003356933593750, +-0.0028381347656250, 0.0011291503906250, -0.0029602050781250, 0.0021667480468750, +-0.0032348632812500, 0.0009460449218750, -0.0030212402343750, 0.0039978027343750, +-0.0030212402343750, 0.0031738281250000, -0.0031738281250000, 0.0034179687500000, +-0.0028076171875000, 0.0055541992187500, -0.0025024414062500, 0.0040893554687500, +-0.0026550292968750, 0.0045776367187500, -0.0020751953125000, 0.0047912597656250, +-0.0020446777343750, 0.0039367675781250, -0.0017089843750000, 0.0034484863281250, +-0.0012817382812500, 0.0034790039062500, -0.0014953613281250, 0.0026245117187500, +-0.0003356933593750, 0.0022583007812500, -0.0003051757812500, 0.0020141601562500, +-0.0003051757812500, 0.0014038085937500, 0.0003356933593750, 0.0010986328125000, +0.0003662109375000, 0.0014038085937500, -0.0000610351562500, 0.0006103515625000, +0.0000915527343750, 0.0009765625000000, 0.0001525878906250, 0.0017395019531250, +-0.0002136230468750, 0.0007934570312500, -0.0002746582031250, 0.0022583007812500, +0.0001831054687500, 0.0020751953125000, -0.0000610351562500, 0.0021667480468750, +0.0000610351562500, 0.0030822753906250, 0.0005187988281250, 0.0026550292968750, +0.0002746582031250, 0.0030822753906250, 0.0004882812500000, 0.0033874511718750, +0.0004882812500000, 0.0031433105468750, 0.0004882812500000, 0.0032653808593750, +0.0005493164062500, 0.0036315917968750, 0.0004882812500000, 0.0022888183593750, +0.0007019042968750, 0.0029602050781250, 0.0007324218750000, 0.0023498535156250, +0.0007019042968750, 0.0012817382812500, 0.0008239746093750, 0.0025024414062500, +0.0008850097656250, 0.0003662109375000, 0.0010070800781250, 0.0008544921875000, +0.0009460449218750, 0.0006408691406250, 0.0012512207031250, -0.0008850097656250, +0.0015563964843750, 0.0000305175781250, 0.0014343261718750, -0.0012817382812500, +0.0019836425781250, -0.0008850097656250, 0.0019226074218750, -0.0009155273437500, +0.0020751953125000, -0.0016174316406250, 0.0023193359375000, -0.0006713867187500, +0.0020446777343750, -0.0016174316406250, 0.0025024414062500, -0.0013732910156250, +0.0023803710937500, -0.0011901855468750, 0.0023498535156250, -0.0017089843750000, +0.0025329589843750, -0.0013732910156250, 0.0022583007812500, -0.0015563964843750, +0.0022583007812500, -0.0014648437500000, 0.0023193359375000, -0.0013732910156250, +0.0020141601562500, -0.0013122558593750, 0.0019531250000000, -0.0009765625000000, +0.0020141601562500, -0.0010986328125000, 0.0015869140625000, -0.0005798339843750, +0.0016479492187500, -0.0003662109375000, 0.0015869140625000, -0.0005798339843750, +0.0013427734375000, -0.0000610351562500, 0.0014343261718750, 0.0002746582031250, +0.0010681152343750, -0.0004272460937500, 0.0012207031250000, 0.0001831054687500, +0.0009460449218750, 0.0007934570312500, 0.0005798339843750, -0.0000610351562500, +0.0008850097656250, 0.0017395019531250, 0.0000305175781250, 0.0016479492187500, +0.0001525878906250, 0.0016784667968750, 0.0000305175781250, 0.0028076171875000, +-0.0005187988281250, 0.0026245117187500, -0.0002136230468750, 0.0025329589843750, +-0.0007934570312500, 0.0030212402343750, -0.0005493164062500, 0.0028381347656250, +-0.0006713867187500, 0.0025024414062500, -0.0012512207031250, 0.0030517578125000, +-0.0007324218750000, 0.0020141601562500, -0.0008850097656250, 0.0023498535156250, +-0.0010986328125000, 0.0021057128906250, -0.0007629394531250, 0.0013427734375000, +-0.0003967285156250, 0.0018920898437500, -0.0005187988281250, 0.0013122558593750, +-0.0006713867187500, 0.0009765625000000, -0.0004882812500000, 0.0014953613281250, +-0.0004882812500000, 0.0014038085937500, -0.0007324218750000, 0.0007324218750000, +-0.0007324218750000, 0.0022583007812500, -0.0006408691406250, 0.0014343261718750, +-0.0005798339843750, 0.0017395019531250, -0.0006408691406250, 0.0032043457031250, +-0.0007324218750000, 0.0020751953125000, -0.0006408691406250, 0.0032958984375000, +-0.0005187988281250, 0.0037841796875000, -0.0005493164062500, 0.0032958984375000, +-0.0006103515625000, 0.0036621093750000, -0.0004882812500000, 0.0043640136718750, +-0.0004272460937500, 0.0026855468750000, -0.0004577636718750, 0.0036315917968750, +-0.0005187988281250, 0.0032043457031250, -0.0001831054687500, 0.0015869140625000, +0.0000610351562500, 0.0026855468750000, -0.0000915527343750, 0.0012207031250000, +0.0008239746093750, 0.0008239746093750, 0.0008544921875000, 0.0008239746093750, +0.0010070800781250, 0.0002136230468750, 0.0016174316406250, 0.0000305175781250, +0.0015563964843750, 0.0002441406250000, 0.0013732910156250, -0.0000305175781250, +0.0018310546875000, 0.0000915527343750, 0.0011596679687500, 0.0003662109375000, +0.0003967285156250, -0.0001220703125000, 0.0010681152343750, 0.0001831054687500, +-0.0009460449218750, -0.0003051757812500, -0.0007934570312500, -0.0002441406250000, +-0.0009765625000000, 0.0000610351562500, -0.0021667480468750, -0.0003356933593750, +-0.0016479492187500, 0.0009155273437500, -0.0021667480468750, 0.0001220703125000, +-0.0020446777343750, 0.0007934570312500, -0.0018920898437500, 0.0020446777343750, +-0.0018615722656250, 0.0002746582031250, -0.0013732910156250, 0.0015563964843750, +-0.0022583007812500, 0.0021057128906250, -0.0021667480468750, 0.0010681152343750, +-0.0018615722656250, 0.0008239746093750, -0.0022583007812500, 0.0012512207031250, +-0.0022583007812500, -0.0005798339843750, -0.0022888183593750, -0.0010986328125000, +-0.0025939941406250, -0.0008544921875000, -0.0024719238281250, -0.0016479492187500, +-0.0022277832031250, -0.0021667480468750, -0.0025329589843750, -0.0008544921875000, +-0.0022888183593750, -0.0015258789062500, -0.0025634765625000, -0.0013427734375000, +-0.0022583007812500, -0.0003356933593750, -0.0009460449218750, -0.0014953613281250, +-0.0003967285156250, -0.0012512207031250, -0.0019226074218750, -0.0015563964843750, +-0.0007324218750000, -0.0014038085937500, -0.0008544921875000, -0.0013732910156250, +-0.0021362304687500, -0.0024414062500000, -0.0008239746093750, -0.0009765625000000, +-0.0020751953125000, -0.0017089843750000, -0.0021667480468750, -0.0022888183593750, +-0.0020751953125000, -0.0016174316406250, -0.0028381347656250, -0.0023803710937500, +-0.0028991699218750, -0.0031433105468750, -0.0030517578125000, -0.0033264160156250, +-0.0032958984375000, -0.0034179687500000, -0.0031433105468750, -0.0036926269531250, +-0.0028686523437500, -0.0039062500000000, -0.0027770996093750, -0.0031433105468750, +-0.0021362304687500, -0.0029907226562500, -0.0012207031250000, -0.0031738281250000, +-0.0011596679687500, -0.0026855468750000, -0.0007629394531250, -0.0019836425781250, +0.0005187988281250, -0.0026550292968750, -0.0004882812500000, -0.0019836425781250, +0.0002441406250000, -0.0015869140625000, 0.0002441406250000, -0.0019531250000000, +-0.0007629394531250, -0.0011596679687500, 0.0000610351562500, -0.0004882812500000, +-0.0001831054687500, -0.0004272460937500, -0.0006408691406250, 0.0000305175781250, +0.0000915527343750, 0.0004577636718750, 0.0008544921875000, 0.0003051757812500, +0.0004882812500000, 0.0013122558593750, 0.0014343261718750, 0.0010681152343750, +0.0021362304687500, 0.0012207031250000, 0.0015563964843750, 0.0020751953125000, +0.0015563964843750, 0.0017089843750000, 0.0026550292968750, 0.0014343261718750, +0.0008544921875000, 0.0018920898437500, 0.0015563964843750, 0.0012512207031250, +0.0017089843750000, 0.0004272460937500, 0.0005493164062500, 0.0008850097656250, +0.0013732910156250, -0.0003356933593750, 0.0011291503906250, -0.0003967285156250, +0.0009155273437500, -0.0001831054687500, 0.0010681152343750, -0.0004882812500000, +0.0010681152343750, -0.0006103515625000, 0.0009460449218750, -0.0007629394531250, +0.0009155273437500, -0.0005493164062500, 0.0008544921875000, -0.0007629394531250, +0.0004882812500000, -0.0011901855468750, 0.0002746582031250, -0.0010070800781250, +0.0002746582031250, -0.0015258789062500, -0.0004882812500000, -0.0015258789062500, +-0.0007019042968750, -0.0014648437500000, -0.0007629394531250, -0.0020141601562500, +-0.0010681152343750, -0.0019836425781250, -0.0009765625000000, -0.0011596679687500, +-0.0007324218750000, -0.0016784667968750, -0.0007019042968750, -0.0012207031250000, +-0.0002136230468750, -0.0002441406250000, 0.0003051757812500, -0.0009155273437500, +0.0002136230468750, 0.0001831054687500, 0.0008850097656250, 0.0000000000000000, +0.0008850097656250, 0.0001831054687500, 0.0010070800781250, 0.0008850097656250, +0.0012817382812500, 0.0003662109375000, 0.0007934570312500, 0.0009155273437500, +0.0013732910156250, 0.0009460449218750, 0.0007324218750000, 0.0007934570312500, +0.0006408691406250, 0.0010070800781250, 0.0007934570312500, 0.0009765625000000, +-0.0002441406250000, 0.0007934570312500, 0.0003051757812500, 0.0007629394531250, +-0.0005187988281250, 0.0007629394531250, -0.0008850097656250, 0.0007934570312500, +-0.0003967285156250, 0.0006713867187500, -0.0010681152343750, 0.0009765625000000, +-0.0008544921875000, 0.0010070800781250, -0.0007629394531250, 0.0008239746093750, +-0.0012512207031250, 0.0008850097656250, -0.0014038085937500, 0.0009155273437500, +-0.0008544921875000, 0.0006103515625000, -0.0014648437500000, 0.0005493164062500, +-0.0015563964843750, 0.0004577636718750, -0.0012512207031250, 0.0002746582031250, +-0.0013427734375000, 0.0002136230468750, -0.0015258789062500, 0.0003356933593750, +-0.0010375976562500, 0.0001525878906250, -0.0012512207031250, 0.0003051757812500, +-0.0015258789062500, 0.0005187988281250, -0.0014038085937500, 0.0001831054687500, +-0.0014648437500000, 0.0009765625000000, -0.0018920898437500, 0.0006713867187500, +-0.0015258789062500, 0.0009155273437500, -0.0018615722656250, 0.0015869140625000, +-0.0023193359375000, 0.0010986328125000, -0.0017089843750000, 0.0017089843750000, +-0.0025024414062500, 0.0017395019531250, -0.0020751953125000, 0.0015258789062500, +-0.0020751953125000, 0.0016784667968750, -0.0025024414062500, 0.0016174316406250, +-0.0015563964843750, 0.0011596679687500, -0.0019226074218750, 0.0011901855468750, +-0.0017395019531250, 0.0010681152343750, -0.0010681152343750, 0.0007019042968750, +-0.0009155273437500, 0.0007324218750000, -0.0009155273437500, 0.0006713867187500, +0.0004272460937500}, +{-0.0004577636718750, -0.0014648437500000, 0.0015563964843750, -0.0012817382812500, +0.0017395019531250, -0.0003967285156250, 0.0015258789062500, -0.0000305175781250, +0.0024108886718750, 0.0000610351562500, 0.0026245117187500, 0.0008850097656250, +0.0016174316406250, 0.0011291503906250, 0.0021667480468750, 0.0011291503906250, +0.0021972656250000, 0.0015869140625000, 0.0015258789062500, 0.0017089843750000, +0.0022888183593750, 0.0009765625000000, 0.0020446777343750, 0.0015563964843750, +0.0019531250000000, 0.0010375976562500, 0.0020141601562500, 0.0001525878906250, +0.0018920898437500, 0.0011596679687500, 0.0016479492187500, -0.0000610351562500, +0.0009155273437500, 0.0001525878906250, 0.0010681152343750, 0.0000610351562500, +0.0006103515625000, -0.0006713867187500, -0.0001831054687500, 0.0000915527343750, +0.0001220703125000, -0.0005187988281250, -0.0004577636718750, -0.0003967285156250, +-0.0006713867187500, -0.0004577636718750, -0.0004882812500000, -0.0007324218750000, +-0.0004882812500000, -0.0002441406250000, -0.0003662109375000, -0.0007324218750000, +0.0002441406250000, -0.0006103515625000, 0.0006103515625000, -0.0005798339843750, +0.0007934570312500, -0.0008239746093750, 0.0012207031250000, -0.0003662109375000, +0.0016174316406250, -0.0009765625000000, 0.0011291503906250, -0.0009155273437500, +0.0014038085937500, -0.0006103515625000, 0.0012512207031250, -0.0008239746093750, +0.0005493164062500, -0.0008239746093750, 0.0006103515625000, -0.0003662109375000, +0.0002746582031250, -0.0004272460937500, -0.0003051757812500, -0.0003051757812500, +-0.0003051757812500, -0.0000305175781250, -0.0004577636718750, -0.0002136230468750, +-0.0011596679687500, 0.0000915527343750, -0.0003356933593750, 0.0000000000000000, +-0.0011291503906250, 0.0001525878906250, -0.0010681152343750, 0.0003967285156250, +-0.0004272460937500, 0.0003662109375000, -0.0014648437500000, 0.0005798339843750, +-0.0001525878906250, 0.0007019042968750, -0.0007934570312500, 0.0006103515625000, +-0.0007629394531250, 0.0005798339843750, 0.0001220703125000, 0.0007324218750000, +-0.0005798339843750, 0.0005187988281250, 0.0003662109375000, 0.0004882812500000, +0.0002136230468750, 0.0005187988281250, 0.0002136230468750, 0.0003356933593750, +0.0004882812500000, 0.0001220703125000, -0.0000305175781250, 0.0004577636718750, +0.0006408691406250, 0.0002441406250000, 0.0001220703125000, 0.0000915527343750, +0.0000610351562500, 0.0002746582031250, 0.0006408691406250, 0.0000915527343750, +-0.0001220703125000, 0.0000305175781250, -0.0002441406250000, 0.0000305175781250, +-0.0000305175781250, -0.0000305175781250, -0.0006713867187500, -0.0000915527343750, +-0.0010986328125000, -0.0000610351562500, -0.0005493164062500, 0.0000915527343750, +-0.0013732910156250, -0.0000610351562500, -0.0012512207031250, 0.0002136230468750, +-0.0011291503906250, 0.0005187988281250, -0.0014648437500000, 0.0002746582031250, +-0.0012817382812500, 0.0007629394531250, -0.0011901855468750, 0.0008239746093750, +-0.0013122558593750, 0.0007324218750000, -0.0011291503906250, 0.0009460449218750, +-0.0009765625000000, 0.0010070800781250, -0.0011901855468750, 0.0007324218750000, +-0.0007629394531250, 0.0008850097656250, -0.0009460449218750, 0.0007019042968750, +-0.0007324218750000, 0.0003967285156250, -0.0003662109375000, 0.0006713867187500, +-0.0008239746093750, 0.0000000000000000, -0.0003356933593750, 0.0001220703125000, +-0.0005798339843750, -0.0000305175781250, -0.0006103515625000, -0.0004577636718750, +-0.0005493164062500, -0.0000305175781250, -0.0010375976562500, -0.0008544921875000, +-0.0003662109375000, -0.0005187988281250, -0.0012207031250000, -0.0007629394531250, +-0.0009155273437500, -0.0013427734375000, -0.0003662109375000, -0.0006713867187500, +-0.0018920898437500, -0.0013427734375000, 0.0001831054687500, -0.0010681152343750, +-0.0013122558593750, -0.0010986328125000, -0.0007629394531250, -0.0014038085937500, +0.0009155273437500, -0.0007934570312500, -0.0014038085937500, -0.0019226074218750, +0.0020751953125000, -0.0015563964843750, 0.0007019042968750, -0.0016479492187500, +0.0009460449218750, -0.0025329589843750, 0.0035705566406250, -0.0020751953125000, +0.0014648437500000, -0.0025024414062500, 0.0033874511718750, -0.0024108886718750, +0.0036621093750000, -0.0025329589843750, 0.0029296875000000, -0.0027160644531250, +0.0035705566406250, -0.0021362304687500, 0.0037841796875000, -0.0028991699218750, +0.0024719238281250, -0.0026550292968750, 0.0028991699218750, -0.0024108886718750, +0.0024414062500000, -0.0027160644531250, 0.0012817382812500, -0.0025024414062500, +0.0020751953125000, -0.0022277832031250, 0.0011901855468750, -0.0021667480468750, +0.0011596679687500, -0.0020751953125000, 0.0014953613281250, -0.0018310546875000, +0.0012817382812500, -0.0017395019531250, 0.0014648437500000, -0.0020446777343750, +0.0022888183593750, -0.0015869140625000, 0.0021057128906250, -0.0015869140625000, +0.0024719238281250, -0.0019226074218750, 0.0032653808593750, -0.0013427734375000, +0.0028991699218750, -0.0015563964843750, 0.0028991699218750, -0.0010375976562500, +0.0028991699218750, -0.0010070800781250, 0.0023803710937500, -0.0011901855468750, +0.0018005371093750, -0.0003051757812500, 0.0015869140625000, -0.0010375976562500, +0.0010375976562500, -0.0008850097656250, 0.0009765625000000, -0.0007324218750000, +0.0006713867187500, -0.0011901855468750, 0.0001831054687500, -0.0008239746093750, +0.0003356933593750, -0.0006103515625000, 0.0004272460937500, -0.0010375976562500, +0.0000610351562500, -0.0003356933593750, -0.0002746582031250, 0.0004272460937500, +-0.0001525878906250, -0.0003967285156250, -0.0000915527343750, 0.0006713867187500, +-0.0004577636718750, 0.0003662109375000, -0.0006408691406250, 0.0003967285156250, +-0.0009460449218750, 0.0010375976562500, -0.0013122558593750, 0.0003662109375000, +-0.0012512207031250, 0.0010681152343750, -0.0014343261718750, 0.0009765625000000, +-0.0021667480468750, 0.0013427734375000, -0.0013122558593750, 0.0020446777343750, +-0.0008239746093750, 0.0016784667968750, -0.0020446777343750, 0.0029907226562500, +0.0011596679687500, 0.0030822753906250, 0.0004577636718750, 0.0027465820312500, +0.0003356933593750, 0.0031433105468750, 0.0022583007812500, 0.0030517578125000, +0.0012207031250000, 0.0018310546875000, 0.0010375976562500, 0.0020141601562500, +0.0010375976562500, 0.0017089843750000, 0.0010070800781250, 0.0002441406250000, +0.0011291503906250, -0.0007629394531250, 0.0020141601562500, -0.0019531250000000, +0.0019836425781250, -0.0018310546875000, 0.0013427734375000, -0.0015563964843750, +0.0020141601562500, -0.0016479492187500, 0.0021972656250000, -0.0015258789062500, +0.0010986328125000, -0.0006408691406250, 0.0036315917968750, -0.0006713867187500, +0.0039367675781250, -0.0005493164062500, 0.0032348632812500, 0.0000000000000000, +0.0042419433593750, -0.0001220703125000, 0.0046691894531250, -0.0007629394531250, +0.0027770996093750, -0.0005493164062500, 0.0030517578125000, -0.0008239746093750, +0.0028991699218750, -0.0017700195312500, 0.0015869140625000, -0.0016784667968750, +0.0020751953125000, -0.0006103515625000, 0.0023498535156250, -0.0017089843750000, +0.0019836425781250, -0.0006103515625000, 0.0019836425781250, 0.0010681152343750, +0.0024108886718750, -0.0007324218750000, 0.0022277832031250, 0.0010375976562500, +0.0010375976562500, 0.0010986328125000, 0.0010681152343750, -0.0001525878906250, +0.0008544921875000, -0.0002746582031250, 0.0000610351562500, -0.0003356933593750, +0.0002441406250000, -0.0017395019531250, 0.0005187988281250, -0.0018615722656250, +0.0003662109375000, -0.0017395019531250, 0.0005493164062500, -0.0024719238281250, +0.0010681152343750, -0.0022888183593750, 0.0009460449218750, -0.0007629394531250, +0.0001220703125000, -0.0013122558593750, 0.0007324218750000, -0.0004882812500000, +0.0000915527343750, 0.0014648437500000, -0.0010375976562500, 0.0007934570312500, +-0.0003967285156250, 0.0007934570312500, -0.0013122558593750, 0.0020141601562500, +-0.0011596679687500, 0.0011291503906250, -0.0010681152343750, 0.0001220703125000, +-0.0014953613281250, 0.0015258789062500, -0.0011291503906250, -0.0003662109375000, +-0.0016174316406250, 0.0003356933593750, -0.0014648437500000, 0.0004272460937500, +-0.0016174316406250, -0.0006408691406250, -0.0020751953125000, 0.0007324218750000, +-0.0017395019531250, 0.0001831054687500, -0.0021057128906250, 0.0007934570312500, +-0.0021057128906250, 0.0012512207031250, -0.0021057128906250, 0.0014953613281250, +-0.0021667480468750, 0.0026245117187500, -0.0020446777343750, 0.0016174316406250, +-0.0025024414062500, 0.0028991699218750, -0.0023803710937500, 0.0023193359375000, +-0.0023498535156250, 0.0010375976562500, -0.0027160644531250, 0.0027160644531250, +-0.0026245117187500, -0.0002746582031250, -0.0021972656250000, 0.0007019042968750, +-0.0024414062500000, 0.0000305175781250, -0.0022277832031250, -0.0020446777343750, +-0.0017089843750000, 0.0000305175781250, -0.0019226074218750, -0.0031738281250000, +-0.0015869140625000, -0.0023193359375000, -0.0015258789062500, -0.0022277832031250, +-0.0014343261718750, -0.0041503906250000, -0.0011596679687500, -0.0025024414062500, +-0.0013122558593750, -0.0036010742187500, -0.0009765625000000, -0.0033264160156250, +-0.0007934570312500, -0.0029907226562500, -0.0009460449218750, -0.0034484863281250, +-0.0009765625000000, -0.0028991699218750, -0.0008239746093750, -0.0028991699218750, +-0.0010681152343750, -0.0027770996093750, -0.0013122558593750, -0.0027770996093750, +-0.0010681152343750, -0.0028381347656250, -0.0010070800781250, -0.0026550292968750, +-0.0012817382812500, -0.0029907226562500, -0.0005187988281250, -0.0027770996093750, +-0.0007629394531250, -0.0024719238281250, -0.0005798339843750, -0.0025939941406250, +-0.0000610351562500, -0.0024108886718750, -0.0005493164062500, -0.0018615722656250, +0.0003356933593750, -0.0020446777343750, 0.0000610351562500, -0.0017395019531250, +0.0002136230468750, -0.0014038085937500, 0.0008850097656250, -0.0018310546875000, +0.0003051757812500, -0.0013122558593750, 0.0009155273437500, -0.0013732910156250, +0.0007629394531250, -0.0015869140625000, 0.0006713867187500, -0.0012512207031250, +0.0009155273437500, -0.0010681152343750, 0.0006408691406250, -0.0014038085937500, +0.0008544921875000, -0.0012817382812500, 0.0007324218750000, -0.0012817382812500, +0.0007019042968750, -0.0015258789062500, 0.0008850097656250, -0.0012512207031250, +0.0007629394531250, -0.0013732910156250, 0.0009460449218750, -0.0010681152343750, +0.0008544921875000, -0.0010681152343750, 0.0009460449218750, -0.0010986328125000, +0.0010681152343750, -0.0006103515625000, 0.0008544921875000, -0.0011291503906250, +0.0008239746093750, -0.0008544921875000, 0.0009460449218750, -0.0008239746093750, +0.0004882812500000, -0.0010986328125000, 0.0001220703125000, -0.0007019042968750, +0.0003967285156250, -0.0008850097656250, -0.0005187988281250, -0.0004882812500000, +-0.0004577636718750, -0.0003662109375000, -0.0004577636718750, -0.0003967285156250, +-0.0009460449218750, 0.0001831054687500, -0.0007019042968750, -0.0003356933593750, +-0.0010070800781250, -0.0006103515625000, -0.0009765625000000, -0.0000305175781250, +-0.0008544921875000, -0.0002746582031250, -0.0010681152343750, -0.0011596679687500, +-0.0010681152343750, 0.0001831054687500, -0.0005493164062500, -0.0004272460937500, +-0.0006713867187500, -0.0006408691406250, -0.0007019042968750, 0.0003051757812500, +-0.0003051757812500, -0.0003356933593750, -0.0003662109375000, -0.0004577636718750, +-0.0007629394531250, -0.0002441406250000, -0.0006408691406250, -0.0003662109375000, +-0.0006103515625000}, +{-0.0011291503906250, 0.0004882812500000, -0.0010681152343750, 0.0006103515625000, +-0.0012207031250000, 0.0016479492187500, -0.0010375976562500, -0.0004882812500000, +-0.0015563964843750, 0.0009155273437500, -0.0015258789062500, 0.0000305175781250, +-0.0015869140625000, -0.0022277832031250, -0.0018615722656250, -0.0002746582031250, +-0.0018615722656250, -0.0029296875000000, -0.0018615722656250, -0.0029296875000000, +-0.0017700195312500, -0.0027770996093750, -0.0020446777343750, -0.0040283203125000, +-0.0023498535156250, -0.0033264160156250, -0.0020446777343750, -0.0040283203125000, +-0.0027770996093750, -0.0036926269531250, -0.0029296875000000, -0.0036315917968750, +-0.0026855468750000, -0.0039062500000000, -0.0028076171875000, -0.0031433105468750, +-0.0029296875000000, -0.0036315917968750, -0.0021972656250000, -0.0031127929687500, +-0.0021972656250000, -0.0032348632812500, -0.0021972656250000, -0.0036621093750000, +-0.0018005371093750, -0.0028686523437500, -0.0018005371093750, -0.0042114257812500, +-0.0018615722656250, -0.0035400390625000, -0.0017700195312500, -0.0039367675781250, +-0.0016479492187500, -0.0050354003906250, -0.0016784667968750, -0.0038452148437500, +-0.0015869140625000, -0.0054626464843750, -0.0015563964843750, -0.0049743652343750, +-0.0014648437500000, -0.0052185058593750, -0.0013732910156250, -0.0063781738281250, +-0.0014343261718750, -0.0052795410156250, -0.0014038085937500, -0.0063171386718750, +-0.0010375976562500, -0.0059509277343750, -0.0012207031250000, -0.0054931640625000, +-0.0009765625000000, -0.0058593750000000, -0.0004577636718750, -0.0054321289062500, +-0.0007019042968750, -0.0048828125000000, -0.0002441406250000, -0.0050354003906250, +-0.0002746582031250, -0.0046081542968750, -0.0002136230468750, -0.0040588378906250, +0.0000000000000000, -0.0043029785156250, -0.0001525878906250, -0.0036010742187500, +0.0001831054687500, -0.0032653808593750, 0.0001831054687500, -0.0031433105468750, +0.0001831054687500, -0.0030212402343750, 0.0003662109375000, -0.0030212402343750, +0.0003967285156250, -0.0028991699218750, 0.0003051757812500, -0.0029296875000000, +0.0003051757812500, -0.0028381347656250, 0.0004272460937500, -0.0028076171875000, +0.0003662109375000, -0.0029907226562500, 0.0003356933593750, -0.0025939941406250, +0.0005493164062500, -0.0026855468750000, 0.0006713867187500, -0.0024719238281250, +0.0004577636718750, -0.0019836425781250, 0.0003967285156250, -0.0021362304687500, +0.0005187988281250, -0.0018005371093750, -0.0000915527343750, -0.0014343261718750, +-0.0000610351562500, -0.0015563964843750, -0.0001525878906250, -0.0015563964843750, +-0.0006408691406250, -0.0013427734375000, -0.0005493164062500, -0.0019836425781250, +-0.0006103515625000, -0.0018615722656250, -0.0007324218750000, -0.0021667480468750, +-0.0007629394531250, -0.0024414062500000, -0.0007324218750000, -0.0019226074218750, +-0.0007629394531250, -0.0031738281250000, -0.0007629394531250, -0.0022277832031250, +-0.0008239746093750, -0.0020751953125000, -0.0007019042968750, -0.0030822753906250, +-0.0004577636718750, -0.0021057128906250, -0.0006103515625000, -0.0021362304687500, +-0.0007324218750000, -0.0030822753906250, -0.0004577636718750, -0.0020446777343750, +-0.0006713867187500, -0.0012207031250000, -0.0010986328125000, -0.0027465820312500, +-0.0007324218750000, -0.0005187988281250, -0.0007324218750000, -0.0007324218750000, +-0.0009155273437500, -0.0009765625000000, -0.0007019042968750, 0.0001220703125000, +-0.0004882812500000, -0.0002441406250000, -0.0004882812500000, -0.0000305175781250, +-0.0002441406250000, -0.0000610351562500, -0.0001831054687500, -0.0003662109375000, +-0.0002441406250000, -0.0001831054687500, -0.0000610351562500, -0.0000610351562500, +-0.0000305175781250, -0.0007019042968750, -0.0003662109375000, -0.0002746582031250, +-0.0003356933593750, -0.0002746582031250, -0.0001525878906250, -0.0008850097656250, +-0.0003967285156250, -0.0002746582031250, -0.0004577636718750, -0.0001220703125000, +0.0001831054687500, -0.0004577636718750, -0.0000915527343750, 0.0002746582031250, +0.0002136230468750, 0.0009460449218750, 0.0007934570312500, 0.0002746582031250, +0.0003051757812500, 0.0018615722656250, 0.0010986328125000, 0.0017395019531250, +0.0009155273437500, 0.0018005371093750, 0.0009765625000000, 0.0028076171875000, +0.0013122558593750, 0.0026245117187500, 0.0007324218750000, 0.0021362304687500, +0.0009765625000000, 0.0029907226562500, 0.0009460449218750, 0.0022277832031250, +0.0005187988281250, 0.0014648437500000, 0.0003051757812500, 0.0030517578125000, +0.0003051757812500, 0.0011901855468750, -0.0000305175781250, 0.0017089843750000, +-0.0001831054687500, 0.0024414062500000, -0.0000915527343750, 0.0016479492187500, +-0.0001220703125000, 0.0020446777343750, -0.0001831054687500, 0.0023498535156250, +0.0002746582031250, 0.0021972656250000, 0.0001220703125000, 0.0020751953125000, +-0.0002746582031250, 0.0020751953125000, -0.0004882812500000, 0.0018005371093750, +-0.0007629394531250, 0.0012512207031250, -0.0010070800781250, 0.0006713867187500, +-0.0018615722656250, 0.0006408691406250, -0.0016174316406250, 0.0007629394531250, +-0.0012512207031250, 0.0008850097656250, -0.0020141601562500, 0.0014343261718750, +-0.0003967285156250, 0.0007934570312500, -0.0007934570312500, 0.0013732910156250, +-0.0008850097656250, 0.0027770996093750, 0.0001220703125000, 0.0021972656250000, +-0.0003356933593750, 0.0022888183593750, 0.0001220703125000, 0.0033264160156250, +-0.0001220703125000, 0.0018920898437500, -0.0003967285156250, 0.0007324218750000, +0.0000915527343750, 0.0025939941406250, 0.0001525878906250, -0.0002136230468750, +-0.0004882812500000, 0.0006103515625000, -0.0002441406250000, 0.0010070800781250, +-0.0001831054687500, -0.0005798339843750, -0.0009155273437500, 0.0004577636718750, +-0.0011291503906250, 0.0003967285156250, -0.0002441406250000, 0.0008850097656250, +-0.0007629394531250, 0.0003662109375000, -0.0009155273437500, -0.0001220703125000, +-0.0002136230468750, 0.0008850097656250, -0.0006408691406250, -0.0005187988281250, +-0.0008239746093750, -0.0000610351562500, -0.0000915527343750, -0.0001525878906250, +-0.0005187988281250, -0.0009460449218750, -0.0009460449218750, 0.0001220703125000, +0.0002441406250000, -0.0012207031250000, -0.0006103515625000, -0.0010375976562500, +-0.0005798339843750, -0.0007324218750000, 0.0000915527343750, -0.0014648437500000, +-0.0000305175781250, -0.0013427734375000, -0.0004272460937500, -0.0011596679687500, +0.0005493164062500, -0.0015869140625000, 0.0001525878906250, -0.0012512207031250, +0.0002136230468750, -0.0010681152343750, 0.0010070800781250, -0.0019226074218750, +0.0008850097656250, -0.0005493164062500, 0.0010681152343750, -0.0012817382812500, +0.0016479492187500, -0.0011291503906250, 0.0015563964843750, -0.0000915527343750, +0.0014648437500000, -0.0010375976562500, 0.0021362304687500, 0.0000305175781250, +0.0012512207031250, 0.0001220703125000, 0.0021972656250000, -0.0004272460937500, +0.0017700195312500, 0.0000305175781250, 0.0009460449218750, 0.0007019042968750, +0.0024719238281250, -0.0007934570312500, 0.0000610351562500, 0.0000305175781250, +0.0007629394531250, 0.0000915527343750, 0.0006103515625000, -0.0008850097656250, +-0.0009155273437500, 0.0003967285156250, 0.0004272460937500, 0.0002441406250000, +-0.0006103515625000, 0.0001831054687500, -0.0003356933593750, 0.0008850097656250, +0.0002136230468750, 0.0013732910156250, 0.0000915527343750, 0.0012207031250000, +0.0005798339843750, 0.0010375976562500, 0.0005493164062500, 0.0018310546875000, +0.0012207031250000, 0.0009765625000000, 0.0007629394531250, -0.0001525878906250, +0.0003051757812500, 0.0008850097656250, 0.0012512207031250, -0.0004882812500000, +-0.0006713867187500, -0.0007019042968750, -0.0001220703125000, -0.0002746582031250, +-0.0003051757812500, -0.0007019042968750, -0.0016479492187500, -0.0008850097656250, +-0.0007019042968750, 0.0002746582031250, -0.0014648437500000, -0.0001220703125000, +-0.0015869140625000, -0.0002136230468750, -0.0013122558593750, 0.0004577636718750, +-0.0014343261718750, 0.0001831054687500, -0.0013427734375000, 0.0000305175781250, +-0.0013732910156250, -0.0000305175781250, -0.0012207031250000, -0.0000305175781250, +-0.0015258789062500, -0.0001220703125000, -0.0017089843750000, -0.0002136230468750, +-0.0012512207031250, -0.0000610351562500, -0.0022277832031250, -0.0000915527343750, +-0.0019226074218750, -0.0002136230468750, -0.0019226074218750, -0.0001831054687500, +-0.0023803710937500, -0.0000610351562500, -0.0018310546875000, -0.0004272460937500, +-0.0031127929687500, -0.0002441406250000, -0.0023193359375000, -0.0003356933593750, +-0.0024414062500000, -0.0007324218750000, -0.0034179687500000, -0.0005187988281250, +-0.0021057128906250, -0.0006713867187500, -0.0027160644531250, -0.0007019042968750, +-0.0027160644531250, -0.0007934570312500, -0.0022888183593750, -0.0008850097656250, +-0.0026245117187500, -0.0006103515625000, -0.0028686523437500, -0.0009765625000000, +-0.0022888183593750, -0.0007629394531250, -0.0028381347656250, -0.0006408691406250, +-0.0026245117187500, -0.0007629394531250, -0.0020446777343750, -0.0004882812500000, +-0.0029602050781250, -0.0005187988281250, -0.0023193359375000, -0.0003662109375000, +-0.0022583007812500, -0.0003051757812500, -0.0025939941406250, -0.0003662109375000, +-0.0026550292968750, -0.0001831054687500, -0.0025634765625000, -0.0002136230468750, +-0.0024414062500000, -0.0002136230468750, -0.0024719238281250, -0.0001220703125000, +-0.0021362304687500, 0.0000915527343750, -0.0019531250000000, 0.0000000000000000, +-0.0023193359375000, -0.0001525878906250, -0.0017089843750000, 0.0001831054687500, +-0.0022277832031250, -0.0000610351562500, -0.0021667480468750, -0.0003662109375000, +-0.0018005371093750, 0.0001525878906250, -0.0024414062500000, -0.0005798339843750, +-0.0017395019531250, -0.0003662109375000, -0.0023498535156250, -0.0002746582031250, +-0.0021972656250000, -0.0006103515625000, -0.0017700195312500, -0.0002441406250000, +-0.0030212402343750, -0.0003662109375000, -0.0017395019531250, -0.0002136230468750, +-0.0027160644531250, -0.0001831054687500, -0.0032043457031250, -0.0002746582031250, +-0.0025024414062500, -0.0000305175781250, -0.0036621093750000, -0.0003967285156250, +-0.0036621093750000, -0.0002746582031250, -0.0037536621093750, -0.0003356933593750, +-0.0044555664062500, -0.0005187988281250, -0.0046997070312500, -0.0003051757812500, +-0.0045166015625000, -0.0007934570312500, -0.0053405761718750, -0.0005187988281250, +-0.0049438476562500, -0.0009155273437500, -0.0049133300781250, -0.0014343261718750, +-0.0053710937500000, -0.0007629394531250, -0.0046997070312500, -0.0018920898437500, +-0.0047912597656250, -0.0015563964843750, -0.0048217773437500, -0.0016174316406250, +-0.0041198730468750, -0.0021362304687500, -0.0039062500000000, -0.0014343261718750, +-0.0041809082031250, -0.0023193359375000, -0.0025329589843750, -0.0017395019531250, +-0.0032348632812500, -0.0017395019531250, -0.0026550292968750, -0.0023803710937500, +-0.0014343261718750, -0.0014038085937500, -0.0029296875000000, -0.0020446777343750, +-0.0010375976562500, -0.0017395019531250, -0.0020141601562500, -0.0013732910156250, +-0.0020751953125000, -0.0014038085937500, -0.0011596679687500, -0.0009765625000000, +-0.0028991699218750, -0.0012207031250000, -0.0013427734375000, -0.0007629394531250, +-0.0021667480468750, -0.0006408691406250, -0.0019226074218750, -0.0007934570312500, +-0.0007629394531250, -0.0000610351562500, -0.0021057128906250, -0.0004272460937500, +-0.0001525878906250, 0.0003051757812500, -0.0007629394531250, 0.0002136230468750, +-0.0001525878906250, -0.0002441406250000, 0.0015869140625000, 0.0006713867187500, +0.0005493164062500}, +{-0.0027465820312500, 0.0001831054687500, -0.0023803710937500, -0.0000915527343750, +-0.0023498535156250, -0.0001220703125000, -0.0019531250000000, -0.0000915527343750, +-0.0016479492187500, -0.0001525878906250, -0.0013122558593750, -0.0000610351562500, +-0.0006713867187500, -0.0001220703125000, -0.0010375976562500, -0.0000915527343750, +-0.0002746582031250, -0.0000610351562500, -0.0000610351562500, -0.0001831054687500, +-0.0003662109375000, -0.0003356933593750, 0.0003967285156250, -0.0003051757812500, +-0.0000610351562500, -0.0003967285156250, -0.0001525878906250, -0.0004577636718750, +-0.0004882812500000, -0.0002746582031250, -0.0012817382812500, -0.0003662109375000, +-0.0015258789062500, -0.0004577636718750, -0.0019836425781250, -0.0001220703125000, +-0.0023803710937500, -0.0003051757812500, -0.0026855468750000, -0.0006103515625000, +-0.0028686523437500, -0.0001220703125000, -0.0029296875000000, -0.0004882812500000, +-0.0033569335937500, -0.0002441406250000, -0.0034179687500000, -0.0002136230468750, +-0.0034790039062500, -0.0003967285156250, -0.0037536621093750, 0.0000305175781250, +-0.0035705566406250, -0.0003967285156250, -0.0034179687500000, -0.0001831054687500, +-0.0036926269531250, -0.0002441406250000, -0.0035705566406250, -0.0005798339843750, +-0.0033264160156250, -0.0001525878906250, -0.0039367675781250, -0.0007934570312500, +-0.0033874511718750, -0.0003967285156250, -0.0038452148437500, -0.0003662109375000, +-0.0036621093750000, -0.0007629394531250, -0.0032653808593750, -0.0003051757812500, +-0.0039672851562500, -0.0006103515625000, -0.0030212402343750, -0.0006103515625000, +-0.0037231445312500, -0.0005493164062500, -0.0035400390625000, -0.0008239746093750, +-0.0028381347656250, -0.0007019042968750, -0.0040588378906250, -0.0008239746093750, +-0.0028381347656250, -0.0009155273437500, -0.0033874511718750, -0.0007629394531250, +-0.0035095214843750, -0.0007019042968750, -0.0028076171875000, -0.0007324218750000, +-0.0035400390625000, -0.0004272460937500, -0.0028686523437500, -0.0003051757812500, +-0.0032043457031250, -0.0003967285156250, -0.0032043457031250, -0.0003051757812500, +-0.0027465820312500, -0.0002136230468750, -0.0032958984375000, -0.0007324218750000, +-0.0028076171875000, -0.0007629394531250, -0.0028381347656250, -0.0008850097656250, +-0.0031127929687500, -0.0012512207031250, -0.0027465820312500, -0.0012207031250000, +-0.0025939941406250, -0.0012512207031250, -0.0033264160156250, -0.0012817382812500, +-0.0025634765625000, -0.0012207031250000, -0.0030212402343750, -0.0011596679687500, +-0.0038757324218750, -0.0009765625000000, -0.0028076171875000, -0.0009765625000000, +-0.0041503906250000, -0.0008239746093750, -0.0040588378906250, -0.0006713867187500, +-0.0036315917968750, -0.0005187988281250, -0.0043640136718750, -0.0004577636718750, +-0.0045166015625000, -0.0004577636718750, -0.0032653808593750, -0.0001220703125000, +-0.0043029785156250, -0.0002441406250000, -0.0034484863281250, -0.0004272460937500, +-0.0021972656250000, 0.0002441406250000, -0.0041198730468750, -0.0002441406250000, +-0.0011901855468750, 0.0001220703125000, -0.0023193359375000, 0.0000305175781250, +-0.0019836425781250, -0.0001831054687500, -0.0000610351562500, 0.0005187988281250, +-0.0023498535156250, -0.0005493164062500, -0.0006103515625000, -0.0000915527343750, +-0.0014038085937500, -0.0001220703125000, -0.0019226074218750, -0.0008850097656250, +-0.0012512207031250, -0.0000610351562500, -0.0024414062500000, -0.0007629394531250, +-0.0014038085937500, -0.0008239746093750, -0.0014953613281250, -0.0006103515625000, +-0.0010681152343750, -0.0007019042968750, -0.0000915527343750, -0.0005798339843750, +-0.0006408691406250, -0.0007324218750000, 0.0009155273437500, -0.0003356933593750, +0.0013122558593750, -0.0005187988281250, 0.0010375976562500, -0.0008544921875000, +0.0018005371093750, -0.0002136230468750, 0.0023803710937500, -0.0003967285156250, +0.0012207031250000, -0.0003051757812500, 0.0016784667968750, 0.0000305175781250, +0.0014038085937500, 0.0005187988281250, 0.0005493164062500, 0.0008239746093750, +0.0014038085937500, 0.0003356933593750, 0.0001220703125000, 0.0012512207031250, +0.0001220703125000, 0.0010375976562500, 0.0007324218750000, 0.0001525878906250, +0.0004272460937500, 0.0010986328125000, 0.0003662109375000, 0.0003051757812500, +0.0010681152343750, 0.0000610351562500, 0.0009765625000000, 0.0007019042968750, +0.0013427734375000, 0.0007934570312500, 0.0023193359375000, 0.0002136230468750, +0.0021667480468750, 0.0008850097656250, 0.0019226074218750, 0.0010986328125000, +0.0028076171875000, 0.0005798339843750, 0.0018615722656250, 0.0006713867187500, +0.0006713867187500, 0.0011596679687500, 0.0018615722656250, 0.0000000000000000, +-0.0001525878906250, 0.0003967285156250, -0.0001220703125000, 0.0004577636718750, +0.0000610351562500, -0.0003051757812500, -0.0006408691406250, 0.0000305175781250, +-0.0001220703125000, 0.0005187988281250, -0.0005187988281250, 0.0003967285156250, +-0.0001831054687500, 0.0000915527343750, -0.0003662109375000, 0.0001220703125000, +-0.0012817382812500, -0.0013122558593750, -0.0009460449218750, 0.0000000000000000, +-0.0002136230468750, -0.0010681152343750, 0.0000915527343750, -0.0001831054687500, +-0.0003967285156250, 0.0012207031250000, -0.0008544921875000, 0.0003967285156250, +-0.0005187988281250, 0.0007324218750000, -0.0005798339843750, 0.0017700195312500, +-0.0014343261718750, 0.0010070800781250, -0.0000610351562500, 0.0000305175781250, +0.0012207031250000, 0.0010681152343750, 0.0000610351562500, 0.0001525878906250, +0.0027770996093750, -0.0002746582031250, 0.0028076171875000, 0.0006408691406250, +0.0021972656250000, 0.0010986328125000, 0.0032348632812500, 0.0007019042968750, +0.0032348632812500, 0.0018005371093750, 0.0020141601562500, 0.0027465820312500, +0.0019531250000000, 0.0017700195312500, 0.0021667480468750, 0.0016784667968750, +0.0017700195312500, 0.0031738281250000, 0.0014648437500000, -0.0001220703125000, +0.0016174316406250, 0.0005798339843750, 0.0019226074218750, 0.0008850097656250, +0.0014038085937500, -0.0009155273437500, 0.0010681152343750, 0.0001525878906250, +0.0015258789062500, 0.0005187988281250, 0.0002136230468750, 0.0002136230468750, +0.0000610351562500, 0.0009765625000000, 0.0003356933593750, 0.0018310546875000, +-0.0003662109375000, 0.0012817382812500, -0.0004577636718750, 0.0014648437500000, +0.0003662109375000, 0.0019836425781250, 0.0004272460937500, 0.0009155273437500, +0.0003051757812500, -0.0000915527343750, 0.0007934570312500, 0.0006408691406250, +0.0008850097656250, -0.0011291503906250, 0.0005187988281250, -0.0018920898437500, +0.0004882812500000, -0.0013732910156250, 0.0006103515625000, -0.0018615722656250, +0.0004272460937500, -0.0026855468750000, 0.0002746582031250, -0.0009155273437500, +0.0003967285156250, -0.0022888183593750, 0.0004577636718750, -0.0017700195312500, +0.0000000000000000, -0.0003051757812500, -0.0002746582031250, -0.0026550292968750, +-0.0001220703125000, -0.0005798339843750, -0.0009155273437500, -0.0012207031250000, +-0.0010070800781250, -0.0022583007812500, -0.0009460449218750, -0.0017395019531250, +-0.0012512207031250, -0.0026550292968750, -0.0011291503906250, -0.0033569335937500, +-0.0011596679687500, -0.0035705566406250, -0.0008850097656250, -0.0039978027343750, +-0.0011596679687500, -0.0045776367187500, -0.0015258789062500, -0.0047302246093750, +-0.0010375976562500, -0.0043945312500000, -0.0015869140625000, -0.0050964355468750, +-0.0015563964843750, -0.0044555664062500, -0.0014648437500000, -0.0039672851562500, +-0.0015563964843750, -0.0050964355468750, -0.0013732910156250, -0.0025634765625000, +-0.0019836425781250, -0.0036926269531250, -0.0017089843750000, -0.0031127929687500, +-0.0019531250000000, -0.0010986328125000, -0.0026550292968750, -0.0030822753906250, +-0.0022583007812500, -0.0010986328125000, -0.0025634765625000, -0.0014953613281250, +-0.0028381347656250, -0.0018310546875000, -0.0024414062500000, -0.0008850097656250, +-0.0021667480468750, -0.0016784667968750, -0.0024108886718750, -0.0014038085937500, +-0.0018920898437500, -0.0013732910156250, -0.0018615722656250, -0.0017700195312500, +-0.0018310546875000, -0.0017395019531250, -0.0014953613281250, -0.0016479492187500, +-0.0015869140625000, -0.0021667480468750, -0.0013427734375000, -0.0018615722656250, +-0.0012512207031250, -0.0022888183593750, -0.0012512207031250, -0.0027770996093750, +-0.0010986328125000, -0.0021667480468750, -0.0010375976562500, -0.0029602050781250, +-0.0012512207031250, -0.0027160644531250, -0.0011901855468750, -0.0026245117187500, +-0.0010986328125000, -0.0031127929687500, -0.0012207031250000, -0.0026550292968750, +-0.0011291503906250, -0.0028076171875000, -0.0009765625000000, -0.0033569335937500, +-0.0008544921875000, -0.0030212402343750, -0.0007934570312500, -0.0028381347656250, +-0.0007324218750000, -0.0037536621093750, -0.0006103515625000, -0.0025634765625000, +-0.0009155273437500, -0.0031127929687500, -0.0007019042968750, -0.0030822753906250, +-0.0007934570312500, -0.0021972656250000, -0.0010681152343750, -0.0030822753906250, +-0.0007934570312500, -0.0023498535156250, -0.0011596679687500, -0.0026550292968750, +-0.0011291503906250, -0.0027770996093750, -0.0010681152343750, -0.0024414062500000, +-0.0012207031250000, -0.0031433105468750, -0.0011291503906250, -0.0028076171875000, +-0.0010681152343750, -0.0032348632812500, -0.0010986328125000, -0.0033874511718750, +-0.0009765625000000, -0.0031433105468750, -0.0008544921875000, -0.0036315917968750, +-0.0008544921875000, -0.0032653808593750, -0.0004882812500000, -0.0031738281250000, +-0.0005798339843750, -0.0032653808593750, -0.0004882812500000, -0.0029602050781250, +-0.0001525878906250, -0.0028991699218750, -0.0003662109375000, -0.0031433105468750, +-0.0003967285156250, -0.0029907226562500, -0.0002746582031250, -0.0030822753906250, +-0.0002136230468750, -0.0032348632812500, -0.0001831054687500, -0.0029296875000000, +-0.0000915527343750, -0.0032653808593750, 0.0000915527343750, -0.0024414062500000, +0.0003662109375000, -0.0023193359375000, 0.0002136230468750, -0.0024719238281250, +0.0001220703125000, -0.0011596679687500, 0.0004882812500000, -0.0016479492187500, +-0.0000610351562500, -0.0018310546875000, 0.0000915527343750, -0.0009765625000000, +0.0000000000000000, -0.0009765625000000, -0.0003967285156250, -0.0018310546875000, +0.0000305175781250, -0.0001525878906250, -0.0006103515625000, -0.0006408691406250, +-0.0006713867187500, -0.0007934570312500, -0.0005493164062500, -0.0002746582031250, +-0.0008850097656250, -0.0014953613281250, -0.0008239746093750, -0.0008239746093750, +-0.0004577636718750, -0.0013732910156250, -0.0007324218750000, -0.0018615722656250, +-0.0003356933593750, -0.0014343261718750, 0.0001831054687500, -0.0018005371093750, +-0.0003356933593750, -0.0018310546875000, 0.0005187988281250, -0.0016784667968750, +0.0006408691406250, -0.0015258789062500, 0.0003967285156250, -0.0015258789062500, +0.0006103515625000, -0.0013427734375000, 0.0006713867187500, -0.0003967285156250, +0.0002746582031250, -0.0008544921875000, 0.0006103515625000, -0.0001831054687500, +0.0003356933593750, 0.0007324218750000, -0.0000915527343750, -0.0003967285156250, +0.0004577636718750, 0.0014343261718750, 0.0000305175781250, 0.0006408691406250, +0.0002441406250000, 0.0007629394531250, 0.0002746582031250, 0.0019836425781250, +0.0000305175781250, 0.0007324218750000, 0.0003356933593750, 0.0018615722656250, +0.0001525878906250, 0.0017089843750000, 0.0001220703125000, 0.0015869140625000, +-0.0000305175781250, 0.0021667480468750, -0.0002441406250000, 0.0020446777343750, +-0.0001220703125000, 0.0032348632812500, -0.0003967285156250, 0.0029296875000000, +-0.0003967285156250}, +{-0.0014343261718750, -0.0013122558593750, -0.0014648437500000, -0.0011291503906250, +-0.0013122558593750, -0.0002136230468750, -0.0013427734375000, -0.0012512207031250, +-0.0014038085937500, 0.0003662109375000, -0.0010375976562500, -0.0003356933593750, +-0.0009460449218750, -0.0000915527343750, -0.0009765625000000, 0.0009460449218750, +-0.0007934570312500, -0.0003967285156250, -0.0006103515625000, 0.0015563964843750, +-0.0009460449218750, 0.0004882812500000, -0.0007019042968750, 0.0005493164062500, +-0.0008239746093750, 0.0020446777343750, -0.0011901855468750, 0.0004882812500000, +-0.0008850097656250, 0.0018615722656250, -0.0014648437500000, 0.0013427734375000, +-0.0013732910156250, 0.0011596679687500, -0.0014343261718750, 0.0019226074218750, +-0.0018005371093750, 0.0010375976562500, -0.0015869140625000, 0.0017700195312500, +-0.0017089843750000, 0.0013122558593750, -0.0017089843750000, 0.0012207031250000, +-0.0016174316406250, 0.0015258789062500, -0.0015563964843750, 0.0007629394531250, +-0.0014038085937500, 0.0012817382812500, -0.0013732910156250, 0.0006713867187500, +-0.0012817382812500, 0.0004882812500000, -0.0011291503906250, 0.0007019042968750, +-0.0010375976562500, -0.0001525878906250, -0.0009460449218750, 0.0003051757812500, +-0.0006408691406250, -0.0001831054687500, -0.0005493164062500, -0.0003967285156250, +-0.0003967285156250, 0.0000000000000000, -0.0001525878906250, -0.0006103515625000, +-0.0000610351562500, -0.0003967285156250, 0.0002746582031250, -0.0002746582031250, +0.0003051757812500, -0.0006713867187500, 0.0003662109375000, -0.0008544921875000, +0.0006103515625000, -0.0007324218750000, 0.0005493164062500, -0.0018615722656250, +0.0005187988281250, -0.0018615722656250, 0.0006408691406250, -0.0023193359375000, +0.0006713867187500, -0.0027770996093750, 0.0006408691406250, -0.0020141601562500, +0.0008239746093750, -0.0030822753906250, 0.0005187988281250, -0.0022583007812500, +0.0007629394531250, -0.0019531250000000, 0.0006713867187500, -0.0029296875000000, +0.0001831054687500, -0.0022277832031250, 0.0005493164062500, -0.0016174316406250, +0.0001220703125000, -0.0025024414062500, 0.0000305175781250, -0.0017089843750000, +0.0002136230468750, -0.0006713867187500, 0.0000305175781250, -0.0020446777343750, +0.0000000000000000, -0.0001525878906250, 0.0006103515625000, -0.0008850097656250, +0.0003967285156250, -0.0011291503906250, 0.0004272460937500, -0.0001220703125000, +0.0009155273437500, -0.0013122558593750, 0.0008544921875000, -0.0009155273437500, +0.0003967285156250, -0.0008544921875000, 0.0007324218750000, -0.0015869140625000, +0.0004577636718750, -0.0017089843750000, -0.0000610351562500, -0.0013122558593750, +0.0004577636718750, -0.0021362304687500, -0.0005798339843750, -0.0021362304687500, +-0.0001220703125000, -0.0015869140625000, -0.0001525878906250, -0.0018615722656250, +-0.0007934570312500, -0.0019531250000000, -0.0001220703125000, -0.0003662109375000, +-0.0008239746093750, -0.0011291503906250, -0.0004882812500000, -0.0005187988281250, +-0.0002746582031250, 0.0009155273437500, -0.0006713867187500, -0.0004272460937500, +-0.0003662109375000, 0.0011291503906250, -0.0005187988281250, 0.0014038085937500, +-0.0002746582031250, 0.0001831054687500, -0.0005187988281250, 0.0003356933593750, +-0.0007019042968750, 0.0015869140625000, -0.0001831054687500, 0.0004882812500000, +-0.0010070800781250, 0.0010070800781250, -0.0003662109375000, 0.0019836425781250, +-0.0005187988281250, 0.0016784667968750, -0.0012207031250000, 0.0019531250000000, +-0.0003356933593750, 0.0030822753906250, -0.0010986328125000, 0.0021667480468750, +-0.0002136230468750, 0.0025024414062500, -0.0002441406250000, 0.0033264160156250, +-0.0010986328125000, 0.0016174316406250, 0.0002136230468750, 0.0021057128906250, +0.0000305175781250, 0.0025329589843750, 0.0000610351562500, 0.0020141601562500, +0.0003051757812500, 0.0010986328125000, 0.0002441406250000, 0.0010375976562500, +0.0005187988281250, 0.0020751953125000, 0.0003356933593750, 0.0007019042968750, +0.0005187988281250, 0.0014038085937500, 0.0003051757812500, 0.0027770996093750, +-0.0000305175781250, 0.0009155273437500, 0.0001831054687500, 0.0035400390625000, +-0.0005493164062500, 0.0027465820312500, -0.0006713867187500, 0.0024719238281250, +-0.0005798339843750, 0.0039978027343750, -0.0006103515625000, 0.0025024414062500, +0.0000305175781250, 0.0022277832031250, 0.0006408691406250, 0.0024108886718750, +0.0004882812500000, 0.0019226074218750, 0.0012512207031250, 0.0016784667968750, +0.0020446777343750, 0.0021057128906250, 0.0016479492187500, 0.0011901855468750, +0.0030517578125000, 0.0010681152343750, 0.0020446777343750, 0.0010986328125000, +0.0021972656250000, 0.0006103515625000, 0.0028686523437500, 0.0005798339843750, +0.0011596679687500, 0.0006408691406250, 0.0027770996093750, 0.0005493164062500, +0.0023193359375000, 0.0003662109375000, 0.0021057128906250, 0.0005493164062500, +0.0032958984375000, 0.0007019042968750, 0.0029602050781250, -0.0000610351562500, +0.0029296875000000, 0.0006103515625000, 0.0034484863281250, 0.0003662109375000, +0.0029602050781250, -0.0004577636718750, 0.0023803710937500, 0.0005187988281250, +0.0030822753906250, -0.0004577636718750, 0.0021362304687500, 0.0002441406250000, +0.0020141601562500, -0.0000610351562500, 0.0019226074218750, -0.0009460449218750, +0.0013427734375000, 0.0002441406250000, 0.0011901855468750, -0.0011901855468750, +0.0007324218750000, -0.0014038085937500, 0.0007019042968750, -0.0004577636718750, +0.0003662109375000, -0.0008544921875000, -0.0002441406250000, -0.0015563964843750, +-0.0002441406250000, 0.0003662109375000, -0.0003356933593750, -0.0004882812500000, +-0.0009765625000000, -0.0003051757812500, -0.0008544921875000, 0.0012512207031250, +-0.0004882812500000, 0.0000610351562500, -0.0011291503906250, 0.0006713867187500, +-0.0008239746093750, 0.0005798339843750, -0.0010986328125000, 0.0004577636718750, +-0.0012512207031250, 0.0005187988281250, -0.0010986328125000, 0.0002136230468750, +-0.0014648437500000, 0.0010986328125000, -0.0016479492187500, 0.0007019042968750, +-0.0017395019531250, 0.0011291503906250, -0.0016784667968750, 0.0021057128906250, +-0.0018005371093750, 0.0016174316406250, -0.0021057128906250, 0.0027465820312500, +-0.0013122558593750, 0.0028381347656250, -0.0018920898437500, 0.0025939941406250, +-0.0015563964843750, 0.0031738281250000, -0.0007019042968750, 0.0032653808593750, +-0.0015563964843750, 0.0022583007812500, -0.0003051757812500, 0.0026855468750000, +-0.0007934570312500, 0.0021972656250000, -0.0010070800781250, 0.0012817382812500, +-0.0003967285156250, 0.0021362304687500, -0.0011901855468750, 0.0005493164062500, +-0.0011901855468750, 0.0008544921875000, -0.0013732910156250, 0.0009155273437500, +-0.0016174316406250, 0.0001220703125000, -0.0018005371093750, 0.0006408691406250, +-0.0021057128906250, 0.0002441406250000, -0.0021972656250000, 0.0004272460937500, +-0.0023498535156250, 0.0003967285156250, -0.0025024414062500, 0.0000915527343750, +-0.0025939941406250, 0.0004272460937500, -0.0025939941406250, 0.0002136230468750, +-0.0023193359375000, 0.0000915527343750, -0.0025939941406250, 0.0002746582031250, +-0.0021362304687500, 0.0003356933593750, -0.0016174316406250, 0.0001220703125000, +-0.0022277832031250, 0.0006713867187500, -0.0014648437500000, 0.0004272460937500, +-0.0015563964843750, 0.0004882812500000, -0.0016174316406250, 0.0008850097656250, +-0.0013122558593750, 0.0004577636718750, -0.0016174316406250, 0.0006408691406250, +-0.0012512207031250, 0.0006713867187500, -0.0011596679687500, 0.0005798339843750, +-0.0012207031250000, 0.0006103515625000, -0.0011596679687500, 0.0006408691406250, +-0.0011291503906250, 0.0004272460937500, -0.0010375976562500, 0.0006408691406250, +-0.0013732910156250, 0.0004272460937500, -0.0010986328125000, 0.0001831054687500, +-0.0006713867187500, 0.0006713867187500, -0.0010681152343750, -0.0000305175781250, +-0.0007019042968750, 0.0000915527343750, -0.0007934570312500, 0.0001525878906250, +-0.0010070800781250, -0.0001831054687500, -0.0008239746093750, 0.0000915527343750, +-0.0007629394531250, -0.0002441406250000, -0.0010070800781250, -0.0002746582031250, +-0.0007934570312500, -0.0003356933593750, -0.0008544921875000, -0.0005493164062500, +-0.0010681152343750, -0.0006713867187500, -0.0008850097656250, -0.0006408691406250, +-0.0011596679687500, -0.0007934570312500, -0.0011596679687500, -0.0008239746093750, +-0.0011596679687500, -0.0008239746093750, -0.0012817382812500, -0.0010070800781250, +-0.0010986328125000, -0.0009460449218750, -0.0012207031250000, -0.0011291503906250, +-0.0010375976562500, -0.0010681152343750, -0.0009765625000000, -0.0010986328125000, +-0.0010070800781250, -0.0014648437500000, -0.0006103515625000, -0.0009460449218750, +-0.0008850097656250, -0.0013122558593750, -0.0005493164062500, -0.0010986328125000, +-0.0006103515625000, -0.0005493164062500, -0.0008850097656250, -0.0009765625000000, +-0.0005798339843750, -0.0001831054687500, -0.0013427734375000, -0.0002746582031250, +-0.0012817382812500, -0.0001220703125000, -0.0017395019531250, 0.0003662109375000, +-0.0026245117187500, 0.0000000000000000, -0.0024719238281250, 0.0005493164062500, +-0.0038146972656250, 0.0003051757812500, -0.0041503906250000, 0.0002441406250000, +-0.0045776367187500, 0.0004577636718750, -0.0055236816406250, 0.0000610351562500, +-0.0054321289062500, 0.0002746582031250, -0.0057678222656250, 0.0001220703125000, +-0.0059814453125000, 0.0001831054687500, -0.0055541992187500, 0.0003662109375000, +-0.0053405761718750, 0.0000915527343750, -0.0055236816406250, 0.0003967285156250, +-0.0043945312500000, 0.0001220703125000, -0.0045166015625000, 0.0000915527343750, +-0.0040588378906250, 0.0000305175781250, -0.0031127929687500, -0.0005798339843750, +-0.0034179687500000, 0.0000610351562500, -0.0027770996093750, -0.0007324218750000, +-0.0026855468750000, -0.0005798339843750, -0.0026855468750000, 0.0000915527343750, +-0.0025329589843750, -0.0009155273437500, -0.0027160644531250, 0.0001525878906250, +-0.0025939941406250, -0.0001831054687500, -0.0031433105468750, -0.0002136230468750, +-0.0029296875000000, 0.0003967285156250, -0.0028381347656250, -0.0003051757812500, +-0.0037536621093750, 0.0004577636718750, -0.0021057128906250, 0.0001525878906250, +-0.0032348632812500, 0.0000305175781250, -0.0025329589843750, 0.0004882812500000, +-0.0007629394531250, 0.0001525878906250, -0.0023803710937500, 0.0002441406250000, +-0.0006408691406250, 0.0003967285156250, -0.0006713867187500, -0.0000305175781250, +-0.0011901855468750, -0.0002746582031250, -0.0006408691406250, 0.0000610351562500, +-0.0008239746093750, -0.0007324218750000, -0.0010070800781250, -0.0006408691406250, +-0.0008239746093750, -0.0003967285156250, -0.0006713867187500, -0.0008544921875000, +-0.0008544921875000, -0.0006713867187500, -0.0008850097656250, 0.0000000000000000, +-0.0000305175781250, -0.0003662109375000, -0.0001525878906250, -0.0000610351562500, +0.0005798339843750, 0.0005187988281250, 0.0017395019531250, -0.0001831054687500, +0.0014953613281250, 0.0004272460937500, 0.0027770996093750, 0.0003967285156250, +0.0027160644531250, 0.0004272460937500, 0.0024719238281250, 0.0009765625000000, +0.0030212402343750, 0.0010681152343750, 0.0026550292968750, 0.0013122558593750, +0.0014648437500000, 0.0015869140625000, 0.0018005371093750, 0.0014343261718750, +0.0011291503906250, 0.0013427734375000, -0.0002136230468750, 0.0014953613281250, +0.0003662109375000, 0.0007629394531250, 0.0003662109375000, 0.0009155273437500, +-0.0000610351562500, 0.0007019042968750, 0.0006408691406250, 0.0002136230468750, +0.0015869140625000}, +{-0.0011901855468750, -0.0006103515625000, -0.0018005371093750, -0.0003662109375000, +-0.0014038085937500, -0.0006408691406250, -0.0019531250000000, -0.0004882812500000, +-0.0017089843750000, -0.0005493164062500, -0.0019531250000000, -0.0007629394531250, +-0.0023498535156250, -0.0005493164062500, -0.0018005371093750, -0.0007324218750000, +-0.0026855468750000, -0.0008544921875000, -0.0024108886718750, -0.0007629394531250, +-0.0023193359375000, -0.0008850097656250, -0.0028686523437500, -0.0010070800781250, +-0.0025024414062500, -0.0006408691406250, -0.0025939941406250, -0.0009155273437500, +-0.0027465820312500, -0.0007629394531250, -0.0025634765625000, -0.0003356933593750, +-0.0025634765625000, -0.0007629394531250, -0.0026245117187500, 0.0000000000000000, +-0.0022277832031250, -0.0001525878906250, -0.0025634765625000, -0.0001220703125000, +-0.0023193359375000, 0.0003662109375000, -0.0018005371093750, 0.0000915527343750, +-0.0023193359375000, 0.0001831054687500, -0.0017395019531250, 0.0002441406250000, +-0.0018310546875000, 0.0001220703125000, -0.0021972656250000, -0.0001220703125000, +-0.0021057128906250, -0.0001220703125000, -0.0024108886718750, -0.0001220703125000, +-0.0032653808593750, -0.0004577636718750, -0.0030517578125000, -0.0003356933593750, +-0.0039062500000000, -0.0001831054687500, -0.0047912597656250, -0.0007324218750000, +-0.0040588378906250, -0.0001220703125000, -0.0059814453125000, -0.0007019042968750, +-0.0054016113281250, -0.0003967285156250, -0.0056762695312500, 0.0002136230468750, +-0.0068969726562500, -0.0007629394531250, -0.0056152343750000, 0.0007324218750000, +-0.0064697265625000, 0.0002136230468750, -0.0063781738281250, 0.0002746582031250, +-0.0054321289062500, 0.0012512207031250, -0.0053405761718750, 0.0002441406250000, +-0.0052490234375000, 0.0012817382812500, -0.0038146972656250, 0.0009765625000000, +-0.0040283203125000, 0.0007324218750000, -0.0035095214843750, 0.0012512207031250, +-0.0025329589843750, 0.0007934570312500, -0.0032653808593750, 0.0007324218750000, +-0.0023498535156250, 0.0006103515625000, -0.0032653808593750, 0.0003662109375000, +-0.0031738281250000, 0.0002136230468750, -0.0025939941406250, 0.0001525878906250, +-0.0039062500000000, 0.0002136230468750, -0.0020446777343750, 0.0001831054687500, +-0.0031433105468750, 0.0002746582031250, -0.0028686523437500, 0.0003967285156250, +-0.0013427734375000, 0.0003662109375000, -0.0029296875000000, 0.0007629394531250, +-0.0011596679687500, 0.0006103515625000, -0.0012817382812500, 0.0006103515625000, +-0.0013122558593750, 0.0007629394531250, -0.0006103515625000, 0.0003356933593750, +-0.0014038085937500, 0.0005493164062500, -0.0004272460937500, 0.0000610351562500, +-0.0006103515625000, 0.0001831054687500, -0.0010375976562500, 0.0007629394531250, +-0.0007324218750000, 0.0005493164062500, -0.0006408691406250, 0.0011596679687500, +-0.0000610351562500, 0.0018005371093750, 0.0000000000000000, 0.0016784667968750, +0.0005493164062500, 0.0017395019531250, 0.0010375976562500, 0.0022888183593750, +0.0005493164062500, 0.0011901855468750, 0.0019836425781250, 0.0014648437500000, +0.0014953613281250, 0.0014343261718750, 0.0013122558593750, 0.0007629394531250, +0.0021972656250000, 0.0013427734375000, 0.0014953613281250, 0.0012207031250000, +0.0004272460937500, 0.0014953613281250, 0.0008850097656250, 0.0014648437500000, +0.0000610351562500, 0.0014648437500000, -0.0013732910156250, 0.0021362304687500, +-0.0005493164062500, 0.0003662109375000, -0.0005798339843750, 0.0013427734375000, +-0.0012207031250000, 0.0009765625000000, -0.0006408691406250, -0.0020141601562500, +0.0006408691406250, -0.0015563964843750, -0.0016479492187500, -0.0009460449218750, +-0.0013122558593750, -0.0012817382812500, -0.0026245117187500, -0.0012512207031250, +-0.0020446777343750, -0.0012512207031250, -0.0007629394531250, -0.0018005371093750, +-0.0016479492187500, -0.0021972656250000, -0.0015869140625000, -0.0028381347656250, +-0.0009460449218750, -0.0022583007812500, -0.0011596679687500, -0.0019836425781250, +-0.0016784667968750, -0.0027160644531250, -0.0012512207031250, -0.0003356933593750, +-0.0004882812500000, -0.0007324218750000, -0.0010681152343750, -0.0008544921875000, +-0.0003662109375000, 0.0005493164062500, 0.0010070800781250, -0.0003051757812500, +0.0003967285156250, -0.0010986328125000, 0.0007934570312500, -0.0012207031250000, +0.0016479492187500, -0.0016784667968750, 0.0010070800781250, -0.0029602050781250, +0.0003662109375000, -0.0034179687500000, 0.0012207031250000, -0.0018615722656250, +0.0000000000000000, -0.0034484863281250, 0.0002136230468750, -0.0029296875000000, +0.0006713867187500, -0.0009155273437500, 0.0003051757812500, -0.0026855468750000, +0.0004882812500000, -0.0015869140625000, 0.0010070800781250, -0.0015563964843750, +0.0010681152343750, -0.0024719238281250, 0.0007019042968750, -0.0026245117187500, +0.0007019042968750, -0.0028076171875000, 0.0010986328125000, -0.0039978027343750, +0.0004577636718750, -0.0040588378906250, 0.0005798339843750, -0.0039978027343750, +0.0007934570312500, -0.0046386718750000, 0.0005798339843750, -0.0047302246093750, +0.0007019042968750, -0.0038146972656250, 0.0005493164062500, -0.0037536621093750, +0.0006103515625000, -0.0039978027343750, 0.0005187988281250, -0.0034484863281250, +0.0003662109375000, -0.0028991699218750, 0.0004882812500000, -0.0043945312500000, +0.0002746582031250, -0.0031127929687500, 0.0002746582031250, -0.0039062500000000, +0.0004577636718750, -0.0052795410156250, 0.0006103515625000, -0.0031433105468750, +0.0005493164062500, -0.0061035156250000, 0.0007019042968750, -0.0051574707031250, +0.0008850097656250, -0.0047302246093750, 0.0006103515625000, -0.0063171386718750, +0.0004577636718750, -0.0049743652343750, 0.0006103515625000, -0.0048828125000000, +0.0002136230468750, -0.0049743652343750, 0.0002441406250000, -0.0041503906250000, +0.0000305175781250, -0.0034790039062500, -0.0003662109375000, -0.0036621093750000, +-0.0003051757812500, -0.0027465820312500, -0.0010375976562500, -0.0024719238281250, +-0.0011901855468750, -0.0025329589843750, -0.0011901855468750, -0.0020446777343750, +-0.0016174316406250, -0.0018310546875000, -0.0018310546875000, -0.0025024414062500, +-0.0013122558593750, -0.0017395019531250, -0.0015869140625000, -0.0021972656250000, +-0.0015869140625000, -0.0031433105468750, -0.0010986328125000, -0.0021362304687500, +-0.0012817382812500, -0.0031127929687500, -0.0014953613281250, -0.0031738281250000, +-0.0013122558593750, -0.0029296875000000, -0.0014343261718750, -0.0033264160156250, +-0.0016784667968750, -0.0032653808593750, -0.0015563964843750, -0.0029602050781250, +-0.0016479492187500, -0.0032653808593750, -0.0016174316406250, -0.0028381347656250, +-0.0015563964843750, -0.0024414062500000, -0.0015869140625000, -0.0028991699218750, +-0.0015258789062500, -0.0014038085937500, -0.0014343261718750, -0.0020141601562500, +-0.0014343261718750, -0.0012512207031250, -0.0013732910156250, 0.0000305175781250, +-0.0011596679687500, -0.0014953613281250, -0.0011596679687500, 0.0006713867187500, +-0.0013427734375000, -0.0001831054687500, -0.0010375976562500, -0.0001220703125000, +-0.0013427734375000, 0.0012512207031250, -0.0018005371093750, -0.0002136230468750, +-0.0013427734375000, 0.0012817382812500, -0.0020446777343750, 0.0009765625000000, +-0.0021057128906250, 0.0007629394531250, -0.0018920898437500, 0.0015258789062500, +-0.0021057128906250, 0.0010375976562500, -0.0020751953125000, 0.0013732910156250, +-0.0019226074218750, 0.0012207031250000, -0.0019226074218750, 0.0011901855468750, +-0.0018920898437500, 0.0012512207031250, -0.0017395019531250, 0.0007324218750000, +-0.0017395019531250, 0.0013732910156250, -0.0016479492187500, 0.0008544921875000, +-0.0016174316406250, 0.0009460449218750, -0.0014343261718750, 0.0013732910156250, +-0.0012207031250000, 0.0005187988281250, -0.0012817382812500, 0.0014343261718750, +-0.0008544921875000, 0.0007629394531250, -0.0006713867187500, 0.0007324218750000, +-0.0006408691406250, 0.0012207031250000, -0.0003662109375000, 0.0001220703125000, +-0.0000915527343750, 0.0009460449218750, -0.0000915527343750, 0.0003051757812500, +0.0001220703125000, 0.0000305175781250, 0.0002136230468750, 0.0003967285156250, +0.0003356933593750, -0.0005187988281250, 0.0005798339843750, -0.0006713867187500, +0.0006713867187500, -0.0009460449218750, 0.0007019042968750, -0.0010681152343750, +0.0008239746093750, -0.0011901855468750, 0.0009155273437500, -0.0016174316406250, +0.0009155273437500, -0.0010986328125000, 0.0010375976562500, -0.0014953613281250, +0.0010375976562500, -0.0016174316406250, 0.0011596679687500, -0.0013122558593750, +0.0011291503906250, -0.0018005371093750, 0.0009155273437500, -0.0017395019531250, +0.0013122558593750, -0.0018920898437500, 0.0011901855468750, -0.0022583007812500, +0.0013122558593750, -0.0021972656250000, 0.0017089843750000, -0.0020141601562500, +0.0015258789062500, -0.0027770996093750, 0.0020141601562500, -0.0018310546875000, +0.0023193359375000, -0.0020141601562500, 0.0020141601562500, -0.0031738281250000, +0.0021057128906250, -0.0024719238281250, 0.0026550292968750, -0.0029296875000000, +0.0015563964843750, -0.0031738281250000, 0.0020141601562500, -0.0027465820312500, +0.0017395019531250, -0.0027770996093750, 0.0010070800781250, -0.0032348632812500, +0.0017700195312500, -0.0023193359375000, 0.0002746582031250, -0.0033569335937500, +0.0007324218750000, -0.0032653808593750, 0.0007324218750000, -0.0026855468750000, +-0.0003356933593750, -0.0042419433593750, 0.0001220703125000, -0.0027465820312500, +-0.0000915527343750, -0.0032043457031250, -0.0005187988281250, -0.0034179687500000, +-0.0003051757812500, -0.0022888183593750, -0.0001831054687500, -0.0025024414062500, +-0.0007324218750000, -0.0023803710937500, -0.0008850097656250, -0.0017089843750000, +-0.0007019042968750, -0.0015258789062500, -0.0012207031250000, -0.0014343261718750, +-0.0018920898437500, -0.0009155273437500, -0.0015563964843750, -0.0009155273437500, +-0.0021057128906250, -0.0005187988281250, -0.0021667480468750, -0.0007629394531250, +-0.0017700195312500, -0.0010375976562500, -0.0016174316406250, -0.0001831054687500, +-0.0015869140625000, -0.0009765625000000, -0.0005798339843750, 0.0002746582031250, +-0.0003662109375000, 0.0001220703125000, -0.0003051757812500, -0.0000610351562500, +0.0000610351562500, 0.0022888183593750, 0.0002746582031250, 0.0001525878906250, +0.0009460449218750, 0.0022277832031250, 0.0006713867187500, 0.0025939941406250, +0.0004577636718750, 0.0006408691406250, 0.0009460449218750, 0.0027465820312500, +0.0010681152343750, 0.0014648437500000, 0.0001831054687500, 0.0011291503906250, +0.0002746582031250, 0.0016174316406250, 0.0003051757812500, 0.0016479492187500, +-0.0002136230468750, 0.0017700195312500, 0.0000305175781250, 0.0014038085937500, +0.0002136230468750, 0.0019531250000000, 0.0001220703125000, 0.0013427734375000, +0.0002746582031250, 0.0003051757812500, 0.0006408691406250, 0.0010070800781250, +0.0006408691406250, 0.0001831054687500, 0.0006713867187500, -0.0005493164062500, +0.0011901855468750, -0.0002136230468750, 0.0010986328125000, 0.0002441406250000, +0.0006103515625000, 0.0001525878906250, 0.0011901855468750, 0.0008544921875000, +0.0020446777343750, 0.0008850097656250, 0.0013427734375000, 0.0007629394531250, +0.0010986328125000, 0.0012817382812500, 0.0014343261718750, 0.0016174316406250, +0.0007629394531250, 0.0008544921875000, 0.0004272460937500, 0.0011901855468750, +0.0010681152343750, 0.0013122558593750, 0.0012207031250000, 0.0007934570312500, +0.0012207031250000, 0.0014038085937500, 0.0022583007812500, 0.0017089843750000, +0.0024414062500000}, +{0.0001831054687500, -0.0007324218750000, 0.0004882812500000, -0.0010375976562500, +0.0005187988281250, -0.0012207031250000, 0.0005493164062500, -0.0006103515625000, +0.0007019042968750, -0.0010681152343750, 0.0006713867187500, -0.0008239746093750, +0.0007934570312500, -0.0008544921875000, 0.0008239746093750, -0.0010375976562500, +0.0008850097656250, -0.0009460449218750, 0.0009460449218750, -0.0008850097656250, +0.0009765625000000, -0.0013427734375000, 0.0013122558593750, -0.0009460449218750, +0.0010986328125000, -0.0014343261718750, 0.0013732910156250, -0.0022583007812500, +0.0019836425781250, -0.0017395019531250, 0.0016784667968750, -0.0032043457031250, +0.0018920898437500, -0.0027160644531250, 0.0024108886718750, -0.0033569335937500, +0.0021972656250000, -0.0042419433593750, 0.0020446777343750, -0.0026245117187500, +0.0025329589843750, -0.0046997070312500, 0.0016479492187500, -0.0043334960937500, +0.0021972656250000, -0.0038452148437500, 0.0019226074218750, -0.0048522949218750, +0.0010681152343750, -0.0042114257812500, 0.0018615722656250, -0.0033569335937500, +0.0012207031250000, -0.0039978027343750, 0.0010070800781250, -0.0032043457031250, +0.0011596679687500, -0.0023193359375000, 0.0010375976562500, -0.0037841796875000, +0.0007629394531250, -0.0018920898437500, 0.0006713867187500, -0.0029296875000000, +0.0005493164062500, -0.0031127929687500, 0.0000610351562500, -0.0018310546875000, +-0.0002441406250000, -0.0031738281250000, -0.0002136230468750, -0.0023193359375000, +-0.0009460449218750, -0.0020751953125000, -0.0012817382812500, -0.0022277832031250, +-0.0011901855468750, -0.0019836425781250, -0.0014038085937500, -0.0018615722656250, +-0.0016784667968750, -0.0012512207031250, -0.0009460449218750, -0.0014343261718750, +-0.0014648437500000, -0.0007629394531250, -0.0009155273437500, 0.0001525878906250, +0.0000000000000000, -0.0005187988281250, -0.0008544921875000, -0.0001220703125000, +0.0001525878906250, 0.0003051757812500, -0.0000915527343750, -0.0003356933593750, +0.0000915527343750, -0.0004272460937500, 0.0005798339843750, 0.0005187988281250, +-0.0004577636718750, -0.0010681152343750, -0.0000305175781250, 0.0006103515625000, +0.0000915527343750, 0.0006408691406250, -0.0003051757812500, -0.0003967285156250, +-0.0005187988281250, 0.0020751953125000, -0.0005493164062500, 0.0007324218750000, +-0.0001831054687500, 0.0006408691406250, -0.0002136230468750, 0.0011901855468750, +0.0000000000000000, 0.0009460449218750, 0.0004882812500000, 0.0012817382812500, +0.0004272460937500, 0.0009155273437500, 0.0003356933593750, 0.0014648437500000, +0.0007324218750000, 0.0009155273437500, 0.0006408691406250, 0.0002746582031250, +0.0003356933593750, 0.0013427734375000, 0.0007019042968750, -0.0002136230468750, +0.0000610351562500, 0.0000915527343750, 0.0002441406250000, 0.0004272460937500, +0.0002441406250000, -0.0007019042968750, -0.0001831054687500, -0.0007934570312500, +0.0003662109375000, -0.0003356933593750, 0.0005798339843750, -0.0006408691406250, +0.0002746582031250, -0.0003967285156250, 0.0000000000000000, 0.0002136230468750, +0.0000915527343750, 0.0000000000000000, 0.0003662109375000, 0.0006713867187500, +0.0010070800781250, 0.0011901855468750, 0.0010986328125000, 0.0009765625000000, +0.0015563964843750, 0.0009765625000000, 0.0022888183593750, 0.0015258789062500, +0.0020446777343750, 0.0009155273437500, 0.0015563964843750, 0.0011291503906250, +0.0019531250000000, 0.0014038085937500, 0.0016479492187500, 0.0013427734375000, +0.0005798339843750, 0.0016784667968750, 0.0007324218750000, 0.0016479492187500, +0.0008544921875000, 0.0019836425781250, 0.0003662109375000, 0.0014953613281250, +0.0004272460937500, 0.0008850097656250, 0.0008850097656250, 0.0013122558593750, +0.0007629394531250, 0.0004882812500000, 0.0006713867187500, 0.0001220703125000, +0.0011901855468750, 0.0001220703125000, 0.0005187988281250, -0.0000915527343750, +-0.0002746582031250, -0.0002136230468750, 0.0003662109375000, -0.0003967285156250, +-0.0011291503906250, -0.0001525878906250, -0.0011291503906250, -0.0005187988281250, +-0.0014648437500000, -0.0009765625000000, -0.0022277832031250, -0.0005798339843750, +-0.0016784667968750, -0.0012817382812500, -0.0028991699218750, -0.0013427734375000, +-0.0019836425781250, -0.0009765625000000, -0.0023498535156250, -0.0011291503906250, +-0.0034179687500000, -0.0013122558593750, -0.0018310546875000, -0.0001831054687500, +-0.0033874511718750, -0.0003356933593750, -0.0028991699218750, 0.0001220703125000, +-0.0025024414062500, 0.0010375976562500, -0.0032348632812500, 0.0003967285156250, +-0.0025939941406250, 0.0013427734375000, -0.0022583007812500, 0.0012817382812500, +-0.0025634765625000, 0.0012207031250000, -0.0021057128906250, 0.0016479492187500, +-0.0014648437500000, 0.0011291503906250, -0.0019226074218750, 0.0015869140625000, +-0.0014343261718750, 0.0014648437500000, -0.0011596679687500, 0.0013732910156250, +-0.0015869140625000, 0.0015258789062500, -0.0017700195312500, 0.0013122558593750, +-0.0016479492187500, 0.0013427734375000, -0.0024108886718750, 0.0013427734375000, +-0.0025634765625000, 0.0015258789062500, -0.0024719238281250, 0.0017089843750000, +-0.0029602050781250, 0.0014953613281250, -0.0032348632812500, 0.0020751953125000, +-0.0025024414062500, 0.0020751953125000, -0.0033569335937500, 0.0016479492187500, +-0.0029907226562500, 0.0017395019531250, -0.0021057128906250, 0.0018615722656250, +-0.0032958984375000, 0.0009460449218750, -0.0019836425781250, 0.0011291503906250, +-0.0023803710937500, 0.0008850097656250, -0.0025634765625000, 0.0001831054687500, +-0.0019226074218750, 0.0004272460937500, -0.0025634765625000, 0.0001831054687500, +-0.0022277832031250, -0.0000305175781250, -0.0024108886718750, -0.0001220703125000, +-0.0024414062500000, -0.0000610351562500, -0.0023193359375000, -0.0001525878906250, +-0.0028686523437500, -0.0006408691406250, -0.0026550292968750, -0.0006408691406250, +-0.0028686523437500, -0.0007934570312500, -0.0032348632812500, -0.0012817382812500, +-0.0032653808593750, -0.0011596679687500, -0.0033264160156250, -0.0010375976562500, +-0.0038146972656250, -0.0012207031250000, -0.0039978027343750, -0.0010986328125000, +-0.0038452148437500, -0.0007934570312500, -0.0039367675781250, -0.0008850097656250, +-0.0041503906250000, -0.0006408691406250, -0.0039062500000000, -0.0006713867187500, +-0.0040588378906250, -0.0006713867187500, -0.0041809082031250, -0.0006103515625000, +-0.0041503906250000, -0.0007019042968750, -0.0043029785156250, -0.0007324218750000, +-0.0040283203125000, -0.0007324218750000, -0.0042114257812500, -0.0007019042968750, +-0.0042114257812500, -0.0007019042968750, -0.0039672851562500, -0.0007019042968750, +-0.0040893554687500, -0.0006713867187500, -0.0039367675781250, -0.0007324218750000, +-0.0038757324218750, -0.0007934570312500, -0.0037841796875000, -0.0007629394531250, +-0.0036315917968750, -0.0008239746093750, -0.0035705566406250, -0.0010070800781250, +-0.0036315917968750, -0.0009460449218750, -0.0033569335937500, -0.0009155273437500, +-0.0034790039062500, -0.0010986328125000, -0.0036315917968750, -0.0010375976562500, +-0.0032958984375000, -0.0009460449218750, -0.0038452148437500, -0.0010070800781250, +-0.0035705566406250, -0.0010375976562500, -0.0036315917968750, -0.0008544921875000, +-0.0040588378906250, -0.0010070800781250, -0.0036315917968750, -0.0011291503906250, +-0.0038452148437500, -0.0010070800781250, -0.0037231445312500, -0.0012512207031250, +-0.0036315917968750, -0.0016174316406250, -0.0036315917968750, -0.0013732910156250, +-0.0033264160156250, -0.0016784667968750, -0.0033264160156250, -0.0018615722656250, +-0.0029602050781250, -0.0014953613281250, -0.0028991699218750, -0.0014343261718750, +-0.0027465820312500, -0.0017395019531250, -0.0021057128906250, -0.0006713867187500, +-0.0027465820312500, -0.0010375976562500, -0.0017700195312500, -0.0007324218750000, +-0.0019836425781250, 0.0000610351562500, -0.0026245117187500, -0.0006103515625000, +-0.0013427734375000, 0.0004577636718750, -0.0031433105468750, 0.0003662109375000, +-0.0024414062500000, 0.0003356933593750, -0.0026245117187500, 0.0008850097656250, +-0.0041503906250000, 0.0005493164062500, -0.0031433105468750, 0.0008544921875000, +-0.0046081542968750, 0.0007019042968750, -0.0047607421875000, 0.0007629394531250, +-0.0046997070312500, 0.0009765625000000, -0.0054626464843750, 0.0007324218750000, +-0.0053405761718750, 0.0010070800781250, -0.0053710937500000, 0.0011596679687500, +-0.0054016113281250, 0.0010070800781250, -0.0052795410156250, 0.0010986328125000, +-0.0050659179687500, 0.0013122558593750, -0.0050048828125000, 0.0010986328125000, +-0.0050659179687500, 0.0011291503906250, -0.0047302246093750, 0.0014343261718750, +-0.0049133300781250, 0.0016174316406250, -0.0051879882812500, 0.0016174316406250, +-0.0047912597656250, 0.0019836425781250, -0.0054321289062500, 0.0021057128906250, +-0.0057373046875000, 0.0021057128906250, -0.0054931640625000, 0.0022277832031250, +-0.0057678222656250, 0.0022888183593750, -0.0062255859375000, 0.0019226074218750, +-0.0048828125000000, 0.0016784667968750, -0.0055236816406250, 0.0016174316406250, +-0.0048828125000000, 0.0012817382812500, -0.0036621093750000, 0.0007629394531250, +-0.0046997070312500, 0.0013732910156250, -0.0027465820312500, 0.0007324218750000, +-0.0031738281250000, 0.0007629394531250, -0.0031738281250000, 0.0015869140625000, +-0.0019226074218750, 0.0010375976562500, -0.0026855468750000, 0.0007629394531250, +-0.0026855468750000, 0.0011901855468750, -0.0022583007812500, 0.0004577636718750, +-0.0030822753906250, -0.0005493164062500, -0.0038452148437500, -0.0002136230468750, +-0.0031738281250000, -0.0015258789062500, -0.0037841796875000, -0.0017395019531250, +-0.0033569335937500, -0.0021362304687500, -0.0027770996093750, -0.0029296875000000, +-0.0026855468750000, -0.0027770996093750, -0.0018615722656250, -0.0037536621093750, +-0.0009765625000000, -0.0035705566406250, -0.0001831054687500, -0.0039978027343750, +-0.0000305175781250, -0.0048522949218750, 0.0004577636718750, -0.0043640136718750, +0.0013732910156250, -0.0050659179687500, -0.0003662109375000, -0.0051574707031250, +0.0001220703125000, -0.0047302246093750, 0.0003662109375000, -0.0046691894531250, +-0.0007934570312500, -0.0045471191406250, -0.0004577636718750, -0.0037536621093750, +0.0000610351562500, -0.0038146972656250, -0.0000610351562500, -0.0035095214843750, +-0.0003051757812500, -0.0026550292968750, -0.0001831054687500, -0.0038452148437500, +-0.0003356933593750, -0.0004272460937500, -0.0005798339843750, -0.0010070800781250, +0.0000000000000000, -0.0010986328125000, -0.0009460449218750, -0.0001220703125000, +-0.0014648437500000, -0.0000915527343750, -0.0004272460937500, -0.0007324218750000, +-0.0032348632812500, -0.0007629394531250, -0.0034179687500000, -0.0006408691406250, +-0.0033874511718750, -0.0012207031250000, -0.0050048828125000, -0.0018005371093750, +-0.0049743652343750, -0.0007019042968750, -0.0043945312500000, -0.0014038085937500, +-0.0047302246093750, -0.0014343261718750, -0.0044555664062500, -0.0005493164062500, +-0.0036010742187500, -0.0013732910156250, -0.0036926269531250, -0.0014038085937500, +-0.0035400390625000, -0.0015258789062500, -0.0038452148437500, -0.0021667480468750, +-0.0031433105468750, -0.0027770996093750, -0.0028076171875000, -0.0028686523437500, +-0.0036926269531250, -0.0025329589843750, -0.0008850097656250, -0.0032958984375000, +-0.0014343261718750, -0.0026550292968750, -0.0010070800781250, -0.0015563964843750, +0.0012817382812500, -0.0022583007812500, 0.0003051757812500, -0.0014038085937500, +0.0003051757812500, -0.0008544921875000, 0.0010375976562500, -0.0015563964843750, +0.0005187988281250}, +{-0.0019836425781250, 0.0007324218750000, -0.0025024414062500, 0.0008239746093750, +-0.0033264160156250, 0.0010375976562500, -0.0026855468750000, 0.0004577636718750, +-0.0043945312500000, 0.0007019042968750, -0.0042114257812500, 0.0006713867187500, +-0.0044555664062500, 0.0003051757812500, -0.0056457519531250, 0.0007019042968750, +-0.0051574707031250, 0.0006408691406250, -0.0058593750000000, 0.0007324218750000, +-0.0060729980468750, 0.0010070800781250, -0.0057678222656250, 0.0010681152343750, +-0.0058593750000000, 0.0010986328125000, -0.0057983398437500, 0.0012817382812500, +-0.0050354003906250, 0.0012207031250000, -0.0049743652343750, 0.0011901855468750, +-0.0047607421875000, 0.0010986328125000, -0.0040283203125000, 0.0007324218750000, +-0.0039367675781250, 0.0010986328125000, -0.0039978027343750, 0.0001525878906250, +-0.0035705566406250, 0.0003967285156250, -0.0037536621093750, 0.0010070800781250, +-0.0040893554687500, -0.0001831054687500, -0.0034484863281250, 0.0010681152343750, +-0.0039978027343750, 0.0011596679687500, -0.0041503906250000, 0.0007629394531250, +-0.0037841796875000, 0.0010070800781250, -0.0036621093750000, 0.0008239746093750, +-0.0036621093750000, 0.0000915527343750, -0.0028686523437500, 0.0000305175781250, +-0.0029602050781250, -0.0009460449218750, -0.0029907226562500, -0.0018615722656250, +-0.0024414062500000, -0.0013122558593750, -0.0025634765625000, -0.0032653808593750, +-0.0029907226562500, -0.0029602050781250, -0.0021667480468750, -0.0033874511718750, +-0.0026550292968750, -0.0047302246093750, -0.0032958984375000, -0.0039672851562500, +-0.0017395019531250, -0.0051574707031250, -0.0031127929687500, -0.0051879882812500, +-0.0025634765625000, -0.0049743652343750, -0.0013732910156250, -0.0054626464843750, +-0.0012817382812500, -0.0054626464843750, -0.0006713867187500, -0.0050048828125000, +0.0006713867187500, -0.0055236816406250, 0.0014343261718750, -0.0050048828125000, +0.0011291503906250, -0.0046386718750000, 0.0012817382812500, -0.0057373046875000, +0.0021362304687500, -0.0032348632812500, 0.0002441406250000, -0.0047607421875000, +0.0004272460937500, -0.0044250488281250, 0.0006408691406250, -0.0002746582031250, +-0.0008239746093750, 0.0002136230468750, 0.0023193359375000, 0.0000305175781250, +0.0007019042968750, -0.0001220703125000, 0.0011291503906250, 0.0002136230468750, +0.0006103515625000, 0.0000915527343750, -0.0002136230468750, -0.0005798339843750, +0.0000000000000000, 0.0009155273437500, -0.0008239746093750, 0.0003662109375000, +-0.0003356933593750, -0.0000610351562500, -0.0009765625000000, 0.0008239746093750, +-0.0022277832031250, 0.0002441406250000, -0.0017089843750000, -0.0010681152343750, +-0.0032043457031250, -0.0009155273437500, -0.0039978027343750, -0.0014953613281250, +-0.0036621093750000, -0.0028991699218750, -0.0041198730468750, -0.0028381347656250, +-0.0046997070312500, -0.0021667480468750, -0.0031738281250000, -0.0030212402343750, +-0.0035705566406250, -0.0021667480468750, -0.0032348632812500, -0.0006103515625000, +-0.0021057128906250, -0.0014953613281250, -0.0027465820312500, -0.0007324218750000, +-0.0013732910156250, 0.0002746582031250, -0.0019226074218750, -0.0008850097656250, +-0.0013427734375000, -0.0017089843750000, -0.0002746582031250, -0.0004882812500000, +-0.0014953613281250, -0.0027160644531250, 0.0008239746093750, -0.0025329589843750, +0.0005187988281250, -0.0023498535156250, 0.0001220703125000, -0.0034484863281250, +0.0015258789062500, -0.0028076171875000, 0.0012512207031250, -0.0028076171875000, +0.0003356933593750, -0.0027465820312500, 0.0006408691406250, -0.0024108886718750, +0.0006408691406250, -0.0021057128906250, -0.0003356933593750, -0.0019226074218750, +-0.0004882812500000, -0.0025024414062500, 0.0002746582031250, -0.0021972656250000, +-0.0001220703125000, -0.0021972656250000, -0.0000305175781250, -0.0029907226562500, +0.0008239746093750, -0.0031738281250000, 0.0003967285156250, -0.0024108886718750, +0.0003356933593750, -0.0037231445312500, 0.0004272460937500, -0.0031738281250000, +0.0003051757812500, -0.0022888183593750, 0.0000305175781250, -0.0041809082031250, +-0.0000915527343750, -0.0013427734375000, 0.0004272460937500, -0.0025329589843750, +0.0001831054687500, -0.0023193359375000, 0.0001220703125000, -0.0000305175781250, +0.0004272460937500, -0.0016479492187500, 0.0003356933593750, -0.0004882812500000, +0.0003051757812500, 0.0000305175781250, 0.0002441406250000, -0.0005798339843750, +0.0004577636718750, -0.0004577636718750, 0.0004577636718750, 0.0000915527343750, +0.0002441406250000, -0.0007324218750000, 0.0006408691406250, -0.0004882812500000, +0.0007324218750000, -0.0003967285156250, 0.0004882812500000, -0.0008544921875000, +0.0005798339843750, -0.0005493164062500, 0.0007934570312500, -0.0006408691406250, +0.0000915527343750, -0.0007934570312500, 0.0000915527343750, -0.0003967285156250, +0.0000915527343750, -0.0001525878906250, -0.0003662109375000, -0.0003051757812500, +-0.0003051757812500, 0.0004882812500000, -0.0004577636718750, 0.0003967285156250, +-0.0004882812500000, 0.0006408691406250, -0.0006713867187500, 0.0011901855468750, +-0.0008239746093750, 0.0008544921875000, -0.0008239746093750, 0.0014953613281250, +-0.0012817382812500, 0.0012512207031250, -0.0012817382812500, 0.0012817382812500, +-0.0014343261718750, 0.0015258789062500, -0.0017395019531250, 0.0009155273437500, +-0.0014953613281250, 0.0011596679687500, -0.0021972656250000, 0.0008850097656250, +-0.0019531250000000, 0.0001220703125000, -0.0021362304687500, -0.0001220703125000, +-0.0027465820312500, 0.0000305175781250, -0.0023498535156250, -0.0011901855468750, +-0.0027465820312500, -0.0007934570312500, -0.0028381347656250, -0.0013732910156250, +-0.0028076171875000, -0.0024108886718750, -0.0029296875000000, -0.0016479492187500, +-0.0028686523437500, -0.0032653808593750, -0.0028686523437500, -0.0033569335937500, +-0.0028686523437500, -0.0033569335937500, -0.0026245117187500, -0.0042114257812500, +-0.0024414062500000, -0.0041198730468750, -0.0025024414062500, -0.0042419433593750, +-0.0020446777343750, -0.0043029785156250, -0.0019226074218750, -0.0043945312500000, +-0.0018920898437500, -0.0043334960937500, -0.0017395019531250, -0.0040283203125000, +-0.0016479492187500, -0.0043945312500000, -0.0017089843750000, -0.0043640136718750, +-0.0017089843750000, -0.0043029785156250, -0.0016174316406250, -0.0046691894531250, +-0.0015869140625000, -0.0048522949218750, -0.0016784667968750, -0.0045471191406250, +-0.0014038085937500, -0.0050048828125000, -0.0014343261718750, -0.0049438476562500, +-0.0014038085937500, -0.0045166015625000, -0.0011291503906250, -0.0049438476562500, +-0.0012207031250000, -0.0043029785156250, -0.0011596679687500, -0.0043640136718750, +-0.0010986328125000, -0.0041809082031250, -0.0011596679687500, -0.0037231445312500, +-0.0011901855468750, -0.0039672851562500, -0.0011291503906250, -0.0030822753906250, +-0.0009765625000000, -0.0034179687500000, -0.0010681152343750, -0.0034484863281250, +-0.0008850097656250, -0.0029907226562500, -0.0006103515625000, -0.0034484863281250, +-0.0006713867187500, -0.0033569335937500, -0.0000305175781250, -0.0030822753906250, +-0.0000305175781250, -0.0035705566406250, 0.0002441406250000, -0.0038146972656250, +0.0008239746093750, -0.0032348632812500, 0.0007629394531250, -0.0042114257812500, +0.0009765625000000, -0.0038452148437500, 0.0012207031250000, -0.0037536621093750, +0.0012207031250000, -0.0041809082031250, 0.0012207031250000, -0.0035705566406250, +0.0013122558593750, -0.0039367675781250, 0.0013427734375000, -0.0035400390625000, +0.0013122558593750, -0.0034790039062500, 0.0014038085937500, -0.0036621093750000, +0.0014343261718750, -0.0029602050781250, 0.0013427734375000, -0.0035400390625000, +0.0016784667968750, -0.0027160644531250, 0.0015869140625000, -0.0028381347656250, +0.0013427734375000, -0.0031127929687500, 0.0014648437500000, -0.0017089843750000, +0.0015258789062500, -0.0034484863281250, 0.0008544921875000, -0.0022277832031250, +0.0012207031250000, -0.0025329589843750, 0.0008850097656250, -0.0040893554687500, +0.0003967285156250, -0.0022888183593750, 0.0010986328125000, -0.0040283203125000, +-0.0001220703125000, -0.0041809082031250, 0.0003051757812500, -0.0033874511718750, +0.0001525878906250, -0.0042114257812500, -0.0006408691406250, -0.0049133300781250, +0.0002441406250000, -0.0031738281250000, -0.0007324218750000, -0.0047607421875000, +-0.0006713867187500, -0.0042724609375000, -0.0003356933593750, -0.0025634765625000, +-0.0006408691406250, -0.0045471191406250, -0.0006103515625000, -0.0018920898437500, +-0.0008544921875000, -0.0022583007812500, -0.0007324218750000, -0.0020446777343750, +-0.0008544921875000, -0.0004882812500000, -0.0013427734375000, -0.0017700195312500, +-0.0014648437500000, -0.0007019042968750, -0.0012207031250000, -0.0014648437500000, +-0.0014648437500000, -0.0013732910156250, -0.0013427734375000, -0.0008850097656250, +-0.0010681152343750, -0.0024719238281250, -0.0012817382812500, -0.0007629394531250, +-0.0004577636718750, -0.0018920898437500, -0.0003662109375000, -0.0021057128906250, +-0.0004577636718750, -0.0007324218750000, -0.0000915527343750, -0.0019226074218750, +0.0000915527343750, -0.0015869140625000, -0.0006408691406250, -0.0014038085937500, +-0.0003051757812500, -0.0017700195312500, -0.0001831054687500, -0.0021057128906250, +-0.0007934570312500, -0.0021057128906250, -0.0006713867187500, -0.0014953613281250, +-0.0004577636718750, -0.0024719238281250, -0.0009460449218750, -0.0015869140625000, +-0.0006713867187500, -0.0004272460937500, -0.0003967285156250, -0.0020446777343750, +-0.0012817382812500, 0.0000000000000000, -0.0002746582031250, -0.0000610351562500, +-0.0007629394531250, -0.0010070800781250, -0.0008239746093750, -0.0001220703125000, +-0.0000610351562500, 0.0009155273437500, -0.0005187988281250, 0.0003051757812500, +0.0000305175781250, -0.0000305175781250, -0.0001220703125000, 0.0000915527343750, +0.0000610351562500, -0.0002746582031250, 0.0005493164062500, -0.0010070800781250, +0.0000610351562500, -0.0004272460937500, 0.0003051757812500, -0.0007019042968750, +0.0000915527343750, -0.0010070800781250, 0.0000000000000000, -0.0007019042968750, +0.0000000000000000, -0.0010070800781250, -0.0005493164062500, -0.0012512207031250, +-0.0002441406250000, -0.0013122558593750, -0.0002136230468750, -0.0016479492187500, +-0.0009155273437500, -0.0018615722656250, -0.0010070800781250, -0.0015563964843750, +-0.0003967285156250, -0.0020751953125000, -0.0016174316406250, -0.0017089843750000, +-0.0011901855468750, -0.0017395019531250, -0.0015563964843750, -0.0019531250000000, +-0.0025939941406250, -0.0012512207031250, -0.0018310546875000, -0.0014038085937500, +-0.0030212402343750, -0.0011901855468750, -0.0027770996093750, -0.0006408691406250, +-0.0033569335937500, -0.0005493164062500, -0.0042114257812500, -0.0006713867187500, +-0.0030822753906250, -0.0000305175781250, -0.0046997070312500, -0.0003356933593750, +-0.0043334960937500, -0.0003662109375000, -0.0036926269531250, -0.0002136230468750, +-0.0043029785156250, -0.0010681152343750, -0.0039062500000000, -0.0004272460937500, +-0.0027770996093750, -0.0008544921875000, -0.0032348632812500, -0.0009155273437500, +-0.0029296875000000, -0.0004882812500000, -0.0020446777343750, -0.0011596679687500, +-0.0028076171875000, -0.0007934570312500, -0.0023193359375000, -0.0011291503906250, +-0.0026855468750000, -0.0011901855468750, -0.0030517578125000, -0.0011291503906250, +-0.0029602050781250, -0.0016479492187500, -0.0033874511718750, -0.0006408691406250, +-0.0032653808593750, -0.0012207031250000, -0.0035095214843750, -0.0005493164062500, +-0.0033874511718750, 0.0006713867187500, -0.0032043457031250, -0.0004577636718750, +-0.0035705566406250}, +{-0.0013122558593750, -0.0029907226562500, -0.0000305175781250, -0.0032043457031250, +-0.0009765625000000, -0.0041809082031250, -0.0003967285156250, -0.0038146972656250, +-0.0005493164062500, -0.0037841796875000, -0.0012817382812500, -0.0052490234375000, +-0.0000305175781250, -0.0038757324218750, -0.0015258789062500, -0.0048217773437500, +-0.0013732910156250, -0.0046691894531250, -0.0008239746093750, -0.0033874511718750, +-0.0011291503906250, -0.0043945312500000, -0.0008850097656250, -0.0024414062500000, +-0.0010375976562500, -0.0025634765625000, -0.0008850097656250, -0.0026550292968750, +-0.0007934570312500, -0.0015258789062500, -0.0008239746093750, -0.0018005371093750, +-0.0007324218750000, -0.0016784667968750, -0.0010986328125000, -0.0018005371093750, +-0.0009460449218750, -0.0019226074218750, -0.0010681152343750, -0.0018615722656250, +-0.0014953613281250, -0.0019531250000000, -0.0013427734375000, -0.0021057128906250, +-0.0010681152343750, -0.0021057128906250, -0.0019226074218750, -0.0021057128906250, +-0.0015563964843750, -0.0020751953125000, -0.0010070800781250, -0.0018615722656250, +-0.0021362304687500, -0.0019226074218750, -0.0007019042968750, -0.0023193359375000, +-0.0014343261718750, -0.0018005371093750, -0.0015258789062500, -0.0018920898437500, +-0.0004882812500000, -0.0029296875000000, -0.0013427734375000, -0.0005798339843750, +-0.0008544921875000, -0.0020141601562500, -0.0007629394531250, -0.0021362304687500, +-0.0007934570312500, 0.0010070800781250, -0.0005493164062500, 0.0014953613281250, +-0.0007019042968750, 0.0006103515625000, -0.0002136230468750, 0.0010986328125000, +-0.0003662109375000, 0.0009765625000000, -0.0003356933593750, 0.0000000000000000, +0.0000000000000000, 0.0000305175781250, -0.0003356933593750, 0.0000305175781250, +-0.0002441406250000, -0.0009460449218750, -0.0000915527343750, -0.0008239746093750, +-0.0006408691406250, -0.0004272460937500, -0.0008850097656250, -0.0014343261718750, +-0.0006103515625000, -0.0007934570312500, -0.0020141601562500, -0.0012207031250000, +-0.0016479492187500, -0.0016479492187500, -0.0018310546875000, -0.0014953613281250, +-0.0026855468750000, -0.0020751953125000, -0.0020751953125000, -0.0019226074218750, +-0.0031127929687500, -0.0022277832031250, -0.0029296875000000, -0.0021362304687500, +-0.0033264160156250, -0.0016784667968750, -0.0041198730468750, -0.0019531250000000, +-0.0034484863281250, -0.0016174316406250, -0.0044860839843750, -0.0012207031250000, +-0.0039978027343750, -0.0013122558593750, -0.0037231445312500, -0.0012817382812500, +-0.0043640136718750, -0.0007324218750000, -0.0035705566406250, -0.0007629394531250, +-0.0027465820312500, -0.0007934570312500, -0.0030822753906250, -0.0003051757812500, +-0.0023803710937500, 0.0000610351562500, -0.0015563964843750, -0.0002136230468750, +-0.0024719238281250, 0.0002136230468750, -0.0014038085937500, 0.0000610351562500, +-0.0020751953125000, -0.0003662109375000, -0.0022277832031250, -0.0004577636718750, +-0.0018310546875000, -0.0006408691406250, -0.0030212402343750, -0.0011291503906250, +-0.0020141601562500, -0.0013122558593750, -0.0028076171875000, -0.0015869140625000, +-0.0028686523437500, -0.0019226074218750, -0.0021362304687500, -0.0018615722656250, +-0.0031738281250000, -0.0020751953125000, -0.0023193359375000, -0.0023498535156250, +-0.0025024414062500, -0.0020141601562500, -0.0027770996093750, -0.0019836425781250, +-0.0025939941406250, -0.0024414062500000, -0.0031433105468750, -0.0010070800781250, +-0.0027160644531250, -0.0017089843750000, -0.0034484863281250, -0.0011901855468750, +-0.0031738281250000, 0.0001831054687500, -0.0026550292968750, -0.0010681152343750, +-0.0038452148437500, 0.0003051757812500, -0.0021667480468750, 0.0002441406250000, +-0.0030212402343750, -0.0001525878906250, -0.0029907226562500, 0.0002136230468750, +-0.0017089843750000, -0.0000610351562500, -0.0028381347656250, -0.0000305175781250, +-0.0021362304687500, -0.0001525878906250, -0.0019226074218750, -0.0002136230468750, +-0.0020446777343750, -0.0000305175781250, -0.0018005371093750, -0.0002746582031250, +-0.0018310546875000, -0.0001220703125000, -0.0022583007812500, -0.0000305175781250, +-0.0022888183593750, -0.0001525878906250, -0.0025024414062500, -0.0001220703125000, +-0.0029602050781250, -0.0000610351562500, -0.0030212402343750, -0.0003662109375000, +-0.0032958984375000, -0.0000610351562500, -0.0034179687500000, -0.0002746582031250, +-0.0036315917968750, -0.0005798339843750, -0.0038757324218750, -0.0000305175781250, +-0.0037231445312500, -0.0008850097656250, -0.0040283203125000, -0.0005493164062500, +-0.0039062500000000, -0.0007324218750000, -0.0033874511718750, -0.0014648437500000, +-0.0031738281250000, -0.0009155273437500, -0.0032348632812500, -0.0016174316406250, +-0.0025024414062500, -0.0017700195312500, -0.0025024414062500, -0.0017700195312500, +-0.0023498535156250, -0.0021057128906250, -0.0020141601562500, -0.0021362304687500, +-0.0021362304687500, -0.0023803710937500, -0.0016174316406250, -0.0023803710937500, +-0.0018005371093750, -0.0025634765625000, -0.0016174316406250, -0.0028076171875000, +-0.0011901855468750, -0.0027465820312500, -0.0017395019531250, -0.0029602050781250, +-0.0012512207031250, -0.0029907226562500, -0.0012207031250000, -0.0027770996093750, +-0.0015258789062500, -0.0027160644531250, -0.0014038085937500, -0.0027770996093750, +-0.0013427734375000, -0.0023498535156250, -0.0017700195312500, -0.0024108886718750, +-0.0015563964843750, -0.0024414062500000, -0.0015869140625000, -0.0021972656250000, +-0.0018615722656250, -0.0023498535156250, -0.0015563964843750, -0.0024414062500000, +-0.0020751953125000, -0.0022583007812500, -0.0016784667968750, -0.0023498535156250, +-0.0018615722656250, -0.0023498535156250, -0.0021972656250000, -0.0020141601562500, +-0.0014953613281250, -0.0019836425781250, -0.0021057128906250, -0.0018310546875000, +-0.0017395019531250, -0.0014953613281250, -0.0015258789062500, -0.0013732910156250, +-0.0018920898437500, -0.0015258789062500, -0.0015563964843750, -0.0010070800781250, +-0.0017395019531250, -0.0014038085937500, -0.0017089843750000, -0.0012817382812500, +-0.0015869140625000, -0.0008544921875000, -0.0017089843750000, -0.0014038085937500, +-0.0016479492187500, -0.0008239746093750, -0.0015869140625000, -0.0008544921875000, +-0.0019531250000000, -0.0009155273437500, -0.0017395019531250, -0.0005798339843750, +-0.0016784667968750, -0.0007019042968750, -0.0023193359375000, -0.0007019042968750, +-0.0013122558593750, -0.0006408691406250, -0.0019531250000000, -0.0007324218750000, +-0.0015869140625000, -0.0008239746093750, -0.0006408691406250, -0.0008239746093750, +-0.0017089843750000, -0.0008850097656250, -0.0001525878906250, -0.0009765625000000, +-0.0003051757812500, -0.0009765625000000, -0.0003967285156250, -0.0010375976562500, +0.0005798339843750, -0.0011291503906250, 0.0003662109375000, -0.0009765625000000, +0.0001831054687500, -0.0010375976562500, 0.0008239746093750, -0.0008544921875000, +0.0002441406250000, -0.0006103515625000, -0.0003051757812500, -0.0007629394531250, +0.0006713867187500, -0.0004882812500000, -0.0011291503906250, -0.0006408691406250, +-0.0005493164062500, -0.0004882812500000, -0.0009765625000000, -0.0003356933593750, +-0.0022277832031250, -0.0008239746093750, -0.0009460449218750, -0.0001220703125000, +-0.0024414062500000, -0.0003967285156250, -0.0018920898437500, -0.0005798339843750, +-0.0017395019531250, -0.0003356933593750, -0.0023803710937500, -0.0009155273437500, +-0.0012817382812500, -0.0005187988281250, -0.0024108886718750, -0.0014343261718750, +-0.0014953613281250, -0.0011291503906250, -0.0019836425781250, -0.0003356933593750, +-0.0030517578125000, -0.0014038085937500, -0.0014648437500000, 0.0001525878906250, +-0.0041809082031250, 0.0001220703125000, -0.0034484863281250, -0.0001525878906250, +-0.0035095214843750, 0.0004577636718750, -0.0052490234375000, 0.0000305175781250, +-0.0039367675781250, -0.0003662109375000, -0.0047302246093750, -0.0004577636718750, +-0.0042724609375000, -0.0008544921875000, -0.0038146972656250, -0.0013427734375000, +-0.0040893554687500, -0.0014343261718750, -0.0034790039062500, -0.0016784667968750, +-0.0031127929687500, -0.0019836425781250, -0.0027770996093750, -0.0021667480468750, +-0.0025024414062500, -0.0023498535156250, -0.0021972656250000, -0.0023498535156250, +-0.0020141601562500, -0.0026245117187500, -0.0023193359375000, -0.0027160644531250, +-0.0020751953125000, -0.0028381347656250, -0.0025024414062500, -0.0032958984375000, +-0.0034484863281250, -0.0034790039062500, -0.0032348632812500, -0.0026550292968750, +-0.0033569335937500, -0.0036926269531250, -0.0043029785156250, -0.0025939941406250, +-0.0033569335937500, -0.0013427734375000, -0.0022583007812500, -0.0031738281250000, +-0.0032653808593750, 0.0003967285156250, -0.0012817382812500, -0.0007934570312500, +-0.0008850097656250, -0.0008239746093750, -0.0010375976562500, 0.0014648437500000, +-0.0001525878906250, -0.0002746582031250, 0.0002136230468750, 0.0001525878906250, +-0.0000305175781250, 0.0002136230468750, 0.0001220703125000, 0.0000610351562500, +0.0007629394531250, 0.0003356933593750, 0.0012207031250000, -0.0001220703125000, +0.0008239746093750, -0.0006408691406250, 0.0003356933593750, -0.0004882812500000, +0.0001220703125000, -0.0011291503906250, 0.0010070800781250, -0.0019836425781250, +0.0016174316406250, -0.0018920898437500, 0.0011596679687500, -0.0018615722656250, +0.0024414062500000, -0.0028686523437500, 0.0025329589843750, -0.0023193359375000, +0.0018310546875000, -0.0015563964843750, 0.0018920898437500, -0.0027465820312500, +0.0018920898437500, -0.0015258789062500, 0.0004577636718750, -0.0014343261718750, +0.0003662109375000, -0.0021057128906250, 0.0006103515625000, -0.0019531250000000, +-0.0001220703125000, -0.0018615722656250, -0.0003967285156250, -0.0025634765625000, +0.0003051757812500, -0.0028991699218750, -0.0000610351562500, -0.0023803710937500, +-0.0006103515625000, -0.0023803710937500, -0.0003662109375000, -0.0029907226562500, +-0.0005187988281250, -0.0015563964843750, -0.0014343261718750, -0.0015869140625000, +-0.0014648437500000, -0.0020751953125000, -0.0011596679687500, -0.0015869140625000, +-0.0014953613281250, -0.0017395019531250, -0.0015258789062500, -0.0027160644531250, +0.0000000000000000, -0.0026855468750000, -0.0003051757812500, -0.0028991699218750, +0.0000000000000000, -0.0037231445312500, 0.0011291503906250, -0.0035400390625000, +0.0004882812500000, -0.0028076171875000, 0.0008544921875000, -0.0036315917968750, +0.0006713867187500, -0.0023803710937500, 0.0004882812500000, -0.0008544921875000, +0.0007934570312500, -0.0022583007812500, 0.0007324218750000, 0.0001831054687500, +0.0007324218750000, 0.0000305175781250, 0.0009765625000000, -0.0004577636718750, +0.0008239746093750, 0.0004882812500000, 0.0004577636718750, 0.0000000000000000, +0.0005187988281250, -0.0003662109375000, 0.0001525878906250, 0.0000000000000000, +-0.0000610351562500, -0.0004272460937500, -0.0000305175781250, -0.0008850097656250, +-0.0000610351562500, -0.0000610351562500, -0.0001525878906250, -0.0006713867187500, +-0.0000915527343750, -0.0003662109375000, -0.0000305175781250, 0.0002136230468750, +-0.0001525878906250, 0.0002746582031250, -0.0002746582031250, 0.0007324218750000, +-0.0001220703125000, 0.0013732910156250, -0.0003051757812500, 0.0015869140625000, +-0.0003356933593750, 0.0017395019531250, -0.0001831054687500, 0.0019836425781250, +-0.0000610351562500, 0.0019836425781250, -0.0001220703125000, 0.0014953613281250, +0.0000610351562500, 0.0016784667968750, 0.0001831054687500, 0.0011291503906250, +0.0000610351562500, 0.0005187988281250, 0.0000000000000000, 0.0010070800781250, +0.0001525878906250, -0.0005798339843750, -0.0000915527343750, -0.0003356933593750, +-0.0001220703125000}, +{-0.0030517578125000, -0.0027770996093750, -0.0031738281250000, -0.0021972656250000, +-0.0026855468750000, -0.0013122558593750, -0.0019531250000000, -0.0025329589843750, +-0.0021972656250000, 0.0000305175781250, -0.0024719238281250, -0.0009460449218750, +-0.0023193359375000, -0.0005187988281250, -0.0029296875000000, 0.0014343261718750, +-0.0039367675781250, -0.0005187988281250, -0.0038452148437500, 0.0008850097656250, +-0.0033264160156250, 0.0008850097656250, -0.0043945312500000, 0.0000610351562500, +-0.0031433105468750, 0.0001831054687500, -0.0014648437500000, 0.0003356933593750, +-0.0027465820312500, 0.0002746582031250, -0.0001220703125000, -0.0000610351562500, +0.0003051757812500, 0.0000305175781250, -0.0002136230468750, 0.0004882812500000, +0.0006408691406250, -0.0014038085937500, -0.0016174316406250, -0.0015869140625000, +-0.0000305175781250, -0.0022277832031250, 0.0001220703125000, -0.0020751953125000, +-0.0000305175781250, -0.0019531250000000, -0.0000305175781250, -0.0028381347656250, +0.0000610351562500, -0.0025634765625000, 0.0003662109375000, -0.0028686523437500, +0.0001831054687500, -0.0032653808593750, 0.0007324218750000, -0.0034484863281250, +0.0015563964843750, -0.0038452148437500, 0.0012207031250000, -0.0031433105468750, +0.0016479492187500, -0.0037841796875000, 0.0020446777343750, -0.0032043457031250, +0.0015258789062500, -0.0021362304687500, 0.0011596679687500, -0.0031127929687500, +0.0014953613281250, -0.0017089843750000, 0.0006408691406250, -0.0016784667968750, +0.0003051757812500, -0.0023193359375000, 0.0004882812500000, -0.0021667480468750, +0.0002746582031250, -0.0022888183593750, -0.0001831054687500, -0.0034484863281250, +0.0001220703125000, -0.0038757324218750, 0.0002136230468750, -0.0035095214843750, +-0.0004577636718750, -0.0037841796875000, -0.0007629394531250, -0.0042114257812500, +-0.0004272460937500, -0.0025024414062500, -0.0010986328125000, -0.0029296875000000, +-0.0013122558593750, -0.0023193359375000, -0.0005187988281250, -0.0008850097656250, +-0.0001525878906250, -0.0016479492187500, -0.0005187988281250, -0.0004272460937500, +0.0010681152343750, -0.0004577636718750, 0.0009765625000000, -0.0007019042968750, +0.0008544921875000, -0.0004577636718750, 0.0014648437500000, -0.0007629394531250, +0.0010070800781250, -0.0004882812500000, 0.0008850097656250, -0.0010070800781250, +0.0011901855468750, -0.0006713867187500, 0.0009460449218750, 0.0001220703125000, +0.0008239746093750, -0.0003051757812500, 0.0011291503906250, 0.0006713867187500, +0.0005798339843750, 0.0010681152343750, 0.0005798339843750, 0.0011596679687500, +0.0004272460937500, 0.0018005371093750, -0.0000610351562500, 0.0021667480468750, +0.0000915527343750, 0.0018310546875000, -0.0000305175781250, 0.0025939941406250, +-0.0001831054687500, 0.0022583007812500, -0.0001220703125000, 0.0014648437500000, +0.0000000000000000, 0.0023193359375000, 0.0000000000000000, 0.0010375976562500, +-0.0001220703125000, 0.0008544921875000, 0.0001525878906250, 0.0008544921875000, +-0.0000915527343750, 0.0001220703125000, -0.0004577636718750, -0.0000305175781250, +-0.0000305175781250, 0.0000000000000000, -0.0004882812500000, -0.0004577636718750, +-0.0005187988281250, -0.0003051757812500, -0.0003356933593750, -0.0001831054687500, +-0.0003051757812500, -0.0006408691406250, -0.0002136230468750, 0.0004272460937500, +-0.0002441406250000, -0.0000915527343750, -0.0000610351562500, 0.0001525878906250, +-0.0002746582031250, 0.0010375976562500, -0.0005187988281250, 0.0001220703125000, +-0.0002746582031250, 0.0007019042968750, -0.0008239746093750, 0.0007934570312500, +-0.0007934570312500, 0.0002441406250000, -0.0009460449218750, 0.0001525878906250, +-0.0013122558593750, 0.0003356933593750, -0.0010070800781250, -0.0006713867187500, +-0.0017089843750000, -0.0002746582031250, -0.0016479492187500, -0.0007324218750000, +-0.0017089843750000, -0.0015563964843750, -0.0021667480468750, -0.0007934570312500, +-0.0020141601562500, -0.0020446777343750, -0.0018920898437500, -0.0018005371093750, +-0.0019836425781250, -0.0016479492187500, -0.0019531250000000, -0.0022277832031250, +-0.0018310546875000, -0.0018310546875000, -0.0019531250000000, -0.0021362304687500, +-0.0020141601562500, -0.0022277832031250, -0.0020446777343750, -0.0020751953125000, +-0.0021057128906250, -0.0021667480468750, -0.0022277832031250, -0.0022888183593750, +-0.0022888183593750, -0.0021972656250000, -0.0022583007812500, -0.0016479492187500, +-0.0023803710937500, -0.0018615722656250, -0.0023803710937500, -0.0017089843750000, +-0.0023193359375000, -0.0004882812500000, -0.0024719238281250, -0.0018005371093750, +-0.0023803710937500, -0.0011291503906250, -0.0023803710937500, -0.0010070800781250, +-0.0024108886718750, -0.0018310546875000, -0.0023193359375000, -0.0010070800781250, +-0.0023193359375000, -0.0019226074218750, -0.0023193359375000, -0.0012817382812500, +-0.0022583007812500, -0.0014343261718750, -0.0022583007812500, -0.0020141601562500, +-0.0023193359375000, -0.0006103515625000, -0.0022888183593750, -0.0021972656250000, +-0.0022277832031250, -0.0012207031250000, -0.0023193359375000, -0.0012512207031250, +-0.0021972656250000, -0.0023193359375000, -0.0020141601562500, -0.0009765625000000, +-0.0022277832031250, -0.0023498535156250, -0.0018615722656250, -0.0021362304687500, +-0.0019226074218750, -0.0019531250000000, -0.0018005371093750, -0.0028076171875000, +-0.0015869140625000, -0.0024719238281250, -0.0017395019531250, -0.0023498535156250, +-0.0015563964843750, -0.0029602050781250, -0.0015563964843750, -0.0027160644531250, +-0.0015563964843750, -0.0025024414062500, -0.0015258789062500, -0.0031433105468750, +-0.0016479492187500, -0.0020141601562500, -0.0015563964843750, -0.0024719238281250, +-0.0017089843750000, -0.0021667480468750, -0.0017395019531250, -0.0014038085937500, +-0.0016479492187500, -0.0024108886718750, -0.0017395019531250, -0.0013427734375000, +-0.0014953613281250, -0.0021057128906250, -0.0016174316406250, -0.0021667480468750, +-0.0015869140625000, -0.0015869140625000, -0.0012512207031250, -0.0027770996093750, +-0.0013732910156250, -0.0019531250000000, -0.0014343261718750, -0.0023498535156250, +-0.0011901855468750, -0.0028076171875000, -0.0013732910156250, -0.0024414062500000, +-0.0014648437500000, -0.0028991699218750, -0.0010681152343750, -0.0029296875000000, +-0.0019531250000000, -0.0029907226562500, -0.0014953613281250, -0.0031127929687500, +-0.0017089843750000, -0.0032653808593750, -0.0024719238281250, -0.0032653808593750, +-0.0018310546875000, -0.0027465820312500, -0.0023498535156250, -0.0031738281250000, +-0.0021667480468750, -0.0026550292968750, -0.0020446777343750, -0.0018310546875000, +-0.0022277832031250, -0.0024719238281250, -0.0017395019531250, -0.0013427734375000, +-0.0018920898437500, -0.0009460449218750, -0.0017395019531250, -0.0012512207031250, +-0.0016479492187500, -0.0007934570312500, -0.0016784667968750, -0.0002746582031250, +-0.0014038085937500, -0.0014343261718750, -0.0016174316406250, -0.0005798339843750, +-0.0017089843750000, -0.0007019042968750, -0.0015563964843750, -0.0018920898437500, +-0.0013427734375000, -0.0010986328125000, -0.0013732910156250, -0.0014343261718750, +-0.0017395019531250, -0.0025939941406250, -0.0012817382812500, -0.0020141601562500, +-0.0012512207031250, -0.0017089843750000, -0.0018310546875000, -0.0035095214843750, +-0.0016479492187500, -0.0016784667968750, -0.0014648437500000, -0.0024414062500000, +-0.0018920898437500, -0.0028991699218750, -0.0017089843750000, -0.0017395019531250, +-0.0016174316406250, -0.0023498535156250, -0.0025329589843750, -0.0022888183593750, +-0.0013732910156250, -0.0020141601562500, -0.0027160644531250, -0.0023193359375000, +-0.0024108886718750, -0.0023193359375000, -0.0012512207031250, -0.0015563964843750, +-0.0031738281250000, -0.0018615722656250, -0.0014038085937500, -0.0015563964843750, +-0.0017395019531250, -0.0014648437500000, -0.0020141601562500, -0.0012207031250000, +-0.0012207031250000, -0.0005187988281250, -0.0018005371093750, -0.0022277832031250, +-0.0014343261718750, -0.0005493164062500, -0.0016479492187500, -0.0012207031250000, +-0.0013732910156250, -0.0030212402343750, -0.0010070800781250, -0.0004577636718750, +-0.0014648437500000, -0.0027160644531250, -0.0003356933593750, -0.0022888183593750, +-0.0003356933593750, -0.0011901855468750, -0.0004272460937500, -0.0018310546875000, +-0.0003051757812500, -0.0011596679687500, -0.0010986328125000, 0.0003356933593750, +-0.0012817382812500, -0.0001525878906250, -0.0011291503906250, -0.0002136230468750, +-0.0017700195312500, 0.0005187988281250, -0.0023193359375000, -0.0000305175781250, +-0.0021362304687500, 0.0002746582031250, -0.0036315917968750, 0.0003356933593750, +-0.0032653808593750, 0.0003662109375000, -0.0035400390625000, 0.0004272460937500, +-0.0045166015625000, 0.0001220703125000, -0.0038757324218750, 0.0005187988281250, +-0.0046997070312500, 0.0000000000000000, -0.0047607421875000, 0.0001831054687500, +-0.0046691894531250, 0.0005187988281250, -0.0050659179687500, -0.0002441406250000, +-0.0048522949218750, 0.0010070800781250, -0.0046691894531250, 0.0001525878906250, +-0.0046386718750000, 0.0000305175781250, -0.0043334960937500, 0.0007934570312500, +-0.0041198730468750, -0.0004577636718750, -0.0043334960937500, 0.0001220703125000, +-0.0036926269531250, -0.0004882812500000, -0.0040588378906250, -0.0006408691406250, +-0.0035705566406250, -0.0001831054687500, -0.0029296875000000, -0.0008544921875000, +-0.0036010742187500, -0.0002441406250000, -0.0020141601562500, 0.0000610351562500, +-0.0024719238281250, -0.0005493164062500, -0.0023803710937500, -0.0004272460937500, +-0.0011291503906250, 0.0004577636718750, -0.0016784667968750, -0.0011596679687500, +-0.0016174316406250, -0.0004272460937500, -0.0012817382812500, -0.0003356933593750, +-0.0014038085937500, -0.0013427734375000, -0.0016784667968750, -0.0003051757812500, +-0.0015869140625000, -0.0010070800781250, -0.0011596679687500, -0.0007324218750000, +-0.0016174316406250, -0.0008850097656250, -0.0010986328125000, -0.0014343261718750, +-0.0006408691406250, -0.0010681152343750, -0.0015258789062500, -0.0023498535156250, +-0.0000610351562500, -0.0020446777343750, -0.0007934570312500, -0.0023498535156250, +-0.0007934570312500, -0.0034484863281250, 0.0000000000000000, -0.0028381347656250, +-0.0012817382812500, -0.0035705566406250, -0.0005798339843750, -0.0038452148437500, +-0.0011291503906250, -0.0033569335937500, -0.0014953613281250, -0.0034790039062500, +-0.0013122558593750, -0.0039062500000000, -0.0020141601562500, -0.0026550292968750, +-0.0017395019531250, -0.0031433105468750, -0.0020446777343750, -0.0027770996093750, +-0.0019531250000000, -0.0018310546875000, -0.0014953613281250, -0.0027465820312500, +-0.0018005371093750, -0.0015258789062500, -0.0010070800781250, -0.0018615722656250, +-0.0011596679687500, -0.0018920898437500, -0.0011291503906250, -0.0011901855468750, +-0.0006713867187500, -0.0018615722656250, -0.0010375976562500, -0.0013427734375000, +-0.0006408691406250, -0.0014038085937500, -0.0007934570312500, -0.0016174316406250, +-0.0010070800781250, -0.0014343261718750, -0.0009155273437500, -0.0015258789062500, +-0.0011596679687500, -0.0018615722656250, -0.0014038085937500, -0.0016479492187500, +-0.0013122558593750, -0.0018310546875000, -0.0015869140625000, -0.0019836425781250, +-0.0018005371093750, -0.0015563964843750, -0.0016174316406250, -0.0021362304687500, +-0.0016174316406250, -0.0017089843750000, -0.0016784667968750, -0.0018615722656250, +-0.0013732910156250, -0.0023803710937500, -0.0011901855468750, -0.0017395019531250, +-0.0012512207031250, -0.0023498535156250, -0.0004882812500000, -0.0020141601562500, +-0.0004882812500000, -0.0020141601562500, -0.0003967285156250, -0.0025329589843750, +0.0000915527343750}, +{-0.0009765625000000, -0.0038757324218750, -0.0013122558593750, -0.0025024414062500, +-0.0014953613281250, -0.0001220703125000, -0.0023803710937500, -0.0013427734375000, +-0.0020751953125000, -0.0010070800781250, -0.0025024414062500, 0.0007019042968750, +-0.0033874511718750, -0.0006103515625000, -0.0028381347656250, 0.0005798339843750, +-0.0038757324218750, 0.0003051757812500, -0.0040893554687500, 0.0001525878906250, +-0.0039978027343750, 0.0005798339843750, -0.0044555664062500, 0.0000000000000000, +-0.0045776367187500, 0.0007934570312500, -0.0045471191406250, 0.0002746582031250, +-0.0047912597656250, 0.0002441406250000, -0.0049133300781250, 0.0009460449218750, +-0.0048217773437500, 0.0001831054687500, -0.0047607421875000, 0.0003051757812500, +-0.0046081542968750, 0.0003662109375000, -0.0047607421875000, 0.0003356933593750, +-0.0042419433593750, 0.0001220703125000, -0.0039367675781250, -0.0002136230468750, +-0.0043334960937500, 0.0004577636718750, -0.0027770996093750, 0.0000305175781250, +-0.0034790039062500, 0.0000610351562500, -0.0030517578125000, 0.0005798339843750, +-0.0018615722656250, -0.0000305175781250, -0.0033874511718750, 0.0001831054687500, +-0.0021057128906250, 0.0000915527343750, -0.0022888183593750, -0.0001525878906250, +-0.0026855468750000, 0.0000915527343750, -0.0021057128906250, 0.0000915527343750, +-0.0022583007812500, -0.0006408691406250, -0.0020141601562500, 0.0001525878906250, +-0.0017700195312500, -0.0002746582031250, -0.0013427734375000, -0.0010986328125000, +-0.0009155273437500, 0.0001220703125000, -0.0007019042968750, -0.0013732910156250, +-0.0001220703125000, -0.0009155273437500, -0.0000305175781250, -0.0008239746093750, +0.0000610351562500, -0.0016784667968750, 0.0002441406250000, -0.0009765625000000, +0.0000000000000000, -0.0019531250000000, 0.0001220703125000, -0.0015563964843750, +-0.0003662109375000, -0.0018615722656250, -0.0003051757812500, -0.0026245117187500, +-0.0002746582031250, -0.0019836425781250, -0.0010375976562500, -0.0032348632812500, +-0.0001525878906250, -0.0031738281250000, -0.0006103515625000, -0.0031738281250000, +-0.0006713867187500, -0.0039672851562500, 0.0000610351562500, -0.0037231445312500, +-0.0003967285156250, -0.0034790039062500, -0.0003967285156250, -0.0039367675781250, +-0.0000610351562500, -0.0034484863281250, -0.0002746582031250, -0.0028686523437500, +-0.0006713867187500, -0.0035095214843750, -0.0003967285156250, -0.0022277832031250, +-0.0008544921875000, -0.0024108886718750, -0.0011291503906250, -0.0023498535156250, +-0.0011901855468750, -0.0016174316406250, -0.0013732910156250, -0.0020446777343750, +-0.0015563964843750, -0.0015869140625000, -0.0012512207031250, -0.0017089843750000, +-0.0014648437500000, -0.0017700195312500, -0.0012207031250000, -0.0014343261718750, +-0.0008544921875000, -0.0017089843750000, -0.0011291503906250, -0.0016784667968750, +-0.0002441406250000, -0.0016174316406250, -0.0003662109375000, -0.0017089843750000, +-0.0000915527343750, -0.0017089843750000, 0.0006103515625000, -0.0015563964843750, +0.0004272460937500, -0.0017700195312500, 0.0010986328125000, -0.0014953613281250, +0.0011901855468750, -0.0017395019531250, 0.0013732910156250, -0.0018615722656250, +0.0017700195312500, -0.0013427734375000, 0.0016174316406250, -0.0021972656250000, +0.0020141601562500, -0.0015869140625000, 0.0021667480468750, -0.0016784667968750, +0.0019531250000000, -0.0024108886718750, 0.0019531250000000, -0.0015869140625000, +0.0020141601562500, -0.0022583007812500, 0.0014648437500000, -0.0020446777343750, +0.0016479492187500, -0.0021362304687500, 0.0013732910156250, -0.0025024414062500, +0.0009155273437500, -0.0020141601562500, 0.0012817382812500, -0.0026855468750000, +0.0005798339843750, -0.0024108886718750, 0.0006713867187500, -0.0023803710937500, +0.0007019042968750, -0.0027465820312500, 0.0003356933593750, -0.0022888183593750, +0.0004882812500000, -0.0026245117187500, 0.0005493164062500, -0.0025329589843750, +0.0003662109375000, -0.0023803710937500, 0.0005187988281250, -0.0025634765625000, +0.0007629394531250, -0.0025024414062500, 0.0004577636718750, -0.0024414062500000, +0.0008239746093750, -0.0025024414062500, 0.0005187988281250, -0.0024414062500000, +0.0006103515625000, -0.0023193359375000, 0.0009155273437500, -0.0023498535156250, +0.0004882812500000, -0.0023803710937500, 0.0012512207031250, -0.0022888183593750, +0.0008850097656250, -0.0023803710937500, 0.0009765625000000, -0.0024414062500000, +0.0014648437500000, -0.0022888183593750, 0.0008544921875000, -0.0025939941406250, +0.0013732910156250, -0.0024414062500000, 0.0011901855468750, -0.0025024414062500, +0.0010375976562500, -0.0026245117187500, 0.0013122558593750, -0.0023193359375000, +0.0010375976562500, -0.0026245117187500, 0.0008850097656250, -0.0024414062500000, +0.0010375976562500, -0.0024108886718750, 0.0004577636718750, -0.0026245117187500, +0.0000000000000000, -0.0025024414062500, 0.0004272460937500, -0.0026245117187500, +-0.0007629394531250, -0.0026855468750000, -0.0004577636718750, -0.0025024414062500, +-0.0005798339843750, -0.0024719238281250, -0.0013427734375000, -0.0025024414062500, +-0.0005798339843750, -0.0018920898437500, -0.0010070800781250, -0.0019836425781250, +-0.0008850097656250, -0.0017395019531250, -0.0004577636718750, -0.0012207031250000, +-0.0004272460937500, -0.0015563964843750, -0.0003662109375000, -0.0012207031250000, +0.0004577636718750, -0.0012207031250000, 0.0003356933593750, -0.0015258789062500, +0.0007629394531250, -0.0015563964843750, 0.0014648437500000, -0.0016174316406250, +0.0010070800781250, -0.0017089843750000, 0.0014343261718750, -0.0021362304687500, +0.0015563964843750, -0.0017089843750000, 0.0011291503906250, -0.0013122558593750, +0.0009460449218750, -0.0018615722656250, 0.0010070800781250, -0.0008239746093750, +-0.0000610351562500, -0.0004272460937500, 0.0000610351562500, -0.0006408691406250, +-0.0003967285156250, -0.0003662109375000, -0.0011901855468750, 0.0000610351562500, +-0.0007019042968750, -0.0007019042968750, -0.0013732910156250, -0.0005798339843750, +-0.0011596679687500, -0.0005187988281250, -0.0008850097656250, -0.0009460449218750, +-0.0011596679687500, -0.0010375976562500, -0.0010375976562500, -0.0012207031250000, +-0.0008544921875000, -0.0011291503906250, -0.0006408691406250, -0.0013732910156250, +-0.0007019042968750, -0.0017395019531250, -0.0007934570312500, -0.0016479492187500, +-0.0005187988281250, -0.0018310546875000, -0.0008239746093750, -0.0024719238281250, +-0.0016174316406250, -0.0021667480468750, -0.0017395019531250, -0.0019836425781250, +-0.0015869140625000, -0.0027465820312500, -0.0019836425781250, -0.0013732910156250, +-0.0019531250000000, -0.0017395019531250, -0.0024108886718750, -0.0016479492187500, +-0.0019226074218750, -0.0007019042968750, -0.0016174316406250, -0.0011291503906250, +-0.0025939941406250, -0.0002136230468750, -0.0015563964843750, -0.0004882812500000, +-0.0021972656250000, -0.0002136230468750, -0.0023803710937500, 0.0005187988281250, +-0.0014038085937500, -0.0004272460937500, -0.0018615722656250, 0.0003356933593750, +-0.0020751953125000, 0.0006103515625000, -0.0016784667968750, -0.0001831054687500, +-0.0020141601562500, -0.0002441406250000, -0.0026550292968750, 0.0003967285156250, +-0.0022583007812500, -0.0010070800781250, -0.0025939941406250, -0.0007934570312500, +-0.0028076171875000, -0.0008239746093750, -0.0027770996093750, -0.0017089843750000, +-0.0025329589843750, -0.0014343261718750, -0.0025024414062500, -0.0016479492187500, +-0.0032348632812500, -0.0019531250000000, -0.0026855468750000, -0.0018920898437500, +-0.0028381347656250, -0.0017395019531250, -0.0040588378906250, -0.0041198730468750, +-0.0033874511718750, -0.0034484863281250, -0.0030212402343750, -0.0046691894531250, +-0.0025329589843750, -0.0035705566406250, -0.0031433105468750, -0.0023498535156250, +-0.0036010742187500, -0.0035095214843750, -0.0027465820312500, -0.0015563964843750, +-0.0027465820312500, -0.0012512207031250, -0.0031433105468750, -0.0019836425781250, +-0.0022583007812500, -0.0016174316406250, -0.0014343261718750, -0.0014648437500000, +-0.0019836425781250, -0.0027465820312500, -0.0010070800781250, -0.0028381347656250, +-0.0005493164062500, -0.0025329589843750, -0.0008544921875000, -0.0029602050781250, +-0.0008850097656250, -0.0029602050781250, -0.0005798339843750, -0.0016174316406250, +-0.0007934570312500, -0.0015563964843750, -0.0010375976562500, -0.0014343261718750, +-0.0006713867187500, -0.0003051757812500, -0.0003356933593750, -0.0000610351562500, +-0.0005798339843750, -0.0008544921875000, -0.0001525878906250, -0.0001525878906250, +-0.0001220703125000, 0.0000610351562500, -0.0003967285156250, -0.0007629394531250, +-0.0005493164062500, -0.0003051757812500, -0.0007324218750000, 0.0005187988281250, +-0.0007019042968750, 0.0001525878906250, -0.0011291503906250, 0.0005493164062500, +-0.0009765625000000, 0.0015563964843750, -0.0005798339843750, 0.0013427734375000, +-0.0009765625000000, 0.0014343261718750, -0.0004272460937500, 0.0024414062500000, +-0.0002746582031250, 0.0015258789062500, -0.0002441406250000, 0.0008544921875000, +0.0000305175781250, 0.0023498535156250, 0.0000305175781250, -0.0004272460937500, +0.0003662109375000, 0.0000305175781250, 0.0002441406250000, 0.0003967285156250, +0.0005187988281250, -0.0011901855468750, 0.0007934570312500, -0.0005798339843750, +0.0003662109375000, -0.0000305175781250, 0.0009765625000000, -0.0008544921875000, +0.0012207031250000, 0.0000915527343750, 0.0009155273437500, 0.0011901855468750, +0.0010681152343750, -0.0002136230468750, 0.0014343261718750, 0.0021667480468750, +0.0008239746093750, 0.0017395019531250, 0.0009155273437500, 0.0014343261718750, +0.0008544921875000, 0.0025634765625000, 0.0004272460937500, 0.0018310546875000, +0.0007324218750000, 0.0016174316406250, 0.0002441406250000, 0.0016479492187500, +0.0003662109375000, 0.0013427734375000, 0.0003356933593750, 0.0008544921875000, +-0.0000305175781250, 0.0008544921875000, 0.0001525878906250, 0.0007934570312500, +-0.0000305175781250, 0.0002746582031250, -0.0000305175781250, 0.0004577636718750, +-0.0001525878906250, 0.0004577636718750, -0.0001831054687500, -0.0003051757812500, +-0.0000915527343750, 0.0009765625000000, -0.0007324218750000, -0.0000305175781250, +-0.0004577636718750, 0.0003967285156250, -0.0006713867187500, 0.0015869140625000, +-0.0012207031250000, 0.0000000000000000, -0.0007324218750000, 0.0018310546875000, +-0.0011901855468750, 0.0013122558593750, -0.0010986328125000, 0.0011901855468750, +-0.0010375976562500, 0.0021362304687500, -0.0011901855468750, 0.0011901855468750, +-0.0008239746093750, 0.0018920898437500, -0.0011901855468750, 0.0016174316406250, +-0.0009460449218750, 0.0011291503906250, -0.0009765625000000, 0.0013732910156250, +-0.0011596679687500, 0.0012817382812500, -0.0009460449218750, 0.0005187988281250, +-0.0012817382812500, 0.0008544921875000, -0.0011596679687500, 0.0005493164062500, +-0.0013122558593750, -0.0000305175781250, -0.0017089843750000, 0.0007019042968750, +-0.0014343261718750, -0.0001220703125000, -0.0017395019531250, 0.0003051757812500, +-0.0018615722656250, 0.0002441406250000, -0.0017395019531250, -0.0000915527343750, +-0.0017395019531250, 0.0008544921875000, -0.0018310546875000, -0.0003662109375000, +-0.0016174316406250, 0.0004882812500000, -0.0015563964843750, 0.0007019042968750, +-0.0016784667968750, -0.0005187988281250, -0.0016479492187500, -0.0001220703125000, +-0.0015258789062500, -0.0003967285156250, -0.0018005371093750, -0.0003662109375000, +-0.0016479492187500, -0.0003051757812500, -0.0017089843750000, -0.0003662109375000, +-0.0018920898437500, -0.0002746582031250, -0.0016784667968750, -0.0005187988281250, +-0.0017089843750000}, +{-0.0019531250000000, -0.0007019042968750, -0.0014648437500000, -0.0001525878906250, +-0.0010070800781250, -0.0000610351562500, -0.0013732910156250, -0.0006103515625000, +-0.0018310546875000, 0.0001220703125000, -0.0016174316406250, 0.0009765625000000, +-0.0013427734375000, 0.0009155273437500, -0.0017395019531250, 0.0014038085937500, +-0.0012512207031250, 0.0025939941406250, -0.0005798339843750, 0.0026855468750000, +-0.0010986328125000, 0.0021362304687500, -0.0007019042968750, 0.0031127929687500, +-0.0007324218750000, 0.0021972656250000, -0.0010070800781250, 0.0009460449218750, +-0.0011596679687500, 0.0020751953125000, -0.0014038085937500, -0.0002746582031250, +-0.0010070800781250, -0.0000610351562500, -0.0013732910156250, 0.0002746582031250, +-0.0010681152343750, -0.0009155273437500, -0.0003051757812500, -0.0003051757812500, +-0.0007019042968750, 0.0006103515625000, -0.0001831054687500, 0.0003051757812500, +0.0002746582031250, 0.0007934570312500, 0.0001831054687500, 0.0016479492187500, +0.0001525878906250, 0.0011901855468750, 0.0003662109375000, 0.0016479492187500, +0.0004577636718750, 0.0016174316406250, 0.0002136230468750, 0.0011901855468750, +0.0003967285156250, 0.0011596679687500, 0.0009155273437500, 0.0010375976562500, +0.0008544921875000, 0.0003967285156250, 0.0009155273437500, 0.0002441406250000, +0.0013732910156250, 0.0002441406250000, 0.0010986328125000, -0.0001220703125000, +0.0006408691406250, -0.0002441406250000, 0.0010070800781250, 0.0005493164062500, +0.0002746582031250, 0.0001220703125000, 0.0003967285156250, 0.0005798339843750, +0.0003356933593750, 0.0014038085937500, 0.0000915527343750, 0.0007324218750000, +0.0004882812500000, 0.0018920898437500, -0.0000915527343750, 0.0015869140625000, +0.0001525878906250, 0.0016784667968750, -0.0000305175781250, 0.0024414062500000, +-0.0004882812500000, 0.0016174316406250, -0.0000915527343750, 0.0020446777343750, +-0.0006713867187500, 0.0019531250000000, -0.0005493164062500, 0.0014648437500000, +-0.0005493164062500, 0.0013427734375000, -0.0007324218750000, 0.0012512207031250, +-0.0004577636718750, 0.0005798339843750, -0.0007324218750000, 0.0005798339843750, +-0.0005798339843750, 0.0003356933593750, -0.0005493164062500, -0.0001525878906250, +-0.0007324218750000, 0.0000915527343750, -0.0003967285156250, -0.0000915527343750, +-0.0006713867187500, -0.0001220703125000, -0.0004577636718750, 0.0000000000000000, +-0.0005493164062500, 0.0001525878906250, -0.0007934570312500, 0.0002136230468750, +-0.0003662109375000, 0.0003662109375000, -0.0008850097656250, 0.0005798339843750, +-0.0007934570312500, 0.0009460449218750, -0.0006713867187500, 0.0012817382812500, +-0.0008850097656250, 0.0014343261718750, -0.0007019042968750, 0.0021972656250000, +-0.0010070800781250, 0.0023498535156250, -0.0008850097656250, 0.0026855468750000, +-0.0009155273437500, 0.0033264160156250, -0.0011901855468750, 0.0036010742187500, +-0.0010070800781250, 0.0039672851562500, -0.0011901855468750, 0.0039367675781250, +-0.0010681152343750, 0.0042724609375000, -0.0010986328125000, 0.0043945312500000, +-0.0011901855468750, 0.0038146972656250, -0.0009765625000000, 0.0046386718750000, +-0.0012512207031250, 0.0044860839843750, -0.0011596679687500, 0.0043640136718750, +-0.0011596679687500, 0.0047607421875000, -0.0013732910156250, 0.0043945312500000, +-0.0011596679687500, 0.0045776367187500, -0.0013122558593750, 0.0044860839843750, +-0.0013122558593750, 0.0042419433593750, -0.0012512207031250, 0.0041503906250000, +-0.0013427734375000, 0.0040588378906250, -0.0012817382812500, 0.0035705566406250, +-0.0013122558593750, 0.0036926269531250, -0.0013732910156250, 0.0032653808593750, +-0.0014648437500000, 0.0028381347656250, -0.0014648437500000, 0.0032043457031250, +-0.0015869140625000, 0.0022277832031250, -0.0015563964843750, 0.0028991699218750, +-0.0018005371093750, 0.0024719238281250, -0.0017089843750000, 0.0017395019531250, +-0.0016479492187500, 0.0030212402343750, -0.0018615722656250, 0.0010070800781250, +-0.0018615722656250, 0.0018920898437500, -0.0017700195312500, 0.0018005371093750, +-0.0018615722656250, 0.0003356933593750, -0.0019836425781250, 0.0015258789062500, +-0.0020141601562500, 0.0002746582031250, -0.0023193359375000, 0.0000610351562500, +-0.0023193359375000, 0.0004272460937500, -0.0025024414062500, -0.0000915527343750, +-0.0027465820312500, -0.0003967285156250, -0.0026550292968750, 0.0004577636718750, +-0.0031127929687500, -0.0002441406250000, -0.0031127929687500, 0.0000915527343750, +-0.0033569335937500, 0.0009765625000000, -0.0039367675781250, 0.0001525878906250, +-0.0038146972656250, 0.0013122558593750, -0.0041503906250000, 0.0009460449218750, +-0.0044555664062500, 0.0010681152343750, -0.0042724609375000, 0.0014953613281250, +-0.0042724609375000, 0.0003356933593750, -0.0046691894531250, 0.0016174316406250, +-0.0039978027343750, 0.0009765625000000, -0.0045471191406250, 0.0007934570312500, +-0.0042419433593750, 0.0015869140625000, -0.0036621093750000, 0.0007324218750000, +-0.0046386718750000, 0.0010986328125000, -0.0035705566406250, 0.0010070800781250, +-0.0039672851562500, 0.0008239746093750, -0.0040283203125000, 0.0009460449218750, +-0.0034179687500000, 0.0008850097656250, -0.0039672851562500, 0.0008850097656250, +-0.0026245117187500, 0.0009460449218750, -0.0029296875000000, 0.0010986328125000, +-0.0026855468750000, 0.0011291503906250, -0.0016479492187500, 0.0012207031250000, +-0.0021667480468750, 0.0015869140625000, -0.0014953613281250, 0.0016479492187500, +-0.0015563964843750, 0.0014953613281250, -0.0015258789062500, 0.0017700195312500, +-0.0012207031250000, 0.0019531250000000, -0.0016174316406250, 0.0003967285156250, +-0.0012817382812500, 0.0012817382812500, -0.0014648437500000, 0.0008239746093750, +-0.0016479492187500, -0.0006103515625000, -0.0014953613281250, 0.0004577636718750, +-0.0016174316406250, -0.0008850097656250, -0.0017700195312500, -0.0012207031250000, +-0.0013427734375000, -0.0012817382812500, -0.0017395019531250, -0.0023193359375000, +-0.0019836425781250, -0.0028686523437500, -0.0010681152343750, -0.0028381347656250, +-0.0018615722656250, -0.0038757324218750, -0.0013732910156250, -0.0040893554687500, +-0.0011901855468750, -0.0038452148437500, -0.0014953613281250, -0.0045166015625000, +-0.0007019042968750, -0.0037841796875000, -0.0014953613281250, -0.0045776367187500, +-0.0009765625000000, -0.0039367675781250, -0.0010070800781250, -0.0030517578125000, +-0.0016784667968750, -0.0046081542968750, -0.0010070800781250, -0.0018005371093750, +-0.0015258789062500, -0.0028381347656250, -0.0013122558593750, -0.0025329589843750, +-0.0014648437500000, -0.0005493164062500, -0.0017700195312500, -0.0024719238281250, +-0.0014343261718750, -0.0009460449218750, -0.0022583007812500, -0.0010070800781250, +-0.0020446777343750, -0.0016784667968750, -0.0022888183593750, -0.0011901855468750, +-0.0030517578125000, -0.0013122558593750, -0.0025634765625000, -0.0018310546875000, +-0.0030212402343750, -0.0014343261718750, -0.0029907226562500, -0.0014038085937500, +-0.0026855468750000, -0.0015869140625000, -0.0026550292968750, -0.0011596679687500, +-0.0027770996093750, -0.0016174316406250, -0.0028686523437500, -0.0011291503906250, +-0.0032043457031250, -0.0010681152343750, -0.0032348632812500, -0.0013427734375000, +-0.0032958984375000, -0.0007324218750000, -0.0036010742187500, -0.0011901855468750, +-0.0028076171875000, -0.0009460449218750, -0.0033569335937500, -0.0009765625000000, +-0.0028991699218750, -0.0013122558593750, -0.0021972656250000, -0.0008239746093750, +-0.0030517578125000, -0.0008544921875000, -0.0015258789062500, -0.0008239746093750, +-0.0024108886718750, -0.0003662109375000, -0.0021972656250000, 0.0000305175781250, +-0.0012512207031250, -0.0000915527343750, -0.0028686523437500, 0.0001831054687500, +-0.0010070800781250, 0.0007324218750000, -0.0017700195312500, 0.0004882812500000, +-0.0016784667968750, 0.0002441406250000, -0.0003356933593750, 0.0006408691406250, +-0.0014343261718750, 0.0001831054687500, -0.0000915527343750, -0.0003356933593750, +-0.0005187988281250, 0.0000000000000000, -0.0003356933593750, -0.0000305175781250, +0.0003662109375000, -0.0009460449218750, -0.0008239746093750, 0.0000305175781250, +0.0010986328125000, -0.0004882812500000, -0.0004577636718750, -0.0008239746093750, +0.0000305175781250, -0.0002136230468750, 0.0018310546875000, -0.0007629394531250, +-0.0004882812500000, -0.0012207031250000, 0.0019836425781250, -0.0009765625000000, +0.0013122558593750, -0.0014953613281250, 0.0007934570312500, -0.0020141601562500, +0.0020141601562500, -0.0012512207031250, 0.0010070800781250, -0.0018310546875000, +0.0010986328125000, -0.0015563964843750, 0.0010986328125000, -0.0015258789062500, +0.0006408691406250, -0.0016784667968750, 0.0004577636718750, -0.0010070800781250, +0.0005187988281250, -0.0021972656250000, 0.0003967285156250, -0.0015563964843750, +0.0001220703125000, -0.0018310546875000, 0.0005493164062500, -0.0028686523437500, +0.0008239746093750, -0.0018005371093750, 0.0004272460937500, -0.0031433105468750, +0.0013427734375000, -0.0027770996093750, 0.0013732910156250, -0.0028076171875000, +0.0012817382812500, -0.0035400390625000, 0.0017700195312500, -0.0027465820312500, +0.0016479492187500, -0.0034179687500000, 0.0014038085937500, -0.0032958984375000, +0.0016479492187500, -0.0028991699218750, 0.0012512207031250, -0.0030212402343750, +0.0008850097656250, -0.0028076171875000, 0.0014343261718750, -0.0021667480468750, +0.0006408691406250, -0.0021362304687500, 0.0010681152343750, -0.0018005371093750, +0.0011901855468750, -0.0011901855468750, 0.0009155273437500, -0.0011901855468750, +0.0017395019531250, -0.0009765625000000, 0.0016174316406250, -0.0007629394531250, +0.0020751953125000, -0.0007324218750000, 0.0024108886718750, -0.0007324218750000, +0.0024719238281250, -0.0006103515625000, 0.0031127929687500, -0.0004882812500000, +0.0029907226562500, -0.0003967285156250, 0.0033264160156250, -0.0004272460937500, +0.0033874511718750, -0.0003662109375000, 0.0032653808593750, -0.0003662109375000, +0.0036621093750000, -0.0006713867187500, 0.0033569335937500, -0.0006408691406250, +0.0036010742187500, -0.0007324218750000, 0.0035095214843750, -0.0008850097656250, +0.0032653808593750, -0.0007019042968750, 0.0037536621093750, -0.0010681152343750, +0.0035095214843750, -0.0008239746093750, 0.0037231445312500, -0.0010070800781250, +0.0039978027343750, -0.0013427734375000, 0.0040283203125000, -0.0008850097656250, +0.0043029785156250, -0.0015563964843750, 0.0044250488281250, -0.0014343261718750, +0.0044555664062500, -0.0014648437500000, 0.0045776367187500, -0.0018310546875000, +0.0046691894531250, -0.0015563964843750, 0.0046081542968750, -0.0021362304687500, +0.0049133300781250, -0.0018615722656250, 0.0046997070312500, -0.0019226074218750, +0.0048217773437500, -0.0024108886718750, 0.0050354003906250, -0.0018920898437500, +0.0047302246093750, -0.0023803710937500, 0.0052490234375000, -0.0022888183593750, +0.0049438476562500, -0.0022583007812500, 0.0051269531250000, -0.0024719238281250, +0.0054931640625000, -0.0022583007812500, 0.0048217773437500, -0.0024108886718750, +0.0055847167968750, -0.0024108886718750, 0.0052490234375000, -0.0022583007812500, +0.0050354003906250, -0.0022888183593750, 0.0054626464843750, -0.0023193359375000, +0.0051269531250000, -0.0020141601562500, 0.0050354003906250, -0.0021362304687500, +0.0052490234375000, -0.0020751953125000, 0.0049438476562500, -0.0018920898437500, +0.0047302246093750, -0.0019531250000000, 0.0049438476562500, -0.0018615722656250, +0.0040283203125000, -0.0018310546875000, 0.0041809082031250, -0.0017089843750000, +0.0038757324218750}, +{0.0019836425781250, -0.0007324218750000, 0.0016479492187500, -0.0002746582031250, +0.0028381347656250, -0.0011596679687500, 0.0012817382812500, -0.0001831054687500, +0.0019836425781250, -0.0004577636718750, 0.0014648437500000, -0.0008544921875000, +0.0010681152343750, -0.0005493164062500, 0.0013732910156250, -0.0009460449218750, +0.0007019042968750, -0.0012817382812500, 0.0014343261718750, -0.0013427734375000, +0.0010986328125000, -0.0012817382812500, 0.0012817382812500, -0.0012817382812500, +0.0021362304687500, -0.0012817382812500, 0.0016479492187500, -0.0011596679687500, +0.0021057128906250, -0.0008544921875000, 0.0023498535156250, -0.0010986328125000, +0.0021972656250000, -0.0012207031250000, 0.0023193359375000, -0.0008239746093750, +0.0024719238281250, -0.0019836425781250, 0.0021667480468750, -0.0015563964843750, +0.0022277832031250, -0.0017700195312500, 0.0023193359375000, -0.0027465820312500, +0.0021972656250000, -0.0020141601562500, 0.0022888183593750, -0.0028076171875000, +0.0025024414062500, -0.0027465820312500, 0.0026855468750000, -0.0025024414062500, +0.0027160644531250, -0.0026855468750000, 0.0030212402343750, -0.0024108886718750, +0.0032653808593750, -0.0023803710937500, 0.0029907226562500, -0.0022583007812500, +0.0035400390625000, -0.0020141601562500, 0.0034484863281250, -0.0019531250000000, +0.0031738281250000, -0.0019531250000000, 0.0039978027343750, -0.0013732910156250, +0.0028381347656250, -0.0014648437500000, 0.0036315917968750, -0.0012512207031250, +0.0032958984375000, -0.0007934570312500, 0.0022888183593750, -0.0011291503906250, +0.0035095214843750, -0.0007019042968750, 0.0019531250000000, -0.0007019042968750, +0.0023803710937500, -0.0006713867187500, 0.0021972656250000, -0.0003967285156250, +0.0010681152343750, -0.0004882812500000, 0.0018615722656250, -0.0004577636718750, +0.0009460449218750, -0.0004882812500000, 0.0009765625000000, -0.0005493164062500, +0.0012817382812500, -0.0005187988281250, 0.0009765625000000, -0.0006103515625000, +0.0011291503906250, -0.0004272460937500, 0.0017700195312500, -0.0006408691406250, +0.0015258789062500, -0.0006103515625000, 0.0018310546875000, -0.0004577636718750, +0.0023803710937500, -0.0007324218750000, 0.0020141601562500, -0.0007019042968750, +0.0027465820312500, -0.0006408691406250, 0.0026550292968750, -0.0008544921875000, +0.0028076171875000, -0.0010070800781250, 0.0032348632812500, -0.0009155273437500, +0.0029296875000000, -0.0013122558593750, 0.0033874511718750, -0.0012817382812500, +0.0032043457031250, -0.0012512207031250, 0.0031738281250000, -0.0016174316406250, +0.0034484863281250, -0.0017089843750000, 0.0030517578125000, -0.0015869140625000, +0.0033569335937500, -0.0017700195312500, 0.0032043457031250, -0.0018005371093750, +0.0030822753906250, -0.0017089843750000, 0.0032653808593750, -0.0016784667968750, +0.0030212402343750, -0.0017700195312500, 0.0032958984375000, -0.0017395019531250, +0.0030212402343750, -0.0016174316406250, 0.0031127929687500, -0.0015869140625000, +0.0032958984375000, -0.0016174316406250, 0.0030212402343750, -0.0013732910156250, +0.0034484863281250, -0.0014343261718750, 0.0032958984375000, -0.0013427734375000, +0.0035705566406250, -0.0010986328125000, 0.0040283203125000, -0.0011291503906250, +0.0037536621093750, -0.0005798339843750, 0.0047607421875000, -0.0007019042968750, +0.0044555664062500, -0.0005187988281250, 0.0046691894531250, -0.0000915527343750, +0.0053405761718750, -0.0004882812500000, 0.0046997070312500, -0.0003967285156250, +0.0055847167968750, -0.0003967285156250, 0.0053100585937500, -0.0007324218750000, +0.0051574707031250, -0.0008239746093750, 0.0055541992187500, -0.0006713867187500, +0.0050354003906250, -0.0010986328125000, 0.0047607421875000, -0.0010375976562500, +0.0046997070312500, -0.0009765625000000, 0.0041198730468750, -0.0012207031250000, +0.0036010742187500, -0.0012512207031250, 0.0036010742187500, -0.0009460449218750, +0.0027465820312500, -0.0011901855468750, 0.0026855468750000, -0.0010070800781250, +0.0025939941406250, -0.0006103515625000, 0.0021362304687500, -0.0008850097656250, +0.0023193359375000, -0.0005187988281250, 0.0024108886718750, -0.0006103515625000, +0.0023498535156250, -0.0007019042968750, 0.0025939941406250, -0.0006713867187500, +0.0028381347656250, -0.0009460449218750, 0.0028381347656250, -0.0008544921875000, +0.0032043457031250, -0.0008850097656250, 0.0032348632812500, -0.0010986328125000, +0.0030822753906250, -0.0011596679687500, 0.0031433105468750, -0.0010681152343750, +0.0032043457031250, -0.0013732910156250, 0.0025939941406250, -0.0015869140625000, +0.0026855468750000, -0.0016174316406250, 0.0023498535156250, -0.0017700195312500, +0.0016784667968750, -0.0020446777343750, 0.0017395019531250, -0.0020446777343750, +0.0015563964843750, -0.0019836425781250, 0.0013122558593750, -0.0021057128906250, +0.0014038085937500, -0.0020751953125000, 0.0015563964843750, -0.0017395019531250, +0.0014038085937500, -0.0019226074218750, 0.0016479492187500, -0.0018310546875000, +0.0019531250000000, -0.0014343261718750, 0.0019531250000000, -0.0014648437500000, +0.0017089843750000, -0.0018920898437500, 0.0016174316406250, -0.0014953613281250, +0.0016174316406250, -0.0016479492187500, 0.0012817382812500, -0.0021972656250000, +0.0013122558593750, -0.0022888183593750, 0.0012512207031250, -0.0021057128906250, +0.0007019042968750, -0.0028686523437500, 0.0010681152343750, -0.0025634765625000, +0.0009460449218750, -0.0025634765625000, 0.0010986328125000, -0.0031127929687500, +0.0012512207031250, -0.0027770996093750, 0.0006408691406250, -0.0031127929687500, +0.0011596679687500, -0.0031127929687500, 0.0010681152343750, -0.0033569335937500, +-0.0000915527343750, -0.0036621093750000, -0.0005187988281250, -0.0034179687500000, +-0.0003051757812500, -0.0036315917968750, -0.0031738281250000, -0.0039062500000000, +-0.0028686523437500, -0.0037536621093750, -0.0034179687500000, -0.0036926269531250, +-0.0052795410156250, -0.0040893554687500, -0.0043029785156250, -0.0038146972656250, +-0.0051879882812500, -0.0039062500000000, -0.0049438476562500, -0.0042724609375000, +-0.0047912597656250, -0.0043334960937500, -0.0055541992187500, -0.0032348632812500, +-0.0038452148437500, -0.0038452148437500, -0.0058898925781250, -0.0025024414062500, +-0.0045166015625000, -0.0028381347656250, -0.0050659179687500, -0.0032958984375000, +-0.0059204101562500, -0.0021057128906250, -0.0043640136718750, -0.0033569335937500, +-0.0059509277343750, -0.0029296875000000, -0.0055236816406250, -0.0022583007812500, +-0.0049133300781250, -0.0024719238281250, -0.0054931640625000, -0.0016479492187500, +-0.0050048828125000, -0.0006713867187500, -0.0040283203125000, 0.0002136230468750, +-0.0040893554687500, 0.0006713867187500, -0.0036315917968750, 0.0014648437500000, +-0.0027770996093750, 0.0024414062500000, -0.0029296875000000, 0.0010986328125000, +-0.0028686523437500, 0.0022277832031250, -0.0027770996093750, 0.0018005371093750, +-0.0027465820312500, 0.0001220703125000, -0.0028076171875000, 0.0015258789062500, +-0.0027465820312500, 0.0006103515625000, -0.0023193359375000, -0.0000305175781250, +-0.0021362304687500, 0.0009765625000000, -0.0021667480468750, 0.0014648437500000, +-0.0019531250000000, 0.0010070800781250, -0.0015869140625000, 0.0021667480468750, +-0.0022583007812500, 0.0024108886718750, -0.0018310546875000, 0.0022277832031250, +-0.0017089843750000, 0.0027770996093750, -0.0022277832031250, 0.0029907226562500, +-0.0018005371093750, 0.0025329589843750, -0.0014343261718750, 0.0027770996093750, +-0.0015869140625000, 0.0030212402343750, -0.0013122558593750, 0.0024108886718750, +-0.0008544921875000, 0.0023803710937500, -0.0012817382812500, 0.0033264160156250, +-0.0009460449218750, 0.0027160644531250, -0.0010070800781250, 0.0028991699218750, +-0.0009765625000000, 0.0039062500000000, -0.0008239746093750, 0.0032958984375000, +-0.0009460449218750, 0.0035705566406250, -0.0002441406250000, 0.0039062500000000, +-0.0001220703125000, 0.0033569335937500, 0.0000305175781250, 0.0032348632812500, +0.0007324218750000, 0.0036926269531250, 0.0008544921875000, 0.0019226074218750, +0.0005798339843750, 0.0024108886718750, 0.0009460449218750, 0.0020751953125000, +0.0007324218750000, 0.0006103515625000, 0.0004577636718750, 0.0011291503906250, +0.0010681152343750, 0.0010681152343750, 0.0006713867187500, 0.0003356933593750, +0.0010986328125000, 0.0008239746093750, 0.0010375976562500, 0.0013122558593750, +0.0007019042968750, 0.0005187988281250, 0.0013122558593750, 0.0020141601562500, +0.0000305175781250, 0.0016784667968750, 0.0004272460937500, 0.0018920898437500, +0.0002746582031250, 0.0028381347656250, -0.0006408691406250, 0.0022277832031250, +0.0000915527343750, 0.0031738281250000, -0.0003662109375000, 0.0032958984375000, +-0.0001525878906250, 0.0030212402343750, -0.0000610351562500, 0.0033874511718750, +-0.0002136230468750, 0.0034179687500000, 0.0000610351562500, 0.0025939941406250, +-0.0002746582031250, 0.0029602050781250, -0.0001220703125000, 0.0026550292968750, +-0.0000915527343750, 0.0020141601562500, -0.0002746582031250, 0.0026245117187500, +-0.0000915527343750, 0.0017395019531250, -0.0001220703125000, 0.0019531250000000, +-0.0000610351562500, 0.0020446777343750, 0.0000000000000000, 0.0015258789062500, +-0.0000305175781250, 0.0019531250000000, 0.0001220703125000, 0.0020141601562500, +0.0000610351562500, 0.0020141601562500, 0.0000915527343750, 0.0023803710937500, +0.0000915527343750, 0.0026245117187500, 0.0001525878906250, 0.0025329589843750, +0.0002136230468750, 0.0032958984375000, 0.0000610351562500, 0.0031433105468750, +0.0002441406250000, 0.0034484863281250, 0.0001525878906250, 0.0039672851562500, +0.0000305175781250, 0.0034790039062500, 0.0003662109375000, 0.0045471191406250, +0.0000000000000000, 0.0039367675781250, 0.0001220703125000, 0.0040588378906250, +0.0000915527343750, 0.0048522949218750, -0.0002136230468750, 0.0040588378906250, +-0.0001831054687500, 0.0049743652343750, -0.0003662109375000, 0.0045471191406250, +-0.0004577636718750, 0.0046081542968750, -0.0004882812500000, 0.0050964355468750, +-0.0006408691406250, 0.0041809082031250, -0.0006408691406250, 0.0050659179687500, +-0.0007019042968750, 0.0046081542968750, -0.0007324218750000, 0.0044860839843750, +-0.0008239746093750, 0.0049743652343750, -0.0009460449218750, 0.0042114257812500, +-0.0007934570312500, 0.0046691894531250, -0.0009765625000000, 0.0043334960937500, +-0.0008850097656250, 0.0039978027343750, -0.0008544921875000, 0.0041809082031250, +-0.0009765625000000, 0.0036926269531250, -0.0007629394531250, 0.0035095214843750, +-0.0009155273437500, 0.0034179687500000, -0.0009155273437500, 0.0030517578125000, +-0.0009155273437500, 0.0028991699218750, -0.0010375976562500, 0.0028686523437500, +-0.0011291503906250, 0.0020446777343750, -0.0012512207031250, 0.0025024414062500, +-0.0014343261718750, 0.0022583007812500, -0.0015563964843750, 0.0017395019531250, +-0.0017395019531250, 0.0028381347656250, -0.0018920898437500, 0.0016784667968750, +-0.0020751953125000, 0.0023498535156250, -0.0022277832031250, 0.0025024414062500, +-0.0024719238281250, 0.0018005371093750, -0.0027465820312500, 0.0026550292968750, +-0.0030212402343750, 0.0022888183593750, -0.0030212402343750, 0.0021667480468750, +-0.0032653808593750, 0.0026245117187500, -0.0033569335937500, 0.0025329589843750, +-0.0033264160156250, 0.0021972656250000, -0.0036621093750000, 0.0034484863281250, +-0.0032043457031250, 0.0027770996093750, -0.0037536621093750, 0.0030517578125000, +-0.0036315917968750, 0.0039672851562500, -0.0032348632812500, 0.0028686523437500, +-0.0039672851562500}, +{0.0008239746093750, 0.0024108886718750, 0.0010070800781250, 0.0033264160156250, +0.0002746582031250, 0.0032348632812500, 0.0007324218750000, 0.0028686523437500, +0.0007629394531250, 0.0031127929687500, 0.0002441406250000, 0.0026855468750000, +0.0008239746093750, 0.0025939941406250, 0.0006408691406250, 0.0024719238281250, +0.0008239746093750, 0.0022583007812500, 0.0006713867187500, 0.0020751953125000, +0.0004577636718750, 0.0019531250000000, 0.0008544921875000, 0.0017089843750000, +-0.0000915527343750, 0.0015563964843750, 0.0001831054687500, 0.0016174316406250, +0.0001831054687500, 0.0016479492187500, -0.0003356933593750, 0.0013732910156250, +0.0000915527343750, 0.0021057128906250, -0.0000915527343750, 0.0018005371093750, +0.0000000000000000, 0.0021972656250000, 0.0000610351562500, 0.0029907226562500, +-0.0001220703125000, 0.0025024414062500, 0.0001525878906250, 0.0037536621093750, +-0.0000610351562500, 0.0036315917968750, -0.0000915527343750, 0.0039367675781250, +0.0000610351562500, 0.0048217773437500, 0.0000305175781250, 0.0043334960937500, +-0.0000305175781250, 0.0052795410156250, 0.0001220703125000, 0.0051879882812500, +0.0000915527343750, 0.0050964355468750, 0.0000915527343750, 0.0054321289062500, +0.0001831054687500, 0.0051574707031250, 0.0001831054687500, 0.0049743652343750, +0.0002136230468750, 0.0049438476562500, 0.0003967285156250, 0.0046691894531250, +0.0003662109375000, 0.0043029785156250, 0.0003662109375000, 0.0041198730468750, +0.0005493164062500, 0.0037841796875000, 0.0003051757812500, 0.0036010742187500, +0.0003662109375000, 0.0034179687500000, 0.0003967285156250, 0.0031127929687500, +0.0001831054687500, 0.0029602050781250, 0.0001220703125000, 0.0029296875000000, +0.0000305175781250, 0.0025329589843750, -0.0000305175781250, 0.0025329589843750, +-0.0001220703125000, 0.0026245117187500, -0.0002746582031250, 0.0021057128906250, +-0.0002441406250000, 0.0027160644531250, -0.0003967285156250, 0.0022277832031250, +-0.0003967285156250, 0.0024108886718750, -0.0004882812500000, 0.0029602050781250, +-0.0004882812500000, 0.0021972656250000, -0.0004577636718750, 0.0033264160156250, +-0.0005493164062500, 0.0029296875000000, -0.0004272460937500, 0.0030822753906250, +-0.0005187988281250, 0.0038146972656250, -0.0006713867187500, 0.0032348632812500, +-0.0005187988281250, 0.0041198730468750, -0.0007324218750000, 0.0038146972656250, +-0.0007934570312500, 0.0038452148437500, -0.0008239746093750, 0.0044250488281250, +-0.0009460449218750, 0.0038757324218750, -0.0010070800781250, 0.0040893554687500, +-0.0011291503906250, 0.0041809082031250, -0.0012512207031250, 0.0039062500000000, +-0.0014648437500000, 0.0039978027343750, -0.0017089843750000, 0.0043334960937500, +-0.0019531250000000, 0.0035095214843750, -0.0020446777343750, 0.0043334960937500, +-0.0024414062500000, 0.0040588378906250, -0.0024719238281250, 0.0034484863281250, +-0.0024719238281250, 0.0046081542968750, -0.0028991699218750, 0.0030517578125000, +-0.0025329589843750, 0.0035705566406250, -0.0027770996093750, 0.0036926269531250, +-0.0027770996093750, 0.0025634765625000, -0.0025939941406250, 0.0032043457031250, +-0.0030212402343750, 0.0028991699218750, -0.0023803710937500, 0.0022888183593750, +-0.0027465820312500, 0.0027770996093750, -0.0025634765625000, 0.0029907226562500, +-0.0019836425781250, 0.0022888183593750, -0.0025024414062500, 0.0036621093750000, +-0.0017700195312500, 0.0028686523437500, -0.0019226074218750, 0.0030822753906250, +-0.0019531250000000, 0.0040283203125000, -0.0016174316406250, 0.0026550292968750, +-0.0020751953125000, 0.0038757324218750, -0.0016479492187500, 0.0032043457031250, +-0.0020446777343750, 0.0028076171875000, -0.0018615722656250, 0.0032348632812500, +-0.0015869140625000, 0.0021972656250000, -0.0024108886718750, 0.0025939941406250, +-0.0011291503906250, 0.0020751953125000, -0.0019226074218750, 0.0017395019531250, +-0.0018920898437500, 0.0019836425781250, -0.0011596679687500, 0.0014038085937500, +-0.0025634765625000, 0.0015563964843750, -0.0014648437500000, 0.0015869140625000, +-0.0023498535156250, 0.0014953613281250, -0.0024414062500000, 0.0017089843750000, +-0.0017395019531250, 0.0019226074218750, -0.0029907226562500, 0.0022583007812500, +-0.0017395019531250, 0.0028381347656250, -0.0019226074218750, 0.0023498535156250, +-0.0022888183593750, 0.0021972656250000, -0.0016479492187500, 0.0033264160156250, +-0.0016784667968750, 0.0009765625000000, -0.0018615722656250, 0.0024414062500000, +-0.0014953613281250, 0.0021667480468750, -0.0014038085937500, 0.0004577636718750, +-0.0016784667968750, 0.0026245117187500, -0.0015563964843750, 0.0007934570312500, +-0.0012817382812500, 0.0016784667968750, -0.0014953613281250, 0.0019531250000000, +-0.0012817382812500, 0.0005187988281250, -0.0008239746093750, 0.0012512207031250, +-0.0010070800781250, -0.0001525878906250, -0.0011291503906250, 0.0007324218750000, +-0.0004882812500000, 0.0000915527343750, -0.0009155273437500, -0.0013122558593750, +-0.0014343261718750, 0.0002441406250000, -0.0007019042968750, -0.0014648437500000, +-0.0019836425781250, -0.0011596679687500, -0.0016784667968750, -0.0006103515625000, +-0.0015258789062500, -0.0010375976562500, -0.0024108886718750, -0.0003356933593750, +-0.0023193359375000, -0.0004272460937500, -0.0021057128906250, -0.0002746582031250, +-0.0025634765625000, 0.0002746582031250, -0.0024719238281250, -0.0007934570312500, +-0.0018310546875000, -0.0032348632812500, -0.0020751953125000, -0.0029602050781250, +-0.0024108886718750, -0.0029907226562500, -0.0020446777343750, -0.0031127929687500, +-0.0022888183593750, -0.0028076171875000, -0.0026550292968750, -0.0031127929687500, +-0.0018310546875000, -0.0028686523437500, -0.0022888183593750, -0.0028076171875000, +-0.0021972656250000, -0.0028076171875000, -0.0013427734375000, -0.0027465820312500, +-0.0010986328125000, -0.0026855468750000, -0.0011901855468750, -0.0018310546875000, +-0.0000915527343750, -0.0021362304687500, -0.0003967285156250, -0.0015869140625000, +-0.0002746582031250, -0.0003356933593750, 0.0003356933593750, -0.0006713867187500, +-0.0000610351562500, 0.0000305175781250, 0.0008850097656250, 0.0007934570312500, +0.0006713867187500, 0.0003356933593750, 0.0011901855468750, 0.0000000000000000, +0.0020446777343750, 0.0005798339843750, 0.0013427734375000, -0.0005798339843750, +0.0027465820312500, -0.0003967285156250, 0.0024719238281250, -0.0004272460937500, +0.0023803710937500, -0.0009765625000000, 0.0030517578125000, -0.0006103515625000, +0.0024414062500000, -0.0011291503906250, 0.0023803710937500, -0.0007629394531250, +0.0022277832031250, -0.0009460449218750, 0.0019836425781250, -0.0014648437500000, +0.0019226074218750, -0.0007934570312500, 0.0018615722656250, -0.0013732910156250, +0.0015563964843750, -0.0012207031250000, 0.0021667480468750, -0.0008544921875000, +0.0019836425781250, -0.0010375976562500, 0.0017395019531250, -0.0010375976562500, +0.0027160644531250, -0.0004577636718750, 0.0017089843750000, -0.0006713867187500, +0.0022583007812500, -0.0003967285156250, 0.0023193359375000, 0.0001220703125000, +0.0016479492187500, -0.0002441406250000, 0.0023803710937500, 0.0003967285156250, +0.0020446777343750, 0.0001525878906250, 0.0019836425781250, 0.0001525878906250, +0.0024414062500000, 0.0006103515625000, 0.0026245117187500, 0.0001831054687500, +0.0025634765625000, 0.0001831054687500, 0.0029602050781250, 0.0003662109375000, +0.0033874511718750, 0.0001525878906250, 0.0030212402343750, 0.0000305175781250, +0.0029907226562500, 0.0003051757812500, 0.0036621093750000, 0.0000000000000000, +0.0020751953125000, 0.0001525878906250, 0.0028381347656250, 0.0001525878906250, +0.0025329589843750, 0.0000915527343750, 0.0012817382812500, 0.0003356933593750, +0.0024719238281250, -0.0003356933593750, 0.0016479492187500, -0.0000915527343750, +0.0016479492187500, -0.0004577636718750, 0.0021362304687500, -0.0012207031250000, +0.0020141601562500, -0.0008239746093750, 0.0020751953125000, -0.0016174316406250, +0.0029296875000000, -0.0018005371093750, 0.0027160644531250, -0.0017089843750000, +0.0029296875000000, -0.0020446777343750, 0.0035400390625000, -0.0022888183593750, +0.0032653808593750, -0.0019531250000000, 0.0036621093750000, -0.0023193359375000, +0.0037231445312500, -0.0021972656250000, 0.0037536621093750, -0.0018920898437500, +0.0039672851562500, -0.0023193359375000, 0.0038757324218750, -0.0014648437500000, +0.0040283203125000, -0.0019226074218750, 0.0039978027343750, -0.0015563964843750, +0.0038146972656250, -0.0007934570312500, 0.0037231445312500, -0.0016479492187500, +0.0036010742187500, -0.0004272460937500, 0.0035400390625000, -0.0006408691406250, +0.0035705566406250, -0.0007019042968750, 0.0034179687500000, -0.0001525878906250, +0.0032653808593750, -0.0006713867187500, 0.0033264160156250, -0.0001831054687500, +0.0029296875000000, -0.0004272460937500, 0.0028686523437500, -0.0005187988281250, +0.0027465820312500, -0.0002441406250000, 0.0024108886718750, -0.0005493164062500, +0.0025329589843750, -0.0002441406250000, 0.0020446777343750, -0.0004577636718750, +0.0020141601562500, -0.0003662109375000, 0.0017700195312500, -0.0001525878906250, +0.0014953613281250, -0.0005493164062500, 0.0016479492187500, -0.0001831054687500, +0.0010986328125000, -0.0004272460937500, 0.0013427734375000, -0.0004577636718750, +0.0012817382812500, -0.0002136230468750, 0.0008239746093750, -0.0005187988281250, +0.0013427734375000, -0.0002441406250000, 0.0007934570312500, -0.0004272460937500, +0.0010375976562500, -0.0005187988281250, 0.0010986328125000, -0.0003967285156250, +0.0008850097656250, -0.0006408691406250, 0.0014343261718750, -0.0005798339843750, +0.0012512207031250, -0.0007324218750000, 0.0014953613281250, -0.0006408691406250, +0.0017089843750000, -0.0004577636718750, 0.0017089843750000, -0.0006713867187500, +0.0020141601562500, -0.0003356933593750, 0.0022583007812500, -0.0002441406250000, +0.0023498535156250, -0.0003356933593750, 0.0027465820312500, -0.0002441406250000, +0.0031127929687500, -0.0002746582031250, 0.0029602050781250, -0.0004272460937500, +0.0035095214843750, -0.0004577636718750, 0.0035095214843750, -0.0005187988281250, +0.0035400390625000, -0.0005798339843750, 0.0038452148437500, -0.0004577636718750, +0.0038757324218750, -0.0004577636718750, 0.0035095214843750, -0.0004272460937500, +0.0040283203125000, -0.0001831054687500, 0.0035400390625000, -0.0001220703125000, +0.0028991699218750, -0.0001831054687500, 0.0036621093750000, 0.0001831054687500, +0.0021667480468750, 0.0002441406250000, 0.0025024414062500, 0.0002136230468750, +0.0023193359375000, 0.0003662109375000, 0.0011291503906250, 0.0004577636718750, +0.0016784667968750, 0.0000610351562500, 0.0012817382812500, 0.0000610351562500, +0.0009765625000000, 0.0000305175781250, 0.0014953613281250, -0.0003662109375000, +0.0016479492187500, -0.0004882812500000, 0.0012817382812500, -0.0003662109375000, +0.0023498535156250, -0.0006713867187500, 0.0021667480468750, -0.0009155273437500, +0.0023498535156250, -0.0009765625000000, 0.0031127929687500, -0.0012817382812500, +0.0027465820312500, -0.0015563964843750, 0.0029907226562500, -0.0021362304687500, +0.0031127929687500, -0.0022888183593750, 0.0026550292968750, -0.0023803710937500, +0.0023193359375000, -0.0028991699218750, 0.0024108886718750, -0.0025329589843750, +0.0017395019531250, -0.0025329589843750, 0.0012512207031250, -0.0025634765625000, +0.0014343261718750, -0.0022888183593750, 0.0013122558593750, -0.0020446777343750, +0.0007324218750000, -0.0020751953125000, 0.0018920898437500, -0.0019531250000000, +0.0013732910156250}, +{0.0025329589843750, -0.0019226074218750, 0.0022583007812500, -0.0016479492187500, +0.0024719238281250, -0.0017089843750000, 0.0026855468750000, -0.0019531250000000, +0.0021972656250000, -0.0012817382812500, 0.0029602050781250, -0.0017700195312500, +0.0025634765625000, -0.0015258789062500, 0.0024108886718750, -0.0009460449218750, +0.0028991699218750, -0.0018615722656250, 0.0024108886718750, -0.0007324218750000, +0.0024414062500000, -0.0010375976562500, 0.0025634765625000, -0.0010375976562500, +0.0023803710937500, -0.0003356933593750, 0.0022888183593750, -0.0009155273437500, +0.0024414062500000, -0.0003051757812500, 0.0022277832031250, -0.0004882812500000, +0.0022277832031250, -0.0005187988281250, 0.0022888183593750, -0.0001220703125000, +0.0021362304687500, -0.0004577636718750, 0.0021362304687500, -0.0001525878906250, +0.0021972656250000, -0.0001831054687500, 0.0022888183593750, -0.0002136230468750, +0.0022888183593750, -0.0000915527343750, 0.0023803710937500, -0.0001831054687500, +0.0025939941406250, -0.0000305175781250, 0.0025939941406250, -0.0001220703125000, +0.0028686523437500, -0.0001220703125000, 0.0028686523437500, -0.0000610351562500, +0.0028381347656250, -0.0002136230468750, 0.0032653808593750, -0.0001220703125000, +0.0029296875000000, -0.0003051757812500, 0.0033874511718750, -0.0002136230468750, +0.0033264160156250, -0.0000915527343750, 0.0030517578125000, -0.0003356933593750, +0.0036621093750000, 0.0001831054687500, 0.0027770996093750, -0.0000610351562500, +0.0033569335937500, -0.0000915527343750, 0.0031738281250000, 0.0002136230468750, +0.0025329589843750, -0.0001525878906250, 0.0033874511718750, -0.0002136230468750, +0.0022583007812500, -0.0002441406250000, 0.0027465820312500, -0.0005187988281250, +0.0027160644531250, -0.0006103515625000, 0.0019226074218750, -0.0005798339843750, +0.0027465820312500, -0.0008850097656250, 0.0019531250000000, -0.0007629394531250, +0.0021667480468750, -0.0006103515625000, 0.0023803710937500, -0.0007019042968750, +0.0020751953125000, -0.0004272460937500, 0.0024414062500000, -0.0001525878906250, +0.0026855468750000, -0.0001220703125000, 0.0027465820312500, 0.0001220703125000, +0.0031738281250000, 0.0003967285156250, 0.0036926269531250, 0.0003967285156250, +0.0036621093750000, 0.0003967285156250, 0.0042724609375000, 0.0005187988281250, +0.0044555664062500, 0.0003967285156250, 0.0044860839843750, 0.0002136230468750, +0.0048828125000000, 0.0001831054687500, 0.0049438476562500, 0.0000305175781250, +0.0044555664062500, -0.0000610351562500, 0.0047607421875000, -0.0003051757812500, +0.0042419433593750, -0.0004272460937500, 0.0035095214843750, -0.0003967285156250, +0.0040283203125000, -0.0013732910156250, 0.0027160644531250, -0.0013732910156250, +0.0026550292968750, -0.0017395019531250, 0.0025939941406250, -0.0026550292968750, +0.0018310546875000, -0.0025329589843750, 0.0020446777343750, -0.0028686523437500, +0.0019226074218750, -0.0030517578125000, 0.0017395019531250, -0.0030517578125000, +0.0020141601562500, -0.0028686523437500, 0.0022277832031250, -0.0025634765625000, +0.0019531250000000, -0.0028076171875000, 0.0024108886718750, -0.0021667480468750, +0.0025634765625000, -0.0020751953125000, 0.0023498535156250, -0.0024414062500000, +0.0023803710937500, -0.0019531250000000, 0.0025329589843750, -0.0020446777343750, +0.0018005371093750, -0.0020751953125000, 0.0017395019531250, -0.0022888183593750, +0.0016174316406250, -0.0021667480468750, 0.0012207031250000, -0.0017395019531250, +0.0014648437500000, -0.0030822753906250, 0.0012817382812500, -0.0020751953125000, +0.0010986328125000, -0.0023193359375000, 0.0011291503906250, -0.0035095214843750, +0.0011596679687500, -0.0019836425781250, 0.0012207031250000, -0.0030822753906250, +0.0013122558593750, -0.0027465820312500, 0.0014343261718750, -0.0022888183593750, +0.0018920898437500, -0.0024719238281250, 0.0019531250000000, -0.0018005371093750, +0.0013122558593750, -0.0024719238281250, 0.0021972656250000, -0.0020446777343750, +0.0014648437500000, -0.0019531250000000, 0.0015258789062500, -0.0025329589843750, +0.0020751953125000, -0.0021667480468750, 0.0009155273437500, -0.0024719238281250, +0.0024108886718750, -0.0027160644531250, 0.0017700195312500, -0.0028076171875000, +0.0018615722656250, -0.0029296875000000, 0.0033264160156250, -0.0028686523437500, +0.0025939941406250, -0.0029602050781250, 0.0025939941406250, -0.0024108886718750, +0.0032348632812500, -0.0025634765625000, 0.0018615722656250, -0.0026550292968750, +0.0005798339843750, -0.0015869140625000, 0.0013122558593750, -0.0028076171875000, +-0.0015563964843750, -0.0019531250000000, -0.0018310546875000, -0.0015869140625000, +-0.0016174316406250, -0.0029296875000000, -0.0033264160156250, -0.0002746582031250, +0.0014343261718750, 0.0003051757812500, -0.0005187988281250, 0.0004272460937500, +-0.0006408691406250, 0.0009460449218750, -0.0011596679687500, 0.0013732910156250, +-0.0019226074218750, 0.0013427734375000, -0.0021972656250000, 0.0024414062500000, +-0.0025329589843750, 0.0023498535156250, -0.0025329589843750, 0.0025024414062500, +-0.0031127929687500, 0.0034179687500000, -0.0037536621093750, 0.0030822753906250, +-0.0034790039062500, 0.0025939941406250, -0.0042114257812500, 0.0030822753906250, +-0.0046386718750000, 0.0024108886718750, -0.0039367675781250, 0.0013427734375000, +-0.0035705566406250, 0.0019226074218750, -0.0039672851562500, 0.0013427734375000, +-0.0027770996093750, 0.0008239746093750, -0.0022888183593750, 0.0016479492187500, +-0.0028076171875000, 0.0020446777343750, -0.0025024414062500, 0.0013427734375000, +-0.0016784667968750, 0.0031127929687500, -0.0032653808593750, 0.0031738281250000, +-0.0025634765625000, 0.0026245117187500, -0.0026550292968750, 0.0032653808593750, +-0.0038452148437500, 0.0032348632812500, -0.0028686523437500, 0.0019531250000000, +-0.0037536621093750, 0.0023498535156250, -0.0034790039062500, 0.0018615722656250, +-0.0034484863281250, 0.0007324218750000, -0.0039367675781250, 0.0013732910156250, +-0.0032348632812500, 0.0010070800781250, -0.0036621093750000, 0.0008544921875000, +-0.0035705566406250, 0.0014038085937500, -0.0031738281250000, 0.0018005371093750, +-0.0030517578125000, 0.0016784667968750, -0.0029296875000000, 0.0018920898437500, +-0.0025939941406250, 0.0025939941406250, -0.0021972656250000, 0.0021057128906250, +-0.0020751953125000, 0.0016784667968750, -0.0018615722656250, 0.0024719238281250, +-0.0014648437500000, 0.0012817382812500, -0.0017395019531250, 0.0015869140625000, +-0.0017089843750000, 0.0014953613281250, -0.0014648437500000, 0.0007019042968750, +-0.0015258789062500, 0.0013732910156250, -0.0016479492187500, 0.0008239746093750, +-0.0011291503906250, 0.0007324218750000, -0.0013427734375000, 0.0012817382812500, +-0.0012512207031250, 0.0014953613281250, -0.0008850097656250, 0.0015563964843750, +-0.0012512207031250, 0.0022583007812500, -0.0004577636718750, 0.0026245117187500, +-0.0007019042968750, 0.0026245117187500, -0.0003662109375000, 0.0029602050781250, +0.0003967285156250, 0.0033874511718750, -0.0001525878906250, 0.0025634765625000, +0.0005187988281250, 0.0031433105468750, 0.0007324218750000, 0.0027160644531250, +0.0006408691406250, 0.0018310546875000, 0.0007629394531250, 0.0028076171875000, +0.0008850097656250, 0.0010070800781250, 0.0010986328125000, 0.0014648437500000, +0.0010070800781250, 0.0013427734375000, 0.0011596679687500, 0.0000915527343750, +0.0014648437500000, 0.0010070800781250, 0.0011901855468750, 0.0004272460937500, +0.0010986328125000, 0.0003967285156250, 0.0011596679687500, 0.0007629394531250, +0.0008850097656250, 0.0007324218750000, 0.0006103515625000, 0.0008239746093750, +0.0007934570312500, 0.0014343261718750, 0.0006713867187500, 0.0011901855468750, +0.0006103515625000, 0.0016784667968750, 0.0006103515625000, 0.0023193359375000, +0.0006713867187500, 0.0017700195312500, 0.0007324218750000, 0.0029907226562500, +0.0005187988281250, 0.0025024414062500, 0.0006103515625000, 0.0026855468750000, +0.0005798339843750, 0.0034179687500000, 0.0003356933593750, 0.0024719238281250, +0.0004577636718750, 0.0034179687500000, 0.0003356933593750, 0.0030212402343750, +0.0003662109375000, 0.0029296875000000, 0.0003967285156250, 0.0033569335937500, +0.0003356933593750, 0.0026855468750000, 0.0003967285156250, 0.0032653808593750, +0.0003051757812500, 0.0028076171875000, 0.0002746582031250, 0.0026855468750000, +0.0003051757812500, 0.0030517578125000, 0.0003356933593750, 0.0024108886718750, +0.0002746582031250, 0.0028076171875000, 0.0004272460937500, 0.0026855468750000, +0.0003356933593750, 0.0025024414062500, 0.0003967285156250, 0.0027160644531250, +0.0004577636718750, 0.0026550292968750, 0.0003051757812500, 0.0026550292968750, +0.0003967285156250, 0.0026245117187500, 0.0002441406250000, 0.0026550292968750, +0.0001831054687500, 0.0026550292968750, 0.0001831054687500, 0.0025024414062500, +-0.0001220703125000, 0.0028076171875000, -0.0001220703125000, 0.0024414062500000, +-0.0002441406250000, 0.0026550292968750, -0.0005493164062500, 0.0030517578125000, +-0.0007019042968750, 0.0024719238281250, -0.0008239746093750, 0.0033874511718750, +-0.0011596679687500, 0.0032043457031250, -0.0012817382812500, 0.0032653808593750, +-0.0014343261718750, 0.0039062500000000, -0.0016479492187500, 0.0035705566406250, +-0.0016479492187500, 0.0038452148437500, -0.0019226074218750, 0.0039978027343750, +-0.0019836425781250, 0.0039672851562500, -0.0019531250000000, 0.0040893554687500, +-0.0021057128906250, 0.0041809082031250, -0.0019836425781250, 0.0039672851562500, +-0.0019836425781250, 0.0042419433593750, -0.0020751953125000, 0.0040283203125000, +-0.0017700195312500, 0.0038757324218750, -0.0016174316406250, 0.0044860839843750, +-0.0019226074218750, 0.0037231445312500, -0.0011596679687500, 0.0045471191406250, +-0.0014343261718750, 0.0043640136718750, -0.0012817382812500, 0.0038757324218750, +-0.0007324218750000, 0.0053710937500000, -0.0010681152343750, 0.0038757324218750, +-0.0004882812500000, 0.0046081542968750, -0.0006408691406250, 0.0048522949218750, +-0.0004882812500000, 0.0039367675781250, -0.0000915527343750, 0.0048217773437500, +-0.0005187988281250, 0.0045471191406250, 0.0002136230468750, 0.0048828125000000, +-0.0000915527343750, 0.0052490234375000, 0.0001220703125000, 0.0052185058593750, +0.0005493164062500, 0.0055236816406250, -0.0003051757812500, 0.0054321289062500, +0.0003967285156250, 0.0055541992187500, -0.0004272460937500, 0.0054016113281250, +-0.0007019042968750, 0.0049743652343750, -0.0003967285156250, 0.0049438476562500, +-0.0015563964843750, 0.0043029785156250, -0.0008239746093750, 0.0040588378906250, +-0.0014038085937500, 0.0037536621093750, -0.0016174316406250, 0.0032653808593750, +-0.0010681152343750, 0.0031738281250000, -0.0016174316406250, 0.0030517578125000, +-0.0013122558593750, 0.0028991699218750, -0.0012207031250000, 0.0028381347656250, +-0.0012817382812500, 0.0030212402343750, -0.0012817382812500, 0.0030517578125000, +-0.0012817382812500, 0.0024414062500000, -0.0010375976562500, 0.0031433105468750, +-0.0013122558593750, 0.0025329589843750, -0.0012512207031250, 0.0018615722656250, +-0.0011291503906250, 0.0033264160156250, -0.0016174316406250, 0.0014343261718750, +-0.0009765625000000, 0.0024414062500000, -0.0014343261718750, 0.0021972656250000, +-0.0013427734375000, 0.0008239746093750, -0.0007019042968750, 0.0024414062500000, +-0.0010375976562500, 0.0007019042968750, -0.0007629394531250, 0.0017395019531250, +-0.0002441406250000, 0.0019531250000000, -0.0006103515625000, 0.0007934570312500, +-0.0008850097656250}, +{0.0006103515625000, -0.0003967285156250, 0.0005493164062500, -0.0003967285156250, +0.0005187988281250, -0.0003967285156250, 0.0005798339843750, -0.0005493164062500, +0.0005493164062500, -0.0005187988281250, 0.0005493164062500, -0.0002746582031250, +0.0005493164062500, -0.0000915527343750, 0.0004577636718750, -0.0001525878906250, +0.0005187988281250, 0.0000915527343750, 0.0003967285156250, 0.0002441406250000, +0.0004272460937500, 0.0002136230468750, 0.0004577636718750, 0.0003967285156250, +0.0002136230468750, 0.0005798339843750, 0.0004272460937500, 0.0006103515625000, +0.0002746582031250, 0.0008850097656250, 0.0001525878906250, 0.0010681152343750, +0.0001220703125000, 0.0010070800781250, -0.0000610351562500, 0.0015869140625000, +-0.0003662109375000, 0.0012817382812500, -0.0005187988281250, 0.0016479492187500, +-0.0007324218750000, 0.0020751953125000, -0.0009765625000000, 0.0014343261718750, +-0.0011291503906250, 0.0026550292968750, -0.0013732910156250, 0.0020141601562500, +-0.0014343261718750, 0.0023498535156250, -0.0016174316406250, 0.0033569335937500, +-0.0018310546875000, 0.0023498535156250, -0.0017395019531250, 0.0038452148437500, +-0.0018615722656250, 0.0035095214843750, -0.0018005371093750, 0.0037841796875000, +-0.0016784667968750, 0.0048217773437500, -0.0016784667968750, 0.0040893554687500, +-0.0015563964843750, 0.0052795410156250, -0.0013122558593750, 0.0051879882812500, +-0.0013427734375000, 0.0050964355468750, -0.0011596679687500, 0.0057678222656250, +-0.0008850097656250, 0.0056152343750000, -0.0010375976562500, 0.0057067871093750, +-0.0005187988281250, 0.0061035156250000, -0.0006408691406250, 0.0058593750000000, +-0.0003967285156250, 0.0058593750000000, -0.0000610351562500, 0.0066223144531250, +-0.0004577636718750, 0.0055236816406250, 0.0003662109375000, 0.0065307617187500, +0.0000305175781250, 0.0062561035156250, 0.0002136230468750, 0.0050964355468750, +0.0008544921875000, 0.0063476562500000, 0.0001831054687500, 0.0048217773437500, +0.0009155273437500, 0.0051879882812500, 0.0004272460937500, 0.0053710937500000, +0.0002441406250000, 0.0044555664062500, 0.0004577636718750, 0.0052490234375000, +-0.0004272460937500, 0.0050354003906250, -0.0000305175781250, 0.0050048828125000, +-0.0003967285156250, 0.0054016113281250, -0.0007934570312500, 0.0055236816406250, +-0.0004882812500000, 0.0054626464843750, -0.0007324218750000, 0.0056762695312500, +-0.0010681152343750, 0.0056457519531250, -0.0006713867187500, 0.0054626464843750, +-0.0009155273437500, 0.0054016113281250, -0.0011901855468750, 0.0054016113281250, +-0.0004882812500000, 0.0046997070312500, -0.0013122558593750, 0.0047607421875000, +-0.0008850097656250, 0.0045166015625000, -0.0007934570312500, 0.0039978027343750, +-0.0013732910156250, 0.0043334960937500, -0.0008544921875000, 0.0037231445312500, +-0.0013427734375000, 0.0039062500000000, -0.0013732910156250, 0.0036315917968750, +-0.0013122558593750, 0.0031738281250000, -0.0016174316406250, 0.0038757324218750, +-0.0016174316406250, 0.0036010742187500, -0.0012512207031250, 0.0039062500000000, +-0.0012817382812500, 0.0035705566406250, -0.0010986328125000, 0.0031127929687500, +-0.0005798339843750, 0.0035095214843750, -0.0005493164062500, 0.0020141601562500, +-0.0009460449218750, 0.0023193359375000, -0.0005798339843750, 0.0019836425781250, +-0.0005493164062500, 0.0009155273437500, -0.0010070800781250, 0.0017700195312500, +-0.0007934570312500, 0.0011901855468750, -0.0008239746093750, 0.0008544921875000, +-0.0014648437500000, 0.0011291503906250, -0.0012817382812500, 0.0012207031250000, +-0.0010681152343750, 0.0008850097656250, -0.0018615722656250, 0.0007324218750000, +-0.0013427734375000, 0.0003051757812500, -0.0018310546875000, -0.0000915527343750, +-0.0017700195312500, -0.0005798339843750, -0.0014343261718750, -0.0011291503906250, +-0.0022277832031250, -0.0007934570312500, -0.0011901855468750, -0.0014953613281250, +-0.0016479492187500, -0.0017395019531250, -0.0016784667968750, -0.0004577636718750, +-0.0008850097656250, 0.0006103515625000, -0.0009460449218750, -0.0006713867187500, +0.0005493164062500, 0.0000305175781250, -0.0002746582031250, -0.0002136230468750, +0.0001525878906250, -0.0013122558593750, 0.0012817382812500, -0.0003356933593750, +-0.0000610351562500, -0.0018615722656250, 0.0017089843750000, -0.0013427734375000, +0.0014953613281250, -0.0015563964843750, 0.0013122558593750, -0.0024108886718750, +0.0022888183593750, -0.0012207031250000, 0.0019531250000000, -0.0025329589843750, +0.0021362304687500, -0.0023193359375000, 0.0022583007812500, -0.0020141601562500, +0.0024414062500000, -0.0027770996093750, 0.0026855468750000, -0.0027160644531250, +0.0023803710937500, -0.0019836425781250, 0.0027465820312500, -0.0025024414062500, +0.0029602050781250, -0.0022277832031250, 0.0025939941406250, -0.0013732910156250, +0.0025939941406250, -0.0020141601562500, 0.0029907226562500, -0.0015258789062500, +0.0018005371093750, -0.0013122558593750, 0.0025634765625000, -0.0016784667968750, +0.0021057128906250, -0.0016479492187500, 0.0010986328125000, -0.0013732910156250, +0.0025024414062500, -0.0018310546875000, 0.0013122558593750, -0.0018615722656250, +0.0018005371093750, -0.0018310546875000, 0.0020751953125000, -0.0023193359375000, +0.0015869140625000, -0.0023803710937500, 0.0022583007812500, -0.0016784667968750, +0.0014038085937500, -0.0022277832031250, 0.0016174316406250, -0.0016784667968750, +0.0014343261718750, -0.0007629394531250, 0.0006713867187500, -0.0017089843750000, +0.0010681152343750, -0.0001831054687500, 0.0004272460937500, -0.0003967285156250, +0.0004272460937500, -0.0004882812500000, 0.0005798339843750, 0.0003662109375000, +0.0005187988281250, -0.0000915527343750, 0.0009460449218750, 0.0000000000000000, +0.0009460449218750, 0.0000610351562500, 0.0015563964843750, -0.0000610351562500, +0.0016174316406250, -0.0003051757812500, 0.0016784667968750, -0.0003967285156250, +0.0025024414062500, -0.0001220703125000, 0.0016174316406250, -0.0005493164062500, +0.0021362304687500, -0.0002441406250000, 0.0023803710937500, 0.0001525878906250, +0.0017089843750000, -0.0005493164062500, 0.0022888183593750, 0.0002441406250000, +0.0024414062500000, 0.0000305175781250, 0.0022583007812500, -0.0002441406250000, +0.0026245117187500, 0.0000610351562500, 0.0030517578125000, -0.0001831054687500, +0.0027770996093750, -0.0002746582031250, 0.0031433105468750, -0.0002441406250000, +0.0033874511718750, -0.0002136230468750, 0.0032348632812500, -0.0000610351562500, +0.0032958984375000, -0.0000610351562500, 0.0034484863281250, -0.0001831054687500, +0.0028381347656250, 0.0002136230468750, 0.0029602050781250, 0.0000000000000000, +0.0027160644531250, -0.0003051757812500, 0.0021362304687500, 0.0001525878906250, +0.0022888183593750, -0.0007324218750000, 0.0018005371093750, -0.0004882812500000, +0.0015563964843750, -0.0005493164062500, 0.0014953613281250, -0.0011596679687500, +0.0012512207031250, -0.0007324218750000, 0.0008850097656250, -0.0011596679687500, +0.0010375976562500, -0.0012817382812500, 0.0007324218750000, -0.0010375976562500, +0.0006713867187500, -0.0011901855468750, 0.0009155273437500, -0.0013427734375000, +0.0005798339843750, -0.0007934570312500, 0.0009460449218750, -0.0012207031250000, +0.0007324218750000, -0.0010375976562500, 0.0007934570312500, -0.0004882812500000, +0.0011901855468750, -0.0010681152343750, 0.0009155273437500, -0.0003356933593750, +0.0012817382812500, -0.0005798339843750, 0.0013427734375000, -0.0004882812500000, +0.0012512207031250, 0.0000000000000000, 0.0013732910156250, -0.0005187988281250, +0.0014953613281250, 0.0002441406250000, 0.0012817382812500, -0.0001525878906250, +0.0014648437500000, -0.0000305175781250, 0.0015258789062500, 0.0004577636718750, +0.0014343261718750, -0.0001525878906250, 0.0016784667968750, 0.0005187988281250, +0.0015258789062500, 0.0003051757812500, 0.0016479492187500, 0.0002746582031250, +0.0017089843750000, 0.0007324218750000, 0.0016479492187500, 0.0003967285156250, +0.0018005371093750, 0.0007324218750000, 0.0018920898437500, 0.0006713867187500, +0.0020446777343750, 0.0006103515625000, 0.0020141601562500, 0.0007629394531250, +0.0019836425781250, 0.0005187988281250, 0.0022277832031250, 0.0005493164062500, +0.0018310546875000, 0.0003967285156250, 0.0021362304687500, 0.0002441406250000, +0.0020446777343750, 0.0001831054687500, 0.0017700195312500, 0.0001220703125000, +0.0022888183593750, 0.0000610351562500, 0.0017395019531250, 0.0000915527343750, +0.0020751953125000, 0.0001220703125000, 0.0021362304687500, 0.0000915527343750, +0.0018005371093750, 0.0001525878906250, 0.0023193359375000, 0.0002136230468750, +0.0021057128906250, 0.0001831054687500, 0.0021972656250000, 0.0000915527343750, +0.0025024414062500, 0.0000610351562500, 0.0025329589843750, 0.0001220703125000, +0.0025939941406250, -0.0002136230468750, 0.0032653808593750, -0.0001831054687500, +0.0029907226562500, -0.0002136230468750, 0.0033569335937500, -0.0003967285156250, +0.0039367675781250, -0.0002746582031250, 0.0034484863281250, -0.0005493164062500, +0.0040588378906250, -0.0004272460937500, 0.0039672851562500, -0.0007629394531250, +0.0037231445312500, -0.0011901855468750, 0.0040588378906250, -0.0008544921875000, +0.0039367675781250, -0.0018615722656250, 0.0035400390625000, -0.0017395019531250, +0.0036621093750000, -0.0019531250000000, 0.0034179687500000, -0.0025024414062500, +0.0029907226562500, -0.0020141601562500, 0.0032958984375000, -0.0027465820312500, +0.0030822753906250, -0.0021057128906250, 0.0029907226562500, -0.0023193359375000, +0.0033264160156250, -0.0027465820312500, 0.0035095214843750, -0.0014648437500000, +0.0036010742187500, -0.0027770996093750, 0.0043029785156250, -0.0021667480468750, +0.0043945312500000, -0.0018005371093750, 0.0046691894531250, -0.0025329589843750, +0.0053405761718750, -0.0019226074218750, 0.0052490234375000, -0.0022583007812500, +0.0054931640625000, -0.0021667480468750, 0.0058288574218750, -0.0025024414062500, +0.0053710937500000, -0.0028686523437500, 0.0051269531250000, -0.0022583007812500, +0.0056762695312500, -0.0034179687500000, 0.0043945312500000, -0.0030212402343750, +0.0046081542968750, -0.0027160644531250, 0.0045471191406250, -0.0031433105468750, +0.0038146972656250, -0.0025329589843750, 0.0044250488281250, -0.0025329589843750, +0.0040283203125000, -0.0021667480468750, 0.0041809082031250, -0.0021972656250000, +0.0044860839843750, -0.0022277832031250, 0.0043029785156250, -0.0016784667968750, +0.0043334960937500, -0.0020446777343750, 0.0044250488281250, -0.0021057128906250, +0.0045471191406250, -0.0013122558593750, 0.0038146972656250, -0.0012512207031250, +0.0034484863281250, -0.0023193359375000, 0.0039367675781250, -0.0011901855468750, +0.0023803710937500, -0.0018615722656250, 0.0027770996093750, -0.0022277832031250, +0.0024414062500000, -0.0017700195312500, 0.0008850097656250, -0.0025634765625000, +0.0013732910156250, -0.0020446777343750, 0.0014648437500000, -0.0022888183593750, +0.0005493164062500, -0.0020751953125000, 0.0012207031250000, -0.0015258789062500, +0.0019531250000000, -0.0018920898437500, 0.0006713867187500, -0.0006713867187500, +0.0020751953125000, -0.0009765625000000, 0.0017089843750000, -0.0005493164062500, +0.0015563964843750, 0.0004272460937500, 0.0020141601562500, -0.0003051757812500, +0.0013732910156250, 0.0010070800781250, 0.0026855468750000, 0.0007324218750000, +0.0016479492187500, 0.0009765625000000, 0.0018615722656250, 0.0026855468750000, +0.0043029785156250, 0.0052795410156250, 0.0030212402343750, 0.0062561035156250, +0.0036315917968750}, +{0.0014343261718750, 0.0003662109375000, 0.0018615722656250, 0.0004882812500000, +0.0016479492187500, 0.0004577636718750, 0.0016174316406250, 0.0003356933593750, +0.0018615722656250, 0.0004272460937500, 0.0015258789062500, 0.0006103515625000, +0.0018005371093750, 0.0005187988281250, 0.0017700195312500, 0.0006408691406250, +0.0016174316406250, 0.0007629394531250, 0.0016479492187500, 0.0005798339843750, +0.0015869140625000, 0.0005798339843750, 0.0013427734375000, 0.0003356933593750, +0.0014038085937500, 0.0002136230468750, 0.0010375976562500, 0.0001525878906250, +0.0007019042968750, -0.0001220703125000, 0.0009460449218750, -0.0000610351562500, +0.0003051757812500, -0.0002441406250000, 0.0002441406250000, -0.0006103515625000, +0.0002441406250000, -0.0007629394531250, -0.0001831054687500, -0.0008239746093750, +-0.0002441406250000, -0.0014648437500000, -0.0002746582031250, -0.0014648437500000, +-0.0004882812500000, -0.0017700195312500, -0.0003051757812500, -0.0022277832031250, +-0.0001220703125000, -0.0019226074218750, -0.0003662109375000, -0.0025634765625000, +0.0003356933593750, -0.0022583007812500, 0.0001525878906250, -0.0022888183593750, +0.0003967285156250, -0.0025329589843750, 0.0010681152343750, -0.0017089843750000, +0.0006408691406250, -0.0023803710937500, 0.0011291503906250, -0.0017089843750000, +0.0010986328125000, -0.0015563964843750, 0.0010375976562500, -0.0019531250000000, +0.0012207031250000, -0.0011901855468750, 0.0010375976562500, -0.0017395019531250, +0.0013427734375000, -0.0015869140625000, 0.0009460449218750, -0.0017395019531250, +0.0013122558593750, -0.0021057128906250, 0.0016174316406250, -0.0018005371093750, +0.0009765625000000, -0.0028381347656250, 0.0026550292968750, -0.0023498535156250, +0.0016479492187500, -0.0024414062500000, 0.0025634765625000, -0.0031738281250000, +0.0043640136718750, -0.0022277832031250, 0.0028076171875000, -0.0024108886718750, +0.0052185058593750, -0.0023498535156250, 0.0049133300781250, -0.0018615722656250, +0.0046691894531250, -0.0017395019531250, 0.0057067871093750, -0.0016174316406250, +0.0047607421875000, -0.0014038085937500, 0.0051269531250000, -0.0014038085937500, +0.0050659179687500, -0.0010375976562500, 0.0047302246093750, -0.0009155273437500, +0.0047302246093750, -0.0013732910156250, 0.0045471191406250, -0.0001525878906250, +0.0043640136718750, -0.0010681152343750, 0.0041809082031250, -0.0006408691406250, +0.0037536621093750, 0.0003356933593750, 0.0035705566406250, -0.0013122558593750, +0.0039062500000000, -0.0003051757812500, 0.0037231445312500, -0.0007019042968750, +0.0043640136718750, -0.0007629394531250, 0.0043945312500000, 0.0000000000000000, +0.0040893554687500, -0.0005187988281250, 0.0046081542968750, 0.0006103515625000, +0.0035400390625000, 0.0006103515625000, 0.0033569335937500, 0.0010070800781250, +0.0032958984375000, 0.0018005371093750, 0.0023193359375000, 0.0014038085937500, +0.0019226074218750, 0.0025939941406250, 0.0031738281250000, 0.0020141601562500, +0.0016479492187500, 0.0026855468750000, 0.0025634765625000, 0.0036315917968750, +0.0044250488281250, 0.0023803710937500, 0.0023193359375000, 0.0049133300781250, +0.0043029785156250, 0.0042419433593750, 0.0041503906250000, 0.0042724609375000, +0.0032348632812500, 0.0071716308593750, 0.0038452148437500, 0.0068664550781250, +0.0049133300781250, 0.0050354003906250, 0.0064086914062500, 0.0054626464843750, +0.0060119628906250, 0.0052185058593750, 0.0052795410156250, 0.0043945312500000, +0.0049133300781250, 0.0043334960937500, 0.0047607421875000, 0.0041809082031250, +0.0043640136718750, 0.0039978027343750, 0.0039978027343750, 0.0034484863281250, +0.0041198730468750, 0.0028991699218750, 0.0042114257812500, 0.0029296875000000, +0.0036926269531250, 0.0021362304687500, 0.0037841796875000, 0.0013732910156250, +0.0036010742187500, 0.0019226074218750, 0.0031738281250000, 0.0018920898437500, +0.0026855468750000, 0.0007324218750000, 0.0022583007812500, 0.0030212402343750, +0.0023498535156250, 0.0021057128906250, 0.0016784667968750, 0.0020141601562500, +0.0014038085937500, 0.0035095214843750, 0.0015869140625000, 0.0022277832031250, +0.0011291503906250, 0.0021972656250000, 0.0006408691406250, 0.0020751953125000, +0.0007629394531250, 0.0018005371093750, 0.0001831054687500, 0.0013732910156250, +-0.0005493164062500, 0.0008850097656250, -0.0002746582031250, 0.0019531250000000, +-0.0009460449218750, 0.0011596679687500, -0.0010986328125000, 0.0016174316406250, +-0.0009460449218750, 0.0027770996093750, -0.0010375976562500, 0.0016479492187500, +-0.0008850097656250, 0.0033569335937500, -0.0010986328125000, 0.0032653808593750, +-0.0010070800781250, 0.0029296875000000, -0.0012817382812500, 0.0036926269531250, +-0.0016479492187500, 0.0033569335937500, -0.0017089843750000, 0.0024719238281250, +-0.0019531250000000, 0.0025329589843750, -0.0022277832031250, 0.0022888183593750, +-0.0022277832031250, 0.0014953613281250, -0.0021362304687500, 0.0015563964843750, +-0.0022583007812500, 0.0018615722656250, -0.0026550292968750, 0.0011901855468750, +-0.0023498535156250, 0.0017395019531250, -0.0027160644531250, 0.0023498535156250, +-0.0032653808593750, 0.0013122558593750, -0.0026245117187500, 0.0028686523437500, +-0.0031433105468750, 0.0024108886718750, -0.0032348632812500, 0.0022583007812500, +-0.0027160644531250, 0.0031738281250000, -0.0026855468750000, 0.0024719238281250, +-0.0029296875000000, 0.0025329589843750, -0.0020751953125000, 0.0027160644531250, +-0.0023193359375000, 0.0021972656250000, -0.0020751953125000, 0.0018920898437500, +-0.0014648437500000, 0.0023803710937500, -0.0020751953125000, 0.0013122558593750, +-0.0009155273437500, 0.0017700195312500, -0.0013732910156250, 0.0016784667968750, +-0.0010681152343750, 0.0010070800781250, -0.0001220703125000, 0.0019226074218750, +-0.0010070800781250, 0.0012207031250000, 0.0001220703125000, 0.0015869140625000, +-0.0000915527343750, 0.0019531250000000, -0.0001525878906250, 0.0018005371093750, +0.0004577636718750, 0.0022277832031250, 0.0000305175781250, 0.0021362304687500, +0.0004882812500000, 0.0023803710937500, 0.0003967285156250, 0.0024414062500000, +0.0004882812500000, 0.0022888183593750, 0.0008239746093750, 0.0025939941406250, +0.0005798339843750, 0.0023193359375000, 0.0011596679687500, 0.0025024414062500, +0.0009155273437500, 0.0025329589843750, 0.0009765625000000, 0.0023193359375000, +0.0013122558593750, 0.0025939941406250, 0.0008544921875000, 0.0023803710937500, +0.0011291503906250, 0.0024108886718750, 0.0010375976562500, 0.0021972656250000, +0.0008544921875000, 0.0019531250000000, 0.0008544921875000, 0.0021362304687500, +0.0007019042968750, 0.0013427734375000, 0.0007324218750000, 0.0015258789062500, +0.0005493164062500, 0.0013427734375000, 0.0006713867187500, 0.0006713867187500, +0.0007324218750000, 0.0009155273437500, 0.0004882812500000, 0.0002441406250000, +0.0007934570312500, 0.0001831054687500, 0.0006103515625000, 0.0000305175781250, +0.0005187988281250, -0.0004577636718750, 0.0006408691406250, -0.0003356933593750, +0.0003356933593750, -0.0007019042968750, 0.0004577636718750, -0.0010070800781250, +0.0002441406250000, -0.0010681152343750, 0.0001220703125000, -0.0012512207031250, +0.0001525878906250, -0.0014953613281250, -0.0001525878906250, -0.0014648437500000, +-0.0000915527343750, -0.0018005371093750, -0.0002441406250000, -0.0018310546875000, +-0.0003356933593750, -0.0017700195312500, -0.0003356933593750, -0.0022888183593750, +-0.0004882812500000, -0.0017395019531250, -0.0004882812500000, -0.0020751953125000, +-0.0004882812500000, -0.0020446777343750, -0.0005798339843750, -0.0014953613281250, +-0.0005798339843750, -0.0018920898437500, -0.0005187988281250, -0.0012512207031250, +-0.0006408691406250, -0.0013122558593750, -0.0005493164062500, -0.0011291503906250, +-0.0005493164062500, -0.0007019042968750, -0.0006103515625000, -0.0009460449218750, +-0.0006103515625000, -0.0001831054687500, -0.0003051757812500, -0.0003967285156250, +-0.0004577636718750, -0.0002136230468750, -0.0003967285156250, 0.0003967285156250, +-0.0000610351562500, 0.0000305175781250, -0.0002746582031250, 0.0006713867187500, +-0.0000915527343750, 0.0010681152343750, 0.0001220703125000, 0.0009460449218750, +0.0001220703125000, 0.0011596679687500, 0.0000915527343750, 0.0016174316406250, +0.0002746582031250, 0.0010375976562500, 0.0001831054687500, 0.0016174316406250, +0.0001831054687500, 0.0014038085937500, 0.0002136230468750, 0.0009460449218750, +0.0001525878906250, 0.0018005371093750, 0.0000610351562500, 0.0004577636718750, +0.0000000000000000, 0.0014343261718750, -0.0003356933593750, 0.0010986328125000, +-0.0005798339843750, 0.0002746582031250, -0.0005493164062500, 0.0021362304687500, +-0.0008850097656250, 0.0000610351562500, -0.0010986328125000, 0.0010375976562500, +-0.0007629394531250, 0.0009765625000000, -0.0010070800781250, -0.0003356933593750, +-0.0011291503906250, 0.0012817382812500, -0.0002746582031250, -0.0002746582031250, +-0.0011901855468750, 0.0003356933593750, -0.0002441406250000, 0.0004882812500000, +-0.0003356933593750, -0.0004577636718750, -0.0009155273437500, 0.0004882812500000, +0.0005187988281250, -0.0003051757812500, -0.0010375976562500, -0.0002136230468750, +-0.0001525878906250, -0.0000305175781250, -0.0001525878906250, -0.0005187988281250, +-0.0013122558593750, -0.0006408691406250, -0.0001220703125000, -0.0002136230468750, +-0.0011596679687500, -0.0013122558593750, -0.0010681152343750, -0.0007934570312500, +-0.0007629394531250, -0.0003356933593750, -0.0011291503906250, -0.0020141601562500, +-0.0009460449218750, 0.0006713867187500, -0.0006408691406250, -0.0008850097656250, +-0.0005798339843750, -0.0005187988281250, -0.0003662109375000, 0.0015563964843750, +-0.0001525878906250, -0.0006408691406250, -0.0003051757812500, 0.0017700195312500, +-0.0002746582031250, 0.0011596679687500, -0.0004272460937500, 0.0013427734375000, +-0.0005187988281250, 0.0027770996093750, -0.0006713867187500, 0.0015563964843750, +-0.0010681152343750, 0.0034790039062500, -0.0011291503906250, 0.0030822753906250, +-0.0016174316406250, 0.0032348632812500, -0.0016784667968750, 0.0045776367187500, +-0.0016174316406250, 0.0037841796875000, -0.0022277832031250, 0.0043640136718750, +-0.0017395019531250, 0.0043029785156250, -0.0019531250000000, 0.0038146972656250, +-0.0019226074218750, 0.0039978027343750, -0.0014953613281250, 0.0042114257812500, +-0.0018615722656250, 0.0034484863281250, -0.0013732910156250, 0.0037536621093750, +-0.0013122558593750, 0.0037231445312500, -0.0011291503906250, 0.0032348632812500, +-0.0008544921875000, 0.0035705566406250, -0.0007934570312500, 0.0030822753906250, +-0.0000305175781250, 0.0031127929687500, 0.0000305175781250, 0.0027160644531250, +0.0003662109375000, 0.0020141601562500, 0.0009765625000000, 0.0018920898437500, +0.0008544921875000, 0.0008850097656250, 0.0017700195312500, 0.0011596679687500, +0.0015869140625000, 0.0010681152343750, 0.0014648437500000, 0.0002441406250000, +0.0019836425781250, 0.0004272460937500, 0.0019531250000000, 0.0003967285156250, +0.0021667480468750, 0.0000305175781250, 0.0025329589843750, -0.0001220703125000, +0.0026550292968750, -0.0000610351562500, 0.0028076171875000, -0.0003051757812500, +0.0031127929687500, -0.0008239746093750, 0.0023498535156250, -0.0005798339843750, +0.0028686523437500, -0.0008239746093750, 0.0025329589843750, -0.0012817382812500, +0.0017395019531250, -0.0007934570312500, 0.0025024414062500, -0.0011596679687500, +0.0012512207031250, -0.0011901855468750, 0.0017700195312500, -0.0011596679687500, +0.0016174316406250}, +{0.0001220703125000, 0.0010070800781250, 0.0001525878906250, 0.0012512207031250, +0.0000000000000000, 0.0011901855468750, -0.0000610351562500, 0.0015563964843750, +-0.0000610351562500, 0.0017089843750000, -0.0001525878906250, 0.0018615722656250, +-0.0003662109375000, 0.0021362304687500, -0.0004882812500000, 0.0021667480468750, +-0.0004882812500000, 0.0023498535156250, -0.0010070800781250, 0.0026550292968750, +-0.0006713867187500, 0.0025024414062500, -0.0009460449218750, 0.0027770996093750, +-0.0012817382812500, 0.0035095214843750, -0.0004577636718750, 0.0025024414062500, +-0.0012512207031250, 0.0035400390625000, -0.0005798339843750, 0.0031127929687500, +-0.0006408691406250, 0.0022277832031250, -0.0010070800781250, 0.0038452148437500, +0.0000915527343750, 0.0016174316406250, -0.0011291503906250, 0.0025024414062500, +-0.0002441406250000, 0.0022583007812500, -0.0002746582031250, 0.0007324218750000, +-0.0013427734375000, 0.0022888183593750, -0.0000610351562500, 0.0007324218750000, +-0.0011291503906250, 0.0010681152343750, -0.0009765625000000, 0.0013122558593750, +-0.0006713867187500, 0.0004882812500000, -0.0011291503906250, 0.0009460449218750, +-0.0009460449218750, 0.0006408691406250, -0.0007934570312500, 0.0003662109375000, +-0.0009765625000000, 0.0002136230468750, -0.0008239746093750, -0.0001220703125000, +-0.0004882812500000, -0.0004577636718750, -0.0006408691406250, -0.0006713867187500, +-0.0002441406250000, -0.0012512207031250, -0.0002136230468750, -0.0010681152343750, +-0.0001220703125000, -0.0010375976562500, 0.0001220703125000, -0.0019531250000000, +-0.0001220703125000, -0.0010681152343750, -0.0003051757812500, -0.0015869140625000, +-0.0005493164062500, -0.0012512207031250, -0.0006713867187500, -0.0002441406250000, +-0.0009765625000000, -0.0007934570312500, -0.0014038085937500, 0.0007934570312500, +-0.0008239746093750, 0.0005798339843750, -0.0015869140625000, 0.0008850097656250, +-0.0014953613281250, 0.0020141601562500, -0.0007934570312500, 0.0014038085937500, +-0.0015258789062500, 0.0023193359375000, -0.0006713867187500, 0.0019226074218750, +-0.0007324218750000, 0.0021362304687500, -0.0007629394531250, 0.0028076171875000, +-0.0002746582031250, 0.0019836425781250, -0.0003051757812500, 0.0032348632812500, +0.0001525878906250, 0.0029907226562500, 0.0000610351562500, 0.0030212402343750, +0.0004882812500000, 0.0039367675781250, 0.0009460449218750, 0.0037231445312500, +0.0006103515625000, 0.0037841796875000, 0.0013122558593750, 0.0040893554687500, +0.0012207031250000, 0.0039672851562500, 0.0013122558593750, 0.0037231445312500, +0.0018615722656250, 0.0039672851562500, 0.0016174316406250, 0.0038757324218750, +0.0019531250000000, 0.0037841796875000, 0.0021057128906250, 0.0033569335937500, +0.0020446777343750, 0.0028991699218750, 0.0024108886718750, 0.0028076171875000, +0.0028686523437500, 0.0019531250000000, 0.0022583007812500, 0.0014648437500000, +0.0027465820312500, 0.0013732910156250, 0.0023803710937500, 0.0009460449218750, +0.0017700195312500, 0.0002441406250000, 0.0025329589843750, 0.0006103515625000, +0.0010986328125000, 0.0003051757812500, 0.0017089843750000, -0.0002136230468750, +0.0014343261718750, -0.0000915527343750, 0.0003967285156250, -0.0000610351562500, +0.0015258789062500, -0.0008850097656250, 0.0002136230468750, -0.0005187988281250, +0.0006103515625000, -0.0006103515625000, 0.0007934570312500, -0.0010986328125000, +0.0000305175781250, -0.0006713867187500, 0.0006713867187500, -0.0009155273437500, +0.0001831054687500, -0.0008239746093750, 0.0001220703125000, -0.0007019042968750, +0.0004577636718750, -0.0008544921875000, 0.0004882812500000, -0.0006408691406250, +0.0003662109375000, -0.0005187988281250, 0.0006713867187500, -0.0007324218750000, +0.0007019042968750, -0.0002746582031250, 0.0003662109375000, 0.0003051757812500, +0.0003356933593750, 0.0000610351562500, 0.0006408691406250, 0.0005798339843750, +0.0001525878906250, 0.0009765625000000, 0.0002441406250000, 0.0006103515625000, +0.0006103515625000, 0.0005798339843750, 0.0006408691406250, 0.0009460449218750, +0.0007019042968750, -0.0002441406250000, 0.0013122558593750, -0.0000610351562500, +0.0011901855468750, -0.0003356933593750, 0.0014953613281250, -0.0011596679687500, +0.0019531250000000, -0.0007324218750000, 0.0014953613281250, -0.0012512207031250, +0.0019226074218750, -0.0013122558593750, 0.0017089843750000, -0.0013732910156250, +0.0014953613281250, -0.0016479492187500, 0.0015563964843750, -0.0015258789062500, +0.0010681152343750, -0.0017395019531250, 0.0013732910156250, -0.0017395019531250, +0.0009155273437500, -0.0015869140625000, 0.0010070800781250, -0.0015563964843750, +0.0013122558593750, -0.0014953613281250, 0.0008239746093750, -0.0011291503906250, +0.0015869140625000, -0.0011596679687500, 0.0014343261718750, -0.0009155273437500, +0.0014038085937500, -0.0005493164062500, 0.0018005371093750, -0.0007019042968750, +0.0014038085937500, -0.0002441406250000, 0.0017089843750000, -0.0004272460937500, +0.0014953613281250, -0.0003051757812500, 0.0014953613281250, -0.0001220703125000, +0.0015869140625000, -0.0004882812500000, 0.0010375976562500, -0.0001220703125000, +0.0015869140625000, -0.0003356933593750, 0.0009765625000000, -0.0003967285156250, +0.0010375976562500, -0.0000915527343750, 0.0014343261718750, -0.0003662109375000, +0.0005493164062500, -0.0001831054687500, 0.0015258789062500, -0.0003051757812500, +0.0010681152343750, -0.0003051757812500, 0.0010375976562500, -0.0001525878906250, +0.0017395019531250, -0.0002746582031250, 0.0011901855468750, -0.0001220703125000, +0.0019531250000000, -0.0000305175781250, 0.0018615722656250, -0.0002746582031250, +0.0019836425781250, -0.0002746582031250, 0.0025024414062500, -0.0000610351562500, +0.0021667480468750, -0.0007324218750000, 0.0026245117187500, -0.0002746582031250, +0.0024719238281250, -0.0003356933593750, 0.0023193359375000, -0.0010070800781250, +0.0022583007812500, -0.0004272460937500, 0.0019226074218750, -0.0007629394531250, +0.0016479492187500, -0.0008544921875000, 0.0014648437500000, -0.0005798339843750, +0.0011901855468750, -0.0005798339843750, 0.0008544921875000, -0.0006713867187500, +0.0007324218750000, -0.0001831054687500, 0.0002746582031250, -0.0004577636718750, +0.0000305175781250, -0.0002441406250000, -0.0001831054687500, 0.0001831054687500, +-0.0004577636718750, -0.0003662109375000, -0.0005187988281250, 0.0003051757812500, +-0.0006713867187500, 0.0001525878906250, -0.0005493164062500, 0.0001220703125000, +-0.0006408691406250, 0.0004882812500000, -0.0006408691406250, 0.0001831054687500, +-0.0002441406250000, 0.0004577636718750, -0.0006103515625000, 0.0003967285156250, +-0.0001525878906250, 0.0005187988281250, -0.0000305175781250, 0.0006713867187500, +-0.0002136230468750, 0.0004577636718750, 0.0005187988281250, 0.0008544921875000, +0.0002441406250000, 0.0007019042968750, 0.0007019042968750, 0.0006408691406250, +0.0009460449218750, 0.0007934570312500, 0.0008544921875000, 0.0005493164062500, +0.0013427734375000, 0.0007629394531250, 0.0010986328125000, 0.0005187988281250, +0.0013732910156250, 0.0004272460937500, 0.0014038085937500, 0.0006408691406250, +0.0011901855468750, 0.0003662109375000, 0.0014648437500000, 0.0002441406250000, +0.0008850097656250, 0.0001525878906250, 0.0011901855468750, -0.0001831054687500, +0.0009460449218750, -0.0003967285156250, 0.0004577636718750, -0.0004882812500000, +0.0010986328125000, -0.0010681152343750, 0.0002136230468750, -0.0010070800781250, +0.0003967285156250, -0.0013427734375000, 0.0005187988281250, -0.0017395019531250, +0.0001831054687500, -0.0013122558593750, 0.0006713867187500, -0.0020751953125000, +0.0007629394531250, -0.0017089843750000, 0.0008850097656250, -0.0015869140625000, +0.0014343261718750, -0.0019226074218750, 0.0018005371093750, -0.0013122558593750, +0.0018310546875000, -0.0014343261718750, 0.0025634765625000, -0.0011901855468750, +0.0027160644531250, -0.0008850097656250, 0.0028686523437500, -0.0009155273437500, +0.0033874511718750, -0.0008239746093750, 0.0034484863281250, -0.0006408691406250, +0.0033569335937500, -0.0008850097656250, 0.0036010742187500, -0.0009765625000000, +0.0034484863281250, -0.0007934570312500, 0.0032348632812500, -0.0010681152343750, +0.0036010742187500, -0.0012512207031250, 0.0031433105468750, -0.0011291503906250, +0.0032958984375000, -0.0010375976562500, 0.0034179687500000, -0.0012207031250000, +0.0032043457031250, -0.0010375976562500, 0.0034179687500000, -0.0006408691406250, +0.0036926269531250, -0.0007324218750000, 0.0037841796875000, -0.0005187988281250, +0.0039062500000000, -0.0001525878906250, 0.0042724609375000, -0.0004882812500000, +0.0043945312500000, 0.0003051757812500, 0.0037536621093750, -0.0001220703125000, +0.0042724609375000, 0.0002441406250000, 0.0038452148437500, 0.0008239746093750, +0.0030517578125000, -0.0002441406250000, 0.0037841796875000, 0.0013427734375000, +0.0024414062500000, 0.0002746582031250, 0.0026245117187500, 0.0002746582031250, +0.0024414062500000, 0.0013122558593750, 0.0017395019531250, -0.0002136230468750, +0.0023803710937500, 0.0014953613281250, 0.0018005371093750, 0.0010986328125000, +0.0019226074218750, 0.0014953613281250, 0.0021057128906250, 0.0029602050781250, +0.0018310546875000, 0.0022277832031250, 0.0020751953125000, 0.0039978027343750, +0.0020446777343750, 0.0037841796875000, 0.0017089843750000, 0.0045471191406250, +0.0015258789062500, 0.0057373046875000, 0.0015563964843750, 0.0047607421875000, +0.0013732910156250, 0.0071411132812500, 0.0010986328125000, 0.0062866210937500, +0.0008544921875000, 0.0065917968750000, 0.0013732910156250, 0.0081787109375000, +0.0013732910156250, 0.0066223144531250, 0.0007019042968750, 0.0079956054687500, +0.0031738281250000, 0.0079040527343750, 0.0023193359375000, 0.0073242187500000, +0.0028381347656250, 0.0077209472656250, 0.0048828125000000, 0.0075683593750000, +0.0036315917968750, 0.0067138671875000, 0.0047302246093750, 0.0070495605468750, +0.0047912597656250, 0.0068054199218750, 0.0046997070312500, 0.0054931640625000, +0.0055541992187500, 0.0042724609375000, 0.0034179687500000, 0.0025939941406250, +0.0050964355468750, 0.0022888183593750, 0.0043945312500000, 0.0025634765625000, +0.0049438476562500, 0.0022277832031250, 0.0054626464843750, 0.0015563964843750, +0.0045471191406250, 0.0028076171875000, 0.0066223144531250, 0.0024108886718750, +0.0061035156250000, 0.0021057128906250, 0.0061950683593750, 0.0027465820312500, +0.0078430175781250, 0.0021972656250000, 0.0071411132812500, 0.0016784667968750, +0.0070190429687500, 0.0013732910156250, 0.0075073242187500, 0.0012207031250000, +0.0068054199218750, 0.0007324218750000, 0.0060119628906250, 0.0003356933593750, +0.0064392089843750, 0.0014343261718750, 0.0053100585937500, 0.0009460449218750, +0.0052795410156250, 0.0012817382812500, 0.0047912597656250, 0.0025939941406250, +0.0040283203125000, 0.0020751953125000, 0.0044555664062500, 0.0018005371093750, +0.0026245117187500, 0.0026855468750000, 0.0027770996093750, 0.0018615722656250, +0.0022888183593750, 0.0006713867187500, 0.0007629394531250, 0.0017395019531250, +0.0012817382812500, 0.0003662109375000, 0.0008850097656250, 0.0003356933593750, +0.0003662109375000, 0.0009155273437500, 0.0007934570312500, 0.0005493164062500, +0.0011901855468750, 0.0005493164062500, 0.0005798339843750, 0.0018005371093750, +0.0009765625000000, 0.0014648437500000, 0.0010681152343750, 0.0017700195312500, +0.0007019042968750, 0.0027770996093750, 0.0004577636718750, 0.0021667480468750, +0.0005798339843750}, +{0.0020446777343750, -0.0011596679687500, 0.0009765625000000, -0.0008850097656250, +0.0027160644531250, -0.0011291503906250, 0.0023803710937500, -0.0006408691406250, +0.0023193359375000, -0.0000915527343750, 0.0032043457031250, -0.0005798339843750, +0.0024414062500000, 0.0005187988281250, 0.0028991699218750, 0.0001220703125000, +0.0026855468750000, 0.0003662109375000, 0.0027770996093750, 0.0010070800781250, +0.0029907226562500, 0.0001525878906250, 0.0023193359375000, 0.0014343261718750, +0.0036315917968750, 0.0006103515625000, 0.0032043457031250, 0.0007629394531250, +0.0033569335937500, 0.0016174316406250, 0.0043029785156250, 0.0001220703125000, +0.0037231445312500, 0.0016784667968750, 0.0043945312500000, 0.0010070800781250, +0.0042724609375000, 0.0010070800781250, 0.0040893554687500, 0.0021667480468750, +0.0045166015625000, 0.0014953613281250, 0.0044555664062500, 0.0025634765625000, +0.0038146972656250, 0.0026855468750000, 0.0043029785156250, 0.0031738281250000, +0.0037841796875000, 0.0038452148437500, 0.0030212402343750, 0.0035095214843750, +0.0037536621093750, 0.0053405761718750, 0.0025024414062500, 0.0046386718750000, +0.0025329589843750, 0.0052490234375000, 0.0028076171875000, 0.0065307617187500, +0.0022888183593750, 0.0049743652343750, 0.0021972656250000, 0.0068359375000000, +0.0024414062500000, 0.0062866210937500, 0.0025024414062500, 0.0058898925781250, +0.0020446777343750, 0.0069885253906250, 0.0019836425781250, 0.0062561035156250, +0.0024719238281250, 0.0063781738281250, 0.0012207031250000, 0.0068969726562500, +0.0010986328125000, 0.0063476562500000, 0.0016479492187500, 0.0061035156250000, +0.0010986328125000, 0.0069885253906250, 0.0006408691406250, 0.0050964355468750, +0.0028991699218750, 0.0057067871093750, 0.0021667480468750, 0.0054931640625000, +0.0022888183593750, 0.0029907226562500, 0.0050354003906250, 0.0011596679687500, +0.0014953613281250, 0.0031127929687500, 0.0028991699218750, 0.0018310546875000, +0.0021362304687500, 0.0019531250000000, 0.0028076171875000, 0.0027770996093750, +0.0038757324218750, 0.0018310546875000, 0.0032958984375000, 0.0017700195312500, +0.0040283203125000, 0.0014038085937500, 0.0036315917968750, 0.0012512207031250, +0.0039367675781250, 0.0010070800781250, 0.0044860839843750, 0.0002746582031250, +0.0037231445312500, 0.0014953613281250, 0.0052185058593750, 0.0009460449218750, +0.0052185058593750, 0.0009765625000000, 0.0051574707031250, 0.0021057128906250, +0.0061035156250000, 0.0016784667968750, 0.0060729980468750, 0.0013732910156250, +0.0056457519531250, 0.0021667480468750, 0.0057983398437500, 0.0014038085937500, +0.0055541992187500, 0.0003662109375000, 0.0050048828125000, 0.0013427734375000, +0.0050659179687500, 0.0001525878906250, 0.0047302246093750, -0.0001831054687500, +0.0046691894531250, 0.0005187988281250, 0.0040893554687500, 0.0006713867187500, +0.0036621093750000, 0.0007019042968750, 0.0037536621093750, 0.0014953613281250, +0.0019836425781250, 0.0018920898437500, 0.0021362304687500, 0.0018005371093750, +0.0016784667968750, 0.0020751953125000, 0.0002746582031250, 0.0025024414062500, +0.0007019042968750, 0.0014648437500000, 0.0005798339843750, 0.0020446777343750, +0.0000610351562500, 0.0019836425781250, 0.0003967285156250, 0.0010986328125000, +0.0008850097656250, 0.0018615722656250, 0.0005187988281250, 0.0018310546875000, +0.0006713867187500, 0.0017089843750000, 0.0008239746093750, 0.0020751953125000, +0.0006408691406250, 0.0024108886718750, 0.0003967285156250, 0.0023193359375000, +0.0003356933593750, 0.0024414062500000, 0.0003662109375000, 0.0027465820312500, +-0.0000610351562500, 0.0024414062500000, -0.0002441406250000, 0.0023803710937500, +-0.0002136230468750, 0.0028686523437500, -0.0007934570312500, 0.0017395019531250, +-0.0009765625000000, 0.0023193359375000, -0.0013427734375000, 0.0021667480468750, +-0.0015258789062500, 0.0011901855468750, -0.0017395019531250, 0.0019226074218750, +-0.0022277832031250, 0.0016479492187500, -0.0015869140625000, 0.0014953613281250, +-0.0019531250000000, 0.0019226074218750, -0.0018920898437500, 0.0019836425781250, +-0.0013122558593750, 0.0016479492187500, -0.0016174316406250, 0.0022888183593750, +-0.0013427734375000, 0.0017089843750000, -0.0014953613281250, 0.0017395019531250, +-0.0013732910156250, 0.0021362304687500, -0.0011291503906250, 0.0010681152343750, +-0.0015563964843750, 0.0017700195312500, -0.0008544921875000, 0.0013122558593750, +-0.0010681152343750, 0.0007629394531250, -0.0010070800781250, 0.0009765625000000, +-0.0004577636718750, 0.0005493164062500, -0.0008850097656250, -0.0001525878906250, +-0.0003967285156250, -0.0000915527343750, -0.0007324218750000, -0.0006103515625000, +-0.0005187988281250, -0.0012817382812500, -0.0000305175781250, -0.0009460449218750, +-0.0005493164062500, -0.0018310546875000, 0.0003967285156250, -0.0015869140625000, +0.0002136230468750, -0.0018310546875000, 0.0002441406250000, -0.0023498535156250, +0.0007629394531250, -0.0016784667968750, 0.0004272460937500, -0.0024414062500000, +0.0009765625000000, -0.0021057128906250, 0.0008544921875000, -0.0018310546875000, +0.0009155273437500, -0.0020141601562500, 0.0012512207031250, -0.0015563964843750, +0.0009460449218750, -0.0014648437500000, 0.0011596679687500, -0.0013732910156250, +0.0010375976562500, -0.0010070800781250, 0.0007934570312500, -0.0008239746093750, +0.0007324218750000, -0.0007934570312500, 0.0005798339843750, -0.0003967285156250, +0.0003967285156250, -0.0003051757812500, 0.0003356933593750, -0.0001831054687500, +0.0001525878906250, 0.0001831054687500, -0.0000305175781250, 0.0002136230468750, +0.0001525878906250, 0.0002136230468750, -0.0003051757812500, 0.0005493164062500, +-0.0001525878906250, 0.0005493164062500, -0.0001831054687500, 0.0005187988281250, +-0.0004272460937500, 0.0009460449218750, -0.0001525878906250, 0.0003356933593750, +-0.0003051757812500, 0.0008850097656250, -0.0001831054687500, 0.0007324218750000, +-0.0001831054687500, 0.0003051757812500, -0.0002746582031250, 0.0010681152343750, +-0.0001525878906250, 0.0000610351562500, -0.0000610351562500, 0.0005187988281250, +-0.0001220703125000, 0.0005187988281250, 0.0000000000000000, -0.0002136230468750, +0.0001525878906250, 0.0004272460937500, 0.0000915527343750, -0.0003356933593750, +0.0001525878906250, -0.0002441406250000, 0.0002746582031250, -0.0001525878906250, +0.0002136230468750, -0.0006103515625000, 0.0002136230468750, -0.0004577636718750, +0.0001831054687500, -0.0003967285156250, 0.0002136230468750, -0.0006713867187500, +0.0001525878906250, -0.0005493164062500, 0.0001220703125000, -0.0004882812500000, +0.0001831054687500, -0.0008850097656250, 0.0000610351562500, -0.0002441406250000, +-0.0000305175781250, -0.0006713867187500, 0.0000610351562500, -0.0004577636718750, +-0.0001831054687500, 0.0000000000000000, -0.0003662109375000, -0.0009460449218750, +-0.0000610351562500, 0.0004272460937500, -0.0007629394531250, -0.0002746582031250, +-0.0003662109375000, -0.0002136230468750, -0.0005187988281250, 0.0007629394531250, +-0.0008544921875000, -0.0002136230468750, -0.0000305175781250, 0.0008239746093750, +-0.0007629394531250, 0.0007019042968750, -0.0001525878906250, 0.0005798339843750, +-0.0002746582031250, 0.0010375976562500, -0.0007934570312500, 0.0006713867187500, +0.0003356933593750, 0.0007324218750000, -0.0010070800781250, 0.0008850097656250, +-0.0005187988281250, 0.0007019042968750, -0.0003662109375000, 0.0006103515625000, +-0.0012512207031250, 0.0009765625000000, -0.0007934570312500, 0.0005798339843750, +-0.0009765625000000, 0.0008544921875000, -0.0013732910156250, 0.0010375976562500, +-0.0011291503906250, 0.0009155273437500, -0.0009765625000000, 0.0013122558593750, +-0.0014953613281250, 0.0012817382812500, -0.0006713867187500, 0.0015869140625000, +-0.0008239746093750, 0.0016174316406250, -0.0006408691406250, 0.0015563964843750, +0.0001220703125000, 0.0021362304687500, 0.0000610351562500, 0.0016174316406250, +0.0005493164062500, 0.0019836425781250, 0.0009765625000000, 0.0021972656250000, +0.0008850097656250, 0.0018615722656250, 0.0008544921875000, 0.0021972656250000, +0.0013427734375000, 0.0021972656250000, 0.0005187988281250, 0.0019836425781250, +0.0007019042968750, 0.0023803710937500, 0.0008544921875000, 0.0025939941406250, +0.0003356933593750, 0.0021057128906250, 0.0004272460937500, 0.0034179687500000, +0.0006103515625000, 0.0029602050781250, 0.0003967285156250, 0.0027465820312500, +0.0003967285156250, 0.0036315917968750, 0.0006408691406250, 0.0031738281250000, +0.0004882812500000, 0.0025634765625000, 0.0005187988281250, 0.0029907226562500, +0.0005187988281250, 0.0025329589843750, 0.0007324218750000, 0.0018005371093750, +0.0010070800781250, 0.0026550292968750, 0.0008850097656250, 0.0017089843750000, +0.0013122558593750, 0.0022277832031250, 0.0013732910156250, 0.0023193359375000, +0.0016479492187500, 0.0017700195312500, 0.0019531250000000, 0.0023193359375000, +0.0018310546875000, 0.0013122558593750, 0.0025939941406250, 0.0016784667968750, +0.0025329589843750, 0.0012817382812500, 0.0027160644531250, 0.0001220703125000, +0.0033874511718750, 0.0008850097656250, 0.0033264160156250, 0.0001220703125000, +0.0034484863281250, -0.0001831054687500, 0.0041198730468750, 0.0004272460937500, +0.0038146972656250, 0.0010070800781250, 0.0031738281250000, 0.0017700195312500, +0.0033874511718750, 0.0034790039062500, 0.0020751953125000, 0.0027465820312500, +0.0027160644531250, 0.0028686523437500, 0.0025634765625000, 0.0038757324218750, +0.0016479492187500, 0.0031127929687500, 0.0025329589843750, 0.0039062500000000, +0.0011291503906250, 0.0035095214843750, 0.0015869140625000, 0.0035095214843750, +0.0012817382812500, 0.0040588378906250, 0.0002746582031250, 0.0033569335937500, +0.0011596679687500, 0.0039672851562500, 0.0002441406250000, 0.0036621093750000, +0.0004577636718750, 0.0033264160156250, 0.0007324218750000, 0.0032653808593750, +0.0005187988281250, 0.0026245117187500, 0.0010070800781250, 0.0023193359375000, +0.0004272460937500, 0.0021972656250000, 0.0007019042968750, 0.0015563964843750, +0.0006408691406250, 0.0012512207031250, 0.0000915527343750, 0.0014343261718750, +0.0004882812500000, 0.0003662109375000, 0.0002441406250000, 0.0007629394531250, +0.0000000000000000, 0.0004882812500000, 0.0002136230468750, -0.0003662109375000, +0.0003356933593750, 0.0003662109375000, 0.0000915527343750, -0.0001220703125000, +0.0007934570312500, -0.0002441406250000, 0.0007324218750000, 0.0000000000000000, +0.0007629394531250, 0.0001220703125000, 0.0011291503906250, 0.0002441406250000, +0.0008544921875000, 0.0003662109375000, 0.0008850097656250, 0.0006713867187500, +0.0006103515625000, 0.0006103515625000, 0.0006713867187500, 0.0005798339843750, +0.0006713867187500, 0.0010681152343750, 0.0002441406250000, 0.0005493164062500, +0.0009460449218750, 0.0009155273437500, 0.0004882812500000, 0.0007629394531250, +0.0005493164062500, 0.0002441406250000, 0.0011901855468750, 0.0007934570312500, +0.0006408691406250, -0.0000915527343750, 0.0008544921875000, 0.0000610351562500, +0.0009155273437500, -0.0001525878906250, 0.0006713867187500, -0.0008850097656250, +0.0005187988281250, -0.0007019042968750, 0.0005798339843750, -0.0009155273437500, +0.0003356933593750, -0.0014343261718750, 0.0000915527343750, -0.0011596679687500, +0.0004272460937500, -0.0009765625000000, 0.0005493164062500, -0.0015563964843750, +0.0002441406250000, -0.0009155273437500, 0.0012207031250000, -0.0010375976562500, +0.0009460449218750}, +{0.0007324218750000, 0.0025024414062500, 0.0007629394531250, 0.0025939941406250, +0.0007934570312500, 0.0022888183593750, 0.0005493164062500, 0.0022277832031250, +0.0007019042968750, 0.0020751953125000, 0.0004882812500000, 0.0014648437500000, +0.0005798339843750, 0.0017395019531250, 0.0005798339843750, 0.0018005371093750, +0.0004272460937500, 0.0007629394531250, 0.0006408691406250, 0.0020751953125000, +0.0010070800781250, 0.0014343261718750, 0.0009765625000000, 0.0013122558593750, +0.0011901855468750, 0.0024108886718750, 0.0013732910156250, 0.0018920898437500, +0.0012207031250000, 0.0023498535156250, 0.0019836425781250, 0.0027160644531250, +0.0017700195312500, 0.0028381347656250, 0.0021667480468750, 0.0031127929687500, +0.0029296875000000, 0.0035095214843750, 0.0022888183593750, 0.0034484863281250, +0.0029602050781250, 0.0039367675781250, 0.0033874511718750, 0.0036926269531250, +0.0030212402343750, 0.0035400390625000, 0.0032043457031250, 0.0043945312500000, +0.0039978027343750, 0.0025634765625000, 0.0027160644531250, 0.0033874511718750, +0.0036621093750000, 0.0032043457031250, 0.0036621093750000, 0.0013122558593750, +0.0021972656250000, 0.0019226074218750, 0.0025634765625000, 0.0015563964843750, +0.0021057128906250, 0.0013732910156250, 0.0023193359375000, 0.0018005371093750, +0.0021362304687500, 0.0019226074218750, 0.0016479492187500, 0.0016784667968750, +0.0019836425781250, 0.0023803710937500, 0.0011901855468750, 0.0023193359375000, +0.0011291503906250, 0.0023193359375000, 0.0011596679687500, 0.0025024414062500, +0.0008850097656250, 0.0023498535156250, 0.0011901855468750, 0.0029296875000000, +0.0010375976562500, 0.0024719238281250, 0.0010986328125000, 0.0029296875000000, +0.0009765625000000, 0.0036621093750000, 0.0005798339843750, 0.0028076171875000, +0.0004577636718750, 0.0039062500000000, 0.0005187988281250, 0.0036010742187500, +0.0001220703125000, 0.0031738281250000, 0.0003051757812500, 0.0034790039062500, +0.0005493164062500, 0.0028686523437500, 0.0000610351562500, 0.0025939941406250, +0.0008239746093750, 0.0025329589843750, 0.0006713867187500, 0.0019531250000000, +0.0005798339843750, 0.0015258789062500, 0.0010681152343750, 0.0017700195312500, +0.0008544921875000, 0.0004577636718750, 0.0008544921875000, 0.0007324218750000, +0.0007629394531250, 0.0005187988281250, 0.0008850097656250, -0.0004882812500000, +0.0007629394531250, -0.0001525878906250, 0.0003967285156250, -0.0003967285156250, +0.0011901855468750, -0.0005798339843750, 0.0004882812500000, -0.0002746582031250, +0.0006408691406250, -0.0000610351562500, 0.0013122558593750, -0.0001831054687500, +0.0003967285156250, 0.0003356933593750, 0.0010375976562500, 0.0004272460937500, +0.0007324218750000, 0.0003967285156250, 0.0005187988281250, 0.0007019042968750, +0.0007019042968750, 0.0008239746093750, 0.0001831054687500, 0.0004272460937500, +0.0005493164062500, 0.0006713867187500, 0.0001220703125000, 0.0004882812500000, +0.0004272460937500, 0.0000610351562500, 0.0009460449218750, 0.0003662109375000, +0.0002136230468750, -0.0003356933593750, 0.0014038085937500, -0.0004577636718750, +0.0010375976562500, -0.0004577636718750, 0.0011291503906250, -0.0009460449218750, +0.0018615722656250, -0.0010375976562500, 0.0012207031250000, -0.0008544921875000, +0.0015869140625000, -0.0014343261718750, 0.0015258789062500, -0.0011596679687500, +0.0012207031250000, -0.0007019042968750, 0.0012207031250000, -0.0014648437500000, +0.0010986328125000, -0.0005798339843750, 0.0007629394531250, -0.0006713867187500, +0.0007934570312500, -0.0008544921875000, 0.0006103515625000, -0.0003662109375000, +0.0003967285156250, -0.0004577636718750, 0.0006408691406250, -0.0006408691406250, +0.0000610351562500, -0.0006103515625000, 0.0003967285156250, -0.0005493164062500, +0.0003051757812500, -0.0007019042968750, 0.0000000000000000, -0.0006713867187500, +0.0005798339843750, -0.0004272460937500, -0.0002136230468750, -0.0005798339843750, +0.0002746582031250, -0.0004272460937500, 0.0002746582031250, -0.0001525878906250, +-0.0002746582031250, -0.0003051757812500, 0.0004882812500000, 0.0000305175781250, +0.0000305175781250, 0.0000610351562500, 0.0002441406250000, 0.0001525878906250, +0.0004272460937500, 0.0004272460937500, 0.0002136230468750, 0.0004577636718750, +0.0003967285156250, 0.0006103515625000, 0.0004882812500000, 0.0006408691406250, +0.0002136230468750, 0.0006713867187500, 0.0003051757812500, 0.0008544921875000, +0.0004577636718750, 0.0009155273437500, 0.0001220703125000, 0.0006408691406250, +0.0003051757812500, 0.0010986328125000, 0.0001525878906250, 0.0008544921875000, +-0.0000610351562500, 0.0005493164062500, -0.0000610351562500, 0.0013122558593750, +-0.0002441406250000, 0.0001831054687500, -0.0004272460937500, 0.0007934570312500, +-0.0007019042968750, 0.0007934570312500, -0.0007629394531250, -0.0000305175781250, +-0.0009155273437500, 0.0008850097656250, -0.0012207031250000, 0.0000305175781250, +-0.0010681152343750, 0.0002746582031250, -0.0014038085937500, 0.0004577636718750, +-0.0013122558593750, 0.0000000000000000, -0.0011901855468750, 0.0003662109375000, +-0.0017395019531250, 0.0002441406250000, -0.0010986328125000, 0.0002441406250000, +-0.0015869140625000, 0.0003051757812500, -0.0015258789062500, 0.0003356933593750, +-0.0010375976562500, 0.0003967285156250, -0.0018615722656250, 0.0002746582031250, +-0.0009460449218750, 0.0003662109375000, -0.0013427734375000, 0.0002441406250000, +-0.0013427734375000, 0.0000610351562500, -0.0007629394531250, 0.0002746582031250, +-0.0013427734375000, -0.0002441406250000, -0.0007324218750000, 0.0000305175781250, +-0.0007934570312500, -0.0001831054687500, -0.0006713867187500, -0.0005493164062500, +-0.0001220703125000, 0.0000000000000000, -0.0003662109375000, -0.0007324218750000, +0.0002136230468750, -0.0005798339843750, 0.0001831054687500, -0.0003967285156250, +0.0003356933593750, -0.0007629394531250, 0.0007324218750000, -0.0004882812500000, +0.0006408691406250, -0.0003051757812500, 0.0008850097656250, -0.0004272460937500, +0.0009460449218750, -0.0001831054687500, 0.0009155273437500, -0.0000305175781250, +0.0009155273437500, -0.0003051757812500, 0.0007629394531250, 0.0001220703125000, +0.0005798339843750, -0.0001831054687500, 0.0005493164062500, -0.0004577636718750, +0.0004272460937500, -0.0003051757812500, 0.0001220703125000, -0.0007629394531250, +-0.0000305175781250, -0.0008850097656250, 0.0002136230468750, -0.0009765625000000, +-0.0001220703125000, -0.0009155273437500, 0.0001831054687500, -0.0009155273437500, +0.0006103515625000, -0.0009765625000000, 0.0001831054687500, -0.0002441406250000, +0.0010986328125000, -0.0003967285156250, 0.0009155273437500, -0.0000305175781250, +0.0010070800781250, 0.0006713867187500, 0.0016174316406250, 0.0003356933593750, +0.0012512207031250, 0.0010681152343750, 0.0015258789062500, 0.0008544921875000, +0.0015258789062500, 0.0013122558593750, 0.0012817382812500, 0.0018615722656250, +0.0012207031250000, 0.0011291503906250, 0.0013122558593750, 0.0023803710937500, +0.0008544921875000, 0.0018920898437500, 0.0009765625000000, 0.0017700195312500, +0.0010681152343750, 0.0024719238281250, 0.0008239746093750, 0.0017089843750000, +0.0009460449218750, 0.0018310546875000, 0.0012512207031250, 0.0019226074218750, +0.0013122558593750, 0.0015869140625000, 0.0013732910156250, 0.0016479492187500, +0.0016174316406250, 0.0019836425781250, 0.0017395019531250, 0.0017700195312500, +0.0014038085937500, 0.0020751953125000, 0.0016784667968750, 0.0023803710937500, +0.0015563964843750, 0.0023193359375000, 0.0011596679687500, 0.0025329589843750, +0.0012817382812500, 0.0030212402343750, 0.0009460449218750, 0.0027160644531250, +0.0008239746093750, 0.0027465820312500, 0.0007629394531250, 0.0029296875000000, +0.0006408691406250, 0.0022888183593750, 0.0007324218750000, 0.0028381347656250, +0.0010375976562500, 0.0026855468750000, 0.0007934570312500, 0.0023803710937500, +0.0011596679687500, 0.0029296875000000, 0.0017700195312500, 0.0031127929687500, +0.0014953613281250, 0.0019531250000000, 0.0018005371093750, 0.0031127929687500, +0.0021972656250000, 0.0024414062500000, 0.0018615722656250, 0.0010681152343750, +0.0014953613281250, 0.0027465820312500, 0.0018615722656250, 0.0007019042968750, +0.0013122558593750, 0.0006713867187500, 0.0010986328125000, 0.0013122558593750, +0.0017089843750000, 0.0004272460937500, 0.0020751953125000, 0.0001831054687500, +0.0018310546875000, 0.0013122558593750, 0.0027160644531250, 0.0005798339843750, +0.0032043457031250, 0.0004882812500000, 0.0028381347656250, 0.0019836425781250, +0.0025634765625000, -0.0009460449218750, 0.0000915527343750, 0.0009765625000000, +0.0011901855468750, -0.0000610351562500, 0.0017395019531250, 0.0003051757812500, +0.0014038085937500, 0.0013122558593750, 0.0015869140625000, 0.0005798339843750, +0.0025939941406250, 0.0009460449218750, 0.0013427734375000, 0.0009460449218750, +0.0020141601562500, 0.0006713867187500, 0.0024108886718750, 0.0005493164062500, +0.0019531250000000, 0.0005187988281250, 0.0028686523437500, 0.0011291503906250, +0.0026550292968750, 0.0008239746093750, 0.0031127929687500, 0.0014038085937500, +0.0031127929687500, 0.0022888183593750, 0.0026245117187500, 0.0018005371093750, +0.0030822753906250, 0.0025634765625000, 0.0024414062500000, 0.0026855468750000, +0.0021972656250000, 0.0021972656250000, 0.0025329589843750, 0.0021362304687500, +0.0024108886718750, 0.0022888183593750, 0.0021362304687500, 0.0017089843750000, +0.0031127929687500, 0.0013122558593750, 0.0028076171875000, 0.0017089843750000, +0.0028991699218750, 0.0018615722656250, 0.0035400390625000, 0.0011596679687500, +0.0030517578125000, 0.0024108886718750, 0.0033569335937500, 0.0019836425781250, +0.0031127929687500, 0.0019531250000000, 0.0030517578125000, 0.0026245117187500, +0.0031433105468750, 0.0020446777343750, 0.0026550292968750, 0.0021057128906250, +0.0029602050781250, 0.0022277832031250, 0.0029602050781250, 0.0017700195312500, +0.0025634765625000, 0.0013732910156250, 0.0023803710937500, 0.0015563964843750, +0.0023193359375000, 0.0011901855468750, 0.0014648437500000, 0.0009155273437500, +0.0014343261718750, 0.0010986328125000, 0.0011596679687500, 0.0012817382812500, +0.0006103515625000, 0.0011901855468750, 0.0008239746093750, 0.0014648437500000, +0.0004272460937500, 0.0015563964843750, 0.0005187988281250, 0.0017089843750000, +0.0005798339843750, 0.0017700195312500, 0.0003662109375000, 0.0016174316406250, +0.0005187988281250, 0.0015258789062500, 0.0005798339843750, 0.0015258789062500, +0.0000915527343750, 0.0012817382812500, 0.0003967285156250, 0.0008850097656250, +0.0005798339843750, 0.0007324218750000, -0.0002136230468750, 0.0004882812500000, +0.0006103515625000, 0.0000000000000000, 0.0001831054687500, 0.0000915527343750, +-0.0002441406250000, 0.0001831054687500, -0.0001220703125000, -0.0003356933593750, +-0.0006103515625000, 0.0004882812500000, -0.0009155273437500, 0.0001831054687500, +-0.0010375976562500, 0.0003356933593750, -0.0011596679687500, 0.0009765625000000, +-0.0012512207031250, 0.0005187988281250, -0.0011596679687500, 0.0013122558593750, +-0.0011901855468750, 0.0012207031250000, -0.0011901855468750, 0.0011596679687500, +-0.0010986328125000, 0.0016784667968750, -0.0011291503906250, 0.0013732910156250, +-0.0011291503906250, 0.0012207031250000, -0.0007934570312500, 0.0013732910156250, +-0.0009460449218750, 0.0009765625000000, -0.0007629394531250, 0.0004882812500000, +-0.0003967285156250}, +{0.0017700195312500, -0.0008544921875000, 0.0012512207031250, 0.0002136230468750, +0.0018920898437500, 0.0000000000000000, 0.0007324218750000, -0.0006713867187500, +0.0014648437500000, -0.0003356933593750, 0.0008544921875000, -0.0001220703125000, +-0.0003662109375000, -0.0009155273437500, 0.0009155273437500, -0.0001525878906250, +-0.0003967285156250, -0.0006713867187500, -0.0005798339843750, -0.0007324218750000, +0.0001525878906250, 0.0004272460937500, 0.0001831054687500, -0.0007629394531250, +0.0007324218750000, -0.0008544921875000, -0.0017089843750000, -0.0006103515625000, +-0.0010375976562500, -0.0007934570312500, -0.0006408691406250, -0.0010986328125000, +-0.0008544921875000, -0.0008239746093750, -0.0004272460937500, -0.0001525878906250, +-0.0001525878906250, -0.0003662109375000, 0.0003356933593750, 0.0003967285156250, +0.0003662109375000, 0.0015563964843750, 0.0003662109375000, 0.0012512207031250, +0.0008544921875000, 0.0018920898437500, 0.0007324218750000, 0.0025939941406250, +0.0009765625000000, 0.0021667480468750, 0.0015258789062500, 0.0016174316406250, +0.0018310546875000, 0.0021667480468750, 0.0020446777343750, 0.0013732910156250, +0.0024414062500000, 0.0010986328125000, 0.0029602050781250, 0.0016174316406250, +0.0025634765625000, 0.0016174316406250, 0.0023803710937500, 0.0012512207031250, +0.0030517578125000, 0.0023498535156250, 0.0019531250000000, 0.0023498535156250, +0.0021362304687500, 0.0021057128906250, 0.0025939941406250, 0.0023803710937500, +0.0021057128906250, 0.0023498535156250, 0.0020446777343750, 0.0018615722656250, +0.0028991699218750, 0.0015869140625000, 0.0026855468750000, 0.0014953613281250, +0.0026245117187500, 0.0010681152343750, 0.0030212402343750, 0.0006103515625000, +0.0026855468750000, 0.0012207031250000, 0.0026855468750000, 0.0004882812500000, +0.0023498535156250, 0.0007934570312500, 0.0024414062500000, 0.0015563964843750, +0.0025939941406250, 0.0005493164062500, 0.0020446777343750, 0.0012512207031250, +0.0025329589843750, 0.0013122558593750, 0.0025024414062500, 0.0007629394531250, +0.0021362304687500, 0.0007019042968750, 0.0022583007812500, 0.0005798339843750, +0.0021362304687500, 0.0000305175781250, 0.0015563964843750, -0.0000305175781250, +0.0016784667968750, -0.0001220703125000, 0.0014343261718750, -0.0005187988281250, +0.0010070800781250, -0.0004577636718750, 0.0013732910156250, -0.0002441406250000, +0.0008544921875000, -0.0006713867187500, 0.0010375976562500, -0.0002746582031250, +0.0010681152343750, 0.0002136230468750, 0.0005493164062500, -0.0003967285156250, +0.0007324218750000, 0.0005493164062500, 0.0006408691406250, 0.0005493164062500, +0.0001525878906250, 0.0004882812500000, 0.0003051757812500, 0.0008544921875000, +0.0004272460937500, 0.0007324218750000, -0.0001831054687500, 0.0006408691406250, +0.0002136230468750, 0.0004882812500000, -0.0000610351562500, 0.0004272460937500, +-0.0004882812500000, 0.0002746582031250, -0.0003967285156250, -0.0001220703125000, +-0.0006103515625000, -0.0003051757812500, -0.0009460449218750, -0.0007019042968750, +-0.0008850097656250, -0.0009155273437500, -0.0009155273437500, -0.0010986328125000, +-0.0010986328125000, -0.0016174316406250, -0.0009155273437500, -0.0012512207031250, +-0.0010986328125000, -0.0018310546875000, -0.0010375976562500, -0.0016174316406250, +-0.0010681152343750, -0.0011291503906250, -0.0011901855468750, -0.0017089843750000, +-0.0010681152343750, -0.0005798339843750, -0.0008544921875000, -0.0007629394531250, +-0.0010375976562500, -0.0004577636718750, -0.0008850097656250, 0.0004272460937500, +-0.0006408691406250, -0.0000305175781250, -0.0009460449218750, 0.0009460449218750, +-0.0007019042968750, 0.0009155273437500, -0.0007019042968750, 0.0010375976562500, +-0.0007324218750000, 0.0016174316406250, -0.0005798339843750, 0.0014038085937500, +-0.0005493164062500, 0.0018005371093750, -0.0004577636718750, 0.0019531250000000, +-0.0003356933593750, 0.0019531250000000, -0.0003051757812500, 0.0021362304687500, +-0.0003051757812500, 0.0022277832031250, -0.0000610351562500, 0.0020446777343750, +-0.0001525878906250, 0.0021057128906250, -0.0000610351562500, 0.0020751953125000, +0.0001220703125000, 0.0017395019531250, 0.0002441406250000, 0.0016174316406250, +0.0003356933593750, 0.0016174316406250, 0.0004577636718750, 0.0013427734375000, +0.0006408691406250, 0.0013427734375000, 0.0006408691406250, 0.0013427734375000, +0.0006103515625000, 0.0009460449218750, 0.0010070800781250, 0.0012817382812500, +0.0005493164062500, 0.0009460449218750, 0.0008239746093750, 0.0009155273437500, +0.0008239746093750, 0.0010986328125000, 0.0005187988281250, 0.0006713867187500, +0.0008850097656250, 0.0009155273437500, 0.0007019042968750, 0.0009765625000000, +0.0008239746093750, 0.0007324218750000, 0.0008544921875000, 0.0008544921875000, +0.0007934570312500, 0.0011291503906250, 0.0010070800781250, 0.0005493164062500, +0.0008239746093750, 0.0011596679687500, 0.0008239746093750, 0.0009460449218750, +0.0008544921875000, 0.0004272460937500, 0.0006713867187500, 0.0013122558593750, +0.0007324218750000, 0.0001525878906250, 0.0004882812500000, 0.0007019042968750, +0.0004882812500000, 0.0005493164062500, 0.0003662109375000, -0.0001525878906250, +0.0001831054687500, 0.0007629394531250, 0.0001220703125000, -0.0004577636718750, +0.0001525878906250, 0.0000000000000000, 0.0000915527343750, -0.0001220703125000, +0.0000915527343750, -0.0009460449218750, 0.0002136230468750, -0.0001831054687500, +0.0001525878906250, -0.0011596679687500, -0.0001525878906250, -0.0008239746093750, +0.0000305175781250, -0.0007934570312500, -0.0001220703125000, -0.0013732910156250, +-0.0005493164062500, -0.0007324218750000, -0.0004577636718750, -0.0012207031250000, +-0.0006103515625000, -0.0012207031250000, -0.0009460449218750, -0.0009765625000000, +-0.0007934570312500, -0.0010986328125000, -0.0007019042968750, -0.0011291503906250, +-0.0010681152343750, -0.0007629394531250, -0.0004882812500000, -0.0007934570312500, +-0.0004577636718750, -0.0007934570312500, -0.0003662109375000, -0.0005798339843750, +0.0001831054687500, -0.0005187988281250, 0.0003051757812500, -0.0007934570312500, +0.0004577636718750, -0.0004272460937500, 0.0009765625000000, -0.0007629394531250, +0.0011291503906250, -0.0011901855468750, 0.0011291503906250, -0.0004882812500000, +0.0014648437500000, -0.0014953613281250, 0.0011596679687500, -0.0011291503906250, +0.0011901855468750, -0.0010681152343750, 0.0011291503906250, -0.0016174316406250, +0.0007324218750000, -0.0010070800781250, 0.0006103515625000, -0.0012817382812500, +0.0007629394531250, -0.0010986328125000, 0.0001220703125000, -0.0009155273437500, +0.0002746582031250, -0.0010375976562500, 0.0005493164062500, -0.0008239746093750, +-0.0002136230468750, -0.0009460449218750, 0.0005798339843750, -0.0010070800781250, +0.0001831054687500, -0.0006103515625000, 0.0002441406250000, -0.0006103515625000, +0.0008239746093750, -0.0010375976562500, 0.0004272460937500, -0.0005187988281250, +0.0012207031250000, -0.0011291503906250, 0.0010986328125000, -0.0007324218750000, +0.0011291503906250, -0.0001525878906250, 0.0015869140625000, -0.0013122558593750, +0.0013427734375000, 0.0006103515625000, 0.0018920898437500, 0.0000000000000000, +0.0018005371093750, 0.0001831054687500, 0.0019226074218750, 0.0017395019531250, +0.0023803710937500, 0.0008850097656250, 0.0021667480468750, 0.0013732910156250, +0.0021362304687500, 0.0020446777343750, 0.0025634765625000, 0.0016784667968750, +0.0025024414062500, 0.0014953613281250, 0.0023498535156250, 0.0023193359375000, +0.0029907226562500, 0.0021057128906250, 0.0024414062500000, 0.0024414062500000, +0.0029602050781250, 0.0029907226562500, 0.0028991699218750, 0.0033264160156250, +0.0024414062500000, 0.0037231445312500, 0.0031127929687500, 0.0034790039062500, +0.0021972656250000, 0.0041198730468750, 0.0024414062500000, 0.0041503906250000, +0.0024108886718750, 0.0029296875000000, 0.0014648437500000, 0.0021667480468750, +0.0014038085937500, 0.0023803710937500, 0.0014343261718750, 0.0022583007812500, +0.0011291503906250, 0.0023193359375000, 0.0011901855468750, 0.0027160644531250, +0.0012817382812500, 0.0025024414062500, 0.0008544921875000, 0.0026245117187500, +0.0015258789062500, 0.0029602050781250, 0.0008239746093750, 0.0026245117187500, +0.0008850097656250, 0.0025634765625000, 0.0013732910156250, 0.0031127929687500, +0.0003356933593750, 0.0018920898437500, 0.0013427734375000, 0.0028076171875000, +0.0007629394531250, 0.0024414062500000, 0.0005187988281250, 0.0012817382812500, +0.0009765625000000, 0.0026550292968750, 0.0000915527343750, 0.0011596679687500, +0.0004577636718750, 0.0012512207031250, 0.0000305175781250, 0.0017700195312500, +0.0000000000000000, 0.0010375976562500, 0.0002746582031250, 0.0008544921875000, +-0.0004577636718750, 0.0020446777343750, 0.0005798339843750, 0.0011291503906250, +0.0000305175781250, 0.0014953613281250, 0.0000610351562500, 0.0025939941406250, +0.0008544921875000, 0.0012817382812500, 0.0001220703125000, 0.0021972656250000, +0.0006103515625000, 0.0020751953125000, 0.0004577636718750, 0.0016174316406250, +0.0003356933593750, 0.0018920898437500, 0.0004882812500000, 0.0015869140625000, +0.0001525878906250, 0.0013122558593750, 0.0007324218750000, 0.0012207031250000, +0.0005493164062500, 0.0010681152343750, 0.0006408691406250, 0.0008850097656250, +0.0011596679687500, 0.0007019042968750, 0.0008239746093750, 0.0004272460937500, +0.0012207031250000, 0.0002746582031250, 0.0009765625000000, 0.0001525878906250, +0.0009155273437500, 0.0000305175781250, 0.0010070800781250, -0.0000305175781250, +0.0004272460937500, 0.0000915527343750, 0.0007934570312500, 0.0001525878906250, +0.0000610351562500, 0.0001831054687500, 0.0000305175781250, 0.0004272460937500, +0.0003051757812500, 0.0006713867187500, -0.0007324218750000, 0.0004272460937500, +0.0000915527343750, 0.0008850097656250, -0.0004577636718750, 0.0007019042968750, +-0.0007324218750000, 0.0003967285156250, -0.0003356933593750, 0.0010681152343750, +-0.0010681152343750, 0.0001525878906250, -0.0010070800781250, 0.0004272460937500, +-0.0012207031250000, 0.0004272460937500, -0.0014953613281250, -0.0001220703125000, +-0.0015869140625000, 0.0002136230468750, -0.0018615722656250, 0.0000305175781250, +-0.0013732910156250, -0.0002746582031250, -0.0018005371093750, -0.0000610351562500, +-0.0014038085937500, -0.0000610351562500, -0.0007324218750000, -0.0003967285156250, +-0.0013427734375000, 0.0001831054687500, 0.0000305175781250, -0.0001220703125000, +-0.0001831054687500, -0.0000305175781250, 0.0001220703125000, 0.0005187988281250, +0.0010986328125000, 0.0001525878906250, 0.0004577636718750, 0.0004272460937500, +0.0013122558593750, 0.0003967285156250, 0.0010681152343750, 0.0002746582031250, +0.0007934570312500, 0.0002746582031250, 0.0010681152343750, 0.0000915527343750, +0.0007019042968750, 0.0000915527343750, 0.0004577636718750, -0.0001525878906250, +0.0004272460937500, -0.0001831054687500, 0.0000000000000000, -0.0000915527343750, +-0.0003051757812500, -0.0002746582031250, -0.0002746582031250, -0.0002441406250000, +-0.0008239746093750, -0.0000610351562500, -0.0006713867187500, -0.0000305175781250, +-0.0007324218750000, -0.0000305175781250, -0.0011901855468750, 0.0001220703125000, +-0.0008544921875000, 0.0003051757812500, -0.0011596679687500, 0.0003356933593750, +-0.0011901855468750, 0.0005798339843750, -0.0009460449218750, 0.0008544921875000, +-0.0009765625000000, 0.0007629394531250, -0.0010375976562500, 0.0011596679687500, +-0.0006713867187500}, +{-0.0000610351562500, 0.0023193359375000, 0.0010070800781250, 0.0021362304687500, +0.0002746582031250, 0.0024108886718750, 0.0002136230468750, 0.0028686523437500, +0.0007934570312500, 0.0026855468750000, -0.0003356933593750, 0.0028076171875000, +0.0004577636718750, 0.0031738281250000, -0.0003356933593750, 0.0027465820312500, +-0.0004272460937500, 0.0026245117187500, 0.0001220703125000, 0.0032958984375000, +-0.0010070800781250, 0.0019836425781250, 0.0003051757812500, 0.0028991699218750, +-0.0002441406250000, 0.0024108886718750, -0.0002136230468750, 0.0012207031250000, +0.0006103515625000, 0.0026245117187500, -0.0003051757812500, 0.0009460449218750, +0.0006408691406250, 0.0010070800781250, 0.0002746582031250, 0.0014648437500000, +0.0001831054687500, 0.0004882812500000, 0.0006103515625000, 0.0004272460937500, +-0.0000305175781250, 0.0013427734375000, 0.0006408691406250, 0.0005493164062500, +0.0003051757812500, 0.0007934570312500, 0.0003662109375000, 0.0016479492187500, +0.0009765625000000, 0.0007019042968750, 0.0004272460937500, 0.0015563964843750, +0.0007629394531250, 0.0013427734375000, 0.0008544921875000, 0.0011291503906250, +0.0005798339843750, 0.0014648437500000, 0.0004577636718750, 0.0010070800781250, +0.0004577636718750, 0.0012512207031250, 0.0001831054687500, 0.0011596679687500, +-0.0000915527343750, 0.0009765625000000, -0.0000610351562500, 0.0011291503906250, +-0.0002136230468750, 0.0010681152343750, -0.0006713867187500, 0.0008850097656250, +-0.0003967285156250, 0.0009765625000000, -0.0009155273437500, 0.0009765625000000, +-0.0011291503906250, 0.0008239746093750, -0.0010070800781250, 0.0009460449218750, +-0.0017089843750000, 0.0008850097656250, -0.0015563964843750, 0.0012207031250000, +-0.0019226074218750, 0.0011291503906250, -0.0021057128906250, 0.0011291503906250, +-0.0020141601562500, 0.0016479492187500, -0.0024108886718750, 0.0010070800781250, +-0.0017395019531250, 0.0016174316406250, -0.0020446777343750, 0.0014343261718750, +-0.0015258789062500, 0.0007019042968750, -0.0007324218750000, 0.0015869140625000, +-0.0012817382812500, 0.0004577636718750, 0.0002136230468750, 0.0005798339843750, +-0.0001525878906250, 0.0007324218750000, -0.0001220703125000, 0.0000610351562500, +0.0006103515625000, 0.0003356933593750, -0.0002441406250000, 0.0001831054687500, +0.0002746582031250, 0.0000305175781250, -0.0001220703125000, 0.0002136230468750, +-0.0004882812500000, 0.0003051757812500, -0.0004577636718750, 0.0001525878906250, +-0.0010681152343750, 0.0005187988281250, -0.0011901855468750, 0.0004272460937500, +-0.0014953613281250, 0.0005187988281250, -0.0016174316406250, 0.0008239746093750, +-0.0016479492187500, 0.0006408691406250, -0.0019531250000000, 0.0005187988281250, +-0.0016479492187500, 0.0006408691406250, -0.0017700195312500, 0.0004272460937500, +-0.0017700195312500, 0.0001831054687500, -0.0015563964843750, 0.0003356933593750, +-0.0016784667968750, 0.0001220703125000, -0.0013427734375000, 0.0003356933593750, +-0.0011291503906250, 0.0003051757812500, -0.0010375976562500, 0.0000915527343750, +-0.0009460449218750, 0.0002136230468750, -0.0009460449218750, 0.0002441406250000, +-0.0006713867187500, 0.0000610351562500, -0.0007629394531250, 0.0002136230468750, +-0.0006103515625000, 0.0003356933593750, -0.0003967285156250, 0.0000610351562500, +-0.0006408691406250, 0.0005493164062500, -0.0002746582031250, 0.0004272460937500, +-0.0003051757812500, 0.0003051757812500, -0.0003051757812500, 0.0005798339843750, +-0.0000610351562500, 0.0005187988281250, -0.0000915527343750, 0.0003051757812500, +-0.0000610351562500, 0.0005798339843750, 0.0001525878906250, 0.0002441406250000, +0.0001831054687500, -0.0000610351562500, 0.0002136230468750, 0.0004882812500000, +0.0004882812500000, -0.0004272460937500, 0.0004577636718750, -0.0001220703125000, +0.0007934570312500, -0.0002441406250000, 0.0008544921875000, -0.0008544921875000, +0.0008850097656250, -0.0002441406250000, 0.0012817382812500, -0.0007629394531250, +0.0010986328125000, -0.0007324218750000, 0.0012512207031250, -0.0004882812500000, +0.0013122558593750, -0.0007324218750000, 0.0011901855468750, -0.0006713867187500, +0.0013732910156250, -0.0003967285156250, 0.0011291503906250, -0.0007324218750000, +0.0011291503906250, -0.0004272460937500, 0.0011291503906250, -0.0000305175781250, +0.0008544921875000, -0.0005798339843750, 0.0007324218750000, 0.0003356933593750, +0.0009155273437500, 0.0000305175781250, 0.0004882812500000, -0.0000305175781250, +0.0007629394531250, 0.0004882812500000, 0.0010986328125000, 0.0000610351562500, +0.0004882812500000, 0.0002136230468750, 0.0015869140625000, 0.0002136230468750, +0.0011901855468750, 0.0001831054687500, 0.0014648437500000, 0.0002441406250000, +0.0024108886718750, 0.0003051757812500, 0.0017395019531250, 0.0005493164062500, +0.0027160644531250, 0.0005187988281250, 0.0026855468750000, 0.0007324218750000, +0.0026855468750000, 0.0009765625000000, 0.0031738281250000, 0.0009155273437500, +0.0029602050781250, 0.0014343261718750, 0.0029602050781250, 0.0011596679687500, +0.0030212402343750, 0.0014953613281250, 0.0026245117187500, 0.0019531250000000, +0.0024108886718750, 0.0011901855468750, 0.0026245117187500, 0.0020751953125000, +0.0020446777343750, 0.0015563964843750, 0.0021057128906250, 0.0013122558593750, +0.0020141601562500, 0.0015869140625000, 0.0017700195312500, 0.0007934570312500, +0.0020446777343750, 0.0012207031250000, 0.0017089843750000, 0.0007019042968750, +0.0019836425781250, 0.0005798339843750, 0.0018920898437500, 0.0010070800781250, +0.0016479492187500, 0.0004577636718750, 0.0020751953125000, 0.0010375976562500, +0.0007934570312500, 0.0009765625000000, 0.0014648437500000, 0.0010375976562500, +0.0007019042968750, 0.0014343261718750, -0.0007629394531250, 0.0012817382812500, +0.0004577636718750, 0.0019531250000000, -0.0014343261718750, 0.0017089843750000, +-0.0013732910156250, 0.0019531250000000, -0.0011901855468750, 0.0023803710937500, +-0.0020446777343750, 0.0017089843750000, -0.0016784667968750, 0.0020446777343750, +-0.0017089843750000, 0.0021057128906250, -0.0018920898437500, 0.0014038085937500, +-0.0017089843750000, 0.0014343261718750, -0.0015563964843750, 0.0019836425781250, +-0.0017089843750000, 0.0002441406250000, -0.0013122558593750, 0.0014343261718750, +-0.0012512207031250, 0.0008239746093750, -0.0011596679687500, -0.0007324218750000, +-0.0009155273437500, 0.0013122558593750, -0.0009765625000000, -0.0010681152343750, +-0.0011291503906250, -0.0002746582031250, -0.0012512207031250, -0.0002746582031250, +-0.0012207031250000, -0.0020141601562500, -0.0013427734375000, -0.0009765625000000, +-0.0013427734375000, -0.0016784667968750, -0.0004272460937500, -0.0026245117187500, +-0.0005493164062500, -0.0021667480468750, 0.0000000000000000, -0.0020751953125000, +0.0012817382812500, -0.0030822753906250, 0.0010986328125000, -0.0015869140625000, +0.0010986328125000, -0.0021057128906250, 0.0022277832031250, -0.0021362304687500, +0.0014953613281250, -0.0010986328125000, 0.0005493164062500, -0.0018310546875000, +0.0019226074218750, -0.0016174316406250, 0.0003967285156250, -0.0014953613281250, +0.0006408691406250, -0.0016174316406250, 0.0012512207031250, -0.0017089843750000, +0.0005798339843750, -0.0014953613281250, -0.0004577636718750, -0.0005187988281250, +-0.0011901855468750, -0.0003051757812500, -0.0013732910156250, -0.0007324218750000, +-0.0006103515625000, -0.0005798339843750, -0.0000915527343750, 0.0001220703125000, +-0.0006408691406250, -0.0008544921875000, -0.0000915527343750, -0.0004577636718750, +0.0001831054687500, -0.0000610351562500, -0.0004882812500000, -0.0004272460937500, +-0.0007019042968750, 0.0000610351562500, -0.0001831054687500, 0.0001220703125000, +-0.0012207031250000, 0.0006713867187500, -0.0009460449218750, 0.0003967285156250, +-0.0006408691406250, 0.0002746582031250, -0.0009765625000000, 0.0010986328125000, +-0.0004577636718750, -0.0003662109375000, -0.0005493164062500, 0.0001220703125000, +-0.0001525878906250, 0.0001831054687500, -0.0000610351562500, -0.0007324218750000, +-0.0003662109375000, -0.0001220703125000, -0.0000915527343750, -0.0000610351562500, +0.0001525878906250, -0.0001525878906250, -0.0001220703125000, -0.0001831054687500, +0.0002441406250000, -0.0000305175781250, 0.0008850097656250, -0.0000305175781250, +0.0007324218750000, -0.0007629394531250, 0.0013122558593750, -0.0005798339843750, +0.0019226074218750, -0.0009155273437500, 0.0018310546875000, -0.0016479492187500, +0.0018310546875000, -0.0013732910156250, 0.0023803710937500, -0.0017089843750000, +0.0021057128906250, -0.0019836425781250, 0.0024414062500000, -0.0014953613281250, +0.0028381347656250, -0.0011596679687500, 0.0028381347656250, -0.0015258789062500, +0.0029602050781250, -0.0001831054687500, 0.0031127929687500, -0.0002441406250000, +0.0029602050781250, -0.0002441406250000, 0.0028381347656250, 0.0004882812500000, +0.0027160644531250, 0.0003356933593750, 0.0024414062500000, 0.0000610351562500, +0.0024719238281250, 0.0002746582031250, 0.0020446777343750, -0.0000915527343750, +0.0019836425781250, -0.0006103515625000, 0.0021362304687500, -0.0004577636718750, +0.0018005371093750, -0.0012207031250000, 0.0018005371093750, -0.0012817382812500, +0.0020446777343750, -0.0012817382812500, 0.0016784667968750, -0.0016479492187500, +0.0015869140625000, -0.0014953613281250, 0.0021057128906250, -0.0013427734375000, +0.0013427734375000, -0.0013122558593750, 0.0019226074218750, -0.0010070800781250, +0.0019836425781250, -0.0006713867187500, 0.0014343261718750, -0.0004882812500000, +0.0021057128906250, -0.0000610351562500, 0.0013732910156250, 0.0001831054687500, +0.0014343261718750, 0.0003662109375000, 0.0014343261718750, 0.0006713867187500, +0.0008850097656250, 0.0008239746093750, 0.0008850097656250, 0.0008544921875000, +0.0006713867187500, 0.0010375976562500, 0.0004272460937500, 0.0009460449218750, +0.0001831054687500, 0.0007019042968750, 0.0000915527343750, 0.0007629394531250, +0.0000000000000000, 0.0005493164062500, -0.0004882812500000, 0.0001220703125000, +-0.0003051757812500, 0.0000305175781250, -0.0005493164062500, -0.0001525878906250, +-0.0009765625000000, -0.0007629394531250, -0.0006103515625000, -0.0003356933593750, +-0.0010070800781250, -0.0009765625000000, -0.0009460449218750, -0.0009460449218750, +-0.0009460449218750, -0.0005187988281250, -0.0011596679687500, -0.0012512207031250, +-0.0008239746093750, -0.0003967285156250, -0.0012207031250000, -0.0007324218750000, +-0.0011291503906250, -0.0004882812500000, -0.0010070800781250, 0.0001831054687500, +-0.0012207031250000, -0.0003356933593750, -0.0010375976562500, 0.0006713867187500, +-0.0009765625000000, 0.0004882812500000, -0.0008544921875000, 0.0006713867187500, +-0.0007629394531250, 0.0013427734375000, -0.0007324218750000, 0.0008544921875000, +-0.0005187988281250, 0.0017700195312500, -0.0004882812500000, 0.0014038085937500, +-0.0003356933593750, 0.0016479492187500, -0.0001525878906250, 0.0023498535156250, +-0.0000915527343750, 0.0017089843750000, 0.0000610351562500, 0.0026550292968750, +0.0003051757812500, 0.0025024414062500, 0.0003662109375000, 0.0024719238281250, +0.0005493164062500, 0.0031127929687500, 0.0007324218750000, 0.0026855468750000, +0.0005798339843750, 0.0032043457031250, 0.0008239746093750, 0.0031433105468750, +0.0008850097656250, 0.0030822753906250, 0.0007629394531250, 0.0033569335937500, +0.0008239746093750, 0.0032043457031250, 0.0008544921875000, 0.0032653808593750, +0.0005798339843750, 0.0033264160156250, 0.0006103515625000, 0.0032653808593750, +0.0004882812500000}, +{0.0006103515625000, -0.0010681152343750, 0.0004577636718750, -0.0021362304687500, +-0.0000305175781250, -0.0016479492187500, 0.0003662109375000, -0.0018005371093750, +0.0001525878906250, -0.0018920898437500, -0.0000915527343750, -0.0015869140625000, +0.0003662109375000, -0.0013122558593750, 0.0008239746093750, -0.0010681152343750, +0.0006408691406250, -0.0007629394531250, 0.0012817382812500, -0.0003662109375000, +0.0016174316406250, -0.0003967285156250, 0.0016174316406250, -0.0003967285156250, +0.0019531250000000, -0.0001220703125000, 0.0023498535156250, -0.0008239746093750, +0.0022583007812500, -0.0009460449218750, 0.0025634765625000, -0.0009460449218750, +0.0027770996093750, -0.0013732910156250, 0.0027770996093750, -0.0016479492187500, +0.0028381347656250, -0.0014343261718750, 0.0027770996093750, -0.0017700195312500, +0.0028381347656250, -0.0015563964843750, 0.0025939941406250, -0.0010986328125000, +0.0022583007812500, -0.0013122558593750, 0.0022888183593750, -0.0005187988281250, +0.0020141601562500, -0.0002441406250000, 0.0017700195312500, -0.0002136230468750, +0.0017089843750000, 0.0003356933593750, 0.0016784667968750, 0.0007934570312500, +0.0016784667968750, 0.0006103515625000, 0.0013427734375000, 0.0011901855468750, +0.0017395019531250, 0.0013427734375000, 0.0015563964843750, 0.0010986328125000, +0.0012512207031250, 0.0016174316406250, 0.0020141601562500, 0.0013732910156250, +0.0013732910156250, 0.0014953613281250, 0.0017700195312500, 0.0014343261718750, +0.0018920898437500, 0.0011901855468750, 0.0014648437500000, 0.0012207031250000, +0.0018615722656250, 0.0009155273437500, 0.0013427734375000, 0.0007629394531250, +0.0013427734375000, 0.0007019042968750, 0.0012207031250000, 0.0004882812500000, +0.0007019042968750, 0.0003051757812500, 0.0007629394531250, 0.0004577636718750, +0.0002136230468750, 0.0001525878906250, 0.0002136230468750, 0.0001831054687500, +-0.0001831054687500, 0.0004272460937500, -0.0005493164062500, 0.0002136230468750, +-0.0001525878906250, 0.0005798339843750, -0.0009765625000000, 0.0005798339843750, +-0.0007629394531250, 0.0006713867187500, -0.0007019042968750, 0.0010070800781250, +-0.0011291503906250, 0.0009765625000000, -0.0007324218750000, 0.0011596679687500, +-0.0008850097656250, 0.0011901855468750, -0.0007934570312500, 0.0012207031250000, +-0.0007324218750000, 0.0013427734375000, -0.0007629394531250, 0.0012207031250000, +-0.0007019042968750, 0.0012207031250000, -0.0007324218750000, 0.0012207031250000, +-0.0007019042968750, 0.0010986328125000, -0.0006713867187500, 0.0009765625000000, +-0.0007019042968750, 0.0008239746093750, -0.0006103515625000, 0.0009155273437500, +-0.0006713867187500, 0.0006408691406250, -0.0005187988281250, 0.0005798339843750, +-0.0003967285156250, 0.0007629394531250, -0.0004577636718750, 0.0005798339843750, +-0.0002441406250000, 0.0005493164062500, -0.0000915527343750, 0.0006103515625000, +-0.0000610351562500, 0.0004272460937500, 0.0001525878906250, 0.0002746582031250, +0.0003662109375000, 0.0002746582031250, 0.0001831054687500, 0.0000000000000000, +0.0004882812500000, -0.0000305175781250, 0.0003662109375000, -0.0001831054687500, +0.0003662109375000, -0.0004272460937500, 0.0005187988281250, -0.0004272460937500, +0.0002746582031250, -0.0005798339843750, 0.0003662109375000, -0.0007324218750000, +0.0002746582031250, -0.0007629394531250, 0.0001831054687500, -0.0008544921875000, +0.0001831054687500, -0.0010375976562500, 0.0000610351562500, -0.0008544921875000, +0.0000610351562500, -0.0011901855468750, 0.0000305175781250, -0.0010986328125000, +-0.0000610351562500, -0.0008544921875000, -0.0000915527343750, -0.0013122558593750, +0.0000610351562500, -0.0008544921875000, -0.0003662109375000, -0.0009765625000000, +-0.0001831054687500, -0.0009765625000000, -0.0001831054687500, -0.0005493164062500, +-0.0005493164062500, -0.0007019042968750, -0.0002746582031250, -0.0004577636718750, +-0.0003662109375000, -0.0004272460937500, -0.0004882812500000, -0.0005493164062500, +-0.0002441406250000, -0.0004882812500000, -0.0000915527343750, -0.0006103515625000, +-0.0003662109375000, -0.0007629394531250, 0.0002746582031250, -0.0010375976562500, +0.0000915527343750, -0.0012207031250000, 0.0003662109375000, -0.0014038085937500, +0.0009765625000000, -0.0017089843750000, 0.0007019042968750, -0.0018615722656250, +0.0014648437500000, -0.0021362304687500, 0.0014343261718750, -0.0023498535156250, +0.0015869140625000, -0.0025329589843750, 0.0021057128906250, -0.0028076171875000, +0.0017395019531250, -0.0027465820312500, 0.0020751953125000, -0.0031433105468750, +0.0018615722656250, -0.0030212402343750, 0.0016479492187500, -0.0029907226562500, +0.0014648437500000, -0.0035400390625000, 0.0009765625000000, -0.0023193359375000, +0.0012512207031250, -0.0030212402343750, 0.0004882812500000, -0.0026550292968750, +0.0004882812500000, -0.0016479492187500, 0.0007629394531250, -0.0028076171875000, +-0.0001831054687500, -0.0013427734375000, 0.0005493164062500, -0.0017089843750000, +0.0001220703125000, -0.0017395019531250, 0.0000000000000000, -0.0008544921875000, +0.0005187988281250, -0.0014038085937500, 0.0002136230468750, -0.0008544921875000, +0.0004577636718750, -0.0004882812500000, 0.0007324218750000, -0.0004577636718750, +0.0007019042968750, -0.0001525878906250, 0.0007019042968750, 0.0003662109375000, +0.0008850097656250, 0.0005798339843750, 0.0006713867187500, 0.0011596679687500, +0.0008239746093750, 0.0014038085937500, 0.0007629394531250, 0.0017700195312500, +0.0005187988281250, 0.0027465820312500, 0.0006408691406250, 0.0024414062500000, +0.0010375976562500, 0.0033264160156250, 0.0009155273437500, 0.0033874511718750, +0.0010986328125000, 0.0029296875000000, 0.0014953613281250, 0.0037231445312500, +0.0013732910156250, 0.0027770996093750, 0.0016174316406250, 0.0029602050781250, +0.0018310546875000, 0.0029296875000000, 0.0018310546875000, 0.0021667480468750, +0.0018615722656250, 0.0020141601562500, 0.0018920898437500, 0.0017700195312500, +0.0017089843750000, 0.0017089843750000, 0.0016479492187500, 0.0012207031250000, +0.0016479492187500, 0.0008544921875000, 0.0013732910156250, 0.0010681152343750, +0.0011291503906250, -0.0001831054687500, 0.0008239746093750, 0.0000610351562500, +0.0004272460937500, -0.0003662109375000, 0.0003051757812500, -0.0014038085937500, +0.0000610351562500, -0.0009765625000000, -0.0004272460937500, -0.0015869140625000, +0.0000915527343750, -0.0018615722656250, -0.0003967285156250, -0.0015869140625000, +-0.0005187988281250, -0.0014648437500000, -0.0000305175781250, -0.0016174316406250, +-0.0002746582031250, -0.0013122558593750, -0.0001220703125000, -0.0015258789062500, +-0.0003051757812500, -0.0012512207031250, -0.0003662109375000, -0.0008239746093750, +-0.0003356933593750, -0.0011596679687500, -0.0007019042968750, -0.0002136230468750, +-0.0002746582031250, -0.0001220703125000, -0.0006713867187500, 0.0001220703125000, +-0.0005798339843750, 0.0007324218750000, -0.0001525878906250, 0.0006103515625000, +-0.0006713867187500, 0.0014038085937500, 0.0000305175781250, 0.0012512207031250, +-0.0002136230468750, 0.0015869140625000, -0.0001220703125000, 0.0022277832031250, +0.0003967285156250, 0.0018005371093750, -0.0001220703125000, 0.0027770996093750, +0.0005187988281250, 0.0028076171875000, 0.0006408691406250, 0.0025634765625000, +0.0004577636718750, 0.0030212402343750, 0.0006713867187500, 0.0030212402343750, +0.0006408691406250, 0.0025024414062500, 0.0003051757812500, 0.0026550292968750, +0.0003967285156250, 0.0025024414062500, 0.0002136230468750, 0.0020446777343750, +-0.0001220703125000, 0.0023193359375000, -0.0000610351562500, 0.0017700195312500, +-0.0003051757812500, 0.0019836425781250, -0.0002441406250000, 0.0017089843750000, +-0.0003051757812500, 0.0011596679687500, -0.0004882812500000, 0.0014648437500000, +-0.0004577636718750, 0.0006103515625000, -0.0009155273437500, 0.0007629394531250, +-0.0007629394531250, 0.0006713867187500, -0.0010070800781250, 0.0001525878906250, +-0.0014038085937500, 0.0005798339843750, -0.0011596679687500, 0.0003662109375000, +-0.0014648437500000, 0.0003356933593750, -0.0014953613281250, 0.0006408691406250, +-0.0012817382812500, 0.0006103515625000, -0.0011596679687500, 0.0003356933593750, +-0.0009155273437500, 0.0010375976562500, -0.0006713867187500, 0.0005187988281250, +-0.0002441406250000, 0.0008850097656250, 0.0000000000000000, 0.0015258789062500, +0.0002746582031250, 0.0006713867187500, 0.0006103515625000, 0.0019836425781250, +0.0003356933593750, 0.0015869140625000, 0.0006713867187500, 0.0016174316406250, +0.0005187988281250, 0.0025024414062500, -0.0000305175781250, 0.0017700195312500, +0.0003356933593750, 0.0021972656250000, -0.0003051757812500, 0.0023193359375000, +-0.0005493164062500, 0.0020751953125000, -0.0004272460937500, 0.0022277832031250, +-0.0005798339843750, 0.0023498535156250, -0.0007324218750000, 0.0019531250000000, +-0.0002441406250000, 0.0021972656250000, -0.0003967285156250, 0.0019531250000000, +-0.0002441406250000, 0.0015869140625000, 0.0002441406250000, 0.0020141601562500, +0.0000610351562500, 0.0009155273437500, 0.0004272460937500, 0.0012512207031250, +0.0005798339843750, 0.0010070800781250, 0.0005493164062500, 0.0000610351562500, +0.0006713867187500, 0.0006103515625000, 0.0008239746093750, 0.0000305175781250, +0.0006103515625000, -0.0000610351562500, 0.0006103515625000, 0.0001220703125000, +0.0006103515625000, 0.0000610351562500, 0.0004272460937500, 0.0000610351562500, +0.0003356933593750, 0.0002441406250000, 0.0005798339843750, 0.0001831054687500, +0.0003356933593750, 0.0003356933593750, 0.0004577636718750, 0.0004882812500000, +0.0006713867187500, 0.0002746582031250, 0.0003662109375000, 0.0007019042968750, +0.0010070800781250, 0.0004272460937500, 0.0008544921875000, 0.0003967285156250, +0.0009460449218750, 0.0007019042968750, 0.0013732910156250, 0.0002746582031250, +0.0011596679687500, 0.0003967285156250, 0.0014038085937500, 0.0003051757812500, +0.0014648437500000, 0.0000610351562500, 0.0013122558593750, 0.0000000000000000, +0.0013122558593750, -0.0000610351562500, 0.0013122558593750, -0.0003356933593750, +0.0009765625000000, -0.0003662109375000, 0.0010070800781250, -0.0004882812500000, +0.0007934570312500, -0.0007324218750000, 0.0004882812500000, -0.0006408691406250, +0.0005493164062500, -0.0007934570312500, 0.0000915527343750, -0.0008544921875000, +0.0000305175781250, -0.0006713867187500, -0.0001220703125000, -0.0007019042968750, +-0.0005493164062500, -0.0007629394531250, -0.0005493164062500, -0.0003662109375000, +-0.0008850097656250, -0.0005493164062500, -0.0010070800781250, -0.0004272460937500, +-0.0012207031250000, -0.0001220703125000, -0.0014953613281250, -0.0005187988281250, +-0.0015258789062500, 0.0000305175781250, -0.0017700195312500, -0.0000915527343750, +-0.0019531250000000, -0.0001220703125000, -0.0020446777343750, 0.0002746582031250, +-0.0022583007812500, -0.0000305175781250, -0.0024108886718750, 0.0000000000000000, +-0.0022277832031250, 0.0001525878906250, -0.0024719238281250, -0.0001220703125000, +-0.0022888183593750, -0.0002441406250000, -0.0019226074218750, 0.0000000000000000, +-0.0021972656250000, -0.0002136230468750, -0.0013122558593750, -0.0001831054687500, +-0.0016479492187500, 0.0000610351562500, -0.0011596679687500, 0.0000610351562500, +-0.0003356933593750, 0.0002136230468750, -0.0010681152343750, 0.0006103515625000, +0.0003051757812500, 0.0005798339843750, 0.0000610351562500, 0.0009155273437500, +0.0001220703125000, 0.0012817382812500, 0.0009155273437500, 0.0011596679687500, +0.0001220703125000}, +{0.0007629394531250, 0.0007934570312500, 0.0010070800781250, 0.0003662109375000, +0.0006103515625000, 0.0003356933593750, 0.0009765625000000, 0.0006713867187500, +0.0007019042968750, 0.0005493164062500, 0.0001220703125000, 0.0003051757812500, +0.0006103515625000, 0.0010070800781250, -0.0002136230468750, 0.0004272460937500, +-0.0001220703125000, 0.0007019042968750, -0.0000305175781250, 0.0013427734375000, +-0.0003662109375000, 0.0003051757812500, -0.0000915527343750, 0.0017089843750000, +-0.0001220703125000, 0.0011901855468750, 0.0000305175781250, 0.0011901855468750, +-0.0000305175781250, 0.0021972656250000, 0.0000000000000000, 0.0014343261718750, +0.0002441406250000, 0.0020141601562500, -0.0002136230468750, 0.0020141601562500, +0.0000305175781250, 0.0018310546875000, -0.0002136230468750, 0.0020446777343750, +-0.0006408691406250, 0.0019531250000000, -0.0001220703125000, 0.0016784667968750, +-0.0007324218750000, 0.0018920898437500, -0.0005187988281250, 0.0014953613281250, +-0.0003356933593750, 0.0010070800781250, -0.0005187988281250, 0.0014343261718750, +-0.0001220703125000, 0.0003356933593750, 0.0001525878906250, 0.0003967285156250, +0.0001525878906250, 0.0003967285156250, 0.0007629394531250, -0.0002441406250000, +0.0011901855468750, -0.0001525878906250, 0.0009765625000000, 0.0001831054687500, +0.0021667480468750, -0.0002441406250000, 0.0019836425781250, 0.0000000000000000, +0.0021972656250000, 0.0003356933593750, 0.0029602050781250, -0.0002441406250000, +0.0024414062500000, 0.0004882812500000, 0.0028991699218750, 0.0001831054687500, +0.0029602050781250, 0.0000610351562500, 0.0026550292968750, 0.0004882812500000, +0.0027465820312500, 0.0001525878906250, 0.0027160644531250, 0.0000915527343750, +0.0022888183593750, 0.0002441406250000, 0.0023498535156250, 0.0000000000000000, +0.0021667480468750, -0.0002746582031250, 0.0018310546875000, -0.0000915527343750, +0.0020141601562500, -0.0004577636718750, 0.0016784667968750, -0.0005493164062500, +0.0015563964843750, -0.0004882812500000, 0.0015869140625000, -0.0007019042968750, +0.0014648437500000, -0.0007934570312500, 0.0014038085937500, -0.0004882812500000, +0.0016479492187500, -0.0008544921875000, 0.0014648437500000, -0.0007019042968750, +0.0014648437500000, -0.0004577636718750, 0.0016479492187500, -0.0009765625000000, +0.0014038085937500, -0.0003051757812500, 0.0015563964843750, -0.0006713867187500, +0.0014648437500000, -0.0006103515625000, 0.0012817382812500, -0.0001220703125000, +0.0012817382812500, -0.0006408691406250, 0.0011901855468750, 0.0000305175781250, +0.0010375976562500, -0.0000610351562500, 0.0010375976562500, -0.0002441406250000, +0.0008850097656250, 0.0000000000000000, 0.0007019042968750, -0.0001220703125000, +0.0007629394531250, -0.0002441406250000, 0.0003967285156250, -0.0000915527343750, +0.0004882812500000, -0.0000610351562500, 0.0002441406250000, -0.0000915527343750, +-0.0000915527343750, 0.0001831054687500, 0.0001220703125000, 0.0001220703125000, +-0.0003356933593750, 0.0002136230468750, -0.0002746582031250, 0.0004272460937500, +-0.0003967285156250, 0.0004577636718750, -0.0007019042968750, 0.0006103515625000, +-0.0004272460937500, 0.0009155273437500, -0.0006408691406250, 0.0007934570312500, +-0.0008544921875000, 0.0011596679687500, -0.0005798339843750, 0.0014953613281250, +-0.0005187988281250, 0.0010375976562500, -0.0008239746093750, 0.0018615722656250, +-0.0000915527343750, 0.0014648437500000, -0.0003662109375000, 0.0013427734375000, +-0.0000915527343750, 0.0017395019531250, 0.0006103515625000, 0.0010375976562500, +0.0001525878906250, 0.0014343261718750, 0.0009765625000000, 0.0010681152343750, +0.0009155273437500, 0.0008239746093750, 0.0008239746093750, 0.0009765625000000, +0.0012817382812500, 0.0004272460937500, 0.0010681152343750, 0.0006713867187500, +0.0008850097656250, 0.0003967285156250, 0.0009155273437500, 0.0004272460937500, +0.0005493164062500, 0.0007019042968750, 0.0000915527343750, 0.0004882812500000, +0.0001831054687500, 0.0008850097656250, -0.0004272460937500, 0.0009765625000000, +-0.0006103515625000, 0.0008544921875000, -0.0006103515625000, 0.0009460449218750, +-0.0009155273437500, 0.0008850097656250, -0.0010986328125000, 0.0006103515625000, +-0.0009155273437500, 0.0005493164062500, -0.0010986328125000, 0.0002746582031250, +-0.0013122558593750, 0.0000610351562500, -0.0011291503906250, 0.0002136230468750, +-0.0010681152343750, -0.0007324218750000, -0.0016784667968750, 0.0000915527343750, +-0.0014038085937500, -0.0004272460937500, -0.0018615722656250, -0.0011291503906250, +-0.0025329589843750, 0.0004272460937500, -0.0020141601562500, -0.0015258789062500, +-0.0030822753906250, -0.0008544921875000, -0.0028991699218750, -0.0006408691406250, +-0.0029296875000000, -0.0019836425781250, -0.0035705566406250, -0.0011901855468750, +-0.0030822753906250, -0.0012512207031250, -0.0031433105468750, -0.0019836425781250, +-0.0033874511718750, -0.0015258789062500, -0.0029296875000000, -0.0011596679687500, +-0.0025329589843750, -0.0021667480468750, -0.0027770996093750, -0.0010375976562500, +-0.0017395019531250, -0.0013427734375000, -0.0016174316406250, -0.0016479492187500, +-0.0016174316406250, -0.0010681152343750, -0.0010070800781250, -0.0013122558593750, +-0.0008239746093750, -0.0011901855468750, -0.0008544921875000, -0.0009155273437500, +-0.0007934570312500, -0.0009460449218750, -0.0002136230468750, -0.0008850097656250, +-0.0000305175781250, -0.0005493164062500, -0.0001525878906250, -0.0008544921875000, +0.0011596679687500, -0.0005798339843750, 0.0012512207031250, -0.0005187988281250, +0.0012512207031250, -0.0007019042968750, 0.0020446777343750, -0.0003356933593750, +0.0021667480468750, -0.0005493164062500, 0.0013732910156250, -0.0001831054687500, +0.0017700195312500, 0.0001220703125000, 0.0016174316406250, -0.0000915527343750, +0.0004882812500000, 0.0017395019531250, 0.0010681152343750, 0.0001525878906250, +0.0012207031250000, 0.0009155273437500, 0.0012512207031250, 0.0008544921875000, +0.0013122558593750, 0.0002441406250000, 0.0011291503906250, 0.0007324218750000, +0.0009155273437500, 0.0008850097656250, 0.0014343261718750, 0.0010681152343750, +0.0014038085937500, 0.0010070800781250, 0.0010070800781250, 0.0011291503906250, +0.0011901855468750, 0.0015258789062500, 0.0013122558593750, 0.0003967285156250, +-0.0001525878906250, 0.0007019042968750, 0.0002136230468750, 0.0007019042968750, +-0.0001831054687500, -0.0001525878906250, -0.0015563964843750, 0.0002136230468750, +-0.0011291503906250, 0.0006103515625000, -0.0015563964843750, 0.0003662109375000, +-0.0017395019531250, 0.0007019042968750, -0.0016174316406250, 0.0014343261718750, +-0.0016174316406250, 0.0011901855468750, -0.0016174316406250, 0.0009460449218750, +-0.0014953613281250, 0.0015258789062500, -0.0015563964843750, 0.0009155273437500, +-0.0012207031250000, -0.0000610351562500, -0.0010070800781250, 0.0006408691406250, +-0.0013427734375000, -0.0003356933593750, 0.0000305175781250, -0.0004882812500000, +-0.0002746582031250, -0.0001831054687500, 0.0000000000000000, -0.0003967285156250, +0.0011291503906250, -0.0003356933593750, 0.0006713867187500, 0.0000610351562500, +0.0007629394531250, 0.0001525878906250, 0.0013122558593750, 0.0001525878906250, +0.0008850097656250, 0.0005493164062500, 0.0004577636718750, 0.0007934570312500, +0.0010986328125000, 0.0001525878906250, 0.0004577636718750, 0.0006408691406250, +0.0006713867187500, 0.0006103515625000, 0.0007934570312500, 0.0000305175781250, +0.0007019042968750, 0.0005798339843750, 0.0013122558593750, 0.0004882812500000, +0.0008850097656250, 0.0003967285156250, 0.0013427734375000, 0.0006408691406250, +0.0014648437500000, 0.0007324218750000, 0.0010986328125000, 0.0004272460937500, +0.0014953613281250, 0.0008239746093750, 0.0016174316406250, 0.0007019042968750, +0.0014953613281250, 0.0002746582031250, 0.0017700195312500, 0.0003967285156250, +0.0020446777343750, 0.0003662109375000, 0.0018310546875000, -0.0007019042968750, +0.0018005371093750, -0.0004577636718750, 0.0019226074218750, -0.0007629394531250, +0.0016479492187500, -0.0015563964843750, 0.0013427734375000, -0.0010681152343750, +0.0015258789062500, -0.0015258789062500, 0.0010375976562500, -0.0014038085937500, +0.0012207031250000, -0.0011291503906250, 0.0010375976562500, -0.0012207031250000, +0.0008239746093750, -0.0009765625000000, 0.0013122558593750, -0.0006103515625000, +0.0006103515625000, -0.0005798339843750, 0.0008850097656250, -0.0001220703125000, +0.0010070800781250, 0.0003967285156250, 0.0005187988281250, 0.0002136230468750, +0.0007934570312500, 0.0010070800781250, 0.0007934570312500, 0.0010986328125000, +0.0005798339843750, 0.0011596679687500, 0.0006103515625000, 0.0016479492187500, +0.0006103515625000, 0.0015563964843750, 0.0004882812500000, 0.0016784667968750, +0.0003662109375000, 0.0018920898437500, 0.0003051757812500, 0.0018615722656250, +0.0001220703125000, 0.0018005371093750, 0.0000000000000000, 0.0019836425781250, +0.0000610351562500, 0.0019531250000000, -0.0002746582031250, 0.0018920898437500, +-0.0001831054687500, 0.0019836425781250, -0.0002746582031250, 0.0019836425781250, +-0.0004882812500000, 0.0018005371093750, -0.0003051757812500, 0.0018920898437500, +-0.0003356933593750, 0.0018005371093750, -0.0004272460937500, 0.0016174316406250, +-0.0003051757812500, 0.0015869140625000, -0.0003051757812500, 0.0013732910156250, +-0.0004272460937500, 0.0012512207031250, -0.0002441406250000, 0.0011596679687500, +-0.0003662109375000, 0.0009460449218750, -0.0004577636718750, 0.0007629394531250, +-0.0004577636718750, 0.0007324218750000, -0.0006713867187500, 0.0004272460937500, +-0.0005493164062500, 0.0003356933593750, -0.0007629394531250, 0.0002136230468750, +-0.0007019042968750, 0.0000915527343750, -0.0005187988281250, 0.0000610351562500, +-0.0009460449218750, -0.0000915527343750, -0.0002746582031250, -0.0000915527343750, +-0.0005798339843750, -0.0000915527343750, -0.0005187988281250, -0.0002136230468750, +0.0000305175781250, -0.0003051757812500, -0.0004272460937500, -0.0001831054687500, +0.0000610351562500, -0.0002746582031250, 0.0001220703125000, -0.0002441406250000, +-0.0000610351562500, -0.0000915527343750, 0.0000610351562500, -0.0002136230468750, +0.0001220703125000, 0.0000305175781250, -0.0002441406250000, -0.0000610351562500, +-0.0000305175781250, -0.0000305175781250, 0.0000000000000000, 0.0001525878906250, +-0.0002441406250000, 0.0000305175781250, 0.0000000000000000, 0.0001525878906250, +0.0000305175781250, 0.0002136230468750, -0.0000610351562500, 0.0001220703125000, +0.0001525878906250, 0.0001831054687500, 0.0003662109375000, 0.0002746582031250, +0.0002441406250000, -0.0000305175781250, 0.0007629394531250, 0.0003051757812500, +0.0007324218750000, 0.0001220703125000, 0.0008850097656250, -0.0000915527343750, +0.0012207031250000, 0.0006713867187500, 0.0012207031250000, -0.0003967285156250, +0.0014038085937500, 0.0005798339843750, 0.0014648437500000, 0.0003662109375000, +0.0015563964843750, -0.0005493164062500, 0.0016174316406250, 0.0009460449218750, +0.0014343261718750, -0.0007324218750000, 0.0014648437500000, -0.0001525878906250, +0.0010681152343750, -0.0000610351562500, 0.0010070800781250, -0.0010375976562500, +0.0009460449218750, 0.0000305175781250, 0.0003662109375000, -0.0008544921875000, +0.0008544921875000, -0.0004577636718750, 0.0003356933593750, -0.0003051757812500, +0.0002136230468750, -0.0007629394531250, 0.0006103515625000, -0.0001220703125000, +0.0000915527343750, -0.0005493164062500, 0.0004272460937500, -0.0001831054687500, +0.0005187988281250}, +{0.0011596679687500, 0.0007019042968750, 0.0013427734375000, 0.0006713867187500, +0.0010070800781250, 0.0015869140625000, 0.0006408691406250, 0.0015563964843750, +0.0009765625000000, 0.0012512207031250, 0.0004577636718750, 0.0019836425781250, +0.0006713867187500, 0.0015563964843750, 0.0006713867187500, 0.0008850097656250, +0.0002441406250000, 0.0018005371093750, 0.0006103515625000, 0.0004272460937500, +0.0003662109375000, 0.0007629394531250, 0.0002136230468750, 0.0007324218750000, +0.0004272460937500, -0.0001220703125000, 0.0004272460937500, 0.0003662109375000, +0.0001220703125000, -0.0000610351562500, 0.0005493164062500, -0.0001525878906250, +0.0003356933593750, 0.0001220703125000, 0.0002441406250000, 0.0000305175781250, +0.0004577636718750, -0.0001220703125000, 0.0001831054687500, 0.0003051757812500, +0.0001831054687500, 0.0000000000000000, 0.0001831054687500, 0.0000000000000000, +0.0000915527343750, 0.0003051757812500, -0.0000305175781250, -0.0002441406250000, +0.0000000000000000, 0.0001831054687500, -0.0000915527343750, -0.0000305175781250, +-0.0001525878906250, -0.0001220703125000, -0.0001525878906250, 0.0001525878906250, +-0.0002136230468750, -0.0002136230468750, -0.0003967285156250, 0.0001525878906250, +-0.0001525878906250, -0.0000915527343750, -0.0004272460937500, 0.0000915527343750, +-0.0003967285156250, 0.0004272460937500, -0.0002441406250000, 0.0000305175781250, +-0.0007019042968750, 0.0008239746093750, -0.0003051757812500, 0.0006408691406250, +-0.0006103515625000, 0.0008544921875000, -0.0006408691406250, 0.0014953613281250, +-0.0003967285156250, 0.0010986328125000, -0.0008239746093750, 0.0018615722656250, +-0.0004272460937500, 0.0017089843750000, -0.0006408691406250, 0.0019226074218750, +-0.0007019042968750, 0.0024108886718750, -0.0004272460937500, 0.0019226074218750, +-0.0006103515625000, 0.0026855468750000, -0.0004882812500000, 0.0024108886718750, +-0.0005187988281250, 0.0024414062500000, -0.0004882812500000, 0.0029602050781250, +-0.0004272460937500, 0.0024414062500000, -0.0004272460937500, 0.0031127929687500, +-0.0001831054687500, 0.0028991699218750, -0.0002746582031250, 0.0028991699218750, +-0.0001220703125000, 0.0032043457031250, 0.0001525878906250, 0.0028076171875000, +0.0000305175781250, 0.0030517578125000, 0.0005493164062500, 0.0030517578125000, +0.0005493164062500, 0.0030517578125000, 0.0006408691406250, 0.0032348632812500, +0.0009155273437500, 0.0030212402343750, 0.0009155273437500, 0.0032043457031250, +0.0009765625000000, 0.0032653808593750, 0.0011901855468750, 0.0032348632812500, +0.0012512207031250, 0.0034179687500000, 0.0012512207031250, 0.0035705566406250, +0.0013427734375000, 0.0035400390625000, 0.0013732910156250, 0.0038757324218750, +0.0012512207031250, 0.0039062500000000, 0.0012207031250000, 0.0038452148437500, +0.0010986328125000, 0.0043334960937500, 0.0007934570312500, 0.0039978027343750, +0.0007629394531250, 0.0042114257812500, 0.0003662109375000, 0.0041503906250000, +0.0002136230468750, 0.0037841796875000, 0.0002441406250000, 0.0039978027343750, +-0.0000610351562500, 0.0033569335937500, 0.0000305175781250, 0.0033874511718750, +0.0000610351562500, 0.0030212402343750, -0.0000915527343750, 0.0023803710937500, +0.0000305175781250, 0.0026550292968750, 0.0003662109375000, 0.0016784667968750, +-0.0000305175781250, 0.0017700195312500, 0.0006408691406250, 0.0015563964843750, +0.0006103515625000, 0.0009460449218750, 0.0002441406250000, 0.0012512207031250, +0.0011291503906250, 0.0008239746093750, 0.0004577636718750, 0.0007019042968750, +0.0006408691406250, 0.0007324218750000, 0.0009155273437500, 0.0004272460937500, +0.0006103515625000, 0.0002746582031250, 0.0007324218750000, 0.0002746582031250, +0.0009155273437500, -0.0000305175781250, 0.0007019042968750, -0.0002136230468750, +0.0008544921875000, -0.0002136230468750, 0.0010681152343750, -0.0007019042968750, +0.0007629394531250, -0.0009460449218750, 0.0012207031250000, -0.0010681152343750, +0.0011901855468750, -0.0012207031250000, 0.0011901855468750, -0.0013427734375000, +0.0014343261718750, -0.0012817382812500, 0.0012817382812500, -0.0009155273437500, +0.0013427734375000, -0.0008544921875000, 0.0012817382812500, -0.0007934570312500, +0.0012207031250000, -0.0005187988281250, 0.0010986328125000, -0.0003356933593750, +0.0009155273437500, -0.0006408691406250, 0.0007629394531250, -0.0002746582031250, +0.0003967285156250, -0.0004272460937500, 0.0003051757812500, -0.0007934570312500, +0.0003356933593750, -0.0004272460937500, 0.0000000000000000, -0.0009155273437500, +-0.0000305175781250, -0.0015258789062500, -0.0002441406250000, -0.0014343261718750, +-0.0004577636718750, -0.0016174316406250, -0.0005187988281250, -0.0024414062500000, +-0.0006103515625000, -0.0019836425781250, -0.0005493164062500, -0.0026550292968750, +-0.0007324218750000, -0.0028076171875000, -0.0007019042968750, -0.0025329589843750, +-0.0005493164062500, -0.0033264160156250, -0.0007324218750000, -0.0023803710937500, +-0.0006103515625000, -0.0028381347656250, -0.0007019042968750, -0.0027770996093750, +-0.0007019042968750, -0.0014953613281250, -0.0006713867187500, -0.0007019042968750, +-0.0005798339843750, 0.0006103515625000, -0.0001831054687500, 0.0002136230468750, +-0.0003967285156250, 0.0003967285156250, -0.0003662109375000, 0.0014038085937500, +0.0000000000000000, 0.0010375976562500, -0.0001525878906250, 0.0015258789062500, +0.0000305175781250, 0.0016479492187500, 0.0002441406250000, 0.0015563964843750, +0.0001525878906250, 0.0015563964843750, 0.0001220703125000, 0.0014343261718750, +0.0003356933593750, 0.0010681152343750, -0.0000305175781250, 0.0012207031250000, +0.0001220703125000, 0.0006408691406250, 0.0000915527343750, 0.0000915527343750, +-0.0000305175781250, 0.0006713867187500, 0.0001831054687500, -0.0002441406250000, +-0.0001220703125000, -0.0002441406250000, 0.0001525878906250, -0.0000305175781250, +0.0000915527343750, -0.0003356933593750, -0.0001220703125000, -0.0002441406250000, +0.0003051757812500, -0.0001220703125000, -0.0002441406250000, -0.0001220703125000, +-0.0000610351562500, 0.0000305175781250, 0.0000000000000000, 0.0000915527343750, +-0.0002136230468750, 0.0000610351562500, 0.0000305175781250, 0.0008239746093750, +0.0000000000000000, 0.0006103515625000, 0.0000915527343750, 0.0009765625000000, +0.0000915527343750, 0.0018005371093750, 0.0000000000000000, 0.0015258789062500, +0.0000305175781250, 0.0021667480468750, -0.0004272460937500, 0.0022277832031250, +-0.0003967285156250, 0.0021972656250000, -0.0006103515625000, 0.0024108886718750, +-0.0010375976562500, 0.0022277832031250, -0.0008850097656250, 0.0023193359375000, +-0.0012207031250000, 0.0021362304687500, -0.0011901855468750, 0.0019836425781250, +-0.0012512207031250, 0.0019836425781250, -0.0013427734375000, 0.0017395019531250, +-0.0010986328125000, 0.0014953613281250, -0.0012817382812500, 0.0016784667968750, +-0.0009765625000000, 0.0010375976562500, -0.0010070800781250, 0.0006408691406250, +-0.0011901855468750, 0.0011901855468750, -0.0007934570312500, -0.0001525878906250, +-0.0011291503906250, 0.0002746582031250, -0.0009155273437500, 0.0001525878906250, +-0.0007934570312500, -0.0007324218750000, -0.0008544921875000, -0.0000610351562500, +-0.0005493164062500, -0.0006103515625000, -0.0004272460937500, -0.0006408691406250, +-0.0002136230468750, -0.0003967285156250, 0.0001220703125000, -0.0007019042968750, +0.0004272460937500, -0.0007934570312500, 0.0007629394531250, -0.0002441406250000, +0.0006103515625000, -0.0007629394531250, 0.0011596679687500, -0.0003967285156250, +0.0010070800781250, 0.0001525878906250, 0.0007019042968750, -0.0005798339843750, +0.0012817382812500, 0.0007629394531250, 0.0003356933593750, 0.0004577636718750, +0.0005187988281250, 0.0006408691406250, 0.0003356933593750, 0.0015258789062500, +-0.0003051757812500, 0.0009155273437500, -0.0000305175781250, 0.0016479492187500, +-0.0004882812500000, 0.0015258789062500, -0.0006713867187500, 0.0014038085937500, +-0.0006408691406250, 0.0016784667968750, -0.0006713867187500, 0.0013732910156250, +-0.0007019042968750, 0.0010681152343750, -0.0006103515625000, 0.0011901855468750, +-0.0004577636718750, 0.0007324218750000, -0.0003051757812500, 0.0001831054687500, +-0.0001220703125000, 0.0005187988281250, 0.0002136230468750, -0.0002746582031250, +0.0004272460937500, -0.0003356933593750, 0.0008850097656250, -0.0003051757812500, +0.0009460449218750, -0.0007324218750000, 0.0009765625000000, -0.0007324218750000, +0.0014038085937500, -0.0005493164062500, 0.0012207031250000, -0.0008239746093750, +0.0014648437500000, -0.0006408691406250, 0.0015258789062500, -0.0004577636718750, +0.0013732910156250, -0.0008239746093750, 0.0017395019531250, -0.0001220703125000, +0.0013732910156250, -0.0005187988281250, 0.0016479492187500, -0.0004272460937500, +0.0017089843750000, 0.0001220703125000, 0.0014953613281250, -0.0004577636718750, +0.0019836425781250, 0.0001220703125000, 0.0017089843750000, -0.0000915527343750, +0.0020446777343750, -0.0001220703125000, 0.0021972656250000, 0.0001831054687500, +0.0020751953125000, -0.0001525878906250, 0.0025634765625000, 0.0000305175781250, +0.0025939941406250, -0.0000915527343750, 0.0028381347656250, -0.0001831054687500, +0.0031738281250000, -0.0001831054687500, 0.0032958984375000, -0.0003967285156250, +0.0036315917968750, -0.0001831054687500, 0.0037536621093750, -0.0003662109375000, +0.0039367675781250, -0.0002746582031250, 0.0040893554687500, -0.0000610351562500, +0.0042419433593750, -0.0003662109375000, 0.0043640136718750, 0.0000305175781250, +0.0042114257812500, -0.0002136230468750, 0.0043945312500000, -0.0001220703125000, +0.0042419433593750, 0.0001220703125000, 0.0039367675781250, -0.0001831054687500, +0.0040588378906250, 0.0003662109375000, 0.0035095214843750, 0.0001220703125000, +0.0034484863281250, 0.0002746582031250, 0.0032653808593750, 0.0006408691406250, +0.0028381347656250, 0.0000000000000000, 0.0028686523437500, 0.0005187988281250, +0.0025939941406250, 0.0002441406250000, 0.0024108886718750, -0.0000305175781250, +0.0025024414062500, 0.0002136230468750, 0.0024719238281250, -0.0002136230468750, +0.0024414062500000, -0.0000610351562500, 0.0028686523437500, -0.0002746582031250, +0.0027160644531250, -0.0002746582031250, 0.0028686523437500, -0.0001220703125000, +0.0032958984375000, -0.0002746582031250, 0.0029907226562500, 0.0000305175781250, +0.0031738281250000, 0.0002441406250000, 0.0032348632812500, 0.0002746582031250, +0.0028381347656250, 0.0006408691406250, 0.0027160644531250, 0.0011291503906250, +0.0027465820312500, 0.0006103515625000, 0.0021667480468750, 0.0012817382812500, +0.0021362304687500, 0.0012512207031250, 0.0018920898437500, 0.0007019042968750, +0.0014038085937500, 0.0014648437500000, 0.0013122558593750, 0.0006408691406250, +0.0010681152343750, 0.0010681152343750, 0.0008239746093750, 0.0007324218750000, +0.0009155273437500, 0.0001525878906250, 0.0009765625000000, 0.0011901855468750, +0.0007934570312500, -0.0004882812500000, 0.0011596679687500, 0.0006408691406250, +0.0011596679687500, 0.0005187988281250, 0.0010375976562500, -0.0006713867187500, +0.0012207031250000, 0.0010681152343750, 0.0013427734375000, -0.0003051757812500, +0.0007019042968750, 0.0000610351562500, 0.0009765625000000, 0.0006103515625000, +0.0006713867187500, -0.0001220703125000, 0.0000000000000000, 0.0001831054687500, +0.0005493164062500, 0.0006408691406250, -0.0001525878906250, -0.0001525878906250, +-0.0000305175781250, 0.0002441406250000, -0.0000610351562500, 0.0008544921875000, +-0.0003967285156250}, +{0.0017395019531250, 0.0006103515625000, 0.0014343261718750, 0.0011596679687500, +0.0021667480468750, 0.0000915527343750, 0.0011901855468750, 0.0002746582031250, +0.0017395019531250, 0.0002746582031250, 0.0016784667968750, -0.0004577636718750, +0.0009765625000000, -0.0002136230468750, 0.0017395019531250, -0.0002746582031250, +0.0009765625000000, -0.0007629394531250, 0.0013732910156250, -0.0005187988281250, +0.0014648437500000, -0.0003662109375000, 0.0010986328125000, -0.0011291503906250, +0.0017700195312500, -0.0001525878906250, 0.0013122558593750, -0.0007324218750000, +0.0016174316406250, -0.0006713867187500, 0.0018005371093750, 0.0001220703125000, +0.0016174316406250, -0.0007019042968750, 0.0020751953125000, 0.0000915527343750, +0.0019226074218750, -0.0000610351562500, 0.0021667480468750, -0.0002441406250000, +0.0022888183593750, 0.0001525878906250, 0.0022888183593750, -0.0001220703125000, +0.0024414062500000, 0.0000305175781250, 0.0024414062500000, 0.0000305175781250, +0.0025329589843750, -0.0000305175781250, 0.0027465820312500, -0.0000305175781250, +0.0027770996093750, -0.0000305175781250, 0.0028076171875000, 0.0000305175781250, +0.0031433105468750, -0.0000305175781250, 0.0029907226562500, 0.0000305175781250, +0.0032348632812500, 0.0001525878906250, 0.0035095214843750, -0.0000915527343750, +0.0032043457031250, 0.0002441406250000, 0.0038757324218750, 0.0001831054687500, +0.0037231445312500, 0.0002136230468750, 0.0037536621093750, 0.0004272460937500, +0.0041503906250000, 0.0002746582031250, 0.0038452148437500, 0.0005798339843750, +0.0042114257812500, 0.0002746582031250, 0.0040893554687500, 0.0002136230468750, +0.0038146972656250, 0.0003967285156250, 0.0038146972656250, -0.0000915527343750, +0.0036926269531250, 0.0000000000000000, 0.0031433105468750, -0.0001220703125000, +0.0031127929687500, -0.0002746582031250, 0.0026855468750000, -0.0003356933593750, +0.0021057128906250, -0.0004577636718750, 0.0022583007812500, -0.0003662109375000, +0.0012817382812500, -0.0003967285156250, 0.0012207031250000, -0.0002746582031250, +0.0010986328125000, -0.0000610351562500, 0.0005493164062500, 0.0000610351562500, +0.0005493164062500, 0.0002441406250000, 0.0006103515625000, 0.0005798339843750, +0.0002441406250000, 0.0007934570312500, 0.0007019042968750, 0.0009155273437500, +0.0010986328125000, 0.0013427734375000, 0.0005187988281250, 0.0011901855468750, +0.0017700195312500, 0.0014953613281250, 0.0014953613281250, 0.0014343261718750, +0.0016784667968750, 0.0012817382812500, 0.0026245117187500, 0.0017089843750000, +0.0021057128906250, 0.0006103515625000, 0.0030212402343750, 0.0013427734375000, +0.0028686523437500, 0.0009765625000000, 0.0028686523437500, 0.0001525878906250, +0.0033264160156250, 0.0015258789062500, 0.0028686523437500, 0.0002746582031250, +0.0031738281250000, 0.0008850097656250, 0.0029296875000000, 0.0012207031250000, +0.0030212402343750, 0.0006408691406250, 0.0032958984375000, 0.0013427734375000, +0.0028076171875000, 0.0011291503906250, 0.0037536621093750, 0.0008239746093750, +0.0035705566406250, 0.0012512207031250, 0.0034484863281250, 0.0011901855468750, +0.0039978027343750, 0.0003967285156250, 0.0037536621093750, 0.0018005371093750, +0.0033569335937500, 0.0009460449218750, 0.0036926269531250, 0.0010681152343750, +0.0031127929687500, 0.0022583007812500, 0.0025329589843750, 0.0013427734375000, +0.0030822753906250, 0.0021667480468750, 0.0014953613281250, 0.0022888183593750, +0.0018920898437500, 0.0022583007812500, 0.0014648437500000, 0.0026245117187500, +0.0003356933593750, 0.0024108886718750, 0.0012512207031250, 0.0027465820312500, +0.0000915527343750, 0.0026245117187500, 0.0001831054687500, 0.0028381347656250, +0.0004577636718750, 0.0031433105468750, 0.0000915527343750, 0.0027465820312500, +0.0004272460937500, 0.0034790039062500, 0.0004272460937500, 0.0031738281250000, +0.0006408691406250, 0.0030517578125000, 0.0005798339843750, 0.0034790039062500, +0.0003051757812500, 0.0031738281250000, 0.0003051757812500, 0.0030212402343750, +0.0005798339843750, 0.0031127929687500, -0.0000610351562500, 0.0030822753906250, +0.0004577636718750, 0.0029296875000000, 0.0011596679687500, 0.0029907226562500, +0.0002746582031250, 0.0029296875000000, 0.0018920898437500, 0.0029296875000000, +0.0016479492187500, 0.0027465820312500, 0.0014038085937500, 0.0024719238281250, +0.0026550292968750, 0.0026855468750000, 0.0005187988281250, 0.0027770996093750, +0.0027465820312500, 0.0025939941406250, 0.0018920898437500, 0.0024108886718750, +0.0022888183593750, 0.0023803710937500, 0.0032348632812500, 0.0023193359375000, +0.0025634765625000, 0.0014648437500000, 0.0032653808593750, 0.0014038085937500, +0.0028076171875000, 0.0011291503906250, 0.0026855468750000, 0.0003051757812500, +0.0031127929687500, 0.0002746582031250, 0.0024414062500000, 0.0004882812500000, +0.0026245117187500, -0.0001220703125000, 0.0025329589843750, 0.0002746582031250, +0.0020446777343750, 0.0010070800781250, 0.0018005371093750, 0.0003662109375000, +0.0016784667968750, 0.0011291503906250, 0.0012207031250000, 0.0013732910156250, +0.0007324218750000, 0.0009155273437500, 0.0010375976562500, 0.0008850097656250, +0.0010986328125000, 0.0011596679687500, 0.0004882812500000, 0.0005187988281250, +0.0018005371093750, 0.0003051757812500, 0.0011901855468750, 0.0006713867187500, +0.0010986328125000, 0.0006713867187500, 0.0019836425781250, 0.0003051757812500, +0.0011291503906250, 0.0009460449218750, 0.0013427734375000, 0.0009460449218750, +0.0011901855468750, 0.0006408691406250, 0.0010070800781250, 0.0009155273437500, +0.0011291503906250, 0.0011291503906250, 0.0009765625000000, 0.0001525878906250, +0.0010375976562500, 0.0006408691406250, 0.0014038085937500, 0.0005187988281250, +0.0012817382812500, -0.0003356933593750, 0.0010986328125000, 0.0004882812500000, +0.0015869140625000, 0.0006713867187500, 0.0009155273437500, 0.0002136230468750, +0.0007629394531250, 0.0011901855468750, 0.0009155273437500, 0.0021057128906250, +0.0006103515625000, 0.0015258789062500, 0.0003662109375000, 0.0031433105468750, +0.0007629394531250, 0.0032043457031250, 0.0005187988281250, 0.0032043457031250, +0.0004272460937500, 0.0040893554687500, 0.0007629394531250, 0.0039062500000000, +0.0005187988281250, 0.0036010742187500, 0.0003662109375000, 0.0040283203125000, +0.0007324218750000, 0.0034790039062500, 0.0006408691406250, 0.0027160644531250, +0.0006103515625000, 0.0032958984375000, 0.0011901855468750, 0.0022888183593750, +0.0006408691406250, 0.0021667480468750, 0.0012512207031250, 0.0024719238281250, +0.0011901855468750, 0.0022277832031250, 0.0006103515625000, 0.0021667480468750, +0.0013427734375000, 0.0029602050781250, 0.0007934570312500, 0.0026855468750000, +0.0007019042968750, 0.0031433105468750, 0.0009765625000000, 0.0038757324218750, +0.0009155273437500, 0.0032043457031250, 0.0007019042968750, 0.0042419433593750, +0.0009155273437500, 0.0041503906250000, 0.0008239746093750, 0.0039672851562500, +0.0007019042968750, 0.0044860839843750, 0.0007019042968750, 0.0043334960937500, +0.0005798339843750, 0.0039062500000000, 0.0004882812500000, 0.0042724609375000, +0.0004882812500000, 0.0038146972656250, 0.0004882812500000, 0.0032653808593750, +0.0004882812500000, 0.0039672851562500, 0.0006103515625000, 0.0027160644531250, +0.0005798339843750, 0.0030212402343750, 0.0005798339843750, 0.0029602050781250, +0.0006713867187500, 0.0021667480468750, 0.0005798339843750, 0.0027160644531250, +0.0003662109375000, 0.0023803710937500, 0.0007934570312500, 0.0023498535156250, +0.0002441406250000, 0.0025939941406250, 0.0002136230468750, 0.0026245117187500, +0.0005493164062500, 0.0026245117187500, -0.0001525878906250, 0.0031127929687500, +0.0003051757812500, 0.0029602050781250, -0.0000305175781250, 0.0032348632812500, +-0.0001220703125000, 0.0036315917968750, 0.0000000000000000, 0.0034179687500000, +-0.0004882812500000, 0.0038452148437500, -0.0001525878906250, 0.0038757324218750, +-0.0003967285156250, 0.0037231445312500, -0.0004882812500000, 0.0039062500000000, +-0.0003051757812500, 0.0039367675781250, -0.0006408691406250, 0.0034484863281250, +-0.0006103515625000, 0.0036315917968750, -0.0006103515625000, 0.0033264160156250, +-0.0008239746093750, 0.0028686523437500, -0.0008239746093750, 0.0031433105468750, +-0.0007629394531250, 0.0021972656250000, -0.0009765625000000, 0.0024414062500000, +-0.0009460449218750, 0.0020446777343750, -0.0008544921875000, 0.0012817382812500, +-0.0010070800781250, 0.0019226074218750, -0.0009460449218750, 0.0006103515625000, +-0.0007324218750000, 0.0009765625000000, -0.0009155273437500, 0.0006408691406250, +-0.0005798339843750, -0.0003662109375000, -0.0002136230468750, 0.0004272460937500, +-0.0005798339843750, -0.0008850097656250, 0.0001220703125000, -0.0007019042968750, +0.0000915527343750, -0.0008850097656250, 0.0000915527343750, -0.0015869140625000, +0.0005187988281250, -0.0010681152343750, 0.0003051757812500, -0.0018310546875000, +0.0006408691406250, -0.0017395019531250, 0.0006713867187500, -0.0016784667968750, +0.0007324218750000, -0.0020751953125000, 0.0009460449218750, -0.0017700195312500, +0.0007324218750000, -0.0018310546875000, 0.0007019042968750, -0.0021057128906250, +0.0007324218750000, -0.0018615722656250, 0.0003662109375000, -0.0017395019531250, +0.0001525878906250, -0.0021362304687500, 0.0002441406250000, -0.0015258789062500, +-0.0002441406250000, -0.0019531250000000, -0.0002441406250000, -0.0019836425781250, +-0.0002136230468750, -0.0015869140625000, -0.0003662109375000, -0.0021972656250000, +-0.0000610351562500, -0.0019531250000000, -0.0002441406250000, -0.0020446777343750, +0.0000915527343750, -0.0024108886718750, 0.0000610351562500, -0.0024414062500000, +-0.0000610351562500, -0.0024108886718750, 0.0004882812500000, -0.0031127929687500, +0.0000915527343750, -0.0030212402343750, 0.0003967285156250, -0.0032958984375000, +0.0005187988281250, -0.0038757324218750, 0.0001831054687500, -0.0035705566406250, +0.0004272460937500, -0.0039062500000000, 0.0004882812500000, -0.0041198730468750, +0.0001220703125000, -0.0038146972656250, 0.0003662109375000, -0.0038146972656250, +0.0006408691406250, -0.0040893554687500, 0.0000305175781250, -0.0030212402343750, +0.0008544921875000, -0.0033874511718750, 0.0003967285156250, -0.0030517578125000, +0.0005798339843750, -0.0021057128906250, 0.0012512207031250, -0.0027160644531250, +0.0005493164062500, -0.0014953613281250, 0.0014343261718750, -0.0017395019531250, +0.0015563964843750, -0.0013427734375000, 0.0014038085937500, -0.0005187988281250, +0.0017700195312500, -0.0011901855468750, 0.0018615722656250, 0.0002746582031250, +0.0014038085937500, -0.0002441406250000, 0.0017089843750000, -0.0000305175781250, +0.0016479492187500, 0.0009765625000000, 0.0011901855468750, 0.0003662109375000, +0.0016174316406250, 0.0015869140625000, 0.0010070800781250, 0.0016174316406250, +0.0011596679687500, 0.0015563964843750, 0.0010375976562500, 0.0022888183593750, +0.0006103515625000, 0.0021667480468750, 0.0008544921875000, 0.0019836425781250, +0.0003356933593750, 0.0020751953125000, 0.0003662109375000, 0.0018920898437500, +0.0003051757812500, 0.0014953613281250, 0.0000000000000000, 0.0015563964843750, +0.0002746582031250, 0.0014038085937500, 0.0000000000000000, 0.0013732910156250, +0.0000610351562500, 0.0012817382812500, 0.0000610351562500, 0.0012512207031250, +-0.0000915527343750, 0.0012512207031250, 0.0001525878906250, 0.0007324218750000, +-0.0001831054687500}, +{-0.0005798339843750, 0.0022277832031250, -0.0007019042968750, 0.0023803710937500, +-0.0007629394531250, 0.0022277832031250, -0.0007629394531250, 0.0013427734375000, +-0.0008239746093750, 0.0018615722656250, -0.0007934570312500, 0.0010375976562500, +-0.0007629394531250, 0.0010986328125000, -0.0007324218750000, 0.0010070800781250, +-0.0006103515625000, 0.0005187988281250, -0.0005187988281250, 0.0007934570312500, +-0.0005187988281250, 0.0004272460937500, -0.0002441406250000, 0.0004272460937500, +-0.0002746582031250, 0.0003967285156250, -0.0002136230468750, 0.0000915527343750, +0.0000000000000000, 0.0002136230468750, -0.0000610351562500, 0.0000915527343750, +0.0000610351562500, -0.0000915527343750, 0.0000305175781250, 0.0000000000000000, +0.0001220703125000, -0.0000915527343750, 0.0003051757812500, -0.0004577636718750, +0.0001525878906250, -0.0000305175781250, 0.0003967285156250, -0.0005187988281250, +0.0003356933593750, -0.0003662109375000, 0.0002746582031250, 0.0000000000000000, +0.0002441406250000, -0.0008544921875000, 0.0000610351562500, 0.0001831054687500, +0.0000000000000000, -0.0003967285156250, -0.0000915527343750, -0.0002441406250000, +-0.0002136230468750, 0.0005187988281250, -0.0001831054687500, -0.0005798339843750, +-0.0000915527343750, 0.0005493164062500, -0.0001831054687500, 0.0000915527343750, +0.0000000000000000, 0.0000915527343750, 0.0000305175781250, 0.0007324218750000, +0.0000000000000000, -0.0000610351562500, 0.0003051757812500, 0.0007324218750000, +0.0000915527343750, 0.0004882812500000, 0.0003356933593750, 0.0004577636718750, +0.0004577636718750, 0.0010070800781250, 0.0002746582031250, 0.0006408691406250, +0.0004882812500000, 0.0009460449218750, 0.0005187988281250, 0.0008850097656250, +0.0003051757812500, 0.0006408691406250, 0.0004577636718750, 0.0006103515625000, +0.0004577636718750, 0.0004577636718750, -0.0000915527343750, 0.0002136230468750, +0.0005798339843750, 0.0000305175781250, 0.0000915527343750, -0.0002136230468750, +0.0001831054687500, -0.0005493164062500, 0.0007019042968750, -0.0008850097656250, +-0.0000610351562500, -0.0010986328125000, 0.0009155273437500, -0.0014343261718750, +0.0007629394531250, -0.0016174316406250, 0.0007324218750000, -0.0017395019531250, +0.0014343261718750, -0.0020446777343750, 0.0013122558593750, -0.0019226074218750, +0.0012512207031250, -0.0021667480468750, 0.0018005371093750, -0.0020446777343750, +0.0016479492187500, -0.0018615722656250, 0.0014038085937500, -0.0022277832031250, +0.0020446777343750, -0.0018005371093750, 0.0014648437500000, -0.0019836425781250, +0.0016784667968750, -0.0021972656250000, 0.0016479492187500, -0.0020751953125000, +0.0012207031250000, -0.0023193359375000, 0.0015563964843750, -0.0020751953125000, +0.0010986328125000, -0.0024414062500000, 0.0010986328125000, -0.0020141601562500, +0.0009460449218750, -0.0014343261718750, 0.0006408691406250, -0.0018920898437500, +0.0008850097656250, -0.0005187988281250, 0.0004577636718750, -0.0005798339843750, +0.0005187988281250, -0.0001831054687500, 0.0005798339843750, 0.0008544921875000, +0.0003356933593750, 0.0003967285156250, 0.0004882812500000, 0.0010070800781250, +0.0002746582031250, 0.0012512207031250, 0.0004577636718750, 0.0012207031250000, +0.0003662109375000, 0.0014648437500000, 0.0001525878906250, 0.0015563964843750, +0.0004882812500000, 0.0019226074218750, 0.0002746582031250, 0.0019226074218750, +0.0004272460937500, 0.0019836425781250, 0.0005493164062500, 0.0021972656250000, +0.0005493164062500, 0.0019531250000000, 0.0007629394531250, 0.0018005371093750, +0.0008850097656250, 0.0017395019531250, 0.0010375976562500, 0.0014343261718750, +0.0012512207031250, 0.0011291503906250, 0.0016479492187500, 0.0012512207031250, +0.0019531250000000, 0.0015869140625000, 0.0017089843750000, 0.0013122558593750, +0.0021667480468750, 0.0013122558593750, 0.0019226074218750, 0.0016479492187500, +0.0017089843750000, 0.0014038085937500, 0.0024719238281250, 0.0009460449218750, +0.0014343261718750, 0.0013122558593750, 0.0018005371093750, 0.0007629394531250, +0.0018310546875000, -0.0000305175781250, 0.0013122558593750, 0.0003662109375000, +0.0019836425781250, -0.0004272460937500, 0.0014038085937500, -0.0007019042968750, +0.0019226074218750, -0.0005798339843750, 0.0016784667968750, -0.0009155273437500, +0.0010986328125000, -0.0010375976562500, 0.0019531250000000, -0.0003967285156250, +0.0007629394531250, -0.0009460449218750, 0.0010070800781250, -0.0004577636718750, +0.0010681152343750, 0.0002746582031250, 0.0004272460937500, -0.0004577636718750, +0.0009460449218750, 0.0011291503906250, 0.0007934570312500, 0.0009460449218750, +0.0008544921875000, 0.0010070800781250, 0.0010375976562500, 0.0020751953125000, +0.0011596679687500, 0.0016784667968750, 0.0014038085937500, 0.0018005371093750, +0.0013427734375000, 0.0021057128906250, 0.0015563964843750, 0.0018615722656250, +0.0015563964843750, 0.0016479492187500, 0.0014038085937500, 0.0019531250000000, +0.0015869140625000, 0.0013122558593750, 0.0016174316406250, 0.0014648437500000, +0.0016479492187500, 0.0013122558593750, 0.0017089843750000, 0.0009460449218750, +0.0017700195312500, 0.0013732910156250, 0.0019226074218750, 0.0004577636718750, +0.0018310546875000, 0.0008544921875000, 0.0020446777343750, 0.0006408691406250, +0.0020141601562500, -0.0000915527343750, 0.0019226074218750, 0.0004577636718750, +0.0022277832031250, 0.0000915527343750, 0.0018920898437500, -0.0002441406250000, +0.0021667480468750, 0.0001525878906250, 0.0021667480468750, 0.0000305175781250, +0.0019531250000000, -0.0005493164062500, 0.0022583007812500, 0.0004272460937500, +0.0018920898437500, -0.0002441406250000, 0.0021667480468750, -0.0001220703125000, +0.0021057128906250, 0.0007019042968750, 0.0018005371093750, -0.0002746582031250, +0.0021667480468750, 0.0008239746093750, 0.0015258789062500, 0.0005493164062500, +0.0017395019531250, 0.0004272460937500, 0.0015869140625000, 0.0010681152343750, +0.0011291503906250, 0.0007324218750000, 0.0014953613281250, 0.0008544921875000, +0.0008544921875000, 0.0010070800781250, 0.0010070800781250, 0.0007934570312500, +0.0009460449218750, 0.0006408691406250, 0.0005798339843750, 0.0006408691406250, +0.0010375976562500, 0.0003051757812500, 0.0004882812500000, 0.0001525878906250, +0.0008850097656250, 0.0000000000000000, 0.0009765625000000, -0.0001525878906250, +0.0007629394531250, -0.0001525878906250, 0.0014953613281250, -0.0005798339843750, +0.0013427734375000, -0.0005187988281250, 0.0017700195312500, -0.0005798339843750, +0.0021362304687500, -0.0009155273437500, 0.0021972656250000, -0.0006713867187500, +0.0027465820312500, -0.0005187988281250, 0.0029907226562500, -0.0006713867187500, +0.0031738281250000, -0.0003356933593750, 0.0034790039062500, 0.0000305175781250, +0.0037536621093750, -0.0002746582031250, 0.0037536621093750, 0.0003967285156250, +0.0040893554687500, 0.0002441406250000, 0.0038757324218750, 0.0002441406250000, +0.0039062500000000, 0.0006713867187500, 0.0040893554687500, 0.0004272460937500, +0.0038757324218750, 0.0003967285156250, 0.0038452148437500, 0.0006713867187500, +0.0037841796875000, 0.0003967285156250, 0.0036010742187500, 0.0000915527343750, +0.0034484863281250, 0.0005187988281250, 0.0035095214843750, -0.0001220703125000, +0.0028991699218750, 0.0000305175781250, 0.0029602050781250, 0.0000610351562500, +0.0027160644531250, -0.0003051757812500, 0.0022583007812500, -0.0000610351562500, +0.0023803710937500, -0.0002441406250000, 0.0018615722656250, -0.0003051757812500, +0.0018310546875000, -0.0001831054687500, 0.0016479492187500, -0.0002136230468750, +0.0012817382812500, -0.0003051757812500, 0.0014038085937500, 0.0000000000000000, +0.0010375976562500, -0.0000305175781250, 0.0008850097656250, 0.0000305175781250, +0.0008850097656250, 0.0002746582031250, 0.0007324218750000, 0.0002441406250000, +0.0006408691406250, 0.0004577636718750, 0.0007934570312500, 0.0004882812500000, +0.0005798339843750, 0.0007019042968750, 0.0007629394531250, 0.0008850097656250, +0.0010681152343750, 0.0006713867187500, 0.0006713867187500, 0.0010681152343750, +0.0014038085937500, 0.0008850097656250, 0.0011901855468750, 0.0007934570312500, +0.0013122558593750, 0.0009460449218750, 0.0019531250000000, 0.0005798339843750, +0.0016479492187500, 0.0006103515625000, 0.0021362304687500, 0.0004882812500000, +0.0022277832031250, 0.0003967285156250, 0.0021667480468750, 0.0004577636718750, +0.0023803710937500, 0.0003356933593750, 0.0023498535156250, 0.0003967285156250, +0.0022277832031250, 0.0005493164062500, 0.0022888183593750, 0.0004577636718750, +0.0020751953125000, 0.0005187988281250, 0.0018615722656250, 0.0007934570312500, +0.0020446777343750, 0.0005798339843750, 0.0018005371093750, 0.0009765625000000, +0.0017700195312500, 0.0010375976562500, 0.0019531250000000, 0.0008239746093750, +0.0018310546875000, 0.0012207031250000, 0.0017089843750000, 0.0008850097656250, +0.0022583007812500, 0.0011291503906250, 0.0020446777343750, 0.0010986328125000, +0.0022583007812500, 0.0008544921875000, 0.0028076171875000, 0.0011596679687500, +0.0024414062500000, 0.0007934570312500, 0.0028991699218750, 0.0010986328125000, +0.0029602050781250, 0.0011291503906250, 0.0026245117187500, 0.0010681152343750, +0.0025939941406250, 0.0017089843750000, 0.0024719238281250, 0.0013427734375000, +0.0017700195312500, 0.0017395019531250, 0.0018920898437500, 0.0019836425781250, +0.0014953613281250, 0.0015869140625000, 0.0007934570312500, 0.0018615722656250, +0.0012207031250000, 0.0021057128906250, 0.0003356933593750, 0.0014648437500000, +0.0003051757812500, 0.0018920898437500, 0.0003051757812500, 0.0022277832031250, +-0.0000305175781250, 0.0010070800781250, 0.0001525878906250, 0.0024108886718750, +-0.0001220703125000, 0.0016784667968750, 0.0001220703125000, 0.0015563964843750, +-0.0001525878906250, 0.0024414062500000, -0.0005798339843750, 0.0016479492187500, +-0.0001220703125000, 0.0023193359375000, -0.0009765625000000, 0.0021972656250000, +-0.0008544921875000, 0.0021667480468750, -0.0009765625000000, 0.0026245117187500, +-0.0015258789062500, 0.0023193359375000, -0.0010986328125000, 0.0028686523437500, +-0.0014953613281250, 0.0027465820312500, -0.0016174316406250, 0.0029907226562500, +-0.0011291503906250, 0.0033874511718750, -0.0010681152343750, 0.0028991699218750, +-0.0011901855468750, 0.0035705566406250, 0.0002136230468750, 0.0034790039062500, +-0.0000610351562500, 0.0034179687500000, 0.0004577636718750, 0.0039062500000000, +0.0015869140625000, 0.0039367675781250, 0.0010375976562500, 0.0038146972656250, +0.0021057128906250, 0.0044250488281250, 0.0020141601562500, 0.0043334960937500, +0.0018615722656250, 0.0040283203125000, 0.0021057128906250, 0.0047302246093750, +0.0016479492187500, 0.0037841796875000, 0.0024108886718750, 0.0039978027343750, +0.0018310546875000, 0.0039367675781250, 0.0022277832031250, 0.0032043457031250, +0.0031433105468750, 0.0036010742187500, 0.0022277832031250, 0.0031433105468750, +0.0029296875000000, 0.0031433105468750, 0.0030212402343750, 0.0031127929687500, +0.0023193359375000, 0.0026245117187500, 0.0018920898437500, 0.0016174316406250, +0.0025939941406250, 0.0015258789062500, 0.0036926269531250, 0.0009460449218750, +0.0039978027343750, 0.0012817382812500, 0.0031127929687500, 0.0014648437500000, +0.0026550292968750, 0.0007629394531250, 0.0032348632812500, 0.0012207031250000, +0.0018310546875000, 0.0009155273437500, 0.0020141601562500, 0.0005493164062500, +0.0022583007812500}, +{0.0039978027343750, 0.0004272460937500, 0.0039672851562500, 0.0004272460937500, +0.0037231445312500, 0.0004272460937500, 0.0039978027343750, 0.0003967285156250, +0.0037231445312500, 0.0004882812500000, 0.0037841796875000, 0.0004577636718750, +0.0038146972656250, 0.0005187988281250, 0.0036926269531250, 0.0007324218750000, +0.0038452148437500, 0.0005798339843750, 0.0038452148437500, 0.0009460449218750, +0.0039672851562500, 0.0010070800781250, 0.0039978027343750, 0.0009765625000000, +0.0040588378906250, 0.0014648437500000, 0.0041809082031250, 0.0011901855468750, +0.0040893554687500, 0.0015258789062500, 0.0041503906250000, 0.0015258789062500, +0.0039978027343750, 0.0012817382812500, 0.0037536621093750, 0.0017089843750000, +0.0039062500000000, 0.0009460449218750, 0.0033264160156250, 0.0012817382812500, +0.0034179687500000, 0.0011596679687500, 0.0032653808593750, 0.0006713867187500, +0.0027465820312500, 0.0014343261718750, 0.0029907226562500, 0.0005493164062500, +0.0027770996093750, 0.0010681152343750, 0.0025634765625000, 0.0012207031250000, +0.0028076171875000, 0.0006713867187500, 0.0029296875000000, 0.0013427734375000, +0.0028381347656250, 0.0013427734375000, 0.0035705566406250, 0.0009765625000000, +0.0033264160156250, 0.0015563964843750, 0.0036315917968750, 0.0017700195312500, +0.0043029785156250, 0.0009155273437500, 0.0038452148437500, 0.0022888183593750, +0.0044250488281250, 0.0014038085937500, 0.0045166015625000, 0.0014648437500000, +0.0043334960937500, 0.0023498535156250, 0.0043029785156250, 0.0010986328125000, +0.0041503906250000, 0.0021972656250000, 0.0040283203125000, 0.0018310546875000, +0.0038146972656250, 0.0018310546875000, 0.0037841796875000, 0.0025329589843750, +0.0037536621093750, 0.0020446777343750, 0.0035095214843750, 0.0026855468750000, +0.0036010742187500, 0.0025634765625000, 0.0034179687500000, 0.0025329589843750, +0.0032348632812500, 0.0028381347656250, 0.0032043457031250, 0.0025329589843750, +0.0029907226562500, 0.0029907226562500, 0.0027770996093750, 0.0026855468750000, +0.0027160644531250, 0.0028991699218750, 0.0021362304687500, 0.0033874511718750, +0.0016479492187500, 0.0029907226562500, 0.0018310546875000, 0.0035095214843750, +0.0007629394531250, 0.0037841796875000, 0.0005493164062500, 0.0034790039062500, +0.0002746582031250, 0.0035705566406250, -0.0004577636718750, 0.0040588378906250, +-0.0003051757812500, 0.0033569335937500, -0.0003967285156250, 0.0035400390625000, +-0.0005798339843750, 0.0034790039062500, -0.0001525878906250, 0.0029907226562500, +0.0002746582031250, 0.0032653808593750, 0.0000000000000000, 0.0027160644531250, +0.0006713867187500, 0.0028076171875000, 0.0004577636718750, 0.0028076171875000, +0.0007629394531250, 0.0025634765625000, 0.0010986328125000, 0.0028381347656250, +0.0005187988281250, 0.0021057128906250, 0.0022277832031250, 0.0022888183593750, +0.0015563964843750, 0.0022277832031250, 0.0018310546875000, 0.0011901855468750, +0.0041809082031250, 0.0008850097656250, 0.0003662109375000, 0.0010070800781250, +0.0020446777343750, 0.0007629394531250, 0.0010375976562500, 0.0005187988281250, +0.0019531250000000, 0.0001831054687500, 0.0035705566406250, -0.0001525878906250, +0.0029296875000000, 0.0002136230468750, 0.0036010742187500, -0.0005187988281250, +0.0041809082031250, -0.0001220703125000, 0.0034484863281250, 0.0006408691406250, +0.0031127929687500, -0.0003051757812500, 0.0038146972656250, 0.0009460449218750, +0.0024108886718750, 0.0009765625000000, 0.0025634765625000, 0.0006408691406250, +0.0025634765625000, 0.0010681152343750, 0.0019836425781250, 0.0009460449218750, +0.0023803710937500, 0.0010070800781250, 0.0017395019531250, 0.0006713867187500, +0.0019531250000000, 0.0012512207031250, 0.0018615722656250, 0.0015258789062500, +0.0013427734375000, 0.0008239746093750, 0.0017395019531250, 0.0028076171875000, +0.0017395019531250, 0.0023498535156250, 0.0012817382812500, 0.0023498535156250, +0.0018005371093750, 0.0036621093750000, 0.0021972656250000, 0.0028991699218750, +0.0016174316406250, 0.0027465820312500, 0.0024108886718750, 0.0029602050781250, +0.0021972656250000, 0.0022583007812500, 0.0018920898437500, 0.0014648437500000, +0.0020446777343750, 0.0016479492187500, 0.0016174316406250, 0.0007629394531250, +0.0014648437500000, 0.0003356933593750, 0.0010681152343750, 0.0005187988281250, +0.0009460449218750, 0.0003051757812500, 0.0009155273437500, -0.0001831054687500, +0.0005493164062500, 0.0005798339843750, 0.0005798339843750, 0.0003967285156250, +0.0005798339843750, 0.0001525878906250, 0.0003356933593750, 0.0005493164062500, +0.0002746582031250, 0.0004577636718750, 0.0004272460937500, -0.0002746582031250, +0.0002136230468750, 0.0001525878906250, 0.0000915527343750, -0.0004882812500000, +0.0003662109375000, -0.0014038085937500, 0.0003967285156250, -0.0006408691406250, +0.0000610351562500, -0.0023193359375000, 0.0005493164062500, -0.0021972656250000, +0.0001831054687500, -0.0020141601562500, 0.0001831054687500, -0.0029296875000000, +0.0005187988281250, -0.0025939941406250, -0.0001220703125000, -0.0020446777343750, +0.0005493164062500, -0.0024108886718750, 0.0002136230468750, -0.0017089843750000, +0.0000610351562500, -0.0007934570312500, 0.0005493164062500, -0.0013122558593750, +0.0002746582031250, 0.0003356933593750, 0.0000915527343750, 0.0003051757812500, +0.0004272460937500, 0.0005187988281250, 0.0002136230468750, 0.0015563964843750, +-0.0000915527343750, 0.0011291503906250, 0.0003662109375000, 0.0014038085937500, +-0.0000610351562500, 0.0017395019531250, 0.0000305175781250, 0.0013122558593750, +0.0002441406250000, 0.0010070800781250, 0.0001220703125000, 0.0014038085937500, +0.0002441406250000, 0.0003967285156250, 0.0004882812500000, 0.0004882812500000, +0.0003662109375000, 0.0002441406250000, 0.0004882812500000, -0.0005798339843750, +0.0007324218750000, -0.0002441406250000, 0.0005187988281250, -0.0008544921875000, +0.0007019042968750, -0.0010681152343750, 0.0007629394531250, -0.0010375976562500, +0.0005798339843750, -0.0014038085937500, 0.0006103515625000, -0.0014648437500000, +0.0007324218750000, -0.0011901855468750, 0.0004272460937500, -0.0015258789062500, +0.0004577636718750, -0.0012512207031250, 0.0005493164062500, -0.0008544921875000, +0.0004577636718750, -0.0013427734375000, 0.0004882812500000, -0.0001525878906250, +0.0004577636718750, -0.0005187988281250, 0.0005798339843750, -0.0001220703125000, +0.0004577636718750, 0.0009155273437500, 0.0004272460937500, 0.0002746582031250, +0.0005187988281250, 0.0014343261718750, 0.0003051757812500, 0.0013732910156250, +0.0003051757812500, 0.0015869140625000, 0.0003051757812500, 0.0023498535156250, +0.0001525878906250, 0.0018920898437500, 0.0003356933593750, 0.0026550292968750, +0.0000610351562500, 0.0027160644531250, 0.0001525878906250, 0.0027770996093750, +0.0002136230468750, 0.0032653808593750, 0.0000000000000000, 0.0031433105468750, +0.0002136230468750, 0.0035095214843750, 0.0001831054687500, 0.0035705566406250, +0.0001525878906250, 0.0036926269531250, 0.0002441406250000, 0.0039367675781250, +0.0003356933593750, 0.0039672851562500, 0.0002746582031250, 0.0040588378906250, +0.0003967285156250, 0.0042724609375000, 0.0003967285156250, 0.0042114257812500, +0.0003662109375000, 0.0042724609375000, 0.0004272460937500, 0.0043945312500000, +0.0003967285156250, 0.0041198730468750, 0.0002136230468750, 0.0042724609375000, +0.0001525878906250, 0.0041198730468750, 0.0000305175781250, 0.0038452148437500, +-0.0001220703125000, 0.0041198730468750, -0.0001831054687500, 0.0035095214843750, +-0.0002136230468750, 0.0036926269531250, -0.0003356933593750, 0.0033874511718750, +-0.0002746582031250, 0.0028686523437500, -0.0001831054687500, 0.0032043457031250, +-0.0003356933593750, 0.0022888183593750, -0.0000305175781250, 0.0023498535156250, +-0.0001220703125000, 0.0022277832031250, -0.0000305175781250, 0.0015869140625000, +0.0001831054687500, 0.0018615722656250, 0.0000000000000000, 0.0015258789062500, +0.0002441406250000, 0.0014648437500000, 0.0002746582031250, 0.0015258789062500, +0.0002136230468750, 0.0013732910156250, 0.0003356933593750, 0.0014648437500000, +0.0002136230468750, 0.0015869140625000, 0.0003356933593750, 0.0013122558593750, +0.0000305175781250, 0.0015563964843750, 0.0001525878906250, 0.0018615722656250, +0.0002441406250000, 0.0015869140625000, -0.0002441406250000, 0.0022888183593750, +0.0005493164062500, 0.0021362304687500, 0.0001525878906250, 0.0021667480468750, +0.0002441406250000, 0.0027160644531250, 0.0008850097656250, 0.0024414062500000, +0.0003967285156250, 0.0025024414062500, 0.0010375976562500, 0.0027160644531250, +0.0011291503906250, 0.0024414062500000, 0.0010986328125000, 0.0022888183593750, +0.0014953613281250, 0.0025939941406250, 0.0014953613281250, 0.0021057128906250, +0.0015258789062500, 0.0021972656250000, 0.0016784667968750, 0.0021972656250000, +0.0016784667968750, 0.0019531250000000, 0.0015258789062500, 0.0021057128906250, +0.0016174316406250, 0.0019531250000000, 0.0014953613281250, 0.0019226074218750, +0.0013427734375000, 0.0019226074218750, 0.0012817382812500, 0.0018920898437500, +0.0011901855468750, 0.0018615722656250, 0.0009765625000000, 0.0017700195312500, +0.0011291503906250, 0.0016784667968750, 0.0008850097656250, 0.0018310546875000, +0.0007934570312500, 0.0017700195312500, 0.0009765625000000, 0.0014648437500000, +0.0008850097656250, 0.0018615722656250, 0.0007019042968750, 0.0014953613281250, +0.0006713867187500, 0.0014343261718750, 0.0006408691406250, 0.0018310546875000, +0.0004882812500000, 0.0015563964843750, 0.0004882812500000, 0.0015563964843750, +0.0004272460937500, 0.0017395019531250, 0.0004882812500000, 0.0014953613281250, +0.0004577636718750, 0.0014038085937500, 0.0004577636718750, 0.0017395019531250, +0.0006103515625000, 0.0010070800781250, 0.0006103515625000, 0.0013732910156250, +0.0006408691406250, 0.0013427734375000, 0.0007934570312500, 0.0007324218750000, +0.0009155273437500, 0.0011291503906250, 0.0010375976562500, 0.0009460449218750, +0.0013427734375000, 0.0009765625000000, 0.0015869140625000, 0.0011596679687500, +0.0015869140625000, 0.0012207031250000, 0.0018005371093750, 0.0013427734375000, +0.0021972656250000, 0.0012512207031250, 0.0016784667968750, 0.0012207031250000, +0.0021057128906250, 0.0014038085937500, 0.0020446777343750, 0.0014343261718750, +0.0015563964843750, 0.0013122558593750, 0.0019226074218750, 0.0022583007812500, +0.0015258789062500, 0.0018005371093750, 0.0017700195312500, 0.0018615722656250, +0.0017089843750000, 0.0024719238281250, 0.0014953613281250, 0.0018920898437500, +0.0019226074218750, 0.0022583007812500, 0.0013732910156250, 0.0020446777343750, +0.0017089843750000, 0.0017089843750000, 0.0018005371093750, 0.0017395019531250, +0.0014648437500000, 0.0014953613281250, 0.0018920898437500, 0.0014038085937500, +0.0015869140625000, 0.0014038085937500, 0.0016784667968750, 0.0012512207031250, +0.0017089843750000, 0.0012817382812500, 0.0014648437500000, 0.0013427734375000, +0.0017395019531250, 0.0008239746093750, 0.0013732910156250, 0.0010681152343750, +0.0013122558593750, 0.0007934570312500, 0.0013122558593750, 0.0002746582031250, +0.0010681152343750, 0.0005187988281250, 0.0010070800781250, -0.0002441406250000, +0.0011291503906250, -0.0002136230468750, 0.0009155273437500, -0.0006408691406250, +0.0010070800781250, -0.0013732910156250, 0.0011596679687500, -0.0010375976562500, +0.0008850097656250}, +{0.0001831054687500, 0.0032043457031250, -0.0003356933593750, 0.0028381347656250, +0.0003662109375000, 0.0027160644531250, -0.0000305175781250, 0.0026245117187500, +0.0000610351562500, 0.0024414062500000, 0.0006408691406250, 0.0022888183593750, +0.0000915527343750, 0.0024414062500000, 0.0006713867187500, 0.0022888183593750, +0.0006713867187500, 0.0023803710937500, 0.0006713867187500, 0.0026245117187500, +0.0010375976562500, 0.0025329589843750, 0.0010375976562500, 0.0030517578125000, +0.0011901855468750, 0.0032043457031250, 0.0014343261718750, 0.0033264160156250, +0.0014343261718750, 0.0038146972656250, 0.0014648437500000, 0.0038146972656250, +0.0016784667968750, 0.0037841796875000, 0.0013122558593750, 0.0039978027343750, +0.0013122558593750, 0.0037536621093750, 0.0012817382812500, 0.0035095214843750, +0.0009765625000000, 0.0038452148437500, 0.0008544921875000, 0.0030822753906250, +0.0008850097656250, 0.0032348632812500, 0.0006713867187500, 0.0031738281250000, +0.0006103515625000, 0.0026245117187500, 0.0006713867187500, 0.0028381347656250, +0.0003967285156250, 0.0025634765625000, 0.0004882812500000, 0.0024108886718750, +0.0005187988281250, 0.0025024414062500, 0.0003356933593750, 0.0025329589843750, +0.0002441406250000, 0.0024108886718750, 0.0003051757812500, 0.0022888183593750, +0.0002441406250000, 0.0023498535156250, 0.0001831054687500, 0.0020141601562500, +0.0002441406250000, 0.0018005371093750, 0.0003051757812500, 0.0019531250000000, +0.0003356933593750, 0.0013732910156250, 0.0003051757812500, 0.0015563964843750, +0.0006103515625000, 0.0016174316406250, 0.0007019042968750, 0.0013427734375000, +0.0007019042968750, 0.0016784667968750, 0.0010375976562500, 0.0018005371093750, +0.0009765625000000, 0.0020141601562500, 0.0012512207031250, 0.0021362304687500, +0.0014038085937500, 0.0021057128906250, 0.0014343261718750, 0.0022277832031250, +0.0017395019531250, 0.0017700195312500, 0.0014648437500000, 0.0018920898437500, +0.0018920898437500, 0.0017395019531250, 0.0017700195312500, 0.0013122558593750, +0.0014343261718750, 0.0015563964843750, 0.0021057128906250, 0.0013732910156250, +0.0014343261718750, 0.0014343261718750, 0.0016479492187500, 0.0014648437500000, +0.0016784667968750, 0.0010375976562500, 0.0013122558593750, 0.0006713867187500, +0.0015563964843750, 0.0006713867187500, 0.0011291503906250, 0.0006103515625000, +0.0013122558593750, 0.0007324218750000, 0.0014343261718750, 0.0008544921875000, +0.0012512207031250, 0.0006713867187500, 0.0014343261718750, 0.0012512207031250, +0.0016174316406250, 0.0011901855468750, 0.0018005371093750, 0.0011901855468750, +0.0016784667968750, 0.0014953613281250, 0.0017089843750000, 0.0013732910156250, +0.0019531250000000, 0.0011596679687500, 0.0014953613281250, 0.0011596679687500, +0.0015563964843750, 0.0010375976562500, 0.0015258789062500, 0.0008239746093750, +0.0010986328125000, 0.0006713867187500, 0.0010375976562500, 0.0007934570312500, +0.0012207031250000, 0.0006713867187500, 0.0011291503906250, 0.0005187988281250, +0.0010986328125000, 0.0006103515625000, 0.0011596679687500, 0.0006103515625000, +0.0011901855468750, 0.0002746582031250, 0.0009460449218750, 0.0003662109375000, +0.0009765625000000, 0.0003051757812500, 0.0008850097656250, 0.0000610351562500, +0.0005798339843750, 0.0001220703125000, 0.0006103515625000, -0.0003051757812500, +0.0004882812500000, -0.0000915527343750, 0.0002441406250000, -0.0004882812500000, +0.0003356933593750, -0.0010681152343750, 0.0004577636718750, -0.0006713867187500, +0.0001831054687500, -0.0013122558593750, 0.0003662109375000, -0.0015258789062500, +0.0003967285156250, -0.0010681152343750, 0.0002136230468750, -0.0011291503906250, +0.0001220703125000, -0.0014953613281250, 0.0001831054687500, -0.0001831054687500, +0.0000000000000000, -0.0006103515625000, -0.0001525878906250, -0.0002136230468750, +-0.0000915527343750, 0.0008850097656250, -0.0001525878906250, 0.0001525878906250, +-0.0003662109375000, 0.0010375976562500, 0.0001220703125000, 0.0012512207031250, +-0.0001525878906250, 0.0010986328125000, 0.0001525878906250, 0.0015563964843750, +0.0007324218750000, 0.0017089843750000, 0.0002441406250000, 0.0013122558593750, +0.0011291503906250, 0.0018310546875000, 0.0010070800781250, 0.0016479492187500, +0.0011291503906250, 0.0012512207031250, 0.0016784667968750, 0.0019226074218750, +0.0013427734375000, 0.0009155273437500, 0.0020141601562500, 0.0012207031250000, +0.0018005371093750, 0.0011596679687500, 0.0020446777343750, 0.0004882812500000, +0.0025329589843750, 0.0009765625000000, 0.0021057128906250, 0.0002441406250000, +0.0028991699218750, 0.0003967285156250, 0.0027160644531250, 0.0002746582031250, +0.0028076171875000, -0.0000915527343750, 0.0032653808593750, 0.0002441406250000, +0.0028381347656250, -0.0002746582031250, 0.0032043457031250, -0.0001525878906250, +0.0031738281250000, -0.0000610351562500, 0.0029602050781250, -0.0003051757812500, +0.0029907226562500, 0.0000000000000000, 0.0028076171875000, 0.0000000000000000, +0.0025024414062500, 0.0000610351562500, 0.0025024414062500, 0.0002136230468750, +0.0021972656250000, 0.0002746582031250, 0.0018615722656250, 0.0003662109375000, +0.0019531250000000, 0.0002136230468750, 0.0012817382812500, 0.0003662109375000, +0.0012817382812500, 0.0003051757812500, 0.0011901855468750, 0.0001220703125000, +0.0007324218750000, 0.0002441406250000, 0.0009155273437500, 0.0000000000000000, +0.0010070800781250, 0.0001220703125000, 0.0009155273437500, 0.0001831054687500, +0.0012512207031250, 0.0000000000000000, 0.0015563964843750, 0.0001831054687500, +0.0014038085937500, 0.0001525878906250, 0.0020446777343750, 0.0001220703125000, +0.0021362304687500, 0.0002136230468750, 0.0022277832031250, 0.0003356933593750, +0.0026855468750000, 0.0003662109375000, 0.0025634765625000, 0.0004577636718750, +0.0027465820312500, 0.0006408691406250, 0.0029907226562500, 0.0006713867187500, +0.0027770996093750, 0.0007629394531250, 0.0026245117187500, 0.0010681152343750, +0.0028991699218750, 0.0008544921875000, 0.0022583007812500, 0.0011596679687500, +0.0023803710937500, 0.0011596679687500, 0.0021667480468750, 0.0010070800781250, +0.0016479492187500, 0.0012207031250000, 0.0018920898437500, 0.0010681152343750, +0.0013122558593750, 0.0010375976562500, 0.0013732910156250, 0.0010070800781250, +0.0014038085937500, 0.0008850097656250, 0.0010375976562500, 0.0007019042968750, +0.0012817382812500, 0.0005798339843750, 0.0013732910156250, 0.0004577636718750, +0.0011901855468750, 0.0003356933593750, 0.0015258789062500, 0.0002746582031250, +0.0018310546875000, 0.0003051757812500, 0.0015563964843750, 0.0002746582031250, +0.0023803710937500, 0.0003356933593750, 0.0022888183593750, 0.0003662109375000, +0.0024719238281250, 0.0004272460937500, 0.0030517578125000, 0.0006408691406250, +0.0028381347656250, 0.0005798339843750, 0.0034484863281250, 0.0007934570312500, +0.0033874511718750, 0.0008544921875000, 0.0035095214843750, 0.0008239746093750, +0.0039367675781250, 0.0012207031250000, 0.0036621093750000, 0.0008850097656250, +0.0039672851562500, 0.0010986328125000, 0.0040283203125000, 0.0010681152343750, +0.0038757324218750, 0.0008239746093750, 0.0038452148437500, 0.0011596679687500, +0.0039672851562500, 0.0005493164062500, 0.0034790039062500, 0.0010375976562500, +0.0036621093750000, 0.0007934570312500, 0.0034179687500000, 0.0003051757812500, +0.0029602050781250, 0.0011901855468750, 0.0032653808593750, 0.0000915527343750, +0.0026245117187500, 0.0007019042968750, 0.0026550292968750, 0.0008850097656250, +0.0026550292968750, 0.0002441406250000, 0.0023193359375000, 0.0011291503906250, +0.0025329589843750, 0.0007934570312500, 0.0025329589843750, 0.0006713867187500, +0.0026245117187500, 0.0010681152343750, 0.0027770996093750, 0.0008850097656250, +0.0029296875000000, 0.0005798339843750, 0.0030822753906250, 0.0012207031250000, +0.0030517578125000, 0.0005187988281250, 0.0033264160156250, 0.0007629394531250, +0.0031433105468750, 0.0014648437500000, 0.0030517578125000, 0.0004882812500000, +0.0035095214843750, 0.0017700195312500, 0.0024108886718750, 0.0015563964843750, +0.0029907226562500, 0.0015563964843750, 0.0026550292968750, 0.0023498535156250, +0.0017089843750000, 0.0020141601562500, 0.0026245117187500, 0.0024108886718750, +0.0014953613281250, 0.0024414062500000, 0.0017700195312500, 0.0024719238281250, +0.0017700195312500, 0.0025329589843750, 0.0011291503906250, 0.0023803710937500, +0.0018005371093750, 0.0026550292968750, 0.0010070800781250, 0.0025634765625000, +0.0011596679687500, 0.0023498535156250, 0.0011291503906250, 0.0024719238281250, +0.0005798339843750, 0.0024108886718750, 0.0007629394531250, 0.0018920898437500, +0.0002746582031250, 0.0022888183593750, 0.0002746582031250, 0.0016784667968750, +0.0000305175781250, 0.0010681152343750, -0.0005187988281250, 0.0019836425781250, +-0.0004272460937500, 0.0008239746093750, -0.0004882812500000, 0.0011291503906250, +-0.0009155273437500, 0.0011901855468750, -0.0003662109375000, 0.0005493164062500, +0.0000305175781250, 0.0010375976562500, -0.0006103515625000, 0.0002441406250000, +0.0014038085937500, 0.0003662109375000, 0.0009155273437500, 0.0002746582031250, +0.0011901855468750, -0.0003051757812500, 0.0025939941406250, 0.0001525878906250, +0.0016784667968750, -0.0001525878906250, 0.0021362304687500, -0.0001525878906250, +0.0023498535156250, -0.0000305175781250, 0.0018920898437500, -0.0000305175781250, +0.0017089843750000, 0.0000915527343750, 0.0018920898437500, -0.0000610351562500, +0.0012817382812500, -0.0000915527343750, 0.0014343261718750, -0.0001220703125000, +0.0012817382812500, -0.0003662109375000, 0.0005493164062500, -0.0007019042968750, +0.0008850097656250, 0.0000305175781250, 0.0008544921875000, 0.0002746582031250, +0.0010986328125000, 0.0001831054687500, 0.0007019042968750, 0.0003051757812500, +0.0005493164062500, 0.0008544921875000, 0.0010070800781250, 0.0002136230468750, +-0.0003051757812500, 0.0005493164062500, 0.0000610351562500, 0.0008850097656250, +0.0000000000000000, 0.0006103515625000, -0.0009765625000000, 0.0009460449218750, +-0.0005798339843750, 0.0011901855468750, -0.0000610351562500, 0.0015258789062500, +-0.0004272460937500, 0.0011901855468750, 0.0003967285156250, 0.0010681152343750, +0.0016174316406250, 0.0014953613281250, 0.0011901855468750, -0.0003967285156250, +0.0025939941406250, -0.0000610351562500, 0.0028076171875000, -0.0004882812500000, +0.0028381347656250, -0.0020141601562500, 0.0034790039062500, -0.0012207031250000, +0.0033874511718750, -0.0015869140625000, 0.0032958984375000, -0.0019836425781250, +0.0035705566406250, -0.0014038085937500, 0.0031738281250000, -0.0007934570312500, +0.0028686523437500, -0.0010986328125000, 0.0032348632812500, -0.0004882812500000, +0.0018920898437500, -0.0003662109375000, 0.0021057128906250, -0.0006408691406250, +0.0017395019531250, -0.0006103515625000, 0.0006103515625000, -0.0007019042968750, +0.0009765625000000, -0.0012512207031250, 0.0007324218750000, -0.0014648437500000, +0.0003662109375000, -0.0014648437500000, 0.0008544921875000, -0.0019226074218750, +0.0011901855468750, -0.0021362304687500, 0.0006713867187500, -0.0011596679687500, +0.0013122558593750, -0.0017395019531250, 0.0012512207031250, -0.0012817382812500, +0.0009765625000000, -0.0001220703125000, 0.0009460449218750, -0.0008544921875000, +0.0007934570312500, 0.0005493164062500, 0.0005493164062500, 0.0006713867187500, +0.0003662109375000}, +{0.0029907226562500, 0.0016784667968750, 0.0029296875000000, 0.0016174316406250, +0.0031738281250000, 0.0016174316406250, 0.0034484863281250, 0.0017089843750000, +0.0033874511718750, 0.0017395019531250, 0.0036926269531250, 0.0017089843750000, +0.0036621093750000, 0.0017395019531250, 0.0037231445312500, 0.0017395019531250, +0.0038146972656250, 0.0016479492187500, 0.0036621093750000, 0.0014038085937500, +0.0038146972656250, 0.0015869140625000, 0.0037231445312500, 0.0012817382812500, +0.0036010742187500, 0.0008850097656250, 0.0036010742187500, 0.0013122558593750, +0.0034484863281250, 0.0006103515625000, 0.0032958984375000, 0.0008544921875000, +0.0032958984375000, 0.0006408691406250, 0.0029907226562500, 0.0001220703125000, +0.0028686523437500, 0.0007629394531250, 0.0031127929687500, -0.0002441406250000, +0.0019531250000000, 0.0001831054687500, 0.0023498535156250, 0.0000305175781250, +0.0016784667968750, -0.0006713867187500, 0.0005187988281250, 0.0000610351562500, +0.0012512207031250, -0.0007629394531250, -0.0003967285156250, -0.0004577636718750, +-0.0004882812500000, -0.0004577636718750, -0.0003662109375000, -0.0009460449218750, +-0.0011901855468750, -0.0003967285156250, -0.0009765625000000, -0.0010681152343750, +-0.0004272460937500, -0.0009460449218750, -0.0007324218750000, -0.0008850097656250, +-0.0003051757812500, -0.0013427734375000, 0.0004272460937500, -0.0011596679687500, +0.0000000000000000, -0.0010986328125000, 0.0006103515625000, -0.0012207031250000, +0.0008239746093750, -0.0009765625000000, 0.0007019042968750, -0.0003356933593750, +0.0008544921875000, -0.0003662109375000, -0.0011291503906250, -0.0009460449218750, +-0.0004882812500000, -0.0005798339843750, -0.0007324218750000, -0.0003662109375000, +-0.0004577636718750, -0.0003051757812500, 0.0000305175781250, -0.0000610351562500, +-0.0001525878906250, -0.0001525878906250, 0.0004577636718750, 0.0005493164062500, +0.0006103515625000, 0.0000915527343750, 0.0003356933593750, -0.0003662109375000, +0.0006103515625000, 0.0006408691406250, 0.0008850097656250, -0.0013122558593750, +-0.0005187988281250, -0.0008850097656250, -0.0000610351562500, -0.0009155273437500, +-0.0003356933593750, -0.0022583007812500, -0.0015563964843750, -0.0016174316406250, +-0.0009155273437500, -0.0015869140625000, -0.0010375976562500, -0.0018615722656250, +-0.0013122558593750, -0.0012817382812500, -0.0005493164062500, -0.0005493164062500, +0.0001220703125000, -0.0009155273437500, -0.0001525878906250, -0.0005493164062500, +0.0011596679687500, -0.0001220703125000, 0.0012207031250000, -0.0005493164062500, +0.0014953613281250, -0.0009155273437500, 0.0023803710937500, -0.0007629394531250, +0.0021057128906250, -0.0010986328125000, 0.0027770996093750, -0.0015258789062500, +0.0030212402343750, -0.0012207031250000, 0.0026550292968750, -0.0011901855468750, +0.0027465820312500, -0.0017395019531250, 0.0028991699218750, -0.0002441406250000, +0.0015869140625000, -0.0008239746093750, 0.0018310546875000, -0.0002441406250000, +0.0014648437500000, 0.0011596679687500, 0.0003051757812500, 0.0002136230468750, +0.0006713867187500, 0.0018310546875000, 0.0004577636718750, 0.0018005371093750, +0.0000000000000000, 0.0018615722656250, 0.0002441406250000, 0.0027770996093750, +0.0005187988281250, 0.0022583007812500, 0.0001525878906250, 0.0025939941406250, +0.0003356933593750, 0.0028076171875000, 0.0003356933593750, 0.0025329589843750, +0.0002136230468750, 0.0025024414062500, 0.0001220703125000, 0.0025634765625000, +0.0000305175781250, 0.0022277832031250, 0.0000305175781250, 0.0024414062500000, +-0.0000610351562500, 0.0022277832031250, -0.0000305175781250, 0.0019531250000000, +0.0001220703125000, 0.0024108886718750, 0.0001220703125000, 0.0016174316406250, +0.0000000000000000, 0.0018615722656250, 0.0000305175781250, 0.0020751953125000, +0.0000610351562500, 0.0015563964843750, -0.0000915527343750, 0.0019836425781250, +-0.0003051757812500, 0.0023193359375000, 0.0001525878906250, 0.0021972656250000, +-0.0002746582031250, 0.0026550292968750, -0.0002136230468750, 0.0031738281250000, +0.0001831054687500, 0.0029602050781250, -0.0003967285156250, 0.0035705566406250, +0.0000000000000000, 0.0037231445312500, -0.0001831054687500, 0.0037536621093750, +-0.0002746582031250, 0.0039672851562500, -0.0000610351562500, 0.0039062500000000, +-0.0001831054687500, 0.0037536621093750, -0.0001525878906250, 0.0039367675781250, +0.0000915527343750, 0.0038146972656250, 0.0000305175781250, 0.0035705566406250, +0.0000000000000000, 0.0036621093750000, 0.0004272460937500, 0.0035095214843750, +-0.0000305175781250, 0.0033264160156250, 0.0002136230468750, 0.0033874511718750, +0.0002746582031250, 0.0033874511718750, -0.0000305175781250, 0.0032653808593750, +0.0004272460937500, 0.0036315917968750, 0.0000000000000000, 0.0035705566406250, +0.0002441406250000, 0.0038146972656250, 0.0001831054687500, 0.0043029785156250, +-0.0001525878906250, 0.0042419433593750, 0.0002441406250000, 0.0048522949218750, +-0.0001525878906250, 0.0049743652343750, 0.0001220703125000, 0.0051879882812500, +0.0002136230468750, 0.0055847167968750, 0.0000305175781250, 0.0055847167968750, +0.0003662109375000, 0.0057983398437500, 0.0004272460937500, 0.0058593750000000, +0.0004882812500000, 0.0058288574218750, 0.0005798339843750, 0.0058288574218750, +0.0006103515625000, 0.0057373046875000, 0.0007019042968750, 0.0056457519531250, +0.0008239746093750, 0.0055847167968750, 0.0008850097656250, 0.0055847167968750, +0.0008544921875000, 0.0054626464843750, 0.0007934570312500, 0.0054016113281250, +0.0008850097656250, 0.0053405761718750, 0.0006103515625000, 0.0052795410156250, +0.0006408691406250, 0.0051269531250000, 0.0004577636718750, 0.0050354003906250, +0.0002136230468750, 0.0050964355468750, 0.0002746582031250, 0.0045166015625000, +0.0000305175781250, 0.0047607421875000, -0.0000305175781250, 0.0043029785156250, +0.0000000000000000, 0.0037231445312500, -0.0001525878906250, 0.0042419433593750, +-0.0002136230468750, 0.0028381347656250, -0.0002136230468750, 0.0031127929687500, +-0.0003356933593750, 0.0027160644531250, -0.0003051757812500, 0.0016479492187500, +-0.0001525878906250, 0.0022583007812500, -0.0003662109375000, 0.0010375976562500, +-0.0001831054687500, 0.0010681152343750, -0.0001831054687500, 0.0009460449218750, +-0.0001831054687500, 0.0001831054687500, -0.0001525878906250, 0.0006103515625000, +-0.0001525878906250, 0.0002136230468750, -0.0000610351562500, 0.0001525878906250, +-0.0001831054687500, 0.0002441406250000, -0.0000915527343750, 0.0002136230468750, +0.0000305175781250, 0.0002746582031250, -0.0002136230468750, 0.0003356933593750, +0.0002136230468750, 0.0003967285156250, 0.0000915527343750, 0.0003356933593750, +0.0001831054687500, 0.0004272460937500, 0.0006103515625000, 0.0004882812500000, +0.0004272460937500, 0.0002746582031250, 0.0008544921875000, 0.0004882812500000, +0.0009765625000000, 0.0003662109375000, 0.0010986328125000, 0.0001525878906250, +0.0014343261718750, 0.0004882812500000, 0.0014343261718750, 0.0003662109375000, +0.0014648437500000, 0.0003051757812500, 0.0017089843750000, 0.0005187988281250, +0.0015563964843750, 0.0006103515625000, 0.0014038085937500, 0.0005798339843750, +0.0016174316406250, 0.0009155273437500, 0.0011901855468750, 0.0008544921875000, +0.0011596679687500, 0.0008544921875000, 0.0011291503906250, 0.0010070800781250, +0.0009765625000000, 0.0010375976562500, 0.0008544921875000, 0.0009460449218750, +0.0006713867187500, 0.0010986328125000, 0.0007019042968750, 0.0010681152343750, +0.0005187988281250, 0.0009765625000000, 0.0002746582031250, 0.0011901855468750, +0.0003356933593750, 0.0010986328125000, 0.0000305175781250, 0.0012512207031250, +0.0000610351562500, 0.0014038085937500, -0.0000305175781250, 0.0014343261718750, +-0.0001831054687500, 0.0015258789062500, 0.0000610351562500, 0.0017700195312500, +-0.0001525878906250, 0.0018920898437500, -0.0000915527343750, 0.0018310546875000, +-0.0000305175781250, 0.0018920898437500, -0.0001525878906250, 0.0019531250000000, +0.0001525878906250, 0.0016174316406250, 0.0001220703125000, 0.0015563964843750, +0.0003051757812500, 0.0016479492187500, 0.0004272460937500, 0.0014038085937500, +0.0004577636718750, 0.0012817382812500, 0.0006408691406250, 0.0017395019531250, +0.0005493164062500, 0.0013427734375000, 0.0008239746093750, 0.0015563964843750, +0.0008544921875000, 0.0021057128906250, 0.0007019042968750, 0.0015869140625000, +0.0009765625000000, 0.0020141601562500, 0.0007629394531250, 0.0021667480468750, +0.0010375976562500, 0.0018615722656250, 0.0010070800781250, 0.0018615722656250, +0.0009155273437500, 0.0021667480468750, 0.0013427734375000, 0.0018920898437500, +0.0008239746093750, 0.0020141601562500, 0.0011901855468750, 0.0021972656250000, +0.0011901855468750, 0.0021972656250000, 0.0007629394531250, 0.0024719238281250, +0.0012207031250000, 0.0021667480468750, 0.0010375976562500, 0.0024414062500000, +0.0010986328125000, 0.0023803710937500, 0.0010986328125000, 0.0017089843750000, +0.0011901855468750, 0.0012817382812500, 0.0015869140625000, 0.0007019042968750, +0.0007324218750000, 0.0009765625000000, 0.0011901855468750, 0.0008544921875000, +0.0010375976562500, 0.0005187988281250, 0.0003051757812500, 0.0007324218750000, +0.0008544921875000, 0.0002136230468750, 0.0001831054687500, 0.0003356933593750, +0.0000000000000000, 0.0001220703125000, 0.0002441406250000, -0.0003356933593750, +0.0000000000000000, -0.0000305175781250, -0.0001831054687500, -0.0006103515625000, +0.0002746582031250, -0.0007629394531250, 0.0000610351562500, -0.0005187988281250, +0.0000915527343750, -0.0005798339843750, 0.0004272460937500, -0.0006103515625000, +0.0001525878906250, -0.0002136230468750, 0.0006103515625000, -0.0001831054687500, +0.0004882812500000, -0.0000305175781250, 0.0004882812500000, 0.0002136230468750, +0.0007934570312500, 0.0001220703125000, 0.0006103515625000, 0.0006713867187500, +0.0006713867187500, 0.0005187988281250, 0.0009155273437500, 0.0004577636718750, +0.0007019042968750, 0.0008544921875000, 0.0005493164062500, 0.0006103515625000, +0.0009155273437500, 0.0004882812500000, 0.0004577636718750, 0.0005187988281250, +0.0006103515625000, 0.0003967285156250, 0.0008850097656250, 0.0000305175781250, +0.0008239746093750, -0.0000915527343750, 0.0010681152343750, -0.0002136230468750, +0.0012512207031250, -0.0004272460937500, 0.0015563964843750, -0.0003967285156250, +0.0016174316406250, -0.0003356933593750, 0.0016479492187500, -0.0003967285156250, +0.0020446777343750, -0.0002441406250000, 0.0017395019531250, -0.0001525878906250, +0.0019836425781250, -0.0001831054687500, 0.0021362304687500, -0.0000915527343750, +0.0019226074218750, 0.0000915527343750, 0.0020751953125000, -0.0000610351562500, +0.0021362304687500, -0.0000610351562500, 0.0019836425781250, 0.0003051757812500, +0.0021667480468750, 0.0003051757812500, 0.0023803710937500, 0.0001525878906250, +0.0020141601562500, 0.0008239746093750, 0.0024108886718750, 0.0007629394531250, +0.0021972656250000, 0.0008544921875000, 0.0019836425781250, 0.0014648437500000, +0.0020446777343750, 0.0014038085937500, 0.0017700195312500, 0.0013732910156250, +0.0015563964843750, 0.0018005371093750, 0.0014648437500000, 0.0016784667968750, +0.0012512207031250, 0.0014953613281250, 0.0009460449218750, 0.0020446777343750, +0.0010070800781250, 0.0013732910156250, 0.0007934570312500, 0.0017395019531250, +0.0006713867187500, 0.0016784667968750, 0.0008544921875000, 0.0011596679687500, +0.0008544921875000}, +{-0.0001220703125000, 0.0012817382812500, -0.0001525878906250, 0.0011596679687500, +0.0000305175781250, 0.0014953613281250, -0.0000915527343750, 0.0013427734375000, +-0.0000305175781250, 0.0012512207031250, 0.0001831054687500, 0.0014038085937500, +0.0002746582031250, 0.0011901855468750, 0.0003662109375000, 0.0010375976562500, +0.0004577636718750, 0.0011596679687500, 0.0007629394531250, 0.0010681152343750, +0.0006713867187500, 0.0009155273437500, 0.0005798339843750, 0.0011291503906250, +0.0010986328125000, 0.0010986328125000, 0.0006103515625000, 0.0011901855468750, +0.0006713867187500, 0.0013732910156250, 0.0008544921875000, 0.0013732910156250, +0.0006103515625000, 0.0014038085937500, 0.0006408691406250, 0.0016479492187500, +0.0005187988281250, 0.0015563964843750, 0.0006408691406250, 0.0016174316406250, +0.0003967285156250, 0.0016479492187500, 0.0001831054687500, 0.0011901855468750, +0.0005187988281250, 0.0010070800781250, -0.0001220703125000, 0.0010986328125000, +0.0000915527343750, 0.0009765625000000, 0.0001525878906250, 0.0007934570312500, +-0.0003051757812500, 0.0009765625000000, 0.0000305175781250, 0.0006713867187500, +-0.0000305175781250, 0.0006103515625000, -0.0003051757812500, 0.0005493164062500, +-0.0000305175781250, 0.0005187988281250, 0.0000915527343750, 0.0006103515625000, +-0.0003356933593750, 0.0000610351562500, 0.0003967285156250, 0.0003967285156250, +0.0000915527343750, -0.0001525878906250, 0.0001525878906250, -0.0008850097656250, +0.0007629394531250, -0.0002136230468750, 0.0003967285156250, -0.0012512207031250, +0.0006103515625000, -0.0012207031250000, 0.0008239746093750, -0.0009460449218750, +0.0006408691406250, -0.0013732910156250, 0.0005798339843750, -0.0011901855468750, +0.0006408691406250, -0.0007934570312500, 0.0006103515625000, -0.0010986328125000, +0.0005493164062500, -0.0006103515625000, 0.0006713867187500, -0.0000915527343750, +0.0009155273437500, -0.0006103515625000, 0.0009460449218750, 0.0003967285156250, +0.0011596679687500, 0.0002441406250000, 0.0015258789062500, 0.0002746582031250, +0.0015258789062500, 0.0009460449218750, 0.0015869140625000, 0.0004882812500000, +0.0021362304687500, 0.0006103515625000, 0.0011596679687500, 0.0006408691406250, +0.0017089843750000, 0.0002136230468750, 0.0016174316406250, 0.0000610351562500, +0.0008850097656250, 0.0000915527343750, 0.0015258789062500, -0.0003662109375000, +0.0010070800781250, -0.0003967285156250, 0.0009765625000000, -0.0002441406250000, +0.0010986328125000, -0.0002441406250000, 0.0007934570312500, -0.0002136230468750, +0.0007934570312500, 0.0001525878906250, 0.0005493164062500, 0.0002746582031250, +0.0004577636718750, 0.0004272460937500, 0.0002136230468750, 0.0007019042968750, +-0.0000305175781250, 0.0007629394531250, -0.0000915527343750, 0.0007934570312500, +-0.0006713867187500, 0.0009460449218750, -0.0008239746093750, 0.0010070800781250, +-0.0010070800781250, 0.0010070800781250, -0.0013732910156250, 0.0010986328125000, +-0.0013732910156250, 0.0012512207031250, -0.0014343261718750, 0.0013732910156250, +-0.0016784667968750, 0.0014648437500000, -0.0014953613281250, 0.0016174316406250, +-0.0014648437500000, 0.0017700195312500, -0.0017089843750000, 0.0016174316406250, +-0.0010681152343750, 0.0018310546875000, -0.0012512207031250, 0.0018005371093750, +-0.0010681152343750, 0.0016784667968750, -0.0005187988281250, 0.0019226074218750, +-0.0008544921875000, 0.0015563964843750, -0.0003662109375000, 0.0016479492187500, +-0.0002746582031250, 0.0015258789062500, -0.0003967285156250, 0.0011901855468750, +-0.0002441406250000, 0.0013732910156250, -0.0002136230468750, 0.0009765625000000, +-0.0003051757812500, 0.0009460449218750, -0.0003662109375000, 0.0009765625000000, +-0.0003356933593750, 0.0008544921875000, -0.0004272460937500, 0.0007019042968750, +-0.0004882812500000, 0.0007324218750000, -0.0002746582031250, 0.0007019042968750, +-0.0005493164062500, 0.0004882812500000, -0.0002746582031250, 0.0003662109375000, +0.0000305175781250, 0.0004882812500000, -0.0003967285156250, 0.0000305175781250, +0.0006713867187500, 0.0002441406250000, 0.0003051757812500, 0.0002136230468750, +0.0007629394531250, -0.0000915527343750, 0.0017395019531250, 0.0001220703125000, +0.0010375976562500, 0.0000915527343750, 0.0024719238281250, 0.0000915527343750, +0.0022277832031250, 0.0002136230468750, 0.0025024414062500, 0.0002441406250000, +0.0034790039062500, 0.0002136230468750, 0.0027770996093750, 0.0003356933593750, +0.0040283203125000, 0.0002441406250000, 0.0037841796875000, 0.0003051757812500, +0.0039672851562500, 0.0003662109375000, 0.0048217773437500, 0.0001525878906250, +0.0041198730468750, 0.0003356933593750, 0.0050964355468750, 0.0001831054687500, +0.0049438476562500, 0.0000915527343750, 0.0048522949218750, 0.0002136230468750, +0.0053100585937500, 0.0000915527343750, 0.0049743652343750, 0.0001525878906250, +0.0048522949218750, 0.0002136230468750, 0.0049438476562500, 0.0002136230468750, +0.0045471191406250, 0.0003051757812500, 0.0041809082031250, 0.0003662109375000, +0.0044555664062500, 0.0003356933593750, 0.0035095214843750, 0.0005187988281250, +0.0037231445312500, 0.0005493164062500, 0.0033569335937500, 0.0005187988281250, +0.0026550292968750, 0.0007324218750000, 0.0031738281250000, 0.0005798339843750, +0.0021057128906250, 0.0006713867187500, 0.0022583007812500, 0.0007019042968750, +0.0020751953125000, 0.0006103515625000, 0.0013122558593750, 0.0006713867187500, +0.0018005371093750, 0.0004882812500000, 0.0007934570312500, 0.0006103515625000, +0.0009155273437500, 0.0003967285156250, 0.0007934570312500, 0.0002136230468750, +0.0001831054687500, 0.0006408691406250, 0.0005493164062500, -0.0000610351562500, +-0.0000305175781250, 0.0003662109375000, -0.0000305175781250, 0.0003967285156250, +0.0000000000000000, -0.0000305175781250, -0.0001525878906250, 0.0007324218750000, +0.0000000000000000, 0.0002746582031250, 0.0002136230468750, 0.0004577636718750, +0.0002441406250000, 0.0007324218750000, 0.0004272460937500, 0.0004577636718750, +0.0007324218750000, 0.0003662109375000, 0.0007934570312500, 0.0007324218750000, +0.0009460449218750, 0.0001525878906250, 0.0013732910156250, 0.0003051757812500, +0.0012512207031250, 0.0006103515625000, 0.0013122558593750, -0.0001831054687500, +0.0017089843750000, 0.0006408691406250, 0.0006103515625000, 0.0003662109375000, +0.0012207031250000, 0.0001831054687500, 0.0007629394531250, 0.0006408691406250, +-0.0002441406250000, 0.0005493164062500, 0.0006408691406250, 0.0004577636718750, +-0.0010070800781250, 0.0008544921875000, -0.0005493164062500, 0.0007324218750000, +-0.0005798339843750, 0.0004882812500000, -0.0015563964843750, 0.0009765625000000, +-0.0007629394531250, 0.0002746582031250, -0.0014953613281250, 0.0006103515625000, +-0.0012207031250000, 0.0005187988281250, -0.0012207031250000, 0.0000915527343750, +-0.0016479492187500, 0.0005798339843750, -0.0011596679687500, 0.0000610351562500, +-0.0018615722656250, 0.0003967285156250, -0.0017700195312500, 0.0002441406250000, +-0.0018005371093750, -0.0001220703125000, -0.0022277832031250, 0.0006408691406250, +-0.0020141601562500, -0.0003051757812500, -0.0020446777343750, 0.0001525878906250, +-0.0022583007812500, 0.0000305175781250, -0.0019226074218750, -0.0007019042968750, +-0.0018310546875000, 0.0000305175781250, -0.0020141601562500, -0.0009155273437500, +-0.0009155273437500, -0.0006408691406250, -0.0013122558593750, -0.0007324218750000, +-0.0008544921875000, -0.0012817382812500, 0.0000915527343750, -0.0008544921875000, +-0.0006103515625000, -0.0015258789062500, 0.0004882812500000, -0.0013732910156250, +0.0003662109375000, -0.0014343261718750, 0.0003967285156250, -0.0018310546875000, +0.0010681152343750, -0.0015563964843750, 0.0008850097656250, -0.0017089843750000, +0.0014343261718750, -0.0018005371093750, 0.0014343261718750, -0.0014343261718750, +0.0017395019531250, -0.0012817382812500, 0.0023803710937500, -0.0014953613281250, +0.0022583007812500, -0.0009155273437500, 0.0025024414062500, -0.0009155273437500, +0.0030822753906250, -0.0012207031250000, 0.0023498535156250, -0.0010681152343750, +0.0020446777343750, -0.0009460449218750, 0.0028686523437500, -0.0014343261718750, +0.0003356933593750, -0.0013122558593750, 0.0010070800781250, -0.0010986328125000, +0.0008239746093750, -0.0013122558593750, -0.0021972656250000, -0.0005187988281250, +0.0024719238281250, -0.0014953613281250, 0.0006713867187500, -0.0009765625000000, +0.0017089843750000, -0.0010375976562500, 0.0007629394531250, -0.0016174316406250, +-0.0006408691406250, -0.0012817382812500, -0.0000305175781250, -0.0008544921875000, +-0.0013122558593750, -0.0011291503906250, -0.0012817382812500, -0.0008239746093750, +-0.0014953613281250, -0.0001831054687500, -0.0024108886718750, -0.0005187988281250, +-0.0020751953125000, -0.0006103515625000, -0.0025939941406250, -0.0001831054687500, +-0.0029907226562500, -0.0004882812500000, -0.0024414062500000, -0.0009765625000000, +-0.0021667480468750, -0.0003662109375000, -0.0025024414062500, -0.0005187988281250, +-0.0011596679687500, -0.0008239746093750, -0.0010375976562500, 0.0000915527343750, +-0.0009765625000000, 0.0006713867187500, -0.0001220703125000, 0.0000915527343750, +0.0000000000000000, 0.0017395019531250, -0.0004882812500000, 0.0015869140625000, +0.0001831054687500, 0.0014038085937500, -0.0001525878906250, 0.0021667480468750, +-0.0007934570312500, 0.0018310546875000, -0.0000610351562500, 0.0016784667968750, +-0.0010986328125000, 0.0017700195312500, -0.0008544921875000, 0.0014343261718750, +-0.0007629394531250, 0.0011291503906250, -0.0014648437500000, 0.0013122558593750, +-0.0010986328125000, 0.0006103515625000, -0.0010986328125000, 0.0006103515625000, +-0.0014038085937500, 0.0002746582031250, -0.0007934570312500, -0.0003051757812500, +-0.0003051757812500, -0.0001220703125000, -0.0007019042968750, -0.0012512207031250, +0.0005798339843750, -0.0012207031250000, 0.0006408691406250, -0.0012817382812500, +0.0006408691406250, -0.0021057128906250, 0.0013732910156250, -0.0021362304687500, +0.0012512207031250, -0.0014953613281250, 0.0010986328125000, -0.0021972656250000, +0.0011901855468750, -0.0017089843750000, 0.0009460449218750, -0.0008239746093750, +0.0005187988281250, -0.0017089843750000, 0.0006408691406250, -0.0003662109375000, +0.0001525878906250, -0.0006103515625000, 0.0001831054687500, -0.0007324218750000, +-0.0000305175781250, 0.0001525878906250, -0.0003356933593750, -0.0003051757812500, +-0.0001525878906250, -0.0005493164062500, -0.0004577636718750, -0.0001831054687500, +-0.0005187988281250, -0.0008239746093750, -0.0003051757812500, -0.0015258789062500, +-0.0003051757812500, -0.0010375976562500, -0.0003356933593750, -0.0023193359375000, +0.0000915527343750, -0.0023803710937500, -0.0000305175781250, -0.0022888183593750, +0.0000000000000000, -0.0029907226562500, 0.0002136230468750, -0.0028381347656250, +-0.0000610351562500, -0.0022583007812500, 0.0002441406250000, -0.0026550292968750, +-0.0000305175781250, -0.0018615722656250, 0.0000305175781250, -0.0009155273437500, +0.0003051757812500, -0.0016479492187500, -0.0000305175781250, 0.0003051757812500, +0.0001525878906250, 0.0001220703125000, 0.0003356933593750, 0.0004882812500000, +0.0000610351562500, 0.0018615722656250, -0.0000305175781250, 0.0012207031250000, +0.0003356933593750, 0.0022888183593750, -0.0004272460937500, 0.0025329589843750, +0.0000305175781250, 0.0023193359375000, 0.0000000000000000, 0.0028381347656250, +-0.0004272460937500, 0.0028991699218750, 0.0003356933593750, 0.0021362304687500, +-0.0003051757812500}, +{0.0000915527343750, -0.0008850097656250, 0.0017395019531250, -0.0006713867187500, +0.0019226074218750, -0.0007629394531250, 0.0016784667968750, -0.0009460449218750, +0.0024108886718750, -0.0007324218750000, -0.0026245117187500, -0.0001831054687500, +0.0005798339843750, -0.0004577636718750, -0.0005493164062500, -0.0003051757812500, +0.0000000000000000, 0.0001525878906250, 0.0015258789062500, 0.0001220703125000, +0.0007934570312500, -0.0002136230468750, 0.0010986328125000, 0.0000610351562500, +0.0011596679687500, -0.0000610351562500, 0.0007019042968750, -0.0005493164062500, +0.0005798339843750, -0.0002136230468750, 0.0006408691406250, 0.0001525878906250, +-0.0002136230468750, 0.0000000000000000, 0.0001220703125000, 0.0005493164062500, +-0.0004882812500000, 0.0012817382812500, -0.0015258789062500, 0.0011596679687500, +-0.0008544921875000, 0.0018005371093750, -0.0023193359375000, 0.0021667480468750, +-0.0023803710937500, 0.0017700195312500, -0.0021057128906250, 0.0017089843750000, +-0.0026855468750000, 0.0021362304687500, -0.0025329589843750, 0.0007629394531250, +-0.0019531250000000, 0.0009155273437500, -0.0019226074218750, 0.0006103515625000, +-0.0016174316406250, -0.0003356933593750, -0.0009155273437500, 0.0002136230468750, +-0.0008850097656250, -0.0008850097656250, -0.0006103515625000, -0.0005798339843750, +-0.0001831054687500, -0.0008239746093750, -0.0002746582031250, -0.0016479492187500, +-0.0002441406250000, -0.0010681152343750, 0.0001831054687500, -0.0018615722656250, +-0.0005187988281250, -0.0020141601562500, -0.0002746582031250, -0.0018615722656250, +-0.0005493164062500, -0.0022583007812500, -0.0012817382812500, -0.0022583007812500, +-0.0008850097656250, -0.0011291503906250, -0.0014648437500000, -0.0017089843750000, +-0.0016784667968750, -0.0009460449218750, -0.0012512207031250, 0.0003967285156250, +-0.0011596679687500, -0.0005187988281250, -0.0013732910156250, 0.0009765625000000, +-0.0002136230468750, 0.0010986328125000, -0.0002746582031250, 0.0008544921875000, +0.0000000000000000, 0.0013427734375000, 0.0008850097656250, 0.0010986328125000, +0.0006103515625000, 0.0005798339843750, 0.0008850097656250, 0.0005798339843750, +0.0009765625000000, 0.0002136230468750, 0.0007934570312500, -0.0003967285156250, +0.0007629394531250, -0.0003967285156250, 0.0007629394531250, -0.0001525878906250, +0.0003051757812500, -0.0009155273437500, 0.0003967285156250, -0.0001831054687500, +0.0002136230468750, 0.0006408691406250, -0.0002136230468750, -0.0003967285156250, +0.0000305175781250, 0.0020751953125000, -0.0002746582031250, 0.0016479492187500, +-0.0003356933593750, 0.0022583007812500, -0.0001831054687500, 0.0041503906250000, +-0.0001831054687500, 0.0032348632812500, -0.0001525878906250, 0.0048828125000000, +-0.0000610351562500, 0.0051574707031250, -0.0000915527343750, 0.0049743652343750, +-0.0001525878906250, 0.0055541992187500, -0.0001831054687500, 0.0054931640625000, +-0.0002746582031250, 0.0048828125000000, -0.0001831054687500, 0.0052490234375000, +-0.0003051757812500, 0.0047607421875000, -0.0002136230468750, 0.0040283203125000, +0.0000610351562500, 0.0045776367187500, -0.0000915527343750, 0.0031127929687500, +0.0000610351562500, 0.0034484863281250, 0.0003051757812500, 0.0028686523437500, +0.0001831054687500, 0.0016479492187500, 0.0001831054687500, 0.0024414062500000, +0.0006103515625000, 0.0006713867187500, 0.0001831054687500, 0.0008544921875000, +0.0005187988281250, 0.0006103515625000, 0.0005493164062500, -0.0004882812500000, +0.0001831054687500, 0.0001831054687500, 0.0006408691406250, -0.0009155273437500, +0.0001525878906250, -0.0008850097656250, 0.0002136230468750, -0.0008850097656250, +0.0002136230468750, -0.0015258789062500, -0.0000915527343750, -0.0012207031250000, +0.0000000000000000, -0.0014648437500000, -0.0001525878906250, -0.0016479492187500, +-0.0001525878906250, -0.0013732910156250, -0.0002441406250000, -0.0013122558593750, +-0.0003967285156250, -0.0015563964843750, -0.0002441406250000, -0.0006408691406250, +-0.0005187988281250, -0.0009765625000000, -0.0003967285156250, -0.0004882812500000, +-0.0002441406250000, 0.0003356933593750, -0.0003662109375000, -0.0002746582031250, +-0.0003662109375000, 0.0012207031250000, -0.0001220703125000, 0.0009765625000000, +-0.0002136230468750, 0.0014038085937500, -0.0001525878906250, 0.0025024414062500, +0.0000610351562500, 0.0018005371093750, -0.0000305175781250, 0.0032348632812500, +0.0001220703125000, 0.0029602050781250, 0.0001831054687500, 0.0033264160156250, +0.0001831054687500, 0.0044250488281250, 0.0003051757812500, 0.0037536621093750, +0.0003356933593750, 0.0049438476562500, 0.0003967285156250, 0.0049133300781250, +0.0003662109375000, 0.0049743652343750, 0.0004577636718750, 0.0056152343750000, +0.0005493164062500, 0.0053405761718750, 0.0004272460937500, 0.0055236816406250, +0.0007324218750000, 0.0056457519531250, 0.0006103515625000, 0.0054321289062500, +0.0008239746093750, 0.0053405761718750, 0.0011901855468750, 0.0054626464843750, +0.0008850097656250, 0.0051574707031250, 0.0014038085937500, 0.0051879882812500, +0.0014648437500000, 0.0050659179687500, 0.0014648437500000, 0.0048828125000000, +0.0017395019531250, 0.0050659179687500, 0.0016784667968750, 0.0046081542968750, +0.0017089843750000, 0.0048828125000000, 0.0018005371093750, 0.0046386718750000, +0.0016479492187500, 0.0042114257812500, 0.0015258789062500, 0.0046997070312500, +0.0016174316406250, 0.0037536621093750, 0.0012512207031250, 0.0040283203125000, +0.0013122558593750, 0.0037841796875000, 0.0011596679687500, 0.0029907226562500, +0.0008850097656250, 0.0034484863281250, 0.0010070800781250, 0.0026855468750000, +0.0007019042968750, 0.0026855468750000, 0.0007324218750000, 0.0028991699218750, +0.0006713867187500, 0.0026550292968750, 0.0005798339843750, 0.0028381347656250, +0.0007324218750000, 0.0033264160156250, 0.0003967285156250, 0.0031433105468750, +0.0007019042968750, 0.0035705566406250, 0.0005798339843750, 0.0042114257812500, +0.0003356933593750, 0.0039672851562500, 0.0008239746093750, 0.0048522949218750, +0.0001220703125000, 0.0049133300781250, 0.0003356933593750, 0.0050048828125000, +0.0003662109375000, 0.0055847167968750, -0.0000915527343750, 0.0054016113281250, +0.0000915527343750, 0.0054626464843750, -0.0000305175781250, 0.0057373046875000, +-0.0001525878906250, 0.0054931640625000, -0.0001220703125000, 0.0053100585937500, +-0.0001525878906250, 0.0055847167968750, -0.0002136230468750, 0.0048217773437500, +-0.0002441406250000, 0.0050048828125000, -0.0003051757812500, 0.0047607421875000, +-0.0002746582031250, 0.0040893554687500, -0.0001831054687500, 0.0044860839843750, +-0.0002746582031250, 0.0036010742187500, 0.0000000000000000, 0.0039062500000000, +-0.0000610351562500, 0.0032653808593750, -0.0000305175781250, 0.0023803710937500, +0.0002136230468750, 0.0030517578125000, 0.0000610351562500, 0.0010986328125000, +0.0000915527343750, 0.0013427734375000, 0.0001831054687500, 0.0009460449218750, +0.0000915527343750, -0.0005493164062500, 0.0001220703125000, 0.0000000000000000, +0.0002136230468750, -0.0005187988281250, -0.0001220703125000, -0.0009155273437500, +-0.0000610351562500, -0.0007629394531250, -0.0001220703125000, -0.0007934570312500, +-0.0003662109375000, -0.0010375976562500, -0.0003662109375000, -0.0010986328125000, +-0.0004577636718750, -0.0010681152343750, -0.0006713867187500, -0.0013122558593750, +-0.0005493164062500, -0.0015869140625000, -0.0004882812500000, -0.0014038085937500, +-0.0008239746093750, -0.0013122558593750, -0.0003356933593750, -0.0014648437500000, +-0.0005798339843750, -0.0011901855468750, -0.0006103515625000, -0.0003967285156250, +-0.0002746582031250, 0.0001831054687500, -0.0005493164062500, 0.0005493164062500, +-0.0001220703125000, 0.0006408691406250, -0.0004882812500000, 0.0007629394531250, +-0.0003662109375000, 0.0009765625000000, -0.0000610351562500, 0.0010681152343750, +-0.0007324218750000, 0.0014038085937500, 0.0000000000000000, 0.0012817382812500, +-0.0001220703125000, 0.0012512207031250, -0.0002136230468750, 0.0014648437500000, +0.0000610351562500, 0.0013732910156250, -0.0002441406250000, 0.0010681152343750, +-0.0000915527343750, 0.0011901855468750, -0.0001831054687500, 0.0009765625000000, +-0.0001525878906250, 0.0006408691406250, -0.0000305175781250, 0.0008239746093750, +-0.0002136230468750, 0.0005798339843750, -0.0000305175781250, 0.0004882812500000, +0.0000610351562500, 0.0004882812500000, -0.0001831054687500, 0.0004882812500000, +-0.0001525878906250, 0.0005493164062500, 0.0000610351562500, 0.0000915527343750, +-0.0005187988281250, 0.0004577636718750, -0.0003967285156250, 0.0000000000000000, +-0.0003662109375000, -0.0006103515625000, -0.0007629394531250, 0.0000610351562500, +-0.0006408691406250, -0.0010375976562500, -0.0006408691406250, -0.0008239746093750, +-0.0008239746093750, -0.0008850097656250, -0.0007324218750000, -0.0014953613281250, +-0.0005798339843750, -0.0010070800781250, -0.0007019042968750, -0.0013427734375000, +-0.0005493164062500, -0.0013732910156250, -0.0005187988281250, -0.0008850097656250, +-0.0004882812500000, -0.0007934570312500, -0.0004577636718750, -0.0007934570312500, +-0.0004882812500000, 0.0002441406250000, -0.0002136230468750, 0.0000305175781250, +-0.0002136230468750, 0.0002746582031250, -0.0001831054687500, 0.0011291503906250, +-0.0000305175781250, 0.0006713867187500, -0.0000610351562500, 0.0007019042968750, +0.0001831054687500, 0.0010681152343750, 0.0001831054687500, 0.0006713867187500, +0.0004272460937500, 0.0002136230468750, 0.0006713867187500, 0.0005798339843750, +0.0005798339843750, -0.0000305175781250, 0.0012817382812500, -0.0000915527343750, +0.0011901855468750, 0.0000915527343750, 0.0016174316406250, -0.0001220703125000, +0.0023498535156250, -0.0001831054687500, 0.0020141601562500, 0.0002746582031250, +0.0031127929687500, 0.0000610351562500, 0.0031433105468750, 0.0001525878906250, +0.0032653808593750, 0.0005493164062500, 0.0038757324218750, 0.0001831054687500, +0.0036315917968750, 0.0005798339843750, 0.0037536621093750, 0.0006408691406250, +0.0038452148437500, 0.0005798339843750, 0.0036926269531250, 0.0007934570312500, +0.0036315917968750, 0.0009155273437500, 0.0036010742187500, 0.0008239746093750, +0.0034790039062500, 0.0010681152343750, 0.0033874511718750, 0.0010986328125000, +0.0033569335937500, 0.0009460449218750, 0.0033264160156250, 0.0012207031250000, +0.0031738281250000, 0.0011291503906250, 0.0032958984375000, 0.0011596679687500, +0.0030517578125000, 0.0011596679687500, 0.0031433105468750, 0.0011901855468750, +0.0032958984375000, 0.0012207031250000, 0.0029907226562500, 0.0010681152343750, +0.0034179687500000, 0.0010681152343750, 0.0033264160156250, 0.0010986328125000, +0.0032043457031250, 0.0009155273437500, 0.0034179687500000, 0.0008544921875000, +0.0032653808593750, 0.0009460449218750, 0.0032043457031250, 0.0007629394531250, +0.0032958984375000, 0.0007324218750000, 0.0032043457031250, 0.0007934570312500, +0.0030517578125000, 0.0006408691406250, 0.0031433105468750, 0.0006103515625000, +0.0028381347656250, 0.0005493164062500, 0.0029296875000000, 0.0003967285156250, +0.0028686523437500, 0.0003051757812500, 0.0026245117187500, 0.0002746582031250, +0.0027770996093750, -0.0001220703125000, 0.0024719238281250, -0.0001525878906250, +0.0025939941406250, -0.0002746582031250, 0.0025024414062500, -0.0005493164062500, +0.0022583007812500, -0.0004272460937500, 0.0025634765625000, -0.0004577636718750, +0.0023193359375000, -0.0005493164062500, 0.0023498535156250, -0.0004272460937500, +0.0025939941406250}, +{-0.0006408691406250, 0.0010986328125000, -0.0008239746093750, 0.0020141601562500, +-0.0010986328125000, 0.0014038085937500, -0.0007019042968750, 0.0015258789062500, +-0.0013122558593750, 0.0017395019531250, -0.0012207031250000, 0.0013427734375000, +-0.0010070800781250, 0.0009155273437500, -0.0012817382812500, 0.0011596679687500, +-0.0011901855468750, 0.0006713867187500, -0.0007324218750000, 0.0007629394531250, +-0.0008544921875000, 0.0006713867187500, -0.0006103515625000, 0.0004577636718750, +-0.0002136230468750, 0.0007934570312500, -0.0002746582031250, 0.0001831054687500, +0.0001525878906250, 0.0005493164062500, 0.0000610351562500, 0.0003356933593750, +0.0001831054687500, -0.0001831054687500, 0.0005187988281250, 0.0003356933593750, +0.0001525878906250, -0.0006713867187500, 0.0007629394531250, -0.0003662109375000, +0.0005187988281250, -0.0004882812500000, 0.0006713867187500, -0.0011901855468750, +0.0010681152343750, -0.0005493164062500, 0.0007324218750000, -0.0010681152343750, +0.0011901855468750, -0.0011596679687500, 0.0011596679687500, -0.0008239746093750, +0.0012512207031250, -0.0009460449218750, 0.0015869140625000, -0.0010375976562500, +0.0015258789062500, -0.0003051757812500, 0.0020751953125000, -0.0005493164062500, +0.0021667480468750, -0.0003967285156250, 0.0026550292968750, 0.0001831054687500, +0.0032653808593750, -0.0001831054687500, 0.0031127929687500, 0.0001831054687500, +0.0039978027343750, 0.0001831054687500, 0.0041198730468750, 0.0000305175781250, +0.0043640136718750, 0.0000915527343750, 0.0049438476562500, -0.0000915527343750, +0.0048522949218750, 0.0000000000000000, 0.0049438476562500, -0.0001831054687500, +0.0050964355468750, -0.0000610351562500, 0.0051269531250000, 0.0000915527343750, +0.0050354003906250, -0.0001220703125000, 0.0050354003906250, 0.0001831054687500, +0.0053405761718750, 0.0001831054687500, 0.0050964355468750, 0.0001831054687500, +0.0053405761718750, 0.0003662109375000, 0.0056762695312500, 0.0003356933593750, +0.0053405761718750, 0.0004882812500000, 0.0059509277343750, 0.0005798339843750, +0.0056762695312500, 0.0006103515625000, 0.0059204101562500, 0.0006713867187500, +0.0064392089843750, 0.0007324218750000, 0.0059814453125000, 0.0006713867187500, +0.0068359375000000, 0.0007934570312500, 0.0067443847656250, 0.0008544921875000, +0.0067443847656250, 0.0008239746093750, 0.0072937011718750, 0.0009765625000000, +0.0071105957031250, 0.0011596679687500, 0.0071411132812500, 0.0011596679687500, +0.0073547363281250, 0.0012512207031250, 0.0071105957031250, 0.0013427734375000, +0.0068359375000000, 0.0012207031250000, 0.0071411132812500, 0.0013122558593750, +0.0065917968750000, 0.0011596679687500, 0.0066833496093750, 0.0010070800781250, +0.0067749023437500, 0.0009155273437500, 0.0064086914062500, 0.0007324218750000, +0.0065002441406250, 0.0005798339843750, 0.0065002441406250, 0.0004272460937500, +0.0063476562500000, 0.0002136230468750, 0.0064392089843750, 0.0000305175781250, +0.0065002441406250, -0.0000610351562500, 0.0063781738281250, -0.0001525878906250, +0.0066223144531250, -0.0001831054687500, 0.0065612792968750, -0.0002136230468750, +0.0064697265625000, -0.0002136230468750, 0.0065002441406250, -0.0001831054687500, +0.0064392089843750, -0.0003051757812500, 0.0060424804687500, -0.0001831054687500, +0.0061035156250000, -0.0002441406250000, 0.0057067871093750, -0.0003356933593750, +0.0052185058593750, -0.0001220703125000, 0.0053710937500000, -0.0002746582031250, +0.0041198730468750, -0.0001831054687500, 0.0043029785156250, -0.0001525878906250, +0.0037231445312500, -0.0001831054687500, 0.0026245117187500, -0.0000915527343750, +0.0031127929687500, -0.0002746582031250, 0.0016174316406250, -0.0000305175781250, +0.0015869140625000, -0.0001220703125000, 0.0014648437500000, -0.0002746582031250, +0.0004577636718750, 0.0000915527343750, 0.0007019042968750, -0.0003356933593750, +0.0006103515625000, 0.0000000000000000, 0.0003051757812500, -0.0000305175781250, +0.0007019042968750, -0.0003051757812500, 0.0009460449218750, 0.0003356933593750, +0.0006103515625000, -0.0001525878906250, 0.0017395019531250, 0.0000915527343750, +0.0015869140625000, 0.0003662109375000, 0.0019226074218750, 0.0000305175781250, +0.0027770996093750, 0.0001220703125000, 0.0024108886718750, 0.0004272460937500, +0.0029907226562500, -0.0000610351562500, 0.0032348632812500, 0.0001220703125000, +0.0030822753906250, 0.0004577636718750, 0.0031738281250000, -0.0004577636718750, +0.0032348632812500, 0.0006408691406250, 0.0027465820312500, 0.0000610351562500, +0.0029602050781250, 0.0000610351562500, 0.0026245117187500, 0.0009155273437500, +0.0020751953125000, 0.0001831054687500, 0.0024108886718750, 0.0007019042968750, +0.0019226074218750, 0.0007934570312500, 0.0018615722656250, 0.0005798339843750, +0.0020141601562500, 0.0007324218750000, 0.0019531250000000, 0.0007934570312500, +0.0019531250000000, 0.0005798339843750, 0.0020141601562500, 0.0006408691406250, +0.0020141601562500, 0.0005798339843750, 0.0017700195312500, 0.0004577636718750, +0.0015869140625000, 0.0004577636718750, 0.0016174316406250, 0.0000915527343750, +0.0008239746093750, 0.0002746582031250, 0.0008544921875000, 0.0000305175781250, +0.0005493164062500, -0.0002441406250000, -0.0001525878906250, 0.0001220703125000, +-0.0000305175781250, -0.0004882812500000, -0.0002441406250000, -0.0001831054687500, +-0.0006713867187500, -0.0003051757812500, -0.0003356933593750, -0.0006408691406250, +-0.0000915527343750, -0.0000305175781250, -0.0005187988281250, -0.0008850097656250, +0.0006408691406250, -0.0005187988281250, 0.0005798339843750, -0.0006103515625000, +0.0006408691406250, -0.0012512207031250, 0.0012512207031250, -0.0007019042968750, +0.0009460449218750, -0.0010986328125000, 0.0014038085937500, -0.0012207031250000, +0.0014038085937500, -0.0009460449218750, 0.0013732910156250, -0.0009460449218750, +0.0014953613281250, -0.0009460449218750, 0.0015563964843750, -0.0005493164062500, +0.0018615722656250, -0.0006408691406250, 0.0017700195312500, -0.0003662109375000, +0.0022888183593750, -0.0001831054687500, 0.0028076171875000, -0.0005798339843750, +0.0025634765625000, -0.0000610351562500, 0.0035400390625000, -0.0005187988281250, +0.0034790039062500, -0.0003356933593750, 0.0036926269531250, 0.0001220703125000, +0.0044555664062500, -0.0005187988281250, 0.0041503906250000, 0.0001220703125000, +0.0040893554687500, -0.0000305175781250, 0.0045471191406250, -0.0002136230468750, +0.0038146972656250, 0.0000610351562500, 0.0030822753906250, -0.0001220703125000, +0.0036010742187500, -0.0002746582031250, 0.0018920898437500, -0.0003051757812500, +0.0020446777343750, -0.0002441406250000, 0.0018005371093750, -0.0003662109375000, +0.0008239746093750, -0.0004882812500000, 0.0014648437500000, 0.0001831054687500, +-0.0001220703125000, -0.0000915527343750, 0.0003662109375000, -0.0000305175781250, +-0.0002136230468750, 0.0007934570312500, -0.0028686523437500, 0.0007019042968750, +0.0034179687500000, 0.0011901855468750, 0.0021362304687500, 0.0009460449218750, +0.0034484863281250, 0.0013427734375000, 0.0017700195312500, 0.0019226074218750, +-0.0000610351562500, 0.0018310546875000, 0.0013122558593750, 0.0017395019531250, +-0.0012512207031250, 0.0024414062500000, -0.0014648437500000, 0.0018310546875000, +-0.0010681152343750, 0.0011596679687500, -0.0020751953125000, 0.0021057128906250, +-0.0020446777343750, 0.0003356933593750, -0.0014648437500000, 0.0003662109375000, +-0.0019226074218750, 0.0005493164062500, -0.0015563964843750, -0.0003356933593750, +-0.0010375976562500, -0.0001525878906250, -0.0017395019531250, -0.0001831054687500, +-0.0003051757812500, -0.0003051757812500, -0.0008239746093750, -0.0003967285156250, +-0.0003662109375000, -0.0001831054687500, 0.0010375976562500, 0.0000000000000000, +0.0000610351562500, -0.0002746582031250, 0.0012512207031250, 0.0000610351562500, +0.0016479492187500, 0.0004272460937500, 0.0010070800781250, 0.0005187988281250, +0.0011291503906250, 0.0008239746093750, 0.0014953613281250, 0.0015563964843750, +-0.0000915527343750, 0.0017089843750000, 0.0002746582031250, 0.0018310546875000, +-0.0000305175781250, 0.0022583007812500, -0.0012207031250000, 0.0023803710937500, +-0.0006103515625000, 0.0020141601562500, -0.0012512207031250, 0.0022888183593750, +-0.0013732910156250, 0.0020446777343750, -0.0010681152343750, 0.0014038085937500, +-0.0010375976562500, 0.0018310546875000, -0.0009765625000000, 0.0017700195312500, +-0.0004272460937500, 0.0011596679687500, -0.0004882812500000, 0.0021667480468750, +-0.0002136230468750, 0.0029602050781250, 0.0002136230468750, 0.0020751953125000, +0.0001220703125000, 0.0052185058593750, 0.0001831054687500, 0.0043945312500000, +0.0004272460937500, 0.0055541992187500, 0.0001220703125000, 0.0082092285156250, +-0.0002746582031250, 0.0065917968750000, 0.0000000000000000, 0.0095825195312500, +-0.0006103515625000, 0.0093688964843750, -0.0007019042968750, 0.0092773437500000, +-0.0005493164062500, 0.0107421875000000, -0.0007629394531250, 0.0098876953125000, +-0.0007934570312500, 0.0099182128906250, -0.0003662109375000, 0.0099792480468750, +-0.0004577636718750, 0.0093383789062500, -0.0002746582031250, 0.0088500976562500, +0.0000915527343750, 0.0089111328125000, -0.0000915527343750, 0.0077819824218750, +0.0002136230468750, 0.0077514648437500, 0.0003356933593750, 0.0074157714843750, +0.0001525878906250, 0.0065917968750000, 0.0001831054687500, 0.0068969726562500, +0.0003662109375000, 0.0063476562500000, -0.0001525878906250, 0.0064697265625000, +0.0000000000000000, 0.0064086914062500, 0.0000000000000000, 0.0062561035156250, +-0.0004577636718750, 0.0067443847656250, -0.0002746582031250, 0.0060119628906250, +-0.0002441406250000, 0.0064392089843750, -0.0004882812500000, 0.0065917968750000, +-0.0003051757812500, 0.0061645507812500, -0.0001525878906250, 0.0067138671875000, +-0.0005187988281250, 0.0066528320312500, -0.0000915527343750, 0.0066833496093750, +-0.0003051757812500, 0.0071716308593750, -0.0002746582031250, 0.0074462890625000, +-0.0000305175781250, 0.0074462890625000, -0.0004272460937500, 0.0082397460937500, +-0.0001220703125000, 0.0082397460937500, -0.0002441406250000, 0.0084533691406250, +-0.0003662109375000, 0.0090026855468750, -0.0002441406250000, 0.0089416503906250, +-0.0003662109375000, 0.0092163085937500, -0.0003356933593750, 0.0094909667968750, +-0.0003662109375000, 0.0093078613281250, -0.0002746582031250, 0.0092773437500000, +-0.0002441406250000, 0.0095214843750000, -0.0002136230468750, 0.0088500976562500, +0.0000610351562500, 0.0089721679687500, 0.0000000000000000, 0.0085449218750000, +0.0000610351562500, 0.0078430175781250, 0.0002136230468750, 0.0082397460937500, +0.0000305175781250, 0.0070800781250000, 0.0001220703125000, 0.0070800781250000, +0.0000915527343750, 0.0068664550781250, 0.0000000000000000, 0.0061035156250000, +0.0000305175781250, 0.0062255859375000, 0.0000610351562500, 0.0057373046875000, +-0.0000915527343750, 0.0055236816406250, -0.0000305175781250, 0.0054321289062500, +0.0000305175781250, 0.0051574707031250, -0.0000915527343750, 0.0050354003906250, +-0.0000915527343750, 0.0048522949218750, 0.0001220703125000, 0.0045776367187500, +-0.0000610351562500, 0.0044250488281250, 0.0001831054687500, 0.0041503906250000, +0.0005493164062500, 0.0038757324218750, 0.0002136230468750, 0.0036315917968750, +0.0010070800781250, 0.0033264160156250, 0.0009155273437500, 0.0030822753906250, +0.0009765625000000, 0.0028686523437500, 0.0014343261718750, 0.0025634765625000, +0.0012817382812500}, +{0.0008239746093750, 0.0024719238281250, 0.0009155273437500, 0.0031433105468750, +0.0000915527343750, 0.0027160644531250, 0.0003967285156250, 0.0038757324218750, +0.0001220703125000, 0.0051574707031250, -0.0005798339843750, 0.0043640136718750, +-0.0001525878906250, 0.0072326660156250, -0.0006103515625000, 0.0071411132812500, +-0.0006408691406250, 0.0074768066406250, -0.0004882812500000, 0.0093078613281250, +-0.0007019042968750, 0.0086364746093750, -0.0005798339843750, 0.0091552734375000, +-0.0001831054687500, 0.0096435546875000, -0.0004272460937500, 0.0088195800781250, +-0.0000915527343750, 0.0083618164062500, 0.0004272460937500, 0.0088806152343750, +0.0000915527343750, 0.0065612792968750, 0.0005798339843750, 0.0070190429687500, +0.0007019042968750, 0.0062255859375000, 0.0004577636718750, 0.0043945312500000, +0.0003967285156250, 0.0053710937500000, 0.0004882812500000, 0.0032348632812500, +-0.0000305175781250, 0.0033264160156250, 0.0000000000000000, 0.0029296875000000, +-0.0000915527343750, 0.0014953613281250, -0.0003967285156250, 0.0021057128906250, +-0.0003051757812500, 0.0009460449218750, -0.0003051757812500, 0.0008850097656250, +-0.0004272460937500, 0.0008239746093750, -0.0002746582031250, 0.0003051757812500, +-0.0001525878906250, 0.0005493164062500, -0.0002136230468750, -0.0000610351562500, +-0.0000305175781250, 0.0000610351562500, 0.0000915527343750, -0.0001220703125000, +0.0000915527343750, -0.0004882812500000, 0.0000610351562500, -0.0000915527343750, +0.0001220703125000, -0.0003967285156250, 0.0000610351562500, -0.0002136230468750, +-0.0000305175781250, 0.0001525878906250, 0.0000305175781250, 0.0002136230468750, +-0.0000915527343750, 0.0004272460937500, -0.0003662109375000, 0.0008544921875000, +-0.0001220703125000, 0.0010375976562500, -0.0005187988281250, 0.0012207031250000, +-0.0005493164062500, 0.0015563964843750, -0.0003051757812500, 0.0018005371093750, +-0.0008544921875000, 0.0018920898437500, -0.0004882812500000, 0.0022888183593750, +-0.0007934570312500, 0.0023803710937500, -0.0008544921875000, 0.0024414062500000, +-0.0005798339843750, 0.0028076171875000, -0.0008850097656250, 0.0027160644531250, +-0.0007324218750000, 0.0031433105468750, -0.0007629394531250, 0.0034179687500000, +-0.0007629394531250, 0.0033264160156250, -0.0006408691406250, 0.0037536621093750, +-0.0006713867187500, 0.0043334960937500, -0.0004882812500000, 0.0043640136718750, +-0.0005798339843750, 0.0050048828125000, -0.0004577636718750, 0.0057678222656250, +-0.0001831054687500, 0.0056457519531250, -0.0003967285156250, 0.0068359375000000, +-0.0000610351562500, 0.0069274902343750, -0.0000610351562500, 0.0074462890625000, +-0.0000305175781250, 0.0083618164062500, 0.0001220703125000, 0.0080566406250000, +0.0000915527343750, 0.0090332031250000, 0.0001831054687500, 0.0090332031250000, +0.0002746582031250, 0.0090637207031250, 0.0003662109375000, 0.0095520019531250, +0.0003967285156250, 0.0092468261718750, 0.0004577636718750, 0.0091247558593750, +0.0006408691406250, 0.0092773437500000, 0.0005187988281250, 0.0087890625000000, +0.0006713867187500, 0.0084228515625000, 0.0009155273437500, 0.0085449218750000, +0.0007324218750000, 0.0073547363281250, 0.0011291503906250, 0.0074462890625000, +0.0010986328125000, 0.0068664550781250, 0.0011596679687500, 0.0057983398437500, +0.0014038085937500, 0.0061950683593750, 0.0012512207031250, 0.0044860839843750, +0.0013732910156250, 0.0045776367187500, 0.0014038085937500, 0.0039367675781250, +0.0013122558593750, 0.0025634765625000, 0.0012512207031250, 0.0029907226562500, +0.0012207031250000, 0.0015258789062500, 0.0009765625000000, 0.0012817382812500, +0.0010375976562500, 0.0010070800781250, 0.0009460449218750, 0.0000915527343750, +0.0006713867187500, 0.0002746582031250, 0.0008544921875000, -0.0000915527343750, +0.0004882812500000, -0.0002746582031250, 0.0005798339843750, -0.0000610351562500, +0.0004577636718750, 0.0000305175781250, 0.0002441406250000, 0.0000000000000000, +0.0005187988281250, 0.0005187988281250, 0.0000305175781250, 0.0005187988281250, +0.0002441406250000, 0.0006713867187500, 0.0000610351562500, 0.0010986328125000, +-0.0003662109375000, 0.0010375976562500, 0.0000610351562500, 0.0012207031250000, +-0.0005798339843750, 0.0013427734375000, -0.0003967285156250, 0.0012512207031250, +-0.0004882812500000, 0.0012512207031250, -0.0009460449218750, 0.0012512207031250, +-0.0005187988281250, 0.0010375976562500, -0.0010070800781250, 0.0010375976562500, +-0.0010070800781250, 0.0009155273437500, -0.0008544921875000, 0.0006713867187500, +-0.0009155273437500, 0.0007324218750000, -0.0007934570312500, 0.0004882812500000, +-0.0006713867187500, 0.0004577636718750, -0.0005187988281250, 0.0004577636718750, +-0.0004272460937500, 0.0003051757812500, -0.0002441406250000, 0.0003051757812500, +-0.0000610351562500, 0.0005798339843750, -0.0001831054687500, 0.0003662109375000, +0.0002136230468750, 0.0006713867187500, 0.0001220703125000, 0.0010681152343750, +-0.0000305175781250, 0.0007019042968750, 0.0004577636718750, 0.0012817382812500, +-0.0000305175781250, 0.0013122558593750, 0.0002136230468750, 0.0010681152343750, +0.0001831054687500, 0.0012512207031250, -0.0001220703125000, 0.0013122558593750, +0.0003967285156250, 0.0009460449218750, -0.0001831054687500, 0.0010070800781250, +0.0000305175781250, 0.0008850097656250, 0.0001831054687500, 0.0007019042968750, +-0.0001525878906250, 0.0007629394531250, 0.0000305175781250, 0.0004272460937500, +0.0001220703125000, 0.0004577636718750, -0.0000305175781250, 0.0002441406250000, +0.0001220703125000, 0.0000000000000000, 0.0003051757812500, 0.0001220703125000, +0.0000610351562500, -0.0005798339843750, 0.0003051757812500, -0.0005187988281250, +0.0003051757812500, -0.0006103515625000, 0.0001220703125000, -0.0011596679687500, +0.0000915527343750, -0.0010375976562500, 0.0000610351562500, -0.0006103515625000, +0.0000000000000000, -0.0010375976562500, -0.0001220703125000, -0.0006103515625000, +-0.0001220703125000, 0.0000915527343750, -0.0001525878906250, -0.0004577636718750, +-0.0002441406250000, 0.0004577636718750, -0.0001525878906250, 0.0004577636718750, +-0.0001831054687500, 0.0004272460937500, -0.0002136230468750, 0.0010375976562500, +-0.0001831054687500, 0.0014343261718750, -0.0002441406250000, 0.0018920898437500, +-0.0002746582031250, 0.0018005371093750, -0.0002441406250000, 0.0014953613281250, +-0.0003051757812500, 0.0017395019531250, -0.0003662109375000, 0.0018310546875000, +-0.0003356933593750, 0.0007629394531250, -0.0005798339843750, 0.0011901855468750, +-0.0006713867187500, 0.0007934570312500, -0.0005187988281250, -0.0000915527343750, +-0.0004882812500000, 0.0006103515625000, -0.0005798339843750, -0.0005798339843750, +0.0002441406250000, -0.0004272460937500, 0.0000610351562500, -0.0004882812500000, +0.0004272460937500, -0.0013122558593750, 0.0011901855468750, -0.0008239746093750, +0.0009155273437500, -0.0011596679687500, 0.0014953613281250, -0.0013427734375000, +0.0016784667968750, -0.0008850097656250, 0.0014953613281250, -0.0007019042968750, +0.0016174316406250, -0.0009460449218750, 0.0017395019531250, 0.0003051757812500, +0.0011901855468750, 0.0000000000000000, 0.0012817382812500, 0.0003356933593750, +0.0012512207031250, 0.0013427734375000, 0.0009460449218750, 0.0007629394531250, +0.0010070800781250, 0.0015563964843750, 0.0011596679687500, 0.0016174316406250, +0.0010070800781250, 0.0014953613281250, 0.0014343261718750, 0.0018615722656250, +0.0019226074218750, 0.0017395019531250, 0.0017700195312500, 0.0014648437500000, +0.0028381347656250, 0.0016784667968750, 0.0028381347656250, 0.0013427734375000, +0.0030517578125000, 0.0009460449218750, 0.0038146972656250, 0.0013732910156250, +0.0035400390625000, 0.0003051757812500, 0.0037231445312500, 0.0005187988281250, +0.0041503906250000, 0.0003051757812500, 0.0037536621093750, -0.0004577636718750, +0.0034484863281250, 0.0000915527343750, 0.0039062500000000, -0.0006408691406250, +0.0027160644531250, -0.0006713867187500, 0.0030212402343750, -0.0007019042968750, +0.0026245117187500, -0.0011901855468750, 0.0016784667968750, -0.0010375976562500, +0.0022277832031250, -0.0014343261718750, 0.0011596679687500, -0.0015258789062500, +0.0010375976562500, -0.0015258789062500, 0.0009765625000000, -0.0017700195312500, +0.0004577636718750, -0.0017700195312500, 0.0004882812500000, -0.0014343261718750, +0.0000305175781250, -0.0017395019531250, -0.0000305175781250, -0.0013427734375000, +-0.0003356933593750, -0.0008239746093750, -0.0007324218750000, -0.0013732910156250, +-0.0005798339843750, -0.0003356933593750, -0.0010681152343750, -0.0006408691406250, +-0.0011596679687500, -0.0005493164062500, -0.0011596679687500, 0.0000915527343750, +-0.0013122558593750, -0.0005798339843750, -0.0013122558593750, 0.0001525878906250, +-0.0012207031250000, -0.0000915527343750, -0.0012512207031250, -0.0000915527343750, +-0.0011901855468750, 0.0003967285156250, -0.0010375976562500, 0.0000000000000000, +-0.0011291503906250, 0.0004272460937500, -0.0007019042968750, 0.0003662109375000, +-0.0008544921875000, 0.0003356933593750, -0.0005798339843750, 0.0006103515625000, +-0.0001525878906250, 0.0004577636718750, -0.0004577636718750, 0.0006408691406250, +0.0004882812500000, 0.0007934570312500, 0.0003967285156250, 0.0006408691406250, +0.0006103515625000, 0.0006408691406250, 0.0012817382812500, 0.0008850097656250, +0.0010375976562500, 0.0003967285156250, 0.0015869140625000, 0.0006103515625000, +0.0016174316406250, 0.0006408691406250, 0.0015258789062500, 0.0003051757812500, +0.0016479492187500, 0.0005798339843750, 0.0016174316406250, 0.0005493164062500, +0.0017089843750000, 0.0004882812500000, 0.0016174316406250, 0.0007324218750000, +0.0017089843750000, 0.0008239746093750, 0.0018005371093750, 0.0006713867187500, +0.0018310546875000, 0.0008544921875000, 0.0023803710937500, 0.0007934570312500, +0.0021667480468750, 0.0007324218750000, 0.0026245117187500, 0.0007934570312500, +0.0033874511718750, 0.0007019042968750, 0.0029907226562500, 0.0004577636718750, +0.0043945312500000, 0.0005187988281250, 0.0044250488281250, 0.0003051757812500, +0.0048522949218750, 0.0000915527343750, 0.0058898925781250, 0.0003051757812500, +0.0056457519531250, -0.0002441406250000, 0.0066528320312500, -0.0000305175781250, +0.0067138671875000, -0.0001831054687500, 0.0068054199218750, -0.0005493164062500, +0.0073852539062500, -0.0000915527343750, 0.0072326660156250, -0.0006713867187500, +0.0075378417968750, -0.0003356933593750, 0.0076904296875000, -0.0002746582031250, +0.0074462890625000, -0.0006408691406250, 0.0074768066406250, -0.0001220703125000, +0.0076293945312500, -0.0002441406250000, 0.0068359375000000, -0.0003356933593750, +0.0071716308593750, 0.0000000000000000, 0.0065917968750000, 0.0000000000000000, +0.0057983398437500, -0.0002746582031250, 0.0063476562500000, 0.0004577636718750, +0.0044860839843750, -0.0001831054687500, 0.0048217773437500, 0.0000305175781250, +0.0040588378906250, 0.0005798339843750, 0.0025939941406250, -0.0003967285156250, +0.0035400390625000, 0.0005798339843750, 0.0015258789062500, 0.0002136230468750, +0.0015869140625000, 0.0000305175781250, 0.0013732910156250, 0.0005493164062500, +0.0001831054687500, 0.0001220703125000, 0.0007324218750000, 0.0002136230468750, +0.0002441406250000, 0.0003967285156250, 0.0000000000000000, 0.0002441406250000, +0.0005798339843750, 0.0001525878906250, 0.0007019042968750, 0.0002441406250000, +0.0003051757812500, 0.0001525878906250, 0.0017089843750000, 0.0001220703125000, +0.0013122558593750}, +{-0.0007629394531250, -0.0005187988281250, -0.0007324218750000, -0.0007934570312500, +-0.0005798339843750, -0.0013122558593750, -0.0004882812500000, -0.0009765625000000, +-0.0002746582031250, -0.0017395019531250, 0.0000000000000000, -0.0017395019531250, +0.0001831054687500, -0.0017700195312500, 0.0007019042968750, -0.0022277832031250, +0.0010375976562500, -0.0021667480468750, 0.0010375976562500, -0.0018005371093750, +0.0018615722656250, -0.0021667480468750, 0.0019226074218750, -0.0017089843750000, +0.0023803710937500, -0.0010681152343750, 0.0031433105468750, -0.0016479492187500, +0.0030517578125000, -0.0003662109375000, 0.0035095214843750, -0.0006408691406250, +0.0036926269531250, -0.0004577636718750, 0.0038452148437500, 0.0004882812500000, +0.0041809082031250, -0.0001831054687500, 0.0042114257812500, 0.0006103515625000, +0.0042114257812500, 0.0005187988281250, 0.0044555664062500, 0.0003967285156250, +0.0041503906250000, 0.0007324218750000, 0.0039062500000000, 0.0004577636718750, +0.0042114257812500, 0.0004882812500000, 0.0029907226562500, 0.0003967285156250, +0.0032958984375000, 0.0003356933593750, 0.0026550292968750, 0.0003662109375000, +0.0015563964843750, 0.0003356933593750, 0.0022888183593750, 0.0002441406250000, +0.0003662109375000, 0.0003967285156250, 0.0007019042968750, 0.0003967285156250, +0.0003662109375000, 0.0002746582031250, -0.0010070800781250, 0.0005493164062500, +-0.0002136230468750, 0.0003356933593750, -0.0012207031250000, 0.0004882812500000, +-0.0011596679687500, 0.0005493164062500, -0.0008544921875000, 0.0003967285156250, +-0.0012207031250000, 0.0005493164062500, -0.0010070800781250, 0.0004577636718750, +-0.0004882812500000, 0.0004882812500000, -0.0005493164062500, 0.0005187988281250, +-0.0000915527343750, 0.0004882812500000, 0.0004882812500000, 0.0005187988281250, +0.0001831054687500, 0.0001525878906250, 0.0014953613281250, 0.0003967285156250, +0.0011291503906250, 0.0002441406250000, 0.0016784667968750, -0.0000305175781250, +0.0027465820312500, 0.0003356933593750, 0.0021057128906250, -0.0002136230468750, +0.0034790039062500, 0.0000915527343750, 0.0033874511718750, 0.0000000000000000, +0.0035400390625000, -0.0004272460937500, 0.0044555664062500, 0.0001525878906250, +0.0041503906250000, -0.0003051757812500, 0.0045776367187500, -0.0001831054687500, +0.0048217773437500, 0.0000610351562500, 0.0047302246093750, -0.0002136230468750, +0.0048217773437500, -0.0000610351562500, 0.0050964355468750, 0.0000610351562500, +0.0047607421875000, -0.0002441406250000, 0.0050354003906250, -0.0000610351562500, +0.0050048828125000, 0.0001220703125000, 0.0047302246093750, -0.0005187988281250, +0.0051574707031250, 0.0003967285156250, 0.0047302246093750, -0.0001831054687500, +0.0050048828125000, -0.0000915527343750, 0.0048828125000000, 0.0006713867187500, +0.0045776367187500, -0.0001831054687500, 0.0050659179687500, 0.0005493164062500, +0.0042724609375000, 0.0004577636718750, 0.0047607421875000, 0.0003356933593750, +0.0044860839843750, 0.0006713867187500, 0.0038757324218750, 0.0004882812500000, +0.0046386718750000, 0.0004882812500000, 0.0033264160156250, 0.0006713867187500, +0.0038452148437500, 0.0004577636718750, 0.0035095214843750, 0.0003051757812500, +0.0023803710937500, 0.0003967285156250, 0.0031433105468750, -0.0000915527343750, +0.0021362304687500, -0.0000305175781250, 0.0020751953125000, -0.0001220703125000, +0.0024108886718750, -0.0004577636718750, 0.0020446777343750, -0.0002441406250000, +0.0018310546875000, -0.0006103515625000, 0.0026855468750000, -0.0003356933593750, +0.0022583007812500, -0.0004882812500000, 0.0025329589843750, -0.0007934570312500, +0.0033264160156250, -0.0001831054687500, 0.0027465820312500, -0.0010070800781250, +0.0034790039062500, -0.0007019042968750, 0.0036315917968750, -0.0007019042968750, +0.0032653808593750, -0.0012207031250000, 0.0033569335937500, -0.0007324218750000, +0.0035400390625000, -0.0011291503906250, 0.0024414062500000, -0.0010681152343750, +0.0025634765625000, -0.0010070800781250, 0.0021667480468750, -0.0012207031250000, +0.0011901855468750, -0.0011291503906250, 0.0014343261718750, -0.0010986328125000, +0.0007629394531250, -0.0012207031250000, 0.0005798339843750, -0.0010375976562500, +0.0005493164062500, -0.0008850097656250, 0.0002746582031250, -0.0011291503906250, +0.0003051757812500, -0.0006103515625000, 0.0002746582031250, -0.0008239746093750, +0.0002136230468750, -0.0008239746093750, 0.0001525878906250, -0.0005798339843750, +0.0000610351562500, -0.0008850097656250, 0.0000915527343750, -0.0007019042968750, +0.0004577636718750, -0.0008544921875000, 0.0002746582031250, -0.0007019042968750, +0.0008239746093750, -0.0004272460937500, 0.0014038085937500, -0.0007019042968750, +0.0010986328125000, -0.0000305175781250, 0.0024414062500000, -0.0001220703125000, +0.0022277832031250, 0.0000915527343750, 0.0027160644531250, 0.0006103515625000, +0.0038452148437500, 0.0003662109375000, 0.0032653808593750, 0.0009460449218750, +0.0046081542968750, 0.0009460449218750, 0.0047302246093750, 0.0010986328125000, +0.0044555664062500, 0.0015563964843750, 0.0050354003906250, 0.0014343261718750, +0.0049133300781250, 0.0019531250000000, 0.0034484863281250, 0.0020141601562500, +0.0038757324218750, 0.0020141601562500, 0.0031433105468750, 0.0022583007812500, +0.0016174316406250, 0.0022277832031250, 0.0021667480468750, 0.0019531250000000, +0.0010681152343750, 0.0021057128906250, 0.0007629394531250, 0.0018310546875000, +0.0007324218750000, 0.0011291503906250, 0.0000000000000000, 0.0005493164062500, +0.0041809082031250, 0.0018005371093750, 0.0028686523437500, 0.0011901855468750, +0.0035095214843750, 0.0013122558593750, 0.0024719238281250, 0.0016784667968750, +0.0014038085937500, 0.0011596679687500, 0.0021667480468750, 0.0016174316406250, +-0.0000305175781250, 0.0010986328125000, 0.0000915527343750, 0.0014953613281250, +-0.0000915527343750, 0.0020751953125000, -0.0016479492187500, 0.0011596679687500, +-0.0011596679687500, 0.0028381347656250, -0.0009765625000000, 0.0024719238281250, +-0.0015258789062500, 0.0025634765625000, -0.0008850097656250, 0.0037536621093750, +-0.0000305175781250, 0.0030822753906250, -0.0006713867187500, 0.0036010742187500, +0.0002136230468750, 0.0036621093750000, 0.0003356933593750, 0.0036315917968750, +0.0001220703125000, 0.0038757324218750, 0.0003356933593750, 0.0037231445312500, +0.0002136230468750, 0.0046691894531250, 0.0000915527343750, 0.0044250488281250, +0.0000915527343750, 0.0046081542968750, -0.0001831054687500, 0.0055236816406250, +-0.0004272460937500, 0.0052490234375000, -0.0003356933593750, 0.0049133300781250, +-0.0012512207031250, 0.0057373046875000, -0.0010986328125000, 0.0047302246093750, +-0.0014953613281250, 0.0037841796875000, -0.0023803710937500, 0.0050048828125000, +-0.0020751953125000, 0.0018615722656250, -0.0024719238281250, 0.0026550292968750, +-0.0028381347656250, 0.0020446777343750, -0.0023193359375000, -0.0003051757812500, +-0.0020141601562500, 0.0011596679687500, -0.0023498535156250, -0.0006103515625000, +-0.0013122558593750, -0.0007324218750000, -0.0013122558593750, -0.0004272460937500, +-0.0013122558593750, -0.0011901855468750, -0.0007629394531250, -0.0009765625000000, +-0.0009155273437500, -0.0004882812500000, -0.0005187988281250, -0.0010681152343750, +-0.0003662109375000, -0.0003967285156250, -0.0004882812500000, 0.0003051757812500, +-0.0003051757812500, -0.0004577636718750, -0.0001831054687500, 0.0016784667968750, +-0.0006103515625000, 0.0009155273437500, -0.0004577636718750, 0.0018920898437500, +-0.0005798339843750, 0.0036621093750000, -0.0010986328125000, 0.0020751953125000, +-0.0008850097656250, 0.0054016113281250, -0.0007019042968750, 0.0048522949218750, +-0.0009155273437500, 0.0054016113281250, -0.0006103515625000, 0.0077209472656250, +-0.0001220703125000, 0.0063781738281250, -0.0003662109375000, 0.0082092285156250, +0.0001831054687500, 0.0081481933593750, 0.0003051757812500, 0.0081481933593750, +0.0002746582031250, 0.0090026855468750, 0.0004882812500000, 0.0083618164062500, +0.0004882812500000, 0.0090332031250000, 0.0004272460937500, 0.0088806152343750, +0.0004577636718750, 0.0088195800781250, 0.0003051757812500, 0.0090637207031250, +0.0001525878906250, 0.0086364746093750, 0.0002746582031250, 0.0090332031250000, +-0.0001525878906250, 0.0087890625000000, -0.0001220703125000, 0.0087890625000000, +-0.0001831054687500, 0.0090942382812500, -0.0004882812500000, 0.0086669921875000, +-0.0004577636718750, 0.0090637207031250, -0.0003967285156250, 0.0089416503906250, +-0.0005187988281250, 0.0088500976562500, -0.0003967285156250, 0.0090637207031250, +-0.0003051757812500, 0.0088806152343750, -0.0004882812500000, 0.0088195800781250, +-0.0000915527343750, 0.0088195800781250, -0.0003967285156250, 0.0085144042968750, +-0.0002746582031250, 0.0082702636718750, 0.0000915527343750, 0.0082702636718750, +-0.0005187988281250, 0.0074768066406250, 0.0000000000000000, 0.0075073242187500, +-0.0003051757812500, 0.0067749023437500, -0.0004577636718750, 0.0058898925781250, +-0.0001831054687500, 0.0063171386718750, -0.0005493164062500, 0.0044250488281250, +-0.0003662109375000, 0.0044860839843750, -0.0005187988281250, 0.0039062500000000, +-0.0004272460937500, 0.0024719238281250, -0.0003051757812500, 0.0029296875000000, +-0.0005187988281250, 0.0014953613281250, -0.0001220703125000, 0.0012817382812500, +-0.0003356933593750, 0.0009765625000000, -0.0001831054687500, 0.0000915527343750, +0.0001220703125000, 0.0002441406250000, -0.0000915527343750, -0.0002746582031250, +0.0004577636718750, -0.0005187988281250, 0.0003967285156250, -0.0004577636718750, +0.0004272460937500, -0.0006103515625000, 0.0007629394531250, -0.0007324218750000, +0.0006408691406250, 0.0000000000000000, 0.0007629394531250, -0.0003356933593750, +0.0009460449218750, 0.0002441406250000, 0.0008544921875000, 0.0011291503906250, +0.0008239746093750, 0.0006103515625000, 0.0009765625000000, 0.0023803710937500, +0.0005798339843750, 0.0021972656250000, 0.0007324218750000, 0.0027160644531250, +0.0006713867187500, 0.0040588378906250, 0.0003967285156250, 0.0033874511718750, +0.0006103515625000, 0.0050354003906250, 0.0002746582031250, 0.0050354003906250, +0.0003662109375000, 0.0052795410156250, 0.0002746582031250, 0.0063171386718750, +0.0000915527343750, 0.0058593750000000, 0.0003662109375000, 0.0066223144531250, +-0.0000610351562500, 0.0067749023437500, 0.0000915527343750, 0.0067443847656250, +0.0000610351562500, 0.0071411132812500, -0.0001831054687500, 0.0070190429687500, +0.0000000000000000, 0.0067138671875000, -0.0003967285156250, 0.0069274902343750, +-0.0002746582031250, 0.0064697265625000, -0.0003967285156250, 0.0058898925781250, +-0.0007324218750000, 0.0062255859375000, -0.0005187988281250, 0.0052185058593750, +-0.0007934570312500, 0.0052490234375000, -0.0008544921875000, 0.0050354003906250, +-0.0007934570312500, 0.0043334960937500, -0.0009155273437500, 0.0045166015625000, +-0.0009460449218750, 0.0041198730468750, -0.0006408691406250, 0.0039367675781250, +-0.0008544921875000, 0.0039367675781250, -0.0007019042968750, 0.0037841796875000, +-0.0003051757812500, 0.0037536621093750, -0.0005493164062500, 0.0039062500000000, +-0.0002441406250000, 0.0038452148437500, -0.0001525878906250, 0.0039062500000000, +-0.0001220703125000, 0.0040283203125000, -0.0000305175781250, 0.0039672851562500, +0.0000610351562500, 0.0039978027343750, 0.0000915527343750, 0.0039672851562500, +0.0000915527343750, 0.0039062500000000, 0.0001220703125000, 0.0039062500000000, +0.0001525878906250}, +{0.0000610351562500, 0.0112304687500000, 0.0001220703125000, 0.0104675292968750, +0.0001220703125000, 0.0113830566406250, -0.0000610351562500, 0.0112609863281250, +0.0000610351562500, 0.0109863281250000, -0.0001525878906250, 0.0113220214843750, +-0.0004577636718750, 0.0110168457031250, -0.0001831054687500, 0.0106506347656250, +-0.0006713867187500, 0.0107727050781250, -0.0006713867187500, 0.0102233886718750, +-0.0005187988281250, 0.0097045898437500, -0.0006713867187500, 0.0100097656250000, +-0.0006103515625000, 0.0086364746093750, -0.0003662109375000, 0.0089721679687500, +-0.0005187988281250, 0.0083923339843750, -0.0003051757812500, 0.0071716308593750, +-0.0000915527343750, 0.0079650878906250, -0.0003967285156250, 0.0061645507812500, +0.0000915527343750, 0.0064697265625000, -0.0001831054687500, 0.0061950683593750, +-0.0001831054687500, 0.0050048828125000, 0.0001220703125000, 0.0057067871093750, +-0.0002441406250000, 0.0050048828125000, 0.0000610351562500, 0.0049133300781250, +-0.0000915527343750, 0.0051269531250000, -0.0000610351562500, 0.0049743652343750, +0.0000915527343750, 0.0051269531250000, -0.0000610351562500, 0.0049133300781250, +0.0002441406250000, 0.0050659179687500, 0.0001831054687500, 0.0049438476562500, +0.0003051757812500, 0.0048217773437500, 0.0006408691406250, 0.0050354003906250, +0.0004882812500000, 0.0046386718750000, 0.0007934570312500, 0.0047912597656250, +0.0007629394531250, 0.0046081542968750, 0.0008239746093750, 0.0042419433593750, +0.0009765625000000, 0.0043640136718750, 0.0008544921875000, 0.0037841796875000, +0.0009460449218750, 0.0037841796875000, 0.0009155273437500, 0.0036621093750000, +0.0005798339843750, 0.0032043457031250, 0.0004882812500000, 0.0031738281250000, +0.0007629394531250, 0.0032653808593750, 0.0003051757812500, 0.0029907226562500, +0.0003662109375000, 0.0033264160156250, 0.0003356933593750, 0.0036010742187500, +-0.0000305175781250, 0.0032043457031250, 0.0001831054687500, 0.0044860839843750, +-0.0002746582031250, 0.0041809082031250, -0.0001525878906250, 0.0046691894531250, +-0.0002746582031250, 0.0057373046875000, -0.0006408691406250, 0.0052490234375000, +-0.0003967285156250, 0.0066528320312500, -0.0007629394531250, 0.0065307617187500, +-0.0007019042968750, 0.0068664550781250, -0.0006103515625000, 0.0078430175781250, +-0.0007324218750000, 0.0073242187500000, -0.0006408691406250, 0.0083923339843750, +-0.0007629394531250, 0.0082397460937500, -0.0008239746093750, 0.0082702636718750, +-0.0008850097656250, 0.0088195800781250, -0.0009155273437500, 0.0083923339843750, +-0.0007629394531250, 0.0085144042968750, -0.0009155273437500, 0.0085449218750000, +-0.0009460449218750, 0.0081176757812500, -0.0008239746093750, 0.0079040527343750, +-0.0007324218750000, 0.0079345703125000, -0.0007324218750000, 0.0071716308593750, +-0.0004577636718750, 0.0071105957031250, -0.0003662109375000, 0.0068664550781250, +-0.0004577636718750, 0.0062561035156250, -0.0003356933593750, 0.0063476562500000, +-0.0002441406250000, 0.0061340332031250, -0.0002136230468750, 0.0058898925781250, +-0.0001220703125000, 0.0061035156250000, -0.0001220703125000, 0.0062255859375000, +-0.0001220703125000, 0.0058288574218750, -0.0001220703125000, 0.0065307617187500, +-0.0001831054687500, 0.0062255859375000, -0.0001831054687500, 0.0061645507812500, +-0.0002136230468750, 0.0065917968750000, -0.0002746582031250, 0.0061340332031250, +-0.0003356933593750, 0.0059814453125000, -0.0000915527343750, 0.0060119628906250, +-0.0002746582031250, 0.0057067871093750, -0.0001220703125000, 0.0054016113281250, +0.0001220703125000, 0.0054016113281250, -0.0001525878906250, 0.0049438476562500, +0.0002746582031250, 0.0049133300781250, 0.0001831054687500, 0.0046081542968750, +0.0001220703125000, 0.0042419433593750, 0.0003356933593750, 0.0043640136718750, +0.0001525878906250, 0.0032043457031250, 0.0002746582031250, 0.0033874511718750, +0.0000610351562500, 0.0027770996093750, 0.0000610351562500, 0.0017700195312500, +0.0001525878906250, 0.0023803710937500, -0.0001525878906250, 0.0008239746093750, +-0.0002136230468750, 0.0009765625000000, -0.0001831054687500, 0.0010070800781250, +-0.0003356933593750, 0.0002746582031250, -0.0004882812500000, 0.0007019042968750, +-0.0005493164062500, 0.0006103515625000, -0.0007019042968750, 0.0005798339843750, +-0.0007934570312500, 0.0007629394531250, -0.0006408691406250, 0.0008239746093750, +-0.0006103515625000, 0.0008850097656250, -0.0009460449218750, 0.0009460449218750, +-0.0003051757812500, 0.0010375976562500, -0.0004882812500000, 0.0008850097656250, +-0.0003967285156250, 0.0007629394531250, 0.0000305175781250, 0.0008850097656250, +-0.0002441406250000, 0.0006103515625000, 0.0004882812500000, 0.0005798339843750, +0.0003967285156250, 0.0004577636718750, 0.0006103515625000, 0.0003051757812500, +0.0012207031250000, 0.0002136230468750, 0.0011291503906250, -0.0001220703125000, +0.0011291503906250, -0.0000915527343750, 0.0012512207031250, -0.0000305175781250, +0.0011291503906250, -0.0001220703125000, 0.0010681152343750, -0.0002136230468750, +0.0012817382812500, -0.0001220703125000, 0.0007629394531250, -0.0001831054687500, +0.0008850097656250, -0.0001220703125000, 0.0009155273437500, -0.0001831054687500, +0.0006408691406250, -0.0003356933593750, 0.0009765625000000, 0.0002136230468750, +0.0009765625000000, -0.0000610351562500, 0.0010681152343750, 0.0001831054687500, +0.0011291503906250, 0.0007934570312500, 0.0011291503906250, 0.0003356933593750, +0.0013122558593750, 0.0007629394531250, 0.0012207031250000, 0.0008850097656250, +0.0014038085937500, 0.0006713867187500, 0.0011901855468750, 0.0006103515625000, +0.0009460449218750, 0.0006408691406250, 0.0012817382812500, 0.0003051757812500, +0.0004577636718750, 0.0002441406250000, 0.0003662109375000, 0.0000915527343750, +0.0003967285156250, -0.0002136230468750, -0.0000305175781250, -0.0000915527343750, +0.0000000000000000, -0.0005187988281250, 0.0004577636718750, -0.0003662109375000, +-0.0002136230468750, -0.0005187988281250, 0.0006408691406250, -0.0009155273437500, +0.0015563964843750, -0.0007324218750000, 0.0005187988281250, -0.0010070800781250, +0.0031433105468750, -0.0011901855468750, 0.0025939941406250, -0.0009155273437500, +0.0031738281250000, -0.0009155273437500, 0.0050354003906250, -0.0011596679687500, +0.0039672851562500, -0.0005493164062500, 0.0059204101562500, -0.0007019042968750, +0.0058593750000000, -0.0005798339843750, 0.0061340332031250, -0.0001525878906250, +0.0072937011718750, -0.0005493164062500, 0.0067749023437500, -0.0001831054687500, +0.0077209472656250, -0.0003051757812500, 0.0079345703125000, -0.0003051757812500, +0.0078735351562500, -0.0000915527343750, 0.0082092285156250, -0.0004272460937500, +0.0082702636718750, -0.0001220703125000, 0.0080871582031250, -0.0002441406250000, +0.0081787109375000, -0.0002441406250000, 0.0082092285156250, -0.0000610351562500, +0.0080261230468750, -0.0003356933593750, 0.0080871582031250, -0.0002746582031250, +0.0081176757812500, -0.0002746582031250, 0.0079650878906250, -0.0003051757812500, +0.0080871582031250, -0.0003356933593750, 0.0082702636718750, -0.0003967285156250, +0.0081481933593750, -0.0005187988281250, 0.0082702636718750, -0.0003967285156250, +0.0083007812500000, -0.0006103515625000, 0.0081176757812500, -0.0008850097656250, +0.0080871582031250, -0.0007019042968750, 0.0081787109375000, -0.0014038085937500, +0.0077209472656250, -0.0013732910156250, 0.0078735351562500, -0.0014038085937500, +0.0077209472656250, -0.0018615722656250, 0.0073852539062500, -0.0017089843750000, +0.0076904296875000, -0.0016174316406250, 0.0072937011718750, -0.0018615722656250, +0.0074768066406250, -0.0015258789062500, 0.0075378417968750, -0.0011596679687500, +0.0073852539062500, -0.0014648437500000, 0.0076904296875000, -0.0004882812500000, +0.0075683593750000, -0.0006408691406250, 0.0078125000000000, -0.0003662109375000, +0.0078125000000000, 0.0003662109375000, 0.0077514648437500, -0.0000305175781250, +0.0080261230468750, 0.0007019042968750, 0.0077514648437500, 0.0007629394531250, +0.0080261230468750, 0.0006408691406250, 0.0078125000000000, 0.0009155273437500, +0.0074462890625000, 0.0008850097656250, 0.0078125000000000, 0.0006408691406250, +0.0069580078125000, 0.0007934570312500, 0.0071105957031250, 0.0006103515625000, +0.0068664550781250, 0.0003967285156250, 0.0062561035156250, 0.0007629394531250, +0.0065917968750000, 0.0002136230468750, 0.0059814453125000, 0.0005798339843750, +0.0060119628906250, 0.0005187988281250, 0.0059204101562500, 0.0001220703125000, +0.0056762695312500, 0.0007019042968750, 0.0059814453125000, 0.0000610351562500, +0.0054931640625000, 0.0003051757812500, 0.0057678222656250, 0.0003662109375000, +0.0057373046875000, 0.0000000000000000, 0.0054321289062500, 0.0003051757812500, +0.0059204101562500, 0.0001525878906250, 0.0053710937500000, 0.0001220703125000, +0.0057373046875000, 0.0001831054687500, 0.0056152343750000, 0.0000915527343750, +0.0051879882812500, 0.0000000000000000, 0.0056457519531250, 0.0002441406250000, +0.0049133300781250, -0.0000915527343750, 0.0051269531250000, 0.0000305175781250, +0.0049743652343750, 0.0002746582031250, 0.0043029785156250, -0.0002441406250000, +0.0046386718750000, 0.0003051757812500, 0.0042419433593750, 0.0000610351562500, +0.0041503906250000, -0.0000305175781250, 0.0042419433593750, 0.0003356933593750, +0.0041809082031250, -0.0000610351562500, 0.0042114257812500, 0.0001220703125000, +0.0047912597656250, 0.0002136230468750, 0.0046081542968750, 0.0001220703125000, +0.0050048828125000, 0.0001831054687500, 0.0057067871093750, 0.0002746582031250, +0.0053710937500000, 0.0001831054687500, 0.0066223144531250, 0.0002136230468750, +0.0065612792968750, 0.0002136230468750, 0.0068359375000000, 0.0001220703125000, +0.0077514648437500, 0.0001831054687500, 0.0073852539062500, 0.0000915527343750, +0.0078430175781250, 0.0001831054687500, 0.0079345703125000, 0.0001220703125000, +0.0078430175781250, 0.0000610351562500, 0.0078430175781250, 0.0002136230468750, +0.0076293945312500, -0.0001220703125000, 0.0075378417968750, 0.0000915527343750, +0.0073547363281250, 0.0000305175781250, 0.0072326660156250, -0.0002136230468750, +0.0071716308593750, 0.0001220703125000, 0.0069580078125000, -0.0003662109375000, +0.0069885253906250, -0.0002441406250000, 0.0068969726562500, -0.0003356933593750, +0.0067138671875000, -0.0007324218750000, 0.0065612792968750, -0.0005798339843750, +0.0065612792968750, -0.0007629394531250, 0.0060424804687500, -0.0009460449218750, +0.0060119628906250, -0.0007629394531250, 0.0057678222656250, -0.0007019042968750, +0.0053405761718750, -0.0008544921875000, 0.0053710937500000, -0.0003967285156250, +0.0050964355468750, -0.0005493164062500, 0.0050048828125000, -0.0004577636718750, +0.0051269531250000, -0.0000915527343750, 0.0051574707031250, -0.0004882812500000, +0.0050964355468750, -0.0000305175781250, 0.0055236816406250, -0.0003967285156250, +0.0055541992187500, -0.0003662109375000, 0.0054626464843750, -0.0001525878906250, +0.0057067871093750, -0.0006713867187500, 0.0056152343750000, 0.0001525878906250, +0.0053100585937500, -0.0001831054687500, 0.0054626464843750, -0.0001220703125000, +0.0050354003906250, 0.0005798339843750, 0.0044860839843750, 0.0001220703125000, +0.0047302246093750, 0.0005187988281250, 0.0038452148437500, 0.0007019042968750, +0.0039062500000000, 0.0005493164062500, 0.0035095214843750, 0.0006103515625000, +0.0028381347656250, 0.0006408691406250, 0.0032043457031250, 0.0004882812500000, +0.0023803710937500}, +{0.0089416503906250, 0.0007629394531250, 0.0086059570312500, 0.0009765625000000, +0.0086669921875000, 0.0007629394531250, 0.0087890625000000, 0.0007629394531250, +0.0086364746093750, 0.0010070800781250, 0.0087890625000000, 0.0004272460937500, +0.0089111328125000, 0.0008850097656250, 0.0089416503906250, 0.0007324218750000, +0.0090332031250000, 0.0003051757812500, 0.0091552734375000, 0.0010070800781250, +0.0091552734375000, 0.0003356933593750, 0.0090332031250000, 0.0006408691406250, +0.0090332031250000, 0.0007629394531250, 0.0089416503906250, 0.0003051757812500, +0.0087585449218750, 0.0007324218750000, 0.0088195800781250, 0.0003967285156250, +0.0083618164062500, 0.0003662109375000, 0.0084838867187500, 0.0004272460937500, +0.0083007812500000, 0.0002441406250000, 0.0079345703125000, 0.0000915527343750, +0.0081481933593750, 0.0003662109375000, 0.0074157714843750, 0.0000915527343750, +0.0076904296875000, 0.0002136230468750, 0.0073242187500000, 0.0004882812500000, +0.0067443847656250, 0.0001220703125000, 0.0072326660156250, 0.0004882812500000, +0.0060729980468750, 0.0004577636718750, 0.0064392089843750, 0.0003662109375000, +0.0060119628906250, 0.0006408691406250, 0.0049743652343750, 0.0005798339843750, +0.0056762695312500, 0.0004577636718750, 0.0044250488281250, 0.0007019042968750, +0.0046386718750000, 0.0004577636718750, 0.0043945312500000, 0.0001525878906250, +0.0035095214843750, 0.0005493164062500, 0.0040893554687500, -0.0001220703125000, +0.0033569335937500, -0.0000305175781250, 0.0030822753906250, -0.0000305175781250, +0.0034790039062500, -0.0004577636718750, 0.0033569335937500, -0.0001220703125000, +0.0032043457031250, -0.0004577636718750, 0.0040893554687500, -0.0003051757812500, +0.0036926269531250, -0.0002136230468750, 0.0041809082031250, -0.0003051757812500, +0.0051574707031250, 0.0000305175781250, 0.0046081542968750, -0.0001831054687500, +0.0055541992187500, 0.0000000000000000, 0.0056152343750000, 0.0000305175781250, +0.0055541992187500, -0.0001220703125000, 0.0059509277343750, 0.0000610351562500, +0.0057373046875000, -0.0001525878906250, 0.0054626464843750, -0.0002746582031250, +0.0055236816406250, -0.0001831054687500, 0.0053710937500000, -0.0002746582031250, +0.0050659179687500, -0.0004272460937500, 0.0051269531250000, -0.0001220703125000, +0.0050048828125000, -0.0003051757812500, 0.0047607421875000, -0.0002746582031250, +0.0048522949218750, -0.0000305175781250, 0.0048522949218750, -0.0003356933593750, +0.0046997070312500, 0.0000305175781250, 0.0049743652343750, -0.0002746582031250, +0.0048828125000000, -0.0001831054687500, 0.0050354003906250, 0.0000000000000000, +0.0052490234375000, -0.0006103515625000, 0.0050659179687500, 0.0002441406250000, +0.0057373046875000, -0.0001525878906250, 0.0056152343750000, -0.0001220703125000, +0.0059204101562500, 0.0004882812500000, 0.0065307617187500, 0.0000000000000000, +0.0061035156250000, 0.0004272460937500, 0.0069580078125000, 0.0004272460937500, +0.0069580078125000, 0.0002441406250000, 0.0067749023437500, 0.0004272460937500, +0.0070190429687500, 0.0004577636718750, 0.0069580078125000, 0.0002746582031250, +0.0067138671875000, 0.0004577636718750, 0.0067443847656250, 0.0003051757812500, +0.0063781738281250, 0.0000610351562500, 0.0059814453125000, 0.0004272460937500, +0.0060729980468750, -0.0000305175781250, 0.0054016113281250, 0.0001525878906250, +0.0054931640625000, 0.0001220703125000, 0.0052185058593750, -0.0001831054687500, +0.0046997070312500, 0.0002136230468750, 0.0049438476562500, 0.0000610351562500, +0.0040893554687500, 0.0000610351562500, 0.0039672851562500, 0.0003356933593750, +0.0038452148437500, 0.0004577636718750, 0.0034484863281250, 0.0003967285156250, +0.0034790039062500, 0.0008239746093750, 0.0027160644531250, 0.0008239746093750, +0.0030212402343750, 0.0009765625000000, 0.0023803710937500, 0.0012512207031250, +0.0014648437500000, 0.0011291503906250, 0.0019836425781250, 0.0015869140625000, +0.0005798339843750, 0.0014953613281250, 0.0004882812500000, 0.0017089843750000, +0.0006103515625000, 0.0025329589843750, -0.0002136230468750, 0.0036926269531250, +0.0036621093750000, 0.0025329589843750, 0.0012512207031250, 0.0034484863281250, +0.0022277832031250, 0.0028076171875000, 0.0015869140625000, 0.0018310546875000, +0.0002441406250000, 0.0025939941406250, 0.0010070800781250, 0.0017395019531250, +0.0003051757812500, 0.0018005371093750, 0.0002441406250000, 0.0018310546875000, +0.0006408691406250, 0.0014648437500000, 0.0005187988281250, 0.0017395019531250, +0.0004882812500000, 0.0012512207031250, 0.0014648437500000, 0.0011596679687500, +0.0011596679687500, 0.0014648437500000, 0.0017089843750000, 0.0012512207031250, +0.0027770996093750, 0.0010681152343750, 0.0022583007812500, 0.0021667480468750, +0.0032348632812500, 0.0017395019531250, 0.0035705566406250, 0.0024719238281250, +0.0031433105468750, 0.0037536621093750, 0.0033569335937500, 0.0029907226562500, +0.0036010742187500, 0.0048217773437500, 0.0022888183593750, 0.0050964355468750, +0.0026245117187500, 0.0050354003906250, 0.0022277832031250, 0.0058898925781250, +0.0010681152343750, 0.0060119628906250, 0.0016174316406250, 0.0063781738281250, +0.0008544921875000, 0.0063171386718750, 0.0006408691406250, 0.0068359375000000, +0.0007324218750000, 0.0072631835937500, 0.0003967285156250, 0.0068969726562500, +0.0003356933593750, 0.0082702636718750, 0.0002136230468750, 0.0080566406250000, +-0.0000305175781250, 0.0083618164062500, 0.0001525878906250, 0.0094299316406250, +0.0002441406250000, 0.0090637207031250, -0.0001220703125000, 0.0092468261718750, +0.0006103515625000, 0.0099182128906250, 0.0006103515625000, 0.0093383789062500, +0.0003967285156250, 0.0089111328125000, 0.0007629394531250, 0.0097045898437500, +0.0007324218750000, 0.0082397460937500, 0.0001525878906250, 0.0086975097656250, +0.0003967285156250, 0.0085449218750000, 0.0001220703125000, 0.0076599121093750, +-0.0004577636718750, 0.0086059570312500, -0.0001220703125000, 0.0075988769531250, +-0.0007324218750000, 0.0081176757812500, -0.0007019042968750, 0.0081176757812500, +-0.0006408691406250, 0.0075683593750000, -0.0009765625000000, 0.0084533691406250, +-0.0007629394531250, 0.0070800781250000, -0.0007324218750000, 0.0078125000000000, +-0.0008850097656250, 0.0071716308593750, -0.0005798339843750, 0.0057678222656250, +-0.0003051757812500, 0.0069580078125000, -0.0005187988281250, 0.0043945312500000, +0.0000000000000000, 0.0049133300781250, 0.0000305175781250, 0.0043029785156250, +-0.0001220703125000, 0.0025024414062500, -0.0000305175781250, 0.0036926269531250, +-0.0001220703125000, 0.0014953613281250, -0.0004577636718750, 0.0017395019531250, +-0.0005493164062500, 0.0016479492187500, -0.0005798339843750, 0.0004272460937500, +-0.0007629394531250, 0.0011291503906250, -0.0008239746093750, 0.0007934570312500, +-0.0006103515625000, 0.0006408691406250, -0.0007934570312500, 0.0009765625000000, +-0.0006408691406250, 0.0010986328125000, -0.0003967285156250, 0.0010986328125000, +-0.0007019042968750, 0.0016784667968750, -0.0001220703125000, 0.0014648437500000, +-0.0002441406250000, 0.0019226074218750, -0.0002441406250000, 0.0024719238281250, +0.0001831054687500, 0.0019836425781250, -0.0000305175781250, 0.0035095214843750, +0.0000305175781250, 0.0030212402343750, 0.0001525878906250, 0.0036926269531250, +-0.0000305175781250, 0.0050659179687500, -0.0001220703125000, 0.0040893554687500, +0.0000610351562500, 0.0061035156250000, -0.0001525878906250, 0.0060424804687500, +-0.0000915527343750, 0.0063781738281250, -0.0000305175781250, 0.0076293945312500, +-0.0000915527343750, 0.0071105957031250, -0.0000305175781250, 0.0082702636718750, +0.0001525878906250, 0.0084838867187500, 0.0001525878906250, 0.0087890625000000, +0.0002746582031250, 0.0095825195312500, 0.0004882812500000, 0.0096130371093750, +0.0003967285156250, 0.0101318359375000, 0.0006713867187500, 0.0104980468750000, +0.0007019042968750, 0.0105895996093750, 0.0006713867187500, 0.0108337402343750, +0.0007934570312500, 0.0111389160156250, 0.0007019042968750, 0.0107116699218750, +0.0004577636718750, 0.0110473632812500, 0.0007019042968750, 0.0107421875000000, +0.0004882812500000, 0.0102539062500000, 0.0003051757812500, 0.0107421875000000, +0.0006103515625000, 0.0097351074218750, 0.0000610351562500, 0.0100402832031250, +0.0003051757812500, 0.0097045898437500, 0.0003051757812500, 0.0089721679687500, +0.0000305175781250, 0.0096130371093750, 0.0003051757812500, 0.0083618164062500, +-0.0001525878906250, 0.0085449218750000, -0.0000915527343750, 0.0081787109375000, +-0.0001525878906250, 0.0072937011718750, -0.0004272460937500, 0.0079345703125000, +-0.0001831054687500, 0.0065307617187500, -0.0005798339843750, 0.0067749023437500, +-0.0004882812500000, 0.0062255859375000, -0.0005798339843750, 0.0051574707031250, +-0.0008544921875000, 0.0057678222656250, -0.0005798339843750, 0.0041503906250000, +-0.0009765625000000, 0.0043029785156250, -0.0009765625000000, 0.0038452148437500, +-0.0008850097656250, 0.0026550292968750, -0.0010375976562500, 0.0032653808593750, +-0.0010681152343750, 0.0018615722656250, -0.0010375976562500, 0.0018920898437500, +-0.0009460449218750, 0.0018310546875000, -0.0008850097656250, 0.0010375976562500, +-0.0008544921875000, 0.0014038085937500, -0.0007934570312500, 0.0013122558593750, +-0.0007324218750000, 0.0010986328125000, -0.0006408691406250, 0.0015563964843750, +-0.0006408691406250, 0.0018615722656250, -0.0006408691406250, 0.0017089843750000, +-0.0005187988281250, 0.0025939941406250, -0.0005798339843750, 0.0026550292968750, +-0.0004882812500000, 0.0028686523437500, -0.0004577636718750, 0.0036010742187500, +-0.0004882812500000, 0.0033874511718750, -0.0004577636718750, 0.0037841796875000, +-0.0003356933593750, 0.0040588378906250, -0.0004882812500000, 0.0036315917968750, +-0.0003662109375000, 0.0034484863281250, -0.0001525878906250, 0.0037841796875000, +-0.0003051757812500, 0.0024108886718750, 0.0000305175781250, 0.0027160644531250, +0.0000305175781250, 0.0022583007812500, -0.0000305175781250, 0.0011291503906250, +0.0001831054687500, 0.0018615722656250, 0.0000915527343750, 0.0009765625000000, +-0.0000305175781250, 0.0007934570312500, 0.0000915527343750, 0.0012817382812500, +0.0000610351562500, 0.0011901855468750, -0.0000610351562500, 0.0011596679687500, +0.0000000000000000, 0.0022277832031250, -0.0000610351562500, 0.0020751953125000, +-0.0001525878906250, 0.0025329589843750, -0.0001831054687500, 0.0034484863281250, +-0.0001831054687500, 0.0030517578125000, -0.0002746582031250, 0.0040588378906250, +-0.0003662109375000, 0.0039978027343750, -0.0003662109375000, 0.0042419433593750, +-0.0003662109375000, 0.0048828125000000, -0.0004577636718750, 0.0044555664062500, +-0.0003662109375000, 0.0053405761718750, -0.0003356933593750, 0.0053405761718750, +-0.0003662109375000, 0.0054016113281250, -0.0001220703125000, 0.0060424804687500, +0.0000915527343750, 0.0059204101562500, -0.0001525878906250, 0.0056762695312500, +0.0005493164062500, 0.0062561035156250, 0.0004272460937500, 0.0057983398437500, +0.0005493164062500, 0.0051879882812500, 0.0010681152343750, 0.0058898925781250, +0.0008239746093750, 0.0046081542968750, 0.0009155273437500, 0.0046997070312500, +0.0011291503906250, 0.0045471191406250, 0.0008544921875000, 0.0037841796875000, +0.0005798339843750, 0.0040893554687500, 0.0009765625000000, 0.0032348632812500, +0.0003662109375000, 0.0033569335937500, 0.0004882812500000, 0.0030517578125000, +0.0007019042968750}, +{-0.0001525878906250, 0.0028381347656250, -0.0001525878906250, 0.0034790039062500, +-0.0001220703125000, 0.0032653808593750, 0.0000915527343750, 0.0042114257812500, +-0.0000915527343750, 0.0043945312500000, -0.0000305175781250, 0.0045776367187500, +-0.0000915527343750, 0.0052185058593750, -0.0001831054687500, 0.0052795410156250, +0.0000000000000000, 0.0056152343750000, -0.0002441406250000, 0.0057373046875000, +-0.0001525878906250, 0.0058288574218750, -0.0002441406250000, 0.0060729980468750, +-0.0003967285156250, 0.0060424804687500, -0.0002136230468750, 0.0063476562500000, +-0.0005493164062500, 0.0063171386718750, -0.0004882812500000, 0.0065307617187500, +-0.0005493164062500, 0.0068359375000000, -0.0007324218750000, 0.0066833496093750, +-0.0006103515625000, 0.0069885253906250, -0.0009155273437500, 0.0071105957031250, +-0.0007629394531250, 0.0071105957031250, -0.0007324218750000, 0.0072631835937500, +-0.0009460449218750, 0.0072937011718750, -0.0006713867187500, 0.0072021484375000, +-0.0007629394531250, 0.0073242187500000, -0.0007324218750000, 0.0072631835937500, +-0.0007019042968750, 0.0070800781250000, -0.0005798339843750, 0.0072937011718750, +-0.0004882812500000, 0.0069580078125000, -0.0004882812500000, 0.0069885253906250, +-0.0004272460937500, 0.0070190429687500, -0.0004272460937500, 0.0068664550781250, +-0.0003967285156250, 0.0068359375000000, -0.0003662109375000, 0.0069274902343750, +-0.0003662109375000, 0.0067749023437500, -0.0004882812500000, 0.0068664550781250, +-0.0003967285156250, 0.0070495605468750, -0.0003662109375000, 0.0068054199218750, +-0.0005493164062500, 0.0073547363281250, -0.0001220703125000, 0.0072937011718750, +-0.0003356933593750, 0.0074157714843750, -0.0003051757812500, 0.0078735351562500, +0.0000305175781250, 0.0077514648437500, -0.0002441406250000, 0.0078430175781250, +0.0000915527343750, 0.0081176757812500, -0.0000610351562500, 0.0077514648437500, +-0.0000610351562500, 0.0075073242187500, 0.0000915527343750, 0.0078430175781250, +-0.0000915527343750, 0.0062866210937500, -0.0000610351562500, 0.0066528320312500, +-0.0000610351562500, 0.0059509277343750, -0.0001831054687500, 0.0043640136718750, +-0.0002441406250000, 0.0051574707031250, -0.0003356933593750, 0.0034179687500000, +-0.0004577636718750, 0.0032348632812500, -0.0004882812500000, 0.0032958984375000, +-0.0004577636718750, 0.0024719238281250, -0.0004882812500000, 0.0025939941406250, +-0.0004577636718750, 0.0027465820312500, -0.0002441406250000, 0.0025329589843750, +-0.0003356933593750, 0.0026550292968750, 0.0000000000000000, 0.0029296875000000, +0.0003051757812500, 0.0027160644531250, 0.0000610351562500, 0.0028686523437500, +0.0007324218750000, 0.0028686523437500, 0.0006103515625000, 0.0028381347656250, +0.0007324218750000, 0.0029907226562500, 0.0012512207031250, 0.0029907226562500, +0.0008850097656250, 0.0033264160156250, 0.0010681152343750, 0.0033264160156250, +0.0012512207031250, 0.0035400390625000, 0.0009155273437500, 0.0039367675781250, +0.0007019042968750, 0.0039672851562500, 0.0010375976562500, 0.0043640136718750, +0.0004272460937500, 0.0043945312500000, 0.0004577636718750, 0.0043945312500000, +0.0007019042968750, 0.0044860839843750, 0.0005493164062500, 0.0044250488281250, +0.0006713867187500, 0.0045471191406250, 0.0010070800781250, 0.0044555664062500, +0.0010986328125000, 0.0043945312500000, 0.0010681152343750, 0.0043640136718750, +0.0013427734375000, 0.0038757324218750, 0.0016174316406250, 0.0031738281250000, +0.0009765625000000, 0.0034790039062500, 0.0013427734375000, 0.0030822753906250, +0.0014038085937500, 0.0022888183593750, 0.0009155273437500, 0.0025939941406250, +0.0013427734375000, 0.0014343261718750, 0.0014038085937500, 0.0013732910156250, +0.0011901855468750, 0.0011596679687500, 0.0017395019531250, 0.0004882812500000, +0.0020446777343750, 0.0007934570312500, 0.0017089843750000, 0.0003967285156250, +0.0033874511718750, 0.0003051757812500, 0.0028991699218750, 0.0005798339843750, +0.0035705566406250, 0.0005798339843750, 0.0051574707031250, 0.0005493164062500, +0.0042419433593750, 0.0011291503906250, 0.0058593750000000, 0.0010681152343750, +0.0058898925781250, 0.0010375976562500, 0.0057678222656250, 0.0014953613281250, +0.0065917968750000, 0.0013732910156250, 0.0063476562500000, 0.0010986328125000, +0.0060119628906250, 0.0013427734375000, 0.0062561035156250, 0.0009765625000000, +0.0059204101562500, 0.0003967285156250, 0.0054931640625000, 0.0007324218750000, +0.0058593750000000, 0.0004577636718750, 0.0047912597656250, 0.0000610351562500, +0.0050659179687500, 0.0004272460937500, 0.0047912597656250, 0.0007019042968750, +0.0039978027343750, 0.0001525878906250, 0.0046386718750000, 0.0012512207031250, +0.0033569335937500, 0.0009765625000000, 0.0034790039062500, 0.0010681152343750, +0.0034484863281250, 0.0018005371093750, 0.0027160644531250, 0.0013427734375000, +0.0030517578125000, 0.0017089843750000, 0.0028686523437500, 0.0018615722656250, +0.0027160644531250, 0.0014953613281250, 0.0028686523437500, 0.0014343261718750, +0.0030212402343750, 0.0017089843750000, 0.0029602050781250, 0.0006408691406250, +0.0029602050781250, 0.0010681152343750, 0.0031433105468750, 0.0007629394531250, +0.0028991699218750, -0.0001220703125000, 0.0026245117187500, 0.0006408691406250, +0.0029907226562500, -0.0002136230468750, 0.0023803710937500, -0.0000915527343750, +0.0024108886718750, 0.0000915527343750, 0.0025939941406250, -0.0001525878906250, +0.0024414062500000, 0.0000305175781250, 0.0025939941406250, -0.0000915527343750, +0.0032043457031250, 0.0000610351562500, 0.0030822753906250, 0.0000305175781250, +0.0036315917968750, -0.0000610351562500, 0.0043945312500000, 0.0001220703125000, +0.0040588378906250, -0.0002441406250000, 0.0048522949218750, 0.0000000000000000, +0.0051269531250000, -0.0001525878906250, 0.0050048828125000, -0.0004272460937500, +0.0051879882812500, -0.0001525878906250, 0.0053405761718750, -0.0006408691406250, +0.0047912597656250, -0.0005187988281250, 0.0050659179687500, -0.0005493164062500, +0.0047607421875000, -0.0008850097656250, 0.0041198730468750, -0.0005493164062500, +0.0045776367187500, -0.0008544921875000, 0.0037231445312500, -0.0007324218750000, +0.0037231445312500, -0.0007019042968750, 0.0036926269531250, -0.0008850097656250, +0.0031738281250000, -0.0007019042968750, 0.0033264160156250, -0.0010681152343750, +0.0033569335937500, -0.0008544921875000, 0.0031433105468750, -0.0009460449218750, +0.0033874511718750, -0.0012512207031250, 0.0036621093750000, -0.0009155273437500, +0.0033264160156250, -0.0012512207031250, 0.0039062500000000, -0.0011596679687500, +0.0038757324218750, -0.0010986328125000, 0.0037536621093750, -0.0012817382812500, +0.0039062500000000, -0.0010681152343750, 0.0037536621093750, -0.0010375976562500, +0.0034790039062500, -0.0010375976562500, 0.0034790039062500, -0.0007629394531250, +0.0031738281250000, -0.0004882812500000, 0.0028076171875000, -0.0005493164062500, +0.0029296875000000, 0.0000915527343750, 0.0023498535156250, -0.0000305175781250, +0.0021972656250000, 0.0002136230468750, 0.0020751953125000, 0.0007934570312500, +0.0018005371093750, 0.0004577636718750, 0.0018920898437500, 0.0010681152343750, +0.0020446777343750, 0.0010375976562500, 0.0018615722656250, 0.0010986328125000, +0.0022277832031250, 0.0014343261718750, 0.0025939941406250, 0.0011291503906250, +0.0023498535156250, 0.0014648437500000, 0.0035400390625000, 0.0013732910156250, +0.0033569335937500, 0.0012817382812500, 0.0038146972656250, 0.0014038085937500, +0.0048217773437500, 0.0012207031250000, 0.0043640136718750, 0.0011901855468750, +0.0054931640625000, 0.0011596679687500, 0.0056457519531250, 0.0009765625000000, +0.0056152343750000, 0.0009155273437500, 0.0061950683593750, 0.0009765625000000, +0.0062561035156250, 0.0005493164062500, 0.0060424804687500, 0.0006713867187500, +0.0062866210937500, 0.0004882812500000, 0.0061340332031250, 0.0001525878906250, +0.0058898925781250, 0.0003967285156250, 0.0061645507812500, -0.0000305175781250, +0.0054626464843750, 0.0000000000000000, 0.0055236816406250, -0.0000915527343750, +0.0055541992187500, -0.0003356933593750, 0.0051269531250000, -0.0000915527343750, +0.0051574707031250, -0.0003662109375000, 0.0054931640625000, -0.0001525878906250, +0.0052185058593750, -0.0002136230468750, 0.0056457519531250, -0.0003662109375000, +0.0061645507812500, 0.0000610351562500, 0.0057983398437500, -0.0005493164062500, +0.0069274902343750, -0.0001525878906250, 0.0068969726562500, -0.0002746582031250, +0.0069885253906250, -0.0008544921875000, 0.0075988769531250, -0.0003967285156250, +0.0073852539062500, -0.0007934570312500, 0.0073852539062500, -0.0008544921875000, +0.0076293945312500, -0.0006713867187500, 0.0073242187500000, -0.0006408691406250, +0.0070800781250000, -0.0006408691406250, 0.0074768066406250, -0.0004882812500000, +0.0069885253906250, -0.0003662109375000, 0.0070495605468750, -0.0002136230468750, +0.0071716308593750, -0.0001525878906250, 0.0069885253906250, -0.0002136230468750, +0.0071716308593750, 0.0002136230468750, 0.0072021484375000, 0.0000000000000000, +0.0073852539062500, 0.0001220703125000, 0.0074768066406250, 0.0004272460937500, +0.0076293945312500, 0.0000610351562500, 0.0079345703125000, 0.0004577636718750, +0.0076599121093750, 0.0004272460937500, 0.0080871582031250, 0.0003356933593750, +0.0078430175781250, 0.0004882812500000, 0.0075378417968750, 0.0004577636718750, +0.0081176757812500, 0.0004882812500000, 0.0068664550781250, 0.0005493164062500, +0.0073547363281250, 0.0005798339843750, 0.0068054199218750, 0.0006408691406250, +0.0056762695312500, 0.0006713867187500, 0.0065612792968750, 0.0006408691406250, +0.0049133300781250, 0.0007019042968750, 0.0050048828125000, 0.0007019042968750, +0.0048217773437500, 0.0005493164062500, 0.0036926269531250, 0.0006408691406250, +0.0042114257812500, 0.0005493164062500, 0.0035705566406250, 0.0003967285156250, +0.0034484863281250, 0.0003662109375000, 0.0038757324218750, 0.0004577636718750, +0.0039367675781250, 0.0005493164062500, 0.0037536621093750, 0.0007019042968750, +0.0044555664062500, 0.0008239746093750, 0.0042419433593750, 0.0009460449218750, +0.0042114257812500, 0.0010375976562500, 0.0045776367187500, 0.0011596679687500, +0.0043029785156250, 0.0015563964843750, 0.0047302246093750, 0.0014648437500000, +0.0045166015625000, 0.0018310546875000, 0.0046386718750000, 0.0023193359375000, +0.0049743652343750, 0.0021362304687500, 0.0046691894531250, 0.0030212402343750, +0.0050048828125000, 0.0031127929687500, 0.0050964355468750, 0.0029907226562500, +0.0047302246093750, 0.0033874511718750, 0.0046386718750000, 0.0034484863281250, +0.0048828125000000, 0.0025939941406250, 0.0041503906250000, 0.0028686523437500, +0.0041809082031250, 0.0025634765625000, 0.0044250488281250, 0.0012817382812500, +0.0042419433593750, 0.0011291503906250, 0.0042724609375000, 0.0034179687500000, +0.0032653808593750, 0.0023498535156250, 0.0031127929687500, 0.0032043457031250, +0.0035400390625000, 0.0046691894531250, 0.0036315917968750, 0.0038146972656250, +0.0034484863281250, 0.0051269531250000, 0.0042419433593750, 0.0051879882812500, +0.0043945312500000, 0.0051269531250000, 0.0041809082031250, 0.0057678222656250, +0.0044555664062500, 0.0056152343750000, 0.0046081542968750, 0.0055541992187500, +0.0035095214843750, 0.0058898925781250, 0.0040283203125000, 0.0056152343750000, +0.0033569335937500, 0.0052185058593750, 0.0022277832031250, 0.0055541992187500, +0.0031738281250000}, +{0.0098876953125000, 0.0000915527343750, 0.0098876953125000, -0.0003967285156250, +0.0086975097656250, -0.0001831054687500, 0.0088500976562500, -0.0002746582031250, +0.0081481933593750, -0.0006408691406250, 0.0069885253906250, -0.0002441406250000, +0.0074768066406250, -0.0006713867187500, 0.0059814453125000, -0.0006713867187500, +0.0058898925781250, -0.0005798339843750, 0.0058288574218750, -0.0007934570312500, +0.0050659179687500, -0.0007324218750000, 0.0053100585937500, -0.0006713867187500, +0.0051574707031250, -0.0007019042968750, 0.0050659179687500, -0.0005493164062500, +0.0054016113281250, -0.0003662109375000, 0.0055847167968750, -0.0004882812500000, +0.0055236816406250, 0.0000000000000000, 0.0056457519531250, -0.0002441406250000, +0.0059204101562500, 0.0000000000000000, 0.0057678222656250, 0.0004272460937500, +0.0057373046875000, -0.0000610351562500, 0.0060729980468750, 0.0005493164062500, +0.0056457519531250, 0.0003967285156250, 0.0057067871093750, 0.0003356933593750, +0.0057067871093750, 0.0006713867187500, 0.0054321289062500, 0.0004272460937500, +0.0056457519531250, 0.0007934570312500, 0.0056762695312500, 0.0007934570312500, +0.0055541992187500, 0.0008544921875000, 0.0059509277343750, 0.0011291503906250, +0.0062255859375000, 0.0009765625000000, 0.0060424804687500, 0.0012207031250000, +0.0069580078125000, 0.0011901855468750, 0.0069274902343750, 0.0011596679687500, +0.0071105957031250, 0.0011291503906250, 0.0077819824218750, 0.0010986328125000, +0.0074462890625000, 0.0010986328125000, 0.0076293945312500, 0.0010681152343750, +0.0078430175781250, 0.0010681152343750, 0.0075073242187500, 0.0009765625000000, +0.0073547363281250, 0.0008544921875000, 0.0075378417968750, 0.0011596679687500, +0.0065612792968750, 0.0009460449218750, 0.0066528320312500, 0.0009765625000000, +0.0063781738281250, 0.0012207031250000, 0.0055236816406250, 0.0010681152343750, +0.0057373046875000, 0.0016784667968750, 0.0054321289062500, 0.0014953613281250, +0.0052185058593750, 0.0018310546875000, 0.0053405761718750, 0.0024108886718750, +0.0054626464843750, 0.0019531250000000, 0.0053710937500000, 0.0025634765625000, +0.0053405761718750, 0.0026550292968750, 0.0056457519531250, 0.0023498535156250, +0.0052795410156250, 0.0025024414062500, 0.0048828125000000, 0.0025329589843750, +0.0053405761718750, 0.0016479492187500, 0.0045166015625000, 0.0018310546875000, +0.0044860839843750, 0.0015258789062500, 0.0047912597656250, 0.0007629394531250, +0.0046081542968750, 0.0009765625000000, 0.0046691894531250, 0.0009460449218750, +0.0045471191406250, 0.0005798339843750, 0.0048217773437500, 0.0010070800781250, +0.0044250488281250, 0.0019531250000000, 0.0034790039062500, 0.0031738281250000, +0.0048217773437500, 0.0046691894531250, 0.0039672851562500, 0.0043640136718750, +0.0046997070312500, 0.0043029785156250, 0.0037536621093750, 0.0047302246093750, +0.0025024414062500, 0.0046691894531250, 0.0031433105468750, 0.0042419433593750, +0.0019226074218750, 0.0044555664062500, 0.0016174316406250, 0.0044860839843750, +0.0019836425781250, 0.0040893554687500, 0.0017089843750000, 0.0042419433593750, +0.0015258789062500, 0.0047302246093750, 0.0025939941406250, 0.0042724609375000, +0.0023803710937500, 0.0050659179687500, 0.0025634765625000, 0.0060729980468750, +0.0034484863281250, 0.0051879882812500, 0.0032043457031250, 0.0067138671875000, +0.0033874511718750, 0.0069274902343750, 0.0038452148437500, 0.0064392089843750, +0.0032653808593750, 0.0068664550781250, 0.0029602050781250, 0.0069274902343750, +0.0037231445312500, 0.0057678222656250, 0.0016784667968750, 0.0058288574218750, +0.0023803710937500, 0.0055236816406250, 0.0016174316406250, 0.0046386718750000, +-0.0003356933593750, 0.0047302246093750, 0.0008544921875000, 0.0044860839843750, +-0.0006713867187500, 0.0041809082031250, -0.0012207031250000, 0.0042419433593750, +-0.0003356933593750, 0.0042724609375000, -0.0002746582031250, 0.0041198730468750, +-0.0007324218750000, 0.0040893554687500, 0.0011596679687500, 0.0040893554687500, +0.0008544921875000, 0.0038757324218750, 0.0011596679687500, 0.0036315917968750, +0.0025634765625000, 0.0036621093750000, 0.0019531250000000, 0.0034179687500000, +0.0026855468750000, 0.0031433105468750, 0.0028381347656250, 0.0033569335937500, +0.0025329589843750, 0.0035400390625000, 0.0027465820312500, 0.0032348632812500, +0.0026855468750000, 0.0043029785156250, 0.0018920898437500, 0.0040283203125000, +0.0021972656250000, 0.0046081542968750, 0.0016479492187500, 0.0056457519531250, +0.0008239746093750, 0.0050659179687500, 0.0014343261718750, 0.0064086914062500, +0.0003356933593750, 0.0065002441406250, 0.0003356933593750, 0.0065002441406250, +0.0004882812500000, 0.0072937011718750, 0.0000610351562500, 0.0071411132812500, +0.0002441406250000, 0.0073547363281250, 0.0003662109375000, 0.0075683593750000, +0.0002441406250000, 0.0076293945312500, 0.0003662109375000, 0.0077819824218750, +0.0005187988281250, 0.0079345703125000, 0.0003356933593750, 0.0083007812500000, +0.0004882812500000, 0.0083312988281250, 0.0005187988281250, 0.0087280273437500, +0.0003051757812500, 0.0091247558593750, 0.0003356933593750, 0.0089416503906250, +0.0003662109375000, 0.0097656250000000, -0.0000610351562500, 0.0096435546875000, +0.0000915527343750, 0.0099182128906250, -0.0000610351562500, 0.0105285644531250, +-0.0004577636718750, 0.0101623535156250, -0.0002441406250000, 0.0107421875000000, +-0.0004577636718750, 0.0108032226562500, -0.0005187988281250, 0.0104980468750000, +-0.0003051757812500, 0.0106811523437500, -0.0001831054687500, 0.0107421875000000, +-0.0000915527343750, 0.0098876953125000, 0.0002441406250000, 0.0101318359375000, +0.0003356933593750, 0.0095214843750000, 0.0005798339843750, 0.0085754394531250, +0.0009460449218750, 0.0091552734375000, 0.0009765625000000, 0.0077819824218750, +0.0012207031250000, 0.0077209472656250, 0.0013732910156250, 0.0075988769531250, +0.0014038085937500, 0.0067749023437500, 0.0014953613281250, 0.0070190429687500, +0.0015563964843750, 0.0066833496093750, 0.0013732910156250, 0.0064697265625000, +0.0014038085937500, 0.0066833496093750, 0.0012512207031250, 0.0067138671875000, +0.0010375976562500, 0.0065002441406250, 0.0010681152343750, 0.0070495605468750, +0.0006103515625000, 0.0068359375000000, 0.0007019042968750, 0.0068969726562500, +0.0005187988281250, 0.0074157714843750, 0.0001525878906250, 0.0071411132812500, +0.0004272460937500, 0.0073242187500000, 0.0000000000000000, 0.0074462890625000, +0.0000000000000000, 0.0072631835937500, 0.0000305175781250, 0.0072937011718750, +-0.0001525878906250, 0.0072937011718750, -0.0001525878906250, 0.0066528320312500, +-0.0003356933593750, 0.0068969726562500, -0.0002746582031250, 0.0063781738281250, +-0.0003662109375000, 0.0056152343750000, -0.0006103515625000, 0.0060424804687500, +-0.0004882812500000, 0.0045471191406250, -0.0007629394531250, 0.0047302246093750, +-0.0007019042968750, 0.0041503906250000, -0.0007019042968750, 0.0029296875000000, +-0.0008239746093750, 0.0035400390625000, -0.0006408691406250, 0.0021362304687500, +-0.0007629394531250, 0.0021667480468750, -0.0007629394531250, 0.0021667480468750, +-0.0007019042968750, 0.0014343261718750, -0.0007324218750000, 0.0018310546875000, +-0.0006408691406250, 0.0017395019531250, -0.0006103515625000, 0.0016479492187500, +-0.0005493164062500, 0.0020751953125000, -0.0004577636718750, 0.0023193359375000, +-0.0003356933593750, 0.0022888183593750, -0.0002441406250000, 0.0033264160156250, +-0.0001220703125000, 0.0032348632812500, -0.0000610351562500, 0.0037536621093750, +-0.0000305175781250, 0.0046386718750000, 0.0000305175781250, 0.0043029785156250, +0.0000610351562500, 0.0053100585937500, 0.0000610351562500, 0.0053100585937500, +0.0000000000000000, 0.0053405761718750, 0.0001220703125000, 0.0058593750000000, +0.0001525878906250, 0.0056762695312500, 0.0000610351562500, 0.0055236816406250, +0.0003662109375000, 0.0055847167968750, 0.0002746582031250, 0.0052795410156250, +0.0003967285156250, 0.0049438476562500, 0.0006408691406250, 0.0051574707031250, +0.0004882812500000, 0.0044250488281250, 0.0007324218750000, 0.0044555664062500, +0.0007629394531250, 0.0042724609375000, 0.0007019042968750, 0.0037536621093750, +0.0007934570312500, 0.0040588378906250, 0.0008544921875000, 0.0036926269531250, +0.0006713867187500, 0.0037231445312500, 0.0008544921875000, 0.0038757324218750, +0.0007019042968750, 0.0037841796875000, 0.0005187988281250, 0.0038452148437500, +0.0007324218750000, 0.0040588378906250, 0.0002746582031250, 0.0039978027343750, +0.0002746582031250, 0.0041809082031250, 0.0002746582031250, 0.0044250488281250, +0.0000000000000000, 0.0042724609375000, 0.0000000000000000, 0.0047912597656250, +0.0002441406250000, 0.0046691894531250, 0.0000000000000000, 0.0048828125000000, +0.0001831054687500, 0.0052795410156250, 0.0005187988281250, 0.0051269531250000, +0.0002136230468750, 0.0056762695312500, 0.0007324218750000, 0.0056762695312500, +0.0006713867187500, 0.0057983398437500, 0.0006408691406250, 0.0062561035156250, +0.0009460449218750, 0.0061035156250000, 0.0007324218750000, 0.0059814453125000, +0.0009460449218750, 0.0061950683593750, 0.0009155273437500, 0.0057678222656250, +0.0008544921875000, 0.0053100585937500, 0.0009460449218750, 0.0055847167968750, +0.0007934570312500, 0.0047302246093750, 0.0007324218750000, 0.0046691894531250, +0.0007019042968750, 0.0048217773437500, 0.0007629394531250, 0.0043945312500000, +0.0008239746093750, 0.0043945312500000, 0.0007629394531250, 0.0047912597656250, +0.0010070800781250, 0.0045776367187500, 0.0010070800781250, 0.0045776367187500, +0.0010681152343750, 0.0050354003906250, 0.0012512207031250, 0.0048217773437500, +0.0013122558593750, 0.0043029785156250, 0.0012512207031250, 0.0047302246093750, +0.0013122558593750, 0.0039978027343750, 0.0014343261718750, 0.0031127929687500, +0.0012817382812500, 0.0038452148437500, 0.0011901855468750, 0.0023498535156250, +0.0018005371093750, 0.0024719238281250, 0.0013122558593750, 0.0023803710937500, +0.0017395019531250, 0.0012817382812500, 0.0026245117187500, 0.0013122558593750, +0.0021972656250000, 0.0008544921875000, 0.0034484863281250, 0.0008544921875000, +0.0029907226562500, 0.0010375976562500, 0.0030822753906250, 0.0007934570312500, +0.0039978027343750, 0.0006713867187500, 0.0034179687500000, 0.0018920898437500, +0.0039978027343750, 0.0011901855468750, 0.0039367675781250, 0.0018615722656250, +0.0037841796875000, 0.0032348632812500, 0.0039672851562500, 0.0022277832031250, +0.0036315917968750, 0.0037536621093750, 0.0033264160156250, 0.0039367675781250, +0.0030517578125000, 0.0035400390625000, 0.0028991699218750, 0.0039978027343750, +0.0026245117187500, 0.0039978027343750, 0.0022583007812500, 0.0030517578125000, +0.0024108886718750, 0.0035095214843750, 0.0021362304687500, 0.0027160644531250, +0.0021667480468750, 0.0015869140625000, 0.0022277832031250, 0.0025329589843750, +0.0018310546875000, 0.0006713867187500, 0.0026550292968750, 0.0007324218750000, +0.0022583007812500, 0.0008850097656250, 0.0028381347656250, -0.0000915527343750, +0.0036926269531250, 0.0002746582031250, 0.0028991699218750, 0.0004882812500000, +0.0048522949218750, 0.0002441406250000, 0.0045166015625000, 0.0004882812500000, +0.0048828125000000, 0.0009460449218750, 0.0063171386718750, 0.0006103515625000, +0.0054931640625000, 0.0010986328125000, 0.0064697265625000, 0.0010681152343750, +0.0065917968750000}, +{0.0007324218750000, 0.0097351074218750, 0.0008544921875000, 0.0094604492187500, +0.0008239746093750, 0.0093383789062500, 0.0007934570312500, 0.0094909667968750, +0.0009460449218750, 0.0087585449218750, 0.0006103515625000, 0.0088500976562500, +0.0007019042968750, 0.0086975097656250, 0.0006103515625000, 0.0081481933593750, +0.0002746582031250, 0.0083007812500000, 0.0003967285156250, 0.0079956054687500, +0.0003051757812500, 0.0078430175781250, 0.0000610351562500, 0.0078735351562500, +0.0002746582031250, 0.0078430175781250, 0.0003662109375000, 0.0076904296875000, +0.0001220703125000, 0.0077209472656250, 0.0006103515625000, 0.0076904296875000, +0.0005187988281250, 0.0076293945312500, 0.0004882812500000, 0.0075988769531250, +0.0007934570312500, 0.0076293945312500, 0.0005798339843750, 0.0073242187500000, +0.0007629394531250, 0.0073852539062500, 0.0007324218750000, 0.0072631835937500, +0.0006408691406250, 0.0070190429687500, 0.0007629394531250, 0.0070190429687500, +0.0007629394531250, 0.0065612792968750, 0.0005493164062500, 0.0065612792968750, +0.0006103515625000, 0.0062866210937500, 0.0006408691406250, 0.0059204101562500, +0.0004882812500000, 0.0060729980468750, 0.0005798339843750, 0.0051269531250000, +0.0006103515625000, 0.0052185058593750, 0.0006408691406250, 0.0047912597656250, +0.0006713867187500, 0.0039062500000000, 0.0007324218750000, 0.0040893554687500, +0.0009155273437500, 0.0032653808593750, 0.0007019042968750, 0.0030822753906250, +0.0008544921875000, 0.0032348632812500, 0.0008850097656250, 0.0029907226562500, +0.0006713867187500, 0.0029296875000000, 0.0009155273437500, 0.0037231445312500, +0.0010681152343750, 0.0036315917968750, 0.0009155273437500, 0.0038452148437500, +0.0012817382812500, 0.0045471191406250, 0.0016479492187500, 0.0044250488281250, +0.0013732910156250, 0.0045166015625000, 0.0021667480468750, 0.0046997070312500, +0.0020751953125000, 0.0044555664062500, 0.0022583007812500, 0.0042114257812500, +0.0028076171875000, 0.0042419433593750, 0.0025634765625000, 0.0033264160156250, +0.0028686523437500, 0.0037536621093750, 0.0028381347656250, 0.0033874511718750, +0.0026855468750000, 0.0027160644531250, 0.0027160644531250, 0.0034179687500000, +0.0026550292968750, 0.0018005371093750, 0.0024719238281250, 0.0019531250000000, +0.0024108886718750, 0.0019531250000000, 0.0022888183593750, 0.0008544921875000, +0.0020141601562500, 0.0011901855468750, 0.0019531250000000, 0.0014648437500000, +0.0021057128906250, 0.0009765625000000, 0.0017700195312500, 0.0013732910156250, +0.0021057128906250, 0.0019836425781250, 0.0025634765625000, 0.0015563964843750, +0.0022583007812500, 0.0023803710937500, 0.0032653808593750, 0.0023803710937500, +0.0028991699218750, 0.0024108886718750, 0.0034484863281250, 0.0028381347656250, +0.0045166015625000, 0.0026245117187500, 0.0039062500000000, 0.0024719238281250, +0.0057067871093750, 0.0028076171875000, 0.0055847167968750, 0.0020751953125000, +0.0058898925781250, 0.0014038085937500, 0.0071716308593750, 0.0020446777343750, +0.0066223144531250, 0.0003051757812500, 0.0072326660156250, 0.0006103515625000, +0.0074157714843750, 0.0004882812500000, 0.0073242187500000, -0.0005493164062500, +0.0074768066406250, 0.0000610351562500, 0.0074157714843750, -0.0002441406250000, +0.0078125000000000, -0.0004272460937500, 0.0076293945312500, 0.0000610351562500, +0.0080261230468750, 0.0002441406250000, 0.0086059570312500, 0.0000000000000000, +0.0081176757812500, 0.0008544921875000, 0.0088500976562500, 0.0007324218750000, +0.0089111328125000, 0.0007934570312500, 0.0087280273437500, 0.0013122558593750, +0.0090637207031250, 0.0010986328125000, 0.0089416503906250, 0.0013122558593750, +0.0086669921875000, 0.0013732910156250, 0.0087585449218750, 0.0013427734375000, +0.0086364746093750, 0.0013732910156250, 0.0083618164062500, 0.0013427734375000, +0.0083923339843750, 0.0016174316406250, 0.0082092285156250, 0.0014648437500000, +0.0081176757812500, 0.0017089843750000, 0.0079345703125000, 0.0020446777343750, +0.0078125000000000, 0.0018005371093750, 0.0077819824218750, 0.0022888183593750, +0.0073547363281250, 0.0024108886718750, 0.0072631835937500, 0.0022583007812500, +0.0070800781250000, 0.0025634765625000, 0.0067749023437500, 0.0027160644531250, +0.0067443847656250, 0.0020751953125000, 0.0065917968750000, 0.0025329589843750, +0.0065002441406250, 0.0021362304687500, 0.0064086914062500, 0.0014038085937500, +0.0061950683593750, 0.0021362304687500, 0.0061035156250000, 0.0008850097656250, +0.0059204101562500, 0.0011901855468750, 0.0057983398437500, 0.0010375976562500, +0.0056152343750000, 0.0003051757812500, 0.0054016113281250, 0.0010986328125000, +0.0054016113281250, 0.0002136230468750, 0.0054321289062500, 0.0005493164062500, +0.0052490234375000, 0.0006408691406250, 0.0054321289062500, 0.0001525878906250, +0.0056762695312500, 0.0008239746093750, 0.0054016113281250, 0.0003356933593750, +0.0062866210937500, 0.0006103515625000, 0.0060424804687500, 0.0005798339843750, +0.0064086914062500, 0.0002136230468750, 0.0070800781250000, 0.0007019042968750, +0.0066833496093750, 0.0000915527343750, 0.0077209472656250, 0.0002441406250000, +0.0076599121093750, 0.0003051757812500, 0.0078430175781250, -0.0001525878906250, +0.0085754394531250, 0.0000000000000000, 0.0082702636718750, -0.0001831054687500, +0.0087280273437500, -0.0004272460937500, 0.0088195800781250, -0.0003051757812500, +0.0087280273437500, -0.0003051757812500, 0.0088806152343750, -0.0006408691406250, +0.0088806152343750, -0.0001831054687500, 0.0084228515625000, -0.0005798339843750, +0.0085449218750000, -0.0004272460937500, 0.0081787109375000, -0.0000305175781250, +0.0076904296875000, -0.0005798339843750, 0.0079345703125000, 0.0000915527343750, +0.0070190429687500, -0.0001220703125000, 0.0071411132812500, -0.0001220703125000, +0.0067443847656250, 0.0003051757812500, 0.0059204101562500, -0.0001525878906250, +0.0063171386718750, 0.0002441406250000, 0.0052795410156250, 0.0001525878906250, +0.0052490234375000, 0.0000305175781250, 0.0050048828125000, 0.0002136230468750, +0.0043640136718750, 0.0001220703125000, 0.0046081542968750, 0.0001831054687500, +0.0042419433593750, 0.0002136230468750, 0.0040283203125000, 0.0001831054687500, +0.0041198730468750, 0.0002746582031250, 0.0039978027343750, 0.0003051757812500, +0.0038452148437500, 0.0003356933593750, 0.0042114257812500, 0.0004882812500000, +0.0038757324218750, 0.0004577636718750, 0.0040588378906250, 0.0004882812500000, +0.0044860839843750, 0.0006713867187500, 0.0039367675781250, 0.0002746582031250, +0.0046691894531250, 0.0005187988281250, 0.0044250488281250, 0.0004272460937500, +0.0045471191406250, 0.0000000000000000, 0.0050354003906250, 0.0003662109375000, +0.0045166015625000, -0.0001831054687500, 0.0052795410156250, -0.0001831054687500, +0.0049438476562500, -0.0001831054687500, 0.0053405761718750, -0.0003967285156250, +0.0059814453125000, -0.0003051757812500, 0.0053405761718750, -0.0002441406250000, +0.0069580078125000, -0.0004272460937500, 0.0065917968750000, -0.0002136230468750, +0.0071411132812500, -0.0000305175781250, 0.0084838867187500, -0.0003051757812500, +0.0076599121093750, 0.0002441406250000, 0.0090942382812500, 0.0000000000000000, +0.0091552734375000, 0.0001220703125000, 0.0090332031250000, 0.0004577636718750, +0.0097045898437500, -0.0000305175781250, 0.0096740722656250, 0.0005493164062500, +0.0093078613281250, 0.0001831054687500, 0.0097045898437500, 0.0002746582031250, +0.0093383789062500, 0.0008544921875000, 0.0087890625000000, 0.0003051757812500, +0.0092163085937500, 0.0010986328125000, 0.0084228515625000, 0.0010070800781250, +0.0084838867187500, 0.0009765625000000, 0.0084533691406250, 0.0014343261718750, +0.0081176757812500, 0.0011901855468750, 0.0084228515625000, 0.0014343261718750, +0.0082702636718750, 0.0014038085937500, 0.0083618164062500, 0.0014343261718750, +0.0084838867187500, 0.0015258789062500, 0.0085449218750000, 0.0013732910156250, +0.0087280273437500, 0.0017395019531250, 0.0084533691406250, 0.0016174316406250, +0.0087890625000000, 0.0018005371093750, 0.0082702636718750, 0.0020751953125000, +0.0077514648437500, 0.0018920898437500, 0.0082702636718750, 0.0025329589843750, +0.0066528320312500, 0.0024719238281250, 0.0069885253906250, 0.0025024414062500, +0.0063781738281250, 0.0029296875000000, 0.0050048828125000, 0.0028381347656250, +0.0057983398437500, 0.0026855468750000, 0.0042114257812500, 0.0029907226562500, +0.0042419433593750, 0.0026245117187500, 0.0042724609375000, 0.0021362304687500, +0.0036010742187500, 0.0024108886718750, 0.0039978027343750, 0.0012207031250000, +0.0039062500000000, 0.0010986328125000, 0.0039672851562500, 0.0010375976562500, +0.0039367675781250, 0.0003051757812500, 0.0039062500000000, 0.0003051757812500, +0.0043029785156250, 0.0010070800781250, 0.0031127929687500, 0.0003967285156250, +0.0035095214843750, 0.0011596679687500, 0.0031738281250000, 0.0022277832031250, +0.0020751953125000, 0.0012207031250000, 0.0026855468750000, 0.0031738281250000, +0.0025939941406250, 0.0029907226562500, 0.0023193359375000, 0.0029296875000000, +0.0026855468750000, 0.0040283203125000, 0.0032348632812500, 0.0035095214843750, +0.0031127929687500, 0.0036621093750000, 0.0031127929687500, 0.0038757324218750, +0.0033569335937500, 0.0036621093750000, 0.0034484863281250, 0.0033874511718750, +0.0032958984375000, 0.0034790039062500, 0.0023803710937500, 0.0049133300781250, +0.0021057128906250, 0.0040893554687500, 0.0020446777343750, 0.0047302246093750, +0.0023498535156250, 0.0059814453125000, 0.0023498535156250, 0.0054931640625000, +0.0021057128906250, 0.0058288574218750, 0.0034179687500000, 0.0065307617187500, +0.0029602050781250, 0.0058288574218750, 0.0034484863281250, 0.0051879882812500, +0.0047302246093750, 0.0059509277343750, 0.0039367675781250, 0.0042419433593750, +0.0045166015625000, 0.0044555664062500, 0.0048828125000000, 0.0045166015625000, +0.0041198730468750, 0.0035400390625000, 0.0037231445312500, 0.0040283203125000, +0.0040893554687500, 0.0042724609375000, 0.0025329589843750, 0.0040588378906250, +0.0026245117187500, 0.0043334960937500, 0.0023498535156250, 0.0047302246093750, +0.0014038085937500, 0.0043945312500000, 0.0018310546875000, 0.0044860839843750, +0.0014038085937500, 0.0044555664062500, 0.0011596679687500, 0.0045166015625000, +0.0016479492187500, 0.0043029785156250, 0.0017395019531250, 0.0041809082031250, +0.0015869140625000, 0.0052795410156250, 0.0029907226562500, 0.0046691894531250, +0.0028076171875000, 0.0055847167968750, 0.0030212402343750, 0.0069274902343750, +0.0040893554687500, 0.0059204101562500, 0.0036926269531250, 0.0085144042968750, +0.0034179687500000, 0.0082702636718750, 0.0040283203125000, 0.0085449218750000, +0.0030822753906250, 0.0101623535156250, 0.0020141601562500, 0.0094604492187500, +0.0028381347656250, 0.0101318359375000, 0.0007934570312500, 0.0104370117187500, +0.0008239746093750, 0.0102233886718750, 0.0007629394531250, 0.0102539062500000, +-0.0003967285156250, 0.0103149414062500, 0.0000305175781250, 0.0098876953125000, +-0.0001831054687500, 0.0100402832031250, -0.0005187988281250, 0.0097351074218750, +0.0000305175781250, 0.0092773437500000, 0.0003051757812500, 0.0096130371093750, +-0.0001220703125000, 0.0083312988281250, 0.0009765625000000, 0.0088195800781250, +0.0007934570312500, 0.0080871582031250, 0.0009765625000000, 0.0069580078125000, +0.0018005371093750}, +{0.0075378417968750, 0.0032043457031250, 0.0085144042968750, 0.0033874511718750, +0.0077514648437500, 0.0029602050781250, 0.0090942382812500, 0.0034484863281250, +0.0090942382812500, 0.0030212402343750, 0.0089416503906250, 0.0025024414062500, +0.0096740722656250, 0.0031433105468750, 0.0094299316406250, 0.0018615722656250, +0.0090637207031250, 0.0020141601562500, 0.0094299316406250, 0.0021362304687500, +0.0087585449218750, 0.0013427734375000, 0.0080261230468750, 0.0015258789062500, +0.0085144042968750, 0.0021362304687500, 0.0069274902343750, 0.0016174316406250, +0.0071716308593750, 0.0023498535156250, 0.0069580078125000, 0.0033264160156250, +0.0059814453125000, 0.0025939941406250, 0.0065307617187500, 0.0042114257812500, +0.0058593750000000, 0.0040893554687500, 0.0061950683593750, 0.0040588378906250, +0.0057678222656250, 0.0049133300781250, 0.0052490234375000, 0.0045166015625000, +0.0059204101562500, 0.0042114257812500, 0.0037841796875000, 0.0045776367187500, +0.0042724609375000, 0.0041809082031250, 0.0039062500000000, 0.0035705566406250, +0.0023193359375000, 0.0041503906250000, 0.0031433105468750, 0.0033874511718750, +0.0024719238281250, 0.0033264160156250, 0.0022277832031250, 0.0036315917968750, +0.0023803710937500, 0.0036315917968750, 0.0021972656250000, 0.0059814453125000, +0.0041809082031250, 0.0057067871093750, 0.0035400390625000, 0.0063476562500000, +0.0036926269531250, 0.0055541992187500, 0.0034179687500000, 0.0047302246093750, +0.0030822753906250, 0.0055236816406250, 0.0031433105468750, 0.0040588378906250, +0.0026550292968750, 0.0039062500000000, 0.0024719238281250, 0.0043029785156250, +0.0026550292968750, 0.0037536621093750, 0.0022888183593750, 0.0037536621093750, +0.0020446777343750, 0.0045776367187500, 0.0031738281250000, 0.0044860839843750, +0.0025024414062500, 0.0046691894531250, 0.0030517578125000, 0.0053710937500000, +0.0044250488281250, 0.0052795410156250, 0.0034790039062500, 0.0053100585937500, +0.0046081542968750, 0.0054016113281250, 0.0048828125000000, 0.0056152343750000, +0.0043945312500000, 0.0055847167968750, 0.0046691894531250, 0.0054321289062500, +0.0050354003906250, 0.0069274902343750, 0.0038757324218750, 0.0063476562500000, +0.0043640136718750, 0.0072021484375000, 0.0038146972656250, 0.0089111328125000, +0.0028076171875000, 0.0080566406250000, 0.0038452148437500, 0.0097656250000000, +0.0020446777343750, 0.0099487304687500, 0.0021057128906250, 0.0095520019531250, +0.0022583007812500, 0.0102539062500000, 0.0014038085937500, 0.0102844238281250, +0.0018005371093750, 0.0090637207031250, 0.0022888183593750, 0.0097351074218750, +0.0019226074218750, 0.0089111328125000, 0.0025329589843750, 0.0076293945312500, +0.0034484863281250, 0.0086059570312500, 0.0030822753906250, 0.0064697265625000, +0.0034484863281250, 0.0069274902343750, 0.0039367675781250, 0.0062561035156250, +0.0033264160156250, 0.0046691894531250, 0.0029602050781250, 0.0058898925781250, +0.0033874511718750, 0.0032043457031250, 0.0018310546875000, 0.0036621093750000, +0.0019531250000000, 0.0028686523437500, 0.0014953613281250, 0.0008239746093750, +0.0003051757812500, 0.0021667480468750, 0.0008544921875000, -0.0005493164062500, +0.0000000000000000, -0.0004272460937500, -0.0002746582031250, -0.0006103515625000, +0.0000610351562500, -0.0023193359375000, -0.0000610351562500, -0.0015869140625000, +-0.0002136230468750, -0.0022277832031250, 0.0008850097656250, -0.0026550292968750, +0.0006103515625000, -0.0021972656250000, 0.0008850097656250, -0.0021972656250000, +0.0018920898437500, -0.0025024414062500, 0.0014343261718750, -0.0014343261718750, +0.0019226074218750, -0.0018615722656250, 0.0021972656250000, -0.0015258789062500, +0.0018920898437500, -0.0005187988281250, 0.0018005371093750, -0.0012817382812500, +0.0020751953125000, -0.0002746582031250, 0.0013427734375000, -0.0001831054687500, +0.0015869140625000, -0.0003967285156250, 0.0014343261718750, -0.0000305175781250, +0.0009765625000000, -0.0000610351562500, 0.0013732910156250, -0.0003051757812500, +0.0010681152343750, -0.0001525878906250, 0.0010375976562500, -0.0003967285156250, +0.0012207031250000, -0.0007019042968750, 0.0012207031250000, -0.0004272460937500, +0.0013427734375000, -0.0010681152343750, 0.0015258789062500, -0.0009460449218750, +0.0016174316406250, -0.0011901855468750, 0.0015258789062500, -0.0017700195312500, +0.0015869140625000, -0.0014038085937500, 0.0017089843750000, -0.0021362304687500, +0.0013122558593750, -0.0022583007812500, 0.0015258789062500, -0.0021362304687500, +0.0012817382812500, -0.0025024414062500, 0.0009155273437500, -0.0024719238281250, +0.0013122558593750, -0.0018005371093750, 0.0007324218750000, -0.0024108886718750, +0.0008544921875000, -0.0017395019531250, 0.0009155273437500, -0.0007324218750000, +0.0005798339843750, -0.0016174316406250, 0.0007629394531250, 0.0005798339843750, +0.0007019042968750, 0.0001220703125000, 0.0006408691406250, 0.0007934570312500, +0.0007629394531250, 0.0024719238281250, 0.0008239746093750, 0.0014343261718750, +0.0006713867187500, 0.0036010742187500, 0.0007934570312500, 0.0033874511718750, +0.0006713867187500, 0.0038757324218750, 0.0006103515625000, 0.0053710937500000, +0.0006103515625000, 0.0046081542968750, 0.0003356933593750, 0.0060729980468750, +0.0002441406250000, 0.0061035156250000, 0.0002136230468750, 0.0062255859375000, +0.0000305175781250, 0.0071411132812500, -0.0001220703125000, 0.0068359375000000, +-0.0001831054687500, 0.0072021484375000, -0.0003662109375000, 0.0073547363281250, +-0.0004577636718750, 0.0072021484375000, -0.0005187988281250, 0.0072631835937500, +-0.0005187988281250, 0.0073547363281250, -0.0004272460937500, 0.0067749023437500, +-0.0005187988281250, 0.0068969726562500, -0.0004272460937500, 0.0066833496093750, +-0.0004272460937500, 0.0062561035156250, -0.0004882812500000, 0.0065612792968750, +-0.0002746582031250, 0.0058593750000000, -0.0003662109375000, 0.0059814453125000, +-0.0002441406250000, 0.0058593750000000, -0.0001525878906250, 0.0054626464843750, +-0.0001831054687500, 0.0058288574218750, 0.0000000000000000, 0.0052490234375000, +0.0000000000000000, 0.0053710937500000, 0.0001220703125000, 0.0052795410156250, +0.0002441406250000, 0.0048828125000000, 0.0003356933593750, 0.0052185058593750, +0.0003967285156250, 0.0045776367187500, 0.0005493164062500, 0.0047607421875000, +0.0005798339843750, 0.0045471191406250, 0.0006103515625000, 0.0041198730468750, +0.0007019042968750, 0.0044860839843750, 0.0007934570312500, 0.0037231445312500, +0.0006408691406250, 0.0037841796875000, 0.0008239746093750, 0.0036926269531250, +0.0007324218750000, 0.0032348632812500, 0.0005493164062500, 0.0032958984375000, +0.0007629394531250, 0.0031433105468750, 0.0005493164062500, 0.0030212402343750, +0.0004577636718750, 0.0031127929687500, 0.0006103515625000, 0.0030517578125000, +0.0005798339843750, 0.0030212402343750, 0.0006103515625000, 0.0034790039062500, +0.0008239746093750, 0.0033874511718750, 0.0008544921875000, 0.0035705566406250, +0.0009765625000000, 0.0039978027343750, 0.0012512207031250, 0.0038452148437500, +0.0012207031250000, 0.0039978027343750, 0.0013732910156250, 0.0042724609375000, +0.0016174316406250, 0.0041198730468750, 0.0015258789062500, 0.0040283203125000, +0.0015258789062500, 0.0042419433593750, 0.0017395019531250, 0.0037841796875000, +0.0013732910156250, 0.0038452148437500, 0.0015258789062500, 0.0037231445312500, +0.0014953613281250, 0.0033569335937500, 0.0012817382812500, 0.0035705566406250, +0.0014648437500000, 0.0033264160156250, 0.0014038085937500, 0.0033264160156250, +0.0013427734375000, 0.0035095214843750, 0.0014648437500000, 0.0035095214843750, +0.0015258789062500, 0.0035400390625000, 0.0014953613281250, 0.0043945312500000, +0.0014038085937500, 0.0042419433593750, 0.0016479492187500, 0.0047912597656250, +0.0014953613281250, 0.0056762695312500, 0.0012207031250000, 0.0052795410156250, +0.0015563964843750, 0.0063476562500000, 0.0014038085937500, 0.0064086914062500, +0.0012512207031250, 0.0065002441406250, 0.0016174316406250, 0.0070800781250000, +0.0018310546875000, 0.0068664550781250, 0.0017089843750000, 0.0068054199218750, +0.0024719238281250, 0.0070495605468750, 0.0023803710937500, 0.0067138671875000, +0.0025939941406250, 0.0064086914062500, 0.0031433105468750, 0.0067138671875000, +0.0027770996093750, 0.0057067871093750, 0.0031127929687500, 0.0059204101562500, +0.0031127929687500, 0.0054016113281250, 0.0029602050781250, 0.0045471191406250, +0.0030517578125000, 0.0050964355468750, 0.0030517578125000, 0.0039367675781250, +0.0028381347656250, 0.0039978027343750, 0.0028381347656250, 0.0038757324218750, +0.0028686523437500, 0.0032348632812500, 0.0025939941406250, 0.0035095214843750, +0.0023803710937500, 0.0034484863281250, 0.0030212402343750, 0.0035095214843750, +0.0025329589843750, 0.0032958984375000, 0.0028076171875000, 0.0030822753906250, +0.0033874511718750, 0.0033569335937500, 0.0027160644531250, 0.0028686523437500, +0.0039672851562500, 0.0028381347656250, 0.0036010742187500, 0.0029602050781250, +0.0040283203125000, 0.0027770996093750, 0.0049743652343750, 0.0029907226562500, +0.0043029785156250, 0.0030822753906250, 0.0057373046875000, 0.0030212402343750, +0.0056762695312500, 0.0030517578125000, 0.0058593750000000, 0.0030822753906250, +0.0067443847656250, 0.0029602050781250, 0.0062866210937500, 0.0028076171875000, +0.0067443847656250, 0.0028686523437500, 0.0069580078125000, 0.0025329589843750, +0.0067443847656250, 0.0022277832031250, 0.0066223144531250, 0.0024719238281250, +0.0066528320312500, 0.0017395019531250, 0.0063476562500000, 0.0017700195312500, +0.0063476562500000, 0.0018310546875000, 0.0061035156250000, 0.0014648437500000, +0.0058288574218750, 0.0016479492187500, 0.0059814453125000, 0.0018920898437500, +0.0051574707031250, 0.0015869140625000, 0.0054931640625000, 0.0018615722656250, +0.0049438476562500, 0.0023803710937500, 0.0041198730468750, 0.0020446777343750, +0.0047912597656250, 0.0022888183593750, 0.0030212402343750, 0.0026245117187500, +0.0033264160156250, 0.0021362304687500, 0.0029907226562500, 0.0019226074218750, +0.0018310546875000, 0.0024719238281250, 0.0024719238281250, 0.0010375976562500, +0.0012207031250000, 0.0013427734375000, 0.0013122558593750, 0.0011901855468750, +0.0010070800781250, 0.0001220703125000, 0.0000610351562500, 0.0005798339843750, +0.0005187988281250, 0.0002136230468750, -0.0004882812500000, 0.0000000000000000, +-0.0005187988281250, 0.0002441406250000, -0.0005187988281250, 0.0002746582031250, +-0.0010681152343750, 0.0001525878906250, -0.0008544921875000, 0.0006408691406250, +-0.0006408691406250, 0.0004882812500000, -0.0007324218750000, 0.0007324218750000, +-0.0002746582031250, 0.0011596679687500, 0.0002136230468750, 0.0007934570312500, +0.0001220703125000, 0.0014343261718750, 0.0007324218750000, 0.0012512207031250, +0.0009155273437500, 0.0012817382812500, 0.0009765625000000, 0.0016784667968750, +0.0011291503906250, 0.0013732910156250, 0.0010986328125000, 0.0016479492187500, +0.0011596679687500, 0.0016784667968750, 0.0011901855468750, 0.0016479492187500, +0.0014953613281250, 0.0017395019531250, 0.0017395019531250, 0.0018005371093750, +0.0015258789062500, 0.0018615722656250, 0.0022888183593750, 0.0019836425781250, +0.0021667480468750, 0.0018920898437500, 0.0023498535156250, 0.0019226074218750, +0.0029602050781250, 0.0021057128906250, 0.0026245117187500, 0.0015869140625000, +0.0030822753906250}, +{0.0026245117187500, 0.0051574707031250, 0.0029602050781250, 0.0050659179687500, +0.0031127929687500, 0.0052185058593750, 0.0029296875000000, 0.0060729980468750, +0.0028991699218750, 0.0056457519531250, 0.0028991699218750, 0.0058593750000000, +0.0025939941406250, 0.0057983398437500, 0.0026550292968750, 0.0054931640625000, +0.0027160644531250, 0.0054931640625000, 0.0025939941406250, 0.0054321289062500, +0.0026550292968750, 0.0047912597656250, 0.0029602050781250, 0.0049438476562500, +0.0028076171875000, 0.0046691894531250, 0.0029602050781250, 0.0039367675781250, +0.0032653808593750, 0.0039672851562500, 0.0032348632812500, 0.0037536621093750, +0.0039367675781250, 0.0036621093750000, 0.0036010742187500, 0.0036315917968750, +0.0039062500000000, 0.0036315917968750, 0.0044555664062500, 0.0036315917968750, +0.0040283203125000, 0.0033874511718750, 0.0050048828125000, 0.0036315917968750, +0.0048217773437500, 0.0032653808593750, 0.0049438476562500, 0.0029296875000000, +0.0057067871093750, 0.0034179687500000, 0.0053405761718750, 0.0025329589843750, +0.0054321289062500, 0.0026855468750000, 0.0057067871093750, 0.0027160644531250, +0.0054016113281250, 0.0022277832031250, 0.0050964355468750, 0.0025329589843750, +0.0052490234375000, 0.0024108886718750, 0.0043945312500000, 0.0023498535156250, +0.0044555664062500, 0.0023193359375000, 0.0042114257812500, 0.0023803710937500, +0.0035400390625000, 0.0024414062500000, 0.0036926269531250, 0.0021057128906250, +0.0028381347656250, 0.0024719238281250, 0.0028076171875000, 0.0022277832031250, +0.0024719238281250, 0.0018615722656250, 0.0017700195312500, 0.0023803710937500, +0.0020141601562500, 0.0017089843750000, 0.0011596679687500, 0.0018005371093750, +0.0011901855468750, 0.0019531250000000, 0.0010681152343750, 0.0016479492187500, +0.0005187988281250, 0.0017395019531250, 0.0007324218750000, 0.0021667480468750, +0.0005187988281250, 0.0019226074218750, 0.0003662109375000, 0.0022277832031250, +0.0004882812500000, 0.0028076171875000, 0.0004577636718750, 0.0024414062500000, +0.0004272460937500, 0.0027770996093750, 0.0009155273437500, 0.0030822753906250, +0.0005798339843750, 0.0025939941406250, 0.0011596679687500, 0.0023498535156250, +0.0018310546875000, 0.0026855468750000, 0.0012817382812500, 0.0014038085937500, +0.0031127929687500, 0.0015563964843750, 0.0029907226562500, 0.0013427734375000, +0.0034790039062500, 0.0003967285156250, 0.0049438476562500, 0.0007324218750000, +0.0043334960937500, 0.0002441406250000, 0.0055236816406250, 0.0000610351562500, +0.0058898925781250, 0.0001831054687500, 0.0056762695312500, 0.0000305175781250, +0.0060729980468750, -0.0000915527343750, 0.0062255859375000, 0.0003051757812500, +0.0057678222656250, -0.0000305175781250, 0.0059509277343750, 0.0002136230468750, +0.0061035156250000, 0.0006713867187500, 0.0058288574218750, 0.0001831054687500, +0.0059814453125000, 0.0009460449218750, 0.0062255859375000, 0.0008544921875000, +0.0063476562500000, 0.0007324218750000, 0.0065002441406250, 0.0011901855468750, +0.0067138671875000, 0.0010375976562500, 0.0068359375000000, 0.0010986328125000, +0.0068054199218750, 0.0012512207031250, 0.0069580078125000, 0.0012207031250000, +0.0068054199218750, 0.0011901855468750, 0.0065917968750000, 0.0014038085937500, +0.0068054199218750, 0.0012817382812500, 0.0062255859375000, 0.0014343261718750, +0.0062866210937500, 0.0014343261718750, 0.0059814453125000, 0.0013732910156250, +0.0054321289062500, 0.0015258789062500, 0.0056152343750000, 0.0012512207031250, +0.0047912597656250, 0.0012512207031250, 0.0047607421875000, 0.0011596679687500, +0.0044860839843750, 0.0008544921875000, 0.0038146972656250, 0.0009460449218750, +0.0040588378906250, 0.0006408691406250, 0.0033264160156250, 0.0004882812500000, +0.0033569335937500, 0.0005493164062500, 0.0032348632812500, 0.0003662109375000, +0.0028076171875000, 0.0001831054687500, 0.0030822753906250, 0.0004882812500000, +0.0026550292968750, 0.0002441406250000, 0.0028076171875000, 0.0003356933593750, +0.0027465820312500, 0.0006713867187500, 0.0025024414062500, 0.0003051757812500, +0.0028381347656250, 0.0006713867187500, 0.0023803710937500, 0.0005493164062500, +0.0026245117187500, 0.0004882812500000, 0.0025024414062500, 0.0006713867187500, +0.0020141601562500, 0.0005187988281250, 0.0024108886718750, 0.0004882812500000, +0.0018310546875000, 0.0004272460937500, 0.0018310546875000, 0.0003662109375000, +0.0017089843750000, 0.0003051757812500, 0.0012817382812500, 0.0001831054687500, +0.0013732910156250, 0.0003051757812500, 0.0010375976562500, 0.0002136230468750, +0.0008850097656250, 0.0001525878906250, 0.0008544921875000, 0.0001831054687500, +0.0007019042968750, 0.0000915527343750, 0.0006103515625000, 0.0000305175781250, +0.0009460449218750, 0.0000305175781250, 0.0006713867187500, 0.0000000000000000, +0.0009460449218750, -0.0000610351562500, 0.0014038085937500, -0.0000610351562500, +0.0010375976562500, 0.0000610351562500, 0.0020446777343750, 0.0000000000000000, +0.0018310546875000, 0.0000915527343750, 0.0021667480468750, 0.0001831054687500, +0.0030517578125000, 0.0001220703125000, 0.0026855468750000, 0.0004272460937500, +0.0035705566406250, 0.0003356933593750, 0.0035705566406250, 0.0004882812500000, +0.0035705566406250, 0.0007934570312500, 0.0041503906250000, 0.0006408691406250, +0.0039672851562500, 0.0008850097656250, 0.0037536621093750, 0.0008850097656250, +0.0041198730468750, 0.0008239746093750, 0.0036315917968750, 0.0008850097656250, +0.0030822753906250, 0.0007629394531250, 0.0035400390625000, 0.0008239746093750, +0.0025634765625000, 0.0006713867187500, 0.0027160644531250, 0.0006408691406250, +0.0026245117187500, 0.0007019042968750, 0.0019226074218750, 0.0005187988281250, +0.0022277832031250, 0.0007629394531250, 0.0020446777343750, 0.0007324218750000, +0.0018310546875000, 0.0008239746093750, 0.0021362304687500, 0.0010681152343750, +0.0024108886718750, 0.0010681152343750, 0.0022277832031250, 0.0012817382812500, +0.0030212402343750, 0.0013732910156250, 0.0028686523437500, 0.0014343261718750, +0.0030822753906250, 0.0015563964843750, 0.0036621093750000, 0.0016479492187500, +0.0032653808593750, 0.0015258789062500, 0.0040893554687500, 0.0017089843750000, +0.0039062500000000, 0.0016174316406250, 0.0040893554687500, 0.0014953613281250, +0.0046386718750000, 0.0018005371093750, 0.0042114257812500, 0.0012817382812500, +0.0046691894531250, 0.0015563964843750, 0.0045776367187500, 0.0015258789062500, +0.0045471191406250, 0.0010986328125000, 0.0047607421875000, 0.0014343261718750, +0.0045166015625000, 0.0011596679687500, 0.0048217773437500, 0.0010681152343750, +0.0047912597656250, 0.0014648437500000, 0.0045471191406250, 0.0015563964843750, +0.0046386718750000, 0.0013427734375000, 0.0046997070312500, 0.0028991699218750, +0.0041503906250000, 0.0024108886718750, 0.0043029785156250, 0.0030822753906250, +0.0041809082031250, 0.0045471191406250, 0.0037841796875000, 0.0035705566406250, +0.0039978027343750, 0.0050354003906250, 0.0036010742187500, 0.0051879882812500, +0.0036010742187500, 0.0047302246093750, 0.0038452148437500, 0.0051269531250000, +0.0037536621093750, 0.0052185058593750, 0.0037536621093750, 0.0044555664062500, +0.0045471191406250, 0.0045166015625000, 0.0042419433593750, 0.0043945312500000, +0.0049133300781250, 0.0037536621093750, 0.0060119628906250, 0.0037841796875000, +0.0055236816406250, 0.0040283203125000, 0.0065002441406250, 0.0034484863281250, +0.0068359375000000, 0.0040283203125000, 0.0063781738281250, 0.0047302246093750, +0.0063781738281250, 0.0038757324218750, 0.0066223144531250, 0.0055541992187500, +0.0056762695312500, 0.0053100585937500, 0.0056457519531250, 0.0053405761718750, +0.0054931640625000, 0.0063781738281250, 0.0049743652343750, 0.0058288574218750, +0.0052185058593750, 0.0057373046875000, 0.0048522949218750, 0.0059509277343750, +0.0049133300781250, 0.0054321289062500, 0.0048828125000000, 0.0044860839843750, +0.0045166015625000, 0.0029602050781250, 0.0055236816406250, 0.0042724609375000, +0.0045166015625000, 0.0038452148437500, 0.0046081542968750, 0.0040893554687500, +0.0044250488281250, 0.0046691894531250, 0.0039978027343750, 0.0044860839843750, +0.0041198730468750, 0.0048522949218750, 0.0039062500000000, 0.0046386718750000, +0.0037841796875000, 0.0051269531250000, 0.0038452148437500, 0.0055541992187500, +0.0037536621093750, 0.0049743652343750, 0.0036621093750000, 0.0068664550781250, +0.0040893554687500, 0.0065917968750000, 0.0039978027343750, 0.0068054199218750, +0.0039367675781250, 0.0081481933593750, 0.0041198730468750, 0.0074768066406250, +0.0040588378906250, 0.0071411132812500, 0.0033264160156250, 0.0079345703125000, +0.0036010742187500, 0.0065917968750000, 0.0030822753906250, 0.0053405761718750, +0.0022277832031250, 0.0065917968750000, 0.0025329589843750, 0.0035705566406250, +0.0017395019531250, 0.0039672851562500, 0.0014953613281250, 0.0035400390625000, +0.0015563964843750, 0.0016479492187500, 0.0011901855468750, 0.0027465820312500, +0.0011596679687500, 0.0011901855468750, 0.0019226074218750, 0.0011291503906250, +0.0015869140625000, 0.0011596679687500, 0.0021362304687500, 0.0002746582031250, +0.0030822753906250, 0.0005187988281250, 0.0025024414062500, 0.0003967285156250, +0.0034790039062500, -0.0000305175781250, 0.0038452148437500, 0.0003051757812500, +0.0033264160156250, 0.0003967285156250, 0.0033874511718750, -0.0001220703125000, +0.0036926269531250, 0.0013427734375000, 0.0020141601562500, 0.0006713867187500, +0.0022888183593750, 0.0013427734375000, 0.0019531250000000, 0.0027160644531250, +0.0006408691406250, 0.0015869140625000, 0.0010681152343750, 0.0037841796875000, +0.0007019042968750, 0.0035095214843750, 0.0003051757812500, 0.0038452148437500, +0.0007934570312500, 0.0053405761718750, 0.0011291503906250, 0.0044250488281250, +0.0007629394531250, 0.0054321289062500, 0.0017089843750000, 0.0055847167968750, +0.0018005371093750, 0.0054016113281250, 0.0017700195312500, 0.0056762695312500, +0.0023193359375000, 0.0054626464843750, 0.0022583007812500, 0.0056152343750000, +0.0018615722656250, 0.0054931640625000, 0.0023498535156250, 0.0054321289062500, +0.0018615722656250, 0.0055236816406250, 0.0011291503906250, 0.0054321289062500, +0.0018005371093750, 0.0052490234375000, 0.0007019042968750, 0.0054016113281250, +0.0007019042968750, 0.0052490234375000, 0.0008850097656250, 0.0050048828125000, +0.0003967285156250, 0.0051269531250000, 0.0005798339843750, 0.0047912597656250, +0.0009765625000000, 0.0047302246093750, 0.0007629394531250, 0.0047302246093750, +0.0010375976562500, 0.0044860839843750, 0.0015869140625000, 0.0045166015625000, +0.0012512207031250, 0.0045776367187500, 0.0017700195312500, 0.0043945312500000, +0.0018310546875000, 0.0048217773437500, 0.0017089843750000, 0.0051574707031250, +0.0018615722656250, 0.0048522949218750, 0.0018920898437500, 0.0061035156250000, +0.0014038085937500, 0.0058898925781250, 0.0015869140625000, 0.0063781738281250, +0.0013122558593750, 0.0075378417968750, 0.0007934570312500, 0.0069274902343750, +0.0010986328125000, 0.0080871582031250, 0.0005493164062500, 0.0083923339843750, +0.0004882812500000, 0.0081481933593750, 0.0005493164062500, 0.0086059570312500, +0.0002746582031250, 0.0087280273437500, 0.0003662109375000, 0.0078735351562500, +0.0003051757812500, 0.0084533691406250, 0.0002746582031250, 0.0077819824218750, +0.0002136230468750}, +{0.0057373046875000, 0.0039978027343750, 0.0050659179687500, 0.0044555664062500, +0.0044250488281250, 0.0037841796875000, 0.0048217773437500, 0.0054321289062500, +0.0038757324218750, 0.0052795410156250, 0.0039672851562500, 0.0051879882812500, +0.0037231445312500, 0.0063171386718750, 0.0030517578125000, 0.0060119628906250, +0.0033569335937500, 0.0049743652343750, 0.0024719238281250, 0.0056762695312500, +0.0022583007812500, 0.0045166015625000, 0.0024108886718750, 0.0028381347656250, +0.0020141601562500, 0.0039672851562500, 0.0019226074218750, 0.0015563964843750, +0.0025329589843750, 0.0015869140625000, 0.0024108886718750, 0.0016479492187500, +0.0024719238281250, 0.0004882812500000, 0.0029907226562500, 0.0010070800781250, +0.0029296875000000, 0.0007934570312500, 0.0025329589843750, 0.0007324218750000, +0.0029602050781250, 0.0007934570312500, 0.0024414062500000, 0.0006713867187500, +0.0016784667968750, 0.0007934570312500, 0.0023498535156250, 0.0011291503906250, +0.0009460449218750, 0.0007019042968750, 0.0010375976562500, 0.0012817382812500, +0.0010681152343750, 0.0018920898437500, 0.0002746582031250, 0.0012207031250000, +0.0006408691406250, 0.0030822753906250, 0.0006713867187500, 0.0026855468750000, +0.0003967285156250, 0.0031127929687500, 0.0009460449218750, 0.0044250488281250, +0.0014648437500000, 0.0036010742187500, 0.0011901855468750, 0.0050354003906250, +0.0020751953125000, 0.0048828125000000, 0.0022888183593750, 0.0049133300781250, +0.0020446777343750, 0.0057678222656250, 0.0023803710937500, 0.0052795410156250, +0.0025329589843750, 0.0057678222656250, 0.0014343261718750, 0.0057373046875000, +0.0017700195312500, 0.0056457519531250, 0.0014038085937500, 0.0057983398437500, +0.0002441406250000, 0.0055541992187500, 0.0008850097656250, 0.0059204101562500, +0.0002746582031250, 0.0055847167968750, 0.0000305175781250, 0.0057373046875000, +0.0004882812500000, 0.0061950683593750, 0.0005493164062500, 0.0056762695312500, +0.0003662109375000, 0.0061950683593750, 0.0013122558593750, 0.0061340332031250, +0.0009765625000000, 0.0059204101562500, 0.0013427734375000, 0.0060119628906250, +0.0021972656250000, 0.0058898925781250, 0.0016784667968750, 0.0057678222656250, +0.0022888183593750, 0.0056152343750000, 0.0024414062500000, 0.0057983398437500, +0.0021057128906250, 0.0058593750000000, 0.0022277832031250, 0.0056457519531250, +0.0023803710937500, 0.0066223144531250, 0.0015869140625000, 0.0061950683593750, +0.0018005371093750, 0.0068359375000000, 0.0014648437500000, 0.0079040527343750, +0.0008544921875000, 0.0071105957031250, 0.0012207031250000, 0.0090637207031250, +0.0006408691406250, 0.0088195800781250, 0.0005493164062500, 0.0090637207031250, +0.0006713867187500, 0.0104064941406250, 0.0004272460937500, 0.0098571777343750, +0.0005187988281250, 0.0103149414062500, 0.0006408691406250, 0.0108032226562500, +0.0006713867187500, 0.0101318359375000, 0.0007019042968750, 0.0099487304687500, +0.0007934570312500, 0.0104980468750000, 0.0008850097656250, 0.0085144042968750, +0.0007934570312500, 0.0091247558593750, 0.0008239746093750, 0.0085144042968750, +0.0007324218750000, 0.0068664550781250, 0.0004577636718750, 0.0079040527343750, +0.0004882812500000, 0.0060729980468750, 0.0003356933593750, 0.0061035156250000, +0.0001525878906250, 0.0061035156250000, 0.0001220703125000, 0.0050964355468750, +0.0001220703125000, 0.0054931640625000, -0.0000915527343750, 0.0052490234375000, +0.0000000000000000, 0.0050048828125000, -0.0000915527343750, 0.0052795410156250, +-0.0000610351562500, 0.0054626464843750, 0.0000915527343750, 0.0051574707031250, +-0.0000610351562500, 0.0057983398437500, 0.0001831054687500, 0.0056152343750000, +0.0001525878906250, 0.0057373046875000, 0.0002746582031250, 0.0061035156250000, +0.0003967285156250, 0.0058288574218750, 0.0002136230468750, 0.0061340332031250, +0.0006713867187500, 0.0061340332031250, 0.0003967285156250, 0.0060119628906250, +0.0006713867187500, 0.0060729980468750, 0.0009155273437500, 0.0060119628906250, +0.0003662109375000, 0.0058288574218750, 0.0012512207031250, 0.0058898925781250, +0.0009460449218750, 0.0056762695312500, 0.0008544921875000, 0.0054321289062500, +0.0014648437500000, 0.0056457519531250, 0.0010070800781250, 0.0051269531250000, +0.0013427734375000, 0.0051574707031250, 0.0013732910156250, 0.0050659179687500, +0.0012207031250000, 0.0046081542968750, 0.0014038085937500, 0.0047607421875000, +0.0014038085937500, 0.0043640136718750, 0.0012207031250000, 0.0042419433593750, +0.0013122558593750, 0.0041198730468750, 0.0011901855468750, 0.0038757324218750, +0.0009460449218750, 0.0038146972656250, 0.0010986328125000, 0.0035400390625000, +0.0009765625000000, 0.0034790039062500, 0.0008239746093750, 0.0035095214843750, +0.0010070800781250, 0.0033264160156250, 0.0010681152343750, 0.0032958984375000, +0.0008544921875000, 0.0033874511718750, 0.0011291503906250, 0.0033569335937500, +0.0009155273437500, 0.0035095214843750, 0.0009765625000000, 0.0036926269531250, +0.0012512207031250, 0.0036315917968750, 0.0009765625000000, 0.0038757324218750, +0.0012207031250000, 0.0039062500000000, 0.0011901855468750, 0.0038757324218750, +0.0011291503906250, 0.0039367675781250, 0.0012207031250000, 0.0038452148437500, +0.0010070800781250, 0.0037231445312500, 0.0010986328125000, 0.0036621093750000, +0.0010986328125000, 0.0036621093750000, 0.0009460449218750, 0.0035400390625000, +0.0008850097656250, 0.0034179687500000, 0.0008239746093750, 0.0037231445312500, +0.0007934570312500, 0.0035095214843750, 0.0007324218750000, 0.0036315917968750, +0.0008239746093750, 0.0038757324218750, 0.0008239746093750, 0.0035400390625000, +0.0007324218750000, 0.0039062500000000, 0.0008850097656250, 0.0038146972656250, +0.0008239746093750, 0.0037841796875000, 0.0007324218750000, 0.0039062500000000, +0.0007629394531250, 0.0036926269531250, 0.0007019042968750, 0.0039367675781250, +0.0006713867187500, 0.0037536621093750, 0.0005187988281250, 0.0039367675781250, +0.0007629394531250, 0.0042419433593750, 0.0009460449218750, 0.0038757324218750, +0.0007019042968750, 0.0046386718750000, 0.0016174316406250, 0.0045471191406250, +0.0014038085937500, 0.0043945312500000, 0.0016479492187500, 0.0048522949218750, +0.0023498535156250, 0.0047302246093750, 0.0019836425781250, 0.0043640136718750, +0.0023193359375000, 0.0046081542968750, 0.0025024414062500, 0.0041809082031250, +0.0022277832031250, 0.0036621093750000, 0.0021057128906250, 0.0039367675781250, +0.0023193359375000, 0.0028686523437500, 0.0018310546875000, 0.0028991699218750, +0.0018615722656250, 0.0024719238281250, 0.0018615722656250, 0.0017395019531250, +0.0015563964843750, 0.0019531250000000, 0.0016174316406250, 0.0006713867187500, +0.0018310546875000, 0.0007629394531250, 0.0015563964843750, 0.0004577636718750, +0.0018615722656250, -0.0005187988281250, 0.0022277832031250, -0.0001831054687500, +0.0018615722656250, -0.0004577636718750, 0.0030517578125000, -0.0006408691406250, +0.0027160644531250, -0.0002136230468750, 0.0030517578125000, -0.0000305175781250, +0.0039672851562500, 0.0000000000000000, 0.0032958984375000, 0.0008850097656250, +0.0043334960937500, 0.0008239746093750, 0.0041503906250000, 0.0012207031250000, +0.0040893554687500, 0.0022888183593750, 0.0047302246093750, 0.0028076171875000, +0.0045471191406250, 0.0038146972656250, 0.0043029785156250, 0.0035705566406250, +0.0044860839843750, 0.0036621093750000, 0.0040893554687500, 0.0043945312500000, +0.0036010742187500, 0.0041503906250000, 0.0039978027343750, 0.0042724609375000, +0.0030517578125000, 0.0045471191406250, 0.0031127929687500, 0.0042419433593750, +0.0028686523437500, 0.0039672851562500, 0.0021667480468750, 0.0042114257812500, +0.0024414062500000, 0.0036926269531250, 0.0018005371093750, 0.0036926269531250, +0.0018310546875000, 0.0035400390625000, 0.0016784667968750, 0.0032348632812500, +0.0012207031250000, 0.0035095214843750, 0.0014648437500000, 0.0030517578125000, +0.0013427734375000, 0.0032653808593750, 0.0012512207031250, 0.0031127929687500, +0.0015869140625000, 0.0027465820312500, 0.0017395019531250, 0.0030822753906250, +0.0015563964843750, 0.0025634765625000, 0.0027770996093750, 0.0025634765625000, +0.0024414062500000, 0.0025024414062500, 0.0030212402343750, 0.0022583007812500, +0.0040283203125000, 0.0023803710937500, 0.0033569335937500, 0.0019836425781250, +0.0050354003906250, 0.0021362304687500, 0.0047302246093750, 0.0019226074218750, +0.0052490234375000, 0.0014343261718750, 0.0066223144531250, 0.0018005371093750, +0.0057983398437500, 0.0010375976562500, 0.0071716308593750, 0.0011291503906250, +0.0073242187500000, 0.0010375976562500, 0.0070190429687500, 0.0005798339843750, +0.0075073242187500, 0.0008239746093750, 0.0073852539062500, 0.0001831054687500, +0.0067138671875000, 0.0002441406250000, 0.0069274902343750, 0.0003356933593750, +0.0065307617187500, -0.0001220703125000, 0.0057983398437500, 0.0000000000000000, +0.0061340332031250, 0.0003051757812500, 0.0055541992187500, -0.0000305175781250, +0.0053710937500000, 0.0003662109375000, 0.0055847167968750, 0.0008239746093750, +0.0054321289062500, 0.0003051757812500, 0.0053405761718750, 0.0010986328125000, +0.0058898925781250, 0.0009765625000000, 0.0056457519531250, 0.0008850097656250, +0.0058593750000000, 0.0012817382812500, 0.0063781738281250, 0.0010070800781250, +0.0060424804687500, 0.0008239746093750, 0.0065307617187500, 0.0010375976562500, +0.0065002441406250, 0.0007629394531250, 0.0065002441406250, 0.0003356933593750, +0.0067443847656250, 0.0006713867187500, 0.0066223144531250, 0.0001525878906250, +0.0067138671875000, 0.0000610351562500, 0.0066833496093750, 0.0001831054687500, +0.0065917968750000, -0.0000610351562500, 0.0065917968750000, -0.0001831054687500, +0.0065612792968750, 0.0003662109375000, 0.0066223144531250, -0.0000610351562500, +0.0065307617187500, 0.0002746582031250, 0.0065612792968750, 0.0009765625000000, +0.0066833496093750, 0.0003051757812500, 0.0065917968750000, 0.0014343261718750, +0.0068969726562500, 0.0011596679687500, 0.0068969726562500, 0.0012817382812500, +0.0070190429687500, 0.0020141601562500, 0.0072937011718750, 0.0014343261718750, +0.0072937011718750, 0.0019531250000000, 0.0073852539062500, 0.0019226074218750, +0.0076599121093750, 0.0017395019531250, 0.0071716308593750, 0.0019836425781250, +0.0069274902343750, 0.0018310546875000, 0.0073242187500000, 0.0017395019531250, +0.0059814453125000, 0.0018615722656250, 0.0063171386718750, 0.0016174316406250, +0.0058898925781250, 0.0014038085937500, 0.0047912597656250, 0.0017700195312500, +0.0054321289062500, 0.0009765625000000, 0.0042724609375000, 0.0013122558593750, +0.0042724609375000, 0.0010070800781250, 0.0043029785156250, 0.0003967285156250, +0.0036315917968750, 0.0009765625000000, 0.0038757324218750, -0.0000305175781250, +0.0038146972656250, 0.0002136230468750, 0.0036010742187500, 0.0000610351562500, +0.0038146972656250, -0.0005798339843750, 0.0039672851562500, -0.0000915527343750, +0.0037536621093750, -0.0007324218750000, 0.0041809082031250, -0.0006103515625000, +0.0041503906250000, -0.0005187988281250, 0.0041809082031250, -0.0007934570312500, +0.0043334960937500, -0.0004882812500000, 0.0042114257812500, -0.0005493164062500, +0.0043945312500000, -0.0004882812500000, 0.0043945312500000, -0.0003967285156250, +0.0043945312500000, -0.0003356933593750, 0.0045166015625000, -0.0001831054687500, +0.0043945312500000}, +{0.0048522949218750, 0.0024719238281250, 0.0046386718750000, 0.0020751953125000, +0.0055236816406250, 0.0021362304687500, 0.0054626464843750, 0.0020751953125000, +0.0056152343750000, 0.0017089843750000, 0.0062255859375000, 0.0018310546875000, +0.0059509277343750, 0.0017395019531250, 0.0062866210937500, 0.0017089843750000, +0.0064697265625000, 0.0016784667968750, 0.0061035156250000, 0.0016174316406250, +0.0059509277343750, 0.0017700195312500, 0.0060729980468750, 0.0012817382812500, +0.0050659179687500, 0.0014953613281250, 0.0050964355468750, 0.0013732910156250, +0.0048828125000000, 0.0009155273437500, 0.0040893554687500, 0.0011596679687500, +0.0042724609375000, 0.0006713867187500, 0.0041198730468750, 0.0007019042968750, +0.0038452148437500, 0.0005493164062500, 0.0041198730468750, 0.0002441406250000, +0.0043945312500000, 0.0003662109375000, 0.0040893554687500, -0.0000305175781250, +0.0046081542968750, 0.0000000000000000, 0.0045776367187500, 0.0000305175781250, +0.0045776367187500, -0.0001831054687500, 0.0048522949218750, -0.0001220703125000, +0.0046386718750000, 0.0001525878906250, 0.0047302246093750, -0.0000915527343750, +0.0046386718750000, 0.0001525878906250, 0.0045776367187500, 0.0005187988281250, +0.0045776367187500, 0.0001525878906250, 0.0044860839843750, 0.0007629394531250, +0.0043334960937500, 0.0006408691406250, 0.0043029785156250, 0.0005798339843750, +0.0040893554687500, 0.0009460449218750, 0.0038452148437500, 0.0007934570312500, +0.0038757324218750, 0.0006103515625000, 0.0036315917968750, 0.0006713867187500, +0.0034484863281250, 0.0006103515625000, 0.0034484863281250, 0.0003662109375000, +0.0033264160156250, 0.0004272460937500, 0.0031738281250000, 0.0002441406250000, +0.0034484863281250, 0.0001220703125000, 0.0032653808593750, 0.0002441406250000, +0.0032958984375000, 0.0001831054687500, 0.0035705566406250, 0.0000000000000000, +0.0033874511718750, 0.0007019042968750, 0.0035400390625000, 0.0002746582031250, +0.0036315917968750, 0.0006408691406250, 0.0035400390625000, 0.0013427734375000, +0.0034790039062500, 0.0006713867187500, 0.0036010742187500, 0.0017395019531250, +0.0034484863281250, 0.0015258789062500, 0.0033569335937500, 0.0014953613281250, +0.0035705566406250, 0.0020751953125000, 0.0035400390625000, 0.0017089843750000, +0.0034484863281250, 0.0018005371093750, 0.0042419433593750, 0.0018615722656250, +0.0041198730468750, 0.0016174316406250, 0.0045471191406250, 0.0014648437500000, +0.0052490234375000, 0.0016174316406250, 0.0049133300781250, 0.0011901855468750, +0.0058898925781250, 0.0012512207031250, 0.0057983398437500, 0.0011596679687500, +0.0061950683593750, 0.0008544921875000, 0.0068664550781250, 0.0010681152343750, +0.0064697265625000, 0.0006408691406250, 0.0073242187500000, 0.0007629394531250, +0.0073547363281250, 0.0006103515625000, 0.0073547363281250, 0.0002441406250000, +0.0077514648437500, 0.0006103515625000, 0.0075378417968750, -0.0000610351562500, +0.0076599121093750, 0.0001831054687500, 0.0076599121093750, -0.0000305175781250, +0.0073852539062500, -0.0005187988281250, 0.0072631835937500, -0.0000610351562500, +0.0072326660156250, -0.0007019042968750, 0.0065612792968750, -0.0006103515625000, +0.0066833496093750, -0.0005798339843750, 0.0061950683593750, -0.0009155273437500, +0.0055541992187500, -0.0006713867187500, 0.0059509277343750, -0.0007019042968750, +0.0046081542968750, -0.0007324218750000, 0.0048522949218750, -0.0005187988281250, +0.0044250488281250, -0.0003967285156250, 0.0033264160156250, -0.0005187988281250, +0.0039978027343750, -0.0001220703125000, 0.0027465820312500, -0.0001525878906250, +0.0027770996093750, -0.0000305175781250, 0.0027160644531250, 0.0002746582031250, +0.0020141601562500, 0.0000305175781250, 0.0023803710937500, 0.0005187988281250, +0.0022888183593750, 0.0003356933593750, 0.0021972656250000, 0.0004272460937500, +0.0024719238281250, 0.0007934570312500, 0.0026855468750000, 0.0005187988281250, +0.0025329589843750, 0.0010375976562500, 0.0028991699218750, 0.0010681152343750, +0.0030212402343750, 0.0011901855468750, 0.0028991699218750, 0.0015869140625000, +0.0030212402343750, 0.0015258789062500, 0.0030517578125000, 0.0016784667968750, +0.0026855468750000, 0.0019531250000000, 0.0028381347656250, 0.0018005371093750, +0.0027465820312500, 0.0017089843750000, 0.0022888183593750, 0.0019226074218750, +0.0025024414062500, 0.0012207031250000, 0.0022583007812500, 0.0013732910156250, +0.0021057128906250, 0.0012817382812500, 0.0022583007812500, 0.0007324218750000, +0.0023193359375000, 0.0010070800781250, 0.0022277832031250, 0.0007629394531250, +0.0025024414062500, 0.0006103515625000, 0.0024108886718750, 0.0009155273437500, +0.0023193359375000, 0.0010681152343750, 0.0024414062500000, 0.0009155273437500, +0.0023498535156250, 0.0017700195312500, 0.0021057128906250, 0.0016784667968750, +0.0021667480468750, 0.0018920898437500, 0.0019531250000000, 0.0025329589843750, +0.0016174316406250, 0.0023498535156250, 0.0015869140625000, 0.0022277832031250, +0.0010375976562500, 0.0024719238281250, 0.0010375976562500, 0.0020141601562500, +0.0008850097656250, 0.0014953613281250, 0.0003356933593750, 0.0018005371093750, +0.0003967285156250, 0.0009765625000000, 0.0003356933593750, 0.0008544921875000, +0.0000305175781250, 0.0009765625000000, 0.0004577636718750, 0.0007324218750000, +0.0007629394531250, 0.0007629394531250, 0.0003356933593750, 0.0016174316406250, +0.0017089843750000, 0.0012817382812500, 0.0014648437500000, 0.0016784667968750, +0.0018920898437500, 0.0025939941406250, 0.0028991699218750, 0.0021972656250000, +0.0023498535156250, 0.0027770996093750, 0.0035705566406250, 0.0032043457031250, +0.0034790039062500, 0.0028686523437500, 0.0036621093750000, 0.0028686523437500, +0.0044555664062500, 0.0032653808593750, 0.0039978027343750, 0.0022888183593750, +0.0048217773437500, 0.0025634765625000, 0.0048217773437500, 0.0024719238281250, +0.0047912597656250, 0.0018005371093750, 0.0052795410156250, 0.0022583007812500, +0.0050659179687500, 0.0022583007812500, 0.0050659179687500, 0.0022277832031250, +0.0052185058593750, 0.0025939941406250, 0.0047912597656250, 0.0029907226562500, +0.0044860839843750, 0.0029907226562500, 0.0046691894531250, 0.0032958984375000, +0.0032958984375000, 0.0035095214843750, 0.0036010742187500, 0.0032653808593750, +0.0028381347656250, 0.0032348632812500, 0.0014038085937500, 0.0036926269531250, +0.0022888183593750, 0.0032653808593750, 0.0008850097656250, 0.0033264160156250, +0.0005798339843750, 0.0036926269531250, 0.0011596679687500, 0.0038146972656250, +0.0010375976562500, 0.0050048828125000, 0.0043029785156250, 0.0023193359375000, +0.0019531250000000, 0.0039978027343750, 0.0022277832031250, 0.0027465820312500, +0.0023498535156250, 0.0005798339843750, 0.0017089843750000, 0.0019531250000000, +0.0017395019531250, 0.0005798339843750, 0.0024414062500000, 0.0001831054687500, +0.0023498535156250, 0.0007934570312500, 0.0023803710937500, 0.0006408691406250, +0.0028076171875000, 0.0004272460937500, 0.0026855468750000, 0.0014038085937500, +0.0028686523437500, 0.0013427734375000, 0.0027465820312500, 0.0014648437500000, +0.0031433105468750, 0.0018920898437500, 0.0035095214843750, 0.0017700195312500, +0.0031433105468750, 0.0025939941406250, 0.0039978027343750, 0.0022888183593750, +0.0040588378906250, 0.0030212402343750, 0.0036621093750000, 0.0040283203125000, +0.0038757324218750, 0.0032958984375000, 0.0039367675781250, 0.0053710937500000, +0.0029907226562500, 0.0053100585937500, 0.0031433105468750, 0.0054931640625000, +0.0028381347656250, 0.0068054199218750, 0.0021057128906250, 0.0065917968750000, +0.0023803710937500, 0.0069580078125000, 0.0019531250000000, 0.0074157714843750, +0.0018310546875000, 0.0071411132812500, 0.0018920898437500, 0.0070495605468750, +0.0017700195312500, 0.0075378417968750, 0.0017089843750000, 0.0067443847656250, +0.0018005371093750, 0.0070495605468750, 0.0017395019531250, 0.0068664550781250, +0.0017700195312500, 0.0064392089843750, 0.0018920898437500, 0.0068664550781250, +0.0017395019531250, 0.0054626464843750, 0.0015258789062500, 0.0060729980468750, +0.0017089843750000, 0.0053710937500000, 0.0014648437500000, 0.0039062500000000, +0.0009765625000000, 0.0046997070312500, 0.0012512207031250, 0.0027160644531250, +0.0008544921875000, 0.0028686523437500, 0.0007019042968750, 0.0025634765625000, +0.0009765625000000, 0.0012817382812500, 0.0010375976562500, 0.0018920898437500, +0.0009460449218750, 0.0011291503906250, 0.0014953613281250, 0.0010070800781250, +0.0015869140625000, 0.0014038085937500, 0.0015869140625000, 0.0012817382812500, +0.0019226074218750, 0.0012207031250000, 0.0019531250000000, 0.0021972656250000, +0.0017700195312500, 0.0020751953125000, 0.0020751953125000, 0.0022277832031250, +0.0018310546875000, 0.0029296875000000, 0.0015258789062500, 0.0027160644531250, +0.0019226074218750, 0.0026855468750000, 0.0012512207031250, 0.0029907226562500, +0.0013427734375000, 0.0024108886718750, 0.0012817382812500, 0.0019226074218750, +0.0007934570312500, 0.0023193359375000, 0.0010681152343750, 0.0007324218750000, +0.0007629394531250, 0.0010070800781250, 0.0006713867187500, 0.0006103515625000, +0.0007629394531250, -0.0005187988281250, 0.0006713867187500, 0.0001831054687500, +0.0006408691406250, -0.0007934570312500, 0.0005798339843750, -0.0007629394531250, +0.0006713867187500, -0.0005798339843750, 0.0004577636718750, -0.0009765625000000, +0.0003356933593750, -0.0007629394531250, 0.0005187988281250, -0.0004272460937500, +-0.0000305175781250, -0.0005187988281250, 0.0000915527343750, -0.0000915527343750, +-0.0001220703125000, 0.0003967285156250, -0.0005187988281250, 0.0002441406250000, +-0.0001831054687500, 0.0011291503906250, -0.0008544921875000, 0.0011901855468750, +-0.0007934570312500, 0.0014343261718750, -0.0007934570312500, 0.0020446777343750, +-0.0011291503906250, 0.0018310546875000, -0.0008850097656250, 0.0021057128906250, +-0.0008544921875000, 0.0023193359375000, -0.0009460449218750, 0.0021057128906250, +-0.0006713867187500, 0.0020446777343750, -0.0004882812500000, 0.0022277832031250, +-0.0005493164062500, 0.0015258789062500, -0.0001220703125000, 0.0018005371093750, +-0.0001831054687500, 0.0015869140625000, 0.0000610351562500, 0.0009155273437500, +0.0004882812500000, 0.0013427734375000, 0.0002136230468750, 0.0008850097656250, +0.0006713867187500, 0.0008239746093750, 0.0006408691406250, 0.0010681152343750, +0.0007019042968750, 0.0010375976562500, 0.0009460449218750, 0.0010681152343750, +0.0009460449218750, 0.0016174316406250, 0.0010375976562500, 0.0013732910156250, +0.0011596679687500, 0.0017700195312500, 0.0011901855468750, 0.0023498535156250, +0.0011901855468750, 0.0019531250000000, 0.0012207031250000, 0.0029296875000000, +0.0013122558593750, 0.0028076171875000, 0.0012817382812500, 0.0030517578125000, +0.0012817382812500, 0.0037231445312500, 0.0013732910156250, 0.0033874511718750, +0.0012817382812500, 0.0041809082031250, 0.0014038085937500, 0.0041809082031250, +0.0012207031250000, 0.0043945312500000, 0.0012207031250000, 0.0049438476562500, +0.0013122558593750, 0.0046691894531250, 0.0010986328125000, 0.0050964355468750, +0.0011901855468750, 0.0050964355468750, 0.0011291503906250, 0.0051574707031250, +0.0010375976562500, 0.0054016113281250, 0.0010070800781250, 0.0051574707031250, +0.0009765625000000, 0.0054016113281250, 0.0009155273437500, 0.0052795410156250, +0.0008850097656250}, +{0.0015869140625000, 0.0003662109375000, 0.0015258789062500, 0.0007019042968750, +0.0015563964843750, -0.0002746582031250, 0.0016479492187500, 0.0001220703125000, +0.0016479492187500, 0.0005493164062500, 0.0014343261718750, 0.0001525878906250, +0.0016174316406250, 0.0007324218750000, 0.0014343261718750, 0.0014343261718750, +0.0010681152343750, 0.0010070800781250, 0.0013427734375000, 0.0021057128906250, +0.0010375976562500, 0.0021057128906250, 0.0008544921875000, 0.0020141601562500, +0.0010681152343750, 0.0025634765625000, 0.0010681152343750, 0.0024108886718750, +0.0008544921875000, 0.0019226074218750, 0.0013427734375000, 0.0022583007812500, +0.0011596679687500, 0.0019531250000000, 0.0012207031250000, 0.0011901855468750, +0.0016174316406250, 0.0015869140625000, 0.0013122558593750, 0.0010070800781250, +0.0015258789062500, 0.0007019042968750, 0.0014953613281250, 0.0009460449218750, +0.0012817382812500, 0.0007324218750000, 0.0013122558593750, 0.0005493164062500, +0.0012817382812500, 0.0013732910156250, 0.0007019042968750, 0.0009460449218750, +0.0009765625000000, 0.0012817382812500, 0.0007019042968750, 0.0021667480468750, +0.0001831054687500, 0.0015869140625000, 0.0006713867187500, 0.0023498535156250, +0.0000610351562500, 0.0024108886718750, 0.0001525878906250, 0.0022277832031250, +0.0001525878906250, 0.0024719238281250, -0.0001525878906250, 0.0024108886718750, +0.0001220703125000, 0.0021362304687500, -0.0003662109375000, 0.0022888183593750, +-0.0002136230468750, 0.0018310546875000, -0.0003662109375000, 0.0014648437500000, +-0.0007324218750000, 0.0016479492187500, -0.0004272460937500, 0.0004882812500000, +-0.0007934570312500, 0.0006103515625000, -0.0007324218750000, 0.0001525878906250, +-0.0007019042968750, -0.0007629394531250, -0.0008850097656250, -0.0003051757812500, +-0.0006713867187500, -0.0017089843750000, -0.0006713867187500, -0.0017089843750000, +-0.0007629394531250, -0.0018920898437500, -0.0005493164062500, -0.0027770996093750, +-0.0003662109375000, -0.0024719238281250, -0.0004272460937500, -0.0027465820312500, +-0.0000610351562500, -0.0030822753906250, 0.0000305175781250, -0.0025939941406250, +0.0000915527343750, -0.0022583007812500, 0.0003662109375000, -0.0026245117187500, +0.0004577636718750, -0.0012207031250000, 0.0005187988281250, -0.0015258789062500, +0.0006713867187500, -0.0009155273437500, 0.0007324218750000, 0.0002441406250000, +0.0007324218750000, -0.0004272460937500, 0.0009155273437500, 0.0013427734375000, +0.0008850097656250, 0.0011291503906250, 0.0009460449218750, 0.0015563964843750, +0.0010070800781250, 0.0026855468750000, 0.0009155273437500, 0.0019836425781250, +0.0009460449218750, 0.0033569335937500, 0.0010070800781250, 0.0031127929687500, +0.0008239746093750, 0.0033874511718750, 0.0009155273437500, 0.0043029785156250, +0.0010681152343750, 0.0037231445312500, 0.0008850097656250, 0.0048828125000000, +0.0011596679687500, 0.0047607421875000, 0.0010375976562500, 0.0050659179687500, +0.0010681152343750, 0.0058593750000000, 0.0012817382812500, 0.0053405761718750, +0.0010986328125000, 0.0064086914062500, 0.0011596679687500, 0.0063476562500000, +0.0012207031250000, 0.0064086914062500, 0.0010986328125000, 0.0070800781250000, +0.0010070800781250, 0.0067443847656250, 0.0010986328125000, 0.0071105957031250, +0.0007934570312500, 0.0071716308593750, 0.0009155273437500, 0.0069885253906250, +0.0008544921875000, 0.0070190429687500, 0.0005798339843750, 0.0070495605468750, +0.0007324218750000, 0.0065917968750000, 0.0005493164062500, 0.0066528320312500, +0.0005187988281250, 0.0065002441406250, 0.0005187988281250, 0.0061950683593750, +0.0005187988281250, 0.0063781738281250, 0.0006103515625000, 0.0061645507812500, +0.0004272460937500, 0.0061645507812500, 0.0005493164062500, 0.0061035156250000, +0.0004272460937500, 0.0060119628906250, 0.0001831054687500, 0.0061950683593750, +0.0004577636718750, 0.0058593750000000, 0.0001525878906250, 0.0060119628906250, +0.0001220703125000, 0.0058898925781250, 0.0003051757812500, 0.0055541992187500, +0.0002441406250000, 0.0057983398437500, 0.0001525878906250, 0.0054626464843750, +0.0009765625000000, 0.0053710937500000, 0.0007629394531250, 0.0054321289062500, +0.0010681152343750, 0.0053710937500000, 0.0018005371093750, 0.0053100585937500, +0.0014343261718750, 0.0054321289062500, 0.0018005371093750, 0.0053710937500000, +0.0021057128906250, 0.0053100585937500, 0.0018615722656250, 0.0053100585937500, +0.0017700195312500, 0.0052795410156250, 0.0020141601562500, 0.0050964355468750, +0.0014953613281250, 0.0051269531250000, 0.0014953613281250, 0.0049438476562500, +0.0015869140625000, 0.0046997070312500, 0.0013732910156250, 0.0048217773437500, +0.0013122558593750, 0.0046386718750000, 0.0016174316406250, 0.0045471191406250, +0.0014343261718750, 0.0046081542968750, 0.0017395019531250, 0.0046386718750000, +0.0020751953125000, 0.0045776367187500, 0.0017395019531250, 0.0046081542968750, +0.0028076171875000, 0.0046691894531250, 0.0025634765625000, 0.0044250488281250, +0.0028381347656250, 0.0043334960937500, 0.0036010742187500, 0.0043945312500000, +0.0031127929687500, 0.0039062500000000, 0.0038452148437500, 0.0039367675781250, +0.0039978027343750, 0.0039672851562500, 0.0038452148437500, 0.0037536621093750, +0.0040893554687500, 0.0038452148437500, 0.0040588378906250, 0.0039367675781250, +0.0038146972656250, 0.0040893554687500, 0.0039062500000000, 0.0041503906250000, +0.0036926269531250, 0.0041809082031250, 0.0033569335937500, 0.0042724609375000, +0.0035705566406250, 0.0042419433593750, 0.0029907226562500, 0.0042724609375000, +0.0029602050781250, 0.0043640136718750, 0.0028991699218750, 0.0043334960937500, +0.0026245117187500, 0.0043334960937500, 0.0028686523437500, 0.0049438476562500, +0.0028381347656250, 0.0048828125000000, 0.0027770996093750, 0.0049133300781250, +0.0028991699218750, 0.0055847167968750, 0.0029602050781250, 0.0057678222656250, +0.0031738281250000, 0.0053100585937500, 0.0036315917968750, 0.0056762695312500, +0.0033874511718750, 0.0055236816406250, 0.0037231445312500, 0.0049438476562500, +0.0043029785156250, 0.0052185058593750, 0.0040588378906250, 0.0046997070312500, +0.0050964355468750, 0.0046691894531250, 0.0051879882812500, 0.0043334960937500, +0.0051574707031250, 0.0039062500000000, 0.0056457519531250, 0.0040588378906250, +0.0057678222656250, 0.0030517578125000, 0.0052185058593750, 0.0031738281250000, +0.0056762695312500, 0.0028991699218750, 0.0053710937500000, 0.0020141601562500, +0.0047912597656250, 0.0023803710937500, 0.0052795410156250, 0.0023498535156250, +0.0042724609375000, 0.0021057128906250, 0.0045166015625000, 0.0023193359375000, +0.0042419433593750, 0.0025634765625000, 0.0035095214843750, 0.0023803710937500, +0.0040283203125000, 0.0028076171875000, 0.0027160644531250, 0.0028381347656250, +0.0030822753906250, 0.0028686523437500, 0.0026550292968750, 0.0031433105468750, +0.0015563964843750, 0.0029602050781250, 0.0022888183593750, 0.0032653808593750, +0.0011596679687500, 0.0032348632812500, 0.0012207031250000, 0.0032043457031250, +0.0012512207031250, 0.0033264160156250, 0.0007934570312500, 0.0032043457031250, +0.0011291503906250, 0.0031127929687500, 0.0006713867187500, 0.0031433105468750, +0.0009765625000000, 0.0029602050781250, 0.0008850097656250, 0.0028686523437500, +0.0004882812500000, 0.0028991699218750, 0.0009155273437500, 0.0027160644531250, +0.0006408691406250, 0.0027465820312500, 0.0007019042968750, 0.0026855468750000, +0.0009155273437500, 0.0025939941406250, 0.0009460449218750, 0.0026550292968750, +0.0009765625000000, 0.0023498535156250, 0.0012817382812500, 0.0025024414062500, +0.0014038085937500, 0.0023193359375000, 0.0013427734375000, 0.0020141601562500, +0.0014343261718750, 0.0021667480468750, 0.0016479492187500, 0.0015258789062500, +0.0014343261718750, 0.0017700195312500, 0.0016174316406250, 0.0014343261718750, +0.0017700195312500, 0.0008239746093750, 0.0016479492187500, 0.0012512207031250, +0.0018310546875000, 0.0004272460937500, 0.0021362304687500, 0.0004272460937500, +0.0021972656250000, 0.0003967285156250, 0.0024719238281250, -0.0001220703125000, +0.0028076171875000, 0.0000610351562500, 0.0028076171875000, 0.0001831054687500, +0.0027160644531250, -0.0001525878906250, 0.0029907226562500, 0.0000915527343750, +0.0028686523437500, 0.0004882812500000, 0.0025939941406250, 0.0000305175781250, +0.0028991699218750, 0.0005187988281250, 0.0024414062500000, 0.0004272460937500, +0.0024108886718750, 0.0003051757812500, 0.0025634765625000, 0.0004577636718750, +0.0025024414062500, 0.0002136230468750, 0.0024719238281250, 0.0001525878906250, +0.0028076171875000, 0.0000915527343750, 0.0027160644531250, -0.0000915527343750, +0.0027770996093750, -0.0002441406250000, 0.0030212402343750, -0.0002746582031250, +0.0029907226562500, -0.0005187988281250, 0.0028381347656250, -0.0005798339843750, +0.0030517578125000, -0.0005493164062500, 0.0028381347656250, -0.0005493164062500, +0.0024719238281250, -0.0006408691406250, 0.0026550292968750, -0.0003356933593750, +0.0021667480468750, -0.0003967285156250, 0.0022277832031250, -0.0002136230468750, +0.0021362304687500, 0.0000305175781250, 0.0018005371093750, 0.0000000000000000, +0.0019226074218750, 0.0002746582031250, 0.0016174316406250, 0.0003967285156250, +0.0015258789062500, 0.0004882812500000, 0.0015563964843750, 0.0007019042968750, +0.0013732910156250, 0.0008239746093750, 0.0013427734375000, 0.0007629394531250, +0.0015258789062500, 0.0009460449218750, 0.0012817382812500, 0.0009460449218750, +0.0014953613281250, 0.0007934570312500, 0.0017395019531250, 0.0010681152343750, +0.0014648437500000, 0.0007324218750000, 0.0024414062500000, 0.0008850097656250, +0.0022583007812500, 0.0009155273437500, 0.0026855468750000, 0.0007019042968750, +0.0035400390625000, 0.0008544921875000, 0.0031127929687500, 0.0007934570312500, +0.0044555664062500, 0.0008544921875000, 0.0043945312500000, 0.0008544921875000, +0.0048217773437500, 0.0007629394531250, 0.0058898925781250, 0.0008850097656250, +0.0054626464843750, 0.0006408691406250, 0.0063476562500000, 0.0007629394531250, +0.0065612792968750, 0.0007324218750000, 0.0065307617187500, 0.0005798339843750, +0.0069274902343750, 0.0005798339843750, 0.0069580078125000, 0.0006408691406250, +0.0065307617187500, 0.0004577636718750, 0.0068664550781250, 0.0005493164062500, +0.0065612792968750, 0.0006408691406250, 0.0060729980468750, 0.0004577636718750, +0.0065002441406250, 0.0008544921875000, 0.0054931640625000, 0.0007019042968750, +0.0055541992187500, 0.0006713867187500, 0.0053405761718750, 0.0009460449218750, +0.0046386718750000, 0.0008239746093750, 0.0049743652343750, 0.0008239746093750, +0.0043945312500000, 0.0008544921875000, 0.0042724609375000, 0.0007934570312500, +0.0043334960937500, 0.0007324218750000, 0.0041198730468750, 0.0008544921875000, +0.0041809082031250, 0.0007934570312500, 0.0045166015625000, 0.0008239746093750, +0.0043029785156250, 0.0010681152343750, 0.0044860839843750, 0.0012207031250000, +0.0049743652343750, 0.0011901855468750, 0.0046386718750000, 0.0016174316406250, +0.0049133300781250, 0.0017395019531250, 0.0048828125000000, 0.0018310546875000, +0.0046691894531250, 0.0021667480468750, 0.0046691894531250, 0.0022888183593750, +0.0046386718750000, 0.0019226074218750, 0.0042114257812500, 0.0022888183593750, +0.0040893554687500, 0.0019836425781250, 0.0040893554687500, 0.0013732910156250, +0.0038146972656250}, +{0.0064086914062500, 0.0003967285156250, 0.0059509277343750, 0.0005493164062500, +0.0063476562500000, 0.0000305175781250, 0.0057067871093750, 0.0000000000000000, +0.0057983398437500, 0.0000305175781250, 0.0059814453125000, -0.0003356933593750, +0.0057983398437500, -0.0003662109375000, 0.0059814453125000, -0.0002136230468750, +0.0061340332031250, -0.0003051757812500, 0.0061950683593750, -0.0002746582031250, +0.0063171386718750, -0.0000610351562500, 0.0065612792968750, -0.0000915527343750, +0.0065917968750000, -0.0001525878906250, 0.0066528320312500, 0.0001220703125000, +0.0067749023437500, 0.0000305175781250, 0.0067138671875000, -0.0001525878906250, +0.0066223144531250, 0.0001525878906250, 0.0067749023437500, -0.0002746582031250, +0.0065307617187500, -0.0001220703125000, 0.0065307617187500, -0.0000610351562500, +0.0065612792968750, -0.0003356933593750, 0.0063781738281250, -0.0002136230468750, +0.0064697265625000, -0.0002136230468750, 0.0060424804687500, -0.0003662109375000, +0.0062255859375000, -0.0002746582031250, 0.0057373046875000, -0.0002441406250000, +0.0051269531250000, -0.0003967285156250, 0.0054016113281250, -0.0001831054687500, +0.0042114257812500, -0.0002441406250000, 0.0042114257812500, -0.0002136230468750, +0.0039062500000000, -0.0000610351562500, 0.0030212402343750, -0.0001220703125000, +0.0033264160156250, 0.0001220703125000, 0.0026550292968750, 0.0001220703125000, +0.0025634765625000, 0.0002441406250000, 0.0025329589843750, 0.0004272460937500, +0.0021972656250000, 0.0003356933593750, 0.0023193359375000, 0.0007324218750000, +0.0023498535156250, 0.0007324218750000, 0.0021667480468750, 0.0007934570312500, +0.0023498535156250, 0.0010375976562500, 0.0025329589843750, 0.0008544921875000, +0.0022888183593750, 0.0011291503906250, 0.0029907226562500, 0.0010681152343750, +0.0027465820312500, 0.0011596679687500, 0.0030212402343750, 0.0013427734375000, +0.0035705566406250, 0.0010986328125000, 0.0032653808593750, 0.0014038085937500, +0.0040588378906250, 0.0013122558593750, 0.0041198730468750, 0.0012817382812500, +0.0041809082031250, 0.0014953613281250, 0.0046386718750000, 0.0013122558593750, +0.0046081542968750, 0.0013122558593750, 0.0046691894531250, 0.0013732910156250, +0.0049133300781250, 0.0011901855468750, 0.0047912597656250, 0.0010375976562500, +0.0046691894531250, 0.0012207031250000, 0.0050354003906250, 0.0007019042968750, +0.0042419433593750, 0.0008544921875000, 0.0046081542968750, 0.0007324218750000, +0.0041809082031250, 0.0003356933593750, 0.0034179687500000, 0.0006103515625000, +0.0039978027343750, 0.0004882812500000, 0.0026855468750000, 0.0004272460937500, +0.0028381347656250, 0.0006103515625000, 0.0025634765625000, 0.0006713867187500, +0.0016784667968750, 0.0006408691406250, 0.0020141601562500, 0.0009460449218750, +0.0013732910156250, 0.0010070800781250, 0.0011291503906250, 0.0010986328125000, +0.0013427734375000, 0.0013732910156250, 0.0010681152343750, 0.0014343261718750, +0.0007934570312500, 0.0014648437500000, 0.0015869140625000, 0.0016784667968750, +0.0011901855468750, 0.0015869140625000, 0.0014038085937500, 0.0014953613281250, +0.0021362304687500, 0.0016784667968750, 0.0015258789062500, 0.0014953613281250, +0.0021057128906250, 0.0014038085937500, 0.0021667480468750, 0.0016784667968750, +0.0018310546875000, 0.0017089843750000, 0.0019226074218750, 0.0014953613281250, +0.0018920898437500, 0.0021362304687500, 0.0014343261718750, 0.0021057128906250, +0.0015869140625000, 0.0021057128906250, 0.0013427734375000, 0.0025634765625000, +0.0009460449218750, 0.0025329589843750, 0.0012512207031250, 0.0023498535156250, +0.0009460449218750, 0.0026855468750000, 0.0008850097656250, 0.0024719238281250, +0.0010986328125000, 0.0021057128906250, 0.0011596679687500, 0.0025939941406250, +0.0010986328125000, 0.0018920898437500, 0.0014953613281250, 0.0020141601562500, +0.0013427734375000, 0.0020751953125000, 0.0015258789062500, 0.0016479492187500, +0.0019226074218750, 0.0020446777343750, 0.0016784667968750, 0.0020141601562500, +0.0025329589843750, 0.0020446777343750, 0.0024719238281250, 0.0021972656250000, +0.0027465820312500, 0.0022277832031250, 0.0032958984375000, 0.0023803710937500, +0.0030822753906250, 0.0024108886718750, 0.0037536621093750, 0.0025329589843750, +0.0035705566406250, 0.0025024414062500, 0.0040588378906250, 0.0023498535156250, +0.0046997070312500, 0.0025329589843750, 0.0040588378906250, 0.0027160644531250, +0.0055236816406250, 0.0026855468750000, 0.0052185058593750, 0.0029907226562500, +0.0054626464843750, 0.0033569335937500, 0.0066528320312500, 0.0033264160156250, +0.0060729980468750, 0.0036010742187500, 0.0064086914062500, 0.0039062500000000, +0.0067749023437500, 0.0033874511718750, 0.0061035156250000, 0.0032348632812500, +0.0057067871093750, 0.0037841796875000, 0.0059509277343750, 0.0020141601562500, +0.0044250488281250, 0.0025024414062500, 0.0046386718750000, 0.0021057128906250, +0.0040588378906250, 0.0007019042968750, 0.0028686523437500, 0.0015869140625000, +0.0034790039062500, 0.0007934570312500, 0.0018310546875000, 0.0003967285156250, +0.0018615722656250, 0.0009460449218750, 0.0019836425781250, 0.0015563964843750, +0.0006713867187500, 0.0034484863281250, 0.0064086914062500, 0.0048217773437500, +0.0032348632812500, 0.0044860839843750, 0.0043029785156250, 0.0049133300781250, +0.0035705566406250, 0.0057373046875000, 0.0017700195312500, 0.0054321289062500, +0.0025939941406250, 0.0058593750000000, 0.0024414062500000, 0.0061950683593750, +0.0020446777343750, 0.0055847167968750, 0.0025024414062500, 0.0053710937500000, +0.0030822753906250, 0.0058593750000000, 0.0027770996093750, 0.0038452148437500, +0.0031433105468750, 0.0044250488281250, 0.0032348632812500, 0.0037536621093750, +0.0032653808593750, 0.0020446777343750, 0.0034179687500000, 0.0030517578125000, +0.0034179687500000, 0.0014343261718750, 0.0039062500000000, 0.0013732910156250, +0.0037536621093750, 0.0013427734375000, 0.0039978027343750, 0.0005798339843750, +0.0045166015625000, 0.0008850097656250, 0.0043029785156250, 0.0002441406250000, +0.0040893554687500, 0.0002441406250000, 0.0043334960937500, 0.0003356933593750, +0.0038452148437500, -0.0000610351562500, 0.0031433105468750, -0.0000305175781250, +0.0034484863281250, 0.0007019042968750, 0.0027770996093750, 0.0002441406250000, +0.0026245117187500, 0.0008544921875000, 0.0028076171875000, 0.0018310546875000, +0.0027465820312500, 0.0010375976562500, 0.0027770996093750, 0.0027770996093750, +0.0029907226562500, 0.0025939941406250, 0.0031127929687500, 0.0026855468750000, +0.0032348632812500, 0.0037841796875000, 0.0033569335937500, 0.0033264160156250, +0.0033569335937500, 0.0034484863281250, 0.0033264160156250, 0.0036621093750000, +0.0034484863281250, 0.0034179687500000, 0.0033569335937500, 0.0031738281250000, +0.0032348632812500, 0.0034179687500000, 0.0034179687500000, 0.0031738281250000, +0.0028381347656250, 0.0030822753906250, 0.0030517578125000, 0.0035705566406250, +0.0028686523437500, 0.0037231445312500, 0.0023193359375000, 0.0033569335937500, +0.0027160644531250, 0.0047912597656250, 0.0021057128906250, 0.0043945312500000, +0.0022888183593750, 0.0048828125000000, 0.0022888183593750, 0.0060424804687500, +0.0018615722656250, 0.0052490234375000, 0.0022583007812500, 0.0066223144531250, +0.0015869140625000, 0.0065917968750000, 0.0017395019531250, 0.0065307617187500, +0.0015563964843750, 0.0071411132812500, 0.0010375976562500, 0.0068664550781250, +0.0012512207031250, 0.0071411132812500, 0.0007629394531250, 0.0072937011718750, +0.0005493164062500, 0.0071716308593750, 0.0006408691406250, 0.0071716308593750, +0.0004577636718750, 0.0072937011718750, 0.0002746582031250, 0.0070800781250000, +0.0004272460937500, 0.0072021484375000, 0.0001525878906250, 0.0070800781250000, +0.0001831054687500, 0.0068969726562500, 0.0002746582031250, 0.0070190429687500, +-0.0001525878906250, 0.0065612792968750, 0.0002441406250000, 0.0066528320312500, +0.0000000000000000, 0.0064392089843750, -0.0001220703125000, 0.0060119628906250, +0.0001831054687500, 0.0062255859375000, -0.0001525878906250, 0.0059509277343750, +0.0000915527343750, 0.0057678222656250, -0.0000915527343750, 0.0061035156250000, +-0.0000305175781250, 0.0060424804687500, 0.0001525878906250, 0.0057983398437500, +-0.0001525878906250, 0.0070190429687500, 0.0001831054687500, 0.0064392089843750, +0.0001525878906250, 0.0071716308593750, 0.0000915527343750, 0.0083618164062500, +0.0002746582031250, 0.0074157714843750, 0.0001220703125000, 0.0093383789062500, +0.0002441406250000, 0.0092773437500000, 0.0002441406250000, 0.0092773437500000, +0.0002746582031250, 0.0103759765625000, 0.0003967285156250, 0.0100097656250000, +0.0003967285156250, 0.0097961425781250, 0.0004882812500000, 0.0102233886718750, +0.0004882812500000, 0.0095214843750000, 0.0004882812500000, 0.0089416503906250, +0.0005493164062500, 0.0094604492187500, 0.0004882812500000, 0.0076904296875000, +0.0005187988281250, 0.0079650878906250, 0.0004577636718750, 0.0072326660156250, +0.0003662109375000, 0.0057373046875000, 0.0003662109375000, 0.0064697265625000, +0.0003356933593750, 0.0043945312500000, 0.0003051757812500, 0.0045166015625000, +0.0003051757812500, 0.0039672851562500, 0.0003356933593750, 0.0025024414062500, +0.0004272460937500, 0.0032043457031250, 0.0004882812500000, 0.0018005371093750, +0.0006103515625000, 0.0017395019531250, 0.0005798339843750, 0.0016479492187500, +0.0006713867187500, 0.0009155273437500, 0.0007934570312500, 0.0011291503906250, +0.0006713867187500, 0.0008850097656250, 0.0007934570312500, 0.0007324218750000, +0.0007324218750000, 0.0009460449218750, 0.0007019042968750, 0.0010070800781250, +0.0007629394531250, 0.0008850097656250, 0.0006103515625000, 0.0014953613281250, +0.0007629394531250, 0.0012512207031250, 0.0006408691406250, 0.0015869140625000, +0.0006408691406250, 0.0021057128906250, 0.0007324218750000, 0.0017089843750000, +0.0004882812500000, 0.0026245117187500, 0.0006408691406250, 0.0025024414062500, +0.0005493164062500, 0.0027160644531250, 0.0004882812500000, 0.0033874511718750, +0.0005187988281250, 0.0030212402343750, 0.0003662109375000, 0.0037841796875000, +0.0003662109375000, 0.0037536621093750, 0.0003662109375000, 0.0037841796875000, +0.0004882812500000, 0.0042724609375000, 0.0004272460937500, 0.0040283203125000, +0.0002746582031250, 0.0040588378906250, 0.0008850097656250, 0.0042724609375000, +0.0006103515625000, 0.0039672851562500, 0.0008239746093750, 0.0037536621093750, +0.0014343261718750, 0.0039672851562500, 0.0010070800781250, 0.0032958984375000, +0.0014648437500000, 0.0033874511718750, 0.0016174316406250, 0.0032348632812500, +0.0013122558593750, 0.0027465820312500, 0.0013732910156250, 0.0029907226562500, +0.0014648437500000, 0.0027770996093750, 0.0009460449218750, 0.0027160644531250, +0.0010070800781250, 0.0028991699218750, 0.0009765625000000, 0.0029602050781250, +0.0005493164062500, 0.0030212402343750, 0.0006408691406250, 0.0031738281250000, +0.0007934570312500, 0.0032958984375000, 0.0005493164062500, 0.0032958984375000, +0.0007629394531250, 0.0033874511718750, 0.0010375976562500, 0.0034790039062500, +0.0007324218750000, 0.0033874511718750, 0.0014038085937500, 0.0034484863281250, +0.0012207031250000, 0.0034790039062500, 0.0015258789062500, 0.0033264160156250, +0.0021667480468750, 0.0033874511718750, 0.0017395019531250, 0.0034179687500000, +0.0026550292968750}, +{0.0011596679687500, 0.0055236816406250, 0.0011596679687500, 0.0049743652343750, +0.0014038085937500, 0.0057373046875000, 0.0012512207031250, 0.0074157714843750, +0.0011596679687500, 0.0063476562500000, 0.0014648437500000, 0.0083618164062500, +0.0009155273437500, 0.0085449218750000, 0.0010986328125000, 0.0083923339843750, +0.0010375976562500, 0.0093994140625000, 0.0006713867187500, 0.0093383789062500, +0.0009155273437500, 0.0087585449218750, 0.0006103515625000, 0.0094909667968750, +0.0006103515625000, 0.0089721679687500, 0.0005493164062500, 0.0080566406250000, +0.0003967285156250, 0.0089111328125000, 0.0005493164062500, 0.0075683593750000, +0.0003967285156250, 0.0078430175781250, 0.0005187988281250, 0.0077209472656250, +0.0004272460937500, 0.0069274902343750, 0.0003051757812500, 0.0075683593750000, +0.0006103515625000, 0.0068359375000000, 0.0002136230468750, 0.0068359375000000, +0.0004882812500000, 0.0068969726562500, 0.0004882812500000, 0.0065917968750000, +0.0001831054687500, 0.0067443847656250, 0.0006408691406250, 0.0064392089843750, +0.0003051757812500, 0.0064697265625000, 0.0004577636718750, 0.0063171386718750, +0.0005187988281250, 0.0061340332031250, 0.0003356933593750, 0.0062866210937500, +0.0005493164062500, 0.0055847167968750, 0.0003967285156250, 0.0057678222656250, +0.0005493164062500, 0.0053405761718750, 0.0006103515625000, 0.0046691894531250, +0.0005187988281250, 0.0050659179687500, 0.0006408691406250, 0.0039062500000000, +0.0006103515625000, 0.0040588378906250, 0.0006713867187500, 0.0037231445312500, +0.0007629394531250, 0.0028991699218750, 0.0008544921875000, 0.0032348632812500, +0.0007934570312500, 0.0023498535156250, 0.0009155273437500, 0.0023498535156250, +0.0009460449218750, 0.0022277832031250, 0.0009460449218750, 0.0016174316406250, +0.0009460449218750, 0.0018005371093750, 0.0008850097656250, 0.0015258789062500, +0.0008850097656250, 0.0013427734375000, 0.0007934570312500, 0.0015563964843750, +0.0008239746093750, 0.0015563964843750, 0.0008239746093750, 0.0014038085937500, +0.0006713867187500, 0.0020141601562500, 0.0010986328125000, 0.0018920898437500, +0.0009155273437500, 0.0021667480468750, 0.0010681152343750, 0.0026245117187500, +0.0015258789062500, 0.0022888183593750, 0.0011901855468750, 0.0031738281250000, +0.0015563964843750, 0.0030822753906250, 0.0017395019531250, 0.0031127929687500, +0.0014648437500000, 0.0036926269531250, 0.0014343261718750, 0.0035095214843750, +0.0015869140625000, 0.0036315917968750, 0.0010986328125000, 0.0038757324218750, +0.0011596679687500, 0.0036010742187500, 0.0011291503906250, 0.0034790039062500, +0.0007934570312500, 0.0037536621093750, 0.0008850097656250, 0.0029602050781250, +0.0010070800781250, 0.0032348632812500, 0.0007934570312500, 0.0031433105468750, +0.0009765625000000, 0.0026245117187500, 0.0011901855468750, 0.0030822753906250, +0.0009155273437500, 0.0029602050781250, 0.0015258789062500, 0.0028991699218750, +0.0013427734375000, 0.0032653808593750, 0.0015563964843750, 0.0035095214843750, +0.0021057128906250, 0.0033874511718750, 0.0017700195312500, 0.0041809082031250, +0.0024719238281250, 0.0040893554687500, 0.0024719238281250, 0.0042419433593750, +0.0025634765625000, 0.0047912597656250, 0.0030212402343750, 0.0045776367187500, +0.0029602050781250, 0.0048522949218750, 0.0029907226562500, 0.0048828125000000, +0.0030822753906250, 0.0048522949218750, 0.0030822753906250, 0.0050048828125000, +0.0030517578125000, 0.0048828125000000, 0.0031127929687500, 0.0048217773437500, +0.0030212402343750, 0.0049133300781250, 0.0031127929687500, 0.0045471191406250, +0.0029602050781250, 0.0042419433593750, 0.0027465820312500, 0.0044555664062500, +0.0029907226562500, 0.0035705566406250, 0.0025024414062500, 0.0036010742187500, +0.0024719238281250, 0.0033874511718750, 0.0026245117187500, 0.0027160644531250, +0.0024108886718750, 0.0029296875000000, 0.0023193359375000, 0.0022888183593750, +0.0028686523437500, 0.0021362304687500, 0.0025939941406250, 0.0022583007812500, +0.0029907226562500, 0.0020141601562500, 0.0037231445312500, 0.0018615722656250, +0.0033569335937500, 0.0023193359375000, 0.0041198730468750, 0.0021667480468750, +0.0042724609375000, 0.0022888183593750, 0.0040283203125000, 0.0025329589843750, +0.0043029785156250, 0.0022888183593750, 0.0043640136718750, 0.0031127929687500, +0.0037231445312500, 0.0027465820312500, 0.0038757324218750, 0.0031433105468750, +0.0036315917968750, 0.0044250488281250, 0.0029602050781250, 0.0045776367187500, +0.0031433105468750, 0.0056762695312500, 0.0028381347656250, 0.0054321289062500, +0.0028076171875000, 0.0053710937500000, 0.0027770996093750, 0.0061035156250000, +0.0026855468750000, 0.0058288574218750, 0.0028686523437500, 0.0054626464843750, +0.0025939941406250, 0.0057373046875000, 0.0026245117187500, 0.0053405761718750, +0.0026245117187500, 0.0047912597656250, 0.0023803710937500, 0.0052490234375000, +0.0024108886718750, 0.0043029785156250, 0.0026550292968750, 0.0045776367187500, +0.0023193359375000, 0.0043334960937500, 0.0026550292968750, 0.0036010742187500, +0.0031127929687500, 0.0041503906250000, 0.0028076171875000, 0.0036315917968750, +0.0039978027343750, 0.0035095214843750, 0.0037536621093750, 0.0037536621093750, +0.0042114257812500, 0.0037231445312500, 0.0052185058593750, 0.0036926269531250, +0.0045471191406250, 0.0039367675781250, 0.0059509277343750, 0.0040283203125000, +0.0058898925781250, 0.0039062500000000, 0.0060424804687500, 0.0038757324218750, +0.0068359375000000, 0.0039672851562500, 0.0064392089843750, 0.0034484863281250, +0.0065917968750000, 0.0036315917968750, 0.0066833496093750, 0.0033569335937500, +0.0064392089843750, 0.0028991699218750, 0.0062561035156250, 0.0032958984375000, +0.0063781738281250, 0.0025024414062500, 0.0062255859375000, 0.0026855468750000, +0.0059814453125000, 0.0025939941406250, 0.0062255859375000, 0.0021057128906250, +0.0064086914062500, 0.0024108886718750, 0.0061950683593750, 0.0021667480468750, +0.0066223144531250, 0.0020446777343750, 0.0067443847656250, 0.0022583007812500, +0.0065917968750000, 0.0024108886718750, 0.0067443847656250, 0.0024108886718750, +0.0068969726562500, 0.0026245117187500, 0.0060729980468750, 0.0028076171875000, +0.0063476562500000, 0.0027465820312500, 0.0059204101562500, 0.0027465820312500, +0.0050048828125000, 0.0030517578125000, 0.0054321289062500, 0.0024719238281250, +0.0046386718750000, 0.0027160644531250, 0.0044860839843750, 0.0026550292968750, +0.0045776367187500, 0.0021362304687500, 0.0043029785156250, 0.0025024414062500, +0.0043029785156250, 0.0021057128906250, 0.0043029785156250, 0.0021362304687500, +0.0043029785156250, 0.0021667480468750, 0.0041503906250000, 0.0019836425781250, +0.0040893554687500, 0.0021057128906250, 0.0042114257812500, 0.0019836425781250, +0.0039672851562500, 0.0019226074218750, 0.0038757324218750, 0.0019226074218750, +0.0039672851562500, 0.0018920898437500, 0.0038757324218750, 0.0018310546875000, +0.0038757324218750, 0.0015869140625000, 0.0039978027343750, 0.0017089843750000, +0.0039672851562500, 0.0013732910156250, 0.0040283203125000, 0.0010070800781250, +0.0041198730468750, 0.0010986328125000, 0.0041503906250000, 0.0005798339843750, +0.0041809082031250, 0.0003967285156250, 0.0042724609375000, 0.0004272460937500, +0.0043945312500000, 0.0001220703125000, 0.0044250488281250, 0.0000000000000000, +0.0045166015625000, 0.0003051757812500, 0.0048828125000000, 0.0000915527343750, +0.0046997070312500, 0.0001831054687500, 0.0050964355468750, 0.0004882812500000, +0.0055541992187500, 0.0002746582031250, 0.0053100585937500, 0.0006103515625000, +0.0063171386718750, 0.0006713867187500, 0.0062866210937500, 0.0006713867187500, +0.0064392089843750, 0.0007629394531250, 0.0070800781250000, 0.0007934570312500, +0.0068969726562500, 0.0007019042968750, 0.0068359375000000, 0.0007019042968750, +0.0070190429687500, 0.0007629394531250, 0.0066528320312500, 0.0007324218750000, +0.0063781738281250, 0.0006408691406250, 0.0065002441406250, 0.0007629394531250, +0.0057983398437500, 0.0006713867187500, 0.0056152343750000, 0.0007019042968750, +0.0054321289062500, 0.0007629394531250, 0.0050048828125000, 0.0006103515625000, +0.0050964355468750, 0.0007934570312500, 0.0047607421875000, 0.0007019042968750, +0.0047912597656250, 0.0007324218750000, 0.0047302246093750, 0.0008544921875000, +0.0046081542968750, 0.0007019042968750, 0.0047912597656250, 0.0008544921875000, +0.0045166015625000, 0.0007934570312500, 0.0047607421875000, 0.0007934570312500, +0.0046691894531250, 0.0008239746093750, 0.0043945312500000, 0.0007629394531250, +0.0046691894531250, 0.0007629394531250, 0.0040283203125000, 0.0007324218750000, +0.0041503906250000, 0.0007324218750000, 0.0039367675781250, 0.0007019042968750, +0.0033874511718750, 0.0007019042968750, 0.0037841796875000, 0.0007934570312500, +0.0032043457031250, 0.0007019042968750, 0.0031127929687500, 0.0008239746093750, +0.0033264160156250, 0.0010375976562500, 0.0031738281250000, 0.0009155273437500, +0.0031738281250000, 0.0011596679687500, 0.0036621093750000, 0.0012207031250000, +0.0034484863281250, 0.0010986328125000, 0.0038452148437500, 0.0012207031250000, +0.0043945312500000, 0.0012817382812500, 0.0040283203125000, 0.0011291503906250, +0.0050964355468750, 0.0012512207031250, 0.0050048828125000, 0.0012817382812500, +0.0054016113281250, 0.0011291503906250, 0.0062255859375000, 0.0013427734375000, +0.0059509277343750, 0.0014343261718750, 0.0068359375000000, 0.0013732910156250, +0.0068969726562500, 0.0016174316406250, 0.0069580078125000, 0.0018310546875000, +0.0075378417968750, 0.0017089843750000, 0.0073547363281250, 0.0022583007812500, +0.0071411132812500, 0.0022277832031250, 0.0074768066406250, 0.0023498535156250, +0.0070495605468750, 0.0026855468750000, 0.0065307617187500, 0.0025939941406250, +0.0070190429687500, 0.0026245117187500, 0.0057678222656250, 0.0026550292968750, +0.0058593750000000, 0.0026245117187500, 0.0057067871093750, 0.0025634765625000, +0.0049438476562500, 0.0025634765625000, 0.0053100585937500, 0.0025939941406250, +0.0046997070312500, 0.0025634765625000, 0.0046691894531250, 0.0025939941406250, +0.0046386718750000, 0.0026245117187500, 0.0043640136718750, 0.0026550292968750, +0.0044555664062500, 0.0026550292968750, 0.0041503906250000, 0.0027465820312500, +0.0043029785156250, 0.0026245117187500, 0.0041198730468750, 0.0025329589843750, +0.0037841796875000, 0.0026550292968750, 0.0040893554687500, 0.0023803710937500, +0.0033264160156250, 0.0024414062500000, 0.0034484863281250, 0.0025024414062500, +0.0033874511718750, 0.0023193359375000, 0.0029296875000000, 0.0023193359375000, +0.0031738281250000, 0.0026550292968750, 0.0028686523437500, 0.0024719238281250, +0.0027770996093750, 0.0025939941406250, 0.0027465820312500, 0.0029602050781250, +0.0025329589843750, 0.0027465820312500, 0.0024719238281250, 0.0028076171875000, +0.0026245117187500, 0.0030517578125000, 0.0024414062500000, 0.0026550292968750, +0.0024108886718750, 0.0024414062500000, 0.0025939941406250, 0.0027770996093750, +0.0025024414062500, 0.0015869140625000, 0.0023193359375000, 0.0017395019531250, +0.0025024414062500, 0.0016479492187500, 0.0021362304687500, 0.0008239746093750, +0.0017395019531250, 0.0010986328125000, 0.0020446777343750, 0.0013732910156250, +0.0008239746093750, 0.0009460449218750, 0.0008850097656250, 0.0015563964843750, +0.0008850097656250}, +{0.0032958984375000, 0.0011901855468750, 0.0038452148437500, 0.0011901855468750, +0.0050354003906250, 0.0011291503906250, 0.0043640136718750, 0.0012207031250000, +0.0057373046875000, 0.0012207031250000, 0.0057373046875000, 0.0011596679687500, +0.0057373046875000, 0.0011901855468750, 0.0064086914062500, 0.0011291503906250, +0.0059814453125000, 0.0010375976562500, 0.0062866210937500, 0.0010681152343750, +0.0062561035156250, 0.0010070800781250, 0.0059509277343750, 0.0009155273437500, +0.0059814453125000, 0.0010070800781250, 0.0059814453125000, 0.0010070800781250, +0.0055236816406250, 0.0010070800781250, 0.0055847167968750, 0.0011291503906250, +0.0053710937500000, 0.0012512207031250, 0.0049743652343750, 0.0012512207031250, +0.0052185058593750, 0.0013427734375000, 0.0046386718750000, 0.0014953613281250, +0.0046386718750000, 0.0013732910156250, 0.0046081542968750, 0.0013122558593750, +0.0042419433593750, 0.0014648437500000, 0.0043334960937500, 0.0010986328125000, +0.0044555664062500, 0.0012207031250000, 0.0043029785156250, 0.0012512207031250, +0.0045776367187500, 0.0010070800781250, 0.0049438476562500, 0.0012817382812500, +0.0046691894531250, 0.0014038085937500, 0.0054626464843750, 0.0013122558593750, +0.0053710937500000, 0.0016479492187500, 0.0056152343750000, 0.0019226074218750, +0.0061645507812500, 0.0017395019531250, 0.0059509277343750, 0.0023803710937500, +0.0065307617187500, 0.0023803710937500, 0.0066223144531250, 0.0023803710937500, +0.0068664550781250, 0.0026855468750000, 0.0072631835937500, 0.0024719238281250, +0.0070495605468750, 0.0024414062500000, 0.0076599121093750, 0.0024108886718750, +0.0076904296875000, 0.0024108886718750, 0.0077514648437500, 0.0022888183593750, +0.0081481933593750, 0.0021972656250000, 0.0081176757812500, 0.0024414062500000, +0.0079040527343750, 0.0022583007812500, 0.0081481933593750, 0.0024414062500000, +0.0077819824218750, 0.0027465820312500, 0.0073242187500000, 0.0025634765625000, +0.0077209472656250, 0.0029602050781250, 0.0067443847656250, 0.0030517578125000, +0.0069274902343750, 0.0030212402343750, 0.0066528320312500, 0.0031433105468750, +0.0060424804687500, 0.0031127929687500, 0.0064697265625000, 0.0030822753906250, +0.0058288574218750, 0.0031127929687500, 0.0059814453125000, 0.0030822753906250, +0.0059204101562500, 0.0029602050781250, 0.0055236816406250, 0.0028686523437500, +0.0058288574218750, 0.0030822753906250, 0.0054016113281250, 0.0029602050781250, +0.0054931640625000, 0.0030212402343750, 0.0053405761718750, 0.0032348632812500, +0.0049133300781250, 0.0030517578125000, 0.0051574707031250, 0.0029907226562500, +0.0047912597656250, 0.0031738281250000, 0.0047607421875000, 0.0027465820312500, +0.0046997070312500, 0.0024108886718750, 0.0044555664062500, 0.0026855468750000, +0.0044555664062500, 0.0015563964843750, 0.0042724609375000, 0.0017089843750000, +0.0041809082031250, 0.0016784667968750, 0.0042114257812500, 0.0010070800781250, +0.0041809082031250, 0.0013122558593750, 0.0040283203125000, 0.0015258789062500, +0.0043640136718750, 0.0010681152343750, 0.0042419433593750, 0.0016174316406250, +0.0043334960937500, 0.0024108886718750, 0.0046997070312500, 0.0017700195312500, +0.0045471191406250, 0.0032043457031250, 0.0046386718750000, 0.0031127929687500, +0.0050354003906250, 0.0033569335937500, 0.0042114257812500, 0.0043640136718750, +0.0036926269531250, 0.0039672851562500, 0.0043945312500000, 0.0047302246093750, +0.0018310546875000, 0.0049133300781250, 0.0024414062500000, 0.0048522949218750, +0.0020446777343750, 0.0053100585937500, 0.0001831054687500, 0.0054931640625000, +0.0012207031250000, 0.0046691894531250, 0.0006408691406250, 0.0052490234375000, +0.0003051757812500, 0.0048522949218750, 0.0009155273437500, 0.0030517578125000, +0.0015563964843750, 0.0018005371093750, 0.0030212402343750, 0.0028686523437500, +0.0022583007812500, 0.0021667480468750, 0.0022583007812500, 0.0025939941406250, +0.0024414062500000, 0.0035705566406250, 0.0024719238281250, 0.0031738281250000, +0.0024719238281250, 0.0033569335937500, 0.0029296875000000, 0.0037536621093750, +0.0026855468750000, 0.0035095214843750, 0.0030517578125000, 0.0031738281250000, +0.0036315917968750, 0.0035705566406250, 0.0032653808593750, 0.0034790039062500, +0.0042419433593750, 0.0033569335937500, 0.0043029785156250, 0.0038757324218750, +0.0043029785156250, 0.0042114257812500, 0.0047912597656250, 0.0040283203125000, +0.0046997070312500, 0.0046997070312500, 0.0048217773437500, 0.0047302246093750, +0.0047302246093750, 0.0046081542968750, 0.0048828125000000, 0.0047912597656250, +0.0050964355468750, 0.0046997070312500, 0.0048828125000000, 0.0049133300781250, +0.0052185058593750, 0.0046691894531250, 0.0053710937500000, 0.0049133300781250, +0.0050659179687500, 0.0052795410156250, 0.0051269531250000, 0.0049133300781250, +0.0054321289062500, 0.0054626464843750, 0.0042724609375000, 0.0055847167968750, +0.0045166015625000, 0.0052795410156250, 0.0042724609375000, 0.0054321289062500, +0.0032348632812500, 0.0055236816406250, 0.0036315917968750, 0.0047607421875000, +0.0033569335937500, 0.0050354003906250, 0.0029296875000000, 0.0045471191406250, +0.0034179687500000, 0.0037231445312500, 0.0037231445312500, 0.0041809082031250, +0.0032348632812500, 0.0031433105468750, 0.0040283203125000, 0.0031127929687500, +0.0039367675781250, 0.0029602050781250, 0.0039062500000000, 0.0023803710937500, +0.0042724609375000, 0.0027160644531250, 0.0039978027343750, 0.0020446777343750, +0.0042114257812500, 0.0020751953125000, 0.0042724609375000, 0.0020141601562500, +0.0041198730468750, 0.0016479492187500, 0.0041503906250000, 0.0018615722656250, +0.0042114257812500, 0.0012817382812500, 0.0037231445312500, 0.0013732910156250, +0.0038452148437500, 0.0012817382812500, 0.0036010742187500, 0.0007934570312500, +0.0030822753906250, 0.0010375976562500, 0.0032958984375000, 0.0008850097656250, +0.0028686523437500, 0.0006713867187500, 0.0028686523437500, 0.0011291503906250, +0.0029296875000000, 0.0012512207031250, 0.0028381347656250, 0.0009460449218750, +0.0029602050781250, 0.0022583007812500, 0.0028686523437500, 0.0018005371093750, +0.0028991699218750, 0.0024108886718750, 0.0029296875000000, 0.0036315917968750, +0.0028686523437500, 0.0027770996093750, 0.0028686523437500, 0.0043334960937500, +0.0028381347656250, 0.0045166015625000, 0.0028686523437500, 0.0040893554687500, +0.0027160644531250, 0.0046081542968750, 0.0026245117187500, 0.0047607421875000, +0.0027465820312500, 0.0035400390625000, 0.0023193359375000, 0.0040283203125000, +0.0023803710937500, 0.0034484863281250, 0.0022583007812500, 0.0022583007812500, +0.0019226074218750, 0.0029602050781250, 0.0020141601562500, 0.0015563964843750, +0.0017700195312500, 0.0015563964843750, 0.0016784667968750, 0.0014648437500000, +0.0017700195312500, 0.0006408691406250, 0.0017395019531250, 0.0008850097656250, +0.0017089843750000, 0.0007019042968750, 0.0018310546875000, 0.0003356933593750, +0.0019226074218750, 0.0005187988281250, 0.0019836425781250, 0.0007324218750000, +0.0021057128906250, 0.0005187988281250, 0.0021972656250000, 0.0007324218750000, +0.0021362304687500, 0.0008239746093750, 0.0022583007812500, 0.0006103515625000, +0.0022583007812500, 0.0005798339843750, 0.0021362304687500, 0.0007324218750000, +0.0022277832031250, 0.0003356933593750, 0.0020141601562500, 0.0003967285156250, +0.0020751953125000, 0.0004577636718750, 0.0019226074218750, 0.0002746582031250, +0.0016784667968750, 0.0004272460937500, 0.0018005371093750, 0.0005798339843750, +0.0013732910156250, 0.0004577636718750, 0.0014038085937500, 0.0008544921875000, +0.0013122558593750, 0.0011291503906250, 0.0010681152343750, 0.0009765625000000, +0.0011596679687500, 0.0020141601562500, 0.0010681152343750, 0.0018310546875000, +0.0010070800781250, 0.0024108886718750, 0.0010681152343750, 0.0032958984375000, +0.0010375976562500, 0.0027160644531250, 0.0008850097656250, 0.0043029785156250, +0.0010375976562500, 0.0039672851562500, 0.0009155273437500, 0.0044250488281250, +0.0007629394531250, 0.0056152343750000, 0.0008239746093750, 0.0049133300781250, +0.0008239746093750, 0.0062561035156250, 0.0006103515625000, 0.0061950683593750, +0.0006103515625000, 0.0062866210937500, 0.0006408691406250, 0.0071716308593750, +0.0005187988281250, 0.0066833496093750, 0.0004577636718750, 0.0070190429687500, +0.0008239746093750, 0.0072326660156250, 0.0006408691406250, 0.0068664550781250, +0.0008850097656250, 0.0067443847656250, 0.0012512207031250, 0.0068664550781250, +0.0010375976562500, 0.0059509277343750, 0.0015258789062500, 0.0061950683593750, +0.0016174316406250, 0.0057373046875000, 0.0015563964843750, 0.0049133300781250, +0.0017395019531250, 0.0054016113281250, 0.0018310546875000, 0.0043334960937500, +0.0015563964843750, 0.0044860839843750, 0.0017395019531250, 0.0043945312500000, +0.0016479492187500, 0.0037841796875000, 0.0013122558593750, 0.0041809082031250, +0.0015563964843750, 0.0039672851562500, 0.0013732910156250, 0.0039367675781250, +0.0012512207031250, 0.0041503906250000, 0.0013732910156250, 0.0042114257812500, +0.0014038085937500, 0.0042724609375000, 0.0014648437500000, 0.0045471191406250, +0.0016784667968750, 0.0046081542968750, 0.0016479492187500, 0.0048217773437500, +0.0018310546875000, 0.0051269531250000, 0.0021057128906250, 0.0050659179687500, +0.0019836425781250, 0.0056152343750000, 0.0024108886718750, 0.0054626464843750, +0.0025024414062500, 0.0057983398437500, 0.0024719238281250, 0.0062561035156250, +0.0027465820312500, 0.0059814453125000, 0.0028076171875000, 0.0066833496093750, +0.0027465820312500, 0.0066833496093750, 0.0028381347656250, 0.0066833496093750, +0.0028381347656250, 0.0070495605468750, 0.0028381347656250, 0.0069580078125000, +0.0028991699218750, 0.0068359375000000, 0.0027770996093750, 0.0069580078125000, +0.0028991699218750, 0.0067138671875000, 0.0027770996093750, 0.0063781738281250, +0.0026245117187500, 0.0065307617187500, 0.0028686523437500, 0.0061645507812500, +0.0023193359375000, 0.0059814453125000, 0.0025024414062500, 0.0061645507812500, +0.0024414062500000, 0.0060424804687500, 0.0019531250000000, 0.0058288574218750, +0.0022583007812500, 0.0063476562500000, 0.0022888183593750, 0.0061340332031250, +0.0021972656250000, 0.0061035156250000, 0.0025939941406250, 0.0064697265625000, +0.0029907226562500, 0.0061645507812500, 0.0027465820312500, 0.0061035156250000, +0.0034790039062500, 0.0061645507812500, 0.0036010742187500, 0.0057983398437500, +0.0035400390625000, 0.0054626464843750, 0.0038757324218750, 0.0055236816406250, +0.0039367675781250, 0.0049438476562500, 0.0035400390625000, 0.0050048828125000, +0.0038757324218750, 0.0049133300781250, 0.0037536621093750, 0.0046691894531250, +0.0033874511718750, 0.0049743652343750, 0.0035705566406250, 0.0048217773437500, +0.0032958984375000, 0.0048828125000000, 0.0033264160156250, 0.0050048828125000, +0.0032958984375000, 0.0050354003906250, 0.0032348632812500, 0.0051879882812500, +0.0032958984375000, 0.0050659179687500, 0.0029907226562500, 0.0053405761718750, +0.0032653808593750, 0.0051269531250000, 0.0032653808593750, 0.0048217773437500, +0.0029296875000000, 0.0048217773437500, 0.0032043457031250, 0.0035095214843750, +0.0033569335937500, 0.0040588378906250, 0.0030822753906250, 0.0037536621093750, +0.0035705566406250, 0.0026855468750000, 0.0040283203125000, 0.0033874511718750, +0.0035400390625000}, +{0.0003356933593750, 0.0036621093750000, 0.0006713867187500, 0.0035095214843750, +0.0005798339843750, 0.0035705566406250, 0.0005493164062500, 0.0037841796875000, +0.0008239746093750, 0.0038452148437500, 0.0010375976562500, 0.0039367675781250, +0.0009765625000000, 0.0044250488281250, 0.0012207031250000, 0.0044250488281250, +0.0014038085937500, 0.0046691894531250, 0.0013427734375000, 0.0050964355468750, +0.0013732910156250, 0.0049743652343750, 0.0014953613281250, 0.0053100585937500, +0.0012512207031250, 0.0054016113281250, 0.0013732910156250, 0.0051574707031250, +0.0013122558593750, 0.0050964355468750, 0.0010986328125000, 0.0050659179687500, +0.0012817382812500, 0.0043945312500000, 0.0012207031250000, 0.0044860839843750, +0.0012207031250000, 0.0040588378906250, 0.0014038085937500, 0.0032958984375000, +0.0015258789062500, 0.0035400390625000, 0.0014038085937500, 0.0028686523437500, +0.0019836425781250, 0.0026855468750000, 0.0018310546875000, 0.0027465820312500, +0.0019531250000000, 0.0025634765625000, 0.0024108886718750, 0.0025634765625000, +0.0020751953125000, 0.0030822753906250, 0.0027465820312500, 0.0029907226562500, +0.0026550292968750, 0.0033264160156250, 0.0026855468750000, 0.0039062500000000, +0.0031127929687500, 0.0036621093750000, 0.0029602050781250, 0.0044555664062500, +0.0030822753906250, 0.0044860839843750, 0.0032348632812500, 0.0046386718750000, +0.0031738281250000, 0.0050964355468750, 0.0032348632812500, 0.0048522949218750, +0.0033264160156250, 0.0051574707031250, 0.0032653808593750, 0.0051269531250000, +0.0033264160156250, 0.0051574707031250, 0.0032348632812500, 0.0052795410156250, +0.0031738281250000, 0.0051269531250000, 0.0032958984375000, 0.0052795410156250, +0.0029296875000000, 0.0052795410156250, 0.0030212402343750, 0.0051879882812500, +0.0029602050781250, 0.0051879882812500, 0.0025939941406250, 0.0052185058593750, +0.0027160644531250, 0.0050354003906250, 0.0027160644531250, 0.0051269531250000, +0.0025024414062500, 0.0050659179687500, 0.0027160644531250, 0.0049133300781250, +0.0029296875000000, 0.0049133300781250, 0.0027160644531250, 0.0049743652343750, +0.0034179687500000, 0.0047912597656250, 0.0033264160156250, 0.0050964355468750, +0.0033874511718750, 0.0053405761718750, 0.0038452148437500, 0.0050048828125000, +0.0036010742187500, 0.0058593750000000, 0.0036010742187500, 0.0057373046875000, +0.0037841796875000, 0.0057373046875000, 0.0035400390625000, 0.0062255859375000, +0.0033874511718750, 0.0059814453125000, 0.0035705566406250, 0.0056762695312500, +0.0032043457031250, 0.0058898925781250, 0.0031738281250000, 0.0053710937500000, +0.0032043457031250, 0.0047912597656250, 0.0030212402343750, 0.0051879882812500, +0.0030822753906250, 0.0042114257812500, 0.0029907226562500, 0.0041809082031250, +0.0028991699218750, 0.0041198730468750, 0.0030212402343750, 0.0036315917968750, +0.0030822753906250, 0.0039367675781250, 0.0030517578125000, 0.0037536621093750, +0.0033874511718750, 0.0037231445312500, 0.0032348632812500, 0.0039367675781250, +0.0035705566406250, 0.0039978027343750, 0.0040893554687500, 0.0041809082031250, +0.0039672851562500, 0.0048828125000000, 0.0047302246093750, 0.0045776367187500, +0.0044555664062500, 0.0046081542968750, 0.0044860839843750, 0.0050964355468750, +0.0050659179687500, 0.0047912597656250, 0.0048217773437500, 0.0046997070312500, +0.0049743652343750, 0.0049438476562500, 0.0048828125000000, 0.0045471191406250, +0.0046386718750000, 0.0040588378906250, 0.0046081542968750, 0.0043029785156250, +0.0045471191406250, 0.0037231445312500, 0.0039672851562500, 0.0034179687500000, +0.0039672851562500, 0.0035095214843750, 0.0036315917968750, 0.0033264160156250, +0.0030212402343750, 0.0031433105468750, 0.0031433105468750, 0.0036621093750000, +0.0028076171875000, 0.0034179687500000, 0.0026245117187500, 0.0036315917968750, +0.0026245117187500, 0.0040588378906250, 0.0025329589843750, 0.0036621093750000, +0.0022888183593750, 0.0042724609375000, 0.0023193359375000, 0.0042114257812500, +0.0023193359375000, 0.0040893554687500, 0.0020446777343750, 0.0044250488281250, +0.0017089843750000, 0.0043334960937500, 0.0018005371093750, 0.0039367675781250, +0.0013732910156250, 0.0041503906250000, 0.0012207031250000, 0.0038757324218750, +0.0013427734375000, 0.0033874511718750, 0.0012207031250000, 0.0035705566406250, +0.0012207031250000, 0.0034790039062500, 0.0018920898437500, 0.0032348632812500, +0.0017395019531250, 0.0036315917968750, 0.0022888183593750, 0.0039062500000000, +0.0031127929687500, 0.0036621093750000, 0.0027465820312500, 0.0043945312500000, +0.0036926269531250, 0.0043334960937500, 0.0037841796875000, 0.0045471191406250, +0.0038452148437500, 0.0051879882812500, 0.0043640136718750, 0.0048522949218750, +0.0041809082031250, 0.0051574707031250, 0.0045166015625000, 0.0052795410156250, +0.0046081542968750, 0.0050354003906250, 0.0047302246093750, 0.0050659179687500, +0.0049743652343750, 0.0050964355468750, 0.0049743652343750, 0.0045471191406250, +0.0051269531250000, 0.0046997070312500, 0.0053405761718750, 0.0045471191406250, +0.0051879882812500, 0.0041198730468750, 0.0051269531250000, 0.0044555664062500, +0.0052795410156250, 0.0039978027343750, 0.0045166015625000, 0.0040893554687500, +0.0046386718750000, 0.0041503906250000, 0.0044555664062500, 0.0039978027343750, +0.0037231445312500, 0.0041809082031250, 0.0040283203125000, 0.0041503906250000, +0.0040893554687500, 0.0043640136718750, 0.0039062500000000, 0.0042114257812500, +0.0040893554687500, 0.0042114257812500, 0.0043640136718750, 0.0045776367187500, +0.0043334960937500, 0.0036010742187500, 0.0042114257812500, 0.0042114257812500, +0.0044860839843750, 0.0037841796875000, 0.0041809082031250, 0.0028686523437500, +0.0037841796875000, 0.0037536621093750, 0.0040588378906250, 0.0022583007812500, +0.0032958984375000, 0.0025939941406250, 0.0032653808593750, 0.0025329589843750, +0.0032958984375000, 0.0015869140625000, 0.0028991699218750, 0.0021972656250000, +0.0029907226562500, 0.0016784667968750, 0.0030822753906250, 0.0017395019531250, +0.0029602050781250, 0.0019226074218750, 0.0031127929687500, 0.0017700195312500, +0.0033874511718750, 0.0018920898437500, 0.0032958984375000, 0.0020751953125000, +0.0033569335937500, 0.0020751953125000, 0.0035705566406250, 0.0020751953125000, +0.0033264160156250, 0.0021972656250000, 0.0031433105468750, 0.0021057128906250, +0.0033264160156250, 0.0020141601562500, 0.0027465820312500, 0.0020141601562500, +0.0028381347656250, 0.0019226074218750, 0.0028076171875000, 0.0016479492187500, +0.0025024414062500, 0.0016479492187500, 0.0027160644531250, 0.0016479492187500, +0.0028076171875000, 0.0014343261718750, 0.0027160644531250, 0.0015563964843750, +0.0031738281250000, 0.0016479492187500, 0.0035705566406250, 0.0014038085937500, +0.0035095214843750, 0.0019836425781250, 0.0044555664062500, 0.0017700195312500, +0.0044555664062500, 0.0018920898437500, 0.0048217773437500, 0.0024719238281250, +0.0055541992187500, 0.0020446777343750, 0.0052795410156250, 0.0025329589843750, +0.0058898925781250, 0.0025329589843750, 0.0060424804687500, 0.0024108886718750, +0.0058898925781250, 0.0025024414062500, 0.0060119628906250, 0.0024719238281250, +0.0060729980468750, 0.0021667480468750, 0.0056457519531250, 0.0021667480468750, +0.0057678222656250, 0.0021057128906250, 0.0055541992187500, 0.0019531250000000, +0.0051269531250000, 0.0020446777343750, 0.0052795410156250, 0.0021667480468750, +0.0047607421875000, 0.0020751953125000, 0.0047302246093750, 0.0021972656250000, +0.0046081542968750, 0.0024719238281250, 0.0043334960937500, 0.0023803710937500, +0.0044555664062500, 0.0026550292968750, 0.0040588378906250, 0.0026855468750000, +0.0040588378906250, 0.0026855468750000, 0.0038146972656250, 0.0027770996093750, +0.0034179687500000, 0.0027465820312500, 0.0036315917968750, 0.0026245117187500, +0.0030822753906250, 0.0026245117187500, 0.0031433105468750, 0.0025634765625000, +0.0029907226562500, 0.0023803710937500, 0.0025329589843750, 0.0024108886718750, +0.0027465820312500, 0.0023498535156250, 0.0022888183593750, 0.0022583007812500, +0.0022583007812500, 0.0023498535156250, 0.0022888183593750, 0.0024108886718750, +0.0018920898437500, 0.0022888183593750, 0.0019836425781250, 0.0024414062500000, +0.0021972656250000, 0.0023803710937500, 0.0019836425781250, 0.0024414062500000, +0.0023498535156250, 0.0025634765625000, 0.0027465820312500, 0.0023498535156250, +0.0024719238281250, 0.0026245117187500, 0.0035400390625000, 0.0025024414062500, +0.0033874511718750, 0.0027160644531250, 0.0038146972656250, 0.0029907226562500, +0.0046997070312500, 0.0027770996093750, 0.0043640136718750, 0.0033264160156250, +0.0052490234375000, 0.0032653808593750, 0.0054931640625000, 0.0032958984375000, +0.0054321289062500, 0.0037231445312500, 0.0057983398437500, 0.0036010742187500, +0.0059814453125000, 0.0035705566406250, 0.0053405761718750, 0.0037231445312500, +0.0057678222656250, 0.0035095214843750, 0.0054016113281250, 0.0032348632812500, +0.0045471191406250, 0.0034484863281250, 0.0050964355468750, 0.0029296875000000, +0.0039672851562500, 0.0028381347656250, 0.0038757324218750, 0.0028686523437500, +0.0038146972656250, 0.0025329589843750, 0.0032653808593750, 0.0025024414062500, +0.0035095214843750, 0.0031127929687500, 0.0033264160156250, 0.0026855468750000, +0.0033264160156250, 0.0031738281250000, 0.0033264160156250, 0.0039672851562500, +0.0032653808593750, 0.0032958984375000, 0.0032653808593750, 0.0046081542968750, +0.0031127929687500, 0.0044860839843750, 0.0031127929687500, 0.0045166015625000, +0.0030212402343750, 0.0051879882812500, 0.0028076171875000, 0.0048522949218750, +0.0028381347656250, 0.0049438476562500, 0.0028076171875000, 0.0051879882812500, +0.0026550292968750, 0.0048522949218750, 0.0028076171875000, 0.0046997070312500, +0.0029907226562500, 0.0050354003906250, 0.0028381347656250, 0.0038452148437500, +0.0029602050781250, 0.0041503906250000, 0.0030822753906250, 0.0036315917968750, +0.0029907226562500, 0.0024108886718750, 0.0029602050781250, 0.0029602050781250, +0.0030822753906250, 0.0020446777343750, 0.0031127929687500, 0.0016784667968750, +0.0028686523437500, 0.0021362304687500, 0.0033569335937500, 0.0019836425781250, +0.0037841796875000, 0.0016784667968750, 0.0034484863281250, 0.0030822753906250, +0.0043334960937500, 0.0027160644531250, 0.0044860839843750, 0.0027465820312500, +0.0042724609375000, 0.0042114257812500, 0.0045166015625000, 0.0042114257812500, +0.0026855468750000, 0.0043640136718750, 0.0043945312500000, 0.0040893554687500, +0.0042724609375000, 0.0044250488281250, 0.0040893554687500, 0.0048522949218750, +0.0045166015625000, 0.0045776367187500, 0.0046081542968750, 0.0048828125000000, +0.0039062500000000, 0.0049743652343750, 0.0040588378906250, 0.0046997070312500, +0.0039978027343750, 0.0046081542968750, 0.0034790039062500, 0.0046691894531250, +0.0036926269531250, 0.0041809082031250, 0.0035400390625000, 0.0042114257812500, +0.0034179687500000, 0.0039978027343750, 0.0035095214843750, 0.0036010742187500, +0.0034790039062500, 0.0039062500000000, 0.0033874511718750, 0.0031433105468750, +0.0035400390625000, 0.0033264160156250, 0.0035095214843750, 0.0029907226562500, +0.0036010742187500, 0.0022277832031250, 0.0038146972656250, 0.0026245117187500, +0.0037231445312500, 0.0020141601562500, 0.0038452148437500, 0.0015258789062500, +0.0039672851562500}, +{0.0048522949218750, 0.0023193359375000, 0.0049133300781250, 0.0024108886718750, +0.0048522949218750, 0.0024108886718750, 0.0051269531250000, 0.0022277832031250, +0.0051269531250000, 0.0026855468750000, 0.0047912597656250, 0.0024108886718750, +0.0050354003906250, 0.0026550292968750, 0.0047607421875000, 0.0031738281250000, +0.0043640136718750, 0.0027770996093750, 0.0046997070312500, 0.0033569335937500, +0.0042114257812500, 0.0032958984375000, 0.0041809082031250, 0.0032043457031250, +0.0042724609375000, 0.0035095214843750, 0.0040893554687500, 0.0033264160156250, +0.0042114257812500, 0.0032043457031250, 0.0047607421875000, 0.0033569335937500, +0.0044555664062500, 0.0030517578125000, 0.0050659179687500, 0.0028076171875000, +0.0057983398437500, 0.0031127929687500, 0.0053405761718750, 0.0026245117187500, +0.0068054199218750, 0.0026855468750000, 0.0067749023437500, 0.0029602050781250, +0.0070190429687500, 0.0027160644531250, 0.0079956054687500, 0.0027160644531250, +0.0075988769531250, 0.0034179687500000, 0.0078125000000000, 0.0030822753906250, +0.0080261230468750, 0.0035095214843750, 0.0075683593750000, 0.0043029785156250, +0.0073242187500000, 0.0037231445312500, 0.0074768066406250, 0.0047607421875000, +0.0066528320312500, 0.0047912597656250, 0.0065917968750000, 0.0047302246093750, +0.0063781738281250, 0.0051879882812500, 0.0058288574218750, 0.0049743652343750, +0.0060119628906250, 0.0048522949218750, 0.0055236816406250, 0.0049743652343750, +0.0055847167968750, 0.0045166015625000, 0.0053100585937500, 0.0041809082031250, +0.0049743652343750, 0.0044860839843750, 0.0051879882812500, 0.0032958984375000, +0.0041809082031250, 0.0036010742187500, 0.0044555664062500, 0.0032958984375000, +0.0039672851562500, 0.0024108886718750, 0.0030212402343750, 0.0028991699218750, +0.0036315917968750, 0.0023193359375000, 0.0026855468750000, 0.0019531250000000, +0.0025939941406250, 0.0024108886718750, 0.0026245117187500, 0.0025024414062500, +0.0022583007812500, 0.0021362304687500, 0.0023498535156250, 0.0034179687500000, +0.0022888183593750, 0.0031433105468750, 0.0023498535156250, 0.0033569335937500, +0.0022583007812500, 0.0044250488281250, 0.0019836425781250, 0.0039672851562500, +0.0021362304687500, 0.0042419433593750, 0.0022277832031250, 0.0044250488281250, +0.0019531250000000, 0.0042114257812500, 0.0024719238281250, 0.0041198730468750, +0.0035705566406250, 0.0043945312500000, 0.0021057128906250, 0.0043640136718750, +0.0023498535156250, 0.0046997070312500, 0.0017395019531250, 0.0042419433593750, +0.0026245117187500, 0.0037841796875000, 0.0035095214843750, 0.0041503906250000, +0.0028686523437500, 0.0032958984375000, 0.0041198730468750, 0.0031738281250000, +0.0042114257812500, 0.0031738281250000, 0.0038757324218750, 0.0028076171875000, +0.0042724609375000, 0.0027160644531250, 0.0043029785156250, 0.0028076171875000, +0.0036315917968750, 0.0026855468750000, 0.0038452148437500, 0.0026550292968750, +0.0035400390625000, 0.0026855468750000, 0.0028991699218750, 0.0025634765625000, +0.0032348632812500, 0.0027160644531250, 0.0025939941406250, 0.0024108886718750, +0.0024719238281250, 0.0027465820312500, 0.0025329589843750, 0.0029907226562500, +0.0021362304687500, 0.0024108886718750, 0.0021362304687500, 0.0036010742187500, +0.0024719238281250, 0.0034484863281250, 0.0022583007812500, 0.0032958984375000, +0.0025634765625000, 0.0039062500000000, 0.0030822753906250, 0.0036315917968750, +0.0028076171875000, 0.0035705566406250, 0.0034484863281250, 0.0034790039062500, +0.0036010742187500, 0.0035400390625000, 0.0033874511718750, 0.0035095214843750, +0.0035095214843750, 0.0031738281250000, 0.0036621093750000, 0.0038757324218750, +0.0033264160156250, 0.0035400390625000, 0.0033264160156250, 0.0039062500000000, +0.0036315917968750, 0.0045776367187500, 0.0036621093750000, 0.0039978027343750, +0.0035705566406250, 0.0055236816406250, 0.0040588378906250, 0.0052795410156250, +0.0041503906250000, 0.0057067871093750, 0.0040588378906250, 0.0068054199218750, +0.0042419433593750, 0.0061340332031250, 0.0043029785156250, 0.0075378417968750, +0.0039367675781250, 0.0073852539062500, 0.0040893554687500, 0.0073547363281250, +0.0039062500000000, 0.0080871582031250, 0.0036621093750000, 0.0077209472656250, +0.0038757324218750, 0.0076293945312500, 0.0033264160156250, 0.0078735351562500, +0.0035095214843750, 0.0075073242187500, 0.0033874511718750, 0.0070190429687500, +0.0029907226562500, 0.0073852539062500, 0.0032958984375000, 0.0065307617187500, +0.0029602050781250, 0.0064697265625000, 0.0030822753906250, 0.0064697265625000, +0.0032043457031250, 0.0060424804687500, 0.0031433105468750, 0.0061645507812500, +0.0032958984375000, 0.0058288574218750, 0.0032958984375000, 0.0058593750000000, +0.0034179687500000, 0.0058288574218750, 0.0033874511718750, 0.0057373046875000, +0.0033874511718750, 0.0059204101562500, 0.0034484863281250, 0.0053710937500000, +0.0034790039062500, 0.0056457519531250, 0.0034179687500000, 0.0054931640625000, +0.0034484863281250, 0.0049133300781250, 0.0035705566406250, 0.0053405761718750, +0.0034484863281250, 0.0052795410156250, 0.0034179687500000, 0.0050048828125000, +0.0034790039062500, 0.0056457519531250, 0.0033569335937500, 0.0061950683593750, +0.0032653808593750, 0.0057983398437500, 0.0033569335937500, 0.0071716308593750, +0.0032653808593750, 0.0071105957031250, 0.0032348632812500, 0.0073852539062500, +0.0032653808593750, 0.0083312988281250, 0.0032653808593750, 0.0080261230468750, +0.0031738281250000, 0.0084533691406250, 0.0032958984375000, 0.0088806152343750, +0.0032958984375000, 0.0084838867187500, 0.0032653808593750, 0.0084228515625000, +0.0033569335937500, 0.0088806152343750, 0.0033264160156250, 0.0075683593750000, +0.0031127929687500, 0.0080261230468750, 0.0032348632812500, 0.0077514648437500, +0.0030212402343750, 0.0066528320312500, 0.0028076171875000, 0.0072631835937500, +0.0030212402343750, 0.0066528320312500, 0.0025939941406250, 0.0065002441406250, +0.0025634765625000, 0.0066528320312500, 0.0025329589843750, 0.0064086914062500, +0.0021972656250000, 0.0064086914062500, 0.0022888183593750, 0.0065307617187500, +0.0021057128906250, 0.0064697265625000, 0.0020446777343750, 0.0064086914062500, +0.0019836425781250, 0.0064086914062500, 0.0018920898437500, 0.0062866210937500, +0.0019531250000000, 0.0061645507812500, 0.0021362304687500, 0.0062866210937500, +0.0020141601562500, 0.0060119628906250, 0.0021362304687500, 0.0057678222656250, +0.0023193359375000, 0.0059814453125000, 0.0022583007812500, 0.0052795410156250, +0.0023498535156250, 0.0054931640625000, 0.0024719238281250, 0.0052185058593750, +0.0022888183593750, 0.0047607421875000, 0.0022277832031250, 0.0052490234375000, +0.0023803710937500, 0.0042419433593750, 0.0018005371093750, 0.0045471191406250, +0.0019226074218750, 0.0042724609375000, 0.0018615722656250, 0.0035400390625000, +0.0014953613281250, 0.0041503906250000, 0.0016479492187500, 0.0028381347656250, +0.0015563964843750, 0.0031127929687500, 0.0014648437500000, 0.0027160644531250, +0.0016174316406250, 0.0016174316406250, 0.0015258789062500, 0.0022583007812500, +0.0014038085937500, 0.0010681152343750, 0.0017700195312500, 0.0010070800781250, +0.0015869140625000, 0.0010070800781250, 0.0017395019531250, 0.0003967285156250, +0.0020751953125000, 0.0006713867187500, 0.0017700195312500, 0.0007934570312500, +0.0024108886718750, 0.0007019042968750, 0.0022583007812500, 0.0010375976562500, +0.0023193359375000, 0.0014953613281250, 0.0027465820312500, 0.0014343261718750, +0.0025024414062500, 0.0019836425781250, 0.0028686523437500, 0.0021667480468750, +0.0028381347656250, 0.0020751953125000, 0.0028076171875000, 0.0022888183593750, +0.0029602050781250, 0.0024414062500000, 0.0028076171875000, 0.0018920898437500, +0.0029602050781250, 0.0021362304687500, 0.0029296875000000, 0.0017395019531250, +0.0028076171875000, 0.0010986328125000, 0.0029296875000000, 0.0015869140625000, +0.0029602050781250, 0.0005187988281250, 0.0026855468750000, 0.0007019042968750, +0.0028381347656250, 0.0005798339843750, 0.0026855468750000, -0.0000610351562500, +0.0024108886718750, 0.0003356933593750, 0.0025939941406250, -0.0000305175781250, +0.0025634765625000, -0.0000915527343750, 0.0023193359375000, 0.0001525878906250, +0.0026550292968750, 0.0001220703125000, 0.0028991699218750, 0.0002136230468750, +0.0026245117187500, 0.0009765625000000, 0.0034179687500000, 0.0008544921875000, +0.0033569335937500, 0.0014343261718750, 0.0034179687500000, 0.0022583007812500, +0.0039062500000000, 0.0018920898437500, 0.0037841796875000, 0.0031127929687500, +0.0038452148437500, 0.0032043457031250, 0.0040283203125000, 0.0033264160156250, +0.0037841796875000, 0.0039367675781250, 0.0036010742187500, 0.0038452148437500, +0.0038146972656250, 0.0041503906250000, 0.0032653808593750, 0.0041198730468750, +0.0033264160156250, 0.0041503906250000, 0.0032043457031250, 0.0042419433593750, +0.0028076171875000, 0.0040893554687500, 0.0031738281250000, 0.0043029785156250, +0.0028991699218750, 0.0043029785156250, 0.0028381347656250, 0.0042114257812500, +0.0030212402343750, 0.0042419433593750, 0.0029907226562500, 0.0041198730468750, +0.0029296875000000, 0.0039062500000000, 0.0033264160156250, 0.0039367675781250, +0.0032653808593750, 0.0039367675781250, 0.0034484863281250, 0.0037536621093750, +0.0038146972656250, 0.0036926269531250, 0.0036010742187500, 0.0039062500000000, +0.0041198730468750, 0.0036621093750000, 0.0042114257812500, 0.0038452148437500, +0.0041198730468750, 0.0041198730468750, 0.0042419433593750, 0.0038146972656250, +0.0040893554687500, 0.0042419433593750, 0.0039367675781250, 0.0041809082031250, +0.0039062500000000, 0.0041503906250000, 0.0037536621093750, 0.0046081542968750, +0.0035400390625000, 0.0048217773437500, 0.0032958984375000, 0.0046081542968750, +0.0031433105468750, 0.0047912597656250, 0.0031738281250000, 0.0045471191406250, +0.0029602050781250, 0.0042724609375000, 0.0026245117187500, 0.0046691894531250, +0.0025634765625000, 0.0036010742187500, 0.0022888183593750, 0.0036315917968750, +0.0019531250000000, 0.0035400390625000, 0.0021362304687500, 0.0029296875000000, +0.0021362304687500, 0.0031433105468750, 0.0018310546875000, 0.0031433105468750, +0.0025329589843750, 0.0028991699218750, 0.0021667480468750, 0.0032348632812500, +0.0024108886718750, 0.0036315917968750, 0.0030517578125000, 0.0032958984375000, +0.0025329589843750, 0.0040893554687500, 0.0036926269531250, 0.0041198730468750, +0.0034179687500000, 0.0040588378906250, 0.0038146972656250, 0.0045166015625000, +0.0046997070312500, 0.0045471191406250, 0.0039978027343750, 0.0043640136718750, +0.0055236816406250, 0.0048217773437500, 0.0053405761718750, 0.0045166015625000, +0.0054626464843750, 0.0041198730468750, 0.0063476562500000, 0.0047912597656250, +0.0059204101562500, 0.0036010742187500, 0.0062561035156250, 0.0039062500000000, +0.0062255859375000, 0.0039367675781250, 0.0061950683593750, 0.0033264160156250, +0.0063476562500000, 0.0038146972656250, 0.0061340332031250, 0.0033874511718750, +0.0061340332031250, 0.0035400390625000, 0.0060424804687500, 0.0035095214843750, +0.0059814453125000, 0.0032653808593750, 0.0060119628906250, 0.0035705566406250, +0.0059509277343750, 0.0029602050781250, 0.0056457519531250, 0.0032348632812500, +0.0057678222656250, 0.0029907226562500, 0.0055541992187500, 0.0024108886718750, +0.0051879882812500}, +{0.0024719238281250, 0.0028076171875000, 0.0026855468750000, 0.0030517578125000, +0.0024414062500000, 0.0023803710937500, 0.0032043457031250, 0.0024719238281250, +0.0031127929687500, 0.0023498535156250, 0.0031738281250000, 0.0018310546875000, +0.0036621093750000, 0.0019531250000000, 0.0035400390625000, 0.0014953613281250, +0.0034484863281250, 0.0013732910156250, 0.0037231445312500, 0.0012817382812500, +0.0036315917968750, 0.0009460449218750, 0.0034790039062500, 0.0009765625000000, +0.0037231445312500, 0.0009765625000000, 0.0033264160156250, 0.0008544921875000, +0.0035095214843750, 0.0010986328125000, 0.0033874511718750, 0.0014343261718750, +0.0030212402343750, 0.0012512207031250, 0.0032958984375000, 0.0018310546875000, +0.0029602050781250, 0.0019531250000000, 0.0030517578125000, 0.0018920898437500, +0.0031738281250000, 0.0020751953125000, 0.0030822753906250, 0.0020751953125000, +0.0032043457031250, 0.0021972656250000, 0.0032958984375000, 0.0020446777343750, +0.0033264160156250, 0.0024719238281250, 0.0034790039062500, 0.0028381347656250, +0.0036621093750000, 0.0026550292968750, 0.0035400390625000, 0.0034179687500000, +0.0036926269531250, 0.0035400390625000, 0.0037841796875000, 0.0036926269531250, +0.0038146972656250, 0.0041809082031250, 0.0039367675781250, 0.0042419433593750, +0.0039062500000000, 0.0042419433593750, 0.0036315917968750, 0.0044555664062500, +0.0036926269531250, 0.0042419433593750, 0.0034790039062500, 0.0039672851562500, +0.0032043457031250, 0.0042114257812500, 0.0032958984375000, 0.0039367675781250, +0.0028686523437500, 0.0039062500000000, 0.0027770996093750, 0.0038757324218750, +0.0026245117187500, 0.0037231445312500, 0.0021362304687500, 0.0038452148437500, +0.0019836425781250, 0.0040893554687500, 0.0019836425781250, 0.0039672851562500, +0.0018005371093750, 0.0041198730468750, 0.0019226074218750, 0.0044250488281250, +0.0019531250000000, 0.0042419433593750, 0.0016479492187500, 0.0046997070312500, +0.0026550292968750, 0.0048217773437500, 0.0023193359375000, 0.0047302246093750, +0.0026550292968750, 0.0047912597656250, 0.0034484863281250, 0.0048217773437500, +0.0028991699218750, 0.0042419433593750, 0.0040893554687500, 0.0044555664062500, +0.0038757324218750, 0.0041198730468750, 0.0042419433593750, 0.0035095214843750, +0.0051574707031250, 0.0038757324218750, 0.0045471191406250, 0.0032653808593750, +0.0056762695312500, 0.0032958984375000, 0.0055847167968750, 0.0033264160156250, +0.0055236816406250, 0.0031127929687500, 0.0060424804687500, 0.0032043457031250, +0.0057373046875000, 0.0034179687500000, 0.0057067871093750, 0.0033569335937500, +0.0057067871093750, 0.0036315917968750, 0.0055541992187500, 0.0039978027343750, +0.0053100585937500, 0.0038452148437500, 0.0053100585937500, 0.0042114257812500, +0.0053710937500000, 0.0043640136718750, 0.0052490234375000, 0.0041503906250000, +0.0051879882812500, 0.0041503906250000, 0.0051574707031250, 0.0043334960937500, +0.0050048828125000, 0.0036621093750000, 0.0046691894531250, 0.0039062500000000, +0.0046997070312500, 0.0038452148437500, 0.0043029785156250, 0.0033569335937500, +0.0038452148437500, 0.0035705566406250, 0.0039062500000000, 0.0034484863281250, +0.0032348632812500, 0.0033874511718750, 0.0031127929687500, 0.0034790039062500, +0.0029907226562500, 0.0035095214843750, 0.0027160644531250, 0.0035705566406250, +0.0026855468750000, 0.0032653808593750, 0.0025634765625000, 0.0035095214843750, +0.0024719238281250, 0.0032958984375000, 0.0023193359375000, 0.0028991699218750, +0.0022277832031250, 0.0032348632812500, 0.0021972656250000, 0.0027160644531250, +0.0017089843750000, 0.0027465820312500, 0.0015869140625000, 0.0028686523437500, +0.0013122558593750, 0.0026245117187500, 0.0007629394531250, 0.0026550292968750, +0.0007934570312500, 0.0029907226562500, 0.0006408691406250, 0.0028686523437500, +0.0002441406250000, 0.0030517578125000, 0.0006103515625000, 0.0033264160156250, +0.0009765625000000, 0.0031127929687500, 0.0005798339843750, 0.0035095214843750, +0.0016479492187500, 0.0036010742187500, 0.0015869140625000, 0.0035095214843750, +0.0015563964843750, 0.0036926269531250, 0.0021362304687500, 0.0036926269531250, +0.0018310546875000, 0.0035095214843750, 0.0016174316406250, 0.0036010742187500, +0.0016784667968750, 0.0036315917968750, 0.0014343261718750, 0.0034179687500000, +0.0011291503906250, 0.0034790039062500, 0.0011901855468750, 0.0036315917968750, +0.0011901855468750, 0.0034484863281250, 0.0010070800781250, 0.0036315917968750, +0.0013122558593750, 0.0037841796875000, 0.0015869140625000, 0.0035705566406250, +0.0013732910156250, 0.0039367675781250, 0.0021362304687500, 0.0038146972656250, +0.0021362304687500, 0.0037841796875000, 0.0020751953125000, 0.0038757324218750, +0.0025329589843750, 0.0037231445312500, 0.0024414062500000, 0.0038452148437500, +0.0021667480468750, 0.0038757324218750, 0.0022583007812500, 0.0036926269531250, +0.0021667480468750, 0.0036621093750000, 0.0018005371093750, 0.0038146972656250, +0.0019531250000000, 0.0032043457031250, 0.0020141601562500, 0.0035705566406250, +0.0017700195312500, 0.0032348632812500, 0.0021667480468750, 0.0025634765625000, +0.0026245117187500, 0.0031433105468750, 0.0023803710937500, 0.0023193359375000, +0.0034484863281250, 0.0024108886718750, 0.0033569335937500, 0.0025024414062500, +0.0037536621093750, 0.0020446777343750, 0.0046997070312500, 0.0023193359375000, +0.0043334960937500, 0.0023803710937500, 0.0052185058593750, 0.0022888183593750, +0.0053405761718750, 0.0024719238281250, 0.0052185058593750, 0.0027465820312500, +0.0055236816406250, 0.0026550292968750, 0.0054931640625000, 0.0029296875000000, +0.0047607421875000, 0.0030212402343750, 0.0051574707031250, 0.0029602050781250, +0.0043945312500000, 0.0029907226562500, 0.0033874511718750, 0.0029907226562500, +0.0041198730468750, 0.0028686523437500, 0.0019836425781250, 0.0028076171875000, +0.0022583007812500, 0.0028076171875000, 0.0017700195312500, 0.0027465820312500, +0.0001831054687500, 0.0026550292968750, 0.0009155273437500, 0.0027160644531250, +-0.0003967285156250, 0.0025939941406250, -0.0006408691406250, 0.0025329589843750, +-0.0004577636718750, 0.0025634765625000, -0.0010070800781250, 0.0024414062500000, +-0.0009155273437500, 0.0025024414062500, -0.0002441406250000, 0.0024414062500000, +-0.0006103515625000, 0.0025024414062500, 0.0001525878906250, 0.0025329589843750, +0.0011291503906250, 0.0024108886718750, 0.0005187988281250, 0.0028686523437500, +0.0023498535156250, 0.0026855468750000, 0.0023498535156250, 0.0028686523437500, +0.0027465820312500, 0.0032958984375000, 0.0039978027343750, 0.0029296875000000, +0.0035400390625000, 0.0035400390625000, 0.0043334960937500, 0.0035095214843750, +0.0045471191406250, 0.0034179687500000, 0.0043640136718750, 0.0036621093750000, +0.0044250488281250, 0.0036010742187500, 0.0045166015625000, 0.0032043457031250, +0.0042114257812500, 0.0034179687500000, 0.0042419433593750, 0.0031433105468750, +0.0041503906250000, 0.0027465820312500, 0.0039978027343750, 0.0029296875000000, +0.0041198730468750, 0.0025634765625000, 0.0037536621093750, 0.0024719238281250, +0.0037841796875000, 0.0026245117187500, 0.0037841796875000, 0.0024719238281250, +0.0036621093750000, 0.0024108886718750, 0.0037231445312500, 0.0028686523437500, +0.0036621093750000, 0.0026245117187500, 0.0037536621093750, 0.0029296875000000, +0.0035705566406250, 0.0034790039062500, 0.0035400390625000, 0.0030822753906250, +0.0036621093750000, 0.0038146972656250, 0.0031127929687500, 0.0038452148437500, +0.0033569335937500, 0.0037536621093750, 0.0030212402343750, 0.0041198730468750, +0.0023498535156250, 0.0040588378906250, 0.0028076171875000, 0.0037231445312500, +0.0018920898437500, 0.0039367675781250, 0.0018005371093750, 0.0036621093750000, +0.0018920898437500, 0.0033264160156250, 0.0015869140625000, 0.0037231445312500, +0.0017089843750000, 0.0030517578125000, 0.0019531250000000, 0.0032043457031250, +0.0019226074218750, 0.0031433105468750, 0.0020751953125000, 0.0026855468750000, +0.0022583007812500, 0.0028991699218750, 0.0022277832031250, 0.0027770996093750, +0.0023803710937500, 0.0027465820312500, 0.0025024414062500, 0.0030822753906250, +0.0022888183593750, 0.0032653808593750, 0.0021362304687500, 0.0030517578125000, +0.0023498535156250, 0.0038452148437500, 0.0020141601562500, 0.0038146972656250, +0.0018920898437500, 0.0039062500000000, 0.0022888183593750, 0.0043640136718750, +0.0022888183593750, 0.0041198730468750, 0.0021667480468750, 0.0043945312500000, +0.0036621093750000, 0.0043945312500000, 0.0033874511718750, 0.0043334960937500, +0.0040893554687500, 0.0044555664062500, 0.0056457519531250, 0.0043640136718750, +0.0049438476562500, 0.0046691894531250, 0.0058593750000000, 0.0045166015625000, +0.0063476562500000, 0.0044555664062500, 0.0058288574218750, 0.0045776367187500, +0.0057373046875000, 0.0043640136718750, 0.0061340332031250, 0.0039672851562500, +0.0050354003906250, 0.0041198730468750, 0.0053710937500000, 0.0038146972656250, +0.0050354003906250, 0.0029602050781250, 0.0034484863281250, 0.0025329589843750, +0.0050659179687500, 0.0032043457031250, 0.0052795410156250, 0.0027465820312500, +0.0056152343750000, 0.0029296875000000, 0.0050048828125000, 0.0033874511718750, +0.0046081542968750, 0.0030822753906250, 0.0050964355468750, 0.0034179687500000, +0.0033874511718750, 0.0033874511718750, 0.0038757324218750, 0.0033569335937500, +0.0032348632812500, 0.0036010742187500, 0.0016784667968750, 0.0035095214843750, +0.0025634765625000, 0.0037231445312500, 0.0012207031250000, 0.0036315917968750, +0.0008239746093750, 0.0036621093750000, 0.0014343261718750, 0.0036315917968750, +0.0011901855468750, 0.0034179687500000, 0.0008850097656250, 0.0039367675781250, +0.0025939941406250, 0.0034790039062500, 0.0020141601562500, 0.0037841796875000, +0.0026550292968750, 0.0043334960937500, 0.0042114257812500, 0.0037841796875000, +0.0032653808593750, 0.0051879882812500, 0.0046081542968750, 0.0049438476562500, +0.0048522949218750, 0.0052795410156250, 0.0044860839843750, 0.0064392089843750, +0.0048828125000000, 0.0059204101562500, 0.0049743652343750, 0.0065612792968750, +0.0039062500000000, 0.0067749023437500, 0.0043334960937500, 0.0065612792968750, +0.0039978027343750, 0.0066528320312500, 0.0029602050781250, 0.0067749023437500, +0.0035095214843750, 0.0061035156250000, 0.0030212402343750, 0.0063476562500000, +0.0026855468750000, 0.0058288574218750, 0.0030212402343750, 0.0050659179687500, +0.0032348632812500, 0.0055541992187500, 0.0030212402343750, 0.0039062500000000, +0.0033874511718750, 0.0042419433593750, 0.0035095214843750, 0.0035705566406250, +0.0033569335937500, 0.0022277832031250, 0.0034484863281250, 0.0029907226562500, +0.0036010742187500, 0.0013732910156250, 0.0032653808593750, 0.0013427734375000, +0.0032348632812500, 0.0012512207031250, 0.0033874511718750, 0.0003967285156250, +0.0031738281250000, 0.0007629394531250, 0.0031127929687500, 0.0003967285156250, +0.0034790039062500, 0.0001220703125000, 0.0033264160156250, 0.0003662109375000, +0.0034790039062500, 0.0003662109375000, 0.0038146972656250, 0.0000610351562500, +0.0035095214843750, 0.0007019042968750, 0.0039978027343750, 0.0003967285156250, +0.0039367675781250, 0.0007934570312500, 0.0039367675781250, 0.0014648437500000, +0.0042419433593750, 0.0008850097656250, 0.0040893554687500, 0.0022277832031250, +0.0041198730468750}, +{0.0042114257812500, 0.0039062500000000, 0.0041809082031250, 0.0039367675781250, +0.0042114257812500, 0.0039672851562500, 0.0040893554687500, 0.0042114257812500, +0.0040283203125000, 0.0040283203125000, 0.0041809082031250, 0.0042114257812500, +0.0036010742187500, 0.0040588378906250, 0.0039367675781250, 0.0041198730468750, +0.0033874511718750, 0.0042114257812500, 0.0025939941406250, 0.0039367675781250, +0.0032043457031250, 0.0043334960937500, 0.0015869140625000, 0.0043334960937500, +0.0016174316406250, 0.0042419433593750, 0.0015869140625000, 0.0045776367187500, +0.0005493164062500, 0.0046081542968750, 0.0008544921875000, 0.0039062500000000, +0.0016174316406250, 0.0042114257812500, 0.0010986328125000, 0.0037841796875000, +0.0019531250000000, 0.0029296875000000, 0.0031738281250000, 0.0034484863281250, +0.0024108886718750, 0.0026855468750000, 0.0042419433593750, 0.0025024414062500, +0.0042114257812500, 0.0027160644531250, 0.0042724609375000, 0.0027160644531250, +0.0058593750000000, 0.0035400390625000, 0.0014648437500000, 0.0037841796875000, +0.0032958984375000, 0.0036315917968750, 0.0026855468750000, 0.0036315917968750, +0.0032348632812500, 0.0036926269531250, 0.0040893554687500, 0.0036010742187500, +0.0036926269531250, 0.0038757324218750, 0.0046081542968750, 0.0037231445312500, +0.0045471191406250, 0.0037231445312500, 0.0045776367187500, 0.0038146972656250, +0.0052795410156250, 0.0036315917968750, 0.0050048828125000, 0.0040283203125000, +0.0044250488281250, 0.0036010742187500, 0.0050048828125000, 0.0039672851562500, +0.0040588378906250, 0.0045471191406250, 0.0028381347656250, 0.0037841796875000, +0.0037231445312500, 0.0052185058593750, 0.0017395019531250, 0.0050659179687500, +0.0014953613281250, 0.0050964355468750, 0.0018920898437500, 0.0060729980468750, +0.0011901855468750, 0.0057067871093750, 0.0010986328125000, 0.0057373046875000, +0.0024414062500000, 0.0061035156250000, 0.0017700195312500, 0.0056762695312500, +0.0025024414062500, 0.0053100585937500, 0.0039062500000000, 0.0057067871093750, +0.0029602050781250, 0.0046386718750000, 0.0046386718750000, 0.0049133300781250, +0.0046081542968750, 0.0044860839843750, 0.0043640136718750, 0.0036926269531250, +0.0051574707031250, 0.0043029785156250, 0.0049133300781250, 0.0027770996093750, +0.0043334960937500, 0.0030517578125000, 0.0046386718750000, 0.0027465820312500, +0.0041198730468750, 0.0016174316406250, 0.0033569335937500, 0.0022888183593750, +0.0037536621093750, 0.0013732910156250, 0.0030822753906250, 0.0011901855468750, +0.0029296875000000, 0.0014343261718750, 0.0032043457031250, 0.0011901855468750, +0.0031738281250000, 0.0010681152343750, 0.0030822753906250, 0.0016784667968750, +0.0034790039062500, 0.0014953613281250, 0.0035705566406250, 0.0018005371093750, +0.0035400390625000, 0.0022888183593750, 0.0037231445312500, 0.0019226074218750, +0.0036926269531250, 0.0029907226562500, 0.0035400390625000, 0.0027770996093750, +0.0036621093750000, 0.0031127929687500, 0.0036010742187500, 0.0039062500000000, +0.0034790039062500, 0.0033569335937500, 0.0036621093750000, 0.0043640136718750, +0.0035705566406250, 0.0043640136718750, 0.0036010742187500, 0.0041198730468750, +0.0036315917968750, 0.0045166015625000, 0.0036621093750000, 0.0044555664062500, +0.0037231445312500, 0.0035095214843750, 0.0038146972656250, 0.0039062500000000, +0.0038757324218750, 0.0031738281250000, 0.0038757324218750, 0.0020141601562500, +0.0039367675781250, 0.0026855468750000, 0.0039978027343750, 0.0013427734375000, +0.0038757324218750, 0.0009460449218750, 0.0039062500000000, 0.0014343261718750, +0.0038452148437500, 0.0010375976562500, 0.0037536621093750, 0.0007629394531250, +0.0037841796875000, 0.0025024414062500, 0.0036010742187500, 0.0018310546875000, +0.0036315917968750, 0.0026245117187500, 0.0035095214843750, 0.0043029785156250, +0.0032958984375000, 0.0032958984375000, 0.0033264160156250, 0.0049438476562500, +0.0029907226562500, 0.0052185058593750, 0.0030212402343750, 0.0048828125000000, +0.0029296875000000, 0.0056152343750000, 0.0026855468750000, 0.0056457519531250, +0.0027770996093750, 0.0045166015625000, 0.0026550292968750, 0.0052490234375000, +0.0026245117187500, 0.0043640136718750, 0.0026855468750000, 0.0030212402343750, +0.0026855468750000, 0.0041503906250000, 0.0026550292968750, 0.0015869140625000, +0.0027465820312500, 0.0018615722656250, 0.0027160644531250, 0.0015563964843750, +0.0027160644531250, -0.0000305175781250, 0.0028686523437500, 0.0007324218750000, +0.0027465820312500, -0.0003662109375000, 0.0028686523437500, -0.0004882812500000, +0.0028381347656250, -0.0004272460937500, 0.0028381347656250, -0.0010070800781250, +0.0028381347656250, -0.0009765625000000, 0.0027770996093750, -0.0008544921875000, +0.0027465820312500, -0.0012207031250000, 0.0027160644531250, -0.0009460449218750, +0.0027770996093750, -0.0005798339843750, 0.0028991699218750, -0.0010070800781250, +0.0028991699218750, -0.0003356933593750, 0.0029602050781250, -0.0004272460937500, +0.0029602050781250, -0.0003356933593750, 0.0030212402343750, 0.0000610351562500, +0.0030212402343750, -0.0001525878906250, 0.0029296875000000, 0.0003662109375000, +0.0030822753906250, 0.0003356933593750, 0.0029602050781250, 0.0005798339843750, +0.0029907226562500, 0.0010375976562500, 0.0030822753906250, 0.0009765625000000, +0.0028991699218750, 0.0017089843750000, 0.0031433105468750, 0.0017700195312500, +0.0029602050781250, 0.0019836425781250, 0.0030822753906250, 0.0025634765625000, +0.0032653808593750, 0.0025329589843750, 0.0028991699218750, 0.0028686523437500, +0.0032043457031250, 0.0032043457031250, 0.0031738281250000, 0.0030517578125000, +0.0030822753906250, 0.0030822753906250, 0.0032348632812500, 0.0034484863281250, +0.0030517578125000, 0.0026245117187500, 0.0031738281250000, 0.0029602050781250, +0.0031738281250000, 0.0026245117187500, 0.0030822753906250, 0.0017395019531250, +0.0030822753906250, 0.0022583007812500, 0.0030822753906250, 0.0012512207031250, +0.0028991699218750, 0.0011291503906250, 0.0029296875000000, 0.0010986328125000, +0.0027465820312500, 0.0006103515625000, 0.0025939941406250, 0.0006713867187500, +0.0028076171875000, 0.0007019042968750, 0.0024719238281250, 0.0004577636718750, +0.0024414062500000, 0.0005187988281250, 0.0026245117187500, 0.0006408691406250, +0.0025939941406250, 0.0002746582031250, 0.0026245117187500, 0.0007934570312500, +0.0031127929687500, 0.0005187988281250, 0.0030212402343750, 0.0006713867187500, +0.0031738281250000, 0.0010070800781250, 0.0035705566406250, 0.0005493164062500, +0.0035095214843750, 0.0016784667968750, 0.0036315917968750, 0.0011596679687500, +0.0037536621093750, 0.0016479492187500, 0.0036621093750000, 0.0026245117187500, +0.0036315917968750, 0.0017089843750000, 0.0036315917968750, 0.0032653808593750, +0.0034179687500000, 0.0030822753906250, 0.0033569335937500, 0.0030212402343750, +0.0033569335937500, 0.0039367675781250, 0.0032348632812500, 0.0033874511718750, +0.0031738281250000, 0.0033874511718750, 0.0032043457031250, 0.0036315917968750, +0.0031433105468750, 0.0031738281250000, 0.0031738281250000, 0.0028686523437500, +0.0031738281250000, 0.0030822753906250, 0.0029907226562500, 0.0026550292968750, +0.0033264160156250, 0.0025634765625000, 0.0032043457031250, 0.0026550292968750, +0.0032958984375000, 0.0025634765625000, 0.0036926269531250, 0.0026550292968750, +0.0035095214843750, 0.0028381347656250, 0.0037841796875000, 0.0028076171875000, +0.0039062500000000, 0.0031127929687500, 0.0038452148437500, 0.0033569335937500, +0.0039062500000000, 0.0033264160156250, 0.0039672851562500, 0.0039672851562500, +0.0036926269531250, 0.0040283203125000, 0.0038757324218750, 0.0041198730468750, +0.0036315917968750, 0.0044555664062500, 0.0032653808593750, 0.0043640136718750, +0.0035705566406250, 0.0043334960937500, 0.0028686523437500, 0.0043640136718750, +0.0029907226562500, 0.0041198730468750, 0.0027770996093750, 0.0039367675781250, +0.0021972656250000, 0.0040283203125000, 0.0024719238281250, 0.0030822753906250, +0.0020446777343750, 0.0031127929687500, 0.0018310546875000, 0.0026245117187500, +0.0021057128906250, 0.0018005371093750, 0.0021057128906250, 0.0022277832031250, +0.0018920898437500, 0.0012207031250000, 0.0028381347656250, 0.0011901855468750, +0.0026245117187500, 0.0012817382812500, 0.0029296875000000, 0.0007019042968750, +0.0039062500000000, 0.0009155273437500, 0.0038146972656250, 0.0016174316406250, +0.0045166015625000, 0.0010986328125000, 0.0043029785156250, 0.0015869140625000, +0.0044250488281250, 0.0023803710937500, 0.0048522949218750, 0.0016479492187500, +0.0045166015625000, 0.0028381347656250, 0.0047912597656250, 0.0026855468750000, +0.0048522949218750, 0.0025939941406250, 0.0045471191406250, 0.0033264160156250, +0.0046386718750000, 0.0030212402343750, 0.0047607421875000, 0.0028686523437500, +0.0040588378906250, 0.0029296875000000, 0.0042419433593750, 0.0029907226562500, +0.0040588378906250, 0.0028381347656250, 0.0034790039062500, 0.0028381347656250, +0.0038146972656250, 0.0033264160156250, 0.0033569335937500, 0.0031127929687500, +0.0035705566406250, 0.0034790039062500, 0.0033264160156250, 0.0040283203125000, +0.0029296875000000, 0.0037231445312500, 0.0033569335937500, 0.0044860839843750, +0.0023803710937500, 0.0045166015625000, 0.0027465820312500, 0.0043945312500000, +0.0023498535156250, 0.0046081542968750, 0.0014038085937500, 0.0046386718750000, +0.0021362304687500, 0.0042724609375000, 0.0010986328125000, 0.0043945312500000, +0.0010375976562500, 0.0043029785156250, 0.0013427734375000, 0.0039978027343750, +0.0011291503906250, 0.0041809082031250, 0.0012207031250000, 0.0040893554687500, +0.0016174316406250, 0.0039367675781250, 0.0016784667968750, 0.0040893554687500, +0.0018005371093750, 0.0042724609375000, 0.0021057128906250, 0.0041809082031250, +0.0021057128906250, 0.0044555664062500, 0.0021057128906250, 0.0045471191406250, +0.0020751953125000, 0.0043945312500000, 0.0021972656250000, 0.0043945312500000, +0.0022277832031250, 0.0045776367187500, 0.0021667480468750, 0.0040588378906250, +0.0027465820312500, 0.0041503906250000, 0.0025634765625000, 0.0041809082031250, +0.0028686523437500, 0.0038757324218750, 0.0035400390625000, 0.0040283203125000, +0.0031738281250000, 0.0040283203125000, 0.0037231445312500, 0.0040283203125000, +0.0038452148437500, 0.0040893554687500, 0.0036926269531250, 0.0041503906250000, +0.0039062500000000, 0.0041503906250000, 0.0037841796875000, 0.0040283203125000, +0.0034790039062500, 0.0041503906250000, 0.0033264160156250, 0.0039672851562500, +0.0034484863281250, 0.0037231445312500, 0.0032958984375000, 0.0039062500000000, +0.0031127929687500, 0.0034179687500000, 0.0039367675781250, 0.0035095214843750, +0.0036926269531250, 0.0034179687500000, 0.0038757324218750, 0.0030517578125000, +0.0045471191406250, 0.0032043457031250, 0.0042419433593750, 0.0031127929687500, +0.0042724609375000, 0.0029296875000000, 0.0045471191406250, 0.0031127929687500, +0.0040893554687500, 0.0032653808593750, 0.0036315917968750, 0.0030517578125000, +0.0039062500000000, 0.0034790039062500, 0.0027770996093750, 0.0034484863281250, +0.0028991699218750, 0.0035095214843750, 0.0025634765625000, 0.0037841796875000, +0.0017089843750000, 0.0036621093750000, 0.0021057128906250, 0.0037536621093750, +0.0014953613281250, 0.0037536621093750, 0.0014953613281250, 0.0036621093750000, +0.0016174316406250}, +{0.0025024414062500, 0.0036926269531250, 0.0028686523437500, 0.0043029785156250, +0.0036621093750000, 0.0039672851562500, 0.0031738281250000, 0.0037231445312500, +0.0039062500000000, 0.0040283203125000, 0.0039978027343750, 0.0034484863281250, +0.0038757324218750, 0.0025024414062500, 0.0040893554687500, 0.0021362304687500, +0.0040893554687500, 0.0007324218750000, 0.0038757324218750, 0.0011596679687500, +0.0039978027343750, 0.0010986328125000, 0.0039062500000000, 0.0000915527343750, +0.0036926269531250, 0.0004272460937500, 0.0038452148437500, 0.0007019042968750, +0.0035400390625000, 0.0000610351562500, 0.0035705566406250, 0.0007934570312500, +0.0035400390625000, 0.0016479492187500, 0.0033264160156250, 0.0007324218750000, +0.0033569335937500, 0.0024719238281250, 0.0031433105468750, 0.0025024414062500, +0.0033264160156250, 0.0025024414062500, 0.0031433105468750, 0.0034484863281250, +0.0030212402343750, 0.0032043457031250, 0.0032348632812500, 0.0032653808593750, +0.0023498535156250, 0.0033874511718750, 0.0025634765625000, 0.0032653808593750, +0.0024719238281250, 0.0030822753906250, 0.0017700195312500, 0.0031127929687500, +0.0021667480468750, 0.0031433105468750, 0.0021057128906250, 0.0030212402343750, +0.0018310546875000, 0.0032348632812500, 0.0024414062500000, 0.0035400390625000, +0.0027770996093750, 0.0033874511718750, 0.0024108886718750, 0.0038452148437500, +0.0036315917968750, 0.0038452148437500, 0.0036621093750000, 0.0039367675781250, +0.0036621093750000, 0.0042114257812500, 0.0043640136718750, 0.0041198730468750, +0.0041503906250000, 0.0041198730468750, 0.0041809082031250, 0.0042724609375000, +0.0043334960937500, 0.0040283203125000, 0.0042419433593750, 0.0038146972656250, +0.0040283203125000, 0.0039672851562500, 0.0040893554687500, 0.0036315917968750, +0.0043029785156250, 0.0035705566406250, 0.0040893554687500, 0.0036010742187500, +0.0042419433593750, 0.0034790039062500, 0.0044860839843750, 0.0034484863281250, +0.0043029785156250, 0.0035095214843750, 0.0043640136718750, 0.0035095214843750, +0.0045471191406250, 0.0034179687500000, 0.0041503906250000, 0.0033569335937500, +0.0038757324218750, 0.0033874511718750, 0.0041503906250000, 0.0031433105468750, +0.0034790039062500, 0.0032348632812500, 0.0034484863281250, 0.0031738281250000, +0.0035705566406250, 0.0029907226562500, 0.0033264160156250, 0.0029907226562500, +0.0032348632812500, 0.0030212402343750, 0.0038146972656250, 0.0028381347656250, +0.0035705566406250, 0.0029602050781250, 0.0037536621093750, 0.0031127929687500, +0.0043945312500000, 0.0028381347656250, 0.0039978027343750, 0.0031738281250000, +0.0039978027343750, 0.0031433105468750, 0.0041503906250000, 0.0030212402343750, +0.0036315917968750, 0.0031738281250000, 0.0031738281250000, 0.0030822753906250, +0.0034484863281250, 0.0029602050781250, 0.0025634765625000, 0.0029907226562500, +0.0025329589843750, 0.0028686523437500, 0.0025329589843750, 0.0027160644531250, +0.0021667480468750, 0.0028686523437500, 0.0022888183593750, 0.0026550292968750, +0.0023193359375000, 0.0025634765625000, 0.0022888183593750, 0.0026550292968750, +0.0022888183593750, 0.0027160644531250, 0.0024414062500000, 0.0026245117187500, +0.0024414062500000, 0.0028686523437500, 0.0023193359375000, 0.0028686523437500, +0.0025024414062500, 0.0028076171875000, 0.0023803710937500, 0.0028991699218750, +0.0021057128906250, 0.0028991699218750, 0.0023193359375000, 0.0026855468750000, +0.0020751953125000, 0.0027465820312500, 0.0020141601562500, 0.0026245117187500, +0.0021667480468750, 0.0024414062500000, 0.0021667480468750, 0.0025939941406250, +0.0020751953125000, 0.0023803710937500, 0.0024719238281250, 0.0024719238281250, +0.0022888183593750, 0.0024108886718750, 0.0023803710937500, 0.0023193359375000, +0.0026855468750000, 0.0025329589843750, 0.0025024414062500, 0.0023193359375000, +0.0027465820312500, 0.0024719238281250, 0.0027770996093750, 0.0024414062500000, +0.0027160644531250, 0.0023498535156250, 0.0027465820312500, 0.0026245117187500, +0.0027770996093750, 0.0025024414062500, 0.0025329589843750, 0.0026550292968750, +0.0026245117187500, 0.0027160644531250, 0.0024719238281250, 0.0027160644531250, +0.0021972656250000, 0.0028686523437500, 0.0023498535156250, 0.0027160644531250, +0.0019836425781250, 0.0029296875000000, 0.0019836425781250, 0.0029296875000000, +0.0020141601562500, 0.0027770996093750, 0.0018310546875000, 0.0030517578125000, +0.0019531250000000, 0.0027770996093750, 0.0021057128906250, 0.0029602050781250, +0.0020141601562500, 0.0029907226562500, 0.0021972656250000, 0.0028381347656250, +0.0025024414062500, 0.0031433105468750, 0.0023193359375000, 0.0029602050781250, +0.0027160644531250, 0.0031433105468750, 0.0027160644531250, 0.0032348632812500, +0.0028076171875000, 0.0031433105468750, 0.0030822753906250, 0.0034179687500000, +0.0030822753906250, 0.0030822753906250, 0.0032653808593750, 0.0032348632812500, +0.0033569335937500, 0.0032043457031250, 0.0034790039062500, 0.0028686523437500, +0.0036315917968750, 0.0031127929687500, 0.0036621093750000, 0.0028076171875000, +0.0039672851562500, 0.0028076171875000, 0.0040588378906250, 0.0028686523437500, +0.0041198730468750, 0.0027160644531250, 0.0043640136718750, 0.0027770996093750, +0.0044555664062500, 0.0028381347656250, 0.0042724609375000, 0.0028686523437500, +0.0045776367187500, 0.0030212402343750, 0.0043029785156250, 0.0031738281250000, +0.0039062500000000, 0.0031738281250000, 0.0042419433593750, 0.0034179687500000, +0.0034179687500000, 0.0035095214843750, 0.0035400390625000, 0.0034790039062500, +0.0033264160156250, 0.0036315917968750, 0.0026855468750000, 0.0036621093750000, +0.0029907226562500, 0.0033874511718750, 0.0026245117187500, 0.0034790039062500, +0.0024108886718750, 0.0033569335937500, 0.0027770996093750, 0.0030822753906250, +0.0028686523437500, 0.0032653808593750, 0.0026855468750000, 0.0031127929687500, +0.0037841796875000, 0.0029907226562500, 0.0035705566406250, 0.0031433105468750, +0.0039062500000000, 0.0032348632812500, 0.0048217773437500, 0.0030822753906250, +0.0044250488281250, 0.0034179687500000, 0.0050964355468750, 0.0033569335937500, +0.0052185058593750, 0.0033569335937500, 0.0051269531250000, 0.0035400390625000, +0.0054321289062500, 0.0034484863281250, 0.0053710937500000, 0.0035095214843750, +0.0053100585937500, 0.0035095214843750, 0.0052185058593750, 0.0035095214843750, +0.0052185058593750, 0.0034484863281250, 0.0052490234375000, 0.0034484863281250, +0.0051269531250000, 0.0035705566406250, 0.0050659179687500, 0.0034790039062500, +0.0051879882812500, 0.0035705566406250, 0.0048828125000000, 0.0037841796875000, +0.0046386718750000, 0.0036621093750000, 0.0048828125000000, 0.0039978027343750, +0.0042724609375000, 0.0040588378906250, 0.0043334960937500, 0.0037536621093750, +0.0042114257812500, 0.0037536621093750, 0.0038757324218750, 0.0037536621093750, +0.0040893554687500, 0.0028991699218750, 0.0035705566406250, 0.0030517578125000, +0.0035705566406250, 0.0027770996093750, 0.0035705566406250, 0.0020446777343750, +0.0032653808593750, 0.0023803710937500, 0.0033569335937500, 0.0021362304687500, +0.0036315917968750, 0.0018615722656250, 0.0033264160156250, 0.0022277832031250, +0.0038452148437500, 0.0024108886718750, 0.0044250488281250, 0.0021057128906250, +0.0038757324218750, 0.0030212402343750, 0.0050048828125000, 0.0029602050781250, +0.0050964355468750, 0.0029602050781250, 0.0047302246093750, 0.0035095214843750, +0.0050964355468750, 0.0033874511718750, 0.0050048828125000, 0.0033874511718750, +0.0039062500000000, 0.0035095214843750, 0.0042724609375000, 0.0034179687500000, +0.0037841796875000, 0.0032958984375000, 0.0019226074218750, 0.0032653808593750, +0.0041809082031250, 0.0043029785156250, 0.0032653808593750, 0.0037536621093750, +0.0036926269531250, 0.0042114257812500, 0.0033264160156250, 0.0048828125000000, +0.0026550292968750, 0.0044555664062500, 0.0028686523437500, 0.0050659179687500, +0.0023193359375000, 0.0050354003906250, 0.0025024414062500, 0.0049438476562500, +0.0021972656250000, 0.0052185058593750, 0.0017089843750000, 0.0050354003906250, +0.0021667480468750, 0.0049133300781250, 0.0012512207031250, 0.0049743652343750, +0.0011596679687500, 0.0046997070312500, 0.0015258789062500, 0.0044250488281250, +0.0010681152343750, 0.0046691894531250, 0.0009460449218750, 0.0042114257812500, +0.0026245117187500, 0.0043029785156250, 0.0018920898437500, 0.0041809082031250, +0.0026550292968750, 0.0039367675781250, 0.0043945312500000, 0.0040893554687500, +0.0033264160156250, 0.0033874511718750, 0.0047607421875000, 0.0037536621093750, +0.0049743652343750, 0.0034484863281250, 0.0043945312500000, 0.0027770996093750, +0.0047912597656250, 0.0033264160156250, 0.0049133300781250, 0.0027160644531250, +0.0034484863281250, 0.0027465820312500, 0.0039672851562500, 0.0030822753906250, +0.0032348632812500, 0.0030212402343750, 0.0016784667968750, 0.0031127929687500, +0.0025329589843750, 0.0036315917968750, 0.0010986328125000, 0.0036010742187500, +0.0008544921875000, 0.0038452148437500, 0.0012817382812500, 0.0042724609375000, +0.0009460449218750, 0.0041809082031250, 0.0009460449218750, 0.0045471191406250, +0.0021667480468750, 0.0047302246093750, 0.0018920898437500, 0.0047302246093750, +0.0023498535156250, 0.0048828125000000, 0.0034484863281250, 0.0049438476562500, +0.0030517578125000, 0.0046997070312500, 0.0034179687500000, 0.0048828125000000, +0.0037536621093750, 0.0045776367187500, 0.0034484863281250, 0.0042114257812500, +0.0032043457031250, 0.0045166015625000, 0.0034179687500000, 0.0036010742187500, +0.0030822753906250, 0.0037841796875000, 0.0029296875000000, 0.0036010742187500, +0.0030212402343750, 0.0028991699218750, 0.0028991699218750, 0.0033264160156250, +0.0026550292968750, 0.0032043457031250, 0.0029602050781250, 0.0028381347656250, +0.0028381347656250, 0.0034179687500000, 0.0028076171875000, 0.0039672851562500, +0.0029602050781250, 0.0036010742187500, 0.0027160644531250, 0.0048828125000000, +0.0030212402343750, 0.0047912597656250, 0.0028686523437500, 0.0049133300781250, +0.0027465820312500, 0.0059204101562500, 0.0029296875000000, 0.0057373046875000, +0.0027770996093750, 0.0052185058593750, 0.0027465820312500, 0.0059204101562500, +0.0026855468750000, 0.0051574707031250, 0.0026855468750000, 0.0040283203125000, +0.0027160644531250, 0.0049743652343750, 0.0026245117187500, 0.0030212402343750, +0.0026855468750000, 0.0030517578125000, 0.0026245117187500, 0.0030517578125000, +0.0025634765625000, 0.0019226074218750, 0.0025939941406250, 0.0022888183593750, +0.0025634765625000, 0.0022888183593750, 0.0026245117187500, 0.0019226074218750, +0.0024414062500000, 0.0024414062500000, 0.0025634765625000, 0.0028381347656250, +0.0026855468750000, 0.0024108886718750, 0.0024414062500000, 0.0034484863281250, +0.0027160644531250, 0.0033874511718750, 0.0026855468750000, 0.0033874511718750, +0.0026550292968750, 0.0039672851562500, 0.0028686523437500, 0.0038452148437500, +0.0027770996093750, 0.0036315917968750, 0.0027160644531250, 0.0038452148437500, +0.0028381347656250, 0.0037231445312500, 0.0028076171875000, 0.0033569335937500, +0.0027465820312500, 0.0035095214843750, 0.0028991699218750, 0.0033874511718750, +0.0027465820312500, 0.0032958984375000, 0.0028381347656250, 0.0032958984375000, +0.0028991699218750, 0.0033569335937500, 0.0027465820312500, 0.0033874511718750, +0.0028381347656250}, +{0.0028686523437500, 0.0040893554687500, 0.0029907226562500, 0.0039672851562500, +0.0026550292968750, 0.0040283203125000, 0.0028381347656250, 0.0038757324218750, +0.0023498535156250, 0.0037536621093750, 0.0019836425781250, 0.0039978027343750, +0.0025024414062500, 0.0034484863281250, 0.0010986328125000, 0.0037231445312500, +0.0012512207031250, 0.0035400390625000, 0.0013122558593750, 0.0029296875000000, +0.0004272460937500, 0.0034179687500000, 0.0007324218750000, 0.0032348632812500, +0.0013122558593750, 0.0029907226562500, 0.0007629394531250, 0.0035095214843750, +0.0016479492187500, 0.0039062500000000, 0.0027160644531250, 0.0037231445312500, +0.0019531250000000, 0.0046081542968750, 0.0038146972656250, 0.0046691894531250, +0.0039978027343750, 0.0047912597656250, 0.0038146972656250, 0.0053100585937500, +0.0047912597656250, 0.0052795410156250, 0.0047607421875000, 0.0053100585937500, +0.0039062500000000, 0.0055541992187500, 0.0045471191406250, 0.0053405761718750, +0.0037231445312500, 0.0052795410156250, 0.0024414062500000, 0.0055236816406250, +0.0034179687500000, 0.0046691894531250, 0.0014953613281250, 0.0050354003906250, +0.0013427734375000, 0.0045166015625000, 0.0017089843750000, 0.0036621093750000, +0.0008544921875000, 0.0043945312500000, 0.0008850097656250, 0.0027770996093750, +0.0018920898437500, 0.0028991699218750, 0.0013427734375000, 0.0028991699218750, +0.0018615722656250, 0.0019836425781250, 0.0029907226562500, 0.0023803710937500, +0.0022277832031250, 0.0020446777343750, 0.0032348632812500, 0.0019531250000000, +0.0033264160156250, 0.0022277832031250, 0.0031738281250000, 0.0023498535156250, +0.0033569335937500, 0.0023193359375000, 0.0032653808593750, 0.0028381347656250, +0.0031127929687500, 0.0031127929687500, 0.0031127929687500, 0.0028991699218750, +0.0030212402343750, 0.0030212402343750, 0.0028686523437500, 0.0033264160156250, +0.0028991699218750, 0.0023498535156250, 0.0028686523437500, 0.0028991699218750, +0.0026855468750000, 0.0022888183593750, 0.0028686523437500, 0.0011901855468750, +0.0029602050781250, 0.0021362304687500, 0.0027160644531250, 0.0004882812500000, +0.0031433105468750, 0.0006103515625000, 0.0030212402343750, 0.0007629394531250, +0.0029907226562500, -0.0000305175781250, 0.0031738281250000, 0.0003967285156250, +0.0030212402343750, 0.0005187988281250, 0.0031433105468750, 0.0004272460937500, +0.0030517578125000, 0.0007934570312500, 0.0031433105468750, 0.0012512207031250, +0.0032958984375000, 0.0011901855468750, 0.0030517578125000, 0.0015869140625000, +0.0033874511718750, 0.0018005371093750, 0.0032653808593750, 0.0017395019531250, +0.0032043457031250, 0.0018310546875000, 0.0033264160156250, 0.0020751953125000, +0.0030822753906250, 0.0015869140625000, 0.0031433105468750, 0.0018005371093750, +0.0029602050781250, 0.0017700195312500, 0.0028381347656250, 0.0013427734375000, +0.0028991699218750, 0.0016784667968750, 0.0027160644531250, 0.0017089843750000, +0.0025939941406250, 0.0014953613281250, 0.0026245117187500, 0.0018310546875000, +0.0025329589843750, 0.0021667480468750, 0.0024108886718750, 0.0019226074218750, +0.0025329589843750, 0.0025329589843750, 0.0025024414062500, 0.0025024414062500, +0.0025024414062500, 0.0025634765625000, 0.0025329589843750, 0.0028381347656250, +0.0025024414062500, 0.0026245117187500, 0.0025939941406250, 0.0030517578125000, +0.0025634765625000, 0.0028991699218750, 0.0026245117187500, 0.0030517578125000, +0.0026245117187500, 0.0034179687500000, 0.0026550292968750, 0.0031738281250000, +0.0027160644531250, 0.0035095214843750, 0.0026855468750000, 0.0034790039062500, +0.0027770996093750, 0.0033264160156250, 0.0028076171875000, 0.0034484863281250, +0.0027160644531250, 0.0034179687500000, 0.0027465820312500, 0.0031433105468750, +0.0028381347656250, 0.0032653808593750, 0.0027465820312500, 0.0030822753906250, +0.0028381347656250, 0.0028381347656250, 0.0029907226562500, 0.0030822753906250, +0.0028076171875000, 0.0027770996093750, 0.0030517578125000, 0.0028381347656250, +0.0029602050781250, 0.0028991699218750, 0.0029296875000000, 0.0027465820312500, +0.0030212402343750, 0.0028381347656250, 0.0028991699218750, 0.0027465820312500, +0.0030517578125000, 0.0027465820312500, 0.0029907226562500, 0.0027160644531250, +0.0029907226562500, 0.0025634765625000, 0.0031127929687500, 0.0024719238281250, +0.0029907226562500, 0.0024108886718750, 0.0031433105468750, 0.0022583007812500, +0.0031738281250000, 0.0022888183593750, 0.0031433105468750, 0.0021972656250000, +0.0032653808593750, 0.0019836425781250, 0.0033569335937500, 0.0024108886718750, +0.0032653808593750, 0.0021362304687500, 0.0033569335937500, 0.0024414062500000, +0.0032348632812500, 0.0029907226562500, 0.0030822753906250, 0.0026550292968750, +0.0033874511718750, 0.0036926269531250, 0.0028991699218750, 0.0035095214843750, +0.0030517578125000, 0.0036621093750000, 0.0029602050781250, 0.0045166015625000, +0.0026245117187500, 0.0041503906250000, 0.0028381347656250, 0.0043029785156250, +0.0025329589843750, 0.0046081542968750, 0.0025329589843750, 0.0039672851562500, +0.0025634765625000, 0.0036010742187500, 0.0023803710937500, 0.0039672851562500, +0.0025329589843750, 0.0024719238281250, 0.0025939941406250, 0.0026855468750000, +0.0025024414062500, 0.0024414062500000, 0.0027465820312500, 0.0014038085937500, +0.0029907226562500, 0.0019226074218750, 0.0028076171875000, 0.0014343261718750, +0.0033264160156250, 0.0013427734375000, 0.0032653808593750, 0.0014953613281250, +0.0032958984375000, 0.0014343261718750, 0.0035400390625000, 0.0014648437500000, +0.0033874511718750, 0.0012817382812500, 0.0032958984375000, 0.0013732910156250, +0.0034484863281250, 0.0011291503906250, 0.0032653808593750, 0.0008544921875000, +0.0030822753906250, 0.0010375976562500, 0.0031738281250000, 0.0006103515625000, +0.0030517578125000, 0.0005187988281250, 0.0030822753906250, 0.0007324218750000, +0.0030517578125000, 0.0006713867187500, 0.0029602050781250, 0.0006713867187500, +0.0030822753906250, 0.0011901855468750, 0.0029296875000000, 0.0011596679687500, +0.0028991699218750, 0.0014038085937500, 0.0030822753906250, 0.0018005371093750, +0.0029907226562500, 0.0017089843750000, 0.0029602050781250, 0.0021667480468750, +0.0035095214843750, 0.0021972656250000, 0.0032958984375000, 0.0024414062500000, +0.0035705566406250, 0.0028076171875000, 0.0042114257812500, 0.0026855468750000, +0.0038146972656250, 0.0034790039062500, 0.0043334960937500, 0.0033264160156250, +0.0043945312500000, 0.0037231445312500, 0.0042114257812500, 0.0045776367187500, +0.0043945312500000, 0.0044250488281250, 0.0043334960937500, 0.0049743652343750, +0.0040588378906250, 0.0052490234375000, 0.0040893554687500, 0.0050659179687500, +0.0039672851562500, 0.0050964355468750, 0.0037231445312500, 0.0052795410156250, +0.0036621093750000, 0.0048828125000000, 0.0039367675781250, 0.0049438476562500, +0.0036926269531250, 0.0049133300781250, 0.0038452148437500, 0.0045471191406250, +0.0041503906250000, 0.0043640136718750, 0.0039062500000000, 0.0043640136718750, +0.0041198730468750, 0.0042724609375000, 0.0041198730468750, 0.0043640136718750, +0.0039978027343750, 0.0044860839843750, 0.0041198730468750, 0.0043945312500000, +0.0041198730468750, 0.0043640136718750, 0.0038452148437500, 0.0046386718750000, +0.0038757324218750, 0.0045776367187500, 0.0039367675781250, 0.0044250488281250, +0.0037231445312500, 0.0046691894531250, 0.0037841796875000, 0.0040283203125000, +0.0043029785156250, 0.0041503906250000, 0.0040588378906250, 0.0036926269531250, +0.0044860839843750, 0.0028991699218750, 0.0051879882812500, 0.0032043457031250, +0.0047912597656250, 0.0023498535156250, 0.0056152343750000, 0.0021362304687500, +0.0059509277343750, 0.0022888183593750, 0.0055541992187500, 0.0020446777343750, +0.0055847167968750, 0.0019836425781250, 0.0058898925781250, 0.0025939941406250, +0.0049438476562500, 0.0023193359375000, 0.0051574707031250, 0.0025329589843750, +0.0049133300781250, 0.0030212402343750, 0.0041503906250000, 0.0026855468750000, +0.0045776367187500, 0.0032348632812500, 0.0041198730468750, 0.0032348632812500, +0.0041198730468750, 0.0030212402343750, 0.0041503906250000, 0.0031738281250000, +0.0040893554687500, 0.0030212402343750, 0.0041503906250000, 0.0026245117187500, +0.0040283203125000, 0.0025939941406250, 0.0041503906250000, 0.0025329589843750, +0.0040283203125000, 0.0021972656250000, 0.0037841796875000, 0.0021667480468750, +0.0039978027343750, 0.0023803710937500, 0.0035705566406250, 0.0021667480468750, +0.0035400390625000, 0.0023193359375000, 0.0036315917968750, 0.0026245117187500, +0.0034484863281250, 0.0024414062500000, 0.0035400390625000, 0.0025939941406250, +0.0036315917968750, 0.0027465820312500, 0.0036315917968750, 0.0024719238281250, +0.0035400390625000, 0.0022888183593750, 0.0036010742187500, 0.0025939941406250, +0.0036621093750000, 0.0019531250000000, 0.0031433105468750, 0.0020141601562500, +0.0033874511718750, 0.0020446777343750, 0.0029602050781250, 0.0016479492187500, +0.0023498535156250, 0.0017089843750000, 0.0027160644531250, 0.0018920898437500, +0.0018615722656250, 0.0017395019531250, 0.0017089843750000, 0.0018005371093750, +0.0017700195312500, 0.0018920898437500, 0.0014343261718750, 0.0017089843750000, +0.0014343261718750, 0.0018920898437500, 0.0014648437500000, 0.0017700195312500, +0.0014648437500000, 0.0018920898437500, 0.0013122558593750, 0.0019531250000000, +0.0011596679687500, 0.0016174316406250, 0.0012512207031250, 0.0021972656250000, +0.0009460449218750, 0.0017700195312500, 0.0009155273437500, 0.0019531250000000, +0.0009460449218750, 0.0024719238281250, 0.0008239746093750, 0.0017700195312500, +0.0009155273437500, 0.0026245117187500, 0.0012207031250000, 0.0024414062500000, +0.0011596679687500, 0.0022888183593750, 0.0014648437500000, 0.0027160644531250, +0.0018920898437500, 0.0023803710937500, 0.0018615722656250, 0.0024414062500000, +0.0024414062500000, 0.0024719238281250, 0.0025329589843750, 0.0024108886718750, +0.0026550292968750, 0.0023193359375000, 0.0029907226562500, 0.0024108886718750, +0.0029602050781250, 0.0023803710937500, 0.0030212402343750, 0.0024414062500000, +0.0030822753906250, 0.0024719238281250, 0.0030822753906250, 0.0025329589843750, +0.0030212402343750, 0.0025634765625000, 0.0031127929687500, 0.0025329589843750, +0.0032653808593750, 0.0026245117187500, 0.0031738281250000, 0.0026550292968750, +0.0033569335937500, 0.0026245117187500, 0.0036315917968750, 0.0026855468750000, +0.0035095214843750, 0.0025329589843750, 0.0037536621093750, 0.0026550292968750, +0.0038452148437500, 0.0026245117187500, 0.0037841796875000, 0.0025024414062500, +0.0038757324218750, 0.0026245117187500, 0.0039672851562500, 0.0025634765625000, +0.0035400390625000, 0.0026550292968750, 0.0037536621093750, 0.0027160644531250, +0.0035095214843750, 0.0027465820312500, 0.0030822753906250, 0.0029296875000000, +0.0033264160156250, 0.0029296875000000, 0.0027160644531250, 0.0030212402343750, +0.0027770996093750, 0.0030822753906250, 0.0026245117187500, 0.0030822753906250, +0.0021972656250000, 0.0031433105468750, 0.0023803710937500, 0.0032958984375000, +0.0019226074218750, 0.0032653808593750, 0.0018920898437500, 0.0033264160156250, +0.0018005371093750, 0.0034179687500000, 0.0015258789062500, 0.0032958984375000, +0.0016174316406250, 0.0035095214843750, 0.0015563964843750, 0.0034179687500000, +0.0013732910156250}, +{0.0033874511718750, 0.0023498535156250, 0.0035400390625000, 0.0027160644531250, +0.0034790039062500, 0.0030212402343750, 0.0029907226562500, 0.0025024414062500, +0.0031433105468750, 0.0031738281250000, 0.0029296875000000, 0.0031738281250000, +0.0027770996093750, 0.0028991699218750, 0.0028686523437500, 0.0031127929687500, +0.0029296875000000, 0.0031127929687500, 0.0027770996093750, 0.0026855468750000, +0.0029296875000000, 0.0027770996093750, 0.0030517578125000, 0.0028076171875000, +0.0028686523437500, 0.0025024414062500, 0.0028686523437500, 0.0026245117187500, +0.0030517578125000, 0.0028991699218750, 0.0024719238281250, 0.0026855468750000, +0.0026855468750000, 0.0029296875000000, 0.0025024414062500, 0.0034179687500000, +0.0019226074218750, 0.0031127929687500, 0.0022277832031250, 0.0034484863281250, +0.0018310546875000, 0.0037231445312500, 0.0018615722656250, 0.0034790039062500, +0.0018005371093750, 0.0034179687500000, 0.0016174316406250, 0.0036621093750000, +0.0017700195312500, 0.0030517578125000, 0.0016174316406250, 0.0031433105468750, +0.0018310546875000, 0.0030822753906250, 0.0016784667968750, 0.0026550292968750, +0.0015258789062500, 0.0028381347656250, 0.0018615722656250, 0.0025634765625000, +0.0014038085937500, 0.0025024414062500, 0.0015258789062500, 0.0024719238281250, +0.0017700195312500, 0.0023803710937500, 0.0016174316406250, 0.0023498535156250, +0.0018310546875000, 0.0022583007812500, 0.0020751953125000, 0.0021972656250000, +0.0020446777343750, 0.0022277832031250, 0.0021362304687500, 0.0021972656250000, +0.0024414062500000, 0.0021057128906250, 0.0024108886718750, 0.0022888183593750, +0.0021972656250000, 0.0021362304687500, 0.0024108886718750, 0.0022583007812500, +0.0021362304687500, 0.0023803710937500, 0.0017395019531250, 0.0021972656250000, +0.0021057128906250, 0.0025024414062500, 0.0013122558593750, 0.0025024414062500, +0.0014038085937500, 0.0024414062500000, 0.0013122558593750, 0.0025329589843750, +0.0007324218750000, 0.0025634765625000, 0.0009765625000000, 0.0024108886718750, +0.0009460449218750, 0.0025634765625000, 0.0008239746093750, 0.0025634765625000, +0.0011596679687500, 0.0024719238281250, 0.0014343261718750, 0.0025939941406250, +0.0012817382812500, 0.0027465820312500, 0.0019226074218750, 0.0027770996093750, +0.0017700195312500, 0.0029602050781250, 0.0019836425781250, 0.0031433105468750, +0.0024414062500000, 0.0031433105468750, 0.0021057128906250, 0.0033569335937500, +0.0026550292968750, 0.0034179687500000, 0.0025024414062500, 0.0034179687500000, +0.0025329589843750, 0.0034790039062500, 0.0028991699218750, 0.0034179687500000, +0.0025939941406250, 0.0032958984375000, 0.0028686523437500, 0.0032348632812500, +0.0029296875000000, 0.0032348632812500, 0.0027465820312500, 0.0031127929687500, +0.0027160644531250, 0.0030517578125000, 0.0027770996093750, 0.0030517578125000, +0.0025024414062500, 0.0029602050781250, 0.0026245117187500, 0.0029602050781250, +0.0026245117187500, 0.0030212402343750, 0.0024719238281250, 0.0029907226562500, +0.0026245117187500, 0.0031433105468750, 0.0026550292968750, 0.0030822753906250, +0.0025939941406250, 0.0031738281250000, 0.0026855468750000, 0.0032653808593750, +0.0028076171875000, 0.0030822753906250, 0.0027160644531250, 0.0033569335937500, +0.0028076171875000, 0.0032043457031250, 0.0028076171875000, 0.0032958984375000, +0.0027770996093750, 0.0034179687500000, 0.0028076171875000, 0.0032348632812500, +0.0028686523437500, 0.0034484863281250, 0.0027465820312500, 0.0034179687500000, +0.0027770996093750, 0.0033569335937500, 0.0027770996093750, 0.0034790039062500, +0.0027465820312500, 0.0033874511718750, 0.0028076171875000, 0.0033569335937500, +0.0028381347656250, 0.0033264160156250, 0.0028686523437500, 0.0032653808593750, +0.0028991699218750, 0.0031738281250000, 0.0028991699218750, 0.0032043457031250, +0.0030212402343750, 0.0031433105468750, 0.0026855468750000, 0.0031127929687500, +0.0029296875000000, 0.0031127929687500, 0.0028076171875000, 0.0031738281250000, +0.0024108886718750, 0.0031127929687500, 0.0027160644531250, 0.0029907226562500, +0.0021057128906250, 0.0031127929687500, 0.0021667480468750, 0.0030212402343750, +0.0021362304687500, 0.0028991699218750, 0.0017700195312500, 0.0029907226562500, +0.0018005371093750, 0.0028686523437500, 0.0017700195312500, 0.0028686523437500, +0.0016174316406250, 0.0029907226562500, 0.0016784667968750, 0.0029907226562500, +0.0017395019531250, 0.0030212402343750, 0.0016479492187500, 0.0031738281250000, +0.0020446777343750, 0.0033264160156250, 0.0019531250000000, 0.0032958984375000, +0.0018920898437500, 0.0034484863281250, 0.0021362304687500, 0.0036010742187500, +0.0021057128906250, 0.0033569335937500, 0.0016784667968750, 0.0036621093750000, +0.0018920898437500, 0.0034484863281250, 0.0016174316406250, 0.0030822753906250, +0.0011291503906250, 0.0035095214843750, 0.0013122558593750, 0.0027465820312500, +0.0011291503906250, 0.0028991699218750, 0.0009460449218750, 0.0029907226562500, +0.0013427734375000, 0.0025329589843750, 0.0016479492187500, 0.0027770996093750, +0.0013732910156250, 0.0032653808593750, 0.0027160644531250, 0.0030822753906250, +0.0024108886718750, 0.0033874511718750, 0.0029296875000000, 0.0039367675781250, +0.0041198730468750, 0.0036315917968750, 0.0035705566406250, 0.0039062500000000, +0.0043334960937500, 0.0041809082031250, 0.0046386718750000, 0.0039672851562500, +0.0043640136718750, 0.0038757324218750, 0.0045166015625000, 0.0041809082031250, +0.0046997070312500, 0.0037231445312500, 0.0041503906250000, 0.0036926269531250, +0.0042724609375000, 0.0038452148437500, 0.0041809082031250, 0.0036315917968750, +0.0038757324218750, 0.0035400390625000, 0.0040283203125000, 0.0040283203125000, +0.0034484863281250, 0.0038452148437500, 0.0036315917968750, 0.0039672851562500, +0.0031127929687500, 0.0043640136718750, 0.0023498535156250, 0.0041809082031250, +0.0028686523437500, 0.0044555664062500, 0.0015563964843750, 0.0045166015625000, +0.0014953613281250, 0.0044250488281250, 0.0018005371093750, 0.0044555664062500, +0.0013122558593750, 0.0044250488281250, 0.0012207031250000, 0.0045471191406250, +0.0021667480468750, 0.0045471191406250, 0.0018615722656250, 0.0045471191406250, +0.0020751953125000, 0.0046081542968750, 0.0032958984375000, 0.0039978027343750, +0.0014343261718750, 0.0038452148437500, 0.0011291503906250, 0.0038452148437500, +0.0007934570312500, 0.0037231445312500, 0.0011901855468750, 0.0036315917968750, +0.0014343261718750, 0.0036621093750000, 0.0010070800781250, 0.0034790039062500, +0.0022277832031250, 0.0035400390625000, 0.0018310546875000, 0.0037536621093750, +0.0024719238281250, 0.0037231445312500, 0.0037841796875000, 0.0037536621093750, +0.0030212402343750, 0.0045776367187500, 0.0046081542968750, 0.0044555664062500, +0.0047607421875000, 0.0049133300781250, 0.0046386718750000, 0.0057678222656250, +0.0053710937500000, 0.0054321289062500, 0.0052795410156250, 0.0061035156250000, +0.0050659179687500, 0.0064697265625000, 0.0050659179687500, 0.0060424804687500, +0.0049743652343750, 0.0061340332031250, 0.0048217773437500, 0.0066833496093750, +0.0047912597656250, 0.0050354003906250, 0.0047302246093750, 0.0057067871093750, +0.0047607421875000, 0.0052185058593750, 0.0044250488281250, 0.0038146972656250, +0.0042419433593750, 0.0047912597656250, 0.0044250488281250, 0.0029602050781250, +0.0031433105468750, 0.0032043457031250, 0.0033569335937500, 0.0028686523437500, +0.0028991699218750, 0.0015869140625000, 0.0017089843750000, 0.0023803710937500, +0.0021057128906250, 0.0011901855468750, 0.0015563964843750, 0.0010375976562500, +0.0010986328125000, 0.0013427734375000, 0.0015869140625000, 0.0008850097656250, +0.0017089843750000, 0.0008850097656250, 0.0012817382812500, 0.0018615722656250, +0.0028991699218750, 0.0014953613281250, 0.0025329589843750, 0.0019531250000000, +0.0031433105468750, 0.0029907226562500, 0.0046081542968750, 0.0023193359375000, +0.0039672851562500, 0.0031738281250000, 0.0049743652343750, 0.0034179687500000, +0.0054016113281250, 0.0030212402343750, 0.0049438476562500, 0.0030517578125000, +0.0050048828125000, 0.0031433105468750, 0.0051879882812500, 0.0024108886718750, +0.0040893554687500, 0.0026245117187500, 0.0042114257812500, 0.0023803710937500, +0.0039367675781250, 0.0017089843750000, 0.0031127929687500, 0.0019836425781250, +0.0034790039062500, 0.0019836425781250, 0.0032043457031250, 0.0016479492187500, +0.0029907226562500, 0.0020446777343750, 0.0032958984375000, 0.0024414062500000, +0.0035095214843750, 0.0021972656250000, 0.0032043457031250, 0.0031127929687500, +0.0039062500000000, 0.0029296875000000, 0.0038757324218750, 0.0031127929687500, +0.0039062500000000, 0.0037231445312500, 0.0044250488281250, 0.0033569335937500, +0.0043640136718750, 0.0040283203125000, 0.0041198730468750, 0.0039367675781250, +0.0043945312500000, 0.0039062500000000, 0.0041809082031250, 0.0042114257812500, +0.0038452148437500, 0.0039672851562500, 0.0041503906250000, 0.0039978027343750, +0.0034484863281250, 0.0040283203125000, 0.0036315917968750, 0.0038146972656250, +0.0034790039062500, 0.0036010742187500, 0.0029907226562500, 0.0035705566406250, +0.0034484863281250, 0.0032043457031250, 0.0028381347656250, 0.0031433105468750, +0.0030517578125000, 0.0028686523437500, 0.0030212402343750, 0.0025939941406250, +0.0026550292968750, 0.0027160644531250, 0.0031127929687500, 0.0019226074218750, +0.0027465820312500, 0.0020446777343750, 0.0028991699218750, 0.0017700195312500, +0.0029296875000000, 0.0012512207031250, 0.0027160644531250, 0.0014953613281250, +0.0029296875000000, 0.0008239746093750, 0.0026855468750000, 0.0007934570312500, +0.0027770996093750, 0.0008850097656250, 0.0027770996093750, 0.0005493164062500, +0.0026245117187500, 0.0005798339843750, 0.0027465820312500, 0.0008850097656250, +0.0024719238281250, 0.0006408691406250, 0.0025329589843750, 0.0008850097656250, +0.0025329589843750, 0.0012207031250000, 0.0023498535156250, 0.0008544921875000, +0.0025024414062500, 0.0015258789062500, 0.0025329589843750, 0.0013732910156250, +0.0024414062500000, 0.0015258789062500, 0.0025939941406250, 0.0020446777343750, +0.0026855468750000, 0.0017395019531250, 0.0026855468750000, 0.0023498535156250, +0.0028381347656250, 0.0023498535156250, 0.0028381347656250, 0.0024719238281250, +0.0028076171875000, 0.0029296875000000, 0.0027770996093750, 0.0028076171875000, +0.0028076171875000, 0.0030517578125000, 0.0027770996093750, 0.0031433105468750, +0.0027465820312500, 0.0031127929687500, 0.0027770996093750, 0.0032348632812500, +0.0027770996093750, 0.0032348632812500, 0.0026855468750000, 0.0030212402343750, +0.0028991699218750, 0.0030822753906250, 0.0028686523437500, 0.0028686523437500, +0.0028991699218750, 0.0026245117187500, 0.0031433105468750, 0.0027465820312500, +0.0030822753906250, 0.0022583007812500, 0.0031127929687500, 0.0023498535156250, +0.0031738281250000, 0.0021667480468750, 0.0030822753906250, 0.0018615722656250, +0.0030212402343750, 0.0020751953125000, 0.0031433105468750, 0.0017395019531250, +0.0028381347656250, 0.0018005371093750, 0.0028991699218750, 0.0018615722656250, +0.0028076171875000, 0.0015869140625000, 0.0026245117187500, 0.0018005371093750, +0.0027160644531250, 0.0015869140625000, 0.0024719238281250, 0.0015563964843750, +0.0025329589843750, 0.0015869140625000, 0.0025329589843750, 0.0015869140625000, +0.0022888183593750}, +{0.0033874511718750, 0.0026245117187500, 0.0044555664062500, 0.0029602050781250, +0.0040588378906250, 0.0029907226562500, 0.0047912597656250, 0.0027465820312500, +0.0051574707031250, 0.0032348632812500, 0.0047607421875000, 0.0036621093750000, +0.0048217773437500, 0.0032958984375000, 0.0051269531250000, 0.0042724609375000, +0.0038757324218750, 0.0042419433593750, 0.0042114257812500, 0.0042724609375000, +0.0038146972656250, 0.0047302246093750, 0.0026550292968750, 0.0045166015625000, +0.0032958984375000, 0.0045166015625000, 0.0023803710937500, 0.0046386718750000, +0.0022277832031250, 0.0045166015625000, 0.0025329589843750, 0.0043334960937500, +0.0023498535156250, 0.0043334960937500, 0.0023803710937500, 0.0043029785156250, +0.0028991699218750, 0.0042114257812500, 0.0028686523437500, 0.0041809082031250, +0.0029602050781250, 0.0041809082031250, 0.0033264160156250, 0.0040283203125000, +0.0032653808593750, 0.0040588378906250, 0.0031433105468750, 0.0039672851562500, +0.0033569335937500, 0.0040893554687500, 0.0032653808593750, 0.0040893554687500, +0.0030212402343750, 0.0039062500000000, 0.0031738281250000, 0.0042419433593750, +0.0028686523437500, 0.0041198730468750, 0.0028381347656250, 0.0041809082031250, +0.0028686523437500, 0.0042724609375000, 0.0026550292968750, 0.0040588378906250, +0.0026245117187500, 0.0045776367187500, 0.0027160644531250, 0.0042724609375000, +0.0025634765625000, 0.0045471191406250, 0.0026550292968750, 0.0050659179687500, +0.0028381347656250, 0.0045776367187500, 0.0026245117187500, 0.0055236816406250, +0.0029907226562500, 0.0052185058593750, 0.0028991699218750, 0.0053710937500000, +0.0028991699218750, 0.0060119628906250, 0.0031127929687500, 0.0055236816406250, +0.0029602050781250, 0.0057678222656250, 0.0031127929687500, 0.0058593750000000, +0.0030212402343750, 0.0054626464843750, 0.0029907226562500, 0.0052795410156250, +0.0030212402343750, 0.0053405761718750, 0.0029296875000000, 0.0045776367187500, +0.0027770996093750, 0.0046386718750000, 0.0028076171875000, 0.0042114257812500, +0.0027465820312500, 0.0035705566406250, 0.0026550292968750, 0.0039367675781250, +0.0027160644531250, 0.0028686523437500, 0.0026550292968750, 0.0030212402343750, +0.0026855468750000, 0.0028076171875000, 0.0027465820312500, 0.0021667480468750, +0.0028076171875000, 0.0026245117187500, 0.0027465820312500, 0.0018310546875000, +0.0030212402343750, 0.0018920898437500, 0.0029602050781250, 0.0018615722656250, +0.0030212402343750, 0.0013122558593750, 0.0032348632812500, 0.0015258789062500, +0.0031433105468750, 0.0013732910156250, 0.0033569335937500, 0.0012512207031250, +0.0033264160156250, 0.0014953613281250, 0.0033264160156250, 0.0016174316406250, +0.0033874511718750, 0.0013732910156250, 0.0033264160156250, 0.0019226074218750, +0.0032348632812500, 0.0018310546875000, 0.0033569335937500, 0.0019836425781250, +0.0032958984375000, 0.0023803710937500, 0.0031127929687500, 0.0022277832031250, +0.0033264160156250, 0.0024414062500000, 0.0029296875000000, 0.0025939941406250, +0.0031433105468750, 0.0024414062500000, 0.0029602050781250, 0.0024414062500000, +0.0026550292968750, 0.0025939941406250, 0.0030212402343750, 0.0021057128906250, +0.0026550292968750, 0.0023498535156250, 0.0026550292968750, 0.0020751953125000, +0.0027770996093750, 0.0016479492187500, 0.0026550292968750, 0.0021057128906250, +0.0026855468750000, 0.0013122558593750, 0.0028381347656250, 0.0013732910156250, +0.0028686523437500, 0.0014038085937500, 0.0028076171875000, 0.0010681152343750, +0.0028991699218750, 0.0013122558593750, 0.0030212402343750, 0.0012817382812500, +0.0028686523437500, 0.0013122558593750, 0.0029602050781250, 0.0014038085937500, +0.0028991699218750, 0.0014648437500000, 0.0027465820312500, 0.0015258789062500, +0.0029296875000000, 0.0015869140625000, 0.0026550292968750, 0.0015563964843750, +0.0027160644531250, 0.0016784667968750, 0.0026550292968750, 0.0016784667968750, +0.0024414062500000, 0.0015563964843750, 0.0026245117187500, 0.0021667480468750, +0.0023498535156250, 0.0019226074218750, 0.0023803710937500, 0.0023193359375000, +0.0025024414062500, 0.0030212402343750, 0.0023803710937500, 0.0025939941406250, +0.0024414062500000, 0.0035705566406250, 0.0027770996093750, 0.0036315917968750, +0.0026550292968750, 0.0035400390625000, 0.0029602050781250, 0.0039367675781250, +0.0033874511718750, 0.0038146972656250, 0.0031433105468750, 0.0032958984375000, +0.0036621093750000, 0.0034484863281250, 0.0036926269531250, 0.0030822753906250, +0.0036926269531250, 0.0024719238281250, 0.0039672851562500, 0.0025634765625000, +0.0038757324218750, 0.0021362304687500, 0.0038452148437500, 0.0018920898437500, +0.0037841796875000, 0.0018920898437500, 0.0036926269531250, 0.0017700195312500, +0.0036926269531250, 0.0017395019531250, 0.0036010742187500, 0.0016784667968750, +0.0036315917968750, 0.0016784667968750, 0.0036315917968750, 0.0014343261718750, +0.0036315917968750, 0.0012207031250000, 0.0035400390625000, 0.0014648437500000, +0.0034790039062500, 0.0010986328125000, 0.0033874511718750, 0.0009460449218750, +0.0033264160156250, 0.0014648437500000, 0.0033874511718750, 0.0016784667968750, +0.0033569335937500, 0.0014648437500000, 0.0032043457031250, 0.0029602050781250, +0.0037841796875000, 0.0029602050781250, 0.0036926269531250, 0.0032653808593750, +0.0038146972656250, 0.0044555664062500, 0.0043334960937500, 0.0041809082031250, +0.0041809082031250, 0.0042419433593750, 0.0045471191406250, 0.0047607421875000, +0.0046997070312500, 0.0043945312500000, 0.0046081542968750, 0.0035705566406250, +0.0047302246093750, 0.0033874511718750, 0.0048828125000000, 0.0023193359375000, +0.0043945312500000, 0.0025634765625000, 0.0047302246093750, 0.0025329589843750, +0.0045166015625000, 0.0018310546875000, 0.0039978027343750, 0.0022583007812500, +0.0044555664062500, 0.0020751953125000, 0.0035400390625000, 0.0019531250000000, +0.0036315917968750, 0.0022277832031250, 0.0036315917968750, 0.0023803710937500, +0.0030517578125000, 0.0022583007812500, 0.0033874511718750, 0.0032043457031250, +0.0031738281250000, 0.0030517578125000, 0.0032043457031250, 0.0033264160156250, +0.0032348632812500, 0.0040588378906250, 0.0031738281250000, 0.0039062500000000, +0.0032958984375000, 0.0042724609375000, 0.0029907226562500, 0.0044860839843750, +0.0031127929687500, 0.0041809082031250, 0.0029907226562500, 0.0039367675781250, +0.0026245117187500, 0.0040283203125000, 0.0028381347656250, 0.0038146972656250, +0.0028076171875000, 0.0036315917968750, 0.0026550292968750, 0.0036010742187500, +0.0030212402343750, 0.0035400390625000, 0.0033569335937500, 0.0035400390625000, +0.0032043457031250, 0.0034179687500000, 0.0038452148437500, 0.0035400390625000, +0.0039978027343750, 0.0034179687500000, 0.0040283203125000, 0.0033569335937500, +0.0044250488281250, 0.0036315917968750, 0.0044860839843750, 0.0030212402343750, +0.0042724609375000, 0.0032348632812500, 0.0045776367187500, 0.0032653808593750, +0.0043945312500000, 0.0028381347656250, 0.0039978027343750, 0.0030822753906250, +0.0042724609375000, 0.0030822753906250, 0.0038452148437500, 0.0029296875000000, +0.0039062500000000, 0.0031738281250000, 0.0038757324218750, 0.0033874511718750, +0.0036010742187500, 0.0032653808593750, 0.0037536621093750, 0.0037231445312500, +0.0036621093750000, 0.0037536621093750, 0.0037231445312500, 0.0037841796875000, +0.0037231445312500, 0.0041198730468750, 0.0037841796875000, 0.0041198730468750, +0.0039062500000000, 0.0038146972656250, 0.0039672851562500, 0.0040893554687500, +0.0039978027343750, 0.0038452148437500, 0.0041503906250000, 0.0033569335937500, +0.0042724609375000, 0.0037841796875000, 0.0043029785156250, 0.0034179687500000, +0.0044555664062500, 0.0034179687500000, 0.0046081542968750, 0.0036010742187500, +0.0044860839843750, 0.0035095214843750, 0.0045166015625000, 0.0036315917968750, +0.0046691894531250, 0.0038452148437500, 0.0040588378906250, 0.0039672851562500, +0.0041809082031250, 0.0039367675781250, 0.0040283203125000, 0.0040893554687500, +0.0035400390625000, 0.0043029785156250, 0.0037536621093750, 0.0038146972656250, +0.0035705566406250, 0.0042114257812500, 0.0034179687500000, 0.0039672851562500, +0.0037536621093750, 0.0034484863281250, 0.0039062500000000, 0.0040893554687500, +0.0037536621093750, 0.0031127929687500, 0.0044250488281250, 0.0032958984375000, +0.0044555664062500, 0.0032958984375000, 0.0045776367187500, 0.0026550292968750, +0.0049438476562500, 0.0031127929687500, 0.0048828125000000, 0.0026550292968750, +0.0050659179687500, 0.0026855468750000, 0.0051269531250000, 0.0027465820312500, +0.0050048828125000, 0.0026550292968750, 0.0050354003906250, 0.0027465820312500, +0.0050354003906250, 0.0027160644531250, 0.0046997070312500, 0.0027770996093750, +0.0046691894531250, 0.0028381347656250, 0.0045166015625000, 0.0028381347656250, +0.0041809082031250, 0.0029296875000000, 0.0041809082031250, 0.0029907226562500, +0.0038757324218750, 0.0030212402343750, 0.0038757324218750, 0.0029907226562500, +0.0037231445312500, 0.0030517578125000, 0.0034790039062500, 0.0030517578125000, +0.0035095214843750, 0.0029907226562500, 0.0031127929687500, 0.0030212402343750, +0.0032653808593750, 0.0029296875000000, 0.0028991699218750, 0.0028686523437500, +0.0024414062500000, 0.0029907226562500, 0.0028076171875000, 0.0028381347656250, +0.0018615722656250, 0.0028686523437500, 0.0020141601562500, 0.0029602050781250, +0.0018615722656250, 0.0028686523437500, 0.0012817382812500, 0.0030212402343750, +0.0016174316406250, 0.0030212402343750, 0.0013732910156250, 0.0030517578125000, +0.0011901855468750, 0.0030822753906250, 0.0014038085937500, 0.0031433105468750, +0.0014953613281250, 0.0032043457031250, 0.0013732910156250, 0.0030822753906250, +0.0020141601562500, 0.0031738281250000, 0.0018615722656250, 0.0031127929687500, +0.0021057128906250, 0.0029907226562500, 0.0025939941406250, 0.0032043457031250, +0.0022583007812500, 0.0028381347656250, 0.0029296875000000, 0.0029602050781250, +0.0028686523437500, 0.0029602050781250, 0.0028991699218750, 0.0028076171875000, +0.0032958984375000, 0.0029907226562500, 0.0031433105468750, 0.0028076171875000, +0.0031433105468750, 0.0028686523437500, 0.0032348632812500, 0.0029296875000000, +0.0031127929687500, 0.0028381347656250, 0.0029907226562500, 0.0029907226562500, +0.0030517578125000, 0.0028991699218750, 0.0027160644531250, 0.0030212402343750, +0.0027770996093750, 0.0029907226562500, 0.0026550292968750, 0.0029602050781250, +0.0024414062500000, 0.0031127929687500, 0.0025634765625000, 0.0029907226562500, +0.0022583007812500, 0.0030822753906250, 0.0022583007812500, 0.0032043457031250, +0.0021972656250000, 0.0031738281250000, 0.0020141601562500, 0.0032348632812500, +0.0021362304687500, 0.0032958984375000, 0.0020446777343750, 0.0033569335937500, +0.0020141601562500, 0.0033874511718750, 0.0021972656250000, 0.0034790039062500, +0.0023193359375000, 0.0035705566406250, 0.0021362304687500, 0.0033569335937500, +0.0025939941406250, 0.0035095214843750, 0.0024414062500000, 0.0034179687500000, +0.0026245117187500, 0.0031738281250000, 0.0031127929687500, 0.0034179687500000, +0.0028686523437500, 0.0032348632812500, 0.0031127929687500, 0.0031127929687500, +0.0032348632812500, 0.0032348632812500, 0.0029907226562500, 0.0032348632812500, +0.0028991699218750, 0.0031433105468750, 0.0030212402343750, 0.0036010742187500, +0.0025024414062500}, +{0.0036010742187500, 0.0031127929687500, 0.0040588378906250, 0.0031433105468750, +0.0041198730468750, 0.0032043457031250, 0.0041503906250000, 0.0034790039062500, +0.0043945312500000, 0.0034179687500000, 0.0042724609375000, 0.0034484863281250, +0.0042724609375000, 0.0035705566406250, 0.0043029785156250, 0.0034179687500000, +0.0042419433593750, 0.0032348632812500, 0.0040893554687500, 0.0032958984375000, +0.0039978027343750, 0.0030212402343750, 0.0041198730468750, 0.0029296875000000, +0.0040283203125000, 0.0028991699218750, 0.0039978027343750, 0.0027160644531250, +0.0040588378906250, 0.0026245117187500, 0.0040283203125000, 0.0025634765625000, +0.0042114257812500, 0.0025024414062500, 0.0042114257812500, 0.0024108886718750, +0.0043945312500000, 0.0022888183593750, 0.0046386718750000, 0.0022888183593750, +0.0045776367187500, 0.0021667480468750, 0.0048828125000000, 0.0020751953125000, +0.0049743652343750, 0.0021057128906250, 0.0050048828125000, 0.0020446777343750, +0.0051269531250000, 0.0020141601562500, 0.0051574707031250, 0.0022277832031250, +0.0050964355468750, 0.0021362304687500, 0.0051574707031250, 0.0022277832031250, +0.0049438476562500, 0.0024414062500000, 0.0048522949218750, 0.0022888183593750, +0.0049438476562500, 0.0025024414062500, 0.0044250488281250, 0.0025024414062500, +0.0044860839843750, 0.0025329589843750, 0.0041809082031250, 0.0026550292968750, +0.0036621093750000, 0.0025024414062500, 0.0039672851562500, 0.0026855468750000, +0.0030822753906250, 0.0026855468750000, 0.0032348632812500, 0.0026550292968750, +0.0030822753906250, 0.0028076171875000, 0.0025024414062500, 0.0027465820312500, +0.0028076171875000, 0.0027465820312500, 0.0024414062500000, 0.0027770996093750, +0.0023498535156250, 0.0027770996093750, 0.0024719238281250, 0.0028076171875000, +0.0024108886718750, 0.0029296875000000, 0.0023498535156250, 0.0028991699218750, +0.0025329589843750, 0.0030212402343750, 0.0025329589843750, 0.0031127929687500, +0.0025634765625000, 0.0031127929687500, 0.0026855468750000, 0.0032043457031250, +0.0025939941406250, 0.0032653808593750, 0.0028076171875000, 0.0032958984375000, +0.0027465820312500, 0.0033874511718750, 0.0026245117187500, 0.0034484863281250, +0.0025939941406250, 0.0035705566406250, 0.0025939941406250, 0.0036621093750000, +0.0024108886718750, 0.0037231445312500, 0.0023193359375000, 0.0038146972656250, +0.0022888183593750, 0.0038757324218750, 0.0021667480468750, 0.0038757324218750, +0.0021362304687500, 0.0039367675781250, 0.0021057128906250, 0.0041198730468750, +0.0021667480468750, 0.0039672851562500, 0.0020751953125000, 0.0038146972656250, +0.0019531250000000, 0.0039978027343750, 0.0020446777343750, 0.0033874511718750, +0.0018920898437500, 0.0035400390625000, 0.0019531250000000, 0.0034179687500000, +0.0017700195312500, 0.0029907226562500, 0.0015563964843750, 0.0032348632812500, +0.0017395019531250, 0.0029602050781250, 0.0014953613281250, 0.0028991699218750, +0.0014343261718750, 0.0030212402343750, 0.0015563964843750, 0.0029602050781250, +0.0014343261718750, 0.0029296875000000, 0.0014953613281250, 0.0031738281250000, +0.0018005371093750, 0.0031127929687500, 0.0018310546875000, 0.0031738281250000, +0.0021057128906250, 0.0034484863281250, 0.0025329589843750, 0.0032958984375000, +0.0024414062500000, 0.0034790039062500, 0.0025939941406250, 0.0034790039062500, +0.0029296875000000, 0.0034790039062500, 0.0025939941406250, 0.0035095214843750, +0.0023498535156250, 0.0033874511718750, 0.0027465820312500, 0.0036315917968750, +0.0017395019531250, 0.0034179687500000, 0.0018310546875000, 0.0036315917968750, +0.0017700195312500, 0.0039672851562500, 0.0010986328125000, 0.0035400390625000, +0.0013732910156250, 0.0043334960937500, 0.0014648437500000, 0.0041809082031250, +0.0011901855468750, 0.0041198730468750, 0.0017395019531250, 0.0045471191406250, +0.0021972656250000, 0.0043334960937500, 0.0018310546875000, 0.0045166015625000, +0.0031738281250000, 0.0044555664062500, 0.0031127929687500, 0.0044250488281250, +0.0030212402343750, 0.0045166015625000, 0.0037536621093750, 0.0043029785156250, +0.0034484863281250, 0.0046386718750000, 0.0030212402343750, 0.0044860839843750, +0.0032348632812500, 0.0045166015625000, 0.0029296875000000, 0.0047607421875000, +0.0023193359375000, 0.0046386718750000, 0.0026855468750000, 0.0048522949218750, +0.0022583007812500, 0.0048217773437500, 0.0022888183593750, 0.0048217773437500, +0.0022277832031250, 0.0048217773437500, 0.0021972656250000, 0.0048217773437500, +0.0023803710937500, 0.0047607421875000, 0.0014343261718750, 0.0047912597656250, +0.0018615722656250, 0.0046691894531250, 0.0015258789062500, 0.0046386718750000, +0.0004882812500000, 0.0046386718750000, 0.0010681152343750, 0.0045166015625000, +0.0011901855468750, 0.0043945312500000, 0.0006103515625000, 0.0045471191406250, +0.0015258789062500, 0.0047607421875000, 0.0033874511718750, 0.0054626464843750, +0.0023193359375000, 0.0046997070312500, 0.0008544921875000, 0.0056152343750000, +0.0008239746093750, 0.0045471191406250, 0.0013427734375000, 0.0034179687500000, +0.0013122558593750, 0.0043640136718750, 0.0010375976562500, 0.0024719238281250, +0.0023193359375000, 0.0024719238281250, 0.0019226074218750, 0.0026245117187500, +0.0025634765625000, 0.0017395019531250, 0.0036926269531250, 0.0020446777343750, +0.0028686523437500, 0.0020751953125000, 0.0050048828125000, 0.0021057128906250, +0.0047912597656250, 0.0021972656250000, 0.0047912597656250, 0.0023498535156250, +0.0062866210937500, 0.0024719238281250, 0.0057983398437500, 0.0026855468750000, +0.0050964355468750, 0.0027465820312500, 0.0058288574218750, 0.0028686523437500, +0.0047607421875000, 0.0030517578125000, 0.0033874511718750, 0.0031433105468750, +0.0043945312500000, 0.0033264160156250, 0.0022277832031250, 0.0033569335937500, +0.0021667480468750, 0.0031738281250000, 0.0022277832031250, 0.0031433105468750, +0.0011291503906250, 0.0032348632812500, 0.0014038085937500, 0.0025024414062500, +0.0016479492187500, 0.0026550292968750, 0.0014038085937500, 0.0024719238281250, +0.0018005371093750, 0.0017700195312500, 0.0023498535156250, 0.0021057128906250, +0.0021362304687500, 0.0019531250000000, 0.0026855468750000, 0.0017089843750000, +0.0028076171875000, 0.0021667480468750, 0.0029296875000000, 0.0025024414062500, +0.0031433105468750, 0.0022583007812500, 0.0030822753906250, 0.0032653808593750, +0.0031738281250000, 0.0031738281250000, 0.0031738281250000, 0.0033874511718750, +0.0032958984375000, 0.0041809082031250, 0.0034179687500000, 0.0038452148437500, +0.0033264160156250, 0.0040588378906250, 0.0033874511718750, 0.0043640136718750, +0.0033569335937500, 0.0041198730468750, 0.0031127929687500, 0.0039978027343750, +0.0029296875000000, 0.0042114257812500, 0.0028991699218750, 0.0034484863281250, +0.0022583007812500, 0.0035705566406250, 0.0023193359375000, 0.0035400390625000, +0.0018920898437500, 0.0029907226562500, 0.0012512207031250, 0.0032348632812500, +0.0015258789062500, 0.0029296875000000, 0.0011901855468750, 0.0029602050781250, +0.0007934570312500, 0.0028381347656250, 0.0013427734375000, 0.0026855468750000, +0.0016479492187500, 0.0028381347656250, 0.0012817382812500, 0.0024108886718750, +0.0023803710937500, 0.0025634765625000, 0.0022888183593750, 0.0023803710937500, +0.0024108886718750, 0.0020446777343750, 0.0031433105468750, 0.0023803710937500, +0.0028381347656250, 0.0021057128906250, 0.0028991699218750, 0.0019836425781250, +0.0031738281250000, 0.0022583007812500, 0.0028686523437500, 0.0022888183593750, +0.0026245117187500, 0.0021667480468750, 0.0027770996093750, 0.0029602050781250, +0.0021667480468750, 0.0026550292968750, 0.0021972656250000, 0.0030517578125000, +0.0022277832031250, 0.0037841796875000, 0.0018920898437500, 0.0032958984375000, +0.0020141601562500, 0.0042419433593750, 0.0022888183593750, 0.0041809082031250, +0.0021057128906250, 0.0041198730468750, 0.0023193359375000, 0.0046691894531250, +0.0027160644531250, 0.0045166015625000, 0.0025024414062500, 0.0044250488281250, +0.0029602050781250, 0.0046081542968750, 0.0030212402343750, 0.0044250488281250, +0.0029602050781250, 0.0042419433593750, 0.0032043457031250, 0.0044250488281250, +0.0032043457031250, 0.0038757324218750, 0.0029907226562500, 0.0041503906250000, +0.0032043457031250, 0.0039672851562500, 0.0030517578125000, 0.0034484863281250, +0.0028381347656250, 0.0038452148437500, 0.0031127929687500, 0.0034484863281250, +0.0027465820312500, 0.0034484863281250, 0.0027770996093750, 0.0036315917968750, +0.0028686523437500, 0.0036315917968750, 0.0028076171875000, 0.0037841796875000, +0.0028686523437500, 0.0040588378906250, 0.0030822753906250, 0.0041198730468750, +0.0030822753906250, 0.0043029785156250, 0.0031433105468750, 0.0046691894531250, +0.0033569335937500, 0.0046691894531250, 0.0033264160156250, 0.0047912597656250, +0.0033874511718750, 0.0049438476562500, 0.0035400390625000, 0.0048217773437500, +0.0034484863281250, 0.0046997070312500, 0.0033874511718750, 0.0048217773437500, +0.0036926269531250, 0.0043334960937500, 0.0032958984375000, 0.0045166015625000, +0.0035400390625000, 0.0041503906250000, 0.0034484863281250, 0.0036010742187500, +0.0031433105468750, 0.0039367675781250, 0.0035705566406250, 0.0029907226562500, +0.0030212402343750, 0.0030517578125000, 0.0031433105468750, 0.0028686523437500, +0.0031738281250000, 0.0022583007812500, 0.0027465820312500, 0.0025024414062500, +0.0031127929687500, 0.0021057128906250, 0.0028076171875000, 0.0019226074218750, +0.0028076171875000, 0.0021972656250000, 0.0028381347656250, 0.0021667480468750, +0.0027770996093750, 0.0019836425781250, 0.0027465820312500, 0.0028076171875000, +0.0028076171875000, 0.0025024414062500, 0.0028076171875000, 0.0030822753906250, +0.0027770996093750, 0.0039672851562500, 0.0028076171875000, 0.0032348632812500, +0.0028076171875000, 0.0047607421875000, 0.0027770996093750, 0.0045166015625000, +0.0028381347656250, 0.0046997070312500, 0.0028991699218750, 0.0056762695312500, +0.0028381347656250, 0.0050354003906250, 0.0028686523437500, 0.0059204101562500, +0.0030517578125000, 0.0058288574218750, 0.0029907226562500, 0.0057678222656250, +0.0029907226562500, 0.0061340332031250, 0.0030517578125000, 0.0057983398437500, +0.0029907226562500, 0.0058593750000000, 0.0028686523437500, 0.0059204101562500, +0.0028991699218750, 0.0056762695312500, 0.0028381347656250, 0.0054931640625000, +0.0027465820312500, 0.0055541992187500, 0.0028381347656250, 0.0050659179687500, +0.0028686523437500, 0.0051574707031250, 0.0027770996093750, 0.0048828125000000, +0.0030517578125000, 0.0045471191406250, 0.0032653808593750, 0.0047912597656250, +0.0031433105468750, 0.0041503906250000, 0.0036926269531250, 0.0042724609375000, +0.0037231445312500, 0.0041198730468750, 0.0037231445312500, 0.0037231445312500, +0.0039672851562500, 0.0040283203125000, 0.0039672851562500, 0.0033264160156250, +0.0038452148437500, 0.0035400390625000, 0.0038452148437500, 0.0032653808593750, +0.0037841796875000, 0.0027465820312500, 0.0036315917968750, 0.0031738281250000, +0.0036010742187500, 0.0024414062500000, 0.0036010742187500, 0.0026245117187500, +0.0035095214843750, 0.0026550292968750, 0.0034484863281250, 0.0022888183593750, +0.0034484863281250, 0.0025329589843750, 0.0034484863281250, 0.0021057128906250, +0.0032958984375000, 0.0022888183593750, 0.0032653808593750, 0.0021057128906250, +0.0032958984375000}, +{0.0035095214843750, 0.0017395019531250, 0.0035400390625000, 0.0009460449218750, +0.0036010742187500, 0.0013427734375000, 0.0036010742187500, 0.0004882812500000, +0.0036621093750000, 0.0003967285156250, 0.0036315917968750, 0.0004272460937500, +0.0036621093750000, -0.0000305175781250, 0.0036926269531250, 0.0000305175781250, +0.0036315917968750, 0.0000915527343750, 0.0036926269531250, -0.0000305175781250, +0.0036010742187500, 0.0000610351562500, 0.0036621093750000, 0.0001525878906250, +0.0037231445312500, 0.0000915527343750, 0.0035705566406250, 0.0003356933593750, +0.0036315917968750, 0.0002136230468750, 0.0036010742187500, 0.0003967285156250, +0.0035705566406250, 0.0006713867187500, 0.0036621093750000, 0.0005493164062500, +0.0036926269531250, 0.0012817382812500, 0.0036621093750000, 0.0010681152343750, +0.0038146972656250, 0.0015563964843750, 0.0037231445312500, 0.0023193359375000, +0.0036926269531250, 0.0018310546875000, 0.0039062500000000, 0.0032043457031250, +0.0036315917968750, 0.0030212402343750, 0.0038757324218750, 0.0034790039062500, +0.0037841796875000, 0.0046691894531250, 0.0035095214843750, 0.0042114257812500, +0.0038146972656250, 0.0057067871093750, 0.0036010742187500, 0.0056457519531250, +0.0035705566406250, 0.0060119628906250, 0.0036926269531250, 0.0070190429687500, +0.0036315917968750, 0.0065612792968750, 0.0036315917968750, 0.0072937011718750, +0.0037231445312500, 0.0073547363281250, 0.0036926269531250, 0.0070800781250000, +0.0036926269531250, 0.0071716308593750, 0.0037841796875000, 0.0071411132812500, +0.0036926269531250, 0.0065612792968750, 0.0036315917968750, 0.0066223144531250, +0.0036926269531250, 0.0063171386718750, 0.0035705566406250, 0.0057067871093750, +0.0034484863281250, 0.0060424804687500, 0.0035705566406250, 0.0056152343750000, +0.0033874511718750, 0.0055236816406250, 0.0033874511718750, 0.0056152343750000, +0.0033874511718750, 0.0055541992187500, 0.0033569335937500, 0.0055847167968750, +0.0033874511718750, 0.0056762695312500, 0.0032043457031250, 0.0057373046875000, +0.0032043457031250, 0.0056762695312500, 0.0030517578125000, 0.0056457519531250, +0.0028991699218750, 0.0057373046875000, 0.0028686523437500, 0.0053100585937500, +0.0029602050781250, 0.0055541992187500, 0.0028076171875000, 0.0052185058593750, +0.0029296875000000, 0.0047912597656250, 0.0031738281250000, 0.0051879882812500, +0.0029296875000000, 0.0043945312500000, 0.0034790039062500, 0.0046081542968750, +0.0034484863281250, 0.0043334960937500, 0.0035095214843750, 0.0037841796875000, +0.0038757324218750, 0.0043334960937500, 0.0038757324218750, 0.0033874511718750, +0.0037231445312500, 0.0036621093750000, 0.0039062500000000, 0.0034484863281250, +0.0038452148437500, 0.0027770996093750, 0.0036315917968750, 0.0033264160156250, +0.0037841796875000, 0.0027465820312500, 0.0036315917968750, 0.0028076171875000, +0.0036315917968750, 0.0029296875000000, 0.0036621093750000, 0.0026245117187500, +0.0035705566406250, 0.0028686523437500, 0.0036010742187500, 0.0028076171875000, +0.0035400390625000, 0.0028686523437500, 0.0034790039062500, 0.0030212402343750, +0.0034790039062500, 0.0031127929687500, 0.0033874511718750, 0.0031127929687500, +0.0033569335937500, 0.0034179687500000, 0.0036315917968750, 0.0033569335937500, +0.0035095214843750, 0.0033264160156250, 0.0036315917968750, 0.0034484863281250, +0.0039672851562500, 0.0033874511718750, 0.0036926269531250, 0.0030822753906250, +0.0040588378906250, 0.0031738281250000, 0.0040588378906250, 0.0028381347656250, +0.0040283203125000, 0.0023803710937500, 0.0040893554687500, 0.0024108886718750, +0.0039978027343750, 0.0014953613281250, 0.0040283203125000, 0.0015563964843750, +0.0040588378906250, 0.0013122558593750, 0.0039367675781250, 0.0006103515625000, +0.0038757324218750, 0.0007934570312500, 0.0039978027343750, 0.0005187988281250, +0.0036315917968750, 0.0001220703125000, 0.0036621093750000, 0.0007324218750000, +0.0036315917968750, 0.0011596679687500, 0.0034179687500000, 0.0006713867187500, +0.0034790039062500, 0.0025024414062500, 0.0034484863281250, 0.0022277832031250, +0.0034484863281250, 0.0023803710937500, 0.0034484863281250, 0.0039062500000000, +0.0034179687500000, 0.0038146972656250, 0.0034179687500000, 0.0034179687500000, +0.0031738281250000, 0.0037231445312500, 0.0033264160156250, 0.0035095214843750, +0.0032653808593750, 0.0029296875000000, 0.0031433105468750, 0.0031433105468750, +0.0033874511718750, 0.0025634765625000, 0.0034484863281250, 0.0024719238281250, +0.0033569335937500, 0.0022888183593750, 0.0035705566406250, 0.0019531250000000, +0.0038146972656250, 0.0021362304687500, 0.0036926269531250, 0.0019226074218750, +0.0040283203125000, 0.0019226074218750, 0.0041503906250000, 0.0022277832031250, +0.0039672851562500, 0.0024108886718750, 0.0039367675781250, 0.0025024414062500, +0.0039978027343750, 0.0029907226562500, 0.0032653808593750, 0.0032348632812500, +0.0035095214843750, 0.0030212402343750, 0.0031433105468750, 0.0031433105468750, +0.0024108886718750, 0.0036315917968750, 0.0027160644531250, 0.0028686523437500, +0.0021057128906250, 0.0033264160156250, 0.0018615722656250, 0.0032043457031250, +0.0019531250000000, 0.0025329589843750, 0.0017700195312500, 0.0031127929687500, +0.0017089843750000, 0.0026245117187500, 0.0019836425781250, 0.0025634765625000, +0.0017700195312500, 0.0027465820312500, 0.0019531250000000, 0.0026245117187500, +0.0023803710937500, 0.0026245117187500, 0.0021362304687500, 0.0028381347656250, +0.0023803710937500, 0.0027770996093750, 0.0025024414062500, 0.0028076171875000, +0.0022583007812500, 0.0029907226562500, 0.0021667480468750, 0.0029907226562500, +0.0022583007812500, 0.0030517578125000, 0.0017089843750000, 0.0030822753906250, +0.0018920898437500, 0.0031433105468750, 0.0017395019531250, 0.0031433105468750, +0.0011901855468750, 0.0030517578125000, 0.0014953613281250, 0.0034179687500000, +0.0010681152343750, 0.0031738281250000, 0.0010070800781250, 0.0033569335937500, +0.0011291503906250, 0.0038452148437500, 0.0010375976562500, 0.0034179687500000, +0.0010375976562500, 0.0036926269531250, 0.0012207031250000, 0.0037231445312500, +0.0012512207031250, 0.0035095214843750, 0.0014038085937500, 0.0034484863281250, +0.0016174316406250, 0.0034179687500000, 0.0015563964843750, 0.0032653808593750, +0.0019531250000000, 0.0030822753906250, 0.0020446777343750, 0.0031433105468750, +0.0021362304687500, 0.0030822753906250, 0.0022888183593750, 0.0028991699218750, +0.0022888183593750, 0.0034179687500000, 0.0023498535156250, 0.0030517578125000, +0.0023803710937500, 0.0032043457031250, 0.0023498535156250, 0.0037231445312500, +0.0023803710937500, 0.0031738281250000, 0.0023193359375000, 0.0037536621093750, +0.0023498535156250, 0.0036315917968750, 0.0021972656250000, 0.0035400390625000, +0.0022583007812500, 0.0037536621093750, 0.0023193359375000, 0.0034790039062500, +0.0021972656250000, 0.0035400390625000, 0.0022888183593750, 0.0033874511718750, +0.0021972656250000, 0.0034484863281250, 0.0021362304687500, 0.0035705566406250, +0.0021362304687500, 0.0032653808593750, 0.0020751953125000, 0.0038452148437500, +0.0020446777343750, 0.0036621093750000, 0.0020446777343750, 0.0036926269531250, +0.0019531250000000, 0.0040893554687500, 0.0018920898437500, 0.0038452148437500, +0.0018615722656250, 0.0040893554687500, 0.0017700195312500, 0.0042419433593750, +0.0018005371093750, 0.0041503906250000, 0.0017700195312500, 0.0041198730468750, +0.0016479492187500, 0.0043029785156250, 0.0016479492187500, 0.0040588378906250, +0.0018920898437500, 0.0041503906250000, 0.0017700195312500, 0.0040893554687500, +0.0019836425781250, 0.0039367675781250, 0.0023498535156250, 0.0040588378906250, +0.0021057128906250, 0.0039062500000000, 0.0026855468750000, 0.0038452148437500, +0.0026855468750000, 0.0039367675781250, 0.0028381347656250, 0.0038757324218750, +0.0031433105468750, 0.0038146972656250, 0.0030212402343750, 0.0039062500000000, +0.0033569335937500, 0.0038452148437500, 0.0032958984375000, 0.0038757324218750, +0.0035400390625000, 0.0039672851562500, 0.0037536621093750, 0.0039062500000000, +0.0035095214843750, 0.0040588378906250, 0.0043029785156250, 0.0040588378906250, +0.0041198730468750, 0.0040588378906250, 0.0043945312500000, 0.0041503906250000, +0.0050659179687500, 0.0041503906250000, 0.0046997070312500, 0.0042419433593750, +0.0056152343750000, 0.0041809082031250, 0.0054626464843750, 0.0042114257812500, +0.0054931640625000, 0.0042114257812500, 0.0060424804687500, 0.0040283203125000, +0.0057678222656250, 0.0042419433593750, 0.0059204101562500, 0.0040283203125000, +0.0059814453125000, 0.0040588378906250, 0.0059204101562500, 0.0041809082031250, +0.0060119628906250, 0.0038757324218750, 0.0060424804687500, 0.0041809082031250, +0.0059814453125000, 0.0039978027343750, 0.0060119628906250, 0.0038452148437500, +0.0058898925781250, 0.0040588378906250, 0.0058288574218750, 0.0037536621093750, +0.0058898925781250, 0.0038757324218750, 0.0057678222656250, 0.0037231445312500, +0.0058288574218750, 0.0036926269531250, 0.0057983398437500, 0.0037231445312500, +0.0057373046875000, 0.0034790039062500, 0.0057373046875000, 0.0038452148437500, +0.0054016113281250, 0.0036315917968750, 0.0054626464843750, 0.0036926269531250, +0.0053100585937500, 0.0039978027343750, 0.0050659179687500, 0.0036621093750000, +0.0051879882812500, 0.0039672851562500, 0.0047302246093750, 0.0038452148437500, +0.0047912597656250, 0.0038146972656250, 0.0046691894531250, 0.0039672851562500, +0.0044250488281250, 0.0037231445312500, 0.0046081542968750, 0.0038452148437500, +0.0041198730468750, 0.0037231445312500, 0.0041809082031250, 0.0036621093750000, +0.0040283203125000, 0.0037841796875000, 0.0037231445312500, 0.0036010742187500, +0.0039367675781250, 0.0039672851562500, 0.0035095214843750, 0.0037841796875000, +0.0035095214843750, 0.0038757324218750, 0.0034179687500000, 0.0043029785156250, +0.0032043457031250, 0.0040588378906250, 0.0033874511718750, 0.0043640136718750, +0.0030212402343750, 0.0044860839843750, 0.0031127929687500, 0.0043640136718750, +0.0031127929687500, 0.0044250488281250, 0.0028686523437500, 0.0045776367187500, +0.0029907226562500, 0.0042419433593750, 0.0032653808593750, 0.0044250488281250, +0.0030212402343750, 0.0042724609375000, 0.0034484863281250, 0.0039062500000000, +0.0039062500000000, 0.0041809082031250, 0.0035705566406250, 0.0039672851562500, +0.0046691894531250, 0.0039367675781250, 0.0045471191406250, 0.0041503906250000, +0.0044250488281250, 0.0041198730468750, 0.0052185058593750, 0.0039978027343750, +0.0050354003906250, 0.0040893554687500, 0.0041503906250000, 0.0039672851562500, +0.0047607421875000, 0.0039672851562500, 0.0039672851562500, 0.0039978027343750, +0.0027160644531250, 0.0039062500000000, 0.0035400390625000, 0.0039978027343750, +0.0019531250000000, 0.0038757324218750, 0.0019531250000000, 0.0039367675781250, +0.0020446777343750, 0.0040283203125000, 0.0013732910156250, 0.0038757324218750, +0.0016784667968750, 0.0041198730468750, 0.0014648437500000, 0.0039062500000000, +0.0016174316406250, 0.0041503906250000, 0.0013732910156250, 0.0044250488281250, +0.0009765625000000, 0.0039672851562500, 0.0013427734375000, 0.0047302246093750, +0.0006408691406250, 0.0046997070312500, 0.0004882812500000, 0.0044860839843750, +0.0010070800781250, 0.0048828125000000, 0.0009765625000000, 0.0047607421875000, +0.0005798339843750}, +{0.0046081542968750, 0.0044860839843750, 0.0042114257812500, 0.0046997070312500, +0.0049743652343750, 0.0045776367187500, 0.0049133300781250, 0.0045471191406250, +0.0050048828125000, 0.0045776367187500, 0.0055236816406250, 0.0044250488281250, +0.0053405761718750, 0.0044555664062500, 0.0056152343750000, 0.0044250488281250, +0.0057678222656250, 0.0043334960937500, 0.0055236816406250, 0.0043334960937500, +0.0054626464843750, 0.0042419433593750, 0.0056152343750000, 0.0041198730468750, +0.0047302246093750, 0.0040893554687500, 0.0050659179687500, 0.0039367675781250, +0.0044860839843750, 0.0038452148437500, 0.0035400390625000, 0.0038452148437500, +0.0040893554687500, 0.0036621093750000, 0.0028381347656250, 0.0035400390625000, +0.0028381347656250, 0.0035400390625000, 0.0025024414062500, 0.0034179687500000, +0.0017700195312500, 0.0033264160156250, 0.0022277832031250, 0.0035095214843750, +0.0014343261718750, 0.0033569335937500, 0.0012817382812500, 0.0034484863281250, +0.0014343261718750, 0.0036926269531250, 0.0010986328125000, 0.0034484863281250, +0.0010681152343750, 0.0038452148437500, 0.0012817382812500, 0.0036926269531250, +0.0011901855468750, 0.0037536621093750, 0.0013732910156250, 0.0039978027343750, +0.0016174316406250, 0.0037536621093750, 0.0013732910156250, 0.0040283203125000, +0.0019226074218750, 0.0039062500000000, 0.0017700195312500, 0.0039367675781250, +0.0019836425781250, 0.0040893554687500, 0.0024108886718750, 0.0038757324218750, +0.0020751953125000, 0.0043029785156250, 0.0028991699218750, 0.0040588378906250, +0.0027770996093750, 0.0042724609375000, 0.0028686523437500, 0.0046997070312500, +0.0034179687500000, 0.0043334960937500, 0.0032348632812500, 0.0047607421875000, +0.0032958984375000, 0.0048522949218750, 0.0035400390625000, 0.0046081542968750, +0.0033569335937500, 0.0046997070312500, 0.0031433105468750, 0.0047607421875000, +0.0033874511718750, 0.0043334960937500, 0.0029296875000000, 0.0045166015625000, +0.0029602050781250, 0.0044555664062500, 0.0029296875000000, 0.0041809082031250, +0.0027160644531250, 0.0043029785156250, 0.0028076171875000, 0.0040893554687500, +0.0023498535156250, 0.0041198730468750, 0.0023803710937500, 0.0041503906250000, +0.0022277832031250, 0.0040893554687500, 0.0018310546875000, 0.0042419433593750, +0.0021972656250000, 0.0042114257812500, 0.0019226074218750, 0.0042724609375000, +0.0017089843750000, 0.0042419433593750, 0.0021667480468750, 0.0042114257812500, +0.0024108886718750, 0.0041809082031250, 0.0021362304687500, 0.0040588378906250, +0.0032958984375000, 0.0039978027343750, 0.0031738281250000, 0.0040283203125000, +0.0032958984375000, 0.0040283203125000, 0.0040283203125000, 0.0041198730468750, +0.0038146972656250, 0.0042419433593750, 0.0037841796875000, 0.0041198730468750, +0.0040283203125000, 0.0043029785156250, 0.0037841796875000, 0.0045166015625000, +0.0034790039062500, 0.0042419433593750, 0.0037536621093750, 0.0047302246093750, +0.0036315917968750, 0.0046386718750000, 0.0034790039062500, 0.0044555664062500, +0.0036926269531250, 0.0046997070312500, 0.0038452148437500, 0.0045166015625000, +0.0038146972656250, 0.0038757324218750, 0.0037231445312500, 0.0040588378906250, +0.0040588378906250, 0.0035705566406250, 0.0034484863281250, 0.0028076171875000, +0.0029602050781250, 0.0031127929687500, 0.0034484863281250, 0.0023193359375000, +0.0018005371093750, 0.0021972656250000, 0.0018005371093750, 0.0024108886718750, +0.0019836425781250, 0.0022277832031250, 0.0010070800781250, 0.0039367675781250, +0.0050354003906250, 0.0025939941406250, 0.0033874511718750, 0.0033569335937500, +0.0041809082031250, 0.0030822753906250, 0.0034790039062500, 0.0021972656250000, +0.0023193359375000, 0.0026855468750000, 0.0029296875000000, 0.0026855468750000, +0.0022888183593750, 0.0025024414062500, 0.0021667480468750, 0.0027160644531250, +0.0024719238281250, 0.0028991699218750, 0.0022888183593750, 0.0028076171875000, +0.0022277832031250, 0.0028686523437500, 0.0031433105468750, 0.0028991699218750, +0.0028991699218750, 0.0029296875000000, 0.0032958984375000, 0.0028991699218750, +0.0042114257812500, 0.0027770996093750, 0.0038146972656250, 0.0030822753906250, +0.0044250488281250, 0.0029296875000000, 0.0046691894531250, 0.0029907226562500, +0.0042114257812500, 0.0032958984375000, 0.0042419433593750, 0.0030822753906250, +0.0046691894531250, 0.0032348632812500, 0.0034484863281250, 0.0032653808593750, +0.0036010742187500, 0.0030517578125000, 0.0036315917968750, 0.0029296875000000, +0.0028991699218750, 0.0029602050781250, 0.0032043457031250, 0.0028076171875000, +0.0037536621093750, 0.0026550292968750, 0.0032958984375000, 0.0027770996093750, +0.0039978027343750, 0.0027770996093750, 0.0050659179687500, 0.0025939941406250, +0.0044860839843750, 0.0032653808593750, 0.0054931640625000, 0.0030212402343750, +0.0057678222656250, 0.0031433105468750, 0.0056457519531250, 0.0037536621093750, +0.0059509277343750, 0.0033569335937500, 0.0059204101562500, 0.0036010742187500, +0.0054016113281250, 0.0036010742187500, 0.0054931640625000, 0.0035095214843750, +0.0052185058593750, 0.0034484863281250, 0.0047302246093750, 0.0034790039062500, +0.0049438476562500, 0.0034179687500000, 0.0043640136718750, 0.0032958984375000, +0.0042419433593750, 0.0035400390625000, 0.0043640136718750, 0.0036010742187500, +0.0042114257812500, 0.0033874511718750, 0.0042114257812500, 0.0042419433593750, +0.0044860839843750, 0.0039672851562500, 0.0043945312500000, 0.0043640136718750, +0.0042419433593750, 0.0052185058593750, 0.0043029785156250, 0.0047302246093750, +0.0042724609375000, 0.0057983398437500, 0.0041198730468750, 0.0057983398437500, +0.0039978027343750, 0.0057983398437500, 0.0039367675781250, 0.0064086914062500, +0.0039062500000000, 0.0061645507812500, 0.0039062500000000, 0.0057983398437500, +0.0038452148437500, 0.0061645507812500, 0.0039062500000000, 0.0055541992187500, +0.0038757324218750, 0.0047912597656250, 0.0039672851562500, 0.0053100585937500, +0.0039978027343750, 0.0037841796875000, 0.0037536621093750, 0.0038452148437500, +0.0039672851562500, 0.0036010742187500, 0.0036621093750000, 0.0025939941406250, +0.0032653808593750, 0.0029602050781250, 0.0037231445312500, 0.0025329589843750, +0.0028686523437500, 0.0024414062500000, 0.0031433105468750, 0.0024719238281250, +0.0031127929687500, 0.0023803710937500, 0.0025024414062500, 0.0024414062500000, +0.0029602050781250, 0.0023193359375000, 0.0026855468750000, 0.0023193359375000, +0.0026245117187500, 0.0024108886718750, 0.0028381347656250, 0.0022888183593750, +0.0028686523437500, 0.0022888183593750, 0.0028991699218750, 0.0027770996093750, +0.0032043457031250, 0.0025939941406250, 0.0032348632812500, 0.0029296875000000, +0.0033874511718750, 0.0034484863281250, 0.0035705566406250, 0.0031127929687500, +0.0035400390625000, 0.0038452148437500, 0.0036315917968750, 0.0037231445312500, +0.0036315917968750, 0.0038146972656250, 0.0036926269531250, 0.0041809082031250, +0.0037231445312500, 0.0038452148437500, 0.0037231445312500, 0.0043029785156250, +0.0037231445312500, 0.0041198730468750, 0.0037231445312500, 0.0039978027343750, +0.0037841796875000, 0.0041809082031250, 0.0038452148437500, 0.0039672851562500, +0.0038452148437500, 0.0037231445312500, 0.0040588378906250, 0.0037841796875000, +0.0039978027343750, 0.0034179687500000, 0.0040283203125000, 0.0030517578125000, +0.0041809082031250, 0.0032043457031250, 0.0040588378906250, 0.0023498535156250, +0.0040588378906250, 0.0025024414062500, 0.0041198730468750, 0.0021667480468750, +0.0040283203125000, 0.0014648437500000, 0.0039978027343750, 0.0019531250000000, +0.0040893554687500, 0.0010375976562500, 0.0038757324218750, 0.0011291503906250, +0.0039367675781250, 0.0010681152343750, 0.0039062500000000, 0.0005493164062500, +0.0037231445312500, 0.0008239746093750, 0.0039367675781250, 0.0005493164062500, +0.0035400390625000, 0.0004882812500000, 0.0036926269531250, 0.0007324218750000, +0.0036010742187500, 0.0007629394531250, 0.0033569335937500, 0.0007629394531250, +0.0036621093750000, 0.0013122558593750, 0.0032043457031250, 0.0011901855468750, +0.0033874511718750, 0.0014953613281250, 0.0033569335937500, 0.0020141601562500, +0.0030517578125000, 0.0018005371093750, 0.0032958984375000, 0.0025024414062500, +0.0029602050781250, 0.0026245117187500, 0.0030517578125000, 0.0027160644531250, +0.0029602050781250, 0.0031738281250000, 0.0026855468750000, 0.0031433105468750, +0.0029296875000000, 0.0032043457031250, 0.0027770996093750, 0.0034790039062500, +0.0026245117187500, 0.0032348632812500, 0.0028076171875000, 0.0030212402343750, +0.0029907226562500, 0.0032958984375000, 0.0028686523437500, 0.0025024414062500, +0.0032958984375000, 0.0026550292968750, 0.0032653808593750, 0.0024108886718750, +0.0033569335937500, 0.0018310546875000, 0.0036926269531250, 0.0021972656250000, +0.0036315917968750, 0.0016479492187500, 0.0037841796875000, 0.0016479492187500, +0.0038452148437500, 0.0018005371093750, 0.0038452148437500, 0.0016479492187500, +0.0039062500000000, 0.0017700195312500, 0.0038452148437500, 0.0021667480468750, +0.0039062500000000, 0.0021362304687500, 0.0038452148437500, 0.0022583007812500, +0.0038452148437500, 0.0025634765625000, 0.0038452148437500, 0.0025634765625000, +0.0037231445312500, 0.0025634765625000, 0.0036926269531250, 0.0027465820312500, +0.0036010742187500, 0.0027160644531250, 0.0035095214843750, 0.0026550292968750, +0.0034179687500000, 0.0028381347656250, 0.0033569335937500, 0.0025634765625000, +0.0034790039062500, 0.0026550292968750, 0.0033264160156250, 0.0026550292968750, +0.0033874511718750, 0.0025024414062500, 0.0035400390625000, 0.0025634765625000, +0.0033569335937500, 0.0024108886718750, 0.0034790039062500, 0.0024719238281250, +0.0035095214843750, 0.0022277832031250, 0.0032958984375000, 0.0019836425781250, +0.0032348632812500, 0.0022277832031250, 0.0033569335937500, 0.0017395019531250, +0.0030822753906250, 0.0018310546875000, 0.0030517578125000, 0.0018310546875000, +0.0031433105468750, 0.0014953613281250, 0.0030212402343750, 0.0015869140625000, +0.0030212402343750, 0.0016479492187500, 0.0028991699218750, 0.0015258789062500, +0.0029907226562500, 0.0017395019531250, 0.0029296875000000, 0.0019226074218750, +0.0028076171875000, 0.0019226074218750, 0.0029602050781250, 0.0024414062500000, +0.0027160644531250, 0.0023803710937500, 0.0027465820312500, 0.0028381347656250, +0.0027770996093750, 0.0034790039062500, 0.0026855468750000, 0.0032958984375000, +0.0026855468750000, 0.0043029785156250, 0.0026855468750000, 0.0045166015625000, +0.0027465820312500, 0.0044555664062500, 0.0028381347656250, 0.0049438476562500, +0.0028991699218750, 0.0050964355468750, 0.0029602050781250, 0.0043640136718750, +0.0032348632812500, 0.0047302246093750, 0.0032653808593750, 0.0044555664062500, +0.0033264160156250, 0.0032958984375000, 0.0036010742187500, 0.0030212402343750, +0.0036926269531250, 0.0025329589843750, 0.0033569335937500, 0.0025939941406250, +0.0035705566406250, 0.0022888183593750, 0.0033569335937500, 0.0018615722656250, +0.0029907226562500, 0.0020141601562500, 0.0031738281250000, 0.0015869140625000, +0.0025329589843750, 0.0015258789062500, 0.0025024414062500, 0.0017089843750000, +0.0024414062500000, 0.0015869140625000, 0.0020141601562500, 0.0015258789062500, +0.0021362304687500, 0.0025329589843750, 0.0019226074218750, 0.0021057128906250, +0.0018005371093750}, +{0.0036010742187500, 0.0019226074218750, 0.0036315917968750, 0.0019531250000000, +0.0036010742187500, 0.0020446777343750, 0.0034179687500000, 0.0019226074218750, +0.0035400390625000, 0.0021057128906250, 0.0033874511718750, 0.0021057128906250, +0.0034484863281250, 0.0020141601562500, 0.0035400390625000, 0.0021057128906250, +0.0034790039062500, 0.0020751953125000, 0.0034790039062500, 0.0020141601562500, +0.0036621093750000, 0.0020141601562500, 0.0037841796875000, 0.0019836425781250, +0.0038146972656250, 0.0019226074218750, 0.0039062500000000, 0.0019836425781250, +0.0039672851562500, 0.0018615722656250, 0.0038452148437500, 0.0019226074218750, +0.0039672851562500, 0.0018005371093750, 0.0038452148437500, 0.0015869140625000, +0.0037231445312500, 0.0017700195312500, 0.0038452148437500, 0.0013427734375000, +0.0036621093750000, 0.0014953613281250, 0.0037231445312500, 0.0012817382812500, +0.0036621093750000, 0.0008544921875000, 0.0035705566406250, 0.0011291503906250, +0.0036010742187500, 0.0008239746093750, 0.0034484863281250, 0.0007629394531250, +0.0034790039062500, 0.0010070800781250, 0.0034484863281250, 0.0009765625000000, +0.0032653808593750, 0.0009155273437500, 0.0032958984375000, 0.0016174316406250, +0.0033264160156250, 0.0015258789062500, 0.0032348632812500, 0.0017700195312500, +0.0033264160156250, 0.0023803710937500, 0.0034484863281250, 0.0022277832031250, +0.0033264160156250, 0.0026855468750000, 0.0036010742187500, 0.0028686523437500, +0.0036010742187500, 0.0028686523437500, 0.0035400390625000, 0.0030517578125000, +0.0036010742187500, 0.0032348632812500, 0.0036315917968750, 0.0030822753906250, +0.0033874511718750, 0.0032043457031250, 0.0034484863281250, 0.0031738281250000, +0.0033874511718750, 0.0030517578125000, 0.0032653808593750, 0.0032043457031250, +0.0032958984375000, 0.0030822753906250, 0.0031738281250000, 0.0031127929687500, +0.0032653808593750, 0.0031738281250000, 0.0031127929687500, 0.0031738281250000, +0.0030212402343750, 0.0032043457031250, 0.0032958984375000, 0.0031738281250000, +0.0027770996093750, 0.0032348632812500, 0.0029602050781250, 0.0032348632812500, +0.0030212402343750, 0.0031738281250000, 0.0026550292968750, 0.0032348632812500, +0.0029296875000000, 0.0030517578125000, 0.0026855468750000, 0.0030212402343750, +0.0026855468750000, 0.0030212402343750, 0.0027465820312500, 0.0028686523437500, +0.0026855468750000, 0.0028076171875000, 0.0027770996093750, 0.0028381347656250, +0.0029296875000000, 0.0027160644531250, 0.0028991699218750, 0.0026245117187500, +0.0029296875000000, 0.0026550292968750, 0.0031127929687500, 0.0026855468750000, +0.0030822753906250, 0.0026550292968750, 0.0028076171875000, 0.0026855468750000, +0.0030517578125000, 0.0027770996093750, 0.0027160644531250, 0.0028381347656250, +0.0020751953125000, 0.0030822753906250, 0.0023498535156250, 0.0036621093750000, +0.0019226074218750, 0.0033264160156250, 0.0018920898437500, 0.0033569335937500, +0.0019531250000000, 0.0038146972656250, 0.0016174316406250, 0.0035400390625000, +0.0014953613281250, 0.0031127929687500, 0.0018310546875000, 0.0032653808593750, +0.0015258789062500, 0.0028686523437500, 0.0015869140625000, 0.0023803710937500, +0.0019531250000000, 0.0026550292968750, 0.0016479492187500, 0.0018310546875000, +0.0018310546875000, 0.0016479492187500, 0.0018005371093750, 0.0017089843750000, +0.0016784667968750, 0.0012207031250000, 0.0017395019531250, 0.0011291503906250, +0.0016174316406250, 0.0017395019531250, 0.0016784667968750, 0.0013122558593750, +0.0015563964843750, 0.0018005371093750, 0.0017089843750000, 0.0025939941406250, +0.0017395019531250, 0.0018920898437500, 0.0014953613281250, 0.0030212402343750, +0.0021667480468750, 0.0031433105468750, 0.0019226074218750, 0.0028686523437500, +0.0020751953125000, 0.0033264160156250, 0.0026245117187500, 0.0032348632812500, +0.0022888183593750, 0.0029296875000000, 0.0027465820312500, 0.0031127929687500, +0.0026550292968750, 0.0029296875000000, 0.0025939941406250, 0.0025939941406250, +0.0028381347656250, 0.0029907226562500, 0.0026855468750000, 0.0026550292968750, +0.0025939941406250, 0.0027160644531250, 0.0025024414062500, 0.0027465820312500, +0.0025634765625000, 0.0026245117187500, 0.0025634765625000, 0.0028991699218750, +0.0024108886718750, 0.0028076171875000, 0.0026245117187500, 0.0028686523437500, +0.0025634765625000, 0.0028381347656250, 0.0025024414062500, 0.0028686523437500, +0.0027465820312500, 0.0029907226562500, 0.0026855468750000, 0.0027465820312500, +0.0023498535156250, 0.0028381347656250, 0.0025939941406250, 0.0028991699218750, +0.0023803710937500, 0.0028381347656250, 0.0019836425781250, 0.0029296875000000, +0.0022888183593750, 0.0030517578125000, 0.0016784667968750, 0.0030212402343750, +0.0016174316406250, 0.0030822753906250, 0.0016479492187500, 0.0031738281250000, +0.0013122558593750, 0.0031127929687500, 0.0013427734375000, 0.0032043457031250, +0.0013427734375000, 0.0032348632812500, 0.0011596679687500, 0.0030822753906250, +0.0012207031250000, 0.0029602050781250, 0.0013122558593750, 0.0031433105468750, +0.0011901855468750, 0.0028991699218750, 0.0011901855468750, 0.0027770996093750, +0.0012512207031250, 0.0030212402343750, 0.0010986328125000, 0.0030822753906250, +0.0009155273437500, 0.0028686523437500, 0.0010070800781250, 0.0034179687500000, +0.0009765625000000, 0.0033569335937500, 0.0007934570312500, 0.0033569335937500, +0.0009765625000000, 0.0036926269531250, 0.0011291503906250, 0.0035705566406250, +0.0009460449218750, 0.0035095214843750, 0.0016174316406250, 0.0036010742187500, +0.0014953613281250, 0.0036010742187500, 0.0017700195312500, 0.0034484863281250, +0.0022888183593750, 0.0035095214843750, 0.0019531250000000, 0.0036315917968750, +0.0027770996093750, 0.0035705566406250, 0.0026245117187500, 0.0036315917968750, +0.0028686523437500, 0.0038146972656250, 0.0034790039062500, 0.0037231445312500, +0.0031738281250000, 0.0037841796875000, 0.0039978027343750, 0.0039672851562500, +0.0039062500000000, 0.0038452148437500, 0.0041503906250000, 0.0038146972656250, +0.0048217773437500, 0.0039978027343750, 0.0044555664062500, 0.0036315917968750, +0.0052185058593750, 0.0037536621093750, 0.0052795410156250, 0.0037536621093750, +0.0052185058593750, 0.0035705566406250, 0.0056762695312500, 0.0036926269531250, +0.0056457519531250, 0.0038146972656250, 0.0052490234375000, 0.0036621093750000, +0.0054931640625000, 0.0039062500000000, 0.0050354003906250, 0.0040893554687500, +0.0044250488281250, 0.0038146972656250, 0.0048522949218750, 0.0042114257812500, +0.0036315917968750, 0.0041809082031250, 0.0036926269531250, 0.0040893554687500, +0.0034790039062500, 0.0042724609375000, 0.0026855468750000, 0.0041198730468750, +0.0029296875000000, 0.0040893554687500, 0.0023193359375000, 0.0040588378906250, +0.0022277832031250, 0.0039367675781250, 0.0022277832031250, 0.0037536621093750, +0.0019836425781250, 0.0037536621093750, 0.0019531250000000, 0.0036010742187500, +0.0018920898437500, 0.0035095214843750, 0.0018005371093750, 0.0034179687500000, +0.0016174316406250, 0.0033569335937500, 0.0015563964843750, 0.0032958984375000, +0.0015869140625000, 0.0032958984375000, 0.0013732910156250, 0.0032348632812500, +0.0013732910156250, 0.0031433105468750, 0.0014038085937500, 0.0031433105468750, +0.0013427734375000, 0.0032043457031250, 0.0014343261718750, 0.0029602050781250, +0.0015258789062500, 0.0030517578125000, 0.0015258789062500, 0.0029296875000000, +0.0016479492187500, 0.0027160644531250, 0.0017089843750000, 0.0029296875000000, +0.0017089843750000, 0.0027770996093750, 0.0020446777343750, 0.0028381347656250, +0.0018920898437500, 0.0029602050781250, 0.0020751953125000, 0.0029602050781250, +0.0024414062500000, 0.0030822753906250, 0.0021667480468750, 0.0032348632812500, +0.0024719238281250, 0.0033569335937500, 0.0025634765625000, 0.0034790039062500, +0.0024414062500000, 0.0036010742187500, 0.0024108886718750, 0.0036010742187500, +0.0024108886718750, 0.0038452148437500, 0.0024719238281250, 0.0039062500000000, +0.0024108886718750, 0.0039978027343750, 0.0025329589843750, 0.0041503906250000, +0.0026550292968750, 0.0042724609375000, 0.0025634765625000, 0.0042114257812500, +0.0028076171875000, 0.0043334960937500, 0.0028076171875000, 0.0043029785156250, +0.0028076171875000, 0.0041809082031250, 0.0029602050781250, 0.0043029785156250, +0.0028381347656250, 0.0042724609375000, 0.0029907226562500, 0.0042114257812500, +0.0028686523437500, 0.0042419433593750, 0.0031127929687500, 0.0043029785156250, +0.0033264160156250, 0.0041809082031250, 0.0030517578125000, 0.0043029785156250, +0.0038757324218750, 0.0042114257812500, 0.0036621093750000, 0.0041809082031250, +0.0038452148437500, 0.0042419433593750, 0.0045166015625000, 0.0041198730468750, +0.0040283203125000, 0.0043334960937500, 0.0044555664062500, 0.0042114257812500, +0.0044250488281250, 0.0043334960937500, 0.0042724609375000, 0.0044860839843750, +0.0043334960937500, 0.0043334960937500, 0.0041809082031250, 0.0044250488281250, +0.0042724609375000, 0.0043945312500000, 0.0041198730468750, 0.0042724609375000, +0.0041503906250000, 0.0042419433593750, 0.0041809082031250, 0.0042419433593750, +0.0040283203125000, 0.0040283203125000, 0.0041503906250000, 0.0040893554687500, +0.0040893554687500, 0.0039062500000000, 0.0040893554687500, 0.0036315917968750, +0.0041809082031250, 0.0037536621093750, 0.0041198730468750, 0.0029602050781250, +0.0041809082031250, 0.0028686523437500, 0.0042114257812500, 0.0027770996093750, +0.0042419433593750, 0.0023498535156250, 0.0043029785156250, 0.0024108886718750, +0.0042419433593750, 0.0027465820312500, 0.0043640136718750, 0.0024719238281250, +0.0044860839843750, 0.0028381347656250, 0.0043029785156250, 0.0035095214843750, +0.0041503906250000, 0.0031127929687500, 0.0043334960937500, 0.0036621093750000, +0.0036621093750000, 0.0040283203125000, 0.0039062500000000, 0.0037231445312500, +0.0035400390625000, 0.0037536621093750, 0.0028381347656250, 0.0041809082031250, +0.0033874511718750, 0.0032958984375000, 0.0028076171875000, 0.0035095214843750, +0.0026245117187500, 0.0035705566406250, 0.0031738281250000, 0.0027770996093750, +0.0036315917968750, 0.0034484863281250, 0.0041503906250000, 0.0032653808593750, +0.0021057128906250, 0.0036010742187500, 0.0024108886718750, 0.0032958984375000, +0.0024414062500000, 0.0029296875000000, 0.0019531250000000, 0.0031738281250000, +0.0019836425781250, 0.0028076171875000, 0.0024414062500000, 0.0026855468750000, +0.0022583007812500, 0.0028686523437500, 0.0025329589843750, 0.0027770996093750, +0.0029907226562500, 0.0025634765625000, 0.0026550292968750, 0.0028381347656250, +0.0032043457031250, 0.0027160644531250, 0.0031738281250000, 0.0027160644531250, +0.0031127929687500, 0.0027770996093750, 0.0033264160156250, 0.0025024414062500, +0.0032653808593750, 0.0027770996093750, 0.0028991699218750, 0.0026550292968750, +0.0032043457031250, 0.0026245117187500, 0.0028381347656250, 0.0028686523437500, +0.0023803710937500, 0.0027160644531250, 0.0028686523437500, 0.0024719238281250, +0.0022583007812500, 0.0026550292968750, 0.0021362304687500, 0.0023193359375000, +0.0023498535156250, 0.0018005371093750, 0.0021667480468750, 0.0021057128906250, +0.0020446777343750, 0.0014038085937500, 0.0026855468750000, 0.0012512207031250, +0.0026550292968750, 0.0013122558593750, 0.0026245117187500, 0.0009155273437500, +0.0031127929687500}, +{0.0016479492187500, 0.0034790039062500, 0.0012207031250000, 0.0036315917968750, +0.0015258789062500, 0.0036010742187500, 0.0012817382812500, 0.0035400390625000, +0.0011596679687500, 0.0036010742187500, 0.0014343261718750, 0.0035400390625000, +0.0016174316406250, 0.0036315917968750, 0.0014953613281250, 0.0035705566406250, +0.0020751953125000, 0.0035705566406250, 0.0020751953125000, 0.0036621093750000, +0.0021362304687500, 0.0037536621093750, 0.0024414062500000, 0.0035705566406250, +0.0023193359375000, 0.0039062500000000, 0.0023803710937500, 0.0037841796875000, +0.0022888183593750, 0.0039672851562500, 0.0024108886718750, 0.0043029785156250, +0.0024414062500000, 0.0040283203125000, 0.0021362304687500, 0.0043945312500000, +0.0027465820312500, 0.0044860839843750, 0.0025329589843750, 0.0043640136718750, +0.0025329589843750, 0.0044250488281250, 0.0029296875000000, 0.0044250488281250, +0.0026855468750000, 0.0041198730468750, 0.0028686523437500, 0.0042724609375000, +0.0028076171875000, 0.0039062500000000, 0.0025939941406250, 0.0034790039062500, +0.0025939941406250, 0.0037841796875000, 0.0025024414062500, 0.0030517578125000, +0.0025329589843750, 0.0030212402343750, 0.0024414062500000, 0.0029907226562500, +0.0023803710937500, 0.0025024414062500, 0.0023193359375000, 0.0025939941406250, +0.0023193359375000, 0.0028076171875000, 0.0026245117187500, 0.0025024414062500, +0.0024719238281250, 0.0027770996093750, 0.0025329589843750, 0.0032653808593750, +0.0027160644531250, 0.0029907226562500, 0.0026550292968750, 0.0034179687500000, +0.0031433105468750, 0.0036010742187500, 0.0029602050781250, 0.0032653808593750, +0.0032958984375000, 0.0032043457031250, 0.0038146972656250, 0.0035705566406250, +0.0036010742187500, 0.0027770996093750, 0.0045471191406250, 0.0028991699218750, +0.0043334960937500, 0.0030212402343750, 0.0045776367187500, 0.0025634765625000, +0.0054016113281250, 0.0028076171875000, 0.0050354003906250, 0.0030517578125000, +0.0046997070312500, 0.0030212402343750, 0.0052490234375000, 0.0031433105468750, +0.0045776367187500, 0.0035095214843750, 0.0028686523437500, 0.0029602050781250, +0.0036926269531250, 0.0029907226562500, 0.0037841796875000, 0.0027465820312500, +0.0044860839843750, 0.0029296875000000, 0.0037231445312500, 0.0031127929687500, +0.0029296875000000, 0.0027160644531250, 0.0036010742187500, 0.0030822753906250, +0.0020751953125000, 0.0030822753906250, 0.0023498535156250, 0.0027465820312500, +0.0021667480468750, 0.0026855468750000, 0.0010986328125000, 0.0027465820312500, +0.0016479492187500, 0.0021972656250000, 0.0010375976562500, 0.0023193359375000, +0.0008850097656250, 0.0020751953125000, 0.0011596679687500, 0.0017089843750000, +0.0009765625000000, 0.0020141601562500, 0.0009460449218750, 0.0012207031250000, +0.0017700195312500, 0.0014038085937500, 0.0013732910156250, 0.0010681152343750, +0.0018005371093750, 0.0002746582031250, 0.0027160644531250, 0.0007934570312500, +0.0021972656250000, -0.0002746582031250, 0.0028381347656250, -0.0003356933593750, +0.0030822753906250, -0.0001220703125000, 0.0026855468750000, -0.0005187988281250, +0.0027770996093750, -0.0005187988281250, 0.0030212402343750, 0.0002136230468750, +0.0021667480468750, -0.0000915527343750, 0.0022277832031250, 0.0003356933593750, +0.0023498535156250, 0.0010986328125000, 0.0019836425781250, 0.0006713867187500, +0.0021362304687500, 0.0015869140625000, 0.0021667480468750, 0.0016784667968750, +0.0022583007812500, 0.0016174316406250, 0.0023193359375000, 0.0020141601562500, +0.0024719238281250, 0.0018615722656250, 0.0027160644531250, 0.0018310546875000, +0.0022888183593750, 0.0018920898437500, 0.0025634765625000, 0.0014953613281250, +0.0023803710937500, 0.0011901855468750, 0.0019836425781250, 0.0015258789062500, +0.0023803710937500, 0.0001525878906250, 0.0018920898437500, 0.0004577636718750, +0.0018920898437500, 0.0000000000000000, 0.0021362304687500, -0.0011596679687500, +0.0020446777343750, -0.0005187988281250, 0.0021057128906250, -0.0015563964843750, +0.0025329589843750, -0.0016784667968750, 0.0024414062500000, -0.0014038085937500, +0.0026855468750000, -0.0018005371093750, 0.0031127929687500, -0.0018920898437500, +0.0028991699218750, -0.0012207031250000, 0.0034484863281250, -0.0015869140625000, +0.0033264160156250, -0.0011596679687500, 0.0031738281250000, -0.0003967285156250, +0.0035400390625000, -0.0009765625000000, 0.0033569335937500, 0.0004577636718750, +0.0030517578125000, 0.0000305175781250, 0.0029907226562500, 0.0003662109375000, +0.0031127929687500, 0.0015563964843750, 0.0030517578125000, 0.0006713867187500, +0.0028991699218750, 0.0017700195312500, 0.0032043457031250, 0.0017395019531250, +0.0031127929687500, 0.0016479492187500, 0.0030822753906250, 0.0021667480468750, +0.0032043457031250, 0.0018615722656250, 0.0029907226562500, 0.0016174316406250, +0.0031127929687500, 0.0018310546875000, 0.0030517578125000, 0.0012512207031250, +0.0029296875000000, 0.0007019042968750, 0.0029296875000000, 0.0010986328125000, +0.0028991699218750, -0.0002746582031250, 0.0028991699218750, -0.0001525878906250, +0.0027465820312500, -0.0004272460937500, 0.0028076171875000, -0.0013427734375000, +0.0029602050781250, -0.0009460449218750, 0.0028076171875000, -0.0012817382812500, +0.0030212402343750, -0.0016174316406250, 0.0030212402343750, -0.0011901855468750, +0.0029602050781250, -0.0010986328125000, 0.0029602050781250, -0.0014343261718750, +0.0029602050781250, -0.0002441406250000, 0.0027160644531250, -0.0006408691406250, +0.0028381347656250, -0.0001831054687500, 0.0027160644531250, 0.0008850097656250, +0.0024719238281250, 0.0002136230468750, 0.0026245117187500, 0.0016479492187500, +0.0025024414062500, 0.0015869140625000, 0.0024108886718750, 0.0016174316406250, +0.0025939941406250, 0.0024108886718750, 0.0025634765625000, 0.0021972656250000, +0.0024108886718750, 0.0023193359375000, 0.0030822753906250, 0.0025329589843750, +0.0028381347656250, 0.0023498535156250, 0.0030212402343750, 0.0021972656250000, +0.0035095214843750, 0.0023498535156250, 0.0031127929687500, 0.0017700195312500, +0.0035400390625000, 0.0018310546875000, 0.0035705566406250, 0.0017089843750000, +0.0034484863281250, 0.0013122558593750, 0.0036010742187500, 0.0014648437500000, +0.0035705566406250, 0.0011901855468750, 0.0034484863281250, 0.0010986328125000, +0.0035705566406250, 0.0011596679687500, 0.0035095214843750, 0.0010986328125000, +0.0032958984375000, 0.0010986328125000, 0.0035095214843750, 0.0014648437500000, +0.0033874511718750, 0.0012512207031250, 0.0032958984375000, 0.0014648437500000, +0.0034484863281250, 0.0018310546875000, 0.0034790039062500, 0.0015258789062500, +0.0032958984375000, 0.0019226074218750, 0.0036926269531250, 0.0018920898437500, +0.0034790039062500, 0.0019226074218750, 0.0036010742187500, 0.0021057128906250, +0.0039367675781250, 0.0019836425781250, 0.0036010742187500, 0.0022888183593750, +0.0039672851562500, 0.0021972656250000, 0.0039978027343750, 0.0023498535156250, +0.0039062500000000, 0.0026245117187500, 0.0039978027343750, 0.0023193359375000, +0.0039978027343750, 0.0029296875000000, 0.0039978027343750, 0.0026855468750000, +0.0038452148437500, 0.0028686523437500, 0.0038146972656250, 0.0033569335937500, +0.0039367675781250, 0.0030212402343750, 0.0039672851562500, 0.0036621093750000, +0.0039672851562500, 0.0035400390625000, 0.0039672851562500, 0.0036315917968750, +0.0039672851562500, 0.0039978027343750, 0.0039062500000000, 0.0036621093750000, +0.0038757324218750, 0.0039367675781250, 0.0038452148437500, 0.0038757324218750, +0.0037841796875000, 0.0036621093750000, 0.0039062500000000, 0.0036315917968750, +0.0039367675781250, 0.0034484863281250, 0.0038146972656250, 0.0033874511718750, +0.0041503906250000, 0.0032958984375000, 0.0040893554687500, 0.0031127929687500, +0.0040588378906250, 0.0030212402343750, 0.0042114257812500, 0.0029602050781250, +0.0041809082031250, 0.0026550292968750, 0.0040283203125000, 0.0027465820312500, +0.0040588378906250, 0.0025024414062500, 0.0039367675781250, 0.0020751953125000, +0.0037536621093750, 0.0022888183593750, 0.0038146972656250, 0.0018005371093750, +0.0035705566406250, 0.0017089843750000, 0.0035400390625000, 0.0017395019531250, +0.0034484863281250, 0.0015258789062500, 0.0032348632812500, 0.0015563964843750, +0.0032958984375000, 0.0015869140625000, 0.0030517578125000, 0.0015258789062500, +0.0030822753906250, 0.0017089843750000, 0.0029602050781250, 0.0019226074218750, +0.0027160644531250, 0.0017395019531250, 0.0028381347656250, 0.0020141601562500, +0.0026855468750000, 0.0019836425781250, 0.0026855468750000, 0.0018005371093750, +0.0028076171875000, 0.0019531250000000, 0.0027465820312500, 0.0018615722656250, +0.0026855468750000, 0.0014038085937500, 0.0029602050781250, 0.0015563964843750, +0.0028991699218750, 0.0011596679687500, 0.0029296875000000, 0.0007324218750000, +0.0031738281250000, 0.0009460449218750, 0.0029907226562500, 0.0000000000000000, +0.0030212402343750, 0.0002441406250000, 0.0031738281250000, 0.0000000000000000, +0.0029296875000000, -0.0007019042968750, 0.0028076171875000, -0.0001831054687500, +0.0029907226562500, -0.0008850097656250, 0.0024414062500000, -0.0007934570312500, +0.0025329589843750, -0.0005187988281250, 0.0025024414062500, -0.0007019042968750, +0.0021057128906250, -0.0005187988281250, 0.0022888183593750, 0.0001220703125000, +0.0021667480468750, 0.0000305175781250, 0.0020751953125000, 0.0001525878906250, +0.0020446777343750, 0.0009460449218750, 0.0019836425781250, 0.0014343261718750, +0.0020751953125000, 0.0010375976562500, 0.0018920898437500, 0.0014038085937500, +0.0019531250000000, 0.0012817382812500, 0.0019531250000000, 0.0007629394531250, +0.0018920898437500, 0.0012207031250000, 0.0018920898437500, 0.0011291503906250, +0.0019226074218750, 0.0008239746093750, 0.0018920898437500, 0.0010070800781250, +0.0019836425781250, 0.0014038085937500, 0.0020751953125000, 0.0011901855468750, +0.0019531250000000, 0.0011901855468750, 0.0021972656250000, 0.0014343261718750, +0.0021362304687500, 0.0015563964843750, 0.0020141601562500, 0.0016174316406250, +0.0020751953125000, 0.0018615722656250, 0.0019836425781250, 0.0021362304687500, +0.0017089843750000, 0.0022277832031250, 0.0017700195312500, 0.0024108886718750, +0.0014953613281250, 0.0025634765625000, 0.0010986328125000, 0.0026245117187500, +0.0013122558593750, 0.0024719238281250, 0.0009460449218750, 0.0025939941406250, +0.0007324218750000, 0.0024414062500000, 0.0009155273437500, 0.0020141601562500, +0.0009155273437500, 0.0021362304687500, 0.0006713867187500, 0.0020751953125000, +0.0011596679687500, 0.0018005371093750, 0.0010986328125000, 0.0021057128906250, +0.0011291503906250, 0.0024108886718750, 0.0014953613281250, 0.0019226074218750, +0.0013732910156250, 0.0026550292968750, 0.0012207031250000, 0.0025634765625000, +0.0013732910156250, 0.0024719238281250, 0.0012817382812500, 0.0027770996093750, +0.0010986328125000, 0.0025329589843750, 0.0011596679687500, 0.0025634765625000, +0.0009765625000000, 0.0025939941406250, 0.0009155273437500, 0.0023803710937500, +0.0010070800781250, 0.0021667480468750, 0.0009460449218750, 0.0021362304687500, +0.0008239746093750, 0.0022888183593750, 0.0009460449218750, 0.0020751953125000, +0.0009155273437500, 0.0022888183593750, 0.0008544921875000, 0.0026245117187500, +0.0008239746093750, 0.0023498535156250, 0.0007934570312500, 0.0029602050781250, +0.0007629394531250}, +{0.0036010742187500, 0.0016174316406250, 0.0034790039062500, 0.0016174316406250, +0.0034179687500000, 0.0014953613281250, 0.0034179687500000, 0.0012207031250000, +0.0033569335937500, 0.0012817382812500, 0.0032958984375000, 0.0011596679687500, +0.0033569335937500, 0.0010986328125000, 0.0033569335937500, 0.0012817382812500, +0.0032653808593750, 0.0014343261718750, 0.0033874511718750, 0.0012512207031250, +0.0033264160156250, 0.0018005371093750, 0.0032958984375000, 0.0017089843750000, +0.0033874511718750, 0.0019226074218750, 0.0033569335937500, 0.0024414062500000, +0.0033264160156250, 0.0021667480468750, 0.0033569335937500, 0.0029296875000000, +0.0031738281250000, 0.0028991699218750, 0.0032958984375000, 0.0029602050781250, +0.0030822753906250, 0.0034790039062500, 0.0028381347656250, 0.0033569335937500, +0.0031127929687500, 0.0031127929687500, 0.0026550292968750, 0.0036621093750000, +0.0027160644531250, 0.0030822753906250, 0.0026550292968750, 0.0024108886718750, +0.0024108886718750, 0.0031738281250000, 0.0026245117187500, 0.0016479492187500, +0.0023803710937500, 0.0020751953125000, 0.0023498535156250, 0.0016784667968750, +0.0023498535156250, 0.0005493164062500, 0.0021972656250000, 0.0014648437500000, +0.0022888183593750, 0.0000610351562500, 0.0021057128906250, 0.0002136230468750, +0.0020751953125000, 0.0002136230468750, 0.0021362304687500, -0.0008239746093750, +0.0020751953125000, -0.0006713867187500, 0.0021362304687500, -0.0004577636718750, +0.0022583007812500, -0.0006713867187500, 0.0022888183593750, -0.0005187988281250, +0.0023803710937500, -0.0002136230468750, 0.0024719238281250, -0.0004272460937500, +0.0025024414062500, 0.0000610351562500, 0.0024719238281250, 0.0000000000000000, +0.0025634765625000, 0.0004577636718750, 0.0023803710937500, 0.0008544921875000, +0.0021972656250000, 0.0003356933593750, 0.0023193359375000, 0.0012207031250000, +0.0018310546875000, 0.0013427734375000, 0.0018005371093750, 0.0010070800781250, +0.0016479492187500, 0.0011596679687500, 0.0012817382812500, 0.0012817382812500, +0.0013732910156250, 0.0010375976562500, 0.0011596679687500, 0.0011596679687500, +0.0010681152343750, 0.0014953613281250, 0.0010986328125000, 0.0014343261718750, +0.0010070800781250, 0.0014038085937500, 0.0010070800781250, 0.0023193359375000, +0.0011596679687500, 0.0022277832031250, 0.0012207031250000, 0.0024719238281250, +0.0010681152343750, 0.0032348632812500, 0.0011291503906250, 0.0029907226562500, +0.0012207031250000, 0.0031433105468750, 0.0010070800781250, 0.0033569335937500, +0.0010375976562500, 0.0032043457031250, 0.0010375976562500, 0.0030517578125000, +0.0008544921875000, 0.0031433105468750, 0.0008850097656250, 0.0032043457031250, +0.0013122558593750, 0.0029907226562500, 0.0010375976562500, 0.0031127929687500, +0.0013427734375000, 0.0033569335937500, 0.0018615722656250, 0.0031738281250000, +0.0014953613281250, 0.0034790039062500, 0.0020141601562500, 0.0034484863281250, +0.0020751953125000, 0.0033874511718750, 0.0019836425781250, 0.0036315917968750, +0.0021057128906250, 0.0036926269531250, 0.0020751953125000, 0.0032958984375000, +0.0020446777343750, 0.0035095214843750, 0.0019836425781250, 0.0034179687500000, +0.0021667480468750, 0.0029907226562500, 0.0022888183593750, 0.0032043457031250, +0.0021972656250000, 0.0031738281250000, 0.0026550292968750, 0.0030212402343750, +0.0027465820312500, 0.0033264160156250, 0.0028686523437500, 0.0034484863281250, +0.0032043457031250, 0.0032958984375000, 0.0032348632812500, 0.0038452148437500, +0.0031738281250000, 0.0037841796875000, 0.0032958984375000, 0.0038757324218750, +0.0032653808593750, 0.0042724609375000, 0.0031433105468750, 0.0040588378906250, +0.0032043457031250, 0.0042114257812500, 0.0030822753906250, 0.0042724609375000, +0.0030212402343750, 0.0042724609375000, 0.0031738281250000, 0.0043029785156250, +0.0031433105468750, 0.0042419433593750, 0.0030212402343750, 0.0044250488281250, +0.0034484863281250, 0.0042724609375000, 0.0033264160156250, 0.0043945312500000, +0.0033569335937500, 0.0046691894531250, 0.0037231445312500, 0.0043945312500000, +0.0036315917968750, 0.0046386718750000, 0.0035705566406250, 0.0046691894531250, +0.0037841796875000, 0.0043945312500000, 0.0033874511718750, 0.0043640136718750, +0.0030517578125000, 0.0043640136718750, 0.0033569335937500, 0.0039367675781250, +0.0024719238281250, 0.0039672851562500, 0.0025634765625000, 0.0038757324218750, +0.0023498535156250, 0.0035705566406250, 0.0016174316406250, 0.0037231445312500, +0.0019531250000000, 0.0035400390625000, 0.0013427734375000, 0.0036010742187500, +0.0013122558593750, 0.0036010742187500, 0.0012817382812500, 0.0035400390625000, +0.0009460449218750, 0.0037231445312500, 0.0010375976562500, 0.0034484863281250, +0.0008544921875000, 0.0036315917968750, 0.0009155273437500, 0.0036315917968750, +0.0008239746093750, 0.0034484863281250, 0.0006408691406250, 0.0036621093750000, +0.0007019042968750, 0.0034179687500000, 0.0000915527343750, 0.0035705566406250, +0.0001525878906250, 0.0035705566406250, 0.0000305175781250, 0.0034484863281250, +-0.0004577636718750, 0.0036010742187500, -0.0003356933593750, 0.0035400390625000, +-0.0003356933593750, 0.0036315917968750, -0.0006408691406250, 0.0036621093750000, +-0.0002136230468750, 0.0036010742187500, 0.0000915527343750, 0.0036926269531250, +-0.0002746582031250, 0.0034790039062500, 0.0010375976562500, 0.0036010742187500, +0.0007324218750000, 0.0036010742187500, 0.0012512207031250, 0.0034484863281250, +0.0024719238281250, 0.0036315917968750, 0.0018310546875000, 0.0036621093750000, +0.0032043457031250, 0.0036010742187500, 0.0031738281250000, 0.0038452148437500, +0.0032348632812500, 0.0040588378906250, 0.0039978027343750, 0.0039062500000000, +0.0036315917968750, 0.0044860839843750, 0.0040893554687500, 0.0044250488281250, +0.0040588378906250, 0.0044250488281250, 0.0041198730468750, 0.0047607421875000, +0.0043029785156250, 0.0047302246093750, 0.0041809082031250, 0.0047607421875000, +0.0042724609375000, 0.0048217773437500, 0.0042419433593750, 0.0046997070312500, +0.0041198730468750, 0.0046386718750000, 0.0041198730468750, 0.0046081542968750, +0.0042419433593750, 0.0043945312500000, 0.0038757324218750, 0.0044555664062500, +0.0040283203125000, 0.0044250488281250, 0.0038146972656250, 0.0042419433593750, +0.0034790039062500, 0.0042114257812500, 0.0037536621093750, 0.0042114257812500, +0.0029907226562500, 0.0040893554687500, 0.0031433105468750, 0.0041503906250000, +0.0029602050781250, 0.0042724609375000, 0.0022888183593750, 0.0041503906250000, +0.0025024414062500, 0.0043640136718750, 0.0022277832031250, 0.0043640136718750, +0.0019531250000000, 0.0043945312500000, 0.0021972656250000, 0.0045166015625000, +0.0023193359375000, 0.0045166015625000, 0.0021057128906250, 0.0045166015625000, +0.0027770996093750, 0.0045471191406250, 0.0026855468750000, 0.0045166015625000, +0.0027770996093750, 0.0045166015625000, 0.0032043457031250, 0.0045471191406250, +0.0029907226562500, 0.0043029785156250, 0.0029296875000000, 0.0043945312500000, +0.0029907226562500, 0.0040893554687500, 0.0026855468750000, 0.0037231445312500, +0.0022888183593750, 0.0039367675781250, 0.0024414062500000, 0.0031738281250000, +0.0019226074218750, 0.0032958984375000, 0.0017700195312500, 0.0030212402343750, +0.0019226074218750, 0.0024108886718750, 0.0017700195312500, 0.0027465820312500, +0.0016479492187500, 0.0020446777343750, 0.0019531250000000, 0.0019226074218750, +0.0019531250000000, 0.0020141601562500, 0.0018615722656250, 0.0018005371093750, +0.0019836425781250, 0.0018310546875000, 0.0020141601562500, 0.0022888183593750, +0.0018920898437500, 0.0021667480468750, 0.0020141601562500, 0.0024108886718750, +0.0018615722656250, 0.0029602050781250, 0.0016479492187500, 0.0026855468750000, +0.0018615722656250, 0.0028381347656250, 0.0014648437500000, 0.0031127929687500, +0.0014038085937500, 0.0027465820312500, 0.0017395019531250, 0.0025024414062500, +0.0017089843750000, 0.0028686523437500, 0.0015869140625000, 0.0021667480468750, +0.0023803710937500, 0.0022277832031250, 0.0021972656250000, 0.0023193359375000, +0.0024719238281250, 0.0020751953125000, 0.0031738281250000, 0.0021667480468750, +0.0027160644531250, 0.0022888183593750, 0.0034790039062500, 0.0022888183593750, +0.0036010742187500, 0.0023193359375000, 0.0032958984375000, 0.0025634765625000, +0.0033874511718750, 0.0025329589843750, 0.0034179687500000, 0.0024108886718750, +0.0029602050781250, 0.0025634765625000, 0.0029907226562500, 0.0025329589843750, +0.0026855468750000, 0.0023803710937500, 0.0023193359375000, 0.0025329589843750, +0.0025329589843750, 0.0027160644531250, 0.0017700195312500, 0.0025329589843750, +0.0018615722656250, 0.0027160644531250, 0.0019531250000000, 0.0033569335937500, +0.0014343261718750, 0.0024108886718750, 0.0023498535156250, 0.0013427734375000, +0.0016479492187500, 0.0017395019531250, 0.0018005371093750, 0.0014648437500000, +0.0016784667968750, 0.0009155273437500, 0.0013427734375000, 0.0011901855468750, +0.0014953613281250, 0.0008239746093750, 0.0017089843750000, 0.0008239746093750, +0.0015258789062500, 0.0007934570312500, 0.0019226074218750, 0.0006103515625000, +0.0023193359375000, 0.0006713867187500, 0.0021362304687500, 0.0006408691406250, +0.0029907226562500, 0.0004882812500000, 0.0028381347656250, 0.0007324218750000, +0.0032958984375000, 0.0009460449218750, 0.0040283203125000, 0.0007324218750000, +0.0036010742187500, 0.0011596679687500, 0.0044250488281250, 0.0011596679687500, +0.0047912597656250, 0.0012207031250000, 0.0041809082031250, 0.0014648437500000, +0.0042724609375000, 0.0014038085937500, 0.0048522949218750, 0.0015563964843750, +0.0030822753906250, 0.0016174316406250, 0.0035095214843750, 0.0015563964843750, +0.0029907226562500, 0.0016479492187500, 0.0014648437500000, 0.0016784667968750, +0.0022583007812500, 0.0014953613281250, 0.0013732910156250, 0.0017395019531250, +0.0008239746093750, 0.0014343261718750, 0.0015258789062500, 0.0010986328125000, +0.0017395019531250, 0.0014343261718750, 0.0012817382812500, 0.0005798339843750, +0.0028076171875000, 0.0006713867187500, 0.0025634765625000, 0.0006713867187500, +0.0027770996093750, 0.0000305175781250, 0.0037841796875000, 0.0003356933593750, +0.0032043457031250, 0.0005187988281250, 0.0035705566406250, 0.0000915527343750, +0.0036010742187500, 0.0008544921875000, 0.0035400390625000, 0.0015258789062500, +0.0036621093750000, 0.0008850097656250, 0.0035095214843750, 0.0026550292968750, +0.0035705566406250, 0.0023803710937500, 0.0035400390625000, 0.0027160644531250, +0.0034484863281250, 0.0039978027343750, 0.0035095214843750, 0.0033569335937500, +0.0036315917968750, 0.0043334960937500, 0.0036010742187500, 0.0044250488281250, +0.0036010742187500, 0.0043945312500000, 0.0035705566406250, 0.0048217773437500, +0.0036621093750000, 0.0046997070312500, 0.0037841796875000, 0.0048217773437500, +0.0033264160156250, 0.0049133300781250, 0.0034790039062500, 0.0046691894531250, +0.0035095214843750, 0.0046386718750000, 0.0031738281250000, 0.0047607421875000, +0.0033874511718750, 0.0037231445312500, 0.0035400390625000, 0.0041198730468750, +0.0034179687500000, 0.0037841796875000, 0.0036926269531250, 0.0028076171875000, +0.0039978027343750, 0.0034179687500000, 0.0038757324218750, 0.0028381347656250, +0.0042114257812500, 0.0026245117187500, 0.0043029785156250, 0.0031738281250000, +0.0043640136718750}, +{0.0020141601562500, 0.0021972656250000, 0.0019836425781250, 0.0022888183593750, +0.0018920898437500, 0.0024719238281250, 0.0018615722656250, 0.0020446777343750, +0.0019836425781250, 0.0023193359375000, 0.0017395019531250, 0.0022583007812500, +0.0019226074218750, 0.0018005371093750, 0.0023193359375000, 0.0021667480468750, +0.0019226074218750, 0.0020141601562500, 0.0022888183593750, 0.0019531250000000, +0.0022277832031250, 0.0022277832031250, 0.0022277832031250, 0.0024108886718750, +0.0023803710937500, 0.0023498535156250, 0.0021057128906250, 0.0024719238281250, +0.0024108886718750, 0.0026550292968750, 0.0023803710937500, 0.0024414062500000, +0.0021667480468750, 0.0019531250000000, 0.0021972656250000, 0.0000915527343750, +0.0017089843750000, 0.0003051757812500, 0.0018310546875000, -0.0000610351562500, +0.0019531250000000, 0.0003051757812500, 0.0019836425781250, 0.0006408691406250, +0.0021057128906250, 0.0002746582031250, 0.0021057128906250, 0.0010375976562500, +0.0016479492187500, 0.0008239746093750, 0.0019836425781250, 0.0011596679687500, +0.0018615722656250, 0.0017700195312500, 0.0014038085937500, 0.0013732910156250, +0.0018310546875000, 0.0024108886718750, 0.0014343261718750, 0.0023193359375000, +0.0016174316406250, 0.0023803710937500, 0.0017089843750000, 0.0028991699218750, +0.0013732910156250, 0.0026855468750000, 0.0017089843750000, 0.0029296875000000, +0.0021667480468750, 0.0028686523437500, 0.0018615722656250, 0.0028991699218750, +0.0025329589843750, 0.0030517578125000, 0.0033264160156250, 0.0028686523437500, +0.0029296875000000, 0.0030212402343750, 0.0039672851562500, 0.0031433105468750, +0.0042419433593750, 0.0027160644531250, 0.0038452148437500, 0.0025329589843750, +0.0042724609375000, 0.0027770996093750, 0.0044860839843750, 0.0017395019531250, +0.0029296875000000, 0.0020141601562500, 0.0036010742187500, 0.0018005371093750, +0.0029602050781250, 0.0010070800781250, 0.0013122558593750, 0.0014038085937500, +0.0021057128906250, 0.0013427734375000, 0.0010681152343750, 0.0009765625000000, +0.0005493164062500, 0.0014343261718750, 0.0012207031250000, 0.0018005371093750, +0.0012512207031250, 0.0014648437500000, 0.0008544921875000, 0.0026550292968750, +0.0024414062500000, 0.0025634765625000, 0.0023803710937500, 0.0027160644531250, +0.0025329589843750, 0.0035095214843750, 0.0036621093750000, 0.0032348632812500, +0.0035705566406250, 0.0037231445312500, 0.0037841796875000, 0.0037231445312500, +0.0041198730468750, 0.0036926269531250, 0.0038757324218750, 0.0039062500000000, +0.0036926269531250, 0.0038452148437500, 0.0039062500000000, 0.0036926269531250, +0.0032348632812500, 0.0038146972656250, 0.0034484863281250, 0.0035705566406250, +0.0034179687500000, 0.0032653808593750, 0.0030212402343750, 0.0035705566406250, +0.0033569335937500, 0.0027770996093750, 0.0033264160156250, 0.0029602050781250, +0.0032348632812500, 0.0026855468750000, 0.0033264160156250, 0.0019836425781250, +0.0035095214843750, 0.0024108886718750, 0.0034484863281250, 0.0021972656250000, +0.0034484863281250, 0.0019226074218750, 0.0034484863281250, 0.0024719238281250, +0.0035400390625000, 0.0027770996093750, 0.0035095214843750, 0.0025329589843750, +0.0033874511718750, 0.0038146972656250, 0.0037841796875000, 0.0037231445312500, +0.0036315917968750, 0.0039367675781250, 0.0037841796875000, 0.0048522949218750, +0.0041503906250000, 0.0045776367187500, 0.0038757324218750, 0.0045776367187500, +0.0040893554687500, 0.0050048828125000, 0.0042114257812500, 0.0045471191406250, +0.0039367675781250, 0.0041198730468750, 0.0038146972656250, 0.0046386718750000, +0.0040283203125000, 0.0033264160156250, 0.0035705566406250, 0.0036010742187500, +0.0036010742187500, 0.0034484863281250, 0.0036315917968750, 0.0025329589843750, +0.0033264160156250, 0.0030822753906250, 0.0035400390625000, 0.0027160644531250, +0.0034484863281250, 0.0024719238281250, 0.0034484863281250, 0.0030212402343750, +0.0035400390625000, 0.0031433105468750, 0.0035705566406250, 0.0028381347656250, +0.0036621093750000, 0.0042114257812500, 0.0036010742187500, 0.0038146972656250, +0.0038146972656250, 0.0043640136718750, 0.0036621093750000, 0.0055847167968750, +0.0035400390625000, 0.0047607421875000, 0.0038146972656250, 0.0060729980468750, +0.0034179687500000, 0.0061035156250000, 0.0034179687500000, 0.0060119628906250, +0.0034484863281250, 0.0066528320312500, 0.0032043457031250, 0.0065002441406250, +0.0032958984375000, 0.0063476562500000, 0.0033874511718750, 0.0066223144531250, +0.0031738281250000, 0.0062255859375000, 0.0033264160156250, 0.0058593750000000, +0.0035095214843750, 0.0062561035156250, 0.0032653808593750, 0.0051269531250000, +0.0036315917968750, 0.0054016113281250, 0.0035400390625000, 0.0049743652343750, +0.0034790039062500, 0.0040893554687500, 0.0037536621093750, 0.0046691894531250, +0.0036315917968750, 0.0033874511718750, 0.0036926269531250, 0.0035400390625000, +0.0037841796875000, 0.0032043457031250, 0.0036621093750000, 0.0021972656250000, +0.0035705566406250, 0.0025939941406250, 0.0037231445312500, 0.0017089843750000, +0.0034179687500000, 0.0015563964843750, 0.0035400390625000, 0.0016784667968750, +0.0033874511718750, 0.0013427734375000, 0.0031738281250000, 0.0013122558593750, +0.0034179687500000, 0.0019531250000000, 0.0030212402343750, 0.0015258789062500, +0.0031127929687500, 0.0022277832031250, 0.0029907226562500, 0.0030822753906250, +0.0026855468750000, 0.0023803710937500, 0.0028991699218750, 0.0041198730468750, +0.0025939941406250, 0.0039367675781250, 0.0025329589843750, 0.0041198730468750, +0.0025939941406250, 0.0053100585937500, 0.0025634765625000, 0.0047607421875000, +0.0025329589843750, 0.0052185058593750, 0.0026550292968750, 0.0053710937500000, +0.0026550292968750, 0.0051574707031250, 0.0026550292968750, 0.0051574707031250, +0.0027160644531250, 0.0051574707031250, 0.0027465820312500, 0.0048828125000000, +0.0027465820312500, 0.0048522949218750, 0.0028381347656250, 0.0048522949218750, +0.0028381347656250, 0.0047912597656250, 0.0028381347656250, 0.0047912597656250, +0.0029907226562500, 0.0047912597656250, 0.0030212402343750, 0.0048828125000000, +0.0030212402343750, 0.0046997070312500, 0.0031127929687500, 0.0046386718750000, +0.0031738281250000, 0.0048217773437500, 0.0032348632812500, 0.0043029785156250, +0.0030822753906250, 0.0043640136718750, 0.0032043457031250, 0.0043334960937500, +0.0031433105468750, 0.0039672851562500, 0.0029907226562500, 0.0040893554687500, +0.0031127929687500, 0.0040893554687500, 0.0029907226562500, 0.0039978027343750, +0.0028991699218750, 0.0041198730468750, 0.0029907226562500, 0.0042419433593750, +0.0030212402343750, 0.0041809082031250, 0.0029602050781250, 0.0044555664062500, +0.0030212402343750, 0.0044555664062500, 0.0031738281250000, 0.0044860839843750, +0.0030822753906250, 0.0046081542968750, 0.0030822753906250, 0.0045776367187500, +0.0032958984375000, 0.0045166015625000, 0.0029907226562500, 0.0045776367187500, +0.0032043457031250, 0.0043945312500000, 0.0029907226562500, 0.0042114257812500, +0.0026245117187500, 0.0043029785156250, 0.0031127929687500, 0.0041198730468750, +0.0024414062500000, 0.0039978027343750, 0.0026550292968750, 0.0040588378906250, +0.0025939941406250, 0.0041503906250000, 0.0021667480468750, 0.0040588378906250, +0.0025634765625000, 0.0042114257812500, 0.0021667480468750, 0.0042114257812500, +0.0023193359375000, 0.0041809082031250, 0.0023803710937500, 0.0041198730468750, +0.0022277832031250, 0.0040588378906250, 0.0024108886718750, 0.0042114257812500, +0.0023193359375000, 0.0039978027343750, 0.0023803710937500, 0.0040588378906250, +0.0024414062500000, 0.0042419433593750, 0.0022888183593750, 0.0039367675781250, +0.0024719238281250, 0.0040283203125000, 0.0025939941406250, 0.0040283203125000, +0.0025634765625000, 0.0036926269531250, 0.0026245117187500, 0.0034790039062500, +0.0028381347656250, 0.0035705566406250, 0.0027770996093750, 0.0030212402343750, +0.0025939941406250, 0.0030822753906250, 0.0027465820312500, 0.0031738281250000, +0.0025024414062500, 0.0031127929687500, 0.0020751953125000, 0.0036010742187500, +0.0021972656250000, 0.0039978027343750, 0.0018310546875000, 0.0040283203125000, +0.0018005371093750, 0.0037841796875000, 0.0017089843750000, 0.0039672851562500, +0.0014343261718750, 0.0041809082031250, 0.0013732910156250, 0.0029296875000000, +0.0014648437500000, 0.0032348632812500, 0.0011901855468750, 0.0027770996093750, +0.0013732910156250, 0.0016174316406250, 0.0016784667968750, 0.0021972656250000, +0.0013427734375000, 0.0012817382812500, 0.0019531250000000, 0.0008239746093750, +0.0018005371093750, 0.0012512207031250, 0.0018615722656250, 0.0011596679687500, +0.0022583007812500, 0.0005493164062500, 0.0021057128906250, 0.0013732910156250, +0.0023498535156250, 0.0011291503906250, 0.0023498535156250, 0.0011596679687500, +0.0023498535156250, 0.0016479492187500, 0.0025329589843750, 0.0011901855468750, +0.0025329589843750, 0.0015563964843750, 0.0027770996093750, 0.0016479492187500, +0.0027465820312500, 0.0014343261718750, 0.0027770996093750, 0.0013732910156250, +0.0030212402343750, 0.0013732910156250, 0.0030517578125000, 0.0014648437500000, +0.0029907226562500, 0.0012512207031250, 0.0032043457031250, 0.0015869140625000, +0.0030212402343750, 0.0019226074218750, 0.0028991699218750, 0.0016174316406250, +0.0031738281250000, 0.0026550292968750, 0.0026245117187500, 0.0025939941406250, +0.0026855468750000, 0.0027770996093750, 0.0027465820312500, 0.0035400390625000, +0.0025024414062500, 0.0032043457031250, 0.0025939941406250, 0.0035705566406250, +0.0026245117187500, 0.0038146972656250, 0.0026245117187500, 0.0035095214843750, +0.0025939941406250, 0.0033569335937500, 0.0026855468750000, 0.0035705566406250, +0.0027465820312500, 0.0032958984375000, 0.0025024414062500, 0.0031433105468750, +0.0025329589843750, 0.0032348632812500, 0.0024719238281250, 0.0032348632812500, +0.0021972656250000, 0.0030517578125000, 0.0022888183593750, 0.0034484863281250, +0.0023498535156250, 0.0031127929687500, 0.0020446777343750, 0.0031738281250000, +0.0022888183593750, 0.0035705566406250, 0.0025634765625000, 0.0032043457031250, +0.0021362304687500, 0.0034484863281250, 0.0027160644531250, 0.0035095214843750, +0.0026245117187500, 0.0032043457031250, 0.0025024414062500, 0.0031433105468750, +0.0028076171875000, 0.0032348632812500, 0.0026550292968750, 0.0027465820312500, +0.0026550292968750, 0.0028686523437500, 0.0026855468750000, 0.0028076171875000, +0.0025024414062500, 0.0025024414062500, 0.0022888183593750, 0.0028076171875000, +0.0023193359375000, 0.0025634765625000, 0.0022888183593750, 0.0028381347656250, +0.0020446777343750, 0.0027465820312500, 0.0023193359375000, 0.0026245117187500, +0.0025939941406250, 0.0031433105468750, 0.0021972656250000, 0.0025329589843750, +0.0032958984375000, 0.0029296875000000, 0.0030517578125000, 0.0029907226562500, +0.0032958984375000, 0.0025939941406250, 0.0040588378906250, 0.0032653808593750, +0.0035705566406250, 0.0028991699218750, 0.0044250488281250, 0.0032348632812500, +0.0043029785156250, 0.0034179687500000, 0.0043640136718750, 0.0033264160156250, +0.0048828125000000, 0.0037841796875000, 0.0045776367187500, 0.0034484863281250, +0.0050659179687500, 0.0037841796875000, 0.0050048828125000, 0.0038146972656250, +0.0050048828125000, 0.0036010742187500, 0.0053405761718750, 0.0040283203125000, +0.0052185058593750}, +{0.0012817382812500, 0.0044860839843750, 0.0012207031250000, 0.0036926269531250, +0.0016174316406250, 0.0038757324218750, 0.0013122558593750, 0.0039062500000000, +0.0014953613281250, 0.0035400390625000, 0.0018615722656250, 0.0037841796875000, +0.0014648437500000, 0.0034790039062500, 0.0021362304687500, 0.0036621093750000, +0.0020446777343750, 0.0033569335937500, 0.0020446777343750, 0.0028991699218750, +0.0023803710937500, 0.0033264160156250, 0.0021972656250000, 0.0023803710937500, +0.0022888183593750, 0.0024719238281250, 0.0022583007812500, 0.0024108886718750, +0.0022888183593750, 0.0015869140625000, 0.0022888183593750, 0.0016174316406250, +0.0021362304687500, 0.0018005371093750, 0.0024108886718750, 0.0014038085937500, +0.0023193359375000, 0.0011901855468750, 0.0023193359375000, 0.0011596679687500, +0.0025024414062500, 0.0008544921875000, 0.0023803710937500, 0.0010986328125000, +0.0025634765625000, 0.0007019042968750, 0.0025634765625000, 0.0007629394531250, +0.0024414062500000, 0.0010375976562500, 0.0024719238281250, 0.0006408691406250, +0.0024719238281250, 0.0010375976562500, 0.0023193359375000, 0.0009460449218750, +0.0023803710937500, 0.0007629394531250, 0.0023193359375000, 0.0008544921875000, +0.0021362304687500, 0.0007324218750000, 0.0021972656250000, 0.0008239746093750, +0.0019836425781250, 0.0005493164062500, 0.0019531250000000, 0.0008239746093750, +0.0018920898437500, 0.0010375976562500, 0.0016784667968750, 0.0005187988281250, +0.0017089843750000, 0.0017089843750000, 0.0014343261718750, 0.0013122558593750, +0.0014038085937500, 0.0015869140625000, 0.0013427734375000, 0.0026855468750000, +0.0010681152343750, 0.0019836425781250, 0.0010986328125000, 0.0026855468750000, +0.0010070800781250, 0.0028686523437500, 0.0009155273437500, 0.0026855468750000, +0.0009765625000000, 0.0028686523437500, 0.0010986328125000, 0.0027770996093750, +0.0009765625000000, 0.0025634765625000, 0.0011291503906250, 0.0025634765625000, +0.0010986328125000, 0.0024108886718750, 0.0010375976562500, 0.0021057128906250, +0.0010681152343750, 0.0020751953125000, 0.0010375976562500, 0.0019836425781250, +0.0010070800781250, 0.0018005371093750, 0.0009155273437500, 0.0018310546875000, +0.0008239746093750, 0.0018005371093750, 0.0007324218750000, 0.0015563964843750, +0.0007629394531250, 0.0017395019531250, 0.0007019042968750, 0.0016479492187500, +0.0006103515625000, 0.0015869140625000, 0.0006408691406250, 0.0015869140625000, +0.0006713867187500, 0.0014343261718750, 0.0005798339843750, 0.0014953613281250, +0.0007629394531250, 0.0013427734375000, 0.0007324218750000, 0.0014038085937500, +0.0007324218750000, 0.0015258789062500, 0.0008544921875000, 0.0012817382812500, +0.0007629394531250, 0.0018310546875000, 0.0007934570312500, 0.0016479492187500, +0.0007019042968750, 0.0017089843750000, 0.0007629394531250, 0.0020751953125000, +0.0007324218750000, 0.0018005371093750, 0.0006103515625000, 0.0020751953125000, +0.0011901855468750, 0.0020446777343750, 0.0009155273437500, 0.0020141601562500, +0.0012817382812500, 0.0021972656250000, 0.0019226074218750, 0.0021362304687500, +0.0014953613281250, 0.0022583007812500, 0.0027160644531250, 0.0023498535156250, +0.0025329589843750, 0.0024108886718750, 0.0026855468750000, 0.0025939941406250, +0.0035095214843750, 0.0027465820312500, 0.0030822753906250, 0.0027160644531250, +0.0036926269531250, 0.0029296875000000, 0.0036926269531250, 0.0030212402343750, +0.0035095214843750, 0.0029907226562500, 0.0036621093750000, 0.0033569335937500, +0.0036315917968750, 0.0031433105468750, 0.0033874511718750, 0.0033874511718750, +0.0034179687500000, 0.0035095214843750, 0.0032348632812500, 0.0033874511718750, +0.0030212402343750, 0.0036926269531250, 0.0030822753906250, 0.0036621093750000, +0.0026550292968750, 0.0037231445312500, 0.0027770996093750, 0.0039062500000000, +0.0026550292968750, 0.0039978027343750, 0.0023803710937500, 0.0039672851562500, +0.0025024414062500, 0.0042419433593750, 0.0022583007812500, 0.0042114257812500, +0.0022583007812500, 0.0042419433593750, 0.0023193359375000, 0.0043945312500000, +0.0021972656250000, 0.0043334960937500, 0.0022583007812500, 0.0044250488281250, +0.0022277832031250, 0.0044250488281250, 0.0022277832031250, 0.0042419433593750, +0.0022583007812500, 0.0041198730468750, 0.0022888183593750, 0.0041809082031250, +0.0022277832031250, 0.0039367675781250, 0.0023803710937500, 0.0039062500000000, +0.0023193359375000, 0.0037841796875000, 0.0024414062500000, 0.0035400390625000, +0.0026245117187500, 0.0036010742187500, 0.0025634765625000, 0.0033569335937500, +0.0027770996093750, 0.0033569335937500, 0.0027770996093750, 0.0032348632812500, +0.0028686523437500, 0.0030517578125000, 0.0030517578125000, 0.0032043457031250, +0.0030212402343750, 0.0027160644531250, 0.0033264160156250, 0.0028991699218750, +0.0033264160156250, 0.0027770996093750, 0.0033874511718750, 0.0024108886718750, +0.0035705566406250, 0.0027160644531250, 0.0035095214843750, 0.0022277832031250, +0.0035400390625000, 0.0023498535156250, 0.0035400390625000, 0.0023193359375000, +0.0035095214843750, 0.0019226074218750, 0.0034179687500000, 0.0022583007812500, +0.0033874511718750, 0.0019531250000000, 0.0032043457031250, 0.0019531250000000, +0.0031127929687500, 0.0021057128906250, 0.0030517578125000, 0.0021057128906250, +0.0029296875000000, 0.0021667480468750, 0.0028076171875000, 0.0023498535156250, +0.0028076171875000, 0.0023498535156250, 0.0026550292968750, 0.0024719238281250, +0.0025634765625000, 0.0026245117187500, 0.0025939941406250, 0.0025939941406250, +0.0024719238281250, 0.0026550292968750, 0.0024719238281250, 0.0027160644531250, +0.0024414062500000, 0.0027465820312500, 0.0022583007812500, 0.0027465820312500, +0.0021667480468750, 0.0028686523437500, 0.0022277832031250, 0.0027770996093750, +0.0016174316406250, 0.0028381347656250, 0.0017700195312500, 0.0026855468750000, +0.0016479492187500, 0.0025329589843750, 0.0010986328125000, 0.0026855468750000, +0.0012817382812500, 0.0023498535156250, 0.0010375976562500, 0.0023803710937500, +0.0010070800781250, 0.0024108886718750, 0.0009460449218750, 0.0022888183593750, +0.0008239746093750, 0.0022888183593750, 0.0010375976562500, 0.0024719238281250, +0.0008239746093750, 0.0024414062500000, 0.0009460449218750, 0.0024108886718750, +0.0008239746093750, 0.0024414062500000, 0.0006103515625000, 0.0025939941406250, +0.0008850097656250, 0.0022277832031250, 0.0006103515625000, 0.0025024414062500, +0.0006103515625000, 0.0024108886718750, 0.0008544921875000, 0.0020446777343750, +0.0008239746093750, 0.0024719238281250, 0.0007934570312500, 0.0021057128906250, +0.0013122558593750, 0.0023193359375000, 0.0011901855468750, 0.0023498535156250, +0.0015869140625000, 0.0022277832031250, 0.0019836425781250, 0.0026245117187500, +0.0016479492187500, 0.0019531250000000, 0.0032043457031250, 0.0023803710937500, +0.0029602050781250, 0.0019226074218750, 0.0033569335937500, 0.0011596679687500, +0.0047302246093750, 0.0018920898437500, 0.0043029785156250, 0.0003662109375000, +0.0048217773437500, 0.0005493164062500, 0.0051879882812500, 0.0004882812500000, +0.0050354003906250, -0.0003967285156250, 0.0050964355468750, -0.0000610351562500, +0.0052795410156250, -0.0001525878906250, 0.0046081542968750, -0.0003967285156250, +0.0049133300781250, -0.0001525878906250, 0.0046691894531250, 0.0003662109375000, +0.0034179687500000, 0.0014953613281250, 0.0031127929687500, 0.0024108886718750, +0.0034484863281250, 0.0019531250000000, 0.0032653808593750, 0.0022888183593750, +0.0033264160156250, 0.0029296875000000, 0.0036010742187500, 0.0025329589843750, +0.0034790039062500, 0.0030822753906250, 0.0034179687500000, 0.0031127929687500, +0.0033874511718750, 0.0030517578125000, 0.0032348632812500, 0.0032958984375000, +0.0032043457031250, 0.0031738281250000, 0.0032958984375000, 0.0030822753906250, +0.0023498535156250, 0.0032348632812500, 0.0023498535156250, 0.0028076171875000, +0.0023193359375000, 0.0025024414062500, 0.0018310546875000, 0.0027465820312500, +0.0018615722656250, 0.0018005371093750, 0.0018005371093750, 0.0017700195312500, +0.0019531250000000, 0.0016784667968750, 0.0014953613281250, 0.0010986328125000, +0.0011596679687500, 0.0012512207031250, 0.0016784667968750, 0.0013427734375000, +0.0005798339843750, 0.0010681152343750, 0.0007629394531250, 0.0013427734375000, +0.0006408691406250, 0.0017395019531250, -0.0001220703125000, 0.0014648437500000, +0.0003662109375000, 0.0018310546875000, 0.0000305175781250, 0.0019836425781250, +-0.0003967285156250, 0.0018005371093750, 0.0002746582031250, 0.0018310546875000, +0.0006408691406250, 0.0018920898437500, 0.0002136230468750, 0.0013732910156250, +0.0019226074218750, 0.0014648437500000, 0.0017395019531250, 0.0011901855468750, +0.0021667480468750, 0.0007019042968750, 0.0036621093750000, 0.0010375976562500, +0.0031127929687500, 0.0000610351562500, 0.0033874511718750, 0.0003356933593750, +0.0038146972656250, -0.0000610351562500, 0.0031433105468750, -0.0008850097656250, +0.0025634765625000, -0.0003662109375000, 0.0029296875000000, -0.0014038085937500, +0.0015563964843750, -0.0014648437500000, 0.0014953613281250, -0.0013427734375000, +0.0014038085937500, -0.0018920898437500, 0.0006408691406250, -0.0018310546875000, +0.0009460449218750, -0.0011596679687500, 0.0011596679687500, -0.0016174316406250, +0.0009155273437500, -0.0008544921875000, 0.0012817382812500, 0.0000915527343750, +0.0018920898437500, -0.0007934570312500, 0.0016174316406250, 0.0010070800781250, +0.0021362304687500, 0.0010375976562500, 0.0023498535156250, 0.0008850097656250, +0.0021972656250000, 0.0017089843750000, 0.0022888183593750, 0.0015258789062500, +0.0024108886718750, 0.0010070800781250, 0.0019836425781250, 0.0012512207031250, +0.0021057128906250, 0.0007934570312500, 0.0020751953125000, 0.0000610351562500, +0.0018005371093750, 0.0003967285156250, 0.0018615722656250, -0.0003967285156250, +0.0018615722656250, -0.0006713867187500, 0.0017395019531250, -0.0004272460937500, +0.0018920898437500, -0.0007629394531250, 0.0020446777343750, -0.0009765625000000, +0.0018615722656250, -0.0003051757812500, 0.0022277832031250, -0.0006103515625000, +0.0021972656250000, -0.0003051757812500, 0.0023498535156250, 0.0003051757812500, +0.0025634765625000, -0.0001525878906250, 0.0024719238281250, 0.0005798339843750, +0.0028381347656250, 0.0005493164062500, 0.0027770996093750, 0.0004577636718750, +0.0028381347656250, 0.0008239746093750, 0.0031127929687500, 0.0006713867187500, +0.0029602050781250, 0.0003356933593750, 0.0033264160156250, 0.0004882812500000, +0.0032043457031250, 0.0001831054687500, 0.0032043457031250, -0.0002746582031250, +0.0033874511718750, -0.0000305175781250, 0.0031127929687500, -0.0005187988281250, +0.0032958984375000, -0.0005493164062500, 0.0031738281250000, -0.0004577636718750, +0.0030517578125000, -0.0006103515625000, 0.0031433105468750, -0.0005187988281250, +0.0029296875000000, -0.0000610351562500, 0.0029602050781250, -0.0002136230468750, +0.0028381347656250, 0.0001220703125000, 0.0027465820312500, 0.0006103515625000, +0.0027770996093750, 0.0004272460937500, 0.0026245117187500, 0.0013427734375000, +0.0027160644531250, 0.0012817382812500, 0.0025939941406250, 0.0016174316406250, +0.0025939941406250, 0.0023193359375000, 0.0026550292968750, 0.0020446777343750, +0.0025329589843750, 0.0026855468750000, 0.0026550292968750, 0.0027160644531250, +0.0025634765625000}, +{0.0025939941406250, 0.0003051757812500, 0.0025329589843750, 0.0005187988281250, +0.0023803710937500, 0.0006713867187500, 0.0018920898437500, 0.0006713867187500, +0.0020141601562500, 0.0005798339843750, 0.0015258789062500, 0.0007934570312500, +0.0015563964843750, 0.0006103515625000, 0.0014038085937500, 0.0002136230468750, +0.0010681152343750, 0.0005187988281250, 0.0012207031250000, 0.0001525878906250, +0.0006103515625000, 0.0000915527343750, 0.0007019042968750, 0.0001831054687500, +0.0004577636718750, 0.0001220703125000, -0.0001525878906250, 0.0000915527343750, +0.0000915527343750, 0.0001525878906250, -0.0003356933593750, 0.0002136230468750, +-0.0005187988281250, 0.0001220703125000, -0.0001220703125000, 0.0001525878906250, +-0.0001525878906250, 0.0001831054687500, -0.0002746582031250, 0.0000915527343750, +0.0012207031250000, -0.0001220703125000, 0.0007934570312500, 0.0003356933593750, +0.0012512207031250, 0.0005493164062500, 0.0025634765625000, 0.0001525878906250, +0.0019226074218750, 0.0018920898437500, 0.0025939941406250, 0.0013427734375000, +0.0029907226562500, 0.0020751953125000, 0.0023193359375000, 0.0036926269531250, +0.0019836425781250, 0.0026550292968750, 0.0022888183593750, 0.0044250488281250, +0.0007934570312500, 0.0043640136718750, 0.0007934570312500, 0.0041198730468750, +0.0007324218750000, 0.0049743652343750, -0.0001831054687500, 0.0046691894531250, +0.0000000000000000, 0.0040893554687500, 0.0003051757812500, 0.0043334960937500, +-0.0001220703125000, 0.0039672851562500, 0.0004577636718750, 0.0032653808593750, +0.0011291503906250, 0.0035400390625000, 0.0005798339843750, 0.0030822753906250, +0.0021057128906250, 0.0029296875000000, 0.0019836425781250, 0.0032348632812500, +0.0022583007812500, 0.0031433105468750, 0.0033264160156250, 0.0029602050781250, +0.0028076171875000, 0.0037536621093750, 0.0033874511718750, 0.0035705566406250, +0.0034790039062500, 0.0037536621093750, 0.0032958984375000, 0.0043640136718750, +0.0033569335937500, 0.0039062500000000, 0.0031738281250000, 0.0043334960937500, +0.0031433105468750, 0.0043945312500000, 0.0030822753906250, 0.0040893554687500, +0.0029296875000000, 0.0041503906250000, 0.0027770996093750, 0.0040893554687500, +0.0028076171875000, 0.0035095214843750, 0.0027160644531250, 0.0035705566406250, +0.0025329589843750, 0.0031433105468750, 0.0026550292968750, 0.0024719238281250, +0.0026245117187500, 0.0027770996093750, 0.0025024414062500, 0.0020141601562500, +0.0026855468750000, 0.0018615722656250, 0.0026550292968750, 0.0018310546875000, +0.0026550292968750, 0.0014648437500000, 0.0027465820312500, 0.0014953613281250, +0.0027465820312500, 0.0012512207031250, 0.0027465820312500, 0.0012512207031250, +0.0028381347656250, 0.0010070800781250, 0.0027770996093750, 0.0008239746093750, +0.0027465820312500, 0.0009765625000000, 0.0028991699218750, 0.0002441406250000, +0.0027465820312500, 0.0004577636718750, 0.0028076171875000, 0.0000915527343750, +0.0028381347656250, -0.0005493164062500, 0.0027465820312500, -0.0000915527343750, +0.0027160644531250, -0.0009460449218750, 0.0029602050781250, -0.0009460449218750, +0.0027160644531250, -0.0009155273437500, 0.0028686523437500, -0.0013122558593750, +0.0031433105468750, -0.0011596679687500, 0.0028076171875000, -0.0009155273437500, +0.0033874511718750, -0.0010986328125000, 0.0032348632812500, -0.0006408691406250, +0.0032653808593750, -0.0001220703125000, 0.0036621093750000, -0.0003967285156250, +0.0033874511718750, 0.0008239746093750, 0.0037231445312500, 0.0006713867187500, +0.0037536621093750, 0.0009765625000000, 0.0036926269531250, 0.0019531250000000, +0.0038452148437500, 0.0015869140625000, 0.0037841796875000, 0.0023193359375000, +0.0037841796875000, 0.0023803710937500, 0.0038452148437500, 0.0022888183593750, +0.0037536621093750, 0.0026245117187500, 0.0037536621093750, 0.0025024414062500, +0.0038452148437500, 0.0023803710937500, 0.0036621093750000, 0.0024719238281250, +0.0037231445312500, 0.0023193359375000, 0.0036926269531250, 0.0021667480468750, +0.0036010742187500, 0.0023193359375000, 0.0035705566406250, 0.0018615722656250, +0.0036010742187500, 0.0021057128906250, 0.0036010742187500, 0.0017395019531250, +0.0035400390625000, 0.0012512207031250, 0.0035400390625000, 0.0017089843750000, +0.0036010742187500, 0.0006713867187500, 0.0033569335937500, 0.0007629394531250, +0.0034790039062500, 0.0004882812500000, 0.0034179687500000, -0.0003051757812500, +0.0032043457031250, 0.0001525878906250, 0.0033264160156250, -0.0003967285156250, +0.0031738281250000, -0.0006103515625000, 0.0032043457031250, -0.0001525878906250, +0.0032043457031250, -0.0001220703125000, 0.0031127929687500, -0.0003662109375000, +0.0031127929687500, 0.0011291503906250, 0.0032043457031250, 0.0007934570312500, +0.0032043457031250, 0.0014343261718750, 0.0032653808593750, 0.0027770996093750, +0.0034179687500000, 0.0020446777343750, 0.0033264160156250, 0.0033874511718750, +0.0032958984375000, 0.0035400390625000, 0.0033874511718750, 0.0033874511718750, +0.0032653808593750, 0.0038757324218750, 0.0032043457031250, 0.0038146972656250, +0.0033264160156250, 0.0034790039062500, 0.0030517578125000, 0.0035705566406250, +0.0030517578125000, 0.0034484863281250, 0.0029602050781250, 0.0031738281250000, +0.0027770996093750, 0.0032348632812500, 0.0028076171875000, 0.0029602050781250, +0.0026855468750000, 0.0029907226562500, 0.0026245117187500, 0.0028991699218750, +0.0026855468750000, 0.0027465820312500, 0.0025939941406250, 0.0028076171875000, +0.0025329589843750, 0.0025634765625000, 0.0027160644531250, 0.0026855468750000, +0.0024719238281250, 0.0025329589843750, 0.0025024414062500, 0.0022583007812500, +0.0026550292968750, 0.0025939941406250, 0.0024108886718750, 0.0021057128906250, +0.0027160644531250, 0.0022277832031250, 0.0026245117187500, 0.0022277832031250, +0.0026245117187500, 0.0019836425781250, 0.0027465820312500, 0.0022277832031250, +0.0025939941406250, 0.0020141601562500, 0.0026245117187500, 0.0022277832031250, +0.0026550292968750, 0.0021667480468750, 0.0025329589843750, 0.0019226074218750, +0.0024414062500000, 0.0022583007812500, 0.0024719238281250, 0.0017395019531250, +0.0023193359375000, 0.0018615722656250, 0.0023803710937500, 0.0016174316406250, +0.0022888183593750, 0.0011596679687500, 0.0021362304687500, 0.0014648437500000, +0.0022583007812500, 0.0006408691406250, 0.0021667480468750, 0.0006103515625000, +0.0020751953125000, 0.0006103515625000, 0.0021362304687500, 0.0001220703125000, +0.0021667480468750, 0.0001831054687500, 0.0021362304687500, 0.0006103515625000, +0.0023803710937500, 0.0002136230468750, 0.0023193359375000, 0.0005798339843750, +0.0023803710937500, 0.0012817382812500, 0.0025634765625000, 0.0010375976562500, +0.0023193359375000, 0.0020141601562500, 0.0021057128906250, 0.0017089843750000, +0.0021972656250000, 0.0020751953125000, 0.0021362304687500, 0.0029907226562500, +0.0019836425781250, 0.0025939941406250, 0.0020751953125000, 0.0036621093750000, +0.0017700195312500, 0.0039978027343750, 0.0018310546875000, 0.0038146972656250, +0.0017700195312500, 0.0042419433593750, 0.0016174316406250, 0.0044555664062500, +0.0017395019531250, 0.0035705566406250, 0.0016479492187500, 0.0042419433593750, +0.0017089843750000, 0.0037536621093750, 0.0015563964843750, 0.0027160644531250, +0.0013427734375000, 0.0035705566406250, 0.0015563964843750, 0.0022888183593750, +0.0013122558593750, 0.0025329589843750, 0.0012512207031250, 0.0028381347656250, +0.0013122558593750, 0.0021667480468750, 0.0011596679687500, 0.0024719238281250, +0.0012512207031250, 0.0025634765625000, 0.0013427734375000, 0.0027160644531250, +0.0013427734375000, 0.0025939941406250, 0.0013122558593750, 0.0025024414062500, +0.0014648437500000, 0.0027160644531250, 0.0014953613281250, 0.0020446777343750, +0.0015258789062500, 0.0023498535156250, 0.0015258789062500, 0.0020446777343750, +0.0016784667968750, 0.0014038085937500, 0.0017700195312500, 0.0018310546875000, +0.0017089843750000, 0.0011291503906250, 0.0023498535156250, 0.0011291503906250, +0.0021972656250000, 0.0012512207031250, 0.0024719238281250, 0.0009765625000000, +0.0029907226562500, 0.0011291503906250, 0.0026245117187500, 0.0011901855468750, +0.0035095214843750, 0.0011901855468750, 0.0033569335937500, 0.0010986328125000, +0.0035095214843750, 0.0009460449218750, 0.0040588378906250, 0.0010681152343750, +0.0036315917968750, 0.0007019042968750, 0.0042419433593750, 0.0007019042968750, +0.0041198730468750, 0.0006713867187500, 0.0041503906250000, 0.0004882812500000, +0.0044555664062500, 0.0005187988281250, 0.0041198730468750, 0.0007324218750000, +0.0044860839843750, 0.0004577636718750, 0.0044555664062500, 0.0008850097656250, +0.0043029785156250, 0.0013732910156250, 0.0043945312500000, 0.0009765625000000, +0.0042419433593750, 0.0018615722656250, 0.0043334960937500, 0.0018005371093750, +0.0041503906250000, 0.0018920898437500, 0.0042419433593750, 0.0025024414062500, +0.0043640136718750, 0.0021362304687500, 0.0040893554687500, 0.0023193359375000, +0.0044860839843750, 0.0023803710937500, 0.0044250488281250, 0.0022583007812500, +0.0044250488281250, 0.0021362304687500, 0.0046997070312500, 0.0021362304687500, +0.0045166015625000, 0.0022583007812500, 0.0046997070312500, 0.0020141601562500, +0.0047912597656250, 0.0021667480468750, 0.0046386718750000, 0.0023803710937500, +0.0046691894531250, 0.0020751953125000, 0.0048522949218750, 0.0026550292968750, +0.0042724609375000, 0.0024414062500000, 0.0045471191406250, 0.0025634765625000, +0.0041503906250000, 0.0029602050781250, 0.0035400390625000, 0.0026855468750000, +0.0039367675781250, 0.0031127929687500, 0.0027160644531250, 0.0030517578125000, +0.0027465820312500, 0.0031433105468750, 0.0023803710937500, 0.0033874511718750, +0.0013732910156250, 0.0031738281250000, 0.0017395019531250, 0.0036621093750000, +0.0006713867187500, 0.0034179687500000, 0.0007019042968750, 0.0035095214843750, +0.0005187988281250, 0.0038146972656250, -0.0001831054687500, 0.0033569335937500, +0.0000915527343750, 0.0037841796875000, -0.0003051757812500, 0.0035095214843750, +-0.0003662109375000, 0.0034484863281250, -0.0002441406250000, 0.0036315917968750, +-0.0003967285156250, 0.0031738281250000, -0.0004272460937500, 0.0036010742187500, +-0.0002441406250000, 0.0032348632812500, -0.0003051757812500, 0.0032348632812500, +-0.0001831054687500, 0.0035095214843750, 0.0000000000000000, 0.0030212402343750, +-0.0002136230468750, 0.0033569335937500, 0.0002746582031250, 0.0032348632812500, +0.0001220703125000, 0.0030822753906250, 0.0003051757812500, 0.0032348632812500, +0.0006103515625000, 0.0031433105468750, 0.0003356933593750, 0.0029296875000000, +0.0008239746093750, 0.0029907226562500, 0.0006408691406250, 0.0028381347656250, +0.0007629394531250, 0.0026550292968750, 0.0011291503906250, 0.0028076171875000, +0.0010070800781250, 0.0025634765625000, 0.0014038085937500, 0.0025634765625000, +0.0013122558593750, 0.0027465820312500, 0.0014038085937500, 0.0027770996093750, +0.0016784667968750, 0.0027160644531250, 0.0014648437500000, 0.0029296875000000, +0.0017089843750000, 0.0028991699218750, 0.0017089843750000, 0.0029602050781250, +0.0015869140625000, 0.0030517578125000, 0.0015869140625000, 0.0030212402343750, +0.0015869140625000, 0.0031127929687500, 0.0010375976562500, 0.0030822753906250, +0.0010681152343750, 0.0030822753906250, 0.0008544921875000, 0.0031433105468750, +0.0003967285156250}, +{0.0043029785156250, 0.0025024414062500, 0.0046386718750000, 0.0029296875000000, +0.0043945312500000, 0.0024108886718750, 0.0044555664062500, 0.0024414062500000, +0.0044555664062500, 0.0025634765625000, 0.0043029785156250, 0.0023193359375000, +0.0041503906250000, 0.0024719238281250, 0.0040588378906250, 0.0023193359375000, +0.0038452148437500, 0.0023803710937500, 0.0037841796875000, 0.0023193359375000, +0.0037231445312500, 0.0022583007812500, 0.0035705566406250, 0.0024108886718750, +0.0035095214843750, 0.0016174316406250, 0.0035095214843750, 0.0018310546875000, +0.0034484863281250, 0.0016784667968750, 0.0034790039062500, 0.0010070800781250, +0.0034484863281250, 0.0014038085937500, 0.0034484863281250, 0.0013427734375000, +0.0036315917968750, 0.0011291503906250, 0.0035400390625000, 0.0015563964843750, +0.0036621093750000, 0.0018005371093750, 0.0037841796875000, 0.0016174316406250, +0.0036315917968750, 0.0026245117187500, 0.0039672851562500, 0.0025024414062500, +0.0038146972656250, 0.0027160644531250, 0.0038146972656250, 0.0034179687500000, +0.0039978027343750, 0.0031738281250000, 0.0036315917968750, 0.0035095214843750, +0.0037536621093750, 0.0037231445312500, 0.0036926269531250, 0.0037231445312500, +0.0035095214843750, 0.0038146972656250, 0.0034179687500000, 0.0038757324218750, +0.0033569335937500, 0.0039062500000000, 0.0030517578125000, 0.0039367675781250, +0.0030212402343750, 0.0039978027343750, 0.0029296875000000, 0.0040588378906250, +0.0027160644531250, 0.0039672851562500, 0.0027160644531250, 0.0042114257812500, +0.0028381347656250, 0.0042114257812500, 0.0027160644531250, 0.0042114257812500, +0.0028991699218750, 0.0043640136718750, 0.0031127929687500, 0.0043640136718750, +0.0029602050781250, 0.0042114257812500, 0.0035705566406250, 0.0043640136718750, +0.0035095214843750, 0.0043640136718750, 0.0036621093750000, 0.0042419433593750, +0.0040893554687500, 0.0043945312500000, 0.0037841796875000, 0.0043029785156250, +0.0039978027343750, 0.0044250488281250, 0.0041503906250000, 0.0043945312500000, +0.0038146972656250, 0.0044250488281250, 0.0036315917968750, 0.0046081542968750, +0.0037536621093750, 0.0042724609375000, 0.0029296875000000, 0.0044555664062500, +0.0030212402343750, 0.0043334960937500, 0.0025939941406250, 0.0039978027343750, +0.0018615722656250, 0.0042724609375000, 0.0021057128906250, 0.0037231445312500, +0.0010375976562500, 0.0037841796875000, 0.0010681152343750, 0.0036621093750000, +0.0006408691406250, 0.0032043457031250, -0.0001220703125000, 0.0034484863281250, +0.0002136230468750, 0.0031433105468750, -0.0005798339843750, 0.0030822753906250, +-0.0007019042968750, 0.0031433105468750, -0.0007019042968750, 0.0030822753906250, +-0.0010375976562500, 0.0030517578125000, -0.0010070800781250, 0.0031433105468750, +-0.0007629394531250, 0.0032043457031250, -0.0010375976562500, 0.0032043457031250, +-0.0007934570312500, 0.0032043457031250, -0.0004577636718750, 0.0032653808593750, +-0.0007934570312500, 0.0032348632812500, -0.0000915527343750, 0.0032348632812500, +-0.0002441406250000, 0.0032653808593750, 0.0000000000000000, 0.0032653808593750, +0.0005798339843750, 0.0032653808593750, 0.0001831054687500, 0.0033874511718750, +0.0009460449218750, 0.0033264160156250, 0.0008850097656250, 0.0034484863281250, +0.0008544921875000, 0.0035095214843750, 0.0013122558593750, 0.0034179687500000, +0.0011291503906250, 0.0038757324218750, 0.0011291503906250, 0.0036926269531250, +0.0013122558593750, 0.0039062500000000, 0.0009765625000000, 0.0043029785156250, +0.0007324218750000, 0.0039367675781250, 0.0010375976562500, 0.0045166015625000, +0.0002136230468750, 0.0043945312500000, 0.0003356933593750, 0.0043029785156250, +0.0003662109375000, 0.0045166015625000, -0.0002136230468750, 0.0043029785156250, +-0.0000305175781250, 0.0043334960937500, 0.0000305175781250, 0.0042114257812500, +-0.0001525878906250, 0.0040893554687500, 0.0001220703125000, 0.0039978027343750, +0.0004272460937500, 0.0038757324218750, 0.0001831054687500, 0.0038757324218750, +0.0006408691406250, 0.0037536621093750, 0.0006408691406250, 0.0038146972656250, +0.0006713867187500, 0.0038757324218750, 0.0008850097656250, 0.0036621093750000, +0.0007324218750000, 0.0038452148437500, 0.0010375976562500, 0.0037536621093750, +0.0009155273437500, 0.0035705566406250, 0.0011901855468750, 0.0036010742187500, +0.0015869140625000, 0.0036315917968750, 0.0013427734375000, 0.0031127929687500, +0.0021362304687500, 0.0032653808593750, 0.0021057128906250, 0.0030517578125000, +0.0022583007812500, 0.0025939941406250, 0.0028381347656250, 0.0028991699218750, +0.0027160644531250, 0.0024108886718750, 0.0029296875000000, 0.0023803710937500, +0.0031127929687500, 0.0023193359375000, 0.0030212402343750, 0.0020141601562500, +0.0029907226562500, 0.0021667480468750, 0.0031127929687500, 0.0017395019531250, +0.0028686523437500, 0.0018615722656250, 0.0029296875000000, 0.0016479492187500, +0.0029602050781250, 0.0011901855468750, 0.0028381347656250, 0.0014953613281250, +0.0028991699218750, 0.0010375976562500, 0.0029296875000000, 0.0009460449218750, +0.0029602050781250, 0.0011901855468750, 0.0028991699218750, 0.0010681152343750, +0.0028076171875000, 0.0008544921875000, 0.0028686523437500, 0.0015869140625000, +0.0025329589843750, 0.0012817382812500, 0.0025329589843750, 0.0016174316406250, +0.0025329589843750, 0.0022277832031250, 0.0024108886718750, 0.0017395019531250, +0.0024108886718750, 0.0025939941406250, 0.0027465820312500, 0.0024719238281250, +0.0025024414062500, 0.0025634765625000, 0.0027160644531250, 0.0030822753906250, +0.0032348632812500, 0.0027160644531250, 0.0030212402343750, 0.0032958984375000, +0.0029907226562500, 0.0031127929687500, 0.0031127929687500, 0.0032043457031250, +0.0029602050781250, 0.0036315917968750, 0.0027770996093750, 0.0032348632812500, +0.0028991699218750, 0.0036621093750000, 0.0024108886718750, 0.0036621093750000, +0.0026550292968750, 0.0034179687500000, 0.0025024414062500, 0.0035095214843750, +0.0017395019531250, 0.0023498535156250, 0.0026550292968750, 0.0009155273437500, +0.0027160644531250, 0.0014038085937500, 0.0027770996093750, 0.0011596679687500, +0.0027770996093750, 0.0003051757812500, 0.0027770996093750, 0.0005798339843750, +0.0028381347656250, 0.0006103515625000, 0.0028991699218750, 0.0003662109375000, +0.0027465820312500, 0.0006713867187500, 0.0030517578125000, 0.0009155273437500, +0.0036010742187500, 0.0005493164062500, 0.0033874511718750, 0.0012512207031250, +0.0031738281250000, 0.0011291503906250, 0.0033874511718750, 0.0012817382812500, +0.0034179687500000, 0.0017700195312500, 0.0031127929687500, 0.0014343261718750, +0.0031127929687500, 0.0021362304687500, 0.0035095214843750, 0.0020446777343750, +0.0032348632812500, 0.0021667480468750, 0.0034179687500000, 0.0026550292968750, +0.0038146972656250, 0.0024719238281250, 0.0034179687500000, 0.0027770996093750, +0.0040283203125000, 0.0028991699218750, 0.0039672851562500, 0.0027770996093750, +0.0037231445312500, 0.0028076171875000, 0.0039367675781250, 0.0029296875000000, +0.0038757324218750, 0.0030822753906250, 0.0034179687500000, 0.0029296875000000, +0.0035095214843750, 0.0033264160156250, 0.0033264160156250, 0.0036926269531250, +0.0028076171875000, 0.0034179687500000, 0.0029296875000000, 0.0047912597656250, +0.0027465820312500, 0.0045776367187500, 0.0023803710937500, 0.0048522949218750, +0.0025329589843750, 0.0059814453125000, 0.0027160644531250, 0.0054931640625000, +0.0023803710937500, 0.0056152343750000, 0.0026550292968750, 0.0061645507812500, +0.0027465820312500, 0.0054626464843750, 0.0024719238281250, 0.0048217773437500, +0.0024108886718750, 0.0054626464843750, 0.0025024414062500, 0.0037841796875000, +0.0017700195312500, 0.0039062500000000, 0.0015869140625000, 0.0038146972656250, +0.0015563964843750, 0.0028076171875000, 0.0010375976562500, 0.0032043457031250, +0.0009155273437500, 0.0029602050781250, 0.0016784667968750, 0.0027160644531250, +0.0011291503906250, 0.0030822753906250, 0.0016479492187500, 0.0033264160156250, +0.0027465820312500, 0.0031127929687500, 0.0020141601562500, 0.0036926269531250, +0.0033264160156250, 0.0038452148437500, 0.0033569335937500, 0.0036621093750000, +0.0032653808593750, 0.0037231445312500, 0.0039062500000000, 0.0038757324218750, +0.0036926269531250, 0.0032653808593750, 0.0033569335937500, 0.0034790039062500, +0.0037536621093750, 0.0031127929687500, 0.0033264160156250, 0.0025634765625000, +0.0026550292968750, 0.0031127929687500, 0.0032043457031250, 0.0021667480468750, +0.0024719238281250, 0.0023498535156250, 0.0024108886718750, 0.0022888183593750, +0.0027465820312500, 0.0016784667968750, 0.0026550292968750, 0.0021667480468750, +0.0026550292968750, 0.0016479492187500, 0.0033264160156250, 0.0016784667968750, +0.0031433105468750, 0.0018005371093750, 0.0033569335937500, 0.0015563964843750, +0.0039978027343750, 0.0016174316406250, 0.0037536621093750, 0.0016479492187500, +0.0040893554687500, 0.0017089843750000, 0.0042114257812500, 0.0015869140625000, +0.0041809082031250, 0.0015869140625000, 0.0043640136718750, 0.0017395019531250, +0.0043334960937500, 0.0014953613281250, 0.0043334960937500, 0.0014953613281250, +0.0043640136718750, 0.0016784667968750, 0.0043029785156250, 0.0015869140625000, +0.0042114257812500, 0.0015563964843750, 0.0040893554687500, 0.0022277832031250, +0.0041503906250000, 0.0019226074218750, 0.0039978027343750, 0.0024719238281250, +0.0039672851562500, 0.0031738281250000, 0.0039672851562500, 0.0026855468750000, +0.0038452148437500, 0.0039062500000000, 0.0039367675781250, 0.0037841796875000, +0.0038452148437500, 0.0039062500000000, 0.0038757324218750, 0.0047302246093750, +0.0040283203125000, 0.0042724609375000, 0.0039062500000000, 0.0044555664062500, +0.0041503906250000, 0.0046997070312500, 0.0042419433593750, 0.0042419433593750, +0.0042724609375000, 0.0039367675781250, 0.0044250488281250, 0.0041503906250000, +0.0044250488281250, 0.0029907226562500, 0.0044555664062500, 0.0031738281250000, +0.0044555664062500, 0.0025939941406250, 0.0044860839843750, 0.0015563964843750, +0.0044250488281250, 0.0020751953125000, 0.0044555664062500, 0.0007324218750000, +0.0044555664062500, 0.0007629394531250, 0.0044555664062500, 0.0005798339843750, +0.0044555664062500, -0.0003662109375000, 0.0045166015625000, -0.0000915527343750, +0.0045166015625000, -0.0005187988281250, 0.0045166015625000, -0.0007324218750000, +0.0045471191406250, -0.0004882812500000, 0.0046081542968750, -0.0004272460937500, +0.0046691894531250, -0.0006408691406250, 0.0046386718750000, 0.0001831054687500, +0.0046997070312500, 0.0000305175781250, 0.0047607421875000, 0.0003662109375000, +0.0046691894531250, 0.0010681152343750, 0.0045776367187500, 0.0007324218750000, +0.0047302246093750, 0.0014953613281250, 0.0043945312500000, 0.0014648437500000, +0.0044555664062500, 0.0015869140625000, 0.0043640136718750, 0.0020751953125000, +0.0041809082031250, 0.0017700195312500, 0.0042724609375000, 0.0018920898437500, +0.0040893554687500, 0.0020141601562500, 0.0041198730468750, 0.0018615722656250, +0.0040893554687500, 0.0018005371093750, 0.0040283203125000, 0.0018615722656250, +0.0040283203125000, 0.0017089843750000, 0.0038757324218750, 0.0016784667968750, +0.0038757324218750, 0.0016784667968750, 0.0038146972656250, 0.0016174316406250, +0.0036315917968750, 0.0016784667968750, 0.0037231445312500, 0.0014648437500000, +0.0034790039062500}, +{0.0014343261718750, 0.0001831054687500, 0.0012512207031250, 0.0003356933593750, +0.0008544921875000, 0.0001831054687500, 0.0012207031250000, -0.0006713867187500, +0.0015869140625000, -0.0002746582031250, 0.0011291503906250, -0.0009155273437500, +0.0024108886718750, -0.0008544921875000, 0.0021362304687500, -0.0008850097656250, +0.0025634765625000, -0.0011291503906250, 0.0036010742187500, -0.0009765625000000, +0.0030212402343750, -0.0014038085937500, 0.0037231445312500, -0.0011596679687500, +0.0039367675781250, -0.0013427734375000, 0.0036926269531250, -0.0017089843750000, +0.0036926269531250, -0.0014038085937500, 0.0037841796875000, -0.0020141601562500, +0.0036315917968750, -0.0019226074218750, 0.0035400390625000, -0.0019226074218750, +0.0037536621093750, -0.0023193359375000, 0.0037841796875000, -0.0020446777343750, +0.0035400390625000, -0.0021362304687500, 0.0041809082031250, -0.0021972656250000, +0.0039978027343750, -0.0017700195312500, 0.0042419433593750, -0.0016784667968750, +0.0047607421875000, -0.0018615722656250, 0.0043945312500000, -0.0006103515625000, +0.0049743652343750, -0.0009155273437500, 0.0050354003906250, -0.0004272460937500, +0.0049133300781250, 0.0007324218750000, 0.0051879882812500, 0.0001220703125000, +0.0051574707031250, 0.0012817382812500, 0.0048828125000000, 0.0014343261718750, +0.0050964355468750, 0.0013732910156250, 0.0048217773437500, 0.0018920898437500, +0.0043945312500000, 0.0018310546875000, 0.0047912597656250, 0.0016174316406250, +0.0039672851562500, 0.0018615722656250, 0.0040588378906250, 0.0016479492187500, +0.0040588378906250, 0.0012207031250000, 0.0035400390625000, 0.0016174316406250, +0.0037231445312500, 0.0011901855468750, 0.0035705566406250, 0.0011291503906250, +0.0034484863281250, 0.0014343261718750, 0.0035400390625000, 0.0014038085937500, +0.0036315917968750, 0.0013427734375000, 0.0035400390625000, 0.0021057128906250, +0.0038757324218750, 0.0019531250000000, 0.0038146972656250, 0.0022583007812500, +0.0038452148437500, 0.0029296875000000, 0.0040588378906250, 0.0025329589843750, +0.0040283203125000, 0.0031738281250000, 0.0039062500000000, 0.0032348632812500, +0.0039978027343750, 0.0030212402343750, 0.0039367675781250, 0.0032653808593750, +0.0038146972656250, 0.0031433105468750, 0.0040283203125000, 0.0026855468750000, +0.0036621093750000, 0.0029602050781250, 0.0038757324218750, 0.0025024414062500, +0.0037536621093750, 0.0019226074218750, 0.0035400390625000, 0.0024108886718750, +0.0038146972656250, 0.0015869140625000, 0.0032043457031250, 0.0015869140625000, +0.0033569335937500, 0.0016174316406250, 0.0033264160156250, 0.0011291503906250, +0.0029296875000000, 0.0012817382812500, 0.0031127929687500, 0.0014343261718750, +0.0029296875000000, 0.0012207031250000, 0.0029296875000000, 0.0014343261718750, +0.0029296875000000, 0.0017089843750000, 0.0028686523437500, 0.0014648437500000, +0.0029907226562500, 0.0020751953125000, 0.0028991699218750, 0.0019531250000000, +0.0028991699218750, 0.0020141601562500, 0.0029296875000000, 0.0024719238281250, +0.0028686523437500, 0.0021667480468750, 0.0029296875000000, 0.0023803710937500, +0.0029907226562500, 0.0023803710937500, 0.0029602050781250, 0.0021972656250000, +0.0029602050781250, 0.0021667480468750, 0.0030212402343750, 0.0021972656250000, +0.0030212402343750, 0.0018310546875000, 0.0030822753906250, 0.0018310546875000, +0.0031127929687500, 0.0016174316406250, 0.0030517578125000, 0.0013732910156250, +0.0030517578125000, 0.0014648437500000, 0.0029907226562500, 0.0009155273437500, +0.0029602050781250, 0.0010070800781250, 0.0029907226562500, 0.0007934570312500, +0.0028991699218750, 0.0003356933593750, 0.0028686523437500, 0.0005493164062500, +0.0029296875000000, 0.0002136230468750, 0.0028381347656250, 0.0000000000000000, +0.0028381347656250, 0.0003356933593750, 0.0027770996093750, 0.0003967285156250, +0.0027465820312500, 0.0001831054687500, 0.0028686523437500, 0.0012817382812500, +0.0026245117187500, 0.0010986328125000, 0.0027465820312500, 0.0014648437500000, +0.0026245117187500, 0.0024414062500000, 0.0024108886718750, 0.0020141601562500, +0.0025634765625000, 0.0027160644531250, 0.0021057128906250, 0.0028686523437500, +0.0021667480468750, 0.0027770996093750, 0.0021057128906250, 0.0030212402343750, +0.0017395019531250, 0.0030212402343750, 0.0018615722656250, 0.0031127929687500, +0.0019226074218750, 0.0029907226562500, 0.0017395019531250, 0.0032043457031250, +0.0018310546875000, 0.0033874511718750, 0.0019836425781250, 0.0031433105468750, +0.0017395019531250, 0.0036621093750000, 0.0020446777343750, 0.0036010742187500, +0.0020446777343750, 0.0036926269531250, 0.0020141601562500, 0.0039672851562500, +0.0021972656250000, 0.0037536621093750, 0.0021057128906250, 0.0039062500000000, +0.0021972656250000, 0.0040588378906250, 0.0021972656250000, 0.0040588378906250, +0.0020751953125000, 0.0040588378906250, 0.0020141601562500, 0.0040588378906250, +0.0020141601562500, 0.0041198730468750, 0.0019226074218750, 0.0041503906250000, +0.0017700195312500, 0.0039978027343750, 0.0018310546875000, 0.0039062500000000, +0.0018615722656250, 0.0039978027343750, 0.0017089843750000, 0.0034790039062500, +0.0019531250000000, 0.0034790039062500, 0.0018920898437500, 0.0033264160156250, +0.0019531250000000, 0.0028686523437500, 0.0020141601562500, 0.0029296875000000, +0.0018920898437500, 0.0028381347656250, 0.0022888183593750, 0.0028686523437500, +0.0020141601562500, 0.0028076171875000, 0.0022888183593750, 0.0028076171875000, +0.0027465820312500, 0.0028381347656250, 0.0023498535156250, 0.0024108886718750, +0.0032043457031250, 0.0025939941406250, 0.0030822753906250, 0.0024414062500000, +0.0032043457031250, 0.0018615722656250, 0.0037536621093750, 0.0019836425781250, +0.0034179687500000, 0.0022277832031250, 0.0037536621093750, 0.0016174316406250, +0.0038146972656250, 0.0020141601562500, 0.0037231445312500, 0.0026245117187500, +0.0038757324218750, 0.0017700195312500, 0.0037536621093750, 0.0030822753906250, +0.0039062500000000, 0.0028991699218750, 0.0038452148437500, 0.0029602050781250, +0.0038146972656250, 0.0036621093750000, 0.0038452148437500, 0.0032348632812500, +0.0037536621093750, 0.0037841796875000, 0.0037231445312500, 0.0038452148437500, +0.0036926269531250, 0.0038146972656250, 0.0035095214843750, 0.0041198730468750, +0.0034484863281250, 0.0039978027343750, 0.0033874511718750, 0.0039367675781250, +0.0027465820312500, 0.0042114257812500, 0.0028686523437500, 0.0038757324218750, +0.0024719238281250, 0.0034484863281250, 0.0018615722656250, 0.0038757324218750, +0.0021362304687500, 0.0028381347656250, 0.0011901855468750, 0.0029907226562500, +0.0012512207031250, 0.0030212402343750, 0.0010986328125000, 0.0024108886718750, +0.0004272460937500, 0.0026855468750000, 0.0007324218750000, 0.0026855468750000, +0.0003051757812500, 0.0027465820312500, 0.0003662109375000, 0.0028991699218750, +0.0003356933593750, 0.0031127929687500, 0.0001525878906250, 0.0032958984375000, +0.0003967285156250, 0.0032653808593750, 0.0000610351562500, 0.0035400390625000, +0.0002441406250000, 0.0034179687500000, 0.0002441406250000, 0.0032043457031250, +-0.0000915527343750, 0.0035400390625000, 0.0001525878906250, 0.0030822753906250, +0.0000000000000000, 0.0030822753906250, -0.0000610351562500, 0.0031738281250000, +0.0000000000000000, 0.0030517578125000, -0.0000610351562500, 0.0031433105468750, +-0.0001525878906250, 0.0030517578125000, -0.0000305175781250, 0.0030212402343750, +-0.0000610351562500, 0.0031127929687500, -0.0001220703125000, 0.0031738281250000, +-0.0000915527343750, 0.0031433105468750, -0.0002136230468750, 0.0030212402343750, +-0.0002441406250000, 0.0031738281250000, -0.0003051757812500, 0.0030517578125000, +-0.0003051757812500, 0.0027770996093750, -0.0003051757812500, 0.0028991699218750, +-0.0003662109375000, 0.0026550292968750, -0.0001220703125000, 0.0025939941406250, +-0.0002441406250000, 0.0026855468750000, 0.0000000000000000, 0.0025634765625000, +0.0003051757812500, 0.0025939941406250, 0.0000915527343750, 0.0028381347656250, +0.0008850097656250, 0.0028076171875000, 0.0007629394531250, 0.0028991699218750, +0.0009765625000000, 0.0032348632812500, 0.0015563964843750, 0.0032043457031250, +0.0012207031250000, 0.0033264160156250, 0.0018920898437500, 0.0034179687500000, +0.0018310546875000, 0.0034484863281250, 0.0018920898437500, 0.0034179687500000, +0.0023498535156250, 0.0036010742187500, 0.0020446777343750, 0.0032958984375000, +0.0023498535156250, 0.0033264160156250, 0.0023193359375000, 0.0033874511718750, +0.0023498535156250, 0.0032653808593750, 0.0025329589843750, 0.0033264160156250, +0.0023498535156250, 0.0032653808593750, 0.0027770996093750, 0.0032958984375000, +0.0026855468750000, 0.0033569335937500, 0.0028991699218750, 0.0033874511718750, +0.0032653808593750, 0.0033569335937500, 0.0030822753906250, 0.0033874511718750, +0.0035400390625000, 0.0033569335937500, 0.0036621093750000, 0.0034484863281250, +0.0036010742187500, 0.0035095214843750, 0.0038452148437500, 0.0034179687500000, +0.0039367675781250, 0.0036926269531250, 0.0036926269531250, 0.0035705566406250, +0.0038757324218750, 0.0036621093750000, 0.0037536621093750, 0.0039062500000000, +0.0034790039062500, 0.0037231445312500, 0.0036010742187500, 0.0040283203125000, +0.0031127929687500, 0.0039367675781250, 0.0032043457031250, 0.0039672851562500, +0.0030822753906250, 0.0041503906250000, 0.0025939941406250, 0.0039367675781250, +0.0028686523437500, 0.0041198730468750, 0.0023498535156250, 0.0040283203125000, +0.0023803710937500, 0.0040283203125000, 0.0022888183593750, 0.0041198730468750, +0.0019836425781250, 0.0039978027343750, 0.0021972656250000, 0.0041198730468750, +0.0016784667968750, 0.0040588378906250, 0.0018310546875000, 0.0040283203125000, +0.0015869140625000, 0.0040893554687500, 0.0011901855468750, 0.0039978027343750, +0.0015258789062500, 0.0039672851562500, 0.0008239746093750, 0.0040283203125000, +0.0008850097656250, 0.0038146972656250, 0.0007629394531250, 0.0036621093750000, +0.0002441406250000, 0.0037841796875000, 0.0005187988281250, 0.0033264160156250, +0.0003662109375000, 0.0033874511718750, 0.0001220703125000, 0.0032653808593750, +0.0004272460937500, 0.0029602050781250, 0.0005798339843750, 0.0031127929687500, +0.0003356933593750, 0.0029602050781250, 0.0010986328125000, 0.0029602050781250, +0.0009765625000000, 0.0029602050781250, 0.0011596679687500, 0.0028991699218750, +0.0018615722656250, 0.0029296875000000, 0.0015258789062500, 0.0029602050781250, +0.0016784667968750, 0.0029602050781250, 0.0019836425781250, 0.0029296875000000, +0.0014038085937500, 0.0029602050781250, 0.0010681152343750, 0.0029296875000000, +0.0014648437500000, 0.0028381347656250, 0.0000915527343750, 0.0028381347656250, +0.0002746582031250, 0.0028076171875000, 0.0000000000000000, 0.0026550292968750, +-0.0009765625000000, 0.0027160644531250, -0.0005493164062500, 0.0025634765625000, +-0.0008239746093750, 0.0025634765625000, -0.0010681152343750, 0.0025329589843750, +-0.0006408691406250, 0.0024719238281250, -0.0003662109375000, 0.0025329589843750, +-0.0005493164062500, 0.0023803710937500, 0.0004272460937500, 0.0024414062500000, +0.0002746582031250, 0.0023803710937500, 0.0005493164062500, 0.0021972656250000, +0.0012207031250000, 0.0022888183593750, 0.0008850097656250, 0.0023803710937500, +0.0015563964843750, 0.0022277832031250, 0.0014038085937500, 0.0024414062500000, +0.0016479492187500}, +{0.0013122558593750, 0.0005493164062500, 0.0011901855468750, 0.0006408691406250, +0.0008544921875000, 0.0003356933593750, 0.0009765625000000, 0.0010681152343750, +0.0007019042968750, 0.0007934570312500, 0.0006103515625000, 0.0009765625000000, +0.0005493164062500, 0.0015563964843750, 0.0003662109375000, 0.0011596679687500, +0.0003662109375000, 0.0018310546875000, 0.0005187988281250, 0.0018005371093750, +0.0003356933593750, 0.0018310546875000, 0.0005798339843750, 0.0021972656250000, +0.0009155273437500, 0.0020446777343750, 0.0006713867187500, 0.0022583007812500, +0.0010986328125000, 0.0023498535156250, 0.0011291503906250, 0.0024108886718750, +0.0012512207031250, 0.0025329589843750, 0.0014648437500000, 0.0026550292968750, +0.0014343261718750, 0.0027465820312500, 0.0017700195312500, 0.0028381347656250, +0.0017089843750000, 0.0029296875000000, 0.0019836425781250, 0.0030822753906250, +0.0024108886718750, 0.0030212402343750, 0.0021362304687500, 0.0030822753906250, +0.0031433105468750, 0.0031127929687500, 0.0030517578125000, 0.0030822753906250, +0.0033874511718750, 0.0030822753906250, 0.0041809082031250, 0.0030822753906250, +0.0038146972656250, 0.0030212402343750, 0.0045166015625000, 0.0029602050781250, +0.0046386718750000, 0.0029907226562500, 0.0044860839843750, 0.0030212402343750, +0.0046997070312500, 0.0029296875000000, 0.0046997070312500, 0.0030517578125000, +0.0041809082031250, 0.0029602050781250, 0.0043640136718750, 0.0028991699218750, +0.0039367675781250, 0.0029602050781250, 0.0033264160156250, 0.0028991699218750, +0.0036315917968750, 0.0027160644531250, 0.0025024414062500, 0.0027160644531250, +0.0025634765625000, 0.0025024414062500, 0.0022888183593750, 0.0023193359375000, +0.0015258789062500, 0.0024108886718750, 0.0018005371093750, 0.0019531250000000, +0.0012512207031250, 0.0019531250000000, 0.0011901855468750, 0.0019226074218750, +0.0011596679687500, 0.0016174316406250, 0.0009155273437500, 0.0017395019531250, +0.0010070800781250, 0.0015563964843750, 0.0007934570312500, 0.0015563964843750, +0.0007934570312500, 0.0015258789062500, 0.0007629394531250, 0.0014953613281250, +0.0005798339843750, 0.0015869140625000, 0.0006713867187500, 0.0013732910156250, +0.0007324218750000, 0.0014953613281250, 0.0006408691406250, 0.0015258789062500, +0.0008544921875000, 0.0013122558593750, 0.0008850097656250, 0.0014343261718750, +0.0007019042968750, 0.0014343261718750, 0.0014953613281250, 0.0013732910156250, +0.0013427734375000, 0.0014953613281250, 0.0016174316406250, 0.0015869140625000, +0.0022583007812500, 0.0015563964843750, 0.0018615722656250, 0.0017089843750000, +0.0024414062500000, 0.0016479492187500, 0.0025634765625000, 0.0016174316406250, +0.0022277832031250, 0.0016784667968750, 0.0023193359375000, 0.0015869140625000, +0.0022888183593750, 0.0015258789062500, 0.0014343261718750, 0.0014648437500000, +0.0016479492187500, 0.0015563964843750, 0.0012817382812500, 0.0015563964843750, +0.0005187988281250, 0.0014953613281250, 0.0008850097656250, 0.0018920898437500, +0.0004577636718750, 0.0017089843750000, 0.0002441406250000, 0.0020446777343750, +0.0005493164062500, 0.0025634765625000, 0.0007629394531250, 0.0021057128906250, +0.0006408691406250, 0.0030822753906250, 0.0012207031250000, 0.0031127929687500, +0.0012817382812500, 0.0031433105468750, 0.0012817382812500, 0.0036621093750000, +0.0015563964843750, 0.0035095214843750, 0.0015563964843750, 0.0036010742187500, +0.0014343261718750, 0.0036621093750000, 0.0014953613281250, 0.0035095214843750, +0.0014343261718750, 0.0034179687500000, 0.0012817382812500, 0.0034484863281250, +0.0013732910156250, 0.0032958984375000, 0.0016479492187500, 0.0032043457031250, +0.0014953613281250, 0.0032043457031250, 0.0018920898437500, 0.0031433105468750, +0.0024108886718750, 0.0029907226562500, 0.0021362304687500, 0.0030212402343750, +0.0029296875000000, 0.0029907226562500, 0.0028991699218750, 0.0028381347656250, +0.0031433105468750, 0.0028076171875000, 0.0037536621093750, 0.0028381347656250, +0.0035095214843750, 0.0021057128906250, 0.0037231445312500, 0.0023498535156250, +0.0039062500000000, 0.0018005371093750, 0.0036926269531250, 0.0010070800781250, +0.0034790039062500, 0.0014953613281250, 0.0035400390625000, 0.0003967285156250, +0.0034179687500000, 0.0003967285156250, 0.0033264160156250, 0.0004577636718750, +0.0032958984375000, -0.0001220703125000, 0.0034179687500000, 0.0000305175781250, +0.0032348632812500, 0.0003356933593750, 0.0030517578125000, 0.0000610351562500, +0.0032348632812500, 0.0003356933593750, 0.0028991699218750, 0.0012207031250000, +0.0020751953125000, 0.0023803710937500, 0.0030517578125000, 0.0026550292968750, +0.0029296875000000, 0.0024719238281250, 0.0032653808593750, 0.0026550292968750, +0.0028076171875000, 0.0027770996093750, 0.0022888183593750, 0.0025329589843750, +0.0025024414062500, 0.0031433105468750, 0.0018615722656250, 0.0030212402343750, +0.0016784667968750, 0.0030822753906250, 0.0018005371093750, 0.0034484863281250, +0.0017089843750000, 0.0032043457031250, 0.0015258789062500, 0.0037536621093750, +0.0013732910156250, 0.0036315917968750, 0.0014953613281250, 0.0037841796875000, +0.0013122558593750, 0.0042114257812500, 0.0010070800781250, 0.0039978027343750, +0.0010986328125000, 0.0039978027343750, 0.0010375976562500, 0.0043029785156250, +0.0006713867187500, 0.0037536621093750, 0.0012512207031250, 0.0033569335937500, +0.0016784667968750, 0.0038452148437500, 0.0011291503906250, 0.0022583007812500, +0.0030212402343750, 0.0025024414062500, 0.0028686523437500, 0.0022277832031250, +0.0030212402343750, 0.0010681152343750, 0.0041503906250000, 0.0017089843750000, +0.0036926269531250, 0.0010070800781250, 0.0043029785156250, 0.0007934570312500, +0.0044250488281250, 0.0010070800781250, 0.0041198730468750, 0.0008850097656250, +0.0042114257812500, 0.0007934570312500, 0.0043640136718750, 0.0008850097656250, +0.0037536621093750, 0.0008850097656250, 0.0038452148437500, 0.0006713867187500, +0.0037841796875000, 0.0006103515625000, 0.0033264160156250, 0.0006713867187500, +0.0035095214843750, 0.0002441406250000, 0.0036621093750000, 0.0001525878906250, +0.0032958984375000, 0.0001525878906250, 0.0036621093750000, -0.0000915527343750, +0.0043334960937500, -0.0001220703125000, 0.0039672851562500, -0.0000305175781250, +0.0041198730468750, -0.0002136230468750, 0.0044250488281250, 0.0000305175781250, +0.0040588378906250, 0.0002136230468750, 0.0036621093750000, -0.0001525878906250, +0.0038757324218750, 0.0004882812500000, 0.0032653808593750, 0.0003662109375000, +0.0030212402343750, 0.0003051757812500, 0.0031433105468750, 0.0007019042968750, +0.0028991699218750, 0.0003967285156250, 0.0026855468750000, 0.0003051757812500, +0.0033569335937500, 0.0003356933593750, 0.0030822753906250, 0.0001525878906250, +0.0031127929687500, -0.0000915527343750, 0.0036315917968750, -0.0000915527343750, +0.0032043457031250, -0.0002136230468750, 0.0032348632812500, -0.0005187988281250, +0.0033569335937500, -0.0000915527343750, 0.0028991699218750, 0.0001220703125000, +0.0024719238281250, -0.0003356933593750, 0.0026550292968750, 0.0014343261718750, +0.0018615722656250, 0.0008239746093750, 0.0018615722656250, 0.0015258789062500, +0.0018005371093750, 0.0030822753906250, 0.0014038085937500, 0.0019531250000000, +0.0014953613281250, 0.0037536621093750, 0.0016479492187500, 0.0038146972656250, +0.0015258789062500, 0.0035095214843750, 0.0016784667968750, 0.0042724609375000, +0.0019836425781250, 0.0039367675781250, 0.0020751953125000, 0.0033569335937500, +0.0020446777343750, 0.0036315917968750, 0.0022277832031250, 0.0028076171875000, +0.0022277832031250, 0.0018920898437500, 0.0021362304687500, 0.0025024414062500, +0.0022277832031250, 0.0007934570312500, 0.0021667480468750, 0.0007629394531250, +0.0021667480468750, 0.0006103515625000, 0.0022888183593750, -0.0003662109375000, +0.0021667480468750, -0.0000915527343750, 0.0021057128906250, -0.0003356933593750, +0.0023498535156250, -0.0006408691406250, 0.0021667480468750, -0.0003051757812500, +0.0023498535156250, -0.0000915527343750, 0.0026245117187500, -0.0003967285156250, +0.0023193359375000, 0.0003967285156250, 0.0028381347656250, 0.0003051757812500, +0.0028381347656250, 0.0003662109375000, 0.0028381347656250, 0.0008544921875000, +0.0031127929687500, 0.0006103515625000, 0.0028991699218750, 0.0005798339843750, +0.0029602050781250, 0.0007934570312500, 0.0029602050781250, 0.0004882812500000, +0.0028991699218750, 0.0001220703125000, 0.0028076171875000, 0.0003662109375000, +0.0027770996093750, -0.0002136230468750, 0.0026550292968750, -0.0002441406250000, +0.0025634765625000, -0.0000915527343750, 0.0025024414062500, -0.0003967285156250, +0.0023498535156250, -0.0003662109375000, 0.0023193359375000, 0.0001525878906250, +0.0022583007812500, -0.0001220703125000, 0.0021972656250000, 0.0004882812500000, +0.0022583007812500, 0.0012512207031250, 0.0022888183593750, 0.0008239746093750, +0.0022277832031250, 0.0025634765625000, 0.0022888183593750, 0.0022888183593750, +0.0023193359375000, 0.0028991699218750, 0.0022277832031250, 0.0043029785156250, +0.0022583007812500, 0.0036010742187500, 0.0022888183593750, 0.0051269531250000, +0.0021972656250000, 0.0051574707031250, 0.0022583007812500, 0.0051574707031250, +0.0022583007812500, 0.0058593750000000, 0.0021667480468750, 0.0055847167968750, +0.0022277832031250, 0.0054626464843750, 0.0023193359375000, 0.0057678222656250, +0.0022888183593750, 0.0053100585937500, 0.0023498535156250, 0.0049133300781250, +0.0024108886718750, 0.0052185058593750, 0.0023498535156250, 0.0041809082031250, +0.0025024414062500, 0.0043945312500000, 0.0025024414062500, 0.0040893554687500, +0.0025939941406250, 0.0033264160156250, 0.0027465820312500, 0.0037536621093750, +0.0026245117187500, 0.0031738281250000, 0.0028686523437500, 0.0031127929687500, +0.0028381347656250, 0.0032958984375000, 0.0028076171875000, 0.0031127929687500, +0.0028686523437500, 0.0031433105468750, 0.0027770996093750, 0.0033569335937500, +0.0028076171875000, 0.0033264160156250, 0.0027160644531250, 0.0034179687500000, +0.0026550292968750, 0.0036010742187500, 0.0027160644531250, 0.0036315917968750, +0.0025939941406250, 0.0037536621093750, 0.0026855468750000, 0.0038757324218750, +0.0025939941406250, 0.0038146972656250, 0.0025634765625000, 0.0038452148437500, +0.0026245117187500, 0.0039672851562500, 0.0024719238281250, 0.0037841796875000, +0.0024108886718750, 0.0038757324218750, 0.0023803710937500, 0.0038146972656250, +0.0022583007812500, 0.0036315917968750, 0.0021667480468750, 0.0037231445312500, +0.0021362304687500, 0.0031433105468750, 0.0020751953125000, 0.0032653808593750, +0.0019836425781250, 0.0029602050781250, 0.0020141601562500, 0.0022888183593750, +0.0020446777343750, 0.0025634765625000, 0.0020141601562500, 0.0019226074218750, +0.0021667480468750, 0.0016479492187500, 0.0020751953125000, 0.0018005371093750, +0.0020751953125000, 0.0015869140625000, 0.0021972656250000, 0.0014953613281250, +0.0021057128906250, 0.0021057128906250, 0.0021362304687500, 0.0018920898437500, +0.0021362304687500, 0.0021057128906250, 0.0020751953125000, 0.0025939941406250, +0.0020446777343750, 0.0021972656250000, 0.0020751953125000, 0.0026550292968750, +0.0019226074218750, 0.0027160644531250, 0.0019226074218750, 0.0025329589843750, +0.0020141601562500, 0.0026245117187500, 0.0018920898437500, 0.0025939941406250, +0.0018920898437500}, +{0.0029602050781250, 0.0053100585937500, 0.0032043457031250, 0.0043334960937500, +0.0028686523437500, 0.0045776367187500, 0.0028686523437500, 0.0040893554687500, +0.0029907226562500, 0.0031433105468750, 0.0028381347656250, 0.0036010742187500, +0.0028991699218750, 0.0025024414062500, 0.0032043457031250, 0.0023803710937500, +0.0030822753906250, 0.0023498535156250, 0.0033264160156250, 0.0017700195312500, +0.0036315917968750, 0.0018615722656250, 0.0034790039062500, 0.0016479492187500, +0.0039062500000000, 0.0016174316406250, 0.0038452148437500, 0.0016479492187500, +0.0038452148437500, 0.0016174316406250, 0.0040893554687500, 0.0017395019531250, +0.0039062500000000, 0.0016479492187500, 0.0040283203125000, 0.0018005371093750, +0.0040283203125000, 0.0018615722656250, 0.0039367675781250, 0.0018005371093750, +0.0039367675781250, 0.0019836425781250, 0.0039367675781250, 0.0020141601562500, +0.0040588378906250, 0.0020751953125000, 0.0039672851562500, 0.0021667480468750, +0.0040588378906250, 0.0022583007812500, 0.0042114257812500, 0.0022888183593750, +0.0041198730468750, 0.0024719238281250, 0.0041503906250000, 0.0025329589843750, +0.0041809082031250, 0.0025634765625000, 0.0041198730468750, 0.0027770996093750, +0.0040283203125000, 0.0028381347656250, 0.0040893554687500, 0.0027770996093750, +0.0039062500000000, 0.0029907226562500, 0.0038757324218750, 0.0027160644531250, +0.0037841796875000, 0.0025329589843750, 0.0036926269531250, 0.0028686523437500, +0.0036926269531250, 0.0020446777343750, 0.0035400390625000, 0.0022888183593750, +0.0035400390625000, 0.0020446777343750, 0.0035095214843750, 0.0013122558593750, +0.0032958984375000, 0.0017395019531250, 0.0033264160156250, 0.0010681152343750, +0.0032348632812500, 0.0009765625000000, 0.0031127929687500, 0.0010986328125000, +0.0030212402343750, 0.0008850097656250, 0.0028991699218750, 0.0009460449218750, +0.0027465820312500, 0.0014038085937500, 0.0028381347656250, 0.0012207031250000, +0.0026855468750000, 0.0016174316406250, 0.0026245117187500, 0.0022277832031250, +0.0026550292968750, 0.0018920898437500, 0.0024719238281250, 0.0029296875000000, +0.0025939941406250, 0.0029602050781250, 0.0024414062500000, 0.0030212402343750, +0.0024108886718750, 0.0036621093750000, 0.0025024414062500, 0.0035095214843750, +0.0023193359375000, 0.0037231445312500, 0.0025024414062500, 0.0038452148437500, +0.0023193359375000, 0.0037841796875000, 0.0023803710937500, 0.0038146972656250, +0.0025634765625000, 0.0037536621093750, 0.0022888183593750, 0.0038452148437500, +0.0026550292968750, 0.0037841796875000, 0.0025024414062500, 0.0038452148437500, +0.0025329589843750, 0.0040283203125000, 0.0027770996093750, 0.0038146972656250, +0.0024414062500000, 0.0038757324218750, 0.0028381347656250, 0.0038757324218750, +0.0026245117187500, 0.0034484863281250, 0.0026550292968750, 0.0032348632812500, +0.0028991699218750, 0.0035400390625000, 0.0025634765625000, 0.0028686523437500, +0.0028686523437500, 0.0028991699218750, 0.0028076171875000, 0.0029907226562500, +0.0027160644531250, 0.0026550292968750, 0.0028686523437500, 0.0026550292968750, +0.0026855468750000, 0.0029907226562500, 0.0026245117187500, 0.0027160644531250, +0.0026245117187500, 0.0029296875000000, 0.0025329589843750, 0.0033874511718750, +0.0024414062500000, 0.0030822753906250, 0.0024108886718750, 0.0033874511718750, +0.0023803710937500, 0.0034484863281250, 0.0022888183593750, 0.0031738281250000, +0.0022277832031250, 0.0031433105468750, 0.0021972656250000, 0.0032653808593750, +0.0021667480468750, 0.0026245117187500, 0.0021057128906250, 0.0028076171875000, +0.0021972656250000, 0.0025024414062500, 0.0019836425781250, 0.0018920898437500, +0.0018310546875000, 0.0022888183593750, 0.0021057128906250, 0.0016784667968750, +0.0013122558593750, 0.0016174316406250, 0.0015563964843750, 0.0017700195312500, +0.0014038085937500, 0.0015869140625000, 0.0007019042968750, 0.0015563964843750, +0.0010986328125000, 0.0020141601562500, 0.0007019042968750, 0.0017700195312500, +0.0007629394531250, 0.0018005371093750, 0.0008239746093750, 0.0020751953125000, +0.0006408691406250, 0.0017700195312500, 0.0007629394531250, 0.0022888183593750, +0.0007324218750000, 0.0021057128906250, 0.0007934570312500, 0.0021667480468750, +0.0008239746093750, 0.0026855468750000, 0.0007934570312500, 0.0024719238281250, +0.0009460449218750, 0.0024414062500000, 0.0008239746093750, 0.0029907226562500, +0.0008850097656250, 0.0024108886718750, 0.0010375976562500, 0.0019226074218750, +0.0010070800781250, 0.0028686523437500, 0.0010375976562500, 0.0014648437500000, +0.0014038085937500, 0.0015258789062500, 0.0013427734375000, 0.0018310546875000, +0.0016174316406250, 0.0011596679687500, 0.0020141601562500, 0.0013732910156250, +0.0018310546875000, 0.0018920898437500, 0.0026245117187500, 0.0014648437500000, +0.0025939941406250, 0.0018005371093750, 0.0027465820312500, 0.0024719238281250, +0.0033569335937500, 0.0019531250000000, 0.0032043457031250, 0.0025939941406250, +0.0034179687500000, 0.0025939941406250, 0.0036010742187500, 0.0025329589843750, +0.0035705566406250, 0.0028381347656250, 0.0036926269531250, 0.0026245117187500, +0.0038146972656250, 0.0027770996093750, 0.0036315917968750, 0.0027770996093750, +0.0037231445312500, 0.0027770996093750, 0.0038146972656250, 0.0028686523437500, +0.0037841796875000, 0.0026855468750000, 0.0038146972656250, 0.0029296875000000, +0.0039672851562500, 0.0027465820312500, 0.0040283203125000, 0.0028381347656250, +0.0040588378906250, 0.0030822753906250, 0.0041809082031250, 0.0028686523437500, +0.0041809082031250, 0.0030212402343750, 0.0041198730468750, 0.0033264160156250, +0.0042419433593750, 0.0029602050781250, 0.0043334960937500, 0.0027770996093750, +0.0043334960937500, 0.0033264160156250, 0.0044860839843750, 0.0023498535156250, +0.0047302246093750, 0.0026245117187500, 0.0046691894531250, 0.0025939941406250, +0.0050659179687500, 0.0019531250000000, 0.0054931640625000, 0.0025329589843750, +0.0053100585937500, 0.0022277832031250, 0.0059509277343750, 0.0021972656250000, +0.0060119628906250, 0.0025634765625000, 0.0060729980468750, 0.0028381347656250, +0.0064086914062500, 0.0027465820312500, 0.0062866210937500, 0.0032653808593750, +0.0060424804687500, 0.0033569335937500, 0.0061950683593750, 0.0034179687500000, +0.0059204101562500, 0.0036621093750000, 0.0054931640625000, 0.0037841796875000, +0.0057067871093750, 0.0035095214843750, 0.0051574707031250, 0.0037231445312500, +0.0051269531250000, 0.0037536621093750, 0.0051879882812500, 0.0034484863281250, +0.0049438476562500, 0.0036621093750000, 0.0050659179687500, 0.0035705566406250, +0.0049743652343750, 0.0035400390625000, 0.0050964355468750, 0.0035705566406250, +0.0049743652343750, 0.0036315917968750, 0.0048522949218750, 0.0035705566406250, +0.0051269531250000, 0.0036010742187500, 0.0044555664062500, 0.0035400390625000, +0.0048217773437500, 0.0034179687500000, 0.0044250488281250, 0.0033569335937500, +0.0037231445312500, 0.0032653808593750, 0.0043029785156250, 0.0030822753906250, +0.0029602050781250, 0.0029602050781250, 0.0032348632812500, 0.0028991699218750, +0.0029602050781250, 0.0027160644531250, 0.0020141601562500, 0.0024719238281250, +0.0025634765625000, 0.0027770996093750, 0.0016479492187500, 0.0024719238281250, +0.0017395019531250, 0.0025329589843750, 0.0015869140625000, 0.0028076171875000, +0.0010375976562500, 0.0023193359375000, 0.0013732910156250, 0.0028991699218750, +0.0004272460937500, 0.0026550292968750, 0.0005187988281250, 0.0025939941406250, +0.0003051757812500, 0.0029296875000000, -0.0004272460937500, 0.0025329589843750, +-0.0002136230468750, 0.0027770996093750, -0.0004577636718750, 0.0027160644531250, +-0.0007629394531250, 0.0026245117187500, -0.0004272460937500, 0.0027160644531250, +-0.0003051757812500, 0.0025329589843750, -0.0006408691406250, 0.0025329589843750, +0.0005798339843750, 0.0025634765625000, 0.0001220703125000, 0.0025024414062500, +0.0007629394531250, 0.0025024414062500, 0.0019531250000000, 0.0025024414062500, +0.0011291503906250, 0.0023803710937500, 0.0030822753906250, 0.0025024414062500, +0.0028991699218750, 0.0024108886718750, 0.0032348632812500, 0.0022277832031250, +0.0045776367187500, 0.0023803710937500, 0.0039672851562500, 0.0021972656250000, +0.0046997070312500, 0.0022583007812500, 0.0048217773437500, 0.0022888183593750, +0.0045776367187500, 0.0021362304687500, 0.0047302246093750, 0.0023498535156250, +0.0048217773437500, 0.0022277832031250, 0.0041503906250000, 0.0022277832031250, +0.0043334960937500, 0.0021972656250000, 0.0038757324218750, 0.0021057128906250, +0.0031433105468750, 0.0021362304687500, 0.0035400390625000, 0.0022277832031250, +0.0025024414062500, 0.0021057128906250, 0.0024108886718750, 0.0021667480468750, +0.0022583007812500, 0.0022888183593750, 0.0017395019531250, 0.0020141601562500, +0.0019531250000000, 0.0023193359375000, 0.0014648437500000, 0.0021057128906250, +0.0014038085937500, 0.0020446777343750, 0.0014953613281250, 0.0021667480468750, +0.0013427734375000, 0.0019531250000000, 0.0013122558593750, 0.0020141601562500, +0.0014953613281250, 0.0019226074218750, 0.0014038085937500, 0.0018615722656250, +0.0014343261718750, 0.0018615722656250, 0.0016174316406250, 0.0017700195312500, +0.0014953613281250, 0.0018310546875000, 0.0013732910156250, 0.0017395019531250, +0.0014953613281250, 0.0018615722656250, 0.0013732910156250, 0.0020141601562500, +0.0011596679687500, 0.0019531250000000, 0.0013122558593750, 0.0022277832031250, +0.0011596679687500, 0.0023193359375000, 0.0010070800781250, 0.0022277832031250, +0.0012207031250000, 0.0022277832031250, 0.0013427734375000, 0.0023193359375000, +0.0011291503906250, 0.0020141601562500, 0.0017395019531250, 0.0020751953125000, +0.0016174316406250, 0.0020446777343750, 0.0016479492187500, 0.0017700195312500, +0.0019836425781250, 0.0018920898437500, 0.0016784667968750, 0.0021057128906250, +0.0018615722656250, 0.0018615722656250, 0.0017089843750000, 0.0019836425781250, +0.0017089843750000, 0.0022583007812500, 0.0017395019531250, 0.0018920898437500, +0.0015563964843750, 0.0024414062500000, 0.0019836425781250, 0.0023193359375000, +0.0016784667968750, 0.0022277832031250, 0.0019531250000000, 0.0024414062500000, +0.0025329589843750, 0.0023193359375000, 0.0020446777343750, 0.0020751953125000, +0.0029602050781250, 0.0021972656250000, 0.0028686523437500, 0.0019226074218750, +0.0027160644531250, 0.0015869140625000, 0.0031433105468750, 0.0016784667968750, +0.0029907226562500, 0.0013732910156250, 0.0031738281250000, 0.0011291503906250, +0.0031433105468750, 0.0013122558593750, 0.0030212402343750, 0.0012817382812500, +0.0031738281250000, 0.0010070800781250, 0.0031433105468750, 0.0017395019531250, +0.0026550292968750, 0.0014038085937500, 0.0028076171875000, 0.0016479492187500, +0.0026245117187500, 0.0023193359375000, 0.0021667480468750, 0.0018310546875000, +0.0023193359375000, 0.0025939941406250, 0.0020141601562500, 0.0025329589843750, +0.0019226074218750, 0.0026245117187500, 0.0021362304687500, 0.0030517578125000, +0.0021667480468750, 0.0028076171875000, 0.0021057128906250, 0.0032958984375000, +0.0024108886718750, 0.0032653808593750, 0.0023803710937500, 0.0032653808593750, +0.0023193359375000, 0.0037841796875000, 0.0024719238281250, 0.0038757324218750, +0.0039978027343750, 0.0034790039062500, 0.0031738281250000, 0.0037231445312500, +0.0036315917968750}, +{-0.0010681152343750, 0.0026855468750000, -0.0011901855468750, 0.0027770996093750, +-0.0011596679687500, 0.0028381347656250, -0.0014343261718750, 0.0028381347656250, +-0.0014343261718750, 0.0029296875000000, -0.0010681152343750, 0.0029907226562500, +-0.0013122558593750, 0.0030517578125000, -0.0009460449218750, 0.0031127929687500, +-0.0004272460937500, 0.0032043457031250, -0.0007629394531250, 0.0032958984375000, +0.0004577636718750, 0.0032958984375000, 0.0002746582031250, 0.0033569335937500, +0.0005187988281250, 0.0034790039062500, 0.0013427734375000, 0.0033569335937500, +0.0009460449218750, 0.0035095214843750, 0.0014038085937500, 0.0034179687500000, +0.0015869140625000, 0.0033874511718750, 0.0014038085937500, 0.0033874511718750, +0.0014953613281250, 0.0032348632812500, 0.0015563964843750, 0.0032043457031250, +0.0012817382812500, 0.0031738281250000, 0.0014648437500000, 0.0031127929687500, +0.0012207031250000, 0.0030822753906250, 0.0009155273437500, 0.0030212402343750, +0.0011901855468750, 0.0029602050781250, 0.0005493164062500, 0.0029602050781250, +0.0006713867187500, 0.0029602050781250, 0.0006103515625000, 0.0029296875000000, +0.0002136230468750, 0.0030517578125000, 0.0003967285156250, 0.0028381347656250, +0.0002746582031250, 0.0030212402343750, 0.0001831054687500, 0.0028381347656250, +0.0003051757812500, 0.0026245117187500, 0.0003051757812500, 0.0029602050781250, +0.0002746582031250, 0.0022277832031250, 0.0003967285156250, 0.0024108886718750, +0.0003051757812500, 0.0021362304687500, 0.0003356933593750, 0.0015258789062500, +0.0003967285156250, 0.0018005371093750, 0.0002746582031250, 0.0013427734375000, +0.0003967285156250, 0.0012512207031250, 0.0002441406250000, 0.0013427734375000, +0.0003356933593750, 0.0011901855468750, 0.0004882812500000, 0.0011291503906250, +0.0003051757812500, 0.0012512207031250, 0.0005493164062500, 0.0012207031250000, +0.0005187988281250, 0.0011596679687500, 0.0004272460937500, 0.0011901855468750, +0.0005187988281250, 0.0011901855468750, 0.0004882812500000, 0.0010070800781250, +0.0003662109375000, 0.0010070800781250, 0.0003967285156250, 0.0009765625000000, +0.0003662109375000, 0.0007934570312500, 0.0001220703125000, 0.0008544921875000, +0.0000610351562500, 0.0010070800781250, 0.0002746582031250, 0.0007019042968750, +0.0000915527343750, 0.0010681152343750, 0.0003356933593750, 0.0014343261718750, +0.0006713867187500, 0.0008850097656250, 0.0004577636718750, 0.0019836425781250, +0.0010070800781250, 0.0016479492187500, 0.0009155273437500, 0.0017700195312500, +0.0013427734375000, 0.0025024414062500, 0.0018920898437500, 0.0019531250000000, +0.0015258789062500, 0.0025939941406250, 0.0028686523437500, 0.0024719238281250, +0.0028076171875000, 0.0025024414062500, 0.0029907226562500, 0.0028686523437500, +0.0037536621093750, 0.0025634765625000, 0.0034179687500000, 0.0032043457031250, +0.0038452148437500, 0.0028991699218750, 0.0038452148437500, 0.0031738281250000, +0.0037231445312500, 0.0037536621093750, 0.0039062500000000, 0.0032653808593750, +0.0037536621093750, 0.0040283203125000, 0.0038146972656250, 0.0039978027343750, +0.0038452148437500, 0.0037231445312500, 0.0037841796875000, 0.0042114257812500, +0.0039062500000000, 0.0021972656250000, 0.0030822753906250, 0.0015258789062500, +0.0038146972656250, 0.0016174316406250, 0.0038146972656250, 0.0013122558593750, +0.0035705566406250, 0.0009460449218750, 0.0037231445312500, 0.0010375976562500, +0.0039062500000000, 0.0005493164062500, 0.0031127929687500, 0.0005187988281250, +0.0033569335937500, 0.0005493164062500, 0.0032043457031250, 0.0003051757812500, +0.0025329589843750, 0.0003051757812500, 0.0029296875000000, 0.0006713867187500, +0.0031433105468750, 0.0004882812500000, 0.0028381347656250, 0.0006408691406250, +0.0032043457031250, 0.0010375976562500, 0.0037536621093750, 0.0009155273437500, +0.0034790039062500, 0.0010375976562500, 0.0039367675781250, 0.0010375976562500, +0.0039062500000000, 0.0012512207031250, 0.0038757324218750, 0.0013122558593750, +0.0040283203125000, 0.0011291503906250, 0.0037841796875000, 0.0021667480468750, +0.0039367675781250, 0.0016784667968750, 0.0040283203125000, 0.0021667480468750, +0.0037536621093750, 0.0031433105468750, 0.0036010742187500, 0.0024108886718750, +0.0037841796875000, 0.0037231445312500, 0.0032958984375000, 0.0035095214843750, +0.0033264160156250, 0.0035705566406250, 0.0028991699218750, 0.0043945312500000, +0.0023803710937500, 0.0039978027343750, 0.0026550292968750, 0.0042419433593750, +0.0018310546875000, 0.0044555664062500, 0.0015563964843750, 0.0041503906250000, +0.0017089843750000, 0.0039672851562500, 0.0014953613281250, 0.0041503906250000, +0.0014648437500000, 0.0036621093750000, 0.0020141601562500, 0.0037231445312500, +0.0016784667968750, 0.0036621093750000, 0.0023498535156250, 0.0034179687500000, +0.0032348632812500, 0.0035095214843750, 0.0027770996093750, 0.0036010742187500, +0.0039978027343750, 0.0034179687500000, 0.0043945312500000, 0.0036315917968750, +0.0044250488281250, 0.0039062500000000, 0.0049438476562500, 0.0037536621093750, +0.0050048828125000, 0.0040283203125000, 0.0043029785156250, 0.0042114257812500, +0.0048828125000000, 0.0039672851562500, 0.0045471191406250, 0.0040283203125000, +0.0036621093750000, 0.0042724609375000, 0.0042419433593750, 0.0032653808593750, +0.0041809082031250, 0.0037536621093750, 0.0038757324218750, 0.0031127929687500, +0.0043945312500000, 0.0020141601562500, 0.0048828125000000, 0.0028381347656250, +0.0046081542968750, 0.0010986328125000, 0.0052795410156250, 0.0012207031250000, +0.0053710937500000, 0.0011596679687500, 0.0052490234375000, 0.0001525878906250, +0.0054016113281250, 0.0006408691406250, 0.0054016113281250, 0.0005493164062500, +0.0048217773437500, 0.0003356933593750, 0.0049743652343750, 0.0008239746093750, +0.0046386718750000, 0.0012207031250000, 0.0040588378906250, 0.0009765625000000, +0.0042724609375000, 0.0015258789062500, 0.0036926269531250, 0.0018310546875000, +0.0036926269531250, 0.0016174316406250, 0.0036621093750000, 0.0017395019531250, +0.0035095214843750, 0.0020446777343750, 0.0036926269531250, 0.0011901855468750, +0.0035705566406250, 0.0015563964843750, 0.0037536621093750, 0.0012817382812500, +0.0036621093750000, 0.0005798339843750, 0.0034179687500000, 0.0011291503906250, +0.0036315917968750, 0.0007324218750000, 0.0031433105468750, 0.0007019042968750, +0.0032958984375000, 0.0010070800781250, 0.0032958984375000, 0.0010070800781250, +0.0029296875000000, 0.0010681152343750, 0.0031127929687500, 0.0016479492187500, +0.0030822753906250, 0.0016479492187500, 0.0029907226562500, 0.0019531250000000, +0.0030822753906250, 0.0025024414062500, 0.0033264160156250, 0.0024414062500000, +0.0032958984375000, 0.0027770996093750, 0.0035095214843750, 0.0031738281250000, +0.0036010742187500, 0.0029296875000000, 0.0035095214843750, 0.0028381347656250, +0.0036010742187500, 0.0033264160156250, 0.0038146972656250, 0.0024108886718750, +0.0032958984375000, 0.0027465820312500, 0.0035095214843750, 0.0025024414062500, +0.0033874511718750, 0.0017395019531250, 0.0029296875000000, 0.0022277832031250, +0.0033264160156250, 0.0012512207031250, 0.0029296875000000, 0.0013732910156250, +0.0029602050781250, 0.0010681152343750, 0.0029602050781250, 0.0003356933593750, +0.0028076171875000, 0.0007324218750000, 0.0029602050781250, -0.0003356933593750, +0.0028686523437500, -0.0002746582031250, 0.0028686523437500, -0.0005798339843750, +0.0029907226562500, -0.0014038085937500, 0.0030212402343750, -0.0011596679687500, +0.0030822753906250, -0.0020751953125000, 0.0032043457031250, -0.0020446777343750, +0.0031738281250000, -0.0022583007812500, 0.0032653808593750, -0.0028991699218750, +0.0033569335937500, -0.0026550292968750, 0.0032958984375000, -0.0031127929687500, +0.0033264160156250, -0.0032043457031250, 0.0032653808593750, -0.0030822753906250, +0.0032348632812500, -0.0032043457031250, 0.0032348632812500, -0.0031433105468750, +0.0032348632812500, -0.0028076171875000, 0.0031433105468750, -0.0030212402343750, +0.0031433105468750, -0.0026855468750000, 0.0031127929687500, -0.0022277832031250, +0.0030517578125000, -0.0026245117187500, 0.0030212402343750, -0.0015563964843750, +0.0029907226562500, -0.0018615722656250, 0.0028991699218750, -0.0014038085937500, +0.0028991699218750, -0.0004272460937500, 0.0028686523437500, -0.0010681152343750, +0.0028076171875000, 0.0004577636718750, 0.0028381347656250, 0.0003356933593750, +0.0027465820312500, 0.0005187988281250, 0.0027465820312500, 0.0014038085937500, +0.0027770996093750, 0.0010375976562500, 0.0027160644531250, 0.0013732910156250, +0.0027770996093750, 0.0016479492187500, 0.0026550292968750, 0.0012817382812500, +0.0026855468750000, 0.0011291503906250, 0.0028076171875000, 0.0014038085937500, +0.0027160644531250, 0.0005493164062500, 0.0028076171875000, 0.0006408691406250, +0.0028381347656250, 0.0006408691406250, 0.0027770996093750, 0.0000610351562500, +0.0027465820312500, 0.0002441406250000, 0.0027770996093750, 0.0004272460937500, +0.0026550292968750, 0.0001525878906250, 0.0026855468750000, 0.0005187988281250, +0.0026245117187500, 0.0009155273437500, 0.0025634765625000, 0.0005493164062500, +0.0025939941406250, 0.0012817382812500, 0.0025329589843750, 0.0012817382812500, +0.0026245117187500, 0.0012207031250000, 0.0025024414062500, 0.0016174316406250, +0.0023803710937500, 0.0014648437500000, 0.0025939941406250, 0.0013732910156250, +0.0021667480468750, 0.0014038085937500, 0.0023193359375000, 0.0013122558593750, +0.0021972656250000, 0.0011291503906250, 0.0018920898437500, 0.0011291503906250, +0.0021972656250000, 0.0007934570312500, 0.0018920898437500, 0.0007934570312500, +0.0019226074218750, 0.0006408691406250, 0.0020141601562500, 0.0004577636718750, +0.0018615722656250, 0.0006408691406250, 0.0019226074218750, -0.0001220703125000, +0.0018005371093750, 0.0001220703125000, 0.0019226074218750, -0.0000915527343750, +0.0018920898437500, -0.0008239746093750, 0.0017700195312500, -0.0005187988281250, +0.0019531250000000, -0.0009765625000000, 0.0016174316406250, -0.0011291503906250, +0.0017700195312500, -0.0007629394531250, 0.0016784667968750, -0.0007324218750000, +0.0013427734375000, -0.0008239746093750, 0.0016479492187500, 0.0003356933593750, +0.0014038085937500, 0.0001220703125000, 0.0013732910156250, 0.0006103515625000, +0.0014648437500000, 0.0016174316406250, 0.0014343261718750, 0.0013122558593750, +0.0014343261718750, 0.0022888183593750, 0.0014953613281250, 0.0024108886718750, +0.0015869140625000, 0.0025329589843750, 0.0015869140625000, 0.0030822753906250, +0.0014953613281250, 0.0030517578125000, 0.0016479492187500, 0.0036010742187500, +0.0018005371093750, 0.0033874511718750, 0.0015869140625000, 0.0032958984375000, +0.0018615722656250, 0.0036926269531250, 0.0021057128906250, 0.0035095214843750, +0.0019226074218750, 0.0030212402343750, 0.0025024414062500, 0.0031433105468750, +0.0023498535156250, 0.0027465820312500, 0.0025634765625000, 0.0020751953125000, +0.0030822753906250, 0.0021972656250000, 0.0027770996093750, 0.0021057128906250, +0.0032958984375000, 0.0016174316406250, 0.0033569335937500, 0.0018920898437500, +0.0032348632812500, 0.0023193359375000, 0.0034790039062500, 0.0019226074218750, +0.0034179687500000, 0.0028381347656250, 0.0032653808593750, 0.0028991699218750, +0.0033874511718750, 0.0030212402343750, 0.0033264160156250, 0.0034790039062500, +0.0031738281250000}, +{0.0023803710937500, -0.0023803710937500, 0.0024719238281250, -0.0025024414062500, +0.0023498535156250, -0.0019531250000000, 0.0024414062500000, -0.0020446777343750, +0.0024108886718750, -0.0018005371093750, 0.0023193359375000, -0.0012817382812500, +0.0023803710937500, -0.0015258789062500, 0.0024108886718750, -0.0008544921875000, +0.0023803710937500, -0.0008850097656250, 0.0023803710937500, -0.0007324218750000, +0.0023498535156250, -0.0002441406250000, 0.0023498535156250, -0.0004882812500000, +0.0022888183593750, 0.0001525878906250, 0.0024108886718750, 0.0001525878906250, +0.0024414062500000, 0.0002441406250000, 0.0023498535156250, 0.0006408691406250, +0.0024108886718750, 0.0004272460937500, 0.0024414062500000, 0.0006103515625000, +0.0023803710937500, 0.0007019042968750, 0.0024414062500000, 0.0003967285156250, +0.0025024414062500, 0.0002441406250000, 0.0024719238281250, 0.0003356933593750, +0.0025634765625000, -0.0002136230468750, 0.0024719238281250, -0.0003051757812500, +0.0025329589843750, -0.0003967285156250, 0.0024719238281250, -0.0007629394531250, +0.0023803710937500, -0.0007629394531250, 0.0024719238281250, -0.0006408691406250, +0.0023193359375000, -0.0008544921875000, 0.0024108886718750, -0.0006408691406250, +0.0023498535156250, -0.0003662109375000, 0.0022277832031250, -0.0005493164062500, +0.0023803710937500, -0.0000915527343750, 0.0022888183593750, -0.0000915527343750, +0.0024108886718750, 0.0000000000000000, 0.0023193359375000, 0.0002746582031250, +0.0022277832031250, 0.0000610351562500, 0.0023803710937500, 0.0000610351562500, +0.0021362304687500, 0.0001220703125000, 0.0022888183593750, -0.0000305175781250, +0.0021667480468750, -0.0001831054687500, 0.0019836425781250, 0.0000000000000000, +0.0022888183593750, -0.0003662109375000, 0.0016174316406250, -0.0000915527343750, +0.0018920898437500, -0.0002136230468750, 0.0017700195312500, -0.0005187988281250, +0.0012817382812500, -0.0001831054687500, 0.0017089843750000, -0.0009460449218750, +0.0012207031250000, -0.0007019042968750, 0.0011901855468750, -0.0008544921875000, +0.0013122558593750, -0.0015563964843750, 0.0011291503906250, -0.0010375976562500, +0.0012512207031250, -0.0012817382812500, 0.0012512207031250, -0.0016174316406250, +0.0012512207031250, -0.0009155273437500, 0.0013427734375000, -0.0004882812500000, +0.0014343261718750, -0.0009155273437500, 0.0014038085937500, 0.0006713867187500, +0.0017395019531250, 0.0004577636718750, 0.0016784667968750, 0.0008239746093750, +0.0019836425781250, 0.0023498535156250, 0.0024414062500000, 0.0026550292968750, +0.0024719238281250, 0.0033569335937500, 0.0030212402343750, 0.0032043457031250, +0.0028686523437500, 0.0035095214843750, 0.0029296875000000, 0.0041503906250000, +0.0033264160156250, 0.0040588378906250, 0.0031738281250000, 0.0046386718750000, +0.0032348632812500, 0.0048522949218750, 0.0032653808593750, 0.0046386718750000, +0.0031433105468750, 0.0046386718750000, 0.0030212402343750, 0.0047607421875000, +0.0030517578125000, 0.0039062500000000, 0.0027770996093750, 0.0037841796875000, +0.0027160644531250, 0.0036621093750000, 0.0027160644531250, 0.0030517578125000, +0.0026855468750000, 0.0028991699218750, 0.0025329589843750, 0.0028991699218750, +0.0026550292968750, 0.0026855468750000, 0.0025634765625000, 0.0025329589843750, +0.0025329589843750, 0.0025329589843750, 0.0025329589843750, 0.0025939941406250, +0.0024719238281250, 0.0025329589843750, 0.0022888183593750, 0.0024414062500000, +0.0022888183593750, 0.0028076171875000, 0.0018615722656250, 0.0030212402343750, +0.0015869140625000, 0.0027465820312500, 0.0017700195312500, 0.0036621093750000, +0.0008850097656250, 0.0034790039062500, 0.0009460449218750, 0.0035705566406250, +0.0007629394531250, 0.0042114257812500, 0.0001525878906250, 0.0037536621093750, +0.0004272460937500, 0.0038757324218750, -0.0000915527343750, 0.0040283203125000, +-0.0002136230468750, 0.0036621093750000, -0.0001525878906250, 0.0033569335937500, +-0.0002746582031250, 0.0035400390625000, -0.0003051757812500, 0.0030517578125000, +-0.0003051757812500, 0.0029907226562500, -0.0003051757812500, 0.0030212402343750, +-0.0003662109375000, 0.0028381347656250, -0.0003967285156250, 0.0027465820312500, +-0.0003356933593750, 0.0032043457031250, -0.0006713867187500, 0.0029907226562500, +-0.0006103515625000, 0.0031127929687500, -0.0007934570312500, 0.0035095214843750, +-0.0011596679687500, 0.0032043457031250, -0.0009155273437500, 0.0037231445312500, +-0.0014648437500000, 0.0036315917968750, -0.0014343261718750, 0.0035705566406250, +-0.0014648437500000, 0.0037536621093750, -0.0017089843750000, 0.0036010742187500, +-0.0015258789062500, 0.0038146972656250, -0.0018005371093750, 0.0036926269531250, +-0.0017395019531250, 0.0037841796875000, -0.0017395019531250, 0.0040588378906250, +-0.0018310546875000, 0.0037536621093750, -0.0017089843750000, 0.0041503906250000, +-0.0021972656250000, 0.0039978027343750, -0.0019836425781250, 0.0038452148437500, +-0.0021057128906250, 0.0041198730468750, -0.0024719238281250, 0.0039062500000000, +-0.0021057128906250, 0.0035400390625000, -0.0024414062500000, 0.0037231445312500, +-0.0025024414062500, 0.0033874511718750, -0.0023193359375000, 0.0029296875000000, +-0.0023193359375000, 0.0032348632812500, -0.0023193359375000, 0.0025024414062500, +-0.0023193359375000, 0.0025329589843750, -0.0023193359375000, 0.0025939941406250, +-0.0024108886718750, 0.0022888183593750, -0.0025024414062500, 0.0025024414062500, +-0.0025024414062500, 0.0024108886718750, -0.0025634765625000, 0.0025024414062500, +-0.0027160644531250, 0.0025634765625000, -0.0025329589843750, 0.0025024414062500, +-0.0024414062500000, 0.0026855468750000, -0.0026245117187500, 0.0026550292968750, +-0.0017089843750000, 0.0027465820312500, -0.0020141601562500, 0.0027770996093750, +-0.0014343261718750, 0.0026245117187500, -0.0005798339843750, 0.0027465820312500, +-0.0011901855468750, 0.0025939941406250, 0.0003356933593750, 0.0025939941406250, +0.0002136230468750, 0.0026550292968750, 0.0004272460937500, 0.0025939941406250, +0.0014038085937500, 0.0026550292968750, 0.0009765625000000, 0.0026245117187500, +0.0013732910156250, 0.0027465820312500, 0.0015563964843750, 0.0027770996093750, +0.0012512207031250, 0.0027465820312500, 0.0011901855468750, 0.0028991699218750, +0.0014343261718750, 0.0026855468750000, 0.0007629394531250, 0.0028686523437500, +0.0009460449218750, 0.0028686523437500, 0.0007629394531250, 0.0027465820312500, +0.0002441406250000, 0.0028991699218750, 0.0006103515625000, 0.0028991699218750, +-0.0000610351562500, 0.0028991699218750, 0.0000305175781250, 0.0030517578125000, +0.0000305175781250, 0.0031127929687500, -0.0003967285156250, 0.0030212402343750, +-0.0001831054687500, 0.0032958984375000, -0.0003967285156250, 0.0031738281250000, +-0.0004577636718750, 0.0031738281250000, -0.0004272460937500, 0.0033569335937500, +-0.0004577636718750, 0.0031127929687500, -0.0005187988281250, 0.0032958984375000, +-0.0005187988281250, 0.0032348632812500, -0.0005187988281250, 0.0030822753906250, +-0.0005798339843750, 0.0031433105468750, -0.0006713867187500, 0.0030212402343750, +-0.0006408691406250, 0.0028381347656250, -0.0009765625000000, 0.0027770996093750, +-0.0009155273437500, 0.0026855468750000, -0.0010375976562500, 0.0025329589843750, +-0.0013427734375000, 0.0024719238281250, -0.0013122558593750, 0.0025939941406250, +-0.0011901855468750, 0.0024108886718750, -0.0014648437500000, 0.0024414062500000, +-0.0010681152343750, 0.0025634765625000, -0.0006103515625000, 0.0024108886718750, +-0.0010375976562500, 0.0024414062500000, -0.0000915527343750, 0.0025024414062500, +-0.0002441406250000, 0.0023498535156250, 0.0000000000000000, 0.0021972656250000, +0.0006408691406250, 0.0022888183593750, 0.0003051757812500, 0.0019226074218750, +0.0008239746093750, 0.0019531250000000, 0.0008850097656250, 0.0018920898437500, +0.0008544921875000, 0.0016479492187500, 0.0010681152343750, 0.0017700195312500, +0.0010070800781250, 0.0018005371093750, 0.0009155273437500, 0.0017395019531250, +0.0009460449218750, 0.0017395019531250, 0.0008544921875000, 0.0018310546875000, +0.0007629394531250, 0.0018310546875000, 0.0007019042968750, 0.0016479492187500, +0.0004272460937500, 0.0018920898437500, 0.0004577636718750, 0.0016174316406250, +0.0003051757812500, 0.0013732910156250, 0.0000305175781250, 0.0017089843750000, +0.0000610351562500, 0.0009460449218750, -0.0001220703125000, 0.0011291503906250, +-0.0000915527343750, 0.0009765625000000, -0.0001220703125000, 0.0004272460937500, +-0.0001831054687500, 0.0007019042968750, -0.0001525878906250, 0.0003662109375000, +-0.0001525878906250, 0.0003051757812500, -0.0001525878906250, 0.0005493164062500, +-0.0001220703125000, 0.0006103515625000, -0.0001220703125000, 0.0005493164062500, +-0.0001525878906250, 0.0009765625000000, 0.0000305175781250, 0.0010986328125000, +-0.0000305175781250, 0.0012512207031250, 0.0000915527343750, 0.0014648437500000, +0.0003051757812500, 0.0014953613281250, 0.0002441406250000, 0.0016479492187500, +0.0005493164062500, 0.0017700195312500, 0.0005798339843750, 0.0018920898437500, +0.0006103515625000, 0.0018920898437500, 0.0007629394531250, 0.0020141601562500, +0.0007629394531250, 0.0024108886718750, 0.0008239746093750, 0.0023498535156250, +0.0007934570312500, 0.0025329589843750, 0.0008850097656250, 0.0029907226562500, +0.0010070800781250, 0.0028991699218750, 0.0009155273437500, 0.0028686523437500, +0.0010070800781250, 0.0031738281250000, 0.0010375976562500, 0.0027770996093750, +0.0010986328125000, 0.0025329589843750, 0.0011901855468750, 0.0028686523437500, +0.0010070800781250, 0.0017395019531250, 0.0011901855468750, 0.0019531250000000, +0.0012512207031250, 0.0017395019531250, 0.0011901855468750, 0.0009765625000000, +0.0011596679687500, 0.0014038085937500, 0.0011901855468750, 0.0006713867187500, +0.0011596679687500, 0.0005798339843750, 0.0010681152343750, 0.0007324218750000, +0.0010070800781250, 0.0003967285156250, 0.0010375976562500, -0.0000305175781250, +0.0010070800781250, 0.0011596679687500, 0.0015258789062500, 0.0005798339843750, +0.0013732910156250, 0.0012817382812500, 0.0014648437500000, 0.0021362304687500, +0.0017089843750000, 0.0016174316406250, 0.0015563964843750, 0.0029907226562500, +0.0015258789062500, 0.0029602050781250, 0.0015258789062500, 0.0031738281250000, +0.0018310546875000, 0.0040588378906250, 0.0018005371093750, 0.0036315917968750, +0.0015258789062500, 0.0044250488281250, 0.0024108886718750, 0.0044555664062500, +0.0023803710937500, 0.0044250488281250, 0.0024108886718750, 0.0048828125000000, +0.0028991699218750, 0.0047912597656250, 0.0027160644531250, 0.0042114257812500, +0.0029907226562500, 0.0046386718750000, 0.0029907226562500, 0.0037841796875000, +0.0029907226562500, 0.0028076171875000, 0.0031433105468750, 0.0035705566406250, +0.0031738281250000, 0.0014648437500000, 0.0034179687500000, 0.0015869140625000, +0.0033569335937500, 0.0012512207031250, 0.0034179687500000, -0.0000610351562500, +0.0037536621093750, 0.0004882812500000, 0.0037231445312500, -0.0004272460937500, +0.0034484863281250, -0.0005798339843750, 0.0036621093750000, -0.0005493164062500, +0.0034179687500000, -0.0010375976562500, 0.0030212402343750, -0.0009765625000000, +0.0033874511718750, -0.0006713867187500, 0.0031127929687500, -0.0010681152343750, +0.0031738281250000, -0.0007019042968750, 0.0032348632812500, -0.0001831054687500, +0.0031738281250000, -0.0006713867187500, 0.0033264160156250, 0.0001525878906250, +0.0032653808593750}, +{-0.0005493164062500, 0.0018005371093750, -0.0002136230468750, 0.0018310546875000, +-0.0001831054687500, 0.0017089843750000, -0.0001525878906250, 0.0014953613281250, +-0.0000305175781250, 0.0016479492187500, -0.0000610351562500, 0.0014953613281250, +0.0000000000000000, 0.0014953613281250, 0.0000305175781250, 0.0015869140625000, +0.0000305175781250, 0.0015869140625000, 0.0000000000000000, 0.0015563964843750, +0.0000915527343750, 0.0017395019531250, 0.0000305175781250, 0.0017700195312500, +0.0000915527343750, 0.0017700195312500, -0.0000305175781250, 0.0018310546875000, +-0.0000610351562500, 0.0019226074218750, 0.0000610351562500, 0.0017395019531250, +-0.0001525878906250, 0.0017700195312500, -0.0000915527343750, 0.0018005371093750, +-0.0001525878906250, 0.0017089843750000, -0.0003967285156250, 0.0017700195312500, +-0.0003356933593750, 0.0019836425781250, -0.0003967285156250, 0.0018920898437500, +-0.0004272460937500, 0.0020446777343750, -0.0004272460937500, 0.0023193359375000, +-0.0004882812500000, 0.0022277832031250, -0.0005493164062500, 0.0023193359375000, +-0.0004882812500000, 0.0025634765625000, -0.0004882812500000, 0.0022583007812500, +-0.0005187988281250, 0.0020446777343750, -0.0004882812500000, 0.0024719238281250, +-0.0004882812500000, 0.0013427734375000, -0.0003967285156250, 0.0015869140625000, +-0.0004272460937500, 0.0013122558593750, -0.0003967285156250, 0.0003662109375000, +-0.0003051757812500, 0.0007934570312500, -0.0003051757812500, 0.0000915527343750, +0.0001525878906250, -0.0000610351562500, -0.0000305175781250, 0.0000000000000000, +0.0001831054687500, -0.0003662109375000, 0.0006713867187500, -0.0002441406250000, +0.0004577636718750, -0.0001525878906250, 0.0008544921875000, -0.0003662109375000, +0.0007934570312500, -0.0001220703125000, 0.0008850097656250, 0.0003967285156250, +0.0013732910156250, 0.0012512207031250, 0.0005187988281250, 0.0024719238281250, +0.0005493164062500, 0.0021362304687500, 0.0002441406250000, 0.0024719238281250, +0.0006103515625000, 0.0031433105468750, 0.0009460449218750, 0.0030212402343750, +0.0006103515625000, 0.0032653808593750, 0.0014343261718750, 0.0036010742187500, +0.0014343261718750, 0.0032958984375000, 0.0011901855468750, 0.0031433105468750, +0.0014038085937500, 0.0035095214843750, 0.0014953613281250, 0.0023193359375000, +0.0014343261718750, 0.0028076171875000, 0.0012512207031250, 0.0021057128906250, +0.0013122558593750, 0.0007934570312500, 0.0014343261718750, 0.0017700195312500, +0.0014953613281250, 0.0000305175781250, 0.0016784667968750, 0.0000000000000000, +0.0016479492187500, 0.0000000000000000, 0.0018005371093750, -0.0007934570312500, +0.0019531250000000, -0.0004882812500000, 0.0017395019531250, -0.0005798339843750, +0.0019226074218750, -0.0007629394531250, 0.0018310546875000, -0.0006408691406250, +0.0019836425781250, -0.0005187988281250, 0.0021362304687500, -0.0006408691406250, +0.0019226074218750, -0.0001525878906250, 0.0028991699218750, -0.0003662109375000, +0.0028381347656250, -0.0001220703125000, 0.0029296875000000, 0.0003051757812500, +0.0036621093750000, -0.0000305175781250, 0.0035705566406250, 0.0005187988281250, +0.0031738281250000, 0.0004882812500000, 0.0035095214843750, 0.0003662109375000, +0.0031433105468750, 0.0005187988281250, 0.0026855468750000, 0.0004272460937500, +0.0032653808593750, -0.0000305175781250, 0.0022888183593750, 0.0000305175781250, +0.0023803710937500, -0.0000915527343750, 0.0025024414062500, -0.0005798339843750, +0.0021057128906250, -0.0004577636718750, 0.0021362304687500, -0.0001525878906250, +0.0019531250000000, -0.0005493164062500, 0.0020141601562500, -0.0000610351562500, +0.0019836425781250, 0.0005798339843750, 0.0018920898437500, 0.0000610351562500, +0.0019531250000000, 0.0013427734375000, 0.0014953613281250, 0.0012512207031250, +0.0017700195312500, 0.0013427734375000, 0.0015258789062500, 0.0021362304687500, +0.0010070800781250, 0.0018310546875000, 0.0013427734375000, 0.0019226074218750, +0.0010681152343750, 0.0021362304687500, 0.0009765625000000, 0.0018005371093750, +0.0013427734375000, 0.0015258789062500, 0.0014648437500000, 0.0016784667968750, +0.0014038085937500, 0.0012817382812500, 0.0019531250000000, 0.0011596679687500, +0.0021057128906250, 0.0011596679687500, 0.0021667480468750, 0.0010375976562500, +0.0025329589843750, 0.0009765625000000, 0.0025939941406250, 0.0009765625000000, +0.0022583007812500, 0.0009460449218750, 0.0024719238281250, 0.0008544921875000, +0.0021667480468750, 0.0007324218750000, 0.0017089843750000, 0.0007934570312500, +0.0019531250000000, 0.0003356933593750, 0.0013732910156250, 0.0004882812500000, +0.0012817382812500, 0.0001220703125000, 0.0012512207031250, -0.0003356933593750, +0.0010070800781250, 0.0000000000000000, 0.0010070800781250, -0.0007324218750000, +0.0010070800781250, -0.0007324218750000, 0.0011291503906250, -0.0006103515625000, +0.0011291503906250, -0.0009765625000000, 0.0011901855468750, -0.0009460449218750, +0.0013427734375000, -0.0006103515625000, 0.0010681152343750, -0.0008544921875000, +0.0012817382812500, -0.0006103515625000, 0.0011901855468750, -0.0002136230468750, +0.0008850097656250, -0.0006408691406250, 0.0011291503906250, 0.0000000000000000, +0.0009155273437500, -0.0001525878906250, 0.0008544921875000, -0.0003356933593750, +0.0009460449218750, 0.0000305175781250, 0.0009460449218750, -0.0001525878906250, +0.0008544921875000, -0.0007019042968750, 0.0010681152343750, -0.0005187988281250, +0.0009155273437500, -0.0009765625000000, 0.0010070800781250, -0.0016784667968750, +0.0012207031250000, -0.0013732910156250, 0.0010070800781250, -0.0022888183593750, +0.0010681152343750, -0.0023803710937500, 0.0010681152343750, -0.0023193359375000, +0.0009155273437500, -0.0027465820312500, 0.0008239746093750, -0.0026550292968750, +0.0007324218750000, -0.0025024414062500, 0.0006408691406250, -0.0026245117187500, +0.0005187988281250, -0.0023803710937500, 0.0005187988281250, -0.0021057128906250, +0.0004882812500000, -0.0022583007812500, 0.0004272460937500, -0.0015258789062500, +0.0004577636718750, -0.0015563964843750, 0.0004577636718750, -0.0012817382812500, +0.0003967285156250, -0.0007629394531250, 0.0003967285156250, -0.0008850097656250, +0.0004272460937500, -0.0001525878906250, 0.0003967285156250, -0.0002136230468750, +0.0003662109375000, 0.0000610351562500, 0.0004882812500000, 0.0007324218750000, +0.0005187988281250, 0.0003967285156250, 0.0005187988281250, 0.0012817382812500, +0.0006408691406250, 0.0011291503906250, 0.0006103515625000, 0.0014038085937500, +0.0006103515625000, 0.0021057128906250, 0.0007934570312500, 0.0017089843750000, +0.0007019042968750, 0.0023803710937500, 0.0008850097656250, 0.0024414062500000, +0.0008544921875000, 0.0022583007812500, 0.0010070800781250, 0.0025329589843750, +0.0012512207031250, 0.0025024414062500, 0.0011901855468750, 0.0019226074218750, +0.0014648437500000, 0.0021667480468750, 0.0015563964843750, 0.0017395019531250, +0.0016479492187500, 0.0010375976562500, 0.0018615722656250, 0.0013732910156250, +0.0018920898437500, 0.0005493164062500, 0.0018920898437500, 0.0004272460937500, +0.0020751953125000, 0.0004577636718750, 0.0020446777343750, 0.0000915527343750, +0.0020141601562500, 0.0001220703125000, 0.0022888183593750, 0.0003662109375000, +0.0019226074218750, 0.0002136230468750, 0.0021057128906250, 0.0003967285156250, +0.0020446777343750, 0.0007629394531250, 0.0018005371093750, 0.0006103515625000, +0.0020751953125000, 0.0011596679687500, 0.0016784667968750, 0.0011596679687500, +0.0017700195312500, 0.0013122558593750, 0.0017089843750000, 0.0017089843750000, +0.0014343261718750, 0.0015869140625000, 0.0015869140625000, 0.0020751953125000, +0.0014038085937500, 0.0021362304687500, 0.0013122558593750, 0.0021667480468750, +0.0014038085937500, 0.0025024414062500, 0.0014343261718750, 0.0025329589843750, +0.0013732910156250, 0.0024719238281250, 0.0015869140625000, 0.0026855468750000, +0.0015869140625000, 0.0025634765625000, 0.0016174316406250, 0.0023803710937500, +0.0017089843750000, 0.0026550292968750, 0.0017395019531250, 0.0022277832031250, +0.0018005371093750, 0.0022888183593750, 0.0018310546875000, 0.0023498535156250, +0.0017700195312500, 0.0020751953125000, 0.0017089843750000, 0.0021972656250000, +0.0018005371093750, 0.0023803710937500, 0.0016784667968750, 0.0021667480468750, +0.0017395019531250, 0.0024414062500000, 0.0017700195312500, 0.0028381347656250, +0.0016784667968750, 0.0024414062500000, 0.0018005371093750, 0.0031433105468750, +0.0017700195312500, 0.0030212402343750, 0.0016784667968750, 0.0030212402343750, +0.0018615722656250, 0.0035095214843750, 0.0019531250000000, 0.0032348632812500, +0.0018310546875000, 0.0033264160156250, 0.0024414062500000, 0.0033874511718750, +0.0023193359375000, 0.0030517578125000, 0.0025329589843750, 0.0028076171875000, +0.0030822753906250, 0.0028381347656250, 0.0027770996093750, 0.0022888183593750, +0.0033569335937500, 0.0021057128906250, 0.0035095214843750, 0.0018005371093750, +0.0033569335937500, 0.0013732910156250, 0.0035095214843750, 0.0013732910156250, +0.0036010742187500, 0.0009155273437500, 0.0031433105468750, 0.0008239746093750, +0.0032958984375000, 0.0007629394531250, 0.0031433105468750, 0.0003967285156250, +0.0027160644531250, 0.0001525878906250, 0.0028076171875000, 0.0005187988281250, +0.0022888183593750, 0.0003051757812500, 0.0025024414062500, 0.0003967285156250, +0.0023498535156250, 0.0007324218750000, 0.0018920898437500, 0.0005187988281250, +0.0021972656250000, 0.0007324218750000, 0.0014343261718750, 0.0008239746093750, +0.0015563964843750, 0.0007019042968750, 0.0012817382812500, 0.0007324218750000, +0.0007324218750000, 0.0009460449218750, 0.0010986328125000, 0.0007324218750000, +0.0001831054687500, 0.0008850097656250, 0.0002441406250000, 0.0007934570312500, +0.0000610351562500, 0.0006103515625000, -0.0006103515625000, 0.0007934570312500, +-0.0003051757812500, 0.0009765625000000, -0.0006713867187500, 0.0005798339843750, +-0.0008239746093750, 0.0009765625000000, -0.0005493164062500, 0.0014038085937500, +-0.0004882812500000, 0.0009155273437500, -0.0006103515625000, 0.0021057128906250, +0.0003051757812500, 0.0018920898437500, 0.0000305175781250, 0.0018310546875000, +0.0004272460937500, 0.0026245117187500, 0.0012817382812500, 0.0024414062500000, +0.0008544921875000, 0.0022888183593750, 0.0017700195312500, 0.0025634765625000, +0.0017700195312500, 0.0023193359375000, 0.0018920898437500, 0.0019836425781250, +0.0025024414062500, 0.0022583007812500, 0.0022583007812500, 0.0017089843750000, +0.0024719238281250, 0.0016174316406250, 0.0025329589843750, 0.0017700195312500, +0.0024719238281250, 0.0015563964843750, 0.0025024414062500, 0.0014343261718750, +0.0025024414062500, 0.0017700195312500, 0.0024108886718750, 0.0015258789062500, +0.0024414062500000, 0.0016784667968750, 0.0023803710937500, 0.0020751953125000, +0.0022888183593750, 0.0017089843750000, 0.0023803710937500, 0.0019836425781250, +0.0021667480468750, 0.0019531250000000, 0.0021362304687500, 0.0018310546875000, +0.0020751953125000, 0.0018615722656250, 0.0019531250000000, 0.0016784667968750, +0.0020141601562500, 0.0014343261718750, 0.0018310546875000, 0.0013427734375000, +0.0018615722656250, 0.0012817382812500, 0.0018005371093750, 0.0010681152343750, +0.0017700195312500, 0.0008544921875000, 0.0017700195312500, 0.0011901855468750, +0.0016479492187500, 0.0009460449218750, 0.0016174316406250, 0.0009460449218750, +0.0016174316406250}, +{0.0014648437500000, 0.0008544921875000, 0.0014648437500000, 0.0004577636718750, +0.0014648437500000, 0.0008239746093750, 0.0014038085937500, 0.0002746582031250, +0.0014648437500000, 0.0003662109375000, 0.0014038085937500, 0.0003967285156250, +0.0015563964843750, 0.0000915527343750, 0.0017089843750000, 0.0002441406250000, +0.0015258789062500, 0.0004577636718750, 0.0021057128906250, 0.0001831054687500, +0.0018920898437500, 0.0006713867187500, 0.0022583007812500, 0.0011596679687500, +0.0028991699218750, 0.0007019042968750, 0.0025329589843750, 0.0021972656250000, +0.0032958984375000, 0.0018615722656250, 0.0033569335937500, 0.0022277832031250, +0.0031738281250000, 0.0034179687500000, 0.0034790039062500, 0.0027770996093750, +0.0035400390625000, 0.0036315917968750, 0.0032043457031250, 0.0037841796875000, +0.0033264160156250, 0.0036010742187500, 0.0032348632812500, 0.0038146972656250, +0.0028686523437500, 0.0038146972656250, 0.0030517578125000, 0.0035400390625000, +0.0028076171875000, 0.0036010742187500, 0.0028991699218750, 0.0034179687500000, +0.0027770996093750, 0.0029907226562500, 0.0025024414062500, 0.0027465820312500, +0.0025634765625000, 0.0022583007812500, 0.0018615722656250, 0.0024108886718750, +0.0021667480468750, 0.0022888183593750, 0.0019836425781250, 0.0018920898437500, +0.0013427734375000, 0.0021057128906250, 0.0017700195312500, 0.0018615722656250, +0.0009155273437500, 0.0018005371093750, 0.0009765625000000, 0.0018310546875000, +0.0008544921875000, 0.0018310546875000, 0.0002746582031250, 0.0018615722656250, +0.0005798339843750, 0.0018615722656250, 0.0003051757812500, 0.0021057128906250, +0.0001831054687500, 0.0019531250000000, 0.0004882812500000, 0.0017395019531250, +0.0005493164062500, 0.0021057128906250, 0.0004272460937500, 0.0012512207031250, +0.0012207031250000, 0.0013732910156250, 0.0011291503906250, 0.0014343261718750, +0.0014343261718750, 0.0009155273437500, 0.0020446777343750, 0.0009765625000000, +0.0018005371093750, 0.0011291503906250, 0.0025634765625000, 0.0009155273437500, +0.0026550292968750, 0.0011291503906250, 0.0026245117187500, 0.0014343261718750, +0.0029602050781250, 0.0012207031250000, 0.0029296875000000, 0.0017089843750000, +0.0028686523437500, 0.0017395019531250, 0.0029602050781250, 0.0018310546875000, +0.0028991699218750, 0.0021972656250000, 0.0028076171875000, 0.0020446777343750, +0.0028686523437500, 0.0019531250000000, 0.0027160644531250, 0.0021667480468750, +0.0026550292968750, 0.0019531250000000, 0.0026245117187500, 0.0015869140625000, +0.0026245117187500, 0.0018005371093750, 0.0025939941406250, 0.0013122558593750, +0.0024108886718750, 0.0012512207031250, 0.0024108886718750, 0.0012817382812500, +0.0023193359375000, 0.0010070800781250, 0.0021057128906250, 0.0010070800781250, +0.0021362304687500, 0.0011291503906250, 0.0020141601562500, 0.0008850097656250, +0.0018920898437500, 0.0010070800781250, 0.0018310546875000, 0.0011596679687500, +0.0018310546875000, 0.0008850097656250, 0.0017395019531250, 0.0010681152343750, +0.0017700195312500, 0.0011291503906250, 0.0017395019531250, 0.0007934570312500, +0.0016479492187500, 0.0006713867187500, 0.0016784667968750, 0.0008239746093750, +0.0016784667968750, 0.0001831054687500, 0.0016174316406250, 0.0002136230468750, +0.0015563964843750, 0.0001220703125000, 0.0014953613281250, -0.0002746582031250, +0.0015258789062500, -0.0001525878906250, 0.0014953613281250, -0.0003356933593750, +0.0012817382812500, -0.0004272460937500, 0.0012817382812500, -0.0003051757812500, +0.0013122558593750, -0.0002746582031250, 0.0011291503906250, -0.0003967285156250, +0.0011291503906250, 0.0000000000000000, 0.0012512207031250, -0.0000915527343750, +0.0011901855468750, 0.0000305175781250, 0.0013122558593750, 0.0003051757812500, +0.0015258789062500, 0.0001831054687500, 0.0014038085937500, 0.0004882812500000, +0.0013732910156250, 0.0004272460937500, 0.0014343261718750, 0.0007019042968750, +0.0013122558593750, 0.0010681152343750, 0.0011596679687500, 0.0008239746093750, +0.0011291503906250, 0.0014648437500000, 0.0009155273437500, 0.0014343261718750, +0.0008239746093750, 0.0014953613281250, 0.0007629394531250, 0.0018005371093750, +0.0005798339843750, 0.0017395019531250, 0.0007019042968750, 0.0016174316406250, +0.0005493164062500, 0.0018005371093750, 0.0005798339843750, 0.0016479492187500, +0.0005187988281250, 0.0014038085937500, 0.0004272460937500, 0.0016174316406250, +0.0004577636718750, 0.0011901855468750, 0.0003967285156250, 0.0012207031250000, +0.0003967285156250, 0.0011901855468750, 0.0003051757812500, 0.0008850097656250, +0.0001525878906250, 0.0010070800781250, 0.0002136230468750, 0.0010681152343750, +-0.0000305175781250, 0.0008850097656250, -0.0000305175781250, 0.0009765625000000, +-0.0001525878906250, 0.0011291503906250, -0.0003051757812500, 0.0009460449218750, +-0.0002746582031250, 0.0011596679687500, -0.0007324218750000, 0.0011596679687500, +-0.0006408691406250, 0.0011291503906250, -0.0009460449218750, 0.0012207031250000, +-0.0014038085937500, 0.0011291503906250, -0.0011291503906250, 0.0011596679687500, +-0.0018005371093750, 0.0012207031250000, -0.0018005371093750, 0.0010986328125000, +-0.0016784667968750, 0.0010375976562500, -0.0020141601562500, 0.0012207031250000, +-0.0019531250000000, 0.0010375976562500, -0.0014343261718750, 0.0010681152343750, +-0.0016784667968750, 0.0010681152343750, -0.0011901855468750, 0.0009765625000000, +-0.0005493164062500, 0.0010986328125000, -0.0009765625000000, 0.0009460449218750, +0.0003051757812500, 0.0010375976562500, 0.0003967285156250, 0.0009765625000000, +0.0005493164062500, 0.0007934570312500, 0.0014038085937500, 0.0009765625000000, +0.0013427734375000, 0.0007324218750000, 0.0011901855468750, 0.0007934570312500, +0.0016174316406250, 0.0008544921875000, 0.0012207031250000, 0.0008239746093750, +0.0006103515625000, 0.0008544921875000, 0.0010681152343750, 0.0011901855468750, +0.0000610351562500, 0.0010986328125000, 0.0000000000000000, 0.0013122558593750, +-0.0000915527343750, 0.0016784667968750, -0.0007019042968750, 0.0014953613281250, +-0.0005798339843750, 0.0018615722656250, -0.0007324218750000, 0.0020141601562500, +-0.0008239746093750, 0.0018920898437500, -0.0007324218750000, 0.0020141601562500, +-0.0007019042968750, 0.0021362304687500, -0.0008239746093750, 0.0018615722656250, +-0.0008239746093750, 0.0020446777343750, -0.0007324218750000, 0.0019836425781250, +-0.0009460449218750, 0.0017089843750000, -0.0011596679687500, 0.0019836425781250, +-0.0010070800781250, 0.0018005371093750, -0.0016174316406250, 0.0017089843750000, +-0.0016174316406250, 0.0019531250000000, -0.0015869140625000, 0.0019226074218750, +-0.0019226074218750, 0.0018920898437500, -0.0018920898437500, 0.0022888183593750, +-0.0018005371093750, 0.0021667480468750, -0.0019226074218750, 0.0022277832031250, +-0.0017089843750000, 0.0025634765625000, -0.0014648437500000, 0.0022888183593750, +-0.0016479492187500, 0.0025634765625000, -0.0011291503906250, 0.0024719238281250, +-0.0010681152343750, 0.0025329589843750, -0.0009765625000000, 0.0027160644531250, +-0.0006408691406250, 0.0024719238281250, -0.0006713867187500, 0.0028381347656250, +-0.0006408691406250, 0.0027465820312500, -0.0004272460937500, 0.0026855468750000, +-0.0004272460937500, 0.0028991699218750, -0.0005187988281250, 0.0027160644531250, +-0.0004272460937500, 0.0025024414062500, -0.0003967285156250, 0.0026245117187500, +-0.0005187988281250, 0.0022888183593750, -0.0002441406250000, 0.0018920898437500, +-0.0001525878906250, 0.0021362304687500, -0.0003051757812500, 0.0014953613281250, +0.0003662109375000, 0.0014038085937500, 0.0002136230468750, 0.0014038085937500, +0.0004577636718750, 0.0010375976562500, 0.0010375976562500, 0.0011291503906250, +0.0006713867187500, 0.0008850097656250, 0.0009155273437500, 0.0008544921875000, +0.0009765625000000, 0.0008544921875000, 0.0010070800781250, 0.0007629394531250, +0.0010681152343750, 0.0007934570312500, 0.0009155273437500, 0.0008544921875000, +0.0013732910156250, 0.0006713867187500, 0.0011901855468750, 0.0009460449218750, +0.0014038085937500, 0.0012817382812500, 0.0019226074218750, 0.0010070800781250, +0.0014953613281250, 0.0018920898437500, 0.0019836425781250, 0.0017700195312500, +0.0021972656250000, 0.0020446777343750, 0.0018615722656250, 0.0026855468750000, +0.0018005371093750, 0.0023803710937500, 0.0021057128906250, 0.0028686523437500, +0.0012512207031250, 0.0030517578125000, 0.0014648437500000, 0.0029602050781250, +0.0013427734375000, 0.0030517578125000, 0.0003662109375000, 0.0027770996093750, +0.0011596679687500, 0.0011596679687500, 0.0015869140625000, 0.0015869140625000, +0.0017089843750000, 0.0011291503906250, 0.0015563964843750, 0.0001525878906250, +0.0014953613281250, 0.0004577636718750, 0.0016174316406250, 0.0000610351562500, +0.0011291503906250, -0.0002441406250000, 0.0013732910156250, -0.0000305175781250, +0.0010986328125000, 0.0000305175781250, 0.0004272460937500, -0.0002441406250000, +0.0006103515625000, 0.0005187988281250, 0.0002136230468750, 0.0002746582031250, +0.0000305175781250, 0.0004272460937500, 0.0003051757812500, 0.0010375976562500, +0.0002136230468750, 0.0006103515625000, -0.0000915527343750, 0.0013122558593750, +0.0011901855468750, 0.0011901855468750, 0.0007934570312500, 0.0014038085937500, +0.0010681152343750, 0.0019531250000000, 0.0021057128906250, 0.0015563964843750, +0.0015869140625000, 0.0022277832031250, 0.0025634765625000, 0.0021362304687500, +0.0025329589843750, 0.0019836425781250, 0.0025329589843750, 0.0022277832031250, +0.0031433105468750, 0.0020141601562500, 0.0030822753906250, 0.0019226074218750, +0.0024414062500000, 0.0018920898437500, 0.0028381347656250, 0.0018920898437500, +0.0022277832031250, 0.0017700195312500, 0.0013732910156250, 0.0016479492187500, +0.0020446777343750, 0.0021667480468750, 0.0008544921875000, 0.0018920898437500, +0.0007934570312500, 0.0021057128906250, 0.0009765625000000, 0.0026245117187500, +0.0003967285156250, 0.0022277832031250, 0.0005187988281250, 0.0028076171875000, +0.0012207031250000, 0.0028381347656250, 0.0007629394531250, 0.0026550292968750, +0.0014038085937500, 0.0028381347656250, 0.0024414062500000, 0.0027465820312500, +0.0016784667968750, 0.0022583007812500, 0.0029907226562500, 0.0023803710937500, +0.0030517578125000, 0.0021362304687500, 0.0029296875000000, 0.0017089843750000, +0.0036010742187500, 0.0019226074218750, 0.0032958984375000, 0.0014953613281250, +0.0028991699218750, 0.0014953613281250, 0.0032043457031250, 0.0013732910156250, +0.0028381347656250, 0.0011901855468750, 0.0022583007812500, 0.0013732910156250, +0.0025939941406250, 0.0007629394531250, 0.0020141601562500, 0.0010681152343750, +0.0020446777343750, 0.0005798339843750, 0.0022277832031250, -0.0001525878906250, +0.0021057128906250, 0.0005187988281250, 0.0021362304687500, -0.0009460449218750, +0.0020751953125000, -0.0009155273437500, 0.0023193359375000, -0.0009460449218750, +0.0021057128906250, -0.0018310546875000, 0.0018310546875000, -0.0015563964843750, +0.0021362304687500, -0.0014038085937500, 0.0015869140625000, -0.0019836425781250, +0.0016784667968750, -0.0014038085937500, 0.0017700195312500, -0.0007324218750000, +0.0014038085937500, -0.0014648437500000, 0.0015869140625000, 0.0001831054687500, +0.0019531250000000, -0.0000915527343750, 0.0016784667968750, 0.0001220703125000, +0.0020751953125000, 0.0012817382812500, 0.0025634765625000, 0.0007019042968750, +0.0021362304687500}, +{0.0002441406250000, 0.0031738281250000, 0.0004272460937500, 0.0038757324218750, +0.0003051757812500, 0.0040283203125000, 0.0000305175781250, 0.0037841796875000, +0.0003356933593750, 0.0039367675781250, 0.0005798339843750, 0.0039978027343750, +0.0003967285156250, 0.0033264160156250, 0.0008850097656250, 0.0035095214843750, +0.0008544921875000, 0.0032043457031250, 0.0009155273437500, 0.0021057128906250, +0.0014038085937500, 0.0014343261718750, 0.0011596679687500, 0.0010375976562500, +0.0020446777343750, 0.0010070800781250, 0.0017395019531250, 0.0009765625000000, +0.0018615722656250, 0.0008544921875000, 0.0023803710937500, 0.0007934570312500, +0.0022888183593750, 0.0009765625000000, 0.0023498535156250, 0.0008239746093750, +0.0024414062500000, 0.0009765625000000, 0.0023803710937500, 0.0010681152343750, +0.0024108886718750, 0.0008850097656250, 0.0025939941406250, 0.0013427734375000, +0.0025634765625000, 0.0011291503906250, 0.0027465820312500, 0.0013732910156250, +0.0022583007812500, 0.0017395019531250, 0.0019531250000000, 0.0013122558593750, +0.0024414062500000, 0.0021362304687500, 0.0010681152343750, 0.0019836425781250, +0.0011291503906250, 0.0019531250000000, 0.0010375976562500, 0.0024108886718750, +0.0003356933593750, 0.0020751953125000, 0.0006408691406250, 0.0022583007812500, +0.0006103515625000, 0.0020446777343750, 0.0002746582031250, 0.0021057128906250, +0.0009155273437500, 0.0023193359375000, 0.0014038085937500, 0.0019836425781250, +0.0008239746093750, 0.0027160644531250, 0.0025329589843750, 0.0025634765625000, +0.0025024414062500, 0.0025939941406250, 0.0027160644531250, 0.0030212402343750, +0.0037841796875000, 0.0029296875000000, 0.0034484863281250, 0.0027770996093750, +0.0035400390625000, 0.0029907226562500, 0.0038757324218750, 0.0025939941406250, +0.0032348632812500, 0.0021972656250000, 0.0026855468750000, 0.0024719238281250, +0.0030517578125000, 0.0014648437500000, 0.0016784667968750, 0.0015563964843750, +0.0016479492187500, 0.0013427734375000, 0.0015258789062500, 0.0007019042968750, +0.0006408691406250, 0.0010681152343750, 0.0009460449218750, 0.0003051757812500, +0.0010375976562500, 0.0004577636718750, 0.0006103515625000, 0.0001220703125000, +0.0011596679687500, -0.0004577636718750, 0.0017089843750000, 0.0000305175781250, +0.0011901855468750, -0.0014038085937500, 0.0022583007812500, -0.0010375976562500, +0.0021972656250000, -0.0014953613281250, 0.0020141601562500, -0.0026550292968750, +0.0024414062500000, -0.0019226074218750, 0.0022583007812500, -0.0032348632812500, +0.0018615722656250, -0.0033569335937500, 0.0019531250000000, -0.0031127929687500, +0.0018005371093750, -0.0038452148437500, 0.0014038085937500, -0.0037841796875000, +0.0015563964843750, -0.0029296875000000, 0.0017395019531250, -0.0034484863281250, +0.0016479492187500, -0.0026855468750000, 0.0018920898437500, -0.0016174316406250, +0.0022888183593750, -0.0025024414062500, 0.0021972656250000, -0.0004577636718750, +0.0025329589843750, -0.0006408691406250, 0.0025634765625000, -0.0005493164062500, +0.0026245117187500, 0.0007019042968750, 0.0028381347656250, 0.0000915527343750, +0.0028381347656250, 0.0002746582031250, 0.0028381347656250, 0.0006103515625000, +0.0030212402343750, -0.0000305175781250, 0.0030822753906250, -0.0005187988281250, +0.0030517578125000, -0.0001525878906250, 0.0030822753906250, -0.0014343261718750, +0.0031433105468750, -0.0013427734375000, 0.0031127929687500, -0.0016479492187500, +0.0032043457031250, -0.0025024414062500, 0.0032653808593750, -0.0020446777343750, +0.0030822753906250, -0.0025939941406250, 0.0030822753906250, -0.0028381347656250, +0.0031127929687500, -0.0024719238281250, 0.0027770996093750, -0.0024108886718750, +0.0025024414062500, -0.0026855468750000, 0.0027160644531250, -0.0014648437500000, +0.0021057128906250, -0.0018615722656250, 0.0020446777343750, -0.0013122558593750, +0.0021057128906250, -0.0001831054687500, 0.0018005371093750, -0.0008850097656250, +0.0018615722656250, 0.0006713867187500, 0.0020141601562500, 0.0005187988281250, +0.0018615722656250, 0.0007324218750000, 0.0021667480468750, 0.0017089843750000, +0.0025329589843750, 0.0012207031250000, 0.0022888183593750, 0.0018005371093750, +0.0027465820312500, 0.0018920898437500, 0.0028076171875000, 0.0017395019531250, +0.0027160644531250, 0.0018615722656250, 0.0028076171875000, 0.0018615722656250, +0.0026855468750000, 0.0013427734375000, 0.0025024414062500, 0.0014953613281250, +0.0024719238281250, 0.0011901855468750, 0.0023498535156250, 0.0006713867187500, +0.0021667480468750, 0.0010070800781250, 0.0021667480468750, 0.0001831054687500, +0.0021972656250000, 0.0002441406250000, 0.0021057128906250, 0.0000305175781250, +0.0021362304687500, -0.0006408691406250, 0.0022277832031250, -0.0003051757812500, +0.0022277832031250, -0.0010681152343750, 0.0022277832031250, -0.0011901855468750, +0.0023803710937500, -0.0012817382812500, 0.0023193359375000, -0.0017395019531250, +0.0022888183593750, -0.0018310546875000, 0.0024414062500000, -0.0017395019531250, +0.0022277832031250, -0.0020751953125000, 0.0023803710937500, -0.0017700195312500, +0.0022277832031250, -0.0014953613281250, 0.0020141601562500, -0.0019226074218750, +0.0022583007812500, -0.0005187988281250, 0.0018005371093750, -0.0008850097656250, +0.0019226074218750, -0.0001831054687500, 0.0019226074218750, 0.0011596679687500, +0.0016174316406250, 0.0003356933593750, 0.0017700195312500, 0.0021972656250000, +0.0015258789062500, 0.0020751953125000, 0.0015563964843750, 0.0023193359375000, +0.0015258789062500, 0.0035705566406250, 0.0013427734375000, 0.0031127929687500, +0.0014343261718750, 0.0037841796875000, 0.0013122558593750, 0.0039367675781250, +0.0013427734375000, 0.0038757324218750, 0.0013732910156250, 0.0041809082031250, +0.0014038085937500, 0.0041198730468750, 0.0014343261718750, 0.0039062500000000, +0.0014953613281250, 0.0041503906250000, 0.0015258789062500, 0.0039062500000000, +0.0015563964843750, 0.0036010742187500, 0.0017089843750000, 0.0039672851562500, +0.0017700195312500, 0.0030822753906250, 0.0016479492187500, 0.0033874511718750, +0.0017700195312500, 0.0030212402343750, 0.0017395019531250, 0.0021972656250000, +0.0015869140625000, 0.0026550292968750, 0.0017395019531250, 0.0015258789062500, +0.0015563964843750, 0.0015563964843750, 0.0015563964843750, 0.0014038085937500, +0.0016479492187500, 0.0006408691406250, 0.0015563964843750, 0.0009460449218750, +0.0015869140625000, 0.0007934570312500, 0.0016174316406250, 0.0006103515625000, +0.0016479492187500, 0.0008850097656250, 0.0017395019531250, 0.0010070800781250, +0.0017700195312500, 0.0009460449218750, 0.0018005371093750, 0.0015563964843750, +0.0021972656250000, 0.0014343261718750, 0.0020751953125000, 0.0017089843750000, +0.0023803710937500, 0.0022277832031250, 0.0028076171875000, 0.0019836425781250, +0.0025024414062500, 0.0025329589843750, 0.0032653808593750, 0.0026550292968750, +0.0032348632812500, 0.0026245117187500, 0.0032043457031250, 0.0028686523437500, +0.0036315917968750, 0.0029907226562500, 0.0034484863281250, 0.0027770996093750, +0.0032653808593750, 0.0029907226562500, 0.0034790039062500, 0.0028381347656250, +0.0032958984375000, 0.0024719238281250, 0.0030212402343750, 0.0027160644531250, +0.0032348632812500, 0.0023193359375000, 0.0028076171875000, 0.0022888183593750, +0.0028991699218750, 0.0023803710937500, 0.0027770996093750, 0.0023193359375000, +0.0025024414062500, 0.0023803710937500, 0.0026855468750000, 0.0026550292968750, +0.0023498535156250, 0.0027160644531250, 0.0023803710937500, 0.0027160644531250, +0.0022583007812500, 0.0029907226562500, 0.0018920898437500, 0.0030822753906250, +0.0020141601562500, 0.0027160644531250, 0.0020141601562500, 0.0029602050781250, +0.0018310546875000, 0.0028686523437500, 0.0020141601562500, 0.0024108886718750, +0.0022583007812500, 0.0024719238281250, 0.0021667480468750, 0.0018920898437500, +0.0027160644531250, 0.0020446777343750, 0.0024414062500000, 0.0021667480468750, +0.0027160644531250, 0.0019226074218750, 0.0033264160156250, 0.0020446777343750, +0.0028991699218750, 0.0021667480468750, 0.0038146972656250, 0.0021667480468750, +0.0037231445312500, 0.0022583007812500, 0.0036926269531250, 0.0024414062500000, +0.0041503906250000, 0.0023498535156250, 0.0039672851562500, 0.0021972656250000, +0.0038146972656250, 0.0022583007812500, 0.0039367675781250, 0.0020751953125000, +0.0036010742187500, 0.0018920898437500, 0.0032958984375000, 0.0019836425781250, +0.0034484863281250, 0.0016784667968750, 0.0027160644531250, 0.0018005371093750, +0.0027770996093750, 0.0015869140625000, 0.0025024414062500, 0.0013427734375000, +0.0019226074218750, 0.0015869140625000, 0.0021362304687500, 0.0010375976562500, +0.0015869140625000, 0.0010070800781250, 0.0014953613281250, 0.0010375976562500, +0.0014343261718750, 0.0008239746093750, 0.0011596679687500, 0.0008239746093750, +0.0013122558593750, 0.0010681152343750, 0.0008239746093750, 0.0009460449218750, +0.0009460449218750, 0.0009460449218750, 0.0007934570312500, 0.0011596679687500, +0.0004577636718750, 0.0011596679687500, 0.0006408691406250, 0.0012817382812500, +0.0000305175781250, 0.0012512207031250, 0.0001220703125000, 0.0014953613281250, +0.0000610351562500, 0.0017395019531250, -0.0003356933593750, 0.0016784667968750, +-0.0001525878906250, 0.0021667480468750, -0.0005187988281250, 0.0022277832031250, +-0.0004882812500000, 0.0022277832031250, -0.0005798339843750, 0.0024414062500000, +-0.0008544921875000, 0.0026245117187500, -0.0007019042968750, 0.0025024414062500, +-0.0009155273437500, 0.0026855468750000, -0.0010070800781250, 0.0026855468750000, +-0.0010375976562500, 0.0025939941406250, -0.0012207031250000, 0.0028686523437500, +-0.0013122558593750, 0.0025024414062500, -0.0012512207031250, 0.0025939941406250, +-0.0014038085937500, 0.0026245117187500, -0.0013122558593750, 0.0024108886718750, +-0.0011901855468750, 0.0025634765625000, -0.0014343261718750, 0.0026245117187500, +-0.0009765625000000, 0.0025634765625000, -0.0011901855468750, 0.0027770996093750, +-0.0009765625000000, 0.0029296875000000, -0.0005493164062500, 0.0028076171875000, +-0.0008239746093750, 0.0033874511718750, -0.0004577636718750, 0.0032043457031250, +-0.0003967285156250, 0.0032653808593750, -0.0005798339843750, 0.0037536621093750, +-0.0005187988281250, 0.0034484863281250, -0.0004272460937500, 0.0034790039062500, +-0.0008239746093750, 0.0035705566406250, -0.0008850097656250, 0.0033264160156250, +-0.0008850097656250, 0.0030517578125000, -0.0010375976562500, 0.0031433105468750, +-0.0010986328125000, 0.0029296875000000, -0.0009460449218750, 0.0027770996093750, +-0.0010681152343750, 0.0028381347656250, -0.0010070800781250, 0.0029296875000000, +-0.0008239746093750, 0.0028381347656250, -0.0009460449218750, 0.0030517578125000, +-0.0005493164062500, 0.0030212402343750, -0.0006713867187500, 0.0030212402343750, +-0.0004577636718750, 0.0030517578125000, -0.0000915527343750, 0.0030517578125000, +-0.0003051757812500, 0.0031433105468750, 0.0004882812500000, 0.0031127929687500, +0.0003662109375000, 0.0031433105468750, 0.0005187988281250, 0.0032653808593750, +0.0010070800781250, 0.0031738281250000, 0.0006713867187500, 0.0032958984375000, +0.0011596679687500, 0.0033569335937500, 0.0011291503906250, 0.0033569335937500, +0.0010681152343750, 0.0033874511718750, 0.0013122558593750, 0.0034790039062500, +0.0010986328125000, 0.0031738281250000, 0.0010681152343750, 0.0034179687500000, +0.0011596679687500}, +{0.0039062500000000, 0.0001220703125000, 0.0042114257812500, 0.0004272460937500, +0.0039062500000000, 0.0004577636718750, 0.0032958984375000, 0.0002441406250000, +0.0037536621093750, 0.0011901855468750, 0.0027465820312500, 0.0008850097656250, +0.0029907226562500, 0.0010986328125000, 0.0026550292968750, 0.0018310546875000, +0.0018920898437500, 0.0013122558593750, 0.0023803710937500, 0.0021057128906250, +0.0013122558593750, 0.0021667480468750, 0.0014953613281250, 0.0020751953125000, +0.0011901855468750, 0.0024719238281250, 0.0003356933593750, 0.0023498535156250, +0.0008239746093750, 0.0023498535156250, -0.0001831054687500, 0.0025634765625000, +-0.0001525878906250, 0.0024108886718750, -0.0003356933593750, 0.0020751953125000, +-0.0010070800781250, 0.0022888183593750, -0.0007934570312500, 0.0021362304687500, +-0.0013122558593750, 0.0020751953125000, -0.0014038085937500, 0.0021972656250000, +-0.0013427734375000, 0.0021972656250000, -0.0015258789062500, 0.0021667480468750, +-0.0014953613281250, 0.0022277832031250, -0.0014038085937500, 0.0023193359375000, +-0.0014648437500000, 0.0021972656250000, -0.0013427734375000, 0.0020751953125000, +-0.0011291503906250, 0.0021667480468750, -0.0012207031250000, 0.0019836425781250, +-0.0009765625000000, 0.0019836425781250, -0.0009765625000000, 0.0020446777343750, +-0.0009765625000000, 0.0020141601562500, -0.0008850097656250, 0.0020751953125000, +-0.0008850097656250, 0.0022888183593750, -0.0007324218750000, 0.0023193359375000, +-0.0007934570312500, 0.0024414062500000, -0.0006713867187500, 0.0025939941406250, +-0.0004882812500000, 0.0025024414062500, -0.0006103515625000, 0.0029907226562500, +-0.0002441406250000, 0.0028991699218750, -0.0001525878906250, 0.0029907226562500, +-0.0000305175781250, 0.0033874511718750, 0.0002441406250000, 0.0032348632812500, +0.0002136230468750, 0.0033874511718750, 0.0003662109375000, 0.0033569335937500, +0.0005493164062500, 0.0033569335937500, 0.0003356933593750, 0.0033874511718750, +0.0002441406250000, 0.0032958984375000, 0.0004272460937500, 0.0033264160156250, +-0.0002746582031250, 0.0031127929687500, -0.0002136230468750, 0.0032043457031250, +-0.0003662109375000, 0.0032043457031250, -0.0009460449218750, 0.0028991699218750, +-0.0006408691406250, 0.0035095214843750, -0.0009765625000000, 0.0032958984375000, +-0.0010681152343750, 0.0032348632812500, -0.0010070800781250, 0.0036621093750000, +-0.0010986328125000, 0.0034484863281250, -0.0010681152343750, 0.0032653808593750, +-0.0010986328125000, 0.0034484863281250, -0.0011596679687500, 0.0031433105468750, +-0.0011901855468750, 0.0028686523437500, -0.0011596679687500, 0.0030822753906250, +-0.0011901855468750, 0.0027160644531250, -0.0011596679687500, 0.0026550292968750, +-0.0010986328125000, 0.0026550292968750, -0.0011291503906250, 0.0024414062500000, +-0.0011901855468750, 0.0025024414062500, -0.0011596679687500, 0.0024414062500000, +-0.0011291503906250, 0.0024719238281250, -0.0012207031250000, 0.0025024414062500, +-0.0010375976562500, 0.0024719238281250, -0.0009765625000000, 0.0024414062500000, +-0.0011901855468750, 0.0025329589843750, -0.0005187988281250, 0.0025024414062500, +-0.0007019042968750, 0.0025634765625000, -0.0005187988281250, 0.0025634765625000, +0.0000610351562500, 0.0025939941406250, -0.0002441406250000, 0.0026550292968750, +0.0004272460937500, 0.0027160644531250, 0.0004882812500000, 0.0027160644531250, +0.0005493164062500, 0.0028076171875000, 0.0009460449218750, 0.0028991699218750, +0.0008239746093750, 0.0024414062500000, 0.0008544921875000, 0.0027770996093750, +0.0009765625000000, 0.0024719238281250, 0.0009155273437500, 0.0020141601562500, +0.0007629394531250, 0.0025024414062500, 0.0008239746093750, 0.0016784667968750, +0.0005493164062500, 0.0018615722656250, 0.0005493164062500, 0.0018615722656250, +0.0006408691406250, 0.0013427734375000, 0.0004272460937500, 0.0017395019531250, +0.0004272460937500, 0.0014648437500000, 0.0006713867187500, 0.0014953613281250, +0.0004577636718750, 0.0014953613281250, 0.0007019042968750, 0.0014343261718750, +0.0011291503906250, 0.0016174316406250, 0.0007629394531250, 0.0014038085937500, +0.0015869140625000, 0.0015258789062500, 0.0014953613281250, 0.0014038085937500, +0.0015563964843750, 0.0012207031250000, 0.0021667480468750, 0.0015258789062500, +0.0019531250000000, 0.0011291503906250, 0.0018920898437500, 0.0012207031250000, +0.0021972656250000, 0.0012207031250000, 0.0017395019531250, 0.0010375976562500, +0.0012512207031250, 0.0012817382812500, 0.0017089843750000, 0.0011596679687500, +0.0004272460937500, 0.0012817382812500, 0.0005798339843750, 0.0013427734375000, +0.0002746582031250, 0.0012817382812500, -0.0005798339843750, 0.0014953613281250, +-0.0002441406250000, 0.0012817382812500, -0.0009765625000000, 0.0014343261718750, +-0.0010070800781250, 0.0015258789062500, -0.0008239746093750, 0.0014038085937500, +-0.0010070800781250, 0.0015869140625000, -0.0009765625000000, 0.0017089843750000, +-0.0006408691406250, 0.0016784667968750, -0.0007324218750000, 0.0018920898437500, +-0.0006103515625000, 0.0020446777343750, -0.0002746582031250, 0.0020446777343750, +-0.0003356933593750, 0.0022888183593750, -0.0004882812500000, 0.0023193359375000, +-0.0003051757812500, 0.0022888183593750, -0.0005798339843750, 0.0024414062500000, +-0.0009155273437500, 0.0024108886718750, -0.0006713867187500, 0.0022583007812500, +-0.0014648437500000, 0.0024108886718750, -0.0013732910156250, 0.0022888183593750, +-0.0015258789062500, 0.0021362304687500, -0.0021362304687500, 0.0022888183593750, +-0.0018920898437500, 0.0021057128906250, -0.0021667480468750, 0.0020751953125000, +-0.0021972656250000, 0.0021667480468750, -0.0019836425781250, 0.0021057128906250, +-0.0019531250000000, 0.0020751953125000, -0.0020141601562500, 0.0024719238281250, +-0.0016784667968750, 0.0023498535156250, -0.0016174316406250, 0.0025024414062500, +-0.0018005371093750, 0.0028686523437500, -0.0018005371093750, 0.0027465820312500, +-0.0018005371093750, 0.0032348632812500, -0.0020446777343750, 0.0031433105468750, +-0.0021362304687500, 0.0033264160156250, -0.0021667480468750, 0.0037841796875000, +-0.0023498535156250, 0.0034790039062500, -0.0024414062500000, 0.0040283203125000, +-0.0018310546875000, 0.0040283203125000, -0.0021667480468750, 0.0040283203125000, +-0.0017395019531250, 0.0043945312500000, -0.0009460449218750, 0.0042114257812500, +-0.0014038085937500, 0.0041198730468750, -0.0002746582031250, 0.0043029785156250, +-0.0003356933593750, 0.0039978027343750, -0.0000915527343750, 0.0037536621093750, +0.0006713867187500, 0.0040283203125000, 0.0003967285156250, 0.0032348632812500, +0.0009155273437500, 0.0033569335937500, 0.0009765625000000, 0.0032043457031250, +0.0010986328125000, 0.0026855468750000, 0.0012817382812500, 0.0028991699218750, +0.0010986328125000, 0.0024414062500000, 0.0018615722656250, 0.0024414062500000, +0.0016479492187500, 0.0023193359375000, 0.0018920898437500, 0.0020141601562500, +0.0025329589843750, 0.0021057128906250, 0.0021667480468750, 0.0017700195312500, +0.0026245117187500, 0.0017700195312500, 0.0027160644531250, 0.0017395019531250, +0.0025024414062500, 0.0014648437500000, 0.0026245117187500, 0.0016174316406250, +0.0000915527343750, 0.0018005371093750, 0.0015869140625000, 0.0017089843750000, +0.0010681152343750, 0.0018920898437500, 0.0012207031250000, 0.0021667480468750, +0.0018310546875000, 0.0020751953125000, 0.0015869140625000, 0.0022583007812500, +0.0020141601562500, 0.0023498535156250, 0.0019836425781250, 0.0022277832031250, +0.0018310546875000, 0.0022277832031250, 0.0019531250000000, 0.0022888183593750, +0.0018920898437500, 0.0019836425781250, 0.0016784667968750, 0.0021057128906250, +0.0016174316406250, 0.0020141601562500, 0.0018310546875000, 0.0017395019531250, +0.0018005371093750, 0.0019531250000000, 0.0015869140625000, 0.0012817382812500, +0.0025024414062500, 0.0016174316406250, 0.0023193359375000, 0.0012817382812500, +0.0024719238281250, 0.0007019042968750, 0.0030822753906250, 0.0012817382812500, +0.0027160644531250, -0.0001525878906250, 0.0029907226562500, 0.0003356933593750, +0.0032348632812500, 0.0000000000000000, 0.0028991699218750, -0.0012207031250000, +0.0028076171875000, -0.0004272460937500, 0.0032348632812500, -0.0013427734375000, +0.0021667480468750, -0.0014038085937500, 0.0025024414062500, -0.0012207031250000, +0.0022583007812500, -0.0014953613281250, 0.0014343261718750, -0.0013732910156250, +0.0019836425781250, -0.0013427734375000, 0.0009765625000000, -0.0012512207031250, +0.0009765625000000, -0.0014038085937500, 0.0010986328125000, -0.0014648437500000, +0.0006103515625000, -0.0012817382812500, 0.0007019042968750, -0.0019226074218750, +0.0014038085937500, -0.0018615722656250, 0.0009765625000000, -0.0018005371093750, +0.0015563964843750, -0.0022583007812500, 0.0025329589843750, -0.0021057128906250, +0.0018310546875000, -0.0015869140625000, 0.0026855468750000, -0.0020141601562500, +0.0030212402343750, -0.0011596679687500, 0.0027465820312500, -0.0002746582031250, +0.0028076171875000, -0.0010375976562500, 0.0028991699218750, 0.0011596679687500, +0.0019226074218750, 0.0008544921875000, 0.0021667480468750, 0.0013122558593750, +0.0018310546875000, 0.0029296875000000, 0.0009460449218750, 0.0021667480468750, +0.0012512207031250, 0.0032348632812500, 0.0007324218750000, 0.0035705566406250, +0.0006103515625000, 0.0031738281250000, 0.0007629394531250, 0.0034484863281250, +0.0005798339843750, 0.0036621093750000, 0.0005798339843750, 0.0023193359375000, +0.0007934570312500, 0.0028381347656250, 0.0008544921875000, 0.0021667480468750, +0.0009155273437500, 0.0009155273437500, 0.0011291503906250, 0.0018310546875000, +0.0012817382812500, 0.0002441406250000, 0.0012207031250000, 0.0001220703125000, +0.0014038085937500, 0.0004577636718750, 0.0013732910156250, -0.0002136230468750, +0.0010986328125000, -0.0002136230468750, 0.0013427734375000, 0.0007629394531250, +0.0010986328125000, 0.0001525878906250, 0.0010070800781250, 0.0007934570312500, +0.0010681152343750, 0.0018615722656250, 0.0010375976562500, 0.0010070800781250, +0.0010986328125000, 0.0022888183593750, 0.0012207031250000, 0.0022583007812500, +0.0012817382812500, 0.0018920898437500, 0.0013122558593750, 0.0023803710937500, +0.0014343261718750, 0.0022583007812500, 0.0015258789062500, 0.0012512207031250, +0.0015563964843750, 0.0017395019531250, 0.0016479492187500, 0.0010070800781250, +0.0016784667968750, -0.0001220703125000, 0.0016784667968750, 0.0006408691406250, +0.0016784667968750, -0.0012512207031250, 0.0018310546875000, -0.0011291503906250, +0.0018310546875000, -0.0014648437500000, 0.0018920898437500, -0.0027465820312500, +0.0020751953125000, -0.0021667480468750, 0.0019531250000000, -0.0029907226562500, +0.0020751953125000, -0.0033264160156250, 0.0021362304687500, -0.0029296875000000, +0.0020446777343750, -0.0031127929687500, 0.0020446777343750, -0.0033874511718750, +0.0021362304687500, -0.0022583007812500, 0.0017395019531250, -0.0027160644531250, +0.0018310546875000, -0.0020446777343750, 0.0017700195312500, -0.0008850097656250, +0.0014953613281250, -0.0017700195312500, 0.0016174316406250, 0.0001831054687500, +0.0016479492187500, -0.0000305175781250, 0.0015869140625000, 0.0003051757812500, +0.0016784667968750, 0.0016174316406250, 0.0018615722656250, 0.0009155273437500, +0.0018005371093750, 0.0020141601562500, 0.0019226074218750, 0.0020446777343750, +0.0019836425781250, 0.0019531250000000, 0.0018615722656250, 0.0025634765625000, +0.0018615722656250}, +{0.0012512207031250, -0.0006103515625000, 0.0010070800781250, -0.0005798339843750, +0.0010375976562500, -0.0005187988281250, 0.0012817382812500, -0.0003051757812500, +0.0011901855468750, -0.0004577636718750, 0.0013122558593750, -0.0006408691406250, +0.0014343261718750, -0.0003356933593750, 0.0012207031250000, -0.0008850097656250, +0.0016784667968750, -0.0007934570312500, 0.0018310546875000, -0.0006713867187500, +0.0015258789062500, -0.0009765625000000, 0.0016174316406250, -0.0007324218750000, +0.0018310546875000, -0.0003051757812500, 0.0010375976562500, -0.0005187988281250, +0.0012512207031250, 0.0000610351562500, 0.0009765625000000, 0.0007324218750000, +0.0002136230468750, 0.0004882812500000, 0.0005798339843750, 0.0018310546875000, +0.0003967285156250, 0.0017395019531250, 0.0000915527343750, 0.0020446777343750, +0.0004272460937500, 0.0030212402343750, 0.0007934570312500, 0.0026855468750000, +0.0007629394531250, 0.0030212402343750, 0.0014038085937500, 0.0033264160156250, +0.0015258789062500, 0.0028381347656250, 0.0014038085937500, 0.0026855468750000, +0.0017700195312500, 0.0030822753906250, 0.0019531250000000, 0.0016784667968750, +0.0011291503906250, 0.0019836425781250, 0.0014343261718750, 0.0015563964843750, +0.0010070800781250, 0.0003662109375000, 0.0000610351562500, 0.0009460449218750, +0.0005187988281250, -0.0000610351562500, -0.0002441406250000, -0.0000915527343750, +-0.0004272460937500, 0.0001831054687500, -0.0002746582031250, -0.0001525878906250, +-0.0004577636718750, -0.0000305175781250, -0.0004882812500000, 0.0007629394531250, +0.0000915527343750, 0.0006103515625000, -0.0000305175781250, 0.0010681152343750, +0.0002746582031250, 0.0019836425781250, 0.0008850097656250, 0.0016479492187500, +0.0006408691406250, 0.0022583007812500, 0.0010681152343750, 0.0025024414062500, +0.0013122558593750, 0.0021667480468750, 0.0011596679687500, 0.0021972656250000, +0.0010986328125000, 0.0024414062500000, 0.0012207031250000, 0.0013732910156250, +0.0008850097656250, 0.0016174316406250, 0.0010375976562500, 0.0012207031250000, +0.0010070800781250, 0.0001831054687500, 0.0007629394531250, 0.0006713867187500, +0.0009155273437500, -0.0001220703125000, 0.0008239746093750, -0.0003662109375000, +0.0007629394531250, -0.0001525878906250, 0.0008544921875000, -0.0002746582031250, +0.0007629394531250, -0.0004882812500000, 0.0007019042968750, 0.0001831054687500, +0.0008544921875000, -0.0002136230468750, 0.0007324218750000, 0.0001831054687500, +0.0007629394531250, 0.0008850097656250, 0.0008544921875000, 0.0003051757812500, +0.0006408691406250, 0.0013122558593750, 0.0009765625000000, 0.0011901855468750, +0.0007019042968750, 0.0012207031250000, 0.0009155273437500, 0.0018615722656250, +0.0013122558593750, 0.0014953613281250, 0.0008850097656250, 0.0017089843750000, +0.0016174316406250, 0.0018310546875000, 0.0014648437500000, 0.0016174316406250, +0.0014343261718750, 0.0015563964843750, 0.0018310546875000, 0.0015869140625000, +0.0014953613281250, 0.0011291503906250, 0.0016784667968750, 0.0012207031250000, +0.0015869140625000, 0.0010375976562500, 0.0014343261718750, 0.0007324218750000, +0.0014343261718750, 0.0008239746093750, 0.0012512207031250, 0.0004272460937500, +0.0013427734375000, 0.0005187988281250, 0.0011596679687500, 0.0003051757812500, +0.0011596679687500, -0.0000305175781250, 0.0011901855468750, 0.0001831054687500, +0.0010375976562500, -0.0003051757812500, 0.0012207031250000, -0.0002441406250000, +0.0011596679687500, -0.0002746582031250, 0.0011291503906250, -0.0005187988281250, +0.0012512207031250, -0.0004577636718750, 0.0012207031250000, -0.0004272460937500, +0.0013427734375000, -0.0005187988281250, 0.0013122558593750, -0.0003662109375000, +0.0013427734375000, -0.0002441406250000, 0.0015258789062500, -0.0003356933593750, +0.0014038085937500, -0.0001220703125000, 0.0015869140625000, -0.0000915527343750, +0.0014953613281250, -0.0000915527343750, 0.0015258789062500, 0.0000610351562500, +0.0016784667968750, 0.0000305175781250, 0.0015563964843750, -0.0000610351562500, +0.0018005371093750, 0.0000610351562500, 0.0017089843750000, -0.0001220703125000, +0.0017700195312500, -0.0003356933593750, 0.0019226074218750, -0.0000915527343750, +0.0017395019531250, -0.0007019042968750, 0.0019531250000000, -0.0005798339843750, +0.0018005371093750, -0.0007629394531250, 0.0018005371093750, -0.0012817382812500, +0.0019226074218750, -0.0009155273437500, 0.0017395019531250, -0.0015258789062500, +0.0020141601562500, -0.0014648437500000, 0.0018310546875000, -0.0014648437500000, +0.0018615722656250, -0.0017700195312500, 0.0021362304687500, -0.0015869140625000, +0.0018310546875000, -0.0013732910156250, 0.0022888183593750, -0.0014953613281250, +0.0020446777343750, -0.0013122558593750, 0.0021972656250000, -0.0010375976562500, +0.0025024414062500, -0.0011901855468750, 0.0020751953125000, -0.0009460449218750, +0.0026855468750000, -0.0009155273437500, 0.0024108886718750, -0.0009155273437500, +0.0023803710937500, -0.0007629394531250, 0.0027160644531250, -0.0008239746093750, +0.0023193359375000, -0.0007629394531250, 0.0024108886718750, -0.0006408691406250, +0.0023193359375000, -0.0007629394531250, 0.0021667480468750, -0.0008544921875000, +0.0020751953125000, -0.0007324218750000, 0.0018920898437500, -0.0013427734375000, +0.0020446777343750, -0.0011596679687500, 0.0018310546875000, -0.0014648437500000, +0.0018920898437500, -0.0021057128906250, 0.0020751953125000, -0.0017395019531250, +0.0017700195312500, -0.0022888183593750, 0.0020141601562500, -0.0024414062500000, +0.0019226074218750, -0.0021667480468750, 0.0019226074218750, -0.0022583007812500, +0.0020446777343750, -0.0023193359375000, 0.0017700195312500, -0.0015869140625000, +0.0021972656250000, -0.0017700195312500, 0.0020751953125000, -0.0013122558593750, +0.0022583007812500, -0.0006408691406250, 0.0026245117187500, -0.0009460449218750, +0.0024719238281250, 0.0001831054687500, 0.0027770996093750, 0.0000305175781250, +0.0028076171875000, 0.0003967285156250, 0.0028076171875000, 0.0012207031250000, +0.0030212402343750, 0.0008239746093750, 0.0029907226562500, 0.0014343261718750, +0.0029602050781250, 0.0015563964843750, 0.0030517578125000, 0.0013732910156250, +0.0029602050781250, 0.0014343261718750, 0.0028381347656250, 0.0014343261718750, +0.0028991699218750, 0.0013122558593750, 0.0025634765625000, 0.0011596679687500, +0.0026245117187500, 0.0012512207031250, 0.0024719238281250, 0.0014343261718750, +0.0021972656250000, 0.0015869140625000, 0.0022583007812500, 0.0018920898437500, +0.0018920898437500, 0.0019836425781250, 0.0019836425781250, 0.0017700195312500, +0.0019226074218750, 0.0018310546875000, 0.0016784667968750, 0.0020141601562500, +0.0018920898437500, 0.0016479492187500, 0.0014648437500000, 0.0016174316406250, +0.0015563964843750, 0.0016479492187500, 0.0014648437500000, 0.0015563964843750, +0.0012207031250000, 0.0015563964843750, 0.0013732910156250, 0.0016174316406250, +0.0010070800781250, 0.0016479492187500, 0.0010070800781250, 0.0016479492187500, +0.0010986328125000, 0.0016174316406250, 0.0009460449218750, 0.0015258789062500, +0.0009460449218750, 0.0016174316406250, 0.0011596679687500, 0.0014038085937500, +0.0010375976562500, 0.0014038085937500, 0.0012817382812500, 0.0014343261718750, +0.0015869140625000, 0.0010986328125000, 0.0014343261718750, 0.0014648437500000, +0.0018920898437500, 0.0013732910156250, 0.0019836425781250, 0.0012207031250000, +0.0019531250000000, 0.0013732910156250, 0.0022277832031250, 0.0012207031250000, +0.0021972656250000, 0.0010986328125000, 0.0019531250000000, 0.0012817382812500, +0.0021362304687500, 0.0011291503906250, 0.0019836425781250, 0.0008850097656250, +0.0017089843750000, 0.0011901855468750, 0.0018920898437500, 0.0008239746093750, +0.0014038085937500, 0.0008544921875000, 0.0015258789062500, 0.0009765625000000, +0.0015258789062500, 0.0008239746093750, 0.0012207031250000, 0.0009765625000000, +0.0013732910156250, 0.0011901855468750, 0.0012817382812500, 0.0010986328125000, +0.0013427734375000, 0.0012207031250000, 0.0012512207031250, 0.0015563964843750, +0.0010986328125000, 0.0012512207031250, 0.0012817382812500, 0.0017089843750000, +0.0009155273437500, 0.0015563964843750, 0.0010681152343750, 0.0015563964843750, +0.0008850097656250, 0.0019226074218750, 0.0005187988281250, 0.0017089843750000, +0.0007934570312500, 0.0018005371093750, 0.0002746582031250, 0.0017700195312500, +0.0002136230468750, 0.0017395019531250, 0.0001831054687500, 0.0017700195312500, +-0.0001220703125000, 0.0017700195312500, -0.0001525878906250, 0.0019531250000000, +-0.0000610351562500, 0.0018920898437500, -0.0002441406250000, 0.0020141601562500, +-0.0000610351562500, 0.0021972656250000, 0.0001525878906250, 0.0020751953125000, +-0.0000305175781250, 0.0023803710937500, 0.0003967285156250, 0.0024108886718750, +0.0003662109375000, 0.0022888183593750, 0.0002441406250000, 0.0024414062500000, +0.0003662109375000, 0.0024719238281250, 0.0002441406250000, 0.0019531250000000, +0.0002746582031250, 0.0021057128906250, 0.0002136230468750, 0.0018615722656250, +0.0001525878906250, 0.0014343261718750, 0.0001220703125000, 0.0016174316406250, +0.0001220703125000, 0.0010986328125000, 0.0000915527343750, 0.0010070800781250, +0.0000915527343750, 0.0010681152343750, 0.0001525878906250, 0.0008850097656250, +0.0002136230468750, 0.0007629394531250, 0.0002136230468750, 0.0009460449218750, +0.0003967285156250, 0.0008850097656250, 0.0002746582031250, 0.0008544921875000, +0.0003051757812500, 0.0009765625000000, 0.0005187988281250, 0.0008544921875000, +0.0004577636718750, 0.0007019042968750, 0.0003967285156250, 0.0007019042968750, +0.0005493164062500, 0.0006713867187500, 0.0003356933593750, 0.0005493164062500, +0.0001220703125000, 0.0004577636718750, 0.0003356933593750, 0.0004577636718750, +-0.0000915527343750, 0.0003662109375000, -0.0000305175781250, 0.0003356933593750, +-0.0000305175781250, 0.0003967285156250, -0.0003356933593750, 0.0001831054687500, +-0.0002136230468750, 0.0003662109375000, -0.0001220703125000, 0.0002136230468750, +-0.0002136230468750, 0.0002746582031250, 0.0000000000000000, 0.0003967285156250, +0.0002136230468750, 0.0001525878906250, 0.0000305175781250, 0.0005187988281250, +0.0004577636718750, 0.0003051757812500, 0.0003662109375000, 0.0005187988281250, +0.0004272460937500, 0.0008850097656250, 0.0006713867187500, 0.0005187988281250, +0.0004272460937500, 0.0012512207031250, 0.0008239746093750, 0.0010681152343750, +0.0005798339843750, 0.0011596679687500, 0.0006103515625000, 0.0017089843750000, +0.0009155273437500, 0.0014343261718750, 0.0006103515625000, 0.0016174316406250, +0.0010070800781250, 0.0017089843750000, 0.0009460449218750, 0.0015869140625000, +0.0009155273437500, 0.0015869140625000, 0.0010986328125000, 0.0016479492187500, +0.0009765625000000, 0.0014343261718750, 0.0007934570312500, 0.0014038085937500, +0.0010070800781250, 0.0013122558593750, 0.0007324218750000, 0.0011901855468750, +0.0005187988281250, 0.0010986328125000, 0.0008239746093750, 0.0010375976562500, +-0.0000305175781250, 0.0008239746093750, 0.0000915527343750, 0.0008544921875000, +0.0000305175781250, 0.0008544921875000, -0.0005493164062500, 0.0006103515625000, +-0.0003356933593750, 0.0009155273437500, -0.0005187988281250, 0.0007019042968750, +-0.0006408691406250, 0.0008544921875000, -0.0005187988281250, 0.0011291503906250, +-0.0005798339843750, 0.0007629394531250, -0.0006408691406250, 0.0012512207031250, +-0.0003356933593750}, +{-0.0000915527343750, 0.0021057128906250, -0.0005493164062500, 0.0021362304687500, +-0.0006103515625000, 0.0019836425781250, -0.0007019042968750, 0.0021362304687500, +-0.0010070800781250, 0.0021057128906250, -0.0008544921875000, 0.0017700195312500, +-0.0010375976562500, 0.0019531250000000, -0.0010681152343750, 0.0017089843750000, +-0.0009460449218750, 0.0012207031250000, -0.0009765625000000, 0.0015563964843750, +-0.0009765625000000, 0.0007019042968750, -0.0007934570312500, 0.0008239746093750, +-0.0007934570312500, 0.0006713867187500, -0.0006713867187500, 0.0001525878906250, +-0.0005798339843750, 0.0003356933593750, -0.0006408691406250, 0.0000915527343750, +-0.0004272460937500, -0.0000305175781250, -0.0004882812500000, 0.0000610351562500, +-0.0003662109375000, 0.0000000000000000, -0.0002441406250000, -0.0000610351562500, +-0.0004272460937500, 0.0001525878906250, -0.0000610351562500, 0.0001525878906250, +-0.0001831054687500, 0.0001525878906250, -0.0001525878906250, 0.0002746582031250, +0.0000610351562500, 0.0001525878906250, -0.0000915527343750, 0.0002136230468750, +0.0000915527343750, 0.0002746582031250, 0.0000610351562500, 0.0000610351562500, +0.0000610351562500, -0.0001220703125000, 0.0002136230468750, -0.0000305175781250, +0.0001831054687500, -0.0004577636718750, 0.0003662109375000, -0.0004577636718750, +0.0003662109375000, -0.0003967285156250, 0.0003662109375000, -0.0004882812500000, +0.0004882812500000, -0.0005493164062500, 0.0005187988281250, -0.0003967285156250, +0.0008544921875000, -0.0003356933593750, 0.0007324218750000, -0.0004577636718750, +0.0010375976562500, -0.0003967285156250, 0.0014343261718750, -0.0003051757812500, +0.0011596679687500, -0.0006408691406250, 0.0017395019531250, -0.0004577636718750, +0.0017700195312500, -0.0005187988281250, 0.0016174316406250, -0.0008239746093750, +0.0017700195312500, -0.0004577636718750, 0.0018005371093750, -0.0007019042968750, +0.0011901855468750, -0.0006713867187500, 0.0013122558593750, -0.0004882812500000, +0.0008239746093750, -0.0005493164062500, 0.0000915527343750, -0.0003967285156250, +0.0003662109375000, -0.0002136230468750, -0.0007934570312500, -0.0002136230468750, +-0.0008544921875000, -0.0001525878906250, -0.0010986328125000, 0.0000000000000000, +-0.0018310546875000, 0.0000000000000000, -0.0016174316406250, 0.0001831054687500, +-0.0020141601562500, 0.0002136230468750, -0.0021972656250000, 0.0003356933593750, +-0.0020141601562500, 0.0005493164062500, -0.0020751953125000, 0.0005493164062500, +-0.0021362304687500, 0.0008239746093750, -0.0013122558593750, 0.0009155273437500, +-0.0016479492187500, 0.0010070800781250, -0.0011291503906250, 0.0010986328125000, +-0.0002441406250000, 0.0012512207031250, -0.0007934570312500, 0.0011596679687500, +0.0005798339843750, 0.0013122558593750, 0.0004882812500000, 0.0012512207031250, +0.0007019042968750, 0.0011291503906250, 0.0017089843750000, 0.0013427734375000, +0.0012817382812500, 0.0010070800781250, 0.0019836425781250, 0.0010681152343750, +0.0021057128906250, 0.0011596679687500, 0.0020446777343750, 0.0010070800781250, +0.0022583007812500, 0.0010986328125000, 0.0021972656250000, 0.0010375976562500, +0.0020751953125000, 0.0010070800781250, 0.0021362304687500, 0.0010375976562500, +0.0020141601562500, 0.0010070800781250, 0.0019531250000000, 0.0010070800781250, +0.0019836425781250, 0.0009155273437500, 0.0017700195312500, 0.0008850097656250, +0.0018005371093750, 0.0009155273437500, 0.0016479492187500, 0.0008239746093750, +0.0013122558593750, 0.0008239746093750, 0.0013427734375000, 0.0007934570312500, +0.0010986328125000, 0.0007629394531250, 0.0010375976562500, 0.0008544921875000, +0.0010681152343750, 0.0009765625000000, 0.0009765625000000, 0.0009155273437500, +0.0009460449218750, 0.0012207031250000, 0.0011596679687500, 0.0012207031250000, +0.0011596679687500, 0.0013427734375000, 0.0012207031250000, 0.0016479492187500, +0.0012817382812500, 0.0015563964843750, 0.0011901855468750, 0.0018920898437500, +0.0011291503906250, 0.0018920898437500, 0.0012207031250000, 0.0020446777343750, +0.0011291503906250, 0.0022888183593750, 0.0009765625000000, 0.0021362304687500, +0.0009765625000000, 0.0024414062500000, 0.0009765625000000, 0.0024414062500000, +0.0007629394531250, 0.0023803710937500, 0.0009155273437500, 0.0024414062500000, +0.0010986328125000, 0.0024108886718750, 0.0008239746093750, 0.0022277832031250, +0.0013732910156250, 0.0021057128906250, 0.0012207031250000, 0.0019226074218750, +0.0011901855468750, 0.0016479492187500, 0.0015563964843750, 0.0015869140625000, +0.0013427734375000, 0.0015869140625000, 0.0011291503906250, 0.0012207031250000, +0.0013122558593750, 0.0013427734375000, 0.0009155273437500, 0.0015258789062500, +0.0004577636718750, 0.0010986328125000, 0.0007629394531250, 0.0015869140625000, +0.0000915527343750, 0.0014343261718750, 0.0001220703125000, 0.0013427734375000, +0.0000915527343750, 0.0016174316406250, -0.0002136230468750, 0.0014038085937500, +-0.0000915527343750, 0.0013122558593750, -0.0004577636718750, 0.0013427734375000, +-0.0005187988281250, 0.0012512207031250, -0.0004882812500000, 0.0010681152343750, +-0.0006103515625000, 0.0011901855468750, -0.0007019042968750, 0.0009460449218750, +-0.0004272460937500, 0.0009765625000000, -0.0005798339843750, 0.0010375976562500, +-0.0004577636718750, 0.0010681152343750, -0.0000915527343750, 0.0010681152343750, +-0.0002136230468750, 0.0013427734375000, 0.0001525878906250, 0.0013427734375000, +0.0002136230468750, 0.0014953613281250, 0.0003662109375000, 0.0017700195312500, +0.0007019042968750, 0.0017089843750000, 0.0007019042968750, 0.0019836425781250, +0.0006408691406250, 0.0021362304687500, 0.0008239746093750, 0.0020141601562500, +0.0007629394531250, 0.0018310546875000, 0.0004577636718750, 0.0009155273437500, +-0.0003662109375000, 0.0000000000000000, -0.0001831054687500, 0.0004272460937500, +-0.0001525878906250, 0.0000915527343750, -0.0002441406250000, -0.0004272460937500, +-0.0001831054687500, -0.0001220703125000, -0.0000610351562500, -0.0008239746093750, +-0.0002136230468750, -0.0007934570312500, -0.0002441406250000, -0.0007934570312500, +-0.0002136230468750, -0.0011901855468750, -0.0002746582031250, -0.0010681152343750, +-0.0002746582031250, -0.0011596679687500, -0.0001525878906250, -0.0012207031250000, +-0.0002441406250000, -0.0011596679687500, -0.0003967285156250, -0.0010986328125000, +-0.0003356933593750, -0.0011596679687500, -0.0003356933593750, -0.0009765625000000, +-0.0008850097656250, -0.0011291503906250, -0.0007934570312500, -0.0009765625000000, +-0.0006408691406250, -0.0007934570312500, -0.0009460449218750, -0.0010681152343750, +-0.0009765625000000, -0.0003662109375000, -0.0002746582031250, -0.0007019042968750, +-0.0005187988281250, -0.0003967285156250, -0.0002441406250000, 0.0003662109375000, +0.0003967285156250, -0.0001831054687500, -0.0000610351562500, 0.0009460449218750, +0.0006713867187500, 0.0009460449218750, 0.0007019042968750, 0.0010070800781250, +0.0006713867187500, 0.0017395019531250, 0.0010681152343750, 0.0015869140625000, +0.0008239746093750, 0.0019226074218750, 0.0008239746093750, 0.0021667480468750, +0.0008544921875000, 0.0020141601562500, 0.0007629394531250, 0.0020446777343750, +0.0006713867187500, 0.0021972656250000, 0.0006713867187500, 0.0014648437500000, +0.0007019042968750, 0.0017395019531250, 0.0006713867187500, 0.0012817382812500, +0.0008239746093750, 0.0004882812500000, 0.0010375976562500, 0.0009460449218750, +0.0008544921875000, -0.0004577636718750, 0.0013427734375000, -0.0003356933593750, +0.0014953613281250, -0.0004882812500000, 0.0014648437500000, -0.0013427734375000, +0.0016479492187500, -0.0009460449218750, 0.0018005371093750, -0.0010375976562500, +0.0014343261718750, -0.0013732910156250, 0.0017395019531250, -0.0007324218750000, +0.0015563964843750, -0.0002746582031250, 0.0010681152343750, -0.0007629394531250, +0.0014648437500000, 0.0006408691406250, 0.0013122558593750, 0.0006103515625000, +0.0011291503906250, 0.0006103515625000, 0.0015563964843750, 0.0014648437500000, +0.0016784667968750, 0.0011596679687500, 0.0013427734375000, 0.0010070800781250, +0.0024108886718750, 0.0012512207031250, 0.0020141601562500, 0.0008239746093750, +0.0021667480468750, 0.0003356933593750, 0.0028991699218750, 0.0005798339843750, +0.0021972656250000, -0.0002136230468750, 0.0025634765625000, -0.0002746582031250, +0.0026245117187500, -0.0002746582031250, 0.0019836425781250, -0.0006713867187500, +0.0018310546875000, -0.0006713867187500, 0.0019836425781250, -0.0003662109375000, +0.0008850097656250, -0.0006408691406250, 0.0011291503906250, -0.0003356933593750, +0.0009155273437500, 0.0001525878906250, 0.0000915527343750, -0.0002136230468750, +0.0006103515625000, 0.0006713867187500, 0.0001831054687500, 0.0006103515625000, +0.0001831054687500, 0.0006103515625000, 0.0003967285156250, 0.0010986328125000, +0.0003356933593750, 0.0009460449218750, 0.0005187988281250, 0.0010681152343750, +0.0005187988281250, 0.0011291503906250, 0.0007629394531250, 0.0011291503906250, +0.0007019042968750, 0.0011596679687500, 0.0006408691406250, 0.0011596679687500, +0.0008544921875000, 0.0012817382812500, 0.0003662109375000, 0.0012207031250000, +0.0005493164062500, 0.0013732910156250, 0.0005798339843750, 0.0015563964843750, +0.0002746582031250, 0.0014038085937500, 0.0005187988281250, 0.0019226074218750, +0.0003051757812500, 0.0018310546875000, 0.0004577636718750, 0.0018310546875000, +0.0004272460937500, 0.0022583007812500, 0.0003051757812500, 0.0020751953125000, +0.0005798339843750, 0.0019226074218750, 0.0002441406250000, 0.0021057128906250, +0.0004882812500000, 0.0017089843750000, 0.0004272460937500, 0.0013427734375000, +0.0001220703125000, 0.0015869140625000, 0.0005187988281250, 0.0006103515625000, +0.0003051757812500, 0.0006713867187500, 0.0003967285156250, 0.0004577636718750, +0.0005493164062500, -0.0002441406250000, 0.0005187988281250, 0.0000305175781250, +0.0006713867187500, -0.0003662109375000, 0.0007629394531250, -0.0005493164062500, +0.0008544921875000, -0.0004272460937500, 0.0009765625000000, -0.0004882812500000, +0.0011291503906250, -0.0006713867187500, 0.0012207031250000, -0.0002441406250000, +0.0012207031250000, -0.0004882812500000, 0.0012817382812500, -0.0002441406250000, +0.0012512207031250, 0.0002441406250000, 0.0012207031250000, -0.0002136230468750, +0.0013122558593750, 0.0006408691406250, 0.0011596679687500, 0.0004577636718750, +0.0011901855468750, 0.0006713867187500, 0.0011901855468750, 0.0012512207031250, +0.0010681152343750, 0.0008850097656250, 0.0011291503906250, 0.0015258789062500, +0.0011596679687500, 0.0014648437500000, 0.0010681152343750, 0.0015869140625000, +0.0011291503906250, 0.0020141601562500, 0.0011901855468750, 0.0017700195312500, +0.0010070800781250, 0.0021667480468750, 0.0012817382812500, 0.0021667480468750, +0.0011901855468750, 0.0022583007812500, 0.0012512207031250, 0.0025024414062500, +0.0014343261718750, 0.0023803710937500, 0.0013122558593750, 0.0026550292968750, +0.0016784667968750, 0.0026245117187500, 0.0014953613281250, 0.0025329589843750, +0.0016479492187500, 0.0026550292968750, 0.0020141601562500, 0.0026855468750000, +0.0018005371093750, 0.0022888183593750, 0.0022888183593750, 0.0024719238281250, +0.0022583007812500, 0.0021057128906250, 0.0023193359375000, 0.0015869140625000, +0.0026855468750000, 0.0019531250000000, 0.0025329589843750, 0.0009155273437500, +0.0024414062500000, 0.0010681152343750, 0.0026245117187500, 0.0008544921875000, +0.0024108886718750}, +{0.0011901855468750, 0.0009460449218750, 0.0013427734375000, 0.0009460449218750, +0.0015258789062500, 0.0006408691406250, 0.0012207031250000, 0.0016174316406250, +0.0018005371093750, 0.0013427734375000, 0.0016784667968750, 0.0016784667968750, +0.0017700195312500, 0.0025024414062500, 0.0022888183593750, 0.0019226074218750, +0.0020141601562500, 0.0028076171875000, 0.0021057128906250, 0.0028381347656250, +0.0024414062500000, 0.0027465820312500, 0.0022583007812500, 0.0031433105468750, +0.0019836425781250, 0.0029907226562500, 0.0022888183593750, 0.0031433105468750, +0.0019226074218750, 0.0030822753906250, 0.0018615722656250, 0.0031127929687500, +0.0020751953125000, 0.0031433105468750, 0.0019226074218750, 0.0030212402343750, +0.0019226074218750, 0.0031738281250000, 0.0022888183593750, 0.0031127929687500, +0.0020751953125000, 0.0029602050781250, 0.0023498535156250, 0.0029296875000000, +0.0027770996093750, 0.0028991699218750, 0.0024108886718750, 0.0025024414062500, +0.0030517578125000, 0.0025939941406250, 0.0030212402343750, 0.0023498535156250, +0.0030212402343750, 0.0019836425781250, 0.0033569335937500, 0.0022277832031250, +0.0032043457031250, 0.0013732910156250, 0.0033569335937500, 0.0016479492187500, +0.0033874511718750, 0.0012512207031250, 0.0032958984375000, 0.0004577636718750, +0.0033569335937500, 0.0009765625000000, 0.0033569335937500, 0.0001220703125000, +0.0032958984375000, 0.0000305175781250, 0.0033569335937500, 0.0002746582031250, +0.0033569335937500, 0.0000305175781250, 0.0032653808593750, 0.0000305175781250, +0.0033264160156250, 0.0007324218750000, 0.0032043457031250, 0.0004882812500000, +0.0031738281250000, 0.0009460449218750, 0.0032043457031250, 0.0017089843750000, +0.0031433105468750, 0.0012817382812500, 0.0029907226562500, 0.0023193359375000, +0.0033264160156250, 0.0022583007812500, 0.0030212402343750, 0.0023193359375000, +0.0031738281250000, 0.0029296875000000, 0.0036010742187500, 0.0026245117187500, +0.0031433105468750, 0.0025939941406250, 0.0037231445312500, 0.0027465820312500, +0.0035400390625000, 0.0024414062500000, 0.0034484863281250, 0.0021667480468750, +0.0037536621093750, 0.0023498535156250, 0.0034179687500000, 0.0014953613281250, +0.0034790039062500, 0.0016479492187500, 0.0033569335937500, 0.0014648437500000, +0.0031433105468750, 0.0008239746093750, 0.0030212402343750, 0.0011901855468750, +0.0028381347656250, 0.0007934570312500, 0.0025329589843750, 0.0007629394531250, +0.0023803710937500, 0.0007934570312500, 0.0022583007812500, 0.0006713867187500, +0.0019531250000000, 0.0007324218750000, 0.0018005371093750, 0.0007019042968750, +0.0017700195312500, 0.0006713867187500, 0.0013732910156250, 0.0007019042968750, +0.0014648437500000, 0.0007019042968750, 0.0016174316406250, 0.0007324218750000, +0.0012207031250000, 0.0007629394531250, 0.0019836425781250, 0.0007324218750000, +0.0015258789062500, 0.0008850097656250, 0.0017089843750000, 0.0009460449218750, +0.0023498535156250, 0.0009460449218750, 0.0016479492187500, 0.0013122558593750, +0.0026245117187500, 0.0013427734375000, 0.0023498535156250, 0.0014343261718750, +0.0024719238281250, 0.0018005371093750, 0.0031127929687500, 0.0017700195312500, +0.0025939941406250, 0.0017089843750000, 0.0032958984375000, 0.0018615722656250, +0.0032043457031250, 0.0016174316406250, 0.0031738281250000, 0.0012512207031250, +0.0035400390625000, 0.0014953613281250, 0.0032958984375000, 0.0004882812500000, +0.0033569335937500, 0.0005187988281250, 0.0033874511718750, 0.0002136230468750, +0.0032348632812500, -0.0006103515625000, 0.0030822753906250, -0.0003356933593750, +0.0031127929687500, -0.0009155273437500, 0.0027770996093750, -0.0010986328125000, +0.0028076171875000, -0.0009155273437500, 0.0026245117187500, -0.0010681152343750, +0.0024108886718750, -0.0011596679687500, 0.0025634765625000, -0.0005187988281250, +0.0022888183593750, -0.0007324218750000, 0.0024108886718750, -0.0005493164062500, +0.0024108886718750, 0.0000305175781250, 0.0022888183593750, -0.0002441406250000, +0.0025024414062500, -0.0000610351562500, 0.0022583007812500, 0.0001220703125000, +0.0024108886718750, 0.0000915527343750, 0.0023498535156250, 0.0000915527343750, +0.0022583007812500, 0.0001831054687500, 0.0024414062500000, 0.0000610351562500, +0.0019531250000000, 0.0000915527343750, 0.0022277832031250, 0.0000305175781250, +0.0020751953125000, -0.0000915527343750, 0.0015869140625000, -0.0000610351562500, +0.0020446777343750, -0.0002441406250000, 0.0013427734375000, -0.0003051757812500, +0.0014038085937500, -0.0004272460937500, 0.0014343261718750, -0.0006408691406250, +0.0010681152343750, -0.0005493164062500, 0.0012512207031250, -0.0006713867187500, +0.0011291503906250, -0.0007934570312500, 0.0010986328125000, -0.0005187988281250, +0.0011596679687500, -0.0002746582031250, 0.0011291503906250, -0.0003967285156250, +0.0010986328125000, 0.0002136230468750, 0.0012512207031250, 0.0002746582031250, +0.0011596679687500, 0.0002441406250000, 0.0012207031250000, 0.0006713867187500, +0.0013427734375000, 0.0008850097656250, 0.0013732910156250, 0.0010070800781250, +0.0016784667968750, 0.0009765625000000, 0.0015563964843750, 0.0011291503906250, +0.0015869140625000, 0.0013122558593750, 0.0018920898437500, 0.0012207031250000, +0.0018005371093750, 0.0015258789062500, 0.0016784667968750, 0.0016784667968750, +0.0018310546875000, 0.0015563964843750, 0.0015869140625000, 0.0014953613281250, +0.0013427734375000, 0.0016479492187500, 0.0015563964843750, 0.0012512207031250, +0.0008850097656250, 0.0013122558593750, 0.0010375976562500, 0.0011291503906250, +0.0009155273437500, 0.0007934570312500, 0.0004577636718750, 0.0010681152343750, +0.0007934570312500, 0.0009155273437500, 0.0003662109375000, 0.0010375976562500, +0.0003051757812500, 0.0012512207031250, 0.0003967285156250, 0.0012512207031250, +0.0002746582031250, 0.0014648437500000, 0.0003967285156250, 0.0019531250000000, +0.0003967285156250, 0.0020446777343750, 0.0004577636718750, 0.0022277832031250, +0.0003967285156250, 0.0026245117187500, 0.0003662109375000, 0.0025024414062500, +0.0004882812500000, 0.0025939941406250, 0.0000915527343750, 0.0027770996093750, +0.0002136230468750, 0.0025634765625000, 0.0001831054687500, 0.0023803710937500, +-0.0000915527343750, 0.0025024414062500, 0.0000000000000000, 0.0018310546875000, +-0.0003356933593750, 0.0019226074218750, -0.0002746582031250, 0.0016174316406250, +-0.0001831054687500, 0.0010070800781250, -0.0003356933593750, 0.0013427734375000, +-0.0002136230468750, 0.0010070800781250, -0.0000610351562500, 0.0006713867187500, +-0.0000305175781250, 0.0009460449218750, 0.0000915527343750, 0.0011596679687500, +0.0003356933593750, 0.0007934570312500, 0.0003051757812500, 0.0015258789062500, +0.0005798339843750, 0.0013427734375000, 0.0006103515625000, 0.0014343261718750, +0.0007934570312500, 0.0019226074218750, 0.0009765625000000, 0.0016479492187500, +0.0008850097656250, 0.0019226074218750, 0.0010681152343750, 0.0020141601562500, +0.0011291503906250, 0.0018310546875000, 0.0010375976562500, 0.0018615722656250, +0.0010681152343750, 0.0021362304687500, 0.0011291503906250, 0.0015563964843750, +0.0009155273437500, 0.0018615722656250, 0.0009765625000000, 0.0019226074218750, +0.0010375976562500, 0.0015563964843750, 0.0008850097656250, 0.0020446777343750, +0.0009765625000000, 0.0018310546875000, 0.0010986328125000, 0.0020751953125000, +0.0010375976562500, 0.0022888183593750, 0.0011901855468750, 0.0021972656250000, +0.0012817382812500, 0.0024414062500000, 0.0011901855468750, 0.0024414062500000, +0.0017089843750000, 0.0025634765625000, 0.0016479492187500, 0.0026245117187500, +0.0018005371093750, 0.0026245117187500, 0.0022888183593750, 0.0026855468750000, +0.0021362304687500, 0.0027160644531250, 0.0025634765625000, 0.0026855468750000, +0.0026855468750000, 0.0028381347656250, 0.0026855468750000, 0.0028381347656250, +0.0028381347656250, 0.0026855468750000, 0.0028991699218750, 0.0032043457031250, +0.0026855468750000, 0.0029602050781250, 0.0028381347656250, 0.0030822753906250, +0.0026245117187500, 0.0034790039062500, 0.0023498535156250, 0.0029907226562500, +0.0025634765625000, 0.0034790039062500, 0.0017395019531250, 0.0033569335937500, +0.0018310546875000, 0.0032043457031250, 0.0015563964843750, 0.0033569335937500, +0.0008239746093750, 0.0030212402343750, 0.0010986328125000, 0.0031127929687500, +0.0004272460937500, 0.0028991699218750, 0.0003356933593750, 0.0028076171875000, +0.0003662109375000, 0.0028381347656250, 0.0000915527343750, 0.0024108886718750, +0.0001831054687500, 0.0028076171875000, 0.0003051757812500, 0.0025329589843750, +0.0002441406250000, 0.0025939941406250, 0.0004577636718750, 0.0028991699218750, +0.0006713867187500, 0.0025329589843750, 0.0005798339843750, 0.0028076171875000, +0.0012512207031250, 0.0027465820312500, 0.0011291503906250, 0.0025634765625000, +0.0014648437500000, 0.0025634765625000, 0.0019836425781250, 0.0025024414062500, +0.0016784667968750, 0.0023803710937500, 0.0025939941406250, 0.0022583007812500, +0.0025329589843750, 0.0022583007812500, 0.0026550292968750, 0.0021972656250000, +0.0032348632812500, 0.0020141601562500, 0.0028991699218750, 0.0020141601562500, +0.0032958984375000, 0.0019226074218750, 0.0033874511718750, 0.0018920898437500, +0.0032043457031250, 0.0019226074218750, 0.0032958984375000, 0.0017395019531250, +0.0032958984375000, 0.0019836425781250, 0.0028076171875000, 0.0018615722656250, +0.0028991699218750, 0.0018920898437500, 0.0025939941406250, 0.0019836425781250, +0.0020446777343750, 0.0018005371093750, 0.0023193359375000, 0.0020446777343750, +0.0015869140625000, 0.0018310546875000, 0.0014648437500000, 0.0018615722656250, +0.0014343261718750, 0.0021057128906250, 0.0010681152343750, 0.0017395019531250, +0.0010681152343750, 0.0020751953125000, 0.0012207031250000, 0.0019226074218750, +0.0009155273437500, 0.0019226074218750, 0.0010681152343750, 0.0021057128906250, +0.0013732910156250, 0.0018310546875000, 0.0010681152343750, 0.0020751953125000, +0.0014648437500000, 0.0018920898437500, 0.0014648437500000, 0.0019531250000000, +0.0014038085937500, 0.0021667480468750, 0.0016479492187500, 0.0018310546875000, +0.0015563964843750, 0.0022583007812500, 0.0016174316406250, 0.0021057128906250, +0.0016784667968750, 0.0021667480468750, 0.0015563964843750, 0.0025634765625000, +0.0014953613281250, 0.0022277832031250, 0.0015563964843750, 0.0024719238281250, +0.0012512207031250, 0.0025024414062500, 0.0013122558593750, 0.0023193359375000, +0.0011596679687500, 0.0023193359375000, 0.0009155273437500, 0.0024108886718750, +0.0009765625000000, 0.0018920898437500, 0.0006408691406250, 0.0020141601562500, +0.0006408691406250, 0.0018310546875000, 0.0005798339843750, 0.0014343261718750, +0.0003662109375000, 0.0016784667968750, 0.0003967285156250, 0.0012512207031250, +0.0003356933593750, 0.0012817382812500, 0.0003051757812500, 0.0011901855468750, +0.0003051757812500, 0.0009155273437500, 0.0002136230468750, 0.0011901855468750, +0.0001831054687500, 0.0005798339843750, 0.0000915527343750, 0.0008544921875000, +0.0001831054687500, 0.0007324218750000, 0.0000000000000000, 0.0002441406250000, +-0.0003051757812500, 0.0007629394531250, -0.0001525878906250, 0.0000000000000000, +-0.0002746582031250, 0.0002136230468750, -0.0003967285156250, 0.0003356933593750, +-0.0002441406250000, -0.0000610351562500, -0.0001525878906250, 0.0003356933593750, +-0.0003356933593750}, +{0.0002441406250000, 0.0028381347656250, 0.0003356933593750, 0.0029296875000000, +0.0004577636718750, 0.0027770996093750, 0.0001831054687500, 0.0029602050781250, +0.0006408691406250, 0.0032043457031250, 0.0010375976562500, 0.0030212402343750, +0.0007019042968750, 0.0033569335937500, 0.0018920898437500, 0.0033569335937500, +0.0017395019531250, 0.0033264160156250, 0.0021362304687500, 0.0035095214843750, +0.0031127929687500, 0.0035705566406250, 0.0026245117187500, 0.0034484863281250, +0.0035400390625000, 0.0036315917968750, 0.0036315917968750, 0.0036010742187500, +0.0035095214843750, 0.0034484863281250, 0.0038146972656250, 0.0036926269531250, +0.0037231445312500, 0.0033569335937500, 0.0036010742187500, 0.0035095214843750, +0.0037536621093750, 0.0034790039062500, 0.0035705566406250, 0.0032348632812500, +0.0033569335937500, 0.0034484863281250, 0.0034790039062500, 0.0031127929687500, +0.0028991699218750, 0.0032653808593750, 0.0030212402343750, 0.0032043457031250, +0.0027770996093750, 0.0029602050781250, 0.0021972656250000, 0.0031127929687500, +0.0023803710937500, 0.0028991699218750, 0.0016784667968750, 0.0028991699218750, +0.0016174316406250, 0.0028076171875000, 0.0014953613281250, 0.0025939941406250, +0.0011291503906250, 0.0027160644531250, 0.0011901855468750, 0.0024719238281250, +0.0009460449218750, 0.0024719238281250, 0.0008239746093750, 0.0024719238281250, +0.0007934570312500, 0.0022888183593750, 0.0007019042968750, 0.0024108886718750, +0.0006408691406250, 0.0023193359375000, 0.0006103515625000, 0.0023193359375000, +0.0005798339843750, 0.0024108886718750, 0.0005798339843750, 0.0023803710937500, +0.0005493164062500, 0.0023193359375000, 0.0004577636718750, 0.0025329589843750, +0.0007324218750000, 0.0024414062500000, 0.0004882812500000, 0.0025329589843750, +0.0008239746093750, 0.0028076171875000, 0.0012512207031250, 0.0025634765625000, +0.0008850097656250, 0.0028686523437500, 0.0019836425781250, 0.0028381347656250, +0.0018615722656250, 0.0027160644531250, 0.0022277832031250, 0.0027770996093750, +0.0030212402343750, 0.0026855468750000, 0.0025634765625000, 0.0025939941406250, +0.0033569335937500, 0.0025634765625000, 0.0035095214843750, 0.0024414062500000, +0.0034179687500000, 0.0022888183593750, 0.0037231445312500, 0.0022277832031250, +0.0037841796875000, 0.0020446777343750, 0.0035705566406250, 0.0020141601562500, +0.0036926269531250, 0.0018615722656250, 0.0035095214843750, 0.0017395019531250, +0.0031738281250000, 0.0016479492187500, 0.0033264160156250, 0.0016479492187500, +0.0028991699218750, 0.0015869140625000, 0.0028686523437500, 0.0014953613281250, +0.0026550292968750, 0.0014648437500000, 0.0023498535156250, 0.0014648437500000, +0.0024108886718750, 0.0012512207031250, 0.0019531250000000, 0.0013732910156250, +0.0019226074218750, 0.0011901855468750, 0.0017395019531250, 0.0008544921875000, +0.0014343261718750, 0.0010986328125000, 0.0015258789062500, 0.0007629394531250, +0.0011291503906250, 0.0007934570312500, 0.0011596679687500, 0.0008544921875000, +0.0009155273437500, 0.0007019042968750, 0.0005798339843750, 0.0008850097656250, +0.0007629394531250, 0.0008544921875000, -0.0000610351562500, 0.0009155273437500, +0.0000000000000000, 0.0009155273437500, -0.0002746582031250, 0.0009460449218750, +-0.0009460449218750, 0.0010375976562500, -0.0007324218750000, 0.0008544921875000, +-0.0012817382812500, 0.0010070800781250, -0.0013427734375000, 0.0008850097656250, +-0.0012817382812500, 0.0006713867187500, -0.0014953613281250, 0.0009460449218750, +-0.0014648437500000, 0.0006713867187500, -0.0011901855468750, 0.0007324218750000, +-0.0013122558593750, 0.0006713867187500, -0.0010070800781250, 0.0004882812500000, +-0.0005798339843750, 0.0006713867187500, -0.0007324218750000, 0.0003967285156250, +-0.0001220703125000, 0.0004577636718750, 0.0000000000000000, 0.0004577636718750, +0.0000000000000000, 0.0003051757812500, 0.0003051757812500, 0.0003662109375000, +0.0003662109375000, 0.0001220703125000, 0.0002441406250000, 0.0002136230468750, +0.0003051757812500, 0.0000610351562500, 0.0003356933593750, -0.0001525878906250, +0.0003051757812500, 0.0000000000000000, 0.0003356933593750, -0.0004882812500000, +0.0001831054687500, -0.0005187988281250, 0.0001831054687500, -0.0004882812500000, +-0.0000305175781250, -0.0008850097656250, -0.0004577636718750, -0.0006103515625000, +0.0009765625000000, 0.0009765625000000, 0.0013122558593750, 0.0003662109375000, +0.0014648437500000, 0.0008544921875000, 0.0010070800781250, 0.0017089843750000, +0.0007629394531250, 0.0012817382812500, 0.0010070800781250, 0.0018920898437500, +-0.0001831054687500, 0.0020141601562500, 0.0001525878906250, 0.0018310546875000, +-0.0003356933593750, 0.0020751953125000, -0.0014648437500000, 0.0020446777343750, +-0.0007934570312500, 0.0015563964843750, -0.0014953613281250, 0.0018310546875000, +-0.0017089843750000, 0.0015563964843750, -0.0013732910156250, 0.0010986328125000, +-0.0013427734375000, 0.0015258789062500, -0.0014953613281250, 0.0007934570312500, +-0.0010681152343750, 0.0008850097656250, -0.0012207031250000, 0.0007934570312500, +-0.0010070800781250, 0.0003356933593750, -0.0006408691406250, 0.0005187988281250, +-0.0009765625000000, 0.0000610351562500, -0.0003051757812500, 0.0001220703125000, +-0.0004577636718750, -0.0001220703125000, -0.0001525878906250, -0.0005493164062500, +0.0003662109375000, -0.0001831054687500, -0.0000915527343750, -0.0006408691406250, +0.0009765625000000, -0.0007324218750000, 0.0009460449218750, -0.0003662109375000, +0.0008850097656250, -0.0003662109375000, 0.0014953613281250, -0.0005187988281250, +0.0012817382812500, 0.0005798339843750, 0.0011596679687500, 0.0003662109375000, +0.0012817382812500, 0.0007629394531250, 0.0010986328125000, 0.0017089843750000, +0.0009460449218750, 0.0012207031250000, 0.0009765625000000, 0.0020751953125000, +0.0008850097656250, 0.0021972656250000, 0.0006408691406250, 0.0018920898437500, +0.0007324218750000, 0.0020751953125000, 0.0008239746093750, 0.0021667480468750, +0.0007324218750000, 0.0015258789062500, 0.0013122558593750, 0.0016784667968750, +0.0012207031250000, 0.0016174316406250, 0.0015563964843750, 0.0011291503906250, +0.0021362304687500, 0.0012817382812500, 0.0020751953125000, 0.0015869140625000, +0.0026550292968750, 0.0012817382812500, 0.0028686523437500, 0.0017089843750000, +0.0027770996093750, 0.0023193359375000, 0.0028686523437500, 0.0018920898437500, +0.0030517578125000, 0.0027465820312500, 0.0031433105468750, 0.0028686523437500, +0.0031738281250000, 0.0027160644531250, 0.0032958984375000, 0.0030822753906250, +0.0033264160156250, 0.0030822753906250, 0.0033569335937500, 0.0027770996093750, +0.0036621093750000, 0.0028686523437500, 0.0036315917968750, 0.0028991699218750, +0.0037841796875000, 0.0027160644531250, 0.0039978027343750, 0.0028076171875000, +0.0037536621093750, 0.0029296875000000, 0.0039978027343750, 0.0028991699218750, +0.0039062500000000, 0.0030517578125000, 0.0037841796875000, 0.0032348632812500, +0.0037536621093750, 0.0032043457031250, 0.0035095214843750, 0.0032958984375000, +0.0033264160156250, 0.0035095214843750, 0.0033264160156250, 0.0032653808593750, +0.0031738281250000, 0.0031738281250000, 0.0030517578125000, 0.0034790039062500, +0.0031127929687500, 0.0024108886718750, 0.0028076171875000, 0.0028076171875000, +0.0030822753906250, 0.0023193359375000, 0.0030822753906250, 0.0013427734375000, +0.0028991699218750, 0.0019531250000000, 0.0033264160156250, 0.0010375976562500, +0.0028381347656250, 0.0008544921875000, 0.0032958984375000, 0.0010681152343750, +0.0031738281250000, 0.0007019042968750, 0.0027160644531250, 0.0007019042968750, +0.0032653808593750, 0.0010986328125000, 0.0025634765625000, 0.0008544921875000, +0.0028686523437500, 0.0011901855468750, 0.0028686523437500, 0.0016174316406250, +0.0023498535156250, 0.0011901855468750, 0.0028381347656250, 0.0022888183593750, +0.0024414062500000, 0.0021057128906250, 0.0025329589843750, 0.0022583007812500, +0.0026245117187500, 0.0030822753906250, 0.0024108886718750, 0.0026855468750000, +0.0025329589843750, 0.0029907226562500, 0.0024719238281250, 0.0032653808593750, +0.0025024414062500, 0.0029907226562500, 0.0024414062500000, 0.0028076171875000, +0.0023498535156250, 0.0030212402343750, 0.0025024414062500, 0.0024108886718750, +0.0022583007812500, 0.0025024414062500, 0.0024414062500000, 0.0023803710937500, +0.0022888183593750, 0.0019836425781250, 0.0020446777343750, 0.0021362304687500, +0.0023803710937500, 0.0016784667968750, 0.0018310546875000, 0.0016784667968750, +0.0019226074218750, 0.0016174316406250, 0.0018615722656250, 0.0013122558593750, +0.0014953613281250, 0.0013122558593750, 0.0016784667968750, 0.0013122558593750, +0.0013427734375000, 0.0011291503906250, 0.0013427734375000, 0.0013427734375000, +0.0013122558593750, 0.0014953613281250, 0.0011596679687500, 0.0012817382812500, +0.0012512207031250, 0.0020446777343750, 0.0012207031250000, 0.0019226074218750, +0.0011901855468750, 0.0020446777343750, 0.0013427734375000, 0.0026245117187500, +0.0014038085937500, 0.0023498535156250, 0.0013122558593750, 0.0024414062500000, +0.0017395019531250, 0.0026245117187500, 0.0016174316406250, 0.0022277832031250, +0.0018005371093750, 0.0019836425781250, 0.0021057128906250, 0.0021362304687500, +0.0018920898437500, 0.0012512207031250, 0.0023193359375000, 0.0013427734375000, +0.0023193359375000, 0.0010986328125000, 0.0023498535156250, 0.0005187988281250, +0.0026245117187500, 0.0008239746093750, 0.0025329589843750, 0.0004882812500000, +0.0026550292968750, 0.0004272460937500, 0.0027160644531250, 0.0005798339843750, +0.0025634765625000, 0.0005798339843750, 0.0024719238281250, 0.0006408691406250, +0.0026550292968750, 0.0008850097656250, 0.0023498535156250, 0.0007629394531250, +0.0024108886718750, 0.0009155273437500, 0.0023193359375000, 0.0010986328125000, +0.0020446777343750, 0.0009155273437500, 0.0021972656250000, 0.0013732910156250, +0.0018615722656250, 0.0011291503906250, 0.0018615722656250, 0.0013427734375000, +0.0019226074218750, 0.0017700195312500, 0.0017089843750000, 0.0014038085937500, +0.0017700195312500, 0.0022583007812500, 0.0017395019531250, 0.0020141601562500, +0.0017089843750000, 0.0022583007812500, 0.0017395019531250, 0.0029602050781250, +0.0018005371093750, 0.0024414062500000, 0.0019531250000000, 0.0031127929687500, +0.0018005371093750, 0.0031433105468750, 0.0020446777343750, 0.0029296875000000, +0.0020751953125000, 0.0031433105468750, 0.0019531250000000, 0.0029907226562500, +0.0021667480468750, 0.0024719238281250, 0.0018920898437500, 0.0026245117187500, +0.0021057128906250, 0.0022583007812500, 0.0020141601562500, 0.0016174316406250, +0.0017700195312500, 0.0018615722656250, 0.0020141601562500, 0.0010375976562500, +0.0017700195312500, 0.0009155273437500, 0.0017089843750000, 0.0007934570312500, +0.0018310546875000, 0.0003662109375000, 0.0017395019531250, 0.0004272460937500, +0.0017089843750000, 0.0003051757812500, 0.0018920898437500, 0.0001831054687500, +0.0018005371093750, 0.0001525878906250, 0.0018310546875000, 0.0000305175781250, +0.0019531250000000, 0.0000305175781250, 0.0017700195312500, -0.0002746582031250, +0.0019531250000000, -0.0001831054687500, 0.0018615722656250, -0.0003356933593750, +0.0018005371093750, -0.0006408691406250, 0.0018310546875000, -0.0004882812500000, +0.0017700195312500, -0.0007324218750000, 0.0016479492187500, -0.0007324218750000, +0.0017395019531250}, +{0.0028076171875000, 0.0014953613281250, 0.0027465820312500, 0.0018005371093750, +0.0027160644531250, 0.0021972656250000, 0.0027465820312500, 0.0018615722656250, +0.0026245117187500, 0.0028076171875000, 0.0028076171875000, 0.0027465820312500, +0.0026855468750000, 0.0028686523437500, 0.0026855468750000, 0.0035705566406250, +0.0028381347656250, 0.0033264160156250, 0.0027160644531250, 0.0035095214843750, +0.0027770996093750, 0.0037841796875000, 0.0027160644531250, 0.0034179687500000, +0.0026245117187500, 0.0031738281250000, 0.0025329589843750, 0.0035400390625000, +0.0024719238281250, 0.0024108886718750, 0.0024719238281250, 0.0025939941406250, +0.0023498535156250, 0.0022888183593750, 0.0023498535156250, 0.0013732910156250, +0.0023193359375000, 0.0018005371093750, 0.0021972656250000, 0.0009460449218750, +0.0023193359375000, 0.0008544921875000, 0.0022277832031250, 0.0008850097656250, +0.0022583007812500, 0.0004272460937500, 0.0023803710937500, 0.0005493164062500, +0.0021362304687500, 0.0007324218750000, 0.0025024414062500, 0.0005493164062500, +0.0023803710937500, 0.0007629394531250, 0.0024108886718750, 0.0010375976562500, +0.0025939941406250, 0.0008239746093750, 0.0024414062500000, 0.0010681152343750, +0.0025024414062500, 0.0011291503906250, 0.0024414062500000, 0.0009460449218750, +0.0024414062500000, 0.0008850097656250, 0.0025329589843750, 0.0008850097656250, +0.0023498535156250, 0.0005493164062500, 0.0023803710937500, 0.0004882812500000, +0.0022277832031250, 0.0004272460937500, 0.0021667480468750, 0.0002136230468750, +0.0021057128906250, 0.0001220703125000, 0.0019531250000000, 0.0004272460937500, +0.0021057128906250, 0.0001220703125000, 0.0018310546875000, 0.0004882812500000, +0.0019836425781250, 0.0009765625000000, 0.0021972656250000, 0.0005187988281250, +0.0018005371093750, 0.0016174316406250, 0.0025329589843750, 0.0014648437500000, +0.0022583007812500, 0.0017700195312500, 0.0023803710937500, 0.0025939941406250, +0.0028991699218750, 0.0021057128906250, 0.0023498535156250, 0.0030212402343750, +0.0029602050781250, 0.0029907226562500, 0.0027465820312500, 0.0031127929687500, +0.0026245117187500, 0.0036926269531250, 0.0029296875000000, 0.0034484863281250, +0.0025329589843750, 0.0039978027343750, 0.0024719238281250, 0.0041198730468750, +0.0024414062500000, 0.0041809082031250, 0.0021362304687500, 0.0044250488281250, +0.0019531250000000, 0.0043945312500000, 0.0019836425781250, 0.0044555664062500, +0.0014038085937500, 0.0045471191406250, 0.0014648437500000, 0.0043640136718750, +0.0011596679687500, 0.0042419433593750, 0.0006408691406250, 0.0044250488281250, +0.0010375976562500, 0.0039367675781250, 0.0004272460937500, 0.0040893554687500, +0.0005798339843750, 0.0038757324218750, 0.0006713867187500, 0.0033874511718750, +0.0003356933593750, 0.0036621093750000, 0.0006713867187500, 0.0030212402343750, +0.0006103515625000, 0.0030212402343750, 0.0006103515625000, 0.0029602050781250, +0.0008850097656250, 0.0025939941406250, 0.0010375976562500, 0.0026855468750000, +0.0009460449218750, 0.0023498535156250, 0.0012817382812500, 0.0023193359375000, +0.0013732910156250, 0.0021972656250000, 0.0013427734375000, 0.0020141601562500, +0.0014648437500000, 0.0019836425781250, 0.0014648437500000, 0.0014038085937500, +0.0012207031250000, 0.0013732910156250, 0.0012817382812500, 0.0009155273437500, +0.0010986328125000, 0.0002746582031250, 0.0008239746093750, 0.0005493164062500, +0.0008544921875000, -0.0000610351562500, 0.0006103515625000, -0.0002136230468750, +0.0004882812500000, -0.0000915527343750, 0.0004882812500000, -0.0004272460937500, +0.0002746582031250, -0.0004882812500000, 0.0000610351562500, 0.0006713867187500, +0.0002136230468750, 0.0001220703125000, 0.0001220703125000, 0.0004577636718750, +0.0000915527343750, 0.0015258789062500, 0.0001525878906250, 0.0008850097656250, +0.0000610351562500, 0.0021362304687500, 0.0002746582031250, 0.0021057128906250, +0.0002136230468750, 0.0022888183593750, 0.0003051757812500, 0.0031127929687500, +0.0005187988281250, 0.0028381347656250, 0.0004272460937500, 0.0035400390625000, +0.0008544921875000, 0.0036926269531250, 0.0007629394531250, 0.0035400390625000, +0.0009155273437500, 0.0038146972656250, 0.0013122558593750, 0.0039062500000000, +0.0010986328125000, 0.0035705566406250, 0.0014953613281250, 0.0037841796875000, +0.0014648437500000, 0.0034179687500000, 0.0014648437500000, 0.0030517578125000, +0.0016174316406250, 0.0034179687500000, 0.0014953613281250, 0.0024414062500000, +0.0018920898437500, 0.0026245117187500, 0.0017089843750000, 0.0023803710937500, +0.0017395019531250, 0.0017089843750000, 0.0020751953125000, 0.0023193359375000, +0.0018310546875000, 0.0016479492187500, 0.0021667480468750, 0.0018005371093750, +0.0020446777343750, 0.0018615722656250, 0.0020446777343750, 0.0015563964843750, +0.0022583007812500, 0.0018615722656250, 0.0020141601562500, 0.0018310546875000, +0.0020141601562500, 0.0017700195312500, 0.0019836425781250, 0.0020446777343750, +0.0019531250000000, 0.0022583007812500, 0.0018920898437500, 0.0020446777343750, +0.0018005371093750, 0.0026245117187500, 0.0018615722656250, 0.0024414062500000, +0.0018310546875000, 0.0026245117187500, 0.0018005371093750, 0.0029907226562500, +0.0017700195312500, 0.0026855468750000, 0.0016784667968750, 0.0030822753906250, +0.0017089843750000, 0.0029602050781250, 0.0016784667968750, 0.0029602050781250, +0.0016479492187500, 0.0032348632812500, 0.0017089843750000, 0.0029296875000000, +0.0016479492187500, 0.0031127929687500, 0.0016784667968750, 0.0031433105468750, +0.0016784667968750, 0.0029602050781250, 0.0016174316406250, 0.0028991699218750, +0.0017089843750000, 0.0029907226562500, 0.0015869140625000, 0.0025939941406250, +0.0017089843750000, 0.0026855468750000, 0.0016174316406250, 0.0026550292968750, +0.0018005371093750, 0.0023803710937500, 0.0020446777343750, 0.0025024414062500, +0.0018615722656250, 0.0023803710937500, 0.0022277832031250, 0.0024414062500000, +0.0022583007812500, 0.0024719238281250, 0.0021362304687500, 0.0024108886718750, +0.0021362304687500, 0.0025634765625000, 0.0021057128906250, 0.0023803710937500, +0.0018310546875000, 0.0026245117187500, 0.0018005371093750, 0.0025024414062500, +0.0017089843750000, 0.0023193359375000, 0.0014648437500000, 0.0025939941406250, +0.0014648437500000, 0.0022583007812500, 0.0014648437500000, 0.0023498535156250, +0.0012512207031250, 0.0024719238281250, 0.0014648437500000, 0.0022277832031250, +0.0016479492187500, 0.0022888183593750, 0.0014648437500000, 0.0022583007812500, +0.0020446777343750, 0.0022583007812500, 0.0019531250000000, 0.0023193359375000, +0.0020751953125000, 0.0023498535156250, 0.0025024414062500, 0.0022277832031250, +0.0023193359375000, 0.0025024414062500, 0.0026245117187500, 0.0024414062500000, +0.0027770996093750, 0.0023193359375000, 0.0026245117187500, 0.0023193359375000, +0.0026855468750000, 0.0022277832031250, 0.0027770996093750, 0.0021057128906250, +0.0022277832031250, 0.0019836425781250, 0.0025329589843750, 0.0019531250000000, +0.0021667480468750, 0.0018310546875000, 0.0016174316406250, 0.0017395019531250, +0.0020141601562500, 0.0017089843750000, 0.0009765625000000, 0.0016479492187500, +0.0010986328125000, 0.0016784667968750, 0.0008850097656250, 0.0016784667968750, +0.0001525878906250, 0.0015563964843750, 0.0004882812500000, 0.0017089843750000, +0.0000915527343750, 0.0016784667968750, -0.0000915527343750, 0.0017089843750000, +0.0002441406250000, 0.0018005371093750, 0.0002746582031250, 0.0017395019531250, +0.0000915527343750, 0.0018005371093750, 0.0011901855468750, 0.0017700195312500, +0.0008544921875000, 0.0017700195312500, 0.0013732910156250, 0.0017700195312500, +0.0023803710937500, 0.0017395019531250, 0.0018005371093750, 0.0018615722656250, +0.0030212402343750, 0.0016479492187500, 0.0031433105468750, 0.0018920898437500, +0.0031127929687500, 0.0020446777343750, 0.0036926269531250, 0.0017700195312500, +0.0036010742187500, 0.0024414062500000, 0.0032348632812500, 0.0022277832031250, +0.0036010742187500, 0.0024108886718750, 0.0030822753906250, 0.0028991699218750, +0.0024108886718750, 0.0025329589843750, 0.0028381347656250, 0.0030822753906250, +0.0018005371093750, 0.0029296875000000, 0.0018005371093750, 0.0029907226562500, +0.0016479492187500, 0.0033874511718750, 0.0009460449218750, 0.0029907226562500, +0.0011596679687500, 0.0032348632812500, 0.0009460449218750, 0.0032043457031250, +0.0006408691406250, 0.0030212402343750, 0.0008544921875000, 0.0030212402343750, +0.0009765625000000, 0.0028991699218750, 0.0008239746093750, 0.0027770996093750, +0.0011291503906250, 0.0026245117187500, 0.0010986328125000, 0.0025329589843750, +0.0010070800781250, 0.0024414062500000, 0.0012207031250000, 0.0022277832031250, +0.0011901855468750, 0.0022583007812500, 0.0008850097656250, 0.0021057128906250, +0.0008850097656250, 0.0019531250000000, 0.0007629394531250, 0.0019531250000000, +0.0004272460937500, 0.0018310546875000, 0.0004882812500000, 0.0015869140625000, +0.0004882812500000, 0.0016479492187500, 0.0003051757812500, 0.0014648437500000, +0.0005798339843750, 0.0012207031250000, 0.0007934570312500, 0.0013427734375000, +0.0005493164062500, 0.0011291503906250, 0.0013427734375000, 0.0010375976562500, +0.0012512207031250, 0.0010986328125000, 0.0013732910156250, 0.0010986328125000, +0.0018920898437500, 0.0010070800781250, 0.0017089843750000, 0.0011901855468750, +0.0019226074218750, 0.0011596679687500, 0.0020751953125000, 0.0011291503906250, +0.0019226074218750, 0.0011901855468750, 0.0018310546875000, 0.0011596679687500, +0.0019226074218750, 0.0010070800781250, 0.0015563964843750, 0.0009460449218750, +0.0014953613281250, 0.0008239746093750, 0.0016174316406250, 0.0006408691406250, +0.0014953613281250, 0.0007019042968750, 0.0014953613281250, 0.0004272460937500, +0.0018920898437500, 0.0003662109375000, 0.0018310546875000, 0.0003662109375000, +0.0019836425781250, 0.0003051757812500, 0.0023803710937500, 0.0001831054687500, +0.0023193359375000, 0.0003356933593750, 0.0030517578125000, 0.0002746582031250, +0.0029296875000000, 0.0003967285156250, 0.0032958984375000, 0.0006408691406250, +0.0039672851562500, 0.0004272460937500, 0.0036010742187500, 0.0006103515625000, +0.0041809082031250, 0.0007019042968750, 0.0042114257812500, 0.0005187988281250, +0.0040588378906250, 0.0004577636718750, 0.0041809082031250, 0.0005187988281250, +0.0041198730468750, 0.0000610351562500, 0.0039062500000000, 0.0000610351562500, +0.0039978027343750, -0.0000305175781250, 0.0036926269531250, -0.0003662109375000, +0.0035095214843750, -0.0004272460937500, 0.0037536621093750, -0.0002136230468750, +0.0025024414062500, -0.0005493164062500, 0.0030212402343750, -0.0001831054687500, +0.0021972656250000, 0.0002441406250000, 0.0007629394531250, -0.0001525878906250, +0.0017089843750000, 0.0007934570312500, -0.0003967285156250, 0.0007934570312500, +-0.0004577636718750, 0.0007324218750000, -0.0003356933593750, 0.0014648437500000, +-0.0018310546875000, 0.0010681152343750, 0.0038452148437500, 0.0006103515625000, +0.0014648437500000, 0.0006713867187500, 0.0023498535156250, 0.0007629394531250, +0.0014953613281250, 0.0006713867187500, 0.0001220703125000, 0.0005493164062500, +0.0008850097656250, 0.0009155273437500, -0.0004272460937500, 0.0008239746093750, +-0.0006103515625000, 0.0008544921875000, -0.0002746582031250, 0.0011596679687500, +-0.0008239746093750}, +{0.0021667480468750, 0.0024414062500000, 0.0024414062500000, 0.0024108886718750, +0.0024108886718750, 0.0023498535156250, 0.0020751953125000, 0.0023803710937500, +0.0022888183593750, 0.0022583007812500, 0.0019226074218750, 0.0021057128906250, +0.0015563964843750, 0.0021362304687500, 0.0018615722656250, 0.0020141601562500, +0.0007629394531250, 0.0019531250000000, 0.0009155273437500, 0.0019836425781250, +0.0006408691406250, 0.0020141601562500, -0.0001525878906250, 0.0019226074218750, +0.0001220703125000, 0.0020446777343750, -0.0003967285156250, 0.0021057128906250, +-0.0005187988281250, 0.0021362304687500, -0.0003356933593750, 0.0021972656250000, +-0.0003967285156250, 0.0023193359375000, -0.0005187988281250, 0.0021667480468750, +-0.0002136230468750, 0.0023498535156250, -0.0002441406250000, 0.0022583007812500, +-0.0002746582031250, 0.0020446777343750, -0.0001525878906250, 0.0023193359375000, +-0.0001525878906250, 0.0018920898437500, -0.0005493164062500, 0.0019226074218750, +-0.0003967285156250, 0.0018920898437500, -0.0006408691406250, 0.0016479492187500, +-0.0010986328125000, 0.0018005371093750, -0.0008544921875000, 0.0017089843750000, +-0.0012512207031250, 0.0016479492187500, -0.0013427734375000, 0.0016479492187500, +-0.0011291503906250, 0.0015869140625000, -0.0011901855468750, 0.0015869140625000, +-0.0012207031250000, 0.0014038085937500, -0.0007019042968750, 0.0014038085937500, +-0.0008239746093750, 0.0012817382812500, -0.0004577636718750, 0.0010986328125000, +0.0001525878906250, 0.0011291503906250, -0.0000305175781250, 0.0008850097656250, +0.0003662109375000, 0.0008544921875000, 0.0005493164062500, 0.0007019042968750, +0.0004577636718750, 0.0005187988281250, 0.0005493164062500, 0.0004882812500000, +0.0007324218750000, 0.0003662109375000, 0.0004882812500000, 0.0002746582031250, +0.0005187988281250, 0.0002136230468750, 0.0005798339843750, 0.0001220703125000, +0.0006103515625000, 0.0000305175781250, 0.0007019042968750, -0.0000915527343750, +0.0008544921875000, -0.0000915527343750, 0.0008850097656250, -0.0003356933593750, +0.0011596679687500, -0.0004882812500000, 0.0014038085937500, -0.0003967285156250, +0.0012817382812500, -0.0007324218750000, 0.0018920898437500, -0.0008544921875000, +0.0018920898437500, -0.0007324218750000, 0.0020751953125000, -0.0008850097656250, +0.0024719238281250, -0.0009460449218750, 0.0023498535156250, -0.0004577636718750, +0.0029907226562500, -0.0007629394531250, 0.0029296875000000, -0.0003051757812500, +0.0031738281250000, 0.0003662109375000, 0.0037231445312500, -0.0000915527343750, +0.0035400390625000, 0.0009765625000000, 0.0043640136718750, 0.0009765625000000, +0.0043945312500000, 0.0009460449218750, 0.0044250488281250, 0.0014343261718750, +0.0050964355468750, 0.0012512207031250, 0.0050659179687500, 0.0011901855468750, +0.0042724609375000, 0.0013122558593750, 0.0047912597656250, 0.0011901855468750, +0.0043945312500000, 0.0008544921875000, 0.0025634765625000, 0.0009460449218750, +0.0033264160156250, 0.0012207031250000, 0.0049743652343750, 0.0011291503906250, +0.0048522949218750, 0.0012512207031250, 0.0047302246093750, 0.0013732910156250, +0.0050964355468750, 0.0013732910156250, 0.0051574707031250, 0.0013427734375000, +0.0041809082031250, 0.0014648437500000, 0.0047607421875000, 0.0014038085937500, +0.0037841796875000, 0.0012512207031250, 0.0023498535156250, 0.0013732910156250, +0.0032043457031250, 0.0015258789062500, 0.0008239746093750, 0.0013427734375000, +0.0008544921875000, 0.0018005371093750, 0.0006713867187500, 0.0021972656250000, +-0.0008544921875000, 0.0018920898437500, -0.0003967285156250, 0.0028991699218750, +-0.0004272460937500, 0.0028686523437500, -0.0011596679687500, 0.0028381347656250, +-0.0002746582031250, 0.0033874511718750, 0.0005798339843750, 0.0032653808593750, +-0.0003356933593750, 0.0027465820312500, 0.0014648437500000, 0.0030212402343750, +0.0013732910156250, 0.0025329589843750, 0.0014038085937500, 0.0017700195312500, +0.0024414062500000, 0.0021972656250000, 0.0019836425781250, 0.0013427734375000, +0.0021057128906250, 0.0011596679687500, 0.0024108886718750, 0.0013122558593750, +0.0019836425781250, 0.0009765625000000, 0.0015869140625000, 0.0008850097656250, +0.0018005371093750, 0.0013122558593750, 0.0010986328125000, 0.0010070800781250, +0.0010681152343750, 0.0010375976562500, 0.0009155273437500, 0.0013427734375000, +0.0005798339843750, 0.0010070800781250, 0.0007629394531250, 0.0010070800781250, +0.0004577636718750, 0.0008850097656250, 0.0001525878906250, 0.0007629394531250, +0.0005187988281250, 0.0006103515625000, 0.0006713867187500, 0.0004882812500000, +0.0003967285156250, 0.0008544921875000, 0.0013732910156250, 0.0005187988281250, +0.0009460449218750, 0.0008544921875000, 0.0012817382812500, 0.0013732910156250, +0.0022277832031250, 0.0008544921875000, 0.0016174316406250, 0.0019836425781250, +0.0025024414062500, 0.0019836425781250, 0.0026245117187500, 0.0018615722656250, +0.0023498535156250, 0.0024719238281250, 0.0025024414062500, 0.0023498535156250, +0.0026245117187500, 0.0018920898437500, 0.0024414062500000, 0.0022277832031250, +0.0024719238281250, 0.0015869140625000, 0.0024719238281250, 0.0008850097656250, +0.0022583007812500, 0.0014038085937500, 0.0022277832031250, -0.0001831054687500, +0.0028076171875000, -0.0000915527343750, 0.0025024414062500, -0.0003662109375000, +0.0027770996093750, -0.0014038085937500, 0.0034179687500000, -0.0010070800781250, +0.0029602050781250, -0.0013427734375000, 0.0035705566406250, -0.0017089843750000, +0.0037536621093750, -0.0012207031250000, 0.0036621093750000, -0.0010070800781250, +0.0037536621093750, -0.0014343261718750, 0.0037841796875000, -0.0002441406250000, +0.0036621093750000, -0.0003662109375000, 0.0036926269531250, -0.0002136230468750, +0.0037536621093750, 0.0006103515625000, 0.0036926269531250, 0.0003662109375000, +0.0035400390625000, 0.0007324218750000, 0.0036010742187500, 0.0008544921875000, +0.0035095214843750, 0.0007629394531250, 0.0035400390625000, 0.0008850097656250, +0.0036010742187500, 0.0008850097656250, 0.0035400390625000, 0.0008239746093750, +0.0033569335937500, 0.0008850097656250, 0.0035400390625000, 0.0009460449218750, +0.0032653808593750, 0.0009460449218750, 0.0029296875000000, 0.0009765625000000, +0.0031738281250000, 0.0009765625000000, 0.0025939941406250, 0.0010375976562500, +0.0027770996093750, 0.0010681152343750, 0.0026550292968750, 0.0010070800781250, +0.0022277832031250, 0.0011291503906250, 0.0026245117187500, 0.0011596679687500, +0.0022277832031250, 0.0011901855468750, 0.0022888183593750, 0.0012817382812500, +0.0023193359375000, 0.0013122558593750, 0.0021057128906250, 0.0013427734375000, +0.0022888183593750, 0.0013122558593750, 0.0019836425781250, 0.0013427734375000, +0.0020141601562500, 0.0013732910156250, 0.0019531250000000, 0.0013732910156250, +0.0017395019531250, 0.0013427734375000, 0.0018005371093750, 0.0015869140625000, +0.0016784667968750, 0.0014343261718750, 0.0016784667968750, 0.0015563964843750, +0.0016479492187500, 0.0017700195312500, 0.0015563964843750, 0.0015563964843750, +0.0016784667968750, 0.0019226074218750, 0.0016784667968750, 0.0018005371093750, +0.0015869140625000, 0.0017395019531250, 0.0018310546875000, 0.0019531250000000, +0.0019531250000000, 0.0018005371093750, 0.0018920898437500, 0.0018005371093750, +0.0023193359375000, 0.0018005371093750, 0.0022277832031250, 0.0017395019531250, +0.0023193359375000, 0.0016479492187500, 0.0025939941406250, 0.0017395019531250, +0.0024719238281250, 0.0016174316406250, 0.0026245117187500, 0.0016479492187500, +0.0026855468750000, 0.0017089843750000, 0.0026550292968750, 0.0016479492187500, +0.0026550292968750, 0.0017089843750000, 0.0027160644531250, 0.0017089843750000, +0.0025329589843750, 0.0017089843750000, 0.0026550292968750, 0.0016784667968750, +0.0025634765625000, 0.0016479492187500, 0.0023193359375000, 0.0016479492187500, +0.0024719238281250, 0.0014648437500000, 0.0020751953125000, 0.0013732910156250, +0.0021362304687500, 0.0012817382812500, 0.0021057128906250, 0.0010681152343750, +0.0018310546875000, 0.0010375976562500, 0.0019226074218750, 0.0010681152343750, +0.0019531250000000, 0.0008544921875000, 0.0018920898437500, 0.0009765625000000, +0.0019531250000000, 0.0011596679687500, 0.0020751953125000, 0.0009155273437500, +0.0019531250000000, 0.0013732910156250, 0.0023193359375000, 0.0013427734375000, +0.0022583007812500, 0.0011901855468750, 0.0022583007812500, 0.0012817382812500, +0.0024719238281250, 0.0012817382812500, 0.0023498535156250, 0.0007629394531250, +0.0023803710937500, 0.0009155273437500, 0.0025024414062500, 0.0007019042968750, +0.0022888183593750, 0.0001831054687500, 0.0021057128906250, 0.0004272460937500, +0.0022583007812500, 0.0000000000000000, 0.0017395019531250, -0.0000915527343750, +0.0018005371093750, 0.0000000000000000, 0.0017395019531250, -0.0000915527343750, +0.0013732910156250, -0.0000915527343750, 0.0015869140625000, 0.0000000000000000, +0.0012512207031250, 0.0000000000000000, 0.0013427734375000, 0.0000000000000000, +0.0012512207031250, -0.0000305175781250, 0.0010070800781250, 0.0000305175781250, +0.0012207031250000, 0.0001220703125000, 0.0008850097656250, 0.0000305175781250, +0.0009765625000000, 0.0000915527343750, 0.0010070800781250, 0.0002441406250000, +0.0008239746093750, 0.0002441406250000, 0.0009765625000000, 0.0003356933593750, +0.0011596679687500, 0.0003051757812500, 0.0010375976562500, 0.0003662109375000, +0.0011291503906250, 0.0003967285156250, 0.0013427734375000, 0.0003356933593750, +0.0012207031250000, 0.0003051757812500, 0.0011901855468750, 0.0003967285156250, +0.0012817382812500, 0.0001831054687500, 0.0010986328125000, -0.0000305175781250, +0.0008850097656250, 0.0001525878906250, 0.0008850097656250, -0.0004577636718750, +0.0006103515625000, -0.0003967285156250, 0.0005493164062500, -0.0004882812500000, +0.0004577636718750, -0.0009460449218750, 0.0002441406250000, -0.0007324218750000, +0.0002136230468750, -0.0006713867187500, 0.0001525878906250, -0.0009460449218750, +0.0000610351562500, -0.0004577636718750, 0.0002136230468750, -0.0000305175781250, +0.0003051757812500, -0.0005187988281250, 0.0001831054687500, 0.0008850097656250, +0.0006103515625000, 0.0007019042968750, 0.0005493164062500, 0.0007324218750000, +0.0006103515625000, 0.0020446777343750, 0.0010070800781250, 0.0025634765625000, +0.0009460449218750, 0.0028991699218750, 0.0011901855468750, 0.0029907226562500, +0.0011901855468750, 0.0029296875000000, 0.0010986328125000, 0.0031433105468750, +0.0012512207031250, 0.0032348632812500, 0.0012207031250000, 0.0027465820312500, +0.0012512207031250, 0.0030212402343750, 0.0011901855468750, 0.0025329589843750, +0.0012207031250000, 0.0018615722656250, 0.0011291503906250, 0.0023193359375000, +0.0010375976562500, 0.0012207031250000, 0.0011901855468750, 0.0010375976562500, +0.0009765625000000, 0.0011901855468750, 0.0010375976562500, 0.0007934570312500, +0.0012207031250000, 0.0006408691406250, 0.0008850097656250, 0.0011901855468750, +0.0011291503906250, 0.0010375976562500, 0.0010681152343750, 0.0012512207031250, +0.0010070800781250, 0.0017089843750000, 0.0010681152343750, 0.0013732910156250, +0.0008850097656250, 0.0021667480468750, 0.0009155273437500, 0.0020446777343750, +0.0007934570312500, 0.0020446777343750, 0.0007324218750000, 0.0025024414062500, +0.0007629394531250, 0.0022583007812500, 0.0006408691406250, 0.0024414062500000, +0.0007019042968750}, +{0.0021667480468750, 0.0020446777343750, 0.0024414062500000, 0.0020446777343750, +0.0024414062500000, 0.0018005371093750, 0.0023193359375000, 0.0013732910156250, +0.0023803710937500, 0.0015258789062500, 0.0023498535156250, 0.0014343261718750, +0.0021362304687500, 0.0012207031250000, 0.0022277832031250, 0.0014343261718750, +0.0019836425781250, 0.0015563964843750, 0.0017395019531250, 0.0014038085937500, +0.0019531250000000, 0.0019531250000000, 0.0013732910156250, 0.0019531250000000, +0.0014648437500000, 0.0019531250000000, 0.0014038085937500, 0.0022277832031250, +0.0009765625000000, 0.0021362304687500, 0.0011596679687500, 0.0019226074218750, +0.0009765625000000, 0.0020141601562500, 0.0008850097656250, 0.0019226074218750, +0.0010070800781250, 0.0016784667968750, 0.0009765625000000, 0.0017700195312500, +0.0008544921875000, 0.0016174316406250, 0.0011596679687500, 0.0014648437500000, +0.0010375976562500, 0.0015258789062500, 0.0011596679687500, 0.0015563964843750, +0.0014038085937500, 0.0014343261718750, 0.0012512207031250, 0.0014648437500000, +0.0014648437500000, 0.0014038085937500, 0.0014953613281250, 0.0013122558593750, +0.0013427734375000, 0.0012817382812500, 0.0014038085937500, 0.0012207031250000, +0.0014343261718750, 0.0010681152343750, 0.0011596679687500, 0.0010375976562500, +0.0013122558593750, 0.0009155273437500, 0.0010986328125000, 0.0007629394531250, +0.0007324218750000, 0.0007934570312500, 0.0010070800781250, 0.0005798339843750, +0.0004882812500000, 0.0005187988281250, 0.0005798339843750, 0.0003967285156250, +0.0005798339843750, 0.0002441406250000, 0.0002746582031250, 0.0001831054687500, +0.0004577636718750, -0.0002136230468750, 0.0003662109375000, -0.0001525878906250, +0.0002746582031250, -0.0004882812500000, 0.0006103515625000, -0.0008544921875000, +0.0006713867187500, -0.0006103515625000, 0.0004882812500000, -0.0014648437500000, +0.0012512207031250, -0.0014343261718750, 0.0010681152343750, -0.0016479492187500, +0.0013122558593750, -0.0022277832031250, 0.0018920898437500, -0.0020446777343750, +0.0015258789062500, -0.0021362304687500, 0.0019836425781250, -0.0023193359375000, +0.0020141601562500, -0.0019226074218750, 0.0017700195312500, -0.0014648437500000, +0.0018005371093750, -0.0011596679687500, 0.0017700195312500, -0.0000305175781250, +0.0014038085937500, -0.0005187988281250, 0.0014953613281250, 0.0000000000000000, +0.0014343261718750, 0.0011901855468750, 0.0011901855468750, 0.0005798339843750, +0.0012817382812500, 0.0024719238281250, 0.0011596679687500, 0.0024719238281250, +0.0011901855468750, 0.0027770996093750, 0.0010986328125000, 0.0040588378906250, +0.0010375976562500, 0.0035400390625000, 0.0011596679687500, 0.0038452148437500, +0.0007324218750000, 0.0041809082031250, 0.0009765625000000, 0.0036315917968750, +0.0007019042968750, 0.0032043457031250, 0.0002136230468750, 0.0033569335937500, +0.0005493164062500, 0.0023193359375000, -0.0000610351562500, 0.0022583007812500, +-0.0000305175781250, 0.0020446777343750, 0.0000305175781250, 0.0013427734375000, +-0.0002746582031250, 0.0015869140625000, -0.0002441406250000, 0.0013732910156250, +-0.0000305175781250, 0.0010986328125000, -0.0001831054687500, 0.0013427734375000, +0.0000305175781250, 0.0016479492187500, 0.0002746582031250, 0.0014648437500000, +0.0000915527343750, 0.0021362304687500, 0.0007019042968750, 0.0021362304687500, +0.0005798339843750, 0.0024414062500000, 0.0007019042968750, 0.0031127929687500, +0.0011596679687500, 0.0029602050781250, 0.0009155273437500, 0.0036315917968750, +0.0014038085937500, 0.0036315917968750, 0.0013122558593750, 0.0037536621093750, +0.0014343261718750, 0.0043029785156250, 0.0018310546875000, 0.0041198730468750, +0.0015563964843750, 0.0041198730468750, 0.0021362304687500, 0.0041809082031250, +0.0020446777343750, 0.0039367675781250, 0.0020446777343750, 0.0037536621093750, +0.0022888183593750, 0.0037536621093750, 0.0021972656250000, 0.0031433105468750, +0.0021972656250000, 0.0032348632812500, 0.0022888183593750, 0.0029602050781250, +0.0020446777343750, 0.0023803710937500, 0.0018920898437500, 0.0026855468750000, +0.0020141601562500, 0.0020446777343750, 0.0013427734375000, 0.0020751953125000, +0.0014343261718750, 0.0021057128906250, 0.0012512207031250, 0.0018005371093750, +0.0007629394531250, 0.0019836425781250, 0.0008850097656250, 0.0019836425781250, +0.0007019042968750, 0.0019531250000000, 0.0004882812500000, 0.0021972656250000, +0.0008239746093750, 0.0023803710937500, 0.0010375976562500, 0.0024108886718750, +0.0007934570312500, 0.0029296875000000, 0.0014038085937500, 0.0029296875000000, +0.0014343261718750, 0.0031127929687500, 0.0014648437500000, 0.0035095214843750, +0.0018005371093750, 0.0034179687500000, 0.0016784667968750, 0.0035095214843750, +0.0019226074218750, 0.0036315917968750, 0.0018615722656250, 0.0033874511718750, +0.0019226074218750, 0.0031738281250000, 0.0021667480468750, 0.0033569335937500, +0.0019836425781250, 0.0027770996093750, 0.0021667480468750, 0.0028381347656250, +0.0022888183593750, 0.0026855468750000, 0.0020751953125000, 0.0022583007812500, +0.0020446777343750, 0.0024719238281250, 0.0021667480468750, 0.0022583007812500, +0.0016174316406250, 0.0022583007812500, 0.0018005371093750, 0.0022583007812500, +0.0016784667968750, 0.0021972656250000, 0.0012817382812500, 0.0022583007812500, +0.0015258789062500, 0.0022888183593750, 0.0013122558593750, 0.0023498535156250, +0.0012512207031250, 0.0023803710937500, 0.0014038085937500, 0.0024414062500000, +0.0014648437500000, 0.0025024414062500, 0.0014343261718750, 0.0025634765625000, +0.0018920898437500, 0.0025329589843750, 0.0017395019531250, 0.0026550292968750, +0.0020141601562500, 0.0027770996093750, 0.0025329589843750, 0.0027770996093750, +0.0022888183593750, 0.0028991699218750, 0.0028381347656250, 0.0029907226562500, +0.0028381347656250, 0.0030212402343750, 0.0028686523437500, 0.0030517578125000, +0.0032043457031250, 0.0031738281250000, 0.0031127929687500, 0.0030517578125000, +0.0031433105468750, 0.0032958984375000, 0.0032653808593750, 0.0032653808593750, +0.0030822753906250, 0.0031738281250000, 0.0028686523437500, 0.0034790039062500, +0.0030822753906250, 0.0030517578125000, 0.0025024414062500, 0.0032958984375000, +0.0026245117187500, 0.0031127929687500, 0.0024108886718750, 0.0027160644531250, +0.0018920898437500, 0.0031433105468750, 0.0021057128906250, 0.0025024414062500, +0.0013427734375000, 0.0025939941406250, 0.0013732910156250, 0.0026245117187500, +0.0012512207031250, 0.0022277832031250, 0.0007324218750000, 0.0025024414062500, +0.0009460449218750, 0.0021667480468750, 0.0006713867187500, 0.0022583007812500, +0.0006408691406250, 0.0022888183593750, 0.0007019042968750, 0.0021362304687500, +0.0007019042968750, 0.0024108886718750, 0.0007934570312500, 0.0021667480468750, +0.0008544921875000, 0.0022888183593750, 0.0008850097656250, 0.0023193359375000, +0.0009155273437500, 0.0021362304687500, 0.0009765625000000, 0.0023498535156250, +0.0010681152343750, 0.0020446777343750, 0.0009460449218750, 0.0021972656250000, +0.0010070800781250, 0.0021972656250000, 0.0011291503906250, 0.0019836425781250, +0.0010986328125000, 0.0022277832031250, 0.0011596679687500, 0.0019531250000000, +0.0014953613281250, 0.0019531250000000, 0.0014343261718750, 0.0019836425781250, +0.0015563964843750, 0.0018005371093750, 0.0018920898437500, 0.0018920898437500, +0.0018005371093750, 0.0018615722656250, 0.0017700195312500, 0.0017700195312500, +0.0019226074218750, 0.0018310546875000, 0.0015869140625000, 0.0017700195312500, +0.0012512207031250, 0.0016784667968750, 0.0014038085937500, 0.0017395019531250, +0.0007019042968750, 0.0016784667968750, 0.0006408691406250, 0.0016174316406250, +0.0005798339843750, 0.0016784667968750, 0.0001525878906250, 0.0014953613281250, +0.0002441406250000, 0.0016479492187500, 0.0003356933593750, 0.0015258789062500, +0.0001831054687500, 0.0015563964843750, 0.0003356933593750, 0.0017089843750000, +0.0006408691406250, 0.0014648437500000, 0.0005187988281250, 0.0016784667968750, +0.0008544921875000, 0.0015869140625000, 0.0009155273437500, 0.0015563964843750, +0.0009155273437500, 0.0015563964843750, 0.0010070800781250, 0.0014953613281250, +0.0010070800781250, 0.0012512207031250, 0.0009765625000000, 0.0014343261718750, +0.0010681152343750, 0.0012207031250000, 0.0010986328125000, 0.0009765625000000, +0.0010070800781250, 0.0012512207031250, 0.0010375976562500, 0.0008544921875000, +0.0012512207031250, 0.0007934570312500, 0.0011901855468750, 0.0009155273437500, +0.0013427734375000, 0.0008239746093750, 0.0016479492187500, 0.0009155273437500, +0.0015258789062500, 0.0010681152343750, 0.0020141601562500, 0.0011291503906250, +0.0019531250000000, 0.0013122558593750, 0.0021057128906250, 0.0014953613281250, +0.0024719238281250, 0.0014343261718750, 0.0023193359375000, 0.0014343261718750, +0.0025634765625000, 0.0016479492187500, 0.0025939941406250, 0.0014038085937500, +0.0024719238281250, 0.0011901855468750, 0.0025634765625000, 0.0014648437500000, +0.0025634765625000, 0.0008850097656250, 0.0022583007812500, 0.0009765625000000, +0.0022888183593750, 0.0010070800781250, 0.0021667480468750, 0.0006408691406250, +0.0019226074218750, 0.0007629394531250, 0.0019836425781250, 0.0009155273437500, +0.0016784667968750, 0.0007629394531250, 0.0016784667968750, 0.0008850097656250, +0.0015258789062500, 0.0010375976562500, 0.0013122558593750, 0.0008544921875000, +0.0014038085937500, 0.0011291503906250, 0.0009765625000000, 0.0010986328125000, +0.0009765625000000, 0.0010986328125000, 0.0008544921875000, 0.0012817382812500, +0.0002746582031250, 0.0015869140625000, 0.0031738281250000, 0.0021667480468750, +0.0022888183593750, 0.0016784667968750, 0.0027770996093750, 0.0019836425781250, +0.0021972656250000, 0.0024719238281250, 0.0013427734375000, 0.0021057128906250, +0.0016784667968750, 0.0024414062500000, 0.0012207031250000, 0.0025634765625000, +0.0009765625000000, 0.0024108886718750, 0.0013122558593750, 0.0024719238281250, +0.0014038085937500, 0.0024719238281250, 0.0012817382812500, 0.0022277832031250, +0.0018920898437500, 0.0021972656250000, 0.0017089843750000, 0.0022277832031250, +0.0020751953125000, 0.0020751953125000, 0.0025939941406250, 0.0020446777343750, +0.0021667480468750, 0.0024414062500000, 0.0031433105468750, 0.0022888183593750, +0.0030822753906250, 0.0025024414062500, 0.0028076171875000, 0.0028991699218750, +0.0032348632812500, 0.0026245117187500, 0.0032348632812500, 0.0028381347656250, +0.0027160644531250, 0.0029907226562500, 0.0028686523437500, 0.0027770996093750, +0.0027160644531250, 0.0025939941406250, 0.0022277832031250, 0.0027160644531250, +0.0025024414062500, 0.0020751953125000, 0.0019226074218750, 0.0021057128906250, +0.0020751953125000, 0.0020141601562500, 0.0020751953125000, 0.0015563964843750, +0.0017089843750000, 0.0016784667968750, 0.0019836425781250, 0.0016479492187500, +0.0020141601562500, 0.0014953613281250, 0.0018920898437500, 0.0015563964843750, +0.0022277832031250, 0.0016784667968750, 0.0024108886718750, 0.0016174316406250, +0.0022583007812500, 0.0014648437500000, 0.0031433105468750, 0.0015563964843750, +0.0030517578125000, 0.0013122558593750, 0.0029602050781250, 0.0010681152343750, +0.0033874511718750, 0.0012207031250000, 0.0032653808593750, 0.0003662109375000, +0.0031433105468750, 0.0004577636718750, 0.0031738281250000, 0.0000915527343750, +0.0029907226562500}, +{0.0009155273437500, 0.0014038085937500, 0.0010986328125000, 0.0010681152343750, +0.0011291503906250, 0.0012512207031250, 0.0010986328125000, 0.0010986328125000, +0.0017089843750000, 0.0009765625000000, 0.0015869140625000, 0.0011901855468750, +0.0017700195312500, 0.0013122558593750, 0.0021972656250000, 0.0011596679687500, +0.0019531250000000, 0.0017395019531250, 0.0023498535156250, 0.0016784667968750, +0.0022277832031250, 0.0017395019531250, 0.0023193359375000, 0.0021362304687500, +0.0024719238281250, 0.0020141601562500, 0.0021972656250000, 0.0019836425781250, +0.0027465820312500, 0.0021667480468750, 0.0025024414062500, 0.0019836425781250, +0.0026550292968750, 0.0016784667968750, 0.0031433105468750, 0.0018615722656250, +0.0028381347656250, 0.0015258789062500, 0.0032043457031250, 0.0014038085937500, +0.0032653808593750, 0.0015258789062500, 0.0032653808593750, 0.0014038085937500, +0.0035095214843750, 0.0012817382812500, 0.0034484863281250, 0.0017089843750000, +0.0034484863281250, 0.0014648437500000, 0.0036010742187500, 0.0016479492187500, +0.0033569335937500, 0.0021057128906250, 0.0031433105468750, 0.0017089843750000, +0.0032958984375000, 0.0020751953125000, 0.0026855468750000, 0.0020751953125000, +0.0026855468750000, 0.0019531250000000, 0.0028686523437500, 0.0020446777343750, +0.0026855468750000, 0.0019226074218750, 0.0026245117187500, 0.0019226074218750, +0.0030822753906250, 0.0018310546875000, 0.0029907226562500, 0.0018005371093750, +0.0029602050781250, 0.0018920898437500, 0.0032958984375000, 0.0026245117187500, +0.0021362304687500, 0.0029907226562500, 0.0028991699218750, 0.0028076171875000, +0.0026550292968750, 0.0026855468750000, 0.0026855468750000, 0.0026245117187500, +0.0029907226562500, 0.0025329589843750, 0.0028991699218750, 0.0021972656250000, +0.0027160644531250, 0.0020141601562500, 0.0027770996093750, 0.0020141601562500, +0.0025939941406250, 0.0018310546875000, 0.0022888183593750, 0.0014953613281250, +0.0023803710937500, 0.0021057128906250, 0.0020446777343750, 0.0016479492187500, +0.0021057128906250, 0.0018310546875000, 0.0019836425781250, 0.0024414062500000, +0.0015869140625000, 0.0019226074218750, 0.0016174316406250, 0.0022277832031250, +0.0015869140625000, 0.0022277832031250, 0.0012512207031250, 0.0019226074218750, +0.0014648437500000, 0.0018005371093750, 0.0017395019531250, 0.0018615722656250, +0.0013427734375000, 0.0015563964843750, 0.0018615722656250, 0.0014343261718750, +0.0018310546875000, 0.0015258789062500, 0.0018005371093750, 0.0014648437500000, +0.0021057128906250, 0.0013427734375000, 0.0021057128906250, 0.0017089843750000, +0.0019836425781250, 0.0014953613281250, 0.0022583007812500, 0.0015869140625000, +0.0020446777343750, 0.0019531250000000, 0.0017700195312500, 0.0016479492187500, +0.0020751953125000, 0.0017089843750000, 0.0011901855468750, 0.0018005371093750, +0.0012512207031250, 0.0014038085937500, 0.0010681152343750, 0.0010986328125000, +0.0004272460937500, 0.0012817382812500, 0.0005798339843750, 0.0004272460937500, +0.0004272460937500, 0.0004577636718750, 0.0000000000000000, 0.0002746582031250, +0.0004272460937500, -0.0003356933593750, 0.0007934570312500, -0.0001220703125000, +0.0003967285156250, -0.0003662109375000, 0.0010375976562500, -0.0005493164062500, +0.0010681152343750, -0.0003967285156250, 0.0010070800781250, -0.0003967285156250, +0.0014343261718750, -0.0005187988281250, 0.0014953613281250, -0.0000915527343750, +0.0012512207031250, -0.0003051757812500, 0.0014648437500000, -0.0001220703125000, +0.0011596679687500, 0.0003356933593750, 0.0007324218750000, 0.0000610351562500, +0.0010986328125000, 0.0004882812500000, 0.0005493164062500, 0.0005187988281250, +0.0005798339843750, 0.0004577636718750, 0.0006408691406250, 0.0006103515625000, +0.0002746582031250, 0.0007019042968750, 0.0003967285156250, 0.0006408691406250, +0.0008239746093750, 0.0006103515625000, 0.0005187988281250, 0.0007019042968750, +0.0009460449218750, 0.0006713867187500, 0.0014648437500000, 0.0006103515625000, +0.0010681152343750, 0.0007629394531250, 0.0020751953125000, 0.0006713867187500, +0.0018920898437500, 0.0007019042968750, 0.0020141601562500, 0.0008544921875000, +0.0025939941406250, 0.0006103515625000, 0.0020751953125000, 0.0008544921875000, +0.0026550292968750, 0.0008239746093750, 0.0025634765625000, 0.0007629394531250, +0.0025939941406250, 0.0008544921875000, 0.0028686523437500, 0.0007934570312500, +0.0026550292968750, 0.0006408691406250, 0.0030517578125000, 0.0006713867187500, +0.0029602050781250, 0.0005493164062500, 0.0030822753906250, 0.0004272460937500, +0.0033569335937500, 0.0004882812500000, 0.0031127929687500, 0.0004577636718750, +0.0035095214843750, 0.0003356933593750, 0.0034790039062500, 0.0005798339843750, +0.0034790039062500, 0.0006713867187500, 0.0036315917968750, 0.0005187988281250, +0.0036315917968750, 0.0011291503906250, 0.0036621093750000, 0.0009460449218750, +0.0036926269531250, 0.0012207031250000, 0.0037536621093750, 0.0017395019531250, +0.0037536621093750, 0.0014343261718750, 0.0038146972656250, 0.0023193359375000, +0.0039978027343750, 0.0021972656250000, 0.0039367675781250, 0.0024108886718750, +0.0039978027343750, 0.0031127929687500, 0.0042114257812500, 0.0027465820312500, +0.0041198730468750, 0.0032653808593750, 0.0042724609375000, 0.0032348632812500, +0.0042419433593750, 0.0030517578125000, 0.0042724609375000, 0.0031738281250000, +0.0043334960937500, 0.0030822753906250, 0.0042419433593750, 0.0026550292968750, +0.0043945312500000, 0.0028076171875000, 0.0043640136718750, 0.0024414062500000, +0.0043334960937500, 0.0019531250000000, 0.0044250488281250, 0.0023193359375000, +0.0043945312500000, 0.0013427734375000, 0.0043640136718750, 0.0015563964843750, +0.0042724609375000, 0.0014038085937500, 0.0043029785156250, 0.0007019042968750, +0.0043029785156250, 0.0011901855468750, 0.0040893554687500, 0.0006103515625000, +0.0043029785156250, 0.0005798339843750, 0.0041809082031250, 0.0008239746093750, +0.0041503906250000, 0.0006713867187500, 0.0042419433593750, 0.0007019042968750, +0.0040893554687500, 0.0010986328125000, 0.0041198730468750, 0.0009460449218750, +0.0041198730468750, 0.0013122558593750, 0.0040283203125000, 0.0017089843750000, +0.0039672851562500, 0.0014038085937500, 0.0039978027343750, 0.0022888183593750, +0.0039367675781250, 0.0021362304687500, 0.0039367675781250, 0.0023498535156250, +0.0038757324218750, 0.0029602050781250, 0.0038452148437500, 0.0025634765625000, +0.0038452148437500, 0.0032348632812500, 0.0036621093750000, 0.0031738281250000, +0.0036926269531250, 0.0032958984375000, 0.0034179687500000, 0.0037231445312500, +0.0031127929687500, 0.0035705566406250, 0.0032348632812500, 0.0039978027343750, +0.0025939941406250, 0.0039978027343750, 0.0026245117187500, 0.0040893554687500, +0.0024108886718750, 0.0043945312500000, 0.0019226074218750, 0.0042724609375000, +0.0020751953125000, 0.0043334960937500, 0.0016479492187500, 0.0045471191406250, +0.0015258789062500, 0.0042419433593750, 0.0014953613281250, 0.0040588378906250, +0.0014038085937500, 0.0043029785156250, 0.0013122558593750, 0.0036315917968750, +0.0016174316406250, 0.0037536621093750, 0.0014038085937500, 0.0037231445312500, +0.0016174316406250, 0.0032348632812500, 0.0019226074218750, 0.0034484863281250, +0.0016784667968750, 0.0032958984375000, 0.0022888183593750, 0.0031738281250000, +0.0021362304687500, 0.0032653808593750, 0.0021972656250000, 0.0033569335937500, +0.0026550292968750, 0.0033569335937500, 0.0023498535156250, 0.0034790039062500, +0.0024414062500000, 0.0035705566406250, 0.0025329589843750, 0.0034484863281250, +0.0023193359375000, 0.0034179687500000, 0.0022277832031250, 0.0035705566406250, +0.0022277832031250, 0.0031738281250000, 0.0018310546875000, 0.0032653808593750, +0.0018920898437500, 0.0032043457031250, 0.0017089843750000, 0.0028991699218750, +0.0014038085937500, 0.0030517578125000, 0.0014953613281250, 0.0033264160156250, +0.0011901855468750, 0.0031738281250000, 0.0011901855468750, 0.0035705566406250, +0.0011901855468750, 0.0039978027343750, 0.0009765625000000, 0.0037231445312500, +0.0010375976562500, 0.0046691894531250, 0.0011596679687500, 0.0045776367187500, +0.0009765625000000, 0.0047912597656250, 0.0011291503906250, 0.0054321289062500, +0.0014038085937500, 0.0051879882812500, 0.0010986328125000, 0.0057678222656250, +0.0014953613281250, 0.0057373046875000, 0.0014038085937500, 0.0057678222656250, +0.0013122558593750, 0.0061340332031250, 0.0014038085937500, 0.0058593750000000, +0.0014343261718750, 0.0058593750000000, 0.0013122558593750, 0.0059509277343750, +0.0012207031250000, 0.0055236816406250, 0.0011901855468750, 0.0051879882812500, +0.0011596679687500, 0.0054321289062500, 0.0011291503906250, 0.0044555664062500, +0.0012817382812500, 0.0045471191406250, 0.0012207031250000, 0.0043029785156250, +0.0012207031250000, 0.0032348632812500, 0.0013427734375000, 0.0029296875000000, +0.0013732910156250, 0.0024414062500000, 0.0011901855468750, 0.0025939941406250, +0.0013427734375000, 0.0024108886718750, 0.0012207031250000, 0.0019531250000000, +0.0009460449218750, 0.0022583007812500, 0.0011901855468750, 0.0012817382812500, +0.0010375976562500, 0.0013122558593750, 0.0009460449218750, 0.0010986328125000, +0.0010986328125000, 0.0004882812500000, 0.0010681152343750, 0.0006713867187500, +0.0010375976562500, 0.0002441406250000, 0.0014648437500000, 0.0002441406250000, +0.0013122558593750, 0.0000610351562500, 0.0015258789062500, -0.0002746582031250, +0.0019836425781250, -0.0000305175781250, 0.0016479492187500, -0.0003051757812500, +0.0020446777343750, -0.0004272460937500, 0.0020446777343750, -0.0000915527343750, +0.0019531250000000, 0.0000915527343750, 0.0019836425781250, -0.0001831054687500, +0.0018615722656250, 0.0007324218750000, 0.0018005371093750, 0.0006103515625000, +0.0017089843750000, 0.0005798339843750, 0.0017700195312500, 0.0010681152343750, +0.0018005371093750, 0.0008544921875000, 0.0016784667968750, 0.0007934570312500, +0.0018310546875000, 0.0007629394531250, 0.0018005371093750, 0.0005798339843750, +0.0017395019531250, 0.0003662109375000, 0.0018920898437500, 0.0003356933593750, +0.0017395019531250, -0.0000305175781250, 0.0016784667968750, -0.0000915527343750, +0.0018310546875000, -0.0000915527343750, 0.0016174316406250, -0.0003356933593750, +0.0014038085937500, -0.0003356933593750, 0.0014953613281250, -0.0001220703125000, +0.0011596679687500, -0.0003051757812500, 0.0010986328125000, -0.0000305175781250, +0.0010375976562500, 0.0003356933593750, 0.0007324218750000, 0.0000305175781250, +0.0007934570312500, 0.0008544921875000, 0.0008239746093750, 0.0006713867187500, +0.0006103515625000, 0.0007934570312500, 0.0007934570312500, 0.0012817382812500, +0.0008544921875000, 0.0009155273437500, 0.0006408691406250, 0.0014038085937500, +0.0011291503906250, 0.0012817382812500, 0.0010681152343750, 0.0013732910156250, +0.0012207031250000, 0.0016479492187500, 0.0016784667968750, 0.0013122558593750, +0.0014038085937500, 0.0018310546875000, 0.0016479492187500, 0.0016174316406250, +0.0017395019531250, 0.0018005371093750, 0.0017089843750000, 0.0021972656250000, +0.0017395019531250, 0.0018920898437500, 0.0017395019531250, 0.0024414062500000, +0.0018005371093750, 0.0022888183593750, 0.0018005371093750, 0.0024108886718750, +0.0017089843750000, 0.0027160644531250, 0.0016784667968750, 0.0024108886718750, +0.0017089843750000}, +{0.0025634765625000, 0.0032043457031250, 0.0024414062500000, 0.0031433105468750, +0.0024719238281250, 0.0030517578125000, 0.0026245117187500, 0.0032653808593750, +0.0024414062500000, 0.0034179687500000, 0.0021972656250000, 0.0032653808593750, +0.0024414062500000, 0.0036315917968750, 0.0018310546875000, 0.0036926269531250, +0.0018615722656250, 0.0038146972656250, 0.0017700195312500, 0.0040283203125000, +0.0013122558593750, 0.0040283203125000, 0.0015258789062500, 0.0044860839843750, +0.0011901855468750, 0.0044860839843750, 0.0010986328125000, 0.0046386718750000, +0.0010681152343750, 0.0049133300781250, 0.0009155273437500, 0.0047912597656250, +0.0010070800781250, 0.0047607421875000, 0.0008850097656250, 0.0050048828125000, +0.0008544921875000, 0.0045776367187500, 0.0007934570312500, 0.0041198730468750, +0.0006713867187500, 0.0041809082031250, 0.0007629394531250, 0.0030822753906250, +0.0007324218750000, 0.0033569335937500, 0.0007019042968750, 0.0032043457031250, +0.0008239746093750, 0.0023803710937500, 0.0009155273437500, 0.0026855468750000, +0.0008544921875000, 0.0017089843750000, 0.0011596679687500, 0.0016784667968750, +0.0011901855468750, 0.0014038085937500, 0.0013732910156250, 0.0005493164062500, +0.0016784667968750, 0.0006713867187500, 0.0016784667968750, 0.0003356933593750, +0.0018005371093750, 0.0000000000000000, 0.0019836425781250, 0.0000305175781250, +0.0018920898437500, 0.0000000000000000, 0.0018310546875000, -0.0003051757812500, +0.0020141601562500, -0.0003356933593750, 0.0018615722656250, -0.0004272460937500, +0.0019531250000000, -0.0005187988281250, 0.0019836425781250, -0.0007324218750000, +0.0018310546875000, -0.0008239746093750, 0.0018920898437500, -0.0003967285156250, +0.0020141601562500, -0.0007629394531250, 0.0019836425781250, -0.0003967285156250, +0.0020141601562500, 0.0001831054687500, 0.0021362304687500, -0.0003356933593750, +0.0020751953125000, 0.0007324218750000, 0.0020446777343750, 0.0005798339843750, +0.0020751953125000, 0.0008850097656250, 0.0019531250000000, 0.0017395019531250, +0.0018615722656250, 0.0012207031250000, 0.0018615722656250, 0.0016174316406250, +0.0015258789062500, 0.0018920898437500, 0.0015258789062500, 0.0016479492187500, +0.0014953613281250, 0.0015258789062500, 0.0012817382812500, 0.0018005371093750, +0.0012817382812500, 0.0013122558593750, 0.0013732910156250, 0.0013122558593750, +0.0012817382812500, 0.0014038085937500, 0.0013732910156250, 0.0011596679687500, +0.0015258789062500, 0.0013122558593750, 0.0014038085937500, 0.0014648437500000, +0.0018005371093750, 0.0013732910156250, 0.0018310546875000, 0.0017089843750000, +0.0019226074218750, 0.0020141601562500, 0.0022277832031250, 0.0018615722656250, +0.0021972656250000, 0.0025939941406250, 0.0024108886718750, 0.0026245117187500, +0.0024414062500000, 0.0028381347656250, 0.0024719238281250, 0.0033569335937500, +0.0025939941406250, 0.0032348632812500, 0.0025024414062500, 0.0035705566406250, +0.0025939941406250, 0.0036926269531250, 0.0025024414062500, 0.0035705566406250, +0.0025329589843750, 0.0037231445312500, 0.0026855468750000, 0.0037536621093750, +0.0025329589843750, 0.0032653808593750, 0.0026550292968750, 0.0034790039062500, +0.0025939941406250, 0.0031127929687500, 0.0026245117187500, 0.0025634765625000, +0.0026550292968750, 0.0029296875000000, 0.0025634765625000, 0.0020141601562500, +0.0028381347656250, 0.0020141601562500, 0.0026855468750000, 0.0020446777343750, +0.0028076171875000, 0.0015258789062500, 0.0031433105468750, 0.0016784667968750, +0.0029907226562500, 0.0016784667968750, 0.0031738281250000, 0.0014038085937500, +0.0032958984375000, 0.0016479492187500, 0.0030822753906250, 0.0018615722656250, +0.0030517578125000, 0.0014953613281250, 0.0031738281250000, 0.0022583007812500, +0.0024719238281250, 0.0020446777343750, 0.0026855468750000, 0.0021667480468750, +0.0022583007812500, 0.0027160644531250, 0.0015563964843750, 0.0022583007812500, +0.0020141601562500, 0.0027160644531250, 0.0008850097656250, 0.0027465820312500, +0.0010070800781250, 0.0025329589843750, 0.0007934570312500, 0.0026245117187500, +0.0000610351562500, 0.0025329589843750, 0.0003967285156250, 0.0023498535156250, +-0.0003051757812500, 0.0023193359375000, -0.0003662109375000, 0.0022888183593750, +-0.0002746582031250, 0.0021667480468750, -0.0006103515625000, 0.0021057128906250, +-0.0006103515625000, 0.0021057128906250, -0.0002746582031250, 0.0020446777343750, +-0.0004577636718750, 0.0019836425781250, -0.0001831054687500, 0.0020446777343750, +0.0002136230468750, 0.0019836425781250, -0.0000305175781250, 0.0018005371093750, +0.0007629394531250, 0.0018615722656250, 0.0007019042968750, 0.0017395019531250, +0.0008544921875000, 0.0015869140625000, 0.0013732910156250, 0.0016479492187500, +0.0011291503906250, 0.0015869140625000, 0.0014038085937500, 0.0014648437500000, +0.0014038085937500, 0.0015563964843750, 0.0013427734375000, 0.0015563964843750, +0.0014648437500000, 0.0014648437500000, 0.0014038085937500, 0.0018310546875000, +0.0014953613281250, 0.0016479492187500, 0.0013732910156250, 0.0018005371093750, +0.0014343261718750, 0.0020751953125000, 0.0014648437500000, 0.0018005371093750, +0.0013122558593750, 0.0022583007812500, 0.0017089843750000, 0.0021667480468750, +0.0015563964843750, 0.0021362304687500, 0.0017700195312500, 0.0023498535156250, +0.0022277832031250, 0.0021667480468750, 0.0019531250000000, 0.0022277832031250, +0.0025939941406250, 0.0022277832031250, 0.0025939941406250, 0.0021362304687500, +0.0025634765625000, 0.0021057128906250, 0.0029296875000000, 0.0022277832031250, +0.0028686523437500, 0.0021057128906250, 0.0027160644531250, 0.0021362304687500, +0.0029602050781250, 0.0021362304687500, 0.0027160644531250, 0.0021362304687500, +0.0024414062500000, 0.0021667480468750, 0.0027160644531250, 0.0022277832031250, +0.0019836425781250, 0.0022583007812500, 0.0021362304687500, 0.0022277832031250, +0.0019836425781250, 0.0022583007812500, 0.0014038085937500, 0.0023498535156250, +0.0018005371093750, 0.0021362304687500, 0.0009765625000000, 0.0022277832031250, +0.0010681152343750, 0.0020751953125000, 0.0010070800781250, 0.0018310546875000, +0.0005187988281250, 0.0019836425781250, 0.0007019042968750, 0.0015869140625000, +0.0003967285156250, 0.0015869140625000, 0.0003662109375000, 0.0016174316406250, +0.0004882812500000, 0.0013427734375000, 0.0004577636718750, 0.0013427734375000, +0.0004577636718750, 0.0015869140625000, 0.0008239746093750, 0.0013732910156250, +0.0007629394531250, 0.0016479492187500, 0.0008850097656250, 0.0019836425781250, +0.0012207031250000, 0.0017395019531250, 0.0011291503906250, 0.0022583007812500, +0.0013427734375000, 0.0022888183593750, 0.0014343261718750, 0.0022888183593750, +0.0014343261718750, 0.0026245117187500, 0.0015258789062500, 0.0025329589843750, +0.0014648437500000, 0.0025329589843750, 0.0014343261718750, 0.0026550292968750, +0.0013732910156250, 0.0025329589843750, 0.0013732910156250, 0.0024108886718750, +0.0013427734375000, 0.0024414062500000, 0.0012512207031250, 0.0023803710937500, +0.0017089843750000, 0.0022888183593750, 0.0014038085937500, 0.0023193359375000, +0.0016174316406250, 0.0022888183593750, 0.0021667480468750, 0.0021972656250000, +0.0019226074218750, 0.0024719238281250, 0.0023498535156250, 0.0023498535156250, +0.0024414062500000, 0.0022583007812500, 0.0023803710937500, 0.0024108886718750, +0.0025024414062500, 0.0022888183593750, 0.0024719238281250, 0.0021972656250000, +0.0024108886718750, 0.0022277832031250, 0.0022888183593750, 0.0021362304687500, +0.0022583007812500, 0.0020751953125000, 0.0021667480468750, 0.0021057128906250, +0.0021362304687500, 0.0018920898437500, 0.0023193359375000, 0.0019531250000000, +0.0020446777343750, 0.0020446777343750, 0.0023498535156250, 0.0019226074218750, +0.0027465820312500, 0.0019226074218750, 0.0023803710937500, 0.0020751953125000, +0.0032348632812500, 0.0020446777343750, 0.0031738281250000, 0.0021057128906250, +0.0032043457031250, 0.0021972656250000, 0.0037536621093750, 0.0021057128906250, +0.0035705566406250, 0.0022888183593750, 0.0034179687500000, 0.0022277832031250, +0.0036926269531250, 0.0021972656250000, 0.0035095214843750, 0.0023498535156250, +0.0028991699218750, 0.0015869140625000, 0.0030212402343750, 0.0014343261718750, +0.0036010742187500, 0.0014953613281250, 0.0035095214843750, 0.0013427734375000, +0.0033569335937500, 0.0011596679687500, 0.0034179687500000, 0.0012817382812500, +0.0034179687500000, 0.0007324218750000, 0.0029907226562500, 0.0008239746093750, +0.0031127929687500, 0.0006713867187500, 0.0029296875000000, 0.0002441406250000, +0.0025939941406250, 0.0004577636718750, 0.0027770996093750, 0.0003051757812500, +0.0022583007812500, 0.0001220703125000, 0.0023498535156250, 0.0003967285156250, +0.0022888183593750, 0.0005798339843750, 0.0019226074218750, 0.0003967285156250, +0.0019836425781250, 0.0011596679687500, 0.0018920898437500, 0.0010986328125000, +0.0017395019531250, 0.0011596679687500, 0.0017395019531250, 0.0016174316406250, +0.0016784667968750, 0.0014343261718750, 0.0015563964843750, 0.0015258789062500, +0.0019836425781250, 0.0016479492187500, 0.0017700195312500, 0.0014953613281250, +0.0018005371093750, 0.0013732910156250, 0.0021057128906250, 0.0014953613281250, +0.0019226074218750, 0.0013122558593750, 0.0015563964843750, 0.0013427734375000, +0.0018310546875000, 0.0012817382812500, 0.0014648437500000, 0.0011596679687500, +0.0008544921875000, 0.0012207031250000, 0.0011291503906250, 0.0012207031250000, +0.0006713867187500, 0.0011291503906250, 0.0006408691406250, 0.0012207031250000, +0.0007019042968750, 0.0013427734375000, 0.0004882812500000, 0.0012512207031250, +0.0005798339843750, 0.0015258789062500, 0.0007934570312500, 0.0015258789062500, +0.0007629394531250, 0.0016784667968750, 0.0007629394531250, 0.0018005371093750, +0.0009460449218750, 0.0018005371093750, 0.0009765625000000, 0.0017089843750000, +0.0011291503906250, 0.0017700195312500, 0.0011291503906250, 0.0017089843750000, +0.0010070800781250, 0.0015869140625000, 0.0010986328125000, 0.0016174316406250, +0.0011901855468750, 0.0015869140625000, 0.0009765625000000, 0.0015258789062500, +0.0009155273437500, 0.0014953613281250, 0.0010681152343750, 0.0014343261718750, +0.0010986328125000, 0.0014038085937500, 0.0010070800781250, 0.0014343261718750, +0.0011901855468750, 0.0013427734375000, 0.0012512207031250, 0.0013732910156250, +0.0012207031250000, 0.0015258789062500, 0.0012512207031250, 0.0014343261718750, +0.0012512207031250, 0.0013732910156250, 0.0011596679687500, 0.0014648437500000, +0.0012512207031250, 0.0012207031250000, 0.0011291503906250, 0.0009765625000000, +0.0009765625000000, 0.0013122558593750, 0.0009460449218750, 0.0007324218750000, +0.0007324218750000, 0.0007629394531250, 0.0007934570312500, 0.0009460449218750, +0.0007324218750000, 0.0006408691406250, 0.0004272460937500, 0.0007629394531250, +0.0005187988281250, 0.0012512207031250, 0.0005187988281250, 0.0009155273437500, +0.0004577636718750, 0.0014038085937500, 0.0006103515625000, 0.0020446777343750, +0.0007019042968750, 0.0014953613281250, 0.0006408691406250, 0.0028076171875000, +0.0008850097656250, 0.0025329589843750, 0.0009765625000000, 0.0026855468750000, +0.0010375976562500, 0.0035705566406250, 0.0011596679687500, 0.0031127929687500, +0.0011901855468750, 0.0033569335937500, 0.0011596679687500, 0.0036315917968750, +0.0011596679687500}, +{0.0029602050781250, 0.0017089843750000, 0.0028686523437500, 0.0016479492187500, +0.0028991699218750, 0.0015869140625000, 0.0035400390625000, 0.0012817382812500, +0.0025024414062500, 0.0005493164062500, 0.0022888183593750, 0.0007019042968750, +0.0021362304687500, 0.0006103515625000, 0.0024414062500000, 0.0002746582031250, +0.0026245117187500, 0.0004272460937500, 0.0024414062500000, 0.0004272460937500, +0.0028991699218750, 0.0003356933593750, 0.0029602050781250, 0.0005798339843750, +0.0028381347656250, 0.0008239746093750, 0.0029296875000000, 0.0006713867187500, +0.0027770996093750, 0.0010681152343750, 0.0027160644531250, 0.0011901855468750, +0.0026550292968750, 0.0010681152343750, 0.0025634765625000, 0.0011901855468750, +0.0024108886718750, 0.0013122558593750, 0.0024719238281250, 0.0010375976562500, +0.0022277832031250, 0.0011291503906250, 0.0023803710937500, 0.0010681152343750, +0.0020751953125000, 0.0009765625000000, 0.0017395019531250, 0.0010986328125000, +0.0020751953125000, 0.0009155273437500, 0.0013732910156250, 0.0009765625000000, +0.0013122558593750, 0.0009765625000000, 0.0014648437500000, 0.0008850097656250, +0.0012512207031250, 0.0010986328125000, 0.0013122558593750, 0.0010070800781250, +0.0013732910156250, 0.0010681152343750, 0.0013732910156250, 0.0011596679687500, +0.0014038085937500, 0.0011901855468750, 0.0014343261718750, 0.0013427734375000, +0.0014648437500000, 0.0013122558593750, 0.0012512207031250, 0.0014343261718750, +0.0013732910156250, 0.0015258789062500, 0.0011596679687500, 0.0016479492187500, +0.0008850097656250, 0.0016479492187500, 0.0010681152343750, 0.0015563964843750, +0.0003967285156250, 0.0016784667968750, 0.0004577636718750, 0.0014648437500000, +0.0003662109375000, 0.0011901855468750, -0.0001831054687500, 0.0014038085937500, +0.0000610351562500, 0.0010070800781250, -0.0001831054687500, 0.0008850097656250, +-0.0003967285156250, 0.0010070800781250, -0.0001831054687500, 0.0008544921875000, +-0.0000915527343750, 0.0007934570312500, -0.0002136230468750, 0.0010986328125000, +0.0001220703125000, 0.0009765625000000, 0.0001831054687500, 0.0010681152343750, +0.0000915527343750, 0.0013427734375000, 0.0002136230468750, 0.0011596679687500, +0.0002746582031250, 0.0013122558593750, 0.0001831054687500, 0.0014038085937500, +0.0001831054687500, 0.0011596679687500, 0.0002136230468750, 0.0010986328125000, +0.0001220703125000, 0.0010986328125000, 0.0001220703125000, 0.0007324218750000, +0.0001831054687500, 0.0006408691406250, 0.0000305175781250, 0.0007934570312500, +0.0000610351562500, 0.0006103515625000, 0.0001831054687500, 0.0004882812500000, +0.0000915527343750, 0.0010986328125000, 0.0001831054687500, 0.0007934570312500, +0.0002441406250000, 0.0011901855468750, 0.0001220703125000, 0.0019226074218750, +0.0000610351562500, 0.0013732910156250, 0.0001525878906250, 0.0023498535156250, +-0.0002441406250000, 0.0023498535156250, -0.0002746582031250, 0.0022583007812500, +-0.0003967285156250, 0.0027465820312500, -0.0007324218750000, 0.0026245117187500, +-0.0006408691406250, 0.0022277832031250, -0.0006408691406250, 0.0024719238281250, +-0.0007019042968750, 0.0021057128906250, -0.0005493164062500, 0.0015563964843750, +-0.0003967285156250, 0.0019836425781250, -0.0003356933593750, 0.0010681152343750, +-0.0000915527343750, 0.0011901855468750, 0.0000610351562500, 0.0011901855468750, +0.0000915527343750, 0.0007324218750000, 0.0002136230468750, 0.0009155273437500, +0.0003051757812500, 0.0009765625000000, 0.0001831054687500, 0.0008239746093750, +0.0003356933593750, 0.0011596679687500, 0.0002746582031250, 0.0015258789062500, +0.0000915527343750, 0.0012817382812500, 0.0004272460937500, 0.0023193359375000, +0.0000915527343750, 0.0021362304687500, 0.0001220703125000, 0.0024719238281250, +0.0002746582031250, 0.0033264160156250, 0.0002136230468750, 0.0029296875000000, +0.0002441406250000, 0.0035095214843750, 0.0005493164062500, 0.0037536621093750, +0.0004577636718750, 0.0035095214843750, 0.0007019042968750, 0.0036010742187500, +0.0010070800781250, 0.0037536621093750, 0.0008239746093750, 0.0028381347656250, +0.0012512207031250, 0.0031433105468750, 0.0012207031250000, 0.0026550292968750, +0.0013427734375000, 0.0016479492187500, 0.0015869140625000, 0.0022277832031250, +0.0014953613281250, 0.0009765625000000, 0.0018005371093750, 0.0010681152343750, +0.0016784667968750, 0.0009765625000000, 0.0018615722656250, 0.0003356933593750, +0.0021972656250000, 0.0007324218750000, 0.0018615722656250, 0.0004577636718750, +0.0024108886718750, 0.0003356933593750, 0.0022888183593750, 0.0005798339843750, +0.0022583007812500, 0.0006103515625000, 0.0026245117187500, 0.0005493164062500, +0.0024414062500000, 0.0009155273437500, 0.0026245117187500, 0.0007629394531250, +0.0027465820312500, 0.0008850097656250, 0.0026245117187500, 0.0011291503906250, +0.0025634765625000, 0.0008850097656250, 0.0027160644531250, 0.0013427734375000, +0.0024108886718750, 0.0012207031250000, 0.0025024414062500, 0.0014648437500000, +0.0024108886718750, 0.0018005371093750, 0.0021972656250000, 0.0014038085937500, +0.0022888183593750, 0.0024108886718750, 0.0021057128906250, 0.0021362304687500, +0.0021057128906250, 0.0025024414062500, 0.0020751953125000, 0.0033569335937500, +0.0019836425781250, 0.0028381347656250, 0.0021057128906250, 0.0042114257812500, +0.0020446777343750, 0.0040283203125000, 0.0020446777343750, 0.0043029785156250, +0.0020141601562500, 0.0052795410156250, 0.0020141601562500, 0.0046691894531250, +0.0019836425781250, 0.0057067871093750, 0.0018005371093750, 0.0057067871093750, +0.0018920898437500, 0.0057067871093750, 0.0017395019531250, 0.0062866210937500, +0.0014953613281250, 0.0060729980468750, 0.0017395019531250, 0.0062561035156250, +0.0013732910156250, 0.0063476562500000, 0.0014648437500000, 0.0062561035156250, +0.0014648437500000, 0.0062561035156250, 0.0013427734375000, 0.0063171386718750, +0.0014953613281250, 0.0059814453125000, 0.0016174316406250, 0.0060729980468750, +0.0015258789062500, 0.0058898925781250, 0.0018005371093750, 0.0056457519531250, +0.0020141601562500, 0.0057678222656250, 0.0019531250000000, 0.0050659179687500, +0.0022888183593750, 0.0051574707031250, 0.0023498535156250, 0.0048217773437500, +0.0024108886718750, 0.0041503906250000, 0.0026245117187500, 0.0045166015625000, +0.0025329589843750, 0.0034790039062500, 0.0025939941406250, 0.0034790039062500, +0.0025939941406250, 0.0032958984375000, 0.0023803710937500, 0.0025939941406250, +0.0022888183593750, 0.0027160644531250, 0.0023498535156250, 0.0022277832031250, +0.0019226074218750, 0.0020446777343750, 0.0019531250000000, 0.0018920898437500, +0.0018005371093750, 0.0016174316406250, 0.0014953613281250, 0.0016174316406250, +0.0016174316406250, 0.0012207031250000, 0.0013427734375000, 0.0013122558593750, +0.0013122558593750, 0.0009765625000000, 0.0012817382812500, 0.0005798339843750, +0.0010986328125000, 0.0007629394531250, 0.0011901855468750, -0.0000305175781250, +0.0010070800781250, 0.0001220703125000, 0.0010375976562500, -0.0000610351562500, +0.0011901855468750, -0.0007019042968750, 0.0010681152343750, -0.0004272460937500, +0.0011291503906250, -0.0008239746093750, 0.0014953613281250, -0.0009765625000000, +0.0013427734375000, -0.0008850097656250, 0.0015869140625000, -0.0009765625000000, +0.0020141601562500, -0.0010375976562500, 0.0018615722656250, -0.0008850097656250, +0.0021972656250000, -0.0010375976562500, 0.0022888183593750, -0.0008544921875000, +0.0022277832031250, -0.0006103515625000, 0.0022888183593750, -0.0006408691406250, +0.0021972656250000, 0.0000000000000000, 0.0020141601562500, -0.0003662109375000, +0.0021362304687500, -0.0001831054687500, 0.0019836425781250, 0.0003967285156250, +0.0018005371093750, -0.0000305175781250, 0.0019836425781250, 0.0010681152343750, +0.0018005371093750, 0.0010375976562500, 0.0018615722656250, 0.0011901855468750, +0.0018920898437500, 0.0019836425781250, 0.0017700195312500, 0.0017089843750000, +0.0017700195312500, 0.0020446777343750, 0.0018005371093750, 0.0021972656250000, +0.0018615722656250, 0.0020446777343750, 0.0017395019531250, 0.0020446777343750, +0.0016479492187500, 0.0021057128906250, 0.0017089843750000, 0.0017089843750000, +0.0013122558593750, 0.0016784667968750, 0.0013122558593750, 0.0015869140625000, +0.0011596679687500, 0.0013732910156250, 0.0008239746093750, 0.0014343261718750, +0.0009765625000000, 0.0015258789062500, 0.0005798339843750, 0.0013427734375000, +0.0006103515625000, 0.0015258789062500, 0.0005187988281250, 0.0017395019531250, +0.0002746582031250, 0.0015869140625000, 0.0004577636718750, 0.0016479492187500, +0.0003967285156250, 0.0019836425781250, 0.0003051757812500, 0.0015563964843750, +0.0004882812500000, 0.0012512207031250, 0.0006103515625000, 0.0016174316406250, +0.0005493164062500, 0.0007934570312500, 0.0008850097656250, 0.0007629394531250, +0.0009460449218750, 0.0009155273437500, 0.0009155273437500, 0.0004882812500000, +0.0011596679687500, 0.0006408691406250, 0.0011901855468750, 0.0007324218750000, +0.0011596679687500, 0.0006713867187500, 0.0011291503906250, 0.0008544921875000, +0.0011596679687500, 0.0010070800781250, 0.0012207031250000, 0.0009765625000000, +0.0012817382812500, 0.0009765625000000, 0.0013427734375000, 0.0010375976562500, +0.0013732910156250, 0.0009765625000000, 0.0014038085937500, 0.0009155273437500, +0.0014343261718750, 0.0008544921875000, 0.0013732910156250, 0.0006408691406250, +0.0015258789062500, 0.0006408691406250, 0.0015258789062500, 0.0005187988281250, +0.0016479492187500, 0.0002746582031250, 0.0017395019531250, 0.0003051757812500, +0.0017089843750000, 0.0000610351562500, 0.0019226074218750, -0.0000305175781250, +0.0018310546875000, -0.0000305175781250, 0.0019531250000000, -0.0001525878906250, +0.0021362304687500, -0.0001831054687500, 0.0021057128906250, -0.0000610351562500, +0.0021667480468750, -0.0001220703125000, 0.0022583007812500, -0.0000610351562500, +0.0021667480468750, 0.0000305175781250, 0.0021362304687500, 0.0000305175781250, +0.0022888183593750, 0.0002136230468750, 0.0018310546875000, 0.0001525878906250, +0.0019226074218750, 0.0000915527343750, 0.0019226074218750, 0.0002136230468750, +0.0015869140625000, 0.0001831054687500, 0.0017089843750000, 0.0000000000000000, +0.0014648437500000, 0.0000610351562500, 0.0014953613281250, -0.0000610351562500, +0.0014953613281250, -0.0002136230468750, 0.0014038085937500, -0.0000305175781250, +0.0014038085937500, -0.0001525878906250, 0.0014343261718750, -0.0000915527343750, +0.0014343261718750, 0.0000305175781250, 0.0014038085937500, -0.0000610351562500, +0.0014343261718750, 0.0000610351562500, 0.0013732910156250, 0.0001831054687500, +0.0016479492187500, 0.0001831054687500, 0.0014953613281250, 0.0004272460937500, +0.0016479492187500, 0.0006713867187500, 0.0020141601562500, 0.0006103515625000, +0.0017395019531250, 0.0010681152343750, 0.0022277832031250, 0.0011596679687500, +0.0021972656250000, 0.0012512207031250, 0.0022277832031250, 0.0015869140625000, +0.0025329589843750, 0.0016479492187500, 0.0023498535156250, 0.0017395019531250, +0.0025024414062500, 0.0019531250000000, 0.0025634765625000, 0.0018920898437500, +0.0024108886718750, 0.0018005371093750, 0.0023498535156250, 0.0020751953125000, +0.0023803710937500, 0.0016784667968750, 0.0020751953125000, 0.0018310546875000, +0.0021972656250000, 0.0018005371093750, 0.0018920898437500, 0.0015258789062500, +0.0015258789062500}, +{0.0017700195312500, 0.0006408691406250, 0.0012512207031250, 0.0004882812500000, +0.0016174316406250, 0.0010070800781250, 0.0008850097656250, 0.0008850097656250, +0.0009460449218750, 0.0009765625000000, 0.0008850097656250, 0.0013427734375000, +0.0003967285156250, 0.0010986328125000, 0.0005798339843750, 0.0012207031250000, +0.0004577636718750, 0.0013122558593750, 0.0003051757812500, 0.0011291503906250, +0.0004577636718750, 0.0010070800781250, 0.0005187988281250, 0.0010986328125000, +0.0003967285156250, 0.0010070800781250, 0.0007629394531250, 0.0009460449218750, +0.0006103515625000, 0.0008850097656250, 0.0007629394531250, 0.0009155273437500, +0.0011291503906250, 0.0009155273437500, 0.0009155273437500, 0.0006713867187500, +0.0013122558593750, 0.0007629394531250, 0.0012817382812500, 0.0005187988281250, +0.0013427734375000, 0.0001831054687500, 0.0016174316406250, 0.0003356933593750, +0.0014953613281250, -0.0002136230468750, 0.0018615722656250, -0.0002746582031250, +0.0019836425781250, -0.0001831054687500, 0.0019531250000000, -0.0003967285156250, +0.0021362304687500, -0.0005187988281250, 0.0022277832031250, 0.0000915527343750, +0.0021362304687500, -0.0002136230468750, 0.0023193359375000, 0.0000305175781250, +0.0023498535156250, 0.0005493164062500, 0.0022583007812500, 0.0000305175781250, +0.0024108886718750, 0.0007629394531250, 0.0025024414062500, 0.0007629394531250, +0.0024719238281250, 0.0006103515625000, 0.0026245117187500, 0.0009460449218750, +0.0027160644531250, 0.0008544921875000, 0.0027465820312500, 0.0005798339843750, +0.0028686523437500, 0.0007629394531250, 0.0028686523437500, 0.0006408691406250, +0.0028076171875000, 0.0003967285156250, 0.0028381347656250, 0.0006103515625000, +0.0028381347656250, 0.0004577636718750, 0.0025634765625000, 0.0004272460937500, +0.0026855468750000, 0.0006713867187500, 0.0024719238281250, 0.0007019042968750, +0.0021667480468750, 0.0006103515625000, 0.0024108886718750, 0.0011901855468750, +0.0018920898437500, 0.0010070800781250, 0.0019226074218750, 0.0013427734375000, +0.0018310546875000, 0.0019226074218750, 0.0015869140625000, 0.0016174316406250, +0.0017089843750000, 0.0021972656250000, 0.0014038085937500, 0.0023193359375000, +0.0014648437500000, 0.0023193359375000, 0.0013732910156250, 0.0025634765625000, +0.0011596679687500, 0.0024719238281250, 0.0013427734375000, 0.0025329589843750, +0.0011596679687500, 0.0025329589843750, 0.0011291503906250, 0.0024108886718750, +0.0012207031250000, 0.0022888183593750, 0.0011596679687500, 0.0022583007812500, +0.0011291503906250, 0.0019226074218750, 0.0011291503906250, 0.0019226074218750, +0.0011596679687500, 0.0017700195312500, 0.0011901855468750, 0.0014648437500000, +0.0011291503906250, 0.0015563964843750, 0.0010681152343750, 0.0014648437500000, +0.0013732910156250, 0.0012817382812500, 0.0011291503906250, 0.0014038085937500, +0.0013427734375000, 0.0014648437500000, 0.0016479492187500, 0.0012512207031250, +0.0014343261718750, 0.0018310546875000, 0.0020446777343750, 0.0015869140625000, +0.0020141601562500, 0.0017700195312500, 0.0021362304687500, 0.0022277832031250, +0.0025939941406250, 0.0018615722656250, 0.0024108886718750, 0.0024414062500000, +0.0028076171875000, 0.0023498535156250, 0.0028686523437500, 0.0023498535156250, +0.0027465820312500, 0.0026245117187500, 0.0028381347656250, 0.0024108886718750, +0.0029602050781250, 0.0025634765625000, 0.0025939941406250, 0.0024414062500000, +0.0027465820312500, 0.0024414062500000, 0.0025329589843750, 0.0024719238281250, +0.0022583007812500, 0.0023498535156250, 0.0025329589843750, 0.0025024414062500, +0.0019836425781250, 0.0023498535156250, 0.0019836425781250, 0.0024108886718750, +0.0019531250000000, 0.0026245117187500, 0.0016479492187500, 0.0023803710937500, +0.0018005371093750, 0.0026855468750000, 0.0018920898437500, 0.0026855468750000, +0.0016784667968750, 0.0026550292968750, 0.0019226074218750, 0.0028076171875000, +0.0022583007812500, 0.0027770996093750, 0.0020751953125000, 0.0026245117187500, +0.0026245117187500, 0.0026855468750000, 0.0026550292968750, 0.0025634765625000, +0.0027160644531250, 0.0024719238281250, 0.0029907226562500, 0.0025024414062500, +0.0029296875000000, 0.0021057128906250, 0.0032348632812500, 0.0022277832031250, +0.0032043457031250, 0.0020751953125000, 0.0033264160156250, 0.0017089843750000, +0.0035705566406250, 0.0018615722656250, 0.0034790039062500, 0.0015563964843750, +0.0035095214843750, 0.0016479492187500, 0.0036926269531250, 0.0016479492187500, +0.0035400390625000, 0.0015563964843750, 0.0034179687500000, 0.0016784667968750, +0.0036315917968750, 0.0014953613281250, 0.0029296875000000, 0.0015869140625000, +0.0031433105468750, 0.0015869140625000, 0.0029296875000000, 0.0015563964843750, +0.0022888183593750, 0.0017395019531250, 0.0026855468750000, 0.0014953613281250, +0.0019836425781250, 0.0016784667968750, 0.0019531250000000, 0.0016479492187500, +0.0019531250000000, 0.0014648437500000, 0.0016174316406250, 0.0017089843750000, +0.0017700195312500, 0.0015563964843750, 0.0018310546875000, 0.0016174316406250, +0.0016174316406250, 0.0017395019531250, 0.0016174316406250, 0.0018005371093750, +0.0017395019531250, 0.0019226074218750, 0.0015563964843750, 0.0019226074218750, +0.0015563964843750, 0.0020751953125000, 0.0014953613281250, 0.0020446777343750, +0.0014648437500000, 0.0019531250000000, 0.0013427734375000, 0.0021667480468750, +0.0011291503906250, 0.0019226074218750, 0.0014343261718750, 0.0020141601562500, +0.0011596679687500, 0.0021667480468750, 0.0012817382812500, 0.0020446777343750, +0.0015869140625000, 0.0022277832031250, 0.0012207031250000, 0.0023803710937500, +0.0018310546875000, 0.0024108886718750, 0.0015869140625000, 0.0025329589843750, +0.0017395019531250, 0.0025939941406250, 0.0022277832031250, 0.0025634765625000, +0.0018005371093750, 0.0025939941406250, 0.0024108886718750, 0.0026855468750000, +0.0023498535156250, 0.0025024414062500, 0.0021362304687500, 0.0023498535156250, +0.0024108886718750, 0.0024414062500000, 0.0022583007812500, 0.0021972656250000, +0.0020751953125000, 0.0021667480468750, 0.0020141601562500, 0.0021667480468750, +0.0018615722656250, 0.0019836425781250, 0.0017395019531250, 0.0020141601562500, +0.0016784667968750, 0.0019226074218750, 0.0014648437500000, 0.0018615722656250, +0.0014953613281250, 0.0018920898437500, 0.0013732910156250, 0.0019226074218750, +0.0011901855468750, 0.0018005371093750, 0.0011596679687500, 0.0017395019531250, +0.0009765625000000, 0.0018310546875000, 0.0009765625000000, 0.0016479492187500, +0.0010986328125000, 0.0014648437500000, 0.0010070800781250, 0.0015869140625000, +0.0009765625000000, 0.0012512207031250, 0.0015258789062500, 0.0012817382812500, +0.0013732910156250, 0.0013122558593750, 0.0015563964843750, 0.0009765625000000, +0.0024108886718750, 0.0011901855468750, 0.0015869140625000, 0.0014648437500000, +0.0019531250000000, 0.0014648437500000, 0.0018005371093750, 0.0014648437500000, +0.0017089843750000, 0.0015258789062500, 0.0017700195312500, 0.0015258789062500, +0.0017395019531250, 0.0014343261718750, 0.0015869140625000, 0.0014038085937500, +0.0015869140625000, 0.0015258789062500, 0.0017700195312500, 0.0015258789062500, +0.0017395019531250, 0.0014343261718750, 0.0016784667968750, 0.0018005371093750, +0.0018615722656250, 0.0017089843750000, 0.0019531250000000, 0.0016784667968750, +0.0019531250000000, 0.0019226074218750, 0.0020446777343750, 0.0018005371093750, +0.0020751953125000, 0.0018005371093750, 0.0018005371093750, 0.0018615722656250, +0.0019226074218750, 0.0018920898437500, 0.0018615722656250, 0.0018310546875000, +0.0015869140625000, 0.0018615722656250, 0.0017395019531250, 0.0019836425781250, +0.0016174316406250, 0.0020446777343750, 0.0016479492187500, 0.0020141601562500, +0.0015563964843750, 0.0020141601562500, 0.0014953613281250, 0.0020751953125000, +0.0016479492187500, 0.0019226074218750, 0.0011596679687500, 0.0019531250000000, +0.0014343261718750, 0.0019226074218750, 0.0010681152343750, 0.0018005371093750, +0.0006103515625000, 0.0018310546875000, 0.0010681152343750, 0.0019531250000000, +0.0000610351562500, 0.0019226074218750, 0.0002441406250000, 0.0020751953125000, +0.0003967285156250, 0.0022277832031250, -0.0002136230468750, 0.0022888183593750, +0.0000610351562500, 0.0023193359375000, 0.0003356933593750, 0.0025024414062500, +0.0000915527343750, 0.0023803710937500, 0.0003662109375000, 0.0022888183593750, +0.0007629394531250, 0.0024414062500000, 0.0003967285156250, 0.0019531250000000, +0.0010986328125000, 0.0021667480468750, 0.0010986328125000, 0.0019531250000000, +0.0009460449218750, 0.0014953613281250, 0.0013427734375000, 0.0018310546875000, +0.0013732910156250, 0.0013427734375000, 0.0009765625000000, 0.0012817382812500, +0.0010986328125000, 0.0015563964843750, 0.0008544921875000, 0.0014038085937500, +0.0004272460937500, 0.0013732910156250, 0.0007629394531250, 0.0021362304687500, +0.0004272460937500, 0.0020446777343750, 0.0002441406250000, 0.0022888183593750, +0.0006408691406250, 0.0029602050781250, 0.0007629394531250, 0.0026855468750000, +0.0005798339843750, 0.0028991699218750, 0.0014648437500000, 0.0031738281250000, +0.0012817382812500, 0.0027770996093750, 0.0014953613281250, 0.0025329589843750, +0.0021057128906250, 0.0028381347656250, 0.0017089843750000, 0.0016174316406250, +0.0021972656250000, 0.0018615722656250, 0.0021362304687500, 0.0014953613281250, +0.0021667480468750, 0.0004882812500000, 0.0024414062500000, 0.0009460449218750, +0.0021667480468750, 0.0003662109375000, 0.0026245117187500, 0.0000610351562500, +0.0026245117187500, 0.0005187988281250, 0.0026550292968750, 0.0006103515625000, +0.0028686523437500, 0.0003356933593750, 0.0028076171875000, 0.0015258789062500, +0.0026245117187500, 0.0012207031250000, 0.0028381347656250, 0.0015869140625000, +0.0026550292968750, 0.0025634765625000, 0.0023498535156250, 0.0020446777343750, +0.0025939941406250, 0.0027160644531250, 0.0020141601562500, 0.0028686523437500, +0.0022583007812500, 0.0025634765625000, 0.0021667480468750, 0.0027160644531250, +0.0016784667968750, 0.0027160644531250, 0.0020751953125000, 0.0020141601562500, +0.0016784667968750, 0.0023193359375000, 0.0016784667968750, 0.0018005371093750, +0.0017395019531250, 0.0009765625000000, 0.0015869140625000, 0.0015258789062500, +0.0017089843750000, 0.0003662109375000, 0.0016479492187500, 0.0003662109375000, +0.0017089843750000, 0.0003356933593750, 0.0016784667968750, -0.0002746582031250, +0.0016784667968750, -0.0000610351562500, 0.0017700195312500, 0.0000000000000000, +0.0015563964843750, -0.0002746582031250, 0.0016784667968750, 0.0000915527343750, +0.0015563964843750, 0.0004272460937500, 0.0014343261718750, 0.0001525878906250, +0.0015258789062500, 0.0013427734375000, 0.0012207031250000, 0.0011291503906250, +0.0013732910156250, 0.0016784667968750, 0.0012512207031250, 0.0026855468750000, +0.0010070800781250, 0.0021972656250000, 0.0012207031250000, 0.0035705566406250, +0.0008239746093750, 0.0035095214843750, 0.0009765625000000, 0.0037841796875000, +0.0008850097656250, 0.0047912597656250, 0.0006713867187500, 0.0043334960937500, +0.0009460449218750, 0.0050048828125000, 0.0005493164062500, 0.0051574707031250, +0.0007629394531250, 0.0049743652343750, 0.0007019042968750, 0.0051574707031250, +0.0003662109375000, 0.0051879882812500, 0.0007019042968750, 0.0046386718750000, +0.0003051757812500}, +{0.0020446777343750, 0.0013427734375000, 0.0014648437500000, 0.0014343261718750, +0.0017700195312500, 0.0012512207031250, 0.0014038085937500, 0.0010986328125000, +0.0006408691406250, 0.0013122558593750, 0.0010986328125000, 0.0008544921875000, +0.0003356933593750, 0.0007324218750000, 0.0001831054687500, 0.0008544921875000, +0.0003662109375000, 0.0007019042968750, 0.0001831054687500, 0.0006408691406250, +0.0001220703125000, 0.0010986328125000, 0.0004577636718750, 0.0008850097656250, +0.0003356933593750, 0.0012207031250000, 0.0006103515625000, 0.0017395019531250, +0.0010681152343750, 0.0014343261718750, 0.0008544921875000, 0.0021362304687500, +0.0015563964843750, 0.0021667480468750, 0.0015869140625000, 0.0020446777343750, +0.0017089843750000, 0.0024414062500000, 0.0021362304687500, 0.0024719238281250, +0.0020446777343750, 0.0019226074218750, 0.0019836425781250, 0.0022888183593750, +0.0021972656250000, 0.0017395019531250, 0.0019531250000000, 0.0009155273437500, +0.0015869140625000, 0.0015258789062500, 0.0018310546875000, 0.0000915527343750, +0.0013732910156250, 0.0001525878906250, 0.0013427734375000, 0.0001525878906250, +0.0013122558593750, -0.0007019042968750, 0.0011291503906250, -0.0005493164062500, +0.0012207031250000, -0.0001220703125000, 0.0009460449218750, -0.0006103515625000, +0.0009460449218750, 0.0000305175781250, 0.0008544921875000, 0.0008544921875000, +0.0007019042968750, 0.0001525878906250, 0.0007629394531250, 0.0019226074218750, +0.0004882812500000, 0.0017089843750000, 0.0005187988281250, 0.0018920898437500, +0.0004577636718750, 0.0031738281250000, 0.0002746582031250, 0.0027160644531250, +0.0004577636718750, 0.0028686523437500, 0.0003356933593750, 0.0033874511718750, +0.0003051757812500, 0.0028076171875000, 0.0001831054687500, 0.0023803710937500, +0.0000915527343750, 0.0029296875000000, 0.0003051757812500, 0.0015869140625000, +0.0000915527343750, 0.0017700195312500, 0.0001831054687500, 0.0015258789062500, +0.0001525878906250, 0.0005187988281250, 0.0000610351562500, 0.0010070800781250, +0.0002746582031250, 0.0003662109375000, 0.0000305175781250, 0.0001525878906250, +0.0000915527343750, 0.0004577636718750, 0.0001831054687500, 0.0002441406250000, +0.0000915527343750, 0.0001220703125000, 0.0001220703125000, 0.0010986328125000, +0.0003051757812500, 0.0006408691406250, 0.0002441406250000, 0.0011901855468750, +0.0003356933593750, 0.0022583007812500, 0.0004882812500000, 0.0014038085937500, +0.0003967285156250, 0.0028991699218750, 0.0006713867187500, 0.0027465820312500, +0.0006103515625000, 0.0028381347656250, 0.0007629394531250, 0.0037231445312500, +0.0010375976562500, 0.0032958984375000, 0.0009460449218750, 0.0038146972656250, +0.0011291503906250, 0.0038452148437500, 0.0012817382812500, 0.0037231445312500, +0.0012817382812500, 0.0038757324218750, 0.0012817382812500, 0.0038452148437500, +0.0014038085937500, 0.0035095214843750, 0.0012207031250000, 0.0036926269531250, +0.0012512207031250, 0.0033569335937500, 0.0012817382812500, 0.0029907226562500, +0.0011291503906250, 0.0032958984375000, 0.0011596679687500, 0.0025634765625000, +0.0012512207031250, 0.0026855468750000, 0.0011901855468750, 0.0024719238281250, +0.0011901855468750, 0.0019836425781250, 0.0013122558593750, 0.0023193359375000, +0.0011901855468750, 0.0016174316406250, 0.0012817382812500, 0.0017089843750000, +0.0013427734375000, 0.0015869140625000, 0.0013122558593750, 0.0010681152343750, +0.0012512207031250, 0.0013427734375000, 0.0013427734375000, 0.0007934570312500, +0.0011596679687500, 0.0008239746093750, 0.0012207031250000, 0.0007629394531250, +0.0011596679687500, 0.0003967285156250, 0.0010070800781250, 0.0005493164062500, +0.0010681152343750, 0.0003662109375000, 0.0009460449218750, 0.0003356933593750, +0.0008850097656250, 0.0003356933593750, 0.0009460449218750, 0.0003051757812500, +0.0008850097656250, 0.0003356933593750, 0.0008239746093750, 0.0003967285156250, +0.0010375976562500, 0.0003967285156250, 0.0009460449218750, 0.0003356933593750, +0.0010070800781250, 0.0003356933593750, 0.0011291503906250, 0.0003662109375000, +0.0009765625000000, -0.0000610351562500, 0.0012817382812500, 0.0000915527343750, +0.0011291503906250, -0.0002136230468750, 0.0012512207031250, -0.0007324218750000, +0.0014953613281250, -0.0004577636718750, 0.0012207031250000, -0.0008544921875000, +0.0015869140625000, -0.0010375976562500, 0.0016174316406250, -0.0008850097656250, +0.0015258789062500, -0.0009460449218750, 0.0017395019531250, -0.0010681152343750, +0.0017700195312500, -0.0005187988281250, 0.0015563964843750, -0.0007324218750000, +0.0017395019531250, -0.0005187988281250, 0.0017089843750000, -0.0000610351562500, +0.0015563964843750, -0.0003356933593750, 0.0018005371093750, 0.0001220703125000, +0.0017395019531250, 0.0000610351562500, 0.0018615722656250, 0.0000610351562500, +0.0020446777343750, 0.0003967285156250, 0.0020446777343750, 0.0002746582031250, +0.0022277832031250, 0.0005187988281250, 0.0021972656250000, 0.0005187988281250, +0.0022888183593750, 0.0003662109375000, 0.0021972656250000, 0.0003967285156250, +0.0021667480468750, 0.0004272460937500, 0.0022583007812500, 0.0000915527343750, +0.0021362304687500, 0.0001220703125000, 0.0021362304687500, -0.0000915527343750, +0.0021667480468750, -0.0004577636718750, 0.0021362304687500, -0.0002746582031250, +0.0022277832031250, -0.0008544921875000, 0.0021057128906250, -0.0008239746093750, +0.0022277832031250, -0.0009155273437500, 0.0022277832031250, -0.0013122558593750, +0.0020751953125000, -0.0012817382812500, 0.0021362304687500, -0.0011901855468750, +0.0020751953125000, -0.0014343261718750, 0.0021057128906250, -0.0010375976562500, +0.0020751953125000, -0.0007019042968750, 0.0020141601562500, -0.0010986328125000, +0.0020751953125000, 0.0001525878906250, 0.0019531250000000, 0.0000000000000000, +0.0019531250000000, 0.0004882812500000, 0.0019226074218750, 0.0015869140625000, +0.0018005371093750, 0.0010681152343750, 0.0018920898437500, 0.0024414062500000, +0.0018310546875000, 0.0024414062500000, 0.0018920898437500, 0.0026550292968750, +0.0018310546875000, 0.0036621093750000, 0.0016784667968750, 0.0035400390625000, +0.0016174316406250, 0.0035705566406250, 0.0014038085937500, 0.0036926269531250, +0.0014648437500000, 0.0035095214843750, 0.0013427734375000, 0.0034179687500000, +0.0010986328125000, 0.0035705566406250, 0.0010986328125000, 0.0028991699218750, +0.0008850097656250, 0.0029602050781250, 0.0008544921875000, 0.0027465820312500, +0.0007934570312500, 0.0021972656250000, 0.0006408691406250, 0.0023193359375000, +0.0005493164062500, 0.0018920898437500, 0.0007629394531250, 0.0017700195312500, +0.0005493164062500, 0.0018310546875000, 0.0007019042968750, 0.0017700195312500, +0.0009765625000000, 0.0017395019531250, 0.0006408691406250, 0.0017089843750000, +0.0013122558593750, 0.0018310546875000, 0.0011596679687500, 0.0017089843750000, +0.0012207031250000, 0.0014953613281250, 0.0016479492187500, 0.0016479492187500, +0.0013122558593750, 0.0015869140625000, 0.0017395019531250, 0.0014648437500000, +0.0016174316406250, 0.0016174316406250, 0.0016784667968750, 0.0017700195312500, +0.0018920898437500, 0.0015258789062500, 0.0017089843750000, 0.0019531250000000, +0.0018005371093750, 0.0018005371093750, 0.0018005371093750, 0.0018310546875000, +0.0017700195312500, 0.0021667480468750, 0.0018310546875000, 0.0019226074218750, +0.0018005371093750, 0.0020446777343750, 0.0016479492187500, 0.0021972656250000, +0.0017089843750000, 0.0020751953125000, 0.0016174316406250, 0.0020141601562500, +0.0014038085937500, 0.0021057128906250, 0.0015258789062500, 0.0019226074218750, +0.0014038085937500, 0.0019531250000000, 0.0013122558593750, 0.0018615722656250, +0.0014343261718750, 0.0017700195312500, 0.0014953613281250, 0.0018310546875000, +0.0014343261718750, 0.0013122558593750, 0.0016174316406250, 0.0014343261718750, +0.0016174316406250, 0.0011901855468750, 0.0015258789062500, 0.0007934570312500, +0.0014953613281250, 0.0010375976562500, 0.0015258789062500, 0.0003051757812500, +0.0011291503906250, 0.0003967285156250, 0.0011596679687500, 0.0003662109375000, +0.0010986328125000, -0.0001220703125000, 0.0007934570312500, 0.0000305175781250, +0.0008544921875000, 0.0000305175781250, 0.0007019042968750, -0.0001525878906250, +0.0006713867187500, -0.0000305175781250, 0.0006408691406250, 0.0000915527343750, +0.0005798339843750, -0.0000610351562500, 0.0006103515625000, 0.0001220703125000, +0.0006713867187500, 0.0000915527343750, 0.0006713867187500, 0.0000610351562500, +0.0007934570312500, 0.0001831054687500, 0.0009765625000000, 0.0001220703125000, +0.0009460449218750, -0.0000915527343750, 0.0011291503906250, 0.0000000000000000, +0.0011901855468750, -0.0000915527343750, 0.0012512207031250, -0.0002136230468750, +0.0014038085937500, 0.0000000000000000, 0.0013732910156250, -0.0001831054687500, +0.0014648437500000, -0.0001220703125000, 0.0014648437500000, 0.0000610351562500, +0.0015258789062500, 0.0001220703125000, 0.0015869140625000, 0.0001831054687500, +0.0014648437500000, 0.0005493164062500, 0.0017395019531250, 0.0005798339843750, +0.0015563964843750, 0.0007934570312500, 0.0016784667968750, 0.0011291503906250, +0.0019226074218750, 0.0010986328125000, 0.0016174316406250, 0.0015258789062500, +0.0021667480468750, 0.0016174316406250, 0.0020446777343750, 0.0016479492187500, +0.0021362304687500, 0.0018920898437500, 0.0025024414062500, 0.0019531250000000, +0.0022583007812500, 0.0018615722656250, 0.0025939941406250, 0.0020446777343750, +0.0026245117187500, 0.0019531250000000, 0.0025634765625000, 0.0017700195312500, +0.0027160644531250, 0.0020446777343750, 0.0026550292968750, 0.0016479492187500, +0.0025939941406250, 0.0018310546875000, 0.0026245117187500, 0.0017395019531250, +0.0025939941406250, 0.0014343261718750, 0.0025634765625000, 0.0017089843750000, +0.0025634765625000, 0.0014038085937500, 0.0027160644531250, 0.0014648437500000, +0.0026550292968750, 0.0014953613281250, 0.0027465820312500, 0.0014038085937500, +0.0029907226562500, 0.0015258789062500, 0.0028076171875000, 0.0014953613281250, +0.0030517578125000, 0.0015563964843750, 0.0030517578125000, 0.0015869140625000, +0.0029602050781250, 0.0015563964843750, 0.0030822753906250, 0.0016174316406250, +0.0030822753906250, 0.0015869140625000, 0.0027160644531250, 0.0016784667968750, +0.0028686523437500, 0.0015869140625000, 0.0025329589843750, 0.0014648437500000, +0.0021057128906250, 0.0016479492187500, 0.0023803710937500, 0.0012512207031250, +0.0015258789062500, 0.0013122558593750, 0.0016784667968750, 0.0011901855468750, +0.0013732910156250, 0.0008850097656250, 0.0006408691406250, 0.0010070800781250, +0.0009765625000000, 0.0009155273437500, 0.0005187988281250, 0.0008239746093750, +0.0003051757812500, 0.0009765625000000, 0.0004882812500000, 0.0010375976562500, +0.0004577636718750, 0.0010375976562500, 0.0003051757812500, 0.0011901855468750, +0.0006713867187500, 0.0013122558593750, 0.0007019042968750, 0.0013427734375000, +0.0006103515625000, 0.0014953613281250, 0.0006713867187500, 0.0015563964843750, +0.0007324218750000, 0.0014953613281250, 0.0004577636718750, 0.0016784667968750, +0.0005493164062500, 0.0017089843750000, 0.0003967285156250, 0.0016174316406250, +0.0001525878906250, 0.0018005371093750, 0.0002136230468750, 0.0017089843750000, +0.0005187988281250, 0.0018310546875000, 0.0001831054687500, 0.0019226074218750, +0.0006103515625000}, +{0.0022888183593750, -0.0003662109375000, 0.0023193359375000, -0.0005187988281250, +0.0022583007812500, -0.0003662109375000, 0.0023193359375000, -0.0003967285156250, +0.0022888183593750, -0.0003662109375000, 0.0022583007812500, -0.0001831054687500, +0.0023803710937500, -0.0000915527343750, 0.0025024414062500, -0.0002136230468750, +0.0024414062500000, 0.0003051757812500, 0.0026245117187500, 0.0001831054687500, +0.0025939941406250, 0.0004882812500000, 0.0025939941406250, 0.0009765625000000, +0.0027160644531250, 0.0006103515625000, 0.0027465820312500, 0.0014648437500000, +0.0024719238281250, 0.0014648437500000, 0.0025939941406250, 0.0015869140625000, +0.0024414062500000, 0.0021057128906250, 0.0022277832031250, 0.0019836425781250, +0.0024719238281250, 0.0022583007812500, 0.0019836425781250, 0.0023193359375000, +0.0021362304687500, 0.0024414062500000, 0.0020446777343750, 0.0025329589843750, +0.0016784667968750, 0.0023193359375000, 0.0019836425781250, 0.0026550292968750, +0.0016174316406250, 0.0025329589843750, 0.0016479492187500, 0.0025634765625000, +0.0016174316406250, 0.0027160644531250, 0.0013427734375000, 0.0024414062500000, +0.0015258789062500, 0.0028076171875000, 0.0011901855468750, 0.0026245117187500, +0.0011901855468750, 0.0027465820312500, 0.0013122558593750, 0.0029907226562500, +0.0011596679687500, 0.0025939941406250, 0.0011291503906250, 0.0030517578125000, +0.0016174316406250, 0.0029296875000000, 0.0013427734375000, 0.0029296875000000, +0.0017700195312500, 0.0032043457031250, 0.0024108886718750, 0.0028686523437500, +0.0020446777343750, 0.0030517578125000, 0.0030822753906250, 0.0029907226562500, +0.0030822753906250, 0.0028381347656250, 0.0032348632812500, 0.0028381347656250, +0.0039367675781250, 0.0028381347656250, 0.0036010742187500, 0.0026855468750000, +0.0035400390625000, 0.0026550292968750, 0.0038146972656250, 0.0025329589843750, +0.0033264160156250, 0.0024414062500000, 0.0028381347656250, 0.0024719238281250, +0.0031433105468750, 0.0022277832031250, 0.0020141601562500, 0.0022583007812500, +0.0020751953125000, 0.0021972656250000, 0.0018005371093750, 0.0020446777343750, +0.0009765625000000, 0.0021057128906250, 0.0012512207031250, 0.0021667480468750, +0.0007934570312500, 0.0020751953125000, 0.0006103515625000, 0.0022277832031250, +0.0008239746093750, 0.0023498535156250, 0.0007019042968750, 0.0022277832031250, +0.0005798339843750, 0.0026855468750000, 0.0013122558593750, 0.0026550292968750, +0.0010986328125000, 0.0026855468750000, 0.0014038085937500, 0.0030212402343750, +0.0021057128906250, 0.0029296875000000, 0.0017395019531250, 0.0029296875000000, +0.0021667480468750, 0.0030212402343750, 0.0022583007812500, 0.0028381347656250, +0.0021667480468750, 0.0026855468750000, 0.0021972656250000, 0.0027770996093750, +0.0021667480468750, 0.0022888183593750, 0.0022888183593750, 0.0022888183593750, +0.0021362304687500, 0.0022277832031250, 0.0022888183593750, 0.0019226074218750, +0.0025024414062500, 0.0018920898437500, 0.0023803710937500, 0.0019836425781250, +0.0026855468750000, 0.0018005371093750, 0.0027160644531250, 0.0019226074218750, +0.0025939941406250, 0.0021362304687500, 0.0026855468750000, 0.0018615722656250, +0.0027770996093750, 0.0022583007812500, 0.0022888183593750, 0.0021667480468750, +0.0024719238281250, 0.0021667480468750, 0.0023193359375000, 0.0024414062500000, +0.0018920898437500, 0.0023193359375000, 0.0021667480468750, 0.0023803710937500, +0.0019531250000000, 0.0024719238281250, 0.0018310546875000, 0.0024414062500000, +0.0021362304687500, 0.0024719238281250, 0.0021972656250000, 0.0025329589843750, +0.0021362304687500, 0.0025939941406250, 0.0027465820312500, 0.0027160644531250, +0.0027160644531250, 0.0025939941406250, 0.0027160644531250, 0.0025634765625000, +0.0030212402343750, 0.0027465820312500, 0.0030212402343750, 0.0022277832031250, +0.0027465820312500, 0.0024108886718750, 0.0029602050781250, 0.0021972656250000, +0.0026550292968750, 0.0017395019531250, 0.0022888183593750, 0.0019836425781250, +0.0025939941406250, 0.0013122558593750, 0.0018920898437500, 0.0012817382812500, +0.0019531250000000, 0.0010986328125000, 0.0019226074218750, 0.0006103515625000, +0.0014953613281250, 0.0007629394531250, 0.0017700195312500, 0.0003356933593750, +0.0015869140625000, 0.0001831054687500, 0.0015258789062500, 0.0003051757812500, +0.0017089843750000, 0.0001220703125000, 0.0017089843750000, 0.0000915527343750, +0.0018310546875000, 0.0005187988281250, 0.0019836425781250, 0.0003051757812500, +0.0020751953125000, 0.0005493164062500, 0.0020446777343750, 0.0010070800781250, +0.0021057128906250, 0.0006713867187500, 0.0021667480468750, 0.0012207031250000, +0.0020141601562500, 0.0012207031250000, 0.0021057128906250, 0.0011596679687500, +0.0020751953125000, 0.0014343261718750, 0.0018920898437500, 0.0012512207031250, +0.0020141601562500, 0.0013122558593750, 0.0014953613281250, 0.0012512207031250, +0.0015563964843750, 0.0011596679687500, 0.0014953613281250, 0.0011596679687500, +0.0010070800781250, 0.0010986328125000, 0.0010986328125000, 0.0011291503906250, +0.0008850097656250, 0.0010070800781250, 0.0008850097656250, 0.0010681152343750, +0.0005798339843750, 0.0011596679687500, 0.0003051757812500, 0.0010986328125000, +0.0005187988281250, 0.0014038085937500, -0.0004272460937500, 0.0014038085937500, +-0.0003662109375000, 0.0014648437500000, -0.0003356933593750, 0.0017395019531250, +-0.0011596679687500, 0.0023803710937500, 0.0016479492187500, 0.0016174316406250, +0.0006103515625000, 0.0020141601562500, 0.0009765625000000, 0.0018005371093750, +0.0005493164062500, 0.0014343261718750, -0.0002136230468750, 0.0017089843750000, +0.0001220703125000, 0.0011596679687500, -0.0003051757812500, 0.0013732910156250, +-0.0005187988281250, 0.0013122558593750, -0.0000915527343750, 0.0008850097656250, +-0.0000610351562500, 0.0012512207031250, -0.0003662109375000, 0.0005798339843750, +0.0008850097656250, 0.0007019042968750, 0.0004272460937500, 0.0006103515625000, +0.0009765625000000, 0.0001525878906250, 0.0021667480468750, 0.0004882812500000, +0.0013732910156250, 0.0003051757812500, 0.0027465820312500, 0.0002746582031250, +0.0027465820312500, 0.0003662109375000, 0.0027160644531250, 0.0003967285156250, +0.0033264160156250, 0.0004577636718750, 0.0030212402343750, 0.0003662109375000, +0.0028381347656250, 0.0005798339843750, 0.0031433105468750, 0.0004577636718750, +0.0025939941406250, 0.0002136230468750, 0.0020141601562500, 0.0005493164062500, +0.0024108886718750, 0.0003967285156250, 0.0015258789062500, 0.0003356933593750, +0.0014648437500000, 0.0006713867187500, 0.0014648437500000, 0.0007324218750000, +0.0010375976562500, 0.0007629394531250, 0.0010681152343750, 0.0016174316406250, +0.0010070800781250, 0.0014038085937500, 0.0008850097656250, 0.0018920898437500, +0.0009765625000000, 0.0028686523437500, 0.0010375976562500, 0.0023803710937500, +0.0008544921875000, 0.0032043457031250, 0.0010375976562500, 0.0033874511718750, +0.0010681152343750, 0.0031738281250000, 0.0009765625000000, 0.0034790039062500, +0.0011291503906250, 0.0034790039062500, 0.0012207031250000, 0.0029602050781250, +0.0008239746093750, 0.0031127929687500, 0.0011291503906250, 0.0028991699218750, +0.0007629394531250, 0.0023193359375000, 0.0002441406250000, 0.0025634765625000, +0.0007019042968750, 0.0024719238281250, -0.0002746582031250, 0.0021667480468750, +-0.0002746582031250, 0.0025939941406250, -0.0003051757812500, 0.0028381347656250, +-0.0009460449218750, 0.0024719238281250, -0.0005798339843750, 0.0037536621093750, +-0.0004882812500000, 0.0034179687500000, -0.0008239746093750, 0.0038146972656250, +-0.0002746582031250, 0.0049743652343750, 0.0003356933593750, 0.0043029785156250, +-0.0000305175781250, 0.0054626464843750, 0.0009155273437500, 0.0054931640625000, +0.0008850097656250, 0.0052185058593750, 0.0010986328125000, 0.0056457519531250, +0.0017700195312500, 0.0055541992187500, 0.0015869140625000, 0.0048828125000000, +0.0019531250000000, 0.0051574707031250, 0.0020141601562500, 0.0046691894531250, +0.0020141601562500, 0.0039062500000000, 0.0020446777343750, 0.0042419433593750, +0.0020141601562500, 0.0034179687500000, 0.0018920898437500, 0.0031738281250000, +0.0018005371093750, 0.0033264160156250, 0.0018005371093750, 0.0029602050781250, +0.0017089843750000, 0.0028381347656250, 0.0015563964843750, 0.0035705566406250, +0.0017700195312500, 0.0032043457031250, 0.0016174316406250, 0.0035095214843750, +0.0017395019531250, 0.0042724609375000, 0.0020446777343750, 0.0036926269531250, +0.0017089843750000, 0.0046691894531250, 0.0021362304687500, 0.0046691894531250, +0.0021057128906250, 0.0045471191406250, 0.0019836425781250, 0.0049743652343750, +0.0021667480468750, 0.0047912597656250, 0.0021057128906250, 0.0043640136718750, +0.0020141601562500, 0.0045471191406250, 0.0021362304687500, 0.0040283203125000, +0.0020141601562500, 0.0033874511718750, 0.0018615722656250, 0.0037841796875000, +0.0020141601562500, 0.0024414062500000, 0.0016784667968750, 0.0026550292968750, +0.0016174316406250, 0.0022888183593750, 0.0015869140625000, 0.0013122558593750, +0.0013427734375000, 0.0018615722656250, 0.0012817382812500, 0.0011596679687500, +0.0013122558593750, 0.0010681152343750, 0.0011596679687500, 0.0011291503906250, +0.0010681152343750, 0.0008850097656250, 0.0010986328125000, 0.0010375976562500, +0.0008850097656250, 0.0008239746093750, 0.0009765625000000, 0.0008850097656250, +0.0009155273437500, 0.0008850097656250, 0.0008239746093750, 0.0007019042968750, +0.0008850097656250, 0.0008239746093750, 0.0007629394531250, 0.0007629394531250, +0.0008544921875000, 0.0007019042968750, 0.0008850097656250, 0.0007629394531250, +0.0008850097656250, 0.0007934570312500, 0.0009460449218750, 0.0007324218750000, +0.0010375976562500, 0.0007629394531250, 0.0010070800781250, 0.0007629394531250, +0.0011291503906250, 0.0007324218750000, 0.0011291503906250, 0.0006408691406250, +0.0010986328125000, 0.0006408691406250, 0.0012207031250000, 0.0005493164062500, +0.0011901855468750, 0.0004882812500000, 0.0012207031250000, 0.0005493164062500, +0.0013732910156250, 0.0006103515625000, 0.0013122558593750, 0.0005493164062500, +0.0013427734375000, 0.0008239746093750, 0.0014953613281250, 0.0007629394531250, +0.0015869140625000, 0.0008544921875000, 0.0015869140625000, 0.0010986328125000, +0.0017395019531250, 0.0009765625000000, 0.0017700195312500, 0.0012817382812500, +0.0017089843750000, 0.0012817382812500, 0.0018920898437500, 0.0013427734375000, +0.0018615722656250, 0.0015869140625000, 0.0017700195312500, 0.0015258789062500, +0.0019226074218750, 0.0016174316406250, 0.0016479492187500, 0.0016784667968750, +0.0018005371093750, 0.0016784667968750, 0.0017089843750000, 0.0017089843750000, +0.0014343261718750, 0.0017089843750000, 0.0017089843750000, 0.0019226074218750, +0.0012512207031250, 0.0018310546875000, 0.0014038085937500, 0.0019836425781250, +0.0012207031250000, 0.0022888183593750, 0.0008544921875000, 0.0021667480468750, +0.0012207031250000, 0.0025024414062500, 0.0007019042968750, 0.0025939941406250, +0.0008239746093750, 0.0025024414062500, 0.0009460449218750, 0.0025939941406250, +0.0007629394531250, 0.0026550292968750, 0.0009765625000000, 0.0023498535156250, +0.0011291503906250, 0.0023498535156250, 0.0010681152343750, 0.0021972656250000, +0.0013427734375000, 0.0019836425781250, 0.0015563964843750, 0.0020141601562500, +0.0014953613281250}, +{0.0015258789062500, 0.0014953613281250, 0.0016479492187500, 0.0024108886718750, +0.0014038085937500, 0.0020751953125000, 0.0015869140625000, 0.0025634765625000, +0.0014648437500000, 0.0035400390625000, 0.0012512207031250, 0.0030212402343750, +0.0014648437500000, 0.0041198730468750, 0.0011901855468750, 0.0042419433593750, +0.0010986328125000, 0.0042419433593750, 0.0011901855468750, 0.0048217773437500, +0.0010070800781250, 0.0047302246093750, 0.0010986328125000, 0.0045166015625000, +0.0013427734375000, 0.0049133300781250, 0.0011596679687500, 0.0046386718750000, +0.0012512207031250, 0.0041809082031250, 0.0015563964843750, 0.0046081542968750, +0.0013427734375000, 0.0036010742187500, 0.0014953613281250, 0.0037841796875000, +0.0015258789062500, 0.0035705566406250, 0.0014343261718750, 0.0028381347656250, +0.0014038085937500, 0.0032043457031250, 0.0014648437500000, 0.0025024414062500, +0.0012817382812500, 0.0024719238281250, 0.0013427734375000, 0.0023498535156250, +0.0012817382812500, 0.0019531250000000, 0.0010681152343750, 0.0020446777343750, +0.0011291503906250, 0.0015869140625000, 0.0010070800781250, 0.0015869140625000, +0.0009765625000000, 0.0013732910156250, 0.0009155273437500, 0.0010070800781250, +0.0008850097656250, 0.0010681152343750, 0.0008850097656250, 0.0009155273437500, +0.0008239746093750, 0.0007324218750000, 0.0008850097656250, 0.0008544921875000, +0.0008239746093750, 0.0009155273437500, 0.0006408691406250, 0.0007324218750000, +0.0007324218750000, 0.0011596679687500, 0.0005798339843750, 0.0010986328125000, +0.0006103515625000, 0.0011901855468750, 0.0006103515625000, 0.0014953613281250, +0.0004882812500000, 0.0013122558593750, 0.0006103515625000, 0.0015258789062500, +0.0005187988281250, 0.0015869140625000, 0.0005187988281250, 0.0014953613281250, +0.0005798339843750, 0.0014953613281250, 0.0006408691406250, 0.0014953613281250, +0.0006103515625000, 0.0012512207031250, 0.0009155273437500, 0.0012817382812500, +0.0009155273437500, 0.0012512207031250, 0.0010070800781250, 0.0010681152343750, +0.0011596679687500, 0.0011291503906250, 0.0011291503906250, 0.0011596679687500, +0.0012817382812500, 0.0010375976562500, 0.0013427734375000, 0.0012512207031250, +0.0013122558593750, 0.0014343261718750, 0.0012817382812500, 0.0012817382812500, +0.0013427734375000, 0.0017089843750000, 0.0013427734375000, 0.0017089843750000, +0.0013427734375000, 0.0017700195312500, 0.0014343261718750, 0.0021972656250000, +0.0014343261718750, 0.0021362304687500, 0.0014038085937500, 0.0023193359375000, +0.0016479492187500, 0.0024414062500000, 0.0016174316406250, 0.0023498535156250, +0.0017089843750000, 0.0023803710937500, 0.0018310546875000, 0.0024719238281250, +0.0017700195312500, 0.0022583007812500, 0.0019226074218750, 0.0022277832031250, +0.0019226074218750, 0.0022888183593750, 0.0018615722656250, 0.0020751953125000, +0.0018615722656250, 0.0021057128906250, 0.0018920898437500, 0.0023803710937500, +0.0014648437500000, 0.0021362304687500, 0.0016784667968750, 0.0023803710937500, +0.0014343261718750, 0.0027160644531250, 0.0009460449218750, 0.0023193359375000, +0.0013122558593750, 0.0030212402343750, 0.0006408691406250, 0.0028991699218750, +0.0007629394531250, 0.0029602050781250, 0.0007324218750000, 0.0034179687500000, +0.0003356933593750, 0.0031738281250000, 0.0006103515625000, 0.0033569335937500, +0.0003051757812500, 0.0034484863281250, 0.0004272460937500, 0.0033264160156250, +0.0006408691406250, 0.0032348632812500, 0.0004882812500000, 0.0032348632812500, +0.0007019042968750, 0.0032043457031250, 0.0009765625000000, 0.0029907226562500, +0.0008239746093750, 0.0030517578125000, 0.0012817382812500, 0.0032348632812500, +0.0017395019531250, 0.0029907226562500, 0.0013122558593750, 0.0034179687500000, +0.0023498535156250, 0.0034484863281250, 0.0021362304687500, 0.0032653808593750, +0.0022277832031250, 0.0034484863281250, 0.0029602050781250, 0.0034790039062500, +0.0024719238281250, 0.0029907226562500, 0.0026550292968750, 0.0032043457031250, +0.0028076171875000, 0.0028686523437500, 0.0026245117187500, 0.0024108886718750, +0.0025024414062500, 0.0027770996093750, 0.0025024414062500, 0.0019226074218750, +0.0021362304687500, 0.0019531250000000, 0.0021972656250000, 0.0017700195312500, +0.0019531250000000, 0.0012817382812500, 0.0016479492187500, 0.0015563964843750, +0.0018310546875000, 0.0010375976562500, 0.0013122558593750, 0.0010986328125000, +0.0013427734375000, 0.0010681152343750, 0.0012817382812500, 0.0007324218750000, +0.0010375976562500, 0.0008544921875000, 0.0011291503906250, 0.0008850097656250, +0.0010986328125000, 0.0007324218750000, 0.0010681152343750, 0.0007019042968750, +0.0011596679687500, 0.0010070800781250, 0.0011901855468750, 0.0012817382812500, +0.0011901855468750, 0.0009155273437500, 0.0015563964843750, 0.0012207031250000, +0.0014038085937500, 0.0009765625000000, 0.0015563964843750, 0.0005493164062500, +0.0018310546875000, 0.0010375976562500, 0.0015563964843750, -0.0001220703125000, +0.0020751953125000, 0.0000915527343750, 0.0020141601562500, -0.0002746582031250, +0.0021362304687500, -0.0011596679687500, 0.0024414062500000, -0.0005798339843750, +0.0021667480468750, -0.0014343261718750, 0.0024108886718750, -0.0015258789062500, +0.0023498535156250, -0.0011596679687500, 0.0022583007812500, -0.0014038085937500, +0.0022888183593750, -0.0016174316406250, 0.0021362304687500, -0.0004577636718750, +0.0021972656250000, -0.0010375976562500, 0.0020751953125000, -0.0003967285156250, +0.0020446777343750, 0.0007934570312500, 0.0020446777343750, -0.0001831054687500, +0.0018920898437500, 0.0017089843750000, 0.0020141601562500, 0.0016784667968750, +0.0017700195312500, 0.0017700195312500, 0.0019226074218750, 0.0029602050781250, +0.0021667480468750, 0.0025024414062500, 0.0019226074218750, 0.0027770996093750, +0.0021972656250000, 0.0030517578125000, 0.0021667480468750, 0.0028076171875000, +0.0021362304687500, 0.0027465820312500, 0.0022583007812500, 0.0029907226562500, +0.0021362304687500, 0.0021057128906250, 0.0021057128906250, 0.0023803710937500, +0.0021667480468750, 0.0020751953125000, 0.0020751953125000, 0.0013427734375000, +0.0019531250000000, 0.0018920898437500, 0.0019531250000000, 0.0013427734375000, +0.0019836425781250, 0.0012512207031250, 0.0018310546875000, 0.0015869140625000, +0.0019226074218750, 0.0015258789062500, 0.0019836425781250, 0.0014343261718750, +0.0018920898437500, 0.0020751953125000, 0.0019836425781250, 0.0019531250000000, +0.0020446777343750, 0.0021362304687500, 0.0019836425781250, 0.0026855468750000, +0.0019836425781250, 0.0023803710937500, 0.0019836425781250, 0.0026550292968750, +0.0018615722656250, 0.0027770996093750, 0.0019531250000000, 0.0025329589843750, +0.0018920898437500, 0.0024719238281250, 0.0018005371093750, 0.0025634765625000, +0.0018005371093750, 0.0019836425781250, 0.0015258789062500, 0.0020446777343750, +0.0015869140625000, 0.0019226074218750, 0.0014343261718750, 0.0016174316406250, +0.0011596679687500, 0.0017089843750000, 0.0013427734375000, 0.0014038085937500, +0.0010375976562500, 0.0014648437500000, 0.0010375976562500, 0.0014038085937500, +0.0010986328125000, 0.0012207031250000, 0.0010375976562500, 0.0014038085937500, +0.0010375976562500, 0.0009765625000000, 0.0012207031250000, 0.0010986328125000, +0.0011291503906250, 0.0010681152343750, 0.0012817382812500, 0.0008544921875000, +0.0014343261718750, 0.0010681152343750, 0.0012512207031250, 0.0007019042968750, +0.0017700195312500, 0.0008239746093750, 0.0015563964843750, 0.0008239746093750, +0.0018615722656250, 0.0007019042968750, 0.0023193359375000, 0.0008850097656250, +0.0019531250000000, 0.0007019042968750, 0.0030212402343750, 0.0008239746093750, +0.0027770996093750, 0.0008239746093750, 0.0031127929687500, 0.0006103515625000, +0.0039978027343750, 0.0008544921875000, 0.0035095214843750, 0.0005798339843750, +0.0045471191406250, 0.0006408691406250, 0.0046081542968750, 0.0006408691406250, +0.0044555664062500, 0.0004882812500000, 0.0048828125000000, 0.0006713867187500, +0.0048828125000000, 0.0004577636718750, 0.0043640136718750, 0.0005798339843750, +0.0046386718750000, 0.0005187988281250, 0.0040588378906250, 0.0003051757812500, +0.0034484863281250, 0.0004577636718750, 0.0038757324218750, 0.0003356933593750, +0.0024414062500000, 0.0001831054687500, 0.0024719238281250, 0.0003967285156250, +0.0021667480468750, 0.0004272460937500, 0.0012207031250000, 0.0002441406250000, +0.0015563964843750, 0.0007324218750000, 0.0010070800781250, 0.0005493164062500, +0.0007629394531250, 0.0006408691406250, 0.0009765625000000, 0.0010070800781250, +0.0009460449218750, 0.0007019042968750, 0.0008239746093750, 0.0011291503906250, +0.0016174316406250, 0.0010681152343750, 0.0014343261718750, 0.0009765625000000, +0.0018310546875000, 0.0012207031250000, 0.0025634765625000, 0.0010986328125000, +0.0021972656250000, 0.0011291503906250, 0.0031738281250000, 0.0011291503906250, +0.0031738281250000, 0.0010375976562500, 0.0032653808593750, 0.0010375976562500, +0.0038757324218750, 0.0010681152343750, 0.0036926269531250, 0.0010986328125000, +0.0038146972656250, 0.0010375976562500, 0.0040588378906250, 0.0011596679687500, +0.0036926269531250, 0.0011901855468750, 0.0034484863281250, 0.0011291503906250, +0.0037231445312500, 0.0015258789062500, 0.0029296875000000, 0.0014343261718750, +0.0029296875000000, 0.0014953613281250, 0.0028686523437500, 0.0018005371093750, +0.0023803710937500, 0.0016174316406250, 0.0025329589843750, 0.0018920898437500, +0.0022888183593750, 0.0018920898437500, 0.0022888183593750, 0.0018615722656250, +0.0022583007812500, 0.0019836425781250, 0.0021667480468750, 0.0019226074218750, +0.0022277832031250, 0.0019836425781250, 0.0020751953125000, 0.0019836425781250, +0.0020751953125000, 0.0019836425781250, 0.0020446777343750, 0.0019836425781250, +0.0019836425781250, 0.0019836425781250, 0.0019531250000000, 0.0020446777343750, +0.0018920898437500, 0.0019836425781250, 0.0018615722656250, 0.0019836425781250, +0.0018920898437500, 0.0020141601562500, 0.0018005371093750, 0.0018920898437500, +0.0018005371093750, 0.0018005371093750, 0.0018005371093750, 0.0018310546875000, +0.0016784667968750, 0.0016784667968750, 0.0017395019531250, 0.0014953613281250, +0.0018005371093750, 0.0015563964843750, 0.0016784667968750, 0.0011291503906250, +0.0016479492187500, 0.0010375976562500, 0.0016479492187500, 0.0009765625000000, +0.0015258789062500, 0.0006713867187500, 0.0014343261718750, 0.0006408691406250, +0.0014648437500000, 0.0005798339843750, 0.0014648437500000, 0.0003967285156250, +0.0013732910156250, 0.0004882812500000, 0.0015563964843750, 0.0005493164062500, +0.0017089843750000, 0.0003356933593750, 0.0016174316406250, 0.0008544921875000, +0.0021362304687500, 0.0006713867187500, 0.0021972656250000, 0.0008239746093750, +0.0022277832031250, 0.0013122558593750, 0.0025634765625000, 0.0010070800781250, +0.0025939941406250, 0.0015869140625000, 0.0023803710937500, 0.0016479492187500, +0.0026550292968750, 0.0016479492187500, 0.0023803710937500, 0.0018310546875000, +0.0019531250000000, 0.0018005371093750, 0.0022583007812500, 0.0016784667968750, +0.0015563964843750, 0.0017089843750000, 0.0016174316406250, 0.0016174316406250, +0.0016479492187500, 0.0014343261718750, 0.0012817382812500, 0.0014648437500000, +0.0014038085937500, 0.0014038085937500, 0.0011901855468750, 0.0012207031250000, +0.0011596679687500}, +{0.0006713867187500, -0.0003967285156250, 0.0003051757812500, -0.0003051757812500, +0.0009155273437500, -0.0003662109375000, 0.0018005371093750, -0.0002441406250000, +0.0012817382812500, -0.0003051757812500, 0.0028381347656250, -0.0003051757812500, +0.0028686523437500, -0.0001220703125000, 0.0031433105468750, -0.0001220703125000, +0.0042114257812500, -0.0002441406250000, 0.0039672851562500, 0.0000915527343750, +0.0043029785156250, 0.0000305175781250, 0.0046081542968750, 0.0001525878906250, +0.0042724609375000, 0.0004577636718750, 0.0041503906250000, 0.0003356933593750, +0.0043945312500000, 0.0007019042968750, 0.0034179687500000, 0.0006713867187500, +0.0036926269531250, 0.0006713867187500, 0.0033264160156250, 0.0009460449218750, +0.0024719238281250, 0.0009460449218750, 0.0028991699218750, 0.0008850097656250, +0.0019226074218750, 0.0010070800781250, 0.0019531250000000, 0.0008850097656250, +0.0018615722656250, 0.0007324218750000, 0.0013427734375000, 0.0008850097656250, +0.0014953613281250, 0.0006713867187500, 0.0015869140625000, 0.0006713867187500, +0.0014648437500000, 0.0007629394531250, 0.0016784667968750, 0.0006103515625000, +0.0019531250000000, 0.0005798339843750, 0.0018310546875000, 0.0007629394531250, +0.0021057128906250, 0.0006408691406250, 0.0021972656250000, 0.0007629394531250, +0.0020141601562500, 0.0009155273437500, 0.0019836425781250, 0.0007019042968750, +0.0020751953125000, 0.0010986328125000, 0.0018310546875000, 0.0009765625000000, +0.0018005371093750, 0.0010681152343750, 0.0017700195312500, 0.0013122558593750, +0.0016479492187500, 0.0010681152343750, 0.0016784667968750, 0.0014953613281250, +0.0016174316406250, 0.0014038085937500, 0.0015869140625000, 0.0014343261718750, +0.0016174316406250, 0.0017395019531250, 0.0016784667968750, 0.0015258789062500, +0.0016174316406250, 0.0016174316406250, 0.0018310546875000, 0.0016174316406250, +0.0017700195312500, 0.0014953613281250, 0.0018005371093750, 0.0014343261718750, +0.0018920898437500, 0.0014038085937500, 0.0019226074218750, 0.0013427734375000, +0.0019226074218750, 0.0011291503906250, 0.0018615722656250, 0.0012512207031250, +0.0019226074218750, 0.0012817382812500, 0.0019531250000000, 0.0010375976562500, +0.0018920898437500, 0.0014038085937500, 0.0019836425781250, 0.0012512207031250, +0.0020141601562500, 0.0012207031250000, 0.0018920898437500, 0.0014038085937500, +0.0018920898437500, 0.0010986328125000, 0.0019531250000000, 0.0012512207031250, +0.0015563964843750, 0.0011291503906250, 0.0016784667968750, 0.0010681152343750, +0.0015563964843750, 0.0011291503906250, 0.0011596679687500, 0.0008850097656250, +0.0012817382812500, 0.0007934570312500, 0.0013122558593750, 0.0007324218750000, +0.0010986328125000, 0.0006103515625000, 0.0013122558593750, 0.0004577636718750, +0.0015869140625000, 0.0003356933593750, 0.0014038085937500, 0.0004577636718750, +0.0018615722656250, 0.0001525878906250, 0.0018920898437500, 0.0003967285156250, +0.0019531250000000, 0.0007324218750000, 0.0021972656250000, 0.0003662109375000, +0.0021057128906250, 0.0014038085937500, 0.0021972656250000, 0.0012207031250000, +0.0022277832031250, 0.0016479492187500, 0.0020751953125000, 0.0025024414062500, +0.0020141601562500, 0.0019836425781250, 0.0021362304687500, 0.0027770996093750, +0.0020751953125000, 0.0028991699218750, 0.0019226074218750, 0.0027465820312500, +0.0021667480468750, 0.0030517578125000, 0.0023193359375000, 0.0030212402343750, +0.0021362304687500, 0.0026855468750000, 0.0026550292968750, 0.0029296875000000, +0.0026855468750000, 0.0026550292968750, 0.0025024414062500, 0.0022277832031250, +0.0027770996093750, 0.0025634765625000, 0.0028991699218750, 0.0018005371093750, +0.0020446777343750, 0.0019226074218750, 0.0023803710937500, 0.0017700195312500, +0.0020141601562500, 0.0012817382812500, 0.0012207031250000, 0.0015563964843750, +0.0017089843750000, 0.0012207031250000, 0.0006713867187500, 0.0012207031250000, +0.0007934570312500, 0.0013122558593750, 0.0006103515625000, 0.0011901855468750, +-0.0004577636718750, 0.0021972656250000, 0.0027770996093750, 0.0020141601562500, +0.0031433105468750, 0.0021057128906250, 0.0036010742187500, 0.0020141601562500, +0.0029296875000000, 0.0018615722656250, 0.0025634765625000, 0.0019226074218750, +0.0031127929687500, 0.0015869140625000, 0.0014038085937500, 0.0015563964843750, +0.0017395019531250, 0.0016174316406250, 0.0014343261718750, 0.0013732910156250, +0.0001220703125000, 0.0013427734375000, 0.0007324218750000, 0.0018005371093750, +0.0000000000000000, 0.0015258789062500, -0.0001831054687500, 0.0020141601562500, +0.0000000000000000, 0.0026550292968750, -0.0002136230468750, 0.0021972656250000, +-0.0002746582031250, 0.0034179687500000, 0.0001831054687500, 0.0032958984375000, +0.0000000000000000, 0.0033874511718750, 0.0003662109375000, 0.0040893554687500, +0.0008850097656250, 0.0037536621093750, 0.0003967285156250, 0.0040283203125000, +0.0013122558593750, 0.0039978027343750, 0.0014343261718750, 0.0036926269531250, +0.0012817382812500, 0.0036926269531250, 0.0016479492187500, 0.0035705566406250, +0.0017089843750000, 0.0031738281250000, 0.0011901855468750, 0.0031127929687500, +0.0014038085937500, 0.0028686523437500, 0.0012817382812500, 0.0025329589843750, +0.0007629394531250, 0.0025329589843750, 0.0009765625000000, 0.0024414062500000, +0.0013122558593750, 0.0022583007812500, 0.0010375976562500, 0.0023498535156250, +0.0015258789062500, 0.0024414062500000, 0.0021667480468750, 0.0022583007812500, +0.0017395019531250, 0.0025634765625000, 0.0025634765625000, 0.0024108886718750, +0.0025024414062500, 0.0024108886718750, 0.0025329589843750, 0.0025939941406250, +0.0028991699218750, 0.0022583007812500, 0.0025634765625000, 0.0021667480468750, +0.0025939941406250, 0.0022277832031250, 0.0026855468750000, 0.0018615722656250, +0.0022888183593750, 0.0014953613281250, 0.0019531250000000, 0.0016174316406250, +0.0020751953125000, 0.0010070800781250, 0.0012512207031250, 0.0009765625000000, +0.0012512207031250, 0.0010070800781250, 0.0009765625000000, 0.0006713867187500, +0.0003662109375000, 0.0007324218750000, 0.0005187988281250, 0.0012817382812500, +0.0002136230468750, 0.0009155273437500, -0.0000915527343750, 0.0014038085937500, +0.0000915527343750, 0.0022583007812500, 0.0001525878906250, 0.0017395019531250, +-0.0001220703125000, 0.0029296875000000, 0.0002746582031250, 0.0028991699218750, +0.0000305175781250, 0.0029602050781250, 0.0000305175781250, 0.0036315917968750, +0.0002441406250000, 0.0032653808593750, 0.0000305175781250, 0.0033874511718750, +-0.0001831054687500, 0.0035705566406250, -0.0000610351562500, 0.0032348632812500, +-0.0003662109375000, 0.0029602050781250, -0.0007324218750000, 0.0032043457031250, +-0.0004882812500000, 0.0024108886718750, -0.0008850097656250, 0.0025024414062500, +-0.0010375976562500, 0.0023498535156250, -0.0009460449218750, 0.0017395019531250, +-0.0010681152343750, 0.0020751953125000, -0.0011596679687500, 0.0014953613281250, +-0.0008544921875000, 0.0014648437500000, -0.0010070800781250, 0.0013427734375000, +-0.0009460449218750, 0.0010375976562500, -0.0006713867187500, 0.0010681152343750, +-0.0008850097656250, 0.0007324218750000, -0.0005798339843750, 0.0007324218750000, +-0.0006408691406250, 0.0005493164062500, -0.0006408691406250, 0.0002441406250000, +-0.0004882812500000, 0.0004882812500000, -0.0007019042968750, -0.0000610351562500, +-0.0004882812500000, -0.0000305175781250, -0.0006408691406250, -0.0001525878906250, +-0.0005798339843750, -0.0005493164062500, -0.0003967285156250, -0.0003051757812500, +-0.0006103515625000, -0.0006103515625000, -0.0001831054687500, -0.0007629394531250, +-0.0002746582031250, -0.0004577636718750, -0.0002136230468750, -0.0004882812500000, +0.0000915527343750, -0.0006713867187500, -0.0000305175781250, 0.0003356933593750, +0.0003967285156250, 0.0000610351562500, 0.0003051757812500, 0.0004882812500000, +0.0004272460937500, 0.0013732910156250, 0.0007934570312500, 0.0008544921875000, +0.0006713867187500, 0.0018615722656250, 0.0010375976562500, 0.0019226074218750, +0.0010375976562500, 0.0019531250000000, 0.0011596679687500, 0.0025024414062500, +0.0014038085937500, 0.0022277832031250, 0.0012512207031250, 0.0024719238281250, +0.0016174316406250, 0.0025939941406250, 0.0015869140625000, 0.0023498535156250, +0.0016174316406250, 0.0022888183593750, 0.0018615722656250, 0.0023498535156250, +0.0017700195312500, 0.0018920898437500, 0.0018615722656250, 0.0019836425781250, +0.0018615722656250, 0.0017700195312500, 0.0018005371093750, 0.0013732910156250, +0.0018005371093750, 0.0016479492187500, 0.0017395019531250, 0.0012817382812500, +0.0017089843750000, 0.0012207031250000, 0.0016479492187500, 0.0012512207031250, +0.0016174316406250, 0.0010986328125000, 0.0016174316406250, 0.0011596679687500, +0.0015258789062500, 0.0013122558593750, 0.0015869140625000, 0.0012817382812500, +0.0015563964843750, 0.0013427734375000, 0.0014648437500000, 0.0014343261718750, +0.0014648437500000, 0.0013427734375000, 0.0014648437500000, 0.0014038085937500, +0.0014038085937500, 0.0013732910156250, 0.0013732910156250, 0.0014038085937500, +0.0012817382812500, 0.0013122558593750, 0.0012207031250000, 0.0011901855468750, +0.0012512207031250, 0.0013122558593750, 0.0010986328125000, 0.0011901855468750, +0.0011291503906250, 0.0012207031250000, 0.0010070800781250, 0.0013122558593750, +0.0007934570312500, 0.0011291503906250, 0.0009765625000000, 0.0013122558593750, +0.0006408691406250, 0.0013122558593750, 0.0006103515625000, 0.0011901855468750, +0.0005493164062500, 0.0013122558593750, 0.0003051757812500, 0.0012512207031250, +0.0004577636718750, 0.0010070800781250, 0.0003967285156250, 0.0011596679687500, +0.0004272460937500, 0.0008850097656250, 0.0004882812500000, 0.0006408691406250, +0.0005187988281250, 0.0009155273437500, 0.0005798339843750, 0.0002441406250000, +0.0007019042968750, 0.0003662109375000, 0.0007324218750000, 0.0002441406250000, +0.0009155273437500, -0.0001525878906250, 0.0011291503906250, 0.0000915527343750, +0.0011596679687500, -0.0002746582031250, 0.0016174316406250, -0.0002441406250000, +0.0015869140625000, -0.0001525878906250, 0.0018310546875000, -0.0002746582031250, +0.0021972656250000, -0.0001525878906250, 0.0020141601562500, -0.0000305175781250, +0.0023803710937500, -0.0000305175781250, 0.0023803710937500, 0.0000000000000000, +0.0021057128906250, 0.0000610351562500, 0.0021057128906250, 0.0001525878906250, +0.0021667480468750, 0.0000915527343750, 0.0015563964843750, 0.0000610351562500, +0.0017395019531250, 0.0000305175781250, 0.0014343261718750, -0.0000915527343750, +0.0008239746093750, -0.0001525878906250, 0.0012512207031250, 0.0000000000000000, +0.0004882812500000, -0.0002746582031250, 0.0004882812500000, -0.0000915527343750, +0.0005187988281250, 0.0000915527343750, 0.0000610351562500, -0.0001525878906250, +0.0001525878906250, 0.0005187988281250, 0.0003051757812500, 0.0003356933593750, +0.0000000000000000, 0.0004882812500000, 0.0003662109375000, 0.0010375976562500, +0.0006713867187500, 0.0007324218750000, 0.0003356933593750, 0.0012207031250000, +0.0011901855468750, 0.0012207031250000, 0.0010070800781250, 0.0011291503906250, +0.0012207031250000, 0.0013427734375000, 0.0019226074218750, 0.0013732910156250, +0.0015563964843750, 0.0015869140625000, 0.0023803710937500, 0.0016479492187500, +0.0024108886718750, 0.0018615722656250, 0.0024108886718750, 0.0023193359375000, +0.0029296875000000}, +{0.0022888183593750, 0.0010681152343750, 0.0020751953125000, 0.0009155273437500, +0.0021667480468750, 0.0014343261718750, 0.0020141601562500, 0.0013427734375000, +0.0019531250000000, 0.0016174316406250, 0.0019531250000000, 0.0021972656250000, +0.0018005371093750, 0.0018615722656250, 0.0018615722656250, 0.0025024414062500, +0.0018310546875000, 0.0025634765625000, 0.0017700195312500, 0.0025024414062500, +0.0018920898437500, 0.0027465820312500, 0.0018920898437500, 0.0026855468750000, +0.0017700195312500, 0.0024414062500000, 0.0018310546875000, 0.0025024414062500, +0.0018005371093750, 0.0023803710937500, 0.0018005371093750, 0.0020751953125000, +0.0018005371093750, 0.0020751953125000, 0.0016174316406250, 0.0021057128906250, +0.0018615722656250, 0.0018920898437500, 0.0017700195312500, 0.0019836425781250, +0.0018310546875000, 0.0021362304687500, 0.0020141601562500, 0.0019531250000000, +0.0018005371093750, 0.0023498535156250, 0.0020446777343750, 0.0023498535156250, +0.0019226074218750, 0.0023498535156250, 0.0018920898437500, 0.0025939941406250, +0.0019836425781250, 0.0025024414062500, 0.0018615722656250, 0.0025634765625000, +0.0019531250000000, 0.0026550292968750, 0.0018615722656250, 0.0025329589843750, +0.0018310546875000, 0.0024108886718750, 0.0019531250000000, 0.0025634765625000, +0.0018615722656250, 0.0021972656250000, 0.0019531250000000, 0.0023193359375000, +0.0019836425781250, 0.0022277832031250, 0.0018310546875000, 0.0019531250000000, +0.0018920898437500, 0.0021972656250000, 0.0019226074218750, 0.0019226074218750, +0.0015563964843750, 0.0020141601562500, 0.0016174316406250, 0.0020446777343750, +0.0014648437500000, 0.0019226074218750, 0.0011901855468750, 0.0020751953125000, +0.0012512207031250, 0.0018920898437500, 0.0008544921875000, 0.0019226074218750, +0.0008544921875000, 0.0019531250000000, 0.0007629394531250, 0.0018310546875000, +0.0005187988281250, 0.0018920898437500, 0.0006103515625000, 0.0018920898437500, +0.0003051757812500, 0.0017700195312500, 0.0003967285156250, 0.0018920898437500, +0.0003967285156250, 0.0020141601562500, 0.0001525878906250, 0.0018920898437500, +0.0003662109375000, 0.0023498535156250, 0.0004272460937500, 0.0021667480468750, +0.0003662109375000, 0.0022888183593750, 0.0006408691406250, 0.0027465820312500, +0.0008544921875000, 0.0025024414062500, 0.0006713867187500, 0.0029602050781250, +0.0012817382812500, 0.0029296875000000, 0.0011291503906250, 0.0028991699218750, +0.0012207031250000, 0.0030822753906250, 0.0016174316406250, 0.0028991699218750, +0.0013122558593750, 0.0030212402343750, 0.0016174316406250, 0.0029602050781250, +0.0015258789062500, 0.0027160644531250, 0.0015563964843750, 0.0026855468750000, +0.0017089843750000, 0.0026245117187500, 0.0014343261718750, 0.0020141601562500, +0.0017089843750000, 0.0021362304687500, 0.0015563964843750, 0.0018615722656250, +0.0014648437500000, 0.0012817382812500, 0.0016784667968750, 0.0014953613281250, +0.0013732910156250, 0.0010070800781250, 0.0014648437500000, 0.0010986328125000, +0.0013427734375000, 0.0008850097656250, 0.0012817382812500, 0.0005187988281250, +0.0013427734375000, 0.0008850097656250, 0.0011596679687500, 0.0001525878906250, +0.0012207031250000, 0.0003051757812500, 0.0011901855468750, 0.0003356933593750, +0.0010986328125000, -0.0000305175781250, 0.0010681152343750, 0.0003662109375000, +0.0010986328125000, 0.0007934570312500, 0.0011596679687500, 0.0005798339843750, +0.0011291503906250, 0.0009155273437500, 0.0012207031250000, 0.0014953613281250, +0.0012817382812500, 0.0014038085937500, 0.0011596679687500, 0.0018920898437500, +0.0015869140625000, 0.0021667480468750, 0.0014343261718750, 0.0022583007812500, +0.0017395019531250, 0.0024108886718750, 0.0022277832031250, 0.0024719238281250, +0.0020446777343750, 0.0025024414062500, 0.0025024414062500, 0.0025024414062500, +0.0026855468750000, 0.0023803710937500, 0.0025329589843750, 0.0023498535156250, +0.0027160644531250, 0.0024414062500000, 0.0029602050781250, 0.0021667480468750, +0.0024719238281250, 0.0022888183593750, 0.0027465820312500, 0.0023193359375000, +0.0025634765625000, 0.0021667480468750, 0.0021667480468750, 0.0022888183593750, +0.0025634765625000, 0.0021972656250000, 0.0017089843750000, 0.0022888183593750, +0.0019226074218750, 0.0020446777343750, 0.0018005371093750, 0.0018005371093750, +0.0013122558593750, 0.0020446777343750, 0.0017089843750000, 0.0010681152343750, +0.0012207031250000, 0.0011901855468750, 0.0012512207031250, 0.0009460449218750, +0.0013122558593750, 0.0001525878906250, 0.0010681152343750, 0.0004882812500000, +0.0012512207031250, -0.0000610351562500, 0.0011596679687500, -0.0004272460937500, +0.0011291503906250, 0.0000610351562500, 0.0011291503906250, 0.0001525878906250, +0.0010681152343750, -0.0002136230468750, 0.0010375976562500, 0.0010986328125000, +0.0009460449218750, 0.0006408691406250, 0.0009460449218750, 0.0011291503906250, +0.0009460449218750, 0.0022277832031250, 0.0008544921875000, 0.0014648437500000, +0.0007934570312500, 0.0026245117187500, 0.0009765625000000, 0.0026855468750000, +0.0008850097656250, 0.0024719238281250, 0.0009765625000000, 0.0029602050781250, +0.0011291503906250, 0.0028686523437500, 0.0009460449218750, 0.0023498535156250, +0.0010986328125000, 0.0024719238281250, 0.0010986328125000, 0.0021667480468750, +0.0010070800781250, 0.0016174316406250, 0.0010070800781250, 0.0018615722656250, +0.0009155273437500, 0.0011596679687500, 0.0007324218750000, 0.0010986328125000, +0.0006103515625000, 0.0011901855468750, 0.0005493164062500, 0.0008544921875000, +0.0003662109375000, 0.0007934570312500, 0.0003356933593750, 0.0010681152343750, +0.0005493164062500, 0.0008544921875000, 0.0003662109375000, 0.0010681152343750, +0.0005493164062500, 0.0013732910156250, 0.0009460449218750, 0.0010986328125000, +0.0006408691406250, 0.0016174316406250, 0.0010681152343750, 0.0016174316406250, +0.0011291503906250, 0.0016479492187500, 0.0010375976562500, 0.0020141601562500, +0.0011901855468750, 0.0018920898437500, 0.0011291503906250, 0.0019531250000000, +0.0010681152343750, 0.0020446777343750, 0.0010986328125000, 0.0021667480468750, +0.0010375976562500, 0.0021667480468750, 0.0009765625000000, 0.0020446777343750, +0.0009155273437500, 0.0022888183593750, 0.0011291503906250, 0.0021667480468750, +0.0010375976562500, 0.0022277832031250, 0.0011901855468750, 0.0023803710937500, +0.0014038085937500, 0.0021667480468750, 0.0013122558593750, 0.0024414062500000, +0.0018310546875000, 0.0021972656250000, 0.0017700195312500, 0.0022277832031250, +0.0019226074218750, 0.0023498535156250, 0.0024108886718750, 0.0020446777343750, +0.0022583007812500, 0.0023498535156250, 0.0025024414062500, 0.0021362304687500, +0.0025634765625000, 0.0022277832031250, 0.0024719238281250, 0.0024719238281250, +0.0025329589843750, 0.0021667480468750, 0.0025024414062500, 0.0024719238281250, +0.0021667480468750, 0.0024108886718750, 0.0021972656250000, 0.0023193359375000, +0.0020141601562500, 0.0025024414062500, 0.0016174316406250, 0.0024108886718750, +0.0018005371093750, 0.0023803710937500, 0.0013122558593750, 0.0024414062500000, +0.0012207031250000, 0.0023193359375000, 0.0012817382812500, 0.0022277832031250, +0.0010070800781250, 0.0023193359375000, 0.0010681152343750, 0.0021667480468750, +0.0012512207031250, 0.0021057128906250, 0.0010986328125000, 0.0021057128906250, +0.0013732910156250, 0.0020446777343750, 0.0017089843750000, 0.0020446777343750, +0.0015563964843750, 0.0020751953125000, 0.0022583007812500, 0.0019531250000000, +0.0022583007812500, 0.0020446777343750, 0.0024414062500000, 0.0021362304687500, +0.0029602050781250, 0.0019226074218750, 0.0027770996093750, 0.0022583007812500, +0.0029602050781250, 0.0021667480468750, 0.0031127929687500, 0.0022888183593750, +0.0028381347656250, 0.0025634765625000, 0.0026855468750000, 0.0024414062500000, +0.0027770996093750, 0.0026245117187500, 0.0021362304687500, 0.0026855468750000, +0.0020446777343750, 0.0025634765625000, 0.0020751953125000, 0.0026245117187500, +0.0017395019531250, 0.0026245117187500, 0.0017700195312500, 0.0023498535156250, +0.0019226074218750, 0.0024108886718750, 0.0017395019531250, 0.0022583007812500, +0.0019226074218750, 0.0019836425781250, 0.0021972656250000, 0.0020141601562500, +0.0020751953125000, 0.0016479492187500, 0.0024108886718750, 0.0016174316406250, +0.0024414062500000, 0.0015563964843750, 0.0025024414062500, 0.0013427734375000, +0.0026855468750000, 0.0013122558593750, 0.0025939941406250, 0.0013427734375000, +0.0026550292968750, 0.0011596679687500, 0.0027160644531250, 0.0012207031250000, +0.0027160644531250, 0.0013732910156250, 0.0027465820312500, 0.0010986328125000, +0.0027465820312500, 0.0014038085937500, 0.0028686523437500, 0.0014038085937500, +0.0028686523437500, 0.0013122558593750, 0.0028381347656250, 0.0014953613281250, +0.0028991699218750, 0.0014648437500000, 0.0029602050781250, 0.0012817382812500, +0.0028381347656250, 0.0014648437500000, 0.0028991699218750, 0.0014038085937500, +0.0028076171875000, 0.0012512207031250, 0.0026550292968750, 0.0014648437500000, +0.0027770996093750, 0.0011901855468750, 0.0026855468750000, 0.0013122558593750, +0.0026550292968750, 0.0014648437500000, 0.0027160644531250, 0.0013732910156250, +0.0028076171875000, 0.0014343261718750, 0.0028381347656250, 0.0016174316406250, +0.0030212402343750, 0.0016479492187500, 0.0030822753906250, 0.0016784667968750, +0.0031433105468750, 0.0018920898437500, 0.0032653808593750, 0.0019836425781250, +0.0033264160156250, 0.0017700195312500, 0.0032958984375000, 0.0021057128906250, +0.0034179687500000, 0.0018920898437500, 0.0033264160156250, 0.0015869140625000, +0.0033264160156250, 0.0020446777343750, 0.0034790039062500, 0.0013427734375000, +0.0030517578125000, 0.0014953613281250, 0.0031127929687500, 0.0014038085937500, +0.0032653808593750, 0.0008239746093750, 0.0030822753906250, 0.0011596679687500, +0.0030517578125000, 0.0007324218750000, 0.0033874511718750, 0.0006713867187500, +0.0032958984375000, 0.0008239746093750, 0.0032653808593750, 0.0007629394531250, +0.0035705566406250, 0.0007019042968750, 0.0036010742187500, 0.0010681152343750, +0.0031433105468750, 0.0009460449218750, 0.0035095214843750, 0.0010681152343750, +0.0030822753906250, 0.0013427734375000, 0.0024108886718750, 0.0011596679687500, +0.0028076171875000, 0.0015869140625000, 0.0017395019531250, 0.0014648437500000, +0.0018310546875000, 0.0016479492187500, 0.0014343261718750, 0.0019836425781250, +0.0006408691406250, 0.0017700195312500, 0.0012207031250000, 0.0021667480468750, +0.0001220703125000, 0.0021972656250000, 0.0001525878906250, 0.0021057128906250, +0.0003662109375000, 0.0024108886718750, -0.0002746582031250, 0.0017700195312500, +0.0024414062500000, 0.0025634765625000, 0.0003356933593750, 0.0021667480468750, +0.0009460449218750, 0.0024719238281250, 0.0004577636718750, 0.0029907226562500, +-0.0006408691406250, 0.0026245117187500, -0.0002136230468750, 0.0031433105468750, +-0.0003356933593750, 0.0032348632812500, -0.0007934570312500, 0.0029907226562500, +-0.0002136230468750, 0.0030212402343750, 0.0001831054687500, 0.0029602050781250, +-0.0003356933593750, 0.0023498535156250, 0.0013122558593750, 0.0024108886718750, +0.0010375976562500, 0.0020751953125000, 0.0015258789062500, 0.0015258789062500, +0.0028076171875000, 0.0016784667968750, 0.0021057128906250, 0.0009765625000000, +0.0034179687500000}}; diff --git a/bridges/bridge_softmix/include/hrirs_configuration.h b/bridges/bridge_softmix/include/hrirs_configuration.h new file mode 100644 index 00000000000..4d5132a2047 --- /dev/null +++ b/bridges/bridge_softmix/include/hrirs_configuration.h @@ -0,0 +1,63 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, Frank Haase, Dennis Guse + * + * Frank Haase + * Dennis Guse + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Multi-party software binaural channel mixing (header) + * + * \author Frank Haase + * \author Dennis Guse + * + * \ingroup bridges + */ + +#ifndef _ASTERISK_HRIRS_CONFIGURATION_H +#define _ASTERISK_HRIRS_CONFIGURATION_H + +#include "hrirs.h" + +/*! The size of possible positions in the virtual enviroment build with the help + * of binaural audio processing. + */ +#define POSITION_SIZE 181 + +#if POSITION_SIZE != HRIRS_IMPULSE_SIZE +#error "The conference is designed for 181 individual places at the moment. If you want to change this please alter the positions array first." +#endif + +/*! The offset for the left channel audio channel. */ +#define HRIRS_CHANNEL_LEFT 0 +/*! The offset for the right channel audio channel. */ +#define HRIRS_CHANNEL_RIGHT 1 + +/*! The ast_binaural_positions array contains a specific plan to order conference + * participants in the virtual enviroment. + */ +static unsigned int ast_binaural_positions[POSITION_SIZE] = { + 90, 80, 100, 70, 110, 60, 120, 50, 130, 40, 140, 20, 160, 0, 180, 85, 95, 75, 105, 65, 115, + 55, 125, 45, 135, 30, 150, 10, 170, 87, 93, 82, 98, 77, 103, 72, 108, 67, 113, 62, 118, 57, + 123, 52, 128, 47, 133, 42, 138, 35, 145, 25, 155, 15, 165, 5, 175, 88, 92, 86, 83, 97, 81, + 99, 78, 102, 76, 104, 73, 94, 107, 71, 109, 68, 112, 66, 114, 63, 117, 61, 119, 58, 122, 56, + 124, 53, 127, 51, 129, 48, 132, 46, 134, 43, 137, 41, 139, 37, 143, 32, 148, 27, 153, 22, + 158, 17, 163, 12, 168, 7, 96, 173, 2, 178, 89, 91, 84, 79, 101, 74, 106, 69, 111, 64, 116, + 59, 121, 54, 126, 49, 131, 44, 136, 38, 142, 36, 144, 33, 147, 31, 149, 28, 152, 26, 154, + 23, 157, 21, 159, 162, 16, 164, 13, 167, 11, 169, 8, 172, 6, 174, 3, 177, 1, 179, 39, 141, + 34, 146, 29, 151, 24, 156, 19, 161, 14, 166, 9, 171, 4, 18, 176 }; + +#endif /* _ASTERISK_HRIRS_CONFIGURATION_H */ diff --git a/bridges/bridges.xml b/bridges/bridges.xml new file mode 100644 index 00000000000..403da50acef --- /dev/null +++ b/bridges/bridges.xml @@ -0,0 +1,8 @@ + + option + bridge_softmix + fftw3 + no + diff --git a/configure b/configure index 42a21d7c587..fb13b5620dd 100755 --- a/configure +++ b/configure @@ -29419,7 +29419,7 @@ if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lfftw3 ${pbxlibdir} -lfftw3 $LIBS" +LIBS="-lfftw3 ${pbxlibdir} $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -29461,7 +29461,7 @@ fi # now check for the header. if test "${AST_FFTW3_FOUND}" = "yes"; then - FFTW3_LIB="${pbxlibdir} -lfftw3 -lfftw3" + FFTW3_LIB="${pbxlibdir} -lfftw3 " # if --with-FFTW3=DIR has been specified, use it. if test "x${FFTW3_DIR}" != "x"; then FFTW3_INCLUDE="-I${FFTW3_DIR}/include" @@ -29499,11 +29499,6 @@ _ACEOF fi -if test "$PBX_FFTW3" = "1"; then - -$as_echo "#define HAVE_FFTW 1" >>confdefs.h - -fi if test "x${PBX_SNDFILE}" != "x1" -a "${USE_SNDFILE}" != "no"; then pbxlibdir="" @@ -29528,7 +29523,7 @@ if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lsndfile ${pbxlibdir} -lsndfile $LIBS" +LIBS="-lsndfile ${pbxlibdir} $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -29570,7 +29565,7 @@ fi # now check for the header. if test "${AST_SNDFILE_FOUND}" = "yes"; then - SNDFILE_LIB="${pbxlibdir} -lsndfile -lsndfile" + SNDFILE_LIB="${pbxlibdir} -lsndfile " # if --with-SNDFILE=DIR has been specified, use it. if test "x${SNDFILE_DIR}" != "x"; then SNDFILE_INCLUDE="-I${SNDFILE_DIR}/include" @@ -29610,8 +29605,6 @@ fi - - if test "x${PBX_SPANDSP}" != "x1" -a "${USE_SPANDSP}" != "no"; then if test "xminimum version of SpanDSP" != "x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for minimum version of SpanDSP" >&5 @@ -36253,6 +36246,31 @@ else touch makeopts.acbak fi +# conf_bridge (binaural rendering): check if HRIRs are available +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bridges/bridge_softmix/include/hrirs.h" >&5 +$as_echo_n "checking for bridges/bridge_softmix/include/hrirs.h... " >&6; } +if ${ac_cv_file_bridges_bridge_softmix_include_hrirs_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 +if test -r "bridges/bridge_softmix/include/hrirs.h"; then + ac_cv_file_bridges_bridge_softmix_include_hrirs_h=yes +else + ac_cv_file_bridges_bridge_softmix_include_hrirs_h=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file_bridges_bridge_softmix_include_hrirs_h" >&5 +$as_echo "$ac_cv_file_bridges_bridge_softmix_include_hrirs_h" >&6; } +if test "x$ac_cv_file_bridges_bridge_softmix_include_hrirs_h" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_BRIDGES_BRIDGE_SOFTMIX_INCLUDE_HRIRS_H 1 +_ACEOF + +fi + + ac_config_files="$ac_config_files build_tools/menuselect-deps makeopts" diff --git a/configure.ac b/configure.ac index fff8ecf7e6a..8a713ea14e6 100644 --- a/configure.ac +++ b/configure.ac @@ -2283,13 +2283,8 @@ AST_EXT_LIB_CHECK([PRI_REVERSE_CHARGE], [pri], [pri_sr_set_reversecharge], [libp # ------------------------------------^ AST_EXT_LIB_CHECK([RESAMPLE], [resample], [resample_open], [libresample.h], [-lm]) -AST_EXT_LIB_CHECK([FFTW3], [fftw3], [fftw_alloc_real], [fftw3.h], [-lfftw3]) -if test "$PBX_FFTW3" = "1"; then - AC_DEFINE([HAVE_FFTW], 1, [Define 1 if your system has fftw.]) -fi -AST_EXT_LIB_CHECK([SNDFILE], [sndfile], [sf_open], [sndfile.h], [-lsndfile]) - - +AST_EXT_LIB_CHECK([FFTW3], [fftw3], [fftw_alloc_real], [fftw3.h]) +AST_EXT_LIB_CHECK([SNDFILE], [sndfile], [sf_open], [sndfile.h]) AST_C_COMPILE_CHECK([SPANDSP], [ #if SPANDSP_RELEASE_DATE < 20080516 @@ -2692,6 +2687,9 @@ else touch makeopts.acbak fi +# conf_bridge (binaural rendering): check if HRIRs are available +AC_CHECK_FILES([bridges/bridge_softmix/include/hrirs.h]) + AC_CONFIG_FILES([build_tools/menuselect-deps makeopts]) AST_CHECK_MANDATORY diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index eecd957fa4e..b9b4e1f8127 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -124,6 +124,10 @@ /* Define to 1 if you have the Bluetooth library. */ #undef HAVE_BLUETOOTH +/* Define to 1 if you have the file `bridges/bridge_softmix/include/hrirs.h'. + */ +#undef HAVE_BRIDGES_BRIDGE_SOFTMIX_INCLUDE_HRIRS_H + /* Define to 1 if byteswap.h macros are available. */ #undef HAVE_BYTESWAP_H @@ -236,9 +240,6 @@ /* Define to 1 if you have the `ffsll' function. */ #undef HAVE_FFSLL -/* Define 1 if your system has fftw. */ -#undef HAVE_FFTW - /* Define to 1 if you have the LIBFFTW3 library. */ #undef HAVE_FFTW3 diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index 61cecbdd644..ffe08da13ef 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -263,6 +263,8 @@ struct ast_bridge_softmix { * for itself. */ unsigned int internal_mixing_interval; + /*! TRUE if binaural convolve is activated in configuration. */ + unsigned int binaural_active; }; /*! @@ -867,6 +869,14 @@ void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int */ void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval); +/*! + * \brief Activates the use of binaural signals in a conference bridge. + * + * \param bridge Channel to activate the binaural signals. + * \param binaural_active If true binaural signal processing will be active for the bridge. + */ +void ast_bridge_set_binaural_active(struct ast_bridge *bridge, unsigned int binaural_active); + /*! * \brief Set a bridge to feed a single video source to all participants. */ diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index 797be4ebcb1..a7971df27f2 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -172,6 +172,17 @@ struct ast_bridge_channel { /*! Collected DTMF digits for DTMF hooks. */ char collected[MAXIMUM_DTMF_FEATURE_STRING]; } dtmf_hook_state; + union { + uint32_t raw; + struct { + /*! TRUE if binaural is suspended. */ + unsigned int binaural_suspended:1; + /*! TRUE if a change of binaural positions has to be performed. */ + unsigned int binaural_pos_change:1; + /*! Padding */ + unsigned int padding:30; + }; + }; }; /*! diff --git a/main/bridge.c b/main/bridge.c index b6ba0a2bf78..d40c3ec9ac9 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -3736,6 +3736,13 @@ void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixi ast_bridge_unlock(bridge); } +void ast_bridge_set_binaural_active(struct ast_bridge *bridge, unsigned int binaural_active) +{ + ast_bridge_lock(bridge); + bridge->softmix.binaural_active = binaural_active; + ast_bridge_unlock(bridge); +} + void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate) { ast_bridge_lock(bridge); diff --git a/menuselect/menuselect.c b/menuselect/menuselect.c index da972d8b12a..689cebf6246 100644 --- a/menuselect/menuselect.c +++ b/menuselect/menuselect.c @@ -238,6 +238,10 @@ static enum support_level_values string_to_support_level(const char *support_lev return SUPPORT_EXTERNAL; } + if (!strcasecmp(support_level, "option")) { + return SUPPORT_OPTION; + } + return SUPPORT_UNSPECIFIED; } @@ -253,6 +257,8 @@ static const char *support_level_to_string(enum support_level_values support_lev return "Deprecated"; case SUPPORT_EXTERNAL: return "External"; + case SUPPORT_OPTION: + return "Module Options"; default: return "Unspecified"; } @@ -461,7 +467,7 @@ static int process_xml_member_node(xmlNode *node, struct category *cat) process_process_xml_category_child_node(cur, mem); } - if (!cat->positive_output) { + if (!cat->positive_output && strcasecmp(mem->support_level, "option")) { mem->enabled = 1; if (!mem->defaultenabled || strcasecmp(mem->defaultenabled, "no")) { mem->was_enabled = 1; diff --git a/menuselect/menuselect.h b/menuselect/menuselect.h index bf2bf4c4fee..78ae8eff6df 100644 --- a/menuselect/menuselect.h +++ b/menuselect/menuselect.h @@ -108,7 +108,8 @@ enum support_level_values { SUPPORT_DEPRECATED = 2, SUPPORT_UNSPECIFIED = 3, SUPPORT_EXTERNAL = 4, - SUPPORT_COUNT = 5, /* Keep this item at the end of the list. Tracks total number of support levels. */ + SUPPORT_OPTION = 5, + SUPPORT_COUNT = 6, /* Keep this item at the end of the list. Tracks total number of support levels. */ }; AST_LIST_HEAD_NOLOCK(support_level_bucket, member); diff --git a/utils/.gitignore b/utils/.gitignore index 8e95c8df8fe..dbdc6b6d21b 100644 --- a/utils/.gitignore +++ b/utils/.gitignore @@ -23,3 +23,4 @@ stereorize strcompat.c streamplayer threadstorage.c +conf_bridge_binaural_hrir_importer diff --git a/utils/Makefile b/utils/Makefile index b6618e19518..5d3119aee79 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -70,10 +70,6 @@ ifneq ($(filter pbx_ael,$(MENUSELECT_PBX)),) UTILS:=$(filter-out conf2ael,$(UTILS)) endif -ifeq ($(SNDFILE_LIB),) - UTILS:=$(filter-out conf_bridge_binaural_hrir_importer,$(UTILS)) -endif - all: $(UTILS) install: @@ -193,10 +189,6 @@ smsq: LIBS+=$(POPT_LIB) streamplayer: streamplayer.o -conf_bridge_binaural_hrir_importer: LIBS+=$(SNDFILE_LIB) -conf_bridge_binaural_hrir_importer: _ASTCFLAGS+=$(SNDFILE_INCLUDE) -conf_bridge_binaural_hrir_importer: conf_bridge_binaural_hrir_importer.o - muted: muted.o muted: LIBS+=$(AUDIO_LIBS) muted: _ASTCFLAGS:=$(filter-out -Werror,$(_ASTCFLAGS)) @@ -213,6 +205,9 @@ astdb2bdb: LIBS+=$(SQLITE3_LIB) astdb2bdb: _ASTCFLAGS+=$(SQLITE3_INCLUDE) astdb2bdb: db1-ast/libdb1.a +conf_bridge_binaural_hrir_importer: LIBS+=$(SNDFILE_LIB) +conf_bridge_binaural_hrir_importer.o: _ASTCFLAGS+=$(SNDFILE_INCLUDE) + ifneq ($(wildcard .*.d),) include .*.d endif diff --git a/utils/conf_bridge_binaural_hrir_importer.c b/utils/conf_bridge_binaural_hrir_importer.c index 5690d86ea7a..c1e5458db01 100644 --- a/utils/conf_bridge_binaural_hrir_importer.c +++ b/utils/conf_bridge_binaural_hrir_importer.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2016, Digium, Inc. + * Copyright (C) 2016, Frank Haase, Dennis Guse * * Frank Haase * Dennis Guse @@ -30,6 +30,7 @@ #include #include #include +#include "conf_bridge_binaural_hrir_importer.h" int main (int argc, char **argv) { @@ -99,46 +100,44 @@ int main (int argc, char **argv) impulse_response_index_end = (binaural_index_end + 1) * 2; /* Write header */ - printf("//Used hrirs database: %s\n", hrir_filename); - printf("//Start index in database: %d\n", impulse_response_index_start); - printf("//End index in database: %d\n", impulse_response_index_end); + printf(FILE_HEADER, hrir_filename, binaural_index_start, binaural_index_end); printf("#define HRIRS_IMPULSE_LEN %ld\n", hrir_info.frames); printf("#define HRIRS_IMPULSE_SIZE %d\n", binaural_index_end - binaural_index_start + 1); - printf("#define HRIRS_SAMPLE_RATE %d\n", hrir_info.samplerate); + printf("#define HRIRS_SAMPLE_RATE %d\n\n", hrir_info.samplerate); printf("float hrirs_left[HRIRS_IMPULSE_SIZE][HRIRS_IMPULSE_LEN] = {\n"); for (ir_current = impulse_response_index_start; ir_current < impulse_response_index_end; ir_current += 2) { - printf("{"); - - for (j = 0; j < hrir_info.frames - 1; j++) { - printf("%.16f,", hrir_data[ir_current * hrir_info.frames + j]); - } - /* Write last without trailing "," */ - printf("%.16f", hrir_data[ir_current * hrir_info.frames + hrir_info.frames - 1]); - - if (ir_current + 2 < impulse_response_index_end) { - printf("},\n"); - } else { - printf("}};"); - } + printf("{"); + + for (j = 0; j < hrir_info.frames - 1; j++) { + printf("%.16f,%s", hrir_data[ir_current * hrir_info.frames + j], ((j + 1) % 4 ? " " : "\n")); + } + /* Write last without trailing "," */ + printf("%.16f", hrir_data[ir_current * hrir_info.frames + hrir_info.frames - 1]); + + if (ir_current + 2 < impulse_response_index_end) { + printf("},\n"); + } else { + printf("}};"); + } } printf("\nfloat hrirs_right[HRIRS_IMPULSE_SIZE][HRIRS_IMPULSE_LEN] = {\n"); for (ir_current = impulse_response_index_start + 1; ir_current < impulse_response_index_end + 1; ir_current += 2) { - printf("{"); - - for (j = 0; j < hrir_info.frames - 1; j++) { - printf("%.16f,", hrir_data[ir_current * hrir_info.frames + j]); - } - /* Write last without trailing "," */ - printf("%.16f", hrir_data[ir_current * hrir_info.frames + hrir_info.frames - 1]); - - if (ir_current + 2 < impulse_response_index_end) { - printf("},\n"); - } else { - printf("}};"); - } + printf("{"); + + for (j = 0; j < hrir_info.frames - 1; j++) { + printf("%.16f,%s", hrir_data[ir_current * hrir_info.frames + j], ((j + 1) % 4 ? " " : "\n")); + } + /* Write last without trailing "," */ + printf("%.16f", hrir_data[ir_current * hrir_info.frames + hrir_info.frames - 1]); + + if (ir_current + 2 < impulse_response_index_end) { + printf("},\n"); + } else { + printf("}};"); + } } fprintf(stderr, "INFO: Successfully converted: imported %d impulse responses.\n", impulse_response_index_end - impulse_response_index_start); diff --git a/utils/conf_bridge_binaural_hrir_importer.h b/utils/conf_bridge_binaural_hrir_importer.h new file mode 100644 index 00000000000..b8acc305112 --- /dev/null +++ b/utils/conf_bridge_binaural_hrir_importer.h @@ -0,0 +1,46 @@ +#define FILE_HEADER "\ + * Asterisk -- An open source telephony toolkit.\n\ + *\n\ + * Copyright (C) 2016, Frank Haase, Dennis Guse\n\ + *\n\ + * Frank Haase \n\ + * Dennis Guse \n\ + *\n\ + * See http://www.asterisk.org for more information about\n\ + * the Asterisk project. Please do not directly contact\n\ + * any of the maintainers of this project for assistance;\n\ + * the project provides a web site, mailing lists and IRC\n\ + * channels for your use.\n\ + *\n\ + * Copyright (c) 2001 The Regents of the University of California. All Rights Reserved.\n\ + *\n\ + * The HRIRs used here are obtained from The CIPIC HRTF Database\n\ + * (http://interface.cipic.ucdavis.edu/CIL_html/CIL_HRTF_database.htm)\n\ + * Note that the above mentioned material is Copyright (c) 2001 The\n\ + * Regents of the University of California. All Rights Reserved.\n\ + *\n\ + * Download the file\n\ + * http://interface.cipic.ucdavis.edu/data/special_kemar_hrir.tar and\n\ + * uncompress it in the folder where this Matlab script resides. Finally,\n\ + * run the script.\n\ + *\n\ + * This program is free software, distributed under the terms of\n\ + * the GNU General Public License Version 2. See the LICENSE file\n\ + * at the top of the source tree.\n\ + */\n\ +\n\ +/*! \\file\n\ + *\n\ + * \\brief Multi-party software binaural channel HRIRS\n\ + *\n\ + * \\author Frank Haase \n\ + * \\author Dennis Guse \n\ + *\n\ + * \\ingroup bridges\n\ + */\n\ +\n\ +/*\n\ + * This file was created with command:\n\ + * $ conf_bridge_binaural_hrir_importer %s %d %d\n\ + */\n\ +" diff --git a/utils/utils.xml b/utils/utils.xml index 498929a27d5..5b3a27ae3b8 100644 --- a/utils/utils.xml +++ b/utils/utils.xml @@ -20,11 +20,6 @@ newt extended - - no - sndfile - extended - no extended @@ -54,4 +49,12 @@ no extended + + no + sndfile + extended + no + From 6cc890b880a6d50b3236860c3ab89e26ba59a7d3 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 22 Feb 2017 11:00:57 +0000 Subject: [PATCH 1080/1578] channel: Add support for writing to a specific stream. This change adds an ast_write_stream function which allows writing a frame to a specific media stream. It also moves ast_write() to using this underneath by writing media frames provided to it to the default streams of the channel. Existing functionality (such as audiohooks, framehooks, etc) are limited to being applied to the default stream only. Unit tests have also been added which test the behavior of both non-multistream and multistream channels to confirm that the write() and write_stream() callbacks are invoked appropriately. ASTERISK-26793 Change-Id: I4df20d1b65bd4d787fce0b4b478e19d2dfea245c --- include/asterisk/channel.h | 28 +++ main/channel.c | 54 +++-- main/channel_internal_api.c | 9 + tests/test_stream.c | 419 ++++++++++++++++++++++++++++++++++++ 4 files changed, 498 insertions(+), 12 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 4170a8af456..80476a4e0b1 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -670,6 +670,9 @@ struct ast_channel_tech { /*! \brief Write a frame, in standard format (see frame.h) */ int (* const write)(struct ast_channel *chan, struct ast_frame *frame); + /*! \brief Write a frame on a specific stream, in standard format (see frame.h) */ + int (* const write_stream)(struct ast_channel *chan, int stream_num, struct ast_frame *frame); + /*! \brief Display or transmit text */ int (* const send_text)(struct ast_channel *chan, const char *text); @@ -1968,6 +1971,18 @@ int ast_write_video(struct ast_channel *chan, struct ast_frame *frame); */ int ast_write_text(struct ast_channel *chan, struct ast_frame *frame); +/*! + * \brief Write a frame to a stream + * This function writes the given frame to the indicated stream on the channel. + * \param chan destination channel of the frame + * \param stream_num destination stream on the channel + * \param frame frame that will be written + * \return It returns 0 on success, -1 on failure. + * \note If -1 is provided as the stream number and a media frame is provided the + * function will write to the default stream of the type of media. + */ +int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *frame); + /*! \brief Send empty audio to prime a channel driver */ int ast_prod(struct ast_channel *chan); @@ -4768,4 +4783,17 @@ struct ast_stream_topology *ast_channel_get_stream_topology( struct ast_stream_topology *ast_channel_set_stream_topology( struct ast_channel *chan, struct ast_stream_topology *topology); +/*! + * \brief Retrieve the default stream of a specific media type on a channel + * + * \param channel The channel to get the stream from + * \param type The media type of the default stream + * + * \pre chan is locked + * + * \retval non-NULL success + * \retval NULL failure + */ +struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan, enum ast_media_type type); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/main/channel.c b/main/channel.c index 1e7bc563ef0..183f8936f12 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5125,6 +5125,12 @@ static void apply_plc(struct ast_channel *chan, struct ast_frame *frame) int ast_write(struct ast_channel *chan, struct ast_frame *fr) { + return ast_write_stream(chan, -1, fr); +} + +int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr) +{ + struct ast_stream *stream = NULL, *default_stream = NULL; int res = -1; struct ast_frame *f = NULL; int count = 0; @@ -5139,13 +5145,28 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) } usleep(1); } + /* Stop if we're a zombie or need a soft hangup */ - if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) + if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) { goto done; + } + + /* If this frame is writing an audio or video frame get the stream information */ + if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO) { + /* Initially use the default stream unless an explicit stream is provided */ + stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(fr->subclass.format)); + + if (stream_num >= 0) { + if (stream_num >= ast_stream_topology_get_count(ast_channel_get_stream_topology(chan))) { + goto done; + } + stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num); + } + } /* Perform the framehook write event here. After the frame enters the framehook list * there is no telling what will happen, how awesome is that!!! */ - if (!(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) { + if ((stream == default_stream) && !(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) { res = 0; goto done; } @@ -5231,17 +5252,20 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) break; case AST_FRAME_VIDEO: /* XXX Handle translation of video codecs one day XXX */ - res = (ast_channel_tech(chan)->write_video == NULL) ? 0 : - ast_channel_tech(chan)->write_video(chan, fr); + if (ast_channel_tech(chan)->write_stream) { + res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr); + } else if ((stream == default_stream) && ast_channel_tech(chan)->write_video) { + res = ast_channel_tech(chan)->write_video(chan, fr); + } else { + res = 0; + + } break; case AST_FRAME_MODEM: res = (ast_channel_tech(chan)->write == NULL) ? 0 : ast_channel_tech(chan)->write(chan, fr); break; case AST_FRAME_VOICE: - if (ast_channel_tech(chan)->write == NULL) - break; /*! \todo XXX should return 0 maybe ? */ - if (ast_opt_generic_plc && ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { apply_plc(chan, fr); } @@ -5250,7 +5274,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) * Send frame to audiohooks if present, if frametype is linear (else, later as per * previous behavior) */ - if (ast_channel_audiohooks(chan)) { + if ((stream == default_stream) && ast_channel_audiohooks(chan)) { if (ast_format_cache_is_slinear(fr->subclass.format)) { struct ast_frame *old_frame; hooked = 1; @@ -5263,7 +5287,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) } /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */ - if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) { + if ((stream != default_stream) || ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) { f = fr; } else { if (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL) { @@ -5299,7 +5323,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) break; } - if (ast_channel_audiohooks(chan) && !hooked) { + if ((stream == default_stream) && ast_channel_audiohooks(chan) && !hooked) { struct ast_frame *prev = NULL, *new_frame, *cur, *dup; int freeoldlist = 0; @@ -5348,7 +5372,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) /* the translator on chan->writetrans may have returned multiple frames from the single frame we passed in; if so, feed each one of them to the monitor */ - if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) { + if ((stream == default_stream) && ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) { struct ast_frame *cur; for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { @@ -5415,7 +5439,13 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) /* reset f so the code below doesn't attempt to free it */ f = NULL; } else { - res = ast_channel_tech(chan)->write(chan, f); + if (ast_channel_tech(chan)->write_stream) { + res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), f); + } else if ((stream == default_stream) && ast_channel_tech(chan)->write) { + res = ast_channel_tech(chan)->write(chan, f); + } else { + res = 0; + } } break; case AST_FRAME_NULL: diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 1934eb9a4a6..362bd1a3d09 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -1816,6 +1816,15 @@ struct ast_stream_topology *ast_channel_set_stream_topology(struct ast_channel * return new_topology; } +struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan, + enum ast_media_type type) +{ + ast_assert(chan != NULL); + ast_assert(type < AST_MEDIA_TYPE_END); + + return chan->default_streams[type]; +} + void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1, struct ast_channel *chan2) { diff --git a/tests/test_stream.c b/tests/test_stream.c index 5134cfb507c..d602d52fe27 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -853,6 +853,421 @@ AST_TEST_DEFINE(stream_topology_channel_set) return res; } +struct mock_channel_pvt { + unsigned int wrote; + unsigned int wrote_stream; + int stream_num; +}; + +static int mock_channel_write(struct ast_channel *chan, struct ast_frame *fr) +{ + struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); + + pvt->wrote = 1; + + return 0; +} + +static int mock_channel_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr) +{ + struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); + + pvt->wrote_stream = 1; + pvt->stream_num = stream_num; + + return 0; +} + +static int mock_channel_hangup(struct ast_channel *chan) +{ + ast_channel_tech_pvt_set(chan, NULL); + return 0; +} + +static const struct ast_channel_tech mock_channel_old_write_tech = { + .write = mock_channel_write, + .write_video = mock_channel_write, + .hangup = mock_channel_hangup, +}; + +AST_TEST_DEFINE(stream_write_non_multistream) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + struct ast_channel *mock_channel; + struct mock_channel_pvt pvt; + enum ast_test_result_state res = AST_TEST_FAIL; + struct ast_frame frame = { 0, }; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_write_non_multistream"; + info->category = "/main/stream/"; + info->summary = "stream writing to non-multistream capable channel test"; + info->description = + "Test that writing frames to a non-multistream channel works as expected"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { + ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_h264, 0)) { + ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"); + if (!mock_channel) { + ast_test_status_update(test, "Failed to create a mock channel for testing\n"); + return AST_TEST_FAIL; + } + + ast_channel_tech_set(mock_channel, &mock_channel_old_write_tech); + ast_channel_nativeformats_set(mock_channel, caps); + + pvt.wrote = 0; + ast_channel_tech_pvt_set(mock_channel, &pvt); + ast_channel_unlock(mock_channel); + + frame.frametype = AST_FRAME_VOICE; + frame.subclass.format = ast_format_ulaw; + + if (ast_write(mock_channel, &frame)) { + ast_test_status_update(test, "Failed to write a ulaw frame to the mock channel when it should be fine\n"); + goto end; + } + + if (!pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw but it never reached the channel driver\n"); + goto end; + } + + pvt.wrote = 0; + + if (!ast_write_stream(mock_channel, 2, &frame) || pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to a non-existent stream\n"); + goto end; + } + + frame.frametype = AST_FRAME_VIDEO; + frame.subclass.format = ast_format_h264; + + if (ast_write(mock_channel, &frame)) { + ast_test_status_update(test, "Failed to write an h264 frame to the mock channel when it should be fine\n"); + goto end; + } + + if (!pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of h264 but it never reached the channel driver\n"); + goto end; + } + + res = AST_TEST_PASS; + +end: + ast_hangup(mock_channel); + + return res; +} + +static const struct ast_channel_tech mock_channel_write_stream_tech = { + .properties = AST_CHAN_TP_MULTISTREAM, + .write = mock_channel_write, + .write_video = mock_channel_write, + .write_stream = mock_channel_write_stream, + .hangup = mock_channel_hangup, +}; + +AST_TEST_DEFINE(stream_write_multistream) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + struct ast_stream *stream; + struct ast_channel *mock_channel; + struct mock_channel_pvt pvt = { 0, }; + enum ast_test_result_state res = AST_TEST_FAIL; + struct ast_frame frame = { 0, }; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_write_multistream"; + info->category = "/main/stream/"; + info->summary = "stream writing to multistream capable channel test"; + info->description = + "Test that writing frames to a multistream channel works as expected"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_alloc(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing multistream writing\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(stream); + return AST_TEST_FAIL; + } + + stream = ast_stream_alloc("audio2", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing multistream writing\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(stream); + return AST_TEST_FAIL; + } + + stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); + if (!stream) { + ast_test_status_update(test, "Failed to create a video stream for testing multistream writing\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(stream); + return AST_TEST_FAIL; + } + + stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO); + if (!stream) { + ast_test_status_update(test, "Failed to create a video stream for testing multistream writing\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(stream); + return AST_TEST_FAIL; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { + ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_h264, 0)) { + ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"); + if (!mock_channel) { + ast_test_status_update(test, "Failed to create a mock channel for testing\n"); + return AST_TEST_FAIL; + } + + ast_channel_tech_set(mock_channel, &mock_channel_write_stream_tech); + ast_channel_set_stream_topology(mock_channel, topology); + ast_channel_nativeformats_set(mock_channel, caps); + topology = NULL; + + ast_channel_tech_pvt_set(mock_channel, &pvt); + ast_channel_unlock(mock_channel); + + frame.frametype = AST_FRAME_VOICE; + frame.subclass.format = ast_format_ulaw; + pvt.stream_num = -1; + + if (ast_write(mock_channel, &frame)) { + ast_test_status_update(test, "Failed to write a ulaw frame to the mock channel when it should be fine\n"); + goto end; + } + + if (pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw but it ended up on the old write callback instead of write_stream\n"); + goto end; + } + + if (!pvt.wrote_stream) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw but it never reached the channel driver\n"); + goto end; + } + + if (pvt.stream_num != 0) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to the default stream but it ended up on stream %d and not 0\n", + pvt.stream_num); + goto end; + } + + pvt.wrote_stream = 0; + pvt.stream_num = -1; + + if (ast_write_stream(mock_channel, 0, &frame)) { + ast_test_status_update(test, "Failed to write a ulaw frame to the first audio stream\n"); + goto end; + } + + if (pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it ended up on the old write callback instead of write_stream\n"); + goto end; + } + + if (!pvt.wrote_stream) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it never reached the channel driver\n"); + goto end; + } + + if (pvt.stream_num != 0) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it ended up on stream %d and not 0\n", + pvt.stream_num); + goto end; + } + + pvt.wrote_stream = 0; + pvt.stream_num = -1; + + if (ast_write_stream(mock_channel, 1, &frame)) { + ast_test_status_update(test, "Failed to write a ulaw frame to the second audio stream\n"); + goto end; + } + + if (pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it ended up on the old write callback instead of write_stream\n"); + goto end; + } + + if (!pvt.wrote_stream) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it never reached the channel driver\n"); + goto end; + } + + if (pvt.stream_num != 1) { + ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it ended up on stream %d and not 1\n", + pvt.stream_num); + goto end; + } + + pvt.wrote_stream = 0; + pvt.stream_num = -1; + + frame.frametype = AST_FRAME_VIDEO; + frame.subclass.format = ast_format_h264; + + if (ast_write(mock_channel, &frame)) { + ast_test_status_update(test, "Failed to write an h264 frame to the mock channel when it should be fine\n"); + goto end; + } + + if (pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of h264 but it ended up on the old write callback instead of write_stream\n"); + goto end; + } + + if (!pvt.wrote_stream) { + ast_test_status_update(test, "Successfully wrote a frame of h264 but it never reached the channel driver\n"); + goto end; + } + + if (pvt.stream_num != 2) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to the default stream but it ended up on stream %d and not 2\n", + pvt.stream_num); + goto end; + } + + pvt.wrote_stream = 0; + pvt.stream_num = -1; + + if (ast_write_stream(mock_channel, 2, &frame)) { + ast_test_status_update(test, "Failed to write an h264 frame to the first video stream\n"); + goto end; + } + + if (pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it ended up on the old write callback instead of write_stream\n"); + goto end; + } + + if (!pvt.wrote_stream) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it never reached the channel driver\n"); + goto end; + } + + if (pvt.stream_num != 2) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it ended up on stream %d and not 2\n", + pvt.stream_num); + goto end; + } + + pvt.wrote_stream = 0; + pvt.stream_num = -1; + + if (ast_write_stream(mock_channel, 3, &frame)) { + ast_test_status_update(test, "Failed to write an h264 frame to the second video stream\n"); + goto end; + } + + if (pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it ended up on the old write callback instead of write_stream\n"); + goto end; + } + + if (!pvt.wrote_stream) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it never reached the channel driver\n"); + goto end; + } + + if (pvt.stream_num != 3) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it ended up on stream %d and not 3\n", + pvt.stream_num); + goto end; + } + + pvt.wrote_stream = 0; + pvt.stream_num = -1; + + if (!ast_write_stream(mock_channel, 9, &frame)) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream\n"); + goto end; + } + + if (pvt.wrote) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream and it ended up on the old write callback\n"); + goto end; + } + + if (pvt.wrote_stream) { + ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream and it ended up on the write_stream callback\n"); + goto end; + } + + res = AST_TEST_PASS; + +end: + ast_hangup(mock_channel); + + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -869,6 +1284,8 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_get_first_stream_by_type); AST_TEST_UNREGISTER(stream_topology_create_from_channel_nativeformats); AST_TEST_UNREGISTER(stream_topology_channel_set); + AST_TEST_UNREGISTER(stream_write_non_multistream); + AST_TEST_UNREGISTER(stream_write_multistream); return 0; } @@ -887,6 +1304,8 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_get_first_stream_by_type); AST_TEST_REGISTER(stream_topology_create_from_channel_nativeformats); AST_TEST_REGISTER(stream_topology_channel_set); + AST_TEST_REGISTER(stream_write_non_multistream); + AST_TEST_REGISTER(stream_write_multistream); return AST_MODULE_LOAD_SUCCESS; } From 0f4b349d371141316d7237488b57d58c2276ee42 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 23 Feb 2017 15:48:53 -0500 Subject: [PATCH 1081/1578] res_config_pgsql: Fix thread safety problems * A missing AST_LIST_UNLOCK() in find_table() * The ESCAPE_STRING() macro uses pgsqlConn under the hood and we were not consistently locking before calling it. * There were a handful of other places where pgsqlConn was accessed directly without appropriate locking. Change-Id: Iea63f0728f76985a01e95b9912c3c5c6065836ed --- res/res_config_pgsql.c | 130 ++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 33 deletions(-) diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index b5f24b0f4da..93126c6a5da 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -268,6 +268,7 @@ static struct tables *find_table(const char *database, const char *orig_tablenam } if (database == NULL) { + AST_LIST_UNLOCK(&psql_tables); return NULL; } @@ -409,6 +410,16 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab return NULL; } + /* + * Must connect to the server before anything else as ESCAPE_STRING() + * uses pgsqlConn + */ + ast_mutex_lock(&pgsql_lock); + if (!pgsql_reconnect(database)) { + ast_mutex_unlock(&pgsql_lock); + return NULL; + } + /* Get the first parameter and first value in our list of passed paramater/value pairs */ if (!field) { ast_log(LOG_WARNING, @@ -417,6 +428,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab PQfinish(pgsqlConn); pgsqlConn = NULL; } + ast_mutex_unlock(&pgsql_lock); return NULL; } @@ -434,6 +446,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); return NULL; } @@ -452,6 +465,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); return NULL; } @@ -459,8 +473,6 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab } /* We now have our complete statement; Lets connect to the server and execute it. */ - ast_mutex_lock(&pgsql_lock); - if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { ast_mutex_unlock(&pgsql_lock); return NULL; @@ -540,6 +552,16 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char if (!(cfg = ast_config_new())) return NULL; + /* + * Must connect to the server before anything else as ESCAPE_STRING() + * uses pgsqlConn + */ + ast_mutex_lock(&pgsql_lock); + if (!pgsql_reconnect(database)) { + ast_mutex_unlock(&pgsql_lock); + return NULL; + } + /* Get the first parameter and first value in our list of passed paramater/value pairs */ if (!field) { ast_log(LOG_WARNING, @@ -548,6 +570,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char PQfinish(pgsqlConn); pgsqlConn = NULL; } + ast_mutex_unlock(&pgsql_lock); ast_config_destroy(cfg); return NULL; } @@ -573,6 +596,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); ast_config_destroy(cfg); return NULL; } @@ -593,6 +617,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); ast_config_destroy(cfg); return NULL; } @@ -604,10 +629,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char ast_str_append(&sql, 0, " ORDER BY %s", initfield); } - /* We now have our complete statement; Lets connect to the server and execute it. */ - ast_mutex_lock(&pgsql_lock); - if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) { ast_mutex_unlock(&pgsql_lock); ast_config_destroy(cfg); @@ -704,6 +726,16 @@ static int update_pgsql(const char *database, const char *tablename, const char return -1; } + /* + * Must connect to the server before anything else as ESCAPE_STRING() + * uses pgsqlConn + */ + ast_mutex_lock(&pgsql_lock); + if (!pgsql_reconnect(database)) { + ast_mutex_unlock(&pgsql_lock); + return -1; + } + /* Get the first parameter and first value in our list of passed paramater/value pairs */ if (!field) { ast_log(LOG_WARNING, @@ -712,6 +744,7 @@ static int update_pgsql(const char *database, const char *tablename, const char PQfinish(pgsqlConn); pgsqlConn = NULL; } + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -725,6 +758,7 @@ static int update_pgsql(const char *database, const char *tablename, const char if (!column) { ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", field->name, tablename); + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -735,6 +769,7 @@ static int update_pgsql(const char *database, const char *tablename, const char ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -749,6 +784,7 @@ static int update_pgsql(const char *database, const char *tablename, const char ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -760,6 +796,7 @@ static int update_pgsql(const char *database, const char *tablename, const char ESCAPE_STRING(escapebuf, lookup); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", lookup); + ast_mutex_unlock(&pgsql_lock); return -1; } @@ -768,8 +805,6 @@ static int update_pgsql(const char *database, const char *tablename, const char ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql)); /* We now have our complete statement; Lets connect to the server and execute it. */ - ast_mutex_lock(&pgsql_lock); - if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { ast_mutex_unlock(&pgsql_lock); return -1; @@ -836,12 +871,23 @@ static int update2_pgsql(const char *database, const char *tablename, const stru return -1; } + /* + * Must connect to the server before anything else as ESCAPE_STRING() + * uses pgsqlConn + */ + ast_mutex_lock(&pgsql_lock); + if (!pgsql_reconnect(database)) { + ast_mutex_unlock(&pgsql_lock); + return -1; + } + ast_str_set(&sql, 0, "UPDATE %s SET", tablename); ast_str_set(&where, 0, " WHERE"); for (field = lookup_fields; field; field = field->next) { if (!find_column(table, field->name)) { ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", field->name, tablename, database); + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -849,6 +895,7 @@ static int update2_pgsql(const char *database, const char *tablename, const stru ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -863,6 +910,7 @@ static int update2_pgsql(const char *database, const char *tablename, const stru PQfinish(pgsqlConn); pgsqlConn = NULL; } + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -879,6 +927,7 @@ static int update2_pgsql(const char *database, const char *tablename, const stru ESCAPE_STRING(escapebuf, field->value); if (pgresult) { ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value); + ast_mutex_unlock(&pgsql_lock); release_table(table); return -1; } @@ -892,7 +941,7 @@ static int update2_pgsql(const char *database, const char *tablename, const stru ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql)); - /* We now have our complete statement; connect to the server and execute it. */ + /* We now have our complete statement; Lets connect to the server and execute it. */ if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { ast_mutex_unlock(&pgsql_lock); return -1; @@ -937,6 +986,16 @@ static int store_pgsql(const char *database, const char *table, const struct ast return -1; } + /* + * Must connect to the server before anything else as ESCAPE_STRING() + * uses pgsqlConn + */ + ast_mutex_lock(&pgsql_lock); + if (!pgsql_reconnect(database)) { + ast_mutex_unlock(&pgsql_lock); + return -1; + } + /* Get the first parameter and first value in our list of passed paramater/value pairs */ if (!field) { ast_log(LOG_WARNING, @@ -945,12 +1004,6 @@ static int store_pgsql(const char *database, const char *table, const struct ast PQfinish(pgsqlConn); pgsqlConn = NULL; } - return -1; - } - - /* Must connect to the server before anything else, as the escape function requires the connection handle.. */ - ast_mutex_lock(&pgsql_lock); - if (!pgsql_reconnect(database)) { ast_mutex_unlock(&pgsql_lock); return -1; } @@ -971,6 +1024,7 @@ static int store_pgsql(const char *database, const char *table, const struct ast ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1)); + /* We now have our complete statement; Lets connect to the server and execute it. */ if (pgsql_exec(database, table, ast_str_buffer(sql1), &result) != 0) { ast_mutex_unlock(&pgsql_lock); return -1; @@ -1014,28 +1068,28 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke return -1; } + /* + * Must connect to the server before anything else as ESCAPE_STRING() + * uses pgsqlConn + */ + ast_mutex_lock(&pgsql_lock); + if (!pgsql_reconnect(database)) { + ast_mutex_unlock(&pgsql_lock); + return -1; + } + /* Get the first parameter and first value in our list of passed paramater/value pairs */ - /*newparam = va_arg(ap, const char *); - newval = va_arg(ap, const char *); - if (!newparam || !newval) {*/ if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup)) { ast_log(LOG_WARNING, "PostgreSQL RealTime: Realtime destroy requires at least 1 parameter and 1 value to search on.\n"); if (pgsqlConn) { PQfinish(pgsqlConn); pgsqlConn = NULL; - }; - return -1; - } - - /* Must connect to the server before anything else, as the escape function requires the connection handle.. */ - ast_mutex_lock(&pgsql_lock); - if (!pgsql_reconnect(database)) { + } ast_mutex_unlock(&pgsql_lock); return -1; } - /* Create the first part of the query using the first parameter/value pairs we just extracted If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */ @@ -1050,10 +1104,11 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql)); - if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) { + /* We now have our complete statement; Lets connect to the server and execute it. */ + if (pgsql_exec(database, table, ast_str_buffer(sql), &result) != 0) { ast_mutex_unlock(&pgsql_lock); - return -1; - } + return -1; + } numrows = atoi(PQcmdTuples(result)); ast_mutex_unlock(&pgsql_lock); @@ -1266,7 +1321,7 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm); if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { - ast_mutex_unlock(&pgsql_lock); + ast_mutex_unlock(&pgsql_lock); return -1; } @@ -1393,6 +1448,7 @@ static int parse_config(int is_reload) ast_mutex_lock(&pgsql_lock); + /* XXX: Why would we do this before we're ready to establish a new connection? */ if (pgsqlConn) { PQfinish(pgsqlConn); pgsqlConn = NULL; @@ -1500,13 +1556,18 @@ static int pgsql_reconnect(const char *database) /* mutex lock should have been locked before calling this function. */ - if (pgsqlConn && PQstatus(pgsqlConn) != CONNECTION_OK) { + if (pgsqlConn) { + if (PQstatus(pgsqlConn) == CONNECTION_OK) { + /* We're good? */ + return 1; + } + PQfinish(pgsqlConn); pgsqlConn = NULL; } /* DB password can legitimately be 0-length */ - if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) { + if ((!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) { struct ast_str *conn_info = ast_str_create(128); if (!conn_info) { @@ -1606,7 +1667,7 @@ static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, char connection_info[256]; char credentials[100] = ""; char buf[376]; /* 256+100+"Connected to "+" for "+NULL */ - int ctimesec = time(NULL) - connect_time; + int is_connected = 0, ctimesec = time(NULL) - connect_time; switch (cmd) { case CLI_INIT: @@ -1632,8 +1693,11 @@ static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, if (!ast_strlen_zero(dbuser)) snprintf(credentials, sizeof(credentials), " with username %s", dbuser); + ast_mutex_lock(&pgsql_lock); + is_connected = (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK); + ast_mutex_unlock(&pgsql_lock); - if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) { + if (is_connected) { snprintf(buf, sizeof(buf), "Connected to %s%s for ", connection_info, credentials); ast_cli_print_timestr_fromseconds(a->fd, ctimesec, buf); return CLI_SUCCESS; From b0067bcf2c64660e3499f8d2f06e7874ab627898 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 23 Feb 2017 14:49:17 -0700 Subject: [PATCH 1082/1578] build: Execute ldconfig to build cache. (take two) On some platforms a multiarch approach is used for libraries. The build system does not take this into account and still places libraries into the lib directory if no --libdir is specified to configure. On initial startup this results in libasteriskssl.so not being found, as it is not in the multiarch lib directory. To make matters worse, options were being passed to ldconfig on both Linux and FreeBSD that actually prevented the rebuild of the cache. * Fedora has a /usr/share/config.site that automatically tells autoconf to use /usr/lib64 but CentOS does not. This logic was copied to configure.ac and modified so systems like Ubuntu, which still use /usr/lib for 64-bit systems, aren't affected. Now that we have them in the correct directory... In order for the system loader to find libasteriskssl and libasteriskpj, one of 3 things has to happen... - The linker cache must be rebuilt including the directory where the libasterisk* libraries were installed. Only root can rebuild the cache. This was busted. - We have to link the asterisk binary with an rpath pointing to the directrory where the libasterisk* libraries were installed. This makes things very complicated and will happen over the collective dead bodies of everyone who's had to package a distribution with an rpath. - Finally, you can start asterisk with LD_LIBRARY_PATH set to the directrory where the libasterisk* libraries were installed. There are no other options. So... * The invokation of ldconfig has been moved from main/Makefile to ASTTOPDIR/Makefile, the options have been removed, and DESTDIR/ASTLIBDIR appended. If you aren't root, you will be warned after the "Asterisk Installation Compete" banner that you must re-run 'make install' as root, manually run 'ldconfig DESTDIR/ASTLIBDIR' as root, or run asterisk with LD_LIBRARY_PATH. ASTERISK-26705 Change-Id: I2a64b7c33a7d3e9bde20f47e3d3ab771977af982 --- Makefile | 29 ++++++++++++++++++++++------- configure | 22 ++++++++++++++++++++++ configure.ac | 21 +++++++++++++++++++++ main/Makefile | 6 ------ 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 8e237e1fda7..80845d5ab83 100644 --- a/Makefile +++ b/Makefile @@ -182,11 +182,6 @@ OTHER_SUBDIR_CFLAGS="-I$(ASTTOPDIR)/include" # Create OPTIONS variable, but probably we can assign directly to ASTCFLAGS OPTIONS= -ifeq ($(OSARCH),linux-gnu) - # flag to tell 'ldconfig' to only process specified directories - LDCONFIG_FLAGS=-n -endif - ifeq ($(findstring -save-temps,$(_ASTCFLAGS) $(ASTCFLAGS)),) ifeq ($(findstring -pipe,$(_ASTCFLAGS) $(ASTCFLAGS)),) _ASTCFLAGS+=-pipe @@ -222,8 +217,6 @@ ifeq ($(OSARCH),FreeBSD) # -V is understood by BSD Make, not by GNU make. BSDVERSION=$(shell make -V OSVERSION -f /usr/share/mk/bsd.port.subdir.mk) _ASTCFLAGS+=$(shell if test $(BSDVERSION) -lt 500016 ; then echo "-D_THREAD_SAFE"; fi) - # flag to tell 'ldconfig' to only process specified directories - LDCONFIG_FLAGS=-m endif ifeq ($(OSARCH),NetBSD) @@ -642,6 +635,23 @@ oldmodcheck: echo " WARNING WARNING WARNING" ;\ fi +ld-cache-update: +ifneq ($(LDCONFIG),) + @if [ $${EUID} -eq 0 ] ; then \ + $(LDCONFIG) "$(DESTDIR)$(ASTLIBDIR)/" ; \ + else \ + echo " WARNING WARNING WARNING" ;\ + echo "" ;\ + echo " You cannot rebuild the system linker cache unless you are root. " ;\ + echo " You MUST do one of the follwing..." ;\ + echo " * Re-run 'make install' as root. " ;\ + echo " * Run 'ldconfig $(DESTDIR)$(ASTLIBDIR)' as root. " ;\ + echo " * Run asterisk with 'LD_LIBRARY_PATH=$(DESTDIR)$(ASTLIBDIR) asterisk' " ;\ + echo "" ;\ + echo " WARNING WARNING WARNING" ;\ + fi +endif + badshell: ifneq ($(filter ~%,$(DESTDIR)),) @echo "Your shell doesn't do ~ expansion when expected (specifically, when doing \"make install DESTDIR=~/path\")." @@ -680,6 +690,7 @@ install: badshell bininstall datafiles @echo " + doxygen installed on your local system +" @echo " +-------------------------------------------+" @$(MAKE) -s oldmodcheck + @$(MAKE) -s ld-cache-update isntall: install @@ -912,6 +923,9 @@ ifeq ($(HAVE_DAHDI),1) rm -f $(DESTDIR)$(DAHDI_UDEV_HOOK_DIR)/40-asterisk endif $(MAKE) -C sounds uninstall +ifneq ($(LDCONFIG),) + $(LDCONFIG) || : +endif uninstall: _uninstall @echo " +--------- Asterisk Uninstall Complete -----+" @@ -1042,6 +1056,7 @@ check-alembic: makeopts .PHONY: ari-stubs .PHONY: basic-pbx .PHONY: check-alembic +.PHONY: ld-cache-update .PHONY: $(SUBDIRS_INSTALL) .PHONY: $(SUBDIRS_DIST_CLEAN) .PHONY: $(SUBDIRS_CLEAN) diff --git a/configure b/configure index 42a21d7c587..0c2d84ee195 100755 --- a/configure +++ b/configure @@ -4892,6 +4892,28 @@ if test ${prefix} = ${ac_default_prefix} || test ${prefix} = 'NONE'; then fi fi +# +# The following code for detecting lib64 was taken from Fedora's +# /usr/share/config.site with a modification to check that the +# /usr/lib64 directory actually exists. This prevents libdir from +# being set to /usr/lib64 on 64-bit systems that still use /usr/lib. +# +if test "$prefix" = /usr ||\ + { test "$prefix" = NONE && test "$ac_default_prefix" = /usr ; } +then + for i in x86_64 ppc64 s390x aarch64; do + if test $host_cpu = $i; then + if test "$libdir" = '${exec_prefix}/lib' &&\ + { test -d "${exec_prefix}/lib64" || test -d "${ac_default_prefix}/lib64" ; } ; then + libdir='${exec_prefix}/lib64' + { $as_echo "$as_me:${as_lineno-$LINENO}: Setting libdir=${libdir} " >&5 +$as_echo "$as_me: Setting libdir=${libdir} " >&6;} + fi + break + fi + done +fi + BUILD_PLATFORM=${build} BUILD_CPU=${build_cpu} BUILD_VENDOR=${build_vendor} diff --git a/configure.ac b/configure.ac index fff8ecf7e6a..beb151a20b8 100644 --- a/configure.ac +++ b/configure.ac @@ -135,6 +135,27 @@ if test ${prefix} = ${ac_default_prefix} || test ${prefix} = 'NONE'; then fi fi +# +# The following code for detecting lib64 was taken from Fedora's +# /usr/share/config.site with a modification to check that the +# /usr/lib64 directory actually exists. This prevents libdir from +# being set to /usr/lib64 on 64-bit systems that still use /usr/lib. +# +if test "$prefix" = /usr ||\ + { test "$prefix" = NONE && test "$ac_default_prefix" = /usr ; } +then + for i in x86_64 ppc64 s390x aarch64; do + if test $host_cpu = $i; then + if test "$libdir" = '${exec_prefix}/lib' &&\ + { test -d "${exec_prefix}/lib64" || test -d "${ac_default_prefix}/lib64" ; } ; then + libdir='${exec_prefix}/lib64' + AC_MSG_NOTICE([ Setting libdir=${libdir} ]) + fi + break + fi + done +fi + BUILD_PLATFORM=${build} BUILD_CPU=${build_cpu} BUILD_VENDOR=${build_vendor} diff --git a/main/Makefile b/main/Makefile index 4d1b2c41bd2..d3463f7b6a8 100644 --- a/main/Makefile +++ b/main/Makefile @@ -353,9 +353,6 @@ ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin else # Darwin $(INSTALL) -m 755 $(ASTPJ_LIB) "$(DESTDIR)$(ASTLIBDIR)/" endif -endif -ifneq ($(LDCONFIG),) - $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" endif $(LN) -sf asterisk "$(DESTDIR)$(ASTSBINDIR)/rasterisk" @@ -372,9 +369,6 @@ ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB).$(ASTPJ_SO_VERSION)" || : rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" endif -ifneq ($(LDCONFIG),) - $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" -endif clean:: rm -f asterisk libasteriskssl.o From a537dae6d0a20ead92a9fce08ac6aeef342d91b7 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 9 Feb 2017 17:05:01 -0700 Subject: [PATCH 1083/1578] pjproject_bundled: Update for pjproject 2.6 * Removed all 2.5.5 functional patches. * Updated usages of pj_release_pool to be "safe". * Updated configure options to disable webrtc. * Updated config_site.h to disable webrtc in pjmedia. * Added Richard Mudgett's recent resolver patches. Change-Id: Ib400cc4dfca68b3d07ce14d314e829bfddc252c7 --- res/res_pjsip.c | 7 +- res/res_pjsip_history.c | 7 +- res/res_rtp_asterisk.c | 11 +- third-party/pjproject/Makefile.rules | 4 +- .../patches/0000-remove-third-party.patch | 49 ++-- ...-r5397-pjsip_generic_array_max_count.patch | 58 ----- .../0001-r5400-pjsip_tx_data_dec_ref.patch | 24 -- ...einitialization-of-uninitialized-cli.patch | 56 ----- ...-r5435-add-pjsip_inv_session-ref_cnt.patch | 212 ------------------ .../0003-r5403-pjsip_IPV6_V6ONLY.patch | 13 -- ...nt-SERVFAIL-from-marking-name-server.patch | 48 ---- ...h-on-using-an-already-destroyed-SSL-.patch | 164 -------------- ...-backport-Various-fixes-for-DNS-IPv6.patch | 134 ----------- ...r5473-svn-backport-Fix-pending-query.patch | 28 --- ...-svn-backport-Remove-DNS-cache-entry.patch | 70 ------ ...ckport-Fix-DNS-write-on-freed-memory.patch | 33 --- ...-t-trigger-SRV-complete-callback-whe.patch | 59 ----- third-party/pjproject/patches/README | 7 + third-party/pjproject/patches/config_site.h | 6 + third-party/versions.mak | 2 +- 20 files changed, 57 insertions(+), 935 deletions(-) delete mode 100644 third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch delete mode 100644 third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch delete mode 100644 third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch delete mode 100644 third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch delete mode 100644 third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch delete mode 100644 third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch delete mode 100644 third-party/pjproject/patches/0005-Re-1969-Fix-crash-on-using-an-already-destroyed-SSL-.patch delete mode 100644 third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch delete mode 100644 third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch delete mode 100644 third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch delete mode 100644 third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch delete mode 100644 third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch create mode 100644 third-party/pjproject/patches/README diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 4dead21f5bb..9782cc99766 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4448,8 +4448,13 @@ static int unload_pjsip(void *data) } if (memory_pool) { - pj_pool_release(memory_pool); + /* This mimics the behavior of pj_pool_safe_release + * which was introduced in pjproject 2.6. + */ + pj_pool_t *temp_pool = memory_pool; + memory_pool = NULL; + pj_pool_release(temp_pool); } ast_pjsip_endpoint = NULL; diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c index 853ba319eac..4e7dbd00713 100644 --- a/res/res_pjsip_history.c +++ b/res/res_pjsip_history.c @@ -606,8 +606,13 @@ static void pjsip_history_entry_dtor(void *obj) struct pjsip_history_entry *entry = obj; if (entry->pool) { - pj_pool_release(entry->pool); + /* This mimics the behavior of pj_pool_safe_release + * which was introduced in pjproject 2.6. + */ + pj_pool_t *temp_pool = entry->pool; + entry->pool = NULL; + pj_pool_release(temp_pool); } } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 5d7adcd4386..28ddeca4206 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1053,7 +1053,16 @@ static void rtp_ioqueue_thread_destroy(struct ast_rtp_ioqueue_thread *ioqueue) pj_thread_destroy(ioqueue->thread); } - pj_pool_release(ioqueue->pool); + if (ioqueue->pool) { + /* This mimics the behavior of pj_pool_safe_release + * which was introduced in pjproject 2.6. + */ + pj_pool_t *temp_pool = ioqueue->pool; + + ioqueue->pool = NULL; + pj_pool_release(temp_pool); + } + ast_free(ioqueue); } diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index ae4b6a5f9ee..e8eb46643e4 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -12,7 +12,6 @@ PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ --disable-g722-codec \ --disable-g7221-codec \ --disable-opencore-amr \ - --disable-webrtc \ --disable-silk \ --disable-opus \ --disable-video \ @@ -26,7 +25,8 @@ PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ --disable-openh264 \ --disable-ipp \ --without-external-pa \ - --without-external-srtp + --without-external-srtp \ + --without-external-webrtc ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),) PJPROJECT_CONFIG_OPTS += --disable-resample --disable-g711-codec diff --git a/third-party/pjproject/patches/0000-remove-third-party.patch b/third-party/pjproject/patches/0000-remove-third-party.patch index 2e3bb5f9fcf..81c53a0c3df 100644 --- a/third-party/pjproject/patches/0000-remove-third-party.patch +++ b/third-party/pjproject/patches/0000-remove-third-party.patch @@ -1,21 +1,14 @@ diff --git a/build.mak.in b/build.mak.in -index 802211c..25fd05e 100644 +index eb28663..83024ef 100644 --- a/build.mak.in +++ b/build.mak.in -@@ -1,4 +1,3 @@ +@@ -1,6 +1,5 @@ -export PJDIR := @ac_pjdir@ include $(PJDIR)/version.mak export PJ_DIR := $(PJDIR) -@@ -9,7 +8,7 @@ export HOST_NAME := unix - export CC_NAME := gcc - export TARGET_NAME := @target@ - export CROSS_COMPILE := @ac_cross_compile@ --export LINUX_POLL := @ac_linux_poll@ -+export LINUX_POLL := @ac_linux_poll@ - export SHLIB_SUFFIX := @ac_shlib_suffix@ - - export prefix := @prefix@ + # @configure_input@ + export MACHINE_NAME := auto @@ -28,19 +27,6 @@ export APP_THIRD_PARTY_EXT := export APP_THIRD_PARTY_LIBS := export APP_THIRD_PARTY_LIB_FILES := @@ -36,7 +29,7 @@ index 802211c..25fd05e 100644 ifeq (@ac_pjmedia_resample@,libresample) APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX) ifeq ($(PJ_SHARED_LIBRARIES),) -@@ -57,85 +43,6 @@ APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFI +@@ -57,99 +43,6 @@ APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFI endif endif @@ -118,25 +111,21 @@ index 802211c..25fd05e 100644 -endif -endif - +-ifneq (@ac_no_webrtc@,1) +-ifeq (@ac_external_webrtc@,1) +-APP_THIRD_PARTY_EXT += -lwebrtc +-else +-APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libwebrtc-$(LIB_SUFFIX) +-ifeq ($(PJ_SHARED_LIBRARIES),) +-APP_THIRD_PARTY_LIBS += -lwebrtc-$(TARGET_NAME) +-else +-APP_THIRD_PARTY_LIBS += -lwebrtc +-APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libwebrtc.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libwebrtc.$(SHLIB_SUFFIX) +-endif +-endif +-endif +- - # Additional flags @ac_build_mak_vars@ -@@ -149,7 +56,7 @@ SDL_CFLAGS = @ac_sdl_cflags@ - SDL_LDFLAGS = @ac_sdl_ldflags@ - - # FFMPEG flags --FFMPEG_CFLAGS = @ac_ffmpeg_cflags@ -+FFMPEG_CFLAGS = @ac_ffmpeg_cflags@ - FFMPEG_LDFLAGS = @ac_ffmpeg_ldflags@ - - # Video4Linux2 -@@ -157,7 +64,7 @@ V4L2_CFLAGS = @ac_v4l2_cflags@ - V4L2_LDFLAGS = @ac_v4l2_ldflags@ - - # OPENH264 flags --OPENH264_CFLAGS = @ac_openh264_cflags@ -+OPENH264_CFLAGS = @ac_openh264_cflags@ - OPENH264_LDFLAGS = @ac_openh264_ldflags@ - - # QT diff --git a/third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch b/third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch deleted file mode 100644 index 3cc328afe36..00000000000 --- a/third-party/pjproject/patches/0001-r5397-pjsip_generic_array_max_count.patch +++ /dev/null @@ -1,58 +0,0 @@ -This patch updates array limit checks and docs -in pjsip_evsub_register_pkg() and pjsip_endpt_add_capability(). - -Index: pjsip/include/pjsip/sip_endpoint.h -=================================================================== ---- a/pjsip/include/pjsip/sip_endpoint.h (revision 5396) -+++ b/pjsip/include/pjsip/sip_endpoint.h (revision 5397) -@@ -583,7 +583,8 @@ - * @param hname If htype specifies PJSIP_H_OTHER, then the header name - * must be supplied in this argument. Otherwise the value - * must be set to NULL. -- * @param count The number of tags in the array. -+ * @param count The number of tags in the array. The value must not -+ * be greater than PJSIP_GENERIC_ARRAY_MAX_COUNT. - * @param tags Array of tags describing the capabilities or extensions - * to be added to the appropriate header. - * -Index: pjsip/include/pjsip-simple/evsub.h -=================================================================== ---- a/pjsip/include/pjsip-simple/evsub.h (revision 5396) -+++ b/pjsip/include/pjsip-simple/evsub.h (revision 5397) -@@ -246,7 +246,8 @@ - * registered. - * @param event_name Event package identification. - * @param expires Default subscription expiration time, in seconds. -- * @param accept_cnt Number of strings in Accept array. -+ * @param accept_cnt Number of strings in Accept array. The value must -+ * not be greater than PJSIP_GENERIC_ARRAY_MAX_COUNT. - * @param accept Array of Accept value. - * - * @return PJ_SUCCESS on success. -Index: pjsip/src/pjsip/sip_endpoint.c -=================================================================== ---- a/pjsip/src/pjsip/sip_endpoint.c (revision 5396) -+++ b/pjsip/src/pjsip/sip_endpoint.c (revision 5397) -@@ -371,6 +371,7 @@ - - /* Check arguments. */ - PJ_ASSERT_RETURN(endpt!=NULL && count>0 && tags, PJ_EINVAL); -+ PJ_ASSERT_RETURN(count <= PJSIP_GENERIC_ARRAY_MAX_COUNT, PJ_ETOOMANY); - PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT || - htype==PJSIP_H_ALLOW || - htype==PJSIP_H_SUPPORTED, -Index: pjsip/src/pjsip-simple/evsub.c -=================================================================== ---- a/pjsip/src/pjsip-simple/evsub.c (revision 5396) -+++ b/pjsip/src/pjsip-simple/evsub.c (revision 5397) -@@ -412,7 +412,9 @@ - unsigned i; - - PJ_ASSERT_RETURN(pkg_mod && event_name, PJ_EINVAL); -- PJ_ASSERT_RETURN(accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values), -+ -+ /* Make sure accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values) */ -+ PJ_ASSERT_RETURN(accept_cnt <= PJSIP_GENERIC_ARRAY_MAX_COUNT, - PJ_ETOOMANY); - - /* Make sure evsub module has been initialized */ diff --git a/third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch b/third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch deleted file mode 100644 index b5c11db4535..00000000000 --- a/third-party/pjproject/patches/0001-r5400-pjsip_tx_data_dec_ref.patch +++ /dev/null @@ -1,24 +0,0 @@ -This patch fixes the issue in pjsip_tx_data_dec_ref() -when tx_data_destroy can be called more than once, -and checks if invalid value (e.g. NULL) is passed to. - -Index: pjsip/src/pjsip/sip_transport.c -=================================================================== ---- a/pjsip/src/pjsip/sip_transport.c (revision 5399) -+++ b/pjsip/src/pjsip/sip_transport.c (revision 5400) -@@ -491,8 +491,13 @@ - */ - PJ_DEF(pj_status_t) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata ) - { -- pj_assert( pj_atomic_get(tdata->ref_cnt) > 0); -- if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) { -+ pj_atomic_value_t ref_cnt; -+ -+ PJ_ASSERT_RETURN(tdata && tdata->ref_cnt, PJ_EINVAL); -+ -+ ref_cnt = pj_atomic_dec_and_get(tdata->ref_cnt); -+ pj_assert( ref_cnt >= 0); -+ if (ref_cnt == 0) { - tx_data_destroy(tdata); - return PJSIP_EBUFDESTROYED; - } else { diff --git a/third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch b/third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch deleted file mode 100644 index c4288a389d5..00000000000 --- a/third-party/pjproject/patches/0002-Fix-1946-Avoid-deinitialization-of-uninitialized-cli.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 33fd755e819dc85a96718abc0ae26a9b46f14800 Mon Sep 17 00:00:00 2001 -From: nanang -Date: Thu, 28 Jul 2016 08:21:45 +0000 -Subject: [PATCH 2/3] Fix #1946: Avoid deinitialization of uninitialized client - auth session. - ---- - pjsip/src/pjsip/sip_dialog.c | 18 ++++++------------ - 1 file changed, 6 insertions(+), 12 deletions(-) - -diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c -index f03885d..421ddc4 100644 ---- a/pjsip/src/pjsip/sip_dialog.c -+++ b/pjsip/src/pjsip/sip_dialog.c -@@ -92,6 +92,12 @@ static pj_status_t create_dialog( pjsip_user_agent *ua, - pj_list_init(&dlg->inv_hdr); - pj_list_init(&dlg->rem_cap_hdr); - -+ /* Init client authentication session. */ -+ status = pjsip_auth_clt_init(&dlg->auth_sess, dlg->endpt, -+ dlg->pool, 0); -+ if (status != PJ_SUCCESS) -+ goto on_error; -+ - status = pj_mutex_create_recursive(pool, dlg->obj_name, &dlg->mutex_); - if (status != PJ_SUCCESS) - goto on_error; -@@ -283,12 +289,6 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua, - /* Initial route set is empty. */ - pj_list_init(&dlg->route_set); - -- /* Init client authentication session. */ -- status = pjsip_auth_clt_init(&dlg->auth_sess, dlg->endpt, -- dlg->pool, 0); -- if (status != PJ_SUCCESS) -- goto on_error; -- - /* Register this dialog to user agent. */ - status = pjsip_ua_register_dlg( ua, dlg ); - if (status != PJ_SUCCESS) -@@ -506,12 +506,6 @@ pj_status_t create_uas_dialog( pjsip_user_agent *ua, - } - dlg->route_set_frozen = PJ_TRUE; - -- /* Init client authentication session. */ -- status = pjsip_auth_clt_init(&dlg->auth_sess, dlg->endpt, -- dlg->pool, 0); -- if (status != PJ_SUCCESS) -- goto on_error; -- - /* Increment the dialog's lock since tsx may cause the dialog to be - * destroyed prematurely (such as in case of transport error). - */ --- -2.7.4 - diff --git a/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch b/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch deleted file mode 100644 index 12ae6a0285f..00000000000 --- a/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch +++ /dev/null @@ -1,212 +0,0 @@ -When a transport error occured on an INVITE session -the stack calls on_tsx_state_changed with new state -PJSIP_INV_STATE_DISCONNECTED and immediately destroys -the INVITE session. -At the same time this INVITE session could being processed -on another thread. This thread could use the session's -memory pools which were already freed, so we get segfault. - -This patch adds a reference counter and new functions: -pjsip_inv_add_ref and pjsip_inv_dec_ref. -The INVITE session is destroyed only when the reference -counter has reached zero. - -To avoid race condition an application should call -pjsip_inv_add_ref/pjsip_inv_dec_ref. - -Index: pjsip/include/pjsip-ua/sip_inv.h -=================================================================== ---- a/pjsip/include/pjsip-ua/sip_inv.h (revision 5434) -+++ b/pjsip/include/pjsip-ua/sip_inv.h (revision 5435) -@@ -383,6 +383,11 @@ - * Other applications that want to use these pools must understand - * that the flip-flop pool's lifetimes are synchronized to the - * SDP offer-answer negotiation. -+ * -+ * The lifetime of this session is controlled by the reference counter in this -+ * structure, which is manipulated by calling #pjsip_inv_add_ref and -+ * #pjsip_inv_dec_ref. When the reference counter has reached zero, then -+ * this session will be destroyed. - */ - struct pjsip_inv_session - { -@@ -412,6 +417,7 @@ - struct pjsip_timer *timer; /**< Session Timers. */ - pj_bool_t following_fork; /**< Internal, following - forked media? */ -+ pj_atomic_t *ref_cnt; /**< Reference counter. */ - }; - - -@@ -631,6 +637,30 @@ - - - /** -+ * Add reference counter to the INVITE session. The reference counter controls -+ * the life time of the session, ie. when the counter reaches zero, then it -+ * will be destroyed. -+ * -+ * @param inv The INVITE session. -+ * @return PJ_SUCCESS if the INVITE session reference counter -+ * was increased. -+ */ -+PJ_DECL(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv ); -+ -+/** -+ * Decrement reference counter of the INVITE session. -+ * When the session is no longer used, it will be destroyed and -+ * caller is informed with PJ_EGONE return status. -+ * -+ * @param inv The INVITE session. -+ * @return PJ_SUCCESS if the INVITE session reference counter -+ * was decreased. A status PJ_EGONE will be returned to -+ * inform that session is destroyed. -+ */ -+PJ_DECL(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv ); -+ -+ -+/** - * Forcefully terminate and destroy INVITE session, regardless of - * the state of the session. Note that this function should only be used - * when there is failure in the INVITE session creation. After the -Index: pjsip/src/pjsip-ua/sip_inv.c -=================================================================== ---- a/pjsip/src/pjsip-ua/sip_inv.c (revision 5434) -+++ b/pjsip/src/pjsip-ua/sip_inv.c (revision 5435) -@@ -195,6 +195,65 @@ - } - - /* -+ * Add reference to INVITE session. -+ */ -+PJ_DEF(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv ) -+{ -+ PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL); -+ -+ pj_atomic_inc(inv->ref_cnt); -+ -+ return PJ_SUCCESS; -+} -+ -+static void inv_session_destroy(pjsip_inv_session *inv) -+{ -+ if (inv->last_ack) { -+ pjsip_tx_data_dec_ref(inv->last_ack); -+ inv->last_ack = NULL; -+ } -+ if (inv->invite_req) { -+ pjsip_tx_data_dec_ref(inv->invite_req); -+ inv->invite_req = NULL; -+ } -+ if (inv->pending_bye) { -+ pjsip_tx_data_dec_ref(inv->pending_bye); -+ inv->pending_bye = NULL; -+ } -+ pjsip_100rel_end_session(inv); -+ pjsip_timer_end_session(inv); -+ pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); -+ -+ /* Release the flip-flop pools */ -+ pj_pool_release(inv->pool_prov); -+ inv->pool_prov = NULL; -+ pj_pool_release(inv->pool_active); -+ inv->pool_active = NULL; -+ -+ pj_atomic_destroy(inv->ref_cnt); -+ inv->ref_cnt = NULL; -+} -+ -+/* -+ * Decrease INVITE session reference, destroy it when the reference count -+ * reaches zero. -+ */ -+PJ_DEF(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv ) -+{ -+ pj_atomic_value_t ref_cnt; -+ -+ PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL); -+ -+ ref_cnt = pj_atomic_dec_and_get(inv->ref_cnt); -+ pj_assert( ref_cnt >= 0); -+ if (ref_cnt == 0) { -+ inv_session_destroy(inv); -+ return PJ_EGONE; -+ } -+ return PJ_SUCCESS; -+} -+ -+/* - * Set session state. - */ - static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state, -@@ -261,27 +320,7 @@ - if (inv->state == PJSIP_INV_STATE_DISCONNECTED && - prev_state != PJSIP_INV_STATE_DISCONNECTED) - { -- if (inv->last_ack) { -- pjsip_tx_data_dec_ref(inv->last_ack); -- inv->last_ack = NULL; -- } -- if (inv->invite_req) { -- pjsip_tx_data_dec_ref(inv->invite_req); -- inv->invite_req = NULL; -- } -- if (inv->pending_bye) { -- pjsip_tx_data_dec_ref(inv->pending_bye); -- inv->pending_bye = NULL; -- } -- pjsip_100rel_end_session(inv); -- pjsip_timer_end_session(inv); -- pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); -- -- /* Release the flip-flop pools */ -- pj_pool_release(inv->pool_prov); -- inv->pool_prov = NULL; -- pj_pool_release(inv->pool_active); -- inv->pool_active = NULL; -+ pjsip_inv_dec_ref(inv); - } - } - -@@ -838,6 +877,12 @@ - inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session); - pj_assert(inv != NULL); - -+ status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt); -+ if (status != PJ_SUCCESS) { -+ pjsip_dlg_dec_lock(dlg); -+ return status; -+ } -+ - inv->pool = dlg->pool; - inv->role = PJSIP_ROLE_UAC; - inv->state = PJSIP_INV_STATE_NULL; -@@ -881,6 +926,7 @@ - pjsip_100rel_attach(inv); - - /* Done */ -+ pjsip_inv_add_ref(inv); - *p_inv = inv; - - pjsip_dlg_dec_lock(dlg); -@@ -1471,6 +1517,12 @@ - inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session); - pj_assert(inv != NULL); - -+ status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt); -+ if (status != PJ_SUCCESS) { -+ pjsip_dlg_dec_lock(dlg); -+ return status; -+ } -+ - inv->pool = dlg->pool; - inv->role = PJSIP_ROLE_UAS; - inv->state = PJSIP_INV_STATE_NULL; -@@ -1540,6 +1592,7 @@ - } - - /* Done */ -+ pjsip_inv_add_ref(inv); - pjsip_dlg_dec_lock(dlg); - *p_inv = inv; - diff --git a/third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch b/third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch deleted file mode 100644 index b324b53f4a9..00000000000 --- a/third-party/pjproject/patches/0003-r5403-pjsip_IPV6_V6ONLY.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- a/pjlib/src/pj/sock_bsd.c -+++ b/pjlib/src/pj/sock_bsd.c -@@ -539,6 +539,10 @@ - pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_NOSIGPIPE(), - &val, sizeof(val)); - } -+ if (af != PJ_AF_INET) { /* Linux Kernel 2.4.21; June 2003 */ -+ pj_sock_setsockopt(*sock, PJ_SOL_IPV6, IPV6_V6ONLY, -+ &val, sizeof(val)); -+ } - #if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ - PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 - if (type == pj_SOCK_DGRAM()) { diff --git a/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch b/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch deleted file mode 100644 index 55f3d2d1526..00000000000 --- a/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch +++ /dev/null @@ -1,48 +0,0 @@ -From a5efddbe9151e9ad99279e59566c86f8bc27d3a9 Mon Sep 17 00:00:00 2001 -From: George Joseph -Date: Wed, 7 Sep 2016 13:10:57 -0600 -Subject: [PATCH] resolver.c: Prevent SERVFAIL from marking name server bad - -A name server that returns "Server Failure" is indicating only that -the server couldn't process that particular request. We should NOT -assume that the name server is incapable of serving other requests. - -Here's the scenario we've been encountering... - -* 2 local name servers configured in resolv.conf. -* An OPTIONS request causes a request for A and AAAA records to go out - to both nameservers. -* The A responses both come back successfully resolved. -* Because of an issue at some upstream nameserver, the AAAA responses - for that particular query come back as "SERVFAIL" from both local - name servers. -* Both local servers are marked as bad and no further queries can be - sent until the 60 second ttl expires. Only previously cached results - can be used. -* In this case, 60 seconds is just enough time for another OPTIONS - request to go out to the same host so the cycle repeats. - -We could set the bad ttl really low but that also affects REFUSED and -NOTAUTH which probably DO signal a real server issue. Besides, even -a really low bad ttl would be an issue on a pbx. ---- - pjlib-util/src/pjlib-util/resolver.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c -index d277e4f..540f88f 100644 ---- a/pjlib-util/src/pjlib-util/resolver.c -+++ b/pjlib-util/src/pjlib-util/resolver.c -@@ -1384,8 +1384,7 @@ static void report_nameserver_status(pj_dns_resolver *resolver, - q_id = (pj_uint32_t)-1; - } - -- if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL || -- rcode == PJ_DNS_RCODE_REFUSED || -+ if (!pkt || rcode == PJ_DNS_RCODE_REFUSED || - rcode == PJ_DNS_RCODE_NOTAUTH) - { - is_good = PJ_FALSE; --- -2.7.4 - diff --git a/third-party/pjproject/patches/0005-Re-1969-Fix-crash-on-using-an-already-destroyed-SSL-.patch b/third-party/pjproject/patches/0005-Re-1969-Fix-crash-on-using-an-already-destroyed-SSL-.patch deleted file mode 100644 index 551e61ab607..00000000000 --- a/third-party/pjproject/patches/0005-Re-1969-Fix-crash-on-using-an-already-destroyed-SSL-.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 9e67e0d5c3fdc747530a956038b374fca4748b76 Mon Sep 17 00:00:00 2001 -From: riza -Date: Thu, 13 Oct 2016 09:02:50 +0000 -Subject: [PATCH 1/4] Re #1969: Fix crash on using an already destroyed SSL - socket. - ---- - pjlib/src/pj/ssl_sock_ossl.c | 66 ++++++++++++++++++++++++++++---------------- - 1 file changed, 42 insertions(+), 24 deletions(-) - -diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c -index fa0db2d..ceab67a 100644 ---- a/pjlib/src/pj/ssl_sock_ossl.c -+++ b/pjlib/src/pj/ssl_sock_ossl.c -@@ -822,7 +822,10 @@ static void close_sockets(pj_ssl_sock_t *ssock) - pj_lock_acquire(ssock->write_mutex); - asock = ssock->asock; - if (asock) { -- ssock->asock = NULL; -+ // Don't set ssock->asock to NULL, as it may trigger assertion in -+ // send operation. This should be safe as active socket will simply -+ // return PJ_EINVALIDOP on any operation if it is already closed. -+ //ssock->asock = NULL; - ssock->sock = PJ_INVALID_SOCKET; - } - sock = ssock->sock; -@@ -841,9 +844,9 @@ static void close_sockets(pj_ssl_sock_t *ssock) - /* Reset SSL socket state */ - static void reset_ssl_sock_state(pj_ssl_sock_t *ssock) - { -+ pj_lock_acquire(ssock->write_mutex); - ssock->ssl_state = SSL_STATE_NULL; -- -- destroy_ssl(ssock); -+ pj_lock_release(ssock->write_mutex); - - close_sockets(ssock); - -@@ -1612,6 +1615,21 @@ static pj_status_t do_handshake(pj_ssl_sock_t *ssock) - return PJ_EPENDING; - } - -+static void ssl_on_destroy(void *arg) -+{ -+ pj_pool_t *pool = NULL; -+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)arg; -+ -+ destroy_ssl(ssock); -+ -+ pj_lock_destroy(ssock->write_mutex); -+ -+ pool = ssock->pool; -+ ssock->pool = NULL; -+ if (pool) -+ pj_pool_release(pool); -+} -+ - - /* - ******************************************************************* -@@ -1830,7 +1848,7 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock, - - /* Create new SSL socket instance */ - status = pj_ssl_sock_create(ssock_parent->pool, -- &ssock_parent->newsock_param, &ssock); -+ &ssock_parent->newsock_param, &ssock); - if (status != PJ_SUCCESS) - goto on_return; - -@@ -1906,12 +1924,10 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock, - if (status != PJ_SUCCESS) - goto on_return; - -- /* Temporarily add ref the group lock until active socket creation, -- * to make sure that group lock is destroyed if the active socket -- * creation fails. -- */ - pj_grp_lock_add_ref(glock); - asock_cfg.grp_lock = ssock->param.grp_lock = glock; -+ pj_grp_lock_add_handler(ssock->param.grp_lock, ssock->pool, ssock, -+ ssl_on_destroy); - } - - pj_bzero(&asock_cb, sizeof(asock_cb)); -@@ -1927,11 +1943,6 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock, - ssock, - &ssock->asock); - -- /* This will destroy the group lock if active socket creation fails */ -- if (asock_cfg.grp_lock) { -- pj_grp_lock_dec_ref(asock_cfg.grp_lock); -- } -- - if (status != PJ_SUCCESS) - goto on_return; - -@@ -2251,17 +2262,26 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool, - /* Create secure socket mutex */ - status = pj_lock_create_recursive_mutex(pool, pool->obj_name, - &ssock->write_mutex); -- if (status != PJ_SUCCESS) -+ if (status != PJ_SUCCESS) { -+ pj_pool_release(pool); - return status; -+ } - - /* Init secure socket param */ - pj_ssl_sock_param_copy(pool, &ssock->param, param); -+ -+ if (ssock->param.grp_lock) { -+ pj_grp_lock_add_ref(ssock->param.grp_lock); -+ pj_grp_lock_add_handler(ssock->param.grp_lock, pool, ssock, -+ ssl_on_destroy); -+ } -+ - ssock->param.read_buffer_size = ((ssock->param.read_buffer_size+7)>>3)<<3; - if (!ssock->param.timer_heap) { - PJ_LOG(3,(ssock->pool->obj_name, "Warning: timer heap is not " - "available. It is recommended to supply one to avoid " -- "a race condition if more than one worker threads " -- "are used.")); -+ "a race condition if more than one worker threads " -+ "are used.")); - } - - /* Finally */ -@@ -2277,8 +2297,6 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool, - */ - PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock) - { -- pj_pool_t *pool; -- - PJ_ASSERT_RETURN(ssock, PJ_EINVAL); - - if (!ssock->pool) -@@ -2290,12 +2308,11 @@ PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock) - } - - reset_ssl_sock_state(ssock); -- pj_lock_destroy(ssock->write_mutex); -- -- pool = ssock->pool; -- ssock->pool = NULL; -- if (pool) -- pj_pool_release(pool); -+ if (ssock->param.grp_lock) { -+ pj_grp_lock_dec_ref(ssock->param.grp_lock); -+ } else { -+ ssl_on_destroy(ssock); -+ } - - return PJ_SUCCESS; - } -@@ -2782,6 +2799,7 @@ pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock, - - /* Start accepting */ - pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param); -+ ssock->newsock_param.grp_lock = NULL; - status = pj_activesock_start_accept(ssock->asock, pool); - if (status != PJ_SUCCESS) - goto on_error; --- -2.7.4 - diff --git a/third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch b/third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch deleted file mode 100644 index 98c33e51105..00000000000 --- a/third-party/pjproject/patches/0006-r5471-svn-backport-Various-fixes-for-DNS-IPv6.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 2ab7a9f67caf73be3f2215473f72882cfaef4972 Mon Sep 17 00:00:00 2001 -From: Richard Mudgett -Date: Fri, 28 Oct 2016 12:11:30 -0500 -Subject: [PATCH 1/3] r5471 svn backport Various fixes for DNS IPv6 - -Fixed #1974: Various fixes for DNS IPv6 ---- - pjlib-util/src/pjlib-util/resolver.c | 11 +++++------ - pjlib-util/src/pjlib-util/srv_resolver.c | 17 +++++++++++++++-- - pjsip/src/pjsip/sip_resolve.c | 14 +++++++------- - 3 files changed, 27 insertions(+), 15 deletions(-) - -diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c -index e5e1bed..d24ef9d 100644 ---- a/pjlib-util/src/pjlib-util/resolver.c -+++ b/pjlib-util/src/pjlib-util/resolver.c -@@ -835,7 +835,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, - pj_time_val now; - struct res_key key; - struct cached_res *cache; -- pj_dns_async_query *q; -+ pj_dns_async_query *q, *p_q = NULL; - pj_uint32_t hval; - pj_status_t status = PJ_SUCCESS; - -@@ -849,9 +849,6 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, - /* Check type */ - PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL); - -- if (p_query) -- *p_query = NULL; -- - /* Build resource key for looking up hash tables */ - init_res_key(&key, type, name); - -@@ -970,10 +967,12 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, - pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key), - 0, q->hbufkey, q); - -- if (p_query) -- *p_query = q; -+ p_q = q; - - on_return: -+ if (p_query) -+ *p_query = p_q; -+ - pj_mutex_unlock(resolver->mutex); - return status; - } -diff --git a/pjlib-util/src/pjlib-util/srv_resolver.c b/pjlib-util/src/pjlib-util/srv_resolver.c -index 02672aa..ff9c979 100644 ---- a/pjlib-util/src/pjlib-util/srv_resolver.c -+++ b/pjlib-util/src/pjlib-util/srv_resolver.c -@@ -187,9 +187,12 @@ PJ_DEF(pj_status_t) pj_dns_srv_cancel_query(pj_dns_srv_async_query *query, - has_pending = PJ_TRUE; - } - if (srv->q_aaaa) { -- pj_dns_resolver_cancel_query(srv->q_aaaa, PJ_FALSE); -+ /* Check if it is a dummy query. */ -+ if (srv->q_aaaa != (pj_dns_async_query*)0x1) { -+ pj_dns_resolver_cancel_query(srv->q_aaaa, PJ_FALSE); -+ has_pending = PJ_TRUE; -+ } - srv->q_aaaa = NULL; -- has_pending = PJ_TRUE; - } - } - -@@ -485,12 +488,22 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job) - srv->common.type = PJ_DNS_TYPE_A; - srv->common_aaaa.type = PJ_DNS_TYPE_AAAA; - srv->parent = query_job; -+ srv->q_a = NULL; -+ srv->q_aaaa = NULL; - - status = PJ_SUCCESS; - - /* Start DNA A record query */ - if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY) == 0) - { -+ if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0) { -+ /* If there will be DNS AAAA query too, let's setup -+ * a dummy one here, otherwise app callback may be called -+ * immediately (before DNS AAAA query is sent) when -+ * DNS A record is available in the cache. -+ */ -+ srv->q_aaaa = (pj_dns_async_query*)0x1; -+ } - status = pj_dns_resolver_start_query(query_job->resolver, - &srv->target_name, - PJ_DNS_TYPE_A, 0, -diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c -index ed326ba..3f3654d 100644 ---- a/pjsip/src/pjsip/sip_resolve.c -+++ b/pjsip/src/pjsip/sip_resolve.c -@@ -452,7 +452,7 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver, - } - - /* Resolve DNS AAAA record if address family is not fixed to IPv4 */ -- if (af != pj_AF_INET()) { -+ if (af != pj_AF_INET() && status == PJ_SUCCESS) { - status = pj_dns_resolver_start_query(resolver->res, - &query->naptr[0].name, - PJ_DNS_TYPE_AAAA, 0, -@@ -530,9 +530,9 @@ static void dns_a_callback(void *user_data, - - ++srv->count; - } -- -- } else { -- -+ } -+ -+ if (status != PJ_SUCCESS) { - char errmsg[PJ_ERR_MSG_SIZE]; - - /* Log error */ -@@ -593,9 +593,9 @@ static void dns_aaaa_callback(void *user_data, - - ++srv->count; - } -- -- } else { -- -+ } -+ -+ if (status != PJ_SUCCESS) { - char errmsg[PJ_ERR_MSG_SIZE]; - - /* Log error */ --- -1.7.9.5 - diff --git a/third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch b/third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch deleted file mode 100644 index 4d11d57efae..00000000000 --- a/third-party/pjproject/patches/0006-r5473-svn-backport-Fix-pending-query.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 509d4339747f11cfbde3a0acc447ef5d521eea93 Mon Sep 17 00:00:00 2001 -From: Richard Mudgett -Date: Fri, 28 Oct 2016 12:12:28 -0500 -Subject: [PATCH 2/3] r5473 svn backport Fix pending query - -Re #1974: -If there is a pending query, set the return value to that query (instead of NULL) - -Thanks to Richard Mudgett for the patch. ---- - pjlib-util/src/pjlib-util/resolver.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c -index d24ef9d..fe687b7 100644 ---- a/pjlib-util/src/pjlib-util/resolver.c -+++ b/pjlib-util/src/pjlib-util/resolver.c -@@ -940,6 +940,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, - /* Done. This child query will be notified once the "parent" - * query completes. - */ -+ p_q = nq; - status = PJ_SUCCESS; - goto on_return; - } --- -1.7.9.5 - diff --git a/third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch b/third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch deleted file mode 100644 index e378c30d757..00000000000 --- a/third-party/pjproject/patches/0006-r5475-svn-backport-Remove-DNS-cache-entry.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 46e1cfa18853a38b7fcdebad782710c5db676657 Mon Sep 17 00:00:00 2001 -From: Richard Mudgett -Date: Fri, 28 Oct 2016 12:15:44 -0500 -Subject: [PATCH 3/3] r5475 svn backport Remove DNS cache entry - -Re #1974: Remove DNS cache entry from resolver's hash table when app callback has a reference. - -Thanks to Richard Mudgett for the patch. ---- - pjlib-util/src/pjlib-util/resolver.c | 29 +++++++++++++++-------------- - 1 file changed, 15 insertions(+), 14 deletions(-) - -diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c -index fe687b7..52b7655 100644 ---- a/pjlib-util/src/pjlib-util/resolver.c -+++ b/pjlib-util/src/pjlib-util/resolver.c -@@ -1444,10 +1444,12 @@ static void update_res_cache(pj_dns_resolver *resolver, - if (ttl > resolver->settings.cache_max_ttl) - ttl = resolver->settings.cache_max_ttl; - -+ /* Get a cache response entry */ -+ cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key, -+ sizeof(*key), &hval); -+ - /* If TTL is zero, clear the same entry in the hash table */ - if (ttl == 0) { -- cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key, -- sizeof(*key), &hval); - /* Remove the entry before releasing its pool (see ticket #1710) */ - pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL); - -@@ -1457,24 +1459,23 @@ static void update_res_cache(pj_dns_resolver *resolver, - return; - } - -- /* Get a cache response entry */ -- cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key, -- sizeof(*key), &hval); - if (cache == NULL) { - cache = alloc_entry(resolver); -- } else if (cache->ref_cnt > 1) { -- /* When cache entry is being used by callback (to app), just decrement -- * ref_cnt so it will be freed after the callback returns and allocate -- * new entry. -- */ -- cache->ref_cnt--; -- cache = alloc_entry(resolver); - } else { - /* Remove the entry before resetting its pool (see ticket #1710) */ - pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL); - -- /* Reset cache to avoid bloated cache pool */ -- reset_entry(&cache); -+ if (cache->ref_cnt > 1) { -+ /* When cache entry is being used by callback (to app), -+ * just decrement ref_cnt so it will be freed after -+ * the callback returns and allocate new entry. -+ */ -+ cache->ref_cnt--; -+ cache = alloc_entry(resolver); -+ } else { -+ /* Reset cache to avoid bloated cache pool */ -+ reset_entry(&cache); -+ } - } - - /* Duplicate the packet. --- -1.7.9.5 - diff --git a/third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch b/third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch deleted file mode 100644 index f70dd45e7a6..00000000000 --- a/third-party/pjproject/patches/0006-r5477-svn-backport-Fix-DNS-write-on-freed-memory.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 732a997010d60fe93a7453e809672386749b0afc Mon Sep 17 00:00:00 2001 -From: Richard Mudgett -Date: Tue, 1 Nov 2016 12:55:31 -0500 -Subject: [PATCH] r5477 svn backport Fix DNS write on freed memory. - -Re #1974: Fix DNS write on freed memory. -Thanks to Richard Mudgett for the patch. ---- - pjlib-util/src/pjlib-util/resolver.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c -index 52b7655..365772e 100644 ---- a/pjlib-util/src/pjlib-util/resolver.c -+++ b/pjlib-util/src/pjlib-util/resolver.c -@@ -908,7 +908,13 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver, - /* Must return PJ_SUCCESS */ - status = PJ_SUCCESS; - -- goto on_return; -+ /* -+ * We cannot write to *p_query after calling cb because what -+ * p_query points to may have been freed by cb. -+ * Refer to ticket #1974. -+ */ -+ pj_mutex_unlock(resolver->mutex); -+ return status; - } - - /* At this point, we have a cached entry, but this entry has expired. --- -1.7.9.5 - diff --git a/third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch b/third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch deleted file mode 100644 index e65556f22bd..00000000000 --- a/third-party/pjproject/patches/0012-Re-1945-misc-Don-t-trigger-SRV-complete-callback-whe.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 783de8956190c47a70ffefed56a1a2b21a62b235 Mon Sep 17 00:00:00 2001 -From: Riza Sulistyo -Date: Mon, 23 Jan 2017 01:34:12 +0000 -Subject: [PATCH 2/5] Re #1945 (misc): Don't trigger SRV complete callback when - there is a parse error. - -git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@5536 74dad513-b988-da41-8d7b-12977e46ad98 ---- - pjlib-util/src/pjlib-util/srv_resolver.c | 24 ++++++++++++++++++------ - 1 file changed, 18 insertions(+), 6 deletions(-) - -diff --git a/pjlib-util/src/pjlib-util/srv_resolver.c b/pjlib-util/src/pjlib-util/srv_resolver.c -index 8a4a599..8a2f7e1 100644 ---- a/pjlib-util/src/pjlib-util/srv_resolver.c -+++ b/pjlib-util/src/pjlib-util/srv_resolver.c -@@ -652,6 +652,7 @@ static void dns_callback(void *user_data, - - } else if (query_job->dns_state == PJ_DNS_TYPE_A) { - pj_bool_t is_type_a, srv_completed; -+ pj_dns_addr_record rec; - - /* Clear outstanding job */ - if (common->type == PJ_DNS_TYPE_A) { -@@ -668,15 +669,26 @@ static void dns_callback(void *user_data, - - is_type_a = (common->type == PJ_DNS_TYPE_A); - -+ /* Parse response */ -+ if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) { -+ status = pj_dns_parse_addr_response(pkt, &rec); -+ if (status!=PJ_SUCCESS) { -+ char errmsg[PJ_ERR_MSG_SIZE]; -+ -+ PJ_LOG(4,(query_job->objname, -+ "DNS %s record parse error for '%.*s'." -+ " Err=%d (%s)", -+ (is_type_a ? "A" : "AAAA"), -+ (int)query_job->domain_part.slen, -+ query_job->domain_part.ptr, -+ status, -+ pj_strerror(status,errmsg,sizeof(errmsg)).ptr)); -+ } -+ } -+ - /* Check that we really have answer */ - if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) { - char addr[PJ_INET6_ADDRSTRLEN]; -- pj_dns_addr_record rec; -- -- /* Parse response */ -- status = pj_dns_parse_addr_response(pkt, &rec); -- if (status != PJ_SUCCESS) -- goto on_error; - - pj_assert(rec.addr_count != 0); - --- -2.7.4 - diff --git a/third-party/pjproject/patches/README b/third-party/pjproject/patches/README new file mode 100644 index 00000000000..d16110bbbdf --- /dev/null +++ b/third-party/pjproject/patches/README @@ -0,0 +1,7 @@ +The 0000-* patches in this directory should not be removed or +reordered when upgrading to a new version of pjproject. They +MAY need to be updated to apply cleanly however. + +New patches should be numbered in ascending order with no +duplicates. Leave 10 slots open after the last patch to +allow others to be inserted. diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index 5e29cdb6aa4..a345734b0f8 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -20,6 +20,12 @@ */ #define PJMEDIA_HAS_SRTP 0 +/* + * Defining PJMEDIA_HAS_WEBRTC_AEC to 0 does NOT disable Asterisk's ability to use + * webrtc. It only disables the pjmedia webrtc transport which Asterisk doesn't use. + */ +#define PJMEDIA_HAS_WEBRTC_AEC 0 + #define PJ_HAS_IPV6 1 #define NDEBUG 1 #define PJ_MAX_HOSTNAME (256) diff --git a/third-party/versions.mak b/third-party/versions.mak index a4d7874d54f..03dd6d38806 100644 --- a/third-party/versions.mak +++ b/third-party/versions.mak @@ -1,2 +1,2 @@ -PJPROJECT_VERSION = 2.5.5 +PJPROJECT_VERSION = 2.6 From c07c6714f270b7689ddd904bd52f547c19b51555 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 23 Feb 2017 19:03:15 +0000 Subject: [PATCH 1084/1578] channel: Add ast_read_stream function for reading frames from all streams. This change introduces an ast_read_stream function and callback in the channel technology which allows reading frames from all streams and not just the default streams. The stream number has also been added to frames. This is to allow the case where frames are queued onto the channel instead of being read directly from the driver. This change does impose a restriction on reading though: a chain of frames can only contain frames from the same stream. ASTERISK-26816 Change-Id: I5d7dc35e86694df91fd025126f6cfe0453aa38ce --- include/asterisk/channel.h | 49 ++++++++++++++++++++++++++++++- include/asterisk/frame.h | 2 ++ main/channel.c | 60 +++++++++++++++++++++++++++++++++----- main/frame.c | 2 ++ 4 files changed, 105 insertions(+), 8 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 80476a4e0b1..f6e09252f3a 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -664,9 +664,33 @@ struct ast_channel_tech { /*! \brief Answer the channel */ int (* const answer)(struct ast_channel *chan); - /*! \brief Read a frame, in standard format (see frame.h) */ + /*! + * \brief Read a frame (or chain of frames from the same stream), in standard format (see frame.h) + * + * \param chan channel to read frames from + * + * \retval non-NULL on success + * \retval NULL on failure + * + * \note Each media frame from this callback will have the stream_num of it changed to the default + * stream num based on the type of media returned. As a result a multistream capable channel + * should not implement this callback. + */ struct ast_frame * (* const read)(struct ast_channel *chan); + /*! + * \brief Read a frame (or chain of frames from the same stream), in standard format (see frame.h), with stream num + * + * \param chan channel to read frames from + * + * \retval non-NULL on success + * \retval NULL on failure + * + * \note Each media frame from this callback should contain a stream_num value which is set to the + * stream that the media frame originated from. + */ + struct ast_frame * (* const read_stream)(struct ast_channel *chan); + /*! \brief Write a frame, in standard format (see frame.h) */ int (* const write)(struct ast_channel *chan, struct ast_frame *frame); @@ -1926,13 +1950,36 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception); /*! * \brief Reads a frame + * * \param chan channel to read a frame from + * * \return Returns a frame, or NULL on error. If it returns NULL, you * best just stop reading frames and assume the channel has been * disconnected. + * + * \note This function will filter frames received from the channel so + * that only frames from the default stream for each media type + * are returned. All other media frames from other streams will + * be absorbed internally and a NULL frame returned instead. */ struct ast_frame *ast_read(struct ast_channel *chan); +/*! + * \brief Reads a frame, but does not filter to just the default streams + * + * \param chan channel to read a frame from + * + * \return Returns a frame, or NULL on error. If it returns NULL, you + * best just stop reading frames and assume the channel has been + * disconnected. + * + * \note This function will not perform any filtering and will return + * media frames from all streams on the channel. To determine which + * stream a frame originated from the stream_num on it can be + * examined. + */ +struct ast_frame *ast_read_stream(struct ast_channel *chan); + /*! * \brief Reads a frame, returning AST_FRAME_NULL frame if audio. * \param chan channel to read a frame from diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 90f8aa086c2..c56539af466 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -181,6 +181,8 @@ struct ast_frame { long len; /*! Sequence number */ int seqno; + /*! Stream number the frame originated from */ + int stream_num; }; /*! diff --git a/main/channel.c b/main/channel.c index 183f8936f12..e3e9561fe95 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3782,11 +3782,12 @@ static inline int calc_monitor_jump(int samples, int sample_rate, int seek_rate) return samples; } -static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) +static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int dropnondefault) { struct ast_frame *f = NULL; /* the return value */ int prestate; int cause = 0; + struct ast_stream *stream = NULL, *default_stream = NULL; /* this function is very long so make sure there is only one return * point at the end (there are only two exceptions to this). @@ -3943,6 +3944,13 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) default: break; } + } else if (!(ast_channel_tech(chan)->properties & AST_CHAN_TP_MULTISTREAM) && ( + f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { + /* Since this channel driver does not support multistream determine the default stream this frame + * originated from and update the frame to include it. + */ + stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + f->stream_num = ast_stream_get_position(stream); } } else { ast_channel_blocker_set(chan, pthread_self()); @@ -3955,15 +3963,43 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) } /* Clear the exception flag */ ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION); - } else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read) + } else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read_stream) { + f = ast_channel_tech(chan)->read_stream(chan); + + /* This channel driver supports multistream so the stream_num on the frame is valid, the only + * thing different is that we need to find the default stream so we know whether to invoke the + * default stream logic or not (such as transcoding). + */ + if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { + stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num); + default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + } + } else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read) { f = ast_channel_tech(chan)->read(chan); + + /* Since this channel driver does not support multistream determine the default stream this frame + * originated from and update the frame to include it. + */ + if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { + stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + f->stream_num = ast_stream_get_position(stream); + } + } else ast_log(LOG_WARNING, "No read routine on channel %s\n", ast_channel_name(chan)); } - /* Perform the framehook read event here. After the frame enters the framehook list - * there is no telling what will happen, !!! */ - f = ast_framehook_list_read_event(ast_channel_framehooks(chan), f); + if (dropnondefault && stream != default_stream) { + /* If the frame originates from a non-default stream and the caller can not handle other streams + * absord the frame and replace it with a null one instead. + */ + ast_frfree(f); + f = &ast_null_frame; + } else if (stream == default_stream) { + /* Perform the framehook read event here. After the frame enters the framehook list + * there is no telling what will happen, !!! */ + f = ast_framehook_list_read_event(ast_channel_framehooks(chan), f); + } /* * Reset the recorded file descriptor that triggered this read so that we can @@ -4162,6 +4198,11 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) } break; case AST_FRAME_VOICE: + /* If media was received from a non-default stream don't perform any actions, let it just go through */ + if (stream != default_stream) { + break; + } + /* The EMULATE_DTMF flag must be cleared here as opposed to when the duration * is reached , because we want to make sure we pass at least one * voice frame through before starting the next digit, to ensure a gap @@ -4396,12 +4437,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) struct ast_frame *ast_read(struct ast_channel *chan) { - return __ast_read(chan, 0); + return __ast_read(chan, 0, 1); +} + +struct ast_frame *ast_read_stream(struct ast_channel *chan) +{ + return __ast_read(chan, 0, 0); } struct ast_frame *ast_read_noaudio(struct ast_channel *chan) { - return __ast_read(chan, 1); + return __ast_read(chan, 1, 1); } int ast_indicate(struct ast_channel *chan, int condition) diff --git a/main/frame.c b/main/frame.c index c284a8e1cd9..c24cc8f7869 100644 --- a/main/frame.c +++ b/main/frame.c @@ -222,6 +222,7 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) out->len = fr->len; out->seqno = fr->seqno; } + out->stream_num = fr->stream_num; } else { out = fr; } @@ -370,6 +371,7 @@ struct ast_frame *ast_frdup(const struct ast_frame *f) out->ts = f->ts; out->len = f->len; out->seqno = f->seqno; + out->stream_num = f->stream_num; return out; } From 204674393863fc2ecea8e11b7b65f8d4139218ff Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 24 Feb 2017 17:49:59 +0000 Subject: [PATCH 1085/1578] config: Improve documentation and behavior of outbound_proxy option. This change updates the documentation for the outbound_proxy option to ensure it is consistently stated that a full SIP URI must be provided for the option. The res_pjsip_outbound_registration module has also been changed so that the provided outbound_proxy value is checked to ensure it is a URI and if not an error is output stating so. ASTERISK-26782 Change-Id: I6c239a32274846fd44e65b44ad9bf6373479b593 --- configs/samples/pjsip.conf.sample | 10 +++++----- res/res_pjsip.c | 2 +- res/res_pjsip_outbound_publish.c | 2 +- res/res_pjsip_outbound_registration.c | 13 ++++++++++++- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 323100b00fb..bb2c8a629ab 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -642,7 +642,7 @@ ; when placing on hold and sendrecv when taking off hold ;outbound_auth= ; Authentication object used for outbound requests (default: ; "") -;outbound_proxy= ; Proxy through which to send requests a full SIP URI +;outbound_proxy= ; Proxy through which to send requests, a full SIP URI ; must be provided (default: "") ;rewrite_contact=no ; Allow Contact header to be rewritten with the source ; IP address port (default: "no") @@ -877,8 +877,8 @@ ;qualify_timeout=3.0 ; Qualify timeout in fractional seconds (default: "3.0") ;authenticate_qualify=no ; Authenticates a qualify request if needed ; (default: "no") -;outbound_proxy= ; Outbound proxy used when sending OPTIONS request - ; (default: "") +;outbound_proxy= ; Proxy through which to send OPTIONS requests, a full SIP URI + ; must be provided (default: "") ;==========================SYSTEM SECTION OPTIONS========================= @@ -1045,8 +1045,8 @@ ;max_retries=10 ; Maximum number of registration attempts (default: "10") ;outbound_auth= ; Authentication object to be used for outbound registrations ; (default: "") -;outbound_proxy= ; Outbound Proxy used to send registrations (default: - ; "") +;outbound_proxy= ; Proxy through which to send registrations, a full SIP URI + ; must be provided (default: "") ;retry_interval=60 ; Interval in seconds between retries if outbound ; registration is unsuccessful (default: "60") ;forbidden_retry_interval=0 ; Interval used when receiving a 403 Forbidden diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 9782cc99766..810b6d3297c 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -349,7 +349,7 @@ - Proxy through which to send requests, a full SIP URI must be provided + Full SIP URI of the outbound proxy used to send requests Allow Contact header to be rewritten with the source IP address-port diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 53eb6aca78a..a19a9bb2441 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -69,7 +69,7 @@ - SIP URI of the outbound proxy used to send publishes + Full SIP URI of the outbound proxy used to send publishes SIP URI of the server and entity to publish to diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 137f3a83287..3b635a159c9 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -96,7 +96,7 @@ - Outbound Proxy used to send registrations + Full SIP URI of the outbound proxy used to send registrations Interval in seconds between retries if outbound registration is unsuccessful @@ -1209,6 +1209,17 @@ static int sip_outbound_registration_regc_alloc(void *data) return -1; } + if (!ast_strlen_zero(registration->outbound_proxy)) { + pj_strdup2_with_null(pool, &tmp, registration->outbound_proxy); + uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0); + if (!uri) { + ast_log(LOG_ERROR, "Invalid outbound proxy URI '%s' specified on outbound registration '%s'\n", + registration->outbound_proxy, ast_sorcery_object_get_id(registration)); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + return -1; + } + } + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); From 5b1796f59d01f399c68b05b31fe173fc7ede16dc Mon Sep 17 00:00:00 2001 From: frahaase Date: Fri, 12 Aug 2016 18:23:40 +0200 Subject: [PATCH 1086/1578] Binaural synthesis (confbridge): DTMF conference management. DTMF configuration options for the binaural softmix bridge: toggle binaural rendering (per channel). ASTERISK-26292 Change-Id: Ibfe708b9fe26097c1798fcbfcc4dc461267d8af8 --- apps/app_confbridge.c | 21 +++++++++++++++++++++ apps/confbridge/conf_config_parser.c | 17 +++++++++++++++++ apps/confbridge/include/confbridge.h | 5 +++++ configs/samples/confbridge.conf.sample | 3 +++ 4 files changed, 46 insertions(+) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index c7c76ff6bc5..5ec20ddb993 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -438,6 +438,10 @@ const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds return S_OR(custom_sounds->muted, "conf-muted"); case CONF_SOUND_UNMUTED: return S_OR(custom_sounds->unmuted, "conf-unmuted"); + case CONF_SOUND_BINAURAL_ON: + return S_OR(custom_sounds->binauralon, "confbridge-binaural-on"); + case CONF_SOUND_BINAURAL_OFF: + return S_OR(custom_sounds->binauraloff, "confbridge-binaural-off"); case CONF_SOUND_ONLY_ONE: return S_OR(custom_sounds->onlyone, "conf-onlyone"); case CONF_SOUND_THERE_ARE: @@ -2452,6 +2456,20 @@ static int action_toggle_mute(struct confbridge_conference *conference, conference->b_profile.sounds)) < 0; } +static int action_toggle_binaural(struct confbridge_conference *conference, + struct confbridge_user *user, + struct ast_bridge_channel *bridge_channel) +{ + unsigned int binaural; + ast_bridge_channel_lock_bridge(bridge_channel); + binaural = !bridge_channel->binaural_suspended; + bridge_channel->binaural_suspended = binaural; + ast_bridge_unlock(bridge_channel->bridge); + return play_file(bridge_channel, NULL, (binaural ? + conf_get_sound(CONF_SOUND_BINAURAL_OFF, user->b_profile.sounds) : + conf_get_sound(CONF_SOUND_BINAURAL_ON, user->b_profile.sounds))) < 0; +} + static int action_toggle_mute_participants(struct confbridge_conference *conference, struct confbridge_user *user) { struct confbridge_user *cur_user = NULL; @@ -2670,6 +2688,9 @@ static int execute_menu_entry(struct confbridge_conference *conference, case MENU_ACTION_TOGGLE_MUTE: res |= action_toggle_mute(conference, user, bridge_channel); break; + case MENU_ACTION_TOGGLE_BINAURAL: + action_toggle_binaural(conference, user, bridge_channel); + break; case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS: if (!isadmin) { break; diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 29d7b7f53f9..4729139c209 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -425,6 +425,8 @@ The sound played to a user who has been kicked from the conference. The sound played when the mute option it toggled on. The sound played when the mute option it toggled off. + The sound played when binaural auudio is turned on. + The sound played when the binaural audio is turned off. The sound played when the user is the only person in the conference. The sound played to a user when there is only one other person is in the conference. @@ -512,6 +514,9 @@ Toggle turning on and off mute. Mute will make the user silent to everyone else, but the user will still be able to listen in. + + Toggle turning on and off binaural audio processing. + This action does nothing (No Operation). Its only real purpose exists for being able to reserve a sequence in the config as a menu exit sequence. @@ -916,6 +921,10 @@ static int set_sound(const char *sound_name, const char *sound_file, struct brid ast_string_field_set(sounds, muted, sound_file); } else if (!strcasecmp(sound_name, "sound_unmuted")) { ast_string_field_set(sounds, unmuted, sound_file); + } else if (!strcasecmp(sound_name, "sound_binaural_on")) { + ast_string_field_set(sounds, binauralon, sound_file); + } else if (!strcasecmp(sound_name, "sound_binaural_off")) { + ast_string_field_set(sounds, binauraloff, sound_file); } else if (!strcasecmp(sound_name, "sound_there_are")) { ast_string_field_set(sounds, thereare, sound_file); } else if (!strcasecmp(sound_name, "sound_other_in_party")) { @@ -1141,6 +1150,7 @@ static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum con switch (id) { case MENU_ACTION_NOOP: case MENU_ACTION_TOGGLE_MUTE: + case MENU_ACTION_TOGGLE_BINAURAL: case MENU_ACTION_INCREASE_LISTENING: case MENU_ACTION_DECREASE_LISTENING: case MENU_ACTION_INCREASE_TALKING: @@ -1249,6 +1259,8 @@ static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char * ast_copy_string(menu_entry->dtmf, dtmf, sizeof(menu_entry->dtmf)); if (!strcasecmp(action, "toggle_mute")) { res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_TOGGLE_MUTE, NULL); + } else if (!strcasecmp(action, "toggle_binaural")) { + res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_TOGGLE_BINAURAL, NULL); } else if (!strcasecmp(action, "no_op")) { res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_NOOP, NULL); } else if (!strcasecmp(action, "increase_listening_volume")) { @@ -1647,6 +1659,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, ast_cli(a->fd,"sound_kicked: %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds)); ast_cli(a->fd,"sound_muted: %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds)); ast_cli(a->fd,"sound_unmuted: %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds)); + ast_cli(a->fd,"sound_binaural_on: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_ON, b_profile.sounds)); + ast_cli(a->fd,"sound_binaural_off: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_OFF, b_profile.sounds)); ast_cli(a->fd,"sound_there_are: %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds)); ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds)); ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds)); @@ -1775,6 +1789,9 @@ static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, s case MENU_ACTION_TOGGLE_MUTE: ast_cli(a->fd, "toggle_mute"); break; + case MENU_ACTION_TOGGLE_BINAURAL: + ast_cli(a->fd, "toggle_binaural"); + break; case MENU_ACTION_NOOP: ast_cli(a->fd, "no_op"); break; diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index f91f2dc89d5..584499ff391 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -93,6 +93,7 @@ enum conf_menu_action_id { MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC, MENU_ACTION_PARTICIPANT_COUNT, MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS, + MENU_ACTION_TOGGLE_BINAURAL, }; /*! The conference menu action contains both @@ -170,6 +171,8 @@ enum conf_sounds { CONF_SOUND_PARTICIPANTS_MUTED, CONF_SOUND_PARTICIPANTS_UNMUTED, CONF_SOUND_BEGIN, + CONF_SOUND_BINAURAL_ON, + CONF_SOUND_BINAURAL_OFF, }; struct bridge_profile_sounds { @@ -197,6 +200,8 @@ struct bridge_profile_sounds { AST_STRING_FIELD(participantsmuted); AST_STRING_FIELD(participantsunmuted); AST_STRING_FIELD(begin); + AST_STRING_FIELD(binauralon); + AST_STRING_FIELD(binauraloff); ); }; diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index 5b9f52d4f74..0e07f6b16df 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -259,6 +259,8 @@ type=bridge ;sound_unlocked_now; The sound played to an admin after toggling the conference to unlocked mode. ;sound_error_menu ; The sound played when an invalid menu option is entered. ;sound_begin ; The sound played to the conference when the first marked user enters the conference. +;sound_binaural_on ; The sound played when binaural audio is turned on +;sound_binaural_off ; The sound played when binaural audio is turned off ; --- ConfBridge Menu Options --- ; The ConfBridge application also has the ability to @@ -297,6 +299,7 @@ type=bridge ; using the '&' character as a delimiter. ; toggle_mute ; Toggle turning on and off mute. Mute will make the user silent ; to everyone else, but the user will still be able to listen in. +; toggle_binaural ; Toggle on or off binaural audio processing. ; no_op ; This action does nothing (No Operation). Its only real purpose exists for ; being able to reserve a sequence in the config as a menu exit sequence. From ff2b4308d1ab605861fb7a0931dc36ae1edff9fc Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 27 Feb 2017 13:02:38 +0000 Subject: [PATCH 1087/1578] bridge_native_rtp: Handle case where channel joins already suspended. The bridge_native_rtp module did not properly handle the case where a smart bridge operation occurs while a channel is suspended. In this scenario the module would incorrectly set up local or remote RTP bridging despite the media having to flow through Asterisk. The remote endpoint would see two media streams and experience wonky audio. The module has been changed so that it ensures both channels are not suspended when performing the native RTP bridging and this requirement has been documented in the bridge technology. ASTERISK-26781 Change-Id: Id4022d73ace837d4a293106445e3ade10dbc7c7c --- bridges/bridge_native_rtp.c | 6 ++++-- include/asterisk/bridge_technology.h | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index e011f50374c..77e321f4f0f 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -129,7 +129,7 @@ static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channe { struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); - enum ast_rtp_glue_result native_type; + enum ast_rtp_glue_result native_type = AST_RTP_GLUE_RESULT_FORBID; struct ast_rtp_glue *glue0, *glue1; RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup); @@ -145,7 +145,9 @@ static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channe } ast_channel_lock_both(bc0->chan, bc1->chan); - native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1); + if (!bc0->suspended && !bc1->suspended) { + native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1); + } switch (native_type) { case AST_RTP_GLUE_RESULT_LOCAL: diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridge_technology.h index 8df19d9e97e..843d93ccfc6 100644 --- a/include/asterisk/bridge_technology.h +++ b/include/asterisk/bridge_technology.h @@ -110,6 +110,9 @@ struct ast_bridge_technology { * * \note The bridge technology must tollerate a failed to join channel * until it can be kicked from the bridge. + * + * \note A channel may be in a suspended state already when joining a bridge + * technology. The technology must handle this case. */ int (*join)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); /*! From 4692a32ed7dccf3248383978741515a0e5b1ce85 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 27 Feb 2017 11:25:01 -0700 Subject: [PATCH 1088/1578] build: Warn if asterisk is installed in both 32 and 64 bit sys dirs ... and clean them both up on uninstall. We've fixed the issue where 'make install' was installing to /usr/lib on 64-bit systems that use /usr/lib64. Now we need to clean up the remnants in /usr/lib. * 'make install' now prints a warning if DESTDIR/ASTLIBDIR contains 'lib64' and libasterisk* shared libraries or modules are also found in DESTDIR/ASTLIBDIR with 'lib64' transformed to 'lib'. * 'make uninstall' ALWAYS cleans up both DESTDIR/ASTLIBDIR and DESTDIR/ASTLIBDIR with 'lib64' transformed to 'lib'. ASTERISK-26705 Change-Id: I6edddeb3c07a51e7c7ba7cac3c05e4bf3ec3f01f --- Makefile | 35 +++++++++++++++++++++++++++++++++++ main/Makefile | 12 ++---------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 80845d5ab83..2c7f92543f3 100644 --- a/Makefile +++ b/Makefile @@ -652,6 +652,37 @@ ifneq ($(LDCONFIG),) fi endif +ifeq ($(and $(findstring 64,$(HOST_CPU)),$(findstring lib64,$(DESTDIR)$(ASTLIBDIR))),lib64) +_oldlibdir = $(subst lib64,lib,$(DESTDIR)$(ASTLIBDIR)) + +check-old-libdir: + @oldfiles=`find "$(_oldlibdir)" -name libasterisk* -print -quit -o \( -path *asterisk/modules/* -a -name *.so \) -print -quit` ;\ + if [ "x$$oldfiles" != "x" ] ; then \ + echo " WARNING WARNING WARNING" ;\ + echo "" ;\ + echo " Installation is to: " ;\ + echo " $(DESTDIR)$(ASTLIBDIR)" ;\ + echo " but there are asterisk shared libraries in: " ;\ + echo " $(_oldlibdir)" ;\ + echo " or" ;\ + echo " $(_oldlibdir)/asterisk/modules" ;\ + echo "" ;\ + echo " It is unlikely that asterisk will start." ;\ + echo "" ;\ + echo " You should do one of the following..." ;\ + echo " * Run 'make uninstall' to remove the incorrect libraries" ;\ + echo " then run 'make install' again." ;\ + echo " * Manually remove the libraries from" ;\ + echo " $(_oldlibdir)" ;\ + echo " and run 'ldconfig' to rebuild the linker cache." ;\ + echo "" ;\ + echo " WARNING WARNING WARNING" ;\ + fi +else +check-old-libdir: + +endif + badshell: ifneq ($(filter ~%,$(DESTDIR)),) @echo "Your shell doesn't do ~ expansion when expected (specifically, when doing \"make install DESTDIR=~/path\")." @@ -691,6 +722,7 @@ install: badshell bininstall datafiles @echo " +-------------------------------------------+" @$(MAKE) -s oldmodcheck @$(MAKE) -s ld-cache-update + @$(MAKE) -s check-old-libdir isntall: install @@ -911,6 +943,7 @@ main-binuninstall: _uninstall: $(SUBDIRS_UNINSTALL) main-binuninstall rm -f "$(DESTDIR)$(ASTMODDIR)/"* + rm -f "$(subst lib64,lib,$(DESTDIR)$(ASTMODDIR))/"* rm -f "$(DESTDIR)$(ASTSBINDIR)/astgenkey" rm -f "$(DESTDIR)$(ASTSBINDIR)/autosupport" rm -rf "$(DESTDIR)$(ASTHEADERDIR)" @@ -943,6 +976,7 @@ uninstall: _uninstall uninstall-all: _uninstall rm -rf "$(DESTDIR)$(ASTMODDIR)" + rm -rf "$(subst lib64,lib,$(DESTDIR)$(ASTMODDIR))" rm -rf "$(DESTDIR)$(ASTVARLIBDIR)" rm -rf "$(DESTDIR)$(ASTDATADIR)" rm -rf "$(DESTDIR)$(ASTSPOOLDIR)" @@ -1057,6 +1091,7 @@ check-alembic: makeopts .PHONY: basic-pbx .PHONY: check-alembic .PHONY: ld-cache-update +.PHONY: check-old-libdir .PHONY: $(SUBDIRS_INSTALL) .PHONY: $(SUBDIRS_DIST_CLEAN) .PHONY: $(SUBDIRS_CLEAN) diff --git a/main/Makefile b/main/Makefile index d3463f7b6a8..cf38f5f465f 100644 --- a/main/Makefile +++ b/main/Makefile @@ -359,16 +359,8 @@ endif binuninstall: rm -f "$(DESTDIR)$(ASTSBINDIR)/$(MAIN_TGT)" rm -f "$(DESTDIR)$(ASTSBINDIR)/rasterisk" -ifneq ($(ASTSSL_LIB).$(ASTSSL_SO_VERSION),.) -# ASTSSL_SO_VERSION may not exist on Darwin - rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)" || : - rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB)" -endif -ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) -# ASTSSL_SO_VERSION may not exist on Darwin - rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB).$(ASTPJ_SO_VERSION)" || : - rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" -endif + rm -f "$(DESTDIR)$(ASTLIBDIR)/libasterisk"* || : + rm -f "$(subst lib64,lib,$(DESTDIR)$(ASTLIBDIR))/libasterisk"* || : clean:: rm -f asterisk libasteriskssl.o From 22242fef5dd4de12697deb219c732b9c69b46954 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 21 Feb 2017 17:06:00 -0700 Subject: [PATCH 1089/1578] res_pjsip_outbound_registration: Subscribe to network change events Outbound registration now subscribes to network change events published by res_stun_monitor and refreshes all registrations when an event happens. The 'pjsip send (un)register' CLI commands were updated to accept '*all' as an argument to operate on all registrations. The 'PJSIP(Un)Register' AMI commands were also updated to accept '*all'. ASTERISK-26808 #close Change-Id: Iad58a9e0aa5d340477fca200bf293187a6ca5a25 --- CHANGES | 8 +++ res/res_pjsip_outbound_registration.c | 95 ++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index fafaa21412f..d3d0cb81eee 100644 --- a/CHANGES +++ b/CHANGES @@ -88,6 +88,14 @@ app_record * Added new 'u' option to Record() application which prevents Asterisk from truncating silence from the end of recorded files. +res_pjsip_outbound_registration +------------------ + * Outbound registrations are now refreshed when res_stun_monitor detects + a network change event has happened. + The 'pjsip send (un)register' CLI commands were updated to accept '*all' + as an argument to operate on all registrations. + The 'PJSIP(Un)Register' AMI commands were updated to also accept '*all'. + app_voicemail ------------------ * The 'Comedian Mail' prompts can now be overriden using the 'vm-login' and diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 137f3a83287..683642f778d 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -180,12 +180,12 @@ - The outbound registration to unregister. + The outbound registration to unregister or '*all' to unregister them all. - Unregisters the specified outbound registration and stops future registration attempts. + Unregisters the specified (or all) outbound registration(s) and stops future registration attempts. Call PJSIPRegister to start registration and schedule re-registrations according to configuration. @@ -197,14 +197,13 @@ - The outbound registration to register. + The outbound registration to register or '*all' to register them all. - Unregisters the specified outbound registration then starts registration and schedules re-registrations + Unregisters the specified (or all) outbound registration(s) then starts registration and schedules re-registrations according to configuration. - future registrations. @@ -379,6 +378,9 @@ static struct ast_serializer_shutdown_group *shutdown_group; #define DEFAULT_STATE_BUCKETS 53 static AO2_GLOBAL_OBJ_STATIC(current_states); +/*! subscription id for network change events */ +static struct stasis_subscription *network_change_sub; + /*! \brief hashing function for state objects */ static int registration_state_hash(const void *obj, const int flags) { @@ -1458,6 +1460,26 @@ static int queue_register(struct sip_outbound_registration_state *state) return 0; } +static void unregister_all(void) +{ + struct ao2_container *states; + + states = ao2_global_obj_ref(current_states); + if (!states) { + return; + } + + /* Clean out all the states and let sorcery handle recreating the registrations */ + ao2_callback(states, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); + ao2_ref(states, -1); +} + +static void reregister_all(void) +{ + unregister_all(); + ast_sorcery_load_object(ast_sip_get_sorcery(), "registration"); +} + static char *cli_complete_registration(const char *line, const char *word, int pos, int state) { @@ -1473,6 +1495,10 @@ static char *cli_complete_registration(const char *line, const char *word, } wordlen = strlen(word); + if (wordlen == 0 && ++which > state) { + return ast_strdup("*all"); + } + registrations = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); if (!registrations) { @@ -1507,8 +1533,9 @@ static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg case CLI_INIT: e->command = "pjsip send unregister"; e->usage = - "Usage: pjsip send unregister \n" - " Unregisters the specified outbound registration and stops future registration attempts.\n"; + "Usage: pjsip send unregister | *all\n" + " Unregisters the specified (or all) outbound registration(s) " + "and stops future registration attempts.\n"; return NULL; case CLI_GENERATE: return cli_complete_registration(a->line, a->word, a->pos, a->n); @@ -1520,6 +1547,12 @@ static char *cli_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg registration_name = a->argv[3]; + if (strcmp(registration_name, "*all") == 0) { + unregister_all(); + ast_cli(a->fd, "Unregister all queued\n"); + return CLI_SUCCESS; + } + state = get_state(registration_name); if (!state) { ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name); @@ -1543,9 +1576,9 @@ static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args case CLI_INIT: e->command = "pjsip send register"; e->usage = - "Usage: pjsip send register \n" - " Unregisters the specified outbound " - "registration then re-registers and re-schedules it.\n"; + "Usage: pjsip send register | *all \n" + " Unregisters the specified (or all) outbound " + "registration(s) then starts registration(s) and schedules re-registrations.\n"; return NULL; case CLI_GENERATE: return cli_complete_registration(a->line, a->word, a->pos, a->n); @@ -1557,6 +1590,12 @@ static char *cli_register(struct ast_cli_entry *e, int cmd, struct ast_cli_args registration_name = a->argv[3]; + if (strcmp(registration_name, "*all") == 0) { + reregister_all(); + ast_cli(a->fd, "Re-register all queued\n"); + return CLI_SUCCESS; + } + state = get_state(registration_name); if (!state) { ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name); @@ -1586,6 +1625,12 @@ static int ami_unregister(struct mansession *s, const struct message *m) return 0; } + if (strcmp(registration_name, "*all") == 0) { + unregister_all(); + astman_send_ack(s, m, "Unregistrations queued."); + return 0; + } + state = get_state(registration_name); if (!state) { astman_send_error(s, m, "Unable to retrieve registration entry\n"); @@ -1612,6 +1657,12 @@ static int ami_register(struct mansession *s, const struct message *m) return 0; } + if (strcmp(registration_name, "*all") == 0) { + reregister_all(); + astman_send_ack(s, m, "Reregistrations queued."); + return 0; + } + state = get_state(registration_name); if (!state) { astman_send_error(s, m, "Unable to retrieve registration entry\n"); @@ -1787,10 +1838,6 @@ static int cli_print_body(void *obj, void *arg, int flags) ast_assert(context->output_buffer != NULL); - if (!state) { - return 0; - } - ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n", id, (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)), @@ -1799,8 +1846,8 @@ static int cli_print_body(void *obj, void *arg, int flags) AST_VECTOR_SIZE(®istration->outbound_auths) ? AST_VECTOR_GET(®istration->outbound_auths, 0) : "n/a", - sip_outbound_registration_status_str(state->client_state->status)); - ao2_ref(state, -1); + (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered")); + ao2_cleanup(state); if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) { @@ -1960,10 +2007,23 @@ static const struct ast_sorcery_observer registration_observer = { .deleted = registration_deleted_observer, }; +static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) +{ + /* This callback is only concerned with network change messages from the system topic. */ + if (stasis_message_type(message) != ast_network_change_type()) { + return; + } + ast_debug(3, "Received network change event\n"); + + reregister_all(); +} + static int unload_module(void) { int remaining; + network_change_sub = stasis_unsubscribe_and_join(network_change_sub); + ast_manager_unregister("PJSIPShowRegistrationsOutbound"); ast_manager_unregister("PJSIPUnregister"); ast_manager_unregister("PJSIPRegister"); @@ -2101,6 +2161,9 @@ static int load_module(void) /* Load configuration objects */ ast_sorcery_load_object(ast_sip_get_sorcery(), "registration"); + network_change_sub = stasis_subscribe(ast_system_topic(), + network_change_stasis_cb, NULL); + return AST_MODULE_LOAD_SUCCESS; } From ee0a123f436042ac685b8046949e45726ae161c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20H?= Date: Thu, 16 Feb 2017 10:16:47 +0000 Subject: [PATCH 1090/1578] res_pjsip: Fix crash when contact has no status This change fixes an assumption in res_pjsip that a contact will always have a status. There is a race condition where this is not true and would crash. The status will now be unknown when this situation occurs. ASTERISK-26623 #close Change-Id: Id52d3ca4d788562d236da49990a319118f8d22b5 --- res/res_pjsip/pjsip_options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 6fd3c25757a..662166c89b5 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1250,8 +1250,8 @@ int ast_sip_format_contact_ami(void *obj, void *arg, int flags) if (!ast_strlen_zero(contact->call_id)) { ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id); } - ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status)); - if (status->status == UNKNOWN) { + ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status ? status->status : UNKNOWN)); + if (!status || status->status == UNKNOWN) { ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); } else { ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt); From fb68db87b1ab4e39c6c8a9d363985b0de6407228 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 27 Feb 2017 19:07:06 -0700 Subject: [PATCH 1091/1578] res_pjsip_pubsub: Remove unneeded endpoint unref When a subscription was being recreated and the endpoint wasn't found, we were trying to unref the endpoint. This was causing FRACKs. Removed the unref. ASTERISK-26823 #close Change-Id: If86d2aecff8fe853c7f38a1bfde721fcef3cd164 --- res/res_pjsip_pubsub.c | 1 - 1 file changed, 1 deletion(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 709dc664047..e90502485c6 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1456,7 +1456,6 @@ static int sub_persistence_recreate(void *obj) ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n", persistence->endpoint); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); - ao2_ref(endpoint, -1); return 0; } From 6ebdcfe27d5a44cc7ec1840ea0295e9ad87ff2fe Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 28 Feb 2017 13:41:18 +0200 Subject: [PATCH 1092/1578] pjsip.conf.sample: user_agent: not a specific version Use the description of useragent from sip.conf here. ASTERISK-26825 #close Change-Id: I5b33a4aaa0ae1d793289d05e3bc09521affbf755 --- configs/samples/pjsip.conf.sample | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 323100b00fb..4d7195f00a1 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -910,11 +910,10 @@ ;max_forwards=70 ; Value used in Max Forwards header for SIP requests ; (default: "70") ;type= ; Must be of type global (default: "") -;user_agent=Asterisk PBX SVN-branch-12-r404375 ; Value used in User Agent - ; header for SIP requests and - ; Server header for SIP - ; responses (default: "Asterisk - ; PBX SVN-branch-12-r404375") +;user_agent=Asterisk PBX ; Allows you to change the user agent string + ; The default user agent string also contains + ; the Asterisk version. If you don't want to + ; expose this, change the user_agent string. ;default_outbound_endpoint=default_outbound_endpoint ; Endpoint to use when ; sending an outbound ; request to a URI From e5b44c26b46babd40a715b6d91aa0eaf775a0746 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 28 Feb 2017 10:41:45 -0500 Subject: [PATCH 1093/1578] res_config_pgsql: Release table locks where appropriate The find_table() functions NULL or a locked table pointer. We are not consistently calling release_table() in failure paths. Change-Id: I6f665b455799c84b036e5b34904b82b05eab9544 --- res/res_config_pgsql.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 93126c6a5da..2d37c6b194b 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -733,6 +733,7 @@ static int update_pgsql(const char *database, const char *tablename, const char ast_mutex_lock(&pgsql_lock); if (!pgsql_reconnect(database)) { ast_mutex_unlock(&pgsql_lock); + release_table(table); return -1; } @@ -878,6 +879,7 @@ static int update2_pgsql(const char *database, const char *tablename, const stru ast_mutex_lock(&pgsql_lock); if (!pgsql_reconnect(database)) { ast_mutex_unlock(&pgsql_lock); + release_table(table); return -1; } @@ -1322,6 +1324,7 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap if (pgsql_exec(database, tablename, ast_str_buffer(sql), &result) != 0) { ast_mutex_unlock(&pgsql_lock); + release_table(table); return -1; } From 60e9e4fcc0ac340c0bfde1e1ade30e07951e9351 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 28 Feb 2017 14:48:51 -0500 Subject: [PATCH 1094/1578] media_cache: Mark cache entry stale if cache file is removed In the event that a cache file is removed out from under us, we should treat the cache entry as stale and force a refresh. ASTERISK-26774 #close Reported by: Igor Gamayunov Change-Id: I3b1bd0c999d59d18664ef73a29823bc5b431dc52 --- main/media_cache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/media_cache.c b/main/media_cache.c index 7be358879fc..2592f353a9b 100644 --- a/main/media_cache.c +++ b/main/media_cache.c @@ -224,7 +224,8 @@ int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, */ bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (bucket_file) { - if (!ast_bucket_file_is_stale(bucket_file)) { + if (!ast_bucket_file_is_stale(bucket_file) + && !access(bucket_file->path, R_OK)) { ast_copy_string(file_path, bucket_file->path, len); if ((ext = strrchr(file_path, '.'))) { *ext = '\0'; From 9c55a7179800fa66e1887383f2a75eac0efd24b0 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 22 Feb 2017 15:11:29 -0600 Subject: [PATCH 1095/1578] SDP: Add initial SDP state machine. This introduces and documents the various states in the state machine. This also introduces API functions that induce state changes, and places TODO comments telling what needs to be done in addition to what is already there. Those TODOs will be replaced with real code in upcoming changes. Change-Id: I871c0eb480b4c84d83e91ac5628e7a673e8b89ed --- include/asterisk/sdp_state.h | 39 +++++++++ main/sdp_state.c | 157 ++++++++++++++++++++++++++++++++++- 2 files changed, 195 insertions(+), 1 deletion(-) diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index b5e44179ee6..14d3e7c04bb 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -55,4 +55,43 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sd */ struct ast_stream_topology *ast_sdp_state_get_joint_topology(struct ast_sdp_state *sdp_state); +/*! + * \brief Get the local SDP. + * + * If we have not received a remote SDP yet, this will be an SDP offer based + * on known streams and options If we have received a remote SDP, this will + * be the negotiated SDP based on the joint capabilities. The return type is + * a void pointer because the representation of the SDP is going to be determined based + * on the SDP options when allocating the SDP state. + * + * This function will allocate RTP instances if RTP instances have not already + * been allocated for the streams. + * + * The return here is const. The use case for this is so that a channel can add the SDP to an outgoing + * message. The API user should not attempt to modify the SDP. SDP modification should only be done through + * the API. + */ +const void *ast_sdp_state_get_local(struct ast_sdp_state *sdp_state); + +/*! + * \brief Set the remote SDP. + * + * This can be used for either a remote offer or answer. + * This can also be used whenever an UPDATE, re-INVITE, etc. arrives. + * The type of the "remote" parameter is dictated by whatever SDP representation + * was set in the ast_sdp_options used during ast_sdp_state allocation + * + * This function will NOT allocate RTP instances. + */ +int ast_sdp_state_set_remote(struct ast_sdp_state *sdp_state, void *remote); + +/*! + * \brief Reset the SDP state and stream capabilities as if the SDP state had just been allocated. + * + * This is most useful for when a channel driver is sending a session refresh message + * and needs to re-advertise its initial capabilities instead of the previously-negotiated + * joint capabilities. + */ +int ast_sdp_state_reset(struct ast_sdp_state *sdp_state); + #endif /* _ASTERISK_SDP_STATE_H */ diff --git a/main/sdp_state.c b/main/sdp_state.c index 04de6e385a9..b478e71486c 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -25,6 +25,41 @@ #include "asterisk/utils.h" #include "asterisk/stream.h" +enum ast_sdp_state_machine { + /*! \brief The initial state. + * + * The state machine starts here. It also goes back to this + * state whenever ast_sdp_state_reset() is called. + */ + SDP_STATE_INITIAL, + /*! \brief We are the SDP offerer. + * + * The state machine enters this state if in the initial state + * and ast_sdp_state_get_local() is called. When this state is + * entered, a local SDP is created and then returned. + */ + SDP_STATE_OFFERER, + /*! \brief We are the SDP answerer. + * + * The state machine enters this state if in the initial state + * and ast_sdp_state_set_remote() is called. + */ + SDP_STATE_ANSWERER, + /*! \brief The SDP has been negotiated. + * + * This state can be entered from either the offerer or answerer + * state. When this state is entered, a joint SDP is created. + */ + SDP_STATE_NEGOTIATED, + /*! \brief Not an actual state. + * + * This is just here to mark the end of the enumeration. + */ + SDP_STATE_END, +}; + +typedef int (*state_fn)(struct ast_sdp_state *state); + struct ast_sdp_state { /*! Local capabilities, learned through configuration */ struct ast_stream_topology *local_capabilities; @@ -44,6 +79,8 @@ struct ast_sdp_state { struct ast_sdp_translator *translator; /*! RTP instance for each media stream */ AST_VECTOR(, struct ast_rtp_instance *) rtp; + /*! The current state machine state that we are in */ + enum ast_sdp_state_machine state; }; struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, struct ast_sdp_options *options) @@ -68,6 +105,7 @@ struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, s ast_sdp_state_free(sdp_state); return NULL; } + sdp_state->state = SDP_STATE_INITIAL; return sdp_state; } @@ -90,6 +128,8 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state) struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sdp_state, int stream_index) { + ast_assert(sdp_state != NULL); + if (stream_index >= AST_VECTOR_SIZE(&sdp_state->rtp)) { return NULL; } @@ -99,9 +139,124 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sd struct ast_stream_topology *ast_sdp_state_get_joint_topology(struct ast_sdp_state *sdp_state) { - if (sdp_state->joint_capabilities) { + ast_assert(sdp_state != NULL); + if (sdp_state->state == SDP_STATE_NEGOTIATED) { return sdp_state->joint_capabilities; } else { return sdp_state->local_capabilities; } } + +static int merge_sdps(struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state->local_sdp != NULL); + ast_assert(sdp_state->remote_sdp != NULL); + /* XXX STUB */ + /* The goal of this function is to take + * sdp_state->local_sdp and sdp_state->remote_sdp + * and negotiate those into a joint SDP. This joint + * SDP should be stored in sdp_state->joint_sdp. After + * the joint SDP is created, the joint SDP should be + * used to create the joint topology. Finally, if necessary, + * the RTP session may need to be adjusted in some ways. For + * instance, if we previously opened three ports for three + * streams, but we negotiate down to two streams, then we + * can shut down the port for the third stream. Similarly, + * if we end up negotiating something like BUNDLE, then we may + * need to tell the RTP layer to close ports and to multiplex + * streams. + */ + + return 0; +} + +const void *ast_sdp_state_get_local(struct ast_sdp_state *sdp_state) +{ + struct ast_sdp *sdp; + + ast_assert(sdp_state != NULL); + + /*TODO Create RTP instances based on local topology and SDP options (if not already created) */ + /*TODO Create local SDP based on local topology, SDP options, and RTP ports (if not already created) */ + + switch (sdp_state->state) { + case SDP_STATE_INITIAL: + sdp_state->state = SDP_STATE_OFFERER; + /* Fall through */ + case SDP_STATE_OFFERER: + default: + sdp = sdp_state->local_sdp; + break; + case SDP_STATE_ANSWERER: + sdp_state->state = SDP_STATE_NEGOTIATED; + merge_sdps(sdp_state); + /* Fall through */ + case SDP_STATE_NEGOTIATED: + sdp = sdp_state->joint_sdp; + break; + } + + return ast_sdp_translator_from_sdp(sdp_state->translator, sdp); +} + +int ast_sdp_state_set_remote(struct ast_sdp_state *sdp_state, void *remote) +{ + struct ast_sdp *sdp; + + ast_assert(sdp_state != NULL); + + sdp = ast_sdp_translator_to_sdp(sdp_state->translator, remote); + if (!sdp) { + return -1; + } + + sdp_state->remote_sdp = remote; + /* TODO Convert the remote SDP into a topology and store that in + * sdp_state->remote_capabilities + */ + + switch (sdp_state->state) { + case SDP_STATE_ANSWERER: + default: + break; + case SDP_STATE_INITIAL: + sdp_state->state = SDP_STATE_ANSWERER; + break; + case SDP_STATE_OFFERER: + sdp_state->state = SDP_STATE_NEGOTIATED; + /* Fall through */ + case SDP_STATE_NEGOTIATED: + /* If state is already negotiated, and we receive a new + * remote SDP, we need to re-create the joint SDP and joint + * capabilities + */ + merge_sdps(sdp_state); + break; + } + + return 0; +} + +int ast_sdp_state_reset(struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state != NULL); + + ast_sdp_free(sdp_state->local_sdp); + sdp_state->local_sdp = NULL; + + ast_sdp_free(sdp_state->remote_sdp); + sdp_state->remote_sdp = NULL; + + ast_sdp_free(sdp_state->joint_sdp); + sdp_state->joint_sdp = NULL; + + ast_stream_topology_free(sdp_state->remote_capabilities); + sdp_state->remote_capabilities = NULL; + + ast_stream_topology_free(sdp_state->joint_capabilities); + sdp_state->joint_capabilities = NULL; + + sdp_state->state = SDP_STATE_INITIAL; + + return 0; +} From 1dacf317f3a9e6a2ae0c33ecf97c6ae1acf3cb62 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 1 Mar 2017 08:23:55 -0500 Subject: [PATCH 1096/1578] res_config_pgsql: Make 'require' return consistent with other backends res_config_pgsql should match the behavior of other realtime backend drivers so that queue_log can disable adaptive logging. ASTERISK-25628 #close Reported by: Dmitry Wagin Change-Id: Ic1fb1600c7ce10fdfb1bcdc43c5576b7e0014372 --- res/res_config_pgsql.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 2d37c6b194b..536c9e17331 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -1284,6 +1284,7 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap if (!column) { if (requirements == RQ_WARN) { ast_log(LOG_WARNING, "Table %s requires a column '%s' of size '%d', but no such column exists.\n", tablename, elm, size); + res = -1; } else { struct ast_str *sql = ast_str_create(100); char fieldtype[15]; From 0560c32375a5edd110d544f5762edb6f1fb0f005 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 24 Feb 2017 14:30:33 -0700 Subject: [PATCH 1097/1578] stream: Unit tests for stream read and tweaks framework * Removed the AST_CHAN_TP_MULTISTREAM tech property. We now rely on read_stream being set to indicate a multi stream channel. * Added ast_channel_is_multistream convenience function. * Fixed issue where stream and default_stream weren't being set on a frame retrieved from the queue. * Now testing for NULL being returned from the driver's read or read_stream callback. * Fixed issue where the dropnondefault code was crashing on a NULL f. * Now enforcing that if either read_stream or write_stream are set when ast_channel_tech_set is called that BOTH are set. * Added the unit tests. ASTERISK-26816 Change-Id: If7792b20d782e71e823dabd3124572cf0a4caab2 --- include/asterisk/channel.h | 15 +- main/channel.c | 38 +++-- main/channel_internal_api.c | 13 +- tests/test_stream.c | 330 +++++++++++++++++++++++++++++++++--- 4 files changed, 348 insertions(+), 48 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index f6e09252f3a..3ae1e2fd41d 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -911,10 +911,6 @@ enum { * world */ AST_CHAN_TP_INTERNAL = (1 << 2), - /*! - * \brief Channels with this particular technology support multiple simultaneous streams - */ - AST_CHAN_TP_MULTISTREAM = (1 << 3), }; /*! \brief ast_channel flags */ @@ -4843,4 +4839,15 @@ struct ast_stream_topology *ast_channel_set_stream_topology( */ struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan, enum ast_media_type type); +/*! + * \brief Determine if a channel is multi-stream capable + * + * \param channel The channel to test + * + * \pre chan is locked + * + * \return Returns true if the channel is multi-stream capable. + */ +int ast_channel_is_multistream(struct ast_channel *chan); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/main/channel.c b/main/channel.c index e3e9561fe95..12a30e04891 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3944,13 +3944,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int default: break; } - } else if (!(ast_channel_tech(chan)->properties & AST_CHAN_TP_MULTISTREAM) && ( - f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { - /* Since this channel driver does not support multistream determine the default stream this frame - * originated from and update the frame to include it. - */ - stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); - f->stream_num = ast_stream_get_position(stream); + } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { + if (ast_channel_tech(chan) && ast_channel_tech(chan)->read_stream) { + stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num); + default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + } else { + /* Since this channel driver does not support multistream determine the default stream this frame + * originated from and update the frame to include it. + */ + stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + f->stream_num = ast_stream_get_position(stream); + } } } else { ast_channel_blocker_set(chan, pthread_self()); @@ -3970,7 +3974,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int * thing different is that we need to find the default stream so we know whether to invoke the * default stream logic or not (such as transcoding). */ - if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { + if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num); default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); } @@ -3980,7 +3984,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int /* Since this channel driver does not support multistream determine the default stream this frame * originated from and update the frame to include it. */ - if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { + if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); f->stream_num = ast_stream_get_position(stream); } @@ -3989,13 +3993,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int ast_log(LOG_WARNING, "No read routine on channel %s\n", ast_channel_name(chan)); } - if (dropnondefault && stream != default_stream) { - /* If the frame originates from a non-default stream and the caller can not handle other streams - * absord the frame and replace it with a null one instead. - */ - ast_frfree(f); - f = &ast_null_frame; - } else if (stream == default_stream) { + if (stream == default_stream) { /* Perform the framehook read event here. After the frame enters the framehook list * there is no telling what will happen, !!! */ f = ast_framehook_list_read_event(ast_channel_framehooks(chan), f); @@ -4022,6 +4020,14 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int AST_LIST_NEXT(f, frame_list) = NULL; } + if (dropnondefault && stream != default_stream) { + /* If the frame originates from a non-default stream and the caller can not handle other streams + * absorb the frame and replace it with a null one instead. + */ + ast_frfree(f); + f = &ast_null_frame; + } + switch (f->frametype) { case AST_FRAME_CONTROL: if (f->subclass.integer == AST_CONTROL_ANSWER) { diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 362bd1a3d09..d7ae8f9c118 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -867,7 +867,7 @@ void ast_channel_nativeformats_set(struct ast_channel *chan, return; } - if (!chan->tech || !(chan->tech->properties & AST_CHAN_TP_MULTISTREAM) || !value) { + if ((!ast_channel_is_multistream(chan)) || !value) { struct ast_stream_topology *new_topology; if (!value) { @@ -949,6 +949,10 @@ const struct ast_channel_tech *ast_channel_tech(const struct ast_channel *chan) } void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value) { + if (value->read_stream || value->write_stream) { + ast_assert(value->read_stream && value->write_stream); + } + chan->tech = value; } enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan) @@ -1798,7 +1802,7 @@ struct ast_stream_topology *ast_channel_set_stream_topology(struct ast_channel * ast_assert(chan != NULL); /* A non-MULTISTREAM channel can't manipulate topology directly */ - ast_assert(chan->tech != NULL && (chan->tech->properties & AST_CHAN_TP_MULTISTREAM)); + ast_assert(ast_channel_is_multistream(chan)); /* Unless the channel is being destroyed, we always want a topology on * it even if its empty. @@ -1839,3 +1843,8 @@ void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1, channel_set_default_streams(chan1); channel_set_default_streams(chan2); } + +int ast_channel_is_multistream(struct ast_channel *chan) +{ + return (chan->tech && chan->tech->read_stream && chan->tech->write_stream); +} diff --git a/tests/test_stream.c b/tests/test_stream.c index d602d52fe27..7c7897697be 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -804,8 +804,75 @@ AST_TEST_DEFINE(stream_topology_create_from_channel_nativeformats) return res; } +struct mock_channel_pvt { + int mallocd; + unsigned int wrote; + unsigned int wrote_stream; + int stream_num; + int frame_limit; + int frame_count; + int streams; + int frames_per_read; +}; + +static struct ast_frame *mock_channel_read(struct ast_channel *chan) +{ + struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); + struct ast_frame f = { 0, }; + struct ast_frame *head_frame = NULL; + struct ast_frame *tail_frame = NULL; + int i; + + if (pvt->frames_per_read == 0) { + pvt->frames_per_read = 1; + } + for (i = 0; i < pvt->frames_per_read && pvt->frame_count < pvt->frame_limit; i++) { + struct ast_frame *fr; + + if (pvt->frame_count % 2 == 0) { + f.frametype = AST_FRAME_VOICE; + f.subclass.format = ast_format_ulaw; + } else { + f.frametype = AST_FRAME_VIDEO; + f.subclass.format = ast_format_h264; + } + f.seqno = pvt->frame_count; + f.stream_num = pvt->frame_count % pvt->streams; + pvt->frame_count++; + fr = ast_frdup(&f); + if (!head_frame) { + head_frame = fr; + } else { + tail_frame->frame_list.next = fr; + } + tail_frame = fr; + } + + return(head_frame); +} + +static int mock_channel_write(struct ast_channel *chan, struct ast_frame *fr) +{ + struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); + + pvt->wrote = 1; + + return 0; +} + +static int mock_channel_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr) +{ + struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); + + pvt->wrote_stream = 1; + pvt->stream_num = stream_num; + + return 0; +} + static const struct ast_channel_tech mock_stream_channel_tech = { - .properties = AST_CHAN_TP_MULTISTREAM, + .read_stream = mock_channel_read, + .write_stream = mock_channel_write_stream, }; AST_TEST_DEFINE(stream_topology_channel_set) @@ -853,33 +920,14 @@ AST_TEST_DEFINE(stream_topology_channel_set) return res; } -struct mock_channel_pvt { - unsigned int wrote; - unsigned int wrote_stream; - int stream_num; -}; - -static int mock_channel_write(struct ast_channel *chan, struct ast_frame *fr) -{ - struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); - - pvt->wrote = 1; - - return 0; -} - -static int mock_channel_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr) +static int mock_channel_hangup(struct ast_channel *chan) { struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); - pvt->wrote_stream = 1; - pvt->stream_num = stream_num; - - return 0; -} + if (pvt->mallocd) { + ast_free(pvt); + } -static int mock_channel_hangup(struct ast_channel *chan) -{ ast_channel_tech_pvt_set(chan, NULL); return 0; } @@ -894,7 +942,7 @@ AST_TEST_DEFINE(stream_write_non_multistream) { RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); struct ast_channel *mock_channel; - struct mock_channel_pvt pvt; + struct mock_channel_pvt pvt = { 0, }; enum ast_test_result_state res = AST_TEST_FAIL; struct ast_frame frame = { 0, }; @@ -981,10 +1029,10 @@ AST_TEST_DEFINE(stream_write_non_multistream) } static const struct ast_channel_tech mock_channel_write_stream_tech = { - .properties = AST_CHAN_TP_MULTISTREAM, .write = mock_channel_write, .write_video = mock_channel_write, .write_stream = mock_channel_write_stream, + .read_stream = mock_channel_read, .hangup = mock_channel_hangup, }; @@ -1268,6 +1316,232 @@ AST_TEST_DEFINE(stream_write_multistream) return res; } +static int load_stream_readqueue(struct ast_channel *chan, int frames) +{ + struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); + struct ast_frame f = { 0, }; + struct ast_frame *frame = NULL; + int i; + + while ((frame = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list))) + ast_frfree(frame); + + for (i = 0; i < frames; i++) { + if (pvt->frame_count % 2 == 0) { + f.frametype = AST_FRAME_VOICE; + f.subclass.format = ast_format_ulaw; + } else { + f.frametype = AST_FRAME_VIDEO; + f.subclass.format = ast_format_h264; + } + f.stream_num = pvt->frame_count % pvt->streams; + f.seqno = pvt->frame_count; + ast_queue_frame(chan, ast_frdup(&f)); + pvt->frame_count++; + } + + return 0; +} + +static struct ast_channel *make_channel(struct ast_test *test, int streams, + struct ast_channel_tech *tech) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + struct ast_channel *mock_channel = NULL; + struct mock_channel_pvt *pvt = NULL; + struct ast_stream_topology *topology = NULL; + struct ast_stream *stream; + enum ast_test_result_state res = AST_TEST_PASS; + int i; + + mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"); + ast_test_validate_cleanup(test, mock_channel, res, done); + ast_channel_tech_set(mock_channel, tech); + + if (tech->read_stream) { + topology = ast_stream_topology_alloc(); + ast_test_validate_cleanup(test, topology, res, done); + + for (i = 0; i < streams; i++) { + stream = ast_stream_alloc((i % 2 ? "video": "audio"), (i % 2 ? AST_MEDIA_TYPE_VIDEO : AST_MEDIA_TYPE_AUDIO)); + ast_test_validate_cleanup(test, stream, res, done); + ast_test_validate_cleanup(test, ast_stream_topology_append_stream(topology, stream) == i, res, done); + } + ast_test_validate_cleanup(test, ast_stream_topology_get_count(topology) == streams, res, done); + ast_channel_set_stream_topology(mock_channel, topology); + topology = NULL; + } else { + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_test_validate_cleanup(test, caps, res, done); + + ast_test_validate_cleanup(test, ast_format_cap_append(caps, ast_format_ulaw, 0) == 0, res, done); + ast_test_validate_cleanup(test, ast_format_cap_append(caps, ast_format_h264, 0) == 0, res, done); + ast_channel_nativeformats_set(mock_channel, caps); + } + + pvt = ast_calloc(1, sizeof(*pvt)); + ast_test_validate_cleanup(test, pvt, res, done); + pvt->mallocd = 1; + ast_channel_tech_pvt_set(mock_channel, pvt); + + ast_channel_unlock(mock_channel); + +done: + ast_stream_topology_free(topology); + if (res == AST_TEST_FAIL && mock_channel) { + ast_hangup(mock_channel); + } + + return mock_channel; +} + +enum CHANNEL_READ_TYPE { + CHANNEL_READ, + CHANNEL_READ_STREAM +}; + +static struct ast_frame *read_from_chan(enum CHANNEL_READ_TYPE rt, struct ast_channel *chan) +{ + if (rt == CHANNEL_READ_STREAM) { + return ast_read_stream(chan); + } else { + return ast_read(chan); + } +} + +static enum ast_test_result_state read_test(struct ast_test *test, struct ast_channel_tech *tech, + enum CHANNEL_READ_TYPE rt, int streams, int frames, int frames_per_read, int expected_nulls) +{ + struct ast_channel *mock_channel; + struct mock_channel_pvt *pvt; + struct ast_frame *fr = NULL; + enum ast_test_result_state res = AST_TEST_PASS; + int i = 0; + int null_frames = 0; + + ast_test_status_update(test, "ChanType: %s ReadType: %s Streams: %d Frames: %d Frames per read: %d Expected Nulls: %d\n", + tech->read_stream ? "MULTI" : "NON-MULTI", + rt == CHANNEL_READ_STREAM ? "STREAM" : "NON-STREAM", + streams, frames, frames_per_read, expected_nulls); + mock_channel = make_channel(test, 4, tech); + ast_test_validate_cleanup(test, mock_channel, res, done); + + pvt = ast_channel_tech_pvt(mock_channel); + pvt->frame_count = 0; + pvt->frame_limit = frames; + pvt->streams = streams; + pvt->frames_per_read = frames_per_read; + + load_stream_readqueue(mock_channel, frames / 2); + ast_channel_fdno_set(mock_channel, 0); + + while ((fr = read_from_chan(rt, mock_channel))) { + ast_channel_fdno_set(mock_channel, 0); + if (fr->frametype != AST_FRAME_NULL) { + ast_test_validate_cleanup(test, i == fr->seqno, res, done); + ast_test_validate_cleanup(test, fr->frametype == ( i % 2 ? AST_FRAME_VIDEO : AST_FRAME_VOICE), res, done); + ast_test_validate_cleanup(test, fr->stream_num == ( i % streams ), res, done); + ast_frfree(fr); + } else { + null_frames++; + } + fr = NULL; + i++; + } + ast_test_validate_cleanup(test, i == frames, res, done); + ast_test_validate_cleanup(test, null_frames == expected_nulls, res, done); + +done: + ast_test_status_update(test, " Frames read: %d NULL frames: %d\n", i, null_frames); + ast_hangup(mock_channel); + + return res; +} + +AST_TEST_DEFINE(stream_read_non_multistream) +{ + struct ast_channel_tech tech = { + .read = mock_channel_read, + .hangup = mock_channel_hangup, + }; + + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_read_non_multistream"; + info->category = "/main/stream/"; + info->summary = "stream reading from non-multistream capable channel test"; + info->description = + "Test that reading frames from a non-multistream channel works as expected"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + res = read_test(test, &tech, CHANNEL_READ, 2, 16, 1, 0); + ast_test_validate(test, res == AST_TEST_PASS, "non multi, non read stream, 2 stream"); + + res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 1, 0); + ast_test_validate(test, res == AST_TEST_PASS, "non multi, read stream, 2 stream"); + + res = read_test(test, &tech, CHANNEL_READ, 2, 16, 3, 0); + ast_test_validate(test, res == AST_TEST_PASS, "non multi, non read stream, 2 stream, 3 frames per read"); + + res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 3, 0); + ast_test_validate(test, res == AST_TEST_PASS, "non multi, read stream, 2 stream, 3 frames per read"); + + return res; +} + +AST_TEST_DEFINE(stream_read_multistream) +{ + struct ast_channel_tech tech = { + .read_stream = mock_channel_read, + .write_stream = mock_channel_write_stream, + .hangup = mock_channel_hangup, + }; + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_read_multistream"; + info->category = "/main/stream/"; + info->summary = "stream reading from multistream capable channel test"; + info->description = + "Test that reading frames from a multistream channel works as expected"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + res = read_test(test, &tech, CHANNEL_READ, 2, 16, 1, 0); + ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 2 stream"); + + res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 1, 0); + ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 2 stream"); + + res = read_test(test, &tech, CHANNEL_READ, 4, 16, 1, 8); + ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 4 stream"); + + res = read_test(test, &tech, CHANNEL_READ_STREAM, 4, 16, 1, 0); + ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 4 stream"); + + res = read_test(test, &tech, CHANNEL_READ, 2, 16, 3, 0); + ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 2 stream, 3 frames per read"); + + res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 3, 0); + ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 2 stream, 3 frames per read"); + + res = read_test(test, &tech, CHANNEL_READ, 4, 16, 3, 8); + ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 4 stream, 3 frames per read"); + + res = read_test(test, &tech, CHANNEL_READ_STREAM, 4, 16, 3, 0); + ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 4 stream, 3 frames per read"); + + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -1286,6 +1560,8 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_channel_set); AST_TEST_UNREGISTER(stream_write_non_multistream); AST_TEST_UNREGISTER(stream_write_multistream); + AST_TEST_UNREGISTER(stream_read_non_multistream); + AST_TEST_UNREGISTER(stream_read_multistream); return 0; } @@ -1306,6 +1582,8 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_channel_set); AST_TEST_REGISTER(stream_write_non_multistream); AST_TEST_REGISTER(stream_write_multistream); + AST_TEST_REGISTER(stream_read_non_multistream); + AST_TEST_REGISTER(stream_read_multistream); return AST_MODULE_LOAD_SUCCESS; } From 7922f26cb0377b0d36ead20178bf1d3bf06db784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20H?= Date: Thu, 16 Feb 2017 10:22:47 +0000 Subject: [PATCH 1098/1578] res_pjsip WebRTC/websockets: Fix usage of WS vs WSS. According to the RFC[1] WSS should only be used in the Via header for secure Websockets. * Use WSS in Via for secure transport. * Only register one transport with the WS name because it would be ambiguous. Outgoing requests may try to find the transport by name and pjproject only finds the first one registered. This may mess up unsecure websockets but the impact should be minimal. Firefox and Chrome do not support anything other than secure websockets anymore. * Added and updated some debug messages concerning websockets. * security_events.c: Relax case restriction when determining security transport type. * The res_pjsip_nat module has been updated to not touch the transport on Websocket originating messages. [1] https://tools.ietf.org/html/rfc7118 ASTERISK-26796 #close Change-Id: Ie3a0fb1a41101a4c1e49d875a8aa87b189e7ab12 --- CHANGES | 8 +++++ res/res_pjsip/security_events.c | 4 +-- res/res_pjsip_nat.c | 4 ++- res/res_pjsip_transport_websocket.c | 53 ++++++++++++++++++++++------- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index d3d0cb81eee..371e9e14249 100644 --- a/CHANGES +++ b/CHANGES @@ -101,6 +101,14 @@ app_voicemail * The 'Comedian Mail' prompts can now be overriden using the 'vm-login' and 'vm-newuser' configuration options in voicemail.conf. +res_pjsip_transport_websocket +------------------ + * Removed non-secure websocket support. Firefox and Chrome have not allowed + non-secure websockets for quite some time so this shouldn't be an issue + for people. Attempting to use a non-secure websocket may or may not work + when Asterisk attempts to send SIP requests to do something like initiate + call hangup. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/res/res_pjsip/security_events.c b/res/res_pjsip/security_events.c index b8a8d521225..ea3810bfd6e 100644 --- a/res/res_pjsip/security_events.c +++ b/res/res_pjsip/security_events.c @@ -42,9 +42,9 @@ static enum ast_transport security_event_get_transport(pjsip_rx_data *rdata) } else if (rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS || rdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS6) { return AST_TRANSPORT_TLS; - } else if (!strcmp(rdata->tp_info.transport->type_name, "WS")) { + } else if (!strcasecmp(rdata->tp_info.transport->type_name, "WS")) { return AST_TRANSPORT_WS; - } else if (!strcmp(rdata->tp_info.transport->type_name, "WSS")) { + } else if (!strcasecmp(rdata->tp_info.transport->type_name, "WSS")) { return AST_TRANSPORT_WSS; } else { return 0; diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c index a32d12bfdba..a855298b2fa 100644 --- a/res/res_pjsip_nat.c +++ b/res/res_pjsip_nat.c @@ -35,7 +35,9 @@ static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri) { pj_cstr(&uri->host, rdata->pkt_info.src_name); - if (strcasecmp("udp", rdata->tp_info.transport->type_name)) { + if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) { + /* WSS is special, we don't want to overwrite the URI at all as it needs to be ws */ + } else if (strcasecmp("udp", rdata->tp_info.transport->type_name)) { uri->transport_param = pj_str(rdata->tp_info.transport->type_name); } else { uri->transport_param.slen = 0; diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index a9f5268846f..a52b42dfc1d 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -38,7 +38,6 @@ #include "asterisk/res_pjsip_session.h" #include "asterisk/taskprocessor.h" -static int transport_type_ws; static int transport_type_wss; /*! @@ -149,6 +148,7 @@ static int transport_create(void *data) pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); struct pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt); + char *ws_addr_str; pj_pool_t *pool; pj_str_t buf; pj_status_t status; @@ -183,9 +183,23 @@ static int transport_create(void *data) goto on_error; } - pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(newtransport->ws_session))), &newtransport->transport.key.rem_addr); + /* + * The type_name here is mostly used by log messages eihter in + * pjproject or Asterisk. Other places are reconstituting subscriptions + * after a restart (which could never work for a websocket connection anyway), + * received MESSAGE requests to set PJSIP_TRANSPORT, and most importantly + * by pjproject when generating the Via header. + */ + newtransport->transport.type_name = ast_websocket_is_secure(newtransport->ws_session) + ? "WSS" : "WS"; + + ws_addr_str = ast_sockaddr_stringify(ast_websocket_remote_address(newtransport->ws_session)); + ast_debug(4, "Creating websocket transport for %s:%s\n", + newtransport->transport.type_name, ws_addr_str); + + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr); newtransport->transport.key.rem_addr.addr.sa_family = pj_AF_INET(); - newtransport->transport.key.type = ast_websocket_is_secure(newtransport->ws_session) ? transport_type_wss : transport_type_ws; + newtransport->transport.key.type = transport_type_wss; newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr); @@ -196,7 +210,6 @@ static int transport_create(void *data) newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr); newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr); - newtransport->transport.type_name = (char *)pjsip_transport_get_type_name(newtransport->transport.key.type); newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type); newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64); @@ -382,19 +395,27 @@ static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata) long type = rdata->tp_info.transport->key.type; - if (type != (long)transport_type_ws && type != (long)transport_type_wss) { + if (type != (long) transport_type_wss) { return PJ_FALSE; } - if ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) && !contact->star && - (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) { + contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); + if (contact + && !contact->star + && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) { pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri); + const pj_str_t *txp_str = &STR_WS; + + ast_debug(4, "%s re-writing Contact URI from %.*s:%d%s%.*s to %s:%d;transport=%s\n", + pjsip_rx_data_get_info(rdata), + (int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port, + pj_strlen(&uri->transport_param) ? ";transport=" : "", + (int)pj_strlen(&uri->transport_param), pj_strbuf(&uri->transport_param), + rdata->pkt_info.src_name ?: "", rdata->pkt_info.src_port, pj_strbuf(txp_str)); pj_cstr(&uri->host, rdata->pkt_info.src_name); uri->port = rdata->pkt_info.src_port; - ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n", - (int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port); - pj_strdup(rdata->tp_info.pool, &uri->transport_param, &STR_WS); + pj_strdup(rdata->tp_info.pool, &uri->transport_param, txp_str); } rdata->msg_info.via->rport_param = 0; @@ -429,8 +450,16 @@ static int load_module(void) { CHECK_PJSIP_MODULE_LOADED(); - pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE, "WS", 5060, &transport_type_ws); - pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "WS", 5060, &transport_type_wss); + /* + * We only need one transport type defined. Firefox and Chrome + * do not support anything other than secure websockets anymore. + * + * Also we really cannot have two transports with the same name + * because it would be ambiguous. Outgoing requests may try to + * find the transport by name and pjproject only finds the first + * one registered. + */ + pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "ws", 5060, &transport_type_wss); if (ast_sip_register_service(&websocket_module) != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; From c9296b23d1574332ccbc83f3fc7ba492cfc34cfe Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 2 Mar 2017 21:27:00 -0600 Subject: [PATCH 1099/1578] core: Cleanup ast_get_hint() usage. * manager.c:manager_state_cb() Fix potential use of uninitialized hint[] if a hint does not exist for the requested extension. Ran into this when developing a testsuite test. The AMI event ExtensionStatus came out with the hint header value containing garbage. The AMI event PresenceStatus also had the same issue. * manager.c:action_extensionstate() no need to completely initialize the hint[]. Only initialize the first element. * pbx.c:ast_add_hint() Remove unnecessary assignment. * chan_sip.c: Eliminate an unneeded hint[] local variable. We only care about the return value of ast_get_hint() there. Change-Id: Ia9a8786f01f93f1f917200f0a50bead0319af97b --- channels/chan_sip.c | 7 ++++--- main/manager.c | 24 ++++++++++++++---------- main/pbx.c | 1 - 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 3e4dafb1b64..8241b67ed92 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -18364,10 +18364,11 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re /* If this is a subscription we actually just need to see if a hint exists for the extension */ if (req->method == SIP_SUBSCRIBE) { - char hint[AST_MAX_EXTENSION]; int which = 0; - if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, uri) || - (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, decoded_uri) && (which = 1))) { + + if (ast_get_hint(NULL, 0, NULL, 0, NULL, p->context, uri) + || (ast_get_hint(NULL, 0, NULL, 0, NULL, p->context, decoded_uri) + && (which = 1))) { if (!oreq) { ast_string_field_set(p, exten, which ? decoded_uri : uri); } diff --git a/main/manager.c b/main/manager.c index f11c8dca4ec..eae1ca52afd 100644 --- a/main/manager.c +++ b/main/manager.c @@ -5680,8 +5680,9 @@ static int action_extensionstate(struct mansession *s, const struct message *m) { const char *exten = astman_get_header(m, "Exten"); const char *context = astman_get_header(m, "Context"); - char hint[256] = ""; + char hint[256]; int status; + if (ast_strlen_zero(exten)) { astman_send_error(s, m, "Extension not specified"); return 0; @@ -5690,16 +5691,18 @@ static int action_extensionstate(struct mansession *s, const struct message *m) context = "default"; } status = ast_extension_state(NULL, context, exten); - ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten); + hint[0] = '\0'; + ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten); astman_start_ack(s, m); - astman_append(s, "Message: Extension Status\r\n" - "Exten: %s\r\n" - "Context: %s\r\n" - "Hint: %s\r\n" - "Status: %d\r\n" - "StatusText: %s\r\n\r\n", - exten, context, hint, status, - ast_extension_state2str(status)); + astman_append(s, "Message: Extension Status\r\n" + "Exten: %s\r\n" + "Context: %s\r\n" + "Hint: %s\r\n" + "Status: %d\r\n" + "StatusText: %s\r\n" + "\r\n", + exten, context, hint, status, + ast_extension_state2str(status)); return 0; } @@ -6973,6 +6976,7 @@ static int manager_state_cb(const char *context, const char *exten, struct ast_s /* Notify managers of change */ char hint[512]; + hint[0] = '\0'; ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten); switch(info->reason) { diff --git a/main/pbx.c b/main/pbx.c index 47e0b0eda0d..fe87d67a5a0 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -3967,7 +3967,6 @@ static int ast_add_hint(struct ast_exten *e) hint_new->last_presence_state = presence_state; hint_new->last_presence_subtype = subtype; hint_new->last_presence_message = message; - message = subtype = NULL; } } From 5a74abc53bb59590ffb8be1363e2d82ebe1755b4 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 6 Mar 2017 14:15:45 -0500 Subject: [PATCH 1100/1578] pbx_spool: Gracefully handle long lines in call files Per the linked issue, we aren't checking the buffer filled by fgets() to determine if it contains a newline, so we will fail to correctly parse the trailing portion of a long line. This patch increases the buffer size from 256 to 1024, and skips any line that exceeds that length, logging a warning in the process. ASTERISK-17067 #close Reported by: Dave Olszewski Change-Id: I51bcf270c1b4347ba05b43f18dc2094c76f5d7b0 --- pbx/pbx_spool.c | 272 +++++++++++++++++++++++++++--------------------- 1 file changed, 152 insertions(+), 120 deletions(-) diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c index ba91d66ab8e..0c6c401cebd 100644 --- a/pbx/pbx_spool.c +++ b/pbx/pbx_spool.c @@ -161,139 +161,171 @@ static struct outgoing *new_outgoing(const char *fn) return o; } -static int apply_outgoing(struct outgoing *o, FILE *f) +static void parse_line(char *line, unsigned int lineno, struct outgoing *o) { - char buf[256]; - char *c, *c2; - int lineno = 0; - struct ast_variable *var, *last = o->vars; + char *c; - while (last && last->next) { - last = last->next; + /* Trim comments */ + c = line; + while ((c = strchr(c, '#'))) { + if ((c == line) || (*(c-1) == ' ') || (*(c-1) == '\t')) { + *c = '\0'; + break; + } + c++; } - while(fgets(buf, sizeof(buf), f)) { - lineno++; - /* Trim comments */ - c = buf; - while ((c = strchr(c, '#'))) { - if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t')) - *c = '\0'; - else - c++; - } - - c = buf; - while ((c = strchr(c, ';'))) { - if ((c > buf) && (c[-1] == '\\')) { - memmove(c - 1, c, strlen(c) + 1); - c++; - } else { - *c = '\0'; - break; - } + c = line; + while ((c = strchr(c, ';'))) { + if ((c > line) && (c[-1] == '\\')) { + memmove(c - 1, c, strlen(c) + 1); + } else { + *c = '\0'; + break; } + } - /* Trim trailing white space */ - ast_trim_blanks(buf); - if (ast_strlen_zero(buf)) { - continue; - } - c = strchr(buf, ':'); - if (!c) { - ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, o->fn); - continue; - } - *c = '\0'; - c = ast_skip_blanks(c + 1); + /* Trim trailing white space */ + ast_trim_blanks(line); + if (ast_strlen_zero(line)) { + return; + } + c = strchr(line, ':'); + if (!c) { + ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, o->fn); + return; + } + *c = '\0'; + c = ast_skip_blanks(c + 1); #if 0 - printf("'%s' is '%s' at line %d\n", buf, c, lineno); + printf("'%s' is '%s' at line %d\n", line, c, lineno); #endif - if (!strcasecmp(buf, "channel")) { - if ((c2 = strchr(c, '/'))) { - *c2 = '\0'; - c2++; - ast_string_field_set(o, tech, c); - ast_string_field_set(o, dest, c2); - } else { - ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, o->fn); - } - } else if (!strcasecmp(buf, "callerid")) { - char cid_name[80] = {0}, cid_num[80] = {0}; - ast_callerid_split(c, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num)); - ast_string_field_set(o, cid_num, cid_num); - ast_string_field_set(o, cid_name, cid_name); - } else if (!strcasecmp(buf, "application")) { - ast_string_field_set(o, app, c); - } else if (!strcasecmp(buf, "data")) { - ast_string_field_set(o, data, c); - } else if (!strcasecmp(buf, "maxretries")) { - if (sscanf(c, "%30d", &o->maxretries) != 1) { - ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, o->fn); - o->maxretries = 0; - } - } else if (!strcasecmp(buf, "codecs")) { - ast_format_cap_update_by_allow_disallow(o->capabilities, c, 1); - } else if (!strcasecmp(buf, "context")) { - ast_string_field_set(o, context, c); - } else if (!strcasecmp(buf, "extension")) { - ast_string_field_set(o, exten, c); - } else if (!strcasecmp(buf, "priority")) { - if ((sscanf(c, "%30d", &o->priority) != 1) || (o->priority < 1)) { - ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, o->fn); - o->priority = 1; - } - } else if (!strcasecmp(buf, "retrytime")) { - if ((sscanf(c, "%30d", &o->retrytime) != 1) || (o->retrytime < 1)) { - ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, o->fn); - o->retrytime = 300; - } - } else if (!strcasecmp(buf, "waittime")) { - if ((sscanf(c, "%30d", &o->waittime) != 1) || (o->waittime < 1)) { - ast_log(LOG_WARNING, "Invalid waittime at line %d of %s\n", lineno, o->fn); - o->waittime = 45; - } - } else if (!strcasecmp(buf, "retry")) { - o->retries++; - } else if (!strcasecmp(buf, "startretry")) { - if (sscanf(c, "%30ld", &o->callingpid) != 1) { - ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n"); - o->callingpid = 0; - } - } else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) { + if (!strcasecmp(line, "channel")) { + char *c2; + if ((c2 = strchr(c, '/'))) { + *c2 = '\0'; + c2++; + ast_string_field_set(o, tech, c); + ast_string_field_set(o, dest, c2); + } else { + ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, o->fn); + } + } else if (!strcasecmp(line, "callerid")) { + char cid_name[80] = {0}, cid_num[80] = {0}; + ast_callerid_split(c, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num)); + ast_string_field_set(o, cid_num, cid_num); + ast_string_field_set(o, cid_name, cid_name); + } else if (!strcasecmp(line, "application")) { + ast_string_field_set(o, app, c); + } else if (!strcasecmp(line, "data")) { + ast_string_field_set(o, data, c); + } else if (!strcasecmp(line, "maxretries")) { + if (sscanf(c, "%30d", &o->maxretries) != 1) { + ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, o->fn); + o->maxretries = 0; + } + } else if (!strcasecmp(line, "codecs")) { + ast_format_cap_update_by_allow_disallow(o->capabilities, c, 1); + } else if (!strcasecmp(line, "context")) { + ast_string_field_set(o, context, c); + } else if (!strcasecmp(line, "extension")) { + ast_string_field_set(o, exten, c); + } else if (!strcasecmp(line, "priority")) { + if ((sscanf(c, "%30d", &o->priority) != 1) || (o->priority < 1)) { + ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, o->fn); + o->priority = 1; + } + } else if (!strcasecmp(line, "retrytime")) { + if ((sscanf(c, "%30d", &o->retrytime) != 1) || (o->retrytime < 1)) { + ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, o->fn); + o->retrytime = 300; + } + } else if (!strcasecmp(line, "waittime")) { + if ((sscanf(c, "%30d", &o->waittime) != 1) || (o->waittime < 1)) { + ast_log(LOG_WARNING, "Invalid waittime at line %d of %s\n", lineno, o->fn); + o->waittime = 45; + } + } else if (!strcasecmp(line, "retry")) { + o->retries++; + } else if (!strcasecmp(line, "startretry")) { + if (sscanf(c, "%30ld", &o->callingpid) != 1) { + ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n"); o->callingpid = 0; - o->retries++; - } else if (!strcasecmp(buf, "delayedretry")) { - } else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) { - c2 = c; - strsep(&c2, "="); - if (c2) { - var = ast_variable_new(c, c2, o->fn); - if (var) { - /* Always insert at the end, because some people want to treat the spool file as a script */ - if (last) { - last->next = var; - } else { - o->vars = var; - } - last = var; + } + } else if (!strcasecmp(line, "endretry") || !strcasecmp(line, "abortretry")) { + o->callingpid = 0; + o->retries++; + } else if (!strcasecmp(line, "delayedretry")) { + } else if (!strcasecmp(line, "setvar") || !strcasecmp(line, "set")) { + char *c2 = c; + + strsep(&c2, "="); + if (c2) { + struct ast_variable *var = ast_variable_new(c, c2, o->fn); + + if (var) { + /* + * Always insert at the end, because some people + * want to treat the spool file as a script + */ + struct ast_variable **tail = &o->vars; + + while (*tail) { + tail = &(*tail)->next; } - } else - ast_log(LOG_WARNING, "Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", buf, buf); - } else if (!strcasecmp(buf, "account")) { - ast_string_field_set(o, account, c); - } else if (!strcasecmp(buf, "alwaysdelete")) { - ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE); - } else if (!strcasecmp(buf, "archive")) { - ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE); - } else if (!strcasecmp(buf, "early_media")) { - ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_EARLY_MEDIA); + *tail = var; + } } else { - ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, o->fn); + ast_log(LOG_WARNING, "Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", line, line); + } + } else if (!strcasecmp(line, "account")) { + ast_string_field_set(o, account, c); + } else if (!strcasecmp(line, "alwaysdelete")) { + ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE); + } else if (!strcasecmp(line, "archive")) { + ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE); + } else if (!strcasecmp(line, "early_media")) { + ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_EARLY_MEDIA); + } else { + ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", line, lineno, o->fn); + } +} + +#define LINE_BUFFER_SIZE 1024 + +static int apply_outgoing(struct outgoing *o, FILE *f) +{ + char buf[LINE_BUFFER_SIZE]; + unsigned int lineno = 0; + + while (fgets(buf, sizeof(buf), f)) { + size_t len = strlen(buf); + + lineno++; + + if (buf[len - 1] == '\n' || feof(f)) { + /* We have a line, parse it */ + parse_line(buf, lineno, o); + continue; + } + + /* Crazy long line, skip it */ + ast_log(LOG_WARNING, "Skipping extremely long line at line %d of %s\n", lineno, o->fn); + + /* Consume the rest of the problematic line */ + while (fgets(buf, sizeof(buf), f)) { + len = strlen(buf); + if (buf[len - 1] == '\n' || feof(f)) { + break; + } } } - if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) { - ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", o->fn); + + if (ast_strlen_zero(o->tech) + || ast_strlen_zero(o->dest) + || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) { + ast_log(LOG_WARNING, "At least one of app or extension must be specified, " + "along with tech and dest in file %s\n", o->fn); return -1; } return 0; From 272259a2c6e952249d07f32948893771e65f3078 Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Mon, 6 Mar 2017 21:54:23 +0000 Subject: [PATCH 1101/1578] Saynumber is trying to get "and" from "digits/" subfolder * say.c Changed 'digits/and' to 'vm-and' for en_GB ASTERISK-26598 #close Change-Id: If1b713e5daea6f952b339f139178d292a6c4fcfe --- main/say.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/say.c b/main/say.c index 4b3711b8545..44f55e25ae5 100644 --- a/main/say.c +++ b/main/say.c @@ -998,7 +998,7 @@ static int ast_say_number_full_de(struct ast_channel *chan, int num, const char /*! \brief ast_say_number_full_en_GB: British syntax New files: - - In addition to American English, the following sounds are required: "and" + - In addition to American English, the following sounds are required: "vm-and" */ static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) { @@ -1021,7 +1021,7 @@ static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const ch ast_copy_string(fn, "digits/hundred", sizeof(fn)); playh = 0; } else if (playa) { - ast_copy_string(fn, "digits/and", sizeof(fn)); + ast_copy_string(fn, "vm-and", sizeof(fn)); playa = 0; } else if (num < 20) { snprintf(fn, sizeof(fn), "digits/%d", num); From 3ed05badb9f6ce3c3a3848b56c0747334624e0c3 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 7 Mar 2017 11:22:18 +0000 Subject: [PATCH 1102/1578] core: Add stream topology changing primitives with tests. This change adds a few things to facilitate stream topology changing: 1. Control frame types have been added for use by the channel driver to notify the application that the channel wants to change the stream topology or that a stream topology change has been accepted. They are also used by the indicate interface to the channel that the application uses to indicate it wants to do the same. 2. Legacy behavior has been adopted in ast_read() such that if a channel requests a stream topology change it is denied automatically and the current stream topology is preserved if the application is not capable of handling streams. Tests have also been written which confirm the multistream and non-multistream behavior. ASTERISK-26839 Change-Id: Ia68ef22bca8e8457265ca4f0f9de600cbcc10bc9 --- channels/chan_iax2.c | 4 + funcs/func_frame_trace.c | 6 + include/asterisk/channel.h | 37 ++++++ include/asterisk/frame.h | 2 + main/channel.c | 41 +++++++ tests/test_stream.c | 239 +++++++++++++++++++++++++++++++++++++ 6 files changed, 329 insertions(+) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index e2f575d048d..6d2eda3f07d 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1430,6 +1430,10 @@ static int iax2_is_control_frame_allowed(int subtype) /* Intended only for the sending machine's local channel structure. */ case AST_CONTROL_MASQUERADE_NOTIFY: /* Intended only for masquerades when calling ast_indicate_data(). */ + case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: + /* Intended only for internal stream topology manipulation. */ + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + /* Intended only for internal stream topology change notification. */ case AST_CONTROL_STREAM_STOP: case AST_CONTROL_STREAM_SUSPEND: case AST_CONTROL_STREAM_RESTART: diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c index 8a0b3dd5928..49abfdf140b 100644 --- a/funcs/func_frame_trace.c +++ b/funcs/func_frame_trace.c @@ -336,6 +336,12 @@ static void print_frame(struct ast_frame *frame) /* Should never happen. */ ast_assert(0); break; + case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: + ast_verbose("SubClass: STREAM_TOPOLOGY_REQUEST_CHANGE\n"); + break; + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + ast_verbose("SubClass: STREAM_TOPOLOGY_CHANGED\n"); + break; case AST_CONTROL_STREAM_STOP: ast_verbose("SubClass: STREAM_STOP\n"); break; diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 3ae1e2fd41d..9a3a967e2e3 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4850,4 +4850,41 @@ struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan, enum */ int ast_channel_is_multistream(struct ast_channel *chan); +/*! + * \brief Request that the stream topology of a channel change + * + * \param chan The channel to change + * \param topology The new stream topology + * + * \pre chan is locked + * + * \retval 0 request has been accepted to be attempted + * \retval -1 request could not be attempted + * + * \note This function initiates an asynchronous request to change the stream topology. It is not + * guaranteed that the topology will change and until an AST_CONTROL_STREAM_TOPOLOGY_CHANGED + * frame is received from the channel the current handler of the channel must tolerate the + * stream topology as it currently exists. + * + * \note This interface is provided for applications and resources to request that the topology change. + * It is not for use by the channel driver itself. + */ +int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology); + +/*! + * \brief Provide notice to a channel that the stream topology has changed + * + * \param chan The channel to provide notice to + * \param topology The new stream topology + * + * \pre chan is locked + * + * \retval 0 success + * \retval -1 failure + * + * \note This interface is provided for applications and resources to accept a topology change. + * It is not for use by the channel driver itself. + */ +int ast_channel_stream_topology_changed(struct ast_channel *chan, struct ast_stream_topology *topology); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index c56539af466..2f6c365ad4b 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -297,6 +297,8 @@ enum ast_control_frame_type { AST_CONTROL_UPDATE_RTP_PEER = 32, /*!< Interrupt the bridge and have it update the peer */ AST_CONTROL_PVT_CAUSE_CODE = 33, /*!< Contains an update to the protocol-specific cause-code stored for branching dials */ AST_CONTROL_MASQUERADE_NOTIFY = 34, /*!< A masquerade is about to begin/end. (Never sent as a frame but directly with ast_indicate_data().) */ + AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE = 35, /*!< Channel indication that a stream topology change has been requested */ + AST_CONTROL_STREAM_TOPOLOGY_CHANGED = 36, /*!< Channel indication that a stream topology change has occurred */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING diff --git a/main/channel.c b/main/channel.c index 12a30e04891..15c7fa4062c 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4068,6 +4068,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int } ast_frfree(f); f = &ast_null_frame; + } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE && dropnondefault) { + /* The caller of this function is incapable of handling streams so we don't accept the change request + * and stick to the streams currently on the channel. + */ + ast_channel_stream_topology_changed(chan, ast_channel_get_stream_topology(chan)); + ast_frfree(f); + f = &ast_null_frame; + } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_CHANGED && dropnondefault) { + /* The caller of this function is incapable of handling streams so we absord the notification that the + * stream topology has changed. + */ + ast_frfree(f); + f = &ast_null_frame; } break; case AST_FRAME_DTMF_END: @@ -4494,6 +4507,8 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con case AST_CONTROL_UPDATE_RTP_PEER: case AST_CONTROL_PVT_CAUSE_CODE: case AST_CONTROL_MASQUERADE_NOTIFY: + case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: case AST_CONTROL_STREAM_STOP: case AST_CONTROL_STREAM_SUSPEND: case AST_CONTROL_STREAM_REVERSE: @@ -4792,6 +4807,8 @@ static int indicate_data_internal(struct ast_channel *chan, int _condition, cons case AST_CONTROL_MCID: case AST_CONTROL_MASQUERADE_NOTIFY: case AST_CONTROL_UPDATE_RTP_PEER: + case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: case AST_CONTROL_STREAM_STOP: case AST_CONTROL_STREAM_SUSPEND: case AST_CONTROL_STREAM_REVERSE: @@ -11147,3 +11164,27 @@ enum ast_channel_error ast_channel_errno(void) { return ast_channel_internal_errno(); } + +int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology) +{ + ast_assert(chan != NULL); + ast_assert(topology != NULL); + + if (!ast_channel_is_multistream(chan) || !ast_channel_tech(chan)->indicate) { + return -1; + } + + return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, topology, sizeof(topology)); +} + +int ast_channel_stream_topology_changed(struct ast_channel *chan, struct ast_stream_topology *topology) +{ + ast_assert(chan != NULL); + ast_assert(topology != NULL); + + if (!ast_channel_is_multistream(chan) || !ast_channel_tech(chan)->indicate) { + return -1; + } + + return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_CHANGED, topology, sizeof(topology)); +} diff --git a/tests/test_stream.c b/tests/test_stream.c index 7c7897697be..3bab67c2cf4 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -813,6 +813,8 @@ struct mock_channel_pvt { int frame_count; int streams; int frames_per_read; + unsigned int indicated_change_request; + unsigned int indicated_changed; }; static struct ast_frame *mock_channel_read(struct ast_channel *chan) @@ -860,6 +862,19 @@ static int mock_channel_write(struct ast_channel *chan, struct ast_frame *fr) return 0; } +static int mock_channel_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen) +{ + struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); + + if (condition == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE) { + pvt->indicated_change_request = 1; + } else if (condition == AST_CONTROL_STREAM_TOPOLOGY_CHANGED) { + pvt->indicated_changed = 1; + } + + return 0; +} + static int mock_channel_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr) { struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan); @@ -1542,6 +1557,222 @@ AST_TEST_DEFINE(stream_read_multistream) return res; } +AST_TEST_DEFINE(stream_topology_change_request_from_application_non_multistream) +{ + struct ast_channel_tech tech = { + .read = mock_channel_read, + .indicate = mock_channel_indicate, + .hangup = mock_channel_hangup, + }; + struct ast_channel *mock_channel; + struct mock_channel_pvt *pvt; + enum ast_test_result_state res = AST_TEST_PASS; + int change_res; + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_change_request_from_application_non_multistream"; + info->category = "/main/stream/"; + info->summary = "stream topology changing on non-multistream channel test"; + info->description = + "Test that an application trying to change the stream topology of a non-multistream channel gets a failure"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + mock_channel = make_channel(test, 1, &tech); + ast_test_validate_cleanup(test, mock_channel, res, done); + + pvt = ast_channel_tech_pvt(mock_channel); + pvt->indicated_change_request = 0; + pvt->indicated_changed = 0; + + topology = ast_stream_topology_alloc(); + ast_test_validate_cleanup(test, topology, res, done); + + change_res = ast_channel_request_stream_topology_change(mock_channel, topology); + + ast_test_validate_cleanup(test, change_res == -1, res, done); + ast_test_validate_cleanup(test, !pvt->indicated_change_request, res, done); + + change_res = ast_channel_stream_topology_changed(mock_channel, topology); + + ast_test_validate_cleanup(test, change_res == -1, res, done); + ast_test_validate_cleanup(test, !pvt->indicated_changed, res, done); + +done: + ast_hangup(mock_channel); + + return res; +} + +AST_TEST_DEFINE(stream_topology_change_request_from_channel_non_multistream) +{ + struct ast_channel_tech tech = { + .read_stream = mock_channel_read, + .write_stream = mock_channel_write_stream, + .indicate = mock_channel_indicate, + .hangup = mock_channel_hangup, + }; + struct ast_channel *mock_channel; + struct mock_channel_pvt *pvt; + enum ast_test_result_state res = AST_TEST_PASS; + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + struct ast_frame request_change = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, + }; + struct ast_frame *fr = NULL; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_change_request_from_channel_non_multistream"; + info->category = "/main/stream/"; + info->summary = "channel requesting stream topology change to non-multistream application test"; + info->description = + "Test that a channel requesting a stream topology change from a non-multistream application does not work"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + mock_channel = make_channel(test, 1, &tech); + ast_test_validate_cleanup(test, mock_channel, res, done); + + pvt = ast_channel_tech_pvt(mock_channel); + pvt->indicated_changed = 0; + + topology = ast_stream_topology_alloc(); + ast_test_validate_cleanup(test, topology, res, done); + + request_change.data.ptr = topology; + ast_queue_frame(mock_channel, &request_change); + + fr = ast_read(mock_channel); + ast_test_validate_cleanup(test, fr, res, done); + ast_test_validate_cleanup(test, fr == &ast_null_frame, res, done); + ast_test_validate_cleanup(test, pvt->indicated_changed, res, done); + +done: + if (fr) { + ast_frfree(fr); + } + ast_hangup(mock_channel); + + return res; +} + +AST_TEST_DEFINE(stream_topology_change_request_from_application) +{ + struct ast_channel_tech tech = { + .read_stream = mock_channel_read, + .write_stream = mock_channel_write_stream, + .indicate = mock_channel_indicate, + .hangup = mock_channel_hangup, + }; + struct ast_channel *mock_channel; + struct mock_channel_pvt *pvt; + enum ast_test_result_state res = AST_TEST_PASS; + int change_res; + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_change_request_from_application"; + info->category = "/main/stream/"; + info->summary = "stream topology change request from application test"; + info->description = + "Test that an application changing the stream topology of a multistream capable channel receives success"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + mock_channel = make_channel(test, 1, &tech); + ast_test_validate_cleanup(test, mock_channel, res, done); + + pvt = ast_channel_tech_pvt(mock_channel); + pvt->indicated_change_request = 0; + pvt->indicated_changed = 0; + + topology = ast_stream_topology_alloc(); + ast_test_validate_cleanup(test, topology, res, done); + + change_res = ast_channel_request_stream_topology_change(mock_channel, topology); + + ast_test_validate_cleanup(test, !change_res, res, done); + ast_test_validate_cleanup(test, pvt->indicated_change_request, res, done); + + change_res = ast_channel_stream_topology_changed(mock_channel, topology); + + ast_test_validate_cleanup(test, !change_res, res, done); + ast_test_validate_cleanup(test, pvt->indicated_changed, res, done); + +done: + ast_hangup(mock_channel); + + return res; +} + +AST_TEST_DEFINE(stream_topology_change_request_from_channel) +{ + struct ast_channel_tech tech = { + .read_stream = mock_channel_read, + .write_stream = mock_channel_write_stream, + .indicate = mock_channel_indicate, + .hangup = mock_channel_hangup, + }; + struct ast_channel *mock_channel; + struct mock_channel_pvt *pvt; + enum ast_test_result_state res = AST_TEST_PASS; + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + struct ast_frame request_change = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, + }; + struct ast_frame *fr = NULL; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_change_request_from_channel"; + info->category = "/main/stream/"; + info->summary = "channel requesting stream topology change to multistream application test"; + info->description = + "Test that a channel requesting a stream topology change from a multistream application works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + mock_channel = make_channel(test, 1, &tech); + ast_test_validate_cleanup(test, mock_channel, res, done); + + pvt = ast_channel_tech_pvt(mock_channel); + pvt->indicated_changed = 0; + + topology = ast_stream_topology_alloc(); + ast_test_validate_cleanup(test, topology, res, done); + + request_change.data.ptr = topology; + ast_queue_frame(mock_channel, &request_change); + + fr = ast_read_stream(mock_channel); + ast_test_validate_cleanup(test, fr, res, done); + ast_test_validate_cleanup(test, fr->frametype == AST_FRAME_CONTROL, res, done); + ast_test_validate_cleanup(test, fr->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, res, done); + ast_test_validate_cleanup(test, !pvt->indicated_changed, res, done); + +done: + if (fr) { + ast_frfree(fr); + } + ast_hangup(mock_channel); + + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -1562,6 +1793,10 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_write_multistream); AST_TEST_UNREGISTER(stream_read_non_multistream); AST_TEST_UNREGISTER(stream_read_multistream); + AST_TEST_UNREGISTER(stream_topology_change_request_from_application_non_multistream); + AST_TEST_UNREGISTER(stream_topology_change_request_from_channel_non_multistream); + AST_TEST_UNREGISTER(stream_topology_change_request_from_application); + AST_TEST_UNREGISTER(stream_topology_change_request_from_channel); return 0; } @@ -1584,6 +1819,10 @@ static int load_module(void) AST_TEST_REGISTER(stream_write_multistream); AST_TEST_REGISTER(stream_read_non_multistream); AST_TEST_REGISTER(stream_read_multistream); + AST_TEST_REGISTER(stream_topology_change_request_from_application_non_multistream); + AST_TEST_REGISTER(stream_topology_change_request_from_channel_non_multistream); + AST_TEST_REGISTER(stream_topology_change_request_from_application); + AST_TEST_REGISTER(stream_topology_change_request_from_channel); return AST_MODULE_LOAD_SUCCESS; } From d51ca4b406e9d45019f00ab8623a2595d189aecd Mon Sep 17 00:00:00 2001 From: Jean Aunis Date: Tue, 7 Mar 2017 15:12:48 +0100 Subject: [PATCH 1103/1578] chan_sip: Call not cancelled after receiving a 422 response When receiving a 422 response, the invitestate variable must be reset to INV_CALLING. ASTERISK-26841 Change-Id: Ia0502d6b02192664cefa4e75bafdd2645ce56099 --- channels/chan_sip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 8241b67ed92..d158b0dbd94 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -23980,6 +23980,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest case 422: /* Session-Timers: Session interval too small */ xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); ast_string_field_set(p, theirtag, NULL); + p->invitestate = INV_CALLING; proc_422_rsp(p, req); break; From 5d0371d7437440482f8d8e42f9fde7288a53159e Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 7 Mar 2017 13:38:17 -0600 Subject: [PATCH 1104/1578] res_http_websocket: Fix faulty read logic. When doing some WebRTC testing, I found that the websocket would disconnect whenever I attempted to place a call into Asterisk. After looking into it, I pinpointed the problem to be due to the iostreams change being merged in. Under certain circumstances, a call to ast_iostream_read() can return a negative value. However, in this circumstance, the websocket code was treating this negative return as if it were a partial read from the websocket. The expected length would get adjusted by this negative value, resulting in the expected length being too large. This patch simply adds an if check to be sure that we are only updating the expected length of a read when the return from a read is positive. ASTERISK-26842 #close Reported by Mark Michelson Change-Id: Ib4423239828a013d27d7bc477d317d2f02db61ab --- res/res_http_websocket.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 84138234ebf..799eb848fad 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -529,10 +529,12 @@ static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len return -1; } } - xlen = xlen - rlen; - rbuf = rbuf + rlen; - if (!xlen) { - break; + if (rlen > 0) { + xlen = xlen - rlen; + rbuf = rbuf + rlen; + if (!xlen) { + break; + } } if (ast_wait_for_input(ast_iostream_get_fd(session->stream), 1000) < 0) { ast_log(LOG_ERROR, "ast_wait_for_input returned err: %s\n", strerror(errno)); From 60998371e3806a55c7cca5ff4dace4b8155dc004 Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Wed, 8 Mar 2017 14:16:29 +0000 Subject: [PATCH 1105/1578] app_voicemail: Cannot set fromstring on a per-mailbox basis * apps/app_voicemail.c fromstring field added to mailbox which will override the global fromstring if set. ASTERISK-24562 #close Change-Id: I5e90e3a1ec2b2d5340b49a0db825e4bbb158b2fe --- CHANGES | 3 +++ apps/app_voicemail.c | 20 ++++++++++++++++---- configs/samples/voicemail.conf.sample | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 371e9e14249..696abeb9db2 100644 --- a/CHANGES +++ b/CHANGES @@ -101,6 +101,9 @@ app_voicemail * The 'Comedian Mail' prompts can now be overriden using the 'vm-login' and 'vm-newuser' configuration options in voicemail.conf. + * Added 'fromstring' field to the voicemail boxes. If set, it will override + the global 'fromstring' field on a per-mailbox basis. + res_pjsip_transport_websocket ------------------ * Removed non-secure websocket support. Firefox and Chrome have not allowed diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 1d7ffc042a4..aebaafaf362 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -803,6 +803,7 @@ struct ast_vm_user { char *emailbody; /*!< E-mail body */ char pager[80]; /*!< E-mail address to pager (no attachment) */ char serveremail[80]; /*!< From: Mail address */ + char fromstring[100]; /*!< From: Username */ char language[MAX_LANGUAGE]; /*!< Config: Language setting */ char zonetag[80]; /*!< Time zone */ char locale[20]; /*!< The locale (for presentation of date/time) */ @@ -811,7 +812,7 @@ struct ast_vm_user { char uniqueid[80]; /*!< Unique integer identifier */ char exit[80]; char attachfmt[20]; /*!< Attachment format */ - unsigned int flags; /*!< VM_ flags */ + unsigned int flags; /*!< VM_ flags */ int saydurationm; int minsecs; /*!< Minimum number of seconds per message for this mailbox */ int maxmsg; /*!< Maximum number of msgs per folder for this mailbox */ @@ -1308,6 +1309,8 @@ static void apply_option(struct ast_vm_user *vmu, const char *var, const char *v ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt)); } else if (!strcasecmp(var, "serveremail")) { ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail)); + } else if (!strcasecmp(var, "fromstring")) { + ast_copy_string(vmu->fromstring, value, sizeof(vmu->fromstring)); } else if (!strcasecmp(var, "emailbody")) { ast_free(vmu->emailbody); vmu->emailbody = ast_strdup(substitute_escapes(value)); @@ -5114,12 +5117,13 @@ static void make_email_file(FILE *p, /* Set date format for voicemail mail */ ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL)); - if (!ast_strlen_zero(fromstring)) { + if (!ast_strlen_zero(fromstring) || !ast_strlen_zero(vmu->fromstring)) { struct ast_channel *ast; + char *e_fromstring = !ast_strlen_zero(vmu->fromstring) ? vmu->fromstring : fromstring; if ((ast = ast_dummy_channel_alloc())) { char *ptr; prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag); - ast_str_substitute_variables(&str1, 0, ast, fromstring); + ast_str_substitute_variables(&str1, 0, ast, e_fromstring); if (check_mime(ast_str_buffer(str1))) { first_line = 1; @@ -12311,7 +12315,7 @@ AST_TEST_DEFINE(test_voicemail_vmuser) struct ast_vm_user *vmu; /* language parameter seems to only be used for display in manager action */ static const char options_string[] = "attach=yes|attachfmt=wav49|" - "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|" + "serveremail=someguy@digium.com|fromstring=Voicemail System|tz=central|delete=yes|saycid=yes|" "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|" "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|" "forcegreetings=yes|callback=somecontext|dialout=somecontext2|" @@ -12352,6 +12356,10 @@ AST_TEST_DEFINE(test_voicemail_vmuser) ast_test_status_update(test, "Parse failure for attachftm option\n"); res = 1; } + if (strcasecmp(vmu->fromstring, "Voicemail System")) { + ast_test_status_update(test, "Parse failure for fromstring option\n"); + res = 1; + } if (strcasecmp(vmu->serveremail, "someguy@digium.com")) { ast_test_status_update(test, "Parse failure for serveremail option\n"); res = 1; @@ -12911,6 +12919,7 @@ static struct ast_cli_entry cli_voicemail[] = { USER(ast_vm_user, emailbody, AST_DATA_STRING) \ USER(ast_vm_user, pager, AST_DATA_STRING) \ USER(ast_vm_user, serveremail, AST_DATA_STRING) \ + USER(ast_vm_user, fromstring, AST_DATA_STRING) \ USER(ast_vm_user, language, AST_DATA_STRING) \ USER(ast_vm_user, zonetag, AST_DATA_STRING) \ USER(ast_vm_user, callback, AST_DATA_STRING) \ @@ -12938,6 +12947,7 @@ static struct ast_cli_entry cli_voicemail[] = { USER(ast_vm_user, emailbody, AST_DATA_STRING) \ USER(ast_vm_user, pager, AST_DATA_STRING) \ USER(ast_vm_user, serveremail, AST_DATA_STRING) \ + USER(ast_vm_user, fromstring, AST_DATA_STRING) \ USER(ast_vm_user, language, AST_DATA_STRING) \ USER(ast_vm_user, zonetag, AST_DATA_STRING) \ USER(ast_vm_user, callback, AST_DATA_STRING) \ @@ -13327,6 +13337,7 @@ static int manager_list_voicemail_users(struct mansession *s, const struct messa "Email: %s\r\n" "Pager: %s\r\n" "ServerEmail: %s\r\n" + "FromString: %s\r\n" "MailCommand: %s\r\n" "Language: %s\r\n" "TimeZone: %s\r\n" @@ -13361,6 +13372,7 @@ static int manager_list_voicemail_users(struct mansession *s, const struct messa vmu->email, vmu->pager, ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail, + ast_strlen_zero(vmu->fromstring) ? fromstring : vmu->fromstring, mailcmd, vmu->language, vmu->zonetag, diff --git a/configs/samples/voicemail.conf.sample b/configs/samples/voicemail.conf.sample index 1c91ffb34b9..f8221eebe05 100644 --- a/configs/samples/voicemail.conf.sample +++ b/configs/samples/voicemail.conf.sample @@ -439,7 +439,7 @@ european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM ; Note: The rest of the system must reference mailboxes defined here as mailbox@default. 1234 => 4242,Example Mailbox,root@localhost -;4200 => 9855,Mark Spencer,markster@linux-support.net,mypager@digium.com,attach=no|serveremail=myaddy@digium.com|tz=central|maxmsg=10 +;4200 => 9855,Mark Spencer,markster@linux-support.net,mypager@digium.com,attach=no|serveremail=myaddy@digium.com|fromstring=MySystem|tz=central|maxmsg=10 ;4300 => 3456,Ben Rigas,ben@american-computer.net ;4310 => -5432,Sales,sales@marko.net ;4069 => 6522,Matt Brooks,matt@marko.net,,|tz=central|attach=yes|saycid=yes|dialout=fromvm|callback=fromvm|review=yes|operator=yes|envelope=yes|moveheard=yes|sayduration=yes|saydurationm=1 From 4e3b0cedba16db80cd9910e64db0763258a0ed5f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 7 Mar 2017 13:37:52 +0000 Subject: [PATCH 1106/1578] res_pjsip_transport_websocket: Add support for IPv6. This change adds a PJSIP patch (which has been contributed upstream) to allow the registration of IPv6 transport types. Using this the res_pjsip_transport_websocket module now registers an IPv6 Websocket transport and uses it for the corresponding traffic. ASTERISK-26685 Change-Id: Id1f9126f995b31dc38db8fdb58afd289b4ad1647 --- res/res_pjsip.c | 22 +++---- res/res_pjsip_outbound_registration.c | 18 +++--- res/res_pjsip_transport_websocket.c | 30 +++++---- ...d-pjsip-transport-register-type-ipv6.patch | 62 +++++++++++++++++++ 4 files changed, 100 insertions(+), 32 deletions(-) create mode 100644 third-party/pjproject/patches/0014-Add-pjsip-transport-register-type-ipv6.patch diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 810b6d3297c..e1800e2deaf 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2757,7 +2757,7 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u pj_str_t tmp, local_addr; pjsip_uri *uri; pjsip_sip_uri *sip_uri; - pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED; + pjsip_transport_type_e type; int local_port; char default_user[PJSIP_MAX_URL_SIZE]; @@ -2777,21 +2777,21 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u sip_uri = pjsip_uri_get_uri(uri); /* Determine the transport type to use */ + type = pjsip_transport_get_type_from_name(&sip_uri->transport_param); if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) { - type = PJSIP_TRANSPORT_TLS; + if (type == PJSIP_TRANSPORT_UNSPECIFIED + || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) { + type = PJSIP_TRANSPORT_TLS; + } } else if (!sip_uri->transport_param.slen) { type = PJSIP_TRANSPORT_UDP; - } else { - type = pjsip_transport_get_type_from_name(&sip_uri->transport_param); - } - - if (type == PJSIP_TRANSPORT_UNSPECIFIED) { + } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) { return -1; } /* If the host is IPv6 turn the transport into an IPv6 version */ - if (pj_strchr(&sip_uri->host, ':') && type < PJSIP_TRANSPORT_START_OTHER) { - type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6); + if (pj_strchr(&sip_uri->host, ':')) { + type |= PJSIP_TRANSPORT_IPV6; } if (!ast_strlen_zero(domain)) { @@ -2815,8 +2815,8 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u } /* If IPv6 was specified in the transport, set the proper type */ - if (pj_strchr(&local_addr, ':') && type < PJSIP_TRANSPORT_START_OTHER) { - type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6); + if (pj_strchr(&local_addr, ':')) { + type |= PJSIP_TRANSPORT_IPV6; } from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 538967ea715..704239bd01a 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1086,7 +1086,7 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c pj_str_t tmp, local_addr; pjsip_uri *uri; pjsip_sip_uri *sip_uri; - pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED; + pjsip_transport_type_e type; int local_port; pj_strdup_with_null(pool, &tmp, target); @@ -1098,20 +1098,20 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c sip_uri = pjsip_uri_get_uri(uri); + type = pjsip_transport_get_type_from_name(&sip_uri->transport_param); if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) { - type = PJSIP_TRANSPORT_TLS; + if (type == PJSIP_TRANSPORT_UNSPECIFIED + || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) { + type = PJSIP_TRANSPORT_TLS; + } } else if (!sip_uri->transport_param.slen) { type = PJSIP_TRANSPORT_UDP; - } else { - type = pjsip_transport_get_type_from_name(&sip_uri->transport_param); - } - - if (type == PJSIP_TRANSPORT_UNSPECIFIED) { + } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) { return -1; } if (pj_strchr(&sip_uri->host, ':')) { - type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6); + type |= PJSIP_TRANSPORT_IPV6; } if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), @@ -1120,7 +1120,7 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c } if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) { - type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6); + type |= PJSIP_TRANSPORT_IPV6; } contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index a52b42dfc1d..b3e63fcc13f 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -39,6 +39,7 @@ #include "asterisk/taskprocessor.h" static int transport_type_wss; +static int transport_type_wss_ipv6; /*! * \brief Wrapper for pjsip_transport, for storing the WebSocket session @@ -198,15 +199,20 @@ static int transport_create(void *data) newtransport->transport.type_name, ws_addr_str); pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr); - newtransport->transport.key.rem_addr.addr.sa_family = pj_AF_INET(); - newtransport->transport.key.type = transport_type_wss; + if (newtransport->transport.key.rem_addr.addr.sa_family == pj_AF_INET6()) { + newtransport->transport.key.type = transport_type_wss_ipv6; + newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN); + pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET6_ADDRSTRLEN, 0); + } else { + newtransport->transport.key.type = transport_type_wss; + newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET_ADDRSTRLEN); + pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET_ADDRSTRLEN, 0); + } newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr); pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr); - newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, newtransport->transport.addr_len+4); - pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, newtransport->transport.addr_len+4, 0); newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr); newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr); @@ -271,8 +277,6 @@ static int transport_read(void *data) rdata->pkt_info.zero = 0; pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(session))), &rdata->pkt_info.src_addr); - rdata->pkt_info.src_addr.addr.sa_family = pj_AF_INET(); - rdata->pkt_info.src_addr_len = sizeof(rdata->pkt_info.src_addr); pj_ansi_strcpy(rdata->pkt_info.src_name, ast_sockaddr_stringify_host(ast_websocket_remote_address(session))); @@ -395,7 +399,7 @@ static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata) long type = rdata->tp_info.transport->key.type; - if (type != (long) transport_type_wss) { + if (type != (long) transport_type_wss && type != (long) transport_type_wss_ipv6) { return PJ_FALSE; } @@ -451,15 +455,17 @@ static int load_module(void) CHECK_PJSIP_MODULE_LOADED(); /* - * We only need one transport type defined. Firefox and Chrome - * do not support anything other than secure websockets anymore. + * We only need one transport type name (ws) defined. Firefox + * and Chrome do not support anything other than secure websockets + * anymore. * * Also we really cannot have two transports with the same name - * because it would be ambiguous. Outgoing requests may try to - * find the transport by name and pjproject only finds the first - * one registered. + * and address family because it would be ambiguous. Outgoing + * requests may try to find the transport by name and pjproject + * only finds the first one registered. */ pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "ws", 5060, &transport_type_wss); + pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_IPV6, "ws", 5060, &transport_type_wss_ipv6); if (ast_sip_register_service(&websocket_module) != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; diff --git a/third-party/pjproject/patches/0014-Add-pjsip-transport-register-type-ipv6.patch b/third-party/pjproject/patches/0014-Add-pjsip-transport-register-type-ipv6.patch new file mode 100644 index 00000000000..796473a3c72 --- /dev/null +++ b/third-party/pjproject/patches/0014-Add-pjsip-transport-register-type-ipv6.patch @@ -0,0 +1,62 @@ +From daeb0956524606b597704a90b54d81340e10b3e4 Mon Sep 17 00:00:00 2001 +From: Joshua Colp +Date: Tue, 7 Mar 2017 12:32:49 +0000 +Subject: [PATCH] Add support for registering IPv6 transport type. + +This change allows an IPv6 transport type to be registered +and used. The IPv4 transport is found (if available) and the +IPv4 flag added to its type to match how the finding of +IPv6 transport types works. +--- + pjsip/src/pjsip/sip_transport.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c +index 7df6138..ce72814 100644 +--- a/pjsip/src/pjsip/sip_transport.c ++++ b/pjsip/src/pjsip/sip_transport.c +@@ -236,6 +236,7 @@ PJ_DEF(pj_status_t) pjsip_transport_register_type( unsigned tp_flag, + int *p_tp_type) + { + unsigned i; ++ pjsip_transport_type_e parent = 0; + + PJ_ASSERT_RETURN(tp_flag && tp_name && def_port, PJ_EINVAL); + PJ_ASSERT_RETURN(pj_ansi_strlen(tp_name) < +@@ -243,6 +244,11 @@ PJ_DEF(pj_status_t) pjsip_transport_register_type( unsigned tp_flag, + PJ_ENAMETOOLONG); + + for (i=1; i Date: Tue, 7 Mar 2017 07:25:25 -0500 Subject: [PATCH 1107/1578] pbx_spool: Set AST_OUTGOING_ATTEMPT variable on channel Set a variable on the channel that indicates which attempt number we are currently performing to allow for attempt-specific behavior. ASTERISK-26568 #close Reported by: Roman Shubovich Change-Id: Iacd7e8d43b0ed5b6cb021c62f41f1a1f5733dd89 --- CHANGES | 6 ++++++ pbx/pbx_spool.c | 33 +++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 371e9e14249..2a4f6584ac7 100644 --- a/CHANGES +++ b/CHANGES @@ -79,6 +79,12 @@ app_queue * Add 'QueueUpdate' application which can be used to track outbound calls using app_queue. +pbx_spool +------------------ + * Asterisk will now set the AST_OUTGOING_ATTEMPT channel variable so that + attempt-specific behavior is possible. This is a 1-based number that + simply increases by 1 for each attempt. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.3.0 to Asterisk 14.4.0 ------------ ------------------------------------------------------------------------------ diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c index 0c6c401cebd..644347fcb86 100644 --- a/pbx/pbx_spool.c +++ b/pbx/pbx_spool.c @@ -161,6 +161,19 @@ static struct outgoing *new_outgoing(const char *fn) return o; } +static void append_variable(struct outgoing *o, const char *name, const char *value) +{ + struct ast_variable *var = ast_variable_new(name, value, o->fn); + + if (!var) { + return; + } + + /* Always insert at the end, because some people want to treat the spool + * file as a script */ + ast_variable_list_append(&o->vars, var); +} + static void parse_line(char *line, unsigned int lineno, struct outgoing *o) { char *c; @@ -261,20 +274,7 @@ static void parse_line(char *line, unsigned int lineno, struct outgoing *o) strsep(&c2, "="); if (c2) { - struct ast_variable *var = ast_variable_new(c, c2, o->fn); - - if (var) { - /* - * Always insert at the end, because some people - * want to treat the spool file as a script - */ - struct ast_variable **tail = &o->vars; - - while (*tail) { - tail = &(*tail)->next; - } - *tail = var; - } + append_variable(o, c, c2); } else { ast_log(LOG_WARNING, "Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", line, line); } @@ -328,6 +328,11 @@ static int apply_outgoing(struct outgoing *o, FILE *f) "along with tech and dest in file %s\n", o->fn); return -1; } + + if (snprintf(buf, sizeof(buf), "%d", o->retries + 1) < sizeof(buf)) { + append_variable(o, "AST_OUTGOING_ATTEMPT", buf); + } + return 0; } From 35cfd2c0ccadceaf43f93e8f44936a6b1d9de876 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 8 Mar 2017 18:08:52 -0500 Subject: [PATCH 1108/1578] media_cache: Prefer ast_file_is_readable() over access() Change-Id: Icc0dc6e61b2e68d5cdcb74b016b2726a388c7def --- main/media_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/media_cache.c b/main/media_cache.c index 2592f353a9b..c58acdd59a8 100644 --- a/main/media_cache.c +++ b/main/media_cache.c @@ -225,7 +225,7 @@ int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (bucket_file) { if (!ast_bucket_file_is_stale(bucket_file) - && !access(bucket_file->path, R_OK)) { + && ast_file_is_readable(bucket_file->path)) { ast_copy_string(file_path, bucket_file->path, len); if ((ext = strrchr(file_path, '.'))) { *ext = '\0'; From b14724adb3ec6a5b2e09061618f49d7b0a205335 Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Wed, 8 Mar 2017 20:29:16 +0000 Subject: [PATCH 1109/1578] res_musiconhold: moh general section is a class and issues warning * res_musiconhold.c: Ensure the general section is not treated as a moh class. ASTERISK-26353 #close Change-Id: Ia3dbd11ea2b43ab3e6c820a9827811dd24bea82d --- res/res_musiconhold.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 70bb0401829..5ee1ac30ba1 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1748,6 +1748,7 @@ static int load_moh_classes(int reload) ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name); } } + continue; } if (!(class = moh_class_malloc())) { From 36fed726146dcc32c5bc02b5f2ef69aec141f1e7 Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Sun, 5 Mar 2017 21:26:07 +0000 Subject: [PATCH 1110/1578] pjsip/cli_commands: pjsip show channelstats shows wrong codec * cli_commands.c Fixed CLI output ASTERISK-26822 #close Change-Id: I3889ef6a8f6738fc312fab42db5efacd6e452b01 --- channels/pjsip/cli_commands.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/channels/pjsip/cli_commands.c b/channels/pjsip/cli_commands.c index 8ea39d144a8..fc14b25a8d4 100644 --- a/channels/pjsip/cli_commands.c +++ b/channels/pjsip/cli_commands.c @@ -344,11 +344,10 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags) struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL; struct chan_pjsip_pvt *pvt = cpvt ? cpvt->pvt : NULL; struct ast_sip_session_media *media = pvt ? pvt->media[SIP_MEDIA_AUDIO] : NULL; - struct ast_rtp_codecs *codecs = media && media->rtp ? ast_rtp_instance_get_codecs(media->rtp) : NULL; - struct ast_format *format = codecs ? ast_rtp_codecs_get_payload_format(codecs, 0) : NULL; struct ast_rtp_instance_stats stats; char *print_name = NULL; char *print_time = alloca(32); + char codec_in_use[7]; ast_assert(context->output_buffer != NULL); @@ -358,6 +357,16 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags) return -1; } + codec_in_use[0] = '\0'; + + if (channel) { + ast_channel_lock(channel); + if (ast_channel_rawreadformat(channel)) { + ast_copy_string(codec_in_use, ast_format_get_name(ast_channel_rawreadformat(channel)), sizeof(codec_in_use)); + } + ast_channel_unlock(channel); + } + print_name = ast_strdupa(snapshot->name); /* Skip the PJSIP/. We know what channel type it is and we need the space. */ print_name += 6; @@ -372,7 +381,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags) snapshot->bridgeid, print_name, print_time, - format ? ast_format_get_name(format) : "", + codec_in_use, stats.rxcount > 100000 ? stats.rxcount / 1000 : stats.rxcount, stats.rxcount > 100000 ? "K": " ", stats.rxploss > 100000 ? stats.rxploss / 1000 : stats.rxploss, @@ -389,7 +398,6 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags) ); } - ao2_cleanup(format); ao2_cleanup(channel); return 0; From d1ef127084786e171f38b5b875ee984c5a5eb544 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 10 Mar 2017 19:29:04 -0700 Subject: [PATCH 1111/1578] pjproject_bundled: Reduce the need for rebuilds Bundled pjproject should now only rebuild if one of the menuselect "Compiler Flags" options changes. Change-Id: If114a2e16b9e77af371a600d6a5e197bbf28fe43 --- third-party/pjproject/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index bfd1c27fc52..99c22fa8be6 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -135,7 +135,7 @@ source/pjlib/include/pj/%.h: patches/%.h $(ECHO_PREFIX) Applying custom include file $< $(CMD_PREFIX) cp -f $< source/pjlib/include/pj/ -.rebuild_needed: $(wildcard ../../makeopts) $(wildcard ../../menuselect.makeopts) +.rebuild_needed: $(wildcard ../../.lastclean) $(ECHO_PREFIX) Rebuilding $(CMD_PREFIX) $(MAKE) clean $(REALLY_QUIET) From 12460b05c1abd37e412e155e47a6e349a2df3338 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 12 Mar 2017 14:21:16 +0000 Subject: [PATCH 1112/1578] chan_pjsip: Don't assume a session will have a channel. When querying for PJSIP specific information using the dialplan function CHANNEL() it is possible that the underlying session will no longer have a channel associated with it. This is most likely to occur when the RTCP HEP module attempts to get the channel name. If this happens then a crash will occur. This change just adds a check that the channel exists on the session before querying it. ASTERISK-26857 Change-Id: I113479cffff6ae64cf8ed089e9e1565223426f01 --- channels/pjsip/dialplan_functions.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 17c19b7c0c6..332df70b4af 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -735,17 +735,27 @@ static int read_pjsip(void *data) struct pjsip_func_args *func_args = data; if (!strcmp(func_args->param, "rtp")) { + if (!func_args->session->channel) { + func_args->ret = -1; + return 0; + } func_args->ret = channel_read_rtp(func_args->session->channel, func_args->type, func_args->field, func_args->buf, func_args->len); } else if (!strcmp(func_args->param, "rtcp")) { + if (!func_args->session->channel) { + func_args->ret = -1; + return 0; + } func_args->ret = channel_read_rtcp(func_args->session->channel, func_args->type, func_args->field, func_args->buf, func_args->len); } else if (!strcmp(func_args->param, "endpoint")) { if (!func_args->session->endpoint) { - ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->session->channel)); - return -1; + ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", func_args->session->channel ? + ast_channel_name(func_args->session->channel) : ""); + func_args->ret = -1; + return 0; } snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->endpoint)); } else if (!strcmp(func_args->param, "contact")) { @@ -759,6 +769,10 @@ static int read_pjsip(void *data) } snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->aor)); } else if (!strcmp(func_args->param, "pjsip")) { + if (!func_args->session->channel) { + func_args->ret = -1; + return 0; + } func_args->ret = channel_read_pjsip(func_args->session->channel, func_args->type, func_args->field, func_args->buf, func_args->len); From 2d7e68c07559a34d114af8edc2248a70a6a46f9a Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Wed, 8 Mar 2017 12:39:20 -0600 Subject: [PATCH 1113/1578] res_pjsip_endpoint_identifier_ip: Clean up a spaces/tabs issue Tabs > spaces. Always. Change-Id: I899ff662361c7ab0327173bd7851a67b53dd65f1 --- res/res_pjsip_endpoint_identifier_ip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 86a5afbdbf0..a7323840172 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -57,7 +57,7 @@ perform SRV lookups for _sip._udp, _sip._tcp, and _sips._tcp of the given hostnames to determine additional addresses that traffic may originate from. - + Must be of type 'identify'. From b03b72717f6d312f6ed106c1eff16581992ba5ef Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 14 Mar 2017 09:37:34 -0500 Subject: [PATCH 1114/1578] main/stasis_cache: Demote the ERROR message when removing a nonexistent item This patch demotes the ERROR message that is displayed when a nonexistent item is removed from the Stasis cache. The genesis of this demotion is due to chan_sip's realtime peers and their interaction with Asterisk's core ast_endpoint code, but ostensibly it could happen from other channel drivers as well. Since Mark Michelson already did an excellent job of explaining on this issue, it is quoted here for posterity: "Internally, when a realtime peer is retrieved, Asterisk creates an ast_endpoint structure. When that peer is destroyed, the ast_endpoint is destroyed as well. Part of the destruction of the ast_endpoint involves clearing the Stasis cache of all information about that endpoint. The problem here is that the act of creating the ast_endpoint is not enough to actually put any information in the Stasis cache. Instead, something has to happen, such as a state change, in order for the Stasis cache to have any information about that endpoint. When a device registers, chan_sip creates an ast_endpoint structure, processes the REGISTER, and then destroys the ast_endpoint. When the ast_endpoint is destroyed, there is nothing to destroy in the Stasis cache, so an error message is emitted. When you use rtcachefriends, ast_endpoint structures persist for the lifetime of the module and so you do not see this error message." ASTERISK-25237 #close Change-Id: I53cebc6b4a897a1ab9564182b75c177780feff70 --- main/stasis_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/stasis_cache.c b/main/stasis_cache.c index e632a21b06d..ce4e0232fab 100644 --- a/main/stasis_cache.c +++ b/main/stasis_cache.c @@ -840,7 +840,7 @@ static void caching_topic_exec(void *data, struct stasis_subscription *sub, } ao2_cleanup(update); } else { - ast_log(LOG_ERROR, + ast_debug(1, "Attempting to remove an item from the %s cache that isn't there: %s %s\n", stasis_topic_name(caching_topic->topic), stasis_message_type_name(msg_type), msg_id); From 0ded269bfa19714da3de4b67858b0b463ecf2430 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 14 Mar 2017 09:59:48 -0500 Subject: [PATCH 1115/1578] funcs/func_devstate: Remove new line in Device field of during module load During module loading of func_devstate, Asterisk emits the current device state of all Custom device states currently stored in the AstDB. This was erroneously including a new line character ('\n') to the end of the device state, causing two new lines to be emitted in DeviceStateChange AMI events. Note that this only happened for those device state changes that occurred during startup. Regular device state changes for Custom device states are handled elsewhere, and did not have the newline. ASTERISK-26643 #close Reported by: Roman Bedros Tested by: Matt Jordan patches: ami_devstate.diff uploaded by Roman Bedros (License 6842) Change-Id: I1f4c02fc79c448d43bf725f5039c83d9611d7d93 --- funcs/func_devstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funcs/func_devstate.c b/funcs/func_devstate.c index 965c7c79430..5789e2b0bdd 100644 --- a/funcs/func_devstate.c +++ b/funcs/func_devstate.c @@ -339,7 +339,7 @@ static int load_module(void) if (dev_name <= (const char *) 1) continue; ast_devstate_changed(ast_devstate_val(db_entry->data), - AST_DEVSTATE_CACHABLE, "Custom:%s\n", dev_name); + AST_DEVSTATE_CACHABLE, "Custom:%s", dev_name); } ast_db_freetree(db_tree); db_tree = NULL; From 05713c36eac3f32f2a9a268c7ac87d19ca6896ca Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 14 Mar 2017 09:55:06 -0500 Subject: [PATCH 1116/1578] configs/samples/hep.conf.sample: Clarify how the HEP stack works This patch updates the documenation in hep.conf.sample to better specify how the various HEP modules interact. ASTERISK-26717 #close Change-Id: I337fb742a89e3ec5edc7fc7a7a0295218d841124 --- configs/samples/hep.conf.sample | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configs/samples/hep.conf.sample b/configs/samples/hep.conf.sample index e1cd52ebb0a..3d1e7413994 100644 --- a/configs/samples/hep.conf.sample +++ b/configs/samples/hep.conf.sample @@ -2,6 +2,15 @@ ; res_hep Module configuration for Asterisk ; +; +; Note that this configuration file is consumed by res_hep, which is responsible +; for the HEPv3 protocol manipulation and managing the connection to the Homer +; capture server. Additional modules provide specific messages to be sent to +; the Homer server: +; - res_hep_pjsip: Send SIP messages transmitted/received by the PJSIP stack +; - res_hep_rtcp: Send RTCP information (all channels) +; + ; All settings are currently set in the general section. [general] enabled = no ; Enable/disable forwarding of packets to a @@ -17,4 +26,3 @@ uuid_type = call-id ; Specify the preferred source for the Homer ; correlation UUID. Valid options are: ; - 'call-id' for the PJSIP SIP Call-ID ; - 'channel' for the Asterisk channel name - From 8470c2bdea89f1ed89d8a773d775de96ededf3fb Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 2 Mar 2017 16:11:06 -0700 Subject: [PATCH 1117/1578] RFC sdp: Initial SDP creation * Added additional fields to ast_sdp_options. * Re-organized ast_sdp. * Updated field names to correspond to RFC4566 terminology. * Created allocs/frees for SDP children. * Created getters/setters for SDP children where appropriate. * Added ast_sdp_create_from_state. * Refactored res_sdp_translator_pjmedia for changes. Change-Id: Iefbd877af7f5a4d3c74deead1bff8802661b0d48 --- include/asterisk/rtp_engine.h | 6 +- include/asterisk/sdp.h | 559 ++++++++++++++++++++++ include/asterisk/sdp_options.h | 390 ++++++++++++--- include/asterisk/sdp_priv.h | 130 ----- include/asterisk/sdp_state.h | 101 +++- include/asterisk/sdp_translator.h | 9 +- include/asterisk/stream.h | 47 ++ main/rtp_engine.c | 6 +- main/sdp.c | 765 ++++++++++++++++++++++++++++++ main/sdp_options.c | 124 +++-- main/sdp_private.h | 55 +++ main/sdp_repr.c | 111 ----- main/sdp_state.c | 109 ++--- main/sdp_translator.c | 14 +- main/stream.c | 36 ++ res/res_sdp_translator_pjmedia.c | 279 ++++++----- 16 files changed, 2136 insertions(+), 605 deletions(-) create mode 100644 include/asterisk/sdp.h delete mode 100644 include/asterisk/sdp_priv.h create mode 100644 main/sdp.c create mode 100644 main/sdp_private.h delete mode 100644 main/sdp_repr.c diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index c0ae3315572..c18e100b656 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -1432,7 +1432,8 @@ unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs); * * \since 1.8 */ -unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format *format, int code); +unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, + const struct ast_format *format, int code); /*! * \brief Retrieve all formats that were found @@ -1537,7 +1538,8 @@ int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload) * * \since 1.8 */ -const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_format *format, int code, enum ast_rtp_options options); +const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, + const struct ast_format *format, int code, enum ast_rtp_options options); /*! * \brief Convert formats into a string and put them into a buffer diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h new file mode 100644 index 00000000000..4d6d2fbb5d5 --- /dev/null +++ b/include/asterisk/sdp.h @@ -0,0 +1,559 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/* NOTE: It is unlikely that you need to include this file. You probably will only need + * this if you are an SDP translator, or if you are an inner part of the SDP API + */ + +#ifndef _SDP_PRIV_H +#define _SDP_PRIV_H + +#include "asterisk/vector.h" +#include "asterisk/format.h" +#include "asterisk/sdp_state.h" +#include "asterisk/stream.h" + +/*! + * \brief Structure representing an SDP Attribute + */ +struct ast_sdp_a_line { + /*! Attribute name */ + char *name; + /*! Attribute value. For attributes that have no value, this will be an empty string */ + char *value; +}; + +/*! + * \brief A collection of SDP Attributes + */ +AST_VECTOR(ast_sdp_a_lines, struct ast_sdp_a_line *); + +/*! + * \brief Structure representing an SDP Connection + */ +struct ast_sdp_c_line { + /* IP family string (e.g. IP4 or IP6) */ + char *address_type; + /* Connection address. Can be an IP address or FQDN */ + char *address; +}; + +/*! + * \brief Structre representing SDP Media Payloads + */ +struct ast_sdp_payload { + /* Media format description */ + char *fmt; +}; + +/*! + * \brief A collection of SDP Media Payloads + */ +AST_VECTOR(ast_sdp_payloads, struct ast_sdp_payload *); + +/*! + * \brief Structure representing an SDP Media Stream + * + * This contains both the m line, as well as its + * constituent a lines. + */ +struct ast_sdp_m_line { + /*! Media type (e.g. "audio" or "video") */ + char *type; + /*! RTP profile string (e.g. "RTP/AVP") */ + char *proto; + /*! Port number in m line */ + uint16_t port; + /*! Number of ports specified in m line */ + uint16_t port_count; + /*! RTP payloads */ + struct ast_sdp_payloads *payloads; + /*! Connection information for this media stream */ + struct ast_sdp_c_line *c_line; + /*! The attributes for this media stream */ + struct ast_sdp_a_lines *a_lines; +}; + +/*! + * \brief A collection of SDP Media Streams + */ +AST_VECTOR(ast_sdp_m_lines, struct ast_sdp_m_line *); + +/*! + * \brief Structure representing an SDP Origin + */ +struct ast_sdp_o_line { + /*! Origin user name */ + char *username; + /*! Origin id */ + uint64_t session_id; + /*! Origin version */ + uint64_t session_version; + /*! Origin IP address type (e.g. "IP4" or "IP6") */ + char *address_type; + /*! Origin address. Can be an IP address or FQDN */ + char *address; +}; + +/*! + * \brief Structure representing an SDP Session Name + */ +struct ast_sdp_s_line { + /* Session Name */ + char *session_name; +}; + +/*! + * \brief Structure representing SDP Timing + */ +struct ast_sdp_t_line { + /*! Session start time */ + uint64_t start_time; + /*! Session end time */ + uint64_t stop_time; +}; + +/*! + * \brief An SDP + */ +struct ast_sdp { + /*! SDP Origin line */ + struct ast_sdp_o_line *o_line; + /*! SDP Session name */ + struct ast_sdp_s_line *s_line; + /*! SDP top-level connection information */ + struct ast_sdp_c_line *c_line; + /*! SDP timing information */ + struct ast_sdp_t_line *t_line; + /*! SDP top-level attributes */ + struct ast_sdp_a_lines *a_lines; + /*! SDP media streams */ + struct ast_sdp_m_lines *m_lines; +}; + +/*! + * \brief Free an SDP Attribute + * + * \param a_line The attribute to free + * + * \since 15 + */ +void ast_sdp_a_free(struct ast_sdp_a_line *a_line); + +/*! + * \brief Free an SDP Attribute collection + * + * \param a_lines The attribute collection to free + * + * \since 15 + */ +void ast_sdp_a_lines_free(struct ast_sdp_a_lines *a_lines); + +/*! + * \brief Free SDP Connection Data + * + * \param c_line The connection data to free + * + * \since 15 + */ +void ast_sdp_c_free(struct ast_sdp_c_line *c_line); + +/*! + * \brief Free an SDP Media Description Payload + * + * \param payload The payload to free + * + * \since 15 + */ +void ast_sdp_payload_free(struct ast_sdp_payload *payload); + +/*! + * \brief Free an SDP Media Description Payload collection + * + * \param payloads collection to free + * + * \since 15 + */ +void ast_sdp_payloads_free(struct ast_sdp_payloads *payloads); + +/*! + * \brief Free an SDP Media Description + * Frees the media description and all resources it contains + * + * \param m_line The media description to free + * + * \since 15 + */ +void ast_sdp_m_free(struct ast_sdp_m_line *m_line); + +/*! + * \brief Free an SDP Media Description collection + * + * \param m_lines The collection description to free + * + * \since 15 + */ +void ast_sdp_m_lines_free(struct ast_sdp_m_lines *m_lines); + +/*! + * \brief Free an SDP Origin + * + * \param o_line The origin description to free + * + * \since 15 + */ +void ast_sdp_o_free(struct ast_sdp_o_line *o_line); + +/*! + * \brief Free an SDP Session + * + * \param s_line The session to free + * + * \since 15 + */ +void ast_sdp_s_free(struct ast_sdp_s_line *s_line); + +/*! + * \brief Free SDP Timing + * + * \param t_line The timing description to free + * + * \since 15 + */ +void ast_sdp_t_free(struct ast_sdp_t_line *t_line); + +/*! + * \brief Free an SDP + * Frees the sdp and all resources it contains + * + * \param sdp The sdp to free + * + * \since 15 + */ +void ast_sdp_free(struct ast_sdp *sdp); + +/*! + * \brief Allocate an SDP Attribute + * + * \param name Attribute Name + * \param value Attribute Name + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_a_line *ast_sdp_a_alloc(const char *name, const char *value); + +/*! + * \brief Allocate an SDP Connection + * + * \param family Family ("IN", etc) + * \param addr Address + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_c_line *ast_sdp_c_alloc(const char *family, const char *addr); + +/*! + * \brief Allocate an SDP Media Description Payload + * + * \param fmt The media format description + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_payload *ast_sdp_payload_alloc(const char *fmt); + +/*! + * \brief Allocate an SDP Media Description + * + * \param type ("audio", "video", etc) + * \param port Starting port + * \param port_count Port pairs to allocate + * \param proto ("RTP/AVP", "RTP/SAVP", "udp") + * \param c_line Connection to add. May be NULL + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_m_line *ast_sdp_m_alloc(const char *type, uint16_t port, + uint16_t port_count, const char *proto, struct ast_sdp_c_line *c_line); + +/*! + * \brief Allocate an SDP Session + * + * \param session_name The session name + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_s_line *ast_sdp_s_alloc(const char *session_name); + +/*! + * \brief Allocate SDP Timing + * + * \param start_time (Seconds since 1900) + * \param end_time (Seconds since 1900) + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_t_line *ast_sdp_t_alloc(uint64_t start_time, uint64_t stop_time); + +/*! + * \brief Allocate an SDP Origin + * + * \param username User name + * \param sesison_id Session ID + * \param sesison_version Session Version + * \param address_type Address type ("IN4", "IN6", etc) + * \param address Unicast address + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_o_line *ast_sdp_o_alloc(const char *username, uint64_t session_id, + uint64_t session_version, const char *address_type, const char *address); + +/*! + * \brief Add an SDP Attribute to an SDP + * + * \param sdp SDP + * \param a_line Attribute + * + * \retval 0 Success + * \retval non-0 Failure + * + * \since 15 + */ +int ast_sdp_add_a(struct ast_sdp *sdp, struct ast_sdp_a_line *a_line); + +/*! + * \brief Get the count of Attributes on an SDP + * + * \param sdp SDP + * + * \returns Number of Attributes + * + * \since 15 + */ +int ast_sdp_get_a_count(const struct ast_sdp *sdp); + +/*! + * \brief Get an Attribute from an SDP + * + * \param sdp SDP + * \param index Attribute index + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_a_line *ast_sdp_get_a(const struct ast_sdp *sdp, int index); + +/*! + * \brief Add a Media Description to an SDP + * + * \param sdp SDP + * \param m_line Media Description + * + * \retval 0 Success + * \retval non-0 Failure + * + * \since 15 + */ +int ast_sdp_add_m(struct ast_sdp *sdp, struct ast_sdp_m_line *m_line); + +/*! + * \brief Add a Media Description to an SDP + * + * \param sdp SDP + * \param options SDP Options + * \param rtp ast_rtp_instance + * \param stream stream + * + * \retval 0 Success + * \retval non-0 Failure + * + * \since 15 + */ +int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options *options, + struct ast_rtp_instance *rtp, const struct ast_stream *stream); + +/*! + * \brief Get the count of Media Descriptions on an SDP + * + * \param sdp SDP + * + * \returns The number of Media Descriptions + * + * \since 15 + */ +int ast_sdp_get_m_count(const struct ast_sdp *sdp); + +/*! + * \brief Get a Media Descriptions from an SDP + * + * \param sdp SDP + * \param index Media Description index + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_m_line *ast_sdp_get_m(const struct ast_sdp *sdp, int index); + +/*! + * \brief Add an SDP Attribute to a Media Description + * + * \param m_line Media Description + * \param a_line Attribute + * + * \retval 0 Success + * \retval non-0 Failure + * + * \since 15 + */ +int ast_sdp_m_add_a(struct ast_sdp_m_line *m_line, struct ast_sdp_a_line *a_line); + +/*! + * \brief Get the count of Attributes on a Media Description + * + * \param m_line Media Description + * + * \returns Number of Attributes + * + * \since 15 + */ +int ast_sdp_m_get_a_count(const struct ast_sdp_m_line *m_line); + +/*! + * \brief Get an Attribute from a Media Description + * + * \param m_line Media Description + * \param index Attribute index + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_a_line *ast_sdp_m_get_a(const struct ast_sdp_m_line *m_line, int index); + +/*! + * \brief Add a Payload to a Media Description + * + * \param m_line Media Description + * \param payload Payload + * + * \retval 0 Success + * \retval non-0 Failure + * + * \since 15 + */ +int ast_sdp_m_add_payload(struct ast_sdp_m_line *m_line, + struct ast_sdp_payload *payload); + +/*! + * \brief Get the count of Payloads on a Media Description + * + * \param m_line Media Description + * + * \returns Number of Attributes + * + * \since 15 + */ +int ast_sdp_m_get_payload_count(const struct ast_sdp_m_line *m_line); + +/*! + * \brief Get a Payload from a Media Description + * + * \param m_line Media Description + * \param index Payload index + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp_payload *ast_sdp_m_get_payload(const struct ast_sdp_m_line *m_line, int index); + +/*! + * \brief Add a Format to a Media Description + * + * \param m_line Media Description + * \param options SDP Options + * \param rtp_code rtp_code from ast_rtp_codecs_payload_code + * \param asterisk_format True if the value in format is to be used. + * \param format Format + * \param code from AST_RTP list + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_options *options, + int rtp_code, int asterisk_format, const struct ast_format *format, int code); + +/*! + * \brief Create an SDP + * + * \param o_line Origin + * \param c_line Connection + * \param s_line Session + * \param t_line Timing + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line, + struct ast_sdp_c_line *c_line, struct ast_sdp_s_line *s_line, + struct ast_sdp_t_line *t_line); + +/*! + * \brief Create an SDP from an existing SDP State local topology + * + * \param sdp_state SDP State + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \since 15 + */ +struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state); + +#endif /* _SDP_PRIV_H */ diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index a5c2d084e0a..3995faf4a9e 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -21,6 +21,48 @@ struct ast_sdp_options; +/*! + * \brief ICE options + * + * This is an enum because it will support a TRICKLE-ICE option + * in the future. + */ +enum ast_sdp_options_ice { + /*! ICE is not enabled on this session */ + AST_SDP_ICE_DISABLED, + /*! Standard ICE is enabled on this session */ + AST_SDP_ICE_ENABLED_STANDARD, +}; + +/*! + * \brief Implementation of the SDP + * + * Users of the SDP API set the implementation based on what they + * natively handle. This indicates the type of SDP that the API expects + * when being given an SDP, and it indicates the type of SDP that the API + * returns when asked for one. + */ +enum ast_sdp_options_impl { + /*! SDP is represented as a string */ + AST_SDP_IMPL_STRING, + /*! SDP is represented as a pjmedia_sdp_session */ + AST_SDP_IMPL_PJMEDIA, + /*! End of the list */ + AST_SDP_IMPL_END, +}; + +/*! + * \brief SDP encryption options + */ +enum ast_sdp_options_encryption { + /*! No encryption */ + AST_SDP_ENCRYPTION_DISABLED, + /*! SRTP SDES encryption */ + AST_SDP_ENCRYPTION_SRTP_SDES, + /*! DTLS encryption */ + AST_SDP_ENCRYPTION_DTLS, +}; + /*! * \since 15.0.0 * \brief Allocate a new SDP options structure. @@ -47,111 +89,343 @@ struct ast_sdp_options *ast_sdp_options_alloc(void); void ast_sdp_options_free(struct ast_sdp_options *options); /*! - * \brief ICE options + * \since 15.0.0 + * \brief Set SDP Options media_address * - * This is an enum because it is predicted that this eventually - * support a TRICKLE-ICE option. + * \param options SDP Options + * \param media_address */ -enum ast_sdp_options_ice { - /*! ICE is not enabled on this session */ - AST_SDP_ICE_DISABLED, - /*! Standard ICE is enabled on this session */ - AST_SDP_ICE_ENABLED_STANDARD, -}; +void ast_sdp_options_set_media_address(struct ast_sdp_options *options, + const char *media_address); /*! * \since 15.0.0 - * \brief Set ICE options + * \brief Get SDP Options media_address + * + * \param options SDP Options * - * The default is AST_SDP_ICE_DISABLED + * \returns media_address */ -int ast_sdp_options_set_ice(struct ast_sdp_options *options, - enum ast_sdp_options_ice ice_setting); +const char *ast_sdp_options_get_media_address(struct ast_sdp_options *options); /*! * \since 15.0.0 - * \brief Retrieve ICE options + * \brief Set SDP Options sdpowner + * + * \param options SDP Options + * \param sdpowner */ -enum ast_sdp_options_ice ast_sdp_options_get_ice(const struct ast_sdp_options *options); +void ast_sdp_options_set_sdpowner(struct ast_sdp_options *options, + const char *sdpowner); /*! * \since 15.0.0 - * \brief Enable or disable telephone events. + * \brief Get SDP Options sdpowner * - * A non-zero value indicates telephone events are enabled. - * A zero value indicates telephone events are disabled. + * \param options SDP Options * - * The default is 0 + * \returns sdpowner */ -int ast_sdp_options_set_telephone_event(struct ast_sdp_options *options, - int telephone_event_enabled); +const char *ast_sdp_options_get_sdpowner(struct ast_sdp_options *options); /*! * \since 15.0.0 - * \brief Retrieve telephone event setting. + * \brief Set SDP Options sdpsession * - * \retval 0 Telephone events are currently disabled. - * \retval non-zero Telephone events are currently enabled. + * \param options SDP Options + * \param sdpsession */ -int ast_sdp_options_get_telephone_event(const struct ast_sdp_options *options); +void ast_sdp_options_set_sdpsession(struct ast_sdp_options *options, + const char *sdpsession); /*! - * \brief Representation of the SDP + * \since 15.0.0 + * \brief Get SDP Options sdpsession * - * Users of the SDP API set the representation based on what they - * natively handle. This indicates the type of SDP that the API expects - * when being given an SDP, and it indicates the type of SDP that the API - * returns when asked for one. + * \param options SDP Options + * + * \returns sdpsession */ -enum ast_sdp_options_repr { - /*! SDP is represented as a string */ - AST_SDP_REPR_STRING, - /*! SDP is represented as a pjmedia_sdp_session */ - AST_SDP_REPR_PJMEDIA, - /*! End of the list */ - AST_SDP_REPR_END, -}; +const char *ast_sdp_options_get_sdpsession(struct ast_sdp_options *options); /*! * \since 15.0.0 - * \brief Set the SDP representation + * \brief Set SDP Options rtp_engine * - * The default is AST_SDP_REPR_STRING + * \param options SDP Options + * \param rtp_engine */ -int ast_sdp_options_set_repr(struct ast_sdp_options *options, - enum ast_sdp_options_repr repr); +void ast_sdp_options_set_rtp_engine(struct ast_sdp_options *options, + const char *rtp_engine); /*! * \since 15.0.0 - * \brief Get the SDP representation + * \brief Get SDP Options rtp_engine + * + * \param options SDP Options + * + * \returns rtp_engine */ -enum ast_sdp_options_repr ast_sdp_options_get_repr(const struct ast_sdp_options *options); +const char *ast_sdp_options_get_rtp_engine(struct ast_sdp_options *options); /*! - * \brief SDP encryption options + * \since 15.0.0 + * \brief Set SDP Options bind_rtp_to_media_address + * + * \param options SDP Options + * \param bind_rtp_to_media_address */ -enum ast_sdp_options_encryption { - /*! No encryption */ - AST_SDP_ENCRYPTION_DISABLED, - /*! SRTP SDES encryption */ - AST_SDP_ENCRYPTION_SRTP_SDES, - /*! DTLS encryption */ - AST_SDP_ENCRYPTION_DTLS, -}; +void ast_sdp_options_set_bind_rtp_to_media_address(struct ast_sdp_options *options, + unsigned int bind_rtp_to_media_address); + +/*! + * \since 15.0.0 + * \brief Get SDP Options bind_rtp_to_media_address + * + * \param options SDP Options + * + * \returns bind_rtp_to_media_address + */ +unsigned int ast_sdp_options_get_bind_rtp_to_media_address(struct ast_sdp_options *options); /*! * \since 15.0.0 - * \brief Set the SDP encryption + * \brief Set SDP Options rtp_symmetric * - * The default is AST_SDP_ENCRYPTION_DISABLED + * \param options SDP Options + * \param rtp_symmetric */ -int ast_sdp_options_set_encryption(struct ast_sdp_options *options, +void ast_sdp_options_set_rtp_symmetric(struct ast_sdp_options *options, + unsigned int rtp_symmetric); + +/*! + * \since 15.0.0 + * \brief Get SDP Options rtp_symmetric + * + * \param options SDP Options + * + * \returns rtp_symmetric + */ +unsigned int ast_sdp_options_get_rtp_symmetric(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options telephone_event + * + * \param options SDP Options + * \param telephone_event + */ +void ast_sdp_options_set_telephone_event(struct ast_sdp_options *options, + unsigned int telephone_event); + +/*! + * \since 15.0.0 + * \brief Get SDP Options telephone_event + * + * \param options SDP Options + * + * \returns telephone_event + */ +unsigned int ast_sdp_options_get_telephone_event(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options rtp_ipv6 + * + * \param options SDP Options + * \param rtp_ipv6 + */ +void ast_sdp_options_set_rtp_ipv6(struct ast_sdp_options *options, + unsigned int rtp_ipv6); + +/*! + * \since 15.0.0 + * \brief Get SDP Options rtp_ipv6 + * + * \param options SDP Options + * + * \returns rtp_ipv6 + */ +unsigned int ast_sdp_options_get_rtp_ipv6(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options g726_non_standard + * + * \param options SDP Options + * \param g726_non_standard + */ +void ast_sdp_options_set_g726_non_standard(struct ast_sdp_options *options, + unsigned int g726_non_standard); + +/*! + * \since 15.0.0 + * \brief Get SDP Options g726_non_standard + * + * \param options SDP Options + * + * \returns g726_non_standard + */ +unsigned int ast_sdp_options_get_g726_non_standard(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options locally_held + * + * \param options SDP Options + * \param locally_held + */ +void ast_sdp_options_set_locally_held(struct ast_sdp_options *options, + unsigned int locally_held); + +/*! + * \since 15.0.0 + * \brief Get SDP Options locally_held + * + * \param options SDP Options + * + * \returns locally_held + */ +unsigned int ast_sdp_options_get_locally_held(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options tos_audio + * + * \param options SDP Options + * \param tos_audio + */ +void ast_sdp_options_set_tos_audio(struct ast_sdp_options *options, + unsigned int tos_audio); + +/*! + * \since 15.0.0 + * \brief Get SDP Options tos_audio + * + * \param options SDP Options + * + * \returns tos_audio + */ +unsigned int ast_sdp_options_get_tos_audio(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options cos_audio + * + * \param options SDP Options + * \param cos_audio + */ +void ast_sdp_options_set_cos_audio(struct ast_sdp_options *options, + unsigned int cos_audio); + +/*! + * \since 15.0.0 + * \brief Get SDP Options cos_audio + * + * \param options SDP Options + * + * \returns cos_audio + */ +unsigned int ast_sdp_options_get_cos_audio(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options tos_video + * + * \param options SDP Options + * \param tos_video + */ +void ast_sdp_options_set_tos_video(struct ast_sdp_options *options, + unsigned int tos_video); + +/*! + * \since 15.0.0 + * \brief Get SDP Options tos_video + * + * \param options SDP Options + * + * \returns tos_video + */ +unsigned int ast_sdp_options_get_tos_video(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options cos_video + * + * \param options SDP Options + * \param cos_video + */ +void ast_sdp_options_set_cos_video(struct ast_sdp_options *options, + unsigned int cos_video); + +/*! + * \since 15.0.0 + * \brief Get SDP Options cos_video + * + * \param options SDP Options + * + * \returns cos_video + */ +unsigned int ast_sdp_options_get_cos_video(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options ice + * + * \param options SDP Options + * \param ice + */ +void ast_sdp_options_set_ice(struct ast_sdp_options *options, + enum ast_sdp_options_ice ice); + +/*! + * \since 15.0.0 + * \brief Get SDP Options ice + * + * \param options SDP Options + * + * \returns ice + */ +enum ast_sdp_options_ice ast_sdp_options_get_ice(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options impl + * + * \param options SDP Options + * \param impl + */ +void ast_sdp_options_set_impl(struct ast_sdp_options *options, + enum ast_sdp_options_impl impl); + +/*! + * \since 15.0.0 + * \brief Get SDP Options impl + * + * \param options SDP Options + * + * \returns impl + */ +enum ast_sdp_options_impl ast_sdp_options_get_impl(struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options encryption + * + * \param options SDP Options + * \param encryption + */ +void ast_sdp_options_set_encryption(struct ast_sdp_options *options, enum ast_sdp_options_encryption encryption); /*! * \since 15.0.0 - * \brief Get the SDP encryption + * \brief Get SDP Options encryption + * + * \param options SDP Options + * + * \returns encryption */ -enum ast_sdp_options_encryption ast_sdp_options_get_encryption(const struct ast_sdp_options *options); +enum ast_sdp_options_encryption ast_sdp_options_get_encryption(struct ast_sdp_options *options); #endif /* _ASTERISK_SDP_OPTIONS_H */ diff --git a/include/asterisk/sdp_priv.h b/include/asterisk/sdp_priv.h deleted file mode 100644 index 000d1114388..00000000000 --- a/include/asterisk/sdp_priv.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2017, Digium, Inc. - * - * Mark Michelson - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/* NOTE: It is unlikely that you need to include this file. You probably will only need - * this if you are an SDP translator, or if you are an inner part of the SDP API - */ - -#ifndef _SDP_PRIV_H -#define _SDP_PRIV_H - -#include "asterisk/vector.h" - -/*! - * \brief Structure representing an SDP attribute - */ -struct ast_sdp_a_line { - /*! Attribute name */ - char *name; - /*! Attribute value. For attributes that have no value, this will be an empty string */ - char *value; -}; - -/*! - * \brief Structure representing an SDP connection - */ -struct ast_sdp_c_line { - /* IP family string (e.g. IP4 or IP6) */ - char *family; - /* Connection address. Can be an IP address or FQDN */ - char *addr; -}; - -/*! - * \brief A collection of SDP attributes - */ -AST_VECTOR(ast_sdp_a_line_vector, struct ast_sdp_a_line); - -/*! - * \brief An SDP media stream - * - * This contains both the m line, as well as its - * constituent a lines. - */ -struct ast_sdp_m_line { - /*! Media type (e.g. "audio" or "video") */ - char *type; - /*! Port number in m line */ - uint16_t port; - /*! Number of ports specified in m line */ - uint16_t port_count; - /*! RTP profile string (e.g. "RTP/AVP") */ - char *profile; - /*! RTP payloads */ - AST_VECTOR(, char *) payloads; - /*! Connection information for this media stream */ - struct ast_sdp_c_line c_line; - /*! The attributes for this media stream */ - struct ast_sdp_a_line_vector a_lines; -}; - -/*! - * \brief SDP time information - */ -struct ast_sdp_t_line { - /*! Session start time */ - uint32_t start; - /*! Session end time */ - uint32_t end; -}; - -/*! - * \brief An SDP - */ -struct ast_sdp { - /*! SDP Origin line */ - struct { - /*! Origin user name */ - char *user; - /*! Origin id */ - uint32_t id; - /*! Origin version */ - uint32_t version; - /*! Origin IP address family (e.g. "IP4" or "IP6") */ - char *family; - /*! Origin address. Can be an IP address or FQDN */ - char *addr; - } o_line; - /*! SDP Session name */ - char *s_line; - /*! SDP top-level connection information */ - struct ast_sdp_c_line c_line; - /*! SDP timing information */ - struct ast_sdp_t_line t_line; - /*! SDP top-level attributes */ - struct ast_sdp_a_line_vector a_lines; - /*! SDP media streams */ - AST_VECTOR(, struct ast_sdp_m_line) m_lines; -}; - -/*! - * \brief Allocate a new SDP. - * - * \note This does not perform any initialization. - * - * \retval NULL FAIL - * \retval non-NULL New SDP - */ -struct ast_sdp *ast_sdp_alloc(void); - -/*! - * \brief Free an SDP and all its constituent parts - */ -void ast_sdp_free(struct ast_sdp *dead); - -#endif /* _SDP_PRIV_H */ diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index 14d3e7c04bb..e2f13eb6135 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -19,9 +19,10 @@ #ifndef _ASTERISK_SDP_STATE_H #define _ASTERISK_SDP_STATE_H +#include "asterisk/stream.h" +#include "asterisk/sdp_options.h" + struct ast_sdp_state; -struct ast_sdp_options; -struct ast_stream_topology; /*! * \brief Allocate a new SDP state @@ -31,7 +32,8 @@ struct ast_stream_topology; * Ownership of the SDP options is taken on by the SDP state. * A good strategy is to call this during session creation. */ -struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, struct ast_sdp_options *options); +struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, + struct ast_sdp_options *options); /*! * \brief Free the SDP state. @@ -45,7 +47,8 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state); * * Stream numbers correspond to the streams in the topology of the associated channel */ -struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sdp_state, int stream_index); +struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(const struct ast_sdp_state *sdp_state, + int stream_index); /*! * \brief Get the joint negotiated streams based on local and remote capabilities. @@ -53,44 +56,96 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sd * If this is called prior to receiving a remote SDP, then this will just mirror * the local configured endpoint capabilities. */ -struct ast_stream_topology *ast_sdp_state_get_joint_topology(struct ast_sdp_state *sdp_state); +const struct ast_stream_topology *ast_sdp_state_get_joint_topology( + const struct ast_sdp_state *sdp_state); + +/*! + * \brief Get the local topology + * + */ +const struct ast_stream_topology *ast_sdp_state_get_local_topology( + const struct ast_sdp_state *sdp_state); + +/*! + * \brief Get the sdp_state options + * + */ +const struct ast_sdp_options *ast_sdp_state_get_options( + const struct ast_sdp_state *sdp_state); + /*! * \brief Get the local SDP. * - * If we have not received a remote SDP yet, this will be an SDP offer based - * on known streams and options If we have received a remote SDP, this will - * be the negotiated SDP based on the joint capabilities. The return type is - * a void pointer because the representation of the SDP is going to be determined based - * on the SDP options when allocating the SDP state. + * \param sdp_state + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \note + * This function will allocate a new SDP with RTP instances if it has not already + * been allocated. + * + */ +const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_state); + +/*! + * \brief Get the local SDP Implementation. + * + * \param sdp_state + * + * \retval non-NULL Success + * \retval NULL Failure + * + * \note + * This function calls ast_sdp_state_get_local_sdp then translates it into + * the defined implementation. + * + * The return here is const. The use case for this is so that a channel can add + * the SDP to an outgoing message. The API user should not attempt to modify the SDP. + * SDP modification should only be done through the API. + * + * \since 15 + */ +const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state); + +/*! + * \brief Set the remote SDP * - * This function will allocate RTP instances if RTP instances have not already - * been allocated for the streams. + * \param sdp_state + * \param sdp * - * The return here is const. The use case for this is so that a channel can add the SDP to an outgoing - * message. The API user should not attempt to modify the SDP. SDP modification should only be done through - * the API. + * \since 15 */ -const void *ast_sdp_state_get_local(struct ast_sdp_state *sdp_state); +void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, struct ast_sdp *sdp); /*! - * \brief Set the remote SDP. + * \brief Set the remote SDP from an Implementation + * + * \param sdp_state + * \param remote The implementation's representation of an SDP. * - * This can be used for either a remote offer or answer. - * This can also be used whenever an UPDATE, re-INVITE, etc. arrives. - * The type of the "remote" parameter is dictated by whatever SDP representation - * was set in the ast_sdp_options used during ast_sdp_state allocation + * \retval 0 Success + * \retval non-0 Failure * - * This function will NOT allocate RTP instances. + * \since 15 */ -int ast_sdp_state_set_remote(struct ast_sdp_state *sdp_state, void *remote); +int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void *remote); /*! * \brief Reset the SDP state and stream capabilities as if the SDP state had just been allocated. * + * \param sdp_state + * \param remote The implementation's representation of an SDP. + * + * \retval 0 Success + * + * \note * This is most useful for when a channel driver is sending a session refresh message * and needs to re-advertise its initial capabilities instead of the previously-negotiated * joint capabilities. + * + * \since 15 */ int ast_sdp_state_reset(struct ast_sdp_state *sdp_state); diff --git a/include/asterisk/sdp_translator.h b/include/asterisk/sdp_translator.h index 62a875e0aa3..09901af2e6c 100644 --- a/include/asterisk/sdp_translator.h +++ b/include/asterisk/sdp_translator.h @@ -28,7 +28,7 @@ struct sdp; */ struct ast_sdp_translator_ops { /*! The SDP representation on which this translator operates */ - enum ast_sdp_options_repr repr; + enum ast_sdp_options_impl repr; /*! Allocate new translator private data for a translator */ void *(*translator_new)(void); /*! Free translator private data */ @@ -36,7 +36,7 @@ struct ast_sdp_translator_ops { /*! Convert the channel-native SDP into an internal Asterisk SDP */ struct ast_sdp *(*to_sdp)(void *repr_sdp, void *translator_priv); /*! Convert an internal Asterisk SDP into a channel-native SDP */ - void *(*from_sdp)(struct ast_sdp *sdp, void *translator_priv); + void *(*from_sdp)(const struct ast_sdp *sdp, void *translator_priv); }; /*! @@ -72,7 +72,7 @@ void ast_sdp_unregister_translator(struct ast_sdp_translator_ops *ops); * \retval NULL FAIL * \retval non-NULL New SDP translator */ -struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_repr repr); +struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_impl repr); /*! * \brief Free an SDP translator @@ -97,6 +97,7 @@ struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, * \retval NULL FAIL * \retval non-NULL The translated SDP */ -void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, struct ast_sdp *ast_sdp); +void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, + const struct ast_sdp *ast_sdp); #endif /* _ASTERISK_SDP_TRANSLATOR_H */ diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 48ee883224e..1becae25a4f 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -43,6 +43,8 @@ struct ast_format_cap; */ struct ast_stream_topology; +typedef void (*ast_stream_data_free_fn)(void *); + /*! * \brief States that a stream may be in */ @@ -69,6 +71,20 @@ enum ast_stream_state { AST_STREAM_STATE_INACTIVE, }; +/*! + * \brief Stream data slots + */ +enum ast_stream_data_slot { + /*! + * \brief Data slot for RTP instance + */ + AST_STREAM_DATA_RTP_INSTANCE = 0, + /*! + * \brief Controls the size of the data pointer array + */ + AST_STREAM_DATA_SLOT_MAX +}; + /*! * \brief Create a new media stream representation * @@ -103,6 +119,9 @@ void ast_stream_free(struct ast_stream *stream); * \retval non-NULL success * \retval NULL failure * + * \note Opaque data pointers set with ast_stream_set_data() are not part + * of the deep clone. The pointers are simply copied. + * * \since 15 */ struct ast_stream *ast_stream_clone(const struct ast_stream *stream); @@ -201,6 +220,34 @@ void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state */ const char *ast_stream_state2str(enum ast_stream_state state); +/*! + * \brief Get the opaque stream data + * + * \param stream The media stream + * \param slot The data slot to retrieve + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 15 + */ +void *ast_stream_get_data(struct ast_stream *stream, enum ast_stream_data_slot slot); + +/*! + * \brief Set the opaque stream data + * + * \param stream The media stream + * \param slot The data slot to set + * \param data Opaque data + * \param data_free_fn Callback to free data when stream is freed. May be NULL for no action. + * + * \return data + * + * \since 15 + */ +void *ast_stream_set_data(struct ast_stream *stream, enum ast_stream_data_slot slot, + void *data, ast_stream_data_free_fn data_free_fn); + /*! * \brief Get the position of the stream in the topology * diff --git a/main/rtp_engine.c b/main/rtp_engine.c index a4654631869..931f89d7cad 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -1493,7 +1493,8 @@ int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload) return res; } -const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_format *format, int code, enum ast_rtp_options options) +const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, + const struct ast_format *format, int code, enum ast_rtp_options options) { int i; const char *res = ""; @@ -1522,7 +1523,8 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f return res; } -unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format *format, int code) +unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, + const struct ast_format *format, int code) { unsigned int i; unsigned int res = 0; diff --git a/main/sdp.c b/main/sdp.c new file mode 100644 index 00000000000..246763edf49 --- /dev/null +++ b/main/sdp.c @@ -0,0 +1,765 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * George Joseph + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + + +#include "asterisk.h" +#include "asterisk/utils.h" +#include "asterisk/netsock2.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" +#include "asterisk/format_cap.h" +#include "asterisk/rtp_engine.h" +#include "asterisk/sdp_state.h" +#include "asterisk/sdp_options.h" +#include "asterisk/sdp_translator.h" +#include "asterisk/sdp.h" +#include "asterisk/vector.h" +#include "asterisk/utils.h" +#include "asterisk/stream.h" +#include "sdp_private.h" + +void ast_sdp_a_free(struct ast_sdp_a_line *a_line) +{ + ast_free(a_line); +} + +void ast_sdp_a_lines_free(struct ast_sdp_a_lines *a_lines) +{ + if (!a_lines) { + return; + } + + AST_VECTOR_CALLBACK_VOID(a_lines, ast_sdp_a_free); + AST_VECTOR_FREE(a_lines); + ast_free(a_lines); +} + +void ast_sdp_c_free(struct ast_sdp_c_line *c_line) +{ + ast_free(c_line); +} + +void ast_sdp_payload_free(struct ast_sdp_payload *payload) +{ + ast_free(payload); +} + +void ast_sdp_payloads_free(struct ast_sdp_payloads *payloads) +{ + if (!payloads) { + return; + } + + AST_VECTOR_CALLBACK_VOID(payloads, ast_sdp_payload_free); + AST_VECTOR_FREE(payloads); + ast_free(payloads); +} + +void ast_sdp_m_free(struct ast_sdp_m_line *m_line) +{ + if (!m_line) { + return; + } + + ast_sdp_a_lines_free(m_line->a_lines); + ast_sdp_payloads_free(m_line->payloads); + ast_sdp_c_free(m_line->c_line); + ast_free(m_line); +} + +void ast_sdp_m_lines_free(struct ast_sdp_m_lines *m_lines) +{ + if (!m_lines) { + return; + } + + AST_VECTOR_CALLBACK_VOID(m_lines, ast_sdp_m_free); + AST_VECTOR_FREE(m_lines); + ast_free(m_lines); +} + +void ast_sdp_o_free(struct ast_sdp_o_line *o_line) +{ + ast_free(o_line); +} + +void ast_sdp_s_free(struct ast_sdp_s_line *s_line) +{ + ast_free(s_line); +} + +void ast_sdp_t_free(struct ast_sdp_t_line *t_line) +{ + ast_free(t_line); +} + +void ast_sdp_free(struct ast_sdp *sdp) +{ + if (!sdp) { + return; + } + + ast_sdp_o_free(sdp->o_line); + ast_sdp_s_free(sdp->s_line); + ast_sdp_c_free(sdp->c_line); + ast_sdp_t_free(sdp->t_line); + ast_sdp_a_lines_free(sdp->a_lines); + ast_sdp_m_lines_free(sdp->m_lines); + ast_free(sdp); +} + +#define COPY_STR_AND_ADVANCE(p, dest, source) \ +({ \ + dest = p; \ + strcpy(dest, source); \ + p += (strlen(source) + 1); \ +}) + +struct ast_sdp_a_line *ast_sdp_a_alloc(const char *name, const char *value) +{ + struct ast_sdp_a_line *a_line; + size_t len; + char *p; + + ast_assert(!ast_strlen_zero(name)); + + if (ast_strlen_zero(value)) { + value = ""; + } + + len = sizeof(*a_line) + strlen(name) + strlen(value) + 2; + a_line = ast_calloc(1, len); + if (!a_line) { + return NULL; + } + + p = ((char *)a_line) + sizeof(*a_line); + + COPY_STR_AND_ADVANCE(p, a_line->name, name); + COPY_STR_AND_ADVANCE(p, a_line->value, value); + + return a_line; +} + +struct ast_sdp_c_line *ast_sdp_c_alloc(const char *address_type, const char *address) +{ + struct ast_sdp_c_line *c_line; + size_t len; + char *p; + + ast_assert(!ast_strlen_zero(address_type) && !ast_strlen_zero(address)); + + len = sizeof(*c_line) + strlen(address_type) + strlen(address) + 2; + c_line = ast_calloc(1, len); + if (!c_line) { + return NULL; + } + + p = ((char *)c_line) + sizeof(*c_line); + + COPY_STR_AND_ADVANCE(p, c_line->address_type, address_type); + COPY_STR_AND_ADVANCE(p, c_line->address, address); + + return c_line; +} + +struct ast_sdp_payload *ast_sdp_payload_alloc(const char *fmt) +{ + struct ast_sdp_payload *payload; + size_t len; + + ast_assert(!ast_strlen_zero(fmt)); + + len = sizeof(*payload) + strlen(fmt) + 1; + payload = ast_calloc(1, len); + if (!payload) { + return NULL; + } + + payload->fmt = ((char *)payload) + sizeof(*payload); + strcpy(payload->fmt, fmt); /* Safe */ + + return payload; +} + +struct ast_sdp_m_line *ast_sdp_m_alloc(const char *type, uint16_t port, + uint16_t port_count, const char *proto, struct ast_sdp_c_line *c_line) +{ + struct ast_sdp_m_line *m_line; + size_t len; + char *p; + + ast_assert(!ast_strlen_zero(type) && !ast_strlen_zero(proto)); + + len = sizeof(*m_line) + strlen(type) + strlen(proto) + 2; + m_line = ast_calloc(1, len); + if (!m_line) { + return NULL; + } + + m_line->a_lines = ast_calloc(1, sizeof(*m_line->a_lines)); + if (!m_line->a_lines) { + ast_sdp_m_free(m_line); + return NULL; + } + if (AST_VECTOR_INIT(m_line->a_lines, 20)) { + ast_sdp_m_free(m_line); + return NULL; + } + + m_line->payloads = ast_calloc(1, sizeof(*m_line->payloads)); + if (!m_line->payloads) { + ast_sdp_m_free(m_line); + return NULL; + } + if (AST_VECTOR_INIT(m_line->payloads, 20)) { + ast_sdp_m_free(m_line); + return NULL; + } + + p = ((char *)m_line) + sizeof(*m_line); + + COPY_STR_AND_ADVANCE(p, m_line->type, type); + COPY_STR_AND_ADVANCE(p, m_line->proto, proto); + m_line->port = port; + m_line->port_count = port_count; + m_line->c_line = c_line; + + return m_line; +} + +struct ast_sdp_s_line *ast_sdp_s_alloc(const char *session_name) +{ + struct ast_sdp_s_line *s_line; + size_t len; + + if (ast_strlen_zero(session_name)) { + session_name = " "; + } + + len = sizeof(*s_line) + strlen(session_name) + 1; + s_line = ast_calloc(1, len); + if (!s_line) { + return NULL; + } + + s_line->session_name = ((char *)s_line) + sizeof(*s_line); + strcpy(s_line->session_name, session_name); /* Safe */ + + return s_line; +} + +struct ast_sdp_t_line *ast_sdp_t_alloc(uint64_t start_time, uint64_t stop_time) +{ + struct ast_sdp_t_line *t_line; + + t_line = ast_calloc(1, sizeof(*t_line)); + if (!t_line) { + return NULL; + } + + t_line->start_time = start_time; + t_line->stop_time = stop_time; + + return t_line; +} + +struct ast_sdp_o_line *ast_sdp_o_alloc(const char *username, uint64_t session_id, + uint64_t session_version, const char *address_type, const char *address) +{ + struct ast_sdp_o_line *o_line; + size_t len; + char *p; + + ast_assert(!ast_strlen_zero(username) && !ast_strlen_zero(address_type) + && !ast_strlen_zero(address)); + + len = sizeof(*o_line) + strlen(username) + strlen(address_type) + strlen(address) + 3; + o_line = ast_calloc(1, len); + if (!o_line) { + return NULL; + } + + o_line->session_id = session_id; + o_line->session_version = session_version; + + p = ((char *)o_line) + sizeof(*o_line); + + COPY_STR_AND_ADVANCE(p, o_line->username, username); + COPY_STR_AND_ADVANCE(p, o_line->address_type, address_type); + COPY_STR_AND_ADVANCE(p, o_line->address, address); + + return o_line; +} + +struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line, + struct ast_sdp_c_line *c_line, struct ast_sdp_s_line *s_line, + struct ast_sdp_t_line *t_line) +{ + struct ast_sdp *new_sdp; + + new_sdp = ast_calloc(1, sizeof *new_sdp); + if (!new_sdp) { + return NULL; + } + + new_sdp->a_lines = ast_calloc(1, sizeof(*new_sdp->a_lines)); + if (!new_sdp->a_lines) { + ast_sdp_free(new_sdp); + return NULL; + } + if (AST_VECTOR_INIT(new_sdp->a_lines, 20)) { + ast_sdp_free(new_sdp); + return NULL; + } + + new_sdp->m_lines = ast_calloc(1, sizeof(*new_sdp->m_lines)); + if (!new_sdp->m_lines) { + ast_sdp_free(new_sdp); + return NULL; + } + if (AST_VECTOR_INIT(new_sdp->m_lines, 20)) { + ast_sdp_free(new_sdp); + return NULL; + } + + new_sdp->o_line = o_line; + new_sdp->c_line = c_line; + new_sdp->s_line = s_line; + new_sdp->t_line = t_line; + + return new_sdp; +} + +int ast_sdp_add_a(struct ast_sdp *sdp, struct ast_sdp_a_line *a_line) +{ + ast_assert(sdp && a_line); + + return AST_VECTOR_APPEND(sdp->a_lines, a_line); +} + +int ast_sdp_get_a_count(const struct ast_sdp *sdp) +{ + ast_assert(sdp != NULL); + + return AST_VECTOR_SIZE(sdp->a_lines); +} + +struct ast_sdp_a_line *ast_sdp_get_a(const struct ast_sdp *sdp, int index) +{ + ast_assert(sdp != NULL); + + return AST_VECTOR_GET(sdp->a_lines, index); +} + +int ast_sdp_add_m(struct ast_sdp *sdp, struct ast_sdp_m_line *m_line) +{ + ast_assert(sdp && m_line); + + return AST_VECTOR_APPEND(sdp->m_lines, m_line); +} + +int ast_sdp_get_m_count(const struct ast_sdp *sdp) +{ + ast_assert(sdp != NULL); + + return AST_VECTOR_SIZE(sdp->m_lines); +} + +struct ast_sdp_m_line *ast_sdp_get_m(const struct ast_sdp *sdp, int index) +{ + ast_assert(sdp != NULL); + + return AST_VECTOR_GET(sdp->m_lines, index); +} + +int ast_sdp_m_add_a(struct ast_sdp_m_line *m_line, struct ast_sdp_a_line *a_line) +{ + ast_assert(m_line && a_line); + + return AST_VECTOR_APPEND(m_line->a_lines, a_line); +} + +int ast_sdp_m_get_a_count(const struct ast_sdp_m_line *m_line) +{ + ast_assert(m_line != NULL); + + return AST_VECTOR_SIZE(m_line->a_lines); +} + +struct ast_sdp_a_line *ast_sdp_m_get_a(const struct ast_sdp_m_line *m_line, int index) +{ + ast_assert(m_line != NULL); + + return AST_VECTOR_GET(m_line->a_lines, index); +} + +int ast_sdp_m_add_payload(struct ast_sdp_m_line *m_line, struct ast_sdp_payload *payload) +{ + ast_assert(m_line && payload); + + return AST_VECTOR_APPEND(m_line->payloads, payload); +} + +int ast_sdp_m_get_payload_count(const struct ast_sdp_m_line *m_line) +{ + ast_assert(m_line != NULL); + + return AST_VECTOR_SIZE(m_line->payloads); +} + +struct ast_sdp_payload *ast_sdp_m_get_payload(const struct ast_sdp_m_line *m_line, int index) +{ + ast_assert(m_line != NULL); + + return AST_VECTOR_GET(m_line->payloads, index); +} + +static int sdp_m_add_fmtp(struct ast_sdp_m_line *m_line, const struct ast_format *format, + int rtp_code) +{ + struct ast_str *fmtp0 = ast_str_alloca(256); + char *tmp; + + ast_format_generate_sdp_fmtp(format, rtp_code, &fmtp0); + if (ast_str_strlen(fmtp0) == 0) { + return -1; + } + + tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1; + /* remove any carriage return line feeds */ + while (*tmp == '\r' || *tmp == '\n') --tmp; + *++tmp = '\0'; + + /* ast...generate gives us everything, just need value */ + tmp = strchr(ast_str_buffer(fmtp0), ':'); + if (tmp && tmp[1] != '\0') { + tmp++; + } else { + tmp = ast_str_buffer(fmtp0); + } + + ast_sdp_m_add_a(m_line, ast_sdp_a_alloc("fmtp", tmp)); + + return 0; +} + +static int sdp_m_add_rtpmap(struct ast_sdp_m_line *m_line, + const struct ast_sdp_options *options, int rtp_code, int asterisk_format, + const struct ast_format *format, int code) +{ + char tmp[64]; + const char *enc_name; + struct ast_sdp_payload *payload; + struct ast_sdp_a_line *a_line; + + snprintf(tmp, sizeof(tmp), "%d", rtp_code); + payload = ast_sdp_payload_alloc(tmp); + if (!payload || ast_sdp_m_add_payload(m_line, payload)) { + ast_sdp_payload_free(payload); + return -1; + } + + enc_name = ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, + options->g726_non_standard ? AST_RTP_OPT_G726_NONSTANDARD : 0); + + snprintf(tmp, sizeof(tmp), "%d %s/%d%s%s", rtp_code, enc_name, + ast_rtp_lookup_sample_rate2(asterisk_format, format, code), + strcmp(enc_name, "opus") ? "" : "/", strcmp(enc_name, "opus") ? "" : "2"); + + a_line = ast_sdp_a_alloc("rtpmap", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + return -1; + } + + return 0; +} + +int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_options *options, + int rtp_code, int asterisk_format, const struct ast_format *format, int code) +{ + sdp_m_add_rtpmap(m_line, options, rtp_code, asterisk_format, format, code); + sdp_m_add_fmtp(m_line, format, rtp_code); + + return 0; +} + +/* TODO + * This isn't set anywhere yet. + */ +/*! \brief Scheduler for RTCP purposes */ +static struct ast_sched_context *sched; + +/*! \brief Internal function which creates an RTP instance */ +static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, + enum ast_media_type media_type) +{ + struct ast_rtp_instance *rtp; + struct ast_rtp_engine_ice *ice; + struct ast_sockaddr temp_media_address; + static struct ast_sockaddr address_rtp; + struct ast_sockaddr *media_address = &address_rtp; + + if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { + ast_sockaddr_parse(&temp_media_address, options->media_address, 0); + media_address = &temp_media_address; + } else { + if (ast_check_ipv6()) { + ast_sockaddr_parse(&address_rtp, "::", 0); + } else { + ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); + } + } + + if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { + ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", + options->rtp_engine); + return NULL; + } + + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); + + if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { + ice->stop(rtp); + } + + if (options->telephone_event) { + ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); + } + + if (media_type == AST_MEDIA_TYPE_AUDIO && + (options->tos_audio || options->cos_audio)) { + ast_rtp_instance_set_qos(rtp, options->tos_audio, + options->cos_audio, "SIP RTP Audio"); + } else if (media_type == AST_MEDIA_TYPE_VIDEO && + (options->tos_video || options->cos_video)) { + ast_rtp_instance_set_qos(rtp, options->tos_video, + options->cos_video, "SIP RTP Video"); + } + + ast_rtp_instance_set_last_rx(rtp, time(NULL)); + + return rtp; +} + +int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options *options, + struct ast_rtp_instance *rtp, const struct ast_stream *stream) +{ + struct ast_sdp_m_line *m_line; + struct ast_format_cap *caps; + int i; + int rtp_code; + int min_packet_size = 0; + int max_packet_size = 0; + enum ast_media_type media_type; + char tmp[64]; + struct ast_sockaddr address_rtp; + struct ast_sdp_a_line *a_line; + + + ast_assert(sdp && options && rtp && stream); + + media_type = ast_stream_get_type(stream); + ast_rtp_instance_get_local_address(rtp, &address_rtp); + + m_line = ast_sdp_m_alloc( + ast_codec_media_type2str(ast_stream_get_type(stream)), + ast_sockaddr_port(&address_rtp), 1, + options->encryption != AST_SDP_ENCRYPTION_DISABLED ? "RTP/SAVP" : "RTP/AVP", + NULL); + if (!m_line) { + return -1; + } + + caps = ast_stream_get_formats(stream); + + for (i = 0; i < ast_format_cap_count(caps); i++) { + struct ast_format *format = ast_format_cap_get_format(caps, i); + + if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) { + ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); + ao2_ref(format, -1); + continue; + } + + if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, format, 0)) { + ast_sdp_m_free(m_line); + ao2_ref(format, -1); + return -1; + } + + if (ast_format_get_maximum_ms(format) && + ((ast_format_get_maximum_ms(format) < max_packet_size) || !max_packet_size)) { + max_packet_size = ast_format_get_maximum_ms(format); + } + + ao2_ref(format, -1); + } + + if (media_type != AST_MEDIA_TYPE_VIDEO) { + for (i = 1LL; i <= AST_RTP_MAX; i <<= 1) { + if (!(options->telephone_event & i)) { + continue; + } + + rtp_code = ast_rtp_codecs_payload_code( + ast_rtp_instance_get_codecs(rtp), 0, NULL, i); + + if (rtp_code == -1) { + continue; + } + + if (sdp_m_add_rtpmap(m_line, options, rtp_code, 0, NULL, i)) { + continue; + } + + if (i == AST_RTP_DTMF) { + snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); + a_line = ast_sdp_a_alloc("fmtp", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + } + } + + if (ast_sdp_m_get_a_count(m_line) == 0) { + return 0; + } + + /* If ptime is set add it as an attribute */ + min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); + if (!min_packet_size) { + min_packet_size = ast_format_cap_get_framing(caps); + } + if (min_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", min_packet_size); + + a_line = ast_sdp_a_alloc("ptime", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + + if (max_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", max_packet_size); + a_line = ast_sdp_a_alloc("maxptime", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + + a_line = ast_sdp_a_alloc(options->locally_held ? "sendonly" : "sendrecv", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + + if (ast_sdp_add_m(sdp, m_line)) { + ast_sdp_m_free(m_line); + return -1; + } + + return 0; +} + +struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state) +{ + const struct ast_sdp_options *options; + RAII_VAR(struct ast_sdp *, sdp, NULL, ao2_cleanup); + const const struct ast_stream_topology *topology; + int stream_count; + int stream_num; + struct ast_sdp_o_line *o_line = NULL; + struct ast_sdp_c_line *c_line = NULL; + struct ast_sdp_s_line *s_line = NULL; + struct ast_sdp_t_line *t_line = NULL; + struct ast_rtp_instance *rtp = NULL; + char *address_type; + struct timeval tv = ast_tvnow(); + uint32_t t; + ast_assert(!!sdp_state); + + options = ast_sdp_state_get_options(sdp_state); + topology = ast_sdp_state_get_local_topology(sdp_state); + stream_count = ast_stream_topology_get_count(topology); + + t = tv.tv_sec + 2208988800UL; + address_type = (strchr(options->media_address, ':') ? "IP6" : "IP4"); + + o_line = ast_sdp_o_alloc(options->sdpowner, t, t, address_type, options->media_address); + if (!o_line) { + goto error; + } + c_line = ast_sdp_c_alloc(address_type, options->media_address); + if (!c_line) { + goto error; + } + + s_line = ast_sdp_s_alloc(options->sdpsession); + if (!s_line) { + goto error; + } + + sdp = ast_sdp_alloc(o_line, c_line, s_line, NULL); + if (!sdp) { + goto error; + } + + for (stream_num = 0; stream_num < stream_count; stream_num++) { + struct ast_stream *stream = ast_stream_topology_get_stream(topology, stream_num); + + rtp = create_rtp(options, ast_stream_get_type(stream)); + if (!rtp) { + goto error; + } + + ast_stream_set_data(stream, AST_STREAM_DATA_RTP_INSTANCE, + rtp, (ast_stream_data_free_fn)&ast_rtp_instance_destroy); + + if (ast_sdp_add_m_from_stream(sdp, options, rtp, stream)) { + goto error; + } + } + + return sdp; + +error: + ao2_cleanup(rtp); + if (sdp) { + ast_sdp_free(sdp); + } else { + ast_sdp_t_free(t_line); + ast_sdp_s_free(s_line); + ast_sdp_c_free(c_line); + ast_sdp_o_free(o_line); + } + + return NULL; +} + diff --git a/main/sdp_options.c b/main/sdp_options.c index e18dfa55abf..ca076ac7b7d 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -21,23 +21,63 @@ #include "asterisk/utils.h" #include "asterisk/sdp_options.h" -struct ast_sdp_options { - enum ast_sdp_options_ice ice; - int telephone_event; - enum ast_sdp_options_repr repr; - enum ast_sdp_options_encryption encryption; -}; +#include "sdp_private.h" #define DEFAULT_ICE AST_SDP_ICE_DISABLED #define DEFAULT_TELEPHONE_EVENT 0 -#define DEFAULT_REPR AST_SDP_REPR_STRING +#define DEFAULT_IMPL AST_SDP_IMPL_STRING #define DEFAULT_ENCRYPTION AST_SDP_ENCRYPTION_DISABLED +#define DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(field, assert_on_null) \ +void ast_sdp_options_set_##field(struct ast_sdp_options *options, const char *value) \ +{ \ + ast_assert(options != NULL); \ + if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \ + if (!strcmp(value, options->field)) return; \ + ast_string_field_set(options, field, value); \ +} \ +const char *ast_sdp_options_get_##field(struct ast_sdp_options *options) \ +{ \ + ast_assert(options != NULL); \ + return options->field; \ +} \ + +#define DEFINE_GETTERS_SETTERS_FOR(type, field) \ +void ast_sdp_options_set_##field(struct ast_sdp_options *options, type value) \ +{ \ + ast_assert(options != NULL); \ + options->field = value; \ +} \ +type ast_sdp_options_get_##field(struct ast_sdp_options *options) \ +{ \ + ast_assert(options != NULL); \ + return options->field; \ +} \ + +DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(media_address, 0); +DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpowner, 0); +DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpsession, 0); +DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(rtp_engine, 0); + +DEFINE_GETTERS_SETTERS_FOR(unsigned int, bind_rtp_to_media_address); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, telephone_event); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_ipv6); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, g726_non_standard); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, locally_held); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_audio); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_audio); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_video); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_video); +DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_ice, ice); +DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_impl, impl); +DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_encryption, encryption); + static void set_defaults(struct ast_sdp_options *options) { options->ice = DEFAULT_ICE; options->telephone_event = DEFAULT_TELEPHONE_EVENT; - options->repr = DEFAULT_REPR; + options->impl = DEFAULT_IMPL; options->encryption = DEFAULT_ENCRYPTION; } @@ -49,72 +89,18 @@ struct ast_sdp_options *ast_sdp_options_alloc(void) if (!options) { return NULL; } + + if (ast_string_field_init(options, 256)) { + ast_free(options); + return NULL; + } + set_defaults(options); return options; } void ast_sdp_options_free(struct ast_sdp_options *options) { + ast_string_field_free_memory(options); ast_free(options); } - -int ast_sdp_options_set_ice(struct ast_sdp_options *options, enum ast_sdp_options_ice ice_setting) -{ - ast_assert(options != NULL); - - options->ice = ice_setting; - return 0; -} - -enum ast_sdp_options_ice ast_sdp_options_get_ice(const struct ast_sdp_options *options) -{ - ast_assert(options != NULL); - - return options->ice; -} - -int ast_sdp_options_set_telephone_event(struct ast_sdp_options *options, int telephone_event_enabled) -{ - ast_assert(options != NULL); - - options->telephone_event = telephone_event_enabled; - return 0; -} - -int ast_sdp_options_get_telephone_event(const struct ast_sdp_options *options) -{ - ast_assert(options != NULL); - - return options->telephone_event; -} - -int ast_sdp_options_set_repr(struct ast_sdp_options *options, enum ast_sdp_options_repr repr) -{ - ast_assert(options != NULL); - - options->repr = repr; - return 0; -} - -enum ast_sdp_options_repr ast_sdp_options_get_repr(const struct ast_sdp_options *options) -{ - ast_assert(options != NULL); - - return options->repr; -} - -int ast_sdp_options_set_encryption(struct ast_sdp_options *options, - enum ast_sdp_options_encryption encryption) -{ - ast_assert(options != NULL); - - options->encryption = encryption; - return 0; -} - -enum ast_sdp_options_encryption ast_sdp_options_get_encryption(const struct ast_sdp_options *options) -{ - ast_assert(options != NULL); - - return options->encryption; -} diff --git a/main/sdp_private.h b/main/sdp_private.h new file mode 100644 index 00000000000..45aaebf9a00 --- /dev/null +++ b/main/sdp_private.h @@ -0,0 +1,55 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef _MAIN_SDP_PRIVATE_H +#define _MAIN_SDP_PRIVATE_H + +#include "asterisk/stringfields.h" +#include "asterisk/sdp_options.h" + +struct ast_sdp_options { + AST_DECLARE_STRING_FIELDS( + /*! Optional media address to use in SDP */ + AST_STRING_FIELD(media_address); + /*! SDP origin username */ + AST_STRING_FIELD(sdpowner); + /*! SDP session name */ + AST_STRING_FIELD(sdpsession); + /*! RTP Engine Name */ + AST_STRING_FIELD(rtp_engine); + ); + struct { + unsigned int bind_rtp_to_media_address : 1; + unsigned int rtp_symmetric : 1; + unsigned int telephone_event : 1; + unsigned int rtp_ipv6 : 1; + unsigned int g726_non_standard : 1; + unsigned int locally_held : 1; + }; + struct { + unsigned int tos_audio; + unsigned int cos_audio; + unsigned int tos_video; + unsigned int cos_video; + }; + enum ast_sdp_options_ice ice; + enum ast_sdp_options_impl impl; + enum ast_sdp_options_encryption encryption; +}; + +#endif /* _MAIN_SDP_PRIVATE_H */ diff --git a/main/sdp_repr.c b/main/sdp_repr.c deleted file mode 100644 index 6df243b0e12..00000000000 --- a/main/sdp_repr.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2017, Digium, Inc. - * - * Mark Michelson - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -#include "asterisk.h" -#include "asterisk/sdp_priv.h" -#include "asterisk/utils.h" - -struct ast_sdp *ast_sdp_alloc(void) -{ - struct ast_sdp *new_sdp; - - new_sdp = ast_calloc(1, sizeof *new_sdp); - return new_sdp; -} - -static void free_o_line(struct ast_sdp *dead) -{ - ast_free(dead->o_line.user); - ast_free(dead->o_line.family); - ast_free(dead->o_line.addr); -} - -static void free_s_line(struct ast_sdp *dead) -{ - ast_free(dead->s_line); -} - -static void free_c_line(struct ast_sdp_c_line *c_line) -{ - ast_free(c_line->family); - ast_free(c_line->addr); -} - -static void free_t_line(struct ast_sdp_t_line *t_line) -{ - return; -} - -static void free_a_line(struct ast_sdp_a_line *a_line) -{ - ast_free(a_line->name); - ast_free(a_line->value); -} - -static void free_a_lines(struct ast_sdp_a_line_vector *a_lines) -{ - int i; - - for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { - free_a_line(AST_VECTOR_GET_ADDR(a_lines, i)); - } - AST_VECTOR_FREE(a_lines); -} - -static void free_m_line(struct ast_sdp_m_line *m_line) -{ - int i; - - ast_free(m_line->type); - ast_free(m_line->profile); - free_c_line(&m_line->c_line); - - for (i = 0; i < AST_VECTOR_SIZE(&m_line->payloads); ++i) { - ast_free(AST_VECTOR_GET(&m_line->payloads, i)); - } - AST_VECTOR_FREE(&m_line->payloads); - - free_a_lines(&m_line->a_lines); -} - -static void free_m_lines(struct ast_sdp *dead) -{ - int i; - - for (i = 0; i < AST_VECTOR_SIZE(&dead->m_lines); ++i) { - free_m_line(AST_VECTOR_GET_ADDR(&dead->m_lines, i)); - } - - AST_VECTOR_FREE(&dead->m_lines); -} - -void ast_sdp_free(struct ast_sdp *dead) -{ - if (!dead) { - return; - } - - free_o_line(dead); - free_s_line(dead); - free_c_line(&dead->c_line); - free_t_line(&dead->t_line); - free_a_lines(&dead->a_lines); - free_m_lines(dead); - ast_free(dead); -} - diff --git a/main/sdp_state.c b/main/sdp_state.c index b478e71486c..1b09ce16f15 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -20,9 +20,10 @@ #include "asterisk/sdp_state.h" #include "asterisk/sdp_options.h" #include "asterisk/sdp_translator.h" -#include "asterisk/sdp_priv.h" #include "asterisk/vector.h" #include "asterisk/utils.h" + +#include "../include/asterisk/sdp.h" #include "asterisk/stream.h" enum ast_sdp_state_machine { @@ -77,13 +78,12 @@ struct ast_sdp_state { struct ast_sdp_options *options; /*! Translator that puts SDPs into the expected representation */ struct ast_sdp_translator *translator; - /*! RTP instance for each media stream */ - AST_VECTOR(, struct ast_rtp_instance *) rtp; /*! The current state machine state that we are in */ enum ast_sdp_state_machine state; }; -struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, struct ast_sdp_options *options) +struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, + struct ast_sdp_options *options) { struct ast_sdp_state *sdp_state; @@ -94,7 +94,7 @@ struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, s sdp_state->options = options; - sdp_state->translator = ast_sdp_translator_new(ast_sdp_options_get_repr(sdp_state->options)); + sdp_state->translator = ast_sdp_translator_new(ast_sdp_options_get_impl(sdp_state->options)); if (!sdp_state->translator) { ast_sdp_state_free(sdp_state); return NULL; @@ -126,18 +126,23 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state) ast_sdp_translator_free(sdp_state->translator); } -struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sdp_state, int stream_index) +struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( + const struct ast_sdp_state *sdp_state, int stream_index) { + struct ast_stream *stream; + ast_assert(sdp_state != NULL); - if (stream_index >= AST_VECTOR_SIZE(&sdp_state->rtp)) { + stream = ast_stream_topology_get_stream(sdp_state->local_capabilities, stream_index); + if (!stream) { return NULL; } - return AST_VECTOR_GET(&sdp_state->rtp, stream_index); + return (struct ast_rtp_instance *)ast_stream_get_data(stream, AST_STREAM_DATA_RTP_INSTANCE); } -struct ast_stream_topology *ast_sdp_state_get_joint_topology(struct ast_sdp_state *sdp_state) +const struct ast_stream_topology *ast_sdp_state_get_joint_topology( + const struct ast_sdp_state *sdp_state) { ast_assert(sdp_state != NULL); if (sdp_state->state == SDP_STATE_NEGOTIATED) { @@ -147,6 +152,23 @@ struct ast_stream_topology *ast_sdp_state_get_joint_topology(struct ast_sdp_stat } } +const struct ast_stream_topology *ast_sdp_state_get_local_topology( + const struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state != NULL); + + return sdp_state->local_capabilities; +} + +const struct ast_sdp_options *ast_sdp_state_get_options( + const struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state != NULL); + + return sdp_state->options; +} + +#if 0 static int merge_sdps(struct ast_sdp_state *sdp_state) { ast_assert(sdp_state->local_sdp != NULL); @@ -169,37 +191,38 @@ static int merge_sdps(struct ast_sdp_state *sdp_state) return 0; } +#endif -const void *ast_sdp_state_get_local(struct ast_sdp_state *sdp_state) +const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_state) { - struct ast_sdp *sdp; - ast_assert(sdp_state != NULL); - /*TODO Create RTP instances based on local topology and SDP options (if not already created) */ - /*TODO Create local SDP based on local topology, SDP options, and RTP ports (if not already created) */ - - switch (sdp_state->state) { - case SDP_STATE_INITIAL: - sdp_state->state = SDP_STATE_OFFERER; - /* Fall through */ - case SDP_STATE_OFFERER: - default: - sdp = sdp_state->local_sdp; - break; - case SDP_STATE_ANSWERER: - sdp_state->state = SDP_STATE_NEGOTIATED; - merge_sdps(sdp_state); - /* Fall through */ - case SDP_STATE_NEGOTIATED: - sdp = sdp_state->joint_sdp; - break; + if (!sdp_state->local_sdp) { + sdp_state->local_sdp = ast_sdp_create_from_state(sdp_state); + } + + return sdp_state->local_sdp; +} + +const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state) +{ + const struct ast_sdp *sdp = ast_sdp_state_get_local_sdp(sdp_state); + + if (!sdp) { + return NULL; } return ast_sdp_translator_from_sdp(sdp_state->translator, sdp); } -int ast_sdp_state_set_remote(struct ast_sdp_state *sdp_state, void *remote) +void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, struct ast_sdp *sdp) +{ + ast_assert(sdp_state != NULL); + + sdp_state->remote_sdp = sdp; +} + +int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void *remote) { struct ast_sdp *sdp; @@ -210,29 +233,7 @@ int ast_sdp_state_set_remote(struct ast_sdp_state *sdp_state, void *remote) return -1; } - sdp_state->remote_sdp = remote; - /* TODO Convert the remote SDP into a topology and store that in - * sdp_state->remote_capabilities - */ - - switch (sdp_state->state) { - case SDP_STATE_ANSWERER: - default: - break; - case SDP_STATE_INITIAL: - sdp_state->state = SDP_STATE_ANSWERER; - break; - case SDP_STATE_OFFERER: - sdp_state->state = SDP_STATE_NEGOTIATED; - /* Fall through */ - case SDP_STATE_NEGOTIATED: - /* If state is already negotiated, and we receive a new - * remote SDP, we need to re-create the joint SDP and joint - * capabilities - */ - merge_sdps(sdp_state); - break; - } + sdp_state->remote_sdp = sdp; return 0; } diff --git a/main/sdp_translator.c b/main/sdp_translator.c index 5426ae95420..abd0f627667 100644 --- a/main/sdp_translator.c +++ b/main/sdp_translator.c @@ -24,13 +24,13 @@ #include "asterisk/lock.h" AST_RWLOCK_DEFINE_STATIC(registered_ops_lock); -static struct ast_sdp_translator_ops *registered_ops[AST_SDP_REPR_END]; +static struct ast_sdp_translator_ops *registered_ops[AST_SDP_IMPL_END]; int ast_sdp_register_translator(struct ast_sdp_translator_ops *ops) { SCOPED_WRLOCK(lock, ®istered_ops_lock); - if (ops->repr >= AST_SDP_REPR_END) { + if (ops->repr >= AST_SDP_IMPL_END) { ast_log(LOG_ERROR, "SDP translator has unrecognized representation\n"); return -1; } @@ -49,14 +49,14 @@ void ast_sdp_unregister_translator(struct ast_sdp_translator_ops *ops) { SCOPED_WRLOCK(lock, ®istered_ops_lock); - if (ops->repr >= AST_SDP_REPR_END) { + if (ops->repr >= AST_SDP_IMPL_END) { return; } registered_ops[ops->repr] = NULL; } -struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_repr repr) +struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_impl repr) { struct ast_sdp_translator *translator; SCOPED_RDLOCK(lock, ®istered_ops_lock); @@ -88,12 +88,14 @@ void ast_sdp_translator_free(struct ast_sdp_translator *translator) ast_free(translator); } -struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, void *native_sdp) +struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, + void *native_sdp) { return translator->ops->to_sdp(native_sdp, translator->translator_priv); } -void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, struct ast_sdp *ast_sdp) +void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, + const struct ast_sdp *ast_sdp) { return translator->ops->from_sdp(ast_sdp, translator->translator_priv); } diff --git a/main/stream.c b/main/stream.c index 8bee2fdd0a9..9d36dbf25af 100644 --- a/main/stream.c +++ b/main/stream.c @@ -56,6 +56,16 @@ struct ast_stream { */ enum ast_stream_state state; + /*! + * \brief Opaque stream data + */ + void *data[AST_STREAM_DATA_SLOT_MAX]; + + /*! + * \brief What to do with data when the stream is freed + */ + ast_stream_data_free_fn data_free_fn[AST_STREAM_DATA_SLOT_MAX]; + /*! * \brief Name for the stream within the context of the channel it is on */ @@ -110,10 +120,18 @@ struct ast_stream *ast_stream_clone(const struct ast_stream *stream) void ast_stream_free(struct ast_stream *stream) { + int i; + if (!stream) { return; } + for (i = 0; i < AST_STREAM_DATA_SLOT_MAX; i++) { + if (stream->data_free_fn[i]) { + stream->data_free_fn[i](stream->data[i]); + } + } + ao2_cleanup(stream->formats); ast_free(stream); } @@ -186,6 +204,24 @@ const char *ast_stream_state2str(enum ast_stream_state state) } } +void *ast_stream_get_data(struct ast_stream *stream, enum ast_stream_data_slot slot) +{ + ast_assert(stream != NULL); + + return stream->data[slot]; +} + +void *ast_stream_set_data(struct ast_stream *stream, enum ast_stream_data_slot slot, + void *data, ast_stream_data_free_fn data_free_fn) +{ + ast_assert(stream != NULL); + + stream->data[slot] = data; + stream->data_free_fn[slot] = data_free_fn; + + return data; +} + int ast_stream_get_position(const struct ast_stream *stream) { ast_assert(stream != NULL); diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c index 141b97617c3..8eab71611d5 100644 --- a/res/res_sdp_translator_pjmedia.c +++ b/res/res_sdp_translator_pjmedia.c @@ -19,13 +19,14 @@ #include "asterisk.h" #include "asterisk/sdp_translator.h" #include "asterisk/sdp_options.h" -#include "asterisk/sdp_priv.h" #include "asterisk/vector.h" #include "asterisk/netsock2.h" #include "asterisk/utils.h" #include "asterisk/config.h" #include "asterisk/test.h" #include "asterisk/module.h" + +#include "../include/asterisk/sdp.h" #ifdef HAVE_PJPROJECT #include #include @@ -55,222 +56,206 @@ static void pjmedia_free(void *translator_priv) pj_pool_release(pool); } -static void copy_pj_str(char *dest, const pj_str_t *src, size_t size) -{ - memcpy(dest, pj_strbuf(src), size); - dest[size] = '\0'; -} +#define dupa_pj_str(pjstr) \ +({ \ + char *dest = ast_alloca(pjstr.slen + 1); \ + memcpy(dest, pjstr.ptr, pjstr.slen); \ + dest[pjstr.slen] = '\0'; \ + dest; \ +}) -static void dup_pj_str(char **dest, const pj_str_t *src) +static struct ast_sdp_m_line *pjmedia_copy_m_line(struct pjmedia_sdp_media *pjmedia_m_line) { - *dest = ast_malloc(pj_strlen(src) + 1); - copy_pj_str(*dest, src, pj_strlen(src)); -} + int i; -static void pjmedia_copy_o_line(struct ast_sdp *new_sdp, struct pjmedia_sdp_session * pjmedia_sdp) -{ - dup_pj_str(&new_sdp->o_line.user, &pjmedia_sdp->origin.user); - new_sdp->o_line.id = pjmedia_sdp->origin.id; - new_sdp->o_line.version = pjmedia_sdp->origin.version; - dup_pj_str(&new_sdp->o_line.family, &pjmedia_sdp->origin.addr_type); - dup_pj_str(&new_sdp->o_line.addr, &pjmedia_sdp->origin.addr); -} + struct ast_sdp_c_line *c_line = pjmedia_m_line->conn ? + ast_sdp_c_alloc(dupa_pj_str(pjmedia_m_line->conn->addr_type), + dupa_pj_str(pjmedia_m_line->conn->addr)) : NULL; -static void pjmedia_copy_s_line(struct ast_sdp *new_sdp, struct pjmedia_sdp_session *pjmedia_sdp) -{ - dup_pj_str(&new_sdp->s_line, &pjmedia_sdp->name); -} + struct ast_sdp_m_line *m_line = ast_sdp_m_alloc(dupa_pj_str(pjmedia_m_line->desc.media), + pjmedia_m_line->desc.port, pjmedia_m_line->desc.port_count, + dupa_pj_str(pjmedia_m_line->desc.transport), c_line); -static void pjmedia_copy_t_line(struct ast_sdp_t_line *new_t_line, struct pjmedia_sdp_session *pjmedia_sdp) -{ - new_t_line->start = pjmedia_sdp->time.start; - new_t_line->end = pjmedia_sdp->time.stop; -} + for (i = 0; i < pjmedia_m_line->desc.fmt_count; ++i) { + ast_sdp_m_add_payload(m_line, + ast_sdp_payload_alloc(dupa_pj_str(pjmedia_m_line->desc.fmt[i]))); + } -static void pjmedia_copy_c_line(struct ast_sdp_c_line *new_c_line, struct pjmedia_sdp_conn *conn) -{ - /* It's perfectly reasonable for a c line not to be present, especially within a media description */ - if (!conn) { - return; + for (i = 0; i < pjmedia_m_line->attr_count; ++i) { + ast_sdp_m_add_a(m_line, ast_sdp_a_alloc(dupa_pj_str(pjmedia_m_line->attr[i]->name), + dupa_pj_str(pjmedia_m_line->attr[i]->value))); } - dup_pj_str(&new_c_line->family, &conn->addr_type); - dup_pj_str(&new_c_line->addr, &conn->addr); + return m_line; } -static void pjmedia_copy_m_line(struct ast_sdp_m_line *new_m_line, struct pjmedia_sdp_media *pjmedia_m_line) +static void pjmedia_copy_a_lines(struct ast_sdp *new_sdp, pjmedia_sdp_session *pjmedia_sdp) { int i; - dup_pj_str(&new_m_line->type, &pjmedia_m_line->desc.media); - new_m_line->port = pjmedia_m_line->desc.port; - new_m_line->port_count = pjmedia_m_line->desc.port_count; - dup_pj_str(&new_m_line->profile, &pjmedia_m_line->desc.transport); - pjmedia_copy_c_line(&new_m_line->c_line, pjmedia_m_line->conn); - - AST_VECTOR_INIT(&new_m_line->payloads, pjmedia_m_line->desc.fmt_count); - for (i = 0; i < pjmedia_m_line->desc.fmt_count; ++i) { - ++new_m_line->payloads.current; - dup_pj_str(AST_VECTOR_GET_ADDR(&new_m_line->payloads, i), &pjmedia_m_line->desc.fmt[i]); + for (i = 0; i < pjmedia_sdp->attr_count; ++i) { + ast_sdp_add_a(new_sdp, ast_sdp_a_alloc(dupa_pj_str(pjmedia_sdp->attr[i]->name), + dupa_pj_str(pjmedia_sdp->attr[i]->value))); } } -static void pjmedia_copy_a_lines(struct ast_sdp_a_line_vector *new_a_lines, pjmedia_sdp_attr **attr, unsigned int attr_count) +static void pjmedia_copy_m_lines(struct ast_sdp *new_sdp, + struct pjmedia_sdp_session *pjmedia_sdp) { int i; - AST_VECTOR_INIT(new_a_lines, attr_count); - - for (i = 0; i < attr_count; ++i) { - struct ast_sdp_a_line *a_line; - - ++new_a_lines->current; - a_line = AST_VECTOR_GET_ADDR(new_a_lines, i); - dup_pj_str(&a_line->name, &attr[i]->name); - dup_pj_str(&a_line->value, &attr[i]->value); + for (i = 0; i < pjmedia_sdp->media_count; ++i) { + ast_sdp_add_m(new_sdp, pjmedia_copy_m_line(pjmedia_sdp->media[i])); } } -static void pjmedia_copy_m_lines(struct ast_sdp *new_sdp, struct pjmedia_sdp_session *pjmedia_sdp) +static struct ast_sdp *pjmedia_to_sdp(void *in, void *translator_priv) { - int i; + struct pjmedia_sdp_session *pjmedia_sdp = in; - AST_VECTOR_INIT(&new_sdp->m_lines, pjmedia_sdp->media_count); + struct ast_sdp_o_line *o_line = ast_sdp_o_alloc(dupa_pj_str(pjmedia_sdp->origin.user), + pjmedia_sdp->origin.id, pjmedia_sdp->origin.version, + dupa_pj_str(pjmedia_sdp->origin.addr_type), dupa_pj_str(pjmedia_sdp->origin.addr)); - for (i = 0; i < pjmedia_sdp->media_count; ++i) { - ++new_sdp->m_lines.current; + struct ast_sdp_c_line *c_line = pjmedia_sdp->conn ? + ast_sdp_c_alloc(dupa_pj_str(pjmedia_sdp->conn->addr_type), + dupa_pj_str(pjmedia_sdp->conn->addr)) : NULL; - pjmedia_copy_m_line(AST_VECTOR_GET_ADDR(&new_sdp->m_lines, i), pjmedia_sdp->media[i]); - pjmedia_copy_a_lines(&AST_VECTOR_GET_ADDR(&new_sdp->m_lines, i)->a_lines, pjmedia_sdp->media[i]->attr, pjmedia_sdp->media[i]->attr_count); - } -} + struct ast_sdp_s_line *s_line = ast_sdp_s_alloc(dupa_pj_str(pjmedia_sdp->name)); -static struct ast_sdp *pjmedia_to_sdp(void *in, void *translator_priv) -{ - struct pjmedia_sdp_session *pjmedia_sdp = in; + struct ast_sdp_t_line *t_line = ast_sdp_t_alloc(pjmedia_sdp->time.start, + pjmedia_sdp->time.stop); - struct ast_sdp *new_sdp = ast_sdp_alloc(); + struct ast_sdp *new_sdp = ast_sdp_alloc(o_line, c_line, s_line, t_line); - pjmedia_copy_o_line(new_sdp, pjmedia_sdp); - pjmedia_copy_s_line(new_sdp, pjmedia_sdp); - pjmedia_copy_t_line(&new_sdp->t_line, pjmedia_sdp); - pjmedia_copy_c_line(&new_sdp->c_line, pjmedia_sdp->conn); - pjmedia_copy_a_lines(&new_sdp->a_lines, pjmedia_sdp->attr, pjmedia_sdp->attr_count); + pjmedia_copy_a_lines(new_sdp, pjmedia_sdp); pjmedia_copy_m_lines(new_sdp, pjmedia_sdp); return new_sdp; } -static void copy_o_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp *sdp) +static void copy_o_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, + struct ast_sdp_o_line *o_line) { - pjmedia_sdp->origin.id = sdp->o_line.id; - pjmedia_sdp->origin.version = sdp->o_line.version; - pj_strdup2(pool, &pjmedia_sdp->origin.user, sdp->o_line.user); - pj_strdup2(pool, &pjmedia_sdp->origin.addr_type, sdp->o_line.family); - pj_strdup2(pool, &pjmedia_sdp->origin.addr, sdp->o_line.addr); + pjmedia_sdp->origin.id = o_line->session_id; + pjmedia_sdp->origin.version = o_line->session_version; + pj_strdup2(pool, &pjmedia_sdp->origin.user, o_line->username); + pj_strdup2(pool, &pjmedia_sdp->origin.addr_type, o_line->address_type); + pj_strdup2(pool, &pjmedia_sdp->origin.addr, o_line->address); pj_strdup2(pool, &pjmedia_sdp->origin.net_type, "IN"); } -static void copy_s_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp *sdp) +static void copy_s_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, + struct ast_sdp_s_line *s_line) { - pj_strdup2(pool, &pjmedia_sdp->name, sdp->s_line); + pj_strdup2(pool, &pjmedia_sdp->name, s_line->session_name); } -static void copy_t_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp_t_line *t_line) +static void copy_t_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, + struct ast_sdp_t_line *t_line) { - pjmedia_sdp->time.start = t_line->start; - pjmedia_sdp->time.stop = t_line->end; + pjmedia_sdp->time.start = t_line->start_time; + pjmedia_sdp->time.stop = t_line->stop_time; } -static void copy_c_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_conn **conn, struct ast_sdp_c_line *c_line) +static void copy_c_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_conn **conn, + struct ast_sdp_c_line *c_line) { pjmedia_sdp_conn *local_conn; local_conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); - pj_strdup2(pool, &local_conn->addr_type, c_line->family); - pj_strdup2(pool, &local_conn->addr, c_line->addr); + pj_strdup2(pool, &local_conn->addr_type, c_line->address_type); + pj_strdup2(pool, &local_conn->addr, c_line->address); pj_strdup2(pool, &local_conn->net_type, "IN"); *conn = local_conn; } -static void copy_a_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp_a_line_vector *a_lines) +static void copy_a_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, + const struct ast_sdp *sdp) { int i; - for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { + for (i = 0; i < ast_sdp_get_a_count(sdp); ++i) { pjmedia_sdp_attr *attr; pj_str_t value; + struct ast_sdp_a_line *a_line; - pj_strdup2(pool, &value, AST_VECTOR_GET(a_lines, i).value); - attr = pjmedia_sdp_attr_create(pool, AST_VECTOR_GET(a_lines, i).name, &value); + a_line = ast_sdp_get_a(sdp, i); + pj_strdup2(pool, &value, a_line->value); + attr = pjmedia_sdp_attr_create(pool, a_line->name, &value); pjmedia_sdp_session_add_attr(pjmedia_sdp, attr); } } -static void copy_a_lines_pjmedia_media(pj_pool_t *pool, pjmedia_sdp_media *media, struct ast_sdp_a_line_vector *a_lines) +static void copy_a_lines_pjmedia_media(pj_pool_t *pool, pjmedia_sdp_media *media, + struct ast_sdp_m_line *m_line) { int i; - for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { + for (i = 0; i < ast_sdp_m_get_a_count(m_line); ++i) { pjmedia_sdp_attr *attr; pj_str_t value; + struct ast_sdp_a_line *a_line; - pj_strdup2(pool, &value, AST_VECTOR_GET(a_lines, i).value); - attr = pjmedia_sdp_attr_create(pool, AST_VECTOR_GET(a_lines, i).name, &value); + a_line = ast_sdp_m_get_a(m_line, i); + pj_strdup2(pool, &value, a_line->value); + attr = pjmedia_sdp_attr_create(pool, a_line->name, &value); pjmedia_sdp_media_add_attr(media, attr); } } -static void copy_m_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_media *media, struct ast_sdp_m_line *m_line) +static void copy_m_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_media *media, + struct ast_sdp_m_line *m_line) { int i; media->desc.port = m_line->port; media->desc.port_count = m_line->port_count; - pj_strdup2(pool, &media->desc.transport, m_line->profile); + pj_strdup2(pool, &media->desc.transport, m_line->proto); pj_strdup2(pool, &media->desc.media, m_line->type); - for (i = 0; i < AST_VECTOR_SIZE(&m_line->payloads); ++i) { - pj_strdup2(pool, &media->desc.fmt[i], AST_VECTOR_GET(&m_line->payloads, i)); + for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { + pj_strdup2(pool, &media->desc.fmt[i], ast_sdp_m_get_payload(m_line, i)->fmt); ++media->desc.fmt_count; } - if (m_line->c_line.addr) { - copy_c_line_pjmedia(pool, &media->conn, &m_line->c_line); + if (m_line->c_line && m_line->c_line->address) { + copy_c_line_pjmedia(pool, &media->conn, m_line->c_line); } - copy_a_lines_pjmedia_media(pool, media, &m_line->a_lines); + copy_a_lines_pjmedia_media(pool, media, m_line); } -static void copy_m_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, struct ast_sdp *sdp) +static void copy_m_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp, + const struct ast_sdp *sdp) { int i; - for (i = 0; i < AST_VECTOR_SIZE(&sdp->m_lines); ++i) { + for (i = 0; i < ast_sdp_get_m_count(sdp); ++i) { pjmedia_sdp_media *media; media = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); - copy_m_line_pjmedia(pool, media, AST_VECTOR_GET_ADDR(&sdp->m_lines, i)); + copy_m_line_pjmedia(pool, media, ast_sdp_get_m(sdp, i)); pjmedia_sdp->media[pjmedia_sdp->media_count] = media; ++pjmedia_sdp->media_count; } } -static void *sdp_to_pjmedia(struct ast_sdp *sdp, void *translator_priv) +static void *sdp_to_pjmedia(const struct ast_sdp *sdp, void *translator_priv) { pj_pool_t *pool = translator_priv; pjmedia_sdp_session *pjmedia_sdp; pjmedia_sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session); - copy_o_line_pjmedia(pool, pjmedia_sdp, sdp); - copy_s_line_pjmedia(pool, pjmedia_sdp, sdp); - copy_t_line_pjmedia(pool, pjmedia_sdp, &sdp->t_line); - copy_c_line_pjmedia(pool, &pjmedia_sdp->conn, &sdp->c_line); - copy_a_lines_pjmedia(pool, pjmedia_sdp, &sdp->a_lines); + copy_o_line_pjmedia(pool, pjmedia_sdp, sdp->o_line); + copy_s_line_pjmedia(pool, pjmedia_sdp, sdp->s_line); + copy_t_line_pjmedia(pool, pjmedia_sdp, sdp->t_line); + copy_c_line_pjmedia(pool, &pjmedia_sdp->conn, sdp->c_line); + copy_a_lines_pjmedia(pool, pjmedia_sdp, sdp); copy_m_lines_pjmedia(pool, pjmedia_sdp, sdp); return pjmedia_sdp; } static struct ast_sdp_translator_ops pjmedia_translator = { - .repr = AST_SDP_REPR_PJMEDIA, + .repr = AST_SDP_IMPL_PJMEDIA, .translator_new = pjmedia_new, .translator_free = pjmedia_free, .to_sdp = pjmedia_to_sdp, @@ -279,37 +264,38 @@ static struct ast_sdp_translator_ops pjmedia_translator = { #ifdef TEST_FRAMEWORK -static int verify_s_line(char *s_line, char *expected) +static int verify_s_line(struct ast_sdp_s_line *s_line, char *expected) { - return strcmp(s_line, expected) == 0; + return strcmp(s_line->session_name, expected) == 0; } static int verify_c_line(struct ast_sdp_c_line *c_line, char *family, char *addr) { - return strcmp(c_line->family, family) == 0 && strcmp(c_line->addr, addr) == 0; + return strcmp(c_line->address_type, family) == 0 && strcmp(c_line->address, addr) == 0; } static int verify_t_line(struct ast_sdp_t_line *t_line, uint32_t start, uint32_t end) { - return t_line->start == start && t_line->end == end; + return t_line->start_time == start && t_line->stop_time == end; } -static int verify_m_line(struct ast_sdp *sdp, int index, char *type, int port, int port_count, char *profile, ...) +static int verify_m_line(struct ast_sdp *sdp, int index, char *type, int port, + int port_count, char *profile, ...) { struct ast_sdp_m_line *m_line; int res; va_list ap; int i; - m_line = AST_VECTOR_GET_ADDR(&sdp->m_lines, index); + m_line = ast_sdp_get_m(sdp, index); res = strcmp(m_line->type, type) == 0; res |= m_line->port == port; res |= m_line->port_count == port_count; - res |= strcmp(m_line->profile, profile) == 0; + res |= strcmp(m_line->proto, profile) == 0; va_start(ap, profile); - for (i = 0; i < AST_VECTOR_SIZE(&m_line->payloads); ++i) { + for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { char *payload; payload = va_arg(ap, char *); @@ -317,19 +303,20 @@ static int verify_m_line(struct ast_sdp *sdp, int index, char *type, int port, i res = -1; break; } - res |= strcmp(AST_VECTOR_GET(&m_line->payloads, i), payload) == 0; + res |= strcmp(ast_sdp_m_get_payload(m_line, i)->fmt, payload) == 0; } va_end(ap); return res; } -static int verify_a_line(struct ast_sdp *sdp, int m_index, int a_index, char *name, char *value) +static int verify_a_line(struct ast_sdp *sdp, int m_index, int a_index, char *name, + char *value) { struct ast_sdp_m_line *m_line; struct ast_sdp_a_line *a_line; - m_line = AST_VECTOR_GET_ADDR(&sdp->m_lines, m_index); - a_line = AST_VECTOR_GET_ADDR(&m_line->a_lines, a_index); + m_line = ast_sdp_get_m(sdp, m_index); + a_line = ast_sdp_m_get_a(m_line, a_index); return strcmp(a_line->name, name) == 0 && strcmp(a_line->value, value) == 0; } @@ -340,10 +327,10 @@ AST_TEST_DEFINE(pjmedia_to_sdp_test) pj_pool_t *pool; char *sdp_str = "v=0\r\n" - "o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com\r\n" + "o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com\r\n" "s= \r\n" "c=IN IP4 host.atlanta.example.com\r\n" - "t=0 0\r\n" + "t=123 456\r\n" "m=audio 49170 RTP/AVP 0 8 97\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" @@ -371,7 +358,7 @@ AST_TEST_DEFINE(pjmedia_to_sdp_test) pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia to sdp test", 1024, 1024, NULL); - translator = ast_sdp_translator_new(AST_SDP_REPR_PJMEDIA); + translator = ast_sdp_translator_new(AST_SDP_IMPL_PJMEDIA); if (!translator) { ast_test_status_update(test, "Failed to create SDP translator\n"); res = AST_TEST_FAIL; @@ -387,24 +374,24 @@ AST_TEST_DEFINE(pjmedia_to_sdp_test) sdp = ast_sdp_translator_to_sdp(translator, pjmedia_sdp); - if (strcmp(sdp->o_line.user, "alice")) { - ast_test_status_update(test, "Unexpected SDP user '%s'\n", sdp->o_line.user); + if (strcmp(sdp->o_line->username, "alice")) { + ast_test_status_update(test, "Unexpected SDP user '%s'\n", sdp->o_line->username); res = AST_TEST_FAIL; goto cleanup; - } else if (sdp->o_line.id != 2890844526u) { - ast_test_status_update(test, "Unexpected SDP id '%u'\n", sdp->o_line.id); + } else if (sdp->o_line->session_id != 2890844526UL) { + ast_test_status_update(test, "Unexpected SDP id '%" PRId64 "lu'\n", sdp->o_line->session_id); res = AST_TEST_FAIL; goto cleanup; - } else if (sdp->o_line.version != 2890844526u) { - ast_test_status_update(test, "Unexpected SDP version '%u'\n", sdp->o_line.version); + } else if (sdp->o_line->session_version != 2890844527UL) { + ast_test_status_update(test, "Unexpected SDP version '%" PRId64 "'\n", sdp->o_line->session_version); res = AST_TEST_FAIL; goto cleanup; - } else if (strcmp(sdp->o_line.family, "IP4")) { - ast_test_status_update(test, "Unexpected address family '%s'\n", sdp->o_line.family); + } else if (strcmp(sdp->o_line->address_type, "IP4")) { + ast_test_status_update(test, "Unexpected address family '%s'\n", sdp->o_line->address_type); res = AST_TEST_FAIL; goto cleanup; - } else if (strcmp(sdp->o_line.addr, "host.atlanta.example.com")) { - ast_test_status_update(test, "Unexpected address '%s'\n", sdp->o_line.addr); + } else if (strcmp(sdp->o_line->address, "host.atlanta.example.com")) { + ast_test_status_update(test, "Unexpected address '%s'\n", sdp->o_line->address); res = AST_TEST_FAIL; goto cleanup; } @@ -413,11 +400,11 @@ AST_TEST_DEFINE(pjmedia_to_sdp_test) ast_test_status_update(test, "Bad s line\n"); res = AST_TEST_FAIL; goto cleanup; - } else if (!verify_c_line(&sdp->c_line, "IP4", "host.atlanta.example.com")) { + } else if (!verify_c_line(sdp->c_line, "IP4", "host.atlanta.example.com")) { ast_test_status_update(test, "Bad c line\n"); res = AST_TEST_FAIL; goto cleanup; - } else if (!verify_t_line(&sdp->t_line, 0, 0)) { + } else if (!verify_t_line(sdp->t_line, 123, 456)) { ast_test_status_update(test, "Bad t line\n"); res = AST_TEST_FAIL; goto cleanup; @@ -472,7 +459,7 @@ AST_TEST_DEFINE(sdp_to_pjmedia_test) "o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com\r\n" "s= \r\n" "c=IN IP4 host.atlanta.example.com\r\n" - "t=0 0\r\n" + "t=123 456\r\n" "m=audio 49170 RTP/AVP 0 8 97\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" @@ -487,6 +474,8 @@ AST_TEST_DEFINE(sdp_to_pjmedia_test) struct ast_sdp *sdp = NULL; pj_status_t status; enum ast_test_result_state res = AST_TEST_PASS; + char buf[2048]; + char errbuf[256]; switch (cmd) { case TEST_INIT: @@ -502,7 +491,7 @@ AST_TEST_DEFINE(sdp_to_pjmedia_test) pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia to sdp test", 1024, 1024, NULL); - translator = ast_sdp_translator_new(AST_SDP_REPR_PJMEDIA); + translator = ast_sdp_translator_new(AST_SDP_IMPL_PJMEDIA); if (!translator) { ast_test_status_update(test, "Failed to create SDP translator\n"); res = AST_TEST_FAIL; @@ -520,15 +509,13 @@ AST_TEST_DEFINE(sdp_to_pjmedia_test) pjmedia_sdp_dup = ast_sdp_translator_from_sdp(translator, sdp); if ((status = pjmedia_sdp_session_cmp(pjmedia_sdp_orig, pjmedia_sdp_dup, 0)) != PJ_SUCCESS) { - char buf[2048]; - char errbuf[256]; ast_test_status_update(test, "SDPs aren't equal\n"); pjmedia_sdp_print(pjmedia_sdp_orig, buf, sizeof(buf)); - ast_log(LOG_NOTICE, "Original SDP is %s\n", buf); + ast_test_status_update(test, "Original SDP is %s\n", buf); pjmedia_sdp_print(pjmedia_sdp_dup, buf, sizeof(buf)); - ast_log(LOG_NOTICE, "New SDP is %s\n", buf); + ast_test_status_update(test, "New SDP is %s\n", buf); pjmedia_strerror(status, errbuf, sizeof(errbuf)); - ast_log(LOG_NOTICE, "PJMEDIA says %d: '%s'\n", status, errbuf); + ast_test_status_update(test, "PJMEDIA says %d: '%s'\n", status, errbuf); res = AST_TEST_FAIL; goto cleanup; } From 59130260e7bde0a0b69445b0b0ad7089387b890c Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 14 Mar 2017 15:12:28 -0500 Subject: [PATCH 1118/1578] configure: Don't use the progress bar with curl when downloading to stdout In some scenarios, such as when there may not be a terminal (such as inside a Docker container), curl will apparently direct the progress bar to stdout. This can cause extra data to be appended to a file curl'd down to stdout, resulting in md5 verification failures. This patch removes the progress bar, and tells curl to download the file silently. ASTERISK-26872 #close Change-Id: Ie860b020f627d4372b3e7ce9453de5faafeebe6c --- configure | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 893f10738fe..078020c5fe7 100755 --- a/configure +++ b/configure @@ -7940,7 +7940,7 @@ if test "${WGET}" != ":" ; then DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" - DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar" + DOWNLOAD_TO_STDOUT="${CURL} -Ls" DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)' else # Extract the first word of "fetch", so it can be a program name with args. diff --git a/configure.ac b/configure.ac index e714c54b663..890f32d4728 100644 --- a/configure.ac +++ b/configure.ac @@ -318,7 +318,7 @@ if test "${WGET}" != ":" ; then DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" - DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar" + DOWNLOAD_TO_STDOUT="${CURL} -Ls" DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)' else AC_PATH_PROG([FETCH], [fetch], [:]) From 0dc007e94df4be041a984da5ed5346617127eb62 Mon Sep 17 00:00:00 2001 From: Richard Begg Date: Wed, 15 Mar 2017 08:51:41 +1100 Subject: [PATCH 1119/1578] chan_iax2: Reload of iax peer results in loss of host address/port When using a non-dynamic peer address, build_peer() invalidates the peer address structure by setting the address family to unspecified. However, if dnsmgr is enabled, the subsequent call to ast_dnsmgr_lookup() will not amend the peer address if the cache is still valid, resulting in peer connectivity failures. To fix this, we call ast_dnsmgr_refresh() instead. ASTERISK-26865 Change-Id: Id8a89a2f771ebbaf32255a35fe596a6dcb97a082 --- channels/chan_iax2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index e2f575d048d..2cc5e1ba263 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -12909,7 +12909,13 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st /* Non-dynamic. Make sure we become that way if we're not */ AST_SCHED_DEL(sched, peer->expire); ast_clear_flag64(peer, IAX_DYNAMIC); - peer->addr.ss.ss_family = AST_AF_UNSPEC; + if (peer->dnsmgr) { + // Make sure we refresh dnsmgr if we're using it + ast_dnsmgr_refresh(peer->dnsmgr); + } else { + // Or just invalidate the address + peer->addr.ss.ss_family = AST_AF_UNSPEC; + } if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL)) { return peer_unref(peer); } From f997090877e4d9b9459e76a9659af4786b8d4c36 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 14 Mar 2017 16:16:23 -0500 Subject: [PATCH 1120/1578] pbx.c: Fix crash from malformed exten pattern. Forgetting to indicate an exten is a pattern can cause a crash if the "pattern" has a character set range. e.g., "9999[3-5]" The crash is due to a buffer overwrite because the '-' exten eye-candy wasn't removed as expected and overran the allocated space. The buffer overwrite is fixed two ways in this patch. 1) Fix ext_strncpy() to distinguish between pattern and non-pattern extens. Now '-' characters are removed when they are eye-candy and not when they are part of a pattern character set. Since the function is private to pbx.c, the return value now returns the number of bytes written to the destination buffer instead of the strlen() of the final buffer so the callers that care don't need to add one. 2) Fix callers to ext_strncpy() to supply the correct available buffer size of the destination buffer. ASTERISK-26668 Change-Id: I555d97411140e47e0522684062d174fbe32aa84a --- main/pbx.c | 55 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/main/pbx.c b/main/pbx.c index fe87d67a5a0..dc4b91f0841 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -657,7 +657,7 @@ static int ast_add_extension2_lockopt(struct ast_context *con, static struct ast_context *find_context_locked(const char *context); static struct ast_context *find_context(const char *context); static void get_device_state_causing_channels(struct ao2_container *c); -static int ext_strncpy(char *dst, const char *src, int len, int nofluff); +static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff); /*! * \internal @@ -6980,32 +6980,51 @@ int ast_async_goto_by_name(const char *channame, const char *context, const char return res; } -/*! \brief copy a string skipping whitespace and dashes */ -static int ext_strncpy(char *dst, const char *src, int len, int nofluff) +/*! + * \internal + * \brief Copy a string skipping whitespace and optionally dashes. + * + * \param dst Destination buffer to copy src string. + * \param src Null terminated string to copy. + * \param dst_size Number of bytes in the dst buffer. + * \param nofluf Nonzero if '-' chars are not copied. + * + * \return Number of bytes written to dst including null terminator. + */ +static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff) { - int count = 0; - int insquares = 0; + unsigned int count; + unsigned int insquares; + unsigned int is_pattern; - while (*src && (count < len - 1)) { + if (!dst_size--) { + /* There really is no dst buffer */ + return 0; + } + + count = 0; + insquares = 0; + is_pattern = *src == '_'; + while (*src && count < dst_size) { if (*src == '[') { - insquares = 1; + if (is_pattern) { + insquares = 1; + } } else if (*src == ']') { insquares = 0; } else if (*src == ' ' && !insquares) { - src++; + ++src; continue; } else if (*src == '-' && !insquares && nofluff) { - src++; + ++src; continue; } - *dst = *src; - dst++; - src++; - count++; + *dst++ = *src++; + ++count; } *dst = '\0'; - return count; + return count + 1; } /*! @@ -7322,10 +7341,10 @@ static int ast_add_extension2_lockopt(struct ast_context *con, p += strlen(label) + 1; } tmp->name = p; - p += ext_strncpy(p, extension, strlen(extension) + 1, 0) + 1; + p += ext_strncpy(p, extension, strlen(extension) + 1, 0); if (exten_fluff) { tmp->exten = p; - p += ext_strncpy(p, extension, strlen(extension) + 1, 1) + 1; + p += ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1); } else { /* no fluff, we don't need a copy. */ tmp->exten = tmp->name; @@ -7335,10 +7354,10 @@ static int ast_add_extension2_lockopt(struct ast_context *con, /* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */ if (callerid) { - p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0) + 1; + p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0); if (callerid_fluff) { tmp->cidmatch = p; - p += ext_strncpy(p, callerid, strlen(callerid) + 1, 1) + 1; + p += ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1); } tmp->matchcid = AST_EXT_MATCHCID_ON; } else { From 1475604effee9c1c864b6004c2e77ec3f1f55b97 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Tue, 14 Mar 2017 07:50:07 -0500 Subject: [PATCH 1121/1578] res_pjsip_endpoint_identifier_ip: Add an option to match requests by header This patch adds a new features to the endpoint identifier module, 'match_header'. When set, inbound requests are matched by a provided SIP header: value pair. This option works in conjunction with the existing 'match' configuration option, such that if any 'match*' attribute matches an inbound request, the request is associated with the specified endpoint. Since this module now identifies by more than just IP address, appropriate renaming of the module and/or variables can be done in a non-release branch. ASTERISK-26863 #close Change-Id: Icfc14835c962f92e35e67bbdb235cf0589de5453 (cherry picked from commit 30f52d79d7fc9ab0b628bef2b61ea515413795a2) --- CHANGES | 22 +++++ ..._add_match_header_attribute_to_identify.py | 21 +++++ res/res_pjsip_endpoint_identifier_ip.c | 94 +++++++++++++++++-- 3 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/465e70e8c337_add_match_header_attribute_to_identify.py diff --git a/CHANGES b/CHANGES index 7de70668ffe..03b2f78bf72 100644 --- a/CHANGES +++ b/CHANGES @@ -89,6 +89,14 @@ pbx_spool --- Functionality changes from Asterisk 14.3.0 to Asterisk 14.4.0 ------------ ------------------------------------------------------------------------------ +AMI +------------------ + * The 'PJSIPShowEndpoint' command's respone event of 'IdentifyDetail' now + contains a new optional parameter, 'MatchHeader', mapping to the new + configuration option 'match_header' for the corresponding 'identify' object. + It should be noted that since 'match_header' takes in a key: value pair, the + event parameter will contain a ':' as well. + app_record ------------------ * Added new 'u' option to Record() application which prevents Asterisk from @@ -118,6 +126,20 @@ res_pjsip_transport_websocket when Asterisk attempts to send SIP requests to do something like initiate call hangup. +res_pjsip_endpoint_identifier_ip +------------------ + * A new option has been added to the 'identify' configuration object, + 'match_header'. The 'match_header' attribute should contain a SIP + header: value pair that, When set, will cause inbound requests that contain + the matching SIP header/value pair to be associated with the corresponding + endpoint. This option is cumulative with the 'match' option, so that if + either option matches the request, the request is associated with the + endpoint. + + In a future release, this module will be renamed to something more + appropriate, as it now matches inbound requests on more than just IP + address. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/contrib/ast-db-manage/config/versions/465e70e8c337_add_match_header_attribute_to_identify.py b/contrib/ast-db-manage/config/versions/465e70e8c337_add_match_header_attribute_to_identify.py new file mode 100644 index 00000000000..343b5cba93e --- /dev/null +++ b/contrib/ast-db-manage/config/versions/465e70e8c337_add_match_header_attribute_to_identify.py @@ -0,0 +1,21 @@ +"""Add match_header attribute to identify + +Revision ID: 465e70e8c337 +Revises: 28ab27a7826d +Create Date: 2017-03-14 08:13:53.986681 + +""" + +# revision identifiers, used by Alembic. +revision = '465e70e8c337' +down_revision = '28ab27a7826d' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoint_id_ips', sa.Column('match_header', sa.String(255))) + +def downgrade(): + op.drop_column('ps_endpoint_id_ips', 'match_header') diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index a7323840172..262bdc5f3e7 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -35,20 +35,33 @@ /*** DOCUMENTATION - Module that identifies endpoints via source IP address + Module that identifies endpoints - Identifies endpoints via source IP address + Identifies endpoints via some criteria. + + This module provides alternatives to matching inbound requests to + a configured endpoint. At least one of the matching mechanisms + must be provided, or the object configuration will be invalid. + If multiple criteria are provided, an inbound request will + be matched if it matches any of the criteria. + The matching mechanisms are provided by the following + configuration options: + + Match by source IP address. + Match by SIP header. + + Name of Endpoint - IP addresses or networks to match against + IP addresses or networks to match against. The value is a comma-delimited list of IP addresses. IP addresses may have a subnet mask appended. The subnet mask may be written in either CIDR or dot-decimal notation. Separate the IP address and subnet - mask with a slash ('/') + mask with a slash ('/'). @@ -58,6 +71,14 @@ hostnames to determine additional addresses that traffic may originate from. + + Header/value pair to match against. + A SIP header who value is used to match against. SIP + requests containing the header, along with the specified value, will be + mapped to the specified endpoint. The header must be specified with a + :, as in match_header = SIPHeader: value. + + Must be of type 'identify'. @@ -77,6 +98,8 @@ struct ip_identify_match { AST_DECLARE_STRING_FIELDS( /*! The name of the endpoint */ AST_STRING_FIELD(endpoint_name); + /*! If matching by header, the header/value to match against */ + AST_STRING_FIELD(match_header); ); /*! \brief Networks or addresses that should match this */ struct ast_ha *matches; @@ -109,7 +132,48 @@ static void *ip_identify_alloc(const char *name) return identify; } -/*! \brief Comparator function for a matching object */ +/*! \brief Comparator function for matching an object by header */ +static int header_identify_match_check(void *obj, void *arg, int flags) +{ + struct ip_identify_match *identify = obj; + struct pjsip_rx_data *rdata = arg; + pjsip_generic_string_hdr *header; + pj_str_t pj_header_name; + pj_str_t pj_header_value; + char *c_header = ast_strdupa(identify->match_header); + char *c_value; + + c_value = strchr(c_header, ':'); + if (!c_value) { + ast_log(LOG_WARNING, "Identify '%s' has invalid header_match: No ':' separator found!\n", + ast_sorcery_object_get_id(identify)); + return 0; + } + *c_value = '\0'; + c_value++; + c_value = ast_strip(c_value); + + pj_header_name = pj_str(c_header); + header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pj_header_name, NULL); + if (!header) { + ast_debug(3, "SIP message does not contain header '%s'\n", c_header); + return 0; + } + + pj_header_value = pj_str(c_value); + if (pj_strcmp(&pj_header_value, &header->hvalue)) { + ast_debug(3, "SIP message contains header '%s' but value '%.*s' does not match value '%s' for endpoint '%s'\n", + c_header, + (int) pj_strlen(&header->hvalue), pj_strbuf(&header->hvalue), + c_value, + identify->endpoint_name); + return 0; + } + + return CMP_MATCH | CMP_STOP; +} + +/*! \brief Comparator function for matching an object by IP address */ static int ip_identify_match_check(void *obj, void *arg, int flags) { struct ip_identify_match *identify = obj; @@ -147,10 +211,14 @@ static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata) ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID); ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port); - if (!(match = ao2_callback(candidates, 0, ip_identify_match_check, &addr))) { - ast_debug(3, "'%s' did not match any identify section rules\n", + match = ao2_callback(candidates, 0, ip_identify_match_check, &addr); + if (!match) { + ast_debug(3, "Identify checks by IP address failed to find match: '%s' did not match any identify section rules\n", ast_sockaddr_stringify(&addr)); - return NULL; + match = ao2_callback(candidates, 0, header_identify_match_check, rdata); + if (!match) { + return NULL; + } } endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", match->endpoint_name); @@ -495,7 +563,7 @@ static int cli_print_header(void *obj, void *arg, int flags) filler = CLI_LAST_TABSTOP - indent - 24; ast_str_append(&context->output_buffer, 0, - "%*s: \n", + "%*s: \n", indent, "Match", filler, filler, CLI_HEADER_FILLER); context->indent_level--; @@ -532,6 +600,13 @@ static int cli_print_body(void *obj, void *arg, int flags) addr, ast_sockaddr_cidr_bits(&match->netmask)); } + if (!ast_strlen_zero(ident->match_header)) { + ast_str_append(&context->output_buffer, 0, "%*s: %s\n", + indent, + "Match", + ident->match_header); + } + context->indent_level--; if (context->indent_level == 0) { @@ -592,6 +667,7 @@ static int load_module(void) ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name)); ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0); + ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "match_header", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, match_header)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "srv_lookups", "yes", OPT_BOOL_T, 1, FLDSET(struct ip_identify_match, srv_lookups)); ast_sorcery_load_object(ast_sip_get_sorcery(), "identify"); From 0b8a57af6d62c19e3ed4b37b06a55484c3a04092 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 15 Mar 2017 13:44:43 +0000 Subject: [PATCH 1122/1578] res_pjsip_endpoint_identifier_ip: Don't output error if no header_match. This change ensures that if no header_match option is set on an identify an error message is not output stating the option is set to an invalid value. ASTERISK-26863 Change-Id: I239bc6d2319dd3da24ba96a38d4d6e9b5526d62a --- res/res_pjsip_endpoint_identifier_ip.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 262bdc5f3e7..30bfc2618c5 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -140,9 +140,14 @@ static int header_identify_match_check(void *obj, void *arg, int flags) pjsip_generic_string_hdr *header; pj_str_t pj_header_name; pj_str_t pj_header_value; - char *c_header = ast_strdupa(identify->match_header); + char *c_header; char *c_value; + if (ast_strlen_zero(identify->match_header)) { + return 0; + } + + c_header = ast_strdupa(identify->match_header); c_value = strchr(c_header, ':'); if (!c_value) { ast_log(LOG_WARNING, "Identify '%s' has invalid header_match: No ':' separator found!\n", From 982d6173c55e67a910fa30e079a1de2cf291c03e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 9 Mar 2017 12:05:12 -0500 Subject: [PATCH 1123/1578] app_queue: Handle the caller being redirected out of a queue bridge A caller can leave the Queue() application after being bridged with a member in a few ways: * Caller or member hangup * Caller is transferred somewhere else (blind or atx) * Caller is externally redirected elsewhere The first 2 scenarios are currently handled by subscribing to stasis messages, but the 3rd is not explicitly covered. If a caller is redirected away from the Queue() application, the member who was last bridged with that caller will remain in an "In use" state until the caller hangs up. This patch adds handling of the caller leaving the queue via redirection. We monitor the caller-member bridge, and if the caller is the one that leaves, we treat it the same as we would a caller hangup. ASTERISK-26400 #close Reported by: Etienne Lessard Change-Id: Iba160907770de5a6c9efeffc9df5a13e9ea75334 --- apps/app_queue.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index 204b4b2deb9..c0de00173e1 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5965,6 +5965,67 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, } } +/*! + * \internal + * \brief Handle a stasis bridge leave event. + * + * We track this event to determine if the caller has left the bridge + * as the result of a redirect. Transfers and hangups are handled in + * separate functions. + * + * \param userdata Data pertaining to the particular call in the queue. + * \param sub The stasis subscription on which the message occurred. + * \param msg The stasis message for the bridge leave event + */ +static void handle_bridge_left(void *userdata, struct stasis_subscription *sub, + struct stasis_message *msg) +{ + struct queue_stasis_data *queue_data = userdata; + struct ast_bridge_blob *left_blob = stasis_message_data(msg); + struct ast_channel_snapshot *caller_snapshot, *member_snapshot; + + ao2_lock(queue_data); + + if (queue_data->dying) { + ao2_unlock(queue_data); + return; + } + + if (ast_strlen_zero(queue_data->bridge_uniqueid)) { + ao2_unlock(queue_data); + return; + } + + /* Correct channel, correct bridge? */ + if (strcmp(left_blob->channel->uniqueid, queue_data->caller_uniqueid) + || strcmp(left_blob->bridge->uniqueid, queue_data->bridge_uniqueid)) { + ao2_unlock(queue_data); + return; + } + + caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid); + member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid); + + ao2_unlock(queue_data); + + ast_debug(3, "Detected redirect of queue caller channel %s\n", + caller_snapshot->name); + + ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, + "COMPLETECALLER", "%ld|%ld|%d", + (long) (queue_data->starttime - queue_data->holdstart), + (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos); + + send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member, + queue_data->holdstart, queue_data->starttime, CALLER); + update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl, + time(NULL) - queue_data->starttime); + remove_stasis_subscriptions(queue_data); + + ao2_cleanup(member_snapshot); + ao2_cleanup(caller_snapshot); +} + /*! * \brief Handle a blind transfer event * @@ -6332,6 +6393,8 @@ static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, str stasis_message_router_add(queue_data->bridge_router, ast_channel_entered_bridge_type(), handle_bridge_enter, queue_data); + stasis_message_router_add(queue_data->bridge_router, ast_channel_left_bridge_type(), + handle_bridge_left, queue_data); stasis_message_router_add(queue_data->bridge_router, ast_blind_transfer_type(), handle_blind_transfer, queue_data); stasis_message_router_add(queue_data->bridge_router, ast_attended_transfer_type(), From dc4cdafd429b1dee46f955c08a48dcb6d0c593cd Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Tue, 14 Mar 2017 14:49:54 +0100 Subject: [PATCH 1124/1578] res/res_pjsip_refer: call xfer w/o extension When transfering to a URI without an extension, ensure that the s extension of the dialplan is entered ASTERISK-26869 #close Change-Id: I07403df66cf93f09e00a40ab5b41bfc6f72b1525 --- res/res_pjsip_refer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index aa2af09333a..0f4a95c77c7 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -822,6 +822,13 @@ static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_r */ AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten); + /* Uri without exten */ + if (ast_strlen_zero(exten)) { + ast_copy_string(exten, "s", sizeof(exten)); + ast_debug(3, "Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s'\n", + ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), context); + } + if (!ast_exists_extension(NULL, context, exten, 1, NULL)) { ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n", ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context); From 10fa49e3275e81860341d5ee5e0b9d15bafd9acd Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 7 Mar 2017 14:13:02 -0600 Subject: [PATCH 1125/1578] Add rtcp-mux support This commit adds support for RFC 5761: Multiplexing RTP Data and Control Packets on a Single Port. Specifically, it enables the feature when using chan_pjsip. A new option, "rtcp_mux" has been added to endpoint configuration in pjsip.conf. If set, then Asterisk will attempt to use rtcp-mux with whatever it communicates with. Asterisk follows the rules set forth in RFC 5761 with regards to falling back to standard RTCP behavior if the far end does not indicate support for rtcp-mux. The lion's share of the changes in this commit are in res_rtp_asterisk.c. This is because it was pretty much hard wired to have an RTP and an RTCP transport. The strategy used here is that when rtcp-mux is enabled, the current RTCP transport and its trappings (such as DTLS SSL session) are freed, and the RTCP session instead just mooches off the RTP session. This leads to a lot of specialized if statements throughout. ASTERISK-26732 #close Reported by Dan Jenkins Change-Id: If46a93ba1282418d2803e3fd7869374da8b77ab5 --- CHANGES | 7 + UPGRADE.txt | 20 +- .../versions/15db7b91a97a_add_rtcp_mux.py | 30 ++ include/asterisk/res_pjsip.h | 2 + include/asterisk/res_pjsip_session.h | 2 + include/asterisk/rtp_engine.h | 11 + res/res_pjsip.c | 10 + res/res_pjsip/pjsip_configuration.c | 1 + res/res_pjsip_sdp_rtp.c | 68 +++- res/res_rtp_asterisk.c | 371 ++++++++++++------ 10 files changed, 395 insertions(+), 127 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py diff --git a/CHANGES b/CHANGES index 03b2f78bf72..4e9df4fa58d 100644 --- a/CHANGES +++ b/CHANGES @@ -140,6 +140,13 @@ res_pjsip_endpoint_identifier_ip appropriate, as it now matches inbound requests on more than just IP address. +res_rtp_asterisk +----------------- + * The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP + Data and Control Packets on a Single Port." So far, the only channel driver + that supports this feature is chan_pjsip. You can set "rtcp_mux = yes" on + a PJSIP endpoint in pjsip.conf to enable the feature. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------ ------------------------------------------------------------------------------ diff --git a/UPGRADE.txt b/UPGRADE.txt index 569cc922274..2275580cabd 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -23,9 +23,23 @@ === UPGRADE-14.txt -- Upgrade info for 13 to 14 =========================================================== -Build System: - - The LOW_MEMORY compile option no longer disables inline API. To disable - inline API you must use the DISABLE_INLINE option. +From 14.3.0 to 14.4.0: + +res_rtp_asterisk: + - The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP + Data and Control Packets on a Single Port." So far, the only channel driver + that supports this feature is chan_pjsip. You can set "rtcp_mux = yes" on + a PJSIP endpoint in pjsip.conf to enable the feature. + +New in 14.0.0 + +ARI: + - The policy for when to send "Dial" events has changed. Previously, "Dial" + events were sent on the calling channel's topic. However, starting in Asterisk + 14, if there is no calling channel on which to send the event, the event is + instead sent on the called channel's topic. Note that for the ARI channels + resource's dial operation, this means that the "Dial" events will always be + sent on the called channel's topic. Queue: - When reloading the members of a queue, the members added dynamically (i.e. diff --git a/contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py b/contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py new file mode 100644 index 00000000000..50d3ee33894 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py @@ -0,0 +1,30 @@ +"""empty message + +Revision ID: 15db7b91a97a +Revises: 465e70e8c337 +Create Date: 2017-03-08 16:56:38.108162 + +""" + +# revision identifiers, used by Alembic. +revision = '15db7b91a97a' +down_revision = '465e70e8c337' + +from alembic import op +import sqlalchemy as sa + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoints', sa.Column('rtcp_mux', yesno_values)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'rtcp_mux') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 09ace0775be..fb045130700 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -676,6 +676,8 @@ struct ast_sip_endpoint_media_configuration { unsigned int g726_non_standard; /*! Bind the RTP instance to the media_address */ unsigned int bind_rtp_to_media_address; + /*! Use RTCP-MUX */ + unsigned int rtcp_mux; }; /*! diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 26dd451a79b..d4d3f705afd 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -85,6 +85,8 @@ struct ast_sip_session_media { unsigned int remotely_held:1; /*! \brief Stream is on hold by local side */ unsigned int locally_held:1; + /*! \brief Does remote support rtcp_mux */ + unsigned int remote_rtcp_mux:1; /*! \brief Stream type this session media handles */ char stream_type[1]; }; diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index c0ae3315572..6544e70a466 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -237,6 +237,15 @@ enum ast_rtp_instance_stat { AST_RTP_INSTANCE_STAT_RXOCTETCOUNT, }; +enum ast_rtp_instance_rtcp { + /*! RTCP should not be sent/received */ + AST_RTP_INSTANCE_RTCP_DISABLED = 0, + /*! RTCP should be sent/received based on standard port rules */ + AST_RTP_INSTANCE_RTCP_STANDARD, + /*! RTCP should be sent/received on the same port as RTP */ + AST_RTP_INSTANCE_RTCP_MUX, +}; + /* Codes for RTP-specific data - not defined by our AST_FORMAT codes */ /*! DTMF (RFC2833) */ #define AST_RTP_DTMF (1 << 0) @@ -447,6 +456,8 @@ struct ast_rtp_engine_ice { void (*turn_request)(struct ast_rtp_instance *instance, enum ast_rtp_ice_component_type component, enum ast_transport transport, const char *server, unsigned int port, const char *username, const char *password); + /*! Callback to alter the number of ICE components on a session */ + void (*change_components)(struct ast_rtp_instance *instance, int num_components); }; /*! \brief DTLS setup types */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index e1800e2deaf..f4df4983640 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -950,6 +950,16 @@ to the receiving one. + + Enable RFC 5761 RTCP multiplexing on the RTP port + + With this option enabled, Asterisk will attempt to negotiate the use of the "rtcp-mux" + attribute on all media streams. This will result in RTP and RTCP being sent and received + on the same port. This shifts the demultiplexing logic to the application rather than + the transport layer. This option is useful when interoperating with WebRTC endpoints + since they mandate this option's use. + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 1111664dc3e..c8ff42708bd 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1937,6 +1937,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index e32d2b65f8d..9f39256e56e 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -169,6 +169,23 @@ static int rtp_check_timeout(const void *data) return 0; } +/*! + * \brief Enable RTCP on an RTP session. + */ +static void enable_rtcp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + const struct pjmedia_sdp_media *remote_media) +{ + enum ast_rtp_instance_rtcp rtcp_type; + + if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux) { + rtcp_type = AST_RTP_INSTANCE_RTCP_MUX; + } else { + rtcp_type = AST_RTP_INSTANCE_RTCP_STANDARD; + } + + ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, rtcp_type); +} + /*! \brief Internal function which creates an RTP instance */ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media) { @@ -186,7 +203,6 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me return -1; } - ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, 1); ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->media.rtp.symmetric); if (!session->endpoint->media.rtp.ice_support && (ice = ast_rtp_instance_get_ice(session_media->rtp))) { @@ -569,6 +585,13 @@ static void process_ice_attributes(struct ast_sip_session *session, struct ast_s continue; } + if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux && candidate.id > 1) { + /* Remote side may have offered RTP and RTCP candidates. However, if we're using RTCP MUX, + * then we should ignore RTCP candidates. + */ + continue; + } + candidate.foundation = foundation; candidate.transport = transport; @@ -865,6 +888,26 @@ static int setup_media_encryption(struct ast_sip_session *session, return 0; } +static void set_ice_components(struct ast_sip_session *session, struct ast_sip_session_media *session_media) +{ + struct ast_rtp_engine_ice *ice; + + ast_assert(session_media->rtp != NULL); + + ice = ast_rtp_instance_get_ice(session_media->rtp); + if (!session->endpoint->media.rtp.ice_support || !ice) { + return; + } + + if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux) { + /* We both support RTCP mux. Only one ICE component necessary */ + ice->change_components(session_media->rtp, 1); + } else { + /* They either don't support RTCP mux or we don't know if they do yet. */ + ice->change_components(session_media->rtp, 2); + } +} + /*! \brief Function which negotiates an incoming media stream */ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream) @@ -909,6 +952,11 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct return -1; } + session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(stream, "rtcp-mux", NULL) != NULL); + set_ice_components(session, session_media); + + enable_rtcp(session, session_media, stream); + res = setup_media_encryption(session, session_media, sdp, stream); if (res) { if (!session->endpoint->media.rtp.encryption_optimistic || @@ -1087,6 +1135,9 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as return -1; } + set_ice_components(session, session_media); + enable_rtcp(session, session_media, NULL); + if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) || !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) { return -1; @@ -1250,6 +1301,12 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as attr->name = !session_media->locally_held ? STR_SENDRECV : STR_SENDONLY; media->attr[media->attr_count++] = attr; + /* If we've got rtcp-mux enabled, just unconditionally offer it in all SDPs */ + if (session->endpoint->media.rtcp_mux) { + attr = pjmedia_sdp_attr_create(pool, "rtcp-mux", NULL); + pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr); + } + /* Add the media stream to the SDP */ sdp->media[sdp->media_count++] = media; @@ -1284,6 +1341,11 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a return -1; } + session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(remote_stream, "rtcp-mux", NULL) != NULL); + set_ice_components(session, session_media); + + enable_rtcp(session, session_media, remote_stream); + res = setup_media_encryption(session, session_media, remote, remote_stream); if (!session->endpoint->media.rtp.encryption_optimistic && res) { /* If optimistic encryption is disabled and crypto should have been enabled but was not @@ -1315,7 +1377,9 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a return -1; } ast_channel_set_fd(session->channel, fdno, ast_rtp_instance_fd(session_media->rtp, 0)); - ast_channel_set_fd(session->channel, fdno + 1, ast_rtp_instance_fd(session_media->rtp, 1)); + if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) { + ast_channel_set_fd(session->channel, fdno + 1, ast_rtp_instance_fd(session_media->rtp, 1)); + } /* If ICE support is enabled find all the needed attributes */ process_ice_attributes(session, session_media, remote, remote_stream); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 28ddeca4206..a67bc8135b4 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -329,6 +329,7 @@ struct ast_rtp { struct ao2_container *ice_active_remote_candidates; /*!< The remote ICE candidates */ struct ao2_container *ice_proposed_remote_candidates; /*!< Incoming remote ICE candidates for new session */ struct ast_sockaddr ice_original_rtp_addr; /*!< rtp address that ICE started on first session */ + unsigned int ice_num_components; /*!< The number of ICE components */ #endif #ifdef HAVE_OPENSSL_SRTP @@ -417,6 +418,9 @@ struct ast_rtcp { * own address every time */ char *local_addr_str; + enum ast_rtp_instance_rtcp type; + /* Buffer for frames created during RTCP interpretation */ + unsigned char frame_buf[512 + AST_FRIENDLY_OFFSET]; }; struct rtp_red { @@ -658,6 +662,22 @@ static int ice_reset_session(struct ast_rtp_instance *instance) pj_ice_sess_change_role(rtp->ice, role); } + /* If we only have one component now, and we previously set up TURN for RTCP, + * we need to destroy that TURN socket. + */ + if (rtp->ice_num_components == 1 && rtp->turn_rtcp) { + struct timeval wait = ast_tvadd(ast_tvnow(), ast_samp2tv(TURN_STATE_WAIT_TIME, 1000)); + struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, }; + + ast_mutex_lock(&rtp->lock); + pj_turn_sock_destroy(rtp->turn_rtcp); + rtp->turn_state = PJ_TURN_STATE_NULL; + while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) { + ast_cond_timedwait(&rtp->cond, &rtp->lock, &ts); + } + ast_mutex_unlock(&rtp->lock); + } + return res; } @@ -773,11 +793,12 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) ast_log(LOG_WARNING, "No RTP candidates; skipping ICE checklist (%p)\n", instance); } - if (!has_rtcp) { + /* If we're only dealing with one ICE component, then we don't care about the lack of RTCP candidates */ + if (!has_rtcp && rtp->ice_num_components > 1) { ast_log(LOG_WARNING, "No RTCP candidates; skipping ICE checklist (%p)\n", instance); } - if (has_rtp && has_rtcp) { + if (has_rtp && (has_rtcp || rtp->ice_num_components == 1)) { pj_status_t res = pj_ice_sess_create_check_list(rtp->ice, &ufrag, &passwd, cand_cnt, &candidates[0]); char reason[80]; @@ -1269,6 +1290,21 @@ static char *generate_random_string(char *buf, size_t size) return buf; } +static void ast_rtp_ice_change_components(struct ast_rtp_instance *instance, int num_components) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + /* Don't do anything if ICE is unsupported or if we're not changing the + * number of components + */ + if (!icesupport || !rtp->ice || rtp->ice_num_components == num_components) { + return; + } + + rtp->ice_num_components = num_components; + ice_reset_session(instance); +} + /* ICE RTP Engine interface declaration */ static struct ast_rtp_engine_ice ast_rtp_ice = { .set_authentication = ast_rtp_ice_set_authentication, @@ -1281,6 +1317,7 @@ static struct ast_rtp_engine_ice ast_rtp_ice = { .ice_lite = ast_rtp_ice_lite, .set_role = ast_rtp_ice_set_role, .turn_request = ast_rtp_ice_turn_request, + .change_components = ast_rtp_ice_change_components, }; #endif @@ -1540,6 +1577,7 @@ static int ast_rtp_dtls_active(struct ast_rtp_instance *instance) static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + int rtcp_dtls_unique = (rtp->dtls.ssl != rtp->rtcp->dtls.ssl); dtls_srtp_stop_timeout_timer(instance, rtp, 0); @@ -1557,7 +1595,7 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) if (rtp->rtcp) { dtls_srtp_stop_timeout_timer(instance, rtp, 1); - if (rtp->rtcp->dtls.ssl) { + if (rtp->rtcp->dtls.ssl && rtcp_dtls_unique) { SSL_free(rtp->rtcp->dtls.ssl); rtp->rtcp->dtls.ssl = NULL; ast_mutex_destroy(&rtp->rtcp->dtls.lock); @@ -1785,7 +1823,7 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) #ifdef HAVE_OPENSSL_SRTP dtls_perform_handshake(instance, &rtp->dtls, 0); - if (rtp->rtcp) { + if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); } #endif @@ -2025,7 +2063,7 @@ static int dtls_srtp_renegotiate(const void *data) SSL_do_handshake(rtp->dtls.ssl); dtls_srtp_check_pending(instance, rtp, 0); - if (rtp->rtcp && rtp->rtcp->dtls.ssl) { + if (rtp->rtcp && rtp->rtcp->dtls.ssl && rtp->rtcp->dtls.ssl != rtp->dtls.ssl) { SSL_renegotiate(rtp->rtcp->dtls.ssl); SSL_do_handshake(rtp->rtcp->dtls.ssl); dtls_srtp_check_pending(instance, rtp, 1); @@ -2616,7 +2654,7 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad passwd = pj_str(rtp->local_passwd); /* Create an ICE session for ICE negotiation */ - if (pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, 2, + if (pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, rtp->ice_num_components, &ast_rtp_ice_sess_cb, &ufrag, &passwd, NULL, &rtp->ice) == PJ_SUCCESS) { /* Make this available for the callbacks */ rtp->ice->user_data = instance; @@ -2625,9 +2663,10 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad rtp_add_candidates_to_ice(instance, rtp, addr, port, AST_RTP_ICE_COMPONENT_RTP, TRANSPORT_SOCKET_RTP); - /* Only add the RTCP candidates to ICE when replacing the session. New sessions + /* Only add the RTCP candidates to ICE when replacing the session and if + * the ICE session contains more than just an RTP component. New sessions * handle this in a separate part of the setup phase */ - if (replace && rtp->rtcp) { + if (replace && rtp->rtcp && rtp->ice_num_components > 1) { rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_SOCKET_RTCP); @@ -2712,6 +2751,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, #ifdef HAVE_PJPROJECT /* Create an ICE session for ICE negotiation */ if (icesupport) { + rtp->ice_num_components = 2; ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(addr), x, instance); if (ice_create(instance, addr, x, 0)) { ast_log(LOG_NOTICE, "Failed to start ICE session\n"); @@ -2721,7 +2761,6 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, } } #endif - /* Record any information we may need */ rtp->sched = sched; @@ -4150,63 +4189,21 @@ static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets) rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current; } -static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) +static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct ast_sockaddr addr; - unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET]; - unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET); - int res, packetwords, position = 0; + unsigned int *rtcpheader = (unsigned int *)(rtcpdata); + int packetwords, position = 0; int report_counter = 0; struct ast_rtp_rtcp_report_block *report_block; struct ast_frame *f = &ast_null_frame; - /* Read in RTCP data from the socket */ - if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET, - sizeof(rtcpdata) - AST_FRIENDLY_OFFSET, - 0, &addr)) < 0) { - ast_assert(errno != EBADF); - if (errno != EAGAIN) { - ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n", - (errno) ? strerror(errno) : "Unspecified"); - return NULL; - } - return &ast_null_frame; - } - - /* If this was handled by the ICE session don't do anything further */ - if (!res) { - return &ast_null_frame; - } - - if (!*(rtcpdata + AST_FRIENDLY_OFFSET)) { - struct sockaddr_in addr_tmp; - struct ast_sockaddr addr_v4; - - if (ast_sockaddr_is_ipv4(&addr)) { - ast_sockaddr_to_sin(&addr, &addr_tmp); - } else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) { - ast_debug(1, "Using IPv6 mapped address %s for STUN\n", - ast_sockaddr_stringify(&addr)); - ast_sockaddr_to_sin(&addr_v4, &addr_tmp); - } else { - ast_debug(1, "Cannot do STUN for non IPv4 address %s\n", - ast_sockaddr_stringify(&addr)); - return &ast_null_frame; - } - if ((ast_stun_handle_packet(rtp->rtcp->s, &addr_tmp, rtcpdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT)) { - ast_sockaddr_from_sin(&addr, &addr_tmp); - ast_sockaddr_copy(&rtp->rtcp->them, &addr); - } - return &ast_null_frame; - } - - packetwords = res / 4; + packetwords = size / 4; if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { /* Send to whoever sent to us */ - if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) { - ast_sockaddr_copy(&rtp->rtcp->them, &addr); + if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) { + ast_sockaddr_copy(&rtp->rtcp->them, addr); if (rtpdebug) { ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", ast_sockaddr_stringify(&rtp->rtcp->them)); @@ -4214,7 +4211,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) } } - ast_debug(1, "Got RTCP report of %d bytes\n", res); + ast_debug(1, "Got RTCP report of %zu bytes\n", size); while (position < packetwords) { int i, pt, rc; @@ -4242,9 +4239,9 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) return &ast_null_frame; } - if (rtcp_debug_test_addr(&addr)) { + if (rtcp_debug_test_addr(addr)) { ast_verbose("\n\nGot RTCP from %s\n", - ast_sockaddr_stringify(&addr)); + ast_sockaddr_stringify(addr)); ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" : (pt == RTCP_PT_RR) ? "Receiver Report" : (pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown"); @@ -4267,7 +4264,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) (unsigned int)ntohl(rtcpheader[i + 1]), &rtcp_report->sender_information.ntp_timestamp); rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]); - if (rtcp_debug_test_addr(&addr)) { + if (rtcp_debug_test_addr(addr)) { ast_verbose("NTP timestamp: %u.%06u\n", (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec, (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec); @@ -4299,7 +4296,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) report_block->dlsr = ntohl(rtcpheader[i + 5]); if (report_block->lsr && update_rtt_stats(rtp, report_block->lsr, report_block->dlsr) - && rtcp_debug_test_addr(&addr)) { + && rtcp_debug_test_addr(addr)) { struct timeval now; unsigned int lsr_now, lsw, msw; gettimeofday(&now, NULL); @@ -4316,7 +4313,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) update_lost_stats(rtp, report_block->lost_count.packets); rtp->rtcp->reported_jitter_count++; - if (rtcp_debug_test_addr(&addr)) { + if (rtcp_debug_test_addr(addr)) { ast_verbose(" Fraction lost: %d\n", report_block->lost_count.fraction); ast_verbose(" Packets lost so far: %u\n", report_block->lost_count.packets); ast_verbose(" Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff); @@ -4344,7 +4341,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) /* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report * object as a its data */ rtp->f.frametype = AST_FRAME_RTCP; - rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET; + rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET; memcpy(rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report)); rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report); if (rc > 0) { @@ -4367,7 +4364,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) case RTCP_PT_FUR: /* Handle RTCP FIR as FUR */ case RTCP_PT_PSFB: - if (rtcp_debug_test_addr(&addr)) { + if (rtcp_debug_test_addr(addr)) { ast_verbose("Received an RTCP Fast Update Request\n"); } rtp->f.frametype = AST_FRAME_CONTROL; @@ -4379,13 +4376,13 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) f = &rtp->f; break; case RTCP_PT_SDES: - if (rtcp_debug_test_addr(&addr)) { + if (rtcp_debug_test_addr(addr)) { ast_verbose("Received an SDES from %s\n", ast_sockaddr_stringify(&rtp->rtcp->them)); } break; case RTCP_PT_BYE: - if (rtcp_debug_test_addr(&addr)) { + if (rtcp_debug_test_addr(addr)) { ast_verbose("Received a BYE from %s\n", ast_sockaddr_stringify(&rtp->rtcp->them)); } @@ -4400,6 +4397,58 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) rtp->rtcp->rtcp_info = 1; return f; + +} + +static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct ast_sockaddr addr; + unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET]; + unsigned char *read_area = rtcpdata + AST_FRIENDLY_OFFSET; + size_t read_area_size = sizeof(rtcpdata) - AST_FRIENDLY_OFFSET; + int res; + + /* Read in RTCP data from the socket */ + if ((res = rtcp_recvfrom(instance, read_area, read_area_size, + 0, &addr)) < 0) { + ast_assert(errno != EBADF); + if (errno != EAGAIN) { + ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n", + (errno) ? strerror(errno) : "Unspecified"); + return NULL; + } + return &ast_null_frame; + } + + /* If this was handled by the ICE session don't do anything further */ + if (!res) { + return &ast_null_frame; + } + + if (!*(read_area)) { + struct sockaddr_in addr_tmp; + struct ast_sockaddr addr_v4; + + if (ast_sockaddr_is_ipv4(&addr)) { + ast_sockaddr_to_sin(&addr, &addr_tmp); + } else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) { + ast_debug(1, "Using IPv6 mapped address %s for STUN\n", + ast_sockaddr_stringify(&addr)); + ast_sockaddr_to_sin(&addr_v4, &addr_tmp); + } else { + ast_debug(1, "Cannot do STUN for non IPv4 address %s\n", + ast_sockaddr_stringify(&addr)); + return &ast_null_frame; + } + if ((ast_stun_handle_packet(rtp->rtcp->s, &addr_tmp, read_area, res, NULL, NULL) == AST_STUN_ACCEPT)) { + ast_sockaddr_from_sin(&addr, &addr_tmp); + ast_sockaddr_copy(&rtp->rtcp->them, &addr); + } + return &ast_null_frame; + } + + return ast_rtcp_interpret(instance, read_area, read_area_size, &addr); } static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int *rtpheader, int len, int hdrlen) @@ -4507,19 +4556,54 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int return 0; } +static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet) +{ + uint8_t version; + uint8_t pt; + uint8_t m; + + if (!rtp->rtcp || rtp->rtcp->type != AST_RTP_INSTANCE_RTCP_MUX) { + return 0; + } + + version = (packet[0] & 0XC0) >> 6; + if (version == 0) { + /* version 0 indicates this is a STUN packet and shouldn't + * be interpreted as a possible RTCP packet + */ + return 0; + } + + /* The second octet of a packet will be one of the following: + * For RTP: The marker bit (1 bit) and the RTP payload type (7 bits) + * For RTCP: The payload type (8) + * + * RTP has a forbidden range of payload types (64-95) since these + * will conflict with RTCP payload numbers if the marker bit is set. + */ + m = packet[1] & 0x80; + pt = packet[1] & 0x7F; + if (m && pt >= 64 && pt <= 95) { + return 1; + } + return 0; +} + static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_sockaddr addr; int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno; - unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp; + unsigned char *read_area = rtp->rawdata + AST_FRIENDLY_OFFSET; + size_t read_area_size = sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET; + unsigned int *rtpheader = (unsigned int*)(read_area), seqno, ssrc, timestamp; RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup); struct ast_sockaddr remote_address = { {0,} }; struct frame_list frames; /* If this is actually RTCP let's hop on over and handle it */ if (rtcp) { - if (rtp->rtcp) { + if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { return ast_rtcp_read(instance); } return &ast_null_frame; @@ -4531,8 +4615,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } /* Actually read in the data from the socket */ - if ((res = rtp_recvfrom(instance, rtp->rawdata + AST_FRIENDLY_OFFSET, - sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0, + if ((res = rtp_recvfrom(instance, read_area, read_area_size, 0, &addr)) < 0) { ast_assert(errno != EBADF); if (errno != EAGAIN) { @@ -4548,12 +4631,17 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc return &ast_null_frame; } + /* This could be a multiplexed RTCP packet. If so, be sure to interpret it correctly */ + if (rtcp_mux(rtp, read_area)) { + return ast_rtcp_interpret(instance, read_area, read_area_size, &addr); + } + /* Make sure the data that was read in is actually enough to make up an RTP packet */ if (res < hdrlen) { /* If this is a keepalive containing only nulls, don't bother with a warning */ int i; for (i = 0; i < res; ++i) { - if (rtp->rawdata[AST_FRIENDLY_OFFSET + i] != '\0') { + if (read_area[i] != '\0') { ast_log(LOG_WARNING, "RTP Read too short\n"); return &ast_null_frame; } @@ -4580,7 +4668,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc ast_sockaddr_stringify(&addr)); return &ast_null_frame; } - if ((ast_stun_handle_packet(rtp->s, &addr_tmp, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT) && + if ((ast_stun_handle_packet(rtp->s, &addr_tmp, read_area, res, NULL, NULL) == AST_STUN_ACCEPT) && ast_sockaddr_isnull(&remote_address)) { ast_sockaddr_from_sin(&addr, &addr_tmp); ast_rtp_instance_set_remote_address(instance, &addr); @@ -4629,7 +4717,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* do not update the originally given address, but only the remote */ ast_rtp_instance_set_incoming_source_address(instance, &addr); ast_sockaddr_copy(&remote_address, &addr); - if (rtp->rtcp) { + if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { ast_sockaddr_copy(&rtp->rtcp->them, &addr); ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(&addr) + 1); } @@ -4696,7 +4784,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* Remove any padding bytes that may be present */ if (padding) { - res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1]; + res -= read_area[res - 1]; } /* Skip over any CSRC fields */ @@ -4770,11 +4858,11 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc * by passing the pointer to the frame list to it so that the method * can append frames to the list as needed. */ - process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames); + process_dtmf_rfc2833(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames); } else if (payload->rtp_code == AST_RTP_CISCO_DTMF) { - f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); + f = process_dtmf_cisco(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); } else if (payload->rtp_code == AST_RTP_CN) { - f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); + f = process_cn_rfc3389(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); } else { ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, @@ -4830,7 +4918,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->f.src = "RTP"; rtp->f.mallocd = 0; rtp->f.datalen = res - hdrlen; - rtp->f.data.ptr = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET; + rtp->f.data.ptr = read_area + hdrlen; rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET; rtp->f.seqno = seqno; @@ -4941,19 +5029,29 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro if (value) { struct ast_sockaddr local_addr; - if (rtp->rtcp) { + if (rtp->rtcp && rtp->rtcp->type == value) { ast_debug(1, "Ignoring duplicate RTCP property on RTP instance '%p'\n", instance); return; } - /* Setup RTCP to be activated on the next RTP write */ - if (!(rtp->rtcp = ast_calloc(1, sizeof(*rtp->rtcp)))) { - return; + + if (!rtp->rtcp) { + rtp->rtcp = ast_calloc(1, sizeof(*rtp->rtcp)); + if (!rtp->rtcp) { + return; + } + rtp->rtcp->s = -1; + rtp->rtcp->dtls.timeout_timer = -1; + rtp->rtcp->schedid = -1; } + rtp->rtcp->type = value; + /* Grab the IP address and port we are going to use */ ast_rtp_instance_get_local_address(instance, &rtp->rtcp->us); - ast_sockaddr_set_port(&rtp->rtcp->us, - ast_sockaddr_port(&rtp->rtcp->us) + 1); + if (value == AST_RTP_INSTANCE_RTCP_STANDARD) { + ast_sockaddr_set_port(&rtp->rtcp->us, + ast_sockaddr_port(&rtp->rtcp->us) + 1); + } ast_sockaddr_copy(&local_addr, &rtp->rtcp->us); if (!ast_find_ourip(&local_addr, &rtp->rtcp->us, 0)) { @@ -4963,6 +5061,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro ast_sockaddr_copy(&local_addr, &rtp->rtcp->us); } + ast_free(rtp->rtcp->local_addr_str); rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local_addr)); if (!rtp->rtcp->local_addr_str) { ast_free(rtp->rtcp); @@ -4970,43 +5069,67 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro return; } - if ((rtp->rtcp->s = - create_new_socket("RTCP", - ast_sockaddr_is_ipv4(&rtp->rtcp->us) ? - AF_INET : - ast_sockaddr_is_ipv6(&rtp->rtcp->us) ? - AF_INET6 : -1)) < 0) { - ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance); - ast_free(rtp->rtcp->local_addr_str); - ast_free(rtp->rtcp); - rtp->rtcp = NULL; - return; - } - - /* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */ - if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) { - ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance); - close(rtp->rtcp->s); - ast_free(rtp->rtcp->local_addr_str); - ast_free(rtp->rtcp); - rtp->rtcp = NULL; - return; - } - - ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance); - rtp->rtcp->schedid = -1; + if (value == AST_RTP_INSTANCE_RTCP_STANDARD) { + /* We're either setting up RTCP from scratch or + * switching from MUX. Either way, we won't have + * a socket set up, and we need to set it up + */ + if ((rtp->rtcp->s = + create_new_socket("RTCP", + ast_sockaddr_is_ipv4(&rtp->rtcp->us) ? + AF_INET : + ast_sockaddr_is_ipv6(&rtp->rtcp->us) ? + AF_INET6 : -1)) < 0) { + ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance); + ast_free(rtp->rtcp->local_addr_str); + ast_free(rtp->rtcp); + rtp->rtcp = NULL; + return; + } + /* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */ + if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) { + ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance); + close(rtp->rtcp->s); + ast_free(rtp->rtcp->local_addr_str); + ast_free(rtp->rtcp); + rtp->rtcp = NULL; + return; + } #ifdef HAVE_PJPROJECT - if (rtp->ice) { - rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_SOCKET_RTCP); - } + if (rtp->ice) { + rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_SOCKET_RTCP); + } #endif - #ifdef HAVE_OPENSSL_SRTP - rtp->rtcp->dtls.timeout_timer = -1; - dtls_setup_rtcp(instance); + dtls_setup_rtcp(instance); #endif + } else { + struct ast_sockaddr addr; + /* RTCPMUX uses the same socket as RTP. If we were previously using standard RTCP + * then close the socket we previously created. + * + * It may seem as though there is a possible race condition here where we might try + * to close the RTCP socket while it is being used to send data. However, this is not + * a problem in practice since setting and adjusting of RTCP properties happens prior + * to activating RTP. It is not until RTP is activated that timers start for RTCP + * transmission + */ + if (rtp->rtcp->s > -1) { + close(rtp->rtcp->s); + } + rtp->rtcp->s = rtp->s; + ast_rtp_instance_get_remote_address(instance, &addr); + ast_sockaddr_copy(&rtp->rtcp->them, &addr); +#ifdef HAVE_OPENSSL_SRTP + if (rtp->rtcp->dtls.ssl) { + SSL_free(rtp->rtcp->dtls.ssl); + } + rtp->rtcp->dtls.ssl = rtp->dtls.ssl; +#endif + } + ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance); return; } else { if (rtp->rtcp) { @@ -5021,9 +5144,11 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro } rtp->rtcp->schedid = -1; } - close(rtp->rtcp->s); + if (rtp->rtcp->s > -1 && rtp->rtcp->s != rtp->s) { + close(rtp->rtcp->s); + } #ifdef HAVE_OPENSSL_SRTP - if (rtp->rtcp->dtls.ssl) { + if (rtp->rtcp->dtls.ssl && rtp->rtcp->dtls.ssl != rtp->dtls.ssl) { SSL_free(rtp->rtcp->dtls.ssl); } #endif @@ -5065,10 +5190,12 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance); ast_sockaddr_copy(&rtp->rtcp->them, addr); if (!ast_sockaddr_isnull(addr)) { - ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1); + if (rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { + ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1); - /* Update the local RTCP address with what is being used */ - ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1); + /* Update the local RTCP address with what is being used */ + ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1); + } ast_sockaddr_copy(&rtp->rtcp->us, &local); ast_free(rtp->rtcp->local_addr_str); @@ -5356,7 +5483,7 @@ static int ast_rtp_activate(struct ast_rtp_instance *instance) dtls_perform_handshake(instance, &rtp->dtls, 0); - if (rtp->rtcp) { + if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); } From c87e7dd9ec01b0e0cfcbd3a2c2207b924201813e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 15 Mar 2017 13:24:33 -0500 Subject: [PATCH 1126/1578] autochan/mixmonitor/chanspy: Fix unsafe channel locking and references. Dereferencing struct ast_autochan.chan without first calling ast_autochan_channel_lock() is unsafe because the pointer could change at any time due to a masquerade. Unfortunately, ast_autochan_channel_lock() itself uses struct ast_autochan.chan unsafely and can result in a deadlock if the original channel happens to get destroyed after a masquerade in addition to the pointer getting changed. The problem is more likely to happen with v11 and earlier because masquerades are used to optimize out local channels on those versions. However, it could still happen on newer versions if the channel is executing a dialplan application when the channel is transferred or redirected. In this situation a masquerade still must be used. * Added a lock to struct ast_autochan to safely be able to use ast_autochan.chan while trying to get the channel lock in ast_autochan_channel_lock(). The locking order is the channel lock then the autochan lock. Locking in the other direction requires deadlock avoidance. * Fix unsafe ast_autochan.chan usages in app_mixmonitor.c. * Fix unsafe ast_autochan.chan usages in app_chanspy.c. * app_chanspy.c: Removed unused autochan parameter from next_channel(). ASTERISK-26867 Change-Id: Id29dd22bc0f369b44e23ca423d2f3657187cc592 --- apps/app_chanspy.c | 67 ++++++++++++++++++++++++++----------- apps/app_mixmonitor.c | 21 ++++++++---- include/asterisk/autochan.h | 20 +++++++---- main/autochan.c | 16 ++++++--- 4 files changed, 88 insertions(+), 36 deletions(-) diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 50d8d63210e..4814f4ce5db 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -506,18 +506,24 @@ static struct ast_generator spygen = { static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags) { + int res; + + ast_autochan_channel_lock(autochan); ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan)); - if(ast_test_flag(flags, OPTION_READONLY)) { + + if (ast_test_flag(flags, OPTION_READONLY)) { ast_set_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE); } else { ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); } - if(ast_test_flag(flags, OPTION_LONG_QUEUE)) { + if (ast_test_flag(flags, OPTION_LONG_QUEUE)) { ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n"); } else { ast_set_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE); } - return ast_audiohook_attach(autochan->chan, audiohook); + res = ast_audiohook_attach(autochan->chan, audiohook); + ast_autochan_channel_unlock(autochan); + return res; } static void change_spy_mode(const char digit, struct ast_flags *flags) @@ -601,8 +607,14 @@ static int attach_barge(struct ast_autochan *spyee_autochan, { int retval = 0; struct ast_autochan *internal_bridge_autochan; - RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(spyee_autochan->chan), ast_channel_cleanup); + struct ast_channel *spyee_chan; + RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup); + ast_autochan_channel_lock(spyee_autochan); + spyee_chan = ast_channel_ref(spyee_autochan->chan); + ast_autochan_channel_unlock(spyee_autochan); + bridged = ast_channel_bridge_peer(spyee_chan); + ast_channel_unref(spyee_chan); if (!bridged) { return -1; } @@ -614,12 +626,10 @@ static int attach_barge(struct ast_autochan *spyee_autochan, return -1; } - ast_autochan_channel_lock(internal_bridge_autochan); if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) { ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name); retval = -1; } - ast_autochan_channel_unlock(internal_bridge_autochan); *spyee_bridge_autochan = internal_bridge_autochan; @@ -639,21 +649,25 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto struct ast_autochan *spyee_bridge_autochan = NULL; const char *spyer_name; - if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) || - ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) { + ast_channel_lock(chan); + if (ast_check_hangup(chan)) { + ast_channel_unlock(chan); return 0; } - - ast_channel_lock(chan); spyer_name = ast_strdupa(ast_channel_name(chan)); ast_channel_unlock(chan); ast_autochan_channel_lock(spyee_autochan); + if (ast_check_hangup(spyee_autochan->chan) + || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) { + ast_autochan_channel_unlock(spyee_autochan); + return 0; + } name = ast_strdupa(ast_channel_name(spyee_autochan->chan)); - ast_autochan_channel_unlock(spyee_autochan); ast_verb(2, "Spying on channel %s\n", name); publish_chanspy_message(chan, spyee_autochan->chan, 1); + ast_autochan_channel_unlock(spyee_autochan); memset(&csth, 0, sizeof(csth)); ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL); @@ -845,7 +859,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto } static struct ast_autochan *next_channel(struct ast_channel_iterator *iter, - struct ast_autochan *autochan, struct ast_channel *chan) + struct ast_channel *chan) { struct ast_channel *next; struct ast_autochan *autochan_store; @@ -982,11 +996,12 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, waitms = 100; num_spyed_upon = 0; - for (autochan = next_channel(iter, autochan, chan); - autochan; - prev = autochan->chan, ast_autochan_destroy(autochan), - autochan = next_autochan ? next_autochan : - next_channel(iter, autochan, chan), next_autochan = NULL) { + for (autochan = next_channel(iter, chan); + autochan; + prev = autochan->chan, + ast_autochan_destroy(autochan), + autochan = next_autochan ?: next_channel(iter, chan), + next_autochan = NULL) { int igrp = !mygroup; int ienf = !myenforced; @@ -1000,13 +1015,19 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, break; } - if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_channel_is_bridged(autochan->chan)) { + ast_autochan_channel_lock(autochan); + if (ast_test_flag(flags, OPTION_BRIDGED) + && !ast_channel_is_bridged(autochan->chan)) { + ast_autochan_channel_unlock(autochan); continue; } - if (ast_check_hangup(autochan->chan) || ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_SPYING)) { + if (ast_check_hangup(autochan->chan) + || ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_SPYING)) { + ast_autochan_channel_unlock(autochan); continue; } + ast_autochan_channel_unlock(autochan); if (mygroup) { int num_groups = 0; @@ -1024,11 +1045,13 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable * rather than "SPYGROUP", this check is done to preserve expected behavior */ + ast_autochan_channel_lock(autochan); if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) { group = pbx_builtin_getvar_helper(autochan->chan, "GROUP"); } else { group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"); } + ast_autochan_channel_unlock(autochan); if (!ast_strlen_zero(group)) { ast_copy_string(dup_group, group, sizeof(dup_group)); @@ -1056,7 +1079,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); + ast_autochan_channel_lock(autochan); ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1); + ast_autochan_channel_unlock(autochan); if ((end = strchr(ext, '-'))) { *end++ = ':'; *end = '\0'; @@ -1078,7 +1103,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, char *ptr, *s; strcpy(peer_name, "spy-"); + ast_autochan_channel_lock(autochan); strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1); + ast_autochan_channel_unlock(autochan); if ((ptr = strchr(peer_name, '/'))) { *ptr++ = '\0'; for (s = peer_name; s < ptr; s++) { @@ -1143,12 +1170,14 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, next = ast_channel_unref(next); } else { /* stay on this channel, if it is still valid */ + ast_autochan_channel_lock(autochan); if (!ast_check_hangup(autochan->chan)) { next_autochan = ast_autochan_setup(autochan->chan); } else { /* the channel is gone */ next_autochan = NULL; } + ast_autochan_channel_unlock(autochan); } } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) { ast_autochan_destroy(autochan); diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index a5a00cc4efc..3258b301fa0 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -617,6 +617,16 @@ static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, } } +static int mixmonitor_autochan_is_bridged(struct ast_autochan *autochan) +{ + int is_bridged; + + ast_autochan_channel_lock(autochan); + is_bridged = ast_channel_is_bridged(autochan->chan); + ast_autochan_channel_unlock(autochan); + return is_bridged; +} + static void *mixmonitor_thread(void *obj) { struct mixmonitor *mixmonitor = obj; @@ -674,8 +684,7 @@ static void *mixmonitor_thread(void *obj) ast_audiohook_unlock(&mixmonitor->audiohook); if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) - || (mixmonitor->autochan->chan - && ast_channel_is_bridged(mixmonitor->autochan->chan))) { + || mixmonitor_autochan_is_bridged(mixmonitor->autochan)) { ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); /* Write out the frame(s) */ @@ -724,11 +733,11 @@ static void *mixmonitor_thread(void *obj) ast_audiohook_unlock(&mixmonitor->audiohook); - ast_autochan_channel_lock(mixmonitor->autochan); if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) { + ast_autochan_channel_lock(mixmonitor->autochan); ast_stream_and_wait(mixmonitor->autochan->chan, "beep", ""); + ast_autochan_channel_unlock(mixmonitor->autochan); } - ast_autochan_channel_unlock(mixmonitor->autochan); ast_autochan_destroy(mixmonitor->autochan); @@ -800,11 +809,11 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel return -1; } - ast_autochan_channel_lock(mixmonitor->autochan); if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) { + ast_autochan_channel_lock(mixmonitor->autochan); ast_stream_and_wait(mixmonitor->autochan->chan, "beep", ""); + ast_autochan_channel_unlock(mixmonitor->autochan); } - ast_autochan_channel_unlock(mixmonitor->autochan); mixmonitor_ds->samp_rate = 8000; mixmonitor_ds->audiohook = &mixmonitor->audiohook; diff --git a/include/asterisk/autochan.h b/include/asterisk/autochan.h index 319c203ab15..128377b57bf 100644 --- a/include/asterisk/autochan.h +++ b/include/asterisk/autochan.h @@ -32,6 +32,7 @@ struct ast_autochan { struct ast_channel *chan; AST_LIST_ENTRY(ast_autochan) list; + ast_mutex_t lock; }; /*! @@ -61,19 +62,24 @@ struct ast_autochan { * ast_autochan_channel_lock and ast_autochan_channel_unlock. An attempt to lock * the autochan->chan directly may result in it being changed after you've * retrieved the value of chan, but before you've had a chance to lock it. - * First when chan is locked, the autochan structure is guaranteed to keep the + * While chan is locked, the autochan structure is guaranteed to keep the * same channel. */ +/*! + * \brief Lock the autochan's channel lock. + * + * \note We must do deadlock avoidance because the channel lock is + * superior to the autochan lock in locking order. + */ #define ast_autochan_channel_lock(autochan) \ do { \ - struct ast_channel *autochan_chan = autochan->chan; \ - ast_channel_lock(autochan_chan); \ - if (autochan->chan == autochan_chan) { \ - break; \ + ast_mutex_lock(&(autochan)->lock); \ + while (ast_channel_trylock((autochan)->chan)) { \ + DEADLOCK_AVOIDANCE(&(autochan)->lock); \ } \ - ast_channel_unlock(autochan_chan); \ - } while (1) + ast_mutex_unlock(&(autochan)->lock); \ + } while (0) #define ast_autochan_channel_unlock(autochan) \ ast_channel_unlock(autochan->chan) diff --git a/main/autochan.c b/main/autochan.c index c7e5c004258..68aeaf804ae 100644 --- a/main/autochan.c +++ b/main/autochan.c @@ -46,15 +46,18 @@ struct ast_autochan *ast_autochan_setup(struct ast_channel *chan) if (!(autochan = ast_calloc(1, sizeof(*autochan)))) { return NULL; } + ast_mutex_init(&autochan->lock); autochan->chan = ast_channel_ref(chan); - ast_channel_lock(autochan->chan); /* autochan is still private, no need for ast_autochan_channel_lock() */ + ast_debug(1, "Created autochan %p to hold channel %s (%p)\n", + autochan, ast_channel_name(chan), chan); + + /* autochan is still private, no need for ast_autochan_channel_lock() */ + ast_channel_lock(autochan->chan); AST_LIST_INSERT_TAIL(ast_channel_autochans(autochan->chan), autochan, list); ast_channel_unlock(autochan->chan); - ast_debug(1, "Created autochan %p to hold channel %s (%p)\n", autochan, ast_channel_name(chan), chan); - return autochan; } @@ -75,6 +78,8 @@ void ast_autochan_destroy(struct ast_autochan *autochan) autochan->chan = ast_channel_unref(autochan->chan); + ast_mutex_destroy(&autochan->lock); + ast_free(autochan); } @@ -84,13 +89,16 @@ void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel * AST_LIST_APPEND_LIST(ast_channel_autochans(new_chan), ast_channel_autochans(old_chan), list); + /* Deadlock avoidance is not needed since the channels are already locked. */ AST_LIST_TRAVERSE(ast_channel_autochans(new_chan), autochan, list) { + ast_mutex_lock(&autochan->lock); if (autochan->chan == old_chan) { - autochan->chan = ast_channel_unref(old_chan); autochan->chan = ast_channel_ref(new_chan); + ast_channel_unref(old_chan); ast_debug(1, "Autochan %p used to hold channel %s (%p) but now holds channel %s (%p)\n", autochan, ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan); } + ast_mutex_unlock(&autochan->lock); } } From 68749a9fa7247497063c036f5a8a9a658daef2e6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 16 Mar 2017 14:07:55 +0000 Subject: [PATCH 1127/1578] res_rtp_asterisk: Fix crash when RTCP is not present when DTLS is stopped. This change removes an assumption that when DTLS is stopped an RTCP session will be present on the RTP session. This is not always the case. ASTERISK-26732 Change-Id: Ib9f7c09ce0b005efe362dbcc8795202b18f94611 --- res/res_rtp_asterisk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index a67bc8135b4..ca614707a66 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1577,7 +1577,7 @@ static int ast_rtp_dtls_active(struct ast_rtp_instance *instance) static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - int rtcp_dtls_unique = (rtp->dtls.ssl != rtp->rtcp->dtls.ssl); + SSL *ssl = rtp->dtls.ssl; dtls_srtp_stop_timeout_timer(instance, rtp, 0); @@ -1595,7 +1595,7 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) if (rtp->rtcp) { dtls_srtp_stop_timeout_timer(instance, rtp, 1); - if (rtp->rtcp->dtls.ssl && rtcp_dtls_unique) { + if (rtp->rtcp->dtls.ssl && (rtp->rtcp->dtls.ssl != ssl)) { SSL_free(rtp->rtcp->dtls.ssl); rtp->rtcp->dtls.ssl = NULL; ast_mutex_destroy(&rtp->rtcp->dtls.lock); From 5013d8f5d31153c243e4a426bd0720e08be3ddc4 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 7 Mar 2017 07:33:26 -0700 Subject: [PATCH 1128/1578] res_pjsip: Symmetric transports A new transport parameter 'symmetric_transport' has been added. When a request from a dynamic contact comes in on a transport with this option set to 'yes', the transport name will be saved and used for subsequent outgoing requests like OPTIONS, NOTIFY and INVITE. It's saved as a contact uri parameter named 'x-ast-txp' and will display with the contact uri in CLI, AMI, and ARI output. On the outgoing request, if a transport wasn't explicitly set on the endpoint AND the request URI is not a hostname, the saved transport will be used and the 'x-ast-txp' parameter stripped from the outgoing packet. * config_transport was modified to accept and store the new parameter. * config_transport/transport_apply was updated to store the transport name in the pjsip_transport->info field using the pjsip_transport->pool on UDP transports. * A 'multihomed_on_rx_message' function was added to pjsip_message_ip_updater that, for incoming requests, retrieves the transport name from pjsip_transport->info and retrieves the transport. If transport->symmetric_transport is set, an 'x-ast-txp' uri parameter containing the transport name is added to the incoming Contact header. * An 'ast_sip_get_transport_name' function was added to res_pjsip. It takes an ast_sip_endpoint and a pjsip_sip_uri and returns a transport name if endpoint->transport is set or if there's an 'x-ast-txp' parameter on the uri and the uri host is an ipv4 or ipv6 address. Otherwise it returns NULL. * An 'ast_sip_dlg_set_transport' function was added to res_pjsip which takes an ast_sip_endpoint, a pjsip_dialog, and an optional pjsip_tpselector. It calls ast_sip_get_transport_name() and if a non-NULL is returned, sets the selector and sets the transport on the dialog. If a selector was passed in, it's updated. * res_pjsip/ast_sip_create_dialog_uac and ast_sip_create_dialog_uas were modified to call ast_sip_dlg_set_transport() instead of their original logic. * res_pjsip/create_out_of_dialog_request was modified to call ast_sip_get_transport_name() and pjsip_tx_data_set_transport() instead of its original logic. * Existing transport logic was removed from endpt_send_request since that can only be called after a create_out_of_dialog_request. * res_pjsip/ast_sip_create_rdata was converted to a wrapper around a new 'ast_sip_create_rdata_with_contact' function which allows a contact_uri to be specified in addition to the existing parameters. (See below) * res_pjsip_pubsub/internal_pjsip_evsub_send_request was eliminated since all it did was transport selection and that is now done in ast_sip_create_dialog_uac and ast_sip_create_dialog_uas. * 'contact_uri' was added to subscription_persistence. This was necessary because although the parsed rdata contact header has the x-ast-txp parameter added (if appropriate), subscription_persistence_update stores the raw packet which doesn't have it. subscription_persistence_recreate was then updated to call ast_sip_create_rdata_with_contact with the persisted contact_uri so the recreated subscription has the correct transport info to send the NOTIFYs. * res_pjsip_session/internal_pjsip_inv_send_msg was eliminated since all it did was transport selection and that is now done in ast_sip_create_dialog_uac. * pjsip_message_ip_updater/multihomed_on_tx_message was updated to remove all traces of the x-ast-txp parameter from the outgoing headers. NOTE: This change does NOT modify the behavior of permanent contacts specified on an aor. To do so would require that the permanent contact's contact uri be updated with the x-ast-txp parameter and the aor sorcery object updated. If we need to persue this, we need to think about cloning permanent contacts into the same store as the dynamic ones on an aor load so they can be updated without disturbing the originally configured value. You CAN add the x-ast-txp parameter to a permanent contact's uri but it would be much simpler to just set endpoint->transport. Change-Id: I4ee1f51473da32ca54b877cd158523efcef9655f --- CHANGES | 16 ++ configs/samples/pjsip.conf.sample | 11 ++ .../versions/15db7b91a97a_add_rtcp_mux.py | 1 + .../f638dbe2eb23_symmetric_transport.py | 32 ++++ include/asterisk/res_pjsip.h | 80 +++++++++- res/res_pjsip.c | 141 +++++++++++++----- res/res_pjsip/config_transport.c | 22 ++- res/res_pjsip/pjsip_message_ip_updater.c | 83 +++++++++++ res/res_pjsip_pubsub.c | 46 +++--- res/res_pjsip_session.c | 34 +---- 10 files changed, 367 insertions(+), 99 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/f638dbe2eb23_symmetric_transport.py diff --git a/CHANGES b/CHANGES index 4e9df4fa58d..e391d1e1749 100644 --- a/CHANGES +++ b/CHANGES @@ -118,6 +118,22 @@ app_voicemail * Added 'fromstring' field to the voicemail boxes. If set, it will override the global 'fromstring' field on a per-mailbox basis. +res_pjsip +------------------ + * A new transport parameter 'symmetric_transport' has been added. + When a request from a dynamic contact comes in on a transport with this + option set to 'yes', the transport name will be saved and used for + subsequent outgoing requests like OPTIONS, NOTIFY and INVITE. It's + saved as a contact uri parameter named 'x-ast-txp' and will display with + the contact uri in CLI, AMI, and ARI output. On the outgoing request, + if a transport wasn't explicitly set on the endpoint AND the request URI + is not a hostname, the saved transport will be used and the 'x-ast-txp' + parameter stripped from the outgoing packet. To facilitate recreation of + subscriptions on asterisk restart, a new column 'contact_uri' needed to be + added to the ps_subcsription_persistence table. Since new columns were + added to both transport and subscription_persistence, an alembic upgrade + should be run to bring the database tables up to date. + res_pjsip_transport_websocket ------------------ * Removed non-secure websocket support. Firefox and Chrome have not allowed diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index b18fdb276e0..120a7ef1c76 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -853,6 +853,17 @@ ; this option is set to 'no' (the default) changes to the ; particular transport will be ignored. If set to 'yes', ; changes (if any) will be applied. +;symmetric_transport=no ; When a request from a dynamic contact comes in on a + ; transport with this option set to 'yes', the transport + ; name will be saved and used for subsequent outgoing + ; requests like OPTIONS, NOTIFY and INVITE. It's saved + ; as a contact uri parameter named 'x-ast-txp' and will + ; display with the contact uri in CLI, AMI, and ARI + ; output. On the outgoing request, if a transport + ; wasn't explicitly set on the endpoint AND the request + ; URI is not a hostname, the saved transport will be + ; used and the 'x-ast-txp' parameter stripped from the + ; outgoing packet. ;==========================AOR SECTION OPTIONS========================= ;[aor] diff --git a/contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py b/contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py index 50d3ee33894..8b0214a1714 100644 --- a/contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py +++ b/contrib/ast-db-manage/config/versions/15db7b91a97a_add_rtcp_mux.py @@ -12,6 +12,7 @@ from alembic import op import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM YESNO_NAME = 'yesno_values' YESNO_VALUES = ['yes', 'no'] diff --git a/contrib/ast-db-manage/config/versions/f638dbe2eb23_symmetric_transport.py b/contrib/ast-db-manage/config/versions/f638dbe2eb23_symmetric_transport.py new file mode 100644 index 00000000000..51b5066f570 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/f638dbe2eb23_symmetric_transport.py @@ -0,0 +1,32 @@ +"""symmetric_transport + +Revision ID: f638dbe2eb23 +Revises: 15db7b91a97a +Create Date: 2017-03-09 09:38:59.513479 + +""" + +# revision identifiers, used by Alembic. +revision = 'f638dbe2eb23' +down_revision = '15db7b91a97a' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_transports', sa.Column('symmetric_transport', yesno_values)) + op.add_column('ps_subscription_persistence', sa.Column('contact_uri', sa.String(256))) + +def downgrade(): + op.drop_column('ps_subscription_persistence', 'contact_uri') + op.drop_column('ps_transports', 'symmetric_transport') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index fb045130700..c6c308beef0 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -194,6 +194,8 @@ struct ast_sip_transport { int write_timeout; /*! Allow reload */ int allow_reload; + /*! Automatically send requests out the same transport requests have come in on */ + int symmetric_transport; }; #define SIP_SORCERY_DOMAIN_ALIAS_TYPE "domain_alias" @@ -765,6 +767,10 @@ struct ast_sip_endpoint { unsigned int asymmetric_rtp_codec; }; +/*! URI parameter for symmetric transport */ +#define AST_SIP_X_AST_TXP "x-ast-txp" +#define AST_SIP_X_AST_TXP_LEN 9 + /*! * \brief Initialize an auth vector with the configured values. * @@ -1657,6 +1663,26 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, */ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status); +/*! + * \brief General purpose method for creating an rdata structure using specific information + * \since 13.15.0 + * + * \param rdata[out] The rdata structure that will be populated + * \param packet A SIP message + * \param src_name The source IP address of the message + * \param src_port The source port of the message + * \param transport_type The type of transport the message was received on + * \param local_name The local IP address the message was received on + * \param local_port The local port the message was received on + * \param contact_uri The contact URI of the message + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, + const char *src_name, int src_port, char *transport_type, const char *local_name, + int local_port, const char *contact_uri); + /*! * \brief General purpose method for creating an rdata structure using specific information * @@ -1671,8 +1697,8 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, * \retval 0 success * \retval -1 failure */ -int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type, - const char *local_name, int local_port); +int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, + int src_port, char *transport_type, const char *local_name, int local_port); /*! * \brief General purpose method for creating a SIP request @@ -2709,4 +2735,54 @@ void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, void ast_sip_get_unidentified_request_thresholds(unsigned int *count, unsigned int *period, unsigned int *prune_interval); +/*! + * \brief Get the transport name from an endpoint or request uri + * \since 13.15.0 + * + * \param endpoint + * \param sip_uri + * \param buf Buffer to receive transport name + * \param buf_len Buffer length + * + * \retval 0 Success + * \retval -1 Failure + * + * \note + * If endpoint->transport is not NULL, it is returned in buf. + * Otherwise if sip_uri has an 'x-ast-txp' parameter AND the sip_uri host is + * an ip4 or ip6 address, its value is returned, + */ +int ast_sip_get_transport_name(const struct ast_sip_endpoint *endpoint, + pjsip_sip_uri *sip_uri, char *buf, size_t buf_len); + +/*! + * \brief Sets pjsip_tpselector from an endpoint or uri + * \since 13.15.0 + * + * \param endpoint If endpoint->transport is set, it's used + * \param sip_uri If sip_uri contains a x-ast-txp parameter, it's used + * \param selector The selector to be populated + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sip_set_tpselector_from_ep_or_uri(const struct ast_sip_endpoint *endpoint, + pjsip_sip_uri *sip_uri, pjsip_tpselector *selector); + +/*! + * \brief Set the transport on a dialog + * \since 13.15.0 + * + * \param endpoint + * \param dlg + * \param selector (optional) + * + * \note + * This API calls ast_sip_get_transport_name(endpoint, dlg->target) and if the result is + * non-NULL, calls pjsip_dlg_set_transport. If 'selector' is non-NULL, it is updated with + * the selector used. + */ +int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg, + pjsip_tpselector *selector); + #endif /* _RES_PJSIP_H */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index f4df4983640..962c4be4f62 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1193,6 +1193,22 @@ in-progress calls. + + Use the same transport for outgoing reqests as incoming ones. + + When a request from a dynamic contact + comes in on a transport with this option set to 'yes', + the transport name will be saved and used for subsequent + outgoing requests like OPTIONS, NOTIFY and INVITE. It's + saved as a contact uri parameter named 'x-ast-txp' and will + display with the contact uri in CLI, AMI, and ARI output. + On the outgoing request, if a transport wasn't explicitly + set on the endpoint AND the request URI is not a hostname, + the saved transport will be used and the 'x-ast-txp' + parameter stripped from the outgoing packet. + + + A way of creating an aliased name to a SIP URI @@ -2762,7 +2778,54 @@ pjsip_endpoint *ast_sip_get_pjsip_endpoint(void) return ast_pjsip_endpoint; } -static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const char *domain, const pj_str_t *target, pjsip_tpselector *selector) +int ast_sip_get_transport_name(const struct ast_sip_endpoint *endpoint, + pjsip_sip_uri *sip_uri, char *buf, size_t buf_len) +{ + char *host = NULL; + static const pj_str_t x_name = { AST_SIP_X_AST_TXP, AST_SIP_X_AST_TXP_LEN }; + pjsip_param *x_transport; + + if (!ast_strlen_zero(endpoint->transport)) { + ast_copy_string(buf, endpoint->transport, buf_len); + return 0; + } + + x_transport = pjsip_param_find(&sip_uri->other_param, &x_name); + if (!x_transport) { + return -1; + } + + /* Only use x_transport if the uri host is an ip (4 or 6) address */ + host = ast_alloca(sip_uri->host.slen + 1); + ast_copy_pj_str(host, &sip_uri->host, sip_uri->host.slen + 1); + if (!ast_sockaddr_parse(NULL, host, PARSE_PORT_FORBID)) { + return -1; + } + + ast_copy_pj_str(buf, &x_transport->value, buf_len); + + return 0; +} + +int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg, + pjsip_tpselector *selector) +{ + pjsip_sip_uri *uri; + pjsip_tpselector sel = { .type = PJSIP_TPSELECTOR_NONE, }; + + uri = pjsip_uri_get_uri(dlg->target); + if (!selector) { + selector = &sel; + } + + ast_sip_set_tpselector_from_ep_or_uri(endpoint, uri, selector); + pjsip_dlg_set_transport(dlg, selector); + + return 0; +} + +static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, + const char *domain, const pj_str_t *target, pjsip_tpselector *selector) { pj_str_t tmp, local_addr; pjsip_uri *uri; @@ -2892,15 +2955,16 @@ int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip return ast_sip_set_tpselector_from_transport(transport, selector); } -static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpoint, pjsip_tpselector *selector) +int ast_sip_set_tpselector_from_ep_or_uri(const struct ast_sip_endpoint *endpoint, + pjsip_sip_uri *sip_uri, pjsip_tpselector *selector) { - const char *transport_name = endpoint->transport; + char transport_name[128]; - if (ast_strlen_zero(transport_name)) { + if (ast_sip_get_transport_name(endpoint, sip_uri, transport_name, sizeof(transport_name))) { return 0; } - return ast_sip_set_tpselector_from_transport_name(endpoint->transport, selector); + return ast_sip_set_tpselector_from_transport_name(transport_name, selector); } void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t *pool, pjsip_uri *uri) @@ -2908,8 +2972,8 @@ void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t pjsip_sip_uri *sip_uri; int i = 0; pjsip_param *param; - const pj_str_t STR_USER = { "user", 4 }; - const pj_str_t STR_PHONE = { "phone", 5 }; + static const pj_str_t STR_USER = { "user", 4 }; + static const pj_str_t STR_PHONE = { "phone", 5 }; if (!endpoint || !endpoint->usereqphone || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) { return; @@ -2942,7 +3006,8 @@ void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t pj_list_insert_before(&sip_uri->other_param, param); } -pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *uri, const char *request_user) +pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, + const char *uri, const char *request_user) { char enclosed_uri[PJSIP_MAX_URL_SIZE]; pj_str_t local_uri = { "sip:temp@temp", 13 }, remote_uri, target_uri; @@ -2967,12 +3032,13 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, return NULL; } - if (sip_get_tpselector_from_endpoint(endpoint, &selector)) { - pjsip_dlg_terminate(dlg); - return NULL; - } + /* We have to temporarily bump up the sess_count here so the dialog is not prematurely destroyed */ + dlg->sess_count++; + + ast_sip_dlg_set_transport(endpoint, dlg, &selector); if (sip_dialog_create_from(dlg->pool, &local_uri, endpoint->fromuser, endpoint->fromdomain, &remote_uri, &selector)) { + dlg->sess_count--; pjsip_dlg_terminate(dlg); return NULL; } @@ -3008,11 +3074,6 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, ast_sip_add_usereqphone(endpoint, dlg->pool, dlg->target); ast_sip_add_usereqphone(endpoint, dlg->pool, dlg->remote.info->uri); - /* We have to temporarily bump up the sess_count here so the dialog is not prematurely destroyed */ - dlg->sess_count++; - - pjsip_dlg_set_transport(dlg, &selector); - if (!ast_strlen_zero(outbound_proxy)) { pjsip_route_hdr route_set, *route; static const pj_str_t ROUTE_HNAME = { "Route", 5 }; @@ -3081,10 +3142,13 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_transport_type_e type = rdata->tp_info.transport->key.type; pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; pjsip_transport *transport; + pjsip_contact_hdr *contact_hdr; ast_assert(status != NULL); - if (sip_get_tpselector_from_endpoint(endpoint, &selector)) { + contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); + if (ast_sip_set_tpselector_from_ep_or_uri(endpoint, pjsip_uri_get_uri(contact_hdr->uri), + &selector)) { return NULL; } @@ -3130,8 +3194,8 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, return dlg; } -int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, - char *transport_type, const char *local_name, int local_port) +int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, + char *transport_type, const char *local_name, int local_port, const char *contact) { pj_str_t tmp; @@ -3155,6 +3219,16 @@ int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_nam return -1; } + if (!ast_strlen_zero(contact)) { + pjsip_contact_hdr *contact_hdr; + + contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); + if (contact_hdr) { + contact_hdr->uri = pjsip_parse_uri(rdata->tp_info.pool, (char *)contact, + strlen(contact), PJSIP_PARSE_URI_AS_NAMEADDR); + } + } + pj_strdup2(rdata->tp_info.pool, &rdata->msg_info.via->recvd_param, rdata->pkt_info.src_name); rdata->msg_info.via->rport_param = -1; @@ -3166,6 +3240,13 @@ int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_nam return 0; } +int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, + char *transport_type, const char *local_name, int local_port) +{ + return ast_sip_create_rdata_with_contact(rdata, packet, src_name, src_port, transport_type, + local_name, local_port, NULL); +} + /* PJSIP doesn't know about the INFO method, so we have to define it ourselves */ static const pjsip_method info_method = {PJSIP_OTHER_METHOD, {"INFO", 4} }; static const pjsip_method message_method = {PJSIP_OTHER_METHOD, {"MESSAGE", 7} }; @@ -3247,14 +3328,6 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s pj_cstr(&remote_uri, uri); } - if (endpoint) { - if (sip_get_tpselector_from_endpoint(endpoint, &selector)) { - ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport selector for endpoint %s\n", - ast_sorcery_object_get_id(endpoint)); - return -1; - } - } - pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Outbound request", 256, 256); if (!pool) { @@ -3272,6 +3345,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s return -1; } + ast_sip_set_tpselector_from_ep_or_uri(endpoint, pjsip_uri_get_uri(sip_uri), &selector); + fromuser = endpoint ? (!ast_strlen_zero(endpoint->fromuser) ? endpoint->fromuser : ast_sorcery_object_get_id(endpoint)) : NULL; if (sip_dialog_create_from(pool, &from, fromuser, endpoint ? endpoint->fromdomain : NULL, &remote_uri, &selector)) { @@ -3291,6 +3366,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s return -1; } + pjsip_tx_data_set_transport(*tdata, &selector); + if (endpoint && !ast_strlen_zero(endpoint->contact_user)){ pjsip_contact_hdr *contact_hdr; pjsip_sip_uri *contact_uri; @@ -3332,6 +3409,8 @@ int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, { const pjsip_method *pmethod = get_pjsip_method(method); + ast_assert(endpoint != NULL); + if (!pmethod) { ast_log(LOG_WARNING, "Unknown method '%s'. Cannot send request\n", method); return -1; @@ -3596,7 +3675,6 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, struct send_request_wrapper *req_wrapper; pj_status_t ret_val; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); - pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; if (!cb && token) { /* Silly. Without a callback we cannot do anything with token. */ @@ -3621,11 +3699,6 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, /* Add a reference to tdata. The wrapper destructor cleans it up. */ pjsip_tx_data_add_ref(tdata); - if (endpoint) { - sip_get_tpselector_from_endpoint(endpoint, &selector); - pjsip_tx_data_set_transport(tdata, &selector); - } - if (timeout > 0) { pj_time_val timeout_timer_val = { timeout / 1000, timeout % 1000 }; diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 60b4507cdb8..3c41f175aa1 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -552,13 +552,20 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) } } - if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { - pj_sock_t sock; - pj_qos_params qos_params; - sock = pjsip_udp_transport_get_socket(temp_state->state->transport); - pj_sock_get_qos_params(sock, &qos_params); - set_qos(transport, &qos_params); - pj_sock_set_qos_params(sock, &qos_params); + if (res == PJ_SUCCESS) { + temp_state->state->transport->info = pj_pool_alloc(temp_state->state->transport->pool, + (AST_SIP_X_AST_TXP_LEN + strlen(transport_id) + 2)); + + sprintf(temp_state->state->transport->info, "%s:%s", AST_SIP_X_AST_TXP, transport_id); + + if (transport->tos || transport->cos) { + pj_sock_t sock; + pj_qos_params qos_params; + sock = pjsip_udp_transport_get_socket(temp_state->state->transport); + pj_sock_get_qos_params(sock, &qos_params); + set_qos(transport, &qos_params); + pj_sock_set_qos_params(sock, &qos_params); + } } } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; @@ -1375,6 +1382,7 @@ int ast_sip_initialize_sorcery_transport(void) ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos)); ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX); ast_sorcery_object_field_register(sorcery, "transport", "allow_reload", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, allow_reload)); + ast_sorcery_object_field_register(sorcery, "transport", "symmetric_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, symmetric_transport)); internal_sip_register_endpoint_formatter(&endpoint_transport_formatter); diff --git a/res/res_pjsip/pjsip_message_ip_updater.c b/res/res_pjsip/pjsip_message_ip_updater.c index 7671ad0a75e..864d898b3f9 100644 --- a/res/res_pjsip/pjsip_message_ip_updater.c +++ b/res/res_pjsip/pjsip_message_ip_updater.c @@ -28,6 +28,7 @@ #define MOD_DATA_RESTRICTIONS "restrictions" static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata); +static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata); /*! \brief Outgoing message modification restrictions */ struct multihomed_message_restrictions { @@ -41,6 +42,7 @@ static pjsip_module multihomed_module = { .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1, .on_tx_request = multihomed_on_tx_message, .on_tx_response = multihomed_on_tx_message, + .on_rx_request = multihomed_on_rx_message, }; /*! \brief Helper function to get (or allocate if not already present) restrictions on a message */ @@ -151,6 +153,44 @@ static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp) return 0; } +static void sanitize_tdata(pjsip_tx_data *tdata) +{ + static const pj_str_t x_name = { AST_SIP_X_AST_TXP, AST_SIP_X_AST_TXP_LEN }; + pjsip_param *x_transport; + pjsip_sip_uri *uri; + pjsip_fromto_hdr *fromto; + pjsip_contact_hdr *contact; + pjsip_hdr *hdr; + + if (tdata->msg->type == PJSIP_REQUEST_MSG) { + uri = pjsip_uri_get_uri(tdata->msg->line.req.uri); + x_transport = pjsip_param_find(&uri->other_param, &x_name); + if (x_transport) { + pj_list_erase(x_transport); + } + } + + for (hdr = tdata->msg->hdr.next; hdr != &tdata->msg->hdr; hdr = hdr->next) { + if (hdr->type == PJSIP_H_TO || hdr->type == PJSIP_H_FROM) { + fromto = (pjsip_fromto_hdr *) hdr; + uri = pjsip_uri_get_uri(fromto->uri); + x_transport = pjsip_param_find(&uri->other_param, &x_name); + if (x_transport) { + pj_list_erase(x_transport); + } + } else if (hdr->type == PJSIP_H_CONTACT) { + contact = (pjsip_contact_hdr *) hdr; + uri = pjsip_uri_get_uri(contact->uri); + x_transport = pjsip_param_find(&uri->other_param, &x_name); + if (x_transport) { + pj_list_erase(x_transport); + } + } + } + + pjsip_tx_data_invalidate_msg(tdata); +} + static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) { struct multihomed_message_restrictions *restrictions = ast_sip_mod_data_get(tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS); @@ -159,6 +199,8 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) pjsip_via_hdr *via; pjsip_fromto_hdr *from; + sanitize_tdata(tdata); + /* Use the destination information to determine what local interface this message will go out on */ pjsip_tpmgr_fla2_param_default(&prm); prm.tp_type = tdata->tp_info.transport->key.type; @@ -273,6 +315,47 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) return PJ_SUCCESS; } +static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata) +{ + pjsip_contact_hdr *contact; + pjsip_sip_uri *uri; + const char *transport_id; + struct ast_sip_transport *transport; + pjsip_param *x_transport; + + if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) { + return PJ_FALSE; + } + + contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); + if (!(contact && contact->uri + && ast_begins_with(rdata->tp_info.transport->info, AST_SIP_X_AST_TXP ":"))) { + return PJ_FALSE; + } + + uri = pjsip_uri_get_uri(contact->uri); + + transport_id = rdata->tp_info.transport->info + AST_SIP_X_AST_TXP_LEN + 1; + transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_id); + + if (!(transport && transport->symmetric_transport)) { + return PJ_FALSE; + } + + x_transport = PJ_POOL_ALLOC_T(rdata->tp_info.pool, pjsip_param); + x_transport->name = pj_strdup3(rdata->tp_info.pool, AST_SIP_X_AST_TXP); + x_transport->value = pj_strdup3(rdata->tp_info.pool, transport_id); + + pj_list_insert_before(&uri->other_param, x_transport); + + ast_debug(1, "Set transport '%s' on %.*s from %.*s:%d\n", transport_id, + (int)rdata->msg_info.msg->line.req.method.name.slen, + rdata->msg_info.msg->line.req.method.name.ptr, + (int)uri->host.slen, uri->host.ptr, uri->port); + + return PJ_FALSE; +} + void ast_res_pjsip_cleanup_message_ip_updater(void) { ast_sip_unregister_service(&multihomed_module); diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index e90502485c6..f0467627ea5 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -123,6 +123,9 @@ The time at which the subscription expires + + The Contact URI of the dialog for the subscription + Resource list configuration parameters. @@ -376,6 +379,8 @@ struct subscription_persistence { char *tag; /*! When this subscription expires */ struct timeval expires; + /*! Contact URI */ + char contact_uri[PJSIP_MAX_URL_SIZE]; }; /*! @@ -591,8 +596,8 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr return; } - ast_debug(3, "Updating persistence for '%s->%s'\n", - ast_sorcery_object_get_id(sub_tree->endpoint), sub_tree->root->resource); + ast_debug(3, "Updating persistence for '%s->%s'\n", sub_tree->persistence->endpoint, + sub_tree->root->resource); dlg = sub_tree->dlg; sub_tree->persistence->cseq = dlg->local.cseq; @@ -600,10 +605,14 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr if (rdata) { int expires; pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); + pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES; sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1)); + pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, + sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri)); + /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf * will always point to the proper SIP message that is to be processed. When updating subscription @@ -1550,8 +1559,9 @@ static int subscription_persistence_recreate(void *obj, void *arg, int flags) pj_pool_reset(pool); rdata.tp_info.pool = pool; - if (ast_sip_create_rdata(&rdata, persistence->packet, persistence->src_name, persistence->src_port, - persistence->transport_key, persistence->local_name, persistence->local_port)) { + if (ast_sip_create_rdata_with_contact(&rdata, persistence->packet, persistence->src_name, + persistence->src_port, persistence->transport_key, persistence->local_name, + persistence->local_port, persistence->contact_uri)) { ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n", persistence->endpoint); ast_sorcery_delete(ast_sip_get_sorcery(), persistence); @@ -1703,28 +1713,6 @@ void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, co return pjsip_msg_find_hdr_by_name(msg, &name, NULL); } -/*! - * \internal - * \brief Wrapper for pjsip_evsub_send_request - * - * This function (re)sets the transport before sending to catch cases - * where the transport might have changed. - * - * If pjproject gives us the ability to resend, we'll only reset the transport - * if PJSIP_ETPNOTAVAIL is returned from send. - * - * \returns pj_status_t - */ -static pj_status_t internal_pjsip_evsub_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata) -{ - pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; - - ast_sip_set_tpselector_from_transport_name(sub_tree->endpoint->transport, &selector); - pjsip_dlg_set_transport(sub_tree->dlg, &selector); - - return pjsip_evsub_send_request(sub_tree->evsub, tdata); -} - /* XXX This function is not used. */ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, const char *resource) @@ -1772,7 +1760,7 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su evsub = sub_tree->evsub; if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) { - internal_pjsip_evsub_send_request(sub_tree, tdata); + pjsip_evsub_send_request(sub_tree->evsub, tdata); } else { /* pjsip_evsub_terminate will result in pubsub_on_evsub_state, * being called and terminating the subscription. Therefore, we don't @@ -1869,7 +1857,7 @@ static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, return -1; } - res = internal_pjsip_evsub_send_request(sub_tree, tdata); + res = pjsip_evsub_send_request(sub_tree->evsub, tdata); subscription_persistence_update(sub_tree, NULL, SUBSCRIPTION_PERSISTENCE_SEND_REQUEST); @@ -5283,6 +5271,8 @@ static int load_module(void) persistence_tag_str2struct, persistence_tag_struct2str, NULL, 0, 0); ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "", persistence_expires_str2struct, persistence_expires_struct2str, NULL, 0, 0); + ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0, + CHARFLDSET(struct subscription_persistence, contact_uri)); if (apply_list_configuration(sorcery)) { ast_sip_unregister_service(&pubsub_module); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index ad9670cd124..fec0768efe8 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -973,32 +973,10 @@ int ast_sip_session_refresh(struct ast_sip_session *session, return 0; } -/*! - * \internal - * \brief Wrapper for pjsip_inv_send_msg - * - * This function (re)sets the transport before sending to catch cases - * where the transport might have changed. - * - * If pjproject gives us the ability to resend, we'll only reset the transport - * if PJSIP_ETPNOTAVAIL is returned from send. - * - * \returns pj_status_t - */ -static pj_status_t internal_pjsip_inv_send_msg(pjsip_inv_session *inv, const char *transport_name, pjsip_tx_data *tdata) -{ - pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; - - ast_sip_set_tpselector_from_transport_name(transport_name, &selector); - pjsip_dlg_set_transport(inv->dlg, &selector); - - return pjsip_inv_send_msg(inv, tdata); -} - void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata) { handle_outgoing_response(session, tdata); - internal_pjsip_inv_send_msg(session->inv_session, session->endpoint->transport, tdata); + pjsip_inv_send_msg(session->inv_session, tdata); return; } @@ -1229,7 +1207,7 @@ void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip MOD_DATA_ON_RESPONSE, on_response); handle_outgoing_request(session, tdata); - internal_pjsip_inv_send_msg(session->inv_session, session->endpoint->transport, tdata); + pjsip_inv_send_msg(session->inv_session, tdata); return; } @@ -2051,7 +2029,7 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } - internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); + pjsip_inv_send_msg(inv_session, tdata); return NULL; } return inv_session; @@ -2222,7 +2200,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } else { - internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); + pjsip_inv_send_msg(inv_session, tdata); } } return; @@ -2234,7 +2212,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } else { - internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); + pjsip_inv_send_msg(inv_session, tdata); } #ifdef HAVE_PJSIP_INV_SESSION_REF pjsip_inv_dec_ref(inv_session); @@ -2247,7 +2225,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } else { - internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata); + pjsip_inv_send_msg(inv_session, tdata); } #ifdef HAVE_PJSIP_INV_SESSION_REF pjsip_inv_dec_ref(inv_session); From 44568fc712c3ed9e820221830a68cd707e83dd44 Mon Sep 17 00:00:00 2001 From: Richard Begg Date: Wed, 15 Mar 2017 08:22:42 +1100 Subject: [PATCH 1129/1578] res_pjsip_sdp_rtp: RTP instance does not use same IP as explicit transport Currently a wildcard address is used for the local RTP socket, which will not always result in the same address as used by the SIP socket (e.g. if explicit transport addresses are configured). Use the transport's host address when binding new local RTP sockets if available. ASTERISK-26851 Change-Id: I098c29c9d1f79a4f970d72ba894874ac75954f1a --- res/res_pjsip_sdp_rtp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 9f39256e56e..178524afe55 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -196,6 +196,20 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me if (session->endpoint->media.bind_rtp_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) { ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0); media_address = &temp_media_address; + } else { + struct ast_sip_transport *transport = + ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", + session->endpoint->transport); + + if (transport && transport->state) { + char hoststr[PJ_INET6_ADDRSTRLEN]; + + pj_sockaddr_print(&transport->state->host, hoststr, sizeof(hoststr), 0); + ast_debug(1, "Transport: %s bound to host: %s, using this for media.\n", + session->endpoint->transport, hoststr); + ast_sockaddr_parse(media_address, hoststr, 0); + } + ao2_cleanup(transport); } if (!(session_media->rtp = ast_rtp_instance_new(session->endpoint->media.rtp.engine, sched, media_address, NULL))) { From e6dc28b78fbb8ae606daf1700a09772401ca063e Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Thu, 16 Mar 2017 10:39:00 -0500 Subject: [PATCH 1130/1578] res/res_pjsip_session: Only check localnet if it is defined If local_net is not defined on a transport, transport_state->localnet will be NULL. ast_apply_ha will, be default, return AST_SENSE_ALLOW in this case, causing the external_media_address, if set, to be skipped. This patch causes us to only check if we are sending within a network if local_net is defined. ASTERISK-26879 #close Change-Id: Ib661c31a954cabc9c99f1f25c9c9a5c5b82cbbfb --- res/res_pjsip_nat.c | 43 +++++++++++++++++++++-------------------- res/res_pjsip_sdp_rtp.c | 5 +++-- res/res_pjsip_session.c | 5 ++++- res/res_pjsip_t38.c | 5 +++-- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c index a855298b2fa..a26180bc0b8 100644 --- a/res/res_pjsip_nat.c +++ b/res/res_pjsip_nat.c @@ -262,32 +262,33 @@ static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) return PJ_SUCCESS; } - if ( !transport_state->localnet || ast_sockaddr_isnull(&transport_state->external_address)) { - return PJ_SUCCESS; - } - - ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID); - ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port); + if (transport_state->localnet) { + ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID); + ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port); - /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */ - if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) { - return PJ_SUCCESS; + /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */ + if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) { + ast_debug(5, "Request is being sent to local address, skipping NAT manipulation\n"); + return PJ_SUCCESS; + } } - /* Update the contact header with the external address */ - if (uri || (uri = nat_get_contact_sip_uri(tdata))) { - pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_address)); - if (transport->external_signaling_port) { - uri->port = transport->external_signaling_port; - ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port); + if (!ast_sockaddr_isnull(&transport_state->external_address)) { + /* Update the contact header with the external address */ + if (uri || (uri = nat_get_contact_sip_uri(tdata))) { + pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_address)); + if (transport->external_signaling_port) { + uri->port = transport->external_signaling_port; + ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port); + } } - } - /* Update the via header if relevant */ - if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) { - pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_address)); - if (transport->external_signaling_port) { - via->sent_by.port = transport->external_signaling_port; + /* Update the via header if relevant */ + if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) { + pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_address)); + if (transport->external_signaling_port) { + via->sent_by.port = transport->external_signaling_port; + } } } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 9f39256e56e..75dc83929d9 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1473,10 +1473,11 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID); /* Is the address within the SDP inside the same network? */ - if (ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { + if (transport_state->localnet + && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { return; } - + ast_debug(5, "Setting media address to %s\n", transport->external_media_address); pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address); } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index ad9670cd124..609d08dc06d 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -3148,7 +3148,10 @@ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_trans ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host)); ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID); - if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) { + if (!transport_state->localnet + || (transport_state->localnet + && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW)) { + ast_debug(5, "Setting external media address to %s\n", transport->external_media_address); pj_strdup2(tdata->pool, &sdp->conn->addr, transport->external_media_address); } } diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 79dc9c3247d..bae4ff1dcaf 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -867,10 +867,11 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID); /* Is the address within the SDP inside the same network? */ - if (ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { + if (transport_state->localnet + && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { return; } - + ast_debug(5, "Setting media address to %s\n", transport->external_media_address); pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address); } From 49b1f1ca16f410696bcac463afa0cba746f0af39 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 16 Mar 2017 15:45:57 -0500 Subject: [PATCH 1131/1578] res_pjsip_sdp_rtp.c: Fix cut-n-paste error We were inadvertenly referencing the cos_video option to determine if we should set the tos_audio and cos_audio value on the RTP instance. Change-Id: Ia7964f486801d39dc6f5dae570baff079e1595b0 --- res/res_pjsip_sdp_rtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 9f39256e56e..9fc1b8af4cc 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -217,7 +217,7 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me } if (!strcmp(session_media->stream_type, STR_AUDIO) && - (session->endpoint->media.tos_audio || session->endpoint->media.cos_video)) { + (session->endpoint->media.tos_audio || session->endpoint->media.cos_audio)) { ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_audio, session->endpoint->media.cos_audio, "SIP RTP Audio"); } else if (!strcmp(session_media->stream_type, STR_VIDEO) && From 82982a191c0715b2dabdecd64e749461e38355ee Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 16 Mar 2017 16:37:42 -0500 Subject: [PATCH 1132/1578] res_pjsip_asterisk.c: Fix compile error if libsrtp is not installed. struct ast_rtcp does not define the dtls member if SRTP is not enabled. ASTERISK-26732 Change-Id: Id15ea212e04490e012f2cf4a56818b4dd948875e --- res/res_rtp_asterisk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index a67bc8135b4..0a906dc7a51 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -5040,7 +5040,9 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro return; } rtp->rtcp->s = -1; +#ifdef HAVE_OPENSSL_SRTP rtp->rtcp->dtls.timeout_timer = -1; +#endif rtp->rtcp->schedid = -1; } From 57656e2b5b58d97dda5f082897c3a532568b01c3 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 16 Mar 2017 16:50:17 -0500 Subject: [PATCH 1133/1578] app_confbridge: Fix ConfbridgeTalking AMI event description. Thanks to Chris Howard for pointing this out on the wiki. Change-Id: I18e56de09a70e736b5d04719d45ef29cf0636705 --- apps/confbridge/confbridge_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c index a99362b33a3..e5db648da35 100644 --- a/apps/confbridge/confbridge_manager.c +++ b/apps/confbridge/confbridge_manager.c @@ -189,7 +189,7 @@ - Raised when a confbridge participant unmutes. + Raised when a confbridge participant begins or ends talking. The name of the Confbridge conference. From 15aa3c0a23fe5a017b44d09c0ef3b8b86f38448b Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 7 Mar 2017 20:28:18 -0500 Subject: [PATCH 1134/1578] chan_sip: Add rtcp-mux support ASTERISK-26846 #close Change-Id: I541a1602ff55ab73684e9f8002edb9e0e745d639 --- UPGRADE.txt | 7 +- channels/chan_sip.c | 139 +++++++++++++++++++++++++------- channels/sip/include/sip.h | 3 +- configs/samples/sip.conf.sample | 2 + 4 files changed, 120 insertions(+), 31 deletions(-) diff --git a/UPGRADE.txt b/UPGRADE.txt index 2275580cabd..1afacf2a4a4 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -27,9 +27,10 @@ From 14.3.0 to 14.4.0: res_rtp_asterisk: - The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP - Data and Control Packets on a Single Port." So far, the only channel driver - that supports this feature is chan_pjsip. You can set "rtcp_mux = yes" on - a PJSIP endpoint in pjsip.conf to enable the feature. + Data and Control Packets on a Single Port." For the PJSIP channel driver, + chan_pjsip, you can set "rtcp_mux = yes" on a PJSIP endpoint in pjsip.conf + to enable the feature. For chan_sip you can set "rtcp_mux = yes" either + globally or on a per-peer basis in sip.conf. New in 14.0.0 diff --git a/channels/chan_sip.c b/channels/chan_sip.c index d158b0dbd94..f659a44a3c6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1216,6 +1216,7 @@ static int process_sdp_o(const char *o, struct sip_pvt *p); static int process_sdp_c(const char *c, struct ast_sockaddr *addr); static int process_sdp_a_sendonly(const char *a, int *sendonly); static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance); +static int process_sdp_a_rtcp_mux(const char *a, struct sip_pvt *p, int *requested); static int process_sdp_a_dtls(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance); static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec); static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec); @@ -6011,7 +6012,7 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) ast_rtp_instance_set_hold_timeout(dialog->vrtp, dialog->rtpholdtimeout); ast_rtp_instance_set_keepalive(dialog->vrtp, dialog->rtpkeepalive); - ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); ast_rtp_instance_set_qos(dialog->vrtp, global_tos_video, global_cos_video, "SIP VIDEO"); } @@ -6031,14 +6032,14 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) /* Do not timeout text as its not constant*/ ast_rtp_instance_set_keepalive(dialog->trtp, dialog->rtpkeepalive); - ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); } ast_rtp_instance_set_timeout(dialog->rtp, dialog->rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->rtp, dialog->rtpholdtimeout); ast_rtp_instance_set_keepalive(dialog->rtp, dialog->rtpkeepalive); - ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE)); @@ -7752,6 +7753,15 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_ return res; } +enum sip_media_fds { + SIP_AUDIO_RTP_FD, + SIP_AUDIO_RTCP_FD, + SIP_VIDEO_RTP_FD, + SIP_VIDEO_RTCP_FD, + SIP_TEXT_RTP_FD, + SIP_UDPTL_FD, +}; + /*! * \internal * \brief Create and initialize UDPTL for the specified dialog @@ -7780,7 +7790,7 @@ static int initialize_udptl(struct sip_pvt *p) /* T38 can be supported by this dialog, create it and set the derived properties */ if ((p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &bindaddr))) { if (p->owner) { - ast_channel_set_fd(p->owner, 5, ast_udptl_fd(p->udptl)); + ast_channel_set_fd(p->owner, SIP_UDPTL_FD, ast_udptl_fd(p->udptl)); } ast_udptl_setqos(p->udptl, global_tos_audio, global_cos_audio); @@ -8206,20 +8216,28 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit * UDPTL is created as needed in the lifetime of a dialog, its file * descriptor is set in initialize_udptl */ if (i->rtp) { - ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0)); - ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1)); + ast_channel_set_fd(tmp, SIP_AUDIO_RTP_FD, ast_rtp_instance_fd(i->rtp, 0)); + if (ast_test_flag(&i->flags[2], SIP_PAGE3_RTCP_MUX)) { + ast_channel_set_fd(tmp, SIP_AUDIO_RTCP_FD, -1); + } else { + ast_channel_set_fd(tmp, SIP_AUDIO_RTCP_FD, ast_rtp_instance_fd(i->rtp, 1)); + } ast_rtp_instance_set_write_format(i->rtp, fmt); ast_rtp_instance_set_read_format(i->rtp, fmt); } if (needvideo && i->vrtp) { - ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0)); - ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1)); + ast_channel_set_fd(tmp, SIP_VIDEO_RTP_FD, ast_rtp_instance_fd(i->vrtp, 0)); + if (ast_test_flag(&i->flags[2], SIP_PAGE3_RTCP_MUX)) { + ast_channel_set_fd(tmp, SIP_VIDEO_RTCP_FD, -1); + } else { + ast_channel_set_fd(tmp, SIP_VIDEO_RTCP_FD, ast_rtp_instance_fd(i->vrtp, 1)); + } } if (needtext && i->trtp) { - ast_channel_set_fd(tmp, 4, ast_rtp_instance_fd(i->trtp, 0)); + ast_channel_set_fd(tmp, SIP_TEXT_RTP_FD, ast_rtp_instance_fd(i->trtp, 0)); } if (i->udptl) { - ast_channel_set_fd(tmp, 5, ast_udptl_fd(i->udptl)); + ast_channel_set_fd(tmp, SIP_UDPTL_FD, ast_udptl_fd(i->udptl)); } if (state == AST_STATE_RING) { @@ -10074,6 +10092,42 @@ static int has_media_stream(struct sip_pvt *p, enum media_type m) return 0; } +static void configure_rtcp(struct sip_pvt *p, struct ast_rtp_instance *instance, int which, int remote_rtcp_mux) +{ + int local_rtcp_mux = ast_test_flag(&p->flags[2], SIP_PAGE3_RTCP_MUX); + int fd = -1; + + if (local_rtcp_mux && remote_rtcp_mux) { + ast_rtp_instance_set_prop(instance, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX); + } else { + ast_rtp_instance_set_prop(instance, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); + fd = ast_rtp_instance_fd(instance, 1); + } + + if (p->owner) { + ast_channel_set_fd(p->owner, which, fd); + } +} + +static void set_ice_components(struct sip_pvt *p, struct ast_rtp_instance *instance, int remote_rtcp_mux) +{ + struct ast_rtp_engine_ice *ice; + int local_rtcp_mux = ast_test_flag(&p->flags[2], SIP_PAGE3_RTCP_MUX); + + ice = ast_rtp_instance_get_ice(instance); + if (!ice) { + return; + } + + if (local_rtcp_mux && remote_rtcp_mux) { + /* We both support RTCP mux. Only one ICE component necessary */ + ice->change_components(instance, 1); + } else { + /* They either don't support RTCP mux or we don't know if they do yet. */ + ice->change_components(instance, 2); + } +} + /*! \brief Process SIP SDP offer, select formats and activate media channels If offer is rejected, we will not change any properties of the call Return 0 on success, a negative value on errors. @@ -10132,6 +10186,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action int secure_audio = FALSE; int secure_video = FALSE; + /* RTCP Multiplexing */ + int remote_rtcp_mux_audio = FALSE; + int remote_rtcp_mux_video = FALSE; + /* Others */ int sendonly = -1; unsigned int numberofports; @@ -10662,6 +10720,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } } else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec)) { processed = TRUE; + } else if (process_sdp_a_rtcp_mux(value, p, &remote_rtcp_mux_audio)) { + processed = TRUE; } } /* Video specific scanning */ @@ -10683,6 +10743,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } } else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec)) { processed = TRUE; + } else if (process_sdp_a_rtcp_mux(value, p, &remote_rtcp_mux_video)) { + processed = TRUE; } } /* Text (T.140) specific scanning */ @@ -10857,6 +10919,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action if (sa && portno > 0) { /* Start ICE negotiation here, only when it is response, and setting that we are conrolling agent, as we are offerer */ + set_ice_components(p, p->rtp, remote_rtcp_mux_audio); if (req->method == SIP_RESPONSE) { start_ice(p->rtp, 1); } @@ -10870,11 +10933,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_rtp_codecs_payloads_copy(&newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp); /* Ensure RTCP is enabled since it may be inactive if we're coming back from a T.38 session */ - ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1); - /* Ensure audio RTCP reads are enabled */ - if (p->owner) { - ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1)); - } + configure_rtcp(p, p->rtp, SIP_AUDIO_RTCP_FD, remote_rtcp_mux_audio); if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) { ast_clear_flag(&p->flags[0], SIP_DTMF); @@ -10897,10 +10956,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Prevent audio RTCP reads */ if (p->owner) { - ast_channel_set_fd(p->owner, 1, -1); + ast_channel_set_fd(p->owner, SIP_AUDIO_RTCP_FD, -1); } /* Silence RTCP while audio RTP is inactive */ - ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 0); + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_DISABLED); } else { ast_rtp_instance_stop(p->rtp); if (debug) @@ -10911,6 +10970,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Setup video address and port */ if (p->vrtp) { if (vsa && vportno > 0) { + set_ice_components(p, p->vrtp, remote_rtcp_mux_video); start_ice(p->vrtp, (req->method != SIP_RESPONSE) ? 0 : 1); ast_sockaddr_set_port(vsa, vportno); ast_rtp_instance_set_remote_address(p->vrtp, vsa); @@ -10919,6 +10979,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_sockaddr_stringify(vsa)); } ast_rtp_codecs_payloads_copy(&newvideortp, ast_rtp_instance_get_codecs(p->vrtp), p->vrtp); + configure_rtcp(p, p->vrtp, SIP_VIDEO_RTCP_FD, remote_rtcp_mux_video); } else { ast_rtp_instance_stop(p->vrtp); if (debug) @@ -11265,6 +11326,18 @@ static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_in return found; } +static int process_sdp_a_rtcp_mux(const char *a, struct sip_pvt *p, int *requested) +{ + int found = FALSE; + + if (!strncasecmp(a, "rtcp-mux", 8)) { + *requested = TRUE; + found = TRUE; + } + + return found; +} + static int process_sdp_a_dtls(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance) { struct ast_rtp_engine_dtls *dtls; @@ -13632,6 +13705,12 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int add_dtls_to_sdp(p->rtp, &a_audio); } + + /* If we've got rtcp-mux enabled, just unconditionally offer it in all SDPs */ + if (ast_test_flag(&p->flags[2], SIP_PAGE3_RTCP_MUX)) { + ast_str_append(&a_audio, 0, "a=rtcp-mux\r\n"); + ast_str_append(&a_video, 0, "a=rtcp-mux\r\n"); + } } if (add_t38) { @@ -13999,18 +14078,18 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old if (p->rtp) { if (t38version) { /* Silence RTCP while audio RTP is inactive */ - ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 0); + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_DISABLED); if (p->owner) { /* Prevent audio RTCP reads */ - ast_channel_set_fd(p->owner, 1, -1); + ast_channel_set_fd(p->owner, SIP_AUDIO_RTCP_FD, -1); } } else if (ast_sockaddr_isnull(&p->redirip)) { /* Enable RTCP since it will be inactive if we're coming back * with this reinvite */ - ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); if (p->owner) { /* Enable audio RTCP reads */ - ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1)); + ast_channel_set_fd(p->owner, SIP_AUDIO_RTCP_FD, ast_rtp_instance_fd(p->rtp, 1)); } } } @@ -21021,6 +21100,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct ast_cli(fd, " Parkinglot : %s\n", peer->parkinglot); ast_cli(fd, " Use Reason : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_Q850_REASON))); ast_cli(fd, " Encryption : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP))); + ast_cli(fd, " RTCP Mux : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[2], SIP_PAGE3_RTCP_MUX))); ast_cli(fd, "\n"); peer = sip_unref_peer(peer, "sip_show_peer: sip_unref_peer: done with peer ptr"); } else if (peer && type == 1) { /* manager listing */ @@ -21091,6 +21171,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct astman_append(s, "SIP-Sess-Min: %d\r\n", peer->stimer.st_min_se); astman_append(s, "SIP-RTP-Engine: %s\r\n", peer->engine); astman_append(s, "SIP-Encryption: %s\r\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP) ? "Y" : "N"); + astman_append(s, "SIP-RTCP-Mux: %s\r\n", ast_test_flag(&peer->flags[2], SIP_PAGE3_RTCP_MUX) ? "Y" : "N"); /* - is enumerated */ astman_append(s, "SIP-DTMFmode: %s\r\n", dtmfmode2str(ast_test_flag(&peer->flags[0], SIP_DTMF))); @@ -21719,6 +21800,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, " MOH Interpret: %s\n", default_mohinterpret); ast_cli(a->fd, " MOH Suggest: %s\n", default_mohsuggest); ast_cli(a->fd, " Voice Mail Extension: %s\n", default_vmexten); + ast_cli(a->fd, " RTCP Multiplexing: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[2], SIP_PAGE3_RTCP_MUX))); if (realtimepeers || realtimeregs) { @@ -30787,6 +30869,9 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask } else if (!strcasecmp(v->name, "buggymwi")) { ast_set_flag(&mask[1], SIP_PAGE2_BUGGY_MWI); ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_BUGGY_MWI); + } else if (!strcasecmp(v->name, "rtcp_mux")) { + ast_set_flag(&mask[2], SIP_PAGE3_RTCP_MUX); + ast_set2_flag(&flags[2], ast_true(v->value), SIP_PAGE3_RTCP_MUX); } else res = 0; @@ -33418,9 +33503,9 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i if (p->rtp) { /* Prevent audio RTCP reads */ - ast_channel_set_fd(chan, 1, -1); + ast_channel_set_fd(chan, SIP_AUDIO_RTCP_FD, -1); /* Silence RTCP while audio RTP is inactive */ - ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 0); + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_DISABLED); } } else if (!ast_sockaddr_isnull(&p->redirip)) { memset(&p->redirip, 0, sizeof(p->redirip)); @@ -33432,9 +33517,9 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i if (p->vrtp) { /* Prevent video RTCP reads */ - ast_channel_set_fd(chan, 3, -1); + ast_channel_set_fd(chan, SIP_VIDEO_RTCP_FD, -1); /* Silence RTCP while video RTP is inactive */ - ast_rtp_instance_set_prop(p->vrtp, AST_RTP_PROPERTY_RTCP, 0); + ast_rtp_instance_set_prop(p->vrtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_DISABLED); } } else if (!ast_sockaddr_isnull(&p->vredirip)) { memset(&p->vredirip, 0, sizeof(p->vredirip)); @@ -33443,9 +33528,9 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i if (p->vrtp) { /* Enable RTCP since it will be inactive if we're coming back * from a reinvite */ - ast_rtp_instance_set_prop(p->vrtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(p->vrtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); /* Enable video RTCP reads */ - ast_channel_set_fd(chan, 3, ast_rtp_instance_fd(p->vrtp, 1)); + ast_channel_set_fd(chan, SIP_VIDEO_RTCP_FD, ast_rtp_instance_fd(p->vrtp, 1)); } } diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index e511d139b02..86f8967c402 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -384,11 +384,12 @@ #define SIP_PAGE3_IGNORE_PREFCAPS (1 << 7) /*!< DP: Ignore prefcaps when setting up an outgoing call leg */ #define SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL (1 << 8) /*!< DGP: Stop telling the peer to start music on hold */ #define SIP_PAGE3_FORCE_AVP (1 << 9) /*!< DGP: Force 'RTP/AVP' for all streams, even DTLS */ +#define SIP_PAGE3_RTCP_MUX (1 << 10) /*!< DGP: Attempt to negotiate RFC 5761 RTCP multiplexing */ #define SIP_PAGE3_FLAGS_TO_COPY \ (SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32 | SIP_PAGE3_NAT_AUTO_RPORT | SIP_PAGE3_NAT_AUTO_COMEDIA | \ SIP_PAGE3_DIRECT_MEDIA_OUTGOING | SIP_PAGE3_USE_AVPF | SIP_PAGE3_ICE_SUPPORT | SIP_PAGE3_IGNORE_PREFCAPS | \ - SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL | SIP_PAGE3_FORCE_AVP) + SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL | SIP_PAGE3_FORCE_AVP | SIP_PAGE3_RTCP_MUX) #define CHECK_AUTH_BUF_INITLEN 256 diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample index 916e2d67173..9b52ec06c0d 100644 --- a/configs/samples/sip.conf.sample +++ b/configs/samples/sip.conf.sample @@ -1090,6 +1090,8 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; option may be specified at the global or peer scope. ;force_avp=yes ; Force 'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', and 'RTP/SAVPF' to be used for ; media streams when appropriate, even if a DTLS stream is present. +;rtcp_mux=yes ; Enable support for RFC 5761 RTCP multiplexing which is required for + ; WebRTC support ; ---------------------------------------- REALTIME SUPPORT ------------------------ ; For additional information on ARA, the Asterisk Realtime Architecture, ; please read https://wiki.asterisk.org/wiki/display/AST/Realtime+Database+Configuration From c13ea6080ee21531f6aefc114bab1da835b79ccc Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 16 Mar 2017 09:42:54 -0400 Subject: [PATCH 1135/1578] app_queue: Fix locking behavior in stasis message handlers The queue_stasis_data structure contains various mutable fields that require appropriate locking. Specifically, the 'dying,' 'member_uniqueid,' and 'caller_uniqueid' fields need to be locked when read from or written to. Change-Id: I246b7dbff8447acc957a1299f6ad0ebd0fd39088 --- apps/app_queue.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index c0de00173e1..3886b7c7adc 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5948,6 +5948,7 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, { struct queue_stasis_data *queue_data = userdata; struct ast_bridge_blob *enter_blob = stasis_message_data(msg); + SCOPED_AO2LOCK(lock, queue_data); if (queue_data->dying) { return; @@ -6011,7 +6012,7 @@ static void handle_bridge_left(void *userdata, struct stasis_subscription *sub, ast_debug(3, "Detected redirect of queue caller channel %s\n", caller_snapshot->name); - ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, + ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername, "COMPLETECALLER", "%ld|%ld|%d", (long) (queue_data->starttime - queue_data->holdstart), (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos); @@ -6047,16 +6048,17 @@ static void handle_blind_transfer(void *userdata, struct stasis_subscription *su RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup); - if (queue_data->dying) { - return; - } - if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) { return; } ao2_lock(queue_data); + if (queue_data->dying) { + ao2_unlock(queue_data); + return; + } + if (ast_strlen_zero(queue_data->bridge_uniqueid) || strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) { ao2_unlock(queue_data); @@ -6104,10 +6106,6 @@ static void handle_attended_transfer(void *userdata, struct stasis_subscription RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup); - if (queue_data->dying) { - return; - } - if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS || atxfer_msg->dest_type == AST_ATTENDED_TRANSFER_DEST_THREEWAY) { return; @@ -6115,6 +6113,11 @@ static void handle_attended_transfer(void *userdata, struct stasis_subscription ao2_lock(queue_data); + if (queue_data->dying) { + ao2_unlock(queue_data); + return; + } + if (ast_strlen_zero(queue_data->bridge_uniqueid)) { ao2_unlock(queue_data); return; @@ -6298,12 +6301,13 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub, RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup); enum agent_complete_reason reason; + ao2_lock(queue_data); + if (queue_data->dying) { + ao2_unlock(queue_data); return; } - ao2_lock(queue_data); - if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) { reason = CALLER; } else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->member_uniqueid)) { @@ -6332,7 +6336,7 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub, ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member", channel_blob->snapshot->name); - ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, + ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername, reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d", (long) (queue_data->starttime - queue_data->holdstart), (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos); From 8cb4f9cea1f8a34d2383551a971a86d3be02c4fd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 22 Feb 2017 23:26:13 -0600 Subject: [PATCH 1136/1578] CHANNEL(callid): Give dialplan access to the callid. * Added CHANNEL(callid) to retrieve the call identifier log tag associated with the channel. Dialplan now has access to the call log search key associated with the channel so it can be saved in case there is a problem with the call. ASTERISK-26878 Change-Id: I2c97ebd928b6f3c5bc80c5729e4d3c07f453049f --- CHANGES | 7 +++++++ funcs/func_channel.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/CHANGES b/CHANGES index e391d1e1749..ea67101eaac 100644 --- a/CHANGES +++ b/CHANGES @@ -118,6 +118,13 @@ app_voicemail * Added 'fromstring' field to the voicemail boxes. If set, it will override the global 'fromstring' field on a per-mailbox basis. +func_channel +------------------ + * Added CHANNEL(callid) to retrieve the call log tag associated with the + channel. e.g., [C-00000000] Dialplan now has access to the call log + search key associated with the channel so it can be saved in case there + is a problem with the call. + res_pjsip ------------------ * A new transport parameter 'symmetric_transport' has been added. diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 27e9f41bf7d..eb3ceddb45a 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -233,6 +233,10 @@ R/W The maximum number of forwards allowed. + + R/O Call identifier log tag associated with the channel + e.g., [C-00000000]. + @@ -450,6 +454,16 @@ static int func_channel_read(struct ast_channel *chan, const char *function, ast_channel_lock(chan); snprintf(buf, len, "%d", ast_max_forwards_get(chan)); ast_channel_unlock(chan); + } else if (!strcasecmp(data, "callid")) { + ast_callid callid; + + buf[0] = '\0'; + ast_channel_lock(chan); + callid = ast_channel_callid(chan); + if (callid) { + ast_callid_strnprint(buf, len, callid); + } + ast_channel_unlock(chan); } else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; From 79069f8ccb45d844afdeb98f64107e4ebf0f4cbc Mon Sep 17 00:00:00 2001 From: Robert Mordec Date: Tue, 14 Mar 2017 15:27:56 +0100 Subject: [PATCH 1137/1578] app_queue: Member stuck as pending after forwarding previous call from queue Queue member will get stuck in pending_members if queue calls a device that is different from the one observed for state changes. This patch removes members from pending_members as a result of channel stasis events such as blind or attended transfers and hangup. ASTERISK-26862 #close Change-Id: I8bf6df487b9bb35726c08049ff25cdad5e357727 --- apps/app_queue.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index c0de00173e1..36e005e36dd 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5574,6 +5574,13 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom member->membername, (long)member->lastcall); ao2_unlock(q); } + /* Member might never experience any direct status change (local + * channel with forwarding in particular). If that's the case, + * this is the last chance to remove it from pending or subsequent + * calls will not occur. + */ + pending_members_remove(member); + ao2_lock(q); q->callscompleted++; if (callcompletedinsl) { From 516e028b44518738dc7bd9534aab153cf11f44cb Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sun, 19 Mar 2017 14:26:38 -0400 Subject: [PATCH 1138/1578] res_rtp_asterisk: Pass correct data length to ast_rtcp_interpret We are currently passing in the capacity of the read buffer instead of the number of bytes that we actually read off the wire. Change-Id: I60465049727d955c7f9a5e529e6f2aaff04cda36 --- res/res_rtp_asterisk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 251227a2612..88201837d36 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4426,7 +4426,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) return &ast_null_frame; } - if (!*(read_area)) { + if (!*read_area) { struct sockaddr_in addr_tmp; struct ast_sockaddr addr_v4; @@ -4448,7 +4448,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) return &ast_null_frame; } - return ast_rtcp_interpret(instance, read_area, read_area_size, &addr); + return ast_rtcp_interpret(instance, read_area, res, &addr); } static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int *rtpheader, int len, int hdrlen) @@ -4633,7 +4633,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* This could be a multiplexed RTCP packet. If so, be sure to interpret it correctly */ if (rtcp_mux(rtp, read_area)) { - return ast_rtcp_interpret(instance, read_area, read_area_size, &addr); + return ast_rtcp_interpret(instance, read_area, res, &addr); } /* Make sure the data that was read in is actually enough to make up an RTP packet */ From fc71c18a9b572296e171eb6b1f87aee5c2256c8c Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sat, 18 Mar 2017 13:30:32 -0400 Subject: [PATCH 1139/1578] thread safety: Don't use getprotobyname() POSIX does not require getprotobyname() to be thread safe and some implementations use static memory which causes issues when multiple threads are used. Further, our usage of it today is just to ultimately get IPPROTO_TCP for calls to setsockopt(). So instead we just use IPPROTO_TCP directly. Change-Id: I2e14e58674808f7ce99b2f5e900d0f90d0d8da48 --- channels/chan_skinny.c | 9 +++------ include/asterisk/network.h | 5 +++++ main/http.c | 3 +-- main/manager.c | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index a3a2f87fbe6..d1c2b927a61 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -7639,7 +7639,6 @@ static void *accept_thread(void *ignore) struct sockaddr_in sin; socklen_t sinlen; struct skinnysession *s; - struct protoent *p; int arg = 1; for (;;) { @@ -7656,12 +7655,10 @@ static void *accept_thread(void *ignore) continue; } - p = getprotobyname("tcp"); - if(p) { - if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) { - ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno)); - } + if (setsockopt(as, IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg)) < 0) { + ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on Skinny TCP connection: %s\n", strerror(errno)); } + if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) { close(as); ast_atomic_fetchadd_int(&unauth_sessions, -1); diff --git a/include/asterisk/network.h b/include/asterisk/network.h index 3371e58952f..5216f4c61a2 100644 --- a/include/asterisk/network.h +++ b/include/asterisk/network.h @@ -86,6 +86,11 @@ const char *ast_inet_ntoa(struct in_addr ia); #endif #define inet_ntoa __dont__use__inet_ntoa__use__ast_inet_ntoa__instead__ +#ifdef getprotobyname +#undef getprotobyname +#endif +#define getprotobyname __getprotobyname_is_not_threadsafe__do_not_use__ + /*! \brief Compares the source address and port of two sockaddr_in */ static force_inline int inaddrcmp(const struct sockaddr_in *sin1, const struct sockaddr_in *sin2) { diff --git a/main/http.c b/main/http.c index 0db6ee7b66f..ea85a282364 100644 --- a/main/http.c +++ b/main/http.c @@ -1917,9 +1917,8 @@ static void *httpd_helper_thread(void *data) * This is necessary to prevent delays (caused by buffering) as we * write to the socket in bits and pieces. */ - if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg) ) < 0) { + if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg)) < 0) { ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno)); - ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n"); } ast_iostream_nonblock(ser->stream); diff --git a/main/manager.c b/main/manager.c index eae1ca52afd..c1d73dce763 100644 --- a/main/manager.c +++ b/main/manager.c @@ -6647,8 +6647,8 @@ static void *session_do(void *data) /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm. * This is necessary to prevent delays (caused by buffering) as we * write to the socket in bits and pieces. */ - if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0) { - ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\nSome manager actions may be slow to respond.\n", strerror(errno)); + if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg)) < 0) { + ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on manager connection: %s\n", strerror(errno)); } ast_iostream_nonblock(ser->stream); From 25016a74f8446137c1b92cb6bc33275d4d43a662 Mon Sep 17 00:00:00 2001 From: Aaron An Date: Wed, 15 Mar 2017 12:49:12 +0800 Subject: [PATCH 1140/1578] audiohook.c: Lost RTP packets lead to out-of-sync MixMonitor. Fixed a bug in function "ast_audiohook_write_frame" that checked the variable other_factory_samples and only flushed the factories, so they would be in sync, when other_factory_samples > 0. When there is not any rtp incoming the variable other_factory_samples will be 0, and although the result of "our_factory_ms - other_factory_ms" may be very large, this led to the record file not syncing. ASTERISK-26875 #close Reported-by: Aaron An Tested-by: Aaron An Change-Id: Ia4d890fb8fc1636a7188502bab35f555685aea22 --- main/audiohook.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/audiohook.c b/main/audiohook.c index 836ae0496fd..986f11f846f 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -185,7 +185,7 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo other_factory_samples = ast_slinfactory_available(other_factory); other_factory_ms = other_factory_samples / (audiohook->hook_internal_samp_rate / 1000); - if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) { + if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) { ast_debug(1, "Flushing audiohook %p so it remains in sync\n", audiohook); ast_slinfactory_flush(factory); ast_slinfactory_flush(other_factory); From fc794de75658a26383dd93278f2b04b13bc3f65b Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 20 Mar 2017 17:27:24 -0400 Subject: [PATCH 1141/1578] bridge_softmix: Ignore non-voice frames from translator Some codecs - codec_speex specifically - take voice frames and return other types of frames, like CNG. If we subsequently treat those as voice frames, we'll run into trouble when destroying the frame because of the requirement that each voice frame have an associated format. ASTERISK-26880 #close Reported by: Kirsty Tyerman Change-Id: I43f8450c48fb276ad8b99db8512be82949c1ca7c --- bridges/bridge_softmix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 7bac4fcb2a3..94dfc571429 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -222,7 +222,8 @@ static void softmix_process_write_audio(struct softmix_translate_helper *trans_h if (entry->trans_pvt && !entry->out_frame) { entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0); } - if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) { + if (entry->out_frame && entry->out_frame->frametype == AST_FRAME_VOICE + && entry->out_frame->datalen < MAX_DATALEN) { ao2_replace(sc->write_frame.subclass.format, entry->out_frame->subclass.format); memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen); sc->write_frame.datalen = entry->out_frame->datalen; From 65ad554c980ed0fa3560de57e6b268a55f7b9bc5 Mon Sep 17 00:00:00 2001 From: Joshua Elson Date: Mon, 13 Mar 2017 14:21:23 -0600 Subject: [PATCH 1142/1578] pjsip: prevent memory corruption on creation of xml bodies ASTERISK-26776 #close Change-Id: I884b6f4e8233a355d0be687ec78d41bc0e4d3fd2 --- .../patches/0025-fix-print-xml-crash.patch | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 third-party/pjproject/patches/0025-fix-print-xml-crash.patch diff --git a/third-party/pjproject/patches/0025-fix-print-xml-crash.patch b/third-party/pjproject/patches/0025-fix-print-xml-crash.patch new file mode 100644 index 00000000000..eafc3890614 --- /dev/null +++ b/third-party/pjproject/patches/0025-fix-print-xml-crash.patch @@ -0,0 +1,24 @@ +From 1bc5ca699f523bd8e910203a3eb4dee58f366976 Mon Sep 17 00:00:00 2001 +From: Joshua Elson +Date: Mon, 20 Mar 2017 19:28:47 -0600 +Subject: [PATCH] Prevent memory corruption on xml tag write + +--- + pjlib-util/src/pjlib-util/xml.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/pjlib-util/src/pjlib-util/xml.c b/pjlib-util/src/pjlib-util/xml.c +index 296b232..b0aad26 100644 +--- a/pjlib-util/src/pjlib-util/xml.c ++++ b/pjlib-util/src/pjlib-util/xml.c +@@ -248,6 +248,7 @@ static int xml_print_node( const pj_xml_node *node, int indent, + if (node->content.slen==0 && + node->node_head.next==(pj_xml_node*)&node->node_head) + { ++ if (SIZE_LEFT() < 3) return -1; + *p++ = ' '; + *p++ = '/'; + *p++ = '>'; +-- +2.10.1 (Apple Git-78) + From 6b4b87787c0735bfe63445d625e2e8749a7caecb Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 21 Mar 2017 09:26:28 -0400 Subject: [PATCH 1143/1578] res_pjsip_messaging: Check URI type before dereferencing We aren't validating that the URI we just parsed is a SIP/SIPS one before trying to access the user, host, and port members of a possibly uninitialized structure. Also update the MessageSend documentation to indicate what 'from' formats are accepted. ASTERISK-26484 #close Reported by: Vinod Dharashive Change-Id: I476b5cc5f18a7713d0ee945374f2a1c164857d30 --- main/message.c | 6 ++++-- res/res_pjsip_messaging.c | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/main/message.c b/main/message.c index a6b04882824..fcdf705fe40 100644 --- a/main/message.c +++ b/main/message.c @@ -125,8 +125,10 @@ A From URI for the message if needed for the - message technology being used to send this message. - + message technology being used to send this message. This can be a + SIP(S) URI, such as Alice <sip:alice@atlanta.com>, + a string in the format alice@atlanta.com, or simply + a username such as alice. diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index 52fc16da773..5c41a70562d 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -235,7 +235,15 @@ static void update_from(pjsip_tx_data *tdata, char *from) parsed_name_addr = (pjsip_name_addr *) pjsip_parse_uri(tdata->pool, from, strlen(from), PJSIP_PARSE_URI_AS_NAMEADDR); if (parsed_name_addr) { - pjsip_sip_uri *parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri); + pjsip_sip_uri *parsed_uri; + + if (!PJSIP_URI_SCHEME_IS_SIP(parsed_name_addr->uri) + && !PJSIP_URI_SCHEME_IS_SIPS(parsed_name_addr->uri)) { + ast_log(LOG_WARNING, "From address '%s' is not a valid SIP/SIPS URI\n", from); + return; + } + + parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri); if (pj_strlen(&parsed_name_addr->display)) { pj_strdup(tdata->pool, &name_addr->display, &parsed_name_addr->display); From 1bf839d44b81e31595635acaa206bd028ebce10c Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 21 Mar 2017 08:57:46 -0600 Subject: [PATCH 1144/1578] Revert "app_queue: Handle the caller being redirected out of a queue bridge" This reverts commit 163e9e53dc7d84dd42721e733b7706c8147bdd27. Change-Id: Ief28479c77a298879dfe2c56be7ee92dc465da4b --- apps/app_queue.c | 63 ------------------------------------------------ 1 file changed, 63 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 3886b7c7adc..ad6364cc974 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5966,67 +5966,6 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, } } -/*! - * \internal - * \brief Handle a stasis bridge leave event. - * - * We track this event to determine if the caller has left the bridge - * as the result of a redirect. Transfers and hangups are handled in - * separate functions. - * - * \param userdata Data pertaining to the particular call in the queue. - * \param sub The stasis subscription on which the message occurred. - * \param msg The stasis message for the bridge leave event - */ -static void handle_bridge_left(void *userdata, struct stasis_subscription *sub, - struct stasis_message *msg) -{ - struct queue_stasis_data *queue_data = userdata; - struct ast_bridge_blob *left_blob = stasis_message_data(msg); - struct ast_channel_snapshot *caller_snapshot, *member_snapshot; - - ao2_lock(queue_data); - - if (queue_data->dying) { - ao2_unlock(queue_data); - return; - } - - if (ast_strlen_zero(queue_data->bridge_uniqueid)) { - ao2_unlock(queue_data); - return; - } - - /* Correct channel, correct bridge? */ - if (strcmp(left_blob->channel->uniqueid, queue_data->caller_uniqueid) - || strcmp(left_blob->bridge->uniqueid, queue_data->bridge_uniqueid)) { - ao2_unlock(queue_data); - return; - } - - caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid); - member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid); - - ao2_unlock(queue_data); - - ast_debug(3, "Detected redirect of queue caller channel %s\n", - caller_snapshot->name); - - ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername, - "COMPLETECALLER", "%ld|%ld|%d", - (long) (queue_data->starttime - queue_data->holdstart), - (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos); - - send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member, - queue_data->holdstart, queue_data->starttime, CALLER); - update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl, - time(NULL) - queue_data->starttime); - remove_stasis_subscriptions(queue_data); - - ao2_cleanup(member_snapshot); - ao2_cleanup(caller_snapshot); -} - /*! * \brief Handle a blind transfer event * @@ -6397,8 +6336,6 @@ static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, str stasis_message_router_add(queue_data->bridge_router, ast_channel_entered_bridge_type(), handle_bridge_enter, queue_data); - stasis_message_router_add(queue_data->bridge_router, ast_channel_left_bridge_type(), - handle_bridge_left, queue_data); stasis_message_router_add(queue_data->bridge_router, ast_blind_transfer_type(), handle_blind_transfer, queue_data); stasis_message_router_add(queue_data->bridge_router, ast_attended_transfer_type(), From d4fcf196a20b3141a10c0cd5b84f09b367e8f7e3 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 21 Mar 2017 07:59:12 -0400 Subject: [PATCH 1145/1578] res_hep: Capture actual transport type in use Rather than hard-coding UDP, allow consumers of the HEP API to specify which protocol is in use. Update the PJSIP provider to pass in the current protocol type. ASTERISK-26850 #close Change-Id: I54bbb0a001cfe4c6a87ad4b6f2014af233349978 --- include/asterisk/res_hep.h | 2 ++ res/res_hep.c | 5 ++++- res/res_hep_pjsip.c | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/asterisk/res_hep.h b/include/asterisk/res_hep.h index cfd213ad7b4..dba86e88b33 100644 --- a/include/asterisk/res_hep.h +++ b/include/asterisk/res_hep.h @@ -72,6 +72,8 @@ struct hepv3_capture_info { size_t len; /*! If non-zero, the payload accompanying this capture info will be compressed */ unsigned int zipped:1; + /*! The IPPROTO_* protocol where we captured the packet */ + int protocol_id; }; /*! diff --git a/res/res_hep.c b/res/res_hep.c index 3bbf4c51ebc..41a55814158 100644 --- a/res/res_hep.c +++ b/res/res_hep.c @@ -439,6 +439,9 @@ struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t memcpy(info->payload, payload, len); info->len = len; + /* Set a reasonable default */ + info->protocol_id = IPPROTO_UDP; + return info; } @@ -470,7 +473,7 @@ static int hep_queue_cb(void *data) /* Build HEPv3 header, capture info, and calculate the total packet size */ memcpy(hg_pkt.header.id, "\x48\x45\x50\x33", 4); - INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, 0x11); + INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, capture_info->protocol_id); INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.src_port, CHUNK_TYPE_SRC_PORT, htons(ast_sockaddr_port(&capture_info->src_addr))); INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.dst_port, CHUNK_TYPE_DST_PORT, htons(ast_sockaddr_port(&capture_info->dst_addr))); INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_sec, CHUNK_TYPE_TIMESTAMP_SEC, htonl(capture_info->capture_time.tv_sec)); diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index 358cbc934e1..13efbfa6afa 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -71,6 +71,15 @@ static char *assign_uuid(const pj_str_t *call_id, const pj_str_t *local_tag, con return uuid; } +static int transport_to_protocol_id(pjsip_transport *tp) +{ + /* XXX If we ever add SCTP support, we'll need to revisit */ + if (tp->flag & PJSIP_TRANSPORT_RELIABLE) { + return IPPROTO_TCP; + } + return IPPROTO_UDP; +} + static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) { char local_buf[256]; @@ -124,6 +133,7 @@ static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE); + capture_info->protocol_id = transport_to_protocol_id(tdata->tp_info.transport); capture_info->capture_time = ast_tvnow(); capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP; capture_info->uuid = uuid; @@ -183,6 +193,8 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) ast_sockaddr_parse(&capture_info->src_addr, remote_buf, PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, local_buf, PARSE_PORT_REQUIRE); + + capture_info->protocol_id = transport_to_protocol_id(rdata->tp_info.transport); capture_info->capture_time.tv_sec = rdata->pkt_info.timestamp.sec; capture_info->capture_time.tv_usec = rdata->pkt_info.timestamp.msec * 1000; capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP; From 6b7697ed486fc3a8e5e7a72344437e66bd4ae507 Mon Sep 17 00:00:00 2001 From: Richard Begg Date: Wed, 15 Mar 2017 08:45:06 +1100 Subject: [PATCH 1146/1578] res_pjsip_session: Enable RFC3578 overlap dialing support. Support for RFC3578 overlap dialling (i.e. 484 Response to partially matched destinations) as currently provided by chan_sip is missing from res_pjsip. This patch adds a new endpoint attribute (allow_overlap) [defaults to yes] which when set to yes enables 484 responses to partial destination matches rather than the current 404. ASTERISK-26864 Change-Id: Iea444da3ee7c7d4f1fde1d01d138a3d7b0fe40f6 --- CHANGES | 4 +++ configs/samples/pjsip.conf.sample | 1 + .../8fce4c573e15_add_pjsip_allow_overlap.py | 31 +++++++++++++++++++ include/asterisk/res_pjsip.h | 2 ++ res/res_pjsip.c | 6 ++++ res/res_pjsip/pjsip_configuration.c | 1 + res/res_pjsip_session.c | 24 +++++++++++--- 7 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py diff --git a/CHANGES b/CHANGES index e391d1e1749..244111fe7c0 100644 --- a/CHANGES +++ b/CHANGES @@ -134,6 +134,10 @@ res_pjsip added to both transport and subscription_persistence, an alembic upgrade should be run to bring the database tables up to date. + * A new option, allow_overlap, has been added to endpoints which allows + overlap dialing functionality to be enabled or disabled. The option defaults + to enabled. + res_pjsip_transport_websocket ------------------ * Removed non-secure websocket support. Firefox and Chrome have not allowed diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 120a7ef1c76..bb80768f552 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -595,6 +595,7 @@ ; "yes") ;aggregate_mwi=yes ; (default: "yes") ;allow= ; Media Codec s to allow (default: "") +;allow_overlap=yes ; Enable RFC3578 overlap dialing support. (default: "yes") ;aors= ; AoR s to be used with the endpoint (default: "") ;auth= ; Authentication Object s associated with the endpoint (default: "") ;callerid= ; CallerID information for the endpoint (default: "") diff --git a/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py b/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py new file mode 100644 index 00000000000..24057ecc878 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py @@ -0,0 +1,31 @@ +"""add pjsip allow_overlap + +Revision ID: 8fce4c573e15 +Revises: f638dbe2eb23 +Create Date: 2017-03-21 15:14:27.612945 + +""" + +# revision identifiers, used by Alembic. +revision = '8fce4c573e15' +down_revision = 'f638dbe2eb23' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoints', sa.Column('allow_overlap', yesno_values)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'allow_overlap') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index c6c308beef0..6f44852b1e4 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -765,6 +765,8 @@ struct ast_sip_endpoint { unsigned int preferred_codec_only; /*! Do we allow an asymmetric RTP codec? */ unsigned int asymmetric_rtp_codec; + /*! Do we allow overlap dialling? */ + unsigned int allow_overlap; }; /*! URI parameter for symmetric transport */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 962c4be4f62..e4bcb703826 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -100,6 +100,9 @@ Media Codec(s) to allow + + Enable RFC3578 overlap dialing support. + AoR(s) to be used with the endpoint @@ -2134,6 +2137,9 @@ + + + diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index c8ff42708bd..02562e78273 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1938,6 +1938,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index de073d3048b..5f42dab9f9c 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1986,10 +1986,17 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s return SIP_GET_DEST_EXTEN_FOUND; } - /* XXX In reality, we'll likely have further options so that partial matches - * can be indicated here, but for getting something up and running, we're going - * to return a "not exists" error here. + + /* + * Check for partial match via overlap dialling (if enabled) */ + if (session->endpoint->allow_overlap && ( + !strncmp(session->exten, pickupexten, strlen(session->exten)) || + ast_canmatch_extension(NULL, session->endpoint->context, session->exten, 1, NULL))) { + /* Overlap partial match */ + return SIP_GET_DEST_EXTEN_PARTIAL; + } + return SIP_GET_DEST_EXTEN_NOT_FOUND; } @@ -2106,8 +2113,17 @@ static int new_invite(void *data) pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE); } goto end; - case SIP_GET_DEST_EXTEN_NOT_FOUND: case SIP_GET_DEST_EXTEN_PARTIAL: + ast_debug(1, "Call from '%s' (%s:%s:%d) to extension '%s' - partial match\n", ast_sorcery_object_get_id(invite->session->endpoint), + invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name, invite->rdata->pkt_info.src_port, invite->session->exten); + + if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) { + ast_sip_session_send_response(invite->session, tdata); + } else { + pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE); + } + goto end; + case SIP_GET_DEST_EXTEN_NOT_FOUND: default: ast_log(LOG_NOTICE, "Call from '%s' (%s:%s:%d) to extension '%s' rejected because extension not found in context '%s'.\n", ast_sorcery_object_get_id(invite->session->endpoint), invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name, From bb2936f3e467452c75ff8079d8c0a4eff4c2456a Mon Sep 17 00:00:00 2001 From: Sebastian Gutierrez Date: Tue, 21 Mar 2017 14:32:06 -0300 Subject: [PATCH 1147/1578] cdr: Allow setting of user field from 'h' extension The CDR code previously did not allow the user field to be set from the 'h' extension in the dialplan. This change removes that limitation and allows it to be set. ASTERISK-26818 Change-Id: I0fed8a79b5e408bac4e30542b8f33a61c5ed9aa6 --- main/cdr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 60fe977a886..363a2c6b1ea 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -3251,7 +3251,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flag struct party_b_userfield_update *info = arg; struct cdr_object *it_cdr; for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (it_cdr->fn_table == &finalized_state_fn_table) { + if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) { continue; } if (it_cdr->party_b.snapshot @@ -3275,7 +3275,7 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) if (cdr) { ao2_lock(cdr); for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (it_cdr->fn_table == &finalized_state_fn_table) { + if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) { continue; } strcpy(it_cdr->party_a.userfield, userfield); From 9b103e7bea40c300f89de67cc23c1015fc03db76 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 20 Mar 2017 13:27:31 -0500 Subject: [PATCH 1148/1578] rtp_engine: allocate RTP dynamic payloads per session Dynamic payload types were statically defined in Asterisk. This unfortunately limited the number of dynamic payloads that could be registered. With this patch dynamic payload type numbers are now assigned dynamically and per RTP instance. However, in order to limit any issues where some clients expect the old statically defined value this patch makes it so the value Asterisk used to pre- designate is used for the dynamic assignment if available. An option, "rtp_use_dynamic", has also been added (can be set in asterisk.conf) that turns the new dynamic behavior on or off. When off it reverts back to using statically defined payload values. This option defaults to "yes" in Asterisk 15. ASTERISK-26515 #close patches: ASTERISK-26515.diff submitted by jcolp (license 5000 Change-Id: I7653465c5ebeaf968f1a1cc8f3f4f5c4321da7fc --- CHANGES | 5 + configs/samples/asterisk.conf.sample | 4 + include/asterisk/options.h | 1 + main/asterisk.c | 5 + main/rtp_engine.c | 267 ++++++++++++++++----------- 5 files changed, 174 insertions(+), 108 deletions(-) diff --git a/CHANGES b/CHANGES index e391d1e1749..00f318be8c1 100644 --- a/CHANGES +++ b/CHANGES @@ -62,6 +62,11 @@ RTP when you use more than 32 formats and calls are not accepted by a remote implementation, please report this and go back to rtp_pt_dynamic = 96. + * A new setting, "rtp_use_dynamic", has been added in asterisk.conf". When set + to "yes" RTP dynamic payload types are assigned dynamically per RTP instance. + When set to "no" RTP dynamic payload types are globally initialized to pre- + designated numbers and function similar to static payload types. + app_originate ------------------ * Added support to gosub predial routines on both original channel and on the diff --git a/configs/samples/asterisk.conf.sample b/configs/samples/asterisk.conf.sample index e13a944b06a..30934e4a997 100644 --- a/configs/samples/asterisk.conf.sample +++ b/configs/samples/asterisk.conf.sample @@ -97,6 +97,10 @@ documentation_language = en_US ; Set the language you want documentation ; This is currently is used by DUNDi and ; Exchanging Device and Mailbox State ; using protocols: XMPP, Corosync and PJSIP. +;rtp_use_dynamic = yes ; When set to "yes" RTP dynamic payload types + ; are assigned dynamically per RTP instance vs. + ; allowing Asterisk to globally initialize them + ; to pre-designated numbers (defaults to "yes"). ;rtp_pt_dynamic = 35 ; Normally the Dynamic RTP Payload Type numbers ; are 96-127, which allow just 32 formats. The ; starting point 35 enables the range 35-63 and diff --git a/include/asterisk/options.h b/include/asterisk/options.h index 05ad6c56010..0a20f10a8dd 100644 --- a/include/asterisk/options.h +++ b/include/asterisk/options.h @@ -196,6 +196,7 @@ extern int dahdi_chan_name_len; extern int ast_language_is_prefix; +extern int ast_option_rtpusedynamic; extern unsigned int ast_option_rtpptdynamic; #if defined(__cplusplus) || defined(c_plusplus) diff --git a/main/asterisk.c b/main/asterisk.c index 69183c1f390..68859ab2fad 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -339,6 +339,7 @@ unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */ #if defined(HAVE_SYSINFO) long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */ #endif +int ast_option_rtpusedynamic; unsigned int ast_option_rtpptdynamic; /*! @} */ @@ -602,6 +603,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled"); ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled"); ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration); + ast_cli(a->fd, " RTP use dynamic payloads: %u\n", ast_option_rtpusedynamic); if (ast_option_rtpptdynamic == AST_RTP_PT_LAST_REASSIGN) { ast_cli(a->fd, " RTP dynamic payload types: %u,%u-%u\n", @@ -3499,6 +3501,7 @@ static void ast_readconfig(void) /* Set default value */ option_dtmfminduration = AST_MIN_DTMF_DURATION; + ast_option_rtpusedynamic = 1; ast_option_rtpptdynamic = 35; /* init with buildtime config */ @@ -3655,6 +3658,8 @@ static void ast_readconfig(void) if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) { option_dtmfminduration = AST_MIN_DTMF_DURATION; } + } else if (!strcasecmp(v->name, "rtp_use_dynamic")) { + ast_option_rtpusedynamic = ast_true(v->value); /* http://www.iana.org/assignments/rtp-parameters * RTP dynamic payload types start at 96 normally; extend down to 0 */ } else if (!strcasecmp(v->name, "rtp_pt_dynamic")) { diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 931f89d7cad..00f9d595fcc 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -266,14 +266,28 @@ static void rtp_payload_type_dtor(void *obj) ao2_cleanup(payload->format); } -struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void) +static struct ast_rtp_payload_type *rtp_payload_type_alloc(struct ast_format *format, + int payload, int rtp_code, int primary_mapping) { - struct ast_rtp_payload_type *payload; + struct ast_rtp_payload_type *type = ao2_alloc_options( + sizeof(*type), rtp_payload_type_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); - payload = ao2_alloc_options(sizeof(*payload), rtp_payload_type_dtor, - AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!type) { + return NULL; + } - return payload; + type->format = ao2_bump(format); + type->asterisk_format = type->format != NULL; + type->payload = payload; + type->rtp_code = rtp_code; + type->primary_mapping = primary_mapping; + + return type; +} + +struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void) +{ + return rtp_payload_type_alloc(NULL, 0, 0, 0); } int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module) @@ -1250,31 +1264,112 @@ static int find_static_payload_type(int asterisk_format, const struct ast_format /*! * \internal - * \brief Find the first unused dynamic rx payload type. - * \since 14.0.0 + * \brief Find the first unused payload type in a given range * - * \param codecs Codecs structure to look in + * \param codecs The codec structure to look in + * \param start Starting index + * \param end Ending index + * \param ignore Skip these payloads types * - * \note It is assumed that codecs is at least read locked before calling. + * \note The static_RTP_PT_lock object must be locked before calling * * \retval Numerical payload type * \retval -1 if not found. */ -static int rtp_codecs_find_empty_dynamic_rx(struct ast_rtp_codecs *codecs) +static int find_unused_payload_in_range(const struct ast_rtp_codecs *codecs, + int start, int end, struct ast_rtp_payload_type *ignore[]) { - struct ast_rtp_payload_type *type; - int idx; - int payload = -1; + int x; - idx = AST_RTP_PT_FIRST_DYNAMIC; - for (; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) { - type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx); + for (x = start; x < end; ++x) { + struct ast_rtp_payload_type *type; + + if (ignore[x]) { + continue; + } else if (!codecs || x >= AST_VECTOR_SIZE(&codecs->payload_mapping_rx)) { + return x; + } + + type = AST_VECTOR_GET(&codecs->payload_mapping_rx, x); if (!type) { - payload = idx; - break; + return x; } } - return payload; + return -1; +} + +/*! + * \internal + * \brief Find an unused payload type + * + * \param codecs Codecs structure to look in + * + * \note Both static_RTP_PT_lock and codecs (if given) must be at least + * read locked before calling. + * + * \retval Numerical payload type + * \retval -1 if not found. + */ +static int find_unused_payload(const struct ast_rtp_codecs *codecs) +{ + int res; + + /* find next available dynamic payload slot */ + res = find_unused_payload_in_range( + codecs, AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT, static_RTP_PT); + if (res != -1) { + return res; + } + + if (ast_option_rtpusedynamic) { + /* + * We're using default values for some dynamic types. So if an unused + * slot was not found try again, but this time ignore the default + * values declared for dynamic types (except for 101 and 121) . + */ + static struct ast_rtp_payload_type *ignore[AST_RTP_MAX_PT] = {0}; + + ignore[101] = static_RTP_PT[101]; + ignore[121] = static_RTP_PT[121]; + + res = find_unused_payload_in_range( + codecs, AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT, ignore); + if (res != -1) { + return res; + } + } + + /* http://www.iana.org/assignments/rtp-parameters + * RFC 3551, Section 3: "[...] applications which need to define more + * than 32 dynamic payload types MAY bind codes below 96, in which case + * it is RECOMMENDED that unassigned payload type numbers be used + * first". Updated by RFC 5761, Section 4: "[...] values in the range + * 64-95 MUST NOT be used [to avoid conflicts with RTCP]". Summaries: + * https://tools.ietf.org/html/draft-roach-mmusic-unified-plan#section-3.2.1.2 + * https://tools.ietf.org/html/draft-wu-avtcore-dynamic-pt-usage#section-3 + */ + res = find_unused_payload_in_range(codecs, MAX(ast_option_rtpptdynamic, 35), + AST_RTP_PT_LAST_REASSIGN, static_RTP_PT); + if (res != -1) { + return res; + } + + /* Yet, reusing mappings below 35 is not supported in Asterisk because + * when Compact Headers are activated, no rtpmap is send for those below + * 35. If you want to use 35 and below + * A) do not use Compact Headers, + * B) remove that code in chan_sip/res_pjsip, or + * C) add a flag that this RTP Payload Type got reassigned dynamically + * and requires a rtpmap even with Compact Headers enabled. + */ + res = find_unused_payload_in_range( + codecs, MAX(ast_option_rtpptdynamic, 20), 35, static_RTP_PT); + if (res != -1) { + return res; + } + + return find_unused_payload_in_range( + codecs, MAX(ast_option_rtpptdynamic, 0), 20, static_RTP_PT); } /*! @@ -1331,30 +1426,26 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int struct ast_rtp_payload_type *new_type; payload = find_static_payload_type(asterisk_format, format, code); - if (payload < 0) { + + if (payload < 0 && (!asterisk_format || ast_option_rtpusedynamic)) { return payload; } - new_type = ast_rtp_engine_alloc_payload_type(); + new_type = rtp_payload_type_alloc(format, payload, code, 1); if (!new_type) { return -1; } - new_type->format = ao2_bump(format); - new_type->asterisk_format = asterisk_format; - new_type->rtp_code = code; - new_type->payload = payload; - new_type->primary_mapping = 1; ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_RTP_PT_FIRST_DYNAMIC + if (payload > -1 && (payload < AST_RTP_PT_FIRST_DYNAMIC || AST_VECTOR_SIZE(&codecs->payload_mapping_rx) <= payload - || !AST_VECTOR_GET(&codecs->payload_mapping_rx, payload)) { + || !AST_VECTOR_GET(&codecs->payload_mapping_rx, payload))) { /* * The payload type is a static assignment * or our default dynamic position is available. */ - rtp_codecs_payload_replace_rx(codecs, payload, new_type); - } else if (-1 < (payload = rtp_codecs_find_empty_dynamic_rx(codecs)) + rtp_codecs_payload_replace_rx(codecs, payload, new_type); + } else if (-1 < (payload = find_unused_payload(codecs)) || -1 < (payload = rtp_codecs_find_non_primary_dynamic_rx(codecs))) { /* * We found the first available empty dynamic position @@ -1370,7 +1461,8 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int * * I don't think this is really possible. */ - ast_log(LOG_WARNING, "No dynamic RTP payload type values available!\n"); + ast_log(LOG_WARNING, "No dynamic RTP payload type values available " + "for %s - %d!\n", format ? ast_format_get_name(format) : "", code); } ast_rwlock_unlock(&codecs->codecs_lock); @@ -2293,95 +2385,47 @@ static void set_next_mime_type(struct ast_format *format, int rtp_code, const ch ast_rwlock_unlock(&mime_types_lock); } -static void add_static_payload(int map, struct ast_format *format, int rtp_code) +static void add_static_payload(int payload, struct ast_format *format, int rtp_code) { - int x; struct ast_rtp_payload_type *type; /* * ARRAY_LEN's result is cast to an int so 'map' is not autocast to a size_t, * which if negative would cause an assertion. */ - ast_assert(map < (int)ARRAY_LEN(static_RTP_PT)); + ast_assert(payload < (int)ARRAY_LEN(static_RTP_PT)); + if (ast_option_rtpusedynamic && payload < 0) { + /* + * We're going to build dynamic payloads dynamically. An RTP code is + * required otherwise one will be dynamically allocated per instance. + */ + return; + } + + /* + * Either the given payload is truly a static type, or Asterisk is + * globally storing the dynamic payloads in the static_RTP_PT object. + */ ast_rwlock_wrlock(&static_RTP_PT_lock); - if (map < 0) { - /* find next available dynamic payload slot */ - for (x = AST_RTP_PT_FIRST_DYNAMIC; x < AST_RTP_MAX_PT; ++x) { - if (!static_RTP_PT[x]) { - map = x; - break; - } - } - /* http://www.iana.org/assignments/rtp-parameters - * RFC 3551, Section 3: "[...] applications which need to define more - * than 32 dynamic payload types MAY bind codes below 96, in which case - * it is RECOMMENDED that unassigned payload type numbers be used - * first". Updated by RFC 5761, Section 4: "[...] values in the range - * 64-95 MUST NOT be used [to avoid conflicts with RTCP]". Summaries: - * https://tools.ietf.org/html/draft-roach-mmusic-unified-plan#section-3.2.1.2 - * https://tools.ietf.org/html/draft-wu-avtcore-dynamic-pt-usage#section-3 - */ - if (map < 0) { - for (x = MAX(ast_option_rtpptdynamic, 35); x <= AST_RTP_PT_LAST_REASSIGN; ++x) { - if (!static_RTP_PT[x]) { - map = x; - break; - } - } - } - /* Yet, reusing mappings below 35 is not supported in Asterisk because - * when Compact Headers are activated, no rtpmap is send for those below - * 35. If you want to use 35 and below - * A) do not use Compact Headers, - * B) remove that code in chan_sip/res_pjsip, or - * C) add a flag that this RTP Payload Type got reassigned dynamically - * and requires a rtpmap even with Compact Headers enabled. + if (payload < 0) { + /* + * This is a dynamic payload that will be stored globally, + * so find the next available empty slot. */ - if (map < 0) { - for (x = MAX(ast_option_rtpptdynamic, 20); x < 35; ++x) { - if (!static_RTP_PT[x]) { - map = x; - break; - } - } - } - if (map < 0) { - for (x = MAX(ast_option_rtpptdynamic, 0); x < 20; ++x) { - if (!static_RTP_PT[x]) { - map = x; - break; - } - } - } - - if (map < 0) { - if (format) { - ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n", - ast_format_get_name(format)); - } else { - ast_log(LOG_WARNING, "No Dynamic RTP mapping available for RTP code %d\n", - rtp_code); - } - ast_rwlock_unlock(&static_RTP_PT_lock); + payload = find_unused_payload(NULL); + if (payload < 0) { + ast_log(LOG_WARNING, "No dynamic RTP payload type values available " + "for %s - %d!\n", format ? ast_format_get_name(format) : "", rtp_code); return; } } - type = ast_rtp_engine_alloc_payload_type(); + type = rtp_payload_type_alloc(format, payload, rtp_code, 1); if (type) { - if (format) { - ao2_ref(format, +1); - type->format = format; - type->asterisk_format = 1; - } else { - type->rtp_code = rtp_code; - } - type->payload = map; - type->primary_mapping = 1; - ao2_cleanup(static_RTP_PT[map]); - static_RTP_PT[map] = type; + ao2_cleanup(static_RTP_PT[payload]); + static_RTP_PT[payload] = type; } ast_rwlock_unlock(&static_RTP_PT_lock); } @@ -2797,23 +2841,34 @@ int ast_rtp_engine_init(void) add_static_payload(26, ast_format_jpeg, 0); add_static_payload(31, ast_format_h261, 0); add_static_payload(34, ast_format_h263, 0); + + /* + * Dynamic payload types - Even when dynamically assigning them we'll fall + * back to using the statically declared values as the default number. + */ + add_static_payload(96, ast_format_slin192, 0); add_static_payload(97, ast_format_ilbc, 0); add_static_payload(98, ast_format_h263p, 0); add_static_payload(99, ast_format_h264, 0); + add_static_payload(100, ast_format_vp8, 0); add_static_payload(101, NULL, AST_RTP_DTMF); add_static_payload(102, ast_format_siren7, 0); add_static_payload(103, ast_format_h263p, 0); add_static_payload(104, ast_format_mp4, 0); add_static_payload(105, ast_format_t140_red, 0); /* Real time text chat (with redundancy encoding) */ add_static_payload(106, ast_format_t140, 0); /* Real time text chat */ + add_static_payload(107, ast_format_opus, 0); + add_static_payload(110, ast_format_speex, 0); add_static_payload(111, ast_format_g726, 0); add_static_payload(112, ast_format_g726_aal2, 0); + add_static_payload(115, ast_format_siren14, 0); add_static_payload(116, ast_format_g719, 0); add_static_payload(117, ast_format_speex16, 0); add_static_payload(118, ast_format_slin16, 0); /* 16 Khz signed linear */ add_static_payload(119, ast_format_speex32, 0); + add_static_payload(121, NULL, AST_RTP_CISCO_DTMF); /* Must be type 121 */ add_static_payload(122, ast_format_slin12, 0); add_static_payload(123, ast_format_slin24, 0); @@ -2822,10 +2877,6 @@ int ast_rtp_engine_init(void) add_static_payload(126, ast_format_slin48, 0); add_static_payload(127, ast_format_slin96, 0); /* payload types above 127 are not valid */ - add_static_payload(96, ast_format_slin192, 0); - /* Opus and VP8 */ - add_static_payload(100, ast_format_vp8, 0); - add_static_payload(107, ast_format_opus, 0); return 0; } From 0136ec12a3038aa5a5bc61f041111b4bc9fca7da Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 22 Mar 2017 16:40:29 -0400 Subject: [PATCH 1149/1578] res_xmpp: Include client name in connection related error messages ASTERISK-25622 #close Reported by: Sean Darcy Change-Id: I8472cb7bfb58d411a3cfbd482da98cae2d94d1e9 --- res/res_xmpp.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 1aa865cd626..4ad16bf3542 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -3752,12 +3752,12 @@ static void *xmpp_client_thread(void *data) do { if (client->state == XMPP_STATE_DISCONNECTING) { - ast_debug(1, "JABBER: Disconnecting client '%s'\n", client->name); + ast_debug(1, "[%s] Disconnecting\n", client->name); break; } if (res == IKS_NET_RWERR || client->timeout == 0) { - ast_debug(3, "Connecting client '%s'\n", client->name); + ast_debug(3, "[%s] Connecting\n", client->name); if ((res = xmpp_client_reconnect(client)) != IKS_OK) { sleep(4); res = IKS_NET_RWERR; @@ -3774,9 +3774,9 @@ static void *xmpp_client_thread(void *data) } if (res == IKS_HOOK) { - ast_debug(2, "JABBER: Got hook event.\n"); + ast_debug(2, "[%s] Got hook event\n", client->name); } else if (res == IKS_NET_TLSFAIL) { - ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n"); + ast_log(LOG_ERROR, "[%s] TLS failure\n", client->name); } else if (!client->timeout && client->state == XMPP_STATE_CONNECTED) { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup); @@ -3794,22 +3794,22 @@ static void *xmpp_client_thread(void *data) if (res == IKS_OK) { client->timeout = 50; } else { - ast_log(LOG_WARNING, "JABBER: Network Timeout\n"); + ast_log(LOG_WARNING, "[%s] Network timeout\n", client->name); } } else if (res == IKS_NET_RWERR) { - ast_log(LOG_WARNING, "JABBER: socket read error\n"); + ast_log(LOG_WARNING, "[%s] Socket read error\n", client->name); } else if (res == IKS_NET_NOSOCK) { - ast_log(LOG_WARNING, "JABBER: No Socket\n"); + ast_log(LOG_WARNING, "[%s] No socket\n", client->name); } else if (res == IKS_NET_NOCONN) { - ast_log(LOG_WARNING, "JABBER: No Connection\n"); + ast_log(LOG_WARNING, "[%s] No connection\n", client->name); } else if (res == IKS_NET_NODNS) { - ast_log(LOG_WARNING, "JABBER: No DNS\n"); + ast_log(LOG_WARNING, "[%s] No DNS\n", client->name); } else if (res == IKS_NET_NOTSUPP) { - ast_log(LOG_WARNING, "JABBER: Not Supported\n"); + ast_log(LOG_WARNING, "[%s] Not supported\n", client->name); } else if (res == IKS_NET_DROPPED) { - ast_log(LOG_WARNING, "JABBER: Dropped?\n"); + ast_log(LOG_WARNING, "[%s] Dropped?\n", client->name); } else if (res == IKS_NET_UNKNOWN) { - ast_debug(5, "JABBER: Unknown\n"); + ast_debug(5, "[%s] Unknown\n", client->name); } } while (1); From 7657c279b592b40fc6922122c3c3954b118a0ec7 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 22 Mar 2017 18:32:37 -0400 Subject: [PATCH 1150/1578] res_xmpp: Don't crash when trying to send a message without a connection If we never establish a connection to our Jabber server, iksemel never sets up its internal transport pointer, so attempting to send a message dereferences a NULL pointer and causes a crash. ASTERISK-21855 #close Reported by: Jeremy Kister Change-Id: I204a568894e4a53ab929783ecc594a000f04d79c --- res/res_xmpp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 1aa865cd626..617c401d22d 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -2562,10 +2562,16 @@ static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incomin static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message) { int ret; -#ifdef HAVE_OPENSSL - int len = strlen(message); + if (client->state == XMPP_STATE_DISCONNECTED) { + /* iks_send_raw will crash without a connection */ + return IKS_NET_NOCONN; + } + +#ifdef HAVE_OPENSSL if (xmpp_is_secure(client)) { + int len = strlen(message); + ret = SSL_write(client->ssl_session, message, len); if (ret) { /* Log the message here, because iksemel's logHook is From 9493981419f86ee19c637a8ff1666af5b80375ad Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 23 Mar 2017 10:30:18 -0400 Subject: [PATCH 1151/1578] res_xmpp: Correctly check return value of SSL_connect SSL_connect returns non-zero for both success and some error conditions so simply negating is inadequate. Change-Id: Ifbf882896e598703b6c615407fa456d3199f95b1 --- res/res_xmpp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 1aa865cd626..ddd4a5722cc 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -2670,7 +2670,7 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_ goto failure; } - if (!SSL_connect(client->ssl_session)) { + if (SSL_connect(client->ssl_session) <= 0) { goto failure; } From ee81ee1f143cfd2c4174c87d779ebe5c5d078f94 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 23 Mar 2017 06:19:18 -0400 Subject: [PATCH 1152/1578] res_xmpp: Fix ref counting issue The only remaining reference to the endpoint is in the endpoints container, and because it is unlinked in ast_endpoint_shutdown, we don't have to explicitly cleanup the endpoint ourselves. Change-Id: I912a2692e52d3e2ed445b32d8ae3f9004bc2f2e8 --- res/res_xmpp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 1aa865cd626..ab4ee9e4f01 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -559,7 +559,6 @@ static void xmpp_client_destructor(void *obj) ast_xmpp_client_disconnect(client); ast_endpoint_shutdown(client->endpoint); - ao2_cleanup(client->endpoint); client->endpoint = NULL; if (client->filter) { From be94105d6dc0cfb41ed88badd2d7cfd18ab7fe89 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 23 Mar 2017 10:45:35 -0400 Subject: [PATCH 1153/1578] res_xmpp: Try to provide useful errors messages from OpenSSL If any errors occur during the TLS connection setup, we currently dump a fairly generic error message. So instead we try to pull in something useful from OpenSSL to report instead. ASTERISK-24712 Reported by: Matthias Urlichs Change-Id: I288500991a9681f447d92913b11fedaf426087f4 --- res/res_xmpp.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 1aa865cd626..4e6685291e7 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -2629,12 +2629,31 @@ static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xm #endif } +#ifdef HAVE_OPENSSL +static char *openssl_error_string(void) +{ + char *buf = NULL, *ret; + size_t len; + BIO *bio = BIO_new(BIO_s_mem()); + + ERR_print_errors(bio); + len = BIO_get_mem_data(bio, &buf); + ret = ast_calloc(1, len + 1); + if (ret) { + memcpy(ret, buf, len); + } + BIO_free(bio); + return ret; +} +#endif + /*! \brief Internal function called when we receive a response to our TLS initiation request */ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node) { #ifdef HAVE_OPENSSL int sock; long ssl_opts; + char *err; #endif if (!strcmp(iks_name(node), "success")) { @@ -2690,7 +2709,10 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_ return 0; failure: - ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name); + err = openssl_error_string(); + ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. " + "OpenSSL initialization failed: %s\n", client->name, err); + ast_free(err); return -1; #endif } From 98a88e9ffa5f664a7f0e507f83bd9767a912dac6 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 22 Mar 2017 21:33:02 -0400 Subject: [PATCH 1154/1578] res_xmpp: Correct implementation of JABBER_STATUS & JabberStatus The documentation for JABBER_STATUS (and the deprecated JabberStatus app) indicate that a return value of 7 indicates that the specified buddy was not in the roster. It also indicates that you can specify a "bare" JID (one without a resource). Unfortunately the actual behavior does not match the documented behavior. Assuming that our roster includes the buddy online and available "valid@example.org/Valid" and does *not* include the buddy "invalid@example.org", the JABBER_STATUS() function returns the following before this patch: +------------------------------+------------+--------------------------+ | Buddy | Status | Result | +------------------------------+------------+--------------------------+ | valid@example.org | Online | 7 (Not in roster) | | valid@example.org/Valid | Online | 1 (Online) | | valid@example.org/Invalid | N/A | 7 (Not in roster) | | invalid@example.org | N/A | Error logged, no return | | invalid@example.org/Valid | N/A | Error logged, no return | +------------------------------+------------+--------------------------+ And after this patch: +------------------------------+------------+--------------------------+ | Buddy | Status | Result | +------------------------------+------------+--------------------------+ | valid@example.org | Online | 1 (Online) | | valid@example.org/Valid | Online | 1 (Online) | | valid@example.org/Invalid | N/A | 6 (Offline) | | invalid@example.org | N/A | 7 (Not in roster) | | invalid@example.org/Valid | N/A | 7 (Not in roster) | +------------------------------+------------+--------------------------+ This brings the behavior in line with the documentation. ASTERISK-23510 #close Reported by: Anthony Critelli Change-Id: I9c3241035363ef4a6bdc21fabfd8ffcd9ec657bf --- res/res_xmpp.c | 75 +++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 1aa865cd626..3c80d4d338b 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -1630,6 +1630,35 @@ static int xmpp_resource_immediate(void *obj, void *arg, int flags) return CMP_MATCH | CMP_STOP; } +#define BUDDY_OFFLINE 6 +#define BUDDY_NOT_IN_ROSTER 7 + +static int get_buddy_status(struct ast_xmpp_client_config *clientcfg, char *screenname, char *resource) +{ + int status = BUDDY_OFFLINE; + struct ast_xmpp_resource *res; + struct ast_xmpp_buddy *buddy = ao2_find(clientcfg->client->buddies, screenname, OBJ_KEY); + + if (!buddy) { + return BUDDY_NOT_IN_ROSTER; + } + + res = ao2_callback( + buddy->resources, + 0, + ast_strlen_zero(resource) ? xmpp_resource_immediate : xmpp_resource_cmp, + resource); + + if (res) { + status = res->status; + } + + ao2_cleanup(res); + ao2_cleanup(buddy); + + return status; +} + /* * \internal * \brief Dial plan function status(). puts the status of watched user @@ -1643,10 +1672,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data) { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup); - struct ast_xmpp_buddy *buddy; - struct ast_xmpp_resource *resource; char *s = NULL, status[2]; - int stat = 7; static int deprecation_warning = 0; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(sender); @@ -1685,25 +1711,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data) return -1; } - if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) { - ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname); - return -1; - } - - if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) { - resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL); - } - - ao2_ref(buddy, -1); - - if (resource) { - stat = resource->status; - ao2_ref(resource, -1); - } else { - ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname); - } - - snprintf(status, sizeof(status), "%d", stat); + snprintf(status, sizeof(status), "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource)); pbx_builtin_setvar_helper(chan, args.variable, status); return 0; @@ -1722,9 +1730,6 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup); - struct ast_xmpp_buddy *buddy; - struct ast_xmpp_resource *resource; - int stat = 7; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(sender); AST_APP_ARG(jid); @@ -1756,25 +1761,7 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha return -1; } - if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) { - ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname); - return -1; - } - - if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) { - resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL); - } - - ao2_ref(buddy, -1); - - if (resource) { - stat = resource->status; - ao2_ref(resource, -1); - } else { - ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname); - } - - snprintf(buf, buflen, "%d", stat); + snprintf(buf, buflen, "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource)); return 0; } From 12dde3b568ff3e44527b73f61b073f902edfb10f Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 23 Mar 2017 12:07:09 -0500 Subject: [PATCH 1155/1578] pjproject_bundled: raise timeout value used when downloading After configuring Asterisk with '--with-pjproject-bundled' the configure/build process attempts to download pjproject from its download site. Currently, a timeout of 10 seconds is used that will stop the download process if pjproject has not been fully downloaded in that time. For some systems this was not enough time and the process was timing out too early. This patch raises the download timeout value to '60'. Also, this patch fixes another bug where the DOWNLOAD_TIMEOUT variable was not being properly exported due to a naming error. DOWNLOAD_MAX_TIMEOUT is now properly renamed to DOWNLOAD_TIMEOUT. ASTERISK-26814 #close Change-Id: Ia56e4e8a3d39db76bc8a1852b2cf07ec10b39842 --- makeopts.in | 2 +- third-party/pjproject/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/makeopts.in b/makeopts.in index 6a1164c329b..5bc5258dab8 100644 --- a/makeopts.in +++ b/makeopts.in @@ -28,7 +28,7 @@ WGET=@WGET@ FETCH=@FETCH@ DOWNLOAD=@DOWNLOAD@ DOWNLOAD_TO_STDOUT=@DOWNLOAD_TO_STDOUT@ -DOWNLOAD_MAX_TIMEOUT=@DOWNLOAD_MAX_TIMEOUT@ +DOWNLOAD_TIMEOUT=@DOWNLOAD_TIMEOUT@ SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@ EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@ RUBBER=@RUBBER@ diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 99c22fa8be6..e691f22428d 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -96,9 +96,9 @@ endef define download_from_pjproject ($(SHELL_ECHO_PREFIX) Downloading $(TARBALL_URL) to $(TARBALL) ;\ - $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(TARBALL_URL) > $(TARBALL) &&\ + $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(TARBALL_URL) > $(TARBALL) &&\ $(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM to $(PJMD5SUM) &&\ - $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\ + $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\ $(verify_tarball)) endef From d2f2cdf4766de9a59472805f8e989f673fcf19f4 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 23 Mar 2017 14:01:40 -0500 Subject: [PATCH 1156/1578] AMI: Updated version Updated the AMI version for the following reason (see CHANGES for more details): The 'PJSIPShowEndpoint' command's response event of 'IdentifyDetail' now contains a new optional parameter, 'MatchHeader'. Change-Id: Ie206913ef1dcfa6a2ebe3282da2387e52d6f05b9 --- include/asterisk/manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 60c51de854c..3de7b1d1753 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -54,7 +54,7 @@ - \ref manager.c Main manager code file */ -#define AMI_VERSION "3.1.0" +#define AMI_VERSION "3.2.0" #define DEFAULT_MANAGER_PORT 5038 /* Default port for Asterisk management via TCP */ #define DEFAULT_MANAGER_TLS_PORT 5039 /* Default port for Asterisk management via TCP */ From d08c69a9e28d98d386971bd8527dec3926f0502b Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 24 Mar 2017 12:29:10 -0400 Subject: [PATCH 1157/1578] res_pjsip_sdp_rtp: Set hangup cause for RTP timeouts chan_sip sets the hangup cause code to AST_CAUSE_REQUESTED_CHAN_UNAVAIL (44) when a channel is hung up due to an RTP timeout. So do the same when it happens with PJSIP for parity. Change-Id: I3546ebbde6460c22a27c9da1bf321711b5961ab8 --- res/res_pjsip_sdp_rtp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a8247577437..b66c1aeb821 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -163,6 +163,10 @@ static int rtp_check_timeout(const void *data) ast_log(LOG_NOTICE, "Disconnecting channel '%s' for lack of RTP activity in %d seconds\n", ast_channel_name(chan), elapsed); + ast_channel_lock(chan); + ast_channel_hangupcause_set(chan, AST_CAUSE_REQUESTED_CHAN_UNAVAIL); + ast_channel_unlock(chan); + ast_softhangup(chan, AST_SOFTHANGUP_DEV); ast_channel_unref(chan); From d5a8799c4b6b496784aa408cda9b6864ba37b3b2 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 23 Mar 2017 10:48:40 -0400 Subject: [PATCH 1158/1578] res_xmpp: Use incremental backoff when a read error occurs If a read error occurs, we immediately attempt a reconnect without any delay. Instead, let's sleep and backoff up to 60 seconds before we try again. ASTERISK-24712 #close Reported by: Matthias Urlichs Change-Id: I6fe10ef4734837727437beab715e336777f13f48 --- res/res_xmpp.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index f4a5d8e05bf..4b52a269c6f 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -3580,6 +3580,7 @@ int ast_xmpp_client_disconnect(struct ast_xmpp_client *client) { if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) { xmpp_client_change_state(client, XMPP_STATE_DISCONNECTING); + pthread_cancel(client->thread); pthread_join(client->thread, NULL); client->thread = AST_PTHREADT_NULL; } @@ -3759,11 +3760,26 @@ static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int time return IKS_OK; } +static void sleep_with_backoff(unsigned int *sleep_time) +{ + /* We're OK with our thread dying here */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + sleep(*sleep_time); + *sleep_time = MIN(60, *sleep_time * 2); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); +} + /*! \brief XMPP client connection thread */ static void *xmpp_client_thread(void *data) { struct ast_xmpp_client *client = data; int res = IKS_NET_RWERR; + unsigned int sleep_time = 1; + + /* We only allow cancellation while sleeping */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); do { if (client->state == XMPP_STATE_DISCONNECTING) { @@ -3774,7 +3790,7 @@ static void *xmpp_client_thread(void *data) if (res == IKS_NET_RWERR || client->timeout == 0) { ast_debug(3, "[%s] Connecting\n", client->name); if ((res = xmpp_client_reconnect(client)) != IKS_OK) { - sleep(4); + sleep_with_backoff(&sleep_time); res = IKS_NET_RWERR; } continue; @@ -3813,6 +3829,8 @@ static void *xmpp_client_thread(void *data) } } else if (res == IKS_NET_RWERR) { ast_log(LOG_WARNING, "[%s] Socket read error\n", client->name); + ast_xmpp_client_disconnect(client); + sleep_with_backoff(&sleep_time); } else if (res == IKS_NET_NOSOCK) { ast_log(LOG_WARNING, "[%s] No socket\n", client->name); } else if (res == IKS_NET_NOCONN) { @@ -3825,6 +3843,8 @@ static void *xmpp_client_thread(void *data) ast_log(LOG_WARNING, "[%s] Dropped?\n", client->name); } else if (res == IKS_NET_UNKNOWN) { ast_debug(5, "[%s] Unknown\n", client->name); + } else if (res == IKS_OK) { + sleep_time = 1; } } while (1); From d22c678999200c7d8ca093c7b17c287c91c040f3 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 27 Mar 2017 09:58:17 -0400 Subject: [PATCH 1159/1578] res_musiconhold: Don't chdir() when scanning MoH files There doesn't appear to be any reason that we are chdir'ing in moh_scan_files, and in the event of an Asterisk crash, the core files may not get written because we have changed into a read-only directory. ASTERISK-23996 #close Reported by: Walter Doekes Change-Id: Iac806dce01b3335963fbd62d4b4da9a65c614354 --- res/res_musiconhold.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 5ee1ac30ba1..992737b15d5 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1112,16 +1112,13 @@ static int moh_scan_files(struct mohclass *class) { DIR *files_DIR; struct dirent *files_dirent; char dir_path[PATH_MAX]; - char path[PATH_MAX]; char filepath[PATH_MAX]; char *ext; struct stat statbuf; int i; if (class->dir[0] != '/') { - ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path)); - strncat(dir_path, "/", sizeof(dir_path) - 1); - strncat(dir_path, class->dir, sizeof(dir_path) - 1); + snprintf(dir_path, sizeof(dir_path), "%s/%s", ast_config_AST_DATA_DIR, class->dir); } else { ast_copy_string(dir_path, class->dir, sizeof(dir_path)); } @@ -1137,16 +1134,6 @@ static int moh_scan_files(struct mohclass *class) { } class->total_files = 0; - if (!getcwd(path, sizeof(path))) { - ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); - closedir(files_DIR); - return -1; - } - if (chdir(dir_path) < 0) { - ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); - closedir(files_DIR); - return -1; - } while ((files_dirent = readdir(files_DIR))) { /* The file name must be at least long enough to have the file type extension */ if ((strlen(files_dirent->d_name) < 4)) @@ -1183,10 +1170,6 @@ static int moh_scan_files(struct mohclass *class) { } closedir(files_DIR); - if (chdir(path) < 0) { - ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); - return -1; - } if (ast_test_flag(class, MOH_SORTALPHA)) qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare); return class->total_files; From cf6a6226ab92a66e827faa4f1c805256c071794d Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 24 Mar 2017 08:43:05 -0400 Subject: [PATCH 1160/1578] core: Remove embedded module support This has not worked for some time and is no longer actively maintained. Change-Id: I5110b0db69c152761b58fa025cb0a53b0e544d99 --- Makefile | 39 +-------------- Makefile.moddir_rules | 43 ++-------------- Makefile.rules | 12 ----- UPGRADE.txt | 7 +++ addons/Makefile | 2 +- build_tools/cflags.xml | 4 -- build_tools/embed_modules.xml | 46 ----------------- codecs/Makefile | 6 +-- configure | 58 --------------------- configure.ac | 23 --------- include/asterisk/module.h | 65 ------------------------ main/Makefile | 19 ++----- main/loader.c | 94 ++++------------------------------- makeopts.in | 3 -- third-party/Makefile | 2 +- 15 files changed, 33 insertions(+), 390 deletions(-) delete mode 100644 build_tools/embed_modules.xml diff --git a/Makefile b/Makefile index 2c7f92543f3..95a3d3da53a 100644 --- a/Makefile +++ b/Makefile @@ -253,9 +253,6 @@ SUBDIRS_INSTALL:=$(SUBDIRS:%=%-install) SUBDIRS_CLEAN:=$(SUBDIRS:%=%-clean) SUBDIRS_DIST_CLEAN:=$(SUBDIRS:%=%-dist-clean) SUBDIRS_UNINSTALL:=$(SUBDIRS:%=%-uninstall) -MOD_SUBDIRS_EMBED_LDSCRIPT:=$(MOD_SUBDIRS:%=%-embed-ldscript) -MOD_SUBDIRS_EMBED_LDFLAGS:=$(MOD_SUBDIRS:%=%-embed-ldflags) -MOD_SUBDIRS_EMBED_LIBS:=$(MOD_SUBDIRS:%=%-embed-libs) MOD_SUBDIRS_MENUSELECT_TREE:=$(MOD_SUBDIRS:%=%-menuselect-tree) ifneq ($(findstring darwin,$(OSARCH)),) @@ -344,41 +341,14 @@ ifeq ($(filter %.menuselect,$(MAKECMDGOALS)),) menuselect/menuselect --check-deps $@ $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) endif -$(MOD_SUBDIRS_EMBED_LDSCRIPT): - +@echo "EMBED_LDSCRIPTS+="`$(SILENTMAKE) -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules - -$(MOD_SUBDIRS_EMBED_LDFLAGS): - +@echo "EMBED_LDFLAGS+="`$(SILENTMAKE) -C $(@:-embed-ldflags=) SUBDIR=$(@:-embed-ldflags=) __embed_ldflags` >> makeopts.embed_rules - -$(MOD_SUBDIRS_EMBED_LIBS): - +@echo "EMBED_LIBS+="`$(SILENTMAKE) -C $(@:-embed-libs=) SUBDIR=$(@:-embed-libs=) __embed_libs` >> makeopts.embed_rules - $(MOD_SUBDIRS_MENUSELECT_TREE): +@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) moduleinfo +@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) makeopts -makeopts.embed_rules: menuselect.makeopts - @echo "Generating embedded module rules ..." - @rm -f $@ - +@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LDSCRIPT) - +@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LDFLAGS) - +@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LIBS) - -$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h include/asterisk/buildopts.h defaults.h makeopts.embed_rules +$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h include/asterisk/buildopts.h defaults.h ifeq ($(findstring $(OSARCH), mingw32 cygwin ),) - ifeq ($(shell grep ^MENUSELECT_EMBED=$$ menuselect.makeopts 2>/dev/null),) - # Non-windows: - # ensure that all module subdirectories are processed before 'main' during - # a parallel build, since if there are modules selected to be embedded the - # directories containing them must be completed before the main Asterisk - # binary can be built. - # If MENUSELECT_EMBED is empty, we don't need this and allow 'main' to be - # be built with only third_party first. -main: $(filter-out main,$(MOD_SUBDIRS)) - else main: third-party - endif else # Windows: we need to build main (i.e. the asterisk dll) first, # followed by res, followed by the other directories, because @@ -443,7 +413,6 @@ distclean: $(SUBDIRS_DIST_CLEAN) _clean @$(MAKE) -C menuselect dist-clean @$(MAKE) -C sounds dist-clean rm -f menuselect.makeopts makeopts menuselect-tree menuselect.makedeps - rm -f makeopts.embed_rules rm -f config.log config.status config.cache rm -rf autom4te.cache rm -f include/asterisk/autoconfig.h @@ -1033,7 +1002,7 @@ menuselect/nmenuselect: menuselect/makeopts .lastclean menuselect/makeopts: makeopts .lastclean +$(MAKE_MENUSELECT) makeopts -menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc) $(wildcard $(dir)/*.xml)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts +menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc) $(wildcard $(dir)/*.xml)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml utils/utils.xml agi/agi.xml configure makeopts @echo "Generating input for menuselect ..." @echo "" > $@ @echo >> $@ @@ -1046,7 +1015,6 @@ menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(di fi @cat utils/utils.xml >> $@ @cat agi/agi.xml >> $@ - @cat build_tools/embed_modules.xml >> $@ @cat sounds/sounds.xml >> $@ @echo "" >> $@ @@ -1097,9 +1065,6 @@ check-alembic: makeopts .PHONY: $(SUBDIRS_CLEAN) .PHONY: $(SUBDIRS_UNINSTALL) .PHONY: $(SUBDIRS) -.PHONY: $(MOD_SUBDIRS_EMBED_LDSCRIPT) -.PHONY: $(MOD_SUBDIRS_EMBED_LDFLAGS) -.PHONY: $(MOD_SUBDIRS_EMBED_LIBS) FORCE: diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules index 95e62788f2f..59190bece9a 100644 --- a/Makefile.moddir_rules +++ b/Makefile.moddir_rules @@ -18,10 +18,6 @@ # Also note that we can only set one variable per rule, so we have to # repeat the left hand side to set multiple variables. -ifeq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),) - _ASTCFLAGS+=${GC_CFLAGS} -endif - ifneq ($(findstring STATIC_BUILD,$(MENUSELECT_CFLAGS)),) STATIC_BUILD=-static endif @@ -29,7 +25,7 @@ endif include $(ASTTOPDIR)/Makefile.rules # If MODULE_PREFIX is defined, use it to run the standard functions to set -# C_MODS, CC_MODS, LOADABLE_MODS and EMBEDDED_MODS. +# C_MODS, CC_MODS and LOADABLE_MODS # Each word of MODULE_PREFIX is a prefix for filenames that we consider # valid C or CC modules (eg. app, func ...). Note that the underscore # is added here, and does not need to be in MODULE_PREFIX @@ -46,11 +42,7 @@ endif C_MODS:=$(filter-out $(MENUSELECT_$(MENUSELECT_CATEGORY)),$(ALL_C_MODS)) CC_MODS:=$(filter-out $(MENUSELECT_$(MENUSELECT_CATEGORY)),$(ALL_CC_MODS)) -ifneq ($(findstring EMBED_$(MENUSELECT_CATEGORY),$(MENUSELECT_EMBED)),) - EMBEDDED_MODS:=$(C_MODS) $(CC_MODS) -else - LOADABLE_MODS:=$(C_MODS) $(CC_MODS) -endif +LOADABLE_MODS:=$(C_MODS) $(CC_MODS) # Both C++ and C++ sources need their module name in AST_MODULE # We also pass whatever _INCLUDE list is generated by menuselect @@ -67,7 +59,7 @@ MOD_ASTCFLAGS=\ $(foreach dep,$(MENUSELECT_DEPENDS_$(1)),$(value $(dep)_INCLUDE)) define MOD_ADD_SOURCE -$$(if $$(filter $(1),$$(EMBEDDED_MODS)),modules.link,$(1).so): $$(subst $(3),$(5),$(2)) +$(1).so: $$(subst $(3),$(5),$(2)) $$(subst $(3),$(5),$(2)): _ASTCFLAGS+=$$(call MOD_ASTCFLAGS,$(1)) .$(1).moduleinfo: MODULEINFO_EXTRA_OUTPUT=" $$(addprefix $$(SUBDIR)/,$$(subst $(3),$(5),$(2)) $$(subst $(3),$(4),$(2)))" # The use of wildcard ensures that 'make menuselect' will not fail for modules that @@ -96,16 +88,11 @@ endif $(LOADABLE_MODS:%=%.so): LIBS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LIB)) $(LOADABLE_MODS:%=%.so): _ASTLDFLAGS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LDFLAGS)) -$(EMBEDDED_MODS:%=%.o): _ASTCFLAGS+=-DEMBEDDED_MODULE=$* - $(addsuffix .so,$(filter $(LOADABLE_MODS),$(C_MODS))): %.so: %.o $(addsuffix .so,$(filter $(LOADABLE_MODS),$(CC_MODS))): %.so: %.oo -modules.link: $(addsuffix .eo,$(filter $(EMBEDDED_MODS),$(C_MODS))) - .PHONY: clean uninstall _all moduleinfo makeopts -ifneq ($(LOADABLE_MODS),) _all: $(LOADABLE_MODS:%=%.so) ifneq ($(findstring $(OSARCH), mingw32 cygwin ),) # linker options and extra libraries for cygwin @@ -113,28 +100,6 @@ ifneq ($(findstring $(OSARCH), mingw32 cygwin ),) LIBS+=-L$(ASTTOPDIR)/main -lasterisk -L$(ASTTOPDIR)/res $($@_LIBS) # additional libraries in res/ endif -endif - -ifneq ($(EMBEDDED_MODS),) -_all: modules.link -__embed_ldscript: - @echo "../$(SUBDIR)/modules.link" -__embed_ldflags: - @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(C_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LDFLAGS))" - @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(CC_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LDFLAGS))" -__embed_libs: - @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(C_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LIB))" - @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(CC_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LIB))" -else -__embed_ldscript: -__embed_ldflags: -__embed_libs: -endif - -modules.link: - @rm -f $@ - @for file in $(patsubst %,$(SUBDIR)/%,$(filter %.eo,$^)); do echo "INPUT (../$${file})" >> $@; done - @for file in $(patsubst %,$(SUBDIR)/%,$(filter-out %.eo,$^)); do echo "INPUT (../$${file})" >> $@; done clean:: rm -f *.so *.o *.oo *.eo *.i *.ii @@ -177,7 +142,7 @@ dist-clean:: echo "" >> $@ .moduleinfo:: $(addsuffix .moduleinfo,$(addprefix .,$(sort $(ALL_C_MODS) $(ALL_CC_MODS)))) $(wildcard $(call tolower,$(MENUSELECT_CATEGORY)).xml) - @echo "" > $@ + @echo "" > $@ @cat $^ >> $@ @echo "" >> $@ diff --git a/Makefile.rules b/Makefile.rules index 45989d6843e..ee8eabd6f87 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -185,18 +185,6 @@ endif $(ECHO_PREFIX) echo " [LDXX] $^ -> $@" $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(CXX_LDFLAGS_SO) $^ $(CXX_LIBS) -%.eo: %.o - $(ECHO_PREFIX) echo " [EMBED] $< -> $@" - $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld - $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $< - $(CMD_PREFIX) rm -f .$@.ld - -%.eo: %.oo - $(ECHO_PREFIX) echo " [EMBED] $< -> $@" - $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld - $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $< - $(CMD_PREFIX) rm -f .$@.ld - %: %.o $(ECHO_PREFIX) echo " [LD] $^ -> $@" $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $^ $(CXX_LIBS) $(ASTLDFLAGS) diff --git a/UPGRADE.txt b/UPGRADE.txt index 1afacf2a4a4..62bb8018291 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -23,6 +23,13 @@ === UPGRADE-14.txt -- Upgrade info for 13 to 14 =========================================================== +From 14.4.0 to 14.5.0: + +Core: + - Support for embedded modules has been removed. This has not worked in + many years. LOADABLE_MODULES menuselect option is also removed as + loadable module support is now always enabled. + From 14.3.0 to 14.4.0: res_rtp_asterisk: diff --git a/addons/Makefile b/addons/Makefile index a02d35f7d8e..d12d0fd3b2c 100644 --- a/addons/Makefile +++ b/addons/Makefile @@ -59,7 +59,7 @@ endif include $(ASTTOPDIR)/Makefile.moddir_rules -$(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): _ASTCFLAGS+=$(H323CFLAGS) +chan_ooh323.so: _ASTCFLAGS+=$(H323CFLAGS) $(call MOD_ADD_C,chan_ooh323,$(H323SOURCE)) $(call MOD_ADD_C,format_mp3,mp3/common.c mp3/dct64_i386.c mp3/decode_ntom.c mp3/layer3.c mp3/tabinit.c mp3/interface.c) diff --git a/build_tools/cflags.xml b/build_tools/cflags.xml index a06d515f3e5..f05f42869f6 100644 --- a/build_tools/cflags.xml +++ b/build_tools/cflags.xml @@ -19,10 +19,6 @@ extended - - yes - core - core diff --git a/build_tools/embed_modules.xml b/build_tools/embed_modules.xml deleted file mode 100644 index a7e4cfd5d01..00000000000 --- a/build_tools/embed_modules.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - - gnu_ld - extended - - diff --git a/codecs/Makefile b/codecs/Makefile index 684ccc67910..64f77ebaa25 100644 --- a/codecs/Makefile +++ b/codecs/Makefile @@ -38,7 +38,7 @@ include $(ASTTOPDIR)/Makefile.moddir_rules ifneq ($(GSM_INTERNAL),no) GSM_INCLUDE := -I$(SUB_GSM)/inc -$(if $(filter codec_gsm,$(EMBEDDED_MODS)),modules.link,codec_gsm.so): $(SUB_GSM)/lib/libgsm.a +codec_gsm.so: $(SUB_GSM)/lib/libgsm.a endif # Don't run the implicit rules for this target. @@ -57,7 +57,7 @@ clean:: .PHONY: $(SUB_DIRS) -$(if $(filter codec_lpc10,$(EMBEDDED_MODS)),modules.link,codec_lpc10.so): $(LIBLPC10) +codec_lpc10.so: $(LIBLPC10) # Don't run the implicit rules for this target. $(LIBLPC10): $(SUB_LPC10) ; @@ -67,7 +67,7 @@ $(SUB_LPC10): ifneq ($(ILBC_INTERNAL),no) -$(if $(filter codec_ilbc,$(EMBEDDED_MODS)),modules.link,codec_ilbc.so): $(LIBILBC) +codec_ilbc.so: $(LIBILBC) else ILBC_INCLUDE += -DILBC_WEBRTC endif diff --git a/configure b/configure index 078020c5fe7..15f127b12a3 100755 --- a/configure +++ b/configure @@ -704,8 +704,6 @@ AST_NO_STRICT_OVERFLOW AST_FORTIFY_SOURCE AST_TRAMPOLINES AST_DECLARATION_AFTER_STATEMENT -GC_LDFLAGS -GC_CFLAGS AST_UNDEFINED_SANITIZER AST_LEAK_SANITIZER AST_THREAD_SANITIZER @@ -18920,62 +18918,6 @@ CFLAGS="${saved_sanitize_CFLAGS}" LDFLAGS="${saved_sanitize_LDFLAGS}" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -ffunction-sections support" >&5 -$as_echo_n "checking for -ffunction-sections support... " >&6; } -saved_CFLAGS="${CFLAGS}" -CFLAGS="${CFLAGS} -ffunction-sections" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -int x = 1; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - saved_LDFLAGS="${LDFLAGS}" - LDFLAGS="${LDFLAGS} -Wl,--gc-sections" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --gc-sections support" >&5 -$as_echo_n "checking for --gc-sections support... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -int x = 1; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - GC_CFLAGS="-ffunction-sections" - GC_LDFLAGS="-Wl,--gc-sections" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="${saved_LDFLAGS}" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -CFLAGS="${saved_CFLAGS}" - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wdeclaration-after-statement support" >&5 $as_echo_n "checking for -Wdeclaration-after-statement support... " >&6; } if $(${CC} -Wdeclaration-after-statement -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then diff --git a/configure.ac b/configure.ac index 890f32d4728..a57446f9242 100644 --- a/configure.ac +++ b/configure.ac @@ -1197,29 +1197,6 @@ CFLAGS="${saved_sanitize_CFLAGS}" LDFLAGS="${saved_sanitize_LDFLAGS}" AC_SUBST(AST_UNDEFINED_SANITIZER) -AC_MSG_CHECKING(for -ffunction-sections support) -saved_CFLAGS="${CFLAGS}" -CFLAGS="${CFLAGS} -ffunction-sections" -AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([], [int x = 1;])], - AC_MSG_RESULT(yes) - [saved_LDFLAGS="${LDFLAGS}"] - [LDFLAGS="${LDFLAGS} -Wl,--gc-sections"] - AC_MSG_CHECKING(for --gc-sections support) - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([], [int x = 1;])], - AC_MSG_RESULT(yes) - [GC_CFLAGS="-ffunction-sections"] - [[GC_LDFLAGS="-Wl,--gc-sections"]], - AC_MSG_RESULT(no) - ) - [LDFLAGS="${saved_LDFLAGS}"], - AC_MSG_RESULT(no) -) -CFLAGS="${saved_CFLAGS}" -AC_SUBST(GC_CFLAGS) -AC_SUBST(GC_LDFLAGS) - AC_MSG_CHECKING(for -Wdeclaration-after-statement support) if $(${CC} -Wdeclaration-after-statement -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then AC_MSG_RESULT(yes) diff --git a/include/asterisk/module.h b/include/asterisk/module.h index a80c7f843ae..e614a726f20 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -303,8 +303,6 @@ struct ast_module_info { enum ast_module_load_result (*load)(void); /*!< register stuff etc. Optional. */ int (*reload)(void); /*!< config etc. Optional. */ int (*unload)(void); /*!< unload. called with the module locked */ - int (*backup_globals)(void); /*!< for embedded modules, backup global data */ - void (*restore_globals)(void); /*!< for embedded modules, restore global data */ const char *name; /*!< name of the module for loader reference and CLI commands */ const char *description; /*!< user friendly description of the module. */ @@ -379,8 +377,6 @@ void __ast_module_unref(struct ast_module *mod, const char *file, int line, cons load_func, \ reload_func, \ unload_func, \ - NULL, \ - NULL, \ AST_MODULE, \ desc, \ keystr, \ @@ -440,70 +436,9 @@ void __ast_module_unref(struct ast_module *mod, const char *file, int line, cons static const __attribute__((unused)) struct ast_module_info *ast_module_info; #endif -#if !defined(EMBEDDED_MODULE) -#define __MODULE_INFO_SECTION -#define __MODULE_INFO_GLOBALS -#else -/* - * For embedded modules we need additional information to backup and - * restore the global variables in the module itself, so we can unload - * reload the module. - * EMBEDDED_MODULE is defined as the module name, so the calls to make_var() - * below will actually define different symbols for each module. - */ -#define __MODULE_INFO_SECTION __attribute__((section(".embed_module"))) -#define __MODULE_INFO_GLOBALS .backup_globals = __backup_globals, .restore_globals = __restore_globals, - -#define make_var_sub(mod, type) __ ## mod ## _ ## type -#define make_var(mod, type) make_var_sub(mod, type) - -extern void make_var(EMBEDDED_MODULE, bss_start); -extern void make_var(EMBEDDED_MODULE, bss_end); -extern void make_var(EMBEDDED_MODULE, data_start); -extern void make_var(EMBEDDED_MODULE, data_end); - -static void * __attribute__((section(".embed_module"))) __global_backup; - -static int __backup_globals(void) -{ - size_t data_size = & make_var(EMBEDDED_MODULE, data_end) - & make_var(EMBEDDED_MODULE, data_start); - - if (__global_backup) - return 0; - - if (!data_size) - return 0; - - if (!(__global_backup = ast_malloc(data_size))) - return -1; - - memcpy(__global_backup, & make_var(EMBEDDED_MODULE, data_start), data_size); - - return 0; -} - -static void __restore_globals(void) -{ - size_t data_size = & make_var(EMBEDDED_MODULE, data_end) - & make_var(EMBEDDED_MODULE, data_start); - size_t bss_size = & make_var(EMBEDDED_MODULE, bss_end) - & make_var(EMBEDDED_MODULE, bss_start); - - if (bss_size) - memset(& make_var(EMBEDDED_MODULE, bss_start), 0, bss_size); - - if (!data_size || !__global_backup) - return; - - memcpy(& make_var(EMBEDDED_MODULE, data_start), __global_backup, data_size); -} -#undef make_var -#undef make_var_sub -#endif /* EMBEDDED_MODULE */ - #define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...) \ static struct ast_module_info \ - __MODULE_INFO_SECTION \ __mod_info = { \ - __MODULE_INFO_GLOBALS \ .name = AST_MODULE, \ .flags = flags_to_set, \ .description = desc, \ diff --git a/main/Makefile b/main/Makefile index cf38f5f465f..cd553cb0dd2 100644 --- a/main/Makefile +++ b/main/Makefile @@ -11,7 +11,7 @@ # the GNU General Public License # --include $(ASTTOPDIR)/menuselect.makeopts $(ASTTOPDIR)/menuselect.makedeps $(ASTTOPDIR)/makeopts.embed_rules $(ASTTOPDIR)/makeopts +-include $(ASTTOPDIR)/menuselect.makeopts $(ASTTOPDIR)/menuselect.makedeps $(ASTTOPDIR)/makeopts all: asterisk @@ -48,9 +48,7 @@ AST_LIBS+=$(RT_LIB) AST_LIBS+=$(SYSTEMD_LIB) ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc linux-musl kfreebsd-gnu),) - ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),) AST_LIBS+=-ldl - endif ifneq (x$(CAP_LIB),x) AST_LIBS+=$(CAP_LIB) endif @@ -69,11 +67,7 @@ ifneq ($(findstring darwin,$(OSARCH)),) ASTLINK+=/usr/lib/bundle1.o else # These are used for all but Darwin - ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),) - ASTLINK+=-Wl,--export-dynamic - else - ASTLINK+=${GC_LDFLAGS} - endif + ASTLINK+=-Wl,--export-dynamic ifneq ($(findstring BSD,$(OSARCH)),) LDFLAGS+=-L/usr/local/lib endif @@ -172,9 +166,6 @@ endif stdtime/localtime.o: _ASTCFLAGS+=$(AST_NO_STRICT_OVERFLOW) -Wno-format-nonliteral -AST_EMBED_LDSCRIPTS:=$(sort $(EMBED_LDSCRIPTS)) -AST_EMBED_LDFLAGS:=$(foreach dep,$(EMBED_LDFLAGS),$(value $(dep))) -AST_EMBED_LIBS:=$(foreach dep,$(EMBED_LIBS),$(value $(dep))) OBJS:=$(sort $(OBJS)) ifneq ($(findstring $(OSARCH), mingw32 cygwin ),) @@ -325,10 +316,10 @@ endif tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) -$(MAIN_TGT): $(OBJS) $(ASTSSL_LIB) $(ASTPJ_LIB) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) +$(MAIN_TGT): $(OBJS) $(ASTSSL_LIB) $(ASTPJ_LIB) $(LIBEDIT_OBJ) @$(CC) -c -o buildinfo.o $(_ASTCFLAGS) buildinfo.c $(ASTCFLAGS) - $(ECHO_PREFIX) echo " [LD] $(OBJS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) -> $@" - $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) $(ASTSSL_LDLIBS) $(ASTPJ_LDLIBS) $(LIBEDIT_OBJ) $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS) $(LIBEDIT_LIB) + $(ECHO_PREFIX) echo " [LD] $(OBJS) $(LIBEDIT_OBJ) -> $@" + $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) $(ASTSSL_LDLIBS) $(ASTPJ_LDLIBS) $(LIBEDIT_OBJ) buildinfo.o $(AST_LIBS) $(GMIMELDFLAGS) $(LIBEDIT_LIB) ifeq ($(GNU_LD),1) $(MAIN_TGT): asterisk.exports diff --git a/main/loader.c b/main/loader.c index dacfce1f687..380fe1c92fa 100644 --- a/main/loader.c +++ b/main/loader.c @@ -109,10 +109,6 @@ static const unsigned char expected_key[] = static char buildopt_sum[33] = AST_BUILDOPT_SUM; -static unsigned int embedding = 1; /* we always start out by registering embedded modules, - since they are here before we dlopen() any - */ - /*! * \brief Internal flag to indicate all modules have been initially loaded. */ @@ -146,14 +142,6 @@ const char *ast_module_name(const struct ast_module *mod) return mod->info->name; } -/* - * module_list is cleared by its constructor possibly after - * we start accumulating embedded modules, so we need to - * use another list (without the lock) to accumulate them. - * Then we update the main list when embedding is done. - */ -static struct module_list embedded_module_list; - struct loadupdate { int (*updater)(void); AST_LIST_ENTRY(loadupdate) entry; @@ -182,15 +170,7 @@ static struct ast_module *resource_being_loaded; void ast_module_register(const struct ast_module_info *info) { - struct ast_module *mod; - - if (embedding) { - if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1))) - return; - strcpy(mod->resource, info->name); - } else { - mod = resource_being_loaded; - } + struct ast_module *mod = resource_being_loaded; ast_debug(5, "Registering module %s\n", info->name); @@ -206,18 +186,14 @@ void ast_module_register(const struct ast_module_info *info) might be unsafe to use the list lock at that point... so let's avoid it altogether */ - if (embedding) { - AST_DLLIST_INSERT_TAIL(&embedded_module_list, mod, entry); - } else { - AST_DLLIST_LOCK(&module_list); - /* it is paramount that the new entry be placed at the tail of - the list, otherwise the code that uses dlopen() to load - dynamic modules won't be able to find out if the module it - just opened was registered or failed to load - */ - AST_DLLIST_INSERT_TAIL(&module_list, mod, entry); - AST_DLLIST_UNLOCK(&module_list); - } + AST_DLLIST_LOCK(&module_list); + /* it is paramount that the new entry be placed at the tail of + the list, otherwise the code that uses dlopen() to load + dynamic modules won't be able to find out if the module it + just opened was registered or failed to load + */ + AST_DLLIST_INSERT_TAIL(&module_list, mod, entry); + AST_DLLIST_UNLOCK(&module_list); /* give the module a copy of its own handle, for later use in registrations and the like */ *((struct ast_module **) &(info->self)) = mod; @@ -431,8 +407,6 @@ static struct ast_module *find_resource(const char *resource, int do_lock) return cur; } -#ifdef LOADABLE_MODULES - /*! * \brief dlclose(), with failure logging. */ @@ -605,8 +579,6 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned return AST_DLLIST_LAST(&module_list); } -#endif - int modules_shutdown(void) { struct ast_module *mod; @@ -721,18 +693,11 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f AST_DLLIST_UNLOCK(&module_list); - if (!error && !mod->lib && mod->info && mod->info->restore_globals) - mod->info->restore_globals(); - -#ifdef LOADABLE_MODULES if (!error) { unload_dynamic_module(mod); ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name); - } -#endif - - if (!error) ast_update_use_count(); + } return res; } @@ -1072,7 +1037,6 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) return AST_MODULE_LOAD_SKIP; } else { -#ifdef LOADABLE_MODULES mod = load_dynamic_module(resource_name, global_symbols_only, suppress_logging, resource_heap); if (mod == MODULE_LOCAL_ONLY) { return AST_MODULE_LOAD_SKIP; @@ -1083,22 +1047,11 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi } return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; } -#else - ast_log(LOG_WARNING, "Module support is not available. Module '%s' could not be loaded.\n", resource_name); - return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; -#endif } if (inspect_module(mod)) { ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); -#ifdef LOADABLE_MODULES unload_dynamic_module(mod); -#endif - return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; - } - - if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) { - ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name); return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; } @@ -1316,7 +1269,6 @@ static int load_resource_list(struct load_order *load_order, unsigned int global int load_modules(unsigned int preload_only) { struct ast_config *cfg; - struct ast_module *mod; struct load_order_entry *order; struct ast_variable *v; unsigned int load_count; @@ -1324,14 +1276,8 @@ int load_modules(unsigned int preload_only) int res = 0; struct ast_flags config_flags = { 0 }; int modulecount = 0; - -#ifdef LOADABLE_MODULES struct dirent *dirent; DIR *dir; -#endif - - /* all embedded modules have registered themselves by now */ - embedding = 0; ast_verb(1, "Asterisk Dynamic Loader Starting:\n"); @@ -1339,12 +1285,6 @@ int load_modules(unsigned int preload_only) AST_DLLIST_LOCK(&module_list); - if (embedded_module_list.first) { - module_list.first = embedded_module_list.first; - module_list.last = embedded_module_list.last; - embedded_module_list.first = NULL; - } - cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags); if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG); @@ -1366,19 +1306,6 @@ int load_modules(unsigned int preload_only) /* check if 'autoload' is on */ if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { - /* if so, first add all the embedded modules that are not already running to the load order */ - AST_DLLIST_TRAVERSE(&module_list, mod, entry) { - /* if it's not embedded, skip it */ - if (mod->lib) - continue; - - if (mod->flags.running) - continue; - - add_to_load_order(mod->resource, &load_order, 0); - } - -#ifdef LOADABLE_MODULES /* if we are allowed to load dynamic modules, scan the directory for for all available modules and add them as well */ if ((dir = opendir(ast_config_AST_MODULE_DIR))) { @@ -1407,7 +1334,6 @@ int load_modules(unsigned int preload_only) ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n", ast_config_AST_MODULE_DIR); } -#endif } /* now scan the config for any modules we are prohibited from loading and diff --git a/makeopts.in b/makeopts.in index 5bc5258dab8..03ef7470c1e 100644 --- a/makeopts.in +++ b/makeopts.in @@ -62,9 +62,6 @@ HOST_OS=@HOST_OS@ OSARCH=@OSARCH@ OSREV=@PBX_OSREV@ -GC_CFLAGS=@GC_CFLAGS@ -GC_LDFLAGS=@GC_LDFLAGS@ - PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ PTHREAD_LIBS=@PTHREAD_LIBS@ diff --git a/third-party/Makefile b/third-party/Makefile index f3016f15332..59b7c064972 100644 --- a/third-party/Makefile +++ b/third-party/Makefile @@ -6,7 +6,7 @@ TP_SUBDIRS := pjproject # to prevent accidentally running the package's default install target. TP_INSTALL_SUBDIRS := pjproject -.PHONY: all dist-clean distclean install clean moduleinfo makeopts uninstall __embed_libs __embed_ldscript __embed_ldflags $(TP_SUBDIRS) +.PHONY: all dist-clean distclean install clean moduleinfo makeopts uninstall $(TP_SUBDIRS) override MAKECMDGOALS?=all From fd204d5c657138885ca5ba34ffa98804becc25fb Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 27 Mar 2017 10:35:15 -0400 Subject: [PATCH 1161/1578] res_musiconhold: Document the 'format' option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASTERISK-26086 #close Reported by: Jens Bürger Change-Id: I6aab666c0bf01fd0c64d7a5bcb22fa7f5d41335e --- configs/samples/musiconhold.conf.sample | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configs/samples/musiconhold.conf.sample b/configs/samples/musiconhold.conf.sample index 3df29bf6973..b2980fc1de4 100644 --- a/configs/samples/musiconhold.conf.sample +++ b/configs/samples/musiconhold.conf.sample @@ -85,7 +85,11 @@ directory=moh ;[ulawstream] ;mode=custom ;application=/usr/bin/streamplayer 192.168.100.52 888 -;format=ulaw +;format=ulaw ; The 'format' option specifies the audio format that the +; ; 'application' will provide to Asterisk. In this example, +; ; streamplayer will output ulaw samples so we need to set the +; ; format to ulaw so that Asterisk knows how to interpret the +; ; incoming audio. ; mpg123 on Solaris does not always exit properly; madplay may be a better ; choice From 5d938045d465d66e28bb49816c482a8b68f99342 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 8 Mar 2017 13:24:46 +0000 Subject: [PATCH 1162/1578] channel: Remove old epoll support and fixed max number of file descriptors. This change removes the old epoll support which has not been used or maintained in quite some time. The fixed number of file descriptors on a channel has also been removed. File descriptors are now contained in a growable vector. This can be used like before by specifying a specific position to store a file descriptor at or using a new API call, ast_channel_fd_add, which adds a file descriptor to the channel and returns its position. Tests have been added which cover the growing behavior of the vector and the new API call. ASTERISK-26885 Change-Id: I1a754b506c009b83dfdeeb08c2d2815db30ef928 --- apps/app_dial.c | 19 -- apps/app_queue.c | 18 -- include/asterisk/channel.h | 38 ++-- main/channel.c | 336 +++--------------------------------- main/channel_internal_api.c | 67 +++---- main/dial.c | 9 - tests/test_channel.c | 119 +++++++++++++ 7 files changed, 201 insertions(+), 405 deletions(-) create mode 100644 tests/test_channel.c diff --git a/apps/app_dial.c b/apps/app_dial.c index 1cb91811fed..c8fcf4696ff 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1186,9 +1186,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, int prestart = num.busy + num.congestion + num.nochan; int orig = *to; struct ast_channel *peer = NULL; -#ifdef HAVE_EPOLL - struct chanlist *epollo; -#endif struct chanlist *outgoing = AST_LIST_FIRST(out_chans); /* single is set if only one destination is enabled */ int single = outgoing && !AST_LIST_NEXT(outgoing, node); @@ -1227,12 +1224,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL); -#ifdef HAVE_EPOLL - AST_LIST_TRAVERSE(out_chans, epollo, node) { - ast_poll_channel_add(in, epollo->chan); - } -#endif - while ((*to = ast_remaining_ms(start, orig)) && !peer) { struct chanlist *o; int pos = 0; /* how many channels do we handle */ @@ -1359,9 +1350,6 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, f = ast_read(winner); if (!f) { ast_channel_hangupcause_set(in, ast_channel_hangupcause(c)); -#ifdef HAVE_EPOLL - ast_poll_channel_del(in, c); -#endif ast_channel_publish_dial(in, c, NULL, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(c))); ast_hangup(c); c = o->chan = NULL; @@ -1786,13 +1774,6 @@ skip_frame:; publish_dial_end_event(in, out_chans, NULL, "NOANSWER"); } -#ifdef HAVE_EPOLL - AST_LIST_TRAVERSE(out_chans, epollo, node) { - if (epollo->chan) - ast_poll_channel_del(in, epollo->chan); - } -#endif - if (is_cc_recall) { ast_cc_completed(in, "Recall completed!"); } diff --git a/apps/app_queue.c b/apps/app_queue.c index 3886b7c7adc..b394084b781 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4794,9 +4794,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte char membername[80] = ""; long starttime = 0; long endtime = 0; -#ifdef HAVE_EPOLL - struct callattempt *epollo; -#endif char *inchan_name; struct timeval start_time_tv = ast_tvnow(); int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */ @@ -4806,13 +4803,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_channel_unlock(qe->chan); starttime = (long) time(NULL); -#ifdef HAVE_EPOLL - for (epollo = outgoing; epollo; epollo = epollo->q_next) { - if (epollo->chan) { - ast_poll_channel_add(in, epollo->chan); - } - } -#endif while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) { int numlines, retry, pos = 1; @@ -5325,14 +5315,6 @@ skip_frame:; publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER"); } -#ifdef HAVE_EPOLL - for (epollo = outgoing; epollo; epollo = epollo->q_next) { - if (epollo->chan) { - ast_poll_channel_del(in, epollo->chan); - } - } -#endif - return peer; } diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 9a3a967e2e3..391e58ccf97 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -183,7 +183,8 @@ extern "C" { #define DATASTORE_INHERIT_FOREVER INT_MAX -#define AST_MAX_FDS 11 +#define AST_MAX_FDS 11 /*!< original maximum number of file descriptors */ +#define AST_EXTENDED_FDS 12 /*!< the start of extended file descriptor positions */ /* * We have AST_MAX_FDS file descriptors in a channel. * Some of them have a fixed use: @@ -2402,12 +2403,6 @@ void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_par /*! Set the file descriptor on the channel */ void ast_channel_set_fd(struct ast_channel *chan, int which, int fd); -/*! Add a channel to an optimized waitfor */ -void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1); - -/*! Delete a channel from an optimized waitfor */ -void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1); - /*! Start a tone going */ int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol); /*! Stop a tone from playing */ @@ -4300,11 +4295,30 @@ void ast_channel_internal_fd_set(struct ast_channel *chan, int which, int value) int ast_channel_fd(const struct ast_channel *chan, int which); int ast_channel_fd_isset(const struct ast_channel *chan, int which); -/* epoll data internal accessors */ -#ifdef HAVE_EPOLL -struct ast_epoll_data *ast_channel_internal_epfd_data(const struct ast_channel *chan, int which); -void ast_channel_internal_epfd_data_set(struct ast_channel *chan, int which , struct ast_epoll_data *value); -#endif +/*! + * \since 15 + * \brief Retrieve the number of file decriptor positions present on the channel + * + * \param chan The channel to get the count of + * + * \pre chan is locked + * + * \return The number of file descriptor positions + */ +int ast_channel_fd_count(const struct ast_channel *chan); + +/*! + * \since 15 + * \brief Add a file descriptor to the channel without a fixed position + * + * \param chan The channel to add the file descriptor to + * \param value The file descriptor + * + * \pre chan is locked + * + * \return The position of the file descriptor + */ +int ast_channel_fd_add(struct ast_channel *chan, int value); pthread_t ast_channel_blocker(const struct ast_channel *chan); void ast_channel_blocker_set(struct ast_channel *chan, pthread_t value); diff --git a/main/channel.c b/main/channel.c index 15c7fa4062c..31f363938f1 100644 --- a/main/channel.c +++ b/main/channel.c @@ -78,21 +78,12 @@ /*** DOCUMENTATION ***/ -#ifdef HAVE_EPOLL -#include -#endif - #if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) #if defined(HAVE_PRI) #include "libpri.h" #endif /* defined(HAVE_PRI) */ #endif /* defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) */ -struct ast_epoll_data { - struct ast_channel *chan; - int which; -}; - /* uncomment if you have problems with 'monitoring' synchronized files */ #if 0 #define MONITOR_CONSTANT_DELAY @@ -850,10 +841,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_channel_internal_alertpipe_clear(tmp); ast_channel_internal_fd_clear_all(tmp); -#ifdef HAVE_EPOLL - ast_channel_epfd_set(tmp, epoll_create(25)); -#endif - if (!(schedctx = ast_sched_context_create())) { ast_log(LOG_WARNING, "Channel allocation failed: Unable to create schedule context\n"); /* See earlier channel creation abort comment above. */ @@ -1058,9 +1045,6 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const ast_channel_timingfd_set(tmp, -1); ast_channel_internal_alertpipe_clear(tmp); ast_channel_internal_fd_clear_all(tmp); -#ifdef HAVE_EPOLL - ast_channel_epfd_set(tmp, -1); -#endif ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD); @@ -2223,9 +2207,6 @@ void ast_party_redirecting_free(struct ast_party_redirecting *doomed) static void ast_channel_destructor(void *obj) { struct ast_channel *chan = obj; -#ifdef HAVE_EPOLL - int i; -#endif struct ast_var_t *vardata; struct ast_frame *f; struct varshead *headp; @@ -2323,14 +2304,6 @@ static void ast_channel_destructor(void *obj) ast_timer_close(ast_channel_timer(chan)); ast_channel_timer_set(chan, NULL); } -#ifdef HAVE_EPOLL - for (i = 0; i < AST_MAX_FDS; i++) { - if (ast_channel_internal_epfd_data(chan, i)) { - ast_free(ast_channel_internal_epfd_data(chan, i)); - } - } - close(ast_channel_epfd(chan)); -#endif while ((f = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list))) ast_frfree(f); @@ -2481,82 +2454,10 @@ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const /*! Set the file descriptor on the channel */ void ast_channel_set_fd(struct ast_channel *chan, int which, int fd) { -#ifdef HAVE_EPOLL - struct epoll_event ev; - struct ast_epoll_data *aed = NULL; - - if (ast_channel_fd_isset(chan, which)) { - epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_DEL, ast_channel_fd(chan, which), &ev); - aed = ast_channel_internal_epfd_data(chan, which); - } - - /* If this new fd is valid, add it to the epoll */ - if (fd > -1) { - if (!aed && (!(aed = ast_calloc(1, sizeof(*aed))))) - return; - - ast_channel_internal_epfd_data_set(chan, which, aed); - aed->chan = chan; - aed->which = which; - - ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; - ev.data.ptr = aed; - epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_ADD, fd, &ev); - } else if (aed) { - /* We don't have to keep around this epoll data structure now */ - ast_free(aed); - ast_channel_epfd_data_set(chan, which, NULL); - } -#endif ast_channel_internal_fd_set(chan, which, fd); return; } -/*! Add a channel to an optimized waitfor */ -void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1) -{ -#ifdef HAVE_EPOLL - struct epoll_event ev; - int i = 0; - - if (ast_channel_epfd(chan0) == -1) - return; - - /* Iterate through the file descriptors on chan1, adding them to chan0 */ - for (i = 0; i < AST_MAX_FDS; i++) { - if (!ast_channel_fd_isset(chan1, i)) { - continue; - } - ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; - ev.data.ptr = ast_channel_internal_epfd_data(chan1, i); - epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_ADD, ast_channel_fd(chan1, i), &ev); - } - -#endif - return; -} - -/*! Delete a channel from an optimized waitfor */ -void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1) -{ -#ifdef HAVE_EPOLL - struct epoll_event ev; - int i = 0; - - if (ast_channel_epfd(chan0) == -1) - return; - - for (i = 0; i < AST_MAX_FDS; i++) { - if (!ast_channel_fd_isset(chan1, i)) { - continue; - } - epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_DEL, ast_channel_fd(chan1, i), &ev); - } - -#endif - return; -} - void ast_channel_clear_softhangup(struct ast_channel *chan, int flag) { ast_channel_lock(chan); @@ -3061,20 +2962,15 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception) } /*! \brief Wait for x amount of time on a file descriptor to have input. */ -#ifdef HAVE_EPOLL -static struct ast_channel *ast_waitfor_nandfds_classic(struct ast_channel **c, int n, int *fds, int nfds, - int *exception, int *outfd, int *ms) -#else struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms) -#endif { struct timeval start = { 0 , 0 }; struct pollfd *pfds = NULL; int res; long rms; int x, y, max; - int sz; + int sz = nfds; struct timeval now = { 0, 0 }; struct timeval whentohangup = { 0, 0 }, diff; struct ast_channel *winner = NULL; @@ -3090,14 +2986,6 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, *exception = 0; } - if ((sz = n * AST_MAX_FDS + nfds)) { - pfds = ast_alloca(sizeof(*pfds) * sz); - fdmap = ast_alloca(sizeof(*fdmap) * sz); - } else { - /* nothing to allocate and no FDs to check */ - return NULL; - } - for (x = 0; x < n; x++) { ast_channel_lock(c[x]); if (!ast_tvzero(*ast_channel_whentohangup(c[x]))) { @@ -3114,8 +3002,17 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, if (ast_tvzero(whentohangup) || ast_tvcmp(diff, whentohangup) < 0) whentohangup = diff; } + sz += ast_channel_fd_count(c[x]); ast_channel_unlock(c[x]); } + + if (!sz) { + return NULL; + } + + pfds = ast_alloca(sizeof(*pfds) * sz); + fdmap = ast_alloca(sizeof(*fdmap) * sz); + /* Wait full interval */ rms = *ms; /* INT_MAX, not LONG_MAX, because it matters on 64-bit */ @@ -3135,12 +3032,12 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, */ max = 0; for (x = 0; x < n; x++) { - for (y = 0; y < AST_MAX_FDS; y++) { + ast_channel_lock(c[x]); + for (y = 0; y < ast_channel_fd_count(c[x]); y++) { fdmap[max].fdno = y; /* fd y is linked to this pfds */ fdmap[max].chan = x; /* channel x is linked to this pfds */ max += ast_add_fd(&pfds[max], ast_channel_fd(c[x], y)); } - ast_channel_lock(c[x]); CHECK_BLOCKING(c[x]); ast_channel_unlock(c[x]); } @@ -3234,205 +3131,6 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, return winner; } -#ifdef HAVE_EPOLL -static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan, int *ms) -{ - struct timeval start = { 0 , 0 }; - int res = 0; - struct epoll_event ev[1]; - long diff, rms = *ms; - struct ast_channel *winner = NULL; - struct ast_epoll_data *aed = NULL; - - ast_channel_lock(chan); - /* Figure out their timeout */ - if (!ast_tvzero(*ast_channel_whentohangup(chan))) { - if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(chan), ast_tvnow())) < 0) { - /* They should already be hungup! */ - ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_TIMEOUT); - ast_channel_unlock(chan); - return NULL; - } - /* If this value is smaller then the current one... make it priority */ - if (rms > diff) { - rms = diff; - } - } - - ast_channel_unlock(chan); - - /* Time to make this channel block... */ - CHECK_BLOCKING(chan); - - if (*ms > 0) { - start = ast_tvnow(); - } - - /* We don't have to add any file descriptors... they are already added, we just have to wait! */ - res = epoll_wait(ast_channel_epfd(chan), ev, 1, rms); - - /* Stop blocking */ - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING); - - /* Simulate a timeout if we were interrupted */ - if (res < 0) { - if (errno != EINTR) { - *ms = -1; - } - return NULL; - } - - /* If this channel has a timeout see if it expired */ - if (!ast_tvzero(*ast_channel_whentohangup(chan))) { - if (ast_tvdiff_ms(ast_tvnow(), *ast_channel_whentohangup(chan)) >= 0) { - ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_TIMEOUT); - winner = chan; - } - } - - /* No fd ready, reset timeout and be done for now */ - if (!res) { - *ms = 0; - return winner; - } - - /* See what events are pending */ - aed = ev[0].data.ptr; - ast_channel_fdno_set(chan, aed->which); - if (ev[0].events & EPOLLPRI) { - ast_set_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION); - } else { - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION); - } - - if (*ms > 0) { - *ms -= ast_tvdiff_ms(ast_tvnow(), start); - if (*ms < 0) { - *ms = 0; - } - } - - return chan; -} - -static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, int n, int *ms) -{ - struct timeval start = { 0 , 0 }; - int res = 0, i; - struct epoll_event ev[25] = { { 0, } }; - struct timeval now = { 0, 0 }; - long whentohangup = 0, diff = 0, rms = *ms; - struct ast_channel *winner = NULL; - - for (i = 0; i < n; i++) { - ast_channel_lock(c[i]); - if (!ast_tvzero(*ast_channel_whentohangup(c[i]))) { - if (whentohangup == 0) { - now = ast_tvnow(); - } - if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(c[i]), now)) < 0) { - ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT); - ast_channel_unlock(c[i]); - return c[i]; - } - if (!whentohangup || whentohangup > diff) { - whentohangup = diff; - } - } - ast_channel_unlock(c[i]); - CHECK_BLOCKING(c[i]); - } - - rms = *ms; - if (whentohangup) { - rms = whentohangup; - if (*ms >= 0 && *ms < rms) { - rms = *ms; - } - } - - if (*ms > 0) { - start = ast_tvnow(); - } - - res = epoll_wait(ast_channel_epfd(c[0]), ev, 25, rms); - - for (i = 0; i < n; i++) { - ast_clear_flag(ast_channel_flags(c[i]), AST_FLAG_BLOCKING); - } - - if (res < 0) { - if (errno != EINTR) { - *ms = -1; - } - return NULL; - } - - if (whentohangup) { - now = ast_tvnow(); - for (i = 0; i < n; i++) { - if (!ast_tvzero(*ast_channel_whentohangup(c[i])) && ast_tvdiff_ms(now, *ast_channel_whentohangup(c[i])) >= 0) { - ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT); - if (!winner) { - winner = c[i]; - } - } - } - } - - if (!res) { - *ms = 0; - return winner; - } - - for (i = 0; i < res; i++) { - struct ast_epoll_data *aed = ev[i].data.ptr; - - if (!ev[i].events || !aed) { - continue; - } - - winner = aed->chan; - if (ev[i].events & EPOLLPRI) { - ast_set_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION); - } else { - ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION); - } - ast_channel_fdno_set(winner, aed->which); - } - - if (*ms > 0) { - *ms -= ast_tvdiff_ms(ast_tvnow(), start); - if (*ms < 0) { - *ms = 0; - } - } - - return winner; -} - -struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, - int *exception, int *outfd, int *ms) -{ - /* Clear all provided values in one place. */ - if (outfd) { - *outfd = -99999; - } - if (exception) { - *exception = 0; - } - - /* If no epoll file descriptor is available resort to classic nandfds */ - if (!n || nfds || ast_channel_epfd(c[0]) == -1) { - return ast_waitfor_nandfds_classic(c, n, fds, nfds, exception, outfd, ms); - } else if (!nfds && n == 1) { - return ast_waitfor_nandfds_simple(c[0], ms); - } else { - return ast_waitfor_nandfds_complex(c, n, ms); - } -} -#endif - struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms) { return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms); @@ -6852,6 +6550,7 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann int origstate; unsigned int orig_disablestatecache; unsigned int clone_disablestatecache; + int generator_fd; int visible_indication; int clone_hold_state; int moh_is_playing; @@ -7042,8 +6741,13 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann /* Keep the same parkinglot. */ ast_channel_parkinglot_set(original, ast_channel_parkinglot(clonechan)); - /* Copy the FD's other than the generator fd */ - for (x = 0; x < AST_MAX_FDS; x++) { + /* Clear all existing file descriptors but retain the generator */ + generator_fd = ast_channel_fd(original, AST_GENERATOR_FD); + ast_channel_internal_fd_clear_all(original); + ast_channel_set_fd(original, AST_GENERATOR_FD, generator_fd); + + /* Copy all file descriptors present on clonechan to original, skipping generator */ + for (x = 0; x < ast_channel_fd_count(clonechan); x++) { if (x != AST_GENERATOR_FD) ast_channel_set_fd(original, x, ast_channel_fd(clonechan, x)); } diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index d7ae8f9c118..b3c0a480538 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -48,6 +48,7 @@ #include "asterisk/stringfields.h" #include "asterisk/stream.h" #include "asterisk/test.h" +#include "asterisk/vector.h" /*! * \brief Channel UniqueId structure @@ -96,9 +97,6 @@ struct ast_channel { * in the CHANNEL dialplan function */ struct ast_channel_monitor *monitor; /*!< Channel monitoring */ ast_callid callid; /*!< Bound call identifier pointer */ -#ifdef HAVE_EPOLL - struct ast_epoll_data *epfd_data[AST_MAX_FDS]; -#endif struct ao2_container *dialed_causes; /*!< Contains tech-specific and Asterisk cause data from dialed channels */ AST_DECLARE_STRING_FIELDS( @@ -167,7 +165,7 @@ struct ast_channel { unsigned long insmpl; /*!< Track the read/written samples for monitor use */ unsigned long outsmpl; /*!< Track the read/written samples for monitor use */ - int fds[AST_MAX_FDS]; /*!< File descriptors for channel -- Drivers will poll on + AST_VECTOR(, int) fds; /*!< File descriptors for channel -- Drivers will poll on * these file descriptors, so at least one must be non -1. * See \arg \ref AstFileDesc */ int softhangup; /*!< Whether or not we have been hung up... Do not set this value @@ -197,9 +195,6 @@ struct ast_channel { struct ast_format *rawreadformat; /*!< Raw read format (before translation) */ struct ast_format *rawwriteformat; /*!< Raw write format (after translation) */ unsigned int emulate_dtmf_duration; /*!< Number of ms left to emulate DTMF for */ -#ifdef HAVE_EPOLL - int epfd; -#endif int visible_indication; /*!< Indication currently playing on the channel */ int hold_state; /*!< Current Hold/Unhold state */ @@ -597,17 +592,6 @@ void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value) chan->amaflags = value; ast_channel_publish_snapshot(chan); } - -#ifdef HAVE_EPOLL -int ast_channel_epfd(const struct ast_channel *chan) -{ - return chan->epfd; -} -void ast_channel_epfd_set(struct ast_channel *chan, int value) -{ - chan->epfd = value; -} -#endif int ast_channel_fdno(const struct ast_channel *chan) { return chan->fdno; @@ -1432,38 +1416,55 @@ void ast_channel_internal_alertpipe_swap(struct ast_channel *chan1, struct ast_c /* file descriptor array accessors */ void ast_channel_internal_fd_set(struct ast_channel *chan, int which, int value) { - chan->fds[which] = value; + int pos; + + /* This ensures that if the vector has to grow with unused positions they will be + * initialized to -1. + */ + for (pos = AST_VECTOR_SIZE(&chan->fds); pos < which; pos++) { + AST_VECTOR_REPLACE(&chan->fds, pos, -1); + } + + AST_VECTOR_REPLACE(&chan->fds, which, value); } void ast_channel_internal_fd_clear(struct ast_channel *chan, int which) { - ast_channel_internal_fd_set(chan, which, -1); + if (which >= AST_VECTOR_SIZE(&chan->fds)) { + return; + } + + AST_VECTOR_REPLACE(&chan->fds, which, -1); } void ast_channel_internal_fd_clear_all(struct ast_channel *chan) { - int i; - for (i = 0; i < AST_MAX_FDS; i++) { - ast_channel_internal_fd_clear(chan, i); - } + AST_VECTOR_RESET(&chan->fds, AST_VECTOR_ELEM_CLEANUP_NOOP); } int ast_channel_fd(const struct ast_channel *chan, int which) { - return chan->fds[which]; + return (which >= AST_VECTOR_SIZE(&chan->fds)) ? -1 : AST_VECTOR_GET(&chan->fds, which); } int ast_channel_fd_isset(const struct ast_channel *chan, int which) { return ast_channel_fd(chan, which) > -1; } -#ifdef HAVE_EPOLL -struct ast_epoll_data *ast_channel_internal_epfd_data(const struct ast_channel *chan, int which) +int ast_channel_fd_count(const struct ast_channel *chan) { - return chan->epfd_data[which]; + return AST_VECTOR_SIZE(&chan->fds); } -void ast_channel_internal_epfd_data_set(struct ast_channel *chan, int which , struct ast_epoll_data *value) + +int ast_channel_fd_add(struct ast_channel *chan, int value) { - chan->epfd_data[which] = value; + int pos = AST_EXTENDED_FDS; + + while (ast_channel_fd_isset(chan, pos)) { + pos += 1; + } + + AST_VECTOR_REPLACE(&chan->fds, pos, value); + + return pos; } -#endif pthread_t ast_channel_blocker(const struct ast_channel *chan) { @@ -1617,6 +1618,8 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), tmp->linkedid = tmp->uniqueid; } + AST_VECTOR_INIT(&tmp->fds, AST_MAX_FDS); + return tmp; } @@ -1693,6 +1696,8 @@ void ast_channel_internal_cleanup(struct ast_channel *chan) chan->topics = NULL; ast_channel_internal_set_stream_topology(chan, NULL); + + AST_VECTOR_FREE(&chan->fds); } void ast_channel_internal_finalize(struct ast_channel *chan) diff --git a/main/dial.c b/main/dial.c index cc2366ed7aa..d0492dcfdda 100644 --- a/main/dial.c +++ b/main/dial.c @@ -479,9 +479,6 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann ast_hangup(channel->owner); channel->owner = NULL; } else { - if (chan) { - ast_poll_channel_add(chan, channel->owner); - } ast_channel_publish_dial(async ? NULL : chan, channel->owner, channel->device, NULL); res = 1; ast_verb(3, "Called %s\n", numsubst); @@ -868,8 +865,6 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann set_state(dial, AST_DIAL_RESULT_HANGUP); break; } - if (chan) - ast_poll_channel_del(chan, channel->owner); ast_channel_publish_dial(chan, who, channel->device, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(who))); ast_hangup(who); channel->owner = NULL; @@ -890,8 +885,6 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (!channel->owner || channel->owner == who) continue; - if (chan) - ast_poll_channel_del(chan, channel->owner); ast_channel_publish_dial(chan, channel->owner, channel->device, "CANCEL"); ast_hangup(channel->owner); channel->cause = AST_CAUSE_ANSWERED_ELSEWHERE; @@ -915,8 +908,6 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (!channel->owner) continue; - if (chan) - ast_poll_channel_del(chan, channel->owner); ast_channel_publish_dial(chan, channel->owner, channel->device, "CANCEL"); ast_hangup(channel->owner); channel->cause = AST_CAUSE_NORMAL_CLEARING; diff --git a/tests/test_channel.c b/tests/test_channel.c new file mode 100644 index 00000000000..854aff782dd --- /dev/null +++ b/tests/test_channel.c @@ -0,0 +1,119 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Channel unit tests + * + * \author Joshua Colp + * + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" + +#include "asterisk/module.h" +#include "asterisk/test.h" +#include "asterisk/channel.h" + +AST_TEST_DEFINE(set_fd_grow) +{ + struct ast_channel *mock_channel; + enum ast_test_result_state res = AST_TEST_PASS; + int pos; + + switch (cmd) { + case TEST_INIT: + info->name = "set_fd_grow"; + info->category = "/main/channel/"; + info->summary = "channel setting file descriptor with growth test"; + info->description = + "Test that setting a file descriptor on a high position of a channel results in -1 set on any new positions"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"); + ast_test_validate_cleanup(test, mock_channel, res, done); + + ast_channel_set_fd(mock_channel, AST_EXTENDED_FDS + 10, 1); + ast_test_validate_cleanup(test, ast_channel_fd_count(mock_channel) == AST_EXTENDED_FDS + 11, res, done); + + for (pos = AST_EXTENDED_FDS; (pos < AST_EXTENDED_FDS + 10); pos++) { + ast_test_validate_cleanup(test, ast_channel_fd(mock_channel, pos) == -1, res, done); + } + +done: + ast_hangup(mock_channel); + + return res; +} + +AST_TEST_DEFINE(add_fd) +{ + struct ast_channel *mock_channel; + enum ast_test_result_state res = AST_TEST_PASS; + int pos; + + switch (cmd) { + case TEST_INIT: + info->name = "add_fd"; + info->category = "/main/channel/"; + info->summary = "channel adding file descriptor test"; + info->description = + "Test that adding a file descriptor to a channel places it in the expected position"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"); + ast_test_validate_cleanup(test, mock_channel, res, done); + + pos = ast_channel_fd_add(mock_channel, 1); + ast_test_validate_cleanup(test, pos == AST_EXTENDED_FDS, res, done); + + ast_channel_set_fd(mock_channel, pos, -1); + ast_test_validate_cleanup(test, ast_channel_fd(mock_channel, pos) == -1, res, done); + +done: + ast_hangup(mock_channel); + + return res; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(set_fd_grow); + AST_TEST_UNREGISTER(add_fd); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(set_fd_grow); + AST_TEST_REGISTER(add_fd); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel Unit Tests"); From 3d8899bacfeff2e0e528d7667121a9ef0cb990cd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 27 Mar 2017 12:37:39 -0500 Subject: [PATCH 1163/1578] Add DTLS sanity check. Change-Id: Ib32612cf6c7ce9213a11b9cba82f630f8cd3564b --- res/res_pjsip_sdp_rtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index b66c1aeb821..21de4409c1d 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -781,7 +781,7 @@ static void apply_dtls_attrib(struct ast_sip_session_media *session_media, struct ast_rtp_engine_dtls *dtls = ast_rtp_instance_get_dtls(session_media->rtp); pj_str_t *value; - if (!attr->value.ptr) { + if (!attr->value.ptr || !dtls) { return; } From 7c0b12dc41ae99345ba6de07db3bbf06ce57e372 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 28 Mar 2017 10:29:25 -0400 Subject: [PATCH 1164/1578] alembic: Turn off execute bit on non-executable python scripts Change-Id: I744c986da4a38aeff8c00837eb89de7841fbc86c --- .../ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py | 0 .../config/versions/10aedae86a32_add_outgoing_enum_va.py | 0 .../config/versions/1758e8bbf6b_increase_useragent_column_size.py | 0 .../config/versions/21e526ad3040_add_pjsip_debug_option.py | 0 .../config/versions/23530d604b96_add_rpid_immediate.py | 0 .../config/versions/28887f25a46f_create_queue_tables.py | 0 .../versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py | 0 .../config/versions/43956d550a44_add_tables_for_pjsip.py | 0 .../config/versions/4c573e7135bd_fix_tos_field_types.py | 0 .../ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py | 0 .../versions/5139253c0423_make_q_member_uniqueid_autoinc.py | 0 .../config/versions/581a4264e537_adding_extensions.py | 0 contrib/ast-db-manage/env.py | 0 .../versions/39428242f7f5_increase_recording_column_size.py | 0 .../ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py | 0 15 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 contrib/ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/28887f25a46f_create_queue_tables.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py mode change 100755 => 100644 contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py mode change 100755 => 100644 contrib/ast-db-manage/env.py mode change 100755 => 100644 contrib/ast-db-manage/voicemail/versions/39428242f7f5_increase_recording_column_size.py mode change 100755 => 100644 contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py diff --git a/contrib/ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py b/contrib/ast-db-manage/cdr/versions/210693f3123d_create_cdr_table.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py b/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/28887f25a46f_create_queue_tables.py b/contrib/ast-db-manage/config/versions/28887f25a46f_create_queue_tables.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py b/contrib/ast-db-manage/config/versions/43956d550a44_add_tables_for_pjsip.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py b/contrib/ast-db-manage/config/versions/4da0c5f79a9c_create_tables.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py b/contrib/ast-db-manage/config/versions/581a4264e537_adding_extensions.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/env.py b/contrib/ast-db-manage/env.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/voicemail/versions/39428242f7f5_increase_recording_column_size.py b/contrib/ast-db-manage/voicemail/versions/39428242f7f5_increase_recording_column_size.py old mode 100755 new mode 100644 diff --git a/contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py b/contrib/ast-db-manage/voicemail/versions/a2e9769475e_create_tables.py old mode 100755 new mode 100644 From 2fe52174de092c89080d0e6dc567bb2d6797d1e7 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 28 Mar 2017 12:10:32 -0600 Subject: [PATCH 1165/1578] res_pjsip_config_wizard: Add 2 new parameters to help with proxy config Two new parameters have been added to the pjsip config wizard. * Setting 'sends_line_with_registrations' to true will cause the wizard to skip the creation of an identify object to match incoming request to the endpoint and instead add the line and endpoint parameters to the outbound registration object. * Setting 'outbound_proxy' is a shortcut for adding individual endpoint/outbound_proxy, aor/outbound_proxy and registration/outbound_proxy parameters. Change-Id: I678e5f80765734c056620528a6d40d82736ceeb0 (cherry picked from commit a827892ff77cd37912b528d9c45b446be091bbc0) (cherry picked from commit 27344675be1941d30508c6e6bd684acdd0791e1a) --- CHANGES | 19 ++++++++++++ configs/samples/pjsip_wizard.conf.sample | 12 ++++++++ res/res_pjsip_config_wizard.c | 38 ++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 5d14c97d176..f7f8505b8f9 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,25 @@ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ +------------------------------------------------------------------------------ + +res_pjsip_config_wizard +------------------ + * Two new parameters have been added to the pjsip config wizard. + Setting 'sends_line_with_registrations' to true will cause the wizard + to skip the creation of an identify object to match incoming requests + to the endpoint and instead add the line and endpoint parameters to + the outbound registration object. + Setting 'outbound_proxy' is a shortcut for adding individual + endpoint/outbound_proxy, aor/outbound_proxy and registration/outbound_proxy + parameters. + +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14.3.0 to Asterisk 14.4.0 ------------ +------------------------------------------------------------------------------ + Build System ------------------ * LOW_MEMORY no longer has an effect on Asterisk ABI. Symbols that were diff --git a/configs/samples/pjsip_wizard.conf.sample b/configs/samples/pjsip_wizard.conf.sample index 0f46083af56..8c8572e4d34 100644 --- a/configs/samples/pjsip_wizard.conf.sample +++ b/configs/samples/pjsip_wizard.conf.sample @@ -79,6 +79,13 @@ ; sends_auth must also be specified. ; (default: "no") +;sends_line_with_registrations= ; Setting this to true will cause the wizard to + ; skip the creation of an identify object to match + ; incoming requests to the endpoint and instead add the + ; line and endpoint parameters to the outbound + ; registration object. + ; (default: "no") + ;accepts_registrations= ; Will create an aor with dynamic contacts which will ; accept registrations. ; accepts_auth must also be specified. @@ -96,6 +103,11 @@ ; SRV records are not currently supported. ; (default: "") +;outbound_proxy= ; Setting this is a shortcut for setting + ; endpoint/outbound_proxy + ; aor/outbound_proxy + ; registration/outbound_proxy + ;transport= ; The transport to use for the endpoint and registrations ; (default: the pjsip default) diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index 83e282821f1..1526dc2e2e1 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -139,6 +139,12 @@ entry in the list. If send_registrations is also set, a registration will also be created for each. + + Shortcut for specifying proxy on individual objects. + Shortcut for specifying endpoint/outbound_proxy, + aor/outbound_proxy, and registration/outbound_proxy individually. + + Send outbound authentication to remote hosts. At least outbound_auth/username is required. @@ -153,6 +159,13 @@ be created for each host in the remote _hosts string. If authentication is required, sends_auth and an outbound_auth/username must also be supplied. + + Sets "line" and "endpoint parameters on registrations. + Setting this to true will cause the wizard to skip the + creation of an identify object to match incoming requests to the endpoint and + instead add the line and endpoint parameters to the outbound registration object. + + Accept inbound registration from remote hosts. An AOR with dynamic contacts will be created. If @@ -595,11 +608,16 @@ static int handle_aor(const struct ast_sorcery *sorcery, struct object_type_wiza struct ast_sorcery_object *obj = NULL; const char *id = ast_category_get_name(wiz); const char *contact_pattern; + const char *outbound_proxy = ast_variable_find_last_in_list(wizvars, "outbound_proxy"); int host_count = AST_VECTOR_SIZE(remote_hosts_vector); RAII_VAR(struct ast_variable *, vars, get_object_variables(wizvars, "aor/"), ast_variables_destroy); variable_list_append(&vars, "@pjsip_wizard", id); + if (!ast_strlen_zero(outbound_proxy)) { + variable_list_append_return(&vars, "outbound_proxy", outbound_proxy); + } + /* If the user explicitly specified an aor/contact, don't use remote hosts. */ if (!ast_variable_find_last_in_list(vars, "contact")) { if (!(contact_pattern = ast_variable_find_last_in_list(wizvars, "contact_pattern"))) { @@ -647,6 +665,7 @@ static int handle_endpoint(const struct ast_sorcery *sorcery, struct object_type struct ast_variable *wizvars = ast_category_first(wiz); struct ast_sorcery_object *obj = NULL; const char *id = ast_category_get_name(wiz); + const char *outbound_proxy = ast_variable_find_last_in_list(wizvars, "outbound_proxy"); const char *transport = ast_variable_find_last_in_list(wizvars, "transport"); const char *hint_context = hint_context = ast_variable_find_last_in_list(wizvars, "hint_context"); const char *hint_exten = ast_variable_find_last_in_list(wizvars, "hint_exten"); @@ -657,6 +676,10 @@ static int handle_endpoint(const struct ast_sorcery *sorcery, struct object_type variable_list_append_return(&vars, "@pjsip_wizard", id); variable_list_append_return(&vars, "aors", id); + if (!ast_strlen_zero(outbound_proxy)) { + variable_list_append_return(&vars, "outbound_proxy", outbound_proxy); + } + if (ast_strlen_zero(hint_context)) { hint_context = ast_variable_find_last_in_list(vars, "context"); } @@ -719,8 +742,9 @@ static int handle_identify(const struct ast_sorcery *sorcery, struct object_type snprintf(new_id, sizeof(new_id), "%s-identify", id); - /* If accepting registrations, we don't need an identify. */ - if (is_variable_true(wizvars, "accepts_registrations")) { + /* If accepting registrations or we're sending line, we don't need an identify. */ + if (is_variable_true(wizvars, "accepts_registrations") + || is_variable_true(wizvars, "sends_line_with_registrations")) { /* If one exists, delete it. */ obj = otw->wizard->retrieve_id(sorcery, otw->wizard_data, "identify", new_id); if (obj) { @@ -836,6 +860,7 @@ static int handle_registrations(const struct ast_sorcery *sorcery, struct object const char *id = ast_category_get_name(wiz); const char *server_uri_pattern; const char *client_uri_pattern; + const char *outbound_proxy = ast_variable_find_last_in_list(wizvars, "outbound_proxy"); const char *transport = ast_variable_find_last_in_list(wizvars, "transport"); const char *username; char new_id[strlen(id) + MAX_ID_SUFFIX]; @@ -855,6 +880,10 @@ static int handle_registrations(const struct ast_sorcery *sorcery, struct object return -1; } + if (!ast_strlen_zero(outbound_proxy)) { + variable_list_append_return(&vars, "outbound_proxy", outbound_proxy); + } + otw->wizard->retrieve_multiple(sorcery, otw->wizard_data, "registration", existing, search); ast_variables_destroy(search); @@ -925,6 +954,11 @@ static int handle_registrations(const struct ast_sorcery *sorcery, struct object variable_list_append_return(®istration_vars, "transport", transport); } + if (is_variable_true(wizvars, "sends_line_with_registrations")) { + variable_list_append_return(®istration_vars, "line", "yes"); + variable_list_append_return(®istration_vars, "endpoint", id); + } + snprintf(new_id, sizeof(new_id), "%s-reg-%d", id, host_counter); obj = create_object(sorcery, new_id, "registration", registration_vars); From e76cc51d5e1d10f7df3855f5a5f233da1140486e Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 29 Mar 2017 15:04:05 +0200 Subject: [PATCH 1166/1578] srtp: Allow zero as tag value for a sRTP Crypto Suite. ASTERISK-25490 #close Change-Id: I1c5fc0942c33c96d62b24203aad0f1e1a1a0131f --- res/res_srtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_srtp.c b/res/res_srtp.c index a611e61657f..c47a8d55e88 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -782,8 +782,8 @@ static int res_sdp_crypto_parse_offer(struct ast_rtp_instance *rtp, struct ast_s return -1; } - /* RFC4568 9.1 - tag is 1-9 digits, greater than zero */ - if (sscanf(tag, "%30d", &tag_from_sdp) != 1 || tag_from_sdp <= 0 || tag_from_sdp > 999999999) { + /* RFC4568 9.1 - tag is 1-9 digits */ + if (sscanf(tag, "%30d", &tag_from_sdp) != 1 || tag_from_sdp < 0 || tag_from_sdp > 999999999) { ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag); return -1; } From f66edcb8b0ef04be61a92092634918b582f3f843 Mon Sep 17 00:00:00 2001 From: Josh Roberson Date: Mon, 27 Mar 2017 11:49:08 -0500 Subject: [PATCH 1167/1578] cel_pgsql.c: Fix buffer overflow calling libpq PQEscapeStringConn() expects the buffer passed in to be an adequitely sized buffer to write out the escaped SQL value string into. It is possible, for large values (such as large values to Dial with a lot of devices) to have more than our 512+1 byte allocation and thus cause libpq to create a buffer overrun. glibc will nicely ABRT asterisk for you, citing a stack smash. Let's only allocate it to be as large as needed: If we have a value, then (strlen(value) * 2) + 1 (as recommended by libpq), and if we have none, just one byte to hold our null will do. ASTERISK-26896 #close Change-Id: If611c734292618ed68dde17816d09dd16667dea2 --- cel/cel_pgsql.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c index 8d9d5dfce71..eba0726da34 100644 --- a/cel/cel_pgsql.c +++ b/cel/cel_pgsql.c @@ -179,11 +179,14 @@ static void pgsql_log(struct ast_event *event) if (connected) { struct columns *cur; struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2); - char buf[257], escapebuf[513]; + char buf[257]; + char *escapebuf = NULL; const char *value; int first = 1; + size_t bufsize = 513; - if (!sql || !sql2) { + escapebuf = ast_malloc(bufsize); + if (!escapebuf || !sql || !sql2) { goto ast_log_cleanup; } @@ -307,6 +310,22 @@ static void pgsql_log(struct ast_event *event) /* XXX Might want to handle dates, times, and other misc fields here XXX */ } else { if (value) { + size_t required_size = strlen(value) * 2 + 1; + + /* If our argument size exceeds our buffer, grow it, + * as PQescapeStringConn() expects the buffer to be + * adequitely sized and does *NOT* do size checking. + */ + if (required_size > bufsize) { + char *tmpbuf = ast_realloc(escapebuf, required_size); + + if (!tmpbuf) { + goto ast_log_cleanup; + } + + escapebuf = tmpbuf; + bufsize = required_size; + } PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL); } else { escapebuf[0] = '\0'; @@ -377,6 +396,7 @@ static void pgsql_log(struct ast_event *event) ast_log_cleanup: ast_free(sql); ast_free(sql2); + ast_free(escapebuf); } ast_mutex_unlock(&pgsql_lock); From 4e5cc70fb46b0737da94bb0e9783818fa3610c6c Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 30 Mar 2017 11:18:38 -0400 Subject: [PATCH 1168/1578] CEL: Remove header declarations of non-existant functions. ast_cel_alloc and ast_cel_destroy do not exist in code, remove them from the headers. Change-Id: I99ce848e2e109e7d61771559f559b9e57973e45c --- include/asterisk/cel.h | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/include/asterisk/cel.h b/include/asterisk/cel.h index 350b4bf9f83..c77a3538cb1 100644 --- a/include/asterisk/cel.h +++ b/include/asterisk/cel.h @@ -87,29 +87,6 @@ enum ast_cel_event_type { */ unsigned int ast_cel_check_enabled(void); -/*! - * \brief Allocate a CEL record - * - * \since 1.8 - * - * \note The CEL record must be destroyed with ast_cel_destroy(). - * - * \retval non-NULL an allocated ast_cel structure - * \retval NULL error - */ -struct ast_cel *ast_cel_alloc(void); - -/*! - * \brief Destroy a CEL record. - * - * \param cel the record to destroy - * - * \since 1.8 - * - * \return nothing. - */ -void ast_cel_destroy(struct ast_cel *cel); - /*! * \brief Get the name of a CEL event type * From 5c1ea3ebbd17b7e409b3531d7b1a9b7615611c4a Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 29 Mar 2017 11:11:51 -0400 Subject: [PATCH 1169/1578] astobj2: Prevent potential deadlocks with ao2_global_obj_release The ao2_global_obj_release() function holds an exclusive lock on the global object while it is being dereferenced. Any destructors that run during this time that call ao2_global_obj_ref() will deadlock because a read lock is required. Instead, we make the global object inaccessible inside of the write lock and only dereference it once we have released the lock. This allows the affected destructors to fail gracefully. While this doesn't completely solve the referenced issue (the error message about not being able to create an IQ continues to be shown) it does solve the backtrace spew that accompanied it. ASTERISK-21009 #close Reported by: Marcello Ceschia Change-Id: Idf40ae136b5070dba22cb576ea8414fbc9939385 --- include/asterisk/astobj2.h | 6 ++---- main/astobj2.c | 24 ------------------------ 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index 28ae73e87ed..484e1e35caa 100644 --- a/include/asterisk/astobj2.h +++ b/include/asterisk/astobj2.h @@ -854,11 +854,9 @@ struct ao2_global_obj { * \return Nothing */ #define ao2_t_global_obj_release(holder, tag) \ - __ao2_global_obj_release(&holder, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder) + __ao2_global_obj_replace_unref(&holder, NULL, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder) #define ao2_global_obj_release(holder) \ - __ao2_global_obj_release(&holder, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder) - -void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name); + __ao2_global_obj_replace_unref(&holder, NULL, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder) /*! * \brief Replace an ao2 object in the global holder. diff --git a/main/astobj2.c b/main/astobj2.c index 1529e91b000..d534900ddfe 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -729,30 +729,6 @@ unsigned int ao2_options_get(void *obj) return orig_obj->priv_data.options; } - -void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name) -{ - if (!holder) { - /* For sanity */ - ast_log(LOG_ERROR, "Must be called with a global object!\n"); - ast_assert(0); - return; - } - if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) { - /* Could not get the write lock. */ - ast_assert(0); - return; - } - - /* Release the held ao2 object. */ - if (holder->obj) { - __ao2_ref(holder->obj, -1, tag, file, line, func); - holder->obj = NULL; - } - - __ast_rwlock_unlock(file, line, func, &holder->lock, name); -} - void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name) { void *obj_old; From f3290d6b664bd2b6ed840b7501666e26b341acb1 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 27 Mar 2017 20:32:45 +0000 Subject: [PATCH 1170/1578] sdp: Add support for setting connection address and clean up state. This change cleans up state management for media streams by moving RTP instances into their own session structure and adding additional details that are not relevant to the core (such as connection address). These can live either in the local capabilities or joint capabilities. The ability to set explicit connection address information for the purposes of direct media and NAT has also been added at the global and stream specific level. ASTERISK-26900 Change-Id: If7e5307239a9534420732de11c451a2705b6b681 --- include/asterisk/sdp.h | 10 +- include/asterisk/sdp_options.h | 20 --- include/asterisk/sdp_state.h | 86 ++++++++++ main/sdp.c | 93 ++-------- main/sdp_options.c | 1 - main/sdp_state.c | 302 +++++++++++++++++++++++++++++++-- 6 files changed, 392 insertions(+), 120 deletions(-) diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h index 4d6d2fbb5d5..3649b403778 100644 --- a/include/asterisk/sdp.h +++ b/include/asterisk/sdp.h @@ -395,20 +395,20 @@ struct ast_sdp_a_line *ast_sdp_get_a(const struct ast_sdp *sdp, int index); int ast_sdp_add_m(struct ast_sdp *sdp, struct ast_sdp_m_line *m_line); /*! - * \brief Add a Media Description to an SDP + * \brief Add an RTP Media Description to an SDP * * \param sdp SDP + * \param sdp_state SDP state information * \param options SDP Options - * \param rtp ast_rtp_instance - * \param stream stream + * \param stream_index stream * * \retval 0 Success * \retval non-0 Failure * * \since 15 */ -int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options *options, - struct ast_rtp_instance *rtp, const struct ast_stream *stream); +int ast_sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, + const struct ast_sdp_options *options, int stream_index); /*! * \brief Get the count of Media Descriptions on an SDP diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index 3995faf4a9e..0186eea57c8 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -268,26 +268,6 @@ void ast_sdp_options_set_g726_non_standard(struct ast_sdp_options *options, */ unsigned int ast_sdp_options_get_g726_non_standard(struct ast_sdp_options *options); -/*! - * \since 15.0.0 - * \brief Set SDP Options locally_held - * - * \param options SDP Options - * \param locally_held - */ -void ast_sdp_options_set_locally_held(struct ast_sdp_options *options, - unsigned int locally_held); - -/*! - * \since 15.0.0 - * \brief Get SDP Options locally_held - * - * \param options SDP Options - * - * \returns locally_held - */ -unsigned int ast_sdp_options_get_locally_held(struct ast_sdp_options *options); - /*! * \since 15.0.0 * \brief Set SDP Options tos_audio diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index e2f13eb6135..a186d7eefec 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -23,6 +23,7 @@ #include "asterisk/sdp_options.h" struct ast_sdp_state; +struct ast_sockaddr; /*! * \brief Allocate a new SDP state @@ -50,6 +51,26 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state); struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(const struct ast_sdp_state *sdp_state, int stream_index); +/*! + * \brief Get the global connection address on the SDP state. + */ +const struct ast_sockaddr *ast_sdp_state_get_connection_address(const struct ast_sdp_state *sdp_state); + +/*! + * \brief Get the connection address for a particular stream. + * + * \param sdp_state + * \param stream_index The particular stream to get the connection address of + * \param address[out] A place to store the address in + * + * \retval 0 Success + * + * \note + * Stream numbers correspond to the streams in the topology of the associated channel + */ +int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_state, + int stream_index, struct ast_sockaddr *address); + /*! * \brief Get the joint negotiated streams based on local and remote capabilities. * @@ -149,4 +170,69 @@ int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void */ int ast_sdp_state_reset(struct ast_sdp_state *sdp_state); +/*! + * \brief Update the local stream topology on the SDP state. + * + * \param sdp_state + * \param streams The new stream topology. + * + * \retval 0 Success + * + * \since 15 + */ +int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams); + +/*! + * \brief Set the local address (IP address) to use for connection addresses + * + * \param sdp_state + * \param address The local address + * + * \note + * Passing NULL as an address will unset the explicit local connection address. + * + * \since 15 + */ +void ast_sdp_state_set_local_address(struct ast_sdp_state *sdp_state, struct ast_sockaddr *address); + +/*! + * \brief Set the connection address (IP address and port) to use for a specific stream + * + * \param sdp_state + * \param stream_index The stream to set the connection address for + * \param address The connection address + * + * \retval 0 Success + * + * \note + * Passing NULL as an address will unset the explicit local connection address. + * + * \since 15 + */ +int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int stream_index, + struct ast_sockaddr *address); + +/*! + * \since 15.0.0 + * \brief Set a stream to be held or unheld + * + * \param sdp_state + * \param stream_index The stream to set the held value for + * \param locally_held + */ +void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state, + int stream_index, unsigned int locally_held); + +/*! + * \since 15.0.0 + * \brief Get whether a stream is held or not + * + * \param sdp_state + * \param stream_index The stream to get the held state for + * + * \returns locally_held + */ +unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_state, + int stream_index); + #endif /* _ASTERISK_SDP_STATE_H */ diff --git a/main/sdp.c b/main/sdp.c index 246763edf49..1ef6400b919 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -500,69 +500,10 @@ int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_opt return 0; } -/* TODO - * This isn't set anywhere yet. - */ -/*! \brief Scheduler for RTCP purposes */ -static struct ast_sched_context *sched; - -/*! \brief Internal function which creates an RTP instance */ -static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, - enum ast_media_type media_type) -{ - struct ast_rtp_instance *rtp; - struct ast_rtp_engine_ice *ice; - struct ast_sockaddr temp_media_address; - static struct ast_sockaddr address_rtp; - struct ast_sockaddr *media_address = &address_rtp; - - if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { - ast_sockaddr_parse(&temp_media_address, options->media_address, 0); - media_address = &temp_media_address; - } else { - if (ast_check_ipv6()) { - ast_sockaddr_parse(&address_rtp, "::", 0); - } else { - ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); - } - } - - if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { - ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", - options->rtp_engine); - return NULL; - } - - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); - - if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { - ice->stop(rtp); - } - - if (options->telephone_event) { - ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); - } - - if (media_type == AST_MEDIA_TYPE_AUDIO && - (options->tos_audio || options->cos_audio)) { - ast_rtp_instance_set_qos(rtp, options->tos_audio, - options->cos_audio, "SIP RTP Audio"); - } else if (media_type == AST_MEDIA_TYPE_VIDEO && - (options->tos_video || options->cos_video)) { - ast_rtp_instance_set_qos(rtp, options->tos_video, - options->cos_video, "SIP RTP Video"); - } - - ast_rtp_instance_set_last_rx(rtp, time(NULL)); - - return rtp; -} - -int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options *options, - struct ast_rtp_instance *rtp, const struct ast_stream *stream) +int ast_sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, + const struct ast_sdp_options *options, int stream_index) { + struct ast_stream *stream = ast_stream_topology_get_stream(ast_sdp_state_get_local_topology(sdp_state), stream_index); struct ast_sdp_m_line *m_line; struct ast_format_cap *caps; int i; @@ -572,13 +513,15 @@ int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options enum ast_media_type media_type; char tmp[64]; struct ast_sockaddr address_rtp; + struct ast_rtp_instance *rtp = ast_sdp_state_get_rtp_instance(sdp_state, stream_index); struct ast_sdp_a_line *a_line; - - ast_assert(sdp && options && rtp && stream); + ast_assert(sdp && options && stream); media_type = ast_stream_get_type(stream); - ast_rtp_instance_get_local_address(rtp, &address_rtp); + if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_rtp)) { + return -1; + } m_line = ast_sdp_m_alloc( ast_codec_media_type2str(ast_stream_get_type(stream)), @@ -673,7 +616,7 @@ int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options } } - a_line = ast_sdp_a_alloc(options->locally_held ? "sendonly" : "sendrecv", ""); + a_line = ast_sdp_a_alloc(ast_sdp_state_get_locally_held(sdp_state, stream_index) ? "sendonly" : "sendrecv", ""); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); @@ -699,7 +642,6 @@ struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state) struct ast_sdp_c_line *c_line = NULL; struct ast_sdp_s_line *s_line = NULL; struct ast_sdp_t_line *t_line = NULL; - struct ast_rtp_instance *rtp = NULL; char *address_type; struct timeval tv = ast_tvnow(); uint32_t t; @@ -732,25 +674,18 @@ struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state) } for (stream_num = 0; stream_num < stream_count; stream_num++) { - struct ast_stream *stream = ast_stream_topology_get_stream(topology, stream_num); - - rtp = create_rtp(options, ast_stream_get_type(stream)); - if (!rtp) { - goto error; - } - - ast_stream_set_data(stream, AST_STREAM_DATA_RTP_INSTANCE, - rtp, (ast_stream_data_free_fn)&ast_rtp_instance_destroy); + enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num)); - if (ast_sdp_add_m_from_stream(sdp, options, rtp, stream)) { - goto error; + if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + if (ast_sdp_add_m_from_rtp_stream(sdp, sdp_state, options, stream_num)) { + goto error; + } } } return sdp; error: - ao2_cleanup(rtp); if (sdp) { ast_sdp_free(sdp); } else { diff --git a/main/sdp_options.c b/main/sdp_options.c index ca076ac7b7d..60848172218 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -64,7 +64,6 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); DEFINE_GETTERS_SETTERS_FOR(unsigned int, telephone_event); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_ipv6); DEFINE_GETTERS_SETTERS_FOR(unsigned int, g726_non_standard); -DEFINE_GETTERS_SETTERS_FOR(unsigned int, locally_held); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_video); diff --git a/main/sdp_state.c b/main/sdp_state.c index 1b09ce16f15..5858a65ab06 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -22,10 +22,14 @@ #include "asterisk/sdp_translator.h" #include "asterisk/vector.h" #include "asterisk/utils.h" +#include "asterisk/netsock2.h" +#include "asterisk/rtp_engine.h" #include "../include/asterisk/sdp.h" #include "asterisk/stream.h" +#include "sdp_private.h" + enum ast_sdp_state_machine { /*! \brief The initial state. * @@ -61,13 +65,33 @@ enum ast_sdp_state_machine { typedef int (*state_fn)(struct ast_sdp_state *state); +struct sdp_state_stream { + union { + /*! The underlying RTP instance */ + struct ast_rtp_instance *instance; + }; + /*! An explicit connection address for this stream */ + struct ast_sockaddr connection_address; + /*! Whether this stream is held or not */ + unsigned int locally_held; +}; + +struct sdp_state_capabilities { + /*! Stream topology */ + struct ast_stream_topology *topology; + /*! Additional information about the streams */ + AST_VECTOR(, struct sdp_state_stream) streams; + /*! An explicit global connection address */ + struct ast_sockaddr connection_address; +}; + struct ast_sdp_state { /*! Local capabilities, learned through configuration */ - struct ast_stream_topology *local_capabilities; + struct sdp_state_capabilities local_capabilities; /*! Remote capabilities, learned through remote SDP */ struct ast_stream_topology *remote_capabilities; /*! Joint capabilities. The combined local and remote capabilities. */ - struct ast_stream_topology *joint_capabilities; + struct sdp_state_capabilities joint_capabilities; /*! Local SDP. Generated via the options and local capabilities. */ struct ast_sdp *local_sdp; /*! Remote SDP. Received directly from a peer. */ @@ -100,25 +124,42 @@ struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, return NULL; } - sdp_state->local_capabilities = ast_stream_topology_clone(streams); - if (!sdp_state->local_capabilities) { + if (ast_sdp_state_update_local_topology(sdp_state, streams)) { ast_sdp_state_free(sdp_state); return NULL; } + sdp_state->state = SDP_STATE_INITIAL; return sdp_state; } +static void sdp_state_capabilities_free(struct sdp_state_capabilities *sdp_capabilities) +{ + int stream_index; + + for (stream_index = 0; stream_index < AST_VECTOR_SIZE(&sdp_capabilities->streams); stream_index++) { + struct sdp_state_stream *stream_state = AST_VECTOR_GET_ADDR(&sdp_capabilities->streams, stream_index); + enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_capabilities->topology, stream_index)); + + if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + ast_rtp_instance_destroy(stream_state->instance); + } + } + + ast_stream_topology_free(sdp_capabilities->topology); + AST_VECTOR_FREE(&sdp_capabilities->streams); +} + void ast_sdp_state_free(struct ast_sdp_state *sdp_state) { if (!sdp_state) { return; } - ast_stream_topology_free(sdp_state->local_capabilities); + sdp_state_capabilities_free(&sdp_state->local_capabilities); ast_stream_topology_free(sdp_state->remote_capabilities); - ast_stream_topology_free(sdp_state->joint_capabilities); + sdp_state_capabilities_free(&sdp_state->joint_capabilities); ast_sdp_free(sdp_state->local_sdp); ast_sdp_free(sdp_state->remote_sdp); ast_sdp_free(sdp_state->joint_sdp); @@ -126,19 +167,75 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state) ast_sdp_translator_free(sdp_state->translator); } +static struct sdp_state_stream *sdp_state_get_stream(const struct ast_sdp_state *sdp_state, int stream_index) +{ + if (stream_index >= AST_VECTOR_SIZE(&sdp_state->local_capabilities.streams)) { + return NULL; + } + + return AST_VECTOR_GET_ADDR(&sdp_state->local_capabilities.streams, stream_index); +} + struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( const struct ast_sdp_state *sdp_state, int stream_index) { - struct ast_stream *stream; + struct sdp_state_stream *stream_state; ast_assert(sdp_state != NULL); - stream = ast_stream_topology_get_stream(sdp_state->local_capabilities, stream_index); - if (!stream) { + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { return NULL; } - return (struct ast_rtp_instance *)ast_stream_get_data(stream, AST_STREAM_DATA_RTP_INSTANCE); + return stream_state->instance; +} + +const struct ast_sockaddr *ast_sdp_state_get_connection_address(const struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state != NULL); + + return &sdp_state->local_capabilities.connection_address; +} + +int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_state, + int stream_index, struct ast_sockaddr *address) +{ + struct sdp_state_stream *stream_state; + enum ast_media_type type; + + ast_assert(sdp_state != NULL); + ast_assert(address != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return -1; + } + + /* If an explicit connection address has been provided for the stream return it */ + if (!ast_sockaddr_isnull(&stream_state->connection_address)) { + ast_sockaddr_copy(address, &stream_state->connection_address); + return 0; + } + + type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->local_capabilities.topology, + stream_index)); + + if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + ast_rtp_instance_get_local_address(stream_state->instance, address); + } else { + return -1; + } + + /* If an explicit global connection address is set use it here for the IP part */ + if (!ast_sockaddr_isnull(&sdp_state->local_capabilities.connection_address)) { + int port = ast_sockaddr_port(address); + + ast_sockaddr_copy(address, &sdp_state->local_capabilities.connection_address); + ast_sockaddr_set_port(address, port); + } + + return 0; } const struct ast_stream_topology *ast_sdp_state_get_joint_topology( @@ -146,9 +243,9 @@ const struct ast_stream_topology *ast_sdp_state_get_joint_topology( { ast_assert(sdp_state != NULL); if (sdp_state->state == SDP_STATE_NEGOTIATED) { - return sdp_state->joint_capabilities; + return sdp_state->joint_capabilities.topology; } else { - return sdp_state->local_capabilities; + return sdp_state->local_capabilities.topology; } } @@ -157,7 +254,7 @@ const struct ast_stream_topology *ast_sdp_state_get_local_topology( { ast_assert(sdp_state != NULL); - return sdp_state->local_capabilities; + return sdp_state->local_capabilities.topology; } const struct ast_sdp_options *ast_sdp_state_get_options( @@ -193,11 +290,109 @@ static int merge_sdps(struct ast_sdp_state *sdp_state) } #endif +/* TODO + * This isn't set anywhere yet. + */ +/*! \brief Scheduler for RTCP purposes */ +static struct ast_sched_context *sched; + +/*! \brief Internal function which creates an RTP instance */ +static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, + enum ast_media_type media_type) +{ + struct ast_rtp_instance *rtp; + struct ast_rtp_engine_ice *ice; + struct ast_sockaddr temp_media_address; + static struct ast_sockaddr address_rtp; + struct ast_sockaddr *media_address = &address_rtp; + + if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { + ast_sockaddr_parse(&temp_media_address, options->media_address, 0); + media_address = &temp_media_address; + } else { + if (ast_check_ipv6()) { + ast_sockaddr_parse(&address_rtp, "::", 0); + } else { + ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); + } + } + + if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { + ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", + options->rtp_engine); + return NULL; + } + + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); + + if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { + ice->stop(rtp); + } + + if (options->telephone_event) { + ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); + } + + if (media_type == AST_MEDIA_TYPE_AUDIO && + (options->tos_audio || options->cos_audio)) { + ast_rtp_instance_set_qos(rtp, options->tos_audio, + options->cos_audio, "SIP RTP Audio"); + } else if (media_type == AST_MEDIA_TYPE_VIDEO && + (options->tos_video || options->cos_video)) { + ast_rtp_instance_set_qos(rtp, options->tos_video, + options->cos_video, "SIP RTP Video"); + } + + ast_rtp_instance_set_last_rx(rtp, time(NULL)); + + return rtp; +} + +static int sdp_state_setup_local_streams(struct ast_sdp_state *sdp_state) +{ + int stream_index; + + for (stream_index = 0; stream_index < AST_VECTOR_SIZE(&sdp_state->local_capabilities.streams); stream_index++) { + struct sdp_state_stream *stream_state_local = AST_VECTOR_GET_ADDR(&sdp_state->local_capabilities.streams, stream_index); + struct sdp_state_stream *stream_state_joint = NULL; + enum ast_media_type type_local = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->local_capabilities.topology, stream_index)); + enum ast_media_type type_joint = AST_MEDIA_TYPE_UNKNOWN; + + if (stream_index < AST_VECTOR_SIZE(&sdp_state->joint_capabilities.streams)) { + stream_state_joint = AST_VECTOR_GET_ADDR(&sdp_state->joint_capabilities.streams, stream_index); + type_joint = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->joint_capabilities.topology, stream_index)); + } + + /* If we can reuse an existing media stream then do so */ + if (type_local == type_joint) { + if (type_local == AST_MEDIA_TYPE_AUDIO || type_local == AST_MEDIA_TYPE_VIDEO) { + stream_state_local->instance = ao2_bump(stream_state_joint->instance); + continue; + } + } + + if (type_local == AST_MEDIA_TYPE_AUDIO || type_local == AST_MEDIA_TYPE_VIDEO) { + /* We need to create a new RTP instance */ + stream_state_local->instance = create_rtp(sdp_state->options, type_local); + if (!stream_state_local->instance) { + return -1; + } + } + } + + return 0; +} + const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_state) { ast_assert(sdp_state != NULL); if (!sdp_state->local_sdp) { + if (sdp_state_setup_local_streams(sdp_state)) { + return NULL; + } sdp_state->local_sdp = ast_sdp_create_from_state(sdp_state); } @@ -254,10 +449,87 @@ int ast_sdp_state_reset(struct ast_sdp_state *sdp_state) ast_stream_topology_free(sdp_state->remote_capabilities); sdp_state->remote_capabilities = NULL; - ast_stream_topology_free(sdp_state->joint_capabilities); - sdp_state->joint_capabilities = NULL; + ast_stream_topology_free(sdp_state->joint_capabilities.topology); + sdp_state->joint_capabilities.topology = NULL; sdp_state->state = SDP_STATE_INITIAL; return 0; } + +int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams) +{ + ast_assert(sdp_state != NULL); + ast_assert(streams != NULL); + + sdp_state_capabilities_free(&sdp_state->local_capabilities); + sdp_state->local_capabilities.topology = ast_stream_topology_clone(streams); + if (!sdp_state->local_capabilities.topology) { + return -1; + } + + if (AST_VECTOR_INIT(&sdp_state->local_capabilities.streams, ast_stream_topology_get_count(streams))) { + return -1; + } + + return 0; +} + +void ast_sdp_state_set_local_address(struct ast_sdp_state *sdp_state, struct ast_sockaddr *address) +{ + ast_assert(sdp_state != NULL); + + if (!address) { + ast_sockaddr_setnull(&sdp_state->local_capabilities.connection_address); + } else { + ast_sockaddr_copy(&sdp_state->local_capabilities.connection_address, address); + } +} + +int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int stream_index, + struct ast_sockaddr *address) +{ + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return -1; + } + + if (!address) { + ast_sockaddr_setnull(&stream_state->connection_address); + } else { + ast_sockaddr_copy(&stream_state->connection_address, address); + } + + return 0; +} + +void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state, + int stream_index, unsigned int locally_held) +{ + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return; + } + + stream_state->locally_held = locally_held; +} + +unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_state, + int stream_index) +{ + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return 0; + } + + return stream_state->locally_held; +} From a7d94f504fc3be80b741bc5cd50faa81aa7e6e8d Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Tue, 28 Mar 2017 20:01:16 +0200 Subject: [PATCH 1171/1578] build: Fix deb build issues with fakeroot If DESTDIR is set, don't call ldconfig. Assume that DESTDIR is used to create a binary archive. The ldconfig call should be delegated to the archive postinst script. This fixes the case where fakeroot wraps 'make install' causing $EUID to be 0 even though it doesn't have permission to call ldconfig. The previous logic in configure.ac to detect and correct libdir has been removed as it was not completely accurate. CentOS 64-bit users should again specifiy --libdir=/usr/lib64 when configuring to prevent install to /usr/lib. Updated Makefile:check-old-libdir to check for orphans in lib64 when installing to lib as well as orphans in lib when installing to lib64. Updated Makefile and main/Makefile uninstall targets to remove the orphans using the new logic. ASTERISK-26705 Change-Id: I51739d4a03e60bff38be719b8d2ead0007afdd51 --- Makefile | 52 ++++++++++++++++++++++++++++++++++++++------------- configure | 22 ---------------------- configure.ac | 21 --------------------- main/Makefile | 2 +- 4 files changed, 40 insertions(+), 57 deletions(-) diff --git a/Makefile b/Makefile index 95a3d3da53a..f29c07f6809 100644 --- a/Makefile +++ b/Makefile @@ -606,26 +606,56 @@ oldmodcheck: ld-cache-update: ifneq ($(LDCONFIG),) +ifeq ($(DESTDIR),) # DESTDIR means binary archive creation; ldconfig should be run on postinst @if [ $${EUID} -eq 0 ] ; then \ - $(LDCONFIG) "$(DESTDIR)$(ASTLIBDIR)/" ; \ + $(LDCONFIG) "$(ASTLIBDIR)/" ; \ else \ echo " WARNING WARNING WARNING" ;\ echo "" ;\ echo " You cannot rebuild the system linker cache unless you are root. " ;\ - echo " You MUST do one of the follwing..." ;\ + echo " You MUST do one of the following..." ;\ echo " * Re-run 'make install' as root. " ;\ - echo " * Run 'ldconfig $(DESTDIR)$(ASTLIBDIR)' as root. " ;\ - echo " * Run asterisk with 'LD_LIBRARY_PATH=$(DESTDIR)$(ASTLIBDIR) asterisk' " ;\ + echo " * Run 'ldconfig $(ASTLIBDIR)' as root. " ;\ + echo " * Run asterisk with 'LD_LIBRARY_PATH=$(ASTLIBDIR) asterisk' " ;\ echo "" ;\ echo " WARNING WARNING WARNING" ;\ fi endif +endif -ifeq ($(and $(findstring 64,$(HOST_CPU)),$(findstring lib64,$(DESTDIR)$(ASTLIBDIR))),lib64) -_oldlibdir = $(subst lib64,lib,$(DESTDIR)$(ASTLIBDIR)) +export _oldlibdir = +export _oldmoddir = +ifeq ($(findstring 64,$(HOST_CPU)),64) + # Strip any trailing '/' so the dir and notdir functions work correctly + _current_libdir = $(patsubst %/,%,$(DESTDIR)$(ASTLIBDIR)) + + # Only process if the paths end in lib64 or lib. + # If we're installing to lib64, check lib for orphans. + # If we're installing to lib, check lib64 for orphans. + # Otherwise, leave _oldlibdir empty. + ifeq ($(notdir $(_current_libdir)),lib64) + _oldlibdir = $(dir $(_current_libdir))lib + else ifeq ($(notdir $(_current_libdir)),lib) + _oldlibdir = $(dir $(_current_libdir))lib64 + endif + + # Strip any trailing '/' so the dir and notdir functions work correctly + _current_moddir = $(patsubst %/,%,$(DESTDIR)$(ASTMODDIR)) + + # Only process if the paths contain /lib64/ or /lib/. + # If we're installing to lib64, check lib for orphans. + # If we're installing to lib, check lib64 for orphans. + # Otherwise, leave _oldmoddir empty. + ifeq ($(findstring /lib64/,$(_current_moddir)),/lib64/) + _oldmoddir = $(subst /lib64/,/lib/,$(_current_moddir)) + else ifeq ($(findstring /lib/,$(_current_moddir)),/lib/) + _oldmoddir = $(subst /lib/,/lib64/,$(_current_moddir)) + endif +endif check-old-libdir: - @oldfiles=`find "$(_oldlibdir)" -name libasterisk* -print -quit -o \( -path *asterisk/modules/* -a -name *.so \) -print -quit` ;\ + @test -n "$(_oldlibdir)" -a -d "$(_oldlibdir)" || exit 0 ;\ + oldfiles=`find "$(_oldlibdir)" -name libasterisk* -print -quit -o \( -path *asterisk/modules/* -a -name *.so \) -print -quit 2>/dev/null` ;\ if [ "x$$oldfiles" != "x" ] ; then \ echo " WARNING WARNING WARNING" ;\ echo "" ;\ @@ -647,10 +677,6 @@ check-old-libdir: echo "" ;\ echo " WARNING WARNING WARNING" ;\ fi -else -check-old-libdir: - -endif badshell: ifneq ($(filter ~%,$(DESTDIR)),) @@ -912,7 +938,7 @@ main-binuninstall: _uninstall: $(SUBDIRS_UNINSTALL) main-binuninstall rm -f "$(DESTDIR)$(ASTMODDIR)/"* - rm -f "$(subst lib64,lib,$(DESTDIR)$(ASTMODDIR))/"* + test -n "$(_oldmoddir)" -a -d "$(_oldmoddir)" && rm -f "$(_oldmoddir)/"* || : rm -f "$(DESTDIR)$(ASTSBINDIR)/astgenkey" rm -f "$(DESTDIR)$(ASTSBINDIR)/autosupport" rm -rf "$(DESTDIR)$(ASTHEADERDIR)" @@ -945,7 +971,7 @@ uninstall: _uninstall uninstall-all: _uninstall rm -rf "$(DESTDIR)$(ASTMODDIR)" - rm -rf "$(subst lib64,lib,$(DESTDIR)$(ASTMODDIR))" + test -n "$(_oldmoddir)" -a -d "$(_oldmoddir)" && rm -rf "$(_oldmoddir)" || : rm -rf "$(DESTDIR)$(ASTVARLIBDIR)" rm -rf "$(DESTDIR)$(ASTDATADIR)" rm -rf "$(DESTDIR)$(ASTSPOOLDIR)" diff --git a/configure b/configure index 15f127b12a3..b27c94e7a9c 100755 --- a/configure +++ b/configure @@ -4890,28 +4890,6 @@ if test ${prefix} = ${ac_default_prefix} || test ${prefix} = 'NONE'; then fi fi -# -# The following code for detecting lib64 was taken from Fedora's -# /usr/share/config.site with a modification to check that the -# /usr/lib64 directory actually exists. This prevents libdir from -# being set to /usr/lib64 on 64-bit systems that still use /usr/lib. -# -if test "$prefix" = /usr ||\ - { test "$prefix" = NONE && test "$ac_default_prefix" = /usr ; } -then - for i in x86_64 ppc64 s390x aarch64; do - if test $host_cpu = $i; then - if test "$libdir" = '${exec_prefix}/lib' &&\ - { test -d "${exec_prefix}/lib64" || test -d "${ac_default_prefix}/lib64" ; } ; then - libdir='${exec_prefix}/lib64' - { $as_echo "$as_me:${as_lineno-$LINENO}: Setting libdir=${libdir} " >&5 -$as_echo "$as_me: Setting libdir=${libdir} " >&6;} - fi - break - fi - done -fi - BUILD_PLATFORM=${build} BUILD_CPU=${build_cpu} BUILD_VENDOR=${build_vendor} diff --git a/configure.ac b/configure.ac index a57446f9242..b0f04887a09 100644 --- a/configure.ac +++ b/configure.ac @@ -135,27 +135,6 @@ if test ${prefix} = ${ac_default_prefix} || test ${prefix} = 'NONE'; then fi fi -# -# The following code for detecting lib64 was taken from Fedora's -# /usr/share/config.site with a modification to check that the -# /usr/lib64 directory actually exists. This prevents libdir from -# being set to /usr/lib64 on 64-bit systems that still use /usr/lib. -# -if test "$prefix" = /usr ||\ - { test "$prefix" = NONE && test "$ac_default_prefix" = /usr ; } -then - for i in x86_64 ppc64 s390x aarch64; do - if test $host_cpu = $i; then - if test "$libdir" = '${exec_prefix}/lib' &&\ - { test -d "${exec_prefix}/lib64" || test -d "${ac_default_prefix}/lib64" ; } ; then - libdir='${exec_prefix}/lib64' - AC_MSG_NOTICE([ Setting libdir=${libdir} ]) - fi - break - fi - done -fi - BUILD_PLATFORM=${build} BUILD_CPU=${build_cpu} BUILD_VENDOR=${build_vendor} diff --git a/main/Makefile b/main/Makefile index cd553cb0dd2..4fb6a013101 100644 --- a/main/Makefile +++ b/main/Makefile @@ -351,7 +351,7 @@ binuninstall: rm -f "$(DESTDIR)$(ASTSBINDIR)/$(MAIN_TGT)" rm -f "$(DESTDIR)$(ASTSBINDIR)/rasterisk" rm -f "$(DESTDIR)$(ASTLIBDIR)/libasterisk"* || : - rm -f "$(subst lib64,lib,$(DESTDIR)$(ASTLIBDIR))/libasterisk"* || : + test -n "$(_oldlibdir)" -a -d "$(_oldlibdir)" && rm -f "$(_oldlibdir)/libasterisk"* || : clean:: rm -f asterisk libasteriskssl.o From c537f994883718d6f4fac3447dae185b88b327a0 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 30 Mar 2017 09:11:46 -0400 Subject: [PATCH 1172/1578] cdr_pgsql: Fix buffer overflow calling libpq Implement the same buffer size checking done in cel_pgsql. ASTERISK-26896 #close Reported by: twisted Change-Id: Iaacfa1f1de7cb1e9414d121850d2d8c2888f3f48 --- cdr/cdr_pgsql.c | 56 ++++++++++++++++++++++++++++++------------------- cel/cel_pgsql.c | 3 +-- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c index cbd9e0558b2..33cc1b8aea2 100644 --- a/cdr/cdr_pgsql.c +++ b/cdr/cdr_pgsql.c @@ -202,6 +202,7 @@ static int pgsql_log(struct ast_cdr *cdr) struct ast_tm tm; char *pgerror; PGresult *result; + int res = -1; ast_mutex_lock(&pgsql_lock); @@ -231,13 +232,14 @@ static int pgsql_log(struct ast_cdr *cdr) if (connected) { struct columns *cur; struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2); - char buf[257], escapebuf[513], *value; + char buf[257]; + char *escapebuf = NULL, *value; char *separator = ""; + size_t bufsize = 513; - if (!sql || !sql2) { - ast_free(sql); - ast_free(sql2); - return -1; + escapebuf = ast_malloc(bufsize); + if (!escapebuf || !sql || !sql2) { + goto ast_log_cleanup; } ast_str_set(&sql, 0, "INSERT INTO %s (", table); @@ -358,10 +360,28 @@ static int pgsql_log(struct ast_cdr *cdr) } /* XXX Might want to handle dates, times, and other misc fields here XXX */ } else { - if (value) + if (value) { + size_t required_size = strlen(value) * 2 + 1; + + /* If our argument size exceeds our buffer, grow it, + * as PQescapeStringConn() expects the buffer to be + * adequitely sized and does *NOT* do size checking. + */ + if (required_size > bufsize) { + char *tmpbuf = ast_realloc(escapebuf, required_size); + + if (!tmpbuf) { + AST_RWLIST_UNLOCK(&psql_columns); + goto ast_log_cleanup; + } + + escapebuf = tmpbuf; + bufsize = required_size; + } PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL); - else + } else { escapebuf[0] = '\0'; + } LENGTHEN_BUF2(strlen(escapebuf) + 3); ast_str_append(&sql2, 0, "%s'%s'", separator, escapebuf); } @@ -395,10 +415,7 @@ static int pgsql_log(struct ast_cdr *cdr) PQfinish(conn); conn = NULL; connected = 0; - ast_mutex_unlock(&pgsql_lock); - ast_free(sql); - ast_free(sql2); - return -1; + goto ast_log_cleanup; } } result = PQexec(conn, ast_str_buffer(sql)); @@ -419,23 +436,17 @@ static int pgsql_log(struct ast_cdr *cdr) pgerror = PQresultErrorMessage(result); ast_log(LOG_ERROR, "HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); ast_log(LOG_ERROR, "Reason: %s\n", pgerror); - } else { + } else { /* Second try worked out ok */ totalrecords++; records++; - ast_mutex_unlock(&pgsql_lock); - PQclear(result); - return 0; + res = 0; } } - ast_mutex_unlock(&pgsql_lock); - PQclear(result); - ast_free(sql); - ast_free(sql2); - return -1; } else { totalrecords++; records++; + res = 0; } PQclear(result); @@ -447,11 +458,14 @@ static int pgsql_log(struct ast_cdr *cdr) maxsize2 = ast_str_strlen(sql2); } +ast_log_cleanup: + ast_free(escapebuf); ast_free(sql); ast_free(sql2); } + ast_mutex_unlock(&pgsql_lock); - return 0; + return res; } /* This function should be called without holding the pgsql_columns lock */ diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c index eba0726da34..5fe66784bb4 100644 --- a/cel/cel_pgsql.c +++ b/cel/cel_pgsql.c @@ -320,6 +320,7 @@ static void pgsql_log(struct ast_event *event) char *tmpbuf = ast_realloc(escapebuf, required_size); if (!tmpbuf) { + AST_RWLIST_UNLOCK(&psql_columns); goto ast_log_cleanup; } @@ -380,8 +381,6 @@ static void pgsql_log(struct ast_event *event) ast_log(LOG_ERROR, "Reason: %s\n", pgerror); } } - PQclear(result); - goto ast_log_cleanup; } PQclear(result); From f9695dc0578484a58cca7bec71810cf7440983d8 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 30 Mar 2017 19:28:18 -0400 Subject: [PATCH 1173/1578] Forward declare 'struct ast_json' in asterisk.h The ast_json structure is used in many Asterisk headers and is often the only part of json.h used. This adds a forward declaration to asterisk.h and removes the include of json.h from many headers. The declaration has been left in endpoints.h and stasis.h to avoid problems with source files that use ast_json functions without directly including json.h. ari.h continues to include json.h as it uses enum ast_json_encoding_format. Change-Id: Id766aabce6bed56626d27e8d29f559b5e687b769 --- include/asterisk.h | 1 + include/asterisk/channel.h | 1 - include/asterisk/stasis_app.h | 1 - include/asterisk/stasis_channels.h | 1 - include/asterisk/stasis_endpoints.h | 1 - include/asterisk/stasis_system.h | 1 - 6 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/asterisk.h b/include/asterisk.h index 862fa1fe5f5..dc530dfd41a 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -196,6 +196,7 @@ struct ast_module; struct ast_variable; struct ast_str; struct ast_sched_context; +struct ast_json; /* Some handy macros for turning a preprocessor token into (effectively) a quoted string */ #define __stringify_1(x) #x diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 391e58ccf97..32c9c7f67f2 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -178,7 +178,6 @@ extern "C" { #include "asterisk/ccss.h" #include "asterisk/framehook.h" #include "asterisk/stasis.h" -#include "asterisk/json.h" #include "asterisk/endpoints.h" #define DATASTORE_INHERIT_FOREVER INT_MAX diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index e131833a979..ca5c25111cb 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -51,7 +51,6 @@ */ #include "asterisk/channel.h" -#include "asterisk/json.h" /*! @{ */ diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h index deb79b0d061..4843617db0c 100644 --- a/include/asterisk/stasis_channels.h +++ b/include/asterisk/stasis_channels.h @@ -22,7 +22,6 @@ #include "asterisk/stringfields.h" #include "asterisk/stasis.h" -#include "asterisk/json.h" #include "asterisk/channel.h" /*! \addtogroup StasisTopicsAndMessages diff --git a/include/asterisk/stasis_endpoints.h b/include/asterisk/stasis_endpoints.h index 539f270cf27..2fbe5f4b70c 100644 --- a/include/asterisk/stasis_endpoints.h +++ b/include/asterisk/stasis_endpoints.h @@ -28,7 +28,6 @@ */ #include "asterisk/endpoints.h" -#include "asterisk/json.h" #include "asterisk/stasis.h" #include "asterisk/stasis_cache_pattern.h" #include "asterisk/stringfields.h" diff --git a/include/asterisk/stasis_system.h b/include/asterisk/stasis_system.h index 274c02e49c8..55959063c7c 100644 --- a/include/asterisk/stasis_system.h +++ b/include/asterisk/stasis_system.h @@ -19,7 +19,6 @@ #ifndef _ASTERISK_STASIS_SYSTEM_H #define _ASTERISK_STASIS_SYSTEM_H -#include "asterisk/json.h" #include "asterisk/stasis.h" /*! From e8b1bb3041572795667d9b0e01d0c9a3f1e7c36a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 31 Mar 2017 13:14:05 -0500 Subject: [PATCH 1174/1578] chan_vpb.cc: Fix compiler error. Added missing channel technology read/write stream callback initialization. Change-Id: I829043a327d987e0d964485dd3d27964bebbd623 --- channels/chan_vpb.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index 595ac8fee2c..87342b1d020 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -373,7 +373,9 @@ static struct ast_channel_tech vpb_tech = { hangup: vpb_hangup, answer: vpb_answer, read: vpb_read, + read_stream: NULL, write: vpb_write, + write_stream: NULL, send_text: NULL, send_image: NULL, send_html: NULL, @@ -404,7 +406,9 @@ static struct ast_channel_tech vpb_tech_indicate = { hangup: vpb_hangup, answer: vpb_answer, read: vpb_read, + read_stream: NULL, write: vpb_write, + write_stream: NULL, send_text: NULL, send_image: NULL, send_html: NULL, From 48be02c5d85680eb13de0595b5bf55d454d7dcca Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 31 Mar 2017 21:31:24 +0000 Subject: [PATCH 1175/1578] res_pjsip_session: Allow BYE to be sent on disconnected session. It is perfectly acceptable for a BYE to be sent on a disconnected session. This occurs when we respond to a challenge to the BYE for authentication credentials. ASTERISK-26363 Change-Id: I6ef0ddece812fea6665a1dd2549ef44fb9d90045 --- res/res_pjsip_session.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 5f42dab9f9c..560b3903dd2 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1198,8 +1198,13 @@ void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip { pjsip_inv_session *inv_session = session->inv_session; - if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) { - /* Don't try to do anything with a hung-up call */ + /* For every request except BYE we disallow sending of the message when + * the session has been disconnected. A BYE request is special though + * because it can be sent again after the session is disconnected except + * with credentials. + */ + if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED && + tdata->msg->line.req.method.id != PJSIP_BYE_METHOD) { return; } From 4fc22c76733fe13bea14605fba6f81dc255d540d Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 3 Apr 2017 09:30:43 +0200 Subject: [PATCH 1176/1578] chan_sip: Session Timers required but refused wrongly. SIP user-agents indicate which protocol extensions are allowed in headers like Supported and Required. Such protocol extensions are Session Timers (RFC 4028) for example. Session Timers are supported since Mantis-10665. Since ASTERISK-21721, not only the first but multiple Supported/Required headers in a message are parsed. In that change, an existing variable was re-used within a newly added do-loop. Currently, at the end of that loop, that variable is an empty string always. Previously, that variable was used within log output. However, the log output was not changed. ASTERISK-26915 #close Change-Id: I09315f31b4d78fb214bb2a9fb6c0f5e143eae990 --- channels/chan_sip.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f659a44a3c6..5419a1dd8b4 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -25818,8 +25818,7 @@ static int handle_request_update(struct sip_pvt *p, struct sip_request *req) * \retval 0 ok * \retval -1 failure */ -static int handle_request_invite_st(struct sip_pvt *p, struct sip_request *req, - const char *required, int reinvite) +static int handle_request_invite_st(struct sip_pvt *p, struct sip_request *req, int reinvite) { const char *p_uac_se_hdr; /* UAC's Session-Expires header string */ const char *p_uac_min_se; /* UAC's requested Min-SE interval (char string) */ @@ -25899,8 +25898,8 @@ static int handle_request_invite_st(struct sip_pvt *p, struct sip_request *req, case SESSION_TIMER_MODE_REFUSE: if (p->reqsipoptions & SIP_OPT_TIMER) { - transmit_response_with_unsupported(p, "420 Option Disabled", req, required); - ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: %s\n", required); + transmit_response_with_unsupported(p, "420 Option Disabled", req, "timer"); + ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: timer\n"); return -1; } break; @@ -26006,7 +26005,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str * then send a 420 with only those unsupported options listed */ if (!ast_strlen_zero(unsupported)) { transmit_response_with_unsupported(p, "420 Bad extension (unsupported)", req, unsupported); - ast_log(LOG_WARNING, "Received SIP INVITE with unsupported required extension: required:%s unsupported:%s\n", required, unsupported); + ast_log(LOG_WARNING, "Received SIP INVITE with unsupported required extension: %s\n", unsupported); p->invitestate = INV_COMPLETED; if (!p->lastinvite) { sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); @@ -26444,7 +26443,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str make_our_tag(p); - if (handle_request_invite_st(p, req, required, reinvite)) { + if (handle_request_invite_st(p, req, reinvite)) { p->invitestate = INV_COMPLETED; sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); res = INV_REQ_ERROR; @@ -26486,7 +26485,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str if (!req->ignore) reinvite = 1; - if (handle_request_invite_st(p, req, required, reinvite)) { + if (handle_request_invite_st(p, req, reinvite)) { p->invitestate = INV_COMPLETED; if (!p->lastinvite) { sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); From a889621b14a55994fcfe68341af3cef2484ff74b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 3 Apr 2017 13:56:43 -0500 Subject: [PATCH 1177/1578] res_pjsip: Fix transport ref leak. We were leaking a transport ref in multihomed_on_rx_message() which resulted in the FRACK about excessive ref counts. ASTERISK-26916 #close Change-Id: I7a96658a9614a060565bb9ad51cb1c9c11ee145f --- res/res_pjsip/pjsip_message_ip_updater.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/res_pjsip/pjsip_message_ip_updater.c b/res/res_pjsip/pjsip_message_ip_updater.c index 864d898b3f9..2d074640ad3 100644 --- a/res/res_pjsip/pjsip_message_ip_updater.c +++ b/res/res_pjsip/pjsip_message_ip_updater.c @@ -339,8 +339,10 @@ static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata) transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_id); if (!(transport && transport->symmetric_transport)) { + ao2_cleanup(transport); return PJ_FALSE; } + ao2_cleanup(transport); x_transport = PJ_POOL_ALLOC_T(rdata->tp_info.pool, pjsip_param); x_transport->name = pj_strdup3(rdata->tp_info.pool, AST_SIP_X_AST_TXP); From 8e36064109b6fabc6cd8caa59e48f9b523c7485b Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 31 Mar 2017 13:09:38 -0400 Subject: [PATCH 1178/1578] core: Improve/simplify handling of required headers. * Report failures if configure finds a required header is missing. * Deduplicate includes between asterisk.h, astmm.h and compat.h. * Unconditionally include headers in compat.h if required elsewhere. Change-Id: Ie67d0185ca71fbfb81c9bdfaebe46a49e3c56dc5 --- configure | 41 ++++++++++++++++++++++++- configure.ac | 27 ++++++++++++++++- include/asterisk.h | 5 +--- include/asterisk/astmm.h | 15 +--------- include/asterisk/autoconfig.h.in | 51 ++++++++++++++++++++++++++++++-- include/asterisk/compat.h | 20 ------------- 6 files changed, 116 insertions(+), 43 deletions(-) diff --git a/configure b/configure index b27c94e7a9c..32433237037 100755 --- a/configure +++ b/configure @@ -13230,6 +13230,10 @@ fi fi +if test -z $ac_header_dirent -o "$ac_header_dirent" = "no"; then + as_fn_error $? "*** Could not find dirent header that defines 'DIR'." "$LINENO" 5 +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : @@ -13342,6 +13346,10 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi +if test "$ac_cv_header_stdc" != "yes"; then + as_fn_error $? "*** ANSI C header files not found." "$LINENO" 5 +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : @@ -13383,7 +13391,38 @@ $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi -for ac_header in arpa/inet.h fcntl.h inttypes.h libintl.h limits.h locale.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/event.h sys/file.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h termios.h unistd.h utime.h arpa/nameser.h sys/io.h +if test "$ac_cv_header_sys_wait_h" != "yes"; then + as_fn_error $? "*** POSIX.1 compatible sys/wait.h is required." "$LINENO" 5 +fi + +# Check for headers that are unconditionally required on all platforms. Do not use +# this to check for headers that are only needed by modules. +for ac_header in \ + arpa/nameser.h assert.h ctype.h dlfcn.h errno.h fcntl.h float.h grp.h \ + inttypes.h limits.h locale.h math.h pwd.h netinet/in.h regex.h resolv.h \ + sched.h stdarg.h stdint.h stdio.h stdlib.h string.h syslog.h \ + sys/file.h sys/ioctl.h sys/param.h sys/resource.h sys/socket.h sys/stat.h \ + sys/time.h sys/types.h sys/un.h \ + termios.h time.h unistd.h \ + +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + + as_fn_error $? "*** A required header was not found." "$LINENO" 5 + +fi + +done + + +for ac_header in arpa/inet.h libintl.h malloc.h netdb.h stddef.h strings.h sys/event.h utime.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/configure.ac b/configure.ac index b0f04887a09..a8e66bccd1e 100644 --- a/configure.ac +++ b/configure.ac @@ -588,9 +588,34 @@ AST_EXT_LIB_SETUP([ZLIB], [zlib compression], [z]) AC_FUNC_ALLOCA AC_HEADER_DIRENT +if test -z $ac_header_dirent -o "$ac_header_dirent" = "no"; then + AC_MSG_ERROR([*** Could not find dirent header that defines 'DIR'.]) +fi + AC_HEADER_STDC +if test "$ac_cv_header_stdc" != "yes"; then + AC_MSG_ERROR([*** ANSI C header files not found.]) +fi + AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h libintl.h limits.h locale.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/event.h sys/file.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h termios.h unistd.h utime.h arpa/nameser.h sys/io.h]) +if test "$ac_cv_header_sys_wait_h" != "yes"; then + AC_MSG_ERROR([*** POSIX.1 compatible sys/wait.h is required.]) +fi + +# Check for headers that are unconditionally required on all platforms. Do not use +# this to check for headers that are only needed by modules. +AC_CHECK_HEADERS([ \ + arpa/nameser.h assert.h ctype.h dlfcn.h errno.h fcntl.h float.h grp.h \ + inttypes.h limits.h locale.h math.h pwd.h netinet/in.h regex.h resolv.h \ + sched.h stdarg.h stdint.h stdio.h stdlib.h string.h syslog.h \ + sys/file.h sys/ioctl.h sys/param.h sys/resource.h sys/socket.h sys/stat.h \ + sys/time.h sys/types.h sys/un.h \ + termios.h time.h unistd.h \ +], [], [ + AC_MSG_ERROR([*** A required header was not found.]) +]) + +AC_CHECK_HEADERS([arpa/inet.h libintl.h malloc.h netdb.h stddef.h strings.h sys/event.h utime.h]) # Any one of these packages support a mandatory requirement, so we want to check on them as early as possible. AST_EXT_LIB_CHECK([TERMCAP], [termcap], [tgetent], []) diff --git a/include/asterisk.h b/include/asterisk.h index dc530dfd41a..899438b0eef 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -19,13 +19,12 @@ #define _ASTERISK_H #include "asterisk/autoconfig.h" +#include "asterisk/compat.h" #if !defined(NO_MALLOC_DEBUG) && !defined(STANDALONE) && !defined(STANDALONE2) && defined(MALLOC_DEBUG) #include "asterisk/astmm.h" #endif -#include "asterisk/compat.h" - /* Default to allowing the umask or filesystem ACLs to determine actual file * creation permissions */ @@ -54,8 +53,6 @@ #if defined(DEBUG_FD_LEAKS) && !defined(STANDALONE) && !defined(STANDALONE2) && !defined(STANDALONE_AEL) /* These includes are all about ordering */ -#include -#include #include #include #include diff --git a/include/asterisk/astmm.h b/include/asterisk/astmm.h index e129dc034a9..06300c861bf 100644 --- a/include/asterisk/astmm.h +++ b/include/asterisk/astmm.h @@ -30,21 +30,10 @@ extern "C" { #ifndef _ASTERISK_ASTMM_H #define _ASTERISK_ASTMM_H -/* IWYU pragma: private, include "asterisk/utils.h" */ - -#ifndef STANDALONE +/* IWYU pragma: private, include "asterisk.h" */ #define __AST_DEBUG_MALLOC -#include "asterisk.h" - -/* Include these now to prevent them from being needed later */ -#include -#include -#include -#include -#include - void *ast_std_malloc(size_t size); void *ast_std_calloc(size_t nmemb, size_t size); void *ast_std_realloc(void *ptr, size_t size); @@ -179,8 +168,6 @@ void __ast_mm_init_phase_2(void); #define ast_free(a) \ __ast_free(a,__FILE__, __LINE__, __PRETTY_FUNCTION__) -#endif /* !STANDALONE */ - #else #error "NEVER INCLUDE astmm.h DIRECTLY!!" #endif /* _ASTERISK_ASTMM_H */ diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index b9b4e1f8127..af1c90b4079 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -62,6 +62,9 @@ /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF +/* Define to 1 if you have the header file. */ +#undef HAVE_ASSERT_H + /* Define to 1 if you have the `atan' function. */ #undef HAVE_ATAN @@ -170,6 +173,9 @@ /* Define to 1 if you have the 'crypt_r' function. */ #undef HAVE_CRYPT_R +/* Define to 1 if you have the header file. */ +#undef HAVE_CTYPE_H + /* Define to 1 if you have a functional curl library. */ #undef HAVE_CURL @@ -198,6 +204,9 @@ /* Define to 1 if your system has the dladdr() GNU extension */ #undef HAVE_DLADDR +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT @@ -210,6 +219,9 @@ /* Define to 1 if you have the `endpwent' function. */ #undef HAVE_ENDPWENT +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + /* Define to 1 if you have the `euidaccess' function. */ #undef HAVE_EUIDACCESS @@ -243,6 +255,9 @@ /* Define to 1 if you have the LIBFFTW3 library. */ #undef HAVE_FFTW3 +/* Define to 1 if you have the header file. */ +#undef HAVE_FLOAT_H + /* Define to 1 if you have the `floor' function. */ #undef HAVE_FLOOR @@ -312,6 +327,9 @@ /* Define if your system has the GMIME libraries. */ #undef HAVE_GMIME +/* Define to 1 if you have the header file. */ +#undef HAVE_GRP_H + /* Define to indicate the GSM library */ #undef HAVE_GSM @@ -461,6 +479,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H +/* Define to 1 if you have the header file. */ +#undef HAVE_MATH_H + /* Define to 1 if you have the `memchr' function. */ #undef HAVE_MEMCHR @@ -752,6 +773,9 @@ /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV +/* Define to 1 if you have the header file. */ +#undef HAVE_PWD_H + /* Define if your system has the PWLib libraries. */ #undef HAVE_PWLIB @@ -764,6 +788,9 @@ /* Define to 1 if you have the `regcomp' function. */ #undef HAVE_REGCOMP +/* Define to 1 if you have the header file. */ +#undef HAVE_REGEX_H + /* Define to 1 if you have the `remainder' function. */ #undef HAVE_REMAINDER @@ -773,6 +800,9 @@ /* Define to 1 if you have the LIBRESAMPLE library. */ #undef HAVE_RESAMPLE +/* Define to 1 if you have the header file. */ +#undef HAVE_RESOLV_H + /* Define to 1 if your system has the close resolver function. */ #undef HAVE_RES_CLOSE @@ -809,6 +839,9 @@ /* Define to 1 if your system has /sbin/launchd. */ #undef HAVE_SBIN_LAUNCHD +/* Define to 1 if you have the header file. */ +#undef HAVE_SCHED_H + /* Define if your system has the SDL libraries. */ #undef HAVE_SDL @@ -889,6 +922,9 @@ zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H @@ -898,6 +934,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H @@ -1066,9 +1105,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IO_H - /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H @@ -1079,6 +1115,9 @@ /* Define to 1 if your system has working sys/poll.h */ #undef HAVE_SYS_POLL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H @@ -1097,6 +1136,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UN_H + /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H @@ -1118,6 +1160,9 @@ /* Define to 1 if your system defines timersub. */ #undef HAVE_TIMERSUB +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + /* Define to 1 if you have the Term Info library. */ #undef HAVE_TINFO diff --git a/include/asterisk/compat.h b/include/asterisk/compat.h index 252ce914a27..88f88cf8bb4 100644 --- a/include/asterisk/compat.h +++ b/include/asterisk/compat.h @@ -27,35 +27,18 @@ #define __STDC_VERSION__ 0 #endif -#ifdef HAVE_INTTYPES_H #include -#endif - -#ifdef HAVE_LIMITS_H #include -#endif - -#ifdef HAVE_UNISTD_H #include -#endif #ifdef HAVE_STDDEF_H #include #endif -#ifdef HAVE_STDINT_H #include -#endif - -#ifdef HAVE_SYS_TYPES_H #include -#endif - #include - -#ifdef HAVE_STDLIB_H #include -#endif #ifdef HAVE_ALLOCA_H #include /* not necessarily present - could be in stdlib */ @@ -65,9 +48,7 @@ #include /* this is always present */ -#ifdef HAVE_STRING_H #include -#endif #ifndef AST_POLL_COMPAT #include @@ -158,7 +139,6 @@ void timersub(struct timeval *tvend, struct timeval *tvstart, struct timeval *tv #include #include -#include #include #include #include From 6c3ae397cbd8c5655e553e3ae7684bedbdfef178 Mon Sep 17 00:00:00 2001 From: Daniel Journo Date: Sun, 26 Mar 2017 00:01:06 +0000 Subject: [PATCH 1179/1578] Unused realtime MOH classes not purged on 'moh reload' Purge Realtime MOH classes on 'moh reload' even when musiconhold.conf hasn't changed. ASTERISK-25974 #close Change-Id: I42c78ea76528473a656f204595956c9eedcf3246 --- res/res_musiconhold.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 992737b15d5..71f4691af26 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -155,6 +155,7 @@ struct moh_files_state { /* Custom astobj2 flag */ #define MOH_NOTDELETED (1 << 30) /*!< Find only records that aren't deleted? */ +#define MOH_REALTIME (1 << 31) /*!< Find only records that are realtime */ static struct ast_flags global_flags[1] = {{0}}; /*!< global MOH_ flags */ @@ -1676,7 +1677,9 @@ static int moh_class_mark(void *obj, void *arg, int flags) { struct mohclass *class = obj; - class->delete = 1; + if ( ((flags & MOH_REALTIME) && class->realtime) || !(flags & MOH_REALTIME) ) { + class->delete = 1; + } return 0; } @@ -1692,22 +1695,27 @@ static int load_moh_classes(int reload) { struct ast_config *cfg; struct ast_variable *var; - struct mohclass *class; + struct mohclass *class; char *cat; int numclasses = 0; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; cfg = ast_config_load("musiconhold.conf", config_flags); - if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { + if (cfg == CONFIG_STATUS_FILEUNCHANGED) { if (ast_check_realtime("musiconhold") && reload) { - ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); + ao2_t_callback(mohclasses, OBJ_NODATA | MOH_REALTIME, moh_class_mark, NULL, "Mark realtime classes for deletion"); ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes"); } + moh_rescan_files(); return 0; } - if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - moh_rescan_files(); + + if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { + if (ast_check_realtime("musiconhold") && reload) { + ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); + ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes"); + } return 0; } From 380973cc477f0060b7bfe09ad1034a0b53a343fd Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 27 Mar 2017 10:03:49 -0400 Subject: [PATCH 1180/1578] CDR: Protect from data overflow in ast_cdr_setuserfield. ast_cdr_setuserfield wrote to a fixed length field using strcpy. This could result in a buffer overrun when called from chan_sip or func_cdr. This patch adds a maximum bytes written to the field by using ast_copy_string instead. ASTERISK-26897 #close patches: 0001-CDR-Protect-from-data-overflow-in-ast_cdr_setuserfie.patch submitted by Corey Farrell (license #5909) Change-Id: Ib23ca77e9b9e2803a450e1206af45df2d2fdf65c --- main/cdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/cdr.c b/main/cdr.c index 363a2c6b1ea..214af2cbc99 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -3278,7 +3278,7 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) { continue; } - strcpy(it_cdr->party_a.userfield, userfield); + ast_copy_string(it_cdr->party_a.userfield, userfield, AST_MAX_USER_FIELD); } ao2_unlock(cdr); } From f2ee8ac21ef7eeb876529e31afef10053673f8d0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 3 Apr 2017 15:38:06 -0500 Subject: [PATCH 1181/1578] res_pjsip_sdp_rtp.c: Don't alter global addr variable. * create_rtp(): Fix unexpected alteration of global address_rtp if a transport is bound to an address. * create_rtp(): Fix use of uninitialized memory if the endpoint RTP media address is invalid or the transport has an invalid address. ASTERISK-26851 Change-Id: Icde42e65164a88913cb5c2601b285eebcff397b7 --- res/res_pjsip_sdp_rtp.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 21de4409c1d..701edc3c202 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -198,8 +198,16 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me struct ast_sockaddr *media_address = &address_rtp; if (session->endpoint->media.bind_rtp_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) { - ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0); - media_address = &temp_media_address; + if (ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0)) { + ast_debug(1, "Endpoint %s: Binding RTP media to %s\n", + ast_sorcery_object_get_id(session->endpoint), + session->endpoint->media.address); + media_address = &temp_media_address; + } else { + ast_debug(1, "Endpoint %s: RTP media address invalid: %s\n", + ast_sorcery_object_get_id(session->endpoint), + session->endpoint->media.address); + } } else { struct ast_sip_transport *transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", @@ -209,9 +217,14 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me char hoststr[PJ_INET6_ADDRSTRLEN]; pj_sockaddr_print(&transport->state->host, hoststr, sizeof(hoststr), 0); - ast_debug(1, "Transport: %s bound to host: %s, using this for media.\n", - session->endpoint->transport, hoststr); - ast_sockaddr_parse(media_address, hoststr, 0); + if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) { + ast_debug(1, "Transport %s bound to %s: Using it for RTP media.\n", + session->endpoint->transport, hoststr); + media_address = &temp_media_address; + } else { + ast_debug(1, "Transport %s bound to %s: Invalid for RTP media.\n", + session->endpoint->transport, hoststr); + } } ao2_cleanup(transport); } From 40e9d5e8b77913fc16af70443b6a0867f41520d6 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 5 Apr 2017 13:50:40 -0600 Subject: [PATCH 1182/1578] sample_config: Add samples for pubsub to pjsip.conf.sample Added: * outbound-publish * resource_list * inbound-publication * asterisk-publication Change-Id: I65043a896c35483f30a92d30b5b118359af7ba5a --- configs/samples/pjsip.conf.sample | 141 ++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index bb80768f552..612649ec545 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -77,6 +77,8 @@ ; * Defines a permission list or references one stored in acl.conf ; * Registration "registration" ; * Contains information about an outbound SIP registration +; * Resource Lists +; * Contains information for configuring resource lists. ; * Phone Provisioning "phoneprov" ; * Contains information needed by res_phoneprov for autoprovisioning @@ -1107,3 +1109,142 @@ ; Common variables include LINE, LINEKEYS, etc. ; See phoneprov.conf.sample for others. ;type= ; Must be of type phoneprov (default: "") + + + +; MODULE PROVIDING BELOW SECTION(S): res_pjsip_outbound_publish +;======================OUTBOUND_PUBLISHEN SECTION OPTIONS===================== +; See https://wiki.asterisk.org/wiki/display/AST/Publishing+Extension+State +; for more information. +;[outbound-publish] +;type=outbound-publish ; Must be of type 'outbound-publish'. + +;expiration=3600 ; Expiration time for publications in seconds + +;outbound_auth= ; Authentication object(s) to be used for outbound + ; publishes. + ; This is a comma-delimited list of auth sections + ; defined in pjsip.conf used to respond to outbound + ; authentication challenges. + ; Using the same auth section for inbound and + ; outbound authentication is not recommended. There + ; is a difference in meaning for an empty realm + ; setting between inbound and outbound authentication + ; uses. See the auth realm description for details. + +;outbound_proxy= ; SIP URI of the outbound proxy used to send + ; publishes + +;server_uri= ; SIP URI of the server and entity to publish to. + ; This is the URI at which to find the entity and + ; server to send the outbound PUBLISH to. + ; This URI is used as the request URI of the outbound + ; PUBLISH request from Asterisk. + +;from_uri= ; SIP URI to use in the From header. + ; This is the URI that will be placed into the From + ; header of outgoing PUBLISH messages. If no URI is + ; specified then the URI provided in server_uri will + ; be used. + +;to_uri= ; SIP URI to use in the To header. + ; This is the URI that will be placed into the To + ; header of outgoing PUBLISH messages. If no URI is + ; specified then the URI provided in server_uri will + ; be used. + +;event= ; Event type of the PUBLISH. + +;max_auth_attempts= ; Maximum number of authentication attempts before + ; stopping the pub. + +;transport= ; Transport used for outbound publish. + ; A transport configured in pjsip.conf. As with other + ; res_pjsip modules, this will use the first + ; available transport of the appropriate type if + ; unconfigured. + +;multi_user=no ; Enable multi-user support (Asterisk 14+ only) + + + +; MODULE PROVIDING BELOW SECTION(S): res_pjsip_pubsub +;=============================RESOURCE-LIST=================================== +; See https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=30278158 +; for more information. +;[resource_list] +;type=resource_list ; Must be of type 'resource_list'. + +;event= ; The SIP event package that the list resource. + ; belongs to. The SIP event package describes the + ; types of resources that Asterisk reports the state + ; of. + +;list_item= ; The name of a resource to report state on. + ; In general Asterisk looks up list items in the + ; following way: + ; 1. Check if the list item refers to another + ; configured resource list. + ; 2. Pass the name of the resource off to + ; event-package-specific handlers to find the + ; specified resource. + ; The second part means that the way the list item + ; is specified depends on what type of list this is. + ; For instance, if you have the event set to + ; presence, then list items should be in the form of + ; dialplan_extension@dialplan_context. For + ; message-summary, mailbox names should be listed. + +;full_state=no ; Indicates if the entire list's state should be + ; sent out. + ; If this option is enabled, and a resource changes + ; state, then Asterisk will construct a notification + ; that contains the state of all resources in the + ; list. If the option is disabled, Asterisk will + ; construct a notification that only contains the + ; states of resources that have changed. + ; NOTE: Even with this option disabled, there are + ; certain situations where Asterisk is forced to send + ; a notification with the states of all resources in + ; the list. When a subscriber renews or terminates + ; its subscription to the list, Asterisk MUST send + ; a full state notification. + +;notification_batch_interval=0 + ; Time Asterisk should wait, in milliseconds, + ; before sending notifications. + +;==========================INBOUND_PUBLICATION================================ +; See https://wiki.asterisk.org/wiki/display/AST/Exchanging+Device+and+Mailbox+State+Using+PJSIP +; for more information. +;[inbound-publication] +;type= ; Must be of type 'inbound-publication'. + +;endpoint= ; Optional name of an endpoint that is only allowed + ; to publish to this resource. + + +; MODULE PROVIDING BELOW SECTION(S): res_pjsip_publish_asterisk +;==========================ASTERISK_PUBLICATION=============================== +; See https://wiki.asterisk.org/wiki/display/AST/Exchanging+Device+and+Mailbox+State+Using+PJSIP +; for more information. +;[asterisk-publication] +;type=asterisk-publication ; Must be of type 'asterisk-publication'. + +;devicestate_publish= ; Optional name of a publish item that can be used + ; to publish a req. + +;mailboxstate_publish= ; Optional name of a publish item that can be used + ; to publish a req. + +;device_state=no ; Whether we should permit incoming device state + ; events. + +;device_state_filter= ; Optional regular expression used to filter what + ; devices we accept events for. + +;mailbox_state=no ; Whether we should permit incoming mailbox state + ; events. + +;mailbox_state_filter= ; Optional regular expression used to filter what + ; mailboxes we accept events for. From fac5115c43b519c42ae8fbfec454311e79b3bbef Mon Sep 17 00:00:00 2001 From: Troy Bowman Date: Tue, 4 Apr 2017 10:44:34 -0600 Subject: [PATCH 1183/1578] app_queue: Log reason for PAUSEALL/UNPAUSEALL We needed the reason for our reporting when agents pause/unpause all of their queues at once. This is a small, simple patch that adds a reason for PAUSEALL and UNPAUSEALL. I have been using it in production for years. ASTERISK-26920 #close Change-Id: Ifb3f0d1a0abd5194253d9794023546e1395baf3d --- CHANGES | 5 +++++ apps/app_queue.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index f7f8505b8f9..9a82e1fe33b 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,11 @@ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ +app_queue +------------------ + * PAUSEALL/UNPAUSEALL now sets the pause reason in the queue_log if it has + been defined. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ diff --git a/apps/app_queue.c b/apps/app_queue.c index 9bba6762d6e..ae2d645e945 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -7332,7 +7332,7 @@ static int set_member_paused(const char *queuename, const char *interface, const * but since this affects all queues, we cannot. */ ast_queue_log("NONE", "NONE", mem->membername, - (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); + (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, "")); } set_queue_member_pause(q, mem, reason, paused); From 01e9eaf3a62d5e32196b441caa59c451fa1364ea Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 4 Apr 2017 15:20:22 -0600 Subject: [PATCH 1184/1578] pjproject_bundled: Add 3 upstream patches 0035-r5572-svn-backport-dialog-transaction-deadlock.patch 0036-r5573-svn-backport-ua-pjsua-transaction-deadlock.patch 0037-r5576-svn-backport-session-timer-crash.patch Also removed the progress bar from wget download to stdout. ASTERISK-26905 #close Reported-by: Ross Beer Change-Id: I268fb3cf71a3bb24283ff0d24bd8b03239d81256 --- configure | 125 +++++++++++++++++- configure.ac | 4 +- include/asterisk/autoconfig.h.in | 4 + third-party/pjproject/configure.m4 | 1 + ...backport-dialog-transaction-deadlock.patch | 32 +++++ ...ckport-ua-pjsua-transaction-deadlock.patch | 119 +++++++++++++++++ ...576-svn-backport-session-timer-crash.patch | 72 ++++++++++ 7 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 third-party/pjproject/patches/0035-r5572-svn-backport-dialog-transaction-deadlock.patch create mode 100644 third-party/pjproject/patches/0036-r5573-svn-backport-ua-pjsua-transaction-deadlock.patch create mode 100644 third-party/pjproject/patches/0037-r5576-svn-backport-session-timer-crash.patch diff --git a/configure b/configure index b27c94e7a9c..2a87d109240 100755 --- a/configure +++ b/configure @@ -945,6 +945,10 @@ PBX_POPT POPT_DIR POPT_INCLUDE POPT_LIB +PBX_PJSIP_TSX_LAYER_FIND_TSX2 +PJSIP_TSX_LAYER_FIND_TSX2_DIR +PJSIP_TSX_LAYER_FIND_TSX2_INCLUDE +PJSIP_TSX_LAYER_FIND_TSX2_LIB PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT PJSIP_EVSUB_SET_UAS_TIMEOUT_DIR PJSIP_EVSUB_SET_UAS_TIMEOUT_INCLUDE @@ -7912,7 +7916,7 @@ fi if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} - DOWNLOAD_TO_STDOUT="${WGET} -O-" + DOWNLOAD_TO_STDOUT="${WGET} -q -O-" DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" @@ -9356,6 +9360,9 @@ $as_echo "#define HAVE_PJSIP_AUTH_CLT_DEINIT 1" >>confdefs.h $as_echo "#define HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT 1" >>confdefs.h +$as_echo "#define HAVE_PJSIP_TSX_LAYER_FIND_TSX2 1" >>confdefs.h + + @@ -11562,6 +11569,18 @@ PBX_PJSIP_EVSUB_SET_UAS_TIMEOUT=0 + +PJSIP_TSX_LAYER_FIND_TSX2_DESCRIP="pjsip_tsx_layer_find_tsx2 support" +PJSIP_TSX_LAYER_FIND_TSX2_OPTION=pjsip +PJSIP_TSX_LAYER_FIND_TSX2_DIR=${PJPROJECT_DIR} + +PBX_PJSIP_TSX_LAYER_FIND_TSX2=0 + + + + + + fi @@ -26739,6 +26758,110 @@ _ACEOF fi + +if test "x${PBX_PJSIP_TSX_LAYER_FIND_TSX2}" != "x1" -a "${USE_PJSIP_TSX_LAYER_FIND_TSX2}" != "no"; then + pbxlibdir="" + # if --with-PJSIP_TSX_LAYER_FIND_TSX2=DIR has been specified, use it. + if test "x${PJSIP_TSX_LAYER_FIND_TSX2_DIR}" != "x"; then + if test -d ${PJSIP_TSX_LAYER_FIND_TSX2_DIR}/lib; then + pbxlibdir="-L${PJSIP_TSX_LAYER_FIND_TSX2_DIR}/lib" + else + pbxlibdir="-L${PJSIP_TSX_LAYER_FIND_TSX2_DIR}" + fi + fi + pbxfuncname="pjsip_tsx_layer_find_tsx2" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_PJSIP_TSX_LAYER_FIND_TSX2_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS" + as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_PJSIP_TSX_LAYER_FIND_TSX2_FOUND=yes +else + AST_PJSIP_TSX_LAYER_FIND_TSX2_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_PJSIP_TSX_LAYER_FIND_TSX2_FOUND}" = "yes"; then + PJSIP_TSX_LAYER_FIND_TSX2_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB" + # if --with-PJSIP_TSX_LAYER_FIND_TSX2=DIR has been specified, use it. + if test "x${PJSIP_TSX_LAYER_FIND_TSX2_DIR}" != "x"; then + PJSIP_TSX_LAYER_FIND_TSX2_INCLUDE="-I${PJSIP_TSX_LAYER_FIND_TSX2_DIR}/include" + fi + PJSIP_TSX_LAYER_FIND_TSX2_INCLUDE="${PJSIP_TSX_LAYER_FIND_TSX2_INCLUDE} $PJPROJECT_CFLAGS" + if test "xpjsip.h" = "x" ; then # no header, assume found + PJSIP_TSX_LAYER_FIND_TSX2_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${PJSIP_TSX_LAYER_FIND_TSX2_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default" +if test "x$ac_cv_header_pjsip_h" = xyes; then : + PJSIP_TSX_LAYER_FIND_TSX2_HEADER_FOUND=1 +else + PJSIP_TSX_LAYER_FIND_TSX2_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${PJSIP_TSX_LAYER_FIND_TSX2_HEADER_FOUND}" = "x0" ; then + PJSIP_TSX_LAYER_FIND_TSX2_LIB="" + PJSIP_TSX_LAYER_FIND_TSX2_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + PJSIP_TSX_LAYER_FIND_TSX2_LIB="" + fi + PBX_PJSIP_TSX_LAYER_FIND_TSX2=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_PJSIP_TSX_LAYER_FIND_TSX2 1 +_ACEOF + + fi + fi +fi + + fi fi diff --git a/configure.ac b/configure.ac index b0f04887a09..d04d369022b 100644 --- a/configure.ac +++ b/configure.ac @@ -293,7 +293,7 @@ AC_PATH_PROG([NM], [nm], :) if test "${WGET}" != ":" ; then DOWNLOAD=${WGET} - DOWNLOAD_TO_STDOUT="${WGET} -O-" + DOWNLOAD_TO_STDOUT="${WGET} -q -O-" DOWNLOAD_TIMEOUT='--timeout=$1' else if test "${CURL}" != ":" ; then DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" @@ -519,6 +519,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_GRP_LOCK], [PJSIP EVSUB Group Lock suppo AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_SESSION_REF], [PJSIP INVITE Session Reference Count support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_AUTH_CLT_DEINIT], [pjsip_auth_clt_deinit support], [PJPROJECT], [pjsip]) AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_SET_UAS_TIMEOUT], [PJSIP EVSUB Set UAS Timeout support], [PJPROJECT], [pjsip]) +AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TSX_LAYER_FIND_TSX2], [pjsip_tsx_layer_find_tsx2 support], [PJPROJECT], [pjsip]) fi AST_EXT_LIB_SETUP([POPT], [popt], [popt]) @@ -2221,6 +2222,7 @@ if test "$USE_PJPROJECT" != "no" ; then AST_EXT_LIB_CHECK([PJSIP_INV_SESSION_REF], [pjsip], [pjsip_inv_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJSIP_AUTH_CLT_DEINIT], [pjsip], [pjsip_auth_clt_deinit], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) AST_EXT_LIB_CHECK([PJSIP_EVSUB_SET_UAS_TIMEOUT], [pjsip], [pjsip_evsub_set_uas_timeout], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) + AST_EXT_LIB_CHECK([PJSIP_TSX_LAYER_FIND_TSX2], [pjsip], [pjsip_tsx_layer_find_tsx2], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS]) fi fi diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index b9b4e1f8127..5446b010cb7 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -618,6 +618,10 @@ /* Define if your system has the PJSIP_TLS_TRANSPORT_PROTO headers. */ #undef HAVE_PJSIP_TLS_TRANSPORT_PROTO +/* Define to 1 if PJPROJECT has the pjsip_tsx_layer_find_tsx2 support feature. + */ +#undef HAVE_PJSIP_TSX_LAYER_FIND_TSX2 + /* Define to 1 if PJPROJECT has the pj_ssl_cert_load_from_files2 support feature. */ #undef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index d5c85317de6..a5e9fca60c1 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -63,6 +63,7 @@ AC_DEFUN([_PJPROJECT_CONFIGURE], AC_DEFINE([HAVE_PJSIP_INV_SESSION_REF], 1, [Define if your system has PJSIP_INV_SESSION_REF]) AC_DEFINE([HAVE_PJSIP_AUTH_CLT_DEINIT], 1, [Define if your system has pjsip_auth_clt_deinit declared.]) AC_DEFINE([HAVE_PJSIP_EVSUB_SET_UAS_TIMEOUT], 1, [Define if your system has pjsip_evsub_set_uas_timeout declared.]) + AC_DEFINE([HAVE_PJSIP_TSX_LAYER_FIND_TSX2], 1, [Define if your system has pjsip_tsx_layer_find_tsx2 declared.]) AC_SUBST([PJPROJECT_BUNDLED]) AC_SUBST([PJPROJECT_DIR]) diff --git a/third-party/pjproject/patches/0035-r5572-svn-backport-dialog-transaction-deadlock.patch b/third-party/pjproject/patches/0035-r5572-svn-backport-dialog-transaction-deadlock.patch new file mode 100644 index 00000000000..0c5e9866c2a --- /dev/null +++ b/third-party/pjproject/patches/0035-r5572-svn-backport-dialog-transaction-deadlock.patch @@ -0,0 +1,32 @@ +Index: trunk/pjsip/src/pjsip/sip_transaction.c +=================================================================== +--- a/pjsip/src/pjsip/sip_transaction.c (revision 5244) ++++ b/pjsip/src/pjsip/sip_transaction.c (revision 5572) +@@ -1231,5 +1231,27 @@ + PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src, + prev_state); ++ ++ /* For timer event, release lock to avoid deadlock. ++ * This should be safe because: ++ * 1. The tsx state just switches to TERMINATED or DESTROYED. ++ * 2. There should be no other processing taking place. All other ++ * events, such as the ones handled by tsx_on_state_terminated() ++ * should be ignored. ++ * 3. tsx_shutdown() hasn't been called. ++ * Refer to ticket #2001 (https://trac.pjsip.org/repos/ticket/2001). ++ */ ++ if (event_src_type == PJSIP_EVENT_TIMER && ++ (pj_timer_entry *)event_src == &tsx->timeout_timer) ++ { ++ pj_grp_lock_release(tsx->grp_lock); ++ } ++ + (*tsx->tsx_user->on_tsx_state)(tsx, &e); ++ ++ if (event_src_type == PJSIP_EVENT_TIMER && ++ (pj_timer_entry *)event_src == &tsx->timeout_timer) ++ { ++ pj_grp_lock_acquire(tsx->grp_lock); ++ } + } + diff --git a/third-party/pjproject/patches/0036-r5573-svn-backport-ua-pjsua-transaction-deadlock.patch b/third-party/pjproject/patches/0036-r5573-svn-backport-ua-pjsua-transaction-deadlock.patch new file mode 100644 index 00000000000..5887380da1e --- /dev/null +++ b/third-party/pjproject/patches/0036-r5573-svn-backport-ua-pjsua-transaction-deadlock.patch @@ -0,0 +1,119 @@ +Index: trunk/pjsip/include/pjsip/sip_transaction.h +=================================================================== +--- a/pjsip/include/pjsip/sip_transaction.h (revision 5572) ++++ b/pjsip/include/pjsip/sip_transaction.h (revision 5573) +@@ -180,4 +180,8 @@ + * is created by calling #pjsip_tsx_create_key() from an incoming message. + * ++ * IMPORTANT: To prevent deadlock, application should use ++ * #pjsip_tsx_layer_find_tsx2() instead which only adds a reference to ++ * the transaction instead of locking it. ++ * + * @param key The key string to find the transaction. + * @param lock If non-zero, transaction will be locked before the +@@ -190,4 +194,19 @@ + PJ_DECL(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key, + pj_bool_t lock ); ++ ++/** ++ * Find a transaction with the specified key. The transaction key normally ++ * is created by calling #pjsip_tsx_create_key() from an incoming message. ++ * ++ * @param key The key string to find the transaction. ++ * @param add_ref If non-zero, transaction's reference will be added ++ * by one before the function returns, to make sure that ++ * it's not deleted by other threads. ++ * ++ * @return The matching transaction instance, or NULL if transaction ++ * can not be found. ++ */ ++PJ_DECL(pjsip_transaction*) pjsip_tsx_layer_find_tsx2( const pj_str_t *key, ++ pj_bool_t add_ref ); + + /** +Index: trunk/pjsip/src/pjsip/sip_transaction.c +=================================================================== +--- a/pjsip/src/pjsip/sip_transaction.c (revision 5572) ++++ b/pjsip/src/pjsip/sip_transaction.c (revision 5573) +@@ -642,6 +642,6 @@ + * Find a transaction. + */ +-PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key, +- pj_bool_t lock ) ++static pjsip_transaction* find_tsx( const pj_str_t *key, pj_bool_t lock, ++ pj_bool_t add_ref ) + { + pjsip_transaction *tsx; +@@ -655,5 +655,5 @@ + /* Prevent the transaction to get deleted before we have chance to lock it. + */ +- if (tsx && lock) ++ if (tsx) + pj_grp_lock_add_ref(tsx->grp_lock); + +@@ -667,10 +667,27 @@ + PJ_RACE_ME(5); + +- if (tsx && lock) { +- pj_grp_lock_acquire(tsx->grp_lock); +- pj_grp_lock_dec_ref(tsx->grp_lock); ++ if (tsx) { ++ if (lock) ++ pj_grp_lock_acquire(tsx->grp_lock); ++ ++ if (!add_ref) ++ pj_grp_lock_dec_ref(tsx->grp_lock); + } + + return tsx; ++} ++ ++ ++PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key, ++ pj_bool_t lock ) ++{ ++ return find_tsx(key, lock, PJ_FALSE); ++} ++ ++ ++PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx2( const pj_str_t *key, ++ pj_bool_t add_ref ) ++{ ++ return find_tsx(key, PJ_FALSE, add_ref); + } + +Index: trunk/pjsip/src/pjsip/sip_ua_layer.c +=================================================================== +--- a/pjsip/src/pjsip/sip_ua_layer.c (revision 5572) ++++ b/pjsip/src/pjsip/sip_ua_layer.c (revision 5573) +@@ -552,10 +552,10 @@ + + /* Lookup the INVITE transaction */ +- tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); ++ tsx = pjsip_tsx_layer_find_tsx2(&key, PJ_TRUE); + + /* We should find the dialog attached to the INVITE transaction */ + if (tsx) { + dlg = (pjsip_dialog*) tsx->mod_data[mod_ua.mod.id]; +- pj_grp_lock_release(tsx->grp_lock); ++ pj_grp_lock_dec_ref(tsx->grp_lock); + + /* Dlg may be NULL on some extreme condition +Index: trunk/pjsip/src/pjsip-ua/sip_inv.c +=================================================================== +--- a/pjsip/src/pjsip-ua/sip_inv.c (revision 5572) ++++ b/pjsip/src/pjsip-ua/sip_inv.c (revision 5573) +@@ -3276,5 +3276,5 @@ + pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, + pjsip_get_invite_method(), rdata); +- invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); ++ invite_tsx = pjsip_tsx_layer_find_tsx2(&key, PJ_TRUE); + + if (invite_tsx == NULL) { +@@ -3325,5 +3325,5 @@ + + if (invite_tsx) +- pj_grp_lock_release(invite_tsx->grp_lock); ++ pj_grp_lock_dec_ref(invite_tsx->grp_lock); + } + diff --git a/third-party/pjproject/patches/0037-r5576-svn-backport-session-timer-crash.patch b/third-party/pjproject/patches/0037-r5576-svn-backport-session-timer-crash.patch new file mode 100644 index 00000000000..098adcd354c --- /dev/null +++ b/third-party/pjproject/patches/0037-r5576-svn-backport-session-timer-crash.patch @@ -0,0 +1,72 @@ +Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_timer.c +=================================================================== +--- a/pjsip/src/pjsip-ua/sip_timer.c (revision 5557) ++++ b/pjsip/src/pjsip-ua/sip_timer.c (revision 5576) +@@ -333,6 +333,8 @@ + pjsip_tx_data *tdata = NULL; + pj_status_t status; + pj_bool_t as_refresher; ++ int entry_id; ++ char obj_name[PJ_MAX_OBJ_NAME]; + + pj_assert(inv); + +@@ -344,7 +346,10 @@ + /* Check our role */ + as_refresher = + (inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) || +- (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS); ++ (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS); ++ ++ entry_id = entry->id; ++ pj_ansi_strncpy(obj_name, inv->pool->obj_name, PJ_MAX_OBJ_NAME); + + /* Do action based on role(refresher or refreshee). + * As refresher: +@@ -353,7 +358,7 @@ + * As refreshee: + * - end session if there is no refresh request received. + */ +- if (as_refresher && (entry->id != REFRESHER_EXPIRE_TIMER_ID)) { ++ if (as_refresher && (entry_id != REFRESHER_EXPIRE_TIMER_ID)) { + pj_time_val now; + + /* As refresher, reshedule the refresh request on the following: +@@ -414,7 +419,7 @@ + } + + pj_gettimeofday(&now); +- PJ_LOG(4, (inv->pool->obj_name, ++ PJ_LOG(4, (obj_name, + "Refreshing session after %ds (expiration period=%ds)", + (now.sec-inv->timer->last_refresh.sec), + inv->timer->setting.sess_expires)); +@@ -432,7 +437,7 @@ + NULL, &tdata); + + pj_gettimeofday(&now); +- PJ_LOG(3, (inv->pool->obj_name, ++ PJ_LOG(3, (obj_name, + "No session %s received after %ds " + "(expiration period=%ds), stopping session now!", + (as_refresher?"refresh response":"refresh"), +@@ -451,11 +456,16 @@ + status = pjsip_inv_send_msg(inv, tdata); + } + ++ /* ++ * At this point, dialog might have already been destroyed, ++ * including its pool used by the invite session. ++ */ ++ + /* Print error message, if any */ + if (status != PJ_SUCCESS) { +- PJ_PERROR(2, (inv->pool->obj_name, status, ++ PJ_PERROR(2, (obj_name, status, + "Error in %s session timer", +- ((as_refresher && entry->id != REFRESHER_EXPIRE_TIMER_ID)? ++ ((as_refresher && entry_id != REFRESHER_EXPIRE_TIMER_ID)? + "refreshing" : "terminating"))); + } + } + From e6ae3651b878ea76f1d72021a73ee05e721eaa83 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Wed, 5 Apr 2017 16:10:42 +0200 Subject: [PATCH 1185/1578] samples: Canonicalize app names in extensions.conf.sample. This takes care of warnings by ossobv/asterisklint. Change-Id: Ia79aea64de89531362e993e34230c2044a70aa93 --- configs/samples/extensions.conf.sample | 45 +++++++++++++------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/configs/samples/extensions.conf.sample b/configs/samples/extensions.conf.sample index 28319b59219..fb710921caa 100644 --- a/configs/samples/extensions.conf.sample +++ b/configs/samples/extensions.conf.sample @@ -448,8 +448,8 @@ same => n,Congestion() ; exten => s,1,Dial(${ARG1}) exten => s,n,Goto(s-${DIALSTATUS},1) -exten => s-NOANSWER,1,Hangup -exten => s-BUSY,1,Hangup +exten => s-NOANSWER,1,Hangup() +exten => s-BUSY,1,Hangup() exten => _s-.,1,NoOp [stdexten] @@ -478,15 +478,15 @@ exten => _X.,n,Set(LOCAL(mbx)=${ext}${IF($[!${ISNULL(${cntx})}]?@${cntx})}) exten => _X.,n,Dial(${dev},20) ; Ring the interface, 20 seconds maximum exten => _X.,n,Goto(stdexten-${DIALSTATUS},1) ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER) -exten => stdexten-NOANSWER,1,Voicemail(${mbx},u) ; If unavailable, send to voicemail w/ unavail announce +exten => stdexten-NOANSWER,1,VoiceMail(${mbx},u) ; If unavailable, send to voicemail w/ unavail announce exten => stdexten-NOANSWER,n,Return() ; If they press #, return to start -exten => stdexten-BUSY,1,Voicemail(${mbx},b) ; If busy, send to voicemail w/ busy announce +exten => stdexten-BUSY,1,VoiceMail(${mbx},b) ; If busy, send to voicemail w/ busy announce exten => stdexten-BUSY,n,Return() ; If they press #, return to start exten => _stde[x]te[n]-.,1,Goto(stdexten-NOANSWER,1) ; Treat anything else as no answer -exten => a,1,VoicemailMain(${mbx}) ; If they press *, send the user into VoicemailMain +exten => a,1,VoiceMailMain(${mbx}) ; If they press *, send the user into VoicemailMain exten => a,n,Return() [stdPrivacyexten] @@ -512,11 +512,11 @@ exten => _X.,n,Dial(${dev},20,p) ; Ring the interface, 20 seconds maximum, cal ; option (or use P for databased call _X.creening) exten => _X.,n,Goto(stdexten-${DIALSTATUS},1) ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER) -exten => stdexten-NOANSWER,1,Voicemail(${mbx},u) ; If unavailable, send to voicemail w/ unavail announce +exten => stdexten-NOANSWER,1,VoiceMail(${mbx},u) ; If unavailable, send to voicemail w/ unavail announce exten => stdexten-NOANSWER,n,NoOp(Finish stdPrivacyexten NOANSWER) exten => stdexten-NOANSWER,n,Return() ; If they press #, return to start -exten => stdexten-BUSY,1,Voicemail(${mbx},b) ; If busy, send to voicemail w/ busy announce +exten => stdexten-BUSY,1,VoiceMail(${mbx},b) ; If busy, send to voicemail w/ busy announce exten => stdexten-BUSY,n,NoOp(Finish stdPrivacyexten BUSY) exten => stdexten-BUSY,n,Return() ; If they press #, return to start @@ -526,10 +526,10 @@ exten => stdexten-TORTURE,1,Goto(${tortcntx},s,1) ; Callee chose to send this ca exten => _stde[x]te[n]-.,1,Goto(stdexten-NOANSWER,1) ; Treat anything else as no answer -exten => a,1,VoicemailMain(${mbx}) ; If they press *, send the user into VoicemailMain -exten => a,n,Return +exten => a,1,VoiceMailMain(${mbx}) ; If they press *, send the user into VoicemailMain +exten => a,n,Return() -[macro-page]; +[macro-page] ; ; Paging macro: ; @@ -538,26 +538,25 @@ exten => a,n,Return ; ${ARG1} - Device to page exten => s,1,ChanIsAvail(${ARG1},s) ; s is for ANY call -exten => s,n,GoToIf($[${AVAILSTATUS} = "1"]?autoanswer:fail) +exten => s,n,GotoIf($[${AVAILSTATUS} = "1"]?autoanswer:fail) exten => s,n(autoanswer),Set(_ALERT_INFO="RA") ; This is for the PolyComs exten => s,n,SIPAddHeader(Call-Info: Answer-After=0) ; This is for the Grandstream, Snoms, and Others exten => s,n,NoOp() ; Add others here and Post on the Wiki!!!! exten => s,n,Dial(${ARG1}) -exten => s,n(fail),Hangup +exten => s,n(fail),Hangup() [demo] -include => stdexten ; ; We start with what to do when a call first comes in. ; exten => s,1,Wait(1) ; Wait a second, just for fun -exten => s,n,Answer ; Answer the line +exten => s,n,Answer() ; Answer the line exten => s,n,Set(TIMEOUT(digit)=5) ; Set Digit Timeout to 5 seconds exten => s,n,Set(TIMEOUT(response)=10) ; Set Response Timeout to 10 seconds exten => s,n(restart),BackGround(demo-congrats) ; Play a congratulatory message exten => s,n(instruct),BackGround(demo-instruct) ; Play some instructions -exten => s,n,WaitExten ; Wait for an extension to be dialed. +exten => s,n,WaitExten() ; Wait for an extension to be dialed. exten => 2,1,BackGround(demo-moreinfo) ; Give some more information. exten => 2,n,Goto(s,instruct) @@ -575,16 +574,16 @@ exten => 1234,1,Playback(transfer,skip) ; "Please hold while..." exten => 1234,n,Gosub(${EXTEN},stdexten(${GLOBAL(CONSOLE)})) exten => 1234,n,Goto(default,s,1) ; exited Voicemail -exten => 1235,1,Voicemail(1234,u) ; Right to voicemail +exten => 1235,1,VoiceMail(1234,u) ; Right to voicemail exten => 1236,1,Dial(Console/dsp) ; Ring forever -exten => 1236,n,Voicemail(1234,b) ; Unless busy +exten => 1236,n,VoiceMail(1234,b) ; Unless busy ; ; # for when they're done with the demo ; exten => #,1,Playback(demo-thanks) ; "Thanks for trying the demo" -exten => #,n,Hangup ; Hang them up. +exten => #,n,Hangup() ; Hang them up. ; ; A timeout and "invalid extension rule" @@ -596,7 +595,7 @@ exten => i,1,Playback(invalid) ; "That's not valid, try again" ; Create an extension, 500, for dialing the ; Asterisk demo. ; -exten => 500,1,Playback(demo-abouttotry); Let them know what's going on +exten => 500,1,Playback(demo-abouttotry) ; Let them know what's going on exten => 500,n,Dial(IAX2/guest@pbx.digium.com/s@default) ; Call the Asterisk demo exten => 500,n,Playback(demo-nogo) ; Couldn't connect to the demo site exten => 500,n,Goto(s,6) ; Return to the start over message. @@ -605,7 +604,7 @@ exten => 500,n,Goto(s,6) ; Return to the start over message. ; Create an extension, 600, for evaluating echo latency. ; exten => 600,1,Playback(demo-echotest) ; Let them know what's going on -exten => 600,n,Echo ; Do the echo test +exten => 600,n,Echo() ; Do the echo test exten => 600,n,Playback(demo-echodone) ; Let them know it's over exten => 600,n,Goto(s,6) ; Start over @@ -623,7 +622,7 @@ exten => 7999,2,Page(Local/Grandstream1@page&Local/Xlite1@page&Local/1234@page/n ; Give voicemail at extension 8500 ; -exten => 8500,1,VoicemailMain +exten => 8500,1,VoiceMailMain() exten => 8500,n,Goto(s,6) ; ; Here's what a phone entry would look like (IXJ for example) @@ -689,9 +688,9 @@ include => demo ;exten => 6245,hint,SIP/Grandstream1&SIP/Xlite1(Joe Schmoe) ; Channel hints for presence ;exten => 6245,1,Dial(SIP/Grandstream1,20,rt) ; permit transfer ;exten => 6245,n(dial),Dial(${HINT},20,rtT) ; Use hint as listed -;exten => 6245,n,Voicemail(6245,u) ; Voicemail (unavailable) +;exten => 6245,n,VoiceMail(6245,u) ; Voicemail (unavailable) ;exten => 6245,s+1,Hangup ; s+1, same as n -;exten => 6245,dial+101,Voicemail(6245,b) ; Voicemail (busy) +;exten => 6245,dial+101,VoiceMail(6245,b) ; Voicemail (busy) ;exten => 6361,1,Dial(IAX2/JaneDoe,,rm) ; ring without time limit ;exten => 6389,1,Dial(MGCP/aaln/1@192.168.0.14) ;exten => 6390,1,Dial(JINGLE/caller/callee) ; Dial via jingle using labels From 7a46cd7433fabb86daca8c07ec397ffe988e95bf Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Fri, 7 Apr 2017 15:06:11 +0200 Subject: [PATCH 1186/1578] pjproject_bundled: Crash on pj_ssl_get_info() while ioqueue_on_read_complete(). When the Asterisk channel driver res_pjsip offers SIP-over-TLS, sometimes, not reproducible, Asterisk crashed in pj_ssl_sock_get_info() because a NULL pointer was read. This change avoids this crash. ASTERISK-26927 #close Change-Id: I24a6011b44d1426d159742ff4421cf806a52938b --- .../0048-r5576-svn-backport-tls-crash.patch | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 third-party/pjproject/patches/0048-r5576-svn-backport-tls-crash.patch diff --git a/third-party/pjproject/patches/0048-r5576-svn-backport-tls-crash.patch b/third-party/pjproject/patches/0048-r5576-svn-backport-tls-crash.patch new file mode 100644 index 00000000000..b5edc71f41b --- /dev/null +++ b/third-party/pjproject/patches/0048-r5576-svn-backport-tls-crash.patch @@ -0,0 +1,32 @@ +Index: /pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c +=================================================================== +--- a/pjlib/src/pj/ssl_sock_ossl.c (revision 5564) ++++ b/pjlib/src/pj/ssl_sock_ossl.c (revision 5565) +@@ -145,5 +145,6 @@ + SSL_STATE_NULL, + SSL_STATE_HANDSHAKING, +- SSL_STATE_ESTABLISHED ++ SSL_STATE_ESTABLISHED, ++ SSL_STATE_ERROR + }; + +@@ -1907,4 +1908,8 @@ + buf->len += size_; + ++ if (status != PJ_SUCCESS) { ++ ssock->ssl_state = SSL_STATE_ERROR; ++ } ++ + ret = (*ssock->param.cb.on_data_read)(ssock, buf->data, + buf->len, status, +@@ -2658,5 +2663,9 @@ + /* Current cipher */ + cipher = SSL_get_current_cipher(ssock->ossl_ssl); +- info->cipher = (SSL_CIPHER_get_id(cipher) & 0x00FFFFFF); ++ if (cipher) { ++ info->cipher = (SSL_CIPHER_get_id(cipher) & 0x00FFFFFF); ++ } else { ++ info->cipher = PJ_TLS_UNKNOWN_CIPHER; ++ } + + /* Remote address */ From 270b485f047d7efaa5f10163ba26a55f1bd02bdf Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 7 Apr 2017 13:35:33 +0000 Subject: [PATCH 1187/1578] pjsip: Add Alembic for PUBLISH support. This change adds database tables for the PUBLISH support so it can be configured using realtime. A minor fix to the res_pjsip_publish_asterisk module was done so that it read the sorcery configuration from the correct section. Finally the sample configuration files have been updated. ASTERISK-26928 Change-Id: I81991ae5c75af98d247f7eacd1c0b0a763675952 --- configs/samples/extconfig.conf.sample | 3 + configs/samples/sorcery.conf.sample | 9 +++ .../2da192dbbc65_add_publish_tables.py | 73 +++++++++++++++++++ res/res_pjsip_publish_asterisk.c | 2 +- 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 contrib/ast-db-manage/config/versions/2da192dbbc65_add_publish_tables.py diff --git a/configs/samples/extconfig.conf.sample b/configs/samples/extconfig.conf.sample index 8fb6cac8cc6..0f347a6abaf 100644 --- a/configs/samples/extconfig.conf.sample +++ b/configs/samples/extconfig.conf.sample @@ -84,6 +84,9 @@ ;ps_aors => odbc,asterisk ;ps_domain_aliases => odbc,asterisk ;ps_endpoint_id_ips => odbc,asterisk +;ps_outbound_publishes => odbc,asterisk +;ps_inbound_publications = odbc,asterisk +;ps_asterisk_publications = odbc,asterisk ;voicemail => odbc,asterisk ;extensions => odbc,asterisk ;meetme => mysql,general diff --git a/configs/samples/sorcery.conf.sample b/configs/samples/sorcery.conf.sample index 7e95883854e..1e7d72a723c 100644 --- a/configs/samples/sorcery.conf.sample +++ b/configs/samples/sorcery.conf.sample @@ -67,3 +67,12 @@ test=memory ;[res_pjsip_endpoint_identifier_ip] ;identify=realtime,ps_endpoint_id_ips + +;[res_pjsip_outbound_publish] +;outbound-publish=realtime,ps_outbound_publishes + +;[res_pjsip_pubsub] +;inbound-publication=realtime,ps_inbound_publications + +;[res_pjsip_publish_asterisk] +;asterisk-publication=realtime,ps_asterisk_publications diff --git a/contrib/ast-db-manage/config/versions/2da192dbbc65_add_publish_tables.py b/contrib/ast-db-manage/config/versions/2da192dbbc65_add_publish_tables.py new file mode 100644 index 00000000000..affdc29fe14 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/2da192dbbc65_add_publish_tables.py @@ -0,0 +1,73 @@ +"""add publish tables + +Revision ID: 2da192dbbc65 +Revises: 8fce4c573e15 +Create Date: 2017-04-05 10:16:52.504699 + +""" + +# revision identifiers, used by Alembic. +revision = '2da192dbbc65' +down_revision = '8fce4c573e15' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.create_table( + 'ps_outbound_publishes', + sa.Column('id', sa.String(40), nullable=False, unique=True), + sa.Column('expiration', sa.Integer), + sa.Column('outbound_auth', sa.String(40)), + sa.Column('outbound_proxy', sa.String(256)), + sa.Column('server_uri', sa.String(256)), + sa.Column('from_uri', sa.String(256)), + sa.Column('to_uri', sa.String(256)), + sa.Column('event', sa.String(40)), + sa.Column('max_auth_attempts', sa.Integer), + sa.Column('transport', sa.String(40)), + sa.Column('multi_user', yesno_values), + sa.Column('@body', sa.String(40)), + sa.Column('@context', sa.String(256)), + sa.Column('@exten', sa.String(256)), + ) + + op.create_index('ps_outbound_publishes_id', 'ps_outbound_publishes', ['id']) + + op.create_table( + 'ps_inbound_publications', + sa.Column('id', sa.String(40), nullable=False, unique=True), + sa.Column('endpoint', sa.String(40)), + sa.Column('event_asterisk-devicestate', sa.String(40)), + sa.Column('event_asterisk-mwi', sa.String(40)), + ) + + op.create_index('ps_inbound_publications_id', 'ps_inbound_publications', ['id']) + + op.create_table( + 'ps_asterisk_publications', + sa.Column('id', sa.String(40), nullable=False, unique=True), + sa.Column('devicestate_publish', sa.String(40)), + sa.Column('mailboxstate_publish', sa.String(40)), + sa.Column('device_state', yesno_values), + sa.Column('device_state_filter', sa.String(256)), + sa.Column('mailbox_state', yesno_values), + sa.Column('mailbox_state_filter', sa.String(256)), + ) + + op.create_index('ps_asterisk_publications_id', 'ps_asterisk_publications', ['id']) + +def downgrade(): + op.drop_table('ps_outbound_publishes') + op.drop_table('ps_inbound_publications') + op.drop_table('ps_asterisk_publications') diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index b32408aa3fd..7e87762fd34 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -863,7 +863,7 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - ast_sorcery_apply_config(ast_sip_get_sorcery(), "asterisk-publication"); + ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_publish_asterisk"); ast_sorcery_apply_default(ast_sip_get_sorcery(), "asterisk-publication", "config", "pjsip.conf,criteria=type=asterisk-publication"); if (ast_sorcery_object_register(ast_sip_get_sorcery(), "asterisk-publication", asterisk_publication_config_alloc, NULL, NULL)) { From 2b8dbc9e00094ad0913fa56580266086fc120f3c Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Sat, 8 Apr 2017 10:05:03 +0200 Subject: [PATCH 1188/1578] samples: Undo removal of include from canonicalize-app-names commit. This include was accidentally removed in changeset Ia79aea64de89531362e993e34230c2044a70aa93. My bad. Change-Id: I1d716c7f9590b4e97909fb8bca1f2ed9bd0e4082 --- configs/samples/extensions.conf.sample | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/samples/extensions.conf.sample b/configs/samples/extensions.conf.sample index fb710921caa..db4c215e84b 100644 --- a/configs/samples/extensions.conf.sample +++ b/configs/samples/extensions.conf.sample @@ -547,6 +547,7 @@ exten => s,n(fail),Hangup() [demo] +include => stdexten ; ; We start with what to do when a call first comes in. ; From d76bc0565c070e329e47bd108d8b6218c3233770 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 10 Apr 2017 17:45:35 -0500 Subject: [PATCH 1189/1578] tcptls.c: Cleanup TCP/TLS listener thread on abnormal exit. Temporarily running out of file descriptors should not terminate the listener thread. Otherwise, when there becomes more file descriptors available, nothing is listening. * Added EMFILE exception to abnormal thread exit. * Added an abnormal TCP/TLS listener exit error message. * Closed the TCP/TLS listener socket on abnormal exit so Asterisk does not appear dead if something tries to connect to the socket. ASTERISK-26903 #close Change-Id: I10f2f784065136277f271159f0925927194581b5 --- main/tcptls.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/main/tcptls.c b/main/tcptls.c index 1377dd72d93..a3c7dfa7202 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -228,14 +228,23 @@ void *ast_tcptls_server_root(void *data) } i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); if (i <= 0) { + /* Prevent tight loop from hogging CPU */ + usleep(1); continue; } fd = ast_accept(desc->accept_fd, &addr); if (fd < 0) { - if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINTR) && (errno != ECONNABORTED)) { - ast_log(LOG_ERROR, "Accept failed: %s\n", strerror(errno)); - break; + if (errno != EAGAIN + && errno != EWOULDBLOCK + && errno != EINTR + && errno != ECONNABORTED) { + ast_log(LOG_ERROR, "TCP/TLS accept failed: %s\n", strerror(errno)); + if (errno != EMFILE) { + break; + } } + /* Prevent tight loop from hogging CPU */ + usleep(1); continue; } tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); @@ -267,10 +276,20 @@ void *ast_tcptls_server_root(void *data) /* This thread is now the only place that controls the single ref to tcptls_session */ if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { - ast_log(LOG_ERROR, "Unable to launch helper thread: %s\n", strerror(errno)); + ast_log(LOG_ERROR, "TCP/TLS unable to launch helper thread: %s\n", + strerror(errno)); ao2_ref(tcptls_session, -1); } } + + ast_log(LOG_ERROR, "TCP/TLS listener thread ended abnormally\n"); + + /* Close the listener socket so Asterisk doesn't appear dead. */ + fd = desc->accept_fd; + desc->accept_fd = -1; + if (0 <= fd) { + close(fd); + } return NULL; } From 6f793ac149c84b05c5364b7181988eff9163c45b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 6 Apr 2017 18:18:16 -0500 Subject: [PATCH 1190/1578] res_pjsip_sdp_rtp.c: Don't use deprecated transport struct member. * create_rtp(): Eliminate use of deprecated transport struct member. That member and several others in the transport structure were deprecated because of an infinite loop created when using realtime configuration. See 2451d4e4550336197ee2e482750cc53f30afa352 ASTERISK-26851 Change-Id: I0533aa13c9ce3c6cc394e0fd2b5bf1cd1b2ef3bc --- res/res_pjsip_sdp_rtp.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 701edc3c202..7c861dac916 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -209,24 +209,30 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me session->endpoint->media.address); } } else { - struct ast_sip_transport *transport = - ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", - session->endpoint->transport); - - if (transport && transport->state) { - char hoststr[PJ_INET6_ADDRSTRLEN]; - - pj_sockaddr_print(&transport->state->host, hoststr, sizeof(hoststr), 0); - if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) { - ast_debug(1, "Transport %s bound to %s: Using it for RTP media.\n", - session->endpoint->transport, hoststr); - media_address = &temp_media_address; - } else { - ast_debug(1, "Transport %s bound to %s: Invalid for RTP media.\n", - session->endpoint->transport, hoststr); + struct ast_sip_transport *transport; + + transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", + session->endpoint->transport); + if (transport) { + struct ast_sip_transport_state *trans_state; + + trans_state = ast_sip_get_transport_state(ast_sorcery_object_get_id(transport)); + if (trans_state) { + char hoststr[PJ_INET6_ADDRSTRLEN]; + + pj_sockaddr_print(&trans_state->host, hoststr, sizeof(hoststr), 0); + if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) { + ast_debug(1, "Transport %s bound to %s: Using it for RTP media.\n", + session->endpoint->transport, hoststr); + media_address = &temp_media_address; + } else { + ast_debug(1, "Transport %s bound to %s: Invalid for RTP media.\n", + session->endpoint->transport, hoststr); + } + ao2_ref(trans_state, -1); } + ao2_ref(transport, -1); } - ao2_cleanup(transport); } if (!(session_media->rtp = ast_rtp_instance_new(session->endpoint->media.rtp.engine, sched, media_address, NULL))) { From 5b4e2ec2677bff5c0e9814795e433d914f52bf7f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 10 Apr 2017 11:30:35 -0500 Subject: [PATCH 1191/1578] res_pjsip: Fix pointer use after unref. Change-Id: I4b6e1b0070563eeaee223cb58326f1b962ed5bc1 --- res/res_pjsip/config_transport.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 3c41f175aa1..d180296f420 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -286,15 +286,16 @@ static struct internal_state *find_internal_state_by_transport(const struct ast_ static struct ast_sip_transport_state *find_state_by_transport(const struct ast_sip_transport *transport) { struct internal_state *state; + struct ast_sip_transport_state *trans_state; state = find_internal_state_by_transport(transport); if (!state) { return NULL; } - ao2_bump(state->state); - ao2_cleanup(state); + trans_state = ao2_bump(state->state); + ao2_ref(state, -1); - return state->state; + return trans_state; } static int remove_temporary_state(void) @@ -1297,22 +1298,22 @@ static struct ast_sip_cli_formatter_entry *cli_formatter; struct ast_sip_transport_state *ast_sip_get_transport_state(const char *transport_id) { - struct internal_state * state = NULL; + struct internal_state *state = NULL; + struct ast_sip_transport_state *trans_state; if (!transport_states) { return NULL; } state = ao2_find(transport_states, transport_id, OBJ_SEARCH_KEY); - if (!state || !state->state) { - ao2_cleanup(state); + if (!state) { return NULL; } - ao2_ref(state->state, +1); + trans_state = ao2_bump(state->state); ao2_ref(state, -1); - return state->state; + return trans_state; } static int populate_transport_states(void *obj, void *arg, int flags) From 8d323c74fa60fd1eb411336753ef4052faf7b309 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 6 Apr 2017 18:30:11 -0500 Subject: [PATCH 1192/1578] sorcery.c: Speed up ast_sorcery_retrieve_by_id() Return early if ast_sorcery_retrieve_by_id() is not passed an id to find. Also eliminated the RAII_VAR() usage in the function. Change-Id: I871dbe162a301b5ced8b4393cec27180c7c6b218 --- main/sorcery.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/main/sorcery.c b/main/sorcery.c index 51b0b22bec6..0bb2826c818 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -1877,12 +1877,17 @@ static int sorcery_cache_create(void *obj, void *arg, int flags) void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id) { - RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); + struct ast_sorcery_object_type *object_type; void *object = NULL; int i; unsigned int cached = 0; - if (!object_type || ast_strlen_zero(id)) { + if (ast_strlen_zero(id)) { + return NULL; + } + + object_type = ao2_find(sorcery->types, type, OBJ_SEARCH_KEY); + if (!object_type) { return NULL; } @@ -1910,6 +1915,7 @@ void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char * } AST_VECTOR_RW_UNLOCK(&object_type->wizards); + ao2_ref(object_type, -1); return object; } From 7c37365f03aed7b7bf9f89a96272fd37d9f904d9 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 6 Apr 2017 17:31:14 -0500 Subject: [PATCH 1193/1578] stun.c: Fix ast_stun_request() erratic timeout. If ast_stun_request() receives packets other than a STUN response then we could conceivably never exit if we continue to receive packets with less than three seconds between them. * Fix poll timeout to keep track of the time when we sent the STUN request. We will now send a STUN request every three seconds regardless of how many other packets we receive while waiting for a response until we have completed three STUN request transmission cycles. Change-Id: Ib606cb08585e06eb50877f67b8d3bd385a85c266 --- main/stun.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/main/stun.c b/main/stun.c index 356266c94d6..77ced82ae0a 100644 --- a/main/stun.c +++ b/main/stun.c @@ -411,6 +411,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst, /* send request, possibly wait for reply */ struct sockaddr_in src; socklen_t srclen; + struct timeval start; /* Send STUN message. */ res = stun_send(s, dst, req); @@ -424,12 +425,20 @@ int ast_stun_request(int s, struct sockaddr_in *dst, break; } + start = ast_tvnow(); try_again: /* Wait for response. */ { struct pollfd pfds = { .fd = s, .events = POLLIN }; + int ms; - res = ast_poll(&pfds, 1, 3000); + ms = ast_remaining_ms(start, 3000); + if (ms <= 0) { + /* No response, timeout */ + res = 1; + continue; + } + res = ast_poll(&pfds, 1, ms); if (res < 0) { /* Error */ continue; From 7312cbe803b975b30b54e3a1b76160be9f158985 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 7 Apr 2017 16:14:16 -0500 Subject: [PATCH 1194/1578] res_rtp_asterisk.c: Add stun_blacklist option Added the stun_blacklist option to rtp.conf. Some multihomed servers have IP interfaces that cannot reach the STUN server specified by stunaddr. Blacklist those interface subnets from trying to send a STUN packet to find the external IP address. Attempting to send the STUN packet needlessly delays processing incoming and outgoing SIP INVITEs because we will wait for a response that can never come until we give up on the response. Multiple subnets may be listed. ASTERISK-26890 #close Change-Id: I3ff4f729e787f00c3e6e670fe6435acce38be342 --- CHANGES | 10 + configs/samples/rtp.conf.sample | 19 ++ res/res_rtp_asterisk.c | 323 ++++++++++++++++++++------------ 3 files changed, 229 insertions(+), 123 deletions(-) diff --git a/CHANGES b/CHANGES index 9a82e1fe33b..9c8ed5b8e77 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,16 @@ app_queue --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ +res_rtp_asterisk +------------------ + * Added the stun_blacklist option to rtp.conf. Some multihomed servers have + IP interfaces that cannot reach the STUN server specified by stunaddr. + Blacklist those interface subnets from trying to send a STUN packet to find + the external IP address. Attempting to send the STUN packet needlessly + delays processing incoming and outgoing SIP INVITEs because we will wait + for a response that can never come until we give up on the response. + Multiple subnets may be listed. + res_pjsip_config_wizard ------------------ * Two new parameters have been added to the pjsip config wizard. diff --git a/configs/samples/rtp.conf.sample b/configs/samples/rtp.conf.sample index fdd1d530e17..eae7d8bafe4 100644 --- a/configs/samples/rtp.conf.sample +++ b/configs/samples/rtp.conf.sample @@ -45,6 +45,25 @@ rtpend=20000 ; ; stunaddr= ; +; Some multihomed servers have IP interfaces that cannot reach the STUN +; server specified by stunaddr. Blacklist those interface subnets from +; trying to send a STUN packet to find the external IP address. +; Attempting to send the STUN packet needlessly delays processing incoming +; and outgoing SIP INVITEs because we will wait for a response that can +; never come until we give up on the response. +; * Multiple subnets may be listed. +; * Blacklisting applies to IPv4 only. STUN isn't needed for IPv6. +; * Blacklisting applies when binding RTP to specific IP addresses and not +; the wildcard 0.0.0.0 address. e.g., A PJSIP endpoint binding RTP to a +; specific address using the bind_rtp_to_media_address and media_address +; options. Or the PJSIP endpoint specifies an explicit transport that binds +; to a specific IP address. +; +; e.g. stun_blacklist = 192.168.1.0/255.255.255.0 +; stun_blacklist = 10.32.77.0/255.255.255.0 +; +; stun_blacklist = +; ; Hostname or address for the TURN server to be used as a relay. The port ; number is optional. If omitted the default value of 3478 will be used. ; This option is disabled by default. diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 88201837d36..a7103860b87 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -131,13 +131,13 @@ static int rtcpstats; /*!< Are we debugging RTCP? */ static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */ static struct ast_sockaddr rtpdebugaddr; /*!< Debug packets to/from this host */ static struct ast_sockaddr rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */ -static int rtpdebugport; /*< Debug only RTP packets from IP or IP+Port if port is > 0 */ -static int rtcpdebugport; /*< Debug only RTCP packets from IP or IP+Port if port is > 0 */ +static int rtpdebugport; /*!< Debug only RTP packets from IP or IP+Port if port is > 0 */ +static int rtcpdebugport; /*!< Debug only RTCP packets from IP or IP+Port if port is > 0 */ #ifdef SO_NO_CHECK static int nochecksums; #endif -static int strictrtp = DEFAULT_STRICT_RTP; /*< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */ -static int learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; /*< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */ +static int strictrtp = DEFAULT_STRICT_RTP; /*!< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */ +static int learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; /*!< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */ #ifdef HAVE_PJPROJECT static int icesupport = DEFAULT_ICESUPPORT; static struct sockaddr_in stunaddr; @@ -145,9 +145,14 @@ static pj_str_t turnaddr; static int turnport = DEFAULT_TURN_PORT; static pj_str_t turnusername; static pj_str_t turnpassword; + static struct ast_ha *ice_blacklist = NULL; /*!< Blacklisted ICE networks */ static ast_rwlock_t ice_blacklist_lock = AST_RWLOCK_INIT_VALUE; +/*! Blacklisted networks for STUN requests */ +static struct ast_ha *stun_blacklist = NULL; +static ast_rwlock_t stun_blacklist_lock = AST_RWLOCK_INIT_VALUE; + /*! \brief Pool factory used by pjlib to allocate memory. */ static pj_caching_pool cachingpool; @@ -2523,6 +2528,32 @@ static int rtp_address_is_ice_blacklisted(const pj_sockaddr_t *address) return result; } +/*! + * \internal + * \brief Checks an address against the STUN blacklist + * \since 13.16.0 + * + * \note If there is no stun_blacklist list, always returns 0 + * + * \param addr The address to consider + * + * \retval 0 if address is not STUN blacklisted + * \retval 1 if address is STUN blacklisted + */ +static int stun_address_is_blacklisted(const struct ast_sockaddr *addr) +{ + int result = 1; + + ast_rwlock_rdlock(&stun_blacklist_lock); + if (!stun_blacklist + || ast_apply_ha(stun_blacklist, addr) == AST_SENSE_ALLOW) { + result = 0; + } + ast_rwlock_unlock(&stun_blacklist_lock); + + return result; +} + static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_sockaddr *addr, int port, int component, int transport) { @@ -2557,7 +2588,8 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct } /* If configured to use a STUN server to get our external mapped address do so */ - if (stunaddr.sin_addr.s_addr && ast_sockaddr_is_ipv4(addr) && count) { + if (stunaddr.sin_addr.s_addr && count && ast_sockaddr_is_ipv4(addr) + && !stun_address_is_blacklisted(addr)) { struct sockaddr_in answer; if (!ast_stun_request(component == AST_RTP_ICE_COMPONENT_RTCP ? rtp->rtcp->s : rtp->s, &stunaddr, NULL, &answer)) { @@ -5626,6 +5658,66 @@ static struct ast_cli_entry cli_rtp[] = { AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats"), }; +#ifdef HAVE_PJPROJECT +/*! + * \internal + * \brief Clear the configured blacklist. + * \since 13.16.0 + * + * \param lock R/W lock protecting the blacklist + * \param blacklist List to clear + * + * \return Nothing + */ +static void blacklist_clear(ast_rwlock_t *lock, struct ast_ha **blacklist) +{ + ast_rwlock_wrlock(lock); + ast_free_ha(*blacklist); + *blacklist = NULL; + ast_rwlock_unlock(lock); +} + +/*! + * \internal + * \brief Load the blacklist configuration. + * \since 13.16.0 + * + * \param cfg Raw config file options. + * \param option_name Blacklist option name + * \param lock R/W lock protecting the blacklist + * \param blacklist List to load + * + * \return Nothing + */ +static void blacklist_config_load(struct ast_config *cfg, const char *option_name, + ast_rwlock_t *lock, struct ast_ha **blacklist) +{ + struct ast_variable *var; + + ast_rwlock_wrlock(lock); + for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { + if (!strcasecmp(var->name, option_name)) { + struct ast_ha *na; + int ha_error = 0; + + na = ast_append_ha("d", var->value, *blacklist, &ha_error); + if (!na) { + ast_log(LOG_WARNING, "Invalid %s value: %s\n", + option_name, var->value); + } else { + *blacklist = na; + } + if (ha_error) { + ast_log(LOG_ERROR, + "Bad %s configuration value line %d: %s\n", + option_name, var->lineno, var->value); + } + } + } + ast_rwlock_unlock(lock); +} +#endif + static int rtp_reload(int reload) { struct ast_config *cfg; @@ -5638,7 +5730,7 @@ static int rtp_reload(int reload) #endif cfg = ast_config_load2("rtp.conf", "rtp", config_flags); - if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { + if (!cfg || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { return 0; } @@ -5664,141 +5756,126 @@ static int rtp_reload(int reload) turnusername = pj_str(NULL); turnpassword = pj_str(NULL); host_candidate_overrides_clear(); - ast_rwlock_wrlock(&ice_blacklist_lock); - ast_free_ha(ice_blacklist); - ice_blacklist = NULL; - ast_rwlock_unlock(&ice_blacklist_lock); + blacklist_clear(&ice_blacklist_lock, &ice_blacklist); + blacklist_clear(&stun_blacklist_lock, &stun_blacklist); #endif - if (cfg) { - if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) { - rtpstart = atoi(s); - if (rtpstart < MINIMUM_RTP_PORT) - rtpstart = MINIMUM_RTP_PORT; - if (rtpstart > MAXIMUM_RTP_PORT) - rtpstart = MAXIMUM_RTP_PORT; - } - if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) { - rtpend = atoi(s); - if (rtpend < MINIMUM_RTP_PORT) - rtpend = MINIMUM_RTP_PORT; - if (rtpend > MAXIMUM_RTP_PORT) - rtpend = MAXIMUM_RTP_PORT; - } - if ((s = ast_variable_retrieve(cfg, "general", "rtcpinterval"))) { - rtcpinterval = atoi(s); - if (rtcpinterval == 0) - rtcpinterval = 0; /* Just so we're clear... it's zero */ - if (rtcpinterval < RTCP_MIN_INTERVALMS) - rtcpinterval = RTCP_MIN_INTERVALMS; /* This catches negative numbers too */ - if (rtcpinterval > RTCP_MAX_INTERVALMS) - rtcpinterval = RTCP_MAX_INTERVALMS; - } - if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) { + if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) { + rtpstart = atoi(s); + if (rtpstart < MINIMUM_RTP_PORT) + rtpstart = MINIMUM_RTP_PORT; + if (rtpstart > MAXIMUM_RTP_PORT) + rtpstart = MAXIMUM_RTP_PORT; + } + if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) { + rtpend = atoi(s); + if (rtpend < MINIMUM_RTP_PORT) + rtpend = MINIMUM_RTP_PORT; + if (rtpend > MAXIMUM_RTP_PORT) + rtpend = MAXIMUM_RTP_PORT; + } + if ((s = ast_variable_retrieve(cfg, "general", "rtcpinterval"))) { + rtcpinterval = atoi(s); + if (rtcpinterval == 0) + rtcpinterval = 0; /* Just so we're clear... it's zero */ + if (rtcpinterval < RTCP_MIN_INTERVALMS) + rtcpinterval = RTCP_MIN_INTERVALMS; /* This catches negative numbers too */ + if (rtcpinterval > RTCP_MAX_INTERVALMS) + rtcpinterval = RTCP_MAX_INTERVALMS; + } + if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) { #ifdef SO_NO_CHECK - nochecksums = ast_false(s) ? 1 : 0; + nochecksums = ast_false(s) ? 1 : 0; #else - if (ast_false(s)) - ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n"); + if (ast_false(s)) + ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n"); #endif + } + if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) { + dtmftimeout = atoi(s); + if ((dtmftimeout < 0) || (dtmftimeout > 64000)) { + ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n", + dtmftimeout, DEFAULT_DTMF_TIMEOUT); + dtmftimeout = DEFAULT_DTMF_TIMEOUT; + }; + } + if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) { + strictrtp = ast_true(s); + } + if ((s = ast_variable_retrieve(cfg, "general", "probation"))) { + if ((sscanf(s, "%d", &learning_min_sequential) <= 0) || learning_min_sequential <= 0) { + ast_log(LOG_WARNING, "Value for 'probation' could not be read, using default of '%d' instead\n", + DEFAULT_LEARNING_MIN_SEQUENTIAL); } - if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) { - dtmftimeout = atoi(s); - if ((dtmftimeout < 0) || (dtmftimeout > 64000)) { - ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n", - dtmftimeout, DEFAULT_DTMF_TIMEOUT); - dtmftimeout = DEFAULT_DTMF_TIMEOUT; - }; - } - if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) { - strictrtp = ast_true(s); - } - if ((s = ast_variable_retrieve(cfg, "general", "probation"))) { - if ((sscanf(s, "%d", &learning_min_sequential) <= 0) || learning_min_sequential <= 0) { - ast_log(LOG_WARNING, "Value for 'probation' could not be read, using default of '%d' instead\n", - DEFAULT_LEARNING_MIN_SEQUENTIAL); - } - } + } #ifdef HAVE_PJPROJECT - if ((s = ast_variable_retrieve(cfg, "general", "icesupport"))) { - icesupport = ast_true(s); - } - if ((s = ast_variable_retrieve(cfg, "general", "stunaddr"))) { - stunaddr.sin_port = htons(STANDARD_STUN_PORT); - if (ast_parse_arg(s, PARSE_INADDR, &stunaddr)) { - ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", s); - } - } - if ((s = ast_variable_retrieve(cfg, "general", "turnaddr"))) { - struct sockaddr_in addr; - addr.sin_port = htons(DEFAULT_TURN_PORT); - if (ast_parse_arg(s, PARSE_INADDR, &addr)) { - ast_log(LOG_WARNING, "Invalid TURN server address: %s\n", s); - } else { - pj_strdup2_with_null(pool, &turnaddr, ast_inet_ntoa(addr.sin_addr)); - /* ntohs() is not a bug here. The port number is used in host byte order with - * a pjnat API. */ - turnport = ntohs(addr.sin_port); - } - } - if ((s = ast_variable_retrieve(cfg, "general", "turnusername"))) { - pj_strdup2_with_null(pool, &turnusername, s); + if ((s = ast_variable_retrieve(cfg, "general", "icesupport"))) { + icesupport = ast_true(s); + } + if ((s = ast_variable_retrieve(cfg, "general", "stunaddr"))) { + stunaddr.sin_port = htons(STANDARD_STUN_PORT); + if (ast_parse_arg(s, PARSE_INADDR, &stunaddr)) { + ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", s); } - if ((s = ast_variable_retrieve(cfg, "general", "turnpassword"))) { - pj_strdup2_with_null(pool, &turnpassword, s); + } + if ((s = ast_variable_retrieve(cfg, "general", "turnaddr"))) { + struct sockaddr_in addr; + addr.sin_port = htons(DEFAULT_TURN_PORT); + if (ast_parse_arg(s, PARSE_INADDR, &addr)) { + ast_log(LOG_WARNING, "Invalid TURN server address: %s\n", s); + } else { + pj_strdup2_with_null(pool, &turnaddr, ast_inet_ntoa(addr.sin_addr)); + /* ntohs() is not a bug here. The port number is used in host byte order with + * a pjnat API. */ + turnport = ntohs(addr.sin_port); } + } + if ((s = ast_variable_retrieve(cfg, "general", "turnusername"))) { + pj_strdup2_with_null(pool, &turnusername, s); + } + if ((s = ast_variable_retrieve(cfg, "general", "turnpassword"))) { + pj_strdup2_with_null(pool, &turnpassword, s); + } - AST_RWLIST_WRLOCK(&host_candidates); - for (var = ast_variable_browse(cfg, "ice_host_candidates"); var; var = var->next) { - struct ast_sockaddr local_addr, advertised_addr; - pj_str_t address; + AST_RWLIST_WRLOCK(&host_candidates); + for (var = ast_variable_browse(cfg, "ice_host_candidates"); var; var = var->next) { + struct ast_sockaddr local_addr, advertised_addr; + pj_str_t address; - ast_sockaddr_setnull(&local_addr); - ast_sockaddr_setnull(&advertised_addr); + ast_sockaddr_setnull(&local_addr); + ast_sockaddr_setnull(&advertised_addr); - if (ast_parse_arg(var->name, PARSE_ADDR | PARSE_PORT_IGNORE, &local_addr)) { - ast_log(LOG_WARNING, "Invalid local ICE host address: %s\n", var->name); - continue; - } + if (ast_parse_arg(var->name, PARSE_ADDR | PARSE_PORT_IGNORE, &local_addr)) { + ast_log(LOG_WARNING, "Invalid local ICE host address: %s\n", var->name); + continue; + } - if (ast_parse_arg(var->value, PARSE_ADDR | PARSE_PORT_IGNORE, &advertised_addr)) { - ast_log(LOG_WARNING, "Invalid advertised ICE host address: %s\n", var->value); - continue; - } + if (ast_parse_arg(var->value, PARSE_ADDR | PARSE_PORT_IGNORE, &advertised_addr)) { + ast_log(LOG_WARNING, "Invalid advertised ICE host address: %s\n", var->value); + continue; + } - if (!(candidate = ast_calloc(1, sizeof(*candidate)))) { - ast_log(LOG_ERROR, "Failed to allocate ICE host candidate mapping.\n"); - break; - } + if (!(candidate = ast_calloc(1, sizeof(*candidate)))) { + ast_log(LOG_ERROR, "Failed to allocate ICE host candidate mapping.\n"); + break; + } - pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&local_addr)), &candidate->local); - pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&advertised_addr)), &candidate->advertised); + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&local_addr)), &candidate->local); + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&advertised_addr)), &candidate->advertised); - AST_RWLIST_INSERT_TAIL(&host_candidates, candidate, next); - } - AST_RWLIST_UNLOCK(&host_candidates); - - /* Read ICE blacklist configuration lines */ - ast_rwlock_wrlock(&ice_blacklist_lock); - for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { - if (!strcasecmp(var->name, "ice_blacklist")) { - struct ast_ha *na; - int ha_error = 0; - if (!(na = ast_append_ha("d", var->value, ice_blacklist, &ha_error))) { - ast_log(LOG_WARNING, "Invalid ice_blacklist value: %s\n", var->value); - } else { - ice_blacklist = na; - } - if (ha_error) { - ast_log(LOG_ERROR, "Bad ice_blacklist configuration value line %d : %s\n", var->lineno, var->value); - } - } - } - ast_rwlock_unlock(&ice_blacklist_lock); + AST_RWLIST_INSERT_TAIL(&host_candidates, candidate, next); + } + AST_RWLIST_UNLOCK(&host_candidates); + + /* Read ICE blacklist configuration lines */ + blacklist_config_load(cfg, "ice_blacklist", &ice_blacklist_lock, &ice_blacklist); + /* Read STUN blacklist configuration lines */ + blacklist_config_load(cfg, "stun_blacklist", &stun_blacklist_lock, &stun_blacklist); #endif - ast_config_destroy(cfg); - } + + ast_config_destroy(cfg); + if (rtpstart >= rtpend) { ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n"); rtpstart = DEFAULT_RTP_START; From 7901225261653b5f883abdafaeb6ab47eb685a3e Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Fri, 7 Apr 2017 15:58:23 +0200 Subject: [PATCH 1195/1578] strings.h: Avoid overflows in the string hash functions On 2's compliment machines abs(INT_MIN) behavior is undefined and results in a negative value still being returnd. This results in negative hash codes that can result in crashes. ASTERISK-26528 #close Change-Id: Idff550145ca2133792a61a2e212b4a3e82c6517b --- include/asterisk/strings.h | 44 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index eb5b4e43c25..1200eb983c1 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -26,6 +26,7 @@ /* #define DEBUG_OPAQUE */ #include +#include #include "asterisk/utils.h" #include "asterisk/threadstorage.h" @@ -1173,6 +1174,19 @@ char *ast_tech_to_upper(char *dev_str), } ) +/*! + * \brief Restrict hash value range + * + * \details + * Hash values used all over asterisk are expected to be non-negative + * (signed) int values. This function restricts an unsigned int hash + * value to the positive half of the (signed) int values. + */ +static force_inline int attribute_pure ast_str_hash_restrict(unsigned int hash) +{ + return (int) (hash & (unsigned int) INT_MAX); +} + /*! * \brief Compute a hash value on a string * @@ -1183,20 +1197,21 @@ char *ast_tech_to_upper(char *dev_str), */ static force_inline int attribute_pure ast_str_hash(const char *str) { - int hash = 5381; + unsigned int hash = 5381; - while (*str) - hash = hash * 33 ^ *str++; + while (*str) { + hash = hash * 33 ^ (unsigned char) *str++; + } - return abs(hash); + return ast_str_hash_restrict(hash); } /*! * \brief Compute a hash value on a string * * \param[in] str The string to add to the hash - * \param[in] hash The hash value to add to - * + * \param[in] seed The hash value to start with + * * \details * This version of the function is for when you need to compute a * string hash of more than one string. @@ -1206,12 +1221,15 @@ static force_inline int attribute_pure ast_str_hash(const char *str) * * \sa http://www.cse.yorku.ca/~oz/hash.html */ -static force_inline int ast_str_hash_add(const char *str, int hash) +static force_inline int ast_str_hash_add(const char *str, int seed) { - while (*str) - hash = hash * 33 ^ *str++; + unsigned int hash = (unsigned int) seed; + + while (*str) { + hash = hash * 33 ^ (unsigned char) *str++; + } - return abs(hash); + return ast_str_hash_restrict(hash); } /*! @@ -1223,13 +1241,13 @@ static force_inline int ast_str_hash_add(const char *str, int hash) */ static force_inline int attribute_pure ast_str_case_hash(const char *str) { - int hash = 5381; + unsigned int hash = 5381; while (*str) { - hash = hash * 33 ^ tolower(*str++); + hash = hash * 33 ^ (unsigned char) tolower(*str++); } - return abs(hash); + return ast_str_hash_restrict(hash); } /*! From 7819f95791fe0ca0e0cdc417e2687a5900444053 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Wed, 5 Apr 2017 13:41:29 +0200 Subject: [PATCH 1196/1578] bridging: Ensure successful T.38 negotation When a T.38 happens immediatly after call establishment, the control frame can be lost because the other leg is not yet in the bridge. This patch detects this case an makes sure T.38 negotation happens when the 2nd leg is being made compatible with the negotating first leg ASTERISK-26923 #close Change-Id: If334125ee61ed63550d242fc9efe7987e37e1d94 --- bridges/bridge_simple.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index 35544f84fac..158c443537a 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -56,6 +56,19 @@ static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chann return 0; } + /* Request resend of T.38 negotiation if in progress and the other leg not yet T.38 + */ + if (ast_channel_get_t38_state(c0) == T38_STATE_NEGOTIATING && ast_channel_get_t38_state(c1) == T38_STATE_UNKNOWN) { + struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, }; + ast_debug(3, "Sending T.38 param renegotiation to first channel %s.\n", ast_channel_name(c0)); + ast_indicate_data(c0, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); + } + if (ast_channel_get_t38_state(c1) == T38_STATE_NEGOTIATING && ast_channel_get_t38_state(c0) == T38_STATE_UNKNOWN) { + struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, }; + ast_debug(3, "Sending T.38 param renegotiation to second channel %s.\n", ast_channel_name(c1)); + ast_indicate_data(c1, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); + } + return ast_channel_make_compatible(c0, c1); } From 747beb1ed159f89a3b58742e4257740b3d6d6bba Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 11 Apr 2017 10:07:39 -0600 Subject: [PATCH 1197/1578] modules: change module LOAD_FAILUREs to LOAD_DECLINES In all non-pbx modules, AST_MODULE_LOAD_FAILURE has been changed to AST_MODULE_LOAD_DECLINE. This prevents asterisk from exiting if a module can't be loaded. If the user wishes to retain the FAILURE behavior for a specific module, they can use the "require" or "preload-require" keyword in modules.conf. A new API was added to logger: ast_is_logger_initialized(). This allows asterisk.c/check_init() to print to the error log once the logger subsystem is ready instead of just to stdout. If something does fail before the logger is initialized, we now print to stderr instead of stdout. Change-Id: I5f4b50623d9b5a6cb7c5624a8c5c1274c13b2b25 --- addons/cdr_mysql.c | 43 ++++++++++---- addons/chan_mobile.c | 11 +++- apps/app_adsiprog.c | 2 +- apps/app_agent_pool.c | 5 +- apps/app_alarmreceiver.c | 2 +- apps/app_authenticate.c | 2 +- apps/app_cdr.c | 5 +- apps/app_confbridge.c | 6 +- apps/app_dahdiras.c | 2 +- apps/app_forkcdr.c | 6 +- apps/app_queue.c | 2 +- apps/app_voicemail.c | 2 +- apps/app_zapateller.c | 2 +- cdr/cdr_custom.c | 4 +- cel/cel_custom.c | 7 ++- cel/cel_odbc.c | 7 ++- channels/chan_alsa.c | 46 ++++++++------- channels/chan_dahdi.c | 12 ++-- channels/chan_iax2.c | 33 +++++++---- channels/chan_mgcp.c | 10 ++-- channels/chan_motif.c | 2 +- channels/chan_nbs.c | 4 +- channels/chan_oss.c | 57 +++++++++---------- channels/chan_phone.c | 6 +- channels/chan_pjsip.c | 2 +- channels/chan_sip.c | 20 +++---- channels/chan_skinny.c | 6 +- channels/chan_unistim.c | 2 +- codecs/codec_a_mu.c | 2 +- codecs/codec_adpcm.c | 2 +- codecs/codec_alaw.c | 2 +- codecs/codec_g722.c | 2 +- codecs/codec_g726.c | 2 +- codecs/codec_gsm.c | 2 +- codecs/codec_ilbc.c | 2 +- codecs/codec_lpc10.c | 2 +- codecs/codec_resample.c | 4 +- codecs/codec_ulaw.c | 2 +- formats/format_g723.c | 2 +- formats/format_g726.c | 23 ++++---- formats/format_g729.c | 2 +- formats/format_gsm.c | 2 +- formats/format_h263.c | 2 +- formats/format_h264.c | 2 +- formats/format_ilbc.c | 2 +- formats/format_jpeg.c | 2 +- formats/format_ogg_vorbis.c | 2 +- formats/format_pcm.c | 22 +++---- formats/format_sln.c | 29 +++++----- formats/format_vox.c | 2 +- formats/format_wav.c | 18 +++--- formats/format_wav_gsm.c | 2 +- funcs/func_cdr.c | 5 +- funcs/func_holdintercept.c | 2 +- funcs/func_talkdetect.c | 2 +- include/asterisk/logger.h | 7 +++ main/asterisk.c | 6 +- main/loader.c | 1 + main/logger.c | 5 ++ res/res_ari.c | 51 +++++++++-------- res/res_ari_events.c | 29 ++++++---- res/res_ari_model.c | 2 +- res/res_calendar.c | 6 +- res/res_chan_stats.c | 23 ++++---- res/res_config_sqlite.c | 16 +++--- res/res_config_sqlite3.c | 6 +- res/res_endpoint_stats.c | 2 +- res/res_hep_rtcp.c | 2 +- res/res_http_websocket.c | 2 +- res/res_limit.c | 2 +- res/res_pjsip/config_transport.c | 2 +- res/res_pjsip_nat.c | 4 +- res/res_pjsip_one_touch_record_info.c | 2 +- res/res_pjsip_outbound_publish.c | 2 +- res/res_pjsip_outbound_registration.c | 8 +-- res/res_pjsip_pubsub.c | 12 ++-- res/res_pjsip_sdp_rtp.c | 2 +- res/res_pjsip_send_to_voicemail.c | 2 +- res/res_pjsip_t38.c | 2 +- res/res_smdi.c | 4 +- res/res_stasis.c | 4 +- res/res_stasis_device_state.c | 5 +- res/res_stasis_playback.c | 5 +- res/res_stasis_recording.c | 5 +- res/res_stasis_test.c | 2 +- res/res_statsd.c | 3 +- .../res_ari_resource.c.mustache | 36 ++++++------ tests/test_bucket.c | 2 +- tests/test_channel_feature_hooks.c | 2 +- 89 files changed, 403 insertions(+), 312 deletions(-) diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c index 0878950e112..f8f4192acde 100644 --- a/addons/cdr_mysql.c +++ b/addons/cdr_mysql.c @@ -351,9 +351,20 @@ static int mysql_log(struct ast_cdr *cdr) return 0; } +static void free_strings(void) +{ + struct unload_string *us; + + AST_LIST_LOCK(&unload_strings); + while ((us = AST_LIST_REMOVE_HEAD(&unload_strings, entry))) { + ast_free(us->str); + ast_free(us); + } + AST_LIST_UNLOCK(&unload_strings); +} + static int my_unload_module(int reload) { - struct unload_string *us; struct column *entry; ast_cli_unregister_multiple(cdr_mysql_status_cli, sizeof(cdr_mysql_status_cli) / sizeof(struct ast_cli_entry)); @@ -364,12 +375,7 @@ static int my_unload_module(int reload) records = 0; } - AST_LIST_LOCK(&unload_strings); - while ((us = AST_LIST_REMOVE_HEAD(&unload_strings, entry))) { - ast_free(us->str); - ast_free(us); - } - AST_LIST_UNLOCK(&unload_strings); + free_strings(); if (!reload) { AST_RWLIST_WRLOCK(&columns); @@ -505,13 +511,16 @@ static int my_load_module(int reload) } else { calldate_compat = 0; } + ast_free(compat); if (res < 0) { if (reload) { AST_RWLIST_UNLOCK(&columns); } ast_config_destroy(cfg); - return AST_MODULE_LOAD_FAILURE; + free_strings(); + + return AST_MODULE_LOAD_DECLINE; } /* Check for any aliases */ @@ -582,7 +591,9 @@ static int my_load_module(int reload) connected = 0; AST_RWLIST_UNLOCK(&columns); ast_config_destroy(cfg); - return AST_MODULE_LOAD_FAILURE; + free_strings(); + + return AST_MODULE_LOAD_DECLINE; } if (!(result = mysql_store_result(&mysql))) { @@ -591,7 +602,9 @@ static int my_load_module(int reload) connected = 0; AST_RWLIST_UNLOCK(&columns); ast_config_destroy(cfg); - return AST_MODULE_LOAD_FAILURE; + free_strings(); + + return AST_MODULE_LOAD_DECLINE; } while ((row = mysql_fetch_row(result))) { @@ -657,7 +670,8 @@ static int my_load_module(int reload) AST_RWLIST_UNLOCK(&columns); ast_config_destroy(cfg); if (res < 0) { - return AST_MODULE_LOAD_FAILURE; + my_unload_module(0); + return AST_MODULE_LOAD_DECLINE; } if (!reload) { @@ -671,7 +685,12 @@ static int my_load_module(int reload) res = ast_cli_register_multiple(cdr_mysql_status_cli, sizeof(cdr_mysql_status_cli) / sizeof(struct ast_cli_entry)); } - return res; + if (res) { + my_unload_module(0); + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; } static int load_module(void) diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c index bd39bee6431..8f04af75302 100644 --- a/addons/chan_mobile.c +++ b/addons/chan_mobile.c @@ -4704,9 +4704,13 @@ static int load_module(void) ast_format_cap_append(mbl_tech.capabilities, DEVICE_FRAME_FORMAT, 0); /* Check if we have Bluetooth, no point loading otherwise... */ dev_id = hci_get_route(NULL); + s = hci_open_dev(dev_id); if (dev_id < 0 || s < 0) { ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n"); + ao2_ref(mbl_tech.capabilities, -1); + mbl_tech.capabilities = NULL; + hci_close_dev(s); return AST_MODULE_LOAD_DECLINE; } @@ -4714,6 +4718,8 @@ static int load_module(void) if (mbl_load_config()) { ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG); + ao2_ref(mbl_tech.capabilities, -1); + mbl_tech.capabilities = NULL; return AST_MODULE_LOAD_DECLINE; } @@ -4738,10 +4744,9 @@ static int load_module(void) return AST_MODULE_LOAD_SUCCESS; e_cleanup: - if (sdp_session) - sdp_close(sdp_session); + unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bluetooth Mobile Device Channel Driver", diff --git a/apps/app_adsiprog.c b/apps/app_adsiprog.c index 9d73702f6a0..6d485d6fb7a 100644 --- a/apps/app_adsiprog.c +++ b/apps/app_adsiprog.c @@ -1605,7 +1605,7 @@ static int unload_module(void) static int load_module(void) { if (ast_register_application_xml(app, adsi_exec)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c index 4563b58a09a..2e0c8e88027 100644 --- a/apps/app_agent_pool.c +++ b/apps/app_agent_pool.c @@ -2653,7 +2653,7 @@ static int load_module(void) agents = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, agent_pvt_sort_cmp, agent_pvt_cmp); if (!agents) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Init agent holding bridge v_table. */ @@ -2677,8 +2677,9 @@ static int load_module(void) res |= ast_register_application_xml(app_agent_request, agent_request_exec); if (res) { + ast_log(LOG_ERROR, "Unable to register application. Not loading module.\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (load_config()) { diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c index 2169617acb3..07885d2bf19 100644 --- a/apps/app_alarmreceiver.c +++ b/apps/app_alarmreceiver.c @@ -975,7 +975,7 @@ static int load_module(void) { if (load_config(0)) { if (ast_register_application_xml(app, alarmreceiver_exec)) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_authenticate.c b/apps/app_authenticate.c index f58ed362619..e0ad4a08911 100644 --- a/apps/app_authenticate.c +++ b/apps/app_authenticate.c @@ -270,7 +270,7 @@ static int unload_module(void) static int load_module(void) { if (ast_register_application_xml(app, auth_exec)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_cdr.c b/apps/app_cdr.c index 17dea431db2..1500c89f6c2 100644 --- a/apps/app_cdr.c +++ b/apps/app_cdr.c @@ -249,7 +249,7 @@ static int load_module(void) int res = 0; if (!router) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } res |= STASIS_MESSAGE_TYPE_INIT(appcdr_message_type); @@ -259,7 +259,8 @@ static int load_module(void) appcdr_callback, NULL); if (res) { - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 5ec20ddb993..a9f917b9a97 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -3955,7 +3955,7 @@ static int load_module(void) if (register_channel_tech(conf_record_get_tech()) || register_channel_tech(conf_announce_get_tech())) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Create a container to hold the conference bridges */ @@ -3963,7 +3963,7 @@ static int load_module(void) conference_bridge_hash_cb, conference_bridge_cmp_cb); if (!conference_bridges) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Setup manager stasis subscriptions */ @@ -3988,7 +3988,7 @@ static int load_module(void) res |= ast_manager_register_xml("ConfbridgeSetSingleVideoSrc", EVENT_FLAG_CALL, action_confbridgesetsinglevideosrc); if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/apps/app_dahdiras.c b/apps/app_dahdiras.c index 6eaa1bd2236..10c2962c690 100644 --- a/apps/app_dahdiras.c +++ b/apps/app_dahdiras.c @@ -223,7 +223,7 @@ static int unload_module(void) static int load_module(void) { - return ((ast_register_application_xml(app, dahdiras_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); + return ((ast_register_application_xml(app, dahdiras_exec)) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS); } AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server"); diff --git a/apps/app_forkcdr.c b/apps/app_forkcdr.c index acd8982ef4f..5946c5009b1 100644 --- a/apps/app_forkcdr.c +++ b/apps/app_forkcdr.c @@ -199,7 +199,7 @@ static int load_module(void) int res = 0; if (!router) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } res |= STASIS_MESSAGE_TYPE_INIT(forkcdr_message_type); @@ -208,7 +208,9 @@ static int load_module(void) forkcdr_callback, NULL); if (res) { - return AST_MODULE_LOAD_FAILURE; + unload_module(); + + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_queue.c b/apps/app_queue.c index ae2d645e945..2389f0b1314 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -8892,7 +8892,7 @@ static int reload_queue_rules(int reload) if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { AST_LIST_UNLOCK(&rule_lists); ast_config_destroy(cfg); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } else { ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index aebaafaf362..de826704a76 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -14974,7 +14974,7 @@ static int load_module(void) umask(my_umask); if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* compute the location of the voicemail spool directory */ diff --git a/apps/app_zapateller.c b/apps/app_zapateller.c index e876a70a8d7..f62f7bb5029 100644 --- a/apps/app_zapateller.c +++ b/apps/app_zapateller.c @@ -132,7 +132,7 @@ static int unload_module(void) static int load_module(void) { - return ((ast_register_application_xml(app, zapateller_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); + return ((ast_register_application_xml(app, zapateller_exec)) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS); } AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Block Telemarketers with Special Information Tone"); diff --git a/cdr/cdr_custom.c b/cdr/cdr_custom.c index 7d8b9d82ec9..fec20eaa8d2 100644 --- a/cdr/cdr_custom.c +++ b/cdr/cdr_custom.c @@ -203,7 +203,7 @@ static enum ast_module_load_result load_module(void) { if (AST_RWLIST_WRLOCK(&sinks)) { ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } load_config(); @@ -216,7 +216,7 @@ static int reload(void) { if (AST_RWLIST_WRLOCK(&sinks)) { ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } free_config(); diff --git a/cel/cel_custom.c b/cel/cel_custom.c index d1655413f3a..d05a1260c3c 100644 --- a/cel/cel_custom.c +++ b/cel/cel_custom.c @@ -191,14 +191,15 @@ static enum ast_module_load_result load_module(void) { if (AST_RWLIST_WRLOCK(&sinks)) { ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } load_config(); AST_RWLIST_UNLOCK(&sinks); if (ast_cel_backend_register(CUSTOM_BACKEND_NAME, custom_log)) { - return AST_MODULE_LOAD_FAILURE; + free_config(); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } @@ -207,7 +208,7 @@ static int reload(void) { if (AST_RWLIST_WRLOCK(&sinks)) { ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } free_config(); diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c index 2ab511418d0..a0cc6e33aaa 100644 --- a/cel/cel_odbc.c +++ b/cel/cel_odbc.c @@ -801,13 +801,14 @@ static int load_module(void) if (AST_RWLIST_WRLOCK(&odbc_tables)) { ast_log(LOG_ERROR, "Unable to lock column list. Load failed.\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } load_config(); AST_RWLIST_UNLOCK(&odbc_tables); if (ast_cel_backend_register(ODBC_BACKEND_NAME, odbc_log)) { ast_log(LOG_ERROR, "Unable to subscribe to CEL events\n"); - return AST_MODULE_LOAD_FAILURE; + free_config(); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } @@ -816,7 +817,7 @@ static int reload(void) { if (AST_RWLIST_WRLOCK(&odbc_tables)) { ast_log(LOG_ERROR, "Unable to lock column list. Reload failed.\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } free_config(); diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index c50b5408e35..c53c1a3449d 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -924,6 +924,26 @@ static struct ast_cli_entry cli_alsa[] = { AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"), }; +static int unload_module(void) +{ + ast_channel_unregister(&alsa_tech); + ast_cli_unregister_multiple(cli_alsa, ARRAY_LEN(cli_alsa)); + + if (alsa.icard) + snd_pcm_close(alsa.icard); + if (alsa.ocard) + snd_pcm_close(alsa.ocard); + if (alsa.owner) + ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD); + if (alsa.owner) + return -1; + + ao2_cleanup(alsa_tech.capabilities); + alsa_tech.capabilities = NULL; + + return 0; +} + /*! * \brief Load the module * @@ -994,12 +1014,16 @@ static int load_module(void) if (soundcard_init() < 0) { ast_verb(2, "No sound card detected -- console channel will be unavailable\n"); ast_verb(2, "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n"); + unload_module(); + return AST_MODULE_LOAD_DECLINE; } if (ast_channel_register(&alsa_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n"); - return AST_MODULE_LOAD_FAILURE; + unload_module(); + + return AST_MODULE_LOAD_DECLINE; } ast_cli_register_multiple(cli_alsa, ARRAY_LEN(cli_alsa)); @@ -1007,26 +1031,6 @@ static int load_module(void) return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) -{ - ast_channel_unregister(&alsa_tech); - ast_cli_unregister_multiple(cli_alsa, ARRAY_LEN(cli_alsa)); - - if (alsa.icard) - snd_pcm_close(alsa.icard); - if (alsa.ocard) - snd_pcm_close(alsa.ocard); - if (alsa.owner) - ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD); - if (alsa.owner) - return -1; - - ao2_cleanup(alsa_tech.capabilities); - alsa_tech.capabilities = NULL; - - return 0; -} - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ALSA Console Channel Driver", .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 97c80c83e30..72fbe6e0c7c 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -19530,11 +19530,11 @@ static int load_module(void) #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */ if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(dahdi_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_format_cap_append(dahdi_tech.capabilities, ast_format_slin, 0); ast_format_cap_append(dahdi_tech.capabilities, ast_format_ulaw, 0); @@ -19542,7 +19542,7 @@ static int load_module(void) if (dahdi_native_load(&dahdi_tech)) { ao2_ref(dahdi_tech.capabilities, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } #ifdef HAVE_PRI @@ -19560,7 +19560,7 @@ static int load_module(void) if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks) || ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks)) { __unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } #endif /* defined(HAVE_PRI_CCSS) */ if (sig_pri_load( @@ -19571,7 +19571,7 @@ static int load_module(void) #endif /* defined(HAVE_PRI_CCSS) */ )) { __unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } #endif #if defined(HAVE_SS7) @@ -19594,7 +19594,7 @@ static int load_module(void) if (ast_channel_register(&dahdi_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n"); __unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } #ifdef HAVE_PRI ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli)); diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 38dc5c00e59..d15b55d725f 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -14886,7 +14886,7 @@ static int load_objects(void) if (calltoken_ignores) { ao2_ref(calltoken_ignores, -1); } - return AST_MODULE_LOAD_FAILURE; + return -1; } @@ -15091,12 +15091,14 @@ static int load_module(void) struct iax2_registry *reg = NULL; if (!(iax2_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_format_cap_append_by_type(iax2_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); if (load_objects()) { - return AST_MODULE_LOAD_FAILURE; + ao2_ref(iax2_tech.capabilities, -1); + iax2_tech.capabilities = NULL; + return AST_MODULE_LOAD_DECLINE; } memset(iaxs, 0, sizeof(iaxs)); @@ -15107,28 +15109,36 @@ static int load_module(void) if (!(sched = ast_sched_context_create())) { ast_log(LOG_ERROR, "Failed to create scheduler thread\n"); - return AST_MODULE_LOAD_FAILURE; + ao2_ref(iax2_tech.capabilities, -1); + iax2_tech.capabilities = NULL; + return AST_MODULE_LOAD_DECLINE; } if (ast_sched_start_thread(sched)) { ast_sched_context_destroy(sched); + ao2_ref(iax2_tech.capabilities, -1); + iax2_tech.capabilities = NULL; sched = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(io = io_context_create())) { ast_log(LOG_ERROR, "Failed to create I/O context\n"); ast_sched_context_destroy(sched); + ao2_ref(iax2_tech.capabilities, -1); + iax2_tech.capabilities = NULL; sched = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(netsock = ast_netsock_list_alloc())) { ast_log(LOG_ERROR, "Failed to create netsock list\n"); io_context_destroy(io); ast_sched_context_destroy(sched); + ao2_ref(iax2_tech.capabilities, -1); + iax2_tech.capabilities = NULL; sched = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_netsock_init(netsock); @@ -15137,8 +15147,10 @@ static int load_module(void) ast_log(LOG_ERROR, "Could not allocate outsock list.\n"); io_context_destroy(io); ast_sched_context_destroy(sched); + ao2_ref(iax2_tech.capabilities, -1); + iax2_tech.capabilities = NULL; sched = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_netsock_init(outsock); @@ -15157,6 +15169,7 @@ static int load_module(void) ast_timer_close(timer); timer = NULL; } + __unload_module(); return AST_MODULE_LOAD_DECLINE; } @@ -15182,7 +15195,7 @@ static int load_module(void) if (ast_channel_register(&iax2_tech)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", "IAX2"); __unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (ast_register_switch(&iax2_switch)) { @@ -15192,7 +15205,7 @@ static int load_module(void) if (start_network_thread()) { ast_log(LOG_ERROR, "Unable to start network thread\n"); __unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } else { ast_verb(2, "IAX Ready and Listening\n"); } diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index af79e218e9c..6cac4bc8acb 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -4860,11 +4860,11 @@ static int reload_config(int reload) static int load_module(void) { if (!(global_capability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(mgcp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ao2_ref(global_capability, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_format_cap_append(global_capability, ast_format_ulaw, 0); ast_format_cap_append(mgcp_tech.capabilities, ast_format_ulaw, 0); @@ -4873,7 +4873,7 @@ static int load_module(void) ast_log(LOG_WARNING, "Unable to create schedule context\n"); ao2_ref(global_capability, -1); ao2_ref(mgcp_tech.capabilities, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(io = io_context_create())) { @@ -4881,7 +4881,7 @@ static int load_module(void) ast_sched_context_destroy(sched); ao2_ref(global_capability, -1); ao2_ref(mgcp_tech.capabilities, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (reload_config(0)) { @@ -4897,7 +4897,7 @@ static int load_module(void) ast_sched_context_destroy(sched); ao2_ref(global_capability, -1); ao2_ref(mgcp_tech.capabilities, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_rtp_glue_register(&mgcp_rtp_glue); diff --git a/channels/chan_motif.c b/channels/chan_motif.c index 5828a11559f..7d696e87dc6 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -2788,7 +2788,7 @@ static int load_module(void) ao2_cleanup(jingle_tech.capabilities); jingle_tech.capabilities = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /*! \brief Reload module */ diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c index 61e5398c30e..a12470cee80 100644 --- a/channels/chan_nbs.c +++ b/channels/chan_nbs.c @@ -257,12 +257,14 @@ static int unload_module(void) static int load_module(void) { if (!(nbs_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_format_cap_append(nbs_tech.capabilities, ast_format_slin, 0); /* Make sure we can register our channel type */ if (ast_channel_register(&nbs_tech)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); + ao2_ref(nbs_tech.capabilities, -1); + nbs_tech.capabilities = NULL; return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 3e1e38d37a9..ec112de3883 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -1435,6 +1435,31 @@ static struct chan_oss_pvt *store_config(struct ast_config *cfg, char *ctg) #endif } +static int unload_module(void) +{ + struct chan_oss_pvt *o, *next; + + ast_channel_unregister(&oss_tech); + ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss)); + + o = oss_default.next; + while (o) { + close(o->sounddev); + if (o->owner) + ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD); + if (o->owner) + return -1; + next = o->next; + ast_free(o->name); + ast_free(o); + o = next; + } + ao2_cleanup(oss_tech.capabilities); + oss_tech.capabilities = NULL; + + return 0; +} + /*! * \brief Load the module * @@ -1472,12 +1497,12 @@ static int load_module(void) if (find_desc(oss_active) == NULL) { ast_log(LOG_NOTICE, "Device %s not found\n", oss_active); /* XXX we could default to 'dsp' perhaps ? */ - /* XXX should cleanup allocated memory etc. */ - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } if (!(oss_tech.capabilities = ast_format_cap_alloc(0))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_format_cap_append(oss_tech.capabilities, ast_format_slin, 0); @@ -1494,31 +1519,5 @@ static int load_module(void) return AST_MODULE_LOAD_SUCCESS; } - -static int unload_module(void) -{ - struct chan_oss_pvt *o, *next; - - ast_channel_unregister(&oss_tech); - ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss)); - - o = oss_default.next; - while (o) { - close(o->sounddev); - if (o->owner) - ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD); - if (o->owner) - return -1; - next = o->next; - ast_free(o->name); - ast_free(o); - o = next; - } - ao2_cleanup(oss_tech.capabilities); - oss_tech.capabilities = NULL; - - return 0; -} - AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "OSS Console Channel Driver"); diff --git a/channels/chan_phone.c b/channels/chan_phone.c index aa10a56202d..76891ac984c 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -1416,7 +1416,7 @@ static int load_module(void) if (ast_mutex_lock(&iflock)) { /* It's a little silly to lock it, but we mind as well just to be sure */ ast_log(LOG_ERROR, "Unable to lock interface list???\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } v = ast_variable_browse(cfg, "interfaces"); while(v) { @@ -1432,7 +1432,7 @@ static int load_module(void) ast_config_destroy(cfg); ast_mutex_unlock(&iflock); __unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } } else if (!strcasecmp(v->name, "silencesupression")) { silencesupression = ast_true(v->value); @@ -1508,7 +1508,7 @@ static int load_module(void) ast_log(LOG_ERROR, "Unable to register channel class 'Phone'\n"); ast_config_destroy(cfg); __unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_config_destroy(cfg); /* And start the monitor for the first time */ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 46c74adf791..a92816431bb 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2749,7 +2749,7 @@ static int load_module(void) ast_channel_unregister(&chan_pjsip_tech); ast_rtp_glue_unregister(&chan_pjsip_rtp_glue); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /*! \brief Unload the PJSIP channel from Asterisk */ diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 5419a1dd8b4..affe937e803 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -35287,17 +35287,17 @@ static int load_module(void) if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(sip_tech.capabilities = ast_format_cap_alloc(0))) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (ast_sip_api_provider_register(&chan_sip_api_provider)) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* the fact that ao2_containers can't resize automatically is a major worry! */ @@ -35312,12 +35312,12 @@ static int load_module(void) || !threadt) { ast_log(LOG_ERROR, "Unable to create primary SIP container(s)\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(sip_cfg.caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_format_cap_append_by_type(sip_tech.capabilities, AST_MEDIA_TYPE_AUDIO); @@ -35328,13 +35328,13 @@ static int load_module(void) if (!(sched = ast_sched_context_create())) { ast_log(LOG_ERROR, "Unable to create scheduler context\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(io = io_context_create())) { ast_log(LOG_ERROR, "Unable to create I/O context\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } sip_reloadreason = CHANNEL_MODULE_LOAD; @@ -35349,7 +35349,7 @@ static int load_module(void) if (!(bogus_peer = temp_peer("(bogus_peer)"))) { ast_log(LOG_ERROR, "Unable to create bogus_peer for authentication\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Make sure the auth will always fail. */ ast_string_field_set(bogus_peer, md5secret, BOGUS_PEER_MD5SECRET); @@ -35366,14 +35366,14 @@ static int load_module(void) if (ast_msg_tech_register(&sip_msg_tech)) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Make sure we can register our sip channel type */ if (ast_channel_register(&sip_tech)) { ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } #ifdef TEST_FRAMEWORK diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index d1c2b927a61..a0530007b18 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -8698,7 +8698,7 @@ static int load_module(void) ao2_ref(skinny_tech.capabilities, -1); ao2_ref(default_cap, -1); ast_log(LOG_WARNING, "Unable to create schedule context\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Make sure we can register our skinny channel type */ @@ -8706,7 +8706,7 @@ static int load_module(void) ao2_ref(default_cap, -1); ao2_ref(skinny_tech.capabilities, -1); ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n"); - return -1; + return AST_MODULE_LOAD_DECLINE; } ast_rtp_glue_register(&skinny_rtp_glue); @@ -8723,7 +8723,7 @@ static int load_module(void) ast_channel_unregister(&skinny_tech); ao2_ref(default_cap, -1); ao2_ref(skinny_tech.capabilities, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index f82522111e2..b820cf51e9b 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -7126,7 +7126,7 @@ int load_module(void) global_cap = NULL; ao2_cleanup(unistim_tech.capabilities); unistim_tech.capabilities = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } static int unload_module(void) diff --git a/codecs/codec_a_mu.c b/codecs/codec_a_mu.c index ea8d01488c4..a2cce4ef78e 100644 --- a/codecs/codec_a_mu.c +++ b/codecs/codec_a_mu.c @@ -141,7 +141,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_adpcm.c b/codecs/codec_adpcm.c index 3076d264e2b..0b2f90f3985 100644 --- a/codecs/codec_adpcm.c +++ b/codecs/codec_adpcm.c @@ -346,7 +346,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_alaw.c b/codecs/codec_alaw.c index ba16936b551..ebaca74c551 100644 --- a/codecs/codec_alaw.c +++ b/codecs/codec_alaw.c @@ -130,7 +130,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_g722.c b/codecs/codec_g722.c index 9c868d3d9ba..48b5e4a27aa 100644 --- a/codecs/codec_g722.c +++ b/codecs/codec_g722.c @@ -241,7 +241,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_g726.c b/codecs/codec_g726.c index 4bf39b7cec0..3b76628d527 100644 --- a/codecs/codec_g726.c +++ b/codecs/codec_g726.c @@ -890,7 +890,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_gsm.c b/codecs/codec_gsm.c index 2ae42a6c0c5..296747ee3cb 100644 --- a/codecs/codec_gsm.c +++ b/codecs/codec_gsm.c @@ -239,7 +239,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_ilbc.c b/codecs/codec_ilbc.c index 16466a9c9d4..d691f706f3e 100644 --- a/codecs/codec_ilbc.c +++ b/codecs/codec_ilbc.c @@ -267,7 +267,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_lpc10.c b/codecs/codec_lpc10.c index 5f6ffff8716..00e30226748 100644 --- a/codecs/codec_lpc10.c +++ b/codecs/codec_lpc10.c @@ -272,7 +272,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_resample.c b/codecs/codec_resample.c index b54f5c92197..e0d530d8570 100644 --- a/codecs/codec_resample.c +++ b/codecs/codec_resample.c @@ -153,7 +153,7 @@ static int load_module(void) trans_size = ARRAY_LEN(codec_list) * (ARRAY_LEN(codec_list) - 1); if (!(translators = ast_calloc(1, sizeof(struct ast_translator) * trans_size))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } for (x = 0; x < ARRAY_LEN(codec_list); x++) { @@ -180,7 +180,7 @@ static int load_module(void) ast_unregister_translator won't fail.*/ if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_ulaw.c b/codecs/codec_ulaw.c index cf4e358da97..e0a4f6841fd 100644 --- a/codecs/codec_ulaw.c +++ b/codecs/codec_ulaw.c @@ -181,7 +181,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_g723.c b/formats/format_g723.c index 750bacaf153..04e03b6086f 100644 --- a/formats/format_g723.c +++ b/formats/format_g723.c @@ -142,7 +142,7 @@ static int load_module(void) g723_1_f.format = ast_format_g723; if (ast_format_def_register(&g723_1_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_g726.c b/formats/format_g726.c index f3b09f0351e..08e669e264f 100644 --- a/formats/format_g726.c +++ b/formats/format_g726.c @@ -221,29 +221,30 @@ static struct ast_format_def f[] = { { .desc_size = 0 } /* terminator */ }; -static int load_module(void) +static int unload_module(void) { int i; for (i = 0; f[i].desc_size ; i++) { - f[i].format = ast_format_g726; - if (ast_format_def_register(&f[i])) { /* errors are fatal */ - ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name); - return AST_MODULE_LOAD_FAILURE; - } + if (ast_format_def_unregister(f[i].name)) + ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f[i].name); } - return AST_MODULE_LOAD_SUCCESS; + return(0); } -static int unload_module(void) +static int load_module(void) { int i; for (i = 0; f[i].desc_size ; i++) { - if (ast_format_def_unregister(f[i].name)) - ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f[i].name); + f[i].format = ast_format_g726; + if (ast_format_def_register(&f[i])) { /* errors are fatal */ + ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name); + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } } - return(0); + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw G.726 (16/24/32/40kbps) data", diff --git a/formats/format_g729.c b/formats/format_g729.c index 6e0632c5351..49e58025f88 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -138,7 +138,7 @@ static int load_module(void) { g729_f.format = ast_format_g729; if (ast_format_def_register(&g729_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_gsm.c b/formats/format_gsm.c index 777d49a636f..a2b6d365616 100644 --- a/formats/format_gsm.c +++ b/formats/format_gsm.c @@ -183,7 +183,7 @@ static int load_module(void) { gsm_f.format = ast_format_gsm; if (ast_format_def_register(&gsm_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_h263.c b/formats/format_h263.c index 027f604f4ac..4cc3db54272 100644 --- a/formats/format_h263.c +++ b/formats/format_h263.c @@ -170,7 +170,7 @@ static int load_module(void) { h263_f.format = ast_format_h263; if (ast_format_def_register(&h263_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_h264.c b/formats/format_h264.c index 38f2734f3c1..60b0902111c 100644 --- a/formats/format_h264.c +++ b/formats/format_h264.c @@ -163,7 +163,7 @@ static int load_module(void) { h264_f.format = ast_format_h264; if (ast_format_def_register(&h264_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c index b556d6cc854..eab465d8871 100644 --- a/formats/format_ilbc.c +++ b/formats/format_ilbc.c @@ -135,7 +135,7 @@ static int load_module(void) { ilbc_f.format = ast_format_ilbc; if (ast_format_def_register(&ilbc_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c index f69c547d360..798141d555e 100644 --- a/formats/format_jpeg.c +++ b/formats/format_jpeg.c @@ -96,7 +96,7 @@ static int load_module(void) { jpeg_format.format = ast_format_jpeg; if (ast_image_register(&jpeg_format)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c index 4c42181fcfb..d4212a169b4 100644 --- a/formats/format_ogg_vorbis.c +++ b/formats/format_ogg_vorbis.c @@ -423,7 +423,7 @@ static int load_module(void) { vorbis_f.format = ast_format_slin; if (ast_format_def_register(&vorbis_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_pcm.c b/formats/format_pcm.c index 0b1706e504a..fedc0632f2b 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -500,6 +500,14 @@ static struct ast_format_def au_f = { .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET, /* this many shorts */ }; +static int unload_module(void) +{ + return ast_format_def_unregister(pcm_f.name) + || ast_format_def_unregister(alaw_f.name) + || ast_format_def_unregister(au_f.name) + || ast_format_def_unregister(g722_f.name); +} + static int load_module(void) { int i; @@ -517,19 +525,13 @@ static int load_module(void) if ( ast_format_def_register(&pcm_f) || ast_format_def_register(&alaw_f) || ast_format_def_register(&au_f) - || ast_format_def_register(&g722_f) ) - return AST_MODULE_LOAD_FAILURE; + || ast_format_def_register(&g722_f) ) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) -{ - return ast_format_def_unregister(pcm_f.name) - || ast_format_def_unregister(alaw_f.name) - || ast_format_def_unregister(au_f.name) - || ast_format_def_unregister(g722_f.name); -} - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw/Sun uLaw/ALaw 8KHz (PCM,PCMA,AU), G.722 16Khz", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, diff --git a/formats/format_sln.c b/formats/format_sln.c index 32972d09d07..af3f691c81c 100644 --- a/formats/format_sln.c +++ b/formats/format_sln.c @@ -235,6 +235,19 @@ static struct ast_format_def *slin_list[] = { &slin192_f, }; +static int unload_module(void) +{ + int res = 0; + int i = 0; + + for (i = 0; i < ARRAY_LEN(slin_list); i++) { + if (ast_format_def_unregister(slin_list[i]->name)) { + res = -1; + } + } + return res; +} + static int load_module(void) { int i; @@ -251,26 +264,14 @@ static int load_module(void) for (i = 0; i < ARRAY_LEN(slin_list); i++) { if (ast_format_def_register(slin_list[i])) { - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } } return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) -{ - int res = 0; - int i = 0; - - for (i = 0; i < ARRAY_LEN(slin_list); i++) { - if (ast_format_def_unregister(slin_list[i]->name)) { - res |= AST_MODULE_LOAD_FAILURE; - } - } - return res; -} - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Raw Signed Linear Audio support (SLN) 8khz-192khz", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, diff --git a/formats/format_vox.c b/formats/format_vox.c index eb8ab0eadb1..5a70c34b140 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -137,7 +137,7 @@ static int load_module(void) { vox_f.format = ast_format_adpcm; if (ast_format_def_register(&vox_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/formats/format_wav.c b/formats/format_wav.c index a415140f9f3..049ead40ee0 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -536,22 +536,24 @@ static struct ast_format_def wav_f = { .desc_size = sizeof(struct wav_desc), }; +static int unload_module(void) +{ + return ast_format_def_unregister(wav_f.name) + || ast_format_def_unregister(wav16_f.name); +} + static int load_module(void) { wav_f.format = ast_format_slin; wav16_f.format = ast_format_slin16; if (ast_format_def_register(&wav_f) - || ast_format_def_register(&wav16_f)) - return AST_MODULE_LOAD_FAILURE; + || ast_format_def_register(&wav16_f)) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) -{ - return ast_format_def_unregister(wav_f.name) - || ast_format_def_unregister(wav16_f.name); -} - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c index 21a8508059f..eef06cef5b7 100644 --- a/formats/format_wav_gsm.c +++ b/formats/format_wav_gsm.c @@ -568,7 +568,7 @@ static int load_module(void) { wav49_f.format = ast_format_gsm; if (ast_format_def_register(&wav49_f)) - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; } diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 83942db4cd2..82ff488b047 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -649,7 +649,7 @@ static int load_module(void) int res = 0; if (!router) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } res |= STASIS_MESSAGE_TYPE_INIT(cdr_read_message_type); @@ -665,7 +665,8 @@ static int load_module(void) cdr_read_callback, NULL); if (res) { - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/funcs/func_holdintercept.c b/funcs/func_holdintercept.c index c2435463a0d..2a1cbb8c148 100644 --- a/funcs/func_holdintercept.c +++ b/funcs/func_holdintercept.c @@ -228,7 +228,7 @@ static int unload_module(void) /*! \internal \brief Load the module */ static int load_module(void) { - return ast_custom_function_register(&hold_intercept_function) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS; + return ast_custom_function_register(&hold_intercept_function) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hold interception dialplan function"); diff --git a/funcs/func_talkdetect.c b/funcs/func_talkdetect.c index 02963f20e4f..5c7f41ab398 100644 --- a/funcs/func_talkdetect.c +++ b/funcs/func_talkdetect.c @@ -397,7 +397,7 @@ static int load_module(void) res |= ast_custom_function_register(&talk_detect_function); - return res ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS; + return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Talk detection dialplan function"); diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index 9f9f671c06f..2f629dfbef5 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -500,6 +500,13 @@ int ast_verb_console_get(void); */ void ast_verb_console_set(int verb_level); +/*! + * \brief Test if logger is initialized + * + * \retval true if the logger is initialized + */ +int ast_is_logger_initialized(void); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/asterisk.c b/main/asterisk.c index 68859ab2fad..16313ea6853 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4354,7 +4354,11 @@ int main(int argc, char *argv[]) static inline void check_init(int init_result, const char *name) { if (init_result) { - printf("%s initialization failed.\n%s", name, term_quit()); + if (ast_is_logger_initialized()) { + ast_log(LOG_ERROR, "%s initialization failed. ASTERISK EXITING!\n%s", name, term_quit()); + } else { + fprintf(stderr, "%s initialization failed. ASTERISK EXITING!\n%s", name, term_quit()); + } ast_run_atexits(0); exit(init_result == -2 ? 2 : 1); } diff --git a/main/loader.c b/main/loader.c index 380fe1c92fa..d5500076b4e 100644 --- a/main/loader.c +++ b/main/loader.c @@ -1243,6 +1243,7 @@ static int load_resource_list(struct load_order *load_order, unsigned int global case AST_MODULE_LOAD_DECLINE: break; case AST_MODULE_LOAD_FAILURE: + ast_log(LOG_ERROR, "*** Failed to load module %s\n", mod->resource); res = -1; goto done; case AST_MODULE_LOAD_SKIP: diff --git a/main/logger.c b/main/logger.c index 146d9198555..8c8162d718d 100644 --- a/main/logger.c +++ b/main/logger.c @@ -1653,6 +1653,11 @@ static void logger_queue_init(void) } } +int ast_is_logger_initialized(void) +{ + return logger_initialized; +} + /*! * \brief Start the ast_queue_log() logger. * diff --git a/res/res_ari.c b/res/res_ari.c index 549d7835365..054d3bf3c59 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -1106,6 +1106,27 @@ static struct ast_http_uri http_uri = { .no_decode_uri = 1, }; +static int unload_module(void) +{ + ast_ari_cli_unregister(); + + if (is_enabled()) { + ast_debug(3, "Disabling ARI\n"); + ast_http_uri_unlink(&http_uri); + } + + ast_ari_config_destroy(); + + ao2_cleanup(root_handler); + root_handler = NULL; + ast_mutex_destroy(&root_handler_lock); + + ast_json_unref(oom_json); + oom_json = NULL; + + return 0; +} + static int load_module(void) { ast_mutex_init(&root_handler_lock); @@ -1115,7 +1136,7 @@ static int load_module(void) root_handler = root_handler_create(); } if (!root_handler) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* oom_json may have been built during a declined load */ @@ -1125,10 +1146,12 @@ static int load_module(void) } if (!oom_json) { /* Ironic */ - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } if (ast_ari_config_init() != 0) { + unload_module(); return AST_MODULE_LOAD_DECLINE; } @@ -1140,33 +1163,13 @@ static int load_module(void) } if (ast_ari_cli_register() != 0) { - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) -{ - ast_ari_cli_unregister(); - - if (is_enabled()) { - ast_debug(3, "Disabling ARI\n"); - ast_http_uri_unlink(&http_uri); - } - - ast_ari_config_destroy(); - - ao2_cleanup(root_handler); - root_handler = NULL; - ast_mutex_destroy(&root_handler_lock); - - ast_json_unref(oom_json); - oom_json = NULL; - - return 0; -} - static int reload_module(void) { char was_enabled = is_enabled(); diff --git a/res/res_ari_events.c b/res/res_ari_events.c index 8ccb8870c8c..8d8a303d1a8 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -417,6 +417,15 @@ static struct stasis_rest_handlers events = { .children = { &events_user, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&events); + ao2_cleanup(events.ws_server); + events.ws_server = NULL; + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; @@ -428,31 +437,27 @@ static int load_module(void) events.ws_server = ast_websocket_server_create(); if (!events.ws_server) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } protocol = ast_websocket_sub_protocol_alloc("ari"); if (!protocol) { ao2_ref(events.ws_server, -1); events.ws_server = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb; protocol->session_established = ast_ari_events_event_websocket_ws_established_cb; res |= ast_websocket_server_add_protocol2(events.ws_server, protocol); stasis_app_ref(); res |= ast_ari_add_handler(&events); - return res; -} -static int unload_module(void) -{ - ast_ari_remove_handler(&events); - ao2_cleanup(events.ws_server); - events.ws_server = NULL; - ast_ari_websocket_events_event_websocket_dtor(); - stasis_app_unref(); - return 0; + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - WebSocket resource", diff --git a/res/res_ari_model.c b/res/res_ari_model.c index dd8e1af388a..015b1e73f1d 100644 --- a/res/res_ari_model.c +++ b/res/res_ari_model.c @@ -190,7 +190,7 @@ static int load_module(void) REG_EXTENDED | REG_ICASE | REG_NOSUB); if (res != 0) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/res/res_calendar.c b/res/res_calendar.c index 92b73c1edc8..666b0e18407 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -1888,7 +1888,7 @@ static int load_module(void) { if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) { ast_log(LOG_ERROR, "Unable to allocate calendars container!\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (load_config(0)) { @@ -1902,7 +1902,9 @@ static int load_module(void) if (!(sched = ast_sched_context_create())) { ast_log(LOG_ERROR, "Unable to create sched context\n"); - return AST_MODULE_LOAD_FAILURE; + ast_config_destroy(calendar_config); + calendar_config = NULL; + return AST_MODULE_LOAD_DECLINE; } if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) { diff --git a/res/res_chan_stats.c b/res/res_chan_stats.c index 9a26db78c2c..061d0867eb3 100644 --- a/res/res_chan_stats.c +++ b/res/res_chan_stats.c @@ -148,13 +148,22 @@ static void default_route(void *data, struct stasis_subscription *sub, } } +static int unload_module(void) +{ + stasis_unsubscribe_and_join(sub); + sub = NULL; + stasis_message_router_unsubscribe_and_join(router); + router = NULL; + return 0; +} + static int load_module(void) { /* You can create a message router to route messages by type */ router = stasis_message_router_create( ast_channel_topic_all_cached()); if (!router) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } stasis_message_router_add(router, stasis_cache_update_type(), updates, NULL); @@ -163,20 +172,12 @@ static int load_module(void) /* Or a subscription to receive all of the messages from a topic */ sub = stasis_subscribe(ast_channel_topic_all(), statsmaker, NULL); if (!sub) { - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) -{ - stasis_unsubscribe_and_join(sub); - sub = NULL; - stasis_message_router_unsubscribe_and_join(router); - router = NULL; - return 0; -} - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Example of how to use Stasis", .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c index 96a10b43f95..0f9113188b7 100644 --- a/res/res_config_sqlite.c +++ b/res/res_config_sqlite.c @@ -1680,7 +1680,7 @@ static int load_module(void) ast_log(LOG_ERROR, "%s\n", S_OR(errormsg, sqlite_error_string(error))); sqlite_freemem(errormsg); unload_module(); - return 1; + return AST_MODULE_LOAD_DECLINE; } sqlite_freemem(errormsg); @@ -1700,7 +1700,7 @@ static int load_module(void) if (!query) { ast_log(LOG_ERROR, "Unable to allocate SQL query\n"); unload_module(); - return 1; + return AST_MODULE_LOAD_DECLINE; } ast_debug(1, "SQL query: %s\n", query); @@ -1719,7 +1719,7 @@ static int load_module(void) ast_log(LOG_ERROR, "%s\n", S_OR(errormsg, sqlite_error_string(error))); sqlite_freemem(errormsg); unload_module(); - return 1; + return AST_MODULE_LOAD_DECLINE; } sqlite_freemem(errormsg); @@ -1729,7 +1729,7 @@ static int load_module(void) if (!query) { ast_log(LOG_ERROR, "Unable to allocate SQL query\n"); unload_module(); - return 1; + return AST_MODULE_LOAD_DECLINE; } ast_debug(1, "SQL query: %s\n", query); @@ -1744,7 +1744,7 @@ static int load_module(void) ast_log(LOG_ERROR, "%s\n", S_OR(errormsg, sqlite_error_string(error))); sqlite_freemem(errormsg); unload_module(); - return 1; + return AST_MODULE_LOAD_DECLINE; } } sqlite_freemem(errormsg); @@ -1754,7 +1754,7 @@ static int load_module(void) if (error) { unload_module(); - return 1; + return AST_MODULE_LOAD_DECLINE; } cdr_registered = 1; @@ -1764,12 +1764,12 @@ static int load_module(void) if (error) { unload_module(); - return 1; + return AST_MODULE_LOAD_DECLINE; } cli_status_registered = 1; - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime SQLite configuration", diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index 087843a6805..0025548be3b 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -1359,18 +1359,18 @@ static int load_module(void) discover_sqlite3_caps(); if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (parse_config(0)) { ao2_ref(databases, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(ast_config_engine_register(&sqlite3_config_engine))) { ast_log(LOG_ERROR, "The config API must have changed, this shouldn't happen.\n"); ao2_ref(databases, -1); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/res/res_endpoint_stats.c b/res/res_endpoint_stats.c index 249cbea9bb8..1e3f104c212 100644 --- a/res/res_endpoint_stats.c +++ b/res/res_endpoint_stats.c @@ -118,7 +118,7 @@ static int load_module(void) router = stasis_message_router_create(ast_endpoint_topic_all_cached()); if (!router) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } stasis_message_router_add(router, stasis_cache_update_type(), cache_update_cb, NULL); diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 25b90c7a266..7191f466163 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -155,7 +155,7 @@ static int load_module(void) stasis_rtp_subscription = stasis_subscribe(ast_rtp_topic(), rtp_topic_handler, NULL); if (!stasis_rtp_subscription) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 799eb848fad..60332f591dc 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -1441,7 +1441,7 @@ static int load_module(void) { websocketuri.data = websocket_server_internal_create(); if (!websocketuri.data) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_http_uri_link(&websocketuri); websocket_add_protocol_internal("echo", websocket_echo_callback); diff --git a/res/res_limit.c b/res/res_limit.c index bff777d9909..a308c41218f 100644 --- a/res/res_limit.c +++ b/res/res_limit.c @@ -209,7 +209,7 @@ static int unload_module(void) static int load_module(void) { - return ast_cli_register(&cli_ulimit) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS; + return ast_cli_register(&cli_ulimit) ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Resource limits"); diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index d180296f420..62bc9d67db2 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -1348,7 +1348,7 @@ int ast_sip_initialize_sorcery_transport(void) transport_states = ao2_container_alloc(DEFAULT_STATE_BUCKETS, internal_state_hash, internal_state_cmp); if (!transport_states) { ast_log(LOG_ERROR, "Unable to allocate transport states container\n"); - return AST_MODULE_LOAD_FAILURE; + return -1; } ast_sorcery_apply_default(sorcery, "transport", "config", "pjsip.conf,criteria=type=transport"); diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c index a26180bc0b8..9205622d7ad 100644 --- a/res/res_pjsip_nat.c +++ b/res/res_pjsip_nat.c @@ -361,13 +361,13 @@ static int load_module(void) if (ast_sip_register_service(&nat_module)) { ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (ast_sip_session_register_supplement(&nat_supplement)) { ast_log(LOG_ERROR, "Could not register NAT session supplement for incoming and outgoing INVITE requests\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/res/res_pjsip_one_touch_record_info.c b/res/res_pjsip_one_touch_record_info.c index 2d53fd48ee0..ec5f9be3e7c 100644 --- a/res/res_pjsip_one_touch_record_info.c +++ b/res/res_pjsip_one_touch_record_info.c @@ -112,7 +112,7 @@ static int load_module(void) if (ast_sip_session_register_supplement(&info_supplement)) { ast_log(LOG_ERROR, "Unable to register One Touch Recording supplement\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index a19a9bb2441..c413cb0e13c 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -1631,7 +1631,7 @@ static int load_module(void) shutdown_group = ast_serializer_shutdown_group_alloc(); if (!shutdown_group) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_publish"); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 704239bd01a..8a840ff05eb 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -2082,7 +2082,7 @@ static int load_module(void) shutdown_group = ast_serializer_shutdown_group_alloc(); if (!shutdown_group) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Create outbound registration states container. */ @@ -2091,7 +2091,7 @@ static int load_module(void) if (!new_states) { ast_log(LOG_ERROR, "Unable to allocate registration states container\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ao2_global_obj_replace_unref(current_states, new_states); ao2_ref(new_states, -1); @@ -2135,7 +2135,7 @@ static int load_module(void) ®istration_observer)) { ast_log(LOG_ERROR, "Unable to register observers.\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } /* Register how this module identifies endpoints. */ @@ -2146,7 +2146,7 @@ static int load_module(void) if (!cli_formatter) { ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n"); unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } cli_formatter->name = "registration"; cli_formatter->print_header = cli_print_header; diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index f0467627ea5..a1f3f246257 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -5225,13 +5225,13 @@ static int load_module(void) if (!(sched = ast_sched_context_create())) { ast_log(LOG_ERROR, "Could not create scheduler for publication expiration\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (ast_sched_start_thread(sched)) { ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n"); ast_sched_context_destroy(sched); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &str_PUBLISH); @@ -5239,7 +5239,7 @@ static int load_module(void) if (ast_sip_register_service(&pubsub_module)) { ast_log(LOG_ERROR, "Could not register pubsub service\n"); ast_sched_context_destroy(sched); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_sorcery_apply_config(sorcery, "res_pjsip_pubsub"); @@ -5249,7 +5249,7 @@ static int load_module(void) ast_log(LOG_ERROR, "Could not register subscription persistence object support\n"); ast_sip_unregister_service(&pubsub_module); ast_sched_context_destroy(sched); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_sorcery_object_field_register(sorcery, "subscription_persistence", "packet", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct subscription_persistence, packet)); @@ -5277,7 +5277,7 @@ static int load_module(void) if (apply_list_configuration(sorcery)) { ast_sip_unregister_service(&pubsub_module); ast_sched_context_destroy(sched); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication"); @@ -5286,7 +5286,7 @@ static int load_module(void) ast_log(LOG_ERROR, "Could not register subscription persistence object support\n"); ast_sip_unregister_service(&pubsub_module); ast_sched_context_destroy(sched); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_sorcery_object_field_register(sorcery, "inbound-publication", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register_custom(sorcery, "inbound-publication", "endpoint", "", diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 7c861dac916..dfa6957c700 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1650,7 +1650,7 @@ static int load_module(void) end: unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP SDP RTP/AVP stream handler", diff --git a/res/res_pjsip_send_to_voicemail.c b/res/res_pjsip_send_to_voicemail.c index bd70bcfd70f..1cd28ceac8f 100644 --- a/res/res_pjsip_send_to_voicemail.c +++ b/res/res_pjsip_send_to_voicemail.c @@ -219,7 +219,7 @@ static int load_module(void) if (ast_sip_session_register_supplement(&refer_supplement)) { ast_log(LOG_ERROR, "Unable to register Send to Voicemail supplement\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index bae4ff1dcaf..4f082d71444 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -938,7 +938,7 @@ static int load_module(void) end: unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Support", diff --git a/res/res_smdi.c b/res/res_smdi.c index 4c7a45164c2..e2e5b17babf 100644 --- a/res/res_smdi.c +++ b/res/res_smdi.c @@ -1126,7 +1126,7 @@ static int smdi_load(int reload) if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) { ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n"); - return AST_MODULE_LOAD_FAILURE; + return -1; } if (ao2_container_count(new_ifaces)) { @@ -1369,7 +1369,7 @@ static int load_module(void) res = smdi_load(0); if (res < 0) { _unload_module(1); - return res; + return AST_MODULE_LOAD_DECLINE; } else if (res == 1) { _unload_module(1); ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n"); diff --git a/res/res_stasis.c b/res/res_stasis.c index 196720984ce..9ea0d63fea0 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -2111,12 +2111,12 @@ static int load_module(void) 37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL); if (!apps_registry || !app_controls || !app_bridges || !app_bridges_moh || !app_bridges_playback) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (messaging_init()) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } bridge_stasis_init(); diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c index e16bd8edddd..344cb40c96a 100644 --- a/res/res_stasis_device_state.c +++ b/res/res_stasis_device_state.c @@ -453,13 +453,14 @@ static int load_module(void) populate_cache(); if (ast_devstate_prov_add(DEVICE_STATE_PROVIDER_STASIS, stasis_device_state_cb)) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (!(device_state_subscriptions = ao2_container_alloc( DEVICE_STATE_BUCKETS, device_state_subscriptions_hash, device_state_subscriptions_cmp))) { - return AST_MODULE_LOAD_FAILURE; + ast_devstate_prov_del(DEVICE_STATE_PROVIDER_STASIS); + return AST_MODULE_LOAD_DECLINE; } stasis_app_register_event_source(&device_state_event_source); diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index 4370f17121d..c6f21365bd7 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -731,13 +731,14 @@ static int load_module(void) r = STASIS_MESSAGE_TYPE_INIT(stasis_app_playback_snapshot_type); if (r != 0) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } playbacks = ao2_container_alloc(PLAYBACK_BUCKETS, playback_hash, playback_cmp); if (!playbacks) { - return AST_MODULE_LOAD_FAILURE; + STASIS_MESSAGE_TYPE_CLEANUP(stasis_app_playback_snapshot_type); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c index 630205c34d5..56984cb4016 100644 --- a/res/res_stasis_recording.c +++ b/res/res_stasis_recording.c @@ -631,13 +631,14 @@ static int load_module(void) r = STASIS_MESSAGE_TYPE_INIT(stasis_app_recording_snapshot_type); if (r != 0) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } recordings = ao2_container_alloc(RECORDING_BUCKETS, recording_hash, recording_cmp); if (!recordings) { - return AST_MODULE_LOAD_FAILURE; + STASIS_MESSAGE_TYPE_CLEANUP(stasis_app_recording_snapshot_type); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/res/res_stasis_test.c b/res/res_stasis_test.c index 8b5bad7aea2..19d2a42c6af 100644 --- a/res/res_stasis_test.c +++ b/res/res_stasis_test.c @@ -272,7 +272,7 @@ static int unload_module(void) static int load_module(void) { if (STASIS_MESSAGE_TYPE_INIT(stasis_test_message_type) != 0) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/res/res_statsd.c b/res/res_statsd.c index 22c4ba2e700..3d7dd168400 100644 --- a/res/res_statsd.c +++ b/res/res_statsd.c @@ -349,7 +349,8 @@ static int load_module(void) } if (statsd_init() != 0) { - return AST_MODULE_LOAD_FAILURE; + aco_info_destroy(&cfg_info); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index c28a62cd9ec..ca4e2f192a3 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -256,6 +256,19 @@ fin: __attribute__((unused)) {{> rest_handler}} {{/root_path}} +static int unload_module(void) +{ + ast_ari_remove_handler(&{{root_full_name}}); +{{#apis}} +{{#has_websocket}} + ao2_cleanup({{full_name}}.ws_server); + {{full_name}}.ws_server = NULL; +{{/has_websocket}} +{{/apis}} + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; @@ -270,14 +283,14 @@ static int load_module(void) {{full_name}}.ws_server = ast_websocket_server_create(); if (!{{full_name}}.ws_server) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } protocol = ast_websocket_sub_protocol_alloc("{{websocket_protocol}}"); if (!protocol) { ao2_ref({{full_name}}.ws_server, -1); {{full_name}}.ws_server = NULL; - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb; protocol->session_established = ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb; @@ -289,21 +302,12 @@ static int load_module(void) {{/apis}} stasis_app_ref(); res |= ast_ari_add_handler(&{{root_full_name}}); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&{{root_full_name}}); -{{#apis}} -{{#has_websocket}} - ao2_cleanup({{full_name}}.ws_server); - {{full_name}}.ws_server = NULL; - ast_ari_websocket_events_event_websocket_dtor(); -{{/has_websocket}} -{{/apis}} - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - {{{description}}}", diff --git a/tests/test_bucket.c b/tests/test_bucket.c index 2b6e059c370..2cf5267c134 100644 --- a/tests/test_bucket.c +++ b/tests/test_bucket.c @@ -1012,7 +1012,7 @@ static int load_module(void) if (ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard, ast_bucket_file_temporary_create, ast_bucket_file_temporary_destroy)) { ast_log(LOG_ERROR, "Failed to register Bucket test wizard scheme implementation\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } AST_TEST_REGISTER(bucket_scheme_register); diff --git a/tests/test_channel_feature_hooks.c b/tests/test_channel_feature_hooks.c index c9fdf098377..a325484587e 100644 --- a/tests/test_channel_feature_hooks.c +++ b/tests/test_channel_feature_hooks.c @@ -345,7 +345,7 @@ static int load_module(void) { test_features_chan_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!test_features_chan_tech.capabilities) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } ast_format_cap_append(test_features_chan_tech.capabilities, TEST_CHANNEL_FORMAT, 0); ast_channel_register(&test_features_chan_tech); From 6db0939b96017b468d2d368e67669fd02b2fdecc Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 12 Apr 2017 06:47:59 -0600 Subject: [PATCH 1198/1578] modules: change module LOAD_FAILUREs to LOAD_DECLINES (14) Change-Id: If99e3b4fc2d7e86fc3e61182aa6c835b407ed49e --- formats/format_ogg_speex.c | 21 ++++++++++--------- res/res_ari_events.c | 5 ++++- res/res_http_media_cache.c | 4 ++-- .../res_ari_resource.c.mustache | 5 ++++- tests/test_media_cache.c | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/formats/format_ogg_speex.c b/formats/format_ogg_speex.c index 747adb37ff7..331c544358d 100644 --- a/formats/format_ogg_speex.c +++ b/formats/format_ogg_speex.c @@ -312,6 +312,15 @@ static struct ast_format_def speex32_f = { .desc_size = sizeof(struct speex_desc), }; +static int unload_module(void) +{ + int res = 0; + res |= ast_format_def_unregister(speex_f.name); + res |= ast_format_def_unregister(speex16_f.name); + res |= ast_format_def_unregister(speex32_f.name); + return res; +} + static int load_module(void) { speex_f.format = ast_format_speex; @@ -321,21 +330,13 @@ static int load_module(void) if (ast_format_def_register(&speex_f) || ast_format_def_register(&speex16_f) || ast_format_def_register(&speex32_f)) { - return AST_MODULE_LOAD_FAILURE; + unload_module(); + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) -{ - int res = 0; - res |= ast_format_def_unregister(speex_f.name); - res |= ast_format_def_unregister(speex16_f.name); - res |= ast_format_def_unregister(speex32_f.name); - return res; -} - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "OGG/Speex audio", .load = load_module, .unload = unload_module, diff --git a/res/res_ari_events.c b/res/res_ari_events.c index 8d8a303d1a8..76b79171992 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -422,6 +422,7 @@ static int unload_module(void) ast_ari_remove_handler(&events); ao2_cleanup(events.ws_server); events.ws_server = NULL; + ast_ari_websocket_events_event_websocket_dtor(); stasis_app_unref(); return 0; } @@ -432,11 +433,12 @@ static int load_module(void) struct ast_websocket_protocol *protocol; if (ast_ari_websocket_events_event_websocket_init() == -1) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } events.ws_server = ast_websocket_server_create(); if (!events.ws_server) { + ast_ari_websocket_events_event_websocket_dtor(); return AST_MODULE_LOAD_DECLINE; } @@ -444,6 +446,7 @@ static int load_module(void) if (!protocol) { ao2_ref(events.ws_server, -1); events.ws_server = NULL; + ast_ari_websocket_events_event_websocket_dtor(); return AST_MODULE_LOAD_DECLINE; } protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb; diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c index 8c67285866a..175f24c9268 100644 --- a/res/res_http_media_cache.c +++ b/res/res_http_media_cache.c @@ -425,13 +425,13 @@ static int load_module(void) if (ast_bucket_scheme_register("http", &http_bucket_wizard, &http_bucket_file_wizard, NULL, NULL)) { ast_log(LOG_ERROR, "Failed to register Bucket HTTP wizard scheme implementation\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } if (ast_bucket_scheme_register("https", &https_bucket_wizard, &https_bucket_file_wizard, NULL, NULL)) { ast_log(LOG_ERROR, "Failed to register Bucket HTTPS wizard scheme implementation\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index ca4e2f192a3..3ccafcd082b 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -263,6 +263,7 @@ static int unload_module(void) {{#has_websocket}} ao2_cleanup({{full_name}}.ws_server); {{full_name}}.ws_server = NULL; + ast_ari_websocket_events_event_websocket_dtor(); {{/has_websocket}} {{/apis}} stasis_app_unref(); @@ -278,11 +279,12 @@ static int load_module(void) struct ast_websocket_protocol *protocol; if (ast_ari_websocket_{{c_name}}_{{c_nickname}}_init() == -1) { - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } {{full_name}}.ws_server = ast_websocket_server_create(); if (!{{full_name}}.ws_server) { + ast_ari_websocket_events_event_websocket_dtor(); return AST_MODULE_LOAD_DECLINE; } @@ -290,6 +292,7 @@ static int load_module(void) if (!protocol) { ao2_ref({{full_name}}.ws_server, -1); {{full_name}}.ws_server = NULL; + ast_ari_websocket_events_event_websocket_dtor(); return AST_MODULE_LOAD_DECLINE; } protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb; diff --git a/tests/test_media_cache.c b/tests/test_media_cache.c index 34f53190a13..c35e43f0d6c 100644 --- a/tests/test_media_cache.c +++ b/tests/test_media_cache.c @@ -397,7 +397,7 @@ static int load_module(void) if (ast_bucket_scheme_register("httptest", &bucket_test_wizard, &bucket_file_test_wizard, NULL, NULL)) { ast_log(LOG_ERROR, "Failed to register Bucket HTTP test wizard scheme implementation\n"); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } AST_TEST_REGISTER(exists_nominal); From 72c5f3b0ba40e352fa26eeeead6e72eabd5e7730 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 10 Apr 2017 12:13:39 +0200 Subject: [PATCH 1199/1578] res_pjsip_sdp_rtp: No rtpmap for static RTP payload IDs in SDP. This saves around 100 bytes when G.711, G.722, G.729, and GSM are advertised in SDP. This reduces the chance to hit the MTU bearer of 1300 bytes for SIP over UDP, if many codecs are allowed in Asterisk. This new feature is enabled together with the optional feature compact_headers=yes via the file pjsip.conf. ASTERISK-26932 #close Change-Id: Iaa556ab4c8325cd34c334387ab2847fab07b1689 --- channels/chan_sip.c | 2 +- include/asterisk/rtp_engine.h | 6 ++++++ main/rtp_engine.c | 15 +++++++++------ res/res_pjsip_sdp_rtp.c | 18 ++++++++++-------- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 5419a1dd8b4..792df5c38b7 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -13097,7 +13097,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p, /* Opus mandates 2 channels in rtpmap */ if (ast_format_cmp(format, ast_format_opus) == AST_FORMAT_CMP_EQUAL) { ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u/2\r\n", rtp_code, mime, rate); - } else if ((35 <= rtp_code) || !(sip_cfg.compactheaders)) { + } else if ((AST_RTP_PT_LAST_STATIC < rtp_code) || !(sip_cfg.compactheaders)) { ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate); } diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index fa7fed8a134..55acf652918 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -81,6 +81,12 @@ extern "C" { /*! Maximum number of payload types RTP can support. */ #define AST_RTP_MAX_PT 128 +/*! + * Last RTP payload type statically assigned, see + * http://www.iana.org/assignments/rtp-parameters + */ +#define AST_RTP_PT_LAST_STATIC 34 + /*! First dynamic RTP payload type */ #define AST_RTP_PT_FIRST_DYNAMIC 96 diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 00f9d595fcc..19ca31cb633 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -1348,28 +1348,31 @@ static int find_unused_payload(const struct ast_rtp_codecs *codecs) * https://tools.ietf.org/html/draft-roach-mmusic-unified-plan#section-3.2.1.2 * https://tools.ietf.org/html/draft-wu-avtcore-dynamic-pt-usage#section-3 */ - res = find_unused_payload_in_range(codecs, MAX(ast_option_rtpptdynamic, 35), + res = find_unused_payload_in_range( + codecs, MAX(ast_option_rtpptdynamic, AST_RTP_PT_LAST_STATIC + 1), AST_RTP_PT_LAST_REASSIGN, static_RTP_PT); if (res != -1) { return res; } - /* Yet, reusing mappings below 35 is not supported in Asterisk because - * when Compact Headers are activated, no rtpmap is send for those below - * 35. If you want to use 35 and below + /* Yet, reusing mappings below AST_RTP_PT_LAST_STATIC (35) is not supported + * in Asterisk because when Compact Headers are activated, no rtpmap is + * send for those below 35. If you want to use 35 and below * A) do not use Compact Headers, * B) remove that code in chan_sip/res_pjsip, or * C) add a flag that this RTP Payload Type got reassigned dynamically * and requires a rtpmap even with Compact Headers enabled. */ res = find_unused_payload_in_range( - codecs, MAX(ast_option_rtpptdynamic, 20), 35, static_RTP_PT); + codecs, MAX(ast_option_rtpptdynamic, 20), + AST_RTP_PT_LAST_STATIC + 1, static_RTP_PT); if (res != -1) { return res; } return find_unused_payload_in_range( - codecs, MAX(ast_option_rtpptdynamic, 0), 20, static_RTP_PT); + codecs, MAX(ast_option_rtpptdynamic, 0), + 20, static_RTP_PT); } /*! diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 701edc3c202..64c50665776 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -447,6 +447,7 @@ static int set_caps(struct ast_sip_session *session, static pjmedia_sdp_attr* generate_rtpmap_attr(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool, int rtp_code, int asterisk_format, struct ast_format *format, int code) { + extern pj_bool_t pjsip_use_compact_form; pjmedia_sdp_rtpmap rtpmap; pjmedia_sdp_attr *attr = NULL; char tmp[64]; @@ -455,6 +456,11 @@ static pjmedia_sdp_attr* generate_rtpmap_attr(struct ast_sip_session *session, p snprintf(tmp, sizeof(tmp), "%d", rtp_code); pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp); + + if (rtp_code <= AST_RTP_PT_LAST_STATIC && pjsip_use_compact_form) { + return NULL; + } + rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1]; rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code); pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, options)); @@ -1254,11 +1260,9 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as continue; } - if (!(attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) { - ao2_ref(format, -1); - continue; + if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) { + media->attr[media->attr_count++] = attr; } - media->attr[media->attr_count++] = attr; if ((attr = generate_fmtp_attr(pool, format, rtp_code))) { media->attr[media->attr_count++] = attr; @@ -1287,12 +1291,10 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as continue; } - if (!(attr = generate_rtpmap_attr(session, media, pool, rtp_code, 0, NULL, index))) { - continue; + if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 0, NULL, index))) { + media->attr[media->attr_count++] = attr; } - media->attr[media->attr_count++] = attr; - if (index == AST_RTP_DTMF) { snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp)); From 2e6075c51fe0466d7410b02efb68f1d47aedb284 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 12 Apr 2017 06:50:49 -0600 Subject: [PATCH 1200/1578] modules: change module LOAD_FAILUREs to LOAD_DECLINES (master) Change-Id: Iac40ecb20e10513d67bf0eaf61807f306067b258 --- codecs/codec_codec2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecs/codec_codec2.c b/codecs/codec_codec2.c index e446854c310..6d2a0f720ce 100644 --- a/codecs/codec_codec2.c +++ b/codecs/codec_codec2.c @@ -213,7 +213,7 @@ static int load_module(void) if (res) { unload_module(); - return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; From be71be7ed2d2a8dd91f4fb4f08e0bcce1d3cbdb3 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 14 Apr 2017 15:36:57 -0400 Subject: [PATCH 1201/1578] format_pcm: Track actual header size of .au files Sun's Au file format has a minimum data offset 24 bytes, but this offset is encoded in each .au file. Instead of assuming the minimum, read the actual value and store it for later use. ASTERISK-20984 #close Reported by: Roman S. Patches: asterisk-1.8.20.0-au-clicks-2.diff (license #6474) patch uploaded by Roman S. Change-Id: I524022fb19ff2fd5af2cc2d669d27a780ab2057c --- formats/format_pcm.c | 55 ++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/formats/format_pcm.c b/formats/format_pcm.c index fedc0632f2b..97af0e9a3a1 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -231,7 +231,7 @@ static int pcm_write(struct ast_filestream *fs, struct ast_frame *f) /* SUN .au support routines */ -#define AU_HEADER_SIZE 24 +#define MIN_AU_HEADER_SIZE 24 #define AU_HEADER(var) uint32_t var[6] #define AU_HDR_MAGIC_OFF 0 @@ -266,7 +266,11 @@ static int pcm_write(struct ast_filestream *fs, struct ast_frame *f) #endif #endif -static int check_header(FILE *f) +struct au_desc { + uint32_t hdr_size; +}; + +static int check_header(struct ast_filestream *fs) { AU_HEADER(header); uint32_t magic; @@ -276,7 +280,10 @@ static int check_header(FILE *f) uint32_t sample_rate; uint32_t channels; - if (fread(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) { + struct au_desc *desc = fs->_private; + FILE *f = fs->f; + + if (fread(header, 1, MIN_AU_HEADER_SIZE, f) != MIN_AU_HEADER_SIZE) { ast_log(LOG_WARNING, "Read failed (header)\n"); return -1; } @@ -285,8 +292,8 @@ static int check_header(FILE *f) ast_log(LOG_WARNING, "Bad magic: 0x%x\n", magic); } hdr_size = ltohl(header[AU_HDR_HDR_SIZE_OFF]); - if (hdr_size < AU_HEADER_SIZE) { - hdr_size = AU_HEADER_SIZE; + if (hdr_size < MIN_AU_HEADER_SIZE) { + hdr_size = MIN_AU_HEADER_SIZE; } /* data_size = ltohl(header[AU_HDR_DATA_SIZE_OFF]); */ encoding = ltohl(header[AU_HDR_ENCODING_OFF]); @@ -311,20 +318,26 @@ static int check_header(FILE *f) ast_log(LOG_WARNING, "Failed to skip to data: %u\n", hdr_size); return -1; } + + /* We'll need this later */ + desc->hdr_size = hdr_size; + return data_size; } -static int update_header(FILE *f) +static int update_header(struct ast_filestream *fs) { off_t cur, end; uint32_t datalen; int bytes; + struct au_desc *desc = fs->_private; + FILE *f = fs->f; cur = ftell(f); fseek(f, 0, SEEK_END); end = ftell(f); /* data starts 24 bytes in */ - bytes = end - AU_HEADER_SIZE; + bytes = end - desc->hdr_size; datalen = htoll(bytes); if (cur < 0) { @@ -346,12 +359,15 @@ static int update_header(FILE *f) return 0; } -static int write_header(FILE *f) +static int write_header(struct ast_filestream *fs) { + struct au_desc *desc = fs->_private; + FILE *f = fs->f; + AU_HEADER(header); header[AU_HDR_MAGIC_OFF] = htoll((uint32_t) AU_MAGIC); - header[AU_HDR_HDR_SIZE_OFF] = htoll(AU_HEADER_SIZE); + header[AU_HDR_HDR_SIZE_OFF] = htoll(desc->hdr_size); header[AU_HDR_DATA_SIZE_OFF] = 0; header[AU_HDR_ENCODING_OFF] = htoll(AU_ENC_8BIT_ULAW); header[AU_HDR_SAMPLE_RATE_OFF] = htoll(DEFAULT_SAMPLE_RATE); @@ -359,7 +375,7 @@ static int write_header(FILE *f) /* Write an au header, ignoring sizes which will be filled in later */ fseek(f, 0, SEEK_SET); - if (fwrite(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) { + if (fwrite(header, 1, MIN_AU_HEADER_SIZE, f) != MIN_AU_HEADER_SIZE) { ast_log(LOG_WARNING, "Unable to write header\n"); return -1; } @@ -368,14 +384,18 @@ static int write_header(FILE *f) static int au_open(struct ast_filestream *s) { - if (check_header(s->f) < 0) + if (check_header(s) < 0) return -1; return 0; } static int au_rewrite(struct ast_filestream *s, const char *comment) { - if (write_header(s->f)) + struct au_desc *desc = s->_private; + + desc->hdr_size = MIN_AU_HEADER_SIZE; + + if (write_header(s)) return -1; return 0; } @@ -383,8 +403,11 @@ static int au_rewrite(struct ast_filestream *s, const char *comment) /* XXX check this, probably incorrect */ static int au_seek(struct ast_filestream *fs, off_t sample_offset, int whence) { - off_t min = AU_HEADER_SIZE, max, cur; + off_t min, max, cur; long offset = 0, bytes; + struct au_desc *desc = fs->_private; + + min = desc->hdr_size; if (ast_format_cmp(fs->fmt->format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) bytes = sample_offset / 2; @@ -440,13 +463,14 @@ static int au_trunc(struct ast_filestream *fs) if (ftruncate(fd, cur)) { return -1; } - return update_header(fs->f); + return update_header(fs); } static off_t au_tell(struct ast_filestream *fs) { + struct au_desc *desc = fs->_private; off_t offset = ftello(fs->f); - return offset - AU_HEADER_SIZE; + return offset - desc->hdr_size; } static struct ast_format_def alaw_f = { @@ -498,6 +522,7 @@ static struct ast_format_def au_f = { .tell = au_tell, .read = pcm_read, .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET, /* this many shorts */ + .desc_size = sizeof(struct au_desc), }; static int unload_module(void) From f6600f2c2ed98f1566f9e24db8392a47ae710299 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 14 Apr 2017 17:50:56 -0400 Subject: [PATCH 1202/1578] res_stun_monitor: Don't fail to load if DNS resolution fails res_stun_monitor will fail to load if DNS resolution of the STUN server fails. Instead, we continue without the STUN server being resolved and we will re-attempt the resolution on the STUN refresh interval. ASTERISK-21856 #close Reported by: Jeremy Kister Change-Id: I6334c54a1cc798f8a836b4b47948e0bb4ef59254 --- res/res_stun_monitor.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/res/res_stun_monitor.c b/res/res_stun_monitor.c index 46deaff7547..08d1d66152e 100644 --- a/res/res_stun_monitor.c +++ b/res/res_stun_monitor.c @@ -269,7 +269,7 @@ static int stun_start_monitor(void) * \retval 0 on success. * \retval -1 on error. */ -static int setup_stunaddr(const char *value) +static int setup_stunaddr(const char *value, int reload) { char *val; char *host_str; @@ -305,8 +305,12 @@ static int setup_stunaddr(const char *value) stun_addr.ss.ss_family = AF_INET; if (ast_get_ip(&stun_addr, host_str)) { ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", host_str); - ast_free(host_str); - return -1; + + /* Only treat this as fatal if we are reloading */ + if (reload) { + ast_free(host_str); + return -1; + } } /* Save STUN server information. */ @@ -348,7 +352,7 @@ static int load_config(int startup) for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { if (!strcasecmp(v->name, "stunaddr")) { - if (setup_stunaddr(v->value)) { + if (setup_stunaddr(v->value, !startup)) { ast_log(LOG_WARNING, "Invalid STUN server address: %s at line %d\n", v->value, v->lineno); } From a3e623dd70c98d490d70a55f76b471c48f0d4283 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 14 Apr 2017 17:32:22 -0500 Subject: [PATCH 1203/1578] Revert "bridging: Ensure successful T.38 negotation" This reverts commit 7819f95791fe0ca0e0cdc417e2687a5900444053. Change-Id: Ib91a7e6c9856f5f41329e42f40ba2394fee861a4 --- bridges/bridge_simple.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index 158c443537a..35544f84fac 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -56,19 +56,6 @@ static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chann return 0; } - /* Request resend of T.38 negotiation if in progress and the other leg not yet T.38 - */ - if (ast_channel_get_t38_state(c0) == T38_STATE_NEGOTIATING && ast_channel_get_t38_state(c1) == T38_STATE_UNKNOWN) { - struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, }; - ast_debug(3, "Sending T.38 param renegotiation to first channel %s.\n", ast_channel_name(c0)); - ast_indicate_data(c0, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); - } - if (ast_channel_get_t38_state(c1) == T38_STATE_NEGOTIATING && ast_channel_get_t38_state(c0) == T38_STATE_UNKNOWN) { - struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_PARMS, }; - ast_debug(3, "Sending T.38 param renegotiation to second channel %s.\n", ast_channel_name(c1)); - ast_indicate_data(c1, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); - } - return ast_channel_make_compatible(c0, c1); } From 4fb9f5d60ec0a5a4e607fb2517e95a95abee53af Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 14 Apr 2017 13:51:31 -0400 Subject: [PATCH 1204/1578] format_ogg_vorbis: Clear ogg/vorbis data structures on close On filestream close, we need to clear out the ogg & vorbis data structures to prevent a memory leak. ASTERISK-26169 #close Reported by: Ivan Myalkin Change-Id: Iee94c5a5d5bdafbf8b181c5c064d15d90ace8274 --- formats/format_ogg_vorbis.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c index d4212a169b4..c0f8c197dfe 100644 --- a/formats/format_ogg_vorbis.c +++ b/formats/format_ogg_vorbis.c @@ -158,6 +158,7 @@ static int ogg_vorbis_rewrite(struct ast_filestream *s, if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) { ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n"); + vorbis_info_clear(&tmp->vi); return -1; } @@ -273,6 +274,13 @@ static void ogg_vorbis_close(struct ast_filestream *fs) * and write out the rest of the data */ vorbis_analysis_wrote(&s->vd, 0); write_stream(s, fs->f); + + /* Cleanup */ + ogg_stream_clear(&s->os); + vorbis_block_clear(&s->vb); + vorbis_dsp_clear(&s->vd); + vorbis_comment_clear(&s->vc); + vorbis_info_clear(&s->vi); } else { /* clear OggVorbis_File handle */ ov_clear(&s->ov_f); From b55d21ad919b42829721ca3a0f7425a0b429ff12 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Sun, 16 Apr 2017 18:59:54 -0600 Subject: [PATCH 1205/1578] make ari-stubs so doc periodic jobs can run The periodic doc job does a make ari-stubs and checks that there are no changes before generating the docs. Since I changed the mustache template (and the generated code directly) recently and forgot to regenerate the stubs, the doc job thinks they're out of date. Change-Id: I94b97035311eccf52b0101b8590223265a7881d4 --- res/ari/resource_channels.h | 4 ++-- res/res_ari_applications.c | 19 ++++++++++++------- res/res_ari_asterisk.c | 19 ++++++++++++------- res/res_ari_bridges.c | 19 ++++++++++++------- res/res_ari_channels.c | 19 ++++++++++++------- res/res_ari_device_states.c | 19 ++++++++++++------- res/res_ari_endpoints.c | 19 ++++++++++++------- res/res_ari_events.c | 1 - res/res_ari_mailboxes.c | 19 ++++++++++++------- res/res_ari_playbacks.c | 19 ++++++++++++------- res/res_ari_recordings.c | 19 ++++++++++++------- res/res_ari_sounds.c | 19 ++++++++++++------- 12 files changed, 122 insertions(+), 73 deletions(-) diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h index f68db2f5b32..b071d08baf2 100644 --- a/res/ari/resource_channels.h +++ b/res/ari/resource_channels.h @@ -78,7 +78,7 @@ struct ast_ari_channels_originate_args { const char *other_channel_id; /*! The unique id of the channel which is originating this one. */ const char *originator; - /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */ + /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names can be found with "core show codecs". */ const char *formats; }; /*! @@ -179,7 +179,7 @@ struct ast_ari_channels_originate_with_id_args { const char *other_channel_id; /*! The unique id of the channel which is originating this one. */ const char *originator; - /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names an be found with "core show codecs". */ + /*! The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names can be found with "core show codecs". */ const char *formats; }; /*! diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c index 951ee85b7c5..21d9f56eb00 100644 --- a/res/res_ari_applications.c +++ b/res/res_ari_applications.c @@ -490,19 +490,24 @@ static struct stasis_rest_handlers applications = { .children = { &applications_applicationName, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&applications); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&applications); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&applications); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Stasis application resources", diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index 1dbd850bb4c..89517ccae0c 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -1211,19 +1211,24 @@ static struct stasis_rest_handlers asterisk = { .children = { &asterisk_config,&asterisk_info,&asterisk_modules,&asterisk_logging,&asterisk_variable, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&asterisk); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&asterisk); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&asterisk); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Asterisk resources", diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index e61865e311a..5402c2b995e 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -1537,19 +1537,24 @@ static struct stasis_rest_handlers bridges = { .children = { &bridges_bridgeId, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&bridges); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&bridges); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&bridges); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Bridge resources", diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 739eb0135bb..9d218e2beef 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -2841,19 +2841,24 @@ static struct stasis_rest_handlers channels = { .children = { &channels_create,&channels_channelId, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&channels); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&channels); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&channels); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Channel resources", diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c index b2aea525e74..d6de5dff869 100644 --- a/res/res_ari_device_states.c +++ b/res/res_ari_device_states.c @@ -321,19 +321,24 @@ static struct stasis_rest_handlers deviceStates = { .children = { &deviceStates_deviceName, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&deviceStates); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&deviceStates); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&deviceStates); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Device state resources", diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index 944146fcb53..d96de0877bf 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -445,19 +445,24 @@ static struct stasis_rest_handlers endpoints = { .children = { &endpoints_sendMessage,&endpoints_tech, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&endpoints); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&endpoints); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&endpoints); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Endpoint resources", diff --git a/res/res_ari_events.c b/res/res_ari_events.c index 76b79171992..3f5b89a440e 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -454,7 +454,6 @@ static int load_module(void) res |= ast_websocket_server_add_protocol2(events.ws_server, protocol); stasis_app_ref(); res |= ast_ari_add_handler(&events); - if (res) { unload_module(); return AST_MODULE_LOAD_DECLINE; diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c index 2eac609872a..12c33cd8847 100644 --- a/res/res_ari_mailboxes.c +++ b/res/res_ari_mailboxes.c @@ -327,19 +327,24 @@ static struct stasis_rest_handlers mailboxes = { .children = { &mailboxes_mailboxName, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&mailboxes); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&mailboxes); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&mailboxes); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Mailboxes resources", diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c index 8267a91b5a2..e2c432db031 100644 --- a/res/res_ari_playbacks.c +++ b/res/res_ari_playbacks.c @@ -279,19 +279,24 @@ static struct stasis_rest_handlers playbacks = { .children = { &playbacks_playbackId, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&playbacks); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&playbacks); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&playbacks); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Playback control resources", diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index e82605c7bc7..57d80f2e0fe 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -863,19 +863,24 @@ static struct stasis_rest_handlers recordings = { .children = { &recordings_stored,&recordings_live, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&recordings); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&recordings); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&recordings); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Recording resources", diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index fe0692f1668..fded7fbced5 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -209,19 +209,24 @@ static struct stasis_rest_handlers sounds = { .children = { &sounds_soundId, } }; +static int unload_module(void) +{ + ast_ari_remove_handler(&sounds); + stasis_app_unref(); + return 0; +} + static int load_module(void) { int res = 0; stasis_app_ref(); res |= ast_ari_add_handler(&sounds); - return res; -} + if (res) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } -static int unload_module(void) -{ - ast_ari_remove_handler(&sounds); - stasis_app_unref(); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Sound resources", From 6c0ab9afa775d30fcc498072eee7f660202fa51e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 14 Apr 2017 14:52:59 -0400 Subject: [PATCH 1206/1578] format_wav: Read 16khz wav samples properly When opening a PCM wave file for reading, we aren't tracking the frequency of the opened file, so we treat 16khz files as 8khz and do half reads. This patch also cleans up some of the data types and an unnecessarily complex `if` expression. ASTERISK-26613 #close Reported by: Vitaly K Change-Id: I05f8b263058dc573ea8ffe0c62e7964506e11815 --- formats/format_wav.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/formats/format_wav.c b/formats/format_wav.c index 049ead40ee0..8316c353027 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -80,9 +80,8 @@ struct wav_desc { /* format-specific parameters */ static int check_header_fmt(FILE *f, int hsize, int hz) { - short format, chans, bysam, bisam; - int bysec; - int freq; + unsigned short format, chans, bysam, bisam; + unsigned int freq, bysec; if (hsize < 16) { ast_log(LOG_WARNING, "Unexpected header size %d\n", hsize); return -1; @@ -92,7 +91,7 @@ static int check_header_fmt(FILE *f, int hsize, int hz) return -1; } if (ltohs(format) != 1) { - ast_log(LOG_WARNING, "Not a supported wav file format (%d). Only PCM encoded, 16 bit, mono, 8kHz files are supported with a lowercase '.wav' extension.\n", ltohs(format)); + ast_log(LOG_WARNING, "Not a supported wav file format (%d). Only PCM encoded, 16 bit, mono, 8kHz/16kHz files are supported with a lowercase '.wav' extension.\n", ltohs(format)); return -1; } if (fread(&chans, 1, 2, f) != 2) { @@ -107,10 +106,9 @@ static int check_header_fmt(FILE *f, int hsize, int hz) ast_log(LOG_WARNING, "Read failed (freq)\n"); return -1; } - if (((ltohl(freq) != 8000) && (ltohl(freq) != 16000)) || - ((ltohl(freq) == 8000) && (hz != 8000)) || - ((ltohl(freq) == 16000) && (hz != 16000))) { - ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", ltohl(freq),hz); + freq = ltohl(freq); + if ((freq != 8000 && freq != 16000) || freq != hz) { + ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", freq, hz); return -1; } /* Ignore the byte frequency */ @@ -323,9 +321,15 @@ static int wav_open(struct ast_filestream *s) /* We don't have any header to read or anything really, but if we did, it would go here. We also might want to check and be sure it's a valid file. */ - struct wav_desc *tmp = (struct wav_desc *)s->_private; - if ((tmp->maxlen = check_header(s->f, ast_format_get_sample_rate(s->fmt->format))) < 0) + struct wav_desc *tmp = s->_private; + unsigned int sample_rate = ast_format_get_sample_rate(s->fmt->format); + + tmp->maxlen = check_header(s->f, sample_rate); + if (tmp->maxlen < 0) { return -1; + } + + tmp->hz = sample_rate; return 0; } From b8b3380944eaa28e768b724018dff854aa3d3eff Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 19 Apr 2017 09:39:00 -0400 Subject: [PATCH 1207/1578] build: Update config.guess and config.sub Change-Id: Id078a1df07a771808775e1053cdfe1d99c8fb172 --- config.guess | 184 ++++++++++++++++++++++++++++++++------------------- config.sub | 90 ++++++++++++++++++------- 2 files changed, 181 insertions(+), 93 deletions(-) diff --git a/config.guess b/config.guess index 1f5c50c0d15..69ed3e573bb 100755 --- a/config.guess +++ b/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2017 Free Software Foundation, Inc. -timestamp='2014-03-23' +timestamp='2017-03-05' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ timestamp='2014-03-23' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. + # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ @@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in os=netbsd ;; esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" + echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` @@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; @@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build - SUN_ARCH="i386" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` @@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} @@ -579,8 +603,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi @@ -617,13 +642,13 @@ EOF sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi @@ -662,11 +687,11 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build @@ -679,12 +704,12 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -789,14 +814,14 @@ EOF echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -812,10 +837,11 @@ EOF UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; esac + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin @@ -878,7 +904,7 @@ EOF exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix @@ -901,7 +927,7 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) @@ -932,6 +958,9 @@ EOF crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -944,6 +973,9 @@ EOF ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -969,6 +1001,9 @@ EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; @@ -1001,6 +1036,9 @@ EOF ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; @@ -1020,7 +1058,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} @@ -1099,7 +1137,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; @@ -1248,6 +1286,9 @@ EOF SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; @@ -1261,9 +1302,9 @@ EOF UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in @@ -1285,7 +1326,7 @@ EOF exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi @@ -1303,6 +1344,9 @@ EOF NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; + NSX-?:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk${UNAME_RELEASE} + exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; @@ -1316,7 +1360,7 @@ EOF # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" @@ -1358,7 +1402,7 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos @@ -1369,23 +1413,25 @@ EOF x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; esac cat >&2 < in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp diff --git a/config.sub b/config.sub index d654d03cdcd..40ea5dfe115 100755 --- a/config.sub +++ b/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2017 Free Software Foundation, Inc. -timestamp='2014-05-01' +timestamp='2017-04-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ timestamp='2014-05-01' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -33,7 +33,7 @@ timestamp='2014-05-01' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -53,8 +53,7 @@ timestamp='2014-05-01' me=`echo "$0" | sed -e 's,.*/,,'` usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. @@ -68,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -255,15 +254,16 @@ case $basic_machine in | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ - | i370 | i860 | i960 | ia64 \ + | i370 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ @@ -301,10 +301,12 @@ case $basic_machine in | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ | pyramid \ + | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -312,6 +314,8 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | wasm32 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -326,6 +330,9 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none @@ -371,17 +378,18 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ + | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ @@ -422,13 +430,15 @@ case $basic_machine in | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ | pyramid-* \ + | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -436,6 +446,8 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ + | wasm32-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -512,6 +524,9 @@ case $basic_machine in basic_machine=i386-pc os=-aros ;; + asmjs) + basic_machine=asmjs-unknown + ;; aux) basic_machine=m68k-apple os=-aux @@ -632,6 +647,14 @@ case $basic_machine in basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -773,6 +796,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -828,6 +854,10 @@ case $basic_machine in basic_machine=powerpc-unknown os=-morphos ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) basic_machine=i386-pc os=-msdos @@ -920,6 +950,9 @@ case $basic_machine in nsr-tandem) basic_machine=nsr-tandem ;; + nsx-tandem) + basic_machine=nsx-tandem + ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf @@ -1004,7 +1037,7 @@ case $basic_machine in ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1014,7 +1047,7 @@ case $basic_machine in ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) @@ -1215,6 +1248,9 @@ case $basic_machine in basic_machine=a29k-wrs os=-vxworks ;; + wasm32) + basic_machine=wasm32-unknown + ;; w65*) basic_machine=w65-wdc os=-none @@ -1360,27 +1396,28 @@ case $os in | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1512,6 +1549,8 @@ case $os in ;; -nacl*) ;; + -ios) + ;; -none) ;; *) @@ -1607,6 +1646,9 @@ case $basic_machine in sparc-* | *-sun) os=-sunos4.1.1 ;; + pru-*) + os=-elf + ;; *-be) os=-beos ;; From d165079cbcb51c94ce729b97f25b42cdbd7b443e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 22 Mar 2017 16:05:49 -0500 Subject: [PATCH 1208/1578] rtp_engine/res_rtp_asterisk: Fix RTP struct reentrancy crashes. The struct ast_rtp_instance has historically been indirectly protected from reentrancy issues by the channel lock because early channel drivers held the lock for really long times. Holding the channel lock for such a long time has caused many deadlock problems in the past. Along comes chan_pjsip/res_pjsip which doesn't necessarily hold the channel lock because sometimes there may not be an associated channel created yet or the channel pointer isn't available. In the case of ASTERISK-26835 a pjsip serializer thread was processing a message's SDP body while another thread was reading a RTP packet from the socket. Both threads wound up changing the rtp->rtcp->local_addr_str string and interfering with each other. The classic reentrancy problem resulted in a crash. In the case of ASTERISK-26853 a pjsip serializer thread was processing a message's SDP body while another thread was reading a RTP packet from the socket. Both threads wound up processing ICE candidates in PJPROJECT and interfering with each other. The classic reentrancy problem resulted in a crash. * rtp_engine.c: Make the ast_rtp_instance_xxx() calls lock the RTP instance struct. * rtp_engine.c: Make ICE and DTLS wrapper functions to lock the RTP instance struct for the API call. * res_rtp_asterisk.c: Lock the RTP instance to prevent a reentrancy problem with rtp->rtcp->local_addr_str in the scheduler thread running ast_rtcp_write(). * res_rtp_asterisk.c: Avoid deadlock when local RTP bridging in bridge_p2p_rtp_write() because there are two RTP instance structs involved. * res_rtp_asterisk.c: Avoid deadlock when trying to stop scheduler callbacks. We cannot hold the instance lock when trying to stop a scheduler callback. * res_rtp_asterisk.c: Remove the lock in struct dtls_details and use the struct ast_rtp_instance ao2 object lock instead. The lock was used to synchronize two threads to prevent a race condition between starting and stopping a timeout timer. The race condition is no longer present between dtls_perform_handshake() and __rtp_recvfrom() because the instance lock prevents these functions from overlapping each other with regards to the timeout timer. * res_rtp_asterisk.c: Remove the lock in struct ast_rtp and use the struct ast_rtp_instance ao2 object lock instead. The lock was used to synchronize two threads using a condition signal to know when TURN negotiations complete. * res_rtp_asterisk.c: Avoid deadlock when trying to stop the TURN ioqueue_worker_thread(). We cannot hold the instance lock when trying to create or shut down the worker thread without a risk of deadlock. This patch exposed a race condition between a PJSIP serializer thread setting up an ICE session in ice_create() and another thread reading RTP packets. * res_rtp_asterisk.c:ice_create(): Set the new rtp->ice pointer after we have re-locked the RTP instance to prevent the other thread from trying to process ICE packets on an incomplete ICE session setup. A similar race condition is between a PJSIP serializer thread resetting up an ICE session in ice_create() and the timer_worker_thread() processing the completion of the previous ICE session. * res_rtp_asterisk.c:ast_rtp_on_ice_complete(): Protect against an uninitialized/null remote_address after calling update_address_with_ice_candidate(). * res_rtp_asterisk.c: Eliminate the chance of ice_reset_session() destroying and setting the rtp->ice pointer to NULL while other threads are using it by adding an ao2 wrapper around the PJPROJECT ice pointer. Now when we have to unlock the RTP instance object to call a PJPROJECT ICE function we will hold a ref to the wrapper. Also added some rtp->ice NULL checks after we relock the RTP instance and have to do something with the ICE structure. ASTERISK-26835 #close ASTERISK-26853 #close Change-Id: I780b39ec935dcefcce880d50c1a7261744f1d1b4 --- main/rtp_engine.c | 507 ++++++++++++++++++++++++++++++--- res/res_rtp_asterisk.c | 622 +++++++++++++++++++++++++++++++---------- 2 files changed, 949 insertions(+), 180 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 00f9d595fcc..0a2e84fcd74 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -388,9 +388,14 @@ static void instance_destructor(void *obj) struct ast_rtp_instance *instance = obj; /* Pass us off to the engine to destroy */ - if (instance->data && instance->engine->destroy(instance)) { - ast_debug(1, "Engine '%s' failed to destroy RTP instance '%p'\n", instance->engine->name, instance); - return; + if (instance->data) { + /* + * Lock in case the RTP engine has other threads that + * need synchronization with the destruction. + */ + ao2_lock(instance); + instance->engine->destroy(instance); + ao2_unlock(instance); } if (instance->srtp) { @@ -465,12 +470,20 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, ast_debug(1, "Using engine '%s' for RTP instance '%p'\n", engine->name, instance); - /* And pass it off to the engine to setup */ + /* + * And pass it off to the engine to setup + * + * Lock in case the RTP engine has other threads that + * need synchronization with the construction. + */ + ao2_lock(instance); if (instance->engine->new(instance, sched, &address, data)) { ast_debug(1, "Engine '%s' failed to setup RTP instance '%p'\n", engine->name, instance); + ao2_unlock(instance); ao2_ref(instance, -1); return NULL; } + ao2_unlock(instance); ast_debug(1, "RTP instance '%p' is setup and ready to go\n", instance); @@ -499,31 +512,48 @@ void *ast_rtp_instance_get_data(struct ast_rtp_instance *instance) int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame) { - return instance->engine->write(instance, frame); + int res; + + ao2_lock(instance); + res = instance->engine->write(instance, frame); + ao2_unlock(instance); + return res; } struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp) { - return instance->engine->read(instance, rtcp); + struct ast_frame *frame; + + ao2_lock(instance); + frame = instance->engine->read(instance, rtcp); + ao2_unlock(instance); + return frame; } int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address) { + ao2_lock(instance); ast_sockaddr_copy(&instance->local_address, address); + ao2_unlock(instance); return 0; } -int ast_rtp_instance_set_incoming_source_address(struct ast_rtp_instance *instance, - const struct ast_sockaddr *address) +static void rtp_instance_set_incoming_source_address_nolock(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) { ast_sockaddr_copy(&instance->incoming_source_address, address); - - /* moo */ - if (instance->engine->remote_address_set) { instance->engine->remote_address_set(instance, &instance->incoming_source_address); } +} + +int ast_rtp_instance_set_incoming_source_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) +{ + ao2_lock(instance); + rtp_instance_set_incoming_source_address_nolock(instance, address); + ao2_unlock(instance); return 0; } @@ -531,18 +561,26 @@ int ast_rtp_instance_set_incoming_source_address(struct ast_rtp_instance *instan int ast_rtp_instance_set_requested_target_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address) { + ao2_lock(instance); + ast_sockaddr_copy(&instance->requested_target_address, address); + rtp_instance_set_incoming_source_address_nolock(instance, address); + + ao2_unlock(instance); - return ast_rtp_instance_set_incoming_source_address(instance, address); + return 0; } int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address) { + ao2_lock(instance); if (ast_sockaddr_cmp(address, &instance->local_address) != 0) { ast_sockaddr_copy(address, &instance->local_address); + ao2_unlock(instance); return 1; } + ao2_unlock(instance); return 0; } @@ -550,16 +588,21 @@ int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address) { + ao2_lock(instance); ast_sockaddr_copy(address, &instance->local_address); + ao2_unlock(instance); } int ast_rtp_instance_get_and_cmp_requested_target_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address) { + ao2_lock(instance); if (ast_sockaddr_cmp(address, &instance->requested_target_address) != 0) { ast_sockaddr_copy(address, &instance->requested_target_address); + ao2_unlock(instance); return 1; } + ao2_unlock(instance); return 0; } @@ -567,43 +610,63 @@ int ast_rtp_instance_get_and_cmp_requested_target_address(struct ast_rtp_instanc void ast_rtp_instance_get_incoming_source_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address) { + ao2_lock(instance); ast_sockaddr_copy(address, &instance->incoming_source_address); + ao2_unlock(instance); } void ast_rtp_instance_get_requested_target_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address) { + ao2_lock(instance); ast_sockaddr_copy(address, &instance->requested_target_address); + ao2_unlock(instance); } void ast_rtp_instance_set_extended_prop(struct ast_rtp_instance *instance, int property, void *value) { if (instance->engine->extended_prop_set) { + ao2_lock(instance); instance->engine->extended_prop_set(instance, property, value); + ao2_unlock(instance); } } void *ast_rtp_instance_get_extended_prop(struct ast_rtp_instance *instance, int property) { + void *prop; + if (instance->engine->extended_prop_get) { - return instance->engine->extended_prop_get(instance, property); + ao2_lock(instance); + prop = instance->engine->extended_prop_get(instance, property); + ao2_unlock(instance); + } else { + prop = NULL; } - return NULL; + return prop; } void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value) { + ao2_lock(instance); instance->properties[property] = value; if (instance->engine->prop_set) { instance->engine->prop_set(instance, property, value); } + ao2_unlock(instance); } int ast_rtp_instance_get_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property) { - return instance->properties[property]; + int prop; + + ao2_lock(instance); + prop = instance->properties[property]; + ao2_unlock(instance); + + return prop; } struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance) @@ -654,9 +717,12 @@ void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp if (instance && instance->engine && instance->engine->payload_set) { int i; + + ao2_lock(instance); for (i = 0; i < AST_RTP_MAX_PT; i++) { instance->engine->payload_set(instance, i, 0, NULL, 0); } + ao2_unlock(instance); } } @@ -771,7 +837,9 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r rtp_codecs_payload_replace_rx(dest, idx, type); if (instance && instance->engine && instance->engine->payload_set) { + ao2_lock(instance); instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); + ao2_unlock(instance); } } } @@ -859,7 +927,9 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, type); if (instance && instance->engine && instance->engine->payload_set) { + ao2_lock(instance); instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); + ao2_unlock(instance); } } } @@ -927,7 +997,9 @@ void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_co rtp_codecs_payload_replace_rx(dest, idx, type); if (instance && instance->engine && instance->engine->payload_set) { + ao2_lock(instance); instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); + ao2_unlock(instance); } } @@ -969,7 +1041,9 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); if (instance && instance->engine && instance->engine->payload_set) { + ao2_lock(instance); instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); + ao2_unlock(instance); } } else { ao2_ref(new_type, -1); @@ -1045,7 +1119,9 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); if (instance && instance->engine && instance->engine->payload_set) { + ao2_lock(instance); instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); + ao2_unlock(instance); } } else { ao2_ref(new_type, -1); @@ -1084,7 +1160,9 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp } if (instance && instance->engine && instance->engine->payload_set) { + ao2_lock(instance); instance->engine->payload_set(instance, payload, 0, NULL, 0); + ao2_unlock(instance); } ast_rwlock_unlock(&codecs->codecs_lock); @@ -1676,57 +1754,127 @@ char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap * int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit) { - return instance->engine->dtmf_begin ? instance->engine->dtmf_begin(instance, digit) : -1; + int res; + + if (instance->engine->dtmf_begin) { + ao2_lock(instance); + res = instance->engine->dtmf_begin(instance, digit); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } int ast_rtp_instance_dtmf_end(struct ast_rtp_instance *instance, char digit) { - return instance->engine->dtmf_end ? instance->engine->dtmf_end(instance, digit) : -1; + int res; + + if (instance->engine->dtmf_end) { + ao2_lock(instance); + res = instance->engine->dtmf_end(instance, digit); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } + int ast_rtp_instance_dtmf_end_with_duration(struct ast_rtp_instance *instance, char digit, unsigned int duration) { - return instance->engine->dtmf_end_with_duration ? instance->engine->dtmf_end_with_duration(instance, digit, duration) : -1; + int res; + + if (instance->engine->dtmf_end_with_duration) { + ao2_lock(instance); + res = instance->engine->dtmf_end_with_duration(instance, digit, duration); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode) { - return (!instance->engine->dtmf_mode_set || instance->engine->dtmf_mode_set(instance, dtmf_mode)) ? -1 : 0; + int res; + + if (instance->engine->dtmf_mode_set) { + ao2_lock(instance); + res = instance->engine->dtmf_mode_set(instance, dtmf_mode); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance) { - return instance->engine->dtmf_mode_get ? instance->engine->dtmf_mode_get(instance) : 0; + int res; + + if (instance->engine->dtmf_mode_get) { + ao2_lock(instance); + res = instance->engine->dtmf_mode_get(instance); + ao2_unlock(instance); + } else { + res = 0; + } + return res; } void ast_rtp_instance_update_source(struct ast_rtp_instance *instance) { if (instance->engine->update_source) { + ao2_lock(instance); instance->engine->update_source(instance); + ao2_unlock(instance); } } void ast_rtp_instance_change_source(struct ast_rtp_instance *instance) { if (instance->engine->change_source) { + ao2_lock(instance); instance->engine->change_source(instance); + ao2_unlock(instance); } } int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc) { - return instance->engine->qos ? instance->engine->qos(instance, tos, cos, desc) : -1; + int res; + + if (instance->engine->qos) { + ao2_lock(instance); + res = instance->engine->qos(instance, tos, cos, desc); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } void ast_rtp_instance_stop(struct ast_rtp_instance *instance) { if (instance->engine->stop) { + ao2_lock(instance); instance->engine->stop(instance); + ao2_unlock(instance); } } int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp) { - return instance->engine->fd ? instance->engine->fd(instance, rtcp) : -1; + int res; + + if (instance->engine->fd) { + ao2_lock(instance); + res = instance->engine->fd(instance, rtcp); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type) @@ -1759,12 +1907,19 @@ static void unref_instance_cond(struct ast_rtp_instance **instance) struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance) { - return instance->bridged; + struct ast_rtp_instance *bridged; + + ao2_lock(instance); + bridged = instance->bridged; + ao2_unlock(instance); + return bridged; } void ast_rtp_instance_set_bridged(struct ast_rtp_instance *instance, struct ast_rtp_instance *bridged) { + ao2_lock(instance); instance->bridged = bridged; + ao2_unlock(instance); } void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, struct ast_channel *c_src) @@ -1936,17 +2091,44 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1 int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations) { - return instance->engine->red_init ? instance->engine->red_init(instance, buffer_time, payloads, generations) : -1; + int res; + + if (instance->engine->red_init) { + ao2_lock(instance); + res = instance->engine->red_init(instance, buffer_time, payloads, generations); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } int ast_rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame) { - return instance->engine->red_buffer ? instance->engine->red_buffer(instance, frame) : -1; + int res; + + if (instance->engine->red_buffer) { + ao2_lock(instance); + res = instance->engine->red_buffer(instance, frame); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat) { - return instance->engine->get_stat ? instance->engine->get_stat(instance, stats, stat) : -1; + int res; + + if (instance->engine->get_stat) { + ao2_lock(instance); + res = instance->engine->get_stat(instance, stats, stat); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_rtp_instance_stat_field field, char *buf, size_t size) @@ -2051,14 +2233,33 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, struct ast_format *format) { - return instance->engine->set_read_format ? instance->engine->set_read_format(instance, format) : -1; + int res; + + if (instance->engine->set_read_format) { + ao2_lock(instance); + res = instance->engine->set_read_format(instance, format); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } int ast_rtp_instance_set_write_format(struct ast_rtp_instance *instance, struct ast_format *format) { - return instance->engine->set_write_format ? instance->engine->set_write_format(instance, format) : -1; + int res; + + if (instance->engine->set_read_format) { + ao2_lock(instance); + res = instance->engine->set_write_format(instance, format); + ao2_unlock(instance); + } else { + res = -1; + } + return res; } +/* XXX Nothing calls this */ int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_channel *peer) { struct ast_rtp_glue *glue; @@ -2089,6 +2290,10 @@ int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_in return -1; } + /* + * XXX Good thing nothing calls this function because we would need + * deadlock avoidance to get the two instance locks. + */ res = instance->engine->make_compatible(chan, instance, peer, peer_instance); ast_channel_unlock(peer); @@ -2102,7 +2307,9 @@ int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_in void ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, struct ast_format_cap *to_endpoint, struct ast_format_cap *to_asterisk, struct ast_format_cap *result) { if (instance->engine->available_formats) { + ao2_lock(instance); instance->engine->available_formats(instance, to_endpoint, to_asterisk, result); + ao2_unlock(instance); if (ast_format_cap_count(result)) { return; } @@ -2113,7 +2320,16 @@ void ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, struc int ast_rtp_instance_activate(struct ast_rtp_instance *instance) { - return instance->engine->activate ? instance->engine->activate(instance) : 0; + int res; + + if (instance->engine->activate) { + ao2_lock(instance); + res = instance->engine->activate(instance); + ao2_unlock(instance); + } else { + res = 0; + } + return res; } void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, @@ -2219,29 +2435,250 @@ struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance, in { if (rtcp && instance->rtcp_srtp) { return instance->rtcp_srtp; - } - else { + } else { return instance->srtp; } } int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level) { + int res; + if (instance->engine->sendcng) { - return instance->engine->sendcng(instance, level); + ao2_lock(instance); + res = instance->engine->sendcng(instance, level); + ao2_unlock(instance); + } else { + res = -1; } + return res; +} - return -1; +static void rtp_ice_wrap_set_authentication(struct ast_rtp_instance *instance, const char *ufrag, const char *password) +{ + ao2_lock(instance); + instance->engine->ice->set_authentication(instance, ufrag, password); + ao2_unlock(instance); +} + +static void rtp_ice_wrap_add_remote_candidate(struct ast_rtp_instance *instance, const struct ast_rtp_engine_ice_candidate *candidate) +{ + ao2_lock(instance); + instance->engine->ice->add_remote_candidate(instance, candidate); + ao2_unlock(instance); +} + +static void rtp_ice_wrap_start(struct ast_rtp_instance *instance) +{ + ao2_lock(instance); + instance->engine->ice->start(instance); + ao2_unlock(instance); +} + +static void rtp_ice_wrap_stop(struct ast_rtp_instance *instance) +{ + ao2_lock(instance); + instance->engine->ice->stop(instance); + ao2_unlock(instance); +} + +static const char *rtp_ice_wrap_get_ufrag(struct ast_rtp_instance *instance) +{ + const char *ufrag; + + ao2_lock(instance); + ufrag = instance->engine->ice->get_ufrag(instance); + ao2_unlock(instance); + return ufrag; +} + +static const char *rtp_ice_wrap_get_password(struct ast_rtp_instance *instance) +{ + const char *password; + + ao2_lock(instance); + password = instance->engine->ice->get_password(instance); + ao2_unlock(instance); + return password; +} + +static struct ao2_container *rtp_ice_wrap_get_local_candidates(struct ast_rtp_instance *instance) +{ + struct ao2_container *local_candidates; + + ao2_lock(instance); + local_candidates = instance->engine->ice->get_local_candidates(instance); + ao2_unlock(instance); + return local_candidates; +} + +static void rtp_ice_wrap_ice_lite(struct ast_rtp_instance *instance) +{ + ao2_lock(instance); + instance->engine->ice->ice_lite(instance); + ao2_unlock(instance); +} + +static void rtp_ice_wrap_set_role(struct ast_rtp_instance *instance, + enum ast_rtp_ice_role role) +{ + ao2_lock(instance); + instance->engine->ice->set_role(instance, role); + ao2_unlock(instance); +} + +static void rtp_ice_wrap_turn_request(struct ast_rtp_instance *instance, + enum ast_rtp_ice_component_type component, enum ast_transport transport, + const char *server, unsigned int port, const char *username, const char *password) +{ + ao2_lock(instance); + instance->engine->ice->turn_request(instance, component, transport, server, port, + username, password); + ao2_unlock(instance); +} + +static void rtp_ice_wrap_change_components(struct ast_rtp_instance *instance, + int num_components) +{ + ao2_lock(instance); + instance->engine->ice->change_components(instance, num_components); + ao2_unlock(instance); } +static struct ast_rtp_engine_ice rtp_ice_wrappers = { + .set_authentication = rtp_ice_wrap_set_authentication, + .add_remote_candidate = rtp_ice_wrap_add_remote_candidate, + .start = rtp_ice_wrap_start, + .stop = rtp_ice_wrap_stop, + .get_ufrag = rtp_ice_wrap_get_ufrag, + .get_password = rtp_ice_wrap_get_password, + .get_local_candidates = rtp_ice_wrap_get_local_candidates, + .ice_lite = rtp_ice_wrap_ice_lite, + .set_role = rtp_ice_wrap_set_role, + .turn_request = rtp_ice_wrap_turn_request, + .change_components = rtp_ice_wrap_change_components, +}; + struct ast_rtp_engine_ice *ast_rtp_instance_get_ice(struct ast_rtp_instance *instance) { - return instance->engine->ice; + if (instance->engine->ice) { + return &rtp_ice_wrappers; + } + /* ICE not available */ + return NULL; +} + +static int rtp_dtls_wrap_set_configuration(struct ast_rtp_instance *instance, + const struct ast_rtp_dtls_cfg *dtls_cfg) +{ + int set_configuration; + + ao2_lock(instance); + set_configuration = instance->engine->dtls->set_configuration(instance, dtls_cfg); + ao2_unlock(instance); + return set_configuration; +} + +static int rtp_dtls_wrap_active(struct ast_rtp_instance *instance) +{ + int active; + + ao2_lock(instance); + active = instance->engine->dtls->active(instance); + ao2_unlock(instance); + return active; +} + +static void rtp_dtls_wrap_stop(struct ast_rtp_instance *instance) +{ + ao2_lock(instance); + instance->engine->dtls->stop(instance); + ao2_unlock(instance); +} + +static void rtp_dtls_wrap_reset(struct ast_rtp_instance *instance) +{ + ao2_lock(instance); + instance->engine->dtls->reset(instance); + ao2_unlock(instance); +} + +static enum ast_rtp_dtls_connection rtp_dtls_wrap_get_connection(struct ast_rtp_instance *instance) +{ + enum ast_rtp_dtls_connection get_connection; + + ao2_lock(instance); + get_connection = instance->engine->dtls->get_connection(instance); + ao2_unlock(instance); + return get_connection; } +static enum ast_rtp_dtls_setup rtp_dtls_wrap_get_setup(struct ast_rtp_instance *instance) +{ + enum ast_rtp_dtls_setup get_setup; + + ao2_lock(instance); + get_setup = instance->engine->dtls->get_setup(instance); + ao2_unlock(instance); + return get_setup; +} + +static void rtp_dtls_wrap_set_setup(struct ast_rtp_instance *instance, + enum ast_rtp_dtls_setup setup) +{ + ao2_lock(instance); + instance->engine->dtls->set_setup(instance, setup); + ao2_unlock(instance); +} + +static void rtp_dtls_wrap_set_fingerprint(struct ast_rtp_instance *instance, + enum ast_rtp_dtls_hash hash, const char *fingerprint) +{ + ao2_lock(instance); + instance->engine->dtls->set_fingerprint(instance, hash, fingerprint); + ao2_unlock(instance); +} + +static enum ast_rtp_dtls_hash rtp_dtls_wrap_get_fingerprint_hash(struct ast_rtp_instance *instance) +{ + enum ast_rtp_dtls_hash get_fingerprint_hash; + + ao2_lock(instance); + get_fingerprint_hash = instance->engine->dtls->get_fingerprint_hash(instance); + ao2_unlock(instance); + return get_fingerprint_hash; +} + +static const char *rtp_dtls_wrap_get_fingerprint(struct ast_rtp_instance *instance) +{ + const char *get_fingerprint; + + ao2_lock(instance); + get_fingerprint = instance->engine->dtls->get_fingerprint(instance); + ao2_unlock(instance); + return get_fingerprint; +} + +static struct ast_rtp_engine_dtls rtp_dtls_wrappers = { + .set_configuration = rtp_dtls_wrap_set_configuration, + .active = rtp_dtls_wrap_active, + .stop = rtp_dtls_wrap_stop, + .reset = rtp_dtls_wrap_reset, + .get_connection = rtp_dtls_wrap_get_connection, + .get_setup = rtp_dtls_wrap_get_setup, + .set_setup = rtp_dtls_wrap_set_setup, + .set_fingerprint = rtp_dtls_wrap_set_fingerprint, + .get_fingerprint_hash = rtp_dtls_wrap_get_fingerprint_hash, + .get_fingerprint = rtp_dtls_wrap_get_fingerprint, +}; + struct ast_rtp_engine_dtls *ast_rtp_instance_get_dtls(struct ast_rtp_instance *instance) { - return instance->engine->dtls; + if (instance->engine->dtls) { + return &rtp_dtls_wrappers; + } + /* DTLS not available */ + return NULL; } int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, const char *value) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index a7103860b87..e2638320c57 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -222,7 +222,6 @@ struct rtp_learning_info { #ifdef HAVE_OPENSSL_SRTP struct dtls_details { - ast_mutex_t lock; /*!< Lock for timeout timer synchronization */ SSL *ssl; /*!< SSL session */ BIO *read_bio; /*!< Memory buffer for reading */ BIO *write_bio; /*!< Memory buffer for writing */ @@ -232,6 +231,13 @@ struct dtls_details { }; #endif +#ifdef HAVE_PJPROJECT +/*! An ao2 wrapper protecting the PJPROJECT ice structure with ref counting. */ +struct ice_wrap { + pj_ice_sess *real_ice; /*!< ICE session */ +}; +#endif + /*! \brief RTP session description */ struct ast_rtp { int s; @@ -307,11 +313,10 @@ struct ast_rtp { struct rtp_red *red; - ast_mutex_t lock; /*!< Lock for synchronization purposes */ - ast_cond_t cond; /*!< Condition for signaling */ - #ifdef HAVE_PJPROJECT - pj_ice_sess *ice; /*!< ICE session */ + ast_cond_t cond; /*!< ICE/TURN condition for signaling */ + + struct ice_wrap *ice; /*!< ao2 wrapped ICE session */ pj_turn_sock *turn_rtp; /*!< RTP TURN relay */ pj_turn_sock *turn_rtcp; /*!< RTCP TURN relay */ pj_turn_state_t turn_state; /*!< Current state of the TURN relay session */ @@ -477,7 +482,7 @@ static void dtls_srtp_start_timeout_timer(struct ast_rtp_instance *instance, str static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp); #endif -static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp); +static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *via_ice, int use_srtp); #ifdef HAVE_PJPROJECT /*! \brief Helper function which clears the ICE host candidate mapping */ @@ -513,17 +518,20 @@ static void host_candidate_overrides_apply(unsigned int count, pj_sockaddr addrs } /*! \brief Helper function which updates an ast_sockaddr with the candidate used for the component */ -static void update_address_with_ice_candidate(struct ast_rtp *rtp, enum ast_rtp_ice_component_type component, +static void update_address_with_ice_candidate(pj_ice_sess *ice, enum ast_rtp_ice_component_type component, struct ast_sockaddr *cand_address) { char address[PJ_INET6_ADDRSTRLEN]; - if (!rtp->ice || (component < 1) || !rtp->ice->comp[component - 1].valid_check) { + if (component < 1 || !ice->comp[component - 1].valid_check) { return; } - ast_sockaddr_parse(cand_address, pj_sockaddr_print(&rtp->ice->comp[component - 1].valid_check->rcand->addr, address, sizeof(address), 0), 0); - ast_sockaddr_set_port(cand_address, pj_sockaddr_get_port(&rtp->ice->comp[component - 1].valid_check->rcand->addr)); + ast_sockaddr_parse(cand_address, + pj_sockaddr_print(&ice->comp[component - 1].valid_check->rcand->addr, address, + sizeof(address), 0), 0); + ast_sockaddr_set_port(cand_address, + pj_sockaddr_get_port(&ice->comp[component - 1].valid_check->rcand->addr)); } /*! \brief Destructor for locally created ICE candidates */ @@ -540,6 +548,7 @@ static void ast_rtp_ice_candidate_destroy(void *obj) } } +/*! \pre instance is locked */ static void ast_rtp_ice_set_authentication(struct ast_rtp_instance *instance, const char *ufrag, const char *password) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -567,6 +576,7 @@ static int ice_candidate_cmp(void *obj, void *arg, int flags) return CMP_MATCH | CMP_STOP; } +/*! \pre instance is locked */ static void ast_rtp_ice_add_remote_candidate(struct ast_rtp_instance *instance, const struct ast_rtp_engine_ice_candidate *candidate) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -631,40 +641,60 @@ static void pj_thread_register_check(void) static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *addr, int port, int replace); +/*! \pre instance is locked */ static void ast_rtp_ice_stop(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct ice_wrap *ice; - if (!rtp->ice) { - return; + ice = rtp->ice; + rtp->ice = NULL; + if (ice) { + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); + ao2_ref(ice, -1); + ao2_lock(instance); } +} - pj_thread_register_check(); +/*! + * \brief ao2 ICE wrapper object destructor. + * + * \param vdoomed Object being destroyed. + * + * \note The associated struct ast_rtp_instance object must not + * be locked when unreffing the object. Otherwise we could + * deadlock trying to destroy the PJPROJECT ICE structure. + */ +static void ice_wrap_dtor(void *vdoomed) +{ + struct ice_wrap *ice = vdoomed; - pj_ice_sess_destroy(rtp->ice); - rtp->ice = NULL; + if (ice->real_ice) { + pj_thread_register_check(); + + pj_ice_sess_destroy(ice->real_ice); + } } +/*! \pre instance is locked */ static int ice_reset_session(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - pj_ice_sess_role role = rtp->ice->role; + pj_ice_sess_role role = rtp->ice->real_ice->role; int res; ast_debug(3, "Resetting ICE for RTP instance '%p'\n", instance); - if (!rtp->ice->is_nominating && !rtp->ice->is_complete) { + if (!rtp->ice->real_ice->is_nominating && !rtp->ice->real_ice->is_complete) { ast_debug(3, "Nevermind. ICE isn't ready for a reset\n"); return 0; } - ast_debug(3, "Stopping ICE for RTP instance '%p'\n", instance); - ast_rtp_ice_stop(instance); - ast_debug(3, "Recreating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(&rtp->ice_original_rtp_addr), rtp->ice_port, instance); res = ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1); if (!res) { /* Preserve the role that the old ICE session used */ - pj_ice_sess_change_role(rtp->ice, role); + pj_ice_sess_change_role(rtp->ice->real_ice, role); } /* If we only have one component now, and we previously set up TURN for RTCP, @@ -674,13 +704,15 @@ static int ice_reset_session(struct ast_rtp_instance *instance) struct timeval wait = ast_tvadd(ast_tvnow(), ast_samp2tv(TURN_STATE_WAIT_TIME, 1000)); struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, }; - ast_mutex_lock(&rtp->lock); - pj_turn_sock_destroy(rtp->turn_rtcp); rtp->turn_state = PJ_TURN_STATE_NULL; + + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); + pj_turn_sock_destroy(rtp->turn_rtcp); + ao2_lock(instance); while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) { - ast_cond_timedwait(&rtp->cond, &rtp->lock, &ts); + ast_cond_timedwait(&rtp->cond, ao2_object_get_lockaddr(instance), &ts); } - ast_mutex_unlock(&rtp->lock); } return res; @@ -713,6 +745,7 @@ static int ice_candidates_compare(struct ao2_container *left, struct ao2_contain return 0; } +/*! \pre instance is locked */ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -757,7 +790,8 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) has_rtp |= candidate->id == AST_RTP_ICE_COMPONENT_RTP; has_rtcp |= candidate->id == AST_RTP_ICE_COMPONENT_RTCP; - pj_strdup2(rtp->ice->pool, &candidates[cand_cnt].foundation, candidate->foundation); + pj_strdup2(rtp->ice->real_ice->pool, &candidates[cand_cnt].foundation, + candidate->foundation); candidates[cand_cnt].comp_id = candidate->id; candidates[cand_cnt].prio = candidate->priority; @@ -777,10 +811,16 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) if (candidate->id == AST_RTP_ICE_COMPONENT_RTP && rtp->turn_rtp) { ast_debug(3, "RTP candidate %s (%p)\n", ast_sockaddr_stringify(&candidate->address), instance); + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); pj_turn_sock_set_perm(rtp->turn_rtp, 1, &candidates[cand_cnt].addr, 1); + ao2_lock(instance); } else if (candidate->id == AST_RTP_ICE_COMPONENT_RTCP && rtp->turn_rtcp) { ast_debug(3, "RTCP candidate %s (%p)\n", ast_sockaddr_stringify(&candidate->address), instance); + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); pj_turn_sock_set_perm(rtp->turn_rtcp, 1, &candidates[cand_cnt].addr, 1); + ao2_lock(instance); } cand_cnt++; @@ -803,18 +843,28 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) ast_log(LOG_WARNING, "No RTCP candidates; skipping ICE checklist (%p)\n", instance); } - if (has_rtp && (has_rtcp || rtp->ice_num_components == 1)) { - pj_status_t res = pj_ice_sess_create_check_list(rtp->ice, &ufrag, &passwd, cand_cnt, &candidates[0]); + if (rtp->ice && has_rtp && (has_rtcp || rtp->ice_num_components == 1)) { + pj_status_t res; char reason[80]; + struct ice_wrap *ice; + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ice = rtp->ice; + ao2_ref(ice, +1); + ao2_unlock(instance); + res = pj_ice_sess_create_check_list(ice->real_ice, &ufrag, &passwd, cand_cnt, &candidates[0]); if (res == PJ_SUCCESS) { ast_debug(3, "Successfully created ICE checklist (%p)\n", instance); ast_test_suite_event_notify("ICECHECKLISTCREATE", "Result: SUCCESS"); - pj_ice_sess_start_check(rtp->ice); + pj_ice_sess_start_check(ice->real_ice); pj_timer_heap_poll(timer_heap, NULL); + ao2_ref(ice, -1); + ao2_lock(instance); rtp->strict_rtp_state = STRICT_RTP_OPEN; return; } + ao2_ref(ice, -1); + ao2_lock(instance); pj_strerror(res, reason, sizeof(reason)); ast_log(LOG_WARNING, "Failed to create ICE session check list: %s (%p)\n", reason, instance); @@ -828,9 +878,12 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) this function may be re-entered */ ao2_ref(rtp->ice_active_remote_candidates, -1); rtp->ice_active_remote_candidates = NULL; - rtp->ice->rcand_cnt = rtp->ice->clist.count = 0; + if (rtp->ice) { + rtp->ice->real_ice->rcand_cnt = rtp->ice->real_ice->clist.count = 0; + } } +/*! \pre instance is locked */ static const char *ast_rtp_ice_get_ufrag(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -838,6 +891,7 @@ static const char *ast_rtp_ice_get_ufrag(struct ast_rtp_instance *instance) return rtp->local_ufrag; } +/*! \pre instance is locked */ static const char *ast_rtp_ice_get_password(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -845,6 +899,7 @@ static const char *ast_rtp_ice_get_password(struct ast_rtp_instance *instance) return rtp->local_passwd; } +/*! \pre instance is locked */ static struct ao2_container *ast_rtp_ice_get_local_candidates(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -856,6 +911,7 @@ static struct ao2_container *ast_rtp_ice_get_local_candidates(struct ast_rtp_ins return rtp->ice_local_candidates; } +/*! \pre instance is locked */ static void ast_rtp_ice_lite(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -866,9 +922,10 @@ static void ast_rtp_ice_lite(struct ast_rtp_instance *instance) pj_thread_register_check(); - pj_ice_sess_change_role(rtp->ice, PJ_ICE_SESS_ROLE_CONTROLLING); + pj_ice_sess_change_role(rtp->ice->real_ice, PJ_ICE_SESS_ROLE_CONTROLLING); } +/*! \pre instance is locked */ static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp_ice_role role) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -883,20 +940,29 @@ static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp pj_thread_register_check(); - pj_ice_sess_change_role(rtp->ice, role == AST_RTP_ICE_ROLE_CONTROLLED ? + pj_ice_sess_change_role(rtp->ice->real_ice, role == AST_RTP_ICE_ROLE_CONTROLLED ? PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING); } -static void ast_rtp_ice_add_cand(struct ast_rtp *rtp, unsigned comp_id, unsigned transport_id, pj_ice_cand_type type, pj_uint16_t local_pref, - const pj_sockaddr_t *addr, const pj_sockaddr_t *base_addr, const pj_sockaddr_t *rel_addr, int addr_len) +/*! \pre instance is locked */ +static void ast_rtp_ice_add_cand(struct ast_rtp_instance *instance, struct ast_rtp *rtp, + unsigned comp_id, unsigned transport_id, pj_ice_cand_type type, pj_uint16_t local_pref, + const pj_sockaddr_t *addr, const pj_sockaddr_t *base_addr, const pj_sockaddr_t *rel_addr, + int addr_len) { pj_str_t foundation; struct ast_rtp_engine_ice_candidate *candidate, *existing; + struct ice_wrap *ice; char address[PJ_INET6_ADDRSTRLEN]; + pj_status_t status; + + if (!rtp->ice) { + return; + } pj_thread_register_check(); - pj_ice_calc_foundation(rtp->ice->pool, &foundation, type, addr); + pj_ice_calc_foundation(rtp->ice->real_ice->pool, &foundation, type, addr); if (!rtp->ice_local_candidates && !(rtp->ice_local_candidates = ao2_container_alloc(1, NULL, ice_candidate_cmp))) { return; @@ -932,42 +998,60 @@ static void ast_rtp_ice_add_cand(struct ast_rtp *rtp, unsigned comp_id, unsigned return; } - if (pj_ice_sess_add_cand(rtp->ice, comp_id, transport_id, type, local_pref, &foundation, addr, base_addr, rel_addr, addr_len, NULL) != PJ_SUCCESS) { + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ice = rtp->ice; + ao2_ref(ice, +1); + ao2_unlock(instance); + status = pj_ice_sess_add_cand(ice->real_ice, comp_id, transport_id, type, local_pref, + &foundation, addr, base_addr, rel_addr, addr_len, NULL); + ao2_ref(ice, -1); + ao2_lock(instance); + if (!rtp->ice || status != PJ_SUCCESS) { ao2_ref(candidate, -1); return; } /* By placing the candidate into the ICE session it will have produced the priority, so update the local candidate with it */ - candidate->priority = rtp->ice->lcand[rtp->ice->lcand_cnt - 1].prio; + candidate->priority = rtp->ice->real_ice->lcand[rtp->ice->real_ice->lcand_cnt - 1].prio; ao2_link(rtp->ice_local_candidates, candidate); ao2_ref(candidate, -1); } +/* PJPROJECT TURN callback */ static void ast_rtp_on_turn_rx_rtp_data(pj_turn_sock *turn_sock, void *pkt, unsigned pkt_len, const pj_sockaddr_t *peer_addr, unsigned addr_len) { struct ast_rtp_instance *instance = pj_turn_sock_get_user_data(turn_sock); struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct ice_wrap *ice; pj_status_t status; - status = pj_ice_sess_on_rx_pkt(rtp->ice, AST_RTP_ICE_COMPONENT_RTP, TRANSPORT_TURN_RTP, pkt, pkt_len, peer_addr, - addr_len); - if (status != PJ_SUCCESS) { - char buf[100]; + ao2_lock(instance); + ice = ao2_bump(rtp->ice); + ao2_unlock(instance); - pj_strerror(status, buf, sizeof(buf)); - ast_log(LOG_WARNING, "PJ ICE Rx error status code: %d '%s'.\n", - (int)status, buf); - return; - } - if (!rtp->rtp_passthrough) { - return; + if (ice) { + status = pj_ice_sess_on_rx_pkt(ice->real_ice, AST_RTP_ICE_COMPONENT_RTP, + TRANSPORT_TURN_RTP, pkt, pkt_len, peer_addr, addr_len); + ao2_ref(ice, -1); + if (status != PJ_SUCCESS) { + char buf[100]; + + pj_strerror(status, buf, sizeof(buf)); + ast_log(LOG_WARNING, "PJ ICE Rx error status code: %d '%s'.\n", + (int)status, buf); + return; + } + if (!rtp->rtp_passthrough) { + return; + } + rtp->rtp_passthrough = 0; } - rtp->rtp_passthrough = 0; ast_sendto(rtp->s, pkt, pkt_len, 0, &rtp->rtp_loop); } +/* PJPROJECT TURN callback */ static void ast_rtp_on_turn_rtp_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, pj_turn_state_t new_state) { struct ast_rtp_instance *instance = pj_turn_sock_get_user_data(turn_sock); @@ -980,8 +1064,9 @@ static void ast_rtp_on_turn_rtp_state(pj_turn_sock *turn_sock, pj_turn_state_t o rtp = ast_rtp_instance_get_data(instance); + ao2_lock(instance); + /* We store the new state so the other thread can actually handle it */ - ast_mutex_lock(&rtp->lock); rtp->turn_state = new_state; ast_cond_signal(&rtp->cond); @@ -990,7 +1075,7 @@ static void ast_rtp_on_turn_rtp_state(pj_turn_sock *turn_sock, pj_turn_state_t o rtp->turn_rtp = NULL; } - ast_mutex_unlock(&rtp->lock); + ao2_unlock(instance); } /* RTP TURN Socket interface declaration */ @@ -999,34 +1084,44 @@ static pj_turn_sock_cb ast_rtp_turn_rtp_sock_cb = { .on_state = ast_rtp_on_turn_rtp_state, }; +/* PJPROJECT TURN callback */ static void ast_rtp_on_turn_rx_rtcp_data(pj_turn_sock *turn_sock, void *pkt, unsigned pkt_len, const pj_sockaddr_t *peer_addr, unsigned addr_len) { struct ast_rtp_instance *instance = pj_turn_sock_get_user_data(turn_sock); struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct ice_wrap *ice; pj_status_t status; - status = pj_ice_sess_on_rx_pkt(rtp->ice, AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_TURN_RTCP, pkt, pkt_len, peer_addr, - addr_len); - if (status != PJ_SUCCESS) { - char buf[100]; + ao2_lock(instance); + ice = ao2_bump(rtp->ice); + ao2_unlock(instance); - pj_strerror(status, buf, sizeof(buf)); - ast_log(LOG_WARNING, "PJ ICE Rx error status code: %d '%s'.\n", - (int)status, buf); - return; - } - if (!rtp->rtcp_passthrough) { - return; + if (ice) { + status = pj_ice_sess_on_rx_pkt(ice->real_ice, AST_RTP_ICE_COMPONENT_RTCP, + TRANSPORT_TURN_RTCP, pkt, pkt_len, peer_addr, addr_len); + ao2_ref(ice, -1); + if (status != PJ_SUCCESS) { + char buf[100]; + + pj_strerror(status, buf, sizeof(buf)); + ast_log(LOG_WARNING, "PJ ICE Rx error status code: %d '%s'.\n", + (int)status, buf); + return; + } + if (!rtp->rtcp_passthrough) { + return; + } + rtp->rtcp_passthrough = 0; } - rtp->rtcp_passthrough = 0; ast_sendto(rtp->rtcp->s, pkt, pkt_len, 0, &rtp->rtcp_loop); } +/* PJPROJECT TURN callback */ static void ast_rtp_on_turn_rtcp_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, pj_turn_state_t new_state) { struct ast_rtp_instance *instance = pj_turn_sock_get_user_data(turn_sock); - struct ast_rtp *rtp = NULL; + struct ast_rtp *rtp; /* If this is a leftover from an already destroyed RTP instance just ignore the state change */ if (!instance) { @@ -1035,8 +1130,9 @@ static void ast_rtp_on_turn_rtcp_state(pj_turn_sock *turn_sock, pj_turn_state_t rtp = ast_rtp_instance_get_data(instance); + ao2_lock(instance); + /* We store the new state so the other thread can actually handle it */ - ast_mutex_lock(&rtp->lock); rtp->turn_state = new_state; ast_cond_signal(&rtp->cond); @@ -1045,7 +1141,7 @@ static void ast_rtp_on_turn_rtcp_state(pj_turn_sock *turn_sock, pj_turn_state_t rtp->turn_rtcp = NULL; } - ast_mutex_unlock(&rtp->lock); + ao2_unlock(instance); } /* RTCP TURN Socket interface declaration */ @@ -1177,6 +1273,7 @@ static struct ast_rtp_ioqueue_thread *rtp_ioqueue_thread_get_or_create(void) return ioqueue; } +/*! \pre instance is locked */ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast_rtp_ice_component_type component, enum ast_transport transport, const char *server, unsigned int port, const char *username, const char *password) { @@ -1193,6 +1290,7 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, }; pj_turn_session_info info; struct ast_sockaddr local, loop; + pj_status_t status; ast_rtp_instance_get_local_address(instance, &local); if (ast_sockaddr_is_ipv4(&local)) { @@ -1227,18 +1325,27 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast ast_sockaddr_parse(&addr, server, PARSE_PORT_FORBID); - ast_mutex_lock(&rtp->lock); if (*turn_sock) { - pj_turn_sock_destroy(*turn_sock); rtp->turn_state = PJ_TURN_STATE_NULL; + + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); + pj_turn_sock_destroy(*turn_sock); + ao2_lock(instance); while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) { - ast_cond_timedwait(&rtp->cond, &rtp->lock, &ts); + ast_cond_timedwait(&rtp->cond, ao2_object_get_lockaddr(instance), &ts); } } - ast_mutex_unlock(&rtp->lock); if (component == AST_RTP_ICE_COMPONENT_RTP && !rtp->ioqueue) { + /* + * We cannot hold the instance lock because we could wait + * for the ioqueue thread to die and we might deadlock as + * a result. + */ + ao2_unlock(instance); rtp->ioqueue = rtp_ioqueue_thread_get_or_create(); + ao2_lock(instance); if (!rtp->ioqueue) { return; } @@ -1246,9 +1353,14 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast pj_stun_config_init(&stun_config, &cachingpool.factory, 0, rtp->ioqueue->ioqueue, rtp->ioqueue->timerheap); - if (pj_turn_sock_create(&stun_config, ast_sockaddr_is_ipv4(&addr) ? pj_AF_INET() : pj_AF_INET6(), conn_type, - turn_cb, NULL, instance, turn_sock) != PJ_SUCCESS) { + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); + status = pj_turn_sock_create(&stun_config, + ast_sockaddr_is_ipv4(&addr) ? pj_AF_INET() : pj_AF_INET6(), conn_type, + turn_cb, NULL, instance, turn_sock); + if (status != PJ_SUCCESS) { ast_log(LOG_WARNING, "Could not create a TURN client socket\n"); + ao2_lock(instance); return; } @@ -1257,13 +1369,16 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; pj_strset2(&cred.data.static_cred.data, (char*)password); - /* Because the TURN socket is asynchronous but we are synchronous we need to wait until it is done */ - ast_mutex_lock(&rtp->lock); pj_turn_sock_alloc(*turn_sock, pj_cstr(&turn_addr, server), port, NULL, &cred, NULL); + ao2_lock(instance); + + /* + * Because the TURN socket is asynchronous and we are synchronous we need to + * wait until it is done + */ while (rtp->turn_state < PJ_TURN_STATE_READY) { - ast_cond_timedwait(&rtp->cond, &rtp->lock, &ts); + ast_cond_timedwait(&rtp->cond, ao2_object_get_lockaddr(instance), &ts); } - ast_mutex_unlock(&rtp->lock); /* If a TURN session was allocated add it as a candidate */ if (rtp->turn_state != PJ_TURN_STATE_READY) { @@ -1272,8 +1387,9 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast pj_turn_sock_get_info(*turn_sock, &info); - ast_rtp_ice_add_cand(rtp, component, conn_transport, PJ_ICE_CAND_TYPE_RELAYED, 65535, &info.relay_addr, - &info.relay_addr, &info.mapped_addr, pj_sockaddr_get_len(&info.relay_addr)); + ast_rtp_ice_add_cand(instance, rtp, component, conn_transport, + PJ_ICE_CAND_TYPE_RELAYED, 65535, &info.relay_addr, &info.relay_addr, + &info.mapped_addr, pj_sockaddr_get_len(&info.relay_addr)); if (component == AST_RTP_ICE_COMPONENT_RTP) { ast_sockaddr_copy(&rtp->rtp_loop, &loop); @@ -1295,6 +1411,7 @@ static char *generate_random_string(char *buf, size_t size) return buf; } +/*! \pre instance is locked */ static void ast_rtp_ice_change_components(struct ast_rtp_instance *instance, int num_components) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1364,8 +1481,6 @@ static int dtls_details_initialize(struct dtls_details *dtls, SSL_CTX *ssl_ctx, } dtls->connection = AST_RTP_DTLS_CONNECTION_NEW; - ast_mutex_init(&dtls->lock); - return 0; error: @@ -1397,6 +1512,7 @@ static int dtls_setup_rtcp(struct ast_rtp_instance *instance) return dtls_details_initialize(&rtp->rtcp->dtls, rtp->ssl_ctx, rtp->dtls.dtls_setup); } +/*! \pre instance is locked */ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1572,6 +1688,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con return res; } +/*! \pre instance is locked */ static int ast_rtp_dtls_active(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1579,12 +1696,15 @@ static int ast_rtp_dtls_active(struct ast_rtp_instance *instance) return !rtp->ssl_ctx ? 0 : 1; } +/*! \pre instance is locked */ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); SSL *ssl = rtp->dtls.ssl; + ao2_unlock(instance); dtls_srtp_stop_timeout_timer(instance, rtp, 0); + ao2_lock(instance); if (rtp->ssl_ctx) { SSL_CTX_free(rtp->ssl_ctx); @@ -1594,20 +1714,21 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) if (rtp->dtls.ssl) { SSL_free(rtp->dtls.ssl); rtp->dtls.ssl = NULL; - ast_mutex_destroy(&rtp->dtls.lock); } if (rtp->rtcp) { + ao2_unlock(instance); dtls_srtp_stop_timeout_timer(instance, rtp, 1); + ao2_lock(instance); if (rtp->rtcp->dtls.ssl && (rtp->rtcp->dtls.ssl != ssl)) { SSL_free(rtp->rtcp->dtls.ssl); rtp->rtcp->dtls.ssl = NULL; - ast_mutex_destroy(&rtp->rtcp->dtls.lock); } } } +/*! \pre instance is locked */ static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1623,6 +1744,7 @@ static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance) } } +/*! \pre instance is locked */ static enum ast_rtp_dtls_connection ast_rtp_dtls_get_connection(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1630,6 +1752,7 @@ static enum ast_rtp_dtls_connection ast_rtp_dtls_get_connection(struct ast_rtp_i return rtp->dtls.connection; } +/*! \pre instance is locked */ static enum ast_rtp_dtls_setup ast_rtp_dtls_get_setup(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1681,6 +1804,7 @@ static void dtls_set_setup(enum ast_rtp_dtls_setup *dtls_setup, enum ast_rtp_dtl } } +/*! \pre instance is locked */ static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1694,6 +1818,7 @@ static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_r } } +/*! \pre instance is locked */ static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint) { char *tmp = ast_strdupa(fingerprint), *value; @@ -1711,6 +1836,7 @@ static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum } } +/*! \pre instance is locked */ static enum ast_rtp_dtls_hash ast_rtp_dtls_get_fingerprint_hash(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1718,6 +1844,7 @@ static enum ast_rtp_dtls_hash ast_rtp_dtls_get_fingerprint_hash(struct ast_rtp_i return rtp->local_hash; } +/*! \pre instance is locked */ static const char *ast_rtp_dtls_get_fingerprint(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1777,6 +1904,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = { }; #ifdef HAVE_OPENSSL_SRTP +/*! \pre instance is locked */ static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtls_details *dtls, int rtcp) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1791,40 +1919,51 @@ static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtl SSL_do_handshake(dtls->ssl); - /* Since the handshake is started in a thread outside of the channel thread it's possible - * for the response to be handled in the channel thread before we start the timeout timer. - * To ensure this doesn't actually happen we hold the DTLS lock. The channel thread will - * block until we're done at which point the timeout timer will be immediately stopped. + /* + * A race condition is prevented between this function and __rtp_recvfrom() + * because both functions have to get the instance lock before they can do + * anything. Without holding the instance lock, this function could start + * the SSL handshake above in one thread and the __rtp_recvfrom() function + * called by the channel thread could read the response and stop the timeout + * timer before we have a chance to even start it. */ - ast_mutex_lock(&dtls->lock); - dtls_srtp_check_pending(instance, rtp, rtcp); dtls_srtp_start_timeout_timer(instance, rtp, rtcp); - ast_mutex_unlock(&dtls->lock); + + /* + * We must call dtls_srtp_check_pending() after starting the timer. + * Otherwise we won't prevent the race condition. + */ + dtls_srtp_check_pending(instance, rtp, rtcp); } #endif #ifdef HAVE_PJPROJECT static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq); +/* PJPROJECT ICE callback */ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) { struct ast_rtp_instance *instance = ice->user_data; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + ao2_lock(instance); if (status == PJ_SUCCESS) { struct ast_sockaddr remote_address; - /* Symmetric RTP must be disabled for the remote address to not get overwritten */ - ast_rtp_instance_set_prop(instance, AST_RTP_PROPERTY_NAT, 0); + ast_sockaddr_setnull(&remote_address); + update_address_with_ice_candidate(ice, AST_RTP_ICE_COMPONENT_RTP, &remote_address); + if (!ast_sockaddr_isnull(&remote_address)) { + /* Symmetric RTP must be disabled for the remote address to not get overwritten */ + ast_rtp_instance_set_prop(instance, AST_RTP_PROPERTY_NAT, 0); - update_address_with_ice_candidate(rtp, AST_RTP_ICE_COMPONENT_RTP, &remote_address); - ast_rtp_instance_set_remote_address(instance, &remote_address); + ast_rtp_instance_set_remote_address(instance, &remote_address); + } if (rtp->rtcp) { - update_address_with_ice_candidate(rtp, AST_RTP_ICE_COMPONENT_RTCP, &rtp->rtcp->them); + update_address_with_ice_candidate(ice, AST_RTP_ICE_COMPONENT_RTCP, &rtp->rtcp->them); } } - + #ifdef HAVE_OPENSSL_SRTP dtls_perform_handshake(instance, &rtp->dtls, 0); @@ -1834,13 +1973,16 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) #endif if (!strictrtp) { + ao2_unlock(instance); return; } rtp->strict_rtp_state = STRICT_RTP_LEARN; rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); + ao2_unlock(instance); } +/* PJPROJECT ICE callback */ static void ast_rtp_on_ice_rx_data(pj_ice_sess *ice, unsigned comp_id, unsigned transport_id, void *pkt, pj_size_t size, const pj_sockaddr_t *src_addr, unsigned src_addr_len) { struct ast_rtp_instance *instance = ice->user_data; @@ -1857,6 +1999,7 @@ static void ast_rtp_on_ice_rx_data(pj_ice_sess *ice, unsigned comp_id, unsigned } } +/* PJPROJECT ICE callback */ static pj_status_t ast_rtp_on_ice_tx_pkt(pj_ice_sess *ice, unsigned comp_id, unsigned transport_id, const void *pkt, pj_size_t size, const pj_sockaddr_t *dst_addr, unsigned dst_addr_len) { struct ast_rtp_instance *instance = ice->user_data; @@ -1953,6 +2096,7 @@ static inline int rtcp_debug_test_addr(struct ast_sockaddr *addr) } #ifdef HAVE_OPENSSL_SRTP +/*! \pre instance is locked */ static int dtls_srtp_handle_timeout(struct ast_rtp_instance *instance, int rtcp) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -1971,13 +2115,15 @@ static int dtls_srtp_handle_timeout(struct ast_rtp_instance *instance, int rtcp) return dtls_timeout.tv_sec * 1000 + dtls_timeout.tv_usec / 1000; } +/* Scheduler callback */ static int dtls_srtp_handle_rtp_timeout(const void *data) { struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data; int reschedule; + ao2_lock(instance); reschedule = dtls_srtp_handle_timeout(instance, 0); - + ao2_unlock(instance); if (!reschedule) { ao2_ref(instance, -1); } @@ -1985,13 +2131,15 @@ static int dtls_srtp_handle_rtp_timeout(const void *data) return reschedule; } +/* Scheduler callback */ static int dtls_srtp_handle_rtcp_timeout(const void *data) { struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data; int reschedule; + ao2_lock(instance); reschedule = dtls_srtp_handle_timeout(instance, 1); - + ao2_unlock(instance); if (!reschedule) { ao2_ref(instance, -1); } @@ -2019,6 +2167,7 @@ static void dtls_srtp_start_timeout_timer(struct ast_rtp_instance *instance, str } } +/*! \pre Must not be called with the instance locked. */ static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp) { struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; @@ -2026,6 +2175,7 @@ static void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, stru AST_SCHED_DEL_UNREF(rtp->sched, dtls->timeout_timer, ao2_ref(instance, -1)); } +/*! \pre instance is locked */ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp) { struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; @@ -2059,11 +2209,14 @@ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct as } } +/* Scheduler callback */ static int dtls_srtp_renegotiate(const void *data) { struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + ao2_lock(instance); + SSL_renegotiate(rtp->dtls.ssl); SSL_do_handshake(rtp->dtls.ssl); dtls_srtp_check_pending(instance, rtp, 0); @@ -2075,6 +2228,8 @@ static int dtls_srtp_renegotiate(const void *data) } rtp->rekeyid = -1; + + ao2_unlock(instance); ao2_ref(instance, -1); return 0; @@ -2216,6 +2371,7 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as } #endif +/*! \pre instance is locked */ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp) { int len; @@ -2244,14 +2400,18 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s return -1; } - /* This mutex is locked so that this thread blocks until the dtls_perform_handshake function - * completes. + /* + * A race condition is prevented between dtls_perform_handshake() + * and this function because both functions have to get the + * instance lock before they can do anything. The + * dtls_perform_handshake() function needs to start the timer + * before we stop it below. */ - ast_mutex_lock(&dtls->lock); - ast_mutex_unlock(&dtls->lock); /* Before we feed data into OpenSSL ensure that the timeout timer is either stopped or completed */ + ao2_unlock(instance); dtls_srtp_stop_timeout_timer(instance, rtp, rtcp); + ao2_lock(instance); /* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */ if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) { @@ -2302,14 +2462,22 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s pj_str_t combined = pj_str(ast_sockaddr_stringify(sa)); pj_sockaddr address; pj_status_t status; + struct ice_wrap *ice; pj_thread_register_check(); pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &combined, &address); - status = pj_ice_sess_on_rx_pkt(rtp->ice, rtcp ? AST_RTP_ICE_COMPONENT_RTCP : AST_RTP_ICE_COMPONENT_RTP, + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ice = rtp->ice; + ao2_ref(ice, +1); + ao2_unlock(instance); + status = pj_ice_sess_on_rx_pkt(ice->real_ice, + rtcp ? AST_RTP_ICE_COMPONENT_RTCP : AST_RTP_ICE_COMPONENT_RTP, rtcp ? TRANSPORT_SOCKET_RTCP : TRANSPORT_SOCKET_RTP, buf, len, &address, pj_sockaddr_get_len(&address)); + ao2_ref(ice, -1); + ao2_lock(instance); if (status != PJ_SUCCESS) { char buf[100]; @@ -2332,17 +2500,20 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s return len; } +/*! \pre instance is locked */ static int rtcp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) { return __rtp_recvfrom(instance, buf, size, flags, sa, 1); } +/*! \pre instance is locked */ static int rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) { return __rtp_recvfrom(instance, buf, size, flags, sa, 0); } -static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp) +/*! \pre instance is locked */ +static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *via_ice, int use_srtp) { int len = size; void *temp = buf; @@ -2350,7 +2521,7 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, rtcp); int res; - *ice = 0; + *via_ice = 0; if (use_srtp && res_srtp && srtp && res_srtp->protect(srtp, &temp, &len, rtcp) < 0) { return -1; @@ -2358,10 +2529,21 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz #ifdef HAVE_PJPROJECT if (rtp->ice) { + pj_status_t status; + struct ice_wrap *ice; + pj_thread_register_check(); - if (pj_ice_sess_send_data(rtp->ice, rtcp ? AST_RTP_ICE_COMPONENT_RTCP : AST_RTP_ICE_COMPONENT_RTP, temp, len) == PJ_SUCCESS) { - *ice = 1; + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ice = rtp->ice; + ao2_ref(ice, +1); + ao2_unlock(instance); + status = pj_ice_sess_send_data(ice->real_ice, + rtcp ? AST_RTP_ICE_COMPONENT_RTCP : AST_RTP_ICE_COMPONENT_RTP, temp, len); + ao2_ref(ice, -1); + ao2_lock(instance); + if (status == PJ_SUCCESS) { + *via_ice = 1; return len; } } @@ -2375,11 +2557,13 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz return res; } +/*! \pre instance is locked */ static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice) { return __rtp_sendto(instance, buf, size, flags, sa, 1, ice, 1); } +/*! \pre instance is locked */ static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -2554,6 +2738,7 @@ static int stun_address_is_blacklisted(const struct ast_sockaddr *addr) return result; } +/*! \pre instance is locked */ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_sockaddr *addr, int port, int component, int transport) { @@ -2578,8 +2763,9 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct basepos = pos; } pj_sockaddr_set_port(&address[pos], port); - ast_rtp_ice_add_cand(rtp, component, transport, PJ_ICE_CAND_TYPE_HOST, 65535, &address[pos], &address[pos], NULL, - pj_sockaddr_get_len(&address[pos])); + ast_rtp_ice_add_cand(instance, rtp, component, transport, + PJ_ICE_CAND_TYPE_HOST, 65535, &address[pos], &address[pos], NULL, + pj_sockaddr_get_len(&address[pos])); } } if (basepos == -1) { @@ -2591,8 +2777,17 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct if (stunaddr.sin_addr.s_addr && count && ast_sockaddr_is_ipv4(addr) && !stun_address_is_blacklisted(addr)) { struct sockaddr_in answer; + int rsp; - if (!ast_stun_request(component == AST_RTP_ICE_COMPONENT_RTCP ? rtp->rtcp->s : rtp->s, &stunaddr, NULL, &answer)) { + /* + * The instance should not be locked because we can block + * waiting for a STUN respone. + */ + ao2_unlock(instance); + rsp = ast_stun_request(component == AST_RTP_ICE_COMPONENT_RTCP + ? rtp->rtcp->s : rtp->s, &stunaddr, NULL, &answer); + ao2_lock(instance); + if (!rsp) { pj_sockaddr base; pj_sockaddr ext; pj_str_t mapped = pj_str(ast_strdupa(ast_inet_ntoa(answer.sin_addr))); @@ -2612,8 +2807,9 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct } if (srflx) { - ast_rtp_ice_add_cand(rtp, component, transport, PJ_ICE_CAND_TYPE_SRFLX, 65535, &ext, &base, - &base, pj_sockaddr_get_len(&ext)); + ast_rtp_ice_add_cand(instance, rtp, component, transport, + PJ_ICE_CAND_TYPE_SRFLX, 65535, &ext, &base, &base, + pj_sockaddr_get_len(&ext)); } } } @@ -2665,6 +2861,8 @@ static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery) * \param port port to use for adding RTP candidates to the ICE session * \param replace 0 when creating a new session, 1 when replacing a destroyed session * + * \pre instance is locked + * * \retval 0 on success * \retval -1 on failure */ @@ -2673,11 +2871,21 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad { pj_stun_config stun_config; pj_str_t ufrag, passwd; + pj_status_t status; + struct ice_wrap *ice_old; + struct ice_wrap *ice; + pj_ice_sess *real_ice = NULL; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); ao2_cleanup(rtp->ice_local_candidates); rtp->ice_local_candidates = NULL; + ice = ao2_alloc_options(sizeof(*ice), ice_wrap_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!ice) { + ast_rtp_ice_stop(instance); + return -1; + } + pj_thread_register_check(); pj_stun_config_init(&stun_config, &cachingpool.factory, 0, NULL, timer_heap); @@ -2685,11 +2893,23 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad ufrag = pj_str(rtp->local_ufrag); passwd = pj_str(rtp->local_passwd); + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); /* Create an ICE session for ICE negotiation */ - if (pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, rtp->ice_num_components, - &ast_rtp_ice_sess_cb, &ufrag, &passwd, NULL, &rtp->ice) == PJ_SUCCESS) { - /* Make this available for the callbacks */ - rtp->ice->user_data = instance; + status = pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, + rtp->ice_num_components, &ast_rtp_ice_sess_cb, &ufrag, &passwd, NULL, &real_ice); + ao2_lock(instance); + if (status == PJ_SUCCESS) { + /* Safely complete linking the ICE session into the instance */ + real_ice->user_data = instance; + ice->real_ice = real_ice; + ice_old = rtp->ice; + rtp->ice = ice; + if (ice_old) { + ao2_unlock(instance); + ao2_ref(ice_old, -1); + ao2_lock(instance); + } /* Add all of the available candidates to the ICE session */ rtp_add_candidates_to_ice(instance, rtp, addr, port, AST_RTP_ICE_COMPONENT_RTP, @@ -2707,11 +2927,19 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad return 0; } + /* + * It is safe to unref this while instance is locked here. + * It was not initialized with a real_ice pointer. + */ + ao2_ref(ice, -1); + + ast_rtp_ice_stop(instance); return -1; } #endif +/*! \pre instance is locked */ static int ast_rtp_new(struct ast_rtp_instance *instance, struct ast_sched_context *sched, struct ast_sockaddr *addr, void *data) @@ -2724,10 +2952,6 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, return -1; } - /* Initialize synchronization aspects */ - ast_mutex_init(&rtp->lock); - ast_cond_init(&rtp->cond, NULL); - /* Set default parameters on the newly created RTP structure */ rtp->ssrc = ast_random(); rtp->seqno = ast_random() & 0x7fff; @@ -2776,6 +3000,9 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, } #ifdef HAVE_PJPROJECT + /* Initialize synchronization aspects */ + ast_cond_init(&rtp->cond, NULL); + generate_random_string(rtp->local_ufrag, sizeof(rtp->local_ufrag)); generate_random_string(rtp->local_passwd, sizeof(rtp->local_passwd)); #endif @@ -2786,7 +3013,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, rtp->ice_num_components = 2; ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(addr), x, instance); if (ice_create(instance, addr, x, 0)) { - ast_log(LOG_NOTICE, "Failed to start ICE session\n"); + ast_log(LOG_NOTICE, "Failed to create ICE session\n"); } else { rtp->ice_port = x; ast_sockaddr_copy(&rtp->ice_original_rtp_addr, addr); @@ -2808,6 +3035,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, return 0; } +/*! \pre instance is locked */ static int ast_rtp_destroy(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -2844,7 +3072,9 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) /* Destroy RED if it was being used */ if (rtp->red) { + ao2_unlock(instance); AST_SCHED_DEL(rtp->sched, rtp->red->schedid); + ao2_lock(instance); ast_free(rtp->red); rtp->red = NULL; } @@ -2852,34 +3082,38 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) #ifdef HAVE_PJPROJECT pj_thread_register_check(); - /* Destroy the RTP TURN relay if being used */ - ast_mutex_lock(&rtp->lock); + /* + * The instance lock is already held. + * + * Destroy the RTP TURN relay if being used + */ if (rtp->turn_rtp) { - pj_turn_sock_destroy(rtp->turn_rtp); rtp->turn_state = PJ_TURN_STATE_NULL; + + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); + pj_turn_sock_destroy(rtp->turn_rtp); + ao2_lock(instance); while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) { - ast_cond_timedwait(&rtp->cond, &rtp->lock, &ts); + ast_cond_timedwait(&rtp->cond, ao2_object_get_lockaddr(instance), &ts); } } /* Destroy the RTCP TURN relay if being used */ if (rtp->turn_rtcp) { - pj_turn_sock_destroy(rtp->turn_rtcp); rtp->turn_state = PJ_TURN_STATE_NULL; + + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ + ao2_unlock(instance); + pj_turn_sock_destroy(rtp->turn_rtcp); + ao2_lock(instance); while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) { - ast_cond_timedwait(&rtp->cond, &rtp->lock, &ts); + ast_cond_timedwait(&rtp->cond, ao2_object_get_lockaddr(instance), &ts); } } - ast_mutex_unlock(&rtp->lock); - - if (rtp->ioqueue) { - rtp_ioqueue_thread_remove(rtp->ioqueue); - } - /* Destroy the ICE session if being used */ - if (rtp->ice) { - pj_ice_sess_destroy(rtp->ice); - } + /* Destroy any ICE session */ + ast_rtp_ice_stop(instance); /* Destroy any candidates */ if (rtp->ice_local_candidates) { @@ -2889,15 +3123,27 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) if (rtp->ice_active_remote_candidates) { ao2_ref(rtp->ice_active_remote_candidates, -1); } + + if (rtp->ioqueue) { + /* + * We cannot hold the instance lock because we could wait + * for the ioqueue thread to die and we might deadlock as + * a result. + */ + ao2_unlock(instance); + rtp_ioqueue_thread_remove(rtp->ioqueue); + ao2_lock(instance); + } #endif ao2_cleanup(rtp->lasttxformat); ao2_cleanup(rtp->lastrxformat); ao2_cleanup(rtp->f.subclass.format); +#ifdef HAVE_PJPROJECT /* Destroy synchronization items */ - ast_mutex_destroy(&rtp->lock); ast_cond_destroy(&rtp->cond); +#endif /* Finally destroy ourselves */ ast_free(rtp); @@ -2905,6 +3151,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) return 0; } +/*! \pre instance is locked */ static int ast_rtp_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -2912,12 +3159,14 @@ static int ast_rtp_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp return 0; } +/*! \pre instance is locked */ static enum ast_rtp_dtmf_mode ast_rtp_dtmf_mode_get(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); return rtp->dtmfmode; } +/*! \pre instance is locked */ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -2992,6 +3241,7 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) return 0; } +/*! \pre instance is locked */ static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -3037,6 +3287,7 @@ static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance) return 0; } +/*! \pre instance is locked */ static int ast_rtp_dtmf_end_with_duration(struct ast_rtp_instance *instance, char digit, unsigned int duration) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -3116,11 +3367,13 @@ static int ast_rtp_dtmf_end_with_duration(struct ast_rtp_instance *instance, cha return res; } +/*! \pre instance is locked */ static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit) { return ast_rtp_dtmf_end_with_duration(instance, digit, 0); } +/*! \pre instance is locked */ static void ast_rtp_update_source(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -3132,6 +3385,7 @@ static void ast_rtp_update_source(struct ast_rtp_instance *instance) return; } +/*! \pre instance is locked */ static void ast_rtp_change_source(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -3254,7 +3508,11 @@ static void calculate_lost_packet_statistics(struct ast_rtp *rtp, rtp->rtcp->rxlost_count++; } -/*! \brief Send RTCP SR or RR report */ +/*! + * \brief Send RTCP SR or RR report + * + * \pre instance is locked + */ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -3408,9 +3666,14 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) return res; } -/*! \brief Write and RTCP packet to the far end +/*! + * \brief Write a RTCP packet to the far end + * * \note Decide if we are going to send an SR (with Reception Block) or RR - * RR is sent if we have not sent any rtp packets in the previous interval */ + * RR is sent if we have not sent any rtp packets in the previous interval + * + * Scheduler callback + */ static int ast_rtcp_write(const void *data) { struct ast_rtp_instance *instance = (struct ast_rtp_instance *) data; @@ -3422,6 +3685,7 @@ static int ast_rtcp_write(const void *data) return 0; } + ao2_lock(instance); if (rtp->txcount > rtp->rtcp->lastsrtxcount) { /* Send an SR */ res = ast_rtcp_write_report(instance, 1); @@ -3429,6 +3693,7 @@ static int ast_rtcp_write(const void *data) /* Send an RR */ res = ast_rtcp_write_report(instance, 0); } + ao2_unlock(instance); if (!res) { /* @@ -3441,6 +3706,7 @@ static int ast_rtcp_write(const void *data) return res; } +/*! \pre instance is locked */ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *frame, int codec) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -3607,6 +3873,7 @@ static struct ast_frame *red_t140_to_red(struct rtp_red *red) return &red->t140red; } +/*! \pre instance is locked */ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -4432,6 +4699,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c } +/*! \pre instance is locked */ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -4483,10 +4751,12 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) return ast_rtcp_interpret(instance, read_area, res, &addr); } -static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int *rtpheader, int len, int hdrlen) +/*! \pre instance is locked */ +static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, + struct ast_rtp_instance *instance1, unsigned int *rtpheader, int len, int hdrlen) { - struct ast_rtp_instance *instance1 = ast_rtp_instance_get_bridged(instance); - struct ast_rtp *rtp = ast_rtp_instance_get_data(instance), *bridged = ast_rtp_instance_get_data(instance1); + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct ast_rtp *bridged = ast_rtp_instance_get_data(instance1); int res = 0, payload = 0, bridged_payload = 0, mark; RAII_VAR(struct ast_rtp_payload_type *, payload_type, NULL, ao2_cleanup); int reconstruct = ntohl(rtpheader[0]); @@ -4550,10 +4820,27 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int reconstruct |= (mark << 23); rtpheader[0] = htonl(reconstruct); + /* + * We have now determined that we need to send the RTP packet + * out the bridged instance to do local bridging so we must unlock + * the receiving instance to prevent deadlock with the bridged + * instance. + * + * Technically we should grab a ref to instance1 so it won't go + * away on us. However, we should be safe because the bridged + * instance won't change without both channels involved being + * locked and we currently have the channel lock for the receiving + * instance. + */ + ao2_unlock(instance); + ao2_lock(instance1); + ast_rtp_instance_get_remote_address(instance1, &remote_address); if (ast_sockaddr_isnull(&remote_address)) { ast_debug(5, "Remote address is null, most likely RTP has been stopped\n"); + ao2_unlock(instance1); + ao2_lock(instance); return 0; } @@ -4575,6 +4862,8 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int } ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN); } + ao2_unlock(instance1); + ao2_lock(instance); return 0; } @@ -4585,6 +4874,8 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int bridged_payload, len - hdrlen); } + ao2_unlock(instance1); + ao2_lock(instance); return 0; } @@ -4621,9 +4912,11 @@ static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet) return 0; } +/*! \pre instance is locked */ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct ast_rtp_instance *instance1; struct ast_sockaddr addr; int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno; unsigned char *read_area = rtp->rawdata + AST_FRIENDLY_OFFSET; @@ -4762,7 +5055,9 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } /* If we are directly bridged to another instance send the audio directly out */ - if (ast_rtp_instance_get_bridged(instance) && !bridge_p2p_rtp_write(instance, rtpheader, res, hdrlen)) { + instance1 = ast_rtp_instance_get_bridged(instance); + if (instance1 + && !bridge_p2p_rtp_write(instance, instance1, rtpheader, res, hdrlen)) { return &ast_null_frame; } @@ -5053,6 +5348,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc return AST_LIST_FIRST(&frames); } +/*! \pre instance is locked */ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -5168,14 +5464,17 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro } else { if (rtp->rtcp) { if (rtp->rtcp->schedid > -1) { + ao2_unlock(instance); if (!ast_sched_del(rtp->sched, rtp->rtcp->schedid)) { /* Successfully cancelled scheduler entry. */ ao2_ref(instance, -1); } else { /* Unable to cancel scheduler entry */ ast_debug(1, "Failed to tear down RTCP on RTP instance '%p'\n", instance); + ao2_lock(instance); return; } + ao2_lock(instance); rtp->rtcp->schedid = -1; } if (rtp->rtcp->s > -1 && rtp->rtcp->s != rtp->s) { @@ -5197,6 +5496,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro return; } +/*! \pre instance is locked */ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -5204,6 +5504,7 @@ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp) return rtcp ? (rtp->rtcp ? rtp->rtcp->s : -1) : rtp->s; } +/*! \pre instance is locked */ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -5245,19 +5546,26 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct } } -/*! \brief Write t140 redundacy frame +/*! + * \brief Write t140 redundacy frame + * * \param data primary data to be buffered + * + * Scheduler callback */ static int red_write(const void *data) { struct ast_rtp_instance *instance = (struct ast_rtp_instance*) data; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + ao2_lock(instance); ast_rtp_write(instance, &rtp->red->t140); + ao2_unlock(instance); return 1; } +/*! \pre instance is locked */ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -5290,6 +5598,7 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int return 0; } +/*! \pre instance is locked */ static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -5304,15 +5613,19 @@ static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *f return 0; } +/*! \pre Neither instance0 nor instance1 are locked */ static int ast_rtp_local_bridge(struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance0); + ao2_lock(instance0); ast_set_flag(rtp, FLAG_NEED_MARKER_BIT); + ao2_unlock(instance0); return 0; } +/*! \pre instance is locked */ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -5364,6 +5677,7 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in return 0; } +/*! \pre Neither instance0 nor instance1 are locked */ static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1) { /* If both sides are not using the same method of DTMF transmission @@ -5380,40 +5694,52 @@ static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_ins (!ast_channel_tech(chan0)->send_digit_begin != !ast_channel_tech(chan1)->send_digit_begin)) ? 0 : 1); } +/*! \pre instance is NOT locked */ static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct sockaddr_in suggestion_tmp; + /* + * The instance should not be locked because we can block + * waiting for a STUN respone. + */ ast_sockaddr_to_sin(suggestion, &suggestion_tmp); ast_stun_request(rtp->s, &suggestion_tmp, username, NULL); ast_sockaddr_from_sin(suggestion, &suggestion_tmp); } +/*! \pre instance is locked */ static void ast_rtp_stop(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_sockaddr addr = { {0,} }; #ifdef HAVE_OPENSSL_SRTP + ao2_unlock(instance); AST_SCHED_DEL_UNREF(rtp->sched, rtp->rekeyid, ao2_ref(instance, -1)); dtls_srtp_stop_timeout_timer(instance, rtp, 0); if (rtp->rtcp) { dtls_srtp_stop_timeout_timer(instance, rtp, 1); } + ao2_lock(instance); #endif if (rtp->rtcp && rtp->rtcp->schedid > -1) { + ao2_unlock(instance); if (!ast_sched_del(rtp->sched, rtp->rtcp->schedid)) { /* successfully cancelled scheduler entry. */ ao2_ref(instance, -1); } + ao2_lock(instance); rtp->rtcp->schedid = -1; } if (rtp->red) { + ao2_unlock(instance); AST_SCHED_DEL(rtp->sched, rtp->red->schedid); + ao2_lock(instance); ast_free(rtp->red); rtp->red = NULL; } @@ -5426,6 +5752,7 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance) ast_set_flag(rtp, FLAG_NEED_MARKER_BIT); } +/*! \pre instance is locked */ static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, const char *desc) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); @@ -5433,7 +5760,11 @@ static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, return ast_set_qos(rtp->s, tos, cos, desc); } -/*! \brief generate comfort noice (CNG) */ +/*! + * \brief generate comfort noice (CNG) + * + * \pre instance is locked + */ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level) { unsigned int *rtpheader; @@ -5498,6 +5829,7 @@ static void dtls_perform_setup(struct dtls_details *dtls) dtls->connection = AST_RTP_DTLS_CONNECTION_NEW; } +/*! \pre instance is locked */ static int ast_rtp_activate(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); From afad2ffd9f84bfb72c7649a6c40e663ce93e25bd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 19 Apr 2017 13:23:55 -0500 Subject: [PATCH 1209/1578] res_rtp_asterisk.c: Fix crash in RTCP DTLS operation. Occasionally a crash happens when processing the RTCP DTLS timeout handler. The RTCP DTLS timeout timer could be left running if we have not completed the DTLS handshake before we place the call on hold or we attempt direct media. * Made ast_rtp_prop_set() stop the RTCP DTLS timer when disabling RTCP. * Made some sanity tweaks to ast_rtp_prop_set() when switching from standard RTCP mode to RTCP multiplexed mode. ASTERISK-26692 #close Change-Id: If6c64c79129961acfa4b3d63a864e8f6b664acc0 --- res/res_rtp_asterisk.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index e2638320c57..d0d79593991 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1721,8 +1721,10 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) dtls_srtp_stop_timeout_timer(instance, rtp, 1); ao2_lock(instance); - if (rtp->rtcp->dtls.ssl && (rtp->rtcp->dtls.ssl != ssl)) { - SSL_free(rtp->rtcp->dtls.ssl); + if (rtp->rtcp->dtls.ssl) { + if (rtp->rtcp->dtls.ssl != ssl) { + SSL_free(rtp->rtcp->dtls.ssl); + } rtp->rtcp->dtls.ssl = NULL; } } @@ -5445,14 +5447,14 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro * to activating RTP. It is not until RTP is activated that timers start for RTCP * transmission */ - if (rtp->rtcp->s > -1) { + if (rtp->rtcp->s > -1 && rtp->rtcp->s != rtp->s) { close(rtp->rtcp->s); } rtp->rtcp->s = rtp->s; ast_rtp_instance_get_remote_address(instance, &addr); ast_sockaddr_copy(&rtp->rtcp->them, &addr); #ifdef HAVE_OPENSSL_SRTP - if (rtp->rtcp->dtls.ssl) { + if (rtp->rtcp->dtls.ssl && rtp->rtcp->dtls.ssl != rtp->dtls.ssl) { SSL_free(rtp->rtcp->dtls.ssl); } rtp->rtcp->dtls.ssl = rtp->dtls.ssl; @@ -5460,7 +5462,6 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro } ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance); - return; } else { if (rtp->rtcp) { if (rtp->rtcp->schedid > -1) { @@ -5481,6 +5482,10 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro close(rtp->rtcp->s); } #ifdef HAVE_OPENSSL_SRTP + ao2_unlock(instance); + dtls_srtp_stop_timeout_timer(instance, rtp, 1); + ao2_lock(instance); + if (rtp->rtcp->dtls.ssl && rtp->rtcp->dtls.ssl != rtp->dtls.ssl) { SSL_free(rtp->rtcp->dtls.ssl); } @@ -5489,11 +5494,8 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro ast_free(rtp->rtcp); rtp->rtcp = NULL; } - return; } } - - return; } /*! \pre instance is locked */ From c47b3e74d232820b79aa53c61a8fca112d128d20 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 19 Apr 2017 16:08:39 -0400 Subject: [PATCH 1210/1578] pbx: Use same thread if AST_OUTGOING_WAIT_COMPLETE specified Both ast_pbx_outgoing_app() and ast_pbx_outgoing_exten() cause the core to spawn a new thread to perform the dial. When AST_OUTGOING_WAIT_COMPLETE is passed to these functions, the calling thread will be blocked until the newly created channel has been hung up. After this patch, we run the dial on the current thread rather than spawning a new one. The only in-tree code that passes AST_OUTGOING_WAIT_COMPLETE is pbx_spool, so you should see reduced thread usage if you are using .call files. Change-Id: I512735d243f0a9da2bcc128f7a96dece71f2d913 --- main/pbx.c | 76 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/main/pbx.c b/main/pbx.c index dc4b91f0841..28027c06b8a 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -7529,8 +7529,8 @@ struct pbx_outgoing { int dial_res; /*! \brief Set when dialing is completed */ unsigned int dialed:1; - /*! \brief Set when execution is completed */ - unsigned int executed:1; + /*! \brief Set if we've spawned a thread to do our work */ + unsigned int in_separate_thread:1; }; /*! \brief Destructor for outgoing structure */ @@ -7553,13 +7553,19 @@ static void *pbx_outgoing_exec(void *data) RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup); enum ast_dial_result res; - /* Notify anyone interested that dialing is complete */ res = ast_dial_run(outgoing->dial, NULL, 0); - ao2_lock(outgoing); - outgoing->dial_res = res; - outgoing->dialed = 1; - ast_cond_signal(&outgoing->cond); - ao2_unlock(outgoing); + + if (outgoing->in_separate_thread) { + /* Notify anyone interested that dialing is complete */ + ao2_lock(outgoing); + outgoing->dial_res = res; + outgoing->dialed = 1; + ast_cond_signal(&outgoing->cond); + ao2_unlock(outgoing); + } else { + /* We still need the dial result, but we don't need to lock */ + outgoing->dial_res = res; + } /* If the outgoing leg was not answered we can immediately return and go no further */ if (res != AST_DIAL_RESULT_ANSWERED) { @@ -7599,12 +7605,6 @@ static void *pbx_outgoing_exec(void *data) } } - /* Notify anyone else again that may be interested that execution is complete */ - ao2_lock(outgoing); - outgoing->executed = 1; - ast_cond_signal(&outgoing->cond); - ao2_unlock(outgoing); - return NULL; } @@ -7810,34 +7810,42 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, } } + /* This extra reference is dereferenced by pbx_outgoing_exec */ ao2_ref(outgoing, +1); - if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) { - ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr); - ao2_ref(outgoing, -1); - if (locked_channel) { - if (!synchronous) { - ast_channel_unlock(dialed); + + if (synchronous == AST_OUTGOING_WAIT_COMPLETE) { + /* + * Because we are waiting until this is complete anyway, there is no + * sense in creating another thread that we will just need to wait + * for, so instead we commandeer the current thread. + */ + pbx_outgoing_exec(outgoing); + } else { + outgoing->in_separate_thread = 1; + + if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) { + ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr); + ao2_ref(outgoing, -1); + if (locked_channel) { + if (!synchronous) { + ast_channel_unlock(dialed); + } + ast_channel_unref(dialed); } - ast_channel_unref(dialed); + return -1; } - return -1; - } - if (synchronous) { - ao2_lock(outgoing); - /* Wait for dialing to complete */ - while (!outgoing->dialed) { - ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing)); - } - if (1 < synchronous - && outgoing->dial_res == AST_DIAL_RESULT_ANSWERED) { - /* Wait for execution to complete */ - while (!outgoing->executed) { + if (synchronous) { + ao2_lock(outgoing); + /* Wait for dialing to complete */ + while (!outgoing->dialed) { ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing)); } + ao2_unlock(outgoing); } - ao2_unlock(outgoing); + } + if (synchronous) { /* Determine the outcome of the dialing attempt up to it being answered. */ if (reason) { *reason = pbx_dial_reason(outgoing->dial_res, From b4b1943c5da420686db6e09628840d0f503ab043 Mon Sep 17 00:00:00 2001 From: Jean Aunis Date: Thu, 20 Apr 2017 09:13:13 +0200 Subject: [PATCH 1211/1578] chan_sip: Trigger reinvite if the SDP answer is included in the SIP ACK Some equipments may send a re-INVITE containing an SDP in the final ACK request. If this happens in the context of direct media, the remote end should be updated with a re-INVITE. This patch queues an "update RTP peer" frame to trigger the re-INVITE, instead of the "source change" frame wich was used previously. ASTERISK-26951 Change-Id: I3644d2025f20e086ea9f8f62b486172c52b5b2e6 --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index affe937e803..63b6606e269 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -28952,7 +28952,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as return -1; } if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { - ast_queue_control(p->owner, AST_CONTROL_SRCCHANGE); + ast_queue_control(p->owner, AST_CONTROL_UPDATE_RTP_PEER); } } sched_check_pendings(p); From 835c20944512db77f5366c4d9e3002b0dfdbd805 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 21 Apr 2017 12:07:39 -0500 Subject: [PATCH 1212/1578] res_pjsip_session.c: Restructure ast_sip_session_alloc() * Restructure ast_sip_session_alloc() to need less cleanup on off nominal error paths. * Made ast_sip_session_alloc() and ast_sip_session_create_outgoing() avoid unnecessary ref manipulation to return a session. This is faster than calling a function. That function may do logging of the ref changes with REF_DEBUG enabled. Change-Id: I2a0affc4be51013d3f0485782c96b8fee3ddb00a --- res/res_pjsip_session.c | 82 ++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 560b3903dd2..a8777415ae8 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1328,9 +1328,7 @@ static void session_destructor(void *obj) ao2_cleanup(session->req_caps); ao2_cleanup(session->direct_media_cap); - if (session->dsp) { - ast_dsp_free(session->dsp); - } + ast_dsp_free(session->dsp); if (session->inv_session) { pjsip_dlg_dec_session(session->inv_session->dlg, &session_module); @@ -1400,6 +1398,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_inv_session *inv_session, pjsip_rx_data *rdata) { RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup); + struct ast_sip_session *ret_session; struct ast_sip_session_supplement *iter; int dsp_features = 0; @@ -1407,12 +1406,39 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, if (!session) { return NULL; } + AST_LIST_HEAD_INIT(&session->supplements); + AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests); + ast_party_id_init(&session->id); + + session->direct_media_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!session->direct_media_cap) { + return NULL; + } + session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!session->req_caps) { + return NULL; + } session->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp); if (!session->datastores) { return NULL; } + if (endpoint->dtmf == AST_SIP_DTMF_INBAND || endpoint->dtmf == AST_SIP_DTMF_AUTO) { + dsp_features |= DSP_FEATURE_DIGIT_DETECT; + } + if (endpoint->faxdetect) { + dsp_features |= DSP_FEATURE_FAX_DETECT; + } + if (dsp_features) { + session->dsp = ast_dsp_new(); + if (!session->dsp) { + return NULL; + } + + ast_dsp_set_features(session->dsp, dsp_features); + } + session->endpoint = ao2_bump(endpoint); session->media = ao2_container_alloc(MEDIA_BUCKETS, session_media_hash, session_media_cmp); @@ -1449,30 +1475,6 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, inv_session->mod_data[session_module.id] = ao2_bump(session); session->contact = ao2_bump(contact); session->inv_session = inv_session; - session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!session->req_caps) { - /* Release the ref held by session->inv_session */ - ao2_ref(session, -1); - return NULL; - } - - if ((endpoint->dtmf == AST_SIP_DTMF_INBAND) || (endpoint->dtmf == AST_SIP_DTMF_AUTO)) { - dsp_features |= DSP_FEATURE_DIGIT_DETECT; - } - - if (endpoint->faxdetect) { - dsp_features |= DSP_FEATURE_FAX_DETECT; - } - - if (dsp_features) { - if (!(session->dsp = ast_dsp_new())) { - /* Release the ref held by session->inv_session */ - ao2_ref(session, -1); - return NULL; - } - - ast_dsp_set_features(session->dsp, dsp_features); - } if (add_supplements(session)) { /* Release the ref held by session->inv_session */ @@ -1484,11 +1486,11 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, iter->session_begin(session); } } - session->direct_media_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests); - ast_party_id_init(&session->id); - ao2_ref(session, +1); - return session; + + /* Avoid unnecessary ref manipulation to return a session */ + ret_session = session; + session = NULL; + return ret_session; } /*! \brief struct controlling the suspension of the session's serializer. */ @@ -1704,6 +1706,7 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint pjsip_dialog *dlg; struct pjsip_inv_session *inv_session; RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup); + struct ast_sip_session *ret_session; /* If no location has been provided use the AOR list from the endpoint itself */ if (location || !contact) { @@ -1760,14 +1763,17 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint if (ast_format_cap_count(req_caps)) { /* get joint caps between req_caps and endpoint caps */ struct ast_format_cap *joint_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - ast_format_cap_get_compatible(req_caps, session->endpoint->media.codecs, joint_caps); + + ast_format_cap_get_compatible(req_caps, endpoint->media.codecs, joint_caps); /* if joint caps */ if (ast_format_cap_count(joint_caps)) { /* copy endpoint caps into session->req_caps */ - ast_format_cap_append_from_cap(session->req_caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(session->req_caps, + endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); /* replace instances of joint caps equivalents in session->req_caps */ - ast_format_cap_replace_from_cap(session->req_caps, joint_caps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_replace_from_cap(session->req_caps, joint_caps, + AST_MEDIA_TYPE_UNKNOWN); } ao2_cleanup(joint_caps); } @@ -1781,8 +1787,10 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint return NULL; } - ao2_ref(session, +1); - return session; + /* Avoid unnecessary ref manipulation to return a session */ + ret_session = session; + session = NULL; + return ret_session; } void ast_sip_session_terminate(struct ast_sip_session *session, int response) From f1d20c84a164ed3502890c1f5cee803d2954b304 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 21 Apr 2017 12:33:34 -0500 Subject: [PATCH 1213/1578] res_pjsip_session.c: Send 100 Trying out earlier to prevent retransmissions. If ICE is enabled and a STUN server does not respond then we will block until we give up on the STUN response. This will take nine seconds. In the mean time the peer that sent the INVITE will send retransmissions. * Restructure res_pjsip_session.c:new_invite() to send a 100 Trying out earlier to prevent these retransmissions. ASTERISK-26890 Change-Id: Ie3fc611e53a0eff6586ad55e4aacad81cf6319a8 --- res/res_pjsip_session.c | 55 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index a8777415ae8..3034652a5a4 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2150,12 +2150,29 @@ static int new_invite(void *data) goto end; }; - if ((sdp_info = pjsip_rdata_get_sdp_info(invite->rdata)) && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) { + pjsip_timer_setting_default(&timer); + timer.min_se = invite->session->endpoint->extensions.timer.min_se; + timer.sess_expires = invite->session->endpoint->extensions.timer.sess_expires; + pjsip_timer_init_session(invite->session->inv_session, &timer); + + /* + * At this point, we've verified what we can that won't take awhile, + * so let's go ahead and send a 100 Trying out to stop any + * retransmissions. + */ + if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) { + pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); + goto end; + } + ast_sip_session_send_response(invite->session, tdata); + + sdp_info = pjsip_rdata_get_sdp_info(invite->rdata); + if (sdp_info && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) { if (handle_incoming_sdp(invite->session, sdp_info->sdp)) { - if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 488, NULL, NULL, &tdata) == PJ_SUCCESS) { + tdata = NULL; + if (pjsip_inv_end_session(invite->session->inv_session, 488, NULL, &tdata) == PJ_SUCCESS + && tdata) { ast_sip_session_send_response(invite->session, tdata); - } else { - pjsip_inv_terminate(invite->session->inv_session, 488, PJ_TRUE); } goto end; } @@ -2168,33 +2185,21 @@ static int new_invite(void *data) /* If we were unable to create a local SDP terminate the session early, it won't go anywhere */ if (!local) { - if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { + tdata = NULL; + if (pjsip_inv_end_session(invite->session->inv_session, 500, NULL, &tdata) == PJ_SUCCESS + && tdata) { ast_sip_session_send_response(invite->session, tdata); - } else { - pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); } goto end; - } else { - pjsip_inv_set_local_sdp(invite->session->inv_session, local); - pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE); -#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS - if (!invite->session->endpoint->preferred_codec_only) { - pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE); - } -#endif } - pjsip_timer_setting_default(&timer); - timer.min_se = invite->session->endpoint->extensions.timer.min_se; - timer.sess_expires = invite->session->endpoint->extensions.timer.sess_expires; - pjsip_timer_init_session(invite->session->inv_session, &timer); - - /* At this point, we've verified what we can, so let's go ahead and send a 100 Trying out */ - if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) { - pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); - goto end; + pjsip_inv_set_local_sdp(invite->session->inv_session, local); + pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE); +#ifdef PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS + if (!invite->session->endpoint->preferred_codec_only) { + pjmedia_sdp_neg_set_answer_multiple_codecs(invite->session->inv_session->neg, PJ_TRUE); } - ast_sip_session_send_response(invite->session, tdata); +#endif handle_incoming_request(invite->session, invite->rdata); From 59203c51cc6a9676ef1ab42aebe070a55f55ead2 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 17 Apr 2017 20:06:10 -0400 Subject: [PATCH 1214/1578] core: Use eventfd for alert pipes on Linux when possible The primary win of switching to eventfd when possible is that it only uses a single file descriptor while pipe() will use two. This means for each bridge channel we're reducing the number of required file descriptors by 1, and - if you're using timerfd - we also now have 1 less file descriptor per Asterisk channel. The API is not ideal (passing int arrays), but this is the cleanest approach I could come up with to maintain API/ABI. I've also removed what I believe to be an erroneous code block that checked the non-blocking flag on the pipe ends for each read. If the file descriptor is 'losing' its non-blocking mode, it is because of a bug somewhere else in our code. In my testing I haven't seen any measurable difference in performance. Change-Id: Iff0fb1573e7f7a187d5211ddc60aa8f3da3edb1d --- configure | 35 +++++++ configure.ac | 9 ++ include/asterisk/alertpipe.h | 159 +++++++++++++++++++++++++++++ include/asterisk/autoconfig.h.in | 4 + include/asterisk/channel.h | 7 +- main/alertpipe.c | 166 +++++++++++++++++++++++++++++++ main/bridge_channel.c | 87 ++-------------- main/channel_internal_api.c | 121 ++-------------------- main/utils.c | 3 + 9 files changed, 394 insertions(+), 197 deletions(-) create mode 100644 include/asterisk/alertpipe.h create mode 100644 main/alertpipe.c diff --git a/configure b/configure index dab70385346..89de95ae6bd 100755 --- a/configure +++ b/configure @@ -18009,6 +18009,41 @@ fi fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have usable eventfd support" >&5 +$as_echo_n "checking if we have usable eventfd support... " >&6; } +if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +return eventfd(0, EFD_NONBLOCK | EFD_SEMAPHORE) == -1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_EVENTFD 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute pure' support" >&5 $as_echo_n "checking for compiler 'attribute pure' support... " >&6; } diff --git a/configure.ac b/configure.ac index d8a567fa622..3bfb82eea35 100644 --- a/configure.ac +++ b/configure.ac @@ -1125,6 +1125,15 @@ if test "${ac_cv_have_variable_fdset}x" = "0x"; then AC_DEFINE([CONFIGURE_RAN_AS_ROOT], 1, [Some configure tests will unexpectedly fail if configure is run by a non-root user. These may be able to be tested at runtime.])) fi +AC_MSG_CHECKING([if we have usable eventfd support]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([#include ], + [return eventfd(0, EFD_NONBLOCK | EFD_SEMAPHORE) == -1;])], + AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_EVENTFD], 1, [Define to 1 if your system supports eventfd and the EFD_NONBLOCK and EFD_SEMAPHORE flags.]), + AC_MSG_RESULT(no) +) + AST_GCC_ATTRIBUTE(pure) AST_GCC_ATTRIBUTE(malloc) AST_GCC_ATTRIBUTE(const) diff --git a/include/asterisk/alertpipe.h b/include/asterisk/alertpipe.h new file mode 100644 index 00000000000..5ff854ce801 --- /dev/null +++ b/include/asterisk/alertpipe.h @@ -0,0 +1,159 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Sean Bright + * + * Sean Bright + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#ifndef ASTERISK_ALERTPIPE_H +#define ASTERISK_ALERTPIPE_H + +#include "asterisk/utils.h" + +typedef enum { + AST_ALERT_READ_SUCCESS = 0, + AST_ALERT_NOT_READABLE, + AST_ALERT_READ_FAIL, + AST_ALERT_READ_FATAL, +} ast_alert_status_t; + +/*! + * \brief Initialize an alert pipe + * \since 13.16.0 + * + * \param p a two-element array to hold the alert pipe's file descriptors + * + * \return non-zero if a failure occurred, zero otherwise. + */ +int ast_alertpipe_init(int alert_pipe[2]); + +/*! + * \brief Close an alert pipe + * \since 13.16.0 + * + * \param p a two-element containing the alert pipe's file descriptors + */ +void ast_alertpipe_close(int alert_pipe[2]); + +/*! + * \brief Read an event from an alert pipe + * \since 13.16.0 + * + * \param p a two-element array containing the alert pipe's file descriptors + * + * \retval AST_ALERT_READ_SUCCESS on success + * \retval AST_ALERT_NOT_READABLE if the alert pipe is not readable + * \retval AST_ALERT_READ_FATAL if the alert pipe's file descriptors are in + * blocking mode, or a read error occurs. + */ +ast_alert_status_t ast_alertpipe_read(int alert_pipe[2]); + +/*! + * \brief Write an event to an alert pipe + * \since 13.16.0 + * + * \param p a two-element array containing the alert pipe's file descriptors + * + * \return see write(2) + */ +ssize_t ast_alertpipe_write(int alert_pipe[2]); + +/*! + * \brief Consume all alerts written to the alert pipe + * \since 13.16.0 + * + * \param p a two-element array containing the alert pipe's file descriptors + * + * \retval AST_ALERT_READ_SUCCESS on success + * \retval AST_ALERT_NOT_READABLE if the alert pipe is not readable + * \retval AST_ALERT_READ_FATAL if the alert pipe's file descriptors are in + * blocking mode, or a read error occurs. + */ +ast_alert_status_t ast_alertpipe_flush(int alert_pipe[2]); + +/*! + * \brief Sets the alert pipe file descriptors to default values + * \since 13.16.0 + * + * \param p a two-element array containing the alert pipe's file descriptors + */ +AST_INLINE_API( +void ast_alertpipe_clear(int alert_pipe[2]), +{ + alert_pipe[0] = alert_pipe[1] = -1; +} +) + +/*! + * \brief Determine if the alert pipe is readable + * \since 13.16.0 + * + * \param p a two-element array containing the alert pipe's file descriptors + * + * \return non-zero if the alert pipe is readable, zero otherwise. + */ +AST_INLINE_API( +int attribute_pure ast_alertpipe_readable(int alert_pipe[2]), +{ + return alert_pipe[0] > -1; +} +) + +/*! + * \brief Determine if the alert pipe is writable + * \since 13.16.0 + * + * \param p a two-element array containing the alert pipe's file descriptors + * + * \return non-zero if the alert pipe is writable, zero otherwise. + */ +AST_INLINE_API( +int attribute_pure ast_alertpipe_writable(int alert_pipe[2]), +{ + return alert_pipe[1] > -1; +} +) + +/*! + * \brief Get the alert pipe's read file descriptor + * \since 13.16.0 + * + * \param p a two-element array containing the alert pipe's file descriptors + * + * \return -1 if the file descriptor is not initialized, a non-negative value + * otherwise. + */ +AST_INLINE_API( +int attribute_pure ast_alertpipe_readfd(int alert_pipe[2]), +{ + return alert_pipe[0]; +} +) + +/*! + * \brief Swap the file descriptors from two alert pipes + * \since 13.16.0 + * + * \param p1 a two-element array containing an alert pipe's file descriptors + * \param p2 a two-element array containing an alert pipe's file descriptors + */ +AST_INLINE_API( +void ast_alertpipe_swap(int alert_pipe_1[2], int alert_pipe_2[2]), +{ + SWAP(alert_pipe_1[0], alert_pipe_2[0]); + SWAP(alert_pipe_1[1], alert_pipe_2[1]); +} +) + +#endif /* ASTERISK_ALERTPIPE_H */ diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 5f8a9d37c82..b39386b4349 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -225,6 +225,10 @@ /* Define to 1 if you have the `euidaccess' function. */ #undef HAVE_EUIDACCESS +/* Define to 1 if your system supports eventfd and the EFD_NONBLOCK and + EFD_SEMAPHORE flags. */ +#undef HAVE_EVENTFD + /* Define to 1 if you have the `exp' function. */ #undef HAVE_EXP diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 32c9c7f67f2..3e04b5d0bb6 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -123,6 +123,7 @@ #ifndef _ASTERISK_CHANNEL_H #define _ASTERISK_CHANNEL_H +#include "asterisk/alertpipe.h" #include "asterisk/abstract_jb.h" #include "asterisk/astobj2.h" #include "asterisk/poll-compat.h" @@ -4267,12 +4268,6 @@ struct ast_namedgroups *ast_channel_named_pickupgroups(const struct ast_channel void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_namedgroups *value); /* Alertpipe accessors--the "internal" functions for channel.c use only */ -typedef enum { - AST_ALERT_READ_SUCCESS = 0, - AST_ALERT_NOT_READABLE, - AST_ALERT_READ_FAIL, - AST_ALERT_READ_FATAL, -} ast_alert_status_t; int ast_channel_alert_write(struct ast_channel *chan); int ast_channel_alert_writable(struct ast_channel *chan); ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan); diff --git a/main/alertpipe.c b/main/alertpipe.c new file mode 100644 index 00000000000..fa6ec7bcce3 --- /dev/null +++ b/main/alertpipe.c @@ -0,0 +1,166 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Sean Bright + * + * Sean Bright + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Alert Pipe API + * + * \author Sean Bright + */ + +#include "asterisk.h" + +#include +#include + +#ifdef HAVE_EVENTFD +# include +#endif + +#include "asterisk/alertpipe.h" +#include "asterisk/logger.h" + +int ast_alertpipe_init(int alert_pipe[2]) +{ +#ifdef HAVE_EVENTFD + + int fd = eventfd(0, EFD_NONBLOCK | EFD_SEMAPHORE); + if (fd > -1) { + alert_pipe[0] = alert_pipe[1] = fd; + return 0; + } + + ast_log(LOG_WARNING, "Failed to create alert pipe with eventfd(), falling back to pipe(): %s\n", + strerror(errno)); + ast_alertpipe_clear(alert_pipe); + +#endif + + if (pipe(alert_pipe)) { + ast_log(LOG_WARNING, "Failed to create alert pipe: %s\n", strerror(errno)); + return -1; + } else { + int flags = fcntl(alert_pipe[0], F_GETFL); + if (fcntl(alert_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) { + ast_log(LOG_WARNING, "Failed to set non-blocking mode on alert pipe: %s\n", + strerror(errno)); + ast_alertpipe_close(alert_pipe); + return -1; + } + flags = fcntl(alert_pipe[1], F_GETFL); + if (fcntl(alert_pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) { + ast_log(LOG_WARNING, "Failed to set non-blocking mode on alert pipe: %s\n", + strerror(errno)); + ast_alertpipe_close(alert_pipe); + return -1; + } + } + + return 0; +} + +void ast_alertpipe_close(int alert_pipe[2]) +{ +#ifdef HAVE_EVENTFD + + if (alert_pipe[0] == alert_pipe[1]) { + if (alert_pipe[0] > -1) { + close(alert_pipe[0]); + ast_alertpipe_clear(alert_pipe); + } + return; + } + +#endif + + if (alert_pipe[0] > -1) { + close(alert_pipe[0]); + } + if (alert_pipe[1] > -1) { + close(alert_pipe[1]); + } + ast_alertpipe_clear(alert_pipe); +} + +ast_alert_status_t ast_alertpipe_read(int alert_pipe[2]) +{ + uint64_t tmp; + + if (!ast_alertpipe_readable(alert_pipe)) { + return AST_ALERT_NOT_READABLE; + } + + if (read(alert_pipe[0], &tmp, sizeof(tmp)) < 0) { + if (errno != EINTR && errno != EAGAIN) { + ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno)); + return AST_ALERT_READ_FAIL; + } + } + + return AST_ALERT_READ_SUCCESS; +} + +ssize_t ast_alertpipe_write(int alert_pipe[2]) +{ + uint64_t tmp = 1; + + if (!ast_alertpipe_writable(alert_pipe)) { + errno = EBADF; + return 0; + } + + /* preset errno in case returned size does not match */ + errno = EPIPE; + return write(alert_pipe[1], &tmp, sizeof(tmp)) != sizeof(tmp); +} + +ast_alert_status_t ast_alertpipe_flush(int alert_pipe[2]) +{ + int bytes_read; + uint64_t tmp[16]; + + if (!ast_alertpipe_readable(alert_pipe)) { + return AST_ALERT_NOT_READABLE; + } + + /* Read the alertpipe until it is exhausted. */ + for (;;) { + bytes_read = read(alert_pipe[0], tmp, sizeof(tmp)); + if (bytes_read < 0) { + if (errno == EINTR) { + continue; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* + * Would block so nothing left to read. + * This is the normal loop exit. + */ + break; + } + ast_log(LOG_WARNING, "read() failed flushing alertpipe: %s\n", + strerror(errno)); + return AST_ALERT_READ_FAIL; + } + if (!bytes_read) { + /* Read nothing so we are done */ + break; + } + } + + return AST_ALERT_READ_SUCCESS; +} diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 7f3c8fe3106..89222d365e7 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -35,6 +35,7 @@ #include #include "asterisk/heap.h" +#include "asterisk/alertpipe.h" #include "asterisk/astobj2.h" #include "asterisk/stringfields.h" #include "asterisk/app.h" @@ -954,7 +955,6 @@ static void bridge_frame_free(struct ast_frame *frame) int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr) { struct ast_frame *dup; - char nudge = 0; if (bridge_channel->suspended /* Also defer DTMF frames. */ @@ -983,7 +983,7 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st } AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list); - if (write(bridge_channel->alert_pipe[1], &nudge, sizeof(nudge)) != sizeof(nudge)) { + if (ast_alertpipe_write(bridge_channel->alert_pipe)) { ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n", bridge_channel, ast_channel_name(bridge_channel->chan)); } @@ -2255,25 +2255,6 @@ static void bridge_channel_handle_control(struct ast_bridge_channel *bridge_chan } } -/*! - * \internal - * \param bridge_channel Channel to read wr_queue alert pipe. - * - * \return Nothing - */ -static void bridge_channel_read_wr_queue_alert(struct ast_bridge_channel *bridge_channel) -{ - char nudge; - - if (read(bridge_channel->alert_pipe[0], &nudge, sizeof(nudge)) < 0) { - if (errno != EINTR && errno != EAGAIN) { - ast_log(LOG_WARNING, "read() failed for alert pipe on %p(%s): %s\n", - bridge_channel, ast_channel_name(bridge_channel->chan), - strerror(errno)); - } - } -} - /*! * \internal * \brief Handle bridge channel write frame to channel. @@ -2296,7 +2277,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe /* No frame, flush the alert pipe of excess alerts. */ ast_log(LOG_WARNING, "Weird. No frame from bridge for %s to process?\n", ast_channel_name(bridge_channel->chan)); - bridge_channel_read_wr_queue_alert(bridge_channel); + ast_alertpipe_read(bridge_channel->alert_pipe); ast_bridge_channel_unlock(bridge_channel); return; } @@ -2312,7 +2293,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe break; } } - bridge_channel_read_wr_queue_alert(bridge_channel); + ast_alertpipe_read(bridge_channel->alert_pipe); AST_LIST_REMOVE_CURRENT(frame_list); break; } @@ -2879,62 +2860,6 @@ int bridge_channel_internal_allows_optimization(struct ast_bridge_channel *bridg && AST_LIST_EMPTY(&bridge_channel->wr_queue); } -/*! - * \internal - * \brief Close a pipe. - * \since 12.0.0 - * - * \param my_pipe What to close. - * - * \return Nothing - */ -static void pipe_close(int *my_pipe) -{ - if (my_pipe[0] > -1) { - close(my_pipe[0]); - my_pipe[0] = -1; - } - if (my_pipe[1] > -1) { - close(my_pipe[1]); - my_pipe[1] = -1; - } -} - -/*! - * \internal - * \brief Initialize a pipe as non-blocking. - * \since 12.0.0 - * - * \param my_pipe What to initialize. - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int pipe_init_nonblock(int *my_pipe) -{ - int flags; - - my_pipe[0] = -1; - my_pipe[1] = -1; - if (pipe(my_pipe)) { - ast_log(LOG_WARNING, "Can't create pipe! Try increasing max file descriptors with ulimit -n\n"); - return -1; - } - flags = fcntl(my_pipe[0], F_GETFL); - if (fcntl(my_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "Unable to set read pipe nonblocking! (%d: %s)\n", - errno, strerror(errno)); - return -1; - } - flags = fcntl(my_pipe[1], F_GETFL); - if (fcntl(my_pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "Unable to set write pipe nonblocking! (%d: %s)\n", - errno, strerror(errno)); - return -1; - } - return 0; -} - /* Destroy elements of the bridge channel structure and the bridge channel structure itself */ static void bridge_channel_destroy(void *obj) { @@ -2954,7 +2879,7 @@ static void bridge_channel_destroy(void *obj) while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list))) { bridge_frame_free(fr); } - pipe_close(bridge_channel->alert_pipe); + ast_alertpipe_close(bridge_channel->alert_pipe); ast_cond_destroy(&bridge_channel->cond); @@ -2971,7 +2896,7 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid return NULL; } ast_cond_init(&bridge_channel->cond, NULL); - if (pipe_init_nonblock(bridge_channel->alert_pipe)) { + if (ast_alertpipe_init(bridge_channel->alert_pipe)) { ao2_ref(bridge_channel, -1); return NULL; } diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index b3c0a480538..d838ea80cfb 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -36,6 +36,7 @@ #include #include +#include "asterisk/alertpipe.h" #include "asterisk/paths.h" #include "asterisk/channel.h" #include "asterisk/channel_internal.h" @@ -1265,152 +1266,52 @@ void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_nam /* Alertpipe functions */ int ast_channel_alert_write(struct ast_channel *chan) { - char blah = 0x7F; - - if (!ast_channel_alert_writable(chan)) { - errno = EBADF; - return 0; - } - /* preset errno in case returned size does not match */ - errno = EPIPE; - return write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah); -} - -static int channel_internal_alert_check_nonblock(struct ast_channel *chan) -{ - int flags; - - flags = fcntl(chan->alertpipe[0], F_GETFL); - /* For some odd reason, the alertpipe occasionally loses nonblocking status, - * which immediately causes a deadlock scenario. Detect and prevent this. */ - if ((flags & O_NONBLOCK) == 0) { - ast_log(LOG_ERROR, "Alertpipe on channel %s lost O_NONBLOCK?!!\n", ast_channel_name(chan)); - if (fcntl(chan->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno)); - return -1; - } - } - return 0; + return ast_alertpipe_write(chan->alertpipe); } ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan) { - int bytes_read; - char blah[100]; - - if (!ast_channel_internal_alert_readable(chan)) { - return AST_ALERT_NOT_READABLE; - } - if (channel_internal_alert_check_nonblock(chan)) { - return AST_ALERT_READ_FATAL; - } - - /* Read the alertpipe until it is exhausted. */ - for (;;) { - bytes_read = read(chan->alertpipe[0], blah, sizeof(blah)); - if (bytes_read < 0) { - if (errno == EINTR) { - continue; - } - if (errno == EAGAIN || errno == EWOULDBLOCK) { - /* - * Would block so nothing left to read. - * This is the normal loop exit. - */ - break; - } - ast_log(LOG_WARNING, "read() failed flushing alertpipe: %s\n", - strerror(errno)); - return AST_ALERT_READ_FAIL; - } - if (!bytes_read) { - /* Read nothing so we are done */ - break; - } - } - - return AST_ALERT_READ_SUCCESS; + return ast_alertpipe_flush(chan->alertpipe); } ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan) { - char blah; - - if (!ast_channel_internal_alert_readable(chan)) { - return AST_ALERT_NOT_READABLE; - } - if (channel_internal_alert_check_nonblock(chan)) { - return AST_ALERT_READ_FATAL; - } - - if (read(chan->alertpipe[0], &blah, sizeof(blah)) < 0) { - if (errno != EINTR && errno != EAGAIN) { - ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno)); - return AST_ALERT_READ_FAIL; - } - } - - return AST_ALERT_READ_SUCCESS; + return ast_alertpipe_read(chan->alertpipe); } int ast_channel_alert_writable(struct ast_channel *chan) { - return chan->alertpipe[1] > -1; + return ast_alertpipe_writable(chan->alertpipe); } int ast_channel_internal_alert_readable(struct ast_channel *chan) { - return chan->alertpipe[0] > -1; + return ast_alertpipe_readable(chan->alertpipe); } void ast_channel_internal_alertpipe_clear(struct ast_channel *chan) { - chan->alertpipe[0] = chan->alertpipe[1] = -1; + ast_alertpipe_clear(chan->alertpipe); } void ast_channel_internal_alertpipe_close(struct ast_channel *chan) { - if (ast_channel_internal_alert_readable(chan)) { - close(chan->alertpipe[0]); - chan->alertpipe[0] = -1; - } - if (ast_channel_alert_writable(chan)) { - close(chan->alertpipe[1]); - chan->alertpipe[1] = -1; - } + ast_alertpipe_close(chan->alertpipe); } int ast_channel_internal_alertpipe_init(struct ast_channel *chan) { - if (pipe(chan->alertpipe)) { - ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe! Try increasing max file descriptors with ulimit -n\n"); - return -1; - } else { - int flags = fcntl(chan->alertpipe[0], F_GETFL); - if (fcntl(chan->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "Channel allocation failed: Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno)); - return -1; - } - flags = fcntl(chan->alertpipe[1], F_GETFL); - if (fcntl(chan->alertpipe[1], F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "Channel allocation failed: Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno)); - return -1; - } - } - return 0; + return ast_alertpipe_init(chan->alertpipe); } int ast_channel_internal_alert_readfd(struct ast_channel *chan) { - return chan->alertpipe[0]; + return ast_alertpipe_readfd(chan->alertpipe); } void ast_channel_internal_alertpipe_swap(struct ast_channel *chan1, struct ast_channel *chan2) { - int i; - for (i = 0; i < ARRAY_LEN(chan1->alertpipe); i++) { - SWAP(chan1->alertpipe[i], chan2->alertpipe[i]); - } + ast_alertpipe_swap(chan1->alertpipe, chan2->alertpipe); } /* file descriptor array accessors */ diff --git a/main/utils.c b/main/utils.c index 2033664b84d..c254db52060 100644 --- a/main/utils.c +++ b/main/utils.c @@ -67,6 +67,9 @@ #define AST_API_MODULE #include "asterisk/config.h" +#define AST_API_MODULE +#include "asterisk/alertpipe.h" + static char base64[64]; static char b2a[256]; From 0611f2ca17515a58957b7b635429371a68858931 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 24 Apr 2017 14:16:45 -0400 Subject: [PATCH 1215/1578] res_hep: Add additional config initialization and validation * Initialize hepv3_runtime_data.sockfd to -1 so that our ao2 destructor does not close fd 0 * Add logging output when the required option - capture_address - is not specified. * Remove a no longer relevant #define and correct related documentation * Pass appropriate flags to aco_option_register so that capture_address cannot be the empty string. ASTERISK-26953 #close Change-Id: Ief08441bc6596d6f1718fa810e54a5048124f076 --- res/res_hep.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/res/res_hep.c b/res/res_hep.c index 41a55814158..25b4d13b1e0 100644 --- a/res/res_hep.c +++ b/res/res_hep.c @@ -69,7 +69,7 @@ - + The address and port of the Homer server to send packets to. @@ -96,8 +96,6 @@ #include #include -#define DEFAULT_HEP_SERVER "" - /*! Generic vendor ID. Used for HEPv3 standard packets */ #define GENERIC_VENDOR_ID 0x0000 @@ -280,11 +278,13 @@ static AO2_GLOBAL_OBJ_STATIC(global_data); static struct ast_taskprocessor *hep_queue_tp; static void *module_config_alloc(void); +static int hepv3_config_pre_apply(void); static void hepv3_config_post_apply(void); /*! \brief Register information about the configs being processed by this module */ CONFIG_INFO_STANDARD(cfg_info, global_config, module_config_alloc, .files = ACO_FILES(&hepv3_conf), + .pre_apply_config = hepv3_config_pre_apply, .post_apply_config = hepv3_config_post_apply, ); @@ -377,6 +377,8 @@ static struct hepv3_runtime_data *hepv3_data_alloc(struct hepv3_global_config *c return NULL; } + data->sockfd = -1; + if (!ast_sockaddr_parse(&data->remote_addr, config->capture_address, PARSE_PORT_REQUIRE)) { ast_log(AST_LOG_WARNING, "Failed to create address from %s\n", config->capture_address); ao2_ref(data, -1); @@ -593,12 +595,34 @@ int hepv3_send_packet(struct hepv3_capture_info *capture_info) return res; } +/*! + * \brief Pre-apply callback for the config framework. + * + * This validates that required fields exist and are populated. + */ +static int hepv3_config_pre_apply(void) +{ + struct module_config *config = aco_pending_config(&cfg_info); + + if (!config->general->enabled) { + /* If we're not enabled, we don't care about anything else */ + return 0; + } + + if (ast_strlen_zero(config->general->capture_address)) { + ast_log(AST_LOG_ERROR, "Missing required configuration option 'capture_address'\n"); + return -1; + } + + return 0; +} + /*! * \brief Post-apply callback for the config framework. * * This will create the run-time information from the supplied * configuration. -*/ + */ static void hepv3_config_post_apply(void) { RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(global_config), ao2_cleanup); @@ -653,7 +677,7 @@ static int load_module(void) } aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options, "yes", OPT_BOOL_T, 1, FLDSET(struct hepv3_global_config, enabled)); - aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, DEFAULT_HEP_SERVER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_address)); + aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct hepv3_global_config, capture_address)); aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password)); aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id)); aco_option_register_custom(&cfg_info, "uuid_type", ACO_EXACT, global_options, "call-id", uuid_type_handler, 0); From 32b3e36c683da0cea37a01c006037ff31f8a2b1d Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 21 Mar 2017 15:44:44 -0500 Subject: [PATCH 1216/1578] SDP: Ensure SDPs "merge" properly. The gist of this work ensures that when a remote SDP is received, it is merged properly with the local capabilities. The remote SDP is converted into a stream topology. That topology is then merged with the current local topology on the SDP state. That new merged topology is then used to create an SDP. Finally, adjustments are made to RTP instances based on knowledge gained from the remote SDP. There are also a battery of tests in this commit that ensure that some basic SDP merges work as expected. While this may not sound like a big change, it has the property that it caused lots of ancillary changes. * The remote SDP is no longer stored on the SDP state. Biggest reason: there's no need for it. The remote SDP is used at the time it is being set and nowhere else. * Some new SDP APIs were added in order to find attributes and convert generic SDP attributes into rtpmap structures. * Writing tests made me realize that retrieving a value from an SDP options structure, the SDP options needs to be made const. * The SDP state machine was essentially gutted by a previous commit. Initially, I attempted to reinstate it, but I found that as it had been defined, it was not all that useful. What was more useful was knowing the role we play in SDP negotiation, so the SDP state machine has been transformed into an indicator of role. * Rather than storing separate local and joint stream state capabilities, it makes more sense to keep track of current stream state and update it as things change. Change-Id: I5938c2be3c6f0a003aa88a39a59e0880f8b2df3d --- include/asterisk/codec.h | 11 + include/asterisk/sdp.h | 99 +++- include/asterisk/sdp_options.h | 51 +- include/asterisk/sdp_state.h | 2 +- main/codec.c | 15 + main/sdp.c | 365 +++++++----- main/sdp_options.c | 5 +- main/sdp_private.h | 1 + main/sdp_state.c | 1010 ++++++++++++++++++++++++++------ tests/test_sdp.c | 821 ++++++++++++++++++++++++++ 10 files changed, 2025 insertions(+), 355 deletions(-) create mode 100644 tests/test_sdp.c diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h index 2ae9551816d..2f5756cd14f 100644 --- a/include/asterisk/codec.h +++ b/include/asterisk/codec.h @@ -165,6 +165,17 @@ int ast_codec_get_max(void); */ const char *ast_codec_media_type2str(enum ast_media_type type); +/*! + * \brief Conversion function to take a media string and convert it to a media type + * + * \param media_type_str The media type string + * + * \retval The ast_media_type that corresponds to the string + * + * \since 15.0.0 + */ +enum ast_media_type ast_media_type_from_str(const char *media_type_str); + /*! * \brief Get the number of samples contained within a frame * diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h index 3649b403778..d5bf9147b24 100644 --- a/include/asterisk/sdp.h +++ b/include/asterisk/sdp.h @@ -146,6 +146,22 @@ struct ast_sdp { struct ast_sdp_m_lines *m_lines; }; +/*! + * \brief A structure representing an SDP rtpmap attribute + */ +struct ast_sdp_rtpmap { + /*! The RTP payload number for the rtpmap */ + int payload; + /*! The Name of the codec */ + char *encoding_name; + /*! The clock rate of the codec */ + int clock_rate; + /*! Optional encoding parameters */ + char *encoding_parameters; + /*! Area where strings are stored */ + char buf[0]; +}; + /*! * \brief Free an SDP Attribute * @@ -545,15 +561,88 @@ struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line, struct ast_sdp_t_line *t_line); /*! - * \brief Create an SDP from an existing SDP State local topology + * \brief Find an attribute on the top-level SDP + * + * \note This will not search within streams for the given attribute. + * + * \param sdp The SDP in which to search + * \param attr_name The name of the attribute to search for + * \param payload Optional payload number to search for. If irrelevant, set to -1 + * + * \retval NULL Could not find the given attribute + * \retval Non-NULL The attribute to find + * + * \since 15.0.0 + */ +struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp, + const char *attr_name, int payload); + +/*! + * \brief Find an attribute on an SDP stream (m-line) * - * \param sdp_state SDP State + * \param sdp The SDP in which to search + * \param attr_name The name of the attribute to search for + * \param payload Optional payload number to search for. If irrelevant, set to -1 * + * \retval NULL Could not find the given attribute + * \retval Non-NULL The attribute to find + * + * \since 15.0.0 + */ +struct ast_sdp_a_line *ast_sdp_m_find_attribute(const struct ast_sdp_m_line *m_line, + const char *attr_name, int payload); + +/*! + * \brief Convert an SDP a_line into an rtpmap + * + * The returned value is heap-allocated and must be freed with + * ast_sdp_rtpmap_free() + * + * \param a_line The SDP a_line to convert + * + * \retval NULL Fail * \retval non-NULL Success - * \retval NULL Failure * - * \since 15 + * \since 15.0.0 */ -struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state); +struct ast_sdp_rtpmap *ast_sdp_a_get_rtpmap(const struct ast_sdp_a_line *a_line); + +/*! + * \brief Allocate a new SDP rtpmap + * + * \param payload The RTP payload number + * \param encoding_name The human-readable name for the codec + * \param clock_rate The rate of the codec, in cycles per second + * \param encoding_parameters Optional codec-specific parameters (such as number of channels) + * + * \retval NULL Fail + * \retval non-NULL Success + * + * \since 15.0.0 + */ +struct ast_sdp_rtpmap *ast_sdp_rtpmap_alloc(int payload, const char *encoding_name, + int clock_rate, const char *encoding_parameters); + +/*! + * \brief Free an SDP rtpmap + * + * \since 15.0.0 + */ +void ast_sdp_rtpmap_free(struct ast_sdp_rtpmap *rtpmap); + +/*! + * \brief Turn an SDP into a stream topology + * + * This traverses the m-lines of the SDP and creates a stream topology, with + * each m-line corresponding to a stream in the created topology. + * + * \param sdp The SDP to convert + * + * \retval NULL An error occurred when converting + * \retval non-NULL The generated stream topology + * + * \since 15.0.0 + */ +struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp); #endif /* _SDP_PRIV_H */ diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index 0186eea57c8..4b411c77122 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -106,7 +106,7 @@ void ast_sdp_options_set_media_address(struct ast_sdp_options *options, * * \returns media_address */ -const char *ast_sdp_options_get_media_address(struct ast_sdp_options *options); +const char *ast_sdp_options_get_media_address(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -126,7 +126,7 @@ void ast_sdp_options_set_sdpowner(struct ast_sdp_options *options, * * \returns sdpowner */ -const char *ast_sdp_options_get_sdpowner(struct ast_sdp_options *options); +const char *ast_sdp_options_get_sdpowner(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -146,7 +146,7 @@ void ast_sdp_options_set_sdpsession(struct ast_sdp_options *options, * * \returns sdpsession */ -const char *ast_sdp_options_get_sdpsession(struct ast_sdp_options *options); +const char *ast_sdp_options_get_sdpsession(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -166,7 +166,7 @@ void ast_sdp_options_set_rtp_engine(struct ast_sdp_options *options, * * \returns rtp_engine */ -const char *ast_sdp_options_get_rtp_engine(struct ast_sdp_options *options); +const char *ast_sdp_options_get_rtp_engine(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -186,7 +186,7 @@ void ast_sdp_options_set_bind_rtp_to_media_address(struct ast_sdp_options *optio * * \returns bind_rtp_to_media_address */ -unsigned int ast_sdp_options_get_bind_rtp_to_media_address(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_bind_rtp_to_media_address(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -206,7 +206,7 @@ void ast_sdp_options_set_rtp_symmetric(struct ast_sdp_options *options, * * \returns rtp_symmetric */ -unsigned int ast_sdp_options_get_rtp_symmetric(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_rtp_symmetric(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -226,7 +226,7 @@ void ast_sdp_options_set_telephone_event(struct ast_sdp_options *options, * * \returns telephone_event */ -unsigned int ast_sdp_options_get_telephone_event(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_telephone_event(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -246,7 +246,7 @@ void ast_sdp_options_set_rtp_ipv6(struct ast_sdp_options *options, * * \returns rtp_ipv6 */ -unsigned int ast_sdp_options_get_rtp_ipv6(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_rtp_ipv6(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -266,7 +266,7 @@ void ast_sdp_options_set_g726_non_standard(struct ast_sdp_options *options, * * \returns g726_non_standard */ -unsigned int ast_sdp_options_get_g726_non_standard(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_g726_non_standard(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -286,7 +286,7 @@ void ast_sdp_options_set_tos_audio(struct ast_sdp_options *options, * * \returns tos_audio */ -unsigned int ast_sdp_options_get_tos_audio(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_tos_audio(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -306,7 +306,7 @@ void ast_sdp_options_set_cos_audio(struct ast_sdp_options *options, * * \returns cos_audio */ -unsigned int ast_sdp_options_get_cos_audio(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_cos_audio(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -326,7 +326,7 @@ void ast_sdp_options_set_tos_video(struct ast_sdp_options *options, * * \returns tos_video */ -unsigned int ast_sdp_options_get_tos_video(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_tos_video(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -346,7 +346,7 @@ void ast_sdp_options_set_cos_video(struct ast_sdp_options *options, * * \returns cos_video */ -unsigned int ast_sdp_options_get_cos_video(struct ast_sdp_options *options); +unsigned int ast_sdp_options_get_cos_video(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -366,7 +366,7 @@ void ast_sdp_options_set_ice(struct ast_sdp_options *options, * * \returns ice */ -enum ast_sdp_options_ice ast_sdp_options_get_ice(struct ast_sdp_options *options); +enum ast_sdp_options_ice ast_sdp_options_get_ice(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -386,7 +386,7 @@ void ast_sdp_options_set_impl(struct ast_sdp_options *options, * * \returns impl */ -enum ast_sdp_options_impl ast_sdp_options_get_impl(struct ast_sdp_options *options); +enum ast_sdp_options_impl ast_sdp_options_get_impl(const struct ast_sdp_options *options); /*! * \since 15.0.0 @@ -406,6 +406,25 @@ void ast_sdp_options_set_encryption(struct ast_sdp_options *options, * * \returns encryption */ -enum ast_sdp_options_encryption ast_sdp_options_get_encryption(struct ast_sdp_options *options); +enum ast_sdp_options_encryption ast_sdp_options_get_encryption(const struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Get SDP Options RTCP MUX + * + * \param options SDP Options + * + * \returns Boolean indicating if RTCP MUX is enabled. + */ +unsigned int ast_sdp_options_get_rtcp_mux(const struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options RTCP MUX + * + * \param options SDP Options + * \param value Boolean that indicates if RTCP MUX should be enabled. + */ +void ast_sdp_options_set_rtcp_mux(struct ast_sdp_options *options, unsigned int value); #endif /* _ASTERISK_SDP_OPTIONS_H */ diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index a186d7eefec..7f25c25322e 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -138,7 +138,7 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state); * * \since 15 */ -void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, struct ast_sdp *sdp); +void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct ast_sdp *sdp); /*! * \brief Set the remote SDP from an Implementation diff --git a/main/codec.c b/main/codec.c index 1870c393bc5..7797147a797 100644 --- a/main/codec.c +++ b/main/codec.c @@ -376,6 +376,21 @@ const char *ast_codec_media_type2str(enum ast_media_type type) } } +enum ast_media_type ast_media_type_from_str(const char *media_type_str) +{ + if (!strcasecmp(media_type_str, "audio")) { + return AST_MEDIA_TYPE_AUDIO; + } else if (!strcasecmp(media_type_str, "video")) { + return AST_MEDIA_TYPE_VIDEO; + } else if (!strcasecmp(media_type_str, "image")) { + return AST_MEDIA_TYPE_IMAGE; + } else if (!strcasecmp(media_type_str, "text")) { + return AST_MEDIA_TYPE_TEXT; + } else { + return AST_MEDIA_TYPE_UNKNOWN; + } +} + unsigned int ast_codec_samples_count(struct ast_frame *frame) { struct ast_codec *codec; diff --git a/main/sdp.c b/main/sdp.c index 1ef6400b919..75a9da94d9b 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -500,201 +500,268 @@ int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_opt return 0; } -int ast_sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, - const struct ast_sdp_options *options, int stream_index) +static struct ast_sdp_a_line *sdp_find_attribute_common(const struct ast_sdp_a_lines *a_lines, + const char *attr_name, int payload) { - struct ast_stream *stream = ast_stream_topology_get_stream(ast_sdp_state_get_local_topology(sdp_state), stream_index); - struct ast_sdp_m_line *m_line; - struct ast_format_cap *caps; - int i; - int rtp_code; - int min_packet_size = 0; - int max_packet_size = 0; - enum ast_media_type media_type; - char tmp[64]; - struct ast_sockaddr address_rtp; - struct ast_rtp_instance *rtp = ast_sdp_state_get_rtp_instance(sdp_state, stream_index); struct ast_sdp_a_line *a_line; + int i; - ast_assert(sdp && options && stream); + for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { + int a_line_payload; - media_type = ast_stream_get_type(stream); - if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_rtp)) { - return -1; - } + a_line = AST_VECTOR_GET(a_lines, i); + if (strcmp(a_line->name, attr_name)) { + continue; + } - m_line = ast_sdp_m_alloc( - ast_codec_media_type2str(ast_stream_get_type(stream)), - ast_sockaddr_port(&address_rtp), 1, - options->encryption != AST_SDP_ENCRYPTION_DISABLED ? "RTP/SAVP" : "RTP/AVP", - NULL); - if (!m_line) { - return -1; + if (payload >= 0) { + int sscanf_res; + sscanf_res = sscanf(a_line->value, "%30d", &a_line_payload); + if (sscanf_res == 1 && payload == a_line_payload) { + return a_line; + } + } else { + return a_line; + } } - caps = ast_stream_get_formats(stream); - - for (i = 0; i < ast_format_cap_count(caps); i++) { - struct ast_format *format = ast_format_cap_get_format(caps, i); + return NULL; +} - if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) { - ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); - ao2_ref(format, -1); - continue; - } +struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp, + const char *attr_name, int payload) +{ + return sdp_find_attribute_common(sdp->a_lines, attr_name, payload); +} - if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, format, 0)) { - ast_sdp_m_free(m_line); - ao2_ref(format, -1); - return -1; - } +struct ast_sdp_a_line *ast_sdp_m_find_attribute(const struct ast_sdp_m_line *m_line, + const char *attr_name, int payload) +{ + return sdp_find_attribute_common(m_line->a_lines, attr_name, payload); +} - if (ast_format_get_maximum_ms(format) && - ((ast_format_get_maximum_ms(format) < max_packet_size) || !max_packet_size)) { - max_packet_size = ast_format_get_maximum_ms(format); - } +struct ast_sdp_rtpmap *ast_sdp_rtpmap_alloc(int payload, const char *encoding_name, + int clock_rate, const char *encoding_parameters) +{ + struct ast_sdp_rtpmap *rtpmap; + char *buf_pos; - ao2_ref(format, -1); + rtpmap = ast_calloc(1, sizeof(*rtpmap) + strlen(encoding_name) + strlen(encoding_parameters) + 2); + if (!rtpmap) { + return NULL; } - if (media_type != AST_MEDIA_TYPE_VIDEO) { - for (i = 1LL; i <= AST_RTP_MAX; i <<= 1) { - if (!(options->telephone_event & i)) { - continue; - } + rtpmap->payload = payload; + rtpmap->clock_rate = clock_rate; - rtp_code = ast_rtp_codecs_payload_code( - ast_rtp_instance_get_codecs(rtp), 0, NULL, i); + buf_pos = rtpmap->buf; + COPY_STR_AND_ADVANCE(buf_pos, rtpmap->encoding_name, encoding_name); + COPY_STR_AND_ADVANCE(buf_pos, rtpmap->encoding_parameters, encoding_parameters); - if (rtp_code == -1) { - continue; - } + return rtpmap; +} - if (sdp_m_add_rtpmap(m_line, options, rtp_code, 0, NULL, i)) { - continue; - } +void ast_sdp_rtpmap_free(struct ast_sdp_rtpmap *rtpmap) +{ + ast_free(rtpmap); +} - if (i == AST_RTP_DTMF) { - snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); - a_line = ast_sdp_a_alloc("fmtp", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - } - } - } +struct ast_sdp_rtpmap *ast_sdp_a_get_rtpmap(const struct ast_sdp_a_line *a_line) +{ + char *value_copy; + char *slash; + int payload; + char encoding_name[64]; + int clock_rate; + char *encoding_parameters; + struct ast_sdp_rtpmap *rtpmap; + int clock_rate_len; - if (ast_sdp_m_get_a_count(m_line) == 0) { - return 0; - } + value_copy = ast_strip(ast_strdupa(a_line->value)); - /* If ptime is set add it as an attribute */ - min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); - if (!min_packet_size) { - min_packet_size = ast_format_cap_get_framing(caps); + if (sscanf(value_copy, "%30d %63s", &payload, encoding_name) != 2) { + return NULL; } - if (min_packet_size) { - snprintf(tmp, sizeof(tmp), "%d", min_packet_size); - a_line = ast_sdp_a_alloc("ptime", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + slash = strchr(encoding_name, '/'); + if (!slash) { + return NULL; + } + *slash++ = '\0'; + if (ast_strlen_zero(encoding_name)) { + return NULL; + } + if (sscanf(slash, "%30d%n", &clock_rate, &clock_rate_len) < 1) { + return NULL; } - if (max_packet_size) { - snprintf(tmp, sizeof(tmp), "%d", max_packet_size); - a_line = ast_sdp_a_alloc("maxptime", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; + slash += clock_rate_len; + if (!ast_strlen_zero(slash)) { + if (*slash == '/') { + *slash++ = '\0'; + encoding_parameters = slash; + if (ast_strlen_zero(encoding_parameters)) { + return NULL; + } + } else { + return NULL; } + } else { + encoding_parameters = ""; } - a_line = ast_sdp_a_alloc(ast_sdp_state_get_locally_held(sdp_state, stream_index) ? "sendonly" : "sendrecv", ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + rtpmap = ast_sdp_rtpmap_alloc(payload, encoding_name, clock_rate, + encoding_parameters); - if (ast_sdp_add_m(sdp, m_line)) { - ast_sdp_m_free(m_line); - return -1; + return rtpmap; +} + +/*! + * \brief Turn an SDP attribute into an sdp_rtpmap structure + * + * \param m_line The media section where this attribute was found. + * \param payload The RTP payload to find an rtpmap for + * \param[out] rtpmap The rtpmap to fill in. + * \return Zero if successful, otherwise less than zero + */ +static struct ast_sdp_rtpmap *sdp_payload_get_rtpmap(const struct ast_sdp_m_line *m_line, int payload) +{ + struct ast_sdp_a_line *rtpmap_attr; + + rtpmap_attr = ast_sdp_m_find_attribute(m_line, "rtpmap", payload); + if (!rtpmap_attr) { + return NULL; } - return 0; + return ast_sdp_a_get_rtpmap(rtpmap_attr); } -struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state) +/*! + * \brief Find and process fmtp attributes for a given payload + * + * \param m_line The stream on which to search for the fmtp attribute + * \param payload The specific fmtp attribute to search for + * \param codecs The current RTP codecs that have been built up + */ +static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload, + struct ast_rtp_codecs *codecs) { - const struct ast_sdp_options *options; - RAII_VAR(struct ast_sdp *, sdp, NULL, ao2_cleanup); - const const struct ast_stream_topology *topology; - int stream_count; - int stream_num; - struct ast_sdp_o_line *o_line = NULL; - struct ast_sdp_c_line *c_line = NULL; - struct ast_sdp_s_line *s_line = NULL; - struct ast_sdp_t_line *t_line = NULL; - char *address_type; - struct timeval tv = ast_tvnow(); - uint32_t t; - ast_assert(!!sdp_state); - - options = ast_sdp_state_get_options(sdp_state); - topology = ast_sdp_state_get_local_topology(sdp_state); - stream_count = ast_stream_topology_get_count(topology); + struct ast_sdp_a_line *attr; + char *param; + char *param_start; + char *param_end; + size_t len; + struct ast_format *replace; + struct ast_format *format; - t = tv.tv_sec + 2208988800UL; - address_type = (strchr(options->media_address, ':') ? "IP6" : "IP4"); + attr = ast_sdp_m_find_attribute(m_line, "fmtp", payload); + if (!attr) { + return; + } - o_line = ast_sdp_o_alloc(options->sdpowner, t, t, address_type, options->media_address); - if (!o_line) { - goto error; + /* Extract the "a=fmtp:%d %s" attribute parameter string after the payload type. */ + param_start = ast_skip_nonblanks(attr->value);/* Skip payload type */ + param_start = ast_skip_blanks(param_start); + param_end = ast_skip_nonblanks(param_start); + if (param_end == param_start) { + /* There is no parameter string */ + return; } - c_line = ast_sdp_c_alloc(address_type, options->media_address); - if (!c_line) { - goto error; + len = param_end - param_start; + param = ast_alloca(len + 1); + memcpy(param, param_start, len); + param[len] = '\0'; + + format = ast_rtp_codecs_get_payload_format(codecs, payload); + if (!format) { + return; } - s_line = ast_sdp_s_alloc(options->sdpsession); - if (!s_line) { - goto error; + replace = ast_format_parse_sdp_fmtp(format, param); + if (replace) { + ast_rtp_codecs_payload_replace_format(codecs, payload, replace); + ao2_ref(replace, -1); } + ao2_ref(format, -1); +} - sdp = ast_sdp_alloc(o_line, c_line, s_line, NULL); - if (!sdp) { - goto error; +/*! + * \brief Convert an SDP stream into an Asterisk stream + * + * Given an m-line from an SDP, convert it into an ast_stream structure. + * This takes formats, as well as clock-rate and fmtp attributes into account. + * + * \param m_line The SDP media section to convert + * \retval NULL An error occurred + * \retval non-NULL The converted stream + */ +static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line) +{ + int i; + int non_ast_fmts; + struct ast_rtp_codecs codecs; + struct ast_format_cap *caps; + struct ast_stream *stream; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } + stream = ast_stream_alloc(m_line->type, ast_media_type_from_str(m_line->type)); + if (!stream) { + ao2_ref(caps, -1); + return NULL; } + ast_rtp_codecs_payloads_initialize(&codecs); - for (stream_num = 0; stream_num < stream_count; stream_num++) { - enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num)); + for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { + struct ast_sdp_payload *payload_s; + struct ast_sdp_rtpmap *rtpmap; + int payload; - if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { - if (ast_sdp_add_m_from_rtp_stream(sdp, sdp_state, options, stream_num)) { - goto error; - } + payload_s = ast_sdp_m_get_payload(m_line, i); + sscanf(payload_s->fmt, "%30d", &payload); + ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, payload); + + rtpmap = sdp_payload_get_rtpmap(m_line, payload); + if (!rtpmap) { + continue; } + ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, + payload, m_line->type, rtpmap->encoding_name, 0, + rtpmap->clock_rate); + ast_sdp_rtpmap_free(rtpmap); + + process_fmtp(m_line, payload, &codecs); } - return sdp; + ast_rtp_codecs_payload_formats(&codecs, caps, &non_ast_fmts); + ast_stream_set_formats(stream, caps); -error: - if (sdp) { - ast_sdp_free(sdp); - } else { - ast_sdp_t_free(t_line); - ast_sdp_s_free(s_line); - ast_sdp_c_free(c_line); - ast_sdp_o_free(o_line); + ao2_ref(caps, -1); + ast_rtp_codecs_payloads_destroy(&codecs); + return stream; +} + +struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp) +{ + struct ast_stream_topology *topology; + int i; + + topology = ast_stream_topology_alloc(); + if (!topology) { + return NULL; } - return NULL; -} + for (i = 0; i < ast_sdp_get_m_count(sdp); ++i) { + struct ast_stream *stream; + + stream = get_stream_from_m(ast_sdp_get_m(sdp, i)); + if (!stream) { + continue; + } + ast_stream_topology_append_stream(topology, stream); + } + return topology; +} diff --git a/main/sdp_options.c b/main/sdp_options.c index 60848172218..1162f693bc0 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -36,7 +36,7 @@ void ast_sdp_options_set_##field(struct ast_sdp_options *options, const char *va if (!strcmp(value, options->field)) return; \ ast_string_field_set(options, field, value); \ } \ -const char *ast_sdp_options_get_##field(struct ast_sdp_options *options) \ +const char *ast_sdp_options_get_##field(const struct ast_sdp_options *options) \ { \ ast_assert(options != NULL); \ return options->field; \ @@ -48,7 +48,7 @@ void ast_sdp_options_set_##field(struct ast_sdp_options *options, type value) \ ast_assert(options != NULL); \ options->field = value; \ } \ -type ast_sdp_options_get_##field(struct ast_sdp_options *options) \ +type ast_sdp_options_get_##field(const struct ast_sdp_options *options) \ { \ ast_assert(options != NULL); \ return options->field; \ @@ -64,6 +64,7 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); DEFINE_GETTERS_SETTERS_FOR(unsigned int, telephone_event); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_ipv6); DEFINE_GETTERS_SETTERS_FOR(unsigned int, g726_non_standard); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtcp_mux); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_video); diff --git a/main/sdp_private.h b/main/sdp_private.h index 45aaebf9a00..15b9d1ecc47 100644 --- a/main/sdp_private.h +++ b/main/sdp_private.h @@ -40,6 +40,7 @@ struct ast_sdp_options { unsigned int rtp_ipv6 : 1; unsigned int g726_non_standard : 1; unsigned int locally_held : 1; + unsigned int rtcp_mux: 1; }; struct { unsigned int tos_audio; diff --git a/main/sdp_state.c b/main/sdp_state.c index 5858a65ab06..fc7fff44923 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -24,43 +24,41 @@ #include "asterisk/utils.h" #include "asterisk/netsock2.h" #include "asterisk/rtp_engine.h" +#include "asterisk/format.h" +#include "asterisk/format_cap.h" +#include "asterisk/config.h" +#include "asterisk/codec.h" #include "../include/asterisk/sdp.h" #include "asterisk/stream.h" #include "sdp_private.h" -enum ast_sdp_state_machine { - /*! \brief The initial state. +enum ast_sdp_role { + /*! + * \brief The role has not yet been determined. * - * The state machine starts here. It also goes back to this - * state whenever ast_sdp_state_reset() is called. + * When the SDP state is allocated, this is the starting role. + * Similarly, when the SDP state is reset, the role is reverted + * to this. */ - SDP_STATE_INITIAL, - /*! \brief We are the SDP offerer. + SDP_ROLE_NOT_SET, + /*! + * \brief We are the offerer. * - * The state machine enters this state if in the initial state - * and ast_sdp_state_get_local() is called. When this state is - * entered, a local SDP is created and then returned. + * If a local SDP is requested before a remote SDP has been set, then + * we assume the role of offerer. This means that we will generate an + * SDP from the local capabilities and configured options. */ - SDP_STATE_OFFERER, - /*! \brief We are the SDP answerer. + SDP_ROLE_OFFERER, + /*! + * \brief We are the answerer. * - * The state machine enters this state if in the initial state - * and ast_sdp_state_set_remote() is called. + * If a remote SDP is set before a local SDP is requested, then we + * assume the role of answerer. This means that we will generate an + * SDP based on a merge of the remote capabilities and our local capabilities. */ - SDP_STATE_ANSWERER, - /*! \brief The SDP has been negotiated. - * - * This state can be entered from either the offerer or answerer - * state. When this state is entered, a joint SDP is created. - */ - SDP_STATE_NEGOTIATED, - /*! \brief Not an actual state. - * - * This is just here to mark the end of the enumeration. - */ - SDP_STATE_END, + SDP_ROLE_ANSWERER, }; typedef int (*state_fn)(struct ast_sdp_state *state); @@ -76,34 +74,185 @@ struct sdp_state_stream { unsigned int locally_held; }; +static void sdp_state_stream_free(struct sdp_state_stream *state_stream) +{ + if (state_stream->instance) { + ast_rtp_instance_destroy(state_stream->instance); + } + ast_free(state_stream); +} + +AST_VECTOR(sdp_state_streams, struct sdp_state_stream *); + struct sdp_state_capabilities { /*! Stream topology */ struct ast_stream_topology *topology; /*! Additional information about the streams */ - AST_VECTOR(, struct sdp_state_stream) streams; + struct sdp_state_streams streams; /*! An explicit global connection address */ struct ast_sockaddr connection_address; }; +static void sdp_state_capabilities_free(struct sdp_state_capabilities *capabilities) +{ + if (!capabilities) { + return; + } + + ast_stream_topology_free(capabilities->topology); + AST_VECTOR_CALLBACK_VOID(&capabilities->streams, sdp_state_stream_free); + AST_VECTOR_FREE(&capabilities->streams); + ast_free(capabilities); +} + +/* TODO + * This isn't set anywhere yet. + */ +/*! \brief Scheduler for RTCP purposes */ +static struct ast_sched_context *sched; + +/*! \brief Internal function which creates an RTP instance */ +static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, + enum ast_media_type media_type) +{ + struct ast_rtp_instance *rtp; + struct ast_rtp_engine_ice *ice; + struct ast_sockaddr temp_media_address; + static struct ast_sockaddr address_rtp; + struct ast_sockaddr *media_address = &address_rtp; + + if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { + ast_sockaddr_parse(&temp_media_address, options->media_address, 0); + media_address = &temp_media_address; + } else { + if (ast_check_ipv6()) { + ast_sockaddr_parse(&address_rtp, "::", 0); + } else { + ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); + } + } + + if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { + ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", + options->rtp_engine); + return NULL; + } + + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); + + if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { + ice->stop(rtp); + } + + if (options->telephone_event) { + ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); + } + + if (media_type == AST_MEDIA_TYPE_AUDIO && + (options->tos_audio || options->cos_audio)) { + ast_rtp_instance_set_qos(rtp, options->tos_audio, + options->cos_audio, "SIP RTP Audio"); + } else if (media_type == AST_MEDIA_TYPE_VIDEO && + (options->tos_video || options->cos_video)) { + ast_rtp_instance_set_qos(rtp, options->tos_video, + options->cos_video, "SIP RTP Video"); + } + + ast_rtp_instance_set_last_rx(rtp, time(NULL)); + + return rtp; +} + +static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const struct ast_stream_topology *topology, + const struct ast_sdp_options *options) +{ + struct sdp_state_capabilities *capabilities; + int i; + + capabilities = ast_calloc(1, sizeof(*capabilities)); + if (!capabilities) { + return NULL; + } + + capabilities->topology = ast_stream_topology_clone(topology); + if (!capabilities->topology) { + sdp_state_capabilities_free(capabilities); + return NULL; + } + + if (AST_VECTOR_INIT(&capabilities->streams, + ast_stream_topology_get_count(topology))) { + sdp_state_capabilities_free(capabilities); + return NULL; + } + ast_sockaddr_setnull(&capabilities->connection_address); + + for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { + struct sdp_state_stream *state_stream; + enum ast_media_type stream_type; + + state_stream = ast_calloc(1, sizeof(*state_stream)); + if (!state_stream) { + return NULL; + } + + stream_type = ast_stream_get_type(ast_stream_topology_get_stream(topology, i)); + + if (stream_type == AST_MEDIA_TYPE_AUDIO || stream_type == AST_MEDIA_TYPE_VIDEO) { + state_stream->instance = create_rtp(options, stream_type); + } + + if (!state_stream->instance) { + sdp_state_stream_free(state_stream); + return NULL; + } + + AST_VECTOR_APPEND(&capabilities->streams, state_stream); + } + + return capabilities; +} + +/*! + * \brief SDP state, the main structure used to keep track of SDP negotiation + * and settings. + * + * Most fields are pretty self-explanatory, but negotiated_capabilities and + * proposed_capabilities could use some further explanation. When an SDP + * state is allocated, a stream topology is provided that dictates the + * types of streams to offer in the resultant SDP. At the time the SDP + * is allocated, this topology is used to create the proposed_capabilities. + * + * If we are the SDP offerer, then the proposed_capabilities are what are used + * to generate the SDP offer. When the SDP answer arrives, the proposed capabilities + * are merged with the SDP answer to create the negotiated capabilities. + * + * If we are the SDP answerer, then the incoming SDP offer is merged with our + * proposed capabilities to to create the negotiated capabilities. These negotiated + * capabilities are what we send in our SDP answer. + * + * Any changes that a user of the API performs will occur on the proposed capabilities. + * The negotiated capabilities are only altered based on actual SDP negotiation. This is + * done so that the negotiated capabilities can be fallen back on if the proposed + * capabilities run into some sort of issue. + */ struct ast_sdp_state { - /*! Local capabilities, learned through configuration */ - struct sdp_state_capabilities local_capabilities; + /*! Current capabilities */ + struct sdp_state_capabilities *negotiated_capabilities; + /*! Proposed capabilities */ + struct sdp_state_capabilities *proposed_capabilities; /*! Remote capabilities, learned through remote SDP */ struct ast_stream_topology *remote_capabilities; - /*! Joint capabilities. The combined local and remote capabilities. */ - struct sdp_state_capabilities joint_capabilities; /*! Local SDP. Generated via the options and local capabilities. */ struct ast_sdp *local_sdp; - /*! Remote SDP. Received directly from a peer. */ - struct ast_sdp *remote_sdp; - /*! Joint SDP. The merged local and remote SDPs. */ - struct ast_sdp *joint_sdp; /*! SDP options. Configured options beyond media capabilities. */ struct ast_sdp_options *options; /*! Translator that puts SDPs into the expected representation */ struct ast_sdp_translator *translator; - /*! The current state machine state that we are in */ - enum ast_sdp_state_machine state; + /*! The role that we occupy in SDP negotiation */ + enum ast_sdp_role role; }; struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, @@ -124,56 +273,39 @@ struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, return NULL; } - if (ast_sdp_state_update_local_topology(sdp_state, streams)) { + sdp_state->proposed_capabilities = sdp_initialize_state_capabilities(streams, options); + if (!sdp_state->proposed_capabilities) { ast_sdp_state_free(sdp_state); return NULL; } - sdp_state->state = SDP_STATE_INITIAL; + sdp_state->role = SDP_ROLE_NOT_SET; return sdp_state; } -static void sdp_state_capabilities_free(struct sdp_state_capabilities *sdp_capabilities) -{ - int stream_index; - - for (stream_index = 0; stream_index < AST_VECTOR_SIZE(&sdp_capabilities->streams); stream_index++) { - struct sdp_state_stream *stream_state = AST_VECTOR_GET_ADDR(&sdp_capabilities->streams, stream_index); - enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_capabilities->topology, stream_index)); - - if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { - ast_rtp_instance_destroy(stream_state->instance); - } - } - - ast_stream_topology_free(sdp_capabilities->topology); - AST_VECTOR_FREE(&sdp_capabilities->streams); -} - void ast_sdp_state_free(struct ast_sdp_state *sdp_state) { if (!sdp_state) { return; } - sdp_state_capabilities_free(&sdp_state->local_capabilities); + sdp_state_capabilities_free(sdp_state->negotiated_capabilities); + sdp_state_capabilities_free(sdp_state->proposed_capabilities); ast_stream_topology_free(sdp_state->remote_capabilities); - sdp_state_capabilities_free(&sdp_state->joint_capabilities); ast_sdp_free(sdp_state->local_sdp); - ast_sdp_free(sdp_state->remote_sdp); - ast_sdp_free(sdp_state->joint_sdp); ast_sdp_options_free(sdp_state->options); ast_sdp_translator_free(sdp_state->translator); + ast_free(sdp_state); } static struct sdp_state_stream *sdp_state_get_stream(const struct ast_sdp_state *sdp_state, int stream_index) { - if (stream_index >= AST_VECTOR_SIZE(&sdp_state->local_capabilities.streams)) { + if (stream_index >= AST_VECTOR_SIZE(&sdp_state->proposed_capabilities->streams)) { return NULL; } - return AST_VECTOR_GET_ADDR(&sdp_state->local_capabilities.streams, stream_index); + return AST_VECTOR_GET(&sdp_state->proposed_capabilities->streams, stream_index); } struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( @@ -195,7 +327,7 @@ const struct ast_sockaddr *ast_sdp_state_get_connection_address(const struct ast { ast_assert(sdp_state != NULL); - return &sdp_state->local_capabilities.connection_address; + return &sdp_state->proposed_capabilities->connection_address; } int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_state, @@ -218,7 +350,7 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_ return 0; } - type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->local_capabilities.topology, + type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->proposed_capabilities->topology, stream_index)); if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { @@ -228,10 +360,10 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_ } /* If an explicit global connection address is set use it here for the IP part */ - if (!ast_sockaddr_isnull(&sdp_state->local_capabilities.connection_address)) { + if (!ast_sockaddr_isnull(&sdp_state->proposed_capabilities->connection_address)) { int port = ast_sockaddr_port(address); - ast_sockaddr_copy(address, &sdp_state->local_capabilities.connection_address); + ast_sockaddr_copy(address, &sdp_state->proposed_capabilities->connection_address); ast_sockaddr_set_port(address, port); } @@ -242,11 +374,12 @@ const struct ast_stream_topology *ast_sdp_state_get_joint_topology( const struct ast_sdp_state *sdp_state) { ast_assert(sdp_state != NULL); - if (sdp_state->state == SDP_STATE_NEGOTIATED) { - return sdp_state->joint_capabilities.topology; - } else { - return sdp_state->local_capabilities.topology; + + if (sdp_state->negotiated_capabilities) { + return sdp_state->negotiated_capabilities->topology; } + + return sdp_state->proposed_capabilities->topology; } const struct ast_stream_topology *ast_sdp_state_get_local_topology( @@ -254,7 +387,7 @@ const struct ast_stream_topology *ast_sdp_state_get_local_topology( { ast_assert(sdp_state != NULL); - return sdp_state->local_capabilities.topology; + return sdp_state->proposed_capabilities->topology; } const struct ast_sdp_options *ast_sdp_state_get_options( @@ -265,120 +398,427 @@ const struct ast_sdp_options *ast_sdp_state_get_options( return sdp_state->options; } -#if 0 -static int merge_sdps(struct ast_sdp_state *sdp_state) -{ - ast_assert(sdp_state->local_sdp != NULL); - ast_assert(sdp_state->remote_sdp != NULL); - /* XXX STUB */ - /* The goal of this function is to take - * sdp_state->local_sdp and sdp_state->remote_sdp - * and negotiate those into a joint SDP. This joint - * SDP should be stored in sdp_state->joint_sdp. After - * the joint SDP is created, the joint SDP should be - * used to create the joint topology. Finally, if necessary, - * the RTP session may need to be adjusted in some ways. For - * instance, if we previously opened three ports for three - * streams, but we negotiate down to two streams, then we - * can shut down the port for the third stream. Similarly, - * if we end up negotiating something like BUNDLE, then we may - * need to tell the RTP layer to close ports and to multiplex - * streams. - */ +/*! + * \brief Merge two streams into a joint stream. + * + * \param local Our local stream + * \param remote A remote stream + * \retval NULL An error occurred + * \retval non-NULL The joint stream created + */ +static struct ast_stream *merge_streams(const struct ast_stream *local, + const struct ast_stream *remote) +{ + struct ast_stream *joint_stream; + struct ast_format_cap *joint_cap; + struct ast_format_cap *local_cap; + struct ast_format_cap *remote_cap; + struct ast_str *local_buf = ast_str_alloca(128); + struct ast_str *remote_buf = ast_str_alloca(128); + struct ast_str *joint_buf = ast_str_alloca(128); + + joint_stream = ast_stream_alloc(ast_codec_media_type2str(ast_stream_get_type(remote)), + ast_stream_get_type(remote)); + if (!joint_stream) { + return NULL; + } - return 0; + if (!local) { + return joint_stream; + } + + joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!joint_cap) { + ast_stream_free(joint_stream); + return NULL; + } + + local_cap = ast_stream_get_formats(local); + remote_cap = ast_stream_get_formats(remote); + + ast_format_cap_get_compatible(local_cap, remote_cap, joint_cap); + + ast_debug(3, "Combined local '%s' with remote '%s' to get joint '%s'. Joint has %zu formats\n", + ast_format_cap_get_names(local_cap, &local_buf), + ast_format_cap_get_names(remote_cap, &remote_buf), + ast_format_cap_get_names(joint_cap, &joint_buf), + ast_format_cap_count(joint_cap)); + + ast_stream_set_formats(joint_stream, joint_cap); + + ao2_ref(joint_cap, -1); + + return joint_stream; } -#endif -/* TODO - * This isn't set anywhere yet. +/*! + * \brief Get a local stream that corresponds with a remote stream. + * + * \param local The local topology + * \param media_type The type of stream we are looking for + * \param[in,out] media_indices Keeps track of where to start searching in the topology + * \retval NULL No corresponding stream found + * \retval non-NULL The corresponding stream */ -/*! \brief Scheduler for RTCP purposes */ -static struct ast_sched_context *sched; +static int get_corresponding_index(const struct ast_stream_topology *local, + enum ast_media_type media_type, int *media_indices) +{ + int i; + int winner = -1; -/*! \brief Internal function which creates an RTP instance */ -static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, - enum ast_media_type media_type) + for (i = media_indices[media_type]; i < ast_stream_topology_get_count(local); ++i) { + struct ast_stream *candidate; + + candidate = ast_stream_topology_get_stream(local, i); + if (ast_stream_get_type(candidate) == media_type) { + winner = i; + break; + } + } + + media_indices[media_type] = i + 1; + return winner; +} + +/*! + * \brief Merge existing stream capabilities and a new topology into joint capabilities. + * + * This is a bit complicated. The idea is that we already have some capabilities set, and + * we've now been confronted with a new stream topology. We want to take what's been + * presented to us and merge those new capabilities with our own. + * + * For each of the new streams, we try to find a corresponding stream in our current + * capabilities. If we find one, then we get the compatible formats of the two streams + * and create a new stream with those formats set. We then will re-use the underlying + * media instance (such as an RTP instance) on this merged stream. + * + * The create_new parameter determines whether we should attempt to create new media + * instances. + * If we do not find a corresponding stream, then we create a new one. If the + * create_new parameter is true, this created stream is made a clone of the new stream, + * and a media instance is created. If the create_new parameter is not true, then the + * created stream has no formats set and no media instance is created for it. + * + * \param current Current capabilities of the SDP state (may be NULL) + * \param new_topology The new topology to base merged capabilities on + * \param options The options set on the SDP state + * \retval NULL An error occurred + * \retval non-NULL The merged capabilities + */ +static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_capabilities *current, + const struct ast_stream_topology *new_topology, const struct ast_sdp_options *options, int create_missing) +{ + struct sdp_state_capabilities *joint_capabilities; + struct ast_stream_topology *topology; + int media_indices[AST_MEDIA_TYPE_END] = {0}; + int i; + + ast_assert(current != NULL); + + joint_capabilities = ast_calloc(1, sizeof(*joint_capabilities)); + if (!joint_capabilities) { + return NULL; + } + + joint_capabilities->topology = ast_stream_topology_alloc(); + if (!joint_capabilities->topology) { + goto fail; + } + + AST_VECTOR_INIT(&joint_capabilities->streams, AST_VECTOR_SIZE(¤t->streams)); + ast_sockaddr_copy(&joint_capabilities->connection_address, ¤t->connection_address); + topology = current->topology; + + for (i = 0; i < ast_stream_topology_get_count(new_topology); ++i) { + enum ast_media_type new_stream_type; + struct ast_stream *new_stream; + struct ast_stream *current_stream; + struct ast_stream *joint_stream; + struct sdp_state_stream *current_state_stream; + struct sdp_state_stream *joint_state_stream; + int current_index; + + joint_state_stream = ast_calloc(1, sizeof(*joint_state_stream)); + if (!joint_state_stream) { + goto fail; + } + + new_stream = ast_stream_topology_get_stream(new_topology, i); + new_stream_type = ast_stream_get_type(new_stream); + + current_index = get_corresponding_index(topology, new_stream_type, media_indices); + + if (current_index >= 0) { + current_stream = ast_stream_topology_get_stream(topology, current_index); + joint_stream = merge_streams(current_stream, new_stream); + if (!joint_stream) { + goto fail; + } + + current_state_stream = AST_VECTOR_GET(¤t->streams, current_index); + joint_state_stream->instance = ao2_bump(current_state_stream->instance); + + if (!ast_sockaddr_isnull(¤t_state_stream->connection_address)) { + ast_sockaddr_copy(&joint_state_stream->connection_address, ¤t_state_stream->connection_address); + } else { + ast_sockaddr_setnull(&joint_state_stream->connection_address); + } + joint_state_stream->locally_held = current_state_stream->locally_held; + } else if (create_missing) { + /* We don't have a stream state that corresponds to the stream in the new topology, so + * create a stream state as appropriate. + */ + joint_stream = ast_stream_clone(new_stream); + if (!joint_stream) { + goto fail; + } + if (new_stream_type == AST_MEDIA_TYPE_AUDIO || new_stream_type == AST_MEDIA_TYPE_VIDEO) { + joint_state_stream->instance = create_rtp(options, new_stream_type); + if (!joint_state_stream->instance) { + goto fail; + } + } + ast_sockaddr_setnull(&joint_state_stream->connection_address); + joint_state_stream->locally_held = 0; + } else { + /* We don't have a stream that corresponds to the stream in the new topology. Create a + * dummy stream to go in its place so that the resulting SDP created will contain + * the stream but will have no port or codecs set + */ + joint_stream = ast_stream_alloc("dummy", new_stream_type); + if (!joint_stream) { + goto fail; + } + } + + ast_stream_topology_append_stream(joint_capabilities->topology, joint_stream); + AST_VECTOR_APPEND(&joint_capabilities->streams, joint_state_stream); + } + + return joint_capabilities; + +fail: + sdp_state_capabilities_free(joint_capabilities); + return NULL; +} + +/*! + * \brief Apply remote SDP's ICE information to our RTP session + * + * \param state The SDP state on which negotiation has taken place + * \param options The SDP options we support + * \param remote_sdp The SDP we most recently received + * \param remote_m_line The stream on which we are examining ICE candidates + */ +static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instance *rtp, const struct ast_sdp_options *options, + const struct ast_sdp *remote_sdp, const struct ast_sdp_m_line *remote_m_line) { - struct ast_rtp_instance *rtp; struct ast_rtp_engine_ice *ice; - struct ast_sockaddr temp_media_address; - static struct ast_sockaddr address_rtp; - struct ast_sockaddr *media_address = &address_rtp; + const struct ast_sdp_a_line *attr; + unsigned int attr_i; - if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { - ast_sockaddr_parse(&temp_media_address, options->media_address, 0); - media_address = &temp_media_address; + /* If ICE support is not enabled or available exit early */ + if (ast_sdp_options_get_ice(options) != AST_SDP_ICE_ENABLED_STANDARD || !(ice = ast_rtp_instance_get_ice(rtp))) { + return; + } + + attr = ast_sdp_m_find_attribute(remote_m_line, "ice-ufrag", -1); + if (!attr) { + attr = ast_sdp_find_attribute(remote_sdp, "ice-ufrag", -1); + } + if (attr) { + ice->set_authentication(rtp, attr->value, NULL); } else { - if (ast_check_ipv6()) { - ast_sockaddr_parse(&address_rtp, "::", 0); + return; + } + + attr = ast_sdp_m_find_attribute(remote_m_line, "ice-pwd", -1); + if (!attr) { + attr = ast_sdp_find_attribute(remote_sdp, "ice-pwd", -1); + } + if (attr) { + ice->set_authentication(rtp, NULL, attr->value); + } else { + return; + } + + if (ast_sdp_m_find_attribute(remote_m_line, "ice-lite", -1)) { + ice->ice_lite(rtp); + } + + /* Find all of the candidates */ + for (attr_i = 0; attr_i < ast_sdp_m_get_a_count(remote_m_line); ++attr_i) { + char foundation[32]; + char transport[32]; + char address[INET6_ADDRSTRLEN + 1]; + char cand_type[6]; + char relay_address[INET6_ADDRSTRLEN + 1] = ""; + unsigned int port; + unsigned int relay_port = 0; + struct ast_rtp_engine_ice_candidate candidate = { 0, }; + + attr = ast_sdp_m_get_a(remote_m_line, attr_i); + + /* If this is not a candidate line skip it */ + if (strcmp(attr->name, "candidate")) { + continue; + } + + if (sscanf(attr->value, "%31s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", + foundation, &candidate.id, transport, (unsigned *)&candidate.priority, address, + &port, cand_type, relay_address, &relay_port) < 7) { + /* Candidate did not parse properly */ + continue; + } + + if (ast_sdp_options_get_rtcp_mux(options) + && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1) + && candidate.id > 1) { + /* Remote side may have offered RTP and RTCP candidates. However, if we're using RTCP MUX, + * then we should ignore RTCP candidates. + */ + continue; + } + + candidate.foundation = foundation; + candidate.transport = transport; + + ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID); + ast_sockaddr_set_port(&candidate.address, port); + + if (!strcasecmp(cand_type, "host")) { + candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST; + } else if (!strcasecmp(cand_type, "srflx")) { + candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX; + } else if (!strcasecmp(cand_type, "relay")) { + candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED; } else { - ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); + continue; } + + if (!ast_strlen_zero(relay_address)) { + ast_sockaddr_parse(&candidate.relay_address, relay_address, PARSE_PORT_FORBID); + } + + if (relay_port) { + ast_sockaddr_set_port(&candidate.relay_address, relay_port); + } + + ice->add_remote_candidate(rtp, &candidate); } - if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { - ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", - options->rtp_engine); - return NULL; + if (state->role == SDP_ROLE_OFFERER) { + ice->set_role(rtp, AST_RTP_ICE_ROLE_CONTROLLING); + } else { + ice->set_role(rtp, AST_RTP_ICE_ROLE_CONTROLLED); } - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); + ice->start(rtp); +} - if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { - ice->stop(rtp); +/*! + * \brief Update RTP instances based on merged SDPs + * + * RTP instances, when first allocated, cannot make assumptions about what the other + * side supports and thus has to go with some default behaviors. This function gets + * called after we know both what we support and what the remote endpoint supports. + * This way, we can update the RTP instance to reflect what is supported by both + * sides. + * + * \param state The SDP state in which SDPs have been negotiated + * \param rtp The RTP instance that is being updated + * \param options Our locally-supported SDP options + * \param remote_sdp The SDP we most recently received + * \param remote_m_line The remote SDP stream that corresponds to the RTP instance we are modifying + */ +static void update_rtp_after_merge(const struct ast_sdp_state *state, struct ast_rtp_instance *rtp, + const struct ast_sdp_options *options, + const struct ast_sdp *remote_sdp, + const struct ast_sdp_m_line *remote_m_line) +{ + if (ast_sdp_options_get_rtcp_mux(options) && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1)) { + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX); + } else { + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); } - if (options->telephone_event) { - ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); + if (ast_sdp_options_get_ice(options) == AST_SDP_ICE_ENABLED_STANDARD) { + update_ice(state, rtp, options, remote_sdp, remote_m_line); } +} - if (media_type == AST_MEDIA_TYPE_AUDIO && - (options->tos_audio || options->cos_audio)) { - ast_rtp_instance_set_qos(rtp, options->tos_audio, - options->cos_audio, "SIP RTP Audio"); - } else if (media_type == AST_MEDIA_TYPE_VIDEO && - (options->tos_video || options->cos_video)) { - ast_rtp_instance_set_qos(rtp, options->tos_video, - options->cos_video, "SIP RTP Video"); - } +static void set_negotiated_capabilities(struct ast_sdp_state *sdp_state, + struct sdp_state_capabilities *new_capabilities) +{ + struct sdp_state_capabilities *old_capabilities = sdp_state->negotiated_capabilities; - ast_rtp_instance_set_last_rx(rtp, time(NULL)); + sdp_state->negotiated_capabilities = new_capabilities; + sdp_state_capabilities_free(old_capabilities); +} - return rtp; +static void set_proposed_capabilities(struct ast_sdp_state *sdp_state, + struct sdp_state_capabilities *new_capabilities) +{ + struct sdp_state_capabilities *old_capabilities = sdp_state->proposed_capabilities; + + sdp_state->proposed_capabilities = new_capabilities; + sdp_state_capabilities_free(old_capabilities); } -static int sdp_state_setup_local_streams(struct ast_sdp_state *sdp_state) +static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_state, + const struct sdp_state_capabilities *capabilities); + +/*! + * \brief Merge SDPs into a joint SDP. + * + * This function is used to take a remote SDP and merge it with our local + * capabilities to produce a new local SDP. After creating the new local SDP, + * it then iterates through media instances and updates them as necessary. For + * instance, if a specific RTP feature is supported by both us and the far end, + * then we can ensure that the feature is enabled. + * + * \param sdp_state The current SDP state + * \retval -1 Failure + * \retval 0 Success + */ +static int merge_sdps(struct ast_sdp_state *sdp_state, + const struct ast_sdp *remote_sdp) { - int stream_index; + struct sdp_state_capabilities *joint_capabilities; + int i; - for (stream_index = 0; stream_index < AST_VECTOR_SIZE(&sdp_state->local_capabilities.streams); stream_index++) { - struct sdp_state_stream *stream_state_local = AST_VECTOR_GET_ADDR(&sdp_state->local_capabilities.streams, stream_index); - struct sdp_state_stream *stream_state_joint = NULL; - enum ast_media_type type_local = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->local_capabilities.topology, stream_index)); - enum ast_media_type type_joint = AST_MEDIA_TYPE_UNKNOWN; + sdp_state->remote_capabilities = ast_get_topology_from_sdp(remote_sdp); + if (!sdp_state->remote_capabilities) { + return -1; + } - if (stream_index < AST_VECTOR_SIZE(&sdp_state->joint_capabilities.streams)) { - stream_state_joint = AST_VECTOR_GET_ADDR(&sdp_state->joint_capabilities.streams, stream_index); - type_joint = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->joint_capabilities.topology, stream_index)); - } + joint_capabilities = merge_capabilities(sdp_state->proposed_capabilities, + sdp_state->remote_capabilities, sdp_state->options, 0); + if (!joint_capabilities) { + return -1; + } + set_negotiated_capabilities(sdp_state, joint_capabilities); - /* If we can reuse an existing media stream then do so */ - if (type_local == type_joint) { - if (type_local == AST_MEDIA_TYPE_AUDIO || type_local == AST_MEDIA_TYPE_VIDEO) { - stream_state_local->instance = ao2_bump(stream_state_joint->instance); - continue; - } - } + if (sdp_state->local_sdp) { + ast_sdp_free(sdp_state->local_sdp); + sdp_state->local_sdp = NULL; + } - if (type_local == AST_MEDIA_TYPE_AUDIO || type_local == AST_MEDIA_TYPE_VIDEO) { - /* We need to create a new RTP instance */ - stream_state_local->instance = create_rtp(sdp_state->options, type_local); - if (!stream_state_local->instance) { - return -1; - } + sdp_state->local_sdp = sdp_create_from_state(sdp_state, joint_capabilities); + if (!sdp_state->local_sdp) { + return -1; + } + + for (i = 0; i < AST_VECTOR_SIZE(&joint_capabilities->streams); ++i) { + struct sdp_state_stream *state_stream; + enum ast_media_type stream_type; + + stream_type = ast_stream_get_type(ast_stream_topology_get_stream(joint_capabilities->topology, i)); + + state_stream = AST_VECTOR_GET(&joint_capabilities->streams, i); + if ((stream_type == AST_MEDIA_TYPE_AUDIO || stream_type == AST_MEDIA_TYPE_VIDEO) && state_stream->instance) { + update_rtp_after_merge(sdp_state, state_stream->instance, sdp_state->options, + remote_sdp, ast_sdp_get_m(remote_sdp, i)); } } @@ -389,11 +829,10 @@ const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_stat { ast_assert(sdp_state != NULL); - if (!sdp_state->local_sdp) { - if (sdp_state_setup_local_streams(sdp_state)) { - return NULL; - } - sdp_state->local_sdp = ast_sdp_create_from_state(sdp_state); + if (sdp_state->role == SDP_ROLE_NOT_SET) { + ast_assert(sdp_state->local_sdp == NULL); + sdp_state->role = SDP_ROLE_OFFERER; + sdp_state->local_sdp = sdp_create_from_state(sdp_state, sdp_state->proposed_capabilities); } return sdp_state->local_sdp; @@ -410,11 +849,15 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state) return ast_sdp_translator_from_sdp(sdp_state->translator, sdp); } -void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, struct ast_sdp *sdp) +void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct ast_sdp *sdp) { ast_assert(sdp_state != NULL); - sdp_state->remote_sdp = sdp; + if (sdp_state->role == SDP_ROLE_NOT_SET) { + sdp_state->role = SDP_ROLE_ANSWERER; + } + + merge_sdps(sdp_state, sdp); } int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void *remote) @@ -427,8 +870,7 @@ int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void if (!sdp) { return -1; } - - sdp_state->remote_sdp = sdp; + ast_sdp_state_set_remote_sdp(sdp_state, sdp); return 0; } @@ -440,37 +882,27 @@ int ast_sdp_state_reset(struct ast_sdp_state *sdp_state) ast_sdp_free(sdp_state->local_sdp); sdp_state->local_sdp = NULL; - ast_sdp_free(sdp_state->remote_sdp); - sdp_state->remote_sdp = NULL; - - ast_sdp_free(sdp_state->joint_sdp); - sdp_state->joint_sdp = NULL; - ast_stream_topology_free(sdp_state->remote_capabilities); sdp_state->remote_capabilities = NULL; - ast_stream_topology_free(sdp_state->joint_capabilities.topology); - sdp_state->joint_capabilities.topology = NULL; + set_proposed_capabilities(sdp_state, NULL); - sdp_state->state = SDP_STATE_INITIAL; + sdp_state->role = SDP_ROLE_NOT_SET; return 0; } int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams) { + struct sdp_state_capabilities *capabilities; ast_assert(sdp_state != NULL); ast_assert(streams != NULL); - sdp_state_capabilities_free(&sdp_state->local_capabilities); - sdp_state->local_capabilities.topology = ast_stream_topology_clone(streams); - if (!sdp_state->local_capabilities.topology) { - return -1; - } - - if (AST_VECTOR_INIT(&sdp_state->local_capabilities.streams, ast_stream_topology_get_count(streams))) { + capabilities = merge_capabilities(sdp_state->proposed_capabilities, streams, sdp_state->options, 1); + if (!capabilities) { return -1; } + set_proposed_capabilities(sdp_state, capabilities); return 0; } @@ -480,9 +912,9 @@ void ast_sdp_state_set_local_address(struct ast_sdp_state *sdp_state, struct ast ast_assert(sdp_state != NULL); if (!address) { - ast_sockaddr_setnull(&sdp_state->local_capabilities.connection_address); + ast_sockaddr_setnull(&sdp_state->proposed_capabilities->connection_address); } else { - ast_sockaddr_copy(&sdp_state->local_capabilities.connection_address, address); + ast_sockaddr_copy(&sdp_state->proposed_capabilities->connection_address, address); } } @@ -533,3 +965,217 @@ unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_stat return stream_state->locally_held; } + +static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, + const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) +{ + struct ast_stream *stream; + struct ast_sdp_m_line *m_line; + struct ast_format_cap *caps; + int i; + int rtp_code; + int min_packet_size = 0; + int max_packet_size = 0; + enum ast_media_type media_type; + char tmp[64]; + struct ast_sockaddr address_rtp; + struct ast_rtp_instance *rtp; + struct ast_sdp_a_line *a_line; + + stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); + rtp = AST_VECTOR_GET(&capabilities->streams, stream_index)->instance; + + ast_assert(sdp && options && stream); + + media_type = ast_stream_get_type(stream); + if (rtp) { + if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_rtp)) { + return -1; + } + } else { + ast_sockaddr_setnull(&address_rtp); + } + + m_line = ast_sdp_m_alloc( + ast_codec_media_type2str(ast_stream_get_type(stream)), + ast_sockaddr_port(&address_rtp), 1, + options->encryption != AST_SDP_ENCRYPTION_DISABLED ? "RTP/SAVP" : "RTP/AVP", + NULL); + if (!m_line) { + return -1; + } + + caps = ast_stream_get_formats(stream); + + for (i = 0; i < ast_format_cap_count(caps); i++) { + struct ast_format *format = ast_format_cap_get_format(caps, i); + + if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) { + ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); + ao2_ref(format, -1); + continue; + } + + if (ast_sdp_m_add_format(m_line, options, rtp_code, 1, format, 0)) { + ast_sdp_m_free(m_line); + ao2_ref(format, -1); + return -1; + } + + if (ast_format_get_maximum_ms(format) && + ((ast_format_get_maximum_ms(format) < max_packet_size) || !max_packet_size)) { + max_packet_size = ast_format_get_maximum_ms(format); + } + + ao2_ref(format, -1); + } + + if (rtp && media_type != AST_MEDIA_TYPE_VIDEO) { + for (i = 1LL; i <= AST_RTP_MAX; i <<= 1) { + if (!(options->telephone_event & i)) { + continue; + } + + rtp_code = ast_rtp_codecs_payload_code( + ast_rtp_instance_get_codecs(rtp), 0, NULL, i); + + if (rtp_code == -1) { + continue; + } + + if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) { + continue; + } + + if (i == AST_RTP_DTMF) { + snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); + a_line = ast_sdp_a_alloc("fmtp", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + } + } + + if (ast_sdp_m_get_a_count(m_line) == 0) { + return 0; + } + + /* If ptime is set add it as an attribute */ + min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); + if (!min_packet_size) { + min_packet_size = ast_format_cap_get_framing(caps); + } + if (min_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", min_packet_size); + + a_line = ast_sdp_a_alloc("ptime", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + + if (max_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", max_packet_size); + a_line = ast_sdp_a_alloc("maxptime", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + + a_line = ast_sdp_a_alloc(ast_sdp_state_get_locally_held(sdp_state, stream_index) ? "sendonly" : "sendrecv", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + + if (ast_sdp_add_m(sdp, m_line)) { + ast_sdp_m_free(m_line); + return -1; + } + + return 0; +} + +/*! + * \brief Create an SDP based on current SDP state + * + * \param sdp_state The current SDP state + * \retval NULL Failed to create SDP + * \retval non-NULL Newly-created SDP + */ +static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_state, + const struct sdp_state_capabilities *capabilities) +{ + struct ast_sdp *sdp = NULL; + struct ast_stream_topology *topology; + const struct ast_sdp_options *options; + int stream_num; + struct ast_sdp_o_line *o_line = NULL; + struct ast_sdp_c_line *c_line = NULL; + struct ast_sdp_s_line *s_line = NULL; + struct ast_sdp_t_line *t_line = NULL; + char *address_type; + struct timeval tv = ast_tvnow(); + uint32_t t; + int stream_count; + + options = ast_sdp_state_get_options(sdp_state); + topology = capabilities->topology; + + t = tv.tv_sec + 2208988800UL; + address_type = (strchr(options->media_address, ':') ? "IP6" : "IP4"); + + o_line = ast_sdp_o_alloc(options->sdpowner, t, t, address_type, options->media_address); + if (!o_line) { + goto error; + } + c_line = ast_sdp_c_alloc(address_type, options->media_address); + if (!c_line) { + goto error; + } + + s_line = ast_sdp_s_alloc(options->sdpsession); + if (!s_line) { + goto error; + } + + sdp = ast_sdp_alloc(o_line, c_line, s_line, NULL); + if (!sdp) { + goto error; + } + + stream_count = ast_stream_topology_get_count(topology); + + for (stream_num = 0; stream_num < stream_count; stream_num++) { + enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num)); + + if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + if (sdp_add_m_from_rtp_stream(sdp, sdp_state, options, capabilities, stream_num)) { + goto error; + } + } + } + + return sdp; + +error: + if (sdp) { + ast_sdp_free(sdp); + } else { + ast_sdp_t_free(t_line); + ast_sdp_s_free(s_line); + ast_sdp_c_free(c_line); + ast_sdp_o_free(o_line); + } + + return NULL; +} + diff --git a/tests/test_sdp.c b/tests/test_sdp.c new file mode 100644 index 00000000000..38968aaaa85 --- /dev/null +++ b/tests/test_sdp.c @@ -0,0 +1,821 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium Inc. + * + * Mark Michelson + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/sdp.h" +#include "asterisk/stream.h" +#include "asterisk/format.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_cap.h" + +static int validate_o_line(struct ast_test *test, const struct ast_sdp_o_line *o_line, + const char *sdpowner, const char *address_type, const char *address) +{ + if (!o_line) { + return -1; + } + + if (strcmp(o_line->username, sdpowner)) { + ast_test_status_update(test, "Expected o-line SDP owner %s but got %s\n", + sdpowner, o_line->username); + return -1; + } + + if (strcmp(o_line->address_type, address_type)) { + ast_test_status_update(test, "Expected o-line SDP address type %s but got %s\n", + address_type, o_line->address_type); + return -1; + } + + if (strcmp(o_line->address, address)) { + ast_test_status_update(test, "Expected o-line SDP address %s but got %s\n", + address, o_line->address); + return -1; + } + + ast_test_status_update(test, "SDP o-line is as expected!\n"); + return 0; +} + +static int validate_c_line(struct ast_test *test, const struct ast_sdp_c_line *c_line, + const char *address_type, const char *address) +{ + if (strcmp(c_line->address_type, address_type)) { + ast_test_status_update(test, "Expected c-line SDP address type %s but got %s\n", + address_type, c_line->address_type); + return -1; + } + + if (strcmp(c_line->address, address)) { + ast_test_status_update(test, "Expected c-line SDP address %s but got %s\n", + address, c_line->address); + return -1; + } + + ast_test_status_update(test, "SDP c-line is as expected!\n"); + return 0; +} + +static int validate_m_line(struct ast_test *test, const struct ast_sdp_m_line *m_line, + const char *media_type, int num_payloads) +{ + if (strcmp(m_line->type, media_type)) { + ast_test_status_update(test, "Expected m-line media type %s but got %s\n", + media_type, m_line->type); + return -1; + } + + if (ast_sdp_m_get_payload_count(m_line) != num_payloads) { + ast_test_status_update(test, "Expected m-line payload count %d but got %d\n", + num_payloads, ast_sdp_m_get_payload_count(m_line)); + return -1; + } + + ast_test_status_update(test, "SDP m-line is as expected\n"); + return 0; +} + +static int validate_rtpmap(struct ast_test *test, const struct ast_sdp_m_line *m_line, + const char *media_name) +{ + struct ast_sdp_a_line *a_line; + int i; + + for (i = 0; i < ast_sdp_m_get_a_count(m_line); ++i) { + struct ast_sdp_rtpmap *rtpmap; + int match; + + a_line = ast_sdp_m_get_a(m_line, i); + if (strcmp(a_line->name, "rtpmap")) { + continue; + } + + rtpmap = ast_sdp_a_get_rtpmap(a_line); + if (!rtpmap) { + return -1; + } + + match = !strcmp(rtpmap->encoding_name, media_name); + + ast_sdp_rtpmap_free(rtpmap); + if (match) { + return 0; + } + } + + ast_test_status_update(test, "Could not find rtpmap with encoding name %s\n", media_name); + + return -1; +} + +AST_TEST_DEFINE(invalid_rtpmap) +{ + /* a=rtpmap: is already assumed. This is the part after that */ + static const char *invalids[] = { + "J PCMU/8000", + "0 PCMU:8000", + "0 PCMU/EIGHT-THOUSAND", + "0 PCMU/8000million/2", + "0 PCMU//2", + "0 /8000/2", + "0 PCMU/8000/", + "0 PCMU/8000million", + }; + int i; + enum ast_test_result_state res = AST_TEST_PASS; + + switch(cmd) { + case TEST_INIT: + info->name = "invalid_rtpmap"; + info->category = "/main/sdp/"; + info->summary = "Ensure invalid rtpmaps are rejected"; + info->description = + "Try to convert several invalid rtpmap attributes. If\n" + "any succeeds, the test fails."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + for (i = 0; i < ARRAY_LEN(invalids); ++i) { + struct ast_sdp_a_line *a_line; + struct ast_sdp_rtpmap *rtpmap; + + a_line = ast_sdp_a_alloc("rtpmap", invalids[i]); + rtpmap = ast_sdp_a_get_rtpmap(a_line); + if (rtpmap) { + ast_test_status_update(test, "Invalid rtpmap '%s' was accepted as valid\n", + invalids[i]); + res = AST_TEST_FAIL; + } + ast_sdp_a_free(a_line); + ast_sdp_rtpmap_free(rtpmap); + } + + return res; +} + +AST_TEST_DEFINE(rtpmap) +{ + static const char *valids[] = { + "0 PCMU/8000", + "107 opus/48000/2", + }; + static int payloads[] = { + 0, + 107, + }; + static const char *encoding_names[] = { + "PCMU", + "opus", + }; + static int clock_rates[] = { + 8000, + 48000, + }; + static const char *encoding_parameters[] = { + "", + "2", + }; + int i; + enum ast_test_result_state res = AST_TEST_PASS; + + switch(cmd) { + case TEST_INIT: + info->name = "rtpmap"; + info->category = "/main/sdp/"; + info->summary = "Ensure rtpmap attribute values are parsed correctly"; + info->description = + "Parse several valid rtpmap attributes. Ensure that the parsed values\n" + "are what we expect"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + for (i = 0; i < ARRAY_LEN(valids); ++i) { + struct ast_sdp_a_line *a_line; + struct ast_sdp_rtpmap *rtpmap; + + a_line = ast_sdp_a_alloc("rtpmap", valids[i]); + rtpmap = ast_sdp_a_get_rtpmap(a_line); + if (!rtpmap) { + ast_test_status_update(test, "Valid rtpmap '%s' was rejected as invalid\n", + valids[i]); + res = AST_TEST_FAIL; + continue; + } + if (rtpmap->payload != payloads[i]) { + ast_test_status_update(test, "RTPmap payload '%d' does not match expected '%d'\n", + rtpmap->payload, payloads[i]); + res = AST_TEST_FAIL; + } + if (strcmp(rtpmap->encoding_name, encoding_names[i])) { + ast_test_status_update(test, "RTPmap encoding_name '%s' does not match expected '%s'\n", + rtpmap->encoding_name, encoding_names[i]); + res = AST_TEST_FAIL; + } + if (rtpmap->clock_rate != clock_rates[i]) { + ast_test_status_update(test, "RTPmap clock rate '%d' does not match expected '%d'\n", + rtpmap->clock_rate, clock_rates[i]); + res = AST_TEST_FAIL; + } + if (strcmp(rtpmap->encoding_parameters, encoding_parameters[i])) { + ast_test_status_update(test, "RTPmap encoding_parameter '%s' does not match expected '%s'\n", + rtpmap->encoding_parameters, encoding_parameters[i]); + res = AST_TEST_FAIL; + } + ast_sdp_a_free(a_line); + ast_sdp_rtpmap_free(rtpmap); + } + + return res; +} + +AST_TEST_DEFINE(find_attr) +{ + enum ast_test_result_state res = AST_TEST_PASS; + struct ast_sdp_m_line *m_line; + struct ast_sdp_a_line *a_line; + + switch(cmd) { + case TEST_INIT: + info->name = "find_attr"; + info->category = "/main/sdp/"; + info->summary = "Ensure that finding attributes works as expected"; + info->description = + "An SDP m-line is created, and two attributes are added.\n" + "We then attempt a series of attribute-finding calls that are expected to work\n" + "followed by a series of attribute-finding calls that are expected fo fail."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + m_line = ast_sdp_m_alloc("audio", 666, 1, "RTP/AVP", NULL); + if (!m_line) { + res = AST_TEST_FAIL; + goto end; + } + a_line = ast_sdp_a_alloc("foo", "0 bar"); + if (!a_line) { + res = AST_TEST_FAIL; + goto end; + } + ast_sdp_m_add_a(m_line, a_line); + + a_line = ast_sdp_a_alloc("baz", "howdy"); + if (!a_line) { + res = AST_TEST_FAIL; + goto end; + } + ast_sdp_m_add_a(m_line, a_line); + + /* These should work */ + a_line = ast_sdp_m_find_attribute(m_line, "foo", 0); + if (!a_line) { + ast_test_status_update(test, "Failed to find attribute 'foo' with payload '0'\n"); + res = AST_TEST_FAIL; + } + a_line = ast_sdp_m_find_attribute(m_line, "foo", -1); + if (!a_line) { + ast_test_status_update(test, "Failed to find attribute 'foo' with unspecified payload\n"); + res = AST_TEST_FAIL; + } + a_line = ast_sdp_m_find_attribute(m_line, "baz", -1); + if (!a_line) { + ast_test_status_update(test, "Failed to find attribute 'baz' with unspecified payload\n"); + res = AST_TEST_FAIL; + } + + /* These should fail */ + a_line = ast_sdp_m_find_attribute(m_line, "foo", 1); + if (a_line) { + ast_test_status_update(test, "Found non-existent attribute 'foo' with payload '1'\n"); + res = AST_TEST_FAIL; + } + a_line = ast_sdp_m_find_attribute(m_line, "baz", 0); + if (a_line) { + ast_test_status_update(test, "Found non-existent attribute 'baz' with payload '0'\n"); + res = AST_TEST_FAIL; + } + a_line = ast_sdp_m_find_attribute(m_line, "wibble", 0); + if (a_line) { + ast_test_status_update(test, "Found non-existent attribute 'wibble' with payload '0'\n"); + res = AST_TEST_FAIL; + } + a_line = ast_sdp_m_find_attribute(m_line, "wibble", -1); + if (a_line) { + ast_test_status_update(test, "Found non-existent attribute 'foo' with unspecified payload\n"); + res = AST_TEST_FAIL; + } + +end: + ast_sdp_m_free(m_line); + return res; +} + +struct sdp_format { + enum ast_media_type type; + const char *formats; +}; + +static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats) +{ + struct ast_stream_topology *topology = NULL; + struct ast_sdp_state *state = NULL; + struct ast_sdp_options *options; + int i; + + options = ast_sdp_options_alloc(); + if (!options) { + goto end; + } + ast_sdp_options_set_media_address(options, "127.0.0.1"); + ast_sdp_options_set_sdpowner(options, "me"); + ast_sdp_options_set_rtp_engine(options, "asterisk"); + ast_sdp_options_set_impl(options, AST_SDP_IMPL_PJMEDIA); + + topology = ast_stream_topology_alloc(); + if (!topology) { + goto end; + } + + for (i = 0; i < num_streams; ++i) { + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + struct ast_stream *stream; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + goto end; + } + if (ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) { + goto end; + } + stream = ast_stream_alloc("sure_thing", formats[i].type); + if (!stream) { + goto end; + } + ast_stream_set_formats(stream, caps); + ast_stream_topology_append_stream(topology, stream); + } + + state = ast_sdp_state_alloc(topology, options); + if (!state) { + goto end; + } + +end: + ast_stream_topology_free(topology); + if (!state) { + ast_sdp_options_free(options); + } + + return state; +} + +AST_TEST_DEFINE(topology_to_sdp) +{ + enum ast_test_result_state res = AST_TEST_FAIL; + struct ast_sdp_state *sdp_state = NULL; + const struct ast_sdp *sdp = NULL; + struct ast_sdp_m_line *m_line = NULL; + struct sdp_format formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, + { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + }; + + switch(cmd) { + case TEST_INIT: + info->name = "topology_to_sdp"; + info->category = "/main/sdp/"; + info->summary = "Convert a topology into an SDP"; + info->description = + "Ensure SDPs get converted to expected stream topology"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + sdp_state = build_sdp_state(ARRAY_LEN(formats), formats); + if (!sdp_state) { + goto end; + } + + sdp = ast_sdp_state_get_local_sdp(sdp_state); + if (!sdp) { + goto end; + } + + if (validate_o_line(test, sdp->o_line, "me", "IP4", "127.0.0.1")) { + goto end; + } + + if (validate_c_line(test, sdp->c_line, "IP4", "127.0.0.1")) { + goto end; + } + + if (ast_sdp_get_m_count(sdp) != 2) { + ast_test_status_update(test, "Unexpected number of streams in generated SDP: %d\n", + ast_sdp_get_m_count(sdp)); + goto end; + } + + m_line = ast_sdp_get_m(sdp, 0); + + if (validate_m_line(test, m_line, "audio", 4)) { + goto end; + } + + if (validate_rtpmap(test, m_line, "PCMU")) { + goto end; + } + + if (validate_rtpmap(test, m_line, "PCMA")) { + goto end; + } + + if (validate_rtpmap(test, m_line, "G722")) { + goto end; + } + + if (validate_rtpmap(test, m_line, "opus")) { + goto end; + } + + m_line = ast_sdp_get_m(sdp, 1); + if (validate_m_line(test, m_line, "video", 2)) { + goto end; + } + + if (validate_rtpmap(test, m_line, "VP8")) { + goto end; + } + + if (validate_rtpmap(test, m_line, "H264")) { + goto end; + } + + res = AST_TEST_PASS; + +end: + ast_sdp_state_free(sdp_state); + return res; +} + +static int validate_formats(struct ast_test *test, struct ast_stream_topology *topology, int index, + enum ast_media_type type, int format_count, const char **expected_formats) +{ + struct ast_stream *stream; + struct ast_format_cap *caps; + struct ast_format *format; + int i; + + stream = ast_stream_topology_get_stream(topology, index); + if (ast_stream_get_type(stream) != type) { + ast_test_status_update(test, "Unexpected stream type encountered\n"); + return -1; + } + caps = ast_stream_get_formats(stream); + + if (ast_format_cap_count(caps) != format_count) { + ast_test_status_update(test, "Unexpected format count '%d'. Expecting '%d'\n", + (int) ast_format_cap_count(caps), format_count); + return -1; + } + + for (i = 0; i < ast_format_cap_count(caps); ++i) { + format = ast_format_cap_get_format(caps, i); + if (strcmp(ast_format_get_name(format), expected_formats[i])) { + ast_test_status_update(test, "Unexpected format '%s'at index %d. Expected '%s'\n", + ast_format_get_name(format), i, expected_formats[i]); + return -1; + } + } + + return 0; +} + +AST_TEST_DEFINE(sdp_to_topology) +{ + enum ast_test_result_state res = AST_TEST_PASS; + struct ast_sdp_state *sdp_state; + const struct ast_sdp *sdp; + struct ast_stream_topology *topology = NULL; + struct sdp_format sdp_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, + { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + }; + static const char *expected_audio_formats[] = { + "ulaw", + "alaw", + "g722", + "opus", + }; + static const char *expected_video_formats[] = { + "h264", + "vp8", + }; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_to_topology"; + info->category = "/main/sdp/"; + info->summary = "Convert an SDP into a topology"; + info->description = + "Ensure SDPs get converted to expected stream topology"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats); + if (!sdp_state) { + res = AST_TEST_FAIL; + goto end; + } + + sdp = ast_sdp_state_get_local_sdp(sdp_state); + if (!sdp) { + res = AST_TEST_FAIL; + goto end; + } + + topology = ast_get_topology_from_sdp(sdp); + + if (ast_stream_topology_get_count(topology) != 2) { + ast_test_status_update(test, "Unexpected topology count '%d'. Expecting 2\n", + ast_stream_topology_get_count(topology)); + res = AST_TEST_FAIL; + goto end; + } + + if (validate_formats(test, topology, 0, AST_MEDIA_TYPE_AUDIO, + ARRAY_LEN(expected_audio_formats), expected_audio_formats)) { + res = AST_TEST_FAIL; + goto end; + } + + if (validate_formats(test, topology, 1, AST_MEDIA_TYPE_VIDEO, + ARRAY_LEN(expected_video_formats), expected_video_formats)) { + res = AST_TEST_FAIL; + goto end; + } + +end: + ast_sdp_state_free(sdp_state); + ast_stream_topology_free(topology); + return res; +} + +static int validate_merged_sdp(struct ast_test *test, const struct ast_sdp *sdp) +{ + struct ast_sdp_m_line *m_line; + + if (!sdp) { + return -1; + } + + m_line = ast_sdp_get_m(sdp, 0); + + if (validate_m_line(test, m_line, "audio", 1)) { + return -1; + } + + if (validate_rtpmap(test, m_line, "PCMU")) { + return -1; + } + + /* The other audio formats should *NOT* be present */ + if (!validate_rtpmap(test, m_line, "PCMA")) { + return -1; + } + + if (!validate_rtpmap(test, m_line, "G722")) { + return -1; + } + + if (!validate_rtpmap(test, m_line, "opus")) { + return -1; + } + + m_line = ast_sdp_get_m(sdp, 1); + + if (validate_m_line(test, m_line, "video", 1)) { + return -1; + } + + if (validate_rtpmap(test, m_line, "VP8")) { + return -1; + } + + if (!validate_rtpmap(test, m_line, "H264")) { + return -1; + } + + return 0; +} + +AST_TEST_DEFINE(sdp_merge_symmetric) +{ + enum ast_test_result_state res = AST_TEST_PASS; + struct ast_sdp_state *sdp_state_offerer = NULL; + struct ast_sdp_state *sdp_state_answerer = NULL; + const struct ast_sdp *offerer_sdp; + const struct ast_sdp *answerer_sdp; + + static const struct sdp_format offerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, + { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + }; + static const struct sdp_format answerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + { AST_MEDIA_TYPE_VIDEO, "vp8" }, + }; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_merge_symmetric"; + info->category = "/main/sdp/"; + info->summary = "Merge two SDPs with symmetric stream types"; + info->description = + "SDPs 1 and 2 each have one audio and one video stream (in that order).\n" + "SDP 1 offers to SDP 2, who answers. We ensure that both local SDPs have\n" + "the expected stream types and the expected formats"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats); + if (!sdp_state_offerer) { + res = AST_TEST_FAIL; + goto end; + } + + sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats); + if (!sdp_state_answerer) { + res = AST_TEST_FAIL; + goto end; + } + + offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); + if (!offerer_sdp) { + res = AST_TEST_FAIL; + goto end; + } + + ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp); + answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); + if (!answerer_sdp) { + res = AST_TEST_FAIL; + goto end; + } + + ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp); + + /* Get the offerer SDP again because it's now going to be the joint SDP */ + offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); + if (validate_merged_sdp(test, offerer_sdp)) { + res = AST_TEST_FAIL; + goto end; + } + if (validate_merged_sdp(test, answerer_sdp)) { + res = AST_TEST_FAIL; + goto end; + } + +end: + ast_sdp_state_free(sdp_state_offerer); + ast_sdp_state_free(sdp_state_answerer); + + return res; +} + +AST_TEST_DEFINE(sdp_merge_crisscross) +{ + enum ast_test_result_state res = AST_TEST_PASS; + struct ast_sdp_state *sdp_state_offerer = NULL; + struct ast_sdp_state *sdp_state_answerer = NULL; + const struct ast_sdp *offerer_sdp; + const struct ast_sdp *answerer_sdp; + + static const struct sdp_format offerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, + { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + }; + static const struct sdp_format answerer_formats[] = { + { AST_MEDIA_TYPE_VIDEO, "vp8" }, + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + }; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_merge_crisscross"; + info->category = "/main/sdp/"; + info->summary = "Merge two SDPs with symmetric stream types"; + info->description = + "SDPs 1 and 2 each have one audio and one video stream. However, SDP 1 and\n" + "2 natively have the formats in a different order.\n" + "SDP 1 offers to SDP 2, who answers. We ensure that both local SDPs have\n" + "the expected stream types and the expected formats. Since SDP 1 was the\n" + "offerer, the format order on SDP 1 should determine the order of formats in the SDPs"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats); + if (!sdp_state_offerer) { + res = AST_TEST_FAIL; + goto end; + } + + sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats); + if (!sdp_state_answerer) { + res = AST_TEST_FAIL; + goto end; + } + + offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); + if (!offerer_sdp) { + res = AST_TEST_FAIL; + goto end; + } + + ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp); + answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); + if (!answerer_sdp) { + res = AST_TEST_FAIL; + goto end; + } + + ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp); + + /* Get the offerer SDP again because it's now going to be the joint SDP */ + offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); + if (validate_merged_sdp(test, offerer_sdp)) { + res = AST_TEST_FAIL; + goto end; + } + if (validate_merged_sdp(test, answerer_sdp)) { + res = AST_TEST_FAIL; + goto end; + } + +end: + ast_sdp_state_free(sdp_state_offerer); + ast_sdp_state_free(sdp_state_answerer); + + return res; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(invalid_rtpmap); + AST_TEST_UNREGISTER(rtpmap); + AST_TEST_UNREGISTER(find_attr); + AST_TEST_UNREGISTER(topology_to_sdp); + AST_TEST_UNREGISTER(sdp_to_topology); + AST_TEST_UNREGISTER(sdp_merge_symmetric); + AST_TEST_UNREGISTER(sdp_merge_crisscross); + + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(invalid_rtpmap); + AST_TEST_REGISTER(rtpmap); + AST_TEST_REGISTER(find_attr); + AST_TEST_REGISTER(topology_to_sdp); + AST_TEST_REGISTER(sdp_to_topology); + AST_TEST_REGISTER(sdp_merge_symmetric); + AST_TEST_REGISTER(sdp_merge_crisscross); + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SDP tests"); From 19a79ae12c73992508910d2c7cddc059e10bc48c Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 14 Apr 2017 10:21:13 +0000 Subject: [PATCH 1217/1578] sdp: Add support for T.38 This change adds a T.38 format which can be used in a stream topology to specify that a UDPTL stream needs to be created. The SDP API has been changed to understand T.38 and create the UDPTL session, add the attributes, and parse the attributes. This change does not change the boundary of the T.38 state machine. It is still up to the channel driver to implement and act on it (such as queueing control frames or reacting to them). ASTERISK-26949 Change-Id: If28956762ccb8ead562ac6c03d162d3d6014f2c7 --- include/asterisk/format_cache.h | 5 + include/asterisk/sdp_options.h | 82 ++++++ include/asterisk/sdp_state.h | 21 ++ main/codec_builtin.c | 7 + main/format_cache.c | 8 + main/sdp.c | 61 +++-- main/sdp_options.c | 4 + main/sdp_private.h | 4 + main/sdp_state.c | 439 ++++++++++++++++++++++++++++++-- tests/test_sdp.c | 39 ++- 10 files changed, 623 insertions(+), 47 deletions(-) diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h index 6099c59ea97..92272e8ebac 100644 --- a/include/asterisk/format_cache.h +++ b/include/asterisk/format_cache.h @@ -223,6 +223,11 @@ extern struct ast_format *ast_format_t140; */ extern struct ast_format *ast_format_t140_red; +/*! + * \brief Built-in cached T.38 format. + */ +extern struct ast_format *ast_format_t38; + /*! * \brief Built-in "null" format. */ diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index 4b411c77122..af694cd140e 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -19,6 +19,8 @@ #ifndef _ASTERISK_SDP_OPTIONS_H #define _ASTERISK_SDP_OPTIONS_H +#include "asterisk/udptl.h" + struct ast_sdp_options; /*! @@ -427,4 +429,84 @@ unsigned int ast_sdp_options_get_rtcp_mux(const struct ast_sdp_options *options) */ void ast_sdp_options_set_rtcp_mux(struct ast_sdp_options *options, unsigned int value); +/*! + * \since 15.0.0 + * \brief Set SDP Options udptl_symmetric + * + * \param options SDP Options + * \param udptl_symmetric + */ +void ast_sdp_options_set_udptl_symmetric(struct ast_sdp_options *options, + unsigned int udptl_symmetric); + +/*! + * \since 15.0.0 + * \brief Get SDP Options udptl_symmetric + * + * \param options SDP Options + * + * \returns udptl_symmetric + */ +unsigned int ast_sdp_options_get_udptl_symmetric(const struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options udptl_error_correction + * + * \param options SDP Options + * \param error_correction + */ +void ast_sdp_options_set_udptl_error_correction(struct ast_sdp_options *options, + enum ast_t38_ec_modes error_correction); + +/*! + * \since 15.0.0 + * \brief Get SDP Options udptl_error_correction + * + * \param options SDP Options + * + * \returns udptl_error_correction + */ +enum ast_t38_ec_modes ast_sdp_options_get_udptl_error_correction(const struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options udptl_far_max_datagram + * + * \param options SDP Options + * \param far_max_datagram + */ +void ast_sdp_options_set_udptl_far_max_datagram(struct ast_sdp_options *options, + unsigned int far_max_datagram); + +/*! + * \since 15.0.0 + * \brief Get SDP Options udptl_far_max_datagram + * + * \param options SDP Options + * + * \returns udptl_far_max_datagram + */ +unsigned int ast_sdp_options_get_udptl_far_max_datagram(const struct ast_sdp_options *options); + +/*! + * \since 15.0.0 + * \brief Set SDP Options bind_udptl_to_media_address + * + * \param options SDP Options + * \param bind_udptl_to_media_address + */ +void ast_sdp_options_set_bind_udptl_to_media_address(struct ast_sdp_options *options, + unsigned int bind_udptl_to_media_address); + +/*! + * \since 15.0.0 + * \brief Get SDP Options bind_udptl_to_media_address + * + * \param options SDP Options + * + * \returns bind_udptl_to_media_address + */ +unsigned int ast_sdp_options_get_bind_udptl_to_media_address(const struct ast_sdp_options *options); + #endif /* _ASTERISK_SDP_OPTIONS_H */ diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index 7f25c25322e..1382ed6af66 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -24,6 +24,8 @@ struct ast_sdp_state; struct ast_sockaddr; +struct ast_udptl; +struct ast_control_t38_parameters; /*! * \brief Allocate a new SDP state @@ -51,6 +53,14 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state); struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(const struct ast_sdp_state *sdp_state, int stream_index); +/*! + * \brief Get the associated UDPTL instance for a particular stream on the SDP state. + * + * Stream numbers correspond to the streams in the topology of the associated channel + */ +struct ast_udptl *ast_sdp_state_get_udptl_instance(const struct ast_sdp_state *sdp_state, + int stream_index); + /*! * \brief Get the global connection address on the SDP state. */ @@ -223,6 +233,17 @@ int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int st void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state, int stream_index, unsigned int locally_held); +/*! + * \since 15.0.0 + * \brief Set the UDPTL session parameters + * + * \param sdp_state + * \param stream_index The stream to set the UDPTL session parameters for + * \param params + */ +void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state, + int stream_index, struct ast_control_t38_parameters *params); + /*! * \since 15.0.0 * \brief Get whether a stream is held or not diff --git a/main/codec_builtin.c b/main/codec_builtin.c index f622c910575..3320900c2e3 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -822,6 +822,12 @@ static struct ast_codec t140 = { .type = AST_MEDIA_TYPE_TEXT, }; +static struct ast_codec t38 = { + .name = "t38", + .description = "T.38 UDPTL Fax", + .type = AST_MEDIA_TYPE_IMAGE, +}; + static int silk_samples(struct ast_frame *frame) { /* XXX This is likely not at all what's intended from this callback. However, @@ -952,6 +958,7 @@ int ast_codec_builtin_init(void) res |= CODEC_REGISTER_AND_CACHE(vp8); res |= CODEC_REGISTER_AND_CACHE(t140red); res |= CODEC_REGISTER_AND_CACHE(t140); + res |= CODEC_REGISTER_AND_CACHE(t38); res |= CODEC_REGISTER_AND_CACHE(none); res |= CODEC_REGISTER_AND_CACHE_NAMED("silk8", silk8); res |= CODEC_REGISTER_AND_CACHE_NAMED("silk12", silk12); diff --git a/main/format_cache.c b/main/format_cache.c index d0ae32e68dc..302bbf827e7 100644 --- a/main/format_cache.c +++ b/main/format_cache.c @@ -230,6 +230,11 @@ struct ast_format *ast_format_t140; */ struct ast_format *ast_format_t140_red; +/*! + * \brief Built-in cached T.38 format. + */ +struct ast_format *ast_format_t38; + /*! * \brief Built-in "null" format. */ @@ -342,6 +347,7 @@ static void format_cache_shutdown(void) ao2_replace(ast_format_vp8, NULL); ao2_replace(ast_format_t140_red, NULL); ao2_replace(ast_format_t140, NULL); + ao2_replace(ast_format_t38, NULL); ao2_replace(ast_format_none, NULL); ao2_replace(ast_format_silk8, NULL); ao2_replace(ast_format_silk12, NULL); @@ -442,6 +448,8 @@ static void set_cached_format(const char *name, struct ast_format *format) ao2_replace(ast_format_t140_red, format); } else if (!strcmp(name, "t140")) { ao2_replace(ast_format_t140, format); + } else if (!strcmp(name, "t38")) { + ao2_replace(ast_format_t38, format); } else if (!strcmp(name, "none")) { ao2_replace(ast_format_none, format); } else if (!strcmp(name, "silk8")) { diff --git a/main/sdp.c b/main/sdp.c index 75a9da94d9b..dc6afe7d8a4 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -23,6 +23,7 @@ #include "asterisk/codec.h" #include "asterisk/format.h" #include "asterisk/format_cap.h" +#include "asterisk/format_cache.h" #include "asterisk/rtp_engine.h" #include "asterisk/sdp_state.h" #include "asterisk/sdp_options.h" @@ -712,34 +713,56 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line) ao2_ref(caps, -1); return NULL; } - ast_rtp_codecs_payloads_initialize(&codecs); - for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { - struct ast_sdp_payload *payload_s; - struct ast_sdp_rtpmap *rtpmap; - int payload; + switch (ast_stream_get_type(stream)) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + ast_rtp_codecs_payloads_initialize(&codecs); - payload_s = ast_sdp_m_get_payload(m_line, i); - sscanf(payload_s->fmt, "%30d", &payload); - ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, payload); + for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { + struct ast_sdp_payload *payload_s; + struct ast_sdp_rtpmap *rtpmap; + int payload; - rtpmap = sdp_payload_get_rtpmap(m_line, payload); - if (!rtpmap) { - continue; + payload_s = ast_sdp_m_get_payload(m_line, i); + sscanf(payload_s->fmt, "%30d", &payload); + ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, payload); + + rtpmap = sdp_payload_get_rtpmap(m_line, payload); + if (!rtpmap) { + continue; + } + ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, + payload, m_line->type, rtpmap->encoding_name, 0, + rtpmap->clock_rate); + ast_sdp_rtpmap_free(rtpmap); + + process_fmtp(m_line, payload, &codecs); } - ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, - payload, m_line->type, rtpmap->encoding_name, 0, - rtpmap->clock_rate); - ast_sdp_rtpmap_free(rtpmap); - process_fmtp(m_line, payload, &codecs); + ast_rtp_codecs_payload_formats(&codecs, caps, &non_ast_fmts); + ast_rtp_codecs_payloads_destroy(&codecs); + break; + case AST_MEDIA_TYPE_IMAGE: + for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { + struct ast_sdp_payload *payload; + + /* As we don't carry T.38 over RTP we do our own format check */ + payload = ast_sdp_m_get_payload(m_line, i); + if (!strcasecmp(payload->fmt, "t38")) { + ast_format_cap_append(caps, ast_format_t38, 0); + } + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; } - ast_rtp_codecs_payload_formats(&codecs, caps, &non_ast_fmts); ast_stream_set_formats(stream, caps); - ao2_ref(caps, -1); - ast_rtp_codecs_payloads_destroy(&codecs); + return stream; } diff --git a/main/sdp_options.c b/main/sdp_options.c index 1162f693bc0..ef056a19075 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -60,7 +60,11 @@ DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpsession, 0); DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(rtp_engine, 0); DEFINE_GETTERS_SETTERS_FOR(unsigned int, bind_rtp_to_media_address); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, bind_udptl_to_media_address); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_symmetric); +DEFINE_GETTERS_SETTERS_FOR(enum ast_t38_ec_modes, udptl_error_correction); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_far_max_datagram); DEFINE_GETTERS_SETTERS_FOR(unsigned int, telephone_event); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_ipv6); DEFINE_GETTERS_SETTERS_FOR(unsigned int, g726_non_standard); diff --git a/main/sdp_private.h b/main/sdp_private.h index 15b9d1ecc47..f2efe86e530 100644 --- a/main/sdp_private.h +++ b/main/sdp_private.h @@ -35,7 +35,9 @@ struct ast_sdp_options { ); struct { unsigned int bind_rtp_to_media_address : 1; + unsigned int bind_udptl_to_media_address : 1; unsigned int rtp_symmetric : 1; + unsigned int udptl_symmetric : 1; unsigned int telephone_event : 1; unsigned int rtp_ipv6 : 1; unsigned int g726_non_standard : 1; @@ -47,10 +49,12 @@ struct ast_sdp_options { unsigned int cos_audio; unsigned int tos_video; unsigned int cos_video; + unsigned int udptl_far_max_datagram; }; enum ast_sdp_options_ice ice; enum ast_sdp_options_impl impl; enum ast_sdp_options_encryption encryption; + enum ast_t38_ec_modes udptl_error_correction; }; #endif /* _MAIN_SDP_PRIVATE_H */ diff --git a/main/sdp_state.c b/main/sdp_state.c index fc7fff44923..5aee567d3b3 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -28,6 +28,7 @@ #include "asterisk/format_cap.h" #include "asterisk/config.h" #include "asterisk/codec.h" +#include "asterisk/udptl.h" #include "../include/asterisk/sdp.h" #include "asterisk/stream.h" @@ -63,21 +64,53 @@ enum ast_sdp_role { typedef int (*state_fn)(struct ast_sdp_state *state); +struct sdp_state_udptl { + /*! The underlying UDPTL instance */ + struct ast_udptl *instance; +}; + struct sdp_state_stream { + /*! Type of the stream */ + enum ast_media_type type; union { /*! The underlying RTP instance */ struct ast_rtp_instance *instance; + /*! The underlying UDPTL instance */ + struct sdp_state_udptl *udptl; }; /*! An explicit connection address for this stream */ struct ast_sockaddr connection_address; /*! Whether this stream is held or not */ unsigned int locally_held; + /*! UDPTL session parameters */ + struct ast_control_t38_parameters t38_local_params; }; +static void sdp_state_udptl_destroy(void *obj) +{ + struct sdp_state_udptl *udptl = obj; + + if (udptl->instance) { + ast_udptl_destroy(udptl->instance); + } +} + static void sdp_state_stream_free(struct sdp_state_stream *state_stream) { - if (state_stream->instance) { - ast_rtp_instance_destroy(state_stream->instance); + switch (state_stream->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + if (state_stream->instance) { + ast_rtp_instance_destroy(state_stream->instance); + } + break; + case AST_MEDIA_TYPE_IMAGE: + ao2_cleanup(state_stream->udptl); + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; } ast_free(state_stream); } @@ -165,6 +198,43 @@ static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options return rtp; } +/*! \brief Internal function which creates a UDPTL instance */ +static struct sdp_state_udptl *create_udptl(const struct ast_sdp_options *options) +{ + struct sdp_state_udptl *udptl; + struct ast_sockaddr temp_media_address; + static struct ast_sockaddr address_udptl; + struct ast_sockaddr *media_address = &address_udptl; + + if (options->bind_udptl_to_media_address && !ast_strlen_zero(options->media_address)) { + ast_sockaddr_parse(&temp_media_address, options->media_address, 0); + media_address = &temp_media_address; + } else { + if (ast_check_ipv6()) { + ast_sockaddr_parse(&address_udptl, "::", 0); + } else { + ast_sockaddr_parse(&address_udptl, "0.0.0.0", 0); + } + } + + udptl = ao2_alloc_options(sizeof(*udptl), sdp_state_udptl_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!udptl) { + return NULL; + } + + udptl->instance = ast_udptl_new_with_bindaddr(NULL, NULL, 0, media_address); + if (!udptl->instance) { + ao2_ref(udptl, -1); + return NULL; + } + + ast_udptl_set_error_correction_scheme(udptl->instance, ast_sdp_options_get_udptl_error_correction(options)); + ast_udptl_setnat(udptl->instance, ast_sdp_options_get_udptl_symmetric(options)); + ast_udptl_set_far_max_datagram(udptl->instance, ast_sdp_options_get_udptl_far_max_datagram(options)); + + return udptl; +} + static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const struct ast_stream_topology *topology, const struct ast_sdp_options *options) { @@ -191,22 +261,34 @@ static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const st for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { struct sdp_state_stream *state_stream; - enum ast_media_type stream_type; state_stream = ast_calloc(1, sizeof(*state_stream)); if (!state_stream) { return NULL; } - stream_type = ast_stream_get_type(ast_stream_topology_get_stream(topology, i)); - - if (stream_type == AST_MEDIA_TYPE_AUDIO || stream_type == AST_MEDIA_TYPE_VIDEO) { - state_stream->instance = create_rtp(options, stream_type); - } + state_stream->type = ast_stream_get_type(ast_stream_topology_get_stream(topology, i)); - if (!state_stream->instance) { - sdp_state_stream_free(state_stream); - return NULL; + switch (state_stream->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + state_stream->instance = create_rtp(options, state_stream->type); + if (!state_stream->instance) { + sdp_state_stream_free(state_stream); + return NULL; + } + break; + case AST_MEDIA_TYPE_IMAGE: + state_stream->udptl = create_udptl(options); + if (!state_stream->udptl) { + sdp_state_stream_free(state_stream); + return NULL; + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; } AST_VECTOR_APPEND(&capabilities->streams, state_stream); @@ -314,6 +396,9 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( struct sdp_state_stream *stream_state; ast_assert(sdp_state != NULL); + ast_assert(ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->proposed_capabilities->topology, + stream_index)) == AST_MEDIA_TYPE_AUDIO || ast_stream_get_type(ast_stream_topology_get_stream( + sdp_state->proposed_capabilities->topology, stream_index)) == AST_MEDIA_TYPE_VIDEO); stream_state = sdp_state_get_stream(sdp_state, stream_index); if (!stream_state) { @@ -323,6 +408,23 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( return stream_state->instance; } +struct ast_udptl *ast_sdp_state_get_udptl_instance( + const struct ast_sdp_state *sdp_state, int stream_index) +{ + struct sdp_state_stream *stream_state; + + ast_assert(sdp_state != NULL); + ast_assert(ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->proposed_capabilities->topology, + stream_index)) == AST_MEDIA_TYPE_IMAGE); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state || !stream_state->udptl) { + return NULL; + } + + return stream_state->udptl->instance; +} + const struct ast_sockaddr *ast_sdp_state_get_connection_address(const struct ast_sdp_state *sdp_state) { ast_assert(sdp_state != NULL); @@ -334,7 +436,6 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_ int stream_index, struct ast_sockaddr *address) { struct sdp_state_stream *stream_state; - enum ast_media_type type; ast_assert(sdp_state != NULL); ast_assert(address != NULL); @@ -350,12 +451,18 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_ return 0; } - type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->proposed_capabilities->topology, - stream_index)); - - if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + switch (ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->proposed_capabilities->topology, + stream_index))) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: ast_rtp_instance_get_local_address(stream_state->instance, address); - } else { + break; + case AST_MEDIA_TYPE_IMAGE: + ast_udptl_get_us(stream_state->udptl->instance, address); + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: return -1; } @@ -556,7 +663,22 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ } current_state_stream = AST_VECTOR_GET(¤t->streams, current_index); - joint_state_stream->instance = ao2_bump(current_state_stream->instance); + joint_state_stream->type = current_state_stream->type; + + switch (joint_state_stream->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + joint_state_stream->instance = ao2_bump(current_state_stream->instance); + break; + case AST_MEDIA_TYPE_IMAGE: + joint_state_stream->udptl = ao2_bump(current_state_stream->udptl); + joint_state_stream->t38_local_params = current_state_stream->t38_local_params; + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; + } if (!ast_sockaddr_isnull(¤t_state_stream->connection_address)) { ast_sockaddr_copy(&joint_state_stream->connection_address, ¤t_state_stream->connection_address); @@ -572,11 +694,25 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ if (!joint_stream) { goto fail; } - if (new_stream_type == AST_MEDIA_TYPE_AUDIO || new_stream_type == AST_MEDIA_TYPE_VIDEO) { + + switch (new_stream_type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: joint_state_stream->instance = create_rtp(options, new_stream_type); if (!joint_state_stream->instance) { goto fail; } + break; + case AST_MEDIA_TYPE_IMAGE: + joint_state_stream->udptl = create_udptl(options); + if (!joint_state_stream->udptl) { + goto fail; + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; } ast_sockaddr_setnull(&joint_state_stream->connection_address); joint_state_stream->locally_held = 0; @@ -747,6 +883,63 @@ static void update_rtp_after_merge(const struct ast_sdp_state *state, struct ast } } +/*! + * \brief Update UDPTL instances based on merged SDPs + * + * UDPTL instances, when first allocated, cannot make assumptions about what the other + * side supports and thus has to go with some default behaviors. This function gets + * called after we know both what we support and what the remote endpoint supports. + * This way, we can update the UDPTL instance to reflect what is supported by both + * sides. + * + * \param state The SDP state in which SDPs have been negotiated + * \param udptl The UDPTL instance that is being updated + * \param options Our locally-supported SDP options + * \param remote_sdp The SDP we most recently received + * \param remote_m_line The remote SDP stream that corresponds to the RTP instance we are modifying + */ +static void update_udptl_after_merge(const struct ast_sdp_state *state, struct sdp_state_udptl *udptl, + const struct ast_sdp_options *options, + const struct ast_sdp *remote_sdp, + const struct ast_sdp_m_line *remote_m_line) +{ + struct ast_sdp_a_line *a_line; + struct ast_sdp_c_line *c_line; + unsigned int fax_max_datagram; + struct ast_sockaddr *addrs; + + a_line = ast_sdp_m_find_attribute(remote_m_line, "t38faxmaxdatagram", -1); + if (!a_line) { + a_line = ast_sdp_m_find_attribute(remote_m_line, "t38maxdatagram", -1); + } + if (a_line && !ast_sdp_options_get_udptl_far_max_datagram(options) && + (sscanf(a_line->value, "%30u", &fax_max_datagram) == 1)) { + ast_udptl_set_far_max_datagram(udptl->instance, fax_max_datagram); + } + + a_line = ast_sdp_m_find_attribute(remote_m_line, "t38faxudpec", -1); + if (a_line) { + if (!strcasecmp(a_line->value, "t38UDPRedundancy")) { + ast_udptl_set_error_correction_scheme(udptl->instance, UDPTL_ERROR_CORRECTION_REDUNDANCY); + } else if (!strcasecmp(a_line->value, "t38UDPFEC")) { + ast_udptl_set_error_correction_scheme(udptl->instance, UDPTL_ERROR_CORRECTION_FEC); + } else { + ast_udptl_set_error_correction_scheme(udptl->instance, UDPTL_ERROR_CORRECTION_NONE); + } + } + + c_line = remote_sdp->c_line; + if (remote_m_line->c_line) { + c_line = remote_m_line->c_line; + } + + if (ast_sockaddr_resolve(&addrs, c_line->address, PARSE_PORT_FORBID, AST_AF_UNSPEC) > 0) { + ast_sockaddr_set_port(addrs, remote_m_line->port); + ast_udptl_set_peer(udptl->instance, addrs); + ast_free(addrs); + } +} + static void set_negotiated_capabilities(struct ast_sdp_state *sdp_state, struct sdp_state_capabilities *new_capabilities) { @@ -811,14 +1004,23 @@ static int merge_sdps(struct ast_sdp_state *sdp_state, for (i = 0; i < AST_VECTOR_SIZE(&joint_capabilities->streams); ++i) { struct sdp_state_stream *state_stream; - enum ast_media_type stream_type; - - stream_type = ast_stream_get_type(ast_stream_topology_get_stream(joint_capabilities->topology, i)); state_stream = AST_VECTOR_GET(&joint_capabilities->streams, i); - if ((stream_type == AST_MEDIA_TYPE_AUDIO || stream_type == AST_MEDIA_TYPE_VIDEO) && state_stream->instance) { + + switch (ast_stream_get_type(ast_stream_topology_get_stream(joint_capabilities->topology, i))) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: update_rtp_after_merge(sdp_state, state_stream->instance, sdp_state->options, remote_sdp, ast_sdp_get_m(remote_sdp, i)); + break; + case AST_MEDIA_TYPE_IMAGE: + update_udptl_after_merge(sdp_state, state_stream->udptl, sdp_state->options, + remote_sdp, ast_sdp_get_m(remote_sdp, i)); + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; } } @@ -966,6 +1168,20 @@ unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_stat return stream_state->locally_held; } +void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state, + int stream_index, struct ast_control_t38_parameters *params) +{ + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL && params != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return; + } + + stream_state->t38_local_params = *params; +} + static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) { @@ -1104,6 +1320,167 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s return 0; } +/*! \brief Get Max T.38 Transmission rate from T38 capabilities */ +static unsigned int t38_get_rate(enum ast_control_t38_rate rate) +{ + switch (rate) { + case AST_T38_RATE_2400: + return 2400; + case AST_T38_RATE_4800: + return 4800; + case AST_T38_RATE_7200: + return 7200; + case AST_T38_RATE_9600: + return 9600; + case AST_T38_RATE_12000: + return 12000; + case AST_T38_RATE_14400: + return 14400; + default: + return 0; + } +} + +static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, + const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) +{ + struct ast_stream *stream; + struct ast_sdp_m_line *m_line; + struct ast_sdp_payload *payload; + char tmp[64]; + struct ast_sockaddr address_udptl; + struct sdp_state_udptl *udptl; + struct ast_sdp_a_line *a_line; + struct sdp_state_stream *stream_state; + + stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); + udptl = AST_VECTOR_GET(&capabilities->streams, stream_index)->udptl; + + ast_assert(sdp && options && stream); + + if (udptl) { + if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_udptl)) { + return -1; + } + } else { + ast_sockaddr_setnull(&address_udptl); + } + + m_line = ast_sdp_m_alloc( + ast_codec_media_type2str(ast_stream_get_type(stream)), + ast_sockaddr_port(&address_udptl), 1, "udptl", NULL); + if (!m_line) { + return -1; + } + + payload = ast_sdp_payload_alloc("t38"); + if (!payload || ast_sdp_m_add_payload(m_line, payload)) { + ast_sdp_payload_free(payload); + ast_sdp_m_free(m_line); + return -1; + } + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + + snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version); + a_line = ast_sdp_a_alloc("T38FaxVersion", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + + snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(stream_state->t38_local_params.rate)); + a_line = ast_sdp_a_alloc("T38FaxMaxBitRate", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + + if (stream_state->t38_local_params.fill_bit_removal) { + a_line = ast_sdp_a_alloc("T38FaxFillBitRemoval", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + + if (stream_state->t38_local_params.transcoding_mmr) { + a_line = ast_sdp_a_alloc("T38FaxTranscodingMMR", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + + if (stream_state->t38_local_params.transcoding_jbig) { + a_line = ast_sdp_a_alloc("T38FaxTranscodingJBIG", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } + + switch (stream_state->t38_local_params.rate_management) { + case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF: + a_line = ast_sdp_a_alloc("T38FaxRateManagement", "transferredTCF"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; + case AST_T38_RATE_MANAGEMENT_LOCAL_TCF: + a_line = ast_sdp_a_alloc("T38FaxRateManagement", "localTCF"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; + } + + snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(udptl->instance)); + a_line = ast_sdp_a_alloc("T38FaxMaxDatagram", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + + switch (ast_udptl_get_error_correction_scheme(udptl->instance)) { + case UDPTL_ERROR_CORRECTION_NONE: + break; + case UDPTL_ERROR_CORRECTION_FEC: + a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPFEC"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; + case UDPTL_ERROR_CORRECTION_REDUNDANCY: + a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPRedundancy"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; + } + + if (ast_sdp_add_m(sdp, m_line)) { + ast_sdp_m_free(m_line); + return -1; + } + + return 0; +} + /*! * \brief Create an SDP based on current SDP state * @@ -1155,12 +1532,22 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta stream_count = ast_stream_topology_get_count(topology); for (stream_num = 0; stream_num < stream_count; stream_num++) { - enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num)); - - if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + switch (ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num))) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: if (sdp_add_m_from_rtp_stream(sdp, sdp_state, options, capabilities, stream_num)) { goto error; } + break; + case AST_MEDIA_TYPE_IMAGE: + if (sdp_add_m_from_udptl_stream(sdp, sdp_state, options, capabilities, stream_num)) { + goto error; + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; } } diff --git a/tests/test_sdp.c b/tests/test_sdp.c index 38968aaaa85..33a6a2892ad 100644 --- a/tests/test_sdp.c +++ b/tests/test_sdp.c @@ -130,6 +130,22 @@ static int validate_rtpmap(struct ast_test *test, const struct ast_sdp_m_line *m return -1; } +static enum ast_test_result_state validate_t38(struct ast_test *test, const struct ast_sdp_m_line *m_line) +{ + struct ast_sdp_a_line *a_line; + + a_line = ast_sdp_m_find_attribute(m_line, "T38FaxVersion", -1); + ast_test_validate(test, a_line && !strcmp(a_line->value, "0")); + + a_line = ast_sdp_m_find_attribute(m_line, "T38FaxMaxBitRate", -1); + ast_test_validate(test, a_line && !strcmp(a_line->value, "14400")); + + a_line = ast_sdp_m_find_attribute(m_line, "T38FaxRateManagement", -1); + ast_test_validate(test, a_line && !strcmp(a_line->value, "transferredTCF")); + + return AST_TEST_PASS; +} + AST_TEST_DEFINE(invalid_rtpmap) { /* a=rtpmap: is already assumed. This is the part after that */ @@ -405,6 +421,7 @@ AST_TEST_DEFINE(topology_to_sdp) struct sdp_format formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, }; switch(cmd) { @@ -437,7 +454,7 @@ AST_TEST_DEFINE(topology_to_sdp) goto end; } - if (ast_sdp_get_m_count(sdp) != 2) { + if (ast_sdp_get_m_count(sdp) != 3) { ast_test_status_update(test, "Unexpected number of streams in generated SDP: %d\n", ast_sdp_get_m_count(sdp)); goto end; @@ -478,6 +495,14 @@ AST_TEST_DEFINE(topology_to_sdp) goto end; } + m_line = ast_sdp_get_m(sdp, 2); + if (validate_m_line(test, m_line, "image", 1)) { + goto end; + } + if (validate_t38(test, m_line) != AST_TEST_PASS) { + goto end; + } + res = AST_TEST_PASS; end: @@ -527,6 +552,7 @@ AST_TEST_DEFINE(sdp_to_topology) struct sdp_format sdp_formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, }; static const char *expected_audio_formats[] = { "ulaw", @@ -538,6 +564,9 @@ AST_TEST_DEFINE(sdp_to_topology) "h264", "vp8", }; + static const char *expected_image_formats[] = { + "t38", + }; switch(cmd) { case TEST_INIT: @@ -565,7 +594,7 @@ AST_TEST_DEFINE(sdp_to_topology) topology = ast_get_topology_from_sdp(sdp); - if (ast_stream_topology_get_count(topology) != 2) { + if (ast_stream_topology_get_count(topology) != 3) { ast_test_status_update(test, "Unexpected topology count '%d'. Expecting 2\n", ast_stream_topology_get_count(topology)); res = AST_TEST_FAIL; @@ -584,6 +613,12 @@ AST_TEST_DEFINE(sdp_to_topology) goto end; } + if (validate_formats(test, topology, 2, AST_MEDIA_TYPE_IMAGE, + ARRAY_LEN(expected_image_formats), expected_image_formats)) { + res = AST_TEST_FAIL; + goto end; + } + end: ast_sdp_state_free(sdp_state); ast_stream_topology_free(topology); From 199d4776c03858598c6253bc75029683a73283f6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 25 Apr 2017 12:52:48 +0000 Subject: [PATCH 1218/1578] alembic: Add table for 'resource_list' PJSIP RLS type. This change adds an Alembic migration which adds a ps_resource_list table that can contain resource_list RLS configuration objects. ASTERISK-26929 Change-Id: I7c888fafc67b3e87012de974f71ca7a5b8b1ec05 --- .../versions/1d0e332c32af_create_rls_table.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/1d0e332c32af_create_rls_table.py diff --git a/contrib/ast-db-manage/config/versions/1d0e332c32af_create_rls_table.py b/contrib/ast-db-manage/config/versions/1d0e332c32af_create_rls_table.py new file mode 100644 index 00000000000..3557f0d5265 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/1d0e332c32af_create_rls_table.py @@ -0,0 +1,39 @@ +"""create rls table + +Revision ID: 1d0e332c32af +Revises: 2da192dbbc65 +Create Date: 2017-04-25 12:50:09.412662 + +""" + +# revision identifiers, used by Alembic. +revision = '1d0e332c32af' +down_revision = '2da192dbbc65' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.create_table( + 'ps_resource_list', + sa.Column('id', sa.String(40), nullable=False, unique=True), + sa.Column('list_item', sa.String(2048)), + sa.Column('event', sa.String(40)), + sa.Column('full_state', yesno_values), + sa.Column('notification_batch_interval', sa.Integer), + ) + + op.create_index('ps_resource_list_id', 'ps_resource_list', ['id']) + +def downgrade(): + op.drop_table('ps_resource_list') From f5b67871df566ddc0f0b6ad22d81a81d8ecce7d7 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 21 Apr 2017 13:04:44 -0400 Subject: [PATCH 1219/1578] cleanup: Fix fread() and fwrite() error handling Cleaned up some of the incorrect uses of fread() and fwrite(), mostly in the format modules. Neither of these functions will ever return a value less than 0, which we were checking for in some cases. I've introduced a fair amount of duplication in the format modules, but I plan to change how format modules work internally in a subsequent patch set, so this is simply a stop-gap. Change-Id: I8ca1cd47c20b2c0b72088bd13b9046f6977aa872 --- addons/format_mp3.c | 8 +++++--- apps/app_minivm.c | 14 +++++++------- apps/app_voicemail.c | 14 +++++++------- formats/format_g719.c | 12 ++++++++++-- formats/format_g723.c | 13 +++++++++++-- formats/format_g726.c | 12 ++++++++++-- formats/format_g729.c | 12 ++++++++++-- formats/format_gsm.c | 16 ++++++++++++---- formats/format_h263.c | 16 ++++++++++++---- formats/format_h264.c | 16 ++++++++++++---- formats/format_ilbc.c | 12 ++++++++++-- formats/format_ogg_vorbis.c | 10 +++++----- formats/format_pcm.c | 24 ++++++++++++++++++------ formats/format_siren14.c | 12 ++++++++++-- formats/format_siren7.c | 12 ++++++++++-- formats/format_sln.c | 14 +++++++++++--- formats/format_vox.c | 14 +++++++++++--- formats/format_wav.c | 23 ++++++++++++++++------- formats/format_wav_gsm.c | 14 +++++++++++--- 19 files changed, 198 insertions(+), 70 deletions(-) diff --git a/addons/format_mp3.c b/addons/format_mp3.c index e0f57b86b4f..bb0b20850da 100644 --- a/addons/format_mp3.c +++ b/addons/format_mp3.c @@ -118,9 +118,11 @@ static int mp3_squeue(struct ast_filestream *s) res = ftell(s->f); p->sbuflen = fread(p->sbuf, 1, MP3_SCACHE, s->f); - if(p->sbuflen < 0) { - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", p->sbuflen, strerror(errno)); - return -1; + if (p->sbuflen < MP3_SCACHE) { + if (ferror(s->f)) { + ast_log(LOG_WARNING, "Error while reading MP3 file: %s\n", strerror(errno)); + return -1; + } } res = decodeMP3(&p->mp,p->sbuf,p->sbuflen,p->dbuf,MP3_DCACHE,&p->dbuflen); if(res != MP3_OK) diff --git a/apps/app_minivm.c b/apps/app_minivm.c index 4cc2f47965c..ff9ab340a63 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -854,16 +854,16 @@ static int b64_inbuf(struct b64_baseio *bio, FILE *fi) if (bio->ateof) return 0; - if ((l = fread(bio->iobuf, 1, B64_BASEMAXINLINE,fi)) <= 0) { - if (ferror(fi)) - return -1; - + if ((l = fread(bio->iobuf, 1, B64_BASEMAXINLINE, fi)) != B64_BASEMAXINLINE) { bio->ateof = 1; - return 0; + if (l == 0) { + /* Assume EOF */ + return 0; + } } - bio->iolen= l; - bio->iocp= 0; + bio->iolen = l; + bio->iocp = 0; return 1; } diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index de826704a76..06f4830faec 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -2728,9 +2728,9 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char *(vmu->email) = '\0'; return -1; } - if (fread(buf, len, 1, p) < len) { + if (fread(buf, 1, len, p) != len) { if (ferror(p)) { - ast_log(LOG_ERROR, "Short read while reading in mail file.\n"); + ast_log(LOG_ERROR, "Error while reading mail file: %s\n"); return -1; } } @@ -4743,12 +4743,12 @@ static int inbuf(struct baseio *bio, FILE *fi) if (bio->ateof) return 0; - if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) { - if (ferror(fi)) - return -1; - + if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) != BASEMAXINLINE) { bio->ateof = 1; - return 0; + if (l == 0) { + /* Assume EOF */ + return 0; + } } bio->iolen = l; diff --git a/formats/format_g719.c b/formats/format_g719.c index 8cc942717a8..572b88f5f7c 100644 --- a/formats/format_g719.c +++ b/formats/format_g719.c @@ -45,8 +45,16 @@ static struct ast_frame *g719read(struct ast_filestream *s, int *whennext) AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = BYTES_TO_SAMPLES(res); diff --git a/formats/format_g723.c b/formats/format_g723.c index 04e03b6086f..d4c4d4b1c9e 100644 --- a/formats/format_g723.c +++ b/formats/format_g723.c @@ -64,8 +64,17 @@ static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext) } /* Read the data into the buffer */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, size); - if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != size) { - ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno)); + if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = 240; diff --git a/formats/format_g726.c b/formats/format_g726.c index 08e669e264f..7da6d1ecbb3 100644 --- a/formats/format_g726.c +++ b/formats/format_g726.c @@ -124,8 +124,16 @@ static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext) AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]); s->fr.samples = 8 * FRAME_TIME; if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples; diff --git a/formats/format_g729.c b/formats/format_g729.c index 49e58025f88..4cefc0401c3 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -51,8 +51,16 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext) s->fr.samples = G729A_SAMPLES; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res && (res != 10)) /* XXX what for ? */ - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples; diff --git a/formats/format_gsm.c b/formats/format_gsm.c index a2b6d365616..39deb983e37 100644 --- a/formats/format_gsm.c +++ b/formats/format_gsm.c @@ -55,10 +55,18 @@ static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext) { int res; - AST_FRAME_SET_BUFFER(&(s->fr), s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE) + AST_FRAME_SET_BUFFER(&(s->fr), s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE); if ((res = fread(s->fr.data.ptr, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), GSM_FRAME_SIZE, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = GSM_SAMPLES; @@ -131,7 +139,7 @@ static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence) int i; fseeko(fs->f, 0, SEEK_END); for (i=0; i< (offset - max) / GSM_FRAME_SIZE; i++) { - if (!fwrite(gsm_silence, 1, GSM_FRAME_SIZE, fs->f)) { + if (fwrite(gsm_silence, 1, GSM_FRAME_SIZE, fs->f) != GSM_FRAME_SIZE) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } } diff --git a/formats/format_h263.c b/formats/format_h263.c index 4cc3db54272..d05e598254a 100644 --- a/formats/format_h263.c +++ b/formats/format_h263.c @@ -58,7 +58,7 @@ static int h263_open(struct ast_filestream *s) { unsigned int ts; - if (fread(&ts, 1, sizeof(ts), s->f) < sizeof(ts)) { + if (fread(&ts, 1, sizeof(ts), s->f) != sizeof(ts)) { ast_log(LOG_WARNING, "Empty file!\n"); return -1; } @@ -74,7 +74,7 @@ static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext) struct h263_desc *fs = (struct h263_desc *)s->_private; /* Send a frame from the file to the appropriate channel */ - if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) + if ((res = fread(&len, 1, sizeof(len), s->f)) != sizeof(len)) return NULL; len = ntohs(len); mark = (len & FRAME_ENDED) ? 1 : 0; @@ -85,8 +85,16 @@ static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext) } AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } s->fr.samples = fs->lastts; /* XXX what ? */ diff --git a/formats/format_h264.c b/formats/format_h264.c index 60b0902111c..47f71ae6cc2 100644 --- a/formats/format_h264.c +++ b/formats/format_h264.c @@ -50,7 +50,7 @@ struct h264_desc { static int h264_open(struct ast_filestream *s) { unsigned int ts; - if (fread(&ts, 1, sizeof(ts), s->f) < sizeof(ts)) { + if (fread(&ts, 1, sizeof(ts), s->f) != sizeof(ts)) { ast_log(LOG_WARNING, "Empty file!\n"); return -1; } @@ -66,7 +66,7 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext) struct h264_desc *fs = (struct h264_desc *)s->_private; /* Send a frame from the file to the appropriate channel */ - if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) + if ((res = fread(&len, 1, sizeof(len), s->f)) != sizeof(len)) return NULL; len = ntohs(len); mark = (len & FRAME_ENDED) ? 1 : 0; @@ -77,8 +77,16 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext) } AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res) - ast_log(LOG_WARNING, "Short read (%d of %d) (%s)!\n", res, len, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } s->fr.samples = fs->lastts; diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c index eab465d8871..ec8ad0ffa6f 100644 --- a/formats/format_ilbc.c +++ b/formats/format_ilbc.c @@ -49,8 +49,16 @@ static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext) /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, ILBC_BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = ILBC_SAMPLES; diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c index c0f8c197dfe..4fdd1c41174 100644 --- a/formats/format_ogg_vorbis.c +++ b/formats/format_ogg_vorbis.c @@ -181,10 +181,10 @@ static int ogg_vorbis_rewrite(struct ast_filestream *s, while (!tmp->eos) { if (ogg_stream_flush(&tmp->os, &tmp->og) == 0) break; - if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) { + if (fwrite(tmp->og.header, 1, tmp->og.header_len, s->f) != tmp->og.header_len) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } - if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) { + if (fwrite(tmp->og.body, 1, tmp->og.body_len, s->f) != tmp->og.body_len) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (ogg_page_eos(&tmp->og)) @@ -211,10 +211,10 @@ static void write_stream(struct ogg_vorbis_desc *s, FILE *f) if (ogg_stream_pageout(&s->os, &s->og) == 0) { break; } - if (!fwrite(s->og.header, 1, s->og.header_len, f)) { - ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); + if (fwrite(s->og.header, 1, s->og.header_len, f) != s->og.header_len) { + ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } - if (!fwrite(s->og.body, 1, s->og.body_len, f)) { + if (fwrite(s->og.body, 1, s->og.body_len, f) != s->og.body_len) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (ogg_page_eos(&s->og)) { diff --git a/formats/format_pcm.c b/formats/format_pcm.c index 97af0e9a3a1..f5ddda9c61a 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -83,9 +83,17 @@ static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext) /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); - if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } s->fr.datalen = res; @@ -140,9 +148,10 @@ static int pcm_seek(struct ast_filestream *fs, off_t sample_offset, int whence) const char *src = (ast_format_cmp(fs->fmt->format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ? alaw_silence : ulaw_silence; while (left) { - size_t written = fwrite(src, 1, (left > BUF_SIZE) ? BUF_SIZE : left, fs->f); - if (written == -1) + size_t written = fwrite(src, 1, MIN(left, BUF_SIZE), fs->f); + if (written < MIN(left, BUF_SIZE)) { break; /* error */ + } left -= written; } ret = 0; /* successful */ @@ -210,7 +219,10 @@ static int pcm_write(struct ast_filestream *fs, struct ast_frame *f) to_write = fpos - cur; if (to_write > sizeof(buf)) to_write = sizeof(buf); - fwrite(buf, 1, to_write, fs->f); + if (fwrite(buf, 1, to_write, fs->f) != to_write) { + ast_log(LOG_ERROR, "Failed to write to file: %s\n", strerror(errno)); + return -1; + } cur += to_write; } } diff --git a/formats/format_siren14.c b/formats/format_siren14.c index 1ce7d18ad29..d54ed993bc3 100644 --- a/formats/format_siren14.c +++ b/formats/format_siren14.c @@ -45,8 +45,16 @@ static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext) AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = BYTES_TO_SAMPLES(res); diff --git a/formats/format_siren7.c b/formats/format_siren7.c index d2059844571..f3b4b42b3c1 100644 --- a/formats/format_siren7.c +++ b/formats/format_siren7.c @@ -45,8 +45,16 @@ static struct ast_frame *siren7read(struct ast_filestream *s, int *whennext) AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = BYTES_TO_SAMPLES(res); diff --git a/formats/format_sln.c b/formats/format_sln.c index af3f691c81c..1977f7dc06d 100644 --- a/formats/format_sln.c +++ b/formats/format_sln.c @@ -38,9 +38,17 @@ static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, u /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, buf_size); - if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = res/2; diff --git a/formats/format_vox.c b/formats/format_vox.c index 5a70c34b140..195714c6f00 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -44,9 +44,17 @@ static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext) /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); - if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } *whennext = s->fr.samples = res * 2; diff --git a/formats/format_wav.c b/formats/format_wav.c index 8316c353027..09e6a5313fd 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -361,7 +361,7 @@ static void wav_close(struct ast_filestream *s) /* Pad to even length */ if (fs->bytes & 0x1) { - if (!fwrite(&zero, 1, 1, s->f)) { + if (fwrite(&zero, 1, 1, s->f) != 1) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } } @@ -385,14 +385,23 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext) here = ftello(s->f); if (fs->maxlen - here < bytes) /* truncate if necessary */ bytes = fs->maxlen - here; - if (bytes < 0) - bytes = 0; + if (bytes <= 0) { + return NULL; + } /* ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes); - - if ( (res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) <= 0 ) { - if (res) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + + if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } s->fr.datalen = res; diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c index eef06cef5b7..bfec903d077 100644 --- a/formats/format_wav_gsm.c +++ b/formats/format_wav_gsm.c @@ -422,8 +422,16 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext) int res; if ((res = fread(msdata, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) { - if (res && (res != 1)) - ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); + if (feof(s->f)) { + if (res) { + ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), MSGSM_FRAME_SIZE, res); + } + } else { + ast_log(LOG_ERROR, "Error while reading %s file: %s\n", + ast_format_get_name(s->fr.subclass.format), strerror(errno)); + } return NULL; } /* Convert from MS format to two real GSM frames */ @@ -511,7 +519,7 @@ static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence) int i; fseek(fs->f, 0, SEEK_END); for (i=0; i< (offset - max) / MSGSM_FRAME_SIZE; i++) { - if (!fwrite(msgsm_silence, 1, MSGSM_FRAME_SIZE, fs->f)) { + if (fwrite(msgsm_silence, 1, MSGSM_FRAME_SIZE, fs->f) != MSGSM_FRAME_SIZE) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } } From 585f9405b11da980d7ffb2f71b90ccd4d5842383 Mon Sep 17 00:00:00 2001 From: Thierry Magnien Date: Wed, 26 Apr 2017 14:58:44 +0200 Subject: [PATCH 1220/1578] channels/chan_sip.c: use binding IP address for outgoing TCP SIP connections For outgoing TCP connections, Asterisk uses the first IP address of the interface instead of the IP address we asked him to bind to. ASTERISK-26922 #close Reported-by: Ksenia Change-Id: I43c71ca89211dbf1838e5bcdb9be8d06d98e54eb --- channels/chan_sip.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index affe937e803..d60927d7a31 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -29275,6 +29275,17 @@ static int sip_prepare_socket(struct sip_pvt *p) } } + /* If a bind address has been specified, use it */ + if ((s->type == AST_TRANSPORT_TLS) && !ast_sockaddr_isnull(&sip_tls_desc.local_address)) { + ca->local_address = sip_tls_desc.local_address; + } + else if ((s->type == AST_TRANSPORT_TCP) && !ast_sockaddr_isnull(&sip_tcp_desc.local_address)) { + ca->local_address = sip_tcp_desc.local_address; + } + /* Reset tcp source port to zero to let system pick a random one */ + if (!ast_sockaddr_isnull(&ca->local_address)) { + ast_sockaddr_set_port(&ca->local_address, 0); + } /* Create a client connection for address, this does not start the connection, just sets it up. */ if (!(s->tcptls_session = ast_tcptls_client_create(ca))) { goto create_tcptls_session_fail; From 858ed604462746713085752dd0b8ccab3be1a842 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 26 Apr 2017 07:45:31 -0600 Subject: [PATCH 1221/1578] pjproject_bundled: Add --disable-libwebrtc to configure Without the disable, pjproject tries to build it's internal webrtc implementation which requires sse2. This fails on platforms without sse2. ASTERISK-26930 #close Reported-by: abelbeck Change-Id: I07231f9160c35cfa42b194d3aad4e7d51fd9a410 --- third-party/pjproject/Makefile.rules | 1 + 1 file changed, 1 insertion(+) diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index e8eb46643e4..c0be1cbdf84 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -24,6 +24,7 @@ PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ --disable-ffmpeg \ --disable-openh264 \ --disable-ipp \ + --disable-libwebrtc \ --without-external-pa \ --without-external-srtp \ --without-external-webrtc From 99dea9ba844097ad3ca275a8ef7bfb392826e03c Mon Sep 17 00:00:00 2001 From: Yasin CANER Date: Wed, 26 Apr 2017 17:22:41 +0300 Subject: [PATCH 1222/1578] res_pjsip_session : fixed wrong From Header number On Re-invite ASTERISK-26964 #close Change-Id: I55a9caa7dc90e6c4c219cb09b5c2ec08af84a302 --- res/res_pjsip_session.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 3034652a5a4..a8292db144c 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -946,11 +946,6 @@ int ast_sip_session_refresh(struct ast_sip_session *session, } } - /* - * We MUST call set_from_header() before pjsip_inv_(reinvite|update). If we don't, the - * From in the reINVITE/UPDATE will be wrong but the rest of the messages will be OK. - */ - set_from_header(session); if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) { if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) { From 985a5fd7aac7a39cf9f9502f9e8e06ef216e1d35 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 26 Apr 2017 10:38:31 +0000 Subject: [PATCH 1223/1578] frame: Better handle interpolated frames. Interpolated frames are frames which contain a number of samples but have no actual data. Audiohooks did not handle this case when translating an incoming frame into signed linear. It assumed that a frame would always contain media when it may not. If this occurs audiohooks will now immediately return and not act on the frame. As well for users of ast_trans_frameout the function has been changed to be a bit more sane and ensure that the data pointer on a frame is set to NULL if no data is actually on the frame. This allows the various spots in Asterisk that check for an interpolated frame based on the presence of a data pointer to work as expected. ASTERISK-26926 Change-Id: I7fa22f631fa28d540722ed789ce28e84c7f8662b --- main/audiohook.c | 9 +++++++++ main/translate.c | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/main/audiohook.c b/main/audiohook.c index 986f11f846f..2cba2de6e28 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -945,6 +945,15 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st if (!(middle_frame = audiohook_list_translate_to_slin(audiohook_list, direction, start_frame))) { return frame; } + + /* If the translation resulted in an interpolated frame then immediately return as audiohooks + * rely on actual media being present to do things. + */ + if (!middle_frame->data.ptr) { + ast_frfree(middle_frame); + return start_frame; + } + samples = middle_frame->samples; /* diff --git a/main/translate.c b/main/translate.c index 168a72a4bd5..f2aa5886b2d 100644 --- a/main/translate.c +++ b/main/translate.c @@ -442,8 +442,14 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt, } if (datalen) { f->datalen = datalen; + f->data.ptr = pvt->outbuf.c; } else { f->datalen = pvt->datalen; + if (!f->datalen) { + f->data.ptr = NULL; + } else { + f->data.ptr = pvt->outbuf.c; + } pvt->datalen = 0; } From cf3429b93444293d131cd0c90df285e7644907d9 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 25 Apr 2017 11:43:26 -0500 Subject: [PATCH 1224/1578] vector: defaults and indexes Added an pre-defined integer vector declaration. This makes integer vectors easier to declare and pass around. Also, added the ability to default a vector up to a given size with a default value. Lastly, added functionality that returns the "nth" index of a matching value. Also, updated a unit test to test these changes. Change-Id: Iaf4b51b2540eda57cb43f67aa59cf1d96cdbcaa5 --- include/asterisk/vector.h | 62 +++++++++++++++++++++++++++++++++++++++ tests/test_vector.c | 19 ++++++++++++ 2 files changed, 81 insertions(+) diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index 83732e7c8ea..2de84d295ab 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -48,6 +48,9 @@ size_t current; \ } +/*! \brief Integer vector definition */ +AST_VECTOR(ast_vector_int, int); + /*! * \brief Define a vector structure with a read/write lock * @@ -240,6 +243,29 @@ res; \ }) +/*! + * \brief Default a vector up to size with the given value. + * + * \note If a size of 0 is given then all elements in the given vector are set. + * \note The vector will grow to the given size if needed. + * + * \param vec Vector to default. + * \param size The number of elements to default + * \param value The default value to set each element to + */ +#define AST_VECTOR_DEFAULT(vec, size, value) ({ \ + int res = 0; \ + typeof((size)) __size = (size) ? (size) : AST_VECTOR_SIZE(vec); \ + size_t idx; \ + for (idx = 0; idx < __size; ++idx) { \ + res = AST_VECTOR_REPLACE(vec, idx, value); \ + if (res == -1) { \ + break; \ + } \ + } \ + res; \ +}) + /*! * \brief Insert an element at a specific position in a vector, growing the vector if needed. * @@ -552,6 +578,42 @@ (vec)->elems[__idx]; \ }) +/*! + * \brief Get the nth index from a vector that matches the given comparison + * + * \param vec Vector to get from. + * \param nth The nth index to find + * \param value Value to pass into comparator. + * \param cmp Comparator function/macros (called as \c cmp(elem, value)) + * + * \return a pointer to the element that was found or NULL + */ +#define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp) ({ \ + int res = -1; \ + size_t idx; \ + typeof(nth) __nth = (nth); \ + typeof(value) __value = (value); \ + for (idx = 0; idx < (vec)->current; ++idx) { \ + if (cmp((vec)->elems[idx], __value) && !(--__nth)) { \ + res = (int)idx; \ + break; \ + } \ + } \ + res; \ +}) + +/*! + * \brief Get the 1st index from a vector that matches the given comparison + * + * \param vec Vector to get from. + * \param value Value to pass into comparator. + * \param cmp Comparator function/macros (called as \c cmp(elem, value)) + * + * \return a pointer to the element that was found or NULL + */ +#define AST_VECTOR_GET_INDEX(vec, value, cmp) \ + AST_VECTOR_GET_INDEX_NTH(vec, 1, value, cmp) + /*! * \brief Get an element from a vector that matches the given comparison * diff --git a/tests/test_vector.c b/tests/test_vector.c index 8ca4efa1abf..8e0d121ddf2 100644 --- a/tests/test_vector.c +++ b/tests/test_vector.c @@ -282,6 +282,25 @@ AST_TEST_DEFINE(basic_ops_integer) ast_test_validate_cleanup(test, *(int *)AST_VECTOR_GET_CMP(&sv1, AAA, AST_VECTOR_ELEM_DEFAULT_CMP) == AAA, rc, cleanup); ast_test_validate_cleanup(test, *(int *)AST_VECTOR_GET_CMP(&sv1, ZZZ, AST_VECTOR_ELEM_DEFAULT_CMP) == ZZZ, rc, cleanup); + /* Default first value */ + ast_test_validate_cleanup(test, AST_VECTOR_DEFAULT(&sv1, 1, CCC) == 0, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 0) == CCC, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 1) == ZZZ, rc, cleanup); + /* Default all values */ + ast_test_validate_cleanup(test, AST_VECTOR_DEFAULT(&sv1, 0, AAA) == 0, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 0) == AAA, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 1) == AAA, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 2) == AAA, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 3) == AAA, rc, cleanup); + /* Default more values than are currently in the vector */ + ast_test_validate_cleanup(test, AST_VECTOR_DEFAULT(&sv1, 5, BBB) == 0, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 4) == BBB, rc, cleanup); + + /* Check getting index(es) */ + ast_test_validate_cleanup(test, AST_VECTOR_GET_INDEX(&sv1, BBB, AST_VECTOR_ELEM_DEFAULT_CMP) == 0, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET_INDEX_NTH(&sv1, 2, BBB, AST_VECTOR_ELEM_DEFAULT_CMP) == 1, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_GET_INDEX_NTH(&sv1, 4, BBB, AST_VECTOR_ELEM_DEFAULT_CMP) == 3, rc, cleanup); + AST_VECTOR_FREE(&sv1); ast_test_validate(test, sv1.elems == NULL); ast_test_validate(test, sv1.current == 0); From c6b757fa05c4c3fe1b7fa77844b9e5e3203d859f Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Wed, 26 Apr 2017 14:20:00 -0500 Subject: [PATCH 1225/1578] res_pjsip/res_pjsip_callerid: NULL check on caller id name string It's possible for a name in a party id structure to be marked as valid, but the name string itself be NULL (for instance this is possible to do by using the dialplan CALLERID function). There were a couple of places where the name was validated, but the string itself was not checked before passing it to functions like 'strlen'. This of course caused a crashed. This patch adds in a NULL check before attempting to pass it into a function that is not NULL tolerant. ASTERISK-25823 #close Change-Id: Iaa6ffe9d92f598fe9e3c8ae373fadbe3dfbf1d4a --- res/res_pjsip.c | 12 ++++++++---- res/res_pjsip_caller_id.c | 9 +++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index e4bcb703826..9de2176a658 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4420,11 +4420,15 @@ void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const s id_uri = pjsip_uri_get_uri(id_name_addr->uri); if (id->name.valid) { - int name_buf_len = strlen(id->name.str) * 2 + 1; - char *name_buf = ast_alloca(name_buf_len); + if (!ast_strlen_zero(id->name.str)) { + int name_buf_len = strlen(id->name.str) * 2 + 1; + char *name_buf = ast_alloca(name_buf_len); - ast_escape_quoted(id->name.str, name_buf, name_buf_len); - pj_strdup2(pool, &id_name_addr->display, name_buf); + ast_escape_quoted(id->name.str, name_buf, name_buf_len); + pj_strdup2(pool, &id_name_addr->display, name_buf); + } else { + pj_strdup2(pool, &id_name_addr->display, NULL); + } } if (id->number.valid) { diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 7948d33bea2..470d90f43ee 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -436,7 +436,7 @@ static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_fromt id_name_addr = pjsip_uri_clone(tdata->pool, base->uri); id_uri = pjsip_uri_get_uri(id_name_addr->uri); - if (id->name.valid) { + if (id->name.valid && !ast_strlen_zero(id->name.str)) { int name_buf_len = strlen(id->name.str) * 2 + 1; char *name_buf = ast_alloca(name_buf_len); @@ -450,7 +450,12 @@ static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_fromt pj_strdup2(tdata->pool, &id_name_addr->display, NULL); } - pj_strdup2(tdata->pool, &id_uri->user, id->number.str); + if (id->number.valid) { + pj_strdup2(tdata->pool, &id_uri->user, id->number.str); + } else { + /* Similar to name, make sure the number is also cleared when invalid */ + pj_strdup2(tdata->pool, &id_uri->user, NULL); + } id_hdr->uri = (pjsip_uri *) id_name_addr; return id_hdr; From 2b22c3c84b8894c5663fec8655b0670b6bca4078 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 24 Apr 2017 15:59:44 +0000 Subject: [PATCH 1226/1578] channel: Add ability to request an outgoing channel with stream topology. This change extends the ast_request functionality by adding another function and callback to create an outgoing channel with a requested stream topology. Fallback is provided by either converting the requested stream topology into a format capabilities structure if the channel driver does not support streams or by converting the requested format capabilities into a stream topology if the channel driver does support streams. The Dial application has also been updated to request an outgoing channel with the stream topology of the calling channel. ASTERISK-26959 Change-Id: Ifa9037a672ac21d42dd7125aa09816dc879a70e6 --- apps/app_dial.c | 17 +++--- include/asterisk/channel.h | 41 ++++++++++++++ include/asterisk/stream.h | 16 ++++++ main/channel.c | 106 +++++++++++++++++++++++++------------ main/stream.c | 26 +++++++++ tests/test_stream.c | 59 +++++++++++++++++++++ 6 files changed, 224 insertions(+), 41 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index c8fcf4696ff..79e2a9b0bb7 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -66,6 +66,7 @@ #include "asterisk/bridge_after.h" #include "asterisk/features_config.h" #include "asterisk/max_forwards.h" +#include "asterisk/stream.h" /*** DOCUMENTATION @@ -970,16 +971,16 @@ static void do_forward(struct chanlist *o, struct cause_args *num, c = o->chan = NULL; cause = AST_CAUSE_BUSY; } else { - struct ast_format_cap *nativeformats; + struct ast_stream_topology *topology; ast_channel_lock(in); - nativeformats = ao2_bump(ast_channel_nativeformats(in)); + topology = ast_stream_topology_clone(ast_channel_get_stream_topology(in)); ast_channel_unlock(in); /* Setup parameters */ - c = o->chan = ast_request(tech, nativeformats, NULL, in, stuff, &cause); + c = o->chan = ast_request_with_stream_topology(tech, topology, NULL, in, stuff, &cause); - ao2_cleanup(nativeformats); + ast_stream_topology_free(topology); if (c) { if (single && !caller_entertained) { @@ -2444,7 +2445,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast char *tech = strsep(&number, "/"); size_t tech_len; size_t number_len; - struct ast_format_cap *nativeformats; + struct ast_stream_topology *topology; num_dialed++; if (ast_strlen_zero(number)) { @@ -2496,13 +2497,13 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast */ ast_party_connected_line_copy(&tmp->connected, ast_channel_connected(chan)); - nativeformats = ao2_bump(ast_channel_nativeformats(chan)); + topology = ast_stream_topology_clone(ast_channel_get_stream_topology(chan)); ast_channel_unlock(chan); - tc = ast_request(tmp->tech, nativeformats, NULL, chan, tmp->number, &cause); + tc = ast_request_with_stream_topology(tmp->tech, topology, NULL, chan, tmp->number, &cause); - ao2_cleanup(nativeformats); + ast_stream_topology_free(topology); if (!tc) { /* If we can't, just go on to the next call */ diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 32c9c7f67f2..70856a96fc0 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -203,6 +203,8 @@ enum ast_bridge_result { typedef unsigned long long ast_group_t; +struct ast_stream_topology; + /*! \todo Add an explanation of an Asterisk generator */ struct ast_generator { @@ -630,6 +632,26 @@ struct ast_channel_tech { */ struct ast_channel *(* const requester)(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause); + /*! + * \brief Requester - to set up call data structures (pvt's) with stream topology + * + * \param type type of channel to request + * \param topology Stream topology for requested channel + * \param assignedid Unique ID string to assign to channel + * \param requestor channel asking for data + * \param addr destination of the call + * \param cause Cause of failure + * + * \details + * Request a channel of a given type, with addr as optional information used + * by the low level module + * + * \retval NULL failure + * \retval non-NULL channel on success + */ + struct ast_channel *(* const requester_with_stream_topology)(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause); + + int (* const devicestate)(const char *device_number); /*!< Devicestate call back */ int (* const presencestate)(const char *presence_provider, char **subtype, char **message); /*!< Presencestate callback */ @@ -1393,6 +1415,25 @@ struct ast_channel *ast_channel_release(struct ast_channel *chan); */ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause); +/*! + * \brief Requests a channel (specifying stream topology) + * + * \param type type of channel to request + * \param topology Stream topology for requested channel + * \param assignedids Unique ID to create channel with + * \param requestor channel asking for data + * \param addr destination of the call + * \param cause Cause of failure + * + * \details + * Request a channel of a given type, with addr as optional information used + * by the low level module + * + * \retval NULL failure + * \retval non-NULL channel on success + */ +struct ast_channel *ast_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause); + enum ast_channel_requestor_relationship { /*! The requestor is the future bridge peer of the channel. */ AST_CHANNEL_REQUESTOR_BRIDGE_PEER, diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 1becae25a4f..924bfb65cdf 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -374,6 +374,22 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_format_cap *cap); +/*! + * \brief A helper function that, given a stream topology, creates a format + * capabilities structure containing all formats from all streams. + * + * \param topology The topology of streams + * + * \retval non-NULL success + * \retval NULL failure + * + * \note The stream topology is NOT altered by this function. + * + * \since 15 + */ +struct ast_format_cap *ast_format_cap_from_stream_topology( + struct ast_stream_topology *topology); + /*! * \brief Gets the first stream of a specific type from the topology * diff --git a/main/channel.c b/main/channel.c index 31f363938f1..e37d6652557 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5976,7 +5976,8 @@ static int set_security_requirements(const struct ast_channel *requestor, struct return 0; } -struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause) +static struct ast_channel *request_channel(const char *type, struct ast_format_cap *request_cap, struct ast_stream_topology *topology, + const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause) { struct chanlist *chan; struct ast_channel *c; @@ -5993,13 +5994,47 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request } AST_RWLIST_TRAVERSE(&backends, chan, list) { + if (strcasecmp(type, chan->tech->type)) { + continue; + } + + break; + } + + AST_RWLIST_UNLOCK(&backends); + + if (!chan) { + ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type); + *cause = AST_CAUSE_NOSUCHDRIVER; + return NULL; + } + + /* Allow either format capabilities or stream topology to be provided and adapt */ + if (chan->tech->requester_with_stream_topology) { + struct ast_stream_topology *tmp_converted_topology = NULL; + + if (!topology && request_cap) { + /* Turn the requested capabilities into a stream topology */ + topology = tmp_converted_topology = ast_stream_topology_create_from_format_cap(request_cap); + } + + c = chan->tech->requester_with_stream_topology(type, topology, assignedids, requestor, addr, cause); + + ast_stream_topology_free(tmp_converted_topology); + if (!c) { + return NULL; + } + } else if (chan->tech->requester) { + struct ast_format_cap *tmp_converted_cap = NULL; struct ast_format_cap *tmp_cap; RAII_VAR(struct ast_format *, tmp_fmt, NULL, ao2_cleanup); RAII_VAR(struct ast_format *, best_audio_fmt, NULL, ao2_cleanup); struct ast_format_cap *joint_cap; - if (strcasecmp(type, chan->tech->type)) - continue; + if (!request_cap && topology) { + /* Turn the request stream topology into capabilities */ + request_cap = tmp_converted_cap = ast_format_cap_from_stream_topology(topology); + } /* find the best audio format to use */ tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); @@ -6018,13 +6053,10 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request ast_format_cap_get_names(chan->tech->capabilities, &tech_codecs), ast_format_cap_get_names(request_cap, &request_codecs)); *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; - AST_RWLIST_UNLOCK(&backends); + ao2_cleanup(tmp_converted_cap); return NULL; } } - AST_RWLIST_UNLOCK(&backends); - if (!chan->tech->requester) - return NULL; /* XXX Only the audio format calculated as being the best for translation * purposes is used for the request. This is because we don't have the ability @@ -6033,50 +6065,58 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request */ joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!joint_cap) { + ao2_cleanup(tmp_converted_cap); return NULL; } ast_format_cap_append_from_cap(joint_cap, request_cap, AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_remove_by_type(joint_cap, AST_MEDIA_TYPE_AUDIO); ast_format_cap_append(joint_cap, best_audio_fmt, 0); + ao2_cleanup(tmp_converted_cap); + + c = chan->tech->requester(type, joint_cap, assignedids, requestor, addr, cause); - if (!(c = chan->tech->requester(type, joint_cap, assignedids, requestor, addr, cause))) { + if (!c) { ao2_ref(joint_cap, -1); return NULL; } + } else { + return NULL; + } - if (requestor) { - ast_callid callid; - - ast_channel_lock_both(c, (struct ast_channel *) requestor); + if (requestor) { + ast_callid callid; - /* Set the newly created channel's callid to the same as the requestor. */ - callid = ast_channel_callid(requestor); - if (callid) { - ast_channel_callid_set(c, callid); - } + ast_channel_lock_both(c, (struct ast_channel *) requestor); - ast_channel_unlock(c); - ast_channel_unlock((struct ast_channel *) requestor); + /* Set the newly created channel's callid to the same as the requestor. */ + callid = ast_channel_callid(requestor); + if (callid) { + ast_channel_callid_set(c, callid); } - ao2_ref(joint_cap, -1); - - if (set_security_requirements(requestor, c)) { - ast_log(LOG_WARNING, "Setting security requirements failed\n"); - ast_hangup(c); - *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; - return NULL; - } + ast_channel_unlock(c); + ast_channel_unlock((struct ast_channel *) requestor); + } - /* no need to generate a Newchannel event here; it is done in the channel_alloc call */ - return c; + if (set_security_requirements(requestor, c)) { + ast_log(LOG_WARNING, "Setting security requirements failed\n"); + ast_hangup(c); + *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; + return NULL; } - ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type); - *cause = AST_CAUSE_NOSUCHDRIVER; - AST_RWLIST_UNLOCK(&backends); + /* no need to generate a Newchannel event here; it is done in the channel_alloc call */ + return c; +} - return NULL; +struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause) +{ + return request_channel(type, request_cap, NULL, assignedids, requestor, addr, cause); +} + +struct ast_channel *ast_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause) +{ + return request_channel(type, NULL, topology, assignedids, requestor, addr, cause); } /*! diff --git a/main/stream.c b/main/stream.c index 9d36dbf25af..cf2633e1b76 100644 --- a/main/stream.c +++ b/main/stream.c @@ -392,6 +392,32 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( return topology; } +struct ast_format_cap *ast_format_cap_from_stream_topology( + struct ast_stream_topology *topology) +{ + struct ast_format_cap *caps; + int i; + + ast_assert(topology != NULL); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } + + for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { + struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i); + + if (!stream->formats) { + continue; + } + + ast_format_cap_append_from_cap(caps, stream->formats, AST_MEDIA_TYPE_UNKNOWN); + } + + return caps; +} + struct ast_stream *ast_stream_topology_get_first_stream_by_type( const struct ast_stream_topology *topology, enum ast_media_type type) diff --git a/tests/test_stream.c b/tests/test_stream.c index 3bab67c2cf4..7eecf373bab 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -1773,6 +1773,63 @@ AST_TEST_DEFINE(stream_topology_change_request_from_channel) return res; } +AST_TEST_DEFINE(format_cap_from_stream_topology) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, stream_caps, NULL, ao2_cleanup); + struct ast_stream_topology *topology; + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_from_stream_topology"; + info->category = "/main/stream/"; + info->summary = "stream topology to format capabilities conversion test"; + info->description = + "Test that converting a stream topology to format capabilities results in expected formats"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { + ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ast_format_h264, 0)) { + ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n"); + return AST_TEST_FAIL; + } + + topology = ast_stream_topology_create_from_format_cap(caps); + if (!topology) { + ast_test_status_update(test, "Failed to create a stream topology from format capabilities of ulaw and h264\n"); + return AST_TEST_FAIL; + } + + stream_caps = ast_format_cap_from_stream_topology(topology); + if (!stream_caps) { + ast_test_status_update(test, "Failed to create a format capabilities from a stream topology\n"); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + + ast_stream_topology_free(topology); + + if (!ast_format_cap_identical(caps, stream_caps)) { + ast_test_status_update(test, "Converting format capabilities into topology and back resulted in different formats\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -1797,6 +1854,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_change_request_from_channel_non_multistream); AST_TEST_UNREGISTER(stream_topology_change_request_from_application); AST_TEST_UNREGISTER(stream_topology_change_request_from_channel); + AST_TEST_UNREGISTER(format_cap_from_stream_topology); return 0; } @@ -1823,6 +1881,7 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_change_request_from_channel_non_multistream); AST_TEST_REGISTER(stream_topology_change_request_from_application); AST_TEST_REGISTER(stream_topology_change_request_from_channel); + AST_TEST_REGISTER(format_cap_from_stream_topology); return AST_MODULE_LOAD_SUCCESS; } From d6b2a58736a6c831f11a8d28a2a1d74d83bd74cb Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 27 Apr 2017 07:02:12 -0600 Subject: [PATCH 1227/1578] res_pjsip_session: Add cleanup to ast_sip_session_terminate If you use ast_request to create a PJSIP channel but then hang it up without causing a transaction to be sent, the session will never be destroyed. This is due ot the fact that it's pjproject that triggers the session cleanup when the transaction ends. app_chanisavail was doing this to get more granular channel state and it's also possible for this to happen via ARI. * ast_sip_session_terminate was modified to explicitly call the cleanup tasks and unreference session if the invite state is NULL AND invite_tsx is NULL (meaning we never sent a transaction). * chan_pjsip/hangup was modified to bump session before it calls ast_sip_session_terminate to insure that session stays valid while it does its own cleanup. * Added test events to session_destructor for a future testsuite test. ASTERISK-26908 #close Reported-by: Richard Mudgett Change-Id: I52daf6f757184e5544c261f64f6fe9602c4680a9 --- channels/chan_pjsip.c | 9 +++++-- include/asterisk/res_pjsip_session.h | 4 +++ res/res_pjsip_session.c | 39 +++++++++++++++++++++++++--- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index a92816431bb..5bf339ee943 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2052,11 +2052,16 @@ static int hangup(void *data) struct ast_sip_session *session = channel->session; int cause = h_data->cause; - ast_sip_session_terminate(session, cause); + /* + * It's possible that session_terminate might cause the session to be destroyed + * immediately so we need to keep a reference to it so we can NULL session->channel + * afterwards. + */ + ast_sip_session_terminate(ao2_bump(session), cause); clear_session_and_channel(session, ast, pvt); + ao2_cleanup(session); ao2_cleanup(channel); ao2_cleanup(h_data); - return 0; } diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index d4d3f705afd..10e55f1337c 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -459,6 +459,10 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint * * \param session The session to terminate * \param response The response code to use for termination if possible + * + * \warning Calling this function MAY cause the last session reference to be + * released and the session destructor to be called. If you need to do something + * with session after this call, be sure to bump the ref count before calling terminate. */ void ast_sip_session_terminate(struct ast_sip_session *session, int response); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 3034652a5a4..2613a74bc2b 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1302,9 +1302,19 @@ static void session_destructor(void *obj) struct ast_sip_session *session = obj; struct ast_sip_session_supplement *supplement; struct ast_sip_session_delayed_request *delay; + const char *endpoint_name = session->endpoint ? + ast_sorcery_object_get_id(session->endpoint) : ""; - ast_debug(3, "Destroying SIP session with endpoint %s\n", - session->endpoint ? ast_sorcery_object_get_id(session->endpoint) : ""); + ast_debug(3, "Destroying SIP session with endpoint %s\n", endpoint_name); + + ast_test_suite_event_notify("SESSION_DESTROYING", + "Endpoint: %s\r\n" + "AOR: %s\r\n" + "Contact: %s" + , endpoint_name + , session->aor ? ast_sorcery_object_get_id(session->aor) : "" + , session->contact ? ast_sorcery_object_get_id(session->contact) : "" + ); while ((supplement = AST_LIST_REMOVE_HEAD(&session->supplements, next))) { if (supplement->session_destroy) { @@ -1333,6 +1343,8 @@ static void session_destructor(void *obj) if (session->inv_session) { pjsip_dlg_dec_session(session->inv_session->dlg, &session_module); } + + ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name); } static int add_supplements(struct ast_sip_session *session) @@ -1793,6 +1805,9 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint return ret_session; } +static int session_end(void *vsession); +static int session_end_completion(void *vsession); + void ast_sip_session_terminate(struct ast_sip_session *session, int response) { pj_status_t status; @@ -1809,7 +1824,25 @@ void ast_sip_session_terminate(struct ast_sip_session *session, int response) switch (session->inv_session->state) { case PJSIP_INV_STATE_NULL: - pjsip_inv_terminate(session->inv_session, response, PJ_TRUE); + if (!session->inv_session->invite_tsx) { + /* + * Normally, it's pjproject's transaction cleanup that ultimately causes the + * final session reference to be released but if both STATE and invite_tsx are NULL, + * we never created a transaction in the first place. In this case, we need to + * do the cleanup ourselves. + */ + /* Transfer the inv_session session reference to the session_end_task */ + session->inv_session->mod_data[session_module.id] = NULL; + pjsip_inv_terminate(session->inv_session, response, PJ_TRUE); + session_end(session); + /* + * session_end_completion will cleanup the final session reference unless + * ast_sip_session_terminate's caller is holding one. + */ + session_end_completion(session); + } else { + pjsip_inv_terminate(session->inv_session, response, PJ_TRUE); + } break; case PJSIP_INV_STATE_CONFIRMED: if (session->inv_session->invite_tsx) { From d6535c0080632bce5ed555904d5198c04e040ffb Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 26 Apr 2017 16:14:00 -0500 Subject: [PATCH 1228/1578] SDP API: Add SSRC-level attributes RFC 5576 defines how SSRC-level attributes may be added to SDP media descriptions. In general, this is useful for grouping related SSRCes, indicating SSRC-level format attributes, and resolving collisions in RTP SSRC values. These attributes are used widely by browsers during WebRTC communications, including attributes defined by documents outside of RFC 5576. This commit introduces the addition of SSRC-level attributes into SDPs generated by Asterisk. Since Asterisk does not tend to use multiple SSRCs on a media stream, the initial support is minimal. Asterisk includes an SSRC-level CNAME attribute if configured to do so. This at least gives browsers (and possibly others) the ability to resolve SSRC collisions at offer-answer time. In order to facilitate this, the RTP engine API has been enhanced to be able to retrieve the SSRC and CNAME on a given RTP instance. res_rtp_asterisk currently does not provide meaningful CNAME values in its RTCP SDES items, and therefore it currently will always return an empty string as the CNAME value. A task in the near future will result in res_rtp_asterisk generating more meaningful CNAMEs. Change-Id: I29e7f23e7db77524f82a3b6e8531b1195ff57789 --- include/asterisk/rtp_engine.h | 22 +++++ include/asterisk/sdp_options.h | 19 ++++ main/rtp_engine.c | 26 ++++++ main/sdp_options.c | 1 + main/sdp_private.h | 1 + main/sdp_state.c | 33 +++++++ res/res_rtp_asterisk.c | 25 +++++ tests/test_sdp.c | 166 ++++++++++++++++++++++++++++++--- 8 files changed, 279 insertions(+), 14 deletions(-) diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 55acf652918..5f439163fe1 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -599,6 +599,10 @@ struct ast_rtp_engine { void (*available_formats)(struct ast_rtp_instance *instance, struct ast_format_cap *to_endpoint, struct ast_format_cap *to_asterisk, struct ast_format_cap *result); /*! Callback to send CNG */ int (*sendcng)(struct ast_rtp_instance *instance, int level); + /*! Callback to retrieve local SSRC */ + unsigned int (*ssrc_get)(struct ast_rtp_instance *instance); + /*! Callback to retrieve RTCP SDES CNAME */ + const char *(*cname_get)(struct ast_rtp_instance *instance); /*! Callback to pointer for optional ICE support */ struct ast_rtp_engine_ice *ice; /*! Callback to pointer for optional DTLS SRTP support */ @@ -2389,6 +2393,24 @@ time_t ast_rtp_instance_get_last_rx(const struct ast_rtp_instance *rtp); */ void ast_rtp_instance_set_last_rx(struct ast_rtp_instance *rtp, time_t time); +/*! + * \brief Retrieve the local SSRC value that we will be using + * + * \param rtp The RTP instance + * \return The SSRC value + */ +unsigned int ast_rtp_instance_get_ssrc(struct ast_rtp_instance *rtp); + +/*! + * \brief Retrieve the CNAME used in RTCP SDES items + * + * This is a pointer directly into the RTP struct, not a copy. + * + * \param rtp The RTP instance + * \return the CNAME + */ +const char *ast_rtp_instance_get_cname(struct ast_rtp_instance *rtp); + /*! \addtogroup StasisTopicsAndMessages * @{ */ diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index af694cd140e..3a1add37f7a 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -509,4 +509,23 @@ void ast_sdp_options_set_bind_udptl_to_media_address(struct ast_sdp_options *opt */ unsigned int ast_sdp_options_get_bind_udptl_to_media_address(const struct ast_sdp_options *options); +/*! + * \since 15.0.0 + * \brief Enable setting SSRC level attributes on SDPs + * + * \param options SDP Options + * \param ssrc Boolean indicating if SSRC attributes should be included in generated SDPs + */ +void ast_sdp_options_set_ssrc(struct ast_sdp_options *options, unsigned int ssrc); + +/*! + * \since 15.0.0 + * \brief Get SDP Options ssrc + * + * \param options SDP Options + * + * \returns Whether SSRC-level attributes will be added to our SDP. + */ +unsigned int ast_sdp_options_get_ssrc(const struct ast_sdp_options *options); + #endif /* _ASTERISK_SDP_OPTIONS_H */ diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 82298901d8d..9cfae09f437 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -3340,3 +3340,29 @@ void ast_rtp_instance_set_last_rx(struct ast_rtp_instance *rtp, time_t time) { rtp->last_rx = time; } + +unsigned int ast_rtp_instance_get_ssrc(struct ast_rtp_instance *rtp) +{ + unsigned int ssrc = 0; + + ao2_lock(rtp); + if (rtp->engine->ssrc_get) { + ssrc = rtp->engine->ssrc_get(rtp); + } + ao2_unlock(rtp); + + return ssrc; +} + +const char *ast_rtp_instance_get_cname(struct ast_rtp_instance *rtp) +{ + const char *cname = ""; + + ao2_lock(rtp); + if (rtp->engine->cname_get) { + cname = rtp->engine->cname_get(rtp); + } + ao2_unlock(rtp); + + return cname; +} diff --git a/main/sdp_options.c b/main/sdp_options.c index ef056a19075..3f25e432620 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -76,6 +76,7 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_video); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_ice, ice); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_impl, impl); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_encryption, encryption); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, ssrc); static void set_defaults(struct ast_sdp_options *options) { diff --git a/main/sdp_private.h b/main/sdp_private.h index f2efe86e530..f80cefb5fea 100644 --- a/main/sdp_private.h +++ b/main/sdp_private.h @@ -43,6 +43,7 @@ struct ast_sdp_options { unsigned int g726_non_standard : 1; unsigned int locally_held : 1; unsigned int rtcp_mux: 1; + unsigned int ssrc: 1; }; struct { unsigned int tos_audio; diff --git a/main/sdp_state.c b/main/sdp_state.c index 5aee567d3b3..98803491227 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -1182,6 +1182,37 @@ void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state, stream_state->t38_local_params = *params; } +/*! + * \brief Add SSRC-level attributes if appropriate. + * + * This function does nothing if the SDP options indicate not to add SSRC-level attributes. + * + * Currently, the only attribute added is cname, which is retrieved from the RTP instance. + * + * \param m_line The m_line on which to add the SSRC attributes + * \param options Options that indicate what, if any, SSRC attributes to add + * \param rtp RTP instance from which we get SSRC-level information + */ +static void add_ssrc_attributes(struct ast_sdp_m_line *m_line, const struct ast_sdp_options *options, + struct ast_rtp_instance *rtp) +{ + struct ast_sdp_a_line *a_line; + char attr_buffer[128]; + + if (!ast_sdp_options_get_ssrc(options)) { + return; + } + + snprintf(attr_buffer, sizeof(attr_buffer), "%u cname:%s", ast_rtp_instance_get_ssrc(rtp), + ast_rtp_instance_get_cname(rtp)); + + a_line = ast_sdp_a_alloc("ssrc", attr_buffer); + if (!a_line) { + return; + } + ast_sdp_m_add_a(m_line, a_line); +} + static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) { @@ -1312,6 +1343,8 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s return -1; } + add_ssrc_attributes(m_line, options, rtp); + if (ast_sdp_add_m(sdp, m_line)) { ast_sdp_m_free(m_line); return -1; diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index d0d79593991..85e2425cbfd 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -474,6 +474,8 @@ static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct ast_s static void ast_rtp_stop(struct ast_rtp_instance *instance); static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, const char* desc); static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level); +static unsigned int ast_rtp_get_ssrc(struct ast_rtp_instance *instance); +static const char *ast_rtp_get_cname(struct ast_rtp_instance *instance); #ifdef HAVE_OPENSSL_SRTP static int ast_rtp_activate(struct ast_rtp_instance *instance); @@ -1903,6 +1905,8 @@ static struct ast_rtp_engine asterisk_rtp_engine = { .dtls = &ast_rtp_dtls, .activate = ast_rtp_activate, #endif + .ssrc_get = ast_rtp_get_ssrc, + .cname_get = ast_rtp_get_cname, }; #ifdef HAVE_OPENSSL_SRTP @@ -5815,6 +5819,27 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level) return res; } +/*! \pre instance is locked */ +static unsigned int ast_rtp_get_ssrc(struct ast_rtp_instance *instance) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + return rtp->ssrc; +} + +/*! \pre instance is locked */ +static const char *ast_rtp_get_cname(struct ast_rtp_instance *instance) +{ + /* XXX + * + * Asterisk currently puts a zero-length CNAME value in RTCP SDES items, + * meaning our CNAME will always be an empty string. In future, should + * Asterisk actually start using meaningful CNAMEs, this function will + * need to return that instead of an empty string + */ + return ""; +} + #ifdef HAVE_OPENSSL_SRTP static void dtls_perform_setup(struct dtls_details *dtls) { diff --git a/tests/test_sdp.c b/tests/test_sdp.c index 33a6a2892ad..a5d3710d899 100644 --- a/tests/test_sdp.c +++ b/tests/test_sdp.c @@ -29,6 +29,7 @@ #include "asterisk/format.h" #include "asterisk/format_cache.h" #include "asterisk/format_cap.h" +#include "asterisk/rtp_engine.h" static int validate_o_line(struct ast_test *test, const struct ast_sdp_o_line *o_line, const char *sdpowner, const char *address_type, const char *address) @@ -353,26 +354,56 @@ AST_TEST_DEFINE(find_attr) return res; } +static struct ast_sdp_options *sdp_options_common(void) +{ + struct ast_sdp_options *options; + + options = ast_sdp_options_alloc(); + if (!options) { + return NULL; + } + ast_sdp_options_set_media_address(options, "127.0.0.1"); + ast_sdp_options_set_sdpowner(options, "me"); + ast_sdp_options_set_rtp_engine(options, "asterisk"); + ast_sdp_options_set_impl(options, AST_SDP_IMPL_PJMEDIA); + + return options; +} + struct sdp_format { enum ast_media_type type; const char *formats; }; -static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats) +/*! + * \brief Common method to build an SDP state for a test. + * + * This uses the passed-in formats to create a stream topology, which is then used to create the SDP + * state. + * + * There is an optional test_options field you can use if your test has specific options you need to + * set. If your test does not require anything special, it can just pass NULL for this parameter. If + * you do pass in test_options, this function steals ownership of those options. + * + * \param num_streams The number of elements in the formats array. + * \param formats Array of media types and formats that will be in the state. + * \param test_options Optional SDP options. + */ +static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats, struct ast_sdp_options *test_options) { struct ast_stream_topology *topology = NULL; struct ast_sdp_state *state = NULL; struct ast_sdp_options *options; int i; - options = ast_sdp_options_alloc(); - if (!options) { - goto end; + if (!test_options) { + options = sdp_options_common(); + if (!options) { + goto end; + } + } else { + options = test_options; } - ast_sdp_options_set_media_address(options, "127.0.0.1"); - ast_sdp_options_set_sdpowner(options, "me"); - ast_sdp_options_set_rtp_engine(options, "asterisk"); - ast_sdp_options_set_impl(options, AST_SDP_IMPL_PJMEDIA); topology = ast_stream_topology_alloc(); if (!topology) { @@ -436,7 +467,7 @@ AST_TEST_DEFINE(topology_to_sdp) break; } - sdp_state = build_sdp_state(ARRAY_LEN(formats), formats); + sdp_state = build_sdp_state(ARRAY_LEN(formats), formats, NULL); if (!sdp_state) { goto end; } @@ -580,7 +611,7 @@ AST_TEST_DEFINE(sdp_to_topology) break; } - sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats); + sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats, NULL); if (!sdp_state) { res = AST_TEST_FAIL; goto end; @@ -704,13 +735,13 @@ AST_TEST_DEFINE(sdp_merge_symmetric) break; } - sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats); + sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, NULL); if (!sdp_state_offerer) { res = AST_TEST_FAIL; goto end; } - sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats); + sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats, NULL); if (!sdp_state_answerer) { res = AST_TEST_FAIL; goto end; @@ -782,13 +813,13 @@ AST_TEST_DEFINE(sdp_merge_crisscross) break; } - sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats); + sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, NULL); if (!sdp_state_offerer) { res = AST_TEST_FAIL; goto end; } - sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats); + sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats, NULL); if (!sdp_state_answerer) { res = AST_TEST_FAIL; goto end; @@ -827,6 +858,111 @@ AST_TEST_DEFINE(sdp_merge_crisscross) return res; } +static int validate_ssrc(struct ast_test *test, struct ast_sdp_m_line *m_line, + struct ast_rtp_instance *rtp) +{ + unsigned int ssrc; + const char *cname; + struct ast_sdp_a_line *a_line; + char attr_value[128]; + + ssrc = ast_rtp_instance_get_ssrc(rtp); + cname = ast_rtp_instance_get_cname(rtp); + + snprintf(attr_value, sizeof(attr_value), "%u cname:%s", ssrc, cname); + + a_line = ast_sdp_m_find_attribute(m_line, "ssrc", -1); + if (!a_line) { + ast_test_status_update(test, "Could not find 'ssrc' attribute\n"); + return -1; + } + + if (strcmp(a_line->value, attr_value)) { + ast_test_status_update(test, "SDP attribute '%s' did not match expected attribute '%s'\n", + a_line->value, attr_value); + return -1; + } + + return 0; +} + +AST_TEST_DEFINE(sdp_ssrc_attributes) +{ + enum ast_test_result_state res; + struct ast_sdp_state *test_state = NULL; + struct ast_sdp_options *options; + struct sdp_format formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, + }; + const struct ast_sdp *sdp; + struct ast_sdp_m_line *m_line; + struct ast_rtp_instance *rtp; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_ssrc_attributes"; + info->category = "/main/sdp/"; + info->summary = "Ensure SSRC-level attributes are added to local SDPs"; + info->description = + "An SDP is created and is instructed to include SSRC-level attributes.\n" + "This test ensures that the CNAME SSRC-level attribute is present and\n" + "that the values match what the RTP instance reports"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + res = AST_TEST_FAIL; + + options = sdp_options_common(); + if (!options) { + ast_test_status_update(test, "Failed to allocate SDP options\n"); + goto end; + } + ast_sdp_options_set_ssrc(options, 1); + + test_state = build_sdp_state(ARRAY_LEN(formats), formats, options); + if (!test_state) { + ast_test_status_update(test, "Failed to create SDP state\n"); + goto end; + } + + sdp = ast_sdp_state_get_local_sdp(test_state); + if (!sdp) { + ast_test_status_update(test, "Failed to get local SDP\n"); + goto end; + } + + /* Need a couple of sanity checks */ + if (ast_sdp_get_m_count(sdp) != ARRAY_LEN(formats)) { + ast_test_status_update(test, "SDP m count is %d instead of %zu\n", + ast_sdp_get_m_count(sdp), ARRAY_LEN(formats)); + goto end; + } + + m_line = ast_sdp_get_m(sdp, 0); + if (!m_line) { + ast_test_status_update(test, "Failed to get SDP m-line\n"); + goto end; + } + + rtp = ast_sdp_state_get_rtp_instance(test_state, 0); + if (!rtp) { + ast_test_status_update(test, "Failed to get the RTP instance\n"); + goto end; + } + + if (validate_ssrc(test, m_line, rtp)) { + goto end; + } + + res = AST_TEST_PASS; + +end: + ast_sdp_state_free(test_state); + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(invalid_rtpmap); @@ -836,6 +972,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(sdp_to_topology); AST_TEST_UNREGISTER(sdp_merge_symmetric); AST_TEST_UNREGISTER(sdp_merge_crisscross); + AST_TEST_UNREGISTER(sdp_ssrc_attributes); return 0; } @@ -849,6 +986,7 @@ static int load_module(void) AST_TEST_REGISTER(sdp_to_topology); AST_TEST_REGISTER(sdp_merge_symmetric); AST_TEST_REGISTER(sdp_merge_crisscross); + AST_TEST_REGISTER(sdp_ssrc_attributes); return AST_MODULE_LOAD_SUCCESS; } From bad091b31761f1f29ae734b5dc2a85a3d9837bbc Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 27 Apr 2017 18:15:48 -0500 Subject: [PATCH 1229/1578] chan_vpb.cc: Fix compile error. Change-Id: I6d9edd34d8b2474222c86f44e379ead61e57a54f --- channels/chan_vpb.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index 87342b1d020..d7e9732e0bc 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -365,6 +365,7 @@ static struct ast_channel_tech vpb_tech = { capabilities: NULL, properties: 0, requester: vpb_request, + requester_with_stream_topology: NULL, devicestate: NULL, presencestate: NULL, send_digit_begin: vpb_digit_begin, @@ -398,6 +399,7 @@ static struct ast_channel_tech vpb_tech_indicate = { capabilities: NULL, properties: 0, requester: vpb_request, + requester_with_stream_topology: NULL, devicestate: NULL, presencestate: NULL, send_digit_begin: vpb_digit_begin, From 176123e76c1705c2cc3247dcd0e15bbb060e7d9b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 14 Apr 2017 11:52:33 -0500 Subject: [PATCH 1230/1578] SDP: Misc cleanups (Mostly memory leaks) Change-Id: I74431b385da333f2c5f5a6d7c55e70b69a4f05d2 --- include/asterisk/sdp.h | 4 +-- main/sdp.c | 23 ++++++++----- main/sdp_state.c | 55 ++++++++++++++++++++++---------- main/sdp_translator.c | 3 ++ res/res_sdp_translator_pjmedia.c | 2 +- 5 files changed, 60 insertions(+), 27 deletions(-) diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h index d5bf9147b24..06470c4b05c 100644 --- a/include/asterisk/sdp.h +++ b/include/asterisk/sdp.h @@ -535,8 +535,8 @@ struct ast_sdp_payload *ast_sdp_m_get_payload(const struct ast_sdp_m_line *m_lin * \param format Format * \param code from AST_RTP list * - * \retval non-NULL Success - * \retval NULL Failure + * \retval 0 Success + * \retval non-0 Failure * * \since 15 */ diff --git a/main/sdp.c b/main/sdp.c index dc6afe7d8a4..62acdd3f758 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -435,19 +435,25 @@ static int sdp_m_add_fmtp(struct ast_sdp_m_line *m_line, const struct ast_format int rtp_code) { struct ast_str *fmtp0 = ast_str_alloca(256); + struct ast_sdp_a_line *a_line; char *tmp; ast_format_generate_sdp_fmtp(format, rtp_code, &fmtp0); if (ast_str_strlen(fmtp0) == 0) { - return -1; + /* Format doesn't have fmtp attributes */ + return 0; } tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1; - /* remove any carriage return line feeds */ + /* remove any carriage return line feeds */ while (*tmp == '\r' || *tmp == '\n') --tmp; *++tmp = '\0'; - /* ast...generate gives us everything, just need value */ + /* + * ast...generate gives us everything, just need value + * + * It can also give multiple fmtp attribute lines. (silk does) + */ tmp = strchr(ast_str_buffer(fmtp0), ':'); if (tmp && tmp[1] != '\0') { tmp++; @@ -455,7 +461,10 @@ static int sdp_m_add_fmtp(struct ast_sdp_m_line *m_line, const struct ast_format tmp = ast_str_buffer(fmtp0); } - ast_sdp_m_add_a(m_line, ast_sdp_a_alloc("fmtp", tmp)); + a_line = ast_sdp_a_alloc("fmtp", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + return -1; + } return 0; } @@ -495,10 +504,8 @@ static int sdp_m_add_rtpmap(struct ast_sdp_m_line *m_line, int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_options *options, int rtp_code, int asterisk_format, const struct ast_format *format, int code) { - sdp_m_add_rtpmap(m_line, options, rtp_code, asterisk_format, format, code); - sdp_m_add_fmtp(m_line, format, rtp_code); - - return 0; + return sdp_m_add_rtpmap(m_line, options, rtp_code, asterisk_format, format, code) + || sdp_m_add_fmtp(m_line, format, rtp_code) ? -1 : 0; } static struct ast_sdp_a_line *sdp_find_attribute_common(const struct ast_sdp_a_lines *a_lines, diff --git a/main/sdp_state.c b/main/sdp_state.c index 5aee567d3b3..8534501497b 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -30,7 +30,7 @@ #include "asterisk/codec.h" #include "asterisk/udptl.h" -#include "../include/asterisk/sdp.h" +#include "asterisk/sdp.h" #include "asterisk/stream.h" #include "sdp_private.h" @@ -171,7 +171,7 @@ static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options return NULL; } - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { @@ -252,8 +252,7 @@ static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const st return NULL; } - if (AST_VECTOR_INIT(&capabilities->streams, - ast_stream_topology_get_count(topology))) { + if (AST_VECTOR_INIT(&capabilities->streams, ast_stream_topology_get_count(topology))) { sdp_state_capabilities_free(capabilities); return NULL; } @@ -264,17 +263,18 @@ static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const st state_stream = ast_calloc(1, sizeof(*state_stream)); if (!state_stream) { + sdp_state_capabilities_free(capabilities); return NULL; } state_stream->type = ast_stream_get_type(ast_stream_topology_get_stream(topology, i)); - switch (state_stream->type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: state_stream->instance = create_rtp(options, state_stream->type); if (!state_stream->instance) { sdp_state_stream_free(state_stream); + sdp_state_capabilities_free(capabilities); return NULL; } break; @@ -282,16 +282,24 @@ static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const st state_stream->udptl = create_udptl(options); if (!state_stream->udptl) { sdp_state_stream_free(state_stream); + sdp_state_capabilities_free(capabilities); return NULL; } break; case AST_MEDIA_TYPE_UNKNOWN: case AST_MEDIA_TYPE_TEXT: case AST_MEDIA_TYPE_END: - break; + ast_assert(0); + sdp_state_stream_free(state_stream); + sdp_state_capabilities_free(capabilities); + return NULL; } - AST_VECTOR_APPEND(&capabilities->streams, state_stream); + if (AST_VECTOR_APPEND(&capabilities->streams, state_stream)) { + sdp_state_stream_free(state_stream); + sdp_state_capabilities_free(capabilities); + return NULL; + } } return capabilities; @@ -632,7 +640,9 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ goto fail; } - AST_VECTOR_INIT(&joint_capabilities->streams, AST_VECTOR_SIZE(¤t->streams)); + if (AST_VECTOR_INIT(&joint_capabilities->streams, AST_VECTOR_SIZE(¤t->streams))) { + goto fail; + } ast_sockaddr_copy(&joint_capabilities->connection_address, ¤t->connection_address); topology = current->topology; @@ -654,11 +664,11 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ new_stream_type = ast_stream_get_type(new_stream); current_index = get_corresponding_index(topology, new_stream_type, media_indices); - if (current_index >= 0) { current_stream = ast_stream_topology_get_stream(topology, current_index); joint_stream = merge_streams(current_stream, new_stream); if (!joint_stream) { + sdp_state_stream_free(joint_state_stream); goto fail; } @@ -692,6 +702,7 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ */ joint_stream = ast_stream_clone(new_stream); if (!joint_stream) { + sdp_state_stream_free(joint_state_stream); goto fail; } @@ -700,12 +711,16 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ case AST_MEDIA_TYPE_VIDEO: joint_state_stream->instance = create_rtp(options, new_stream_type); if (!joint_state_stream->instance) { + ast_stream_free(joint_stream); + sdp_state_stream_free(joint_state_stream); goto fail; } break; case AST_MEDIA_TYPE_IMAGE: joint_state_stream->udptl = create_udptl(options); if (!joint_state_stream->udptl) { + ast_stream_free(joint_stream); + sdp_state_stream_free(joint_state_stream); goto fail; } break; @@ -723,12 +738,20 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ */ joint_stream = ast_stream_alloc("dummy", new_stream_type); if (!joint_stream) { + sdp_state_stream_free(joint_state_stream); goto fail; } } - ast_stream_topology_append_stream(joint_capabilities->topology, joint_stream); - AST_VECTOR_APPEND(&joint_capabilities->streams, joint_state_stream); + if (ast_stream_topology_append_stream(joint_capabilities->topology, joint_stream) < 0) { + ast_stream_free(joint_stream); + sdp_state_stream_free(joint_state_stream); + goto fail; + } + if (AST_VECTOR_APPEND(&joint_capabilities->streams, joint_state_stream)) { + sdp_state_stream_free(joint_state_stream); + goto fail; + } } return joint_capabilities; @@ -974,8 +997,7 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta * \retval -1 Failure * \retval 0 Success */ -static int merge_sdps(struct ast_sdp_state *sdp_state, - const struct ast_sdp *remote_sdp) +static int merge_sdps(struct ast_sdp_state *sdp_state, const struct ast_sdp *remote_sdp) { struct sdp_state_capabilities *joint_capabilities; int i; @@ -1073,7 +1095,7 @@ int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void return -1; } ast_sdp_state_set_remote_sdp(sdp_state, sdp); - + ast_sdp_free(sdp); return 0; } @@ -1254,13 +1276,13 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s rtp_code = ast_rtp_codecs_payload_code( ast_rtp_instance_get_codecs(rtp), 0, NULL, i); - if (rtp_code == -1) { continue; } if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) { - continue; + ast_sdp_m_free(m_line); + return -1; } if (i == AST_RTP_DTMF) { @@ -1276,6 +1298,7 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s } if (ast_sdp_m_get_a_count(m_line) == 0) { + ast_sdp_m_free(m_line); return 0; } diff --git a/main/sdp_translator.c b/main/sdp_translator.c index abd0f627667..2426b10ea23 100644 --- a/main/sdp_translator.c +++ b/main/sdp_translator.c @@ -84,6 +84,9 @@ struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_impl repr void ast_sdp_translator_free(struct ast_sdp_translator *translator) { + if (!translator) { + return; + } translator->ops->translator_free(translator->translator_priv); ast_free(translator); } diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c index 8eab71611d5..6ad1e9b0948 100644 --- a/res/res_sdp_translator_pjmedia.c +++ b/res/res_sdp_translator_pjmedia.c @@ -26,7 +26,7 @@ #include "asterisk/test.h" #include "asterisk/module.h" -#include "../include/asterisk/sdp.h" +#include "asterisk/sdp.h" #ifdef HAVE_PJPROJECT #include #include From d71c6e3bfd0db7b069da326c155766b679de552f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 24 Apr 2017 16:55:23 -0500 Subject: [PATCH 1231/1578] SDP: Make ast_sdp_state_set_remote_sdp() return error. Change-Id: I7707c9d872c476d897ff459008652b35142a35e1 --- include/asterisk/sdp_state.h | 5 ++++- main/sdp_state.c | 9 +++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index 1382ed6af66..88660b6c7e7 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -146,9 +146,12 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state); * \param sdp_state * \param sdp * + * \retval 0 Success + * \retval non-0 Failure + * * \since 15 */ -void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct ast_sdp *sdp); +int ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct ast_sdp *sdp); /*! * \brief Set the remote SDP from an Implementation diff --git a/main/sdp_state.c b/main/sdp_state.c index 8534501497b..2c018b12614 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -1073,7 +1073,7 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state) return ast_sdp_translator_from_sdp(sdp_state->translator, sdp); } -void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct ast_sdp *sdp) +int ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct ast_sdp *sdp) { ast_assert(sdp_state != NULL); @@ -1081,12 +1081,13 @@ void ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct sdp_state->role = SDP_ROLE_ANSWERER; } - merge_sdps(sdp_state, sdp); + return merge_sdps(sdp_state, sdp); } int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void *remote) { struct ast_sdp *sdp; + int ret; ast_assert(sdp_state != NULL); @@ -1094,9 +1095,9 @@ int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void if (!sdp) { return -1; } - ast_sdp_state_set_remote_sdp(sdp_state, sdp); + ret = ast_sdp_state_set_remote_sdp(sdp_state, sdp); ast_sdp_free(sdp); - return 0; + return ret; } int ast_sdp_state_reset(struct ast_sdp_state *sdp_state) From 5c1851cbc0e31cc1fee108983b1937212002860c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 20 Apr 2017 19:25:10 -0500 Subject: [PATCH 1232/1578] stream: Make ast_stream_topology_create_from_format_cap() allow NULL cap. Change-Id: Ie29760c49c25d7022ba2124698283181a0dd5d08 --- include/asterisk/stream.h | 2 +- main/channel_internal_api.c | 8 ++------ main/stream.c | 6 ++---- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 924bfb65cdf..1e07407a9f8 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -356,7 +356,7 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, * creates a topology and separates the media types in format_cap into * separate streams. * - * \param caps The format capabilities structure + * \param caps The format capabilities structure (NULL creates an empty topology) * * \retval non-NULL success * \retval NULL failure diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index d838ea80cfb..7f32b219665 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -852,14 +852,10 @@ void ast_channel_nativeformats_set(struct ast_channel *chan, return; } - if ((!ast_channel_is_multistream(chan)) || !value) { + if (!ast_channel_is_multistream(chan) || !value) { struct ast_stream_topology *new_topology; - if (!value) { - new_topology = ast_stream_topology_alloc(); - } else { - new_topology = ast_stream_topology_create_from_format_cap(value); - } + new_topology = ast_stream_topology_create_from_format_cap(value); ast_channel_internal_set_stream_topology(chan, new_topology); } } diff --git a/main/stream.c b/main/stream.c index cf2633e1b76..39b6b1b13f6 100644 --- a/main/stream.c +++ b/main/stream.c @@ -345,11 +345,9 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_stream_topology *topology; enum ast_media_type type; - ast_assert(cap != NULL); - topology = ast_stream_topology_alloc(); - if (!topology) { - return NULL; + if (!topology || !cap || !ast_format_cap_count(cap)) { + return topology; } for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; type++) { From ede90e4aa56b6654e86ceefc6d2944526a5f182c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 24 Apr 2017 18:13:04 -0500 Subject: [PATCH 1233/1578] SDP: Make SDP translation to/from internal representation more const. Change-Id: I473a174b869728604b37c60853896b0c458bc504 --- include/asterisk/sdp_state.h | 2 +- include/asterisk/sdp_translator.h | 8 ++++---- main/sdp_state.c | 2 +- main/sdp_translator.c | 4 ++-- res/res_sdp_translator_pjmedia.c | 12 ++++++------ 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index 88660b6c7e7..c2122fbce5a 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -164,7 +164,7 @@ int ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct a * * \since 15 */ -int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void *remote); +int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, const void *remote); /*! * \brief Reset the SDP state and stream capabilities as if the SDP state had just been allocated. diff --git a/include/asterisk/sdp_translator.h b/include/asterisk/sdp_translator.h index 09901af2e6c..e1d51f0be09 100644 --- a/include/asterisk/sdp_translator.h +++ b/include/asterisk/sdp_translator.h @@ -34,9 +34,9 @@ struct ast_sdp_translator_ops { /*! Free translator private data */ void (*translator_free)(void *translator_priv); /*! Convert the channel-native SDP into an internal Asterisk SDP */ - struct ast_sdp *(*to_sdp)(void *repr_sdp, void *translator_priv); + struct ast_sdp *(*to_sdp)(const void *repr_sdp, void *translator_priv); /*! Convert an internal Asterisk SDP into a channel-native SDP */ - void *(*from_sdp)(const struct ast_sdp *sdp, void *translator_priv); + const void *(*from_sdp)(const struct ast_sdp *sdp, void *translator_priv); }; /*! @@ -87,7 +87,7 @@ void ast_sdp_translator_free(struct ast_sdp_translator *translator); * \retval NULL FAIL * \retval Non-NULL The translated SDP */ -struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, void *native_sdp); +struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, const void *native_sdp); /*! * \brief Translate an internal Asterisk SDP to a native SDP @@ -97,7 +97,7 @@ struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, * \retval NULL FAIL * \retval non-NULL The translated SDP */ -void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, +const void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, const struct ast_sdp *ast_sdp); #endif /* _ASTERISK_SDP_TRANSLATOR_H */ diff --git a/main/sdp_state.c b/main/sdp_state.c index 2c018b12614..dddc79c071b 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -1084,7 +1084,7 @@ int ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct a return merge_sdps(sdp_state, sdp); } -int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void *remote) +int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, const void *remote) { struct ast_sdp *sdp; int ret; diff --git a/main/sdp_translator.c b/main/sdp_translator.c index 2426b10ea23..6fe330a60dd 100644 --- a/main/sdp_translator.c +++ b/main/sdp_translator.c @@ -92,12 +92,12 @@ void ast_sdp_translator_free(struct ast_sdp_translator *translator) } struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, - void *native_sdp) + const void *native_sdp) { return translator->ops->to_sdp(native_sdp, translator->translator_priv); } -void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, +const void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator, const struct ast_sdp *ast_sdp) { return translator->ops->from_sdp(ast_sdp, translator->translator_priv); diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c index 6ad1e9b0948..3b9c26c46d9 100644 --- a/res/res_sdp_translator_pjmedia.c +++ b/res/res_sdp_translator_pjmedia.c @@ -89,7 +89,7 @@ static struct ast_sdp_m_line *pjmedia_copy_m_line(struct pjmedia_sdp_media *pjme return m_line; } -static void pjmedia_copy_a_lines(struct ast_sdp *new_sdp, pjmedia_sdp_session *pjmedia_sdp) +static void pjmedia_copy_a_lines(struct ast_sdp *new_sdp, const pjmedia_sdp_session *pjmedia_sdp) { int i; @@ -100,7 +100,7 @@ static void pjmedia_copy_a_lines(struct ast_sdp *new_sdp, pjmedia_sdp_session *p } static void pjmedia_copy_m_lines(struct ast_sdp *new_sdp, - struct pjmedia_sdp_session *pjmedia_sdp) + const struct pjmedia_sdp_session *pjmedia_sdp) { int i; @@ -109,9 +109,9 @@ static void pjmedia_copy_m_lines(struct ast_sdp *new_sdp, } } -static struct ast_sdp *pjmedia_to_sdp(void *in, void *translator_priv) +static struct ast_sdp *pjmedia_to_sdp(const void *in, void *translator_priv) { - struct pjmedia_sdp_session *pjmedia_sdp = in; + const struct pjmedia_sdp_session *pjmedia_sdp = in; struct ast_sdp_o_line *o_line = ast_sdp_o_alloc(dupa_pj_str(pjmedia_sdp->origin.user), pjmedia_sdp->origin.id, pjmedia_sdp->origin.version, @@ -239,7 +239,7 @@ static void copy_m_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_s } } -static void *sdp_to_pjmedia(const struct ast_sdp *sdp, void *translator_priv) +static const void *sdp_to_pjmedia(const struct ast_sdp *sdp, void *translator_priv) { pj_pool_t *pool = translator_priv; pjmedia_sdp_session *pjmedia_sdp; @@ -470,7 +470,7 @@ AST_TEST_DEFINE(sdp_to_pjmedia_test) "a=rtpmap:32 MPV/90000\r\n\r\n"; pj_pool_t *pool; pjmedia_sdp_session *pjmedia_sdp_orig; - pjmedia_sdp_session *pjmedia_sdp_dup; + const pjmedia_sdp_session *pjmedia_sdp_dup; struct ast_sdp *sdp = NULL; pj_status_t status; enum ast_test_result_state res = AST_TEST_PASS; From 48566b8c66551a4b709acd700575887144c6cfad Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 27 Apr 2017 16:46:40 -0500 Subject: [PATCH 1234/1578] res_sdp_translator_pjmedia.c: Add TODO notes. Change-Id: If27ca61f79accc882c3376d2e876d2b44aa1347b --- res/res_sdp_translator_pjmedia.c | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c index 3b9c26c46d9..85f246e8371 100644 --- a/res/res_sdp_translator_pjmedia.c +++ b/res/res_sdp_translator_pjmedia.c @@ -37,6 +37,45 @@ core ***/ +/* + * XXX TODO: The memory in the pool is held onto longer than necessary. It + * is kept and grows for the duration of the associated chan_pjsip session. + * + * The translation API does not need to be so generic. The users will know + * at compile time what the non-Asterisk SDP format they have or need. They + * should simply call the specific translation functions. However, to make + * this a loadable module we need to be able to keep it in memory when a + * dependent module is loaded. + * + * To address both issues I propose this API: + * + * void ast_sdp_translate_pjmedia_ref(void) - Inc this module's user ref + * void ast_sdp_translate_pjmedia_unref(void) - Dec this module's user ref. + * The res_pjsip_session.c:ast_sip_session_alloc() can call the module ref + * and the session's destructor can call the module unref. + * + * struct ast_sdp *ast_sdp_translate_pjmedia_from(const pjmedia_sdp_session *pjmedia_sdp); + * + * pjmedia_sdp_session *ast_sdp_translate_pjmedia_to(const struct ast_sdp *sdp, pj_pool_t *pool); + * Passing in a memory pool allows the memory to be obtained from an + * rdata memory pool that will be released when the message processing + * is complete. This prevents memory from accumulating for the duration + * of a call. + * + * int ast_sdp_translate_pjmedia_set_remote_sdp(struct ast_sdp_state *sdp_state, const pjmedia_sdp_session *remote); + * const pjmedia_sdp_session *ast_sdp_translate_pjmedia_get_local_sdp(struct ast_sdp_state *sdp_state, pj_pool_t *pool); + * These two functions just do the bookkeeping to translate and set or get + * the requested SDP. + * + * + * XXX TODO: This code doesn't handle allocation failures very well. i.e., + * It assumes they will never happen. + * + * XXX TODO: This code uses ast_alloca() inside loops. Doing so if the number + * of times through the loop is unconstrained will blow the stack. + * See dupa_pj_str() usage. + */ + static pj_caching_pool sdp_caching_pool; From 8170793be672f1440efc4c1f9297b24c73723c6d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 28 Apr 2017 09:56:20 -0600 Subject: [PATCH 1235/1578] res_pjsip_outbound_authenticator_digest: Add context to log messages There was no context info in this module's log messages so it was impossible to toubleshoot. Added endpoint or host to all messages and added the realms in the challenge for the "No auth credentials for any realm" message. Change-Id: Ifeed2786f35fbea7d141237ae15625e472acff9b --- res/res_pjsip_outbound_authenticator_digest.c | 80 ++++++++++++++----- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c index 4bbac342f53..7e2d7112927 100644 --- a/res/res_pjsip_outbound_authenticator_digest.c +++ b/res/res_pjsip_outbound_authenticator_digest.c @@ -31,7 +31,9 @@ #include "asterisk/module.h" #include "asterisk/strings.h" -static pjsip_www_authenticate_hdr *get_auth_header(pjsip_rx_data *challenge) { +static pjsip_www_authenticate_hdr *get_auth_header(pjsip_rx_data *challenge, + const void *start) +{ pjsip_hdr_e search_type; if (challenge->msg_info.msg->line.status.code == PJSIP_SC_UNAUTHORIZED) { @@ -45,17 +47,17 @@ static pjsip_www_authenticate_hdr *get_auth_header(pjsip_rx_data *challenge) { return NULL ; } - return pjsip_msg_find_hdr(challenge->msg_info.msg, search_type, NULL); + return pjsip_msg_find_hdr(challenge->msg_info.msg, search_type, start); } static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_sess, - const struct ast_sip_auth_vector *auth_vector, pjsip_rx_data *challenge) + const struct ast_sip_auth_vector *auth_vector, pjsip_rx_data *challenge, + pjsip_www_authenticate_hdr *auth_hdr) { size_t auth_size = AST_VECTOR_SIZE(auth_vector); struct ast_sip_auth **auths = ast_alloca(auth_size * sizeof(*auths)); pjsip_cred_info *auth_creds = ast_alloca(auth_size * sizeof(*auth_creds)); - pjsip_www_authenticate_hdr *auth_hdr = NULL; int res = 0; int i; @@ -64,13 +66,6 @@ static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_ses goto cleanup; } - auth_hdr = get_auth_header(challenge); - if (auth_hdr == NULL) { - res = -1; - ast_log(LOG_ERROR, "Unable to find authenticate header in challenge.\n"); - goto cleanup; - } - for (i = 0; i < auth_size; ++i) { if (ast_strlen_zero(auths[i]->realm)) { auth_creds[i].realm = auth_hdr->challenge.common.realm; @@ -101,21 +96,50 @@ static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_ses return res; } -static int digest_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, - pjsip_tx_data *old_request, pjsip_tx_data **new_request) +static int digest_create_request_with_auth(const struct ast_sip_auth_vector *auths, + pjsip_rx_data *challenge, pjsip_tx_data *old_request, pjsip_tx_data **new_request) { pjsip_auth_clt_sess auth_sess; pjsip_cseq_hdr *cseq; pj_status_t status; + struct ast_sip_endpoint *endpoint; + char *id = NULL; + const char *id_type; + pjsip_www_authenticate_hdr *auth_hdr; + struct ast_str *realms; + pjsip_dialog *dlg; + + dlg = pjsip_rdata_get_dlg(challenge); + if (dlg) { + endpoint = ast_sip_dialog_get_endpoint(dlg); + id = endpoint ? ast_strdupa(ast_sorcery_object_get_id(endpoint)) : NULL; + ao2_cleanup(endpoint); + id_type = "Endpoint"; + } + /* If there was no dialog, then this is probably a REGISTER so no endpoint */ + if (!id) { + id = ast_alloca(strlen(challenge->pkt_info.src_name) + 7 /* ':' + port + NULL */); + sprintf(id, "%s:%d", challenge->pkt_info.src_name, challenge->pkt_info.src_port); + id_type = "Host"; + } + + auth_hdr = get_auth_header(challenge, NULL); + if (auth_hdr == NULL) { + ast_log(LOG_ERROR, "%s: '%s': Unable to find authenticate header in challenge.\n", + id_type, id); + return -1; + } if (pjsip_auth_clt_init(&auth_sess, ast_sip_get_pjsip_endpoint(), old_request->pool, 0) != PJ_SUCCESS) { - ast_log(LOG_WARNING, "Failed to initialize client authentication session\n"); + ast_log(LOG_ERROR, "%s: '%s': Failed to initialize client authentication session\n", + id_type, id); return -1; } - if (set_outbound_authentication_credentials(&auth_sess, auths, challenge)) { - ast_log(LOG_WARNING, "Failed to set authentication credentials\n"); + if (set_outbound_authentication_credentials(&auth_sess, auths, challenge, auth_hdr)) { + ast_log(LOG_WARNING, "%s: '%s': Failed to set authentication credentials\n", + id_type, id); #if defined(HAVE_PJSIP_AUTH_CLT_DEINIT) /* In case it is not a noop here in the future. */ pjsip_auth_clt_deinit(&auth_sess); @@ -128,6 +152,7 @@ static int digest_create_request_with_auth(const struct ast_sip_auth_vector *aut /* Release any cached auths */ pjsip_auth_clt_deinit(&auth_sess); #endif + switch (status) { case PJ_SUCCESS: /* PJSIP creates a new transaction for new_request (meaning it creates a new @@ -141,18 +166,33 @@ static int digest_create_request_with_auth(const struct ast_sip_auth_vector *aut ++cseq->cseq; return 0; case PJSIP_ENOCREDENTIAL: + realms = ast_str_create(32); + if (realms) { + ast_str_append(&realms, 0, "%.*s", (int)auth_hdr->challenge.common.realm.slen, + auth_hdr->challenge.common.realm.ptr); + while((auth_hdr = get_auth_header(challenge, auth_hdr->next))) { + ast_str_append(&realms, 0, ",%.*s", (int)auth_hdr->challenge.common.realm.slen, + auth_hdr->challenge.common.realm.ptr); + } + } ast_log(LOG_WARNING, - "Unable to create request with auth. No auth credentials for any realms in challenge.\n"); + "%s: '%s': Unable to create request with auth. " + "No auth credentials for realm(s) '%s' in challenge.\n", id_type, id, + realms ? ast_str_buffer(realms) : ""); + ast_free(realms); break; case PJSIP_EAUTHSTALECOUNT: ast_log(LOG_WARNING, - "Unable to create request with auth. Number of stale retries exceeded.\n"); + "%s: '%s': Unable to create request with auth. Number of stale retries exceeded.\n", + id_type, id); break; case PJSIP_EFAILEDCREDENTIAL: - ast_log(LOG_WARNING, "Authentication credentials not accepted by server.\n"); + ast_log(LOG_WARNING, "%s: '%s': Authentication credentials not accepted by server.\n", + id_type, id); break; default: - ast_log(LOG_WARNING, "Unable to create request with auth. Unknown failure.\n"); + ast_log(LOG_WARNING, "%s: '%s': Unable to create request with auth. Unknown failure.\n", + id_type, id); break; } From 52e4f02b1a100a414161ee70c64b9af5993e26bb Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Sat, 29 Apr 2017 16:11:21 -0500 Subject: [PATCH 1236/1578] res_pjsip_t38.c: Fix deadlock in T.38 framehook. A deadlock can happen between a channel lock and a pjsip session media container lock. One thread is processing a reINVITE's SDP and walking through the session's media container when it waits for the channel lock to put the determined format capabilities onto the channel. The other thread is writing a frame to the channel and processing the T.38 frame hook. The T.38 frame hook then waits for the pjsip session's media container lock. The two threads are now deadlocked. * Made the T.38 frame hook release the channel lock before searching the session's media container. This fix has been done to several other frame hooks to fix deadlocks. ASTERISK-26974 #close Change-Id: Ie984a76ce00bef6ec9aa239010e51e8dd74c8186 --- res/res_pjsip_t38.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 4f082d71444..bb1641a44c5 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -398,7 +398,8 @@ static int t38_interpret_parameters(void *obj) } /*! \brief Frame hook callback for writing */ -static struct ast_frame *t38_framehook_write(struct ast_sip_session *session, struct ast_frame *f) +static struct ast_frame *t38_framehook_write(struct ast_channel *chan, + struct ast_sip_session *session, struct ast_frame *f) { if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS && session->endpoint->media.t38.enabled) { @@ -412,27 +413,36 @@ static struct ast_frame *t38_framehook_write(struct ast_sip_session *session, st ao2_ref(data, -1); } } else if (f->frametype == AST_FRAME_MODEM) { - RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup); + struct ast_sip_session_media *session_media; - if ((session_media = ao2_find(session->media, "image", OBJ_KEY)) && - session_media->udptl) { + /* Avoid deadlock between chan and the session->media container lock */ + ast_channel_unlock(chan); + session_media = ao2_find(session->media, "image", OBJ_SEARCH_KEY); + ast_channel_lock(chan); + if (session_media && session_media->udptl) { ast_udptl_write(session_media->udptl, f); } + ao2_cleanup(session_media); } return f; } /*! \brief Frame hook callback for reading */ -static struct ast_frame *t38_framehook_read(struct ast_sip_session *session, struct ast_frame *f) +static struct ast_frame *t38_framehook_read(struct ast_channel *chan, + struct ast_sip_session *session, struct ast_frame *f) { if (ast_channel_fdno(session->channel) == 5) { - RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup); + struct ast_sip_session_media *session_media; - if ((session_media = ao2_find(session->media, "image", OBJ_KEY)) && - session_media->udptl) { + /* Avoid deadlock between chan and the session->media container lock */ + ast_channel_unlock(chan); + session_media = ao2_find(session->media, "image", OBJ_SEARCH_KEY); + ast_channel_lock(chan); + if (session_media && session_media->udptl) { f = ast_udptl_read(session_media->udptl); } + ao2_cleanup(session_media); } return f; @@ -445,9 +455,9 @@ static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_fram struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); if (event == AST_FRAMEHOOK_EVENT_READ) { - f = t38_framehook_read(channel->session, f); + f = t38_framehook_read(chan, channel->session, f); } else if (event == AST_FRAMEHOOK_EVENT_WRITE) { - f = t38_framehook_write(channel->session, f); + f = t38_framehook_write(chan, channel->session, f); } return f; From cd272da7a8aa121113a7ca7e44d85eb88e721607 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 26 Apr 2017 16:22:38 -0500 Subject: [PATCH 1237/1578] SDP: Replace SDP telephone_event option with dtmf option The telephone_event option was used as a flag and a bit mapped value in different places when it is a boolean. It is also inadequate to configure the DTMF operation of the RTP instance created for the stream. Change-Id: Ib1addeaf0ce86f07039f2f979cab29405dc5239b --- include/asterisk/sdp_options.h | 54 +++++++++++++++++++++------------- main/sdp_options.c | 6 ++-- main/sdp_private.h | 20 ++++++------- main/sdp_state.c | 38 ++++++++++-------------- 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index 3a1add37f7a..9c699a2f25f 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -23,6 +23,20 @@ struct ast_sdp_options; +/*! + * \brief SDP DTMF mode options + */ +enum ast_sdp_options_dtmf { + /*! No DTMF to be used */ + AST_SDP_DTMF_NONE, + /*! Use RFC 4733 events for DTMF */ + AST_SDP_DTMF_RFC_4733, + /*! Use DTMF in the audio stream */ + AST_SDP_DTMF_INBAND, + /*! Use SIP 4733 if supported by the other side or INBAND if not */ + AST_SDP_DTMF_AUTO, +}; + /*! * \brief ICE options * @@ -210,26 +224,6 @@ void ast_sdp_options_set_rtp_symmetric(struct ast_sdp_options *options, */ unsigned int ast_sdp_options_get_rtp_symmetric(const struct ast_sdp_options *options); -/*! - * \since 15.0.0 - * \brief Set SDP Options telephone_event - * - * \param options SDP Options - * \param telephone_event - */ -void ast_sdp_options_set_telephone_event(struct ast_sdp_options *options, - unsigned int telephone_event); - -/*! - * \since 15.0.0 - * \brief Get SDP Options telephone_event - * - * \param options SDP Options - * - * \returns telephone_event - */ -unsigned int ast_sdp_options_get_telephone_event(const struct ast_sdp_options *options); - /*! * \since 15.0.0 * \brief Set SDP Options rtp_ipv6 @@ -350,6 +344,26 @@ void ast_sdp_options_set_cos_video(struct ast_sdp_options *options, */ unsigned int ast_sdp_options_get_cos_video(const struct ast_sdp_options *options); +/*! + * \since 15.0.0 + * \brief Set SDP Options dtmf + * + * \param options SDP Options + * \param dtmf + */ +void ast_sdp_options_set_dtmf(struct ast_sdp_options *options, + enum ast_sdp_options_dtmf dtmf); + +/*! + * \since 15.0.0 + * \brief Get SDP Options dtmf + * + * \param options SDP Options + * + * \returns dtmf + */ +enum ast_sdp_options_dtmf ast_sdp_options_get_dtmf(const struct ast_sdp_options *options); + /*! * \since 15.0.0 * \brief Set SDP Options ice diff --git a/main/sdp_options.c b/main/sdp_options.c index 3f25e432620..9b57e189fb3 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -23,8 +23,8 @@ #include "sdp_private.h" +#define DEFAULT_DTMF AST_SDP_DTMF_NONE #define DEFAULT_ICE AST_SDP_ICE_DISABLED -#define DEFAULT_TELEPHONE_EVENT 0 #define DEFAULT_IMPL AST_SDP_IMPL_STRING #define DEFAULT_ENCRYPTION AST_SDP_ENCRYPTION_DISABLED @@ -65,7 +65,6 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_symmetric); DEFINE_GETTERS_SETTERS_FOR(enum ast_t38_ec_modes, udptl_error_correction); DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_far_max_datagram); -DEFINE_GETTERS_SETTERS_FOR(unsigned int, telephone_event); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_ipv6); DEFINE_GETTERS_SETTERS_FOR(unsigned int, g726_non_standard); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtcp_mux); @@ -73,6 +72,7 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_video); DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_video); +DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_dtmf, dtmf); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_ice, ice); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_impl, impl); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_encryption, encryption); @@ -80,8 +80,8 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, ssrc); static void set_defaults(struct ast_sdp_options *options) { + options->dtmf = DEFAULT_DTMF; options->ice = DEFAULT_ICE; - options->telephone_event = DEFAULT_TELEPHONE_EVENT; options->impl = DEFAULT_IMPL; options->encryption = DEFAULT_ENCRYPTION; } diff --git a/main/sdp_private.h b/main/sdp_private.h index f80cefb5fea..c90a57485e1 100644 --- a/main/sdp_private.h +++ b/main/sdp_private.h @@ -34,16 +34,15 @@ struct ast_sdp_options { AST_STRING_FIELD(rtp_engine); ); struct { - unsigned int bind_rtp_to_media_address : 1; - unsigned int bind_udptl_to_media_address : 1; - unsigned int rtp_symmetric : 1; - unsigned int udptl_symmetric : 1; - unsigned int telephone_event : 1; - unsigned int rtp_ipv6 : 1; - unsigned int g726_non_standard : 1; - unsigned int locally_held : 1; - unsigned int rtcp_mux: 1; - unsigned int ssrc: 1; + unsigned int bind_rtp_to_media_address:1; + unsigned int bind_udptl_to_media_address:1; + unsigned int rtp_symmetric:1; + unsigned int udptl_symmetric:1; + unsigned int rtp_ipv6:1; + unsigned int g726_non_standard:1; + unsigned int locally_held:1; + unsigned int rtcp_mux:1; + unsigned int ssrc:1; }; struct { unsigned int tos_audio; @@ -52,6 +51,7 @@ struct ast_sdp_options { unsigned int cos_video; unsigned int udptl_far_max_datagram; }; + enum ast_sdp_options_dtmf dtmf; enum ast_sdp_options_ice ice; enum ast_sdp_options_impl impl; enum ast_sdp_options_encryption encryption; diff --git a/main/sdp_state.c b/main/sdp_state.c index 953f90c364d..3a87a81e23b 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -178,9 +178,11 @@ static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options ice->stop(rtp); } - if (options->telephone_event) { + if (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO) { ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); + } else if (options->dtmf == AST_SDP_DTMF_INBAND) { + ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_INBAND); } if (media_type == AST_MEDIA_TYPE_AUDIO && @@ -1257,7 +1259,6 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s ast_assert(sdp && options && stream); - media_type = ast_stream_get_type(stream); if (rtp) { if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_rtp)) { return -1; @@ -1300,31 +1301,24 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s ao2_ref(format, -1); } - if (rtp && media_type != AST_MEDIA_TYPE_VIDEO) { - for (i = 1LL; i <= AST_RTP_MAX; i <<= 1) { - if (!(options->telephone_event & i)) { - continue; - } - - rtp_code = ast_rtp_codecs_payload_code( - ast_rtp_instance_get_codecs(rtp), 0, NULL, i); - if (rtp_code == -1) { - continue; - } - + media_type = ast_stream_get_type(stream); + if (rtp && media_type != AST_MEDIA_TYPE_VIDEO + && (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO)) { + i = AST_RTP_DTMF; + rtp_code = ast_rtp_codecs_payload_code( + ast_rtp_instance_get_codecs(rtp), 0, NULL, i); + if (-1 < rtp_code) { if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) { ast_sdp_m_free(m_line); return -1; } - if (i == AST_RTP_DTMF) { - snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); - a_line = ast_sdp_a_alloc("fmtp", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); + a_line = ast_sdp_a_alloc("fmtp", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; } } } From 675e058e7794f15a4729093a165a0a66abb5d9f9 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 2 May 2017 12:34:24 -0400 Subject: [PATCH 1238/1578] cleanup: Change severity of fread short-read warning Many sound files don't have a full frame's worth of data at EOF, so the warning messages were a bit too noisy. So we demote them to debug messages. Change-Id: I6b617467d687658adca39170a81797a11cc766f6 --- formats/format_g719.c | 6 +++--- formats/format_g723.c | 6 +++--- formats/format_g726.c | 6 +++--- formats/format_g729.c | 6 +++--- formats/format_gsm.c | 6 +++--- formats/format_h263.c | 6 +++--- formats/format_h264.c | 6 +++--- formats/format_ilbc.c | 6 +++--- formats/format_pcm.c | 6 +++--- formats/format_siren14.c | 6 +++--- formats/format_siren7.c | 6 +++--- formats/format_sln.c | 6 +++--- formats/format_vox.c | 6 +++--- formats/format_wav.c | 6 +++--- formats/format_wav_gsm.c | 6 +++--- 15 files changed, 45 insertions(+), 45 deletions(-) diff --git a/formats/format_g719.c b/formats/format_g719.c index 572b88f5f7c..3b2195a30b8 100644 --- a/formats/format_g719.c +++ b/formats/format_g719.c @@ -47,9 +47,9 @@ static struct ast_frame *g719read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_g723.c b/formats/format_g723.c index d4c4d4b1c9e..fff6ed07bbc 100644 --- a/formats/format_g723.c +++ b/formats/format_g723.c @@ -67,9 +67,9 @@ static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_g726.c b/formats/format_g726.c index 7da6d1ecbb3..33f9639537a 100644 --- a/formats/format_g726.c +++ b/formats/format_g726.c @@ -126,9 +126,9 @@ static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_g729.c b/formats/format_g729.c index 4cefc0401c3..1e523062edb 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -53,9 +53,9 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_gsm.c b/formats/format_gsm.c index 39deb983e37..b737c97e5fe 100644 --- a/formats/format_gsm.c +++ b/formats/format_gsm.c @@ -59,9 +59,9 @@ static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), GSM_FRAME_SIZE, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), GSM_FRAME_SIZE, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_h263.c b/formats/format_h263.c index d05e598254a..586e2d8e548 100644 --- a/formats/format_h263.c +++ b/formats/format_h263.c @@ -87,9 +87,9 @@ static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_h264.c b/formats/format_h264.c index 47f71ae6cc2..9230129e7ed 100644 --- a/formats/format_h264.c +++ b/formats/format_h264.c @@ -79,9 +79,9 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c index ec8ad0ffa6f..8b41ab22874 100644 --- a/formats/format_ilbc.c +++ b/formats/format_ilbc.c @@ -51,9 +51,9 @@ static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_pcm.c b/formats/format_pcm.c index f5ddda9c61a..4891f7ed5b2 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -86,9 +86,9 @@ static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_siren14.c b/formats/format_siren14.c index d54ed993bc3..e15e20f465e 100644 --- a/formats/format_siren14.c +++ b/formats/format_siren14.c @@ -47,9 +47,9 @@ static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_siren7.c b/formats/format_siren7.c index f3b4b42b3c1..298992c3ca0 100644 --- a/formats/format_siren7.c +++ b/formats/format_siren7.c @@ -47,9 +47,9 @@ static struct ast_frame *siren7read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_sln.c b/formats/format_sln.c index 1977f7dc06d..5a5cde77708 100644 --- a/formats/format_sln.c +++ b/formats/format_sln.c @@ -41,9 +41,9 @@ static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, u if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_vox.c b/formats/format_vox.c index 195714c6f00..c3da4ab9419 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -47,9 +47,9 @@ static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_wav.c b/formats/format_wav.c index 09e6a5313fd..ce8a8bf0ab5 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -394,9 +394,9 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext) if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c index bfec903d077..8d7d87f6579 100644 --- a/formats/format_wav_gsm.c +++ b/formats/format_wav_gsm.c @@ -424,9 +424,9 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext) if ((res = fread(msdata, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) { if (feof(s->f)) { if (res) { - ast_log(LOG_WARNING, "Incomplete frame data at end of %s file " - "(expected %d bytes, read %d)\n", - ast_format_get_name(s->fr.subclass.format), MSGSM_FRAME_SIZE, res); + ast_debug(3, "Incomplete frame data at end of %s file " + "(expected %d bytes, read %d)\n", + ast_format_get_name(s->fr.subclass.format), MSGSM_FRAME_SIZE, res); } } else { ast_log(LOG_ERROR, "Error while reading %s file: %s\n", From 008e25def96eaf58ccaef2276eb0cb36ff4b67bf Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 1 May 2017 13:04:16 -0500 Subject: [PATCH 1239/1578] res_rtp_asterisk: Clearing the remote RTCP address causes RTCP failures When a call gets put on hold RTP is temporarily stopped and Asterisk was setting the remote RTCP address to NULL. Then when RTCP data was received from the remote endpoint, Asterisk would be missing this information when publishing the rtcp_message stasis event. Consequently, message subscribers (in this case res_hep_rtcp) trying to parse the "from" field output the following error: "ast_sockaddr_split_hostport: Port missing in (null)" This patch makes it so the remote RTCP address is no longer set to NULL when stopping RTP. There was only one place that appeared to check if the remote RTCP address was NULL as a way to tell if RTCP was running. This patch added an additional check on the RTCP schedid for that case to make sure RTCP was truly not running. ASTERISK-26860 #close Change-Id: I6be200fb20db647e48b5138ea4b81dfa7962974b --- res/res_rtp_asterisk.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 85e2425cbfd..f7e97627286 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -3908,7 +3908,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr return 0; } - if (ast_sockaddr_isnull(&rtp->rtcp->them)) { + if (ast_sockaddr_isnull(&rtp->rtcp->them) || rtp->rtcp->schedid < 0) { /* * RTCP was stopped. */ @@ -5527,21 +5527,20 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct } } - if (rtp->rtcp) { + if (rtp->rtcp && !ast_sockaddr_isnull(addr)) { ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance); ast_sockaddr_copy(&rtp->rtcp->them, addr); - if (!ast_sockaddr_isnull(addr)) { - if (rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { - ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1); - /* Update the local RTCP address with what is being used */ - ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1); - } - ast_sockaddr_copy(&rtp->rtcp->us, &local); + if (rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { + ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1); - ast_free(rtp->rtcp->local_addr_str); - rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local)); + /* Update the local RTCP address with what is being used */ + ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1); } + ast_sockaddr_copy(&rtp->rtcp->us, &local); + + ast_free(rtp->rtcp->local_addr_str); + rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local)); } rtp->rxseqno = 0; @@ -5751,9 +5750,6 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance) } ast_rtp_instance_set_remote_address(instance, &addr); - if (rtp->rtcp) { - ast_sockaddr_setnull(&rtp->rtcp->them); - } ast_set_flag(rtp, FLAG_NEED_MARKER_BIT); } From 7b0e3b92fd49e5fbe406ef74336e164eb3f31b6e Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 25 Apr 2017 11:49:16 -0500 Subject: [PATCH 1240/1578] bridge_simple: Added support for streams This patch is the first cut at adding stream support to the bridging framework. Changes were made to the framework that allows mapping of stream topologies to a bridge's supported media types. The first channel to enter a bridge initially defines the media types for a bridge (i.e. a one to one mapping is created between the bridge and the first channel). Subsequently added channels merge their media types into the bridge's adding to it when necessary. This allows channels with different sized topologies to map correctly to each other according to media type. The bridge drops any frame that does not have a matching index into a given write stream. For now though, bridge_simple will align its two channels according to size or first to join. Once both channels join the bridge the one with the most streams will indicate to the other channel to update its streams to be the same as that of the other. If both channels have the same number of streams then the first channel to join is chosen as the stream base. A topology change source was also added to a channel when a stream toplogy change request is made. This allows subsystems to know whether or not they initiated a change request. Thus avoiding potential recursive situations. ASTERISK-26966 #close Change-Id: I1eb5987921dd80c3cdcf52accc136393ca2d4163 --- bridges/bridge_simple.c | 38 ++++++++++- include/asterisk/bridge.h | 3 + include/asterisk/bridge_channel.h | 27 ++++++++ include/asterisk/bridge_technology.h | 19 ++++++ include/asterisk/channel.h | 13 +++- include/asterisk/channel_internal.h | 2 + include/asterisk/stream.h | 23 +++++++ main/bridge.c | 11 ++++ main/bridge_channel.c | 59 ++++++++++++++++- main/channel.c | 5 +- main/channel_internal_api.c | 12 ++++ main/stream.c | 45 +++++++++++++ tests/test_stream.c | 97 +++++++++++++++++++++++++++- 13 files changed, 348 insertions(+), 6 deletions(-) diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index 35544f84fac..47f41cbb3b3 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -42,6 +42,10 @@ #include "asterisk/bridge.h" #include "asterisk/bridge_technology.h" #include "asterisk/frame.h" +#include "asterisk/stream.h" + +static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, + struct ast_bridge_channel *bridge_channel); static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { @@ -56,7 +60,13 @@ static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chann return 0; } - return ast_channel_make_compatible(c0, c1); + if (ast_channel_make_compatible(c0, c1)) { + return -1; + } + + /* Align stream topologies */ + simple_bridge_stream_topology_changed(bridge, NULL); + return 0; } static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) @@ -70,8 +80,34 @@ static struct ast_bridge_technology simple_bridge = { .preference = AST_BRIDGE_PREFERENCE_BASE_1TO1MIX, .join = simple_bridge_join, .write = simple_bridge_write, + .stream_topology_changed = simple_bridge_stream_topology_changed, }; +static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, + struct ast_bridge_channel *bridge_channel) +{ + struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan; + struct ast_channel *c1 = AST_LIST_LAST(&bridge->channels)->chan; + struct ast_stream_topology *t0 = ast_channel_get_stream_topology(c0); + struct ast_stream_topology *t1 = ast_channel_get_stream_topology(c1); + + /* + * The bridge_channel should only be NULL after both channels join + * the bridge and their topologies are being aligned. + */ + if (bridge_channel && ast_channel_get_stream_topology_change_source( + bridge_channel->chan) == &simple_bridge) { + return; + } + + /* Align topologies according to size or first channel to join */ + if (ast_stream_topology_get_count(t0) < ast_stream_topology_get_count(t1)) { + ast_channel_request_stream_topology_change(c0, t1, &simple_bridge); + } else { + ast_channel_request_stream_topology_change(c1, t0, &simple_bridge); + } +} + static int unload_module(void) { ast_bridge_technology_unregister(&simple_bridge); diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index ffe08da13ef..a9b01a6bbec 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -323,6 +323,9 @@ struct ast_bridge { /*! Immutable bridge UUID. */ AST_STRING_FIELD(uniqueid); ); + + /*! Type mapping used for media routing */ + struct ast_vector_int media_types; }; /*! \brief Bridge base class virtual method table. */ diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index a7971df27f2..dd72f3275fc 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -183,6 +183,12 @@ struct ast_bridge_channel { unsigned int padding:30; }; }; + struct { + /*! An index mapping of where a channel's media needs to be routed */ + struct ast_vector_int to_bridge; + /*! An index mapping of where a bridge's media needs to be routed */ + struct ast_vector_int to_channel; + } stream_map; }; /*! @@ -704,6 +710,27 @@ void ast_bridge_channel_feature_digit_add(struct ast_bridge_channel *bridge_chan */ void ast_bridge_channel_feature_digit(struct ast_bridge_channel *bridge_channel, int digit); +/*! + * \brief Maps a channel's stream topology to and from the bridge + * \since 15.0.0 + * + * When a channel joins a bridge or its associated stream topology is updated, each stream + * in the topology needs to be mapped according to its media type to the bridge. Calling + * this method creates a mapping of each stream on the channel indexed to the bridge's + * supported media types and vice versa (i.e. bridge's media types indexed to channel + * streams). + * + * The first channel to join the bridge creates the initial order for the bridge's media + * types (e.g. a one to one mapping is made). Subsequently added channels are mapped to + * that order adding more media types if/when the newly added channel has more streams + * and/or media types specified by the bridge. + * + * \param bridge_channel Channel to map + * + * \return Nothing + */ +void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridge_technology.h index 843d93ccfc6..09b0fc0e8d8 100644 --- a/include/asterisk/bridge_technology.h +++ b/include/asterisk/bridge_technology.h @@ -158,6 +158,25 @@ struct ast_bridge_technology { * \note On entry, bridge is already locked. */ int (*write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame); + /*! + * \brief Callback for when a request has been made to change a stream topology on a channel + * + * This is called when a bridge receives a request to change the topology on the channel. A bridge + * technology should define a handler for this callback if it needs to update internals or intercept + * the request and not pass it on to other channels. This can be done by returning a nonzero value. + * + * \retval 0 Frame accepted by the bridge. + * \retval -1 Frame rejected. + */ + int (*stream_topology_request_change)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); + /*! + * \brief Callback for when a stream topology changes on the channel + * + * This is called when a bridge receives an indication that a topology has been changed on a channel + * and the new topology has been mapped to the bridge. A bridge technology should define a handler for + * this callback if it needs to update internals due to a channel's topology changing. + */ + void (*stream_topology_changed)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); /*! TRUE if the bridge technology is currently suspended. */ unsigned int suspended:1; /*! Module this bridge technology belongs to. It is used for reference counting bridges using the technology. */ diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 128cd3056c9..889d3ff07e1 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4904,6 +4904,7 @@ int ast_channel_is_multistream(struct ast_channel *chan); * * \param chan The channel to change * \param topology The new stream topology + * \param change_source The source that initiated the change * * \pre chan is locked * @@ -4918,7 +4919,8 @@ int ast_channel_is_multistream(struct ast_channel *chan); * \note This interface is provided for applications and resources to request that the topology change. * It is not for use by the channel driver itself. */ -int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology); +int ast_channel_request_stream_topology_change(struct ast_channel *chan, + struct ast_stream_topology *topology, void *change_source); /*! * \brief Provide notice to a channel that the stream topology has changed @@ -4936,4 +4938,13 @@ int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct */ int ast_channel_stream_topology_changed(struct ast_channel *chan, struct ast_stream_topology *topology); +/*! + * \brief Retrieve the source that initiated the last stream topology change + * + * \param chan The channel + * + * \retval The channel's stream topology change source + */ +void *ast_channel_get_stream_topology_change_source(struct ast_channel *chan); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h index 3de2b14aa1c..dd791a4169c 100644 --- a/include/asterisk/channel_internal.h +++ b/include/asterisk/channel_internal.h @@ -29,5 +29,7 @@ void ast_channel_internal_errno_set(enum ast_channel_error error); enum ast_channel_error ast_channel_internal_errno(void); void ast_channel_internal_set_stream_topology(struct ast_channel *chan, struct ast_stream_topology *topology); +void ast_channel_internal_set_stream_topology_change_source( + struct ast_channel *chan, void *change_source); void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1, struct ast_channel *chan2); diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 1e07407a9f8..1bb34b72a27 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -27,6 +27,7 @@ #define _AST_STREAM_H_ #include "asterisk/codec.h" +#include "asterisk/vector.h" /*! * \brief Forward declaration for a stream, as it is opaque @@ -43,6 +44,11 @@ struct ast_format_cap; */ struct ast_stream_topology; +/*! + * \brief A mapping of two topologies. + */ +struct ast_stream_topology_map; + typedef void (*ast_stream_data_free_fn)(void *); /*! @@ -405,4 +411,21 @@ struct ast_stream *ast_stream_topology_get_first_stream_by_type( const struct ast_stream_topology *topology, enum ast_media_type type); +/*! + * \brief Map a given topology's streams to the given types. + * + * \note The given vectors in which mapping values are placed are reset by + * this function. This means if those vectors already contain mapping + * values they will be lost. + * + * \param topology The topology to map + * \param types The media types to be mapped + * \param v0 Index mapping of topology to types + * \param v1 Index mapping of types to topology + * + * \since 15 + */ +void ast_stream_topology_map(const struct ast_stream_topology *topology, + struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1); + #endif /* _AST_STREAM_H */ diff --git a/main/bridge.c b/main/bridge.c index d40c3ec9ac9..9d9a3118bbe 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -440,6 +440,13 @@ static void bridge_channel_complete_join(struct ast_bridge *bridge, struct ast_b } bridge_channel->just_joined = 0; + + /* + * When a channel joins the bridge its streams need to be mapped to the bridge's + * media types vector. This way all streams map to the same media type index for + * a given channel. + */ + ast_bridge_channel_stream_map(bridge_channel); } /*! @@ -689,6 +696,8 @@ static void destroy_bridge(void *obj) bridge->technology = NULL; } + AST_VECTOR_FREE(&bridge->media_types); + bridge->callid = 0; cleanup_video_mode(bridge); @@ -744,6 +753,8 @@ struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_ bridge->v_table = v_table; + AST_VECTOR_INIT(&bridge->media_types, AST_MEDIA_TYPE_END); + return bridge; } diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 89222d365e7..4f166fff06f 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -55,6 +55,7 @@ #include "asterisk/causes.h" #include "asterisk/test.h" #include "asterisk/sem.h" +#include "asterisk/stream.h" /*! * \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge. @@ -982,6 +983,16 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st return 0; } + if (ast_channel_is_multistream(bridge_channel->chan) && + (fr->frametype == AST_FRAME_IMAGE || fr->frametype == AST_FRAME_TEXT || + fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_VOICE)) { + /* Media frames need to be mapped to an appropriate write stream */ + dup->stream_num = AST_VECTOR_GET( + &bridge_channel->stream_map.to_bridge, fr->stream_num); + } else { + dup->stream_num = -1; + } + AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list); if (ast_alertpipe_write(bridge_channel->alert_pipe)) { ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n", @@ -2249,6 +2260,9 @@ static void bridge_channel_handle_control(struct ast_bridge_channel *bridge_chan /* Should never happen. */ ast_assert(0); break; + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); + break; default: ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); break; @@ -2268,6 +2282,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe { struct ast_frame *fr; struct sync_payload *sync_payload; + int num; ast_bridge_channel_lock(bridge_channel); @@ -2324,9 +2339,18 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe case AST_FRAME_NULL: break; default: + if (fr->stream_num >= (int)AST_VECTOR_SIZE(&bridge_channel->stream_map.to_channel)) { + /* Nowhere to write to, so drop it */ + break; + } + + /* Find what stream number to write to for the channel */ + num = fr->stream_num < 0 ? -1 : + AST_VECTOR_GET(&bridge_channel->stream_map.to_channel, fr->stream_num); + /* Write the frame to the channel. */ bridge_channel->activity = BRIDGE_CHANNEL_THREAD_SIMPLE; - ast_write(bridge_channel->chan, fr); + ast_write_stream(bridge_channel->chan, num, fr); break; } bridge_frame_free(fr); @@ -2435,6 +2459,27 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) case AST_CONTROL_ANSWER: ast_channel_publish_dial(NULL, bridge_channel->chan, NULL, controls[frame->subclass.integer]); break; + case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: + if (bridge_channel->bridge->technology->stream_topology_request_change && + bridge_channel->bridge->technology->stream_topology_request_change( + bridge_channel->bridge, bridge_channel)) { + /* Topology change was denied so drop frame */ + bridge_frame_free(frame); + return; + } + break; + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + /* + * If a stream topology has changed then the bridge_channel's + * media mapping needs to be updated. + */ + ast_bridge_channel_stream_map(bridge_channel); + + if (bridge_channel->bridge->technology->stream_topology_changed) { + bridge_channel->bridge->technology->stream_topology_changed( + bridge_channel->bridge, bridge_channel); + } + break; default: break; } @@ -2885,6 +2930,9 @@ static void bridge_channel_destroy(void *obj) ao2_cleanup(bridge_channel->write_format); ao2_cleanup(bridge_channel->read_format); + + AST_VECTOR_FREE(&bridge_channel->stream_map.to_bridge); + AST_VECTOR_FREE(&bridge_channel->stream_map.to_channel); } struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *bridge) @@ -2905,5 +2953,14 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid ao2_ref(bridge_channel->bridge, +1); } + /* The stream_map is initialized later - see ast_bridge_channel_stream_map */ + return bridge_channel; } + +void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel) +{ + ast_stream_topology_map(ast_channel_get_stream_topology(bridge_channel->chan), + &bridge_channel->bridge->media_types, &bridge_channel->stream_map.to_bridge, + &bridge_channel->stream_map.to_channel); +} diff --git a/main/channel.c b/main/channel.c index e37d6652557..dbf2354995b 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10909,7 +10909,8 @@ enum ast_channel_error ast_channel_errno(void) return ast_channel_internal_errno(); } -int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology) +int ast_channel_request_stream_topology_change(struct ast_channel *chan, + struct ast_stream_topology *topology, void *change_source) { ast_assert(chan != NULL); ast_assert(topology != NULL); @@ -10918,6 +10919,8 @@ int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct return -1; } + ast_channel_internal_set_stream_topology_change_source(chan, change_source); + return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, topology, sizeof(topology)); } diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 7f32b219665..5e7df8983a7 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -219,6 +219,7 @@ struct ast_channel { struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */ struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */ struct ast_stream_topology *stream_topology; /*!< Stream topology */ + void *stream_topology_change_source; /*!< Source that initiated a stream topology change */ struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */ }; @@ -838,6 +839,17 @@ void ast_channel_internal_set_stream_topology(struct ast_channel *chan, channel_set_default_streams(chan); } +void ast_channel_internal_set_stream_topology_change_source( + struct ast_channel *chan, void *change_source) +{ + chan->stream_topology_change_source = change_source; +} + +void *ast_channel_get_stream_topology_change_source(struct ast_channel *chan) +{ + return chan->stream_topology_change_source; +} + void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value) { diff --git a/main/stream.c b/main/stream.c index 39b6b1b13f6..0f239335900 100644 --- a/main/stream.c +++ b/main/stream.c @@ -434,3 +434,48 @@ struct ast_stream *ast_stream_topology_get_first_stream_by_type( return NULL; } + +void ast_stream_topology_map(const struct ast_stream_topology *topology, + struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1) +{ + int i; + int nths[AST_MEDIA_TYPE_END] = {0}; + int size = ast_stream_topology_get_count(topology); + + /* + * Clear out any old mappings and initialize the new ones + */ + AST_VECTOR_FREE(v0); + AST_VECTOR_FREE(v1); + + /* + * Both vectors are sized to the topology. The media types vector is always + * guaranteed to be the size of the given topology or greater. + */ + AST_VECTOR_INIT(v0, size); + AST_VECTOR_INIT(v1, size); + + for (i = 0; i < size; ++i) { + struct ast_stream *stream = ast_stream_topology_get_stream(topology, i); + enum ast_media_type type = ast_stream_get_type(stream); + int index = AST_VECTOR_GET_INDEX_NTH(types, ++nths[type], + type, AST_VECTOR_ELEM_DEFAULT_CMP); + + if (index == -1) { + /* + * If a given type is not found for an index level then update the + * media types vector with that type. This keeps the media types + * vector always at the max topology size. + */ + AST_VECTOR_APPEND(types, type); + index = AST_VECTOR_SIZE(types) - 1; + } + + /* + * The mapping is reflexive in the sense that if it maps in one direction + * then the reverse direction maps back to the other's index. + */ + AST_VECTOR_REPLACE(v0, i, index); + AST_VECTOR_REPLACE(v1, index, i); + } +} diff --git a/tests/test_stream.c b/tests/test_stream.c index 7eecf373bab..a2a97018109 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -1592,7 +1592,7 @@ AST_TEST_DEFINE(stream_topology_change_request_from_application_non_multistream) topology = ast_stream_topology_alloc(); ast_test_validate_cleanup(test, topology, res, done); - change_res = ast_channel_request_stream_topology_change(mock_channel, topology); + change_res = ast_channel_request_stream_topology_change(mock_channel, topology, NULL); ast_test_validate_cleanup(test, change_res == -1, res, done); ast_test_validate_cleanup(test, !pvt->indicated_change_request, res, done); @@ -1700,7 +1700,7 @@ AST_TEST_DEFINE(stream_topology_change_request_from_application) topology = ast_stream_topology_alloc(); ast_test_validate_cleanup(test, topology, res, done); - change_res = ast_channel_request_stream_topology_change(mock_channel, topology); + change_res = ast_channel_request_stream_topology_change(mock_channel, topology, NULL); ast_test_validate_cleanup(test, !change_res, res, done); ast_test_validate_cleanup(test, pvt->indicated_change_request, res, done); @@ -1830,6 +1830,97 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) return AST_TEST_PASS; } +#define topology_append_stream(topology, name, type, res, label) \ + do { \ + struct ast_stream *__stream = ast_stream_alloc((name), (type)); \ + ast_test_validate_cleanup(test, __stream, res, label); \ + if (ast_stream_topology_append_stream((topology), __stream) < 0) { \ + ast_stream_free(__stream); \ + res = AST_TEST_FAIL; \ + goto label; \ + } \ + } while(0) + +AST_TEST_DEFINE(stream_topology_map_create) +{ + RAII_VAR(struct ast_stream_topology *, t0, NULL, ast_stream_topology_free); + + struct ast_vector_int types = { NULL }; + struct ast_vector_int v0 = { NULL }; + struct ast_vector_int v1 = { NULL }; + + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_map_create"; + info->category = "/main/stream/"; + info->summary = "stream topology map creation unit test"; + info->description = + "Test that creating a stream topology map works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, AST_VECTOR_INIT(&types, 5) == 0); + + /* Map a first topology and check that it mapped one to one */ + ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done); + + ast_stream_topology_map(t0, &types, &v0, &v1); + ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 2, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 1, res, done); + + /* Map a second topology and check that it merged */ + ast_stream_topology_free(t0); + ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done); + topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + + ast_stream_topology_map(t0, &types, &v0, &v1); + ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 2, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 0, res, done); + + /* Map a third topology with more streams and check that it merged */ + ast_stream_topology_free(t0); + ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done); + topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + + ast_stream_topology_map(t0, &types, &v0, &v1); + ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 3, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 2) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 2) == 2, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 2) == 2, res, done); + +done: + AST_VECTOR_FREE(&v1); + AST_VECTOR_FREE(&v0); + AST_VECTOR_FREE(&types); + + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -1855,6 +1946,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_change_request_from_application); AST_TEST_UNREGISTER(stream_topology_change_request_from_channel); AST_TEST_UNREGISTER(format_cap_from_stream_topology); + AST_TEST_UNREGISTER(stream_topology_map_create); return 0; } @@ -1882,6 +1974,7 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_change_request_from_application); AST_TEST_REGISTER(stream_topology_change_request_from_channel); AST_TEST_REGISTER(format_cap_from_stream_topology); + AST_TEST_REGISTER(stream_topology_map_create); return AST_MODULE_LOAD_SUCCESS; } From c90d81ef5195c71db81ed69782d84ab357787516 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 30 Apr 2017 21:40:16 +0000 Subject: [PATCH 1241/1578] bridge: Fix returning to dialplan when executing Bridge() from AMI. When using the Bridge AMI action on the same channel multiple times it was possible for the channel to return to the wrong location in the dialplan if the other party hung up. This happened because the priority of the channel was not preserved across each action invocation and it would fail to move on to the next priority in other cases. This change makes it so that the priority of a channel is preserved when taking control of it from another thread and it is incremented as appropriate such that the priority reflects where the channel should next be executed in the dialplan, not where it may or may not currently be. The Bridge AMI action was also changed to ensure that it too starts the channels at the next location in the dialplan. ASTERISK-24529 Change-Id: I52406669cf64208aef7252a65b63ade31fbf7a5a --- include/asterisk/channel.h | 3 +++ main/channel.c | 12 ++++++++++++ main/features.c | 8 ++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 889d3ff07e1..fd339d97483 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4640,6 +4640,9 @@ struct ast_bridge_channel *ast_channel_get_bridge_channel(struct ast_channel *ch * * \note absolutely _NO_ channel locks should be held before calling this function. * + * \note The dialplan location on the returned channel is where the channel + * should be started in the dialplan if it is returned to it. + * * \param yankee The channel to gain control of * \retval NULL Could not gain control of the channel * \retval non-NULL The channel diff --git a/main/channel.c b/main/channel.c index dbf2354995b..099e6f65abb 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10566,6 +10566,7 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee) char *context; char *name; int amaflags; + int priority; struct ast_format *readformat; struct ast_format *writeformat; } my_vars = { 0, }; @@ -10576,6 +10577,16 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee) my_vars.context = ast_strdupa(ast_channel_context(yankee)); my_vars.name = ast_strdupa(ast_channel_name(yankee)); my_vars.amaflags = ast_channel_amaflags(yankee); + my_vars.priority = ast_channel_priority(yankee); + /* The priority as returned by ast_channel_yank is where the channel + * should go if the dialplan is executed on it. If the channel is + * already executing dialplan then the priority currently set is + * where it is currently. We increment it so it becomes where it should + * execute. + */ + if (ast_test_flag(ast_channel_flags(yankee), AST_FLAG_IN_AUTOLOOP)) { + my_vars.priority++; + } my_vars.writeformat = ao2_bump(ast_channel_writeformat(yankee)); my_vars.readformat = ao2_bump(ast_channel_readformat(yankee)); ast_channel_unlock(yankee); @@ -10595,6 +10606,7 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee) ast_channel_set_writeformat(yanked_chan, my_vars.writeformat); ao2_cleanup(my_vars.readformat); ao2_cleanup(my_vars.writeformat); + ast_channel_priority_set(yanked_chan, my_vars.priority); ast_channel_unlock(yanked_chan); diff --git a/main/features.c b/main/features.c index ae16374b2e0..61d9e511f5b 100644 --- a/main/features.c +++ b/main/features.c @@ -782,7 +782,7 @@ static int action_bridge(struct mansession *s, const struct message *m) chana_exten = ast_strdupa(ast_channel_exten(chana)); chana_context = ast_strdupa(ast_channel_context(chana)); chana_priority = ast_channel_priority(chana); - if (!ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) { + if (ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) { chana_priority++; } ast_channel_unlock(chana); @@ -798,7 +798,7 @@ static int action_bridge(struct mansession *s, const struct message *m) chanb_exten = ast_strdupa(ast_channel_exten(chanb)); chanb_context = ast_strdupa(ast_channel_context(chanb)); chanb_priority = ast_channel_priority(chanb); - if (!ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) { + if (ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) { chanb_priority++; } ast_channel_unlock(chanb); @@ -809,7 +809,7 @@ static int action_bridge(struct mansession *s, const struct message *m) return 0; } - ast_bridge_set_after_go_on(chana, chana_context, chana_exten, chana_priority, NULL); + ast_bridge_set_after_goto(chana, chana_context, chana_exten, chana_priority); if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) { snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana)); astman_send_error(s, m, buf); @@ -817,7 +817,7 @@ static int action_bridge(struct mansession *s, const struct message *m) return 0; } - ast_bridge_set_after_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL); + ast_bridge_set_after_goto(chanb, chanb_context, chanb_exten, chanb_priority); if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) { snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb)); astman_send_error(s, m, buf); From 000183415717adae0c5ce1dd015213e7ee286dd4 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 4 May 2017 15:04:46 -0600 Subject: [PATCH 1242/1578] app_confbridge: Fix reference to cfg in menu_template_handler menu_template_handler wasn't properly accounting for the fact that it might be called both during a load/reload (which isn't really valid but not prevented) and by a dialplan function. In both cases it was attempting to use the "pending" config which wasn't valid in the latter case. aco_process_config is also partly to blame because it wasn't properly cleaning "pending" up when a reload was done and no changes were made. Both of these contributed to a crash if CONFBRIDGE(menu,template) was called in a dialplan after a reload. * aco_process_config now sets info->internal->pending to NULL after it unrefs it although this isn't strictly necessary in the context of this fix. * menu_template_handler now uses the "current" config and silently ignores any attempt to be called as a result of someone uses the "template" parameter in the conf file. Luckily there's no other place in the codebase where aco_pending_config is used outside of aco_process_config. ASTERISK-25506 #close Reported-by: Frederic LE FOLL Change-Id: Ib349a17d3d088f092480b19addd7122fcaac21a7 --- apps/confbridge/conf_config_parser.c | 4 +++- main/config_options.c | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 4729139c209..3e4075ba94d 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -2077,7 +2077,7 @@ static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src) static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct conf_menu *dst_menu = obj; - struct confbridge_cfg *cfg = aco_pending_config(&cfg_info); + RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup); RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup); if (!cfg) { @@ -2112,6 +2112,7 @@ static int verify_default_profiles(void) RAII_VAR(struct user_profile *, user_profile, NULL, ao2_cleanup); RAII_VAR(struct bridge_profile *, bridge_profile, NULL, ao2_cleanup); RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup); + /* We can only be called as a result of an aco_process_config so this is safe */ struct confbridge_cfg *cfg = aco_pending_config(&cfg_info); if (!cfg) { @@ -2213,6 +2214,7 @@ int conf_load_config(void) /* Menu options */ aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0); + /* This option should only be used with the CONFBRIDGE dialplan function */ aco_option_register_custom(&cfg_info, "template", ACO_EXACT, menu_types, NULL, menu_template_handler, 0); aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0); diff --git a/main/config_options.c b/main/config_options.c index 18b04ff7dcf..c8077790623 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -586,10 +586,13 @@ enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco }; ao2_cleanup(info->internal->pending); + info->internal->pending = NULL; return ACO_PROCESS_OK; error: ao2_cleanup(info->internal->pending); + info->internal->pending = NULL; + return ACO_PROCESS_ERROR; } @@ -702,6 +705,8 @@ enum aco_process_status aco_process_config(struct aco_info *info, int reload) end: ao2_cleanup(info->internal->pending); + info->internal->pending = NULL; + return res; } int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj) From 4146facfec4366b406197746dab0fb69799690bd Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 5 May 2017 13:48:34 +0000 Subject: [PATCH 1243/1578] func_cdr: Allow empty value for CDR dialplan function. A regression was introduced in 12 where passing an empty value to the CDR dialplan function was not longer allowed. This change returns to the behavior of 11 where it is permitted. ASTERISK-26173 Change-Id: I3f148203b54ec088007e29e30005a5de122e51c5 --- funcs/func_cdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 82ff488b047..219e0042987 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -377,7 +377,7 @@ static void cdr_write_callback(void *data, struct stasis_subscription *sub, stru payload->cmd, payload->cmd); return; } - if (ast_strlen_zero(payload->value)) { + if (!payload->value) { ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)", payload->cmd, payload->cmd); return; From 924628812b68e01cf7506b44b292e6057716f77a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 4 May 2017 17:32:03 -0500 Subject: [PATCH 1244/1578] netsock2.c: Made get/set addr port avoid potential uninitialized memory. Change-Id: I532052bd7cd95a4b3565485fc01e2a1ea07ee647 --- main/netsock2.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/main/netsock2.c b/main/netsock2.c index bfa181c86cb..8fb9c9e56a4 100644 --- a/main/netsock2.c +++ b/main/netsock2.c @@ -431,11 +431,16 @@ int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockadd uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, int line, const char *func) { - if (addr->ss.ss_family == AF_INET && - addr->len == sizeof(struct sockaddr_in)) { + /* + * Test addr->len first to be tolerant of an ast_sockaddr_setnull() + * addr. In that case addr->len might be the only value initialized. + */ + if (addr->len == sizeof(struct sockaddr_in) + && addr->ss.ss_family == AF_INET) { return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port); - } else if (addr->ss.ss_family == AF_INET6 && - addr->len == sizeof(struct sockaddr_in6)) { + } + if (addr->len == sizeof(struct sockaddr_in6) + && addr->ss.ss_family == AF_INET6) { return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port); } if (option_debug >= 1) { @@ -446,11 +451,15 @@ uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, i void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char *file, int line, const char *func) { - if (addr->ss.ss_family == AF_INET && - addr->len == sizeof(struct sockaddr_in)) { + /* + * Test addr->len first to be tolerant of an ast_sockaddr_setnull() + * addr. In that case addr->len might be the only value initialized. + */ + if (addr->len == sizeof(struct sockaddr_in) + && addr->ss.ss_family == AF_INET) { ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port); - } else if (addr->ss.ss_family == AF_INET6 && - addr->len == sizeof(struct sockaddr_in6)) { + } else if (addr->len == sizeof(struct sockaddr_in6) + && addr->ss.ss_family == AF_INET6) { ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port); } else if (option_debug >= 1) { ast_log(__LOG_DEBUG, file, line, func, From 56c5c51076ac75e25130083d1358160cd27b0b8f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 2 May 2017 18:05:01 -0500 Subject: [PATCH 1245/1578] stream: ast_stream_clone() cannot copy the opaque user data. ast_stream_clone() cannot copy the opaque user data stored on a stream. We don't know how to clone the data so it isn't copied into the clone. Change-Id: Ia51321bf38ecbfdcc53787ca77ea5fd2cabdf367 --- include/asterisk/stream.h | 2 +- main/stream.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 1bb34b72a27..821ecec030d 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -126,7 +126,7 @@ void ast_stream_free(struct ast_stream *stream); * \retval NULL failure * * \note Opaque data pointers set with ast_stream_set_data() are not part - * of the deep clone. The pointers are simply copied. + * of the deep clone. We have no way to clone the data. * * \since 15 */ diff --git a/main/stream.c b/main/stream.c index 0f239335900..804a0b8eeda 100644 --- a/main/stream.c +++ b/main/stream.c @@ -99,6 +99,7 @@ struct ast_stream *ast_stream_clone(const struct ast_stream *stream) { struct ast_stream *new_stream; size_t stream_size; + int idx; if (!stream) { return NULL; @@ -115,6 +116,12 @@ struct ast_stream *ast_stream_clone(const struct ast_stream *stream) ao2_ref(new_stream->formats, +1); } + /* We cannot clone the opaque data because we don't know how. */ + for (idx = 0; idx < AST_STREAM_DATA_SLOT_MAX; ++idx) { + new_stream->data[idx] = NULL; + new_stream->data_free_fn[idx] = NULL; + } + return new_stream; } From 201346fb7dff373d73a0663d1b05d968685013c7 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 8 May 2017 15:11:19 -0600 Subject: [PATCH 1246/1578] logger: Added logger_queue_limit to the configuration options. All log messages go to a queue serviced by a single thread which does all the IO. This setting controls how big that queue can get (and therefore how much memory is allocated) before new messages are discarded. The default is 1000. Should something go bezerk and log tons of messages in a tight loop, this will prevent memory escalation. When the limit is reached, a WARNING is logged to that effect and messages are discarded until the queue is empty again. At that time another WARNING will be logged with the count of discarded messages. There's no "low water mark" for this queue because the logger thread empties the entire queue and processes it in 1 batch before going back and waiting on the queue again. Implementing a low water mark would mean additional locking as the thread processes each message and it's not worth it. A "test" was added to test_logger.c but since the outcome is non-deterministic, it's really just a cli command, not a unit test. Change-Id: Ib4520c95e1ca5325dbf584c7989ce391649836d1 --- CHANGES | 9 ++ configs/samples/logger.conf.sample | 8 ++ include/asterisk/logger.h | 16 +++ main/logger.c | 187 ++++++++++++++++++++--------- tests/test_logger.c | 67 +++++++++++ 5 files changed, 228 insertions(+), 59 deletions(-) diff --git a/CHANGES b/CHANGES index 9c8ed5b8e77..7723ab3ebd3 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,15 @@ res_rtp_asterisk for a response that can never come until we give up on the response. Multiple subnets may be listed. +Logging +------------------- + * Added logger_queue_limit to the configuration options. + All log messages go to a queue serviced by a single thread + which does all the IO. This setting controls how big that + queue can get (and therefore how much memory is allocated) + before new messages are discarded. + The default is 1000. + res_pjsip_config_wizard ------------------ * Two new parameters have been added to the pjsip config wizard. diff --git a/configs/samples/logger.conf.sample b/configs/samples/logger.conf.sample index b504467ec69..e5f0c551a76 100644 --- a/configs/samples/logger.conf.sample +++ b/configs/samples/logger.conf.sample @@ -78,6 +78,14 @@ ; Directory for log files is configures in asterisk.conf ; option astlogdir ; +; All log messages go to a queue serviced by a single thread +; which does all the IO. This setting controls how big that +; queue can get (and therefore how much memory is allocated) +; before new messages are discarded. +; The default is 1000 +;logger_queue_limit = 250 +; +; [logfiles] ; ; Format is: diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index 2f629dfbef5..849f986b3dd 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -507,6 +507,22 @@ void ast_verb_console_set(int verb_level); */ int ast_is_logger_initialized(void); +/*! + * \brief Set the maximum number of messages allowed in the processing queue + * + * \param queue_limit + * + * \return Nothing + */ +void ast_logger_set_queue_limit(int queue_limit); + +/*! + * \brief Get the maximum number of messages allowed in the processing queue + * + * \return Queue limit + */ +int ast_logger_get_queue_limit(void); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/logger.c b/main/logger.c index 8c8162d718d..6060b3c4d2b 100644 --- a/main/logger.c +++ b/main/logger.c @@ -86,6 +86,11 @@ static int display_callids; AST_THREADSTORAGE(unique_callid); +static int logger_queue_size; +static int logger_queue_limit = 1000; +static int logger_messages_discarded; +static unsigned int high_water_alert; + static enum rotatestrategy { NONE = 0, /* Do not rotate log files at all, instead rely on external mechanisms */ SEQUENTIAL = 1 << 0, /* Original method - create a new file, in order */ @@ -719,6 +724,16 @@ static int init_logger_chain(const char *altconf) fprintf(stderr, "rotatetimestamp option has been deprecated. Please use rotatestrategy instead.\n"); } } + if ((s = ast_variable_retrieve(cfg, "general", "logger_queue_limit"))) { + if (sscanf(s, "%30d", &logger_queue_limit) != 1) { + fprintf(stderr, "logger_queue_limit has an invalid value. Leaving at default of %d.\n", + logger_queue_limit); + } + if (logger_queue_limit < 10) { + fprintf(stderr, "logger_queue_limit must be >= 10. Setting to 10.\n"); + logger_queue_limit = 10; + } + } var = ast_variable_browse(cfg, "logfiles"); for (; var; var = var->next) { @@ -1297,6 +1312,7 @@ static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struc case CLI_GENERATE: return NULL; } + ast_cli(a->fd, "Logger queue limit: %d\n\n", logger_queue_limit); ast_cli(a->fd, FORMATL, "Channel", "Type", "Formatter", "Status"); ast_cli(a->fd, "Configuration\n"); ast_cli(a->fd, FORMATL, "-------", "----", "---------", "------"); @@ -1585,6 +1601,79 @@ static void logger_print_normal(struct logmsg *logmsg) return; } +static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message_ap(int level, + int sublevel, const char *file, int line, const char *function, ast_callid callid, + const char *fmt, va_list ap) +{ + struct logmsg *logmsg = NULL; + struct ast_str *buf = NULL; + struct ast_tm tm; + struct timeval now = ast_tvnow(); + int res = 0; + char datestring[256]; + + if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) { + return NULL; + } + + /* Build string */ + res = ast_str_set_va(&buf, BUFSIZ, fmt, ap); + + /* If the build failed, then abort and free this structure */ + if (res == AST_DYNSTR_BUILD_FAILED) { + return NULL; + } + + /* Create a new logging message */ + if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) { + return NULL; + } + + /* Copy string over */ + ast_string_field_set(logmsg, message, ast_str_buffer(buf)); + + /* Set type */ + if (level == __LOG_VERBOSE) { + logmsg->type = LOGMSG_VERBOSE; + } else { + logmsg->type = LOGMSG_NORMAL; + } + + if (display_callids && callid) { + logmsg->callid = callid; + } + + /* Create our date/time */ + ast_localtime(&now, &tm, NULL); + ast_strftime(datestring, sizeof(datestring), dateformat, &tm); + ast_string_field_set(logmsg, date, datestring); + + /* Copy over data */ + logmsg->level = level; + logmsg->sublevel = sublevel; + logmsg->line = line; + ast_string_field_set(logmsg, level_name, levels[level]); + ast_string_field_set(logmsg, file, file); + ast_string_field_set(logmsg, function, function); + logmsg->lwp = ast_get_tid(); + + return logmsg; +} + +static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message(int level, + int sublevel, const char *file, int line, const char *function, ast_callid callid, + const char *fmt, ...) +{ + struct logmsg *logmsg; + va_list ap; + + va_start(ap, fmt); + logmsg = format_log_message_ap(level, sublevel, file, line, function, callid, fmt, ap); + va_end(ap); + + return logmsg; +} + /*! \brief Actual logging thread */ static void *logger_thread(void *data) { @@ -1601,8 +1690,21 @@ static void *logger_thread(void *data) ast_cond_wait(&logcond, &logmsgs.lock); } } + + if (high_water_alert) { + msg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0, + "Logging resumed. %d message%s discarded.\n", + logger_messages_discarded, logger_messages_discarded == 1 ? "" : "s"); + if (msg) { + AST_LIST_INSERT_TAIL(&logmsgs, msg, list); + } + high_water_alert = 0; + logger_messages_discarded = 0; + } + next = AST_LIST_FIRST(&logmsgs); AST_LIST_HEAD_INIT_NOLOCK(&logmsgs); + logger_queue_size = 0; AST_LIST_UNLOCK(&logmsgs); /* Otherwise go through and process each message in the order added */ @@ -1861,79 +1963,36 @@ void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created) /*! * \brief send log messages to syslog and/or the console */ -static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel, const char *file, int line, const char *function, ast_callid callid, const char *fmt, va_list ap) +static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel, + const char *file, int line, const char *function, ast_callid callid, + const char *fmt, va_list ap) { struct logmsg *logmsg = NULL; - struct ast_str *buf = NULL; - struct ast_tm tm; - struct timeval now = ast_tvnow(); - int res = 0; - char datestring[256]; if (level == __LOG_VERBOSE && ast_opt_remote && ast_opt_exec) { return; } - if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) - return; - - if (level != __LOG_VERBOSE && AST_RWLIST_EMPTY(&logchannels)) { - /* - * we don't have the logger chain configured yet, - * so just log to stdout - */ - int result; - result = ast_str_set_va(&buf, BUFSIZ, fmt, ap); /* XXX BUFSIZ ? */ - if (result != AST_DYNSTR_BUILD_FAILED) { - term_filter_escapes(ast_str_buffer(buf)); - fputs(ast_str_buffer(buf), stdout); + AST_LIST_LOCK(&logmsgs); + if (logger_queue_size >= logger_queue_limit && !close_logger_thread) { + logger_messages_discarded++; + if (!high_water_alert && !close_logger_thread) { + logmsg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0, + "Log queue threshold (%d) exceeded. Discarding new messages.\n", logger_queue_limit); + AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list); + high_water_alert = 1; + ast_cond_signal(&logcond); } + AST_LIST_UNLOCK(&logmsgs); return; } + AST_LIST_UNLOCK(&logmsgs); - /* Ignore anything that never gets logged anywhere */ - if (level != __LOG_VERBOSE && !(global_logmask & (1 << level))) - return; - - /* Build string */ - res = ast_str_set_va(&buf, BUFSIZ, fmt, ap); - - /* If the build failed, then abort and free this structure */ - if (res == AST_DYNSTR_BUILD_FAILED) + logmsg = format_log_message_ap(level, sublevel, file, line, function, callid, fmt, ap); + if (!logmsg) { return; - - /* Create a new logging message */ - if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) - return; - - /* Copy string over */ - ast_string_field_set(logmsg, message, ast_str_buffer(buf)); - - /* Set type */ - if (level == __LOG_VERBOSE) { - logmsg->type = LOGMSG_VERBOSE; - } else { - logmsg->type = LOGMSG_NORMAL; } - if (display_callids && callid) { - logmsg->callid = callid; - } - - /* Create our date/time */ - ast_localtime(&now, &tm, NULL); - ast_strftime(datestring, sizeof(datestring), dateformat, &tm); - ast_string_field_set(logmsg, date, datestring); - - /* Copy over data */ - logmsg->level = level; - logmsg->sublevel = sublevel; - logmsg->line = line; - ast_string_field_set(logmsg, level_name, levels[level]); - ast_string_field_set(logmsg, file, file); - ast_string_field_set(logmsg, function, function); - logmsg->lwp = ast_get_tid(); - /* If the logger thread is active, append it to the tail end of the list - otherwise skip that step */ if (logthread != AST_PTHREADT_NULL) { AST_LIST_LOCK(&logmsgs); @@ -1942,6 +2001,7 @@ static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int su logmsg_free(logmsg); } else { AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list); + logger_queue_size++; ast_cond_signal(&logcond); } AST_LIST_UNLOCK(&logmsgs); @@ -2300,3 +2360,12 @@ const char *ast_logger_get_dateformat(void) return dateformat; } +void ast_logger_set_queue_limit(int queue_limit) +{ + logger_queue_limit = queue_limit; +} + +int ast_logger_get_queue_limit(void) +{ + return logger_queue_limit; +} diff --git a/tests/test_logger.c b/tests/test_logger.c index 07a4c369b81..59ee3e6c129 100644 --- a/tests/test_logger.c +++ b/tests/test_logger.c @@ -188,9 +188,76 @@ static char *handle_cli_performance_test(struct ast_cli_entry *e, int cmd, struc return CLI_SUCCESS; } +static char *handle_cli_queue_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + unsigned int level; + int current_queue_limit; + unsigned int x; + struct timeval start, end; + int elapsed; + char tmppath[] = "/tmp/asterisk_logger_queue.XXXXXX"; + int fd; + + switch (cmd) { + case CLI_INIT: + e->command = "logger test queue"; + e->usage = "" + "Usage: logger test queue\n" + ""; + return NULL; + case CLI_GENERATE: + return NULL; + } + + fd = mkstemp(tmppath); + if (fd < 0) { + ast_cli(a->fd, "Test: Failed, could not create temporary log file '%s'.\n", tmppath); + return CLI_SUCCESS; + } + + level = ast_logger_register_level("queuetest"); + if (level < 0) { + ast_cli(a->fd, "Test: Failed, could not register level 'queuetest'.\n"); + return CLI_SUCCESS; + } + ast_cli(a->fd, "Test: got level %u for 'queuetest'.\n", level); + + if (ast_logger_create_channel(tmppath, "queuetest") != AST_LOGGER_SUCCESS) { + ast_cli(a->fd, "Test: Unable to create logger channel '%s'\n", tmppath); + goto error; + } + + current_queue_limit = ast_logger_get_queue_limit(); + ast_cli(a->fd, "Test: Current queue limit: %d. Setting to 100 for test.\n", current_queue_limit); + ast_logger_set_queue_limit(100); + + ast_cli(a->fd, "Test: You should see SOME 'exceeded' and 'resumed' messages after the test " + "is completed. How many is dependent on system resources.\n"); + + start = ast_tvnow(); + for (x = 0; x < 10000; x++) { + ast_log_dynamic_level(level, "Performance test log message %2d\n", x); + } + end = ast_tvnow(); + elapsed = ast_tvdiff_ms(end, start); + ast_cli(a->fd, "Test: 10,000 messages in %f seconds.\n", (float) elapsed / 1000); + ast_cli(a->fd, "Test: Completed. Resetting queue limit to %d.\n", current_queue_limit); + ast_logger_set_queue_limit(current_queue_limit); + +error: + + ast_logger_remove_channel(tmppath); + ast_logger_unregister_level("queuetest"); + close(fd); + unlink(tmppath); + + return CLI_SUCCESS; +} + static struct ast_cli_entry cli_logger[] = { AST_CLI_DEFINE(handle_cli_dynamic_level_test, "Test the dynamic logger level implementation"), AST_CLI_DEFINE(handle_cli_performance_test, "Test the logger performance"), + AST_CLI_DEFINE(handle_cli_queue_test, "Test the logger queue"), }; static int unload_module(void) From 3c36c29c81c07ad220860a59349def72afc35d86 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 9 May 2017 10:25:29 +0000 Subject: [PATCH 1247/1578] res_hep_rtcp: Provide chan_sip Call-ID for RTCP messages. This change adds the required logic to allow the SIP Call-ID to be placed into the HEP RTCP traffic if the chan_sip module is used. In cases where the option is enabled but the channel is not either SIP or PJSIP then the code will fallback to the channel name as done previously. Based on the change on Nir's branch at: team/nirs/hep-chan-sip-support ASTERISK-26427 Change-Id: I09ffa5f6e2fdfd99ee999650ba4e0a7aad6dc40d --- CHANGES | 6 ++++++ configs/samples/hep.conf.sample | 6 +++++- res/res_hep_rtcp.c | 18 ++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 9c8ed5b8e77..21fde194a99 100644 --- a/CHANGES +++ b/CHANGES @@ -42,6 +42,12 @@ res_pjsip_config_wizard endpoint/outbound_proxy, aor/outbound_proxy and registration/outbound_proxy parameters. +res_hep_rtcp +------------------ + * If the 'call-id' value is specified for the uuid_type option and a + chan_sip channel is used the resulting HEP traffic will now contain the + SIP Call-ID instead of the Asterisk channel name. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.3.0 to Asterisk 14.4.0 ------------ ------------------------------------------------------------------------------ diff --git a/configs/samples/hep.conf.sample b/configs/samples/hep.conf.sample index 3d1e7413994..32bd8df39ff 100644 --- a/configs/samples/hep.conf.sample +++ b/configs/samples/hep.conf.sample @@ -24,5 +24,9 @@ capture_id = 1234 ; A unique integer identifier for this ; with each packet from this server. uuid_type = call-id ; Specify the preferred source for the Homer ; correlation UUID. Valid options are: - ; - 'call-id' for the PJSIP SIP Call-ID + ; - 'call-id' for the PJSIP or chan_sip SIP + ; Call-ID ; - 'channel' for the Asterisk channel name + ; Note: If 'call-id' is specified but the + ; channel is not PJSIP or chan_sip then the + ; Asterisk channel name will be used instead. diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 7191f466163..395031a3d4d 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -53,12 +53,22 @@ static char *assign_uuid(struct ast_json *json_channel) return NULL; } - if (uuid_type == HEP_UUID_TYPE_CALL_ID && ast_begins_with(channel_name, "PJSIP")) { - struct ast_channel *chan = ast_channel_get_by_name(channel_name); + if (uuid_type == HEP_UUID_TYPE_CALL_ID) { + struct ast_channel *chan = NULL; char buf[128]; - if (chan && !ast_func_read(chan, "CHANNEL(pjsip,call-id)", buf, sizeof(buf))) { - uuid = ast_strdup(buf); + if (ast_begins_with(channel_name, "PJSIP")) { + chan = ast_channel_get_by_name(channel_name); + + if (chan && !ast_func_read(chan, "CHANNEL(pjsip,call-id)", buf, sizeof(buf))) { + uuid = ast_strdup(buf); + } + } else if (ast_begins_with(channel_name, "SIP")) { + chan = ast_channel_get_by_name(channel_name); + + if (chan && !ast_func_read(chan, "SIP_HEADER(call-id)", buf, sizeof(buf))) { + uuid = ast_strdup(buf); + } } ast_channel_cleanup(chan); From 1a1c86239d9aa64dc7e9301ea03326dd5436931c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 5 May 2017 10:33:34 -0600 Subject: [PATCH 1248/1578] cel_odbc: Fix timestamp processing for microseconds When a column is of type timestamp, the fraction part of the event field's seconds was frequently parsed incorrectly especially if there were leading zeros. For instance "2017-05-23 23:55:03.023" would be parsed into an int as "23" then when the timestamp was formatted again to be inserted into the database column it'd be "2017-05-23 23:55:03.23" which is now 230 milliseconds instead of 23 milliseconds. "03.000001" would be transformed to "03.1", etc. * If the event field is 'eventtime' and the db column is timestamp, then existing processing has already correctly formatted the timestamp so now we simply use it rather than parsing it and re-printing it. This is the most common use case anyway. * If the event field is other than 'eventtime' and the db column is timestamp, we now parse the seconds, including the fractional part into a double rather than 2 ints. This preserves the magnitude and precision of the fractional part. When we print it, we now print it as a "%09.6lf" which correctly represents the input. To be honest, why we parse the string timestamp into components, test the components, then print the components back into a string timestamp is beyond me. We should use parse it, test it, then if it passes, use the original string representation in the database call. Maybe someone thought that some implementations wouldn't take a partial timestamp string like "2017-05-06" and decided to always produce a full timestamp string even if an abbreviated one was supplied. Anyway, I'm leaving it as it is. ASTERISK-25032 #close Reported-by: Etienne Lessard Change-Id: Id407e6221f79a5c1120e1a70bc7e893bbcaf1938 --- cel/cel_odbc.c | 83 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c index a0cc6e33aaa..bdf913cd4c6 100644 --- a/cel/cel_odbc.c +++ b/cel/cel_odbc.c @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -607,40 +608,62 @@ static void odbc_log(struct ast_event *event) if (ast_strlen_zero(colptr)) { continue; } else { - int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, fraction = 0; - if (strcasecmp(entry->name, "eventdate") == 0) { - struct ast_tm tm; - ast_localtime(&record.event_time, &tm, tableptr->usegmtime ? "UTC" : NULL); - year = tm.tm_year + 1900; - month = tm.tm_mon + 1; - day = tm.tm_mday; - hour = tm.tm_hour; - minute = tm.tm_min; - second = (tableptr->allowleapsec || tm.tm_sec < 60) ? tm.tm_sec : 59; - fraction = tm.tm_usec; + if (datefield) { + /* + * We've already properly formatted the timestamp so there's no need + * to parse it and re-format it. + */ + ast_str_append(&sql, 0, "%s%s", separator, entry->name); + LENGTHEN_BUF2(27); + ast_str_append(&sql2, 0, "%s{ts '%s'}", separator, colptr); } else { - int count = sscanf(colptr, "%4d-%2d-%2d %2d:%2d:%2d.%6d", &year, &month, &day, &hour, &minute, &second, &fraction); - - if ((count != 3 && count != 5 && count != 6 && count != 7) || year <= 0 || - month <= 0 || month > 12 || day < 0 || day > 31 || - ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || - (month == 2 && year % 400 == 0 && day > 29) || - (month == 2 && year % 100 == 0 && day > 28) || - (month == 2 && year % 4 == 0 && day > 29) || - (month == 2 && year % 4 != 0 && day > 28) || - hour > 23 || minute > 59 || second > (tableptr->allowleapsec ? 60 : 59) || hour < 0 || minute < 0 || second < 0 || fraction < 0) { - ast_log(LOG_WARNING, "CEL variable %s is not a valid timestamp ('%s').\n", entry->name, colptr); - continue; + int year = 0, month = 0, day = 0, hour = 0, minute = 0; + /* MUST use double for microsecond precision */ + double second = 0.0; + if (strcasecmp(entry->name, "eventdate") == 0) { + /* + * There doesn't seem to be any reference to 'eventdate' anywhere + * other than in this module. It should be considered for removal + * at a later date. + */ + struct ast_tm tm; + ast_localtime(&record.event_time, &tm, tableptr->usegmtime ? "UTC" : NULL); + year = tm.tm_year + 1900; + month = tm.tm_mon + 1; + day = tm.tm_mday; + hour = tm.tm_hour; + minute = tm.tm_min; + second = (tableptr->allowleapsec || tm.tm_sec < 60) ? tm.tm_sec : 59; + second += (tm.tm_usec / 1000000.0); + } else { + /* + * If we're here, the data to be inserted MAY be a timestamp + * but the column is. We parse as much as we can. + */ + int count = sscanf(colptr, "%4d-%2d-%2d %2d:%2d:%lf", &year, &month, &day, &hour, &minute, &second); + + if ((count != 3 && count != 5 && count != 6) || year <= 0 || + month <= 0 || month > 12 || day < 0 || day > 31 || + ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) || + (month == 2 && year % 400 == 0 && day > 29) || + (month == 2 && year % 100 == 0 && day > 28) || + (month == 2 && year % 4 == 0 && day > 29) || + (month == 2 && year % 4 != 0 && day > 28) || + hour > 23 || minute > 59 || ((int)floor(second)) > (tableptr->allowleapsec ? 60 : 59) || + hour < 0 || minute < 0 || ((int)floor(second)) < 0) { + ast_log(LOG_WARNING, "CEL variable %s is not a valid timestamp ('%s').\n", entry->name, colptr); + continue; + } + + if (year > 0 && year < 100) { + year += 2000; + } } - if (year > 0 && year < 100) { - year += 2000; - } + ast_str_append(&sql, 0, "%s%s", separator, entry->name); + LENGTHEN_BUF2(27); + ast_str_append(&sql2, 0, "%s{ts '%04d-%02d-%02d %02d:%02d:%09.6lf'}", separator, year, month, day, hour, minute, second); } - - ast_str_append(&sql, 0, "%s%s", separator, entry->name); - LENGTHEN_BUF2(27); - ast_str_append(&sql2, 0, "%s{ts '%04d-%02d-%02d %02d:%02d:%02d.%d'}", separator, year, month, day, hour, minute, second, fraction); } break; case SQL_INTEGER: From 10a4439ac93e1610cd138ec080f3230de0ae58fc Mon Sep 17 00:00:00 2001 From: Joshua Elson Date: Thu, 4 May 2017 18:28:55 -0400 Subject: [PATCH 1249/1578] Prevent Undefined Capath Crash It is possible to initialize a valid config without a capath or cafile definition. This will cause a crash on a reload. This fix ensures capath is always allocated. ASTERISK-26983 #close Change-Id: I63ff715d9d9023427543a5b8a4ba7b0d82533c12 --- main/manager.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main/manager.c b/main/manager.c index c1d73dce763..c592fbd37a9 100644 --- a/main/manager.c +++ b/main/manager.c @@ -8736,6 +8736,10 @@ static void manager_shutdown(void) ami_tls_cfg.pvtfile = NULL; ast_free(ami_tls_cfg.cipher); ami_tls_cfg.cipher = NULL; + ast_free(ami_tls_cfg.cafile); + ami_tls_cfg.cafile = NULL; + ast_free(ami_tls_cfg.capath); + ami_tls_cfg.capath = NULL; ao2_global_obj_release(mgr_sessions); @@ -8836,6 +8840,10 @@ static void manager_set_defaults(void) ami_tls_cfg.pvtfile = ast_strdup(""); ast_free(ami_tls_cfg.cipher); ami_tls_cfg.cipher = ast_strdup(""); + ast_free(ami_tls_cfg.cafile); + ami_tls_cfg.cafile = ast_strdup(""); + ast_free(ami_tls_cfg.capath); + ami_tls_cfg.capath = ast_strdup(""); } static int __init_manager(int reload, int by_external_config) From cbbd119c211af085f16adb915f3b50f753642b91 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 9 May 2017 15:34:49 +0000 Subject: [PATCH 1250/1578] tcptls: Improve error messages for TLS connections. This change uses the functions provided by OpenSSL to query and better construct error messages for situations where the connection encounters a problem. ASTERISK-26606 Change-Id: I7ae40ce88c0dc4e185c4df1ceb3a6ccc198f075b --- main/iostream.c | 67 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/main/iostream.c b/main/iostream.c index 6187bc2fbb1..06414cf43d6 100644 --- a/main/iostream.c +++ b/main/iostream.c @@ -37,6 +37,39 @@ struct ast_iostream { char rbuf[2048]; }; +#if defined(DO_SSL) +AST_THREADSTORAGE(err2str_threadbuf); +#define ERR2STR_BUFSIZE 128 + +static const char *ssl_error_to_string(int sslerr, int ret) +{ + switch (sslerr) { + case SSL_ERROR_SSL: + return "Internal SSL error"; + case SSL_ERROR_SYSCALL: + if (!ret) { + return "System call EOF"; + } else if (ret == -1) { + char *buf; + + buf = ast_threadstorage_get(&err2str_threadbuf, ERR2STR_BUFSIZE); + if (!buf) { + return "Unknown"; + } + + snprintf(buf, ERR2STR_BUFSIZE, "Underlying BIO error: %s", strerror(errno)); + return buf; + } else { + return "System call other"; + } + default: + break; + } + + return "Unknown"; +} +#endif + int ast_iostream_get_fd(struct ast_iostream *stream) { return stream->fd; @@ -109,13 +142,16 @@ static ssize_t iostream_read(struct ast_iostream *stream, void *buf, size_t size #if defined(DO_SSL) if (stream->ssl) { for (;;) { + int sslerr; + char err[256]; res = SSL_read(stream->ssl, buf, size); if (0 < res) { /* We read some payload data. */ stream->timeout = stream->timeout_reset; return res; } - switch (SSL_get_error(stream->ssl, res)) { + sslerr = SSL_get_error(stream->ssl, res); + switch (sslerr) { case SSL_ERROR_ZERO_RETURN: /* Report EOF for a shutdown */ ast_debug(1, "TLS clean shutdown alert reading data\n"); @@ -163,7 +199,8 @@ static ssize_t iostream_read(struct ast_iostream *stream, void *buf, size_t size break; default: /* Report EOF for an undecoded SSL or transport error. */ - ast_debug(1, "TLS transport or SSL error reading data\n"); + ast_debug(1, "TLS transport or SSL error reading data: %s, %s\n", ERR_error_string(sslerr, err), + ssl_error_to_string(sslerr, res)); return 0; } if (!ms) { @@ -318,6 +355,8 @@ ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buf, size_t written = 0; remaining = size; for (;;) { + int sslerr; + char err[256]; res = SSL_write(stream->ssl, buf + written, remaining); if (res == remaining) { /* Everything was written. */ @@ -329,7 +368,8 @@ ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buf, size_t remaining -= res; continue; } - switch (SSL_get_error(stream->ssl, res)) { + sslerr = SSL_get_error(stream->ssl, res); + switch (sslerr) { case SSL_ERROR_ZERO_RETURN: ast_debug(1, "TLS clean shutdown alert writing data\n"); if (written) { @@ -358,7 +398,8 @@ ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buf, size_t break; default: /* Undecoded SSL or transport error. */ - ast_debug(1, "TLS transport or SSL error writing data\n"); + ast_debug(1, "TLS transport or SSL error writing data: %s, %s\n", ERR_error_string(sslerr, err), + ssl_error_to_string(sslerr, res)); if (written) { /* Report partial write. */ return written; @@ -461,8 +502,10 @@ int ast_iostream_close(struct ast_iostream *stream) */ res = SSL_shutdown(stream->ssl); if (res < 0) { - ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n", - SSL_get_error(stream->ssl, res)); + int sslerr = SSL_get_error(stream->ssl, res); + char err[256]; + ast_log(LOG_ERROR, "SSL_shutdown() failed: %s, %s\n", + ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res)); } #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L @@ -534,7 +577,7 @@ int ast_iostream_start_tls(struct ast_iostream **pstream, SSL_CTX *ssl_ctx, int #ifdef DO_SSL struct ast_iostream *stream = *pstream; int (*ssl_setup)(SSL *) = client ? SSL_connect : SSL_accept; - char err[256]; + int res; stream->ssl = SSL_new(ssl_ctx); if (!stream->ssl) { @@ -551,9 +594,13 @@ int ast_iostream_start_tls(struct ast_iostream **pstream, SSL_CTX *ssl_ctx, int */ SSL_set_fd(stream->ssl, stream->fd); - if (ssl_setup(stream->ssl) <= 0) { - ast_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", - ERR_error_string(ERR_get_error(), err)); + res = ssl_setup(stream->ssl); + if (res <= 0) { + int sslerr = SSL_get_error(stream->ssl, res); + char err[256]; + + ast_log(LOG_ERROR, "Problem setting up ssl connection: %s, %s\n", + ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res)); errno = EIO; return -1; } From ae7689f09333d88867a5eb6feeec8437c17dc1d2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 28 Apr 2017 12:30:34 -0500 Subject: [PATCH 1251/1578] SDP: Update ast_get_topology_from_sdp() to keep RTP map. * Add failure exits to ast_get_topology_from_sdp(). Change-Id: I4cc85c1ede8d712766ed20f544dbcef04c8c1049 --- include/asterisk/sdp.h | 3 +- include/asterisk/stream.h | 70 +++++++++++++++++++-------------------- main/sdp.c | 64 ++++++++++++++++++++++++++--------- main/sdp_state.c | 3 +- tests/test_sdp.c | 6 +++- 5 files changed, 93 insertions(+), 53 deletions(-) diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h index 06470c4b05c..8aa9e3b7fae 100644 --- a/include/asterisk/sdp.h +++ b/include/asterisk/sdp.h @@ -638,11 +638,12 @@ void ast_sdp_rtpmap_free(struct ast_sdp_rtpmap *rtpmap); * each m-line corresponding to a stream in the created topology. * * \param sdp The SDP to convert + * \param g726_non_standard Non-zero if G.726 is non-standard * * \retval NULL An error occurred when converting * \retval non-NULL The generated stream topology * * \since 15.0.0 */ -struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp); +struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp, int g726_non_standard); #endif /* _SDP_PRIV_H */ diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 821ecec030d..526aee17d27 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -55,39 +55,39 @@ typedef void (*ast_stream_data_free_fn)(void *); * \brief States that a stream may be in */ enum ast_stream_state { - /*! - * \brief Set when the stream has been removed - */ - AST_STREAM_STATE_REMOVED = 0, - /*! - * \brief Set when the stream is sending and receiving media - */ - AST_STREAM_STATE_SENDRECV, - /*! - * \brief Set when the stream is sending media only - */ - AST_STREAM_STATE_SENDONLY, - /*! - * \brief Set when the stream is receiving media only - */ - AST_STREAM_STATE_RECVONLY, - /*! - * \brief Set when the stream is not sending OR receiving media - */ - AST_STREAM_STATE_INACTIVE, + /*! + * \brief Set when the stream has been removed + */ + AST_STREAM_STATE_REMOVED = 0, + /*! + * \brief Set when the stream is sending and receiving media + */ + AST_STREAM_STATE_SENDRECV, + /*! + * \brief Set when the stream is sending media only + */ + AST_STREAM_STATE_SENDONLY, + /*! + * \brief Set when the stream is receiving media only + */ + AST_STREAM_STATE_RECVONLY, + /*! + * \brief Set when the stream is not sending OR receiving media + */ + AST_STREAM_STATE_INACTIVE, }; /*! * \brief Stream data slots */ enum ast_stream_data_slot { - /*! - * \brief Data slot for RTP instance - */ - AST_STREAM_DATA_RTP_INSTANCE = 0, - /*! - * \brief Controls the size of the data pointer array - */ + /*! + * \brief Data slot for RTP instance + */ + AST_STREAM_DATA_RTP_CODECS = 0, + /*! + * \brief Controls the size of the data pointer array + */ AST_STREAM_DATA_SLOT_MAX }; @@ -386,15 +386,15 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( * * \param topology The topology of streams * - * \retval non-NULL success - * \retval NULL failure - * - * \note The stream topology is NOT altered by this function. - * - * \since 15 - */ + * \retval non-NULL success + * \retval NULL failure + * + * \note The stream topology is NOT altered by this function. + * + * \since 15 + */ struct ast_format_cap *ast_format_cap_from_stream_topology( - struct ast_stream_topology *topology); + struct ast_stream_topology *topology); /*! * \brief Gets the first stream of a specific type from the topology diff --git a/main/sdp.c b/main/sdp.c index 62acdd3f758..019c6699f1a 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -693,6 +693,17 @@ static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload, ao2_ref(format, -1); } +/* + * Needed so we don't have an external function referenced as data. + * The dynamic linker doesn't handle that very well. + */ +static void rtp_codecs_free(struct ast_rtp_codecs *codecs) +{ + if (codecs) { + ast_rtp_codecs_payloads_destroy(codecs); + } +} + /*! * \brief Convert an SDP stream into an Asterisk stream * @@ -700,16 +711,19 @@ static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload, * This takes formats, as well as clock-rate and fmtp attributes into account. * * \param m_line The SDP media section to convert + * \param g726_non_standard Non-zero if G.726 is non-standard + * * \retval NULL An error occurred * \retval non-NULL The converted stream */ -static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line) +static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line, int g726_non_standard) { int i; int non_ast_fmts; - struct ast_rtp_codecs codecs; + struct ast_rtp_codecs *codecs; struct ast_format_cap *caps; struct ast_stream *stream; + enum ast_rtp_options options; caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!caps) { @@ -724,8 +738,15 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line) switch (ast_stream_get_type(stream)) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - ast_rtp_codecs_payloads_initialize(&codecs); + codecs = ast_calloc(1, sizeof(*codecs)); + if (!codecs || ast_rtp_codecs_payloads_initialize(codecs)) { + rtp_codecs_free(codecs); + ast_stream_free(stream); + ao2_ref(caps, -1); + return NULL; + } + options = g726_non_standard ? AST_RTP_OPT_G726_NONSTANDARD : 0; for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { struct ast_sdp_payload *payload_s; struct ast_sdp_rtpmap *rtpmap; @@ -733,22 +754,25 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line) payload_s = ast_sdp_m_get_payload(m_line, i); sscanf(payload_s->fmt, "%30d", &payload); - ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, payload); rtpmap = sdp_payload_get_rtpmap(m_line, payload); if (!rtpmap) { + /* No rtpmap attribute. Try static payload type format assignment */ + ast_rtp_codecs_payloads_set_m_type(codecs, NULL, payload); continue; } - ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, - payload, m_line->type, rtpmap->encoding_name, 0, - rtpmap->clock_rate); - ast_sdp_rtpmap_free(rtpmap); - process_fmtp(m_line, payload, &codecs); + if (!ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, payload, + m_line->type, rtpmap->encoding_name, options, rtpmap->clock_rate)) { + /* Successfully mapped the payload type to format */ + process_fmtp(m_line, payload, codecs); + } + ast_sdp_rtpmap_free(rtpmap); } - ast_rtp_codecs_payload_formats(&codecs, caps, &non_ast_fmts); - ast_rtp_codecs_payloads_destroy(&codecs); + ast_rtp_codecs_payload_formats(codecs, caps, &non_ast_fmts); + ast_stream_set_data(stream, AST_STREAM_DATA_RTP_CODECS, codecs, + (ast_stream_data_free_fn) rtp_codecs_free); break; case AST_MEDIA_TYPE_IMAGE: for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { @@ -773,7 +797,7 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line) return stream; } -struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp) +struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp, int g726_non_standard) { struct ast_stream_topology *topology; int i; @@ -786,11 +810,21 @@ struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp) for (i = 0; i < ast_sdp_get_m_count(sdp); ++i) { struct ast_stream *stream; - stream = get_stream_from_m(ast_sdp_get_m(sdp, i)); + stream = get_stream_from_m(ast_sdp_get_m(sdp, i), g726_non_standard); if (!stream) { - continue; + /* + * The topology cannot match the SDP because + * we failed to create a corresponding stream. + */ + ast_stream_topology_free(topology); + return NULL; + } + if (ast_stream_topology_append_stream(topology, stream) < 0) { + /* Failed to add stream to topology */ + ast_stream_free(stream); + ast_stream_topology_free(topology); + return NULL; } - ast_stream_topology_append_stream(topology, stream); } return topology; diff --git a/main/sdp_state.c b/main/sdp_state.c index a9979eb7d96..6ce06ee523a 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -1007,7 +1007,8 @@ static int merge_sdps(struct ast_sdp_state *sdp_state, const struct ast_sdp *rem struct ast_stream_topology *remote_capabilities; int i; - remote_capabilities = ast_get_topology_from_sdp(remote_sdp); + remote_capabilities = ast_get_topology_from_sdp(remote_sdp, + sdp_state->options->g726_non_standard); if (!remote_capabilities) { return -1; } diff --git a/tests/test_sdp.c b/tests/test_sdp.c index a5d3710d899..408888fc007 100644 --- a/tests/test_sdp.c +++ b/tests/test_sdp.c @@ -623,7 +623,11 @@ AST_TEST_DEFINE(sdp_to_topology) goto end; } - topology = ast_get_topology_from_sdp(sdp); + topology = ast_get_topology_from_sdp(sdp, 0); + if (!topology) { + res = AST_TEST_FAIL; + goto end; + } if (ast_stream_topology_get_count(topology) != 3) { ast_test_status_update(test, "Unexpected topology count '%d'. Expecting 2\n", From be5809fac8b423536a6af05817db5705c2977f53 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 28 Apr 2017 19:48:29 -0500 Subject: [PATCH 1252/1578] SDP: Rework merge_capabilities(). * Tried to give better variable names. * Made our SDP answer use the offer's RTP payload types as the SDP RFC says we SHOULD. * Updating the local topology now takes the stream format caps. We are likely preparing to send an offer. Change-Id: I34d3be8e3036402a8575ffcae3eebc5ce348d7c0 --- main/sdp_state.c | 176 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 56 deletions(-) diff --git a/main/sdp_state.c b/main/sdp_state.c index 6ce06ee523a..598a6102cd5 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -522,6 +522,7 @@ const struct ast_sdp_options *ast_sdp_state_get_options( * * \param local Our local stream * \param remote A remote stream + * * \retval NULL An error occurred * \retval non-NULL The joint stream created */ @@ -542,10 +543,6 @@ static struct ast_stream *merge_streams(const struct ast_stream *local, return NULL; } - if (!local) { - return joint_stream; - } - joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!joint_cap) { ast_stream_free(joint_stream); @@ -576,63 +573,100 @@ static struct ast_stream *merge_streams(const struct ast_stream *local, * \param local The local topology * \param media_type The type of stream we are looking for * \param[in,out] media_indices Keeps track of where to start searching in the topology - * \retval NULL No corresponding stream found - * \retval non-NULL The corresponding stream + * + * \retval -1 No corresponding stream found + * \retval index The corresponding stream index */ static int get_corresponding_index(const struct ast_stream_topology *local, enum ast_media_type media_type, int *media_indices) { int i; - int winner = -1; for (i = media_indices[media_type]; i < ast_stream_topology_get_count(local); ++i) { struct ast_stream *candidate; candidate = ast_stream_topology_get_stream(local, i); if (ast_stream_get_type(candidate) == media_type) { - winner = i; - break; + media_indices[media_type] = i + 1; + return i; } } - media_indices[media_type] = i + 1; - return winner; + /* No stream of the type left in the topology */ + media_indices[media_type] = i; + return -1; } +/*! + * XXX TODO The merge_capabilities() function needs to be split into + * merging for new local topologies and new remote topologies. Also + * the possibility of changing the stream types needs consideration. + * Audio to video may or may not need us to keep the same RTP instance + * because the stream position is still RTP. A new RTP instance would + * cause us to change ports. Audio to image is definitely going to + * happen for T.38. + * + * A new remote topology as an initial offer needs to dictate the + * number of streams and the order. As a sdp_state option we may + * allow creation of new active streams not defined by the current + * local topology. A subsequent remote offer can change the stream + * types and add streams. The sdp_state option could regulate + * creation of new active streams here as well. An answer cannot + * change stream types or the number of streams but can decline + * streams. Any attempt to do so should report an error and possibly + * disconnect the call. + * + * A local topology update needs to be merged differently. It cannot + * reduce the number of streams already defined without violating the + * SDP RFC. The local merge could take the new topology stream + * verbatim and add declined streams to fill out any shortfall with + * the exiting topology. This strategy is needed if we want to change + * an audio stream to an image stream for T.38 fax and vice versa. + * The local merge could take the new topology and map the streams to + * the existing local topology. The new topology stream format caps + * would be copied into the merged topology so we could change what + * codecs are negotiated. + */ /*! * \brief Merge existing stream capabilities and a new topology into joint capabilities. * - * This is a bit complicated. The idea is that we already have some capabilities set, and - * we've now been confronted with a new stream topology. We want to take what's been - * presented to us and merge those new capabilities with our own. + * \param sdp_state The state needing capabilities merged + * \param new_topology The new topology to base merged capabilities on + * \param is_local If new_topology is a local update. * - * For each of the new streams, we try to find a corresponding stream in our current - * capabilities. If we find one, then we get the compatible formats of the two streams - * and create a new stream with those formats set. We then will re-use the underlying - * media instance (such as an RTP instance) on this merged stream. + * \details + * This is a bit complicated. The idea is that we already have some + * capabilities set, and we've now been confronted with a new stream + * topology. We want to take what's been presented to us and merge + * those new capabilities with our own. * - * The create_new parameter determines whether we should attempt to create new media - * instances. - * If we do not find a corresponding stream, then we create a new one. If the - * create_new parameter is true, this created stream is made a clone of the new stream, - * and a media instance is created. If the create_new parameter is not true, then the - * created stream has no formats set and no media instance is created for it. + * For each of the new streams, we try to find a corresponding stream + * in our proposed capabilities. If we find one, then we get the + * compatible formats of the two streams and create a new stream with + * those formats set. We then will re-use the underlying media + * instance (such as an RTP instance) on this merged stream. + * + * The is_local parameter determines whether we should attempt to + * create new media instances. If we do not find a corresponding + * stream, then we create a new one. If the is_local parameter is + * true, this created stream is made a clone of the new stream, and a + * media instance is created. If the is_local parameter is not true, + * then the created stream has no formats set and no media instance is + * created for it. * - * \param current Current capabilities of the SDP state (may be NULL) - * \param new_topology The new topology to base merged capabilities on - * \param options The options set on the SDP state * \retval NULL An error occurred * \retval non-NULL The merged capabilities */ -static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_capabilities *current, - const struct ast_stream_topology *new_topology, const struct ast_sdp_options *options, int create_missing) +static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *new_topology, int is_local) { + const struct sdp_state_capabilities *local = sdp_state->proposed_capabilities; struct sdp_state_capabilities *joint_capabilities; - struct ast_stream_topology *topology; int media_indices[AST_MEDIA_TYPE_END] = {0}; int i; + static const char dummy_name[] = "dummy"; - ast_assert(current != NULL); + ast_assert(local != NULL); joint_capabilities = ast_calloc(1, sizeof(*joint_capabilities)); if (!joint_capabilities) { @@ -644,20 +678,18 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ goto fail; } - if (AST_VECTOR_INIT(&joint_capabilities->streams, AST_VECTOR_SIZE(¤t->streams))) { + if (AST_VECTOR_INIT(&joint_capabilities->streams, AST_VECTOR_SIZE(&local->streams))) { goto fail; } - ast_sockaddr_copy(&joint_capabilities->connection_address, ¤t->connection_address); - topology = current->topology; + ast_sockaddr_copy(&joint_capabilities->connection_address, &local->connection_address); for (i = 0; i < ast_stream_topology_get_count(new_topology); ++i) { enum ast_media_type new_stream_type; struct ast_stream *new_stream; - struct ast_stream *current_stream; + struct ast_stream *local_stream; struct ast_stream *joint_stream; - struct sdp_state_stream *current_state_stream; struct sdp_state_stream *joint_state_stream; - int current_index; + int local_index; joint_state_stream = ast_calloc(1, sizeof(*joint_state_stream)); if (!joint_state_stream) { @@ -667,26 +699,57 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ new_stream = ast_stream_topology_get_stream(new_topology, i); new_stream_type = ast_stream_get_type(new_stream); - current_index = get_corresponding_index(topology, new_stream_type, media_indices); - if (current_index >= 0) { - current_stream = ast_stream_topology_get_stream(topology, current_index); - joint_stream = merge_streams(current_stream, new_stream); + local_index = get_corresponding_index(local->topology, new_stream_type, media_indices); + if (0 <= local_index) { + local_stream = ast_stream_topology_get_stream(local->topology, local_index); + if (!strcmp(ast_stream_get_name(local_stream), dummy_name)) { + /* The local stream is a non-exixtent dummy stream. */ + local_stream = NULL; + } + } else { + local_stream = NULL; + } + if (local_stream) { + struct sdp_state_stream *local_state_stream; + struct ast_rtp_codecs *codecs; + + if (is_local) { + /* Replace the local stream with the new local stream. */ + joint_stream = ast_stream_clone(new_stream); + } else { + joint_stream = merge_streams(local_stream, new_stream); + } if (!joint_stream) { sdp_state_stream_free(joint_state_stream); goto fail; } - current_state_stream = AST_VECTOR_GET(¤t->streams, current_index); - joint_state_stream->type = current_state_stream->type; + local_state_stream = AST_VECTOR_GET(&local->streams, local_index); + joint_state_stream->type = local_state_stream->type; switch (joint_state_stream->type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - joint_state_stream->instance = ao2_bump(current_state_stream->instance); + joint_state_stream->instance = ao2_bump(local_state_stream->instance); + if (is_local) { + break; + } + codecs = ast_stream_get_data(new_stream, AST_STREAM_DATA_RTP_CODECS); + ast_assert(codecs != NULL); + if (sdp_state->role == SDP_ROLE_ANSWERER) { + /* + * Setup rx payload type mapping to prefer the mapping + * from the peer that the RFC says we SHOULD use. + */ + ast_rtp_codecs_payloads_xover(codecs, codecs, NULL); + } + ast_rtp_codecs_payloads_copy(codecs, + ast_rtp_instance_get_codecs(joint_state_stream->instance), + joint_state_stream->instance); break; case AST_MEDIA_TYPE_IMAGE: - joint_state_stream->udptl = ao2_bump(current_state_stream->udptl); - joint_state_stream->t38_local_params = current_state_stream->t38_local_params; + joint_state_stream->udptl = ao2_bump(local_state_stream->udptl); + joint_state_stream->t38_local_params = local_state_stream->t38_local_params; break; case AST_MEDIA_TYPE_UNKNOWN: case AST_MEDIA_TYPE_TEXT: @@ -694,13 +757,14 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ break; } - if (!ast_sockaddr_isnull(¤t_state_stream->connection_address)) { - ast_sockaddr_copy(&joint_state_stream->connection_address, ¤t_state_stream->connection_address); + if (!ast_sockaddr_isnull(&local_state_stream->connection_address)) { + ast_sockaddr_copy(&joint_state_stream->connection_address, + &local_state_stream->connection_address); } else { ast_sockaddr_setnull(&joint_state_stream->connection_address); } - joint_state_stream->locally_held = current_state_stream->locally_held; - } else if (create_missing) { + joint_state_stream->locally_held = local_state_stream->locally_held; + } else if (is_local) { /* We don't have a stream state that corresponds to the stream in the new topology, so * create a stream state as appropriate. */ @@ -713,7 +777,8 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ switch (new_stream_type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - joint_state_stream->instance = create_rtp(options, new_stream_type); + joint_state_stream->instance = create_rtp(sdp_state->options, + new_stream_type); if (!joint_state_stream->instance) { ast_stream_free(joint_stream); sdp_state_stream_free(joint_state_stream); @@ -721,7 +786,7 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ } break; case AST_MEDIA_TYPE_IMAGE: - joint_state_stream->udptl = create_udptl(options); + joint_state_stream->udptl = create_udptl(sdp_state->options); if (!joint_state_stream->udptl) { ast_stream_free(joint_stream); sdp_state_stream_free(joint_state_stream); @@ -740,7 +805,7 @@ static struct sdp_state_capabilities *merge_capabilities(const struct sdp_state_ * dummy stream to go in its place so that the resulting SDP created will contain * the stream but will have no port or codecs set */ - joint_stream = ast_stream_alloc("dummy", new_stream_type); + joint_stream = ast_stream_alloc(dummy_name, new_stream_type); if (!joint_stream) { sdp_state_stream_free(joint_state_stream); goto fail; @@ -1013,8 +1078,7 @@ static int merge_sdps(struct ast_sdp_state *sdp_state, const struct ast_sdp *rem return -1; } - joint_capabilities = merge_capabilities(sdp_state->proposed_capabilities, - remote_capabilities, sdp_state->options, 0); + joint_capabilities = merge_capabilities(sdp_state, remote_capabilities, 0); ast_stream_topology_free(remote_capabilities); if (!joint_capabilities) { return -1; @@ -1127,7 +1191,7 @@ int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_assert(sdp_state != NULL); ast_assert(streams != NULL); - capabilities = merge_capabilities(sdp_state->proposed_capabilities, streams, sdp_state->options, 1); + capabilities = merge_capabilities(sdp_state, streams, 1); if (!capabilities) { return -1; } From 367042bd3e58233bdb23542c1f19ec4907f07ff2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 5 May 2017 14:49:30 -0500 Subject: [PATCH 1253/1578] SDP: Explicitly stop a RTP instance before destoying it. * Made sdp_add_m_from_rtp_stream() and sdp_add_m_from_udptl_stream() handle generating disabled/declined streams. * Added /main/sdp/sdp_merge_asymmetric unit test. It currently does not check the offerer side negotiated SDP because that isn't the purpose of this patch and there is much to be done to handle declined/dummy streams. * Added T.38 image streams to the /main/sdp/sdp_merge_symmetric and /main/sdp/sdp_merge_crisscross unit tests. Change-Id: Ib4dcb3ca4f9a9133b376f4e3302f9a1f963f2b31 --- include/asterisk/stream.h | 2 +- main/sdp_state.c | 439 +++++++++++++++++++++++--------------- tests/test_sdp.c | 167 ++++++++++++++- 3 files changed, 429 insertions(+), 179 deletions(-) diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 526aee17d27..b453ab9c326 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -56,7 +56,7 @@ typedef void (*ast_stream_data_free_fn)(void *); */ enum ast_stream_state { /*! - * \brief Set when the stream has been removed + * \brief Set when the stream has been removed/declined */ AST_STREAM_STATE_REMOVED = 0, /*! diff --git a/main/sdp_state.c b/main/sdp_state.c index 598a6102cd5..9b116ca5492 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -64,6 +64,11 @@ enum ast_sdp_role { typedef int (*state_fn)(struct ast_sdp_state *state); +struct sdp_state_rtp { + /*! The underlying RTP instance */ + struct ast_rtp_instance *instance; +}; + struct sdp_state_udptl { /*! The underlying UDPTL instance */ struct ast_udptl *instance; @@ -74,7 +79,7 @@ struct sdp_state_stream { enum ast_media_type type; union { /*! The underlying RTP instance */ - struct ast_rtp_instance *instance; + struct sdp_state_rtp *rtp; /*! The underlying UDPTL instance */ struct sdp_state_udptl *udptl; }; @@ -86,6 +91,16 @@ struct sdp_state_stream { struct ast_control_t38_parameters t38_local_params; }; +static void sdp_state_rtp_destroy(void *obj) +{ + struct sdp_state_rtp *rtp = obj; + + if (rtp->instance) { + ast_rtp_instance_stop(rtp->instance); + ast_rtp_instance_destroy(rtp->instance); + } +} + static void sdp_state_udptl_destroy(void *obj) { struct sdp_state_udptl *udptl = obj; @@ -100,9 +115,7 @@ static void sdp_state_stream_free(struct sdp_state_stream *state_stream) switch (state_stream->type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - if (state_stream->instance) { - ast_rtp_instance_destroy(state_stream->instance); - } + ao2_cleanup(state_stream->rtp); break; case AST_MEDIA_TYPE_IMAGE: ao2_cleanup(state_stream->udptl); @@ -145,10 +158,10 @@ static void sdp_state_capabilities_free(struct sdp_state_capabilities *capabilit static struct ast_sched_context *sched; /*! \brief Internal function which creates an RTP instance */ -static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, +static struct sdp_state_rtp *create_rtp(const struct ast_sdp_options *options, enum ast_media_type media_type) { - struct ast_rtp_instance *rtp; + struct sdp_state_rtp *rtp; struct ast_rtp_engine_ice *ice; static struct ast_sockaddr address_rtp; struct ast_sockaddr *media_address = &address_rtp; @@ -167,38 +180,57 @@ static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options } } - rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL); + rtp = ao2_alloc_options(sizeof(*rtp), sdp_state_rtp_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!rtp) { + return NULL; + } + + rtp->instance = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL); + if (!rtp->instance) { ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", options->rtp_engine); + ao2_ref(rtp, -1); return NULL; } - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); + ast_rtp_instance_set_prop(rtp->instance, AST_RTP_PROPERTY_RTCP, + AST_RTP_INSTANCE_RTCP_STANDARD); + ast_rtp_instance_set_prop(rtp->instance, AST_RTP_PROPERTY_NAT, + options->rtp_symmetric); - if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { - ice->stop(rtp); + if (options->ice == AST_SDP_ICE_DISABLED + && (ice = ast_rtp_instance_get_ice(rtp->instance))) { + ice->stop(rtp->instance); } if (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO) { - ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); + ast_rtp_instance_dtmf_mode_set(rtp->instance, AST_RTP_DTMF_MODE_RFC2833); + ast_rtp_instance_set_prop(rtp->instance, AST_RTP_PROPERTY_DTMF, 1); } else if (options->dtmf == AST_SDP_DTMF_INBAND) { - ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_INBAND); + ast_rtp_instance_dtmf_mode_set(rtp->instance, AST_RTP_DTMF_MODE_INBAND); } - if (media_type == AST_MEDIA_TYPE_AUDIO && - (options->tos_audio || options->cos_audio)) { - ast_rtp_instance_set_qos(rtp, options->tos_audio, - options->cos_audio, "SIP RTP Audio"); - } else if (media_type == AST_MEDIA_TYPE_VIDEO && - (options->tos_video || options->cos_video)) { - ast_rtp_instance_set_qos(rtp, options->tos_video, - options->cos_video, "SIP RTP Video"); + switch (media_type) { + case AST_MEDIA_TYPE_AUDIO: + if (options->tos_audio || options->cos_audio) { + ast_rtp_instance_set_qos(rtp->instance, options->tos_audio, + options->cos_audio, "SIP RTP Audio"); + } + break; + case AST_MEDIA_TYPE_VIDEO: + if (options->tos_video || options->cos_video) { + ast_rtp_instance_set_qos(rtp->instance, options->tos_video, + options->cos_video, "SIP RTP Video"); + } + break; + case AST_MEDIA_TYPE_IMAGE: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_END: + break; } - ast_rtp_instance_set_last_rx(rtp, time(NULL)); + ast_rtp_instance_set_last_rx(rtp->instance, time(NULL)); return rtp; } @@ -278,8 +310,8 @@ static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const st switch (state_stream->type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - state_stream->instance = create_rtp(options, state_stream->type); - if (!state_stream->instance) { + state_stream->rtp = create_rtp(options, state_stream->type); + if (!state_stream->rtp) { sdp_state_stream_free(state_stream); sdp_state_capabilities_free(capabilities); return NULL; @@ -413,11 +445,11 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( sdp_state->proposed_capabilities->topology, stream_index)) == AST_MEDIA_TYPE_VIDEO); stream_state = sdp_state_get_stream(sdp_state, stream_index); - if (!stream_state) { + if (!stream_state || !stream_state->rtp) { return NULL; } - return stream_state->instance; + return stream_state->rtp->instance; } struct ast_udptl *ast_sdp_state_get_udptl_instance( @@ -467,7 +499,7 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_ stream_index))) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - ast_rtp_instance_get_local_address(stream_state->instance, address); + ast_rtp_instance_get_local_address(stream_state->rtp->instance, address); break; case AST_MEDIA_TYPE_IMAGE: ast_udptl_get_us(stream_state->udptl->instance, address); @@ -730,7 +762,7 @@ static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_st switch (joint_state_stream->type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - joint_state_stream->instance = ao2_bump(local_state_stream->instance); + joint_state_stream->rtp = ao2_bump(local_state_stream->rtp); if (is_local) { break; } @@ -744,8 +776,8 @@ static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_st ast_rtp_codecs_payloads_xover(codecs, codecs, NULL); } ast_rtp_codecs_payloads_copy(codecs, - ast_rtp_instance_get_codecs(joint_state_stream->instance), - joint_state_stream->instance); + ast_rtp_instance_get_codecs(joint_state_stream->rtp->instance), + joint_state_stream->rtp->instance); break; case AST_MEDIA_TYPE_IMAGE: joint_state_stream->udptl = ao2_bump(local_state_stream->udptl); @@ -777,9 +809,9 @@ static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_st switch (new_stream_type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - joint_state_stream->instance = create_rtp(sdp_state->options, + joint_state_stream->rtp = create_rtp(sdp_state->options, new_stream_type); - if (!joint_state_stream->instance) { + if (!joint_state_stream->rtp) { ast_stream_free(joint_stream); sdp_state_stream_free(joint_state_stream); goto fail; @@ -954,24 +986,33 @@ static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instanc * sides. * * \param state The SDP state in which SDPs have been negotiated - * \param rtp The RTP instance that is being updated + * \param rtp The RTP wrapper that is being updated * \param options Our locally-supported SDP options * \param remote_sdp The SDP we most recently received * \param remote_m_line The remote SDP stream that corresponds to the RTP instance we are modifying */ -static void update_rtp_after_merge(const struct ast_sdp_state *state, struct ast_rtp_instance *rtp, +static void update_rtp_after_merge(const struct ast_sdp_state *state, + struct sdp_state_rtp *rtp, const struct ast_sdp_options *options, const struct ast_sdp *remote_sdp, const struct ast_sdp_m_line *remote_m_line) { - if (ast_sdp_options_get_rtcp_mux(options) && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1)) { - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX); + if (!rtp) { + /* This is a dummy stream */ + return; + } + + if (ast_sdp_options_get_rtcp_mux(options) + && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1)) { + ast_rtp_instance_set_prop(rtp->instance, AST_RTP_PROPERTY_RTCP, + AST_RTP_INSTANCE_RTCP_MUX); } else { - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_STANDARD); + ast_rtp_instance_set_prop(rtp->instance, AST_RTP_PROPERTY_RTCP, + AST_RTP_INSTANCE_RTCP_STANDARD); } if (ast_sdp_options_get_ice(options) == AST_SDP_ICE_ENABLED_STANDARD) { - update_ice(state, rtp, options, remote_sdp, remote_m_line); + update_ice(state, rtp->instance, options, remote_sdp, remote_m_line); } } @@ -1000,6 +1041,11 @@ static void update_udptl_after_merge(const struct ast_sdp_state *state, struct s unsigned int fax_max_datagram; struct ast_sockaddr *addrs; + if (!udptl) { + /* This is a dummy stream */ + return; + } + a_line = ast_sdp_m_find_attribute(remote_m_line, "t38faxmaxdatagram", -1); if (!a_line) { a_line = ast_sdp_m_find_attribute(remote_m_line, "t38maxdatagram", -1); @@ -1103,7 +1149,7 @@ static int merge_sdps(struct ast_sdp_state *sdp_state, const struct ast_sdp *rem switch (ast_stream_get_type(ast_stream_topology_get_stream(joint_capabilities->topology, i))) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - update_rtp_after_merge(sdp_state, state_stream->instance, sdp_state->options, + update_rtp_after_merge(sdp_state, state_stream->rtp, sdp_state->options, remote_sdp, ast_sdp_get_m(remote_sdp, i)); break; case AST_MEDIA_TYPE_IMAGE: @@ -1312,123 +1358,163 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s struct ast_format_cap *caps; int i; int rtp_code; + int rtp_port; int min_packet_size = 0; int max_packet_size = 0; enum ast_media_type media_type; char tmp[64]; - struct ast_sockaddr address_rtp; + struct sdp_state_stream *stream_state; struct ast_rtp_instance *rtp; struct ast_sdp_a_line *a_line; stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); - rtp = AST_VECTOR_GET(&capabilities->streams, stream_index)->instance; ast_assert(sdp && options && stream); + caps = ast_stream_get_formats(stream); + + stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); + if (stream_state->rtp && caps && ast_format_cap_count(caps)) { + rtp = stream_state->rtp->instance; + } else { + /* This is a disabled stream */ + rtp = NULL; + } + if (rtp) { + struct ast_sockaddr address_rtp; + if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_rtp)) { return -1; } + rtp_port = ast_sockaddr_port(&address_rtp); } else { - ast_sockaddr_setnull(&address_rtp); + rtp_port = 0; } m_line = ast_sdp_m_alloc( ast_codec_media_type2str(ast_stream_get_type(stream)), - ast_sockaddr_port(&address_rtp), 1, + rtp_port, 1, options->encryption != AST_SDP_ENCRYPTION_DISABLED ? "RTP/SAVP" : "RTP/AVP", NULL); if (!m_line) { return -1; } - caps = ast_stream_get_formats(stream); + if (rtp_port) { + /* Stream is not declined/disabled */ + for (i = 0; i < ast_format_cap_count(caps); i++) { + struct ast_format *format = ast_format_cap_get_format(caps, i); - for (i = 0; i < ast_format_cap_count(caps); i++) { - struct ast_format *format = ast_format_cap_get_format(caps, i); + rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, + format, 0); + if (rtp_code == -1) { + ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", + ast_format_get_name(format)); + ao2_ref(format, -1); + continue; + } - if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) { - ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); - ao2_ref(format, -1); - continue; - } + if (ast_sdp_m_add_format(m_line, options, rtp_code, 1, format, 0)) { + ast_sdp_m_free(m_line); + ao2_ref(format, -1); + return -1; + } + + if (ast_format_get_maximum_ms(format) + && ((ast_format_get_maximum_ms(format) < max_packet_size) + || !max_packet_size)) { + max_packet_size = ast_format_get_maximum_ms(format); + } - if (ast_sdp_m_add_format(m_line, options, rtp_code, 1, format, 0)) { - ast_sdp_m_free(m_line); ao2_ref(format, -1); - return -1; } - if (ast_format_get_maximum_ms(format) && - ((ast_format_get_maximum_ms(format) < max_packet_size) || !max_packet_size)) { - max_packet_size = ast_format_get_maximum_ms(format); + media_type = ast_stream_get_type(stream); + if (media_type != AST_MEDIA_TYPE_VIDEO + && (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO)) { + i = AST_RTP_DTMF; + rtp_code = ast_rtp_codecs_payload_code( + ast_rtp_instance_get_codecs(rtp), 0, NULL, i); + if (-1 < rtp_code) { + if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) { + ast_sdp_m_free(m_line); + return -1; + } + + snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); + a_line = ast_sdp_a_alloc("fmtp", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + } } - ao2_ref(format, -1); - } + /* If ptime is set add it as an attribute */ + min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); + if (!min_packet_size) { + min_packet_size = ast_format_cap_get_framing(caps); + } + if (min_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", min_packet_size); - media_type = ast_stream_get_type(stream); - if (rtp && media_type != AST_MEDIA_TYPE_VIDEO - && (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO)) { - i = AST_RTP_DTMF; - rtp_code = ast_rtp_codecs_payload_code( - ast_rtp_instance_get_codecs(rtp), 0, NULL, i); - if (-1 < rtp_code) { - if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) { + a_line = ast_sdp_a_alloc("ptime", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } + } - snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); - a_line = ast_sdp_a_alloc("fmtp", tmp); + if (max_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", max_packet_size); + a_line = ast_sdp_a_alloc("maxptime", tmp); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } } - } - if (ast_sdp_m_get_a_count(m_line) == 0) { - ast_sdp_m_free(m_line); - return 0; - } - - /* If ptime is set add it as an attribute */ - min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); - if (!min_packet_size) { - min_packet_size = ast_format_cap_get_framing(caps); - } - if (min_packet_size) { - snprintf(tmp, sizeof(tmp), "%d", min_packet_size); - - a_line = ast_sdp_a_alloc("ptime", tmp); + a_line = ast_sdp_a_alloc(ast_sdp_state_get_locally_held(sdp_state, stream_index) + ? "sendonly" : "sendrecv", ""); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } - } - if (max_packet_size) { - snprintf(tmp, sizeof(tmp), "%d", max_packet_size); - a_line = ast_sdp_a_alloc("maxptime", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); + add_ssrc_attributes(m_line, options, rtp); + } else { + /* Declined/disabled stream */ + struct ast_sdp_payload *payload; + const char *fmt; + + /* + * Add a static payload type placeholder to the declined/disabled stream. + * + * XXX We should use the default payload type in the received offer but + * we don't have that available. + */ + switch (ast_stream_get_type(stream)) { + default: + case AST_MEDIA_TYPE_AUDIO: + fmt = "0"; /* ulaw */ + break; + case AST_MEDIA_TYPE_VIDEO: + fmt = "31"; /* H.261 */ + break; + } + payload = ast_sdp_payload_alloc(fmt); + if (!payload || ast_sdp_m_add_payload(m_line, payload)) { + ast_sdp_payload_free(payload); ast_sdp_m_free(m_line); return -1; } } - a_line = ast_sdp_a_alloc(ast_sdp_state_get_locally_held(sdp_state, stream_index) ? "sendonly" : "sendrecv", ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - - add_ssrc_attributes(m_line, options, rtp); - if (ast_sdp_add_m(sdp, m_line)) { ast_sdp_m_free(m_line); return -1; @@ -1465,27 +1551,37 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp struct ast_sdp_m_line *m_line; struct ast_sdp_payload *payload; char tmp[64]; - struct ast_sockaddr address_udptl; struct sdp_state_udptl *udptl; struct ast_sdp_a_line *a_line; struct sdp_state_stream *stream_state; + int udptl_port; stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); - udptl = AST_VECTOR_GET(&capabilities->streams, stream_index)->udptl; ast_assert(sdp && options && stream); + stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); + if (stream_state->udptl) { + udptl = stream_state->udptl; + } else { + /* This is a disabled stream */ + udptl = NULL; + } + if (udptl) { + struct ast_sockaddr address_udptl; + if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_udptl)) { return -1; } + udptl_port = ast_sockaddr_port(&address_udptl); } else { - ast_sockaddr_setnull(&address_udptl); + udptl_port = 0; } m_line = ast_sdp_m_alloc( ast_codec_media_type2str(ast_stream_get_type(stream)), - ast_sockaddr_port(&address_udptl), 1, "udptl", NULL); + udptl_port, 1, "udptl", NULL); if (!m_line) { return -1; } @@ -1497,97 +1593,100 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp return -1; } - stream_state = sdp_state_get_stream(sdp_state, stream_index); - - snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version); - a_line = ast_sdp_a_alloc("T38FaxVersion", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - - snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(stream_state->t38_local_params.rate)); - a_line = ast_sdp_a_alloc("T38FaxMaxBitRate", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + if (udptl_port) { + /* Stream is not declined/disabled */ + stream_state = sdp_state_get_stream(sdp_state, stream_index); - if (stream_state->t38_local_params.fill_bit_removal) { - a_line = ast_sdp_a_alloc("T38FaxFillBitRemoval", ""); + snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version); + a_line = ast_sdp_a_alloc("T38FaxVersion", tmp); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } - } - if (stream_state->t38_local_params.transcoding_mmr) { - a_line = ast_sdp_a_alloc("T38FaxTranscodingMMR", ""); + snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(stream_state->t38_local_params.rate)); + a_line = ast_sdp_a_alloc("T38FaxMaxBitRate", tmp); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } - } - if (stream_state->t38_local_params.transcoding_jbig) { - a_line = ast_sdp_a_alloc("T38FaxTranscodingJBIG", ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; + if (stream_state->t38_local_params.fill_bit_removal) { + a_line = ast_sdp_a_alloc("T38FaxFillBitRemoval", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } } - } - switch (stream_state->t38_local_params.rate_management) { - case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF: - a_line = ast_sdp_a_alloc("T38FaxRateManagement", "transferredTCF"); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; + if (stream_state->t38_local_params.transcoding_mmr) { + a_line = ast_sdp_a_alloc("T38FaxTranscodingMMR", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } } - break; - case AST_T38_RATE_MANAGEMENT_LOCAL_TCF: - a_line = ast_sdp_a_alloc("T38FaxRateManagement", "localTCF"); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; + + if (stream_state->t38_local_params.transcoding_jbig) { + a_line = ast_sdp_a_alloc("T38FaxTranscodingJBIG", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } } - break; - } - snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(udptl->instance)); - a_line = ast_sdp_a_alloc("T38FaxMaxDatagram", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + switch (stream_state->t38_local_params.rate_management) { + case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF: + a_line = ast_sdp_a_alloc("T38FaxRateManagement", "transferredTCF"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; + case AST_T38_RATE_MANAGEMENT_LOCAL_TCF: + a_line = ast_sdp_a_alloc("T38FaxRateManagement", "localTCF"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; + } - switch (ast_udptl_get_error_correction_scheme(udptl->instance)) { - case UDPTL_ERROR_CORRECTION_NONE: - break; - case UDPTL_ERROR_CORRECTION_FEC: - a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPFEC"); + snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(udptl->instance)); + a_line = ast_sdp_a_alloc("T38FaxMaxDatagram", tmp); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } - break; - case UDPTL_ERROR_CORRECTION_REDUNDANCY: - a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPRedundancy"); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; + + switch (ast_udptl_get_error_correction_scheme(udptl->instance)) { + case UDPTL_ERROR_CORRECTION_NONE: + break; + case UDPTL_ERROR_CORRECTION_FEC: + a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPFEC"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; + case UDPTL_ERROR_CORRECTION_REDUNDANCY: + a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPRedundancy"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + break; } - break; } if (ast_sdp_add_m(sdp, m_line)) { diff --git a/tests/test_sdp.c b/tests/test_sdp.c index 408888fc007..79b9e7b2c92 100644 --- a/tests/test_sdp.c +++ b/tests/test_sdp.c @@ -630,7 +630,7 @@ AST_TEST_DEFINE(sdp_to_topology) } if (ast_stream_topology_get_count(topology) != 3) { - ast_test_status_update(test, "Unexpected topology count '%d'. Expecting 2\n", + ast_test_status_update(test, "Unexpected topology count '%d'. Expecting 3\n", ast_stream_topology_get_count(topology)); res = AST_TEST_FAIL; goto end; @@ -669,11 +669,9 @@ static int validate_merged_sdp(struct ast_test *test, const struct ast_sdp *sdp) } m_line = ast_sdp_get_m(sdp, 0); - if (validate_m_line(test, m_line, "audio", 1)) { return -1; } - if (validate_rtpmap(test, m_line, "PCMU")) { return -1; } @@ -682,29 +680,29 @@ static int validate_merged_sdp(struct ast_test *test, const struct ast_sdp *sdp) if (!validate_rtpmap(test, m_line, "PCMA")) { return -1; } - if (!validate_rtpmap(test, m_line, "G722")) { return -1; } - if (!validate_rtpmap(test, m_line, "opus")) { return -1; } m_line = ast_sdp_get_m(sdp, 1); - if (validate_m_line(test, m_line, "video", 1)) { return -1; } - if (validate_rtpmap(test, m_line, "VP8")) { return -1; } - if (!validate_rtpmap(test, m_line, "H264")) { return -1; } + m_line = ast_sdp_get_m(sdp, 2); + if (validate_m_line(test, m_line, "image", 1)) { + return -1; + } + return 0; } @@ -719,10 +717,12 @@ AST_TEST_DEFINE(sdp_merge_symmetric) static const struct sdp_format offerer_formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, }; static const struct sdp_format answerer_formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw" }, { AST_MEDIA_TYPE_VIDEO, "vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, }; switch(cmd) { @@ -795,8 +795,10 @@ AST_TEST_DEFINE(sdp_merge_crisscross) static const struct sdp_format offerer_formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, }; static const struct sdp_format answerer_formats[] = { + { AST_MEDIA_TYPE_IMAGE, "t38" }, { AST_MEDIA_TYPE_VIDEO, "vp8" }, { AST_MEDIA_TYPE_AUDIO, "ulaw" }, }; @@ -862,6 +864,153 @@ AST_TEST_DEFINE(sdp_merge_crisscross) return res; } +static int validate_merged_sdp_asymmetric(struct ast_test *test, const struct ast_sdp *sdp, int is_offer) +{ + struct ast_sdp_m_line *m_line; + const char *side = is_offer ? "Offer side" : "Answer side"; + + if (!sdp) { + ast_test_status_update(test, "%s does not have a SDP\n", side); + return -1; + } + + /* Stream 0 */ + m_line = ast_sdp_get_m(sdp, 0); + if (validate_m_line(test, m_line, "audio", 1)) { + return -1; + } + if (!m_line->port) { + ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 0, "n't"); + return -1; + } + if (validate_rtpmap(test, m_line, "PCMU")) { + return -1; + } + + /* The other audio formats should *NOT* be present */ + if (!validate_rtpmap(test, m_line, "PCMA")) { + return -1; + } + if (!validate_rtpmap(test, m_line, "G722")) { + return -1; + } + if (!validate_rtpmap(test, m_line, "opus")) { + return -1; + } + + /* The remaining streams should be declined */ + + /* Stream 1 */ + m_line = ast_sdp_get_m(sdp, 1); + if (validate_m_line(test, m_line, "audio", 1)) { + return -1; + } + if (m_line->port) { + ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 1, ""); + return -1; + } + + /* Stream 2 */ + m_line = ast_sdp_get_m(sdp, 2); + if (validate_m_line(test, m_line, "video", 1)) { + return -1; + } + if (m_line->port) { + ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 2, ""); + return -1; + } + + /* Stream 3 */ + m_line = ast_sdp_get_m(sdp, 3); + if (validate_m_line(test, m_line, "image", 1)) { + return -1; + } + if (m_line->port) { + ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 3, ""); + return -1; + } + + return 0; +} + +AST_TEST_DEFINE(sdp_merge_asymmetric) +{ + enum ast_test_result_state res = AST_TEST_PASS; + struct ast_sdp_state *sdp_state_offerer = NULL; + struct ast_sdp_state *sdp_state_answerer = NULL; + const struct ast_sdp *offerer_sdp; + const struct ast_sdp *answerer_sdp; + + static const struct sdp_format offerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + { AST_MEDIA_TYPE_VIDEO, "h261" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, + }; + static const struct sdp_format answerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + }; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_merge_asymmetric"; + info->category = "/main/sdp/"; + info->summary = "Merge two SDPs with an asymmetric number of streams"; + info->description = + "SDP 1 offers a four stream topology: Audio,Audio,Video,T.38\n" + "SDP 2 only has a single audio stream topology\n" + "We ensure that both local SDPs have the expected stream types and\n" + "the expected declined streams"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, NULL); + if (!sdp_state_offerer) { + res = AST_TEST_FAIL; + goto end; + } + + sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats, NULL); + if (!sdp_state_answerer) { + res = AST_TEST_FAIL; + goto end; + } + + offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); + if (!offerer_sdp) { + res = AST_TEST_FAIL; + goto end; + } + + ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp); + answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); + if (!answerer_sdp) { + res = AST_TEST_FAIL; + goto end; + } + + ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp); + +#if defined(XXX_TODO_NEED_TO_HANDLE_DECLINED_STREAMS_ON_OFFER_SIDE) + /* Get the offerer SDP again because it's now going to be the joint SDP */ + offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); + if (validate_merged_sdp_asymmetric(test, offerer_sdp, 1)) { + res = AST_TEST_FAIL; + } +#endif + if (validate_merged_sdp_asymmetric(test, answerer_sdp, 0)) { + res = AST_TEST_FAIL; + } + +end: + ast_sdp_state_free(sdp_state_offerer); + ast_sdp_state_free(sdp_state_answerer); + + return res; +} + static int validate_ssrc(struct ast_test *test, struct ast_sdp_m_line *m_line, struct ast_rtp_instance *rtp) { @@ -976,6 +1125,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(sdp_to_topology); AST_TEST_UNREGISTER(sdp_merge_symmetric); AST_TEST_UNREGISTER(sdp_merge_crisscross); + AST_TEST_UNREGISTER(sdp_merge_asymmetric); AST_TEST_UNREGISTER(sdp_ssrc_attributes); return 0; @@ -990,6 +1140,7 @@ static int load_module(void) AST_TEST_REGISTER(sdp_to_topology); AST_TEST_REGISTER(sdp_merge_symmetric); AST_TEST_REGISTER(sdp_merge_crisscross); + AST_TEST_REGISTER(sdp_merge_asymmetric); AST_TEST_REGISTER(sdp_ssrc_attributes); return AST_MODULE_LOAD_SUCCESS; From 16785c0908791b0bd583599ea9ce0ad5cb479f81 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 5 May 2017 14:30:40 -0500 Subject: [PATCH 1254/1578] SDP: Add interface_address to specify our address to use. When we optionally set the interface_address we are forcing the media to go out a specific interface address. This allows us to optionally have the media go out the interface that SIP signalling came in on or if we are configured to have the media always go out a specific address. Change-Id: I160d9fac322a075bd2557b430632544178196189 --- include/asterisk/sdp_options.h | 60 ++++++++++++---------------------- main/sdp_options.c | 3 +- main/sdp_private.h | 6 ++-- main/sdp_state.c | 27 ++++++++------- 4 files changed, 40 insertions(+), 56 deletions(-) diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index 9c699a2f25f..f49b79483bd 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -124,6 +124,26 @@ void ast_sdp_options_set_media_address(struct ast_sdp_options *options, */ const char *ast_sdp_options_get_media_address(const struct ast_sdp_options *options); +/*! + * \since 15.0.0 + * \brief Set SDP Options interface_address + * + * \param options SDP Options + * \param interface_address + */ +void ast_sdp_options_set_interface_address(struct ast_sdp_options *options, + const char *interface_address); + +/*! + * \since 15.0.0 + * \brief Get SDP Options interface_address + * + * \param options SDP Options + * + * \returns interface_address + */ +const char *ast_sdp_options_get_interface_address(const struct ast_sdp_options *options); + /*! * \since 15.0.0 * \brief Set SDP Options sdpowner @@ -184,26 +204,6 @@ void ast_sdp_options_set_rtp_engine(struct ast_sdp_options *options, */ const char *ast_sdp_options_get_rtp_engine(const struct ast_sdp_options *options); -/*! - * \since 15.0.0 - * \brief Set SDP Options bind_rtp_to_media_address - * - * \param options SDP Options - * \param bind_rtp_to_media_address - */ -void ast_sdp_options_set_bind_rtp_to_media_address(struct ast_sdp_options *options, - unsigned int bind_rtp_to_media_address); - -/*! - * \since 15.0.0 - * \brief Get SDP Options bind_rtp_to_media_address - * - * \param options SDP Options - * - * \returns bind_rtp_to_media_address - */ -unsigned int ast_sdp_options_get_bind_rtp_to_media_address(const struct ast_sdp_options *options); - /*! * \since 15.0.0 * \brief Set SDP Options rtp_symmetric @@ -503,26 +503,6 @@ void ast_sdp_options_set_udptl_far_max_datagram(struct ast_sdp_options *options, */ unsigned int ast_sdp_options_get_udptl_far_max_datagram(const struct ast_sdp_options *options); -/*! - * \since 15.0.0 - * \brief Set SDP Options bind_udptl_to_media_address - * - * \param options SDP Options - * \param bind_udptl_to_media_address - */ -void ast_sdp_options_set_bind_udptl_to_media_address(struct ast_sdp_options *options, - unsigned int bind_udptl_to_media_address); - -/*! - * \since 15.0.0 - * \brief Get SDP Options bind_udptl_to_media_address - * - * \param options SDP Options - * - * \returns bind_udptl_to_media_address - */ -unsigned int ast_sdp_options_get_bind_udptl_to_media_address(const struct ast_sdp_options *options); - /*! * \since 15.0.0 * \brief Enable setting SSRC level attributes on SDPs diff --git a/main/sdp_options.c b/main/sdp_options.c index 9b57e189fb3..ab8fb297397 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -55,12 +55,11 @@ type ast_sdp_options_get_##field(const struct ast_sdp_options *options) \ } \ DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(media_address, 0); +DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(interface_address, 0); DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpowner, 0); DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpsession, 0); DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(rtp_engine, 0); -DEFINE_GETTERS_SETTERS_FOR(unsigned int, bind_rtp_to_media_address); -DEFINE_GETTERS_SETTERS_FOR(unsigned int, bind_udptl_to_media_address); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_symmetric); DEFINE_GETTERS_SETTERS_FOR(enum ast_t38_ec_modes, udptl_error_correction); diff --git a/main/sdp_private.h b/main/sdp_private.h index c90a57485e1..a0b63df032d 100644 --- a/main/sdp_private.h +++ b/main/sdp_private.h @@ -24,8 +24,10 @@ struct ast_sdp_options { AST_DECLARE_STRING_FIELDS( - /*! Optional media address to use in SDP */ + /*! Media address to use in SDP */ AST_STRING_FIELD(media_address); + /*! Optional address of the interface media should use. */ + AST_STRING_FIELD(interface_address); /*! SDP origin username */ AST_STRING_FIELD(sdpowner); /*! SDP session name */ @@ -34,8 +36,6 @@ struct ast_sdp_options { AST_STRING_FIELD(rtp_engine); ); struct { - unsigned int bind_rtp_to_media_address:1; - unsigned int bind_udptl_to_media_address:1; unsigned int rtp_symmetric:1; unsigned int udptl_symmetric:1; unsigned int rtp_ipv6:1; diff --git a/main/sdp_state.c b/main/sdp_state.c index 3a87a81e23b..0da93e4acad 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -150,13 +150,15 @@ static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options { struct ast_rtp_instance *rtp; struct ast_rtp_engine_ice *ice; - struct ast_sockaddr temp_media_address; static struct ast_sockaddr address_rtp; - struct ast_sockaddr *media_address = &address_rtp; + struct ast_sockaddr *media_address = &address_rtp; - if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { - ast_sockaddr_parse(&temp_media_address, options->media_address, 0); - media_address = &temp_media_address; + if (!ast_strlen_zero(options->interface_address)) { + if (!ast_sockaddr_parse(&address_rtp, options->interface_address, 0)) { + ast_log(LOG_ERROR, "Attempted to bind RTP to invalid media address: %s\n", + options->interface_address); + return NULL; + } } else { if (ast_check_ipv6()) { ast_sockaddr_parse(&address_rtp, "::", 0); @@ -165,7 +167,8 @@ static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options } } - if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { + rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL); + if (!rtp) { ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", options->rtp_engine); return NULL; @@ -204,13 +207,15 @@ static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options static struct sdp_state_udptl *create_udptl(const struct ast_sdp_options *options) { struct sdp_state_udptl *udptl; - struct ast_sockaddr temp_media_address; static struct ast_sockaddr address_udptl; - struct ast_sockaddr *media_address = &address_udptl; + struct ast_sockaddr *media_address = &address_udptl; - if (options->bind_udptl_to_media_address && !ast_strlen_zero(options->media_address)) { - ast_sockaddr_parse(&temp_media_address, options->media_address, 0); - media_address = &temp_media_address; + if (!ast_strlen_zero(options->interface_address)) { + if (!ast_sockaddr_parse(&address_udptl, options->interface_address, 0)) { + ast_log(LOG_ERROR, "Attempted to bind UDPTL to invalid media address: %s\n", + options->interface_address); + return NULL; + } } else { if (ast_check_ipv6()) { ast_sockaddr_parse(&address_udptl, "::", 0); From c2906dfa05ad6f2d3b952d21d09178e724180e95 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 28 Apr 2017 11:53:37 -0500 Subject: [PATCH 1255/1578] SDP: Remove sdp_state.remote_capabilities The sdp_state.remote_capabilities was only used inside merge_sdps() and subsequent calls to merge_sdps() by re-INVITE's would leak them. Change-Id: I0ceb7838ea044cc913e8ad4a255c39c9740ae0ce --- main/sdp_state.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/main/sdp_state.c b/main/sdp_state.c index 0da93e4acad..a9979eb7d96 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -340,9 +340,7 @@ struct ast_sdp_state { struct sdp_state_capabilities *negotiated_capabilities; /*! Proposed capabilities */ struct sdp_state_capabilities *proposed_capabilities; - /*! Remote capabilities, learned through remote SDP */ - struct ast_stream_topology *remote_capabilities; - /*! Local SDP. Generated via the options and local capabilities. */ + /*! Local SDP. Generated via the options and currently negotiated/proposed capabilities. */ struct ast_sdp *local_sdp; /*! SDP options. Configured options beyond media capabilities. */ struct ast_sdp_options *options; @@ -389,7 +387,6 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state) sdp_state_capabilities_free(sdp_state->negotiated_capabilities); sdp_state_capabilities_free(sdp_state->proposed_capabilities); - ast_stream_topology_free(sdp_state->remote_capabilities); ast_sdp_free(sdp_state->local_sdp); ast_sdp_options_free(sdp_state->options); ast_sdp_translator_free(sdp_state->translator); @@ -1007,15 +1004,17 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta static int merge_sdps(struct ast_sdp_state *sdp_state, const struct ast_sdp *remote_sdp) { struct sdp_state_capabilities *joint_capabilities; + struct ast_stream_topology *remote_capabilities; int i; - sdp_state->remote_capabilities = ast_get_topology_from_sdp(remote_sdp); - if (!sdp_state->remote_capabilities) { + remote_capabilities = ast_get_topology_from_sdp(remote_sdp); + if (!remote_capabilities) { return -1; } joint_capabilities = merge_capabilities(sdp_state->proposed_capabilities, - sdp_state->remote_capabilities, sdp_state->options, 0); + remote_capabilities, sdp_state->options, 0); + ast_stream_topology_free(remote_capabilities); if (!joint_capabilities) { return -1; } @@ -1114,9 +1113,6 @@ int ast_sdp_state_reset(struct ast_sdp_state *sdp_state) ast_sdp_free(sdp_state->local_sdp); sdp_state->local_sdp = NULL; - ast_stream_topology_free(sdp_state->remote_capabilities); - sdp_state->remote_capabilities = NULL; - set_proposed_capabilities(sdp_state, NULL); sdp_state->role = SDP_ROLE_NOT_SET; From b8659be9b0028aa2655527772852ae6d740c0fb6 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 27 Apr 2017 19:37:53 -0500 Subject: [PATCH 1256/1578] SDP: Make process possible multiple fmtp attributes per rtpmap. Change-Id: Ie7511008d82b59590e0eb520a21b5e1da4bd7349 --- include/asterisk/sdp.h | 70 ++++++++++++++++++++++++++-- main/sdp.c | 102 ++++++++++++++++++++++++++++++----------- tests/test_sdp.c | 73 +++++++++++++++++++++++++++-- 3 files changed, 210 insertions(+), 35 deletions(-) diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h index 8aa9e3b7fae..224a0e5a30c 100644 --- a/include/asterisk/sdp.h +++ b/include/asterisk/sdp.h @@ -561,7 +561,40 @@ struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line, struct ast_sdp_t_line *t_line); /*! - * \brief Find an attribute on the top-level SDP + * \brief Find the first attribute match index in the top-level SDP + * + * \note This will not search within streams for the given attribute. + * + * \param sdp The SDP in which to search + * \param attr_name The name of the attribute to search for + * \param payload Optional payload number to search for. If irrelevant, set to -1 + * + * \retval index of attribute line on success. + * \retval -1 on failure or not found. + * + * \since 15.0.0 + */ +int ast_sdp_find_a_first(const struct ast_sdp *sdp, const char *attr_name, int payload); + +/*! + * \brief Find the next attribute match index in the top-level SDP + * + * \note This will not search within streams for the given attribute. + * + * \param sdp The SDP in which to search + * \param last The last matching index found + * \param attr_name The name of the attribute to search for + * \param payload Optional payload number to search for. If irrelevant, set to -1 + * + * \retval index of attribute line on success. + * \retval -1 on failure or not found. + * + * \since 15.0.0 + */ +int ast_sdp_find_a_next(const struct ast_sdp *sdp, int last, const char *attr_name, int payload); + +/*! + * \brief Find an attribute in the top-level SDP * * \note This will not search within streams for the given attribute. * @@ -578,9 +611,40 @@ struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp, const char *attr_name, int payload); /*! - * \brief Find an attribute on an SDP stream (m-line) + * \brief Find the first attribute match index in an SDP stream (m-line) * - * \param sdp The SDP in which to search + * \param m_line The SDP m-line in which to search + * \param attr_name The name of the attribute to search for + * \param payload Optional payload number to search for. If irrelevant, set to -1 + * + * \retval index of attribute line on success. + * \retval -1 on failure or not found. + * + * \since 15.0.0 + */ +int ast_sdp_m_find_a_first(const struct ast_sdp_m_line *m_line, const char *attr_name, + int payload); + +/*! + * \brief Find the next attribute match index in an SDP stream (m-line) + * + * \param m_line The SDP m-line in which to search + * \param last The last matching index found + * \param attr_name The name of the attribute to search for + * \param payload Optional payload number to search for. If irrelevant, set to -1 + * + * \retval index of attribute line on success. + * \retval -1 on failure or not found. + * + * \since 15.0.0 + */ +int ast_sdp_m_find_a_next(const struct ast_sdp_m_line *m_line, int last, + const char *attr_name, int payload); + +/*! + * \brief Find an attribute in an SDP stream (m-line) + * + * \param m_line The SDP m-line in which to search * \param attr_name The name of the attribute to search for * \param payload Optional payload number to search for. If irrelevant, set to -1 * diff --git a/main/sdp.c b/main/sdp.c index 019c6699f1a..bfb83e82fec 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -508,44 +508,81 @@ int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_opt || sdp_m_add_fmtp(m_line, format, rtp_code) ? -1 : 0; } -static struct ast_sdp_a_line *sdp_find_attribute_common(const struct ast_sdp_a_lines *a_lines, +static int sdp_find_a_common(const struct ast_sdp_a_lines *a_lines, int start, const char *attr_name, int payload) { struct ast_sdp_a_line *a_line; - int i; + int idx; + + ast_assert(-1 <= start); - for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) { + for (idx = start + 1; idx < AST_VECTOR_SIZE(a_lines); ++idx) { int a_line_payload; - a_line = AST_VECTOR_GET(a_lines, i); + a_line = AST_VECTOR_GET(a_lines, idx); if (strcmp(a_line->name, attr_name)) { continue; } if (payload >= 0) { int sscanf_res; + sscanf_res = sscanf(a_line->value, "%30d", &a_line_payload); if (sscanf_res == 1 && payload == a_line_payload) { - return a_line; + return idx; } } else { - return a_line; + return idx; } } - return NULL; + return -1; +} + +int ast_sdp_find_a_first(const struct ast_sdp *sdp, const char *attr_name, int payload) +{ + return sdp_find_a_common(sdp->a_lines, -1, attr_name, payload); +} + +int ast_sdp_find_a_next(const struct ast_sdp *sdp, int last, const char *attr_name, int payload) +{ + return sdp_find_a_common(sdp->a_lines, last, attr_name, payload); } struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp, const char *attr_name, int payload) { - return sdp_find_attribute_common(sdp->a_lines, attr_name, payload); + int idx; + + idx = ast_sdp_find_a_first(sdp, attr_name, payload); + if (idx < 0) { + return NULL; + } + return ast_sdp_get_a(sdp, idx); +} + +int ast_sdp_m_find_a_first(const struct ast_sdp_m_line *m_line, const char *attr_name, + int payload) +{ + return sdp_find_a_common(m_line->a_lines, -1, attr_name, payload); +} + +int ast_sdp_m_find_a_next(const struct ast_sdp_m_line *m_line, int last, + const char *attr_name, int payload) +{ + return sdp_find_a_common(m_line->a_lines, last, attr_name, payload); } struct ast_sdp_a_line *ast_sdp_m_find_attribute(const struct ast_sdp_m_line *m_line, const char *attr_name, int payload) { - return sdp_find_attribute_common(m_line->a_lines, attr_name, payload); + int idx; + + idx = ast_sdp_m_find_a_first(m_line, attr_name, payload); + if (idx < 0) { + return NULL; + } + return ast_sdp_m_get_a(m_line, idx); } struct ast_sdp_rtpmap *ast_sdp_rtpmap_alloc(int payload, const char *encoding_name, @@ -644,17 +681,8 @@ static struct ast_sdp_rtpmap *sdp_payload_get_rtpmap(const struct ast_sdp_m_line return ast_sdp_a_get_rtpmap(rtpmap_attr); } -/*! - * \brief Find and process fmtp attributes for a given payload - * - * \param m_line The stream on which to search for the fmtp attribute - * \param payload The specific fmtp attribute to search for - * \param codecs The current RTP codecs that have been built up - */ -static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload, - struct ast_rtp_codecs *codecs) +static void process_fmtp_value(const char *value, int payload, struct ast_rtp_codecs *codecs) { - struct ast_sdp_a_line *attr; char *param; char *param_start; char *param_end; @@ -662,13 +690,11 @@ static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload, struct ast_format *replace; struct ast_format *format; - attr = ast_sdp_m_find_attribute(m_line, "fmtp", payload); - if (!attr) { - return; - } - - /* Extract the "a=fmtp:%d %s" attribute parameter string after the payload type. */ - param_start = ast_skip_nonblanks(attr->value);/* Skip payload type */ + /* + * Extract the "a=fmtp:%d %s" attribute parameter string value which + * starts after the colon. + */ + param_start = ast_skip_nonblanks(value);/* Skip payload type */ param_start = ast_skip_blanks(param_start); param_end = ast_skip_nonblanks(param_start); if (param_end == param_start) { @@ -693,6 +719,28 @@ static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload, ao2_ref(format, -1); } +/*! + * \brief Find and process all fmtp attribute lines for a given payload + * + * \param m_line The stream on which to search for the fmtp attributes + * \param payload The specific fmtp attribute to search for + * \param codecs The current RTP codecs that have been built up + */ +static void process_fmtp_lines(const struct ast_sdp_m_line *m_line, int payload, + struct ast_rtp_codecs *codecs) +{ + const struct ast_sdp_a_line *a_line; + int idx; + + idx = ast_sdp_m_find_a_first(m_line, "fmtp", payload); + for (; 0 <= idx; idx = ast_sdp_m_find_a_next(m_line, idx, "fmtp", payload)) { + a_line = ast_sdp_m_get_a(m_line, idx); + ast_assert(a_line != NULL); + + process_fmtp_value(a_line->value, payload, codecs); + } +} + /* * Needed so we don't have an external function referenced as data. * The dynamic linker doesn't handle that very well. @@ -765,7 +813,7 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line, if (!ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, payload, m_line->type, rtpmap->encoding_name, options, rtpmap->clock_rate)) { /* Successfully mapped the payload type to format */ - process_fmtp(m_line, payload, codecs); + process_fmtp_lines(m_line, payload, codecs); } ast_sdp_rtpmap_free(rtpmap); } diff --git a/tests/test_sdp.c b/tests/test_sdp.c index 79b9e7b2c92..7eef3f741e8 100644 --- a/tests/test_sdp.c +++ b/tests/test_sdp.c @@ -276,6 +276,7 @@ AST_TEST_DEFINE(find_attr) enum ast_test_result_state res = AST_TEST_PASS; struct ast_sdp_m_line *m_line; struct ast_sdp_a_line *a_line; + int idx; switch(cmd) { case TEST_INIT: @@ -283,7 +284,7 @@ AST_TEST_DEFINE(find_attr) info->category = "/main/sdp/"; info->summary = "Ensure that finding attributes works as expected"; info->description = - "An SDP m-line is created, and two attributes are added.\n" + "A SDP m-line is created, and attributes are added.\n" "We then attempt a series of attribute-finding calls that are expected to work\n" "followed by a series of attribute-finding calls that are expected fo fail."; return AST_TEST_NOT_RUN; @@ -302,6 +303,12 @@ AST_TEST_DEFINE(find_attr) goto end; } ast_sdp_m_add_a(m_line, a_line); + a_line = ast_sdp_a_alloc("foo", "0 bee"); + if (!a_line) { + res = AST_TEST_FAIL; + goto end; + } + ast_sdp_m_add_a(m_line, a_line); a_line = ast_sdp_a_alloc("baz", "howdy"); if (!a_line) { @@ -312,21 +319,77 @@ AST_TEST_DEFINE(find_attr) /* These should work */ a_line = ast_sdp_m_find_attribute(m_line, "foo", 0); - if (!a_line) { + if (!a_line || strcmp(a_line->value, "0 bar")) { ast_test_status_update(test, "Failed to find attribute 'foo' with payload '0'\n"); res = AST_TEST_FAIL; } a_line = ast_sdp_m_find_attribute(m_line, "foo", -1); - if (!a_line) { + if (!a_line || strcmp(a_line->value, "0 bar")) { ast_test_status_update(test, "Failed to find attribute 'foo' with unspecified payload\n"); res = AST_TEST_FAIL; } a_line = ast_sdp_m_find_attribute(m_line, "baz", -1); - if (!a_line) { + if (!a_line || strcmp(a_line->value, "howdy")) { ast_test_status_update(test, "Failed to find attribute 'baz' with unspecified payload\n"); res = AST_TEST_FAIL; } + idx = ast_sdp_m_find_a_first(m_line, "foo", 0); + if (idx < 0) { + ast_test_status_update(test, "Failed to find first attribute 'foo' with payload '0'\n"); + res = AST_TEST_FAIL; + goto end; + } + a_line = ast_sdp_m_get_a(m_line, idx); + if (!a_line || strcmp(a_line->value, "0 bar")) { + ast_test_status_update(test, "Find first attribute 'foo' with payload '0' didn't match\n"); + res = AST_TEST_FAIL; + } + idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0); + if (idx < 0) { + ast_test_status_update(test, "Failed to find next attribute 'foo' with payload '0'\n"); + res = AST_TEST_FAIL; + goto end; + } + a_line = ast_sdp_m_get_a(m_line, idx); + if (!a_line || strcmp(a_line->value, "0 bee")) { + ast_test_status_update(test, "Find next attribute 'foo' with payload '0' didn't match\n"); + res = AST_TEST_FAIL; + } + idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0); + if (0 <= idx) { + ast_test_status_update(test, "Find next attribute 'foo' with payload '0' found too many\n"); + res = AST_TEST_FAIL; + } + + idx = ast_sdp_m_find_a_first(m_line, "foo", -1); + if (idx < 0) { + ast_test_status_update(test, "Failed to find first attribute 'foo' with unspecified payload\n"); + res = AST_TEST_FAIL; + goto end; + } + a_line = ast_sdp_m_get_a(m_line, idx); + if (!a_line || strcmp(a_line->value, "0 bar")) { + ast_test_status_update(test, "Find first attribute 'foo' with unspecified payload didn't match\n"); + res = AST_TEST_FAIL; + } + idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1); + if (idx < 0) { + ast_test_status_update(test, "Failed to find next attribute 'foo' with unspecified payload\n"); + res = AST_TEST_FAIL; + goto end; + } + a_line = ast_sdp_m_get_a(m_line, idx); + if (!a_line || strcmp(a_line->value, "0 bee")) { + ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload didn't match\n"); + res = AST_TEST_FAIL; + } + idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1); + if (0 <= idx) { + ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload found too many\n"); + res = AST_TEST_FAIL; + } + /* These should fail */ a_line = ast_sdp_m_find_attribute(m_line, "foo", 1); if (a_line) { @@ -345,7 +408,7 @@ AST_TEST_DEFINE(find_attr) } a_line = ast_sdp_m_find_attribute(m_line, "wibble", -1); if (a_line) { - ast_test_status_update(test, "Found non-existent attribute 'foo' with unspecified payload\n"); + ast_test_status_update(test, "Found non-existent attribute 'wibble' with unspecified payload\n"); res = AST_TEST_FAIL; } From 045dbcc2d6e6b28645fad2c16843305c50150d5b Mon Sep 17 00:00:00 2001 From: Ivan Poddubny Date: Thu, 11 May 2017 07:25:44 +0200 Subject: [PATCH 1257/1578] app_queue: Fix duplicate queue_log entries for EXITEMPTY and ABANDON There are 2 places in app_queue.c that log EXITEMPTY event: one in wait_our_turn, and another one in queue_exec in the loop trying to call an agent after wait_our_turn. In most cases it leads to logging EXITEMPTY twice. ABANDON is also logged on two places, and in the rare case when an agent and caller hang up simultaneously it's also possible to get duplicates in queue_log. This commit changes wait_our_turn to return -1 ("the caller should exit the queue") instead of 0 ("the caller's turn has arrived") in case of leaving when empty, so queue_exec skips the agent calling loop. Also, leave_queue is now executed only once in this case, because 2nd time is just a noop when the queue entry has already been removed. Also, it sets qe->handled to -1 to indicate that the call was not answered by an agent, but the necessary handling has already been done in order to avoid logging an extra ABANDON entry. ASTERISK-25665 #close Reported by: Ove Aursand Change-Id: I4578dd383bf2ac41589cf167865e8aaebcd4c11e --- apps/app_queue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 2389f0b1314..0f46d280cd8 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5465,7 +5465,8 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty, 0))) { *reason = QUEUE_LEAVEEMPTY; ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start)); - leave_queue(qe); + res = -1; + qe->handled = -1; break; } } @@ -6803,6 +6804,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer)); ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start)); record_abandoned(qe); + qe->handled = -1; ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer))); ast_autoservice_chan_hangup_peer(qe->chan, peer); ao2_ref(member, -1); From 808f2998085b78225addfd73289fdc6c473b7fa1 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 8 May 2017 16:56:32 -0400 Subject: [PATCH 1258/1578] res_pjsip: New endpoint option "refer_blind_progress" This option was added to turn off notifying the progress details on Blind Transfer. If this option is not set then the chan_pjsip will send NOTIFY "200 OK" immediately after "202 Accepted". Some SIP phones like Mitel/Aastra or Snom keep the line busy until receive "200 OK". ASTERISK-26333 #close Change-Id: Id606fbff2e02e967c02138457badc399144720f2 --- CHANGES | 9 ++++++ configs/samples/pjsip.conf.sample | 4 +++ ...d_add_ps_endpoints_refer_blind_progress.py | 30 +++++++++++++++++++ include/asterisk/res_pjsip.h | 2 ++ res/res_pjsip.c | 8 +++++ res/res_pjsip/pjsip_configuration.c | 1 + res/res_pjsip_refer.c | 20 +++++++++++-- 7 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/86bb1efa278d_add_ps_endpoints_refer_blind_progress.py diff --git a/CHANGES b/CHANGES index 9c8ed5b8e77..a881e75b73f 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,15 @@ app_queue --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ +res_pjsip +------------------ + * A new endpoint option "refer_blind_progress" was added to turn off notifying + the progress details on Blind Transfer. If this option is not set then + the chan_pjsip will send NOTIFY "200 OK" immediately after "202 Accepted". + On default is enabled. + Some SIP phones like Mitel/Aastra or Snom keep the line busy until + receive "200 OK". + res_rtp_asterisk ------------------ * Added the stun_blacklist option to rtp.conf. Some multihomed servers have diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 612649ec545..a992ff8b6bd 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -770,6 +770,10 @@ ; default is no. ;asymmetric_rtp_codec= ; Allow the sending and receiving codec to differ and ; not be automatically matched (default: "no") +;refer_blind_progress= ; Whether to notifies all the progress details on blind + ; transfer (default: "yes"). The value "no" is useful + ; for some SIP phones (Mitel/Aastra, Snom) which expect + ; a sip/frag "200 OK" after REFER has been accepted. ;==========================AUTH SECTION OPTIONS========================= ;[auth] diff --git a/contrib/ast-db-manage/config/versions/86bb1efa278d_add_ps_endpoints_refer_blind_progress.py b/contrib/ast-db-manage/config/versions/86bb1efa278d_add_ps_endpoints_refer_blind_progress.py new file mode 100644 index 00000000000..9b0f6d4d08a --- /dev/null +++ b/contrib/ast-db-manage/config/versions/86bb1efa278d_add_ps_endpoints_refer_blind_progress.py @@ -0,0 +1,30 @@ +"""add ps_endpoints.refer_blind_progress + +Revision ID: 86bb1efa278d +Revises: 1d0e332c32af +Create Date: 2017-05-08 16:52:36.615161 + +""" + +# revision identifiers, used by Alembic. +revision = '86bb1efa278d' +down_revision = '1d0e332c32af' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoints', sa.Column('refer_blind_progress', yesno_values)) + +def downgrade(): + op.drop_column('ps_endpoints', 'refer_blind_progress') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 6f44852b1e4..59f1710d1d7 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -767,6 +767,8 @@ struct ast_sip_endpoint { unsigned int asymmetric_rtp_codec; /*! Do we allow overlap dialling? */ unsigned int allow_overlap; + /*! Whether to notifies all the progress details on blind transfer */ + unsigned int refer_blind_progress; }; /*! URI parameter for symmetric transport */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 9de2176a658..102bc393365 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -963,6 +963,14 @@ since they mandate this option's use. + + Whether to notifies all the progress details on blind transfer + + Some SIP phones (Mitel/Aastra, Snom) expect a sip/frag "200 OK" + after REFER has been accepted. If set to no then asterisk + will not send the progress details, but immediately will send "200 OK". + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 02562e78273..679c8837d93 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1939,6 +1939,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 0f4a95c77c7..46295387d53 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -61,6 +61,8 @@ struct refer_progress { char *transferee; /*! \brief Non-zero if the 100 notify has been sent */ int sent_100; + /*! \brief Whether to notifies all the progress details on blind transfer */ + unsigned int refer_blind_progress; }; /*! \brief REFER Progress notification structure */ @@ -372,6 +374,8 @@ static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data * ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n", progress, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint)); + (*progress)->refer_blind_progress = session->endpoint->refer_blind_progress; + (*progress)->framehook = -1; /* To prevent a potential deadlock we need the dialog so we can lock/unlock */ @@ -563,6 +567,8 @@ struct refer_blind { pjsip_replaces_hdr *replaces; /*! \brief Optional Refer-To header */ pjsip_sip_uri *refer_to; + /*! \brief Attended transfer flag */ + unsigned int attended:1; }; /*! \brief Blind transfer callback function */ @@ -577,8 +583,16 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes"); - /* If progress monitoring is being done attach a frame hook so we can monitor it */ - if (refer->progress) { + if (refer->progress && !refer->attended && !refer->progress->refer_blind_progress) { + /* If blind transfer and endpoint doesn't want to receive all the progress details */ + struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200, + PJSIP_EVSUB_STATE_TERMINATED); + + if (notification) { + refer_progress_notify(notification); + } + } else if (refer->progress) { + /* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */ struct ast_framehook_interface hook = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = refer_progress_framehook, @@ -785,6 +799,7 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi refer.rdata = rdata; refer.replaces = replaces; refer.refer_to = target_uri; + refer.attended = 1; if (ast_sip_session_defer_termination(session)) { ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n", @@ -839,6 +854,7 @@ static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_r refer.progress = progress; refer.rdata = rdata; refer.refer_to = target; + refer.attended = 0; if (ast_sip_session_defer_termination(session)) { ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting\n", From 93b7f84c1ac61208607ec6f7360b594dee921a1b Mon Sep 17 00:00:00 2001 From: Vitezslav Novy Date: Mon, 8 May 2017 20:40:47 +0200 Subject: [PATCH 1259/1578] chan_sip: Change sip_get_codec() to return correct codec list Return cahnnel nativeformats to fix bridge technology selection process. Same approach as in pjsip module. ASTERISK-26143 Reported-by: Henning Holtschneider Change-Id: I64e863753954d6ad67a9e722df2ebc328705ad48 --- channels/chan_sip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index e7c15bcbd0c..930dc0f6756 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -33588,9 +33588,7 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i static void sip_get_codec(struct ast_channel *chan, struct ast_format_cap *result) { - struct sip_pvt *p = ast_channel_tech_pvt(chan); - - ast_format_cap_append_from_cap(result, !ast_format_cap_count(p->peercaps) ? p->caps : p->peercaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(result, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_UNKNOWN); } static struct ast_rtp_glue sip_rtp_glue = { From 6e7b78414ffd08783bf34bb889a0354f7a6cb50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sun, 14 May 2017 01:37:09 -0400 Subject: [PATCH 1260/1578] Fix spelling queues.conf.sample file Change-Id: Ie1c2d83af66f27a449da09a68d987e0992627fee --- configs/samples/queues.conf.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configs/samples/queues.conf.sample b/configs/samples/queues.conf.sample index ebb5da126cc..b34a8d87014 100644 --- a/configs/samples/queues.conf.sample +++ b/configs/samples/queues.conf.sample @@ -301,8 +301,8 @@ monitor-type = MixMonitor ; ;random-periodic-announce=no ; -; If set to yes, the periodic announcment frequency will be timed from the end -; of each announcment rather than from the start of each announcment. This +; If set to yes, the periodic announcement frequency will be timed from the end +; of each announcement rather than from the start of each announcement. This ; defaults to off. ; ;relative-periodic-announce=yes From 30fbed65f11fe313283c180ae37a7fab2ad08d12 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 12 May 2017 21:04:59 -0500 Subject: [PATCH 1261/1578] res_pjsip_session.c: Process initial INVITE sooner. (key exists) Retransmissions of an initial INVITE could be queued in the serializer before we have processed the first INVITE message. If the first INVITE message doesn't get completely processed before the retransmissions are seen then we could try to setup the same call from the retransmissions. A symptom of this is seeing a (key exists) message associated with an INVITE. An earlier change attempted to address this kind of problem by calculating a distributor serializer to use for unassociated messages. Part of that change also made incoming calls keep using that distributor serializer. (ASTERISK-26088) However, some leftover code was still deferring the INVITE processing to the session's serializer even though we were already in that serializer. This not only is unnecessary but would cause the same call resetup problem. * Removed the code to defer processing the initial INVITE to the session's serializer because we are already running in that serializer. ASTERISK-26998 #close Change-Id: I1e822d82dcc650e508bc2d40d545d5de4f3421f6 --- res/res_pjsip_session.c | 71 ++++++++++++----------------------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 2613a74bc2b..add7168c28e 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2096,39 +2096,8 @@ struct new_invite { pjsip_rx_data *rdata; }; -static void new_invite_destroy(void *obj) +static int new_invite(struct new_invite *invite) { - struct new_invite *invite = obj; - - ao2_cleanup(invite->session); - - if (invite->rdata) { - pjsip_rx_data_free_cloned(invite->rdata); - } -} - -static struct new_invite *new_invite_alloc(struct ast_sip_session *session, pjsip_rx_data *rdata) -{ - struct new_invite *invite = ao2_alloc(sizeof(*invite), new_invite_destroy); - - if (!invite) { - return NULL; - } - - ao2_ref(session, +1); - invite->session = session; - - if (pjsip_rx_data_clone(rdata, 0, &invite->rdata) != PJ_SUCCESS) { - ao2_ref(invite, -1); - return NULL; - } - - return invite; -} - -static int new_invite(void *data) -{ - RAII_VAR(struct new_invite *, invite, data, ao2_cleanup); pjsip_tx_data *tdata = NULL; pjsip_timer_setting timer; pjsip_rdata_sdp_info *sdp_info; @@ -2250,7 +2219,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) pjsip_tx_data *tdata = NULL; pjsip_inv_session *inv_session = NULL; struct ast_sip_session *session; - struct new_invite *invite; + struct new_invite invite; ast_assert(endpoint != NULL); @@ -2287,18 +2256,17 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) return; } - invite = new_invite_alloc(session, rdata); - if (!invite || ast_sip_push_task(session->serializer, new_invite, invite)) { - if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { - pjsip_inv_terminate(inv_session, 500, PJ_FALSE); - } else { - pjsip_inv_send_msg(inv_session, tdata); - } -#ifdef HAVE_PJSIP_INV_SESSION_REF - pjsip_inv_dec_ref(inv_session); -#endif - ao2_cleanup(invite); - } + /* + * The current thread is supposed be the session serializer to prevent + * any initial INVITE retransmissions from trying to setup the same + * call again. + */ + ast_assert(ast_taskprocessor_is_task(session->serializer)); + + invite.session = session; + invite.rdata = rdata; + new_invite(&invite); + ao2_ref(session, -1); } @@ -2339,13 +2307,14 @@ static pj_bool_t has_supplement(const struct ast_sip_session *session, const pjs * 2) An in-dialog request that the inv_session layer does not * handle is received (such as an in-dialog INFO) * - * In all cases, there is very little we actually do in this function + * Except for INVITEs, there is very little we actually do in this function * 1) For requests we don't handle, we return PJ_FALSE - * 2) For new INVITEs, throw the work into the SIP threadpool to be done - * there to free up the thread(s) handling incoming requests - * 3) For in-dialog requests we handle, we defer handling them until the - * on_inv_state_change() callback instead (where we will end up putting - * them into the threadpool). + * 2) For new INVITEs, handle them now to prevent retransmissions from + * trying to setup the same call again. + * 3) For in-dialog requests we handle, we process them in the + * .on_state_changed = session_inv_on_state_changed or + * .on_tsx_state_changed = session_inv_on_tsx_state_changed + * callbacks instead. */ static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata) { From 5a7af00e80b9f360a11fcbbc6c6b6dfd2ee478a6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sat, 13 May 2017 16:40:00 +0000 Subject: [PATCH 1262/1578] asterisk: Audit locking of channel when manipulating flags. When manipulating flags on a channel the channel has to be locked to guarantee that nothing else is also manipulating the flags. This change introduces locking where necessary to guarantee this. It also adds helper functions that manipulate channel flags and lock to reduce repeated code. ASTERISK-26789 Change-Id: I489280662dba0f4c50981bfc5b5a7073fef2db10 --- apps/app_chanspy.c | 16 ++++++---------- apps/app_dial.c | 6 +++--- apps/app_disa.c | 10 +++++----- apps/app_dumpchan.c | 4 +--- apps/app_externalivr.c | 6 +++--- include/asterisk/channel.h | 25 +++++++++++++++++++++++++ main/autoservice.c | 2 +- main/bridge_after.c | 2 +- main/bridge_channel.c | 2 +- main/channel.c | 37 +++++++++++++++++++++++++++---------- main/file.c | 20 ++++++++++---------- main/manager.c | 8 ++------ main/pbx.c | 4 ++++ res/res_agi.c | 4 +++- res/res_musiconhold.c | 4 +++- 15 files changed, 95 insertions(+), 55 deletions(-) diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 4814f4ce5db..354b9ea7d35 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -693,9 +693,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto } } - ast_channel_lock(chan); - ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); - ast_channel_unlock(chan); + ast_channel_set_flag(chan, AST_FLAG_END_DTMF_ONLY); csth.volfactor = *volfactor; @@ -825,9 +823,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto else ast_deactivate_generator(chan); - ast_channel_lock(chan); - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); - ast_channel_unlock(chan); + ast_channel_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { ast_audiohook_lock(&csth.whisper_audiohook); @@ -921,7 +917,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, if (ast_channel_state(chan) != AST_STATE_UP) ast_answer(chan); - ast_set_flag(ast_channel_flags(chan), AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ + ast_channel_set_flag(chan, AST_FLAG_SPYING); waitms = 100; @@ -934,7 +930,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SPYING); + ast_channel_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { @@ -977,7 +973,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, res = ast_waitfordigit(chan, waitms); if (res < 0) { iter = ast_channel_iterator_destroy(iter); - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SPYING); + ast_channel_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { @@ -1196,7 +1192,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, } exit: - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SPYING); + ast_channel_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); diff --git a/apps/app_dial.c b/apps/app_dial.c index 79e2a9b0bb7..847a095f44a 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -2855,7 +2855,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast ast_log(LOG_ERROR, "error streaming file '%s' to callee\n", opt_args[OPT_ARG_ANNOUNCE]); } - ast_set_flag(ast_channel_flags(peer), AST_FLAG_END_DTMF_ONLY); + ast_channel_set_flag(peer, AST_FLAG_END_DTMF_ONLY); while (ast_channel_stream(peer)) { int ms; @@ -2919,13 +2919,13 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast } ast_sched_runq(ast_channel_sched(peer)); } - ast_clear_flag(ast_channel_flags(peer), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(peer, AST_FLAG_END_DTMF_ONLY); } if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) { /* chan and peer are going into the PBX; as such neither are considered * outgoing channels any longer */ - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING); + ast_channel_clear_flag(chan, AST_FLAG_OUTGOING); ast_replace_subargument_delimiter(opt_args[OPT_ARG_GOTO]); ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]); diff --git a/apps/app_disa.c b/apps/app_disa.c index 8dc61ff64c5..cceb5541dda 100644 --- a/apps/app_disa.c +++ b/apps/app_disa.c @@ -208,7 +208,7 @@ static int disa_exec(struct ast_channel *chan, const char *data) play_dialtone(chan, args.mailbox); - ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); + ast_channel_set_flag(chan, AST_FLAG_END_DTMF_ONLY); for (;;) { /* if outa time, give em reorder */ @@ -224,7 +224,7 @@ static int disa_exec(struct ast_channel *chan, const char *data) } if (!(f = ast_read(chan))) { - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); return -1; } @@ -232,7 +232,7 @@ static int disa_exec(struct ast_channel *chan, const char *data) if (f->data.uint32) ast_channel_hangupcause_set(chan, f->data.uint32); ast_frfree(f); - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); return -1; } @@ -261,7 +261,7 @@ static int disa_exec(struct ast_channel *chan, const char *data) fp = fopen(args.passcode,"r"); if (!fp) { ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,ast_channel_name(chan)); - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); return -1; } pwline[0] = 0; @@ -357,7 +357,7 @@ static int disa_exec(struct ast_channel *chan, const char *data) } } - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); if (k == 3) { int recheck = 0; diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c index 0789ce06eb8..bec7788170d 100644 --- a/apps/app_dumpchan.c +++ b/apps/app_dumpchan.c @@ -88,8 +88,6 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) ast_channel_lock(c); bridge = ast_channel_get_bridge(c); - ast_channel_unlock(c); - snprintf(buf,size, "Name= %s\n" "Type= %s\n" @@ -166,7 +164,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)", ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)", (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)")); - + ast_channel_unlock(c); ao2_cleanup(bridge); return 0; } diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c index c2224b44b66..84267a5ea49 100644 --- a/apps/app_externalivr.c +++ b/apps/app_externalivr.c @@ -642,9 +642,9 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, waitfds[0] = ast_iostream_get_fd(eivr_commands); waitfds[1] = eivr_errors ? ast_iostream_get_fd(eivr_errors) : -1; - while (1) { - if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) { - ast_chan_log(LOG_ERROR, chan, "Is a zombie\n"); + while (1) { + if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) { + ast_chan_log(LOG_ERROR, chan, "Is a zombie\n"); break; } if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) { diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index fd339d97483..005803d5cad 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4436,6 +4436,31 @@ void ast_channel_dialed_causes_clear(const struct ast_channel *chan); struct ast_flags *ast_channel_flags(struct ast_channel *chan); +/*! + * \since 13.17.0 + * \brief Set a flag on a channel + * + * \param chan The channel to set the flag on + * \param flag The flag to set + * + * \note This will lock the channel internally. If the channel is already + * locked it is still safe to call. + */ + +void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag); + +/*! + * \since 13.17.0 + * \param Clear a flag on a channel + * + * \param chan The channel to clear the flag from + * \param flag The flag to clear + * + * \note This will lock the channel internally. If the channel is already + * locked it is still safe to call. + */ +void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag); + /*! * \since 12.4.0 * \brief Return whether or not any manager variables have been set diff --git a/main/autoservice.c b/main/autoservice.c index 11c9eab969d..d1a0156ab46 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -295,11 +295,11 @@ int ast_autoservice_stop(struct ast_channel *chan) res = 0; } + ast_channel_lock(chan); if (!as->orig_end_dtmf_flag) { ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY); } - ast_channel_lock(chan); while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) { if (!((1 << f->frametype) & as->ignore_frame_types)) { ast_queue_frame_head(chan, f); diff --git a/main/bridge_after.c b/main/bridge_after.c index d649717e2b8..d4aec75d0fe 100644 --- a/main/bridge_after.c +++ b/main/bridge_after.c @@ -482,7 +482,7 @@ int ast_bridge_setup_after_goto(struct ast_channel *chan) } } else if (!ast_check_hangup(chan)) { /* Clear the outgoing flag */ - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING); + ast_channel_clear_flag(chan, AST_FLAG_OUTGOING); if (after_bridge->specific) { goto_failed = ast_explicit_goto(chan, after_bridge->context, diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 4f166fff06f..c6ea222eeb8 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2101,7 +2101,7 @@ void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel) && (ast_channel_is_leaving_bridge(bridge_channel->chan) || bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT)) { ast_debug(2, "Channel %s will survive this bridge; clearing outgoing (dialed) flag\n", ast_channel_name(bridge_channel->chan)); - ast_clear_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_OUTGOING); + ast_channel_clear_flag(bridge_channel->chan, AST_FLAG_OUTGOING); } bridge->reconfigured = 1; diff --git a/main/channel.c b/main/channel.c index 099e6f65abb..1f97e651c32 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1288,8 +1288,10 @@ int ast_channel_defer_dtmf(struct ast_channel *chan) int pre = 0; if (chan) { + ast_channel_lock(chan); pre = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF); ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF); + ast_channel_unlock(chan); } return pre; } @@ -1297,8 +1299,9 @@ int ast_channel_defer_dtmf(struct ast_channel *chan) /*! \brief Unset defer DTMF flag on channel */ void ast_channel_undefer_dtmf(struct ast_channel *chan) { - if (chan) - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF); + if (chan) { + ast_channel_clear_flag(chan, AST_FLAG_DEFER_DTMF); + } } struct ast_channel *ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg, @@ -3223,7 +3226,7 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in return -1; /* Only look for the end of DTMF, don't bother with the beginning and don't emulate things */ - ast_set_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_set_flag(c, AST_FLAG_END_DTMF_ONLY); /* Wait for a digit, no more than timeout_ms milliseconds total. * Or, wait indefinitely if timeout_ms is <0. @@ -3242,12 +3245,12 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in if (errno == 0 || errno == EINTR) continue; ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno)); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return -1; } else if (outfd > -1) { /* The FD we were watching has something waiting */ ast_log(LOG_WARNING, "The FD we were waiting for has something waiting. Waitfordigit returning numeric 1\n"); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return 1; } else if (rchan) { int res; @@ -3261,13 +3264,13 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in case AST_FRAME_DTMF_END: res = f->subclass.integer; ast_frfree(f); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return res; case AST_FRAME_CONTROL: switch (f->subclass.integer) { case AST_CONTROL_HANGUP: ast_frfree(f); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return -1; case AST_CONTROL_STREAM_STOP: case AST_CONTROL_STREAM_SUSPEND: @@ -3278,7 +3281,7 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in * that perform stream control will handle this. */ res = f->subclass.integer; ast_frfree(f); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return res; case AST_CONTROL_PVT_CAUSE_CODE: case AST_CONTROL_RINGING: @@ -3313,7 +3316,7 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in } } - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return 0; /* Time is up */ } @@ -5709,9 +5712,9 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan } else if (caller) { /* no outgoing helper so use caller if available */ call_forward_inherit(new_chan, caller, orig); } - ast_set_flag(ast_channel_flags(new_chan), AST_FLAG_ORIGINATED); ast_channel_lock_both(orig, new_chan); + ast_channel_set_flag(new_chan, AST_FLAG_ORIGINATED); pbx_builtin_setvar_helper(new_chan, "FORWARDERNAME", forwarder); ast_party_connected_line_copy(ast_channel_connected(new_chan), ast_channel_connected(orig)); ast_party_redirecting_copy(ast_channel_redirecting(new_chan), ast_channel_redirecting(orig)); @@ -10947,3 +10950,17 @@ int ast_channel_stream_topology_changed(struct ast_channel *chan, struct ast_str return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_CHANGED, topology, sizeof(topology)); } + +void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag) +{ + ast_channel_lock(chan); + ast_set_flag(ast_channel_flags(chan), flag); + ast_channel_unlock(chan); +} + +void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag) +{ + ast_channel_lock(chan); + ast_clear_flag(ast_channel_flags(chan), flag); + ast_channel_unlock(chan); +} diff --git a/main/file.c b/main/file.c index fb4ede6c88b..41131f9eebc 100644 --- a/main/file.c +++ b/main/file.c @@ -1543,7 +1543,7 @@ static int waitstream_core(struct ast_channel *c, reverse = ""; /* Switch the channel to end DTMF frame only. waitstream_core doesn't care about the start of DTMF. */ - ast_set_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_set_flag(c, AST_FLAG_END_DTMF_ONLY); if (ast_test_flag(ast_channel_flags(c), AST_FLAG_MASQ_NOSTREAM)) orig_chan_name = ast_strdupa(ast_channel_name(c)); @@ -1575,7 +1575,7 @@ static int waitstream_core(struct ast_channel *c, res = ast_waitfor(c, ms); if (res < 0) { ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno)); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return res; } } else { @@ -1586,11 +1586,11 @@ static int waitstream_core(struct ast_channel *c, if (errno == EINTR) continue; ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno)); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return -1; } else if (outfd > -1) { /* this requires cmdfd set */ /* The FD we were watching has something waiting */ - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return 1; } /* if rchan is set, it is 'c' */ @@ -1599,7 +1599,7 @@ static int waitstream_core(struct ast_channel *c, if (res > 0) { struct ast_frame *fr = ast_read(c); if (!fr) { - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return -1; } switch (fr->frametype) { @@ -1610,7 +1610,7 @@ static int waitstream_core(struct ast_channel *c, S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) { res = fr->subclass.integer; ast_frfree(fr); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return res; } } else { @@ -1626,7 +1626,7 @@ static int waitstream_core(struct ast_channel *c, "Break"); ast_frfree(fr); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return res; } } @@ -1643,7 +1643,7 @@ static int waitstream_core(struct ast_channel *c, "Break"); res = fr->subclass.integer; ast_frfree(fr); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return res; case AST_CONTROL_STREAM_REVERSE: if (!skip_ms) { @@ -1661,7 +1661,7 @@ static int waitstream_core(struct ast_channel *c, case AST_CONTROL_BUSY: case AST_CONTROL_CONGESTION: ast_frfree(fr); - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return -1; case AST_CONTROL_RINGING: case AST_CONTROL_ANSWER: @@ -1698,7 +1698,7 @@ static int waitstream_core(struct ast_channel *c, ast_sched_runq(ast_channel_sched(c)); } - ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); return (err || ast_channel_softhangup_internal_flag(c)) ? -1 : 0; } diff --git a/main/manager.c b/main/manager.c index c592fbd37a9..dfb0d96c93d 100644 --- a/main/manager.c +++ b/main/manager.c @@ -4847,14 +4847,10 @@ static int action_redirect(struct mansession *s, const struct message *m) /* Release the bridge wait. */ if (chan1_wait) { - ast_channel_lock(chan); - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); - ast_channel_unlock(chan); + ast_channel_clear_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); } if (chan2_wait) { - ast_channel_lock(chan2); - ast_clear_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); - ast_channel_unlock(chan2); + ast_channel_clear_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); } chan2 = ast_channel_unref(chan2); diff --git a/main/pbx.c b/main/pbx.c index 28027c06b8a..ccfba054e7c 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -4300,8 +4300,10 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, ast_channel_pbx(c)->rtimeoutms = 10000; ast_channel_pbx(c)->dtimeoutms = 5000; + ast_channel_lock(c); autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */ ast_set_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); + ast_channel_unlock(c); if (ast_strlen_zero(ast_channel_exten(c))) { /* If not successful fall back to 's' - but only if there is no given exten */ @@ -4546,8 +4548,10 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, ast_pbx_hangup_handler_run(c); } + ast_channel_lock(c); ast_set2_flag(ast_channel_flags(c), autoloopflag, AST_FLAG_IN_AUTOLOOP); ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */ + ast_channel_unlock(c); pbx_destroy(ast_channel_pbx(c)); ast_channel_pbx_set(c, NULL); diff --git a/res/res_agi.c b/res/res_agi.c index 557f3497152..dd341141a34 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -3119,12 +3119,14 @@ static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : ""); if ((app_to_exec = pbx_findapp(argv[1]))) { + ast_channel_lock(chan); if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) { ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS); } + ast_channel_unlock(chan); res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]); if (!workaround) { - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS); + ast_channel_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS); } } else { ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]); diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 71f4691af26..be50e9cee2b 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1558,8 +1558,10 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con } } if (!res) { + ast_channel_lock(chan); ast_channel_latest_musicclass_set(chan, mohclass->name); ast_set_flag(ast_channel_flags(chan), AST_FLAG_MOH); + ast_channel_unlock(chan); } mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start"); @@ -1569,10 +1571,10 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con static void local_ast_moh_stop(struct ast_channel *chan) { - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_MOH); ast_deactivate_generator(chan); ast_channel_lock(chan); + ast_clear_flag(ast_channel_flags(chan), AST_FLAG_MOH); if (ast_channel_music_state(chan)) { if (ast_channel_stream(chan)) { ast_closestream(ast_channel_stream(chan)); From 51375686f7c42f14b979b8e70bc5a8c7c32da890 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 15 May 2017 13:25:43 -0500 Subject: [PATCH 1263/1578] core/conversions: Added string to unsigned integer and long conversions Added functions that convert a string to an unsigned integer or unsigned long. A couple of unit test were also created to test the routines. The reasons for adding these conversion utilities (and hopefully eventually more) are as follows: * Conversion routines are functionally contained with consistent and better error checking * The function names offer a better description of what is happening * It encourages code reuse for easier bug fixing at a single source * It's simpler to use * It's unit testable For instance, currently in a lot of places when converting to an integer or similar the "sscanf" function is used. When using "sscanf" it may not be immediately clear what's happening as it lacks semantic naming. Limited error checking is usually done as well. For example, most of the time a check is done to make sure the value converted, but does not check for overflows or negative valued conversions when converting unsigned numbers. Why use/wrap "strtoul" and not "sscanf" then? Primarily, it lacks some of the built in error handling that "strtoul" has. For instance "strtoul" contains overflow checks. Less so, but can still factor as reasons, "sscanf" is slightly more complex in its use. And maybe a bit controversial, but it may be ("big if") potentially slower than "strtoul" in some cases. Change-Id: If7eaca4a48f8c7b89cc8b5a1f4bed2852fca82bb --- include/asterisk/conversions.h | 62 +++++++++++++++ main/conversions.c | 77 +++++++++++++++++++ tests/test_conversions.c | 136 +++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 include/asterisk/conversions.h create mode 100644 main/conversions.c create mode 100644 tests/test_conversions.c diff --git a/include/asterisk/conversions.h b/include/asterisk/conversions.h new file mode 100644 index 00000000000..2997760a859 --- /dev/null +++ b/include/asterisk/conversions.h @@ -0,0 +1,62 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Kevin Harwell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * \brief Conversion utility functions + */ + +#ifndef _ASTERISK_CONVERSIONS_H +#define _ASTERISK_CONVERSIONS_H + +/*! + * \brief Convert the given string to an unsigned integer + * + * This function will return failure for the following reasons: + * + * The given string to convert is NULL + * The given string to convert is empty. + * The given string to convert is negative (starts with a '-') + * The given string to convert contains non numeric values + * Once converted the number is out of range (greater than UINT_MAX) + * + * \param str The string to convert + * \param res [out] The converted value + * + * \returns -1 if it fails to convert, 0 on success + */ +int ast_str_to_uint(const char *str, unsigned int *res); + +/*! + * \brief Convert the given string to an unsigned long + * + * This function will return failure for the following reasons: + * + * The given string to convert is NULL + * The given string to convert is empty. + * The given string to convert is negative (starts with a '-') + * The given string to convert contains non numeric values + * Once converted the number is out of range (greater than ULONG_MAX) + * + * \param str The string to convert + * \param res [out] The converted value + * + * \returns -1 if it fails to convert, 0 on success + */ +int ast_str_to_ulong(const char *str, unsigned long *res); + +#endif /* _ASTERISK_CONVERSIONS_H */ diff --git a/main/conversions.c b/main/conversions.c new file mode 100644 index 00000000000..e73e1a2137b --- /dev/null +++ b/main/conversions.c @@ -0,0 +1,77 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Conversion utility functions + */ + +/*** MODULEINFO + core + ***/ + +#include +#include +#include +#include + +#include "asterisk/conversions.h" + +static int str_is_negative(const char *str) +{ + /* Ignore any preceding white space */ + while (isspace(*str) && *++str); + return *str == '-'; +} + +int ast_str_to_uint(const char *str, unsigned int *res) +{ + unsigned long val; + + if (ast_str_to_ulong(str, &val) || val > UINT_MAX) { + return -1; + } + + *res = val; + return 0; +} + +int ast_str_to_ulong(const char *str, unsigned long *res) +{ + char *end; + unsigned long val; + + if (!str || str_is_negative(str)) { + return -1; + } + + errno = 0; + val = strtoul(str, &end, 0); + + /* + * If str equals end then no digits were found. If end is not pointing to + * a null character then the string contained some numbers that could be + * converted, but some characters that could not, which we'll consider + * invalid. + */ + if ((str == end || *end != '\0' || (errno == ERANGE && val == ULONG_MAX))) { + return -1; + } + + *res = val; + return 0; + +} diff --git a/tests/test_conversions.c b/tests/test_conversions.c new file mode 100644 index 00000000000..689aba9cda5 --- /dev/null +++ b/tests/test_conversions.c @@ -0,0 +1,136 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Kevin Harwell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Conversions Unit Tests + * + * \author Kevin Harwell + * + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" + +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/conversions.h" + +#define CATEGORY "/main/conversions/" + +AST_TEST_DEFINE(str_to_uint) +{ + const char *invalid = "abc"; + const char *invalid_partial = "7abc"; + const char *negative = "-7"; + const char *negative_spaces = " -7"; + const char *out_of_range = "9999999999"; + const char *spaces = " "; + const char *valid = "7"; + const char *valid_spaces = " 7"; + unsigned int val; + char str[64]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "convert a string to an unsigned integer"; + info->description = info->summary; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, ast_str_to_uint(NULL, &val)); + ast_test_validate(test, ast_str_to_uint(invalid, &val)); + ast_test_validate(test, ast_str_to_uint(invalid_partial, &val)); + ast_test_validate(test, ast_str_to_uint(negative, &val)); + ast_test_validate(test, ast_str_to_uint(negative_spaces, &val)); + ast_test_validate(test, ast_str_to_uint(out_of_range, &val)); + ast_test_validate(test, ast_str_to_uint(spaces, &val)); + ast_test_validate(test, !ast_str_to_uint(valid, &val)); + ast_test_validate(test, !ast_str_to_uint(valid_spaces, &val)); + + ast_test_validate(test, snprintf(str, sizeof(str), "%u", UINT_MAX) > 0); + ast_test_validate(test, !ast_str_to_uint(str, &val)); + ast_test_validate(test, val == UINT_MAX); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(str_to_ulong) +{ + const char *invalid = "abc"; + const char *invalid_partial = "7abc"; + const char *negative = "-7"; + const char *negative_spaces = " -7"; + const char *out_of_range = "99999999999999999999"; + const char *spaces = " "; + const char *valid = "7"; + const char *valid_spaces = " 7"; + unsigned long val; + char str[64]; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "convert a string to an unsigned long"; + info->description = info->summary; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, ast_str_to_ulong(NULL, &val)); + ast_test_validate(test, ast_str_to_ulong(invalid, &val)); + ast_test_validate(test, ast_str_to_ulong(invalid_partial, &val)); + ast_test_validate(test, ast_str_to_ulong(negative, &val)); + ast_test_validate(test, ast_str_to_ulong(negative_spaces, &val)); + ast_test_validate(test, ast_str_to_ulong(out_of_range, &val)); + ast_test_validate(test, ast_str_to_ulong(spaces, &val)); + ast_test_validate(test, !ast_str_to_ulong(valid, &val)); + ast_test_validate(test, !ast_str_to_ulong(valid_spaces, &val)); + + ast_test_validate(test, snprintf(str, sizeof(str), "%lu", ULONG_MAX) > 0); + ast_test_validate(test, !ast_str_to_ulong(str, &val)); + ast_test_validate(test, val == ULONG_MAX); + + return AST_TEST_PASS; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(str_to_uint); + AST_TEST_REGISTER(str_to_ulong); + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(str_to_uint); + AST_TEST_UNREGISTER(str_to_ulong); + return 0; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "URI test module"); From a60d1f3974e0f250925cae8237ea5dc40d564ccd Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 15 May 2017 13:26:50 -0500 Subject: [PATCH 1264/1578] app_stream_echo: Added a multi-stream echo application If the channel does not have multi-stream support then this application acts just like app_echo. If it does have multi-stream support then each stream is echoed back to itself (one-to-one). If a "num" is specified, then a new topology is made that contains clones (from the channel's topology) of all media types that are not equal to the given "type". If the media type differs then the first stream matching the "type" is cloned into the new topology and then up to "num" - 1 of the same stream are also cloned into it. Any additional streams from the original topology matching the "type" are subsequently ignored (i.e. not added to the new topology). For this same case when a frame is read from a stream that frame is still echoed back like before, but now that frame is also echoed out to the additional streams that matched on the specified "type". ASTERISK-26997 #close Change-Id: I254144486734178e196c7f590a26ffc13543ff2c --- apps/app_stream_echo.c | 339 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 apps/app_stream_echo.c diff --git a/apps/app_stream_echo.c b/apps/app_stream_echo.c new file mode 100644 index 00000000000..53cbcd74dd7 --- /dev/null +++ b/apps/app_stream_echo.c @@ -0,0 +1,339 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Kevin Harwell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Stream echo application + * + * \author Kevin Harwell + */ + +/*** MODULEINFO + core + ***/ + +#include "asterisk.h" + +#include "asterisk/app.h" +#include "asterisk/conversions.h" +#include "asterisk/file.h" +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/stream.h" + +/*** DOCUMENTATION + + + Echo media, up to 'N' streams of a type, and DTMF back to the calling party + + + + The number of streams of a type to echo back. If '0' is specified then + all streams of a type are removed. + + + The media type of the stream(s) to add or remove (in the case of "num" + being '0'). This can be set to either "audio" or "video" (default). If "num" + is empty (i.e. not specified) then this parameter is ignored. + + + + If a "num" (the number of streams) is not given then this simply echos + back any media or DTMF frames (note, however if '#' is detected then the + application exits) read from the calling channel back to itself. This means + for any relevant frame read from a particular stream it is written back out + to the associated write stream in a one to one fashion. + + However if a "num" is specified, and if the calling channel allows it + (a new offer is made requesting the allowance of additional streams) then any + any media received, like before, is echoed back onto each stream. However, in + this case a relevant frame received on a stream of the given "type" is also + echoed back out to the other streams of that same type. It should be noted that + when operating in this mode only the first stream found of the given "type" is + allowed from the original offer. And this first stream found is also the only + stream of that "type" granted read (send/receive) capabilities in the new offer + whereas the additional ones are set to receive only. + This does not echo CONTROL, MODEM, or NULL frames. + + + ***/ + +static const char app[] = "StreamEcho"; + +static int stream_echo_write_error(struct ast_channel *chan, struct ast_frame *frame, int pos) +{ + char frame_type[32]; + const char *media_type; + struct ast_stream *stream; + + ast_frame_type2str(frame->frametype, frame_type, sizeof(frame_type)); + + stream = pos < 0 ? + ast_channel_get_default_stream(chan, ast_format_get_type(frame->subclass.format)) : + ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), pos); + + media_type = ast_codec_media_type2str(ast_stream_get_type(stream)); + + ast_log(LOG_ERROR, "%s - unable to write frame type '%s' to stream type '%s' at " + "position '%d'\n", ast_channel_name(chan), frame_type, media_type, + ast_stream_get_position(stream)); + + return -1; +} + +static int stream_echo_write(struct ast_channel *chan, struct ast_frame *frame, + enum ast_media_type type, int one_to_one) +{ + int i; + int num; + struct ast_stream_topology *topology; + + /* + * Since this is an echo application if we get a frame in on a stream + * we simply want to echo it back out onto the same stream number. + */ + num = ast_channel_is_multistream(chan) ? frame->stream_num : -1; + + if (ast_write_stream(chan, num, frame)) { + return stream_echo_write_error(chan, frame, num); + } + + /* + * If the frame's type and given type don't match, or we are operating in + * a one to one stream echo mode then there is nothing left to do. + * + * Note, if the channel is not multi-stream capable then one_to_one will + * always be true, so it is safe to also not check for that here too. + */ + if (one_to_one || ast_format_get_type(frame->subclass.format) != type) { + return 0; + } + + /* + * However, if we are operating in a single stream echoed to many stream + * mode, and the frame's type matches the given type then we also need to + * find the other streams of the same type and write out to those streams + * as well. + * + * If we are here, then it's accepted that whatever stream number the frame + * was read from for the given type is the only one set to send/receive, + * while the others of the same type are set to receive only. Since we + * shouldn't assume any order to the streams, we'll loop back through all + * streams in the channel's topology writing only to those of the same type. + * And, of course also not the stream which has already been written to. + */ + topology = ast_channel_get_stream_topology(chan); + + for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { + struct ast_stream *stream = ast_stream_topology_get_stream(topology, i); + + if (num != i && ast_stream_get_type(stream) == type) { + if (ast_write_stream(chan, i, frame)) { + return stream_echo_write_error(chan, frame, i); + } + } + } + + return 0; +} + +static int stream_echo_perform(struct ast_channel *chan, + struct ast_stream_topology *topology, enum ast_media_type type) +{ + int update_sent = 0; + int request_change = topology != NULL; + int one_to_one = 1; + + while (ast_waitfor(chan, -1) > -1) { + struct ast_frame *f; + + if (request_change) { + /* Request a change to the new topology */ + if (ast_channel_request_stream_topology_change(chan, topology, NULL)) { + ast_log(LOG_WARNING, "Request stream topology change not supported " + "by channel '%s'\n", ast_channel_name(chan)); + } + request_change = 0; + } + + f = ast_read(chan); + if (!f) { + return -1; + } + + if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) { + ast_frfree(f); + break; + } + + f->delivery.tv_sec = 0; + f->delivery.tv_usec = 0; + + if (f->frametype == AST_FRAME_CONTROL) { + if (f->subclass.integer == AST_CONTROL_VIDUPDATE && !update_sent) { + if (stream_echo_write(chan, f, one_to_one, type)) { + ast_frfree(f); + return -1; + } + update_sent = 1; + } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_CHANGED) { + update_sent = 0; + one_to_one = 0; /* Switch writing to one to many */ + } + } else if (f->frametype == AST_FRAME_VIDEO && !update_sent){ + struct ast_frame frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_VIDUPDATE, + }; + stream_echo_write(chan, &frame, one_to_one, type); + update_sent = 1; + } + + if (f->frametype != AST_FRAME_CONTROL && + f->frametype != AST_FRAME_MODEM && + f->frametype != AST_FRAME_NULL && + stream_echo_write(chan, f, one_to_one, type)) { + ast_frfree(f); + return -1; + } + + ast_frfree(f); + } + + return 0; +} + +static struct ast_stream_topology *stream_echo_topology_alloc( + struct ast_stream_topology *original, unsigned int num, enum ast_media_type type) +{ + int i, n = num; + struct ast_stream_topology *res = ast_stream_topology_alloc(); + + if (!res) { + return NULL; + } + + /* + * Clone every stream of a type not matching the given one. If the type + * matches clone only the first stream found for the given type. Then for + * that stream clone it again up to num - 1 times. Ignore any other streams + * of the same matched type in the original topology. + * + * So for instance if the original stream contains 1 audio stream and 2 video + * streams (video stream 'A' and video stream 'B'), num is '3', and the given + * type is 'video' then the resulting topology will contain a clone of the + * audio stream along with 3 clones of video stream 'A'. Video stream 'B' is + * not copied over. + */ + for (i = 0; i < ast_stream_topology_get_count(original); ++i) { + struct ast_stream *stream = ast_stream_topology_get_stream(original, i); + + if (!n && ast_stream_get_type(stream) == type) { + /* Don't copy any[more] of the given type */ + continue; + } + + do { + stream = ast_stream_clone(stream); + + if (!stream || ast_stream_topology_append_stream(res, stream) < 0) { + ast_stream_free(stream); + ast_stream_topology_free(res); + return NULL; + } + + if (ast_stream_get_type(stream) != type) { + /* Do not multiply non matching streams */ + break; + } + + /* + * Since num is not zero yet (i.e. this is first stream found to + * match on the type) and the types match then loop num - 1 times + * cloning the same stream. + */ + ast_stream_set_state(stream, n == num ? + AST_STREAM_STATE_SENDRECV : AST_STREAM_STATE_RECVONLY); + } while (--n); + } + + return res; +} + +static int stream_echo_exec(struct ast_channel *chan, const char *data) +{ + int res; + unsigned int num = 0; + enum ast_media_type type; + char *parse; + struct ast_stream_topology *topology; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(num); + AST_APP_ARG(type); + ); + + parse = ast_strdupa(data); + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_strlen_zero(args.num)) { + /* + * If a number is not given then no topology is to be created + * and renegotiated. The app will just echo back each stream + * received to itself. + */ + return stream_echo_perform(chan, NULL, AST_MEDIA_TYPE_UNKNOWN); + } + + if (ast_str_to_uint(args.num, &num)) { + ast_log(LOG_ERROR, "Failed to parse the first parameter '%s' into a" + " greater than or equal to zero\n", args.num); + return -1; + } + + type = ast_strlen_zero(args.type) ? AST_MEDIA_TYPE_VIDEO : + ast_media_type_from_str(args.type); + + topology = stream_echo_topology_alloc( + ast_channel_get_stream_topology(chan), num, type); + if (!topology) { + ast_log(LOG_ERROR, "Unable to create '%u' streams of type '%s' to" + " the topology\n", num, ast_codec_media_type2str(type)); + return -1; + } + + res = stream_echo_perform(chan, topology, type); + + if (ast_channel_get_stream_topology(chan) != topology) { + ast_stream_topology_free(topology); + } + + return res; +} + +static int unload_module(void) +{ + return ast_unregister_application(app); +} + +static int load_module(void) +{ + return ast_register_application_xml(app, stream_echo_exec); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stream Echo Application"); From 4141748e859f0719ac99d5309da8f8e22ffb9d16 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 18 May 2017 17:35:21 -0400 Subject: [PATCH 1265/1578] res_hep_rtcp: Add support level to module info Change-Id: I5661478f9cf12d431f730e42be79323b62831e92 --- res/res_hep_rtcp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index 395031a3d4d..31b9c485b16 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -181,6 +181,7 @@ static int unload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RTCP HEPv3 Logger", + .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, From 2bb98d8faca2b0b3b2d5f9554ac53cc09f17cd44 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 13 Apr 2017 17:16:42 -0500 Subject: [PATCH 1266/1578] AST-2017-002: Ensure transaction key buffer is large enough. ASTERISK-26938 #close Change-Id: I266490792fd8896a23be7cb92f316b7e69356413 --- ...ansaction-key-buffer-is-large-enough.patch | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 third-party/pjproject/patches/0059-Ensure-2543-transaction-key-buffer-is-large-enough.patch diff --git a/third-party/pjproject/patches/0059-Ensure-2543-transaction-key-buffer-is-large-enough.patch b/third-party/pjproject/patches/0059-Ensure-2543-transaction-key-buffer-is-large-enough.patch new file mode 100644 index 00000000000..eb5a7db7339 --- /dev/null +++ b/third-party/pjproject/patches/0059-Ensure-2543-transaction-key-buffer-is-large-enough.patch @@ -0,0 +1,29 @@ +From b5f0f8868363c482a2c4ce343e3ee6ad256b0708 Mon Sep 17 00:00:00 2001 +From: Mark Michelson +Date: Thu, 13 Apr 2017 16:20:07 -0500 +Subject: [PATCH] Ensure 2543 transaction key buffer is large enough. + +The CSeq method length needs to be factored into the allocated buffer +length. Otherwise, the buffer may not be large enough to accommodate the +entire key. +--- + pjsip/src/pjsip/sip_transaction.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c +index c1750dc..2200d8d 100644 +--- a/pjsip/src/pjsip/sip_transaction.c ++++ b/pjsip/src/pjsip/sip_transaction.c +@@ -288,7 +288,8 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool, + host = &rdata->msg_info.via->sent_by.host; + + /* Calculate length required. */ +- len_required = 9 + /* CSeq number */ ++ len_required = method->name.slen + /* Method */ ++ 9 + /* CSeq number */ + rdata->msg_info.from->tag.slen + /* From tag. */ + rdata->msg_info.cid->id.slen + /* Call-ID */ + host->slen + /* Via host. */ +-- +1.9.1 + From 949e9147bfed119fb04cadd2b6916fe9bfc1d9b0 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 13 Apr 2017 10:14:48 -0600 Subject: [PATCH 1267/1578] AST-2017-004: chan_skinny: Add EOF check in skinny_session The while(1) loop in skinny_session wasn't checking for EOF so a packet that was longer than a header but still truncated would spin the while loop infinitely. Not only does this permanently tie up a thread and drive a core to 100% utilization, the call of ast_log() in such a tight loop eats all available process memory. Added poll with timeout to top of read loop ASTERISK-26940 #close Reported-by: Sandro Gauci Change-Id: I2ce65f3c5cb24b4943a9f75b64d545a1e2cd2898 --- channels/chan_skinny.c | 122 ++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index a0530007b18..aeb06056971 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -6658,7 +6658,7 @@ static int handle_capabilities_res_message(struct skinny_req *req, struct skinny #ifdef AST_DEVMODE struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); #endif - + if (!codecs) { return 0; @@ -7499,6 +7499,8 @@ static void skinny_session_cleanup(void *data) destroy_session(s); } +#define PACKET_TIMEOUT 10000 + static void *skinny_session(void *data) { int res; @@ -7545,78 +7547,86 @@ static void *skinny_session(void *data) } } - if (fds[0].revents) { + if (!fds[0].revents) { + continue; + } + ast_debug(1, "Reading header\n"); - if (!(req = ast_calloc(1, SKINNY_MAX_PACKET))) { - ast_log(LOG_WARNING, "Unable to allocated memorey for skinny_req.\n"); - break; - } + if (!(req = ast_calloc(1, SKINNY_MAX_PACKET))) { + ast_log(LOG_WARNING, "Unable to allocated memorey for skinny_req.\n"); + break; + } - ast_mutex_lock(&s->lock); - s->lockstate = 1; + ast_mutex_lock(&s->lock); + s->lockstate = 1; - if ((res = read(s->fd, req, skinny_header_size)) != skinny_header_size) { - if (res < 0) { - ast_log(LOG_WARNING, "Header read() returned error: %s\n", strerror(errno)); - } else { - ast_log(LOG_WARNING, "Unable to read header. Only found %d bytes.\n", res); - } - break; + if ((res = read(s->fd, req, skinny_header_size)) != skinny_header_size) { + if (res < 0) { + ast_log(LOG_WARNING, "Header read() returned error: %s\n", strerror(errno)); + } else { + ast_log(LOG_WARNING, "Unable to read header. Only found %d bytes.\n", res); } + break; + } - eventmessage = letohl(req->e); - if (eventmessage < 0) { - ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd); - break; - } + eventmessage = letohl(req->e); + if (eventmessage < 0) { + ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd); + break; + } - dlen = letohl(req->len) - 4; - if (dlen < 0) { - ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n"); - break; - } - if (dlen > (SKINNY_MAX_PACKET - skinny_header_size)) { - ast_log(LOG_WARNING, "Skinny packet too large (%d bytes), max length(%d bytes)\n", dlen+8, SKINNY_MAX_PACKET); - break; - } + dlen = letohl(req->len) - 4; + if (dlen < 0) { + ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n"); + break; + } + if (dlen > (SKINNY_MAX_PACKET - skinny_header_size)) { + ast_log(LOG_WARNING, "Skinny packet too large (%d bytes), max length(%d bytes)\n", dlen+8, SKINNY_MAX_PACKET); + break; + } - bytesread = 0; - while (1) { - if ((res = read(s->fd, ((char*)&req->data)+bytesread, dlen-bytesread)) < 0) { - ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno)); - break; - } - bytesread += res; - if (bytesread >= dlen) { - if (res < bytesread) { - ast_log(LOG_WARNING, "Rest of partial data received.\n"); - } - if (bytesread > dlen) { - ast_log(LOG_WARNING, "Client sent wrong amount of data (%d), expected (%d).\n", bytesread, dlen); - res = -1; - } - break; - } + ast_debug(1, "Read header: Message ID: 0x%04x, %d bytes in packet\n", eventmessage, dlen); - ast_log(LOG_WARNING, "Partial data received, waiting (%d bytes read of %d)\n", bytesread, dlen); - if (sched_yield() < 0) { - ast_log(LOG_WARNING, "Data yield() returned error: %s\n", strerror(errno)); - res = -1; - break; + bytesread = 0; + while (bytesread < dlen) { + ast_debug(1, "Waiting %dms for %d bytes of %d\n", PACKET_TIMEOUT, dlen - bytesread, dlen); + fds[0].revents = 0; + res = ast_poll(fds, 1, PACKET_TIMEOUT); + if (res <= 0) { + if (res == 0) { + ast_debug(1, "Poll timed out waiting for %d bytes\n", dlen - bytesread); + } else { + ast_log(LOG_WARNING, "Poll failed waiting for %d bytes: %s\n", + dlen - bytesread, strerror(errno)); } + ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr)); + res = -1; + + break; + } + if (!fds[0].revents) { + continue; } - s->lockstate = 0; - ast_mutex_unlock(&s->lock); + res = read(s->fd, ((char*)&req->data)+bytesread, dlen-bytesread); if (res < 0) { + ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno)); break; } + bytesread += res; + ast_debug(1, "Read %d bytes. %d of %d now read\n", res, bytesread, dlen); + } - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - res = handle_message(req, s); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + s->lockstate = 0; + ast_mutex_unlock(&s->lock); + if (res < 0) { + break; } + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + res = handle_message(req, s); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + if (req) { ast_free(req); req = NULL; From 7c0466092ce605fbf5ee895bee0d8fcab5374111 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 13 Apr 2017 17:17:36 -0500 Subject: [PATCH 1268/1578] AST-2017-003: Handle zero-length body parts correctly. ASTERISK-26939 #close Change-Id: I7ea235ab39833a187db4e078f0788bd0af0a24fd --- ...ength-multipart-body-parts-correctly.patch | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 third-party/pjproject/patches/0058-Parse-zero-length-multipart-body-parts-correctly.patch diff --git a/third-party/pjproject/patches/0058-Parse-zero-length-multipart-body-parts-correctly.patch b/third-party/pjproject/patches/0058-Parse-zero-length-multipart-body-parts-correctly.patch new file mode 100644 index 00000000000..49334c354c3 --- /dev/null +++ b/third-party/pjproject/patches/0058-Parse-zero-length-multipart-body-parts-correctly.patch @@ -0,0 +1,41 @@ +From f0c717463d569f87a16f9b014033c8ca8939a7b4 Mon Sep 17 00:00:00 2001 +From: Mark Michelson +Date: Thu, 13 Apr 2017 16:59:40 -0500 +Subject: [PATCH] Parse zero-length multipart body parts correctly. + +The calculation of end_body could result in a negative length being +passed to multipart_body_parse_part(). +--- + pjsip/src/pjsip/sip_multipart.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/pjsip/src/pjsip/sip_multipart.c b/pjsip/src/pjsip/sip_multipart.c +index 8351f7e..b302139 100644 +--- a/pjsip/src/pjsip/sip_multipart.c ++++ b/pjsip/src/pjsip/sip_multipart.c +@@ -653,13 +653,15 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool, + + end_body = curptr; + +- /* The newline preceeding the delimiter is conceptually part of +- * the delimiter, so trim it from the body. +- */ +- if (*(end_body-1) == '\n') +- --end_body; +- if (*(end_body-1) == '\r') +- --end_body; ++ if (end_body > start_body) { ++ /* The newline preceeding the delimiter is conceptually part of ++ * the delimiter, so trim it from the body. ++ */ ++ if (*(end_body-1) == '\n') ++ --end_body; ++ if (*(end_body-1) == '\r') ++ --end_body; ++ } + + /* Now that we have determined the part's boundary, parse it + * to get the header and body part of the part. +-- +1.9.1 + From be4beff3e494ac809b9fd5549fbdf9a34eb85f3d Mon Sep 17 00:00:00 2001 From: Steve Davies Date: Fri, 12 May 2017 16:38:27 +0100 Subject: [PATCH 1269/1578] app_queue: Add QUEUE_RAISE_PENALTY feature Additional variable to work alongside QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY, including an extra parameter in queuerules.conf. This value causes lower Agent penalty values to "raise up" so that they can join higher penalty agents and be treated equally after a period of time. ASTERISK-26995 #close Change-Id: If1c6421a983667a5ac4c359f6dac25b212b4c459 --- apps/app_queue.c | 131 ++++++++++++++++++++----- configs/samples/queuerules.conf.sample | 21 +++- 2 files changed, 125 insertions(+), 27 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 2389f0b1314..41014ed500c 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1545,6 +1545,7 @@ struct queue_ent { int pending; /*!< Non-zero if we are attempting to call a member */ int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */ int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */ + int raise_penalty; /*!< Float lower penalty mambers to a minimum penalty */ int linpos; /*!< If using linear strategy, what position are we at? */ int linwrapped; /*!< Is the linpos wrapped? */ time_t start; /*!< When we started holding */ @@ -1605,8 +1606,10 @@ struct penalty_rule { int time; /*!< Number of seconds that need to pass before applying this rule */ int max_value; /*!< The amount specified in the penalty rule for max penalty */ int min_value; /*!< The amount specified in the penalty rule for min penalty */ + int raise_value; /*!< The amount specified in the penalty rule for min penalty */ int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */ int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */ + int raise_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */ AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */ }; @@ -2233,7 +2236,7 @@ static struct ast_json *queue_member_blob_create(struct call_queue *q, struct me * is available, the function immediately returns 0. If no members are available, * then -1 is returned. */ -static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate) +static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate) { struct member *member; struct ao2_iterator mem_iter; @@ -2241,7 +2244,12 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena ao2_lock(q); mem_iter = ao2_iterator_init(q->members, 0); for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { - if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) { + int penalty = member->penalty; + if (raise_penalty != INT_MAX && penalty < raise_penalty) { + ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty); + penalty = raise_penalty; + } + if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) { if (conditions & QUEUE_EMPTY_PENALTY) { ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty); continue; @@ -2306,7 +2314,7 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) { /* member state still may be RINGING due to lag in event message - check again with device state */ - return get_member_status(q, max_penalty, min_penalty, conditions, 1); + return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1); } return -1; } @@ -2810,7 +2818,7 @@ static void clear_queue(struct call_queue *q) */ static int insert_penaltychange(const char *list_name, const char *content, const int linenum) { - char *timestr, *maxstr, *minstr, *contentdup; + char *timestr, *maxstr, *minstr, *raisestr, *contentdup; struct penalty_rule *rule = NULL, *rule_iter; struct rule_list *rl_iter; int penaltychangetime, inserted = 0; @@ -2828,8 +2836,16 @@ static int insert_penaltychange(const char *list_name, const char *content, cons } *maxstr++ = '\0'; - timestr = contentdup; + if ((minstr = strchr(maxstr,','))) { + *minstr++ = '\0'; + if ((raisestr = strchr(minstr,','))) { + *raisestr++ = '\0'; + } + } else { + raisestr = NULL; + } + timestr = contentdup; if ((penaltychangetime = atoi(timestr)) < 0) { ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); ast_free(rule); @@ -2838,10 +2854,6 @@ static int insert_penaltychange(const char *list_name, const char *content, cons rule->time = penaltychangetime; - if ((minstr = strchr(maxstr,','))) { - *minstr++ = '\0'; - } - /* The last check will evaluate true if either no penalty change is indicated for a given rule * OR if a min penalty change is indicated but no max penalty change is */ if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { @@ -2859,6 +2871,15 @@ static int insert_penaltychange(const char *list_name, const char *content, cons rule->min_relative = 1; } + if (!ast_strlen_zero(raisestr)) { + if (*raisestr == '+' || *raisestr == '-') { + rule->raise_relative = 1; + } + rule->raise_value = atoi(raisestr); + } else { /*there was no raise specified, so assume this means no change*/ + rule->raise_relative = 1; + } + /*We have the rule made, now we need to insert it where it belongs*/ AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ if (strcasecmp(rl_iter->name, list_name)) { @@ -2915,9 +2936,10 @@ static int load_realtime_rules(void) return 0; } while ((rulecat = ast_category_browse(cfg, rulecat))) { - const char *timestr, *maxstr, *minstr, *rule_name; + const char *timestr, *maxstr, *minstr, *raisestr, *rule_name; int penaltychangetime, rule_exists = 0, inserted = 0; - int max_penalty = 0, min_penalty = 0, min_relative = 0, max_relative = 0; + int max_penalty = 0, min_penalty = 0, raise_penalty = 0; + int min_relative = 0, max_relative = 0, raise_relative = 0; struct penalty_rule *new_penalty_rule = NULL; rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name"); @@ -2968,11 +2990,22 @@ static int load_realtime_rules(void) min_relative = 1; } } + if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) || + ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) { + raise_penalty = 0; + raise_relative = 1; + } else { + if (*raisestr == '+' || *raisestr == '-') { + raise_relative = 1; + } + } new_penalty_rule->time = penaltychangetime; new_penalty_rule->max_relative = max_relative; new_penalty_rule->max_value = max_penalty; new_penalty_rule->min_relative = min_relative; new_penalty_rule->min_value = min_penalty; + new_penalty_rule->raise_relative = raise_relative; + new_penalty_rule->raise_value = raise_penalty; AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) { if (new_penalty_rule->time < pr_iter->time) { AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list); @@ -3714,7 +3747,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * /* This is our one */ if (q->joinempty) { int status = 0; - if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty, 0))) { + if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) { *reason = QUEUE_JOINEMPTY; ao2_unlock(q); queue_t_unref(q, "Done with realtime queue"); @@ -5429,6 +5462,32 @@ static void update_qe_rule(struct queue_ent *qe) qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time); } + if (qe->raise_penalty != INT_MAX) { + char raise_penalty_str[20]; + int raise_penalty; + + if (qe->pr->raise_relative) { + raise_penalty = qe->raise_penalty + qe->pr->raise_value; + } else { + raise_penalty = qe->pr->raise_value; + } + + /* a relative change to the penalty could put it below 0 */ + if (raise_penalty < 0) { + raise_penalty = 0; + } + + if (max_penalty != INT_MAX && raise_penalty > max_penalty) { + raise_penalty = max_penalty; + } + + snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty); + pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str); + qe->raise_penalty = raise_penalty; + ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n", + qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time); + } + qe->pr = AST_LIST_NEXT(qe->pr, list); } @@ -5462,7 +5521,7 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r if (qe->parent->leavewhenempty) { int status = 0; - if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty, 0))) { + if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->raise_penalty, qe->parent->leavewhenempty, 0))) { *reason = QUEUE_LEAVEEMPTY; ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start)); leave_queue(qe); @@ -5592,10 +5651,15 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct /* disregarding penalty on too few members? */ int membercount = ao2_container_count(q->members); unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1; + int penalty = mem->penalty; if (usepenalty) { - if ((qe->max_penalty != INT_MAX && mem->penalty > qe->max_penalty) || - (qe->min_penalty != INT_MAX && mem->penalty < qe->min_penalty)) { + if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) { + /* Low penalty is raised up to the current minimum */ + penalty = qe->raise_penalty; + } + if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) || + (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) { return -1; } } else { @@ -5606,7 +5670,7 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct switch (q->strategy) { case QUEUE_STRATEGY_RINGALL: /* Everyone equal, except for penalty */ - tmp->metric = mem->penalty * 1000000 * usepenalty; + tmp->metric = penalty * 1000000 * usepenalty; break; case QUEUE_STRATEGY_LINEAR: if (pos < qe->linpos) { @@ -5618,7 +5682,7 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct } tmp->metric = pos; } - tmp->metric += mem->penalty * 1000000 * usepenalty; + tmp->metric += penalty * 1000000 * usepenalty; break; case QUEUE_STRATEGY_RRORDERED: case QUEUE_STRATEGY_RRMEMORY: @@ -5632,18 +5696,18 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct } tmp->metric = pos; } - tmp->metric += mem->penalty * 1000000 * usepenalty; + tmp->metric += penalty * 1000000 * usepenalty; break; case QUEUE_STRATEGY_RANDOM: tmp->metric = ast_random() % 1000; - tmp->metric += mem->penalty * 1000000 * usepenalty; + tmp->metric += penalty * 1000000 * usepenalty; break; case QUEUE_STRATEGY_WRANDOM: - tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); + tmp->metric = ast_random() % ((1 + penalty) * 1000); break; case QUEUE_STRATEGY_FEWESTCALLS: tmp->metric = mem->calls; - tmp->metric += mem->penalty * 1000000 * usepenalty; + tmp->metric += penalty * 1000000 * usepenalty; break; case QUEUE_STRATEGY_LEASTRECENT: if (!mem->lastcall) { @@ -5651,7 +5715,7 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct } else { tmp->metric = 1000000 - (time(NULL) - mem->lastcall); } - tmp->metric += mem->penalty * 1000000 * usepenalty; + tmp->metric += penalty * 1000000 * usepenalty; break; default: ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); @@ -7914,8 +7978,10 @@ static void copy_rules(struct queue_ent *qe, const char *rulename) new_pr->time = pr_iter->time; new_pr->max_value = pr_iter->max_value; new_pr->min_value = pr_iter->min_value; + new_pr->raise_value = pr_iter->raise_value; new_pr->max_relative = pr_iter->max_relative; new_pr->min_relative = pr_iter->min_relative; + new_pr->raise_relative = pr_iter->raise_relative; AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); } } @@ -7941,9 +8007,10 @@ static int queue_exec(struct ast_channel *chan, const char *data) const char *user_priority; const char *max_penalty_str; const char *min_penalty_str; + const char *raise_penalty_str; int prio; int qcontinue = 0; - int max_penalty, min_penalty; + int max_penalty, min_penalty, raise_penalty; enum queue_result reason = QUEUE_UNKNOWN; /* whether to exit Queue application after the timeout hits */ int tries = 0; @@ -8055,6 +8122,18 @@ static int queue_exec(struct ast_channel *chan, const char *data) } else { min_penalty = INT_MAX; } + + if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) { + if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) { + ast_debug(1, "%s: Got raise penalty %d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), raise_penalty); + } else { + ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n", + raise_penalty_str, ast_channel_name(chan)); + raise_penalty = INT_MAX; + } + } else { + raise_penalty = INT_MAX; + } ast_channel_unlock(chan); if (ast_test_flag(&opts, OPT_RINGING)) { @@ -8084,6 +8163,7 @@ static int queue_exec(struct ast_channel *chan, const char *data) qe.prio = prio; qe.max_penalty = max_penalty; qe.min_penalty = min_penalty; + qe.raise_penalty = raise_penalty; qe.last_pos_said = 0; qe.last_pos = 0; qe.last_periodic_announce_time = time(NULL); @@ -8171,7 +8251,7 @@ static int queue_exec(struct ast_channel *chan, const char *data) if (qe.parent->leavewhenempty) { int status = 0; - if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty, 0))) { + if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.raise_penalty, qe.parent->leavewhenempty, 0))) { record_abandoned(&qe); reason = QUEUE_LEAVEEMPTY; ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); @@ -10620,7 +10700,7 @@ static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { ast_cli(a->fd, "Rule: %s\n", rl_iter->name); AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { - ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value); + ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d, adjust QUEUE_MIN_PENALTY %s %d and adjust QUEUE_RAISE_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value, pr_iter->raise_relative ? "by" : "to", pr_iter->raise_value); } } } @@ -10918,6 +10998,7 @@ AST_DATA_STRUCTURE(member, DATA_EXPORT_MEMBER); MEMBER(queue_ent, pending, AST_DATA_INTEGER) \ MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER) \ MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER) \ + MEMBER(queue_ent, raise_penalty, AST_DATA_INTEGER) \ MEMBER(queue_ent, linpos, AST_DATA_INTEGER) \ MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER) \ MEMBER(queue_ent, start, AST_DATA_INTEGER) \ diff --git a/configs/samples/queuerules.conf.sample b/configs/samples/queuerules.conf.sample index 417f52de133..16648f98c0a 100644 --- a/configs/samples/queuerules.conf.sample +++ b/configs/samples/queuerules.conf.sample @@ -9,23 +9,40 @@ ; realtime_rules = yes ; -; It is possible to change the value of the QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY +; It is possible to change the value of the QUEUE_MAX_PENALTY, QUEUE_MIN_PENALTY and QUEUE_RAISE_PENALTY ; channel variables in mid-call by defining rules in the queue for when to do so. This can allow for ; a call to be opened to more members or potentially a different set of members. ; The advantage to changing members this way as opposed to inserting the caller into a ; different queue with more members or reinserting the caller into the same queue with a different ; QUEUE_MAX_PENALTY or QUEUE_MIN_PENALTY set is that the caller does not lose his place in the queue. ; +; QUEUE_MAX_PENALTY, QUEUE_MIN_PENALTY and QUEUE_RAISE_PENALTY only apply to a queue call, and are only +; modified by these rules if they are initially set in the dialplan. +; +; If QUEUE_MIN_PENALTY is set, agents with a lower penalty value will not be considered for the caller. +; If QUEUE_MAX_PENALTY is set, agents with a higher penalty value will not be considered for the caller. +; If QUEUE_RAISE_PENALTY is set, agents with a lower penalty will be treated as having a penalty = QUEUE_RAISE_PENALTY. +; +; QUEUE_RAISE_PENALTY example: +; - Agent 1 has penalty 1 +; - Agent 2 has penalty 2 +; - the queue rule is set to: +; penaltychange => 30,,,2 +; +; Prior to the 30 second mark, Agent 1 will take priority over Agent 2 for call distribution. +; After 30 seconds, Agent 1's priority is bumped to 2 by the penaltychange, so both agents are treated equally. +; ; Note: There is a limitation to these rules; a caller will follow the penaltychange rules for ; the queue that were defined at the time the caller entered the queue. If an update to the rules is ; made during the caller's stay in the queue, these will not be reflected for that caller. ; ; The syntax for these rules is -; penaltychange => ,[,absolute or relative change to QUEUE_MIN_PENALTY] +; penaltychange => ,[,absolute or relative change to QUEUE_MIN_PENALTY][,absolute or relative change to QUEUE_RAISE_PENALTY] ; ; Example: ; [myrule] ; penaltychange => 30,+3 ; 30 seconds into the call increase the QUEUE_MAX_PENALTY by 3, no change to QUEUE_MIN_PENALTY ; penaltychange => 60,10,5 ; 60 seconds into the call increase the QUEUE_MAX_PENALTY to 10 and increase the QUEUE_MIN_PENALTY to 5 ; penaltychange => 75,,7 ; 75 seconds into the call keep the QUEUE_MAX_PENALTY the same and increase the QUEUE_MIN_PENALTY to 7 +; penaltychange => 90,,,20 ; 90 seconds into the call leave QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY untouched and set QUEUE_RAISE_PENALTY to 20 From 0f487978a911356407a6faf17ffe3e1ab4518b4a Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 19 May 2017 15:05:36 +0000 Subject: [PATCH 1270/1578] chan_sip: Better ICE handling for RTCP-MUX If we are offered or are offering RTCP-MUX, don't consider RTCP ICE candidates. This confuses certain browsers (current Firefox for example) and causes intial audio setup delays. ASTERISK-26982 #close Change-Id: Ifeaf47e83972fe8dbe58b7fb3d6d1823400cfb91 --- channels/chan_sip.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 930dc0f6756..aaeb01e1398 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1215,7 +1215,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action static int process_sdp_o(const char *o, struct sip_pvt *p); static int process_sdp_c(const char *c, struct ast_sockaddr *addr); static int process_sdp_a_sendonly(const char *a, int *sendonly); -static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance); +static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance, int rtcp_mux); static int process_sdp_a_rtcp_mux(const char *a, struct sip_pvt *p, int *requested); static int process_sdp_a_dtls(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance); static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec); @@ -10128,6 +10128,24 @@ static void set_ice_components(struct sip_pvt *p, struct ast_rtp_instance *insta } } +static int has_media_level_attribute(int start, struct sip_request *req, const char *attr) +{ + int next = start; + char type; + const char *value; + + /* We don't care about the return result here */ + get_sdp_iterate(&next, req, "m"); + + while ((type = get_sdp_line(&start, next, req, &value)) != '\0') { + if (type == 'a' && !strcasecmp(value, attr)) { + return 1; + } + } + + return 0; +} + /*! \brief Process SIP SDP offer, select formats and activate media channels If offer is rejected, we will not change any properties of the call Return 0 on success, a negative value on errors. @@ -10270,13 +10288,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action else if (process_sdp_a_image(value, p)) processed = TRUE; - if (process_sdp_a_ice(value, p, p->rtp)) { + if (process_sdp_a_ice(value, p, p->rtp, 0)) { processed = TRUE; } - if (process_sdp_a_ice(value, p, p->vrtp)) { + if (process_sdp_a_ice(value, p, p->vrtp, 0)) { processed = TRUE; } - if (process_sdp_a_ice(value, p, p->trtp)) { + if (process_sdp_a_ice(value, p, p->trtp, 0)) { processed = TRUE; } @@ -10316,6 +10334,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action int image = FALSE; int text = FALSE; int processed_crypto = FALSE; + int rtcp_mux_offered = 0; char protocol[18] = {0,}; unsigned int x; struct ast_rtp_engine_dtls *dtls; @@ -10335,6 +10354,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action AST_LIST_INSERT_TAIL(&p->offered_media, offer, next); offer->type = SDP_UNKNOWN; + /* We need to check for this ahead of time */ + rtcp_mux_offered = has_media_level_attribute(iterator, req, "rtcp-mux"); + /* Check for 'audio' media offer */ if (strncmp(m, "audio ", 6) == 0) { if ((sscanf(m, "audio %30u/%30u %17s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || @@ -10701,7 +10723,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action case 'a': /* Audio specific scanning */ if (audio) { - if (process_sdp_a_ice(value, p, p->rtp)) { + if (process_sdp_a_ice(value, p, p->rtp, rtcp_mux_offered)) { processed = TRUE; } else if (process_sdp_a_dtls(value, p, p->rtp)) { processed_crypto = TRUE; @@ -10726,7 +10748,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } /* Video specific scanning */ else if (video) { - if (process_sdp_a_ice(value, p, p->vrtp)) { + if (process_sdp_a_ice(value, p, p->vrtp, rtcp_mux_offered)) { processed = TRUE; } else if (process_sdp_a_dtls(value, p, p->vrtp)) { processed_crypto = TRUE; @@ -10749,7 +10771,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } /* Text (T.140) specific scanning */ else if (text) { - if (process_sdp_a_ice(value, p, p->trtp)) { + if (process_sdp_a_ice(value, p, p->trtp, rtcp_mux_offered)) { processed = TRUE; } else if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec)) { processed = TRUE; @@ -11271,7 +11293,7 @@ static int process_sdp_a_sendonly(const char *a, int *sendonly) return found; } -static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance) +static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance, int rtcp_mux_offered) { struct ast_rtp_engine_ice *ice; int found = FALSE; @@ -11291,6 +11313,12 @@ static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_in found = TRUE; } else if (sscanf(a, "candidate: %31s %30u %3s %30u %23s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport, (unsigned *)&candidate.priority, address, &port, cand_type, relay_address, &relay_port) >= 7) { + + if (rtcp_mux_offered && ast_test_flag(&p->flags[2], SIP_PAGE3_RTCP_MUX) && candidate.id > 1) { + /* If we support RTCP-MUX and they offered it, don't consider RTCP candidates */ + return TRUE; + } + candidate.foundation = foundation; candidate.transport = transport; From 440ff38c0878e21a8ea046112ba59ee636cedfd4 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 22 May 2017 13:51:40 -0500 Subject: [PATCH 1271/1578] res_rtp_asterisk: rtcp mux using the wrong srtp unprotecting algorithm When using rtcp mux if an rtcp payload came in it would still use the srtp unprotect algorithm instead of the srtp unprotect rtcp method. Since rtcp data was being passed to the rtp unprotect method this would result in an error. This patch ensures that the correct unprotect method is chosen by making sure the passed in rtcp flag is appropriately set when rtcp mux is enabled and an rtcp payload is received. ASTERISK-26979 #close Change-Id: Ic5409f9d1a267f1d4785fc5aed867daaecca6241 --- res/res_rtp_asterisk.c | 69 +++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index f7e97627286..18987cee9eb 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2377,6 +2377,39 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as } #endif +static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet) +{ + uint8_t version; + uint8_t pt; + uint8_t m; + + if (!rtp->rtcp || rtp->rtcp->type != AST_RTP_INSTANCE_RTCP_MUX) { + return 0; + } + + version = (packet[0] & 0XC0) >> 6; + if (version == 0) { + /* version 0 indicates this is a STUN packet and shouldn't + * be interpreted as a possible RTCP packet + */ + return 0; + } + + /* The second octet of a packet will be one of the following: + * For RTP: The marker bit (1 bit) and the RTP payload type (7 bits) + * For RTCP: The payload type (8) + * + * RTP has a forbidden range of payload types (64-95) since these + * will conflict with RTCP payload numbers if the marker bit is set. + */ + m = packet[1] & 0x80; + pt = packet[1] & 0x7F; + if (m && pt >= 64 && pt <= 95) { + return 1; + } + return 0; +} + /*! \pre instance is locked */ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp) { @@ -2499,7 +2532,8 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s } #endif - if ((*in & 0xC0) && res_srtp && srtp && res_srtp->unprotect(srtp, buf, &len, rtcp) < 0) { + if ((*in & 0xC0) && res_srtp && srtp && res_srtp->unprotect( + srtp, buf, &len, rtcp || rtcp_mux(rtp, buf)) < 0) { return -1; } @@ -4885,39 +4919,6 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, return 0; } -static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet) -{ - uint8_t version; - uint8_t pt; - uint8_t m; - - if (!rtp->rtcp || rtp->rtcp->type != AST_RTP_INSTANCE_RTCP_MUX) { - return 0; - } - - version = (packet[0] & 0XC0) >> 6; - if (version == 0) { - /* version 0 indicates this is a STUN packet and shouldn't - * be interpreted as a possible RTCP packet - */ - return 0; - } - - /* The second octet of a packet will be one of the following: - * For RTP: The marker bit (1 bit) and the RTP payload type (7 bits) - * For RTCP: The payload type (8) - * - * RTP has a forbidden range of payload types (64-95) since these - * will conflict with RTCP payload numbers if the marker bit is set. - */ - m = packet[1] & 0x80; - pt = packet[1] & 0x7F; - if (m && pt >= 64 && pt <= 95) { - return 1; - } - return 0; -} - /*! \pre instance is locked */ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp) { From 36e90952ec6a6ee85926bf43a235c48940957ddc Mon Sep 17 00:00:00 2001 From: Robert Mordec Date: Tue, 23 May 2017 12:45:29 +0200 Subject: [PATCH 1272/1578] app_confbridge: Race between removing and playing name recording while leaving When user leaves a conference, its channel calls async_play_sound_file() in order to play the name announcement and then unlinks the sound file. The async_play_sound_file() function adds a task to conference playback queue, which then runs playback_common() function in a different thread. It leads to a race condition when, in some cases, channel thread may unlink the sound file before playback_common() had a chance to open it. This patch creates a file deletion task, that is queued after playback. ASTERISK-27012 #close Change-Id: I412f7922d412004b80917d4e892546c15bd70dd3 --- apps/app_confbridge.c | 79 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index a9f917b9a97..42a45c10e1a 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -2149,6 +2149,80 @@ static int conf_rec_name(struct confbridge_user *user, const char *conf_name) return 0; } +struct async_delete_name_rec_task_data { + struct confbridge_conference *conference; + char filename[0]; +}; + +static struct async_delete_name_rec_task_data *async_delete_name_rec_task_data_alloc( + struct confbridge_conference *conference, const char *filename) +{ + struct async_delete_name_rec_task_data *atd; + + atd = ast_malloc(sizeof(*atd) + strlen(filename) + 1); + if (!atd) { + return NULL; + } + + /* Safe */ + strcpy(atd->filename, filename); + atd->conference = conference; + + return atd; +} + +static void async_delete_name_rec_task_data_destroy(struct async_delete_name_rec_task_data *atd) +{ + ast_free(atd); +} + +/*! + * \brief Delete user's name file asynchronously + * + * This runs in the playback queue taskprocessor. This ensures that + * sound file is removed after playback is finished and not before. + * + * \param data An async_delete_name_rec_task_data + * \return 0 + */ +static int async_delete_name_rec_task(void *data) +{ + struct async_delete_name_rec_task_data *atd = data; + + ast_filedelete(atd->filename, NULL); + ast_log(LOG_DEBUG, "Conference '%s' removed user name file '%s'\n", + atd->conference->name, atd->filename); + + async_delete_name_rec_task_data_destroy(atd); + return 0; +} + +static int async_delete_name_rec(struct confbridge_conference *conference, + const char *filename) +{ + struct async_delete_name_rec_task_data *atd; + + if (ast_strlen_zero(filename)) { + return 0; + } else if (!sound_file_exists(filename)) { + return 0; + } + + atd = async_delete_name_rec_task_data_alloc(conference, filename); + if (!atd) { + return -1; + } + + if (ast_taskprocessor_push(conference->playback_queue, async_delete_name_rec_task, atd)) { + ast_log(LOG_WARNING, "Conference '%s' was unable to remove user name file '%s'\n", + conference->name, filename); + async_delete_name_rec_task_data_destroy(atd); + return -1; + } + + return 0; +} + static int join_callback(struct ast_bridge_channel *bridge_channel, void *ignore) { async_play_sound_ready(bridge_channel->chan); @@ -2404,6 +2478,7 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) async_play_sound_file(conference, user.name_rec_location, NULL); async_play_sound_file(conference, conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds), NULL); + async_delete_name_rec(conference, user.name_rec_location); } /* play the leave sound */ @@ -2431,10 +2506,6 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]); } - if (!ast_strlen_zero(user.name_rec_location)) { - ast_filedelete(user.name_rec_location, NULL); - } - confbridge_cleanup: ast_bridge_features_cleanup(&user.features); conf_bridge_profile_destroy(&user.b_profile); From faab0580145940f7be8ab72980aa8e69dad376fb Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 15 May 2017 20:03:36 +0000 Subject: [PATCH 1273/1578] app_queue: Fix members showing as being in call when not. A change was done which added an 'in_call' flag to queue members that was set to true while talking to an agent. Unfortunately in practice this does not accurately reflect whether they are talking to an agent or not. If a Local channel is involved and a transfer is performed then the app_queue application would incorrectly think the agent was still in a call with the caller. This was done to fix a race condition between an agent becoming available by device state and the checking of the last call information for the wrapup time. There was a small window where the last call information would be the previous value instead of the new one. This change goes about fixing the original issue in a different way by considering the call completed if device state is received which would make the agent available and if they are currently in a call. If this occurs the last call information is updated before the agent becomes available ensuring that old information is not present when checking if the member should be called. This also improves the transfer situation by actually updating and enforcing the wrapup time. ASTERISK-26399 ASTERISK-26400 ASTERISK-26715 ASTERISK-26975 Change-Id: Ife1cb686e3173b3a6d368601adef9aff69d4beea --- apps/app_queue.c | 108 +++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 60 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 0f46d280cd8..0e0b80108e2 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1570,10 +1570,11 @@ struct member { int paused; /*!< Are we paused (not accepting calls)? */ char reason_paused[80]; /*!< Reason of paused if member is paused */ int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */ + int callcompletedinsl; /*!< Whether the current call was completed within service level */ + time_t starttime; /*!< The time at which the member answered the current caller. */ time_t lastcall; /*!< When last successful call was hungup */ time_t lastpause; /*!< When started the last pause */ - unsigned int in_call:1; /*!< True if member is still in call. (so lastcall is not actual) */ - struct call_queue *lastqueue; /*!< Last queue we received a call */ + struct call_queue *lastqueue; /*!< Last queue we received a call */ unsigned int dead:1; /*!< Used to detect members deleted in realtime */ unsigned int delme:1; /*!< Flag to delete entry on reload */ char rt_uniqueid[80]; /*!< Unique id of realtime member entry */ @@ -1729,6 +1730,7 @@ static struct ao2_container *queues; static void update_realtime_members(struct call_queue *q); static struct member *interface_exists(struct call_queue *q, const char *interface); static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused); +static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime); static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface); /*! \brief sets the QUEUESTATUS channel variable */ @@ -2220,7 +2222,7 @@ static struct ast_json *queue_member_blob_create(struct call_queue *q, struct me "CallsTaken", mem->calls, "LastCall", (int)mem->lastcall, "LastPause", (int)mem->lastpause, - "InCall", mem->in_call, + "InCall", mem->starttime ? 1 : 0, "Status", mem->status, "Paused", mem->paused, "PausedReason", mem->reason_paused, @@ -2284,10 +2286,6 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) { ast_debug(4, "%s is unavailable because he is paused'\n", member->membername); break; - } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->in_call && q->wrapuptime) { - ast_debug(4, "%s is unavailable because still in call, so we can`t check " - "wrapuptime (%d)\n", member->membername, q->wrapuptime); - break; } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) { ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime); break; @@ -2384,6 +2382,14 @@ static void pending_members_remove(struct member *mem) static void update_status(struct call_queue *q, struct member *m, const int status) { if (m->status != status) { + /* If this member has transitioned to being available then update their queue + * information. If they are currently in a call then the leg to the agent will be + * considered done and the call finished. + */ + if (status == AST_DEVICE_NOT_INUSE) { + update_queue(q, m, m->callcompletedinsl, m->starttime); + } + m->status = status; /* Remove the member from the pending members pool only when the status changes. @@ -2430,9 +2436,6 @@ static int is_member_available(struct call_queue *q, struct member *mem) } /* Let wrapuptimes override device state availability */ - if (q->wrapuptime && mem->in_call) { - available = 0; /* member is still in call, cant check wrapuptime to lastcall time */ - } if (mem->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < mem->lastcall)) { available = 0; } @@ -2791,8 +2794,9 @@ static void clear_queue(struct call_queue *q) struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); while ((mem = ao2_iterator_next(&mem_iter))) { mem->calls = 0; + mem->callcompletedinsl = 0; mem->lastcall = 0; - mem->in_call = 0; + mem->starttime = 0; ao2_ref(mem, -1); } ao2_iterator_destroy(&mem_iter); @@ -4275,12 +4279,6 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call) return 0; } - if (call->member->in_call && call->lastqueue && call->lastqueue->wrapuptime) { - ast_debug(1, "%s is in call, so not available (wrapuptime %d)\n", - call->interface, call->lastqueue->wrapuptime); - return 0; - } - if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime)) || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) { ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", @@ -5522,14 +5520,22 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r * \brief update the queue status * \retval Always 0 */ -static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime) +static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime) { int oldtalktime; - + int newtalktime = time(NULL) - starttime; struct member *mem; struct call_queue *qtmp; struct ao2_iterator queue_iter; + /* It is possible for us to be called when a call has already been considered terminated + * and data updated, so to ensure we only act on the call that the agent is currently in + * we check when the call was bridged. + */ + if (!starttime || (member->starttime != starttime)) { + return 0; + } + if (shared_lastcall) { queue_iter = ao2_iterator_init(queues, 0); while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { @@ -5537,10 +5543,9 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { time(&mem->lastcall); mem->calls++; + mem->callcompletedinsl = 0; + mem->starttime = 0; mem->lastqueue = q; - mem->in_call = 0; - ast_debug(4, "Marked member %s as NOT in_call. Lastcall time: %ld \n", - mem->membername, (long)mem->lastcall); ao2_ref(mem, -1); } ao2_unlock(qtmp); @@ -5550,11 +5555,10 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom } else { ao2_lock(q); time(&member->lastcall); + member->callcompletedinsl = 0; member->calls++; + member->starttime = 0; member->lastqueue = q; - member->in_call = 0; - ast_debug(4, "Marked member %s as NOT in_call. Lastcall time: %ld \n", - member->membername, (long)member->lastcall); ao2_unlock(q); } /* Member might never experience any direct status change (local @@ -6012,7 +6016,7 @@ static void handle_blind_transfer(void *userdata, struct stasis_subscription *su send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member, queue_data->holdstart, queue_data->starttime, TRANSFER); update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl, - time(NULL) - queue_data->starttime); + queue_data->starttime); remove_stasis_subscriptions(queue_data); } @@ -6072,7 +6076,7 @@ static void handle_attended_transfer(void *userdata, struct stasis_subscription send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member, queue_data->holdstart, queue_data->starttime, TRANSFER); update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl, - time(NULL) - queue_data->starttime); + queue_data->starttime); remove_stasis_subscriptions(queue_data); } @@ -6273,7 +6277,7 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub, send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member, queue_data->holdstart, queue_data->starttime, reason); update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl, - time(NULL) - queue_data->starttime); + queue_data->starttime); remove_stasis_subscriptions(queue_data); } @@ -6534,7 +6538,6 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a int x=0; char *announce = NULL; char digit = 0; - time_t callstart; time_t now = time(NULL); struct ast_bridge_config bridge_config; char nondataquality = 1; @@ -6545,12 +6548,10 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a char tmpid[256]; int forwardsallowed = 1; int block_connected_line = 0; - int callcompletedinsl; struct ao2_iterator memi; struct queue_end_bridge *queue_end_bridge = NULL; - struct ao2_iterator queue_iter; /* to iterate through all queues (for shared_lastcall)*/ - struct member *mem; - struct call_queue *queuetmp; + int callcompletedinsl; + time_t starttime; memset(&bridge_config, 0, sizeof(bridge_config)); tmpid[0] = 0; @@ -6739,10 +6740,10 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a /* Update parameters for the queue */ time(&now); recalc_holdtime(qe, (now - qe->start)); + member = lpeer->member; ao2_lock(qe->parent); - callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); + callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); ao2_unlock(qe->parent); - member = lpeer->member; /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ ao2_ref(member, 1); hangupcalls(qe, outgoing, peer, qe->cancel_answered_elsewhere); @@ -6978,27 +6979,6 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a } qe->handled++; - /** mark member as "in_call" in all queues */ - if (shared_lastcall) { - queue_iter = ao2_iterator_init(queues, 0); - while ((queuetmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { - ao2_lock(queuetmp); - if ((mem = ao2_find(queuetmp->members, member, OBJ_POINTER))) { - mem->in_call = 1; - ast_debug(4, "Marked member %s as in_call \n", mem->membername); - ao2_ref(mem, -1); - } - ao2_unlock(queuetmp); - queue_t_unref(queuetmp, "Done with iterator"); - } - ao2_iterator_destroy(&queue_iter); - } else { - ao2_lock(qe->parent); - member->in_call = 1; - ast_debug(4, "Marked member %s as in_call \n", member->membername); - ao2_unlock(qe->parent); - } - ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer), (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); @@ -7026,8 +7006,16 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a queue_t_ref(qe->parent, "For bridge_config reference"); } - time(&callstart); - setup_stasis_subs(qe, peer, member, qe->start, callstart, callcompletedinsl); + ao2_lock(qe->parent); + time(&member->starttime); + starttime = member->starttime; + ao2_unlock(qe->parent); + /* As a queue member may end up in multiple calls at once if a transfer occurs with + * a Local channel in the mix we pass the current call information (starttime) to the + * Stasis subscriptions so when they update the queue member data it becomes a noop + * if this call is no longer between the caller and the queue member. + */ + setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl); bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM | AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM); @@ -9469,7 +9457,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s", mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(), mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(), - mem->in_call ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->in_call ? " (in call)" : "", ast_term_reset()); + mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset()); if (mem->paused) { if (ast_strlen_zero(mem->reason_paused)) { ast_str_append(&out, 0, " %s(paused was %ld secs ago)%s", @@ -9860,7 +9848,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) "%s" "\r\n", q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static", - mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, mem->in_call, mem->status, + mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, mem->starttime ? 1 : 0, mem->status, mem->paused, mem->reason_paused, idText); ++q_items; } From 8ae0227cf33ee6abfdaa29b90864d52faacc5d2c Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 23 May 2017 11:06:02 -0400 Subject: [PATCH 1274/1578] res_format_attr_h26x: Trim blanks in fmtp attributes Some devices separate format attributes with a semicolon followed by a space, so trim blanks before trying to match them. ASTERISK-27008 #close Change-Id: Ia44cb2e4fef5c73dc541a29da79cb0e19c22d9cc --- res/res_format_attr_h263.c | 2 ++ res/res_format_attr_h264.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/res/res_format_attr_h263.c b/res/res_format_attr_h263.c index 139fbf17aa9..a32f40f7d55 100644 --- a/res/res_format_attr_h263.c +++ b/res/res_format_attr_h263.c @@ -156,6 +156,8 @@ static struct ast_format *h263_parse_sdp_fmtp(const struct ast_format *format, c while ((attrib = strsep(&attribs, ";"))) { unsigned int val, val2 = 0, val3 = 0, val4 = 0; + attrib = ast_strip(attrib); + if (sscanf(attrib, "SQCIF=%30u", &val) == 1) { attr->SQCIF = val; } else if (sscanf(attrib, "QCIF=%30u", &val) == 1) { diff --git a/res/res_format_attr_h264.c b/res/res_format_attr_h264.c index 29d495bc772..fa3339543b6 100644 --- a/res/res_format_attr_h264.c +++ b/res/res_format_attr_h264.c @@ -184,6 +184,8 @@ static struct ast_format *h264_parse_sdp_fmtp(const struct ast_format *format, c unsigned int val; unsigned long int val2; + attrib = ast_strip(attrib); + if (sscanf(attrib, "profile-level-id=%lx", &val2) == 1) { attr->PROFILE_IDC = ((val2 >> 16) & 0xFF); attr->PROFILE_IOP = ((val2 >> 8) & 0xFF); From e490aa317662d91209909ca28f0112a2dd40c0c7 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 23 May 2017 13:35:25 -0400 Subject: [PATCH 1275/1578] res_agi: Fix malformed AGI usage response If the generated XML documentation for a command does not end with a \n, the postamble of the usage message does not appear on its own line. ASTERISK-25662 #close Change-Id: If190f1e9e37fe215fed95897d78d4a6e142b0020 --- res/res_agi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_agi.c b/res/res_agi.c index 557f3497152..fab9f360fe8 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -4037,7 +4037,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n"); } else { ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n"); - ast_agi_send(agi->fd, chan, "%s", c->usage); + ast_agi_send(agi->fd, chan, "%s\n", c->usage); ast_agi_send(agi->fd, chan, "520 End of proper usage.\n"); } From 3dcb3c88aa2f77d32fb4a0c6370b337bb017f30e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 23 May 2017 14:06:22 -0400 Subject: [PATCH 1276/1578] res_agi: Prevent crash when SET VARIABLE called without arguments Explicitly check that the appropriate number of arguments were passed to SET VARIABLE before attempting to reference them. Also initialize the arguments array to zeroes before populating it. ASTERISK-22432 #close Change-Id: I5143607d80a2724f749c1674f3126b04ed32ea97 --- res/res_agi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/res/res_agi.c b/res/res_agi.c index 557f3497152..6ba173f2a57 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -3183,6 +3183,10 @@ static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, co static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[]) { + if (argc != 4) { + return RESULT_SHOWUSAGE; + } + if (argv[3]) pbx_builtin_setvar_helper(chan, argv[2], argv[3]); @@ -4001,7 +4005,7 @@ static void publish_async_exec_end(struct ast_channel *chan, int command_id, con static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead) { - const char *argv[MAX_ARGS]; + const char *argv[MAX_ARGS] = {0}; int argc = MAX_ARGS; int res; agi_command *c; From e2e6baa8d8f3bc46fb642e23b62fecdc94dd0236 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 23 May 2017 14:33:16 -0400 Subject: [PATCH 1277/1578] res_agi: Clarify 'RECORD FILE' documentation Documented the 'beep' option in both the parameters list and the command description. ASTERISK-23839 #close Change-Id: I4970395c922dbdce3f7cf0f56d5b065ec9aa53ea --- res/res_agi.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/res/res_agi.c b/res/res_agi.c index 557f3497152..0bf62900481 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -449,13 +449,34 @@ Records to a given file. - - - - - - - + + The destination filename of the recorded audio. + + + The audio format in which to save the resulting file. + + + The DTMF digits that will terminate the recording process. + + + The maximum recording time in milliseconds. Set to -1 for no + limit. + + + Causes the recording to first seek to the specified offset before + recording begins. + + + Causes Asterisk to play a beep as recording begins. This argument + can take any value. + + + The number of seconds of silence that are permitted before the + recording is terminated, regardless of the + escape_digits or timeout + arguments. If specified, this parameter must be preceded by + s=. + Record to a file until a given dtmf digit in the sequence is received. @@ -463,7 +484,9 @@ will be recorded. The timeout is the maximum record time in milliseconds, or -1 for no timeout. offset samples is optional, and, if provided, will seek - to the offset without exceeding the end of the file. silence is + to the offset without exceeding the end of the + file. beep can take any value, and causes Asterisk + to play a beep to the channel that is about to be recorded. silence is the number of seconds of silence allowed before the function returns despite the lack of dtmf digits or reaching timeout. silence value must be preceded by s= and is also optional. From d847fe6585bee14b6b9f76d0b6c50b0b4d5bf9cc Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 23 May 2017 16:42:04 -0400 Subject: [PATCH 1278/1578] res_agi: Allow configuration of audio format of EAGI pipe This change allows the format of the EAGI audio pipe to be changed by setting the dialplan variable 'EAGI_AUDIO_FORMAT' to the name of one of the loaded formats. ASTERISK-26124 #close Change-Id: I7a10fad401ad2a21c68c2e7246fa357d5cee5bbd --- CHANGES | 11 +++++++++++ res/res_agi.c | 22 +++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index fcbe04c943b..305719ae4d2 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,17 @@ app_queue * PAUSEALL/UNPAUSEALL now sets the pause reason in the queue_log if it has been defined. +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------ +------------------------------------------------------------------------------ + +res_agi +------------------ + * The EAGI() application will now look for a dialplan variable named + EAGI_AUDIO_FORMAT and use that format with the 'enhanced' audio pipe that + EAGI provides. If not specified, it will continue to use the default signed + linear (slin). + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ diff --git a/res/res_agi.c b/res/res_agi.c index 557f3497152..0463573bbd5 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -4552,15 +4552,30 @@ static int eagi_exec(struct ast_channel *chan, const char *data) { int res; struct ast_format *readformat; + struct ast_format *requested_format = NULL; + const char *requested_format_name; if (ast_check_hangup(chan)) { ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n"); return 0; } + + requested_format_name = pbx_builtin_getvar_helper(chan, "EAGI_AUDIO_FORMAT"); + if (requested_format_name) { + requested_format = ast_format_cache_get(requested_format_name); + if (requested_format) { + ast_verb(3, "<%s> Setting EAGI audio pipe format to %s\n", + ast_channel_name(chan), ast_format_get_name(requested_format)); + } else { + ast_log(LOG_ERROR, "Could not find requested format: %s\n", requested_format_name); + } + } + readformat = ao2_bump(ast_channel_readformat(chan)); - if (ast_set_read_format(chan, ast_format_slin)) { + if (ast_set_read_format(chan, requested_format ?: ast_format_slin)) { ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan)); - ao2_ref(readformat, -1); + ao2_cleanup(requested_format); + ao2_cleanup(readformat); return -1; } res = agi_exec_full(chan, data, 1, 0); @@ -4570,7 +4585,8 @@ static int eagi_exec(struct ast_channel *chan, const char *data) ast_format_get_name(readformat)); } } - ao2_ref(readformat, -1); + ao2_cleanup(requested_format); + ao2_cleanup(readformat); return res; } From 08edd54c1b11ec35bfa988bf9d3115e6ae9a94f3 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 24 May 2017 14:50:56 -0600 Subject: [PATCH 1279/1578] unittests: Add a unit test that causes a SEGV and... ...that can only be run by explicitly calling it with 'test execute category /DO_NOT_RUN/ name RAISE_SEGV' This allows us to more easily test CI and debugging tools that should do certain things when asterisk coredumps. To allow this a new member was added to the ast_test_info structure named 'explicit_only'. If set by a test, the test will be skipped during a 'test execute all' or 'test execute category ...'. Change-Id: Ia3a11856aae4887df9a02b6b081cc777b36eb6ed --- include/asterisk/test.h | 8 ++++++++ main/test.c | 4 ++-- tests/test_pbx.c | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/asterisk/test.h b/include/asterisk/test.h index 49731feb678..90e772cbc72 100644 --- a/include/asterisk/test.h +++ b/include/asterisk/test.h @@ -241,6 +241,14 @@ struct ast_test_info { * \note The description must not end with a newline. */ const char *description; + /*! + * \brief Only run if explicitly named + * + * \details + * Run this test only if it's explicitly named on the command line. + * Do NOT run it as part of an execute category or execute all command. + */ + unsigned int explicit_only; }; #ifdef TEST_FRAMEWORK diff --git a/main/test.c b/main/test.c index 062451fb668..f45ad9b620b 100644 --- a/main/test.c +++ b/main/test.c @@ -344,7 +344,7 @@ static int test_execute_multiple(const char *name, const char *category, struct execute = 0; switch (mode) { case TEST_CATEGORY: - if (!test_cat_cmp(test->info.category, category)) { + if (!test_cat_cmp(test->info.category, category) && !test->info.explicit_only) { execute = 1; } break; @@ -354,7 +354,7 @@ static int test_execute_multiple(const char *name, const char *category, struct } break; case TEST_ALL: - execute = 1; + execute = !test->info.explicit_only; } if (execute) { diff --git a/tests/test_pbx.c b/tests/test_pbx.c index 576fe1fb889..00fa4113069 100644 --- a/tests/test_pbx.c +++ b/tests/test_pbx.c @@ -321,8 +321,29 @@ AST_TEST_DEFINE(pattern_match_test) return res; } +AST_TEST_DEFINE(segv) +{ + switch (cmd) { + case TEST_INIT: + info->name = "RAISE_SEGV"; + info->category = "/DO_NOT_RUN/"; + info->summary = "RAISES SEGV!!! (will only be run if explicitly called)"; + info->description = "RAISES SEGV!!! (will only be run if explicitly called). " + "This test is mainly used for testing CI and tool failure scenarios."; + info->explicit_only = 1; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + raise(SIGSEGV); + + return AST_TEST_FAIL; +} + static int unload_module(void) { + AST_TEST_UNREGISTER(segv); AST_TEST_UNREGISTER(pattern_match_test); return 0; } @@ -330,6 +351,7 @@ static int unload_module(void) static int load_module(void) { AST_TEST_REGISTER(pattern_match_test); + AST_TEST_REGISTER(segv); return AST_MODULE_LOAD_SUCCESS; } From 44c5a144ce3194fb9cec02f42436d93853b33a86 Mon Sep 17 00:00:00 2001 From: Martin Tomec Date: Tue, 23 May 2017 18:07:53 +0200 Subject: [PATCH 1280/1578] Sqlite3: make busy_timeout configurable. Enables runtime configuration of busy_timeout for sqlite databases. Default timeout remains 1000ms. ASTERISK-27014 #close Change-Id: I8921a3aac3c335843be4cb17d2dd0a5c157a36da --- cdr/cdr_sqlite3_custom.c | 12 +++++++++++- cel/cel_sqlite3_custom.c | 12 +++++++++++- configs/samples/cdr_sqlite3_custom.conf.sample | 1 + configs/samples/cel_sqlite3_custom.conf.sample | 1 + configs/samples/res_config_sqlite3.conf.sample | 6 +++++- res/res_config_sqlite3.c | 13 ++++++++++++- 6 files changed, 41 insertions(+), 4 deletions(-) diff --git a/cdr/cdr_sqlite3_custom.c b/cdr/cdr_sqlite3_custom.c index e8d763edd52..2212d04992e 100644 --- a/cdr/cdr_sqlite3_custom.c +++ b/cdr/cdr_sqlite3_custom.c @@ -61,6 +61,7 @@ static sqlite3 *db = NULL; static char table[80]; static char *columns; +static int busy_timeout; struct values { AST_LIST_ENTRY(values) list; @@ -181,6 +182,15 @@ static int load_config(int reload) strcpy(table, "cdr"); } + /* sqlite3_busy_timeout in miliseconds */ + if ((tmp = ast_variable_retrieve(cfg, "master", "busy_timeout")) != NULL) { + if (ast_parse_arg(tmp, PARSE_INT32|PARSE_DEFAULT, &busy_timeout, 1000) != 0) { + ast_log(LOG_WARNING, "Invalid busy_timeout value '%s' specified. Using 1000 instead.\n", tmp); + } + } else { + busy_timeout = 1000; + } + /* Columns */ if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) { ast_config_destroy(cfg); @@ -305,7 +315,7 @@ static int load_module(void) free_config(0); return AST_MODULE_LOAD_DECLINE; } - sqlite3_busy_timeout(db, 1000); + sqlite3_busy_timeout(db, busy_timeout); /* is the table there? */ sql = sqlite3_mprintf("SELECT COUNT(AcctId) FROM %q;", table); res = sqlite3_exec(db, sql, NULL, NULL, NULL); diff --git a/cel/cel_sqlite3_custom.c b/cel/cel_sqlite3_custom.c index 6075b8a2b5c..5675da6b33f 100644 --- a/cel/cel_sqlite3_custom.c +++ b/cel/cel_sqlite3_custom.c @@ -68,6 +68,7 @@ static char table[80]; * \bug Handling of this var is crash prone on reloads */ static char *columns; +static int busy_timeout; struct values { char *expression; @@ -187,6 +188,15 @@ static int load_config(int reload) strcpy(table, "cel"); } + /* sqlite3_busy_timeout in miliseconds */ + if ((tmp = ast_variable_retrieve(cfg, "master", "busy_timeout")) != NULL) { + if (ast_parse_arg(tmp, PARSE_INT32|PARSE_DEFAULT, &busy_timeout, 1000) != 0) { + ast_log(LOG_WARNING, "Invalid busy_timeout value '%s' specified. Using 1000 instead.\n", tmp); + } + } else { + busy_timeout = 1000; + } + /* Columns */ if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) { ast_config_destroy(cfg); @@ -306,7 +316,7 @@ static int load_module(void) free_config(); return AST_MODULE_LOAD_DECLINE; } - sqlite3_busy_timeout(db, 1000); + sqlite3_busy_timeout(db, busy_timeout); /* is the table there? */ sql = sqlite3_mprintf("SELECT COUNT(*) FROM %q;", table); res = sqlite3_exec(db, sql, NULL, NULL, NULL); diff --git a/configs/samples/cdr_sqlite3_custom.conf.sample b/configs/samples/cdr_sqlite3_custom.conf.sample index 0d5dc091c4b..4b88d58d481 100644 --- a/configs/samples/cdr_sqlite3_custom.conf.sample +++ b/configs/samples/cdr_sqlite3_custom.conf.sample @@ -5,6 +5,7 @@ ;table => cdr ;columns => calldate, clid, dcontext, channel, dstchannel, lastapp, lastdata, duration, billsec, disposition, amaflags, accountcode, uniqueid, userfield, test ;values => '${CDR(start)}','${CDR(clid)}','${CDR(dcontext)}','${CDR(channel)}','${CDR(dstchannel)}','${CDR(lastapp)}','${CDR(lastdata)}','${CDR(duration)}','${CDR(billsec)}','${CDR(disposition)}','${CDR(amaflags)}','${CDR(accountcode)}','${CDR(uniqueid)}','${CDR(userfield)}','${CDR(test)}' +;busy_timeout => 1000 ;Enable High Resolution Times for billsec and duration fields ;values => '${CDR(start)}','${CDR(clid)}','${CDR(dcontext)}','${CDR(channel)}','${CDR(dstchannel)}','${CDR(lastapp)}','${CDR(lastdata)}','${CDR(duration,f)}','${CDR(billsec,f)}','${CDR(disposition)}','${CDR(amaflags)}','${CDR(accountcode)}','${CDR(uniqueid)}','${CDR(userfield)}','${CDR(test)}' diff --git a/configs/samples/cel_sqlite3_custom.conf.sample b/configs/samples/cel_sqlite3_custom.conf.sample index 2d9a24fc7bf..aa908a4f366 100644 --- a/configs/samples/cel_sqlite3_custom.conf.sample +++ b/configs/samples/cel_sqlite3_custom.conf.sample @@ -22,3 +22,4 @@ ;table => cel ;columns => eventtype, eventtime, cidname, cidnum, cidani, cidrdnis, ciddnid, context, exten, channame, appname, appdata, amaflags, accountcode, uniqueid, userfield, peer, userdeftype, eventextra ;values => '${eventtype}','${eventtime}','${CALLERID(name)}','${CALLERID(num)}','${CALLERID(ANI)}','${CALLERID(RDNIS)}','${CALLERID(DNID)}','${CHANNEL(context)}','${CHANNEL(exten)}','${CHANNEL(channame)}','${CHANNEL(appname)}','${CHANNEL(appdata)}','${CHANNEL(amaflags)}','${CHANNEL(accountcode)}','${CHANNEL(uniqueid)}','${CHANNEL(userfield)}','${BRIDGEPEER}','${userdeftype}','${eventextra}' +;busy_timeout => 1000 \ No newline at end of file diff --git a/configs/samples/res_config_sqlite3.conf.sample b/configs/samples/res_config_sqlite3.conf.sample index 5416c809e87..2588b26c938 100644 --- a/configs/samples/res_config_sqlite3.conf.sample +++ b/configs/samples/res_config_sqlite3.conf.sample @@ -28,4 +28,8 @@ ; to lock for writing. ; ;batch=1000 - +; +; busy timeout - timeout in miliseconds to stop waiting for locked database. +; More info at https://www.sqlite.org/c3ref/busy_timeout.html +; +;busy_timeout=1000 \ No newline at end of file diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index 0025548be3b..bbf6db211e7 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -103,6 +103,7 @@ struct realtime_sqlite3_db { unsigned int exiting:1; unsigned int wakeup:1; unsigned int batch; + int busy_timeout; }; struct ao2_container *databases; @@ -342,7 +343,7 @@ static int db_open(struct realtime_sqlite3_db *db) ao2_unlock(db); return -1; } - sqlite3_busy_timeout(db->handle, 1000); + sqlite3_busy_timeout(db->handle, db->busy_timeout); if (db->debug) { sqlite3_trace(db->handle, trace_cb, db); @@ -400,6 +401,7 @@ static struct realtime_sqlite3_db *new_realtime_sqlite3_db(struct ast_config *co db->requirements = REALTIME_SQLITE3_REQ_WARN; db->batch = 100; ast_string_field_set(db, name, cat); + db->busy_timeout = 1000; for (var = ast_variable_browse(config, cat); var; var = var->next) { if (!strcasecmp(var->name, "dbfile")) { @@ -410,6 +412,10 @@ static struct realtime_sqlite3_db *new_realtime_sqlite3_db(struct ast_config *co ast_app_parse_timelen(var->value, (int *) &db->batch, TIMELEN_MILLISECONDS); } else if (!strcasecmp(var->name, "debug")) { db->debug = ast_true(var->value); + } else if (!strcasecmp(var->name, "busy_timeout")) { + if (ast_parse_arg(var->value, PARSE_INT32|PARSE_DEFAULT, &(db->busy_timeout), 1000) != 0) { + ast_log(LOG_WARNING, "Invalid busy_timeout value '%s' at res_config_sqlite3.conf:%d. Using 1000 instead.\n", var->value, var->lineno); + } } } @@ -454,6 +460,11 @@ static int update_realtime_sqlite3_db(struct realtime_sqlite3_db *db, struct ast db_open(db); /* Also handles setting appropriate debug on new handle */ } + if (db->busy_timeout != new->busy_timeout) { + db->busy_timeout = new->busy_timeout; + sqlite3_busy_timeout(db->handle, db->busy_timeout); + } + if (db->batch != new->batch) { if (db->batch == 0) { db->batch = new->batch; From 59348aa18206b9d15d46ed8d78f811b611f6405b Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 25 May 2017 12:10:00 -0400 Subject: [PATCH 1281/1578] format_mp3: Don't try to build format_mp3 if we don't have sources ASTERISK-23951 #close Reported by: Tzafrir Cohen Change-Id: Iebf181d44bb735787fde4b5be863c4d7e2478a30 --- addons/Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/Makefile b/addons/Makefile index d12d0fd3b2c..82bbc49a113 100644 --- a/addons/Makefile +++ b/addons/Makefile @@ -32,9 +32,12 @@ ALL_C_MODS:=app_mysql \ cdr_mysql \ chan_mobile \ chan_ooh323 \ - format_mp3 \ res_config_mysql +ifneq ($(wildcard mp3/Makefile),) + ALL_C_MODS += format_mp3 +endif + all: check_mp3 _all check_mp3: @@ -43,10 +46,10 @@ ifeq ($(filter format_mp3,$(MENUSELECT_ADDONS)),) echo ; \ echo "**************************************************************" ; \ echo "*** ***" ; \ - echo "*** ---> READ THIS OR YOUR BUILD WILL FAIL <--- ***" ; \ + echo "*** ---> IMPORTANT INFORMATION ABOUT format_mp3 <--- ***" ; \ echo "*** ***" ; \ echo "*** format_mp3 has been selected to be installed, but the ***" ; \ - echo "*** mp3 decoder library has not yet been downloaded into ***" ; \ + echo "*** MP3 decoder library has not yet been downloaded into ***" ; \ echo "*** the source tree. To do so, please run the following ***" ; \ echo "*** command: ***" ; \ echo "*** ***" ; \ From 1f136fe8859c8c4b42e9608bab01eab45d549a55 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 26 May 2017 12:15:42 -0400 Subject: [PATCH 1282/1578] res_srtp: Add support for libsrtp2 ASTERISK-25294 #close Reported by: Tzafrir Cohen ASTERISK-26976 #close Reported by: Alex Change-Id: I789b1c3d1ed31365bbd9339fa58ef36f48833c40 --- autoconf/ast_ext_lib.m4 | 36 ++ configure | 589 +++++++++++++++++++++++++++++-- configure.ac | 93 ++--- include/asterisk/autoconfig.h.in | 3 + res/res_srtp.c | 16 +- res/srtp/srtp_compat.h | 40 +++ 6 files changed, 703 insertions(+), 74 deletions(-) create mode 100644 res/srtp/srtp_compat.h diff --git a/autoconf/ast_ext_lib.m4 b/autoconf/ast_ext_lib.m4 index 2c73b40c5de..cd5a3a77938 100644 --- a/autoconf/ast_ext_lib.m4 +++ b/autoconf/ast_ext_lib.m4 @@ -164,3 +164,39 @@ _ACEOF fi m4_ifval([$7], [AH_TEMPLATE(m4_bpatsubst([[HAVE_$1_VERSION]], [(.*)]), [Define to the version of the $2 library.])]) ]) + +# Check if the previously discovered library can be dynamically linked. +# +# AST_EXT_LIB_CHECK_SHARED([package], [library], [function], [header], +# [extra libs], [extra cflags], [action-if-true], [action-if-false]) +AC_DEFUN([AST_EXT_LIB_CHECK_SHARED], +[ +if test "x${PBX_$1}" = "x1"; then + ast_ext_lib_check_shared_saved_libs="${LIBS}" + ast_ext_lib_check_shared_saved_ldflags="${LDFLAGS}" + ast_ext_lib_check_shared_saved_cflags="${CFLAGS}" + LIBS="${LIBS} ${$1_LIB} $5" + LDFLAGS="${LDFLAGS} -shared -fPIC" + CFLAGS="${CFLAGS} ${$1_INCLUDE} $6" + AC_MSG_CHECKING(for the ability of -l$2 to be linked in a shared object) + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM( + [#include <$4>], + [$3();] + ) + ], + [ + AC_MSG_RESULT(yes) + $7 + ], + [ + AC_MSG_RESULT(no) + $8 + ] + ) + CFLAGS="${ast_ext_lib_check_shared_saved_cflags}" + LDFLAGS="${ast_ext_lib_check_shared_saved_ldflags}" + LIBS="${ast_ext_lib_check_shared_saved_libs}" +fi +]) diff --git a/configure b/configure index 89de95ae6bd..739cf65e410 100755 --- a/configure +++ b/configure @@ -1354,6 +1354,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -1537,6 +1538,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1789,6 +1791,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1926,7 +1937,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2079,6 +2090,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -14897,7 +14909,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14943,7 +14955,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14967,7 +14979,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15012,7 +15024,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15036,7 +15048,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -33421,6 +33433,516 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi +if test "x${PBX_SRTP}" != "x1" -a "${USE_SRTP}" != "no"; then + pbxlibdir="" + # if --with-SRTP=DIR has been specified, use it. + if test "x${SRTP_DIR}" != "x"; then + if test -d ${SRTP_DIR}/lib; then + pbxlibdir="-L${SRTP_DIR}/lib" + else + pbxlibdir="-L${SRTP_DIR}" + fi + fi + pbxfuncname="srtp_init" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp2_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp2" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp2... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp2 ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_FOUND=yes +else + AST_SRTP_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_FOUND}" = "yes"; then + SRTP_LIB="${pbxlibdir} -lsrtp2 " + # if --with-SRTP=DIR has been specified, use it. + if test "x${SRTP_DIR}" != "x"; then + SRTP_INCLUDE="-I${SRTP_DIR}/include" + fi + SRTP_INCLUDE="${SRTP_INCLUDE} " + if test "xsrtp2/srtp.h" = "x" ; then # no header, assume found + SRTP_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "srtp2/srtp.h" "ac_cv_header_srtp2_srtp_h" "$ac_includes_default" +if test "x$ac_cv_header_srtp2_srtp_h" = xyes; then : + SRTP_HEADER_FOUND=1 +else + SRTP_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_HEADER_FOUND}" = "x0" ; then + SRTP_LIB="" + SRTP_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_LIB="" + fi + PBX_SRTP=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP 1 +_ACEOF + + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_VERSION 2 +_ACEOF + + fi + fi +fi + + + +if test "x${PBX_SRTP}" = "x1"; then + ast_ext_lib_check_shared_saved_libs="${LIBS}" + ast_ext_lib_check_shared_saved_ldflags="${LDFLAGS}" + ast_ext_lib_check_shared_saved_cflags="${CFLAGS}" + LIBS="${LIBS} ${SRTP_LIB} " + LDFLAGS="${LDFLAGS} -shared -fPIC" + CFLAGS="${CFLAGS} ${SRTP_INCLUDE} " + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the ability of -lsrtp2 to be linked in a shared object" >&5 +$as_echo_n "checking for the ability of -lsrtp2 to be linked in a shared object... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ +srtp_init(); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ***" >&5 +$as_echo "$as_me: WARNING: ***" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** libsrtp2 could not be linked as a shared object." >&5 +$as_echo "$as_me: WARNING: *** libsrtp2 could not be linked as a shared object." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Try compiling libsrtp2 manually. Configure libsrtp2" >&5 +$as_echo "$as_me: WARNING: *** Try compiling libsrtp2 manually. Configure libsrtp2" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** with ./configure --prefix=/usr replacing /usr with" >&5 +$as_echo "$as_me: WARNING: *** with ./configure --prefix=/usr replacing /usr with" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** the prefix of your choice, and then make with" >&5 +$as_echo "$as_me: WARNING: *** the prefix of your choice, and then make with" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** 'make libsrtp2.so'" >&5 +$as_echo "$as_me: WARNING: *** 'make libsrtp2.so'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ***" >&5 +$as_echo "$as_me: WARNING: ***" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** After re-installing libsrtp2, re-run the Asterisk" >&5 +$as_echo "$as_me: WARNING: *** After re-installing libsrtp2, re-run the Asterisk" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** configure script." >&5 +$as_echo "$as_me: WARNING: *** configure script." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ***" >&5 +$as_echo "$as_me: WARNING: ***" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** If you do not need SRTP support re-run configure" >&5 +$as_echo "$as_me: WARNING: *** If you do not need SRTP support re-run configure" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** with the --without-srtp option." >&5 +$as_echo "$as_me: WARNING: *** with the --without-srtp option." >&2;} + exit 1 + + + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="${ast_ext_lib_check_shared_saved_cflags}" + LDFLAGS="${ast_ext_lib_check_shared_saved_ldflags}" + LIBS="${ast_ext_lib_check_shared_saved_libs}" +fi + + +if test "x$PBX_SRTP" = x1; +then + +if test "x${PBX_SRTP_256}" != "x1" -a "${USE_SRTP_256}" != "no"; then + pbxlibdir="" + # if --with-SRTP_256=DIR has been specified, use it. + if test "x${SRTP_256_DIR}" != "x"; then + if test -d ${SRTP_256_DIR}/lib; then + pbxlibdir="-L${SRTP_256_DIR}/lib" + else + pbxlibdir="-L${SRTP_256_DIR}" + fi + fi + pbxfuncname="srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_256_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp2_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp2" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp2... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp2 ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_256_FOUND=yes +else + AST_SRTP_256_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_256_FOUND}" = "yes"; then + SRTP_256_LIB="${pbxlibdir} -lsrtp2 " + # if --with-SRTP_256=DIR has been specified, use it. + if test "x${SRTP_256_DIR}" != "x"; then + SRTP_256_INCLUDE="-I${SRTP_256_DIR}/include" + fi + SRTP_256_INCLUDE="${SRTP_256_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_256_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_256_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_256_HEADER_FOUND=1 +else + SRTP_256_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_256_HEADER_FOUND}" = "x0" ; then + SRTP_256_LIB="" + SRTP_256_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_256_LIB="" + fi + PBX_SRTP_256=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_256 1 +_ACEOF + + fi + fi +fi + + + +if test "x${PBX_SRTP_GCM}" != "x1" -a "${USE_SRTP_GCM}" != "no"; then + pbxlibdir="" + # if --with-SRTP_GCM=DIR has been specified, use it. + if test "x${SRTP_GCM_DIR}" != "x"; then + if test -d ${SRTP_GCM_DIR}/lib; then + pbxlibdir="-L${SRTP_GCM_DIR}/lib" + else + pbxlibdir="-L${SRTP_GCM_DIR}" + fi + fi + pbxfuncname="srtp_crypto_policy_set_aes_gcm_128_8_auth" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_GCM_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp2_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp2" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp2... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp2 ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_GCM_FOUND=yes +else + AST_SRTP_GCM_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_GCM_FOUND}" = "yes"; then + SRTP_GCM_LIB="${pbxlibdir} -lsrtp2 " + # if --with-SRTP_GCM=DIR has been specified, use it. + if test "x${SRTP_GCM_DIR}" != "x"; then + SRTP_GCM_INCLUDE="-I${SRTP_GCM_DIR}/include" + fi + SRTP_GCM_INCLUDE="${SRTP_GCM_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_GCM_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_GCM_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_GCM_HEADER_FOUND=1 +else + SRTP_GCM_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_GCM_HEADER_FOUND}" = "x0" ; then + SRTP_GCM_LIB="" + SRTP_GCM_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_GCM_LIB="" + fi + PBX_SRTP_GCM=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_GCM 1 +_ACEOF + + fi + fi +fi + + + +if test "x${PBX_SRTP_SHUTDOWN}" != "x1" -a "${USE_SRTP_SHUTDOWN}" != "no"; then + pbxlibdir="" + # if --with-SRTP_SHUTDOWN=DIR has been specified, use it. + if test "x${SRTP_SHUTDOWN_DIR}" != "x"; then + if test -d ${SRTP_SHUTDOWN_DIR}/lib; then + pbxlibdir="-L${SRTP_SHUTDOWN_DIR}/lib" + else + pbxlibdir="-L${SRTP_SHUTDOWN_DIR}" + fi + fi + pbxfuncname="srtp_shutdown" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_SHUTDOWN_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp2_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp2" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp2... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp2 ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_SHUTDOWN_FOUND=yes +else + AST_SRTP_SHUTDOWN_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_SHUTDOWN_FOUND}" = "yes"; then + SRTP_SHUTDOWN_LIB="${pbxlibdir} -lsrtp2 " + # if --with-SRTP_SHUTDOWN=DIR has been specified, use it. + if test "x${SRTP_SHUTDOWN_DIR}" != "x"; then + SRTP_SHUTDOWN_INCLUDE="-I${SRTP_SHUTDOWN_DIR}/include" + fi + SRTP_SHUTDOWN_INCLUDE="${SRTP_SHUTDOWN_INCLUDE} " + if test "xsrtp2/srtp.h" = "x" ; then # no header, assume found + SRTP_SHUTDOWN_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_SHUTDOWN_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "srtp2/srtp.h" "ac_cv_header_srtp2_srtp_h" "$ac_includes_default" +if test "x$ac_cv_header_srtp2_srtp_h" = xyes; then : + SRTP_SHUTDOWN_HEADER_FOUND=1 +else + SRTP_SHUTDOWN_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_SHUTDOWN_HEADER_FOUND}" = "x0" ; then + SRTP_SHUTDOWN_LIB="" + SRTP_SHUTDOWN_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_SHUTDOWN_LIB="" + fi + PBX_SRTP_SHUTDOWN=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_SHUTDOWN 1 +_ACEOF + + fi + fi +fi + + + + # libsrtp2 removed support for PRNG, so we require OpenSSL + if test "x$PBX_OPENSSL" != x1; + then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ***" >&5 +$as_echo "$as_me: WARNING: ***" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** OpenSSL required when using libsrtp2, checking for libsrtp instead." >&5 +$as_echo "$as_me: WARNING: *** OpenSSL required when using libsrtp2, checking for libsrtp instead." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ***" >&5 +$as_echo "$as_me: WARNING: ***" >&2;} + PBX_SRTP=0 + fi +fi + +if test "x$PBX_SRTP" != x1; +then + if test "x${PBX_SRTP}" != "x1" -a "${USE_SRTP}" != "no"; then pbxlibdir="" # if --with-SRTP=DIR has been specified, use it. @@ -33517,6 +34039,10 @@ fi PBX_SRTP=1 cat >>confdefs.h <<_ACEOF #define HAVE_SRTP 1 +_ACEOF + + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_VERSION 1 _ACEOF fi @@ -33525,20 +34051,19 @@ fi -if test "$PBX_SRTP" = "1"; -then - saved_libs="${LIBS}" - saved_ldflags="${LDFLAGS}" - saved_cflags="${CFLAGS}" - LIBS="${LIBS} ${SRTP_LIB}" - LDFLAGS="${LDFLAGS} -shared -fPIC" - CFLAGS="${CFLAGS} ${SRTP_INCLUDE}" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the ability of -lsrtp to be linked in a shared object" >&5 +if test "x${PBX_SRTP}" = "x1"; then + ast_ext_lib_check_shared_saved_libs="${LIBS}" + ast_ext_lib_check_shared_saved_ldflags="${LDFLAGS}" + ast_ext_lib_check_shared_saved_cflags="${CFLAGS}" + LIBS="${LIBS} ${SRTP_LIB} " + LDFLAGS="${LDFLAGS} -shared -fPIC" + CFLAGS="${CFLAGS} ${SRTP_INCLUDE} " + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the ability of -lsrtp to be linked in a shared object" >&5 $as_echo_n "checking for the ability of -lsrtp to be linked in a shared object... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #include + #include int main () { @@ -33550,12 +34075,16 @@ srtp_init(); _ACEOF if ac_fn_c_try_link "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + + else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ***" >&5 $as_echo "$as_me: WARNING: ***" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** libsrtp could not be linked as a shared object." >&5 @@ -33566,8 +34095,8 @@ $as_echo "$as_me: WARNING: *** Try compiling libsrtp manually. Configure libsrtp $as_echo "$as_me: WARNING: *** with ./configure CFLAGS=-fPIC --prefix=/usr" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** replacing /usr with the prefix of your choice." >&5 $as_echo "$as_me: WARNING: *** replacing /usr with the prefix of your choice." >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** After re-installing libsrtp" >&5 -$as_echo "$as_me: WARNING: *** After re-installing libsrtp" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** After re-installing libsrtp, re-run the Asterisk" >&5 +$as_echo "$as_me: WARNING: *** After re-installing libsrtp, re-run the Asterisk" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** configure script." >&5 $as_echo "$as_me: WARNING: *** configure script." >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ***" >&5 @@ -33579,16 +34108,18 @@ $as_echo "$as_me: WARNING: *** with the --without-srtp option." >&2;} exit 1 + fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LIBS="${saved_libs}" - LDFLAGS="${saved_ldflags}" - CFLAGS="${saved_cflags}" + CFLAGS="${ast_ext_lib_check_shared_saved_cflags}" + LDFLAGS="${ast_ext_lib_check_shared_saved_ldflags}" + LIBS="${ast_ext_lib_check_shared_saved_libs}" fi -if test "$PBX_SRTP" = "1"; -then + + if test "x$PBX_SRTP" = x1; + then if test "x${PBX_SRTP_256}" != "x1" -a "${USE_SRTP_256}" != "no"; then pbxlibdir="" @@ -33808,7 +34339,7 @@ if test "x${PBX_SRTP_GCM}" != "x1" -a "${USE_SRTP_GCM}" != "no"; then pbxlibdir="-L${SRTP_GCM_DIR}" fi fi - pbxfuncname="aes_gcm_128_openssl" + pbxfuncname="crypto_policy_set_aes_gcm_128_8_auth" if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers AST_SRTP_GCM_FOUND=yes else @@ -33901,8 +34432,6 @@ _ACEOF fi -fi - if test "x${PBX_SRTP_SHUTDOWN}" != "x1" -a "${USE_SRTP_SHUTDOWN}" != "no"; then pbxlibdir="" @@ -34007,6 +34536,8 @@ _ACEOF fi + fi +fi for ver in 2.0 2.2 2.4 2.6; do diff --git a/configure.ac b/configure.ac index 3bfb82eea35..9c07a4f6d99 100644 --- a/configure.ac +++ b/configure.ac @@ -2476,53 +2476,64 @@ then AST_C_DEFINE_CHECK([SSL_OP_NO_TLSV1_2], [SSL_OP_NO_TLSv1_2], [openssl/ssl.h]) fi -AST_EXT_LIB_CHECK([SRTP], [srtp], [srtp_init], [srtp/srtp.h]) +AST_EXT_LIB_CHECK([SRTP], [srtp2], [srtp_init], [srtp2/srtp.h], [], [], [2]) +AST_EXT_LIB_CHECK_SHARED([SRTP], [srtp2], [srtp_init], [srtp2/srtp.h], [], [], [], [ + AC_MSG_WARN([***]) + AC_MSG_WARN([*** libsrtp2 could not be linked as a shared object.]) + AC_MSG_WARN([*** Try compiling libsrtp2 manually. Configure libsrtp2]) + AC_MSG_WARN([*** with ./configure --prefix=/usr replacing /usr with]) + AC_MSG_WARN([*** the prefix of your choice, and then make with]) + AC_MSG_WARN([*** 'make libsrtp2.so']) + AC_MSG_WARN([***]) + AC_MSG_WARN([*** After re-installing libsrtp2, re-run the Asterisk]) + AC_MSG_WARN([*** configure script.]) + AC_MSG_WARN([***]) + AC_MSG_WARN([*** If you do not need SRTP support re-run configure]) + AC_MSG_WARN([*** with the --without-srtp option.]) + exit 1 +]) -if test "$PBX_SRTP" = "1"; +if test "x$PBX_SRTP" = x1; then - saved_libs="${LIBS}" - saved_ldflags="${LDFLAGS}" - saved_cflags="${CFLAGS}" - LIBS="${LIBS} ${SRTP_LIB}" - LDFLAGS="${LDFLAGS} -shared -fPIC" - CFLAGS="${CFLAGS} ${SRTP_INCLUDE}" - AC_MSG_CHECKING(for the ability of -lsrtp to be linked in a shared object) - AC_LINK_IFELSE( - [ - AC_LANG_PROGRAM( - [#include ], - [srtp_init();] - ) - ], - [ AC_MSG_RESULT(yes) ], - [ - AC_MSG_RESULT(no) - AC_MSG_WARN(***) - AC_MSG_WARN(*** libsrtp could not be linked as a shared object.) - AC_MSG_WARN(*** Try compiling libsrtp manually. Configure libsrtp) - AC_MSG_WARN(*** with ./configure CFLAGS=-fPIC --prefix=/usr) - AC_MSG_WARN(*** replacing /usr with the prefix of your choice.) - AC_MSG_WARN(*** After re-installing libsrtp, re-run the Asterisk) - AC_MSG_WARN(*** configure script.) - AC_MSG_WARN(***) - AC_MSG_WARN(*** If you do not need SRTP support re-run configure) - AC_MSG_WARN(*** with the --without-srtp option.) - exit 1 - ] - ) - LIBS="${saved_libs}" - LDFLAGS="${saved_ldflags}" - CFLAGS="${saved_cflags}" + AST_EXT_LIB_CHECK([SRTP_256], [srtp2], [srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_GCM], [srtp2], [srtp_crypto_policy_set_aes_gcm_128_8_auth]) + AST_EXT_LIB_CHECK([SRTP_SHUTDOWN], [srtp2], [srtp_shutdown], [srtp2/srtp.h]) + + # libsrtp2 removed support for PRNG, so we require OpenSSL + if test "x$PBX_OPENSSL" != x1; + then + AC_MSG_WARN([***]) + AC_MSG_WARN([*** OpenSSL required when using libsrtp2, checking for libsrtp instead.]) + AC_MSG_WARN([***]) + PBX_SRTP=0 + fi fi -if test "$PBX_SRTP" = "1"; +if test "x$PBX_SRTP" != x1; then - AST_EXT_LIB_CHECK([SRTP_256], [srtp], [crypto_policy_set_aes_cm_256_hmac_sha1_80]) - AST_EXT_LIB_CHECK([SRTP_192], [srtp], [crypto_policy_set_aes_cm_192_hmac_sha1_80]) - AST_EXT_LIB_CHECK([SRTP_GCM], [srtp], [aes_gcm_128_openssl]) -fi + AST_EXT_LIB_CHECK([SRTP], [srtp], [srtp_init], [srtp/srtp.h], [], [], [1]) + AST_EXT_LIB_CHECK_SHARED([SRTP], [srtp], [srtp_init], [srtp/srtp.h], [], [], [], [ + AC_MSG_WARN([***]) + AC_MSG_WARN([*** libsrtp could not be linked as a shared object.]) + AC_MSG_WARN([*** Try compiling libsrtp manually. Configure libsrtp]) + AC_MSG_WARN([*** with ./configure CFLAGS=-fPIC --prefix=/usr]) + AC_MSG_WARN([*** replacing /usr with the prefix of your choice.]) + AC_MSG_WARN([*** After re-installing libsrtp, re-run the Asterisk]) + AC_MSG_WARN([*** configure script.]) + AC_MSG_WARN([***]) + AC_MSG_WARN([*** If you do not need SRTP support re-run configure]) + AC_MSG_WARN([*** with the --without-srtp option.]) + exit 1 + ]) -AST_EXT_LIB_CHECK([SRTP_SHUTDOWN], [srtp], [srtp_shutdown], [srtp/srtp.h]) + if test "x$PBX_SRTP" = x1; + then + AST_EXT_LIB_CHECK([SRTP_256], [srtp], [crypto_policy_set_aes_cm_256_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_192], [srtp], [crypto_policy_set_aes_cm_192_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_GCM], [srtp], [crypto_policy_set_aes_gcm_128_8_auth]) + AST_EXT_LIB_CHECK([SRTP_SHUTDOWN], [srtp], [srtp_shutdown], [srtp/srtp.h]) + fi +fi for ver in 2.0 2.2 2.4 2.6; do AST_PKG_CONFIG_CHECK([GMIME], gmime-$ver) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index b39386b4349..f85ad8d07e0 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -917,6 +917,9 @@ /* Define to 1 if SRTP has the SRTP Library Shutdown Function feature. */ #undef HAVE_SRTP_SHUTDOWN +/* Define to the version of the srtp library. */ +#undef HAVE_SRTP_VERSION + /* Define to 1 if you have the ISDN SS7 library. */ #undef HAVE_SS7 diff --git a/res/res_srtp.c b/res/res_srtp.c index c47a8d55e88..caedfb6c879 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -38,11 +38,19 @@ #include "asterisk.h" /* for NULL, size_t, memcpy, etc */ #include /* for pow */ -#include -#ifdef HAVE_OPENSSL -#include + +#if HAVE_SRTP_VERSION > 1 +# include +# include +# include "srtp/srtp_compat.h" +# include #else -#include +# include +# ifdef HAVE_OPENSSL +# include +# else +# include +# endif #endif #include "asterisk/astobj2.h" /* for ao2_t_ref, etc */ diff --git a/res/srtp/srtp_compat.h b/res/srtp/srtp_compat.h new file mode 100644 index 00000000000..c23daabe13c --- /dev/null +++ b/res/srtp/srtp_compat.h @@ -0,0 +1,40 @@ +#ifndef AST_SRTP_COMPAT_H +#define AST_SRTP_COMPAT_H + +/* Compatibility for libsrtp 2.x */ + +#define crypto_policy_t srtp_crypto_policy_t + +#define crypto_policy_set_aes_cm_128_hmac_sha1_80 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80 +#define crypto_policy_set_aes_cm_128_hmac_sha1_32 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32 +#define crypto_policy_set_aes_cm_192_hmac_sha1_80 srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80 +#define crypto_policy_set_aes_cm_192_hmac_sha1_32 srtp_crypto_policy_set_aes_cm_192_hmac_sha1_32 +#define crypto_policy_set_aes_cm_256_hmac_sha1_80 srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80 +#define crypto_policy_set_aes_cm_256_hmac_sha1_32 srtp_crypto_policy_set_aes_cm_256_hmac_sha1_32 +#define crypto_policy_set_aes_gcm_128_16_auth srtp_crypto_policy_set_aes_gcm_128_16_auth +#define crypto_policy_set_aes_gcm_256_16_auth srtp_crypto_policy_set_aes_gcm_256_16_auth +#define crypto_policy_set_aes_gcm_128_8_auth srtp_crypto_policy_set_aes_gcm_128_8_auth +#define crypto_policy_set_aes_gcm_256_8_auth srtp_crypto_policy_set_aes_gcm_256_8_auth + +#define AES_128_ICM SRTP_AES_ICM +#define HMAC_SHA1 SRTP_HMAC_SHA1 + +#define err_status_t srtp_err_status_t +#define err_status_ok srtp_err_status_ok +#define err_status_fail srtp_err_status_fail +#define err_status_bad_param srtp_err_status_bad_param +#define err_status_alloc_fail srtp_err_status_alloc_fail +#define err_status_dealloc_fail srtp_err_status_dealloc_fail +#define err_status_init_fail srtp_err_status_init_fail +#define err_status_terminus srtp_err_status_terminus +#define err_status_auth_fail srtp_err_status_auth_fail +#define err_status_cipher_fail srtp_err_status_cipher_fail +#define err_status_replay_fail srtp_err_status_replay_fail +#define err_status_replay_old srtp_err_status_replay_old +#define err_status_algo_fail srtp_err_status_algo_fail +#define err_status_no_such_op srtp_err_status_no_such_op +#define err_status_no_ctx srtp_err_status_no_ctx +#define err_status_cant_check srtp_err_status_cant_check +#define err_status_key_expired srtp_err_status_key_expired + +#endif /* AST_SRTP_COMPAT_H */ From 9c4f63263c3828ec137d25dcf88b2bfe8838327b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 26 May 2017 16:41:59 +0000 Subject: [PATCH 1283/1578] manager: Clear the flag on the other channel. During the channel flag audit an incorrect change was done. The flag should be cleared on the second channel. ASTERISK-26469 Change-Id: I770c5a389550a2fb5a6ade942fccbb2e1d9199c8 --- main/manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/manager.c b/main/manager.c index dfb0d96c93d..1bbd1bbe94d 100644 --- a/main/manager.c +++ b/main/manager.c @@ -4850,7 +4850,7 @@ static int action_redirect(struct mansession *s, const struct message *m) ast_channel_clear_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); } if (chan2_wait) { - ast_channel_clear_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); + ast_channel_clear_flag(chan2, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); } chan2 = ast_channel_unref(chan2); From 80206cdc657472d0cefe23325af4564da7553b5e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 30 May 2017 08:43:49 -0600 Subject: [PATCH 1284/1578] test_json: Fix test names with reserved words Some of the test names were actually reserved words (true, false, int, null, string, bool). When the jenkins test results analyzer does its thing it tries to create a map using the test names as keys and fails because they're reserved words. Added "type_" to those test names. Change-Id: I90d809f46969c78a1c605b736ff0635196a2cf1b --- tests/test_json.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test_json.c b/tests/test_json.c index fee17e7c263..394591fa439 100644 --- a/tests/test_json.c +++ b/tests/test_json.c @@ -99,7 +99,7 @@ AST_TEST_DEFINE(json_test_false) switch (cmd) { case TEST_INIT: - info->name = "false"; + info->name = "type_false"; info->category = CATEGORY; info->summary = "Testing fundamental JSON false value."; info->description = "Test JSON abstraction library."; @@ -124,7 +124,7 @@ AST_TEST_DEFINE(json_test_true) switch (cmd) { case TEST_INIT: - info->name = "true"; + info->name = "type_true"; info->category = CATEGORY; info->summary = "Testing JSON true value."; info->description = "Test JSON abstraction library."; @@ -149,7 +149,7 @@ AST_TEST_DEFINE(json_test_bool0) switch (cmd) { case TEST_INIT: - info->name = "bool0"; + info->name = "type_bool0"; info->category = CATEGORY; info->summary = "Testing JSON boolean function (false)."; info->description = "Test JSON abstraction library."; @@ -176,7 +176,7 @@ AST_TEST_DEFINE(json_test_bool1) switch (cmd) { case TEST_INIT: - info->name = "bool1"; + info->name = "type_bool1"; info->category = CATEGORY; info->summary = "Testing JSON boolean function (true)."; info->description = "Test JSON abstraction library."; @@ -203,7 +203,7 @@ AST_TEST_DEFINE(json_test_null) switch (cmd) { case TEST_INIT: - info->name = "null"; + info->name = "type_null"; info->category = CATEGORY; info->summary = "Testing JSON null value."; info->description = "Test JSON abstraction library."; @@ -255,7 +255,7 @@ AST_TEST_DEFINE(json_test_string) switch (cmd) { case TEST_INIT: - info->name = "string"; + info->name = "type_string"; info->category = CATEGORY; info->summary = "Basic string tests."; info->description = "Test JSON abstraction library."; @@ -360,7 +360,7 @@ AST_TEST_DEFINE(json_test_int) switch (cmd) { case TEST_INIT: - info->name = "int"; + info->name = "type_int"; info->category = CATEGORY; info->summary = "Basic JSON integer tests."; info->description = "Test JSON abstraction library."; @@ -1644,7 +1644,7 @@ AST_TEST_DEFINE(json_test_timeval) switch (cmd) { case TEST_INIT: - info->name = "timeval"; + info->name = "type_timeval"; info->category = CATEGORY; info->summary = "JSON encoding of timevals."; info->description = "Test JSON abstraction library."; From 045d7b8cb774318ea09fb95feb989f7636ca7786 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 30 May 2017 10:34:34 -0400 Subject: [PATCH 1285/1578] format_mp3: Re-work menuselect/build issues Rather than removing format_mp3 from ALL_C_MODS (which caused format_mp3 to not show up in menuselect), use .PHONY targets when the necessary source files are not present. ASTERISK-23951 Reported by: Tzafrir Cohen Change-Id: I0a7512c51acc9e86043671795020b0de725bd9e8 --- addons/Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/Makefile b/addons/Makefile index 82bbc49a113..47da132470f 100644 --- a/addons/Makefile +++ b/addons/Makefile @@ -32,12 +32,9 @@ ALL_C_MODS:=app_mysql \ cdr_mysql \ chan_mobile \ chan_ooh323 \ + format_mp3 \ res_config_mysql -ifneq ($(wildcard mp3/Makefile),) - ALL_C_MODS += format_mp3 -endif - all: check_mp3 _all check_mp3: @@ -65,6 +62,10 @@ include $(ASTTOPDIR)/Makefile.moddir_rules chan_ooh323.so: _ASTCFLAGS+=$(H323CFLAGS) $(call MOD_ADD_C,chan_ooh323,$(H323SOURCE)) +ifneq ($(wildcard mp3/Makefile),) $(call MOD_ADD_C,format_mp3,mp3/common.c mp3/dct64_i386.c mp3/decode_ntom.c mp3/layer3.c mp3/tabinit.c mp3/interface.c) .PHONY: check_mp3 +else +.PHONY: check_mp3 format_mp3.o format_mp3.so +endif From 2da869408ae5556022526bcd0f526d92fdbb5a5f Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Fri, 5 May 2017 11:56:34 -0500 Subject: [PATCH 1286/1578] Add primitive SFU support to bridge_softmix. This sets up the "plumbing" in bridge_softmix to be able to accommodate Asterisk asking as an SFU (selective forwarding unit) for conferences. The way this works is that whenever a channel enters or leaves a conference, all participants in the bridge get sent a stream topology change request. The topologies consist of the channels' original topology, along with video destination streams corresponding to each participants' source video streams. So for instance, if Alice, Bob, and Carol are in the conference, and each supplies one video stream, then the topologies for each would look like so: Alice: Audio, Source video(Alice), Destination Video(Bob), Destination video (Carol) Bob: Audio, Source video(Bob) Destination Video(Alice), Destination video (Carol) Carol: Audio, Source video(Carol) Destination Video(Alice), Destination video (Bob) This way, video that arrives from a source video stream can then be copied out to the destination video streams on the other participants' channels. Once the bridge gets told that a topology on a channel has changed, the bridge constructs a map in order to get the video frames routed to the proper destination streams. This is done using the bridge channel's stream_map. This change is bare-bones with regards to SFU support. Some key features are missing at this point: * Stream limits. This commit makes no effort to limit the number of streams on a specific channel. This means that if there were 50 video callers in a conference, bridge_softmix will happily send out topology change requests to every channel in the bridge, requesting 50+ streams. * Configuration. The plumbing has been added to bridge_softmix, but there has been nothing added as of yet to app_confbridge to enable SFU video mode. * Testing. Some functions included here have unit tests. However, the functionality as a whole has only been verified by hand-tracing the code. * Selectivenss. For a "selective" forwarding unit, this does not currently have any means of being selective. * Features. Presumably, someone might wish to only receive video from specific sources. There are no external-facing functions at the moment that allow for users to select who they receive video from. * Efficiency. The current scheme treats all video streams as being unidirectional. We could be re-using a source video stream as a desetnation, too. But to simplify things on this first round, I did it this way. Change-Id: I7c44a829cc63acf8b596a337b2dc3c13898a6c4d --- apps/app_stream_echo.c | 2 +- bridges/bridge_simple.c | 3 + bridges/bridge_softmix.c | 716 +++++++++++++++++++++++++++++++++++++- include/asterisk/bridge.h | 8 +- include/asterisk/stream.h | 3 +- main/bridge.c | 11 +- main/bridge_channel.c | 13 +- main/sdp_state.c | 4 +- main/stream.c | 11 +- 9 files changed, 757 insertions(+), 14 deletions(-) diff --git a/apps/app_stream_echo.c b/apps/app_stream_echo.c index 53cbcd74dd7..79d15917b4a 100644 --- a/apps/app_stream_echo.c +++ b/apps/app_stream_echo.c @@ -249,7 +249,7 @@ static struct ast_stream_topology *stream_echo_topology_alloc( } do { - stream = ast_stream_clone(stream); + stream = ast_stream_clone(stream, NULL); if (!stream || ast_stream_topology_append_stream(res, stream) < 0) { ast_stream_free(stream); diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index 47f41cbb3b3..3bf04038096 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -91,6 +91,9 @@ static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, struct ast_stream_topology *t0 = ast_channel_get_stream_topology(c0); struct ast_stream_topology *t1 = ast_channel_get_stream_topology(c1); + if (bridge_channel) { + ast_bridge_channel_stream_map(bridge_channel); + } /* * The bridge_channel should only be NULL after both channels join * the bridge and their topologies are being aligned. diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 94dfc571429..ae877eb6e3c 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -31,7 +31,11 @@ core ***/ +#include "asterisk.h" +#include "asterisk/stream.h" +#include "asterisk/test.h" +#include "asterisk/vector.h" #include "bridge_softmix/include/bridge_softmix_internal.h" /*! The minimum sample rate of the bridge. */ @@ -54,6 +58,10 @@ #define DEFAULT_SOFTMIX_SILENCE_THRESHOLD 2500 #define DEFAULT_SOFTMIX_TALKING_THRESHOLD 160 +#define SOFTBRIDGE_VIDEO_DEST_PREFIX "softbridge_dest" +#define SOFTBRIDGE_VIDEO_DEST_LEN strlen(SOFTBRIDGE_VIDEO_DEST_PREFIX) +#define SOFTBRIDGE_VIDEO_DEST_SEPARATOR '_' + struct softmix_stats { /*! Each index represents a sample rate used above the internal rate. */ unsigned int sample_rates[16]; @@ -401,6 +409,215 @@ static void softmix_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridg } } +/*! + * \brief Determine if a stream is a video source stream. + * + * \param stream The stream to test + * \retval 1 The stream is a video source + * \retval 0 The stream is not a video source + */ +static int is_video_source(const struct ast_stream *stream) +{ + if (ast_stream_get_type(stream) == AST_MEDIA_TYPE_VIDEO && + strncmp(ast_stream_get_name(stream), SOFTBRIDGE_VIDEO_DEST_PREFIX, + SOFTBRIDGE_VIDEO_DEST_LEN)) { + return 1; + } + + return 0; +} + +/*! + * \brief Determine if a stream is a video destination stream. + * + * A source channel name can be provided to narrow this to a destination stream + * for a particular source channel. Further, a source stream name can be provided + * to narrow this to a particular source stream's destination. However, empty strings + * can be provided to match any destination video stream, regardless of source channel + * or source stream. + * + * \param stream The stream to test + * \param source_channel_name The name of a source video channel to match + * \param source_stream_name The name of the source video stream to match + * \retval 1 The stream is a video destination stream + * \retval 0 The stream is not a video destination stream + */ +static int is_video_dest(const struct ast_stream *stream, const char *source_channel_name, + const char *source_stream_name) +{ + char *dest_video_name; + size_t dest_video_name_len; + + if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_VIDEO) { + return 0; + } + + dest_video_name_len = SOFTBRIDGE_VIDEO_DEST_LEN + 1; + + if (!ast_strlen_zero(source_channel_name)) { + dest_video_name_len += strlen(source_channel_name) + 1; + if (!ast_strlen_zero(source_stream_name)) { + dest_video_name_len += strlen(source_stream_name) + 1; + } + } + dest_video_name = ast_alloca(dest_video_name_len); + + if (!ast_strlen_zero(source_channel_name)) { + if (!ast_strlen_zero(source_stream_name)) { + snprintf(dest_video_name, dest_video_name_len, "%s%c%s%c%s", + SOFTBRIDGE_VIDEO_DEST_PREFIX, SOFTBRIDGE_VIDEO_DEST_SEPARATOR, + source_channel_name, SOFTBRIDGE_VIDEO_DEST_SEPARATOR, + source_stream_name); + return !strcmp(ast_stream_get_name(stream), dest_video_name); + } else { + snprintf(dest_video_name, dest_video_name_len, "%s%c%s", + SOFTBRIDGE_VIDEO_DEST_PREFIX, SOFTBRIDGE_VIDEO_DEST_SEPARATOR, + source_channel_name); + return !strncmp(ast_stream_get_name(stream), dest_video_name, dest_video_name_len - 1); + } + } else { + snprintf(dest_video_name, dest_video_name_len, "%s", + SOFTBRIDGE_VIDEO_DEST_PREFIX); + return !strncmp(ast_stream_get_name(stream), dest_video_name, dest_video_name_len - 1); + } + + return 0; +} + +static int append_source_streams(struct ast_stream_topology *dest, + const char *channel_name, + const struct ast_stream_topology *source) +{ + int i; + + for (i = 0; i < ast_stream_topology_get_count(source); ++i) { + struct ast_stream *stream; + struct ast_stream *stream_clone; + char *stream_clone_name; + size_t stream_clone_name_len; + + stream = ast_stream_topology_get_stream(source, i); + if (!is_video_source(stream)) { + continue; + } + + /* The +3 is for the two underscore separators and null terminator */ + stream_clone_name_len = SOFTBRIDGE_VIDEO_DEST_LEN + strlen(channel_name) + strlen(ast_stream_get_name(stream)) + 3; + stream_clone_name = ast_alloca(stream_clone_name_len); + snprintf(stream_clone_name, stream_clone_name_len, "%s_%s_%s", SOFTBRIDGE_VIDEO_DEST_PREFIX, + channel_name, ast_stream_get_name(stream)); + + stream_clone = ast_stream_clone(stream, stream_clone_name); + if (!stream_clone) { + return -1; + } + if (ast_stream_topology_append_stream(dest, stream_clone) < 0) { + ast_stream_free(stream_clone); + return -1; + } + } + + return 0; +} + +static int append_all_streams(struct ast_stream_topology *dest, + const struct ast_stream_topology *source) +{ + int i; + + for (i = 0; i < ast_stream_topology_get_count(source); ++i) { + struct ast_stream *clone; + + clone = ast_stream_clone(ast_stream_topology_get_stream(source, i), NULL); + if (!clone) { + return -1; + } + if (ast_stream_topology_append_stream(dest, clone) < 0) { + ast_stream_free(clone); + return -1; + } + } + + return 0; +} + +/*! + * \brief Issue channel stream topology change requests. + * + * When in SFU mode, each participant needs to be able to + * send video directly to other participants in the bridge. + * This means that all participants need to have their topologies + * updated. The joiner needs to have destination streams for + * all current participants, and the current participants need + * to have destinations streams added for the joiner's sources. + * + * \param joiner The channel that is joining the softmix bridge + * \param participants The current participants in the softmix bridge + */ +static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast_bridge_channels_list *participants) +{ + struct ast_stream_topology *joiner_topology = NULL; + struct ast_stream_topology *joiner_video = NULL; + struct ast_stream_topology *existing_video = NULL; + struct ast_bridge_channel *participant; + + joiner_video = ast_stream_topology_alloc(); + if (!joiner_video) { + return; + } + + if (append_source_streams(joiner_video, ast_channel_name(joiner->chan), ast_channel_get_stream_topology(joiner->chan))) { + goto cleanup; + } + + existing_video = ast_stream_topology_alloc(); + if (!existing_video) { + goto cleanup; + } + + AST_LIST_TRAVERSE(participants, participant, entry) { + if (participant == joiner) { + continue; + } + if (append_source_streams(existing_video, ast_channel_name(participant->chan), + ast_channel_get_stream_topology(participant->chan))) { + goto cleanup; + } + } + + joiner_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(joiner->chan)); + if (!joiner_topology) { + goto cleanup; + } + if (append_all_streams(joiner_topology, existing_video)) { + goto cleanup; + } + ast_channel_request_stream_topology_change(joiner->chan, joiner_topology, NULL); + + AST_LIST_TRAVERSE(participants, participant, entry) { + struct ast_stream_topology *participant_topology; + + if (participant == joiner) { + continue; + } + participant_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(joiner->chan)); + if (!participant_topology) { + goto cleanup; + } + if (append_all_streams(participant_topology, joiner_video)) { + ast_stream_topology_free(participant_topology); + goto cleanup; + } + ast_channel_request_stream_topology_change(participant->chan, participant_topology, NULL); + ast_stream_topology_free(participant_topology); + } + +cleanup: + ast_stream_topology_free(joiner_video); + ast_stream_topology_free(existing_video); + ast_stream_topology_free(joiner_topology); +} + /*! \brief Function called when a channel is joined into the bridge */ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { @@ -464,19 +681,84 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan : DEFAULT_SOFTMIX_INTERVAL, bridge_channel, 0, set_binaural, pos_id, is_announcement); + if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU) { + sfu_topologies_on_join(bridge_channel, &bridge->channels); + } + softmix_poke_thread(softmix_data); return 0; } +static int remove_destination_streams(struct ast_stream_topology *dest, + const char *channel_name, + const struct ast_stream_topology *source) +{ + int i; + + for (i = 0; i < ast_stream_topology_get_count(source); ++i) { + struct ast_stream *stream; + struct ast_stream *stream_clone; + + stream = ast_stream_topology_get_stream(source, i); + + if (is_video_dest(stream, channel_name, NULL)) { + continue; + } + + stream_clone = ast_stream_clone(stream, NULL); + if (!stream_clone) { + continue; + } + if (ast_stream_topology_append_stream(dest, stream_clone) < 0) { + ast_stream_free(stream_clone); + } + } + + return 0; +} + +static int sfu_topologies_on_leave(struct ast_bridge_channel *leaver, struct ast_bridge_channels_list *participants) +{ + struct ast_stream_topology *leaver_topology; + struct ast_bridge_channel *participant; + + leaver_topology = ast_stream_topology_alloc(); + if (!leaver_topology) { + return -1; + } + + AST_LIST_TRAVERSE(participants, participant, entry) { + struct ast_stream_topology *participant_topology; + + participant_topology = ast_stream_topology_alloc(); + if (!participant_topology) { + continue; + } + + remove_destination_streams(participant_topology, ast_channel_name(leaver->chan), ast_channel_get_stream_topology(participant->chan)); + ast_channel_request_stream_topology_change(participant->chan, participant_topology, NULL); + ast_stream_topology_free(participant_topology); + } + + remove_destination_streams(leaver_topology, "", ast_channel_get_stream_topology(leaver->chan)); + ast_channel_request_stream_topology_change(leaver->chan, leaver_topology, NULL); + ast_stream_topology_free(leaver_topology); + + return 0; +} + /*! \brief Function called when a channel leaves the bridge */ static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { - struct softmix_channel *sc; struct softmix_bridge_data *softmix_data; softmix_data = bridge->tech_pvt; sc = bridge_channel->tech_pvt; + if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU) { + sfu_topologies_on_leave(bridge_channel, &bridge->channels); + } + if (!sc) { return; } @@ -565,6 +847,12 @@ static void softmix_bridge_write_video(struct ast_bridge *bridge, struct ast_bri softmix_pass_video_top_priority(bridge, frame); } break; + case AST_BRIDGE_VIDEO_MODE_SFU: + /* Nothing special to do here, the bridge channel stream map will ensure the + * video goes everywhere it needs to + */ + ast_bridge_queue_everyone_else(bridge, bridge_channel, frame); + break; } } @@ -1323,6 +1611,140 @@ static void softmix_bridge_destroy(struct ast_bridge *bridge) bridge->tech_pvt = NULL; } +/*! + * \brief Map a source stream to all of its destination streams. + * + * \param source_stream_name Name of the source stream + * \param source_channel_name Name of channel where the source stream originates + * \param bridge_stream_position The slot in the bridge where source video will come from + * \param participants The bridge_channels in the bridge + */ +static void map_source_to_destinations(const char *source_stream_name, const char *source_channel_name, + size_t bridge_stream_position, struct ast_bridge_channels_list *participants) +{ + struct ast_bridge_channel *participant; + + AST_LIST_TRAVERSE(participants, participant, entry) { + int i; + struct ast_stream_topology *topology; + + if (!strcmp(source_channel_name, ast_channel_name(participant->chan))) { + continue; + } + + ast_bridge_channel_lock(participant); + topology = ast_channel_get_stream_topology(participant->chan); + + for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { + struct ast_stream *stream; + + stream = ast_stream_topology_get_stream(topology, i); + if (is_video_dest(stream, source_channel_name, source_stream_name)) { + AST_VECTOR_REPLACE(&participant->stream_map.to_channel, bridge_stream_position, i); + break; + } + } + ast_bridge_channel_unlock(participant); + } +} + +/*\brief stream_topology_changed callback + * + * For most video modes, nothing beyond the ordinary is required. + * For the SFU case, though, we need to completely remap the streams + * in order to ensure video gets directed where it is expected to go. + * + * \param bridge The bridge + * \param bridge_channel Channel whose topology has changed + */ +static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) +{ + struct ast_bridge_channel *participant; + struct ast_vector_int media_types; + int nths[AST_MEDIA_TYPE_END] = {0}; + + switch (bridge->softmix.video_mode.mode) { + case AST_BRIDGE_VIDEO_MODE_NONE: + case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC: + case AST_BRIDGE_VIDEO_MODE_TALKER_SRC: + default: + ast_bridge_channel_stream_map(bridge_channel); + return; + case AST_BRIDGE_VIDEO_MODE_SFU: + break; + } + + AST_VECTOR_INIT(&media_types, AST_MEDIA_TYPE_END); + + /* First traversal: re-initialize all of the participants' stream maps */ + AST_LIST_TRAVERSE(&bridge->channels, participant, entry) { + int size; + + ast_bridge_channel_lock(participant); + size = ast_stream_topology_get_count(ast_channel_get_stream_topology(participant->chan)); + + AST_VECTOR_FREE(&participant->stream_map.to_channel); + AST_VECTOR_FREE(&participant->stream_map.to_bridge); + + AST_VECTOR_INIT(&participant->stream_map.to_channel, size); + AST_VECTOR_INIT(&participant->stream_map.to_bridge, size); + ast_bridge_channel_unlock(participant); + } + + /* Second traversal: Map specific video channels from their source to their destinations. + * + * This is similar to what is done in ast_stream_topology_map(), except that + * video channels are handled differently. Each video source has it's own + * unique index on the bridge. this way, a particular channel's source video + * can be distributed to the appropriate destination streams on the other + * channels + */ + AST_LIST_TRAVERSE(&bridge->channels, participant, entry) { + int i; + struct ast_stream_topology *topology; + + topology = ast_channel_get_stream_topology(participant->chan); + + for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { + struct ast_stream *stream = ast_stream_topology_get_stream(topology, i); + ast_bridge_channel_lock(participant); + if (is_video_source(stream)) { + AST_VECTOR_APPEND(&media_types, AST_MEDIA_TYPE_VIDEO); + AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, AST_VECTOR_SIZE(&media_types) - 1); + AST_VECTOR_REPLACE(&participant->stream_map.to_channel, AST_VECTOR_SIZE(&media_types) - 1, -1); + /* Unlock the participant to prevent potential deadlock + * in map_source_to_destinations + */ + ast_bridge_channel_unlock(participant); + map_source_to_destinations(ast_stream_get_name(stream), ast_channel_name(participant->chan), + AST_VECTOR_SIZE(&media_types) - 1, &bridge->channels); + ast_bridge_channel_lock(participant); + } else if (is_video_dest(stream, NULL, NULL)) { + /* We expect to never read media from video destination channels, but just + * in case, we should set their to_bridge value to -1. + */ + AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, -1); + } else { + /* XXX This is copied from ast_stream_topology_map(). This likely could + * be factored out in some way + */ + enum ast_media_type type = ast_stream_get_type(stream); + int index = AST_VECTOR_GET_INDEX_NTH(&media_types, ++nths[type], + type, AST_VECTOR_ELEM_DEFAULT_CMP); + + if (index == -1) { + AST_VECTOR_APPEND(&media_types, type); + index = AST_VECTOR_SIZE(&media_types) - 1; + } + + AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, index); + AST_VECTOR_REPLACE(&participant->stream_map.to_channel, index, i); + } + ast_bridge_channel_unlock(participant); + } + } +} + static struct ast_bridge_technology softmix_bridge = { .name = "softmix", .capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX, @@ -1334,11 +1756,301 @@ static struct ast_bridge_technology softmix_bridge = { .leave = softmix_bridge_leave, .unsuspend = softmix_bridge_unsuspend, .write = softmix_bridge_write, + .stream_topology_changed = softmix_bridge_stream_topology_changed, +}; + +#ifdef TEST_FRAMEWORK +struct stream_parameters { + const char *name; + const char *formats; + enum ast_media_type type; }; +static struct ast_stream_topology *build_topology(const struct stream_parameters *params, size_t num_streams) +{ + struct ast_stream_topology *topology; + size_t i; + + topology = ast_stream_topology_alloc(); + if (!topology) { + return NULL; + } + + for (i = 0; i < num_streams; ++i) { + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + struct ast_stream *stream; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + goto fail; + } + if (ast_format_cap_update_by_allow_disallow(caps, params[i].formats, 1) < 0) { + goto fail; + } + stream = ast_stream_alloc(params[i].name, params[i].type); + if (!stream) { + goto fail; + } + ast_stream_set_formats(stream, caps); + if (ast_stream_topology_append_stream(topology, stream) < 0) { + ast_stream_free(stream); + goto fail; + } + } + + return topology; + +fail: + ast_stream_topology_free(topology); + return NULL; +} + +static int validate_stream(struct ast_test *test, struct ast_stream *stream, + const struct stream_parameters *params) +{ + struct ast_format_cap *stream_caps; + struct ast_format_cap *params_caps; + + if (ast_stream_get_type(stream) != params->type) { + ast_test_status_update(test, "Expected stream type '%s' but got type '%s'\n", + ast_codec_media_type2str(params->type), + ast_codec_media_type2str(ast_stream_get_type(stream))); + return -1; + } + if (strcmp(ast_stream_get_name(stream), params->name)) { + ast_test_status_update(test, "Expected stream name '%s' but got type '%s'\n", + params->name, ast_stream_get_name(stream)); + return -1; + } + + stream_caps = ast_stream_get_formats(stream); + params_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!params_caps) { + ast_test_status_update(test, "Allocation error on capabilities\n"); + return -1; + } + ast_format_cap_update_by_allow_disallow(params_caps, params->formats, 1); + + if (ast_format_cap_identical(stream_caps, params_caps)) { + ast_test_status_update(test, "Formats are not as expected on stream '%s'\n", + ast_stream_get_name(stream)); + ao2_cleanup(params_caps); + return -1; + } + + ao2_cleanup(params_caps); + return 0; +} + +static int validate_original_streams(struct ast_test *test, struct ast_stream_topology *topology, + const struct stream_parameters *params, size_t num_streams) +{ + int i; + + if (ast_stream_topology_get_count(topology) < num_streams) { + ast_test_status_update(test, "Topology only has %d streams. Needs to have at least %zu\n", + ast_stream_topology_get_count(topology), num_streams); + return -1; + } + + for (i = 0; i < ARRAY_LEN(params); ++i) { + if (validate_stream(test, ast_stream_topology_get_stream(topology, i), ¶ms[i])) { + return -1; + } + } + + return 0; +} + +AST_TEST_DEFINE(sfu_append_source_streams) +{ + enum ast_test_result_state res = AST_TEST_FAIL; + static const struct stream_parameters bob_streams[] = { + { "bob_audio", "ulaw,alaw,g722,opus", AST_MEDIA_TYPE_AUDIO, }, + { "bob_video", "h264,vp8", AST_MEDIA_TYPE_VIDEO, }, + }; + static const struct stream_parameters alice_streams[] = { + { "alice_audio", "ulaw,opus", AST_MEDIA_TYPE_AUDIO, }, + { "alice_video", "vp8", AST_MEDIA_TYPE_VIDEO, }, + }; + static const struct stream_parameters alice_dest_stream = { + "softbridge_dest_PJSIP/Bob-00000001_bob_video", "vp8", AST_MEDIA_TYPE_VIDEO, + }; + static const struct stream_parameters bob_dest_stream = { + "softbridge_dest_PJSIP/Alice-00000000_alice_video", "h264,vp8", AST_MEDIA_TYPE_VIDEO, + }; + struct ast_stream_topology *topology_alice = NULL; + struct ast_stream_topology *topology_bob = NULL; + + switch (cmd) { + case TEST_INIT: + info->name = "sfu_append_source_streams"; + info->category = "/bridges/bridge_softmix/"; + info->summary = "Test appending of video streams"; + info->description = + "This tests does stuff."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology_alice = build_topology(alice_streams, ARRAY_LEN(alice_streams)); + if (!topology_alice) { + goto end; + } + + topology_bob = build_topology(bob_streams, ARRAY_LEN(bob_streams)); + if (!topology_bob) { + goto end; + } + + if (append_source_streams(topology_alice, "PJSIP/Bob-00000001", topology_bob)) { + ast_test_status_update(test, "Failed to append Bob's streams to Alice\n"); + goto end; + } + + if (ast_stream_topology_get_count(topology_alice) != 3) { + ast_test_status_update(test, "Alice's topology isn't large enough! It's %d but needs to be %d\n", + ast_stream_topology_get_count(topology_alice), 3); + goto end; + } + + if (validate_original_streams(test, topology_alice, alice_streams, ARRAY_LEN(alice_streams))) { + goto end; + } + + if (validate_stream(test, ast_stream_topology_get_stream(topology_alice, 2), &alice_dest_stream)) { + goto end; + } + + if (append_source_streams(topology_bob, "PJSIP/Alice-00000000", topology_alice)) { + ast_test_status_update(test, "Failed to append Alice's streams to Bob\n"); + goto end; + } + + if (ast_stream_topology_get_count(topology_bob) != 3) { + ast_test_status_update(test, "Bob's topology isn't large enough! It's %d but needs to be %d\n", + ast_stream_topology_get_count(topology_bob), 3); + goto end; + } + + if (validate_original_streams(test, topology_bob, bob_streams, ARRAY_LEN(bob_streams))) { + goto end; + } + + if (validate_stream(test, ast_stream_topology_get_stream(topology_bob, 2), &bob_dest_stream)) { + goto end; + } + + res = AST_TEST_PASS; + +end: + ast_stream_topology_free(topology_alice); + ast_stream_topology_free(topology_bob); + return res; +} + +AST_TEST_DEFINE(sfu_remove_destination_streams) +{ + enum ast_test_result_state res = AST_TEST_FAIL; + static const struct stream_parameters params[] = { + { "alice_audio", "ulaw,alaw,g722,opus", AST_MEDIA_TYPE_AUDIO, }, + { "alice_video", "h264,vp8", AST_MEDIA_TYPE_VIDEO, }, + { "softbridge_dest_PJSIP/Bob-00000001_video", "vp8", AST_MEDIA_TYPE_VIDEO, }, + { "softbridge_dest_PJSIP/Carol-00000002_video", "h264", AST_MEDIA_TYPE_VIDEO, }, + }; + static const struct { + const char *channel_name; + int num_streams; + int params_index[4]; + } removal_results[] = { + { "PJSIP/Bob-00000001", 3, { 0, 1, 3, -1 }, }, + { "PJSIP/Edward-00000004", 4, { 0, 1, 2, 3 }, }, + { "", 2, { 0, 1, -1, -1 }, }, + }; + struct ast_stream_topology *orig = NULL; + struct ast_stream_topology *result = NULL; + int i; + + switch (cmd) { + case TEST_INIT: + info->name = "sfu_remove_destination_streams"; + info->category = "/bridges/bridge_softmix/"; + info->summary = "Test removal of destination video streams"; + info->description = + "This tests does stuff."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + orig = build_topology(params, ARRAY_LEN(params)); + if (!orig) { + ast_test_status_update(test, "Unable to build initial stream topology\n"); + goto end; + } + + for (i = 0; i < ARRAY_LEN(removal_results); ++i) { + int j; + + result = ast_stream_topology_alloc(); + if (!result) { + ast_test_status_update(test, "Unable to allocate result stream topology\n"); + goto end; + } + + if (remove_destination_streams(result, removal_results[i].channel_name, orig)) { + ast_test_status_update(test, "Failure while attempting to remove video streams\n"); + goto end; + } + + if (ast_stream_topology_get_count(result) != removal_results[i].num_streams) { + ast_test_status_update(test, "Resulting topology has %d streams, when %d are expected\n", + ast_stream_topology_get_count(result), removal_results[i].num_streams); + goto end; + } + + for (j = 0; j < removal_results[i].num_streams; ++j) { + struct ast_stream *actual; + struct ast_stream *expected; + int orig_index; + + actual = ast_stream_topology_get_stream(result, j); + + orig_index = removal_results[i].params_index[j]; + expected = ast_stream_topology_get_stream(orig, orig_index); + + if (!ast_format_cap_identical(ast_stream_get_formats(actual), + ast_stream_get_formats(expected))) { + struct ast_str *expected_str; + struct ast_str *actual_str; + + expected_str = ast_str_alloca(64); + actual_str = ast_str_alloca(64); + + ast_test_status_update(test, "Mismatch between expected (%s) and actual (%s) stream formats\n", + ast_format_cap_get_names(ast_stream_get_formats(expected), &expected_str), + ast_format_cap_get_names(ast_stream_get_formats(actual), &actual_str)); + goto end; + } + } + } + + res = AST_TEST_PASS; + +end: + ast_stream_topology_free(orig); + ast_stream_topology_free(result); + return res; +} + +#endif + static int unload_module(void) { ast_bridge_technology_unregister(&softmix_bridge); + AST_TEST_UNREGISTER(sfu_append_source_streams); + AST_TEST_UNREGISTER(sfu_remove_destination_streams); return 0; } @@ -1348,6 +2060,8 @@ static int load_module(void) unload_module(); return AST_MODULE_LOAD_DECLINE; } + AST_TEST_REGISTER(sfu_append_source_streams); + AST_TEST_REGISTER(sfu_remove_destination_streams); return AST_MODULE_LOAD_SUCCESS; } diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index a9b01a6bbec..6915af28b4a 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -102,6 +102,10 @@ enum ast_bridge_video_mode_type { /*! A single user's video feed is distributed to all bridge channels, but * that feed is automatically picked based on who is talking the most. */ AST_BRIDGE_VIDEO_MODE_TALKER_SRC, + /*! Operate as a selective forwarding unit. Video from each participant is + * cloned to a dedicated stream on a subset of the remaining participants. + */ + AST_BRIDGE_VIDEO_MODE_SFU, }; /*! \brief This is used for both SINGLE_SRC mode to set what channel @@ -267,6 +271,8 @@ struct ast_bridge_softmix { unsigned int binaural_active; }; +AST_LIST_HEAD_NOLOCK(ast_bridge_channels_list, ast_bridge_channel); + /*! * \brief Structure that contains information about a bridge */ @@ -284,7 +290,7 @@ struct ast_bridge { /*! Call ID associated with the bridge */ ast_callid callid; /*! Linked list of channels participating in the bridge */ - AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels; + struct ast_bridge_channels_list channels; /*! Queue of actions to perform on the bridge. */ AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue; /*! Softmix technology parameters. */ diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index b453ab9c326..fcee3e47b9b 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -121,6 +121,7 @@ void ast_stream_free(struct ast_stream *stream); * \brief Create a deep clone of an existing stream * * \param stream The existing stream + * \param Optional name for cloned stream. If NULL, then existing stream's name is copied. * * \retval non-NULL success * \retval NULL failure @@ -130,7 +131,7 @@ void ast_stream_free(struct ast_stream *stream); * * \since 15 */ -struct ast_stream *ast_stream_clone(const struct ast_stream *stream); +struct ast_stream *ast_stream_clone(const struct ast_stream *stream, const char *name); /*! * \brief Get the name of a stream diff --git a/main/bridge.c b/main/bridge.c index 9d9a3118bbe..7d6bdfaa07b 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -3778,6 +3778,8 @@ static void cleanup_video_mode(struct ast_bridge *bridge) if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc) { ast_channel_unref(bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc); } + case AST_BRIDGE_VIDEO_MODE_SFU: + break; } memset(&bridge->softmix.video_mode, 0, sizeof(bridge->softmix.video_mode)); } @@ -3873,6 +3875,8 @@ int ast_bridge_number_video_src(struct ast_bridge *bridge) if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc) { res++; } + case AST_BRIDGE_VIDEO_MODE_SFU: + break; } ast_bridge_unlock(bridge); return res; @@ -3897,7 +3901,8 @@ int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan) } else if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) { res = 2; } - + case AST_BRIDGE_VIDEO_MODE_SFU: + break; } ast_bridge_unlock(bridge); return res; @@ -3931,6 +3936,8 @@ void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel * } bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc = NULL; } + case AST_BRIDGE_VIDEO_MODE_SFU: + break; } ast_bridge_unlock(bridge); } @@ -3942,6 +3949,8 @@ const char *ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type vide return "talker"; case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC: return "single"; + case AST_BRIDGE_VIDEO_MODE_SFU: + return "sfu"; case AST_BRIDGE_VIDEO_MODE_NONE: default: return "none"; diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 4f166fff06f..b299ca98f00 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -989,6 +989,11 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st /* Media frames need to be mapped to an appropriate write stream */ dup->stream_num = AST_VECTOR_GET( &bridge_channel->stream_map.to_bridge, fr->stream_num); + if (dup->stream_num == -1) { + ast_bridge_channel_unlock(bridge_channel); + bridge_frame_free(dup); + return 0; + } } else { dup->stream_num = -1; } @@ -2339,7 +2344,9 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe case AST_FRAME_NULL: break; default: - if (fr->stream_num >= (int)AST_VECTOR_SIZE(&bridge_channel->stream_map.to_channel)) { + if (fr->stream_num > 0 && + (fr->stream_num >= (int)AST_VECTOR_SIZE(&bridge_channel->stream_map.to_channel) || + AST_VECTOR_GET(&bridge_channel->stream_map.to_channel, fr->stream_num) == -1)) { /* Nowhere to write to, so drop it */ break; } @@ -2473,11 +2480,11 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) * If a stream topology has changed then the bridge_channel's * media mapping needs to be updated. */ - ast_bridge_channel_stream_map(bridge_channel); - if (bridge_channel->bridge->technology->stream_topology_changed) { bridge_channel->bridge->technology->stream_topology_changed( bridge_channel->bridge, bridge_channel); + } else { + ast_bridge_channel_stream_map(bridge_channel); } break; default: diff --git a/main/sdp_state.c b/main/sdp_state.c index 9b116ca5492..00f147f474e 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -747,7 +747,7 @@ static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_st if (is_local) { /* Replace the local stream with the new local stream. */ - joint_stream = ast_stream_clone(new_stream); + joint_stream = ast_stream_clone(new_stream, NULL); } else { joint_stream = merge_streams(local_stream, new_stream); } @@ -800,7 +800,7 @@ static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_st /* We don't have a stream state that corresponds to the stream in the new topology, so * create a stream state as appropriate. */ - joint_stream = ast_stream_clone(new_stream); + joint_stream = ast_stream_clone(new_stream, NULL); if (!joint_stream) { sdp_state_stream_free(joint_state_stream); goto fail; diff --git a/main/stream.c b/main/stream.c index 804a0b8eeda..fb146931da9 100644 --- a/main/stream.c +++ b/main/stream.c @@ -95,23 +95,26 @@ struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type) return stream; } -struct ast_stream *ast_stream_clone(const struct ast_stream *stream) +struct ast_stream *ast_stream_clone(const struct ast_stream *stream, const char *name) { struct ast_stream *new_stream; size_t stream_size; int idx; + const char *stream_name; if (!stream) { return NULL; } - stream_size = sizeof(*stream) + strlen(stream->name) + 1; + stream_name = name ?: stream->name; + stream_size = sizeof(*stream) + strlen(stream_name) + 1; new_stream = ast_calloc(1, stream_size); if (!new_stream) { return NULL; } - memcpy(new_stream, stream, stream_size); + memcpy(new_stream, stream, sizeof(*new_stream)); + strcpy(new_stream->name, stream_name); /* Safe */ if (new_stream->formats) { ao2_ref(new_stream->formats, +1); } @@ -269,7 +272,7 @@ struct ast_stream_topology *ast_stream_topology_clone( for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { struct ast_stream *stream = - ast_stream_clone(AST_VECTOR_GET(&topology->streams, i)); + ast_stream_clone(AST_VECTOR_GET(&topology->streams, i), NULL); if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) { ast_stream_free(stream); From 39d14834f83e8727e841c51d1752d90bc7be5c63 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Wed, 24 May 2017 10:09:22 -0500 Subject: [PATCH 1287/1578] Confbridge: Add "sfu" video mode to bridge profile options. A previous commit added plumbing to bridge_softmix to allow for an SFU experience with Asterisk. This commit adds an option to app_confbridge that allows for a confbridge to actually make use of the SFU video mode. SFU mode is implemented in a "set it and forget it" kind of way. That is, when the bridge is created, if SFU mode is enabled, then the video mode gets set to SFU and cannot be changed. Future improvements may allow for a hybrid experience (e.g. forward multiple video streams, specifically those of the most recent talkers), but for this addition, no such capability is present. Change-Id: I87bbcb63dec6dbbb42488f894871b86f112b2020 --- apps/app_confbridge.c | 6 +++++- apps/confbridge/conf_config_parser.c | 19 +++++++++++++++---- apps/confbridge/include/confbridge.h | 1 + include/asterisk/bridge.h | 5 +++++ main/bridge.c | 8 ++++++++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index a9f917b9a97..1baf257a48f 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1483,6 +1483,8 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) { ast_bridge_set_talker_src_video_mode(conference->bridge); + } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_SFU)) { + ast_bridge_set_sfu_video_mode(conference->bridge); } /* Link it into the conference bridges container */ @@ -2770,7 +2772,9 @@ static int execute_menu_entry(struct confbridge_conference *conference, break; case MENU_ACTION_SET_SINGLE_VIDEO_SRC: ao2_lock(conference); - ast_bridge_set_single_src_video_mode(conference->bridge, bridge_channel->chan); + if (!ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_SFU)) { + ast_bridge_set_single_src_video_mode(conference->bridge, bridge_channel->chan); + } ao2_unlock(conference); break; case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC: diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 3e4075ba94d..cc8fcfe5df4 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -1952,25 +1952,36 @@ static int video_mode_handler(const struct aco_option *opt, struct ast_variable ast_set_flags_to(b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED - | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER, + | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER + | BRIDGE_OPT_VIDEO_SRC_SFU, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED); } else if (!strcasecmp(var->value, "last_marked")) { ast_set_flags_to(b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED - | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER, + | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER + | BRIDGE_OPT_VIDEO_SRC_SFU, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED); } else if (!strcasecmp(var->value, "follow_talker")) { ast_set_flags_to(b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED - | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER, + | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER + | BRIDGE_OPT_VIDEO_SRC_SFU, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER); } else if (!strcasecmp(var->value, "none")) { ast_clear_flag(b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED - | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER); + | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER + | BRIDGE_OPT_VIDEO_SRC_SFU); + } else if (!strcasecmp(var->value, "sfu")) { + ast_set_flags_to(b_profile, + BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED + | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED + | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER + | BRIDGE_OPT_VIDEO_SRC_SFU, + BRIDGE_OPT_VIDEO_SRC_SFU); } else { return -1; } diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 584499ff391..cf30d5c6270 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -72,6 +72,7 @@ enum bridge_profile_flags { BRIDGE_OPT_RECORD_FILE_APPEND = (1 << 4), /*!< Set if the record file should be appended to between start/stops. */ BRIDGE_OPT_RECORD_FILE_TIMESTAMP = (1 << 5), /*< Set if the record file should have a timestamp appended */ BRIDGE_OPT_BINAURAL_ACTIVE = (1 << 6), /*< Set if binaural convolution is activated */ + BRIDGE_OPT_VIDEO_SRC_SFU = (1 << 7), /*< Selective forwarding unit */ }; enum conf_menu_action_id { diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index 6915af28b4a..bc0e9c81e08 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -897,6 +897,11 @@ void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_ */ void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge); +/*! + * \brief Set the bridge to be a selective forwarding unit + */ +void ast_bridge_set_sfu_video_mode(struct ast_bridge *bridge); + /*! * \brief Update information about talker energy for talker src video mode. */ diff --git a/main/bridge.c b/main/bridge.c index 7d6bdfaa07b..4631e5a5276 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -3807,6 +3807,14 @@ void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge) ast_bridge_unlock(bridge); } +void ast_bridge_set_sfu_video_mode(struct ast_bridge *bridge) +{ + ast_bridge_lock(bridge); + cleanup_video_mode(bridge); + bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_SFU; + ast_bridge_unlock(bridge); +} + void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe) { struct ast_bridge_video_talker_src_data *data; From 5c27fe218776b499cff772660f2b4b7ee42b3802 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sun, 28 May 2017 16:43:12 -0400 Subject: [PATCH 1288/1578] format: Reintroduce smoother flags In review 4843 (ASTERISK-24858), we added a hack that forced a smoother creation when sending signed linear so that the byte order was adjusted during transmission. This was needed because smoother flags were lost during the new format work that was done in Asterisk 13. Rather than rolling that same hack into res_rtp_multicast, re-introduce smoother flags so that formats can dictate their own options. Change-Id: I77b835fba0e539c6ce50014a984766f63cab2c16 --- include/asterisk/codec.h | 2 + include/asterisk/format.h | 11 ++++ include/asterisk/smoother.h | 1 + main/codec_builtin.c | 10 +++ main/format.c | 5 ++ res/res_rtp_asterisk.c | 14 ++-- res/res_rtp_multicast.c | 124 ++++++++++++++++++++++++++---------- 7 files changed, 124 insertions(+), 43 deletions(-) diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h index 2f5756cd14f..79798acd085 100644 --- a/include/asterisk/codec.h +++ b/include/asterisk/codec.h @@ -76,6 +76,8 @@ struct ast_codec { int (*get_length)(unsigned int samples); /*! \brief Whether the media can be smoothed or not */ unsigned int smooth; + /*! \brief Flags to be passed to the smoother */ + unsigned int smoother_flags; /*! \brief The module that registered this codec */ struct ast_module *mod; }; diff --git a/include/asterisk/format.h b/include/asterisk/format.h index b01592d16e9..0bad96dccc1 100644 --- a/include/asterisk/format.h +++ b/include/asterisk/format.h @@ -355,6 +355,17 @@ const char *ast_format_get_codec_name(const struct ast_format *format); */ int ast_format_can_be_smoothed(const struct ast_format *format); +/*! + * \since 13.17.0 + * + * \brief Get smoother flags for this format + * + * \param format The media format + * + * \return smoother flags for the provided format + */ +int ast_format_get_smoother_flags(const struct ast_format *format); + /*! * \brief Get the media type of a format * diff --git a/include/asterisk/smoother.h b/include/asterisk/smoother.h index e63aa77bd68..65ac88921fa 100644 --- a/include/asterisk/smoother.h +++ b/include/asterisk/smoother.h @@ -33,6 +33,7 @@ extern "C" { #define AST_SMOOTHER_FLAG_G729 (1 << 0) #define AST_SMOOTHER_FLAG_BE (1 << 1) +#define AST_SMOOTHER_FLAG_FORCED (1 << 2) /*! \name AST_Smoother */ diff --git a/main/codec_builtin.c b/main/codec_builtin.c index 3320900c2e3..32ec12d3d42 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -36,6 +36,7 @@ #include "asterisk/format.h" #include "asterisk/format_cache.h" #include "asterisk/frame.h" +#include "asterisk/smoother.h" int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name, struct ast_module *mod); @@ -288,6 +289,7 @@ static struct ast_codec slin8 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin12 = { @@ -302,6 +304,7 @@ static struct ast_codec slin12 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin16 = { @@ -316,6 +319,7 @@ static struct ast_codec slin16 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin24 = { @@ -330,6 +334,7 @@ static struct ast_codec slin24 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin32 = { @@ -344,6 +349,7 @@ static struct ast_codec slin32 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin44 = { @@ -358,6 +364,7 @@ static struct ast_codec slin44 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin48 = { @@ -372,6 +379,7 @@ static struct ast_codec slin48 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin96 = { @@ -386,6 +394,7 @@ static struct ast_codec slin96 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static struct ast_codec slin192 = { @@ -400,6 +409,7 @@ static struct ast_codec slin192 = { .samples_count = slin_samples, .get_length = slin_length, .smooth = 1, + .smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED, }; static int lpc10_samples(struct ast_frame *frame) diff --git a/main/format.c b/main/format.c index 5ae5ad98623..09e736cf5f4 100644 --- a/main/format.c +++ b/main/format.c @@ -391,6 +391,11 @@ int ast_format_can_be_smoothed(const struct ast_format *format) return format->codec->smooth; } +int ast_format_get_smoother_flags(const struct ast_format *format) +{ + return format->codec->smoother_flags; +} + enum ast_media_type ast_format_get_type(const struct ast_format *format) { return format->codec->type; diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 18987cee9eb..c120fc1452e 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -3747,7 +3747,7 @@ static int ast_rtcp_write(const void *data) } /*! \pre instance is locked */ -static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *frame, int codec) +static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *frame, int codec) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); int pred, mark = 0; @@ -4016,10 +4016,10 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr /* If no smoother is present see if we have to set one up */ if (!rtp->smoother && ast_format_can_be_smoothed(format)) { + unsigned int smoother_flags = ast_format_get_smoother_flags(format); unsigned int framing_ms = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(instance)); - int is_slinear = ast_format_cache_is_slinear(format); - if (!framing_ms && is_slinear) { + if (!framing_ms && (smoother_flags & AST_SMOOTHER_FLAG_FORCED)) { framing_ms = ast_format_get_default_ms(format); } @@ -4030,9 +4030,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr ast_format_get_name(format), framing_ms, ast_format_get_minimum_bytes(format)); return -1; } - if (is_slinear) { - ast_smoother_set_flags(rtp->smoother, AST_SMOOTHER_FLAG_BE); - } + ast_smoother_set_flags(rtp->smoother, smoother_flags); } } @@ -4047,7 +4045,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr } while ((f = ast_smoother_read(rtp->smoother)) && (f->data.ptr)) { - ast_rtp_raw_write(instance, f, codec); + rtp_raw_write(instance, f, codec); } } else { int hdrlen = 12; @@ -4059,7 +4057,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr f = frame; } if (f->data.ptr) { - ast_rtp_raw_write(instance, f, codec); + rtp_raw_write(instance, f, codec); } if (f != frame) { ast_frfree(f); diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index 42de11f65e8..14176da413a 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -54,6 +54,7 @@ #include "asterisk/format_cache.h" #include "asterisk/multicast_rtp.h" #include "asterisk/app.h" +#include "asterisk/smoother.h" /*! Command value used for Linksys paging to indicate we are starting */ #define LINKSYS_MCAST_STARTCMD 6 @@ -95,6 +96,7 @@ struct multicast_rtp { uint16_t seqno; unsigned int lastts; struct timeval txcore; + struct ast_smoother *smoother; }; enum { @@ -395,6 +397,10 @@ static int multicast_rtp_destroy(struct ast_rtp_instance *instance) multicast_send_control_packet(instance, multicast, LINKSYS_MCAST_STOPCMD); } + if (multicast->smoother) { + ast_smoother_free(multicast->smoother); + } + close(multicast->socket); ast_free(multicast); @@ -402,43 +408,24 @@ static int multicast_rtp_destroy(struct ast_rtp_instance *instance) return 0; } -/*! \brief Function called to broadcast some audio on a multicast instance */ -static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame) +static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *frame, int codec) { struct multicast_rtp *multicast = ast_rtp_instance_get_data(instance); - struct ast_frame *f = frame; - struct ast_sockaddr remote_address; - int hdrlen = 12, res = 0, codec; - unsigned char *rtpheader; unsigned int ms = calc_txstamp(multicast, &frame->delivery); + unsigned char *rtpheader; + struct ast_sockaddr remote_address = { {0,} }; int rate = rtp_get_rate(frame->subclass.format) / 1000; + int hdrlen = 12; - /* We only accept audio, nothing else */ - if (frame->frametype != AST_FRAME_VOICE) { - return 0; - } - - /* Grab the actual payload number for when we create the RTP packet */ - codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), - 1, frame->subclass.format, 0); - if (codec < 0) { - return -1; - } - - /* If we do not have space to construct an RTP header duplicate the frame so we get some */ - if (frame->offset < hdrlen) { - f = ast_frdup(frame); - } - - /* Calucate last TS */ + /* Calculate last TS */ multicast->lastts = multicast->lastts + ms * rate; - + /* Construct an RTP header for our packet */ - rtpheader = (unsigned char *)(f->data.ptr - hdrlen); + rtpheader = (unsigned char *)(frame->data.ptr - hdrlen); put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (multicast->seqno))); - - if (ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO)) { - put_unaligned_uint32(rtpheader + 4, htonl(f->ts * 8)); + + if (ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO)) { + put_unaligned_uint32(rtpheader + 4, htonl(frame->ts * 8)); } else { put_unaligned_uint32(rtpheader + 4, htonl(multicast->lastts)); } @@ -451,19 +438,86 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra /* Finally send it out to the eager phones listening for us */ ast_rtp_instance_get_remote_address(instance, &remote_address); - if (ast_sendto(multicast->socket, (void *) rtpheader, f->datalen + hdrlen, 0, &remote_address) < 0) { + if (ast_sendto(multicast->socket, (void *) rtpheader, frame->datalen + hdrlen, 0, &remote_address) < 0) { ast_log(LOG_ERROR, "Multicast RTP Transmission error to %s: %s\n", ast_sockaddr_stringify(&remote_address), strerror(errno)); - res = -1; + return -1; } - /* If we were forced to duplicate the frame free the new one */ - if (frame != f) { - ast_frfree(f); + return 0; +} + +/*! \brief Function called to broadcast some audio on a multicast instance */ +static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame) +{ + struct multicast_rtp *multicast = ast_rtp_instance_get_data(instance); + struct ast_format *format; + struct ast_frame *f; + int codec; + + /* We only accept audio, nothing else */ + if (frame->frametype != AST_FRAME_VOICE) { + return 0; } - return res; + /* Grab the actual payload number for when we create the RTP packet */ + codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), + 1, frame->subclass.format, 0); + if (codec < 0) { + return -1; + } + + format = frame->subclass.format; + if (!multicast->smoother && ast_format_can_be_smoothed(format)) { + unsigned int smoother_flags = ast_format_get_smoother_flags(format); + unsigned int framing_ms = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(instance)); + + if (!framing_ms && (smoother_flags & AST_SMOOTHER_FLAG_FORCED)) { + framing_ms = ast_format_get_default_ms(format); + } + + if (framing_ms) { + multicast->smoother = ast_smoother_new((framing_ms * ast_format_get_minimum_bytes(format)) / ast_format_get_minimum_ms(format)); + if (!multicast->smoother) { + ast_log(LOG_WARNING, "Unable to create smoother: format %s ms: %u len %u\n", + ast_format_get_name(format), framing_ms, ast_format_get_minimum_bytes(format)); + return -1; + } + ast_smoother_set_flags(multicast->smoother, smoother_flags); + } + } + + if (multicast->smoother) { + if (ast_smoother_test_flag(multicast->smoother, AST_SMOOTHER_FLAG_BE)) { + ast_smoother_feed_be(multicast->smoother, frame); + } else { + ast_smoother_feed(multicast->smoother, frame); + } + + while ((f = ast_smoother_read(multicast->smoother)) && f->data.ptr) { + rtp_raw_write(instance, f, codec); + } + } else { + int hdrlen = 12; + + /* If we do not have space to construct an RTP header duplicate the frame so we get some */ + if (frame->offset < hdrlen) { + f = ast_frdup(frame); + } else { + f = frame; + } + + if (f->data.ptr) { + rtp_raw_write(instance, f, codec); + } + + if (f != frame) { + ast_frfree(f); + } + } + + return 0; } /*! \brief Function called to read from a multicast instance */ From 9dce4a947bef6c7c9de09a29f3097faaba632f28 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 30 May 2017 17:07:56 -0400 Subject: [PATCH 1289/1578] stasis_recording: Correct ast_asprintf error checking ASTERISK-27021 #close Reported by: Tim Morgan Change-Id: I0ac061f040093e806c3b1f4e2340864f3ce4dd75 --- res/stasis_recording/stored.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/stasis_recording/stored.c b/res/stasis_recording/stored.c index 23d535604b9..9df5d75dc67 100644 --- a/res/stasis_recording/stored.c +++ b/res/stasis_recording/stored.c @@ -173,7 +173,7 @@ static int handle_find_recording(const char *dir_name, const char *filename, voi return 0; } - if (ast_asprintf(&data->file_with_ext, "%s/%s", dir_name, filename)) { + if (ast_asprintf(&data->file_with_ext, "%s/%s", dir_name, filename) < 0) { return -1; } @@ -268,7 +268,7 @@ static int handle_scan_file(const char *dir_name, const char *filename, void *ob return 0; } - if (ast_asprintf(&filepath, "%s/%s", dir_name, filename)) { + if (ast_asprintf(&filepath, "%s/%s", dir_name, filename) < 0) { return -1; } From f6eeaaafd507df6e2094dd201cb6897dbb63216a Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 31 May 2017 09:25:02 +0000 Subject: [PATCH 1290/1578] channel / app_meetme: Fix parentheses. ASTERISK-27025 Change-Id: Id736b0aa4ec6b6b0f04663d64fa8d151f81fdbed --- apps/app_meetme.c | 2 +- main/channel.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 36f5c77273f..71ca9dc9f8e 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -4661,7 +4661,7 @@ static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char if (cnf) { if (confflags->flags && !cnf->chan && !ast_test_flag64(confflags, CONFFLAG_QUIET) && - ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) | CONFFLAG_INTROUSER_VMREC) { + ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) { ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n"); ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC); } diff --git a/main/channel.c b/main/channel.c index 1f97e651c32..4451e524f8e 100644 --- a/main/channel.c +++ b/main/channel.c @@ -9116,7 +9116,7 @@ static int redirecting_reason_build_data(unsigned char *data, size_t datalen, if (reason->str) { length = strlen(reason->str); - if (datalen < pos + sizeof(data[0] * 2) + length) { + if (datalen < pos + (sizeof(data[0]) * 2) + length) { ast_log(LOG_WARNING, "No space left for %s string\n", label); return -1; } From 001f4ddda43092d936980ebedcd9ea789e961cf5 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 31 May 2017 12:45:45 -0400 Subject: [PATCH 1291/1578] pbx_builtin: Properly handle hangup during Background Before this patch, when a user hung up during a Background, we would stuff 0xff into a char and attempt a dialplan lookup of it. This caused problems for some realtime engines which interpreted the value as the beginning of an invalid UTF-8 sequence. ASTERISK-19291 #close Reported by: Andrew Nowrot Change-Id: I8ca6da93252d61c76ebdb46a4aa65e73ca985358 --- main/pbx_builtins.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/main/pbx_builtins.c b/main/pbx_builtins.c index 20fdb4c22b7..bc27b0d58a6 100644 --- a/main/pbx_builtins.c +++ b/main/pbx_builtins.c @@ -1111,6 +1111,13 @@ static int pbx_builtin_background(struct ast_channel *chan, const char *data) } } + /* If ast_waitstream didn't give us back a digit, there is nothing else to do */ + if (res <= 0) { + goto done; + } + + exten[0] = res; + /* * If the single digit DTMF is an extension in the specified context, then * go there and signal no DTMF. Otherwise, we should exit with that DTMF. @@ -1130,7 +1137,6 @@ static int pbx_builtin_background(struct ast_channel *chan, const char *data) * be returned (see #16434). */ if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS) - && (exten[0] = res) && ast_canmatch_extension(chan, args.context, exten, 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)) && !ast_matchmore_extension(chan, args.context, exten, 1, From d8802a6a0faa5c983dc93d022475994cd8dbb3c8 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 5 Jun 2017 11:27:32 -0500 Subject: [PATCH 1292/1578] channel: ast_write frame wrongly freed after call to audiohooks ASTERISK-26419 introduced a bug when calling ast_audiohook_write_list in ast_write. It would free the frame given to ast_write if the frame returned by ast_audiohook_write_list was different than the given one. The frame give to ast_write should never be freed within that function. It is the caller's resposibility to free the frame after writing (or when it its done with it). By freeing it within ast_write this of course led to some memory corruption problems. This patch makes it so the frame given to ast_write is no longer freed within the function. The frame returned by ast_audiohook_write_list is now subsequently used in ast_write and is freed later. It is freed either after translate if the frame returned by translate is different, or near the end of ast_write prior to function exit. ASTERISK-26973 #close Change-Id: Ic9085ba5f555eeed12f6e565a638c3649695988b --- main/channel.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/main/channel.c b/main/channel.c index 4451e524f8e..58f960aafc6 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5040,26 +5040,21 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame apply_plc(chan, fr); } + f = fr; + /* * Send frame to audiohooks if present, if frametype is linear (else, later as per * previous behavior) */ if ((stream == default_stream) && ast_channel_audiohooks(chan)) { if (ast_format_cache_is_slinear(fr->subclass.format)) { - struct ast_frame *old_frame; hooked = 1; - old_frame = fr; - fr = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_WRITE, fr); - if (old_frame != fr) { - ast_frfree(old_frame); - } + f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_WRITE, fr); } } /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */ - if ((stream != default_stream) || ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) { - f = fr; - } else { + if ((stream == default_stream) && ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_EQUAL) { if (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL) { struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); @@ -5085,7 +5080,18 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame break; } } - f = ast_channel_writetrans(chan) ? ast_translate(ast_channel_writetrans(chan), fr, 0) : fr; + + if (ast_channel_writetrans(chan)) { + struct ast_frame *trans_frame = ast_translate(ast_channel_writetrans(chan), f, 0); + if (trans_frame != f && f != fr) { + /* + * If translate gives us a new frame and so did the audio + * hook then we need to free the one from the audio hook. + */ + ast_frfree(f); + } + f = trans_frame; + } } if (!f) { From 861984eac0d9d3582db6922a89e2d75796ae108f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 31 May 2017 15:41:45 +0000 Subject: [PATCH 1293/1578] res_pjsip: Add support for returning only reachable contacts and use it. This introduces the ability for PJSIP code to specify filtering flags when retrieving PJSIP contacts. The first flag for use causes the query code to only retrieve contacts that are not unreachable. This change has been leveraged by both the Dial() process and the PJSIP_DIAL_CONTACTS dialplan function so they will now only attempt calls to contacts which are not unreachable. ASTERISK-26281 Change-Id: I8233b4faa21ba3db114f5a42e946e4b191446f6c --- CHANGES | 6 +++ channels/pjsip/dialplan_functions.c | 2 +- include/asterisk/res_pjsip.h | 68 +++++++++++++++++++++++++++++ res/res_pjsip.c | 2 +- res/res_pjsip/location.c | 53 ++++++++++++++++++++-- res/res_pjsip_session.c | 3 +- 6 files changed, 128 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index b81ef1cdee3..442f59d6241 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,12 @@ res_agi EAGI provides. If not specified, it will continue to use the default signed linear (slin). +chan_pjsip +------------------ + * When dialing an endpoint directly or using the PJSIP_DIAL_CONTACTS dialplan + function any contact which is considered unreachable due to qualify being + enabled will no longer be called. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 332df70b4af..7b3434d408f 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -896,7 +896,7 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char if (!aor) { /* If the AOR provided is not found skip it, there may be more */ continue; - } else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) { + } else if (!(contacts = ast_sip_location_retrieve_aor_contacts_filtered(aor, AST_SIP_CONTACT_FILTER_REACHABLE))) { /* No contacts are available, skip it as well */ continue; } else if (!ao2_container_count(contacts)) { diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 59f1710d1d7..8c589ef85ea 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -864,6 +864,17 @@ struct ast_sip_endpoint_identifier { struct ast_sip_endpoint *(*identify_endpoint)(pjsip_rx_data *rdata); }; +/*! + * \brief Contact retrieval filtering flags + */ +enum ast_sip_contact_filter { + /*! \brief Default filter flags */ + AST_SIP_CONTACT_FILTER_DEFAULT = 0, + + /*! \brief Return only reachable or unknown contacts */ + AST_SIP_CONTACT_FILTER_REACHABLE = (1 << 0), +}; + /*! * \brief Register a SIP service in Asterisk. * @@ -1049,6 +1060,18 @@ struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name); */ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor); +/*! + * \brief Retrieve the first bound contact for an AOR and filter based on flags + * \since 13.16.0 + * + * \param aor Pointer to the AOR + * \param flags Filtering flags + * \retval NULL if no contacts available + * \retval non-NULL if contacts available + */ +struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact_filtered(const struct ast_sip_aor *aor, + unsigned int flags); + /*! * \brief Retrieve all contacts currently available for an AOR * @@ -1063,6 +1086,23 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct */ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor); +/*! + * \brief Retrieve all contacts currently available for an AOR and filter based on flags + * \since 13.16.0 + * + * \param aor Pointer to the AOR + * \param flags Filtering flags + * + * \retval NULL if no contacts available + * \retval non-NULL if contacts available + * + * \warning + * Since this function prunes expired contacts before returning, it holds a named write + * lock on the aor. If you already hold the lock, call ast_sip_location_retrieve_aor_contacts_nolock instead. + */ +struct ao2_container *ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor, + unsigned int flags); + /*! * \brief Retrieve all contacts currently available for an AOR without locking the AOR * \since 13.9.0 @@ -1077,6 +1117,22 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_si */ struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor); +/*! + * \brief Retrieve all contacts currently available for an AOR without locking the AOR and filter based on flags + * \since 13.16.0 + * + * \param aor Pointer to the AOR + * \param flags Filtering flags + * + * \retval NULL if no contacts available + * \retval non-NULL if contacts available + * + * \warning + * This function should only be called if you already hold a named write lock on the aor. + */ +struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock_filtered(const struct ast_sip_aor *aor, + unsigned int flags); + /*! * \brief Retrieve the first bound contact from a list of AORs * @@ -1105,6 +1161,18 @@ struct ao2_container *ast_sip_location_retrieve_contacts_from_aor_list(const cha void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor, struct ast_sip_contact **contact); +/*! + * \brief Retrieve the first bound contact AND the AOR chosen from a list of AORs and filter based on flags + * \since 13.16.0 + * + * \param aor_list A comma-separated list of AOR names + * \param flags Filtering flags + * \param aor The chosen AOR + * \param contact The chosen contact + */ +void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags, + struct ast_sip_aor **aor, struct ast_sip_contact **contact); + /*! * \brief Retrieve a named contact * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 102bc393365..d994f28248b 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3040,7 +3040,7 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, if (res != PJ_SUCCESS) { if (res == PJSIP_EINVALIDURI) { ast_log(LOG_ERROR, - "Endpoint '%s': Could not create dialog to invalid URI '%s'. Is endpoint registered?\n", + "Endpoint '%s': Could not create dialog to invalid URI '%s'. Is endpoint registered and reachable?\n", ast_sorcery_object_get_id(endpoint), uri); } return NULL; diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 5abfcabadfc..6213046e39e 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -177,12 +177,36 @@ static int contact_link_static(void *obj, void *arg, int flags) return 0; } +/*! \brief Internal callback function which removes any contact which is unreachable */ +static int contact_remove_unreachable(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_contact_status *status; + int unreachable; + + status = ast_res_pjsip_find_or_create_contact_status(contact); + if (!status) { + return 0; + } + + unreachable = (status->status == UNAVAILABLE); + ao2_ref(status, -1); + + return unreachable ? CMP_MATCH : 0; +} + struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor) +{ + return ast_sip_location_retrieve_first_aor_contact_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT); +} + +struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact_filtered(const struct ast_sip_aor *aor, + unsigned int flags) { struct ao2_container *contacts; struct ast_sip_contact *contact = NULL; - contacts = ast_sip_location_retrieve_aor_contacts(aor); + contacts = ast_sip_location_retrieve_aor_contacts_filtered(aor, flags); if (contacts && ao2_container_count(contacts)) { /* Get the first AOR contact in the container. */ contact = ao2_callback(contacts, 0, NULL, NULL); @@ -192,6 +216,12 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct } struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor) +{ + return ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT); +} + +struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock_filtered(const struct ast_sip_aor *aor, + unsigned int flags) { /* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */ char regex[strlen(ast_sorcery_object_get_id(aor)) + 4]; @@ -211,23 +241,40 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ao2_callback(aor->permanent_contacts, OBJ_NODATA, contact_link_static, contacts); } + if (flags & AST_SIP_CONTACT_FILTER_REACHABLE) { + ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_remove_unreachable, NULL); + } + return contacts; } struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor) +{ + return ast_sip_location_retrieve_aor_contacts_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT); +} + +struct ao2_container *ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor, + unsigned int flags) { struct ao2_container *contacts; /* ao2_lock / ao2_unlock do not actually write aor since it has an ao2 lockobj. */ ao2_lock((void*)aor); - contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); + contacts = ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, flags); ao2_unlock((void*)aor); return contacts; } + void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor, struct ast_sip_contact **contact) +{ + ast_sip_location_retrieve_contact_and_aor_from_list_filtered(aor_list, AST_SIP_CONTACT_FILTER_DEFAULT, aor, contact); +} + +void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags, + struct ast_sip_aor **aor, struct ast_sip_contact **contact) { char *aor_name; char *rest; @@ -247,7 +294,7 @@ void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, s if (!(*aor)) { continue; } - *contact = ast_sip_location_retrieve_first_aor_contact(*aor); + *contact = ast_sip_location_retrieve_first_aor_contact_filtered(*aor, flags); /* If a valid contact is available use its URI for dialing */ if (*contact) { break; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 9e3abf253c5..8447be36e71 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1719,7 +1719,8 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint if (location || !contact) { location = S_OR(location, endpoint->aors); - ast_sip_location_retrieve_contact_and_aor_from_list(location, &found_aor, &found_contact); + ast_sip_location_retrieve_contact_and_aor_from_list_filtered(location, AST_SIP_CONTACT_FILTER_REACHABLE, + &found_aor, &found_contact); if (!found_contact || ast_strlen_zero(found_contact->uri)) { uri = location; } else { From b3ca24d216120d6f6fa1440c73331bb85592ddf1 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 6 Jun 2017 11:04:44 -0400 Subject: [PATCH 1294/1578] res_rtp_multicast: Use consistent timestamps when possible When a frame destined for a MulticastRTP channel does not have timing information (such as when an 'originate' is done), we generate the RTP timestamps ourselves without regard to the number of samples we are about to send. Instead, use the same method as res_rtp_asterisk and 'predict' a timestamp given the number of samples. If the difference between the timestamp that we generate and the one we predict is within a specific threshold, use the predicted timestamp so that we end up with timestamps that are consistent with the number of samples we are actually sending. Change-Id: I2bf0db3541b1573043330421cbb114ff0f22ec1f --- res/res_rtp_multicast.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index 14176da413a..72c53211bfa 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -99,6 +99,8 @@ struct multicast_rtp { struct ast_smoother *smoother; }; +#define MAX_TIMESTAMP_SKEW 640 + enum { OPT_CODEC = (1 << 0), OPT_LOOP = (1 << 1), @@ -415,21 +417,36 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr unsigned char *rtpheader; struct ast_sockaddr remote_address = { {0,} }; int rate = rtp_get_rate(frame->subclass.format) / 1000; - int hdrlen = 12; - - /* Calculate last TS */ - multicast->lastts = multicast->lastts + ms * rate; + int hdrlen = 12, mark = 0; - /* Construct an RTP header for our packet */ - rtpheader = (unsigned char *)(frame->data.ptr - hdrlen); - put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (multicast->seqno))); + if (ast_format_cmp(frame->subclass.format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) { + frame->samples /= 2; + } if (ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO)) { - put_unaligned_uint32(rtpheader + 4, htonl(frame->ts * 8)); + multicast->lastts = frame->ts * rate; } else { - put_unaligned_uint32(rtpheader + 4, htonl(multicast->lastts)); + /* Try to predict what our timestamp should be */ + int pred = multicast->lastts + frame->samples; + + /* Calculate last TS */ + multicast->lastts = multicast->lastts + ms * rate; + if (ast_tvzero(frame->delivery)) { + int delta = abs((int) multicast->lastts - pred); + if (delta < MAX_TIMESTAMP_SKEW) { + multicast->lastts = pred; + } else { + ast_debug(3, "Difference is %d, ms is %u\n", delta, ms); + mark = 1; + } + } } + /* Construct an RTP header for our packet */ + rtpheader = (unsigned char *)(frame->data.ptr - hdrlen); + + put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (multicast->seqno) | (mark << 23))); + put_unaligned_uint32(rtpheader + 4, htonl(multicast->lastts)); put_unaligned_uint32(rtpheader + 8, htonl(multicast->ssrc)); /* Increment sequence number and wrap to 0 if it overflows 16 bits. */ From d3e951edf5517b9f508a7e1b474176ec2be9e18f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 6 Jun 2017 12:04:21 +0000 Subject: [PATCH 1295/1578] pjsip: Extend 'asymmetric_rtp_codec' option to include us changing. PJSIP support in Asterisk differs from chan_sip in that it allows media to be sent as-is without transcoding provided the codecs were negotiated in the SDP. This is allowed according to the RFC. Support for this differs quite a lot though and some endpoints do not handle it well. This change extends the 'asymmetric_rtp_codec' option to also cover this case. When set to no (the default) the code behaves as chan_sip does - the best codec is selected and we will only ever send that, unless we change what we are sending if the remote side changes. When set to yes we will send media as-is without transcoding if the codec has been negotiated in the SDP. ASTERISK-26996 Change-Id: Ib1647f6902a0843e8c435946f831c2159e8d1d51 --- CHANGES | 6 ++++++ channels/chan_pjsip.c | 15 ++++++++++++++- res/res_pjsip_sdp_rtp.c | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 442f59d6241..741916aa2ba 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,12 @@ chan_pjsip function any contact which is considered unreachable due to qualify being enabled will no longer be called. + * The asymmetric_rtp_codec option now also controls whether chan_pjsip will + send media as-is without transcoding if the codec has been negotiated in the + SDP. If set to "no" then Asterisk will only ever send the preferred codec + from the SDP, unless the remote side sends a different codec and we will + switch to match. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5bf339ee943..19fb20bec4c 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -735,11 +735,24 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) if (!session->endpoint->asymmetric_rtp_codec && ast_format_cmp(ast_channel_rawwriteformat(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - /* For maximum compatibility we ensure that the write format matches that of the received media */ + struct ast_format_cap *caps; + + /* For maximum compatibility we ensure that the formats match that of the received media */ ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when we're sending '%s', switching to match\n", ast_format_get_name(f->subclass.format), ast_channel_name(ast), ast_format_get_name(ast_channel_rawwriteformat(ast))); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(ast), AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append(caps, f->subclass.format, 0); + ast_channel_nativeformats_set(ast, caps); + ao2_ref(caps, -1); + } + ast_set_write_format_path(ast, ast_channel_writeformat(ast), f->subclass.format); + ast_set_read_format_path(ast, ast_channel_readformat(ast), f->subclass.format); if (ast_channel_is_bridged(ast)) { ast_channel_set_unbridged_nolock(ast, 1); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 97e365c103a..c5a673aa4e0 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -410,13 +410,29 @@ static int set_caps(struct ast_sip_session *session, ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_remove_by_type(caps, media_type); + if (session->endpoint->preferred_codec_only){ struct ast_format *preferred_fmt = ast_format_cap_get_format(joint, 0); ast_format_cap_append(caps, preferred_fmt, 0); ao2_ref(preferred_fmt, -1); + } else if (!session->endpoint->asymmetric_rtp_codec) { + struct ast_format *best; + /* + * If we don't allow the sending codec to be changed on our side + * then get the best codec from the joint capabilities of the media + * type and use only that. This ensures the core won't start sending + * out a format that we aren't currently sending. + */ + + best = ast_format_cap_get_best_by_type(joint, media_type); + if (best) { + ast_format_cap_append(caps, best, ast_format_cap_get_framing(joint)); + ao2_ref(best, -1); + } } else { ast_format_cap_append_from_cap(caps, joint, media_type); } + /* * Apply the new formats to the channel, potentially changing * raw read/write formats and translation path while doing so. From 19da99df2f09ddfc11b2b2ba89727349fe915b1d Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Wed, 7 Jun 2017 12:21:10 -0400 Subject: [PATCH 1296/1578] CHANGES: correct version for a new option 'refer_blind_progress' Change-Id: If4817d26a8974610827624fb8a4e56d681d6bf97 --- CHANGES | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 442f59d6241..829086513f6 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,15 @@ app_queue --- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------ ------------------------------------------------------------------------------ +res_pjsip +------------------ + * A new endpoint option "refer_blind_progress" was added to turn off notifying + the progress details on Blind Transfer. If this option is not set then + the chan_pjsip will send NOTIFY "200 OK" immediately after "202 Accepted". + On default is enabled. + Some SIP phones like Mitel/Aastra or Snom keep the line busy until + receive "200 OK". + res_agi ------------------ * The EAGI() application will now look for a dialplan variable named @@ -38,15 +47,6 @@ chan_pjsip --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ -res_pjsip ------------------- - * A new endpoint option "refer_blind_progress" was added to turn off notifying - the progress details on Blind Transfer. If this option is not set then - the chan_pjsip will send NOTIFY "200 OK" immediately after "202 Accepted". - On default is enabled. - Some SIP phones like Mitel/Aastra or Snom keep the line busy until - receive "200 OK". - res_rtp_asterisk ------------------ * Added the stun_blacklist option to rtp.conf. Some multihomed servers have From e497a76d24ea079beb48968e9a2ef2b8102dd149 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 7 Jun 2017 15:32:57 -0400 Subject: [PATCH 1297/1578] eventfd: Disable during cross compilation Reported by Lonnie Abelbeck via private e-mail. Change-Id: Icc80f12b8d8d591e14a8e0ed9f1c02cbd193a89b --- configure | 8 +++----- configure.ac | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 739cf65e410..39ed4945746 100755 --- a/configure +++ b/configure @@ -18024,10 +18024,9 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have usable eventfd support" >&5 $as_echo_n "checking if we have usable eventfd support... " >&6; } if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compile" >&5 +$as_echo "cross-compile" >&6; } + else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18049,7 +18048,6 @@ $as_echo "#define HAVE_EVENTFD 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext diff --git a/configure.ac b/configure.ac index 9c07a4f6d99..d7fb2171e30 100644 --- a/configure.ac +++ b/configure.ac @@ -1131,7 +1131,8 @@ AC_RUN_IFELSE( [return eventfd(0, EFD_NONBLOCK | EFD_SEMAPHORE) == -1;])], AC_MSG_RESULT(yes) AC_DEFINE([HAVE_EVENTFD], 1, [Define to 1 if your system supports eventfd and the EFD_NONBLOCK and EFD_SEMAPHORE flags.]), - AC_MSG_RESULT(no) + AC_MSG_RESULT(no), + AC_MSG_RESULT(cross-compile) ) AST_GCC_ATTRIBUTE(pure) From 5b80496b42b0bef60a12a4c8fb3632beeba69cec Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 7 Jun 2017 20:19:05 +0000 Subject: [PATCH 1298/1578] chan_pjsip: Update device state when in early media. The chan_pjsip module uses a calculation approach for determining device state. This means that in situations where we would expect device state to change we need to tell the core to query. A scenario that was missed is when early media was signaled. This change adds the notification for the core to query device state when we are told that early media is being provided. ASTERISK-27039 Change-Id: Iafebfd152894966344ff2e950a3cee9f59a3eb6f --- channels/chan_pjsip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5bf339ee943..3f65a13de20 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1387,6 +1387,7 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi } else { res = -1; } + ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_sorcery_object_get_id(channel->session->endpoint)); break; case AST_CONTROL_VIDUPDATE: media = pvt->media[SIP_MEDIA_VIDEO]; From 7b668297f3feb2a85abdc666b759ff69b69f109e Mon Sep 17 00:00:00 2001 From: Guido Falsi Date: Thu, 8 Jun 2017 17:36:00 +0200 Subject: [PATCH 1299/1578] BuildSystem: Fix build on FreeBSD due to missing crypt.h FreeBSD does not include a crypt.h include file. Definitions for crypt() and crypt_r() are in unistd.h ASTERISK-27042 #close Change-Id: Ib307ee5e384870c6af50efa89fb73722dd0c3a7e --- main/crypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/crypt.c b/main/crypt.c index 924618205a4..131ebbd6090 100644 --- a/main/crypt.c +++ b/main/crypt.c @@ -29,7 +29,7 @@ #include "asterisk.h" #include -#if defined(HAVE_CRYPT_R) +#if defined(HAVE_CRYPT_R) && !defined(__FreeBSD__) #include #endif From fcb1a0d7e803e033545fc721ab12a903603d302c Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Tue, 6 Jun 2017 14:54:43 -0500 Subject: [PATCH 1300/1578] CFLAGS for BIND8 support Some systems (like macOS) require BIND_8_COMPAT to be defined so that the nameser libraries are, well, BIND8 compatible. Change-Id: If79fc27a64f90de1835b5aa3aadfa9be22bd16b0 --- Makefile | 3 +++ configure | 28 ++++++++++++++++++++++++++++ configure.ac | 12 ++++++++++++ makeopts.in | 2 ++ 4 files changed, 45 insertions(+) diff --git a/Makefile b/Makefile index f29c07f6809..85a1152eac7 100644 --- a/Makefile +++ b/Makefile @@ -124,6 +124,9 @@ _ASTLDFLAGS+=$(LDOPTS) # libxml2 cflags _ASTCFLAGS+=$(LIBXML2_INCLUDE) +# BIND_8_COMPAT +_ASTCFLAGS+=$(BIND8_CFLAGS) + #Uncomment this to see all build commands instead of 'quiet' output #NOISY_BUILD=yes diff --git a/configure b/configure index 739cf65e410..91117632acf 100755 --- a/configure +++ b/configure @@ -697,6 +697,7 @@ PBX_IP_MTU_DISCOVER PBX_RTLD_NOLOAD PBX_GLOB_BRACE PBX_GLOB_NOMAGIC +BIND8_CFLAGS AST_RPATH AST_NATIVE_ARCH AST_SHADOW_WARNINGS @@ -19410,6 +19411,33 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BIND_8_COMPAT required" >&5 +$as_echo_n "checking for BIND_8_COMPAT required... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#undef BIND_8_COMPAT +#include + +int +main () +{ +int x = NXDOMAIN + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +BIND8_CFLAGS=-DBIND_8_COMPAT +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + if test "x${PBX_GLOB_NOMAGIC}" != "x1"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLOB_NOMAGIC in glob.h" >&5 diff --git a/configure.ac b/configure.ac index 9c07a4f6d99..07aa1670dc6 100644 --- a/configure.ac +++ b/configure.ac @@ -1360,6 +1360,18 @@ AC_LINK_IFELSE( AC_MSG_RESULT(no) ) +AC_MSG_CHECKING(for BIND_8_COMPAT required) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[[ +#undef BIND_8_COMPAT +#include +]], +[[int x = NXDOMAIN]])], +AC_MSG_RESULT(no), +AC_MSG_RESULT(yes) +[BIND8_CFLAGS=-DBIND_8_COMPAT]) +AC_SUBST(BIND8_CFLAGS) + AST_C_DEFINE_CHECK([GLOB_NOMAGIC], [GLOB_NOMAGIC], [glob.h]) AST_C_DEFINE_CHECK([GLOB_BRACE], [GLOB_BRACE], [glob.h]) diff --git a/makeopts.in b/makeopts.in index 03ef7470c1e..07360a71b47 100644 --- a/makeopts.in +++ b/makeopts.in @@ -62,6 +62,8 @@ HOST_OS=@HOST_OS@ OSARCH=@OSARCH@ OSREV=@PBX_OSREV@ +BIND8_CFLAGS=@BIND8_CFLAGS@ + PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ PTHREAD_LIBS=@PTHREAD_LIBS@ From d27168d36ffb634e4a70a3c93738bfa9da7e2605 Mon Sep 17 00:00:00 2001 From: Guido Falsi Date: Thu, 8 Jun 2017 17:54:46 +0200 Subject: [PATCH 1301/1578] BuildSystem: Add patches to allow building with recent LibreSSL Add some #if defined checks which allow building against LibreSSL. These patchess come from OpenBSD ports: https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/telephony/asterisk/patches/ ASTERISK-27043 #close Reported by: OpenBSD ports Change-Id: I2f6c08a5840b85ad4d2b75370b947ddde7a9a572 --- main/iostream.c | 4 ++-- main/libasteriskssl.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main/iostream.c b/main/iostream.c index 06414cf43d6..2a2601d3809 100644 --- a/main/iostream.c +++ b/main/iostream.c @@ -508,13 +508,13 @@ int ast_iostream_close(struct ast_iostream *stream) ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res)); } -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) if (!SSL_is_server(stream->ssl)) { #else if (!stream->ssl->server) { #endif /* For client threads, ensure that the error stack is cleared */ -#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L +#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) #if OPENSSL_VERSION_NUMBER >= 0x10000000L ERR_remove_thread_state(NULL); #else diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c index 0ed05e3dcbf..9da63de4c56 100644 --- a/main/libasteriskssl.c +++ b/main/libasteriskssl.c @@ -72,7 +72,7 @@ static void ssl_lock(int mode, int n, const char *file, int line) } } -#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L +#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) int SSL_library_init(void) { #if defined(AST_DEVMODE) @@ -127,7 +127,7 @@ void ERR_free_strings(void) int ast_ssl_init(void) { #if defined(HAVE_OPENSSL) && defined(OPENSSL_VERSION_NUMBER) && \ - OPENSSL_VERSION_NUMBER < 0x10100000L + (OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)) unsigned int i; int (*real_SSL_library_init)(void); void (*real_CRYPTO_set_id_callback)(unsigned long (*)(void)); From 8d1f54b92e5946de8297a26aa196edc778f0d4eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20H?= Date: Thu, 8 Jun 2017 22:31:47 +0000 Subject: [PATCH 1302/1578] res_pjsip_transport_websocket: Add NULL check in get_write_timeout Added check for NULL return value when calling ast_sorcery_retrieve_by_id in function get_write_timeout ASTERISK-27046 Change-Id: I9357717278da631c3a1cb502c412693929b0cb41 --- res/res_pjsip_transport_websocket.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index b3e63fcc13f..cdda8c19642 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -302,10 +302,14 @@ static int get_write_timeout(void) for (; (transport_state = ao2_iterator_next(&it_transport_states)); ao2_cleanup(transport_state)) { struct ast_sip_transport *transport; + if (transport_state->type != AST_TRANSPORT_WS && transport_state->type != AST_TRANSPORT_WSS) { continue; } transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id); + if (!transport) { + continue; + } ast_debug(5, "Found %s transport with write timeout: %d\n", transport->type == AST_TRANSPORT_WS ? "WS" : "WSS", transport->write_timeout); From 847087a4ffc3fe914cdeea519c9d52a2f8709d7f Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sun, 11 Jun 2017 13:06:17 -0400 Subject: [PATCH 1303/1578] codecs.conf.sample: Fix max_bandwidth speling error Reported by Sylvain Boily via asterisk-dev mailing list. Change-Id: Idc7623f335aea3e144dd369ba383b9a757480a9d --- configs/samples/codecs.conf.sample | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configs/samples/codecs.conf.sample b/configs/samples/codecs.conf.sample index e40aa35a3b9..9b7af3e3625 100644 --- a/configs/samples/codecs.conf.sample +++ b/configs/samples/codecs.conf.sample @@ -165,9 +165,9 @@ packetloss_percentage=10; ;complexity= ; Encoder's computational complexity. Can be any number between 0 ; and 10, inclusive. Note, 10 equals the highest complexity. ; (default: 10) -;max_bandwitdth= ; Encoder's maximum bandwidth allowed. Sets an upper bandwidth - ; bound on the encoder. Can be any of the following: narrow, - ; medium, wide, super_wide, full. (default: full) +;max_bandwidth= ; Encoder's maximum bandwidth allowed. Sets an upper bandwidth + ; bound on the encoder. Can be any of the following: narrow, + ; medium, wide, super_wide, full. (default: full) ;signal= ; Encoder's signal type. Aids in mode selection on the encoder: Can ; be any of the following: auto, voice, music. (default: auto) ;application= ; Encoder's application type. Can be any of the following: voip, From 42f738e0528252479496680925081a35b1172b7e Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 12 Jun 2017 10:57:24 -0400 Subject: [PATCH 1304/1578] res_pjsip_mwi: don't create mwi subscriptions if initial unsolicited disabled If sending unsolicited mwi to all endpoints on startup is disabled (mwi_disable_initial_unsolicited=yes) do not need to create subscriptions. If there are many (thousands) realtime endpoints configured with unsolicited mwi and Vociemail Storage configured as ODBC or IMAP there will be huge number of DB/IMAP requests on startup. ASTERISK-26230 #close Change-Id: I50ae909639e3ee298b931a54def4b2b9e0fb86c5 --- res/res_pjsip_mwi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index e625df77a72..3dfccef86bc 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -1278,7 +1278,9 @@ static struct ast_sorcery_observer global_observer = { static int reload(void) { - create_mwi_subscriptions(); + if (!ast_sip_get_mwi_disable_initial_unsolicited()) { + create_mwi_subscriptions(); + } return 0; } @@ -1301,13 +1303,13 @@ static int load_module(void) ast_sip_unregister_subscription_handler(&mwi_handler); return AST_MODULE_LOAD_DECLINE; } - create_mwi_subscriptions(); ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer); ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer); ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); if (!ast_sip_get_mwi_disable_initial_unsolicited()) { + create_mwi_subscriptions(); if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { ast_sip_push_task(NULL, send_initial_notify_all, NULL); } else { From b2fd7e50695b64826cbfcd65aa6e5c06532b3e5e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 13 Jun 2017 09:47:43 -0600 Subject: [PATCH 1305/1578] pjproject_bundled: Use the asterisk github mirror for download We now mirror the pjproject tarball and md5 at https://github.com/asterisk/third-party/tree/master/pjproject To improve download reliability, we now get the tarball from our mirror instead of from pjsip.org. ASTERISK-27052 #close Reported-by: 'alex' Change-Id: I60236587a8935bfa71fcc391f4e2ecb31918c08a --- third-party/pjproject/Makefile | 2 +- third-party/pjproject/Makefile.rules | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index e691f22428d..a5b5508425e 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -97,7 +97,7 @@ endef define download_from_pjproject ($(SHELL_ECHO_PREFIX) Downloading $(TARBALL_URL) to $(TARBALL) ;\ $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(TARBALL_URL) > $(TARBALL) &&\ - $(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM to $(PJMD5SUM) &&\ + $(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM.TXT to $(PJMD5SUM) &&\ $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\ $(verify_tarball)) endef diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index c0be1cbdf84..3f99c8a8f1f 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -1,4 +1,4 @@ -PJPROJECT_URL = http://www.pjsip.org/release/$(PJPROJECT_VERSION) +PJPROJECT_URL ?= https://raw.githubusercontent.com/asterisk/third-party/master/pjproject/$(PJPROJECT_VERSION) # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe From 9e53c30610945fa0c16e9954ccb549c70d74f923 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 13 Jun 2017 14:17:29 -0500 Subject: [PATCH 1306/1578] res_pjsip_refer/session: Calls dropped during transfer When doing an attended transfer it's possible for the transferer, after receiving an accepted response from Asterisk, to send a BYE to Asterisk, which can then be processed before Asterisk has time to start and/or complete the transfer process. This of course causes the transfer to not complete successfully, thus dropping the call. This patch makes it so any BYEs received from the transferer, after the REFER, that initiate a session end are deferred until the transfer is complete. This allows the channel that would have otherwise been hung up by Asterisk to remain available throughout the transfer process. ASTERISK-27053 #close Change-Id: I43586db79079457d92d71f1fd993be9a3b409d5a --- include/asterisk/res_pjsip_session.h | 11 +++++++++++ res/res_pjsip_refer.c | 8 ++++++++ res/res_pjsip_session.c | 26 ++++++++++++++++++++++++++ res/res_pjsip_session.exports.in | 1 + 4 files changed, 46 insertions(+) diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 10e55f1337c..e2a90662ed0 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -155,6 +155,10 @@ struct ast_sip_session { struct ast_sip_aor *aor; /*! From header saved at invite creation */ pjsip_fromto_hdr *saved_from_hdr; + /*! Whether the end of the session should be deferred */ + unsigned int defer_end:1; + /*! Session end (remote hangup) requested while termination deferred */ + unsigned int ended_while_deferred:1; }; typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata); @@ -483,6 +487,13 @@ int ast_sip_session_defer_termination(struct ast_sip_session *session); */ void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session); +/*! + * \brief End the session if it had been previously deferred + * + * \param session The session to end if it had been deferred + */ +void ast_sip_session_end_if_deferred(struct ast_sip_session *session); + /*! * \brief Register an SDP handler * diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 46295387d53..456e09dd812 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -543,6 +543,7 @@ static int refer_attended_task(void *data) } } + ast_sip_session_end_if_deferred(attended->transferer); if (response != 200) { if (!ast_sip_push_task(attended->transferer->serializer, defer_termination_cancel, attended->transferer)) { @@ -772,6 +773,7 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi /* Push it to the other session, which will have both channels with minimal locking */ if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) { + ast_sip_session_end_if_deferred(session); ast_sip_session_defer_termination_cancel(session); ao2_cleanup(attended); return 500; @@ -810,9 +812,12 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi response = xfer_response_code2sip(ast_bridge_transfer_blind(1, session->channel, "external_replaces", context, refer_blind_callback, &refer)); + + ast_sip_session_end_if_deferred(session); if (response != 200) { ast_sip_session_defer_termination_cancel(session); } + return response; } } @@ -865,9 +870,12 @@ static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_r response = xfer_response_code2sip(ast_bridge_transfer_blind(1, session->channel, exten, context, refer_blind_callback, &refer)); + + ast_sip_session_end_if_deferred(session); if (response != 200) { ast_sip_session_defer_termination_cancel(session); } + return response; } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 8447be36e71..2f71c4c0893 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1905,6 +1905,9 @@ int ast_sip_session_defer_termination(struct ast_sip_session *session) session->defer_terminate = 1; + session->defer_end = 1; + session->ended_while_deferred = 0; + session->scheduled_termination.id = 0; ao2_ref(session, +1); session->scheduled_termination.user_data = session; @@ -1942,6 +1945,7 @@ void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session) /* Already canceled or timer fired. */ return; } + session->defer_terminate = 0; if (session->terminate_while_deferred) { @@ -1953,6 +1957,22 @@ void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session) sip_session_defer_termination_stop_timer(session); } +void ast_sip_session_end_if_deferred(struct ast_sip_session *session) +{ + if (!session->defer_end) { + return; + } + + session->defer_end = 0; + + if (session->ended_while_deferred) { + /* Complete the session end started by the remote hangup. */ + ast_debug(3, "Ending session (%p) after being deferred\n", session); + session->ended_while_deferred = 0; + session_end(session); + } +} + struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg) { pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg); @@ -2672,6 +2692,12 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) } if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + if (session->defer_end) { + ast_debug(3, "Deferring session (%p) end\n", session); + session->ended_while_deferred = 1; + return; + } + if (ast_sip_push_task(session->serializer, session_end, session)) { /* Do it anyway even though this is not the right thread. */ session_end(session); diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in index a39485e66d2..fdfc5fb4724 100644 --- a/res/res_pjsip_session.exports.in +++ b/res/res_pjsip_session.exports.in @@ -3,6 +3,7 @@ LINKER_SYMBOL_PREFIXast_sip_session_terminate; LINKER_SYMBOL_PREFIXast_sip_session_defer_termination; LINKER_SYMBOL_PREFIXast_sip_session_defer_termination_cancel; + LINKER_SYMBOL_PREFIXast_sip_session_end_if_deferred; LINKER_SYMBOL_PREFIXast_sip_session_register_sdp_handler; LINKER_SYMBOL_PREFIXast_sip_session_unregister_sdp_handler; LINKER_SYMBOL_PREFIXast_sip_session_register_supplement; From d6386a8f0ca635ba770c1d102f69361beebef7d6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 8 Jun 2017 19:38:51 +0000 Subject: [PATCH 1307/1578] bridge: Add a deferred queue. This change adds a deferred queue to bridging. If a bridge technology determines that a frame can not be written and should be deferred it can indicate back to bridging to do so. Bridging will then requeue any deferred frames upon a new channel joining the bridge. This change has been leveraged for T.38 request negotiate control frames. Without the deferred queue there is a race condition between the bridge receiving the T.38 request negotiate and the second channel joining and being in the bridge. If the channel is not yet in the bridge then the T.38 negotiation fails. A unit test has also been added that confirms that a T.38 request negotiate control frame is deferred when no other channel is in the bridge and that it is requeued when a new channel joins the bridge. ASTERISK-26923 Change-Id: Ie05b08523f399eae579130f4a5f562a344d2e415 --- bridges/bridge_native_rtp.c | 32 ++- bridges/bridge_simple.c | 32 ++- include/asterisk/bridge_channel.h | 2 + include/asterisk/bridge_channel_internal.h | 11 + include/asterisk/bridge_technology.h | 3 + main/bridge.c | 1 + main/bridge_channel.c | 36 ++- tests/test_bridging.c | 290 +++++++++++++++++++++ 8 files changed, 397 insertions(+), 10 deletions(-) create mode 100644 tests/test_bridging.c diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 77e321f4f0f..4af93bfca21 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -508,7 +508,37 @@ static void native_rtp_bridge_leave(struct ast_bridge *bridge, struct ast_bridge static int native_rtp_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { - return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame); + const struct ast_control_t38_parameters *t38_parameters; + int defer = 0; + + if (!ast_bridge_queue_everyone_else(bridge, bridge_channel, frame)) { + /* This frame was successfully queued so no need to defer */ + return 0; + } + + /* Depending on the frame defer it so when the next channel joins it receives it */ + switch (frame->frametype) { + case AST_FRAME_CONTROL: + switch (frame->subclass.integer) { + case AST_CONTROL_T38_PARAMETERS: + t38_parameters = frame->data.ptr; + switch (t38_parameters->request_response) { + case AST_T38_REQUEST_NEGOTIATE: + defer = -1; + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + + return defer; } static struct ast_bridge_technology native_rtp_bridge = { diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index 3bf04038096..a49bc39f3a2 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -71,7 +71,37 @@ static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chann static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { - return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame); + const struct ast_control_t38_parameters *t38_parameters; + int defer = 0; + + if (!ast_bridge_queue_everyone_else(bridge, bridge_channel, frame)) { + /* This frame was successfully queued so no need to defer */ + return 0; + } + + /* Depending on the frame defer it so when the next channel joins it receives it */ + switch (frame->frametype) { + case AST_FRAME_CONTROL: + switch (frame->subclass.integer) { + case AST_CONTROL_T38_PARAMETERS: + t38_parameters = frame->data.ptr; + switch (t38_parameters->request_response) { + case AST_T38_REQUEST_NEGOTIATE: + defer = -1; + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + + return defer; } static struct ast_bridge_technology simple_bridge = { diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index dd72f3275fc..4d3326083a6 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -145,6 +145,8 @@ struct ast_bridge_channel { AST_LIST_ENTRY(ast_bridge_channel) entry; /*! Queue of outgoing frames to the channel. */ AST_LIST_HEAD_NOLOCK(, ast_frame) wr_queue; + /*! Queue of deferred frames, queued onto channel when other party joins. */ + AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_queue; /*! Pipe to alert thread when frames are put into the wr_queue. */ int alert_pipe[2]; /*! diff --git a/include/asterisk/bridge_channel_internal.h b/include/asterisk/bridge_channel_internal.h index fb8e781e8fe..ba71e9fc4ef 100644 --- a/include/asterisk/bridge_channel_internal.h +++ b/include/asterisk/bridge_channel_internal.h @@ -96,6 +96,17 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid */ void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct ast_bridge_channel *bridge_channel); +/*! + * \internal + * \brief Queue any deferred frames on the channel. + * \since 13.17.0 + * + * \param bridge_channel Channel that the deferred frames should be pulled from and queued to. + * + * \return Nothing + */ +void bridge_channel_queue_deferred_frames(struct ast_bridge_channel *bridge_channel); + /*! * \internal * \brief Push the bridge channel into its specified bridge. diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridge_technology.h index 09b0fc0e8d8..8cebe93266f 100644 --- a/include/asterisk/bridge_technology.h +++ b/include/asterisk/bridge_technology.h @@ -156,6 +156,9 @@ struct ast_bridge_technology { * \retval -1 Frame needs to be deferred. * * \note On entry, bridge is already locked. + * + * \note Deferred frames will be automatically queued onto the channel when another + * channel joins the bridge. */ int (*write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame); /*! diff --git a/main/bridge.c b/main/bridge.c index 4631e5a5276..8cde62cb536 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -476,6 +476,7 @@ static void bridge_complete_join(struct ast_bridge *bridge) } AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { + bridge_channel_queue_deferred_frames(bridge_channel); if (!bridge_channel->just_joined) { continue; } diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 02783b103b6..e8ab8a89805 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -638,18 +638,21 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int caus static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { const struct ast_control_t38_parameters *t38_parameters; + int deferred; ast_assert(frame->frametype != AST_FRAME_BRIDGE_ACTION_SYNC); ast_bridge_channel_lock_bridge(bridge_channel); -/* - * XXX need to implement a deferred write queue for when there - * is no peer channel in the bridge (yet or it was kicked). - * - * The tech decides if a frame needs to be pushed back for deferral. - * simple_bridge/native_bridge are likely the only techs that will do this. - */ - bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame); + + deferred = bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame); + if (deferred) { + struct ast_frame *dup; + + dup = ast_frdup(frame); + if (dup) { + AST_LIST_INSERT_HEAD(&bridge_channel->deferred_queue, dup, frame_list); + } + } /* Remember any owed events to the bridge. */ switch (frame->frametype) { @@ -753,6 +756,18 @@ void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct as } } +void bridge_channel_queue_deferred_frames(struct ast_bridge_channel *bridge_channel) +{ + struct ast_frame *frame; + + ast_channel_lock(bridge_channel->chan); + while ((frame = AST_LIST_REMOVE_HEAD(&bridge_channel->deferred_queue, frame_list))) { + ast_queue_frame_head(bridge_channel->chan, frame); + ast_frfree(frame); + } + ast_channel_unlock(bridge_channel->chan); +} + /*! * \internal * \brief Suspend a channel from a bridge. @@ -2933,6 +2948,11 @@ static void bridge_channel_destroy(void *obj) } ast_alertpipe_close(bridge_channel->alert_pipe); + /* Flush any unhandled deferred_queue frames. */ + while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->deferred_queue, frame_list))) { + ast_frfree(fr); + } + ast_cond_destroy(&bridge_channel->cond); ao2_cleanup(bridge_channel->write_format); diff --git a/tests/test_bridging.c b/tests/test_bridging.c new file mode 100644 index 00000000000..74595c4f205 --- /dev/null +++ b/tests/test_bridging.c @@ -0,0 +1,290 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Bridging unit tests + * + * \author Joshua Colp + * + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" + +#include "asterisk/module.h" +#include "asterisk/test.h" +#include "asterisk/channel.h" +#include "asterisk/time.h" +#include "asterisk/bridge.h" +#include "asterisk/bridge_basic.h" +#include "asterisk/features.h" +#include "asterisk/format_cache.h" + +#define TEST_CATEGORY "/main/bridging/" + +#define CHANNEL_TECH_NAME "BridgingTestChannel" + +#define TEST_CHANNEL_FORMAT ast_format_slin + +/*! \brief A private structure for the test channel */ +struct test_bridging_chan_pvt { + /* \brief The expected indication */ + int condition; + /*! \brief The number of indicated things */ + unsigned int indicated; +}; + +/*! \brief Callback function for when a frame is written to a channel */ +static int test_bridging_chan_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen) +{ + struct test_bridging_chan_pvt *test_pvt = ast_channel_tech_pvt(chan); + + if (condition == test_pvt->condition) { + test_pvt->indicated++; + } + + return 0; +} + +/*! \brief Callback function for when a channel is hung up */ +static int test_bridging_chan_hangup(struct ast_channel *chan) +{ + struct test_bridging_chan_pvt *test_pvt = ast_channel_tech_pvt(chan); + + ast_free(test_pvt); + ast_channel_tech_pvt_set(chan, NULL); + + return 0; +} + +/*! \brief A channel technology used for the unit tests */ +static struct ast_channel_tech test_bridging_chan_tech = { + .type = CHANNEL_TECH_NAME, + .description = "Mock channel technology for bridge tests", + .indicate = test_bridging_chan_indicate, + .hangup = test_bridging_chan_hangup, + .properties = AST_CHAN_TP_INTERNAL, +}; + +static void test_nanosleep(int secs, long nanosecs) +{ + struct timespec sleep_time = {secs, nanosecs}; + + while ((nanosleep(&sleep_time, &sleep_time) == -1) && (errno == EINTR)) { + } +} + +/*! \brief Wait until a channel is bridged */ +static void wait_for_bridged(struct ast_channel *channel) +{ + ast_channel_lock(channel); + while (!ast_channel_is_bridged(channel)) { + ast_channel_unlock(channel); + test_nanosleep(0, 1000000); + ast_channel_lock(channel); + } + ast_channel_unlock(channel); +} + +/*! \brief Wait until a channel is not bridged */ +static void wait_for_unbridged(struct ast_channel *channel) +{ + ast_channel_lock(channel); + while (ast_channel_is_bridged(channel)) { + ast_channel_unlock(channel); + test_nanosleep(0, 1000000); + ast_channel_lock(channel); + } + ast_channel_unlock(channel); +} + +/*! \brief Wait until a channel has no frames on its read queue */ +static void wait_for_empty_queue(struct ast_channel *channel) +{ + ast_channel_lock(channel); + while (!AST_LIST_EMPTY(ast_channel_readq(channel))) { + ast_channel_unlock(channel); + test_nanosleep(0, 1000000); + ast_channel_lock(channel); + } + ast_channel_unlock(channel); +} + +/*! \brief Create a \ref test_bridging_chan_tech for Alice. */ +#define START_ALICE(channel, pvt) START_CHANNEL(channel, pvt, "Alice", "100") + +/*! \brief Create a \ref test_bridging_chan_tech for Bob. */ +#define START_BOB(channel, pvt) START_CHANNEL(channel, pvt, "Bob", "200") + +#define START_CHANNEL(channel, pvt, name, number) do { \ + channel = ast_channel_alloc(0, AST_STATE_UP, number, name, number, number, \ + "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/" name); \ + pvt = ast_calloc(1, sizeof(*pvt)); \ + ast_channel_tech_pvt_set(channel, pvt); \ + ast_channel_nativeformats_set(channel, test_bridging_chan_tech.capabilities); \ + ast_channel_set_rawwriteformat(channel, TEST_CHANNEL_FORMAT); \ + ast_channel_set_rawreadformat(channel, TEST_CHANNEL_FORMAT); \ + ast_channel_set_writeformat(channel, TEST_CHANNEL_FORMAT); \ + ast_channel_set_readformat(channel, TEST_CHANNEL_FORMAT); \ + ast_channel_unlock(channel); \ + } while (0) + +/*! \brief Hang up a test channel safely */ +#define HANGUP_CHANNEL(channel) do { \ + ao2_ref(channel, +1); \ + ast_hangup((channel)); \ + ao2_cleanup(channel); \ + channel = NULL; \ + } while (0) + +static void safe_channel_release(struct ast_channel *chan) +{ + if (!chan) { + return; + } + ast_channel_release(chan); +} + +static void safe_bridge_destroy(struct ast_bridge *bridge) +{ + if (!bridge) { + return; + } + ast_bridge_destroy(bridge, 0); +} + +static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms) +{ + long nanosecs; + + ast_assert(chan != NULL); + ast_assert(0 < ms); + ast_assert(0 < interval_ms); + + nanosecs = interval_ms * 1000000L; + while (0 < ms) { + ast_queue_frame(chan, &ast_null_frame); + + if (interval_ms < ms) { + ms -= interval_ms; + } else { + nanosecs = ms * 1000000L; + ms = 0; + } + test_nanosleep(0, nanosecs); + } +} + +AST_TEST_DEFINE(test_bridging_deferred_queue) +{ + RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release); + struct test_bridging_chan_pvt *alice_pvt; + struct ast_control_t38_parameters t38_parameters = { + .request_response = AST_T38_REQUEST_NEGOTIATE, + }; + struct ast_frame frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_T38_PARAMETERS, + .data.ptr = &t38_parameters, + .datalen = sizeof(t38_parameters), + }; + RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release); + struct test_bridging_chan_pvt *bob_pvt; + RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy); + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = TEST_CATEGORY; + info->summary = "Test that deferred frames from a channel in a bridge get written"; + info->description = + "This test creates two channels, queues a deferrable frame on one, places it into\n" + "a bridge, confirms the frame was read by the bridge, adds the second channel to the\n" + "bridge, and makes sure the deferred frame is written to it."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* Create the bridges */ + bridge1 = ast_bridge_basic_new(); + ast_test_validate(test, bridge1 != NULL); + + /* Create channels that will go into the bridge */ + START_ALICE(chan_alice, alice_pvt); + START_BOB(chan_bob, bob_pvt); + bob_pvt->condition = AST_CONTROL_T38_PARAMETERS; + + /* Bridge alice and wait for the frame to be deferred */ + ast_test_validate(test, !ast_bridge_impart(bridge1, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); + wait_for_bridged(chan_alice); + ast_queue_frame(chan_alice, &frame); + wait_for_empty_queue(chan_alice); + + /* Bridge bob for a second so it can receive the deferred T.38 request negotiate frame */ + ast_test_validate(test, !ast_bridge_impart(bridge1, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); + wait_for_bridged(chan_bob); + stream_periodic_frames(chan_alice, 1000, 20); + ast_test_validate(test, !ast_bridge_depart(chan_bob)); + wait_for_unbridged(chan_bob); + + /* Ensure that we received the expected indications while it was in there (request to negotiate, and to terminate) */ + ast_test_validate(test, bob_pvt->indicated == 2); + + /* Now remove alice since we are done */ + ast_test_validate(test, !ast_bridge_depart(chan_alice)); + wait_for_unbridged(chan_alice); + + /* Hangup the channels */ + HANGUP_CHANNEL(chan_alice); + HANGUP_CHANNEL(chan_bob); + + return AST_TEST_PASS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(test_bridging_deferred_queue); + + ast_channel_unregister(&test_bridging_chan_tech); + ao2_cleanup(test_bridging_chan_tech.capabilities); + test_bridging_chan_tech.capabilities = NULL; + + return 0; +} + +static int load_module(void) +{ + test_bridging_chan_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!test_bridging_chan_tech.capabilities) { + return AST_MODULE_LOAD_DECLINE; + } + ast_format_cap_append(test_bridging_chan_tech.capabilities, TEST_CHANNEL_FORMAT, 0); + ast_channel_register(&test_bridging_chan_tech); + + AST_TEST_REGISTER(test_bridging_deferred_queue); + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bridging Unit Tests"); From 88f18faf2a150b85255ce3010456e4f039956c99 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 14 Jun 2017 07:54:45 -0600 Subject: [PATCH 1308/1578] res_rtp_asterisk: Fix ssrc change for rtcp srtp It looks like there was a copy/paste error in ast_rtp_change_source where if there was a rtcp srtp instance, instead of updating its ssrc we were updating the srtp instance ssrc twice. ASTERISK-27022 #close Reported-by: Michael Walton Change-Id: Ic88f3aee7227b401c58745ac265ff92c19620095 --- res/res_rtp_asterisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index c120fc1452e..600846c8510 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -3447,7 +3447,7 @@ static void ast_rtp_change_source(struct ast_rtp_instance *instance) ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc); res_srtp->change_source(srtp, rtp->ssrc, ssrc); if (rtcp_srtp != srtp) { - res_srtp->change_source(srtp, rtp->ssrc, ssrc); + res_srtp->change_source(rtcp_srtp, rtp->ssrc, ssrc); } } From ea3f8c6889e236a8c7aa8065da5fe426a28f01ae Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 14 Jun 2017 07:29:00 -0600 Subject: [PATCH 1309/1578] res_pjsip_session: Correct inverted test in session_outgoing_nat_hook There was a typo introduced in commit 776ffd77 which was preventing the transport's external media address from being used. ASTERISK-27024 #close Reported-by: Christopher van de Sande patches: patch.diff submitted by Florian Floimair (license 6892) Change-Id: I7ec617171eaa2d86d2680b00cf37d5088adafc27 --- res/res_pjsip_session.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 8447be36e71..bde66d25adc 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -3159,8 +3159,7 @@ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_trans ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID); if (!transport_state->localnet - || (transport_state->localnet - && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW)) { + || ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) { ast_debug(5, "Setting external media address to %s\n", transport->external_media_address); pj_strdup2(tdata->pool, &sdp->conn->addr, transport->external_media_address); } From 65ed2ea311146264c4ae0c5edd6c5932e6b06f32 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 14 Jun 2017 10:12:21 -0600 Subject: [PATCH 1310/1578] res_pjsip_pubsub: Fix reference to released endpoint destroy_subscription was attempting to get the id of the subscription tree's endpoint after we'd already called ao2_cleanup on it causing a segfault. Moved the cleanup until after the debug statement and since endpoint could also be NULL at this point, check for that as well. ASTERISK-27057 #close Reported-by: Ryan Smith Change-Id: Ice0a7727f560cf204d870a774c6df71e159b1678 --- res/res_pjsip_pubsub.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index a1f3f246257..9f0eae241c8 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1086,7 +1086,9 @@ static void remove_subscription(struct sip_subscription_tree *obj) static void destroy_subscription(struct ast_sip_subscription *sub) { ast_debug(3, "Destroying SIP subscription from '%s->%s'\n", - ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource); + sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown", + sub->resource); + ast_free(sub->body_text); AST_VECTOR_FREE(&sub->children); @@ -1243,14 +1245,14 @@ static void subscription_tree_destructor(void *obj) sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown", sub_tree->root ? sub_tree->root->resource : "Unknown"); - ao2_cleanup(sub_tree->endpoint); - destroy_subscriptions(sub_tree->root); if (sub_tree->dlg) { ast_sip_push_task_synchronous(sub_tree->serializer, subscription_unreference_dialog, sub_tree); } + ao2_cleanup(sub_tree->endpoint); + ast_taskprocessor_unreference(sub_tree->serializer); ast_module_unref(ast_module_info->self); } From 023eede2652d95a98b756df1b105ed978e561c81 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 12 Jun 2017 18:55:15 -0400 Subject: [PATCH 1311/1578] app_voicemail: IMAP logout on MWI unsubscribe Closing IMAP connection on MWI unsubscribe. ASTERISK-24052 #close Change-Id: I4ff964026002b2817b48c20fb4239f0a880228fd --- apps/app_voicemail.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 06f4830faec..ba9378380e2 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -13106,6 +13106,40 @@ static void mwi_sub_destroy(struct mwi_sub *mwi_sub) ast_free(mwi_sub); } +#ifdef IMAP_STORAGE +static void imap_logout(const char *mailbox_id) +{ + char *context; + char *mailbox; + struct ast_vm_user vmus; + RAII_VAR(struct ast_vm_user *, vmu, NULL, free_user); + struct vm_state *vms = NULL; + + if (ast_strlen_zero(mailbox_id) + || separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) { + return; + } + + memset(&vmus, 0, sizeof(vmus)); + + if (!(vmu = find_user(&vmus, context, mailbox)) || vmu->imapuser[0] == '\0') { + return; + } + + vms = get_vm_state_by_imapuser(vmu->imapuser, 0); + if (!vms) { + vms = get_vm_state_by_mailbox(mailbox, context, 0); + } + if (!vms) { + return; + } + + vms->mailstream = mail_close(vms->mailstream); + vmstate_delete(vms); +} + +#endif + static int handle_unsubscribe(void *datap) { struct mwi_sub *mwi_sub; @@ -13117,6 +13151,9 @@ static int handle_unsubscribe(void *datap) AST_LIST_REMOVE_CURRENT(entry); /* Don't break here since a duplicate uniqueid * may have been added as a result of a cache dump. */ +#ifdef IMAP_STORAGE + imap_logout(mwi_sub->mailbox); +#endif mwi_sub_destroy(mwi_sub); } } From b8b0b61a245eab59dafe05a7475e2c3b69d8d6d5 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 14 Jun 2017 12:34:06 -0500 Subject: [PATCH 1312/1578] app_voicemail.c: Fix compile error when IMAP enabled. Change-Id: I2703f15b4099b4210c68eccf293105d1975c1fc1 --- apps/app_voicemail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 06f4830faec..1247bde9598 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -2730,7 +2730,7 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char } if (fread(buf, 1, len, p) != len) { if (ferror(p)) { - ast_log(LOG_ERROR, "Error while reading mail file: %s\n"); + ast_log(LOG_ERROR, "Error while reading mail file: %s\n", tmp); return -1; } } From bd16c3c524f7afa79a530fe5000f7054c22dd5f4 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 15 Jun 2017 12:32:32 +0000 Subject: [PATCH 1313/1578] channel: Fix reference counting in ast_channel_suppress. The ast_channel_suppress function wrongly decremented the reference count of the underlying structure used to keep track of what should be suppressed on a channel if the function was called multiple times on the same channel. This change cleans up the reference counting a bit so this no longer occurs. ASTERISK-27016 Change-Id: I2eed4077cb4916e6626f9f120b63b963acc5c136 --- main/channel.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/channel.c b/main/channel.c index 58f960aafc6..1ca485e7ad1 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10744,7 +10744,7 @@ static const struct ast_datastore_info *suppress_get_datastore_information(enum int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum ast_frame_type frametype) { - RAII_VAR(struct suppress_data *, suppress, NULL, ao2_cleanup); + struct suppress_data *suppress; const struct ast_datastore_info *datastore_info = NULL; struct ast_datastore *datastore = NULL; struct ast_framehook_interface interface = { @@ -10780,6 +10780,7 @@ int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum if (framehook_id < 0) { /* Hook attach failed. Get rid of the evidence. */ ast_log(LOG_WARNING, "Failed to attach framehook while attempting to suppress a stream.\n"); + ao2_ref(suppress, -1); return -1; } @@ -10791,11 +10792,11 @@ int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum if (!(datastore = ast_datastore_alloc(datastore_info, NULL))) { ast_log(LOG_WARNING, "Failed to allocate datastore while attempting to suppress a stream.\n"); ast_framehook_detach(chan, framehook_id); + ao2_ref(suppress, -1); return -1; } - /* and another ref for the datastore */ - ao2_ref(suppress, +1); + /* the ref provided by the allocation is taken by the datastore */ datastore->data = suppress; ast_channel_datastore_add(chan, datastore); From 4797a8bb810c7b7c5445f49f367e3f054797fd7c Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 14 Jun 2017 13:07:17 -0500 Subject: [PATCH 1314/1578] stream: Ignore declined streams for some topology calls. * Made ast_format_cap_from_stream_topology() not include any formats from declined streams. * Made ast_stream_topology_get_first_stream_by_type() ignore declined streams to return the first active stream of the type. * Updated unit tests to check these changes have the expected effect. Change-Id: Iabbc6a3e8edf263a25fd3056c3c614407c7897df --- include/asterisk/stream.h | 9 +++-- main/stream.c | 12 ++++-- tests/test_stream.c | 85 ++++++++++++++++++++++++++++++++++----- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 14d624fb228..00169a3f1f6 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -401,8 +401,11 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_format_cap *cap); /*! - * \brief A helper function that, given a stream topology, creates a format - * capabilities structure containing all formats from all streams. + * \brief Create a format capabilities structure representing the topology. + * + * \details + * A helper function that, given a stream topology, creates a format + * capabilities structure containing all formats from all active streams. * * \param topology The topology of streams * @@ -417,7 +420,7 @@ struct ast_format_cap *ast_format_cap_from_stream_topology( struct ast_stream_topology *topology); /*! - * \brief Gets the first stream of a specific type from the topology + * \brief Gets the first active stream of a specific type from the topology * * \param topology The topology of streams * \param type The media type diff --git a/main/stream.c b/main/stream.c index b6177447435..20179f33133 100644 --- a/main/stream.c +++ b/main/stream.c @@ -437,9 +437,11 @@ struct ast_format_cap *ast_format_cap_from_stream_topology( } for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { - struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i); + struct ast_stream *stream; - if (!stream->formats) { + stream = AST_VECTOR_GET(&topology->streams, i); + if (!stream->formats + || stream->state == AST_STREAM_STATE_REMOVED) { continue; } @@ -458,9 +460,11 @@ struct ast_stream *ast_stream_topology_get_first_stream_by_type( ast_assert(topology != NULL); for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { - struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i); + struct ast_stream *stream; - if (stream->type == type) { + stream = AST_VECTOR_GET(&topology->streams, i); + if (stream->type == type + && stream->state != AST_STREAM_STATE_REMOVED) { return stream; } } diff --git a/tests/test_stream.c b/tests/test_stream.c index cf3d2e3658b..fdb9885849e 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -755,7 +755,12 @@ AST_TEST_DEFINE(stream_topology_create_from_format_cap) AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) { RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); - struct ast_stream *first_stream, *second_stream, *third_stream, *fourth_stream; + struct ast_stream *first_stream; + struct ast_stream *second_stream; + struct ast_stream *third_stream; + struct ast_stream *fourth_stream; + struct ast_stream *fifth_stream; + struct ast_stream *sixth_stream; switch (cmd) { case TEST_INIT: @@ -780,6 +785,7 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); return AST_TEST_FAIL; } + ast_stream_set_state(first_stream, AST_STREAM_STATE_REMOVED); if (ast_stream_topology_append_stream(topology, first_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); @@ -799,9 +805,9 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) return AST_TEST_FAIL; } - third_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); + third_stream = ast_stream_alloc("audio3", AST_MEDIA_TYPE_AUDIO); if (!third_stream) { - ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); + ast_test_status_update(test, "Failed to create a third audio stream for testing stream topology\n"); return AST_TEST_FAIL; } @@ -811,11 +817,12 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) return AST_TEST_FAIL; } - fourth_stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO); + fourth_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); if (!fourth_stream) { - ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n"); + ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); return AST_TEST_FAIL; } + ast_stream_set_state(fourth_stream, AST_STREAM_STATE_REMOVED); if (ast_stream_topology_append_stream(topology, fourth_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); @@ -823,12 +830,36 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) return AST_TEST_FAIL; } - if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_AUDIO) != first_stream) { + fifth_stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO); + if (!fifth_stream) { + ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, fifth_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(fifth_stream); + return AST_TEST_FAIL; + } + + sixth_stream = ast_stream_alloc("video3", AST_MEDIA_TYPE_VIDEO); + if (!sixth_stream) { + ast_test_status_update(test, "Failed to create a third video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, sixth_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(sixth_stream); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_AUDIO) != second_stream) { ast_test_status_update(test, "Retrieved first audio stream from topology but it is not the correct one\n"); return AST_TEST_FAIL; } - if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_VIDEO) != third_stream) { + if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_VIDEO) != fifth_stream) { ast_test_status_update(test, "Retrieved first video stream from topology but it is not the correct one\n"); return AST_TEST_FAIL; } @@ -1918,6 +1949,8 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, stream_caps, NULL, ao2_cleanup); struct ast_stream_topology *topology; + struct ast_stream *stream; + struct ast_format_cap *new_cap; switch (cmd) { case TEST_INIT: @@ -1938,12 +1971,12 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) } if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { - ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n"); + ast_test_status_update(test, "Failed to append ulaw format to capabilities\n"); return AST_TEST_FAIL; } if (ast_format_cap_append(caps, ast_format_h264, 0)) { - ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n"); + ast_test_status_update(test, "Failed to append h264 format to capabilities\n"); return AST_TEST_FAIL; } @@ -1953,6 +1986,40 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) return AST_TEST_FAIL; } + /* + * Append declined stream with formats that should not be included + * in combined topology caps. + */ + stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!new_cap) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + ast_stream_free(stream); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + if (ast_format_cap_append(new_cap, ast_format_alaw, 0)) { + ast_test_status_update(test, "Failed to append alaw format to capabilities\n"); + ao2_cleanup(new_cap); + ast_stream_free(stream); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + ast_stream_set_formats(stream, new_cap); + ao2_cleanup(new_cap); + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(stream); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + stream_caps = ast_format_cap_from_stream_topology(topology); if (!stream_caps) { ast_test_status_update(test, "Failed to create a format capabilities from a stream topology\n"); From 0fdb99c268d13e51bc271fe24c691f61f03b9578 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 11 May 2017 14:09:06 -0500 Subject: [PATCH 1315/1578] SDP: Add t= line in sdp_create_from_state() Change-Id: I4060391328a893101ed87d0d9bacbbab4fd8b141 --- main/sdp_state.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/main/sdp_state.c b/main/sdp_state.c index 00f147f474e..a5f116706bb 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -1734,13 +1734,16 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta if (!c_line) { goto error; } - s_line = ast_sdp_s_alloc(options->sdpsession); if (!s_line) { goto error; } + t_line = ast_sdp_t_alloc(0, 0); + if (!t_line) { + goto error; + } - sdp = ast_sdp_alloc(o_line, c_line, s_line, NULL); + sdp = ast_sdp_alloc(o_line, c_line, s_line, t_line); if (!sdp) { goto error; } From 06265b8c8a7e38707c76b5ca257882223797e612 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 9 Jun 2017 19:03:05 -0500 Subject: [PATCH 1316/1578] stream: Add ast_stream_topology_del_stream() and unit test. Change-Id: If07e3c716a2e3ff85ae905c17572ea6ec3cdc1f9 --- include/asterisk/stream.h | 19 +++++ main/stream.c | 23 ++++++ tests/test_stream.c | 142 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index fcee3e47b9b..14d624fb228 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -358,6 +358,25 @@ struct ast_stream *ast_stream_topology_get_stream( int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream); +/*! + * \brief Delete a specified stream from the given topology. + * \since 15.0.0 + * + * \param topology The topology of streams. + * \param position The topology position to delete. + * + * \note Deleting a stream will completely remove it from the topology + * as if it never existed in it. i.e., Any following stream positions + * will shift down so there is no gap. + * + * \retval 0 on success. + * \retval -1 on failure. + * + * \return Nothing + */ +int ast_stream_topology_del_stream(struct ast_stream_topology *topology, + unsigned int position); + /*! * \brief A helper function that, given a format capabilities structure, * creates a topology and separates the media types in format_cap into diff --git a/main/stream.c b/main/stream.c index fb146931da9..b6177447435 100644 --- a/main/stream.c +++ b/main/stream.c @@ -349,6 +349,29 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, return AST_VECTOR_REPLACE(&topology->streams, position, stream); } +int ast_stream_topology_del_stream(struct ast_stream_topology *topology, + unsigned int position) +{ + struct ast_stream *stream; + + ast_assert(topology != NULL); + + if (AST_VECTOR_SIZE(&topology->streams) <= position) { + return -1; + } + + stream = AST_VECTOR_REMOVE_ORDERED(&topology->streams, position); + ast_stream_free(stream); + + /* Fix up higher stream position indices */ + for (; position < AST_VECTOR_SIZE(&topology->streams); ++position) { + stream = AST_VECTOR_GET(&topology->streams, position); + stream->position = position; + } + + return 0; +} + struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_format_cap *cap) { diff --git a/tests/test_stream.c b/tests/test_stream.c index a2a97018109..cf3d2e3658b 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -529,6 +529,146 @@ AST_TEST_DEFINE(stream_topology_set_stream) return AST_TEST_PASS; } +static int check_stream_positions(struct ast_test *test, const struct ast_stream_topology *topology) +{ + const struct ast_stream *stream; + int idx; + int pos; + enum ast_media_type type; + + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) { + stream = ast_stream_topology_get_stream(topology, idx); + pos = ast_stream_get_position(stream); + if (idx != pos) { + type = ast_stream_get_type(stream); + ast_test_status_update(test, "Failed: '%s' stream says it is at position %d instead of %d\n", + ast_codec_media_type2str(type), pos, idx); + return -1; + } + } + return 0; +} + +AST_TEST_DEFINE(stream_topology_del_stream) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + struct ast_stream *stream; + enum ast_media_type type; + int idx; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_del_stream"; + info->category = "/main/stream/"; + info->summary = "stream topology stream delete unit test"; + info->description = + "Test that deleting streams at a specific position in a topology works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_alloc(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + /* Create streams */ + for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) { + stream = ast_stream_alloc(ast_codec_media_type2str(type), type); + if (!stream) { + ast_test_status_update(test, "Failed to create '%s' stream for testing stream topology\n", + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append '%s' stream to topology\n", + ast_codec_media_type2str(type)); + ast_stream_free(stream); + return AST_TEST_FAIL; + } + } + + /* Check initial stream positions and types for sanity. */ + type = AST_MEDIA_TYPE_UNKNOWN; + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx, ++type) { + stream = ast_stream_topology_get_stream(topology, idx); + if (type != ast_stream_get_type(stream)) { + ast_test_status_update(test, "Initial topology types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(type), + ast_codec_media_type2str(ast_stream_get_type(stream))); + return AST_TEST_FAIL; + } + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "Initial topology positions failed.\n"); + return AST_TEST_FAIL; + } + + /* Try to delete outside of topology size */ + if (!ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology))) { + ast_test_status_update(test, "Deleting stream outside of topology succeeded!\n"); + return AST_TEST_FAIL; + } + + /* Try to delete the last topology stream */ + if (ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology) - 1)) { + ast_test_status_update(test, "Failed deleting last stream of topology.\n"); + return AST_TEST_FAIL; + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "Last stream delete topology positions failed.\n"); + return AST_TEST_FAIL; + } + stream = ast_stream_topology_get_stream(topology, ast_stream_topology_get_count(topology) - 1); + type = ast_stream_get_type(stream); + if (type != AST_MEDIA_TYPE_END - 2) { + ast_test_status_update(test, "Last stream delete types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(AST_MEDIA_TYPE_END - 2), + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + + /* Try to delete the second stream in the topology */ + if (ast_stream_topology_del_stream(topology, 1)) { + ast_test_status_update(test, "Failed deleting second stream in topology.\n"); + return AST_TEST_FAIL; + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "Second stream delete topology positions failed.\n"); + return AST_TEST_FAIL; + } + stream = ast_stream_topology_get_stream(topology, 1); + type = ast_stream_get_type(stream); + if (type != AST_MEDIA_TYPE_UNKNOWN + 2) { + ast_test_status_update(test, "Second stream delete types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2), + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + + /* Try to delete the first stream in the topology */ + if (ast_stream_topology_del_stream(topology, 0)) { + ast_test_status_update(test, "Failed deleting first stream in topology.\n"); + return AST_TEST_FAIL; + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "First stream delete topology positions failed.\n"); + return AST_TEST_FAIL; + } + stream = ast_stream_topology_get_stream(topology, 0); + type = ast_stream_get_type(stream); + if (type != AST_MEDIA_TYPE_UNKNOWN + 2) { + ast_test_status_update(test, "First stream delete types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2), + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + AST_TEST_DEFINE(stream_topology_create_from_format_cap) { RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); @@ -1933,6 +2073,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_clone); AST_TEST_UNREGISTER(stream_topology_append_stream); AST_TEST_UNREGISTER(stream_topology_set_stream); + AST_TEST_UNREGISTER(stream_topology_del_stream); AST_TEST_UNREGISTER(stream_topology_create_from_format_cap); AST_TEST_UNREGISTER(stream_topology_get_first_stream_by_type); AST_TEST_UNREGISTER(stream_topology_create_from_channel_nativeformats); @@ -1961,6 +2102,7 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_clone); AST_TEST_REGISTER(stream_topology_append_stream); AST_TEST_REGISTER(stream_topology_set_stream); + AST_TEST_REGISTER(stream_topology_del_stream); AST_TEST_REGISTER(stream_topology_create_from_format_cap); AST_TEST_REGISTER(stream_topology_get_first_stream_by_type); AST_TEST_REGISTER(stream_topology_create_from_channel_nativeformats); From a95584d07999035de85da3a84a422bb3c6475122 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 11 May 2017 18:46:52 -0500 Subject: [PATCH 1317/1578] SDP: Set the remote c= line in RTP instance. Change-Id: I23b646392082deab65bedeb19b12dcbcb9216d0c --- include/asterisk/sdp_state.h | 4 ++++ main/sdp_state.c | 38 ++++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index c2122fbce5a..b8209e1d557 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -146,6 +146,10 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state); * \param sdp_state * \param sdp * + * \note It is assumed that the passed in SDP has been checked for sanity + * already. e.g., There are no syntax errors, a c= line is reachable for + * each m= line, etc... + * * \retval 0 Success * \retval non-0 Failure * diff --git a/main/sdp_state.c b/main/sdp_state.c index a5f116706bb..f27da211bf4 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -997,11 +997,32 @@ static void update_rtp_after_merge(const struct ast_sdp_state *state, const struct ast_sdp *remote_sdp, const struct ast_sdp_m_line *remote_m_line) { + struct ast_sdp_c_line *c_line; + struct ast_sockaddr *addrs; + if (!rtp) { /* This is a dummy stream */ return; } + c_line = remote_m_line->c_line; + if (!c_line) { + c_line = remote_sdp->c_line; + } + /* + * There must be a c= line somewhere but that would be an error by + * the far end that should have been caught by a validation check + * before we processed the SDP. + */ + ast_assert(c_line != NULL); + + if (ast_sockaddr_resolve(&addrs, c_line->address, PARSE_PORT_FORBID, AST_AF_UNSPEC) > 0) { + /* Apply connection information to the RTP instance */ + ast_sockaddr_set_port(addrs, remote_m_line->port); + ast_rtp_instance_set_remote_address(rtp->instance, addrs); + ast_free(addrs); + } + if (ast_sdp_options_get_rtcp_mux(options) && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1)) { ast_rtp_instance_set_prop(rtp->instance, AST_RTP_PROPERTY_RTCP, @@ -1011,9 +1032,7 @@ static void update_rtp_after_merge(const struct ast_sdp_state *state, AST_RTP_INSTANCE_RTCP_STANDARD); } - if (ast_sdp_options_get_ice(options) == AST_SDP_ICE_ENABLED_STANDARD) { - update_ice(state, rtp->instance, options, remote_sdp, remote_m_line); - } + update_ice(state, rtp->instance, options, remote_sdp, remote_m_line); } /*! @@ -1066,12 +1085,19 @@ static void update_udptl_after_merge(const struct ast_sdp_state *state, struct s } } - c_line = remote_sdp->c_line; - if (remote_m_line->c_line) { - c_line = remote_m_line->c_line; + c_line = remote_m_line->c_line; + if (!c_line) { + c_line = remote_sdp->c_line; } + /* + * There must be a c= line somewhere but that would be an error by + * the far end that should have been caught by a validation check + * before we processed the SDP. + */ + ast_assert(c_line != NULL); if (ast_sockaddr_resolve(&addrs, c_line->address, PARSE_PORT_FORBID, AST_AF_UNSPEC) > 0) { + /* Apply connection information to the UDPTL instance */ ast_sockaddr_set_port(addrs, remote_m_line->port); ast_udptl_set_peer(udptl->instance, addrs); ast_free(addrs); From 716abaf33dc13c41d95629f853a0850c9ef3e8ce Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 11 May 2017 18:49:09 -0500 Subject: [PATCH 1318/1578] SDP: Search for the ice-lite attribute in the right place. * Pulled finding the rtcp-mux attribute flag out of the ICE candidate for loop. Also ordered the RTCP ICE candidate skip test to fail earlier. Change-Id: I8905d9c68563027a46cd3ae14dbcc27e9c814809 --- main/sdp_state.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/main/sdp_state.c b/main/sdp_state.c index f27da211bf4..0f06bf9e303 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -875,6 +875,7 @@ static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instanc { struct ast_rtp_engine_ice *ice; const struct ast_sdp_a_line *attr; + const struct ast_sdp_a_line *attr_rtcp_mux; unsigned int attr_i; /* If ICE support is not enabled or available exit early */ @@ -902,10 +903,12 @@ static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instanc return; } - if (ast_sdp_m_find_attribute(remote_m_line, "ice-lite", -1)) { + if (ast_sdp_find_attribute(remote_sdp, "ice-lite", -1)) { ice->ice_lite(rtp); } + attr_rtcp_mux = ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1); + /* Find all of the candidates */ for (attr_i = 0; attr_i < ast_sdp_m_get_a_count(remote_m_line); ++attr_i) { char foundation[32]; @@ -931,9 +934,9 @@ static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instanc continue; } - if (ast_sdp_options_get_rtcp_mux(options) - && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1) - && candidate.id > 1) { + if (candidate.id > 1 + && attr_rtcp_mux + && ast_sdp_options_get_rtcp_mux(options)) { /* Remote side may have offered RTP and RTCP candidates. However, if we're using RTCP MUX, * then we should ignore RTCP candidates. */ From e563a1920e35b3986462dceadde5e162628adeb6 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 8 Jun 2017 11:38:33 -0500 Subject: [PATCH 1319/1578] SDP: Add get/set option calls for RTP sched context per type. Change-Id: I82dc75c63c48904e9e5a49e2205dcc06e88487e4 --- include/asterisk/sdp_options.h | 25 +++++++++++++++++++++++++ main/sdp_options.c | 33 +++++++++++++++++++++++++++++++++ main/sdp_private.h | 2 ++ main/sdp_state.c | 9 ++------- 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index f49b79483bd..b8c1bbd56eb 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -522,4 +522,29 @@ void ast_sdp_options_set_ssrc(struct ast_sdp_options *options, unsigned int ssrc */ unsigned int ast_sdp_options_get_ssrc(const struct ast_sdp_options *options); +/*! + * \brief Set the SDP options scheduler context used to create new streams of the type. + * \since 15.0.0 + * + * \param options SDP Options + * \param type Media type the scheduler context is for. + * \param sched Scheduler context to use for the specified media type. + * + * \return Nothing + */ +void ast_sdp_options_set_sched_type(struct ast_sdp_options *options, + enum ast_media_type type, struct ast_sched_context *sched); + +/*! + * \brief Get the SDP options scheduler context used to create new streams of the type. + * \since 15.0.0 + * + * \param options SDP Options + * \param type Media type the format cap represents. + * + * \return The stored scheduler context to create new streams of the type. + */ +struct ast_sched_context *ast_sdp_options_get_sched_type(const struct ast_sdp_options *options, + enum ast_media_type type); + #endif /* _ASTERISK_SDP_OPTIONS_H */ diff --git a/main/sdp_options.c b/main/sdp_options.c index ab8fb297397..a938583c683 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -77,6 +77,39 @@ DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_impl, impl); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_encryption, encryption); DEFINE_GETTERS_SETTERS_FOR(unsigned int, ssrc); +struct ast_sched_context *ast_sdp_options_get_sched_type(const struct ast_sdp_options *options, enum ast_media_type type) +{ + struct ast_sched_context *sched = NULL; + + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + case AST_MEDIA_TYPE_IMAGE: + case AST_MEDIA_TYPE_TEXT: + sched = options->sched[type]; + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_END: + break; + } + return sched; +} + +void ast_sdp_options_set_sched_type(struct ast_sdp_options *options, enum ast_media_type type, struct ast_sched_context *sched) +{ + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + case AST_MEDIA_TYPE_IMAGE: + case AST_MEDIA_TYPE_TEXT: + options->sched[type] = sched; + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_END: + break; + } +} + static void set_defaults(struct ast_sdp_options *options) { options->dtmf = DEFAULT_DTMF; diff --git a/main/sdp_private.h b/main/sdp_private.h index a0b63df032d..62228a5c89e 100644 --- a/main/sdp_private.h +++ b/main/sdp_private.h @@ -35,6 +35,8 @@ struct ast_sdp_options { /*! RTP Engine Name */ AST_STRING_FIELD(rtp_engine); ); + /*! Scheduler context for the media stream types (Mainly for RTP) */ + struct ast_sched_context *sched[AST_MEDIA_TYPE_END]; struct { unsigned int rtp_symmetric:1; unsigned int udptl_symmetric:1; diff --git a/main/sdp_state.c b/main/sdp_state.c index 0f06bf9e303..99421ad4da7 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -151,12 +151,6 @@ static void sdp_state_capabilities_free(struct sdp_state_capabilities *capabilit ast_free(capabilities); } -/* TODO - * This isn't set anywhere yet. - */ -/*! \brief Scheduler for RTCP purposes */ -static struct ast_sched_context *sched; - /*! \brief Internal function which creates an RTP instance */ static struct sdp_state_rtp *create_rtp(const struct ast_sdp_options *options, enum ast_media_type media_type) @@ -185,7 +179,8 @@ static struct sdp_state_rtp *create_rtp(const struct ast_sdp_options *options, return NULL; } - rtp->instance = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL); + rtp->instance = ast_rtp_instance_new(options->rtp_engine, + ast_sdp_options_get_sched_type(options, media_type), media_address, NULL); if (!rtp->instance) { ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", options->rtp_engine); From 11ec2945c7a8f43cdc71c58ccf76846e34150830 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 15 Jun 2017 12:33:22 -0500 Subject: [PATCH 1320/1578] chan_pjsip: Fix PJSIP_MEDIA_OFFER dialplan function read. The construction of the returned string assumed incorrectly that the supplied buffer would always be initialized as an empty string. If it is not an empty string we could overrun the supplied buffer by the length of the non-empty buffer string plus one. It is also theoreticaly possible for the supplied buffer to be overrun by a string terminator during a read operation even if the supplied buffer is an empty string. * Fix the assumption that the supplied buffer would already be an empty string. The buffer is not guaranteed to contain an empty string by all possible callers. * Fix string terminator buffer overrun potential. Change-Id: If6a0806806527678c8554b1dcb34fd7808aa95c9 --- channels/pjsip/dialplan_functions.c | 35 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 7b3434d408f..e2c78cd87b4 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -927,36 +927,40 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char static int media_offer_read_av(struct ast_sip_session *session, char *buf, size_t len, enum ast_media_type media_type) { - int i, size = 0; + int idx; + size_t accum = 0; - for (i = 0; i < ast_format_cap_count(session->req_caps); i++) { - struct ast_format *fmt = ast_format_cap_get_format(session->req_caps, i); + /* Note: buf is not terminated while the string is being built. */ + for (idx = 0; idx < ast_format_cap_count(session->req_caps); ++idx) { + struct ast_format *fmt; + size_t size; + fmt = ast_format_cap_get_format(session->req_caps, idx); if (ast_format_get_type(fmt) != media_type) { ao2_ref(fmt, -1); continue; } - /* add one since we'll include a comma */ + /* Add one for a comma or terminator */ size = strlen(ast_format_get_name(fmt)) + 1; if (len < size) { ao2_ref(fmt, -1); break; } - len -= size; - - /* no reason to use strncat here since we have already ensured buf has - enough space, so strcat can be safely used */ - strcat(buf, ast_format_get_name(fmt)); - strcat(buf, ","); + /* Append the format name */ + strcpy(buf + accum, ast_format_get_name(fmt));/* Safe */ ao2_ref(fmt, -1); - } - if (size) { - /* remove the extra comma */ - buf[strlen(buf) - 1] = '\0'; + accum += size; + len -= size; + + /* The last comma on the built string will be set to the terminator. */ + buf[accum - 1] = ','; } + + /* Remove the trailing comma or terminate an empty buffer. */ + buf[accum ? accum - 1 : 0] = '\0'; return 0; } @@ -996,6 +1000,9 @@ int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char * return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_AUDIO); } else if (!strcmp(data, "video")) { return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_VIDEO); + } else { + /* Ensure that the buffer is empty */ + buf[0] = '\0'; } return 0; From 1ac009651265460a3093671de1b33dc4ad6eda0b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 13 Jun 2017 10:33:34 -0600 Subject: [PATCH 1321/1578] res_ari: Add "module loaded" check to ari stubs The recent change to make the use of LOAD_DECLINE more consistent caused res_ari to unload itself before declining if the ari.conf file wasn't found. The ari stubs though still tried to use the configuration resulting in segfaults. This patch creates a new CHECK_ARI_MODULE_LOADED macro which tests to see if res_ari is actually loaded and causes the stubs to also decline if it isn't. The macro was then added to the mustache template's "load_module" function. ASTERISK-27026 #close Reported-by: Ronald Raikes Change-Id: I263d56efa628ee3c411bdcd16d49af6260c6c91d --- include/asterisk/ari.h | 10 +++++ res/res_ari_applications.c | 4 ++ res/res_ari_asterisk.c | 4 ++ res/res_ari_bridges.c | 4 ++ res/res_ari_channels.c | 4 ++ res/res_ari_device_states.c | 4 ++ res/res_ari_endpoints.c | 4 ++ res/res_ari_events.c | 43 ++++++++++-------- res/res_ari_mailboxes.c | 4 ++ res/res_ari_playbacks.c | 4 ++ res/res_ari_recordings.c | 4 ++ res/res_ari_sounds.c | 4 ++ .../res_ari_resource.c.mustache | 45 +++++++++++-------- 13 files changed, 101 insertions(+), 37 deletions(-) diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h index 865b4b00cc5..f83d5963f32 100644 --- a/include/asterisk/ari.h +++ b/include/asterisk/ari.h @@ -268,4 +268,14 @@ void ast_ari_response_created(struct ast_ari_response *response, */ void ast_ari_response_alloc_failed(struct ast_ari_response *response); +/*! \brief Determines whether the res_ari module is loaded */ +#define CHECK_ARI_MODULE_LOADED() \ + do { \ + if (!ast_module_check("res_ari.so") \ + || !ast_ari_oom_json()) { \ + return AST_MODULE_LOAD_DECLINE; \ + } \ + } while(0) + + #endif /* _ASTERISK_ARI_H */ diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c index 21d9f56eb00..cf700c464e0 100644 --- a/res/res_ari_applications.c +++ b/res/res_ari_applications.c @@ -500,6 +500,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&applications); if (res) { diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index 89517ccae0c..eb0617b4c70 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -1221,6 +1221,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&asterisk); if (res) { diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 5402c2b995e..65bf7ed3e73 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -1547,6 +1547,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&bridges); if (res) { diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index 9d218e2beef..f6befcc90d4 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -2851,6 +2851,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&channels); if (res) { diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c index d6de5dff869..f3939356265 100644 --- a/res/res_ari_device_states.c +++ b/res/res_ari_device_states.c @@ -331,6 +331,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&deviceStates); if (res) { diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index d96de0877bf..d1242c0fbc0 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -455,6 +455,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&endpoints); if (res) { diff --git a/res/res_ari_events.c b/res/res_ari_events.c index 3f5b89a440e..f916d0e4eed 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -430,28 +430,35 @@ static int unload_module(void) static int load_module(void) { int res = 0; - struct ast_websocket_protocol *protocol; - if (ast_ari_websocket_events_event_websocket_init() == -1) { - return AST_MODULE_LOAD_DECLINE; - } + CHECK_ARI_MODULE_LOADED(); - events.ws_server = ast_websocket_server_create(); - if (!events.ws_server) { - ast_ari_websocket_events_event_websocket_dtor(); - return AST_MODULE_LOAD_DECLINE; - } + /* This is scoped to not conflict with CHECK_ARI_MODULE_LOADED */ + { + struct ast_websocket_protocol *protocol; - protocol = ast_websocket_sub_protocol_alloc("ari"); - if (!protocol) { - ao2_ref(events.ws_server, -1); - events.ws_server = NULL; - ast_ari_websocket_events_event_websocket_dtor(); - return AST_MODULE_LOAD_DECLINE; + if (ast_ari_websocket_events_event_websocket_init() == -1) { + return AST_MODULE_LOAD_DECLINE; + } + + events.ws_server = ast_websocket_server_create(); + if (!events.ws_server) { + ast_ari_websocket_events_event_websocket_dtor(); + return AST_MODULE_LOAD_DECLINE; + } + + protocol = ast_websocket_sub_protocol_alloc("ari"); + if (!protocol) { + ao2_ref(events.ws_server, -1); + events.ws_server = NULL; + ast_ari_websocket_events_event_websocket_dtor(); + return AST_MODULE_LOAD_DECLINE; + } + protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb; + protocol->session_established = ast_ari_events_event_websocket_ws_established_cb; + res |= ast_websocket_server_add_protocol2(events.ws_server, protocol); } - protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb; - protocol->session_established = ast_ari_events_event_websocket_ws_established_cb; - res |= ast_websocket_server_add_protocol2(events.ws_server, protocol); + stasis_app_ref(); res |= ast_ari_add_handler(&events); if (res) { diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c index 12c33cd8847..1f6d2cc81b9 100644 --- a/res/res_ari_mailboxes.c +++ b/res/res_ari_mailboxes.c @@ -337,6 +337,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&mailboxes); if (res) { diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c index e2c432db031..40099cfb488 100644 --- a/res/res_ari_playbacks.c +++ b/res/res_ari_playbacks.c @@ -289,6 +289,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&playbacks); if (res) { diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index 57d80f2e0fe..fe3d343ee2a 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -873,6 +873,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&recordings); if (res) { diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index fded7fbced5..8d5928a504b 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -219,6 +219,10 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + + stasis_app_ref(); res |= ast_ari_add_handler(&sounds); if (res) { diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache index 3ccafcd082b..d4ccda9e8ea 100644 --- a/rest-api-templates/res_ari_resource.c.mustache +++ b/rest-api-templates/res_ari_resource.c.mustache @@ -273,36 +273,43 @@ static int unload_module(void) static int load_module(void) { int res = 0; + + CHECK_ARI_MODULE_LOADED(); + {{#apis}} {{#operations}} {{#has_websocket}} - struct ast_websocket_protocol *protocol; + /* This is scoped to not conflict with CHECK_ARI_MODULE_LOADED */ + { + struct ast_websocket_protocol *protocol; - if (ast_ari_websocket_{{c_name}}_{{c_nickname}}_init() == -1) { - return AST_MODULE_LOAD_DECLINE; - } + if (ast_ari_websocket_{{c_name}}_{{c_nickname}}_init() == -1) { + return AST_MODULE_LOAD_DECLINE; + } - {{full_name}}.ws_server = ast_websocket_server_create(); - if (!{{full_name}}.ws_server) { - ast_ari_websocket_events_event_websocket_dtor(); - return AST_MODULE_LOAD_DECLINE; - } + {{full_name}}.ws_server = ast_websocket_server_create(); + if (!{{full_name}}.ws_server) { + ast_ari_websocket_events_event_websocket_dtor(); + return AST_MODULE_LOAD_DECLINE; + } - protocol = ast_websocket_sub_protocol_alloc("{{websocket_protocol}}"); - if (!protocol) { - ao2_ref({{full_name}}.ws_server, -1); - {{full_name}}.ws_server = NULL; - ast_ari_websocket_events_event_websocket_dtor(); - return AST_MODULE_LOAD_DECLINE; - } - protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb; - protocol->session_established = ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb; + protocol = ast_websocket_sub_protocol_alloc("{{websocket_protocol}}"); + if (!protocol) { + ao2_ref({{full_name}}.ws_server, -1); + {{full_name}}.ws_server = NULL; + ast_ari_websocket_events_event_websocket_dtor(); + return AST_MODULE_LOAD_DECLINE; + } + protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb; + protocol->session_established = ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb; {{/has_websocket}} {{#is_websocket}} - res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol); + res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol); + } {{/is_websocket}} {{/operations}} {{/apis}} + stasis_app_ref(); res |= ast_ari_add_handler(&{{root_full_name}}); if (res) { From 9aeab4aced35f668149aa083a96928766f645f23 Mon Sep 17 00:00:00 2001 From: Jan Friesse Date: Thu, 30 Mar 2017 16:33:51 +0200 Subject: [PATCH 1322/1578] res_corosync: Change thread stack size In Corosync 2.x libraries were changed to use LibQB IPC. Sadly LibQB IPC doesn't support copy-free access to received buffer, so Corosync libraries were rewritten to use stack as buffer. Mostly the needed stack size is quite small, but for all *_dispatch functions, 1MiB is needed. Asterisk function ast_pthread_create_background set stack size for new thread to much smaller AST_BACKGROUND_STACKSIZE (~500KiB). This results in Asterisk crash when running with Corosync 2.x. Patch solves this issue by creating it's own version of ast_pthread_create_background which sets stack size to much higher value (actually it's AST_BACKGROUND_STACKSIZE + 3MiB). Another problem may appear when "corosync show members" netconsole command is executed. It is also executed in thread and also has only 500KiB stack size. Sadly it calls corosync_cfg_get_node_addrs which again needs at least 1MiB stack. Solution is to use HAVE_COROSYNC_CFG_STATE_TRACK as a discriminator between Corosync 1.x and 2.x. If 1.x is found, nothing changes. If 2.x is found, NodeID is displayed instead of IP address. ASTERISK-25370 #close Reported by: mdu113 Change-Id: Id95b0d21ab6e708e7d74ad8786c587211676fa08 --- res/res_corosync.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/res/res_corosync.c b/res/res_corosync.c index 79cd810cef4..0d91b1860ac 100644 --- a/res/res_corosync.c +++ b/res/res_corosync.c @@ -77,6 +77,15 @@ struct corosync_node { struct ast_sockaddr addr; }; +/*! \brief Corosync ipc dispatch/request and reply size */ +#define COROSYNC_IPC_BUFFER_SIZE (8192 * 128) + +/*! \brief Version of pthread_create to ensure stack is large enough */ +#define corosync_pthread_create_background(a, b, c, d) \ + ast_pthread_create_stack(a, b, c, d, \ + (AST_BACKGROUND_STACKSIZE + (3 * COROSYNC_IPC_BUFFER_SIZE)), \ + __FILE__, __FUNCTION__, __LINE__, #c) + static struct corosync_node *corosync_node_alloc(struct ast_event *event) { struct corosync_node *node; @@ -808,10 +817,21 @@ static char *corosync_show_members(struct ast_cli_entry *e, int cmd, struct ast_ for (i = 1, cs_err = cpg_iteration_next(cpg_iter, &cpg_desc); cs_err == CS_OK; cs_err = cpg_iteration_next(cpg_iter, &cpg_desc), i++) { +#ifdef HAVE_COROSYNC_CFG_STATE_TRACK corosync_cfg_node_address_t addrs[8]; int num_addrs = 0; unsigned int j; +#endif + + ast_cli(a->fd, "=== Node %u\n", i); + ast_cli(a->fd, "=== --> Group: %s\n", cpg_desc.group.value); +#ifdef HAVE_COROSYNC_CFG_STATE_TRACK + /* + * Corosync 2.x cfg lib needs to allocate 1M on stack after calling + * corosync_cfg_get_node_addrs. netconsole thread has allocated only 0.5M + * resulting in crash. + */ cs_err = corosync_cfg_get_node_addrs(cfg_handle, cpg_desc.nodeid, ARRAY_LEN(addrs), &num_addrs, addrs); if (cs_err != CS_OK) { @@ -819,9 +839,6 @@ static char *corosync_show_members(struct ast_cli_entry *e, int cmd, struct ast_ continue; } - ast_cli(a->fd, "=== Node %u\n", i); - ast_cli(a->fd, "=== --> Group: %s\n", cpg_desc.group.value); - for (j = 0; j < num_addrs; j++) { struct sockaddr *sa = (struct sockaddr *) addrs[j].address; size_t sa_len = (size_t) addrs[j].address_length; @@ -831,7 +848,9 @@ static char *corosync_show_members(struct ast_cli_entry *e, int cmd, struct ast_ ast_cli(a->fd, "=== --> Address %u: %s\n", j + 1, buf); } - +#else + ast_cli(a->fd, "=== --> Nodeid: %"PRIu32"\n", cpg_desc.nodeid); +#endif } ast_cli(a->fd, "===\n" @@ -1157,7 +1176,7 @@ static int load_module(void) goto failed; } - if (ast_pthread_create_background(&dispatch_thread.id, NULL, + if (corosync_pthread_create_background(&dispatch_thread.id, NULL, dispatch_thread_handler, NULL)) { ast_log(LOG_ERROR, "Error starting CPG dispatch thread.\n"); goto failed; From 53b7df82f4f56e4f8f89d2fb703a22fda877d521 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Thu, 15 Jun 2017 14:48:13 -0400 Subject: [PATCH 1323/1578] app_voicemail: IMAP logout on reload/unload Closing IMAP connection on module reload or unload. ASTERISK-24052 #close Change-Id: I2a40182aa9ef249fa6865d33570430e9ada68525 --- apps/app_voicemail.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 8f50e1106ae..a9516801332 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -13134,10 +13134,25 @@ static void imap_logout(const char *mailbox_id) return; } + ast_mutex_lock(&vms->lock); vms->mailstream = mail_close(vms->mailstream); + ast_mutex_unlock(&vms->lock); + vmstate_delete(vms); } +static void imap_close_subscribed_mailboxes(void) +{ + struct mwi_sub *mwi_sub; + + AST_RWLIST_RDLOCK(&mwi_subs); + AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) { + if (!ast_strlen_zero(mwi_sub->mailbox)) { + imap_logout(mwi_sub->mailbox); + } + } + AST_RWLIST_UNLOCK(&mwi_subs); +} #endif static int handle_unsubscribe(void *datap) @@ -13591,7 +13606,11 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY); strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY); - /* Free all the users structure */ +#ifdef IMAP_STORAGE + imap_close_subscribed_mailboxes(); +#endif + + /* Free all the users structure */ free_vm_users(); /* Free all the zones structure */ @@ -14985,6 +15004,9 @@ static int unload_module(void) ast_unload_realtime("voicemail"); ast_unload_realtime("voicemail_data"); +#ifdef IMAP_STORAGE + imap_close_subscribed_mailboxes(); +#endif free_vm_users(); free_vm_zones(); return res; From 7a46309d3df85a893b67a8ab9aa043e0c8f53805 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 12 Jun 2017 10:23:56 -0400 Subject: [PATCH 1324/1578] res_pjsip: New endpoint option "notify_early_inuse_ringing" This option was added to control whether to notify dialog-info state 'early' or 'confirmed' on Ringing when already INUSE. The value "yes" is useful for some SIP phones (Cisco SPA) to be able to indicate and pick up ringing devices. ASTERISK-26919 #close Change-Id: Ie050bc30023543c7dfb4365c5be3ce58c738c711 --- CHANGES | 4 +++ configs/samples/pjsip.conf.sample | 5 ++++ ...96_add_ps_endpoints_notify_early_inuse_.py | 30 +++++++++++++++++++ include/asterisk/res_pjsip.h | 2 ++ include/asterisk/res_pjsip_presence_xml.h | 3 +- res/res_pjsip.c | 7 +++++ res/res_pjsip/pjsip_configuration.c | 1 + res/res_pjsip/presence_xml.c | 9 ++++-- res/res_pjsip_dialog_info_body_generator.c | 10 +++++-- res/res_pjsip_pidf_body_generator.c | 2 +- res/res_pjsip_pidf_eyebeam_body_supplement.c | 2 +- res/res_pjsip_xpidf_body_generator.c | 2 +- 12 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/d7983954dd96_add_ps_endpoints_notify_early_inuse_.py diff --git a/CHANGES b/CHANGES index 9bfa506d333..9cd579b6565 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,10 @@ res_pjsip Some SIP phones like Mitel/Aastra or Snom keep the line busy until receive "200 OK". + * A new endpoint option "notify_early_inuse_ringing" was added to control + whether to notify dialog-info state 'early' or 'confirmed' on Ringing + when already INUSE. + res_agi ------------------ * The EAGI() application will now look for a dialplan variable named diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index a992ff8b6bd..3b93bb61fc2 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -774,6 +774,11 @@ ; transfer (default: "yes"). The value "no" is useful ; for some SIP phones (Mitel/Aastra, Snom) which expect ; a sip/frag "200 OK" after REFER has been accepted. +;notify_early_inuse_ringing = ; Whether to notifies dialog-info 'early' + ; on INUSE && RINGING state (default: "no"). + ; The value "yes" is useful for some SIP phones + ; (Cisco SPA) to be able to indicate and pick up + ; ringing devices. ;==========================AUTH SECTION OPTIONS========================= ;[auth] diff --git a/contrib/ast-db-manage/config/versions/d7983954dd96_add_ps_endpoints_notify_early_inuse_.py b/contrib/ast-db-manage/config/versions/d7983954dd96_add_ps_endpoints_notify_early_inuse_.py new file mode 100644 index 00000000000..e1dcdd133b1 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/d7983954dd96_add_ps_endpoints_notify_early_inuse_.py @@ -0,0 +1,30 @@ +"""add ps_endpoints.notify_early_inuse_ringing + +Revision ID: d7983954dd96 +Revises: 86bb1efa278d +Create Date: 2017-06-05 15:44:41.152280 + +""" + +# revision identifiers, used by Alembic. +revision = 'd7983954dd96' +down_revision = '86bb1efa278d' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoints', sa.Column('notify_early_inuse_ringing', yesno_values)) + +def downgrade(): + op.drop_column('ps_endpoints', 'notify_early_inuse_ringing') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 8c589ef85ea..b9c50addad4 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -769,6 +769,8 @@ struct ast_sip_endpoint { unsigned int allow_overlap; /*! Whether to notifies all the progress details on blind transfer */ unsigned int refer_blind_progress; + /*! Whether to notifies dialog-info 'early' on INUSE && RINGING state */ + unsigned int notify_early_inuse_ringing; }; /*! URI parameter for symmetric transport */ diff --git a/include/asterisk/res_pjsip_presence_xml.h b/include/asterisk/res_pjsip_presence_xml.h index deed0901e49..55b79ad6e83 100644 --- a/include/asterisk/res_pjsip_presence_xml.h +++ b/include/asterisk/res_pjsip_presence_xml.h @@ -69,7 +69,8 @@ void ast_sip_sanitize_xml(const char *input, char *output, size_t len); * \param[out] local_state */ void ast_sip_presence_exten_state_to_str(int state, char **statestring, - char **pidfstate, char **pidfnote, enum ast_sip_pidf_state *local_state); + char **pidfstate, char **pidfnote, enum ast_sip_pidf_state *local_state, + unsigned int notify_early_inuse_ringing); /*! * \brief Create XML attribute diff --git a/res/res_pjsip.c b/res/res_pjsip.c index d994f28248b..f6d63c64007 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -971,6 +971,13 @@ will not send the progress details, but immediately will send "200 OK". + + Whether to notifies dialog-info 'early' on InUse&Ringing state + + Control whether dialog-info subscriptions get 'early' state + on Ringing when already INUSE. + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 679c8837d93..7a05f87f08c 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1940,6 +1940,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip/presence_xml.c b/res/res_pjsip/presence_xml.c index c991a0d68c9..1aca307e5a0 100644 --- a/res/res_pjsip/presence_xml.c +++ b/res/res_pjsip/presence_xml.c @@ -82,7 +82,8 @@ void ast_sip_sanitize_xml(const char *input, char *output, size_t len) } void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **pidfstate, - char **pidfnote, enum ast_sip_pidf_state *local_state) + char **pidfnote, enum ast_sip_pidf_state *local_state, + unsigned int notify_early_inuse_ringing) { switch (state) { case AST_EXTENSION_RINGING: @@ -92,7 +93,11 @@ void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **p *pidfnote = "Ringing"; break; case (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING): - *statestring = "confirmed"; + if (notify_early_inuse_ringing) { + *statestring = "early"; + } else { + *statestring = "confirmed"; + } *local_state = NOTIFY_INUSE; *pidfstate = "busy"; *pidfnote = "Ringing"; diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c index 5006b9efb4e..7c386e3b2d1 100644 --- a/res/res_pjsip_dialog_info_body_generator.c +++ b/res/res_pjsip_dialog_info_body_generator.c @@ -107,6 +107,8 @@ static int dialog_info_generate_body_content(void *body, void *data) enum ast_sip_pidf_state local_state; unsigned int version; char version_str[32], sanitized[PJSIP_MAX_URL_SIZE]; + struct ast_sip_endpoint *endpoint = NULL; + unsigned int notify_early_inuse_ringing = 0; if (!local || !state_data->datastores) { return -1; @@ -120,8 +122,12 @@ static int dialog_info_generate_body_content(void *body, void *data) stripped = ast_strip_quoted(local, "<", ">"); ast_sip_sanitize_xml(stripped, sanitized, sizeof(sanitized)); + if (state_data->sub && (endpoint = ast_sip_subscription_get_endpoint(state_data->sub))) { + notify_early_inuse_ringing = endpoint->notify_early_inuse_ringing; + ao2_cleanup(endpoint); + } ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring, - &pidfstate, &pidfnote, &local_state); + &pidfstate, &pidfnote, &local_state, notify_early_inuse_ringing); ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "xmlns", "urn:ietf:params:xml:ns:dialog-info"); @@ -133,7 +139,7 @@ static int dialog_info_generate_body_content(void *body, void *data) dialog = ast_sip_presence_xml_create_node(state_data->pool, dialog_info, "dialog"); ast_sip_presence_xml_create_attr(state_data->pool, dialog, "id", state_data->exten); - if (state_data->exten_state == AST_EXTENSION_RINGING) { + if (!ast_strlen_zero(statestring) && !strcmp(statestring, "early")) { ast_sip_presence_xml_create_attr(state_data->pool, dialog, "direction", "recipient"); } diff --git a/res/res_pjsip_pidf_body_generator.c b/res/res_pjsip_pidf_body_generator.c index 25f0639157b..cc10082ad38 100644 --- a/res/res_pjsip_pidf_body_generator.c +++ b/res/res_pjsip_pidf_body_generator.c @@ -58,7 +58,7 @@ static int pidf_generate_body_content(void *body, void *data) struct ast_sip_exten_state_data *state_data = data; ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring, - &pidfstate, &pidfnote, &local_state); + &pidfstate, &pidfnote, &local_state, 0); if (!pjpidf_pres_add_note(state_data->pool, pres, pj_cstr(¬e, pidfnote))) { ast_log(LOG_WARNING, "Unable to add note to PIDF presence\n"); diff --git a/res/res_pjsip_pidf_eyebeam_body_supplement.c b/res/res_pjsip_pidf_eyebeam_body_supplement.c index cc6dfd125c9..a0f50fddee5 100644 --- a/res/res_pjsip_pidf_eyebeam_body_supplement.c +++ b/res/res_pjsip_pidf_eyebeam_body_supplement.c @@ -80,7 +80,7 @@ static int pidf_supplement_body(void *body, void *data) enum ast_sip_pidf_state local_state; ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring, - &pidfstate, &pidfnote, &local_state); + &pidfstate, &pidfnote, &local_state, 0); add_eyebeam(state_data->pool, pres, pidfstate); return 0; diff --git a/res/res_pjsip_xpidf_body_generator.c b/res/res_pjsip_xpidf_body_generator.c index 924046549a8..41f6224d1a7 100644 --- a/res/res_pjsip_xpidf_body_generator.c +++ b/res/res_pjsip_xpidf_body_generator.c @@ -63,7 +63,7 @@ static int xpidf_generate_body_content(void *body, void *data) pj_xml_node *msnsubstatus; ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring, - &pidfstate, &pidfnote, &local_state); + &pidfstate, &pidfnote, &local_state, 0); ast_sip_presence_xml_find_node_attr(state_data->pool, pres, "atom", "id", &atom, &attr); From 0ad95bc8a048e165148c68c5bdec5555b25218a9 Mon Sep 17 00:00:00 2001 From: Frederic LE FOLL Date: Thu, 8 Jun 2017 19:28:12 +0200 Subject: [PATCH 1325/1578] Core/PBX: Deadlock between dialplan execution and application unregistration. Not easy to reproduce, but we have noticed deadlocks when unloading a module while dialplan is handling a request. The deadlock is between : 1) Dialplan execution: pbx_extension_helper() first taking conlock, then pbx_findapp() [when called] asking for lock on apps list. 2) Application unregistration: ast_unregister_application() first taking lock on apps list, then unreference_cached_app() [when called] asking for conlock. As a protection, I suggest to modify ast_unregister_application(), so that it anticipates the need of conlock, before taking the lock on apps list. The side effect is a longer unavailability of conlock when unregistering an application. ASTERISK-27041 Change-Id: I0db0f1eb320da6a5758cce3a47d765be1face8e2 --- main/pbx_app.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/main/pbx_app.c b/main/pbx_app.c index e0609db70e6..ec6bc75890a 100644 --- a/main/pbx_app.c +++ b/main/pbx_app.c @@ -394,6 +394,11 @@ int ast_unregister_application(const char *app) struct ast_app *cur; int cmp; + /* Anticipate need for conlock in unreference_cached_app(), in order to avoid + * possible deadlock with pbx_extension_helper()/pbx_findapp() + */ + ast_rdlock_contexts(); + AST_RWLIST_WRLOCK(&apps); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) { cmp = strcasecmp(app, cur->name); @@ -416,6 +421,8 @@ int ast_unregister_application(const char *app) AST_RWLIST_TRAVERSE_SAFE_END; AST_RWLIST_UNLOCK(&apps); + ast_unlock_contexts(); + return cur ? 0 : -1; } From e33bd966386eaa0669e22b9ea62f48cde5a85121 Mon Sep 17 00:00:00 2001 From: Matthew Fredrickson Date: Fri, 16 Jun 2017 14:56:37 -0500 Subject: [PATCH 1326/1578] formats/format_g729: Fix typo in comment There was a typo in a comment. This commit is to fix the typo. ASTERISK-27060 #close Change-Id: Ic2699f8dbeaacd58ccb6ec3203e853e1babe3235 --- formats/format_g729.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/formats/format_g729.c b/formats/format_g729.c index 1e523062edb..91dc855f173 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -19,7 +19,7 @@ /*! \file * * \brief Save to raw, headerless G729 data. - * \note This is not an encoder/decoder. The codec fo g729 is only + * \note This is not an encoder/decoder. The codec for g729 is only * available with a commercial license from Digium, due to patent * restrictions. Check http://www.digium.com for information. * \arg Extensions: g729 From 854a6de819b8c14b7493fde28460eb4f9fb305e3 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 16 Jun 2017 08:31:04 -0600 Subject: [PATCH 1327/1578] res_stasis: Plug reference leak on stolen channels When a stasis channel is stolen by another app, the control structure is unreffed but never unlinked from the app_controls container. This causes the channel reference to leak. Added OBJ_UNLINK to the callback in channel_stolen_cb. Also added some additional channel lifecycle debug messages to channel.c. ASTERISK-27059 #close Repoorted-by: George Joseph Change-Id: Ib820936cd49453f20156971785e7f4f182c56e14 --- main/channel.c | 9 ++++++++- res/res_stasis.c | 20 ++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/main/channel.c b/main/channel.c index 1ca485e7ad1..8b4dc75bec8 100644 --- a/main/channel.c +++ b/main/channel.c @@ -998,6 +998,9 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char * the world know of its existance */ ast_channel_stage_snapshot_done(tmp); + + ast_debug(1, "Channel %p '%s' allocated\n", tmp, ast_channel_name(tmp)); + return tmp; } @@ -2217,6 +2220,8 @@ static void ast_channel_destructor(void *obj) char device_name[AST_CHANNEL_NAME]; ast_callid callid; + ast_debug(1, "Channel %p '%s' destroying\n", chan, ast_channel_name(chan)); + /* Stop monitoring */ if (ast_channel_monitor(chan)) { ast_channel_monitor(chan)->stop(chan, 0); @@ -2579,6 +2584,9 @@ void ast_hangup(struct ast_channel *chan) return; } + ast_debug(1, "Channel %p '%s' hanging up. Refs: %d\n", chan, ast_channel_name(chan), + ao2_ref(chan, 0)); + ast_autoservice_stop(chan); ast_channel_lock(chan); @@ -2638,7 +2646,6 @@ void ast_hangup(struct ast_channel *chan) ast_assert(ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING) == 0); } - ast_debug(1, "Hanging up channel '%s'\n", ast_channel_name(chan)); if (ast_channel_tech(chan)->hangup) { ast_channel_tech(chan)->hangup(chan); } diff --git a/res/res_stasis.c b/res/res_stasis.c index 9ea0d63fea0..899c8f720a2 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -1069,8 +1069,18 @@ static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct a { struct stasis_app_control *control; - /* find control */ - control = ao2_callback(app_controls, 0, masq_match_cb, old_chan); + /* + * At this point, old_chan is the channel pointer that is in Stasis() and + * has the unknown channel's name in it while new_chan is the channel pointer + * that is not in Stasis(), but has the guts of the channel that Stasis() knows + * about. + * + * Find and unlink control since the channel has a new name/uniqueid + * and its hash has changed. Since the channel is leaving stasis don't + * bother putting it back into the container. Nobody is going to + * remove it from the container later. + */ + control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, old_chan); if (!control) { ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n"); return; @@ -1111,8 +1121,10 @@ static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct return; } - /* find, unlink, and relink control since the channel has a new name and - * its hash has likely changed */ + /* + * Find, unlink, and relink control since the channel has a new + * name/uniqueid and its hash has changed. + */ control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan); if (!control) { ast_log(LOG_ERROR, "Could not find control for masquerading channel\n"); From d7b6e06abba0d96661d93184e68b6adcdad87f87 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 12 Jun 2017 17:17:38 -0400 Subject: [PATCH 1328/1578] res_pjsip_mwi: unsubscribe unsolicited MWI on deleting endpoint last contact If the endpoint's last contact is deleted unsolicited MWI has to be unsubscribed. ASTERISK-27051 #close Change-Id: I33e174e0b9dba0998927d16d6d100fda5c7254e0 --- res/res_pjsip_mwi.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 3dfccef86bc..f73f10cd692 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -1229,10 +1229,50 @@ static void mwi_contact_added(const void *object) mwi_contact_updated(object); } +/*! \brief Function called when a contact is deleted */ +static void mwi_contact_deleted(const void *object) +{ + const struct ast_sip_contact *contact = object; + struct ao2_iterator *mwi_subs; + struct mwi_subscription *mwi_sub; + RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); + RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup); + + if (contact->endpoint) { + endpoint = ao2_bump(contact->endpoint); + } else { + if (!ast_strlen_zero(contact->endpoint_name)) { + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", contact->endpoint_name); + } + } + + if (!endpoint || ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { + return; + } + + /* Check if there is another contact */ + found_contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors); + if (found_contact) { + return; + } + + ao2_lock(unsolicited_mwi); + mwi_subs = ao2_find(unsolicited_mwi, contact->endpoint_name, + OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK); + if (mwi_subs) { + for (; (mwi_sub = ao2_iterator_next(mwi_subs)); ao2_cleanup(mwi_sub)) { + unsubscribe(mwi_sub, NULL, 0); + } + ao2_iterator_destroy(mwi_subs); + } + ao2_unlock(unsolicited_mwi); +} + /*! \brief Observer for contacts so unsolicited MWI is sent when a contact changes */ static const struct ast_sorcery_observer mwi_contact_observer = { .created = mwi_contact_added, .updated = mwi_contact_updated, + .deleted = mwi_contact_deleted, }; /*! \brief Task invoked to send initial MWI NOTIFY for unsolicited */ From a7488f8a70f76d9b1e5b2607d703c0e267a243ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Mon, 19 Jun 2017 12:28:18 -0400 Subject: [PATCH 1329/1578] cdr: fix mistake spelling of a word for Unanswered. Change-Id: I7a610bef369924523a445c7e849ee88cc45dc5df --- configs/samples/cdr.conf.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/samples/cdr.conf.sample b/configs/samples/cdr.conf.sample index e175a2a7629..1d0af78643a 100644 --- a/configs/samples/cdr.conf.sample +++ b/configs/samples/cdr.conf.sample @@ -17,7 +17,7 @@ ; party. Setting this to "yes" will make calls to extensions that don't answer ; and don't set a B side channel (such as by using the Dial application) ; receive CDR log entries. If this option is set to "no", then those log -; entries will not be created. Unasnwered Calls which get offered to an +; entries will not be created. Unanswered Calls which get offered to an ; outgoing line will always receive log entries regardless of this option, and ; that is the intended behaviour. ;unanswered = no From 70d2ccb9daa1926788b1296c6ccb2611341302d0 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sun, 18 Jun 2017 20:24:04 -0400 Subject: [PATCH 1330/1578] Core: Add support for systemd socket activation. This change adds support for socket activation of certain SOCK_STREAM listeners in Asterisk: * AMI / AMI over TLS * CLI * HTTP / HTTPS Example systemd units are provided. This support extends to any socket which is initialized using ast_tcptls_server_start, so any unknown modules using this function will support socket activation. Asterisk continues to function as normal if socket activation is not enabled or if systemd development headers are not available during build. ASTERISK-27063 #close Change-Id: Id814ee6a892f4b80d018365c8ad8d89063474f4d --- contrib/systemd/README.txt | 119 ++++++++++++++++++++++++++ contrib/systemd/asterisk-ami.socket | 10 +++ contrib/systemd/asterisk-amis.socket | 10 +++ contrib/systemd/asterisk-cli.socket | 13 +++ contrib/systemd/asterisk-http.socket | 11 +++ contrib/systemd/asterisk-https.socket | 11 +++ contrib/systemd/asterisk.service | 27 ++++++ contrib/systemd/asterisk.socket | 26 ++++++ include/asterisk/io.h | 24 ++++++ include/asterisk/netsock2.h | 16 ++++ main/asterisk.c | 29 ++++++- main/io.c | 74 ++++++++++++++++ main/tcptls.c | 17 ++++ 13 files changed, 384 insertions(+), 3 deletions(-) create mode 100644 contrib/systemd/README.txt create mode 100644 contrib/systemd/asterisk-ami.socket create mode 100644 contrib/systemd/asterisk-amis.socket create mode 100644 contrib/systemd/asterisk-cli.socket create mode 100644 contrib/systemd/asterisk-http.socket create mode 100644 contrib/systemd/asterisk-https.socket create mode 100644 contrib/systemd/asterisk.service create mode 100644 contrib/systemd/asterisk.socket diff --git a/contrib/systemd/README.txt b/contrib/systemd/README.txt new file mode 100644 index 00000000000..3225641f496 --- /dev/null +++ b/contrib/systemd/README.txt @@ -0,0 +1,119 @@ +SystemD Socket Activation for Asterisk +====================================== + +This folder contains sample unit files which can be used as the basis of a +socket activated Asterisk deployment. Socket activation support currently +extends to the following listeners: + +* Asterisk Command-line Interface +* Asterisk Manager Interface (clear text and TLS) +* Builtin HTTP / HTTPS server + +The primary use case of this feature is to allow Asterisk to be started by +other services through use of AMI, CLI or REST API. + + +Security +======== + +Care must be take if enabling socket activation on any IP:PORT that is not +protected by a firewall. Any user that can reach any socket activation +port can start Asterisk, even if they do not have valid credentials to sign +into the service in question. Enabling HTTP socket activation on a system +which provides SIP over websockets would allow remote users to start Asterisk +any time the HTTP socket is running. + +This functionality bypasses the normal restriction where only 'root' can start +a service. Enabling AMI socket activation allows any user on the local server +to start Asterisk by running 'telnet localhost 5038'. + +CLI activation is secured by the combination of SocketUser, SocketGroup and +SocketMode settings in the systemd socket. Only local users with access will +be able to start asterisk by using CLI. + + +Separate .socket units or a single unit +======================================= + +Asterisk is a complex system with many components which can be enabled or +disabled individually. Using socket activation requires deciding to use +a single socket file or multiple separate socket files. + +The remainder of this README assumes separate socket units are used for each +listener. + + +Service and Socket files +======================== + +All .socket and .service examples in this folder use "reasonable" default +paths for Linux. Depending on your distribution and ./configure options +you may need to modify these before installing. The files are meant to +be examples rather than files to be blindly installed. + + +Installing and enabling socket units +==================================== + +Modify socket files as desired. Install them to a location where systemd +will find them. pkg-config can be used to determine an appropriate location. + +For socket files to be managed directly by the local administrator: + pkg-config systemd --variable systemdsystemconfdir + +For socket files to be deployed by package manager: + pkg-config systemd --variable systemdsystemunitdir + + +After installing socket files you must run 'systemctl daemon-reload' for +systemd to read the added/modified units. After this you can enable the +desired sockets, for example to enable AMI: + systemctl enable asterisk-ami.socket + + +Socket Selection +================ + +Asterisk configuration is unchanged by use of socket activation. When a +component that supports socket activation starts a listener in Asterisk, +any sockets provided by systemd are iterated. The systemd socket is used +when the bound address configured by Asterisk is an exact match with the +address given by the ListenStream setting in the systemd socket. + + +Command-line Interface +====================== + +Symbolic links do not appear to be resolved when checking the CLI listener. +This may be of concern since /var/run is often a symbolic link to /run. Both +Asterisk and systemd must use /var/run, or both must use /run. Mismatching +will result in service startup failure. + +When socket activation is used for Asterisk CLI some asterisk.conf options +are ignored. The following options from the [files] section are ignored +and must instead be set by the systemd socket file. +* astctlowner - use SocketUser +* astctlgroup - use SocketGroup +* astctlpermissions - use SocketMode + +See asterisk-cli.socket for an example of these settings. + + +Stopping Asterisk +================= + +Some existing asterisk.service files use CLI 'core stop now' for the ExecStop +command. It is not recommended to use CLI to stop Asterisk on systems where +CLI socket activation is enabled. If Asterisk fails to start systemd still +tries running the ExecStop command. This can result in an loop where ExecStop +causes CLI socket activation to start Asterisk again. A better way to deal +with shutdown is to use Type=notify and do not specify an ExecStop command. +See the example asterisk.service. + + +Unused Sockets +============== + +Asterisk makes no attempt to check for sockets provided by systemd that are not +used. It is the users responsibility to only provide sockets which Asterisk is +configured to use. diff --git a/contrib/systemd/asterisk-ami.socket b/contrib/systemd/asterisk-ami.socket new file mode 100644 index 00000000000..1fd45e4cb87 --- /dev/null +++ b/contrib/systemd/asterisk-ami.socket @@ -0,0 +1,10 @@ +[Unit] +Description=Asterisk Manager Interface Socket + +[Socket] +Service=asterisk.service +ListenStream=0.0.0.0:5038 + +[Install] +WantedBy=sockets.target +RequiredBy=asterisk.service diff --git a/contrib/systemd/asterisk-amis.socket b/contrib/systemd/asterisk-amis.socket new file mode 100644 index 00000000000..c17cee3e268 --- /dev/null +++ b/contrib/systemd/asterisk-amis.socket @@ -0,0 +1,10 @@ +[Unit] +Description=Asterisk Manager Interface TLS Socket + +[Socket] +Service=asterisk.service +ListenStream=0.0.0.0:5039 + +[Install] +WantedBy=sockets.target +RequiredBy=asterisk.service diff --git a/contrib/systemd/asterisk-cli.socket b/contrib/systemd/asterisk-cli.socket new file mode 100644 index 00000000000..9161a7be466 --- /dev/null +++ b/contrib/systemd/asterisk-cli.socket @@ -0,0 +1,13 @@ +[Unit] +Description=Asterisk Command-line Interface Socket + +[Socket] +Service=asterisk.service +ListenStream=/var/run/asterisk/asterisk.ctl +SocketUser=asterisk +SocketGroup=asterisk +SocketMode=0660 + +[Install] +WantedBy=sockets.target +RequiredBy=asterisk.service diff --git a/contrib/systemd/asterisk-http.socket b/contrib/systemd/asterisk-http.socket new file mode 100644 index 00000000000..e6862b5b922 --- /dev/null +++ b/contrib/systemd/asterisk-http.socket @@ -0,0 +1,11 @@ +[Unit] +Description=Asterisk HTTP Socket + +[Socket] +Service=asterisk.service +FreeBind=true +ListenStream=127.0.0.1:8088 + +[Install] +WantedBy=sockets.target +RequiredBy=asterisk.service diff --git a/contrib/systemd/asterisk-https.socket b/contrib/systemd/asterisk-https.socket new file mode 100644 index 00000000000..d9240dd9106 --- /dev/null +++ b/contrib/systemd/asterisk-https.socket @@ -0,0 +1,11 @@ +[Unit] +Description=Asterisk HTTPS Socket + +[Socket] +Service=asterisk.service +FreeBind=true +ListenStream=127.0.0.1:8089 + +[Install] +WantedBy=sockets.target +RequiredBy=asterisk.service diff --git a/contrib/systemd/asterisk.service b/contrib/systemd/asterisk.service new file mode 100644 index 00000000000..c3d46483c73 --- /dev/null +++ b/contrib/systemd/asterisk.service @@ -0,0 +1,27 @@ +[Unit] +Description=Asterisk PBX and telephony daemon. +After=network.target + +[Service] +Type=notify +Environment=HOME=/var/lib/asterisk +WorkingDirectory=/var/lib/asterisk +User=asterisk +Group=asterisk +ExecStart=/usr/sbin/asterisk -mqf -C /etc/asterisk/asterisk.conf +ExecReload=/usr/sbin/asterisk -rx 'core reload' + +#Nice=0 +#UMask=0002 +LimitCORE=infinity +#LimitNOFILE= +Restart=always +RestartSec=4 + +# Prevent duplication of logs with color codes to /var/log/messages +StandardOutput=null + +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/contrib/systemd/asterisk.socket b/contrib/systemd/asterisk.socket new file mode 100644 index 00000000000..afdca0df78a --- /dev/null +++ b/contrib/systemd/asterisk.socket @@ -0,0 +1,26 @@ +[Unit] +Description=Asterisk Sockets + +[Socket] +FreeBind=true +SocketUser=asterisk +SocketGroup=asterisk +SocketMode=0660 + +# CLI +ListenStream=/var/run/asterisk/asterisk.ctl +# AMI +ListenStream=0.0.0.0:5038 +# AMIS +ListenStream=0.0.0.0:5039 +# HTTP +ListenStream=127.0.0.1:8088 +# HTTPS +ListenStream=127.0.0.1:8089 +# chan_sip TCP +ListenStream=0.0.0.0:5060 +# chan_sip TLS +ListenStream=0.0.0.0:5061 + +[Install] +WantedBy=sockets.target diff --git a/include/asterisk/io.h b/include/asterisk/io.h index 6ee8450bd70..f103cf556ba 100644 --- a/include/asterisk/io.h +++ b/include/asterisk/io.h @@ -24,6 +24,7 @@ #define _ASTERISK_IO_H #include "asterisk/poll-compat.h" +#include "asterisk/netsock2.h" #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -148,6 +149,29 @@ int ast_get_termcols(int fd); */ int ast_sd_notify(const char *state); +/*! + * \brief Find a listening file descriptor provided by socket activation. + * \param type SOCK_STREAM or SOCK_DGRAM + * \param addr The socket address of the bound listener. + * \retval <0 No match. + * \retval >0 File Descriptor matching sockaddr. + * + * \note This function returns -1 if systemd's development headers were not + * detected on the system. + */ +int ast_sd_get_fd(int type, const struct ast_sockaddr *addr); + +/*! + * \brief Find a listening AF_LOCAL file descriptor provided by socket activation. + * \param type SOCK_STREAM or SOCK_DGRAM + * \param path The path of the listener. + * \retval <0 No match. + * \retval >0 File Descriptor matching path. + * + * \note This function returns -1 if systemd's development headers were not + * detected on the system. + */ +int ast_sd_get_fd_un(int type, const char *path); #if defined(__cplusplus) || defined(c_plusplus) } diff --git a/include/asterisk/netsock2.h b/include/asterisk/netsock2.h index 3ede9908778..6c0dd633b03 100644 --- a/include/asterisk/netsock2.h +++ b/include/asterisk/netsock2.h @@ -128,6 +128,22 @@ static inline void ast_sockaddr_setnull(struct ast_sockaddr *addr) addr->len = 0; } +/*! + * \brief + * Copies the data from a sockaddr to an ast_sockaddr + * + * \param dst The destination ast_sockaddr + * \param src The source sockaddr + * \param len Length of the value stored in sockaddr + * \retval void + */ +static inline void ast_sockaddr_copy_sockaddr(struct ast_sockaddr *dst, + struct sockaddr *src, socklen_t len) +{ + memcpy(dst, src, len); + dst->len = len; +} + /*! * \since 1.8 * diff --git a/main/asterisk.c b/main/asterisk.c index 16313ea6853..4424022c94a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -350,6 +350,7 @@ struct ast_eid ast_eid_default; char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR; static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */ +static int ast_socket_is_sd = 0; /*!< Is socket activation responsible for ast_socket? */ static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */ pid_t ast_mainpid; struct console { @@ -1576,8 +1577,16 @@ static int ast_makesocket(void) uid_t uid = -1; gid_t gid = -1; - for (x = 0; x < AST_MAX_CONNECTS; x++) + for (x = 0; x < AST_MAX_CONNECTS; x++) { consoles[x].fd = -1; + } + + if (ast_socket_is_sd) { + ast_socket = ast_sd_get_fd_un(SOCK_STREAM, ast_config_AST_SOCKET); + + goto start_lthread; + } + unlink(ast_config_AST_SOCKET); ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0); if (ast_socket < 0) { @@ -1602,12 +1611,19 @@ static int ast_makesocket(void) return -1; } +start_lthread: if (ast_pthread_create_background(<hread, NULL, listener, NULL)) { ast_log(LOG_WARNING, "Unable to create listener thread.\n"); close(ast_socket); return -1; } + if (ast_socket_is_sd) { + /* owner/group/permissions are set by systemd, we might not even have access + * to socket file so leave it alone */ + return 0; + } + if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) { struct passwd *pw; if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) @@ -2075,7 +2091,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart) pthread_cancel(lthread); close(ast_socket); ast_socket = -1; - unlink(ast_config_AST_SOCKET); + if (!ast_socket_is_sd) { + unlink(ast_config_AST_SOCKET); + } pthread_kill(lthread, SIGURG); pthread_join(lthread, NULL); } @@ -4317,7 +4335,12 @@ int main(int argc, char *argv[]) /* Initial value of the maximum active system verbosity level. */ ast_verb_sys_level = option_verbose; - if (ast_tryconnect()) { + if (ast_sd_get_fd_un(SOCK_STREAM, ast_config_AST_SOCKET) > 0) { + ast_socket_is_sd = 1; + } + + /* DO NOT perform check for existing daemon if systemd has CLI socket activation */ + if (!ast_socket_is_sd && ast_tryconnect()) { /* One is already running */ if (ast_opt_remote) { multi_thread_safe = 1; diff --git a/main/io.c b/main/io.c index b063c22396c..ed455df977f 100644 --- a/main/io.c +++ b/main/io.c @@ -36,6 +36,10 @@ #include "asterisk/utils.h" #ifdef HAVE_SYSTEMD #include + +#ifndef SD_LISTEN_FDS_START +#define SD_LISTEN_FDS_START 3 +#endif #endif #ifdef DEBUG_IO @@ -392,3 +396,73 @@ int ast_sd_notify(const char *state) { return 0; #endif } + +/*! + * \internal \brief Check the type and sockaddr of a file descriptor. + * \param fd File Descriptor to check. + * \param type SOCK_STREAM or SOCK_DGRAM + * \param addr The socket address to match. + * \retval 0 if matching + * \retval -1 if not matching + */ +#ifdef HAVE_SYSTEMD +static int ast_sd_is_socket_sockaddr(int fd, int type, const struct ast_sockaddr* addr) +{ + int canretry = 1; + struct ast_sockaddr fd_addr; + struct sockaddr ss; + socklen_t ss_len; + + if (sd_is_socket(fd, AF_UNSPEC, type, 1) <= 0) { + return -1; + } + +doretry: + if (getsockname(fd, &ss, &ss_len) != 0) { + return -1; + } + + if (ss.sa_family == AF_UNSPEC && canretry) { + /* An unknown bug can cause silent failure from + * the first call to getsockname. */ + canretry = 0; + goto doretry; + } + + ast_sockaddr_copy_sockaddr(&fd_addr, &ss, ss_len); + + return ast_sockaddr_cmp(addr, &fd_addr); +} +#endif + +int ast_sd_get_fd(int type, const struct ast_sockaddr *addr) +{ +#ifdef HAVE_SYSTEMD + int count = sd_listen_fds(0); + int idx; + + for (idx = 0; idx < count; idx++) { + if (!ast_sd_is_socket_sockaddr(idx + SD_LISTEN_FDS_START, type, addr)) { + return idx + SD_LISTEN_FDS_START; + } + } +#endif + + return -1; +} + +int ast_sd_get_fd_un(int type, const char *path) +{ +#ifdef HAVE_SYSTEMD + int count = sd_listen_fds(0); + int idx; + + for (idx = 0; idx < count; idx++) { + if (sd_is_socket_unix(idx + SD_LISTEN_FDS_START, type, 1, path, 0) > 0) { + return idx + SD_LISTEN_FDS_START; + } + } +#endif + + return -1; +} diff --git a/main/tcptls.c b/main/tcptls.c index a3c7dfa7202..85859a3435c 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -40,6 +40,7 @@ #include "asterisk/compat.h" #include "asterisk/tcptls.h" +#include "asterisk/io.h" #include "asterisk/http.h" #include "asterisk/utils.h" #include "asterisk/strings.h" @@ -618,6 +619,7 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) int flags; int x = 1; int tls_changed = 0; + int sd_socket; if (desc->tls_cfg) { char hash[41]; @@ -689,6 +691,19 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) pthread_join(desc->master, NULL); } + sd_socket = ast_sd_get_fd(SOCK_STREAM, &desc->local_address); + + if (sd_socket != -1) { + if (desc->accept_fd != sd_socket) { + if (desc->accept_fd != -1) { + close(desc->accept_fd); + } + desc->accept_fd = sd_socket; + } + + goto systemd_socket_activation; + } + if (desc->accept_fd != -1) { close(desc->accept_fd); } @@ -718,6 +733,8 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); goto error; } + +systemd_socket_activation: flags = fcntl(desc->accept_fd, F_GETFL); fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { From 3a18a090309271420516ea345ec32c7afa9b332b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 2 May 2017 18:51:56 -0500 Subject: [PATCH 1331/1578] SDP: Rework SDP offer/answer model and update capabilities merges. The SDP offer/answer model requires an answer to an offer before a new SDP can be processed. This allows our local SDP creation to be deferred until we know that we need to create an offer or an answer SDP. Once the local SDP is created it won't change until the SDP negotiation is restarted. An offer SDP in an initial SIP INVITE can receive more than one answer SDP. In this case, we need to merge each answer SDP with our original offer capabilities to get the currently negotiated capabilities. To satisfy this requirement means that we cannot update our proposed capabilities until the negotiations are restarted. Local topology updates from ast_sdp_state_update_local_topology() are merged together until the next offer SDP is created. These accumulated updates are then merged with the current negotiated capabilities to create the new proposed capabilities that the offer SDP is built. Local topology updates are merged in several passes to attempt to be smart about how streams from the system are matched with the previously negotiated stream slots. To allow for T.38 support when merging, type matching considers audio and image types to be equivalent. First streams are matched by stream name and type. Then streams are matched by stream type only. Any remaining unmatched existing streams are declined. Any new active streams are either backfilled into pre-merge declined slots or appended onto the end of the merged topology. Any excess new streams above the maximum supported number of streams are simply discarded. Remote topology negotiation merges depend if the topology is an offer or answer. An offer remote topology negotiation dictates the stream slot ordering and new streams can be added. A remote offer can do anything to the previously negotiated streams except reduce the number of stream slots. An answer remote topology negotiation is limited to what our offer requested. The answer can only decline streams, pick codecs from the offered list, or indicate the remote's stream hold state. I had originally kept the RTP instance if the remote offer SDP changed a stream type between audio and video since they both use RTP. However, I later removed this support in favor of simply creating a new RTP instance since the stream's purpose has to be changing anyway. Any RTP packets from the old stream type might cause mischief for the bridged peer. * Added ast_sdp_state_restart_negotiations() to restart the SDP offer/answer negotiations. We will thus know to create a new local SDP when it is time to create an offer or answer. * Removed ast_sdp_state_reset(). Save the current topology before starting T.38. To recover from T.38 simply update the local topology to the saved topology and restart the SDP negotiations to get the offer SDP renegotiating the previous configuration. * Allow initial topology for ast_sdp_state_alloc() to be NULL so an initial remote offer SDP can dictate the streams we start with. We can always update the local topology later if it turns out we need to offer SDP first because the remote chose to defer sending us a SDP. * Made the ast_sdp_state_alloc() initial topology limit to max_streams, limit to configured codecs, handle declined streams, and discard unsupported types. * Convert struct ast_sdp to ao2 object. Needed to easily save off a remote SDP to refer to later for various reasons such as generating declined m= lines in the local SDP. * Improve converting remote SDP streams to a topology including stream state. A stream state of AST_STREAM_STATE_REMOVED indicates the stream is declined/dead. * Improve merging streams to take into account the stream state. * Added query for remote hold state. * Added maximum streams allowed SDP config option. * Added ability to create new streams as needed. New streams are created with configured default audio, video, or image codecs depending on stream type. * Added global locally_held state along with a per stream local hold state. Historically, Asterisk only has a global locally held state because when the we put the remote on hold we do it for all active streams. * Added queries for a rejected offer and current SDP negotiation role. The rejected query allows the using module to know how to respond to a failed remote SDP set. Should the using module respond with a 488 Not Acceptable Here or 500 Internal Error to the offer SDP? * Moved sdp_state_capabilities.connection_address to ast_sdp_state. There seems no reason to keep it in the sdp_state_capabilities struct since it was only used by the ast_sdp_state.proposed_capabilities instance. * Callbacks are now available to allow the using module some customization of negotiated streams and to complete setting up streams for use. See the typedef doxygen for each callback for what is allowable and when they are called. * Added topology answerer modify callback. * Added topology pre and post apply callbacks. * Added topology offerer modify callback. * Added topology offerer configure callback. * Had to rework the unit tests because I changed how SDP topologies are merged. Replaced several unit tests with new negotiation tests. Change-Id: If07fe6d79fbdce33968a9401d41d908385043a06 --- include/asterisk/sdp.h | 12 +- include/asterisk/sdp_options.h | 224 ++++ include/asterisk/sdp_state.h | 127 +- include/asterisk/stream.h | 11 + main/sdp.c | 99 +- main/sdp_options.c | 92 ++ main/sdp_private.h | 19 +- main/sdp_state.c | 2159 +++++++++++++++++++++++++----- main/stream.c | 17 + res/res_sdp_translator_pjmedia.c | 4 +- tests/test_sdp.c | 1150 +++++++++++++--- 11 files changed, 3351 insertions(+), 563 deletions(-) diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h index 224a0e5a30c..768469544e6 100644 --- a/include/asterisk/sdp.h +++ b/include/asterisk/sdp.h @@ -253,16 +253,6 @@ void ast_sdp_s_free(struct ast_sdp_s_line *s_line); */ void ast_sdp_t_free(struct ast_sdp_t_line *t_line); -/*! - * \brief Free an SDP - * Frees the sdp and all resources it contains - * - * \param sdp The sdp to free - * - * \since 15 - */ -void ast_sdp_free(struct ast_sdp *sdp); - /*! * \brief Allocate an SDP Attribute * @@ -544,7 +534,7 @@ int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_opt int rtp_code, int asterisk_format, const struct ast_format *format, int code); /*! - * \brief Create an SDP + * \brief Create an SDP ao2 object * * \param o_line Origin * \param c_line Connection diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index b8c1bbd56eb..e45ae8cb106 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -20,6 +20,7 @@ #define _ASTERISK_SDP_OPTIONS_H #include "asterisk/udptl.h" +#include "asterisk/format_cap.h" struct ast_sdp_options; @@ -79,6 +80,149 @@ enum ast_sdp_options_encryption { AST_SDP_ENCRYPTION_DTLS, }; +/*! + * \brief Callback when processing an offer SDP for our answer SDP. + * \since 15.0.0 + * + * \details + * This callback is called after merging our last negotiated topology + * with the remote's offer topology and before we have sent our answer + * SDP. At this point you can alter new_topology streams. You can + * decline, remove formats, or rename streams. Changing anything else + * on the streams is likely to not end well. + * + * * To decline a stream simply set the stream state to + * AST_STREAM_STATE_REMOVED. You could implement a maximum number + * of active streams of a given type policy. + * + * * To remove formats use the format API to remove any formats from a + * stream. The streams have the current joint negotiated formats. + * Most likely you would want to remove all but the first format. + * + * * To rename a stream you need to clone the stream and give it a + * new name and then set it in new_topology using + * ast_stream_topology_set_stream(). + * + * \note Removing all formats is an error. You should decline the + * stream instead. + * + * \param context User supplied context data pointer for the SDP + * state. + * \param old_topology Active negotiated topology. NULL if this is + * the first SDP negotiation. The old topology is available so you + * can tell if any streams are new or changing type. + * \param new_topology New negotiated topology that we intend to + * generate the answer SDP. + * + * \return Nothing + */ +typedef void (*ast_sdp_answerer_modify_cb)(void *context, + const struct ast_stream_topology *old_topology, + struct ast_stream_topology *new_topology); + +/*! + * \internal + * \brief Callback when generating a topology for our SDP offer. + * \since 15.0.0 + * + * \details + * This callback is called after merging any topology updates from the + * system by ast_sdp_state_update_local_topology() and before we have + * sent our offer SDP. At this point you can alter new_topology + * streams. You can decline, add/remove/update formats, or rename + * streams. Changing anything else on the streams is likely to not + * end well. + * + * * To decline a stream simply set the stream state to + * AST_STREAM_STATE_REMOVED. You could implement a maximum number + * of active streams of a given type policy. + * + * * To update formats use the format API to change formats of the + * streams. The streams have the current proposed formats. You + * could do whatever you want for formats but you should stay within + * the configured formats for the stream type's endpoint. However, + * you should use ast_sdp_state_update_local_topology() instead of + * this backdoor method. + * + * * To rename a stream you need to clone the stream and give it a + * new name and then set it in new_topology using + * ast_stream_topology_set_stream(). + * + * \note Removing all formats is an error. You should decline the + * stream instead. + * + * \note Declined new streams that are in slots higher than present in + * old_topology are removed so the SDP can be smaller. The remote has + * never seen those slots so we shouldn't bother keeping them. + * + * \param context User supplied context data pointer for the SDP + * state. + * \param old_topology Active negotiated topology. NULL if this is + * the first SDP negotiation. The old topology is available so you + * can tell if any streams are new or changing type. + * \param new_topology Merged topology that we intend to generate the + * offer SDP. + * + * \return Nothing + */ +typedef void (*ast_sdp_offerer_modify_cb)(void *context, + const struct ast_stream_topology *old_topology, + struct ast_stream_topology *new_topology); + +/*! + * \brief Callback when generating an offer SDP to configure extra stream data. + * \since 15.0.0 + * + * \details + * This callback is called after any ast_sdp_offerer_modify_cb + * callback and before we have sent our offer SDP. The callback can + * call several SDP API calls to configure the proposed capabilities + * of streams before we create the SDP offer. For example, the + * callback could configure a stream specific connection address, T.38 + * parameters, RTP instance, or UDPTL instance parameters. + * + * \param context User supplied context data pointer for the SDP + * state. + * \param topology Topology ready to configure extra stream options. + * + * \return Nothing + */ +typedef void (*ast_sdp_offerer_config_cb)(void *context, const struct ast_stream_topology *topology); + +/*! + * \brief Callback before applying a topology. + * \since 15.0.0 + * + * \details + * This callback is called before the topology is applied so the + * using module can do what is necessary before the topology becomes + * active. + * + * \param context User supplied context data pointer for the SDP + * state. + * \param topology Topology ready to be applied. + * + * \return Nothing + */ +typedef void (*ast_sdp_preapply_cb)(void *context, const struct ast_stream_topology *topology); + +/*! + * \brief Callback after applying a topology. + * \since 15.0.0 + * + * \details + * This callback is called after the topology is applied so the + * using module can do what is necessary after the topology becomes + * active. + * + * \param context User supplied context data pointer for the SDP + * state. + * \param topology Topology already applied. + * + * \return Nothing + */ +typedef void (*ast_sdp_postapply_cb)(void *context, const struct ast_stream_topology *topology); + /*! * \since 15.0.0 * \brief Allocate a new SDP options structure. @@ -204,6 +348,24 @@ void ast_sdp_options_set_rtp_engine(struct ast_sdp_options *options, */ const char *ast_sdp_options_get_rtp_engine(const struct ast_sdp_options *options); +void ast_sdp_options_set_state_context(struct ast_sdp_options *options, void *state_context); +void *ast_sdp_options_get_state_context(const struct ast_sdp_options *options); + +void ast_sdp_options_set_answerer_modify_cb(struct ast_sdp_options *options, ast_sdp_answerer_modify_cb answerer_modify_cb); +ast_sdp_answerer_modify_cb ast_sdp_options_get_answerer_modify_cb(const struct ast_sdp_options *options); + +void ast_sdp_options_set_offerer_modify_cb(struct ast_sdp_options *options, ast_sdp_offerer_modify_cb offerer_modify_cb); +ast_sdp_offerer_modify_cb ast_sdp_options_get_offerer_modify_cb(const struct ast_sdp_options *options); + +void ast_sdp_options_set_offerer_config_cb(struct ast_sdp_options *options, ast_sdp_offerer_config_cb offerer_config_cb); +ast_sdp_offerer_config_cb ast_sdp_options_get_offerer_config_cb(const struct ast_sdp_options *options); + +void ast_sdp_options_set_preapply_cb(struct ast_sdp_options *options, ast_sdp_preapply_cb preapply_cb); +ast_sdp_preapply_cb ast_sdp_options_get_preapply_cb(const struct ast_sdp_options *options); + +void ast_sdp_options_set_postapply_cb(struct ast_sdp_options *options, ast_sdp_postapply_cb postapply_cb); +ast_sdp_postapply_cb ast_sdp_options_get_postapply_cb(const struct ast_sdp_options *options); + /*! * \since 15.0.0 * \brief Set SDP Options rtp_symmetric @@ -503,6 +665,26 @@ void ast_sdp_options_set_udptl_far_max_datagram(struct ast_sdp_options *options, */ unsigned int ast_sdp_options_get_udptl_far_max_datagram(const struct ast_sdp_options *options); +/*! + * \since 15.0.0 + * \brief Set SDP Options max_streams + * + * \param options SDP Options + * \param max_streams + */ +void ast_sdp_options_set_max_streams(struct ast_sdp_options *options, + unsigned int max_streams); + +/*! + * \since 15.0.0 + * \brief Get SDP Options max_streams + * + * \param options SDP Options + * + * \returns max_streams + */ +unsigned int ast_sdp_options_get_max_streams(const struct ast_sdp_options *options); + /*! * \since 15.0.0 * \brief Enable setting SSRC level attributes on SDPs @@ -547,4 +729,46 @@ void ast_sdp_options_set_sched_type(struct ast_sdp_options *options, struct ast_sched_context *ast_sdp_options_get_sched_type(const struct ast_sdp_options *options, enum ast_media_type type); +/*! + * \brief Set all allowed stream types to create new streams. + * \since 15.0.0 + * + * \param options SDP Options + * \param cap Format capabilities to set all allowed stream types at once. + * Could be NULL to disable creating any new streams. + * + * \return Nothing + */ +void ast_sdp_options_set_format_caps(struct ast_sdp_options *options, + struct ast_format_cap *cap); + +/*! + * \brief Set the SDP options format cap used to create new streams of the type. + * \since 15.0.0 + * + * \param options SDP Options + * \param type Media type the format cap represents. + * \param cap Format capabilities to use for the specified media type. + * Could be NULL to disable creating new streams of type. + * + * \return Nothing + */ +void ast_sdp_options_set_format_cap_type(struct ast_sdp_options *options, + enum ast_media_type type, struct ast_format_cap *cap); + +/*! + * \brief Get the SDP options format cap used to create new streams of the type. + * \since 15.0.0 + * + * \param options SDP Options + * \param type Media type the format cap represents. + * + * \retval NULL if stream not allowed to be created. + * \retval cap to use in negotiating the new stream. + * + * \note The returned cap does not have its own ao2 ref. + */ +struct ast_format_cap *ast_sdp_options_get_format_cap_type(const struct ast_sdp_options *options, + enum ast_media_type type); + #endif /* _ASTERISK_SDP_OPTIONS_H */ diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index b8209e1d557..ec9d502e2cd 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -30,12 +30,22 @@ struct ast_control_t38_parameters; /*! * \brief Allocate a new SDP state * + * \details * SDP state keeps tabs on everything SDP-related for a media session. * Most SDP operations will require the state to be provided. * Ownership of the SDP options is taken on by the SDP state. * A good strategy is to call this during session creation. + * + * \param topology Initial stream topology to offer. + * NULL if we are going to be the answerer. We can always + * update the local topology later if it turns out we need + * to be the offerer. + * \param options SDP options for the duration of the session. + * + * \retval SDP state struct + * \retval NULL on failure */ -struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, +struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *topology, struct ast_sdp_options *options); /*! @@ -86,6 +96,8 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_ * * If this is called prior to receiving a remote SDP, then this will just mirror * the local configured endpoint capabilities. + * + * \note Cannot return NULL. It is a BUG if it does. */ const struct ast_stream_topology *ast_sdp_state_get_joint_topology( const struct ast_sdp_state *sdp_state); @@ -93,6 +105,7 @@ const struct ast_stream_topology *ast_sdp_state_get_joint_topology( /*! * \brief Get the local topology * + * \note Cannot return NULL. It is a BUG if it does. */ const struct ast_stream_topology *ast_sdp_state_get_local_topology( const struct ast_sdp_state *sdp_state); @@ -114,9 +127,10 @@ const struct ast_sdp_options *ast_sdp_state_get_options( * \retval NULL Failure * * \note - * This function will allocate a new SDP with RTP instances if it has not already - * been allocated. - * + * This function will return the last local SDP created if one were + * previously requested for the current negotiation. Otherwise it + * creates our SDP offer/answer depending on what role we are playing + * in the current negotiation. */ const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_state); @@ -152,6 +166,7 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state); * * \retval 0 Success * \retval non-0 Failure + * Use ast_sdp_state_is_offer_rejected() to see if the SDP offer was rejected. * * \since 15 */ @@ -165,39 +180,72 @@ int ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct a * * \retval 0 Success * \retval non-0 Failure + * Use ast_sdp_state_is_offer_rejected() to see if the SDP offer was rejected. * * \since 15 */ int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, const void *remote); /*! - * \brief Reset the SDP state and stream capabilities as if the SDP state had just been allocated. + * \brief Was the set remote offer rejected. + * \since 15.0.0 * * \param sdp_state - * \param remote The implementation's representation of an SDP. * - * \retval 0 Success + * \retval 0 if not rejected. + * \retval non-zero if rejected. + */ +int ast_sdp_state_is_offer_rejected(struct ast_sdp_state *sdp_state); + +/*! + * \brief Are we the SDP offerer. + * \since 15.0.0 * - * \note - * This is most useful for when a channel driver is sending a session refresh message - * and needs to re-advertise its initial capabilities instead of the previously-negotiated - * joint capabilities. + * \param sdp_state * - * \since 15 + * \retval 0 if we are not the offerer. + * \retval non-zero we are the offerer. */ -int ast_sdp_state_reset(struct ast_sdp_state *sdp_state); +int ast_sdp_state_is_offerer(struct ast_sdp_state *sdp_state); + +/*! + * \brief Are we the SDP answerer. + * \since 15.0.0 + * + * \param sdp_state + * + * \retval 0 if we are not the answerer. + * \retval non-zero we are the answerer. + */ +int ast_sdp_state_is_answerer(struct ast_sdp_state *sdp_state); + +/*! + * \brief Restart the SDP offer/answer negotiations. + * + * \param sdp_state + * + * \retval 0 Success + * \retval non-0 Failure + */ +int ast_sdp_state_restart_negotiations(struct ast_sdp_state *sdp_state); /*! * \brief Update the local stream topology on the SDP state. * + * \details + * Basically we are saving off any topology updates until we create the + * next SDP offer. Repeated updates merge with the previous updated + * topology. + * * \param sdp_state - * \param streams The new stream topology. + * \param topology The new stream topology. * * \retval 0 Success + * \retval non-0 Failure * * \since 15 */ -int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams); +int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *topology); /*! * \brief Set the local address (IP address) to use for connection addresses @@ -231,7 +279,26 @@ int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int st /*! * \since 15.0.0 - * \brief Set a stream to be held or unheld + * \brief Set the global locally held state. + * + * \param sdp_state + * \param locally_held + */ +void ast_sdp_state_set_global_locally_held(struct ast_sdp_state *sdp_state, unsigned int locally_held); + +/*! + * \since 15.0.0 + * \brief Get the global locally held state. + * + * \param sdp_state + * + * \returns locally_held + */ +unsigned int ast_sdp_state_get_global_locally_held(const struct ast_sdp_state *sdp_state); + +/*! + * \since 15.0.0 + * \brief Set a stream to be held or unheld locally * * \param sdp_state * \param stream_index The stream to set the held value for @@ -242,25 +309,37 @@ void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state, /*! * \since 15.0.0 - * \brief Set the UDPTL session parameters + * \brief Get whether a stream is locally held or not * * \param sdp_state - * \param stream_index The stream to set the UDPTL session parameters for - * \param params + * \param stream_index The stream to get the held state for + * + * \returns locally_held */ -void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state, - int stream_index, struct ast_control_t38_parameters *params); +unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_state, + int stream_index); /*! * \since 15.0.0 - * \brief Get whether a stream is held or not + * \brief Get whether a stream is remotely held or not * * \param sdp_state * \param stream_index The stream to get the held state for * - * \returns locally_held + * \returns remotely_held */ -unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_state, +unsigned int ast_sdp_state_get_remotely_held(const struct ast_sdp_state *sdp_state, int stream_index); +/*! + * \since 15.0.0 + * \brief Set the UDPTL session parameters + * + * \param sdp_state + * \param stream_index The stream to set the UDPTL session parameters for + * \param params + */ +void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state, + int stream_index, struct ast_control_t38_parameters *params); + #endif /* _ASTERISK_SDP_STATE_H */ diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 00169a3f1f6..21af53faeef 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -227,6 +227,17 @@ void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state */ const char *ast_stream_state2str(enum ast_stream_state state); +/*! + * \brief Convert a string to a stream state + * + * \param str The string to convert + * + * \return The stream state + * + * \since 15.0.0 + */ +enum ast_stream_state ast_stream_str2state(const char *str); + /*! * \brief Get the opaque stream data * diff --git a/main/sdp.c b/main/sdp.c index bfb83e82fec..fd10ba8c3f5 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -109,11 +109,9 @@ void ast_sdp_t_free(struct ast_sdp_t_line *t_line) ast_free(t_line); } -void ast_sdp_free(struct ast_sdp *sdp) +static void ast_sdp_dtor(void *vdoomed) { - if (!sdp) { - return; - } + struct ast_sdp *sdp = vdoomed; ast_sdp_o_free(sdp->o_line); ast_sdp_s_free(sdp->s_line); @@ -121,7 +119,6 @@ void ast_sdp_free(struct ast_sdp *sdp) ast_sdp_t_free(sdp->t_line); ast_sdp_a_lines_free(sdp->a_lines); ast_sdp_m_lines_free(sdp->m_lines); - ast_free(sdp); } #define COPY_STR_AND_ADVANCE(p, dest, source) \ @@ -314,28 +311,28 @@ struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line, { struct ast_sdp *new_sdp; - new_sdp = ast_calloc(1, sizeof *new_sdp); + new_sdp = ao2_alloc_options(sizeof(*new_sdp), ast_sdp_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!new_sdp) { return NULL; } new_sdp->a_lines = ast_calloc(1, sizeof(*new_sdp->a_lines)); if (!new_sdp->a_lines) { - ast_sdp_free(new_sdp); + ao2_ref(new_sdp, -1); return NULL; } if (AST_VECTOR_INIT(new_sdp->a_lines, 20)) { - ast_sdp_free(new_sdp); + ao2_ref(new_sdp, -1); return NULL; } new_sdp->m_lines = ast_calloc(1, sizeof(*new_sdp->m_lines)); if (!new_sdp->m_lines) { - ast_sdp_free(new_sdp); + ao2_ref(new_sdp, -1); return NULL; } if (AST_VECTOR_INIT(new_sdp->m_lines, 20)) { - ast_sdp_free(new_sdp); + ao2_ref(new_sdp, -1); return NULL; } @@ -741,6 +738,62 @@ static void process_fmtp_lines(const struct ast_sdp_m_line *m_line, int payload, } } +/*! + * \internal + * \brief Determine the RTP stream direction in the given a lines. + * \since 15.0.0 + * + * \param a_lines Attribute lines to search. + * + * \retval Stream direction on success. + * \retval AST_STREAM_STATE_REMOVED on failure. + * + * \return Nothing + */ +static enum ast_stream_state get_a_line_direction(const struct ast_sdp_a_lines *a_lines) +{ + if (a_lines) { + enum ast_stream_state direction; + int idx; + const struct ast_sdp_a_line *a_line; + + for (idx = 0; idx < AST_VECTOR_SIZE(a_lines); ++idx) { + a_line = AST_VECTOR_GET(a_lines, idx); + direction = ast_stream_str2state(a_line->name); + if (direction != AST_STREAM_STATE_REMOVED) { + return direction; + } + } + } + + return AST_STREAM_STATE_REMOVED; +} + +/*! + * \internal + * \brief Determine the RTP stream direction. + * \since 15.0.0 + * + * \param a_lines The SDP media global attributes + * \param m_line The SDP media section to convert + * + * \return Stream direction + */ +static enum ast_stream_state get_stream_direction(const struct ast_sdp_a_lines *a_lines, const struct ast_sdp_m_line *m_line) +{ + enum ast_stream_state direction; + + direction = get_a_line_direction(m_line->a_lines); + if (direction != AST_STREAM_STATE_REMOVED) { + return direction; + } + direction = get_a_line_direction(a_lines); + if (direction != AST_STREAM_STATE_REMOVED) { + return direction; + } + return AST_STREAM_STATE_SENDRECV; +} + /* * Needed so we don't have an external function referenced as data. * The dynamic linker doesn't handle that very well. @@ -758,13 +811,14 @@ static void rtp_codecs_free(struct ast_rtp_codecs *codecs) * Given an m-line from an SDP, convert it into an ast_stream structure. * This takes formats, as well as clock-rate and fmtp attributes into account. * + * \param a_lines The SDP media global attributes * \param m_line The SDP media section to convert * \param g726_non_standard Non-zero if G.726 is non-standard * * \retval NULL An error occurred * \retval non-NULL The converted stream */ -static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line, int g726_non_standard) +static struct ast_stream *get_stream_from_m(const struct ast_sdp_a_lines *a_lines, const struct ast_sdp_m_line *m_line, int g726_non_standard) { int i; int non_ast_fmts; @@ -793,6 +847,14 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line, ao2_ref(caps, -1); return NULL; } + ast_stream_set_data(stream, AST_STREAM_DATA_RTP_CODECS, codecs, + (ast_stream_data_free_fn) rtp_codecs_free); + + if (!m_line->port) { + /* Stream is declined. There may not be any attributes. */ + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + break; + } options = g726_non_standard ? AST_RTP_OPT_G726_NONSTANDARD : 0; for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { @@ -819,10 +881,16 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line, } ast_rtp_codecs_payload_formats(codecs, caps, &non_ast_fmts); - ast_stream_set_data(stream, AST_STREAM_DATA_RTP_CODECS, codecs, - (ast_stream_data_free_fn) rtp_codecs_free); + + ast_stream_set_state(stream, get_stream_direction(a_lines, m_line)); break; case AST_MEDIA_TYPE_IMAGE: + if (!m_line->port) { + /* Stream is declined. There may not be any attributes. */ + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + break; + } + for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) { struct ast_sdp_payload *payload; @@ -830,12 +898,15 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line, payload = ast_sdp_m_get_payload(m_line, i); if (!strcasecmp(payload->fmt, "t38")) { ast_format_cap_append(caps, ast_format_t38, 0); + ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV); } } break; case AST_MEDIA_TYPE_UNKNOWN: case AST_MEDIA_TYPE_TEXT: case AST_MEDIA_TYPE_END: + /* Consider these unsupported streams as declined */ + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); break; } @@ -858,7 +929,7 @@ struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp, for (i = 0; i < ast_sdp_get_m_count(sdp); ++i) { struct ast_stream *stream; - stream = get_stream_from_m(ast_sdp_get_m(sdp, i), g726_non_standard); + stream = get_stream_from_m(sdp->a_lines, ast_sdp_get_m(sdp, i), g726_non_standard); if (!stream) { /* * The topology cannot match the SDP because diff --git a/main/sdp_options.c b/main/sdp_options.c index a938583c683..79efbafa05a 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -27,6 +27,7 @@ #define DEFAULT_ICE AST_SDP_ICE_DISABLED #define DEFAULT_IMPL AST_SDP_IMPL_STRING #define DEFAULT_ENCRYPTION AST_SDP_ENCRYPTION_DISABLED +#define DEFAULT_MAX_STREAMS 16 /* Set to match our PJPROJECT PJMEDIA_MAX_SDP_MEDIA. */ #define DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(field, assert_on_null) \ void ast_sdp_options_set_##field(struct ast_sdp_options *options, const char *value) \ @@ -60,6 +61,12 @@ DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpowner, 0); DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpsession, 0); DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(rtp_engine, 0); +DEFINE_GETTERS_SETTERS_FOR(void *, state_context); +DEFINE_GETTERS_SETTERS_FOR(ast_sdp_answerer_modify_cb, answerer_modify_cb); +DEFINE_GETTERS_SETTERS_FOR(ast_sdp_offerer_modify_cb, offerer_modify_cb); +DEFINE_GETTERS_SETTERS_FOR(ast_sdp_offerer_config_cb, offerer_config_cb); +DEFINE_GETTERS_SETTERS_FOR(ast_sdp_preapply_cb, preapply_cb); +DEFINE_GETTERS_SETTERS_FOR(ast_sdp_postapply_cb, postapply_cb); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_symmetric); DEFINE_GETTERS_SETTERS_FOR(enum ast_t38_ec_modes, udptl_error_correction); @@ -71,6 +78,7 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_video); DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_video); +DEFINE_GETTERS_SETTERS_FOR(unsigned int, max_streams); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_dtmf, dtmf); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_ice, ice); DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_impl, impl); @@ -110,12 +118,87 @@ void ast_sdp_options_set_sched_type(struct ast_sdp_options *options, enum ast_me } } +struct ast_format_cap *ast_sdp_options_get_format_cap_type(const struct ast_sdp_options *options, + enum ast_media_type type) +{ + struct ast_format_cap *cap = NULL; + + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + case AST_MEDIA_TYPE_IMAGE: + case AST_MEDIA_TYPE_TEXT: + cap = options->caps[type]; + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_END: + break; + } + return cap; +} + +void ast_sdp_options_set_format_cap_type(struct ast_sdp_options *options, + enum ast_media_type type, struct ast_format_cap *cap) +{ + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + case AST_MEDIA_TYPE_IMAGE: + case AST_MEDIA_TYPE_TEXT: + ao2_cleanup(options->caps[type]); + options->caps[type] = NULL; + if (cap && !ast_format_cap_empty(cap)) { + ao2_ref(cap, +1); + options->caps[type] = cap; + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_END: + break; + } +} + +void ast_sdp_options_set_format_caps(struct ast_sdp_options *options, + struct ast_format_cap *cap) +{ + enum ast_media_type type; + + for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) { + ao2_cleanup(options->caps[type]); + options->caps[type] = NULL; + } + + if (!cap || ast_format_cap_empty(cap)) { + return; + } + + for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; ++type) { + struct ast_format_cap *type_cap; + + type_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!type_cap) { + continue; + } + + ast_format_cap_set_framing(type_cap, ast_format_cap_get_framing(cap)); + if (ast_format_cap_append_from_cap(type_cap, cap, type) + || ast_format_cap_empty(type_cap)) { + ao2_ref(type_cap, -1); + continue; + } + + /* This takes the allocation reference */ + options->caps[type] = type_cap; + } +} + static void set_defaults(struct ast_sdp_options *options) { options->dtmf = DEFAULT_DTMF; options->ice = DEFAULT_ICE; options->impl = DEFAULT_IMPL; options->encryption = DEFAULT_ENCRYPTION; + options->max_streams = DEFAULT_MAX_STREAMS; } struct ast_sdp_options *ast_sdp_options_alloc(void) @@ -138,6 +221,15 @@ struct ast_sdp_options *ast_sdp_options_alloc(void) void ast_sdp_options_free(struct ast_sdp_options *options) { + enum ast_media_type type; + + if (!options) { + return; + } + + for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) { + ao2_cleanup(options->caps[type]); + } ast_string_field_free_memory(options); ast_free(options); } diff --git a/main/sdp_private.h b/main/sdp_private.h index 62228a5c89e..48bedc80200 100644 --- a/main/sdp_private.h +++ b/main/sdp_private.h @@ -24,7 +24,7 @@ struct ast_sdp_options { AST_DECLARE_STRING_FIELDS( - /*! Media address to use in SDP */ + /*! Media address to advertise in SDP session c= line */ AST_STRING_FIELD(media_address); /*! Optional address of the interface media should use. */ AST_STRING_FIELD(interface_address); @@ -37,12 +37,25 @@ struct ast_sdp_options { ); /*! Scheduler context for the media stream types (Mainly for RTP) */ struct ast_sched_context *sched[AST_MEDIA_TYPE_END]; + /*! Capabilities to create new streams of the indexed media type. */ + struct ast_format_cap *caps[AST_MEDIA_TYPE_END]; + /*! User supplied context data pointer for the SDP state. */ + void *state_context; + /*! Modify negotiated topology before create answer SDP callback. */ + ast_sdp_answerer_modify_cb answerer_modify_cb; + /*! Modify proposed topology before create offer SDP callback. */ + ast_sdp_offerer_modify_cb offerer_modify_cb; + /*! Configure proposed topology extra stream options before create offer SDP callback. */ + ast_sdp_offerer_config_cb offerer_config_cb; + /*! Negotiated topology is about to be applied callback. */ + ast_sdp_preapply_cb preapply_cb; + /*! Negotiated topology was just applied callback. */ + ast_sdp_postapply_cb postapply_cb; struct { unsigned int rtp_symmetric:1; unsigned int udptl_symmetric:1; unsigned int rtp_ipv6:1; unsigned int g726_non_standard:1; - unsigned int locally_held:1; unsigned int rtcp_mux:1; unsigned int ssrc:1; }; @@ -52,6 +65,8 @@ struct ast_sdp_options { unsigned int tos_video; unsigned int cos_video; unsigned int udptl_far_max_datagram; + /*! Maximum number of streams to allow. */ + unsigned int max_streams; }; enum ast_sdp_options_dtmf dtmf; enum ast_sdp_options_ice ice; diff --git a/main/sdp_state.c b/main/sdp_state.c index 99421ad4da7..330140c6937 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -85,12 +85,39 @@ struct sdp_state_stream { }; /*! An explicit connection address for this stream */ struct ast_sockaddr connection_address; - /*! Whether this stream is held or not */ - unsigned int locally_held; + /*! + * \brief Stream is on hold by remote side + * + * \note This flag is never set on the + * sdp_state->proposed_capabilities->streams states. This is useful + * when the remote sends us a reINVITE with a deferred SDP to place + * us on and off of hold. + */ + unsigned int remotely_held:1; + /*! Stream is on hold by local side */ + unsigned int locally_held:1; /*! UDPTL session parameters */ struct ast_control_t38_parameters t38_local_params; }; +static int sdp_is_stream_type_supported(enum ast_media_type type) +{ + int is_supported = 0; + + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + case AST_MEDIA_TYPE_IMAGE: + is_supported = 1; + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; + } + return is_supported; +} + static void sdp_state_rtp_destroy(void *obj) { struct sdp_state_rtp *rtp = obj; @@ -135,8 +162,6 @@ struct sdp_state_capabilities { struct ast_stream_topology *topology; /*! Additional information about the streams */ struct sdp_state_streams streams; - /*! An explicit global connection address */ - struct ast_sockaddr connection_address; }; static void sdp_state_capabilities_free(struct sdp_state_capabilities *capabilities) @@ -269,30 +294,80 @@ static struct sdp_state_udptl *create_udptl(const struct ast_sdp_options *option return udptl; } +static struct ast_stream *merge_local_stream(const struct ast_sdp_options *options, + const struct ast_stream *update); + static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const struct ast_stream_topology *topology, const struct ast_sdp_options *options) { struct sdp_state_capabilities *capabilities; - int i; + struct ast_stream *stream; + unsigned int topology_count; + unsigned int max_streams; + unsigned int idx; capabilities = ast_calloc(1, sizeof(*capabilities)); if (!capabilities) { return NULL; } - capabilities->topology = ast_stream_topology_clone(topology); + capabilities->topology = ast_stream_topology_alloc(); if (!capabilities->topology) { sdp_state_capabilities_free(capabilities); return NULL; } - if (AST_VECTOR_INIT(&capabilities->streams, ast_stream_topology_get_count(topology))) { + max_streams = ast_sdp_options_get_max_streams(options); + if (topology) { + topology_count = ast_stream_topology_get_count(topology); + } else { + topology_count = 0; + } + + /* Gather acceptable streams from the initial topology */ + for (idx = 0; idx < topology_count; ++idx) { + stream = ast_stream_topology_get_stream(topology, idx); + if (!sdp_is_stream_type_supported(ast_stream_get_type(stream))) { + /* Delete the unsupported stream from the initial topology */ + continue; + } + if (max_streams <= ast_stream_topology_get_count(capabilities->topology)) { + /* Cannot support any more streams */ + break; + } + + stream = merge_local_stream(options, stream); + if (!stream) { + sdp_state_capabilities_free(capabilities); + return NULL; + } + + if (ast_stream_topology_append_stream(capabilities->topology, stream) < 0) { + ast_stream_free(stream); + sdp_state_capabilities_free(capabilities); + return NULL; + } + } + + /* + * Remove trailing declined streams from the initial built topology. + * No need to waste space in the SDP with these unused slots. + */ + for (idx = ast_stream_topology_get_count(capabilities->topology); idx--;) { + stream = ast_stream_topology_get_stream(capabilities->topology, idx); + if (ast_stream_get_state(stream) != AST_STREAM_STATE_REMOVED) { + break; + } + ast_stream_topology_del_stream(capabilities->topology, idx); + } + + topology_count = ast_stream_topology_get_count(capabilities->topology); + if (AST_VECTOR_INIT(&capabilities->streams, topology_count)) { sdp_state_capabilities_free(capabilities); return NULL; } - ast_sockaddr_setnull(&capabilities->connection_address); - for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { + for (idx = 0; idx < topology_count; ++idx) { struct sdp_state_stream *state_stream; state_stream = ast_calloc(1, sizeof(*state_stream)); @@ -301,32 +376,34 @@ static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const st return NULL; } - state_stream->type = ast_stream_get_type(ast_stream_topology_get_stream(topology, i)); - switch (state_stream->type) { - case AST_MEDIA_TYPE_AUDIO: - case AST_MEDIA_TYPE_VIDEO: - state_stream->rtp = create_rtp(options, state_stream->type); - if (!state_stream->rtp) { - sdp_state_stream_free(state_stream); - sdp_state_capabilities_free(capabilities); - return NULL; - } - break; - case AST_MEDIA_TYPE_IMAGE: - state_stream->udptl = create_udptl(options); - if (!state_stream->udptl) { - sdp_state_stream_free(state_stream); - sdp_state_capabilities_free(capabilities); - return NULL; + stream = ast_stream_topology_get_stream(capabilities->topology, idx); + state_stream->type = ast_stream_get_type(stream); + if (ast_stream_get_state(stream) != AST_STREAM_STATE_REMOVED) { + switch (state_stream->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + state_stream->rtp = create_rtp(options, state_stream->type); + if (!state_stream->rtp) { + sdp_state_stream_free(state_stream); + sdp_state_capabilities_free(capabilities); + return NULL; + } + break; + case AST_MEDIA_TYPE_IMAGE: + state_stream->udptl = create_udptl(options); + if (!state_stream->udptl) { + sdp_state_stream_free(state_stream); + sdp_state_capabilities_free(capabilities); + return NULL; + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + /* Unsupported stream type already handled earlier */ + ast_assert(0); + break; } - break; - case AST_MEDIA_TYPE_UNKNOWN: - case AST_MEDIA_TYPE_TEXT: - case AST_MEDIA_TYPE_END: - ast_assert(0); - sdp_state_stream_free(state_stream); - sdp_state_capabilities_free(capabilities); - return NULL; } if (AST_VECTOR_APPEND(&capabilities->streams, state_stream)) { @@ -350,12 +427,12 @@ static struct sdp_state_capabilities *sdp_initialize_state_capabilities(const st * is allocated, this topology is used to create the proposed_capabilities. * * If we are the SDP offerer, then the proposed_capabilities are what are used - * to generate the SDP offer. When the SDP answer arrives, the proposed capabilities - * are merged with the SDP answer to create the negotiated capabilities. + * to generate the offer SDP. When the answer SDP arrives, the proposed capabilities + * are merged with the answer SDP to create the negotiated capabilities. * - * If we are the SDP answerer, then the incoming SDP offer is merged with our + * If we are the SDP answerer, then the incoming offer SDP is merged with our * proposed capabilities to to create the negotiated capabilities. These negotiated - * capabilities are what we send in our SDP answer. + * capabilities are what we send in our answer SDP. * * Any changes that a user of the API performs will occur on the proposed capabilities. * The negotiated capabilities are only altered based on actual SDP negotiation. This is @@ -367,17 +444,33 @@ struct ast_sdp_state { struct sdp_state_capabilities *negotiated_capabilities; /*! Proposed capabilities */ struct sdp_state_capabilities *proposed_capabilities; - /*! Local SDP. Generated via the options and currently negotiated/proposed capabilities. */ + /*! + * \brief New topology waiting to be merged. + * + * \details + * Repeated topology updates are merged into each other here until + * negotiations are restarted and we create an offer. + */ + struct ast_stream_topology *pending_topology_update; + /*! Local SDP. Generated via the options and negotiated/proposed capabilities. */ struct ast_sdp *local_sdp; + /*! Saved remote SDP */ + struct ast_sdp *remote_sdp; /*! SDP options. Configured options beyond media capabilities. */ struct ast_sdp_options *options; /*! Translator that puts SDPs into the expected representation */ struct ast_sdp_translator *translator; + /*! An explicit global connection address */ + struct ast_sockaddr connection_address; /*! The role that we occupy in SDP negotiation */ enum ast_sdp_role role; + /*! TRUE if all streams on hold by local side */ + unsigned int locally_held:1; + /*! TRUE if the remote offer resulted in all streams being declined. */ + unsigned int remote_offer_rejected:1; }; -struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, +struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *topology, struct ast_sdp_options *options) { struct ast_sdp_state *sdp_state; @@ -395,7 +488,7 @@ struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, return NULL; } - sdp_state->proposed_capabilities = sdp_initialize_state_capabilities(streams, options); + sdp_state->proposed_capabilities = sdp_initialize_state_capabilities(topology, options); if (!sdp_state->proposed_capabilities) { ast_sdp_state_free(sdp_state); return NULL; @@ -414,12 +507,217 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state) sdp_state_capabilities_free(sdp_state->negotiated_capabilities); sdp_state_capabilities_free(sdp_state->proposed_capabilities); - ast_sdp_free(sdp_state->local_sdp); + ao2_cleanup(sdp_state->local_sdp); + ao2_cleanup(sdp_state->remote_sdp); ast_sdp_options_free(sdp_state->options); ast_sdp_translator_free(sdp_state->translator); ast_free(sdp_state); } +/*! + * \internal + * \brief Allow a configured callback to alter the new negotiated joint topology. + * \since 15.0.0 + * + * \details + * The callback can alter topology stream names, formats, or decline streams. + * + * \param sdp_state + * \param topology Joint topology that we intend to generate the answer SDP. + * + * \return Nothing + */ +static void sdp_state_cb_answerer_modify_topology(const struct ast_sdp_state *sdp_state, + struct ast_stream_topology *topology) +{ + ast_sdp_answerer_modify_cb cb; + + cb = ast_sdp_options_get_answerer_modify_cb(sdp_state->options); + if (cb) { + void *context; + const struct ast_stream_topology *neg_topology;/*!< Last negotiated topology */ +#ifdef AST_DEVMODE + struct ast_stream *stream; + int idx; + enum ast_media_type type[ast_stream_topology_get_count(topology)]; + enum ast_stream_state state[ast_stream_topology_get_count(topology)]; + + /* + * Save stream types and states to validate that they don't + * get changed unexpectedly. + */ + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) { + stream = ast_stream_topology_get_stream(topology, idx); + type[idx] = ast_stream_get_type(stream); + state[idx] = ast_stream_get_state(stream); + } +#endif + + context = ast_sdp_options_get_state_context(sdp_state->options); + neg_topology = sdp_state->negotiated_capabilities + ? sdp_state->negotiated_capabilities->topology : NULL; + cb(context, neg_topology, topology); + +#ifdef AST_DEVMODE + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) { + stream = ast_stream_topology_get_stream(topology, idx); + + /* Check that active streams have at least one format */ + ast_assert(ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED + || (ast_stream_get_formats(stream) + && ast_format_cap_count(ast_stream_get_formats(stream)))); + + /* Check that stream types didn't change. */ + ast_assert(type[idx] == ast_stream_get_type(stream)); + + /* Check that streams didn't get resurected. */ + ast_assert(state[idx] != AST_STREAM_STATE_REMOVED + || ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED); + } +#endif + } +} + +/*! + * \internal + * \brief Allow a configured callback to alter the merged local topology. + * \since 15.0.0 + * + * \details + * The callback can modify streams in the merged topology. The + * callback can decline, add/remove/update formats, or rename + * streams. Changing anything else on the streams is likely to not + * end well. + * + * \param sdp_state + * \param topology Merged topology that we intend to generate the offer SDP. + * + * \return Nothing + */ +static void sdp_state_cb_offerer_modify_topology(const struct ast_sdp_state *sdp_state, + struct ast_stream_topology *topology) +{ + ast_sdp_offerer_modify_cb cb; + + cb = ast_sdp_options_get_offerer_modify_cb(sdp_state->options); + if (cb) { + void *context; + const struct ast_stream_topology *neg_topology;/*!< Last negotiated topology */ + + context = ast_sdp_options_get_state_context(sdp_state->options); + neg_topology = sdp_state->negotiated_capabilities + ? sdp_state->negotiated_capabilities->topology : NULL; + cb(context, neg_topology, topology); + +#ifdef AST_DEVMODE + { + struct ast_stream *stream; + int idx; + + /* Check that active streams have at least one format */ + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) { + stream = ast_stream_topology_get_stream(topology, idx); + ast_assert(ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED + || (ast_stream_get_formats(stream) + && ast_format_cap_count(ast_stream_get_formats(stream)))); + } + } +#endif + } +} + +/*! + * \internal + * \brief Allow a configured callback to configure the merged local topology. + * \since 15.0.0 + * + * \details + * The callback can configure other parameters associated with each + * active stream on the topology. The callback can call several SDP + * API calls to configure the proposed capabilities of the streams + * before we create the offer SDP. For example, the callback could + * configure a stream specific connection address, T.38 parameters, + * RTP instance, or UDPTL instance parameters. + * + * \param sdp_state + * \param topology Merged topology that we intend to generate the offer SDP. + * + * \return Nothing + */ +static void sdp_state_cb_offerer_config_topology(const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *topology) +{ + ast_sdp_offerer_config_cb cb; + + cb = ast_sdp_options_get_offerer_config_cb(sdp_state->options); + if (cb) { + void *context; + + context = ast_sdp_options_get_state_context(sdp_state->options); + cb(context, topology); + } +} + +/*! + * \internal + * \brief Call any registered pre-apply topology callback. + * \since 15.0.0 + * + * \param sdp_state + * \param topology + * + * \return Nothing + */ +static void sdp_state_cb_preapply_topology(const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *topology) +{ + ast_sdp_preapply_cb cb; + + cb = ast_sdp_options_get_preapply_cb(sdp_state->options); + if (cb) { + void *context; + + context = ast_sdp_options_get_state_context(sdp_state->options); + cb(context, topology); + } +} + +/*! + * \internal + * \brief Call any registered post-apply topology callback. + * \since 15.0.0 + * + * \param sdp_state + * \param topology + * + * \return Nothing + */ +static void sdp_state_cb_postapply_topology(const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *topology) +{ + ast_sdp_postapply_cb cb; + + cb = ast_sdp_options_get_postapply_cb(sdp_state->options); + if (cb) { + void *context; + + context = ast_sdp_options_get_state_context(sdp_state->options); + cb(context, topology); + } +} + +static const struct sdp_state_capabilities *sdp_state_get_joint_capabilities( + const struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state != NULL); + + if (sdp_state->negotiated_capabilities) { + return sdp_state->negotiated_capabilities; + } + + return sdp_state->proposed_capabilities; +} + static struct sdp_state_stream *sdp_state_get_stream(const struct ast_sdp_state *sdp_state, int stream_index) { if (stream_index >= AST_VECTOR_SIZE(&sdp_state->proposed_capabilities->streams)) { @@ -429,6 +727,18 @@ static struct sdp_state_stream *sdp_state_get_stream(const struct ast_sdp_state return AST_VECTOR_GET(&sdp_state->proposed_capabilities->streams, stream_index); } +static struct sdp_state_stream *sdp_state_get_joint_stream(const struct ast_sdp_state *sdp_state, int stream_index) +{ + const struct sdp_state_capabilities *capabilities; + + capabilities = sdp_state_get_joint_capabilities(sdp_state); + if (AST_VECTOR_SIZE(&capabilities->streams) <= stream_index) { + return NULL; + } + + return AST_VECTOR_GET(&capabilities->streams, stream_index); +} + struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( const struct ast_sdp_state *sdp_state, int stream_index) { @@ -468,35 +778,34 @@ const struct ast_sockaddr *ast_sdp_state_get_connection_address(const struct ast { ast_assert(sdp_state != NULL); - return &sdp_state->proposed_capabilities->connection_address; + return &sdp_state->connection_address; } -int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_state, - int stream_index, struct ast_sockaddr *address) +static int sdp_state_stream_get_connection_address(const struct ast_sdp_state *sdp_state, + struct sdp_state_stream *stream_state, struct ast_sockaddr *address) { - struct sdp_state_stream *stream_state; - ast_assert(sdp_state != NULL); + ast_assert(stream_state != NULL); ast_assert(address != NULL); - stream_state = sdp_state_get_stream(sdp_state, stream_index); - if (!stream_state) { - return -1; - } - /* If an explicit connection address has been provided for the stream return it */ if (!ast_sockaddr_isnull(&stream_state->connection_address)) { ast_sockaddr_copy(address, &stream_state->connection_address); return 0; } - switch (ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->proposed_capabilities->topology, - stream_index))) { + switch (stream_state->type) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: + if (!stream_state->rtp->instance) { + return -1; + } ast_rtp_instance_get_local_address(stream_state->rtp->instance, address); break; case AST_MEDIA_TYPE_IMAGE: + if (!stream_state->udptl->instance) { + return -1; + } ast_udptl_get_us(stream_state->udptl->instance, address); break; case AST_MEDIA_TYPE_UNKNOWN: @@ -505,27 +814,45 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_ return -1; } + if (ast_sockaddr_isnull(address)) { + /* No address is set on the stream state. */ + return -1; + } + /* If an explicit global connection address is set use it here for the IP part */ - if (!ast_sockaddr_isnull(&sdp_state->proposed_capabilities->connection_address)) { + if (!ast_sockaddr_isnull(&sdp_state->connection_address)) { int port = ast_sockaddr_port(address); - ast_sockaddr_copy(address, &sdp_state->proposed_capabilities->connection_address); + ast_sockaddr_copy(address, &sdp_state->connection_address); ast_sockaddr_set_port(address, port); } return 0; } -const struct ast_stream_topology *ast_sdp_state_get_joint_topology( - const struct ast_sdp_state *sdp_state) +int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_state, + int stream_index, struct ast_sockaddr *address) { + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL); + ast_assert(address != NULL); - if (sdp_state->negotiated_capabilities) { - return sdp_state->negotiated_capabilities->topology; + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return -1; } - return sdp_state->proposed_capabilities->topology; + return sdp_state_stream_get_connection_address(sdp_state, stream_state, address); +} + +const struct ast_stream_topology *ast_sdp_state_get_joint_topology( + const struct ast_sdp_state *sdp_state) +{ + const struct sdp_state_capabilities *capabilities; + + capabilities = sdp_state_get_joint_capabilities(sdp_state); + return capabilities->topology; } const struct ast_stream_topology *ast_sdp_state_get_local_topology( @@ -544,50 +871,185 @@ const struct ast_sdp_options *ast_sdp_state_get_options( return sdp_state->options; } +static struct ast_stream *decline_stream(enum ast_media_type type, const char *name) +{ + struct ast_stream *stream; + + if (!name) { + name = ast_codec_media_type2str(type); + } + stream = ast_stream_alloc(name, type); + if (!stream) { + return NULL; + } + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + return stream; +} + +/*! + * \brief Merge an update stream into a local stream. + * + * \param options SDP Options + * \param update An updated stream + * + * \retval NULL An error occurred + * \retval non-NULL The joint stream created + */ +static struct ast_stream *merge_local_stream(const struct ast_sdp_options *options, + const struct ast_stream *update) +{ + struct ast_stream *joint_stream; + struct ast_format_cap *joint_cap; + struct ast_format_cap *allowed_cap; + struct ast_format_cap *update_cap; + enum ast_stream_state joint_state; + + joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!joint_cap) { + return NULL; + } + + update_cap = ast_stream_get_formats(update); + allowed_cap = ast_sdp_options_get_format_cap_type(options, + ast_stream_get_type(update)); + if (allowed_cap && update_cap) { + struct ast_str *allowed_buf = ast_str_alloca(128); + struct ast_str *update_buf = ast_str_alloca(128); + struct ast_str *joint_buf = ast_str_alloca(128); + + ast_format_cap_get_compatible(allowed_cap, update_cap, joint_cap); + ast_debug(3, + "Filtered update '%s' with allowed '%s' to get joint '%s'. Joint has %zu formats\n", + ast_format_cap_get_names(update_cap, &update_buf), + ast_format_cap_get_names(allowed_cap, &allowed_buf), + ast_format_cap_get_names(joint_cap, &joint_buf), + ast_format_cap_count(joint_cap)); + } + + /* Determine the joint stream state */ + joint_state = AST_STREAM_STATE_REMOVED; + if (ast_stream_get_state(update) != AST_STREAM_STATE_REMOVED + && ast_format_cap_count(joint_cap)) { + joint_state = AST_STREAM_STATE_SENDRECV; + } + + joint_stream = ast_stream_alloc(ast_stream_get_name(update), + ast_stream_get_type(update)); + if (joint_stream) { + ast_stream_set_state(joint_stream, joint_state); + if (joint_state != AST_STREAM_STATE_REMOVED) { + ast_stream_set_formats(joint_stream, joint_cap); + } + } + + ao2_ref(joint_cap, -1); + + return joint_stream; +} + /*! - * \brief Merge two streams into a joint stream. + * \brief Merge a remote stream into a local stream. * - * \param local Our local stream + * \param sdp_state + * \param local Our local stream (NULL if creating new stream) + * \param locally_held Nonzero if the local stream is held * \param remote A remote stream * * \retval NULL An error occurred * \retval non-NULL The joint stream created */ -static struct ast_stream *merge_streams(const struct ast_stream *local, +static struct ast_stream *merge_remote_stream(const struct ast_sdp_state *sdp_state, + const struct ast_stream *local, unsigned int locally_held, const struct ast_stream *remote) { struct ast_stream *joint_stream; struct ast_format_cap *joint_cap; struct ast_format_cap *local_cap; struct ast_format_cap *remote_cap; - struct ast_str *local_buf = ast_str_alloca(128); - struct ast_str *remote_buf = ast_str_alloca(128); - struct ast_str *joint_buf = ast_str_alloca(128); - - joint_stream = ast_stream_alloc(ast_codec_media_type2str(ast_stream_get_type(remote)), - ast_stream_get_type(remote)); - if (!joint_stream) { - return NULL; - } + const char *joint_name; + enum ast_stream_state joint_state; + enum ast_stream_state remote_state; joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!joint_cap) { - ast_stream_free(joint_stream); return NULL; } - local_cap = ast_stream_get_formats(local); remote_cap = ast_stream_get_formats(remote); + if (local) { + local_cap = ast_stream_get_formats(local); + } else { + local_cap = ast_sdp_options_get_format_cap_type(sdp_state->options, + ast_stream_get_type(remote)); + } + if (local_cap && remote_cap) { + struct ast_str *local_buf = ast_str_alloca(128); + struct ast_str *remote_buf = ast_str_alloca(128); + struct ast_str *joint_buf = ast_str_alloca(128); + + ast_format_cap_get_compatible(local_cap, remote_cap, joint_cap); + ast_debug(3, + "Combined local '%s' with remote '%s' to get joint '%s'. Joint has %zu formats\n", + ast_format_cap_get_names(local_cap, &local_buf), + ast_format_cap_get_names(remote_cap, &remote_buf), + ast_format_cap_get_names(joint_cap, &joint_buf), + ast_format_cap_count(joint_cap)); + } + + /* Determine the joint stream state */ + remote_state = ast_stream_get_state(remote); + joint_state = AST_STREAM_STATE_REMOVED; + if ((!local || ast_stream_get_state(local) != AST_STREAM_STATE_REMOVED) + && ast_format_cap_count(joint_cap)) { + if (sdp_state->locally_held || locally_held) { + switch (remote_state) { + case AST_STREAM_STATE_REMOVED: + break; + case AST_STREAM_STATE_INACTIVE: + joint_state = AST_STREAM_STATE_INACTIVE; + break; + case AST_STREAM_STATE_SENDRECV: + joint_state = AST_STREAM_STATE_SENDONLY; + break; + case AST_STREAM_STATE_SENDONLY: + joint_state = AST_STREAM_STATE_INACTIVE; + break; + case AST_STREAM_STATE_RECVONLY: + joint_state = AST_STREAM_STATE_SENDONLY; + break; + } + } else { + switch (remote_state) { + case AST_STREAM_STATE_REMOVED: + break; + case AST_STREAM_STATE_INACTIVE: + joint_state = AST_STREAM_STATE_RECVONLY; + break; + case AST_STREAM_STATE_SENDRECV: + joint_state = AST_STREAM_STATE_SENDRECV; + break; + case AST_STREAM_STATE_SENDONLY: + joint_state = AST_STREAM_STATE_RECVONLY; + break; + case AST_STREAM_STATE_RECVONLY: + joint_state = AST_STREAM_STATE_SENDRECV; + break; + } + } + } - ast_format_cap_get_compatible(local_cap, remote_cap, joint_cap); - - ast_debug(3, "Combined local '%s' with remote '%s' to get joint '%s'. Joint has %zu formats\n", - ast_format_cap_get_names(local_cap, &local_buf), - ast_format_cap_get_names(remote_cap, &remote_buf), - ast_format_cap_get_names(joint_cap, &joint_buf), - ast_format_cap_count(joint_cap)); - - ast_stream_set_formats(joint_stream, joint_cap); + if (local) { + joint_name = ast_stream_get_name(local); + } else { + joint_name = ast_codec_media_type2str(ast_stream_get_type(remote)); + } + joint_stream = ast_stream_alloc(joint_name, ast_stream_get_type(remote)); + if (joint_stream) { + ast_stream_set_state(joint_stream, joint_state); + if (joint_state != AST_STREAM_STATE_REMOVED) { + ast_stream_set_formats(joint_stream, joint_cap); + } + } ao2_ref(joint_cap, -1); @@ -595,103 +1057,916 @@ static struct ast_stream *merge_streams(const struct ast_stream *local, } /*! - * \brief Get a local stream that corresponds with a remote stream. + * \internal + * \brief Determine if a merged topology should be rejected. + * \since 15.0.0 * - * \param local The local topology - * \param media_type The type of stream we are looking for - * \param[in,out] media_indices Keeps track of where to start searching in the topology + * \param topology What topology to determine if we reject * - * \retval -1 No corresponding stream found - * \retval index The corresponding stream index + * \retval 0 if not rejected. + * \retval non-zero if rejected. */ -static int get_corresponding_index(const struct ast_stream_topology *local, - enum ast_media_type media_type, int *media_indices) +static int sdp_topology_is_rejected(struct ast_stream_topology *topology) { - int i; - - for (i = media_indices[media_type]; i < ast_stream_topology_get_count(local); ++i) { - struct ast_stream *candidate; + int idx; + struct ast_stream *stream; - candidate = ast_stream_topology_get_stream(local, i); - if (ast_stream_get_type(candidate) == media_type) { - media_indices[media_type] = i + 1; - return i; + for (idx = ast_stream_topology_get_count(topology); idx--;) { + stream = ast_stream_topology_get_stream(topology, idx); + if (ast_stream_get_state(stream) != AST_STREAM_STATE_REMOVED) { + /* At least one stream is not declined */ + return 0; } } - /* No stream of the type left in the topology */ - media_indices[media_type] = i; - return -1; + /* All streams are declined */ + return 1; +} + +static void sdp_state_stream_copy_common(struct sdp_state_stream *dst, const struct sdp_state_stream *src) +{ + ast_sockaddr_copy(&dst->connection_address, + &src->connection_address); + /* Explicitly does not copy the local or remote hold states. */ + dst->t38_local_params = src->t38_local_params; +} + +static void sdp_state_stream_copy(struct sdp_state_stream *dst, const struct sdp_state_stream *src) +{ + *dst = *src; + + switch (dst->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + ao2_bump(dst->rtp); + break; + case AST_MEDIA_TYPE_IMAGE: + ao2_bump(dst->udptl); + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; + } +} + +/*! + * \internal + * \brief Initialize an int vector and default the contents to the member index. + * \since 15.0.0 + * + * \param vect Vetctor to initialize and set to default values. + * \param size Size of the vector to setup. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +static int sdp_vect_idx_init(struct ast_vector_int *vect, size_t size) +{ + int idx; + + if (AST_VECTOR_INIT(vect, size)) { + return -1; + } + for (idx = 0; idx < size; ++idx) { + AST_VECTOR_APPEND(vect, idx); + } + return 0; +} + +/*! + * \internal + * \brief Compare stream types for sort order. + * \since 15.0.0 + * + * \param left Stream parameter on left + * \param right Stream parameter on right + * + * \retval <0 left stream sorts first. + * \retval =0 streams match. + * \retval >0 right stream sorts first. + */ +static int sdp_stream_cmp_by_type(const struct ast_stream *left, const struct ast_stream *right) +{ + enum ast_media_type left_type = ast_stream_get_type(left); + enum ast_media_type right_type = ast_stream_get_type(right); + + /* Treat audio and image as the same for T.38 support */ + if (left_type == AST_MEDIA_TYPE_IMAGE) { + left_type = AST_MEDIA_TYPE_AUDIO; + } + if (right_type == AST_MEDIA_TYPE_IMAGE) { + right_type = AST_MEDIA_TYPE_AUDIO; + } + + return left_type - right_type; +} + +/*! + * \internal + * \brief Compare stream names and types for sort order. + * \since 15.0.0 + * + * \param left Stream parameter on left + * \param right Stream parameter on right + * + * \retval <0 left stream sorts first. + * \retval =0 streams match. + * \retval >0 right stream sorts first. + */ +static int sdp_stream_cmp_by_name(const struct ast_stream *left, const struct ast_stream *right) +{ + int cmp; + const char *left_name; + + left_name = ast_stream_get_name(left); + cmp = strcmp(left_name, ast_stream_get_name(right)); + if (!cmp) { + cmp = sdp_stream_cmp_by_type(left, right); + if (!cmp) { + /* Are the stream names real or type names which aren't matchable? */ + if (ast_strlen_zero(left_name) + || !strcmp(left_name, ast_codec_media_type2str(ast_stream_get_type(left))) + || !strcmp(left_name, ast_codec_media_type2str(ast_stream_get_type(right)))) { + /* The streams don't actually have real names */ + cmp = -1; + } + } + } + return cmp; +} + +/*! + * \internal + * \brief Merge topology streams by the match function. + * \since 15.0.0 + * + * \param sdp_state + * \param current_topology Topology to update with state. + * \param update_topology Topology to merge into the current topology. + * \param current_vect Stream index vector of remaining current_topology streams. + * \param update_vect Stream index vector of remaining update_topology streams. + * \param backfill_candidate Array of flags marking current_topology streams + * that can be reused for a different stream. + * \param match Stream comparison function to identify corresponding streams + * between the current_topology and update_topology. + * \param merged_topology Output topology of merged streams. + * \param compact_streams TRUE if backfill and limit number of streams. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +static int sdp_merge_streams_match( + const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *current_topology, + const struct ast_stream_topology *update_topology, + struct ast_vector_int *current_vect, + struct ast_vector_int *update_vect, + char backfill_candidate[], + int (*match)(const struct ast_stream *left, const struct ast_stream *right), + struct ast_stream_topology *merged_topology, + int compact_streams) +{ + struct ast_stream *current_stream; + struct ast_stream *update_stream; + int current_idx; + int update_idx; + int idx; + + for (current_idx = 0; current_idx < AST_VECTOR_SIZE(current_vect);) { + idx = AST_VECTOR_GET(current_vect, current_idx); + current_stream = ast_stream_topology_get_stream(current_topology, idx); + + for (update_idx = 0; update_idx < AST_VECTOR_SIZE(update_vect); ++update_idx) { + idx = AST_VECTOR_GET(update_vect, update_idx); + update_stream = ast_stream_topology_get_stream(update_topology, idx); + + if (match(current_stream, update_stream)) { + continue; + } + + if (!compact_streams + || ast_stream_get_state(current_stream) != AST_STREAM_STATE_REMOVED + || ast_stream_get_state(update_stream) != AST_STREAM_STATE_REMOVED) { + struct ast_stream *merged_stream; + + merged_stream = merge_local_stream(sdp_state->options, update_stream); + if (!merged_stream) { + return -1; + } + idx = AST_VECTOR_GET(current_vect, current_idx); + ast_stream_topology_set_stream(merged_topology, idx, merged_stream); + + /* + * The current_stream cannot be considered a backfill_candidate + * anymore since it got updated. + * + * XXX It could be argued that if the declined status didn't + * change because the merged_stream became declined then we + * shouldn't remove the stream slot as a backfill_candidate + * and we shouldn't update the merged_topology stream. If we + * then backfilled the stream we would likely mess up the core + * if it is matching streams by type since the core attempted + * to update the stream with an incompatible stream. Any + * backfilled streams could cause a stream type ordering + * problem. However, we do need to reclaim declined stream + * slots sometime. + */ + backfill_candidate[idx] = 0; + } + + AST_VECTOR_REMOVE_ORDERED(current_vect, current_idx); + AST_VECTOR_REMOVE_ORDERED(update_vect, update_idx); + goto matched_next; + } + + ++current_idx; +matched_next:; + } + return 0; +} + +/*! + * \internal + * \brief Merge the current local topology with an updated topology. + * \since 15.0.0 + * + * \param sdp_state + * \param current_topology Topology to update with state. + * \param update_topology Topology to merge into the current topology. + * \param compact_streams TRUE if backfill and limit number of streams. + * + * \retval merged topology on success. + * \retval NULL on failure. + */ +static struct ast_stream_topology *merge_local_topologies( + const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *current_topology, + const struct ast_stream_topology *update_topology, + int compact_streams) +{ + struct ast_stream_topology *merged_topology; + struct ast_stream *current_stream; + struct ast_stream *update_stream; + struct ast_stream *merged_stream; + struct ast_vector_int current_vect; + struct ast_vector_int update_vect; + int current_idx = ast_stream_topology_get_count(current_topology); + int update_idx; + int idx; + char backfill_candidate[current_idx]; + + memset(backfill_candidate, 0, current_idx); + + if (compact_streams) { + /* Limit matching consideration to the maximum allowed live streams. */ + idx = ast_sdp_options_get_max_streams(sdp_state->options); + if (idx < current_idx) { + current_idx = idx; + } + } + if (sdp_vect_idx_init(¤t_vect, current_idx)) { + return NULL; + } + + if (sdp_vect_idx_init(&update_vect, ast_stream_topology_get_count(update_topology))) { + AST_VECTOR_FREE(¤t_vect); + return NULL; + } + + merged_topology = ast_stream_topology_clone(current_topology); + if (!merged_topology) { + goto fail; + } + + /* + * Remove any unsupported current streams from match consideration + * and mark potential backfill candidates. + */ + for (current_idx = AST_VECTOR_SIZE(¤t_vect); current_idx--;) { + idx = AST_VECTOR_GET(¤t_vect, current_idx); + current_stream = ast_stream_topology_get_stream(current_topology, idx); + if (ast_stream_get_state(current_stream) == AST_STREAM_STATE_REMOVED + && compact_streams) { + /* The declined stream is a potential backfill candidate */ + backfill_candidate[idx] = 1; + } + if (sdp_is_stream_type_supported(ast_stream_get_type(current_stream))) { + continue; + } + /* Unsupported current streams should always be declined */ + ast_assert(ast_stream_get_state(current_stream) == AST_STREAM_STATE_REMOVED); + + AST_VECTOR_REMOVE_ORDERED(¤t_vect, current_idx); + } + + /* Remove any unsupported update streams from match consideration. */ + for (update_idx = AST_VECTOR_SIZE(&update_vect); update_idx--;) { + idx = AST_VECTOR_GET(&update_vect, update_idx); + update_stream = ast_stream_topology_get_stream(update_topology, idx); + if (sdp_is_stream_type_supported(ast_stream_get_type(update_stream))) { + continue; + } + + AST_VECTOR_REMOVE_ORDERED(&update_vect, update_idx); + } + + /* Match by stream name and type */ + if (sdp_merge_streams_match(sdp_state, current_topology, update_topology, + ¤t_vect, &update_vect, backfill_candidate, sdp_stream_cmp_by_name, + merged_topology, compact_streams)) { + goto fail; + } + + /* Match by stream type */ + if (sdp_merge_streams_match(sdp_state, current_topology, update_topology, + ¤t_vect, &update_vect, backfill_candidate, sdp_stream_cmp_by_type, + merged_topology, compact_streams)) { + goto fail; + } + + /* Decline unmatched current stream slots */ + for (current_idx = AST_VECTOR_SIZE(¤t_vect); current_idx--;) { + idx = AST_VECTOR_GET(¤t_vect, current_idx); + current_stream = ast_stream_topology_get_stream(current_topology, idx); + + if (ast_stream_get_state(current_stream) == AST_STREAM_STATE_REMOVED) { + /* Stream is already declined. */ + continue; + } + + merged_stream = decline_stream(ast_stream_get_type(current_stream), + ast_stream_get_name(current_stream)); + if (!merged_stream) { + goto fail; + } + ast_stream_topology_set_stream(merged_topology, idx, merged_stream); + } + + /* Backfill new update stream slots into pre-existing declined current stream slots */ + while (AST_VECTOR_SIZE(&update_vect)) { + idx = ast_stream_topology_get_count(current_topology); + for (current_idx = 0; current_idx < idx; ++current_idx) { + if (backfill_candidate[current_idx]) { + break; + } + } + if (idx <= current_idx) { + /* No more backfill candidates remain. */ + break; + } + /* There should only be backfill stream slots when we are compact_streams */ + ast_assert(compact_streams); + + idx = AST_VECTOR_GET(&update_vect, 0); + update_stream = ast_stream_topology_get_stream(update_topology, idx); + AST_VECTOR_REMOVE_ORDERED(&update_vect, 0); + + if (ast_stream_get_state(update_stream) == AST_STREAM_STATE_REMOVED) { + /* New stream is already declined so don't bother adding it. */ + continue; + } + + merged_stream = merge_local_stream(sdp_state->options, update_stream); + if (!merged_stream) { + goto fail; + } + if (ast_stream_get_state(merged_stream) == AST_STREAM_STATE_REMOVED) { + /* New stream not compatible so don't bother adding it. */ + ast_stream_free(merged_stream); + continue; + } + + /* Add the new stream into the backfill stream slot. */ + ast_stream_topology_set_stream(merged_topology, current_idx, merged_stream); + backfill_candidate[current_idx] = 0; + } + + /* Append any remaining new update stream slots that can fit. */ + while (AST_VECTOR_SIZE(&update_vect) + && (!compact_streams + || ast_stream_topology_get_count(merged_topology) + < ast_sdp_options_get_max_streams(sdp_state->options))) { + idx = AST_VECTOR_GET(&update_vect, 0); + update_stream = ast_stream_topology_get_stream(update_topology, idx); + AST_VECTOR_REMOVE_ORDERED(&update_vect, 0); + + if (ast_stream_get_state(update_stream) == AST_STREAM_STATE_REMOVED) { + /* New stream is already declined so don't bother adding it. */ + continue; + } + + merged_stream = merge_local_stream(sdp_state->options, update_stream); + if (!merged_stream) { + goto fail; + } + if (ast_stream_get_state(merged_stream) == AST_STREAM_STATE_REMOVED) { + /* New stream not compatible so don't bother adding it. */ + ast_stream_free(merged_stream); + continue; + } + + /* Append the new update stream. */ + if (ast_stream_topology_append_stream(merged_topology, merged_stream) < 0) { + ast_stream_free(merged_stream); + goto fail; + } + } + + AST_VECTOR_FREE(¤t_vect); + AST_VECTOR_FREE(&update_vect); + return merged_topology; + +fail: + ast_stream_topology_free(merged_topology); + AST_VECTOR_FREE(¤t_vect); + AST_VECTOR_FREE(&update_vect); + return NULL; +} + +/*! + * \internal + * \brief Remove declined streams appended beyond orig_topology. + * \since 15.0.0 + * + * \param sdp_state + * \param orig_topology Negotiated or initial topology. + * \param new_topology New proposed topology. + * + * \return Nothing + */ +static void remove_appended_declined_streams(const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *orig_topology, + struct ast_stream_topology *new_topology) +{ + struct ast_stream *stream; + int orig_count; + int idx; + + orig_count = ast_stream_topology_get_count(orig_topology); + for (idx = ast_stream_topology_get_count(new_topology); orig_count < idx;) { + --idx; + stream = ast_stream_topology_get_stream(new_topology, idx); + if (ast_stream_get_state(stream) != AST_STREAM_STATE_REMOVED) { + continue; + } + ast_stream_topology_del_stream(new_topology, idx); + } +} + +/*! + * \internal + * \brief Setup a new state stream from a possibly existing state stream. + * \since 15.0.0 + * + * \param sdp_state + * \param new_state_stream What state stream to setup + * \param old_state_stream Source of previous state stream information. + * May be NULL. + * \param new_type Type of the new state stream. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +static int setup_new_stream_capabilities( + const struct ast_sdp_state *sdp_state, + struct sdp_state_stream *new_state_stream, + struct sdp_state_stream *old_state_stream, + enum ast_media_type new_type) +{ + if (old_state_stream) { + /* + * Copy everything potentially useful for a new stream state type + * from the old stream of a possible different type. + */ + sdp_state_stream_copy_common(new_state_stream, old_state_stream); + /* We also need to preserve the locally_held state for the new stream. */ + new_state_stream->locally_held = old_state_stream->locally_held; + } + new_state_stream->type = new_type; + + switch (new_type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + new_state_stream->rtp = create_rtp(sdp_state->options, new_type); + if (!new_state_stream->rtp) { + return -1; + } + break; + case AST_MEDIA_TYPE_IMAGE: + new_state_stream->udptl = create_udptl(sdp_state->options); + if (!new_state_stream->udptl) { + return -1; + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; + } + return 0; +} + +/*! + * \brief Merge existing stream capabilities and a new topology. + * + * \param sdp_state The state needing capabilities merged + * \param new_topology The topology to merge with our proposed capabilities + * + * \details + * + * This is a bit complicated. The idea is that we already have some + * capabilities set, and we've now been confronted with a new stream + * topology from the system. We want to take what we had before and + * merge them with the new topology from the system. + * + * According to the RFC, stream slots can change their types only if + * they are carrying the same logical information or an offer is + * reusing a declined slot or new stream slots are added to the end + * of the list. Switching a stream from audio to T.38 makes sense + * because the stream slot is carrying the same information just in a + * different format. + * + * We can setup new streams offered by the system up to our + * configured maximum stream slots. New stream slots requested over + * the maximum are discarded. + * + * \retval NULL An error occurred + * \retval non-NULL The merged capabilities + */ +static struct sdp_state_capabilities *merge_local_capabilities( + const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *new_topology) +{ + const struct sdp_state_capabilities *current = sdp_state->proposed_capabilities; + struct sdp_state_capabilities *merged_capabilities; + int idx; + + ast_assert(current != NULL); + + merged_capabilities = ast_calloc(1, sizeof(*merged_capabilities)); + if (!merged_capabilities) { + return NULL; + } + + merged_capabilities->topology = merge_local_topologies(sdp_state, current->topology, + new_topology, 1); + if (!merged_capabilities->topology) { + goto fail; + } + sdp_state_cb_offerer_modify_topology(sdp_state, merged_capabilities->topology); + remove_appended_declined_streams(sdp_state, current->topology, + merged_capabilities->topology); + + if (AST_VECTOR_INIT(&merged_capabilities->streams, + ast_stream_topology_get_count(merged_capabilities->topology))) { + goto fail; + } + + for (idx = 0; idx < ast_stream_topology_get_count(merged_capabilities->topology); ++idx) { + struct sdp_state_stream *merged_state_stream; + struct sdp_state_stream *current_state_stream; + struct ast_stream *merged_stream; + struct ast_stream *current_stream; + enum ast_media_type merged_stream_type; + enum ast_media_type current_stream_type; + + merged_state_stream = ast_calloc(1, sizeof(*merged_state_stream)); + if (!merged_state_stream) { + goto fail; + } + + merged_stream = ast_stream_topology_get_stream(merged_capabilities->topology, idx); + merged_stream_type = ast_stream_get_type(merged_stream); + + if (idx < ast_stream_topology_get_count(current->topology)) { + current_state_stream = AST_VECTOR_GET(¤t->streams, idx); + current_stream = ast_stream_topology_get_stream(current->topology, idx); + current_stream_type = ast_stream_get_type(current_stream); + } else { + /* The merged topology is adding a stream */ + current_state_stream = NULL; + current_stream = NULL; + current_stream_type = AST_MEDIA_TYPE_UNKNOWN; + } + + if (ast_stream_get_state(merged_stream) == AST_STREAM_STATE_REMOVED) { + if (current_state_stream) { + /* Copy everything potentially useful to a declined stream state. */ + sdp_state_stream_copy_common(merged_state_stream, current_state_stream); + } + merged_state_stream->type = merged_stream_type; + } else if (!current_stream + || ast_stream_get_state(current_stream) == AST_STREAM_STATE_REMOVED) { + /* This is a new stream */ + if (setup_new_stream_capabilities(sdp_state, merged_state_stream, + current_state_stream, merged_stream_type)) { + sdp_state_stream_free(merged_state_stream); + goto fail; + } + } else if (merged_stream_type == current_stream_type) { + /* Stream type is not changing. */ + sdp_state_stream_copy(merged_state_stream, current_state_stream); + } else { + /* + * Stream type is changing. Need to replace the stream. + * + * Unsupported streams should already be handled earlier because + * they are always declined. + */ + ast_assert(sdp_is_stream_type_supported(merged_stream_type)); + + /* + * XXX We might need to keep the old RTP instance if the new + * stream type is also RTP. We would just be changing between + * audio and video in that case. However we will create a new + * RTP instance anyway since its purpose has to be changing. + * Any RTP packets in flight from the old stream type might + * cause mischief. + */ + if (setup_new_stream_capabilities(sdp_state, merged_state_stream, + current_state_stream, merged_stream_type)) { + sdp_state_stream_free(merged_state_stream); + goto fail; + } + } + + if (AST_VECTOR_APPEND(&merged_capabilities->streams, merged_state_stream)) { + sdp_state_stream_free(merged_state_stream); + goto fail; + } + } + + return merged_capabilities; + +fail: + sdp_state_capabilities_free(merged_capabilities); + return NULL; +} + +static void merge_remote_stream_capabilities( + const struct ast_sdp_state *sdp_state, + struct sdp_state_stream *joint_state_stream, + struct sdp_state_stream *local_state_stream, + struct ast_stream *remote_stream) +{ + struct ast_rtp_codecs *codecs; + + *joint_state_stream = *local_state_stream; + /* + * Need to explicitly set the type to the remote because we could + * be changing the type between audio and video. + */ + joint_state_stream->type = ast_stream_get_type(remote_stream); + + switch (joint_state_stream->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + ao2_bump(joint_state_stream->rtp); + codecs = ast_stream_get_data(remote_stream, AST_STREAM_DATA_RTP_CODECS); + ast_assert(codecs != NULL); + if (sdp_state->role == SDP_ROLE_ANSWERER) { + /* + * Setup rx payload type mapping to prefer the mapping + * from the peer that the RFC says we SHOULD use. + */ + ast_rtp_codecs_payloads_xover(codecs, codecs, NULL); + } + ast_rtp_codecs_payloads_copy(codecs, + ast_rtp_instance_get_codecs(joint_state_stream->rtp->instance), + joint_state_stream->rtp->instance); + break; + case AST_MEDIA_TYPE_IMAGE: + joint_state_stream->udptl = ao2_bump(joint_state_stream->udptl); + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; + } +} + +static int create_remote_stream_capabilities( + const struct ast_sdp_state *sdp_state, + struct sdp_state_stream *joint_state_stream, + struct sdp_state_stream *local_state_stream, + struct ast_stream *remote_stream) +{ + struct ast_rtp_codecs *codecs; + + /* We can only create streams if we are the answerer */ + ast_assert(sdp_state->role == SDP_ROLE_ANSWERER); + + if (local_state_stream) { + /* + * Copy everything potentially useful for a new stream state type + * from the old stream of a possible different type. + */ + sdp_state_stream_copy_common(joint_state_stream, local_state_stream); + /* We also need to preserve the locally_held state for the new stream. */ + joint_state_stream->locally_held = local_state_stream->locally_held; + } + joint_state_stream->type = ast_stream_get_type(remote_stream); + + switch (joint_state_stream->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + joint_state_stream->rtp = create_rtp(sdp_state->options, joint_state_stream->type); + if (!joint_state_stream->rtp) { + return -1; + } + + /* + * Setup rx payload type mapping to prefer the mapping + * from the peer that the RFC says we SHOULD use. + */ + codecs = ast_stream_get_data(remote_stream, AST_STREAM_DATA_RTP_CODECS); + ast_assert(codecs != NULL); + ast_rtp_codecs_payloads_xover(codecs, codecs, NULL); + ast_rtp_codecs_payloads_copy(codecs, + ast_rtp_instance_get_codecs(joint_state_stream->rtp->instance), + joint_state_stream->rtp->instance); + break; + case AST_MEDIA_TYPE_IMAGE: + joint_state_stream->udptl = create_udptl(sdp_state->options); + if (!joint_state_stream->udptl) { + return -1; + } + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; + } + return 0; +} + +/*! + * \internal + * \brief Create a joint topology from the remote topology. + * \since 15.0.0 + * + * \param sdp_state The state needing capabilities merged. + * \param local Capabilities to merge the remote topology into. + * \param remote_topology The topology to merge with our local capabilities. + * + * \retval joint topology on success. + * \retval NULL on failure. + */ +static struct ast_stream_topology *merge_remote_topology( + const struct ast_sdp_state *sdp_state, + const struct sdp_state_capabilities *local, + const struct ast_stream_topology *remote_topology) +{ + struct ast_stream_topology *joint_topology; + int idx; + + joint_topology = ast_stream_topology_alloc(); + if (!joint_topology) { + return NULL; + } + + for (idx = 0; idx < ast_stream_topology_get_count(remote_topology); ++idx) { + enum ast_media_type local_stream_type; + enum ast_media_type remote_stream_type; + struct ast_stream *remote_stream; + struct ast_stream *local_stream; + struct ast_stream *joint_stream; + struct sdp_state_stream *local_state_stream; + + remote_stream = ast_stream_topology_get_stream(remote_topology, idx); + remote_stream_type = ast_stream_get_type(remote_stream); + + if (idx < ast_stream_topology_get_count(local->topology)) { + local_state_stream = AST_VECTOR_GET(&local->streams, idx); + local_stream = ast_stream_topology_get_stream(local->topology, idx); + local_stream_type = ast_stream_get_type(local_stream); + } else { + /* The remote is adding a stream slot */ + local_state_stream = NULL; + local_stream = NULL; + local_stream_type = AST_MEDIA_TYPE_UNKNOWN; + + if (sdp_state->role != SDP_ROLE_ANSWERER) { + /* Remote cannot add a new stream slot in an answer SDP */ + ast_debug(1, + "Bad. Ignoring new %s stream slot remote answer SDP trying to add.\n", + ast_codec_media_type2str(remote_stream_type)); + continue; + } + } + + if (local_stream + && ast_stream_get_state(local_stream) != AST_STREAM_STATE_REMOVED) { + if (remote_stream_type == local_stream_type) { + /* Stream type is not changing. */ + joint_stream = merge_remote_stream(sdp_state, local_stream, + local_state_stream->locally_held, remote_stream); + } else if (sdp_state->role == SDP_ROLE_ANSWERER) { + /* Stream type is changing. */ + joint_stream = merge_remote_stream(sdp_state, NULL, + local_state_stream->locally_held, remote_stream); + } else { + /* + * Remote cannot change the stream type we offered. + * Mark as declined. + */ + ast_debug(1, + "Bad. Remote answer SDP trying to change the stream type from %s to %s.\n", + ast_codec_media_type2str(local_stream_type), + ast_codec_media_type2str(remote_stream_type)); + joint_stream = decline_stream(local_stream_type, + ast_stream_get_name(local_stream)); + } + } else { + /* Local stream is either dead/declined or nonexistent. */ + if (sdp_state->role == SDP_ROLE_ANSWERER) { + if (sdp_is_stream_type_supported(remote_stream_type) + && ast_stream_get_state(remote_stream) != AST_STREAM_STATE_REMOVED + && idx < ast_sdp_options_get_max_streams(sdp_state->options)) { + /* Try to create the new stream */ + joint_stream = merge_remote_stream(sdp_state, NULL, + local_state_stream ? local_state_stream->locally_held : 0, + remote_stream); + } else { + const char *stream_name; + + /* Decline the remote stream. */ + if (local_stream + && local_stream_type == remote_stream_type) { + /* Preserve the previous stream name */ + stream_name = ast_stream_get_name(local_stream); + } else { + stream_name = NULL; + } + joint_stream = decline_stream(remote_stream_type, stream_name); + } + } else { + /* Decline the stream. */ + if (DEBUG_ATLEAST(1) + && ast_stream_get_state(remote_stream) != AST_STREAM_STATE_REMOVED) { + /* + * Remote cannot request a new stream in place of a declined + * stream in an answer SDP. + */ + ast_log(LOG_DEBUG, + "Bad. Remote answer SDP trying to use a declined stream slot for %s.\n", + ast_codec_media_type2str(remote_stream_type)); + } + joint_stream = decline_stream(local_stream_type, + ast_stream_get_name(local_stream)); + } + } + + if (!joint_stream) { + goto fail; + } + if (ast_stream_topology_append_stream(joint_topology, joint_stream) < 0) { + ast_stream_free(joint_stream); + goto fail; + } + } + + return joint_topology; + +fail: + ast_stream_topology_free(joint_topology); + return NULL; } /*! - * XXX TODO The merge_capabilities() function needs to be split into - * merging for new local topologies and new remote topologies. Also - * the possibility of changing the stream types needs consideration. - * Audio to video may or may not need us to keep the same RTP instance - * because the stream position is still RTP. A new RTP instance would - * cause us to change ports. Audio to image is definitely going to - * happen for T.38. - * - * A new remote topology as an initial offer needs to dictate the - * number of streams and the order. As a sdp_state option we may - * allow creation of new active streams not defined by the current - * local topology. A subsequent remote offer can change the stream - * types and add streams. The sdp_state option could regulate - * creation of new active streams here as well. An answer cannot - * change stream types or the number of streams but can decline - * streams. Any attempt to do so should report an error and possibly - * disconnect the call. - * - * A local topology update needs to be merged differently. It cannot - * reduce the number of streams already defined without violating the - * SDP RFC. The local merge could take the new topology stream - * verbatim and add declined streams to fill out any shortfall with - * the exiting topology. This strategy is needed if we want to change - * an audio stream to an image stream for T.38 fax and vice versa. - * The local merge could take the new topology and map the streams to - * the existing local topology. The new topology stream format caps - * would be copied into the merged topology so we could change what - * codecs are negotiated. - */ -/*! - * \brief Merge existing stream capabilities and a new topology into joint capabilities. + * \brief Merge our stream capabilities and a remote topology into joint capabilities. * * \param sdp_state The state needing capabilities merged - * \param new_topology The new topology to base merged capabilities on - * \param is_local If new_topology is a local update. + * \param remote_topology The topology to merge with our proposed capabilities * * \details * This is a bit complicated. The idea is that we already have some - * capabilities set, and we've now been confronted with a new stream - * topology. We want to take what's been presented to us and merge - * those new capabilities with our own. - * - * For each of the new streams, we try to find a corresponding stream - * in our proposed capabilities. If we find one, then we get the - * compatible formats of the two streams and create a new stream with - * those formats set. We then will re-use the underlying media - * instance (such as an RTP instance) on this merged stream. - * - * The is_local parameter determines whether we should attempt to - * create new media instances. If we do not find a corresponding - * stream, then we create a new one. If the is_local parameter is - * true, this created stream is made a clone of the new stream, and a - * media instance is created. If the is_local parameter is not true, - * then the created stream has no formats set and no media instance is - * created for it. + * capabilities set, and we've now been confronted with a stream + * topology from the remote end. We want to take what's been + * presented to us and merge those new capabilities with our own. + * + * According to the RFC, stream slots can change their types only if + * they are carrying the same logical information or an offer is + * reusing a declined slot or new stream slots are added to the end + * of the list. Switching a stream from audio to T.38 makes sense + * because the stream slot is carrying the same information just in a + * different format. + * + * When we are the answerer we can setup new streams offered by the + * remote up to our configured maximum stream slots. New stream + * slots offered over the maximum are unconditionally declined. * * \retval NULL An error occurred * \retval non-NULL The merged capabilities */ -static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_state *sdp_state, - const struct ast_stream_topology *new_topology, int is_local) +static struct sdp_state_capabilities *merge_remote_capabilities( + const struct ast_sdp_state *sdp_state, + const struct ast_stream_topology *remote_topology) { const struct sdp_state_capabilities *local = sdp_state->proposed_capabilities; struct sdp_state_capabilities *joint_capabilities; - int media_indices[AST_MEDIA_TYPE_END] = {0}; - int i; - static const char dummy_name[] = "dummy"; + int idx; ast_assert(local != NULL); @@ -700,150 +1975,131 @@ static struct sdp_state_capabilities *merge_capabilities(const struct ast_sdp_st return NULL; } - joint_capabilities->topology = ast_stream_topology_alloc(); + joint_capabilities->topology = merge_remote_topology(sdp_state, local, remote_topology); if (!joint_capabilities->topology) { goto fail; } - if (AST_VECTOR_INIT(&joint_capabilities->streams, AST_VECTOR_SIZE(&local->streams))) { + if (sdp_state->role == SDP_ROLE_ANSWERER) { + sdp_state_cb_answerer_modify_topology(sdp_state, joint_capabilities->topology); + } + idx = ast_stream_topology_get_count(joint_capabilities->topology); + if (AST_VECTOR_INIT(&joint_capabilities->streams, idx)) { goto fail; } - ast_sockaddr_copy(&joint_capabilities->connection_address, &local->connection_address); - for (i = 0; i < ast_stream_topology_get_count(new_topology); ++i) { - enum ast_media_type new_stream_type; - struct ast_stream *new_stream; + for (idx = 0; idx < ast_stream_topology_get_count(remote_topology); ++idx) { + enum ast_media_type local_stream_type; + enum ast_media_type remote_stream_type; + struct ast_stream *remote_stream; struct ast_stream *local_stream; struct ast_stream *joint_stream; + struct sdp_state_stream *local_state_stream; struct sdp_state_stream *joint_state_stream; - int local_index; joint_state_stream = ast_calloc(1, sizeof(*joint_state_stream)); if (!joint_state_stream) { goto fail; } - new_stream = ast_stream_topology_get_stream(new_topology, i); - new_stream_type = ast_stream_get_type(new_stream); + remote_stream = ast_stream_topology_get_stream(remote_topology, idx); + remote_stream_type = ast_stream_get_type(remote_stream); - local_index = get_corresponding_index(local->topology, new_stream_type, media_indices); - if (0 <= local_index) { - local_stream = ast_stream_topology_get_stream(local->topology, local_index); - if (!strcmp(ast_stream_get_name(local_stream), dummy_name)) { - /* The local stream is a non-exixtent dummy stream. */ - local_stream = NULL; - } + if (idx < ast_stream_topology_get_count(local->topology)) { + local_state_stream = AST_VECTOR_GET(&local->streams, idx); + local_stream = ast_stream_topology_get_stream(local->topology, idx); + local_stream_type = ast_stream_get_type(local_stream); } else { + /* The remote is adding a stream slot */ + local_state_stream = NULL; local_stream = NULL; - } - if (local_stream) { - struct sdp_state_stream *local_state_stream; - struct ast_rtp_codecs *codecs; + local_stream_type = AST_MEDIA_TYPE_UNKNOWN; - if (is_local) { - /* Replace the local stream with the new local stream. */ - joint_stream = ast_stream_clone(new_stream, NULL); - } else { - joint_stream = merge_streams(local_stream, new_stream); - } - if (!joint_stream) { + if (sdp_state->role != SDP_ROLE_ANSWERER) { + /* Remote cannot add a new stream slot in an answer SDP */ sdp_state_stream_free(joint_state_stream); - goto fail; - } - - local_state_stream = AST_VECTOR_GET(&local->streams, local_index); - joint_state_stream->type = local_state_stream->type; - - switch (joint_state_stream->type) { - case AST_MEDIA_TYPE_AUDIO: - case AST_MEDIA_TYPE_VIDEO: - joint_state_stream->rtp = ao2_bump(local_state_stream->rtp); - if (is_local) { - break; - } - codecs = ast_stream_get_data(new_stream, AST_STREAM_DATA_RTP_CODECS); - ast_assert(codecs != NULL); - if (sdp_state->role == SDP_ROLE_ANSWERER) { - /* - * Setup rx payload type mapping to prefer the mapping - * from the peer that the RFC says we SHOULD use. - */ - ast_rtp_codecs_payloads_xover(codecs, codecs, NULL); - } - ast_rtp_codecs_payloads_copy(codecs, - ast_rtp_instance_get_codecs(joint_state_stream->rtp->instance), - joint_state_stream->rtp->instance); - break; - case AST_MEDIA_TYPE_IMAGE: - joint_state_stream->udptl = ao2_bump(local_state_stream->udptl); - joint_state_stream->t38_local_params = local_state_stream->t38_local_params; - break; - case AST_MEDIA_TYPE_UNKNOWN: - case AST_MEDIA_TYPE_TEXT: - case AST_MEDIA_TYPE_END: break; } + } - if (!ast_sockaddr_isnull(&local_state_stream->connection_address)) { - ast_sockaddr_copy(&joint_state_stream->connection_address, - &local_state_stream->connection_address); + joint_stream = ast_stream_topology_get_stream(joint_capabilities->topology, + idx); + + if (local_stream + && ast_stream_get_state(local_stream) != AST_STREAM_STATE_REMOVED) { + if (ast_stream_get_state(joint_stream) == AST_STREAM_STATE_REMOVED) { + /* Copy everything potentially useful to a declined stream state. */ + sdp_state_stream_copy_common(joint_state_stream, local_state_stream); + + joint_state_stream->type = ast_stream_get_type(joint_stream); + } else if (remote_stream_type == local_stream_type) { + /* Stream type is not changing. */ + merge_remote_stream_capabilities(sdp_state, joint_state_stream, + local_state_stream, remote_stream); + ast_assert(joint_state_stream->type == ast_stream_get_type(joint_stream)); } else { - ast_sockaddr_setnull(&joint_state_stream->connection_address); - } - joint_state_stream->locally_held = local_state_stream->locally_held; - } else if (is_local) { - /* We don't have a stream state that corresponds to the stream in the new topology, so - * create a stream state as appropriate. - */ - joint_stream = ast_stream_clone(new_stream, NULL); - if (!joint_stream) { - sdp_state_stream_free(joint_state_stream); - goto fail; - } - - switch (new_stream_type) { - case AST_MEDIA_TYPE_AUDIO: - case AST_MEDIA_TYPE_VIDEO: - joint_state_stream->rtp = create_rtp(sdp_state->options, - new_stream_type); - if (!joint_state_stream->rtp) { - ast_stream_free(joint_stream); - sdp_state_stream_free(joint_state_stream); - goto fail; - } - break; - case AST_MEDIA_TYPE_IMAGE: - joint_state_stream->udptl = create_udptl(sdp_state->options); - if (!joint_state_stream->udptl) { - ast_stream_free(joint_stream); + /* + * Stream type is changing. Need to replace the stream. + * + * XXX We might need to keep the old RTP instance if the new + * stream type is also RTP. We would just be changing between + * audio and video in that case. However we will create a new + * RTP instance anyway since its purpose has to be changing. + * Any RTP packets in flight from the old stream type might + * cause mischief. + */ + if (create_remote_stream_capabilities(sdp_state, joint_state_stream, + local_state_stream, remote_stream)) { sdp_state_stream_free(joint_state_stream); goto fail; } - break; - case AST_MEDIA_TYPE_UNKNOWN: - case AST_MEDIA_TYPE_TEXT: - case AST_MEDIA_TYPE_END: - break; + ast_assert(joint_state_stream->type == ast_stream_get_type(joint_stream)); } - ast_sockaddr_setnull(&joint_state_stream->connection_address); - joint_state_stream->locally_held = 0; } else { - /* We don't have a stream that corresponds to the stream in the new topology. Create a - * dummy stream to go in its place so that the resulting SDP created will contain - * the stream but will have no port or codecs set - */ - joint_stream = ast_stream_alloc(dummy_name, new_stream_type); - if (!joint_stream) { - sdp_state_stream_free(joint_state_stream); - goto fail; + /* Local stream is either dead/declined or nonexistent. */ + if (sdp_state->role == SDP_ROLE_ANSWERER) { + if (ast_stream_get_state(joint_stream) == AST_STREAM_STATE_REMOVED) { + if (local_state_stream) { + /* Copy everything potentially useful to a declined stream state. */ + sdp_state_stream_copy_common(joint_state_stream, local_state_stream); + } + joint_state_stream->type = ast_stream_get_type(joint_stream); + } else { + /* Try to create the new stream */ + if (create_remote_stream_capabilities(sdp_state, joint_state_stream, + local_state_stream, remote_stream)) { + sdp_state_stream_free(joint_state_stream); + goto fail; + } + ast_assert(joint_state_stream->type == ast_stream_get_type(joint_stream)); + } + } else { + /* Decline the stream. */ + ast_assert(ast_stream_get_state(joint_stream) == AST_STREAM_STATE_REMOVED); + if (local_state_stream) { + /* Copy everything potentially useful to a declined stream state. */ + sdp_state_stream_copy_common(joint_state_stream, local_state_stream); + } + joint_state_stream->type = ast_stream_get_type(joint_stream); } } - if (ast_stream_topology_append_stream(joint_capabilities->topology, joint_stream) < 0) { - ast_stream_free(joint_stream); - sdp_state_stream_free(joint_state_stream); - goto fail; + /* Determine if the remote placed the stream on hold. */ + joint_state_stream->remotely_held = 0; + if (ast_stream_get_state(joint_stream) != AST_STREAM_STATE_REMOVED) { + enum ast_stream_state remote_state; + + remote_state = ast_stream_get_state(remote_stream); + switch (remote_state) { + case AST_STREAM_STATE_INACTIVE: + case AST_STREAM_STATE_SENDONLY: + joint_state_stream->remotely_held = 1; + break; + default: + break; + } } + if (AST_VECTOR_APPEND(&joint_capabilities->streams, joint_state_stream)) { sdp_state_stream_free(joint_state_stream); goto fail; @@ -998,11 +2254,6 @@ static void update_rtp_after_merge(const struct ast_sdp_state *state, struct ast_sdp_c_line *c_line; struct ast_sockaddr *addrs; - if (!rtp) { - /* This is a dummy stream */ - return; - } - c_line = remote_m_line->c_line; if (!c_line) { c_line = remote_sdp->c_line; @@ -1058,11 +2309,6 @@ static void update_udptl_after_merge(const struct ast_sdp_state *state, struct s unsigned int fax_max_datagram; struct ast_sockaddr *addrs; - if (!udptl) { - /* This is a dummy stream */ - return; - } - a_line = ast_sdp_m_find_attribute(remote_m_line, "t38faxmaxdatagram", -1); if (!a_line) { a_line = ast_sdp_m_find_attribute(remote_m_line, "t38maxdatagram", -1); @@ -1102,6 +2348,49 @@ static void update_udptl_after_merge(const struct ast_sdp_state *state, struct s } } +static void sdp_apply_negotiated_state(struct ast_sdp_state *sdp_state) +{ + struct sdp_state_capabilities *capabilities = sdp_state->negotiated_capabilities; + int idx; + + if (!capabilities) { + /* Nothing to apply */ + return; + } + + sdp_state_cb_preapply_topology(sdp_state, capabilities->topology); + for (idx = 0; idx < AST_VECTOR_SIZE(&capabilities->streams); ++idx) { + struct sdp_state_stream *state_stream; + struct ast_stream *stream; + + stream = ast_stream_topology_get_stream(capabilities->topology, idx); + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + /* Stream is declined */ + continue; + } + + state_stream = AST_VECTOR_GET(&capabilities->streams, idx); + switch (ast_stream_get_type(stream)) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + update_rtp_after_merge(sdp_state, state_stream->rtp, sdp_state->options, + sdp_state->remote_sdp, ast_sdp_get_m(sdp_state->remote_sdp, idx)); + break; + case AST_MEDIA_TYPE_IMAGE: + update_udptl_after_merge(sdp_state, state_stream->udptl, sdp_state->options, + sdp_state->remote_sdp, ast_sdp_get_m(sdp_state->remote_sdp, idx)); + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + /* All unsupported streams are declined */ + ast_assert(0); + break; + } + } + sdp_state_cb_postapply_topology(sdp_state, capabilities->topology); +} + static void set_negotiated_capabilities(struct ast_sdp_state *sdp_state, struct sdp_state_capabilities *new_capabilities) { @@ -1120,6 +2409,81 @@ static void set_proposed_capabilities(struct ast_sdp_state *sdp_state, sdp_state_capabilities_free(old_capabilities); } +/*! + * \internal + * \brief Copy the new capabilities into the proposed capabilities. + * \since 15.0.0 + * + * \param sdp_state The current SDP state + * \param new_capabilities Capabilities to copy + * + * \retval 0 on success. + * \retval -1 on failure. + */ +static int update_proposed_capabilities(struct ast_sdp_state *sdp_state, + struct sdp_state_capabilities *new_capabilities) +{ + struct sdp_state_capabilities *proposed_capabilities; + int idx; + + proposed_capabilities = ast_calloc(1, sizeof(*proposed_capabilities)); + if (!proposed_capabilities) { + return -1; + } + + proposed_capabilities->topology = ast_stream_topology_clone(new_capabilities->topology); + if (!proposed_capabilities->topology) { + goto fail; + } + + if (AST_VECTOR_INIT(&proposed_capabilities->streams, + AST_VECTOR_SIZE(&new_capabilities->streams))) { + goto fail; + } + + for (idx = 0; idx < AST_VECTOR_SIZE(&new_capabilities->streams); ++idx) { + struct sdp_state_stream *proposed_state_stream; + struct sdp_state_stream *new_state_stream; + + proposed_state_stream = ast_calloc(1, sizeof(*proposed_state_stream)); + if (!proposed_state_stream) { + goto fail; + } + + new_state_stream = AST_VECTOR_GET(&new_capabilities->streams, idx); + *proposed_state_stream = *new_state_stream; + + switch (proposed_state_stream->type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + ao2_bump(proposed_state_stream->rtp); + break; + case AST_MEDIA_TYPE_IMAGE: + ao2_bump(proposed_state_stream->udptl); + break; + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; + } + + /* This is explicitly never set on the proposed capabilities struct */ + proposed_state_stream->remotely_held = 0; + + if (AST_VECTOR_APPEND(&proposed_capabilities->streams, proposed_state_stream)) { + sdp_state_stream_free(proposed_state_stream); + goto fail; + } + } + + set_proposed_capabilities(sdp_state, proposed_capabilities); + return 0; + +fail: + sdp_state_capabilities_free(proposed_capabilities); + return -1; +} + static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_state, const struct sdp_state_capabilities *capabilities); @@ -1127,65 +2491,47 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta * \brief Merge SDPs into a joint SDP. * * This function is used to take a remote SDP and merge it with our local - * capabilities to produce a new local SDP. After creating the new local SDP, - * it then iterates through media instances and updates them as necessary. For + * capabilities to produce a new local SDP. After creating the new local SDP, + * it then iterates through media instances and updates them as necessary. For * instance, if a specific RTP feature is supported by both us and the far end, * then we can ensure that the feature is enabled. * * \param sdp_state The current SDP state - * \retval -1 Failure + * * \retval 0 Success + * \retval -1 Failure + * Use ast_sdp_state_is_offer_rejected() to see if the offer SDP was rejected. */ static int merge_sdps(struct ast_sdp_state *sdp_state, const struct ast_sdp *remote_sdp) { struct sdp_state_capabilities *joint_capabilities; struct ast_stream_topology *remote_capabilities; - int i; remote_capabilities = ast_get_topology_from_sdp(remote_sdp, - sdp_state->options->g726_non_standard); + ast_sdp_options_get_g726_non_standard(sdp_state->options)); if (!remote_capabilities) { return -1; } - joint_capabilities = merge_capabilities(sdp_state, remote_capabilities, 0); + joint_capabilities = merge_remote_capabilities(sdp_state, remote_capabilities); ast_stream_topology_free(remote_capabilities); if (!joint_capabilities) { return -1; } - set_negotiated_capabilities(sdp_state, joint_capabilities); - - if (sdp_state->local_sdp) { - ast_sdp_free(sdp_state->local_sdp); - sdp_state->local_sdp = NULL; - } - - sdp_state->local_sdp = sdp_create_from_state(sdp_state, joint_capabilities); - if (!sdp_state->local_sdp) { - return -1; + if (sdp_state->role == SDP_ROLE_ANSWERER) { + sdp_state->remote_offer_rejected = + sdp_topology_is_rejected(joint_capabilities->topology) ? 1 : 0; + if (sdp_state->remote_offer_rejected) { + sdp_state_capabilities_free(joint_capabilities); + return -1; + } } + set_negotiated_capabilities(sdp_state, joint_capabilities); - for (i = 0; i < AST_VECTOR_SIZE(&joint_capabilities->streams); ++i) { - struct sdp_state_stream *state_stream; - - state_stream = AST_VECTOR_GET(&joint_capabilities->streams, i); + ao2_cleanup(sdp_state->remote_sdp); + sdp_state->remote_sdp = ao2_bump((struct ast_sdp *) remote_sdp); - switch (ast_stream_get_type(ast_stream_topology_get_stream(joint_capabilities->topology, i))) { - case AST_MEDIA_TYPE_AUDIO: - case AST_MEDIA_TYPE_VIDEO: - update_rtp_after_merge(sdp_state, state_stream->rtp, sdp_state->options, - remote_sdp, ast_sdp_get_m(remote_sdp, i)); - break; - case AST_MEDIA_TYPE_IMAGE: - update_udptl_after_merge(sdp_state, state_stream->udptl, sdp_state->options, - remote_sdp, ast_sdp_get_m(remote_sdp, i)); - break; - case AST_MEDIA_TYPE_UNKNOWN: - case AST_MEDIA_TYPE_TEXT: - case AST_MEDIA_TYPE_END: - break; - } - } + sdp_apply_negotiated_state(sdp_state); return 0; } @@ -1194,10 +2540,43 @@ const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_stat { ast_assert(sdp_state != NULL); - if (sdp_state->role == SDP_ROLE_NOT_SET) { + switch (sdp_state->role) { + case SDP_ROLE_NOT_SET: ast_assert(sdp_state->local_sdp == NULL); sdp_state->role = SDP_ROLE_OFFERER; + + if (sdp_state->pending_topology_update) { + struct sdp_state_capabilities *capabilities; + + /* We have a topology update to perform before generating the offer */ + capabilities = merge_local_capabilities(sdp_state, + sdp_state->pending_topology_update); + if (!capabilities) { + break; + } + ast_stream_topology_free(sdp_state->pending_topology_update); + sdp_state->pending_topology_update = NULL; + set_proposed_capabilities(sdp_state, capabilities); + } + + /* + * Allow the system to configure the topology streams + * before we create the offer SDP. + */ + sdp_state_cb_offerer_config_topology(sdp_state, + sdp_state->proposed_capabilities->topology); + sdp_state->local_sdp = sdp_create_from_state(sdp_state, sdp_state->proposed_capabilities); + break; + case SDP_ROLE_OFFERER: + break; + case SDP_ROLE_ANSWERER: + if (!sdp_state->local_sdp + && sdp_state->negotiated_capabilities + && !sdp_state->remote_offer_rejected) { + sdp_state->local_sdp = sdp_create_from_state(sdp_state, sdp_state->negotiated_capabilities); + } + break; } return sdp_state->local_sdp; @@ -1237,35 +2616,63 @@ int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, cons return -1; } ret = ast_sdp_state_set_remote_sdp(sdp_state, sdp); - ast_sdp_free(sdp); + ao2_ref(sdp, -1); return ret; } -int ast_sdp_state_reset(struct ast_sdp_state *sdp_state) +int ast_sdp_state_is_offer_rejected(struct ast_sdp_state *sdp_state) +{ + return sdp_state->remote_offer_rejected; +} + +int ast_sdp_state_is_offerer(struct ast_sdp_state *sdp_state) +{ + return sdp_state->role == SDP_ROLE_OFFERER; +} + +int ast_sdp_state_is_answerer(struct ast_sdp_state *sdp_state) +{ + return sdp_state->role == SDP_ROLE_ANSWERER; +} + +int ast_sdp_state_restart_negotiations(struct ast_sdp_state *sdp_state) { ast_assert(sdp_state != NULL); - ast_sdp_free(sdp_state->local_sdp); + ao2_cleanup(sdp_state->local_sdp); sdp_state->local_sdp = NULL; - set_proposed_capabilities(sdp_state, NULL); - sdp_state->role = SDP_ROLE_NOT_SET; + sdp_state->remote_offer_rejected = 0; + + if (sdp_state->negotiated_capabilities) { + update_proposed_capabilities(sdp_state, sdp_state->negotiated_capabilities); + } return 0; } -int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams) +int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *topology) { - struct sdp_state_capabilities *capabilities; + struct ast_stream_topology *merged_topology; + ast_assert(sdp_state != NULL); - ast_assert(streams != NULL); + ast_assert(topology != NULL); - capabilities = merge_capabilities(sdp_state, streams, 1); - if (!capabilities) { - return -1; + if (sdp_state->pending_topology_update) { + merged_topology = merge_local_topologies(sdp_state, + sdp_state->pending_topology_update, topology, 0); + if (!merged_topology) { + return -1; + } + ast_stream_topology_free(sdp_state->pending_topology_update); + sdp_state->pending_topology_update = merged_topology; + } else { + sdp_state->pending_topology_update = ast_stream_topology_clone(topology); + if (!sdp_state->pending_topology_update) { + return -1; + } } - set_proposed_capabilities(sdp_state, capabilities); return 0; } @@ -1275,9 +2682,9 @@ void ast_sdp_state_set_local_address(struct ast_sdp_state *sdp_state, struct ast ast_assert(sdp_state != NULL); if (!address) { - ast_sockaddr_setnull(&sdp_state->proposed_capabilities->connection_address); + ast_sockaddr_setnull(&sdp_state->connection_address); } else { - ast_sockaddr_copy(&sdp_state->proposed_capabilities->connection_address, address); + ast_sockaddr_copy(&sdp_state->connection_address, address); } } @@ -1301,18 +2708,37 @@ int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int st return 0; } +void ast_sdp_state_set_global_locally_held(struct ast_sdp_state *sdp_state, unsigned int locally_held) +{ + ast_assert(sdp_state != NULL); + + sdp_state->locally_held = locally_held ? 1 : 0; +} + +unsigned int ast_sdp_state_get_global_locally_held(const struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state != NULL); + + return sdp_state->locally_held; +} + void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state, int stream_index, unsigned int locally_held) { struct sdp_state_stream *stream_state; ast_assert(sdp_state != NULL); - stream_state = sdp_state_get_stream(sdp_state, stream_index); - if (!stream_state) { - return; + locally_held = locally_held ? 1 : 0; + + stream_state = sdp_state_get_joint_stream(sdp_state, stream_index); + if (stream_state) { + stream_state->locally_held = locally_held; } - stream_state->locally_held = locally_held; + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (stream_state) { + stream_state->locally_held = locally_held; + } } unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_state, @@ -1321,7 +2747,7 @@ unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_stat struct sdp_state_stream *stream_state; ast_assert(sdp_state != NULL); - stream_state = sdp_state_get_stream(sdp_state, stream_index); + stream_state = sdp_state_get_joint_stream(sdp_state, stream_index); if (!stream_state) { return 0; } @@ -1329,6 +2755,21 @@ unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_stat return stream_state->locally_held; } +unsigned int ast_sdp_state_get_remotely_held(const struct ast_sdp_state *sdp_state, + int stream_index) +{ + struct sdp_state_stream *stream_state; + + ast_assert(sdp_state != NULL); + + stream_state = sdp_state_get_joint_stream(sdp_state, stream_index); + if (!stream_state) { + return 0; + } + + return stream_state->remotely_held; +} + void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state, int stream_index, struct ast_control_t38_parameters *params) { @@ -1336,11 +2777,9 @@ void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state, ast_assert(sdp_state != NULL && params != NULL); stream_state = sdp_state_get_stream(sdp_state, stream_index); - if (!stream_state) { - return; + if (stream_state) { + stream_state->t38_local_params = *params; } - - stream_state->t38_local_params = *params; } /*! @@ -1398,7 +2837,8 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s caps = ast_stream_get_formats(stream); stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); - if (stream_state->rtp && caps && ast_format_cap_count(caps)) { + if (stream_state->rtp && caps && ast_format_cap_count(caps) + && AST_STREAM_STATE_REMOVED != ast_stream_get_state(stream)) { rtp = stream_state->rtp->instance; } else { /* This is a disabled stream */ @@ -1408,7 +2848,7 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s if (rtp) { struct ast_sockaddr address_rtp; - if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_rtp)) { + if (sdp_state_stream_get_connection_address(sdp_state, stream_state, &address_rtp)) { return -1; } rtp_port = ast_sockaddr_port(&address_rtp); @@ -1426,6 +2866,8 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s } if (rtp_port) { + const char *direction; + /* Stream is not declined/disabled */ for (i = 0; i < ast_format_cap_count(caps); i++) { struct ast_format *format = ast_format_cap_get_format(caps, i); @@ -1502,12 +2944,27 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s } } - a_line = ast_sdp_a_alloc(ast_sdp_state_get_locally_held(sdp_state, stream_index) - ? "sendonly" : "sendrecv", ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; + if (sdp_state->locally_held || stream_state->locally_held) { + if (stream_state->remotely_held) { + direction = "inactive"; + } else { + direction = "sendonly"; + } + } else { + if (stream_state->remotely_held) { + direction = "recvonly"; + } else { + /* Default is "sendrecv" */ + direction = NULL; + } + } + if (direction) { + a_line = ast_sdp_a_alloc(direction, ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } } add_ssrc_attributes(m_line, options, rtp); @@ -1585,7 +3042,8 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp ast_assert(sdp && options && stream); stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); - if (stream_state->udptl) { + if (stream_state->udptl + && AST_STREAM_STATE_REMOVED != ast_stream_get_state(stream)) { udptl = stream_state->udptl; } else { /* This is a disabled stream */ @@ -1595,7 +3053,7 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp if (udptl) { struct ast_sockaddr address_udptl; - if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_udptl)) { + if (sdp_state_stream_get_connection_address(sdp_state, stream_state, &address_udptl)) { return -1; } udptl_port = ast_sockaddr_port(&address_udptl); @@ -1619,8 +3077,6 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp if (udptl_port) { /* Stream is not declined/disabled */ - stream_state = sdp_state_get_stream(sdp_state, stream_index); - snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version); a_line = ast_sdp_a_alloc("T38FaxVersion", tmp); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { @@ -1773,7 +3229,6 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta } stream_count = ast_stream_topology_get_count(topology); - for (stream_num = 0; stream_num < stream_count; stream_num++) { switch (ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num))) { case AST_MEDIA_TYPE_AUDIO: @@ -1798,7 +3253,7 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta error: if (sdp) { - ast_sdp_free(sdp); + ao2_ref(sdp, -1); } else { ast_sdp_t_free(t_line); ast_sdp_s_free(s_line); diff --git a/main/stream.c b/main/stream.c index 20179f33133..b6d39112234 100644 --- a/main/stream.c +++ b/main/stream.c @@ -214,6 +214,23 @@ const char *ast_stream_state2str(enum ast_stream_state state) } } +enum ast_stream_state ast_stream_str2state(const char *str) +{ + if (!strcmp("sendrecv", str)) { + return AST_STREAM_STATE_SENDRECV; + } + if (!strcmp("sendonly", str)) { + return AST_STREAM_STATE_SENDONLY; + } + if (!strcmp("recvonly", str)) { + return AST_STREAM_STATE_RECVONLY; + } + if (!strcmp("inactive", str)) { + return AST_STREAM_STATE_INACTIVE; + } + return AST_STREAM_STATE_REMOVED; +} + void *ast_stream_get_data(struct ast_stream *stream, enum ast_stream_data_slot slot) { ast_assert(stream != NULL); diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c index 85f246e8371..d80f3d554be 100644 --- a/res/res_sdp_translator_pjmedia.c +++ b/res/res_sdp_translator_pjmedia.c @@ -484,7 +484,7 @@ AST_TEST_DEFINE(pjmedia_to_sdp_test) } cleanup: - ast_sdp_free(sdp); + ao2_cleanup(sdp); ast_sdp_translator_free(translator); pj_pool_release(pool); return res; @@ -560,7 +560,7 @@ AST_TEST_DEFINE(sdp_to_pjmedia_test) } cleanup: - ast_sdp_free(sdp); + ao2_cleanup(sdp); ast_sdp_translator_free(translator); pj_pool_release(pool); return res; diff --git a/tests/test_sdp.c b/tests/test_sdp.c index 7eef3f741e8..662e2aaf154 100644 --- a/tests/test_sdp.c +++ b/tests/test_sdp.c @@ -89,12 +89,31 @@ static int validate_m_line(struct ast_test *test, const struct ast_sdp_m_line *m } if (ast_sdp_m_get_payload_count(m_line) != num_payloads) { - ast_test_status_update(test, "Expected m-line payload count %d but got %d\n", - num_payloads, ast_sdp_m_get_payload_count(m_line)); + ast_test_status_update(test, "Expected %s m-line payload count %d but got %d\n", + media_type, num_payloads, ast_sdp_m_get_payload_count(m_line)); return -1; } - ast_test_status_update(test, "SDP m-line is as expected\n"); + ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type); + return 0; +} + +static int validate_m_line_declined(struct ast_test *test, + const struct ast_sdp_m_line *m_line, const char *media_type) +{ + if (strcmp(m_line->type, media_type)) { + ast_test_status_update(test, "Expected m-line media type %s but got %s\n", + media_type, m_line->type); + return -1; + } + + if (m_line->port != 0) { + ast_test_status_update(test, "Expected %s m-line to be declined but got port %u\n", + media_type, m_line->port); + return -1; + } + + ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type); return 0; } @@ -438,6 +457,26 @@ struct sdp_format { const char *formats; }; +static int build_sdp_option_formats(struct ast_sdp_options *options, int num_streams, const struct sdp_format *formats) +{ + int idx; + + for (idx = 0; idx < num_streams; ++idx) { + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return -1; + } + + if (ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) { + return -1; + } + ast_sdp_options_set_format_cap_type(options, formats[idx].type, caps); + } + return 0; +} + /*! * \brief Common method to build an SDP state for a test. * @@ -450,9 +489,16 @@ struct sdp_format { * * \param num_streams The number of elements in the formats array. * \param formats Array of media types and formats that will be in the state. + * \param opt_num_streams The number of new stream types allowed to create. + * Not used if test_options provided. + * \param opt_formats Array of new stream media types and formats allowed to create. + * NULL if use a default stream creation. + * Not used if test_options provided. * \param test_options Optional SDP options. */ -static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats, struct ast_sdp_options *test_options) +static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats, + int opt_num_streams, const struct sdp_format *opt_formats, + struct ast_sdp_options *test_options) { struct ast_stream_topology *topology = NULL; struct ast_sdp_state *state = NULL; @@ -460,10 +506,34 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f int i; if (!test_options) { + unsigned int max_streams; + + static const struct sdp_format sdp_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + { AST_MEDIA_TYPE_VIDEO, "vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, + }; + options = sdp_options_common(); if (!options) { goto end; } + + /* Determine max_streams to allow */ + max_streams = ARRAY_LEN(sdp_formats); + if (ARRAY_LEN(sdp_formats) < num_streams) { + max_streams = num_streams; + } + ast_sdp_options_set_max_streams(options, max_streams); + + /* Determine new stream formats and types allowed */ + if (!opt_formats) { + opt_num_streams = ARRAY_LEN(sdp_formats); + opt_formats = sdp_formats; + } + if (build_sdp_option_formats(options, opt_num_streams, opt_formats)) { + goto end; + } } else { options = test_options; } @@ -489,7 +559,10 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f goto end; } ast_stream_set_formats(stream, caps); - ast_stream_topology_append_stream(topology, stream); + if (ast_stream_topology_append_stream(topology, stream) < 0) { + ast_stream_free(stream); + goto end; + } } state = ast_sdp_state_alloc(topology, options); @@ -530,7 +603,8 @@ AST_TEST_DEFINE(topology_to_sdp) break; } - sdp_state = build_sdp_state(ARRAY_LEN(formats), formats, NULL); + sdp_state = build_sdp_state(ARRAY_LEN(formats), formats, + ARRAY_LEN(formats), formats, NULL); if (!sdp_state) { goto end; } @@ -674,7 +748,8 @@ AST_TEST_DEFINE(sdp_to_topology) break; } - sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats, NULL); + sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats, + ARRAY_LEN(sdp_formats), sdp_formats, NULL); if (!sdp_state) { res = AST_TEST_FAIL; goto end; @@ -723,7 +798,7 @@ AST_TEST_DEFINE(sdp_to_topology) return res; } -static int validate_merged_sdp(struct ast_test *test, const struct ast_sdp *sdp) +static int validate_avi_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) { struct ast_sdp_m_line *m_line; @@ -769,7 +844,11 @@ static int validate_merged_sdp(struct ast_test *test, const struct ast_sdp *sdp) return 0; } -AST_TEST_DEFINE(sdp_merge_symmetric) +static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_test *test, + int offer_num_streams, const struct sdp_format *offer_formats, + int answer_num_streams, const struct sdp_format *answer_formats, + int allowed_ans_num_streams, const struct sdp_format *allowed_ans_formats, + int (*validate_sdp)(struct ast_test *test, const struct ast_sdp *sdp)) { enum ast_test_result_state res = AST_TEST_PASS; struct ast_sdp_state *sdp_state_offerer = NULL; @@ -777,38 +856,15 @@ AST_TEST_DEFINE(sdp_merge_symmetric) const struct ast_sdp *offerer_sdp; const struct ast_sdp *answerer_sdp; - static const struct sdp_format offerer_formats[] = { - { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, - { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, - { AST_MEDIA_TYPE_IMAGE, "t38" }, - }; - static const struct sdp_format answerer_formats[] = { - { AST_MEDIA_TYPE_AUDIO, "ulaw" }, - { AST_MEDIA_TYPE_VIDEO, "vp8" }, - { AST_MEDIA_TYPE_IMAGE, "t38" }, - }; - - switch(cmd) { - case TEST_INIT: - info->name = "sdp_merge_symmetric"; - info->category = "/main/sdp/"; - info->summary = "Merge two SDPs with symmetric stream types"; - info->description = - "SDPs 1 and 2 each have one audio and one video stream (in that order).\n" - "SDP 1 offers to SDP 2, who answers. We ensure that both local SDPs have\n" - "the expected stream types and the expected formats"; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, NULL); + sdp_state_offerer = build_sdp_state(offer_num_streams, offer_formats, + offer_num_streams, offer_formats, NULL); if (!sdp_state_offerer) { res = AST_TEST_FAIL; goto end; } - sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats, NULL); + sdp_state_answerer = build_sdp_state(answer_num_streams, answer_formats, + allowed_ans_num_streams, allowed_ans_formats, NULL); if (!sdp_state_answerer) { res = AST_TEST_FAIL; goto end; @@ -820,22 +876,37 @@ AST_TEST_DEFINE(sdp_merge_symmetric) goto end; } - ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp); + if (ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) { + res = AST_TEST_FAIL; + goto end; + } answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); if (!answerer_sdp) { res = AST_TEST_FAIL; goto end; } - ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp); + if (ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp)) { + res = AST_TEST_FAIL; + goto end; + } - /* Get the offerer SDP again because it's now going to be the joint SDP */ + /* + * Restart SDP negotiations to build the joint SDP on the offerer + * side. Otherwise we will get the original offer for use in + * case of retransmissions. + */ + if (ast_sdp_state_restart_negotiations(sdp_state_offerer)) { + ast_test_status_update(test, "Restarting negotiations failed\n"); + res = AST_TEST_FAIL; + goto end; + } offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); - if (validate_merged_sdp(test, offerer_sdp)) { + if (validate_sdp(test, offerer_sdp)) { res = AST_TEST_FAIL; goto end; } - if (validate_merged_sdp(test, answerer_sdp)) { + if (validate_sdp(test, answerer_sdp)) { res = AST_TEST_FAIL; goto end; } @@ -847,14 +918,37 @@ AST_TEST_DEFINE(sdp_merge_symmetric) return res; } -AST_TEST_DEFINE(sdp_merge_crisscross) +AST_TEST_DEFINE(sdp_negotiation_initial) { - enum ast_test_result_state res = AST_TEST_PASS; - struct ast_sdp_state *sdp_state_offerer = NULL; - struct ast_sdp_state *sdp_state_answerer = NULL; - const struct ast_sdp *offerer_sdp; - const struct ast_sdp *answerer_sdp; + static const struct sdp_format offerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, + { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, + }; + switch(cmd) { + case TEST_INIT: + info->name = "sdp_negotiation_initial"; + info->category = "/main/sdp/"; + info->summary = "Simulate an initial negotiation"; + info->description = + "Initial negotiation tests creating new streams on the answering side.\n" + "After negotiation both offerer and answerer sides should have the same\n" + "expected stream types and formats."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + return sdp_negotiation_completed_tests(test, + ARRAY_LEN(offerer_formats), offerer_formats, + 0, NULL, + 0, NULL, + validate_avi_sdp_streams); +} + +AST_TEST_DEFINE(sdp_negotiation_type_change) +{ static const struct sdp_format offerer_formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, { AST_MEDIA_TYPE_VIDEO, "h264,vp8" }, @@ -868,174 +962,194 @@ AST_TEST_DEFINE(sdp_merge_crisscross) switch(cmd) { case TEST_INIT: - info->name = "sdp_merge_crisscross"; + info->name = "sdp_negotiation_type_change"; info->category = "/main/sdp/"; - info->summary = "Merge two SDPs with symmetric stream types"; + info->summary = "Simulate a re-negotiation changing stream types"; info->description = - "SDPs 1 and 2 each have one audio and one video stream. However, SDP 1 and\n" - "2 natively have the formats in a different order.\n" - "SDP 1 offers to SDP 2, who answers. We ensure that both local SDPs have\n" - "the expected stream types and the expected formats. Since SDP 1 was the\n" - "offerer, the format order on SDP 1 should determine the order of formats in the SDPs"; + "Reinvite negotiation tests changing stream types on the answering side.\n" + "After negotiation both offerer and answerer sides should have the same\n" + "expected stream types and formats."; return AST_TEST_NOT_RUN; case TEST_EXECUTE: break; } - sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, NULL); - if (!sdp_state_offerer) { - res = AST_TEST_FAIL; - goto end; - } + return sdp_negotiation_completed_tests(test, + ARRAY_LEN(offerer_formats), offerer_formats, + ARRAY_LEN(answerer_formats), answerer_formats, + 0, NULL, + validate_avi_sdp_streams); +} - sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats, NULL); - if (!sdp_state_answerer) { - res = AST_TEST_FAIL; - goto end; - } +static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) +{ + struct ast_sdp_m_line *m_line; - offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); - if (!offerer_sdp) { - res = AST_TEST_FAIL; - goto end; + if (!sdp) { + return -1; } - ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp); - answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); - if (!answerer_sdp) { - res = AST_TEST_FAIL; - goto end; + m_line = ast_sdp_get_m(sdp, 0); + if (validate_m_line_declined(test, m_line, "audio")) { + return -1; } - ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp); + m_line = ast_sdp_get_m(sdp, 1); + if (validate_m_line_declined(test, m_line, "video")) { + return -1; + } - /* Get the offerer SDP again because it's now going to be the joint SDP */ - offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); - if (validate_merged_sdp(test, offerer_sdp)) { - res = AST_TEST_FAIL; - goto end; + m_line = ast_sdp_get_m(sdp, 2); + if (validate_m_line(test, m_line, "audio", 1)) { + return -1; } - if (validate_merged_sdp(test, answerer_sdp)) { - res = AST_TEST_FAIL; - goto end; + if (validate_rtpmap(test, m_line, "PCMU")) { + return -1; } -end: - ast_sdp_state_free(sdp_state_offerer); - ast_sdp_state_free(sdp_state_answerer); + /* The other audio formats should *NOT* be present */ + if (!validate_rtpmap(test, m_line, "PCMA")) { + return -1; + } - return res; + return 0; } -static int validate_merged_sdp_asymmetric(struct ast_test *test, const struct ast_sdp *sdp, int is_offer) +AST_TEST_DEFINE(sdp_negotiation_decline_incompatible) +{ + static const struct sdp_format offerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "alaw" }, + { AST_MEDIA_TYPE_VIDEO, "vp8" }, + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw" }, + }; + static const struct sdp_format answerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + }; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_negotiation_decline_incompatible"; + info->category = "/main/sdp/"; + info->summary = "Simulate an initial negotiation declining streams"; + info->description = + "Initial negotiation tests declining incompatible streams on the answering side.\n" + "After negotiation both offerer and answerer sides should have the same\n" + "expected stream types and formats."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + return sdp_negotiation_completed_tests(test, + ARRAY_LEN(offerer_formats), offerer_formats, + ARRAY_LEN(answerer_formats), answerer_formats, + ARRAY_LEN(answerer_formats), answerer_formats, + validate_ava_declined_sdp_streams); +} + +static int validate_aaaa_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) { struct ast_sdp_m_line *m_line; - const char *side = is_offer ? "Offer side" : "Answer side"; if (!sdp) { - ast_test_status_update(test, "%s does not have a SDP\n", side); return -1; } - /* Stream 0 */ m_line = ast_sdp_get_m(sdp, 0); if (validate_m_line(test, m_line, "audio", 1)) { return -1; } - if (!m_line->port) { - ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 0, "n't"); - return -1; - } if (validate_rtpmap(test, m_line, "PCMU")) { return -1; } - /* The other audio formats should *NOT* be present */ - if (!validate_rtpmap(test, m_line, "PCMA")) { - return -1; - } - if (!validate_rtpmap(test, m_line, "G722")) { - return -1; - } - if (!validate_rtpmap(test, m_line, "opus")) { - return -1; - } - - /* The remaining streams should be declined */ - - /* Stream 1 */ m_line = ast_sdp_get_m(sdp, 1); if (validate_m_line(test, m_line, "audio", 1)) { return -1; } - if (m_line->port) { - ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 1, ""); + if (validate_rtpmap(test, m_line, "PCMU")) { return -1; } - /* Stream 2 */ m_line = ast_sdp_get_m(sdp, 2); - if (validate_m_line(test, m_line, "video", 1)) { + if (validate_m_line(test, m_line, "audio", 1)) { return -1; } - if (m_line->port) { - ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 2, ""); + if (validate_rtpmap(test, m_line, "PCMU")) { return -1; } - /* Stream 3 */ m_line = ast_sdp_get_m(sdp, 3); - if (validate_m_line(test, m_line, "image", 1)) { - return -1; - } - if (m_line->port) { - ast_test_status_update(test, "%s stream %d does%s have a port\n", side, 3, ""); + if (validate_m_line_declined(test, m_line, "audio")) { return -1; } return 0; } -AST_TEST_DEFINE(sdp_merge_asymmetric) +AST_TEST_DEFINE(sdp_negotiation_decline_max_streams) +{ + static const struct sdp_format offerer_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + }; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_negotiation_decline_max_streams"; + info->category = "/main/sdp/"; + info->summary = "Simulate an initial negotiation declining excessive streams"; + info->description = + "Initial negotiation tests declining too many streams on the answering side.\n" + "After negotiation both offerer and answerer sides should have the same\n" + "expected stream types and formats."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + return sdp_negotiation_completed_tests(test, + ARRAY_LEN(offerer_formats), offerer_formats, + 0, NULL, + 0, NULL, + validate_aaaa_declined_sdp_streams); +} + +AST_TEST_DEFINE(sdp_negotiation_not_acceptable) { enum ast_test_result_state res = AST_TEST_PASS; struct ast_sdp_state *sdp_state_offerer = NULL; struct ast_sdp_state *sdp_state_answerer = NULL; const struct ast_sdp *offerer_sdp; - const struct ast_sdp *answerer_sdp; static const struct sdp_format offerer_formats[] = { - { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" }, - { AST_MEDIA_TYPE_AUDIO, "ulaw" }, - { AST_MEDIA_TYPE_VIDEO, "h261" }, - { AST_MEDIA_TYPE_IMAGE, "t38" }, - }; - static const struct sdp_format answerer_formats[] = { - { AST_MEDIA_TYPE_AUDIO, "ulaw" }, + { AST_MEDIA_TYPE_AUDIO, "alaw" }, + { AST_MEDIA_TYPE_AUDIO, "alaw" }, }; switch(cmd) { case TEST_INIT: - info->name = "sdp_merge_asymmetric"; + info->name = "sdp_negotiation_not_acceptable"; info->category = "/main/sdp/"; - info->summary = "Merge two SDPs with an asymmetric number of streams"; + info->summary = "Simulate an initial negotiation declining all streams"; info->description = - "SDP 1 offers a four stream topology: Audio,Audio,Video,T.38\n" - "SDP 2 only has a single audio stream topology\n" - "We ensure that both local SDPs have the expected stream types and\n" - "the expected declined streams"; + "Initial negotiation tests declining all streams for a 488 on the answering side.\n" + "Negotiations should fail because there are no acceptable streams."; return AST_TEST_NOT_RUN; case TEST_EXECUTE: break; } - sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, NULL); + sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, + ARRAY_LEN(offerer_formats), offerer_formats, NULL); if (!sdp_state_offerer) { res = AST_TEST_FAIL; goto end; } - sdp_state_answerer = build_sdp_state(ARRAY_LEN(answerer_formats), answerer_formats, NULL); + sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, NULL); if (!sdp_state_answerer) { res = AST_TEST_FAIL; goto end; @@ -1047,24 +1161,15 @@ AST_TEST_DEFINE(sdp_merge_asymmetric) goto end; } - ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp); - answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); - if (!answerer_sdp) { + if (!ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) { + ast_test_status_update(test, "Bad. Setting remote SDP was successful.\n"); res = AST_TEST_FAIL; goto end; } - - ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp); - -#if defined(XXX_TODO_NEED_TO_HANDLE_DECLINED_STREAMS_ON_OFFER_SIDE) - /* Get the offerer SDP again because it's now going to be the joint SDP */ - offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); - if (validate_merged_sdp_asymmetric(test, offerer_sdp, 1)) { - res = AST_TEST_FAIL; - } -#endif - if (validate_merged_sdp_asymmetric(test, answerer_sdp, 0)) { + if (!ast_sdp_state_is_offer_rejected(sdp_state_answerer)) { + ast_test_status_update(test, "Bad. Negotiation failed for some other reason.\n"); res = AST_TEST_FAIL; + goto end; } end: @@ -1135,9 +1240,12 @@ AST_TEST_DEFINE(sdp_ssrc_attributes) ast_test_status_update(test, "Failed to allocate SDP options\n"); goto end; } + if (build_sdp_option_formats(options, ARRAY_LEN(formats), formats)) { + goto end; + } ast_sdp_options_set_ssrc(options, 1); - test_state = build_sdp_state(ARRAY_LEN(formats), formats, options); + test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, options); if (!test_state) { ast_test_status_update(test, "Failed to create SDP state\n"); goto end; @@ -1179,6 +1287,726 @@ AST_TEST_DEFINE(sdp_ssrc_attributes) return res; } +struct sdp_topology_stream { + /*! Media stream type: audio, video, image */ + enum ast_media_type type; + /*! Media stream state: removed/declined, sendrecv */ + enum ast_stream_state state; + /*! Comma separated list of formats allowed on the stream. Can be NULL if stream is removed/declined. */ + const char *formats; + /*! Optional name of stream. NULL for default name. */ + const char *name; +}; + +struct sdp_update_test { + /*! Maximum number of streams. (0 if default) */ + int max_streams; + /*! Optional initial SDP state topology (NULL if not present) */ + const struct sdp_topology_stream * const *initial; + /*! Required first topology update */ + const struct sdp_topology_stream * const *update_1; + /*! Optional second topology update (NULL if not present) */ + const struct sdp_topology_stream * const *update_2; + /*! Expected topology to be offered */ + const struct sdp_topology_stream * const *expected; +}; + +static struct ast_stream_topology *build_update_topology(const struct sdp_topology_stream * const *spec) +{ + struct ast_stream_topology *topology; + const struct sdp_topology_stream *desc; + + topology = ast_stream_topology_alloc(); + if (!topology) { + return NULL; + } + + for (desc = *spec; desc; ++spec, desc = *spec) { + struct ast_stream *stream; + const char *name; + + name = desc->name ?: ast_codec_media_type2str(desc->type); + stream = ast_stream_alloc(name, desc->type); + if (!stream) { + goto fail; + } + ast_stream_set_state(stream, desc->state); + if (desc->formats) { + struct ast_format_cap *caps; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + goto fail; + } + if (ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) { + ao2_ref(caps, -1); + goto fail; + } + ast_stream_set_formats(stream, caps); + ao2_ref(caps, -1); + } + if (ast_stream_topology_append_stream(topology, stream) < 0) { + ast_stream_free(stream); + goto fail; + } + } + return topology; + +fail: + ast_stream_topology_free(topology); + return NULL; +} + +static int cmp_update_topology(struct ast_test *test, + const struct ast_stream_topology *expected, const struct ast_stream_topology *merged) +{ + int status = 0; + int idx; + int max_streams; + struct ast_stream *exp_stream; + struct ast_stream *mrg_stream; + + idx = ast_stream_topology_get_count(expected); + max_streams = ast_stream_topology_get_count(merged); + if (idx != max_streams) { + ast_test_status_update(test, "Expected %d streams got %d streams\n", + idx, max_streams); + status = -1; + } + if (idx < max_streams) { + max_streams = idx; + } + + /* Compare common streams by position */ + for (idx = 0; idx < max_streams; ++idx) { + exp_stream = ast_stream_topology_get_stream(expected, idx); + mrg_stream = ast_stream_topology_get_stream(merged, idx); + + if (strcmp(ast_stream_get_name(exp_stream), ast_stream_get_name(mrg_stream))) { + ast_test_status_update(test, + "Stream %d: Expected stream name '%s' got stream name '%s'\n", + idx, + ast_stream_get_name(exp_stream), + ast_stream_get_name(mrg_stream)); + status = -1; + } + + if (ast_stream_get_state(exp_stream) != ast_stream_get_state(mrg_stream)) { + ast_test_status_update(test, + "Stream %d: Expected stream state '%s' got stream state '%s'\n", + idx, + ast_stream_state2str(ast_stream_get_state(exp_stream)), + ast_stream_state2str(ast_stream_get_state(mrg_stream))); + status = -1; + } + + if (ast_stream_get_type(exp_stream) != ast_stream_get_type(mrg_stream)) { + ast_test_status_update(test, + "Stream %d: Expected stream type '%s' got stream type '%s'\n", + idx, + ast_codec_media_type2str(ast_stream_get_type(exp_stream)), + ast_codec_media_type2str(ast_stream_get_type(mrg_stream))); + status = -1; + continue; + } + + if (ast_stream_get_state(exp_stream) == AST_STREAM_STATE_REMOVED + || ast_stream_get_state(mrg_stream) == AST_STREAM_STATE_REMOVED) { + /* + * Cannot compare formats if one of the streams is + * declined because there may not be any on the declined + * stream. + */ + continue; + } + if (!ast_format_cap_identical(ast_stream_get_formats(exp_stream), + ast_stream_get_formats(mrg_stream))) { + ast_test_status_update(test, + "Stream %d: Expected formats do not match merged formats\n", + idx); + status = -1; + } + } + + return status; +} + + +static const struct sdp_topology_stream audio_declined_no_name = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_REMOVED, NULL, NULL +}; + +static const struct sdp_topology_stream audio_ulaw_no_name = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", NULL +}; + +static const struct sdp_topology_stream audio_alaw_no_name = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", NULL +}; + +static const struct sdp_topology_stream audio_g722_no_name = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", NULL +}; + +static const struct sdp_topology_stream audio_g723_no_name = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g723", NULL +}; + +static const struct sdp_topology_stream video_declined_no_name = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, NULL, NULL +}; + +static const struct sdp_topology_stream video_h261_no_name = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", NULL +}; + +static const struct sdp_topology_stream video_h263_no_name = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", NULL +}; + +static const struct sdp_topology_stream video_h264_no_name = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", NULL +}; + +static const struct sdp_topology_stream video_vp8_no_name = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "vp8", NULL +}; + +static const struct sdp_topology_stream image_declined_no_name = { + AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_REMOVED, NULL, NULL +}; + +static const struct sdp_topology_stream image_t38_no_name = { + AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_SENDRECV, "t38", NULL +}; + + +static const struct sdp_topology_stream *top_ulaw_alaw_h264__vp8[] = { + &audio_ulaw_no_name, + &audio_alaw_no_name, + &video_h264_no_name, + &video_vp8_no_name, + NULL +}; + +static const struct sdp_topology_stream *top__vp8_alaw_h264_ulaw[] = { + &video_vp8_no_name, + &audio_alaw_no_name, + &video_h264_no_name, + &audio_ulaw_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_alaw_ulaw__vp8_h264[] = { + &audio_alaw_no_name, + &audio_ulaw_no_name, + &video_vp8_no_name, + &video_h264_no_name, + NULL +}; + +/* Sorting by type with no new or deleted streams */ +static const struct sdp_update_test mrg_by_type_00 = { + .initial = top_ulaw_alaw_h264__vp8, + .update_1 = top__vp8_alaw_h264_ulaw, + .expected = top_alaw_ulaw__vp8_h264, +}; + + +static const struct sdp_topology_stream *top_alaw__vp8[] = { + &audio_alaw_no_name, + &video_vp8_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_h264__vp8_ulaw[] = { + &video_h264_no_name, + &video_vp8_no_name, + &audio_ulaw_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_ulaw_h264__vp8[] = { + &audio_ulaw_no_name, + &video_h264_no_name, + &video_vp8_no_name, + NULL +}; + +/* Sorting by type and adding a stream */ +static const struct sdp_update_test mrg_by_type_01 = { + .initial = top_alaw__vp8, + .update_1 = top_h264__vp8_ulaw, + .expected = top_ulaw_h264__vp8, +}; + + +static const struct sdp_topology_stream *top_alaw__vp8_vdec[] = { + &audio_alaw_no_name, + &video_vp8_no_name, + &video_declined_no_name, + NULL +}; + +/* Sorting by type and deleting a stream */ +static const struct sdp_update_test mrg_by_type_02 = { + .initial = top_ulaw_h264__vp8, + .update_1 = top_alaw__vp8, + .expected = top_alaw__vp8_vdec, +}; + + +static const struct sdp_topology_stream *top_h264_alaw_ulaw[] = { + &video_h264_no_name, + &audio_alaw_no_name, + &audio_ulaw_no_name, + NULL +}; + +static const struct sdp_topology_stream *top__t38[] = { + &image_t38_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_vdec__t38_adec[] = { + &video_declined_no_name, + &image_t38_no_name, + &audio_declined_no_name, + NULL +}; + +/* Sorting by type changing stream types for T.38 */ +static const struct sdp_update_test mrg_by_type_03 = { + .initial = top_h264_alaw_ulaw, + .update_1 = top__t38, + .expected = top_vdec__t38_adec, +}; + + +/* Sorting by type changing stream types back from T.38 */ +static const struct sdp_update_test mrg_by_type_04 = { + .initial = top_vdec__t38_adec, + .update_1 = top_h264_alaw_ulaw, + .expected = top_h264_alaw_ulaw, +}; + + +static const struct sdp_topology_stream *top_h264[] = { + &video_h264_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_vdec__t38[] = { + &video_declined_no_name, + &image_t38_no_name, + NULL +}; + +/* Sorting by type changing stream types for T.38 */ +static const struct sdp_update_test mrg_by_type_05 = { + .initial = top_h264, + .update_1 = top__t38, + .expected = top_vdec__t38, +}; + + +static const struct sdp_topology_stream *top_h264_idec[] = { + &video_h264_no_name, + &image_declined_no_name, + NULL +}; + +/* Sorting by type changing stream types back from T.38 */ +static const struct sdp_update_test mrg_by_type_06 = { + .initial = top_vdec__t38, + .update_1 = top_h264, + .expected = top_h264_idec, +}; + + +static const struct sdp_topology_stream *top_ulaw_adec_h264__vp8[] = { + &audio_ulaw_no_name, + &audio_declined_no_name, + &video_h264_no_name, + &video_vp8_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_h263_alaw_h261_h264_vp8[] = { + &video_h263_no_name, + &audio_alaw_no_name, + &video_h261_no_name, + &video_h264_no_name, + &video_vp8_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_alaw_h264_h263_h261_vp8[] = { + &audio_alaw_no_name, + &video_h264_no_name, + &video_h263_no_name, + &video_h261_no_name, + &video_vp8_no_name, + NULL +}; + +/* Sorting by type with backfill and adding streams */ +static const struct sdp_update_test mrg_by_type_07 = { + .initial = top_ulaw_adec_h264__vp8, + .update_1 = top_h263_alaw_h261_h264_vp8, + .expected = top_alaw_h264_h263_h261_vp8, +}; + + +static const struct sdp_topology_stream *top_ulaw_alaw_h264__vp8_h261[] = { + &audio_ulaw_no_name, + &audio_alaw_no_name, + &video_h264_no_name, + &video_vp8_no_name, + &video_h261_no_name, + NULL +}; + +/* Sorting by type overlimit of 4 and drop */ +static const struct sdp_update_test mrg_by_type_08 = { + .max_streams = 4, + .initial = top_ulaw_alaw_h264__vp8, + .update_1 = top_ulaw_alaw_h264__vp8_h261, + .expected = top_ulaw_alaw_h264__vp8, +}; + + +static const struct sdp_topology_stream *top_ulaw_alaw_h264[] = { + &audio_ulaw_no_name, + &audio_alaw_no_name, + &video_h264_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_alaw_h261__vp8[] = { + &audio_alaw_no_name, + &video_h261_no_name, + &video_vp8_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_alaw_adec_h261__vp8[] = { + &audio_alaw_no_name, + &audio_declined_no_name, + &video_h261_no_name, + &video_vp8_no_name, + NULL +}; + +/* Sorting by type with delete and add of streams */ +static const struct sdp_update_test mrg_by_type_09 = { + .initial = top_ulaw_alaw_h264, + .update_1 = top_alaw_h261__vp8, + .expected = top_alaw_adec_h261__vp8, +}; + + +static const struct sdp_topology_stream *top_ulaw_adec_h264[] = { + &audio_ulaw_no_name, + &audio_declined_no_name, + &video_h264_no_name, + NULL +}; + +/* Sorting by type and adding streams */ +static const struct sdp_update_test mrg_by_type_10 = { + .initial = top_ulaw_adec_h264, + .update_1 = top_alaw_ulaw__vp8_h264, + .expected = top_alaw_ulaw__vp8_h264, +}; + + +static const struct sdp_topology_stream *top_adec_g722_h261[] = { + &audio_declined_no_name, + &audio_g722_no_name, + &video_h261_no_name, + NULL +}; + +/* Sorting by type and deleting old streams */ +static const struct sdp_update_test mrg_by_type_11 = { + .initial = top_ulaw_alaw_h264, + .update_1 = top_adec_g722_h261, + .expected = top_adec_g722_h261, +}; + + +static const struct sdp_topology_stream audio_alaw4dave = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "dave" +}; + +static const struct sdp_topology_stream audio_g7224dave = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "dave" +}; + +static const struct sdp_topology_stream audio_ulaw4fred = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "fred" +}; + +static const struct sdp_topology_stream audio_alaw4fred = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "fred" +}; + +static const struct sdp_topology_stream audio_ulaw4rose = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "rose" +}; + +static const struct sdp_topology_stream audio_g7224rose = { + AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "rose" +}; + + +static const struct sdp_topology_stream video_h2614dave = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "dave" +}; + +static const struct sdp_topology_stream video_h2634dave = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "dave" +}; + +static const struct sdp_topology_stream video_h2634fred = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "fred" +}; + +static const struct sdp_topology_stream video_h2644fred = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "fred" +}; + +static const struct sdp_topology_stream video_h2644rose = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "rose" +}; + +static const struct sdp_topology_stream video_h2614rose = { + AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "rose" +}; + + +static const struct sdp_topology_stream *top_adave_alaw_afred_ulaw_arose_g722_vdave_h261_vfred_h263_vrose_h264[] = { + &audio_alaw4dave, + &audio_alaw_no_name, + &audio_ulaw4fred, + &audio_ulaw_no_name, + &audio_g7224rose, + &audio_g722_no_name, + &video_h2614dave, + &video_h261_no_name, + &video_h2634fred, + &video_h263_no_name, + &video_h2644rose, + &video_h264_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_vfred_vrose_vdave_h263_h264_h261_afred_ulaw_arose_g722_adave_alaw[] = { + &video_h2644fred, + &video_h2614rose, + &video_h2634dave, + &video_h263_no_name, + &video_h264_no_name, + &video_h261_no_name, + &audio_alaw4fred, + &audio_ulaw_no_name, + &audio_ulaw4rose, + &audio_g722_no_name, + &audio_g7224dave, + &audio_alaw_no_name, + NULL +}; + +static const struct sdp_topology_stream *top_adave_ulaw_afred_g722_arose_alaw_vdave_h263_vfred_h264_vrose_h261[] = { + &audio_g7224dave, + &audio_ulaw_no_name, + &audio_alaw4fred, + &audio_g722_no_name, + &audio_ulaw4rose, + &audio_alaw_no_name, + &video_h2634dave, + &video_h263_no_name, + &video_h2644fred, + &video_h264_no_name, + &video_h2614rose, + &video_h261_no_name, + NULL +}; + +/* Sorting by name and type with no new or deleted streams */ +static const struct sdp_update_test mrg_by_name_00 = { + .initial = top_adave_alaw_afred_ulaw_arose_g722_vdave_h261_vfred_h263_vrose_h264, + .update_1 = top_vfred_vrose_vdave_h263_h264_h261_afred_ulaw_arose_g722_adave_alaw, + .expected = top_adave_ulaw_afred_g722_arose_alaw_vdave_h263_vfred_h264_vrose_h261, +}; + + +static const struct sdp_topology_stream *top_adave_g723_h261[] = { + &audio_g7224dave, + &audio_g723_no_name, + &video_h261_no_name, + NULL +}; + +/* Sorting by name and type adding names to streams */ +static const struct sdp_update_test mrg_by_name_01 = { + .initial = top_ulaw_alaw_h264, + .update_1 = top_adave_g723_h261, + .expected = top_adave_g723_h261, +}; + + +/* Sorting by name and type removing names from streams */ +static const struct sdp_update_test mrg_by_name_02 = { + .initial = top_adave_g723_h261, + .update_1 = top_ulaw_alaw_h264, + .expected = top_ulaw_alaw_h264, +}; + + +static const struct sdp_update_test *sdp_update_cases[] = { + /* Merging by type */ + /* 00 */ &mrg_by_type_00, + /* 01 */ &mrg_by_type_01, + /* 02 */ &mrg_by_type_02, + /* 03 */ &mrg_by_type_03, + /* 04 */ &mrg_by_type_04, + /* 05 */ &mrg_by_type_05, + /* 06 */ &mrg_by_type_06, + /* 07 */ &mrg_by_type_07, + /* 08 */ &mrg_by_type_08, + /* 09 */ &mrg_by_type_09, + /* 10 */ &mrg_by_type_10, + /* 11 */ &mrg_by_type_11, + + /* Merging by name and type */ + /* 12 */ &mrg_by_name_00, + /* 13 */ &mrg_by_name_01, + /* 14 */ &mrg_by_name_02, +}; + +AST_TEST_DEFINE(sdp_update_topology) +{ + enum ast_test_result_state res; + unsigned int idx; + int status; + struct ast_sdp_options *options; + struct ast_stream_topology *topology; + struct ast_sdp_state *test_state = NULL; + + static const struct sdp_format sdp_formats[] = { + { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,g723" }, + { AST_MEDIA_TYPE_VIDEO, "h261,h263,h264,vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, + }; + + switch(cmd) { + case TEST_INIT: + info->name = "sdp_update_topology"; + info->category = "/main/sdp/"; + info->summary = "Merge topology updates from the system"; + info->description = + "1) Create a SDP state with an optional initial topology.\n" + "2) Update the initial topology with one or two new topologies.\n" + "3) Get the SDP offer to merge the updates into the initial topology.\n" + "4) Check that the offered topology matches the expected topology.\n" + "5) Repeat these steps for each test case defined."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + res = AST_TEST_FAIL; + for (idx = 0; idx < ARRAY_LEN(sdp_update_cases); ++idx) { + ast_test_status_update(test, "Starting update case %d\n", idx); + + /* Create a SDP state with an optional initial topology. */ + options = sdp_options_common(); + if (!options) { + ast_test_status_update(test, "Failed to allocate SDP options\n"); + goto end; + } + if (sdp_update_cases[idx]->max_streams) { + ast_sdp_options_set_max_streams(options, sdp_update_cases[idx]->max_streams); + } + if (build_sdp_option_formats(options, ARRAY_LEN(sdp_formats), sdp_formats)) { + ast_test_status_update(test, "Failed to setup SDP options new stream formats\n"); + goto end; + } + if (sdp_update_cases[idx]->initial) { + topology = build_update_topology(sdp_update_cases[idx]->initial); + if (!topology) { + ast_test_status_update(test, "Failed to build initial SDP state topology\n"); + goto end; + } + } else { + topology = NULL; + } + test_state = ast_sdp_state_alloc(topology, options); + ast_stream_topology_free(topology); + if (!test_state) { + ast_test_status_update(test, "Failed to build SDP state\n"); + goto end; + } + + /* Update the initial topology with one or two new topologies. */ + topology = build_update_topology(sdp_update_cases[idx]->update_1); + if (!topology) { + ast_test_status_update(test, "Failed to build first update SDP state topology\n"); + goto end; + } + status = ast_sdp_state_update_local_topology(test_state, topology); + ast_stream_topology_free(topology); + if (status) { + ast_test_status_update(test, "Failed to update first update SDP state topology\n"); + goto end; + } + if (sdp_update_cases[idx]->update_2) { + topology = build_update_topology(sdp_update_cases[idx]->update_2); + if (!topology) { + ast_test_status_update(test, "Failed to build second update SDP state topology\n"); + goto end; + } + status = ast_sdp_state_update_local_topology(test_state, topology); + ast_stream_topology_free(topology); + if (status) { + ast_test_status_update(test, "Failed to update second update SDP state topology\n"); + goto end; + } + } + + /* Get the SDP offer to merge the updates into the initial topology. */ + if (!ast_sdp_state_get_local_sdp(test_state)) { + ast_test_status_update(test, "Failed to create offer SDP\n"); + goto end; + } + + /* Check that the offered topology matches the expected topology. */ + topology = build_update_topology(sdp_update_cases[idx]->expected); + if (!topology) { + ast_test_status_update(test, "Failed to build expected topology\n"); + goto end; + } + status = cmp_update_topology(test, topology, + ast_sdp_state_get_local_topology(test_state)); + ast_stream_topology_free(topology); + if (status) { + ast_test_status_update(test, "Failed to match expected topology\n"); + goto end; + } + + /* Repeat for each test case defined. */ + ast_sdp_state_free(test_state); + test_state = NULL; + } + res = AST_TEST_PASS; + +end: + ast_sdp_state_free(test_state); + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(invalid_rtpmap); @@ -1186,10 +2014,13 @@ static int unload_module(void) AST_TEST_UNREGISTER(find_attr); AST_TEST_UNREGISTER(topology_to_sdp); AST_TEST_UNREGISTER(sdp_to_topology); - AST_TEST_UNREGISTER(sdp_merge_symmetric); - AST_TEST_UNREGISTER(sdp_merge_crisscross); - AST_TEST_UNREGISTER(sdp_merge_asymmetric); + AST_TEST_UNREGISTER(sdp_negotiation_initial); + AST_TEST_UNREGISTER(sdp_negotiation_type_change); + AST_TEST_UNREGISTER(sdp_negotiation_decline_incompatible); + AST_TEST_UNREGISTER(sdp_negotiation_decline_max_streams); + AST_TEST_UNREGISTER(sdp_negotiation_not_acceptable); AST_TEST_UNREGISTER(sdp_ssrc_attributes); + AST_TEST_UNREGISTER(sdp_update_topology); return 0; } @@ -1201,10 +2032,13 @@ static int load_module(void) AST_TEST_REGISTER(find_attr); AST_TEST_REGISTER(topology_to_sdp); AST_TEST_REGISTER(sdp_to_topology); - AST_TEST_REGISTER(sdp_merge_symmetric); - AST_TEST_REGISTER(sdp_merge_crisscross); - AST_TEST_REGISTER(sdp_merge_asymmetric); + AST_TEST_REGISTER(sdp_negotiation_initial); + AST_TEST_REGISTER(sdp_negotiation_type_change); + AST_TEST_REGISTER(sdp_negotiation_decline_incompatible); + AST_TEST_REGISTER(sdp_negotiation_decline_max_streams); + AST_TEST_REGISTER(sdp_negotiation_not_acceptable); AST_TEST_REGISTER(sdp_ssrc_attributes); + AST_TEST_REGISTER(sdp_update_topology); return AST_MODULE_LOAD_SUCCESS; } From d2fbbdd6922617af381adae81277c237dd047c42 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 19 May 2017 23:28:50 -0500 Subject: [PATCH 1332/1578] SDP: Create declined m= SDP lines using remote SDP if applicable. * Update SDP unit tests to test negotiating with declined streams. Generation of declined m= lines created and responded tested. Change-Id: I5cb99f5010994ab0c7d9cf2d395eca23fab37b98 --- main/sdp_state.c | 503 ++++++++++++++++++++++++++++++----------------- tests/test_sdp.c | 137 +++++++++---- 2 files changed, 418 insertions(+), 222 deletions(-) diff --git a/main/sdp_state.c b/main/sdp_state.c index 330140c6937..a77d96da5d4 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -2813,8 +2813,161 @@ static void add_ssrc_attributes(struct ast_sdp_m_line *m_line, const struct ast_ ast_sdp_m_add_a(m_line, a_line); } +/*! + * \internal + * \brief Create a declined m-line from a remote requested stream. + * \since 15.0.0 + * + * \details + * Using the last received remote SDP create a declined stream + * m-line for the requested stream. The stream may be unsupported. + * + * \param sdp Our SDP under construction to append the declined stream. + * \param sdp_state + * \param stream_index Which remote SDP stream we are declining. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +static int sdp_add_m_from_declined_remote_stream(struct ast_sdp *sdp, + const struct ast_sdp_state *sdp_state, int stream_index) +{ + const struct ast_sdp_m_line *m_line_remote; + struct ast_sdp_m_line *m_line; + int idx; + + ast_assert(sdp && sdp_state && sdp_state->remote_sdp); + ast_assert(stream_index < ast_sdp_get_m_count(sdp_state->remote_sdp)); + + /* + * The only way we can generate a declined unsupported stream + * m-line is if the remote offered it to us. + */ + m_line_remote = ast_sdp_get_m(sdp_state->remote_sdp, stream_index); + + /* Copy remote SDP stream m-line except for port number. */ + m_line = ast_sdp_m_alloc(m_line_remote->type, 0, m_line_remote->port_count, + m_line_remote->proto, NULL); + if (!m_line) { + return -1; + } + + /* Copy any m-line payload strings from the remote SDP */ + for (idx = 0; idx < ast_sdp_m_get_payload_count(m_line_remote); ++idx) { + const struct ast_sdp_payload *payload_remote; + struct ast_sdp_payload *payload; + + payload_remote = ast_sdp_m_get_payload(m_line_remote, idx); + payload = ast_sdp_payload_alloc(payload_remote->fmt); + if (!payload) { + ast_sdp_m_free(m_line); + return -1; + } + if (ast_sdp_m_add_payload(m_line, payload)) { + ast_sdp_payload_free(payload); + ast_sdp_m_free(m_line); + return -1; + } + } + + if (ast_sdp_add_m(sdp, m_line)) { + ast_sdp_m_free(m_line); + return -1; + } + + return 0; +} + +/*! + * \internal + * \brief Create a declined m-line for our SDP stream. + * \since 15.0.0 + * + * \param sdp Our SDP under construction to append the declined stream. + * \param sdp_state + * \param type Stream type we are declining. + * \param stream_index Which remote SDP stream we are declining. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +static int sdp_add_m_from_declined_stream(struct ast_sdp *sdp, + const struct ast_sdp_state *sdp_state, enum ast_media_type type, int stream_index) +{ + struct ast_sdp_m_line *m_line; + const char *proto; + const char *fmt; + struct ast_sdp_payload *payload; + + if (sdp_state->role == SDP_ROLE_ANSWERER) { + /* We are declining the remote stream or it is still declined. */ + return sdp_add_m_from_declined_remote_stream(sdp, sdp_state, stream_index); + } + + /* Send declined remote stream in our offer if the type matches. */ + if (sdp_state->remote_sdp + && stream_index < ast_sdp_get_m_count(sdp_state->remote_sdp)) { + if (!sdp_is_stream_type_supported(type) + || !strcasecmp(ast_sdp_get_m(sdp_state->remote_sdp, stream_index)->type, + ast_codec_media_type2str(type))) { + /* Stream is still declined */ + return sdp_add_m_from_declined_remote_stream(sdp, sdp_state, stream_index); + } + } + + /* Build a new declined stream in our offer. */ + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + case AST_MEDIA_TYPE_VIDEO: + proto = "RTP/AVP"; + break; + case AST_MEDIA_TYPE_IMAGE: + proto = "udptl"; + break; + default: + /* Stream type not supported */ + ast_assert(0); + return -1; + } + m_line = ast_sdp_m_alloc(ast_codec_media_type2str(type), 0, 1, proto, NULL); + if (!m_line) { + return -1; + } + + /* Add a dummy static payload type */ + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + fmt = "0"; /* ulaw */ + break; + case AST_MEDIA_TYPE_VIDEO: + fmt = "31"; /* H.261 */ + break; + case AST_MEDIA_TYPE_IMAGE: + fmt = "t38"; /* T.38 */ + break; + default: + /* Stream type not supported */ + ast_assert(0); + ast_sdp_m_free(m_line); + return -1; + } + payload = ast_sdp_payload_alloc(fmt); + if (!payload || ast_sdp_m_add_payload(m_line, payload)) { + ast_sdp_payload_free(payload); + ast_sdp_m_free(m_line); + return -1; + } + + if (ast_sdp_add_m(sdp, m_line)) { + ast_sdp_m_free(m_line); + return -1; + } + + return 0; +} + static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, - const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) + const struct sdp_state_capabilities *capabilities, int stream_index) { struct ast_stream *stream; struct ast_sdp_m_line *m_line; @@ -2829,11 +2982,14 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s struct sdp_state_stream *stream_state; struct ast_rtp_instance *rtp; struct ast_sdp_a_line *a_line; + const struct ast_sdp_options *options; + const char *direction; stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); - ast_assert(sdp && options && stream); + ast_assert(sdp && sdp_state && stream); + options = sdp_state->options; caps = ast_stream_get_formats(stream); stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); @@ -2856,146 +3012,119 @@ static int sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_s rtp_port = 0; } - m_line = ast_sdp_m_alloc( - ast_codec_media_type2str(ast_stream_get_type(stream)), - rtp_port, 1, + media_type = ast_stream_get_type(stream); + if (!rtp_port) { + /* Declined/disabled stream */ + return sdp_add_m_from_declined_stream(sdp, sdp_state, media_type, stream_index); + } + + /* Stream is not declined/disabled */ + m_line = ast_sdp_m_alloc(ast_codec_media_type2str(media_type), rtp_port, 1, options->encryption != AST_SDP_ENCRYPTION_DISABLED ? "RTP/SAVP" : "RTP/AVP", NULL); if (!m_line) { return -1; } - if (rtp_port) { - const char *direction; - - /* Stream is not declined/disabled */ - for (i = 0; i < ast_format_cap_count(caps); i++) { - struct ast_format *format = ast_format_cap_get_format(caps, i); - - rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, - format, 0); - if (rtp_code == -1) { - ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", - ast_format_get_name(format)); - ao2_ref(format, -1); - continue; - } - - if (ast_sdp_m_add_format(m_line, options, rtp_code, 1, format, 0)) { - ast_sdp_m_free(m_line); - ao2_ref(format, -1); - return -1; - } - - if (ast_format_get_maximum_ms(format) - && ((ast_format_get_maximum_ms(format) < max_packet_size) - || !max_packet_size)) { - max_packet_size = ast_format_get_maximum_ms(format); - } + for (i = 0; i < ast_format_cap_count(caps); i++) { + struct ast_format *format = ast_format_cap_get_format(caps, i); + rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, + format, 0); + if (rtp_code == -1) { + ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", + ast_format_get_name(format)); ao2_ref(format, -1); + continue; } - media_type = ast_stream_get_type(stream); - if (media_type != AST_MEDIA_TYPE_VIDEO - && (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO)) { - i = AST_RTP_DTMF; - rtp_code = ast_rtp_codecs_payload_code( - ast_rtp_instance_get_codecs(rtp), 0, NULL, i); - if (-1 < rtp_code) { - if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) { - ast_sdp_m_free(m_line); - return -1; - } - - snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); - a_line = ast_sdp_a_alloc("fmtp", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - } + if (ast_sdp_m_add_format(m_line, options, rtp_code, 1, format, 0)) { + ast_sdp_m_free(m_line); + ao2_ref(format, -1); + return -1; } - /* If ptime is set add it as an attribute */ - min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); - if (!min_packet_size) { - min_packet_size = ast_format_cap_get_framing(caps); + if (ast_format_get_maximum_ms(format) + && ((ast_format_get_maximum_ms(format) < max_packet_size) + || !max_packet_size)) { + max_packet_size = ast_format_get_maximum_ms(format); } - if (min_packet_size) { - snprintf(tmp, sizeof(tmp), "%d", min_packet_size); - a_line = ast_sdp_a_alloc("ptime", tmp); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); + ao2_ref(format, -1); + } + + if (media_type != AST_MEDIA_TYPE_VIDEO + && (options->dtmf == AST_SDP_DTMF_RFC_4733 || options->dtmf == AST_SDP_DTMF_AUTO)) { + i = AST_RTP_DTMF; + rtp_code = ast_rtp_codecs_payload_code( + ast_rtp_instance_get_codecs(rtp), 0, NULL, i); + if (-1 < rtp_code) { + if (ast_sdp_m_add_format(m_line, options, rtp_code, 0, NULL, i)) { ast_sdp_m_free(m_line); return -1; } - } - if (max_packet_size) { - snprintf(tmp, sizeof(tmp), "%d", max_packet_size); - a_line = ast_sdp_a_alloc("maxptime", tmp); + snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code); + a_line = ast_sdp_a_alloc("fmtp", tmp); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } } + } - if (sdp_state->locally_held || stream_state->locally_held) { - if (stream_state->remotely_held) { - direction = "inactive"; - } else { - direction = "sendonly"; - } - } else { - if (stream_state->remotely_held) { - direction = "recvonly"; - } else { - /* Default is "sendrecv" */ - direction = NULL; - } + /* If ptime is set add it as an attribute */ + min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(rtp)); + if (!min_packet_size) { + min_packet_size = ast_format_cap_get_framing(caps); + } + if (min_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", min_packet_size); + + a_line = ast_sdp_a_alloc("ptime", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; } - if (direction) { - a_line = ast_sdp_a_alloc(direction, ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + } + + if (max_packet_size) { + snprintf(tmp, sizeof(tmp), "%d", max_packet_size); + a_line = ast_sdp_a_alloc("maxptime", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; } + } - add_ssrc_attributes(m_line, options, rtp); + if (sdp_state->locally_held || stream_state->locally_held) { + if (stream_state->remotely_held) { + direction = "inactive"; + } else { + direction = "sendonly"; + } } else { - /* Declined/disabled stream */ - struct ast_sdp_payload *payload; - const char *fmt; - - /* - * Add a static payload type placeholder to the declined/disabled stream. - * - * XXX We should use the default payload type in the received offer but - * we don't have that available. - */ - switch (ast_stream_get_type(stream)) { - default: - case AST_MEDIA_TYPE_AUDIO: - fmt = "0"; /* ulaw */ - break; - case AST_MEDIA_TYPE_VIDEO: - fmt = "31"; /* H.261 */ - break; + if (stream_state->remotely_held) { + direction = "recvonly"; + } else { + /* Default is "sendrecv" */ + direction = NULL; } - payload = ast_sdp_payload_alloc(fmt); - if (!payload || ast_sdp_m_add_payload(m_line, payload)) { - ast_sdp_payload_free(payload); + } + if (direction) { + a_line = ast_sdp_a_alloc(direction, ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } } + add_ssrc_attributes(m_line, options, rtp); + if (ast_sdp_add_m(sdp, m_line)) { ast_sdp_m_free(m_line); return -1; @@ -3026,11 +3155,12 @@ static unsigned int t38_get_rate(enum ast_control_t38_rate rate) } static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, - const struct ast_sdp_options *options, const struct sdp_state_capabilities *capabilities, int stream_index) + const struct sdp_state_capabilities *capabilities, int stream_index) { struct ast_stream *stream; struct ast_sdp_m_line *m_line; struct ast_sdp_payload *payload; + enum ast_media_type media_type; char tmp[64]; struct sdp_state_udptl *udptl; struct ast_sdp_a_line *a_line; @@ -3039,7 +3169,7 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp stream = ast_stream_topology_get_stream(capabilities->topology, stream_index); - ast_assert(sdp && options && stream); + ast_assert(sdp && sdp_state && stream); stream_state = AST_VECTOR_GET(&capabilities->streams, stream_index); if (stream_state->udptl @@ -3061,9 +3191,15 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp udptl_port = 0; } - m_line = ast_sdp_m_alloc( - ast_codec_media_type2str(ast_stream_get_type(stream)), - udptl_port, 1, "udptl", NULL); + media_type = ast_stream_get_type(stream); + if (!udptl_port) { + /* Declined/disabled stream */ + return sdp_add_m_from_declined_stream(sdp, sdp_state, media_type, stream_index); + } + + /* Stream is not declined/disabled */ + m_line = ast_sdp_m_alloc(ast_codec_media_type2str(media_type), udptl_port, 1, + "udptl", NULL); if (!m_line) { return -1; } @@ -3075,98 +3211,95 @@ static int sdp_add_m_from_udptl_stream(struct ast_sdp *sdp, const struct ast_sdp return -1; } - if (udptl_port) { - /* Stream is not declined/disabled */ - snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version); - a_line = ast_sdp_a_alloc("T38FaxVersion", tmp); + snprintf(tmp, sizeof(tmp), "%u", stream_state->t38_local_params.version); + a_line = ast_sdp_a_alloc("T38FaxVersion", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + + snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(stream_state->t38_local_params.rate)); + a_line = ast_sdp_a_alloc("T38FaxMaxBitRate", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } + + if (stream_state->t38_local_params.fill_bit_removal) { + a_line = ast_sdp_a_alloc("T38FaxFillBitRemoval", ""); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } + } - snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(stream_state->t38_local_params.rate)); - a_line = ast_sdp_a_alloc("T38FaxMaxBitRate", tmp); + if (stream_state->t38_local_params.transcoding_mmr) { + a_line = ast_sdp_a_alloc("T38FaxTranscodingMMR", ""); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } + } - if (stream_state->t38_local_params.fill_bit_removal) { - a_line = ast_sdp_a_alloc("T38FaxFillBitRemoval", ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + if (stream_state->t38_local_params.transcoding_jbig) { + a_line = ast_sdp_a_alloc("T38FaxTranscodingJBIG", ""); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; } + } - if (stream_state->t38_local_params.transcoding_mmr) { - a_line = ast_sdp_a_alloc("T38FaxTranscodingMMR", ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + switch (stream_state->t38_local_params.rate_management) { + case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF: + a_line = ast_sdp_a_alloc("T38FaxRateManagement", "transferredTCF"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; } - - if (stream_state->t38_local_params.transcoding_jbig) { - a_line = ast_sdp_a_alloc("T38FaxTranscodingJBIG", ""); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } + break; + case AST_T38_RATE_MANAGEMENT_LOCAL_TCF: + a_line = ast_sdp_a_alloc("T38FaxRateManagement", "localTCF"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; } + break; + } - switch (stream_state->t38_local_params.rate_management) { - case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF: - a_line = ast_sdp_a_alloc("T38FaxRateManagement", "transferredTCF"); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - break; - case AST_T38_RATE_MANAGEMENT_LOCAL_TCF: - a_line = ast_sdp_a_alloc("T38FaxRateManagement", "localTCF"); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - break; - } + snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(udptl->instance)); + a_line = ast_sdp_a_alloc("T38FaxMaxDatagram", tmp); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; + } - snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(udptl->instance)); - a_line = ast_sdp_a_alloc("T38FaxMaxDatagram", tmp); + switch (ast_udptl_get_error_correction_scheme(udptl->instance)) { + case UDPTL_ERROR_CORRECTION_NONE: + break; + case UDPTL_ERROR_CORRECTION_FEC: + a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPFEC"); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); return -1; } - - switch (ast_udptl_get_error_correction_scheme(udptl->instance)) { - case UDPTL_ERROR_CORRECTION_NONE: - break; - case UDPTL_ERROR_CORRECTION_FEC: - a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPFEC"); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - break; - case UDPTL_ERROR_CORRECTION_REDUNDANCY: - a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPRedundancy"); - if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { - ast_sdp_a_free(a_line); - ast_sdp_m_free(m_line); - return -1; - } - break; + break; + case UDPTL_ERROR_CORRECTION_REDUNDANCY: + a_line = ast_sdp_a_alloc("T38FaxUdpEC", "t38UDPRedundancy"); + if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { + ast_sdp_a_free(a_line); + ast_sdp_m_free(m_line); + return -1; } + break; } if (ast_sdp_add_m(sdp, m_line)) { @@ -3200,7 +3333,7 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta uint32_t t; int stream_count; - options = ast_sdp_state_get_options(sdp_state); + options = sdp_state->options; topology = capabilities->topology; t = tv.tv_sec + 2208988800UL; @@ -3233,18 +3366,22 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta switch (ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num))) { case AST_MEDIA_TYPE_AUDIO: case AST_MEDIA_TYPE_VIDEO: - if (sdp_add_m_from_rtp_stream(sdp, sdp_state, options, capabilities, stream_num)) { + if (sdp_add_m_from_rtp_stream(sdp, sdp_state, capabilities, stream_num)) { goto error; } break; case AST_MEDIA_TYPE_IMAGE: - if (sdp_add_m_from_udptl_stream(sdp, sdp_state, options, capabilities, stream_num)) { + if (sdp_add_m_from_udptl_stream(sdp, sdp_state, capabilities, stream_num)) { goto error; } break; case AST_MEDIA_TYPE_UNKNOWN: case AST_MEDIA_TYPE_TEXT: case AST_MEDIA_TYPE_END: + /* Decline any of these streams from the remote. */ + if (sdp_add_m_from_declined_remote_stream(sdp, sdp_state, stream_num)) { + goto error; + } break; } } diff --git a/tests/test_sdp.c b/tests/test_sdp.c index 662e2aaf154..0ab8ec8aee0 100644 --- a/tests/test_sdp.c +++ b/tests/test_sdp.c @@ -88,6 +88,12 @@ static int validate_m_line(struct ast_test *test, const struct ast_sdp_m_line *m return -1; } + if (m_line->port == 0) { + ast_test_status_update(test, "Expected %s m-line to not be declined\n", + media_type); + return -1; + } + if (ast_sdp_m_get_payload_count(m_line) != num_payloads) { ast_test_status_update(test, "Expected %s m-line payload count %d but got %d\n", media_type, num_payloads, ast_sdp_m_get_payload_count(m_line)); @@ -462,17 +468,20 @@ static int build_sdp_option_formats(struct ast_sdp_options *options, int num_str int idx; for (idx = 0; idx < num_streams; ++idx) { - RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + struct ast_format_cap *caps; - caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!caps) { - return -1; + if (ast_strlen_zero(formats[idx].formats)) { + continue; } - if (ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) { + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps + || ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) { + ao2_cleanup(caps); return -1; } ast_sdp_options_set_format_cap_type(options, formats[idx].type, caps); + ao2_cleanup(caps); } return 0; } @@ -494,10 +503,12 @@ static int build_sdp_option_formats(struct ast_sdp_options *options, int num_str * \param opt_formats Array of new stream media types and formats allowed to create. * NULL if use a default stream creation. * Not used if test_options provided. + * \param max_streams 0 if set max to max(3, num_streams) else max(max_streams, num_streams) + * Not used if test_options provided. * \param test_options Optional SDP options. */ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats, - int opt_num_streams, const struct sdp_format *opt_formats, + int opt_num_streams, const struct sdp_format *opt_formats, unsigned int max_streams, struct ast_sdp_options *test_options) { struct ast_stream_topology *topology = NULL; @@ -506,8 +517,6 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f int i; if (!test_options) { - unsigned int max_streams; - static const struct sdp_format sdp_formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw" }, { AST_MEDIA_TYPE_VIDEO, "vp8" }, @@ -520,8 +529,10 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f } /* Determine max_streams to allow */ - max_streams = ARRAY_LEN(sdp_formats); - if (ARRAY_LEN(sdp_formats) < num_streams) { + if (!max_streams) { + max_streams = ARRAY_LEN(sdp_formats); + } + if (max_streams < num_streams) { max_streams = num_streams; } ast_sdp_options_set_max_streams(options, max_streams); @@ -544,21 +555,27 @@ static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_f } for (i = 0; i < num_streams; ++i) { - RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); struct ast_stream *stream; - caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!caps) { - goto end; - } - if (ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) { - goto end; - } stream = ast_stream_alloc("sure_thing", formats[i].type); if (!stream) { goto end; } - ast_stream_set_formats(stream, caps); + if (!ast_strlen_zero(formats[i].formats)) { + struct ast_format_cap *caps; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps + || ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) { + ao2_cleanup(caps); + ast_stream_free(stream); + goto end; + } + ast_stream_set_formats(stream, caps); + ao2_cleanup(caps); + } else { + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + } if (ast_stream_topology_append_stream(topology, stream) < 0) { ast_stream_free(stream); goto end; @@ -604,7 +621,7 @@ AST_TEST_DEFINE(topology_to_sdp) } sdp_state = build_sdp_state(ARRAY_LEN(formats), formats, - ARRAY_LEN(formats), formats, NULL); + ARRAY_LEN(formats), formats, 0, NULL); if (!sdp_state) { goto end; } @@ -749,7 +766,7 @@ AST_TEST_DEFINE(sdp_to_topology) } sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats, - ARRAY_LEN(sdp_formats), sdp_formats, NULL); + ARRAY_LEN(sdp_formats), sdp_formats, 0, NULL); if (!sdp_state) { res = AST_TEST_FAIL; goto end; @@ -848,6 +865,7 @@ static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_tes int offer_num_streams, const struct sdp_format *offer_formats, int answer_num_streams, const struct sdp_format *answer_formats, int allowed_ans_num_streams, const struct sdp_format *allowed_ans_formats, + unsigned int max_streams, int (*validate_sdp)(struct ast_test *test, const struct ast_sdp *sdp)) { enum ast_test_result_state res = AST_TEST_PASS; @@ -857,36 +875,42 @@ static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_tes const struct ast_sdp *answerer_sdp; sdp_state_offerer = build_sdp_state(offer_num_streams, offer_formats, - offer_num_streams, offer_formats, NULL); + offer_num_streams, offer_formats, max_streams, NULL); if (!sdp_state_offerer) { + ast_test_status_update(test, "Building offerer SDP state failed\n"); res = AST_TEST_FAIL; goto end; } sdp_state_answerer = build_sdp_state(answer_num_streams, answer_formats, - allowed_ans_num_streams, allowed_ans_formats, NULL); + allowed_ans_num_streams, allowed_ans_formats, max_streams, NULL); if (!sdp_state_answerer) { + ast_test_status_update(test, "Building answerer SDP state failed\n"); res = AST_TEST_FAIL; goto end; } offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); if (!offerer_sdp) { + ast_test_status_update(test, "Building offerer offer failed\n"); res = AST_TEST_FAIL; goto end; } if (ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) { + ast_test_status_update(test, "Setting answerer offer failed\n"); res = AST_TEST_FAIL; goto end; } answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer); if (!answerer_sdp) { + ast_test_status_update(test, "Building answerer answer failed\n"); res = AST_TEST_FAIL; goto end; } if (ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp)) { + ast_test_status_update(test, "Setting offerer answer failed\n"); res = AST_TEST_FAIL; goto end; } @@ -902,6 +926,11 @@ static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_tes goto end; } offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer); + if (!offerer_sdp) { + ast_test_status_update(test, "Building offerer current sdp failed\n"); + res = AST_TEST_FAIL; + goto end; + } if (validate_sdp(test, offerer_sdp)) { res = AST_TEST_FAIL; goto end; @@ -944,6 +973,7 @@ AST_TEST_DEFINE(sdp_negotiation_initial) ARRAY_LEN(offerer_formats), offerer_formats, 0, NULL, 0, NULL, + 0, validate_avi_sdp_streams); } @@ -978,10 +1008,11 @@ AST_TEST_DEFINE(sdp_negotiation_type_change) ARRAY_LEN(offerer_formats), offerer_formats, ARRAY_LEN(answerer_formats), answerer_formats, 0, NULL, + 0, validate_avi_sdp_streams); } -static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) +static int validate_aviavia_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) { struct ast_sdp_m_line *m_line; @@ -1000,6 +1031,26 @@ static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct } m_line = ast_sdp_get_m(sdp, 2); + if (validate_m_line_declined(test, m_line, "image")) { + return -1; + } + + m_line = ast_sdp_get_m(sdp, 3); + if (validate_m_line_declined(test, m_line, "audio")) { + return -1; + } + + m_line = ast_sdp_get_m(sdp, 4); + if (validate_m_line_declined(test, m_line, "video")) { + return -1; + } + + m_line = ast_sdp_get_m(sdp, 5); + if (validate_m_line_declined(test, m_line, "image")) { + return -1; + } + + m_line = ast_sdp_get_m(sdp, 6); if (validate_m_line(test, m_line, "audio", 1)) { return -1; } @@ -1018,11 +1069,18 @@ static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct AST_TEST_DEFINE(sdp_negotiation_decline_incompatible) { static const struct sdp_format offerer_formats[] = { + /* Incompatible declined streams */ { AST_MEDIA_TYPE_AUDIO, "alaw" }, { AST_MEDIA_TYPE_VIDEO, "vp8" }, + { AST_MEDIA_TYPE_IMAGE, "t38" }, + /* Initially declined streams */ + { AST_MEDIA_TYPE_AUDIO, "" }, + { AST_MEDIA_TYPE_VIDEO, "" }, + { AST_MEDIA_TYPE_IMAGE, "" }, + /* Compatible stream so not all are declined */ { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw" }, }; - static const struct sdp_format answerer_formats[] = { + static const struct sdp_format allowed_formats[] = { { AST_MEDIA_TYPE_AUDIO, "ulaw" }, }; @@ -1032,9 +1090,9 @@ AST_TEST_DEFINE(sdp_negotiation_decline_incompatible) info->category = "/main/sdp/"; info->summary = "Simulate an initial negotiation declining streams"; info->description = - "Initial negotiation tests declining incompatible streams on the answering side.\n" - "After negotiation both offerer and answerer sides should have the same\n" - "expected stream types and formats."; + "Initial negotiation tests declining incompatible streams.\n" + "After negotiation both offerer and answerer sides should have\n" + "the same expected stream types and formats."; return AST_TEST_NOT_RUN; case TEST_EXECUTE: break; @@ -1042,9 +1100,10 @@ AST_TEST_DEFINE(sdp_negotiation_decline_incompatible) return sdp_negotiation_completed_tests(test, ARRAY_LEN(offerer_formats), offerer_formats, - ARRAY_LEN(answerer_formats), answerer_formats, - ARRAY_LEN(answerer_formats), answerer_formats, - validate_ava_declined_sdp_streams); + 0, NULL, + ARRAY_LEN(allowed_formats), allowed_formats, + ARRAY_LEN(offerer_formats), + validate_aviavia_declined_sdp_streams); } static int validate_aaaa_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp) @@ -1114,6 +1173,7 @@ AST_TEST_DEFINE(sdp_negotiation_decline_max_streams) ARRAY_LEN(offerer_formats), offerer_formats, 0, NULL, 0, NULL, + 0, validate_aaaa_declined_sdp_streams); } @@ -1143,13 +1203,13 @@ AST_TEST_DEFINE(sdp_negotiation_not_acceptable) } sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats, - ARRAY_LEN(offerer_formats), offerer_formats, NULL); + ARRAY_LEN(offerer_formats), offerer_formats, 0, NULL); if (!sdp_state_offerer) { res = AST_TEST_FAIL; goto end; } - sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, NULL); + sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, 0, NULL); if (!sdp_state_answerer) { res = AST_TEST_FAIL; goto end; @@ -1245,7 +1305,7 @@ AST_TEST_DEFINE(sdp_ssrc_attributes) } ast_sdp_options_set_ssrc(options, 1); - test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, options); + test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, 0, options); if (!test_state) { ast_test_status_update(test, "Failed to create SDP state\n"); goto end; @@ -1335,11 +1395,10 @@ static struct ast_stream_topology *build_update_topology(const struct sdp_topolo struct ast_format_cap *caps; caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!caps) { - goto fail; - } - if (ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) { - ao2_ref(caps, -1); + if (!caps + || ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) { + ao2_cleanup(caps); + ast_stream_free(stream); goto fail; } ast_stream_set_formats(stream, caps); From 45a1f4e2ae3749d16820d7f9ea1e7dfbe028bbdf Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 20 Jun 2017 16:01:48 -0500 Subject: [PATCH 1333/1578] bridge: stuck channel(s) after failed attended transfer If an attended transfer failed it was possible for some of the channels involved to get "stuck" because Asterisk was not hanging up the transfer target. This patch ensures Asterisk hangs up the transfer target when an attended transfer failure occurs. ASTERISK-27075 #close Change-Id: I98a6ecd92d3461ab98c36f0d9451d23adaf3e5f9 --- main/bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/bridge.c b/main/bridge.c index 8cde62cb536..07880ab8fd0 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -4822,7 +4822,7 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra res = AST_BRIDGE_TRANSFER_SUCCESS; end: - if (res == AST_BRIDGE_TRANSFER_SUCCESS && hangup_target) { + if ((res == AST_BRIDGE_TRANSFER_SUCCESS && hangup_target) || res == AST_BRIDGE_TRANSFER_FAIL) { ast_softhangup(to_transfer_target, AST_SOFTHANGUP_DEV); } From 27dae55fb6bf802befe6f398d02f278f2c31114c Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 20 Jun 2017 16:05:08 -0500 Subject: [PATCH 1334/1578] core_local: local channel data not being properly unref'ed and unlocked In an earlier version of Asterisk a local channel [un]lock all functions were added in order to keep a crash from occurring when a channel hung up too early during an attended transfer. Unfortunately, when a transfer failure occurs and depending on the timing, the local channels sometime do not get properly unlocked and deref'ed after being locked and ref'ed. This happens because the underlying local channel structure gets NULLed out before unlocking. This patch reworks those [un]lock functions and makes sure the values that get locked and ref'ed later get unlocked and deref'ed. ASTERISK-27074 #close Change-Id: Ice96653e29bd9d6674ed5f95feb6b448ab148b09 --- include/asterisk/core_local.h | 37 +++++++++++++++--------------- main/bridge.c | 7 +++--- main/core_local.c | 42 ++++++++++++++++------------------- 3 files changed, 42 insertions(+), 44 deletions(-) diff --git a/include/asterisk/core_local.h b/include/asterisk/core_local.h index 8557072c69b..27e92447721 100644 --- a/include/asterisk/core_local.h +++ b/include/asterisk/core_local.h @@ -42,36 +42,37 @@ struct stasis_message_type; /* ------------------------------------------------------------------- */ /*! - * \brief Lock the "chan" and "owner" channels (and return them) on the base - * private structure as well as the base private structure itself. + * \brief Add a reference to the local channel's private tech, lock the local channel's + * private base, and add references and lock both sides of the local channel. * - * \note This also adds references to each of the above mentioned elements and - * also the underlying private local structure. * \note None of these locks should be held prior to calling this function. - * \note To undo this process call ast_local_unlock_all. + * \note To undo this process call ast_local_unlock_all2. * - * \since 13.8.0 + * \since 13.17.0, 14.6.0 * * \param chan Must be a local channel - * \param outchan The local channel's "chan" channel - * \param outowner The local channel's "owner" channel + * \param tech_pvt [out] channel's private tech (ref and lock added) + * \param base_chan [out] One side of the local channel (ref and lock added) + * \param base_owner [out] Other side of the local channel (ref and lock added) */ -void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan, - struct ast_channel **outowner); +void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt, + struct ast_channel **base_chan, struct ast_channel **base_owner); /*! - * \brief Unlock the "chan" and "owner" channels on the base private structure - * as well as the base private structure itself. + * \brief Remove a reference to the given local channel's private tech, unlock the given + * local channel's private base, and remove references and unlock both sides of + * given the local channel. * - * \note This also removes references to each of the above mentioned elements and - * also the underlying private local structure. - * \note This function should be used in conjunction with ast_local_lock_all. + * \note This function should be used in conjunction with ast_local_lock_all2. * - * \since 13.8.0 + * \since 13.17.0, 14.6.0 * - * \param chan Must be a local channel + * \param tech_pvt channel's private tech (ref and lock removed) + * \param base_chan One side of the local channel (ref and lock removed) + * \param base_owner Other side of the local channel (ref and lock removed) */ -void ast_local_unlock_all(struct ast_channel *chan); +void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan, + struct ast_channel *base_owner); /*! * \brief Get the other local channel in the pair. diff --git a/main/bridge.c b/main/bridge.c index 8cde62cb536..8902145cfef 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -4276,14 +4276,15 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2); if (bridge2) { + void *tech; struct ast_channel *locals[2]; /* Have to lock everything just in case a hangup comes in early */ - ast_local_lock_all(local_chan, &locals[0], &locals[1]); + ast_local_lock_all(local_chan, &tech, &locals[0], &locals[1]); if (!locals[0] || !locals[1]) { ast_log(LOG_ERROR, "Transfer failed probably due to an early hangup - " "missing other half of '%s'\n", ast_channel_name(local_chan)); - ast_local_unlock_all(local_chan); + ast_local_unlock_all(tech, locals[0], locals[1]); ao2_cleanup(local_chan); return AST_BRIDGE_TRANSFER_FAIL; } @@ -4294,7 +4295,7 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha } ast_attended_transfer_message_add_link(transfer_msg, locals); - ast_local_unlock_all(local_chan); + ast_local_unlock_all(tech, locals[0], locals[1]); } else { ast_attended_transfer_message_add_app(transfer_msg, app, local_chan); } diff --git a/main/core_local.c b/main/core_local.c index aa232a4b6df..23c7cce9d86 100644 --- a/main/core_local.c +++ b/main/core_local.c @@ -233,43 +233,39 @@ struct local_pvt { char exten[AST_MAX_EXTENSION]; }; -void ast_local_lock_all(struct ast_channel *chan, struct ast_channel **outchan, - struct ast_channel **outowner) +void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt, + struct ast_channel **base_chan, struct ast_channel **base_owner) { struct local_pvt *p = ast_channel_tech_pvt(chan); - *outchan = NULL; - *outowner = NULL; + *tech_pvt = NULL; + *base_chan = NULL; + *base_owner = NULL; if (p) { - ao2_ref(p, 1); - ast_unreal_lock_all(&p->base, outchan, outowner); + *tech_pvt = ao2_bump(p); + ast_unreal_lock_all(&p->base, base_chan, base_owner); } } -void ast_local_unlock_all(struct ast_channel *chan) +void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan, + struct ast_channel *base_owner) { - struct local_pvt *p = ast_channel_tech_pvt(chan); - struct ast_unreal_pvt *base; - - if (!p) { - return; + if (base_chan) { + ast_channel_unlock(base_chan); + ast_channel_unref(base_chan); } - base = &p->base; - - if (base->owner) { - ast_channel_unlock(base->owner); - ast_channel_unref(base->owner); + if (base_owner) { + ast_channel_unlock(base_owner); + ast_channel_unref(base_owner); } - if (base->chan) { - ast_channel_unlock(base->chan); - ast_channel_unref(base->chan); + if (tech_pvt) { + struct local_pvt *p = tech_pvt; + ao2_unlock(&p->base); + ao2_ref(tech_pvt, -1); } - - ao2_unlock(base); - ao2_ref(p, -1); } struct ast_channel *ast_local_get_peer(struct ast_channel *ast) From 34db4c3993dd2d6276c1d2ccdf31c5f3daad2785 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Fri, 16 Jun 2017 19:08:30 -0400 Subject: [PATCH 1335/1578] res_pjsip_mwi: update unsolicited MWI subscriptions on updating contact Do not need to unsubscribe/subscribe on creating the ednpoint's contact. The modified function create_mwi_subscriptions_for_endpoint adds the subscription only if it does not exist. The subscriptions aren't added for active contacts which are retrieved on startup from realtime if mwi_disable_initial_unsolicited=yes. Because the mwi_contact_added is not called. So the subscriptions also should be created on updating contact. ASTERISK-26230 #close Change-Id: I47e265af9296ca09aa42a316fdacac104148cee4 --- res/res_pjsip_mwi.c | 68 ++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index f73f10cd692..d0930df4c60 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -1102,6 +1102,13 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags } if (endpoint->subscription.mwi.aggregate) { + const char *endpoint_id = ast_sorcery_object_get_id(endpoint); + + /* Check if subscription exists */ + aggregate_sub = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (aggregate_sub) { + return 0; + } aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL); if (!aggregate_sub) { return 0; @@ -1113,7 +1120,9 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags struct mwi_subscription *sub; struct mwi_stasis_subscription *mwi_stasis_sub; - if (ast_strlen_zero(mailbox)) { + /* check if subscription exists */ + if (ast_strlen_zero(mailbox) || + (!aggregate_sub && endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox))) { continue; } @@ -1189,44 +1198,45 @@ static int send_contact_notify(void *obj, void *arg, int flags) return 0; } -/*! \brief Function called when a contact is updated */ -static void mwi_contact_updated(const void *object) +/*! \brief Create mwi subscriptions and notify */ +static void mwi_contact_changed(const struct ast_sip_contact *contact) { - char *id = ast_strdupa(ast_sorcery_object_get_id(object)), *aor = NULL; + char *id = ast_strdupa(ast_sorcery_object_get_id(contact)); + char *aor = NULL; + struct ast_sip_endpoint *endpoint = NULL; - aor = strsep(&id, ";@"); - - ao2_callback(unsolicited_mwi, OBJ_NODATA, send_contact_notify, aor); -} - -/*! \brief Function called when a contact is added */ -static void mwi_contact_added(const void *object) -{ - const struct ast_sip_contact *contact = object; - struct ao2_iterator *mwi_subs; - struct mwi_subscription *mwi_sub; - const char *endpoint_id = ast_sorcery_object_get_id(contact->endpoint); + if (contact->endpoint) { + endpoint = ao2_bump(contact->endpoint); + } else { + if (!ast_strlen_zero(contact->endpoint_name)) { + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", contact->endpoint_name); + } + } - if (ast_strlen_zero(contact->endpoint->subscription.mwi.mailboxes)) { + if (!endpoint || ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { + ao2_cleanup(endpoint); return; } ao2_lock(unsolicited_mwi); + create_mwi_subscriptions_for_endpoint(endpoint, NULL, 0); + ao2_unlock(unsolicited_mwi); + ao2_cleanup(endpoint); - mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, - OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK); - if (mwi_subs) { - for (; (mwi_sub = ao2_iterator_next(mwi_subs)); ao2_cleanup(mwi_sub)) { - unsubscribe(mwi_sub, NULL, 0); - } - ao2_iterator_destroy(mwi_subs); - } - - create_mwi_subscriptions_for_endpoint(contact->endpoint, NULL, 0); + aor = strsep(&id, ";@"); + ao2_callback(unsolicited_mwi, OBJ_NODATA, send_contact_notify, aor); +} - ao2_unlock(unsolicited_mwi); +/*! \brief Function called when a contact is updated */ +static void mwi_contact_updated(const void *object) +{ + mwi_contact_changed(object); +} - mwi_contact_updated(object); +/*! \brief Function called when a contact is added */ +static void mwi_contact_added(const void *object) +{ + mwi_contact_changed(object); } /*! \brief Function called when a contact is deleted */ From 975e271b0189844c37f922b5807c61b1c7537634 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 21 Jun 2017 17:57:11 -0500 Subject: [PATCH 1336/1578] res_pjsip_mwi.c: Eliminate RAII_VAR in contact delete observer Change-Id: I0bc97c6608de1d1a4228826b3b3be43f162f05f3 --- res/res_pjsip_mwi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index f73f10cd692..cc4b40a04d3 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -1235,8 +1235,8 @@ static void mwi_contact_deleted(const void *object) const struct ast_sip_contact *contact = object; struct ao2_iterator *mwi_subs; struct mwi_subscription *mwi_sub; - RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup); + struct ast_sip_endpoint *endpoint = NULL; + struct ast_sip_contact *found_contact; if (contact->endpoint) { endpoint = ao2_bump(contact->endpoint); @@ -1247,12 +1247,15 @@ static void mwi_contact_deleted(const void *object) } if (!endpoint || ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { + ao2_cleanup(endpoint); return; } /* Check if there is another contact */ found_contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors); + ao2_cleanup(endpoint); if (found_contact) { + ao2_cleanup(found_contact); return; } From 0cef7b9d4ef3a7f55685203328960a89dd7fd247 Mon Sep 17 00:00:00 2001 From: Alexei Gradinari Date: Mon, 19 Jun 2017 18:21:29 -0400 Subject: [PATCH 1337/1578] app_voicemail: IMAP connection control A new global option "imap_poll_logout" was added to specify whether need to disconnect from the IMAP server after polling of mailboxes. ASTERISK-27068 #close Closing IMAP connection after loading mailbox from voicemail.conf ASTERISK-24052 #close Change-Id: Ib7558ba04516240a32b65f42e9be64372a0ae12a --- CHANGES | 6 ++++++ apps/app_voicemail.c | 17 +++++++++++++++++ configs/samples/voicemail.conf.sample | 3 +++ 3 files changed, 26 insertions(+) diff --git a/CHANGES b/CHANGES index 9cd579b6565..97cdda96ea0 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,12 @@ app_queue --- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------ ------------------------------------------------------------------------------ +app_voicemail +------------------ + * A new global option "imap_poll_logout" was added to specify whether need to + disconnect from the IMAP server after polling of mailboxes. + Default: no + res_pjsip ------------------ * A new endpoint option "refer_blind_progress" was added to turn off notifying diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index a9516801332..783cab69ecf 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -505,6 +505,7 @@ static int imapversion = 1; static int expungeonhangup = 1; static int imapgreetings = 0; +static int imap_poll_logout = 0; static char delimiter = '\0'; /* mail_open cannot be protected on a stream basis */ @@ -542,6 +543,8 @@ static int imap_retrieve_file (const char *dir, const int msgnum, const char *ma static int imap_delete_old_greeting (char *dir, struct vm_state *vms); static void check_quota(struct vm_state *vms, char *mailbox); static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box); +static void imap_logout(const char *mailbox_id); + struct vmstate { struct vm_state *vms; AST_LIST_ENTRY(vmstate) list; @@ -12303,6 +12306,9 @@ static int append_mailbox(const char *context, const char *box, const char *data strcat(mailbox_full, context); inboxcount2(mailbox_full, &urgent, &new, &old); +#ifdef IMAP_STORAGE + imap_logout(mailbox_full); +#endif queue_mwi_event(NULL, mailbox_full, urgent, new, old); return 0; @@ -13055,6 +13061,12 @@ static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub) inboxcount2(mwi_sub->mailbox, &urgent, &new, &old); +#ifdef IMAP_STORAGE + if (imap_poll_logout) { + imap_logout(mwi_sub->mailbox); + } +#endif + if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) { mwi_sub->old_urgent = urgent; mwi_sub->old_new = new; @@ -13775,6 +13787,11 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con } else { ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder)); } + if ((val = ast_variable_retrieve(cfg, "general", "imap_poll_logout"))) { + imap_poll_logout = ast_true(val); + } else { + imap_poll_logout = 0; + } /* There is some very unorthodox casting done here. This is due * to the way c-client handles the argument passed in. It expects a diff --git a/configs/samples/voicemail.conf.sample b/configs/samples/voicemail.conf.sample index f8221eebe05..84e83a3447d 100644 --- a/configs/samples/voicemail.conf.sample +++ b/configs/samples/voicemail.conf.sample @@ -227,6 +227,9 @@ pagerdateformat=%A, %B %d, %Y at %r ;imapclosetimeout=60 ; The TCP close timeout (in seconds) ;imapreadtimeout=60 ; The TCP read timeout (in seconds) ;imapwritetimeout=60 ; The TCP write timeout (in seconds) +;imap_poll_logout=no ; If pollmailboxes=yes, then specify whether need to + ; disconnect from the IMAP server after polling. + ; Default: no ; ----------------------------------------------------------------------------- ; From 78277555703ba3b58ab925040211a272011a9a12 Mon Sep 17 00:00:00 2001 From: Ivan Poddubny Date: Tue, 27 Jun 2017 11:37:11 +0200 Subject: [PATCH 1338/1578] app_queue: Fix returning to dialplan when a queue is empty The fix for ASTERISK-25665 introduced a regression. The return value of queue_exec used to be 0 in case of leavewhenempty but it was changed to -1 (returned from wait_our_turn and passed transparently by queue_exec), thus leading to hangup instead of returning back to dialplan. This commit resets the value back to 0 in this case, restoring original behavior. ASTERISK-27065 #close Reported by: Marek Cervenka Change-Id: Id9c83b75aeda463250155e88c5004be52bbca5ac --- apps/app_queue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index f158a4caa81..b306af1aefa 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -8301,6 +8301,9 @@ static int queue_exec(struct ast_channel *chan, const char *data) } else if (qcontinue) { reason = QUEUE_CONTINUE; res = 0; + } else if (reason == QUEUE_LEAVEEMPTY) { + /* Return back to dialplan, don't hang up */ + res = 0; } } else if (qe.valid_digits) { ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY", From 80e11bd79b8a9ca9ed6733c316332e8fb9315b94 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 8 Jun 2017 21:50:43 -0600 Subject: [PATCH 1339/1578] bridge_native_rtp: Keep rtp instance refs on bridge_channel There have been reports of deadlocks caused by an attempt to send a frame to a channel's rtp instance after the channel has left the native bridge and been destroyed. This patch effectively causes the bridge channel to keep a reference to the glue and both the audio and video rtp instances so what gets started will get stopped. ASTERISK-26978 #close Reported-by: Ross Beer Change-Id: I9e1ac49fa4af68d64826ccccd152593cf8cdb21a --- bridges/bridge_native_rtp.c | 645 ++++++++++++++++++++++++++-------- include/asterisk/rtp_engine.h | 9 +- 2 files changed, 515 insertions(+), 139 deletions(-) diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 4af93bfca21..a459c9ce778 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -44,76 +44,214 @@ #include "asterisk/frame.h" #include "asterisk/rtp_engine.h" -/*! \brief Internal structure which contains information about bridged RTP channels */ -struct native_rtp_bridge_data { +/*! \brief Internal structure which contains bridged RTP channel hook data */ +struct native_rtp_framehook_data { /*! \brief Framehook used to intercept certain control frames */ int id; /*! \brief Set when this framehook has been detached */ unsigned int detached; }; -/*! \brief Internal helper function which gets all RTP information (glue and instances) relating to the given channels */ -static enum ast_rtp_glue_result native_rtp_bridge_get(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_glue **glue0, - struct ast_rtp_glue **glue1, struct ast_rtp_instance **instance0, struct ast_rtp_instance **instance1, - struct ast_rtp_instance **vinstance0, struct ast_rtp_instance **vinstance1) +struct rtp_glue_stream { + /*! \brief RTP instance */ + struct ast_rtp_instance *instance; + /*! \brief glue result */ + enum ast_rtp_glue_result result; +}; + +struct rtp_glue_data { + /*! + * \brief glue callbacks + * + * \note The glue data is considered valid if cb is not NULL. + */ + struct ast_rtp_glue *cb; + struct rtp_glue_stream audio; + struct rtp_glue_stream video; + /*! Combined glue result of both bridge channels. */ + enum ast_rtp_glue_result result; +}; + +/*! \brief Internal structure which contains instance information about bridged RTP channels */ +struct native_rtp_bridge_channel_data { + /*! \brief Channel's hook data */ + struct native_rtp_framehook_data *hook_data; + /*! + * \brief Glue callbacks to bring remote channel streams back to Asterisk. + * \note NULL if channel streams are local. + */ + struct ast_rtp_glue *remote_cb; + /*! \brief Channel's cached RTP glue information */ + struct rtp_glue_data glue; +}; + +static void rtp_glue_data_init(struct rtp_glue_data *glue) { - enum ast_rtp_glue_result audio_glue0_res; - enum ast_rtp_glue_result video_glue0_res; - enum ast_rtp_glue_result audio_glue1_res; - enum ast_rtp_glue_result video_glue1_res; + glue->cb = NULL; + glue->audio.instance = NULL; + glue->audio.result = AST_RTP_GLUE_RESULT_FORBID; + glue->video.instance = NULL; + glue->video.result = AST_RTP_GLUE_RESULT_FORBID; + glue->result = AST_RTP_GLUE_RESULT_FORBID; +} - if (!(*glue0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) || - !(*glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type))) { - return AST_RTP_GLUE_RESULT_FORBID; +static void rtp_glue_data_destroy(struct rtp_glue_data *glue) +{ + if (!glue) { + return; } + ao2_cleanup(glue->audio.instance); + ao2_cleanup(glue->video.instance); +} + +static void rtp_glue_data_reset(struct rtp_glue_data *glue) +{ + rtp_glue_data_destroy(glue); + rtp_glue_data_init(glue); +} + +static void native_rtp_bridge_channel_data_free(struct native_rtp_bridge_channel_data *data) +{ + ast_debug(2, "Destroying channel tech_pvt data %p\n", data); - audio_glue0_res = (*glue0)->get_rtp_info(c0, instance0); - video_glue0_res = (*glue0)->get_vrtp_info ? (*glue0)->get_vrtp_info(c0, vinstance0) : AST_RTP_GLUE_RESULT_FORBID; + /* + * hook_data will probably already have been unreferenced by the framehook detach + * and the pointer set to null. + */ + ao2_cleanup(data->hook_data); - audio_glue1_res = (*glue1)->get_rtp_info(c1, instance1); - video_glue1_res = (*glue1)->get_vrtp_info ? (*glue1)->get_vrtp_info(c1, vinstance1) : AST_RTP_GLUE_RESULT_FORBID; + rtp_glue_data_reset(&data->glue); + ast_free(data); +} + +static struct native_rtp_bridge_channel_data *native_rtp_bridge_channel_data_alloc(void) +{ + struct native_rtp_bridge_channel_data *data; + + data = ast_calloc(1, sizeof(*data)); + if (data) { + rtp_glue_data_init(&data->glue); + } + return data; +} + +/*! + * \internal + * \brief Helper function which gets all RTP information (glue and instances) relating to the given channels + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int rtp_glue_data_get(struct ast_channel *c0, struct rtp_glue_data *glue0, + struct ast_channel *c1, struct rtp_glue_data *glue1) +{ + struct ast_rtp_glue *cb0; + struct ast_rtp_glue *cb1; + enum ast_rtp_glue_result combined_result; + + cb0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type); + cb1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type); + if (!cb0 || !cb1) { + /* One or both channels doesn't have any RTP glue registered. */ + return -1; + } + + /* The glue callbacks bump the RTP instance refcounts for us. */ + + glue0->cb = cb0; + glue0->audio.result = cb0->get_rtp_info(c0, &glue0->audio.instance); + glue0->video.result = cb0->get_vrtp_info + ? cb0->get_vrtp_info(c0, &glue0->video.instance) : AST_RTP_GLUE_RESULT_FORBID; + + glue1->cb = cb1; + glue1->audio.result = cb1->get_rtp_info(c1, &glue1->audio.instance); + glue1->video.result = cb1->get_vrtp_info + ? cb1->get_vrtp_info(c1, &glue1->video.instance) : AST_RTP_GLUE_RESULT_FORBID; + + /* + * Now determine the combined glue result. + */ /* Apply any limitations on direct media bridging that may be present */ - if (audio_glue0_res == audio_glue1_res && audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) { - if ((*glue0)->allow_rtp_remote && !((*glue0)->allow_rtp_remote(c0, *instance1))) { + if (glue0->audio.result == glue1->audio.result && glue1->audio.result == AST_RTP_GLUE_RESULT_REMOTE) { + if (glue0->cb->allow_rtp_remote && !glue0->cb->allow_rtp_remote(c0, glue1->audio.instance)) { /* If the allow_rtp_remote indicates that remote isn't allowed, revert to local bridge */ - audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; - } else if ((*glue1)->allow_rtp_remote && !((*glue1)->allow_rtp_remote(c1, *instance0))) { - audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; + glue0->audio.result = glue1->audio.result = AST_RTP_GLUE_RESULT_LOCAL; + } else if (glue1->cb->allow_rtp_remote && !glue1->cb->allow_rtp_remote(c1, glue0->audio.instance)) { + glue0->audio.result = glue1->audio.result = AST_RTP_GLUE_RESULT_LOCAL; } } - if (video_glue0_res == video_glue1_res && video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) { - if ((*glue0)->allow_vrtp_remote && !((*glue0)->allow_vrtp_remote(c0, *instance1))) { + if (glue0->video.result == glue1->video.result && glue1->video.result == AST_RTP_GLUE_RESULT_REMOTE) { + if (glue0->cb->allow_vrtp_remote && !glue0->cb->allow_vrtp_remote(c0, glue1->audio.instance)) { /* if the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */ - video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; - } else if ((*glue1)->allow_vrtp_remote && !((*glue1)->allow_vrtp_remote(c1, *instance0))) { - video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; + glue0->video.result = glue1->video.result = AST_RTP_GLUE_RESULT_LOCAL; + } else if (glue1->cb->allow_vrtp_remote && !glue1->cb->allow_vrtp_remote(c1, glue0->audio.instance)) { + glue0->video.result = glue1->video.result = AST_RTP_GLUE_RESULT_LOCAL; } } /* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */ - if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID - && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE - || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) { - audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID; + if (glue0->video.result != AST_RTP_GLUE_RESULT_FORBID + && (glue0->audio.result != AST_RTP_GLUE_RESULT_REMOTE + || glue0->video.result != AST_RTP_GLUE_RESULT_REMOTE)) { + glue0->audio.result = AST_RTP_GLUE_RESULT_FORBID; } - if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID - && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE - || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) { - audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID; + if (glue1->video.result != AST_RTP_GLUE_RESULT_FORBID + && (glue1->audio.result != AST_RTP_GLUE_RESULT_REMOTE + || glue1->video.result != AST_RTP_GLUE_RESULT_REMOTE)) { + glue1->audio.result = AST_RTP_GLUE_RESULT_FORBID; } /* The order of preference is: forbid, local, and remote. */ - if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID || - audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) { + if (glue0->audio.result == AST_RTP_GLUE_RESULT_FORBID + || glue1->audio.result == AST_RTP_GLUE_RESULT_FORBID) { /* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */ - return AST_RTP_GLUE_RESULT_FORBID; - } else if (audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || - audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) { - return AST_RTP_GLUE_RESULT_LOCAL; + combined_result = AST_RTP_GLUE_RESULT_FORBID; + } else if (glue0->audio.result == AST_RTP_GLUE_RESULT_LOCAL + || glue1->audio.result == AST_RTP_GLUE_RESULT_LOCAL) { + combined_result = AST_RTP_GLUE_RESULT_LOCAL; } else { - return AST_RTP_GLUE_RESULT_REMOTE; + combined_result = AST_RTP_GLUE_RESULT_REMOTE; + } + glue0->result = combined_result; + glue1->result = combined_result; + + return 0; +} + +/*! + * \internal + * \brief Get the current RTP native bridge combined glue result. + * \since 15.0.0 + * + * \param c0 First bridge channel + * \param c1 Second bridge channel + * + * \note Both channels must be locked when calling this function. + * + * \return Current combined glue result. + */ +static enum ast_rtp_glue_result rtp_glue_get_current_combined_result(struct ast_channel *c0, + struct ast_channel *c1) +{ + struct rtp_glue_data glue_a; + struct rtp_glue_data glue_b; + struct rtp_glue_data *glue0; + struct rtp_glue_data *glue1; + enum ast_rtp_glue_result combined_result; + + rtp_glue_data_init(&glue_a); + glue0 = &glue_a; + rtp_glue_data_init(&glue_b); + glue1 = &glue_b; + if (rtp_glue_data_get(c0, glue0, c1, glue1)) { + return AST_RTP_GLUE_RESULT_FORBID; } + + combined_result = glue0->result; + rtp_glue_data_destroy(glue0); + rtp_glue_data_destroy(glue1); + return combined_result; } /*! @@ -129,52 +267,91 @@ static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channe { struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); - enum ast_rtp_glue_result native_type = AST_RTP_GLUE_RESULT_FORBID; - struct ast_rtp_glue *glue0, *glue1; - RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, tinstance0, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, tinstance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); - RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); + struct native_rtp_bridge_channel_data *data0; + struct native_rtp_bridge_channel_data *data1; + struct rtp_glue_data *glue0; + struct rtp_glue_data *glue1; + struct ast_format_cap *cap0; + struct ast_format_cap *cap1; + enum ast_rtp_glue_result native_type; if (bc0 == bc1) { return; } + data0 = bc0->tech_pvt; + data1 = bc1->tech_pvt; + if (!data0 || !data1) { + /* Not all channels are joined with the bridge tech yet */ + return; + } + glue0 = &data0->glue; + glue1 = &data1->glue; ast_channel_lock_both(bc0->chan, bc1->chan); - if (!bc0->suspended && !bc1->suspended) { - native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1); + + if (!glue0->cb || !glue1->cb) { + /* + * Somebody doesn't have glue data so the bridge isn't running + * + * Actually neither side should have glue data. + */ + ast_assert(!glue0->cb && !glue1->cb); + + if (rtp_glue_data_get(bc0->chan, glue0, bc1->chan, glue1)) { + /* + * This might happen if one of the channels got masqueraded + * at a critical time. It's a bit of a stretch even then + * since the channel is in a bridge. + */ + goto done; + } } + ast_debug(2, "Bridge '%s'. Tech starting '%s' and '%s' with target '%s'\n", + bridge->uniqueid, ast_channel_name(bc0->chan), ast_channel_name(bc1->chan), + target ? ast_channel_name(target) : "none"); + + native_type = glue0->result; + switch (native_type) { case AST_RTP_GLUE_RESULT_LOCAL: - if (ast_rtp_instance_get_engine(instance0)->local_bridge) { - ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, instance1); + if (ast_rtp_instance_get_engine(glue0->audio.instance)->local_bridge) { + ast_rtp_instance_get_engine(glue0->audio.instance)->local_bridge(glue0->audio.instance, glue1->audio.instance); } - if (ast_rtp_instance_get_engine(instance1)->local_bridge) { - ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, instance0); + if (ast_rtp_instance_get_engine(glue1->audio.instance)->local_bridge) { + ast_rtp_instance_get_engine(glue1->audio.instance)->local_bridge(glue1->audio.instance, glue0->audio.instance); } - ast_rtp_instance_set_bridged(instance0, instance1); - ast_rtp_instance_set_bridged(instance1, instance0); + ast_rtp_instance_set_bridged(glue0->audio.instance, glue1->audio.instance); + ast_rtp_instance_set_bridged(glue1->audio.instance, glue0->audio.instance); ast_verb(4, "Locally RTP bridged '%s' and '%s' in stack\n", ast_channel_name(bc0->chan), ast_channel_name(bc1->chan)); break; - case AST_RTP_GLUE_RESULT_REMOTE: - if (glue0->get_codec) { - glue0->get_codec(bc0->chan, cap0); + cap0 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + cap1 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!cap0 || !cap1) { + ao2_cleanup(cap0); + ao2_cleanup(cap1); + break; } - if (glue1->get_codec) { - glue1->get_codec(bc1->chan, cap1); + + if (glue0->cb->get_codec) { + glue0->cb->get_codec(bc0->chan, cap0); + } + if (glue1->cb->get_codec) { + glue1->cb->get_codec(bc1->chan, cap1); } - /* If we have a target, it's the channel that received the UNHOLD or UPDATE_RTP_PEER frame and was told to resume */ + /* + * If we have a target, it's the channel that received the UNHOLD or + * UPDATE_RTP_PEER frame and was told to resume + */ if (!target) { - glue0->update_peer(bc0->chan, instance1, vinstance1, tinstance1, cap1, 0); - glue1->update_peer(bc1->chan, instance0, vinstance0, tinstance0, cap0, 0); + /* Send both channels to remote */ + data0->remote_cb = glue0->cb; + data1->remote_cb = glue1->cb; + glue0->cb->update_peer(bc0->chan, glue1->audio.instance, glue1->video.instance, NULL, cap1, 0); + glue1->cb->update_peer(bc1->chan, glue0->audio.instance, glue0->video.instance, NULL, cap0, 0); ast_verb(4, "Remotely bridged '%s' and '%s' - media will flow directly between them\n", ast_channel_name(bc0->chan), ast_channel_name(bc1->chan)); } else { @@ -184,51 +361,121 @@ static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channe * already set up to handle the new media path or will have its own set of updates independent * of this pass. */ + ast_debug(2, "Bridge '%s'. Sending '%s' back to remote\n", + bridge->uniqueid, ast_channel_name(target)); if (bc0->chan == target) { - glue0->update_peer(bc0->chan, instance1, vinstance1, tinstance1, cap1, 0); + data0->remote_cb = glue0->cb; + glue0->cb->update_peer(bc0->chan, glue1->audio.instance, glue1->video.instance, NULL, cap1, 0); } else { - glue1->update_peer(bc1->chan, instance0, vinstance0, tinstance0, cap0, 0); + data1->remote_cb = glue1->cb; + glue1->cb->update_peer(bc1->chan, glue0->audio.instance, glue0->video.instance, NULL, cap0, 0); } } + + ao2_cleanup(cap0); + ao2_cleanup(cap1); break; case AST_RTP_GLUE_RESULT_FORBID: break; } + if (native_type != AST_RTP_GLUE_RESULT_REMOTE) { + /* Bring any remaining channels back to us. */ + if (data0->remote_cb) { + ast_debug(2, "Bridge '%s'. Bringing back '%s' to us\n", + bridge->uniqueid, ast_channel_name(bc0->chan)); + data0->remote_cb->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0); + data0->remote_cb = NULL; + } + if (data1->remote_cb) { + ast_debug(2, "Bridge '%s'. Bringing back '%s' to us\n", + bridge->uniqueid, ast_channel_name(bc1->chan)); + data1->remote_cb->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0); + data1->remote_cb = NULL; + } + } + +done: ast_channel_unlock(bc0->chan); ast_channel_unlock(bc1->chan); } +/*! + * \internal + * \brief Stop native RTP bridging of two channels + * + * \param bridge The bridge that had native RTP bridging happening on it + * \param target If remote RTP bridging, the channel that is held. + * + * \note The first channel to leave the bridge triggers the cleanup for both channels + */ static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel *target) { struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels); struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels); - enum ast_rtp_glue_result native_type; - struct ast_rtp_glue *glue0, *glue1 = NULL; - RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup); + struct native_rtp_bridge_channel_data *data0; + struct native_rtp_bridge_channel_data *data1; + struct rtp_glue_data *glue0; + struct rtp_glue_data *glue1; if (bc0 == bc1) { return; } + data0 = bc0->tech_pvt; + data1 = bc1->tech_pvt; + if (!data0 || !data1) { + /* Not all channels are joined with the bridge tech */ + return; + } + glue0 = &data0->glue; + glue1 = &data1->glue; + + ast_debug(2, "Bridge '%s'. Tech stopping '%s' and '%s' with target '%s'\n", + bridge->uniqueid, ast_channel_name(bc0->chan), ast_channel_name(bc1->chan), + target ? ast_channel_name(target) : "none"); + + if (!glue0->cb || !glue1->cb) { + /* + * Somebody doesn't have glue data so the bridge isn't running + * + * Actually neither side should have glue data. + */ + ast_assert(!glue0->cb && !glue1->cb); + /* At most one channel can be left at the remote endpoint here. */ + ast_assert(!data0->remote_cb || !data1->remote_cb); + + /* Bring selected channel streams back to us */ + if (data0->remote_cb && (!target || target == bc0->chan)) { + ast_channel_lock(bc0->chan); + ast_debug(2, "Bridge '%s'. Bringing back '%s' to us\n", + bridge->uniqueid, ast_channel_name(bc0->chan)); + data0->remote_cb->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0); + data0->remote_cb = NULL; + ast_channel_unlock(bc0->chan); + } + if (data1->remote_cb && (!target || target == bc1->chan)) { + ast_channel_lock(bc1->chan); + ast_debug(2, "Bridge '%s'. Bringing back '%s' to us\n", + bridge->uniqueid, ast_channel_name(bc1->chan)); + data1->remote_cb->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0); + data1->remote_cb = NULL; + ast_channel_unlock(bc1->chan); + } + return; + } ast_channel_lock_both(bc0->chan, bc1->chan); - native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1); - switch (native_type) { + switch (glue0->result) { case AST_RTP_GLUE_RESULT_LOCAL: - if (ast_rtp_instance_get_engine(instance0)->local_bridge) { - ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, NULL); - } - if (instance1 && ast_rtp_instance_get_engine(instance1)->local_bridge) { - ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, NULL); + if (ast_rtp_instance_get_engine(glue0->audio.instance)->local_bridge) { + ast_rtp_instance_get_engine(glue0->audio.instance)->local_bridge(glue0->audio.instance, NULL); } - ast_rtp_instance_set_bridged(instance0, NULL); - if (instance1) { - ast_rtp_instance_set_bridged(instance1, NULL); + if (ast_rtp_instance_get_engine(glue1->audio.instance)->local_bridge) { + ast_rtp_instance_get_engine(glue1->audio.instance)->local_bridge(glue1->audio.instance, NULL); } + ast_rtp_instance_set_bridged(glue0->audio.instance, NULL); + ast_rtp_instance_set_bridged(glue1->audio.instance, NULL); break; case AST_RTP_GLUE_RESULT_REMOTE: if (target) { @@ -236,10 +483,38 @@ static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel * If a target was provided, it is being put on hold and should expect to * receive media from Asterisk instead of what it was previously connected to. */ + ast_debug(2, "Bridge '%s'. Bringing back '%s' to us\n", + bridge->uniqueid, ast_channel_name(target)); if (bc0->chan == target) { - glue0->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0); + data0->remote_cb = NULL; + glue0->cb->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0); + } else { + data1->remote_cb = NULL; + glue1->cb->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0); + } + } else { + data0->remote_cb = NULL; + data1->remote_cb = NULL; + /* + * XXX We don't want to bring back the channels if we are + * switching to T.38. We have received a reinvite on one channel + * and we will be sending a reinvite on the other to start T.38. + * If we bring the streams back now we confuse the chan_pjsip + * channel driver processing the incoming T.38 reinvite with + * reinvite glare. I think this is really a bug in chan_pjsip + * that this exception case is working around. + */ + if (rtp_glue_get_current_combined_result(bc0->chan, bc1->chan) + != AST_RTP_GLUE_RESULT_FORBID) { + ast_debug(2, "Bridge '%s'. Bringing back '%s' and '%s' to us\n", + bridge->uniqueid, ast_channel_name(bc0->chan), + ast_channel_name(bc1->chan)); + glue0->cb->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0); + glue1->cb->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0); } else { - glue1->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0); + ast_debug(2, "Bridge '%s'. Skip bringing back '%s' and '%s' to us\n", + bridge->uniqueid, ast_channel_name(bc0->chan), + ast_channel_name(bc1->chan)); } } break; @@ -247,10 +522,8 @@ static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel break; } - if (!target && native_type != AST_RTP_GLUE_RESULT_FORBID) { - glue0->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0); - glue1->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0); - } + rtp_glue_data_reset(glue0); + rtp_glue_data_reset(glue1); ast_debug(2, "Discontinued RTP bridging of '%s' and '%s' - media will flow through Asterisk core\n", ast_channel_name(bc0->chan), ast_channel_name(bc1->chan)); @@ -259,11 +532,15 @@ static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel ast_channel_unlock(bc1->chan); } -/*! \brief Frame hook that is called to intercept hold/unhold */ -static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) +/*! + * \internal + * \brief Frame hook that is called to intercept hold/unhold + */ +static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, + struct ast_frame *f, enum ast_framehook_event event, void *data) { RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup); - struct native_rtp_bridge_data *native_data = data; + struct native_rtp_framehook_data *native_data = data; if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) { return f; @@ -293,39 +570,49 @@ static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct a } ast_bridge_unlock(bridge); ast_channel_lock(chan); - } return f; } -/*! \brief Callback function which informs upstream if we are consuming a frame of a specific type */ +/*! + * \internal + * \brief Callback function which informs upstream if we are consuming a frame of a specific type + */ static int native_rtp_framehook_consume(void *data, enum ast_frame_type type) { return (type == AST_FRAME_CONTROL ? 1 : 0); } -/*! \brief Internal helper function which checks whether the channels are compatible with our native bridging */ +/*! + * \internal + * \brief Internal helper function which checks whether a channel is compatible with our native bridging + */ static int native_rtp_bridge_capable(struct ast_channel *chan) { return !ast_channel_has_hook_requiring_audio(chan); } +/*! + * \internal + * \brief Internal helper function which checks whether both channels are compatible with our native bridging + */ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct ast_bridge_channel *bc0, struct ast_bridge_channel *bc1) { enum ast_rtp_glue_result native_type; - struct ast_rtp_glue *glue0; - struct ast_rtp_glue *glue1; - RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup); - RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_format_cap *, cap0, NULL, ao2_cleanup); - RAII_VAR(struct ast_format_cap *, cap1, NULL, ao2_cleanup); int read_ptime0; int read_ptime1; int write_ptime0; int write_ptime1; + struct rtp_glue_data glue_a; + struct rtp_glue_data glue_b; + RAII_VAR(struct ast_format_cap *, cap0, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, cap1, NULL, ao2_cleanup); + RAII_VAR(struct rtp_glue_data *, glue0, NULL, rtp_glue_data_destroy); + RAII_VAR(struct rtp_glue_data *, glue1, NULL, rtp_glue_data_destroy); + + ast_debug(1, "Bridge '%s'. Checking compatability for channels '%s' and '%s'\n", + bridge->uniqueid, ast_channel_name(bc0->chan), ast_channel_name(bc1->chan)); if (!native_rtp_bridge_capable(bc0->chan)) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n", @@ -339,8 +626,17 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct return 0; } - native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, - &instance0, &instance1, &vinstance0, &vinstance1); + rtp_glue_data_init(&glue_a); + glue0 = &glue_a; + rtp_glue_data_init(&glue_b); + glue1 = &glue_b; + if (rtp_glue_data_get(bc0->chan, glue0, bc1->chan, glue1)) { + ast_debug(1, "Bridge '%s' can not use native RTP bridge as could not get details\n", + bridge->uniqueid); + return 0; + } + native_type = glue0->result; + if (native_type == AST_RTP_GLUE_RESULT_FORBID) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n", bridge->uniqueid); @@ -348,25 +644,25 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct } if (ao2_container_count(bc0->features->dtmf_hooks) - && ast_rtp_instance_dtmf_mode_get(instance0)) { + && ast_rtp_instance_dtmf_mode_get(glue0->audio.instance)) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n", bridge->uniqueid, ast_channel_name(bc0->chan)); return 0; } if (ao2_container_count(bc1->features->dtmf_hooks) - && ast_rtp_instance_dtmf_mode_get(instance1)) { + && ast_rtp_instance_dtmf_mode_get(glue1->audio.instance)) { ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n", bridge->uniqueid, ast_channel_name(bc1->chan)); return 0; } if (native_type == AST_RTP_GLUE_RESULT_LOCAL - && (ast_rtp_instance_get_engine(instance0)->local_bridge - != ast_rtp_instance_get_engine(instance1)->local_bridge - || (ast_rtp_instance_get_engine(instance0)->dtmf_compatible - && !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan, - instance0, bc1->chan, instance1)))) { + && (ast_rtp_instance_get_engine(glue0->audio.instance)->local_bridge + != ast_rtp_instance_get_engine(glue1->audio.instance)->local_bridge + || (ast_rtp_instance_get_engine(glue0->audio.instance)->dtmf_compatible + && !ast_rtp_instance_get_engine(glue0->audio.instance)->dtmf_compatible(bc0->chan, + glue0->audio.instance, bc1->chan, glue1->audio.instance)))) { ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n", bridge->uniqueid); return 0; @@ -379,11 +675,11 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct } /* Make sure that codecs match */ - if (glue0->get_codec) { - glue0->get_codec(bc0->chan, cap0); + if (glue0->cb->get_codec) { + glue0->cb->get_codec(bc0->chan, cap0); } - if (glue1->get_codec) { - glue1->get_codec(bc1->chan, cap1); + if (glue1->cb->get_codec) { + glue1->cb->get_codec(bc1->chan, cap1); } if (ast_format_cap_count(cap0) != 0 && ast_format_cap_count(cap1) != 0 @@ -413,6 +709,10 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct return 1; } +/*! + * \internal + * \brief Called by the bridge core "compatible' callback + */ static int native_rtp_bridge_compatible(struct ast_bridge *bridge) { struct ast_bridge_channel *bc0; @@ -437,10 +737,13 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge) return is_compatible; } -/*! \brief Helper function which adds frame hook to bridge channel */ +/*! + * \internal + * \brief Helper function which adds frame hook to bridge channel + */ static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel) { - struct native_rtp_bridge_data *data = ao2_alloc(sizeof(*data), NULL); + struct native_rtp_bridge_channel_data *data = bridge_channel->tech_pvt; static struct ast_framehook_interface hook = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = native_rtp_framehook, @@ -449,45 +752,82 @@ static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_ .disable_inheritance = 1, }; - if (!data) { + ast_assert(data->hook_data == NULL); + data->hook_data = ao2_alloc_options(sizeof(*data->hook_data), NULL, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!data->hook_data) { return -1; } + ast_debug(2, "Bridge '%s'. Attaching hook data %p to '%s'\n", + bridge_channel->bridge->uniqueid, data, ast_channel_name(bridge_channel->chan)); + ast_channel_lock(bridge_channel->chan); - hook.data = ao2_bump(data); - data->id = ast_framehook_attach(bridge_channel->chan, &hook); + /* We're giving 1 ref to the framehook and keeping the one from the alloc for ourselves */ + hook.data = ao2_bump(data->hook_data); + data->hook_data->id = ast_framehook_attach(bridge_channel->chan, &hook); ast_channel_unlock(bridge_channel->chan); - if (data->id < 0) { - /* We need to drop both the reference we hold, and the one the framehook would hold */ - ao2_ref(data, -2); + if (data->hook_data->id < 0) { + /* + * We need to drop both the reference we hold in data, + * and the one the framehook would hold. + */ + ao2_ref(data->hook_data, -2); + data->hook_data = NULL; + return -1; } - bridge_channel->tech_pvt = data; - return 0; } -/*! \brief Helper function which removes frame hook from bridge channel */ +/*! + * \internal + * \brief Helper function which removes frame hook from bridge channel + */ static void native_rtp_bridge_framehook_detach(struct ast_bridge_channel *bridge_channel) { - RAII_VAR(struct native_rtp_bridge_data *, data, bridge_channel->tech_pvt, ao2_cleanup); + struct native_rtp_bridge_channel_data *data = bridge_channel->tech_pvt; - if (!data) { + if (!data || !data->hook_data) { return; } + ast_debug(2, "Bridge '%s'. Detaching hook data %p from '%s'\n", + bridge_channel->bridge->uniqueid, data->hook_data, ast_channel_name(bridge_channel->chan)); + ast_channel_lock(bridge_channel->chan); - ast_framehook_detach(bridge_channel->chan, data->id); - data->detached = 1; + ast_framehook_detach(bridge_channel->chan, data->hook_data->id); + data->hook_data->detached = 1; ast_channel_unlock(bridge_channel->chan); - bridge_channel->tech_pvt = NULL; + ao2_cleanup(data->hook_data); + data->hook_data = NULL; } +/*! + * \internal + * \brief Called by the bridge core 'join' callback for each channel joining he bridge + */ static int native_rtp_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { - native_rtp_bridge_framehook_detach(bridge_channel); + ast_debug(2, "Bridge '%s'. Channel '%s' is joining bridge tech\n", + bridge->uniqueid, ast_channel_name(bridge_channel->chan)); + + ast_assert(bridge_channel->tech_pvt == NULL); + + if (bridge_channel->suspended) { + /* The channel will rejoin when it is unsuspended */ + return 0; + } + + bridge_channel->tech_pvt = native_rtp_bridge_channel_data_alloc(); + if (!bridge_channel->tech_pvt) { + return -1; + } + if (native_rtp_bridge_framehook_attach(bridge_channel)) { + native_rtp_bridge_channel_data_free(bridge_channel->tech_pvt); + bridge_channel->tech_pvt = NULL; return -1; } @@ -495,15 +835,46 @@ static int native_rtp_bridge_join(struct ast_bridge *bridge, struct ast_bridge_c return 0; } +/*! + * \internal + * \brief Add the channel back into the bridge + */ static void native_rtp_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { + ast_debug(2, "Bridge '%s'. Channel '%s' is unsuspended back to bridge tech\n", + bridge->uniqueid, ast_channel_name(bridge_channel->chan)); native_rtp_bridge_join(bridge, bridge_channel); } +/*! + * \internal + * \brief Leave the bridge + */ static void native_rtp_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { + ast_debug(2, "Bridge '%s'. Channel '%s' is leaving bridge tech\n", + bridge->uniqueid, ast_channel_name(bridge_channel->chan)); + + if (!bridge_channel->tech_pvt) { + return; + } + native_rtp_bridge_framehook_detach(bridge_channel); native_rtp_bridge_stop(bridge, NULL); + + native_rtp_bridge_channel_data_free(bridge_channel->tech_pvt); + bridge_channel->tech_pvt = NULL; +} + +/*! + * \internal + * \brief Suspend the channel from the bridge + */ +static void native_rtp_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) +{ + ast_debug(2, "Bridge '%s'. Channel '%s' is suspending from bridge tech\n", + bridge->uniqueid, ast_channel_name(bridge_channel->chan)); + native_rtp_bridge_leave(bridge, bridge_channel); } static int native_rtp_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) @@ -548,7 +919,7 @@ static struct ast_bridge_technology native_rtp_bridge = { .join = native_rtp_bridge_join, .unsuspend = native_rtp_bridge_unsuspend, .leave = native_rtp_bridge_leave, - .suspend = native_rtp_bridge_leave, + .suspend = native_rtp_bridge_suspend, .write = native_rtp_bridge_write, .compatible = native_rtp_bridge_compatible, }; diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 5f439163fe1..36f499b50a1 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -640,12 +640,13 @@ struct ast_rtp_glue { /*! * \brief Used to prevent two channels from remotely bridging audio rtp if the channel tech has a * reason for prohibiting it based on qualities that need to be compared from both channels. - * \note This function may be NULL for a given channel driver. This should be accounted for and if that is the case, function this is not used. + * \note This function may be NULL for a given channel driver. This should be accounted for and if that is the case, this function is not used. */ int (*allow_rtp_remote)(struct ast_channel *chan1, struct ast_rtp_instance *instance); /*! * \brief Callback for retrieving the RTP instance carrying video * \note This function increases the reference count on the returned RTP instance. + * \note This function may be NULL for a given channel driver. This should be accounted for and if that is the case, this function is not used. */ enum ast_rtp_glue_result (*get_vrtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance); /*! @@ -658,11 +659,15 @@ struct ast_rtp_glue { /*! * \brief Callback for retrieving the RTP instance carrying text * \note This function increases the reference count on the returned RTP instance. + * \note This function may be NULL for a given channel driver. This should be accounted for and if that is the case, this function is not used. */ enum ast_rtp_glue_result (*get_trtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance); /*! Callback for updating the destination that the remote side should send RTP to */ int (*update_peer)(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, const struct ast_format_cap *cap, int nat_active); - /*! Callback for retrieving codecs that the channel can do. Result returned in result_cap. */ + /*! + * \brief Callback for retrieving codecs that the channel can do. Result returned in result_cap. + * \note This function may be NULL for a given channel driver. This should be accounted for and if that is the case, this function is not used. + */ void (*get_codec)(struct ast_channel *chan, struct ast_format_cap *result_cap); /*! Linked list information */ AST_RWLIST_ENTRY(ast_rtp_glue) entry; From a48d3e4d31c8060856d785fca00c5213d5e012bc Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Tue, 27 Jun 2017 17:46:43 +0200 Subject: [PATCH 1340/1578] res/res_pjsip_t38: fix incorrect increment of media_count The T38 sdp callback incorrectly has a side effect of incrementing the media_count. This can lead to core dumps. Change-Id: I7bb2f4987de4046ec52cfc34e5ea0662dae32af8 --- res/res_pjsip_t38.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index bb1641a44c5..6019412b00f 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -276,7 +276,7 @@ static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_sess /* Move the image media stream to the front and have it as the only stream, pjmedia will fill in * dummy streams for the rest */ - for (stream = 0; stream < sdp->media_count++; ++stream) { + for (stream = 0; stream < sdp->media_count; ++stream) { if (!pj_strcmp2(&sdp->media[stream]->desc.media, "image")) { sdp->media[0] = sdp->media[stream]; sdp->media_count = 1; From 642f8356abd626a6acdeeac6387be69b1e17b044 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 28 Jun 2017 14:03:31 +0000 Subject: [PATCH 1341/1578] res_rtp_asterisk: Fix issues with ICE renegotiation. When re-inviting to add more streams it is possible for the role of existing ICE sessions to be changed to the incorrect value. This results in subsequent refreshes within the sessions getting a role conflict and the ICE session breaking down. This change only sets the role to be the new value if an ICE renegotiation is actually going to happen, otherwise the existing role is preserved. As well if we encounter a situation where a unidirectional ICE negotiation happens and the other side does not send us candidates we will not store any information for sending traffic, even though we know where they are reachable. This change fixes this by using the source of the ICE traffic itself as the target if no candidates are known and we receive some ICE traffic. ASTERISK-27088 Change-Id: I71228181e358917fcefc3100fad21b2fc02a59a9 --- res/res_rtp_asterisk.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 600846c8510..01dfe76f29d 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -317,6 +317,7 @@ struct ast_rtp { ast_cond_t cond; /*!< ICE/TURN condition for signaling */ struct ice_wrap *ice; /*!< ao2 wrapped ICE session */ + enum ast_rtp_ice_role role; /*!< Our role in ICE negotiation */ pj_turn_sock *turn_rtp; /*!< RTP TURN relay */ pj_turn_sock *turn_rtcp; /*!< RTCP TURN relay */ pj_turn_state_t turn_state; /*!< Current state of the TURN relay session */ @@ -683,7 +684,6 @@ static void ice_wrap_dtor(void *vdoomed) static int ice_reset_session(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - pj_ice_sess_role role = rtp->ice->real_ice->role; int res; ast_debug(3, "Resetting ICE for RTP instance '%p'\n", instance); @@ -695,8 +695,9 @@ static int ice_reset_session(struct ast_rtp_instance *instance) ast_debug(3, "Recreating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(&rtp->ice_original_rtp_addr), rtp->ice_port, instance); res = ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1); if (!res) { - /* Preserve the role that the old ICE session used */ - pj_ice_sess_change_role(rtp->ice->real_ice, role); + /* Use the current expected role for the ICE session */ + pj_ice_sess_change_role(rtp->ice->real_ice, rtp->role == AST_RTP_ICE_ROLE_CONTROLLED ? + PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING); } /* If we only have one component now, and we previously set up TURN for RTCP, @@ -767,6 +768,8 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) ast_debug(3, "Proposed == active candidates for RTP instance '%p'\n", instance); ao2_cleanup(rtp->ice_proposed_remote_candidates); rtp->ice_proposed_remote_candidates = NULL; + /* If this ICE session is being preserved then go back to the role it currently is */ + rtp->role = rtp->ice->real_ice->role; return; } @@ -940,10 +943,7 @@ static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp return; } - pj_thread_register_check(); - - pj_ice_sess_change_role(rtp->ice->real_ice, role == AST_RTP_ICE_ROLE_CONTROLLED ? - PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING); + rtp->role = role; } /*! \pre instance is locked */ @@ -2526,6 +2526,17 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s return -1; } if (!rtp->passthrough) { + /* If a unidirectional ICE negotiation occurs then lock on to the source of the + * ICE traffic and use it as the target. This will occur if the remote side only + * wants to receive media but never send to us. + */ + if (!rtp->ice_active_remote_candidates && !rtp->ice_proposed_remote_candidates) { + if (rtcp) { + ast_sockaddr_copy(&rtp->rtcp->them, sa); + } else { + ast_rtp_instance_set_remote_address(instance, sa); + } + } return 0; } rtp->passthrough = 0; From 45df25a579edd5423c9d319758d109a74fe8ef33 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 30 May 2017 09:12:47 -0500 Subject: [PATCH 1342/1578] chan_pjsip: Add support for multiple streams of the same type. The stream topology (list of streams and order) is now stored with the configured PJSIP endpoints and used during the negotiation process. Media negotiation state information has been changed to be stored in a separate object. Two of these objects exist at any one time on a session. The active media state information is what was previously negotiated and the pending media state information is what the media state will become if negotiation succeeds. Streams and other state information is stored in this object using the index (or position) of each individual stream for easy lookup. The ability for a media type handler to specify a callback for writing has been added as well as the ability to add file descriptors with a callback which is invoked when data is available to be read on them. This allows media logic to live outside of the chan_pjsip module. Direct media has been changed so that only the first audio and video stream are directly connected. In the future once the RTP engine glue API has been updated to know about streams each individual stream can be directly connected as appropriate. Media negotiation itself will currently answer all the provided streams on an offer within configured limits and on an offer will use the topology created as a result of the disallow/allow codec lines. If a stream has been removed or declined we will now mark it as such within the resulting SDP. Applications can now also request that the stream topology change. If we are told to do so we will limit any provided formats to the ones configured on the endpoint and send a re-invite with the new topology. Two new configuration options have also been added to PJSIP endpoints: max_audio_streams: determines the maximum number of audio streams to offer/accept from an endpoint. Defaults to 1. max_video_streams: determines the maximum number of video streams to offer/accept from an endpoint. Defaults to 1. ASTERISK-27076 Change-Id: I8afd8dd2eb538806a39b887af0abd046266e14c7 --- channels/chan_pjsip.c | 523 +++++++--- channels/pjsip/cli_commands.c | 37 +- channels/pjsip/dialplan_functions.c | 185 +++- channels/pjsip/include/chan_pjsip.h | 13 - configs/samples/pjsip.conf.sample | 4 + .../39959b9c2566_pjsip_stream_maximum.py | 24 + include/asterisk/res_pjsip.h | 6 + include/asterisk/res_pjsip_session.h | 211 +++- include/asterisk/stream.h | 16 +- main/channel.c | 45 +- main/stream.c | 47 + res/res_pjsip.c | 14 + res/res_pjsip/pjsip_configuration.c | 11 +- res/res_pjsip_sdp_rtp.c | 239 +++-- res/res_pjsip_session.c | 962 +++++++++++++----- res/res_pjsip_session.exports.in | 22 +- res/res_pjsip_t38.c | 243 +++-- 17 files changed, 1912 insertions(+), 690 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/39959b9c2566_pjsip_stream_maximum.py diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 83dc77f3825..7cab428731e 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -64,6 +64,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_session.h" +#include "asterisk/stream.h" #include "pjsip/include/chan_pjsip.h" #include "pjsip/include/dialplan_functions.h" @@ -78,25 +79,22 @@ static unsigned int chan_idx; static void chan_pjsip_pvt_dtor(void *obj) { - struct chan_pjsip_pvt *pvt = obj; - int i; - - for (i = 0; i < SIP_MEDIA_SIZE; ++i) { - ao2_cleanup(pvt->media[i]); - pvt->media[i] = NULL; - } } /* \brief Asterisk core interaction functions */ static struct ast_channel *chan_pjsip_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause); +static struct ast_channel *chan_pjsip_request_with_stream_topology(const char *type, + struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, + const struct ast_channel *requestor, const char *data, int *cause); static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text); static int chan_pjsip_digit_begin(struct ast_channel *ast, char digit); static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration); static int chan_pjsip_call(struct ast_channel *ast, const char *dest, int timeout); static int chan_pjsip_hangup(struct ast_channel *ast); static int chan_pjsip_answer(struct ast_channel *ast); -static struct ast_frame *chan_pjsip_read(struct ast_channel *ast); +static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast); static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *f); +static int chan_pjsip_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *f); static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); static int chan_pjsip_transfer(struct ast_channel *ast, const char *target); static int chan_pjsip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); @@ -109,16 +107,17 @@ struct ast_channel_tech chan_pjsip_tech = { .type = channel_type, .description = "PJSIP Channel Driver", .requester = chan_pjsip_request, + .requester_with_stream_topology = chan_pjsip_request_with_stream_topology, .send_text = chan_pjsip_sendtext, .send_digit_begin = chan_pjsip_digit_begin, .send_digit_end = chan_pjsip_digit_end, .call = chan_pjsip_call, .hangup = chan_pjsip_hangup, .answer = chan_pjsip_answer, - .read = chan_pjsip_read, + .read_stream = chan_pjsip_read_stream, .write = chan_pjsip_write, - .write_video = chan_pjsip_write, - .exception = chan_pjsip_read, + .write_stream = chan_pjsip_write_stream, + .exception = chan_pjsip_read_stream, .indicate = chan_pjsip_indicate, .transfer = chan_pjsip_transfer, .fixup = chan_pjsip_fixup, @@ -159,11 +158,20 @@ static struct ast_sip_session_supplement chan_pjsip_ack_supplement = { static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - struct chan_pjsip_pvt *pvt; struct ast_sip_endpoint *endpoint; struct ast_datastore *datastore; + struct ast_sip_session_media *media; - if (!channel || !channel->session || !(pvt = channel->pvt) || !pvt->media[SIP_MEDIA_AUDIO]->rtp) { + if (!channel || !channel->session) { + return AST_RTP_GLUE_RESULT_FORBID; + } + + /* XXX Getting the first RTP instance for direct media related stuff seems just + * absolutely wrong. But the native RTP bridge knows no other method than single-stream + * for direct media. So this is the best we can do. + */ + media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; + if (!media || !media->rtp) { return AST_RTP_GLUE_RESULT_FORBID; } @@ -175,7 +183,7 @@ static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan endpoint = channel->session->endpoint; - *instance = pvt->media[SIP_MEDIA_AUDIO]->rtp; + *instance = media->rtp; ao2_ref(*instance, +1); ast_assert(endpoint != NULL); @@ -194,16 +202,21 @@ static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan static enum ast_rtp_glue_result chan_pjsip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_sip_endpoint *endpoint; + struct ast_sip_session_media *media; - if (!pvt || !channel->session || !pvt->media[SIP_MEDIA_VIDEO]->rtp) { + if (!channel || !channel->session) { + return AST_RTP_GLUE_RESULT_FORBID; + } + + media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO]; + if (!media || !media->rtp) { return AST_RTP_GLUE_RESULT_FORBID; } endpoint = channel->session->endpoint; - *instance = pvt->media[SIP_MEDIA_VIDEO]->rtp; + *instance = media->rtp; ao2_ref(*instance, +1); ast_assert(endpoint != NULL); @@ -265,18 +278,43 @@ static int direct_media_mitigate_glare(struct ast_sip_session *session) return 0; } +/*! \brief Helper function to find the position for RTCP */ +static int rtp_find_rtcp_fd_position(struct ast_sip_session *session, struct ast_rtp_instance *rtp) +{ + int index; + + for (index = 0; index < AST_VECTOR_SIZE(&session->active_media_state->read_callbacks); ++index) { + struct ast_sip_session_media_read_callback_state *callback_state = + AST_VECTOR_GET_ADDR(&session->active_media_state->read_callbacks, index); + + if (callback_state->fd != ast_rtp_instance_fd(rtp, 1)) { + continue; + } + + return index; + } + + return -1; +} + /*! * \pre chan is locked */ static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instance *rtp, - struct ast_sip_session_media *media, int rtcp_fd) + struct ast_sip_session_media *media, struct ast_sip_session *session) { - int changed = 0; + int changed = 0, position = -1; + + if (media->rtp) { + position = rtp_find_rtcp_fd_position(session, media->rtp); + } if (rtp) { changed = ast_rtp_instance_get_and_cmp_remote_address(rtp, &media->direct_media_addr); if (media->rtp) { - ast_channel_set_fd(chan, rtcp_fd, -1); + if (position != -1) { + ast_channel_set_fd(chan, position + AST_EXTENDED_FDS, -1); + } ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 0); } } else if (!ast_sockaddr_isnull(&media->direct_media_addr)){ @@ -284,7 +322,9 @@ static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instan changed = 1; if (media->rtp) { ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 1); - ast_channel_set_fd(chan, rtcp_fd, ast_rtp_instance_fd(media->rtp, 1)); + if (position != -1) { + ast_channel_set_fd(chan, position + AST_EXTENDED_FDS, ast_rtp_instance_fd(media->rtp, 1)); + } } } @@ -333,22 +373,27 @@ static int send_direct_media_request(void *data) { struct rtp_direct_media_data *cdata = data; struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(cdata->chan); - struct chan_pjsip_pvt *pvt = channel->pvt; + struct ast_sip_session *session; int changed = 0; int res = 0; + /* XXX In an ideal world each media stream would be direct, but for now preserve behavior + * and connect only the default media sessions for audio and video. + */ + /* The channel needs to be locked when checking for RTP changes. * Otherwise, we could end up destroying an underlying RTCP structure * at the same time that the channel thread is attempting to read RTCP */ ast_channel_lock(cdata->chan); - if (pvt->media[SIP_MEDIA_AUDIO]) { + session = channel->session; + if (session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) { changed |= check_for_rtp_changes( - cdata->chan, cdata->rtp, pvt->media[SIP_MEDIA_AUDIO], 1); + cdata->chan, cdata->rtp, session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO], session); } - if (pvt->media[SIP_MEDIA_VIDEO]) { + if (session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO]) { changed |= check_for_rtp_changes( - cdata->chan, cdata->vrtp, pvt->media[SIP_MEDIA_VIDEO], 3); + cdata->chan, cdata->vrtp, session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO], session); } ast_channel_unlock(cdata->chan); @@ -368,7 +413,7 @@ static int send_direct_media_request(void *data) if (changed) { ast_debug(4, "RTP changed on %s; initiating direct media update\n", ast_channel_name(cdata->chan)); res = ast_sip_session_refresh(cdata->session, NULL, NULL, NULL, - cdata->session->endpoint->media.direct_media.method, 1); + cdata->session->endpoint->media.direct_media.method, 1, NULL); } ao2_ref(cdata, -1); @@ -420,14 +465,53 @@ static struct ast_rtp_glue chan_pjsip_rtp_glue = { .update_peer = chan_pjsip_set_rtp_peer, }; -static void set_channel_on_rtp_instance(struct chan_pjsip_pvt *pvt, const char *channel_id) +static void set_channel_on_rtp_instance(const struct ast_sip_session *session, + const char *channel_id) { - if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, channel_id); + int i; + + for (i = 0; i < AST_VECTOR_SIZE(&session->active_media_state->sessions); ++i) { + struct ast_sip_session_media *session_media; + + session_media = AST_VECTOR_GET(&session->active_media_state->sessions, i); + if (!session_media || !session_media->rtp) { + continue; + } + + ast_rtp_instance_set_channel_id(session_media->rtp, channel_id); } - if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, channel_id); +} + +/*! + * \brief Determine if a topology is compatible with format capabilities + * + * This will return true if ANY formats in the topology are compatible with the format + * capabilities. + * + * XXX When supporting true multistream, we will need to be sure to mark which streams from + * top1 are compatible with which streams from top2. Then the ones that are not compatible + * will need to be marked as "removed" so that they are negotiated as expected. + * + * \param top Topology + * \param cap Format capabilities + * \retval 1 The topology has at least one compatible format + * \retval 0 The topology has no compatible formats or an error occurred. + */ +static int compatible_formats_exist(struct ast_stream_topology *top, struct ast_format_cap *cap) +{ + struct ast_format_cap *cap_from_top; + int res; + + cap_from_top = ast_format_cap_from_stream_topology(top); + + if (!cap_from_top) { + return 0; } + + res = ast_format_cap_iscompatible(cap_from_top, cap); + ao2_ref(cap_from_top, -1); + + return res; } /*! \brief Function called to create a new PJSIP Asterisk channel */ @@ -438,12 +522,9 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s RAII_VAR(struct chan_pjsip_pvt *, pvt, NULL, ao2_cleanup); struct ast_sip_channel_pvt *channel; struct ast_variable *var; + struct ast_stream_topology *topology; - if (!(pvt = ao2_alloc(sizeof(*pvt), chan_pjsip_pvt_dtor))) { - return NULL; - } - caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!caps) { + if (!(pvt = ao2_alloc_options(sizeof(*pvt), chan_pjsip_pvt_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK))) { return NULL; } @@ -457,31 +538,46 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s ast_sorcery_object_get_id(session->endpoint), (unsigned) ast_atomic_fetchadd_int((int *) &chan_idx, +1)); if (!chan) { - ao2_ref(caps, -1); return NULL; } ast_channel_tech_set(chan, &chan_pjsip_tech); if (!(channel = ast_sip_channel_pvt_alloc(pvt, session))) { - ao2_ref(caps, -1); ast_channel_unlock(chan); ast_hangup(chan); return NULL; } - ast_channel_stage_snapshot(chan); - ast_channel_tech_pvt_set(chan, channel); - if (!ast_format_cap_count(session->req_caps) || - !ast_format_cap_iscompatible(session->req_caps, session->endpoint->media.codecs)) { + if (!ast_stream_topology_get_count(session->pending_media_state->topology) || + !compatible_formats_exist(session->pending_media_state->topology, session->endpoint->media.codecs)) { + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_channel_unlock(chan); + ast_hangup(chan); + return NULL; + } ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); + topology = ast_stream_topology_clone(session->endpoint->media.topology); } else { - ast_format_cap_append_from_cap(caps, session->req_caps, AST_MEDIA_TYPE_UNKNOWN); + caps = ast_format_cap_from_stream_topology(session->pending_media_state->topology); + topology = ast_stream_topology_clone(session->pending_media_state->topology); } + if (!topology || !caps) { + ao2_cleanup(caps); + ast_stream_topology_free(topology); + ast_channel_unlock(chan); + ast_hangup(chan); + return NULL; + } + + ast_channel_stage_snapshot(chan); + ast_channel_nativeformats_set(chan, caps); + ast_channel_set_stream_topology(chan, topology); if (!ast_format_cap_empty(caps)) { struct ast_format *fmt; @@ -538,12 +634,7 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s ast_channel_stage_snapshot_done(chan); ast_channel_unlock(chan); - /* If res_pjsip_session is ever updated to create/destroy ast_sip_session_media - * during a call such as if multiple same-type stream support is introduced, - * these will need to be recaptured as well */ - pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY); - pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY); - set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(chan)); + set_channel_on_rtp_instance(session, ast_channel_uniqueid(chan)); return chan; } @@ -682,49 +773,32 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se * * \note The channel is already locked. */ -static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) +static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); - struct ast_sip_session *session; - struct chan_pjsip_pvt *pvt = channel->pvt; + struct ast_sip_session *session = channel->session; + struct ast_sip_session_media_read_callback_state *callback_state; struct ast_frame *f; - struct ast_sip_session_media *media = NULL; - int rtcp = 0; - int fdno = ast_channel_fdno(ast); + int fdno = ast_channel_fdno(ast) - AST_EXTENDED_FDS; - switch (fdno) { - case 0: - media = pvt->media[SIP_MEDIA_AUDIO]; - break; - case 1: - media = pvt->media[SIP_MEDIA_AUDIO]; - rtcp = 1; - break; - case 2: - media = pvt->media[SIP_MEDIA_VIDEO]; - break; - case 3: - media = pvt->media[SIP_MEDIA_VIDEO]; - rtcp = 1; - break; - } - - if (!media || !media->rtp) { + if (fdno >= AST_VECTOR_SIZE(&session->active_media_state->read_callbacks)) { return &ast_null_frame; } - if (!(f = ast_rtp_instance_read(media->rtp, rtcp))) { + callback_state = AST_VECTOR_GET_ADDR(&session->active_media_state->read_callbacks, fdno); + f = callback_state->read_callback(session, callback_state->session); + + if (!f) { return f; } - ast_rtp_instance_set_last_rx(media->rtp, time(NULL)); + f->stream_num = callback_state->session->stream_num; - if (f->frametype != AST_FRAME_VOICE) { + if (f->frametype != AST_FRAME_VOICE || + callback_state->session != session->active_media_state->default_session[callback_state->session->type]) { return f; } - session = channel->session; - if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when it has not been negotiated\n", ast_format_get_name(f->subclass.format), ast_channel_name(ast)); @@ -794,22 +868,31 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) return f; } -/*! \brief Function called by core to write frames */ -static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame) +static int chan_pjsip_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *frame) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); - struct chan_pjsip_pvt *pvt = channel->pvt; - struct ast_sip_session_media *media; + struct ast_sip_session *session = channel->session; + struct ast_sip_session_media *media = NULL; int res = 0; + /* The core provides a guarantee that the stream will exist when we are called if stream_num is provided */ + if (stream_num >= 0) { + /* What is not guaranteed is that a media session will exist */ + if (stream_num < AST_VECTOR_SIZE(&channel->session->active_media_state->sessions)) { + media = AST_VECTOR_GET(&channel->session->active_media_state->sessions, stream_num); + } + } + switch (frame->frametype) { case AST_FRAME_VOICE: - media = pvt->media[SIP_MEDIA_AUDIO]; - if (!media) { return 0; - } - if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + } else if (media->type != AST_MEDIA_TYPE_AUDIO) { + ast_debug(3, "Channel %s stream %d is of type '%s', not audio!\n", + ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type)); + return 0; + } else if (media == channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO] && + ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); @@ -826,17 +909,32 @@ static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame) ast_format_get_name(ast_channel_rawwriteformat(ast)), ast_translate_path_to_str(ast_channel_writetrans(ast), &write_transpath)); return 0; - } - if (media->rtp) { - res = ast_rtp_instance_write(media->rtp, frame); + } else if (media->write_callback) { + res = media->write_callback(session, media, frame); + } break; case AST_FRAME_VIDEO: - if ((media = pvt->media[SIP_MEDIA_VIDEO]) && media->rtp) { - res = ast_rtp_instance_write(media->rtp, frame); + if (!media) { + return 0; + } else if (media->type != AST_MEDIA_TYPE_VIDEO) { + ast_debug(3, "Channel %s stream %d is of type '%s', not video!\n", + ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type)); + return 0; + } else if (media->write_callback) { + res = media->write_callback(session, media, frame); } break; case AST_FRAME_MODEM: + if (!media) { + return 0; + } else if (media->type != AST_MEDIA_TYPE_IMAGE) { + ast_debug(3, "Channel %s stream %d is of type '%s', not image!\n", + ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type)); + return 0; + } else if (media->write_callback) { + res = media->write_callback(session, media, frame); + } break; default: ast_log(LOG_WARNING, "Can't send %u type frames with PJSIP\n", frame->frametype); @@ -846,11 +944,15 @@ static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame) return res; } +static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame) +{ + return chan_pjsip_write_stream(ast, -1, frame); +} + /*! \brief Function called by core to change the underlying owner channel */ static int chan_pjsip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(newchan); - struct chan_pjsip_pvt *pvt = channel->pvt; if (channel->session->channel != oldchan) { return -1; @@ -863,7 +965,7 @@ static int chan_pjsip_fixup(struct ast_channel *oldchan, struct ast_channel *new */ channel->session->channel = newchan; - set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(newchan)); + set_channel_on_rtp_instance(channel->session, ast_channel_uniqueid(newchan)); return 0; } @@ -1278,7 +1380,7 @@ static int update_connected_line_information(void *data) /* Only the INVITE method actually needs SDP, UPDATE can do without */ generate_new_sdp = (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE); - ast_sip_session_refresh(session, NULL, NULL, NULL, method, generate_new_sdp); + ast_sip_session_refresh(session, NULL, NULL, NULL, method, generate_new_sdp, NULL); } } else if (session->endpoint->id.rpid_immediate && session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED @@ -1309,21 +1411,18 @@ static int update_connected_line_information(void *data) } /*! \brief Callback which changes the value of locally held on the media stream */ -static int local_hold_set_state(void *obj, void *arg, int flags) +static void local_hold_set_state(struct ast_sip_session_media *session_media, unsigned int held) { - struct ast_sip_session_media *session_media = obj; - unsigned int *held = arg; - - session_media->locally_held = *held; - - return 0; + if (session_media) { + session_media->locally_held = held; + } } /*! \brief Update local hold state and send a re-INVITE with the new SDP */ static int remote_send_hold_refresh(struct ast_sip_session *session, unsigned int held) { - ao2_callback(session->media, OBJ_NODATA, local_hold_set_state, &held); - ast_sip_session_refresh(session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1); + AST_VECTOR_CALLBACK_VOID(&session->active_media_state->sessions, local_hold_set_state, held); + ast_sip_session_refresh(session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, NULL); ao2_ref(session, -1); return 0; @@ -1341,16 +1440,103 @@ static int remote_send_unhold(void *data) return remote_send_hold_refresh(data, 0); } +struct topology_change_refresh_data { + struct ast_sip_session *session; + struct ast_sip_session_media_state *media_state; +}; + +static void topology_change_refresh_data_free(struct topology_change_refresh_data *refresh_data) +{ + ao2_cleanup(refresh_data->session); + + ast_sip_session_media_state_free(refresh_data->media_state); + ast_free(refresh_data); +} + +static struct topology_change_refresh_data *topology_change_refresh_data_alloc( + struct ast_sip_session *session, const struct ast_stream_topology *topology) +{ + struct topology_change_refresh_data *refresh_data; + + refresh_data = ast_calloc(1, sizeof(*refresh_data)); + if (!refresh_data) { + return NULL; + } + + refresh_data->session = ao2_bump(session); + refresh_data->media_state = ast_sip_session_media_state_alloc(); + if (!refresh_data->media_state) { + topology_change_refresh_data_free(refresh_data); + return NULL; + } + refresh_data->media_state->topology = ast_stream_topology_clone(topology); + if (!refresh_data->media_state->topology) { + topology_change_refresh_data_free(refresh_data); + return NULL; + } + + return refresh_data; +} + +static int on_topology_change_response(struct ast_sip_session *session, pjsip_rx_data *rdata) +{ + if (rdata->msg_info.msg->line.status.code == 200) { + /* The topology was changed to something new so give notice to what requested + * it so it queries the channel and updates accordingly. + */ + if (session->channel) { + ast_queue_control(session->channel, AST_CONTROL_STREAM_TOPOLOGY_CHANGED); + } + } else if (rdata->msg_info.msg->line.status.code != 100) { + /* The topology change failed, so drop the current pending media state */ + ast_sip_session_media_state_reset(session->pending_media_state); + } + + return 0; +} + +static int send_topology_change_refresh(void *data) +{ + struct topology_change_refresh_data *refresh_data = data; + int ret; + + ret = ast_sip_session_refresh(refresh_data->session, NULL, NULL, on_topology_change_response, + AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, refresh_data->media_state); + refresh_data->media_state = NULL; + topology_change_refresh_data_free(refresh_data); + + return ret; +} + +static int handle_topology_request_change(struct ast_sip_session *session, + const struct ast_stream_topology *proposed) +{ + struct topology_change_refresh_data *refresh_data; + int res; + + refresh_data = topology_change_refresh_data_alloc(session, proposed); + if (!refresh_data) { + return -1; + } + + res = ast_sip_push_task(session->serializer, send_topology_change_refresh, refresh_data); + if (res) { + topology_change_refresh_data_free(refresh_data); + } + return res; +} + /*! \brief Function called by core to ask the channel to indicate some sort of condition */ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); - struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_sip_session_media *media; int response_code = 0; int res = 0; char *device_buf; size_t device_buf_size; + int i; + const struct ast_stream_topology *topology; switch (condition) { case AST_CONTROL_RINGING: @@ -1403,39 +1589,47 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_sorcery_object_get_id(channel->session->endpoint)); break; case AST_CONTROL_VIDUPDATE: - media = pvt->media[SIP_MEDIA_VIDEO]; - if (media && media->rtp) { - /* FIXME: Only use this for VP8. Additional work would have to be done to - * fully support other video codecs */ - - if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) { - /* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the - * RTP engine would provide a way to externally write/schedule RTCP - * packets */ - struct ast_frame fr; - fr.frametype = AST_FRAME_CONTROL; - fr.subclass.integer = AST_CONTROL_VIDUPDATE; - res = ast_rtp_instance_write(media->rtp, &fr); - } else { - ao2_ref(channel->session, +1); -#ifdef HAVE_PJSIP_INV_SESSION_REF - if (pjsip_inv_add_ref(channel->session->inv_session) != PJ_SUCCESS) { - ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); - ao2_cleanup(channel->session); + for (i = 0; i < AST_VECTOR_SIZE(&channel->session->active_media_state->sessions); ++i) { + media = AST_VECTOR_GET(&channel->session->active_media_state->sessions, i); + if (!media || media->type != AST_MEDIA_TYPE_VIDEO) { + continue; + } + if (media->rtp) { + /* FIXME: Only use this for VP8. Additional work would have to be done to + * fully support other video codecs */ + + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) { + /* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the + * RTP engine would provide a way to externally write/schedule RTCP + * packets */ + struct ast_frame fr; + fr.frametype = AST_FRAME_CONTROL; + fr.subclass.integer = AST_CONTROL_VIDUPDATE; + res = ast_rtp_instance_write(media->rtp, &fr); } else { -#endif - if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) { + ao2_ref(channel->session, +1); +#ifdef HAVE_PJSIP_INV_SESSION_REF + if (pjsip_inv_add_ref(channel->session->inv_session) != PJ_SUCCESS) { + ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); ao2_cleanup(channel->session); - } + } else { +#endif + if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) { + ao2_cleanup(channel->session); + } #ifdef HAVE_PJSIP_INV_SESSION_REF - } + } #endif + } + ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Success"); + } else { + ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Failure"); + res = -1; } - ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Success"); - } else { - ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Failure"); - res = -1; } + /* XXX If there were no video streams, then this should set + * res to -1 + */ break; case AST_CONTROL_CONNECTED_LINE: ao2_ref(channel->session, +1); @@ -1530,6 +1724,10 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi } } + break; + case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: + topology = data; + res = handle_topology_request_change(channel->session, topology); break; case -1: res = -1; @@ -1744,10 +1942,11 @@ static int chan_pjsip_transfer(struct ast_channel *chan, const char *target) static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - struct chan_pjsip_pvt *pvt = channel->pvt; - struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO]; + struct ast_sip_session_media *media; int res = 0; + media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; + switch (channel->session->endpoint->dtmf) { case AST_SIP_DTMF_RFC_4733: if (!media || !media->rtp) { @@ -1755,14 +1954,14 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit) } ast_rtp_instance_dtmf_begin(media->rtp, digit); - break; + break; case AST_SIP_DTMF_AUTO: - if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND)) { - return -1; - } + if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND)) { + return -1; + } - ast_rtp_instance_dtmf_begin(media->rtp, digit); - break; + ast_rtp_instance_dtmf_begin(media->rtp, digit); + break; case AST_SIP_DTMF_NONE: break; case AST_SIP_DTMF_INBAND: @@ -1858,10 +2057,11 @@ static int transmit_info_dtmf(void *data) static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); - struct chan_pjsip_pvt *pvt = channel->pvt; - struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO]; + struct ast_sip_session_media *media; int res = 0; + media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; + switch (channel->session->endpoint->dtmf) { case AST_SIP_DTMF_INFO: { @@ -1943,7 +2143,6 @@ static int call(void *data) { struct ast_sip_channel_pvt *channel = data; struct ast_sip_session *session = channel->session; - struct chan_pjsip_pvt *pvt = channel->pvt; pjsip_tx_data *tdata; int res = ast_sip_session_create_invite(session, &tdata); @@ -1952,7 +2151,7 @@ static int call(void *data) ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0); ast_queue_hangup(session->channel); } else { - set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(session->channel)); + set_channel_on_rtp_instance(session, ast_channel_uniqueid(session->channel)); update_initial_connected_line(session); ast_sip_session_send_request(session, tdata); } @@ -2050,10 +2249,10 @@ static struct hangup_data *hangup_data_alloc(int cause, struct ast_channel *chan } /*! \brief Clear a channel from a session along with its PVT */ -static void clear_session_and_channel(struct ast_sip_session *session, struct ast_channel *ast, struct chan_pjsip_pvt *pvt) +static void clear_session_and_channel(struct ast_sip_session *session, struct ast_channel *ast) { session->channel = NULL; - set_channel_on_rtp_instance(pvt, ""); + set_channel_on_rtp_instance(session, ""); ast_channel_tech_pvt_set(ast, NULL); } @@ -2062,7 +2261,6 @@ static int hangup(void *data) struct hangup_data *h_data = data; struct ast_channel *ast = h_data->chan; struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); - struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_sip_session *session = channel->session; int cause = h_data->cause; @@ -2072,7 +2270,7 @@ static int hangup(void *data) * afterwards. */ ast_sip_session_terminate(ao2_bump(session), cause); - clear_session_and_channel(session, ast, pvt); + clear_session_and_channel(session, ast); ao2_cleanup(session); ao2_cleanup(channel); ao2_cleanup(h_data); @@ -2083,7 +2281,6 @@ static int hangup(void *data) static int chan_pjsip_hangup(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); - struct chan_pjsip_pvt *pvt; int cause; struct hangup_data *h_data; @@ -2091,7 +2288,6 @@ static int chan_pjsip_hangup(struct ast_channel *ast) return -1; } - pvt = channel->pvt; cause = hangup_cause2sip(ast_channel_hangupcause(channel->session->channel)); h_data = hangup_data_alloc(cause, ast); @@ -2110,7 +2306,7 @@ static int chan_pjsip_hangup(struct ast_channel *ast) /* Go ahead and do our cleanup of the session and channel even if we're not going * to be able to send our SIP request/response */ - clear_session_and_channel(channel->session, ast, pvt); + clear_session_and_channel(channel->session, ast); ao2_cleanup(channel); ao2_cleanup(h_data); @@ -2119,7 +2315,7 @@ static int chan_pjsip_hangup(struct ast_channel *ast) struct request_data { struct ast_sip_session *session; - struct ast_format_cap *caps; + struct ast_stream_topology *topology; const char *dest; int cause; }; @@ -2193,7 +2389,7 @@ static int request(void *obj) } } - if (!(session = ast_sip_session_create_outgoing(endpoint, NULL, args.aor, request_user, req_data->caps))) { + if (!(session = ast_sip_session_create_outgoing(endpoint, NULL, args.aor, request_user, req_data->topology))) { ast_log(LOG_ERROR, "Failed to create outgoing session to endpoint '%s'\n", endpoint_name); req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; return -1; @@ -2205,12 +2401,12 @@ static int request(void *obj) } /*! \brief Function called by core to create a new outgoing PJSIP session */ -static struct ast_channel *chan_pjsip_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) +static struct ast_channel *chan_pjsip_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { struct request_data req_data; RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup); - req_data.caps = cap; + req_data.topology = topology; req_data.dest = data; if (ast_sip_push_task_synchronous(NULL, request, &req_data)) { @@ -2228,6 +2424,23 @@ static struct ast_channel *chan_pjsip_request(const char *type, struct ast_forma return session->channel; } +static struct ast_channel *chan_pjsip_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) +{ + struct ast_stream_topology *topology; + struct ast_channel *chan; + + topology = ast_stream_topology_create_from_format_cap(cap); + if (!topology) { + return NULL; + } + + chan = chan_pjsip_request_with_stream_topology(type, topology, assignedids, requestor, data, cause); + + ast_stream_topology_free(topology); + + return chan; +} + struct sendtext_data { struct ast_sip_session *session; char text[0]; diff --git a/channels/pjsip/cli_commands.c b/channels/pjsip/cli_commands.c index fc14b25a8d4..33d0e02c11d 100644 --- a/channels/pjsip/cli_commands.c +++ b/channels/pjsip/cli_commands.c @@ -342,8 +342,9 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags) const struct ast_channel_snapshot *snapshot = obj; struct ast_channel *channel = ast_channel_get_by_name(snapshot->name); struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL; - struct chan_pjsip_pvt *pvt = cpvt ? cpvt->pvt : NULL; - struct ast_sip_session_media *media = pvt ? pvt->media[SIP_MEDIA_AUDIO] : NULL; + struct ast_sip_session *session; + struct ast_sip_session_media *media; + struct ast_rtp_instance *rtp; struct ast_rtp_instance_stats stats; char *print_name = NULL; char *print_time = alloca(32); @@ -351,29 +352,46 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags) ast_assert(context->output_buffer != NULL); + if (!channel) { + ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); + return -1; + } + + ast_channel_lock(channel); + + session = cpvt->session; + if (!session) { + ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); + ast_channel_unlock(channel); + ao2_cleanup(channel); + return -1; + } + + media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; if (!media || !media->rtp) { ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); + ast_channel_unlock(channel); ao2_cleanup(channel); return -1; } + rtp = ao2_bump(media->rtp); + codec_in_use[0] = '\0'; - if (channel) { - ast_channel_lock(channel); - if (ast_channel_rawreadformat(channel)) { - ast_copy_string(codec_in_use, ast_format_get_name(ast_channel_rawreadformat(channel)), sizeof(codec_in_use)); - } - ast_channel_unlock(channel); + if (ast_channel_rawreadformat(channel)) { + ast_copy_string(codec_in_use, ast_format_get_name(ast_channel_rawreadformat(channel)), sizeof(codec_in_use)); } + ast_channel_unlock(channel); + print_name = ast_strdupa(snapshot->name); /* Skip the PJSIP/. We know what channel type it is and we need the space. */ print_name += 6; ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32); - if (ast_rtp_instance_get_stats(media->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) { + if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) { ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name); } else { ast_str_append(&context->output_buffer, 0, @@ -398,6 +416,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags) ); } + ao2_cleanup(rtp); ao2_cleanup(channel); return 0; diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index e2c78cd87b4..59ca9d791c8 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -437,6 +437,7 @@ #include "asterisk/acl.h" #include "asterisk/app.h" #include "asterisk/channel.h" +#include "asterisk/stream.h" #include "asterisk/format.h" #include "asterisk/pbx.h" #include "asterisk/res_pjsip.h" @@ -461,8 +462,8 @@ static const char *t38state_to_string[T38_MAX_ENUM] = { static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - struct chan_pjsip_pvt *pvt; - struct ast_sip_session_media *media = NULL; + struct ast_sip_session *session; + struct ast_sip_session_media *media; struct ast_sockaddr addr; if (!channel) { @@ -470,9 +471,9 @@ static int channel_read_rtp(struct ast_channel *chan, const char *type, const ch return -1; } - pvt = channel->pvt; - if (!pvt) { - ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan)); + session = channel->session; + if (!session) { + ast_log(AST_LOG_WARNING, "Channel %s has no session!\n", ast_channel_name(chan)); return -1; } @@ -482,9 +483,9 @@ static int channel_read_rtp(struct ast_channel *chan, const char *type, const ch } if (ast_strlen_zero(field) || !strcmp(field, "audio")) { - media = pvt->media[SIP_MEDIA_AUDIO]; + media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; } else if (!strcmp(field, "video")) { - media = pvt->media[SIP_MEDIA_VIDEO]; + media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO]; } else { ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field); return -1; @@ -522,17 +523,17 @@ static int channel_read_rtp(struct ast_channel *chan, const char *type, const ch static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - struct chan_pjsip_pvt *pvt; - struct ast_sip_session_media *media = NULL; + struct ast_sip_session *session; + struct ast_sip_session_media *media; if (!channel) { ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan)); return -1; } - pvt = channel->pvt; - if (!pvt) { - ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan)); + session = channel->session; + if (!session) { + ast_log(AST_LOG_WARNING, "Channel %s has no session!\n", ast_channel_name(chan)); return -1; } @@ -542,9 +543,9 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c } if (ast_strlen_zero(field) || !strcmp(field, "audio")) { - media = pvt->media[SIP_MEDIA_AUDIO]; + media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; } else if (!strcmp(field, "video")) { - media = pvt->media[SIP_MEDIA_VIDEO]; + media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO]; } else { ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field); return -1; @@ -924,22 +925,117 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char return 0; } +/*! \brief Session refresh state information */ +struct session_refresh_state { + /*! \brief Created proposed media state */ + struct ast_sip_session_media_state *media_state; +}; + +/*! \brief Destructor for session refresh information */ +static void session_refresh_state_destroy(void *obj) +{ + struct session_refresh_state *state = obj; + + ast_sip_session_media_state_free(state->media_state); + ast_free(obj); +} + +/*! \brief Datastore for attaching session refresh state information */ +static const struct ast_datastore_info session_refresh_datastore = { + .type = "pjsip_session_refresh", + .destroy = session_refresh_state_destroy, +}; + +/*! \brief Helper function which retrieves or allocates a session refresh state information datastore */ +static struct session_refresh_state *session_refresh_state_get_or_alloc(struct ast_sip_session *session) +{ + RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "pjsip_session_refresh"), ao2_cleanup); + struct session_refresh_state *state; + + /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */ + if (datastore) { + return datastore->data; + } + + if (!(datastore = ast_sip_session_alloc_datastore(&session_refresh_datastore, "pjsip_session_refresh")) + || !(datastore->data = ast_calloc(1, sizeof(struct session_refresh_state))) + || ast_sip_session_add_datastore(session, datastore)) { + return NULL; + } + + state = datastore->data; + state->media_state = ast_sip_session_media_state_alloc(); + if (!state->media_state) { + ast_sip_session_remove_datastore(session, "pjsip_session_refresh"); + return NULL; + } + state->media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + if (!state->media_state->topology) { + ast_sip_session_remove_datastore(session, "pjsip_session_refresh"); + return NULL; + } + + datastore->data = state; + + return state; +} + static int media_offer_read_av(struct ast_sip_session *session, char *buf, size_t len, enum ast_media_type media_type) { + struct ast_stream_topology *topology; int idx; + struct ast_stream *stream = NULL; + struct ast_format_cap *caps; size_t accum = 0; + if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) { + struct session_refresh_state *state; + + /* As we've already answered we need to store our media state until we are ready to send it */ + state = session_refresh_state_get_or_alloc(session); + if (!state) { + return -1; + } + topology = state->media_state->topology; + } else { + /* The session is not yet up so we are initially answering or offering */ + if (!session->pending_media_state->topology) { + session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + if (!session->pending_media_state->topology) { + return -1; + } + } + topology = session->pending_media_state->topology; + } + + /* Find the first suitable stream */ + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) { + stream = ast_stream_topology_get_stream(topology, idx); + + if (ast_stream_get_type(stream) != media_type || + ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + stream = NULL; + continue; + } + + break; + } + + /* If no suitable stream then exit early */ + if (!stream) { + buf[0] = '\0'; + return 0; + } + + caps = ast_stream_get_formats(stream); + /* Note: buf is not terminated while the string is being built. */ - for (idx = 0; idx < ast_format_cap_count(session->req_caps); ++idx) { + for (idx = 0; idx < ast_format_cap_count(caps); ++idx) { struct ast_format *fmt; size_t size; - fmt = ast_format_cap_get_format(session->req_caps, idx); - if (ast_format_get_type(fmt) != media_type) { - ao2_ref(fmt, -1); - continue; - } + fmt = ast_format_cap_get_format(caps, idx); /* Add one for a comma or terminator */ size = strlen(ast_format_get_name(fmt)) + 1; @@ -973,9 +1069,43 @@ struct media_offer_data { static int media_offer_write_av(void *obj) { struct media_offer_data *data = obj; + struct ast_stream_topology *topology; + struct ast_stream *stream; + struct ast_format_cap *caps; - ast_format_cap_remove_by_type(data->session->req_caps, data->media_type); - ast_format_cap_update_by_allow_disallow(data->session->req_caps, data->value, 1); + if (data->session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) { + struct session_refresh_state *state; + + /* As we've already answered we need to store our media state until we are ready to send it */ + state = session_refresh_state_get_or_alloc(data->session); + if (!state) { + return -1; + } + topology = state->media_state->topology; + } else { + /* The session is not yet up so we are initially answering or offering */ + if (!data->session->pending_media_state->topology) { + data->session->pending_media_state->topology = ast_stream_topology_clone(data->session->endpoint->media.topology); + if (!data->session->pending_media_state->topology) { + return -1; + } + } + topology = data->session->pending_media_state->topology; + } + + /* XXX This method won't work when it comes time to do multistream support. The proper way to do this + * will either be to + * a) Alter all media streams of a particular type. + * b) Change the dialplan function to be able to specify which stream to alter and alter only that + * one stream + */ + stream = ast_stream_topology_get_first_stream_by_type(topology, data->media_type); + if (!stream) { + return 0; + } + caps = ast_stream_get_formats(stream); + ast_format_cap_remove_by_type(caps, data->media_type); + ast_format_cap_update_by_allow_disallow(caps, data->value, 1); return 0; } @@ -1068,9 +1198,18 @@ static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_dat static int refresh_write_cb(void *obj) { struct refresh_data *data = obj; + struct session_refresh_state *state; + + state = session_refresh_state_get_or_alloc(data->session); + if (!state) { + return -1; + } ast_sip_session_refresh(data->session, NULL, NULL, - sip_session_response_cb, data->method, 1); + sip_session_response_cb, data->method, 1, state->media_state); + + state->media_state = NULL; + ast_sip_session_remove_datastore(data->session, "pjsip_session_refresh"); return 0; } diff --git a/channels/pjsip/include/chan_pjsip.h b/channels/pjsip/include/chan_pjsip.h index b229a0487f3..1fee86419e4 100644 --- a/channels/pjsip/include/chan_pjsip.h +++ b/channels/pjsip/include/chan_pjsip.h @@ -34,25 +34,12 @@ struct transport_info_data { pj_sockaddr local_addr; }; -/*! - * \brief Positions of various media - */ -enum sip_session_media_position { - /*! \brief First is audio */ - SIP_MEDIA_AUDIO = 0, - /*! \brief Second is video */ - SIP_MEDIA_VIDEO, - /*! \brief Last is the size for media details */ - SIP_MEDIA_SIZE, -}; /*! * \brief The PJSIP channel driver pvt, stored in the \ref ast_sip_channel_pvt * data structure */ struct chan_pjsip_pvt { - /*! \brief The available media sessions */ - struct ast_sip_session_media *media[SIP_MEDIA_SIZE]; }; #endif /* _CHAN_PJSIP_HEADER */ diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 3b93bb61fc2..ed5f93e71e3 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -779,6 +779,10 @@ ; The value "yes" is useful for some SIP phones ; (Cisco SPA) to be able to indicate and pick up ; ringing devices. +;max_audio_streams= ; The maximum number of allowed negotiated audio streams + ; (default: 1) +;max_video_streams= ; The maximum number of allowed negotiated video streams + ; (default: 1) ;==========================AUTH SECTION OPTIONS========================= ;[auth] diff --git a/contrib/ast-db-manage/config/versions/39959b9c2566_pjsip_stream_maximum.py b/contrib/ast-db-manage/config/versions/39959b9c2566_pjsip_stream_maximum.py new file mode 100644 index 00000000000..a091272b01b --- /dev/null +++ b/contrib/ast-db-manage/config/versions/39959b9c2566_pjsip_stream_maximum.py @@ -0,0 +1,24 @@ +"""pjsip_stream_maximum + +Revision ID: 39959b9c2566 +Revises: d7983954dd96 +Create Date: 2017-06-15 13:18:12.372333 + +""" + +# revision identifiers, used by Alembic. +revision = '39959b9c2566' +down_revision = 'd7983954dd96' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('max_audio_streams', sa.Integer)) + op.add_column('ps_endpoints', sa.Column('max_video_streams', sa.Integer)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'max_audio_streams') + op.drop_column('ps_endpoints', 'max_video_streams') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index b9c50addad4..f907effcfdd 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -666,6 +666,8 @@ struct ast_sip_endpoint_media_configuration { struct ast_sip_t38_configuration t38; /*! Configured codecs */ struct ast_format_cap *codecs; + /*! Capabilities in topology form */ + struct ast_stream_topology *topology; /*! DSCP TOS bits for audio streams */ unsigned int tos_audio; /*! Priority for audio streams */ @@ -680,6 +682,10 @@ struct ast_sip_endpoint_media_configuration { unsigned int bind_rtp_to_media_address; /*! Use RTCP-MUX */ unsigned int rtcp_mux; + /*! Maximum number of audio streams to offer/accept */ + unsigned int max_audio_streams; + /*! Maximum number of video streams to offer/accept */ + unsigned int max_video_streams; }; /*! diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index e2a90662ed0..e298e1f32da 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -28,6 +28,8 @@ #include "asterisk/netsock2.h" /* Needed for ast_sdp_srtp struct */ #include "asterisk/sdp_srtp.h" +/* Needed for ast_media_type */ +#include "asterisk/codec.h" /* Forward declarations */ struct ast_sip_endpoint; @@ -56,17 +58,21 @@ enum ast_sip_session_t38state { }; struct ast_sip_session_sdp_handler; +struct ast_sip_session; +struct ast_sip_session_media; + +typedef struct ast_frame *(*ast_sip_session_media_read_cb)(struct ast_sip_session *session, struct ast_sip_session_media *session_media); +typedef int (*ast_sip_session_media_write_cb)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + struct ast_frame *frame); /*! * \brief A structure containing SIP session media information */ struct ast_sip_session_media { - union { - /*! \brief RTP instance itself */ - struct ast_rtp_instance *rtp; - /*! \brief UDPTL instance itself */ - struct ast_udptl *udptl; - }; + /*! \brief RTP instance itself */ + struct ast_rtp_instance *rtp; + /*! \brief UDPTL instance itself */ + struct ast_udptl *udptl; /*! \brief Direct media address */ struct ast_sockaddr direct_media_addr; /*! \brief SDP handler that setup the RTP */ @@ -87,8 +93,38 @@ struct ast_sip_session_media { unsigned int locally_held:1; /*! \brief Does remote support rtcp_mux */ unsigned int remote_rtcp_mux:1; - /*! \brief Stream type this session media handles */ - char stream_type[1]; + /*! \brief Media type of this session media */ + enum ast_media_type type; + /*! \brief The write callback when writing frames */ + ast_sip_session_media_write_cb write_callback; + /*! \brief The stream number to place into any resulting frames */ + int stream_num; +}; + +/*! + * \brief Structure which contains read callback information + */ +struct ast_sip_session_media_read_callback_state { + /*! \brief The file descriptor itself */ + int fd; + /*! \brief The callback to invoke */ + ast_sip_session_media_read_cb read_callback; + /*! \brief The media session */ + struct ast_sip_session_media *session; +}; + +/*! + * \brief Structure which contains media state information (streams, sessions) + */ +struct ast_sip_session_media_state { + /*! \brief Mapping of stream to media sessions */ + AST_VECTOR(, struct ast_sip_session_media *) sessions; + /*! \brief Added read callbacks - these are whole structs and not pointers */ + AST_VECTOR(, struct ast_sip_session_media_read_callback_state) read_callbacks; + /*! \brief Default media sessions for each type */ + struct ast_sip_session_media *default_session[AST_MEDIA_TYPE_END]; + /*! \brief The media stream topology */ + struct ast_stream_topology *topology; }; /*! @@ -123,8 +159,6 @@ struct ast_sip_session { AST_LIST_HEAD(, ast_sip_session_supplement) supplements; /*! Datastores added to the session by supplements to the session */ struct ao2_container *datastores; - /*! Media streams */ - struct ao2_container *media; /*! Serializer for tasks relating to this SIP session */ struct ast_taskprocessor *serializer; /*! Non-null if the session serializer is suspended or being suspended. */ @@ -139,8 +173,10 @@ struct ast_sip_session { pj_timer_entry scheduled_termination; /*! Identity of endpoint this session deals with */ struct ast_party_id id; - /*! Requested capabilities */ - struct ast_format_cap *req_caps; + /*! Active media state (sessions + streams) - contents are guaranteed not to change */ + struct ast_sip_session_media_state *active_media_state; + /*! Pending media state (sessions + streams) */ + struct ast_sip_session_media_state *pending_media_state; /*! Optional DSP, used only for inband DTMF/Fax-CNG detection if configured */ struct ast_dsp *dsp; /*! Whether the termination of the session should be deferred */ @@ -315,34 +351,29 @@ struct ast_sip_session_sdp_handler { /*! * \brief Set session details based on a stream in an incoming SDP offer or answer * \param session The session for which the media is being negotiated - * \param session_media The media to be setup for this session + * \param session_media The media session * \param sdp The entire SDP. Useful for getting "global" information, such as connections or attributes - * \param stream The stream on which to operate - * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called. - * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned. - * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called. - */ - int (*negotiate_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream); - /*! - * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer - * \param session The session for which media is being added - * \param session_media The media to be setup for this session - * \param stream The stream on which to operate + * \param index The index for the session media, Asterisk stream, and PJMEDIA stream being negotiated + * \param asterisk_stream The Asterisk stream representation * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called. * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned. * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called. */ - int (*handle_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, struct pjmedia_sdp_media *stream); + int (*negotiate_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + const struct pjmedia_sdp_session *sdp, int index, struct ast_stream *asterisk_stream); /*! * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer * \param session The session for which media is being added * \param session_media The media to be setup for this session * \param sdp The entire SDP as currently built + * \param remote Optional remote SDP if this is an answer + * \param stream The stream that is to be added to the outgoing SDP * \retval 0 This handler has no stream to add. If there are other registered handlers for this stream type, they will be called. * \retval <0 There was an error encountered. No further operation will take place and the current SDP negotiation will be abandoned. * \retval >0 The handler has a stream to be added to the SDP. No further handler of this stream type will be called. */ - int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp); + int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp, + const struct pjmedia_sdp_session *remote, struct ast_stream *stream); /*! * \brief Update media stream with external address if applicable * \param tdata The outgoing message itself @@ -353,17 +384,18 @@ struct ast_sip_session_sdp_handler { /*! * \brief Apply a negotiated SDP media stream * \param session The session for which media is being applied - * \param session_media The media to be setup for this session + * \param session_media The media session * \param local The entire local negotiated SDP - * \param local_stream The local stream which to apply * \param remote The entire remote negotiated SDP - * \param remote_stream The remote stream which to apply + * \param index The index of the session media, SDP streams, and Asterisk streams + * \param asterisk_stream The Asterisk stream representation * \retval 0 The stream was not applied by this handler. If there are other registered handlers for this stream type, they will be called. * \retval <0 There was an error encountered. No further operation will take place and the current application will be abandoned. * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called. */ - int (*apply_negotiated_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream, - const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream); + int (*apply_negotiated_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_session *remote, int index, + struct ast_stream *asterisk_stream); /*! * \brief Stop a session_media created by this handler but do not destroy resources * \param session The session for which media is being stopped @@ -393,7 +425,7 @@ struct ast_sip_channel_pvt { /*! * \brief Allocate a new SIP channel pvt structure * - * \param pvt Pointer to channel specific implementation + * \param pvt Pointer to channel specific information * \param session Pointer to SIP session * * \retval non-NULL success @@ -452,11 +484,11 @@ void ast_sip_session_unsuspend(struct ast_sip_session *session); * \param contact The contact that this session will communicate with * \param location Name of the location to call, be it named location or explicit URI. Overrides contact if present. * \param request_user Optional request user to place in the request URI if permitted - * \param req_caps The requested capabilities + * \param req_topology The requested capabilities */ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, - struct ast_format_cap *req_caps); + struct ast_stream_topology *req_topology); /*! * \brief Terminate a session and, if possible, send the provided response code @@ -613,15 +645,20 @@ void ast_sip_session_remove_datastore(struct ast_sip_session *session, const cha * \param on_response Callback called when response for request is received * \param method The method that should be used when constructing the session refresh * \param generate_new_sdp Boolean to indicate if a new SDP should be created + * \param media_state Optional requested media state for the SDP + * * \retval 0 Successfully sent refresh * \retval -1 Failure to send refresh + * + * \note If a media_state is passed in ownership will be taken in all cases */ int ast_sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, - int generate_new_sdp); + int generate_new_sdp, + struct ast_sip_session_media_state *media_state); /*! * \brief Send a SIP response @@ -692,6 +729,110 @@ struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg); */ void ast_sip_session_resume_reinvite(struct ast_sip_session *session); +/*! + * \brief Determines if a provided pending stream will be the default stream or not + * \since 15.0.0 + * + * \param session The session to check against + * \param stream The pending stream + * + * \retval 1 if stream will be default + * \retval 0 if stream will NOT be the default + */ +int ast_sip_session_is_pending_stream_default(const struct ast_sip_session *session, const struct ast_stream *stream); + +/*! + * \brief Allocate a session media state structure + * \since 15.0.0 + * + * \retval non-NULL success + * \retval NULL failure + */ +struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void); + +/*! + * \brief Allocate an ast_session_media and add it to the media state's vector. + * \since 15.0.0 + * + * This allocates a session media of the specified type. The position argument + * determines where in the vector that the new session media will be inserted. + * + * \note The returned ast_session_media is the reference held by the vector. Callers + * of this function must NOT decrement the refcount of the session media. + * + * \param session Session on which to query active media state for + * \param media_state Media state to place the session media into + * \param type The type of the session media + * \param position Position at which to insert the new session media. + * + * \note The active media state will be queried and if a media session already + * exists at the given position for the same type it will be reused instead of + * allocating a new one. + * + * \retval non-NULL success + * \retval NULL failure + */ +struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session, + struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position); + +/*! + * \brief Reset a media state to a clean state + * \since 15.0.0 + * + * \param media_state The media state to reset + */ +void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state); + +/*! + * \brief Clone a media state + * \since 15.0.0 + * + * \param media_state The media state to clone + * + * \retval non-NULL success + * \retval NULL failure + */ +struct ast_sip_session_media_state *ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state); + +/*! + * \brief Free a session media state structure + * \since 15.0.0 + */ +void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state); + +/*! + * \brief Set a read callback for a media session with a specific file descriptor + * \since 15.0.0 + * + * \param session The session + * \param session_media The media session + * \param fd The file descriptor + * \param callback The read callback + * + * \retval 0 the read callback was successfully added + * \retval -1 the read callback could not be added + * + * \note This operations on the pending media state + */ +int ast_sip_session_media_add_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + int fd, ast_sip_session_media_read_cb callback); + +/*! + * \brief Set a write callback for a media session + * \since 15.0.0 + * + * \param session The session + * \param session_media The media session + * \param callback The write callback + * + * \retval 0 the write callback was successfully add + * \retval -1 the write callback is already set to something different + * + * \note This operates on the pending media state + */ +int ast_sip_session_media_set_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + ast_sip_session_media_write_cb callback); + /*! \brief Determines whether the res_pjsip_session module is loaded */ #define CHECK_PJSIP_SESSION_MODULE_LOADED() \ do { \ diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 00169a3f1f6..4027231edd4 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -289,6 +289,20 @@ struct ast_stream_topology *ast_stream_topology_alloc(void); struct ast_stream_topology *ast_stream_topology_clone( const struct ast_stream_topology *topology); +/*! + * \brief Compare two stream topologies to see if they are equal + * + * \param left The left topology + * \param right The right topology + * + * \retval 1 topologies are equivalent + * \retval 0 topologies differ + * + * \since 15 + */ +int ast_stream_topology_equal(const struct ast_stream_topology *left, + const struct ast_stream_topology *right); + /*! * \brief Destroy a stream topology * @@ -391,7 +405,7 @@ int ast_stream_topology_del_stream(struct ast_stream_topology *topology, * since a new format capabilities structure is created for each media type. * * \note Each stream will have its name set to the corresponding media type. - * For example: "AST_MEDIA_TYPE_AUDIO". + * For example: "audio". * * \note Each stream will be set to the sendrecv state. * diff --git a/main/channel.c b/main/channel.c index 8b4dc75bec8..c7c2b9d1e6e 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4928,17 +4928,28 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame goto done; } - /* If this frame is writing an audio or video frame get the stream information */ - if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO) { - /* Initially use the default stream unless an explicit stream is provided */ - stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(fr->subclass.format)); + if (stream_num >= 0) { + /* If we were told to write to an explicit stream then allow this frame through, no matter + * if the type is expected or not (a framehook could change) + */ + if (stream_num >= ast_stream_topology_get_count(ast_channel_get_stream_topology(chan))) { + goto done; + } + stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num); + default_stream = ast_channel_get_default_stream(chan, ast_stream_get_type(stream)); + } else if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_MODEM) { + /* If we haven't been told of a stream then we need to figure out which once we need */ + enum ast_media_type type = AST_MEDIA_TYPE_UNKNOWN; - if (stream_num >= 0) { - if (stream_num >= ast_stream_topology_get_count(ast_channel_get_stream_topology(chan))) { - goto done; - } - stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num); + /* Some frame types have a fixed media type */ + if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO) { + type = ast_format_get_type(fr->subclass.format); + } else if (fr->frametype == AST_FRAME_MODEM) { + type = AST_MEDIA_TYPE_IMAGE; } + + /* No stream was specified, so use the default one */ + stream = default_stream = ast_channel_get_default_stream(chan, type); } /* Perform the framehook write event here. After the frame enters the framehook list @@ -5035,12 +5046,16 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame res = ast_channel_tech(chan)->write_video(chan, fr); } else { res = 0; - } break; case AST_FRAME_MODEM: - res = (ast_channel_tech(chan)->write == NULL) ? 0 : - ast_channel_tech(chan)->write(chan, fr); + if (ast_channel_tech(chan)->write_stream) { + res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr); + } else if ((stream == default_stream) && ast_channel_tech(chan)->write) { + res = ast_channel_tech(chan)->write(chan, fr); + } else { + res = 0; + } break; case AST_FRAME_VOICE: if (ast_opt_generic_plc && ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { @@ -10948,6 +10963,12 @@ int ast_channel_request_stream_topology_change(struct ast_channel *chan, return -1; } + if (ast_stream_topology_equal(ast_channel_get_stream_topology(chan), topology)) { + ast_debug(3, "Topology of %s already matches what is requested so ignoring topology change request\n", + ast_channel_name(chan)); + return 0; + } + ast_channel_internal_set_stream_topology_change_source(chan, change_source); return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, topology, sizeof(topology)); diff --git a/main/stream.c b/main/stream.c index 20179f33133..093cd5450ba 100644 --- a/main/stream.c +++ b/main/stream.c @@ -284,6 +284,53 @@ struct ast_stream_topology *ast_stream_topology_clone( return new_topology; } +int ast_stream_topology_equal(const struct ast_stream_topology *left, + const struct ast_stream_topology *right) +{ + int index; + + ast_assert(left != NULL); + ast_assert(right != NULL); + + if (ast_stream_topology_get_count(left) != ast_stream_topology_get_count(right)) { + return 0; + } + + for (index = 0; index < ast_stream_topology_get_count(left); ++index) { + const struct ast_stream *left_stream = ast_stream_topology_get_stream(left, index); + const struct ast_stream *right_stream = ast_stream_topology_get_stream(right, index); + + if (ast_stream_get_type(left_stream) != ast_stream_get_type(right_stream)) { + return 0; + } + + if (ast_stream_get_state(left_stream) != ast_stream_get_state(right_stream)) { + return 0; + } + + if (!ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) && + ast_format_cap_count(ast_stream_get_formats(right_stream))) { + /* A NULL format capabilities and an empty format capabilities are the same, as they have + * no formats inside. If one does though... they are not equal. + */ + return 0; + } else if (!ast_stream_get_formats(right_stream) && ast_stream_get_formats(left_stream) && + ast_format_cap_count(ast_stream_get_formats(left_stream))) { + return 0; + } else if (ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) && + !ast_format_cap_identical(ast_stream_get_formats(left_stream), ast_stream_get_formats(right_stream))) { + /* But if both are actually present we need to do an actual identical check. */ + return 0; + } + + if (strcmp(ast_stream_get_name(left_stream), ast_stream_get_name(right_stream))) { + return 0; + } + } + + return 1; +} + void ast_stream_topology_free(struct ast_stream_topology *topology) { if (!topology) { diff --git a/res/res_pjsip.c b/res/res_pjsip.c index f6d63c64007..e717fdb40f9 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -978,6 +978,20 @@ on Ringing when already INUSE. + + The maximum number of allowed audio streams for the endpoint + + This option enforces a limit on the maximum simultaneous negotiated audio + streams allowed for the endpoint. + + + + The maximum number of allowed video streams for the endpoint + + This option enforces a limit on the maximum simultaneous negotiated video + streams allowed for the endpoint. + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 7a05f87f08c..56a8419a88b 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -22,6 +22,7 @@ #include "asterisk/test.h" #include "asterisk/statsd.h" #include "asterisk/pbx.h" +#include "asterisk/stream.h" /*! \brief Number of buckets for persistent endpoint information */ #define PERSISTENT_BUCKETS 53 @@ -1321,6 +1322,11 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o return -1; } + endpoint->media.topology = ast_stream_topology_create_from_format_cap(endpoint->media.codecs); + if (!endpoint->media.topology) { + return -1; + } + return 0; } @@ -1941,6 +1947,8 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); @@ -2060,7 +2068,8 @@ static void endpoint_destructor(void* obj) ast_string_field_free_memory(endpoint); - ao2_ref(endpoint->media.codecs, -1); + ao2_cleanup(endpoint->media.codecs); + ast_stream_topology_free(endpoint->media.topology); subscription_configuration_destroy(&endpoint->subscription); info_configuration_destroy(&endpoint->info); media_configuration_destroy(&endpoint->media); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index c5a673aa4e0..03fef40cf4b 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -51,6 +51,8 @@ #include "asterisk/sdp_srtp.h" #include "asterisk/dsp.h" #include "asterisk/linkedlists.h" /* for AST_LIST_NEXT */ +#include "asterisk/stream.h" +#include "asterisk/format_cache.h" #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_session.h" @@ -62,48 +64,7 @@ static struct ast_sched_context *sched; static struct ast_sockaddr address_rtp; static const char STR_AUDIO[] = "audio"; -static const int FD_AUDIO = 0; - static const char STR_VIDEO[] = "video"; -static const int FD_VIDEO = 2; - -/*! \brief Retrieves an ast_format_type based on the given stream_type */ -static enum ast_media_type stream_to_media_type(const char *stream_type) -{ - if (!strcasecmp(stream_type, STR_AUDIO)) { - return AST_MEDIA_TYPE_AUDIO; - } else if (!strcasecmp(stream_type, STR_VIDEO)) { - return AST_MEDIA_TYPE_VIDEO; - } - - return 0; -} - -/*! \brief Get the starting descriptor for a media type */ -static int media_type_to_fdno(enum ast_media_type media_type) -{ - switch (media_type) { - case AST_MEDIA_TYPE_AUDIO: return FD_AUDIO; - case AST_MEDIA_TYPE_VIDEO: return FD_VIDEO; - case AST_MEDIA_TYPE_TEXT: - case AST_MEDIA_TYPE_UNKNOWN: - case AST_MEDIA_TYPE_IMAGE: - case AST_MEDIA_TYPE_END: break; - } - return -1; -} - -/*! \brief Remove all other cap types but the one given */ -static void format_cap_only_type(struct ast_format_cap *caps, enum ast_media_type media_type) -{ - int i = 0; - while (i <= AST_MEDIA_TYPE_TEXT) { - if (i != media_type && i != AST_MEDIA_TYPE_UNKNOWN) { - ast_format_cap_remove_by_type(caps, i); - } - i += 1; - } -} static int send_keepalive(const void *data) { @@ -253,11 +214,11 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND); } - if (!strcmp(session_media->stream_type, STR_AUDIO) && + if (session_media->type == AST_MEDIA_TYPE_AUDIO && (session->endpoint->media.tos_audio || session->endpoint->media.cos_audio)) { ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_audio, session->endpoint->media.cos_audio, "SIP RTP Audio"); - } else if (!strcmp(session_media->stream_type, STR_VIDEO) && + } else if (session_media->type == AST_MEDIA_TYPE_VIDEO && (session->endpoint->media.tos_video || session->endpoint->media.cos_video)) { ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_video, session->endpoint->media.cos_video, "SIP RTP Video"); @@ -347,12 +308,13 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream, - int is_offer) + int is_offer, struct ast_stream *asterisk_stream) { RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup); - enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); + RAII_VAR(struct ast_format_cap *, endpoint_caps, NULL, ao2_cleanup); + enum ast_media_type media_type = session_media->type; struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT; int fmts = 0; int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && @@ -362,14 +324,14 @@ static int set_caps(struct ast_sip_session *session, if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type); + ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", + ast_codec_media_type2str(session_media->type)); return -1; } /* get the endpoint capabilities */ if (direct_media_enabled) { ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps); - format_cap_only_type(caps, media_type); } else { ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type); } @@ -386,7 +348,7 @@ static int set_caps(struct ast_sip_session *session, ast_rtp_codecs_payloads_destroy(&codecs); ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n", - session_media->stream_type, + ast_codec_media_type2str(session_media->type), ast_format_cap_get_names(caps, &usbuf), ast_format_cap_get_names(peer, &thembuf)); return -1; @@ -402,9 +364,9 @@ static int set_caps(struct ast_sip_session *session, ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp), session_media->rtp); - ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN); + ast_stream_set_formats(asterisk_stream, joint); - if (session->channel) { + if (session->channel && ast_sip_session_is_pending_stream_default(session, asterisk_stream)) { ast_channel_lock(session->channel); ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), @@ -968,24 +930,21 @@ static void set_ice_components(struct ast_sip_session *session, struct ast_sip_s } /*! \brief Function which negotiates an incoming media stream */ -static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, - const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream) +static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, + int index, struct ast_stream *asterisk_stream) { char host[NI_MAXHOST]; RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); - enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); + pjmedia_sdp_media *stream = sdp->media[index]; + enum ast_media_type media_type = session_media->type; enum ast_sip_session_media_encryption encryption = AST_SIP_MEDIA_ENCRYPT_NONE; int res; - /* If port is 0, ignore this media stream */ - if (!stream->desc.port) { - ast_debug(3, "Media stream '%s' is already declined\n", session_media->stream_type); - return 0; - } - /* If no type formats have been configured reject this stream */ if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) { - ast_debug(3, "Endpoint has no codecs for media type '%s', declining stream\n", session_media->stream_type); + ast_debug(3, "Endpoint has no codecs for media type '%s', declining stream\n", + ast_codec_media_type2str(session_media->type)); return 0; } @@ -1040,7 +999,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport); } - if (set_caps(session, session_media, stream, 1)) { + if (set_caps(session, session_media, stream, 1, asterisk_stream)) { return 0; } return 1; @@ -1161,9 +1120,10 @@ static int add_crypto_to_stream(struct ast_sip_session *session, /*! \brief Function which creates an outgoing stream */ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, - struct pjmedia_sdp_session *sdp) + struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream) { pj_pool_t *pool = session->inv_session->pool_prov; + static const pj_str_t STR_RTP_AVP = { "RTP/AVP", 7 }; static const pj_str_t STR_IN = { "IN", 2 }; static const pj_str_t STR_IP4 = { "IP4", 3}; static const pj_str_t STR_IP6 = { "IP6", 3}; @@ -1180,33 +1140,60 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as int min_packet_size = 0, max_packet_size = 0; int rtp_code; RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); - enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); - int use_override_prefs = ast_format_cap_count(session->req_caps); + enum ast_media_type media_type = session_media->type; int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && ast_format_cap_count(session->direct_media_cap); - if ((use_override_prefs && !ast_format_cap_has_type(session->req_caps, media_type)) || - (!use_override_prefs && !ast_format_cap_has_type(session->endpoint->media.codecs, media_type))) { - /* If no type formats are configured don't add a stream */ - return 0; - } else if (!session_media->rtp && create_rtp(session, session_media)) { + media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media)); + if (!media) { return -1; } + pj_strdup2(pool, &media->desc.media, ast_codec_media_type2str(session_media->type)); - set_ice_components(session, session_media); - enable_rtcp(session, session_media, NULL); + /* If this is a removed (or declined) stream OR if no formats exist then construct a minimal stream in SDP */ + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED || !ast_stream_get_formats(stream) || + !ast_format_cap_count(ast_stream_get_formats(stream))) { + media->desc.port = 0; + media->desc.port_count = 1; + + if (remote) { + pjmedia_sdp_media *remote_media = remote->media[ast_stream_get_position(stream)]; + int index; + + media->desc.transport = remote_media->desc.transport; + + /* Preserve existing behavior by copying the formats provided from the offer */ + for (index = 0; index < remote_media->desc.fmt_count; ++index) { + media->desc.fmt[index] = remote_media->desc.fmt[index]; + } + media->desc.fmt_count = remote_media->desc.fmt_count; + } else { + /* This is actually an offer so put a dummy payload in that is ignored and sane transport */ + media->desc.transport = STR_RTP_AVP; + pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], "32"); + } + + sdp->media[sdp->media_count++] = media; + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + + return 1; + } - if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) || - !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) { + if (!session_media->rtp && create_rtp(session, session_media)) { return -1; } + set_ice_components(session, session_media); + enable_rtcp(session, session_media, NULL); + + /* Crypto has to be added before setting the media transport so that SRTP is properly + * set up according to the configuration. This ends up changing the media transport. + */ if (add_crypto_to_stream(session, session_media, pool, media)) { return -1; } - media->desc.media = pj_str(session_media->stream_type); if (pj_strlen(&session_media->transport)) { /* If a transport has already been specified use it */ media->desc.transport = session_media->transport; @@ -1219,6 +1206,11 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as session->endpoint->media.rtp.force_avp)); } + media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)); + if (!media->conn) { + return -1; + } + /* Add connection level details */ if (direct_media_enabled) { hostip = ast_sockaddr_stringify_fmt(&session_media->direct_media_addr, AST_SOCKADDR_STR_ADDR); @@ -1229,7 +1221,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } if (ast_strlen_zero(hostip)) { - ast_log(LOG_ERROR, "No local host IP available for stream %s\n", session_media->stream_type); + ast_log(LOG_ERROR, "No local host IP available for stream %s\n", + ast_codec_media_type2str(session_media->type)); return -1; } @@ -1247,25 +1240,23 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } } + /* Add ICE attributes and candidates */ + add_ice_to_stream(session, session_media, pool, media); + ast_rtp_instance_get_local_address(session_media->rtp, &addr); media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr); media->desc.port_count = 1; - /* Add ICE attributes and candidates */ - add_ice_to_stream(session, session_media, pool, media); - if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type); + ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", + ast_codec_media_type2str(session_media->type)); return -1; } if (direct_media_enabled) { ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps); - } else if (!ast_format_cap_count(session->req_caps) || - !ast_format_cap_iscompatible(session->req_caps, session->endpoint->media.codecs)) { - ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type); } else { - ast_format_cap_append_from_cap(caps, session->req_caps, media_type); + ast_format_cap_append_from_cap(caps, ast_stream_get_formats(stream), media_type); } for (index = 0; index < ast_format_cap_count(caps); ++index) { @@ -1302,7 +1293,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } /* Add non-codec formats */ - if (media_type != AST_MEDIA_TYPE_VIDEO && media->desc.fmt_count < PJMEDIA_MAX_SDP_FMT) { + if (ast_sip_session_is_pending_stream_default(session, stream) && media_type != AST_MEDIA_TYPE_VIDEO + && media->desc.fmt_count < PJMEDIA_MAX_SDP_FMT) { for (index = 1LL; index <= AST_RTP_MAX; index <<= 1) { if (!(noncodec & index)) { continue; @@ -1368,23 +1360,65 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as return 1; } -static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, - const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream, - const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream) +static struct ast_frame *media_session_rtp_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media) +{ + struct ast_frame *f; + + if (!session_media->rtp) { + return &ast_null_frame; + } + + f = ast_rtp_instance_read(session_media->rtp, 0); + if (!f) { + return NULL; + } + + ast_rtp_instance_set_last_rx(session_media->rtp, time(NULL)); + + return f; +} + +static struct ast_frame *media_session_rtcp_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media) +{ + struct ast_frame *f; + + if (!session_media->rtp) { + return &ast_null_frame; + } + + f = ast_rtp_instance_read(session_media->rtp, 1); + if (!f) { + return NULL; + } + + ast_rtp_instance_set_last_rx(session_media->rtp, time(NULL)); + + return f; +} + +static int media_session_rtp_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame) +{ + if (!session_media->rtp) { + return 0; + } + + return ast_rtp_instance_write(session_media->rtp, frame); +} + +static int apply_negotiated_sdp_stream(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, + const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream) { RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); - enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); + struct pjmedia_sdp_media *remote_stream = remote->media[index]; + enum ast_media_type media_type = session_media->type; char host[NI_MAXHOST]; - int fdno, res; + int res; if (!session->channel) { return 1; } - if (!local_stream->desc.port || !remote_stream->desc.port) { - return 1; - } - /* Ensure incoming transport is compatible with the endpoint's configuration */ if (!session->endpoint->media.rtp.use_received_transport && check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) { @@ -1424,21 +1458,26 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a /* Apply connection information to the RTP instance */ ast_sockaddr_set_port(addrs, remote_stream->desc.port); ast_rtp_instance_set_remote_address(session_media->rtp, addrs); - if (set_caps(session, session_media, remote_stream, 0)) { + if (set_caps(session, session_media, remote_stream, 0, asterisk_stream)) { return 1; } - if ((fdno = media_type_to_fdno(media_type)) < 0) { - return -1; - } - ast_channel_set_fd(session->channel, fdno, ast_rtp_instance_fd(session_media->rtp, 0)); + ast_sip_session_media_set_write_callback(session, session_media, media_session_rtp_write_callback); + ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 0), + media_session_rtp_read_callback); if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) { - ast_channel_set_fd(session->channel, fdno + 1, ast_rtp_instance_fd(session_media->rtp, 1)); + ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 1), + media_session_rtcp_read_callback); } /* If ICE support is enabled find all the needed attributes */ process_ice_attributes(session, session_media, remote, remote_stream); + /* Set the channel uniqueid on the RTP instance now that it is becoming active */ + ast_channel_lock(session->channel); + ast_rtp_instance_set_channel_id(session_media->rtp, ast_channel_uniqueid(session->channel)); + ast_channel_unlock(session->channel); + /* Ensure the RTP instance is active */ ast_rtp_instance_activate(session_media->rtp); @@ -1476,7 +1515,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a session_media->encryption = session->endpoint->media.rtp.encryption; if (session->endpoint->media.rtp.keepalive > 0 && - stream_to_media_type(session_media->stream_type) == AST_MEDIA_TYPE_AUDIO) { + session_media->type == AST_MEDIA_TYPE_AUDIO) { ast_rtp_instance_set_keepalive(session_media->rtp, session->endpoint->media.rtp.keepalive); /* Schedule the initial keepalive early in case this is being used to punch holes through * a NAT. This way there won't be an awkward delay before media starts flowing in some diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index ffd01cadf05..ecda4990132 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -47,12 +47,16 @@ #include "asterisk/features_config.h" #include "asterisk/pickup.h" #include "asterisk/test.h" +#include "asterisk/stream.h" #define SDP_HANDLER_BUCKETS 11 #define MOD_DATA_ON_RESPONSE "on_response" #define MOD_DATA_NAT_HOOK "nat_hook" +/* Most common case is one audio and one video stream */ +#define DEFAULT_NUM_SESSION_MEDIA 2 + /* Some forward declarations */ static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata); static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, @@ -103,23 +107,6 @@ static int sdp_handler_list_cmp(void *obj, void *arg, int flags) return strcmp(handler_list1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP; } -static int session_media_hash(const void *obj, int flags) -{ - const struct ast_sip_session_media *session_media = obj; - const char *stream_type = flags & OBJ_KEY ? obj : session_media->stream_type; - - return ast_str_hash(stream_type); -} - -static int session_media_cmp(void *obj, void *arg, int flags) -{ - struct ast_sip_session_media *session_media1 = obj; - struct ast_sip_session_media *session_media2 = arg; - const char *stream_type2 = flags & OBJ_KEY ? arg : session_media2->stream_type; - - return strcmp(session_media1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP; -} - int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type) { RAII_VAR(struct sdp_handler_list *, handler_list, @@ -187,6 +174,156 @@ void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler * ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler); } +struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) +{ + struct ast_sip_session_media_state *media_state; + + media_state = ast_calloc(1, sizeof(*media_state)); + if (!media_state) { + return NULL; + } + + if (AST_VECTOR_INIT(&media_state->sessions, DEFAULT_NUM_SESSION_MEDIA) < 0) { + ast_free(media_state); + return NULL; + } + + if (AST_VECTOR_INIT(&media_state->read_callbacks, DEFAULT_NUM_SESSION_MEDIA) < 0) { + AST_VECTOR_FREE(&media_state->sessions); + ast_free(media_state); + return NULL; + } + + return media_state; +} + +void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state) +{ + int index; + + if (!media_state) { + return; + } + + AST_VECTOR_RESET(&media_state->sessions, ao2_cleanup); + AST_VECTOR_RESET(&media_state->read_callbacks, AST_VECTOR_ELEM_CLEANUP_NOOP); + + for (index = 0; index < AST_MEDIA_TYPE_END; ++index) { + media_state->default_session[index] = NULL; + } + + ast_stream_topology_free(media_state->topology); + media_state->topology = NULL; +} + +struct ast_sip_session_media_state *ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state) +{ + struct ast_sip_session_media_state *cloned; + int index; + + if (!media_state) { + return NULL; + } + + cloned = ast_sip_session_media_state_alloc(); + if (!cloned) { + return NULL; + } + + if (media_state->topology) { + cloned->topology = ast_stream_topology_clone(media_state->topology); + if (!cloned->topology) { + ast_sip_session_media_state_free(cloned); + return NULL; + } + } + + for (index = 0; index < AST_VECTOR_SIZE(&media_state->sessions); ++index) { + struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index); + enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(cloned->topology, index)); + + AST_VECTOR_REPLACE(&cloned->sessions, index, ao2_bump(session_media)); + if (ast_stream_get_state(ast_stream_topology_get_stream(cloned->topology, index)) != AST_STREAM_STATE_REMOVED && + !cloned->default_session[type]) { + cloned->default_session[type] = session_media; + } + } + + for (index = 0; index < AST_VECTOR_SIZE(&media_state->read_callbacks); ++index) { + struct ast_sip_session_media_read_callback_state *read_callback = AST_VECTOR_GET_ADDR(&media_state->read_callbacks, index); + + AST_VECTOR_REPLACE(&cloned->read_callbacks, index, *read_callback); + } + + return cloned; +} + +void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state) +{ + if (!media_state) { + return; + } + + /* This will reset the internal state so we only have to free persistent things */ + ast_sip_session_media_state_reset(media_state); + + AST_VECTOR_FREE(&media_state->sessions); + AST_VECTOR_FREE(&media_state->read_callbacks); + + ast_free(media_state); +} + +int ast_sip_session_is_pending_stream_default(const struct ast_sip_session *session, const struct ast_stream *stream) +{ + int index; + + ast_assert(session->pending_media_state->topology != NULL); + + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + return 0; + } + + for (index = 0; index < ast_stream_topology_get_count(session->pending_media_state->topology); ++index) { + if (ast_stream_get_type(ast_stream_topology_get_stream(session->pending_media_state->topology, index)) != + ast_stream_get_type(stream)) { + continue; + } + + return ast_stream_topology_get_stream(session->pending_media_state->topology, index) == stream ? 1 : 0; + } + + return 0; +} + +int ast_sip_session_media_add_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + int fd, ast_sip_session_media_read_cb callback) +{ + struct ast_sip_session_media_read_callback_state callback_state = { + .fd = fd, + .read_callback = callback, + .session = session_media, + }; + + /* The contents of the vector are whole structs and not pointers */ + return AST_VECTOR_APPEND(&session->pending_media_state->read_callbacks, callback_state); +} + +int ast_sip_session_media_set_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + ast_sip_session_media_write_cb callback) +{ + if (session_media->write_callback) { + if (session_media->write_callback == callback) { + return 0; + } + + return -1; + } + + session_media->write_callback = callback; + + return 0; +} + /*! * \brief Set an SDP stream handler for a corresponding session media. * @@ -207,50 +344,178 @@ static void session_media_set_handler(struct ast_sip_session_media *session_medi session_media->handler = handler; } +static int stream_destroy(void *obj, void *arg, int flags) +{ + struct sdp_handler_list *handler_list = obj; + struct ast_sip_session_media *session_media = arg; + struct ast_sip_session_sdp_handler *handler; + + AST_LIST_TRAVERSE(&handler_list->list, handler, next) { + handler->stream_destroy(session_media); + } + + return 0; +} + +static void session_media_dtor(void *obj) +{ + struct ast_sip_session_media *session_media = obj; + + /* It is possible for multiple handlers to have allocated memory on the + * session media (usually through a stream changing types). Therefore, we + * traverse all the SDP handlers and let them all call stream_destroy on + * the session_media + */ + ao2_callback(sdp_handlers, 0, stream_destroy, session_media); + + if (session_media->srtp) { + ast_sdp_srtp_destroy(session_media->srtp); + } +} + +struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session, + struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position) +{ + struct ast_sip_session_media *session_media = NULL; + + /* It is possible for this media state to already contain a session for the stream. If this + * is the case we simply return it. + */ + if (position < AST_VECTOR_SIZE(&media_state->sessions)) { + return AST_VECTOR_GET(&media_state->sessions, position); + } + + /* Determine if we can reuse the session media from the active media state if present */ + if (position < AST_VECTOR_SIZE(&session->active_media_state->sessions)) { + session_media = AST_VECTOR_GET(&session->active_media_state->sessions, position); + /* A stream can never exist without an accompanying media session */ + if (session_media->type == type) { + ao2_ref(session_media, +1); + } else { + session_media = NULL; + } + } + + if (!session_media) { + /* No existing media session we can use so create a new one */ + session_media = ao2_alloc_options(sizeof(*session_media), session_media_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!session_media) { + return NULL; + } + + session_media->encryption = session->endpoint->media.rtp.encryption; + session_media->keepalive_sched_id = -1; + session_media->timeout_sched_id = -1; + session_media->type = type; + session_media->stream_num = position; + } + + AST_VECTOR_REPLACE(&media_state->sessions, position, session_media); + + /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */ + if (!media_state->default_session[type] && + ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) { + media_state->default_session[type] = session_media; + } + + return session_media; +} + +static int is_stream_limitation_reached(enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams) +{ + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + return !(type_streams[type] < endpoint->media.max_audio_streams); + case AST_MEDIA_TYPE_VIDEO: + return !(type_streams[type] < endpoint->media.max_video_streams); + case AST_MEDIA_TYPE_IMAGE: + /* We don't have an option for image (T.38) streams so cap it to one. */ + return (type_streams[type] > 0); + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_TEXT: + default: + /* We don't want any unknown or "other" streams on our endpoint, + * so always just say we've reached the limit + */ + return 1; + } +} + static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp) { int i; int handled = 0; + int type_streams[AST_MEDIA_TYPE_END] = {0}; if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) { ast_log(LOG_ERROR, "Failed to handle incoming SDP. Session has been already disconnected\n"); return -1; } + /* It is possible for SDP deferral to have already created a pending topology */ + if (!session->pending_media_state->topology) { + session->pending_media_state->topology = ast_stream_topology_alloc(); + if (!session->pending_media_state->topology) { + return -1; + } + } + for (i = 0; i < sdp->media_count; ++i) { /* See if there are registered handlers for this media stream type */ char media[20]; struct ast_sip_session_sdp_handler *handler; RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup); + struct ast_sip_session_media *session_media = NULL; int res; + enum ast_media_type type; + struct ast_stream *stream = NULL; + pjmedia_sdp_media *remote_stream = sdp->media[i]; /* We need a null-terminated version of the media string */ ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media)); + type = ast_media_type_from_str(media); + + /* See if we have an already existing stream, which can occur from SDP deferral checking */ + if (i < ast_stream_topology_get_count(session->pending_media_state->topology)) { + stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i); + } + if (!stream) { + stream = ast_stream_alloc(ast_codec_media_type2str(type), type); + if (!stream) { + return -1; + } + ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream); + } - session_media = ao2_find(session->media, media, OBJ_KEY); + session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i); if (!session_media) { - /* if the session_media doesn't exist, there weren't - * any handlers at the time of its creation */ + return -1; + } + + /* If this stream is already declined mark it as such, or mark it as such if we've reached the limit */ + if (!remote_stream->desc.port || is_stream_limitation_reached(type, session->endpoint, type_streams)) { + ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n", + ast_codec_media_type2str(type), i); + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); continue; } if (session_media->handler) { handler = session_media->handler; ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n", - session_media->stream_type, + ast_codec_media_type2str(session_media->type), session_media->handler->id); - res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, - sdp->media[i]); + res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream); if (res < 0) { /* Catastrophic failure. Abort! */ return -1; } else if (res > 0) { ast_debug(1, "Media stream '%s' handled by %s\n", - session_media->stream_type, + ast_codec_media_type2str(session_media->type), session_media->handler->id); /* Handled by this handler. Move to the next stream */ handled = 1; + ++type_streams[type]; continue; } } @@ -265,21 +530,21 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd continue; } ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n", - session_media->stream_type, + ast_codec_media_type2str(session_media->type), handler->id); - res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, - sdp->media[i]); + res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream); if (res < 0) { /* Catastrophic failure. Abort! */ return -1; } if (res > 0) { ast_debug(1, "Media stream '%s' handled by %s\n", - session_media->stream_type, + ast_codec_media_type2str(session_media->type), handler->id); /* Handled by this handler. Move to the next stream */ session_media_set_handler(session_media, handler); handled = 1; + ++type_streams[type]; break; } } @@ -290,110 +555,159 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd return 0; } -struct handle_negotiated_sdp_cb { - struct ast_sip_session *session; - const pjmedia_sdp_session *local; - const pjmedia_sdp_session *remote; -}; - -static int handle_negotiated_sdp_session_media(void *obj, void *arg, int flags) +static int handle_negotiated_sdp_session_media(struct ast_sip_session_media *session_media, + struct ast_sip_session *session, const pjmedia_sdp_session *local, + const pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream) { - struct ast_sip_session_media *session_media = obj; - struct handle_negotiated_sdp_cb *callback_data = arg; - struct ast_sip_session *session = callback_data->session; - const pjmedia_sdp_session *local = callback_data->local; - const pjmedia_sdp_session *remote = callback_data->remote; - int i; - - for (i = 0; i < local->media_count; ++i) { - /* See if there are registered handlers for this media stream type */ - char media[20]; - struct ast_sip_session_sdp_handler *handler; - RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup); - int res; + /* See if there are registered handlers for this media stream type */ + struct pjmedia_sdp_media *local_stream = local->media[index]; + char media[20]; + struct ast_sip_session_sdp_handler *handler; + RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup); + int res; - if (!remote->media[i]) { - continue; + /* For backwards compatibility we only reflect the stream state correctly on + * the non-default streams. This is because the stream state is also used for + * signaling that someone has placed us on hold. This situation is not handled + * currently and can result in the remote side being sort of placed on hold too. + */ + if (!ast_sip_session_is_pending_stream_default(session, asterisk_stream)) { + /* Determine the state of the stream based on our local SDP */ + if (pjmedia_sdp_media_find_attr2(local_stream, "sendonly", NULL)) { + ast_stream_set_state(asterisk_stream, AST_STREAM_STATE_SENDONLY); + } else if (pjmedia_sdp_media_find_attr2(local_stream, "recvonly", NULL)) { + ast_stream_set_state(asterisk_stream, AST_STREAM_STATE_RECVONLY); + } else if (pjmedia_sdp_media_find_attr2(local_stream, "inactive", NULL)) { + ast_stream_set_state(asterisk_stream, AST_STREAM_STATE_INACTIVE); + } else { + ast_stream_set_state(asterisk_stream, AST_STREAM_STATE_SENDRECV); } + } else { + ast_stream_set_state(asterisk_stream, AST_STREAM_STATE_SENDRECV); + } - /* We need a null-terminated version of the media string */ - ast_copy_pj_str(media, &local->media[i]->desc.media, sizeof(media)); - - /* stream type doesn't match the one we're looking to fill */ - if (strcasecmp(session_media->stream_type, media)) { - continue; - } + /* We need a null-terminated version of the media string */ + ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media)); - handler = session_media->handler; - if (handler) { - ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n", - session_media->stream_type, + handler = session_media->handler; + if (handler) { + ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n", + ast_codec_media_type2str(session_media->type), + handler->id); + res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream); + if (res >= 0) { + ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n", + ast_codec_media_type2str(session_media->type), handler->id); - res = handler->apply_negotiated_sdp_stream(session, session_media, local, - local->media[i], remote, remote->media[i]); - if (res >= 0) { - ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n", - session_media->stream_type, - handler->id); - return CMP_MATCH; - } return 0; } + return -1; + } - handler_list = ao2_find(sdp_handlers, media, OBJ_KEY); - if (!handler_list) { - ast_debug(1, "No registered SDP handlers for media type '%s'\n", media); + handler_list = ao2_find(sdp_handlers, media, OBJ_KEY); + if (!handler_list) { + ast_debug(1, "No registered SDP handlers for media type '%s'\n", media); + return -1; + } + AST_LIST_TRAVERSE(&handler_list->list, handler, next) { + if (handler == session_media->handler) { continue; } - AST_LIST_TRAVERSE(&handler_list->list, handler, next) { - if (handler == session_media->handler) { - continue; - } - ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n", - session_media->stream_type, + ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n", + ast_codec_media_type2str(session_media->type), + handler->id); + res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream); + if (res < 0) { + /* Catastrophic failure. Abort! */ + return -1; + } + if (res > 0) { + ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n", + ast_codec_media_type2str(session_media->type), handler->id); - res = handler->apply_negotiated_sdp_stream(session, session_media, local, - local->media[i], remote, remote->media[i]); - if (res < 0) { - /* Catastrophic failure. Abort! */ - return 0; - } - if (res > 0) { - ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n", - session_media->stream_type, - handler->id); - /* Handled by this handler. Move to the next stream */ - session_media_set_handler(session_media, handler); - return CMP_MATCH; - } + /* Handled by this handler. Move to the next stream */ + session_media_set_handler(session_media, handler); + return 0; } } if (session_media->handler && session_media->handler->stream_stop) { ast_debug(1, "Stopping SDP media stream '%s' as it is not currently negotiated\n", - session_media->stream_type); + ast_codec_media_type2str(session_media->type)); session_media->handler->stream_stop(session_media); } - return CMP_MATCH; + return 0; } static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote) { - RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup); - struct handle_negotiated_sdp_cb callback_data = { - .session = session, - .local = local, - .remote = remote, - }; + int i; + struct ast_stream_topology *topology; - successful = ao2_callback(session->media, OBJ_MULTIPLE, handle_negotiated_sdp_session_media, &callback_data); - if (successful && ao2_iterator_count(successful) == ao2_container_count(session->media)) { - /* Nothing experienced a catastrophic failure */ - ast_queue_frame(session->channel, &ast_null_frame); - return 0; + for (i = 0; i < local->media_count; ++i) { + struct ast_sip_session_media *session_media; + struct ast_stream *stream; + + if (!remote->media[i]) { + continue; + } + + /* If we're handling negotiated streams, then we should already have set + * up session media instances (and Asterisk streams) that correspond to + * the local SDP, and there should be the same number of session medias + * and streams as there are local SDP streams + */ + ast_assert(i < AST_VECTOR_SIZE(&session->pending_media_state->sessions)); + ast_assert(i < ast_stream_topology_get_count(session->pending_media_state->topology)); + + session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i); + stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i); + + /* The stream state will have already been set to removed when either we + * negotiate the incoming SDP stream or when we produce our own local SDP. + * This can occur if an internal thing has requested it to be removed, or if + * we remove it as a result of the stream limit being reached. + */ + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + continue; + } + + if (handle_negotiated_sdp_session_media(session_media, session, local, remote, i, stream)) { + return -1; + } } - return -1; + + /* Apply the pending media state to the channel and make it active */ + ast_channel_lock(session->channel); + + /* Update the topology on the channel to match the accepted one */ + topology = ast_stream_topology_clone(session->pending_media_state->topology); + if (topology) { + ast_channel_set_stream_topology(session->channel, topology); + } + + /* Remove all current file descriptors from the channel */ + for (i = 0; i < AST_VECTOR_SIZE(&session->active_media_state->read_callbacks); ++i) { + ast_channel_internal_fd_clear(session->channel, i + AST_EXTENDED_FDS); + } + + /* Add all the file descriptors from the pending media state */ + for (i = 0; i < AST_VECTOR_SIZE(&session->pending_media_state->read_callbacks); ++i) { + struct ast_sip_session_media_read_callback_state *callback_state = AST_VECTOR_GET_ADDR(&session->pending_media_state->read_callbacks, i); + + ast_channel_internal_fd_set(session->channel, i + AST_EXTENDED_FDS, callback_state->fd); + } + + /* Active and pending flip flop as needed */ + SWAP(session->active_media_state, session->pending_media_state); + ast_sip_session_media_state_reset(session->pending_media_state); + + ast_channel_unlock(session->channel); + + ast_queue_frame(session->channel, &ast_null_frame); + + return 0; } AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement); @@ -570,6 +884,8 @@ struct ast_sip_session_delayed_request { ast_sip_session_response_cb on_response; /*! Whether to generate new SDP */ int generate_new_sdp; + /*! Requested media state for the SDP */ + struct ast_sip_session_media_state *media_state; AST_LIST_ENTRY(ast_sip_session_delayed_request) next; }; @@ -578,7 +894,8 @@ static struct ast_sip_session_delayed_request *delayed_request_alloc( ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, - int generate_new_sdp) + int generate_new_sdp, + struct ast_sip_session_media_state *media_state) { struct ast_sip_session_delayed_request *delay = ast_calloc(1, sizeof(*delay)); @@ -590,9 +907,16 @@ static struct ast_sip_session_delayed_request *delayed_request_alloc( delay->on_sdp_creation = on_sdp_creation; delay->on_response = on_response; delay->generate_new_sdp = generate_new_sdp; + delay->media_state = media_state; return delay; } +static void delayed_request_free(struct ast_sip_session_delayed_request *delay) +{ + ast_sip_session_media_state_free(delay->media_state); + ast_free(delay); +} + static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay) { ast_debug(3, "Endpoint '%s(%s)' sending delayed %s request.\n", @@ -604,12 +928,16 @@ static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_ case DELAYED_METHOD_INVITE: ast_sip_session_refresh(session, delay->on_request_creation, delay->on_sdp_creation, delay->on_response, - AST_SIP_SESSION_REFRESH_METHOD_INVITE, delay->generate_new_sdp); + AST_SIP_SESSION_REFRESH_METHOD_INVITE, delay->generate_new_sdp, delay->media_state); + /* Ownership of media state transitions to ast_sip_session_refresh */ + delay->media_state = NULL; return 0; case DELAYED_METHOD_UPDATE: ast_sip_session_refresh(session, delay->on_request_creation, delay->on_sdp_creation, delay->on_response, - AST_SIP_SESSION_REFRESH_METHOD_UPDATE, delay->generate_new_sdp); + AST_SIP_SESSION_REFRESH_METHOD_UPDATE, delay->generate_new_sdp, delay->media_state); + /* Ownership of media state transitions to ast_sip_session_refresh */ + delay->media_state = NULL; return 0; case DELAYED_METHOD_BYE: ast_sip_session_terminate(session, 0); @@ -644,7 +972,7 @@ static int invite_proceeding(void *vsession) case DELAYED_METHOD_UPDATE: AST_LIST_REMOVE_CURRENT(next); res = send_delayed_request(session, delay); - ast_free(delay); + delayed_request_free(delay); found = 1; break; case DELAYED_METHOD_BYE: @@ -698,7 +1026,7 @@ static int invite_terminated(void *vsession) if (found) { AST_LIST_REMOVE_CURRENT(next); res = send_delayed_request(session, delay); - ast_free(delay); + delayed_request_free(delay); break; } } @@ -775,12 +1103,14 @@ static int delay_request(struct ast_sip_session *session, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, int generate_new_sdp, - enum delayed_method method) + enum delayed_method method, + struct ast_sip_session_media_state *media_state) { struct ast_sip_session_delayed_request *delay = delayed_request_alloc(method, - on_request, on_sdp_creation, on_response, generate_new_sdp); + on_request, on_sdp_creation, on_response, generate_new_sdp, media_state); if (!delay) { + ast_sip_session_media_state_free(media_state); return -1; } @@ -881,16 +1211,23 @@ int ast_sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, - enum ast_sip_session_refresh_method method, int generate_new_sdp) + enum ast_sip_session_refresh_method method, int generate_new_sdp, + struct ast_sip_session_media_state *media_state) { pjsip_inv_session *inv_session = session->inv_session; pjmedia_sdp_session *new_sdp = NULL; pjsip_tx_data *tdata; + if (media_state && (!media_state->topology || !generate_new_sdp)) { + ast_sip_session_media_state_free(media_state); + return -1; + } + if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) { /* Don't try to do anything with a hung-up call */ ast_debug(3, "Not sending reinvite to %s because of disconnected state...\n", ast_sorcery_object_get_id(session->endpoint)); + ast_sip_session_media_state_free(media_state); return 0; } @@ -901,7 +1238,8 @@ int ast_sip_session_refresh(struct ast_sip_session *session, return delay_request(session, on_request_creation, on_sdp_creation, on_response, generate_new_sdp, method == AST_SIP_SESSION_REFRESH_METHOD_INVITE - ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE); + ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, + media_state); } if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) { @@ -910,13 +1248,14 @@ int ast_sip_session_refresh(struct ast_sip_session *session, ast_debug(3, "Delay sending reinvite to %s because of outstanding transaction...\n", ast_sorcery_object_get_id(session->endpoint)); return delay_request(session, on_request_creation, on_sdp_creation, - on_response, generate_new_sdp, DELAYED_METHOD_INVITE); + on_response, generate_new_sdp, DELAYED_METHOD_INVITE, media_state); } else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) { /* Initial INVITE transaction failed to progress us to a confirmed state * which means re-invites are not possible */ ast_debug(3, "Not sending reinvite to %s because not in confirmed state...\n", ast_sorcery_object_get_id(session->endpoint)); + ast_sip_session_media_state_free(media_state); return 0; } } @@ -931,33 +1270,130 @@ int ast_sip_session_refresh(struct ast_sip_session *session, return delay_request(session, on_request_creation, on_sdp_creation, on_response, generate_new_sdp, method == AST_SIP_SESSION_REFRESH_METHOD_INVITE - ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE); + ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, media_state); + } + + /* If an explicitly requested media state has been provided use it instead of any pending one */ + if (media_state) { + int index; + int type_streams[AST_MEDIA_TYPE_END] = {0}; + struct ast_stream *stream; + + /* Prune the media state so the number of streams fit within the configured limits - we do it here + * so that the index of the resulting streams in the SDP match. If we simply left the streams out + * of the SDP when producing it we'd be in trouble. We also enforce formats here for media types that + * are configurable on the endpoint. + */ + for (index = 0; index < ast_stream_topology_get_count(media_state->topology); ++index) { + stream = ast_stream_topology_get_stream(media_state->topology, index); + + if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) { + if (index < AST_VECTOR_SIZE(&media_state->sessions)) { + struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index); + + ao2_cleanup(session_media); + AST_VECTOR_REMOVE(&media_state->sessions, index, 1); + } + + ast_stream_topology_del_stream(media_state->topology, index); + + /* A stream has potentially moved into our spot so we need to jump back so we process it */ + index -= 1; + continue; + } + + + /* Enforce the configured allowed codecs on audio and video streams */ + if (ast_stream_get_type(stream) == AST_MEDIA_TYPE_AUDIO || ast_stream_get_type(stream) == AST_MEDIA_TYPE_VIDEO) { + struct ast_format_cap *joint_cap; + + joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!joint_cap) { + ast_sip_session_media_state_free(media_state); + return 0; + } + + ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap); + if (!ast_format_cap_count(joint_cap)) { + ao2_ref(joint_cap, -1); + ast_sip_session_media_state_free(media_state); + return 0; + } + + ast_stream_set_formats(stream, joint_cap); + } + + ++type_streams[ast_stream_get_type(stream)]; + } + + if (session->active_media_state->topology) { + /* SDP is a fun thing. Take for example the fact that streams are never removed. They just become + * declined. To better handle this in the case where something requests a topology change for fewer + * streams than are currently present we fill in the topology to match the current number of streams + * that are active. + */ + for (index = ast_stream_topology_get_count(media_state->topology); + index < ast_stream_topology_get_count(session->active_media_state->topology); ++index) { + struct ast_stream *cloned; + + stream = ast_stream_topology_get_stream(session->active_media_state->topology, index); + ast_assert(stream != NULL); + + cloned = ast_stream_clone(stream, NULL); + if (!cloned) { + ast_sip_session_media_state_free(media_state); + return -1; + } + + ast_stream_set_state(cloned, AST_STREAM_STATE_REMOVED); + ast_stream_topology_append_stream(media_state->topology, cloned); + } + + /* If the resulting media state matches the existing active state don't bother doing a session refresh */ + if (ast_stream_topology_equal(session->active_media_state->topology, media_state->topology)) { + ast_sip_session_media_state_free(media_state); + return 0; + } + } + + ast_sip_session_media_state_free(session->pending_media_state); + session->pending_media_state = media_state; } new_sdp = generate_session_refresh_sdp(session); if (!new_sdp) { ast_log(LOG_ERROR, "Failed to generate session refresh SDP. Not sending session refresh\n"); + ast_sip_session_media_state_reset(session->pending_media_state); return -1; } if (on_sdp_creation) { if (on_sdp_creation(session, new_sdp)) { + ast_sip_session_media_state_reset(session->pending_media_state); return -1; } } } - if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) { if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) { ast_log(LOG_WARNING, "Failed to create reinvite properly.\n"); + if (generate_new_sdp) { + ast_sip_session_media_state_reset(session->pending_media_state); + } return -1; } } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) { ast_log(LOG_WARNING, "Failed to create UPDATE properly.\n"); + if (generate_new_sdp) { + ast_sip_session_media_state_reset(session->pending_media_state); + } return -1; } if (on_request_creation) { if (on_request_creation(session, tdata)) { + if (generate_new_sdp) { + ast_sip_session_media_state_reset(session->pending_media_state); + } return -1; } } @@ -992,22 +1428,40 @@ static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_ { int i; + if (!session->pending_media_state->topology) { + session->pending_media_state->topology = ast_stream_topology_alloc(); + if (!session->pending_media_state->topology) { + return -1; + } + } + for (i = 0; i < sdp->media_count; ++i) { /* See if there are registered handlers for this media stream type */ char media[20]; struct ast_sip_session_sdp_handler *handler; RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup); + struct ast_stream *stream; + enum ast_media_type type; + struct ast_sip_session_media *session_media = NULL; enum ast_sip_session_sdp_stream_defer res; /* We need a null-terminated version of the media string */ ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media)); - session_media = ao2_find(session->media, media, OBJ_KEY); + type = ast_media_type_from_str(media); + stream = ast_stream_alloc(ast_codec_media_type2str(type), type); + if (!stream) { + return -1; + } + + /* As this is only called on an incoming SDP offer before processing it is not possible + * for streams and their media sessions to exist. + */ + ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream); + + session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i); if (!session_media) { - /* if the session_media doesn't exist, there weren't - * any handlers at the time of its creation */ - continue; + return -1; } if (session_media->handler) { @@ -1269,29 +1723,6 @@ static int datastore_cmp(void *obj, void *arg, int flags) return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP; } -static void session_media_dtor(void *obj) -{ - struct ast_sip_session_media *session_media = obj; - struct sdp_handler_list *handler_list; - /* It is possible for SDP handlers to allocate memory on a session_media but - * not end up getting set as the handler for this session_media. This traversal - * ensures that all memory allocated by SDP handlers on the session_media is - * cleared (as well as file descriptors, etc.). - */ - handler_list = ao2_find(sdp_handlers, session_media->stream_type, OBJ_KEY); - if (handler_list) { - struct ast_sip_session_sdp_handler *handler; - - AST_LIST_TRAVERSE(&handler_list->list, handler, next) { - handler->stream_destroy(session_media); - } - } - ao2_cleanup(handler_list); - if (session_media->srtp) { - ast_sdp_srtp_destroy(session_media->srtp); - } -} - static void session_destructor(void *obj) { struct ast_sip_session *session = obj; @@ -1320,17 +1751,17 @@ static void session_destructor(void *obj) ast_taskprocessor_unreference(session->serializer); ao2_cleanup(session->datastores); - ao2_cleanup(session->media); + ast_sip_session_media_state_free(session->active_media_state); + ast_sip_session_media_state_free(session->pending_media_state); AST_LIST_HEAD_DESTROY(&session->supplements); while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) { - ast_free(delay); + delayed_request_free(delay); } ast_party_id_free(&session->id); ao2_cleanup(session->endpoint); ao2_cleanup(session->aor); ao2_cleanup(session->contact); - ao2_cleanup(session->req_caps); ao2_cleanup(session->direct_media_cap); ast_dsp_free(session->dsp); @@ -1357,25 +1788,6 @@ static int add_supplements(struct ast_sip_session *session) return 0; } -static int add_session_media(void *obj, void *arg, int flags) -{ - struct sdp_handler_list *handler_list = obj; - struct ast_sip_session *session = arg; - RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup); - - session_media = ao2_alloc(sizeof(*session_media) + strlen(handler_list->stream_type), session_media_dtor); - if (!session_media) { - return CMP_STOP; - } - session_media->encryption = session->endpoint->media.rtp.encryption; - session_media->keepalive_sched_id = -1; - session_media->timeout_sched_id = -1; - /* Safe use of strcpy */ - strcpy(session_media->stream_type, handler_list->stream_type); - ao2_link(session->media, session_media); - return 0; -} - /*! \brief Destructor for SIP channel */ static void sip_channel_destroy(void *obj) { @@ -1422,14 +1834,18 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, if (!session->direct_media_cap) { return NULL; } - session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!session->req_caps) { - return NULL; - } session->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp); if (!session->datastores) { return NULL; } + session->active_media_state = ast_sip_session_media_state_alloc(); + if (!session->active_media_state) { + return NULL; + } + session->pending_media_state = ast_sip_session_media_state_alloc(); + if (!session->pending_media_state) { + return NULL; + } if (endpoint->dtmf == AST_SIP_DTMF_INBAND || endpoint->dtmf == AST_SIP_DTMF_AUTO) { dsp_features |= DSP_FEATURE_DIGIT_DETECT; @@ -1448,13 +1864,6 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, session->endpoint = ao2_bump(endpoint); - session->media = ao2_container_alloc(MEDIA_BUCKETS, session_media_hash, session_media_cmp); - if (!session->media) { - return NULL; - } - /* fill session->media with available types */ - ao2_callback(sdp_handlers, OBJ_NODATA, add_session_media, session); - if (rdata) { /* * We must continue using the serializer that the original @@ -1704,7 +2113,7 @@ static int setup_outbound_invite_auth(pjsip_dialog *dlg) struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, - struct ast_format_cap *req_caps) + struct ast_stream_topology *req_topology) { const char *uri = NULL; RAII_VAR(struct ast_sip_aor *, found_aor, NULL, ao2_cleanup); @@ -1768,22 +2177,68 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint session->aor = ao2_bump(found_aor); ast_party_id_copy(&session->id, &endpoint->id.self); - if (ast_format_cap_count(req_caps)) { - /* get joint caps between req_caps and endpoint caps */ - struct ast_format_cap *joint_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (ast_stream_topology_get_count(req_topology) > 0) { + /* get joint caps between req_topology and endpoint topology */ + int i; + + for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) { + struct ast_stream *req_stream; + struct ast_format_cap *req_cap; + struct ast_format_cap *joint_cap; + struct ast_stream *clone_stream; + + req_stream = ast_stream_topology_get_stream(req_topology, i); + + if (ast_stream_get_state(req_stream) == AST_STREAM_STATE_REMOVED) { + continue; + } + + req_cap = ast_stream_get_formats(req_stream); - ast_format_cap_get_compatible(req_caps, endpoint->media.codecs, joint_caps); + joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!joint_cap) { + continue; + } + + ast_format_cap_get_compatible(req_cap, endpoint->media.codecs, joint_cap); + if (!ast_format_cap_count(joint_cap)) { + ao2_ref(joint_cap, -1); + continue; + } + + clone_stream = ast_stream_clone(req_stream, NULL); + if (!clone_stream) { + ao2_ref(joint_cap, -1); + continue; + } + + ast_stream_set_formats(clone_stream, joint_cap); + ao2_ref(joint_cap, -1); + + if (!session->pending_media_state->topology) { + session->pending_media_state->topology = ast_stream_topology_alloc(); + if (!session->pending_media_state->topology) { + pjsip_inv_terminate(inv_session, 500, PJ_FALSE); + ao2_ref(session, -1); + return NULL; + } + } - /* if joint caps */ - if (ast_format_cap_count(joint_caps)) { - /* copy endpoint caps into session->req_caps */ - ast_format_cap_append_from_cap(session->req_caps, - endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); - /* replace instances of joint caps equivalents in session->req_caps */ - ast_format_cap_replace_from_cap(session->req_caps, joint_caps, - AST_MEDIA_TYPE_UNKNOWN); + if (ast_stream_topology_append_stream(session->pending_media_state->topology, clone_stream) < 0) { + ast_stream_free(clone_stream); + continue; + } + } + } + + if (!session->pending_media_state->topology) { + /* Use the configured topology on the endpoint as the pending one */ + session->pending_media_state->topology = ast_stream_topology_clone(endpoint->media.topology); + if (!session->pending_media_state->topology) { + pjsip_inv_terminate(inv_session, 500, PJ_FALSE); + ao2_ref(session, -1); + return NULL; } - ao2_cleanup(joint_caps); } if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) { @@ -1847,7 +2302,7 @@ void ast_sip_session_terminate(struct ast_sip_session *session, int response) /* If this is delayed the only thing that will happen is a BYE request so we don't * actually need to store the response code for when it happens. */ - delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE); + delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE, NULL); break; } /* Fall through */ @@ -1858,7 +2313,7 @@ void ast_sip_session_terminate(struct ast_sip_session *session, int response) /* Flush any delayed requests so they cannot overlap this transaction. */ while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) { - ast_free(delay); + delayed_request_free(delay); } if (packet->msg->type == PJSIP_RESPONSE_MSG) { @@ -2387,7 +2842,7 @@ static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session ast_debug(3, "Endpoint '%s(%s)' re-INVITE collision.\n", ast_sorcery_object_get_id(session->endpoint), session->channel ? ast_channel_name(session->channel) : ""); - if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE)) { + if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, NULL)) { return; } if (pj_timer_entry_running(&session->rescheduled_reinvite)) { @@ -2944,27 +3399,27 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } } -static int add_sdp_streams(void *obj, void *arg, void *data, int flags) +static int add_sdp_streams(struct ast_sip_session_media *session_media, + struct ast_sip_session *session, pjmedia_sdp_session *answer, + const struct pjmedia_sdp_session *remote, + struct ast_stream *stream) { - struct ast_sip_session_media *session_media = obj; - pjmedia_sdp_session *answer = arg; - struct ast_sip_session *session = data; struct ast_sip_session_sdp_handler *handler = session_media->handler; RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup); int res; if (handler) { /* if an already assigned handler reports a catastrophic error, fail */ - res = handler->create_outgoing_sdp_stream(session, session_media, answer); + res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream); if (res < 0) { - return 0; + return -1; } - return CMP_MATCH; + return 0; } - handler_list = ao2_find(sdp_handlers, session_media->stream_type, OBJ_KEY); + handler_list = ao2_find(sdp_handlers, ast_codec_media_type2str(session_media->type), OBJ_KEY); if (!handler_list) { - return CMP_MATCH; + return 0; } /* no handler for this stream type and we have a list to search */ @@ -2972,29 +3427,30 @@ static int add_sdp_streams(void *obj, void *arg, void *data, int flags) if (handler == session_media->handler) { continue; } - res = handler->create_outgoing_sdp_stream(session, session_media, answer); + res = handler->create_outgoing_sdp_stream(session, session_media, answer, remote, stream); if (res < 0) { /* catastrophic error */ - return 0; + return -1; } if (res > 0) { /* Handled by this handler. Move to the next stream */ session_media_set_handler(session_media, handler); - return CMP_MATCH; + return 0; } } /* streams that weren't handled won't be included in generated outbound SDP */ - return CMP_MATCH; + return 0; } static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer) { - RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup); static const pj_str_t STR_IN = { "IN", 2 }; static const pj_str_t STR_IP4 = { "IP4", 3 }; static const pj_str_t STR_IP6 = { "IP6", 3 }; pjmedia_sdp_session *local; + int i; + int stream; if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { ast_log(LOG_ERROR, "Failed to create session SDP. Session has been already disconnected\n"); @@ -3015,47 +3471,81 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru pj_strdup2(inv->pool_prov, &local->origin.user, session->endpoint->media.sdpowner); pj_strdup2(inv->pool_prov, &local->name, session->endpoint->media.sdpsession); - /* Now let the handlers add streams of various types, pjmedia will automatically reorder the media streams for us */ - successful = ao2_callback_data(session->media, OBJ_MULTIPLE, add_sdp_streams, local, session); - if (!successful || ao2_iterator_count(successful) != ao2_container_count(session->media)) { - /* Something experienced a catastrophic failure */ - return NULL; + if (!session->pending_media_state->topology || !ast_stream_topology_get_count(session->pending_media_state->topology)) { + /* We've encountered a situation where we have been told to create a local SDP but noone has given us any indication + * of what kind of stream topology they would like. As a fallback we use the topology from the configured endpoint. + */ + ast_stream_topology_free(session->pending_media_state->topology); + session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + if (!session->pending_media_state->topology) { + return NULL; + } } - /* Use the connection details of the first media stream if possible for SDP level */ - if (local->media_count) { - int stream; + for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) { + struct ast_sip_session_media *session_media; + struct ast_stream *stream; - /* Since we are using the first media stream as the SDP level we can get rid of it - * from the stream itself + /* This code does not enforce any maximum stream count limitations as that is done on either + * the handling of an incoming SDP offer or on the handling of a session refresh. */ - local->conn = local->media[0]->conn; - local->media[0]->conn = NULL; - pj_strassign(&local->origin.net_type, &local->conn->net_type); - pj_strassign(&local->origin.addr_type, &local->conn->addr_type); - pj_strassign(&local->origin.addr, &local->conn->addr); - - /* Go through each media stream seeing if the connection details actually differ, - * if not just use SDP level and reduce the SDP size - */ - for (stream = 1; stream < local->media_count; stream++) { + + stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i); + + session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_stream_get_type(stream), i); + if (!session_media) { + return NULL; + } + + if (add_sdp_streams(session_media, session, local, offer, stream)) { + return NULL; + } + + /* Ensure that we never exceed the maximum number of streams PJMEDIA will allow. */ + if (local->media_count == PJMEDIA_MAX_SDP_MEDIA) { + break; + } + } + + /* Use the connection details of an available media if possible for SDP level */ + for (stream = 0; stream < local->media_count; stream++) { + if (!local->media[stream]->conn) { + continue; + } + + if (local->conn) { if (!pj_strcmp(&local->conn->net_type, &local->media[stream]->conn->net_type) && !pj_strcmp(&local->conn->addr_type, &local->media[stream]->conn->addr_type) && !pj_strcmp(&local->conn->addr, &local->media[stream]->conn->addr)) { local->media[stream]->conn = NULL; } + continue; } - } else { - local->origin.net_type = STR_IN; - local->origin.addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4; + + /* This stream's connection info will serve as the connection details for SDP level */ + local->conn = local->media[stream]->conn; + local->media[stream]->conn = NULL; + + continue; + } + + /* If no SDP level connection details are present then create some */ + if (!local->conn) { + local->conn = pj_pool_zalloc(inv->pool_prov, sizeof(struct pjmedia_sdp_conn)); + local->conn->net_type = STR_IN; + local->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4; if (!ast_strlen_zero(session->endpoint->media.address)) { - pj_strdup2(inv->pool_prov, &local->origin.addr, session->endpoint->media.address); + pj_strdup2(inv->pool_prov, &local->conn->addr, session->endpoint->media.address); } else { - pj_strdup2(inv->pool_prov, &local->origin.addr, ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET())); + pj_strdup2(inv->pool_prov, &local->conn->addr, ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET())); } } + pj_strassign(&local->origin.net_type, &local->conn->net_type); + pj_strassign(&local->origin.addr_type, &local->conn->addr_type); + pj_strassign(&local->origin.addr, &local->conn->addr); + return local; } diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in index fdfc5fb4724..b7bd21b893d 100644 --- a/res/res_pjsip_session.exports.in +++ b/res/res_pjsip_session.exports.in @@ -1,27 +1,7 @@ { global: - LINKER_SYMBOL_PREFIXast_sip_session_terminate; - LINKER_SYMBOL_PREFIXast_sip_session_defer_termination; - LINKER_SYMBOL_PREFIXast_sip_session_defer_termination_cancel; - LINKER_SYMBOL_PREFIXast_sip_session_end_if_deferred; - LINKER_SYMBOL_PREFIXast_sip_session_register_sdp_handler; - LINKER_SYMBOL_PREFIXast_sip_session_unregister_sdp_handler; - LINKER_SYMBOL_PREFIXast_sip_session_register_supplement; - LINKER_SYMBOL_PREFIXast_sip_session_unregister_supplement; - LINKER_SYMBOL_PREFIXast_sip_session_alloc_datastore; - LINKER_SYMBOL_PREFIXast_sip_session_add_datastore; - LINKER_SYMBOL_PREFIXast_sip_session_get_datastore; - LINKER_SYMBOL_PREFIXast_sip_session_remove_datastore; - LINKER_SYMBOL_PREFIXast_sip_session_get_identity; - LINKER_SYMBOL_PREFIXast_sip_session_refresh; - LINKER_SYMBOL_PREFIXast_sip_session_send_response; - LINKER_SYMBOL_PREFIXast_sip_session_send_request; - LINKER_SYMBOL_PREFIXast_sip_session_create_invite; - LINKER_SYMBOL_PREFIXast_sip_session_create_outgoing; - LINKER_SYMBOL_PREFIXast_sip_session_suspend; - LINKER_SYMBOL_PREFIXast_sip_session_unsuspend; + LINKER_SYMBOL_PREFIXast_sip_session_*; LINKER_SYMBOL_PREFIXast_sip_dialog_get_session; - LINKER_SYMBOL_PREFIXast_sip_session_resume_reinvite; LINKER_SYMBOL_PREFIXast_sip_channel_pvt_alloc; local: *; diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 6019412b00f..a032bb12fb4 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -43,6 +43,8 @@ #include "asterisk/netsock2.h" #include "asterisk/channel.h" #include "asterisk/acl.h" +#include "asterisk/stream.h" +#include "asterisk/format_cache.h" #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_session.h" @@ -63,11 +65,16 @@ struct t38_state { struct ast_control_t38_parameters their_parms; /*! \brief Timer entry for automatically rejecting an inbound re-invite */ pj_timer_entry timer; + /*! Preserved media state for when T.38 ends */ + struct ast_sip_session_media_state *media_state; }; /*! \brief Destructor for T.38 state information */ static void t38_state_destroy(void *obj) { + struct t38_state *state = obj; + + ast_sip_session_media_state_free(state->media_state); ast_free(obj); } @@ -195,7 +202,7 @@ static int t38_automatic_reject(void *obj) { RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup); RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup); - RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(session->media, "image", OBJ_KEY), ao2_cleanup); + struct ast_sip_session_media *session_media; if (!datastore) { return 0; @@ -204,6 +211,7 @@ static int t38_automatic_reject(void *obj) ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n", session->channel ? ast_channel_name(session->channel) : ""); + session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; t38_change_state(session, session_media, datastore->data, T38_REJECTED); ast_sip_session_resume_reinvite(session); @@ -259,7 +267,6 @@ static int t38_initialize_session(struct ast_sip_session *session, struct ast_si return -1; } - ast_channel_set_fd(session->channel, 5, ast_udptl_fd(session_media->udptl)); ast_udptl_set_error_correction_scheme(session_media->udptl, session->endpoint->media.t38.error_correction); ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat); ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->media.t38.maxdatagram); @@ -271,19 +278,15 @@ static int t38_initialize_session(struct ast_sip_session *session, struct ast_si /*! \brief Callback for when T.38 reinvite SDP is created */ static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp) { - int stream; - - /* Move the image media stream to the front and have it as the only stream, pjmedia will fill in - * dummy streams for the rest - */ - for (stream = 0; stream < sdp->media_count; ++stream) { - if (!pj_strcmp2(&sdp->media[stream]->desc.media, "image")) { - sdp->media[0] = sdp->media[stream]; - sdp->media_count = 1; - break; - } + struct t38_state *state; + + state = t38_state_get_or_alloc(session); + if (!state) { + return -1; } + state->media_state = ast_sip_session_media_state_clone(session->active_media_state); + return 0; } @@ -292,34 +295,109 @@ static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_da { struct pjsip_status_line status = rdata->msg_info.msg->line.status; struct t38_state *state; - RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup); + struct ast_sip_session_media *session_media = NULL; if (status.code == 100) { return 0; } - if (!(state = t38_state_get_or_alloc(session)) || - !(session_media = ao2_find(session->media, "image", OBJ_KEY))) { + state = t38_state_get_or_alloc(session); + if (!state) { ast_log(LOG_WARNING, "Received response to T.38 re-invite on '%s' but state unavailable\n", ast_channel_name(session->channel)); return 0; } - t38_change_state(session, session_media, state, (status.code == 200) ? T38_ENABLED : T38_REJECTED); + if (status.code == 200) { + int index; + + session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; + t38_change_state(session, session_media, state, T38_ENABLED); + + /* Stop all the streams in the stored away active state, they'll go back to being active once + * we reinvite back. + */ + for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) { + struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index); + + if (session_media && session_media->handler && session_media->handler->stream_stop) { + session_media->handler->stream_stop(session_media); + } + } + } else { + session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; + t38_change_state(session, session_media, state, T38_REJECTED); + + /* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */ + ast_sip_session_media_state_free(state->media_state); + state->media_state = NULL; + ast_sip_session_media_state_reset(session->pending_media_state); + } return 0; } +/*! \brief Helper function which creates a media state for strictly T.38 */ +static struct ast_sip_session_media_state *t38_create_media_state(struct ast_sip_session *session) +{ + struct ast_sip_session_media_state *media_state; + struct ast_stream *stream; + struct ast_format_cap *caps; + struct ast_sip_session_media *session_media; + + media_state = ast_sip_session_media_state_alloc(); + if (!media_state) { + return NULL; + } + + media_state->topology = ast_stream_topology_alloc(); + if (!media_state->topology) { + ast_sip_session_media_state_free(media_state); + return NULL; + } + + stream = ast_stream_alloc("t38", AST_MEDIA_TYPE_IMAGE); + if (!stream) { + ast_sip_session_media_state_free(media_state); + return NULL; + } + + ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV); + ast_stream_topology_set_stream(media_state->topology, 0, stream); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_sip_session_media_state_free(media_state); + return NULL; + } + + ast_format_cap_append(caps, ast_format_t38, 0); + ast_stream_set_formats(stream, caps); + ao2_ref(caps, -1); + + session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0); + if (!session_media) { + ast_sip_session_media_state_free(media_state); + return NULL; + } + + if (t38_initialize_session(session, session_media)) { + ast_sip_session_media_state_free(media_state); + return NULL; + } + + return media_state; +} + /*! \brief Task for reacting to T.38 control frame */ static int t38_interpret_parameters(void *obj) { RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup); const struct ast_control_t38_parameters *parameters = data->frame->data.ptr; struct t38_state *state = t38_state_get_or_alloc(data->session); - RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(data->session->media, "image", OBJ_KEY), ao2_cleanup); + struct ast_sip_session_media *session_media = NULL; - /* Without session media or state we can't interpret parameters */ - if (!session_media || !state) { + if (!state) { return 0; } @@ -329,12 +407,15 @@ static int t38_interpret_parameters(void *obj) /* Negotiation can not take place without a valid max_ifp value. */ if (!parameters->max_ifp) { if (data->session->t38state == T38_PEER_REINVITE) { + session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; t38_change_state(data->session, session_media, state, T38_REJECTED); ast_sip_session_resume_reinvite(data->session); } else if (data->session->t38state == T38_ENABLED) { + session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; t38_change_state(data->session, session_media, state, T38_DISABLED); ast_sip_session_refresh(data->session, NULL, NULL, NULL, - AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1); + AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state); + state->media_state = NULL; } break; } else if (data->session->t38state == T38_PEER_REINVITE) { @@ -353,37 +434,46 @@ static int t38_interpret_parameters(void *obj) } state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version); state->our_parms.rate_management = state->their_parms.rate_management; + session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp); t38_change_state(data->session, session_media, state, T38_ENABLED); ast_sip_session_resume_reinvite(data->session); } else if ((data->session->t38state != T38_ENABLED) || ((data->session->t38state == T38_ENABLED) && (parameters->request_response == AST_T38_REQUEST_NEGOTIATE))) { - if (t38_initialize_session(data->session, session_media)) { + struct ast_sip_session_media_state *media_state; + + media_state = t38_create_media_state(data->session); + if (!media_state) { break; } state->our_parms = *parameters; + session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE]; ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp); t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE); ast_sip_session_refresh(data->session, NULL, t38_reinvite_sdp_cb, t38_reinvite_response_cb, - AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1); + AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, media_state); } break; case AST_T38_TERMINATED: case AST_T38_REFUSED: case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */ if (data->session->t38state == T38_PEER_REINVITE) { + session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; t38_change_state(data->session, session_media, state, T38_REJECTED); ast_sip_session_resume_reinvite(data->session); } else if (data->session->t38state == T38_ENABLED) { + session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; t38_change_state(data->session, session_media, state, T38_DISABLED); - ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1); + ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state); + state->media_state = NULL; } break; case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */ struct ast_control_t38_parameters parameters = state->their_parms; if (data->session->t38state == T38_PEER_REINVITE) { + session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl); parameters.request_response = AST_T38_REQUEST_NEGOTIATE; ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); @@ -397,67 +487,27 @@ static int t38_interpret_parameters(void *obj) return 0; } -/*! \brief Frame hook callback for writing */ -static struct ast_frame *t38_framehook_write(struct ast_channel *chan, - struct ast_sip_session *session, struct ast_frame *f) +/*! \brief Frame hook callback for T.38 related stuff */ +static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f, + enum ast_framehook_event event, void *data) { + struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); + + if (event != AST_FRAMEHOOK_EVENT_WRITE) { + return f; + } + if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS && - session->endpoint->media.t38.enabled) { - struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(session, f); + channel->session->endpoint->media.t38.enabled) { + struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(channel->session, f); if (!data) { return f; } - if (ast_sip_push_task(session->serializer, t38_interpret_parameters, data)) { + if (ast_sip_push_task(channel->session->serializer, t38_interpret_parameters, data)) { ao2_ref(data, -1); } - } else if (f->frametype == AST_FRAME_MODEM) { - struct ast_sip_session_media *session_media; - - /* Avoid deadlock between chan and the session->media container lock */ - ast_channel_unlock(chan); - session_media = ao2_find(session->media, "image", OBJ_SEARCH_KEY); - ast_channel_lock(chan); - if (session_media && session_media->udptl) { - ast_udptl_write(session_media->udptl, f); - } - ao2_cleanup(session_media); - } - - return f; -} - -/*! \brief Frame hook callback for reading */ -static struct ast_frame *t38_framehook_read(struct ast_channel *chan, - struct ast_sip_session *session, struct ast_frame *f) -{ - if (ast_channel_fdno(session->channel) == 5) { - struct ast_sip_session_media *session_media; - - /* Avoid deadlock between chan and the session->media container lock */ - ast_channel_unlock(chan); - session_media = ao2_find(session->media, "image", OBJ_SEARCH_KEY); - ast_channel_lock(chan); - if (session_media && session_media->udptl) { - f = ast_udptl_read(session_media->udptl); - } - ao2_cleanup(session_media); - } - - return f; -} - -/*! \brief Frame hook callback for T.38 related stuff */ -static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f, - enum ast_framehook_event event, void *data) -{ - struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - - if (event == AST_FRAMEHOOK_EVENT_READ) { - f = t38_framehook_read(chan, channel->session, f); - } else if (event == AST_FRAMEHOOK_EVENT_WRITE) { - f = t38_framehook_write(chan, channel->session, f); } return f; @@ -476,7 +526,7 @@ static void t38_masq(void *data, int framehook_id, static int t38_consume(void *data, enum ast_frame_type type) { - return 0; + return (type == AST_FRAME_CONTROL) ? 1 : 0; } static const struct ast_datastore_info t38_framehook_datastore = { @@ -676,11 +726,13 @@ static enum ast_sip_session_sdp_stream_defer defer_incoming_sdp_stream( } /*! \brief Function which negotiates an incoming media stream */ -static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, - const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream) +static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, + int index, struct ast_stream *asterisk_stream) { struct t38_state *state; char host[NI_MAXHOST]; + pjmedia_sdp_media *stream = sdp->media[index]; RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); if (!session->endpoint->media.t38.enabled) { @@ -720,7 +772,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct /*! \brief Function which creates an outgoing stream */ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, - struct pjmedia_sdp_session *sdp) + struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream) { pj_pool_t *pool = session->inv_session->pool_prov; static const pj_str_t STR_IN = { "IN", 2 }; @@ -758,7 +810,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as return -1; } - media->desc.media = pj_str(session_media->stream_type); + pj_strdup2(pool, &media->desc.media, ast_codec_media_type2str(session_media->type)); media->desc.transport = STR_UDPTL; if (ast_strlen_zero(session->endpoint->media.address)) { @@ -826,12 +878,31 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as return 1; } +static struct ast_frame *media_session_udptl_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media) +{ + if (!session_media->udptl) { + return &ast_null_frame; + } + + return ast_udptl_read(session_media->udptl); +} + +static int media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame) +{ + if (!session_media->udptl) { + return 0; + } + + return ast_udptl_write(session_media->udptl, frame); +} + /*! \brief Function which applies a negotiated stream */ -static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, - const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream, - const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream) +static int apply_negotiated_sdp_stream(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, + const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream) { RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); + pjmedia_sdp_media *remote_stream = remote->media[index]; char host[NI_MAXHOST]; struct t38_state *state; @@ -858,6 +929,10 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a t38_interpret_sdp(state, session, session_media, remote_stream); + ast_sip_session_media_set_write_callback(session, session_media, media_session_udptl_write_callback); + ast_sip_session_media_add_read_callback(session, session_media, ast_udptl_fd(session_media->udptl), + media_session_udptl_read_callback); + return 0; } From ab7d99e62d1d1cdc0bcf69bb396bcf2f5decc514 Mon Sep 17 00:00:00 2001 From: Niklas Larsson Date: Thu, 29 Jun 2017 10:47:41 +0200 Subject: [PATCH 1343/1578] app_queue: Add priority to AMI QueueStatus Add priority to callers in AMI QueueStatus response ASTERISK-27092 #close Change-Id: I8d1f737a72c7c38f4cfe1a4ee3ecc0a4f85bd199 --- apps/app_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index f158a4caa81..aa0423860b7 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -9949,6 +9949,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) "ConnectedLineNum: %s\r\n" "ConnectedLineName: %s\r\n" "Wait: %ld\r\n" + "Priority: %d\r\n" "%s" "\r\n", q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan), @@ -9956,7 +9957,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"), S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"), S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"), - (long) (now - qe->start), idText); + (long) (now - qe->start), qe->prio, idText); ++q_items; } } From fb7247c57c532f2d5e174ef12d6f82e576d65d10 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Thu, 15 Jun 2017 10:12:41 +0200 Subject: [PATCH 1344/1578] res_pjsip: Add DTMF INFO Failback mode The existing auto dtmf mode reverts to inband if 4733 fails to be negotiated. This patch adds a new mode auto_info which will switch to INFO instead of inband if 4733 is not available. ASTERISK-27066 #close Change-Id: Id185b11e84afd9191a2f269e8443019047765e91 --- CHANGES | 4 ++ channels/chan_pjsip.c | 37 +++++++++--- ...08c_add_auto_info_to_endpoint_dtmf_mode.py | 57 +++++++++++++++++++ include/asterisk/res_pjsip.h | 2 + res/res_pjsip.c | 3 + res/res_pjsip/pjsip_configuration.c | 7 ++- res/res_pjsip_sdp_rtp.c | 19 +++++-- 7 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py diff --git a/CHANGES b/CHANGES index 9cd579b6565..68e4599ed90 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,10 @@ res_pjsip whether to notify dialog-info state 'early' or 'confirmed' on Ringing when already INUSE. + * The endpoint option 'dtmf_mode' has a new option 'auto_dtmf' added. This + mode works similar to 'auto' except uses DTMF INFO as fallback instead of + INBAND. + res_agi ------------------ * The EAGI() application will now look for a dialplan variable named diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 7cab428731e..0e4468cdcd9 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1960,6 +1960,12 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit) return -1; } + ast_rtp_instance_dtmf_begin(media->rtp, digit); + break; + case AST_SIP_DTMF_AUTO_INFO: + if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_NONE)) { + return -1; + } ast_rtp_instance_dtmf_begin(media->rtp, digit); break; case AST_SIP_DTMF_NONE: @@ -2063,6 +2069,20 @@ static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned in media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; switch (channel->session->endpoint->dtmf) { + case AST_SIP_DTMF_AUTO_INFO: + { + if (!media || !media->rtp) { + return -1; + } + if (ast_rtp_instance_dtmf_mode_get(media->rtp) != AST_RTP_DTMF_MODE_NONE) { + ast_debug(3, "Told to send end of digit on Auto-Info channel %s RFC4733 negotiated so using it.\n", ast_channel_name(ast)); + ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration); + break; + } + /* If RFC_4733 was not negotiated, fail through to the DTMF_INFO processing */ + ast_debug(3, "Told to send end of digit on Auto-Info channel %s RFC4733 NOT negotiated using INFO instead.\n", ast_channel_name(ast)); + } + case AST_SIP_DTMF_INFO: { struct info_dtmf_data *dtmf_data = info_dtmf_data_alloc(channel->session, digit, duration); @@ -2095,14 +2115,15 @@ static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned in } ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration); - break; - case AST_SIP_DTMF_AUTO: - if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND)) { - return -1; - } - - ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration); - break; + break; + case AST_SIP_DTMF_AUTO: + if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND)) { + return -1; + } + + ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration); + break; + case AST_SIP_DTMF_NONE: break; diff --git a/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py b/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py new file mode 100644 index 00000000000..dbc8ce9c4d0 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py @@ -0,0 +1,57 @@ +"""Add auto_info to endpoint dtmf_mode + +Revision ID: 164abbd708c +Revises: 86bb1efa278d +Create Date: 2017-06-19 13:55:15.354706 + +""" + +# revision identifiers, used by Alembic. +revision = '164abbd708c' +down_revision = '86bb1efa278d' + +from alembic import op +import sqlalchemy as sa + +OLD_ENUM = ['rfc4733', 'inband', 'info', 'auto'] +NEW_ENUM = ['rfc4733', 'inband', 'info', 'auto', 'auto_info'] + +old_type = sa.Enum(*OLD_ENUM, name='pjsip_dtmf_mode_values_v2') +new_type = sa.Enum(*NEW_ENUM, name='pjsip_dtmf_mode_values_v3') + +def upgrade(): + context = op.get_context() + + # Upgrading to this revision WILL clear your directmedia values. + if context.bind.dialect.name != 'postgresql': + op.alter_column('ps_endpoints', 'dtmf_mode', + type_=new_type, + existing_type=old_type) + else: + enum = ENUM('rfc4733', 'inband', 'info', 'auto', 'auto_info', + name='pjsip_dtmf_mode_values_v3') + enum.create(op.get_bind(), checkfirst=False) + + op.execute('ALTER TABLE ps_endpoints ALTER COLUMN dtmf_mode TYPE' + ' pjsip_dtmf_mode_values_v3 USING' + ' dtmf_mode::text::pjsip_dtmf_mode_values_v3') + + ENUM(name="pjsip_dtmf_mode_values_v2").drop(op.get_bind(), checkfirst=False) + +def downgrade(): + context = op.get_context() + + if context.bind.dialect.name != 'postgresql': + op.alter_column('ps_endpoints', 'dtmf_mode', + type_=old_type, + existing_type=new_type) + else: + enum = ENUM('rfc4733', 'inband', 'info', 'auto', + name='pjsip_dtmf_mode_values_v2') + enum.create(op.get_bind(), checkfirst=False) + + op.execute('ALTER TABLE ps_endpoints ALTER COLUMN dtmf_mode TYPE' + ' pjsip_dtmf_mode_values USING' + ' dtmf_mode::text::pjsip_dtmf_mode_values_v2') + + ENUM(name="pjsip_dtmf_mode_values_v3").drop(op.get_bind(), checkfirst=False) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index f907effcfdd..2cd27d37f33 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -365,6 +365,8 @@ enum ast_sip_dtmf_mode { AST_SIP_DTMF_INFO, /*! Use SIP 4733 if supported by the other side or INBAND if not */ AST_SIP_DTMF_AUTO, + /*! Use SIP 4733 if supported by the other side or INFO DTMF (blech) if not */ + AST_SIP_DTMF_AUTO_INFO, }; /*! diff --git a/res/res_pjsip.c b/res/res_pjsip.c index e717fdb40f9..0cf03437451 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -229,6 +229,9 @@ DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not. + + DTMF is sent as RFC 4733 if the other side supports it or as SIP INFO if not. + diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 56a8419a88b..372b01bc8dd 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -371,6 +371,8 @@ static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, endpoint->dtmf = AST_SIP_DTMF_RFC_4733; } else if (!strcasecmp(var->value, "inband")) { endpoint->dtmf = AST_SIP_DTMF_INBAND; + } else if (!strcasecmp(var->value, "auto_info")) { + endpoint->dtmf = AST_SIP_DTMF_AUTO_INFO; } else if (!strcasecmp(var->value, "info")) { endpoint->dtmf = AST_SIP_DTMF_INFO; } else if (!strcasecmp(var->value, "auto")) { @@ -395,8 +397,11 @@ static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf) *buf = "inband"; break; case AST_SIP_DTMF_INFO : *buf = "info"; break; - case AST_SIP_DTMF_AUTO : + case AST_SIP_DTMF_AUTO : *buf = "auto"; break; + case AST_SIP_DTMF_AUTO_INFO : + *buf = "auto_info"; + break; default: *buf = "none"; } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 03fef40cf4b..a4913086820 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -207,7 +207,7 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me ice->stop(session_media->rtp); } - if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) { + if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833); ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_DTMF, 1); } else if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) { @@ -230,7 +230,7 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me } static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs, - struct ast_sip_session_media *session_media) + struct ast_sip_session_media *session_media) { pjmedia_sdp_attr *attr; pjmedia_sdp_rtpmap *rtpmap; @@ -296,6 +296,16 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp if (!tel_event && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND); } + + if (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) { + if (tel_event) { + ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833); + } else { + ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_NONE); + } + } + + /* Get the packetization, if it exists */ if ((attr = pjmedia_sdp_media_find_attr2(stream, "ptime", NULL))) { unsigned long framing = pj_strtoul(pj_strltrim(&attr->value)); @@ -404,7 +414,8 @@ static int set_caps(struct ast_sip_session *session, ast_set_read_format(session->channel, ast_channel_readformat(session->channel)); ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); } - if ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) + + if ( ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) || (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) ) && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833) && (session->dsp)) { dsp_features = ast_dsp_get_features(session->dsp); @@ -1136,7 +1147,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as pj_str_t stmp; pjmedia_sdp_attr *attr; int index = 0; - int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) ? AST_RTP_DTMF : 0; + int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) ? AST_RTP_DTMF : 0; int min_packet_size = 0, max_packet_size = 0; int rtp_code; RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); From c0c99c7618f480656b2c2436b31ddcb6e3d9db95 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 29 Jun 2017 13:50:14 -0600 Subject: [PATCH 1345/1578] chan_pjsip: Fix ability to send UPDATE on COLP When connected_line_method is "invite", we're supposed to determine if the client can support UPDATE and if it can, send UPDATE instead of INVITE to avoid the SDP renegotiation. Not only was pjproject not setting the PJSIP_INV_SUPPORT_UPDATE flag, we were testing that invite_tsx wasn't NULL which isn't always the case. * Updated chan_pjsip/update_connected_line_information to drop the requirement that invite_tsx isn't NULL. * Submitted patch to pjproject sip_inv.c that sets the PJSIP_INV_SUPPORT_UPDATE flag correctly. * Updated pjsip.conf.sample to clarify what happens when "invite" is specified. ASTERISK-27095 Change-Id: Ic2381b3567b8052c616d96fbe79564c530e81560 --- channels/chan_pjsip.c | 3 +- configs/samples/pjsip.conf.sample | 11 +++++-- res/res_pjsip.c | 11 +++++-- ...PPORT_UPDATE-correctly-in-pjsip_inv_.patch | 29 +++++++++++++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 third-party/pjproject/patches/0070-Set-PJSIP_INV_SUPPORT_UPDATE-correctly-in-pjsip_inv_.patch diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 7cab428731e..247e04d2abe 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1372,8 +1372,7 @@ static int update_connected_line_information(void *data) int generate_new_sdp; method = session->endpoint->id.refresh_method; - if (session->inv_session->invite_tsx - && (session->inv_session->options & PJSIP_INV_SUPPORT_UPDATE)) { + if (session->inv_session->options & PJSIP_INV_SUPPORT_UPDATE) { method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE; } diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index ed5f93e71e3..c05938ea5fd 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -608,8 +608,15 @@ ;direct_media_glare_mitigation=none ; Mitigation of direct media re INVITE ; glare (default: "none") ;direct_media_method=invite ; Direct Media method type (default: "invite") -;connected_line_method=invite ; Connected line method type (default: - ; "invite") +;connected_line_method=invite ; Connected line method type. + ; When set to "invite", check the remote's + ; Allow header and if UPDATE is allowed, send + ; UPDATE instead of INVITE to avoid SDP + ; renegotiation. If UPDATE is not Allowed, + ; send INVITE. + ; If set to "update", send UPDATE regardless + ; of what the remote Allows. + ; (default: "invite") ;direct_media=yes ; Determines whether media may flow directly between ; endpoints (default: "yes") ;disable_direct_media_on_nat=no ; Disable direct media session refreshes when diff --git a/res/res_pjsip.c b/res/res_pjsip.c index e717fdb40f9..9581e7cb55d 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -193,11 +193,18 @@ Method used when updating connected line information. - + + When set to invite, check the remote's Allow header and + if UPDATE is allowed, send UPDATE instead of INVITE to avoid SDP + renegotiation. If UPDATE is not Allowed, send INVITE. + Alias for the invite value. - + + If set to update, send UPDATE regardless of what the remote + Allows. + diff --git a/third-party/pjproject/patches/0070-Set-PJSIP_INV_SUPPORT_UPDATE-correctly-in-pjsip_inv_.patch b/third-party/pjproject/patches/0070-Set-PJSIP_INV_SUPPORT_UPDATE-correctly-in-pjsip_inv_.patch new file mode 100644 index 00000000000..9238e3ec9f1 --- /dev/null +++ b/third-party/pjproject/patches/0070-Set-PJSIP_INV_SUPPORT_UPDATE-correctly-in-pjsip_inv_.patch @@ -0,0 +1,29 @@ +From 1193681959816effa121c4470748d5faa3a59272 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Thu, 29 Jun 2017 13:42:10 -0600 +Subject: [PATCH] Set PJSIP_INV_SUPPORT_UPDATE correctly in + pjsip_inv_verify_request3 + +pjsip_inv_verify_request3 was setting rem_options when UPDATE was +detected in the Allow header. That's just an internal variable and +doesn't go anywhere. It's '*options' that needs to be set. +--- + pjsip/src/pjsip-ua/sip_inv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c +index fbc8ebe..6db7e6b 100644 +--- a/pjsip/src/pjsip-ua/sip_inv.c ++++ b/pjsip/src/pjsip-ua/sip_inv.c +@@ -1237,7 +1237,7 @@ PJ_DEF(pj_status_t) pjsip_inv_verify_request3(pjsip_rx_data *rdata, + + if (i != allow->count) { + /* UPDATE is present in Allow */ +- rem_option |= PJSIP_INV_SUPPORT_UPDATE; ++ *options |= PJSIP_INV_SUPPORT_UPDATE; + } + + } +-- +2.9.4 + From f573e599c0aeeb8807a2f39f636e3920b4aba4cf Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 30 Jun 2017 07:31:52 -0600 Subject: [PATCH 1346/1578] pjproject_bundled: Allow passing configure options to bundled There wasn't any good way to pass options like --host or --build down to the pjproject configure which makes cross-compiling difficult. * Added a new PJPROJECT_CONFIGURE_OPTS environment variable which can be used to pass arbitrary options to pjproject configure. * Automatically set the pjproject configure --host and --build options to match those supplied for the asterisk configure. ASTERISK-27097 #close Reported-by: Kinsey Moore Change-Id: I5fa776e110262851173002a26ffe1172e4c35b2e --- CHANGES | 8 +++++ configure | 47 +++++++++++++++------------- third-party/configure.m4 | 5 ++- third-party/pjproject/Makefile.rules | 5 ++- third-party/pjproject/configure.m4 | 24 ++++++++++++-- 5 files changed, 63 insertions(+), 26 deletions(-) diff --git a/CHANGES b/CHANGES index 97cdda96ea0..02d9ef598c7 100644 --- a/CHANGES +++ b/CHANGES @@ -59,6 +59,14 @@ chan_pjsip from the SDP, unless the remote side sends a different codec and we will switch to match. +Build System +------------------ + * Added a new PJPROJECT_CONFIGURE_OPTS environment variable which can be used + to pass arbitrary options to the bundled pjproject configure. + + * Automatically set the bundled pjproject configure --host and --build + options to match those supplied for the asterisk configure. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.4.0 to Asterisk 14.5.0 ------------ ------------------------------------------------------------------------------ diff --git a/configure b/configure index 361af8884c7..1808633f426 100755 --- a/configure +++ b/configure @@ -1219,6 +1219,7 @@ PJPROJECT_LIB PBX_PJPROJECT PJPROJECT_DIR PJPROJECT_BUNDLED +PJPROJECT_CONFIGURE_OPTS AST_C_COMPILER_FAMILY AST_CLANG_BLOCKS AST_CLANG_BLOCKS_LIBS @@ -1355,7 +1356,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1484,6 +1484,7 @@ CXX CXXFLAGS CCC CXXCPP +PJPROJECT_CONFIGURE_OPTS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR @@ -1539,7 +1540,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1792,15 +1792,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1938,7 +1929,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2091,7 +2082,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -2242,6 +2232,8 @@ Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor + PJPROJECT_CONFIGURE_OPTS + Additional configure options to pass to bundled pjproject PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path @@ -9315,20 +9307,33 @@ $as_echo "configuring" >&6; } as_fn_error $? "cat is required to build bundled pjproject" "$LINENO" 5 fi + + this_host=$(./config.sub $(./config.guess)) + if test "$build" != "$this_host" ; then + PJPROJECT_CONFIGURE_OPTS+=" --build=$build" + fi + if test "$host" != "$this_host" ; then + PJPROJECT_CONFIGURE_OPTS+=" --host=$host" + fi + export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT - ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} configure + export NOISY_BUILD + ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} \ + PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" \ + EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" \ + configure if test $? -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: Unable to configure ${PJPROJECT_DIR}" >&5 $as_echo "$as_me: Unable to configure ${PJPROJECT_DIR}" >&6;} - as_fn_error $? "Run \"${GNU_MAKE} -C ${PJPROJECT_DIR} NOISY_BUILD=yes configure\" to see error details." "$LINENO" 5 + as_fn_error $? "Re-run the ./configure command with 'NOISY_BUILD=yes' appended to see error details." "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for bundled pjproject" >&5 $as_echo_n "checking for bundled pjproject... " >&6; } - PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} echo_cflags) + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" echo_cflags) PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" PBX_PJPROJECT=1 @@ -14910,7 +14915,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14956,7 +14961,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14980,7 +14985,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15025,7 +15030,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15049,7 +15054,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; diff --git a/third-party/configure.m4 b/third-party/configure.m4 index 63544663897..55b72daf9ea 100644 --- a/third-party/configure.m4 +++ b/third-party/configure.m4 @@ -1,4 +1,7 @@ - +# +# If this file is changed, be sure to run ASTTOPDIR/bootstrap.sh +# before committing. +# AC_DEFUN([THIRD_PARTY_CONFIGURE], [ diff --git a/third-party/pjproject/Makefile.rules b/third-party/pjproject/Makefile.rules index 3f99c8a8f1f..acd76621842 100644 --- a/third-party/pjproject/Makefile.rules +++ b/third-party/pjproject/Makefile.rules @@ -1,8 +1,11 @@ PJPROJECT_URL ?= https://raw.githubusercontent.com/asterisk/third-party/master/pjproject/$(PJPROJECT_VERSION) +# PJPROJECT_CONFIGURE_OPTS could come from the command line or could be +# set/modified by configure.m4 if the build or host tuples aren't the same +# as the current build environment (cross-compile). # Even though we're not installing pjproject, we're setting prefix to /opt/pjproject to be safe -PJPROJECT_CONFIG_OPTS = --prefix=/opt/pjproject \ +PJPROJECT_CONFIG_OPTS = $(PJPROJECT_CONFIGURE_OPTS) --prefix=/opt/pjproject \ --disable-speex-codec \ --disable-speex-aec \ --disable-speex-aec \ diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index a5e9fca60c1..709a706a1b0 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -1,3 +1,8 @@ +# +# If this file is changed, be sure to run ASTTOPDIR/bootstrap.sh +# before committing. +# + AC_DEFUN([_PJPROJECT_CONFIGURE], [ if test "${ac_mandatory_list#*PJPROJECT*}" != "$ac_mandatory_list" ; then @@ -35,17 +40,30 @@ AC_DEFUN([_PJPROJECT_CONFIGURE], AC_MSG_ERROR(cat is required to build bundled pjproject) fi + AC_ARG_VAR([PJPROJECT_CONFIGURE_OPTS],[Additional configure options to pass to bundled pjproject]) + this_host=$(./config.sub $(./config.guess)) + if test "$build" != "$this_host" ; then + PJPROJECT_CONFIGURE_OPTS+=" --build=$build" + fi + if test "$host" != "$this_host" ; then + PJPROJECT_CONFIGURE_OPTS+=" --host=$host" + fi + export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT - ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} configure + export NOISY_BUILD + ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} \ + PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" \ + EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" \ + configure if test $? -ne 0 ; then AC_MSG_RESULT(failed) AC_MSG_NOTICE(Unable to configure ${PJPROJECT_DIR}) - AC_MSG_ERROR(Run "${GNU_MAKE} -C ${PJPROJECT_DIR} NOISY_BUILD=yes configure" to see error details.) + AC_MSG_ERROR(Re-run the ./configure command with 'NOISY_BUILD=yes' appended to see error details.) fi AC_MSG_CHECKING(for bundled pjproject) - PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} echo_cflags) + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" echo_cflags) PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" PBX_PJPROJECT=1 From 7df7b8a90c42068d0e9badee974a7efb065c741b Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 29 Jun 2017 14:56:10 -0500 Subject: [PATCH 1347/1578] res_rtp_asterisk: trigger source change control frame when dtls is established There needed to be a way to notify handlers upstream that DTLS had been established. This patch makes it so once DTLS has been estalished a source change control frame is put into the read queue. Any handlers can then watch for that frame and trigger off of it. ASTERISK-27096 #close Change-Id: I27ff344f5a8c691a1890dfe3254a4b1a49e7f4a0 --- res/res_rtp_asterisk.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 600846c8510..dc09166a7a5 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -109,6 +109,8 @@ #define SRTP_MASTER_SALT_LEN 14 #define SRTP_MASTER_LEN (SRTP_MASTER_KEY_LEN + SRTP_MASTER_SALT_LEN) +#define RTP_DTLS_ESTABLISHED -37 + enum strict_rtp_state { STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */ STRICT_RTP_LEARN, /*! Accept next packet as source */ @@ -2477,7 +2479,11 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s /* Any further connections will be existing since this is now established */ dtls->connection = AST_RTP_DTLS_CONNECTION_EXISTING; /* Use the keying material to set up key/salt information */ - res = dtls_srtp_setup(rtp, srtp, instance, rtcp); + if ((res = dtls_srtp_setup(rtp, srtp, instance, rtcp))) { + return res; + } + /* Notify that dtls has been established */ + res = RTP_DTLS_ESTABLISHED; } else { /* Since we've sent additional traffic start the timeout timer for retransmission */ dtls_srtp_start_timeout_timer(instance, rtp, rtcp); @@ -4750,6 +4756,12 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) /* Read in RTCP data from the socket */ if ((res = rtcp_recvfrom(instance, read_area, read_area_size, 0, &addr)) < 0) { + if (res == RTP_DTLS_ESTABLISHED) { + rtp->f.frametype = AST_FRAME_CONTROL; + rtp->f.subclass.integer = AST_CONTROL_SRCCHANGE; + return &rtp->f; + } + ast_assert(errno != EBADF); if (errno != EAGAIN) { ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n", @@ -4947,6 +4959,12 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* Actually read in the data from the socket */ if ((res = rtp_recvfrom(instance, read_area, read_area_size, 0, &addr)) < 0) { + if (res == RTP_DTLS_ESTABLISHED) { + rtp->f.frametype = AST_FRAME_CONTROL; + rtp->f.subclass.integer = AST_CONTROL_SRCCHANGE; + return &rtp->f; + } + ast_assert(errno != EBADF); if (errno != EAGAIN) { ast_log(LOG_WARNING, "RTP Read error: %s. Hanging up.\n", From e7d41050e0672a1cf670957dd0b13a7a1e2131ff Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Thu, 29 Jun 2017 15:06:21 -0500 Subject: [PATCH 1348/1578] app_stream_echo: misc bug fixes Fixed the following bugs: * calls to stream_echo_write had the last two parameters swapped * ast_read should have been ast_read_stream * added a null check on the frame's subclass format This also resets the update_sent flag upon receiving SRRCHANGE control frame. This will then force a video update. ASTERISK-26997 Change-Id: I6ad7c8253559b800800433c52339e7f5aa583566 --- apps/app_stream_echo.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/app_stream_echo.c b/apps/app_stream_echo.c index 79d15917b4a..9695dcc8725 100644 --- a/apps/app_stream_echo.c +++ b/apps/app_stream_echo.c @@ -108,7 +108,6 @@ static int stream_echo_write(struct ast_channel *chan, struct ast_frame *frame, * we simply want to echo it back out onto the same stream number. */ num = ast_channel_is_multistream(chan) ? frame->stream_num : -1; - if (ast_write_stream(chan, num, frame)) { return stream_echo_write_error(chan, frame, num); } @@ -120,7 +119,8 @@ static int stream_echo_write(struct ast_channel *chan, struct ast_frame *frame, * Note, if the channel is not multi-stream capable then one_to_one will * always be true, so it is safe to also not check for that here too. */ - if (one_to_one || ast_format_get_type(frame->subclass.format) != type) { + if (one_to_one || !frame->subclass.format || + ast_format_get_type(frame->subclass.format) != type) { return 0; } @@ -141,7 +141,6 @@ static int stream_echo_write(struct ast_channel *chan, struct ast_frame *frame, for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { struct ast_stream *stream = ast_stream_topology_get_stream(topology, i); - if (num != i && ast_stream_get_type(stream) == type) { if (ast_write_stream(chan, i, frame)) { return stream_echo_write_error(chan, frame, i); @@ -171,7 +170,7 @@ static int stream_echo_perform(struct ast_channel *chan, request_change = 0; } - f = ast_read(chan); + f = ast_read_stream(chan); if (!f) { return -1; } @@ -186,11 +185,13 @@ static int stream_echo_perform(struct ast_channel *chan, if (f->frametype == AST_FRAME_CONTROL) { if (f->subclass.integer == AST_CONTROL_VIDUPDATE && !update_sent) { - if (stream_echo_write(chan, f, one_to_one, type)) { + if (stream_echo_write(chan, f, type, one_to_one)) { ast_frfree(f); return -1; } update_sent = 1; + } else if (f->subclass.integer == AST_CONTROL_SRCCHANGE) { + update_sent = 0; } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_CHANGED) { update_sent = 0; one_to_one = 0; /* Switch writing to one to many */ @@ -200,14 +201,14 @@ static int stream_echo_perform(struct ast_channel *chan, .frametype = AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_VIDUPDATE, }; - stream_echo_write(chan, &frame, one_to_one, type); + stream_echo_write(chan, &frame, type, one_to_one); update_sent = 1; } if (f->frametype != AST_FRAME_CONTROL && f->frametype != AST_FRAME_MODEM && f->frametype != AST_FRAME_NULL && - stream_echo_write(chan, f, one_to_one, type)) { + stream_echo_write(chan, f, type, one_to_one)) { ast_frfree(f); return -1; } From 65a5ac0168ae39340432d60e4fffabc8688a3ca9 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 29 Jun 2017 18:22:33 -0500 Subject: [PATCH 1349/1578] pjsip_distributor.c: Fix unidentified_requests hash functions. The OBJ_SEARCH_xxx defines should not be used as if they were individual bits. They represent a multi-bit enumeration value field. Change-Id: I32abc9a475396dab02402a7014357dd94284e17b --- res/res_pjsip/pjsip_distributor.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index cca26a83ca4..2c9bcbf6ec8 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -837,7 +837,7 @@ static int suspects_compare(void *obj, void *arg, int flags) /* Fall through */ case OBJ_SEARCH_KEY: if (strcmp(object_left->src_name, right_key) == 0) { - cmp = CMP_MATCH | CMP_STOP; + cmp = CMP_MATCH; } break; case OBJ_SEARCH_PARTIAL_KEY: @@ -852,15 +852,25 @@ static int suspects_compare(void *obj, void *arg, int flags) return cmp; } -static int suspects_hash(const void *obj, int flags) { - const struct unidentified_request *object_left = obj; +static int suspects_hash(const void *obj, int flags) +{ + const struct unidentified_request *object; + const char *key; - if (flags & OBJ_SEARCH_OBJECT) { - return ast_str_hash(object_left->src_name); - } else if (flags & OBJ_SEARCH_KEY) { - return ast_str_hash(obj); + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + object = obj; + key = object->src_name; + break; + default: + /* Hash can only work on something with a full key. */ + ast_assert(0); + return 0; } - return -1; + return ast_str_hash(key); } static struct ao2_container *cli_unid_get_container(const char *regex) From b485f6c59c5ffcbb2d7f1fe501c9db44add68bab Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 29 Jun 2017 18:27:20 -0500 Subject: [PATCH 1350/1578] pjsip_distributor.c: Fix deadlock with TCP type transports. When a SIP message comes in on a transport, pjproject obtains the lock on the transport and pulls the data out of the socket. Unlike UDP, the TCP transport does not allow concurrent access. Without concurrency the transport lock is not released when the transport's message complete callback is called. The processing continues and eventually Asterisk starts processing the SIP message. The first thing Asterisk tries to do is determine the associated dialog of the message to determine the associated serializer. To get the associated serializer safely requires us to get the dialog lock. To send a request or response message for a dialog, pjproject obtains the dialog lock and then obtains the transport lock. Deadlock can result because of the opposite order the locks are obtained. * Fix the deadlock by obtaining the serializer associated with the dialog another way that doesn't involve obtaining the dialog lock. In this case, we use an ao2 container to hold the associated endpoint and serializer. The new locks are held a brief time and won't overlap other existing lock times. ASTERISK-27090 #close Change-Id: I9ed63f4da9649e9db6ed4be29c360968917a89bd --- res/res_pjsip/pjsip_distributor.c | 216 ++++++++++++++++++++++++------ 1 file changed, 174 insertions(+), 42 deletions(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index cca26a83ca4..d5a8c841175 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -150,62 +150,189 @@ static struct ast_taskprocessor *find_request_serializer(pjsip_rx_data *rdata) /*! Dialog-specific information the distributor uses */ struct distributor_dialog_data { + /*! dialog_associations ao2 container key */ + pjsip_dialog *dlg; /*! Serializer to distribute tasks to for this dialog */ struct ast_taskprocessor *serializer; /*! Endpoint associated with this dialog */ struct ast_sip_endpoint *endpoint; }; +#define DIALOG_ASSOCIATIONS_BUCKETS 251 + +static struct ao2_container *dialog_associations; + /*! * \internal + * \brief Compute a hash value on an arbitrary buffer. + * \since 13.17.0 + * + * \param[in] pos The buffer to add to the hash + * \param[in] len The buffer length to add to the hash + * \param[in] hash The hash value to add to + * + * \details + * This version of the function is for when you need to compute a + * hash of more than one buffer. + * + * This famous hash algorithm was written by Dan Bernstein and is + * commonly used. * - * \note Call this with the dialog locked + * \sa http://www.cse.yorku.ca/~oz/hash.html */ -static struct distributor_dialog_data *distributor_dialog_data_alloc(pjsip_dialog *dlg) +static int buf_hash_add(const char *pos, size_t len, int hash) { - struct distributor_dialog_data *dist; + while (len--) { + hash = hash * 33 ^ *pos++; + } + + return hash; +} + +/*! + * \internal + * \brief Compute a hash value on an arbitrary buffer. + * \since 13.17.0 + * + * \param[in] pos The buffer to add to the hash + * \param[in] len The buffer length to add to the hash + * + * \details + * This version of the function is for when you need to compute a + * hash of more than one buffer. + * + * This famous hash algorithm was written by Dan Bernstein and is + * commonly used. + * + * \sa http://www.cse.yorku.ca/~oz/hash.html + */ +static int buf_hash(const char *pos, size_t len) +{ + return buf_hash_add(pos, len, 5381); +} + +static int dialog_associations_hash(const void *obj, int flags) +{ + const struct distributor_dialog_data *object; + union { + const pjsip_dialog *dlg; + const char buf[sizeof(pjsip_dialog *)]; + } key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key.dlg = obj; + break; + case OBJ_SEARCH_OBJECT: + object = obj; + key.dlg = object->dlg; + break; + default: + /* Hash can only work on something with a full key. */ + ast_assert(0); + return 0; + } + return ast_str_hash_restrict(buf_hash(key.buf, sizeof(key.buf))); +} - dist = PJ_POOL_ZALLOC_T(dlg->pool, struct distributor_dialog_data); - pjsip_dlg_set_mod_data(dlg, distributor_mod.id, dist); +static int dialog_associations_cmp(void *obj, void *arg, int flags) +{ + const struct distributor_dialog_data *object_left = obj; + const struct distributor_dialog_data *object_right = arg; + const pjsip_dialog *right_key = arg; + int cmp = 0; - return dist; + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = object_right->dlg; + /* Fall through */ + case OBJ_SEARCH_KEY: + if (object_left->dlg == right_key) { + cmp = CMP_MATCH; + } + break; + case OBJ_SEARCH_PARTIAL_KEY: + /* There is no such thing for this container. */ + ast_assert(0); + break; + default: + cmp = 0; + break; + } + return cmp; } void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer) { struct distributor_dialog_data *dist; - SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock); - dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id); + ao2_wrlock(dialog_associations); + dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!dist) { - dist = distributor_dialog_data_alloc(dlg); + if (serializer) { + dist = ao2_alloc(sizeof(*dist), NULL); + if (dist) { + dist->dlg = dlg; + dist->serializer = serializer; + ao2_link_flags(dialog_associations, dist, OBJ_NOLOCK); + ao2_ref(dist, -1); + } + } + } else { + ao2_lock(dist); + dist->serializer = serializer; + if (!dist->serializer && !dist->endpoint) { + ao2_unlink_flags(dialog_associations, dist, OBJ_NOLOCK); + } + ao2_unlock(dist); + ao2_ref(dist, -1); } - dist->serializer = serializer; + ao2_unlock(dialog_associations); } void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint) { struct distributor_dialog_data *dist; - SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock); - dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id); + ao2_wrlock(dialog_associations); + dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!dist) { - dist = distributor_dialog_data_alloc(dlg); + if (endpoint) { + dist = ao2_alloc(sizeof(*dist), NULL); + if (dist) { + dist->dlg = dlg; + dist->endpoint = endpoint; + ao2_link_flags(dialog_associations, dist, OBJ_NOLOCK); + ao2_ref(dist, -1); + } + } + } else { + ao2_lock(dist); + dist->endpoint = endpoint; + if (!dist->serializer && !dist->endpoint) { + ao2_unlink_flags(dialog_associations, dist, OBJ_NOLOCK); + } + ao2_unlock(dist); + ao2_ref(dist, -1); } - dist->endpoint = endpoint; + ao2_unlock(dialog_associations); } struct ast_sip_endpoint *ast_sip_dialog_get_endpoint(pjsip_dialog *dlg) { struct distributor_dialog_data *dist; - SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock); + struct ast_sip_endpoint *endpoint; - dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id); - if (!dist || !dist->endpoint) { - return NULL; + dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY); + if (dist) { + ao2_lock(dist); + endpoint = ao2_bump(dist->endpoint); + ao2_unlock(dist); + ao2_ref(dist, -1); + } else { + endpoint = NULL; } - ao2_ref(dist->endpoint, +1); - return dist->endpoint; + return endpoint; } static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) @@ -237,7 +364,7 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || rdata->msg_info.to->tag.slen != 0) { dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag, - remote_tag, PJ_TRUE); + remote_tag, PJ_FALSE); if (dlg) { return dlg; } @@ -275,11 +402,6 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) pj_mutex_unlock(tsx->mutex); #endif - if (!dlg) { - return NULL; - } - - pjsip_dlg_inc_lock(dlg); return dlg; } @@ -302,16 +424,7 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata) */ static int pjstr_hash_add(pj_str_t *str, int hash) { - size_t len; - const char *pos; - - len = pj_strlen(str); - pos = pj_strbuf(str); - while (len--) { - hash = hash * 33 ^ *pos++; - } - - return hash; + return buf_hash_add(pj_strbuf(str), pj_strlen(str), hash); } /*! @@ -350,7 +463,7 @@ struct ast_taskprocessor *ast_sip_get_distributor_serializer(pjsip_rx_data *rdat /* Compute the hash from the SIP message call-id and remote-tag */ hash = pjstr_hash(&rdata->msg_info.cid->id); hash = pjstr_hash_add(remote_tag, hash); - hash = abs(hash); + hash = ast_str_hash_restrict(hash); serializer = ao2_bump(distributor_pool[hash % ARRAY_LEN(distributor_pool)]); if (serializer) { @@ -385,17 +498,18 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) dlg = find_dialog(rdata); if (dlg) { - ast_debug(3, "Searching for serializer on dialog %s for %s\n", + ast_debug(3, "Searching for serializer associated with dialog %s for %s\n", dlg->obj_name, pjsip_rx_data_get_info(rdata)); - dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id); + dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY); if (dist) { + ao2_lock(dist); serializer = ao2_bump(dist->serializer); + ao2_unlock(dist); if (serializer) { - ast_debug(3, "Found serializer %s on dialog %s\n", + ast_debug(3, "Found serializer %s associated with dialog %s\n", ast_taskprocessor_name(serializer), dlg->obj_name); } } - pjsip_dlg_dec_lock(dlg); } if (serializer) { @@ -417,6 +531,7 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) /* We have a BYE or CANCEL request without a serializer. */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL); + ao2_cleanup(dist); return PJ_TRUE; } else { if (ast_taskprocessor_alert_get()) { @@ -431,6 +546,7 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) */ ast_debug(3, "Taskprocessor overload alert: Ignoring '%s'.\n", pjsip_rx_data_get_info(rdata)); + ao2_cleanup(dist); return PJ_TRUE; } @@ -438,10 +554,17 @@ static pj_bool_t distributor(pjsip_rx_data *rdata) serializer = ast_sip_get_distributor_serializer(rdata); } - pjsip_rx_data_clone(rdata, 0, &clone); + if (pjsip_rx_data_clone(rdata, 0, &clone) != PJ_SUCCESS) { + ast_taskprocessor_unreference(serializer); + ao2_cleanup(dist); + return PJ_TRUE; + } if (dist) { + ao2_lock(dist); clone->endpt_info.mod_data[endpoint_mod.id] = ao2_bump(dist->endpoint); + ao2_unlock(dist); + ao2_cleanup(dist); } if (ast_sip_push_task(serializer, distribute, clone)) { @@ -1078,6 +1201,14 @@ int ast_sip_initialize_distributor(void) return -1; } + dialog_associations = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, + DIALOG_ASSOCIATIONS_BUCKETS, dialog_associations_hash, NULL, + dialog_associations_cmp); + if (!dialog_associations) { + ast_sip_destroy_distributor(); + return -1; + } + if (distributor_pool_setup()) { ast_sip_destroy_distributor(); return -1; @@ -1156,5 +1287,6 @@ void ast_sip_destroy_distributor(void) distributor_pool_shutdown(); + ao2_cleanup(dialog_associations); ao2_cleanup(unidentified_requests); } From 50ddb56dad7da1712c08505e409063d6e3bda7af Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 1 Jul 2017 00:57:31 -0400 Subject: [PATCH 1351/1578] channel: Clear channel flag in error branch. Clear channel flag AST_FLAG_END_DTMF_ONLY in ast_waitfordigit_full when ast_read returns NULL. ASTERISK-27100 #close Change-Id: Id3039e9a4e74e0cb359f636c9fd0c9740ebf7d9d --- main/channel.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/main/channel.c b/main/channel.c index c7c2b9d1e6e..1a591bd27fa 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3262,8 +3262,12 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in } else if (rchan) { int res; struct ast_frame *f = ast_read(c); - if (!f) + + if (!f) { + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); + return -1; + } switch (f->frametype) { case AST_FRAME_DTMF_BEGIN: From 950b39a4f50ed3f63f520ba6bbd7359c6c5bc66e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 29 Jun 2017 14:58:35 -0400 Subject: [PATCH 1352/1578] app_voicemail: Cleanup ODBC connection handling The primary focus of this patch is adding a missing call to ast_odbc_release_obj(), but is also a general cleanup of the ODBC related code in app_voicemail. ASTERISK-27093 #close Change-Id: I8e285142eaeb3146b4287a928276b70db76c902b --- apps/app_voicemail.c | 743 +++++++++++++++++++++---------------------- 1 file changed, 366 insertions(+), 377 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 783cab69ecf..940b6ffd534 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -3779,12 +3779,12 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) SQLHSTMT stmt; res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + if (!SQL_SUCCEEDED(res)) { ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n"); return NULL; } res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + if (!SQL_SUCCEEDED(res)) { ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql); SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; @@ -3826,14 +3826,14 @@ static void odbc_update_msg_id(char *dir, int msg_num, char *msg_id) * \brief Retrieves a file from an ODBC data store. * \param dir the path to the file to be retrieved. * \param msgnum the message number, such as within a mailbox folder. - * + * * This method is used by the RETRIEVE macro when mailboxes are stored in an ODBC back end. * The purpose is to get the message from the database store to the local file system, so that the message may be played, or the information file may be read. * * The file is looked up by invoking a SQL on the odbc_table (default 'voicemessages') using the dir and msgnum input parameters. * The output is the message information file with the name msgnum and the extension .txt * and the message file with the extension of its format, in the directory with base file name of the msgnum. - * + * * \return 0 on success, -1 on error. */ static int retrieve_file(char *dir, int msgnum) @@ -3846,7 +3846,7 @@ static int retrieve_file(char *dir, int msgnum) SQLSMALLINT colcount = 0; SQLHSTMT stmt; char sql[PATH_MAX]; - char fmt[80]=""; + char fmt[80] = ""; char *c; char coltitle[256]; SQLSMALLINT collen; @@ -3862,144 +3862,139 @@ static int retrieve_file(char *dir, int msgnum) char msgnums[80]; char *argv[] = { dir, msgnums }; struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; - struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - ast_copy_string(fmt, vmfmts, sizeof(fmt)); - c = strchr(fmt, '|'); - if (c) - *c = '\0'; - if (!strcasecmp(fmt, "wav49")) - strcpy(fmt, "WAV"); - snprintf(msgnums, sizeof(msgnums), "%d", msgnum); - if (msgnum > -1) - make_file(fn, sizeof(fn), dir, msgnum); - else - ast_copy_string(fn, dir, sizeof(fn)); + if (!obj) { + ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return -1; + } - /* Create the information file */ - snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); - - if (!(f = fopen(full_fn, "w+"))) { - ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn); - goto yuck; - } - - snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt); - snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLFetch(stmt); - if (res == SQL_NO_DATA) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_copy_string(fmt, vmfmts, sizeof(fmt)); + c = strchr(fmt, '|'); + if (c) + *c = '\0'; + if (!strcasecmp(fmt, "wav49")) + strcpy(fmt, "WAV"); + + snprintf(msgnums, sizeof(msgnums), "%d", msgnum); + if (msgnum > -1) + make_file(fn, sizeof(fn), dir, msgnum); + else + ast_copy_string(fn, dir, sizeof(fn)); + + /* Create the information file */ + snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); + + if (!(f = fopen(full_fn, "w+"))) { + ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn); + goto bail; + } + + snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt); + snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table); + + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + goto bail; + } + + res = SQLFetch(stmt); + if (!SQL_SUCCEEDED(res)) { + if (res != SQL_NO_DATA) { ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; } - fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE); - if (fd < 0) { - ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno)); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLNumResultCols(stmt, &colcount); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - if (f) - fprintf(f, "[message]\n"); - for (x = 0; x < colcount; x++) { - rowdata[0] = '\0'; - colsize = 0; - collen = sizeof(coltitle); - res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen, - &datatype, &colsize, &decimaldigits, &nullable); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - if (!strcasecmp(coltitle, "recording")) { - off_t offset; - res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2); - fdlen = colsize2; - if (fd > -1) { - char tmp[1]=""; - lseek(fd, fdlen - 1, SEEK_SET); - if (write(fd, tmp, 1) != 1) { - close(fd); - fd = -1; - continue; - } - /* Read out in small chunks */ - for (offset = 0; offset < colsize2; offset += CHUNKSIZE) { - if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) { - ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } else { - res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL); - munmap(fdm, CHUNKSIZE); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - unlink(full_fn); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - } + goto bail_with_handle; + } + + fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE); + if (fd < 0) { + ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno)); + goto bail_with_handle; + } + + res = SQLNumResultCols(stmt, &colcount); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + + fprintf(f, "[message]\n"); + for (x = 0; x < colcount; x++) { + rowdata[0] = '\0'; + colsize = 0; + collen = sizeof(coltitle); + res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen, + &datatype, &colsize, &decimaldigits, &nullable); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + if (!strcasecmp(coltitle, "recording")) { + off_t offset; + res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2); + fdlen = colsize2; + if (fd > -1) { + char tmp[1] = ""; + lseek(fd, fdlen - 1, SEEK_SET); + if (write(fd, tmp, 1) != 1) { + close(fd); + fd = -1; + continue; + } + /* Read out in small chunks */ + for (offset = 0; offset < colsize2; offset += CHUNKSIZE) { + if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) { + ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno); + goto bail_with_handle; } - if (truncate(full_fn, fdlen) < 0) { - ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno)); + res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL); + munmap(fdm, CHUNKSIZE); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + unlink(full_fn); + goto bail_with_handle; } } - } else { - res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res == SQL_NULL_DATA) && (!strcasecmp(coltitle, "msg_id"))) { - char msg_id[MSG_ID_LEN]; - generate_msg_id(msg_id); - snprintf(rowdata, sizeof(rowdata), "%s", msg_id); - odbc_update_msg_id(dir, msgnum, msg_id); - } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + if (truncate(full_fn, fdlen) < 0) { + ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno)); } - if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f) - fprintf(f, "%s=%s\n", coltitle, rowdata); + } + } else { + res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if (res == SQL_NULL_DATA && !strcasecmp(coltitle, "msg_id")) { + char msg_id[MSG_ID_LEN]; + generate_msg_id(msg_id); + snprintf(rowdata, sizeof(rowdata), "%s", msg_id); + odbc_update_msg_id(dir, msgnum, msg_id); + } else if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql); + goto bail_with_handle; + } + if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir")) { + fprintf(f, "%s=%s\n", coltitle, rowdata); } } - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else - ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: + } + +bail_with_handle: + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + +bail: if (f) fclose(f); if (fd > -1) close(fd); + + ast_odbc_release_obj(obj); + return x - 1; } /*! * \brief Determines the highest message number in use for a given user and mailbox folder. - * \param vmu + * \param vmu * \param dir the folder the mailbox folder to look for messages. Used to construct the SQL where clause. * * This method is used when mailboxes are stored in an ODBC back end. @@ -4010,58 +4005,61 @@ static int retrieve_file(char *dir, int msgnum) */ static int last_message_index(struct ast_vm_user *vmu, char *dir) { - int x = 0; + int x = -1; int res; SQLHSTMT stmt; char sql[PATH_MAX]; char rowdata[20]; char *argv[] = { dir }; struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv }; - struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table); + if (!obj) { + ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return -1; + } - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - ast_odbc_release_obj(obj); - goto yuck; + snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table); + + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + goto bail; + } + + res = SQLFetch(stmt); + if (!SQL_SUCCEEDED(res)) { + if (res == SQL_NO_DATA) { + ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir); + } else { + ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - if (res == SQL_NO_DATA) { - ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir); - } else { - ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - } + goto bail_with_handle; + } - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - if (sscanf(rowdata, "%30d", &x) != 1) - ast_log(AST_LOG_WARNING, "Failed to read message index!\n"); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - return x; - } else - ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: - return x - 1; + res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + + if (sscanf(rowdata, "%30d", &x) != 1) { + ast_log(AST_LOG_WARNING, "Failed to read message index!\n"); + } + +bail_with_handle: + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + +bail: + ast_odbc_release_obj(obj); + + return x; } /*! * \brief Determines if the specified message exists. - * \param dir the folder the mailbox folder to look for messages. + * \param dir the folder the mailbox folder to look for messages. * \param msgnum the message index to query for. * * This method is used when mailboxes are stored in an ODBC back end. @@ -4078,39 +4076,43 @@ static int message_exists(char *dir, int msgnum) char msgnums[20]; char *argv[] = { dir, msgnums }; struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; - struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", msgnum); - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - if (sscanf(rowdata, "%30d", &x) != 1) - ast_log(AST_LOG_WARNING, "Failed to read message count!\n"); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: + return 0; + } + + snprintf(msgnums, sizeof(msgnums), "%d", msgnum); + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + goto bail; + } + + res = SQLFetch(stmt); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + + res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + + if (sscanf(rowdata, "%30d", &x) != 1) { + ast_log(AST_LOG_WARNING, "Failed to read message count!\n"); + } + +bail_with_handle: + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + +bail: + ast_odbc_release_obj(obj); return x; } @@ -4125,48 +4127,50 @@ static int message_exists(char *dir, int msgnum) */ static int count_messages(struct ast_vm_user *vmu, char *dir) { - int x = 0; + int x = -1; int res; SQLHSTMT stmt; char sql[PATH_MAX]; char rowdata[20]; char *argv[] = { dir }; struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv }; - struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - if (sscanf(rowdata, "%30d", &x) != 1) - ast_log(AST_LOG_WARNING, "Failed to read message count!\n"); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - return x; - } else + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: - return x - 1; + return -1; + } + + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + goto bail; + } + + res = SQLFetch(stmt); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + + res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + + if (sscanf(rowdata, "%30d", &x) != 1) { + ast_log(AST_LOG_WARNING, "Failed to read message count!\n"); + } +bail_with_handle: + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + +bail: + ast_odbc_release_obj(obj); + return x; } /*! @@ -4176,7 +4180,7 @@ static int count_messages(struct ast_vm_user *vmu, char *dir) * * This method is used when mailboxes are stored in an ODBC back end. * The specified message is directly deleted from the database 'voicemessages' table. - * + * * \return the value greater than zero on success to indicate the number of messages, less than zero on error. */ static void delete_file(const char *sdir, int smsg) @@ -4188,21 +4192,25 @@ static void delete_file(const char *sdir, int smsg) struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; struct odbc_obj *obj; - argv[0] = ast_strdupa(sdir); - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", smsg); - snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - else - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; + return; + } + + argv[0] = ast_strdupa(sdir); + + snprintf(msgnums, sizeof(msgnums), "%d", smsg); + snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + } else { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + ast_odbc_release_obj(obj); + + return; } /*! @@ -4230,19 +4238,22 @@ static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailbox generate_msg_id(msg_id); delete_file(ddir, dmsg); obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", smsg); - snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); - snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql); - else - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; + return; + } + + snprintf(msgnums, sizeof(msgnums), "%d", smsg); + snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); + snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql); + else + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + + return; } struct insert_data { @@ -4271,9 +4282,8 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata) SQLHSTMT stmt; res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + if (!SQL_SUCCEEDED(res)) { ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n"); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; } @@ -4293,7 +4303,7 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata) SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL); } res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + if (!SQL_SUCCEEDED(res)) { ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n"); SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; @@ -4310,7 +4320,7 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata) * \param msgnum the message index for the message to be stored. * * This method is used when mailboxes are stored in an ODBC back end. - * The message sound file and information file is looked up on the file system. + * The message sound file and information file is looked up on the file system. * A SQL query is invoked to store the message into the (MySQL) database. * * \return the zero on success -1 on error. @@ -4335,7 +4345,9 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; delete_file(dir, msgnum); - if (!(obj = ast_odbc_request_obj(odbc_database, 0))) { + + obj = ast_odbc_request_obj(odbc_database, 0); + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); return -1; } @@ -4398,25 +4410,25 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn); res = -1; break; - } + } idata.data = fdm; idata.datalen = idata.indlen = fdlen; - if (!ast_strlen_zero(idata.category)) - snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table); + if (!ast_strlen_zero(idata.category)) + snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table); else snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table); if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); } else { ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); res = -1; } } while (0); - if (obj) { - ast_odbc_release_obj(obj); - } + + ast_odbc_release_obj(obj); + if (valid_config(cfg)) ast_config_destroy(cfg); if (fdm != MAP_FAILED) @@ -4450,20 +4462,23 @@ static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxco struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv }; delete_file(ddir, dmsg); + obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", smsg); - snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); - snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - else - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; + return; + } + + snprintf(msgnums, sizeof(msgnums), "%d", smsg); + snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); + snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + else + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + return; } /*! @@ -5663,17 +5678,48 @@ static void free_zone(struct vm_zone *z) } #ifdef ODBC_STORAGE -static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) + +static int count_messages_in_folder(struct odbc_obj *odbc, const char *context, const char *mailbox, const char *folder, int *messages) { - int x = -1; int res; - SQLHSTMT stmt = NULL; char sql[PATH_MAX]; char rowdata[20]; + SQLHSTMT stmt = NULL; + struct generic_prepare_struct gps = { .sql = sql, .argc = 0 }; + + if (!messages) { + return 0; + } + + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder); + if (!(stmt = ast_odbc_prepare_and_execute(odbc, generic_prepare, &gps))) { + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + return 1; + } + res = SQLFetch(stmt); + if (!SQL_SUCCEEDED(res)) { + ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return 1; + } + res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if (!SQL_SUCCEEDED(res)) { + ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return 1; + } + + *messages = atoi(rowdata); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + + return 0; +} + +static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) +{ char tmp[PATH_MAX] = ""; - struct odbc_obj *obj = NULL; + struct odbc_obj *obj; char *context; - struct generic_prepare_struct gps = { .sql = sql, .argc = 0 }; if (newmsgs) *newmsgs = 0; @@ -5715,87 +5761,28 @@ static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int * } else context = "default"; - if ((obj = ast_odbc_request_obj(odbc_database, 0))) { - do { - if (newmsgs) { - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX"); - if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) { - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - break; - } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - break; - } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - break; - } - *newmsgs = atoi(rowdata); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - } - - if (oldmsgs) { - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old"); - if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) { - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - break; - } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - break; - } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - break; - } - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - *oldmsgs = atoi(rowdata); - } - - if (urgentmsgs) { - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent"); - if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) { - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - break; - } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - break; - } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - break; - } - *urgentmsgs = atoi(rowdata); - } - - x = 0; - } while (0); - } else { + obj = ast_odbc_request_obj(odbc_database, 0); + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return -1; } - if (stmt) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); + if (count_messages_in_folder(obj, context, tmp, "INBOX", newmsgs) + || count_messages_in_folder(obj, context, tmp, "Old", oldmsgs) + || count_messages_in_folder(obj, context, tmp, "Urgent", urgentmsgs)) { + ast_log(AST_LOG_WARNING, "Failed to obtain message count for mailbox %s@%s\n", + tmp, context); } - if (obj) { - ast_odbc_release_obj(obj); - } - return x; + + ast_odbc_release_obj(obj); + return 0; } /*! * \brief Gets the number of messages that exist in a mailbox folder. * \param mailbox_id * \param folder - * + * * This method is used when ODBC backend is used. * \return The number of messages in this mailbox folder (zero or more). */ @@ -5822,37 +5809,39 @@ static int messagecount(const char *mailbox_id, const char *folder) } obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - if (!strcmp(folder, "INBOX")) { - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox); - } else { - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder); - } - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - goto yuck; - } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - goto yuck; - } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - goto yuck; - } - nummsgs = atoi(rowdata); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - } else + if (!obj) { ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return 0; + } + + if (!strcmp(folder, "INBOX")) { + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox); + } else { + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder); + } -yuck: - if (obj) - ast_odbc_release_obj(obj); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + goto bail; + } + res = SQLFetch(stmt); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if (!SQL_SUCCEEDED(res)) { + ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + goto bail_with_handle; + } + nummsgs = atoi(rowdata); + +bail_with_handle: + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + +bail: + ast_odbc_release_obj(obj); return nummsgs; } From 4398aa8fa42f6812491782ec93eb42627cb45468 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 3 Jul 2017 17:38:32 +0200 Subject: [PATCH 1353/1578] chan_sip: Fix a typo for tlsbindaddr in autodomain (SIP Domain Support). Because of a copy-and-paste error when the struct ast_sockaddr changed, tlsbindaddr was not added, when sip.conf contained autodomain=yes; see "show sip domains" on the command-line interface (CLI) of Asterisk. ASTERISK-27106 Change-Id: I3d0957150017c223136968ef1266f275d0d6695e --- channels/chan_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index aaeb01e1398..dff1482cccd 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -33288,7 +33288,7 @@ static int reload_config(enum channelreloadreason reason) !ast_sockaddr_cmp(&bindaddr, &sip_tls_desc.local_address) && !ast_sockaddr_cmp(&sip_tcp_desc.local_address, &sip_tls_desc.local_address)) { - add_sip_domain(ast_sockaddr_stringify_addr(&sip_tcp_desc.local_address), + add_sip_domain(ast_sockaddr_stringify_addr(&sip_tls_desc.local_address), SIP_DOMAIN_AUTO, NULL); } From 910c05455d33564fd2008225b3f18917dd980ca6 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 3 Jul 2017 17:59:43 +0200 Subject: [PATCH 1354/1578] chan_sip: Only when different, add TCP|TLS in autodomain (SIP Domain Support). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When sip.conf contained tcpenable=yes and autodomain=yes, the TCP domain was added in any case, because of a local Boolean-negation error of the return value of ast_sockaddr_cmp. After fixing this error for TCP and TLS, the TLS domain was still always added with tlsenable=yes, because the domains were not compared just on the address but also on the port – and TLS is always on a different port than UDP/TCP. ASTERISK-27106 Change-Id: I14fe9e319e238320b094016980445ef3a5b3337c --- channels/chan_sip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index aaeb01e1398..bdff0a998ae 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -33278,15 +33278,15 @@ static int reload_config(enum channelreloadreason reason) /* If TCP is running on a different IP than UDP, then add it too */ if (!ast_sockaddr_isnull(&sip_tcp_desc.local_address) && - !ast_sockaddr_cmp(&bindaddr, &sip_tcp_desc.local_address)) { + ast_sockaddr_cmp_addr(&bindaddr, &sip_tcp_desc.local_address)) { add_sip_domain(ast_sockaddr_stringify_addr(&sip_tcp_desc.local_address), SIP_DOMAIN_AUTO, NULL); } /* If TLS is running on a different IP than UDP and TCP, then add that too */ if (!ast_sockaddr_isnull(&sip_tls_desc.local_address) && - !ast_sockaddr_cmp(&bindaddr, &sip_tls_desc.local_address) && - !ast_sockaddr_cmp(&sip_tcp_desc.local_address, + ast_sockaddr_cmp_addr(&bindaddr, &sip_tls_desc.local_address) && + ast_sockaddr_cmp_addr(&sip_tcp_desc.local_address, &sip_tls_desc.local_address)) { add_sip_domain(ast_sockaddr_stringify_addr(&sip_tcp_desc.local_address), SIP_DOMAIN_AUTO, NULL); From d556c67f9fdd0f57bd41aca80e707020cc73ec78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Mon, 19 Jun 2017 12:22:40 -0400 Subject: [PATCH 1355/1578] app_queue: Add change priority of call This patch include a feature to change the priority a caller in a queue by CLI and AMI. Change-Id: I55d520d71cc1cefe9a9b81fefaefc14679e96133 --- apps/app_queue.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index ae2d645e945..25aff4dab5e 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1009,6 +1009,26 @@ Reset the statistics for a queue. + + + Change priority of a caller on queue. + + + + + The name of the queue to take action on. + + + The caller (channel) to change priority on queue. + + + + Priority value for change for caller on queue. + + + + + @@ -1408,6 +1428,7 @@ static const struct autopause { #define RES_OUTOFMEMORY (-2) /*!< Out of memory */ #define RES_NOSUCHQUEUE (-3) /*!< No such queue */ #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */ +#define RES_NOT_CALLER (-5) /*!< Caller not found */ static char *app = "Queue"; @@ -7232,6 +7253,39 @@ static int add_to_queue(const char *queuename, const char *interface, const char return res; } + +/*! \brief Change priority caller into a queue + * \retval RES_NOSUCHQUEUE queue does not exist + * \retval RES_OKAY change priority + * \retval RES_NOT_CALLER queue exists but no caller +*/ +static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority) +{ + struct call_queue *q; + struct queue_ent *qe; + int res = RES_NOSUCHQUEUE; + + /*! \note Ensure the appropriate realtime queue is loaded. Note that this + * short-circuits if the queue is already in memory. */ + if (!(q = find_load_queue_rt_friendly(queuename))) { + return res; + } + + ao2_lock(q); + res = RES_NOT_CALLER; + for (qe = q->head; qe; qe = qe->next) { + if (strcmp(ast_channel_name(qe->chan), caller) == 0) { + ast_debug(1, "%s Caller new prioriry %d in queue %s\n", + caller, priority, queuename); + qe->prio = priority; + res = RES_OKAY; + } + } + ao2_unlock(q); + return res; +} + + static int publish_queue_member_pause(struct call_queue *q, struct member *member, const char *reason) { struct ast_json *json_blob = queue_member_blob_create(q, member); @@ -10189,6 +10243,50 @@ static int manager_queue_member_penalty(struct mansession *s, const struct messa return 0; } +static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m) +{ + const char *queuename, *caller, *priority_s; + int priority = 0; + + queuename = astman_get_header(m, "Queue"); + caller = astman_get_header(m, "Caller"); + priority_s = astman_get_header(m, "Priority"); + + if (ast_strlen_zero(queuename)) { + astman_send_error(s, m, "'Queue' not specified."); + return 0; + } + + if (ast_strlen_zero(caller)) { + astman_send_error(s, m, "'Caller' not specified."); + return 0; + } + + if (ast_strlen_zero(priority_s)) { + astman_send_error(s, m, "'Priority' not specified."); + return 0; + } else if (sscanf(priority_s, "%30d", &priority) != 1) { + astman_send_error(s, m, "'Priority' need integer."); + return 0; + } + + switch (change_priority_caller_on_queue(queuename, caller, priority)) { + case RES_OKAY: + astman_send_ack(s, m, "Priority change for caller on queue"); + break; + case RES_NOSUCHQUEUE: + astman_send_error(s, m, "Unable to change priority caller on queue: No such queue"); + break; + case RES_NOT_CALLER: + astman_send_error(s, m, "Unable to change priority caller on queue: No such caller"); + break; + } + + return 0; +} + + + static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { const char *queuename, *interface, *membername = NULL, *state_interface = NULL; @@ -10376,6 +10474,57 @@ static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct return res; } + + +static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + const char *queuename, *caller; + int priority; + char *res = CLI_FAILURE; + + switch (cmd) { + case CLI_INIT: + e->command = "queue priority caller"; + e->usage = + "Usage: queue priority caller on to \n" + " Change the priority of a channel on a queue.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 8) { + return CLI_SHOWUSAGE; + } else if (strcmp(a->argv[4], "on")) { + return CLI_SHOWUSAGE; + } else if (strcmp(a->argv[6], "to")) { + return CLI_SHOWUSAGE; + } else if (sscanf(a->argv[7], "%30d", &priority) != 1) { + ast_log (LOG_ERROR, " parameter must be an integer.\n"); + return CLI_SHOWUSAGE; + } + + caller = a->argv[3]; + queuename = a->argv[5]; + + switch (change_priority_caller_on_queue(queuename, caller, priority)) { + case RES_OKAY: + res = CLI_SUCCESS; + break; + case RES_NOSUCHQUEUE: + ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename); + break; + case RES_NOT_CALLER: + ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename); + + break; + } + + return res; +} + + + static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state) { /* 0 - queue; 1 - pause; 2 - member; 3 - ; 4 - queue; 5 - ; 6 - reason; 7 - */ @@ -10821,6 +10970,7 @@ static struct ast_cli_entry cli_queue[] = { AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"), AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"), AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"), + AST_CLI_DEFINE(handle_queue_change_priority_caller, "Change priority caller on queue"), }; /* struct call_queue astdata mapping. */ @@ -11132,6 +11282,7 @@ static int unload_module(void) ast_manager_unregister("QueueReload"); ast_manager_unregister("QueueReset"); ast_manager_unregister("QueueMemberRingInUse"); + ast_manager_unregister("QueueChangePriorityCaller"); ast_unregister_application(app_aqm); ast_unregister_application(app_rqm); ast_unregister_application(app_pqm); @@ -11250,6 +11401,7 @@ static int load_module(void) err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); + err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue); err |= ast_custom_function_register(&queuevar_function); err |= ast_custom_function_register(&queueexists_function); err |= ast_custom_function_register(&queuemembercount_function); From 325eeced6a7edea019cc6a013460f617d10bfc28 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 5 Jul 2017 11:29:01 -0400 Subject: [PATCH 1356/1578] core: Remove 'Data Retrieval API' This API was not actively maintained, was not added to new modules (such as res_pjsip), and there exist better alternatives to acquire the same information, such as the ARI. Change-Id: I4b2185a83aeb74798b4ad43ff8f89f971096aa83 --- UPGRADE.txt | 9 + apps/app_meetme.c | 191 -- apps/app_queue.c | 274 --- apps/app_voicemail.c | 143 -- channels/chan_dahdi.c | 233 --- channels/chan_iax2.c | 334 ---- channels/chan_sip.c | 242 --- include/asterisk/_private.h | 1 - include/asterisk/channel.h | 23 +- include/asterisk/data.h | 828 -------- include/asterisk/indications.h | 9 - main/asterisk.c | 1 - main/cdr.c | 1 - main/channel.c | 120 -- main/channel_internal_api.c | 206 -- main/data.c | 3346 -------------------------------- main/indications.c | 41 - main/pbx.c | 52 - res/res_odbc.c | 70 - 19 files changed, 10 insertions(+), 6114 deletions(-) delete mode 100644 include/asterisk/data.h delete mode 100644 main/data.c diff --git a/UPGRADE.txt b/UPGRADE.txt index 62bb8018291..eb05b035e1b 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -23,6 +23,15 @@ === UPGRADE-14.txt -- Upgrade info for 13 to 14 =========================================================== +New in 15.0.0: + +Core: + - The 'Data Retrieval API' has been removed. This API was not actively + maintained, was not added to new modules (such as res_pjsip), and there + exist better alternatives to acquire the same information, such as the + ARI. As a result, the 'DataGet' AMI action as well as the 'data get' + CLI command have been removed. + From 14.4.0 to 14.5.0: Core: diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 71ca9dc9f8e..d98c418c354 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -69,7 +69,6 @@ #include "asterisk/dial.h" #include "asterisk/causes.h" #include "asterisk/paths.h" -#include "asterisk/data.h" #include "asterisk/test.h" #include "asterisk/stasis.h" #include "asterisk/stasis_channels.h" @@ -8005,186 +8004,6 @@ static int load_config(int reload) return sla_load_config(reload); } -#define MEETME_DATA_EXPORT(MEMBER) \ - MEMBER(ast_conference, confno, AST_DATA_STRING) \ - MEMBER(ast_conference, dahdiconf, AST_DATA_INTEGER) \ - MEMBER(ast_conference, users, AST_DATA_INTEGER) \ - MEMBER(ast_conference, markedusers, AST_DATA_INTEGER) \ - MEMBER(ast_conference, maxusers, AST_DATA_INTEGER) \ - MEMBER(ast_conference, isdynamic, AST_DATA_BOOLEAN) \ - MEMBER(ast_conference, locked, AST_DATA_BOOLEAN) \ - MEMBER(ast_conference, recordingfilename, AST_DATA_STRING) \ - MEMBER(ast_conference, recordingformat, AST_DATA_STRING) \ - MEMBER(ast_conference, pin, AST_DATA_PASSWORD) \ - MEMBER(ast_conference, pinadmin, AST_DATA_PASSWORD) \ - MEMBER(ast_conference, start, AST_DATA_TIMESTAMP) \ - MEMBER(ast_conference, endtime, AST_DATA_TIMESTAMP) - -AST_DATA_STRUCTURE(ast_conference, MEETME_DATA_EXPORT); - -#define MEETME_USER_DATA_EXPORT(MEMBER) \ - MEMBER(ast_conf_user, user_no, AST_DATA_INTEGER) \ - MEMBER(ast_conf_user, talking, AST_DATA_BOOLEAN) \ - MEMBER(ast_conf_user, dahdichannel, AST_DATA_BOOLEAN) \ - MEMBER(ast_conf_user, jointime, AST_DATA_TIMESTAMP) \ - MEMBER(ast_conf_user, kicktime, AST_DATA_TIMESTAMP) \ - MEMBER(ast_conf_user, timelimit, AST_DATA_MILLISECONDS) \ - MEMBER(ast_conf_user, play_warning, AST_DATA_MILLISECONDS) \ - MEMBER(ast_conf_user, warning_freq, AST_DATA_MILLISECONDS) - -AST_DATA_STRUCTURE(ast_conf_user, MEETME_USER_DATA_EXPORT); - -static int user_add_provider_cb(void *obj, void *arg, int flags) -{ - struct ast_data *data_meetme_user; - struct ast_data *data_meetme_user_channel; - struct ast_data *data_meetme_user_volume; - - struct ast_conf_user *user = obj; - struct ast_data *data_meetme_users = arg; - - data_meetme_user = ast_data_add_node(data_meetme_users, "user"); - if (!data_meetme_user) { - return 0; - } - /* user structure */ - ast_data_add_structure(ast_conf_user, data_meetme_user, user); - - /* user's channel */ - data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel"); - if (!data_meetme_user_channel) { - return 0; - } - - ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1); - - /* volume structure */ - data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume"); - if (!data_meetme_user_volume) { - return 0; - } - ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired); - ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual); - - data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume"); - if (!data_meetme_user_volume) { - return 0; - } - ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired); - ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual); - - return 0; -} - -/*! - * \internal - * \brief Implements the meetme data provider. - */ -static int meetme_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct ast_conference *cnf; - struct ast_data *data_meetme, *data_meetme_users; - - AST_LIST_LOCK(&confs); - AST_LIST_TRAVERSE(&confs, cnf, list) { - data_meetme = ast_data_add_node(data_root, "meetme"); - if (!data_meetme) { - continue; - } - - ast_data_add_structure(ast_conference, data_meetme, cnf); - - if (ao2_container_count(cnf->usercontainer)) { - data_meetme_users = ast_data_add_node(data_meetme, "users"); - if (!data_meetme_users) { - ast_data_remove_node(data_root, data_meetme); - continue; - } - - ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users); - } - - if (!ast_data_search_match(search, data_meetme)) { - ast_data_remove_node(data_root, data_meetme); - } - } - AST_LIST_UNLOCK(&confs); - - return 0; -} - -static const struct ast_data_handler meetme_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = meetme_data_provider_get -}; - -static const struct ast_data_entry meetme_data_providers[] = { - AST_DATA_ENTRY("asterisk/application/meetme/list", &meetme_data_provider), -}; - -#ifdef TEST_FRAMEWORK -AST_TEST_DEFINE(test_meetme_data_provider) -{ - struct ast_channel *chan; - struct ast_conference *cnf; - struct ast_data *node; - struct ast_data_query query = { - .path = "/asterisk/application/meetme/list", - .search = "list/meetme/confno=9898" - }; - - switch (cmd) { - case TEST_INIT: - info->name = "meetme_get_data_test"; - info->category = "/main/data/app_meetme/list/"; - info->summary = "Meetme data provider unit test"; - info->description = - "Tests whether the Meetme data provider implementation works as expected."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "MeetMeTest"); - if (!chan) { - ast_test_status_update(test, "Channel allocation failed\n"); - return AST_TEST_FAIL; - } - - ast_channel_unlock(chan); - - cnf = build_conf("9898", "", "1234", 1, 1, 1, chan, test); - if (!cnf) { - ast_test_status_update(test, "Build of test conference 9898 failed\n"); - ast_hangup(chan); - return AST_TEST_FAIL; - } - - node = ast_data_get(&query); - if (!node) { - ast_test_status_update(test, "Data query for test conference 9898 failed\n"); - dispose_conf(cnf); - ast_hangup(chan); - return AST_TEST_FAIL; - } - - if (strcmp(ast_data_retrieve_string(node, "meetme/confno"), "9898")) { - ast_test_status_update(test, "Query returned the wrong conference\n"); - dispose_conf(cnf); - ast_hangup(chan); - ast_data_free(node); - return AST_TEST_FAIL; - } - - ast_data_free(node); - dispose_conf(cnf); - ast_hangup(chan); - - return AST_TEST_PASS; -} -#endif - static int unload_module(void) { int res = 0; @@ -8201,11 +8020,6 @@ static int unload_module(void) res |= ast_unregister_application(slastation_app); res |= ast_unregister_application(slatrunk_app); -#ifdef TEST_FRAMEWORK - AST_TEST_UNREGISTER(test_meetme_data_provider); -#endif - ast_data_unregister(NULL); - ast_devstate_prov_del("Meetme"); ast_devstate_prov_del("SLA"); @@ -8249,11 +8063,6 @@ static int load_module(void) res |= ast_register_application_xml(slastation_app, sla_station_exec); res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec); -#ifdef TEST_FRAMEWORK - AST_TEST_REGISTER(test_meetme_data_provider); -#endif - ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers)); - res |= ast_devstate_prov_add("Meetme", meetmestate); res |= ast_devstate_prov_add("SLA", sla_state); diff --git a/apps/app_queue.c b/apps/app_queue.c index b306af1aefa..3f8e136f2f8 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -99,7 +99,6 @@ #include "asterisk/taskprocessor.h" #include "asterisk/aoc.h" #include "asterisk/callerid.h" -#include "asterisk/data.h" #include "asterisk/term.h" #include "asterisk/dial.h" #include "asterisk/stasis_channels.h" @@ -10896,275 +10895,6 @@ static struct ast_cli_entry cli_queue[] = { AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"), }; -/* struct call_queue astdata mapping. */ -#define DATA_EXPORT_CALL_QUEUE(MEMBER) \ - MEMBER(call_queue, name, AST_DATA_STRING) \ - MEMBER(call_queue, moh, AST_DATA_STRING) \ - MEMBER(call_queue, announce, AST_DATA_STRING) \ - MEMBER(call_queue, context, AST_DATA_STRING) \ - MEMBER(call_queue, membermacro, AST_DATA_STRING) \ - MEMBER(call_queue, membergosub, AST_DATA_STRING) \ - MEMBER(call_queue, defaultrule, AST_DATA_STRING) \ - MEMBER(call_queue, sound_next, AST_DATA_STRING) \ - MEMBER(call_queue, sound_thereare, AST_DATA_STRING) \ - MEMBER(call_queue, sound_calls, AST_DATA_STRING) \ - MEMBER(call_queue, queue_quantity1, AST_DATA_STRING) \ - MEMBER(call_queue, queue_quantity2, AST_DATA_STRING) \ - MEMBER(call_queue, sound_holdtime, AST_DATA_STRING) \ - MEMBER(call_queue, sound_minutes, AST_DATA_STRING) \ - MEMBER(call_queue, sound_minute, AST_DATA_STRING) \ - MEMBER(call_queue, sound_seconds, AST_DATA_STRING) \ - MEMBER(call_queue, sound_thanks, AST_DATA_STRING) \ - MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING) \ - MEMBER(call_queue, sound_reporthold, AST_DATA_STRING) \ - MEMBER(call_queue, dead, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, announce_to_first_user, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, reportholdtime, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER) \ - MEMBER(call_queue, realtime, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, found, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \ - MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS) \ - MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS) \ - MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS) \ - MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER) \ - MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER) \ - MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS) \ - MEMBER(call_queue, holdtime, AST_DATA_SECONDS) \ - MEMBER(call_queue, talktime, AST_DATA_SECONDS) \ - MEMBER(call_queue, callscompleted, AST_DATA_INTEGER) \ - MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER) \ - MEMBER(call_queue, servicelevel, AST_DATA_INTEGER) \ - MEMBER(call_queue, callscompletedinsl, AST_DATA_INTEGER) \ - MEMBER(call_queue, monfmt, AST_DATA_STRING) \ - MEMBER(call_queue, montype, AST_DATA_INTEGER) \ - MEMBER(call_queue, count, AST_DATA_INTEGER) \ - MEMBER(call_queue, maxlen, AST_DATA_INTEGER) \ - MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS) \ - MEMBER(call_queue, retry, AST_DATA_SECONDS) \ - MEMBER(call_queue, timeout, AST_DATA_SECONDS) \ - MEMBER(call_queue, weight, AST_DATA_INTEGER) \ - MEMBER(call_queue, autopause, AST_DATA_INTEGER) \ - MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER) \ - MEMBER(call_queue, rrpos, AST_DATA_INTEGER) \ - MEMBER(call_queue, memberdelay, AST_DATA_INTEGER) \ - MEMBER(call_queue, autofill, AST_DATA_INTEGER) \ - MEMBER(call_queue, members, AST_DATA_CONTAINER) - -AST_DATA_STRUCTURE(call_queue, DATA_EXPORT_CALL_QUEUE); - -/* struct member astdata mapping. */ -#define DATA_EXPORT_MEMBER(MEMBER) \ - MEMBER(member, interface, AST_DATA_STRING) \ - MEMBER(member, state_interface, AST_DATA_STRING) \ - MEMBER(member, membername, AST_DATA_STRING) \ - MEMBER(member, penalty, AST_DATA_INTEGER) \ - MEMBER(member, calls, AST_DATA_INTEGER) \ - MEMBER(member, dynamic, AST_DATA_INTEGER) \ - MEMBER(member, realtime, AST_DATA_INTEGER) \ - MEMBER(member, status, AST_DATA_INTEGER) \ - MEMBER(member, paused, AST_DATA_BOOLEAN) \ - MEMBER(member, rt_uniqueid, AST_DATA_STRING) - -AST_DATA_STRUCTURE(member, DATA_EXPORT_MEMBER); - -#define DATA_EXPORT_QUEUE_ENT(MEMBER) \ - MEMBER(queue_ent, moh, AST_DATA_STRING) \ - MEMBER(queue_ent, announce, AST_DATA_STRING) \ - MEMBER(queue_ent, context, AST_DATA_STRING) \ - MEMBER(queue_ent, digits, AST_DATA_STRING) \ - MEMBER(queue_ent, valid_digits, AST_DATA_INTEGER) \ - MEMBER(queue_ent, pos, AST_DATA_INTEGER) \ - MEMBER(queue_ent, prio, AST_DATA_INTEGER) \ - MEMBER(queue_ent, last_pos_said, AST_DATA_INTEGER) \ - MEMBER(queue_ent, last_periodic_announce_time, AST_DATA_INTEGER) \ - MEMBER(queue_ent, last_periodic_announce_sound, AST_DATA_INTEGER) \ - MEMBER(queue_ent, last_pos, AST_DATA_INTEGER) \ - MEMBER(queue_ent, opos, AST_DATA_INTEGER) \ - MEMBER(queue_ent, handled, AST_DATA_INTEGER) \ - MEMBER(queue_ent, pending, AST_DATA_INTEGER) \ - MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER) \ - MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER) \ - MEMBER(queue_ent, raise_penalty, AST_DATA_INTEGER) \ - MEMBER(queue_ent, linpos, AST_DATA_INTEGER) \ - MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER) \ - MEMBER(queue_ent, start, AST_DATA_INTEGER) \ - MEMBER(queue_ent, expire, AST_DATA_INTEGER) \ - MEMBER(queue_ent, cancel_answered_elsewhere, AST_DATA_INTEGER) - -AST_DATA_STRUCTURE(queue_ent, DATA_EXPORT_QUEUE_ENT); - -/*! - * \internal - * \brief Add a queue to the data_root node. - * \param[in] search The search tree. - * \param[in] data_root The main result node. - * \param[in] queue The queue to add. - */ -static void queues_data_provider_get_helper(const struct ast_data_search *search, - struct ast_data *data_root, struct call_queue *queue) -{ - struct ao2_iterator im; - struct member *member; - struct queue_ent *qe; - struct ast_data *data_queue, *data_members = NULL, *enum_node; - struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel; - - data_queue = ast_data_add_node(data_root, "queue"); - if (!data_queue) { - return; - } - - ast_data_add_structure(call_queue, data_queue, queue); - - ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy)); - ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members)); - - /* announce position */ - enum_node = ast_data_add_node(data_queue, "announceposition"); - if (!enum_node) { - return; - } - switch (queue->announceposition) { - case ANNOUNCEPOSITION_LIMIT: - ast_data_add_str(enum_node, "text", "limit"); - break; - case ANNOUNCEPOSITION_MORE_THAN: - ast_data_add_str(enum_node, "text", "more"); - break; - case ANNOUNCEPOSITION_YES: - ast_data_add_str(enum_node, "text", "yes"); - break; - case ANNOUNCEPOSITION_NO: - ast_data_add_str(enum_node, "text", "no"); - break; - default: - ast_data_add_str(enum_node, "text", "unknown"); - break; - } - ast_data_add_int(enum_node, "value", queue->announceposition); - - /* add queue members */ - im = ao2_iterator_init(queue->members, 0); - while ((member = ao2_iterator_next(&im))) { - if (!data_members) { - data_members = ast_data_add_node(data_queue, "members"); - if (!data_members) { - ao2_ref(member, -1); - continue; - } - } - - data_member = ast_data_add_node(data_members, "member"); - if (!data_member) { - ao2_ref(member, -1); - continue; - } - - ast_data_add_structure(member, data_member, member); - - ao2_ref(member, -1); - } - ao2_iterator_destroy(&im); - - /* include the callers inside the result. */ - if (queue->head) { - for (qe = queue->head; qe; qe = qe->next) { - if (!data_callers) { - data_callers = ast_data_add_node(data_queue, "callers"); - if (!data_callers) { - continue; - } - } - - data_caller = ast_data_add_node(data_callers, "caller"); - if (!data_caller) { - continue; - } - - ast_data_add_structure(queue_ent, data_caller, qe); - - /* add the caller channel. */ - data_caller_channel = ast_data_add_node(data_caller, "channel"); - if (!data_caller_channel) { - continue; - } - - ast_channel_data_add_structure(data_caller_channel, qe->chan, 1); - } - } - - /* if this queue doesn't match remove the added queue. */ - if (!ast_data_search_match(search, data_queue)) { - ast_data_remove_node(data_root, data_queue); - } -} - -/*! - * \internal - * \brief Callback used to generate the queues tree. - * \param[in] search The search pattern tree. - * \retval NULL on error. - * \retval non-NULL The generated tree. - */ -static int queues_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct ao2_iterator i; - struct call_queue *queue, *queue_realtime = NULL; - struct ast_config *cfg; - - /* load realtime queues. */ - cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); - if (cfg) { - char *category = NULL; - while ((category = ast_category_browse(cfg, category))) { - const char *queuename = ast_variable_retrieve(cfg, category, "name"); - if ((queue = find_load_queue_rt_friendly(queuename))) { - queue_unref(queue); - } - } - ast_config_destroy(cfg); - } - - /* static queues. */ - i = ao2_iterator_init(queues, 0); - while ((queue = ao2_iterator_next(&i))) { - ao2_lock(queue); - if (queue->realtime) { - queue_realtime = find_load_queue_rt_friendly(queue->name); - if (!queue_realtime) { - ao2_unlock(queue); - queue_unref(queue); - continue; - } - queue_unref(queue_realtime); - } - - queues_data_provider_get_helper(search, data_root, queue); - ao2_unlock(queue); - queue_unref(queue); - } - ao2_iterator_destroy(&i); - - return 0; -} - -static const struct ast_data_handler queues_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = queues_data_provider_get -}; - -static const struct ast_data_entry queue_data_providers[] = { - AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider), -}; - static struct stasis_message_router *agent_router; static struct stasis_forward *topic_forwarder; @@ -11222,8 +10952,6 @@ static int unload_module(void) ast_custom_function_unregister(&queuewaitingcount_function); ast_custom_function_unregister(&queuememberpenalty_function); - ast_data_unregister(NULL); - device_state_sub = stasis_unsubscribe_and_join(device_state_sub); ast_extension_state_del(0, extension_state_cb); @@ -11302,8 +11030,6 @@ static int load_module(void) reload_queue_members(); } - ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers)); - err |= ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue)); err |= ast_register_application_xml(app, queue_exec); err |= ast_register_application_xml(app_aqm, aqm_exec); diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 783cab69ecf..e5fa91605d2 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -12914,147 +12914,6 @@ static struct ast_cli_entry cli_voicemail[] = { AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"), }; -#ifdef IMAP_STORAGE - #define DATA_EXPORT_VM_USERS(USER) \ - USER(ast_vm_user, context, AST_DATA_STRING) \ - USER(ast_vm_user, mailbox, AST_DATA_STRING) \ - USER(ast_vm_user, password, AST_DATA_PASSWORD) \ - USER(ast_vm_user, fullname, AST_DATA_STRING) \ - USER(ast_vm_user, email, AST_DATA_STRING) \ - USER(ast_vm_user, emailsubject, AST_DATA_STRING) \ - USER(ast_vm_user, emailbody, AST_DATA_STRING) \ - USER(ast_vm_user, pager, AST_DATA_STRING) \ - USER(ast_vm_user, serveremail, AST_DATA_STRING) \ - USER(ast_vm_user, fromstring, AST_DATA_STRING) \ - USER(ast_vm_user, language, AST_DATA_STRING) \ - USER(ast_vm_user, zonetag, AST_DATA_STRING) \ - USER(ast_vm_user, callback, AST_DATA_STRING) \ - USER(ast_vm_user, dialout, AST_DATA_STRING) \ - USER(ast_vm_user, uniqueid, AST_DATA_STRING) \ - USER(ast_vm_user, exit, AST_DATA_STRING) \ - USER(ast_vm_user, attachfmt, AST_DATA_STRING) \ - USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \ - USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \ - USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \ - USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \ - USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \ - USER(ast_vm_user, imapuser, AST_DATA_STRING) \ - USER(ast_vm_user, imappassword, AST_DATA_STRING) \ - USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \ - USER(ast_vm_user, volgain, AST_DATA_DOUBLE) -#else - #define DATA_EXPORT_VM_USERS(USER) \ - USER(ast_vm_user, context, AST_DATA_STRING) \ - USER(ast_vm_user, mailbox, AST_DATA_STRING) \ - USER(ast_vm_user, password, AST_DATA_PASSWORD) \ - USER(ast_vm_user, fullname, AST_DATA_STRING) \ - USER(ast_vm_user, email, AST_DATA_STRING) \ - USER(ast_vm_user, emailsubject, AST_DATA_STRING) \ - USER(ast_vm_user, emailbody, AST_DATA_STRING) \ - USER(ast_vm_user, pager, AST_DATA_STRING) \ - USER(ast_vm_user, serveremail, AST_DATA_STRING) \ - USER(ast_vm_user, fromstring, AST_DATA_STRING) \ - USER(ast_vm_user, language, AST_DATA_STRING) \ - USER(ast_vm_user, zonetag, AST_DATA_STRING) \ - USER(ast_vm_user, callback, AST_DATA_STRING) \ - USER(ast_vm_user, dialout, AST_DATA_STRING) \ - USER(ast_vm_user, uniqueid, AST_DATA_STRING) \ - USER(ast_vm_user, exit, AST_DATA_STRING) \ - USER(ast_vm_user, attachfmt, AST_DATA_STRING) \ - USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \ - USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \ - USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \ - USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \ - USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \ - USER(ast_vm_user, volgain, AST_DATA_DOUBLE) -#endif - -AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS); - -#define DATA_EXPORT_VM_ZONES(ZONE) \ - ZONE(vm_zone, name, AST_DATA_STRING) \ - ZONE(vm_zone, timezone, AST_DATA_STRING) \ - ZONE(vm_zone, msg_format, AST_DATA_STRING) - -AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES); - -/*! - * \internal - * \brief Add voicemail user to the data_root. - * \param[in] search The search tree. - * \param[in] data_root The main result node. - * \param[in] user The voicemail user. - */ -static int vm_users_data_provider_get_helper(const struct ast_data_search *search, - struct ast_data *data_root, struct ast_vm_user *user) -{ - struct ast_data *data_user, *data_zone; - struct ast_data *data_state; - struct vm_zone *zone = NULL; - int urgentmsg = 0, newmsg = 0, oldmsg = 0; - char ext_context[256] = ""; - - data_user = ast_data_add_node(data_root, "user"); - if (!data_user) { - return -1; - } - - ast_data_add_structure(ast_vm_user, data_user, user); - - AST_LIST_LOCK(&zones); - AST_LIST_TRAVERSE(&zones, zone, list) { - if (!strcmp(zone->name, user->zonetag)) { - break; - } - } - AST_LIST_UNLOCK(&zones); - - /* state */ - data_state = ast_data_add_node(data_user, "state"); - if (!data_state) { - return -1; - } - snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context); - inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg); - ast_data_add_int(data_state, "urgentmsg", urgentmsg); - ast_data_add_int(data_state, "newmsg", newmsg); - ast_data_add_int(data_state, "oldmsg", oldmsg); - - if (zone) { - data_zone = ast_data_add_node(data_user, "zone"); - ast_data_add_structure(vm_zone, data_zone, zone); - } - - if (!ast_data_search_match(search, data_user)) { - ast_data_remove_node(data_root, data_user); - } - - return 0; -} - -static int vm_users_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct ast_vm_user *user; - - AST_LIST_LOCK(&users); - AST_LIST_TRAVERSE(&users, user, list) { - vm_users_data_provider_get_helper(search, data_root, user); - } - AST_LIST_UNLOCK(&users); - - return 0; -} - -static const struct ast_data_handler vm_users_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = vm_users_data_provider_get -}; - -static const struct ast_data_entry vm_data_providers[] = { - AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider) -}; - static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub) { int new = 0, old = 0, urgent = 0; @@ -14997,7 +14856,6 @@ static int unload_module(void) res |= ast_custom_function_unregister(&vm_info_acf); res |= ast_manager_unregister("VoicemailUsersList"); res |= ast_manager_unregister("VoicemailRefresh"); - res |= ast_data_unregister(NULL); #ifdef TEST_FRAMEWORK res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname); res |= AST_TEST_UNREGISTER(test_voicemail_msgcount); @@ -15107,7 +14965,6 @@ static int load_module(void) } ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail)); - ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers)); #ifdef TEST_FRAMEWORK ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user); diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 72fbe6e0c7c..4f717ffacc7 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -119,7 +119,6 @@ #include "asterisk/devicestate.h" #include "asterisk/paths.h" #include "asterisk/ccss.h" -#include "asterisk/data.h" #include "asterisk/features_config.h" #include "asterisk/bridge.h" #include "asterisk/stasis_channels.h" @@ -791,78 +790,6 @@ const char * const subnames[] = { "Threeway" }; -#define DATA_EXPORT_DAHDI_PVT(MEMBER) \ - MEMBER(dahdi_pvt, cid_rxgain, AST_DATA_DOUBLE) \ - MEMBER(dahdi_pvt, rxgain, AST_DATA_DOUBLE) \ - MEMBER(dahdi_pvt, txgain, AST_DATA_DOUBLE) \ - MEMBER(dahdi_pvt, txdrc, AST_DATA_DOUBLE) \ - MEMBER(dahdi_pvt, rxdrc, AST_DATA_DOUBLE) \ - MEMBER(dahdi_pvt, adsi, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, answeronpolarityswitch, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, busydetect, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, callreturn, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, callwaiting, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, callwaitingcallerid, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, cancallforward, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, canpark, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, confirmanswer, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, destroy, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, didtdd, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, dialednone, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, dialing, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, digital, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, dnd, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, echobreak, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, echocanbridged, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, echocanon, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, faxhandled, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, usefaxbuffers, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, bufferoverrideinuse, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, firstradio, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, hanguponpolarityswitch, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, hardwaredtmf, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, hidecallerid, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, hidecalleridname, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, ignoredtmf, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, immediate, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, inalarm, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, mate, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, outgoing, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, permcallwaiting, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, priindication_oob, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, priexclusive, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, pulse, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, pulsedial, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, restartpending, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, restrictcid, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, threewaycalling, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, transfer, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, use_callerid, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, use_callingpres, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, usedistinctiveringdetection, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, dahditrcallerid, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, transfertobusy, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, mwimonitor_neon, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, mwimonitor_fsk, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, mwimonitor_rpas, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, mwimonitoractive, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, mwisendactive, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, inservice, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, locallyblocked, AST_DATA_UNSIGNED_INTEGER) \ - MEMBER(dahdi_pvt, remotelyblocked, AST_DATA_UNSIGNED_INTEGER) \ - MEMBER(dahdi_pvt, manages_span_alarms, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, use_smdi, AST_DATA_BOOLEAN) \ - MEMBER(dahdi_pvt, context, AST_DATA_STRING) \ - MEMBER(dahdi_pvt, defcontext, AST_DATA_STRING) \ - MEMBER(dahdi_pvt, description, AST_DATA_STRING) \ - MEMBER(dahdi_pvt, exten, AST_DATA_STRING) \ - MEMBER(dahdi_pvt, language, AST_DATA_STRING) \ - MEMBER(dahdi_pvt, mohinterpret, AST_DATA_STRING) \ - MEMBER(dahdi_pvt, mohsuggest, AST_DATA_STRING) \ - MEMBER(dahdi_pvt, parkinglot, AST_DATA_STRING) - -AST_DATA_STRUCTURE(dahdi_pvt, DATA_EXPORT_DAHDI_PVT); - static struct dahdi_pvt *iflist = NULL; /*!< Main interface list start */ static struct dahdi_pvt *ifend = NULL; /*!< Main interface list end */ @@ -17313,7 +17240,6 @@ static int __unload_module(void) ast_manager_unregister("PRIDebugFileSet"); ast_manager_unregister("PRIDebugFileUnset"); #endif /* defined(HAVE_PRI) */ - ast_data_unregister(NULL); ast_channel_unregister(&dahdi_tech); /* Hangup all interfaces if they have an owner */ @@ -19355,163 +19281,6 @@ static int setup_dahdi(int reload) return res; } -/*! - * \internal - * \brief Callback used to generate the dahdi status tree. - * \param[in] search The search pattern tree. - * \retval NULL on error. - * \retval non-NULL The generated tree. - */ -static int dahdi_status_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - int ctl, res, span; - struct ast_data *data_span, *data_alarms; - struct dahdi_spaninfo s; - - ctl = open("/dev/dahdi/ctl", O_RDWR); - if (ctl < 0) { - ast_log(LOG_ERROR, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno)); - return -1; - } - for (span = 1; span < DAHDI_MAX_SPANS; ++span) { - s.spanno = span; - res = ioctl(ctl, DAHDI_SPANSTAT, &s); - if (res) { - continue; - } - - data_span = ast_data_add_node(data_root, "span"); - if (!data_span) { - continue; - } - ast_data_add_str(data_span, "description", s.desc); - - /* insert the alarms status */ - data_alarms = ast_data_add_node(data_span, "alarms"); - if (!data_alarms) { - continue; - } - - ast_data_add_bool(data_alarms, "BLUE", s.alarms & DAHDI_ALARM_BLUE); - ast_data_add_bool(data_alarms, "YELLOW", s.alarms & DAHDI_ALARM_YELLOW); - ast_data_add_bool(data_alarms, "RED", s.alarms & DAHDI_ALARM_RED); - ast_data_add_bool(data_alarms, "LOOPBACK", s.alarms & DAHDI_ALARM_LOOPBACK); - ast_data_add_bool(data_alarms, "RECOVER", s.alarms & DAHDI_ALARM_RECOVER); - ast_data_add_bool(data_alarms, "NOTOPEN", s.alarms & DAHDI_ALARM_NOTOPEN); - - ast_data_add_int(data_span, "irqmisses", s.irqmisses); - ast_data_add_int(data_span, "bpviol", s.bpvcount); - ast_data_add_int(data_span, "crc4", s.crc4count); - ast_data_add_str(data_span, "framing", s.lineconfig & DAHDI_CONFIG_D4 ? "D4" : - s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" : - s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" : - "CAS"); - ast_data_add_str(data_span, "coding", s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" : - s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" : - s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" : - "Unknown"); - ast_data_add_str(data_span, "options", s.lineconfig & DAHDI_CONFIG_CRC4 ? - s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" : - s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "YEL" : ""); - ast_data_add_str(data_span, "lbo", lbostr[s.lbo]); - - /* if this span doesn't match remove it. */ - if (!ast_data_search_match(search, data_span)) { - ast_data_remove_node(data_root, data_span); - } - } - close(ctl); - - return 0; -} - -/*! - * \internal - * \brief Callback used to generate the dahdi channels tree. - * \param[in] search The search pattern tree. - * \retval NULL on error. - * \retval non-NULL The generated tree. - */ -static int dahdi_channels_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct dahdi_pvt *tmp; - struct ast_data *data_channel; - - ast_mutex_lock(&iflock); - for (tmp = iflist; tmp; tmp = tmp->next) { - data_channel = ast_data_add_node(data_root, "channel"); - if (!data_channel) { - continue; - } - - ast_data_add_structure(dahdi_pvt, data_channel, tmp); - - /* if this channel doesn't match remove it. */ - if (!ast_data_search_match(search, data_channel)) { - ast_data_remove_node(data_root, data_channel); - } - } - ast_mutex_unlock(&iflock); - - return 0; -} - -/*! - * \internal - * \brief Callback used to generate the dahdi channels tree. - * \param[in] search The search pattern tree. - * \retval NULL on error. - * \retval non-NULL The generated tree. - */ -static int dahdi_version_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - int pseudo_fd = -1; - struct dahdi_versioninfo vi = { - .version = "Unknown", - .echo_canceller = "Unknown" - }; - - if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) { - ast_log(LOG_ERROR, "Failed to open control file to get version.\n"); - return -1; - } - - if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi)) { - ast_log(LOG_ERROR, "Failed to get DAHDI version: %s\n", strerror(errno)); - } - - close(pseudo_fd); - - ast_data_add_str(data_root, "value", vi.version); - ast_data_add_str(data_root, "echocanceller", vi.echo_canceller); - - return 0; -} - -static const struct ast_data_handler dahdi_status_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = dahdi_status_data_provider_get -}; - -static const struct ast_data_handler dahdi_channels_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = dahdi_channels_data_provider_get -}; - -static const struct ast_data_handler dahdi_version_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = dahdi_version_data_provider_get -}; - -static const struct ast_data_entry dahdi_data_providers[] = { - AST_DATA_ENTRY("asterisk/channel/dahdi/status", &dahdi_status_data_provider), - AST_DATA_ENTRY("asterisk/channel/dahdi/channels", &dahdi_channels_data_provider), - AST_DATA_ENTRY("asterisk/channel/dahdi/version", &dahdi_version_data_provider) -}; - /*! * \brief Load the module * @@ -19608,8 +19377,6 @@ static int load_module(void) #endif ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli)); - /* register all the data providers */ - ast_data_register_multiple(dahdi_data_providers, ARRAY_LEN(dahdi_data_providers)); memset(round_robin, 0, sizeof(round_robin)); ast_manager_register_xml("DAHDITransfer", 0, action_transfer); ast_manager_register_xml("DAHDIHangup", 0, action_transferhangup); diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index d15b55d725f..f40873e9dcb 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -106,7 +106,6 @@ #include "asterisk/timing.h" #include "asterisk/taskprocessor.h" #include "asterisk/test.h" -#include "asterisk/data.h" #include "asterisk/security_events.h" #include "asterisk/stasis_endpoints.h" #include "asterisk/bridge.h" @@ -1950,19 +1949,6 @@ static int iax2_parse_allow_disallow(struct iax2_codec_pref *pref, iax2_format * return res; } -static int iax2_data_add_codecs(struct ast_data *root, const char *node_name, iax2_format formats) -{ - int res; - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!cap) { - return -1; - } - iax2_format_compatibility_bitfield2cap(formats, cap); - res = ast_data_add_codecs(root, node_name, cap); - ao2_ref(cap, -1); - return res; -} - /*! * \note The only member of the peer passed here guaranteed to be set is the name field */ @@ -14555,129 +14541,6 @@ static struct ast_cli_entry cli_iax2[] = { #endif /* IAXTESTS */ }; -#ifdef TEST_FRAMEWORK -AST_TEST_DEFINE(test_iax2_peers_get) -{ - struct ast_data_query query = { - .path = "/asterisk/channel/iax2/peers", - .search = "peers/peer/name=test_peer_data_provider" - }; - struct ast_data *node; - struct iax2_peer *peer; - - switch (cmd) { - case TEST_INIT: - info->name = "iax2_peers_get_data_test"; - info->category = "/main/data/iax2/peers/"; - info->summary = "IAX2 peers data providers unit test"; - info->description = - "Tests whether the IAX2 peers data provider implementation works as expected."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - /* build a test peer */ - peer = build_peer("test_peer_data_provider", NULL, NULL, 0); - if (!peer) { - return AST_TEST_FAIL; - } - peer->expiry= 1010; - ao2_link(peers, peer); - - node = ast_data_get(&query); - if (!node) { - ao2_unlink(peers, peer); - peer_unref(peer); - return AST_TEST_FAIL; - } - - /* check returned data node. */ - if (strcmp(ast_data_retrieve_string(node, "peer/name"), "test_peer_data_provider")) { - ao2_unlink(peers, peer); - peer_unref(peer); - ast_data_free(node); - return AST_TEST_FAIL; - } - - if (ast_data_retrieve_int(node, "peer/expiry") != 1010) { - ao2_unlink(peers, peer); - peer_unref(peer); - ast_data_free(node); - return AST_TEST_FAIL; - } - - /* release resources */ - ast_data_free(node); - - ao2_unlink(peers, peer); - peer_unref(peer); - - return AST_TEST_PASS; -} - -AST_TEST_DEFINE(test_iax2_users_get) -{ - struct ast_data_query query = { - .path = "/asterisk/channel/iax2/users", - .search = "users/user/name=test_user_data_provider" - }; - struct ast_data *node; - struct iax2_user *user; - - switch (cmd) { - case TEST_INIT: - info->name = "iax2_users_get_data_test"; - info->category = "/main/data/iax2/users/"; - info->summary = "IAX2 users data providers unit test"; - info->description = - "Tests whether the IAX2 users data provider implementation works as expected."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - user = build_user("test_user_data_provider", NULL, NULL, 0); - if (!user) { - ast_test_status_update(test, "Failed to build a test user\n"); - return AST_TEST_FAIL; - } - user->amaflags = 1010; - ao2_link(users, user); - - node = ast_data_get(&query); - if (!node) { - ast_test_status_update(test, "The data query to find our test user failed\n"); - ao2_unlink(users, user); - user_unref(user); - return AST_TEST_FAIL; - } - - if (strcmp(ast_data_retrieve_string(node, "user/name"), "test_user_data_provider")) { - ast_test_status_update(test, "Our data results did not return the test user created in the previous step.\n"); - ao2_unlink(users, user); - user_unref(user); - ast_data_free(node); - return AST_TEST_FAIL; - } - - if (ast_data_retrieve_int(node, "user/amaflags/value") != 1010) { - ast_test_status_update(test, "The amaflags field in our test user was '%d' not the expected value '1010'\n", ast_data_retrieve_int(node, "user/amaflags/value")); - ao2_unlink(users, user); - user_unref(user); - ast_data_free(node); - return AST_TEST_FAIL; - } - - ast_data_free(node); - - ao2_unlink(users, user); - user_unref(user); - - return AST_TEST_PASS; -} -#endif - static void cleanup_thread_list(void *head) { AST_LIST_HEAD(iax2_thread_list, iax2_thread); @@ -14743,11 +14606,6 @@ static int __unload_module(void) ast_manager_unregister( "IAXnetstats" ); ast_manager_unregister( "IAXregistry" ); ast_unregister_application(papp); -#ifdef TEST_FRAMEWORK - AST_TEST_UNREGISTER(test_iax2_peers_get); - AST_TEST_UNREGISTER(test_iax2_users_get); -#endif - ast_data_unregister(NULL); ast_cli_unregister_multiple(cli_iax2, ARRAY_LEN(cli_iax2)); ast_unregister_switch(&iax2_switch); ast_channel_unregister(&iax2_tech); @@ -14889,191 +14747,6 @@ static int load_objects(void) return -1; } - -#define DATA_EXPORT_IAX2_PEER(MEMBER) \ - MEMBER(iax2_peer, name, AST_DATA_STRING) \ - MEMBER(iax2_peer, username, AST_DATA_STRING) \ - MEMBER(iax2_peer, secret, AST_DATA_PASSWORD) \ - MEMBER(iax2_peer, dbsecret, AST_DATA_PASSWORD) \ - MEMBER(iax2_peer, outkey, AST_DATA_STRING) \ - MEMBER(iax2_peer, regexten, AST_DATA_STRING) \ - MEMBER(iax2_peer, context, AST_DATA_STRING) \ - MEMBER(iax2_peer, peercontext, AST_DATA_STRING) \ - MEMBER(iax2_peer, mailbox, AST_DATA_STRING) \ - MEMBER(iax2_peer, mohinterpret, AST_DATA_STRING) \ - MEMBER(iax2_peer, mohsuggest, AST_DATA_STRING) \ - MEMBER(iax2_peer, inkeys, AST_DATA_STRING) \ - MEMBER(iax2_peer, cid_num, AST_DATA_STRING) \ - MEMBER(iax2_peer, cid_name, AST_DATA_STRING) \ - MEMBER(iax2_peer, zonetag, AST_DATA_STRING) \ - MEMBER(iax2_peer, parkinglot, AST_DATA_STRING) \ - MEMBER(iax2_peer, expiry, AST_DATA_SECONDS) \ - MEMBER(iax2_peer, callno, AST_DATA_INTEGER) \ - MEMBER(iax2_peer, lastms, AST_DATA_MILLISECONDS) \ - MEMBER(iax2_peer, maxms, AST_DATA_MILLISECONDS) \ - MEMBER(iax2_peer, pokefreqok, AST_DATA_MILLISECONDS) \ - MEMBER(iax2_peer, pokefreqnotok, AST_DATA_MILLISECONDS) \ - MEMBER(iax2_peer, historicms, AST_DATA_INTEGER) \ - MEMBER(iax2_peer, smoothing, AST_DATA_BOOLEAN) \ - MEMBER(iax2_peer, maxcallno, AST_DATA_INTEGER) - -AST_DATA_STRUCTURE(iax2_peer, DATA_EXPORT_IAX2_PEER); - -static int peers_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct ast_data *data_peer; - struct iax2_peer *peer; - struct ao2_iterator i; - char status[20]; - struct ast_str *encmethods = ast_str_alloca(256); - - i = ao2_iterator_init(peers, 0); - while ((peer = ao2_iterator_next(&i))) { - data_peer = ast_data_add_node(data_root, "peer"); - if (!data_peer) { - peer_unref(peer); - continue; - } - - ast_data_add_structure(iax2_peer, data_peer, peer); - - iax2_data_add_codecs(data_peer, "codecs", peer->capability); - - peer_status(peer, status, sizeof(status)); - ast_data_add_str(data_peer, "status", status); - - ast_data_add_str(data_peer, "host", ast_sockaddr_stringify_host(&peer->addr)); - - ast_data_add_str(data_peer, "mask", ast_sockaddr_stringify_addr(&peer->mask)); - - ast_data_add_int(data_peer, "port", ast_sockaddr_port(&peer->addr)); - - ast_data_add_bool(data_peer, "trunk", ast_test_flag64(peer, IAX_TRUNK)); - - ast_data_add_bool(data_peer, "dynamic", ast_test_flag64(peer, IAX_DYNAMIC)); - - encmethods_to_str(peer->encmethods, &encmethods); - ast_data_add_str(data_peer, "encryption", peer->encmethods ? ast_str_buffer(encmethods) : "no"); - - peer_unref(peer); - - if (!ast_data_search_match(search, data_peer)) { - ast_data_remove_node(data_root, data_peer); - } - } - ao2_iterator_destroy(&i); - - return 0; -} - -#define DATA_EXPORT_IAX2_USER(MEMBER) \ - MEMBER(iax2_user, name, AST_DATA_STRING) \ - MEMBER(iax2_user, dbsecret, AST_DATA_PASSWORD) \ - MEMBER(iax2_user, accountcode, AST_DATA_STRING) \ - MEMBER(iax2_user, mohinterpret, AST_DATA_STRING) \ - MEMBER(iax2_user, mohsuggest, AST_DATA_STRING) \ - MEMBER(iax2_user, inkeys, AST_DATA_STRING) \ - MEMBER(iax2_user, language, AST_DATA_STRING) \ - MEMBER(iax2_user, cid_num, AST_DATA_STRING) \ - MEMBER(iax2_user, cid_name, AST_DATA_STRING) \ - MEMBER(iax2_user, parkinglot, AST_DATA_STRING) \ - MEMBER(iax2_user, maxauthreq, AST_DATA_INTEGER) \ - MEMBER(iax2_user, curauthreq, AST_DATA_INTEGER) - -AST_DATA_STRUCTURE(iax2_user, DATA_EXPORT_IAX2_USER); - -static int users_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct ast_data *data_user, *data_authmethods, *data_enum_node; - struct iax2_user *user; - struct ao2_iterator i; - struct ast_str *auth; - char *pstr = ""; - - if (!(auth = ast_str_create(90))) { - ast_log(LOG_ERROR, "Unable to create temporary string for storing 'secret'\n"); - return 0; - } - - i = ao2_iterator_init(users, 0); - for (; (user = ao2_iterator_next(&i)); user_unref(user)) { - data_user = ast_data_add_node(data_root, "user"); - if (!data_user) { - continue; - } - - ast_data_add_structure(iax2_user, data_user, user); - - iax2_data_add_codecs(data_user, "codecs", user->capability); - - if (!ast_strlen_zero(user->secret)) { - ast_str_set(&auth, 0, "%s", user->secret); - } else if (!ast_strlen_zero(user->inkeys)) { - ast_str_set(&auth, 0, "Key: %s", user->inkeys); - } else { - ast_str_set(&auth, 0, "no secret"); - } - ast_data_add_password(data_user, "secret", ast_str_buffer(auth)); - - ast_data_add_str(data_user, "context", user->contexts ? user->contexts->context : DEFAULT_CONTEXT); - - /* authmethods */ - data_authmethods = ast_data_add_node(data_user, "authmethods"); - if (!data_authmethods) { - ast_data_remove_node(data_root, data_user); - continue; - } - ast_data_add_bool(data_authmethods, "rsa", user->authmethods & IAX_AUTH_RSA); - ast_data_add_bool(data_authmethods, "md5", user->authmethods & IAX_AUTH_MD5); - ast_data_add_bool(data_authmethods, "plaintext", user->authmethods & IAX_AUTH_PLAINTEXT); - - /* amaflags */ - data_enum_node = ast_data_add_node(data_user, "amaflags"); - if (!data_enum_node) { - ast_data_remove_node(data_root, data_user); - continue; - } - ast_data_add_int(data_enum_node, "value", user->amaflags); - ast_data_add_str(data_enum_node, "text", ast_channel_amaflags2string(user->amaflags)); - - ast_data_add_bool(data_user, "access-control", ast_acl_list_is_empty(user->acl) ? 0 : 1); - - if (ast_test_flag64(user, IAX_CODEC_NOCAP)) { - pstr = "REQ only"; - } else if (ast_test_flag64(user, IAX_CODEC_NOPREFS)) { - pstr = "disabled"; - } else { - pstr = ast_test_flag64(user, IAX_CODEC_USER_FIRST) ? "caller" : "host"; - } - ast_data_add_str(data_user, "codec-preferences", pstr); - - if (!ast_data_search_match(search, data_user)) { - ast_data_remove_node(data_root, data_user); - } - } - ao2_iterator_destroy(&i); - - ast_free(auth); - return 0; -} - -static const struct ast_data_handler peers_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = peers_data_provider_get -}; - -static const struct ast_data_handler users_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = users_data_provider_get -}; - -static const struct ast_data_entry iax2_data_providers[] = { - AST_DATA_ENTRY("asterisk/channel/iax2/peers", &peers_data_provider), - AST_DATA_ENTRY("asterisk/channel/iax2/users", &users_data_provider), -}; - /*! * \brief Load the module * @@ -15173,13 +14846,6 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } -#ifdef TEST_FRAMEWORK - AST_TEST_REGISTER(test_iax2_peers_get); - AST_TEST_REGISTER(test_iax2_users_get); -#endif - - /* Register AstData providers */ - ast_data_register_multiple(iax2_data_providers, ARRAY_LEN(iax2_data_providers)); ast_cli_register_multiple(cli_iax2, ARRAY_LEN(cli_iax2)); ast_register_application_xml(papp, iax2_prov_app); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index aaeb01e1398..af82678668b 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -263,7 +263,6 @@ #include "asterisk/threadstorage.h" #include "asterisk/translate.h" #include "asterisk/ast_version.h" -#include "asterisk/data.h" #include "asterisk/aoc.h" #include "asterisk/message.h" #include "sip/include/sip.h" @@ -34530,75 +34529,6 @@ AST_TEST_DEFINE(test_sip_mwi_subscribe_parse) return res; } -AST_TEST_DEFINE(test_sip_peers_get) -{ - struct sip_peer *peer; - struct ast_data *node; - struct ast_data_query query = { - .path = "/asterisk/channel/sip/peers", - .search = "peers/peer/name=test_peer_data_provider" - }; - - switch (cmd) { - case TEST_INIT: - info->name = "sip_peers_get_data_test"; - info->category = "/main/data/sip/peers/"; - info->summary = "SIP peers data providers unit test"; - info->description = - "Tests whether the SIP peers data provider implementation works as expected."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - /* Create the peer that we will retrieve. */ - peer = build_peer("test_peer_data_provider", NULL, NULL, 0, 0); - if (!peer) { - return AST_TEST_FAIL; - } - peer->type = SIP_TYPE_USER; - peer->call_limit = 10; - ao2_link(peers, peer); - - /* retrieve the chan_sip/peers tree and check the created peer. */ - node = ast_data_get(&query); - if (!node) { - ao2_unlink(peers, peer); - ao2_ref(peer, -1); - return AST_TEST_FAIL; - } - - /* compare item. */ - if (strcmp(ast_data_retrieve_string(node, "peer/name"), "test_peer_data_provider")) { - ao2_unlink(peers, peer); - ao2_ref(peer, -1); - ast_data_free(node); - return AST_TEST_FAIL; - } - - if (strcmp(ast_data_retrieve_string(node, "peer/type"), "user")) { - ao2_unlink(peers, peer); - ao2_ref(peer, -1); - ast_data_free(node); - return AST_TEST_FAIL; - } - - if (ast_data_retrieve_int(node, "peer/call_limit") != 10) { - ao2_unlink(peers, peer); - ao2_ref(peer, -1); - ast_data_free(node); - return AST_TEST_FAIL; - } - - /* release resources */ - ast_data_free(node); - - ao2_unlink(peers, peer); - ao2_ref(peer, -1); - - return AST_TEST_PASS; -} - /*! * \brief Imitation TCP reception loop * @@ -35130,170 +35060,6 @@ AST_TEST_DEFINE(get_in_brackets_const_test) #endif -#define DATA_EXPORT_SIP_PEER(MEMBER) \ - MEMBER(sip_peer, name, AST_DATA_STRING) \ - MEMBER(sip_peer, secret, AST_DATA_PASSWORD) \ - MEMBER(sip_peer, md5secret, AST_DATA_PASSWORD) \ - MEMBER(sip_peer, remotesecret, AST_DATA_PASSWORD) \ - MEMBER(sip_peer, context, AST_DATA_STRING) \ - MEMBER(sip_peer, subscribecontext, AST_DATA_STRING) \ - MEMBER(sip_peer, username, AST_DATA_STRING) \ - MEMBER(sip_peer, accountcode, AST_DATA_STRING) \ - MEMBER(sip_peer, tohost, AST_DATA_STRING) \ - MEMBER(sip_peer, regexten, AST_DATA_STRING) \ - MEMBER(sip_peer, fromuser, AST_DATA_STRING) \ - MEMBER(sip_peer, fromdomain, AST_DATA_STRING) \ - MEMBER(sip_peer, fullcontact, AST_DATA_STRING) \ - MEMBER(sip_peer, cid_num, AST_DATA_STRING) \ - MEMBER(sip_peer, cid_name, AST_DATA_STRING) \ - MEMBER(sip_peer, vmexten, AST_DATA_STRING) \ - MEMBER(sip_peer, language, AST_DATA_STRING) \ - MEMBER(sip_peer, mohinterpret, AST_DATA_STRING) \ - MEMBER(sip_peer, mohsuggest, AST_DATA_STRING) \ - MEMBER(sip_peer, parkinglot, AST_DATA_STRING) \ - MEMBER(sip_peer, useragent, AST_DATA_STRING) \ - MEMBER(sip_peer, mwi_from, AST_DATA_STRING) \ - MEMBER(sip_peer, engine, AST_DATA_STRING) \ - MEMBER(sip_peer, unsolicited_mailbox, AST_DATA_STRING) \ - MEMBER(sip_peer, is_realtime, AST_DATA_BOOLEAN) \ - MEMBER(sip_peer, host_dynamic, AST_DATA_BOOLEAN) \ - MEMBER(sip_peer, autoframing, AST_DATA_BOOLEAN) \ - MEMBER(sip_peer, inuse, AST_DATA_INTEGER) \ - MEMBER(sip_peer, ringing, AST_DATA_INTEGER) \ - MEMBER(sip_peer, onhold, AST_DATA_INTEGER) \ - MEMBER(sip_peer, call_limit, AST_DATA_INTEGER) \ - MEMBER(sip_peer, t38_maxdatagram, AST_DATA_INTEGER) \ - MEMBER(sip_peer, maxcallbitrate, AST_DATA_INTEGER) \ - MEMBER(sip_peer, rtptimeout, AST_DATA_SECONDS) \ - MEMBER(sip_peer, rtpholdtimeout, AST_DATA_SECONDS) \ - MEMBER(sip_peer, rtpkeepalive, AST_DATA_SECONDS) \ - MEMBER(sip_peer, lastms, AST_DATA_MILLISECONDS) \ - MEMBER(sip_peer, maxms, AST_DATA_MILLISECONDS) \ - MEMBER(sip_peer, qualifyfreq, AST_DATA_MILLISECONDS) \ - MEMBER(sip_peer, timer_t1, AST_DATA_MILLISECONDS) \ - MEMBER(sip_peer, timer_b, AST_DATA_MILLISECONDS) \ - MEMBER(sip_peer, description, AST_DATA_STRING) - -AST_DATA_STRUCTURE(sip_peer, DATA_EXPORT_SIP_PEER); - -static int peers_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct sip_peer *peer; - struct ao2_iterator i; - struct ast_data *data_peer, *data_peer_mailboxes = NULL, *data_peer_mailbox, *enum_node; - struct ast_data *data_sip_options; - int total_mailboxes, x; - struct sip_mailbox *mailbox; - - i = ao2_iterator_init(peers, 0); - while ((peer = ao2_iterator_next(&i))) { - ao2_lock(peer); - - data_peer = ast_data_add_node(data_root, "peer"); - if (!data_peer) { - ao2_unlock(peer); - ao2_ref(peer, -1); - continue; - } - - ast_data_add_structure(sip_peer, data_peer, peer); - - /* transfer mode */ - enum_node = ast_data_add_node(data_peer, "allowtransfer"); - if (!enum_node) { - ao2_unlock(peer); - ao2_ref(peer, -1); - continue; - } - ast_data_add_str(enum_node, "text", transfermode2str(peer->allowtransfer)); - ast_data_add_int(enum_node, "value", peer->allowtransfer); - - /* transports */ - ast_data_add_str(data_peer, "transports", get_transport_list(peer->transports)); - - /* peer type */ - if ((peer->type & SIP_TYPE_USER) && (peer->type & SIP_TYPE_PEER)) { - ast_data_add_str(data_peer, "type", "friend"); - } else if (peer->type & SIP_TYPE_PEER) { - ast_data_add_str(data_peer, "type", "peer"); - } else if (peer->type & SIP_TYPE_USER) { - ast_data_add_str(data_peer, "type", "user"); - } - - /* mailboxes */ - total_mailboxes = 0; - AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { - if (!total_mailboxes) { - data_peer_mailboxes = ast_data_add_node(data_peer, "mailboxes"); - if (!data_peer_mailboxes) { - break; - } - total_mailboxes++; - } - - data_peer_mailbox = ast_data_add_node(data_peer_mailboxes, "mailbox"); - if (!data_peer_mailbox) { - continue; - } - ast_data_add_str(data_peer_mailbox, "id", mailbox->id); - } - - /* amaflags */ - enum_node = ast_data_add_node(data_peer, "amaflags"); - if (!enum_node) { - ao2_unlock(peer); - ao2_ref(peer, -1); - continue; - } - ast_data_add_int(enum_node, "value", peer->amaflags); - ast_data_add_str(enum_node, "text", ast_channel_amaflags2string(peer->amaflags)); - - /* sip options */ - data_sip_options = ast_data_add_node(data_peer, "sipoptions"); - if (!data_sip_options) { - ao2_unlock(peer); - ao2_ref(peer, -1); - continue; - } - for (x = 0 ; x < ARRAY_LEN(sip_options); x++) { - ast_data_add_bool(data_sip_options, sip_options[x].text, peer->sipoptions & sip_options[x].id); - } - - /* callingpres */ - enum_node = ast_data_add_node(data_peer, "callingpres"); - if (!enum_node) { - ao2_unlock(peer); - ao2_ref(peer, -1); - continue; - } - ast_data_add_int(enum_node, "value", peer->callingpres); - ast_data_add_str(enum_node, "text", ast_describe_caller_presentation(peer->callingpres)); - - /* codecs */ - ast_data_add_codecs(data_peer, "codecs", peer->caps); - - if (!ast_data_search_match(search, data_peer)) { - ast_data_remove_node(data_root, data_peer); - } - - ao2_unlock(peer); - ao2_ref(peer, -1); - } - ao2_iterator_destroy(&i); - - return 0; -} - -static const struct ast_data_handler peers_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = peers_data_provider_get -}; - -static const struct ast_data_entry sip_data_providers[] = { - AST_DATA_ENTRY("asterisk/channel/sip/peers", &peers_data_provider), -}; - static const struct ast_sip_api_tech chan_sip_api_provider = { .version = AST_SIP_API_VERSION, .name = "chan_sip", @@ -35414,15 +35180,11 @@ static int load_module(void) } #ifdef TEST_FRAMEWORK - AST_TEST_REGISTER(test_sip_peers_get); AST_TEST_REGISTER(test_sip_mwi_subscribe_parse); AST_TEST_REGISTER(test_tcp_message_fragmentation); AST_TEST_REGISTER(get_in_brackets_const_test); #endif - /* Register AstData providers */ - ast_data_register_multiple(sip_data_providers, ARRAY_LEN(sip_data_providers)); - /* Register all CLI functions for SIP */ ast_cli_register_multiple(cli_sip, ARRAY_LEN(cli_sip)); @@ -35549,14 +35311,10 @@ static int unload_module(void) #ifdef TEST_FRAMEWORK ast_unregister_application(app_sipsendcustominfo); - AST_TEST_UNREGISTER(test_sip_peers_get); AST_TEST_UNREGISTER(test_sip_mwi_subscribe_parse); AST_TEST_UNREGISTER(test_tcp_message_fragmentation); AST_TEST_UNREGISTER(get_in_brackets_const_test); #endif - /* Unregister all the AstData providers */ - ast_data_unregister(NULL); - /* Unregister CLI commands */ ast_cli_unregister_multiple(cli_sip, ARRAY_LEN(cli_sip)); diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index b3c2b200206..e989b16fd1c 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -44,7 +44,6 @@ int ast_named_locks_init(void); /*!< Provided by named_locks.c */ int ast_file_init(void); /*!< Provided by file.c */ int ast_features_init(void); /*!< Provided by features.c */ void ast_autoservice_init(void); /*!< Provided by autoservice.c */ -int ast_data_init(void); /*!< Provided by data.c */ int ast_http_init(void); /*!< Provided by http.c */ int ast_http_reload(void); /*!< Provided by http.c */ int ast_tps_init(void); /*!< Provided by taskprocessor.c */ diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 005803d5cad..197cc990dbd 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -174,7 +174,7 @@ extern "C" { #include "asterisk/linkedlists.h" #include "asterisk/stringfields.h" #include "asterisk/datastore.h" -#include "asterisk/data.h" +#include "asterisk/format_cap.h" #include "asterisk/channelstate.h" #include "asterisk/ccss.h" #include "asterisk/framehook.h" @@ -3838,27 +3838,6 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc */ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame); -/*! - * \brief Insert into an astdata tree, the channel structure. - * \param[in] tree The ast data tree. - * \param[in] chan The channel structure to add to tree. - * \param[in] add_bridged Add the bridged channel to the structure. - * \retval <0 on error. - * \retval 0 on success. - */ -int ast_channel_data_add_structure(struct ast_data *tree, struct ast_channel *chan, int add_bridged); - -/*! - * \brief Compare to channel structures using the data api. - * \param[in] tree The search tree generated by the data api. - * \param[in] chan The channel to compare. - * \param[in] structure_name The name of the node of the channel structure. - * \retval 0 The structure matches. - * \retval 1 The structure doesn't matches. - */ -int ast_channel_data_cmp_structure(const struct ast_data_search *tree, struct ast_channel *chan, - const char *structure_name); - /*! * \since 1.8 * \brief Run a redirecting interception macro and update a channel's redirecting information diff --git a/include/asterisk/data.h b/include/asterisk/data.h deleted file mode 100644 index d6da1f7d64c..00000000000 --- a/include/asterisk/data.h +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2009, Eliel C. Sardanons (LU1ALY) - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! - * \file - * \brief Data retrieval API. - * \author Brett Bryant - * \author Eliel C. Sardanons (LU1ALY) - * \arg \ref AstDataRetrieval - */ - -#ifndef ASTERISK_DATA_H -#define ASTERISK_DATA_H - -#include "asterisk/frame.h" -#include "asterisk/format_cap.h" - -/*! - * \page AstDataRetrieval The Asterisk DATA retrieval API. - * - * This module implements an abstraction for retrieving asterisk data and - * export it. - * - * \section USAGE - * - * \subsection Provider - * - * \b Register - * - * To register a callback use: - * - * \code - * static const struct ast_data_handler callback_handler = { - * .get = callback_handler_get_function, - * }; - * - * ast_data_register("/node/path", &callback_handler); - * \endcode - * - * If you instead want to register multiple nodes at once use: - * \code - * static const struct ast_data_handler handler_struct1 = { - * .get = handler_callback_read, - * }; - * ... other handlers ... - * - * static const struct ast_data_entry list_providers[] = { - * AST_DATA_ENTRY("/path1/node1", &handler_struct1), - * AST_DATA_ENTRY("/path2/node2", &handler_struct2), - * AST_DATA_ENTRY("/path3/node3", &handler_struct3), - * }; - * - * ... - * - * ast_data_register_multiple(list_providers, ARRAY_LEN(list_providers)); - * \endcode - * - * \b Unregister - * - * To unregister a callback function already registered you can just call: - * - * \code - * ast_data_unregister(NULL); - * \endcode - * And every node registered by the current module (file) will be unregistered. - * If you want to unregister a specific node use: - * - * \code - * ast_data_unregister("/node/path"); - * \endcode - * - * \b Implementation - * - * A simple callback function implementation: - * - * \code - * #include - * - * struct test_structure { - * int a; - * double b; - * }; - * - * DATA_EXPORT_TEST_STRUCTURE(MEMBER) \ - * MEMBER(test_structure, a, AST_DATA_INTEGER) \ - * MEMBER(test_structure, b, AST_DATA_DOUBLE) - * - * AST_DATA_STRUCTURE(test_structure, DATA_EXPORT_TEST_STRUCTURE) - * - * static int my_callback_function(struct ast_data_search *search, - * struct ast_data *root_node) - * { - * struct ast_data *internal_node; - * struct test_structure ts = { - * .a = 10, - * .b = 20 - * }; - * - * internal_node = ast_data_add_node(root_node, "test_node"); - * if (!internal_node) { - * return -1; - * } - * - * ast_data_add_structure(test_structure, internal_node, ts); - * - * if (!ast_data_search_match(search, internal_node)) { - * ast_data_remove_node(root_node, internal_node); - * } - * - * return 0; - * } - * - * \endcode - * - * \subsection Get - * - * \b Getting \b the \b tree - * - * To get the tree you need to create a query, a query is based on three parameters - * a \b path to the provider, a \b search condition and a \b filter condition. - * \code - * struct ast_data *result; - * struct ast_data_query query = { - * .path = "/asterisk/application/app_queue/queues", - * .search = "/queues/queue/name=queue1", - * .filter = "/queues/queue/name|wrapuptime|members/member/interface" - * }; - * - * result = ast_data_get(&query); - * \endcode - * - * After using it you need to release the allocated memory of the returned tree: - * \code - * ast_data_free(result); - * \endcode - * - * \b Iterate - * - * To retrieve nodes from the tree, it is possible to iterate through the returned - * nodes of the tree using: - * \code - * struct ast_data_iterator *i; - * struct ast_data *internal_node; - * - * i = ast_data_iterator_init(result_tree, "path/node_name"); - * while ((internal_node = ast_data_iterator_next(i))) { - * ... do something with node ... - * } - * ast_data_iterator_end(i); - * \endcode - * node_name is the name of the nodes to retrieve and path is the path to the internal - * nodes to retrieve (if needed). - * - * \b Retrieving - * - * After getting the node you where searching for, you will need to retrieve its value, - * to do that you may use one of the ast_data_retrieve_##type functions: - * \code - * int a = ast_data_retrieve_int(tree, "path/to/the/node"); - * double b = ast_data_retrieve_dbl(tree, "path/to/the/node"); - * unsigned int c = ast_data_retrieve_bool(tree, "path/to/the/node"); - * char *d = ast_data_retrieve_string(tree, "path/to/the/node"); - * struct sockaddr_in e = ast_data_retrieve_ipaddr(tree, "path/to/the/node"); - * unsigned int f = ast_data_retrieve_uint(tree, "path/to/the/node"); - * void *g = ast_data_retrieve_ptr(tree, "path/to/the/node"); - * \endcode - * - */ - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif - -/*! \brief The data type of the data node. */ -enum ast_data_type { - AST_DATA_CONTAINER, - AST_DATA_INTEGER, - AST_DATA_UNSIGNED_INTEGER, - AST_DATA_DOUBLE, - AST_DATA_BOOLEAN, - AST_DATA_STRING, - AST_DATA_CHARACTER, - AST_DATA_PASSWORD, - AST_DATA_IPADDR, - AST_DATA_TIMESTAMP, - AST_DATA_SECONDS, - AST_DATA_MILLISECONDS, - AST_DATA_POINTER -}; - -/*! \brief The Data API structures version. */ -#define AST_DATA_HANDLER_VERSION 1 -#define AST_DATA_QUERY_VERSION 1 - -/*! \brief opaque definition of an ast_data handler, a tree node. */ -struct ast_data; - -/*! \brief opaque definition of an ast_data_iterator handler. */ -struct ast_data_iterator; - -/*! \brief opaque definition of an ast_data_search structure. */ -struct ast_data_search; - -/*! \brief structure retrieved from a node, with the nodes content. */ -struct ast_data_retrieve { - /*! \brief The type of the node retrieved. */ - enum ast_data_type type; - - union { - char AST_DATA_CHARACTER; - char *AST_DATA_STRING; - char *AST_DATA_PASSWORD; - int AST_DATA_INTEGER; - unsigned int AST_DATA_TIMESTAMP; - unsigned int AST_DATA_SECONDS; - unsigned int AST_DATA_MILLISECONDS; - double AST_DATA_DOUBLE; - unsigned int AST_DATA_UNSIGNED_INTEGER; - unsigned int AST_DATA_BOOLEAN; - void *AST_DATA_POINTER; - struct in_addr AST_DATA_IPADDR; - void *AST_DATA_CONTAINER; - } value; -}; - -/*! - * \brief The get callback definition. - */ -typedef int (*ast_data_get_cb)(const struct ast_data_search *search, - struct ast_data *root); - -/*! \brief The structure of the node handler. */ -struct ast_data_handler { - /*! \brief Structure version. */ - uint32_t version; - /*! \brief Data get callback implementation. */ - ast_data_get_cb get; -}; - -/*! \brief This entries are for multiple registers. */ -struct ast_data_entry { - /*! \brief Path of the node to register. */ - const char *path; - /*! \brief Data handler structure. */ - const struct ast_data_handler *handler; -}; - -#define AST_DATA_ENTRY(__path, __handler) { .path = __path, .handler = __handler } - -/*! \brief A query to the data API is specified in this structure. */ -struct ast_data_query { - /*! \brief Data query version. */ - uint32_t version; - /*! \brief Path to the node to retrieve. */ - char *path; - /*! \brief Filter string, return the internal nodes specified here. - * Setting it to NULL will return every internal node. */ - char *filter; - /*! \brief Search condition. */ - char *search; -}; - -/*! \brief Map the members of a structure. */ -struct ast_data_mapping_structure { - /*! \brief structure member name. */ - const char *name; - /*! \brief structure member type. */ - enum ast_data_type type; - /*! \brief member getter. */ - union { - char (*AST_DATA_CHARACTER)(void *ptr); - char *(*AST_DATA_STRING)(void *ptr); - char *(*AST_DATA_PASSWORD)(void *ptr); - int (*AST_DATA_INTEGER)(void *ptr); - int (*AST_DATA_TIMESTAMP)(void *ptr); - int (*AST_DATA_SECONDS)(void *ptr); - int (*AST_DATA_MILLISECONDS)(void *ptr); - double (*AST_DATA_DOUBLE)(void *ptr); - unsigned int (*AST_DATA_UNSIGNED_INTEGER)(void *ptr); - unsigned int (*AST_DATA_BOOLEAN)(void *ptr); - void *(*AST_DATA_POINTER)(void *ptr); - struct in_addr (*AST_DATA_IPADDR)(void *ptr); - void *(*AST_DATA_CONTAINER)(void *ptr); - } get; -}; - -/* Generate the structure and the functions to access the members of a structure. */ -#define AST_DATA_STRUCTURE(__struct, __name) \ - __name(__AST_DATA_MAPPING_FUNCTION); \ - static const struct ast_data_mapping_structure __data_mapping_structure_##__struct[] = { \ - __name(__AST_DATA_MAPPING_STRUCTURE) \ - } - -/* Generate the structure to access the members and setup the pointer of the getter. */ -#define __AST_DATA_MAPPING_STRUCTURE(__structure, __member, __type) \ - { .name = #__member, .get.__type = data_mapping_structure_get_##__structure##__member, \ - .type = __type }, - -/* based on the data type, specifify the type of return value for the getter function. */ -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_PASSWORD(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_PASSWORD, char *) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_STRING(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_STRING, char *) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_CHARACTER(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_CHARACTER, char) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_INTEGER(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_INTEGER, int) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_TIMESTAMP(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_INTEGER, int) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_SECONDS(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_INTEGER, int) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_MILLISECONDS(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_INTEGER, int) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_UNSIGNED_INTEGER(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_UNSIGNED_INTEGER, unsigned int) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_BOOLEAN(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_BOOLEAN, unsigned int) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_POINTER(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_POINTER, void *) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_IPADDR(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_IPADDR, struct in_addr) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_DOUBLE(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_DBL, double) -#define __AST_DATA_MAPPING_FUNCTION_AST_DATA_CONTAINER(__structure, __member) \ - __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, AST_DATA_CONTAINER, void *) - -#define __AST_DATA_MAPPING_FUNCTION(__structure, __member, __type) \ - __AST_DATA_MAPPING_FUNCTION_##__type(__structure, __member) - -/* Create the function to retrieve a member of the structure. */ -#define __AST_DATA_MAPPING_FUNCTION_TYPE(__structure, __member, __type, __real_type) \ - static __real_type data_mapping_structure_get_##__structure##__member(void *ptr) { \ - struct __structure *struct_##__member = (struct __structure *) ptr; \ - return (__real_type) struct_##__member->__member; \ - } - -/*! - * \brief Register a data provider. - * \param[in] path The path of the node to register. - * \param[in] handler The structure defining this node handler. - * \param[in] registrar Who is registering this node. - * \param[in] mod The module registering this handler. - * \see ast_data_unregister - * \retval <0 on error. - * \retval 0 on success. - * \see __ast_data_unregister, __ast_data_register_multiple - */ -int __ast_data_register(const char *path, const struct ast_data_handler *handler, - const char *registrar, struct ast_module *mod); -#define ast_data_register(path, handler) __ast_data_register(path, handler, __FILE__, AST_MODULE_SELF) -#define ast_data_register_core(path, handler) __ast_data_register(path, handler, __FILE__, NULL) - -/*! - * \brief Register multiple data providers at once. - * \param[in] data_entries An array of data_entries structures. - * \param[in] entries The number of entries in the data_entries array. - * \param[in] registrar Who is registering this nodes. - * \param[in] mod The module registering this handlers. - * \retval <0 on error (none of the nodes are being registered on error). - * \retval 0 on success. - * \see __ast_data_register, __ast_data_unregister - */ -int __ast_data_register_multiple(const struct ast_data_entry *data_entries, - size_t entries, const char *registrar, struct ast_module *mod); -#define ast_data_register_multiple(data_entries, entries) \ - __ast_data_register_multiple(data_entries, entries, __FILE__, AST_MODULE_SELF) -#define ast_data_register_multiple_core(data_entries, entries) \ - __ast_data_register_multiple(data_entries, entries, __FILE__, NULL) - -/*! - * \brief Unregister a data provider. - * \param[in] path Which node to unregister, if path is NULL unregister every node - * registered by the passed 'registrar'. - * \param[in] registrar Who is trying to unregister this node, only the owner (the - * one who registered the node) will be able to unregister it. - * \see ast_data_register - * \retval <0 on error. - * \retval 0 on success. - * \see __ast_data_register, __ast_data_register_multiple - */ -int __ast_data_unregister(const char *path, const char *registrar); -#define ast_data_unregister(path) __ast_data_unregister(path, __FILE__) - -/*! - * \brief Check the current generated node to know if it matches the search - * condition. - * \param[in] search The search condition. - * \param[in] data The AstData node generated. - * \return 1 If the "data" node matches the search condition. - * \return 0 If the "data" node does not matches the search condition. - * \see ast_data_remove_node - */ -int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data); - -/*! - * \brief Based on a search tree, evaluate every member of a structure against it. - * \param[in] search The search tree. - * \param[in] mapping The structure mapping. - * \param[in] mapping_len The lenght of the structure mapping. - * \param[in] structure The structure pointer. - * \param[in] structure_name The name of the structure to compare. - * \retval 0 If the structure matches. - * \retval 1 If the structure doesn't match. - */ -int __ast_data_search_cmp_structure(const struct ast_data_search *search, - const struct ast_data_mapping_structure *mapping, size_t mapping_len, - void *structure, const char *structure_name); -#define ast_data_search_cmp_structure(search, structure_name, structure, structure_name_cmp) \ - __ast_data_search_cmp_structure(search, __data_mapping_structure_##structure_name, \ - ARRAY_LEN(__data_mapping_structure_##structure_name), structure, structure_name_cmp) - -/*! - * \brief Retrieve a subtree from the asterisk data API. - * \param[in] query The query structure specifying what nodes to retrieve. - * \retval NULL on error. - * \retval non-NULL The dynamically allocated requested sub-tree (it needs to be - * released using ast_data_free. - * \see ast_data_free, ast_data_get_xml - */ -struct ast_data *ast_data_get(const struct ast_data_query *query); - -#ifdef HAVE_LIBXML2 -/*! - * \brief Retrieve a subtree from the asterisk data API in XML format.. - * \param[in] query The query structure specifying what nodes to retrieve. - * \retval NULL on error. - * \retval non-NULL The dynamically allocated requested sub-tree (it needs to be - * released using ast_data_free. - * \see ast_data_free, ast_data_get - */ -struct ast_xml_doc *ast_data_get_xml(const struct ast_data_query *query); -#endif - -/*! - * \brief Release the allocated memory of a tree. - * \param[in] root The sub-tree pointer returned by a call to ast_data_get. - * \see ast_data_get - */ -void ast_data_free(struct ast_data *root); - -/*! - * \brief Get a node type. - * \param[in] res A pointer to the ast_data result set. - * \param[in] path A path to the node to get the type. - * \return The type of the requested node type. - */ -enum ast_data_type ast_data_retrieve_type(struct ast_data *res, const char *path); - -/*! - * \brief Get the node name. - * \param[in] node The node pointer. - * \returns The node name. - */ -char *ast_data_retrieve_name(struct ast_data *node); - -/*! - * \brief Add a container child. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_node(struct ast_data *root, const char *childname); - -/*! - * \brief Add an integer node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] value The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_int(struct ast_data *root, const char *childname, - int value); - -/*! - * \brief Add a char node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] value The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_char(struct ast_data *root, const char *childname, - char value); - -/*! - * \brief Add an unsigned integer node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] value The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_uint(struct ast_data *root, const char *childname, - unsigned int value); - -/*! - * \brief Add a floating point node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] dbl The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_dbl(struct ast_data *root, const char *childname, - double dbl); -/*! - * \brief Add a ipv4 address type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] addr The ipv4 address value. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_ipaddr(struct ast_data *root, const char *childname, - struct in_addr addr); - -/*! - * \brief Add a ptr node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] ptr The pointer value to add. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_ptr(struct ast_data *root, const char *childname, - void *ptr); - -/*! - * \brief Add a password node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] string The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_password(struct ast_data *root, const char *childname, - const char *string); - -/*! - * \brief Add a timestamp node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] timestamp The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_timestamp(struct ast_data *root, const char *childname, - unsigned int timestamp); - -/*! - * \brief Add a seconds node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] seconds The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_seconds(struct ast_data *root, const char *childname, - unsigned int seconds); - -/*! - * \brief Add a milliseconds node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] milliseconds The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_milliseconds(struct ast_data *root, const char *childname, - unsigned int milliseconds); - -/*! - * \brief Add a string node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] string The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_str(struct ast_data *root, const char *childname, - const char *string); - -/*! - * \brief Add a boolean node type. - * \param[in] root The root of the ast_data to insert into. - * \param[in] childname The name of the child element to be added. - * \param[in] boolean The value for the new node. - * \retval NULL on error (memory exhaustion only). - * \retval non-NULL a newly allocated node. - */ -struct ast_data *ast_data_add_bool(struct ast_data *root, const char *childname, - unsigned int boolean); - -/*! - * \brief Add a complete structure to a node. - * \param[in] root Where to add the structure. - * \param[in] mapping The structure mapping array. - * \param[in] mapping_len The lenght of the mapping array. - * \param[in] structure The structure pointer. - * \retval 0 on success. - * \retval 1 on error. - */ -int __ast_data_add_structure(struct ast_data *root, - const struct ast_data_mapping_structure *mapping, - size_t mapping_len, void *structure); -#define ast_data_add_structure(structure_name, root, structure) \ - __ast_data_add_structure(root, __data_mapping_structure_##structure_name, \ - ARRAY_LEN(__data_mapping_structure_##structure_name), structure) - -/*! - * \brief Remove a node that was added using ast_data_add_ - * \param[in] root The root node of the node to be removed. - * \param[in] child The node pointer to remove. - */ -void ast_data_remove_node(struct ast_data *root, struct ast_data *child); - -/*! - * \brief Initialize an iterator. - * \param[in] tree The returned tree by a call to ast_data_get. - * \param[in] elements Which elements to iterate through. - * \retval NULL on error. - * \retval non-NULL A dinamically allocated iterator structure. - */ -struct ast_data_iterator *ast_data_iterator_init(struct ast_data *tree, - const char *elements); - -/*! - * \brief Release (stop using) an iterator. - * \param[in] iterator The iterator created by ast_data_iterator_start. - * \see ast_data_iterator_start - */ -void ast_data_iterator_end(struct ast_data_iterator *iterator); - -/*! - * \brief Get the next node of the tree. - * \param[in] iterator The iterator structure returned by ast_data_iterator_start. - * \retval NULL when no more nodes to return. - * \retval non-NULL A node of the ast_data tree. - * \see ast_data_iterator_start, ast_data_iterator_stop - */ -struct ast_data *ast_data_iterator_next(struct ast_data_iterator *iterator); - -/*! - * \brief Retrieve a value from a node in the tree. - * \param[in] tree The structure returned by a call to ast_data_get. - * \param[in] path The path to the node. - * \param[out] content The node content. - * \retval 0 on success. - * \retval <0 on error. - */ -int ast_data_retrieve(struct ast_data *tree, const char *path, struct ast_data_retrieve *content); - -/*! - * \brief Retrieve the integer value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline int ast_data_retrieve_int(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_INTEGER; -} - -/*! - * \brief Retrieve the character value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline char ast_data_retrieve_char(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_CHARACTER; -} - -/*! - * \brief Retrieve the boolean value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline unsigned int ast_data_retrieve_bool(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_BOOLEAN; -} - -/*! - * \brief Retrieve the unsigned integer value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline unsigned int ast_data_retrieve_uint(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_UNSIGNED_INTEGER; -} - -/*! - * \brief Retrieve the password value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline const char *ast_data_retrieve_password(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_PASSWORD; -} - -/*! - * \brief Retrieve the string value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline const char *ast_data_retrieve_string(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_STRING; -} - -/*! - * \brief Retrieve the ptr value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline void *ast_data_retrieve_ptr(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_POINTER; -} - -/*! - * \brief Retrieve the double value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline double ast_data_retrieve_dbl(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_DOUBLE; -} - -/*! - * \brief Retrieve the ipv4 address value of a node. - * \param[in] tree The tree from where to get the value. - * \param[in] path The node name or path. - * \returns The value of the node. - */ -static inline struct in_addr ast_data_retrieve_ipaddr(struct ast_data *tree, const char *path) -{ - struct ast_data_retrieve ret; - - ast_data_retrieve(tree, path, &ret); - - return ret.value.AST_DATA_IPADDR; -} - -/*! - * \brief Add the codec in the root node based on the format parameter. - * \param[in] root The astdata root node where to add the codec node. - * \param[in] node_name The name of the node where we are going to add the codec. - * \param[in] format The codec allowed. - * \return < 0 on error. - * \return 0 on success. - */ -int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_format *format); - -/*! - * \brief Add the list of codecs in the root node based on the capability parameter. - * \param[in] root The astdata root node where to add the codecs node. - * \param[in] node_name The name of the node where we are going to add the list of - * codecs. - * \param[in] capability The codecs allowed. - * \return < 0 on error. - * \return 0 on success. - */ -int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast_format_cap *capability); - -#if defined(__cplusplus) || defined(c_plusplus) -} -#endif - -#endif /* ASTERISK_DATA_H */ diff --git a/include/asterisk/indications.h b/include/asterisk/indications.h index b02be1fdf1c..309954b0572 100644 --- a/include/asterisk/indications.h +++ b/include/asterisk/indications.h @@ -28,7 +28,6 @@ #include "asterisk/astobj2.h" #include "asterisk/utils.h" -#include "asterisk/data.h" /*! * \brief Description of a tone @@ -242,12 +241,4 @@ static inline struct ast_tone_zone_sound *ast_tone_zone_sound_ref(struct ast_ton return ts; } -/*! - * \brief Add a tone_zone structure to the data tree specified. - * - * \retval <0 on error. - * \retval 0 on success. - */ -int ast_tone_zone_data_add_structure(struct ast_data *tree, struct ast_tone_zone *zone); - #endif /* _ASTERISK_INDICATIONS_H */ diff --git a/main/asterisk.c b/main/asterisk.c index 16313ea6853..3e16d695033 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -4560,7 +4560,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou check_init(app_init(), "App Core"); check_init(devstate_init(), "Device State Core"); check_init(ast_msg_init(), "Messaging API"); - check_init(ast_data_init(), "Data Retrieval API"); check_init(ast_channels_init(), "Channel"); check_init(ast_endpoint_init(), "Endpoints"); check_init(ast_pickup_init(), "Call Pickup"); diff --git a/main/cdr.c b/main/cdr.c index 214af2cbc99..1817e80a7b4 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -60,7 +60,6 @@ #include "asterisk/config.h" #include "asterisk/cli.h" #include "asterisk/stringfields.h" -#include "asterisk/data.h" #include "asterisk/config_options.h" #include "asterisk/json.h" #include "asterisk/parking.h" diff --git a/main/channel.c b/main/channel.c index c7c2b9d1e6e..1134d01bada 100644 --- a/main/channel.c +++ b/main/channel.c @@ -66,7 +66,6 @@ #include "asterisk/autochan.h" #include "asterisk/stringfields.h" #include "asterisk/global_datastores.h" -#include "asterisk/data.h" #include "asterisk/channel_internal.h" #include "asterisk/features.h" #include "asterisk/bridge.h" @@ -7564,122 +7563,6 @@ int ast_plc_reload(void) return 0; } -/*! - * \internal - * \brief Implements the channels provider. - */ -static int data_channels_provider_handler(const struct ast_data_search *search, - struct ast_data *root) -{ - struct ast_channel *c; - struct ast_channel_iterator *iter = NULL; - struct ast_data *data_channel; - - for (iter = ast_channel_iterator_all_new(); - iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) { - ast_channel_lock(c); - - data_channel = ast_data_add_node(root, "channel"); - if (!data_channel) { - ast_channel_unlock(c); - continue; - } - - if (ast_channel_data_add_structure(data_channel, c, 1) < 0) { - ast_log(LOG_ERROR, "Unable to add channel structure for channel: %s\n", ast_channel_name(c)); - } - - ast_channel_unlock(c); - - if (!ast_data_search_match(search, data_channel)) { - ast_data_remove_node(root, data_channel); - } - } - if (iter) { - ast_channel_iterator_destroy(iter); - } - - return 0; -} - -/*! - * \internal - * \brief Implements the channeltypes provider. - */ -static int data_channeltypes_provider_handler(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct chanlist *cl; - struct ast_data *data_type; - - AST_RWLIST_RDLOCK(&backends); - AST_RWLIST_TRAVERSE(&backends, cl, list) { - data_type = ast_data_add_node(data_root, "type"); - if (!data_type) { - continue; - } - ast_data_add_str(data_type, "name", cl->tech->type); - ast_data_add_str(data_type, "description", cl->tech->description); - ast_data_add_bool(data_type, "devicestate", cl->tech->devicestate ? 1 : 0); - ast_data_add_bool(data_type, "presencestate", cl->tech->presencestate ? 1 : 0); - ast_data_add_bool(data_type, "indications", cl->tech->indicate ? 1 : 0); - ast_data_add_bool(data_type, "transfer", cl->tech->transfer ? 1 : 0); - ast_data_add_bool(data_type, "send_digit_begin", cl->tech->send_digit_begin ? 1 : 0); - ast_data_add_bool(data_type, "send_digit_end", cl->tech->send_digit_end ? 1 : 0); - ast_data_add_bool(data_type, "call", cl->tech->call ? 1 : 0); - ast_data_add_bool(data_type, "hangup", cl->tech->hangup ? 1 : 0); - ast_data_add_bool(data_type, "answer", cl->tech->answer ? 1 : 0); - ast_data_add_bool(data_type, "read", cl->tech->read ? 1 : 0); - ast_data_add_bool(data_type, "write", cl->tech->write ? 1 : 0); - ast_data_add_bool(data_type, "send_text", cl->tech->send_text ? 1 : 0); - ast_data_add_bool(data_type, "send_image", cl->tech->send_image ? 1 : 0); - ast_data_add_bool(data_type, "send_html", cl->tech->send_html ? 1 : 0); - ast_data_add_bool(data_type, "exception", cl->tech->exception ? 1 : 0); - ast_data_add_bool(data_type, "early_bridge", cl->tech->early_bridge ? 1 : 0); - ast_data_add_bool(data_type, "fixup", cl->tech->fixup ? 1 : 0); - ast_data_add_bool(data_type, "setoption", cl->tech->setoption ? 1 : 0); - ast_data_add_bool(data_type, "queryoption", cl->tech->queryoption ? 1 : 0); - ast_data_add_bool(data_type, "write_video", cl->tech->write_video ? 1 : 0); - ast_data_add_bool(data_type, "write_text", cl->tech->write_text ? 1 : 0); - ast_data_add_bool(data_type, "func_channel_read", cl->tech->func_channel_read ? 1 : 0); - ast_data_add_bool(data_type, "func_channel_write", cl->tech->func_channel_write ? 1 : 0); - ast_data_add_bool(data_type, "get_pvt_uniqueid", cl->tech->get_pvt_uniqueid ? 1 : 0); - ast_data_add_bool(data_type, "cc_callback", cl->tech->cc_callback ? 1 : 0); - - ast_data_add_codecs(data_type, "capabilities", cl->tech->capabilities); - - if (!ast_data_search_match(search, data_type)) { - ast_data_remove_node(data_root, data_type); - } - } - AST_RWLIST_UNLOCK(&backends); - - return 0; -} - -/*! - * \internal - * \brief /asterisk/core/channels provider. - */ -static const struct ast_data_handler channels_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = data_channels_provider_handler -}; - -/*! - * \internal - * \brief /asterisk/core/channeltypes provider. - */ -static const struct ast_data_handler channeltypes_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = data_channeltypes_provider_handler -}; - -static const struct ast_data_entry channel_providers[] = { - AST_DATA_ENTRY("/asterisk/core/channels", &channels_provider), - AST_DATA_ENTRY("/asterisk/core/channeltypes", &channeltypes_provider), -}; - /*! * \internal * \brief Print channel object key (name). @@ -7879,7 +7762,6 @@ static void channels_shutdown(void) free_external_channelvars(&ami_vars); free_external_channelvars(&ari_vars); - ast_data_unregister(NULL); ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel)); if (channels) { ao2_container_unregister("channels"); @@ -7904,8 +7786,6 @@ int ast_channels_init(void) ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel)); - ast_data_register_multiple_core(channel_providers, ARRAY_LEN(channel_providers)); - ast_plc_reload(); ast_register_cleanup(channels_shutdown); diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 5e7df8983a7..d31ce94d8b7 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -40,7 +40,6 @@ #include "asterisk/paths.h" #include "asterisk/channel.h" #include "asterisk/channel_internal.h" -#include "asterisk/data.h" #include "asterisk/endpoints.h" #include "asterisk/indications.h" #include "asterisk/stasis_cache_pattern.h" @@ -226,211 +225,6 @@ struct ast_channel { /*! \brief The monotonically increasing integer counter for channel uniqueids */ static int uniqueint; -/* AST_DATA definitions, which will probably have to be re-thought since the channel will be opaque */ - -#if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ -#define DATA_EXPORT_CALLERID(MEMBER) \ - MEMBER(ast_callerid, cid_dnid, AST_DATA_STRING) \ - MEMBER(ast_callerid, cid_num, AST_DATA_STRING) \ - MEMBER(ast_callerid, cid_name, AST_DATA_STRING) \ - MEMBER(ast_callerid, cid_ani, AST_DATA_STRING) \ - MEMBER(ast_callerid, cid_pres, AST_DATA_INTEGER) \ - MEMBER(ast_callerid, cid_ani2, AST_DATA_INTEGER) \ - MEMBER(ast_callerid, cid_tag, AST_DATA_STRING) - -AST_DATA_STRUCTURE(ast_callerid, DATA_EXPORT_CALLERID); -#endif - -#define DATA_EXPORT_CHANNEL(MEMBER) \ - MEMBER(ast_channel, blockproc, AST_DATA_STRING) \ - MEMBER(ast_channel, appl, AST_DATA_STRING) \ - MEMBER(ast_channel, data, AST_DATA_STRING) \ - MEMBER(ast_channel, name, AST_DATA_STRING) \ - MEMBER(ast_channel, language, AST_DATA_STRING) \ - MEMBER(ast_channel, musicclass, AST_DATA_STRING) \ - MEMBER(ast_channel, accountcode, AST_DATA_STRING) \ - MEMBER(ast_channel, peeraccount, AST_DATA_STRING) \ - MEMBER(ast_channel, userfield, AST_DATA_STRING) \ - MEMBER(ast_channel, call_forward, AST_DATA_STRING) \ - MEMBER(ast_channel, parkinglot, AST_DATA_STRING) \ - MEMBER(ast_channel, hangupsource, AST_DATA_STRING) \ - MEMBER(ast_channel, dialcontext, AST_DATA_STRING) \ - MEMBER(ast_channel, rings, AST_DATA_INTEGER) \ - MEMBER(ast_channel, priority, AST_DATA_INTEGER) \ - MEMBER(ast_channel, macropriority, AST_DATA_INTEGER) \ - MEMBER(ast_channel, adsicpe, AST_DATA_INTEGER) \ - MEMBER(ast_channel, fin, AST_DATA_UNSIGNED_INTEGER) \ - MEMBER(ast_channel, fout, AST_DATA_UNSIGNED_INTEGER) \ - MEMBER(ast_channel, emulate_dtmf_duration, AST_DATA_UNSIGNED_INTEGER) \ - MEMBER(ast_channel, visible_indication, AST_DATA_INTEGER) \ - MEMBER(ast_channel, context, AST_DATA_STRING) \ - MEMBER(ast_channel, exten, AST_DATA_STRING) \ - MEMBER(ast_channel, macrocontext, AST_DATA_STRING) \ - MEMBER(ast_channel, macroexten, AST_DATA_STRING) - -AST_DATA_STRUCTURE(ast_channel, DATA_EXPORT_CHANNEL); - -static void channel_data_add_flags(struct ast_data *tree, - struct ast_channel *chan) -{ - ast_data_add_bool(tree, "DEFER_DTMF", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF)); - ast_data_add_bool(tree, "WRITE_INT", ast_test_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT)); - ast_data_add_bool(tree, "BLOCKING", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING)); - ast_data_add_bool(tree, "ZOMBIE", ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)); - ast_data_add_bool(tree, "EXCEPTION", ast_test_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION)); - ast_data_add_bool(tree, "MOH", ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH)); - ast_data_add_bool(tree, "SPYING", ast_test_flag(ast_channel_flags(chan), AST_FLAG_SPYING)); - ast_data_add_bool(tree, "IN_AUTOLOOP", ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)); - ast_data_add_bool(tree, "OUTGOING", ast_test_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING)); - ast_data_add_bool(tree, "IN_DTMF", ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_DTMF)); - ast_data_add_bool(tree, "EMULATE_DTMF", ast_test_flag(ast_channel_flags(chan), AST_FLAG_EMULATE_DTMF)); - ast_data_add_bool(tree, "END_DTMF_ONLY", ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY)); - ast_data_add_bool(tree, "MASQ_NOSTREAM", ast_test_flag(ast_channel_flags(chan), AST_FLAG_MASQ_NOSTREAM)); - ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN)); - ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS)); - ast_data_add_bool(tree, "DISABLE_DEVSTATE_CACHE", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE)); - ast_data_add_bool(tree, "BRIDGE_DUAL_REDIRECT_WAIT", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)); - ast_data_add_bool(tree, "ORIGINATED", ast_test_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED)); - ast_data_add_bool(tree, "DEAD", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEAD)); -} - -int ast_channel_data_add_structure(struct ast_data *tree, - struct ast_channel *chan, int add_bridged) -{ - struct ast_data *data_bridged; - struct ast_data *data_cdr; - struct ast_data *data_flags; - struct ast_data *data_zones; - struct ast_data *enum_node; - struct ast_data *data_softhangup; -#if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ - struct ast_data *data_callerid; - char value_str[100]; -#endif - - if (!tree) { - return -1; - } - - ast_data_add_structure(ast_channel, tree, chan); - - if (add_bridged) { - RAII_VAR(struct ast_channel *, bc, ast_channel_bridge_peer(chan), ast_channel_cleanup); - if (bc) { - data_bridged = ast_data_add_node(tree, "bridged"); - if (!data_bridged) { - return -1; - } - ast_channel_data_add_structure(data_bridged, bc, 0); - } - } - - ast_data_add_str(tree, "uniqueid", ast_channel_uniqueid(chan)); - ast_data_add_str(tree, "linkedid", ast_channel_linkedid(chan)); - - ast_data_add_codec(tree, "oldwriteformat", ast_channel_oldwriteformat(chan)); - ast_data_add_codec(tree, "readformat", ast_channel_readformat(chan)); - ast_data_add_codec(tree, "writeformat", ast_channel_writeformat(chan)); - ast_data_add_codec(tree, "rawreadformat", ast_channel_rawreadformat(chan)); - ast_data_add_codec(tree, "rawwriteformat", ast_channel_rawwriteformat(chan)); - ast_data_add_codecs(tree, "nativeformats", ast_channel_nativeformats(chan)); - - /* state */ - enum_node = ast_data_add_node(tree, "state"); - if (!enum_node) { - return -1; - } - ast_data_add_str(enum_node, "text", ast_state2str(ast_channel_state(chan))); - ast_data_add_int(enum_node, "value", ast_channel_state(chan)); - - /* hangupcause */ - enum_node = ast_data_add_node(tree, "hangupcause"); - if (!enum_node) { - return -1; - } - ast_data_add_str(enum_node, "text", ast_cause2str(ast_channel_hangupcause(chan))); - ast_data_add_int(enum_node, "value", ast_channel_hangupcause(chan)); - - /* amaflags */ - enum_node = ast_data_add_node(tree, "amaflags"); - if (!enum_node) { - return -1; - } - ast_data_add_str(enum_node, "text", ast_channel_amaflags2string(ast_channel_amaflags(chan))); - ast_data_add_int(enum_node, "value", ast_channel_amaflags(chan)); - - /* transfercapability */ - enum_node = ast_data_add_node(tree, "transfercapability"); - if (!enum_node) { - return -1; - } - ast_data_add_str(enum_node, "text", ast_transfercapability2str(ast_channel_transfercapability(chan))); - ast_data_add_int(enum_node, "value", ast_channel_transfercapability(chan)); - - /* _softphangup */ - data_softhangup = ast_data_add_node(tree, "softhangup"); - if (!data_softhangup) { - return -1; - } - ast_data_add_bool(data_softhangup, "dev", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_DEV); - ast_data_add_bool(data_softhangup, "asyncgoto", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO); - ast_data_add_bool(data_softhangup, "shutdown", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_SHUTDOWN); - ast_data_add_bool(data_softhangup, "timeout", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_TIMEOUT); - ast_data_add_bool(data_softhangup, "appunload", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_APPUNLOAD); - ast_data_add_bool(data_softhangup, "explicit", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_EXPLICIT); - - /* channel flags */ - data_flags = ast_data_add_node(tree, "flags"); - if (!data_flags) { - return -1; - } - channel_data_add_flags(data_flags, chan); - - ast_data_add_uint(tree, "timetohangup", ast_channel_whentohangup(chan)->tv_sec); - -#if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ - /* callerid */ - data_callerid = ast_data_add_node(tree, "callerid"); - if (!data_callerid) { - return -1; - } - ast_data_add_structure(ast_callerid, data_callerid, &(chan->cid)); - /* insert the callerid ton */ - enum_node = ast_data_add_node(data_callerid, "cid_ton"); - if (!enum_node) { - return -1; - } - ast_data_add_int(enum_node, "value", chan->cid.cid_ton); - snprintf(value_str, sizeof(value_str), "TON: %s/Plan: %s", - party_number_ton2str(chan->cid.cid_ton), - party_number_plan2str(chan->cid.cid_ton)); - ast_data_add_str(enum_node, "text", value_str); -#endif - - /* tone zone */ - if (ast_channel_zone(chan)) { - data_zones = ast_data_add_node(tree, "zone"); - if (!data_zones) { - return -1; - } - ast_tone_zone_data_add_structure(data_zones, ast_channel_zone(chan)); - } - - /* insert cdr */ - data_cdr = ast_data_add_node(tree, "cdr"); - if (!data_cdr) { - return -1; - } - - return 0; -} - -int ast_channel_data_cmp_structure(const struct ast_data_search *tree, - struct ast_channel *chan, const char *structure_name) -{ - return ast_data_search_cmp_structure(tree, ast_channel, chan, structure_name); -} - /* ACCESSORS */ #define DEFINE_STRINGFIELD_SETTERS_FOR(field, publish, assert_on_null) \ diff --git a/main/data.c b/main/data.c deleted file mode 100644 index 15aca8b9d3d..00000000000 --- a/main/data.c +++ /dev/null @@ -1,3346 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2009, Eliel C. Sardanons (LU1ALY) - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Data retrieval API. - * - * \author Brett Bryant - * \author Eliel C. Sardanons (LU1ALY) - */ - -/*** MODULEINFO - core - ***/ - -#include "asterisk.h" - -#include "asterisk/_private.h" - -#include - -#include "asterisk/module.h" -#include "asterisk/utils.h" -#include "asterisk/lock.h" -#include "asterisk/data.h" -#include "asterisk/astobj2.h" -#include "asterisk/xml.h" -#include "asterisk/cli.h" -#include "asterisk/term.h" -#include "asterisk/manager.h" -#include "asterisk/test.h" -#include "asterisk/frame.h" -#include "asterisk/codec.h" - -/*** DOCUMENTATION - - - Retrieve the data api tree. - - - - - - - - - Retrieve the data api tree. - - - ***/ - -#define NUM_DATA_NODE_BUCKETS 59 -#define NUM_DATA_RESULT_BUCKETS 59 -#define NUM_DATA_SEARCH_BUCKETS 59 -#define NUM_DATA_FILTER_BUCKETS 59 - -/*! \brief The last compatible version. */ -static const uint32_t latest_handler_compatible_version = 0; - -/*! \brief The last compatible version. */ -static const uint32_t latest_query_compatible_version = 0; - -/*! \brief Current handler structure version. */ -static const uint32_t current_handler_version = AST_DATA_HANDLER_VERSION; - -/*! \brief Current query structure version. */ -static const uint32_t current_query_version = AST_DATA_QUERY_VERSION; - -/*! \brief The data tree to be returned by the callbacks and - managed by functions local to this file. */ -struct ast_data { - enum ast_data_type type; - - /*! \brief The node content. */ - union { - int32_t sint; - uint32_t uint; - double dbl; - unsigned int boolean; - char *str; - char character; - struct in_addr ipaddr; - void *ptr; - } payload; - - /*! \brief The filter node that depends on the current node, - * this is used only when creating the result tree. */ - const struct data_filter *filter; - - /*! \brief The list of nodes inside this node. */ - struct ao2_container *children; - /*! \brief The name of the node. */ - char name[0]; -}; - -/*! \brief Type of comparisons allow in the search string. */ -enum data_search_comparison { - DATA_CMP_UNKNOWN, - DATA_CMP_EQ, /* = */ - DATA_CMP_NEQ, /* != */ - DATA_CMP_GT, /* > */ - DATA_CMP_GE, /* >= */ - DATA_CMP_LT, /* < */ - DATA_CMP_LE /* <= */ -}; - -/*! \brief The list of nodes with their search requirement. */ -struct ast_data_search { - /*! \brief The value of the comparison. */ - char *value; - /*! \brief The type of comparison. */ - enum data_search_comparison cmp_type; - /*! \brief reference another node. */ - struct ao2_container *children; - /*! \brief The name of the node we are trying to compare. */ - char name[0]; -}; - -struct data_filter; - -/*! \brief The filter node. */ -struct data_filter { - /*! \brief node childrens. */ - struct ao2_container *children; - /*! \brief glob list */ - AST_LIST_HEAD_NOLOCK(glob_list_t, data_filter) glob_list; - /*! \brief glob list entry */ - AST_LIST_ENTRY(data_filter) list; - /*! \brief node name. */ - char name[0]; -}; - -/*! \brief A data container node pointing to the registered handler. */ -struct data_provider { - /*! \brief node content handler. */ - const struct ast_data_handler *handler; - /*! \brief Module providing this handler. */ - struct ast_module *module; - /*! \brief children nodes. */ - struct ao2_container *children; - /*! \brief Who registered this node. */ - const char *registrar; - /*! \brief Node name. */ - char name[0]; -}; - -/*! \brief This structure is used by the iterator. */ -struct ast_data_iterator { - /*! \brief The internal iterator. */ - struct ao2_iterator internal_iterator; - /*! \brief The last returned node. */ - struct ast_data *last; - /*! \brief The iterator pattern. */ - const char *pattern; - /*! \brief The compiled patter. */ - regex_t regex_pattern; - /*! \brief is a regular expression. */ - unsigned int is_pattern:1; -}; - -struct { - /*! \brief The asterisk data main content structure. */ - struct ao2_container *container; - /*! \brief asterisk data locking mechanism. */ - ast_rwlock_t lock; -} root_data; - -static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_t depth); - -/*! - * \internal - * \brief Common string hash function. - * \see ast_data_init - */ -static int data_provider_hash(const void *obj, const int flags) -{ - const struct data_provider *node = obj; - return ast_str_case_hash(node->name); -} - -/*! - * \internal - * \brief Compare two data_provider's. - * \see ast_data_init - */ -static int data_provider_cmp(void *obj1, void *obj2, int flags) -{ - struct data_provider *node1 = obj1, *node2 = obj2; - return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH; -} - -/*! - * \internal - * \brief Common string hash function for data nodes - */ -static int data_result_hash(const void *obj, const int flags) -{ - const struct ast_data *node = obj; - return ast_str_hash(node->name); -} - -/*! - * \internal - * \brief Common string comparison function - */ -static int data_result_cmp(void *obj, void *arg, int flags) -{ - struct ast_data *node1 = obj, *node2 = arg; - return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH; -} - -/*! - * \internal - * \brief Lock the data registered handlers structure for writing. - * \see data_unlock - */ -#define data_write_lock() ast_rwlock_wrlock(&root_data.lock) - -/*! - * \internal - * \brief Lock the data registered handlers structure for reading. - * \see data_unlock - */ -#define data_read_lock() ast_rwlock_rdlock(&root_data.lock) - -/*! - * \internal - * \brief Unlock the data registered handlers structure. - */ -#define data_unlock() ast_rwlock_unlock(&root_data.lock) - -/*! - * \internal - * \brief Check if a version is compatible with the current core. - * \param[in] structure_version The current structure version. - * \param[in] latest_compatible The latest compatible version. - * \param[in] current The current Data API version. - * \retval 1 If the module is compatible. - * \retval 0 If the module is NOT compatible. - */ -static int data_structure_compatible(int structure_version, uint32_t latest_compatible, - uint32_t current) -{ - if (structure_version >= latest_compatible && structure_version <= current) { - return 1; - } - - ast_log(LOG_ERROR, "A module is not compatible with the" - "current data api version\n"); - - return 0; -} - -/*! - * \internal - * \brief Get the next node name in a path (/node1/node2) - * Avoid null nodes like //node1//node2/node3. - * \param[in] path The path where we are going to search for the next node name. - * \retval The next node name we found inside the given path. - * \retval NULL if there are no more node names. - */ -static char *next_node_name(char **path) -{ - char *res; - - do { - res = strsep(path, "/"); - } while (res && ast_strlen_zero(res)); - - return res; -} - -/*! - * \internal - * \brief Release the memory allocated by a call to ao2_alloc. - */ -static void data_provider_destructor(void *obj) -{ - struct data_provider *provider = obj; - - ao2_ref(provider->children, -1); -} - -/*! - * \internal - * \brief Create a new data node. - * \param[in] name The name of the node we are going to create. - * \param[in] handler The handler registered for this node. - * \param[in] registrar The name of the registrar. - * \retval NULL on error. - * \retval The allocated data node structure. - */ -static struct data_provider *data_provider_new(const char *name, - const struct ast_data_handler *handler, const char *registrar) -{ - struct data_provider *node; - size_t namelen; - - namelen = strlen(name) + 1; - - node = ao2_alloc(sizeof(*node) + namelen, data_provider_destructor); - if (!node) { - return NULL; - } - - node->handler = handler; - node->registrar = registrar; - strcpy(node->name, name); - - /* initialize the childrens container. */ - if (!(node->children = ao2_container_alloc(NUM_DATA_NODE_BUCKETS, - data_provider_hash, data_provider_cmp))) { - ao2_ref(node, -1); - return NULL; - } - - return node; -} - -/*! - * \internal - * \brief Add a child node named 'name' to the 'parent' node. - * \param[in] parent Where to add the child node. - * \param[in] name The name of the child node. - * \param[in] handler The handler structure. - * \param[in] registrar Who registered this node. - * \retval NULL on error. - * \retval A newly allocated child in parent. - */ -static struct data_provider *data_provider_add_child(struct ao2_container *parent, - const char *name, const struct ast_data_handler *handler, const char *registrar) -{ - struct data_provider *child; - - child = data_provider_new(name, handler, registrar); - if (!child) { - return NULL; - } - - ao2_link(parent, child); - - return child; -} - -/*! - * \internal - * \brief Find a child node, based on his name. - * \param[in] parent Where to find the node. - * \param[in] name The node name to find. - * \param[in] registrar Also check if the node was being used by this registrar. - * \retval NULL if a node wasn't found. - * \retval The node found. - * \note Remember to decrement the ref count of the returned node after using it. - */ -static struct data_provider *data_provider_find(struct ao2_container *parent, - const char *name, const char *registrar) -{ - struct data_provider *find_node, *found; - - /* XXX avoid allocating a new data node for searching... */ - find_node = data_provider_new(name, NULL, NULL); - if (!find_node) { - return NULL; - } - - found = ao2_find(parent, find_node, OBJ_POINTER); - - /* free the created node used for searching. */ - ao2_ref(find_node, -1); - - if (found && found->registrar && registrar) { - if (strcmp(found->registrar, registrar)) { - /* if the name doesn't match, do not return this node. */ - ast_debug(1, "Registrar doesn't match, node was registered" - " by '%s' and we are searching for '%s'\n", - found->registrar, registrar); - ao2_ref(found, -1); - return NULL; - } - } - - return found; -} - -/*! - * \internal - * \brief Release a group of nodes. - * \param[in] parent The parent node. - * \param[in] path The path of nodes to release. - * \param[in] registrar Who registered this node. - * \retval <0 on error. - * \retval 0 on success. - * \see data_provider_create - */ -static int data_provider_release(struct ao2_container *parent, const char *path, - const char *registrar) -{ - char *node_name, *rpath; - struct data_provider *child; - int ret = 0; - - rpath = ast_strdupa(path); - - node_name = next_node_name(&rpath); - if (!node_name) { - return -1; - } - - child = data_provider_find(parent, node_name, registrar); - if (!child) { - return -1; - } - - /* if this is not a terminal node. */ - if (!child->handler && rpath) { - ret = data_provider_release(child->children, rpath, registrar); - } - - /* if this node is empty, unlink it. */ - if (!ret && !ao2_container_count(child->children)) { - ao2_unlink(parent, child); - } - - ao2_ref(child, -1); - - return ret; -} - -/*! - * \internal - * \brief Release every node registered by 'registrar'. - * \param[in] parent The parent node. - * \param[in] registrar - * \see __ast_data_unregister - */ -static void data_provider_release_all(struct ao2_container *parent, - const char *registrar) -{ - struct ao2_iterator i; - struct data_provider *node; - - i = ao2_iterator_init(parent, 0); - while ((node = ao2_iterator_next(&i))) { - if (!node->handler) { - /* this is a non-terminal node, go inside it. */ - data_provider_release_all(node->children, registrar); - if (!ao2_container_count(node->children)) { - /* if this node was left empty, unlink it. */ - ao2_unlink(parent, node); - } - } else { - if (!strcmp(node->registrar, registrar)) { - /* if the registrars match, release it! */ - ao2_unlink(parent, node); - } - } - ao2_ref(node, -1); - } - ao2_iterator_destroy(&i); - -} - -/*! - * \internal - * \brief Create the middle nodes for the specified path (asterisk/testnode1/childnode) - * \param[in] parent Where to add the middle nodes structure. - * \param[in] path The path of nodes to add. - * \param[in] registrar Who is trying to create this node provider. - * \retval NULL on error. - * \retval The created node. - * \see data_provider_release - */ -static struct data_provider *data_provider_create(struct ao2_container *parent, - const char *path, const char *registrar) -{ - char *rpath, *node_name; - struct data_provider *child, *ret = NULL; - - rpath = ast_strdupa(path); - - node_name = next_node_name(&rpath); - if (!node_name) { - /* no more nodes to create. */ - return NULL; - } - - child = data_provider_find(parent, node_name, NULL); - - if (!child) { - /* nodes without handler are non-terminal nodes. */ - child = data_provider_add_child(parent, node_name, NULL, registrar); - } - - if (rpath) { - ret = data_provider_create(child->children, rpath, registrar); - if (ret) { - ao2_ref(child, -1); - } - } - - return ret ? ret : child; -} - -int __ast_data_register(const char *path, const struct ast_data_handler *handler, - const char *registrar, struct ast_module *mod) -{ - struct data_provider *node; - - if (!path) { - return -1; - } - - /* check if the handler structure is compatible. */ - if (!data_structure_compatible(handler->version, - latest_handler_compatible_version, - current_handler_version)) { - return -1; - } - - /* create the node structure for the registered handler. */ - data_write_lock(); - - node = data_provider_create(root_data.container, path, registrar); - if (!node) { - ast_log(LOG_ERROR, "Unable to create the specified path (%s) " - "for '%s'.\n", path, registrar); - data_unlock(); - return -1; - } - - if (ao2_container_count(node->children) || node->handler) { - ast_log(LOG_ERROR, "The node '%s' was already registered. " - "We were unable to register '%s' for registrar '%s'.\n", - node->name, path, registrar); - ao2_ref(node, -1); - data_unlock(); - return -1; - } - - /* add handler to that node. */ - node->handler = handler; - node->module = mod; - - ao2_ref(node, -1); - - data_unlock(); - - return 0; -} - -int __ast_data_register_multiple(const struct ast_data_entry *data_entries, - size_t entries, const char *registrar, struct ast_module *mod) -{ - int i, res; - - for (i = 0; i < entries; i++) { - res = __ast_data_register(data_entries[i].path, data_entries[i].handler, - registrar, mod); - if (res) { - /* unregister all the already registered nodes, and make - * this an atomic action. */ - while ((--i) >= 0) { - __ast_data_unregister(data_entries[i].path, registrar); - } - return -1; - } - } - - return 0; -} - -int __ast_data_unregister(const char *path, const char *registrar) -{ - int ret = 0; - - data_write_lock(); - if (path) { - ret = data_provider_release(root_data.container, path, registrar); - } else { - data_provider_release_all(root_data.container, registrar); - } - data_unlock(); - - if (path && ret) { - ast_log(LOG_ERROR, "Unable to unregister '%s' for '%s'\n", - path, registrar); - } - - return ret; -} - -/*! - * \internal - * \brief Is a char used to specify a comparison? - * \param[in] a Character to evaluate. - * \retval 1 It is a char used to specify a comparison. - * \retval 0 It is NOT a char used to specify a comparison. - */ -static int data_search_comparison_char(char a) -{ - switch (a) { - case '!': - case '=': - case '<': - case '>': - return 1; - } - - return 0; -} - -/*! - * \internal - * \brief Get the type of comparison. - */ -static enum data_search_comparison data_search_comparison_type(const char *comparison) -{ - if (!strcmp(comparison, "=")) { - return DATA_CMP_EQ; - } else if (!strcmp(comparison, "!=")) { - return DATA_CMP_NEQ; - } else if (!strcmp(comparison, "<")) { - return DATA_CMP_LT; - } else if (!strcmp(comparison, ">")) { - return DATA_CMP_GT; - } else if (!strcmp(comparison, "<=")) { - return DATA_CMP_LE; - } else if (!strcmp(comparison, ">=")) { - return DATA_CMP_GE; - } - - return DATA_CMP_UNKNOWN; -} - -/*! - * \internal - * \brief Common string hash function for data nodes - */ -static int data_search_hash(const void *obj, const int flags) -{ - const struct ast_data_search *node = obj; - return ast_str_hash(node->name); -} - -/*! - * \internal - * \brief Common string comparison function - */ -static int data_search_cmp(void *obj, void *arg, int flags) -{ - struct ast_data_search *node1 = obj, *node2 = arg; - return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH; -} - -/*! - * \internal - * \brief Destroy the ao2 search node. - */ -static void data_search_destructor(void *obj) -{ - struct ast_data_search *node = obj; - - if (node->value) { - ast_free(node->value); - } - - ao2_ref(node->children, -1); -} - -/*! - * \internal - * \brief Allocate a search node. - * \retval NULL on error. - * \retval non-NULL The allocated search node structure. - */ -static struct ast_data_search *data_search_alloc(const char *name) -{ - struct ast_data_search *res; - size_t name_len = strlen(name) + 1; - - res = ao2_alloc(sizeof(*res) + name_len, data_search_destructor); - if (!res) { - return NULL; - } - - res->children = ao2_container_alloc(NUM_DATA_SEARCH_BUCKETS, data_search_hash, - data_search_cmp); - - if (!res->children) { - ao2_ref(res, -1); - return NULL; - } - - strcpy(res->name, name); - - return res; -} - -/*! - * \internal - * \brief Find a child node, based on his name. - * \param[in] parent Where to find the node. - * \param[in] name The node name to find. - * \retval NULL if a node wasn't found. - * \retval The node found. - * \note Remember to decrement the ref count of the returned node after using it. - */ -static struct ast_data_search *data_search_find(struct ao2_container *parent, - const char *name) -{ - struct ast_data_search *find_node, *found; - - find_node = data_search_alloc(name); - if (!find_node) { - return NULL; - } - - found = ao2_find(parent, find_node, OBJ_POINTER); - - /* free the created node used for searching. */ - ao2_ref(find_node, -1); - - return found; -} - -/*! - * \internal - * \brief Add a child node named 'name' to the 'parent' node. - * \param[in] parent Where to add the child node. - * \param[in] name The name of the child node. - * \retval NULL on error. - * \retval A newly allocated child in parent. - */ -static struct ast_data_search *data_search_add_child(struct ao2_container *parent, - const char *name) -{ - struct ast_data_search *child; - - child = data_search_alloc(name); - if (!child) { - return NULL; - } - - ao2_link(parent, child); - - return child; -} - -/*! - * \internal - * \brief Create the middle nodes for the specified path (asterisk/testnode1/childnode) - * \param[in] parent Where to add the middle nodes structure. - * \param[in] path The path of nodes to add. - * \retval NULL on error. - * \retval The created node. - */ -static struct ast_data_search *data_search_create(struct ao2_container *parent, - const char *path) -{ - char *rpath, *node_name; - struct ast_data_search *child = NULL; - struct ao2_container *current = parent; - - rpath = ast_strdupa(path); - - node_name = next_node_name(&rpath); - while (node_name) { - child = data_search_find(current, node_name); - if (!child) { - child = data_search_add_child(current, node_name); - } - ao2_ref(child, -1); - current = child->children; - node_name = next_node_name(&rpath); - } - - return child; -} - -/*! - * \internal - * \brief Allocate a tree with the search string parsed. - * \param[in] search_string The search string. - * \retval NULL on error. - * \retval non-NULL A dynamically allocated search tree. - */ -static struct ast_data_search *data_search_generate(const char *search_string) -{ - struct ast_str *name, *value, *comparison; - char *elements, *search_string_dup, *saveptr; - int i; - struct ast_data_search *root, *child; - enum data_search_comparison cmp_type; - size_t search_string_len; - - if (!search_string) { - ast_log(LOG_ERROR, "You must pass a valid search string.\n"); - return NULL; - } - - search_string_len = strlen(search_string); - - name = ast_str_create(search_string_len); - if (!name) { - return NULL; - } - value = ast_str_create(search_string_len); - if (!value) { - ast_free(name); - return NULL; - } - comparison = ast_str_create(search_string_len); - if (!comparison) { - ast_free(name); - ast_free(value); - return NULL; - } - - search_string_dup = ast_strdupa(search_string); - - /* Create the root node (just used as a container) */ - root = data_search_alloc("/"); - if (!root) { - ast_free(name); - ast_free(value); - ast_free(comparison); - return NULL; - } - - for (elements = strtok_r(search_string_dup, ",", &saveptr); elements; - elements = strtok_r(NULL, ",", &saveptr)) { - /* Parse the name */ - ast_str_reset(name); - for (i = 0; !data_search_comparison_char(elements[i]) && - elements[i]; i++) { - ast_str_append(&name, 0, "%c", elements[i]); - } - - /* check if the syntax is ok. */ - if (!data_search_comparison_char(elements[i])) { - /* if this is the end of the string, then this is - * an error! */ - ast_log(LOG_ERROR, "Invalid search string!\n"); - continue; - } - - /* parse the comparison string. */ - ast_str_reset(comparison); - for (; data_search_comparison_char(elements[i]) && elements[i]; i++) { - ast_str_append(&comparison, 0, "%c", elements[i]); - } - - /* parse the value string. */ - ast_str_reset(value); - for (; elements[i]; i++) { - ast_str_append(&value, 0, "%c", elements[i]); - } - - cmp_type = data_search_comparison_type(ast_str_buffer(comparison)); - if (cmp_type == DATA_CMP_UNKNOWN) { - ast_log(LOG_ERROR, "Invalid comparison '%s'\n", - ast_str_buffer(comparison)); - continue; - } - - /* add this node to the tree. */ - child = data_search_create(root->children, ast_str_buffer(name)); - if (child) { - child->cmp_type = cmp_type; - child->value = ast_strdup(ast_str_buffer(value)); - } - } - - ast_free(name); - ast_free(value); - ast_free(comparison); - - return root; -} - -/*! - * \internal - * \brief Release the allocated memory for the search tree. - * \param[in] search The search tree root node. - */ -static void data_search_release(struct ast_data_search *search) -{ - ao2_ref(search, -1); -} - -/*! - * \internal - * \brief Based on the kind of comparison and the result in cmpval, return - * if it matches. - * \param[in] cmpval A result returned by a strcmp() for example. - * \param[in] comparison_type The kind of comparison (<,>,=,!=,...) - * \retval 1 If the comparison doesn't match. - * \retval 0 If the comparison matches. - */ -static inline int data_search_comparison_result(int cmpval, - enum data_search_comparison comparison_type) -{ - switch (comparison_type) { - case DATA_CMP_GE: - if (cmpval >= 0) { - return 0; - } - break; - case DATA_CMP_LE: - if (cmpval <= 0) { - return 0; - } - break; - case DATA_CMP_EQ: - if (cmpval == 0) { - return 0; - } - break; - case DATA_CMP_NEQ: - if (cmpval != 0) { - return 0; - } - break; - case DATA_CMP_LT: - if (cmpval < 0) { - return 0; - } - break; - case DATA_CMP_GT: - if (cmpval > 0) { - return 0; - } - break; - case DATA_CMP_UNKNOWN: - break; - } - return 1; -} - -/*! - * \internal - * \brief Get an internal node, from the search tree. - * \param[in] node A node container. - * \param[in] path The path to the needed internal node. - * \retval NULL if the internal node is not found. - * \retval non-NULL the internal node with path 'path'. - */ -static struct ast_data_search *data_search_get_node(const struct ast_data_search *node, - const char *path) -{ - char *savepath, *node_name; - struct ast_data_search *child, *current = (struct ast_data_search *) node; - - if (!node) { - return NULL; - } - - savepath = ast_strdupa(path); - node_name = next_node_name(&savepath); - - while (node_name) { - child = data_search_find(current->children, node_name); - if (current != node) { - ao2_ref(current, -1); - } - if (!child) { - return NULL; - }; - current = child; - node_name = next_node_name(&savepath); - } - - return current; -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current string value. - * .search = "somename=somestring" - * name = "somename" - * value is the current value of something and will be evaluated against "somestring". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] value The value to compare. - * \returns The strcmp return value. - */ -static int data_search_cmp_string(const struct ast_data_search *root, const char *name, - char *value) -{ - struct ast_data_search *child; - enum data_search_comparison cmp_type; - int ret; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - - ret = strcmp(value, child->value); - cmp_type = child->cmp_type; - - ao2_ref(child, -1); - - return data_search_comparison_result(ret, cmp_type); -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current pointer address value. - * .search = "something=0x32323232" - * name = "something" - * value is the current value of something and will be evaluated against "0x32323232". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] ptr The pointer address to compare. - * \returns The (value - current_value) result. - */ -static int data_search_cmp_ptr(const struct ast_data_search *root, const char *name, - void *ptr) -{ - struct ast_data_search *child; - enum data_search_comparison cmp_type; - void *node_ptr; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - - cmp_type = child->cmp_type; - - if (sscanf(child->value, "%p", &node_ptr) <= 0) { - ao2_ref(child, -1); - return 1; - } - - ao2_ref(child, -1); - - return data_search_comparison_result((node_ptr - ptr), cmp_type); -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current ipv4 address value. - * .search = "something=192.168.2.2" - * name = "something" - * value is the current value of something and will be evaluated against "192.168.2.2". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] addr The ipv4 address value to compare. - * \returns The (value - current_value) result. - */ -static int data_search_cmp_ipaddr(const struct ast_data_search *root, const char *name, - struct in_addr addr) -{ - struct ast_data_search *child; - enum data_search_comparison cmp_type; - struct in_addr node_addr; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - cmp_type = child->cmp_type; - - inet_aton(child->value, &node_addr); - - ao2_ref(child, -1); - - return data_search_comparison_result((node_addr.s_addr - addr.s_addr), cmp_type); -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current boolean value. - * .search = "something=true" - * name = "something" - * value is the current value of something and will be evaluated against "true". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] value The boolean value to compare. - * \returns The (value - current_value) result. - */ -static int data_search_cmp_bool(const struct ast_data_search *root, const char *name, - unsigned int value) -{ - struct ast_data_search *child; - unsigned int node_value; - enum data_search_comparison cmp_type; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - - node_value = abs(ast_true(child->value)); - cmp_type = child->cmp_type; - - ao2_ref(child, -1); - - return data_search_comparison_result(value - node_value, cmp_type); -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current double value. - * .search = "something=222" - * name = "something" - * value is the current value of something and will be evaluated against "222". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] value The double value to compare. - * \returns The (value - current_value) result. - */ -static int data_search_cmp_dbl(const struct ast_data_search *root, const char *name, - double value) -{ - struct ast_data_search *child; - double node_value; - enum data_search_comparison cmp_type; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - - node_value = strtod(child->value, NULL); - cmp_type = child->cmp_type; - - ao2_ref(child, -1); - - return data_search_comparison_result(value - node_value, cmp_type); -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current unsigned integer value. - * .search = "something=10" - * name = "something" - * value is the current value of something and will be evaluated against "10". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] value The unsigned value to compare. - * \returns The strcmp return value. - */ -static int data_search_cmp_uint(const struct ast_data_search *root, const char *name, - unsigned int value) -{ - struct ast_data_search *child; - unsigned int node_value; - enum data_search_comparison cmp_type; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - - node_value = atoi(child->value); - cmp_type = child->cmp_type; - - ao2_ref(child, -1); - - return data_search_comparison_result(value - node_value, cmp_type); -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current signed integer value. - * .search = "something=10" - * name = "something" - * value is the current value of something and will be evaluated against "10". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] value The value to compare. - * \returns The strcmp return value. - */ -static int data_search_cmp_int(const struct ast_data_search *root, const char *name, - int value) -{ - struct ast_data_search *child; - int node_value; - enum data_search_comparison cmp_type; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - - node_value = atoi(child->value); - cmp_type = child->cmp_type; - - ao2_ref(child, -1); - - return data_search_comparison_result(value - node_value, cmp_type); -} - -/*! - * \internal - * \brief Based on a search tree, evaluate the specified 'name' inside the tree with the - * current character value. - * .search = "something=c" - * name = "something" - * value is the current value of something and will be evaluated against "c". - * \param[in] root The root node pointer of the search tree. - * \param[in] name The name of the specific. - * \param[in] value The boolean value to compare. - * \returns The (value - current_value) result. - */ -static int data_search_cmp_char(const struct ast_data_search *root, const char *name, - char value) -{ - struct ast_data_search *child; - char node_value; - enum data_search_comparison cmp_type; - - child = data_search_get_node(root, name); - if (!child) { - return 0; - } - - node_value = *(child->value); - cmp_type = child->cmp_type; - - ao2_ref(child, -1); - - return data_search_comparison_result(value - node_value, cmp_type); -} - -/*! - * \internal - * \brief Get the member pointer, from a mapping structure, based on its name. - * \XXX We will need to improve performance here!!. - * \retval <0 if the member was not found. - * \retval >=0 The member position in the mapping structure. - */ -static inline int data_search_mapping_find(const struct ast_data_mapping_structure *map, - size_t mapping_len, - const char *member_name) -{ - int i; - - for (i = 0; i < mapping_len; i++) { - if (!strcmp(map[i].name, member_name)) { - return i; - } - } - - return -1; -} - -int __ast_data_search_cmp_structure(const struct ast_data_search *search, - const struct ast_data_mapping_structure *mapping, size_t mapping_len, - void *structure, const char *structure_name) -{ - struct ao2_iterator i; - struct ast_data_search *node, *struct_children; - int member, notmatch = 0; - - if (!search) { - return 0; - } - - struct_children = data_search_get_node(search, structure_name); - if (!struct_children) { - return 0; - } - - i = ao2_iterator_init(struct_children->children, 0); - while ((node = ao2_iterator_next(&i))) { - member = data_search_mapping_find(mapping, mapping_len, node->name); - if (member < 0) { - /* the structure member name doesn't match! */ - ao2_ref(node, -1); - ao2_ref(struct_children, -1); - ao2_iterator_destroy(&i); - return 0; - } - - notmatch = 0; - switch (mapping[member].type) { - case AST_DATA_PASSWORD: - notmatch = data_search_cmp_string(struct_children, - node->name, - mapping[member].get.AST_DATA_PASSWORD(structure)); - break; - case AST_DATA_TIMESTAMP: - notmatch = data_search_cmp_uint(struct_children, - node->name, - mapping[member].get.AST_DATA_TIMESTAMP(structure)); - break; - case AST_DATA_SECONDS: - notmatch = data_search_cmp_uint(struct_children, - node->name, - mapping[member].get.AST_DATA_SECONDS(structure)); - break; - case AST_DATA_MILLISECONDS: - notmatch = data_search_cmp_uint(struct_children, - node->name, - mapping[member].get.AST_DATA_MILLISECONDS(structure)); - break; - case AST_DATA_STRING: - notmatch = data_search_cmp_string(struct_children, - node->name, - mapping[member].get.AST_DATA_STRING(structure)); - break; - case AST_DATA_CHARACTER: - notmatch = data_search_cmp_char(struct_children, - node->name, - mapping[member].get.AST_DATA_CHARACTER(structure)); - break; - case AST_DATA_INTEGER: - notmatch = data_search_cmp_int(struct_children, - node->name, - mapping[member].get.AST_DATA_INTEGER(structure)); - break; - case AST_DATA_BOOLEAN: - notmatch = data_search_cmp_bool(struct_children, - node->name, - mapping[member].get.AST_DATA_BOOLEAN(structure)); - break; - case AST_DATA_UNSIGNED_INTEGER: - notmatch = data_search_cmp_uint(struct_children, - node->name, - mapping[member].get.AST_DATA_UNSIGNED_INTEGER(structure)); - break; - case AST_DATA_DOUBLE: - notmatch = data_search_cmp_dbl(struct_children, - node->name, - mapping[member].get.AST_DATA_DOUBLE(structure)); - break; - case AST_DATA_IPADDR: - notmatch = data_search_cmp_ipaddr(struct_children, - node->name, - mapping[member].get.AST_DATA_IPADDR(structure)); - break; - case AST_DATA_POINTER: - notmatch = data_search_cmp_ptr(struct_children, - node->name, - mapping[member].get.AST_DATA_POINTER(structure)); - break; - case AST_DATA_CONTAINER: - break; - } - - ao2_ref(node, -1); - } - ao2_iterator_destroy(&i); - - ao2_ref(struct_children, -1); - - return notmatch; -} - -/*! - * \internal - * \brief Release the memory allocated by a call to ao2_alloc. - */ -static void data_result_destructor(void *obj) -{ - struct ast_data *root = obj; - - switch (root->type) { - case AST_DATA_PASSWORD: - case AST_DATA_STRING: - ast_free(root->payload.str); - ao2_ref(root->children, -1); - break; - case AST_DATA_POINTER: - case AST_DATA_CHARACTER: - case AST_DATA_CONTAINER: - case AST_DATA_INTEGER: - case AST_DATA_TIMESTAMP: - case AST_DATA_SECONDS: - case AST_DATA_MILLISECONDS: - case AST_DATA_UNSIGNED_INTEGER: - case AST_DATA_DOUBLE: - case AST_DATA_BOOLEAN: - case AST_DATA_IPADDR: - ao2_ref(root->children, -1); - break; - } -} - -static struct ast_data *data_result_create(const char *name) -{ - struct ast_data *res; - size_t namelen; - - namelen = ast_strlen_zero(name) ? 1 : strlen(name) + 1; - - res = ao2_alloc(sizeof(*res) + namelen, data_result_destructor); - if (!res) { - return NULL; - } - - strcpy(res->name, namelen ? name : ""); - - /* initialize the children container */ - res->children = ao2_container_alloc(NUM_DATA_RESULT_BUCKETS, data_result_hash, - data_result_cmp); - if (!res->children) { - ao2_ref(res, -1); - return NULL; - } - - /* set this node as a container. */ - res->type = AST_DATA_CONTAINER; - - return res; -} - -/*! - * \internal - * \brief Find a child node, based on its name. - * \param[in] root The starting point. - * \param[in] name The child name. - * \retval NULL if the node wasn't found. - * \retval non-NULL the node we were looking for. - */ -static struct ast_data *data_result_find_child(struct ast_data *root, const char *name) -{ - struct ast_data *found, *find_node; - - find_node = data_result_create(name); - if (!find_node) { - return NULL; - } - - found = ao2_find(root->children, find_node, OBJ_POINTER); - - /* release the temporary created node used for searching. */ - ao2_ref(find_node, -1); - - return found; -} - -int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data) -{ - struct ao2_iterator i, ii; - struct ast_data_search *s, *s_child; - struct ast_data *d_child; - int notmatch = 1; - - if (!search) { - return 1; - } - - s_child = data_search_find(search->children, data->name); - if (!s_child) { - /* nothing to compare */ - ao2_ref(s_child, -1); - return 1; - } - - i = ao2_iterator_init(s_child->children, 0); - while ((s = ao2_iterator_next(&i))) { - if (!ao2_container_count(s->children)) { - /* compare this search node with every data node */ - d_child = data_result_find_child(data, s->name); - if (!d_child) { - ao2_ref(s, -1); - notmatch = 1; - continue; - } - - switch (d_child->type) { - case AST_DATA_PASSWORD: - case AST_DATA_STRING: - notmatch = data_search_cmp_string(s_child, d_child->name, - d_child->payload.str); - break; - case AST_DATA_CHARACTER: - notmatch = data_search_cmp_char(s_child, d_child->name, - d_child->payload.character); - break; - case AST_DATA_INTEGER: - notmatch = data_search_cmp_int(s_child, d_child->name, - d_child->payload.sint); - break; - case AST_DATA_BOOLEAN: - notmatch = data_search_cmp_bool(s_child, d_child->name, - d_child->payload.boolean); - break; - case AST_DATA_UNSIGNED_INTEGER: - notmatch = data_search_cmp_uint(s_child, d_child->name, - d_child->payload.uint); - break; - case AST_DATA_TIMESTAMP: - case AST_DATA_SECONDS: - case AST_DATA_MILLISECONDS: - case AST_DATA_DOUBLE: - notmatch = data_search_cmp_uint(s_child, d_child->name, - d_child->payload.dbl); - break; - case AST_DATA_IPADDR: - notmatch = data_search_cmp_ipaddr(s_child, d_child->name, - d_child->payload.ipaddr); - break; - case AST_DATA_POINTER: - notmatch = data_search_cmp_ptr(s_child, d_child->name, - d_child->payload.ptr); - break; - case AST_DATA_CONTAINER: - break; - } - ao2_ref(d_child, -1); - } else { - ii = ao2_iterator_init(data->children, 0); - while ((d_child = ao2_iterator_next(&ii))) { - if (strcmp(d_child->name, s->name)) { - ao2_ref(d_child, -1); - continue; - } - if (!(notmatch = !ast_data_search_match(s_child, d_child))) { - /* do not continue if we have a match. */ - ao2_ref(d_child, -1); - break; - } - ao2_ref(d_child, -1); - } - ao2_iterator_destroy(&ii); - } - ao2_ref(s, -1); - if (notmatch) { - /* do not continue if we don't have a match. */ - break; - } - } - ao2_iterator_destroy(&i); - - ao2_ref(s_child, -1); - - return !notmatch; -} - -/*! - * \internal - * \brief Get an internal node, from the result set. - * \param[in] node A node container. - * \param[in] path The path to the needed internal node. - * \retval NULL if the internal node is not found. - * \retval non-NULL the internal node with path 'path'. - */ -static struct ast_data *data_result_get_node(struct ast_data *node, - const char *path) -{ - char *savepath, *node_name; - struct ast_data *child, *current = node; - - savepath = ast_strdupa(path); - node_name = next_node_name(&savepath); - - while (node_name) { - child = data_result_find_child(current, node_name); - if (current != node) { - ao2_ref(current, -1); - } - if (!child) { - return NULL; - } - current = child; - node_name = next_node_name(&savepath); - } - - /* do not increment the refcount of the returned object. */ - if (current != node) { - ao2_ref(current, -1); - } - - return current; -} - -/*! - * \internal - * \brief Add a child to the specified root node. - * \param[in] root The root node pointer. - * \param[in] child The child to add to the root node. - */ -static void data_result_add_child(struct ast_data *root, struct ast_data *child) -{ - ao2_link(root->children, child); -} - -/*! - * \internal - * \brief Common string hash function for data nodes - */ -static int data_filter_hash(const void *obj, const int flags) -{ - const struct data_filter *node = obj; - return ast_str_hash(node->name); -} - -/*! - * \internal - * \brief Common string comparison function - */ -static int data_filter_cmp(void *obj, void *arg, int flags) -{ - struct data_filter *node1 = obj, *node2 = arg; - return strcasecmp(node1->name, node2->name) ? 0 : CMP_MATCH; -} - -/*! - * \internal - * \brief Destroy a data filter tree. - * \param[in] obj Data filter list to be destroyed. - */ -static void data_filter_destructor(void *obj) -{ - struct data_filter *filter = obj, *globres; - - while ((globres = AST_LIST_REMOVE_HEAD(&(filter->glob_list), list))) { - ao2_ref(globres, -1); - } - - ao2_ref(filter->children, -1); -} - -/*! - * \internal - * \brief Allocate a filter node. - * \retval NULL on error. - * \retval non-NULL The allocated search node structure. - */ -static struct data_filter *data_filter_alloc(const char *name) -{ - char *globname, *token; - struct data_filter *res, *globfilter; - size_t name_len = strlen(name) + 1; - - res = ao2_alloc(sizeof(*res) + name_len, data_filter_destructor); - if (!res) { - return NULL; - } - - res->children = ao2_container_alloc(NUM_DATA_FILTER_BUCKETS, data_filter_hash, - data_filter_cmp); - - if (!res->children) { - ao2_ref(res, -1); - return NULL; - } - - strcpy(res->name, name); - - if (strchr(res->name, '*')) { - globname = ast_strdupa(res->name); - - while ((token = strsep(&globname, "*"))) { - globfilter = data_filter_alloc(token); - AST_LIST_INSERT_TAIL(&(res->glob_list), globfilter, list); - } - } - - return res; -} - -/*! - * \internal - * \brief Release a filter tree. - * \param[in] filter The filter tree root node. - */ -static void data_filter_release(struct data_filter *filter) -{ - ao2_ref(filter, -1); -} - -/*! - * \internal - * \brief Find a child node, based on his name. - * \param[in] parent Where to find the node. - * \param[in] name The node name to find. - * \retval NULL if a node wasn't found. - * \retval The node found. - * \note Remember to decrement the ref count of the returned node after using it. - */ -static struct data_filter *data_filter_find(struct ao2_container *parent, - const char *name) -{ - int i, olend, orend, globfound; - size_t name_len = strlen(name), glob_len; - struct ao2_iterator iter; - struct data_filter *find_node, *found, *globres; - - find_node = data_filter_alloc(name); - if (!find_node) { - return NULL; - } - - found = ao2_find(parent, find_node, OBJ_POINTER); - - /* free the created node used for searching. */ - ao2_ref(find_node, -1); - - if (found) { - return found; - } - - iter = ao2_iterator_init(parent, 0); - while ((found = ao2_iterator_next(&iter))) { - if (!AST_LIST_EMPTY(&(found->glob_list))) { - i = 0; - globfound = 1; - - olend = ast_strlen_zero(AST_LIST_FIRST(&(found->glob_list))->name); - orend = ast_strlen_zero(AST_LIST_LAST(&(found->glob_list))->name); - - AST_LIST_TRAVERSE(&(found->glob_list), globres, list) { - if (!*globres->name) { - continue; - } - - glob_len = strlen(globres->name); - - if (!i && !olend) { - if (strncasecmp(name, globres->name, glob_len)) { - globfound = 0; - break; - } - - i += glob_len; - continue; - } - - for (globfound = 0; name_len - i >= glob_len; ++i) { - if (!strncasecmp(name + i, globres->name, glob_len)) { - globfound = 1; - i += glob_len; - break; - } - } - - if (!globfound) { - break; - } - } - - if (globfound && (i == name_len || orend)) { - ao2_iterator_destroy(&iter); - return found; - } - } - - ao2_ref(found, -1); - } - ao2_iterator_destroy(&iter); - - return NULL; -} - -/*! - * \internal - * \brief Add a child to the specified node. - * \param[in] root The root node where to add the child. - * \param[in] name The name of the node to add. - * \note Remember to decrement the ref count after using the returned node. - */ -static struct data_filter *data_filter_add_child(struct ao2_container *root, - char *name) -{ - struct data_filter *node; - - node = data_filter_find(root, name); - if (node) { - return node; - } - - node = data_filter_alloc(name); - if (!node) { - return NULL; - } - - ao2_link(root, node); - - return node; -} - -/*! - * \internal - * \brief Add a node to a filter list from a path - * \param[in] Filter list to add the path onto. - * \param[in] The path to add into the filter list. - * \retval NULL on error. - * \retval non-NULL A tree with the wanted nodes. - */ -static int data_filter_add_nodes(struct ao2_container *root, char *path) -{ - struct data_filter *node; - char *savepath, *saveptr, *token, *node_name; - int ret = 0; - - if (!path) { - return 0; - } - - savepath = ast_strdupa(path); - - node_name = next_node_name(&savepath); - - if (!node_name) { - return 0; - } - - for (token = strtok_r(node_name, "|", &saveptr); - token; token = strtok_r(NULL, "|", &saveptr)) { - node = data_filter_add_child(root, token); - if (!node) { - continue; - } - data_filter_add_nodes(node->children, savepath); - ret = 1; - ao2_ref(node, -1); - } - - return ret; -} - -/*! - * \internal - * \brief Generate a filter list based on a filter string provided by the API user. - * \param[in] A filter string to create a filter from. - */ -static struct data_filter *data_filter_generate(const char *constfilter) -{ - struct data_filter *filter = NULL; - char *strfilter, *token, *saveptr; - int node_added = 0; - - if (!constfilter) { - return NULL; - } - - strfilter = ast_strdupa(constfilter); - - filter = data_filter_alloc("/"); - if (!filter) { - return NULL; - } - - for (token = strtok_r(strfilter, ",", &saveptr); token; - token = strtok_r(NULL, ",", &saveptr)) { - node_added = data_filter_add_nodes(filter->children, token); - } - - if (!node_added) { - ao2_ref(filter, -1); - return NULL; - } - - return filter; -} - -/*! - * \internal - * \brief Generate all the tree from a specified provider. - * \param[in] query The query executed. - * \param[in] root_provider The provider specified in the path of the query. - * \param[in] parent_node_name The root node name. - * \retval NULL on error. - * \retval non-NULL The generated result tree. - */ -static struct ast_data *data_result_generate_node(const struct ast_data_query *query, - const struct data_provider *root_provider, - const char *parent_node_name, - const struct ast_data_search *search, - const struct data_filter *filter) -{ - struct ast_data *generated, *node; - struct ao2_iterator i; - struct data_provider *provider; - struct ast_data_search *search_child = NULL; - struct data_filter *filter_child; - - node = data_result_create(parent_node_name); - if (!node) { - ast_log(LOG_ERROR, "Unable to allocate '%s' node\n", parent_node_name); - return NULL; - } - - if (root_provider->module) { - ast_module_ref(root_provider->module); - } - - /* if this is a terminal node, just run the callback function. */ - if (root_provider->handler && root_provider->handler->get) { - node->filter = filter; - root_provider->handler->get(search, node); - if (root_provider->module) { - ast_module_unref(root_provider->module); - } - return node; - } - - if (root_provider->module) { - ast_module_unref(root_provider->module); - } - - /* if this is not a terminal node, generate every child node. */ - i = ao2_iterator_init(root_provider->children, 0); - while ((provider = ao2_iterator_next(&i))) { - filter_child = NULL; - generated = NULL; - - /* get the internal search node. */ - if (search) { - search_child = data_search_find(search->children, provider->name); - } - /* get the internal filter node. */ - if (filter) { - filter_child = data_filter_find(filter->children, provider->name); - } - - if (!filter || filter_child) { - /* only generate the internal node, if we have something to - * generate based on the filtering string. */ - generated = data_result_generate_node(query, provider, - provider->name, - search_child, filter_child); - } - - /* decrement the refcount of the internal search node. */ - if (search_child) { - ao2_ref(search_child, -1); - } - - /* decrement the refcount of the internal filter node. */ - if (filter_child) { - ao2_ref(filter_child, -1); - } - - if (generated) { - data_result_add_child(node, generated); - ao2_ref(generated, -1); - } - - ao2_ref(provider, -1); - } - ao2_iterator_destroy(&i); - - return node; -} - -/*! - * \internal - * \brief Generate a result tree based on a query. - * \param[in] query The complete query structure. - * \param[in] search_path The path to retrieve. - * \retval NULL on error. - * \retval non-NULL The generated data result. - */ -static struct ast_data *data_result_generate(const struct ast_data_query *query, - const char *search_path) -{ - char *node_name, *tmp_path; - struct data_provider *provider_child, *tmp_provider_child; - struct ast_data *result, *result_filtered; - struct ast_data_search *search = NULL, *search_child = NULL; - struct data_filter *filter = NULL, *filter_child = NULL; - - if (!search_path) { - /* generate all the trees?. */ - return NULL; - } - - tmp_path = ast_strdupa(search_path); - - /* start searching the root node name */ - node_name = next_node_name(&tmp_path); - if (!node_name) { - return NULL; - } - provider_child = data_provider_find(root_data.container, node_name, NULL); - - /* continue with the rest of the path. */ - while (provider_child) { - node_name = next_node_name(&tmp_path); - if (!node_name) { - break; - } - - tmp_provider_child = data_provider_find(provider_child->children, - node_name, NULL); - - /* release the reference from this child */ - ao2_ref(provider_child, -1); - - provider_child = tmp_provider_child; - } - - if (!provider_child) { - ast_log(LOG_ERROR, "Invalid path '%s', '%s' not found.\n", - tmp_path, node_name); - return NULL; - } - - /* generate the search tree. */ - if (query->search) { - search = data_search_generate(query->search); - if (search) { - search_child = data_search_find(search->children, - provider_child->name); - } - } - - /* generate the filter tree. */ - if (query->filter) { - filter = data_filter_generate(query->filter); - if (filter) { - filter_child = data_filter_find(filter->children, - provider_child->name); - } - } - - result = data_result_generate_node(query, provider_child, provider_child->name, - search_child, filter_child); - - /* release the requested provider. */ - ao2_ref(provider_child, -1); - - /* release the generated search tree. */ - if (search_child) { - ao2_ref(search_child, -1); - } - - if (filter_child) { - ao2_ref(filter_child, -1); - } - - if (search) { - data_search_release(search); - } - - result_filtered = result; - - /* release the generated filter tree. */ - if (filter) { - data_filter_release(filter); - } - - return result_filtered; -} - -struct ast_data *ast_data_get(const struct ast_data_query *query) -{ - struct ast_data *res; - - /* check compatibility */ - if (!data_structure_compatible(query->version, latest_query_compatible_version, - current_query_version)) { - return NULL; - } - - data_read_lock(); - res = data_result_generate(query, query->path); - data_unlock(); - - if (!res) { - ast_log(LOG_ERROR, "Unable to get data from %s\n", query->path); - return NULL; - } - - return res; -} - -#ifdef HAVE_LIBXML2 -/*! - * \internal - * \brief Helper function to move an ast_data tree to xml. - * \param[in] parent_data The initial ast_data node to be passed to xml. - * \param[out] parent_xml The root node to insert the xml. - */ -static void data_get_xml_add_child(struct ast_data *parent_data, - struct ast_xml_node *parent_xml) -{ - struct ao2_iterator i; - struct ast_data *node; - struct ast_xml_node *child_xml; - char node_content[256]; - - i = ao2_iterator_init(parent_data->children, 0); - while ((node = ao2_iterator_next(&i))) { - child_xml = ast_xml_new_node(node->name); - if (!child_xml) { - ao2_ref(node, -1); - continue; - } - - switch (node->type) { - case AST_DATA_CONTAINER: - data_get_xml_add_child(node, child_xml); - break; - case AST_DATA_PASSWORD: - ast_xml_set_text(child_xml, node->payload.str); - break; - case AST_DATA_TIMESTAMP: - snprintf(node_content, sizeof(node_content), "%u", - node->payload.uint); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_SECONDS: - snprintf(node_content, sizeof(node_content), "%u", - node->payload.uint); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_MILLISECONDS: - snprintf(node_content, sizeof(node_content), "%u", - node->payload.uint); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_STRING: - ast_xml_set_text(child_xml, node->payload.str); - break; - case AST_DATA_CHARACTER: - snprintf(node_content, sizeof(node_content), "%c", - node->payload.character); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_INTEGER: - snprintf(node_content, sizeof(node_content), "%d", - node->payload.sint); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_UNSIGNED_INTEGER: - snprintf(node_content, sizeof(node_content), "%u", - node->payload.uint); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_DOUBLE: - snprintf(node_content, sizeof(node_content), "%f", - node->payload.dbl); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_BOOLEAN: - if (node->payload.boolean) { - ast_xml_set_text(child_xml, "true"); - } else { - ast_xml_set_text(child_xml, "false"); - } - break; - case AST_DATA_POINTER: - snprintf(node_content, sizeof(node_content), "%p", - node->payload.ptr); - ast_xml_set_text(child_xml, node_content); - break; - case AST_DATA_IPADDR: - snprintf(node_content, sizeof(node_content), "%s", - ast_inet_ntoa(node->payload.ipaddr)); - ast_xml_set_text(child_xml, node_content); - break; - } - ast_xml_add_child(parent_xml, child_xml); - - ao2_ref(node, -1); - } - ao2_iterator_destroy(&i); - -} - -struct ast_xml_doc *ast_data_get_xml(const struct ast_data_query *query) -{ - struct ast_xml_doc *doc; - struct ast_xml_node *root; - struct ast_data *res; - - res = ast_data_get(query); - if (!res) { - return NULL; - } - - doc = ast_xml_new(); - if (!doc) { - ast_data_free(res); - return NULL; - } - - root = ast_xml_new_node(res->name); - if (!root) { - ast_xml_close(doc); - } - - ast_xml_set_root(doc, root); - - data_get_xml_add_child(res, root); - - ast_data_free(res); - - return doc; -} -#endif - -enum ast_data_type ast_data_retrieve_type(struct ast_data *node, const char *path) -{ - struct ast_data *internal; - - internal = data_result_get_node(node, path); - if (!internal) { - return -1; - } - - return internal->type; -} - -char *ast_data_retrieve_name(struct ast_data *node) -{ - return node->name; -} - -/*! - * \internal - * \brief Insert a child node inside a passed parent node. - * \param root Where we are going to insert the child node. - * \param name The name of the child node to add. - * \param type The type of content inside the child node. - * \param ptr The actual content of the child node. - * \retval NULL on error. - * \retval non-NULL The added child node pointer. - */ -static struct ast_data *__ast_data_add(struct ast_data *root, const char *name, - enum ast_data_type type, void *ptr) -{ - struct ast_data *node; - struct data_filter *filter, *filter_child = NULL; - - if (!root || !root->children) { - /* invalid data result node. */ - return NULL; - } - - /* check if we need to add this node, based on the filter. */ - if (root->filter) { - filter = data_filter_find(root->filter->children, name); - if (!filter) { - return NULL; - } - ao2_ref(filter, -1); - } - - node = data_result_create(name); - if (!node) { - return NULL; - } - - node->type = type; - - switch (type) { - case AST_DATA_BOOLEAN: - node->payload.boolean = *(unsigned int *) ptr; - break; - case AST_DATA_INTEGER: - node->payload.sint = *(int *) ptr; - break; - case AST_DATA_TIMESTAMP: - case AST_DATA_SECONDS: - case AST_DATA_MILLISECONDS: - case AST_DATA_UNSIGNED_INTEGER: - node->payload.uint = *(unsigned int *) ptr; - break; - case AST_DATA_DOUBLE: - node->payload.dbl = *(double *) ptr; - break; - case AST_DATA_PASSWORD: - case AST_DATA_STRING: - node->payload.str = (char *) ptr; - break; - case AST_DATA_CHARACTER: - node->payload.character = *(char *) ptr; - break; - case AST_DATA_POINTER: - node->payload.ptr = ptr; - break; - case AST_DATA_IPADDR: - node->payload.ipaddr = *(struct in_addr *) ptr; - break; - case AST_DATA_CONTAINER: - if (root->filter) { - filter_child = data_filter_find(root->filter->children, name); - if (filter_child) { - /* do not increment the refcount because it is not neccesary. */ - ao2_ref(filter_child, -1); - } - } - node->filter = filter_child; - break; - default: - break; - } - - data_result_add_child(root, node); - - ao2_ref(node, -1); - - return node; -} - -struct ast_data *ast_data_add_node(struct ast_data *root, const char *name) -{ - return __ast_data_add(root, name, AST_DATA_CONTAINER, NULL); -} - -struct ast_data *ast_data_add_int(struct ast_data *root, const char *name, int value) -{ - return __ast_data_add(root, name, AST_DATA_INTEGER, &value); -} - -struct ast_data *ast_data_add_char(struct ast_data *root, const char *name, char value) -{ - return __ast_data_add(root, name, AST_DATA_CHARACTER, &value); -} - -struct ast_data *ast_data_add_uint(struct ast_data *root, const char *name, - unsigned int value) -{ - return __ast_data_add(root, name, AST_DATA_UNSIGNED_INTEGER, &value); -} - -struct ast_data *ast_data_add_dbl(struct ast_data *root, const char *childname, - double dbl) -{ - return __ast_data_add(root, childname, AST_DATA_DOUBLE, &dbl); -} - -struct ast_data *ast_data_add_bool(struct ast_data *root, const char *childname, - unsigned int boolean) -{ - return __ast_data_add(root, childname, AST_DATA_BOOLEAN, &boolean); -} - -struct ast_data *ast_data_add_ipaddr(struct ast_data *root, const char *childname, - struct in_addr addr) -{ - return __ast_data_add(root, childname, AST_DATA_IPADDR, &addr); -} - -struct ast_data *ast_data_add_ptr(struct ast_data *root, const char *childname, - void *ptr) -{ - return __ast_data_add(root, childname, AST_DATA_POINTER, ptr); -} - -struct ast_data *ast_data_add_timestamp(struct ast_data *root, const char *childname, - unsigned int timestamp) -{ - return __ast_data_add(root, childname, AST_DATA_TIMESTAMP, ×tamp); -} - -struct ast_data *ast_data_add_seconds(struct ast_data *root, const char *childname, - unsigned int seconds) -{ - return __ast_data_add(root, childname, AST_DATA_SECONDS, &seconds); -} - -struct ast_data *ast_data_add_milliseconds(struct ast_data *root, const char *childname, - unsigned int milliseconds) -{ - return __ast_data_add(root, childname, AST_DATA_MILLISECONDS, &milliseconds); -} - -struct ast_data *ast_data_add_password(struct ast_data *root, const char *childname, - const char *value) -{ - char *name; - size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value)); - struct ast_data *res; - - if (!(name = ast_malloc(namelen))) { - return NULL; - } - - strcpy(name, (ast_strlen_zero(value) ? "" : value)); - - res = __ast_data_add(root, childname, AST_DATA_PASSWORD, name); - if (!res) { - ast_free(name); - } - - return res; -} - -struct ast_data *ast_data_add_str(struct ast_data *root, const char *childname, - const char *value) -{ - char *name; - size_t namelen = 1 + (ast_strlen_zero(value) ? 0 : strlen(value)); - struct ast_data *res; - - if (!(name = ast_malloc(namelen))) { - return NULL; - } - - strcpy(name, (ast_strlen_zero(value) ? "" : value)); - - res = __ast_data_add(root, childname, AST_DATA_STRING, name); - if (!res) { - ast_free(name); - } - - return res; -} - -int __ast_data_add_structure(struct ast_data *root, - const struct ast_data_mapping_structure *mapping, size_t mapping_len, - void *structure) -{ - int i; - - for (i = 0; i < mapping_len; i++) { - switch (mapping[i].type) { - case AST_DATA_INTEGER: - ast_data_add_int(root, mapping[i].name, - mapping[i].get.AST_DATA_INTEGER(structure)); - break; - case AST_DATA_UNSIGNED_INTEGER: - ast_data_add_uint(root, mapping[i].name, - mapping[i].get.AST_DATA_UNSIGNED_INTEGER(structure)); - break; - case AST_DATA_DOUBLE: - ast_data_add_dbl(root, mapping[i].name, - mapping[i].get.AST_DATA_DOUBLE(structure)); - break; - case AST_DATA_BOOLEAN: - ast_data_add_bool(root, mapping[i].name, - mapping[i].get.AST_DATA_BOOLEAN(structure)); - break; - case AST_DATA_PASSWORD: - ast_data_add_password(root, mapping[i].name, - mapping[i].get.AST_DATA_PASSWORD(structure)); - break; - case AST_DATA_TIMESTAMP: - ast_data_add_timestamp(root, mapping[i].name, - mapping[i].get.AST_DATA_TIMESTAMP(structure)); - break; - case AST_DATA_SECONDS: - ast_data_add_seconds(root, mapping[i].name, - mapping[i].get.AST_DATA_SECONDS(structure)); - break; - case AST_DATA_MILLISECONDS: - ast_data_add_milliseconds(root, mapping[i].name, - mapping[i].get.AST_DATA_MILLISECONDS(structure)); - break; - case AST_DATA_STRING: - ast_data_add_str(root, mapping[i].name, - mapping[i].get.AST_DATA_STRING(structure)); - break; - case AST_DATA_CHARACTER: - ast_data_add_char(root, mapping[i].name, - mapping[i].get.AST_DATA_CHARACTER(structure)); - break; - case AST_DATA_CONTAINER: - break; - case AST_DATA_IPADDR: - ast_data_add_ipaddr(root, mapping[i].name, - mapping[i].get.AST_DATA_IPADDR(structure)); - break; - case AST_DATA_POINTER: - ast_data_add_ptr(root, mapping[i].name, - mapping[i].get.AST_DATA_POINTER(structure)); - break; - } - } - - return 0; -} - -void ast_data_remove_node(struct ast_data *root, struct ast_data *child) -{ - ao2_unlink(root->children, child); -} - -void ast_data_free(struct ast_data *root) -{ - /* destroy it, this will destroy all the internal nodes. */ - ao2_ref(root, -1); -} - -struct ast_data_iterator *ast_data_iterator_init(struct ast_data *tree, - const char *elements) -{ - struct ast_data_iterator *iterator; - struct ao2_iterator i; - struct ast_data *internal = tree; - char *path, *ptr = NULL; - - if (!elements) { - return NULL; - } - - /* tree is the node we want to use to iterate? or we are going - * to iterate thow an internal node? */ - path = ast_strdupa(elements); - - ptr = strrchr(path, '/'); - if (ptr) { - *ptr = '\0'; - internal = data_result_get_node(tree, path); - if (!internal) { - return NULL; - } - } - - iterator = ast_calloc(1, sizeof(*iterator)); - if (!iterator) { - return NULL; - } - - i = ao2_iterator_init(internal->children, 0); - - iterator->pattern = (ptr ? strrchr(elements, '/') + 1 : elements); - - /* is the last node a regular expression?, compile it! */ - if (!regcomp(&(iterator->regex_pattern), iterator->pattern, - REG_EXTENDED | REG_NOSUB | REG_ICASE)) { - iterator->is_pattern = 1; - } - - iterator->internal_iterator = i; - - return iterator; -} - -void ast_data_iterator_end(struct ast_data_iterator *iterator) -{ - /* decrement the reference counter. */ - if (iterator->last) { - ao2_ref(iterator->last, -1); - } - - /* release the generated pattern. */ - if (iterator->is_pattern) { - regfree(&(iterator->regex_pattern)); - } - - ao2_iterator_destroy(&(iterator->internal_iterator)); - - ast_free(iterator); - iterator = NULL; -} - -struct ast_data *ast_data_iterator_next(struct ast_data_iterator *iterator) -{ - struct ast_data *res; - - if (iterator->last) { - /* release the last retrieved node reference. */ - ao2_ref(iterator->last, -1); - } - - while ((res = ao2_iterator_next(&iterator->internal_iterator))) { - /* if there is no node name pattern specified, return - * the next node. */ - if (!iterator->pattern) { - break; - } - - /* if the pattern is a regular expression, check if this node - * matches. */ - if (iterator->is_pattern && !regexec(&(iterator->regex_pattern), - res->name, 0, NULL, 0)) { - break; - } - - /* if there is a pattern specified, check if this node matches - * the wanted node names. */ - if (!iterator->is_pattern && (iterator->pattern && - !strcasecmp(res->name, iterator->pattern))) { - break; - } - - ao2_ref(res, -1); - } - - iterator->last = res; - - return res; -} - -int ast_data_retrieve(struct ast_data *tree, const char *path, - struct ast_data_retrieve *content) -{ - struct ast_data *node; - - if (!content) { - return -1; - } - - node = data_result_get_node(tree, path); - if (!node) { - ast_log(LOG_ERROR, "Invalid internal node %s\n", path); - return -1; - } - - content->type = node->type; - switch (node->type) { - case AST_DATA_STRING: - content->value.AST_DATA_STRING = node->payload.str; - break; - case AST_DATA_PASSWORD: - content->value.AST_DATA_PASSWORD = node->payload.str; - break; - case AST_DATA_TIMESTAMP: - content->value.AST_DATA_TIMESTAMP = node->payload.uint; - break; - case AST_DATA_SECONDS: - content->value.AST_DATA_SECONDS = node->payload.uint; - break; - case AST_DATA_MILLISECONDS: - content->value.AST_DATA_MILLISECONDS = node->payload.uint; - break; - case AST_DATA_CHARACTER: - content->value.AST_DATA_CHARACTER = node->payload.character; - break; - case AST_DATA_INTEGER: - content->value.AST_DATA_INTEGER = node->payload.sint; - break; - case AST_DATA_UNSIGNED_INTEGER: - content->value.AST_DATA_UNSIGNED_INTEGER = node->payload.uint; - break; - case AST_DATA_BOOLEAN: - content->value.AST_DATA_BOOLEAN = node->payload.boolean; - break; - case AST_DATA_IPADDR: - content->value.AST_DATA_IPADDR = node->payload.ipaddr; - break; - case AST_DATA_DOUBLE: - content->value.AST_DATA_DOUBLE = node->payload.dbl; - break; - case AST_DATA_CONTAINER: - break; - case AST_DATA_POINTER: - content->value.AST_DATA_POINTER = node->payload.ptr; - break; - } - - return 0; -} - -/*! - * \internal - * \brief One color for each node type. - */ -static const struct { - enum ast_data_type type; - int color; -} data_result_color[] = { - { AST_DATA_STRING, COLOR_BLUE }, - { AST_DATA_PASSWORD, COLOR_BRBLUE }, - { AST_DATA_TIMESTAMP, COLOR_CYAN }, - { AST_DATA_SECONDS, COLOR_MAGENTA }, - { AST_DATA_MILLISECONDS, COLOR_BRMAGENTA }, - { AST_DATA_CHARACTER, COLOR_GRAY }, - { AST_DATA_INTEGER, COLOR_RED }, - { AST_DATA_UNSIGNED_INTEGER, COLOR_RED }, - { AST_DATA_DOUBLE, COLOR_RED }, - { AST_DATA_BOOLEAN, COLOR_BRRED }, - { AST_DATA_CONTAINER, COLOR_GREEN }, - { AST_DATA_IPADDR, COLOR_BROWN }, - { AST_DATA_POINTER, COLOR_YELLOW }, -}; - -/*! - * \internal - * \brief Get the color configured for a specific node type. - * \param[in] type The node type. - * \returns The color specified for the passed type. - */ -static int data_result_get_color(enum ast_data_type type) -{ - int i; - for (i = 0; i < ARRAY_LEN(data_result_color); i++) { - if (data_result_color[i].type == type) { - return data_result_color[i].color; - } - } - - return COLOR_BLUE; -} - -/*! - * \internal - * \brief Print a node to the CLI. - * \param[in] fd The CLI file descriptor. - * \param[in] node The node to print. - * \param[in] depth The actual node depth in the tree. - */ -static void data_result_print_cli_node(int fd, const struct ast_data *node, uint32_t depth) -{ - int i; - struct ast_str *tabs, *output; - - tabs = ast_str_create(depth * 10 + 1); - if (!tabs) { - return; - } - ast_str_reset(tabs); - for (i = 0; i < depth; i++) { - ast_str_append(&tabs, 0, " "); - } - - output = ast_str_create(20); - if (!output) { - ast_free(tabs); - return; - } - - ast_str_reset(output); - ast_term_color_code(&output, data_result_get_color(node->type), 0); - - switch (node->type) { - case AST_DATA_POINTER: - ast_str_append(&output, 0, "%s%s: %p\n", ast_str_buffer(tabs), - node->name, node->payload.ptr); - break; - case AST_DATA_PASSWORD: - ast_str_append(&output, 0, "%s%s: \"%s\"\n", - ast_str_buffer(tabs), - node->name, - node->payload.str); - break; - case AST_DATA_STRING: - ast_str_append(&output, 0, "%s%s: \"%s\"\n", - ast_str_buffer(tabs), - node->name, - node->payload.str); - break; - case AST_DATA_CHARACTER: - ast_str_append(&output, 0, "%s%s: \'%c\'\n", - ast_str_buffer(tabs), - node->name, - node->payload.character); - break; - case AST_DATA_CONTAINER: - ast_str_append(&output, 0, "%s%s\n", ast_str_buffer(tabs), - node->name); - break; - case AST_DATA_TIMESTAMP: - ast_str_append(&output, 0, "%s%s: %u\n", ast_str_buffer(tabs), - node->name, - node->payload.uint); - break; - case AST_DATA_SECONDS: - ast_str_append(&output, 0, "%s%s: %u\n", ast_str_buffer(tabs), - node->name, - node->payload.uint); - break; - case AST_DATA_MILLISECONDS: - ast_str_append(&output, 0, "%s%s: %u\n", ast_str_buffer(tabs), - node->name, - node->payload.uint); - break; - case AST_DATA_INTEGER: - ast_str_append(&output, 0, "%s%s: %d\n", ast_str_buffer(tabs), - node->name, - node->payload.sint); - break; - case AST_DATA_UNSIGNED_INTEGER: - ast_str_append(&output, 0, "%s%s: %u\n", ast_str_buffer(tabs), - node->name, - node->payload.uint); - break; - case AST_DATA_DOUBLE: - ast_str_append(&output, 0, "%s%s: %lf\n", ast_str_buffer(tabs), - node->name, - node->payload.dbl); - break; - case AST_DATA_BOOLEAN: - ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs), - node->name, - ((node->payload.boolean) ? "True" : "False")); - break; - case AST_DATA_IPADDR: - ast_str_append(&output, 0, "%s%s: %s\n", ast_str_buffer(tabs), - node->name, - ast_inet_ntoa(node->payload.ipaddr)); - break; - } - - ast_free(tabs); - - ast_term_color_code(&output, 0, 0); - - ast_cli(fd, "%s", ast_str_buffer(output)); - - ast_free(output); - - if (node->type == AST_DATA_CONTAINER) { - __data_result_print_cli(fd, node, depth + 1); - } -} - -/*! - * \internal - * \brief Print out an ast_data tree to the CLI. - * \param[in] fd The CLI file descriptor. - * \param[in] root The root node of the tree. - * \param[in] depth Actual depth. - */ - -static void __data_result_print_cli(int fd, const struct ast_data *root, uint32_t depth) -{ - struct ao2_iterator iter; - struct ast_data *node; - - if (root->type == AST_DATA_CONTAINER) { - iter = ao2_iterator_init(root->children, 0); - while ((node = ao2_iterator_next(&iter))) { - data_result_print_cli_node(fd, node, depth + 1); - ao2_ref(node, -1); - } - ao2_iterator_destroy(&iter); - } else { - data_result_print_cli_node(fd, root, depth); - } -} - -/*! - * \internal - * \brief - * \param[in] fd The CLI file descriptor. - * \param[in] root The root node of the tree. - */ -static void data_result_print_cli(int fd, const struct ast_data *root) -{ - ast_cli(fd, COLORIZE_FMT "\n", COLORIZE(data_result_get_color(root->type), 0, root->name)); - - __data_result_print_cli(fd, root, 0); - - ast_cli(fd, "\n"); -} - -/*! - * \internal - * \brief Handle the CLI command "data get". - */ -static char *handle_cli_data_get(struct ast_cli_entry *e, int cmd, - struct ast_cli_args *a) -{ - struct ast_data_query query = { - .version = AST_DATA_QUERY_VERSION - }; - struct ast_data *tree; - - switch (cmd) { - case CLI_INIT: - e->command = "data get"; - e->usage = "" - "Usage: data get [ []]\n" - " Get the tree based on a path.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc < e->args + 1) { - return CLI_SHOWUSAGE; - } - - query.path = (char *) a->argv[e->args]; - - if (a->argc > e->args + 1) { - query.search = (char *) a->argv[e->args + 1]; - } - - if (a->argc > e->args + 2) { - query.filter = (char *) a->argv[e->args + 2]; - } - - tree = ast_data_get(&query); - if (!tree) { - return CLI_FAILURE; - } - - data_result_print_cli(a->fd, tree); - - ast_data_free(tree); - - return CLI_SUCCESS; -} - -/*! - * \internal - * \brief Print the list of data providers. - * \param[in] fd The CLI file descriptor. - * \param[in] name The last node visited name. - * \param[in] container The childrens of the last node. - * \param[in] path The path to the current node. - */ -static void data_provider_print_cli(int fd, const char *name, - struct ao2_container *container, struct ast_str *path) -{ - struct ao2_iterator i; - struct ast_str *current_path; - struct data_provider *provider; - - current_path = ast_str_create(60); - if (!current_path) { - return; - } - - ast_str_reset(current_path); - if (path) { - ast_str_set(¤t_path, 0, "%s/%s", ast_str_buffer(path), name); - } else { - ast_str_set(¤t_path, 0, "%s", name); - } - - i = ao2_iterator_init(container, 0); - while ((provider = ao2_iterator_next(&i))) { - if (provider->handler) { - /* terminal node, print it. */ - ast_cli(fd, "%s/%s (", ast_str_buffer(current_path), - provider->name); - if (provider->handler->get) { - ast_cli(fd, "get"); - } - ast_cli(fd, ") [%s]\n", provider->registrar); - } - data_provider_print_cli(fd, provider->name, provider->children, - current_path); - ao2_ref(provider, -1); - } - ao2_iterator_destroy(&i); - - ast_free(current_path); -} - -/*! - * \internal - * \brief Handle CLI command "data show providers" - */ -static char *handle_cli_data_show_providers(struct ast_cli_entry *e, int cmd, - struct ast_cli_args *a) -{ - switch (cmd) { - case CLI_INIT: - e->command = "data show providers"; - e->usage = "" - "Usage: data show providers\n" - " Show the list of registered providers\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - data_read_lock(); - data_provider_print_cli(a->fd, "", root_data.container, NULL); - data_unlock(); - - return CLI_SUCCESS; -} - -/*! - * \internal - * \brief Data API CLI commands. - */ -static struct ast_cli_entry cli_data[] = { - AST_CLI_DEFINE(handle_cli_data_get, "Data API get"), - AST_CLI_DEFINE(handle_cli_data_show_providers, "Show data providers") -}; - -/*! - * \internal - * \brief Output a tree to the AMI. - * \param[in] s AMI session. - * \param[in] name The root node name. - * \param[in] container The root container. - * \param[in] path The current path. - */ -static void data_result_manager_output(struct mansession *s, const char *name, - struct ao2_container *container, struct ast_str *path, int id) -{ - struct ao2_iterator i; - struct ast_str *current_path; - struct ast_data *node; - int current_id = id; - - current_path = ast_str_create(60); - if (!current_path) { - return; - } - - ast_str_reset(current_path); - if (path) { - ast_str_set(¤t_path, 0, "%s.%s", ast_str_buffer(path), name); - } else { - ast_str_set(¤t_path, 0, "%s", name); - } - - i = ao2_iterator_init(container, 0); - while ((node = ao2_iterator_next(&i))) { - /* terminal node, print it. */ - if (node->type != AST_DATA_CONTAINER) { - astman_append(s, "%d-%s.%s", id, ast_str_buffer(current_path), - node->name); - } - switch (node->type) { - case AST_DATA_CONTAINER: - data_result_manager_output(s, node->name, node->children, current_path, ++current_id); - break; - case AST_DATA_INTEGER: - astman_append(s, ": %d\r\n", node->payload.sint); - break; - case AST_DATA_TIMESTAMP: - case AST_DATA_SECONDS: - case AST_DATA_MILLISECONDS: - case AST_DATA_UNSIGNED_INTEGER: - astman_append(s, ": %u\r\n", node->payload.uint); - break; - case AST_DATA_PASSWORD: - astman_append(s, ": %s\r\n", node->payload.str); - break; - case AST_DATA_STRING: - astman_append(s, ": %s\r\n", node->payload.str); - break; - case AST_DATA_CHARACTER: - astman_append(s, ": %c\r\n", node->payload.character); - break; - case AST_DATA_IPADDR: - astman_append(s, ": %s\r\n", ast_inet_ntoa(node->payload.ipaddr)); - break; - case AST_DATA_POINTER: - break; - case AST_DATA_DOUBLE: - astman_append(s, ": %f\r\n", node->payload.dbl); - break; - case AST_DATA_BOOLEAN: - astman_append(s, ": %s\r\n", - (node->payload.boolean ? "True" : "False")); - break; - } - - ao2_ref(node, -1); - } - ao2_iterator_destroy(&i); - - ast_free(current_path); -} - -/*! - * \internal - * \brief Implements the manager action: "DataGet". - */ -static int manager_data_get(struct mansession *s, const struct message *m) -{ - const char *path = astman_get_header(m, "Path"); - const char *search = astman_get_header(m, "Search"); - const char *filter = astman_get_header(m, "Filter"); - const char *id = astman_get_header(m, "ActionID"); - struct ast_data *res; - struct ast_data_query query = { - .version = AST_DATA_QUERY_VERSION, - .path = (char *) path, - .search = (char *) search, - .filter = (char *) filter, - }; - - if (ast_strlen_zero(path)) { - astman_send_error(s, m, "'Path' parameter not specified"); - return 0; - } - - res = ast_data_get(&query); - if (!res) { - astman_send_error(s, m, "No data returned"); - return 0; - } - - astman_append(s, "Event: DataGet Tree\r\n"); - if (!ast_strlen_zero(id)) { - astman_append(s, "ActionID: %s\r\n", id); - } - data_result_manager_output(s, res->name, res->children, NULL, 0); - astman_append(s, "\r\n"); - - ast_data_free(res); - - return RESULT_SUCCESS; -} - -static int data_add_codec(struct ast_data *codecs, struct ast_format *format) { - struct ast_data *codec; - struct ast_codec *tmp; - - tmp = ast_codec_get_by_id(ast_format_get_codec_id(format)); - if (!tmp) { - return -1; - } - - codec = ast_data_add_node(codecs, "codec"); - if (!codec) { - ao2_ref(tmp, -1); - return -1; - } - - ast_data_add_str(codec, "name", tmp->name); - ast_data_add_int(codec, "samplespersecond", tmp->sample_rate); - ast_data_add_str(codec, "description", tmp->description); - ast_data_add_int(codec, "frame_length", tmp->minimum_bytes); - ao2_ref(tmp, -1); - - return 0; -} - -int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_format *format) -{ - struct ast_data *codecs; - - codecs = ast_data_add_node(root, node_name); - if (!codecs) { - return -1; - } - - return data_add_codec(codecs, format); -} - -int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast_format_cap *cap) -{ - struct ast_data *codecs; - size_t i; - size_t count; - - codecs = ast_data_add_node(root, node_name); - if (!codecs) { - return -1; - } - - count = ast_format_cap_count(cap); - for (i = 0; i < count; ++i) { - struct ast_format *fmt; - - fmt = ast_format_cap_get_format(cap, i); - if (!fmt) { - return -1; - } - - if (data_add_codec(codecs, fmt)) { - ao2_ref(fmt, -1); - return -1; - } - - ao2_ref(fmt, -1); - } - - return 0; -} - -#ifdef TEST_FRAMEWORK - -/*! - * \internal - * \brief Structure used to test how to add a complete structure, - * and how to compare it. - */ -struct test_structure { - int a_int; - unsigned int b_bool:1; - char *c_str; - unsigned int a_uint; -}; - -/*! - * \internal - * \brief test_structure mapping. - */ -#define DATA_EXPORT_TEST_STRUCTURE(MEMBER) \ - MEMBER(test_structure, a_int, AST_DATA_INTEGER) \ - MEMBER(test_structure, b_bool, AST_DATA_BOOLEAN) \ - MEMBER(test_structure, c_str, AST_DATA_STRING) \ - MEMBER(test_structure, a_uint, AST_DATA_UNSIGNED_INTEGER) - -AST_DATA_STRUCTURE(test_structure, DATA_EXPORT_TEST_STRUCTURE); - -/*! - * \internal - * \brief Callback implementation. - */ -static int test_data_full_provider(const struct ast_data_search *search, - struct ast_data *root) -{ - struct ast_data *test_structure; - struct test_structure local_test_structure = { - .a_int = 10, - .b_bool = 1, - .c_str = "test string", - .a_uint = 20 - }; - - test_structure = ast_data_add_node(root, "test_structure"); - if (!test_structure) { - ast_debug(1, "Internal data api error\n"); - return 0; - } - - /* add the complete structure. */ - ast_data_add_structure(test_structure, test_structure, &local_test_structure); - - if (!ast_data_search_match(search, test_structure)) { - ast_data_remove_node(root, test_structure); - } - - return 0; -} - -/*! - * \internal - * \brief Handler definition for the full provider. - */ -static const struct ast_data_handler full_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = test_data_full_provider -}; - -/*! - * \internal - * \brief Structure used to define multiple providers at once. - */ -static const struct ast_data_entry test_providers[] = { - AST_DATA_ENTRY("test/node1/node11/node111", &full_provider) -}; - -AST_TEST_DEFINE(test_data_get) -{ - struct ast_data *res, *node; - struct ast_data_iterator *i; - struct ast_data_query query = { - .version = AST_DATA_QUERY_VERSION, - .path = "test/node1/node11/node111", - .search = "node111/test_structure/a_int=10", - .filter = "node111/test_structure/a*int" - }; - - switch (cmd) { - case TEST_INIT: - info->name = "data_test"; - info->category = "/main/data/"; - info->summary = "Data API unit test"; - info->description = - "Tests whether data API get implementation works as expected."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - ast_data_register_multiple_core(test_providers, ARRAY_LEN(test_providers)); - - res = ast_data_get(&query); - if (!res) { - ast_test_status_update(test, "Unable to get tree."); - ast_data_unregister("test/node1/node11/node111"); - return AST_TEST_FAIL; - } - - /* initiate the iterator and check for errors. */ - i = ast_data_iterator_init(res, "test_structure/"); - if (!i) { - ast_test_status_update(test, "Unable to initiate the iterator."); - ast_data_free(res); - ast_data_unregister("test/node1/node11/node111"); - return AST_TEST_FAIL; - } - - /* walk the returned nodes. */ - while ((node = ast_data_iterator_next(i))) { - if (!strcmp(ast_data_retrieve_name(node), "a_int")) { - if (ast_data_retrieve_int(node, "/") != 10) { - ast_data_iterator_end(i); - ast_data_free(res); - ast_data_unregister("test/node1/node11/node111"); - return AST_TEST_FAIL; - } - } else if (!strcmp(ast_data_retrieve_name(node), "a_uint")) { - if (ast_data_retrieve_uint(node, "/") != 20) { - ast_data_iterator_end(i); - ast_data_free(res); - ast_data_unregister("test/node1/node11/node111"); - return AST_TEST_FAIL; - } - } - } - - /* finish the iterator. */ - ast_data_iterator_end(i); - - ast_data_free(res); - - ast_data_unregister("test/node1/node11/node111"); - - return AST_TEST_PASS; -} - -#endif - -/*! - * \internal - * \brief Clean up resources on Asterisk shutdown - */ -static void data_shutdown(void) -{ - ast_manager_unregister("DataGet"); - ast_cli_unregister_multiple(cli_data, ARRAY_LEN(cli_data)); - ao2_t_ref(root_data.container, -1, "Unref root_data.container in data_shutdown"); - root_data.container = NULL; - ast_rwlock_destroy(&root_data.lock); - AST_TEST_UNREGISTER(test_data_get); -} - -int ast_data_init(void) -{ - int res = 0; - - ast_rwlock_init(&root_data.lock); - - if (!(root_data.container = ao2_container_alloc(NUM_DATA_NODE_BUCKETS, - data_provider_hash, data_provider_cmp))) { - return -1; - } - - res |= ast_cli_register_multiple(cli_data, ARRAY_LEN(cli_data)); - - res |= ast_manager_register_xml_core("DataGet", 0, manager_data_get); - - AST_TEST_REGISTER(test_data_get); - - ast_register_cleanup(data_shutdown); - - return res; -} diff --git a/main/indications.c b/main/indications.c index 0af6668cfc0..8940a37b08d 100644 --- a/main/indications.c +++ b/main/indications.c @@ -41,23 +41,9 @@ #include "asterisk/cli.h" #include "asterisk/module.h" #include "asterisk/astobj2.h" -#include "asterisk/data.h" #include "asterisk/_private.h" /* _init(), _reload() */ -#define DATA_EXPORT_TONE_ZONE(MEMBER) \ - MEMBER(ast_tone_zone, country, AST_DATA_STRING) \ - MEMBER(ast_tone_zone, description, AST_DATA_STRING) \ - MEMBER(ast_tone_zone, nrringcadence, AST_DATA_UNSIGNED_INTEGER) - -AST_DATA_STRUCTURE(ast_tone_zone, DATA_EXPORT_TONE_ZONE); - -#define DATA_EXPORT_TONE_ZONE_SOUND(MEMBER) \ - MEMBER(ast_tone_zone_sound, name, AST_DATA_STRING) \ - MEMBER(ast_tone_zone_sound, data, AST_DATA_STRING) - -AST_DATA_STRUCTURE(ast_tone_zone_sound, DATA_EXPORT_TONE_ZONE_SOUND); - /* Globals */ static const char config[] = "indications.conf"; @@ -1124,33 +1110,6 @@ static int ast_tone_zone_cmp(void *obj, void *arg, int flags) CMP_MATCH | CMP_STOP : 0; } -int ast_tone_zone_data_add_structure(struct ast_data *tree, struct ast_tone_zone *zone) -{ - struct ast_data *data_zone_sound; - struct ast_tone_zone_sound *s; - - ast_data_add_structure(ast_tone_zone, tree, zone); - - if (AST_LIST_EMPTY(&zone->tones)) { - return 0; - } - - data_zone_sound = ast_data_add_node(tree, "tones"); - if (!data_zone_sound) { - return -1; - } - - ast_tone_zone_lock(zone); - - AST_LIST_TRAVERSE(&zone->tones, s, entry) { - ast_data_add_structure(ast_tone_zone_sound, data_zone_sound, s); - } - - ast_tone_zone_unlock(zone); - - return 0; -} - /*! * \internal * \brief Clean up resources on Asterisk shutdown diff --git a/main/pbx.c b/main/pbx.c index ccfba054e7c..2366b72b05b 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -8306,56 +8306,6 @@ static void presence_state_cb(void *unused, struct stasis_subscription *sub, str ast_free(hint_app); } -/*! - * \internal - * \brief Implements the hints data provider. - */ -static int hints_data_provider_get(const struct ast_data_search *search, - struct ast_data *data_root) -{ - struct ast_data *data_hint; - struct ast_hint *hint; - int watchers; - struct ao2_iterator i; - - if (ao2_container_count(hints) == 0) { - return 0; - } - - i = ao2_iterator_init(hints, 0); - for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) { - watchers = ao2_container_count(hint->callbacks); - data_hint = ast_data_add_node(data_root, "hint"); - if (!data_hint) { - continue; - } - ast_data_add_str(data_hint, "extension", ast_get_extension_name(hint->exten)); - ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten))); - ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten)); - ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate)); - ast_data_add_str(data_hint, "presence_state", ast_presence_state2str(hint->last_presence_state)); - ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_subtype, "")); - ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_message, "")); - ast_data_add_int(data_hint, "watchers", watchers); - - if (!ast_data_search_match(search, data_hint)) { - ast_data_remove_node(data_root, data_hint); - } - } - ao2_iterator_destroy(&i); - - return 0; -} - -static const struct ast_data_handler hints_data_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = hints_data_provider_get -}; - -static const struct ast_data_entry pbx_data_providers[] = { - AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider), -}; - static int action_extensionstatelist(struct mansession *s, const struct message *m) { const char *action_id = astman_get_header(m, "ActionID"); @@ -8431,7 +8381,6 @@ static void unload_pbx(void) ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli)); ast_custom_function_unregister(&exception_function); ast_custom_function_unregister(&testtime_function); - ast_data_unregister(NULL); } int load_pbx(void) @@ -8445,7 +8394,6 @@ int load_pbx(void) ast_verb(2, "Registering builtin functions:\n"); ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli)); - ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers)); __ast_custom_function_register(&exception_function, NULL); __ast_custom_function_register(&testtime_function, NULL); diff --git a/res/res_odbc.c b/res/res_odbc.c index 0b81bc6396f..24f63a92ecd 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -61,7 +61,6 @@ #include "asterisk/app.h" #include "asterisk/strings.h" #include "asterisk/threadstorage.h" -#include "asterisk/data.h" struct odbc_class { @@ -119,15 +118,6 @@ struct odbc_txn_frame { char name[0]; /*!< Name of this transaction ID */ }; -#define DATA_EXPORT_ODBC_CLASS(MEMBER) \ - MEMBER(odbc_class, name, AST_DATA_STRING) \ - MEMBER(odbc_class, dsn, AST_DATA_STRING) \ - MEMBER(odbc_class, username, AST_DATA_STRING) \ - MEMBER(odbc_class, password, AST_DATA_PASSWORD) \ - MEMBER(odbc_class, forcecommit, AST_DATA_BOOLEAN) - -AST_DATA_STRUCTURE(odbc_class, DATA_EXPORT_ODBC_CLASS); - const char *ast_odbc_isolation2text(int iso) { if (iso == SQL_TXN_READ_COMMITTED) { @@ -971,65 +961,6 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj) return ODBC_SUCCESS; } -/*! - * \internal - * \brief Implements the channels provider. - */ -static int data_odbc_provider_handler(const struct ast_data_search *search, - struct ast_data *root) -{ - struct ao2_iterator aoi; - struct odbc_class *class; - struct ast_data *data_odbc_class, *data_odbc_connections; - struct ast_data *enum_node; - - aoi = ao2_iterator_init(class_container, 0); - while ((class = ao2_iterator_next(&aoi))) { - data_odbc_class = ast_data_add_node(root, "class"); - if (!data_odbc_class) { - ao2_ref(class, -1); - continue; - } - - ast_data_add_structure(odbc_class, data_odbc_class, class); - - data_odbc_connections = ast_data_add_node(data_odbc_class, "connections"); - if (!data_odbc_connections) { - ao2_ref(class, -1); - continue; - } - - /* isolation */ - enum_node = ast_data_add_node(data_odbc_class, "isolation"); - if (!enum_node) { - ao2_ref(class, -1); - continue; - } - ast_data_add_int(enum_node, "value", class->isolation); - ast_data_add_str(enum_node, "text", ast_odbc_isolation2text(class->isolation)); - ao2_ref(class, -1); - - if (!ast_data_search_match(search, data_odbc_class)) { - ast_data_remove_node(root, data_odbc_class); - } - } - ao2_iterator_destroy(&aoi); - return 0; -} - -/*! - * \internal - * \brief /asterisk/res/odbc/listprovider. - */ -static const struct ast_data_handler odbc_provider = { - .version = AST_DATA_HANDLER_VERSION, - .get = data_odbc_provider_handler -}; - -static const struct ast_data_entry odbc_providers[] = { - AST_DATA_ENTRY("/asterisk/res/odbc", &odbc_provider), -}; - static int reload(void) { struct odbc_cache_tables *table; @@ -1087,7 +1018,6 @@ static int load_module(void) if (load_odbc_config() == -1) return AST_MODULE_LOAD_DECLINE; ast_cli_register_multiple(cli_odbc, ARRAY_LEN(cli_odbc)); - ast_data_register_multiple(odbc_providers, ARRAY_LEN(odbc_providers)); ast_log(LOG_NOTICE, "res_odbc loaded.\n"); return 0; } From 1028f64be478d7197dff3f7be6615c802d773a60 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 23 Jun 2017 11:17:51 -0500 Subject: [PATCH 1357/1578] bridge_native_rtp.c: Fix direct media video RTP instance ACL check. The video stream was using the audio stream RTP instance addresses to check if the video RTP gets directed to an allowed direct media Access Control List (ACL) address. There is no guarantee that the video RTP instance uses the same addresses as the audio RTP instance. This looks like it has been a bug since v11 when direct media ACL was first added to chan_sip and then faithfully reproduced through a couple code refactorings into the new bridging architecture. Change-Id: I8ddd56320e0eea769f3ceed3fa5b6bdfb51d681a --- bridges/bridge_native_rtp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index a459c9ce778..02b27e1234d 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -182,10 +182,10 @@ static int rtp_glue_data_get(struct ast_channel *c0, struct rtp_glue_data *glue0 } } if (glue0->video.result == glue1->video.result && glue1->video.result == AST_RTP_GLUE_RESULT_REMOTE) { - if (glue0->cb->allow_vrtp_remote && !glue0->cb->allow_vrtp_remote(c0, glue1->audio.instance)) { - /* if the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */ + if (glue0->cb->allow_vrtp_remote && !glue0->cb->allow_vrtp_remote(c0, glue1->video.instance)) { + /* If the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */ glue0->video.result = glue1->video.result = AST_RTP_GLUE_RESULT_LOCAL; - } else if (glue1->cb->allow_vrtp_remote && !glue1->cb->allow_vrtp_remote(c1, glue0->audio.instance)) { + } else if (glue1->cb->allow_vrtp_remote && !glue1->cb->allow_vrtp_remote(c1, glue0->video.instance)) { glue0->video.result = glue1->video.result = AST_RTP_GLUE_RESULT_LOCAL; } } From 7a4f577eb76d0f17894979f4c83924183e5d056c Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 6 Jul 2017 04:55:17 -0600 Subject: [PATCH 1358/1578] Fix alembic branches Change-Id: I04f607f084bda9b1b7f626e8e9735c37dc751187 --- .../164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py b/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py index dbc8ce9c4d0..20cab2f389f 100644 --- a/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py +++ b/contrib/ast-db-manage/config/versions/164abbd708c_add_auto_info_to_endpoint_dtmf_mode.py @@ -1,17 +1,18 @@ """Add auto_info to endpoint dtmf_mode Revision ID: 164abbd708c -Revises: 86bb1efa278d +Revises: 39959b9c2566 Create Date: 2017-06-19 13:55:15.354706 """ # revision identifiers, used by Alembic. revision = '164abbd708c' -down_revision = '86bb1efa278d' +down_revision = '39959b9c2566' from alembic import op import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM OLD_ENUM = ['rfc4733', 'inband', 'info', 'auto'] NEW_ENUM = ['rfc4733', 'inband', 'info', 'auto', 'auto_info'] From 9cd8a1df792c26cc4e82263a950f877d4c255100 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 5 Jul 2017 13:39:45 -0500 Subject: [PATCH 1359/1578] res_rtp_asterisk.c: Fix TURN deadlock by using ICE session group lock. When a message is received on the TURN socket, the code processing the message needs to call into the ICE/STUN session for further processing. This code path locks the TURN group lock then the ICE/STUN group lock. In another thread an ICE/STUN timer can fire off to send a keep alive message over the TURN socket. In this code path, the ICE/STUN group lock is obtained then the TURN group lock is obtained to send the packet. A classic deadlock case if the group locks are not the same. * Made TURN get created using the ICE/STUN session's group lock. NOTE: I was originally concerned that the ICE/STUN session can get recreated by ice_reset_session() for an event like RTCP multiplexing causing a change during SDP negotiation. In this case the TURN group lock would become different. However, TURN is also recreated as part of the ICE/STUN recreation in ice_create() when all known ICE candidates are added to the new ICE session. While the ICE/STUN and TURN sessions are being recreated there is a period where the group locks could be different. ASTERISK-27023 #close Patches: res_rtp_asterisk-turn-deadlock-fix.patch (license #6502) patch uploaded by Michael Walton (modified) Change-Id: Ic870edb99ce4988a8c8eb6e678ca7f19da1432b9 --- res/res_rtp_asterisk.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 01dfe76f29d..e60d4af7579 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1293,6 +1293,8 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast pj_turn_session_info info; struct ast_sockaddr local, loop; pj_status_t status; + pj_turn_sock_cfg turn_sock_cfg; + struct ice_wrap *ice; ast_rtp_instance_get_local_address(instance, &local); if (ast_sockaddr_is_ipv4(&local)) { @@ -1355,11 +1357,20 @@ static void ast_rtp_ice_turn_request(struct ast_rtp_instance *instance, enum ast pj_stun_config_init(&stun_config, &cachingpool.factory, 0, rtp->ioqueue->ioqueue, rtp->ioqueue->timerheap); + /* Use ICE session group lock for TURN session to avoid deadlock */ + pj_turn_sock_cfg_default(&turn_sock_cfg); + ice = rtp->ice; + if (ice) { + turn_sock_cfg.grp_lock = ice->real_ice->grp_lock; + ao2_ref(ice, +1); + } + /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ ao2_unlock(instance); status = pj_turn_sock_create(&stun_config, ast_sockaddr_is_ipv4(&addr) ? pj_AF_INET() : pj_AF_INET6(), conn_type, - turn_cb, NULL, instance, turn_sock); + turn_cb, &turn_sock_cfg, instance, turn_sock); + ao2_cleanup(ice); if (status != PJ_SUCCESS) { ast_log(LOG_WARNING, "Could not create a TURN client socket\n"); ao2_lock(instance); From 03ae8b010552fd21317175a861fce8dd92294a23 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 27 Jun 2017 19:27:43 -0500 Subject: [PATCH 1360/1578] json.c: Add backtrace log to find 'Invalid UTF-8 string' errors Change-Id: I9020ff9f2b3749904317c0c173f47a1bbed6f929 --- main/json.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main/json.c b/main/json.c index a28dbb2e22f..9004978b467 100644 --- a/main/json.c +++ b/main/json.c @@ -823,6 +823,7 @@ struct ast_json *ast_json_vpack(char const *format, va_list ap) ast_log(LOG_ERROR, "Error building JSON from '%s': %s.\n", format, error.text); + ast_log_backtrace(); } } return r; From 8f72128e661c34b626a71d25fd0d2e9d694e51ba Mon Sep 17 00:00:00 2001 From: Benjamin Keith Ford Date: Fri, 7 Jul 2017 11:19:13 -0500 Subject: [PATCH 1361/1578] res_pjsip: Fix crash with from_user containing invalid characters. If the from_user field contains certain characters (like @, {, ^, etc.), PJSIP will return a null value for the URI when attempting to parse it. This causes a crash when trying to dial out through a trunk that contains these invalid characters in its from_user field. This change checks the configuration and ensures that an endpoint will not be created if the from_user contains an invalid character. It also adds a null check to the PJSIP URI parsing as a backup. ASTERISK-27036 #close Reported by: Maxim Vasilev Change-Id: I0396fdb5080604e0bdf1277464d5c8a85db913d0 --- res/res_pjsip.c | 8 +++++++ res/res_pjsip/pjsip_configuration.c | 33 ++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 8923540a957..6e389d5f37d 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3091,6 +3091,14 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, /* Update the dialog with the new local URI, we do it afterwards so we can use the dialog pool for construction */ pj_strdup_with_null(dlg->pool, &dlg->local.info_str, &local_uri); dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.slen, 0); + if (!dlg->local.info->uri) { + ast_log(LOG_ERROR, + "Could not parse URI '%s' for endpoint '%s'\n", + dlg->local.info_str.ptr, ast_sorcery_object_get_id(endpoint)); + dlg->sess_count--; + pjsip_dlg_terminate(dlg); + return NULL; + } dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, local_uri.ptr, local_uri.slen, NULL); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 372b01bc8dd..ef3e05b067a 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1148,6 +1148,37 @@ static int tos_video_to_str(const void *obj, const intptr_t *args, char **buf) return 0; } +static int from_user_handler(const struct aco_option *opt, + struct ast_variable *var, void *obj) +{ + struct ast_sip_endpoint *endpoint = obj; + /* Valid non-alphanumeric characters for URI */ + char *valid_uri_marks = "-_.!~*`()"; + const char *val; + + for (val = var->value; *val; val++) { + if (!strchr(valid_uri_marks, *val) && !isdigit(*val) && !isalpha(*val)) { + ast_log(LOG_ERROR, "Error configuring endpoint '%s' - '%s' field " + "contains invalid character '%c'\n", + ast_sorcery_object_get_id(endpoint), var->name, *val); + return -1; + } + } + + ast_string_field_set(endpoint, fromuser, var->value); + + return 0; +} + +static int from_user_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + *buf = ast_strdup(endpoint->fromuser); + + return 0; +} + static int set_var_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -1918,7 +1949,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry)); - ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromuser)); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "from_user", "", from_user_handler, from_user_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine)); From 303f935a50835ce40c3589603d8c66fff292c64a Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 5 Jul 2017 14:31:43 -0600 Subject: [PATCH 1362/1578] http.c: Reduce log spam Messages like "fwrite() failed: Connection reset by peer" are no help whatsoever, especially since they can be caused simply by a client disconnecting. * Make those WARNINGs DEBUGs. * Check the return from ast_iostream_printf of headers. Change-Id: I17bd5f3621514152a7b2b263c801324c5e96568b --- main/http.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/main/http.c b/main/http.c index ea85a282364..7191eb52409 100644 --- a/main/http.c +++ b/main/http.c @@ -508,7 +508,7 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, send_content = method != AST_HTTP_HEAD || status_code >= 400; /* send http header */ - ast_iostream_printf(ser->stream, + if (ast_iostream_printf(ser->stream, "HTTP/1.1 %d %s\r\n" "%s" "Date: %s\r\n" @@ -526,13 +526,16 @@ void ast_http_send(struct ast_tcptls_session_instance *ser, http_header ? ast_str_buffer(http_header) : "", content_length, send_content && out && ast_str_strlen(out) ? ast_str_buffer(out) : "" - ); + ) <= 0) { + ast_debug(1, "ast_iostream_printf() failed: %s\n", strerror(errno)); + close_connection = 1; + } /* send content */ - if (send_content && fd) { + if (!close_connection && send_content && fd) { while ((len = read(fd, buf, sizeof(buf))) > 0) { if (ast_iostream_write(ser->stream, buf, len) != len) { - ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); + ast_debug(1, "ast_iostream_write() failed: %s\n", strerror(errno)); close_connection = 1; break; } From d58ef31acd94217ad51a8b91bb1a3e02fb2579af Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Mon, 3 Jul 2017 15:30:37 +0300 Subject: [PATCH 1363/1578] Avoid setting maxfiles for a remote asterisk Setting maxfiles (maximum number of open files) has no practical effect on a remote asterisk (rasterisk, rasterisk -x). It has an ill effect of printing an extra message, which may be annoying in case of -x. ASTERISK-27105 #close Change-Id: Iaf9eb344e4b4b517df91b736b27ec55f6a6921a2 --- main/asterisk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main/asterisk.c b/main/asterisk.c index 16313ea6853..a6e2149a77a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -3681,7 +3681,9 @@ static void ast_readconfig(void) /* Set the maximum amount of open files */ } else if (!strcasecmp(v->name, "maxfiles")) { ast_option_maxfiles = atoi(v->value); - set_ulimit(ast_option_maxfiles); + if (!ast_opt_remote) { + set_ulimit(ast_option_maxfiles); + } /* What user to run as */ } else if (!strcasecmp(v->name, "runuser")) { ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user)); From 5d86da61a66989507e91bed4930a39faba97638a Mon Sep 17 00:00:00 2001 From: Benjamin Keith Ford Date: Wed, 5 Jul 2017 12:44:18 -0500 Subject: [PATCH 1364/1578] manager: Remove AMI "Queues" action. When performing the "Queues" action via AMI, it outputs the same text that the Asterisk CLI outputs when running a "queue show" command, which does not conform with the AMI spec. "QueueStatus" already does what the "Queues" action should do, so instead of correcting the output, the "Queues" action will be removed and "QueueStatus" should be used instead. ASTERISK-27073 #close Reported by: Brian Change-Id: Id11743859758255b69cc3a557750d7a56c6d16f8 --- apps/app_queue.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index f158a4caa81..4fbd5f3c0fd 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -793,16 +793,6 @@ QUEUE_MEMBER_PENALTY - - - Queues. - - - - - Show queues information. - - Show queue status. @@ -9728,19 +9718,6 @@ static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a return __queues_show(NULL, a->fd, a->argc, a->argv); } -/*!\brief callback to display queues status in manager - \addtogroup Group_AMI - */ -static int manager_queues_show(struct mansession *s, const struct message *m) -{ - static const char * const a[] = { "queue", "show" }; - - __queues_show(s, -1, 2, a); - astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ - - return RESULT_SUCCESS; -} - static int manager_queue_rule_show(struct mansession *s, const struct message *m) { const char *rule = astman_get_header(m, "Rule"); @@ -11191,7 +11168,6 @@ static int unload_module(void) ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue)); ast_manager_unregister("QueueStatus"); - ast_manager_unregister("Queues"); ast_manager_unregister("QueueRule"); ast_manager_unregister("QueueSummary"); ast_manager_unregister("QueueAdd"); @@ -11309,7 +11285,6 @@ static int load_module(void) err |= ast_register_application_xml(app_upqm, upqm_exec); err |= ast_register_application_xml(app_ql, ql_exec); err |= ast_register_application_xml(app_qupd, qupd_exec); - err |= ast_manager_register_xml("Queues", 0, manager_queues_show); err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); err |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member); From b7a875778a3817e2f8a1e9f4a950bcc2f21a6146 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 11 Jul 2017 06:26:27 -0600 Subject: [PATCH 1365/1578] res_musiconhold: Add kill_escalation_delay, kill_method to class By default, when res_musiconhold reloads or unloads, it sends a HUP signal to custom applications (and all descendants), waits 100ms, then sends a TERM signal, waits 100ms, then finally sends a KILL signal. An application which is interacting with an external device and/or spawns children of its own may not be able to exit cleanly in the default times, expecially if sent a KILL signal, or if it's children are getting signals directly from res_musiconhoild. * To allow extra time, the 'kill_escalation_delay' class option can be used to set the number of milliseconds res_musiconhold waits before escalating kill signals, with the default being the current 100ms. * To control to whom the signals are sent, the "kill_method" class option can be set to "process_group" (the default, existing behavior), which sends signals to the application and its descendants directly, or "process" which sends signals only to the application itself. Change-Id: Iff70a1a9405685a9021a68416830c0db5158603b --- CHANGES | 20 +++ configs/samples/musiconhold.conf.sample | 23 ++++ res/res_musiconhold.c | 156 ++++++++++++++++-------- 3 files changed, 150 insertions(+), 49 deletions(-) diff --git a/CHANGES b/CHANGES index f2760c338e7..5daa81618fb 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,26 @@ app_queue * PAUSEALL/UNPAUSEALL now sets the pause reason in the queue_log if it has been defined. +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14.6.0 to Asterisk 14.7.0 ------------ +------------------------------------------------------------------------------ + +res_musiconhold +------------------ + * By default, when res_musiconhold reloads or unloads, it sends a HUP signal + to custom applications (and all descendants), waits 100ms, then sends a + TERM signal, waits 100ms, then finally sends a KILL signal. An application + which is interacting with an external device and/or spawns children of its + own may not be able to exit cleanly in the default times, expecially if sent + a KILL signal, or if it's children are getting signals directly from + res_musiconhoild. To allow extra time, the 'kill_escalation_delay' + class option can be used to set the number of milliseconds res_musiconhold + waits before escalating kill signals, with the default being the current + 100ms. To control to whom the signals are sent, the "kill_method" + class option can be set to "process_group" (the default, existing behavior), + which sends signals to the application and its descendants directly, or + "process" which sends signals only to the application itself. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------ ------------------------------------------------------------------------------ diff --git a/configs/samples/musiconhold.conf.sample b/configs/samples/musiconhold.conf.sample index b2980fc1de4..741bde60379 100644 --- a/configs/samples/musiconhold.conf.sample +++ b/configs/samples/musiconhold.conf.sample @@ -97,3 +97,26 @@ directory=moh ;mode=custom ;directory=/var/lib/asterisk/mohmp3 ;application=/site/sw/bin/madplay -Q -o raw:- --mono -R 8000 -a -12 + +; By default, when res_musiconhold reloads or unloads, it sends a HUP signal +; to custom applications (and all descendants), waits 100ms, then sends a +; TERM signal, waits 100ms, then finally sends a KILL signal. An application +; which is interacting with an external device and/or spawns children of its +; own may not be able to exit cleanly in the default times, expecially if sent +; a KILL signal, or if it's children are getting signals directly from +; res_musiconhoild. To allow extra time, the 'kill_escalation_delay' +; class option can be used to set the number of milliseconds res_musiconhold +; waits before escalating kill signals, with the default being the current +; 100ms. To control to whom the signals are sent, the "kill_method" +; class option can be set to "process_group" (the default, existing behavior), +; which sends signals to the application and its descendants directly, or +; "process" which sends signals only to the application itself. + +;[sox_from_device] +;mode=custom +;directory=/var/lib/asterisk/mohmp3 +;application=/usr/bin/sox -q -t alsa -c 2 -r 48000 hw:1 -c 1 -r 8000 -t raw -s - +; Wait 500ms before escalating kill signals +;kill_escalation_delay=500 +; Send signals to just the child process instead of all descendants +;kill_method=process diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index be50e9cee2b..e4bb7a2d9fa 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -159,6 +159,11 @@ struct moh_files_state { static struct ast_flags global_flags[1] = {{0}}; /*!< global MOH_ flags */ +enum kill_methods { + KILL_METHOD_PROCESS_GROUP = 0, + KILL_METHOD_PROCESS +}; + struct mohclass { char name[MAX_MUSICCLASS]; char dir[256]; @@ -179,6 +184,10 @@ struct mohclass { int pid; time_t start; pthread_t thread; + /*! Millisecond delay between kill attempts */ + size_t kill_delay; + /*! Kill method */ + enum kill_methods kill_method; /*! Source of audio */ int srcfd; /*! Generic timer */ @@ -680,6 +689,51 @@ static int spawn_mp3(struct mohclass *class) return fds[0]; } +static int killer(pid_t pid, int signum, enum kill_methods kill_method) +{ + switch (kill_method) { + case KILL_METHOD_PROCESS_GROUP: + return killpg(pid, signum); + case KILL_METHOD_PROCESS: + return kill(pid, signum); + } + + return -1; +} + +static void killpid(int pid, size_t delay, enum kill_methods kill_method) +{ + if (killer(pid, SIGHUP, kill_method) < 0) { + if (errno == ESRCH) { + return; + } + ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process '%d'?!!: %s\n", pid, strerror(errno)); + } else { + ast_debug(1, "Sent HUP to pid %d%s\n", pid, + kill_method == KILL_METHOD_PROCESS_GROUP ? " and all children" : " only"); + } + usleep(delay); + if (killer(pid, SIGTERM, kill_method) < 0) { + if (errno == ESRCH) { + return; + } + ast_log(LOG_WARNING, "Unable to terminate MOH process '%d'?!!: %s\n", pid, strerror(errno)); + } else { + ast_debug(1, "Sent TERM to pid %d%s\n", pid, + kill_method == KILL_METHOD_PROCESS_GROUP ? " and all children" : " only"); + } + usleep(delay); + if (killer(pid, SIGKILL, kill_method) < 0) { + if (errno == ESRCH) { + return; + } + ast_log(LOG_WARNING, "Unable to kill MOH process '%d'?!!: %s\n", pid, strerror(errno)); + } else { + ast_debug(1, "Sent KILL to pid %d%s\n", pid, + kill_method == KILL_METHOD_PROCESS_GROUP ? " and all children" : " only"); + } +} + static void *monmp3thread(void *data) { #define MOH_MS_INTERVAL 100 @@ -755,28 +809,7 @@ static void *monmp3thread(void *data) class->srcfd = -1; pthread_testcancel(); if (class->pid > 1) { - do { - if (killpg(class->pid, SIGHUP) < 0) { - if (errno == ESRCH) { - break; - } - ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); - } - usleep(100000); - if (killpg(class->pid, SIGTERM) < 0) { - if (errno == ESRCH) { - break; - } - ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); - } - usleep(100000); - if (killpg(class->pid, SIGKILL) < 0) { - if (errno == ESRCH) { - break; - } - ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); - } - } while (0); + killpid(class->pid, class->kill_delay, class->kill_method); class->pid = 0; } } else { @@ -1357,6 +1390,7 @@ static struct mohclass *_moh_class_malloc(const char *file, int line, const char if (class) { class->format = ao2_bump(ast_format_slin); class->srcfd = -1; + class->kill_delay = 100000; } return class; @@ -1610,44 +1644,22 @@ static void moh_class_destructor(void *obj) if (class->pid > 1) { char buff[8192]; - int bytes, tbytes = 0, stime = 0, pid = 0; + int bytes, tbytes = 0, stime = 0; ast_debug(1, "killing %d!\n", class->pid); stime = time(NULL) + 2; - pid = class->pid; - class->pid = 0; - - /* Back when this was just mpg123, SIGKILL was fine. Now we need - * to give the process a reason and time enough to kill off its - * children. */ - do { - if (killpg(pid, SIGHUP) < 0) { - ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); - } - usleep(100000); - if (killpg(pid, SIGTERM) < 0) { - if (errno == ESRCH) { - break; - } - ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); - } - usleep(100000); - if (killpg(pid, SIGKILL) < 0) { - if (errno == ESRCH) { - break; - } - ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); - } - } while (0); + killpid(class->pid, class->kill_delay, class->kill_method); while ((ast_wait_for_input(class->srcfd, 100) > 0) && (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { tbytes = tbytes + bytes; } - ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); + ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", + class->pid, tbytes); + class->pid = 0; close(class->srcfd); class->srcfd = -1; } @@ -1752,6 +1764,49 @@ static int load_moh_classes(int reload) /* For compatibility with the past, we overwrite any name=name * with the context [name]. */ ast_copy_string(class->name, cat, sizeof(class->name)); + for (var = ast_variable_browse(cfg, cat); var; var = var->next) { + if (!strcasecmp(var->name, "mode")) { + ast_copy_string(class->mode, var->value, sizeof(class->mode)); + } else if (!strcasecmp(var->name, "directory")) { + ast_copy_string(class->dir, var->value, sizeof(class->dir)); + } else if (!strcasecmp(var->name, "application")) { + ast_copy_string(class->args, var->value, sizeof(class->args)); + } else if (!strcasecmp(var->name, "announcement")) { + ast_copy_string(class->announcement, var->value, sizeof(class->announcement)); + ast_set_flag(class, MOH_ANNOUNCEMENT); + } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) { + class->digit = *var->value; + } else if (!strcasecmp(var->name, "random")) { + ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); + } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) { + ast_set_flag(class, MOH_RANDOMIZE); + } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) { + ast_set_flag(class, MOH_SORTALPHA); + } else if (!strcasecmp(var->name, "format")) { + ao2_cleanup(class->format); + class->format = ast_format_cache_get(var->value); + if (!class->format) { + ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); + class->format = ao2_bump(ast_format_slin); + } + } else if (!strcasecmp(var->name, "kill_escalation_delay")) { + if (sscanf(var->value, "%zu", &class->kill_delay) == 1) { + class->kill_delay *= 1000; + } else { + ast_log(LOG_WARNING, "kill_escalation_delay '%s' is invalid. Setting to 100ms\n", var->value); + class->kill_delay = 100000; + } + } else if (!strcasecmp(var->name, "kill_method")) { + if (!strcasecmp(var->value, "process")) { + class->kill_method = KILL_METHOD_PROCESS; + } else if (!strcasecmp(var->value, "process_group")){ + class->kill_method = KILL_METHOD_PROCESS_GROUP; + } else { + ast_log(LOG_WARNING, "kill_method '%s' is invalid. Setting to 'process_group'\n", var->value); + class->kill_method = KILL_METHOD_PROCESS_GROUP; + } + } + } if (ast_strlen_zero(class->dir)) { if (!strcasecmp(class->mode, "custom")) { @@ -1884,6 +1939,9 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "")); if (ast_test_flag(class, MOH_CUSTOM)) { ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "")); + ast_cli(a->fd, "\tKill Escalation Delay: %zu ms\n", class->kill_delay / 1000); + ast_cli(a->fd, "\tKill Method: %s\n", + class->kill_method == KILL_METHOD_PROCESS ? "process" : "process_group"); } if (strcasecmp(class->mode, "files")) { ast_cli(a->fd, "\tFormat: %s\n", ast_format_get_name(class->format)); From 7f09fd2c2f1501aeccc7737be4dd0e52fd656913 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 11 Jul 2017 19:33:44 +0000 Subject: [PATCH 1366/1578] bridge/core_unreal: Fix SFU bugs with forwarding frames. This change fixes a few things uncovered during SFU testing. 1. Unreal channels incorrectly forwarded video frames when no video stream was present on them. This caused a crash when they were read as the core requires a stream to exist for the underlying media type. The Unreal channel will now ensure a stream exists for the media type before forwarding the frame and if no stream exists then the frame is dropped. 2. Mapping of frames during bridging from the stream number of the underlying channel to the stream number of the bridge was done in the wrong location. This resulted in the frame getting dropped. This mapping now occurs on reading of the frame from the channel. 3. Bridging was using the wrong ast_read function resulting in it living in a non-multistream world. 4. In bridge_softmix when adding new streams to existing channels the wrong stream topology was copied resulting in no streams being added. Change-Id: Ib7445722c3219951d6740802a0feddf2908c18c8 --- bridges/bridge_softmix.c | 2 +- include/asterisk/channel.h | 20 ++++++++++++++++++++ main/bridge_channel.c | 30 +++++++++++++----------------- main/channel.c | 5 +++++ main/core_unreal.c | 13 +++++++++++++ 5 files changed, 52 insertions(+), 18 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index ae877eb6e3c..21f5190e57e 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -600,7 +600,7 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast if (participant == joiner) { continue; } - participant_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(joiner->chan)); + participant_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(participant->chan)); if (!participant_topology) { goto cleanup; } diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 197cc990dbd..55126b472f5 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -2029,6 +2029,26 @@ struct ast_frame *ast_read_stream(struct ast_channel *chan); */ struct ast_frame *ast_read_noaudio(struct ast_channel *chan); +/*! + * \brief Reads a frame, but does not filter to just the default streams, + * returning AST_FRAME_NULL frame if audio. + * + * \param chan channel to read a frame from + * + * \return Returns a frame, or NULL on error. If it returns NULL, you + * best just stop reading frames and assume the channel has been + * disconnected. + * + * \note This function will not perform any filtering and will return + * media frames from all streams on the channel. To determine which + * stream a frame originated from the stream_num on it can be + * examined. + * + * \note Audio is replaced with AST_FRAME_NULL to avoid + * transcode when the resulting audio is not necessary. + */ +struct ast_frame *ast_read_stream_noaudio(struct ast_channel *chan); + /*! * \brief Write a frame to a channel * This function writes the given frame to the indicated channel. diff --git a/main/bridge_channel.c b/main/bridge_channel.c index e8ab8a89805..2e943000cc1 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -998,21 +998,6 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st return 0; } - if (ast_channel_is_multistream(bridge_channel->chan) && - (fr->frametype == AST_FRAME_IMAGE || fr->frametype == AST_FRAME_TEXT || - fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_VOICE)) { - /* Media frames need to be mapped to an appropriate write stream */ - dup->stream_num = AST_VECTOR_GET( - &bridge_channel->stream_map.to_bridge, fr->stream_num); - if (dup->stream_num == -1) { - ast_bridge_channel_unlock(bridge_channel); - bridge_frame_free(dup); - return 0; - } - } else { - dup->stream_num = -1; - } - AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list); if (ast_alertpipe_write(bridge_channel->alert_pipe)) { ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n", @@ -2455,15 +2440,26 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) } if (bridge_channel->features->mute) { - frame = ast_read_noaudio(bridge_channel->chan); + frame = ast_read_stream_noaudio(bridge_channel->chan); } else { - frame = ast_read(bridge_channel->chan); + frame = ast_read_stream(bridge_channel->chan); } if (!frame) { ast_bridge_channel_kick(bridge_channel, 0); return; } + + if (ast_channel_is_multistream(bridge_channel->chan) && + (frame->frametype == AST_FRAME_IMAGE || frame->frametype == AST_FRAME_TEXT || + frame->frametype == AST_FRAME_VIDEO || frame->frametype == AST_FRAME_VOICE)) { + /* Media frames need to be mapped to an appropriate write stream */ + frame->stream_num = AST_VECTOR_GET( + &bridge_channel->stream_map.to_bridge, frame->stream_num); + } else { + frame->stream_num = -1; + } + switch (frame->frametype) { case AST_FRAME_CONTROL: switch (frame->subclass.integer) { diff --git a/main/channel.c b/main/channel.c index 811826f1cf0..23bb74f0823 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4180,6 +4180,11 @@ struct ast_frame *ast_read_noaudio(struct ast_channel *chan) return __ast_read(chan, 1, 1); } +struct ast_frame *ast_read_stream_noaudio(struct ast_channel *chan) +{ + return __ast_read(chan, 1, 0); +} + int ast_indicate(struct ast_channel *chan, int condition) { return ast_indicate_data(chan, condition, NULL, 0); diff --git a/main/core_unreal.c b/main/core_unreal.c index 5da7408770d..3db6a4dbdd8 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -323,6 +323,19 @@ int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f) return -1; } + /* If we are told to write a frame with a type that has no corresponding + * stream on the channel then drop it. + */ + if (f->frametype == AST_FRAME_VOICE) { + if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_AUDIO)) { + return 0; + } + } else if (f->frametype == AST_FRAME_VIDEO) { + if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_VIDEO)) { + return 0; + } + } + /* Just queue for delivery to the other side */ ao2_ref(p, 1); ao2_lock(p); From e83b9d141a416ab8c0b1fcfcd29d73abf2ca04c9 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 12 Jul 2017 16:07:42 -0400 Subject: [PATCH 1367/1578] basic-pbx: Remove res_pjsip_multihomed from sample config ASTERISK-27127 #close Reported by: HZMI8gkCvPpom0tM Change-Id: I2b0c54570d58156e37166ac536728af3b6c01789 --- configs/basic-pbx/modules.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/configs/basic-pbx/modules.conf b/configs/basic-pbx/modules.conf index 8de58bf2d9b..9711745edce 100644 --- a/configs/basic-pbx/modules.conf +++ b/configs/basic-pbx/modules.conf @@ -77,7 +77,6 @@ load = res_pjsip_exten_state.so load = res_pjsip_header_funcs.so load = res_pjsip_logger.so load = res_pjsip_messaging.so -load = res_pjsip_multihomed.so load = res_pjsip_mwi_body_generator.so load = res_pjsip_mwi.so load = res_pjsip_nat.so From b54eb167b4062ab73f4fd2dfd29dbc75a4ec9ed5 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 11 Jul 2017 11:48:26 +0200 Subject: [PATCH 1368/1578] app_playback.c: Use the timezonename parameter In say_date_generic the timezonename parameter is passed but never used. Fix it by passing it to the ast_localtime function. ASTERISK-27124 Change-Id: I63106b8db10426d417d7275f22554a616e92fae4 --- apps/app_playback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app_playback.c b/apps/app_playback.c index 35900e8f78f..7c895e36239 100644 --- a/apps/app_playback.c +++ b/apps/app_playback.c @@ -322,7 +322,7 @@ static int say_date_generic(struct ast_channel *chan, time_t t, if (format == NULL) format = ""; - ast_localtime(&when, &tm, NULL); + ast_localtime(&when, &tm, timezonename); snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d", prefix, format, From 6b138046e7db59e975fc06ee3aea54fe0c143f5d Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 12 Jul 2017 14:24:36 -0400 Subject: [PATCH 1369/1578] core: Add digit filtering to ast_waitfordigit_full This adds a parameter to ast_waitfordigit_full which can be used to only stop waiting when certain expected digits are received. Any unexpected DTMF digits are simply ignored. This also creates a new dialplan application WaitDigit. ASTERISK-27129 #close Change-Id: Id233935ea3d13e71c75a0861834c5936c3700ef9 --- include/asterisk/channel.h | 3 +- main/channel.c | 17 +++++---- main/pbx_builtins.c | 78 ++++++++++++++++++++++++++++++++++++++ res/res_agi.c | 4 +- 4 files changed, 92 insertions(+), 10 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 197cc990dbd..cb2e0e6a41d 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -2219,11 +2219,12 @@ int ast_waitfordigit(struct ast_channel *c, int ms); * Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading. * \param c channel to wait for a digit on * \param ms how many milliseconds to wait (<0 for indefinite). + * \param breakon string of DTMF digits to break upon or NULL for any. * \param audiofd audio file descriptor to write to if audio frames are received * \param ctrlfd control file descriptor to monitor for reading * \return Returns 1 if ctrlfd becomes available */ -int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd); +int ast_waitfordigit_full(struct ast_channel *c, int ms, const char *breakon, int audiofd, int ctrlfd); /*! * \brief Reads multiple digits diff --git a/main/channel.c b/main/channel.c index 811826f1cf0..27efb2ee342 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3160,7 +3160,7 @@ int ast_waitfor(struct ast_channel *c, int ms) int ast_waitfordigit(struct ast_channel *c, int ms) { - return ast_waitfordigit_full(c, ms, -1, -1); + return ast_waitfordigit_full(c, ms, NULL, -1, -1); } int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data) @@ -3222,7 +3222,7 @@ int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(co return res; } -int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, int cmdfd) +int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, const char *breakon, int audiofd, int cmdfd) { struct timeval start = ast_tvnow(); int ms; @@ -3273,9 +3273,12 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in break; case AST_FRAME_DTMF_END: res = f->subclass.integer; - ast_frfree(f); - ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); - return res; + if (!breakon || strchr(breakon, res)) { + ast_frfree(f); + ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY); + return res; + } + break; case AST_FRAME_CONTROL: switch (f->subclass.integer) { case AST_CONTROL_HANGUP: @@ -6351,11 +6354,11 @@ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, in silgen = ast_channel_start_silence_generator(c); usleep(1000); if (!d) - d = ast_waitfordigit_full(c, to, audiofd, ctrlfd); + d = ast_waitfordigit_full(c, to, NULL, audiofd, ctrlfd); } else { if (!silgen && ast_opt_transmit_silence) silgen = ast_channel_start_silence_generator(c); - d = ast_waitfordigit_full(c, to, audiofd, ctrlfd); + d = ast_waitfordigit_full(c, to, NULL, audiofd, ctrlfd); } if (d < 0) { ast_channel_stop_silence_generator(c, silgen); diff --git a/main/pbx_builtins.c b/main/pbx_builtins.c index bc27b0d58a6..9d43c10ffc2 100644 --- a/main/pbx_builtins.c +++ b/main/pbx_builtins.c @@ -580,6 +580,42 @@ This application waits for a specified number of seconds. + + + Waits for a digit to be entered. + + + + Can be passed with fractions of a second. For example, 1.5 will ask the + application to wait for 1.5 seconds. + + + Digits to accept, all others are ignored. + + + + This application waits for the user to press one of the accepted + digits for a specified number of + seconds. + + + This is the final status of the command + Parameters are invalid. + An accepted digit was received. + The timeout passed before any acceptable digits were received. + The channel has hungup or was redirected. + + + The digit that was received, only set if + WAITDIGITSTATUS is DTMF. + + + + + Wait + WaitExten + + Waits for an extension to be entered. @@ -954,6 +990,47 @@ static int pbx_builtin_wait(struct ast_channel *chan, const char *data) return 0; } +/*! + * \ingroup applications + */ +static int pbx_builtin_waitdigit(struct ast_channel *chan, const char *data) +{ + int res; + int ms; + char *parse; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(timeout); + AST_APP_ARG(digits); + ); + + parse = ast_strdupa(data); + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) || ms < 0) { + pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "ERROR"); + return 0; + } + + /* Wait for "n" seconds */ + res = ast_waitfordigit_full(chan, ms, S_OR(args.digits, AST_DIGIT_ANY), -1, -1); + if (res < 0) { + pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "CANCEL"); + return -1; + } + + if (res == 0) { + pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "TIMEOUT"); + } else { + char key[2]; + + snprintf(key, sizeof(key), "%c", res); + pbx_builtin_setvar_helper(chan, "WAITDIGITRESULT", key); + pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "DTMF"); + } + + return 0; +} + /*! * \ingroup applications */ @@ -1410,6 +1487,7 @@ struct pbx_builtin { { "SayPhonetic", pbx_builtin_sayphonetic }, { "SetAMAFlags", pbx_builtin_setamaflags }, { "Wait", pbx_builtin_wait }, + { "WaitDigit", pbx_builtin_waitdigit }, { "WaitExten", pbx_builtin_waitexten } }; diff --git a/res/res_agi.c b/res/res_agi.c index e8497f7caee..466063557b3 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -2393,7 +2393,7 @@ static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, con return RESULT_SHOWUSAGE; if (sscanf(argv[3], "%30d", &to) != 1) return RESULT_SHOWUSAGE; - res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl); + res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl); ast_agi_send(agi->fd, chan, "200 result=%d\n", res); return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; } @@ -2673,7 +2673,7 @@ static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const /* If the user didnt press a key, wait for digitTimeout*/ if (res == 0 ) { - res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl); + res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl); /* Make sure the new result is in the escape digits of the GET OPTION */ if ( !strchr(edigits,res) ) res=0; From d42a9cc9dc3c218254d5bb71159ca290431fa244 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Thu, 22 Jun 2017 14:47:54 +0200 Subject: [PATCH 1370/1578] res/res_pjsip_t38 ensure t38 requests get rejected quickly arm the t38 webhook always, so we can correctly reject a T38 negotiation request when t38 is disabled on a channel Change-Id: Ib1ffe35aee145d4e0fe61dd012580be11aae079d --- res/res_pjsip_t38.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index a032bb12fb4..5fc55971e77 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -497,16 +497,21 @@ static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_fram return f; } - if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS && - channel->session->endpoint->media.t38.enabled) { - struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(channel->session, f); + if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) { + if (channel->session->endpoint->media.t38.enabled) { + struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(channel->session, f); - if (!data) { - return f; - } + if (!data) { + return f; + } - if (ast_sip_push_task(channel->session->serializer, t38_interpret_parameters, data)) { - ao2_ref(data, -1); + if (ast_sip_push_task(channel->session->serializer, t38_interpret_parameters, data)) { + ao2_ref(data, -1); + } + } else { + struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REFUSED, }; + ast_debug(2, "T.38 support not enabled, rejecting T.38 control packet\n"); + ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); } } @@ -551,10 +556,7 @@ static void t38_attach_framehook(struct ast_sip_session *session) return; } - /* Only attach the framehook if t38 is enabled for the endpoint */ - if (!session->endpoint->media.t38.enabled) { - return; - } + /* Always attach the framehook so we can quickly reject */ ast_channel_lock(session->channel); From 8b535a406bc4f8c70ff9a557ac1e337135377cb3 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Tue, 11 Jul 2017 16:55:36 +0200 Subject: [PATCH 1371/1578] res/res_stasis_snoop: generate silence when audiohook returns null Currently when rtp is paused, no packets are written to the recorded audio file, causing the silence to be skipped and recording not properly time aligned. The read handler as been adapted to return a silence frame of the correct size. ASTERISK-27128 #close Change-Id: I2d7f60650457860b9c70907b14426756b058a844 --- res/res_stasis_snoop.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c index cd51638ea91..f797a9b9427 100644 --- a/res/res_stasis_snoop.c +++ b/res/res_stasis_snoop.c @@ -72,6 +72,8 @@ struct stasis_app_snoop { unsigned int whisper_active:1; /*! \brief Uniqueid of the channel this snoop is snooping on */ char uniqueid[AST_MAX_UNIQUEID]; + /*! \brief A frame of silence to use when the audiohook returns null */ + struct ast_frame silence; }; /*! \brief Destructor for snoop structure */ @@ -91,6 +93,11 @@ static void snoop_destroy(void *obj) ast_audiohook_destroy(&snoop->whisper); } + if (snoop->silence.data.ptr) { + ast_free(snoop->silence.data.ptr); + snoop->silence.data.ptr = NULL; + } + ast_free(snoop->app); ast_channel_cleanup(snoop->chan); @@ -197,7 +204,7 @@ static struct ast_frame *snoop_read(struct ast_channel *chan) frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format); ast_audiohook_unlock(&snoop->spy); - return frame ? frame : &ast_null_frame; + return frame ? frame : &snoop->silence; } /*! \brief Callback function for hanging up a Snoop channel */ @@ -383,6 +390,19 @@ struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan, snoop->spy_samples = ast_format_get_sample_rate(snoop->spy_format) / (1000 / SNOOP_INTERVAL); snoop->spy_active = 1; + + snoop->silence.frametype = AST_FRAME_VOICE, + snoop->silence.datalen = snoop->spy_samples * sizeof(uint16_t), + snoop->silence.samples = snoop->spy_samples, + snoop->silence.mallocd = 0, + snoop->silence.offset = 0, + snoop->silence.src = __PRETTY_FUNCTION__, + snoop->silence.subclass.format = snoop->spy_format, + snoop->silence.data.ptr = ast_calloc(snoop->spy_samples, sizeof(uint16_t)); + if (!snoop->silence.data.ptr) { + ast_hangup(snoop->chan); + return NULL; + } } /* If whispering is enabled set up the audiohook */ From 065c3005ad920f5fe2cedcf062e38b8e28eeb015 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 30 Jun 2017 18:55:57 +0000 Subject: [PATCH 1372/1578] res_rtp_asterisk / res_pjsip: Add support for BUNDLE. BUNDLE is a specification used in WebRTC to allow multiple streams to use the same underlying transport. This reduces the number of ICE and DTLS negotiations that has to occur to 1 normally. This change implements this by adding support for it to the RTP SDP module in PJSIP. BUNDLE can be turned on using the "bundle" option and on an offer we will offer to bundle streams together. On an answer we will accept any bundle groups provided. Once accepted each stream is bundled to another RTP instance for transport. For the res_rtp_asterisk changes the ability to bundle an RTP instance to another based on the SSRC received from the remote side has been added. For outgoing traffic if an RTP instance is bundled to another we will use the other RTP instance for any transport related things. For incoming traffic received from the transport instance we look up the correct instance based on the SSRC and use it for any non-transport related data. ASTERISK-27118 Change-Id: I96c0920b9f9aca7382256484765a239017973c11 --- channels/chan_pjsip.c | 2 - include/asterisk/res_pjsip.h | 2 + include/asterisk/res_pjsip_session.h | 19 + include/asterisk/rtp_engine.h | 52 ++ main/rtp_engine.c | 68 ++- res/res_pjsip.c | 8 + res/res_pjsip/pjsip_configuration.c | 5 + res/res_pjsip_sdp_rtp.c | 411 ++++++++++----- res/res_pjsip_session.c | 213 +++++++- res/res_pjsip_t38.c | 11 +- res/res_rtp_asterisk.c | 740 ++++++++++++++++++--------- 11 files changed, 1154 insertions(+), 377 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 0e4468cdcd9..3de980a520b 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -792,8 +792,6 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast) return f; } - f->stream_num = callback_state->session->stream_num; - if (f->frametype != AST_FRAME_VOICE || callback_state->session != session->active_media_state->default_session[callback_state->session->type]) { return f; diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 2cd27d37f33..d499d5514bf 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -688,6 +688,8 @@ struct ast_sip_endpoint_media_configuration { unsigned int max_audio_streams; /*! Maximum number of video streams to offer/accept */ unsigned int max_video_streams; + /*! Use BUNDLE */ + unsigned int bundle; }; /*! diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index e298e1f32da..eae29de0467 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -99,6 +99,12 @@ struct ast_sip_session_media { ast_sip_session_media_write_cb write_callback; /*! \brief The stream number to place into any resulting frames */ int stream_num; + /*! \brief Media identifier for this stream (may be shared across multiple streams) */ + char *mid; + /*! \brief The bundle group the stream belongs to */ + int bundle_group; + /*! \brief Whether this stream is currently bundled or not */ + unsigned int bundled; }; /*! @@ -833,6 +839,19 @@ int ast_sip_session_media_add_read_callback(struct ast_sip_session *session, str int ast_sip_session_media_set_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, ast_sip_session_media_write_cb callback); +/*! + * \brief Retrieve the underlying media session that is acting as transport for a media session + * \since 15.0.0 + * + * \param session The session + * \param session_media The media session to retrieve the transport for + * + * \note This operates on the pending media state + * + * \note This function is guaranteed to return non-NULL + */ +struct ast_sip_session_media *ast_sip_session_media_get_transport(struct ast_sip_session *session, struct ast_sip_session_media *session_media); + /*! \brief Determines whether the res_pjsip_session module is loaded */ #define CHECK_PJSIP_SESSION_MODULE_LOADED() \ do { \ diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 5f439163fe1..20ae959e96c 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -603,6 +603,12 @@ struct ast_rtp_engine { unsigned int (*ssrc_get)(struct ast_rtp_instance *instance); /*! Callback to retrieve RTCP SDES CNAME */ const char *(*cname_get)(struct ast_rtp_instance *instance); + /*! Callback to bundle an RTP instance to another */ + int (*bundle)(struct ast_rtp_instance *child, struct ast_rtp_instance *parent); + /*! Callback to set remote SSRC information */ + void (*set_remote_ssrc)(struct ast_rtp_instance *instance, unsigned int ssrc); + /*! Callback to set the stream identifier */ + void (*set_stream_num)(struct ast_rtp_instance *instance, int stream_num); /*! Callback to pointer for optional ICE support */ struct ast_rtp_engine_ice *ice; /*! Callback to pointer for optional DTLS SRTP support */ @@ -1506,6 +1512,20 @@ void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_fo */ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code); +/*! + * \brief Set a payload code for use with a specific Asterisk format + * + * \param codecs Codecs structure to manipulate + * \param code The payload code + * \param format Asterisk format + * + * \retval 0 Payload was set to the given format + * \retval -1 Payload was in use or could not be set + * + * \since 15.0.0 + */ +int ast_rtp_codecs_payload_set_rx(struct ast_rtp_codecs *codecs, int code, struct ast_format *format); + /*! * \brief Retrieve a tx mapped payload type based on whether it is an Asterisk format and the code * \since 14.0.0 @@ -2266,6 +2286,8 @@ int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level); * * \retval 0 Success * \retval non-zero Failure + * + * \note If no remote policy is provided any existing SRTP policies are left and the new local policy is added */ int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy* remote_policy, struct ast_srtp_policy *local_policy, int rtcp); @@ -2411,6 +2433,36 @@ unsigned int ast_rtp_instance_get_ssrc(struct ast_rtp_instance *rtp); */ const char *ast_rtp_instance_get_cname(struct ast_rtp_instance *rtp); +/*! + * \brief Request that an RTP instance be bundled with another + * \since 15.0.0 + * + * \param child The child RTP instance + * \param parent The parent RTP instance the child should be bundled with + * + * \retval 0 success + * \retval -1 failure + */ +int ast_rtp_instance_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent); + +/*! + * \brief Set the remote SSRC for an RTP instance + * \since 15.0.0 + * + * \param rtp The RTP instance + * \param ssrc The remote SSRC + */ +void ast_rtp_instance_set_remote_ssrc(struct ast_rtp_instance *rtp, unsigned int ssrc); + +/*! + * \brief Set the stream number for an RTP instance + * \since 15.0.0 + * + * \param rtp The RTP instance + * \param stream_num The stream identifier number + */ +void ast_rtp_instance_set_stream_num(struct ast_rtp_instance *instance, int stream_num); + /*! \addtogroup StasisTopicsAndMessages * @{ */ diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 9cfae09f437..abd4b1fcfca 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -1495,21 +1495,24 @@ static int rtp_codecs_find_non_primary_dynamic_rx(struct ast_rtp_codecs *codecs) * \param asterisk_format Non-zero if the given Asterisk format is present * \param format Asterisk format to look for * \param code The format to look for + * \param explicit Require the provided code to be explicitly used * * \note It is assumed that static_RTP_PT_lock is at least read locked before calling. * * \retval Numerical payload type * \retval -1 if could not assign. */ -static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code) +static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code, int explicit) { - int payload; + int payload = code; struct ast_rtp_payload_type *new_type; - payload = find_static_payload_type(asterisk_format, format, code); + if (!explicit) { + payload = find_static_payload_type(asterisk_format, format, code); - if (payload < 0 && (!asterisk_format || ast_option_rtpusedynamic)) { - return payload; + if (payload < 0 && (!asterisk_format || ast_option_rtpusedynamic)) { + return payload; + } } new_type = rtp_payload_type_alloc(format, payload, code, 1); @@ -1525,9 +1528,9 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int * The payload type is a static assignment * or our default dynamic position is available. */ - rtp_codecs_payload_replace_rx(codecs, payload, new_type); - } else if (-1 < (payload = find_unused_payload(codecs)) - || -1 < (payload = rtp_codecs_find_non_primary_dynamic_rx(codecs))) { + rtp_codecs_payload_replace_rx(codecs, payload, new_type); + } else if (!explicit && (-1 < (payload = find_unused_payload(codecs)) + || -1 < (payload = rtp_codecs_find_non_primary_dynamic_rx(codecs)))) { /* * We found the first available empty dynamic position * or we found a mapping that should no longer be @@ -1535,6 +1538,11 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int */ new_type->payload = payload; rtp_codecs_payload_replace_rx(codecs, payload, new_type); + } else if (explicit) { + /* + * They explicitly requested this payload number be used but it couldn't be + */ + payload = -1; } else { /* * There are no empty or non-primary dynamic positions @@ -1595,13 +1603,18 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form if (payload < 0) { payload = rtp_codecs_assign_payload_code_rx(codecs, asterisk_format, format, - code); + code, 0); } ast_rwlock_unlock(&static_RTP_PT_lock); return payload; } +int ast_rtp_codecs_payload_set_rx(struct ast_rtp_codecs *codecs, int code, struct ast_format *format) +{ + return rtp_codecs_assign_payload_code_rx(codecs, 1, format, code, 1); +} + int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code) { struct ast_rtp_payload_type *type; @@ -2424,7 +2437,7 @@ int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct a if (!*srtp) { res = res_srtp->create(srtp, instance, remote_policy); - } else { + } else if (remote_policy) { res = res_srtp->replace(srtp, instance, remote_policy); } if (!res) { @@ -3366,3 +3379,38 @@ const char *ast_rtp_instance_get_cname(struct ast_rtp_instance *rtp) return cname; } + +int ast_rtp_instance_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent) +{ + int res = -1; + + if (child->engine != parent->engine) { + return -1; + } + + ao2_lock(child); + if (child->engine->bundle) { + res = child->engine->bundle(child, parent); + } + ao2_unlock(child); + + return res; +} + +void ast_rtp_instance_set_remote_ssrc(struct ast_rtp_instance *rtp, unsigned int ssrc) +{ + ao2_lock(rtp); + if (rtp->engine->set_remote_ssrc) { + rtp->engine->set_remote_ssrc(rtp, ssrc); + } + ao2_unlock(rtp); +} + +void ast_rtp_instance_set_stream_num(struct ast_rtp_instance *rtp, int stream_num) +{ + ao2_lock(rtp); + if (rtp->engine->set_stream_num) { + rtp->engine->set_stream_num(rtp, stream_num); + } + ao2_unlock(rtp); +} \ No newline at end of file diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 0cf03437451..1b546eff92c 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -995,6 +995,14 @@ streams allowed for the endpoint. + + Enable RTP bundling + + With this option enabled, Asterisk will attempt to negotiate the use of bundle. + If negotiated this will result in multiple RTP streams being carried over the same + underlying transport. Note that enabling bundle will also enable the rtcp_mux option. + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 372b01bc8dd..d56ff5d23e1 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1332,6 +1332,10 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o return -1; } + if (endpoint->media.bundle) { + endpoint->media.rtcp_mux = 1; + } + return 0; } @@ -1954,6 +1958,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a4913086820..4ec81152880 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -317,6 +317,7 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + struct ast_sip_session_media *session_media_transport, const struct pjmedia_sdp_media *stream, int is_offer, struct ast_stream *asterisk_stream) { @@ -376,6 +377,24 @@ static int set_caps(struct ast_sip_session *session, ast_stream_set_formats(asterisk_stream, joint); + /* If this is a bundled stream then apply the payloads to RTP instance acting as transport to prevent conflicts */ + if (session_media_transport != session_media && session_media->bundled) { + int index; + + for (index = 0; index < ast_format_cap_count(joint); ++index) { + struct ast_format *format = ast_format_cap_get_format(joint, index); + int rtp_code; + + /* Ensure this payload is in the bundle group transport codecs, this purposely doesn't check the return value for + * things as the format is guaranteed to have a payload already. + */ + rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0); + ast_rtp_codecs_payload_set_rx(ast_rtp_instance_get_codecs(session_media_transport->rtp), rtp_code, format); + + ao2_ref(format, -1); + } + } + if (session->channel && ast_sip_session_is_pending_stream_default(session, asterisk_stream)) { ast_channel_lock(session->channel); ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); @@ -496,7 +515,8 @@ static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format * } /*! \brief Function which adds ICE attributes to a media stream */ -static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media) +static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media, + unsigned int include_candidates) { struct ast_rtp_engine_ice *ice; struct ao2_container *candidates; @@ -506,8 +526,7 @@ static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_se struct ao2_iterator it_candidates; struct ast_rtp_engine_ice_candidate *candidate; - if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp)) || - !(candidates = ice->get_local_candidates(session_media->rtp))) { + if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) { return; } @@ -521,6 +540,15 @@ static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_se media->attr[media->attr_count++] = attr; } + if (!include_candidates) { + return; + } + + candidates = ice->get_local_candidates(session_media->rtp); + if (!candidates) { + return; + } + it_candidates = ao2_iterator_init(candidates, 0); for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) { struct ast_str *attr_candidate = ast_str_create(128); @@ -940,6 +968,63 @@ static void set_ice_components(struct ast_sip_session *session, struct ast_sip_s } } +/*! \brief Function which adds ssrc attributes to a media stream */ +static void add_ssrc_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media) +{ + pj_str_t stmp; + pjmedia_sdp_attr *attr; + char tmp[128]; + + if (!session->endpoint->media.bundle || session_media->bundle_group == -1) { + return; + } + + snprintf(tmp, sizeof(tmp), "%u cname:%s", ast_rtp_instance_get_ssrc(session_media->rtp), ast_rtp_instance_get_cname(session_media->rtp)); + attr = pjmedia_sdp_attr_create(pool, "ssrc", pj_cstr(&stmp, tmp)); + media->attr[media->attr_count++] = attr; +} + +/*! \brief Function which processes ssrc attributes in a stream */ +static void process_ssrc_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media, + const struct pjmedia_sdp_media *remote_stream) +{ + int index; + + if (!session->endpoint->media.bundle) { + return; + } + + for (index = 0; index < remote_stream->attr_count; ++index) { + pjmedia_sdp_attr *attr = remote_stream->attr[index]; + char attr_value[pj_strlen(&attr->value) + 1]; + char *ssrc_attribute_name, *ssrc_attribute_value = NULL; + unsigned int ssrc; + + /* We only care about ssrc attributes */ + if (pj_strcmp2(&attr->name, "ssrc")) { + continue; + } + + ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value)); + + if ((ssrc_attribute_name = strchr(attr_value, ' '))) { + /* This has an actual attribute */ + *ssrc_attribute_name++ = '\0'; + ssrc_attribute_value = strchr(ssrc_attribute_name, ':'); + if (ssrc_attribute_value) { + /* Values are actually optional according to the spec */ + *ssrc_attribute_value++ = '\0'; + } + } + + if (sscanf(attr_value, "%30u", &ssrc) < 1) { + continue; + } + + ast_rtp_instance_set_remote_ssrc(session_media->rtp, ssrc); + } +} + /*! \brief Function which negotiates an incoming media stream */ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, @@ -948,6 +1033,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, char host[NI_MAXHOST]; RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); pjmedia_sdp_media *stream = sdp->media[index]; + struct ast_sip_session_media *session_media_transport; enum ast_media_type media_type = session_media->type; enum ast_sip_session_media_encryption encryption = AST_SIP_MEDIA_ENCRYPT_NONE; int res; @@ -981,38 +1067,51 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, return -1; } - session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(stream, "rtcp-mux", NULL) != NULL); - set_ice_components(session, session_media); + process_ssrc_attributes(session, session_media, stream); - enable_rtcp(session, session_media, stream); + session_media_transport = ast_sip_session_media_get_transport(session, session_media); - res = setup_media_encryption(session, session_media, sdp, stream); - if (res) { - if (!session->endpoint->media.rtp.encryption_optimistic || - !pj_strncmp2(&stream->desc.transport, "RTP/SAVP", 8)) { - /* If optimistic encryption is disabled and crypto should have been enabled - * but was not this session must fail. This must also fail if crypto was - * required in the offer but could not be set up. - */ - return -1; + if (session_media_transport == session_media || !session_media->bundled) { + /* If this media session is carrying actual traffic then set up those aspects */ + session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(stream, "rtcp-mux", NULL) != NULL); + set_ice_components(session, session_media); + + enable_rtcp(session, session_media, stream); + + res = setup_media_encryption(session, session_media, sdp, stream); + if (res) { + if (!session->endpoint->media.rtp.encryption_optimistic || + !pj_strncmp2(&stream->desc.transport, "RTP/SAVP", 8)) { + /* If optimistic encryption is disabled and crypto should have been enabled + * but was not this session must fail. This must also fail if crypto was + * required in the offer but could not be set up. + */ + return -1; + } + /* There is no encryption, sad. */ + session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE; } - /* There is no encryption, sad. */ - session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE; - } - /* If we've been explicitly configured to use the received transport OR if - * encryption is on and crypto is present use the received transport. - * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending - * on the configuration of the remote endpoint (optimistic themselves or mandatory). - */ - if ((session->endpoint->media.rtp.use_received_transport) || - ((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) { - pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport); - } + /* If we've been explicitly configured to use the received transport OR if + * encryption is on and crypto is present use the received transport. + * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending + * on the configuration of the remote endpoint (optimistic themselves or mandatory). + */ + if ((session->endpoint->media.rtp.use_received_transport) || + ((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) { + pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport); + } + } else { + /* This is bundled with another session, so mark it as such */ + ast_rtp_instance_bundle(session_media->rtp, session_media_transport->rtp); - if (set_caps(session, session_media, stream, 1, asterisk_stream)) { + enable_rtcp(session, session_media, stream); + } + + if (set_caps(session, session_media, session_media_transport, stream, 1, asterisk_stream)) { return 0; } + return 1; } @@ -1032,6 +1131,7 @@ static int add_crypto_to_stream(struct ast_sip_session *session, static const pj_str_t STR_PASSIVE = { "passive", 7 }; static const pj_str_t STR_ACTPASS = { "actpass", 7 }; static const pj_str_t STR_HOLDCONN = { "holdconn", 8 }; + enum ast_rtp_dtls_setup setup; switch (session_media->encryption) { case AST_SIP_MEDIA_ENCRYPT_NONE: @@ -1085,7 +1185,16 @@ static int add_crypto_to_stream(struct ast_sip_session *session, break; } - switch (dtls->get_setup(session_media->rtp)) { + /* If this is an answer we need to use our current state, if it's an offer we need to use + * the configured value. + */ + if (pjmedia_sdp_neg_get_state(session->inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { + setup = dtls->get_setup(session_media->rtp); + } else { + setup = session->endpoint->media.rtp.dtls_cfg.default_setup; + } + + switch (setup) { case AST_RTP_DTLS_SETUP_ACTIVE: attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTIVE); media->attr[media->attr_count++] = attr; @@ -1100,7 +1209,6 @@ static int add_crypto_to_stream(struct ast_sip_session *session, break; case AST_RTP_DTLS_SETUP_HOLDCONN: attr = pjmedia_sdp_attr_create(pool, "setup", &STR_HOLDCONN); - media->attr[media->attr_count++] = attr; break; default: break; @@ -1152,6 +1260,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as int rtp_code; RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); enum ast_media_type media_type = session_media->type; + struct ast_sip_session_media *session_media_transport; int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && ast_format_cap_count(session->direct_media_cap); @@ -1195,68 +1304,106 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as return -1; } - set_ice_components(session, session_media); - enable_rtcp(session, session_media, NULL); + /* If this stream has not been bundled already it is new and we need to ensure there is no SSRC conflict */ + if (session_media->bundle_group != -1 && !session_media->bundled) { + for (index = 0; index < sdp->media_count; ++index) { + struct ast_sip_session_media *other_session_media; - /* Crypto has to be added before setting the media transport so that SRTP is properly - * set up according to the configuration. This ends up changing the media transport. - */ - if (add_crypto_to_stream(session, session_media, pool, media)) { - return -1; - } + other_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index); + if (!other_session_media->rtp || other_session_media->bundle_group != session_media->bundle_group) { + continue; + } - if (pj_strlen(&session_media->transport)) { - /* If a transport has already been specified use it */ - media->desc.transport = session_media->transport; - } else { - media->desc.transport = pj_str(ast_sdp_get_rtp_profile( - /* Optimistic encryption places crypto in the normal RTP/AVP profile */ - !session->endpoint->media.rtp.encryption_optimistic && - (session_media->encryption == AST_SIP_MEDIA_ENCRYPT_SDES), - session_media->rtp, session->endpoint->media.rtp.use_avpf, - session->endpoint->media.rtp.force_avp)); + if (ast_rtp_instance_get_ssrc(session_media->rtp) == ast_rtp_instance_get_ssrc(other_session_media->rtp)) { + ast_rtp_instance_change_source(session_media->rtp); + /* Start the conflict check over again */ + index = -1; + continue; + } + } } - media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)); - if (!media->conn) { - return -1; - } + session_media_transport = ast_sip_session_media_get_transport(session, session_media); - /* Add connection level details */ - if (direct_media_enabled) { - hostip = ast_sockaddr_stringify_fmt(&session_media->direct_media_addr, AST_SOCKADDR_STR_ADDR); - } else if (ast_strlen_zero(session->endpoint->media.address)) { - hostip = ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET()); - } else { - hostip = session->endpoint->media.address; - } + if (session_media_transport == session_media || !session_media->bundled) { + set_ice_components(session, session_media); + enable_rtcp(session, session_media, NULL); - if (ast_strlen_zero(hostip)) { - ast_log(LOG_ERROR, "No local host IP available for stream %s\n", - ast_codec_media_type2str(session_media->type)); - return -1; - } + /* Crypto has to be added before setting the media transport so that SRTP is properly + * set up according to the configuration. This ends up changing the media transport. + */ + if (add_crypto_to_stream(session, session_media, pool, media)) { + return -1; + } - media->conn->net_type = STR_IN; - /* Assume that the connection will use IPv4 until proven otherwise */ - media->conn->addr_type = STR_IP4; - pj_strdup2(pool, &media->conn->addr, hostip); + if (pj_strlen(&session_media->transport)) { + /* If a transport has already been specified use it */ + media->desc.transport = session_media->transport; + } else { + media->desc.transport = pj_str(ast_sdp_get_rtp_profile( + /* Optimistic encryption places crypto in the normal RTP/AVP profile */ + !session->endpoint->media.rtp.encryption_optimistic && + (session_media->encryption == AST_SIP_MEDIA_ENCRYPT_SDES), + session_media->rtp, session->endpoint->media.rtp.use_avpf, + session->endpoint->media.rtp.force_avp)); + } - if (!ast_strlen_zero(session->endpoint->media.address)) { - pj_sockaddr ip; + media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)); + if (!media->conn) { + return -1; + } - if ((pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &media->conn->addr, &ip) == PJ_SUCCESS) && - (ip.addr.sa_family == pj_AF_INET6())) { - media->conn->addr_type = STR_IP6; + /* Add connection level details */ + if (direct_media_enabled) { + hostip = ast_sockaddr_stringify_fmt(&session_media->direct_media_addr, AST_SOCKADDR_STR_ADDR); + } else if (ast_strlen_zero(session->endpoint->media.address)) { + hostip = ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET()); + } else { + hostip = session->endpoint->media.address; } - } - /* Add ICE attributes and candidates */ - add_ice_to_stream(session, session_media, pool, media); + if (ast_strlen_zero(hostip)) { + ast_log(LOG_ERROR, "No local host IP available for stream %s\n", + ast_codec_media_type2str(session_media->type)); + return -1; + } + + media->conn->net_type = STR_IN; + /* Assume that the connection will use IPv4 until proven otherwise */ + media->conn->addr_type = STR_IP4; + pj_strdup2(pool, &media->conn->addr, hostip); + + if (!ast_strlen_zero(session->endpoint->media.address)) { + pj_sockaddr ip; + + if ((pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &media->conn->addr, &ip) == PJ_SUCCESS) && + (ip.addr.sa_family == pj_AF_INET6())) { + media->conn->addr_type = STR_IP6; + } + } + + /* Add ICE attributes and candidates */ + add_ice_to_stream(session, session_media, pool, media, 1); + + ast_rtp_instance_get_local_address(session_media->rtp, &addr); + media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr); + media->desc.port_count = 1; + } else { + pjmedia_sdp_media *bundle_group_stream = sdp->media[session_media_transport->stream_num]; + + /* As this is in a bundle group it shares the same details as the group instance */ + media->desc.transport = bundle_group_stream->desc.transport; + media->conn = bundle_group_stream->conn; + media->desc.port = bundle_group_stream->desc.port; + + if (add_crypto_to_stream(session, session_media_transport, pool, media)) { + return -1; + } - ast_rtp_instance_get_local_address(session_media->rtp, &addr); - media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr); - media->desc.port_count = 1; + add_ice_to_stream(session, session_media_transport, pool, media, 0); + + enable_rtcp(session, session_media, NULL); + } if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", @@ -1278,10 +1425,23 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as continue; } - if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0)) == -1) { - ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); - ao2_ref(format, -1); - continue; + /* If this stream is not a transport we need to use the transport codecs structure for payload management to prevent + * conflicts. + */ + if (session_media_transport != session_media) { + if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media_transport->rtp), 1, format, 0)) == -1) { + ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); + ao2_ref(format, -1); + continue; + } + /* Our instance has to match the payload number though */ + ast_rtp_codecs_payload_set_rx(ast_rtp_instance_get_codecs(session_media->rtp), rtp_code, format); + } else { + if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0)) == -1) { + ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); + ao2_ref(format, -1); + continue; + } } if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) { @@ -1332,6 +1492,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } } + /* If no formats were actually added to the media stream don't add it to the SDP */ if (!media->desc.fmt_count) { return 1; @@ -1365,6 +1526,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr); } + add_ssrc_to_stream(session, session_media, pool, media); + /* Add the media stream to the SDP */ sdp->media[sdp->media_count++] = media; @@ -1425,6 +1588,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, enum ast_media_type media_type = session_media->type; char host[NI_MAXHOST]; int res; + struct ast_sip_session_media *session_media_transport; if (!session->channel) { return 1; @@ -1441,48 +1605,60 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, return -1; } - session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(remote_stream, "rtcp-mux", NULL) != NULL); - set_ice_components(session, session_media); + process_ssrc_attributes(session, session_media, remote_stream); - enable_rtcp(session, session_media, remote_stream); + session_media_transport = ast_sip_session_media_get_transport(session, session_media); - res = setup_media_encryption(session, session_media, remote, remote_stream); - if (!session->endpoint->media.rtp.encryption_optimistic && res) { - /* If optimistic encryption is disabled and crypto should have been enabled but was not - * this session must fail. - */ - return -1; - } + if (session_media_transport == session_media || !session_media->bundled) { + session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(remote_stream, "rtcp-mux", NULL) != NULL); + set_ice_components(session, session_media); - if (!remote_stream->conn && !remote->conn) { - return 1; - } + enable_rtcp(session, session_media, remote_stream); - ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host)); + res = setup_media_encryption(session, session_media, remote, remote_stream); + if (!session->endpoint->media.rtp.encryption_optimistic && res) { + /* If optimistic encryption is disabled and crypto should have been enabled but was not + * this session must fail. + */ + return -1; + } - /* Ensure that the address provided is valid */ - if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) { - /* The provided host was actually invalid so we error out this negotiation */ - return -1; - } + if (!remote_stream->conn && !remote->conn) { + return 1; + } - /* Apply connection information to the RTP instance */ - ast_sockaddr_set_port(addrs, remote_stream->desc.port); - ast_rtp_instance_set_remote_address(session_media->rtp, addrs); - if (set_caps(session, session_media, remote_stream, 0, asterisk_stream)) { - return 1; - } + ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host)); - ast_sip_session_media_set_write_callback(session, session_media, media_session_rtp_write_callback); - ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 0), - media_session_rtp_read_callback); - if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) { - ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 1), - media_session_rtcp_read_callback); + /* Ensure that the address provided is valid */ + if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) { + /* The provided host was actually invalid so we error out this negotiation */ + return -1; + } + + /* Apply connection information to the RTP instance */ + ast_sockaddr_set_port(addrs, remote_stream->desc.port); + ast_rtp_instance_set_remote_address(session_media->rtp, addrs); + + ast_sip_session_media_set_write_callback(session, session_media, media_session_rtp_write_callback); + ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 0), + media_session_rtp_read_callback); + if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) { + ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 1), + media_session_rtcp_read_callback); + } + + /* If ICE support is enabled find all the needed attributes */ + process_ice_attributes(session, session_media, remote, remote_stream); + } else { + /* This is bundled with another session, so mark it as such */ + ast_rtp_instance_bundle(session_media->rtp, session_media_transport->rtp); + ast_sip_session_media_set_write_callback(session, session_media, media_session_rtp_write_callback); + enable_rtcp(session, session_media, remote_stream); } - /* If ICE support is enabled find all the needed attributes */ - process_ice_attributes(session, session_media, remote, remote_stream); + if (set_caps(session, session_media, session_media_transport, remote_stream, 0, asterisk_stream)) { + return 1; + } /* Set the channel uniqueid on the RTP instance now that it is becoming active */ ast_channel_lock(session->channel); @@ -1490,6 +1666,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, ast_channel_unlock(session->channel); /* Ensure the RTP instance is active */ + ast_rtp_instance_set_stream_num(session_media->rtp, ast_stream_get_position(asterisk_stream)); ast_rtp_instance_activate(session_media->rtp); /* audio stream handles music on hold */ diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index ecda4990132..315db6df5db 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -324,6 +324,28 @@ int ast_sip_session_media_set_write_callback(struct ast_sip_session *session, st return 0; } +struct ast_sip_session_media *ast_sip_session_media_get_transport(struct ast_sip_session *session, struct ast_sip_session_media *session_media) +{ + int index; + + if (!session->endpoint->media.bundle || ast_strlen_zero(session_media->mid)) { + return session_media; + } + + for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) { + struct ast_sip_session_media *bundle_group_session_media; + + bundle_group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index); + + /* The first session which is in the bundle group is considered the authoritative session for transport */ + if (bundle_group_session_media->bundle_group == session_media->bundle_group) { + return bundle_group_session_media; + } + } + + return session_media; +} + /*! * \brief Set an SDP stream handler for a corresponding session media. * @@ -371,6 +393,8 @@ static void session_media_dtor(void *obj) if (session_media->srtp) { ast_sdp_srtp_destroy(session_media->srtp); } + + ast_free(session_media->mid); } struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session, @@ -408,13 +432,25 @@ struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_ses session_media->timeout_sched_id = -1; session_media->type = type; session_media->stream_num = position; + + if (session->endpoint->media.bundle) { + /* This is a new stream so create a new mid based on media type and position, which makes it unique. + * If this is the result of an offer the mid will just end up getting replaced. + */ + if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) { + ao2_ref(session_media, -1); + return NULL; + } + session_media->bundle_group = 0; + } else { + session_media->bundle_group = -1; + } } AST_VECTOR_REPLACE(&media_state->sessions, position, session_media); /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */ - if (!media_state->default_session[type] && - ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) { + if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) { media_state->default_session[type] = session_media; } @@ -441,6 +477,78 @@ static int is_stream_limitation_reached(enum ast_media_type type, const struct a } } +static int get_mid_bundle_group(const pjmedia_sdp_session *sdp, const char *mid) +{ + int bundle_group = 0; + int index; + + for (index = 0; index < sdp->attr_count; ++index) { + pjmedia_sdp_attr *attr = sdp->attr[index]; + char value[pj_strlen(&attr->value) + 1], *mids = value, *attr_mid; + + if (pj_strcmp2(&attr->name, "group") || pj_strncmp2(&attr->value, "BUNDLE", 6)) { + continue; + } + + ast_copy_pj_str(value, &attr->value, sizeof(value)); + + /* Skip the BUNDLE at the front */ + mids += 7; + + while ((attr_mid = strsep(&mids, " "))) { + if (!strcmp(attr_mid, mid)) { + /* The ordering of attributes determines our internal identification of the bundle group based on number, + * with -1 being not in a bundle group. Since this is only exposed internally for response purposes it's + * actually even fine if things move around. + */ + return bundle_group; + } + } + + bundle_group++; + } + + return -1; +} + +static int set_mid_and_bundle_group(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, + const pjmedia_sdp_session *sdp, + const struct pjmedia_sdp_media *stream) +{ + pjmedia_sdp_attr *attr; + + if (!session->endpoint->media.bundle) { + return 0; + } + + /* By default on an incoming negotiation we assume no mid and bundle group is present */ + ast_free(session_media->mid); + session_media->mid = NULL; + session_media->bundle_group = -1; + session_media->bundled = 0; + + /* Grab the media identifier for the stream */ + attr = pjmedia_sdp_media_find_attr2(stream, "mid", NULL); + if (!attr) { + return 0; + } + + session_media->mid = ast_calloc(1, attr->value.slen + 1); + if (!session_media->mid) { + return 0; + } + ast_copy_pj_str(session_media->mid, &attr->value, attr->value.slen + 1); + + /* Determine what bundle group this is part of */ + session_media->bundle_group = get_mid_bundle_group(sdp, session_media->mid); + + /* If this is actually part of a bundle group then the other side requested or accepted the bundle request */ + session_media->bundled = session_media->bundle_group != -1; + + return 0; +} + static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp) { int i; @@ -497,9 +605,13 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n", ast_codec_media_type2str(type), i); ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + session_media->bundle_group = -1; + session_media->bundled = 0; continue; } + set_mid_and_bundle_group(session, session_media, sdp, remote_stream); + if (session_media->handler) { handler = session_media->handler; ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n", @@ -589,6 +701,8 @@ static int handle_negotiated_sdp_session_media(struct ast_sip_session_media *ses /* We need a null-terminated version of the media string */ ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media)); + set_mid_and_bundle_group(session, session_media, remote, remote->media[index]); + handler = session_media->handler; if (handler) { ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n", @@ -3443,6 +3557,82 @@ static int add_sdp_streams(struct ast_sip_session_media *session_media, return 0; } +/*! \brief Bundle group building structure */ +struct sip_session_media_bundle_group { + /*! \brief The media identifiers in this bundle group */ + char *mids[PJMEDIA_MAX_SDP_MEDIA]; + /*! \brief SDP attribute string */ + struct ast_str *attr_string; +}; + +static int add_bundle_groups(struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_session *answer) +{ + pj_str_t stmp; + pjmedia_sdp_attr *attr; + struct sip_session_media_bundle_group bundle_groups[PJMEDIA_MAX_SDP_MEDIA]; + int index, mid_id; + struct sip_session_media_bundle_group *bundle_group; + + if (!session->endpoint->media.bundle) { + return 0; + } + + memset(bundle_groups, 0, sizeof(bundle_groups)); + + attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *")); + pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr); + + /* Build the bundle group layout so we can then add it to the SDP */ + for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) { + struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index); + + /* If this stream is not part of a bundle group we can't add it */ + if (session_media->bundle_group == -1) { + continue; + } + + bundle_group = &bundle_groups[session_media->bundle_group]; + + /* If this is the first mid then we need to allocate the attribute string and place BUNDLE in front */ + if (!bundle_group->mids[0]) { + bundle_group->mids[0] = session_media->mid; + bundle_group->attr_string = ast_str_create(64); + if (!bundle_group->attr_string) { + continue; + } + + ast_str_set(&bundle_group->attr_string, -1, "BUNDLE %s", session_media->mid); + continue; + } + + for (mid_id = 1; mid_id < PJMEDIA_MAX_SDP_MEDIA; ++mid_id) { + if (!bundle_group->mids[mid_id]) { + bundle_group->mids[mid_id] = session_media->mid; + ast_str_append(&bundle_group->attr_string, -1, " %s", session_media->mid); + break; + } else if (!strcmp(bundle_group->mids[mid_id], session_media->mid)) { + break; + } + } + } + + /* Add all bundle groups that have mids to the SDP */ + for (index = 0; index < PJMEDIA_MAX_SDP_MEDIA; ++index) { + bundle_group = &bundle_groups[index]; + + if (!bundle_group->attr_string) { + continue; + } + + attr = pjmedia_sdp_attr_create(pool, "group", pj_cstr(&stmp, ast_str_buffer(bundle_group->attr_string))); + pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr); + + ast_free(bundle_group->attr_string); + } + + return 0; +} + static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer) { static const pj_str_t STR_IN = { "IN", 2 }; @@ -3485,6 +3675,7 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) { struct ast_sip_session_media *session_media; struct ast_stream *stream; + unsigned int streams = local->media_count; /* This code does not enforce any maximum stream count limitations as that is done on either * the handling of an incoming SDP offer or on the handling of a session refresh. @@ -3501,12 +3692,30 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru return NULL; } + /* If a stream was actually added then add any additional details */ + if (streams != local->media_count) { + pjmedia_sdp_media *media = local->media[streams]; + pj_str_t stmp; + pjmedia_sdp_attr *attr; + + /* Add the media identifier if present */ + if (!ast_strlen_zero(session_media->mid)) { + attr = pjmedia_sdp_attr_create(inv->pool_prov, "mid", pj_cstr(&stmp, session_media->mid)); + pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr); + } + } + /* Ensure that we never exceed the maximum number of streams PJMEDIA will allow. */ if (local->media_count == PJMEDIA_MAX_SDP_MEDIA) { break; } } + /* Add any bundle groups that are present on the media state */ + if (add_bundle_groups(session, inv->pool_prov, local)) { + return NULL; + } + /* Use the connection details of an available media if possible for SDP level */ for (stream = 0; stream < local->media_count; stream++) { if (!local->media[stream]->conn) { diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index a032bb12fb4..877d48fb6d4 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -880,11 +880,20 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as static struct ast_frame *media_session_udptl_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media) { + struct ast_frame *frame; + if (!session_media->udptl) { return &ast_null_frame; } - return ast_udptl_read(session_media->udptl); + frame = ast_udptl_read(session_media->udptl); + if (!frame) { + return NULL; + } + + frame->stream_num = session_media->stream_num; + + return frame; } static int media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 01dfe76f29d..4bfbf9b087e 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -68,6 +68,7 @@ #include "asterisk/module.h" #include "asterisk/rtp_engine.h" #include "asterisk/smoother.h" +#include "asterisk/uuid.h" #include "asterisk/test.h" #define MAX_TIMESTAMP_SKEW 640 @@ -238,6 +239,14 @@ struct ice_wrap { }; #endif +/*! \brief Structure used for mapping an incoming SSRC to an RTP instance */ +struct rtp_ssrc_mapping { + /*! \brief The received SSRC */ + unsigned int ssrc; + /*! \brief The RTP instance this SSRC belongs to*/ + struct ast_rtp_instance *instance; +}; + /*! \brief RTP session description */ struct ast_rtp { int s; @@ -245,6 +254,7 @@ struct ast_rtp { struct ast_frame f; unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET]; unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */ + char cname[AST_UUID_STR_LEN]; /*!< Our local CNAME */ unsigned int themssrc; /*!< Their SSRC */ unsigned int rxssrc; unsigned int lastts; @@ -301,6 +311,11 @@ struct ast_rtp { struct ast_rtcp *rtcp; struct ast_rtp *bridged; /*!< Who we are Packet bridged to */ + struct ast_rtp_instance *bundled; /*!< The RTP instance we are bundled to */ + int stream_num; /*!< Stream num for this RTP instance */ + AST_VECTOR(, struct rtp_ssrc_mapping) ssrc_mapping; /*!< Mappings of SSRC to RTP instances */ + struct ast_sockaddr bind_address; /*!< Requested bind address for the sockets */ + enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */ struct ast_sockaddr strict_rtp_address; /*!< Remote address information for strict RTP purposes */ @@ -477,6 +492,9 @@ static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level); static unsigned int ast_rtp_get_ssrc(struct ast_rtp_instance *instance); static const char *ast_rtp_get_cname(struct ast_rtp_instance *instance); +static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned int ssrc); +static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num); +static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent); #ifdef HAVE_OPENSSL_SRTP static int ast_rtp_activate(struct ast_rtp_instance *instance); @@ -1907,6 +1925,9 @@ static struct ast_rtp_engine asterisk_rtp_engine = { #endif .ssrc_get = ast_rtp_get_ssrc, .cname_get = ast_rtp_get_cname, + .set_remote_ssrc = ast_rtp_set_remote_ssrc, + .set_stream_num = ast_rtp_set_stream_num, + .bundle = ast_rtp_bundle, }; #ifdef HAVE_OPENSSL_SRTP @@ -1943,6 +1964,23 @@ static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtl } #endif +#ifdef HAVE_OPENSSL_SRTP +static void dtls_perform_setup(struct dtls_details *dtls) +{ + if (!dtls->ssl || !SSL_is_init_finished(dtls->ssl)) { + return; + } + + SSL_clear(dtls->ssl); + if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + SSL_set_accept_state(dtls->ssl); + } else { + SSL_set_connect_state(dtls->ssl); + } + dtls->connection = AST_RTP_DTLS_CONNECTION_NEW; +} +#endif + #ifdef HAVE_PJPROJECT static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq); @@ -1971,9 +2009,12 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) } #ifdef HAVE_OPENSSL_SRTP + + dtls_perform_setup(&rtp->dtls); dtls_perform_handshake(instance, &rtp->dtls, 0); if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { + dtls_perform_setup(&rtp->rtcp->dtls); dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); } #endif @@ -2241,59 +2282,14 @@ static int dtls_srtp_renegotiate(const void *data) return 0; } -static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance, int rtcp) +static int dtls_srtp_add_local_ssrc(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance, int rtcp, unsigned int ssrc, int set_remote_policy) { unsigned char material[SRTP_MASTER_LEN * 2]; unsigned char *local_key, *local_salt, *remote_key, *remote_salt; struct ast_srtp_policy *local_policy, *remote_policy = NULL; - struct ast_rtp_instance_stats stats = { 0, }; int res = -1; struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; - /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */ - if (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) { - X509 *certificate; - - if (!(certificate = SSL_get_peer_certificate(dtls->ssl))) { - ast_log(LOG_WARNING, "No certificate was provided by the peer on RTP instance '%p'\n", instance); - return -1; - } - - /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */ - if (rtp->remote_fingerprint[0]) { - const EVP_MD *type; - unsigned char fingerprint[EVP_MAX_MD_SIZE]; - unsigned int size; - - if (rtp->remote_hash == AST_RTP_DTLS_HASH_SHA1) { - type = EVP_sha1(); - } else if (rtp->remote_hash == AST_RTP_DTLS_HASH_SHA256) { - type = EVP_sha256(); - } else { - ast_log(LOG_WARNING, "Unsupported fingerprint hash type on RTP instance '%p'\n", instance); - return -1; - } - - if (!X509_digest(certificate, type, fingerprint, &size) || - !size || - memcmp(fingerprint, rtp->remote_fingerprint, size)) { - X509_free(certificate); - ast_log(LOG_WARNING, "Fingerprint provided by remote party does not match that of peer certificate on RTP instance '%p'\n", - instance); - return -1; - } - } - - X509_free(certificate); - } - - /* Ensure that certificate verification was successful */ - if ((rtp->dtls_verify & AST_RTP_DTLS_VERIFY_CERTIFICATE) && SSL_get_verify_result(dtls->ssl) != X509_V_OK) { - ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n", - instance); - return -1; - } - /* Produce key information and set up SRTP */ if (!SSL_export_keying_material(dtls->ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { ast_log(LOG_WARNING, "Unable to extract SRTP keying material from DTLS-SRTP negotiation on RTP instance '%p'\n", @@ -2328,41 +2324,31 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as goto error; } - if (ast_rtp_instance_get_stats(instance, &stats, AST_RTP_INSTANCE_STAT_LOCAL_SSRC)) { - goto error; - } + res_srtp_policy->set_ssrc(local_policy, ssrc, 0); - res_srtp_policy->set_ssrc(local_policy, stats.local_ssrc, 0); + if (set_remote_policy) { + if (!(remote_policy = res_srtp_policy->alloc())) { + goto error; + } - if (!(remote_policy = res_srtp_policy->alloc())) { - goto error; - } + if (res_srtp_policy->set_master_key(remote_policy, remote_key, SRTP_MASTER_KEY_LEN, remote_salt, SRTP_MASTER_SALT_LEN) < 0) { + ast_log(LOG_WARNING, "Could not set key/salt information on remote policy of '%p' when setting up DTLS-SRTP\n", rtp); + goto error; + } - if (res_srtp_policy->set_master_key(remote_policy, remote_key, SRTP_MASTER_KEY_LEN, remote_salt, SRTP_MASTER_SALT_LEN) < 0) { - ast_log(LOG_WARNING, "Could not set key/salt information on remote policy of '%p' when setting up DTLS-SRTP\n", rtp); - goto error; - } + if (res_srtp_policy->set_suite(remote_policy, rtp->suite)) { + ast_log(LOG_WARNING, "Could not set suite to '%u' on remote policy of '%p' when setting up DTLS-SRTP\n", rtp->suite, rtp); + goto error; + } - if (res_srtp_policy->set_suite(remote_policy, rtp->suite)) { - ast_log(LOG_WARNING, "Could not set suite to '%u' on remote policy of '%p' when setting up DTLS-SRTP\n", rtp->suite, rtp); - goto error; + res_srtp_policy->set_ssrc(remote_policy, 0, 1); } - res_srtp_policy->set_ssrc(remote_policy, 0, 1); - if (ast_rtp_instance_add_srtp_policy(instance, remote_policy, local_policy, rtcp)) { ast_log(LOG_WARNING, "Could not set policies when setting up DTLS-SRTP on '%p'\n", rtp); goto error; } - if (rtp->rekey) { - ao2_ref(instance, +1); - if ((rtp->rekeyid = ast_sched_add(rtp->sched, rtp->rekey * 1000, dtls_srtp_renegotiate, instance)) < 0) { - ao2_ref(instance, -1); - goto error; - } - } - res = 0; error: @@ -2375,6 +2361,71 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as return res; } + +static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance, int rtcp) +{ + struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; + int index; + + /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */ + if (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) { + X509 *certificate; + + if (!(certificate = SSL_get_peer_certificate(dtls->ssl))) { + ast_log(LOG_WARNING, "No certificate was provided by the peer on RTP instance '%p'\n", instance); + return -1; + } + + /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */ + if (rtp->remote_fingerprint[0]) { + const EVP_MD *type; + unsigned char fingerprint[EVP_MAX_MD_SIZE]; + unsigned int size; + + if (rtp->remote_hash == AST_RTP_DTLS_HASH_SHA1) { + type = EVP_sha1(); + } else if (rtp->remote_hash == AST_RTP_DTLS_HASH_SHA256) { + type = EVP_sha256(); + } else { + ast_log(LOG_WARNING, "Unsupported fingerprint hash type on RTP instance '%p'\n", instance); + return -1; + } + + if (!X509_digest(certificate, type, fingerprint, &size) || + !size || + memcmp(fingerprint, rtp->remote_fingerprint, size)) { + X509_free(certificate); + ast_log(LOG_WARNING, "Fingerprint provided by remote party does not match that of peer certificate on RTP instance '%p'\n", + instance); + return -1; + } + } + + X509_free(certificate); + } + + if (dtls_srtp_add_local_ssrc(rtp, srtp, instance, rtcp, ast_rtp_instance_get_ssrc(instance), 1)) { + return -1; + } + + for (index = 0; index < AST_VECTOR_SIZE(&rtp->ssrc_mapping); ++index) { + struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&rtp->ssrc_mapping, index); + + if (dtls_srtp_add_local_ssrc(rtp, srtp, instance, rtcp, ast_rtp_instance_get_ssrc(mapping->instance), 0)) { + return -1; + } + } + + if (rtp->rekey) { + ao2_ref(instance, +1); + if ((rtp->rekeyid = ast_sched_add(rtp->sched, rtp->rekey * 1000, dtls_srtp_renegotiate, instance)) < 0) { + ao2_ref(instance, -1); + return -1; + } + } + + return 0; +} #endif static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet) @@ -2569,7 +2620,9 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz int len = size; void *temp = buf; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, rtcp); + struct ast_rtp_instance *transport = rtp->bundled ? rtp->bundled : instance; + struct ast_rtp *transport_rtp = ast_rtp_instance_get_data(transport); + struct ast_srtp *srtp = ast_rtp_instance_get_srtp(transport, rtcp); int res; *via_ice = 0; @@ -2579,20 +2632,24 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz } #ifdef HAVE_PJPROJECT - if (rtp->ice) { + if (transport_rtp->ice) { pj_status_t status; struct ice_wrap *ice; pj_thread_register_check(); /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ - ice = rtp->ice; + ice = transport_rtp->ice; ao2_ref(ice, +1); - ao2_unlock(instance); + if (instance == transport) { + ao2_unlock(instance); + } status = pj_ice_sess_send_data(ice->real_ice, rtcp ? AST_RTP_ICE_COMPONENT_RTCP : AST_RTP_ICE_COMPONENT_RTP, temp, len); ao2_ref(ice, -1); - ao2_lock(instance); + if (instance == transport) { + ao2_lock(instance); + } if (status == PJ_SUCCESS) { *via_ice = 1; return len; @@ -2600,7 +2657,7 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz } #endif - res = ast_sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa); + res = ast_sendto(rtcp ? transport_rtp->rtcp->s : transport_rtp->s, temp, len, flags, sa); if (res > 0) { ast_rtp_instance_set_last_tx(instance, time(NULL)); } @@ -2990,22 +3047,10 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad } #endif -/*! \pre instance is locked */ -static int ast_rtp_new(struct ast_rtp_instance *instance, - struct ast_sched_context *sched, struct ast_sockaddr *addr, - void *data) +static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_rtp *rtp) { - struct ast_rtp *rtp = NULL; int x, startplace; - /* Create a new RTP structure to hold all of our data */ - if (!(rtp = ast_calloc(1, sizeof(*rtp)))) { - return -1; - } - - /* Set default parameters on the newly created RTP structure */ - rtp->ssrc = ast_random(); - rtp->seqno = ast_random() & 0x7fff; rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); if (strictrtp) { rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); @@ -3015,10 +3060,9 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, /* Create a new socket for us to listen on and use */ if ((rtp->s = create_new_socket("RTP", - ast_sockaddr_is_ipv4(addr) ? AF_INET : - ast_sockaddr_is_ipv6(addr) ? AF_INET6 : -1)) < 0) { + ast_sockaddr_is_ipv4(&rtp->bind_address) ? AF_INET : + ast_sockaddr_is_ipv6(&rtp->bind_address) ? AF_INET6 : -1)) < 0) { ast_log(LOG_WARNING, "Failed to create a new socket for RTP instance '%p'\n", instance); - ast_free(rtp); return -1; } @@ -3028,11 +3072,11 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, startplace = x; for (;;) { - ast_sockaddr_set_port(addr, x); + ast_sockaddr_set_port(&rtp->bind_address, x); /* Try to bind, this will tell us whether the port is available or not */ - if (!ast_bind(rtp->s, addr)) { + if (!ast_bind(rtp->s, &rtp->bind_address)) { ast_debug(1, "Allocated port %d for RTP instance '%p'\n", x, instance); - ast_rtp_instance_set_local_address(instance, addr); + ast_rtp_instance_set_local_address(instance, &rtp->bind_address); break; } @@ -3045,7 +3089,6 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, if (x == startplace || (errno != EADDRINUSE && errno != EACCES)) { ast_log(LOG_ERROR, "Oh dear... we couldn't allocate a port for RTP instance '%p'\n", instance); close(rtp->s); - ast_free(rtp); return -1; } } @@ -3056,40 +3099,30 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, generate_random_string(rtp->local_ufrag, sizeof(rtp->local_ufrag)); generate_random_string(rtp->local_passwd, sizeof(rtp->local_passwd)); -#endif - ast_rtp_instance_set_data(instance, rtp); -#ifdef HAVE_PJPROJECT + /* Create an ICE session for ICE negotiation */ if (icesupport) { rtp->ice_num_components = 2; - ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(addr), x, instance); - if (ice_create(instance, addr, x, 0)) { + ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(&rtp->bind_address), x, instance); + if (ice_create(instance, &rtp->bind_address, x, 0)) { ast_log(LOG_NOTICE, "Failed to create ICE session\n"); } else { rtp->ice_port = x; - ast_sockaddr_copy(&rtp->ice_original_rtp_addr, addr); + ast_sockaddr_copy(&rtp->ice_original_rtp_addr, &rtp->bind_address); } } #endif - /* Record any information we may need */ - rtp->sched = sched; #ifdef HAVE_OPENSSL_SRTP rtp->rekeyid = -1; rtp->dtls.timeout_timer = -1; #endif - rtp->f.subclass.format = ao2_bump(ast_format_none); - rtp->lastrxformat = ao2_bump(ast_format_none); - rtp->lasttxformat = ao2_bump(ast_format_none); - return 0; } -/*! \pre instance is locked */ -static int ast_rtp_destroy(struct ast_rtp_instance *instance) +static void rtp_deallocate_transport(struct ast_rtp_instance *instance, struct ast_rtp *rtp) { - struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); #ifdef HAVE_PJPROJECT struct timeval wait = ast_tvadd(ast_tvnow(), ast_samp2tv(TURN_STATE_WAIT_TIME, 1000)); struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, }; @@ -3099,35 +3132,16 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) ast_rtp_dtls_stop(instance); #endif - /* Destroy the smoother that was smoothing out audio if present */ - if (rtp->smoother) { - ast_smoother_free(rtp->smoother); - } - /* Close our own socket so we no longer get packets */ if (rtp->s > -1) { close(rtp->s); + rtp->s = -1; } /* Destroy RTCP if it was being used */ - if (rtp->rtcp) { - /* - * It is not possible for there to be an active RTCP scheduler - * entry at this point since it holds a reference to the - * RTP instance while it's active. - */ + if (rtp->rtcp && rtp->rtcp->s > -1) { close(rtp->rtcp->s); - ast_free(rtp->rtcp->local_addr_str); - ast_free(rtp->rtcp); - } - - /* Destroy RED if it was being used */ - if (rtp->red) { - ao2_unlock(instance); - AST_SCHED_DEL(rtp->sched, rtp->red->schedid); - ao2_lock(instance); - ast_free(rtp->red); - rtp->red = NULL; + rtp->rtcp->s = -1; } #ifdef HAVE_PJPROJECT @@ -3148,6 +3162,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) { ast_cond_timedwait(&rtp->cond, ao2_object_get_lockaddr(instance), &ts); } + rtp->turn_rtp = NULL; } /* Destroy the RTCP TURN relay if being used */ @@ -3161,6 +3176,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) { ast_cond_timedwait(&rtp->cond, ao2_object_get_lockaddr(instance), &ts); } + rtp->turn_rtcp = NULL; } /* Destroy any ICE session */ @@ -3169,10 +3185,12 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) /* Destroy any candidates */ if (rtp->ice_local_candidates) { ao2_ref(rtp->ice_local_candidates, -1); + rtp->ice_local_candidates = NULL; } if (rtp->ice_active_remote_candidates) { ao2_ref(rtp->ice_active_remote_candidates, -1); + rtp->ice_active_remote_candidates = NULL; } if (rtp->ioqueue) { @@ -3184,17 +3202,109 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) ao2_unlock(instance); rtp_ioqueue_thread_remove(rtp->ioqueue); ao2_lock(instance); + rtp->ioqueue = NULL; } #endif +} + +/*! \pre instance is locked */ +static int ast_rtp_new(struct ast_rtp_instance *instance, + struct ast_sched_context *sched, struct ast_sockaddr *addr, + void *data) +{ + struct ast_rtp *rtp = NULL; + + /* Create a new RTP structure to hold all of our data */ + if (!(rtp = ast_calloc(1, sizeof(*rtp)))) { + return -1; + } + + /* Set default parameters on the newly created RTP structure */ + rtp->ssrc = ast_random(); + ast_uuid_generate_str(rtp->cname, sizeof(rtp->cname)); + rtp->seqno = ast_random() & 0x7fff; + rtp->sched = sched; + ast_sockaddr_copy(&rtp->bind_address, addr); + + /* Transport creation operations can grab the RTP data from the instance, so set it */ + ast_rtp_instance_set_data(instance, rtp); + + if (rtp_allocate_transport(instance, rtp)) { + ast_free(rtp); + return -1; + } + + rtp->f.subclass.format = ao2_bump(ast_format_none); + rtp->lastrxformat = ao2_bump(ast_format_none); + rtp->lasttxformat = ao2_bump(ast_format_none); + rtp->stream_num = -1; + AST_VECTOR_INIT(&rtp->ssrc_mapping, 1); + + return 0; +} + +/*! + * \brief SSRC mapping comparator for AST_VECTOR_REMOVE_CMP_UNORDERED() + * + * \param elem Element to compare against + * \param value Value to compare with the vector element. + * + * \return 0 if element does not match. + * \return Non-zero if element matches. + */ +#define SSRC_MAPPING_ELEM_CMP(elem, value) ((elem).ssrc == (value)) + +/*! \pre instance is locked */ +static int ast_rtp_destroy(struct ast_rtp_instance *instance) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + if (rtp->bundled) { + struct ast_rtp *bundled_rtp; + + /* We can't hold our instance lock while removing ourselves from the parent */ + ao2_unlock(instance); + + ao2_lock(rtp->bundled); + bundled_rtp = ast_rtp_instance_get_data(rtp->bundled); + AST_VECTOR_REMOVE_CMP_UNORDERED(&bundled_rtp->ssrc_mapping, rtp->themssrc, SSRC_MAPPING_ELEM_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP); + ao2_unlock(rtp->bundled); + + ao2_lock(instance); + ao2_ref(rtp->bundled, -1); + } + + rtp_deallocate_transport(instance, rtp); + + /* Destroy the smoother that was smoothing out audio if present */ + if (rtp->smoother) { + ast_smoother_free(rtp->smoother); + } + + /* Destroy RTCP if it was being used */ + if (rtp->rtcp) { + /* + * It is not possible for there to be an active RTCP scheduler + * entry at this point since it holds a reference to the + * RTP instance while it's active. + */ + ast_free(rtp->rtcp->local_addr_str); + ast_free(rtp->rtcp); + } + + /* Destroy RED if it was being used */ + if (rtp->red) { + ao2_unlock(instance); + AST_SCHED_DEL(rtp->sched, rtp->red->schedid); + ao2_lock(instance); + ast_free(rtp->red); + rtp->red = NULL; + } ao2_cleanup(rtp->lasttxformat); ao2_cleanup(rtp->lastrxformat); ao2_cleanup(rtp->f.subclass.format); - -#ifdef HAVE_PJPROJECT - /* Destroy synchronization items */ - ast_cond_destroy(&rtp->cond); -#endif + AST_VECTOR_FREE(&rtp->ssrc_mapping); /* Finally destroy ourselves */ ast_free(rtp); @@ -3444,21 +3554,18 @@ static void ast_rtp_change_source(struct ast_rtp_instance *instance) struct ast_srtp *rtcp_srtp = ast_rtp_instance_get_srtp(instance, 1); unsigned int ssrc = ast_random(); - if (!rtp->lastts) { - ast_debug(3, "Not changing SSRC since we haven't sent any RTP yet\n"); - return; - } - - /* We simply set this bit so that the next packet sent will have the marker bit turned on */ - ast_set_flag(rtp, FLAG_NEED_MARKER_BIT); + if (rtp->lastts) { + /* We simply set this bit so that the next packet sent will have the marker bit turned on */ + ast_set_flag(rtp, FLAG_NEED_MARKER_BIT); - ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc); + ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc); - if (srtp) { - ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc); - res_srtp->change_source(srtp, rtp->ssrc, ssrc); - if (rtcp_srtp != srtp) { - res_srtp->change_source(rtcp_srtp, rtp->ssrc, ssrc); + if (srtp) { + ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc); + res_srtp->change_source(srtp, rtp->ssrc, ssrc); + if (rtcp_srtp != srtp) { + res_srtp->change_source(rtcp_srtp, rtp->ssrc, ssrc); + } } } @@ -3573,14 +3680,13 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) struct timeval now; unsigned int now_lsw; unsigned int now_msw; - unsigned int *rtcpheader; + unsigned char *rtcpheader; unsigned int lost_packets; int fraction_lost; struct timeval dlsr = { 0, }; - char bdata[512]; + unsigned char bdata[512] = ""; int rate = rtp_get_rate(rtp->f.subclass.format); int ice; - int header_offset = 0; struct ast_sockaddr remote_address = { { 0, } }; struct ast_rtp_rtcp_report_block *report_block = NULL; RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, @@ -3634,38 +3740,42 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) } } timeval2ntp(rtcp_report->sender_information.ntp_timestamp, &now_msw, &now_lsw); - rtcpheader = (unsigned int *)bdata; - rtcpheader[1] = htonl(rtcp_report->ssrc); /* Our SSRC */ + rtcpheader = bdata; + put_unaligned_uint32(rtcpheader + 4, htonl(rtcp_report->ssrc)); /* Our SSRC */ len += 8; if (sr) { - header_offset = 5; - rtcpheader[2] = htonl(now_msw); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/ - rtcpheader[3] = htonl(now_lsw); /* now, LSW */ - rtcpheader[4] = htonl(rtcp_report->sender_information.rtp_timestamp); - rtcpheader[5] = htonl(rtcp_report->sender_information.packet_count); - rtcpheader[6] = htonl(rtcp_report->sender_information.octet_count); + put_unaligned_uint32(rtcpheader + len, htonl(now_msw)); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/ + put_unaligned_uint32(rtcpheader + len + 4, htonl(now_lsw)); /* now, LSW */ + put_unaligned_uint32(rtcpheader + len + 8, htonl(rtcp_report->sender_information.rtp_timestamp)); + put_unaligned_uint32(rtcpheader + len + 12, htonl(rtcp_report->sender_information.packet_count)); + put_unaligned_uint32(rtcpheader + len + 16, htonl(rtcp_report->sender_information.octet_count)); len += 20; } if (report_block) { - rtcpheader[2 + header_offset] = htonl(report_block->source_ssrc); /* Their SSRC */ - rtcpheader[3 + header_offset] = htonl((report_block->lost_count.fraction << 24) | report_block->lost_count.packets); - rtcpheader[4 + header_offset] = htonl(report_block->highest_seq_no); - rtcpheader[5 + header_offset] = htonl(report_block->ia_jitter); - rtcpheader[6 + header_offset] = htonl(report_block->lsr); - rtcpheader[7 + header_offset] = htonl(report_block->dlsr); + put_unaligned_uint32(rtcpheader + len, htonl(report_block->source_ssrc)); /* Their SSRC */ + put_unaligned_uint32(rtcpheader + len + 4, htonl((report_block->lost_count.fraction << 24) | report_block->lost_count.packets)); + put_unaligned_uint32(rtcpheader + len + 8, htonl(report_block->highest_seq_no)); + put_unaligned_uint32(rtcpheader + len + 12, htonl(report_block->ia_jitter)); + put_unaligned_uint32(rtcpheader + len + 16, htonl(report_block->lsr)); + put_unaligned_uint32(rtcpheader + len + 20, htonl(report_block->dlsr)); len += 24; } - rtcpheader[0] = htonl((2 << 30) | (rtcp_report->reception_report_count << 24) - | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1)); - /* Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos */ - /* it can change mid call, and SDES can't) */ - rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2); - rtcpheader[(len/4)+1] = htonl(rtcp_report->ssrc); - rtcpheader[(len/4)+2] = htonl(0x01 << 24); - len += 12; + put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (rtcp_report->reception_report_count << 24) + | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1))); + + put_unaligned_uint32(rtcpheader + len, htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | (2 + (AST_UUID_STR_LEN / 4)))); + put_unaligned_uint32(rtcpheader + len + 4, htonl(rtcp_report->ssrc)); + put_unaligned_uint16(rtcpheader + len + 8, htonl(0x01 << 24)); + put_unaligned_uint16(rtcpheader + len + 9, htonl(AST_UUID_STR_LEN << 24)); + memcpy(rtcpheader + len + 10, rtp->cname, AST_UUID_STR_LEN); + len += 12 + AST_UUID_STR_LEN; - ast_sockaddr_copy(&remote_address, &rtp->rtcp->them); + if (rtp->bundled) { + ast_rtp_instance_get_remote_address(instance, &remote_address); + } else { + ast_sockaddr_copy(&remote_address, &rtp->rtcp->them); + } res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice); if (res < 0) { ast_log(LOG_ERROR, "RTCP %s transmission error to %s, rtcp halted %s\n", @@ -3942,7 +4052,6 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr /* VP8: is this a request to send a RTCP FIR? */ if (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_VIDUPDATE) { - struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); unsigned int *rtcpheader; char bdata[1024]; int len = 20; @@ -3972,7 +4081,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr rtcpheader[2] = htonl(rtp->themssrc); rtcpheader[3] = htonl(rtp->themssrc); /* FCI: SSRC */ rtcpheader[4] = htonl(rtp->rtcp->firseq << 24); /* FCI: Sequence number */ - res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &rtp->rtcp->them, &ice); + res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, rtp->bundled ? &remote_address : &rtp->rtcp->them, &ice); if (res < 0) { ast_log(LOG_ERROR, "RTCP FIR transmission error: %s\n", strerror(errno)); } @@ -4537,9 +4646,29 @@ static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets) rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current; } +/*! \pre instance is locked */ +static struct ast_rtp_instance *rtp_find_instance_by_ssrc(struct ast_rtp_instance *instance, + struct ast_rtp *rtp, unsigned int ssrc) +{ + int index; + struct ast_rtp_instance *found = instance; + + for (index = 0; index < AST_VECTOR_SIZE(&rtp->ssrc_mapping); ++index) { + struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&rtp->ssrc_mapping, index); + + if (mapping->ssrc == ssrc) { + found = mapping->instance; + break; + } + } + + return found; +} + static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr) { - struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + struct ast_rtp_instance *transport = instance; + struct ast_rtp *transport_rtp = ast_rtp_instance_get_data(instance); unsigned int *rtcpheader = (unsigned int *)(rtcpdata); int packetwords, position = 0; int report_counter = 0; @@ -4548,13 +4677,13 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c packetwords = size / 4; - if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { + if (ast_rtp_instance_get_prop(transport, AST_RTP_PROPERTY_NAT)) { /* Send to whoever sent to us */ - if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) { - ast_sockaddr_copy(&rtp->rtcp->them, addr); + if (ast_sockaddr_cmp(&transport_rtp->rtcp->them, addr)) { + ast_sockaddr_copy(&transport_rtp->rtcp->them, addr); if (rtpdebug) { ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", - ast_sockaddr_stringify(&rtp->rtcp->them)); + ast_sockaddr_stringify(&transport_rtp->rtcp->them)); } } } @@ -4566,6 +4695,8 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c unsigned int length; struct ast_json *message_blob; RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, NULL, ao2_cleanup); + struct ast_rtp_instance *child; + struct ast_rtp *rtp; i = position; length = ntohl(rtcpheader[i]); @@ -4597,6 +4728,21 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c ast_verbose("SSRC of sender: %u\n", rtcp_report->ssrc); } + /* Determine the appropriate instance for this */ + child = rtp_find_instance_by_ssrc(transport, transport_rtp, rtcp_report->ssrc); + if (child != transport) { + /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order + * is always parent->child or that the child lock is not held when acquiring the parent lock. + */ + ao2_lock(child); + instance = child; + rtp = ast_rtp_instance_get_data(instance); + } else { + /* The child is the parent! We don't need to unlock it. */ + child = NULL; + rtp = transport_rtp; + } + i += 2; /* Advance past header and ssrc */ switch (pt) { case RTCP_PT_SR: @@ -4632,6 +4778,9 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c /* Don't handle multiple reception reports (rc > 1) yet */ report_block = ast_calloc(1, sizeof(*report_block)); if (!report_block) { + if (child) { + ao2_unlock(child); + } return &ast_null_frame; } rtcp_report->report_block[report_counter] = report_block; @@ -4678,8 +4827,8 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c */ message_blob = ast_json_pack("{s: s, s: s, s: f}", - "from", ast_sockaddr_stringify(&rtp->rtcp->them), - "to", rtp->rtcp->local_addr_str, + "from", ast_sockaddr_stringify(&transport_rtp->rtcp->them), + "to", transport_rtp->rtcp->local_addr_str, "rtt", rtp->rtcp->rtt); ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(), rtcp_report, @@ -4688,26 +4837,26 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c /* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report * object as a its data */ - rtp->f.frametype = AST_FRAME_RTCP; - rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET; - memcpy(rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report)); - rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report); + transport_rtp->f.frametype = AST_FRAME_RTCP; + transport_rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET; + memcpy(transport_rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report)); + transport_rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report); if (rc > 0) { /* There's always a single report block stored, here */ struct ast_rtp_rtcp_report *rtcp_report2; - report_block = rtp->f.data.ptr + rtp->f.datalen + sizeof(struct ast_rtp_rtcp_report_block *); + report_block = transport_rtp->f.data.ptr + transport_rtp->f.datalen + sizeof(struct ast_rtp_rtcp_report_block *); memcpy(report_block, rtcp_report->report_block[report_counter-1], sizeof(struct ast_rtp_rtcp_report_block)); - rtcp_report2 = (struct ast_rtp_rtcp_report *)rtp->f.data.ptr; + rtcp_report2 = (struct ast_rtp_rtcp_report *)transport_rtp->f.data.ptr; rtcp_report2->report_block[report_counter-1] = report_block; - rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block); + transport_rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block); } - rtp->f.offset = AST_FRIENDLY_OFFSET; - rtp->f.samples = 0; - rtp->f.mallocd = 0; - rtp->f.delivery.tv_sec = 0; - rtp->f.delivery.tv_usec = 0; - rtp->f.src = "RTP"; - f = &rtp->f; + transport_rtp->f.offset = AST_FRIENDLY_OFFSET; + transport_rtp->f.samples = 0; + transport_rtp->f.mallocd = 0; + transport_rtp->f.delivery.tv_sec = 0; + transport_rtp->f.delivery.tv_usec = 0; + transport_rtp->f.src = "RTP"; + f = &transport_rtp->f; break; case RTCP_PT_FUR: /* Handle RTCP FIR as FUR */ @@ -4715,34 +4864,38 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c if (rtcp_debug_test_addr(addr)) { ast_verbose("Received an RTCP Fast Update Request\n"); } - rtp->f.frametype = AST_FRAME_CONTROL; - rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE; - rtp->f.datalen = 0; - rtp->f.samples = 0; - rtp->f.mallocd = 0; - rtp->f.src = "RTP"; - f = &rtp->f; + transport_rtp->f.frametype = AST_FRAME_CONTROL; + transport_rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE; + transport_rtp->f.datalen = 0; + transport_rtp->f.samples = 0; + transport_rtp->f.mallocd = 0; + transport_rtp->f.src = "RTP"; + f = &transport_rtp->f; break; case RTCP_PT_SDES: if (rtcp_debug_test_addr(addr)) { ast_verbose("Received an SDES from %s\n", - ast_sockaddr_stringify(&rtp->rtcp->them)); + ast_sockaddr_stringify(&transport_rtp->rtcp->them)); } break; case RTCP_PT_BYE: if (rtcp_debug_test_addr(addr)) { ast_verbose("Received a BYE from %s\n", - ast_sockaddr_stringify(&rtp->rtcp->them)); + ast_sockaddr_stringify(&transport_rtp->rtcp->them)); } break; default: ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s\n", - pt, ast_sockaddr_stringify(&rtp->rtcp->them)); + pt, ast_sockaddr_stringify(&transport_rtp->rtcp->them)); break; } position += (length + 1); + rtp->rtcp->rtcp_info = 1; + + if (child) { + ao2_unlock(child); + } } - rtp->rtcp->rtcp_info = 1; return f; @@ -4928,11 +5081,19 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, return 0; } +static void rtp_instance_unlock(struct ast_rtp_instance *instance) +{ + if (instance) { + ao2_unlock(instance); + } +} + /*! \pre instance is locked */ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_rtp_instance *instance1; + RAII_VAR(struct ast_rtp_instance *, child, NULL, rtp_instance_unlock); struct ast_sockaddr addr; int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno; unsigned char *read_area = rtp->rawdata + AST_FRIENDLY_OFFSET; @@ -4950,11 +5111,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc return &ast_null_frame; } - /* If we are currently sending DTMF to the remote party send a continuation packet */ - if (rtp->sending_digit) { - ast_rtp_dtmf_continuation(instance); - } - /* Actually read in the data from the socket */ if ((res = rtp_recvfrom(instance, read_area, read_area_size, 0, &addr)) < 0) { @@ -5070,6 +5226,33 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } } + /* If the version is not what we expected by this point then just drop the packet */ + if (version != 2) { + return &ast_null_frame; + } + + /* We use the SSRC to determine what RTP instance this packet is actually for */ + ssrc = ntohl(rtpheader[2]); + + /* Determine the appropriate instance for this */ + child = rtp_find_instance_by_ssrc(instance, rtp, ssrc); + if (child != instance) { + /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order + * is always parent->child or that the child lock is not held when acquiring the parent lock. + */ + ao2_lock(child); + instance = child; + rtp = ast_rtp_instance_get_data(instance); + } else { + /* The child is the parent! We don't need to unlock it. */ + child = NULL; + } + + /* If we are currently sending DTMF to the remote party send a continuation packet */ + if (rtp->sending_digit) { + ast_rtp_dtmf_continuation(instance); + } + /* If we are directly bridged to another instance send the audio directly out */ instance1 = ast_rtp_instance_get_bridged(instance); if (instance1 @@ -5077,11 +5260,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc return &ast_null_frame; } - /* If the version is not what we expected by this point then just drop the packet */ - if (version != 2) { - return &ast_null_frame; - } - /* Pull out the various other fields we will need */ payloadtype = (seqno & 0x7f0000) >> 16; padding = seqno & (1 << 29); @@ -5090,7 +5268,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc cc = (seqno & 0xF000000) >> 24; seqno &= 0xffff; timestamp = ntohl(rtpheader[1]); - ssrc = ntohl(rtpheader[2]); AST_LIST_HEAD_INIT_NOLOCK(&frames); /* Force a marker bit and change SSRC if the SSRC changes */ @@ -5264,6 +5441,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->f.data.ptr = read_area + hdrlen; rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET; rtp->f.seqno = seqno; + rtp->f.stream_num = rtp->stream_num; if ((ast_format_cmp(rtp->f.subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL) && ((int)seqno - (prev_seqno + 1) > 0) @@ -5525,6 +5703,7 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_sockaddr local; + int index; ast_rtp_instance_get_local_address(instance, &local); if (!ast_sockaddr_isnull(addr)) { @@ -5553,6 +5732,13 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local)); } + /* Update any bundled RTP instances */ + for (index = 0; index < AST_VECTOR_SIZE(&rtp->ssrc_mapping); ++index) { + struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&rtp->ssrc_mapping, index); + + ast_rtp_instance_set_remote_address(mapping->instance, addr); + } + rtp->rxseqno = 0; if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN) { @@ -5836,42 +6022,104 @@ static unsigned int ast_rtp_get_ssrc(struct ast_rtp_instance *instance) /*! \pre instance is locked */ static const char *ast_rtp_get_cname(struct ast_rtp_instance *instance) { - /* XXX - * - * Asterisk currently puts a zero-length CNAME value in RTCP SDES items, - * meaning our CNAME will always be an empty string. In future, should - * Asterisk actually start using meaningful CNAMEs, this function will - * need to return that instead of an empty string - */ - return ""; + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + return rtp->cname; } -#ifdef HAVE_OPENSSL_SRTP -static void dtls_perform_setup(struct dtls_details *dtls) +static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned int ssrc) { - if (!dtls->ssl || !SSL_is_init_finished(dtls->ssl)) { + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + if (rtp->themssrc) { return; } - SSL_clear(dtls->ssl); - if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { - SSL_set_accept_state(dtls->ssl); - } else { - SSL_set_connect_state(dtls->ssl); - } - dtls->connection = AST_RTP_DTLS_CONNECTION_NEW; + rtp->themssrc = ssrc; } -/*! \pre instance is locked */ -static int ast_rtp_activate(struct ast_rtp_instance *instance) +static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - dtls_perform_setup(&rtp->dtls); + rtp->stream_num = stream_num; +} - if (rtp->rtcp) { - dtls_perform_setup(&rtp->rtcp->dtls); +static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent) +{ + struct ast_rtp *child_rtp = ast_rtp_instance_get_data(child); + struct ast_rtp *parent_rtp = ast_rtp_instance_get_data(parent); + struct rtp_ssrc_mapping mapping; + struct ast_sockaddr them = { { 0, } }; + + if (child_rtp->bundled == parent) { + return 0; + } + + /* If this instance was already bundled then remove the SSRC mapping */ + if (child_rtp->bundled) { + struct ast_rtp *bundled_rtp; + + ao2_unlock(child); + + /* The child lock can't be held while accessing the parent */ + ao2_lock(child_rtp->bundled); + bundled_rtp = ast_rtp_instance_get_data(child_rtp->bundled); + AST_VECTOR_REMOVE_CMP_UNORDERED(&bundled_rtp->ssrc_mapping, child_rtp->themssrc, SSRC_MAPPING_ELEM_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP); + ao2_unlock(child_rtp->bundled); + + ao2_lock(child); + ao2_ref(child_rtp->bundled, -1); + child_rtp->bundled = NULL; + } + + if (!parent) { + /* We transitioned away from bundle so we need our own transport resources once again */ + rtp_allocate_transport(child, child_rtp); + return 0; + } + + /* We no longer need any transport related resources as we will use our parent RTP instance instead */ + rtp_deallocate_transport(child, child_rtp); + + /* Children maintain a reference to the parent to guarantee that the transport doesn't go away on them */ + child_rtp->bundled = ao2_bump(parent); + + mapping.ssrc = child_rtp->themssrc; + mapping.instance = child; + + ao2_unlock(child); + + ao2_lock(parent); + + AST_VECTOR_APPEND(&parent_rtp->ssrc_mapping, mapping); + +#ifdef HAVE_OPENSSL_SRTP + /* If DTLS-SRTP is already in use then add the local SSRC to it, otherwise it will get added once DTLS + * negotiation has been completed. + */ + if (parent_rtp->dtls.connection == AST_RTP_DTLS_CONNECTION_EXISTING) { + dtls_srtp_add_local_ssrc(parent_rtp, ast_rtp_instance_get_srtp(parent, 0), parent, 0, child_rtp->ssrc, 0); } +#endif + + /* Bundle requires that RTCP-MUX be in use so only the main remote address needs to match */ + ast_rtp_instance_get_remote_address(parent, &them); + + ao2_unlock(parent); + + ao2_lock(child); + + ast_rtp_instance_set_remote_address(child, &them); + + return 0; +} + +#ifdef HAVE_OPENSSL_SRTP +/*! \pre instance is locked */ +static int ast_rtp_activate(struct ast_rtp_instance *instance) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); /* If ICE negotiation is enabled the DTLS Handshake will be performed upon completion of it */ #ifdef HAVE_PJPROJECT @@ -5880,9 +6128,11 @@ static int ast_rtp_activate(struct ast_rtp_instance *instance) } #endif + dtls_perform_setup(&rtp->dtls); dtls_perform_handshake(instance, &rtp->dtls, 0); if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) { + dtls_perform_setup(&rtp->rtcp->dtls); dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); } From 78a50b034368d3a21f81dfce0fc740021092d7f1 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 10 Jul 2017 15:04:58 -0400 Subject: [PATCH 1373/1578] core: Add PARSE_TIMELEN support to ast_parse_arg and ACO. This adds support for parsing timelen values from config files. This includes support for all flags which apply to PARSE_INT32. Support for this parser is added to ACO via the OPT_TIMELEN_T option type. Fixes an issue where extra characters provided to ast_app_parse_timelen were ignored, they now cause an error. Testing is included. ASTERISK-27117 #close Change-Id: I6b333feca7e3f83b4ef5bf2636fc0fd613742554 --- UPGRADE.txt | 6 ++ configs/samples/config_test.conf.sample | 8 +++ include/asterisk/config.h | 11 ++++ include/asterisk/config_options.h | 24 +++++++ main/app.c | 13 ++++ main/config.c | 49 ++++++++++++++ main/config_options.c | 36 +++++++++++ tests/test_config.c | 85 +++++++++++++++++++++++++ 8 files changed, 232 insertions(+) diff --git a/UPGRADE.txt b/UPGRADE.txt index eb05b035e1b..6bb74449e93 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -32,6 +32,12 @@ Core: ARI. As a result, the 'DataGet' AMI action as well as the 'data get' CLI command have been removed. +From 14.6.0 to 14.7.0: + +Core: + - ast_app_parse_timelen now returns an error if it encounters extra characters + at the end of the string to be parsed. + From 14.4.0 to 14.5.0: Core: diff --git a/configs/samples/config_test.conf.sample b/configs/samples/config_test.conf.sample index 2fff45ecec9..b7cb2129202 100644 --- a/configs/samples/config_test.conf.sample +++ b/configs/samples/config_test.conf.sample @@ -6,6 +6,10 @@ [global] intopt=-1 uintopt=1 +timelenopt1=1ms +timelenopt2=1s +timelenopt3=1m +timelenopt4=1h doubleopt=0.1 sockaddropt=1.2.3.4:1234 boolopt=true @@ -23,6 +27,10 @@ customopt=yes [item] intopt=-1 uintopt=1 +timelenopt1=1 +timelenopt2=1 +timelenopt3=1 +timelenopt4=1 doubleopt=0.1 sockaddropt=1.2.3.4:1234 boolopt=true diff --git a/include/asterisk/config.h b/include/asterisk/config.h index f57966b0bab..1addfa317ef 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -1086,6 +1086,11 @@ enum ast_parse_flags { PARSE_UINT16 = 0x0005, #endif + /* Returns an int processed by ast_app_parse_timelen. + * The first argument is an enum ast_timelen value (required). + */ + PARSE_TIMELEN = 0x0006, + /* Returns a struct ast_sockaddr, with optional default value * (passed by reference) and port handling (accept, ignore, * require, forbid). The format is 'ipaddress[:port]'. IPv6 address @@ -1152,6 +1157,12 @@ enum ast_parse_flags { * returns 1, b unchanged * ast_parse_arg("12", PARSE_UINT32|PARSE_IN_RANGE|PARSE_RANGE_DEFAULTS, &a, 1, 10); * returns 1, a = 10 + * ast_parse_arg("223", PARSE_TIMELEN|PARSE_IN_RANGE, &a, TIMELEN_SECONDS, -1000, 1000); + * returns 0, a = 1000 + * ast_parse_arg("223", PARSE_TIMELEN|PARSE_IN_RANGE, &a, TIMELEN_SECONDS, -1000, 250000); + * returns 0, a = 223000 + * ast_parse_arg("223", PARSE_TIMELEN|PARSE_IN_RANGE|PARSE_DEFAULT, &a, TIMELEN_SECONDS, 9999, -1000, 250000); + * returns 0, a = 9999 * ast_parse_arg("www.foo.biz:44", PARSE_INADDR, &sa); * returns 0, sa contains address and port * ast_parse_arg("www.foo.biz", PARSE_INADDR|PARSE_PORT_REQUIRE, &sa); diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h index f2a457eb57a..f4c3db188fd 100644 --- a/include/asterisk/config_options.h +++ b/include/asterisk/config_options.h @@ -468,6 +468,30 @@ enum aco_option_type { */ OPT_YESNO_T, + /*! \brief Type for default option handler for time length signed integers + * + * \note aco_option_register flags: + * See flags available for use with the PARSE_TIMELEN type for the ast_parse_arg function + * aco_option_register varargs: + * FLDSET macro with the field of type int + * The remaining varargs for should be arguments compatible with the varargs for the + * ast_parse_arg function with the PARSE_TIMELEN type and the flags passed in the + * aco_option_register flags parameter. + * + * \note In most situations, it is preferable to not pass the PARSE_DEFAULT flag. If a config + * contains an invalid value, it is better to let the config loading fail with warnings so that + * the problem is fixed by the administrator. + * + * Example: + * struct test_item { + * int timelen; + * }; + * {code} + * aco_option_register(&cfg_info, "timelen", ACO_EXACT, my_types, "3", OPT_TIMELEN_T, PARSE_IN_RANGE, FLDSET(struct test_item, intopt), TIMELEN_MILLISECONDS, -10, 10); + * {endcode} + */ + OPT_TIMELEN_T, + }; /*! \brief A callback function for handling a particular option diff --git a/main/app.c b/main/app.c index 1eb0741ee15..69c96c06c8f 100644 --- a/main/app.c +++ b/main/app.c @@ -3060,19 +3060,32 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen uni case 'h': case 'H': unit = TIMELEN_HOURS; + if (u[1] != '\0') { + return -1; + } break; case 's': case 'S': unit = TIMELEN_SECONDS; + if (u[1] != '\0') { + return -1; + } break; case 'm': case 'M': if (toupper(u[1]) == 'S') { unit = TIMELEN_MILLISECONDS; + if (u[2] != '\0') { + return -1; + } } else if (u[1] == '\0') { unit = TIMELEN_MINUTES; + } else { + return -1; } break; + default: + return -1; } } diff --git a/main/config.c b/main/config.c index a3e09f67ecc..3d8dcfb3d7a 100644 --- a/main/config.c +++ b/main/config.c @@ -3741,6 +3741,55 @@ int ast_parse_arg(const char *arg, enum ast_parse_flags flags, break; } + case PARSE_TIMELEN: + { + int x = 0; + int *result = p_result; + int def = result ? *result : 0; + int high = INT_MAX; + int low = INT_MIN; + enum ast_timelen defunit; + + defunit = va_arg(ap, enum ast_timelen); + /* optional arguments: default value and/or (low, high) */ + if (flags & PARSE_DEFAULT) { + def = va_arg(ap, int); + } + if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) { + low = va_arg(ap, int); + high = va_arg(ap, int); + } + if (ast_strlen_zero(arg)) { + error = 1; + goto timelen_done; + } + error = ast_app_parse_timelen(arg, &x, defunit); + if (error || x < INT_MIN || x > INT_MAX) { + /* Parse error, or type out of int bounds */ + error = 1; + goto timelen_done; + } + error = (x < low) || (x > high); + if (flags & PARSE_RANGE_DEFAULTS) { + if (x < low) { + def = low; + } else if (x > high) { + def = high; + } + } + if (flags & PARSE_OUT_RANGE) { + error = !error; + } +timelen_done: + if (result) { + *result = error ? def : x; + } + + ast_debug(3, "extract timelen from [%s] in [%d, %d] gives [%d](%d)\n", + arg, low, high, result ? *result : x, error); + break; + } + case PARSE_DOUBLE: { double *result = p_result; diff --git a/main/config_options.c b/main/config_options.c index c8077790623..8eacbda35e6 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -34,6 +34,7 @@ #include "asterisk/config_options.h" #include "asterisk/stringfields.h" #include "asterisk/acl.h" +#include "asterisk/app.h" #include "asterisk/frame.h" #include "asterisk/xmldoc.h" #include "asterisk/cli.h" @@ -118,6 +119,7 @@ static void config_option_destroy(void *obj) static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj); static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj); +static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj); static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj); static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj); static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj); @@ -151,6 +153,7 @@ static aco_option_handler ast_config_option_default_handler(enum aco_option_type case OPT_SOCKADDR_T: return sockaddr_handler_fn; case OPT_STRINGFIELD_T: return stringfield_handler_fn; case OPT_UINT_T: return uint_handler_fn; + case OPT_TIMELEN_T: return timelen_handler_fn; case OPT_CUSTOM_T: return NULL; } @@ -1378,6 +1381,39 @@ static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *va return res; } +/*! \brief Default option handler for timelen signed integers + * \note For a description of the opt->flags and opt->args values, see the documentation for + * enum aco_option_type in config_options.h + */ +static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + int *field = (int *)(obj + opt->args[0]); + unsigned int flags = PARSE_TIMELEN | opt->flags; + int res = 0; + if (opt->flags & PARSE_IN_RANGE) { + if (opt->flags & PARSE_DEFAULT) { + res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3], opt->args[4]); + } else { + res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3]); + } + if (res) { + if (opt->flags & PARSE_RANGE_DEFAULTS) { + ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[2], (int) opt->args[3]); + res = 0; + } else if (opt->flags & PARSE_DEFAULT) { + ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field); + res = 0; + } + } + } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2])) { + ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field); + } else { + res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1]); + } + + return res; +} + /*! \brief Default option handler for doubles * \note For a description of the opt->flags and opt->args values, see the documentation for * enum aco_option_type in config_options.h diff --git a/tests/test_config.c b/tests/test_config.c index 6635c6f78a1..d737108604b 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -41,6 +41,7 @@ #include "asterisk/config_options.h" #include "asterisk/netsock2.h" #include "asterisk/acl.h" +#include "asterisk/app.h" #include "asterisk/pbx.h" #include "asterisk/frame.h" #include "asterisk/utils.h" @@ -1080,6 +1081,13 @@ enum { ast_test_status_update(test, "ast_parse_arg double failed with %f != %f\n", *r, e); \ ret = AST_TEST_FAIL; \ } \ + } else if (((flags) & PARSE_TYPE) == PARSE_TIMELEN) { \ + int *r = (int *) (void *) result; \ + int e = (int) expected_result; \ + if (*r != e) { \ + ast_test_status_update(test, "ast_parse_arg timelen failed with %d != %d\n", *r, e); \ + ret = AST_TEST_FAIL; \ + } \ } \ } \ *(result) = DEFAULTVAL; \ @@ -1090,6 +1098,7 @@ AST_TEST_DEFINE(ast_parse_arg_test) int ret = AST_TEST_PASS; int32_t int32_t_val = DEFAULTVAL; uint32_t uint32_t_val = DEFAULTVAL; + int timelen_val = DEFAULTVAL; double double_val = DEFAULTVAL; switch (cmd) { @@ -1222,6 +1231,60 @@ AST_TEST_DEFINE(ast_parse_arg_test) TEST_PARSE(" -123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val); + /* timelen testing */ + TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + + TEST_PARSE("123s", EXPECT_SUCCEED, 123000, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("-123s", EXPECT_SUCCEED, -123000, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("1m", EXPECT_SUCCEED, 60000, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("1", EXPECT_SUCCEED, 60000, PARSE_TIMELEN, &timelen_val, TIMELEN_MINUTES); + TEST_PARSE("1h", EXPECT_SUCCEED, 3600000, PARSE_TIMELEN, &timelen_val, TIMELEN_MILLISECONDS); + TEST_PARSE("1", EXPECT_SUCCEED, 3600000, PARSE_TIMELEN, &timelen_val, TIMELEN_HOURS); + + TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_TIMELEN | PARSE_DEFAULT, &timelen_val, TIMELEN_MILLISECONDS, 7); + TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_TIMELEN | PARSE_DEFAULT, &timelen_val, TIMELEN_MILLISECONDS, 7); + TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_TIMELEN | PARSE_DEFAULT, &timelen_val, TIMELEN_MILLISECONDS, 7); + TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT, &timelen_val, TIMELEN_MILLISECONDS, 7); + TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT, &timelen_val, TIMELEN_MILLISECONDS, 7); + + TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 0, 200); + TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, -200, 100); + TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, -1, 0); + TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 0, 122); + TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, -122, 100); + TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 1, 100); + TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, INT_MIN, INT_MAX); + TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, INT_MIN, INT_MAX); + TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 0, 200); + TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, -200, 100); + TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, -1, 0); + TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 0, 122); + TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, -122, 100); + TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 1, 100); + TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, INT_MIN, INT_MAX); + TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_TIMELEN | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, INT_MIN, INT_MAX); + + TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, 0, 200); + TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, -200, 100); + TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, -1, 0); + TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, 0, 122); + TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, -122, 100); + TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, 1, 100); + TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, INT_MIN, INT_MAX); + TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_IN_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, INT_MIN, INT_MAX); + TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, 0, 200); + TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, -200, 100); + TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, -1, 0); + TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, 0, 122); + TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, -122, 100); + TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, 1, 100); + TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, INT_MIN, INT_MAX); + TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_TIMELEN | PARSE_DEFAULT | PARSE_OUT_RANGE, &timelen_val, TIMELEN_MILLISECONDS, 7, INT_MIN, INT_MAX); + /* double testing */ TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_DOUBLE, &double_val); TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE, &double_val); @@ -1281,6 +1344,10 @@ struct test_item { ); int32_t intopt; uint32_t uintopt; + int timelenopt1; + int timelenopt2; + int timelenopt3; + int timelenopt4; unsigned int flags; double doubleopt; struct ast_sockaddr sockaddropt; @@ -1435,6 +1502,8 @@ AST_TEST_DEFINE(config_options_test) #define INT_CONFIG "-1" #define UINT_DEFAULT "2" #define UINT_CONFIG "1" +#define TIMELEN_DEFAULT "2" +#define TIMELEN_CONFIG "1" #define DOUBLE_DEFAULT "1.1" #define DOUBLE_CONFIG "0.1" #define SOCKADDR_DEFAULT "4.3.2.1:4321" @@ -1469,6 +1538,10 @@ AST_TEST_DEFINE(config_options_test) /* Register all options */ aco_option_register(&cfg_info, "intopt", ACO_EXACT, config_test_conf.types, INT_DEFAULT, OPT_INT_T, 0, FLDSET(struct test_item, intopt)); aco_option_register(&cfg_info, "uintopt", ACO_EXACT, config_test_conf.types, UINT_DEFAULT, OPT_UINT_T, 0, FLDSET(struct test_item, uintopt)); + aco_option_register(&cfg_info, "timelenopt1", ACO_EXACT, config_test_conf.types, TIMELEN_DEFAULT, OPT_TIMELEN_T, 0, FLDSET(struct test_item, timelenopt1), TIMELEN_MILLISECONDS); + aco_option_register(&cfg_info, "timelenopt2", ACO_EXACT, config_test_conf.types, TIMELEN_DEFAULT, OPT_TIMELEN_T, 0, FLDSET(struct test_item, timelenopt2), TIMELEN_SECONDS); + aco_option_register(&cfg_info, "timelenopt3", ACO_EXACT, config_test_conf.types, TIMELEN_DEFAULT, OPT_TIMELEN_T, 0, FLDSET(struct test_item, timelenopt3), TIMELEN_MINUTES); + aco_option_register(&cfg_info, "timelenopt4", ACO_EXACT, config_test_conf.types, TIMELEN_DEFAULT, OPT_TIMELEN_T, 0, FLDSET(struct test_item, timelenopt4), TIMELEN_HOURS); aco_option_register(&cfg_info, "doubleopt", ACO_EXACT, config_test_conf.types, DOUBLE_DEFAULT, OPT_DOUBLE_T, 0, FLDSET(struct test_item, doubleopt)); aco_option_register(&cfg_info, "sockaddropt", ACO_EXACT, config_test_conf.types, SOCKADDR_DEFAULT, OPT_SOCKADDR_T, 0, FLDSET(struct test_item, sockaddropt)); aco_option_register(&cfg_info, "boolopt", ACO_EXACT, config_test_conf.types, BOOL_DEFAULT, OPT_BOOL_T, 1, FLDSET(struct test_item, boolopt)); @@ -1490,6 +1563,14 @@ AST_TEST_DEFINE(config_options_test) ast_parse_arg(INT_DEFAULT, PARSE_INT32, &defaults.intopt); ast_parse_arg(INT_CONFIG, PARSE_INT32, &configs.intopt); + ast_parse_arg(TIMELEN_DEFAULT, PARSE_TIMELEN, &defaults.timelenopt1, TIMELEN_MILLISECONDS); + ast_parse_arg(TIMELEN_CONFIG, PARSE_TIMELEN, &configs.timelenopt1, TIMELEN_MILLISECONDS); + ast_parse_arg(TIMELEN_DEFAULT, PARSE_TIMELEN, &defaults.timelenopt2, TIMELEN_SECONDS); + ast_parse_arg(TIMELEN_CONFIG, PARSE_TIMELEN, &configs.timelenopt2, TIMELEN_SECONDS); + ast_parse_arg(TIMELEN_DEFAULT, PARSE_TIMELEN, &defaults.timelenopt3, TIMELEN_MINUTES); + ast_parse_arg(TIMELEN_CONFIG, PARSE_TIMELEN, &configs.timelenopt3, TIMELEN_MINUTES); + ast_parse_arg(TIMELEN_DEFAULT, PARSE_TIMELEN, &defaults.timelenopt4, TIMELEN_HOURS); + ast_parse_arg(TIMELEN_CONFIG, PARSE_TIMELEN, &configs.timelenopt4, TIMELEN_HOURS); ast_parse_arg(UINT_DEFAULT, PARSE_UINT32, &defaults.uintopt); ast_parse_arg(UINT_CONFIG, PARSE_UINT32, &configs.uintopt); ast_parse_arg(DOUBLE_DEFAULT, PARSE_DOUBLE, &defaults.doubleopt); @@ -1551,6 +1632,10 @@ AST_TEST_DEFINE(config_options_test) NOT_EQUAL_FAIL(intopt, "%d"); NOT_EQUAL_FAIL(uintopt, "%u"); + NOT_EQUAL_FAIL(timelenopt1, "%d"); + NOT_EQUAL_FAIL(timelenopt2, "%d"); + NOT_EQUAL_FAIL(timelenopt3, "%d"); + NOT_EQUAL_FAIL(timelenopt4, "%d"); NOT_EQUAL_FAIL(boolopt, "%d"); NOT_EQUAL_FAIL(flags, "%u"); NOT_EQUAL_FAIL(customopt, "%d"); From 3fbb4a0a0802ebc5f4b0c054479a08c845ed5815 Mon Sep 17 00:00:00 2001 From: Rusty Newton Date: Thu, 13 Jul 2017 15:43:42 -0500 Subject: [PATCH 1374/1578] Sounds: Update for core sounds 1.6 release Added necessary lines to make the en_NZ language set selectable and to get core sounds 1.6 pulled down. ASTERISK-26807 #close ASTERISK-25816 #close ASTERISK-26274 #close Change-Id: I84e4dd4696568cc1ba318d12ac4b075461d6eed4 --- sounds/Makefile | 5 ++++- sounds/sounds.xml | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/sounds/Makefile b/sounds/Makefile index 84d0f45c049..9dfd0c61c8e 100644 --- a/sounds/Makefile +++ b/sounds/Makefile @@ -19,13 +19,14 @@ CMD_PREFIX?=@ SOUNDS_DIR:=$(DESTDIR)$(ASTDATADIR)/sounds SOUNDS_CACHE_DIR?= MOH_DIR:=$(DESTDIR)$(ASTDATADIR)/moh -CORE_SOUNDS_VERSION:=1.5 +CORE_SOUNDS_VERSION:=1.6 EXTRA_SOUNDS_VERSION:=1.5 MOH_VERSION:=2.03 SOUNDS_URL:=http://downloads.asterisk.org/pub/telephony/sounds/releases MCS:=$(subst -EN-,-en-,$(MENUSELECT_CORE_SOUNDS)) MCS:=$(subst -EN_AU-,-en_AU-,$(MCS)) MCS:=$(subst -EN_GB-,-en_GB-,$(MCS)) +MCS:=$(subst -EN_NZ-,-en_NZ-,$(MCS)) MCS:=$(subst -FR-,-fr-,$(MCS)) MCS:=$(subst -ES-,-es-,$(MCS)) MCS:=$(subst -RU-,-ru-,$(MCS)) @@ -144,6 +145,8 @@ $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,en_AU,$(CORE_SOUN $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,en_GB,$(CORE_SOUNDS_VERSION))) +$(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,en_NZ,$(CORE_SOUNDS_VERSION))) + $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,es,$(CORE_SOUNDS_VERSION))) $(eval $(call sound_format_lang_rule,$(SOUNDS_DIR),core-sounds,fr,$(CORE_SOUNDS_VERSION))) diff --git a/sounds/sounds.xml b/sounds/sounds.xml index 547be4b4ae0..2d996c57e82 100644 --- a/sounds/sounds.xml +++ b/sounds/sounds.xml @@ -81,6 +81,33 @@ core + + core + + + core + + + core + + + core + + + core + + + core + + + core + + + core + + + core + core From 7da6ddda30ab9291ec810fa88d4219145616bae8 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 10 Jul 2017 18:17:44 -0500 Subject: [PATCH 1375/1578] res_pjsip: Add "webrtc" configuration option This patch creates a new configuration option called "webrtc". When enabled it defaults and enables the following options that are needed in order for webrtc to work in Asterisk: rtcp-mux, use_avpf, ice_support, and use_received_transport=enabled media_encryption=dtls dtls_verify=fingerprint dtls_setup=actpass When "webrtc" is enabled, this patch also parses the "msid" media level attribute from an SDP. It will also appropriately add it onto the outgoing session when applicable. Lastly, when "webrtc" is enabled h264 RTCP FIR feedback frames are now sent. ASTERISK-27119 #close Change-Id: I5ec02e07c5d5b9ad86a34fdf31bf2f9da9aac6fd --- channels/chan_pjsip.c | 4 +- configs/samples/pjsip.conf.sample | 8 ++++ include/asterisk/res_pjsip.h | 20 +++++++++ include/asterisk/res_pjsip_session.h | 2 + res/res_pjsip.c | 24 +++++++++++ res/res_pjsip.exports.in | 1 + res/res_pjsip/pjsip_configuration.c | 27 +++++++++++- res/res_pjsip_sdp_rtp.c | 63 +++++++++++++++++++++++++++- res/res_pjsip_session.c | 9 ++-- 9 files changed, 151 insertions(+), 7 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 931b6083905..f009943ed9a 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1595,7 +1595,9 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi /* FIXME: Only use this for VP8. Additional work would have to be done to * fully support other video codecs */ - if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL || + (channel->session->endpoint->media.webrtc && + ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_h264) != AST_FORMAT_CMP_NOT_EQUAL)) { /* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the * RTP engine would provide a way to externally write/schedule RTCP * packets */ diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index c05938ea5fd..3c3e52a053f 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -790,6 +790,14 @@ ; (default: 1) ;max_video_streams= ; The maximum number of allowed negotiated video streams ; (default: 1) +;webrtc= ; When set to "yes" this also enables the following values that are needed + ; for webrtc: rtcp_mux, use_avpf, ice_support, and use_received_transport. + ; The following configuration settings also get defaulted as follows: + ; media_encryption=dtls + ; dtls_verify=fingerprint + ; dtls_setup=actpass + ; A dtls_cert_file and a dtls_ca_file still need to be specified. + ; Default for this option is "no" ;==========================AUTH SECTION OPTIONS========================= ;[auth] diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index d499d5514bf..cf366cbab36 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -690,6 +690,8 @@ struct ast_sip_endpoint_media_configuration { unsigned int max_video_streams; /*! Use BUNDLE */ unsigned int bundle; + /*! Enable webrtc settings and defaults */ + unsigned int webrtc; }; /*! @@ -2060,6 +2062,24 @@ int ast_sip_append_body(pjsip_tx_data *tdata, const char *body_text); */ void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size); +/*! + * \brief Create and copy a pj_str_t into a standard character buffer. + * + * pj_str_t is not NULL-terminated. Any place that expects a NULL- + * terminated string needs to have the pj_str_t copied into a separate + * buffer. + * + * Copies the pj_str_t contents into a newly allocated buffer pointed to + * by dest. NULL-terminates the buffer. + * + * \note Caller is responsible for freeing the allocated memory. + * + * \param dest [out] The destination buffer + * \param src The pj_str_t to copy + * \retval Number of characters copied or negative value on error + */ +int ast_copy_pj_str2(char **dest, const pj_str_t *src); + /*! * \brief Get the looked-up endpoint on an out-of dialog request or response * diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index eae29de0467..eae11af4348 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -105,6 +105,8 @@ struct ast_sip_session_media { int bundle_group; /*! \brief Whether this stream is currently bundled or not */ unsigned int bundled; + /*! \brief RTP/Media streams association identifier */ + char *msid; }; /*! diff --git a/res/res_pjsip.c b/res/res_pjsip.c index ee5c5fe5e90..02112113cd7 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1010,6 +1010,18 @@ underlying transport. Note that enabling bundle will also enable the rtcp_mux option. + + Defaults and enables some options that are relevant to WebRTC + + When set to "yes" this also enables the following values that are needed in + order for basic WebRTC support to work: rtcp_mux, use_avpf, ice_support, and + use_received_transport. The following configuration settings also get defaulted + as follows: + media_encryption=dtls + dtls_verify=fingerprint + dtls_setup=actpass + + Authentication type @@ -4244,6 +4256,18 @@ void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size) dest[chars_to_copy] = '\0'; } +int ast_copy_pj_str2(char **dest, const pj_str_t *src) +{ + int res = ast_asprintf(dest, "%.*s", (int)pj_strlen(src), pj_strbuf(src)); + + if (res < 0) { + *dest = NULL; + } + + return res; +} + + int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype) { pjsip_media_type compare; diff --git a/res/res_pjsip.exports.in b/res/res_pjsip.exports.in index 8b62abbfe45..4adecd419c2 100644 --- a/res/res_pjsip.exports.in +++ b/res/res_pjsip.exports.in @@ -2,6 +2,7 @@ global: LINKER_SYMBOL_PREFIXast_sip_*; LINKER_SYMBOL_PREFIXast_copy_pj_str; + LINKER_SYMBOL_PREFIXast_copy_pj_str2; LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint; local: *; diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index c60173721b9..9f9de36faa3 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1363,8 +1363,30 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o return -1; } - if (endpoint->media.bundle) { - endpoint->media.rtcp_mux = 1; + endpoint->media.rtcp_mux |= endpoint->media.bundle; + + /* + * If webrtc has been enabled then enable those attributes, and default + * some, that are needed in order for webrtc to work. + */ + endpoint->media.bundle |= endpoint->media.webrtc; + endpoint->media.rtcp_mux |= endpoint->media.webrtc; + endpoint->media.rtp.use_avpf |= endpoint->media.webrtc; + endpoint->media.rtp.ice_support |= endpoint->media.webrtc; + endpoint->media.rtp.use_received_transport |= endpoint->media.webrtc; + + if (endpoint->media.webrtc) { + endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS; + endpoint->media.rtp.dtls_cfg.enabled = 1; + endpoint->media.rtp.dtls_cfg.default_setup = AST_RTP_DTLS_SETUP_ACTPASS; + endpoint->media.rtp.dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT; + + if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile) || + (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.cafile))) { + ast_log(LOG_ERROR, "WebRTC can't be enabled on endpoint '%s' - a DTLS cert " + "or ca file has not been specified", ast_sorcery_object_get_id(endpoint)); + return -1; + } } return 0; @@ -1990,6 +2012,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 4ec81152880..a2e7f8f9223 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1025,6 +1025,65 @@ static void process_ssrc_attributes(struct ast_sip_session *session, struct ast_ } } +static void process_msid_attribute(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, pjmedia_sdp_media *media) +{ + pjmedia_sdp_attr *attr; + + if (!session->endpoint->media.webrtc) { + return; + } + + attr = pjmedia_sdp_media_find_attr2(media, "msid", NULL); + if (attr) { + ast_free(session_media->msid); + ast_copy_pj_str2(&session_media->msid, &attr->value); + } +} + +static void add_msid_to_stream(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media) +{ + pj_str_t stmp; + pjmedia_sdp_attr *attr; + + if (!session->endpoint->media.webrtc) { + return; + } + + if (ast_strlen_zero(session_media->msid)) { + char uuid1[AST_UUID_STR_LEN], uuid2[AST_UUID_STR_LEN]; + + if (ast_asprintf(&session_media->msid, "{%s} {%s}", + ast_uuid_generate_str(uuid1, sizeof(uuid1)), + ast_uuid_generate_str(uuid2, sizeof(uuid2))) < 0) { + session_media->msid = NULL; + return; + } + } + + attr = pjmedia_sdp_attr_create(pool, "msid", pj_cstr(&stmp, session_media->msid)); + pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr); +} + +static void add_rtcp_fb_to_stream(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media) +{ + pj_str_t stmp; + pjmedia_sdp_attr *attr; + + if (!session->endpoint->media.webrtc || session_media->type != AST_MEDIA_TYPE_VIDEO) { + return; + } + + /* + * For now just automatically add it the stream even though it hasn't + * necessarily been negotiated. + */ + attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* ccm fir")); + pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr); +} + /*! \brief Function which negotiates an incoming media stream */ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, @@ -1068,7 +1127,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, } process_ssrc_attributes(session, session_media, stream); - + process_msid_attribute(session, session_media, stream); session_media_transport = ast_sip_session_media_get_transport(session, session_media); if (session_media_transport == session_media || !session_media->bundled) { @@ -1527,6 +1586,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } add_ssrc_to_stream(session, session_media, pool, media); + add_msid_to_stream(session, session_media, pool, media); + add_rtcp_fb_to_stream(session, session_media, pool, media); /* Add the media stream to the SDP */ sdp->media[sdp->media_count++] = media; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 315db6df5db..fe3680f3b78 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -395,6 +395,7 @@ static void session_media_dtor(void *obj) } ast_free(session_media->mid); + ast_free(session_media->msid); } struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session, @@ -3573,15 +3574,17 @@ static int add_bundle_groups(struct ast_sip_session *session, pj_pool_t *pool, p int index, mid_id; struct sip_session_media_bundle_group *bundle_group; + if (session->endpoint->media.webrtc) { + attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *")); + pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr); + } + if (!session->endpoint->media.bundle) { return 0; } memset(bundle_groups, 0, sizeof(bundle_groups)); - attr = pjmedia_sdp_attr_create(pool, "msid-semantic", pj_cstr(&stmp, "WMS *")); - pjmedia_sdp_attr_add(&answer->attr_count, answer->attr, attr); - /* Build the bundle group layout so we can then add it to the SDP */ for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) { struct ast_sip_session_media *session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index); From d3f5b265c77760351cfa1892b14e386c3d362b9b Mon Sep 17 00:00:00 2001 From: Sergej Kasumovic Date: Fri, 14 Jul 2017 08:11:50 +0200 Subject: [PATCH 1376/1578] chan_iax2: On reload make sure to check for existing MWI subscription On every reload of chan_iax2 module, MWI subscription was added, which results in additional taskprocessors being accumulated over time. This commit fixes it by making sure we check for existing subscription first. This was verified with 'core show taskprocessors' CLI command. ASTERISK-27122 #close Change-Id: Ie2ef528fd5ca01b933eeb88188cc10967899cfb9 --- channels/chan_iax2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index f40873e9dcb..5abb6c37fb1 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -13055,7 +13055,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st ast_free_acl_list(oldacl); } - if (!ast_strlen_zero(peer->mailbox)) { + if (!ast_strlen_zero(peer->mailbox) && !peer->mwi_event_sub) { struct stasis_topic *mailbox_specific_topic; mailbox_specific_topic = ast_mwi_topic(peer->mailbox); From 26f149ab0ac3ad62fa79bc406f0f9e5ba5591bba Mon Sep 17 00:00:00 2001 From: Sergej Kasumovic Date: Fri, 14 Jul 2017 08:25:36 +0200 Subject: [PATCH 1377/1578] app_confbridge: Make sure name recordings are always removed from the filesystem This commit fixes two possible scenarios: * When recording name and if during recording you hangup, file is never removed. This is due to the fact file location is nulled. * When recording name and if you hangup during thank-you prompt, file is never removed. ASTERISK-27123 #close Change-Id: I39b7271408b4b54ce880c5111a886aa8f28c2625 --- apps/app_confbridge.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 0f846b659d9..c6372fa2fbf 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -2145,6 +2145,7 @@ static int conf_rec_name(struct confbridge_user *user, const char *conf_name) } if (res == -1) { + ast_filedelete(user->name_rec_location, NULL); user->name_rec_location[0] = '\0'; return -1; } @@ -2236,6 +2237,7 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) { int res = 0, volume_adjustments[2]; int quiet = 0; + int async_delete_task_pushed = 0; char *parse; const char *b_profile_name = NULL; const char *u_profile_name = NULL; @@ -2481,6 +2483,7 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) async_play_sound_file(conference, conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds), NULL); async_delete_name_rec(conference, user.name_rec_location); + async_delete_task_pushed = 1; } /* play the leave sound */ @@ -2509,6 +2512,9 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) } confbridge_cleanup: + if (!async_delete_task_pushed && !ast_strlen_zero(user.name_rec_location)) { + ast_filedelete(user.name_rec_location, NULL); + } ast_bridge_features_cleanup(&user.features); conf_bridge_profile_destroy(&user.b_profile); return res; From 942ee54b53a68d4eec4463f8be8735d2f8edb580 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 16 Jul 2017 17:18:39 +0000 Subject: [PATCH 1378/1578] res_rtp_asterisk: Use RTP component for ICE if RTCP-MUX is in use. This change makes it so that if an RTCP packet is being sent the RTP ICE component is used for sending if RTCP-MUX is in use. ASTERISK-27133 Change-Id: I6200f611ede709602ee9b89501720c29545ed68b --- res/res_rtp_asterisk.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 9d3969fbe30..a2e63ec0bec 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2650,9 +2650,15 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz #ifdef HAVE_PJPROJECT if (transport_rtp->ice) { + enum ast_rtp_ice_component_type component = rtcp ? AST_RTP_ICE_COMPONENT_RTCP : AST_RTP_ICE_COMPONENT_RTP; pj_status_t status; struct ice_wrap *ice; + /* If RTCP is sharing the same socket then use the same component */ + if (rtcp && rtp->rtcp->s == rtp->s) { + component = AST_RTP_ICE_COMPONENT_RTP; + } + pj_thread_register_check(); /* Release the instance lock to avoid deadlock with PJPROJECT group lock */ @@ -2661,8 +2667,7 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz if (instance == transport) { ao2_unlock(instance); } - status = pj_ice_sess_send_data(ice->real_ice, - rtcp ? AST_RTP_ICE_COMPONENT_RTCP : AST_RTP_ICE_COMPONENT_RTP, temp, len); + status = pj_ice_sess_send_data(ice->real_ice, component, temp, len); ao2_ref(ice, -1); if (instance == transport) { ao2_lock(instance); From f48695ce5bde836691e1b46350c22f1de21de5d9 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 16 Jul 2017 17:31:35 +0000 Subject: [PATCH 1379/1578] bridge_softmix: Use removed stream spots when renegotiating. Streams are never truly removed in SDP, they still occupy a location within the SDP. This location can be reused by another stream if it so chooses. This change takes advantage of this such that if a new stream is needing to be added for a new participant any removed streams are instead replaced first. This reduces the size of the SDP and the number of streams. ASTERISK-27134 Change-Id: I95cdcfd55cf47e02ea52abb5d94008db3fb68b1d --- bridges/bridge_softmix.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index ae877eb6e3c..3801ccbec2a 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -524,15 +524,32 @@ static int append_all_streams(struct ast_stream_topology *dest, const struct ast_stream_topology *source) { int i; + int dest_index = 0; for (i = 0; i < ast_stream_topology_get_count(source); ++i) { struct ast_stream *clone; + int added = 0; clone = ast_stream_clone(ast_stream_topology_get_stream(source, i), NULL); if (!clone) { return -1; } - if (ast_stream_topology_append_stream(dest, clone) < 0) { + + /* If we can reuse an existing removed stream then do so */ + while (dest_index < ast_stream_topology_get_count(dest)) { + struct ast_stream *stream = ast_stream_topology_get_stream(dest, dest_index); + + dest_index++; + + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + ast_stream_topology_set_stream(dest, dest_index - 1, clone); + added = 1; + break; + } + } + + /* If no removed stream exists that we took the place of append the stream */ + if (!added && ast_stream_topology_append_stream(dest, clone) < 0) { ast_stream_free(clone); return -1; } From bcd3f65174ace4993c2f76095166b7a2110916a9 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 17 Jul 2017 12:19:59 +0000 Subject: [PATCH 1380/1578] bridge_softmix: Don't reorder streams on participant leaving. When a participant leaves a bridge while operating in SFU mode their respective stream on every other participant needs to be removed. Leaving the stream out of the new topology results in every stream after it being moved and reordered. This causes problems with clients. Instead simply mark the stream as removed which leaves it in place in the SDP and doesn't reorder or touch any other streams. ASTERISK-27136 Change-Id: I4b3f840adcdf69b83842b0d8a737665ba0ef9cb1 --- bridges/bridge_softmix.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index ae877eb6e3c..9aa8a7a8a27 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -701,14 +701,15 @@ static int remove_destination_streams(struct ast_stream_topology *dest, stream = ast_stream_topology_get_stream(source, i); - if (is_video_dest(stream, channel_name, NULL)) { - continue; - } - stream_clone = ast_stream_clone(stream, NULL); if (!stream_clone) { continue; } + + if (is_video_dest(stream, channel_name, NULL)) { + ast_stream_set_state(stream_clone, AST_STREAM_STATE_REMOVED); + } + if (ast_stream_topology_append_stream(dest, stream_clone) < 0) { ast_stream_free(stream_clone); } @@ -1964,9 +1965,9 @@ AST_TEST_DEFINE(sfu_remove_destination_streams) int num_streams; int params_index[4]; } removal_results[] = { - { "PJSIP/Bob-00000001", 3, { 0, 1, 3, -1 }, }, + { "PJSIP/Bob-00000001", 4, { 0, 1, 2, 3 }, }, { "PJSIP/Edward-00000004", 4, { 0, 1, 2, 3 }, }, - { "", 2, { 0, 1, -1, -1 }, }, + { "", 4, { 0, 1, 2, 3 }, }, }; struct ast_stream_topology *orig = NULL; struct ast_stream_topology *result = NULL; @@ -2033,6 +2034,12 @@ AST_TEST_DEFINE(sfu_remove_destination_streams) ast_format_cap_get_names(ast_stream_get_formats(actual), &actual_str)); goto end; } + + if (is_video_dest(actual, removal_results[i].channel_name, NULL) && + ast_stream_get_state(actual) != AST_STREAM_STATE_REMOVED) { + ast_test_status_update(test, "Removed stream %s does not have a state of removed\n", ast_stream_get_name(actual)); + goto end; + } } } From e7d9e42616975b594f7ad45baeb4305a61fa6dd0 Mon Sep 17 00:00:00 2001 From: Benjamin Keith Ford Date: Tue, 18 Jul 2017 15:04:44 -0500 Subject: [PATCH 1381/1578] pjsip: Increase maximum packet size. The maximum packet size for PJSIP has been increased to handle the multiple streams being added for WebRTC. Change-Id: I9ea1e8d02668c544acadcb1c6200e1cc1bd588b3 --- third-party/pjproject/patches/config_site.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h index a345734b0f8..561b3a231f1 100644 --- a/third-party/pjproject/patches/config_site.h +++ b/third-party/pjproject/patches/config_site.h @@ -68,7 +68,7 @@ Enabling it will result in SEGFAULTS when URIs containing escape sequences are encountered. */ #undef PJSIP_UNESCAPE_IN_PLACE -#define PJSIP_MAX_PKT_LEN 6000 +#define PJSIP_MAX_PKT_LEN 32000 #undef PJ_TODO #define PJ_TODO(x) From 680c491a6238274132bff3608ae17b1371c2af2a Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 17 Jul 2017 16:01:24 +0000 Subject: [PATCH 1382/1578] bridge_softmix / res_rtp_asterisk: Fix packet loss and renegotiation issues. This change does a few things to improve packet loss and renegotiation: 1. On outgoing RTP streams we will now properly reflect out of order packets and packet loss in the sequence number. This allows the remote jitterbuffer to better reorder things. 2. Video updates can now be discarded for a period of time after one has been sent to prevent flooding of clients. 3. For declined and removed streams we will now release any media session resources associated with them. This was not previously done and caused an issue where old state was being used for a new stream. 4. RTP bundling was not actually removing bundled RTP instances from the parent. This has been resolved by removing based on the RTP instance itself and not the SSRC. 5. The code did not properly handle explicitly unbundling an RTP instance from its parent. This now works as expected. ASTERISK-27143 Change-Id: Ibd91362f0e4990b6129638e712bc8adf0899fd45 --- apps/app_confbridge.c | 1 + apps/confbridge/conf_config_parser.c | 13 ++++ apps/confbridge/include/confbridge.h | 1 + bridges/bridge_softmix.c | 8 ++- .../include/bridge_softmix_internal.h | 2 + configs/samples/confbridge.conf.sample | 6 ++ include/asterisk/bridge.h | 9 +++ include/asterisk/frame.h | 2 + main/bridge.c | 7 +++ main/rtp_engine.c | 2 +- res/res_pjsip_session.c | 6 ++ res/res_rtp_asterisk.c | 60 ++++++++++++++++--- 12 files changed, 108 insertions(+), 9 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index c6372fa2fbf..b2d612df3b5 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1485,6 +1485,7 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen ast_bridge_set_talker_src_video_mode(conference->bridge); } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_SFU)) { ast_bridge_set_sfu_video_mode(conference->bridge); + ast_bridge_set_video_update_discard(conference->bridge, conference->b_profile.video_update_discard); } /* Link it into the conference bridges container */ diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index cc8fcfe5df4..bfd9f4f5697 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -450,6 +450,16 @@ + + Sets the amount of time in milliseconds after sending a video update to discard subsequent video updates + + Sets the amount of time in milliseconds after sending a video update request + that subsequent video updates should be discarded. This means that if we + send a video update we will discard any other video update requests until + after the configured amount of time has elapsed. This prevents flooding of + video update requests from clients. + + When using the CONFBRIDGE dialplan function, use a bridge profile as a template for creating a new temporary profile @@ -1652,6 +1662,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, break; } + ast_cli(a->fd,"Video Update Discard: %u\n", b_profile.video_update_discard); + ast_cli(a->fd,"sound_only_person: %s\n", conf_get_sound(CONF_SOUND_ONLY_PERSON, b_profile.sounds)); ast_cli(a->fd,"sound_only_one: %s\n", conf_get_sound(CONF_SOUND_ONLY_ONE, b_profile.sounds)); ast_cli(a->fd,"sound_has_joined: %s\n", conf_get_sound(CONF_SOUND_HAS_JOINED, b_profile.sounds)); @@ -2220,6 +2232,7 @@ int conf_load_config(void) aco_option_register(&cfg_info, "regcontext", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, regcontext)); aco_option_register(&cfg_info, "language", ACO_EXACT, bridge_types, "en", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, language)); aco_option_register_custom(&cfg_info, "^sound_", ACO_REGEX, bridge_types, NULL, sound_option_handler, 0); + aco_option_register(&cfg_info, "video_update_discard", ACO_EXACT, bridge_types, "2000", OPT_UINT_T, 0, FLDSET(struct bridge_profile, video_update_discard)); /* This option should only be used with the CONFBRIDGE dialplan function */ aco_option_register_custom(&cfg_info, "template", ACO_EXACT, bridge_types, NULL, bridge_template_handler, 0); diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index cf30d5c6270..adf9b867d69 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -218,6 +218,7 @@ struct bridge_profile { unsigned int mix_interval; /*!< The internal mixing interval used by the bridge. When set to 0 the bridgewill use a default interval. */ struct bridge_profile_sounds *sounds; char regcontext[AST_MAX_CONTEXT]; + unsigned int video_update_discard; /*!< Amount of time after sending a video update request that subsequent requests should be discarded */ }; /*! \brief The structure that represents a conference bridge */ diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 3dd26603e4e..132ff08224f 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -968,6 +968,8 @@ static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bri */ static int softmix_bridge_write_control(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { + struct softmix_bridge_data *softmix_data = bridge->tech_pvt; + /* * XXX Softmix needs to use channel roles to determine what to * do with control frames. @@ -975,7 +977,11 @@ static int softmix_bridge_write_control(struct ast_bridge *bridge, struct ast_br switch (frame->subclass.integer) { case AST_CONTROL_VIDUPDATE: - ast_bridge_queue_everyone_else(bridge, NULL, frame); + if (!bridge->softmix.video_mode.video_update_discard || + ast_tvdiff_ms(ast_tvnow(), softmix_data->last_video_update) > bridge->softmix.video_mode.video_update_discard) { + ast_bridge_queue_everyone_else(bridge, NULL, frame); + softmix_data->last_video_update = ast_tvnow(); + } break; default: break; diff --git a/bridges/bridge_softmix/include/bridge_softmix_internal.h b/bridges/bridge_softmix/include/bridge_softmix_internal.h index 9daae4ce8a0..f93e6639159 100644 --- a/bridges/bridge_softmix/include/bridge_softmix_internal.h +++ b/bridges/bridge_softmix/include/bridge_softmix_internal.h @@ -198,6 +198,8 @@ struct softmix_bridge_data { * (does not guarantee success) */ unsigned int binaural_init; + /*! The last time a video update was sent into the bridge */ + struct timeval last_video_update; }; struct softmix_mixing_array { diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index 0e07f6b16df..265b95342aa 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -218,6 +218,12 @@ type=bridge ; Default is en (English). ;regcontext=conferences ; The name of the context into which to register conference names as extensions. +;video_update_discard=2000 ; Amount of time (in milliseconds) to discard video update requests after sending a video + ; update request. Default is 2000. A video update request is a request for a full video + ; intra-frame. Clients can request this if they require a full frame in order to decode + ; the video stream. Since a full frame can be large limiting how often they occur can + ; reduce bandwidth usage at the cost of increasing how long it may take a newly joined + ; channel to receive the video stream. ; All sounds in the conference are customizable using the bridge profile options below. ; Simply state the option followed by the filename or full path of the filename after diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index bc0e9c81e08..8d5c502113e 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -134,6 +134,7 @@ struct ast_bridge_video_mode { struct ast_bridge_video_single_src_data single_src_data; struct ast_bridge_video_talker_src_data talker_src_data; } mode_data; + unsigned int video_update_discard; }; /*! @@ -902,6 +903,14 @@ void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge); */ void ast_bridge_set_sfu_video_mode(struct ast_bridge *bridge); +/*! + * \brief Set the amount of time to discard subsequent video updates after a video update has been sent + * + * \param bridge Bridge to set the minimum video update wait time on + * \param video_update_discard Amount of time after sending a video update that others should be discarded + */ +void ast_bridge_set_video_update_discard(struct ast_bridge *bridge, unsigned int video_update_discard); + /*! * \brief Update information about talker energy for talker src video mode. */ diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 2f6c365ad4b..8f0daccb702 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -137,6 +137,8 @@ enum { AST_FRFLAG_HAS_TIMING_INFO = (1 << 0), /*! This frame has been requeued */ AST_FRFLAG_REQUEUED = (1 << 1), + /*! This frame contains a valid sequence number */ + AST_FRFLAG_HAS_SEQUENCE_NUMBER = (1 << 2), }; struct ast_frame_subclass { diff --git a/main/bridge.c b/main/bridge.c index 3a358d9f8ec..a1a1a6f5599 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -3816,6 +3816,13 @@ void ast_bridge_set_sfu_video_mode(struct ast_bridge *bridge) ast_bridge_unlock(bridge); } +void ast_bridge_set_video_update_discard(struct ast_bridge *bridge, unsigned int video_update_discard) +{ + ast_bridge_lock(bridge); + bridge->softmix.video_mode.video_update_discard = video_update_discard; + ast_bridge_unlock(bridge); +} + void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe) { struct ast_bridge_video_talker_src_data *data; diff --git a/main/rtp_engine.c b/main/rtp_engine.c index abd4b1fcfca..64b2b317b5d 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -3384,7 +3384,7 @@ int ast_rtp_instance_bundle(struct ast_rtp_instance *child, struct ast_rtp_insta { int res = -1; - if (child->engine != parent->engine) { + if (parent && (child->engine != parent->engine)) { return -1; } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index fe3680f3b78..0ad2c8f30ac 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -785,6 +785,12 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ * we remove it as a result of the stream limit being reached. */ if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + /* This stream is no longer being used so release any resources the handler + * may have on it. + */ + if (session_media->handler) { + session_media_set_handler(session_media, NULL); + } continue; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index a2e63ec0bec..70561d0b6da 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -266,7 +266,8 @@ struct ast_rtp { unsigned int lastitexttimestamp; unsigned int lastotexttimestamp; unsigned int lasteventseqn; - int lastrxseqno; /*!< Last received sequence number */ + int lastrxseqno; /*!< Last received sequence number, from the network */ + int expectedseqno; /*!< Next expected sequence number, from the core */ unsigned short seedrxseqno; /*!< What sequence number did they start with?*/ unsigned int seedrxts; /*!< What RTP timestamp did they start with? */ unsigned int rxcount; /*!< How many packets have we received? */ @@ -3245,6 +3246,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, rtp->ssrc = ast_random(); ast_uuid_generate_str(rtp->cname, sizeof(rtp->cname)); rtp->seqno = ast_random() & 0x7fff; + rtp->expectedseqno = -1; rtp->sched = sched; ast_sockaddr_copy(&rtp->bind_address, addr); @@ -3274,7 +3276,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, * \return 0 if element does not match. * \return Non-zero if element matches. */ -#define SSRC_MAPPING_ELEM_CMP(elem, value) ((elem).ssrc == (value)) +#define SSRC_MAPPING_ELEM_CMP(elem, value) (elem.instance == value) /*! \pre instance is locked */ static int ast_rtp_destroy(struct ast_rtp_instance *instance) @@ -3289,7 +3291,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) ao2_lock(rtp->bundled); bundled_rtp = ast_rtp_instance_get_data(rtp->bundled); - AST_VECTOR_REMOVE_CMP_UNORDERED(&bundled_rtp->ssrc_mapping, rtp->themssrc, SSRC_MAPPING_ELEM_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP); + AST_VECTOR_REMOVE_CMP_UNORDERED(&bundled_rtp->ssrc_mapping, instance, SSRC_MAPPING_ELEM_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP); ao2_unlock(rtp->bundled); ao2_lock(instance); @@ -3897,6 +3899,7 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr unsigned int ms = calc_txstamp(rtp, &frame->delivery); struct ast_sockaddr remote_address = { {0,} }; int rate = rtp_get_rate(frame->subclass.format) / 1000; + unsigned int seqno; if (ast_format_cmp(frame->subclass.format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) { frame->samples /= 2; @@ -3963,6 +3966,40 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr rtp->lastdigitts = rtp->lastts; } + /* Assume that the sequence number we expect to use is what will be used until proven otherwise */ + seqno = rtp->seqno; + + /* If the frame contains sequence number information use it to influence our sequence number */ + if (ast_test_flag(frame, AST_FRFLAG_HAS_SEQUENCE_NUMBER)) { + if (rtp->expectedseqno != -1) { + /* Determine where the frame from the core is in relation to where we expected */ + int difference = frame->seqno - rtp->expectedseqno; + + /* If there is a substantial difference then we've either got packets really out + * of order, or the source is RTP and it has cycled. If this happens we resync + * the sequence number adjustments to this frame. If we also have packet loss + * things won't be reflected correctly but it will sort itself out after a bit. + */ + if (abs(difference) > 100) { + difference = 0; + } + + /* Adjust the sequence number being used for this packet accordingly */ + seqno += difference; + + if (difference >= 0) { + /* This frame is on time or in the future */ + rtp->expectedseqno = frame->seqno + 1; + rtp->seqno += difference; + } + } else { + /* This is the first frame with sequence number we've seen, so start keeping track */ + rtp->expectedseqno = frame->seqno + 1; + } + } else { + rtp->expectedseqno = -1; + } + if (ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO)) { rtp->lastts = frame->ts * rate; } @@ -3974,7 +4011,7 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr int hdrlen = 12, res, ice; unsigned char *rtpheader = (unsigned char *)(frame->data.ptr - hdrlen); - put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (rtp->seqno) | (mark << 23))); + put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (seqno) | (mark << 23))); put_unaligned_uint32(rtpheader + 4, htonl(rtp->lastts)); put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc)); @@ -4011,7 +4048,13 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr } } - rtp->seqno++; + /* If the sequence number that has been used doesn't match what we expected then this is an out of + * order late packet, so we don't need to increment as we haven't yet gotten the expected frame from + * the core. + */ + if (seqno == rtp->seqno) { + rtp->seqno++; + } return 0; } @@ -5474,6 +5517,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->f.datalen = res - hdrlen; rtp->f.data.ptr = read_area + hdrlen; rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET; + ast_set_flag(&rtp->f, AST_FRFLAG_HAS_SEQUENCE_NUMBER); rtp->f.seqno = seqno; rtp->f.stream_num = rtp->stream_num; @@ -6082,7 +6126,7 @@ static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent) { struct ast_rtp *child_rtp = ast_rtp_instance_get_data(child); - struct ast_rtp *parent_rtp = ast_rtp_instance_get_data(parent); + struct ast_rtp *parent_rtp; struct rtp_ssrc_mapping mapping; struct ast_sockaddr them = { { 0, } }; @@ -6099,7 +6143,7 @@ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instanc /* The child lock can't be held while accessing the parent */ ao2_lock(child_rtp->bundled); bundled_rtp = ast_rtp_instance_get_data(child_rtp->bundled); - AST_VECTOR_REMOVE_CMP_UNORDERED(&bundled_rtp->ssrc_mapping, child_rtp->themssrc, SSRC_MAPPING_ELEM_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP); + AST_VECTOR_REMOVE_CMP_UNORDERED(&bundled_rtp->ssrc_mapping, child, SSRC_MAPPING_ELEM_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP); ao2_unlock(child_rtp->bundled); ao2_lock(child); @@ -6113,6 +6157,8 @@ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instanc return 0; } + parent_rtp = ast_rtp_instance_get_data(parent); + /* We no longer need any transport related resources as we will use our parent RTP instance instead */ rtp_deallocate_transport(child, child_rtp); From 25c9464325af5b7e91cd6c46dc9977c8debe97a9 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 20 Jul 2017 10:57:08 -0400 Subject: [PATCH 1383/1578] corosync: Fix corosync library name in configure.ac Also add new corosync packages to install_prereq. Reported by Travis Ryan in #asterisk-dev Change-Id: Ib861c95ba630fed62dc54e56784ad8446ed9d2db --- configure | 28 ++++++++++++++++++++-------- configure.ac | 2 +- contrib/scripts/install_prereq | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 1808633f426..5bb75236bd3 100755 --- a/configure +++ b/configure @@ -1356,6 +1356,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -1540,6 +1541,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1792,6 +1794,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1929,7 +1940,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2082,6 +2093,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -14915,7 +14927,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14961,7 +14973,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14985,7 +14997,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15030,7 +15042,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15054,7 +15066,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -31910,7 +31922,7 @@ if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lcpg ${pbxlibdir} -lcfg $LIBS" +LIBS="-lcpg ${pbxlibdir} -lcpg $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -31952,7 +31964,7 @@ fi # now check for the header. if test "${AST_COROSYNC_FOUND}" = "yes"; then - COROSYNC_LIB="${pbxlibdir} -lcpg -lcfg" + COROSYNC_LIB="${pbxlibdir} -lcpg -lcpg" # if --with-COROSYNC=DIR has been specified, use it. if test "x${COROSYNC_DIR}" != "x"; then COROSYNC_INCLUDE="-I${COROSYNC_DIR}/include" diff --git a/configure.ac b/configure.ac index ecbe870936e..a2eaab4ada8 100644 --- a/configure.ac +++ b/configure.ac @@ -2414,7 +2414,7 @@ fi AST_EXT_LIB_CHECK([CODEC2], [codec2], [codec2_create], [codec2/codec2.h]) -AST_EXT_LIB_CHECK([COROSYNC], [cpg], [cpg_join], [corosync/cpg.h], [-lcfg]) +AST_EXT_LIB_CHECK([COROSYNC], [cpg], [cpg_join], [corosync/cpg.h], [-lcpg]) AST_EXT_LIB_CHECK([COROSYNC_CFG_STATE_TRACK], [cfg], [corosync_cfg_state_track], [corosync/cfg.h], [-lcfg]) AST_EXT_LIB_CHECK([SPEEX], [speex], [speex_encode], [speex/speex.h], [-lm]) diff --git a/contrib/scripts/install_prereq b/contrib/scripts/install_prereq index fb240890bb4..d69f5527a7f 100755 --- a/contrib/scripts/install_prereq +++ b/contrib/scripts/install_prereq @@ -26,7 +26,7 @@ PACKAGES_DEBIAN="$PACKAGES_DEBIAN libncurses-dev libz-dev libssl-dev libxml2-dev PACKAGES_DEBIAN="$PACKAGES_DEBIAN libcurl-dev libspeex-dev libspeexdsp-dev libogg-dev libvorbis-dev libasound2-dev portaudio19-dev libcurl4-openssl-dev" PACKAGES_DEBIAN="$PACKAGES_DEBIAN libpq-dev unixodbc-dev libsqlite0-dev libmysqlclient15-dev libneon27-dev libgmime-dev libusb-dev liblua5.1-0-dev lua5.1" PACKAGES_DEBIAN="$PACKAGES_DEBIAN libopenh323-dev libvpb-dev libgtk2.0-dev libmysqlclient-dev libbluetooth-dev libradiusclient-ng-dev freetds-dev" -PACKAGES_DEBIAN="$PACKAGES_DEBIAN libsnmp-dev libiksemel-dev libcorosync-dev libnewt-dev libpopt-dev libical-dev libspandsp-dev libjack-dev" +PACKAGES_DEBIAN="$PACKAGES_DEBIAN libsnmp-dev libiksemel-dev libcorosync-dev libcpg-dev libcfg-dev libnewt-dev libpopt-dev libical-dev libspandsp-dev libjack-dev" PACKAGES_DEBIAN="$PACKAGES_DEBIAN libresample-dev libc-client-dev binutils-dev libsrtp-dev libgsm1-dev libedit-dev doxygen libjansson-dev libldap-dev" PACKAGES_DEBIAN="$PACKAGES_DEBIAN subversion git libxslt1-dev automake libsrtp-dev libncurses5-dev python-dev" PACKAGES_RH="automake bzip2 gcc gcc-c++ patch ncurses-devel openssl-devel libxml2-devel unixODBC-devel libcurl-devel libogg-devel libvorbis-devel speex-devel" From 3e8d628c0e3da7a75e4187c6369b873758d53353 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 20 Jul 2017 09:52:38 -0600 Subject: [PATCH 1384/1578] Update AMI and ARI versions for master/15 and update UPDATE.txt AMI goes from 3.2.0 to 4.0.0 ARI goes from 2.0.0 to 3.0.0 Copied UPGRADE.txt -> UPGRADE-15.txt Created new UPGRADE.txt Removed a log file that was accidentally checked in a while ago Change-Id: I1c794f910038459b13e16f9c3a12c44e56f142f7 --- UPGRADE-15.txt | 85 ++++ UPGRADE.txt | 61 +-- contrib/scripts/spandspflow2pcap.log | 605 --------------------------- include/asterisk/manager.h | 2 +- rest-api/resources.json | 2 +- 5 files changed, 88 insertions(+), 667 deletions(-) create mode 100644 UPGRADE-15.txt delete mode 100644 contrib/scripts/spandspflow2pcap.log diff --git a/UPGRADE-15.txt b/UPGRADE-15.txt new file mode 100644 index 00000000000..4ebe400a6d3 --- /dev/null +++ b/UPGRADE-15.txt @@ -0,0 +1,85 @@ +=========================================================== +=== +=== Information for upgrading between Asterisk versions +=== +=== These files document all the changes that MUST be taken +=== into account when upgrading between the Asterisk +=== versions listed below. These changes may require that +=== you modify your configuration files, dialplan or (in +=== some cases) source code if you have your own Asterisk +=== modules or patches. These files also include advance +=== notice of any functionality that has been marked as +=== 'deprecated' and may be removed in a future release, +=== along with the suggested replacement functionality. +=== +=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2 +=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4 +=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6 +=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8 +=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10 +=== UPGRADE-11.txt -- Upgrade info for 10 to 11 +=== UPGRADE-12.txt -- Upgrade info for 11 to 12 +=== UPGRADE-13.txt -- Upgrade info for 12 to 13 +=== UPGRADE-14.txt -- Upgrade info for 13 to 14 +=== UPGRADE-15.txt -- Upgrade info for 14 to 15 +=========================================================== + +New in 15.0.0: + +Core: + - The 'Data Retrieval API' has been removed. This API was not actively + maintained, was not added to new modules (such as res_pjsip), and there + exist better alternatives to acquire the same information, such as the + ARI. As a result, the 'DataGet' AMI action as well as the 'data get' + CLI command have been removed. + +From 14.6.0 to 14.7.0: + +Core: + - ast_app_parse_timelen now returns an error if it encounters extra characters + at the end of the string to be parsed. + +From 14.4.0 to 14.5.0: + +Core: + - Support for embedded modules has been removed. This has not worked in + many years. LOADABLE_MODULES menuselect option is also removed as + loadable module support is now always enabled. + +From 14.3.0 to 14.4.0: + +res_rtp_asterisk: + - The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP + Data and Control Packets on a Single Port." For the PJSIP channel driver, + chan_pjsip, you can set "rtcp_mux = yes" on a PJSIP endpoint in pjsip.conf + to enable the feature. For chan_sip you can set "rtcp_mux = yes" either + globally or on a per-peer basis in sip.conf. + +New in 14.0.0 + +ARI: + - The policy for when to send "Dial" events has changed. Previously, "Dial" + events were sent on the calling channel's topic. However, starting in Asterisk + 14, if there is no calling channel on which to send the event, the event is + instead sent on the called channel's topic. Note that for the ARI channels + resource's dial operation, this means that the "Dial" events will always be + sent on the called channel's topic. + +Queue: + - When reloading the members of a queue, the members added dynamically (i.e. + added via the CLI command "queue add" or the AMI action "QueueAdd") now have + their ringinuse value updated to the value of the queue. Previously, the + ringinuse value for dynamic members was not updated on reload. + +Queue log: + - New RINGCANCELED event is logged when the caller hangs up while ringing. + The data1 field contains number of miliseconds since start of ringing. + +Channel Drivers: + +chan_dahdi: + - Support for specifying a DAHDI channel using a path under /dev/dahdi + ("by name") has been removed. It was never used. Instead you should + use kernel-level channel number allocation using span assignments. + See the documentation of dahdi-linux and dahdi-tools. + diff --git a/UPGRADE.txt b/UPGRADE.txt index 6bb74449e93..87eabde2dae 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -21,64 +21,5 @@ === UPGRADE-12.txt -- Upgrade info for 11 to 12 === UPGRADE-13.txt -- Upgrade info for 12 to 13 === UPGRADE-14.txt -- Upgrade info for 13 to 14 +=== UPGRADE-15.txt -- Upgrade info for 14 to 15 =========================================================== - -New in 15.0.0: - -Core: - - The 'Data Retrieval API' has been removed. This API was not actively - maintained, was not added to new modules (such as res_pjsip), and there - exist better alternatives to acquire the same information, such as the - ARI. As a result, the 'DataGet' AMI action as well as the 'data get' - CLI command have been removed. - -From 14.6.0 to 14.7.0: - -Core: - - ast_app_parse_timelen now returns an error if it encounters extra characters - at the end of the string to be parsed. - -From 14.4.0 to 14.5.0: - -Core: - - Support for embedded modules has been removed. This has not worked in - many years. LOADABLE_MODULES menuselect option is also removed as - loadable module support is now always enabled. - -From 14.3.0 to 14.4.0: - -res_rtp_asterisk: - - The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP - Data and Control Packets on a Single Port." For the PJSIP channel driver, - chan_pjsip, you can set "rtcp_mux = yes" on a PJSIP endpoint in pjsip.conf - to enable the feature. For chan_sip you can set "rtcp_mux = yes" either - globally or on a per-peer basis in sip.conf. - -New in 14.0.0 - -ARI: - - The policy for when to send "Dial" events has changed. Previously, "Dial" - events were sent on the calling channel's topic. However, starting in Asterisk - 14, if there is no calling channel on which to send the event, the event is - instead sent on the called channel's topic. Note that for the ARI channels - resource's dial operation, this means that the "Dial" events will always be - sent on the called channel's topic. - -Queue: - - When reloading the members of a queue, the members added dynamically (i.e. - added via the CLI command "queue add" or the AMI action "QueueAdd") now have - their ringinuse value updated to the value of the queue. Previously, the - ringinuse value for dynamic members was not updated on reload. - -Queue log: - - New RINGCANCELED event is logged when the caller hangs up while ringing. - The data1 field contains number of miliseconds since start of ringing. - -Channel Drivers: - -chan_dahdi: - - Support for specifying a DAHDI channel using a path under /dev/dahdi - ("by name") has been removed. It was never used. Instead you should - use kernel-level channel number allocation using span assignments. - See the documentation of dahdi-linux and dahdi-tools. - diff --git a/contrib/scripts/spandspflow2pcap.log b/contrib/scripts/spandspflow2pcap.log deleted file mode 100644 index 7ed0ed99afd..00000000000 --- a/contrib/scripts/spandspflow2pcap.log +++ /dev/null @@ -1,605 +0,0 @@ -[2015-12-02 11:55:55] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 0: indicator no-signal -[2015-12-02 11:55:55] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 1: indicator ced -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 2: IFP 00 -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 2: indicator no-signal -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 3: IFP 06 -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 3: indicator v21-preamble -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 1 -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 1 -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_A_CED to T30_PHASE_B_RX -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4 -[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 4: IFP c0 01 80 00 00 ff -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 4: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 5: IFP c0 01 80 00 00 c0 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 5: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 6: IFP c0 01 80 00 00 c2 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 6: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 7: IFP c0 01 80 00 00 76 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 7: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 8: IFP c0 01 80 00 00 ee -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 8: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 9: IFP c0 01 80 00 00 f6 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 9: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 10: IFP c0 01 80 00 00 76 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 10: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 11: IFP c0 01 80 00 00 d6 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 11: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 12: IFP c0 01 80 00 00 76 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 12: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 13: IFP c0 01 80 00 00 ae -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 13: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 14: IFP c0 01 80 00 00 04 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 14: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 15: IFP c0 01 80 00 00 04 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 15: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 16: IFP c0 01 80 00 00 04 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 16: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 17: IFP c0 01 80 00 00 04 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 17: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 18: IFP c0 01 80 00 00 04 -[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 18: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 19: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 19: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 20: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 20: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 21: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 21: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 22: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 22: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 23: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 23: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 24: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 24: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 25: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 25: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 26: IFP c0 01 80 00 00 04 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 26: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 27: IFP c0 01 20 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 27: (0) data v21/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type TSI - CRC OK (clean) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: TSI without final frame tag -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 43 6e 77 6f 6e 6b 6e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Remote gave TSI as: "unknown" -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 28: IFP c0 01 80 00 00 ff -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 28: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 29: IFP c0 01 80 00 00 c8 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 29: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 30: IFP c0 01 80 00 00 c1 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 30: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 31: IFP c0 01 80 00 00 00 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 31: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 32: IFP c0 01 80 00 00 46 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 32: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 33: IFP c0 01 80 00 00 1f -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 33: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 34: IFP c0 01 80 00 00 22 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 34: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 35: IFP c0 01 40 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 35: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type DCS - CRC OK, sig end (clean) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: DCS with final frame tag -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 13 83 00 62 f8 44 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 1 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 DCS before DIS -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 DCS: -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ...0= Store and forward Internet fax (T.37): Not set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... .0..= Real-time Internet fax (T.38): Not set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... 0...= 3G mobile network: Not set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ..1.= Receive fax: Set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 ..10 00..= Selected data signalling rate: V.17 14400bps -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .1.. ....= R8x7.7lines/mm and/or 200x200pels/25.4mm: Set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 0... ....= 2-D coding: Not set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ..00= Recording width: 215mm +- 1% -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... 10..= Recording length: Unlimited -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .111 ....= Minimum scan line time: 0ms -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 1... ....= Extension indicator: Set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ..0.= Compressed/uncompressed mode: Compressed -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... .1..= Error correction mode (ECM): ECM -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... 0...= Frame size: 256 octets -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .1.. ....= T.6 coding: Set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 0... ....= Extension indicator: Not set -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Selected compression T.6 (3) -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Get document at 14400bps, modem 7 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 1 to 7 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 7 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_B_RX to T30_PHASE_C_NON_ECM_RX -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 7 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 36: IFP 00 -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 36: indicator no-signal -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 37: IFP 1e -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 37: indicator v17-14400-long-training -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present -[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 38: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 38: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Non-ECM signal status is Training succeeded (-4) in state 7 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 39: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 39: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 40: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 40: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 41: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 41: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 42: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 42: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 43: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 43: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 44: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 44: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 45: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 45: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 46: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 46: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 47: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 47: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 48: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 48: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 49: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 49: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 50: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 50: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 51: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 51: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 52: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 52: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 53: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 53: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 54: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 54: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 55: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 55: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 56: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 56: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 57: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 57: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 58: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 58: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 59: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 59: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 60: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 60: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 61: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 61: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 62: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 62: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 63: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 63: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 64: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 64: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 65: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 65: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 66: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 66: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 67: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 67: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 68: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 68: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 69: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 69: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 70: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 70: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 71: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 71: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 72: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 72: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 73: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 73: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 74: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 74: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 75: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 75: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 76: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 76: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 77: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 77: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 78: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 78: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 79: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 79: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 80: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 80: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 81: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 81: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 82: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 82: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 83: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 83: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 84: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 84: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 85: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 85: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 86: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 86: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 87: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 87: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 88: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 88: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 89: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 89: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 90: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 90: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 91: IFP d0 01 f0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 91: (0) data v17-14400/t4-non-ecm-sig-end + 54 byte(s) -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Receive complete in phase T30_PHASE_C_NON_ECM_RX, state 7 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Non-ECM signal status is Carrier down (-1) in state 7 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Trainability (TCF) test result - 23328 total bits. longest run of zeros was 23328 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_C_NON_ECM_RX to T30_PHASE_B_TX -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 4 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 7 to 8 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: CFR with final frame tag -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: ff 13 84 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 92: IFP 00 -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 92: indicator no-signal -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 2: indicator no-signal -[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 3: indicator v21-preamble -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 4: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 4: IFP c0 01 80 00 00 ff -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 5: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 5: IFP c0 01 80 00 00 c8 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 6: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 6: IFP c0 01 80 00 00 21 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_B_TX, state 8 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 7: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 7: IFP c0 01 40 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_B_TX, state 8 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 8 to 12 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_B_TX to T30_PHASE_C_ECM_RX -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 7 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 -[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 8: indicator no-signal -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 93: IFP 1c -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 93: indicator v17-14400-short-training -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (51520 remaining) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 94: IFP d0 01 80 00 35 ff c0 60 00 ff ff ff ff ff ff ff ff 2b 92 8a 4c c2 9d 8b 22 38 68 23 a8 22 87 0c 8e 90 60 81 21 10 c8 ea da b1 91 d5 06 e1 38 55 04 ed b6 b5 49 7b df c2 45 90 c9 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 94: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 95: IFP d0 01 80 00 35 17 45 d1 84 54 91 74 5d 18 45 2d 17 44 55 17 45 d1 74 5d 17 45 d1 74 5d 17 45 d1 74 76 24 8b a2 e8 c2 25 08 ba 2e 8b a2 e8 ba 2e 8b a2 e8 ba 2e 8b a3 b1 24 61 17 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 95: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 96: IFP d0 01 80 00 35 44 b1 17 45 d1 74 5d 17 45 d1 74 5d 17 45 d1 75 ed b2 ba 11 1c 8c 81 51 1c ce c1 51 1c 08 23 a2 2e 88 e1 9c 8e 8a 9a 08 49 98 28 71 11 11 11 11 11 06 76 a1 11 c3 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 96: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 97: IFP d0 01 80 00 35 39 1d 04 22 22 22 22 22 24 f6 a0 a1 c4 48 a3 94 06 50 e2 22 22 22 22 22 0f a4 08 a1 d0 41 46 10 51 a1 1c 47 1b c4 60 8a 1e 84 64 75 1f 77 8c 20 a2 d3 23 a4 1a 60 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 97: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 98: IFP d0 01 80 00 2b 8a 1d a0 dd 30 8a 1d f5 50 54 30 45 0e 30 45 0f 23 a0 a3 82 28 79 1d 61 06 3d db a2 3a b5 42 0e 23 50 8a 1f 11 84 50 ed 03 5a 54 11 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 98: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 99: IFP d0 01 20 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 99: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 00 ff ff ff ff ff ff ff ff d4 49 51 32 43 b9 d1 44 1c 16 c4 15 44 e1 30 71 09 06 81 84 08 13 57 5b 8d 89 ab 60 87 1c aa 20 b7 6d ad 92 de fb 43 a2 09 93 e8 a2 8b 21 2a 89 2e ba 18 a2 b4 e8 22 aa e8 a2 8b 2e ba e8 a2 8b 2e ba e8 a2 8b 2e 6e 24 d1 45 17 43 a4 10 5d 74 d1 45 17 5d 74 d1 45 17 5d 74 d1 c5 8d 24 86 e8 22 8d e8 a2 8b 2e ba e8 a2 8b 2e ba e8 a2 8b ae b7 4d 5d 88 38 31 81 8a 38 73 83 8a 38 10 c4 45 74 11 87 39 71 51 59 10 92 19 14 8e 88 88 88 88 88 60 6e 85 88 c3 9c b8 20 44 44 44 44 44 24 6f 05 85 23 12 c5 29 60 0a 47 44 44 44 44 44 f0 25 10 85 0b 82 62 08 8a 85 38 e2 d8 23 06 51 78 21 26 ae f8 ee 31 04 45 cb c4 25 58 06 51 b8 05 bb 0c 51 b8 af 0a 2a 0c a2 70 0c a2 f0 c4 05 c5 41 14 9e b8 86 60 bc db 45 5c ad 42 70 c4 0a 51 f8 88 21 0a b7 c0 5a 2a 88 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 0, length 256 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 100: IFP d0 01 80 00 35 ff c0 60 80 43 c5 25 0a 10 61 5c 10 63 41 56 1a d9 0d 04 2f b0 8a 1d 84 50 fd be de d2 d2 2a 11 1d 2e 15 dd 42 84 50 f5 23 ae d1 74 f4 28 a5 f5 7c 34 19 02 40 af -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 100: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 101: IFP d0 01 80 00 35 0c 6c 22 87 61 14 3e 11 50 10 ac 23 08 48 e8 ba ad 42 a1 e1 42 51 0c 78 8b 74 08 10 88 df 0e 18 22 87 84 50 f8 6e 11 43 bf 4a 29 74 93 8e 96 e1 14 3f bb f7 60 bd -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 101: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 102: IFP d0 01 80 00 35 84 50 ef 1a af fe 6b 0d 30 8a 1d 63 09 48 e8 22 87 56 ea f0 c8 31 6c 22 87 21 b2 24 75 8c 83 ec a0 a1 c8 6c 89 1d 48 3e ca 88 6c 86 c8 60 c1 52 32 49 35 d8 20 45 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 102: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 103: IFP d0 01 80 00 35 5a 61 06 d5 23 e8 fa 60 83 69 1e 47 d0 45 0e 10 45 5e 8f a3 e8 f2 19 5c a9 18 45 d1 74 47 44 74 47 44 74 47 44 74 47 44 74 47 58 22 9d 97 45 d1 74 47 44 74 47 44 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 103: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 104: IFP d0 01 80 00 2b 74 5d 17 40 8a 79 74 61 02 28 70 cb a2 ea 88 e8 5e 10 6f a1 1a 23 a3 09 b6 c4 5a 16 1d 08 8c c8 c0 72 28 1c e8 1a 44 69 11 c3 0a 77 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 104: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 105: IFP d0 01 20 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 105: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 01 c2 a3 a4 50 08 86 3a 08 c6 82 6a 58 9b b0 20 f4 0d 51 b8 21 0a bf 7d 7b 4b 4b 54 88 b8 74 a8 bb 42 21 0a af c4 75 8b 2e 2f 14 a5 af 3e 2c 98 40 02 f5 30 36 44 e1 86 28 7c 88 0a 08 35 c4 10 12 17 5d b5 42 85 87 42 8a 30 1e d1 2e 10 08 11 fb 70 18 44 e1 21 0a 1f 76 88 c2 fd 52 94 2e c9 71 69 87 28 fc dd ef 06 bd 21 0a f7 58 f5 7f d6 b0 0c 51 b8 c6 90 12 17 44 e1 6a 57 0f 13 8c 36 44 e1 84 4d 24 ae 31 c1 37 05 85 13 36 91 b8 12 7c 53 11 36 61 13 06 83 4a 4c 92 ac 1b 04 a2 5a 86 60 ab c4 17 5f 06 c1 96 78 e2 0b a2 70 08 a2 7a f1 c5 17 4f 98 3a 95 18 a2 8b 2e e2 22 2e e2 22 2e e2 22 2e e2 22 2e e2 1a 44 b9 e9 a2 8b 2e e2 22 2e e2 22 2e ba e8 02 51 9e 2e 86 40 14 0e d3 45 57 11 17 7a 08 f6 85 58 c4 c5 90 6d 23 5a 68 b8 10 31 13 03 4e 14 38 17 58 22 96 88 c3 50 ee -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 1, length 256 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 106: IFP d0 01 80 00 35 ff c0 60 40 40 53 3a a2 3a 23 82 82 3a 29 03 90 60 e4 74 77 c0 a6 49 a2 38 30 47 44 59 11 c3 61 1d 12 e0 a6 8a 1d 0b 84 8b a0 45 45 54 8e 82 42 21 d2 08 a1 d2 28 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 106: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 107: IFP d0 01 80 00 35 74 b4 e1 c3 08 28 b6 d0 71 11 06 99 1d 21 a6 08 12 11 61 05 11 64 75 0c 58 20 8a 76 d0 88 45 3c 8e 9d c5 a0 8a 79 1d 3b 45 d0 b0 db ea 94 45 50 52 3a 4d 76 e2 35 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 107: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 108: IFP d0 01 80 00 35 41 18 42 d0 48 ba 1b 7c 24 5d 0d aa 42 d5 6f c1 14 3e db 6c 8e ae c2 64 74 08 a1 de 23 b8 b7 db 8b bd 58 45 0e eb f1 d0 41 91 d5 d2 40 87 1e 77 a2 23 ad 69 14 3d -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 108: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 109: IFP d0 01 80 00 35 25 c8 e9 57 1a bf 69 ec 6d 82 28 74 e9 91 d2 78 8b 7b 63 be e3 b6 df d6 81 14 3a 5b 76 b4 c2 5a 54 11 43 d9 0c 3d 68 22 87 6b 09 a5 ef bb 76 c3 4a ec 8e bf a1 78 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 109: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 110: IFP d0 01 80 00 2b 4e c3 a1 77 23 a0 8a 1e 11 43 dc 8e bd 6b 4a 92 a4 08 a1 d8 45 0f d5 48 e8 fa 23 a2 3a 08 a1 ed 17 5e 47 44 74 47 44 74 5d 29 a2 23 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 110: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 111: IFP d0 01 20 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 111: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 02 02 ca 5c 45 5c c4 41 41 5c 94 c0 09 06 27 2e ee 03 65 92 45 1c 0c e2 22 9a 88 c3 86 b8 48 07 65 51 b8 d0 21 d1 05 a2 a2 2a 71 41 42 84 4b 10 85 4b 14 2e 2d 87 c3 10 14 6d 0b 8e 88 60 99 b8 84 65 10 48 88 86 a0 88 26 ae 30 1a 04 51 6e 0b 11 a2 3c 71 b9 a3 05 51 9e b8 dc a2 0b 0d db 57 29 a2 0a 4a 5c b2 6e 47 ac 82 18 42 0b 12 5d d8 3e 24 ba b0 55 42 ab f6 83 28 7c db 36 71 75 43 26 2e 10 85 7b c4 1d ed db d1 bd 1a a2 70 d7 8f 0b 82 89 ab 4b 02 e1 78 ee 45 c4 b5 96 28 bc a4 13 97 ea 58 fd 96 37 b6 41 14 2e 97 89 4b 1e d1 de c6 7d c7 6d fb 6b 81 28 5c da 6e 2d 43 5a 2a 88 c2 9b 30 bc 16 44 e1 d6 90 a5 f7 dd 6e c3 52 37 71 fd 85 1e 72 c3 85 ee c4 05 51 78 88 c2 3b 71 bd d6 52 49 25 10 85 1b a2 f0 ab 12 17 5f c4 45 5c 10 85 b7 e8 7a e2 22 2e e2 22 2e ba 94 45 c4 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 2, length 256 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 112: IFP d0 01 80 00 35 ff c0 60 c0 a2 3a 2e 82 28 7d 97 44 74 47 44 74 5d 34 5d 1e 44 74 47 44 74 3a 19 1d 11 d1 1d 11 d1 75 b0 8a 1d d8 45 0e ed 86 1b 23 aa 23 a7 61 b7 db 42 10 4c 43 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 112: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 113: IFP d0 01 80 00 35 08 21 6c 22 9c 21 c2 28 71 11 10 cc 22 3a 68 ba 08 28 88 63 c4 44 58 91 d1 75 88 41 31 16 11 4e e2 22 21 97 44 75 48 6a 9a ae e8 70 90 4b 04 50 eb 6c 11 43 a1 12 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 113: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 114: IFP d0 01 80 00 35 3a c6 0c 71 6c 11 51 43 1a 6c 52 8c 6f ff 6d ad c3 7c 6b 23 a0 45 0e c5 ca 74 5d 0e 83 23 a2 ea c1 14 3b 08 a1 db 64 74 61 64 74 83 6e 0c 8e b9 1d 04 50 f2 3a c2 -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 114: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 115: IFP d0 01 80 00 35 ee 8a 1e 47 41 14 3a a4 95 a0 aa 2d e2 3c 62 47 49 36 35 16 91 85 88 45 0e 9a b2 eb 89 c4 47 0a e2 db b4 47 41 14 3c 5b 8a 6a c8 ea ee 9f 08 a1 df 21 aa e5 6c 3d -[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 115: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 116: IFP d0 01 80 00 2b f1 0c 76 c2 28 7c 43 23 ae f9 ad 1d 01 70 a0 ca e2 04 0b e3 3b ad 1c 02 0d a3 68 da 36 82 28 77 08 19 56 50 e4 33 d9 56 55 95 65 6c -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 116: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 117: IFP d0 01 20 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 117: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 03 45 5c 74 41 14 be e9 22 2e e2 22 2e ba 2c ba 78 22 2e e2 22 2e 5c 98 b8 88 8b b8 88 8b ae 0d 51 b8 1b a2 70 b7 61 d8 c4 55 c4 e5 86 ed db 42 08 32 c2 10 84 36 44 39 84 43 14 8e 88 08 33 44 5c 16 5d 10 14 11 c6 23 22 1a 89 8b ae 11 82 8c 68 88 72 47 44 84 e9 22 ae 12 56 59 75 17 0e 09 d2 20 0a d7 36 88 c2 85 48 5c 63 30 8e 36 88 8a c2 58 36 4a 31 f6 ff b6 b5 c3 3e d6 c4 05 a2 70 a3 53 2e ba 70 c1 c4 45 57 83 28 dc 10 85 db 26 2e 86 26 2e c1 76 30 71 9d b8 20 0a 4f 5c 43 77 51 78 e2 82 28 5c 25 a9 05 55 b4 47 3c 46 e2 92 6c ac 68 89 a1 11 a2 70 59 4d d7 91 23 e2 50 47 db 2d e2 82 28 3c da 51 56 13 57 77 f9 10 85 fb 84 55 a7 36 bc 8f 30 6e 43 14 3e c2 c4 75 9f b5 b8 80 0e 05 53 47 20 d0 c7 dc b5 38 40 b0 c5 16 5b 6c 41 14 ee 10 98 6a 0a 27 cc 9b 6a aa a9 a6 36 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 3, length 256 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 118: IFP d0 01 80 00 35 ff c0 60 20 4c a1 d1 75 a7 5c 3a 5d 3f 1c 8e ae e4 74 9e 08 10 98 45 d1 74 11 4f 90 d1 46 08 10 84 54 23 68 ba 2e 8b a2 e8 ba 2e 91 50 74 ed c1 02 10 8a 74 08 10 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 118: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 119: IFP d0 01 80 00 35 88 89 74 c8 67 43 90 60 38 20 42 21 84 08 10 88 88 d0 ee fd 91 d5 f6 d9 1d 5d dd c2 28 78 84 50 f0 8a 1e 22 22 2e 91 74 8a 1d 08 d0 88 88 88 88 40 83 29 ca 20 a7 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 119: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 120: IFP d0 01 80 00 35 48 21 16 84 42 08 c2 0f 91 d0 45 42 23 a1 c4 ed 4d 05 49 42 28 7f 69 75 74 92 a6 47 51 86 39 1d 0d db 42 2f 62 22 2d 87 b7 10 8a 77 88 a2 85 ae f8 df 64 74 42 03 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 120: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 121: IFP d0 01 80 00 35 5b ee 11 43 86 47 44 18 35 ee ed d2 4d 05 54 5d 3d 06 9a a0 82 16 b1 2e 8b ac 11 43 85 e9 71 85 f5 1b 4f f8 77 76 f5 16 ec 22 87 61 14 eb 61 3e 47 42 3b 57 bf 91 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 121: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 122: IFP d0 01 80 00 2b d5 de dc 34 fb ef 91 d2 91 d1 84 92 c2 a4 87 1a 5c 8e 8d 49 3b c1 14 3a 4b d6 f4 b4 92 ad 2f b8 d8 ed ee e4 11 17 44 74 47 44 74 47 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 122: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 123: IFP d0 01 20 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 123: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 04 32 85 8b ae e5 3a 5c ba fc 38 71 75 27 2e 79 10 08 19 a2 8b 2e 88 f2 09 8b 62 10 08 21 2a c4 16 5d 74 d1 45 17 5d 74 89 0a 2e b7 83 40 08 51 2e 10 08 11 91 2e 13 e6 c2 09 06 1c 04 42 84 21 10 08 11 11 0b 77 bf 89 ab 6f 9b b8 ba bb 43 14 1e 21 0a 0f 51 78 44 44 74 89 2e 51 b8 10 0b 11 11 11 11 02 c1 94 53 04 e5 12 84 68 21 42 10 43 f0 89 0b a2 42 c4 85 23 b7 b2 a0 92 42 14 fe 96 ae 2e 49 65 e2 8a 61 9c b8 b0 db 42 f4 46 44 b4 e1 ed 08 51 ee 11 45 a1 75 1f fb 26 2e 42 c0 da 77 88 c2 61 e2 22 18 ac 77 b7 4b b2 a0 2a ba bc 60 59 05 41 68 8d 74 d1 35 88 c2 a1 97 8e a1 af d8 f2 1f ee 6e af 68 37 44 e1 86 28 d7 86 7c e2 42 dc ea fd 89 ab 7b 3b 2c df f7 89 4b 89 8b 21 49 43 25 e1 58 3a 71 b1 92 dc 83 28 5c d2 6b 2f 2d 49 b5 f4 1d 1b b7 77 27 88 e8 22 2e e2 22 2e e2 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 4, length 256 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 124: IFP d0 01 80 00 35 ff c0 60 a0 44 74 47 44 74 08 a1 ee 47 4d c4 19 1d 11 d1 1d 11 d1 1d 04 14 6c 86 c1 ca 72 8a ed b6 d0 45 0e dd bd b7 76 1f be e4 75 08 a1 e4 75 91 d5 17 55 45 d2 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 124: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 125: IFP d0 01 80 00 35 e0 81 31 11 11 11 11 a4 34 84 44 44 46 85 89 1d 60 8a 1c 2a c6 b4 50 f2 3a 5a 4b 7f d4 22 87 71 bb 08 a1 d8 dd 8b 76 21 43 db b0 7b 0b c1 14 fc 49 01 a4 de e1 14 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 125: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 126: IFP d0 01 80 00 35 3b 2a 03 4e f6 9c 48 61 a4 47 55 04 50 f1 a4 92 49 22 52 82 c2 49 58 64 75 82 28 74 a4 75 42 b9 02 46 11 38 66 52 b4 d1 ad 18 44 e1 97 5a 82 29 e6 a4 61 13 86 64 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 126: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 127: IFP d0 01 80 00 35 38 b9 1d 53 bb b6 10 4e ef 84 50 e3 2e b6 8b a6 c3 de 22 11 57 23 ad c8 e9 a2 3a c4 4f 24 54 07 76 1a 1a 11 45 47 69 84 50 f2 3a fe 9c 22 9d 78 86 32 3a c1 14 3c -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 127: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 128: IFP d0 01 80 00 2b 76 15 62 11 56 d6 c1 15 08 71 14 54 2e 83 09 48 e8 a8 42 8a 89 1d 42 28 77 b8 de 11 43 bb 04 50 f1 c8 ea f0 8a 71 91 d5 b0 b1 08 a1 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 128: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 129: IFP d0 01 20 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 129: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 05 22 2e e2 22 2e 10 85 77 e2 b2 23 98 b8 88 8b b8 88 8b b8 20 28 36 61 83 53 4e 51 b7 6d 0b a2 70 bb bd ed 6e f8 7d 27 ae 10 85 27 ae 89 ab e8 aa a2 4b 07 81 8c 88 88 88 88 25 2c 21 22 22 62 a1 91 b8 06 51 38 54 63 2d 0a 4f 5c 5a d2 fe 2b 44 e1 8e dd 10 85 1b bb d1 6e 84 c2 db 0d de d0 83 28 3f 92 80 25 7b 87 28 dc 54 c0 72 6f 39 12 86 25 e2 aa 20 0a 8f 25 49 92 44 4a 41 43 92 1a 26 ae 41 14 2e 25 ae 42 9d 40 62 88 1c 66 4a 2d 8b b5 18 22 87 e9 5a 41 94 67 25 86 c8 61 26 1c 9d b8 ca dd 6d 08 72 f7 21 0a c7 74 6d d1 65 c3 7b 44 88 ea c4 b5 13 97 45 5c 23 f2 24 2a e0 6e 58 58 88 a2 e2 96 21 0a 4f 5c 7f 39 44 b9 1e 61 4c 5c 83 28 3c 6e a8 46 88 6a 6b 83 a8 10 8e 28 2a 74 c1 90 12 17 15 42 51 91 b8 42 14 ee 1d 7b 88 c2 dd 20 0a 8f 13 57 0f 51 8e 89 ab 0d 8d 10 85 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 5, length 256 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 130: IFP d0 01 80 00 35 ff c0 60 60 f9 17 42 11 59 7c 42 2b 48 83 d6 11 47 2a 22 22 7c 33 c6 3d 2c 69 27 51 4b 1b a0 45 0e 94 cd 1b 43 e2 2f a8 9b 40 8a 1e 1f c8 e8 4d a1 57 b8 22 9e fe -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 130: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 131: IFP d0 01 80 00 35 e0 8a 7b 0d bb 6c 8e b6 9b 23 a1 1b c2 29 fb 91 d0 8b 61 14 ed bc 46 c2 29 f5 15 d5 71 50 45 0e 8c 2a a0 d9 75 82 28 74 5d 50 82 28 75 8b d6 34 34 95 84 50 e8 5e -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 131: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 132: IFP d0 01 80 00 35 df 6d b7 6a c3 1f 0d 8e 34 36 3e d8 68 8e a1 ab 61 85 64 74 38 45 3f a4 95 24 90 55 5c 11 58 c8 eb 04 50 e1 29 1d 6a 11 43 a1 14 81 14 3f 1a 10 45 0f 1f 16 f6 ed -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 132: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 133: IFP d0 01 80 00 35 bc 36 f1 0d ee d8 22 87 b8 ed 91 d0 ee d8 dd d2 f2 eb ac 22 87 55 41 15 0f 04 50 eb 1f f1 ae c2 55 7b b1 bb c2 09 b2 ea da 23 a1 08 ab 76 c2 61 af 76 a4 75 84 50 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 133: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 134: IFP d0 01 80 00 2b ed fe 96 95 22 1b 03 8a 62 b2 0b ee 9a a4 ab a7 51 08 a1 e3 4a bb 6e 1b ec 11 b4 61 3a 0d e8 c2 26 88 3e 11 43 dc 22 87 e1 14 3c 22 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 134: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 135: IFP d0 01 20 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 135: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 06 9f e8 42 88 9a 3e 42 d4 12 c1 6b 88 e2 54 44 44 3e cc 63 bc 34 96 e4 8a d2 d8 05 a2 70 29 b3 d8 c2 47 f4 15 d9 02 51 78 f8 13 17 b2 85 ea 1d 44 79 7f 07 51 de b0 dd 36 71 6d d9 c4 85 d8 43 94 df 89 0b d1 86 28 b7 3d 62 43 94 af a8 ab 8e 0a a2 70 31 54 05 9b ae 41 14 2e ba 0a 41 14 ae d1 6b 2c 2c a9 21 0a 17 7a fb b6 ed 56 c3 f8 b0 71 2c 6c 7c 1b 16 71 85 d5 86 a1 26 2e 1c a2 fc 25 a9 24 09 aa 3a 88 1a 13 d7 20 0a 87 94 b8 56 88 c2 85 28 81 28 fc 58 08 a2 f0 f8 68 6f b7 3d 6c 8f b0 77 1b 44 e1 1d b7 89 0b 77 1b bb 4b 4f d7 35 44 e1 aa 82 a8 f0 20 0a d7 f8 8f 75 43 aa de 8d dd 43 90 4d 57 5b c4 85 10 d5 6e 43 86 f5 6e 25 ae 21 0a b7 7f 69 a9 44 d8 c0 51 46 4d d0 77 59 25 d5 e5 8a 10 85 c7 52 dd 76 d8 37 88 2d 86 5c b0 17 43 64 11 7c 88 c2 3b 44 e1 87 28 3c 44 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 6, length 256 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 136: IFP d0 01 80 00 35 ff c0 60 e0 87 6e d4 3d ec 82 81 d5 6a a9 02 04 22 11 43 c2 28 75 a8 41 09 18 8b a2 e8 84 46 10 f6 d5 be e3 82 28 74 5d 12 11 26 82 91 d5 02 28 74 4b 10 58 45 0f -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 136: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 137: IFP d0 01 80 00 35 7d cb a6 db b1 1d b2 3a b2 3a 3a 22 e8 ba 63 38 85 84 25 d0 41 34 61 3e 47 47 44 5d 17 49 36 47 49 17 59 50 88 e8 8e 88 e8 83 41 5b 23 a6 c4 20 84 ba 2e 87 16 cb -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 137: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 138: IFP d0 01 80 00 35 a1 a3 a2 23 a2 3a 23 a0 82 78 d2 4b 0e aa b5 14 c5 21 60 c4 90 81 03 10 82 88 62 47 4f 62 29 04 50 e8 22 9d 82 28 74 38 20 4c 62 47 41 04 e9 82 28 70 81 02 68 4d -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 138: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 139: IFP d0 01 80 00 35 68 15 b1 3e 82 91 d0 20 4c 62 47 42 bc 39 1d 37 64 74 47 4b 6d 91 d7 21 88 6d 91 d1 a2 04 09 03 23 a0 8a 1c 33 08 ba 04 09 94 38 6c 31 27 41 14 3b 86 47 46 88 b9 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 139: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 140: IFP d0 01 80 00 2b 91 d3 44 74 30 c8 e9 c8 eb 65 0e 18 97 41 04 e1 b2 3a 08 27 14 19 1d 11 d1 74 10 43 c3 23 a6 84 42 0c 4b a3 a2 0b 5c 69 14 38 c4 8e -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 140: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 141: IFP d0 01 20 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 141: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 07 e1 76 2b bc 37 41 81 ab 56 95 40 20 44 88 c2 43 14 ae 15 82 90 18 d1 45 17 21 62 08 6f ab 7d c7 41 14 2e ba 48 88 64 41 89 ab 40 14 2e d2 08 1a a2 f0 be d3 65 db 8d b8 4d 5c 4d 5c 5c 44 17 5d c6 1c a1 21 a4 0b 82 2c 86 7c e2 e2 22 ba e8 92 6c e2 92 e8 9a 0a 11 17 71 11 17 c1 82 da c4 65 23 04 21 5d 74 e1 68 d3 85 c5 45 c4 45 5c c4 05 41 1e 4b d2 70 55 ad 28 a3 84 06 23 09 81 c0 08 41 11 46 e2 f2 46 94 20 0a 17 44 b9 41 14 2e 1c 04 32 46 e2 82 20 97 41 14 0e 81 40 16 b2 16 a8 8d 7c 41 89 0b 04 32 46 e2 42 3d 9c b8 ec 26 2e e2 d2 b6 89 eb 84 11 b6 89 8b 45 20 90 c0 c4 05 51 38 cc 10 5d 20 90 29 1c 36 8c e4 82 28 dc 61 e2 62 11 9d 89 cb 22 2e 0c 13 97 13 d7 a6 70 18 e9 82 20 87 4d 5c 10 e4 28 98 b8 88 8b 2e 08 c2 c3 c4 65 21 42 30 d2 c5 45 d0 3a 96 28 1c 23 71 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 7, length 256 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 142: IFP d0 01 80 00 35 ff c0 60 10 8b a5 49 0c 8e 8c 22 e8 ba 50 8a 1e e4 75 65 d1 74 08 13 16 2c 31 10 82 10 87 06 47 45 d0 41 0a 15 65 d1 74 08 14 5a 65 d1 74 47 45 d1 74 5d 17 45 d1 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 142: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 143: IFP d0 01 80 00 35 74 5d 26 5d 02 42 44 23 08 c2 04 50 f2 3a 2e 98 31 23 a2 3a 2e 8b a6 a3 04 09 a0 45 0e 23 48 ba 23 a2 3a 08 21 04 82 29 d9 74 08 a1 e0 8a 1c 18 91 d1 1d 11 d1 74 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 143: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 144: IFP d0 01 80 00 35 47 41 05 15 6d f1 62 23 6d 88 88 8d c2 29 dc 44 47 11 71 11 1b 11 11 71 11 11 11 11 10 c8 e8 31 16 10 88 88 89 16 65 0e 22 22 29 88 c8 e9 88 88 88 c8 e8 62 22 c6 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 144: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 145: IFP d0 01 80 00 35 22 22 22 2a d2 4a b5 82 28 74 2d 91 d6 47 48 a1 d0 45 0f 5b a5 68 ba 51 08 a1 d0 c2 09 70 d3 61 bf 76 ec 5c 76 ef bc 5a 69 dc ba 84 53 a7 23 aa a5 54 12 fa 54 ad -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 145: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 146: IFP d0 01 80 00 2b 61 14 3a 7d 20 90 c7 23 ac 6d db 0f 86 1b b7 7b fb 74 47 54 47 41 b7 a8 aa 4b 5a 54 e1 14 3a a4 50 f2 3a d1 4e 12 c2 68 42 28 74 2c -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 146: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 147: IFP d0 01 20 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 147: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 08 d1 a5 92 30 71 31 44 17 5d 0a 51 78 27 ae a6 8b 2e 10 c8 68 34 8c 08 41 08 e1 60 e2 a2 0b 82 50 a8 a6 8b 2e 10 28 5a a6 8b 2e e2 a2 8b 2e ba e8 a2 8b 2e ba 64 ba 40 42 22 c4 10 43 20 0a 4f 5c 74 19 8c c4 45 5c 74 d1 65 c5 20 90 05 a2 70 c4 12 5d c4 45 5c 10 84 20 41 94 9b 2e 10 85 07 51 38 18 89 8b b8 88 8b 2e e2 82 a0 a8 b6 8f 46 c4 b6 11 11 b1 43 94 3b 22 e2 88 8e 88 d8 88 88 8e 88 88 88 88 08 13 17 8c 68 08 11 11 91 68 a6 70 44 44 94 11 13 97 11 11 11 13 17 46 44 63 44 44 44 54 4b 52 ad 41 14 2e b4 89 6b e2 12 85 0b a2 f0 da a5 16 5d 8a 10 85 0b 43 90 0e cb 86 fd 6e 37 3a 6e f7 3d 5a 96 3b 5d 21 ca e5 c4 55 a5 2a 48 5f 2a b5 86 28 5c be 04 09 e3 c4 35 b6 db f0 61 d8 ed de df 2e e2 2a e2 82 ed 15 55 d2 5a 2a 87 28 5c 25 0a 4f 5c 8b 72 48 43 16 42 14 2e 34 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 8, length 256 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 148: IFP d0 01 80 00 35 ff c0 60 90 2a 87 69 c3 76 ee 47 4c 3b 10 f4 2d e2 d3 d0 45 45 da ad 3e d5 04 53 ca 12 42 8a 1d 04 53 ae b5 5d 04 35 09 14 3a 41 72 3a bb 7b 16 85 45 b2 3a 17 0d -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 148: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 149: IFP d0 01 80 00 35 b4 47 4d 38 6b 72 3a 69 a1 da 23 aa 42 8a 1d 24 ea 8a 1e 12 4d 5a 48 5d 5a 2e 95 84 28 a1 d2 4c 2a 1b 8e e1 15 09 c5 b6 88 e8 36 0e 11 50 81 84 db 86 10 bc 21 0c -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 149: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 150: IFP d0 01 80 00 35 20 c2 30 83 09 85 69 f1 0e 47 54 18 4a 3b 42 1a 2e 83 08 c2 08 a7 0b 0c 2d 14 38 46 13 09 82 10 d3 08 c2 e4 74 11 4e ad a1 b7 6a c2 29 d0 45 3a 08 21 08 a7 40 81 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 150: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 151: IFP d0 01 80 00 35 08 86 b0 8a 74 5d 62 1a 10 d1 74 11 4e 88 e9 a2 3a 08 a8 08 74 23 45 d2 41 15 01 34 08 ab 08 c2 a6 10 86 10 86 10 88 68 51 43 84 61 24 34 2d 22 9c 10 45 3a 11 06 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 151: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 152: IFP d0 01 80 00 2b 10 82 2a c2 11 45 38 45 d4 1a 06 08 5c 4c c1 c9 08 22 9c 21 45 79 06 0e 08 41 84 61 04 55 82 08 ae 20 88 28 21 53 20 9e 52 b2 bc 83 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 152: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 153: IFP d0 01 20 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 153: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 09 54 e1 96 c3 6e 77 e2 32 dc 08 2f b4 47 cb 0b a2 a2 5b b5 7c ab 20 ca 53 48 42 51 b8 20 ca 75 ad ba 20 ac 90 28 5c 82 4e 5c dd de 68 a1 a2 4d 5c e8 b0 2d e2 b2 1c d6 4e 5c 96 85 5b c4 55 42 51 b8 24 57 51 78 48 b2 5a 12 ba 5a 74 a9 21 14 85 4b 32 54 d8 71 87 a8 90 a3 6d 11 17 6c 70 88 0a 81 21 db 61 08 3d 84 30 04 43 0c c1 90 a1 96 8f 70 e2 2a 18 52 dc 42 58 74 c1 10 43 10 e5 d0 30 b4 28 1c 62 c8 90 41 08 cb 10 43 27 2e 88 72 b5 85 ed 56 43 94 0b a2 5c 10 84 10 e5 02 81 10 61 0d 51 2e ba 46 58 08 8b 2e 88 72 11 97 45 5c 10 15 10 2e c4 a2 4b 82 a8 80 2c 10 d5 10 43 65 08 61 08 61 08 11 16 8a c2 21 86 24 2c b4 44 39 08 a2 5c 88 60 08 41 54 43 88 a2 1c a2 2b 58 60 10 3a 32 83 93 10 44 39 84 a2 9e 60 70 10 82 21 86 20 aa 41 10 75 04 11 14 84 ca 04 79 4a 4d 3d c1 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 9, length 256 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 154: IFP d0 01 80 00 35 ff c0 60 50 ac 90 7d 83 08 8d 05 38 82 29 c2 12 70 c0 9f 08 46 d2 2a 64 1f 65 a5 61 08 58 43 0b d6 22 47 41 48 d2 08 aa 8a 82 a4 90 a2 e5 39 52 17 2a a2 a0 a1 32 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 154: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 155: IFP d0 01 80 00 35 ab 28 50 a4 e5 59 40 a5 56 55 94 df 8a 72 93 95 05 6c a0 ad 0a 82 84 8a 72 aa 2a 0a d9 51 41 95 05 0d 14 e5 27 2a 0a 5d 02 d8 88 88 88 88 88 88 88 88 88 88 88 88 -[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 155: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 156: IFP d0 01 80 00 35 88 88 88 88 88 8c ae 28 8b a0 94 20 9b 23 a2 3a 7b 18 82 28 7c 11 43 86 47 45 d3 71 88 65 d0 4a 84 7a dd 05 6a 14 8e ad 0f 84 53 a8 d1 75 0c 21 86 8b a8 68 60 8a -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 156: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 157: IFP d0 01 80 00 35 b0 8b a8 84 52 61 58 9f 46 14 47 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 157: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 158: IFP d0 01 80 00 2b ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 158: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 159: IFP d0 01 20 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 159: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 0a 35 09 be c1 10 b1 a0 1c 41 94 43 48 0e 03 f9 10 62 4b 54 26 f8 a6 a5 86 10 1a c2 d0 6b 44 e2 82 12 4b 10 55 51 41 25 09 45 a7 9c 4a e8 54 45 05 85 4c d5 14 0a 25 a7 9a 02 a5 6a aa 29 fb 51 4e c9 a9 a0 36 05 b5 50 41 21 51 4e 55 54 50 9b 8a 82 a9 a0 b0 28 a7 e4 54 50 ba 40 1b 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 31 75 14 d1 05 29 04 d9 c4 45 5c de 18 41 14 3e 88 c2 61 e2 a2 cb 8e 11 a6 0b 52 21 5e bb a0 56 28 71 b5 f0 21 ca 15 8b ae 30 84 61 d1 15 16 06 51 0d d1 15 21 4a 86 1a f9 62 28 e2 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 10, length 256 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 160: IFP d0 01 80 00 35 ff c0 60 d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 160: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 161: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 161: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 162: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 162: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 163: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff fe 00 20 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 163: (0) data v17-14400/hdlc-data + 54 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 164: IFP d0 01 80 00 2b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 164: (0) data v17-14400/hdlc-data + 44 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 165: IFP d0 01 20 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 165: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 0b ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 7f 00 04 c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 11, length 256 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 166: IFP d0 01 80 00 02 ff c0 61 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 166: (0) data v17-14400/hdlc-data + 3 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 167: IFP d0 01 20 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 167: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 12 to 13 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 168: IFP d0 01 80 00 02 ff c0 61 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 168: (0) data v17-14400/hdlc-data + 3 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 169: IFP d0 01 20 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 169: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 170: IFP d0 01 80 00 02 ff c0 61 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 170: (0) data v17-14400/hdlc-data + 3 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 171: IFP d0 01 20 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 171: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 172: IFP d0 01 80 00 02 ff c0 61 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 172: (0) data v17-14400/hdlc-data + 3 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 173: IFP d0 01 40 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 173: (0) data v17-14400/hdlc-fcs-OK-sig-end + 0 byte(s) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK, sig end (clean) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 13 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_C_ECM_RX to T30_PHASE_D_RX -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 174: IFP 00 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 174: indicator no-signal -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 175: IFP 06 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 175: indicator v21-preamble -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 13 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 13 -[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2A -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 176: IFP c0 01 80 00 00 ff -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 176: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 177: IFP c0 01 80 00 00 c8 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 177: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 178: IFP c0 01 80 00 00 fd -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 178: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 179: IFP c0 01 80 00 00 f4 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 179: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 180: IFP c0 01 80 00 00 00 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 180: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 181: IFP c0 01 80 00 00 00 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 181: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 182: IFP c0 01 80 00 00 d0 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 182: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 183: IFP c0 01 40 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 183: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type PPS - CRC OK, sig end (clean) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2A (16960 remaining) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: PPS with final frame tag -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 13 bf 2f 00 00 0b -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 13 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Received PPS + EOP - page 0, block 0, 12 frames -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Partial page OK - committing block 0, 12 frames -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Page no = 1 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Image size = 1728 x 2292 pixels -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Image resolution = 8031/m x 7700/m -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Compression = T.6 (3) -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Compressed image size = 2998 bytes -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 13 to 14 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: MCF with final frame tag -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: ff 13 8c -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 14 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_RX to T30_PHASE_D_TX -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 4 -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present -[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 9: indicator v21-preamble -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 184: IFP 00 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 184: indicator no-signal -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 10: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 10: IFP c0 01 80 00 00 ff -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 11: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 11: IFP c0 01 80 00 00 c8 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 12: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 12: IFP c0 01 80 00 00 31 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_D_TX, state 14 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 13: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 13: IFP c0 01 40 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_D_TX, state 14 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_TX to T30_PHASE_D_RX -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T4 -[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 14: indicator no-signal -[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 185: IFP 06 -[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 185: indicator v21-preamble -[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present -[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 14 -[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 14 -[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T4A -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 186: IFP c0 01 80 00 00 ff -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 186: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 187: IFP c0 01 80 00 00 c8 -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 187: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 188: IFP c0 01 80 00 00 df -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 188: (0) data v21/hdlc-data + 1 byte(s) -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 189: IFP c0 01 40 -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 189: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type DCN - CRC OK, sig end (clean) -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T4A (15680 remaining) -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: DCN with final frame tag -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 13 fb -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 14 -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Disconnecting -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_RX to T30_PHASE_E -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 1 -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 14 to 2 -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 2 -[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present -[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_E, state 2 -[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 2 to 32 -[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_E to T30_PHASE_CALL_FINISHED -[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 9 -[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 9 -[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T FAX exchange complete diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 3de7b1d1753..67dcead4778 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -54,7 +54,7 @@ - \ref manager.c Main manager code file */ -#define AMI_VERSION "3.2.0" +#define AMI_VERSION "4.0.0" #define DEFAULT_MANAGER_PORT 5038 /* Default port for Asterisk management via TCP */ #define DEFAULT_MANAGER_TLS_PORT 5039 /* Default port for Asterisk management via TCP */ diff --git a/rest-api/resources.json b/rest-api/resources.json index df5b8d6fd06..920bb896d2a 100644 --- a/rest-api/resources.json +++ b/rest-api/resources.json @@ -2,7 +2,7 @@ "_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.", "_author": "David M. Lee, II ", "_svn_revision": "$Revision$", - "apiVersion": "2.0.0", + "apiVersion": "3.0.0", "swaggerVersion": "1.1", "basePath": "http://localhost:8088/ari", "apis": [ From ba52a36ff269ba7aa74915bac684d80cd2705223 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 21 Jul 2017 10:24:24 -0600 Subject: [PATCH 1385/1578] Restore the incorrectly deleted spandspflow2pcap.log Change-Id: Iafe78cf0fb1e7064223d4dea279eeb776c8fa8e5 --- contrib/scripts/spandspflow2pcap.log | 605 +++++++++++++++++++++++++++ 1 file changed, 605 insertions(+) create mode 100644 contrib/scripts/spandspflow2pcap.log diff --git a/contrib/scripts/spandspflow2pcap.log b/contrib/scripts/spandspflow2pcap.log new file mode 100644 index 00000000000..7ed0ed99afd --- /dev/null +++ b/contrib/scripts/spandspflow2pcap.log @@ -0,0 +1,605 @@ +[2015-12-02 11:55:55] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 0: indicator no-signal +[2015-12-02 11:55:55] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 1: indicator ced +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 2: IFP 00 +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 2: indicator no-signal +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 3: IFP 06 +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 3: indicator v21-preamble +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 1 +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 1 +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_A_CED to T30_PHASE_B_RX +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4 +[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 4: IFP c0 01 80 00 00 ff +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 4: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 5: IFP c0 01 80 00 00 c0 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 5: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 6: IFP c0 01 80 00 00 c2 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 6: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 7: IFP c0 01 80 00 00 76 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 7: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 8: IFP c0 01 80 00 00 ee +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 8: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 9: IFP c0 01 80 00 00 f6 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 9: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 10: IFP c0 01 80 00 00 76 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 10: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 11: IFP c0 01 80 00 00 d6 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 11: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 12: IFP c0 01 80 00 00 76 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 12: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 13: IFP c0 01 80 00 00 ae +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 13: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 14: IFP c0 01 80 00 00 04 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 14: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 15: IFP c0 01 80 00 00 04 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 15: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 16: IFP c0 01 80 00 00 04 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 16: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 17: IFP c0 01 80 00 00 04 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 17: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 18: IFP c0 01 80 00 00 04 +[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 18: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 19: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 19: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 20: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 20: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 21: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 21: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 22: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 22: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 23: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 23: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 24: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 24: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 25: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 25: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 26: IFP c0 01 80 00 00 04 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 26: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 27: IFP c0 01 20 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 27: (0) data v21/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type TSI - CRC OK (clean) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: TSI without final frame tag +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 43 6e 77 6f 6e 6b 6e 75 20 20 20 20 20 20 20 20 20 20 20 20 20 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Remote gave TSI as: "unknown" +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 28: IFP c0 01 80 00 00 ff +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 28: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 29: IFP c0 01 80 00 00 c8 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 29: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 30: IFP c0 01 80 00 00 c1 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 30: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 31: IFP c0 01 80 00 00 00 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 31: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 32: IFP c0 01 80 00 00 46 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 32: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 33: IFP c0 01 80 00 00 1f +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 33: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 34: IFP c0 01 80 00 00 22 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 34: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 35: IFP c0 01 40 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 35: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type DCS - CRC OK, sig end (clean) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: DCS with final frame tag +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 13 83 00 62 f8 44 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 1 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 DCS before DIS +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 DCS: +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ...0= Store and forward Internet fax (T.37): Not set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... .0..= Real-time Internet fax (T.38): Not set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... 0...= 3G mobile network: Not set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ..1.= Receive fax: Set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 ..10 00..= Selected data signalling rate: V.17 14400bps +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .1.. ....= R8x7.7lines/mm and/or 200x200pels/25.4mm: Set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 0... ....= 2-D coding: Not set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ..00= Recording width: 215mm +- 1% +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... 10..= Recording length: Unlimited +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .111 ....= Minimum scan line time: 0ms +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 1... ....= Extension indicator: Set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... ..0.= Compressed/uncompressed mode: Compressed +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... .1..= Error correction mode (ECM): ECM +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .... 0...= Frame size: 256 octets +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 .1.. ....= T.6 coding: Set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 0... ....= Extension indicator: Not set +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Selected compression T.6 (3) +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Get document at 14400bps, modem 7 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 1 to 7 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 7 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_B_RX to T30_PHASE_C_NON_ECM_RX +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 7 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 36: IFP 00 +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 36: indicator no-signal +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 37: IFP 1e +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 37: indicator v17-14400-long-training +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present +[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 38: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 38: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Non-ECM signal status is Training succeeded (-4) in state 7 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 39: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 39: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 40: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 40: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 41: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 41: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 42: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 42: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 43: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 43: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 44: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 44: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 45: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 45: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 46: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 46: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 47: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 47: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 48: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 48: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 49: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 49: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 50: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 50: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 51: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 51: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 52: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 52: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 53: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 53: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 54: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 54: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 55: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 55: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 56: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 56: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 57: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 57: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 58: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 58: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 59: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 59: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 60: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 60: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 61: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 61: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 62: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 62: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 63: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 63: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 64: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 64: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 65: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 65: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 66: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 66: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 67: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 67: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 68: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 68: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 69: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 69: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 70: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 70: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 71: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 71: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 72: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 72: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 73: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 73: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 74: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 74: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 75: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 75: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 76: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 76: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 77: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 77: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 78: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 78: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 79: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 79: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 80: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 80: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 81: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 81: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 82: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 82: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 83: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 83: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 84: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 84: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 85: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 85: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 86: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 86: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 87: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 87: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 88: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 88: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 89: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 89: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 90: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 90: (0) data v17-14400/t4-non-ecm-data + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 91: IFP d0 01 f0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 91: (0) data v17-14400/t4-non-ecm-sig-end + 54 byte(s) +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Receive complete in phase T30_PHASE_C_NON_ECM_RX, state 7 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Non-ECM signal status is Carrier down (-1) in state 7 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Trainability (TCF) test result - 23328 total bits. longest run of zeros was 23328 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_C_NON_ECM_RX to T30_PHASE_B_TX +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 4 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 7 to 8 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: CFR with final frame tag +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: ff 13 84 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 92: IFP 00 +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 92: indicator no-signal +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 2: indicator no-signal +[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 3: indicator v21-preamble +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 4: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 4: IFP c0 01 80 00 00 ff +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 5: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 5: IFP c0 01 80 00 00 c8 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 6: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 6: IFP c0 01 80 00 00 21 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_B_TX, state 8 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 7: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 7: IFP c0 01 40 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_B_TX, state 8 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 8 to 12 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_B_TX to T30_PHASE_C_ECM_RX +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 7 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 +[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 8: indicator no-signal +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 93: IFP 1c +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 93: indicator v17-14400-short-training +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (51520 remaining) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 94: IFP d0 01 80 00 35 ff c0 60 00 ff ff ff ff ff ff ff ff 2b 92 8a 4c c2 9d 8b 22 38 68 23 a8 22 87 0c 8e 90 60 81 21 10 c8 ea da b1 91 d5 06 e1 38 55 04 ed b6 b5 49 7b df c2 45 90 c9 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 94: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 95: IFP d0 01 80 00 35 17 45 d1 84 54 91 74 5d 18 45 2d 17 44 55 17 45 d1 74 5d 17 45 d1 74 5d 17 45 d1 74 76 24 8b a2 e8 c2 25 08 ba 2e 8b a2 e8 ba 2e 8b a2 e8 ba 2e 8b a3 b1 24 61 17 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 95: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 96: IFP d0 01 80 00 35 44 b1 17 45 d1 74 5d 17 45 d1 74 5d 17 45 d1 75 ed b2 ba 11 1c 8c 81 51 1c ce c1 51 1c 08 23 a2 2e 88 e1 9c 8e 8a 9a 08 49 98 28 71 11 11 11 11 11 06 76 a1 11 c3 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 96: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 97: IFP d0 01 80 00 35 39 1d 04 22 22 22 22 22 24 f6 a0 a1 c4 48 a3 94 06 50 e2 22 22 22 22 22 0f a4 08 a1 d0 41 46 10 51 a1 1c 47 1b c4 60 8a 1e 84 64 75 1f 77 8c 20 a2 d3 23 a4 1a 60 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 97: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 98: IFP d0 01 80 00 2b 8a 1d a0 dd 30 8a 1d f5 50 54 30 45 0e 30 45 0f 23 a0 a3 82 28 79 1d 61 06 3d db a2 3a b5 42 0e 23 50 8a 1f 11 84 50 ed 03 5a 54 11 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 98: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 99: IFP d0 01 20 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 99: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 00 ff ff ff ff ff ff ff ff d4 49 51 32 43 b9 d1 44 1c 16 c4 15 44 e1 30 71 09 06 81 84 08 13 57 5b 8d 89 ab 60 87 1c aa 20 b7 6d ad 92 de fb 43 a2 09 93 e8 a2 8b 21 2a 89 2e ba 18 a2 b4 e8 22 aa e8 a2 8b 2e ba e8 a2 8b 2e ba e8 a2 8b 2e 6e 24 d1 45 17 43 a4 10 5d 74 d1 45 17 5d 74 d1 45 17 5d 74 d1 c5 8d 24 86 e8 22 8d e8 a2 8b 2e ba e8 a2 8b 2e ba e8 a2 8b ae b7 4d 5d 88 38 31 81 8a 38 73 83 8a 38 10 c4 45 74 11 87 39 71 51 59 10 92 19 14 8e 88 88 88 88 88 60 6e 85 88 c3 9c b8 20 44 44 44 44 44 24 6f 05 85 23 12 c5 29 60 0a 47 44 44 44 44 44 f0 25 10 85 0b 82 62 08 8a 85 38 e2 d8 23 06 51 78 21 26 ae f8 ee 31 04 45 cb c4 25 58 06 51 b8 05 bb 0c 51 b8 af 0a 2a 0c a2 70 0c a2 f0 c4 05 c5 41 14 9e b8 86 60 bc db 45 5c ad 42 70 c4 0a 51 f8 88 21 0a b7 c0 5a 2a 88 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 0, length 256 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 100: IFP d0 01 80 00 35 ff c0 60 80 43 c5 25 0a 10 61 5c 10 63 41 56 1a d9 0d 04 2f b0 8a 1d 84 50 fd be de d2 d2 2a 11 1d 2e 15 dd 42 84 50 f5 23 ae d1 74 f4 28 a5 f5 7c 34 19 02 40 af +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 100: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 101: IFP d0 01 80 00 35 0c 6c 22 87 61 14 3e 11 50 10 ac 23 08 48 e8 ba ad 42 a1 e1 42 51 0c 78 8b 74 08 10 88 df 0e 18 22 87 84 50 f8 6e 11 43 bf 4a 29 74 93 8e 96 e1 14 3f bb f7 60 bd +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 101: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 102: IFP d0 01 80 00 35 84 50 ef 1a af fe 6b 0d 30 8a 1d 63 09 48 e8 22 87 56 ea f0 c8 31 6c 22 87 21 b2 24 75 8c 83 ec a0 a1 c8 6c 89 1d 48 3e ca 88 6c 86 c8 60 c1 52 32 49 35 d8 20 45 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 102: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 103: IFP d0 01 80 00 35 5a 61 06 d5 23 e8 fa 60 83 69 1e 47 d0 45 0e 10 45 5e 8f a3 e8 f2 19 5c a9 18 45 d1 74 47 44 74 47 44 74 47 44 74 47 44 74 47 58 22 9d 97 45 d1 74 47 44 74 47 44 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 103: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 104: IFP d0 01 80 00 2b 74 5d 17 40 8a 79 74 61 02 28 70 cb a2 ea 88 e8 5e 10 6f a1 1a 23 a3 09 b6 c4 5a 16 1d 08 8c c8 c0 72 28 1c e8 1a 44 69 11 c3 0a 77 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 104: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 105: IFP d0 01 20 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 105: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 01 c2 a3 a4 50 08 86 3a 08 c6 82 6a 58 9b b0 20 f4 0d 51 b8 21 0a bf 7d 7b 4b 4b 54 88 b8 74 a8 bb 42 21 0a af c4 75 8b 2e 2f 14 a5 af 3e 2c 98 40 02 f5 30 36 44 e1 86 28 7c 88 0a 08 35 c4 10 12 17 5d b5 42 85 87 42 8a 30 1e d1 2e 10 08 11 fb 70 18 44 e1 21 0a 1f 76 88 c2 fd 52 94 2e c9 71 69 87 28 fc dd ef 06 bd 21 0a f7 58 f5 7f d6 b0 0c 51 b8 c6 90 12 17 44 e1 6a 57 0f 13 8c 36 44 e1 84 4d 24 ae 31 c1 37 05 85 13 36 91 b8 12 7c 53 11 36 61 13 06 83 4a 4c 92 ac 1b 04 a2 5a 86 60 ab c4 17 5f 06 c1 96 78 e2 0b a2 70 08 a2 7a f1 c5 17 4f 98 3a 95 18 a2 8b 2e e2 22 2e e2 22 2e e2 22 2e e2 22 2e e2 1a 44 b9 e9 a2 8b 2e e2 22 2e e2 22 2e ba e8 02 51 9e 2e 86 40 14 0e d3 45 57 11 17 7a 08 f6 85 58 c4 c5 90 6d 23 5a 68 b8 10 31 13 03 4e 14 38 17 58 22 96 88 c3 50 ee +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 1, length 256 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 106: IFP d0 01 80 00 35 ff c0 60 40 40 53 3a a2 3a 23 82 82 3a 29 03 90 60 e4 74 77 c0 a6 49 a2 38 30 47 44 59 11 c3 61 1d 12 e0 a6 8a 1d 0b 84 8b a0 45 45 54 8e 82 42 21 d2 08 a1 d2 28 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 106: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 107: IFP d0 01 80 00 35 74 b4 e1 c3 08 28 b6 d0 71 11 06 99 1d 21 a6 08 12 11 61 05 11 64 75 0c 58 20 8a 76 d0 88 45 3c 8e 9d c5 a0 8a 79 1d 3b 45 d0 b0 db ea 94 45 50 52 3a 4d 76 e2 35 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 107: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 108: IFP d0 01 80 00 35 41 18 42 d0 48 ba 1b 7c 24 5d 0d aa 42 d5 6f c1 14 3e db 6c 8e ae c2 64 74 08 a1 de 23 b8 b7 db 8b bd 58 45 0e eb f1 d0 41 91 d5 d2 40 87 1e 77 a2 23 ad 69 14 3d +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 108: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 109: IFP d0 01 80 00 35 25 c8 e9 57 1a bf 69 ec 6d 82 28 74 e9 91 d2 78 8b 7b 63 be e3 b6 df d6 81 14 3a 5b 76 b4 c2 5a 54 11 43 d9 0c 3d 68 22 87 6b 09 a5 ef bb 76 c3 4a ec 8e bf a1 78 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 109: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 110: IFP d0 01 80 00 2b 4e c3 a1 77 23 a0 8a 1e 11 43 dc 8e bd 6b 4a 92 a4 08 a1 d8 45 0f d5 48 e8 fa 23 a2 3a 08 a1 ed 17 5e 47 44 74 47 44 74 5d 29 a2 23 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 110: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 111: IFP d0 01 20 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 111: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 02 02 ca 5c 45 5c c4 41 41 5c 94 c0 09 06 27 2e ee 03 65 92 45 1c 0c e2 22 9a 88 c3 86 b8 48 07 65 51 b8 d0 21 d1 05 a2 a2 2a 71 41 42 84 4b 10 85 4b 14 2e 2d 87 c3 10 14 6d 0b 8e 88 60 99 b8 84 65 10 48 88 86 a0 88 26 ae 30 1a 04 51 6e 0b 11 a2 3c 71 b9 a3 05 51 9e b8 dc a2 0b 0d db 57 29 a2 0a 4a 5c b2 6e 47 ac 82 18 42 0b 12 5d d8 3e 24 ba b0 55 42 ab f6 83 28 7c db 36 71 75 43 26 2e 10 85 7b c4 1d ed db d1 bd 1a a2 70 d7 8f 0b 82 89 ab 4b 02 e1 78 ee 45 c4 b5 96 28 bc a4 13 97 ea 58 fd 96 37 b6 41 14 2e 97 89 4b 1e d1 de c6 7d c7 6d fb 6b 81 28 5c da 6e 2d 43 5a 2a 88 c2 9b 30 bc 16 44 e1 d6 90 a5 f7 dd 6e c3 52 37 71 fd 85 1e 72 c3 85 ee c4 05 51 78 88 c2 3b 71 bd d6 52 49 25 10 85 1b a2 f0 ab 12 17 5f c4 45 5c 10 85 b7 e8 7a e2 22 2e e2 22 2e ba 94 45 c4 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 2, length 256 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 112: IFP d0 01 80 00 35 ff c0 60 c0 a2 3a 2e 82 28 7d 97 44 74 47 44 74 5d 34 5d 1e 44 74 47 44 74 3a 19 1d 11 d1 1d 11 d1 75 b0 8a 1d d8 45 0e ed 86 1b 23 aa 23 a7 61 b7 db 42 10 4c 43 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 112: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 113: IFP d0 01 80 00 35 08 21 6c 22 9c 21 c2 28 71 11 10 cc 22 3a 68 ba 08 28 88 63 c4 44 58 91 d1 75 88 41 31 16 11 4e e2 22 21 97 44 75 48 6a 9a ae e8 70 90 4b 04 50 eb 6c 11 43 a1 12 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 113: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 114: IFP d0 01 80 00 35 3a c6 0c 71 6c 11 51 43 1a 6c 52 8c 6f ff 6d ad c3 7c 6b 23 a0 45 0e c5 ca 74 5d 0e 83 23 a2 ea c1 14 3b 08 a1 db 64 74 61 64 74 83 6e 0c 8e b9 1d 04 50 f2 3a c2 +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 114: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 115: IFP d0 01 80 00 35 ee 8a 1e 47 41 14 3a a4 95 a0 aa 2d e2 3c 62 47 49 36 35 16 91 85 88 45 0e 9a b2 eb 89 c4 47 0a e2 db b4 47 41 14 3c 5b 8a 6a c8 ea ee 9f 08 a1 df 21 aa e5 6c 3d +[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 115: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 116: IFP d0 01 80 00 2b f1 0c 76 c2 28 7c 43 23 ae f9 ad 1d 01 70 a0 ca e2 04 0b e3 3b ad 1c 02 0d a3 68 da 36 82 28 77 08 19 56 50 e4 33 d9 56 55 95 65 6c +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 116: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 117: IFP d0 01 20 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 117: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 03 45 5c 74 41 14 be e9 22 2e e2 22 2e ba 2c ba 78 22 2e e2 22 2e 5c 98 b8 88 8b b8 88 8b ae 0d 51 b8 1b a2 70 b7 61 d8 c4 55 c4 e5 86 ed db 42 08 32 c2 10 84 36 44 39 84 43 14 8e 88 08 33 44 5c 16 5d 10 14 11 c6 23 22 1a 89 8b ae 11 82 8c 68 88 72 47 44 84 e9 22 ae 12 56 59 75 17 0e 09 d2 20 0a d7 36 88 c2 85 48 5c 63 30 8e 36 88 8a c2 58 36 4a 31 f6 ff b6 b5 c3 3e d6 c4 05 a2 70 a3 53 2e ba 70 c1 c4 45 57 83 28 dc 10 85 db 26 2e 86 26 2e c1 76 30 71 9d b8 20 0a 4f 5c 43 77 51 78 e2 82 28 5c 25 a9 05 55 b4 47 3c 46 e2 92 6c ac 68 89 a1 11 a2 70 59 4d d7 91 23 e2 50 47 db 2d e2 82 28 3c da 51 56 13 57 77 f9 10 85 fb 84 55 a7 36 bc 8f 30 6e 43 14 3e c2 c4 75 9f b5 b8 80 0e 05 53 47 20 d0 c7 dc b5 38 40 b0 c5 16 5b 6c 41 14 ee 10 98 6a 0a 27 cc 9b 6a aa a9 a6 36 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 3, length 256 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 118: IFP d0 01 80 00 35 ff c0 60 20 4c a1 d1 75 a7 5c 3a 5d 3f 1c 8e ae e4 74 9e 08 10 98 45 d1 74 11 4f 90 d1 46 08 10 84 54 23 68 ba 2e 8b a2 e8 ba 2e 91 50 74 ed c1 02 10 8a 74 08 10 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 118: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 119: IFP d0 01 80 00 35 88 89 74 c8 67 43 90 60 38 20 42 21 84 08 10 88 88 d0 ee fd 91 d5 f6 d9 1d 5d dd c2 28 78 84 50 f0 8a 1e 22 22 2e 91 74 8a 1d 08 d0 88 88 88 88 40 83 29 ca 20 a7 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 119: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 120: IFP d0 01 80 00 35 48 21 16 84 42 08 c2 0f 91 d0 45 42 23 a1 c4 ed 4d 05 49 42 28 7f 69 75 74 92 a6 47 51 86 39 1d 0d db 42 2f 62 22 2d 87 b7 10 8a 77 88 a2 85 ae f8 df 64 74 42 03 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 120: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 121: IFP d0 01 80 00 35 5b ee 11 43 86 47 44 18 35 ee ed d2 4d 05 54 5d 3d 06 9a a0 82 16 b1 2e 8b ac 11 43 85 e9 71 85 f5 1b 4f f8 77 76 f5 16 ec 22 87 61 14 eb 61 3e 47 42 3b 57 bf 91 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 121: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 122: IFP d0 01 80 00 2b d5 de dc 34 fb ef 91 d2 91 d1 84 92 c2 a4 87 1a 5c 8e 8d 49 3b c1 14 3a 4b d6 f4 b4 92 ad 2f b8 d8 ed ee e4 11 17 44 74 47 44 74 47 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 122: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 123: IFP d0 01 20 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 123: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 04 32 85 8b ae e5 3a 5c ba fc 38 71 75 27 2e 79 10 08 19 a2 8b 2e 88 f2 09 8b 62 10 08 21 2a c4 16 5d 74 d1 45 17 5d 74 89 0a 2e b7 83 40 08 51 2e 10 08 11 91 2e 13 e6 c2 09 06 1c 04 42 84 21 10 08 11 11 0b 77 bf 89 ab 6f 9b b8 ba bb 43 14 1e 21 0a 0f 51 78 44 44 74 89 2e 51 b8 10 0b 11 11 11 11 02 c1 94 53 04 e5 12 84 68 21 42 10 43 f0 89 0b a2 42 c4 85 23 b7 b2 a0 92 42 14 fe 96 ae 2e 49 65 e2 8a 61 9c b8 b0 db 42 f4 46 44 b4 e1 ed 08 51 ee 11 45 a1 75 1f fb 26 2e 42 c0 da 77 88 c2 61 e2 22 18 ac 77 b7 4b b2 a0 2a ba bc 60 59 05 41 68 8d 74 d1 35 88 c2 a1 97 8e a1 af d8 f2 1f ee 6e af 68 37 44 e1 86 28 d7 86 7c e2 42 dc ea fd 89 ab 7b 3b 2c df f7 89 4b 89 8b 21 49 43 25 e1 58 3a 71 b1 92 dc 83 28 5c d2 6b 2f 2d 49 b5 f4 1d 1b b7 77 27 88 e8 22 2e e2 22 2e e2 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 4, length 256 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 124: IFP d0 01 80 00 35 ff c0 60 a0 44 74 47 44 74 08 a1 ee 47 4d c4 19 1d 11 d1 1d 11 d1 1d 04 14 6c 86 c1 ca 72 8a ed b6 d0 45 0e dd bd b7 76 1f be e4 75 08 a1 e4 75 91 d5 17 55 45 d2 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 124: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 125: IFP d0 01 80 00 35 e0 81 31 11 11 11 11 a4 34 84 44 44 46 85 89 1d 60 8a 1c 2a c6 b4 50 f2 3a 5a 4b 7f d4 22 87 71 bb 08 a1 d8 dd 8b 76 21 43 db b0 7b 0b c1 14 fc 49 01 a4 de e1 14 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 125: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 126: IFP d0 01 80 00 35 3b 2a 03 4e f6 9c 48 61 a4 47 55 04 50 f1 a4 92 49 22 52 82 c2 49 58 64 75 82 28 74 a4 75 42 b9 02 46 11 38 66 52 b4 d1 ad 18 44 e1 97 5a 82 29 e6 a4 61 13 86 64 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 126: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 127: IFP d0 01 80 00 35 38 b9 1d 53 bb b6 10 4e ef 84 50 e3 2e b6 8b a6 c3 de 22 11 57 23 ad c8 e9 a2 3a c4 4f 24 54 07 76 1a 1a 11 45 47 69 84 50 f2 3a fe 9c 22 9d 78 86 32 3a c1 14 3c +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 127: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 128: IFP d0 01 80 00 2b 76 15 62 11 56 d6 c1 15 08 71 14 54 2e 83 09 48 e8 a8 42 8a 89 1d 42 28 77 b8 de 11 43 bb 04 50 f1 c8 ea f0 8a 71 91 d5 b0 b1 08 a1 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 128: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 129: IFP d0 01 20 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 129: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 05 22 2e e2 22 2e 10 85 77 e2 b2 23 98 b8 88 8b b8 88 8b b8 20 28 36 61 83 53 4e 51 b7 6d 0b a2 70 bb bd ed 6e f8 7d 27 ae 10 85 27 ae 89 ab e8 aa a2 4b 07 81 8c 88 88 88 88 25 2c 21 22 22 62 a1 91 b8 06 51 38 54 63 2d 0a 4f 5c 5a d2 fe 2b 44 e1 8e dd 10 85 1b bb d1 6e 84 c2 db 0d de d0 83 28 3f 92 80 25 7b 87 28 dc 54 c0 72 6f 39 12 86 25 e2 aa 20 0a 8f 25 49 92 44 4a 41 43 92 1a 26 ae 41 14 2e 25 ae 42 9d 40 62 88 1c 66 4a 2d 8b b5 18 22 87 e9 5a 41 94 67 25 86 c8 61 26 1c 9d b8 ca dd 6d 08 72 f7 21 0a c7 74 6d d1 65 c3 7b 44 88 ea c4 b5 13 97 45 5c 23 f2 24 2a e0 6e 58 58 88 a2 e2 96 21 0a 4f 5c 7f 39 44 b9 1e 61 4c 5c 83 28 3c 6e a8 46 88 6a 6b 83 a8 10 8e 28 2a 74 c1 90 12 17 15 42 51 91 b8 42 14 ee 1d 7b 88 c2 dd 20 0a 8f 13 57 0f 51 8e 89 ab 0d 8d 10 85 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 5, length 256 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 130: IFP d0 01 80 00 35 ff c0 60 60 f9 17 42 11 59 7c 42 2b 48 83 d6 11 47 2a 22 22 7c 33 c6 3d 2c 69 27 51 4b 1b a0 45 0e 94 cd 1b 43 e2 2f a8 9b 40 8a 1e 1f c8 e8 4d a1 57 b8 22 9e fe +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 130: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 131: IFP d0 01 80 00 35 e0 8a 7b 0d bb 6c 8e b6 9b 23 a1 1b c2 29 fb 91 d0 8b 61 14 ed bc 46 c2 29 f5 15 d5 71 50 45 0e 8c 2a a0 d9 75 82 28 74 5d 50 82 28 75 8b d6 34 34 95 84 50 e8 5e +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 131: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 132: IFP d0 01 80 00 35 df 6d b7 6a c3 1f 0d 8e 34 36 3e d8 68 8e a1 ab 61 85 64 74 38 45 3f a4 95 24 90 55 5c 11 58 c8 eb 04 50 e1 29 1d 6a 11 43 a1 14 81 14 3f 1a 10 45 0f 1f 16 f6 ed +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 132: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 133: IFP d0 01 80 00 35 bc 36 f1 0d ee d8 22 87 b8 ed 91 d0 ee d8 dd d2 f2 eb ac 22 87 55 41 15 0f 04 50 eb 1f f1 ae c2 55 7b b1 bb c2 09 b2 ea da 23 a1 08 ab 76 c2 61 af 76 a4 75 84 50 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 133: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 134: IFP d0 01 80 00 2b ed fe 96 95 22 1b 03 8a 62 b2 0b ee 9a a4 ab a7 51 08 a1 e3 4a bb 6e 1b ec 11 b4 61 3a 0d e8 c2 26 88 3e 11 43 dc 22 87 e1 14 3c 22 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 134: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 135: IFP d0 01 20 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 135: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 06 9f e8 42 88 9a 3e 42 d4 12 c1 6b 88 e2 54 44 44 3e cc 63 bc 34 96 e4 8a d2 d8 05 a2 70 29 b3 d8 c2 47 f4 15 d9 02 51 78 f8 13 17 b2 85 ea 1d 44 79 7f 07 51 de b0 dd 36 71 6d d9 c4 85 d8 43 94 df 89 0b d1 86 28 b7 3d 62 43 94 af a8 ab 8e 0a a2 70 31 54 05 9b ae 41 14 2e ba 0a 41 14 ae d1 6b 2c 2c a9 21 0a 17 7a fb b6 ed 56 c3 f8 b0 71 2c 6c 7c 1b 16 71 85 d5 86 a1 26 2e 1c a2 fc 25 a9 24 09 aa 3a 88 1a 13 d7 20 0a 87 94 b8 56 88 c2 85 28 81 28 fc 58 08 a2 f0 f8 68 6f b7 3d 6c 8f b0 77 1b 44 e1 1d b7 89 0b 77 1b bb 4b 4f d7 35 44 e1 aa 82 a8 f0 20 0a d7 f8 8f 75 43 aa de 8d dd 43 90 4d 57 5b c4 85 10 d5 6e 43 86 f5 6e 25 ae 21 0a b7 7f 69 a9 44 d8 c0 51 46 4d d0 77 59 25 d5 e5 8a 10 85 c7 52 dd 76 d8 37 88 2d 86 5c b0 17 43 64 11 7c 88 c2 3b 44 e1 87 28 3c 44 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 6, length 256 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 136: IFP d0 01 80 00 35 ff c0 60 e0 87 6e d4 3d ec 82 81 d5 6a a9 02 04 22 11 43 c2 28 75 a8 41 09 18 8b a2 e8 84 46 10 f6 d5 be e3 82 28 74 5d 12 11 26 82 91 d5 02 28 74 4b 10 58 45 0f +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 136: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 137: IFP d0 01 80 00 35 7d cb a6 db b1 1d b2 3a b2 3a 3a 22 e8 ba 63 38 85 84 25 d0 41 34 61 3e 47 47 44 5d 17 49 36 47 49 17 59 50 88 e8 8e 88 e8 83 41 5b 23 a6 c4 20 84 ba 2e 87 16 cb +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 137: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 138: IFP d0 01 80 00 35 a1 a3 a2 23 a2 3a 23 a0 82 78 d2 4b 0e aa b5 14 c5 21 60 c4 90 81 03 10 82 88 62 47 4f 62 29 04 50 e8 22 9d 82 28 74 38 20 4c 62 47 41 04 e9 82 28 70 81 02 68 4d +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 138: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 139: IFP d0 01 80 00 35 68 15 b1 3e 82 91 d0 20 4c 62 47 42 bc 39 1d 37 64 74 47 4b 6d 91 d7 21 88 6d 91 d1 a2 04 09 03 23 a0 8a 1c 33 08 ba 04 09 94 38 6c 31 27 41 14 3b 86 47 46 88 b9 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 139: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 140: IFP d0 01 80 00 2b 91 d3 44 74 30 c8 e9 c8 eb 65 0e 18 97 41 04 e1 b2 3a 08 27 14 19 1d 11 d1 74 10 43 c3 23 a6 84 42 0c 4b a3 a2 0b 5c 69 14 38 c4 8e +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 140: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 141: IFP d0 01 20 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 141: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 07 e1 76 2b bc 37 41 81 ab 56 95 40 20 44 88 c2 43 14 ae 15 82 90 18 d1 45 17 21 62 08 6f ab 7d c7 41 14 2e ba 48 88 64 41 89 ab 40 14 2e d2 08 1a a2 f0 be d3 65 db 8d b8 4d 5c 4d 5c 5c 44 17 5d c6 1c a1 21 a4 0b 82 2c 86 7c e2 e2 22 ba e8 92 6c e2 92 e8 9a 0a 11 17 71 11 17 c1 82 da c4 65 23 04 21 5d 74 e1 68 d3 85 c5 45 c4 45 5c c4 05 41 1e 4b d2 70 55 ad 28 a3 84 06 23 09 81 c0 08 41 11 46 e2 f2 46 94 20 0a 17 44 b9 41 14 2e 1c 04 32 46 e2 82 20 97 41 14 0e 81 40 16 b2 16 a8 8d 7c 41 89 0b 04 32 46 e2 42 3d 9c b8 ec 26 2e e2 d2 b6 89 eb 84 11 b6 89 8b 45 20 90 c0 c4 05 51 38 cc 10 5d 20 90 29 1c 36 8c e4 82 28 dc 61 e2 62 11 9d 89 cb 22 2e 0c 13 97 13 d7 a6 70 18 e9 82 20 87 4d 5c 10 e4 28 98 b8 88 8b 2e 08 c2 c3 c4 65 21 42 30 d2 c5 45 d0 3a 96 28 1c 23 71 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 7, length 256 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 142: IFP d0 01 80 00 35 ff c0 60 10 8b a5 49 0c 8e 8c 22 e8 ba 50 8a 1e e4 75 65 d1 74 08 13 16 2c 31 10 82 10 87 06 47 45 d0 41 0a 15 65 d1 74 08 14 5a 65 d1 74 47 45 d1 74 5d 17 45 d1 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 142: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 143: IFP d0 01 80 00 35 74 5d 26 5d 02 42 44 23 08 c2 04 50 f2 3a 2e 98 31 23 a2 3a 2e 8b a6 a3 04 09 a0 45 0e 23 48 ba 23 a2 3a 08 21 04 82 29 d9 74 08 a1 e0 8a 1c 18 91 d1 1d 11 d1 74 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 143: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 144: IFP d0 01 80 00 35 47 41 05 15 6d f1 62 23 6d 88 88 8d c2 29 dc 44 47 11 71 11 1b 11 11 71 11 11 11 11 10 c8 e8 31 16 10 88 88 89 16 65 0e 22 22 29 88 c8 e9 88 88 88 c8 e8 62 22 c6 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 144: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 145: IFP d0 01 80 00 35 22 22 22 2a d2 4a b5 82 28 74 2d 91 d6 47 48 a1 d0 45 0f 5b a5 68 ba 51 08 a1 d0 c2 09 70 d3 61 bf 76 ec 5c 76 ef bc 5a 69 dc ba 84 53 a7 23 aa a5 54 12 fa 54 ad +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 145: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 146: IFP d0 01 80 00 2b 61 14 3a 7d 20 90 c7 23 ac 6d db 0f 86 1b b7 7b fb 74 47 54 47 41 b7 a8 aa 4b 5a 54 e1 14 3a a4 50 f2 3a d1 4e 12 c2 68 42 28 74 2c +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 146: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 147: IFP d0 01 20 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 147: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 08 d1 a5 92 30 71 31 44 17 5d 0a 51 78 27 ae a6 8b 2e 10 c8 68 34 8c 08 41 08 e1 60 e2 a2 0b 82 50 a8 a6 8b 2e 10 28 5a a6 8b 2e e2 a2 8b 2e ba e8 a2 8b 2e ba 64 ba 40 42 22 c4 10 43 20 0a 4f 5c 74 19 8c c4 45 5c 74 d1 65 c5 20 90 05 a2 70 c4 12 5d c4 45 5c 10 84 20 41 94 9b 2e 10 85 07 51 38 18 89 8b b8 88 8b 2e e2 82 a0 a8 b6 8f 46 c4 b6 11 11 b1 43 94 3b 22 e2 88 8e 88 d8 88 88 8e 88 88 88 88 08 13 17 8c 68 08 11 11 91 68 a6 70 44 44 94 11 13 97 11 11 11 13 17 46 44 63 44 44 44 54 4b 52 ad 41 14 2e b4 89 6b e2 12 85 0b a2 f0 da a5 16 5d 8a 10 85 0b 43 90 0e cb 86 fd 6e 37 3a 6e f7 3d 5a 96 3b 5d 21 ca e5 c4 55 a5 2a 48 5f 2a b5 86 28 5c be 04 09 e3 c4 35 b6 db f0 61 d8 ed de df 2e e2 2a e2 82 ed 15 55 d2 5a 2a 87 28 5c 25 0a 4f 5c 8b 72 48 43 16 42 14 2e 34 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 8, length 256 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 148: IFP d0 01 80 00 35 ff c0 60 90 2a 87 69 c3 76 ee 47 4c 3b 10 f4 2d e2 d3 d0 45 45 da ad 3e d5 04 53 ca 12 42 8a 1d 04 53 ae b5 5d 04 35 09 14 3a 41 72 3a bb 7b 16 85 45 b2 3a 17 0d +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 148: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 149: IFP d0 01 80 00 35 b4 47 4d 38 6b 72 3a 69 a1 da 23 aa 42 8a 1d 24 ea 8a 1e 12 4d 5a 48 5d 5a 2e 95 84 28 a1 d2 4c 2a 1b 8e e1 15 09 c5 b6 88 e8 36 0e 11 50 81 84 db 86 10 bc 21 0c +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 149: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 150: IFP d0 01 80 00 35 20 c2 30 83 09 85 69 f1 0e 47 54 18 4a 3b 42 1a 2e 83 08 c2 08 a7 0b 0c 2d 14 38 46 13 09 82 10 d3 08 c2 e4 74 11 4e ad a1 b7 6a c2 29 d0 45 3a 08 21 08 a7 40 81 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 150: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 151: IFP d0 01 80 00 35 08 86 b0 8a 74 5d 62 1a 10 d1 74 11 4e 88 e9 a2 3a 08 a8 08 74 23 45 d2 41 15 01 34 08 ab 08 c2 a6 10 86 10 86 10 88 68 51 43 84 61 24 34 2d 22 9c 10 45 3a 11 06 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 151: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 152: IFP d0 01 80 00 2b 10 82 2a c2 11 45 38 45 d4 1a 06 08 5c 4c c1 c9 08 22 9c 21 45 79 06 0e 08 41 84 61 04 55 82 08 ae 20 88 28 21 53 20 9e 52 b2 bc 83 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 152: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 153: IFP d0 01 20 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 153: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 09 54 e1 96 c3 6e 77 e2 32 dc 08 2f b4 47 cb 0b a2 a2 5b b5 7c ab 20 ca 53 48 42 51 b8 20 ca 75 ad ba 20 ac 90 28 5c 82 4e 5c dd de 68 a1 a2 4d 5c e8 b0 2d e2 b2 1c d6 4e 5c 96 85 5b c4 55 42 51 b8 24 57 51 78 48 b2 5a 12 ba 5a 74 a9 21 14 85 4b 32 54 d8 71 87 a8 90 a3 6d 11 17 6c 70 88 0a 81 21 db 61 08 3d 84 30 04 43 0c c1 90 a1 96 8f 70 e2 2a 18 52 dc 42 58 74 c1 10 43 10 e5 d0 30 b4 28 1c 62 c8 90 41 08 cb 10 43 27 2e 88 72 b5 85 ed 56 43 94 0b a2 5c 10 84 10 e5 02 81 10 61 0d 51 2e ba 46 58 08 8b 2e 88 72 11 97 45 5c 10 15 10 2e c4 a2 4b 82 a8 80 2c 10 d5 10 43 65 08 61 08 61 08 11 16 8a c2 21 86 24 2c b4 44 39 08 a2 5c 88 60 08 41 54 43 88 a2 1c a2 2b 58 60 10 3a 32 83 93 10 44 39 84 a2 9e 60 70 10 82 21 86 20 aa 41 10 75 04 11 14 84 ca 04 79 4a 4d 3d c1 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 9, length 256 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 154: IFP d0 01 80 00 35 ff c0 60 50 ac 90 7d 83 08 8d 05 38 82 29 c2 12 70 c0 9f 08 46 d2 2a 64 1f 65 a5 61 08 58 43 0b d6 22 47 41 48 d2 08 aa 8a 82 a4 90 a2 e5 39 52 17 2a a2 a0 a1 32 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 154: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 155: IFP d0 01 80 00 35 ab 28 50 a4 e5 59 40 a5 56 55 94 df 8a 72 93 95 05 6c a0 ad 0a 82 84 8a 72 aa 2a 0a d9 51 41 95 05 0d 14 e5 27 2a 0a 5d 02 d8 88 88 88 88 88 88 88 88 88 88 88 88 +[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 155: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 156: IFP d0 01 80 00 35 88 88 88 88 88 8c ae 28 8b a0 94 20 9b 23 a2 3a 7b 18 82 28 7c 11 43 86 47 45 d3 71 88 65 d0 4a 84 7a dd 05 6a 14 8e ad 0f 84 53 a8 d1 75 0c 21 86 8b a8 68 60 8a +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 156: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 157: IFP d0 01 80 00 35 b0 8b a8 84 52 61 58 9f 46 14 47 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 157: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 158: IFP d0 01 80 00 2b ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 158: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 159: IFP d0 01 20 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 159: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 0a 35 09 be c1 10 b1 a0 1c 41 94 43 48 0e 03 f9 10 62 4b 54 26 f8 a6 a5 86 10 1a c2 d0 6b 44 e2 82 12 4b 10 55 51 41 25 09 45 a7 9c 4a e8 54 45 05 85 4c d5 14 0a 25 a7 9a 02 a5 6a aa 29 fb 51 4e c9 a9 a0 36 05 b5 50 41 21 51 4e 55 54 50 9b 8a 82 a9 a0 b0 28 a7 e4 54 50 ba 40 1b 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 31 75 14 d1 05 29 04 d9 c4 45 5c de 18 41 14 3e 88 c2 61 e2 a2 cb 8e 11 a6 0b 52 21 5e bb a0 56 28 71 b5 f0 21 ca 15 8b ae 30 84 61 d1 15 16 06 51 0d d1 15 21 4a 86 1a f9 62 28 e2 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 10, length 256 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 160: IFP d0 01 80 00 35 ff c0 60 d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 160: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 161: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 161: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 162: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 162: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 163: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff fe 00 20 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 163: (0) data v17-14400/hdlc-data + 54 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 164: IFP d0 01 80 00 2b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 164: (0) data v17-14400/hdlc-data + 44 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 165: IFP d0 01 20 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 165: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: FCD without final frame tag +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 06 0b ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 7f 00 04 c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 11, length 256 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 166: IFP d0 01 80 00 02 ff c0 61 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 166: (0) data v17-14400/hdlc-data + 3 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 167: IFP d0 01 20 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 167: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 12 to 13 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 168: IFP d0 01 80 00 02 ff c0 61 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 168: (0) data v17-14400/hdlc-data + 3 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 169: IFP d0 01 20 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 169: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 170: IFP d0 01 80 00 02 ff c0 61 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 170: (0) data v17-14400/hdlc-data + 3 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 171: IFP d0 01 20 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 171: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 172: IFP d0 01 80 00 02 ff c0 61 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 172: (0) data v17-14400/hdlc-data + 3 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 173: IFP d0 01 40 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 173: (0) data v17-14400/hdlc-fcs-OK-sig-end + 0 byte(s) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK, sig end (clean) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining) +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: RCP without final frame tag +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 03 86 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 13 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_C_ECM_RX to T30_PHASE_D_RX +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 174: IFP 00 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 174: indicator no-signal +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 175: IFP 06 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 175: indicator v21-preamble +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 13 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 13 +[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2A +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 176: IFP c0 01 80 00 00 ff +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 176: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 177: IFP c0 01 80 00 00 c8 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 177: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 178: IFP c0 01 80 00 00 fd +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 178: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 179: IFP c0 01 80 00 00 f4 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 179: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 180: IFP c0 01 80 00 00 00 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 180: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 181: IFP c0 01 80 00 00 00 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 181: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 182: IFP c0 01 80 00 00 d0 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 182: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 183: IFP c0 01 40 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 183: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type PPS - CRC OK, sig end (clean) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2A (16960 remaining) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: PPS with final frame tag +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 13 bf 2f 00 00 0b +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 13 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Received PPS + EOP - page 0, block 0, 12 frames +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Partial page OK - committing block 0, 12 frames +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Page no = 1 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Image size = 1728 x 2292 pixels +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Image resolution = 8031/m x 7700/m +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Compression = T.6 (3) +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Compressed image size = 2998 bytes +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 13 to 14 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: MCF with final frame tag +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx: ff 13 8c +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 14 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_RX to T30_PHASE_D_TX +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 4 +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present +[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 9: indicator v21-preamble +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 184: IFP 00 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 184: indicator no-signal +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 10: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 10: IFP c0 01 80 00 00 ff +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 11: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 11: IFP c0 01 80 00 00 c8 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 12: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 12: IFP c0 01 80 00 00 31 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_D_TX, state 14 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 13: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 13: IFP c0 01 40 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_D_TX, state 14 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_TX to T30_PHASE_D_RX +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T4 +[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx 14: indicator no-signal +[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 185: IFP 06 +[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 185: indicator v21-preamble +[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present +[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 14 +[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 14 +[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T4A +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 186: IFP c0 01 80 00 00 ff +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 186: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 187: IFP c0 01 80 00 00 c8 +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 187: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 188: IFP c0 01 80 00 00 df +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 188: (0) data v21/hdlc-data + 1 byte(s) +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 189: IFP c0 01 40 +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx 189: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s) +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type DCN - CRC OK, sig end (clean) +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T4A (15680 remaining) +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: DCN with final frame tag +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx: ff 13 fb +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 14 +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Disconnecting +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_RX to T30_PHASE_E +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0 +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 1 +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 14 to 2 +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 2 +[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present +[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_E, state 2 +[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 2 to 32 +[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_E to T30_PHASE_CALL_FINISHED +[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 9 +[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 9 +[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T FAX exchange complete From 063c9a935f2133e1726ce0851935745118ca04cd Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 21 Jul 2017 10:17:38 -0600 Subject: [PATCH 1386/1578] Update make_ari_stubs in master to make the version 16 Ready for next major version Change-Id: If9dc99b3b78768529e69a297d8f87e23582ca6d0 --- rest-api-templates/make_ari_stubs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-api-templates/make_ari_stubs.py b/rest-api-templates/make_ari_stubs.py index 4e02cdd5ff5..0aba06d6d2a 100755 --- a/rest-api-templates/make_ari_stubs.py +++ b/rest-api-templates/make_ari_stubs.py @@ -41,7 +41,7 @@ def rel(file): """ return os.path.join(TOPDIR, file) -WIKI_PREFIX = 'Asterisk 13' +WIKI_PREFIX = 'Asterisk 16' API_TRANSFORMS = [ Transform(rel('api.wiki.mustache'), From a2f6028a516cba8f7a95f2f286add0555fac8a67 Mon Sep 17 00:00:00 2001 From: Rusty Newton Date: Fri, 21 Jul 2017 14:20:10 -0500 Subject: [PATCH 1387/1578] Sounds: Update Makefile for Extra sounds 1.5.1 release Incrementing version for the Extra sounds release. 1.5.1 Extra sounds removes two prompts that were moved into the Core packages in the 1.6 Core sounds release. ASTERISK-27142 #close Change-Id: I82f017812b0ea9599e19dd4635afd55611f13ee7 --- sounds/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sounds/Makefile b/sounds/Makefile index 9dfd0c61c8e..381776f7233 100644 --- a/sounds/Makefile +++ b/sounds/Makefile @@ -20,7 +20,7 @@ SOUNDS_DIR:=$(DESTDIR)$(ASTDATADIR)/sounds SOUNDS_CACHE_DIR?= MOH_DIR:=$(DESTDIR)$(ASTDATADIR)/moh CORE_SOUNDS_VERSION:=1.6 -EXTRA_SOUNDS_VERSION:=1.5 +EXTRA_SOUNDS_VERSION:=1.5.1 MOH_VERSION:=2.03 SOUNDS_URL:=http://downloads.asterisk.org/pub/telephony/sounds/releases MCS:=$(subst -EN-,-en-,$(MENUSELECT_CORE_SOUNDS)) From 19b080b54749a9c89003bc749de36e77fdaa9cc1 Mon Sep 17 00:00:00 2001 From: Rusty Newton Date: Fri, 14 Jul 2017 13:47:50 -0500 Subject: [PATCH 1388/1578] say.c: Fix file locations for second, seconds, minute, minutes files The seconds and minutes files have always existed in the base language directory of the Core package. So say.c has always been calling the wrong location (under digits/) for those two files and in the case of second and minute they didn't exist in the Core packages at all. The 1.6 sounds release moves the second and minute files into Core from Extra for the languages that already had them. A future release will include the second and minute files for languages that didn't already have them. This patch just changes all the target locations for second, seconds, minute, and minutes that were under the digits subdir to be under the root of sounds instead. Which is where the sounds will be for some languages after 1.6 sounds and for all languages after a future release. ASTERISK-25810 #close Change-Id: I05d9d4bee6a7237030530a46e7eb3df15f13f702 Reported-by: Nicolas Riendeau --- main/say.c | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/main/say.c b/main/say.c index 44f55e25ae5..c97dc9fd8a9 100644 --- a/main/say.c +++ b/main/say.c @@ -4441,9 +4441,9 @@ int ast_say_date_with_format_da(struct ast_channel *chan, time_t t, const char * } if (!res && next_item(&format[offset + 1]) == 'S') { /* minutes only if seconds follow */ if (tm.tm_min == 1) { - res = wait_file(chan, ints, "digits/minute", lang); + res = wait_file(chan, ints, "minute", lang); } else { - res = wait_file(chan, ints, "digits/minutes", lang); + res = wait_file(chan, ints, "minutes", lang); } } break; @@ -4517,7 +4517,7 @@ int ast_say_date_with_format_da(struct ast_channel *chan, time_t t, const char * if (!res) { res = ast_say_number(chan, tm.tm_sec, ints, lang, "f"); if (!res) { - res = wait_file(chan, ints, "digits/seconds", lang); + res = wait_file(chan, ints, "seconds", lang); } } break; @@ -4637,16 +4637,16 @@ int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const char * case 'M': /* Minute */ if (next_item(&format[offset + 1]) == 'S') { /* zero 'digits/0' only if seconds follow */ - res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); /* female only if we say digits/minutes */ + res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); /* female only if we say minutes */ } else if (tm.tm_min > 0) { res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); } if (!res && next_item(&format[offset + 1]) == 'S') { /* minutes only if seconds follow */ if (tm.tm_min == 1) { - res = wait_file(chan, ints, "digits/minute", lang); + res = wait_file(chan, ints, "minute", lang); } else { - res = wait_file(chan, ints, "digits/minutes", lang); + res = wait_file(chan, ints, "minutes", lang); } } break; @@ -4720,7 +4720,7 @@ int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const char * if (!res) { res = ast_say_number(chan, tm.tm_sec, ints, lang, "f"); if (!res) { - res = wait_file(chan, ints, tm.tm_sec == 1 ? "digits/second" : "digits/seconds", lang); + res = wait_file(chan, ints, tm.tm_sec == 1 ? "second" : "seconds", lang); } } break; @@ -4853,9 +4853,9 @@ int ast_say_date_with_format_is(struct ast_channel *chan, time_t t, const char * if (!res && next_item(&format[offset + 1]) == 'S') { /* minutes only if seconds follow */ /* Say minute/minutes depending on whether minutes end in 1 */ if ((tm.tm_min % 10 == 1) && (tm.tm_min != 11)) { - res = wait_file(chan, ints, "digits/minute", lang); + res = wait_file(chan, ints, "minute", lang); } else { - res = wait_file(chan, ints, "digits/minutes", lang); + res = wait_file(chan, ints, "minutes", lang); } } break; @@ -4930,9 +4930,9 @@ int ast_say_date_with_format_is(struct ast_channel *chan, time_t t, const char * res = ast_say_number(chan, tm.tm_sec, ints, lang, "f"); /* Say minute/minutes depending on whether seconds end in 1 */ if (!res && (tm.tm_sec % 10 == 1) && (tm.tm_sec != 11)) { - res = wait_file(chan, ints, "digits/second", lang); + res = wait_file(chan, ints, "second", lang); } else { - res = wait_file(chan, ints, "digits/seconds", lang); + res = wait_file(chan, ints, "seconds", lang); } } break; @@ -5652,7 +5652,7 @@ int ast_say_date_with_format_fr(struct ast_channel *chan, time_t t, const char * /* Seconds */ res = ast_say_number(chan, tm.tm_sec, ints, lang, (char * ) NULL); if (!res) { - res = wait_file(chan, ints, "digits/second", lang); + res = wait_file(chan, ints, "second", lang); } break; case 'T': @@ -6303,9 +6303,9 @@ int ast_say_date_with_format_pl(struct ast_channel *chan, time_t thetime, const one = tm.tm_sec % 10; if (one > 1 && one < 5 && ten != 1) - res = wait_file(chan, ints, "digits/seconds", lang); + res = wait_file(chan, ints, "seconds", lang); else - res = wait_file(chan, ints, "digits/second", lang); + res = wait_file(chan, ints, "second", lang); } } } @@ -6469,9 +6469,9 @@ int ast_say_date_with_format_pt(struct ast_channel *chan, time_t t, const char * res = ast_say_number(chan, tm.tm_min, ints, lang, NULL); if (!res) { if (tm.tm_min > 1) { - res = wait_file(chan, ints, "digits/minutes", lang); + res = wait_file(chan, ints, "minutes", lang); } else { - res = wait_file(chan, ints, "digits/minute", lang); + res = wait_file(chan, ints, "minute", lang); } } } else { @@ -6567,9 +6567,9 @@ int ast_say_date_with_format_pt(struct ast_channel *chan, time_t t, const char * res = ast_say_number(chan, tm.tm_sec, ints, lang, NULL); if (!res) { if (tm.tm_sec > 1) { - res = wait_file(chan, ints, "digits/seconds", lang); + res = wait_file(chan, ints, "seconds", lang); } else { - res = wait_file(chan, ints, "digits/second", lang); + res = wait_file(chan, ints, "second", lang); } } } else { @@ -6783,7 +6783,7 @@ int ast_say_date_with_format_zh(struct ast_channel *chan, time_t t, const char * } } if (!res) { - res = wait_file(chan, ints, "digits/minute", lang); + res = wait_file(chan, ints, "minute", lang); } break; case 'P': @@ -6867,7 +6867,7 @@ int ast_say_date_with_format_zh(struct ast_channel *chan, time_t t, const char * } } if (!res) { - res = wait_file(chan, ints, "digits/second", lang); + res = wait_file(chan, ints, "second", lang); } break; case 'T': @@ -7022,7 +7022,7 @@ int ast_say_time_hu(struct ast_channel *chan, time_t t, const char *ints, const if (tm.tm_min > 0) { res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); if (!res) - res = ast_streamfile(chan, "digits/minute", lang); + res = ast_streamfile(chan, "minute", lang); } return res; } @@ -7117,9 +7117,9 @@ int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, con res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); if (!res) { if (tm.tm_min > 1) - res = wait_file(chan, ints, "digits/minutes", lang); + res = wait_file(chan, ints, "minutes", lang); else - res = wait_file(chan, ints, "digits/minute", lang); + res = wait_file(chan, ints, "minute", lang); } } return res; @@ -7179,7 +7179,7 @@ int ast_say_time_zh(struct ast_channel *chan, time_t t, const char *ints, const if (!res) res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); if (!res) - res = ast_streamfile(chan, "digits/minute", lang); + res = ast_streamfile(chan, "minute", lang); if (!res) res = ast_waitstream(chan, ints); return res; @@ -7602,7 +7602,7 @@ int ast_say_datetime_zh(struct ast_channel *chan, time_t t, const char *ints, co if (!res) res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); if (!res) - res = ast_streamfile(chan, "digits/minute", lang); + res = ast_streamfile(chan, "minute", lang); if (!res) res = ast_waitstream(chan, ints); return res; @@ -8480,7 +8480,7 @@ static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t t, const if (!res) res = ast_say_number_full_gr(chan, tm.tm_sec, ints, lang, -1, -1); if (!res) - ast_copy_string(nextmsg, "digits/seconds", sizeof(nextmsg)); + ast_copy_string(nextmsg, "seconds", sizeof(nextmsg)); res = wait_file(chan, ints, nextmsg, lang); break; case 'T': From 2697e4515722379435a6bf3ecac13b5c82914783 Mon Sep 17 00:00:00 2001 From: Matthew Fredrickson Date: Fri, 21 Jul 2017 15:57:46 -0500 Subject: [PATCH 1389/1578] format.h: Fix a few minor errors in comments. A few minor problems were found in comments in format.h. This patch fixes them. Change-Id: I07f0bdb47b93359b361c4c3d8ecc87cd3199dd94 --- include/asterisk/format.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asterisk/format.h b/include/asterisk/format.h index 0bad96dccc1..946c03d980b 100644 --- a/include/asterisk/format.h +++ b/include/asterisk/format.h @@ -32,7 +32,7 @@ struct ast_format; /*! \brief Format comparison results */ enum ast_format_cmp_res { - /*! Both formats are equivalent to eachother */ + /*! Both formats are equivalent to each other */ AST_FORMAT_CMP_EQUAL = 0, /*! Both formats are completely different and not the same in any way */ AST_FORMAT_CMP_NOT_EQUAL, @@ -110,7 +110,7 @@ struct ast_format_interface { struct ast_format *(* const format_parse_sdp_fmtp)(const struct ast_format *format, const char *attributes); /*! - * \brief Generate SDP attribute information from an ast_format_attr structure. + * \brief Generate SDP attribute information from an ast_format structure. * * \param format The format containing attributes * \param payload The payload number to place into the fmtp line From 922930753cf82044394935c739527bb868cb9efc Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 19 Jul 2017 18:11:19 -0500 Subject: [PATCH 1390/1578] app_voicemail.c: Allow mailbox entry on authentication retry prompt. The following testsuite voicemail tests were failing to re-enter the mailbox after the first login attempt. tests/apps/voicemail/authenticate_invalid_mailbox tests/apps/voicemail/authenticate_invalid_password The tests were noting the start of the vm-incorrect-mailbox prompt and immediately sending the mailbox for the next login attempt. Since the invalid message playback had to complete before the digits were recognized, the test passed for the wrong reason and added approximately 20 seconds to the test times. * Allow the vm-incorrect-mailbox prompt to get interrupted by the mailbox digits like the initial vm-login prompt so the tests are able to enter the intended mailbox. Change-Id: I1dc53fe917bfe03a4587b2c4cd24c94696a69df8 --- apps/app_voicemail.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 956b951fd46..0a07cc10305 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -11064,7 +11064,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ int skipuser, int max_logins, int silent) { int useadsi = 0, valid = 0, logretries = 0; - char password[AST_MAX_EXTENSION]="", *passptr; + char password[AST_MAX_EXTENSION], *passptr; struct ast_vm_user vmus, *vmu = NULL; /* If ADSI is supported, setup login screen */ @@ -11106,7 +11106,8 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ adsi_password(chan); if (!ast_strlen_zero(prefix)) { - char fullusername[80] = ""; + char fullusername[80]; + ast_copy_string(fullusername, prefix, sizeof(fullusername)); strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername)); ast_copy_string(mailbox, fullusername, mailbox_size); @@ -11164,6 +11165,10 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ free_user(vmu); return -1; } + if (ast_waitstream(chan, "")) { /* Channel is hung up */ + free_user(vmu); + return -1; + } } else { if (useadsi) adsi_login(chan); @@ -11173,10 +11178,6 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ return -1; } } - if (ast_waitstream(chan, "")) { /* Channel is hung up */ - free_user(vmu); - return -1; - } } } if (!valid && (logretries >= max_logins)) { From a6eb9ee7d22c3cf733e9c05419844519ff3ab05d Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 24 Jul 2017 18:30:59 +0000 Subject: [PATCH 1391/1578] core: Add VP9 passthrough support. This change adds VP9 as a known codec and creates a cached "vp9" media format for use. Change-Id: I025a93ed05cf96153d66f36db1839109cc24c5cc --- channels/chan_pjsip.c | 1 + include/asterisk/format_cache.h | 5 +++++ main/codec_builtin.c | 8 ++++++++ main/format_cache.c | 8 ++++++++ main/rtp_engine.c | 6 ++++-- 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index f009943ed9a..51b5dab5cbc 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1596,6 +1596,7 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi * fully support other video codecs */ if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL || + ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp9) != AST_FORMAT_CMP_NOT_EQUAL || (channel->session->endpoint->media.webrtc && ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_h264) != AST_FORMAT_CMP_NOT_EQUAL)) { /* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h index 92272e8ebac..067546310ff 100644 --- a/include/asterisk/format_cache.h +++ b/include/asterisk/format_cache.h @@ -183,6 +183,11 @@ extern struct ast_format *ast_format_mp4; */ extern struct ast_format *ast_format_vp8; +/*! + * \brief Built-in cached vp9 format. + */ +extern struct ast_format *ast_format_vp9; + /*! * \brief Built-in cached jpeg format. */ diff --git a/main/codec_builtin.c b/main/codec_builtin.c index 32ec12d3d42..25aa51384b5 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -820,6 +820,13 @@ static struct ast_codec vp8 = { .sample_rate = 1000, }; +static struct ast_codec vp9 = { + .name = "vp9", + .description = "VP9 video", + .type = AST_MEDIA_TYPE_VIDEO, + .sample_rate = 1000, +}; + static struct ast_codec t140red = { .name = "red", .description = "T.140 Realtime Text with redundancy", @@ -966,6 +973,7 @@ int ast_codec_builtin_init(void) res |= CODEC_REGISTER_AND_CACHE(h264); res |= CODEC_REGISTER_AND_CACHE(mpeg4); res |= CODEC_REGISTER_AND_CACHE(vp8); + res |= CODEC_REGISTER_AND_CACHE(vp9); res |= CODEC_REGISTER_AND_CACHE(t140red); res |= CODEC_REGISTER_AND_CACHE(t140); res |= CODEC_REGISTER_AND_CACHE(t38); diff --git a/main/format_cache.c b/main/format_cache.c index 302bbf827e7..1a67ebe6088 100644 --- a/main/format_cache.c +++ b/main/format_cache.c @@ -190,6 +190,11 @@ struct ast_format *ast_format_mp4; */ struct ast_format *ast_format_vp8; +/*! + * \brief Built-in cached vp9 format. + */ +struct ast_format *ast_format_vp9; + /*! * \brief Built-in cached jpeg format. */ @@ -345,6 +350,7 @@ static void format_cache_shutdown(void) ao2_replace(ast_format_h264, NULL); ao2_replace(ast_format_mp4, NULL); ao2_replace(ast_format_vp8, NULL); + ao2_replace(ast_format_vp9, NULL); ao2_replace(ast_format_t140_red, NULL); ao2_replace(ast_format_t140, NULL); ao2_replace(ast_format_t38, NULL); @@ -444,6 +450,8 @@ static void set_cached_format(const char *name, struct ast_format *format) ao2_replace(ast_format_mp4, format); } else if (!strcmp(name, "vp8")) { ao2_replace(ast_format_vp8, format); + } else if (!strcmp(name, "vp9")) { + ao2_replace(ast_format_vp9, format); } else if (!strcmp(name, "red")) { ao2_replace(ast_format_t140_red, format); } else if (!strcmp(name, "t140")) { diff --git a/main/rtp_engine.c b/main/rtp_engine.c index abd4b1fcfca..fe60c4eae2b 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -3268,9 +3268,10 @@ int ast_rtp_engine_init(void) set_next_mime_type(ast_format_siren7, 0, "audio", "G7221", 16000); set_next_mime_type(ast_format_siren14, 0, "audio", "G7221", 32000); set_next_mime_type(ast_format_g719, 0, "audio", "G719", 48000); - /* Opus and VP8 */ + /* Opus, VP8, and VP9 */ set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000); set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000); + set_next_mime_type(ast_format_vp9, 0, "video", "VP9", 90000); /* Define the static rtp payload mappings */ add_static_payload(0, ast_format_ulaw, 0); @@ -3311,6 +3312,7 @@ int ast_rtp_engine_init(void) add_static_payload(105, ast_format_t140_red, 0); /* Real time text chat (with redundancy encoding) */ add_static_payload(106, ast_format_t140, 0); /* Real time text chat */ add_static_payload(107, ast_format_opus, 0); + add_static_payload(108, ast_format_vp9, 0); add_static_payload(110, ast_format_speex, 0); add_static_payload(111, ast_format_g726, 0); @@ -3413,4 +3415,4 @@ void ast_rtp_instance_set_stream_num(struct ast_rtp_instance *rtp, int stream_nu rtp->engine->set_stream_num(rtp, stream_num); } ao2_unlock(rtp); -} \ No newline at end of file +} From 4f4936fd72d92b394362f937c13c1cc1322d27ea Mon Sep 17 00:00:00 2001 From: Sergej Kasumovic Date: Thu, 20 Jul 2017 15:08:05 +0200 Subject: [PATCH 1392/1578] res_stasis_device_state: Unsubscribe should remove old subscriptions Case scenario with Applications ARI: * Once you subscribe to deviceState with Applications REST API, it will be added into subscription pool. * When you unsubscribe it will remove from the device_state_subscription hash table but not from the subscription pool. * When you subscribe again, it will add it to pool again. * Now you will have two subscriptions and you will receive same event twice. This fix should now remove deviceState subscription from pool and it should fix unsubscribe on deviceState. ASTERISK-27130 #close Change-Id: I718b70d770a086e39b4ddba4f69a3c616d4476c4 --- res/res_stasis_device_state.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c index 344cb40c96a..276a98b930d 100644 --- a/res/res_stasis_device_state.c +++ b/res/res_stasis_device_state.c @@ -106,7 +106,6 @@ static int device_state_subscriptions_cmp(void *obj, void *arg, int flags) static void device_state_subscription_destroy(void *obj) { struct device_state_subscription *sub = obj; - sub->sub = stasis_unsubscribe_and_join(sub->sub); ast_string_field_free_memory(sub); } @@ -152,6 +151,9 @@ static struct device_state_subscription *find_device_state_subscription( static void remove_device_state_subscription( struct device_state_subscription *sub) { + if (sub->sub) { + sub->sub = stasis_unsubscribe_and_join(sub->sub); + } ao2_unlink_flags(device_state_subscriptions, sub, OBJ_NOLOCK); } From b3914df10bbb61494f3023a8a22894e4aeeadf05 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 25 Jul 2017 16:17:45 -0400 Subject: [PATCH 1393/1578] res_rtp_asterisk: Fix mapping of pjsip's ICE roles to ours Change-Id: Ia578ede1a55b21014581793992a429441903278b --- res/res_rtp_asterisk.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 70561d0b6da..65ab9020fc0 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -701,6 +701,37 @@ static void ice_wrap_dtor(void *vdoomed) } } +static void ast2pj_rtp_ice_role(enum ast_rtp_ice_role ast_role, enum pj_ice_sess_role *pj_role) +{ + switch (ast_role) { + case AST_RTP_ICE_ROLE_CONTROLLED: + *pj_role = PJ_ICE_SESS_ROLE_CONTROLLED; + break; + case AST_RTP_ICE_ROLE_CONTROLLING: + *pj_role = PJ_ICE_SESS_ROLE_CONTROLLING; + break; + } +} + +static void pj2ast_rtp_ice_role(enum pj_ice_sess_role pj_role, enum ast_rtp_ice_role *ast_role) +{ + switch (pj_role) { + case PJ_ICE_SESS_ROLE_CONTROLLED: + *ast_role = AST_RTP_ICE_ROLE_CONTROLLED; + return; + case PJ_ICE_SESS_ROLE_CONTROLLING: + *ast_role = AST_RTP_ICE_ROLE_CONTROLLING; + return; + case PJ_ICE_SESS_ROLE_UNKNOWN: + /* Don't change anything */ + return; + default: + /* If we aren't explicitly handling something, it's a bug */ + ast_assert(0); + return; + } +} + /*! \pre instance is locked */ static int ice_reset_session(struct ast_rtp_instance *instance) { @@ -717,8 +748,9 @@ static int ice_reset_session(struct ast_rtp_instance *instance) res = ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1); if (!res) { /* Use the current expected role for the ICE session */ - pj_ice_sess_change_role(rtp->ice->real_ice, rtp->role == AST_RTP_ICE_ROLE_CONTROLLED ? - PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING); + enum pj_ice_sess_role role = PJ_ICE_SESS_ROLE_UNKNOWN; + ast2pj_rtp_ice_role(rtp->role, &role); + pj_ice_sess_change_role(rtp->ice->real_ice, role); } /* If we only have one component now, and we previously set up TURN for RTCP, @@ -790,7 +822,7 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance) ao2_cleanup(rtp->ice_proposed_remote_candidates); rtp->ice_proposed_remote_candidates = NULL; /* If this ICE session is being preserved then go back to the role it currently is */ - rtp->role = rtp->ice->real_ice->role; + pj2ast_rtp_ice_role(rtp->ice->real_ice->role, &rtp->role); return; } From 65c560894d0d53167af9c6013c7f93703ebb6722 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Mon, 26 Jun 2017 14:52:52 +0200 Subject: [PATCH 1394/1578] chan_pjsip: add a new function PJSIP_DTMF_MODE This function is a replica of SIPDtmfMode, allowing the DTMF mode of a PJSIP call to be modified on a per-call basis ASTERISK-27085 #close Change-Id: I20eef5da3e5d1d3e58b304416bc79683f87e7612 --- CHANGES | 3 + channels/chan_pjsip.c | 17 ++- channels/pjsip/dialplan_functions.c | 153 ++++++++++++++++++++ channels/pjsip/include/dialplan_functions.h | 25 ++++ include/asterisk/res_pjsip.h | 27 ++++ include/asterisk/res_pjsip_session.h | 2 + res/res_pjsip.c | 50 +++++++ res/res_pjsip/pjsip_configuration.c | 40 ++--- res/res_pjsip_sdp_rtp.c | 12 +- res/res_pjsip_session.c | 2 + 10 files changed, 294 insertions(+), 37 deletions(-) diff --git a/CHANGES b/CHANGES index 5daa81618fb..1721ed14c98 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,9 @@ res_musiconhold which sends signals to the application and its descendants directly, or "process" which sends signals only to the application itself. + * New dialplan function PJSIP_DTMF_MODE added to get or change the DTMF mode + of a channel on a per-call basis. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------ ------------------------------------------------------------------------------ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 51b5dab5cbc..ebda6c7ee17 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1947,7 +1947,7 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit) media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; - switch (channel->session->endpoint->dtmf) { + switch (channel->session->dtmf) { case AST_SIP_DTMF_RFC_4733: if (!media || !media->rtp) { return -1; @@ -2068,7 +2068,7 @@ static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned in media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; - switch (channel->session->endpoint->dtmf) { + switch (channel->session->dtmf) { case AST_SIP_DTMF_AUTO_INFO: { if (!media || !media->rtp) { @@ -2893,6 +2893,12 @@ static struct ast_custom_function media_offer_function = { .write = pjsip_acf_media_offer_write }; +static struct ast_custom_function dtmf_mode_function = { + .name = "PJSIP_DTMF_MODE", + .read = pjsip_acf_dtmf_mode_read, + .write = pjsip_acf_dtmf_mode_write +}; + static struct ast_custom_function session_refresh_function = { .name = "PJSIP_SEND_SESSION_REFRESH", .write = pjsip_acf_session_refresh_write, @@ -2937,6 +2943,11 @@ static int load_module(void) goto end; } + if (ast_custom_function_register(&dtmf_mode_function)) { + ast_log(LOG_WARNING, "Unable to register PJSIP_DTMF_MODE dialplan function\n"); + goto end; + } + if (ast_custom_function_register(&session_refresh_function)) { ast_log(LOG_WARNING, "Unable to register PJSIP_SEND_SESSION_REFRESH dialplan function\n"); goto end; @@ -2996,6 +3007,7 @@ static int load_module(void) end: ao2_cleanup(pjsip_uids_onhold); pjsip_uids_onhold = NULL; + ast_custom_function_unregister(&dtmf_mode_function); ast_custom_function_unregister(&media_offer_function); ast_custom_function_unregister(&chan_pjsip_dial_contacts_function); ast_custom_function_unregister(&session_refresh_function); @@ -3018,6 +3030,7 @@ static int unload_module(void) ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement); ast_sip_session_unregister_supplement(&call_pickup_supplement); + ast_custom_function_unregister(&dtmf_mode_function); ast_custom_function_unregister(&media_offer_function); ast_custom_function_unregister(&chan_pjsip_dial_contacts_function); ast_custom_function_unregister(&session_refresh_function); diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 59ca9d791c8..c89d9ca2624 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -68,6 +68,18 @@ PJSIP_SEND_SESSION_REFRESH + + + Get or change the DTMF mode for a SIP call. + + + + + When read, returns the current DTMF mode + When written, sets the current DTMF mode + This function uses the same DTMF mode naming as the dtmf_mode configuration option + + W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session @@ -439,6 +451,7 @@ #include "asterisk/channel.h" #include "asterisk/stream.h" #include "asterisk/format.h" +#include "asterisk/dsp.h" #include "asterisk/pbx.h" #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_session.h" @@ -1167,6 +1180,34 @@ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata); } +int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + struct ast_sip_channel_pvt *channel; + + if (!chan) { + ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); + return -1; + } + + ast_channel_lock(chan); + if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) { + ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd); + ast_channel_unlock(chan); + return -1; + } + + channel = ast_channel_tech_pvt(chan); + + if (ast_sip_dtmf_to_str(channel->session->dtmf, buf, len) < 0) { + ast_log(LOG_WARNING, "Unknown DTMF mode %d on PJSIP channel %s\n", channel->session->dtmf, ast_channel_name(chan)); + ast_channel_unlock(chan); + return -1; + } + + ast_channel_unlock(chan); + return 0; +} + struct refresh_data { struct ast_sip_session *session; enum ast_sip_session_refresh_method method; @@ -1195,6 +1236,118 @@ static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_dat return 0; } +static int dtmf_mode_refresh_cb(void *obj) +{ + struct refresh_data *data = obj; + + if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) { + ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSER completion. Sending session refresh\n", ast_channel_name(data->session->channel)); + + ast_sip_session_refresh(data->session, NULL, NULL, + sip_session_response_cb, data->method, 1, NULL); + } + + return 0; +} + +int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) +{ + struct ast_sip_channel_pvt *channel; + struct ast_sip_session_media *media; + int dsp_features = 0; + int dtmf = -1; + struct refresh_data rdata = { + .method = AST_SIP_SESSION_REFRESH_METHOD_INVITE, + }; + + if (!chan) { + ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); + return -1; + } + + ast_channel_lock(chan); + if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) { + ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd); + ast_channel_unlock(chan); + return -1; + } + + channel = ast_channel_tech_pvt(chan); + rdata.session = channel->session; + + dtmf = ast_sip_str_to_dtmf(value); + + if (dtmf == -1) { + ast_log(LOG_WARNING, "Cannot set DTMF mode to '%s' on channel '%s' as value is invalid.\n", value, + ast_channel_name(chan)); + ast_channel_unlock(chan); + return -1; + } + + if (channel->session->dtmf == dtmf) { + /* DTMF mode unchanged, nothing to do! */ + ast_channel_unlock(chan); + return 0; + } + + channel->session->dtmf = dtmf; + + media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; + + if (media && media->rtp) { + if (channel->session->dtmf == AST_SIP_DTMF_RFC_4733) { + ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 1); + ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_RFC2833); + } else if (channel->session->dtmf == AST_SIP_DTMF_INFO) { + ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0); + ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_NONE); + } else if (channel->session->dtmf == AST_SIP_DTMF_INBAND) { + ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0); + ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_INBAND); + } else if (channel->session->dtmf == AST_SIP_DTMF_NONE) { + ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0); + ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_NONE); + } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO) { + if (ast_rtp_instance_dtmf_mode_get(media->rtp) != AST_RTP_DTMF_MODE_RFC2833) { + /* no RFC4733 negotiated, enable inband */ + ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_INBAND); + } + } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO_INFO) { + ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_DTMF, 0); + if (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_INBAND) { + /* if inband, switch to INFO */ + ast_rtp_instance_dtmf_mode_set(media->rtp, AST_RTP_DTMF_MODE_NONE); + } + } + } + + if (channel->session->dsp) { + dsp_features = ast_dsp_get_features(channel->session->dsp); + } + if (channel->session->dtmf == AST_SIP_DTMF_INBAND || + channel->session->dtmf == AST_SIP_DTMF_AUTO) { + dsp_features |= DSP_FEATURE_DIGIT_DETECT; + } else { + dsp_features &= ~DSP_FEATURE_DIGIT_DETECT; + } + if (dsp_features) { + if (!channel->session->dsp) { + if (!(channel->session->dsp = ast_dsp_new())) { + ast_channel_unlock(chan); + return 0; + } + } + ast_dsp_set_features(channel->session->dsp, dsp_features); + } else if (channel->session->dsp) { + ast_dsp_free(channel->session->dsp); + channel->session->dsp = NULL; + } + + ast_channel_unlock(chan); + + return ast_sip_push_task_synchronous(channel->session->serializer, dtmf_mode_refresh_cb, &rdata); +} + static int refresh_write_cb(void *obj) { struct refresh_data *data = obj; diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h index 8b80bfa7474..731e91d139e 100644 --- a/channels/pjsip/include/dialplan_functions.h +++ b/channels/pjsip/include/dialplan_functions.h @@ -47,6 +47,31 @@ int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data */ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value); +/*! + * \brief PJSIP_DTMF_MODE function read callback + * \param chan The channel the function is called on + * \param cmd The name of the function + * \param data Arguments passed to the function + * \param buf Out buffer that should be populated with the data + * \param len Size of the buffer + * + * \retval 0 on success + * \retval -1 on failure + */ +int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len); + +/*! + * \brief PJSIP_DTMF_MODE function write callback + * \param chan The channel the function is called on + * \param cmd The name of the function + * \param data Arguments passed to the function + * \param value Value to be set by the function + * + * \retval 0 on success + * \retval -1 on failure + */ +int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value); + /*! * \brief PJSIP_MEDIA_OFFER function read callback * \param chan The channel the function is called on diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index cf366cbab36..cb77fa35632 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2889,4 +2889,31 @@ int ast_sip_set_tpselector_from_ep_or_uri(const struct ast_sip_endpoint *endpoin int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg, pjsip_tpselector *selector); +/*! + * \brief Convert the DTMF mode enum value into a string + * \since 13.18.0 + * + * \param dtmf the dtmf mode + * \param buf Buffer to receive dtmf mode string + * \param buf_len Buffer length + * + * \retval 0 Success + * \retval -1 Failure + * + */ +int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf, + char *buf, size_t buf_len); + +/*! + * \brief Convert the DTMF mode name into an enum + * \since 13.18.0 + * + * \param dtmf_mode dtmf mode as a string + * + * \retval >= 0 The enum value + * \retval -1 Failure + * + */ +int ast_sip_str_to_dtmf(const char *dtmf_mode); + #endif /* _RES_PJSIP_H */ diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index eae11af4348..caf10db1112 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -203,6 +203,8 @@ struct ast_sip_session { unsigned int defer_end:1; /*! Session end (remote hangup) requested while termination deferred */ unsigned int ended_while_deferred:1; + /*! DTMF mode to use with this session, from endpoint but can change */ + enum ast_sip_dtmf_mode dtmf; }; typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata); diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 02112113cd7..f3648acdbff 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4483,6 +4483,56 @@ const char *ast_sip_get_host_ip_string(int af) return NULL; } +int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf, + char *buf, size_t buf_len) +{ + switch (dtmf) { + case AST_SIP_DTMF_NONE: + ast_copy_string(buf, "none", buf_len); + break; + case AST_SIP_DTMF_RFC_4733: + ast_copy_string(buf, "rfc4733", buf_len); + break; + case AST_SIP_DTMF_INBAND: + ast_copy_string(buf, "inband", buf_len); + break; + case AST_SIP_DTMF_INFO: + ast_copy_string(buf, "info", buf_len); + break; + case AST_SIP_DTMF_AUTO: + ast_copy_string(buf, "auto", buf_len); + break; + case AST_SIP_DTMF_AUTO_INFO: + ast_copy_string(buf, "auto_info", buf_len); + break; + default: + buf[0] = '\0'; + return -1; + } + return 0; +} + +int ast_sip_str_to_dtmf(const char * dtmf_mode) +{ + int result = -1; + + if (!strcasecmp(dtmf_mode, "info")) { + result = AST_SIP_DTMF_INFO; + } else if (!strcasecmp(dtmf_mode, "rfc4733")) { + result = AST_SIP_DTMF_RFC_4733; + } else if (!strcasecmp(dtmf_mode, "inband")) { + result = AST_SIP_DTMF_INBAND; + } else if (!strcasecmp(dtmf_mode, "none")) { + result = AST_SIP_DTMF_NONE; + } else if (!strcasecmp(dtmf_mode, "auto")) { + result = AST_SIP_DTMF_AUTO; + } else if (!strcasecmp(dtmf_mode, "auto_info")) { + result = AST_SIP_DTMF_AUTO_INFO; + } + + return result; +} + /*! * \brief Set name and number information on an identity header. * diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 9f9de36faa3..4e12b04cca8 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -366,47 +366,29 @@ static int contact_acl_to_str(const void *obj, const intptr_t *args, char **buf) static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; + enum ast_sip_dtmf_mode dtmf = ast_sip_str_to_dtmf(var->value); - if (!strcasecmp(var->value, "rfc4733")) { - endpoint->dtmf = AST_SIP_DTMF_RFC_4733; - } else if (!strcasecmp(var->value, "inband")) { - endpoint->dtmf = AST_SIP_DTMF_INBAND; - } else if (!strcasecmp(var->value, "auto_info")) { - endpoint->dtmf = AST_SIP_DTMF_AUTO_INFO; - } else if (!strcasecmp(var->value, "info")) { - endpoint->dtmf = AST_SIP_DTMF_INFO; - } else if (!strcasecmp(var->value, "auto")) { - endpoint->dtmf = AST_SIP_DTMF_AUTO; - } else if (!strcasecmp(var->value, "none")) { - endpoint->dtmf = AST_SIP_DTMF_NONE; - } else { + if (dtmf == -1) { return -1; } + endpoint->dtmf = dtmf; return 0; } static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_endpoint *endpoint = obj; + char dtmf_str[20]; + int result = -1; - switch (endpoint->dtmf) { - case AST_SIP_DTMF_RFC_4733 : - *buf = "rfc4733"; break; - case AST_SIP_DTMF_INBAND : - *buf = "inband"; break; - case AST_SIP_DTMF_INFO : - *buf = "info"; break; - case AST_SIP_DTMF_AUTO : - *buf = "auto"; break; - case AST_SIP_DTMF_AUTO_INFO : - *buf = "auto_info"; - break; - default: - *buf = "none"; - } + result = ast_sip_dtmf_to_str(endpoint->dtmf, dtmf_str, sizeof(dtmf_str)); - *buf = ast_strdup(*buf); + if (result == 0) { + *buf = ast_strdup(dtmf_str); + } else { + *buf = ast_strdup("none"); + } return 0; } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a2e7f8f9223..4ed1f8a57da 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -207,10 +207,10 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me ice->stop(session_media->rtp); } - if (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) { + if (session->dtmf == AST_SIP_DTMF_RFC_4733 || session->dtmf == AST_SIP_DTMF_AUTO || session->dtmf == AST_SIP_DTMF_AUTO_INFO) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833); ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_DTMF, 1); - } else if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) { + } else if (session->dtmf == AST_SIP_DTMF_INBAND) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND); } @@ -293,11 +293,11 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp } } } - if (!tel_event && (session->endpoint->dtmf == AST_SIP_DTMF_AUTO)) { + if (!tel_event && (session->dtmf == AST_SIP_DTMF_AUTO)) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND); } - if (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) { + if (session->dtmf == AST_SIP_DTMF_AUTO_INFO) { if (tel_event) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833); } else { @@ -434,7 +434,7 @@ static int set_caps(struct ast_sip_session *session, ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); } - if ( ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) || (session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) ) + if ( ((session->dtmf == AST_SIP_DTMF_AUTO) || (session->dtmf == AST_SIP_DTMF_AUTO_INFO) ) && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833) && (session->dsp)) { dsp_features = ast_dsp_get_features(session->dsp); @@ -1314,7 +1314,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as pj_str_t stmp; pjmedia_sdp_attr *attr; int index = 0; - int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733 || session->endpoint->dtmf == AST_SIP_DTMF_AUTO || session->endpoint->dtmf == AST_SIP_DTMF_AUTO_INFO) ? AST_RTP_DTMF : 0; + int noncodec = (session->dtmf == AST_SIP_DTMF_RFC_4733 || session->dtmf == AST_SIP_DTMF_AUTO || session->dtmf == AST_SIP_DTMF_AUTO_INFO) ? AST_RTP_DTMF : 0; int min_packet_size = 0, max_packet_size = 0; int rtp_code; RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 0ad2c8f30ac..2711efeb86a 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2013,6 +2013,8 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, session->contact = ao2_bump(contact); session->inv_session = inv_session; + session->dtmf = endpoint->dtmf; + if (add_supplements(session)) { /* Release the ref held by session->inv_session */ ao2_ref(session, -1); From ac6d98b28d2fd8022b11839f2c4febfdc7431d78 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 27 Jul 2017 05:35:51 -0600 Subject: [PATCH 1395/1578] bundled_pjproject: Improve SSL/TLS error handling OpenSSL has 2 levels or error processing. It's possible for the top layer to return SSL_ERROR_SYSCALL but the lower layer return no error, in which case processing should continue. Only the top layer was being examined though so connections were being torn down when they didn't need to be. This patch adds the examination of the lower level codes, and if they return no errors, allows processing to continue. ASTERISK-27001 Reported-by: Ian Gilmour patches: pjproject-2.6.patch submitted by Ian Gilmour (license 6889) Updated-by: George Joseph and Sauw Ming (Teluu) Merged to upstream pjproject on 7/27/2017 (commit 5631) Change-Id: I23844ca0c68ef1ee550f14d46f6dae57d33b7bd2 --- ...ove-error-handling-in-OpenSSL-socket.patch | 247 ++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 third-party/pjproject/patches/0075-Fixed-2030-Improve-error-handling-in-OpenSSL-socket.patch diff --git a/third-party/pjproject/patches/0075-Fixed-2030-Improve-error-handling-in-OpenSSL-socket.patch b/third-party/pjproject/patches/0075-Fixed-2030-Improve-error-handling-in-OpenSSL-socket.patch new file mode 100644 index 00000000000..1e7035d9357 --- /dev/null +++ b/third-party/pjproject/patches/0075-Fixed-2030-Improve-error-handling-in-OpenSSL-socket.patch @@ -0,0 +1,247 @@ +From 96c06899d95eaf01d05561554b21e8c63baa7129 Mon Sep 17 00:00:00 2001 +From: ming +Date: Thu, 27 Jul 2017 06:07:54 +0000 +Subject: [PATCH 75/76] Fixed #2030: Improve error handling in OpenSSL socket + +--- + pjlib/src/pj/ssl_sock_ossl.c | 173 ++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 156 insertions(+), 17 deletions(-) + +diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c +index c466b3c..b8175e1 100644 +--- a/pjlib/src/pj/ssl_sock_ossl.c ++++ b/pjlib/src/pj/ssl_sock_ossl.c +@@ -298,14 +298,104 @@ static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock); + /* Expected maximum value of reason component in OpenSSL error code */ + #define MAX_OSSL_ERR_REASON 1200 + +-static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock, +- unsigned long err) ++ ++static char *SSLErrorString (int err) + { +- pj_status_t status; ++ switch (err) { ++ case SSL_ERROR_NONE: ++ return "SSL_ERROR_NONE"; ++ case SSL_ERROR_ZERO_RETURN: ++ return "SSL_ERROR_ZERO_RETURN"; ++ case SSL_ERROR_WANT_READ: ++ return "SSL_ERROR_WANT_READ"; ++ case SSL_ERROR_WANT_WRITE: ++ return "SSL_ERROR_WANT_WRITE"; ++ case SSL_ERROR_WANT_CONNECT: ++ return "SSL_ERROR_WANT_CONNECT"; ++ case SSL_ERROR_WANT_ACCEPT: ++ return "SSL_ERROR_WANT_ACCEPT"; ++ case SSL_ERROR_WANT_X509_LOOKUP: ++ return "SSL_ERROR_WANT_X509_LOOKUP"; ++ case SSL_ERROR_SYSCALL: ++ return "SSL_ERROR_SYSCALL"; ++ case SSL_ERROR_SSL: ++ return "SSL_ERROR_SSL"; ++ default: ++ return "SSL_ERROR_UNKNOWN"; ++ } ++} + +- /* General SSL error, dig more from OpenSSL error queue */ +- if (err == SSL_ERROR_SSL) +- err = ERR_get_error(); ++#define ERROR_LOG(msg, err) \ ++ PJ_LOG(2,("SSL", "%s (%s): Level: %d err: <%lu> <%s-%s-%s> len: %d", \ ++ msg, action, level, err, \ ++ (ERR_lib_error_string(err)? ERR_lib_error_string(err): "???"), \ ++ (ERR_func_error_string(err)? ERR_func_error_string(err):"???"),\ ++ (ERR_reason_error_string(err)? \ ++ ERR_reason_error_string(err): "???"), len)); ++ ++static void SSLLogErrors(char * action, int ret, int ssl_err, int len) ++{ ++ char *ssl_err_str = SSLErrorString(ssl_err); ++ ++ if (!action) { ++ action = "UNKNOWN"; ++ } ++ ++ switch (ssl_err) { ++ case SSL_ERROR_SYSCALL: ++ { ++ unsigned long err2 = ERR_get_error(); ++ if (err2) { ++ int level = 0; ++ while (err2) { ++ ERROR_LOG("SSL_ERROR_SYSCALL", err2); ++ level++; ++ err2 = ERR_get_error(); ++ } ++ } else if (ret == 0) { ++ /* An EOF was observed that violates the protocol */ ++ ++ /* The TLS/SSL handshake was not successful but was shut down ++ * controlled and by the specifications of the TLS/SSL protocol. ++ */ ++ } else if (ret == -1) { ++ /* BIO error - look for more info in errno... */ ++ char errStr[250] = ""; ++ strerror_r(errno, errStr, sizeof(errStr)); ++ /* for now - continue logging these if they occur.... */ ++ PJ_LOG(4,("SSL", "BIO error, SSL_ERROR_SYSCALL (%s): " ++ "errno: <%d> <%s> len: %d", ++ action, errno, errStr, len)); ++ } else { ++ /* ret!=0 & ret!=-1 & nothing on error stack - is this valid??? */ ++ PJ_LOG(2,("SSL", "SSL_ERROR_SYSCALL (%s) ret: %d len: %d", ++ action, ret, len)); ++ } ++ break; ++ } ++ case SSL_ERROR_SSL: ++ { ++ unsigned long err2 = ERR_get_error(); ++ int level = 0; ++ ++ while (err2) { ++ ERROR_LOG("SSL_ERROR_SSL", err2); ++ level++; ++ err2 = ERR_get_error(); ++ } ++ break; ++ } ++ default: ++ PJ_LOG(2,("SSL", "%lu [%s] (%s) ret: %d len: %d", ++ ssl_err, ssl_err_str, action, ret, len)); ++ break; ++ } ++} ++ ++ ++static pj_status_t GET_STATUS_FROM_SSL_ERR(unsigned long err) ++{ ++ pj_status_t status; + + /* OpenSSL error range is much wider than PJLIB errno space, so + * if it exceeds the space, only the error reason will be kept. +@@ -317,13 +407,49 @@ static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock, + status = ERR_GET_REASON(err); + + status += PJ_SSL_ERRNO_START; +- ssock->last_err = err; + return status; + } + ++/* err contains ERR_get_error() status */ ++static pj_status_t STATUS_FROM_SSL_ERR(char *action, pj_ssl_sock_t *ssock, ++ unsigned long err) ++{ ++ int level = 0; ++ int len = 0; //dummy ++ ++ ERROR_LOG("STATUS_FROM_SSL_ERR", err); ++ level++; ++ ++ /* General SSL error, dig more from OpenSSL error queue */ ++ if (err == SSL_ERROR_SSL) { ++ err = ERR_get_error(); ++ ERROR_LOG("STATUS_FROM_SSL_ERR", err); ++ } ++ ++ ssock->last_err = err; ++ return GET_STATUS_FROM_SSL_ERR(err); ++} ++ ++/* err contains SSL_get_error() status */ ++static pj_status_t STATUS_FROM_SSL_ERR2(char *action, pj_ssl_sock_t *ssock, ++ int ret, int err, int len) ++{ ++ unsigned long ssl_err = err; ++ ++ if (err == SSL_ERROR_SSL) { ++ ssl_err = ERR_peek_error(); ++ } ++ ++ /* Dig for more from OpenSSL error queue */ ++ SSLLogErrors(action, ret, err, len); ++ ++ ssock->last_err = ssl_err; ++ return GET_STATUS_FROM_SSL_ERR(ssl_err); ++} ++ + static pj_status_t GET_SSL_STATUS(pj_ssl_sock_t *ssock) + { +- return STATUS_FROM_SSL_ERR(ssock, ERR_get_error()); ++ return STATUS_FROM_SSL_ERR("status", ssock, ERR_get_error()); + } + + +@@ -1514,7 +1640,7 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock, + unsigned long err; + err = ERR_get_error(); + if (err != SSL_ERROR_NONE) +- status = STATUS_FROM_SSL_ERR(ssock, err); ++ status = STATUS_FROM_SSL_ERR("connecting", ssock, err); + } + reset_ssl_sock_state(ssock); + } +@@ -1833,11 +1959,11 @@ static pj_status_t do_handshake(pj_ssl_sock_t *ssock) + } + + if (err < 0) { +- err = SSL_get_error(ssock->ossl_ssl, err); +- if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ) ++ int err2 = SSL_get_error(ssock->ossl_ssl, err); ++ if (err2 != SSL_ERROR_NONE && err2 != SSL_ERROR_WANT_READ) + { + /* Handshake fails */ +- status = STATUS_FROM_SSL_ERR(ssock, err); ++ status = STATUS_FROM_SSL_ERR2("Handshake", ssock, err, err2, 0); + return status; + } + } +@@ -1913,6 +2039,7 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock, + read_data_t *buf = *(OFFSET_OF_READ_DATA_PTR(ssock, data)); + void *data_ = (pj_int8_t*)buf->data + buf->len; + int size_ = (int)(ssock->read_size - buf->len); ++ int len = size_; + + /* SSL_read() may write some data to BIO write when re-negotiation + * is on progress, so let's protect it with write mutex. +@@ -1965,10 +2092,22 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock, + */ + if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ) + { +- /* Reset SSL socket state, then return PJ_FALSE */ +- status = STATUS_FROM_SSL_ERR(ssock, err); +- reset_ssl_sock_state(ssock); +- goto on_error; ++ if (err == SSL_ERROR_SYSCALL && size_ == -1 && ++ ERR_peek_error() == 0 && errno == 0) ++ { ++ status = STATUS_FROM_SSL_ERR2("Read", ssock, size_, ++ err, len); ++ PJ_LOG(4,("SSL", "SSL_read() = -1, with " ++ "SSL_ERROR_SYSCALL, no SSL error, " ++ "and errno = 0 - skip BIO error")); ++ /* Ignore these errors */ ++ } else { ++ /* Reset SSL socket state, then return PJ_FALSE */ ++ status = STATUS_FROM_SSL_ERR2("Read", ssock, size_, ++ err, len); ++ reset_ssl_sock_state(ssock); ++ goto on_error; ++ } + } + + status = do_handshake(ssock); +@@ -2856,7 +2995,7 @@ static pj_status_t ssl_write(pj_ssl_sock_t *ssock, + status = PJ_EBUSY; + } else { + /* Some problem occured */ +- status = STATUS_FROM_SSL_ERR(ssock, err); ++ status = STATUS_FROM_SSL_ERR2("Write", ssock, nwritten, err, size); + } + } else { + /* nwritten < *size, shouldn't happen, unless write BIO cannot hold +-- +2.9.4 + From 3f98488279dbc576c7569e8dd23e3120c07bbe7e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 26 Jul 2017 10:27:00 -0400 Subject: [PATCH 1396/1578] app_queue: Add announce-position-only-up option Setting this option will cause the Queue application to only announce the caller's position if it has improved since the last time that we announced it. Change-Id: I173a124121422209485b043e2bf784f54242fce6 --- CHANGES | 5 +++++ apps/app_queue.c | 9 +++++++++ configs/samples/queues.conf.sample | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/CHANGES b/CHANGES index 1721ed14c98..fb54ca6400c 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,11 @@ app_queue * PAUSEALL/UNPAUSEALL now sets the pause reason in the queue_log if it has been defined. + * A new option, "announce-position-only-up," has been added that, when set to + yes, causes position announcements to only be played when the caller's + queue position has improved since the last time that we annouced their + position. This default is no. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.6.0 to Asterisk 14.7.0 ------------ ------------------------------------------------------------------------------ diff --git a/apps/app_queue.c b/apps/app_queue.c index 762119e9413..f297dad8d7d 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1683,6 +1683,7 @@ struct call_queue { unsigned int timeoutrestart:1; unsigned int announceholdtime:2; unsigned int announceposition:3; + unsigned int announceposition_only_up:1; /*!< Only announce position if it has improved */ int strategy:4; unsigned int realtime:1; unsigned int found:1; @@ -2722,6 +2723,7 @@ static void init_queue(struct call_queue *q) q->announcefrequency = 0; q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; q->announceholdtime = 1; + q->announceposition_only_up = 0; q->announcepositionlimit = 10; /* Default 10 positions */ q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ q->roundingseconds = 0; /* Default - don't announce seconds */ @@ -3171,6 +3173,8 @@ static void queue_set_param(struct call_queue *q, const char *param, const char } else { q->announceposition = ANNOUNCEPOSITION_NO; } + } else if (!strcasecmp(param, "announce-position-only-up")) { + q->announceposition_only_up = ast_true(val); } else if (!strcasecmp(param, "announce-position-limit")) { q->announcepositionlimit = atoi(val); } else if (!strcasecmp(param, "periodic-announce")) { @@ -3911,6 +3915,11 @@ static int say_position(struct queue_ent *qe, int ringing) return 0; } + /* Only announce if the caller's queue position has improved since last time */ + if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) { + return 0; + } + if (ringing) { ast_indicate(qe->chan,-1); } else { diff --git a/configs/samples/queues.conf.sample b/configs/samples/queues.conf.sample index b34a8d87014..3e7cbd809b6 100644 --- a/configs/samples/queues.conf.sample +++ b/configs/samples/queues.conf.sample @@ -345,6 +345,11 @@ monitor-type = MixMonitor ; ; announce-round-seconds = 10 ; +; Only announce the caller's position if it has improved since the last announcement. +; The default value is no. +; +; announce-position-only-up = yes +; ; Use these sound files in making position/holdtime announcements. The ; defaults are as listed below -- change only if you need to. ; From 58d032112b28294946427a379c40d51e5238999a Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 27 Jul 2017 21:58:22 -0400 Subject: [PATCH 1397/1578] Fix compiler warnings on Fedora 26 / GCC 7. GCC 7 has added capability to produce warnings, this fixes most of those warnings. The specific warnings are disabled in a few places: * app_voicemail.c: truncation of paths more than 4096 chars in many places. * chan_mgcp.c: callid truncated to 80 chars. * cdr.c: two userfields are combined to cdr copy, fix would break ABI. * tcptls.c: ignore use of deprecated method SSLv3_client_method(). ASTERISK-27156 #close Change-Id: I65f280e7d3cfad279d16f41823a4d6fddcbc4c88 --- addons/chan_ooh323.c | 8 ++++---- apps/Makefile | 2 ++ apps/app_chanspy.c | 2 +- apps/app_followme.c | 2 +- apps/app_minivm.c | 2 +- apps/app_queue.c | 18 +++++++++--------- apps/app_voicemail.c | 4 ++-- channels/Makefile | 2 ++ channels/chan_iax2.c | 2 +- channels/chan_motif.c | 2 +- channels/chan_sip.c | 6 +++--- channels/chan_unistim.c | 4 ++-- channels/iax2/firmware.c | 13 ++++++++----- main/Makefile | 3 ++- main/ast_expr2.c | 6 ++---- main/ast_expr2.y | 6 ++---- main/asterisk.c | 7 +++++-- main/ccss.c | 2 +- main/cli.c | 4 ++-- main/libasteriskssl.c | 24 ++++++++++++----------- main/manager.c | 2 +- main/stdtime/localtime.c | 2 +- main/utils.c | 2 +- res/res_calendar.c | 2 +- res/res_config_pgsql.c | 2 +- res/res_monitor.c | 41 ++++++++++++++++++++-------------------- utils/astman.c | 2 +- utils/extconf.c | 4 ++++ 28 files changed, 94 insertions(+), 82 deletions(-) diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index 2a895650a50..0d5a588b77f 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -3181,7 +3181,7 @@ int reload_config(int reload) static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char ip_port[30]; + char ip_port[64]; struct ooh323_peer *prev = NULL, *peer = NULL; switch (cmd) { @@ -3212,7 +3212,7 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc } if (peer) { - sprintf(ip_port, "%s:%d", peer->ip, peer->port); + sprintf(ip_port, "%s:%hu", peer->ip, peer->port); ast_cli(a->fd, "%-15.15s%s\n", "Name: ", peer->name); ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", peer->faststart?"yes":"no", peer->h245tunneling?"yes":"no"); @@ -3280,7 +3280,7 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru { struct ooh323_peer *prev = NULL, *peer = NULL; struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN); - char ip_port[30]; + char ip_port[64]; #define FORMAT "%-15.15s %-15.15s %-23.23s %-s\n" switch (cmd) { @@ -3303,7 +3303,7 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru peer = peerl.peers; while (peer) { ast_mutex_lock(&peer->lock); - snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port); + snprintf(ip_port, sizeof(ip_port), "%s:%hu", peer->ip, peer->port); ast_cli(a->fd, FORMAT, peer->name, peer->accountcode, ip_port, diff --git a/apps/Makefile b/apps/Makefile index 7730460fe14..d688173501d 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -29,6 +29,8 @@ include $(ASTTOPDIR)/Makefile.moddir_rules $(call MOD_ADD_C,app_confbridge,$(wildcard confbridge/*.c)) +app_voicemail.o: _ASTCFLAGS+=-Wno-format-truncation + ifneq ($(findstring $(OSARCH), mingw32 cygwin ),) LIBS+= -lres_ael_share.so -lres_monitor.so -lres_speech.so LIBS+= -lres_smdi.so diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 354b9ea7d35..95ebace633e 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -1442,7 +1442,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data) static int dahdiscan_exec(struct ast_channel *chan, const char *data) { const char *spec = "DAHDI"; - struct ast_flags flags; + struct ast_flags flags = {0}; struct spy_dtmf_options user_options = { .cycle = '#', .volume = '\0', diff --git a/apps/app_followme.c b/apps/app_followme.c index 72afa3dd137..578118ad38a 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -1558,7 +1558,7 @@ static int app_exec(struct ast_channel *chan, const char *data) } if (!ast_strlen_zero(targs->namerecloc)) { int ret; - char fn[PATH_MAX]; + char fn[PATH_MAX + sizeof(REC_FORMAT)]; snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc, REC_FORMAT); diff --git a/apps/app_minivm.c b/apps/app_minivm.c index ff9ab340a63..9359f82f3bd 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -2251,7 +2251,7 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data) char ecodes[16] = "#"; char *tmpptr; struct minivm_account *vmu; - char *username = argv[0]; + char *username; if (ast_strlen_zero(data)) { ast_log(LOG_ERROR, "Minivm needs at least an account argument \n"); diff --git a/apps/app_queue.c b/apps/app_queue.c index f297dad8d7d..004d93a2ead 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -6610,7 +6610,6 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a char oldexten[AST_MAX_EXTENSION]=""; char oldcontext[AST_MAX_CONTEXT]=""; char queuename[256]=""; - char interfacevar[256]=""; struct ast_channel *peer; struct ast_channel *which; struct callattempt *lpeer; @@ -6811,6 +6810,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a } } else { /* peer is valid */ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); + RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free); /* Ah ha! Someone answered within the desired timeframe. Of course after this we will always return with -1 so that it is hung up properly after the conversation. */ @@ -6924,20 +6924,20 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a ao2_lock(qe->parent); /* if setinterfacevar is defined, make member variables available to the channel */ /* use pbx_builtin_setvar to set a load of variables with one call */ - if (qe->parent->setinterfacevar) { - snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", + if (qe->parent->setinterfacevar && interfacevar) { + ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); - pbx_builtin_setvar_multiple(qe->chan, interfacevar); - pbx_builtin_setvar_multiple(peer, interfacevar); + pbx_builtin_setvar_multiple(qe->chan, ast_str_buffer(interfacevar)); + pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar)); } /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ /* use pbx_builtin_setvar to set a load of variables with one call */ - if (qe->parent->setqueueentryvar) { - snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", + if (qe->parent->setqueueentryvar && interfacevar) { + ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d", (long) (time(NULL) - qe->start), qe->opos); - pbx_builtin_setvar_multiple(qe->chan, interfacevar); - pbx_builtin_setvar_multiple(peer, interfacevar); + pbx_builtin_setvar_multiple(qe->chan, ast_str_buffer(interfacevar)); + pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar)); } ao2_unlock(qe->parent); diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 0a07cc10305..5f821285959 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -7913,7 +7913,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, *duration += prepend_duration; msg_cat = ast_category_get(msg_cfg, "message", NULL); - snprintf(duration_buf, 11, "%ld", *duration); + snprintf(duration_buf, sizeof(duration_buf), "%ld", *duration); if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) { ast_config_text_file_save(textfile, msg_cfg, "app_voicemail"); } @@ -8685,7 +8685,7 @@ static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms) { int res = 0; - char filename[256], *cid; + char filename[PATH_MAX], *cid; const char *origtime, *context, *category, *duration, *flag; struct ast_config *msg_cfg; struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; diff --git a/channels/Makefile b/channels/Makefile index 44a0429a938..ae7107f7c1a 100644 --- a/channels/Makefile +++ b/channels/Makefile @@ -29,6 +29,8 @@ $(call MOD_ADD_C,chan_pjsip,$(wildcard pjsip/*.c)) $(call MOD_ADD_C,chan_dahdi,$(wildcard dahdi/*.c) sig_analog.c sig_pri.c sig_ss7.c) $(call MOD_ADD_C,chan_misdn,misdn_config.c misdn/isdn_lib.c misdn/isdn_msg_parser.c) +chan_mgcp.o: _ASTCFLAGS+=-Wno-format-truncation + chan_misdn.o: _ASTCFLAGS+=-Imisdn misdn_config.o: _ASTCFLAGS+=-Imisdn misdn/isdn_lib.o: _ASTCFLAGS+=-Wno-strict-aliasing diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 5abb6c37fb1..490c4cea51c 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -8545,7 +8545,7 @@ static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies) { int newcall = 0; struct iax_ie_data ied; - struct ast_sockaddr new; + struct ast_sockaddr new = { {0,} }; memset(&ied, 0, sizeof(ied)); if (!ast_sockaddr_isnull(&ies->apparent_addr)) { diff --git a/channels/chan_motif.c b/channels/chan_motif.c index 7d696e87dc6..210cf36c6c7 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -1901,7 +1901,7 @@ static struct ast_channel *jingle_request(const char *type, struct ast_format_ca { RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup); - char *dialed, target[200] = ""; + char *dialed, target[1024] = ""; struct ast_xmpp_buddy *buddy; struct jingle_session *session; struct ast_channel *chan; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f2daf2b8fa5..beaa3de0b15 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -2085,7 +2085,7 @@ static int sip_cc_monitor_request_cc(struct ast_cc_monitor *monitor, int *availa static int construct_pidf_body(enum sip_cc_publish_state state, char *pidf_body, size_t size, const char *presentity) { struct ast_str *body = ast_str_alloca(size); - char tuple_id[32]; + char tuple_id[64]; generate_random_string(tuple_id, sizeof(tuple_id)); @@ -15333,7 +15333,7 @@ static int transmit_cc_notify(struct ast_cc_agent *agent, struct sip_pvt *subscr { struct sip_request req; struct sip_cc_agent_pvt *agent_pvt = agent->private_data; - char uri[SIPBUFSIZE]; + char uri[SIPBUFSIZE + sizeof("cc-URI: \r\n") - 1]; char state_str[64]; char subscription_state_hdr[64]; @@ -15350,7 +15350,7 @@ static int transmit_cc_notify(struct ast_cc_agent *agent, struct sip_pvt *subscr add_header(&req, "Subscription-State", subscription_state_hdr); if (state == CC_READY) { generate_uri(subscription, agent_pvt->notify_uri, sizeof(agent_pvt->notify_uri)); - snprintf(uri, sizeof(uri) - 1, "cc-URI: %s\r\n", agent_pvt->notify_uri); + snprintf(uri, sizeof(uri), "cc-URI: %s\r\n", agent_pvt->notify_uri); } add_content(&req, state_str); if (state == CC_READY) { diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index b820cf51e9b..f124c0f2bc5 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -370,7 +370,7 @@ struct unistim_subchannel { struct unistim_line { ast_mutex_t lock; char name[80]; /*! Like 200 */ - char fullname[80]; /*! Like USTM/200\@black */ + char fullname[101]; /*! Like USTM/200\@black */ char exten[AST_MAX_EXTENSION]; /*! Extension where to start */ char cid_num[AST_MAX_EXTENSION]; /*! CallerID Number */ char mailbox[AST_MAX_EXTENSION]; /*! Mailbox for MWI */ @@ -3698,7 +3698,7 @@ static void key_select_option(struct unistimsession *pte, char keycode) #define SELECTCODEC_MSG "Codec number : .." static void handle_select_codec(struct unistimsession *pte) { - char buf[30], buf2[5]; + char buf[30], buf2[6]; pte->state = STATE_SELECTCODEC; ast_copy_string(buf, ustmtext("Using codec", pte), sizeof(buf)); diff --git a/channels/iax2/firmware.c b/channels/iax2/firmware.c index 00a9d9ebbeb..500cf893897 100644 --- a/channels/iax2/firmware.c +++ b/channels/iax2/firmware.c @@ -44,6 +44,8 @@ #include "include/firmware.h" +#define IAX_FIRMWARE_SUBDIR "/firmware/iax" + struct iax_firmware { AST_LIST_ENTRY(iax_firmware) list; int fd; @@ -206,7 +208,7 @@ void iax_firmware_reload(void) struct iax_firmware *cur = NULL; DIR *fwd; struct dirent *de; - char dir[256], fn[256]; + char fn[PATH_MAX + sizeof(IAX_FIRMWARE_SUBDIR) + sizeof(de->d_name)]; AST_LIST_LOCK(&firmwares); @@ -216,12 +218,13 @@ void iax_firmware_reload(void) } /* Now that we have marked them dead... load new ones */ - snprintf(dir, sizeof(dir), "%s/firmware/iax", ast_config_AST_DATA_DIR); - fwd = opendir(dir); + snprintf(fn, sizeof(fn), "%s%s", ast_config_AST_DATA_DIR, IAX_FIRMWARE_SUBDIR); + fwd = opendir(fn); if (fwd) { while((de = readdir(fwd))) { if (de->d_name[0] != '.') { - snprintf(fn, sizeof(fn), "%s/%s", dir, de->d_name); + snprintf(fn, sizeof(fn), "%s%s/%s", + ast_config_AST_DATA_DIR, IAX_FIRMWARE_SUBDIR, de->d_name); if (!try_firmware(fn)) { ast_verb(2, "Loaded firmware '%s'\n", de->d_name); } @@ -229,7 +232,7 @@ void iax_firmware_reload(void) } closedir(fwd); } else { - ast_log(LOG_WARNING, "Error opening firmware directory '%s': %s\n", dir, strerror(errno)); + ast_log(LOG_WARNING, "Error opening firmware directory '%s': %s\n", fn, strerror(errno)); } /* Clean up leftovers */ diff --git a/main/Makefile b/main/Makefile index 4fb6a013101..d816443d072 100644 --- a/main/Makefile +++ b/main/Makefile @@ -140,6 +140,7 @@ endif $(CMD_PREFIX) rm $@.fix ast_expr2f.o: _ASTCFLAGS+=-Wno-unused +cdr.o: _ASTCFLAGS+=-Wno-format-truncation testexpr2: ast_expr2f.c ast_expr2.c ast_expr2.h $(CC) -g -c -Iinclude -DSTANDALONE ast_expr2f.c @@ -314,7 +315,7 @@ endif endif -tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) +tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) -Wno-deprecated-declarations $(MAIN_TGT): $(OBJS) $(ASTSSL_LIB) $(ASTPJ_LIB) $(LIBEDIT_OBJ) @$(CC) -c -o buildinfo.o $(_ASTCFLAGS) buildinfo.c $(ASTCFLAGS) diff --git a/main/ast_expr2.c b/main/ast_expr2.c index 4b06ffe91c8..093b441d0dd 100644 --- a/main/ast_expr2.c +++ b/main/ast_expr2.c @@ -2635,13 +2635,11 @@ to_string (struct val *vp) if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string) return; - tmp = malloc ((size_t)25); - if (tmp == NULL) { - ast_log(LOG_WARNING,"malloc() failed\n"); + if (asprintf(&tmp, FP___PRINTF, vp->u.i) == -1) { + ast_log(LOG_WARNING, "asprintf() failed\n"); return; } - sprintf(tmp, FP___PRINTF, vp->u.i); vp->type = AST_EXPR_string; vp->u.s = tmp; } diff --git a/main/ast_expr2.y b/main/ast_expr2.y index f516291f9c3..3c8943094e7 100644 --- a/main/ast_expr2.y +++ b/main/ast_expr2.y @@ -628,13 +628,11 @@ to_string (struct val *vp) if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string) return; - tmp = malloc ((size_t)25); - if (tmp == NULL) { - ast_log(LOG_WARNING,"malloc() failed\n"); + if (asprintf(&tmp, FP___PRINTF, vp->u.i) == -1) { + ast_log(LOG_WARNING, "asprintf() failed\n"); return; } - sprintf(tmp, FP___PRINTF, vp->u.i); vp->type = AST_EXPR_string; vp->u.s = tmp; } diff --git a/main/asterisk.c b/main/asterisk.c index a302836a4de..0a131fda964 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -393,6 +393,9 @@ static void ast_el_write_default_histfile(void); static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup); +#define DEFAULT_MONITOR_DIR DEFAULT_SPOOL_DIR "/monitor" +#define DEFAULT_RECORDING_DIR DEFAULT_SPOOL_DIR "/recording" + struct _cfg_paths { char config_dir[PATH_MAX]; char module_dir[PATH_MAX]; @@ -3526,8 +3529,8 @@ static void ast_readconfig(void) ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir)); ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir)); ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir)); - snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir); - snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", cfg_paths.spool_dir); + ast_copy_string(cfg_paths.monitor_dir, DEFAULT_MONITOR_DIR, sizeof(cfg_paths.monitor_dir)); + ast_copy_string(cfg_paths.recording_dir, DEFAULT_RECORDING_DIR, sizeof(cfg_paths.recording_dir)); ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir)); ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir)); ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir)); diff --git a/main/ccss.c b/main/ccss.c index f96d7aa1d6f..a9d15b072f3 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -3546,7 +3546,7 @@ struct ast_cc_monitor *ast_cc_get_monitor_by_recall_core_id(const int core_id, c */ static void cc_unique_append(struct ast_str **str, const char *dialstring) { - char dialstring_search[AST_CHANNEL_NAME]; + char dialstring_search[AST_CHANNEL_NAME + 1]; if (ast_strlen_zero(dialstring)) { /* No dialstring to append. */ diff --git a/main/cli.c b/main/cli.c index 06f2d55b2bb..ef86e256ac3 100644 --- a/main/cli.c +++ b/main/cli.c @@ -372,7 +372,7 @@ static char *complete_number(const char *partial, unsigned int min, unsigned int int i, count = 0; unsigned int prospective[2]; unsigned int part = strtoul(partial, NULL, 10); - char next[12]; + char next[13]; if (part < min || part > max) { return NULL; @@ -1031,7 +1031,7 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar it_chans = ao2_iterator_init(channels, 0); for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) { struct ast_channel_snapshot *cs = stasis_message_data(msg); - char durbuf[10] = "-"; + char durbuf[16] = "-"; if (!count) { if ((concise || verbose) && !ast_tvzero(cs->creationtime)) { diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c index 9da63de4c56..8b19e247da9 100644 --- a/main/libasteriskssl.c +++ b/main/libasteriskssl.c @@ -29,20 +29,21 @@ #include "asterisk.h" +#include "asterisk/_private.h" /* ast_ssl_init() */ + #ifdef HAVE_OPENSSL #include #include #endif -#include +#if defined(HAVE_OPENSSL) && \ + !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -#include "asterisk/_private.h" /* ast_ssl_init() */ +#include #include "asterisk/utils.h" #include "asterisk/lock.h" -#ifdef HAVE_OPENSSL - #define get_OpenSSL_function(func) do { real_##func = dlsym(RTLD_NEXT, __stringify(func)); } while(0) static int startup_complete; @@ -72,7 +73,6 @@ static void ssl_lock(int mode, int n, const char *file, int line) } } -#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) int SSL_library_init(void) { #if defined(AST_DEVMODE) @@ -114,9 +114,6 @@ void ERR_free_strings(void) { /* we can't allow this to be called, ever */ } -#endif /* !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L */ - -#endif /* HAVE_OPENSSL */ /*! * \internal @@ -126,8 +123,6 @@ void ERR_free_strings(void) */ int ast_ssl_init(void) { -#if defined(HAVE_OPENSSL) && defined(OPENSSL_VERSION_NUMBER) && \ - (OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)) unsigned int i; int (*real_SSL_library_init)(void); void (*real_CRYPTO_set_id_callback)(unsigned long (*)(void)); @@ -192,7 +187,14 @@ int ast_ssl_init(void) startup_complete = 1; -#endif /* HAVE_OPENSSL and its version < 1.1 */ return 0; } +#else + +int ast_ssl_init(void) +{ + return 0; +} + +#endif diff --git a/main/manager.c b/main/manager.c index 1bbd1bbe94d..d16a6927810 100644 --- a/main/manager.c +++ b/main/manager.c @@ -6115,7 +6115,7 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) { struct ast_channel_snapshot *cs = stasis_message_data(msg); struct ast_str *built = ast_manager_build_channel_state_string_prefix(cs, ""); - char durbuf[10] = ""; + char durbuf[16] = ""; if (!built) { continue; diff --git a/main/stdtime/localtime.c b/main/stdtime/localtime.c index bb221aebf60..88b80202861 100644 --- a/main/stdtime/localtime.c +++ b/main/stdtime/localtime.c @@ -2434,7 +2434,7 @@ static const char *store_by_locale(locale_t prevlocale) cur = NULL; AST_LIST_LOCK(&localelist); for (x = 0; x < 10000; x++) { - char name[5]; + char name[6]; snprintf(name, sizeof(name), "%04d", x); if (!find_by_name(name)) { if ((cur = ast_calloc(1, sizeof(*cur) + strlen(name) + 1))) { diff --git a/main/utils.c b/main/utils.c index c254db52060..f20ccd36e44 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1490,7 +1490,7 @@ char *ast_strsep(char **iss, const char sep, uint32_t flags) int found = 0; char stack[8]; - if (iss == NULL || *iss == '\0') { + if (ast_strlen_zero(st)) { return NULL; } diff --git a/res/res_calendar.c b/res/res_calendar.c index 666b0e18407..9ce8159c769 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -741,7 +741,7 @@ static void *do_notify(void *data) struct ast_channel *chan = NULL; struct ast_variable *itervar; char *tech, *dest; - char buf[8]; + char buf[33]; struct ast_format_cap *caps; tech = ast_strdupa(event->owner->notify_channel); diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 536c9e17331..7a2c9dbf829 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -1294,7 +1294,7 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap /* Size is minimum length; make it at least 50% greater, * just to be sure, because PostgreSQL doesn't support * resizing columns. */ - snprintf(fieldtype, sizeof(fieldtype), "CHAR(%d)", + snprintf(fieldtype, sizeof(fieldtype), "CHAR(%hhu)", size < 15 ? size * 2 : (size * 3 / 2 > 255) ? 255 : size * 3 / 2); } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) { diff --git a/res/res_monitor.c b/res/res_monitor.c index 2ab52d87304..fd3ff7a1c9c 100644 --- a/res/res_monitor.c +++ b/res/res_monitor.c @@ -457,7 +457,7 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l LOCK_IF_NEEDED(chan, need_lock); if (ast_channel_monitor(chan)) { - char filename[ FILENAME_MAX ]; + RAII_VAR(struct ast_str *, tmp, ast_str_create(1024), ast_free); if (ast_channel_monitor(chan)->read_stream) { ast_closestream(ast_channel_monitor(chan)->read_stream); @@ -466,31 +466,29 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l ast_closestream(ast_channel_monitor(chan)->write_stream); } - if (ast_channel_monitor(chan)->filename_changed && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) { + if (tmp && ast_channel_monitor(chan)->filename_changed && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) { if (ast_fileexists(ast_channel_monitor(chan)->read_filename,NULL,NULL) > 0) { - snprintf(filename, FILENAME_MAX, "%s-in", ast_channel_monitor(chan)->filename_base); - if (ast_fileexists(filename, NULL, NULL) > 0) { - ast_filedelete(filename, NULL); + ast_str_set(&tmp, 0, "%s-in", ast_channel_monitor(chan)->filename_base); + if (ast_fileexists(ast_str_buffer(tmp), NULL, NULL) > 0) { + ast_filedelete(ast_str_buffer(tmp), NULL); } - ast_filerename(ast_channel_monitor(chan)->read_filename, filename, ast_channel_monitor(chan)->format); + ast_filerename(ast_channel_monitor(chan)->read_filename, ast_str_buffer(tmp), ast_channel_monitor(chan)->format); } else { ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->read_filename); } - if (ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) { - snprintf(filename, FILENAME_MAX, "%s-out", ast_channel_monitor(chan)->filename_base); - if (ast_fileexists(filename, NULL, NULL) > 0) { - ast_filedelete(filename, NULL); + if (tmp && ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) { + ast_str_set(&tmp, 0, "%s-out", ast_channel_monitor(chan)->filename_base); + if (ast_fileexists(ast_str_buffer(tmp), NULL, NULL) > 0) { + ast_filedelete(ast_str_buffer(tmp), NULL); } - ast_filerename(ast_channel_monitor(chan)->write_filename, filename, ast_channel_monitor(chan)->format); + ast_filerename(ast_channel_monitor(chan)->write_filename, ast_str_buffer(tmp), ast_channel_monitor(chan)->format); } else { ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->write_filename); } } - if (ast_channel_monitor(chan)->joinfiles && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) { - char tmp[1024]; - char tmp2[1024]; + if (tmp && ast_channel_monitor(chan)->joinfiles && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) { const char *format = !strcasecmp(ast_channel_monitor(chan)->format,"wav49") ? "WAV" : ast_channel_monitor(chan)->format; char *fname_base = ast_channel_monitor(chan)->filename_base; const char *execute, *execute_args; @@ -511,16 +509,17 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l if (ast_strlen_zero(execute_args)) { execute_args = ""; } - - snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &", + + ast_str_set(&tmp, 0, delfiles ? "( " : ""); + ast_str_append(&tmp, 0, "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &", execute, fname_base, format, fname_base, format, fname_base, format,execute_args); if (delfiles) { - snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */ - ast_copy_string(tmp, tmp2, sizeof(tmp)); + /* remove legs when done mixing */ + ast_str_append(&tmp, 0, "& rm -f \"%s-\"* ) &", fname_base); } - ast_debug(1,"monitor executing %s\n",tmp); - if (ast_safe_system(tmp) == -1) - ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); + ast_debug(1,"monitor executing %s\n", ast_str_buffer(tmp)); + if (ast_safe_system(ast_str_buffer(tmp)) == -1) + ast_log(LOG_WARNING, "Execute of %s failed.\n", ast_str_buffer(tmp)); } if (!ast_strlen_zero(ast_channel_monitor(chan)->beep_id)) { diff --git a/utils/astman.c b/utils/astman.c index 63d7f5ada1e..af3185104cd 100644 --- a/utils/astman.c +++ b/utils/astman.c @@ -275,7 +275,7 @@ static void rebuild_channels(newtComponent c) { void *prev = NULL; struct ast_chan *chan; - char tmpn[42]; + char tmpn[sizeof(chan->name) + sizeof(chan->callerid) + 3 - 1]; char tmp[256]; int x=0; prev = newtListboxGetCurrent(c); diff --git a/utils/extconf.c b/utils/extconf.c index d035e12c06c..1163022809d 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -4605,6 +4605,10 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_exten *e, *eroot; struct ast_include *i; + if (!context) { + return NULL; + } + /* Initialize status if appropriate */ if (q->stacklen == 0) { q->status = STATUS_NO_CONTEXT; From 2a4283f3e7f0c8459be1f6e877d3ef45a8ceacc2 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 23 Jul 2017 23:34:32 +0000 Subject: [PATCH 1398/1578] res_pjsip: Add support for dnsmgr to external_media_address. The "external_media_address" option on transports is now resolved using dnsmgr. This allows it to be automatically refreshed regularly if refreshes are enabled in dnsmgr. If the system is using a dynamic IP address a dynamic DNS hostname can be provided to keep the IP address up to date. Change-Id: Ia54771720dff0105bde55d5bbb81a3ba437e05b2 --- CHANGES | 6 +++++ include/asterisk/res_pjsip.h | 18 +++++++++++--- res/res_pjsip/config_transport.c | 42 +++++++++++++++++++++++++------- res/res_pjsip_nat.c | 6 ++--- res/res_pjsip_sdp_rtp.c | 4 +-- res/res_pjsip_session.c | 4 +-- res/res_pjsip_t38.c | 4 +-- 7 files changed, 62 insertions(+), 22 deletions(-) diff --git a/CHANGES b/CHANGES index fb54ca6400c..71166ef90f1 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,12 @@ app_queue --- Functionality changes from Asterisk 14.6.0 to Asterisk 14.7.0 ------------ ------------------------------------------------------------------------------ +res_pjsip +------------------ + * The "external_media_address" on transports is now resolved using dnsmgr and + when dnsmgr refreshes are enabled will be automatically updated with the new + IP address of a given hostname. + res_musiconhold ------------------ * By default, when res_musiconhold reloads or unloads, it sends a HUP signal diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index cb77fa35632..890ce59fba2 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -103,15 +103,25 @@ struct ast_sip_transport_state { */ struct ast_ha *localnet; /*! - * DNS manager for refreshing the external address + * DNS manager for refreshing the external signaling address * \since 13.8.0 */ - struct ast_dnsmgr_entry *external_address_refresher; + struct ast_dnsmgr_entry *external_signaling_address_refresher; /*! - * Optional external address information + * Optional external signaling address information * \since 13.8.0 */ - struct ast_sockaddr external_address; + struct ast_sockaddr external_signaling_address; + /*! + * DNS manager for refreshing the external media address + * \since 13.18.0 + */ + struct ast_dnsmgr_entry *external_media_address_refresher; + /*! + * Optional external signaling address information + * \since 13.18.0 + */ + struct ast_sockaddr external_media_address; }; /* diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 62bc9d67db2..5f7eafa1c4d 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -248,8 +248,11 @@ static int destroy_sip_transport_state(void *data) ast_free(transport_state->id); ast_free_ha(transport_state->localnet); - if (transport_state->external_address_refresher) { - ast_dnsmgr_release(transport_state->external_address_refresher); + if (transport_state->external_signaling_address_refresher) { + ast_dnsmgr_release(transport_state->external_signaling_address_refresher); + } + if (transport_state->external_media_address_refresher) { + ast_dnsmgr_release(transport_state->external_media_address_refresher); } if (transport_state->transport) { pjsip_transport_shutdown(transport_state->transport); @@ -399,8 +402,8 @@ static void copy_state_to_transport(struct ast_sip_transport *transport) memcpy(&transport->tls, &transport->state->tls, sizeof(transport->tls)); memcpy(&transport->ciphers, &transport->state->ciphers, sizeof(transport->ciphers)); transport->localnet = transport->state->localnet; - transport->external_address_refresher = transport->state->external_address_refresher; - memcpy(&transport->external_address, &transport->state->external_address, sizeof(transport->external_address)); + transport->external_address_refresher = transport->state->external_signaling_address_refresher; + memcpy(&transport->external_address, &transport->state->external_signaling_address, sizeof(transport->external_signaling_address)); } static int has_state_changed(struct ast_sip_transport_state *a, struct ast_sip_transport_state *b) @@ -421,7 +424,11 @@ static int has_state_changed(struct ast_sip_transport_state *a, struct ast_sip_t return -1; } - if (ast_sockaddr_cmp(&a->external_address, &b->external_address)) { + if (ast_sockaddr_cmp(&a->external_signaling_address, &b->external_signaling_address)) { + return -1; + } + + if (ast_sockaddr_cmp(&a->external_media_address, &b->external_media_address)) { return -1; } @@ -515,24 +522,41 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) pj_sockaddr_set_port(&temp_state->state->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060); } - /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */ + /* Now that we know what address family we can set up a dnsmgr refresh for the external addresses if present */ if (!ast_strlen_zero(transport->external_signaling_address)) { if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { - temp_state->state->external_address.ss.ss_family = AF_INET; + temp_state->state->external_signaling_address.ss.ss_family = AF_INET; } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { - temp_state->state->external_address.ss.ss_family = AF_INET6; + temp_state->state->external_signaling_address.ss.ss_family = AF_INET6; } else { ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n", transport_id); return -1; } - if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_address, &temp_state->state->external_address_refresher, NULL) < 0) { + if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_signaling_address, &temp_state->state->external_signaling_address_refresher, NULL) < 0) { ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id); return -1; } } + if (!ast_strlen_zero(transport->external_media_address)) { + if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { + temp_state->state->external_media_address.ss.ss_family = AF_INET; + } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { + temp_state->state->external_media_address.ss.ss_family = AF_INET6; + } else { + ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external media address\n", + transport_id); + return -1; + } + + if (ast_dnsmgr_lookup(transport->external_media_address, &temp_state->state->external_media_address, &temp_state->state->external_media_address_refresher, NULL) < 0) { + ast_log(LOG_ERROR, "Could not create dnsmgr for external media address on '%s'\n", transport_id); + return -1; + } + } + if (transport->type == AST_TRANSPORT_UDP) { for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c index 9205622d7ad..7dfd5ec6dca 100644 --- a/res/res_pjsip_nat.c +++ b/res/res_pjsip_nat.c @@ -273,10 +273,10 @@ static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) } } - if (!ast_sockaddr_isnull(&transport_state->external_address)) { + if (!ast_sockaddr_isnull(&transport_state->external_signaling_address)) { /* Update the contact header with the external address */ if (uri || (uri = nat_get_contact_sip_uri(tdata))) { - pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_address)); + pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address)); if (transport->external_signaling_port) { uri->port = transport->external_signaling_port; ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port); @@ -285,7 +285,7 @@ static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) /* Update the via header if relevant */ if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) { - pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_address)); + pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address)); if (transport->external_signaling_port) { via->sent_by.port = transport->external_signaling_port; } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 4ed1f8a57da..f79c4cbf068 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1820,8 +1820,8 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { return; } - ast_debug(5, "Setting media address to %s\n", transport->external_media_address); - pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address); + ast_debug(5, "Setting media address to %s\n", ast_sockaddr_stringify_host(&transport_state->external_media_address)); + pj_strdup2(tdata->pool, &stream->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address)); } /*! \brief Function which stops the RTP instance */ diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 2711efeb86a..bb349a4b67d 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -3896,8 +3896,8 @@ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_trans if (!transport_state->localnet || ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) { - ast_debug(5, "Setting external media address to %s\n", transport->external_media_address); - pj_strdup2(tdata->pool, &sdp->conn->addr, transport->external_media_address); + ast_debug(5, "Setting external media address to %s\n", ast_sockaddr_stringify_host(&transport_state->external_media_address)); + pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address)); } } diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index fbfbd0cb01d..27eff424a88 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -967,8 +967,8 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) { return; } - ast_debug(5, "Setting media address to %s\n", transport->external_media_address); - pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address); + ast_debug(5, "Setting media address to %s\n", ast_sockaddr_stringify_host(&transport_state->external_media_address)); + pj_strdup2(tdata->pool, &stream->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address)); } /*! \brief Function which destroys the UDPTL instance when session ends */ From 2be8d91c0f5802a1f9c87b35f8f419e0db1b22d8 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 26 Jul 2017 09:48:29 -0400 Subject: [PATCH 1399/1578] res_pjsip_pidf_eyebeam_body_supplement: Correct status presentation This change fixes PIDF content generation when the underlying device state is considered in use. Previously it was incorrectly marked as closed meaning they were offline/unavailable. The code now correctly marks them as open. Additionally: * Generate an XML element for our activity instead of a using a text node. * Consider every extension state other than "unavailable" to be 'open' status. * Update the XML namespaces and structure to reflect those documented in RFC 4480 * Use 'on-the-phone' (defined in RFC 4880) instead of 'busy' as the "in use" activity. This change results in eyeBeam using the appropriate icon for the watched user. This was tested on eyeBeam 1.5.20.2 build 59030 on Windows. ASTERISK-26659 #close Reported by: Abraham Liebsch patches: ASTERISK-26659.diff submitted by snuffy (license 5024) Change-Id: I6e5ad450f91106029fb30517b8c0ea0c2058c810 --- res/res_pjsip/presence_xml.c | 16 +++++----- res/res_pjsip_pidf_body_generator.c | 2 +- res/res_pjsip_pidf_eyebeam_body_supplement.c | 32 +++++++++----------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/res/res_pjsip/presence_xml.c b/res/res_pjsip/presence_xml.c index 1aca307e5a0..3cea79e984a 100644 --- a/res/res_pjsip/presence_xml.c +++ b/res/res_pjsip/presence_xml.c @@ -89,7 +89,7 @@ void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **p case AST_EXTENSION_RINGING: *statestring = "early"; *local_state = NOTIFY_INUSE; - *pidfstate = "busy"; + *pidfstate = "on-the-phone"; *pidfnote = "Ringing"; break; case (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING): @@ -99,31 +99,31 @@ void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **p *statestring = "confirmed"; } *local_state = NOTIFY_INUSE; - *pidfstate = "busy"; + *pidfstate = "on-the-phone"; *pidfnote = "Ringing"; break; case AST_EXTENSION_INUSE: *statestring = "confirmed"; *local_state = NOTIFY_INUSE; - *pidfstate = "busy"; + *pidfstate = "on-the-phone"; *pidfnote = "On the phone"; break; case AST_EXTENSION_BUSY: *statestring = "confirmed"; - *local_state = NOTIFY_CLOSED; - *pidfstate = "busy"; + *local_state = NOTIFY_INUSE; + *pidfstate = "on-the-phone"; *pidfnote = "On the phone"; break; case AST_EXTENSION_UNAVAILABLE: *statestring = "terminated"; *local_state = NOTIFY_CLOSED; - *pidfstate = "away"; + *pidfstate = "--"; *pidfnote = "Unavailable"; break; case AST_EXTENSION_ONHOLD: *statestring = "confirmed"; - *local_state = NOTIFY_CLOSED; - *pidfstate = "busy"; + *local_state = NOTIFY_INUSE; + *pidfstate = "on-the-phone"; *pidfnote = "On hold"; break; case AST_EXTENSION_NOT_INUSE: diff --git a/res/res_pjsip_pidf_body_generator.c b/res/res_pjsip_pidf_body_generator.c index cc10082ad38..29c9e6be2fd 100644 --- a/res/res_pjsip_pidf_body_generator.c +++ b/res/res_pjsip_pidf_body_generator.c @@ -75,7 +75,7 @@ static int pidf_generate_body_content(void *body, void *data) pjpidf_tuple_set_contact(state_data->pool, tuple, pj_cstr(&contact, sanitized)); pjpidf_tuple_set_contact_prio(state_data->pool, tuple, pj_cstr(&priority, "1")); pjpidf_status_set_basic_open(pjpidf_tuple_get_status(tuple), - local_state == NOTIFY_OPEN); + local_state == NOTIFY_OPEN || local_state == NOTIFY_INUSE); return 0; } diff --git a/res/res_pjsip_pidf_eyebeam_body_supplement.c b/res/res_pjsip_pidf_eyebeam_body_supplement.c index a0f50fddee5..40470840c05 100644 --- a/res/res_pjsip_pidf_eyebeam_body_supplement.c +++ b/res/res_pjsip_pidf_eyebeam_body_supplement.c @@ -46,30 +46,28 @@ */ static void add_eyebeam(pj_pool_t *pool, pj_xml_node *node, const char *pidfstate) { - static const char *XMLNS_PP = "xmlns:pp"; - static const char *XMLNS_PERSON = "urn:ietf:params:xml:ns:pidf:person"; + static const char *XMLNS_DM_PREFIX = "xmlns:dm"; + static const char *XMLNS_DM = "urn:ietf:params:xml:ns:pidf:data-model"; - static const char *XMLNS_ES = "xmlns:es"; - static const char *XMLNS_RPID_STATUS = "urn:ietf:params:xml:ns:pidf:rpid:status:rpid-status"; + static const char *XMLNS_RPID_PREFIX = "xmlns:rpid"; + static const char *XMLNS_RPID = "urn:ietf:params:xml:ns:pidf:rpid"; - static const char *XMLNS_EP = "xmlns:ep"; - static const char *XMLNS_RPID_PERSON = "urn:ietf:params:xml:ns:pidf:rpid:rpid-person"; - - pj_xml_node *person = ast_sip_presence_xml_create_node(pool, node, "pp:person"); - pj_xml_node *status = ast_sip_presence_xml_create_node(pool, person, "status"); + pj_xml_node *person = ast_sip_presence_xml_create_node(pool, node, "dm:person"); if (pidfstate[0] != '-') { - pj_xml_node *activities = ast_sip_presence_xml_create_node(pool, status, "ep:activities"); - size_t str_size = sizeof("ep:") + strlen(pidfstate); + pj_xml_node *activities = ast_sip_presence_xml_create_node(pool, person, "rpid:activities"); + size_t str_size = sizeof("rpid:") + strlen(pidfstate); + char *act_str = ast_alloca(str_size); + + /* Safe */ + strcpy(act_str, "rpid:"); + strcat(act_str, pidfstate); - activities->content.ptr = pj_pool_alloc(pool, str_size); - activities->content.slen = pj_ansi_snprintf(activities->content.ptr, str_size, - "ep:%s", pidfstate); + ast_sip_presence_xml_create_node(pool, activities, act_str); } - ast_sip_presence_xml_create_attr(pool, node, XMLNS_PP, XMLNS_PERSON); - ast_sip_presence_xml_create_attr(pool, node, XMLNS_ES, XMLNS_RPID_STATUS); - ast_sip_presence_xml_create_attr(pool, node, XMLNS_EP, XMLNS_RPID_PERSON); + ast_sip_presence_xml_create_attr(pool, node, XMLNS_DM_PREFIX, XMLNS_DM); + ast_sip_presence_xml_create_attr(pool, node, XMLNS_RPID_PREFIX, XMLNS_RPID); } static int pidf_supplement_body(void *body, void *data) From 148cf2e0f7b0fe94f92e07731f652e6e1d49569e Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 2 Aug 2017 17:08:38 -0400 Subject: [PATCH 1400/1578] app_privacy: remove unused header asterisk/image.h Change-Id: I56ed530633a642633b18383821069e806c92ae82 --- apps/app_privacy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/app_privacy.c b/apps/app_privacy.c index a9afe02220e..86aec015149 100644 --- a/apps/app_privacy.c +++ b/apps/app_privacy.c @@ -38,7 +38,6 @@ #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/translate.h" -#include "asterisk/image.h" #include "asterisk/callerid.h" #include "asterisk/app.h" #include "asterisk/config.h" From 4b03eb5c3822765a49b7ab4b05294ce7c012522b Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 2 Aug 2017 15:16:43 -0400 Subject: [PATCH 1401/1578] Fix compile error for old versions of GCC. Use -Wno-format-truncation only if supported by compiler. ASTERISK-27171 #close Change-Id: Iac0aed7a5bcaa16c21b7d62c4e4678d244c4ccb6 --- apps/Makefile | 2 +- channels/Makefile | 2 +- configure | 38 ++++++++++++++++++++------------------ configure.ac | 10 ++++++++++ main/Makefile | 2 +- makeopts.in | 1 + 6 files changed, 34 insertions(+), 21 deletions(-) diff --git a/apps/Makefile b/apps/Makefile index d688173501d..d7f755ff15b 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -29,7 +29,7 @@ include $(ASTTOPDIR)/Makefile.moddir_rules $(call MOD_ADD_C,app_confbridge,$(wildcard confbridge/*.c)) -app_voicemail.o: _ASTCFLAGS+=-Wno-format-truncation +app_voicemail.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION) ifneq ($(findstring $(OSARCH), mingw32 cygwin ),) LIBS+= -lres_ael_share.so -lres_monitor.so -lres_speech.so diff --git a/channels/Makefile b/channels/Makefile index ae7107f7c1a..242d3f46af0 100644 --- a/channels/Makefile +++ b/channels/Makefile @@ -29,7 +29,7 @@ $(call MOD_ADD_C,chan_pjsip,$(wildcard pjsip/*.c)) $(call MOD_ADD_C,chan_dahdi,$(wildcard dahdi/*.c) sig_analog.c sig_pri.c sig_ss7.c) $(call MOD_ADD_C,chan_misdn,misdn_config.c misdn/isdn_lib.c misdn/isdn_msg_parser.c) -chan_mgcp.o: _ASTCFLAGS+=-Wno-format-truncation +chan_mgcp.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION) chan_misdn.o: _ASTCFLAGS+=-Imisdn misdn_config.o: _ASTCFLAGS+=-Imisdn diff --git a/configure b/configure index 5bb75236bd3..9bbff7677c4 100755 --- a/configure +++ b/configure @@ -701,6 +701,7 @@ BIND8_CFLAGS AST_RPATH AST_NATIVE_ARCH AST_SHADOW_WARNINGS +AST_NO_FORMAT_TRUNCATION AST_NO_STRICT_OVERFLOW AST_FORTIFY_SOURCE AST_TRAMPOLINES @@ -1356,7 +1357,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1541,7 +1541,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1794,15 +1793,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1940,7 +1930,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2093,7 +2083,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -14927,7 +14916,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14973,7 +14962,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14997,7 +14986,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15042,7 +15031,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15066,7 +15055,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -19069,6 +19058,19 @@ $as_echo "no" >&6; } fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wno-format-truncation" >&5 +$as_echo_n "checking for -Wno-format-truncation... " >&6; } +if $(${CC} -O2 -Wno-format-truncation -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + AST_NO_FORMAT_TRUNCATION=-Wno-format-truncation +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + AST_NO_FORMAT_TRUNCATION= +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wshadow" >&5 $as_echo_n "checking for -Wshadow... " >&6; } if $(${CC} -Wshadow -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then diff --git a/configure.ac b/configure.ac index a2eaab4ada8..32b5fc09b27 100644 --- a/configure.ac +++ b/configure.ac @@ -1252,6 +1252,16 @@ else fi AC_SUBST(AST_NO_STRICT_OVERFLOW) +AC_MSG_CHECKING(for -Wno-format-truncation) +if $(${CC} -O2 -Wno-format-truncation -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then + AC_MSG_RESULT(yes) + AST_NO_FORMAT_TRUNCATION=-Wno-format-truncation +else + AC_MSG_RESULT(no) + AST_NO_FORMAT_TRUNCATION= +fi +AC_SUBST(AST_NO_FORMAT_TRUNCATION) + AC_MSG_CHECKING(for -Wshadow) if $(${CC} -Wshadow -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then AC_MSG_RESULT(yes) diff --git a/main/Makefile b/main/Makefile index d816443d072..e64aace2654 100644 --- a/main/Makefile +++ b/main/Makefile @@ -140,7 +140,7 @@ endif $(CMD_PREFIX) rm $@.fix ast_expr2f.o: _ASTCFLAGS+=-Wno-unused -cdr.o: _ASTCFLAGS+=-Wno-format-truncation +cdr.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION) testexpr2: ast_expr2f.c ast_expr2.c ast_expr2.h $(CC) -g -c -Iinclude -DSTANDALONE ast_expr2f.c diff --git a/makeopts.in b/makeopts.in index 07360a71b47..887a1556754 100644 --- a/makeopts.in +++ b/makeopts.in @@ -116,6 +116,7 @@ AST_ASTERISKSSL=@AST_ASTERISKSSL@ AST_DECLARATION_AFTER_STATEMENT=@AST_DECLARATION_AFTER_STATEMENT@ AST_TRAMPOLINES=@AST_TRAMPOLINES@ AST_NO_STRICT_OVERFLOW=@AST_NO_STRICT_OVERFLOW@ +AST_NO_FORMAT_TRUNCATION=@AST_NO_FORMAT_TRUNCATION@ AST_SHADOW_WARNINGS=@AST_SHADOW_WARNINGS@ AST_NESTED_FUNCTIONS=@AST_NESTED_FUNCTIONS@ AST_CLANG_BLOCKS=@AST_CLANG_BLOCKS@ From 4c0798e91dff59682c16e269a87a181ea198a64e Mon Sep 17 00:00:00 2001 From: kkm Date: Sat, 29 Jul 2017 23:17:00 -0700 Subject: [PATCH 1402/1578] chan_sip: Add dialplan function SIP_HEADERS Syntax: SIP_HEADERS([prefix]) If the argument is specified, only the headers matching the given prefix are returned. The function returns a comma-separated list of SIP header names from an incoming INVITE message. Multiple headers with the same name are included in the list only once. The returned list can be iterated over using the functions POP() and SIP_HEADER(). For example, '${SIP_HEADERS(Co)}' might return the string 'Contact,Content-Length,Content-Type'. Practical use is rather '${SIP_HEADERS(X-)}' to enumerate optional extended headers sent by a peer. ASTERISK-27163 Change-Id: I2076d3893d03a2f82429f393b5b46db6cf68a267 --- CHANGES | 10 +++- channels/chan_sip.c | 121 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 71166ef90f1..4f5225ac1b1 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,14 @@ === ============================================================================== +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 15 to Asterisk 16 -------------------- +------------------------------------------------------------------------------ + +chan_sip +------------------ + * New function SIP_HEADERS() enumerates all headers in the incoming INVITE. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ @@ -1539,7 +1547,7 @@ res_pjsip_endpoint_identifer_ip ------------------ * New CLI commands have been added: "pjsip show identif(y|ies)", which lists all configured PJSIP identify objects - + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 12 to Asterisk 13 -------------------- ------------------------------------------------------------------------------ diff --git a/channels/chan_sip.c b/channels/chan_sip.c index beaa3de0b15..941a1e96dc0 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -380,6 +380,37 @@ Please observe that contents of the SDP (an attachment to the SIP request) can't be accessed with this function. + + SIP_HEADERS + + + + + Gets the list of SIP header names from an incoming INVITE message. + + + + If specified, only the headers matching the given prefix are returned. + + + + Returns a comma-separated list of header names (without values) from the + INVITE message that originated the current channel. Multiple headers with the + same name are included in the list only once. The returned list can be iterated + over using the functions POP() and SIP_HEADER(). + For example, ${SIP_HEADERS(Co)} might return + Contact,Content-Length,Content-Type. As a practical example, + you may use ${SIP_HEADERS(X-)} to enumerate optional extended + headers. + This function does not access headers from the incoming SIP REFER message; + see the documentation of the function SIP_HEADER for how to access them. + Please observe that contents of the SDP (an attachment to the + SIP request) can't be accessed with this function. + + + SIP_HEADER + POP + @@ -22995,6 +23026,7 @@ static int func_header_read(struct ast_channel *chan, const char *function, char { struct sip_pvt *p; const char *content = NULL; + char *mutable_data = ast_strdupa(data); AST_DECLARE_APP_ARGS(args, AST_APP_ARG(header); AST_APP_ARG(number); @@ -23018,7 +23050,7 @@ static int func_header_read(struct ast_channel *chan, const char *function, char return -1; } - AST_STANDARD_APP_ARGS(args, data); + AST_STANDARD_APP_ARGS(args, mutable_data); if (!args.number) { number = 1; } else { @@ -23054,6 +23086,91 @@ static struct ast_custom_function sip_header_function = { .read = func_header_read, }; +/*! \brief Read unique list of SIP headers (dialplan function) */ +static int func_headers_read2(struct ast_channel *chan, const char *function, char *data, struct ast_str **buf, ssize_t maxlen) +{ + int i; + struct sip_pvt *pvt; + char *mutable_data = ast_strdupa(data); + struct ast_str *token = ast_str_alloca(100); + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(pattern); + ); + + if (!chan) { + return -1; + } + + ast_channel_lock(chan); + + if (!IS_SIP_TECH(ast_channel_tech(chan))) { + ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n"); + ast_channel_unlock(chan); + return -1; + } + + pvt = ast_channel_tech_pvt(chan); + if (!pvt) { + ast_channel_unlock(chan); + return -1; + } + + AST_STANDARD_APP_ARGS(args, mutable_data); + if (!args.pattern || strcmp(args.pattern, "*") == 0) { + args.pattern = ""; + } + + for (i = 0; i < pvt->initreq.headers; i++) { + const char *header = REQ_OFFSET_TO_STR(&pvt->initreq, header[i]); + if (ast_begins_with(header, args.pattern)) { + int hdrlen = strcspn(header, " \t:,"); /* Comma will break our logic, and illegal per RFC. */ + const char *term = ast_skip_blanks(header + hdrlen); + if (hdrlen > 0 && *term == ':') { /* Header is malformed otherwise! */ + const char *s = NULL; + + /* Return short headers in full form always. */ + if (hdrlen == 1) { + char short_hdr[2] = { header[0], '\0' }; + s = find_full_alias(short_hdr, NULL); + } + if (s) { + /* Short header was found and expanded. */ + ast_str_set(&token, -1, "%s,", s); + } else { + /* Return the header as is, whether 1-character or not. */ + ast_str_set(&token, -1, "%.*s,", hdrlen, header); + } + + /* Has the same header been already added? */ + s = ast_str_buffer(*buf); + while ((s = strstr(s, ast_str_buffer(token))) != NULL) { + /* Found suffix, but is it the full token? */ + if (s == ast_str_buffer(*buf) || s[-1] == ',') + break; + /* Only suffix matched, go on with the search after the comma. */ + s += hdrlen + 1; + } + + /* s is null iff not broken from the loop, hence header not yet added. */ + if (s == NULL) { + ast_str_append(buf, maxlen, "%s", ast_str_buffer(token)); + } + } + } + } + + ast_str_truncate(*buf, -1); /* Trim the last comma. Safe if empty. */ + + ast_channel_unlock(chan); + return 0; +} + +static struct ast_custom_function sip_headers_function = { + .name = "SIP_HEADERS", + .read2 = func_headers_read2, +}; + + /*! \brief Dial plan function to check if domain is local */ static int func_check_sipdomain(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -35201,6 +35318,7 @@ static int load_module(void) /* Register dialplan functions */ ast_custom_function_register(&sip_header_function); + ast_custom_function_register(&sip_headers_function); ast_custom_function_register(&sippeer_function); ast_custom_function_register(&checksipdomain_function); @@ -35301,6 +35419,7 @@ static int unload_module(void) /* Unregister dial plan functions */ ast_custom_function_unregister(&sippeer_function); + ast_custom_function_unregister(&sip_headers_function); ast_custom_function_unregister(&sip_header_function); ast_custom_function_unregister(&checksipdomain_function); From 521b6fed12b7466a63bee5956e112de96824b1a8 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Wed, 2 Aug 2017 09:43:56 -0500 Subject: [PATCH 1403/1578] alembic/res_pjsip: Add "webrtc" configuration option When the "webrtc" option was added in res_pjsip it was not added to the alembic scripts. This patch adds the option for alembic. Also, changed the sorcery configuration type to an OPT_YESNO_T value instead of an OPT_BOOL_T so if this field is ever written to a database it will write out the correct value. ASTERISK-27119 #close Change-Id: I3e199f060aea25e193c439fc5cf96be4d3ed1c7b --- .../versions/44ccced114ce_add_webrtc.py | 31 +++++++++++++++++++ res/res_pjsip/pjsip_configuration.c | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 contrib/ast-db-manage/config/versions/44ccced114ce_add_webrtc.py diff --git a/contrib/ast-db-manage/config/versions/44ccced114ce_add_webrtc.py b/contrib/ast-db-manage/config/versions/44ccced114ce_add_webrtc.py new file mode 100644 index 00000000000..fdeb058da47 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/44ccced114ce_add_webrtc.py @@ -0,0 +1,31 @@ +"""add webrtc option to ps_endpoints + +Revision ID: 44ccced114ce +Revises: 164abbd708c +Create Date: 2017-07-10 17:07:25.926150 + +""" + +# revision identifiers, used by Alembic. +revision = '44ccced114ce' +down_revision = '164abbd708c' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoints', sa.Column('webrtc', yesno_values)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'webrtc') diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 4e12b04cca8..d3ff1f32bc1 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1994,7 +1994,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle)); - ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); From 123c93a77c5411f0d8686d454640ae3e619fd658 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Thu, 3 Aug 2017 14:13:01 -0400 Subject: [PATCH 1404/1578] Support GMIME 3.0 Support building the Asterisk httpd with version 3.0 of gmime as well as earlier versions of that library. ASTERISK-27173 Change-Id: I7e13dd05a3083ccb0df2dabf83110223f6a9fa8f --- configure | 2 +- configure.ac | 2 +- res/res_http_post.c | 19 +++++++++++++++++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 5bb75236bd3..c25f031a3b4 100755 --- a/configure +++ b/configure @@ -34582,7 +34582,7 @@ fi fi fi -for ver in 2.0 2.2 2.4 2.6; do +for ver in 2.0 2.2 2.4 2.6 3.0; do if test "x${PBX_GMIME}" != "x1" -a "${USE_GMIME}" != "no"; then diff --git a/configure.ac b/configure.ac index a2eaab4ada8..0c392ace260 100644 --- a/configure.ac +++ b/configure.ac @@ -2548,7 +2548,7 @@ then fi fi -for ver in 2.0 2.2 2.4 2.6; do +for ver in 2.0 2.2 2.4 2.6 3.0; do AST_PKG_CONFIG_CHECK([GMIME], gmime-$ver) if test "$PBX_GMIME" = 1; then break; diff --git a/res/res_http_post.c b/res/res_http_post.c index 3f0a58e36b8..9f5b1837a27 100644 --- a/res/res_http_post.c +++ b/res/res_http_post.c @@ -55,6 +55,9 @@ #ifdef GMIME_TYPE_CONTENT_TYPE #define AST_GMIME_VER_24 #endif +#if GMIME_MAJOR_VERSION >= 3 +#define AST_GMIME_VER_30 +#endif /* just a little structure to hold callback info for gmime */ struct mime_cbinfo { @@ -84,7 +87,11 @@ static void post_raw(GMimePart *part, const char *post_dir, const char *fn) stream = g_mime_stream_fs_new(fd); +#ifdef AST_GMIME_VER_30 + content = g_mime_part_get_content(part); +#else content = g_mime_part_get_content_object(part); +#endif g_mime_data_wrapper_write_to_stream(content, stream); g_mime_stream_flush(stream); @@ -107,7 +114,11 @@ static GMimeMessage *parse_message(FILE *f) g_object_unref(stream); - message = g_mime_parser_construct_message(parser); + message = g_mime_parser_construct_message(parser +#ifdef AST_GMIME_VER_30 + , NULL +#endif + ); g_object_unref(parser); @@ -486,7 +497,11 @@ static int reload(void) static int load_module(void) { - g_mime_init(0); + g_mime_init( +#ifndef AST_GMIME_VER_30 + 0 +#endif + ); __ast_http_post_load(0); From 5655cded78960716e05702b1d27e5e84ce560f2d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 31 Jul 2017 14:20:02 -0500 Subject: [PATCH 1405/1578] res_pjsip_registrar.c: Remove unnecessary CMP_STOP. Most uses of CMP_STOP are superfluous and are only respected when OBJ_MULTIPLE is used to search the container. Change-Id: I20571a202ec0aa1098bb2749eeba18de7ca110b8 --- res/res_pjsip_registrar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index 2db75388900..a4ce54769f7 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -123,7 +123,7 @@ static int registrar_find_contact(void *obj, void *arg, int flags) const struct registrar_contact_details *details = arg; pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0); - return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH | CMP_STOP : 0; + return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0; } /*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */ From 564927c5ed1880132069b0c77878c456afa16787 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 31 Jul 2017 20:20:13 -0500 Subject: [PATCH 1406/1578] res_pjsip_nat.c: Remove unnecessary CMP_STOP. Change-Id: I6279b0d723bc3b75b8d65e81e02da9ea9bc0c3da --- res/res_pjsip_nat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c index 7dfd5ec6dca..45b0d7ce6b6 100644 --- a/res/res_pjsip_nat.c +++ b/res/res_pjsip_nat.c @@ -35,6 +35,7 @@ static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri) { pj_cstr(&uri->host, rdata->pkt_info.src_name); + uri->port = rdata->pkt_info.src_port; if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) { /* WSS is special, we don't want to overwrite the URI at all as it needs to be ws */ } else if (strcasecmp("udp", rdata->tp_info.transport->type_name)) { @@ -42,7 +43,6 @@ static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri) } else { uri->transport_param.slen = 0; } - uri->port = rdata->pkt_info.src_port; } static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg) @@ -165,7 +165,7 @@ static int find_transport_state_in_use(void *obj, void *arg, int flags) ((details->type == transport_state->type) && (transport_state->factory) && !pj_strcmp(&transport_state->factory->addr_name.host, &details->local_address) && transport_state->factory->addr_name.port == details->local_port))) { - return CMP_MATCH | CMP_STOP; + return CMP_MATCH; } return 0; From 615b6a200af6142656f9246718796c54df1258de Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 2 Aug 2017 18:41:49 -0500 Subject: [PATCH 1407/1578] res_pjsip_outbound_registration.c: Misc fixes. * Remove unnecessary CMP_STOP. * In handle_client_registration() use DEBUG_ATLEAST() to only do work needed for the debug log message when the debug log message is needed. * In sip_outbound_registration_state_destroy() check state->registration for NULL. Change-Id: I656d0fa11dda0b00048103efb1558e67a426fd80 --- res/res_pjsip_outbound_registration.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 8a840ff05eb..7b605b98288 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -459,7 +459,7 @@ static int line_identify_relationship(void *obj, void *arg, int flags) struct sip_outbound_registration_state *state = obj; pjsip_param *line = arg; - return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH | CMP_STOP : 0; + return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH : 0; } static struct pjsip_param *get_uri_option_line(const void *uri) @@ -558,20 +558,21 @@ static int handle_client_registration(void *data) { RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup); pjsip_tx_data *tdata; - pjsip_regc_info info; - char server_uri[PJSIP_MAX_URL_SIZE]; - char client_uri[PJSIP_MAX_URL_SIZE]; if (client_state->status == SIP_REGISTRATION_STOPPED || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) { return 0; } - pjsip_regc_get_info(client_state->client, &info); - ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri)); - ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri)); - ast_debug(1, "Outbound REGISTER attempt %u to '%s' with client '%s'\n", - client_state->retries + 1, server_uri, client_uri); + if (DEBUG_ATLEAST(1)) { + pjsip_regc_info info; + + pjsip_regc_get_info(client_state->client, &info); + ast_log(LOG_DEBUG, "Outbound REGISTER attempt %u to '%.*s' with client '%.*s'\n", + client_state->retries + 1, + (int) info.server_uri.slen, info.server_uri.ptr, + (int) info.client_uri.slen, info.client_uri.ptr); + } if (client_state->support_path) { pjsip_supported_hdr *hdr; @@ -987,7 +988,8 @@ static void sip_outbound_registration_state_destroy(void *obj) struct sip_outbound_registration_state *state = obj; ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n", - state->registration->server_uri, state->registration->client_uri); + state->registration ? state->registration->server_uri : "", + state->registration ? state->registration->client_uri : ""); ao2_cleanup(state->registration); if (!state->client_state) { From 842e1414d025170d9f733cf7662f50cb31c05cc2 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 26 Jul 2017 17:49:57 -0500 Subject: [PATCH 1408/1578] res_pjsip_transport_websocket.c: Fix serializer ref leak. Change-Id: Ib5a19bfd597f63d9021baeb645fc11153b3afa57 --- res/res_pjsip_transport_websocket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index cdda8c19642..1429cceed8b 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -365,6 +365,7 @@ static void websocket_cb(struct ast_websocket *session, struct ast_variable *par if (ast_sip_push_task_synchronous(serializer, transport_create, &create_data)) { ast_log(LOG_ERROR, "Could not create WebSocket transport.\n"); + ast_taskprocessor_unreference(serializer); ast_websocket_unref(session); return; } From 7f8f3ca4dddb99b79f1b2455c04ed9f14600d758 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 3 Aug 2017 21:58:25 -0400 Subject: [PATCH 1409/1578] Correct some leaks in unit tests. * chan_sip: channel in test_sip_rtpqos_1. * test_config: config hook, config info and global config holder. * test_core_format: format in format_attribute_set_without_interface. * test_stream: unneeded frame duplication. * test_taskprocessor: task_data. Change-Id: I94d364d195cf3b3b5de2bf3ad565343275c7ad31 --- channels/sip/dialplan_functions.c | 3 +++ tests/test_config.c | 3 +++ tests/test_core_format.c | 5 ++++- tests/test_stream.c | 2 +- tests/test_taskprocessor.c | 2 +- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c index e21bb2c240c..59e841df478 100644 --- a/channels/sip/dialplan_functions.c +++ b/channels/sip/dialplan_functions.c @@ -484,6 +484,9 @@ AST_TEST_DEFINE(test_sip_rtpqos_1) dialog_unlink_all(p); dialog_unref(p, "Destroy test object"); } + if (chan) { + ast_channel_unref(chan); + } ast_rtp_engine_unregister(&test_engine); return res; } diff --git a/tests/test_config.c b/tests/test_config.c index d737108604b..8675cb8906f 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -1038,6 +1038,7 @@ AST_TEST_DEFINE(config_hook) res = AST_TEST_PASS; out: + ast_config_hook_unregister("test_hook"); delete_config_file(); return res; } @@ -1675,6 +1676,8 @@ AST_TEST_DEFINE(config_options_test) configs.codeccapopt = NULL; ast_string_field_free_memory(&defaults); ast_string_field_free_memory(&configs); + aco_info_destroy(&cfg_info); + ao2_global_obj_release(global_obj); return res; } diff --git a/tests/test_core_format.c b/tests/test_core_format.c index a697f8e7d59..164dff81fd3 100644 --- a/tests/test_core_format.c +++ b/tests/test_core_format.c @@ -858,6 +858,7 @@ AST_TEST_DEFINE(format_attribute_set_without_interface) { RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + struct ast_format *attr_set; switch (cmd) { case TEST_INIT: @@ -883,10 +884,12 @@ AST_TEST_DEFINE(format_attribute_set_without_interface) return AST_TEST_FAIL; } - if (!ast_format_attribute_set(format, "bees", "cool")) { + attr_set = ast_format_attribute_set(format, "bees", "cool"); + if (!attr_set) { ast_test_status_update(test, "Successfully set an attribute on a format without an interface\n"); return AST_TEST_FAIL; } + ao2_cleanup(attr_set); return AST_TEST_PASS; } diff --git a/tests/test_stream.c b/tests/test_stream.c index fdb9885849e..28983e05cce 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -1522,7 +1522,7 @@ static int load_stream_readqueue(struct ast_channel *chan, int frames) } f.stream_num = pvt->frame_count % pvt->streams; f.seqno = pvt->frame_count; - ast_queue_frame(chan, ast_frdup(&f)); + ast_queue_frame(chan, &f); pvt->frame_count++; } diff --git a/tests/test_taskprocessor.c b/tests/test_taskprocessor.c index be48f92488f..ad2074cb8d8 100644 --- a/tests/test_taskprocessor.c +++ b/tests/test_taskprocessor.c @@ -677,7 +677,7 @@ AST_TEST_DEFINE(taskprocessor_push_local) { RAII_VAR(struct ast_taskprocessor *, tps, NULL, ast_taskprocessor_unreference); - struct task_data *task_data; + RAII_VAR(struct task_data *, task_data, NULL, ao2_cleanup); int local_data; int res; From 104a8047a53b538b76d7befaf1c95eea9ad5114e Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Fri, 4 Aug 2017 16:47:30 -0500 Subject: [PATCH 1410/1578] res_pjsip_session/_sdp_rtp: Handling of 'msid' is incorrect Currently, the handling of the msid attribute is not quite right. According to the spec the msid's between the offer/answer are not dependent upon one another. Meaning the same msid's given in an offer do not have to be returned in the answer for a given stream. And they probably shouldn't be (copied/reused) since this can potentially cause some browser side confusion. This patch generates new msids when both an offer and answer are sent from Asterisk. However, Asterisk does reuse the original msid it sent out for a reinvite. Also audio+video streams are paired together by sharing the same stream id, but a different track id. ASTERISK-27179 #close Change-Id: Ifaec06dc7e65ad841633a24ebec8c8a9302d6643 --- include/asterisk/res_pjsip_session.h | 6 ++-- res/res_pjsip_sdp_rtp.c | 53 ++++++++++++++-------------- res/res_pjsip_session.c | 1 - 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index caf10db1112..5f49c82371e 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -105,8 +105,10 @@ struct ast_sip_session_media { int bundle_group; /*! \brief Whether this stream is currently bundled or not */ unsigned int bundled; - /*! \brief RTP/Media streams association identifier */ - char *msid; + /*! \brief Media stream label */ + char mslabel[AST_UUID_STR_LEN]; + /*! \brief Track label */ + char label[AST_UUID_STR_LEN]; }; /*! diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index f79c4cbf068..77cd807825f 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1025,44 +1025,46 @@ static void process_ssrc_attributes(struct ast_sip_session *session, struct ast_ } } -static void process_msid_attribute(struct ast_sip_session *session, - struct ast_sip_session_media *session_media, pjmedia_sdp_media *media) +static void add_msid_to_stream(struct ast_sip_session *session, + struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media, + struct ast_stream *stream) { + pj_str_t stmp; pjmedia_sdp_attr *attr; + char msid[(AST_UUID_STR_LEN * 2) + 2]; if (!session->endpoint->media.webrtc) { return; } - attr = pjmedia_sdp_media_find_attr2(media, "msid", NULL); - if (attr) { - ast_free(session_media->msid); - ast_copy_pj_str2(&session_media->msid, &attr->value); - } -} + if (ast_strlen_zero(session_media->mslabel)) { + if (ast_sip_session_is_pending_stream_default(session, stream)) { + int index; -static void add_msid_to_stream(struct ast_sip_session *session, - struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media) -{ - pj_str_t stmp; - pjmedia_sdp_attr *attr; + /* If this is a default stream we group them together under the same stream, but as different tracks */ + for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) { + struct ast_sip_session_media *other_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index); - if (!session->endpoint->media.webrtc) { - return; - } + if (session_media == other_session_media) { + continue; + } - if (ast_strlen_zero(session_media->msid)) { - char uuid1[AST_UUID_STR_LEN], uuid2[AST_UUID_STR_LEN]; + ast_copy_string(session_media->mslabel, other_session_media->mslabel, sizeof(session_media->mslabel)); + break; + } + } - if (ast_asprintf(&session_media->msid, "{%s} {%s}", - ast_uuid_generate_str(uuid1, sizeof(uuid1)), - ast_uuid_generate_str(uuid2, sizeof(uuid2))) < 0) { - session_media->msid = NULL; - return; + if (ast_strlen_zero(session_media->mslabel)) { + ast_uuid_generate_str(session_media->mslabel, sizeof(session_media->mslabel)); } } - attr = pjmedia_sdp_attr_create(pool, "msid", pj_cstr(&stmp, session_media->msid)); + if (ast_strlen_zero(session_media->label)) { + ast_uuid_generate_str(session_media->label, sizeof(session_media->label)); + } + + snprintf(msid, sizeof(msid), "%s %s", session_media->mslabel, session_media->label); + attr = pjmedia_sdp_attr_create(pool, "msid", pj_cstr(&stmp, msid)); pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr); } @@ -1127,7 +1129,6 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, } process_ssrc_attributes(session, session_media, stream); - process_msid_attribute(session, session_media, stream); session_media_transport = ast_sip_session_media_get_transport(session, session_media); if (session_media_transport == session_media || !session_media->bundled) { @@ -1586,7 +1587,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } add_ssrc_to_stream(session, session_media, pool, media); - add_msid_to_stream(session, session_media, pool, media); + add_msid_to_stream(session, session_media, pool, media, stream); add_rtcp_fb_to_stream(session, session_media, pool, media); /* Add the media stream to the SDP */ diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index bb349a4b67d..607f329abfc 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -395,7 +395,6 @@ static void session_media_dtor(void *obj) } ast_free(session_media->mid); - ast_free(session_media->msid); } struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session, From 16cfc3a954e2db42519c32bc5a84ac8ccb367658 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 5 Aug 2017 15:43:39 -0400 Subject: [PATCH 1411/1578] channel: Fix leak on successful call to chan->tech->requester. joint_cap needs to be released unconditionally as chan->tech->requester does not steal the reference even on success. ASTERISK-27180 #close Change-Id: I647728992559bdb0a9c7357c20be1b36400d68b6 --- main/channel.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/main/channel.c b/main/channel.c index 66825559c28..632d4724783 100644 --- a/main/channel.c +++ b/main/channel.c @@ -6022,7 +6022,7 @@ static struct ast_channel *request_channel(const char *type, struct ast_format_c const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause) { struct chanlist *chan; - struct ast_channel *c; + struct ast_channel *c = NULL; int res; int foo; @@ -6063,9 +6063,6 @@ static struct ast_channel *request_channel(const char *type, struct ast_format_c c = chan->tech->requester_with_stream_topology(type, topology, assignedids, requestor, addr, cause); ast_stream_topology_free(tmp_converted_topology); - if (!c) { - return NULL; - } } else if (chan->tech->requester) { struct ast_format_cap *tmp_converted_cap = NULL; struct ast_format_cap *tmp_cap; @@ -6116,12 +6113,10 @@ static struct ast_channel *request_channel(const char *type, struct ast_format_c ao2_cleanup(tmp_converted_cap); c = chan->tech->requester(type, joint_cap, assignedids, requestor, addr, cause); + ao2_ref(joint_cap, -1); + } - if (!c) { - ao2_ref(joint_cap, -1); - return NULL; - } - } else { + if (!c) { return NULL; } From 88c65f7cb6f2064ba1b6a7713cb47c9a63790f8f Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sun, 6 Aug 2017 16:15:34 +0000 Subject: [PATCH 1412/1578] bridge: Fix stream topology/participant locking and video misrouting. This change fixes a few locking issues and some video misrouting. 1. When accessing the stream topology of a channel the channel lock must be held to guarantee the topology remains valid. 2. When a channel was joined to a bridge the bridge specific implementation for stream mapping was not invoked, causing video to be misrouted for a brief period of time. ASTERISK-27182 Change-Id: I5d2f779248b84d41c5bb3896bf22ba324b336b03 --- bridges/bridge_softmix.c | 39 +++++++++++++++++++++++++++------------ main/bridge.c | 7 ++++++- main/bridge_channel.c | 27 ++++++++++++++++++--------- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index c5428a85451..b35994895e1 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -577,13 +577,18 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast struct ast_stream_topology *joiner_video = NULL; struct ast_stream_topology *existing_video = NULL; struct ast_bridge_channel *participant; + int res; joiner_video = ast_stream_topology_alloc(); if (!joiner_video) { return; } - if (append_source_streams(joiner_video, ast_channel_name(joiner->chan), ast_channel_get_stream_topology(joiner->chan))) { + ast_channel_lock(joiner->chan); + res = append_source_streams(joiner_video, ast_channel_name(joiner->chan), ast_channel_get_stream_topology(joiner->chan)); + ast_channel_unlock(joiner->chan); + + if (res) { goto cleanup; } @@ -596,13 +601,18 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast if (participant == joiner) { continue; } - if (append_source_streams(existing_video, ast_channel_name(participant->chan), - ast_channel_get_stream_topology(participant->chan))) { + ast_channel_lock(participant->chan); + res = append_source_streams(existing_video, ast_channel_name(participant->chan), + ast_channel_get_stream_topology(participant->chan)); + ast_channel_unlock(participant->chan); + if (res) { goto cleanup; } } + ast_channel_lock(joiner->chan); joiner_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(joiner->chan)); + ast_channel_unlock(joiner->chan); if (!joiner_topology) { goto cleanup; } @@ -617,7 +627,9 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast if (participant == joiner) { continue; } + ast_channel_lock(participant->chan); participant_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(participant->chan)); + ast_channel_unlock(participant->chan); if (!participant_topology) { goto cleanup; } @@ -753,12 +765,16 @@ static int sfu_topologies_on_leave(struct ast_bridge_channel *leaver, struct ast continue; } + ast_channel_lock(participant->chan); remove_destination_streams(participant_topology, ast_channel_name(leaver->chan), ast_channel_get_stream_topology(participant->chan)); + ast_channel_unlock(participant->chan); ast_channel_request_stream_topology_change(participant->chan, participant_topology, NULL); ast_stream_topology_free(participant_topology); } + ast_channel_lock(leaver->chan); remove_destination_streams(leaver_topology, "", ast_channel_get_stream_topology(leaver->chan)); + ast_channel_unlock(leaver->chan); ast_channel_request_stream_topology_change(leaver->chan, leaver_topology, NULL); ast_stream_topology_free(leaver_topology); @@ -1657,6 +1673,7 @@ static void map_source_to_destinations(const char *source_stream_name, const cha } ast_bridge_channel_lock(participant); + ast_channel_lock(participant->chan); topology = ast_channel_get_stream_topology(participant->chan); for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { @@ -1668,6 +1685,7 @@ static void map_source_to_destinations(const char *source_stream_name, const cha break; } } + ast_channel_unlock(participant->chan); ast_bridge_channel_unlock(participant); } } @@ -1702,16 +1720,9 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st /* First traversal: re-initialize all of the participants' stream maps */ AST_LIST_TRAVERSE(&bridge->channels, participant, entry) { - int size; - ast_bridge_channel_lock(participant); - size = ast_stream_topology_get_count(ast_channel_get_stream_topology(participant->chan)); - - AST_VECTOR_FREE(&participant->stream_map.to_channel); - AST_VECTOR_FREE(&participant->stream_map.to_bridge); - - AST_VECTOR_INIT(&participant->stream_map.to_channel, size); - AST_VECTOR_INIT(&participant->stream_map.to_bridge, size); + AST_VECTOR_RESET(&participant->stream_map.to_channel, AST_VECTOR_ELEM_CLEANUP_NOOP); + AST_VECTOR_RESET(&participant->stream_map.to_bridge, AST_VECTOR_ELEM_CLEANUP_NOOP); ast_bridge_channel_unlock(participant); } @@ -1727,6 +1738,8 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st int i; struct ast_stream_topology *topology; + ast_channel_lock(participant->chan); + topology = ast_channel_get_stream_topology(participant->chan); for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { @@ -1766,6 +1779,8 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st } ast_bridge_channel_unlock(participant); } + + ast_channel_unlock(participant->chan); } } diff --git a/main/bridge.c b/main/bridge.c index a1a1a6f5599..b732d5fc55c 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -446,7 +446,12 @@ static void bridge_channel_complete_join(struct ast_bridge *bridge, struct ast_b * media types vector. This way all streams map to the same media type index for * a given channel. */ - ast_bridge_channel_stream_map(bridge_channel); + if (bridge_channel->bridge->technology->stream_topology_changed) { + bridge_channel->bridge->technology->stream_topology_changed( + bridge_channel->bridge, bridge_channel); + } else { + ast_bridge_channel_stream_map(bridge_channel); + } } /*! diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 2e943000cc1..1427fd0141f 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2344,16 +2344,23 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe case AST_FRAME_NULL: break; default: - if (fr->stream_num > 0 && - (fr->stream_num >= (int)AST_VECTOR_SIZE(&bridge_channel->stream_map.to_channel) || - AST_VECTOR_GET(&bridge_channel->stream_map.to_channel, fr->stream_num) == -1)) { - /* Nowhere to write to, so drop it */ - break; - } + /* Assume that there is no mapped stream for this */ + num = -1; - /* Find what stream number to write to for the channel */ - num = fr->stream_num < 0 ? -1 : - AST_VECTOR_GET(&bridge_channel->stream_map.to_channel, fr->stream_num); + if (fr->stream_num > -1) { + ast_bridge_channel_lock(bridge_channel); + if (fr->stream_num < (int)AST_VECTOR_SIZE(&bridge_channel->stream_map.to_channel)) { + num = AST_VECTOR_GET(&bridge_channel->stream_map.to_channel, fr->stream_num); + } + ast_bridge_channel_unlock(bridge_channel); + + /* If there is no mapped stream after checking the mapping then there is nowhere + * to write this frame to, so drop it. + */ + if (num == -1) { + break; + } + } /* Write the frame to the channel. */ bridge_channel->activity = BRIDGE_CHANNEL_THREAD_SIMPLE; @@ -2983,7 +2990,9 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel) { + ast_channel_lock(bridge_channel->chan); ast_stream_topology_map(ast_channel_get_stream_topology(bridge_channel->chan), &bridge_channel->bridge->media_types, &bridge_channel->stream_map.to_bridge, &bridge_channel->stream_map.to_channel); + ast_channel_unlock(bridge_channel->chan); } From 4b58609c331c013845a0a61d946cbbc82092170e Mon Sep 17 00:00:00 2001 From: kkm Date: Sat, 29 Jul 2017 18:03:02 -0700 Subject: [PATCH 1413/1578] chan_sip: Access incoming REFER headers in dialplan This adds a way to access information passed along with SIP headers in a REFER message that initiates a transfer. Headers matching a dialplan variable GET_TRANSFERRER_DATA in the transferrer channel are added to a HASH object TRANSFER_DATA to be accessed with functions HASHKEY and HASH. The variable GET_TRANSFERRER_DATA is interpreted to be a prefix for headers that should be put into the hash. If not set, no headers are included. If set to a string (perhaps 'X-' in a typical case), all headers starting this string are added. Empty string matches all headers. If there are multiple of the same header, only the latest occurrence in the REFER message is available in the hash. Obviously, the variable GET_TRANSFERRER_DATA must be inherited by the referrer channel, and should be set with the '_' or '__' prefix. I avoided a specific reference to SIP or REFER, as in my mind the mechanism can be generalized to other channel techs. ASTERISK-27162 Change-Id: I73d7a1e95981693bc59aa0d5093c074b555f708e --- CHANGES | 4 ++++ channels/chan_sip.c | 46 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4f5225ac1b1..67d33c95b06 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,10 @@ chan_sip ------------------ * New function SIP_HEADERS() enumerates all headers in the incoming INVITE. + * The variable GET_TRANSFERRER_DATA set in the peer channel causes matching + headers be retrieved from the REFER message and made accessible to the + dialplan in the hash TRANSFER_DATA. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 941a1e96dc0..dcfadf4a877 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -377,7 +377,20 @@ Since there are several headers (such as Via) which can occur multiple times, SIP_HEADER takes an optional second argument to specify which header with that name to retrieve. Headers start at offset 1. - Please observe that contents of the SDP (an attachment to the + This function does not access headers from the REFER message if the call + was transferred. To obtain the REFER headers, set the dialplan variable + GET_TRANSFERRER_DATA to the prefix of the headers of the + REFER message that you need to access; for example, X- to + get all headers starting with X-. The variable must be set + before a call to the application that starts the channel that may eventually + transfer back into the dialplan, and must be inherited by that channel, so prefix + it with the _ or __ when setting (or + set it in the pre-dial handler executed on the new channel). To get all headers + of the REFER message, set the value to *. Headers + are returned in the form of a dialplan hash TRANSFER_DATA, and can be accessed + with the functions HASHKEYS(TRANSFER_DATA) and, e. g., + HASH(TRANSFER_DATA,X-That-Special-Header). + Please also note that contents of the SDP (an attachment to the SIP request) can't be accessed with this function. @@ -18662,6 +18675,29 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag, return 0; } +static void extract_transferrer_headers(const char *prefix, struct ast_channel *peer, const struct sip_request *req) +{ + struct ast_str *pbxvar = ast_str_alloca(120); + int i; + + /* The '*' alone matches all headers. */ + if (strcmp(prefix, "*") == 0) { + prefix = ""; + } + + for (i = 0; i < req->headers; i++) { + const char *header = REQ_OFFSET_TO_STR(req, header[i]); + if (ast_begins_with(header, prefix)) { + int hdrlen = strcspn(header, " \t:"); + const char *val = ast_skip_blanks(header + hdrlen); + if (hdrlen > 0 && *val == ':') { + ast_str_set(&pbxvar, -1, "~HASH~TRANSFER_DATA~%.*s~", hdrlen, header); + pbx_builtin_setvar_helper(peer, ast_str_buffer(pbxvar), ast_skip_blanks(val + 1)); + } + } + } +} + /*! \brief Call transfer support (the REFER method) * Extracts Refer headers into pvt dialog structure * @@ -18724,10 +18760,18 @@ static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoi peer = ast_channel_bridge_peer(owner_ref); if (peer) { + const char *get_xfrdata; + pbx_builtin_setvar_helper(peer, "SIPREFERRINGCONTEXT", S_OR(transferer->context, NULL)); pbx_builtin_setvar_helper(peer, "__SIPREFERREDBYHDR", S_OR(p_referred_by, NULL)); + + ast_channel_lock(peer); + get_xfrdata = pbx_builtin_getvar_helper(peer, "GET_TRANSFERRER_DATA"); + if (!ast_strlen_zero(get_xfrdata)) { + extract_transferrer_headers(get_xfrdata, peer, req); + } ast_channel_unlock(peer); } From 62092bc1140a29c86e1fe4dd195ff819e6e7569b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sat, 5 Aug 2017 11:36:49 +0000 Subject: [PATCH 1414/1578] res_pjsip_session: Release media resources on session end quicker. A change was made long ago where the session was kept around until the underlying INVITE session had been destroyed. This had the side effect of also keeping the underlying media resources around for this time as well. This change ensures that when we are told to terminate the session we immediately release any media sessions associated with it. ASTERISK-27110 Change-Id: I643e431d5c3bf05cda220c1d39e824a505a29b82 --- res/res_pjsip_session.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index bb349a4b67d..31e20142d1f 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2396,6 +2396,15 @@ void ast_sip_session_terminate(struct ast_sip_session *session, int response) response = 603; } + /* The media sessions need to exist for the lifetime of the underlying channel + * to ensure that anything (such as bridge_native_rtp) has access to them as + * appropriate. Since ast_sip_session_terminate is called by chan_pjsip and other + * places when the session is to be terminated we terminate any existing + * media sessions here. + */ + SWAP(session->active_media_state, session->pending_media_state); + ast_sip_session_media_state_reset(session->pending_media_state); + switch (session->inv_session->state) { case PJSIP_INV_STATE_NULL: if (!session->inv_session->invite_tsx) { From 305bd0d99fa0349db99b5aa631cd1ed2b11a59f7 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 8 Aug 2017 12:33:50 -0600 Subject: [PATCH 1415/1578] Make --with-pjproject-bundled the default for Asterisk 15 '--with-pjproject-bundled' is now the default when running ./configure. It can be disabled with '--without-pjproject-bundled'. To make building without an internet connection easier, a new ./configure option '--with-download-cache' was added that sets the cache for externals (like pjproject, the codecs and the DPMA), AND the sounds files. It can also be specified as an environment variable named "AST_DOWNLOAD_CACHE". The existing '--with-sounds-cache' option / SOUNDS_CACHE_DIR env variable and '--with-externals-cache' option / EXTERNALS_CACHE_DIR env variable remain and if specified, will override '--with-downloads-cache'. ASTERISK-27189 Change-Id: Ifa9783fddf44aafadb060c9feba713dfa81d38ce --- CHANGES | 10 ++++++ UPGRADE-15.txt | 4 +++ build_tools/download_externals | 6 +++- build_tools/list_valid_installed_externals | 6 +++- configure | 39 +++++++++++++++++++--- configure.ac | 5 +-- makeopts.in | 5 +-- third-party/pjproject/configure.m4 | 6 ++-- 8 files changed, 67 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 67d33c95b06..f6c94f8fd78 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,16 @@ app_queue queue position has improved since the last time that we annouced their position. This default is no. +Build System +------------------ + * '--with-pjproject-bundled' is now the default when running ./configure + It can be disabled with '--without-pjproject-bundled'. + + * A '--with-download-cache' option is now available which is equivalent to + setting '--with-sounds-cache' and '--with-externals-cache' to the same + value. The download cache can also be set via the AST_DOWNLOAD_CACHE + environment variable. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.6.0 to Asterisk 14.7.0 ------------ ------------------------------------------------------------------------------ diff --git a/UPGRADE-15.txt b/UPGRADE-15.txt index 4ebe400a6d3..2e5eb1c1791 100644 --- a/UPGRADE-15.txt +++ b/UPGRADE-15.txt @@ -33,6 +33,10 @@ Core: ARI. As a result, the 'DataGet' AMI action as well as the 'data get' CLI command have been removed. +Build System: + - '--with-pjproject-bundled' is now the default when running ./configure + It can be disabled with '--without-pjproject-bundled'. + From 14.6.0 to 14.7.0: Core: diff --git a/build_tools/download_externals b/build_tools/download_externals index b0a414ed1fd..f6cc5239075 100755 --- a/build_tools/download_externals +++ b/build_tools/download_externals @@ -26,7 +26,11 @@ if [[ -z "${tmpdir}" ]] ; then fi trap "rm -rf ${tmpdir}" EXIT -sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts +# We have to pre-process the makeopts file so it will be parsable by bash +# Surround values with double quotes +# Convert make $(or) functions to bash ${name:-value} +sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" \ + -e 's/^([^ =]+)="\$\(or ([^,]*),([^)]+)\)"/_tmp="\2"\n\1="${_tmp:-\3}"/g' ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts source ${tmpdir}/makeopts if [[ -z "${ASTMODDIR}" ]] ; then echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." diff --git a/build_tools/list_valid_installed_externals b/build_tools/list_valid_installed_externals index 12aff3f95a0..194801c94ae 100755 --- a/build_tools/list_valid_installed_externals +++ b/build_tools/list_valid_installed_externals @@ -14,7 +14,11 @@ if [[ -z "${tmpdir}" ]] ; then fi trap "rm -rf ${tmpdir}" EXIT -sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts +# We have to pre-process the makeopts file so it will be parsable by bash +# Surround values with double quotes +# Convert make $(or) functions to bash ${name:-value} +sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" \ + -e 's/^([^ =]+)="\$\(or ([^,]*),([^)]+)\)"/_tmp="\2"\n\1="${_tmp:-\3}"/g' ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts source ${tmpdir}/makeopts if [[ -z "${ASTMODDIR}" ]] ; then echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." diff --git a/configure b/configure index a6ebe003db4..368e6b453e0 100755 --- a/configure +++ b/configure @@ -1228,6 +1228,7 @@ AST_NESTED_FUNCTIONS AST_CODE_COVERAGE EXTERNALS_CACHE_DIR SOUNDS_CACHE_DIR +AST_DOWNLOAD_CACHE AST_DEVMODE_STRICT AST_DEVMODE NOISY_BUILD @@ -1381,6 +1382,7 @@ ac_user_opts=' enable_option_checking with_gnu_ld enable_dev_mode +with_download_cache with_sounds_cache with_externals_cache enable_coverage @@ -2128,12 +2130,15 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-download-cache=PATH + use cached sound AND external module tarfiles in + PATH --with-sounds-cache=PATH use cached sound tarfiles in PATH --with-externals-cache=PATH use cached external module tarfiles in PATH --with-pjproject-bundled - Use bundled pjproject libraries + Use bundled pjproject libraries (default) --with-asound=PATH use Advanced Linux Sound Architecture files in PATH --with-bfd=PATH use Debug symbol decoding files in PATH --with-execinfo=PATH use Stack Backtrace files in PATH @@ -9055,6 +9060,30 @@ fi +# Check whether --with-download-cache was given. +if test "${with_download_cache+set}" = set; then : + withval=$with_download_cache; + case ${withval} in + n|no) + unset AST_DOWNLOAD_CACHE + ;; + *) + if test "x${withval}" = "x"; then + : + else + AST_DOWNLOAD_CACHE="${withval}" + fi + ;; + esac + +else + : +fi + + + + + # Check whether --with-sounds-cache was given. if test "${with_sounds_cache+set}" = set; then : withval=$with_sounds_cache; @@ -9254,7 +9283,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$save_CFLAGS" -PJPROJECT_BUNDLED=no +PJPROJECT_BUNDLED=yes @@ -9317,11 +9346,11 @@ $as_echo "configuring" >&6; } PJPROJECT_CONFIGURE_OPTS+=" --host=$host" fi - export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT + export TAR PATCH SED NM EXTERNALS_CACHE_DIR AST_DOWNLOAD_CACHE DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT export NOISY_BUILD ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} \ PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" \ - EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" \ + EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR:-${AST_DOWNLOAD_CACHE}}" \ configure if test $? -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 @@ -9334,7 +9363,7 @@ $as_echo "$as_me: Unable to configure ${PJPROJECT_DIR}" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for bundled pjproject" >&5 $as_echo_n "checking for bundled pjproject... " >&6; } - PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" echo_cflags) + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR:-${AST_DOWNLOAD_CACHE}}" echo_cflags) PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" PBX_PJPROJECT=1 diff --git a/configure.ac b/configure.ac index ccd6936dde5..cf4518c2103 100644 --- a/configure.ac +++ b/configure.ac @@ -407,6 +407,7 @@ AC_SUBST(NOISY_BUILD) AC_SUBST(AST_DEVMODE) AC_SUBST(AST_DEVMODE_STRICT) +AST_OPTION_ONLY([download-cache], [AST_DOWNLOAD_CACHE], [cached sound AND external module tarfiles], []) AST_OPTION_ONLY([sounds-cache], [SOUNDS_CACHE_DIR], [cached sound tarfiles], []) AST_OPTION_ONLY([externals-cache], [EXTERNALS_CACHE_DIR], [cached external module tarfiles], []) @@ -424,12 +425,12 @@ AC_SUBST(AST_CODE_COVERAGE) AST_CHECK_RAII() AST_CHECK_STRSEP_ARRAY_BOUNDS() -PJPROJECT_BUNDLED=no +PJPROJECT_BUNDLED=yes AH_TEMPLATE(m4_bpatsubst([[HAVE_PJPROJECT_BUNDLED]], [(.*)]), [Define to 1 when using the bundled pjproject.]) AC_ARG_WITH([pjproject-bundled], [AS_HELP_STRING([--with-pjproject-bundled], - [Use bundled pjproject libraries])], + [Use bundled pjproject libraries (default)])], [case "${withval}" in n|no) PJPROJECT_BUNDLED=no ;; *) PJPROJECT_BUNDLED=yes ;; diff --git a/makeopts.in b/makeopts.in index 887a1556754..7d0347ddc92 100644 --- a/makeopts.in +++ b/makeopts.in @@ -29,8 +29,9 @@ FETCH=@FETCH@ DOWNLOAD=@DOWNLOAD@ DOWNLOAD_TO_STDOUT=@DOWNLOAD_TO_STDOUT@ DOWNLOAD_TIMEOUT=@DOWNLOAD_TIMEOUT@ -SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@ -EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@ +AST_DOWNLOAD_CACHE=@AST_DOWNLOAD_CACHE@ +SOUNDS_CACHE_DIR=$(or @SOUNDS_CACHE_DIR@,${AST_DOWNLOAD_CACHE}) +EXTERNALS_CACHE_DIR=$(or @EXTERNALS_CACHE_DIR@,${AST_DOWNLOAD_CACHE}) RUBBER=@RUBBER@ CATDVI=@CATDVI@ KPATHSEA=@KPATHSEA@ diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4 index 709a706a1b0..2d3353476e9 100644 --- a/third-party/pjproject/configure.m4 +++ b/third-party/pjproject/configure.m4 @@ -49,11 +49,11 @@ AC_DEFUN([_PJPROJECT_CONFIGURE], PJPROJECT_CONFIGURE_OPTS+=" --host=$host" fi - export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT + export TAR PATCH SED NM EXTERNALS_CACHE_DIR AST_DOWNLOAD_CACHE DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT export NOISY_BUILD ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} \ PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" \ - EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" \ + EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR:-${AST_DOWNLOAD_CACHE}}" \ configure if test $? -ne 0 ; then AC_MSG_RESULT(failed) @@ -63,7 +63,7 @@ AC_DEFUN([_PJPROJECT_CONFIGURE], AC_MSG_CHECKING(for bundled pjproject) - PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR}" echo_cflags) + PJPROJECT_INCLUDE=$(${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR:-${AST_DOWNLOAD_CACHE}}" echo_cflags) PJPROJECT_CFLAGS="$PJPROJECT_INCLUDE" PBX_PJPROJECT=1 From a2dde5915400bfd2355f23c60b3ae7316290f820 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Fri, 28 Jul 2017 14:53:44 +0200 Subject: [PATCH 1416/1578] res_rtp_asterisk: Make P2P bridge Asymmetric codec aware Introduce a new property to rtp-engine to make it aware of the desire for assymetric codecs or not. If asymmetric codecs is not allowed, the bridge will compare read/write formats and shut down the p2p bridge if needed ASTERISK-26745 #close Change-Id: I0d9c83e5356df81661e58d40a8db565833501a6f --- channels/chan_pjsip.c | 21 ++++++++++++++------- include/asterisk/rtp_engine.h | 2 ++ res/res_pjsip_sdp_rtp.c | 1 + res/res_rtp_asterisk.c | 20 ++++++++++++++++++++ 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index ebda6c7ee17..4a24fa689fc 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -797,14 +797,13 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast) return f; } - if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when it has not been negotiated\n", - ast_format_get_name(f->subclass.format), ast_channel_name(ast)); - - ast_frfree(f); - return &ast_null_frame; - } + session = channel->session; + /* + * Asymmetric RTP only has one native format set at a time. + * Therefore we need to update the native format to the current + * raw read format BEFORE the native format check + */ if (!session->endpoint->asymmetric_rtp_codec && ast_format_cmp(ast_channel_rawwriteformat(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { struct ast_format_cap *caps; @@ -831,6 +830,14 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast) } } + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when it has not been negotiated\n", + ast_format_get_name(f->subclass.format), ast_channel_name(ast)); + + ast_frfree(f); + return &ast_null_frame; + } + if (session->dsp) { int dsp_features; diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index d030bdb1921..3ceac8467e1 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -120,6 +120,8 @@ enum ast_rtp_property { AST_RTP_PROPERTY_STUN, /*! Enable RTCP support */ AST_RTP_PROPERTY_RTCP, + /*! Enable Asymmetric RTP Codecs */ + AST_RTP_PROPERTY_ASYMMETRIC_CODEC, /*! * \brief Maximum number of RTP properties supported diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 77cd807825f..b082b1d8963 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -202,6 +202,7 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me } ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->media.rtp.symmetric); + ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_ASYMMETRIC_CODEC, session->endpoint->asymmetric_rtp_codec); if (!session->endpoint->media.rtp.ice_support && (ice = ast_rtp_instance_get_ice(session_media->rtp))) { ice->stop(session_media->rtp); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 65ab9020fc0..0ff2b559d7a 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -313,6 +313,7 @@ struct ast_rtp { void *data; struct ast_rtcp *rtcp; struct ast_rtp *bridged; /*!< Who we are Packet bridged to */ + unsigned int asymmetric_codec; /*!< Indicate if asymmetric send/receive codecs are allowed */ struct ast_rtp_instance *bundled; /*!< The RTP instance we are bundled to */ int stream_num; /*!< Stream num for this RTP instance */ @@ -5113,6 +5114,23 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, return -1; } + + ao2_replace(rtp->lastrxformat, payload_type->format); + ao2_replace(bridged->lasttxformat, payload_type->format); + + /* + * If bridged peer has already received rtp, perform the asymmetric codec check + * if that feature has been activated + */ + if (!bridged->asymmetric_codec && bridged->lastrxformat != ast_format_none) { + if (ast_format_cmp(bridged->lasttxformat, bridged->lastrxformat) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_debug(1, "Asymmetric RTP codecs detected (TX: %s, RX: %s) sending frame to core\n", + ast_format_get_name(bridged->lasttxformat), + ast_format_get_name(bridged->lastrxformat)); + return -1; + } + } + /* If the marker bit has been explicitly set turn it on */ if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) { mark = 1; @@ -5797,6 +5815,8 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro rtp->rtcp = NULL; } } + } else if (property == AST_RTP_PROPERTY_ASYMMETRIC_CODEC) { + rtp->asymmetric_codec = value; } } From d430f718f58b85e35cfb82f72504e78b1080a67a Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Wed, 26 Jul 2017 16:17:02 +0200 Subject: [PATCH 1417/1578] res_rtp_asterisk: enable rtcp & QOS stats on native bridge Asterisk wasn't generating or forwarding RTCP packets when native bridge was activated. Also the stats weren't available via CHANNEL(qos). Now the RTCP stats are always calculated. ASTERISK-27158 #close Change-Id: I46fb8f61c95e836b9d2dda6054b0cf205c16037b --- res/res_rtp_asterisk.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 65ab9020fc0..ce899dffef6 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -5088,9 +5088,6 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, return -1; } - rtp->rxcount++; - rtp->rxoctetcount += (len - hdrlen); - /* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */ if (ast_rtp_codecs_find_payload_code(ast_rtp_instance_get_codecs(instance1), bridged_payload) == -1) { ast_debug(1, "Unsupported payload type received \n"); @@ -5362,13 +5359,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc ast_rtp_dtmf_continuation(instance); } - /* If we are directly bridged to another instance send the audio directly out */ - instance1 = ast_rtp_instance_get_bridged(instance); - if (instance1 - && !bridge_p2p_rtp_write(instance, instance1, rtpheader, res, hdrlen)) { - return &ast_null_frame; - } - /* Pull out the various other fields we will need */ payloadtype = (seqno & 0x7f0000) >> 16; padding = seqno & (1 << 29); @@ -5467,6 +5457,28 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */ } + + /* If we are directly bridged to another instance send the audio directly out, + * but only after updating core information about the received traffic so that + * outgoing RTCP reflects it. + */ + instance1 = ast_rtp_instance_get_bridged(instance); + if (instance1 + && !bridge_p2p_rtp_write(instance, instance1, rtpheader, res, hdrlen)) { + struct timeval rxtime; + struct ast_frame *f; + + /* Update statistics for jitter so they are correct in RTCP */ + calc_rxstamp(&rxtime, rtp, timestamp, mark); + + /* When doing P2P we don't need to raise any frames about SSRC change to the core */ + while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list)) != NULL) { + ast_frfree(f); + } + + return &ast_null_frame; + } + if (rtp_debug_test_addr(&addr)) { ast_verbose("Got RTP packet from %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6d)\n", ast_sockaddr_stringify(&addr), From 4ed2733ddea705761f0e340cdcba972a5f8be68a Mon Sep 17 00:00:00 2001 From: Scott Griepentrog Date: Thu, 10 Aug 2017 09:09:29 -0500 Subject: [PATCH 1418/1578] res_pjsip_messaging: IPv6 receive address needs brackets When handling an incoming SIP MESSAGE, PJSIP attaches the IP address that the message was received from to the message in the variable PJSIP_RECVADDR. When the IP address is IPv6 the :PORT appended results in an unparseable mess. By using an additional bit flag on the pj_sockaddr_print call, the conventional use of brackets around the address is achieved. ASTERISK-27193 #close Change-Id: I12342521f2ce87a5b6e4883d480a3fd957aa9fd9 --- res/res_pjsip_messaging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index 5c41a70562d..d31e10129c1 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -512,7 +512,7 @@ static enum pjsip_status_code rx_data_to_ast_msg(pjsip_rx_data *rdata, struct as buf[size] = '\0'; res |= ast_msg_set_from(msg, "%s", buf); - field = pj_sockaddr_print(&rdata->pkt_info.src_addr, buf, sizeof(buf) - 1, 1); + field = pj_sockaddr_print(&rdata->pkt_info.src_addr, buf, sizeof(buf) - 1, 3); res |= ast_msg_set_var(msg, "PJSIP_RECVADDR", field); switch (rdata->tp_info.transport->key.type) { From ecd1f87edf71158f836f81a4b2dabccc7b394726 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 9 Aug 2017 15:24:58 -0500 Subject: [PATCH 1419/1578] UPGRADE notes: Prepare for the eventual 16 branch. Change-Id: I4ca2f07ed62d77f1fdd10c3b216f6a28dd75720c --- UPGRADE-14.txt | 24 +++++++++++++++++++ UPGRADE-15.txt | 63 ++++++-------------------------------------------- UPGRADE.txt | 18 +++++++++++++++ 3 files changed, 49 insertions(+), 56 deletions(-) diff --git a/UPGRADE-14.txt b/UPGRADE-14.txt index f8fa7906b42..aaf236ba23c 100644 --- a/UPGRADE-14.txt +++ b/UPGRADE-14.txt @@ -22,6 +22,30 @@ === UPGRADE-13.txt -- Upgrade info for 12 to 13 =========================================================== +From 14.6.0 to 14.7.0: + +Core: + - ast_app_parse_timelen now returns an error if it encounters extra characters + at the end of the string to be parsed. + +From 14.4.0 to 14.5.0: + +Core: + - Support for embedded modules has been removed. This has not worked in + many years. LOADABLE_MODULES menuselect option is also removed as + loadable module support is now always enabled. + +From 14.3.0 to 14.4.0: + +res_rtp_asterisk: + - The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP + Data and Control Packets on a Single Port." For the PJSIP channel driver, + chan_pjsip, you can set "rtcp_mux = yes" on a PJSIP endpoint in pjsip.conf + to enable the feature. For chan_sip you can set "rtcp_mux = yes" either + globally or on a per-peer basis in sip.conf. + +New in 14.0.0 + ARI: - The policy for when to send "Dial" events has changed. Previously, "Dial" events were sent on the calling channel's topic. However, starting in Asterisk diff --git a/UPGRADE-15.txt b/UPGRADE-15.txt index 2e5eb1c1791..30dc5d04c74 100644 --- a/UPGRADE-15.txt +++ b/UPGRADE-15.txt @@ -21,69 +21,20 @@ === UPGRADE-12.txt -- Upgrade info for 11 to 12 === UPGRADE-13.txt -- Upgrade info for 12 to 13 === UPGRADE-14.txt -- Upgrade info for 13 to 14 -=== UPGRADE-15.txt -- Upgrade info for 14 to 15 =========================================================== New in 15.0.0: -Core: - - The 'Data Retrieval API' has been removed. This API was not actively - maintained, was not added to new modules (such as res_pjsip), and there - exist better alternatives to acquire the same information, such as the - ARI. As a result, the 'DataGet' AMI action as well as the 'data get' - CLI command have been removed. - Build System: - '--with-pjproject-bundled' is now the default when running ./configure It can be disabled with '--without-pjproject-bundled'. -From 14.6.0 to 14.7.0: - -Core: - - ast_app_parse_timelen now returns an error if it encounters extra characters - at the end of the string to be parsed. - -From 14.4.0 to 14.5.0: - Core: - - Support for embedded modules has been removed. This has not worked in - many years. LOADABLE_MODULES menuselect option is also removed as - loadable module support is now always enabled. - -From 14.3.0 to 14.4.0: - -res_rtp_asterisk: - - The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP - Data and Control Packets on a Single Port." For the PJSIP channel driver, - chan_pjsip, you can set "rtcp_mux = yes" on a PJSIP endpoint in pjsip.conf - to enable the feature. For chan_sip you can set "rtcp_mux = yes" either - globally or on a per-peer basis in sip.conf. - -New in 14.0.0 - -ARI: - - The policy for when to send "Dial" events has changed. Previously, "Dial" - events were sent on the calling channel's topic. However, starting in Asterisk - 14, if there is no calling channel on which to send the event, the event is - instead sent on the called channel's topic. Note that for the ARI channels - resource's dial operation, this means that the "Dial" events will always be - sent on the called channel's topic. - -Queue: - - When reloading the members of a queue, the members added dynamically (i.e. - added via the CLI command "queue add" or the AMI action "QueueAdd") now have - their ringinuse value updated to the value of the queue. Previously, the - ringinuse value for dynamic members was not updated on reload. - -Queue log: - - New RINGCANCELED event is logged when the caller hangs up while ringing. - The data1 field contains number of miliseconds since start of ringing. - -Channel Drivers: - -chan_dahdi: - - Support for specifying a DAHDI channel using a path under /dev/dahdi - ("by name") has been removed. It was never used. Instead you should - use kernel-level channel number allocation using span assignments. - See the documentation of dahdi-linux and dahdi-tools. + - Multi-stream support has been added so a channel can have multiple + streams of the same type such as audio and video. + - The 'Data Retrieval API' has been removed. This API was not actively + maintained, was not added to new modules (such as res_pjsip), and there + exist better alternatives to acquire the same information, such as the + ARI. As a result, the 'DataGet' AMI action as well as the 'data get' + CLI command have been removed. diff --git a/UPGRADE.txt b/UPGRADE.txt index 87eabde2dae..1fe82c04eae 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -23,3 +23,21 @@ === UPGRADE-14.txt -- Upgrade info for 13 to 14 === UPGRADE-15.txt -- Upgrade info for 14 to 15 =========================================================== + +New in 16.0.0: + +New in 15.0.0: + +Build System: + - '--with-pjproject-bundled' is now the default when running ./configure + It can be disabled with '--without-pjproject-bundled'. + +Core: + - Multi-stream support has been added so a channel can have multiple + streams of the same type such as audio and video. + + - The 'Data Retrieval API' has been removed. This API was not actively + maintained, was not added to new modules (such as res_pjsip), and there + exist better alternatives to acquire the same information, such as the + ARI. As a result, the 'DataGet' AMI action as well as the 'data get' + CLI command have been removed. From ee5edfb050f8bfff7a28ba716d70ee479929ce56 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 27 Jul 2017 15:36:20 -0500 Subject: [PATCH 1420/1578] res_pjsip_transport_management.c: Rename some variables. * Use monitored instead of the misleading keepalive name. Change-Id: I9e5bcbb4ab2b82d49bcd0f06dfe85d15e0b552b6 --- res/res_pjsip_transport_management.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c index 3e129dc5f69..86c53ca9e27 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip_transport_management.c @@ -33,7 +33,7 @@ #include "asterisk/module.h" #include "asterisk/astobj2.h" -/*! \brief Number of buckets for keepalive transports */ +/*! \brief Number of buckets for monitored transports */ #define TRANSPORTS_BUCKETS 53 #define IDLE_TIMEOUT (pjsip_cfg()->tsx.td) @@ -114,7 +114,7 @@ AST_THREADSTORAGE(desc_storage); static int idle_sched_cb(const void *data) { - struct monitored_transport *keepalive = (struct monitored_transport *) data; + struct monitored_transport *monitored = (struct monitored_transport *) data; if (!pj_thread_is_registered()) { pj_thread_t *thread; @@ -123,7 +123,7 @@ static int idle_sched_cb(const void *data) desc = ast_threadstorage_get(&desc_storage, sizeof(pj_thread_desc)); if (!desc) { ast_log(LOG_ERROR, "Could not get thread desc from thread-local storage.\n"); - ao2_ref(keepalive, -1); + ao2_ref(monitored, -1); return 0; } @@ -132,22 +132,22 @@ static int idle_sched_cb(const void *data) pj_thread_register("Transport Monitor", *desc, &thread); } - if (!keepalive->sip_received) { + if (!monitored->sip_received) { ast_log(LOG_NOTICE, "Shutting down transport '%s' since no request was received in %d seconds\n", - keepalive->transport->info, IDLE_TIMEOUT / 1000); - pjsip_transport_shutdown(keepalive->transport); + monitored->transport->info, IDLE_TIMEOUT / 1000); + pjsip_transport_shutdown(monitored->transport); } - ao2_ref(keepalive, -1); + ao2_ref(monitored, -1); return 0; } /*! \brief Destructor for keepalive transport */ static void monitored_transport_destroy(void *obj) { - struct monitored_transport *keepalive = obj; + struct monitored_transport *monitored = obj; - pjsip_transport_dec_ref(keepalive->transport); + pjsip_transport_dec_ref(monitored->transport); } /*! \brief Callback invoked when transport changes occur */ From 1dcb92bba89440fff3454670ed5f892da157bf27 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 28 Jul 2017 18:26:17 -0500 Subject: [PATCH 1421/1578] res_pjsip: PJSIP Transport state monitor refactor. The fix for the issue is broken up into three parts. This is part one which refactors the transport state monitor code to allow more modules to be able to monitor transports. * Pull the management of PJPROJECT's transport state callback code from res_pjsip_transport_management.c into res_pjsip. Now other modules can dynamically add and remove themselves from transport monitoring without worrying about breaking PJPROJECT's callback chain. * Add the ability for other modules to get a callback whenever a specific transport is shutdown. ASTERISK-27147 Change-Id: I7d9a31371eb1487c9b7050cf82a9af5180a57912 --- include/asterisk/res_pjsip.h | 87 +++++ res/res_pjsip.c | 7 +- res/res_pjsip/include/res_pjsip_private.h | 23 ++ res/res_pjsip/pjsip_transport_events.c | 366 ++++++++++++++++++++++ res/res_pjsip_transport_management.c | 40 +-- 5 files changed, 493 insertions(+), 30 deletions(-) create mode 100644 res/res_pjsip/pjsip_transport_events.c diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 890ce59fba2..31db3676628 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2926,4 +2926,91 @@ int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf, */ int ast_sip_str_to_dtmf(const char *dtmf_mode); +/*! + * \brief Transport shutdown monitor callback. + * \since 13.18.0 + * + * \param data User data to know what to do when transport shuts down. + * + * \note The callback does not need to care that data is an ao2 object. + * + * \return Nothing + */ +typedef void (*ast_transport_monitor_shutdown_cb)(void *data); + +enum ast_transport_monitor_reg { + /*! \brief Successfully registered the transport monitor */ + AST_TRANSPORT_MONITOR_REG_SUCCESS, + /*! \brief Replaced the already existing transport monitor with new one. */ + AST_TRANSPORT_MONITOR_REG_REPLACED, + /*! + * \brief Transport not found to monitor. + * \note Transport is either already shutdown or is not reliable. + */ + AST_TRANSPORT_MONITOR_REG_NOT_FOUND, + /*! \brief Error while registering transport monitor. */ + AST_TRANSPORT_MONITOR_REG_FAILED, +}; + +/*! + * \brief Register a reliable transport shutdown monitor callback. + * \since 13.18.0 + * + * \param transport Transport to monitor for shutdown. + * \param cb Who to call when transport is shutdown. + * \param ao2_data Data to pass with the callback. + * + * \return enum ast_transport_monitor_reg + */ +enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *ao2_data); + +/*! + * \brief Unregister a reliable transport shutdown monitor callback. + * \since 13.18.0 + * + * \param transport Transport to monitor for shutdown. + * \param cb Who to call when transport is shutdown. + * + * \return Nothing + */ +void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb); + +/*! + * \brief Unregister monitor callback from all reliable transports. + * \since 13.18.0 + * + * \param cb Who to call when a transport is shutdown. + * + * \return Nothing + */ +void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb); + +/*! Transport state notification registration element. */ +struct ast_sip_tpmgr_state_callback { + /*! PJPROJECT transport state notification callback */ + pjsip_tp_state_callback cb; + AST_LIST_ENTRY(ast_sip_tpmgr_state_callback) node; +}; + +/*! + * \brief Register a transport state notification callback element. + * \since 13.18.0 + * + * \param element What we are registering. + * + * \return Nothing + */ +void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element); + +/*! + * \brief Unregister a transport state notification callback element. + * \since 13.18.0 + * + * \param element What we are unregistering. + * + * \return Nothing + */ +void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element); + #endif /* _RES_PJSIP_H */ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index f3648acdbff..2917df3c597 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4662,6 +4662,7 @@ static int unload_pjsip(void *data) ast_sip_destroy_system(); ast_sip_destroy_global_headers(); internal_sip_unregister_service(&supplement_module); + ast_sip_destroy_transport_events(); } if (monitor_thread) { @@ -4740,7 +4741,6 @@ static int load_pjsip(void) return AST_MODULE_LOAD_SUCCESS; error: - unload_pjsip(NULL); return AST_MODULE_LOAD_DECLINE; } @@ -4806,6 +4806,11 @@ static int load_module(void) goto error; } + if (ast_sip_initialize_transport_events()) { + ast_log(LOG_ERROR, "Failed to initialize SIP transport monitor. Aborting load\n"); + goto error; + } + ast_sip_initialize_dns(); ast_sip_initialize_global_headers(); diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 0bdb63325af..2969f0e40c8 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -133,6 +133,29 @@ int ast_sip_initialize_distributor(void); */ void ast_sip_destroy_distributor(void); +/*! + * \internal + * \brief Initialize the transport events notify module + * \since 13.18.0 + * + * The transport events notify module is responsible for monitoring + * when transports die and calling any registered callbacks when that + * happens. It also manages any PJPROJECT transport state callbacks + * registered to it so the callbacks be more dynamic allowing module + * loading/unloading. + * + * \retval -1 Failure + * \retval 0 Success + */ +int ast_sip_initialize_transport_events(void); + +/*! + * \internal + * \brief Destruct the transport events notify module. + * \since 13.18.0 + */ +void ast_sip_destroy_transport_events(void); + /*! * \internal * \brief Initialize global type on a sorcery instance diff --git a/res/res_pjsip/pjsip_transport_events.c b/res/res_pjsip/pjsip_transport_events.c new file mode 100644 index 00000000000..0f57303ba22 --- /dev/null +++ b/res/res_pjsip/pjsip_transport_events.c @@ -0,0 +1,366 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, Digium Inc. + * + * Richard Mudgett + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Manages the global transport event notification callbacks. + * + * \author Richard Mudgett + * See Also: + * + * \arg \ref AstCREDITS + */ + + +#include "asterisk.h" + +#include "asterisk/res_pjsip.h" +#include "include/res_pjsip_private.h" +#include "asterisk/linkedlists.h" +#include "asterisk/vector.h" + +/* ------------------------------------------------------------------- */ + +/*! \brief Number of buckets for monitored active transports */ +#define ACTIVE_TRANSPORTS_BUCKETS 127 + +/*! Who to notify when transport shuts down. */ +struct transport_monitor_notifier { + /*! Who to call when transport shuts down. */ + ast_transport_monitor_shutdown_cb cb; + /*! ao2 data object to pass to callback. */ + void *data; +}; + +/*! \brief Structure for transport to be monitored */ +struct transport_monitor { + /*! \brief The underlying PJSIP transport */ + pjsip_transport *transport; + /*! Who is interested in when this transport shuts down. */ + AST_VECTOR(, struct transport_monitor_notifier) monitors; +}; + +/*! \brief Global container of active reliable transports */ +static AO2_GLOBAL_OBJ_STATIC(active_transports); + +/*! \brief Existing transport events callback that we need to invoke */ +static pjsip_tp_state_callback tpmgr_state_callback; + +/*! List of registered transport state callbacks. */ +static AST_RWLIST_HEAD(, ast_sip_tpmgr_state_callback) transport_state_list; + + +/*! \brief Hashing function for struct transport_monitor */ +AO2_STRING_FIELD_HASH_FN(transport_monitor, transport->obj_name); + +/*! \brief Comparison function for struct transport_monitor */ +AO2_STRING_FIELD_CMP_FN(transport_monitor, transport->obj_name); + +static const char *transport_state2str(pjsip_transport_state state) +{ + const char *name; + + switch (state) { + case PJSIP_TP_STATE_CONNECTED: + name = "CONNECTED"; + break; + case PJSIP_TP_STATE_DISCONNECTED: + name = "DISCONNECTED"; + break; + case PJSIP_TP_STATE_SHUTDOWN: + name = "SHUTDOWN"; + break; + case PJSIP_TP_STATE_DESTROY: + name = "DESTROY"; + break; + default: + /* + * We have to have a default case because the enum is + * defined by a third-party library. + */ + ast_assert(0); + name = ""; + break; + } + return name; +} + +static void transport_monitor_dtor(void *vdoomed) +{ + struct transport_monitor *monitored = vdoomed; + int idx; + + for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { + struct transport_monitor_notifier *notifier; + + notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); + ao2_cleanup(notifier->data); + } + AST_VECTOR_FREE(&monitored->monitors); +} + +/*! \brief Callback invoked when transport state changes occur */ +static void transport_state_callback(pjsip_transport *transport, + pjsip_transport_state state, const pjsip_transport_state_info *info) +{ + struct ao2_container *transports; + + /* We only care about monitoring reliable transports */ + if (PJSIP_TRANSPORT_IS_RELIABLE(transport) + && (transports = ao2_global_obj_ref(active_transports))) { + struct transport_monitor *monitored; + + ast_debug(3, "Reliable transport '%s' state:%s\n", + transport->obj_name, transport_state2str(state)); + switch (state) { + case PJSIP_TP_STATE_CONNECTED: + monitored = ao2_alloc_options(sizeof(*monitored), + transport_monitor_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!monitored) { + break; + } + monitored->transport = transport; + if (AST_VECTOR_INIT(&monitored->monitors, 2)) { + ao2_ref(monitored, -1); + break; + } + + ao2_link(transports, monitored); + ao2_ref(monitored, -1); + break; + case PJSIP_TP_STATE_DISCONNECTED: + if (!transport->is_shutdown) { + pjsip_transport_shutdown(transport); + } + break; + case PJSIP_TP_STATE_SHUTDOWN: + /* + * Set shutdown flag early so we can force a new transport to be + * created if a monitor callback needs to reestablish a link. + * PJPROJECT sets the flag after this routine returns even though + * it has already called the transport's shutdown routine. + */ + transport->is_shutdown = PJ_TRUE; + + monitored = ao2_find(transports, transport->obj_name, + OBJ_SEARCH_KEY | OBJ_UNLINK); + if (monitored) { + int idx; + + for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { + struct transport_monitor_notifier *notifier; + + notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); + notifier->cb(notifier->data); + } + ao2_ref(monitored, -1); + } + break; + default: + break; + } + + ao2_ref(transports, -1); + } + + /* Loop over other transport state callbacks registered with us. */ + if (!AST_LIST_EMPTY(&transport_state_list)) { + struct ast_sip_tpmgr_state_callback *tpmgr_notifier; + + AST_RWLIST_RDLOCK(&transport_state_list); + AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) { + tpmgr_notifier->cb(transport, state, info); + } + AST_RWLIST_UNLOCK(&transport_state_list); + } + + /* Forward to the old state callback if present */ + if (tpmgr_state_callback) { + tpmgr_state_callback(transport, state, info); + } +} + +static int transport_monitor_unregister_all(void *obj, void *arg, int flags) +{ + struct transport_monitor *monitored = obj; + ast_transport_monitor_shutdown_cb cb = arg; + int idx; + + for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { + struct transport_monitor_notifier *notifier; + + notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); + if (notifier->cb == cb) { + ao2_cleanup(notifier->data); + AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx); + break; + } + } + return 0; +} + +void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb) +{ + struct ao2_container *transports; + + transports = ao2_global_obj_ref(active_transports); + if (!transports) { + return; + } + ao2_callback(transports, OBJ_MULTIPLE | OBJ_NODATA, transport_monitor_unregister_all, + cb); + ao2_ref(transports, -1); +} + +void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb) +{ + struct ao2_container *transports; + struct transport_monitor *monitored; + + transports = ao2_global_obj_ref(active_transports); + if (!transports) { + return; + } + + ao2_lock(transports); + monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (monitored) { + int idx; + + for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { + struct transport_monitor_notifier *notifier; + + notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); + if (notifier->cb == cb) { + ao2_cleanup(notifier->data); + AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx); + break; + } + } + ao2_ref(monitored, -1); + } + ao2_unlock(transports); + ao2_ref(transports, -1); +} + +enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *ao2_data) +{ + struct ao2_container *transports; + struct transport_monitor *monitored; + enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND; + + transports = ao2_global_obj_ref(active_transports); + if (!transports) { + return res; + } + + ao2_lock(transports); + monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (monitored) { + int idx; + struct transport_monitor_notifier new_monitor; + + /* Check if the callback monitor already exists */ + for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { + struct transport_monitor_notifier *notifier; + + notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); + if (notifier->cb == cb) { + /* The monitor is already in the vector replace with new ao2_data. */ + ao2_replace(notifier->data, ao2_data); + res = AST_TRANSPORT_MONITOR_REG_REPLACED; + goto register_done; + } + } + + /* Add new monitor to vector */ + new_monitor.cb = cb; + new_monitor.data = ao2_bump(ao2_data); + if (AST_VECTOR_APPEND(&monitored->monitors, new_monitor)) { + ao2_cleanup(ao2_data); + res = AST_TRANSPORT_MONITOR_REG_FAILED; + } + +register_done: + ao2_ref(monitored, -1); + } + ao2_unlock(transports); + ao2_ref(transports, -1); + return res; +} + +void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element) +{ + AST_RWLIST_WRLOCK(&transport_state_list); + AST_LIST_REMOVE(&transport_state_list, element, node); + AST_RWLIST_UNLOCK(&transport_state_list); +} + +void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element) +{ + struct ast_sip_tpmgr_state_callback *tpmgr_notifier; + + AST_RWLIST_WRLOCK(&transport_state_list); + AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) { + if (element == tpmgr_notifier) { + /* Already registered. */ + AST_RWLIST_UNLOCK(&transport_state_list); + return; + } + } + AST_LIST_INSERT_HEAD(&transport_state_list, element, node); + AST_RWLIST_UNLOCK(&transport_state_list); +} + +void ast_sip_destroy_transport_events(void) +{ + pjsip_tpmgr *tpmgr; + + tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + if (tpmgr) { + pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback); + } + + ao2_global_obj_release(active_transports); +} + +int ast_sip_initialize_transport_events(void) +{ + pjsip_tpmgr *tpmgr; + struct ao2_container *transports; + + tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + if (!tpmgr) { + return -1; + } + + transports = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, + ACTIVE_TRANSPORTS_BUCKETS, transport_monitor_hash_fn, NULL, + transport_monitor_cmp_fn); + if (!transports) { + return -1; + } + ao2_global_obj_replace_unref(active_transports, transports); + ao2_ref(transports, -1); + + tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr); + pjsip_tpmgr_set_state_cb(tpmgr, &transport_state_callback); + + return 0; +} diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c index 86c53ca9e27..eb92eb7a519 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip_transport_management.c @@ -34,7 +34,7 @@ #include "asterisk/astobj2.h" /*! \brief Number of buckets for monitored transports */ -#define TRANSPORTS_BUCKETS 53 +#define TRANSPORTS_BUCKETS 127 #define IDLE_TIMEOUT (pjsip_cfg()->tsx.td) @@ -53,9 +53,6 @@ static pthread_t keepalive_thread = AST_PTHREADT_NULL; /*! \brief The global interval at which to send keepalives */ static unsigned int keepalive_interval; -/*! \brief Existing transport manager callback that we need to invoke */ -static pjsip_tp_state_callback tpmgr_state_callback; - /*! \brief Structure for transport to be monitored */ struct monitored_transport { /*! \brief The underlying PJSIP transport */ @@ -178,14 +175,13 @@ static void monitored_transport_state_callback(pjsip_transport *transport, pjsip /* Let the scheduler inherit the reference from allocation */ if (ast_sched_add_variable(sched, IDLE_TIMEOUT, idle_sched_cb, monitored, 1) < 0) { /* Uh Oh. Could not schedule the idle check. Kill the transport. */ - ao2_unlink(transports, monitored); - ao2_ref(monitored, -1); pjsip_transport_shutdown(transport); + } else { + /* monitored ref successfully passed to idle_sched_cb() */ + break; } - } else { - /* No scheduled task, so get rid of the allocation reference */ - ao2_ref(monitored, -1); } + ao2_ref(monitored, -1); break; case PJSIP_TP_STATE_SHUTDOWN: case PJSIP_TP_STATE_DISCONNECTED: @@ -197,13 +193,12 @@ static void monitored_transport_state_callback(pjsip_transport *transport, pjsip ao2_ref(transports, -1); } - - /* Forward to the old state callback if present */ - if (tpmgr_state_callback) { - tpmgr_state_callback(transport, state, info); - } } +struct ast_sip_tpmgr_state_callback monitored_transport_reg = { + monitored_transport_state_callback, +}; + /*! \brief Hashing function for monitored transport */ static int monitored_transport_hash_fn(const void *obj, int flags) { @@ -327,16 +322,9 @@ static pjsip_module idle_monitor_module = { static int load_module(void) { struct ao2_container *transports; - pjsip_tpmgr *tpmgr; CHECK_PJSIP_MODULE_LOADED(); - tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); - if (!tpmgr) { - ast_log(LOG_ERROR, "No transport manager to attach keepalive functionality to.\n"); - return AST_MODULE_LOAD_DECLINE; - } - transports = ao2_container_alloc(TRANSPORTS_BUCKETS, monitored_transport_hash_fn, monitored_transport_cmp_fn); if (!transports) { @@ -363,8 +351,7 @@ static int load_module(void) ast_sip_register_service(&idle_monitor_module); - tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr); - pjsip_tpmgr_set_state_cb(tpmgr, &monitored_transport_state_callback); + ast_sip_transport_state_register(&monitored_transport_reg); ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &keepalive_global_observer); ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); @@ -375,8 +362,6 @@ static int load_module(void) static int unload_module(void) { - pjsip_tpmgr *tpmgr; - if (keepalive_interval) { keepalive_interval = 0; if (keepalive_thread != AST_PTHREADT_NULL) { @@ -388,10 +373,7 @@ static int unload_module(void) ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &keepalive_global_observer); - tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); - if (tpmgr) { - pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback); - } + ast_sip_transport_state_unregister(&monitored_transport_reg); ast_sip_unregister_service(&idle_monitor_module); From 82f4ade959ef3ab7abb5deb4bc06882850dcde90 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 31 Jul 2017 14:21:06 -0500 Subject: [PATCH 1422/1578] res_pjsip: Remove ephemeral registered contacts on transport shutdown. The fix for the issue is broken up into three parts. This is part two which handles the server side of REGISTER requests when rewrite_contact is enabled. Any registered reliable transport contact becomes invalid when the transport connection becomes disconnected. * Monitor the rewrite_contact's reliable transport REGISTER contact for shutdown. If it is shutdown then the contact must be removed because it is no longer valid. Otherwise, when the client attempts to re-REGISTER it may be blocked because the invalid contact is there. Also if we try to send a call to the endpoint using the invalid contact then the endpoint is not likely to see the request. The endpoint either won't be listening on that port for new connections or a NAT/firewall will block it. * Prune any rewrite_contact's registered reliable transport contacts on boot. The reliable transport no longer exists so the contact is invalid. * Websockets always rewrite the REGISTER contact address and the transport needs to be monitored for shutdown. * Made the websocket transport set a unique name since that is what we use as the ao2 container key. Otherwise, we would not know which transport we find when one of them shuts down. The names are also used for PJPROJECT debug logging. * Made the websocket transport post the PJSIP_TP_STATE_CONNECTED state event. Now the global keep_alive_interval option, initially idle shutdown timer, and the server REGISTER contact monitor can work on wetsocket transports. * Made the websocket transport set the PJSIP_TP_DIR_INCOMING direction. Now initially idle websockets will automatically shutdown. ASTERISK-27147 Change-Id: I397a5e7d18476830f7ffe1726adf9ee6c15964f4 --- .../f3d1c5d38b56_add_prune_on_boot.py | 28 +++++ include/asterisk/res_pjsip.h | 39 +++++++ res/res_pjsip.c | 16 ++- res/res_pjsip/location.c | 59 ++++++++-- res/res_pjsip/pjsip_configuration.c | 2 + res/res_pjsip_registrar.c | 107 +++++++++++++++++- res/res_pjsip_transport_websocket.c | 16 +++ 7 files changed, 250 insertions(+), 17 deletions(-) create mode 100644 contrib/ast-db-manage/config/versions/f3d1c5d38b56_add_prune_on_boot.py diff --git a/contrib/ast-db-manage/config/versions/f3d1c5d38b56_add_prune_on_boot.py b/contrib/ast-db-manage/config/versions/f3d1c5d38b56_add_prune_on_boot.py new file mode 100644 index 00000000000..fe9c35ed154 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/f3d1c5d38b56_add_prune_on_boot.py @@ -0,0 +1,28 @@ +"""add_prune_on_boot + +Revision ID: f3d1c5d38b56 +Revises: 44ccced114ce +Create Date: 2017-08-04 17:31:23.124767 + +""" + +# revision identifiers, used by Alembic. +revision = 'f3d1c5d38b56' +down_revision = '44ccced114ce' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_contacts', sa.Column('prune_on_boot', yesno_values)) + + +def downgrade(): + op.drop_column('ps_contacts', 'prune_on_boot') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 31db3676628..e2c487aa316 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -270,6 +270,8 @@ struct ast_sip_contact { AST_STRING_FIELD_EXTENDED(call_id); /*! The name of the endpoint that added the contact */ AST_STRING_FIELD_EXTENDED(endpoint_name); + /*! If true delete the contact on Asterisk restart/boot */ + int prune_on_boot; }; #define CONTACT_STATUS "contact_status" @@ -1215,6 +1217,9 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na * \param expiration_time Optional expiration time of the contact * \param path_info Path information * \param user_agent User-Agent header from REGISTER request + * \param via_addr + * \param via_port + * \param call_id * \param endpoint The endpoint that resulted in the contact being added * * \retval -1 failure @@ -1238,6 +1243,9 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, * \param expiration_time Optional expiration time of the contact * \param path_info Path information * \param user_agent User-Agent header from REGISTER request + * \param via_addr + * \param via_port + * \param call_id * \param endpoint The endpoint that resulted in the contact being added * * \retval -1 failure @@ -1251,6 +1259,31 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint); +/*! + * \brief Create a new contact for an AOR without locking the AOR + * \since 13.18.0 + * + * \param aor Pointer to the AOR + * \param uri Full contact URI + * \param expiration_time Optional expiration time of the contact + * \param path_info Path information + * \param user_agent User-Agent header from REGISTER request + * \param via_addr + * \param via_port + * \param call_id + * \param prune_on_boot Non-zero if the contact cannot survive a restart/boot. + * \param endpoint The endpoint that resulted in the contact being added + * + * \return The created contact or NULL on failure. + * + * \warning + * This function should only be called if you already hold a named write lock on the aor. + */ +struct ast_sip_contact *ast_sip_location_create_contact(struct ast_sip_aor *aor, + const char *uri, struct timeval expiration_time, const char *path_info, + const char *user_agent, const char *via_addr, int via_port, const char *call_id, + int prune_on_boot, struct ast_sip_endpoint *endpoint); + /*! * \brief Update a contact * @@ -1271,6 +1304,12 @@ int ast_sip_location_update_contact(struct ast_sip_contact *contact); */ int ast_sip_location_delete_contact(struct ast_sip_contact *contact); +/*! + * \brief Prune the prune_on_boot contacts + * \since 13.18.0 + */ +void ast_sip_location_prune_boot_contacts(void); + /*! * \brief Callback called when an outbound request with authentication credentials is to be sent in dialog * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 2917df3c597..ca0c30126eb 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -367,9 +367,12 @@ Allow Contact header to be rewritten with the source IP address-port - On inbound SIP messages from this endpoint, the Contact header or an appropriate Record-Route - header will be changed to have the source IP address and port. This option does not affect - outbound messages sent to this endpoint. + On inbound SIP messages from this endpoint, the Contact header or an + appropriate Record-Route header will be changed to have the source IP + address and port. This option does not affect outbound messages sent to + this endpoint. This option helps servers communicate with endpoints + that are behind NATs. This option also helps reuse reliable transport + connections such as TCP and TLS. @@ -1364,6 +1367,13 @@ in incoming SIP REGISTER requests and is not intended to be configured manually. + + A contact that cannot survive a restart/boot. + + The option is set if the incoming SIP REGISTER contact is rewritten + on a reliable transport and is not intended to be configured manually. + + The configuration for a location of an endpoint diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 6213046e39e..557aeb6b9ba 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -356,13 +356,12 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name); } -int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, - struct timeval expiration_time, const char *path_info, const char *user_agent, - const char *via_addr, int via_port, const char *call_id, - struct ast_sip_endpoint *endpoint) +struct ast_sip_contact *ast_sip_location_create_contact(struct ast_sip_aor *aor, + const char *uri, struct timeval expiration_time, const char *path_info, + const char *user_agent, const char *via_addr, int via_port, const char *call_id, + int prune_on_boot, struct ast_sip_endpoint *endpoint) { struct ast_sip_contact *contact; - int res; char name[MAX_OBJECT_FIELD * 2 + 3]; char hash[33]; @@ -371,7 +370,7 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name); if (!contact) { - return -1; + return NULL; } ast_string_field_set(contact, uri, uri); @@ -405,14 +404,30 @@ int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri } contact->endpoint = ao2_bump(endpoint); - if (endpoint) { ast_string_field_set(contact, endpoint_name, ast_sorcery_object_get_id(endpoint)); } - res = ast_sorcery_create(ast_sip_get_sorcery(), contact); - ao2_ref(contact, -1); - return res; + contact->prune_on_boot = prune_on_boot; + + if (ast_sorcery_create(ast_sip_get_sorcery(), contact)) { + ao2_ref(contact, -1); + return NULL; + } + return contact; +} + +int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, + struct timeval expiration_time, const char *path_info, const char *user_agent, + const char *via_addr, int via_port, const char *call_id, + struct ast_sip_endpoint *endpoint) +{ + struct ast_sip_contact *contact; + + contact = ast_sip_location_create_contact(aor, uri, expiration_time, path_info, + user_agent, via_addr, via_port, call_id, 0, endpoint); + ao2_cleanup(contact); + return contact ? 0 : -1; } int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, @@ -441,6 +456,29 @@ int ast_sip_location_delete_contact(struct ast_sip_contact *contact) return ast_sorcery_delete(ast_sip_get_sorcery(), contact); } +static int prune_boot_contacts_cb(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + + if (contact->prune_on_boot) { + ast_sip_location_delete_contact(contact); + } + + return 0; +} + +void ast_sip_location_prune_boot_contacts(void) +{ + struct ao2_container *contacts; + + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", + AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (contacts) { + ao2_callback(contacts, 0, prune_boot_contacts_cb, NULL); + ao2_ref(contacts, -1); + } +} + /*! \brief Custom handler for translating from a string timeval to actual structure */ static int expiration_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -1221,6 +1259,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "via_addr", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, via_addr)); ast_sorcery_object_field_register(sorcery, "contact", "via_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact, via_port)); ast_sorcery_object_field_register(sorcery, "contact", "call_id", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, call_id)); + ast_sorcery_object_field_register(sorcery, "contact", "prune_on_boot", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_contact, prune_on_boot)); ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration)); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index d3ff1f32bc1..715ffe8ebe4 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -2057,6 +2057,8 @@ int ast_res_pjsip_initialize_configuration(void) load_all_endpoints(); + ast_sip_location_prune_boot_contacts(); + return 0; } diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index a4ce54769f7..ba1c074b369 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -310,6 +310,47 @@ static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor return -1; } +/*! Transport monitor for incoming REGISTER contacts */ +struct contact_transport_monitor { + /*! + * \brief Sorcery contact name to remove on transport shutdown + * \note Stored after aor_name in space reserved when struct allocated. + */ + char *contact_name; + /*! AOR name the contact is associated */ + char aor_name[0]; +}; + +static void register_contact_transport_shutdown_cb(void *data) +{ + struct contact_transport_monitor *monitor = data; + struct ast_sip_contact *contact; + struct ast_sip_aor *aor; + + aor = ast_sip_location_retrieve_aor(monitor->aor_name); + if (!aor) { + return; + } + + ao2_lock(aor); + contact = ast_sip_location_retrieve_contact(monitor->contact_name); + if (contact) { + ast_sip_location_delete_contact(contact); + ast_verb(3, "Removed contact '%s' from AOR '%s' due to transport shutdown\n", + contact->uri, monitor->aor_name); + ast_test_suite_event_notify("AOR_CONTACT_REMOVED", + "Contact: %s\r\n" + "AOR: %s\r\n" + "UserAgent: %s", + contact->uri, + monitor->aor_name, + contact->user_agent); + ao2_ref(contact, -1); + } + ao2_unlock(aor); + ao2_ref(aor, -1); +} + static int register_aor_core(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, @@ -419,6 +460,9 @@ static int register_aor_core(pjsip_rx_data *rdata, pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)); if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) { + int prune_on_boot = 0; + pj_str_t host_name; + /* If they are actually trying to delete a contact that does not exist... be forgiving */ if (!expiration) { ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n", @@ -426,14 +470,68 @@ static int register_aor_core(pjsip_rx_data *rdata, continue; } - if (ast_sip_location_add_contact_nolock(aor, contact_uri, ast_tvadd(ast_tvnow(), - ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, - user_agent, via_addr, via_port, call_id, endpoint)) { + /* Determine if the contact cannot survive a restart/boot. */ + if (details.uri->port == rdata->pkt_info.src_port + && !pj_strcmp(&details.uri->host, + pj_cstr(&host_name, rdata->pkt_info.src_name)) + /* We have already checked if the URI scheme is sip: or sips: */ + && PJSIP_TRANSPORT_IS_RELIABLE(rdata->tp_info.transport)) { + pj_str_t type_name; + + /* Determine the transport parameter value */ + if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) { + /* WSS is special, as it needs to be ws. */ + pj_cstr(&type_name, "ws"); + } else { + pj_cstr(&type_name, rdata->tp_info.transport->type_name); + } + + if (!pj_stricmp(&details.uri->transport_param, &type_name) + && (endpoint->nat.rewrite_contact + /* Websockets are always rewritten */ + || !pj_stricmp(&details.uri->transport_param, + pj_cstr(&type_name, "ws")))) { + /* + * The contact was rewritten to the reliable transport's + * source address. Disconnecting the transport for any + * reason invalidates the contact. + */ + prune_on_boot = 1; + } + } + + contact = ast_sip_location_create_contact(aor, contact_uri, + ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), + path_str ? ast_str_buffer(path_str) : NULL, + user_agent, via_addr, via_port, call_id, prune_on_boot, endpoint); + if (!contact) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", - contact_uri, aor_name); + contact_uri, aor_name); continue; } + if (prune_on_boot) { + const char *contact_name; + struct contact_transport_monitor *monitor; + + /* + * Monitor the transport in case it gets disconnected because + * the contact won't be valid anymore if that happens. + */ + contact_name = ast_sorcery_object_get_id(contact); + monitor = ao2_alloc_options(sizeof(*monitor) + 2 + strlen(aor_name) + + strlen(contact_name), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (monitor) { + strcpy(monitor->aor_name, aor_name);/* Safe */ + monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1; + strcpy(monitor->contact_name, contact_name);/* Safe */ + + ast_sip_transport_monitor_register(rdata->tp_info.transport, + register_contact_transport_shutdown_cb, monitor); + ao2_ref(monitor, -1); + } + } + ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_ADDED", @@ -885,6 +983,7 @@ static int unload_module(void) ast_manager_unregister(AMI_SHOW_REGISTRATIONS); ast_manager_unregister(AMI_SHOW_REGISTRATION_CONTACT_STATUSES); ast_sip_unregister_service(®istrar_module); + ast_sip_transport_monitor_unregister_all(register_contact_transport_shutdown_cb); return 0; } diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index 1429cceed8b..22ec19540dc 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -145,6 +145,7 @@ static int transport_create(void *data) { struct transport_create_data *create_data = data; struct ws_transport *newtransport = NULL; + pjsip_tp_state_callback state_cb; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); struct pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt); @@ -161,6 +162,10 @@ static int transport_create(void *data) goto on_error; } + /* Give websocket transport a unique name for its lifetime */ + snprintf(newtransport->transport.obj_name, PJ_MAX_OBJ_NAME, "ws%p", + &newtransport->transport); + newtransport->transport.endpt = endpt; if (!(pool = pjsip_endpt_create_pool(endpt, "ws", 512, 512))) { @@ -219,6 +224,7 @@ static int transport_create(void *data) newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type); newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64); + newtransport->transport.dir = PJSIP_TP_DIR_INCOMING; newtransport->transport.tpmgr = tpmgr; newtransport->transport.send_msg = &ws_send_msg; newtransport->transport.destroy = &ws_destroy; @@ -242,6 +248,16 @@ static int transport_create(void *data) } create_data->transport = newtransport; + + /* Notify application of transport state */ + state_cb = pjsip_tpmgr_get_state_cb(newtransport->transport.tpmgr); + if (state_cb) { + pjsip_transport_state_info state_info; + + memset(&state_info, 0, sizeof(state_info)); + state_cb(&newtransport->transport, PJSIP_TP_STATE_CONNECTED, &state_info); + } + return 0; on_error: From 1bec781ccec7df8e8a847e5bb5e46530d642f82d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 2 Aug 2017 18:44:12 -0500 Subject: [PATCH 1423/1578] res_pjsip_outbound_registration.c: Re-REGISTER on transport shutdown. The fix for the issue is broken up into three parts. This is part three which handles the client side of REGISTER requests. The registered contact may no longer be valid on the server when the transport used is reliable and the connection is broken. * Re-REGISTER our contact if the reliable transport is broken after registration completes. We attempt to re-REGISTER immediately to minimize the time we are unreachable. Time may have already passed between the connection being broken and the loss being detected. * Reorder sip_outbound_registration_state_alloc() so the STATSD_GUAGE's are still correct if an allocation failure happens. ASTERISK-27147 Change-Id: I3668405b1ee75dfefb07c0d637826176f741ce83 --- res/res_pjsip_outbound_registration.c | 114 ++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 9 deletions(-) diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 7b605b98288..bbb286acf42 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -358,6 +358,8 @@ struct sip_outbound_registration_client_state { unsigned int auth_attempted:1; /*! \brief The name of the transport to be used for the registration */ char *transport_name; + /*! \brief The name of the registration sorcery object */ + char *registration_name; }; /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */ @@ -795,6 +797,82 @@ static void schedule_retry(struct registration_response *response, unsigned int } } +static int reregister_immediately_cb(void *obj) +{ + struct sip_outbound_registration_state *state = obj; + + if (state->client_state->status != SIP_REGISTRATION_REGISTERED) { + ao2_ref(state, -1); + return 0; + } + + if (DEBUG_ATLEAST(1)) { + pjsip_regc_info info; + + pjsip_regc_get_info(state->client_state->client, &info); + ast_log(LOG_DEBUG, + "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n", + (int) info.server_uri.slen, info.server_uri.ptr, + (int) info.client_uri.slen, info.client_uri.ptr); + } + + cancel_registration(state->client_state); + + ao2_ref(state->client_state, +1); + handle_client_registration(state->client_state); + + ao2_ref(state, -1); + return 0; +} + +/*! + * \internal + * \brief The reliable transport we registered using has shutdown. + * \since 13.18.0 + * + * \param obj What is needed to initiate a reregister attempt. + * + * \return Nothing + */ +static void registration_transport_shutdown_cb(void *obj) +{ + const char *registration_name = obj; + struct sip_outbound_registration_state *state; + + state = get_state(registration_name); + if (!state) { + /* Registration no longer exists or shutting down. */ + return; + } + if (ast_sip_push_task(state->client_state->serializer, reregister_immediately_cb, state)) { + ao2_ref(state, -1); + } +} + +static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name) +{ + char *monitor; + + if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) { + return; + } + monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!monitor) { + return; + } + strcpy(monitor, registration_name);/* Safe */ + + /* + * We'll ignore if the transport has already been shutdown before we + * register the monitor. We might get into a message spamming infinite + * loop of registration, shutdown, reregistration... + */ + ast_sip_transport_monitor_register(transport, registration_transport_shutdown_cb, + monitor); + ao2_ref(monitor, -1); +} + /*! \brief Callback function for handling a response to a registration attempt */ static int handle_registration_response(void *data) { @@ -863,9 +941,15 @@ static int handle_registration_response(void *data) next_registration_round = 0; } schedule_registration(response->client_state, next_registration_round); + + /* See if we should monitor for transport shutdown */ + registration_transport_monitor_setup(response->rdata->tp_info.transport, + response->client_state->registration_name); } else { ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri); update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED); + ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport, + registration_transport_shutdown_cb); } } else if (response->client_state->destroy) { /* We need to deal with the pending destruction instead. */ @@ -1008,12 +1092,13 @@ static void sip_outbound_registration_client_state_destroy(void *obj) { struct sip_outbound_registration_client_state *client_state = obj; - ast_free(client_state->transport_name); ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0); ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0, sip_outbound_registration_status_str(client_state->status)); ast_taskprocessor_unreference(client_state->serializer); + ast_free(client_state->transport_name); + ast_free(client_state->registration_name); } /*! \brief Allocator function for registration state */ @@ -1033,6 +1118,23 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a return NULL; } + state->client_state->status = SIP_REGISTRATION_UNREGISTERED; + state->client_state->timer.user_data = state->client_state; + state->client_state->timer.cb = sip_outbound_registration_timer_cb; + state->client_state->transport_name = ast_strdup(registration->transport); + state->client_state->registration_name = + ast_strdup(ast_sorcery_object_get_id(registration)); + + ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0, + sip_outbound_registration_status_str(state->client_state->status)); + + if (!state->client_state->transport_name + || !state->client_state->registration_name) { + ao2_cleanup(state); + return NULL; + } + /* Create name with seq number appended. */ ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s", ast_sorcery_object_get_id(registration)); @@ -1043,14 +1145,6 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a ao2_cleanup(state); return NULL; } - state->client_state->status = SIP_REGISTRATION_UNREGISTERED; - state->client_state->timer.user_data = state->client_state; - state->client_state->timer.cb = sip_outbound_registration_timer_cb; - state->client_state->transport_name = ast_strdup(registration->transport); - - ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0); - ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0, - sip_outbound_registration_status_str(state->client_state->status)); state->registration = ao2_bump(registration); return state; @@ -2054,6 +2148,8 @@ static int unload_module(void) ao2_global_obj_release(current_states); + ast_sip_transport_monitor_unregister_all(registration_transport_shutdown_cb); + /* Wait for registration serializers to get destroyed. */ ast_debug(2, "Waiting for registration transactions to complete for unload.\n"); remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME); From bd28a9bbd8ee88f8747b512d51a8ed6a5929e494 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 10 Aug 2017 14:18:01 -0500 Subject: [PATCH 1424/1578] STUN/netsock2: Fix some valgrind uninitialized memory findings. * netsock2.c: Test the addr->len member first as it may be the only member initialized in the struct. * stun.c:ast_stun_handle_packet(): The combinded[] local array could get used uninitialized by ast_stun_request(). The uninitialized string gets copied to another location and could overflow the destination memory buffer. These valgrind findings were found for ASTERISK_27150 but are not necessarily a fix for the issue. Change-Id: I55f8687ba4ffc0f69578fd850af006a56cbc9a57 --- main/netsock2.c | 16 ++++++++++++---- main/stun.c | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/main/netsock2.c b/main/netsock2.c index 8fb9c9e56a4..53a43e04150 100644 --- a/main/netsock2.c +++ b/main/netsock2.c @@ -475,8 +475,12 @@ uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr) int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr) { - return addr->ss.ss_family == AF_INET && - addr->len == sizeof(struct sockaddr_in); + /* + * Test addr->len first to be tolerant of an ast_sockaddr_setnull() + * addr. In that case addr->len might be the only value initialized. + */ + return addr->len == sizeof(struct sockaddr_in) + && addr->ss.ss_family == AF_INET; } int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr) @@ -498,8 +502,12 @@ int ast_sockaddr_is_ipv6_link_local(const struct ast_sockaddr *addr) int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr) { - return addr->ss.ss_family == AF_INET6 && - addr->len == sizeof(struct sockaddr_in6); + /* + * Test addr->len first to be tolerant of an ast_sockaddr_setnull() + * addr. In that case addr->len might be the only value initialized. + */ + return addr->len == sizeof(struct sockaddr_in6) + && addr->ss.ss_family == AF_INET6; } int ast_sockaddr_is_any(const struct ast_sockaddr *addr) diff --git a/main/stun.c b/main/stun.c index 77ced82ae0a..c103ab8d8cc 100644 --- a/main/stun.c +++ b/main/stun.c @@ -343,6 +343,8 @@ int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, if (st.username) { append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft); snprintf(combined, sizeof(combined), "%16s%16s", st.username + 16, st.username); + } else { + combined[0] = '\0'; } append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft); @@ -398,8 +400,6 @@ int ast_stun_request(int s, struct sockaddr_in *dst, stun_req_id(req); reqlen = 0; reqleft = sizeof(req_buf) - sizeof(struct stun_header); - req->msgtype = 0; - req->msglen = 0; attr = (struct stun_attr *) req->ies; if (username) { append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft); From 15fbcc74d8fd1b3655f4c34a280fe76665bd0c5c Mon Sep 17 00:00:00 2001 From: Andrey Egorov Date: Fri, 4 Aug 2017 17:25:52 +0300 Subject: [PATCH 1425/1578] res_xmpp: Google OAuth 2.0 protocol support for XMPP / Motif Add ability to use tokens instead of passwords according to Google OAuth 2.0 protocol. ASTERISK-27169 Reported by: Andrey Egorov Tested by: Andrey Egorov Change-Id: I07f7052a502457ab55010a4d3686653b60f4c8db --- CHANGES | 6 ++ configs/samples/xmpp.conf.sample | 23 ++++++++ res/res_xmpp.c | 99 +++++++++++++++++++++++++++----- 3 files changed, 115 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index f6c94f8fd78..67454bcceb8 100644 --- a/CHANGES +++ b/CHANGES @@ -73,6 +73,12 @@ res_musiconhold * New dialplan function PJSIP_DTMF_MODE added to get or change the DTMF mode of a channel on a per-call basis. +res_xmpp +----------------- + * OAuth 2.0 authentication is now supported when contacting Google. Follow the + instructions in xmpp.conf.sample to retrieve and configure the necessary + tokens. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------ ------------------------------------------------------------------------------ diff --git a/configs/samples/xmpp.conf.sample b/configs/samples/xmpp.conf.sample index dad0f79ef20..e3a4be142b3 100644 --- a/configs/samples/xmpp.conf.sample +++ b/configs/samples/xmpp.conf.sample @@ -18,6 +18,29 @@ ;pubsub_node=pubsub.astjab.org ; Node to use for publishing events via PubSub ;username=asterisk@astjab.org/asterisk ; Username with optional resource. ;secret=blah ; Password +;refresh_token=TOKEN_VALUE ; Refresh token issued by Google OAuth 2.0 protocol. + ; `secret` must NOT be set if you use OAuth. + ; See https://developers.google.com/identity/protocols/OAuth2WebServer + ; for more details. + ; For test reasons you can obtain one on the page + ; https://developers.google.com/oauthplayground/ + ; 1. Click on Settings icon, check "Use your own OAuth credentials" + ; and enter your Client ID and Client Secret (see below). + ; 2. Input the scope https://www.googleapis.com/auth/googletalk + ; and push "Authorize APIs" button. + ; 3. Approve permissions. + ; 4. On section "Step 2" push "Exchange authorization code for tokens" + ; and get your Refresh token. +;oauth_clientid=OAUTH_CLIENT_ID_VALUE ; The application's client id to authorize using Google OAuth 2.0 protocol. +;oauth_secret=OAUTH_SECRET_VALUE ; The application's client secret to authorize using Google OAuth 2.0 protocol. + ; 1. Create new Project on the page: + ; https://console.cloud.google.com/apis/credentials/oauthclient + ; 2. Create new Application ID on the same page with type Web-application. + ; In section "Allowed URI redirections" put the path to the corresponding + ; script on your site or https://developers.google.com/oauthplayground + ; if you would like to obtain refresh_token from users by hand + ; (for example, for test reasons). + ; 3. Client ID and Client Secret will be shown and available on the same page. ;priority=1 ; Resource priority ;port=5222 ; Port to use defaults to 5222 ;usetls=yes ; Use tls or not diff --git a/res/res_xmpp.c b/res/res_xmpp.c index cc9d56f3244..f8eb50599bb 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -59,6 +59,7 @@ #include "asterisk/manager.h" #include "asterisk/cli.h" #include "asterisk/config_options.h" +#include "asterisk/json.h" /*** DOCUMENTATION @@ -321,6 +322,15 @@ XMPP password + + Google OAuth 2.0 refresh token + + + Google OAuth 2.0 application's client id + + + Google OAuth 2.0 application's secret + Route to server, e.g. talk.google.com @@ -459,6 +469,9 @@ struct ast_xmpp_client_config { AST_STRING_FIELD(name); /*!< Name of the client connection */ AST_STRING_FIELD(user); /*!< Username to use for authentication */ AST_STRING_FIELD(password); /*!< Password to use for authentication */ + AST_STRING_FIELD(refresh_token); /*!< Refresh token to use for OAuth authentication */ + AST_STRING_FIELD(oauth_clientid); /*!< Client ID to use for OAuth authentication */ + AST_STRING_FIELD(oauth_secret); /*!< Secret to use for OAuth authentication */ AST_STRING_FIELD(server); /*!< Server hostname */ AST_STRING_FIELD(statusmsg); /*!< Status message for presence */ AST_STRING_FIELD(pubsubnode); /*!< Pubsub node */ @@ -527,6 +540,7 @@ static ast_cond_t message_received_condition; static ast_mutex_t messagelock; static int xmpp_client_config_post_apply(void *obj, void *arg, int flags); +static int fetch_access_token(struct ast_xmpp_client_config *cfg); /*! \brief Destructor function for configuration */ static void ast_xmpp_client_config_destructor(void *obj) @@ -759,12 +773,16 @@ static int xmpp_config_prelink(void *newitem) if (ast_strlen_zero(clientcfg->user)) { ast_log(LOG_ERROR, "No user specified on client '%s'\n", clientcfg->name); return -1; - } else if (ast_strlen_zero(clientcfg->password)) { - ast_log(LOG_ERROR, "No password specified on client '%s'\n", clientcfg->name); + } else if (ast_strlen_zero(clientcfg->password) && ast_strlen_zero(clientcfg->refresh_token)) { + ast_log(LOG_ERROR, "No password or refresh_token specified on client '%s'\n", clientcfg->name); return -1; } else if (ast_strlen_zero(clientcfg->server)) { ast_log(LOG_ERROR, "No server specified on client '%s'\n", clientcfg->name); return -1; + } else if (!ast_strlen_zero(clientcfg->refresh_token) && + (ast_strlen_zero(clientcfg->oauth_clientid) || ast_strlen_zero(clientcfg->oauth_secret))) { + ast_log(LOG_ERROR, "No oauth_clientid or oauth_secret specified, so client '%s' can't be used\n", clientcfg->name); + return -1; } /* If this is a new connection force a reconnect */ @@ -776,6 +794,9 @@ static int xmpp_config_prelink(void *newitem) /* If any configuration options are changing that would require reconnecting set the bit so we will do so if possible */ if (strcmp(clientcfg->user, oldclientcfg->user) || strcmp(clientcfg->password, oldclientcfg->password) || + strcmp(clientcfg->refresh_token, oldclientcfg->refresh_token) || + strcmp(clientcfg->oauth_clientid, oldclientcfg->oauth_clientid) || + strcmp(clientcfg->oauth_secret, oldclientcfg->oauth_secret) || strcmp(clientcfg->server, oldclientcfg->server) || (clientcfg->port != oldclientcfg->port) || (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) != ast_test_flag(&oldclientcfg->flags, XMPP_COMPONENT)) || @@ -2784,7 +2805,13 @@ static int xmpp_client_authenticate_sasl(struct ast_xmpp_client *client, struct } iks_insert_attrib(auth, "xmlns", IKS_NS_XMPP_SASL); - iks_insert_attrib(auth, "mechanism", "PLAIN"); + if (!ast_strlen_zero(cfg->refresh_token)) { + iks_insert_attrib(auth, "mechanism", "X-OAUTH2"); + iks_insert_attrib(auth, "auth:service", "oauth2"); + iks_insert_attrib(auth, "xmlns:auth", "http://www.google.com/talk/protocol/auth"); + } else { + iks_insert_attrib(auth, "mechanism", "PLAIN"); + } if (strchr(client->jid->user, '/')) { char *user = ast_strdupa(client->jid->user); @@ -3283,28 +3310,28 @@ static int xmpp_ping_request(struct ast_xmpp_client *client, const char *to, con { iks *iq, *ping; int res; - + ast_debug(2, "JABBER: Sending Keep-Alive Ping for client '%s'\n", client->name); if (!(iq = iks_new("iq")) || !(ping = iks_new("ping"))) { iks_delete(iq); return -1; } - + iks_insert_attrib(iq, "type", "get"); iks_insert_attrib(iq, "to", to); iks_insert_attrib(iq, "from", from); - + ast_xmpp_client_lock(client); iks_insert_attrib(iq, "id", client->mid); ast_xmpp_increment_mid(client->mid); ast_xmpp_client_unlock(client); - + iks_insert_attrib(ping, "xmlns", "urn:xmpp:ping"); iks_insert_node(iq, ping); - + res = ast_xmpp_client_send(client, iq); - + iks_delete(ping); iks_delete(iq); @@ -3625,6 +3652,13 @@ static int xmpp_client_reconnect(struct ast_xmpp_client *client) return -1; } + if (!ast_strlen_zero(clientcfg->refresh_token)) { + ast_debug(2, "Obtaining OAuth access token for client '%s'\n", client->name); + if (fetch_access_token(clientcfg)) { + return -1; + } + } + ast_xmpp_client_disconnect(client); client->timeout = 50; @@ -3641,7 +3675,7 @@ static int xmpp_client_reconnect(struct ast_xmpp_client *client) /* Set socket timeout options */ setsockopt(iks_fd(client->parser), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); - + if (res == IKS_NET_NOCONN) { ast_log(LOG_ERROR, "No XMPP connection available when trying to connect client '%s'\n", client->name); return -1; @@ -3726,7 +3760,7 @@ static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int time /* Log the message here, because iksemel's logHook is unaccessible */ xmpp_log_hook(client, buf, len, 1); - + if(buf[0] == ' ') { ast_debug(1, "JABBER: Detected Google Keep Alive. " "Sending out Ping request for client '%s'\n", client->name); @@ -3867,6 +3901,42 @@ static int xmpp_client_config_merge_buddies(void *obj, void *arg, int flags) return 1; } +static int fetch_access_token(struct ast_xmpp_client_config *cfg) +{ + RAII_VAR(char *, cmd, NULL, ast_free); + char cBuf[1024] = ""; + const char *url = "https://www.googleapis.com/oauth2/v3/token"; + struct ast_json_error error; + RAII_VAR(struct ast_json *, jobj, NULL, ast_json_unref); + + ast_asprintf(&cmd, "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)", + url, cfg->oauth_clientid, cfg->oauth_secret, cfg->refresh_token); + + ast_debug(2, "Performing OAuth 2.0 authentication for client '%s' using command: %s\n", + cfg->name, cmd); + + if (!ast_func_read(NULL, cmd, cBuf, sizeof(cBuf) - 1)) { + ast_log(LOG_ERROR, "CURL is unavailable. This is required for OAuth 2.0 authentication of XMPP client '%s'. Please ensure it is loaded.\n", + cfg->name); + return -1; + } + + ast_debug(2, "OAuth 2.0 authentication for client '%s' returned: %s\n", cfg->name, cBuf); + + jobj = ast_json_load_string(cBuf, &error); + if (jobj) { + const char *token = ast_json_string_get(ast_json_object_get(jobj, "access_token")); + if (token) { + ast_string_field_set(cfg, password, token); + return 0; + } + } + + ast_log(LOG_ERROR, "An error occurred while performing OAuth 2.0 authentication for client '%s': %s\n", cfg->name, cBuf); + + return -1; +} + static int xmpp_client_config_post_apply(void *obj, void *arg, int flags) { struct ast_xmpp_client_config *cfg = obj; @@ -4620,8 +4690,8 @@ static int client_buddy_handler(const struct aco_option *opt, struct ast_variabl * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) @@ -4639,6 +4709,9 @@ static int load_module(void) aco_option_register(&cfg_info, "username", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, user)); aco_option_register(&cfg_info, "secret", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, password)); + aco_option_register(&cfg_info, "refresh_token", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, refresh_token)); + aco_option_register(&cfg_info, "oauth_clientid", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, oauth_clientid)); + aco_option_register(&cfg_info, "oauth_secret", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, oauth_secret)); aco_option_register(&cfg_info, "serverhost", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, server)); aco_option_register(&cfg_info, "statusmessage", ACO_EXACT, client_options, "Online and Available", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, statusmsg)); aco_option_register(&cfg_info, "pubsub_node", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, pubsubnode)); From 9e2b2a9837bc25adfc4a6d760a8ffa7bb4d379d9 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 15 Aug 2017 11:14:20 -0500 Subject: [PATCH 1426/1578] res_pjsip: Fix prune_on_boot to remove only contacts for the host. * Check that the contact's reg_server matches the host's name before deleting any prune_on_boot contacts. We don't want to delete reliable transport contacts made with other servers if the ps_contacts database table is shared with other servers. Thanks to Ross Beer for pointing out that the original prune logic would delete reliable transport contacts from other servers. ASTERISK-27147 Change-Id: I8e439d0d1c266ffdfd7b73d1e5e466180a689bd0 --- res/res_pjsip/location.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 557aeb6b9ba..2273273e31e 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -460,7 +460,10 @@ static int prune_boot_contacts_cb(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; - if (contact->prune_on_boot) { + if (contact->prune_on_boot + && !strcmp(contact->reg_server, ast_config_AST_SYSTEM_NAME ?: "")) { + ast_verb(3, "Removed contact '%s' from AOR '%s' due to system boot\n", + contact->uri, contact->aor); ast_sip_location_delete_contact(contact); } From c049d1c3b267c6a139807885cbdd126ae2ba1d63 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 15 Aug 2017 15:15:58 -0500 Subject: [PATCH 1427/1578] configure: Check cache for valid pjproject tarball before downloading. On a fresh Asterisk source directory, the bundled pjproject tarball is unconditionally downloaded even if the tarball is already in a specified cache directory. * Made check if the pjproject tarball is valid in the cache directory before downloading the tarball on a fresh source directory. Change-Id: Ic7ec842d3c97ecd8dafbad6f056b7fdbce41cae5 --- third-party/pjproject/Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index a5b5508425e..7a42edcde2c 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -86,6 +86,11 @@ SHELL_ECHO_PREFIX := echo '[pjproject] ' _all: $(TARGETS) +define tarball_exists + (if [ -f $(TARBALL) -a -f $(PJMD5SUM) ] ; then exit 0 ;\ + else exit 1; fi; ) +endef + define verify_tarball ($(SHELL_ECHO_PREFIX) Verifying $(TARBALL) &&\ tarball_sum=$$($(CAT) $(TARBALL) | $(MD5) | $(SED) -n -r -e "s/^([^ ]+)\s+.*/\1/gp") ;\ @@ -111,11 +116,12 @@ TARBALL_URL = $(PJPROJECT_URL)/$(TARBALL_FILE) PJMD5SUM = $(patsubst %.tar.bz2,%.md5,$(TARBALL)) $(TARBALL): ../versions.mak - $(CMD_PREFIX) $(download_from_pjproject) || (rm -rf $@ ;\ + $(CMD_PREFIX) ($(tarball_exists) && $(verify_tarball) && touch $@) || (rm -rf $@ ;\ + $(download_from_pjproject)) || (rm -rf $@ ;\ $(SHELL_ECHO_PREFIX) Retrying download ; $(download_from_pjproject)) source/.unpacked: $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 - ($(verify_tarball)) || (rm -rf $@ ;\ + $(CMD_PREFIX) $(verify_tarball) || (rm -rf $@ ;\ $(SHELL_ECHO_PREFIX) Retrying download ; $(download_from_pjproject)) $(ECHO_PREFIX) Unpacking $< -@rm -rf source pjproject-* >/dev/null 2>&1 From e4e2e53c8a5b6bc96e6cc41aa2224ec95d4c8714 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Tue, 15 Aug 2017 13:12:10 -0500 Subject: [PATCH 1428/1578] manager: hook event is not being raised When the iostream code went in it introduced a conditional that made it so the hook event was not being raised even if a hook is present. This patch adds a check to see if a hook is present in astman_append. If so then call into the send_string function, which in turn raises the even for specified hook. Also updated the ami hooks unit test, so the test could be automated. ASTERISK-27200 #close Change-Id: Iff37f02f9708195d8f23e68f959d6eab720e1e36 --- main/manager.c | 7 +++-- tests/test_amihooks.c | 64 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/main/manager.c b/main/manager.c index d16a6927810..e67efe3f3fc 100644 --- a/main/manager.c +++ b/main/manager.c @@ -2905,14 +2905,13 @@ int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg) return ret; } - /*! * helper function to send a string to the socket. * Return -1 on error (e.g. buffer full). */ static int send_string(struct mansession *s, char *string) { - struct ast_iostream *stream = s->stream ? s->stream : s->session->stream; + struct ast_iostream *stream; int len, res; /* It's a result from one of the hook's action invocation */ @@ -2925,6 +2924,8 @@ static int send_string(struct mansession *s, char *string) return 0; } + stream = s->stream ? s->stream : s->session->stream; + len = strlen(string); ast_iostream_set_timeout_inactivity(stream, s->session->writetimeout); res = ast_iostream_write(stream, string, len); @@ -2971,7 +2972,7 @@ void astman_append(struct mansession *s, const char *fmt, ...) return; } - if (s->tcptls_session != NULL && s->tcptls_session->stream != NULL) { + if (s->hook || (s->tcptls_session != NULL && s->tcptls_session->stream != NULL)) { send_string(s, ast_str_buffer(buf)); } else { ast_verbose("No connection stream in astman_append, should not happen\n"); diff --git a/tests/test_amihooks.c b/tests/test_amihooks.c index 1297cb57ffc..14cfbdd1334 100644 --- a/tests/test_amihooks.c +++ b/tests/test_amihooks.c @@ -22,8 +22,10 @@ * * \author David Brooks based off of code written by Russell Bryant * - * This is simply an example or test module illustrating the ability for a custom module - * to hook into AMI. Registration for AMI events and sending of AMI actions is shown. + * This started, and continues to serves, as an example illustrating the ability + * for a custom module to hook into AMI. Registration for AMI events and sending + * of AMI actions is shown. A test has also been created that utilizes the original + * example in order to make sure the ami event hook gets raised. */ /*** MODULEINFO @@ -37,11 +39,66 @@ #include "asterisk/cli.h" #include "asterisk/utils.h" #include "asterisk/manager.h" +#include "asterisk/test.h" + +#define CATEGORY "/main/amihooks/" + +AST_MUTEX_DEFINE_STATIC(hook_lock); +ast_cond_t hook_cond; +int done; + +static int wait_for_hook(struct ast_test *test) +{ + struct timeval start = ast_tvnow(); + struct timespec timeout = { + .tv_sec = start.tv_sec + 2, + .tv_nsec = start.tv_usec * 1000 + }; + int res = 0; + + ast_mutex_lock(&hook_lock); + while (!done) { + if (ast_cond_timedwait(&hook_cond, &hook_lock, &timeout) == ETIMEDOUT) { + ast_test_status_update(test, "Test timed out while waiting for hook event\n"); + res = -1; + break; + } + } + ast_mutex_unlock(&hook_lock); + + return res; +} + +AST_TEST_DEFINE(amihook_cli_send) +{ + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = CATEGORY; + info->summary = "Execute an action using an AMI hook"; + info->description = info->summary; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + done = 0; + if (ast_cli_command(-1, "amihook send")) { + return AST_TEST_FAIL; + } + + return wait_for_hook(test) ? AST_TEST_FAIL : AST_TEST_PASS; +} /* The helper function is required by struct manager_custom_hook. See __manager_event for details */ static int amihook_helper(int category, const char *event, char *content) { ast_log(LOG_NOTICE, "AMI Event: \nCategory: %d Event: %s\n%s\n", category, event, content); + + ast_mutex_lock(&hook_lock); + done = 1; + ast_cond_signal(&hook_cond); + ast_mutex_unlock(&hook_lock); return 0; } @@ -141,6 +198,7 @@ static struct ast_cli_entry cli_amihook_evt[] = { static int unload_module(void) { + AST_TEST_UNREGISTER(amihook_cli_send); ast_manager_unregister_hook(&test_hook); return ast_cli_unregister_multiple(cli_amihook_evt, ARRAY_LEN(cli_amihook_evt)); } @@ -151,6 +209,8 @@ static int load_module(void) res = ast_cli_register_multiple(cli_amihook_evt, ARRAY_LEN(cli_amihook_evt)); + AST_TEST_REGISTER(amihook_cli_send); + return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; } From 0e777258be34b3454ac252d4b9e917465efeb741 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 16 Aug 2017 14:43:10 -0600 Subject: [PATCH 1429/1578] Fix downloader not working with curl The codec/dpma downloader wasn't handling curl correctly. The logic that transforms makeopts into a bash-sourceable file wasn't handling the make 'or' command in DOWNLOAD_TIMEOUT so bash was looking for an 'or' command. That logic has been eliminated. Instead of trying to transform and source makeopts, the downloader now calls a make scriptlet to print the value of a specific variable. This way, make handles the ors (or any other make construct that happens to creep into that file). ASTERISK-27202 Reported by: Sean McCord Change-Id: Iadfb6693528e4d4da7b8bb201fa66da2c71c7f99 --- build_tools/download_externals | 27 ++++++++++++++-------- build_tools/list_valid_installed_externals | 24 +++++++++++++------ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/build_tools/download_externals b/build_tools/download_externals index f6cc5239075..efeb6c53c6f 100755 --- a/build_tools/download_externals +++ b/build_tools/download_externals @@ -5,7 +5,24 @@ if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO fi set -e + ASTTOPDIR=${ASTTOPDIR:-.} +export make=`sed -n -r -e "s/^MAKE\s*=\s*//gp" ${ASTTOPDIR}/makeopts` + +getvar() { + $make --quiet --no-print-directory -f- <${tmpdir}/makeopts -source ${tmpdir}/makeopts if [[ -z "${ASTMODDIR}" ]] ; then echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." exit 1 fi -XMLSTARLET=${XMLSTARLET:-xmlstarlet} if [[ "${XMLSTARLET}" = ":" ]] ; then echo "${module_name}: The externals downloader requires xmlstarlet to be installed." exit 1 fi -cache_dir="${EXTERNALS_CACHE_DIR}" if [[ -z ${cache_dir} ]] ; then cache_dir=${tmpdir} fi @@ -191,7 +200,7 @@ if [[ -f ${cache_dir}/${full_name}.manifest.xml ]] ; then fi if [[ ${need_download} = 1 ]] ; then - echo "${full_name}: Downloading ${remote_url}/${tarball}" + echo "${full_name}: Downloading ${remote_url}/${tarball} to ${cache_dir}/${tarball}" ${DOWNLOAD_TO_STDOUT} ${remote_url}/${tarball} > ${cache_dir}/${tarball} || { echo "${full_name}: Unable to fetch ${remote_url}/${tarball}" exit 1 diff --git a/build_tools/list_valid_installed_externals b/build_tools/list_valid_installed_externals index 194801c94ae..ed362743ca8 100755 --- a/build_tools/list_valid_installed_externals +++ b/build_tools/list_valid_installed_externals @@ -6,6 +6,23 @@ fi set -e ASTTOPDIR=${ASTTOPDIR:-.} +export make=`sed -n -r -e "s/^MAKE\s*=\s*//gp" ${ASTTOPDIR}/makeopts` + +getvar() { + $make --quiet --no-print-directory -f- <${tmpdir}/makeopts -source ${tmpdir}/makeopts if [[ -z "${ASTMODDIR}" ]] ; then echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." exit 1 fi -XMLSTARLET=${XMLSTARLET:-xmlstarlet} if [[ "${XMLSTARLET}" = ":" ]] ; then echo "${module_name}: The externals downloader requires xmlstarlet to be installed." exit 1 From 667986d875d32a1abe8dc19a89b5ff31eb86de25 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 17 Aug 2017 13:00:09 -0400 Subject: [PATCH 1430/1578] res_calendar_icalendar: Properly handle recurring events When looking for recurring events, use the correct end time based on the configured 'timeframe.' ASTERISK-27174 #close Reported by: Mark Thompson Change-Id: Id90c3cfc79d561a5521d79be176683e225f2edef --- res/res_calendar_icalendar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c index 33480608aad..795a35bd944 100644 --- a/res/res_calendar_icalendar.c +++ b/res/res_calendar_icalendar.c @@ -333,7 +333,7 @@ static void icalendar_add_event(icalcomponent *comp, struct icaltime_span *span, start_time = icaltime_current_time_with_zone(icaltimezone_get_utc_timezone()); end_time = icaltime_current_time_with_zone(icaltimezone_get_utc_timezone()); end_time.second += pvt->owner->timeframe * 60; - icaltime_normalize(end_time); + end_time = icaltime_normalize(end_time); for (iter = icalcomponent_get_first_component(pvt->data, ICAL_VEVENT_COMPONENT); iter; From 83b81d1f8d88a093bb3d4d7ae378bd0176996b73 Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Sun, 20 Aug 2017 15:15:37 +0200 Subject: [PATCH 1431/1578] res_xmpp: fix inverted return code check in OAuth fetch_access_token calls func_curl via ast_func_read. The latter returns 0 upon success and -1 if the function is not available. This commit inverts the return code check so that an error is printed if the module is not loaded and not if it is loaded. ASTERISK-27207 #close Change-Id: I9ef903f80702d1218e8701f65a4e5e918e6548fb --- res/res_xmpp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index f8eb50599bb..444eacbe9aa 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -3915,7 +3915,7 @@ static int fetch_access_token(struct ast_xmpp_client_config *cfg) ast_debug(2, "Performing OAuth 2.0 authentication for client '%s' using command: %s\n", cfg->name, cmd); - if (!ast_func_read(NULL, cmd, cBuf, sizeof(cBuf) - 1)) { + if (ast_func_read(NULL, cmd, cBuf, sizeof(cBuf) - 1)) { ast_log(LOG_ERROR, "CURL is unavailable. This is required for OAuth 2.0 authentication of XMPP client '%s'. Please ensure it is loaded.\n", cfg->name); return -1; From 22af5e3784b41c903b85193e6facf21e9e907e0e Mon Sep 17 00:00:00 2001 From: Sungtae Kim Date: Thu, 17 Aug 2017 23:46:49 +0200 Subject: [PATCH 1432/1578] app_queue: Fix initial hold time queue statistic Fixed to use correct initial value and fixed to use the correct queue info to check the first value. ASTERISK-27204 Change-Id: Ia9e36c828e566e1cc25c66f73307566e4acb8e73 --- apps/app_queue.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 004d93a2ead..b139ef7b1ee 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4072,8 +4072,12 @@ static void recalc_holdtime(struct queue_ent *qe, int newholdtime) /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ ao2_lock(qe->parent); - oldvalue = qe->parent->holdtime; - qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; + if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) { + qe->parent->holdtime = newholdtime; + } else { + oldvalue = qe->parent->holdtime; + qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; + } ao2_unlock(qe->parent); } @@ -5651,7 +5655,7 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom if (callcompletedinsl) { q->callscompletedinsl++; } - if (q->callscompletedinsl == 1) { + if (q->callscompleted == 1) { q->talktime = newtalktime; } else { /* Calculate talktime using the same exponential average as holdtime code */ From 946ef2d711e47f0dd939879bca06e22e44e18451 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 11 Aug 2017 11:40:46 -0500 Subject: [PATCH 1433/1578] bridge_softmix.c: Remove always true test. Change-Id: I26238df2ff0d0f6dfe95c3aa35da588f1ee71727 --- bridges/bridge_softmix.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index b35994895e1..b9a0e98ad65 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -1060,14 +1060,10 @@ static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_cha res = ast_bridge_queue_everyone_else(bridge, bridge_channel, frame); break; case AST_FRAME_VOICE: - if (bridge_channel) { - softmix_bridge_write_voice(bridge, bridge_channel, frame); - } + softmix_bridge_write_voice(bridge, bridge_channel, frame); break; case AST_FRAME_VIDEO: - if (bridge_channel) { - softmix_bridge_write_video(bridge, bridge_channel, frame); - } + softmix_bridge_write_video(bridge, bridge_channel, frame); break; case AST_FRAME_CONTROL: res = softmix_bridge_write_control(bridge, bridge_channel, frame); From f96536b1ea545b24acfbcb114415386d10e28748 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 17 Aug 2017 17:06:21 -0500 Subject: [PATCH 1434/1578] confbridge.h: Fix doxygen comments. Change-Id: I16133166a85fdb557c66ffcbfe8128d0b4725b0e --- apps/confbridge/include/confbridge.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index adf9b867d69..162ff224ca2 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -30,11 +30,11 @@ #include "asterisk/bridge_features.h" #include "conf_state.h" -/* Maximum length of a conference bridge name */ +/*! Maximum length of a conference bridge name */ #define MAX_CONF_NAME AST_MAX_EXTENSION -/* Maximum length of a conference pin */ +/*! Maximum length of a conference pin */ #define MAX_PIN 80 -/* Maximum length of bridge/user/menu profile names */ +/*! Maximum length of bridge/user/menu profile names */ #define MAX_PROFILE_NAME 128 #define DEFAULT_USER_PROFILE "default_user" @@ -70,9 +70,9 @@ enum bridge_profile_flags { BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED = (1 << 2), /*!< Set if conference should feed video of first marked user to all participants. */ BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER = (1 << 3), /*!< Set if conference set the video feed to follow the loudest talker. */ BRIDGE_OPT_RECORD_FILE_APPEND = (1 << 4), /*!< Set if the record file should be appended to between start/stops. */ - BRIDGE_OPT_RECORD_FILE_TIMESTAMP = (1 << 5), /*< Set if the record file should have a timestamp appended */ - BRIDGE_OPT_BINAURAL_ACTIVE = (1 << 6), /*< Set if binaural convolution is activated */ - BRIDGE_OPT_VIDEO_SRC_SFU = (1 << 7), /*< Selective forwarding unit */ + BRIDGE_OPT_RECORD_FILE_TIMESTAMP = (1 << 5), /*!< Set if the record file should have a timestamp appended */ + BRIDGE_OPT_BINAURAL_ACTIVE = (1 << 6), /*!< Set if binaural convolution is activated */ + BRIDGE_OPT_VIDEO_SRC_SFU = (1 << 7), /*!< Selective forwarding unit */ }; enum conf_menu_action_id { From 5bbf7b2aad7456979ac470958f26366944dca232 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 17 Aug 2017 17:07:18 -0500 Subject: [PATCH 1435/1578] app_confbridge: Document sfu video_mode value. Change-Id: I26e17df2c93f3933b23f78070603adbcc84ba204 --- apps/confbridge/conf_config_parser.c | 4 ++++ configs/samples/confbridge.conf.sample | 3 +++ 2 files changed, 7 insertions(+) diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index bfd9f4f5697..6659305760d 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -391,6 +391,10 @@ is the single source of video distribution among all participants. If that user leaves, the marked user to join after them becomes the source. + + Selective Forwarding Unit - Sets multi-stream + operation for a multi-party video conference. + diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index 265b95342aa..9cf86aa0b21 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -213,6 +213,9 @@ type=bridge ; first_marked: The first marked user to join the conference with video capabilities ; is the single source of video distribution among all participants. If ; that user leaves, the marked user to join after them becomes the source. + ; + ; sfu: Selective Forwarding Unit - Sets multi-stream operation + ; for a multi-party video conference. ;language=en ; Set the language used for announcements to the conference. ; Default is en (English). From 87c7a1c79cc9ff061d9d4bbdc116976ba59904bf Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 11 Aug 2017 17:06:01 -0500 Subject: [PATCH 1436/1578] bridge_softmix.c: Restored softmix_bridge_leave() shortcut exit. Change-Id: I13026cd90954e0265eab94a0faf635a3e11f0e35 --- bridges/bridge_softmix.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index b35994895e1..f11de6d3c07 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -786,17 +786,17 @@ static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_ch { struct softmix_channel *sc; struct softmix_bridge_data *softmix_data; + softmix_data = bridge->tech_pvt; sc = bridge_channel->tech_pvt; + if (!sc) { + return; + } if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU) { sfu_topologies_on_leave(bridge_channel, &bridge->channels); } - if (!sc) { - return; - } - if (bridge->softmix.binaural_active) { if (sc->binaural) { set_binaural_data_leave(&softmix_data->convolve, sc->binaural_pos, From 850a3fd0173f96dfdf5f025a0a91348863acbb62 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 14 Aug 2017 12:20:25 -0500 Subject: [PATCH 1437/1578] chan_pjsip.c: Fix topology refresh response code accuracy. There are other 1xx and 2xx codes than 100 and 200 respectively. Change-Id: I680db0997343256add1478714f5bf5b5569aee17 --- channels/chan_pjsip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 4a24fa689fc..677dfd3dd3b 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1484,14 +1484,14 @@ static struct topology_change_refresh_data *topology_change_refresh_data_alloc( static int on_topology_change_response(struct ast_sip_session *session, pjsip_rx_data *rdata) { - if (rdata->msg_info.msg->line.status.code == 200) { + if (PJSIP_IS_STATUS_IN_CLASS(rdata->msg_info.msg->line.status.code, 200)) { /* The topology was changed to something new so give notice to what requested * it so it queries the channel and updates accordingly. */ if (session->channel) { ast_queue_control(session->channel, AST_CONTROL_STREAM_TOPOLOGY_CHANGED); } - } else if (rdata->msg_info.msg->line.status.code != 100) { + } else if (300 <= rdata->msg_info.msg->line.status.code) { /* The topology change failed, so drop the current pending media state */ ast_sip_session_media_state_reset(session->pending_media_state); } From 6ad8249233080aab4f2ea0e72f3e0b7ef384f243 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 16 Aug 2017 15:22:04 -0500 Subject: [PATCH 1438/1578] bridge: Fix softmix bridge deadlock. * Fix deadlock in bridge_softmix.c:softmix_bridge_stream_topology_changed() between bridge_channel and channel locks. * The new bridge technology topology change callbacks must be called with the bridge locked. The callback references the bridge channel list, the bridge technology could change, and the bridge stream mapping is updated. ASTERISK-27212 Change-Id: Ide4360ab853607e738ad471721af3f561ddd83be --- bridges/bridge_softmix.c | 41 +++++++++++++++++++++------- include/asterisk/bridge_channel.h | 25 ++++++++++------- include/asterisk/bridge_technology.h | 26 ++++++++++++------ main/bridge_channel.c | 19 ++++++++++--- 4 files changed, 79 insertions(+), 32 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index b35994895e1..bae0b8c7a2d 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -1690,7 +1690,8 @@ static void map_source_to_destinations(const char *source_stream_name, const cha } } -/*\brief stream_topology_changed callback +/*! + * \brief stream_topology_changed callback * * For most video modes, nothing beyond the ordinary is required. * For the SFU case, though, we need to completely remap the streams @@ -1728,34 +1729,52 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st /* Second traversal: Map specific video channels from their source to their destinations. * - * This is similar to what is done in ast_stream_topology_map(), except that - * video channels are handled differently. Each video source has it's own - * unique index on the bridge. this way, a particular channel's source video - * can be distributed to the appropriate destination streams on the other - * channels + * This is similar to what is done in ast_stream_topology_map(), + * except that video channels are handled differently. Each video + * source has it's own unique index on the bridge. This way, a + * particular channel's source video can be distributed to the + * appropriate destination streams on the other channels. */ AST_LIST_TRAVERSE(&bridge->channels, participant, entry) { int i; struct ast_stream_topology *topology; + ast_bridge_channel_lock(participant); ast_channel_lock(participant->chan); topology = ast_channel_get_stream_topology(participant->chan); + if (topology) { + /* + * Sigh. We have to clone to avoid deadlock in + * map_source_to_destinations() because topology + * is not an ao2 object. + */ + topology = ast_stream_topology_clone(topology); + } + if (!topology) { + /* Oh, my, we are in trouble. */ + ast_channel_unlock(participant->chan); + ast_bridge_channel_unlock(participant); + continue; + } for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { struct ast_stream *stream = ast_stream_topology_get_stream(topology, i); - ast_bridge_channel_lock(participant); + if (is_video_source(stream)) { AST_VECTOR_APPEND(&media_types, AST_MEDIA_TYPE_VIDEO); AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, AST_VECTOR_SIZE(&media_types) - 1); AST_VECTOR_REPLACE(&participant->stream_map.to_channel, AST_VECTOR_SIZE(&media_types) - 1, -1); - /* Unlock the participant to prevent potential deadlock - * in map_source_to_destinations + /* + * Unlock the channel and participant to prevent + * potential deadlock in map_source_to_destinations(). */ + ast_channel_unlock(participant->chan); ast_bridge_channel_unlock(participant); map_source_to_destinations(ast_stream_get_name(stream), ast_channel_name(participant->chan), AST_VECTOR_SIZE(&media_types) - 1, &bridge->channels); ast_bridge_channel_lock(participant); + ast_channel_lock(participant->chan); } else if (is_video_dest(stream, NULL, NULL)) { /* We expect to never read media from video destination channels, but just * in case, we should set their to_bridge value to -1. @@ -1777,10 +1796,12 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, index); AST_VECTOR_REPLACE(&participant->stream_map.to_channel, index, i); } - ast_bridge_channel_unlock(participant); } + ast_stream_topology_free(topology); + ast_channel_unlock(participant->chan); + ast_bridge_channel_unlock(participant); } } diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index 4d3326083a6..4504d6bcb7d 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -716,19 +716,24 @@ void ast_bridge_channel_feature_digit(struct ast_bridge_channel *bridge_channel, * \brief Maps a channel's stream topology to and from the bridge * \since 15.0.0 * - * When a channel joins a bridge or its associated stream topology is updated, each stream - * in the topology needs to be mapped according to its media type to the bridge. Calling - * this method creates a mapping of each stream on the channel indexed to the bridge's - * supported media types and vice versa (i.e. bridge's media types indexed to channel - * streams). - * - * The first channel to join the bridge creates the initial order for the bridge's media - * types (e.g. a one to one mapping is made). Subsequently added channels are mapped to - * that order adding more media types if/when the newly added channel has more streams - * and/or media types specified by the bridge. + * \details + * When a channel joins a bridge or its associated stream topology is + * updated, each stream in the topology needs to be mapped according + * to its media type to the bridge. Calling this method creates a + * mapping of each stream on the channel indexed to the bridge's + * supported media types and vice versa (i.e. bridge's media types + * indexed to channel streams). + * + * The first channel to join the bridge creates the initial order for + * the bridge's media types (e.g. a one to one mapping is made). + * Subsequently added channels are mapped to that order adding more + * media types if/when the newly added channel has more streams and/or + * media types specified by the bridge. * * \param bridge_channel Channel to map * + * \note The bridge_channel's bridge must be locked prior to calling this function. + * * \return Nothing */ void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel); diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridge_technology.h index 8cebe93266f..def7b19335f 100644 --- a/include/asterisk/bridge_technology.h +++ b/include/asterisk/bridge_technology.h @@ -164,20 +164,30 @@ struct ast_bridge_technology { /*! * \brief Callback for when a request has been made to change a stream topology on a channel * - * This is called when a bridge receives a request to change the topology on the channel. A bridge - * technology should define a handler for this callback if it needs to update internals or intercept - * the request and not pass it on to other channels. This can be done by returning a nonzero value. + * \details + * This is called when a bridge receives a request to change the + * topology on the channel. A bridge technology should define a + * handler for this callback if it needs to update internals or + * intercept the request and not pass it on to other channels. + * This can be done by returning a nonzero value. * - * \retval 0 Frame accepted by the bridge. - * \retval -1 Frame rejected. + * \retval 0 Frame can pass to the bridge technology. + * \retval non-zero Frame intercepted by the bridge technology. + * + * \note On entry, bridge is already locked. */ int (*stream_topology_request_change)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); /*! * \brief Callback for when a stream topology changes on the channel * - * This is called when a bridge receives an indication that a topology has been changed on a channel - * and the new topology has been mapped to the bridge. A bridge technology should define a handler for - * this callback if it needs to update internals due to a channel's topology changing. + * \details + * This is called when a bridge receives an indication that a + * topology has been changed on a channel and the new topology has + * been mapped to the bridge. A bridge technology should define a + * handler for this callback if it needs to update internals due + * to a channel's topology changing. + * + * \note On entry, bridge is already locked. */ void (*stream_topology_changed)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); /*! TRUE if the bridge technology is currently suspended. */ diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 1427fd0141f..c465ec16eb4 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2434,6 +2434,7 @@ static const char *controls[] = { static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) { struct ast_frame *frame; + int blocked; if (!ast_strlen_zero(ast_channel_call_forward(bridge_channel->chan))) { /* TODO If early bridging is ever used by anything other than ARI, @@ -2485,10 +2486,16 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) ast_channel_publish_dial(NULL, bridge_channel->chan, NULL, controls[frame->subclass.integer]); break; case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: - if (bridge_channel->bridge->technology->stream_topology_request_change && - bridge_channel->bridge->technology->stream_topology_request_change( - bridge_channel->bridge, bridge_channel)) { - /* Topology change was denied so drop frame */ + ast_bridge_channel_lock_bridge(bridge_channel); + blocked = bridge_channel->bridge->technology->stream_topology_request_change + && bridge_channel->bridge->technology->stream_topology_request_change( + bridge_channel->bridge, bridge_channel); + ast_bridge_unlock(bridge_channel->bridge); + if (blocked) { + /* + * Topology change was intercepted by the bridge technology + * so drop frame. + */ bridge_frame_free(frame); return; } @@ -2498,12 +2505,14 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) * If a stream topology has changed then the bridge_channel's * media mapping needs to be updated. */ + ast_bridge_channel_lock_bridge(bridge_channel); if (bridge_channel->bridge->technology->stream_topology_changed) { bridge_channel->bridge->technology->stream_topology_changed( bridge_channel->bridge, bridge_channel); } else { ast_bridge_channel_stream_map(bridge_channel); } + ast_bridge_unlock(bridge_channel->bridge); break; default: break; @@ -2990,9 +2999,11 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel) { + ast_bridge_channel_lock(bridge_channel); ast_channel_lock(bridge_channel->chan); ast_stream_topology_map(ast_channel_get_stream_topology(bridge_channel->chan), &bridge_channel->bridge->media_types, &bridge_channel->stream_map.to_bridge, &bridge_channel->stream_map.to_channel); ast_channel_unlock(bridge_channel->chan); + ast_bridge_channel_unlock(bridge_channel); } From 9c70c883697d63e6f16b0b06b688a6131423c7e1 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 11 Aug 2017 16:31:45 -0500 Subject: [PATCH 1439/1578] channel: Fix topology API locking. * ast_channel_request_stream_topology_change() must not be called with any channel locks held. * ast_channel_stream_topology_changed() must be called with only the passed channel lock held. ASTERISK-27212 Change-Id: I843de7956d9f1cc7cc02025aea3463d8fe19c691 --- include/asterisk/channel.h | 4 ++-- main/channel.c | 9 ++++++++- tests/test_stream.c | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index f0fe5b212fd..3dfbe61d906 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4934,7 +4934,7 @@ int ast_channel_is_multistream(struct ast_channel *chan); * \param topology The new stream topology * \param change_source The source that initiated the change * - * \pre chan is locked + * \note Absolutely _NO_ channel locks should be held before calling this function. * * \retval 0 request has been accepted to be attempted * \retval -1 request could not be attempted @@ -4956,7 +4956,7 @@ int ast_channel_request_stream_topology_change(struct ast_channel *chan, * \param chan The channel to provide notice to * \param topology The new stream topology * - * \pre chan is locked + * \pre chan is locked Absolutely _NO_ other channels can be locked. * * \retval 0 success * \retval -1 failure diff --git a/main/channel.c b/main/channel.c index 632d4724783..74de9caac8f 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10843,22 +10843,29 @@ enum ast_channel_error ast_channel_errno(void) int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology, void *change_source) { + int res; + ast_assert(chan != NULL); ast_assert(topology != NULL); + ast_channel_lock(chan); if (!ast_channel_is_multistream(chan) || !ast_channel_tech(chan)->indicate) { + ast_channel_unlock(chan); return -1; } if (ast_stream_topology_equal(ast_channel_get_stream_topology(chan), topology)) { ast_debug(3, "Topology of %s already matches what is requested so ignoring topology change request\n", ast_channel_name(chan)); + ast_channel_unlock(chan); return 0; } ast_channel_internal_set_stream_topology_change_source(chan, change_source); - return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, topology, sizeof(topology)); + res = ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, topology, sizeof(topology)); + ast_channel_unlock(chan); + return res; } int ast_channel_stream_topology_changed(struct ast_channel *chan, struct ast_stream_topology *topology) diff --git a/tests/test_stream.c b/tests/test_stream.c index 28983e05cce..8c887048cfb 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -1768,7 +1768,9 @@ AST_TEST_DEFINE(stream_topology_change_request_from_application_non_multistream) ast_test_validate_cleanup(test, change_res == -1, res, done); ast_test_validate_cleanup(test, !pvt->indicated_change_request, res, done); + ast_channel_lock(mock_channel); change_res = ast_channel_stream_topology_changed(mock_channel, topology); + ast_channel_unlock(mock_channel); ast_test_validate_cleanup(test, change_res == -1, res, done); ast_test_validate_cleanup(test, !pvt->indicated_changed, res, done); @@ -1876,7 +1878,9 @@ AST_TEST_DEFINE(stream_topology_change_request_from_application) ast_test_validate_cleanup(test, !change_res, res, done); ast_test_validate_cleanup(test, pvt->indicated_change_request, res, done); + ast_channel_lock(mock_channel); change_res = ast_channel_stream_topology_changed(mock_channel, topology); + ast_channel_unlock(mock_channel); ast_test_validate_cleanup(test, !change_res, res, done); ast_test_validate_cleanup(test, pvt->indicated_changed, res, done); From 17976d1b4e302b3aa7cc510109a78010d7893fe1 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 16 Aug 2017 17:50:18 -0500 Subject: [PATCH 1440/1578] bridge_channel.c: Fix FRACK when mapping frames to the bridge. * Add protection checks when mapping streams to the bridge. The channel and bridge may be in the process of updating the stream mapping when a media frame comes in so we may not be able to map the frame at the time. * We need to map the streams to the bridge's stream numbers right before they are written into the bridge. That way we don't have to keep locking/unlocking the bridge and we won't have any synchronization problems before the frames actually go into the bridge. * Protect the deferred queue with the bridge_channel lock. ASTERISK-27212 Change-Id: Id6860dd61b594b90c8395f6e2c0150219094c21a --- main/bridge_channel.c | 71 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/main/bridge_channel.c b/main/bridge_channel.c index c465ec16eb4..66292bf9212 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -626,11 +626,11 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int caus /*! * \internal - * \brief Write an \ref ast_frame onto the bridge channel + * \brief Write an \ref ast_frame into the bridge * \since 12.0.0 * - * \param bridge_channel Which channel to queue the frame onto. - * \param frame The frame to write onto the bridge_channel + * \param bridge_channel Which channel is queueing the frame. + * \param frame The frame to write into the bridge * * \retval 0 on success. * \retval -1 on error. @@ -638,19 +638,73 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int caus static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { const struct ast_control_t38_parameters *t38_parameters; + int unmapped_stream_num; int deferred; ast_assert(frame->frametype != AST_FRAME_BRIDGE_ACTION_SYNC); ast_bridge_channel_lock_bridge(bridge_channel); + /* Map the frame to the bridge. */ + if (ast_channel_is_multistream(bridge_channel->chan)) { + unmapped_stream_num = frame->stream_num; + switch (frame->frametype) { + case AST_FRAME_VOICE: + case AST_FRAME_VIDEO: + case AST_FRAME_TEXT: + case AST_FRAME_IMAGE: + /* Media frames need to be mapped to an appropriate write stream */ + if (frame->stream_num < 0) { + /* Map to default stream */ + frame->stream_num = -1; + break; + } + ast_bridge_channel_lock(bridge_channel); + if (frame->stream_num < (int)AST_VECTOR_SIZE(&bridge_channel->stream_map.to_bridge)) { + frame->stream_num = AST_VECTOR_GET( + &bridge_channel->stream_map.to_bridge, frame->stream_num); + if (0 <= frame->stream_num) { + ast_bridge_channel_unlock(bridge_channel); + break; + } + } + ast_bridge_channel_unlock(bridge_channel); + ast_bridge_unlock(bridge_channel->bridge); + /* + * Ignore frame because we don't know how to map the frame + * or the bridge is not expecting any media from that + * stream. + */ + return 0; + case AST_FRAME_DTMF_BEGIN: + case AST_FRAME_DTMF_END: + /* + * XXX It makes sense that DTMF could be on any audio stream. + * For now we will only put it on the default audio stream. + */ + default: + frame->stream_num = -1; + break; + } + } else { + unmapped_stream_num = -1; + frame->stream_num = -1; + } + deferred = bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame); if (deferred) { struct ast_frame *dup; dup = ast_frdup(frame); if (dup) { + /* + * We have to unmap the deferred frame so it comes back + * in like a new frame. + */ + dup->stream_num = unmapped_stream_num; + ast_bridge_channel_lock(bridge_channel); AST_LIST_INSERT_HEAD(&bridge_channel->deferred_queue, dup, frame_list); + ast_bridge_channel_unlock(bridge_channel); } } @@ -760,12 +814,14 @@ void bridge_channel_queue_deferred_frames(struct ast_bridge_channel *bridge_chan { struct ast_frame *frame; + ast_bridge_channel_lock(bridge_channel); ast_channel_lock(bridge_channel->chan); while ((frame = AST_LIST_REMOVE_HEAD(&bridge_channel->deferred_queue, frame_list))) { ast_queue_frame_head(bridge_channel->chan, frame); ast_frfree(frame); } ast_channel_unlock(bridge_channel->chan); + ast_bridge_channel_unlock(bridge_channel); } /*! @@ -2458,13 +2514,8 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) return; } - if (ast_channel_is_multistream(bridge_channel->chan) && - (frame->frametype == AST_FRAME_IMAGE || frame->frametype == AST_FRAME_TEXT || - frame->frametype == AST_FRAME_VIDEO || frame->frametype == AST_FRAME_VOICE)) { - /* Media frames need to be mapped to an appropriate write stream */ - frame->stream_num = AST_VECTOR_GET( - &bridge_channel->stream_map.to_bridge, frame->stream_num); - } else { + if (!ast_channel_is_multistream(bridge_channel->chan)) { + /* This may not be initialized by non-multistream channel drivers */ frame->stream_num = -1; } From f2c14f00b8ae4cd1fa809db705d4c368f1cfed1a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 18 Aug 2017 17:37:12 -0500 Subject: [PATCH 1441/1578] res_pjsip_session.c: Fix crash when declining an active stream. If a previously active stream is declined we could crash because the channel's thread is still using the stream while we are updating the topology in the serializer thread. * Defer removing any declined stream's handler until we have blocked the channel's thread with the channel lock. ASTERISK-27212 Change-Id: I50e1d3ef26f8e41948f4c411ee329aa3b960a420 --- res/res_pjsip_session.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index c4b0041a125..b6b8a21ac36 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -784,12 +784,11 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ * we remove it as a result of the stream limit being reached. */ if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { - /* This stream is no longer being used so release any resources the handler - * may have on it. + /* + * Defer removing the handler until we are ready to activate + * the new topology. The channel's thread may still be using + * the stream and we could crash before we are ready. */ - if (session_media->handler) { - session_media_set_handler(session_media, NULL); - } continue; } @@ -801,6 +800,32 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ /* Apply the pending media state to the channel and make it active */ ast_channel_lock(session->channel); + /* Now update the stream handler for any declined/removed streams */ + for (i = 0; i < local->media_count; ++i) { + struct ast_sip_session_media *session_media; + struct ast_stream *stream; + + if (!remote->media[i]) { + continue; + } + + ast_assert(i < AST_VECTOR_SIZE(&session->pending_media_state->sessions)); + ast_assert(i < ast_stream_topology_get_count(session->pending_media_state->topology)); + + session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i); + stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i); + + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED + && session_media->handler) { + /* + * This stream is no longer being used and the channel's thread + * is held off because we have the channel lock so release any + * resources the handler may have on it. + */ + session_media_set_handler(session_media, NULL); + } + } + /* Update the topology on the channel to match the accepted one */ topology = ast_stream_topology_clone(session->pending_media_state->topology); if (topology) { @@ -814,8 +839,9 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ /* Add all the file descriptors from the pending media state */ for (i = 0; i < AST_VECTOR_SIZE(&session->pending_media_state->read_callbacks); ++i) { - struct ast_sip_session_media_read_callback_state *callback_state = AST_VECTOR_GET_ADDR(&session->pending_media_state->read_callbacks, i); + struct ast_sip_session_media_read_callback_state *callback_state; + callback_state = AST_VECTOR_GET_ADDR(&session->pending_media_state->read_callbacks, i); ast_channel_internal_fd_set(session->channel, i + AST_EXTENDED_FDS, callback_state->fd); } From 7937d5b8b3f4c5ccac64e0646afb46448e1db63c Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 24 Aug 2017 09:35:45 -0400 Subject: [PATCH 1442/1578] res_smdi: Clean up memory leak Change-Id: I1e33290929e1aa7c5b9cb513f8254f2884974de8 --- res/res_smdi.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/res/res_smdi.c b/res/res_smdi.c index e2e5b17babf..7f9af5cd56e 100644 --- a/res/res_smdi.c +++ b/res/res_smdi.c @@ -608,13 +608,12 @@ static void *smdi_read(void *iface_p) ast_debug(1, "Read a 'D' ... it's an MD message.\n"); - if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) { + md_msg = ao2_alloc(sizeof(*md_msg), NULL); + if (!md_msg) { ao2_ref(iface, -1); return NULL; } - md_msg = ao2_alloc(sizeof(*md_msg), NULL); - /* read the message desk number */ for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) { md_msg->mesg_desk_num[i] = fgetc(iface->file); @@ -710,13 +709,12 @@ static void *smdi_read(void *iface_p) ast_debug(1, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n"); - if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) { + mwi_msg = ao2_alloc(sizeof(*mwi_msg), NULL); + if (!mwi_msg) { ao2_ref(iface, -1); return NULL; } - mwi_msg = ao2_alloc(sizeof(*mwi_msg), NULL); - /* discard the 'I' (from 'MWI') */ fgetc(iface->file); From b1097be13432dddd351c63d87525ed1ec115de86 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 23 Aug 2017 10:19:35 -0400 Subject: [PATCH 1443/1578] app_voicemail: Honor escape digits in "greeting only" mode ASTERISK-21241 #close Reported by: Eelco Brolman Patches: Patch uploaded by Eelco Brolman (License 6442) Change-Id: Icbe39b5c82a49b46cf1d168dc17766f3d84f54fe --- apps/app_voicemail.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 5f821285959..f1b8bd1e19b 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -6488,6 +6488,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ int ausemacro = 0; int ousemacro = 0; int ouseexten = 0; + int greeting_only = 0; char tmpdur[16]; char priority[16]; char origtime[16]; @@ -6547,6 +6548,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ ast_free(tmp); return res; } + + /* If maxmsg is zero, act as a "greetings only" voicemail: Exit successfully without recording */ + if (vmu->maxmsg == 0) { + greeting_only = 1; + ast_set_flag(options, OPT_SILENT); + } + /* Setup pre-file if appropriate */ if (strcmp(vmu->context, "default")) snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context); @@ -6671,12 +6679,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ ast_set_flag(options, OPT_SILENT); res = 0; } - /* If maxmsg is zero, act as a "greetings only" voicemail: Exit successfully without recording */ - if (vmu->maxmsg == 0) { - ast_debug(3, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n"); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS"); - goto leave_vm_out; - } if (!res && !ast_test_flag(options, OPT_SILENT)) { res = ast_stream_and_wait(chan, INTRO, ecodes); if (res == '#') { @@ -6732,6 +6734,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ return res; } + if (greeting_only) { + ast_debug(3, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n"); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS"); + res = 0; + goto leave_vm_out; + } + if (res < 0) { free_user(vmu); pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); From 02f95d290f51e0b81c76e63ec54df3c336262f4f Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 24 Aug 2017 10:42:24 -0400 Subject: [PATCH 1444/1578] app_queue: Evaluate realtime queues when running dialplan functions ASTERISK-19103 #close Reported by: Jim Van Meggelen Change-Id: I4bd32a9d1fcebb8ac56bff0e084d4f53e31b692b --- apps/app_queue.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index b139ef7b1ee..ef40a891cae 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -7628,12 +7628,10 @@ static int set_member_value(const char *queuename, const char *interface, int pr static int get_member_penalty(char *queuename, char *interface) { int foundqueue = 0, penalty; - struct call_queue *q, tmpq = { - .name = queuename, - }; + struct call_queue *q; struct member *mem; - if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { + if ((q = find_load_queue_rt_friendly(queuename))) { foundqueue = 1; ao2_lock(q); if ((mem = interface_exists(q, interface))) { @@ -8403,10 +8401,7 @@ static int queue_exec(struct ast_channel *chan, const char *data) static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { int res = -1; - struct call_queue *q, tmpq = { - .name = data, - }; - + struct call_queue *q; char interfacevar[256] = ""; float sl = 0; @@ -8415,7 +8410,7 @@ static int queue_function_var(struct ast_channel *chan, const char *cmd, char *d return -1; } - if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { + if ((q = find_load_queue_rt_friendly(data))) { ao2_lock(q); if (q->setqueuevar) { sl = 0; @@ -8813,9 +8808,7 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, const char /*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */ static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { - struct call_queue *q, tmpq = { - .name = data, - }; + struct call_queue *q; struct member *m; /* Ensure an otherwise empty list doesn't return garbage */ @@ -8826,7 +8819,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, const char * return -1; } - if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { + if ((q = find_load_queue_rt_friendly(data))) { int buflen = 0, count = 0; struct ao2_iterator mem_iter; From 33a648d4c694b8951db2b664ca8d8edb0cb9da26 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Mon, 21 Aug 2017 11:28:52 +0200 Subject: [PATCH 1445/1578] res/res_pjsip_session: allow SDP answer to be regenerated If an SDP answer hasn't been sent yet, it's legal to change it. This is required for PJSIP_DTMF_MODE to work correctly, and can also have use in the future for updating codecs too. ASTERISK-27209 #close Change-Id: Idbbfb7cb3f72fbd96c94d10d93540f69bd51e7a1 --- channels/pjsip/dialplan_functions.c | 5 +++- include/asterisk/res_pjsip_session.h | 17 ++++++++++++ res/res_pjsip_session.c | 40 ++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index c89d9ca2624..93875b35c1d 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -1241,10 +1241,13 @@ static int dtmf_mode_refresh_cb(void *obj) struct refresh_data *data = obj; if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) { - ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSER completion. Sending session refresh\n", ast_channel_name(data->session->channel)); + ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSWER completion. Sending session refresh\n", ast_channel_name(data->session->channel)); ast_sip_session_refresh(data->session, NULL, NULL, sip_session_response_cb, data->method, 1, NULL); + } else if (data->session->inv_session->state == PJSIP_INV_STATE_INCOMING) { + ast_debug(3, "Changing DTMF mode on channel %s during OFFER/ANSWER exchange. Updating SDP answer\n", ast_channel_name(data->session->channel)); + ast_sip_session_regenerate_answer(data->session, NULL); } return 0; diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 5f49c82371e..d5b6fa194e8 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -672,6 +672,23 @@ int ast_sip_session_refresh(struct ast_sip_session *session, int generate_new_sdp, struct ast_sip_session_media_state *media_state); +/*! + * \brief Regenerate SDP Answer + * + * This method is used when an SDP offer has been received but an SDP answer + * has not been sent yet. It requests that a new local SDP be created and + * set as the SDP answer. As with any outgoing request in res_pjsip_session, + * this will call into registered supplements in case they wish to add anything. + * + * \param session The session on which the answer will be updated + * \param on_sdp_creation Callback called when SDP is created + * \param generate_new_sdp Boolean to indicate if a new SDP should be created + * \retval 0 Successfully updated the SDP answer + * \retval -1 Failure to updated the SDP answer + */ +int ast_sip_session_regenerate_answer(struct ast_sip_session *session, + ast_sip_session_sdp_creation_cb on_sdp_creation); + /*! * \brief Send a SIP response * diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index b6b8a21ac36..f6b3b937a17 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1550,6 +1550,46 @@ int ast_sip_session_refresh(struct ast_sip_session *session, return 0; } +int ast_sip_session_regenerate_answer(struct ast_sip_session *session, + ast_sip_session_sdp_creation_cb on_sdp_creation) +{ + pjsip_inv_session *inv_session = session->inv_session; + pjmedia_sdp_session *new_answer = NULL; + const pjmedia_sdp_session *previous_offer = NULL; + + /* The SDP answer can only be regenerated if it is still pending to be sent */ + if (!inv_session->neg || (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER && + pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)) { + ast_log(LOG_WARNING, "Requested to regenerate local SDP answer for channel '%s' but negotiation in state '%s'\n", + ast_channel_name(session->channel), pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv_session->neg))); + return -1; + } + + pjmedia_sdp_neg_get_neg_remote(inv_session->neg, &previous_offer); + if (pjmedia_sdp_neg_get_state(inv_session->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) { + /* Transition the SDP negotiator back to when it received the remote offer */ + pjmedia_sdp_neg_negotiate(inv_session->pool, inv_session->neg, 0); + pjmedia_sdp_neg_set_remote_offer(inv_session->pool, inv_session->neg, previous_offer); + } + + new_answer = create_local_sdp(inv_session, session, previous_offer); + if (!new_answer) { + ast_log(LOG_WARNING, "Could not create a new local SDP answer for channel '%s'\n", + ast_channel_name(session->channel)); + return -1; + } + + if (on_sdp_creation) { + if (on_sdp_creation(session, new_answer)) { + return -1; + } + } + + pjsip_inv_set_sdp_answer(inv_session, new_answer); + + return 0; +} + void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata) { handle_outgoing_response(session, tdata); From 2ee644aacf88b1ccc00f234f503e12eb34003bdd Mon Sep 17 00:00:00 2001 From: Florian Floimair Date: Wed, 23 Aug 2017 17:01:09 +0200 Subject: [PATCH 1446/1578] alembic: Add dtls_fingerprint column in ps_endpoints table The ps_endpoints table was missing the dtls_fingerprint column introduced with commit adba2a8d7fd. ASTERISK-27168 #close Change-Id: I9cb5006f7f50718b5239919562773adabb334cfd --- ...dd_add_dtls_fingerprint_to_ps_endpoints.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/b83645976fdd_add_dtls_fingerprint_to_ps_endpoints.py diff --git a/contrib/ast-db-manage/config/versions/b83645976fdd_add_dtls_fingerprint_to_ps_endpoints.py b/contrib/ast-db-manage/config/versions/b83645976fdd_add_dtls_fingerprint_to_ps_endpoints.py new file mode 100644 index 00000000000..0efefa2fda3 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/b83645976fdd_add_dtls_fingerprint_to_ps_endpoints.py @@ -0,0 +1,23 @@ +"""add dtls_fingerprint to ps_endpoints + +Revision ID: b83645976fdd +Revises: f3d1c5d38b56 +Create Date: 2017-08-03 09:01:49.558111 + +""" + +# revision identifiers, used by Alembic. +revision = 'b83645976fdd' +down_revision = 'f3d1c5d38b56' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +SHA_HASH_VALUES = ['SHA-1', 'SHA-256'] + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('dtls_fingerprint', sa.Enum(*SHA_HASH_VALUES, name='sha_hash_values'))) + +def downgrade(): + op.drop_column('ps_endpoints', 'dtls_fingerprint') From 43670e471fecefb9fbd150b91cc1f69ec4ce2083 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 25 Aug 2017 13:20:16 -0400 Subject: [PATCH 1447/1578] app_record: Resolve some absolute vs. relative filename bugs If the Record() application is called with a relative filename that includes directories, we were not properly creating the intermediate directories and Record() would fail. Secondarily, updated the documentation for RECORDED_FILE to mention that it does not include a filename extension. Finally, rewrote the '%d' functionality to be a bit more straight forward and less noisy. ASTERISK-16777 #close Reported by: klaus3000 Change-Id: Ibc2640cba3a8c7f17d97b02f76b7608b1e7ffde2 --- apps/app_record.c | 113 ++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 45 deletions(-) diff --git a/apps/app_record.c b/apps/app_record.c index 0b85ff8a699..8c3a577ef86 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -38,6 +38,7 @@ #include "asterisk/channel.h" #include "asterisk/dsp.h" /* use dsp routines for silence detection */ #include "asterisk/format_cache.h" +#include "asterisk/paths.h" /*** DOCUMENTATION @@ -102,7 +103,7 @@ If the user hangs up during a recording, all data will be lost and the application will terminate. - Will be set to the final filename of the recording. + Will be set to the final filename of the recording, without an extension. This is the final status of the command @@ -131,10 +132,9 @@ enum { OPTION_STAR_TERMINATE = (1 << 4), OPTION_IGNORE_TERMINATE = (1 << 5), OPTION_KEEP = (1 << 6), - FLAG_HAS_PERCENT = (1 << 7), - OPTION_ANY_TERMINATE = (1 << 8), - OPTION_OPERATOR_EXIT = (1 << 9), - OPTION_NO_TRUNCATE = (1 << 10), + OPTION_ANY_TERMINATE = (1 << 7), + OPTION_OPERATOR_EXIT = (1 << 8), + OPTION_NO_TRUNCATE = (1 << 9), }; AST_APP_OPTIONS(app_opts,{ @@ -180,14 +180,47 @@ static int record_dtmf_response(struct ast_channel *chan, struct ast_flags *flag return 0; } +static int create_destination_directory(const char *path) +{ + int res; + char directory[PATH_MAX], *file_sep; + + if (!(file_sep = strrchr(path, '/'))) { + /* No directory to create */ + return 0; + } + + /* Overwrite temporarily */ + *file_sep = '\0'; + + /* Absolute path? */ + if (path[0] == '/') { + res = ast_mkdir(path, 0777); + *file_sep = '/'; + return res; + } + + /* Relative path */ + res = snprintf(directory, sizeof(directory), "%s/sounds/%s", + ast_config_AST_DATA_DIR, path); + + *file_sep = '/'; + + if (res >= sizeof(directory)) { + /* We truncated, so we fail */ + return -1; + } + + return ast_mkdir(directory, 0777); +} + static int record_exec(struct ast_channel *chan, const char *data) { int res = 0; - int count = 0; char *ext = NULL, *opts[0]; - char *parse, *dir, *file; + char *parse; int i = 0; - char tmp[256]; + char tmp[PATH_MAX]; struct ast_filestream *s = NULL; struct ast_frame *f = NULL; @@ -227,8 +260,6 @@ static int record_exec(struct ast_channel *chan, const char *data) ast_app_parse_options(app_opts, &flags, opts, args.options); if (!ast_strlen_zero(args.filename)) { - if (strstr(args.filename, "%d")) - ast_set_flag(&flags, FLAG_HAS_PERCENT); ext = strrchr(args.filename, '.'); /* to support filename with a . in the filename, not format */ if (!ext) ext = strchr(args.filename, ':'); @@ -266,38 +297,31 @@ static int record_exec(struct ast_channel *chan, const char *data) if (ast_test_flag(&flags, OPTION_IGNORE_TERMINATE)) terminator = '\0'; - /* done parsing */ - - /* these are to allow the use of the %d in the config file for a wild card of sort to - create a new file with the inputed name scheme */ - if (ast_test_flag(&flags, FLAG_HAS_PERCENT)) { - AST_DECLARE_APP_ARGS(fname, - AST_APP_ARG(piece)[100]; - ); - char *tmp2 = ast_strdupa(args.filename); - char countstring[15]; - int idx; + /* + If a '%d' is specified as part of the filename, we replace that token with + sequentially incrementing numbers until we find a unique filename. + */ + if (strchr(args.filename, '%')) { + size_t src, dst, count = 0; + size_t src_len = strlen(args.filename); + size_t dst_len = sizeof(tmp) - 1; - /* Separate each piece out by the format specifier */ - AST_NONSTANDARD_APP_ARGS(fname, tmp2, '%'); do { - int tmplen; - /* First piece has no leading percent, so it's copied verbatim */ - ast_copy_string(tmp, fname.piece[0], sizeof(tmp)); - tmplen = strlen(tmp); - for (idx = 1; idx < fname.argc; idx++) { - if (fname.piece[idx][0] == 'd') { - /* Substitute the count */ - snprintf(countstring, sizeof(countstring), "%d", count); - ast_copy_string(tmp + tmplen, countstring, sizeof(tmp) - tmplen); - tmplen += strlen(countstring); - } else if (tmplen + 2 < sizeof(tmp)) { - /* Unknown format specifier - just copy it verbatim */ - tmp[tmplen++] = '%'; - tmp[tmplen++] = fname.piece[idx][0]; + for (src = 0, dst = 0; src < src_len && dst < dst_len; src++) { + if (!strncmp(&args.filename[src], "%d", 2)) { + int s = snprintf(&tmp[dst], PATH_MAX - dst, "%zu", count); + if (s >= PATH_MAX - dst) { + /* We truncated, so we need to bail */ + ast_log(LOG_WARNING, "Failed to create unique filename from template: %s\n", args.filename); + pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + return -1; + } + dst += s; + src++; + } else { + tmp[dst] = args.filename[src]; + tmp[++dst] = '\0'; } - /* Copy the remaining portion of the piece */ - ast_copy_string(tmp + tmplen, &(fname.piece[idx][1]), sizeof(tmp) - tmplen); } count++; } while (ast_fileexists(tmp, ext, ast_channel_language(chan)) > 0); @@ -305,7 +329,6 @@ static int record_exec(struct ast_channel *chan, const char *data) ast_copy_string(tmp, args.filename, sizeof(tmp)); pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); - /* end of routine mentioned */ if (ast_channel_state(chan) != AST_STATE_UP) { if (ast_test_flag(&flags, OPTION_SKIP)) { @@ -354,11 +377,11 @@ static int record_exec(struct ast_channel *chan, const char *data) ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); } - /* Create the directory if it does not exist. */ - dir = ast_strdupa(tmp); - if ((file = strrchr(dir, '/'))) - *file++ = '\0'; - ast_mkdir (dir, 0777); + if (create_destination_directory(tmp)) { + ast_log(LOG_WARNING, "Could not create directory for file %s\n", args.filename); + pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + goto out; + } ioflags = ast_test_flag(&flags, OPTION_APPEND) ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; s = ast_writefile(tmp, ext, NULL, ioflags, 0, AST_FILE_MODE); From da13cdb9e7e402633240c32ca24193952c4b1867 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 25 Aug 2017 14:44:35 -0400 Subject: [PATCH 1448/1578] voicemail: Fix various abuses of mkstemp mkstemp() returns a unique filename, but appending an extension to that filename does not guarantee uniqueness. Instead, use mkdtemp() and we can put whatever extension we want on the files that we create inside the directory. In the case of app_minivm, we also now properly clean up any temporary files that we create. ASTERISK-20858 #close Reported by: Walter Doekes Change-Id: I30ad04f0e115f0b11693ff678ba5184d8b938e43 --- apps/app_minivm.c | 121 +++++++++++++++++++++++++------------------ apps/app_voicemail.c | 94 +++++++++++++++++++++++---------- 2 files changed, 137 insertions(+), 78 deletions(-) diff --git a/apps/app_minivm.c b/apps/app_minivm.c index 9359f82f3bd..15449ad4eac 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -1232,6 +1232,8 @@ static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const cha * \brief Send voicemail with audio file as an attachment */ static int sendmail(struct minivm_template *template, struct minivm_account *vmu, char *cidnum, char *cidname, const char *filename, char *format, int duration, int attach_user_voicemail, enum mvm_messagetype type, const char *counter) { + RAII_VAR(struct ast_str *, str1, ast_str_create(16), ast_free); + RAII_VAR(struct ast_str *, str2, ast_str_create(16), ast_free); FILE *p = NULL; int pfd; char email[256] = ""; @@ -1241,20 +1243,18 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu char fname[PATH_MAX]; char dur[PATH_MAX]; char tmp[80] = "/tmp/astmail-XXXXXX"; - char tmp2[PATH_MAX]; - char newtmp[PATH_MAX]; /* Only used with volgain */ + char mail_cmd_buffer[PATH_MAX]; + char sox_gain_tmpdir[PATH_MAX] = ""; /* Only used with volgain */ + char *file_to_delete = NULL, *dir_to_delete = NULL; struct timeval now; struct ast_tm tm; struct minivm_zone *the_zone = NULL; - struct ast_channel *ast; - char *finalfilename = ""; - struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16); + struct ast_channel *chan = NULL; char *fromaddress; char *fromemail; + int res; if (!str1 || !str2) { - ast_free(str1); - ast_free(str2); return -1; } @@ -1269,9 +1269,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu if (ast_strlen_zero(email)) { ast_log(LOG_WARNING, "No address to send message to.\n"); - ast_free(str1); - ast_free(str2); - return -1; + return -1; } ast_debug(3, "Sending mail to %s@%s - Using template %s\n", vmu->username, vmu->domain, template->name); @@ -1279,35 +1277,30 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu if (!strcmp(format, "wav49")) format = "WAV"; - /* If we have a gain option, process it now with sox */ if (type == MVM_MESSAGE_EMAIL && (vmu->volgain < -.001 || vmu->volgain > .001) ) { - char tmpcmd[PATH_MAX]; - int tmpfd; - - ast_copy_string(newtmp, "/tmp/XXXXXX", sizeof(newtmp)); - ast_debug(3, "newtmp: %s\n", newtmp); - tmpfd = mkstemp(newtmp); - if (tmpfd < 0) { - ast_log(LOG_WARNING, "Failed to create temporary file for volgain: %d\n", errno); - ast_free(str1); - ast_free(str2); + char sox_gain_cmd[PATH_MAX]; + + ast_copy_string(sox_gain_tmpdir, "/tmp/minivm-gain-XXXXXX", sizeof(sox_gain_tmpdir)); + ast_debug(3, "sox_gain_tmpdir: %s\n", sox_gain_tmpdir); + if (!mkdtemp(sox_gain_tmpdir)) { + ast_log(LOG_WARNING, "Failed to create temporary directory for volgain: %d\n", errno); return -1; } - snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format); - ast_safe_system(tmpcmd); - close(tmpfd); - finalfilename = newtmp; + snprintf(fname, sizeof(fname), "%s/output.%s", sox_gain_tmpdir, format); + snprintf(sox_gain_cmd, sizeof(sox_gain_cmd), "sox -v %.4f %s.%s %s", vmu->volgain, filename, format, fname); + ast_safe_system(sox_gain_cmd); ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username); + + /* Mark some things for deletion */ + file_to_delete = fname; + dir_to_delete = sox_gain_tmpdir; } else { - finalfilename = ast_strdupa(filename); + snprintf(fname, sizeof(fname), "%s.%s", filename, format); } - /* Create file name */ - snprintf(fname, sizeof(fname), "%s.%s", finalfilename, format); - if (template->attachment) - ast_debug(1, "Attaching file '%s', format '%s', uservm is '%d'\n", finalfilename, format, attach_user_voicemail); + ast_debug(1, "Attaching file '%s', format '%s', uservm is '%d'\n", fname, format, attach_user_voicemail); /* Make a temporary file instead of piping directly to sendmail, in case the mail command hangs */ @@ -1322,16 +1315,12 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu } if (!p) { ast_log(LOG_WARNING, "Unable to open temporary file '%s'\n", tmp); - ast_free(str1); - ast_free(str2); - return -1; + goto out; } /* Allocate channel used for chanvar substitution */ - ast = ast_dummy_channel_alloc(); - if (!ast) { - ast_free(str1); - ast_free(str2); - return -1; + chan = ast_dummy_channel_alloc(); + if (!chan) { + goto out; } snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60); @@ -1359,9 +1348,8 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu /* Set date format for voicemail mail */ ast_strftime(date, sizeof(date), template->dateformat, &tm); - /* Populate channel with channel variables for substitution */ - prep_email_sub_vars(ast, vmu, cidnum, cidname, dur, date, counter); + prep_email_sub_vars(chan, vmu, cidnum, cidname, dur, date, counter); /* Find email address to use */ /* If there's a server e-mail address in the account, use that, othterwise template */ @@ -1386,7 +1374,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu fprintf(p, "From: Asterisk PBX <%s>\n", who); } else { ast_debug(4, "Fromaddress template: %s\n", fromaddress); - ast_str_substitute_variables(&str1, 0, ast, fromaddress); + ast_str_substitute_variables(&str1, 0, chan, fromaddress); if (check_mime(ast_str_buffer(str1))) { int first_line = 1; char *ptr; @@ -1429,7 +1417,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu } if (!ast_strlen_zero(template->subject)) { - ast_str_substitute_variables(&str1, 0, ast, template->subject); + ast_str_substitute_variables(&str1, 0, chan, template->subject); if (check_mime(ast_str_buffer(str1))) { int first_line = 1; char *ptr; @@ -1462,7 +1450,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu fprintf(p, "--%s\n", bound); fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", template->charset); if (!ast_strlen_zero(template->body)) { - ast_str_substitute_variables(&str1, 0, ast, template->body); + ast_str_substitute_variables(&str1, 0, chan, template->body); ast_debug(3, "Message now: %s\n-----\n", ast_str_buffer(str1)); fprintf(p, "%s\n", ast_str_buffer(str1)); } else { @@ -1489,14 +1477,45 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu fprintf(p, "\n\n--%s--\n.\n", bound); } fclose(p); - snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", global_mailcmd, tmp, tmp); - ast_safe_system(tmp2); - ast_debug(1, "Sent message to %s with command '%s' - %s\n", vmu->email, global_mailcmd, template->attachment ? "(media attachment)" : ""); - ast_debug(3, "Actual command used: %s\n", tmp2); - ast = ast_channel_unref(ast); - ast_free(str1); - ast_free(str2); - return 0; + + chan = ast_channel_unref(chan); + + if (file_to_delete && dir_to_delete) { + /* We can't delete these files ourselves because the mail command will execute in + the background and we'll end up deleting them out from under it. */ + res = snprintf(mail_cmd_buffer, sizeof(mail_cmd_buffer), + "( %s < %s ; rm -f %s %s ; rmdir %s ) &", + global_mailcmd, tmp, tmp, file_to_delete, dir_to_delete); + } else { + res = snprintf(mail_cmd_buffer, sizeof(mail_cmd_buffer), + "( %s < %s ; rm -f %s ) &", + global_mailcmd, tmp, tmp); + } + + if (res < sizeof(mail_cmd_buffer)) { + file_to_delete = dir_to_delete = NULL; + } else { + ast_log(LOG_ERROR, "Could not send message, command line too long\n"); + res = -1; + goto out; + } + + ast_safe_system(mail_cmd_buffer); + ast_debug(1, "Sent message to %s with command '%s'%s\n", vmu->email, global_mailcmd, template->attachment ? " - (media attachment)" : ""); + ast_debug(3, "Actual command used: %s\n", mail_cmd_buffer); + + res = 0; + +out: + if (file_to_delete) { + unlink(file_to_delete); + } + + if (dir_to_delete) { + rmdir(dir_to_delete); + } + + return res; } /*!\internal diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index f1b8bd1e19b..a9b8fe36209 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -5370,55 +5370,95 @@ static void make_email_file(FILE *p, static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum) { - char tmpdir[256], newtmp[256]; - char fname[256]; - char tmpcmd[256]; - int tmpfd = -1; - int soxstatus = 0; + char fname[PATH_MAX] = ""; + char *file_to_delete = NULL, *dir_to_delete = NULL; + int res; /* Eww. We want formats to tell us their own MIME type */ - char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-"; + char *mime_type = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-"; + + /* This 'while' loop will only execute once. We use it so that we can 'break' */ + while (vmu->volgain < -.001 || vmu->volgain > .001) { + char tmpdir[PATH_MAX]; + char sox_gain_tmpdir[PATH_MAX]; - if (vmu->volgain < -.001 || vmu->volgain > .001) { create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp"); - snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir); - tmpfd = mkstemp(newtmp); - chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask); - ast_debug(3, "newtmp: %s\n", newtmp); - if (tmpfd > -1) { - snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format); - if ((soxstatus = ast_safe_system(tmpcmd)) == 0) { - attach = newtmp; - ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox); + + res = snprintf(sox_gain_tmpdir, sizeof(sox_gain_tmpdir), "%s/vm-gain-XXXXXX", tmpdir); + if (res >= sizeof(sox_gain_tmpdir)) { + ast_log(LOG_ERROR, "Failed to create temporary directory path %s: Out of buffer space\n", tmpdir); + break; + } + + if (mkdtemp(sox_gain_tmpdir)) { + int soxstatus = 0; + char sox_gain_cmd[PATH_MAX]; + + ast_debug(3, "sox_gain_tmpdir: %s\n", sox_gain_tmpdir); + + /* Save for later */ + dir_to_delete = sox_gain_tmpdir; + + res = snprintf(fname, sizeof(fname), "%s/output.%s", sox_gain_tmpdir, format); + if (res >= sizeof(fname)) { + ast_log(LOG_ERROR, "Failed to create filename buffer for %s/output.%s: Too long\n", sox_gain_tmpdir, format); + break; + } + + res = snprintf(sox_gain_cmd, sizeof(sox_gain_cmd), "sox -v %.4f %s.%s %s", + vmu->volgain, attach, format, fname); + if (res >= sizeof(sox_gain_cmd)) { + ast_log(LOG_ERROR, "Failed to generate sox command, out of buffer space\n"); + break; + } + + soxstatus = ast_safe_system(sox_gain_cmd); + if (!soxstatus) { + /* Save for later */ + file_to_delete = fname; + ast_debug(3, "VOLGAIN: Stored at: %s - Level: %.4f - Mailbox: %s\n", fname, vmu->volgain, mailbox); } else { - ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format, - soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing"); + ast_log(LOG_WARNING, "Sox failed to re-encode %s: %s (have you installed support for all sox file formats?)\n", + fname, + soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing"); ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n"); } } + + break; + } + + if (!file_to_delete) { + res = snprintf(fname, sizeof(fname), "%s.%s", attach, format); + if (res >= sizeof(fname)) { + ast_log(LOG_ERROR, "Failed to create filename buffer for %s.%s: Too long\n", attach, format); + return -1; + } } + fprintf(p, "--%s" ENDL, bound); if (msgnum > -1) - fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename); + fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, mime_type, format, filename); else - fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format); + fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, mime_type, format, greeting_attachment, format); fprintf(p, "Content-Transfer-Encoding: base64" ENDL); fprintf(p, "Content-Description: Voicemail sound attachment." ENDL); if (msgnum > -1) fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename); else fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format); - snprintf(fname, sizeof(fname), "%s.%s", attach, format); base_encode(fname, p); if (last) fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound); - if (tmpfd > -1) { - if (soxstatus == 0) { - unlink(fname); - } - close(tmpfd); - unlink(newtmp); + + if (file_to_delete) { + unlink(file_to_delete); } + + if (dir_to_delete) { + rmdir(dir_to_delete); + } + return 0; } From 9a9589e8e11696a8afdbafbb16c687a4d295c23b Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 24 Aug 2017 13:45:08 -0300 Subject: [PATCH 1449/1578] core: Reduce video update queueing. A video update frame is used to indicate that a channel with video negotiated should provide a full frame so the decoder decoding the stream is able to do so. In situations where a queue is used to store frames it makes no sense for the queue to contain multiple video update frames. One is sufficient to have a full frame be sent. ASTERISK-27222 Change-Id: Id3f40a6f51b740ae4704003a1800185c0c658ee7 --- main/autoservice.c | 12 ++++++++++++ main/core_unreal.c | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/main/autoservice.c b/main/autoservice.c index d1a0156ab46..cd7388b7dda 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -58,6 +58,7 @@ struct asent { * it gets stopped for the last time. */ unsigned int use_count; unsigned int orig_end_dtmf_flag:1; + unsigned int video_update:1; unsigned int ignore_frame_types; /*! Frames go on at the head of deferred_frames, so we have the frames * from newest to oldest. As we put them at the head of the readq, we'll @@ -161,6 +162,17 @@ static void *autoservice_run(void *ign) AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); } } else { + if (defer_frame->frametype == AST_FRAME_CONTROL && + defer_frame->subclass.integer == AST_CONTROL_VIDUPDATE) { + + /* If a video update is already queued don't needlessly queue another */ + if (ents[i]->video_update) { + ast_frfree(defer_frame); + break; + } + + ents[i]->video_update = 1; + } if ((dup_f = ast_frisolate(defer_frame))) { AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list); } diff --git a/main/core_unreal.c b/main/core_unreal.c index 3db6a4dbdd8..763be4f0ca3 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -330,7 +330,8 @@ int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f) if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_AUDIO)) { return 0; } - } else if (f->frametype == AST_FRAME_VIDEO) { + } else if (f->frametype == AST_FRAME_VIDEO || + (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_VIDUPDATE)) { if (!ast_channel_get_default_stream(ast, AST_MEDIA_TYPE_VIDEO)) { return 0; } From 06cc5ae9ff26b87d2d18abaa4c0871874f410a2e Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 29 Aug 2017 10:26:17 -0400 Subject: [PATCH 1450/1578] confbridge: Handle user hangup during name recording This prevents orphaned CBAnn channels from getting stuck in the bridge. ASTERISK-26994 #close Reported by: James Terhune Change-Id: I5e43e832a9507ec3f2c59752cd900b41dab80457 --- apps/app_confbridge.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index b2d612df3b5..d218d0f2eeb 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -2326,7 +2326,11 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) if (!quiet && (ast_test_flag(&user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE) || (ast_test_flag(&user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW)))) { - conf_rec_name(&user, args.conf_name); + if (conf_rec_name(&user, args.conf_name)) { + pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED"); + res = -1; /* Hangup during name recording */ + goto confbridge_cleanup; + } } /* menu name */ From 4650fc477a88e84e9b3845dd60eeb43d64b30a3a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 29 Aug 2017 14:22:15 -0500 Subject: [PATCH 1451/1578] bridge_native_rtp.c: Fixup native_rtp_framehook() * Fix framehook to test frame type for control frame. * Made framehook exit early if frame type is not a control frame. * Eliminated RAII_VAR in framehook. * Use switch instead of else-if ladder for control frame handling. Change-Id: Ia555fc3600bd85470e3c0141147dbe3ad07c1d18 --- bridges/bridge_native_rtp.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 02b27e1234d..a46b4202771 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -539,10 +539,12 @@ static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) { - RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup); + struct ast_bridge *bridge; struct native_rtp_framehook_data *native_data = data; - if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) { + if (!f + || f->frametype != AST_FRAME_CONTROL + || event != AST_FRAMEHOOK_EVENT_WRITE) { return f; } @@ -561,14 +563,20 @@ static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, ast_channel_unlock(chan); ast_bridge_lock(bridge); if (!native_data->detached) { - if (f->subclass.integer == AST_CONTROL_HOLD) { + switch (f->subclass.integer) { + case AST_CONTROL_HOLD: native_rtp_bridge_stop(bridge, chan); - } else if ((f->subclass.integer == AST_CONTROL_UNHOLD) || - (f->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) { + break; + case AST_CONTROL_UNHOLD: + case AST_CONTROL_UPDATE_RTP_PEER: native_rtp_bridge_start(bridge, chan); + break; + default: + break; } } ast_bridge_unlock(bridge); + ao2_ref(bridge, -1); ast_channel_lock(chan); } From 71be8d5bbed8547072a53f2bb16404010588e95e Mon Sep 17 00:00:00 2001 From: Andre Nazario Date: Fri, 25 Aug 2017 23:06:10 -0300 Subject: [PATCH 1452/1578] chan_pjsip: Add tag info in CHANNEL function Create local_tag and remote_tag in CHANNEL info to get tag from From and To headers of a SIP dialog. ASTERISK-27220 Change-Id: I59b16c4b928896fcbde02ad88f0e98922b15d524 --- channels/pjsip/dialplan_functions.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 93875b35c1d..861edf72d36 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -393,9 +393,15 @@ The local URI. + + Tag in From header + The remote URI. + + Tag in To header + The current state of any T.38 fax on this channel. @@ -690,10 +696,18 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, buf, buflen); buf_copy = ast_strdupa(buf); ast_escape_quoted(buf_copy, buf, buflen); + } else if (!strcmp(type, "local_tag")) { + ast_copy_pj_str(buf, &dlg->local.info->tag, buflen); + buf_copy = ast_strdupa(buf); + ast_escape_quoted(buf_copy, buf, buflen); } else if (!strcmp(type, "remote_uri")) { pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->remote.info->uri, buf, buflen); buf_copy = ast_strdupa(buf); ast_escape_quoted(buf_copy, buf, buflen); + } else if (!strcmp(type, "remote_tag")) { + ast_copy_pj_str(buf, &dlg->remote.info->tag, buflen); + buf_copy = ast_strdupa(buf); + ast_escape_quoted(buf_copy, buf, buflen); } else if (!strcmp(type, "t38state")) { ast_copy_string(buf, t38state_to_string[channel->session->t38state], buflen); } else if (!strcmp(type, "local_addr")) { From 5ba82cedc6675e1f5f0c3e1f2e9bdda3b486730a Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Wed, 30 Aug 2017 12:28:58 +0000 Subject: [PATCH 1453/1578] res_rtp_asterisk: Allow remote SSRC to change on an RTP instance. When SDP renegotiation occurs it is possible for an RTP instance to be reused for a new stream, resulting in the remote SSRC changing if it is part of a bundle group. This change allows this and updates its mapping in the current bundle group. ASTERISK-27231 Change-Id: I6e3703974f236bc024c5dbe9bd43adae0c6fb490 --- res/res_rtp_asterisk.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 0f4f6abdafc..ab803842209 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -6173,10 +6173,35 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - if (rtp->themssrc) { + if (rtp->themssrc == ssrc) { return; } + /* If this is bundled we need to update the SSRC mapping */ + if (rtp->bundled) { + struct ast_rtp *bundled_rtp; + int index; + + ao2_unlock(instance); + + /* The child lock can't be held while accessing the parent */ + ao2_lock(rtp->bundled); + bundled_rtp = ast_rtp_instance_get_data(rtp->bundled); + + for (index = 0; index < AST_VECTOR_SIZE(&bundled_rtp->ssrc_mapping); ++index) { + struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&bundled_rtp->ssrc_mapping, index); + + if (mapping->ssrc == rtp->themssrc) { + mapping->ssrc = ssrc; + break; + } + } + + ao2_unlock(rtp->bundled); + + ao2_lock(instance); + } + rtp->themssrc = ssrc; } From 7f2a60fb38ebb5343fcc12c79323991035187a94 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 22 May 2017 15:36:38 +0000 Subject: [PATCH 1454/1578] res_rtp_asterisk: Only learn a new source in learn state. This change moves the logic which learns a new source address for RTP so it only occurs in the learning state. The learning state is entered on initial allocation of RTP or if we are told that the remote address for the media has changed. While in the learning state if we continue to receive media from the original source we restart the learning process. It is only once we receive a sufficient number of RTP packets from the new source that we will switch to it. Once this is done the closed state is entered where all packets that do not originate from the expected source are dropped. The learning process has also been improved to take into account the time between received packets so a flood of them while in the learning state does not cause media to be switched. Finally RTCP now drops packets which are not for the learned SSRC if strict RTP is enabled. ASTERISK-27013 Change-Id: I56a96e993700906355e79bc880ad9d4ad3ab129c --- res/res_rtp_asterisk.c | 129 +++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 58 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 0f4f6abdafc..d976ed250a0 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -219,8 +219,9 @@ static AST_RWLIST_HEAD_STATIC(host_candidates, ast_ice_host_candidate); /*! \brief RTP learning mode tracking information */ struct rtp_learning_info { - int max_seq; /*!< The highest sequence number received */ - int packets; /*!< The number of remaining packets before the source is accepted */ + int max_seq; /*!< The highest sequence number received */ + int packets; /*!< The number of remaining packets before the source is accepted */ + struct timeval received; /*!< The time of the last received packet */ }; #ifdef HAVE_OPENSSL_SRTP @@ -328,7 +329,6 @@ struct ast_rtp { * but these are in place to keep learning mode sequence values sealed from their normal counterparts. */ struct rtp_learning_info rtp_source_learn; /* Learning mode track for the expected RTP source */ - struct rtp_learning_info alt_source_learn; /* Learning mode tracking for a new RTP source after one has been chosen */ struct rtp_red *red; @@ -2823,6 +2823,7 @@ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq) { info->max_seq = seq - 1; info->packets = learning_min_sequential; + memset(&info->received, 0, sizeof(info->received)); } /*! @@ -2837,6 +2838,13 @@ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq) */ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq) { + if (!ast_tvzero(info->received) && ast_tvdiff_ms(ast_tvnow(), info->received) < 5) { + /* During the probation period the minimum amount of media we'll accept is + * 10ms so give a reasonable 5ms buffer just in case we get it sporadically. + */ + return 1; + } + if (seq == info->max_seq + 1) { /* packet is in sequence */ info->packets--; @@ -2845,6 +2853,7 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t info->packets = learning_min_sequential - 1; } info->max_seq = seq; + info->received = ast_tvnow(); return (info->packets == 0); } @@ -3110,7 +3119,6 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_ rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); if (strictrtp) { rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); - rtp_learning_seq_init(&rtp->alt_source_learn, (uint16_t)rtp->seqno); } /* Create a new socket for us to listen on and use */ @@ -4775,17 +4783,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c packetwords = size / 4; - if (ast_rtp_instance_get_prop(transport, AST_RTP_PROPERTY_NAT)) { - /* Send to whoever sent to us */ - if (ast_sockaddr_cmp(&transport_rtp->rtcp->them, addr)) { - ast_sockaddr_copy(&transport_rtp->rtcp->them, addr); - if (rtpdebug) { - ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", - ast_sockaddr_stringify(&transport_rtp->rtcp->them)); - } - } - } - ast_debug(1, "Got RTCP report of %zu bytes\n", size); while (position < packetwords) { @@ -4841,6 +4838,25 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c rtp = transport_rtp; } + if ((rtp->strict_rtp_state != STRICT_RTP_OPEN) && (rtcp_report->ssrc != rtp->themssrc)) { + /* Skip over this RTCP record as it does not contain the correct SSRC */ + position += (length + 1); + ast_debug(1, "%p -- Received RTCP report from %s, dropping due to strict RTP protection. Received SSRC '%u' but expected '%u'\n", + rtp, ast_sockaddr_stringify(addr), rtcp_report->ssrc, rtp->themssrc); + continue; + } + + if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { + /* Send to whoever sent to us */ + if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) { + ast_sockaddr_copy(&rtp->rtcp->them, addr); + if (rtpdebug) { + ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", + ast_sockaddr_stringify(&rtp->rtcp->them)); + } + } + } + i += 2; /* Advance past header and ssrc */ switch (pt) { case RTCP_PT_SR: @@ -5297,39 +5313,54 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc return &ast_null_frame; } - /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */ - if (rtp->strict_rtp_state == STRICT_RTP_LEARN) { - ast_debug(1, "%p -- Probation learning mode pass with source address %s\n", rtp, ast_sockaddr_stringify(&addr)); - /* For now, we always copy the address. */ - ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); - - /* Send the rtp and the seqno from header to rtp_learning_rtp_seq_update to see whether we can exit or not*/ - if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) { - ast_debug(1, "%p -- Probation at seq %d with %d to go; discarding frame\n", - rtp, rtp->rtp_source_learn.max_seq, rtp->rtp_source_learn.packets); - return &ast_null_frame; - } + /* If the version is not what we expected by this point then just drop the packet */ + if (version != 2) { + return &ast_null_frame; + } - ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr)); - rtp->strict_rtp_state = STRICT_RTP_CLOSED; + /* We use the SSRC to determine what RTP instance this packet is actually for */ + ssrc = ntohl(rtpheader[2]); + + /* Determine the appropriate instance for this */ + child = rtp_find_instance_by_ssrc(instance, rtp, ssrc); + if (child != instance) { + /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order + * is always parent->child or that the child lock is not held when acquiring the parent lock. + */ + ao2_lock(child); + instance = child; + rtp = ast_rtp_instance_get_data(instance); + } else { + /* The child is the parent! We don't need to unlock it. */ + child = NULL; } - if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) { + + /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */ + if (rtp->strict_rtp_state == STRICT_RTP_LEARN) { if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { - /* Always reset the alternate learning source */ - rtp_learning_seq_init(&rtp->alt_source_learn, seqno); + /* We are learning a new address but have received traffic from the existing address, + * accept it but reset the current learning for the new source so it only takes over + * once sufficient traffic has been received. */ + rtp_learning_seq_init(&rtp->rtp_source_learn, seqno); } else { /* Start trying to learn from the new address. If we pass a probationary period with * it, that means we've stopped getting RTP from the original source and we should * switch to it. */ - if (rtp_learning_rtp_seq_update(&rtp->alt_source_learn, seqno)) { + if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) { ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n", - rtp, ast_sockaddr_stringify(&addr), rtp->alt_source_learn.packets); + rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets); return &ast_null_frame; } - ast_verb(4, "%p -- Switching RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr)); ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); + + ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr)); + rtp->strict_rtp_state = STRICT_RTP_CLOSED; } + } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED && ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { + ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n", + rtp, ast_sockaddr_stringify(&addr)); + return &ast_null_frame; } /* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */ @@ -5350,28 +5381,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } } - /* If the version is not what we expected by this point then just drop the packet */ - if (version != 2) { - return &ast_null_frame; - } - - /* We use the SSRC to determine what RTP instance this packet is actually for */ - ssrc = ntohl(rtpheader[2]); - - /* Determine the appropriate instance for this */ - child = rtp_find_instance_by_ssrc(instance, rtp, ssrc); - if (child != instance) { - /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order - * is always parent->child or that the child lock is not held when acquiring the parent lock. - */ - ao2_lock(child); - instance = child; - rtp = ast_rtp_instance_get_data(instance); - } else { - /* The child is the parent! We don't need to unlock it. */ - child = NULL; - } - /* If we are currently sending DTMF to the remote party send a continuation packet */ if (rtp->sending_digit) { ast_rtp_dtmf_continuation(instance); @@ -5883,7 +5892,11 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct rtp->rxseqno = 0; - if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN) { + if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN && !ast_sockaddr_isnull(addr) && + ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) { + /* We only need to learn a new strict source address if we've been told the source is + * changing to something different. + */ rtp->strict_rtp_state = STRICT_RTP_LEARN; rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno); } From 1bf3dfffd7f98f7259c04e3276c2f9ef1704eba7 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 1 Jul 2017 20:24:27 -0400 Subject: [PATCH 1455/1578] AST-2017-006: Fix app_minivm application MinivmNotify command injection An admin can configure app_minivm with an externnotify program to be run when a voicemail is received. The app_minivm application MinivmNotify uses ast_safe_system() for this purpose which is vulnerable to command injection since the Caller-ID name and number values given to externnotify can come from an external untrusted source. * Add ast_safe_execvp() function. This gives modules the ability to run external commands with greater safety compared to ast_safe_system(). Specifically when some parameters are filled by untrusted sources the new function does not allow malicious input to break argument encoding. This may be of particular concern where CALLERID(name) or CALLERID(num) may be used as a parameter to a script run by ast_safe_system() which could potentially allow arbitrary command execution. * Changed app_minivm.c:run_externnotify() to use the new ast_safe_execvp() instead of ast_safe_system() to avoid command injection. * Document code injection potential from untrusted data sources for other shell commands that are under user control. ASTERISK-27103 Change-Id: I7552472247a84cde24e1358aaf64af160107aef1 --- README-SERIOUSLY.bestpractices.txt | 7 +++ apps/app_minivm.c | 36 ++++++++---- apps/app_mixmonitor.c | 15 +++++ apps/app_system.c | 10 ++++ configs/samples/minivm.conf.sample | 2 +- funcs/func_shell.c | 5 ++ include/asterisk/app.h | 31 +++++++++- main/asterisk.c | 91 +++++++++++++++++++++++++----- res/res_monitor.c | 13 ++++- 9 files changed, 179 insertions(+), 31 deletions(-) diff --git a/README-SERIOUSLY.bestpractices.txt b/README-SERIOUSLY.bestpractices.txt index b6b418d9fae..0d3e670cf24 100644 --- a/README-SERIOUSLY.bestpractices.txt +++ b/README-SERIOUSLY.bestpractices.txt @@ -94,6 +94,13 @@ your ITSP in a place where you didn't expect to allow it. There are a couple of ways in which you can mitigate this impact: stricter pattern matching, or using the FILTER() dialplan function. +The CALLERID(num) and CALLERID(name) values are other commonly used values that +are sources of data potentially supplied by outside sources. If you use these +values as parameters to the System(), MixMonitor(), or Monitor() applications +or the SHELL() dialplan function, you can allow injection of arbitrary operating +system command execution. The FILTER() dialplan function is available to remove +dangerous characters from untrusted strings to block the command injection. + Strict Pattern Matching ----------------------- diff --git a/apps/app_minivm.c b/apps/app_minivm.c index 15449ad4eac..0d7a5f4077f 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -1774,21 +1774,35 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re /*! \brief Run external notification for voicemail message */ static void run_externnotify(struct ast_channel *chan, struct minivm_account *vmu) { - char arguments[BUFSIZ]; + char fquser[AST_MAX_CONTEXT * 2]; + char *argv[5] = { NULL }; + struct ast_party_caller *caller; + char *cid; + int idx; - if (ast_strlen_zero(vmu->externnotify) && ast_strlen_zero(global_externnotify)) + if (ast_strlen_zero(vmu->externnotify) && ast_strlen_zero(global_externnotify)) { return; + } + + snprintf(fquser, sizeof(fquser), "%s@%s", vmu->username, vmu->domain); - snprintf(arguments, sizeof(arguments), "%s %s@%s %s %s&", - ast_strlen_zero(vmu->externnotify) ? global_externnotify : vmu->externnotify, - vmu->username, vmu->domain, - (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) - ? ast_channel_caller(chan)->id.name.str : "", - (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) - ? ast_channel_caller(chan)->id.number.str : ""); + caller = ast_channel_caller(chan); + idx = 0; + argv[idx++] = ast_strlen_zero(vmu->externnotify) ? global_externnotify : vmu->externnotify; + argv[idx++] = fquser; + cid = S_COR(caller->id.name.valid, caller->id.name.str, NULL); + if (cid) { + argv[idx++] = cid; + } + cid = S_COR(caller->id.number.valid, caller->id.number.str, NULL); + if (cid) { + argv[idx++] = cid; + } + argv[idx] = NULL; - ast_debug(1, "Executing: %s\n", arguments); - ast_safe_system(arguments); + ast_debug(1, "Executing: %s %s %s %s\n", + argv[0], argv[1], argv[2] ?: "", argv[3] ?: ""); + ast_safe_execvp(1, argv[0], argv); } /*!\internal diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 3258b301fa0..ac45642052a 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -136,6 +136,11 @@ Will be executed when the recording is over. Any strings matching ^{X} will be unescaped to X. All variables will be evaluated at the time MixMonitor is called. + Do not use untrusted strings such as CALLERID(num) + or CALLERID(name) as part of the command parameters. You + risk a command injection attack executing arbitrary commands if the untrusted + strings aren't filtered to remove dangerous characters. See function + FILTER(). @@ -148,6 +153,11 @@ Will contain the filename used to record. + Do not use untrusted strings such as CALLERID(num) + or CALLERID(name) as part of ANY of the application's + parameters. You risk a command injection attack executing arbitrary commands + if the untrusted strings aren't filtered to remove dangerous characters. See + function FILTER(). Monitor @@ -222,6 +232,11 @@ Will be executed when the recording is over. Any strings matching ^{X} will be unescaped to X. All variables will be evaluated at the time MixMonitor is called. + Do not use untrusted strings such as CALLERID(num) + or CALLERID(name) as part of the command parameters. You + risk a command injection attack executing arbitrary commands if the untrusted + strings aren't filtered to remove dangerous characters. See function + FILTER(). diff --git a/apps/app_system.c b/apps/app_system.c index 09179f7f707..64d529798c1 100644 --- a/apps/app_system.c +++ b/apps/app_system.c @@ -46,6 +46,11 @@ Command to execute + Do not use untrusted strings such as CALLERID(num) + or CALLERID(name) as part of the command parameters. You + risk a command injection attack executing arbitrary commands if the untrusted + strings aren't filtered to remove dangerous characters. See function + FILTER(). @@ -71,6 +76,11 @@ Command to execute + Do not use untrusted strings such as CALLERID(num) + or CALLERID(name) as part of the command parameters. You + risk a command injection attack executing arbitrary commands if the untrusted + strings aren't filtered to remove dangerous characters. See function + FILTER(). diff --git a/configs/samples/minivm.conf.sample b/configs/samples/minivm.conf.sample index 2df3449d13f..79fdbb0e2ce 100644 --- a/configs/samples/minivm.conf.sample +++ b/configs/samples/minivm.conf.sample @@ -51,7 +51,7 @@ silencethreshold=128 ; If you need to have an external program, i.e. /usr/bin/myapp called when a ; voicemail is received by the server. The arguments are ; -; +; ; ;externnotify=/usr/bin/myapp ; The character set for voicemail messages can be specified here diff --git a/funcs/func_shell.c b/funcs/func_shell.c index 0398cd83960..fe1debe8848 100644 --- a/funcs/func_shell.c +++ b/funcs/func_shell.c @@ -82,6 +82,11 @@ static int shell_helper(struct ast_channel *chan, const char *cmd, char *data, The command that the shell should execute. + Do not use untrusted strings such as CALLERID(num) + or CALLERID(name) as part of the command parameters. You + risk a command injection attack executing arbitrary commands if the untrusted + strings aren't filtered to remove dangerous characters. See function + FILTER(). diff --git a/include/asterisk/app.h b/include/asterisk/app.h index d86b63338f2..0505a6b987d 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -871,9 +871,34 @@ int ast_vm_test_destroy_user(const char *context, const char *mailbox); int ast_vm_test_create_user(const char *context, const char *mailbox); #endif -/*! \brief Safely spawn an external program while closing file descriptors - \note This replaces the \b system call in all Asterisk modules -*/ +/*! + * \brief Safely spawn an external program while closing file descriptors + * + * \note This replaces the \b execvp call in all Asterisk modules + * + * \param dualfork Non-zero to simulate running the program in the + * background by forking twice. The option provides similar + * functionality to the '&' in the OS shell command "cmd &". The + * option allows Asterisk to run a reaper loop to watch the first fork + * which immediately exits after spaning the second fork. The actual + * program is run in the second fork. + * \param file execvp(file, argv) file parameter + * \param argv execvp(file, argv) argv parameter + */ +int ast_safe_execvp(int dualfork, const char *file, char *const argv[]); + +/*! + * \brief Safely spawn an OS shell command while closing file descriptors + * + * \note This replaces the \b system call in all Asterisk modules + * + * \param s - OS shell command string to execute. + * + * \warning Command injection can happen using this call if the passed + * in string is created using untrusted data from an external source. + * It is best not to use untrusted data. However, the caller could + * filter out dangerous characters to avoid command injection. + */ int ast_safe_system(const char *s); /*! diff --git a/main/asterisk.c b/main/asterisk.c index 0a131fda964..d555949839a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1170,11 +1170,10 @@ void ast_unreplace_sigchld(void) ast_mutex_unlock(&safe_system_lock); } -int ast_safe_system(const char *s) +/*! \brief fork and perform other preparations for spawning applications */ +static pid_t safe_exec_prep(int dualfork) { pid_t pid; - int res; - int status; #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK) ast_replace_sigchld(); @@ -1196,35 +1195,101 @@ int ast_safe_system(const char *s) cap_free(cap); #endif #ifdef HAVE_WORKING_FORK - if (ast_opt_high_priority) + if (ast_opt_high_priority) { ast_set_priority(0); + } /* Close file descriptors and launch system command */ ast_close_fds_above_n(STDERR_FILENO); #endif - execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL); - _exit(1); - } else if (pid > 0) { + if (dualfork) { +#ifdef HAVE_WORKING_FORK + pid = fork(); +#else + pid = vfork(); +#endif + if (pid < 0) { + /* Second fork failed. */ + /* No logger available. */ + _exit(1); + } + + if (pid > 0) { + /* This is the first fork, exit so the reaper finishes right away. */ + _exit(0); + } + + /* This is the second fork. The first fork will exit immediately so + * Asterisk doesn't have to wait for completion. + * ast_safe_system("cmd &") would run in the background, but the '&' + * cannot be added with ast_safe_execvp, so we have to double fork. + */ + } + } + + if (pid < 0) { + ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); + } +#else + ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(ENOTSUP)); + pid = -1; +#endif + + return pid; +} + +/*! \brief wait for spawned application to complete and unreplace sigchld */ +static int safe_exec_wait(pid_t pid) +{ + int res = -1; + +#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK) + if (pid > 0) { for (;;) { + int status; + res = waitpid(pid, &status, 0); if (res > -1) { res = WIFEXITED(status) ? WEXITSTATUS(status) : -1; break; - } else if (errno != EINTR) + } + if (errno != EINTR) { break; + } } - } else { - ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); - res = -1; } ast_unreplace_sigchld(); -#else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */ - res = -1; #endif return res; } +int ast_safe_execvp(int dualfork, const char *file, char *const argv[]) +{ + pid_t pid = safe_exec_prep(dualfork); + + if (pid == 0) { + execvp(file, argv); + _exit(1); + /* noreturn from _exit */ + } + + return safe_exec_wait(pid); +} + +int ast_safe_system(const char *s) +{ + pid_t pid = safe_exec_prep(0); + + if (pid == 0) { + execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL); + _exit(1); + /* noreturn from _exit */ + } + + return safe_exec_wait(pid); +} + /*! * \brief enable or disable a logging level to a specified console */ diff --git a/res/res_monitor.c b/res/res_monitor.c index fd3ff7a1c9c..3e3611b3615 100644 --- a/res/res_monitor.c +++ b/res/res_monitor.c @@ -59,17 +59,17 @@ - optional, if not set, defaults to wav + Optional. If not set, defaults to wav - if set, changes the filename used to the one specified. + If set, changes the filename used to the one specified. + + Mailbox name to use when incoming MWI NOTIFYs are received + + If an MWI NOTIFY is received from this endpoint, + this mailbox will be used when notifying other modules of MWI status + changes. If not set, incoming MWI NOTIFYs are ignored. + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 715ffe8ebe4..cba8a7e7fba 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1995,6 +1995,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "incoming_mwi_mailbox", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, incoming_mwi_mailbox)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); @@ -2159,6 +2160,9 @@ void *ast_sip_endpoint_alloc(const char *name) ao2_cleanup(endpoint); return NULL; } + + ast_string_field_init_extended(endpoint, incoming_mwi_mailbox); + if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ao2_cleanup(endpoint); return NULL; diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 9f0eae241c8..81b25ac2e4e 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -31,6 +31,7 @@ #include #include +#include "asterisk/app.h" #include "asterisk/res_pjsip_pubsub.h" #include "asterisk/module.h" #include "asterisk/linkedlists.h" @@ -3402,12 +3403,144 @@ int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype, return res; } +struct simple_message_summary { + int messages_waiting; + int voice_messages_new; + int voice_messages_old; + int voice_messages_urgent_new; + int voice_messages_urgent_old; + char message_account[PJSIP_MAX_URL_SIZE]; +}; + +static int parse_simple_message_summary(char *body, + struct simple_message_summary *summary) +{ + char *line; + char *buffer; + int found_counts = 0; + + if (ast_strlen_zero(body) || !summary) { + return -1; + } + + buffer = ast_strdupa(body); + memset(summary, 0, sizeof(*summary)); + + while ((line = ast_read_line_from_buffer(&buffer))) { + line = ast_str_to_lower(line); + + if (sscanf(line, "voice-message: %d/%d (%d/%d)", + &summary->voice_messages_new, &summary->voice_messages_old, + &summary->voice_messages_urgent_new, &summary->voice_messages_urgent_old)) { + found_counts = 1; + } else { + sscanf(line, "message-account: %s", summary->message_account); + } + } + + return !found_counts; +} + +static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata) +{ + RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); + struct simple_message_summary summary; + const char *endpoint_name; + char *atsign; + char *context; + char *body; + char *mailbox; + int rc; + + endpoint = ast_pjsip_rdata_get_endpoint(rdata); + if (!endpoint) { + ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata); + rc = 404; + goto error; + } + + endpoint_name = ast_sorcery_object_get_id(endpoint); + ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name); + if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) { + ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name); + ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX", + "Endpoint: %s", endpoint_name); + rc = 404; + goto error; + } + + mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox); + atsign = strchr(mailbox, '@'); + if (!atsign) { + ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n", + endpoint_name, endpoint->incoming_mwi_mailbox); + rc = 404; + goto error; + } + + *atsign = '\0'; + context = atsign + 1; + + body = ast_alloca(rdata->msg_info.msg->body->len + 1); + rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body, + rdata->msg_info.msg->body->len + 1); + + if (parse_simple_message_summary(body, &summary) != 0) { + ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n", + ast_sorcery_object_get_id(endpoint), body); + rc = 404; + goto error; + } + + if (ast_publish_mwi_state(mailbox, context, + summary.voice_messages_new, summary.voice_messages_old)) { + ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. " + "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n", + endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account, + summary.voice_messages_new, summary.voice_messages_old, + summary.voice_messages_urgent_new, summary.voice_messages_urgent_old); + rc = 404; + } else { + ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n", + endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account, + summary.voice_messages_new, summary.voice_messages_old, + summary.voice_messages_urgent_new, summary.voice_messages_urgent_old); + ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH", + "Endpoint: %s\r\n" + "Mailbox: %s\r\n" + "MessageAccount: %s\r\n" + "VoiceMessagesNew: %d\r\n" + "VoiceMessagesOld: %d\r\n" + "VoiceMessagesUrgentNew: %d\r\n" + "VoiceMessagesUrgentOld: %d", + endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account, + summary.voice_messages_new, summary.voice_messages_old, + summary.voice_messages_urgent_new, summary.voice_messages_urgent_old); + rc = 200; + } + +error: + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL); + return PJ_TRUE; +} + +static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata) +{ + if (pj_stricmp2(&rdata->msg_info.msg->body->content_type.type, "application") == 0 && + pj_stricmp2(&rdata->msg_info.msg->body->content_type.subtype, "simple-message-summary") == 0) { + return pubsub_on_rx_mwi_notify_request(rdata); + } + return PJ_FALSE; +} + static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata) { if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) { return pubsub_on_rx_subscribe_request(rdata); } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) { return pubsub_on_rx_publish_request(rdata); + } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) { + return pubsub_on_rx_notify_request(rdata); } return PJ_FALSE; From eec03963951138ad1ceb24ad3b57f0867e3ffb1f Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 13 Sep 2017 10:38:11 -0400 Subject: [PATCH 1481/1578] =?UTF-8?q?chan=5Frtp:=20Use=20=CE=BC-law=20by?= =?UTF-8?q?=20default=20instead=20of=20signed=20linear?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multicast/Unicast RTP do not use SDP so we need to use a format that cleanly maps to one of the static RTP payload types. Without this change, an Originate to a Multicast or Unicast channel without a format specified would produce no audio on the receiving device. ASTERISK-21399 #close Reported by: Tzafrir Cohen Change-Id: I97e332b566e85da04b0004b9b0daae746cfca0e3 --- channels/chan_rtp.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index 6eec91e22b5..e1c29a2ac9f 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -117,6 +117,22 @@ static int rtp_hangup(struct ast_channel *ast) return 0; } +static struct ast_format *derive_format_from_cap(struct ast_format_cap *cap) +{ + struct ast_format *fmt = ast_format_cap_get_format(cap, 0); + + if (ast_format_cap_count(cap) == 1 && fmt == ast_format_slin) { + /* + * Because we have no SDP, we must use one of the static RTP payload + * assignments. Signed linear @ 8kHz does not map, so if that is our + * only capability, we force μ-law instead. + */ + fmt = ast_format_ulaw; + } + + return fmt; +} + /*! \brief Function called when we should prepare to call the multicast destination */ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { @@ -171,7 +187,7 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo fmt = ast_multicast_rtp_options_get_format(mcast_options); if (!fmt) { - fmt = ast_format_cap_get_format(cap, 0); + fmt = derive_format_from_cap(cap); } if (!fmt) { ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n", @@ -298,7 +314,7 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form goto failure; } } else { - fmt = ast_format_cap_get_format(cap, 0); + fmt = derive_format_from_cap(cap); if (!fmt) { ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n", args.destination); From d8112cd98b5f8c8402e04220018b6a96f789869d Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 13 Sep 2017 15:08:39 -0400 Subject: [PATCH 1482/1578] res_calendar: Various fixes * The way that we were looking at XML elements for CalDAV was extremely fragile, so use SAX2 for increased robustness. * Don't complain about a 'channel' not be specified if autoreminder is not set. Assume that if 'channel' is not set, we don't want to be notified. * Fix some truncated CLI output in 'calendar show calendar' and make the 'Autoreminder' description a bit more clear ASTERISK-24588 #close Reported by: Stefan Gofferje ASTERISK-25523 #close Reported by: Jesper Change-Id: I200d11afca6a47e7d97888f286977e2e69874b2c --- res/res_calendar.c | 23 +++++++++++++++++----- res/res_calendar_caldav.c | 40 +++++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/res/res_calendar.c b/res/res_calendar.c index e4c89dfd7cb..bf385dba692 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -488,6 +488,13 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c } } + if (cal->autoreminder && ast_strlen_zero(cal->notify_channel)) { + ast_log(LOG_WARNING, + "You have set 'autoreminder' but not 'channel' for calendar '%s.' " + "Notifications will not occur.\n", + cal->name); + } + if (new_calendar) { cal->thread = AST_PTHREADT_NULL; ast_cond_init(&cal->unload, NULL); @@ -495,7 +502,7 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) { /* If we start failing to create threads, go ahead and return NULL * and the tech module will be unregistered - */ + */ ao2_unlink(calendars, cal); cal = unref_calendar(cal); } @@ -954,7 +961,7 @@ static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar event = cmp_event ? cmp_event : old_event; ao2_lock(event); - if (!cmp_event || old_event->alarm != event->alarm) { + if (!ast_strlen_zero(cal->notify_channel) && (!cmp_event || old_event->alarm != event->alarm)) { changed = 1; if (cal->autoreminder) { alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000; @@ -963,7 +970,7 @@ static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar } /* For now, send the notification if we missed it, but the meeting hasn't happened yet */ - if (event->start >= now.tv_sec) { + if (event->start >= now.tv_sec) { if (alarm_notify_sched <= 0) { alarm_notify_sched = 1; } @@ -1596,7 +1603,7 @@ static char *epoch_to_string(char *buf, size_t buflen, time_t epoch) static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { -#define FORMAT "%-17.17s : %-20.20s\n" +#define FORMAT "%-18.18s : %-20.20s\n" #define FORMAT2 "%-12.12s: %-40.60s\n" struct ao2_iterator i; struct ast_calendar *cal; @@ -1645,7 +1652,13 @@ static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_c ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata); ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh); ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe); - ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder); + + if (cal->autoreminder) { + ast_cli(a->fd, "%-17.17s : %d minutes before event\n", "Autoreminder", cal->autoreminder); + } else { + ast_cli(a->fd, "%-17.17s : None\n", "Autoreminder"); + } + ast_cli(a->fd, "%s\n", "Events"); ast_cli(a->fd, "%s\n", "------"); diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c index 3c1c74a4c27..b6822b0854d 100644 --- a/res/res_calendar_caldav.c +++ b/res/res_calendar_caldav.c @@ -156,6 +156,7 @@ static struct ast_str *caldav_request(struct caldav_pvt *pvt, const char *method ne_add_response_body_reader(req, debug_response_handler, fetch_response_reader, &response); ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body)); ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type); + ne_add_request_header(req, "Depth", "1"); ret = ne_request_dispatch(req); ne_request_destroy(req); @@ -476,17 +477,26 @@ struct xmlstate { time_t end; }; -static void handle_start_element(void *data, const xmlChar *fullname, const xmlChar **atts) +static const xmlChar *caldav_node_localname = BAD_CAST "calendar-data"; +static const xmlChar *caldav_node_nsuri = BAD_CAST "urn:ietf:params:xml:ns:caldav"; + +static void handle_start_element(void *data, + const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri, + int nb_namespaces, const xmlChar **namespaces, + int nb_attributes, int nb_defaulted, const xmlChar **attributes) { struct xmlstate *state = data; - if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data") || !xmlStrcasecmp(fullname, BAD_CAST "caldav:calendar-data")) { - state->in_caldata = 1; - ast_str_reset(state->cdata); + if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) { + return; } + + state->in_caldata = 1; + ast_str_reset(state->cdata); } -static void handle_end_element(void *data, const xmlChar *name) +static void handle_end_element(void *data, + const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri) { struct xmlstate *state = data; struct icaltimetype start, end; @@ -494,7 +504,7 @@ static void handle_end_element(void *data, const xmlChar *name) icalcomponent *iter; icalcomponent *comp; - if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data") && xmlStrcasecmp(name, BAD_CAST "caldav:calendar-data")) { + if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) { return; } @@ -557,9 +567,23 @@ static int update_caldav(struct caldav_pvt *pvt) state.start = start; state.end = end; + /* + * We want SAX2, so you assume that we want to call xmlSAXVersion() here, and + * that certainly seems like the right thing to do, but the default SAX + * handling functions assume that the 'data' pointer is going to be a + * xmlParserCtxtPtr, not a user data pointer, so we have to make sure that we + * are only calling the handlers that we control. + * + * So instead we hack things up a bit, clearing the struct and then assigning + * the magic number manually. + * + * There may be a cleaner way to do this, but frankly the libxml2 docs are + * pretty sparse. + */ memset(&saxHandler, 0, sizeof(saxHandler)); - saxHandler.startElement = handle_start_element; - saxHandler.endElement = handle_end_element; + saxHandler.initialized = XML_SAX2_MAGIC; + saxHandler.startElementNs = handle_start_element; + saxHandler.endElementNs = handle_end_element; saxHandler.characters = handle_characters; xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response)); From 01f2220bec079dcc95498285d6121322de737962 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 14 Sep 2017 12:54:40 +0000 Subject: [PATCH 1483/1578] tcptls: Change error message to debug. The Websocket implementation will steal the underlying stream of TCP/TLS sessions. This results in an error message being output about a stream not being present when in reality this is actually fine. This change moves it to a debug message instead. Change-Id: I66cc639080b4b4599beadb4faa7d313f2721d094 --- main/tcptls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/tcptls.c b/main/tcptls.c index 85859a3435c..ebe86f3e005 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -777,7 +777,7 @@ void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_se ast_iostream_close(tcptls_session->stream); tcptls_session->stream = NULL; } else { - ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); + ast_debug(1, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); } } From d178f497d2657361374abaa92d517bcdc8a81f97 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 13 Sep 2017 15:23:54 -0600 Subject: [PATCH 1484/1578] res_pjsip: Filter out non SIP(S) requests Incoming requests with non sip(s) URIs in the Request, To, From or Contact URIs are now rejected with PJSIP_SC_UNSUPPORTED_URI_SCHEME (416). This is performed in pjsip_message_filter (formerly pjsip_message_ip_updater) and is done at pjproject's "TRANSPORT" layer before a request can even reach the distributor. URIs read by res_pjsip_outbound_publish from pjsip.conf are now also checked for both length and sip(s) scheme. Those URIs read by outbound registration and aor were already being checked for scheme but their error messages needed to be updated to include scheme failure as well as length failure. Change-Id: Ibb2f9f1d2dc7549da562af4cbd9156c44ffdd460 --- configs/samples/pjsip.conf.sample | 2 +- res/res_pjsip.c | 4 +- res/res_pjsip/include/res_pjsip_private.h | 4 +- res/res_pjsip/location.c | 2 +- ...ge_ip_updater.c => pjsip_message_filter.c} | 248 +++++++++++++----- res/res_pjsip_outbound_publish.c | 18 ++ res/res_pjsip_outbound_registration.c | 4 +- 7 files changed, 204 insertions(+), 78 deletions(-) rename res/res_pjsip/{pjsip_message_ip_updater.c => pjsip_message_filter.c} (60%) diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 1e1029b2046..9a2592bedcf 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -1147,7 +1147,7 @@ ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_outbound_publish -;======================OUTBOUND_PUBLISHEN SECTION OPTIONS===================== +;======================OUTBOUND_PUBLISH SECTION OPTIONS===================== ; See https://wiki.asterisk.org/wiki/display/AST/Publishing+Extension+State ; for more information. ;[outbound-publish] diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 0ff6ab85c98..6c1f7765949 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4674,7 +4674,7 @@ static int unload_pjsip(void *data) */ if (ast_pjsip_endpoint && serializer_pool[0]) { ast_res_pjsip_cleanup_options_handling(); - ast_res_pjsip_cleanup_message_ip_updater(); + ast_res_pjsip_cleanup_message_filter(); ast_sip_destroy_distributor(); ast_res_pjsip_destroy_configuration(); ast_sip_destroy_system(); @@ -4853,7 +4853,7 @@ static int load_module(void) ast_res_pjsip_init_options_handling(0); - if (ast_res_pjsip_init_message_ip_updater()) { + if (ast_res_pjsip_init_message_filter()) { ast_log(LOG_ERROR, "Failed to initialize message IP updating. Aborting load\n"); goto error; } diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 2969f0e40c8..9fd7aed9766 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -212,7 +212,7 @@ int ast_res_pjsip_init_options_handling(int reload); * \retval 0 on success * \retval other on failure */ -int ast_res_pjsip_init_message_ip_updater(void); +int ast_res_pjsip_init_message_filter(void); /*! * \internal @@ -269,7 +269,7 @@ void ast_res_pjsip_cleanup_options_handling(void); * \internal * \brief Clean up res_pjsip message ip updating handling */ -void ast_res_pjsip_cleanup_message_ip_updater(void); +void ast_res_pjsip_cleanup_message_filter(void); /*! * \internal diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 2273273e31e..9945c7c1093 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -613,7 +613,7 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab } if (ast_sip_validate_uri_length(contact_uri)) { - ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit: %s\n", contact_uri); + ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit or is not a sip(s) uri: %s\n", contact_uri); return -1; } diff --git a/res/res_pjsip/pjsip_message_ip_updater.c b/res/res_pjsip/pjsip_message_filter.c similarity index 60% rename from res/res_pjsip/pjsip_message_ip_updater.c rename to res/res_pjsip/pjsip_message_filter.c index 099ecaa66ca..63b8bd5af55 100644 --- a/res/res_pjsip/pjsip_message_ip_updater.c +++ b/res/res_pjsip/pjsip_message_filter.c @@ -27,72 +27,72 @@ #define MOD_DATA_RESTRICTIONS "restrictions" -static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata); -static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata); +static pj_status_t filter_on_tx_message(pjsip_tx_data *tdata); +static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata); /*! \brief Outgoing message modification restrictions */ -struct multihomed_message_restrictions { +struct filter_message_restrictions { /*! \brief Disallow modification of the From domain */ unsigned int disallow_from_domain_modification; }; -static pjsip_module multihomed_module = { - .name = { "Multihomed Routing", 18 }, +static pjsip_module filter_module = { + .name = { "Message Filtering", 17 }, .id = -1, - .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1, - .on_tx_request = multihomed_on_tx_message, - .on_tx_response = multihomed_on_tx_message, - .on_rx_request = multihomed_on_rx_message, + .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, + .on_tx_request = filter_on_tx_message, + .on_tx_response = filter_on_tx_message, + .on_rx_request = filter_on_rx_message, }; /*! \brief Helper function to get (or allocate if not already present) restrictions on a message */ -static struct multihomed_message_restrictions *multihomed_get_restrictions(pjsip_tx_data *tdata) +static struct filter_message_restrictions *get_restrictions(pjsip_tx_data *tdata) { - struct multihomed_message_restrictions *restrictions; + struct filter_message_restrictions *restrictions; - restrictions = ast_sip_mod_data_get(tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS); + restrictions = ast_sip_mod_data_get(tdata->mod_data, filter_module.id, MOD_DATA_RESTRICTIONS); if (restrictions) { return restrictions; } - restrictions = PJ_POOL_ALLOC_T(tdata->pool, struct multihomed_message_restrictions); - ast_sip_mod_data_set(tdata->pool, tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS, restrictions); + restrictions = PJ_POOL_ALLOC_T(tdata->pool, struct filter_message_restrictions); + ast_sip_mod_data_set(tdata->pool, tdata->mod_data, filter_module.id, MOD_DATA_RESTRICTIONS, restrictions); return restrictions; } /*! \brief Callback invoked on non-session outgoing messages */ -static void multihomed_outgoing_message(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata) +static void filter_outgoing_message(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata) { - struct multihomed_message_restrictions *restrictions = multihomed_get_restrictions(tdata); + struct filter_message_restrictions *restrictions = get_restrictions(tdata); restrictions->disallow_from_domain_modification = !ast_strlen_zero(endpoint->fromdomain); } /*! \brief PJSIP Supplement for tagging messages with restrictions */ -static struct ast_sip_supplement multihomed_supplement = { +static struct ast_sip_supplement filter_supplement = { .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST, - .outgoing_request = multihomed_outgoing_message, - .outgoing_response = multihomed_outgoing_message, + .outgoing_request = filter_outgoing_message, + .outgoing_response = filter_outgoing_message, }; /*! \brief Callback invoked on session outgoing messages */ -static void multihomed_session_outgoing_message(struct ast_sip_session *session, struct pjsip_tx_data *tdata) +static void filter_session_outgoing_message(struct ast_sip_session *session, struct pjsip_tx_data *tdata) { - struct multihomed_message_restrictions *restrictions = multihomed_get_restrictions(tdata); + struct filter_message_restrictions *restrictions = get_restrictions(tdata); restrictions->disallow_from_domain_modification = !ast_strlen_zero(session->endpoint->fromdomain); } /*! \brief PJSIP Session Supplement for tagging messages with restrictions */ -static struct ast_sip_session_supplement multihomed_session_supplement = { +static struct ast_sip_session_supplement filter_session_supplement = { .priority = 1, - .outgoing_request = multihomed_session_outgoing_message, - .outgoing_response = multihomed_session_outgoing_message, + .outgoing_request = filter_session_outgoing_message, + .outgoing_response = filter_session_outgoing_message, }; /*! \brief Helper function which returns a UDP transport bound to the given address and port */ -static pjsip_transport *multihomed_get_udp_transport(pj_str_t *address, int port) +static pjsip_transport *get_udp_transport(pj_str_t *address, int port) { struct ao2_container *transport_states = ast_sip_get_transport_states(); struct ast_sip_transport_state *transport_state; @@ -121,7 +121,7 @@ static pjsip_transport *multihomed_get_udp_transport(pj_str_t *address, int port } /*! \brief Helper function which determines if a transport is bound to any */ -static int multihomed_bound_any(pjsip_transport *transport) +static int is_bound_any(pjsip_transport *transport) { pj_uint32_t loop6[4] = {0, 0, 0, 0}; @@ -156,6 +156,19 @@ static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp) #define is_sip_uri(uri) \ (PJSIP_URI_SCHEME_IS_SIP(uri) || PJSIP_URI_SCHEME_IS_SIPS(uri)) +static void print_sanitize_debug(char *msg, pjsip_uri_context_e context, pjsip_sip_uri *uri) +{ +#ifdef AST_DEVMODE + char hdrbuf[512]; + int hdrbuf_len; + + hdrbuf_len = pjsip_uri_print(context, uri, hdrbuf, 512); + hdrbuf[hdrbuf_len] = '\0'; + ast_debug(2, "%s: %s\n", msg, hdrbuf); +#endif +} + +/* If in DEVMODE, prevent inlining to assist in debugging */ #ifdef AST_DEVMODE #define FUNC_ATTRS __attribute__ ((noinline)) #else @@ -167,21 +180,12 @@ static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata) static const pj_str_t x_name = { AST_SIP_X_AST_TXP, AST_SIP_X_AST_TXP_LEN }; pjsip_param *x_transport; pjsip_sip_uri *uri; - pjsip_fromto_hdr *fromto; - pjsip_contact_hdr *contact; pjsip_hdr *hdr; -#ifdef AST_DEVMODE - char hdrbuf[512]; - int hdrbuf_len; -#endif if (tdata->msg->type == PJSIP_REQUEST_MSG) { if (is_sip_uri(tdata->msg->line.req.uri)) { uri = pjsip_uri_get_uri(tdata->msg->line.req.uri); -#ifdef AST_DEVMODE - hdrbuf_len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, hdrbuf, 512); - ast_debug(2, "Sanitizing Request: %s\n", hdrbuf); -#endif + print_sanitize_debug("Sanitizing Request", PJSIP_URI_IN_REQ_URI, uri); while ((x_transport = pjsip_param_find(&uri->other_param, &x_name))) { pj_list_erase(x_transport); } @@ -190,27 +194,17 @@ static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata) for (hdr = tdata->msg->hdr.next; hdr != &tdata->msg->hdr; hdr = hdr->next) { if (hdr->type == PJSIP_H_TO || hdr->type == PJSIP_H_FROM) { - fromto = (pjsip_fromto_hdr *) hdr; - if (is_sip_uri(fromto->uri)) { - uri = pjsip_uri_get_uri(fromto->uri); -#ifdef AST_DEVMODE - hdrbuf_len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, hdrbuf, 512); - hdrbuf[hdrbuf_len] = '\0'; - ast_debug(2, "Sanitizing From/To: %s\n", hdrbuf); -#endif + if (is_sip_uri(((pjsip_fromto_hdr *) hdr)->uri)) { + uri = pjsip_uri_get_uri(((pjsip_fromto_hdr *) hdr)->uri); + print_sanitize_debug("Sanitizing From/To header", PJSIP_URI_IN_FROMTO_HDR, uri); while ((x_transport = pjsip_param_find(&uri->other_param, &x_name))) { pj_list_erase(x_transport); } } } else if (hdr->type == PJSIP_H_CONTACT) { - contact = (pjsip_contact_hdr *) hdr; - if (is_sip_uri(contact->uri)) { - uri = pjsip_uri_get_uri(contact->uri); -#ifdef AST_DEVMODE - hdrbuf_len = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, uri, hdrbuf, 512); - hdrbuf[hdrbuf_len] = '\0'; - ast_debug(2, "Sanitizing Contact: %s\n", hdrbuf); -#endif + if (!((pjsip_contact_hdr *) hdr)->star && is_sip_uri(((pjsip_contact_hdr *) hdr)->uri)) { + uri = pjsip_uri_get_uri(((pjsip_contact_hdr *) hdr)->uri); + print_sanitize_debug("Sanitizing Contact header", PJSIP_URI_IN_CONTACT_HDR, uri); while ((x_transport = pjsip_param_find(&uri->other_param, &x_name))) { pj_list_erase(x_transport); } @@ -221,9 +215,9 @@ static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata) pjsip_tx_data_invalidate_msg(tdata); } -static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) +static pj_status_t filter_on_tx_message(pjsip_tx_data *tdata) { - struct multihomed_message_restrictions *restrictions = ast_sip_mod_data_get(tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS); + struct filter_message_restrictions *restrictions = ast_sip_mod_data_get(tdata->mod_data, filter_module.id, MOD_DATA_RESTRICTIONS); pjsip_tpmgr_fla2_param prm; pjsip_cseq_hdr *cseq; pjsip_via_hdr *via; @@ -256,7 +250,7 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) { pjsip_transport *transport; - transport = multihomed_get_udp_transport(&prm.ret_addr, prm.ret_port); + transport = get_udp_transport(&prm.ret_addr, prm.ret_port); if (transport) { tdata->tp_info.transport = transport; @@ -264,7 +258,7 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) } /* If the chosen transport is not bound to any we can't use the source address as it won't get back to us */ - if (!multihomed_bound_any(tdata->tp_info.transport)) { + if (!is_bound_any(tdata->tp_info.transport)) { pj_strassign(&prm.ret_addr, &tdata->tp_info.transport->local_name.host); } } else { @@ -345,7 +339,104 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) return PJ_SUCCESS; } -static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata) +enum uri_type { + URI_TYPE_REQUEST = -1, + URI_TYPE_TO = PJSIP_H_TO, + URI_TYPE_FROM = PJSIP_H_FROM, + URI_TYPE_CONTACT = PJSIP_H_CONTACT, +}; + +static void print_uri_debug(enum uri_type ut, pjsip_rx_data *rdata, pjsip_hdr *hdr) +{ +#ifdef AST_DEVMODE + pjsip_uri *local_uri = NULL; + char hdrbuf[512]; + int hdrbuf_len; + char *request_uri; + pjsip_uri_context_e context = PJSIP_URI_IN_OTHER; + char header_name[32]; + + switch (ut) { + case(URI_TYPE_REQUEST): + context = PJSIP_URI_IN_REQ_URI; + strcpy(header_name, "Request"); /* Safe */ + local_uri = rdata->msg_info.msg->line.req.uri; + break; + case(PJSIP_H_FROM): + strcpy(header_name, "From"); /* Safe */ + context = PJSIP_URI_IN_FROMTO_HDR; + local_uri = pjsip_uri_get_uri(((pjsip_from_hdr *)hdr)->uri); + break; + case(PJSIP_H_TO): + strcpy(header_name, "To"); /* Safe */ + context = PJSIP_URI_IN_FROMTO_HDR; + local_uri = pjsip_uri_get_uri(((pjsip_to_hdr *)hdr)->uri); + break; + case(PJSIP_H_CONTACT): + strcpy(header_name, "Contact"); /* Safe */ + context = PJSIP_URI_IN_CONTACT_HDR; + local_uri = pjsip_uri_get_uri(((pjsip_contact_hdr *)hdr)->uri); + break; + } + + hdrbuf_len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, hdrbuf, 512); + hdrbuf[hdrbuf_len] = '\0'; + request_uri = ast_strdupa(hdrbuf); + hdrbuf_len = pjsip_uri_print(context, local_uri, hdrbuf, 512); + hdrbuf[hdrbuf_len] = '\0'; + + ast_debug(2, "There was a non sip(s) URI scheme in %s URI '%s' for request '%*.*s %s'\n", + header_name, hdrbuf, + (int)rdata->msg_info.msg->line.req.method.name.slen, + (int)rdata->msg_info.msg->line.req.method.name.slen, + rdata->msg_info.msg->line.req.method.name.ptr, request_uri); +#endif +} + +static pj_bool_t on_rx_process_uris(pjsip_rx_data *rdata) +{ + pjsip_contact_hdr *contact = NULL; + + if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) { + return PJ_FALSE; + } + + if (!is_sip_uri(rdata->msg_info.msg->line.req.uri)) { + print_uri_debug(URI_TYPE_REQUEST, rdata, NULL); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, + PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL); + return PJ_TRUE; + } + + if (!is_sip_uri(rdata->msg_info.from->uri)) { + print_uri_debug(URI_TYPE_FROM, rdata, (pjsip_hdr *)rdata->msg_info.from); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, + PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL); + return PJ_TRUE; + } + + if (!is_sip_uri(rdata->msg_info.to->uri)) { + print_uri_debug(URI_TYPE_TO, rdata, (pjsip_hdr *)rdata->msg_info.to); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, + PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL); + return PJ_TRUE; + } + + while ((contact = + (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, + contact ? contact->next : NULL))) { + if (!contact->star && !is_sip_uri(contact->uri)) { + print_uri_debug(URI_TYPE_CONTACT, rdata, (pjsip_hdr *)contact); + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, + PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL); + return PJ_TRUE; + } + } + + return PJ_FALSE; +} + +static pj_bool_t on_rx_process_symmetric_transport(pjsip_rx_data *rdata) { pjsip_contact_hdr *contact; pjsip_sip_uri *uri; @@ -388,29 +479,46 @@ static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata) return PJ_FALSE; } -void ast_res_pjsip_cleanup_message_ip_updater(void) +static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata) +{ + pj_bool_t rc; + + rc = on_rx_process_uris(rdata); + if (rc == PJ_TRUE) { + return rc; + } + + rc = on_rx_process_symmetric_transport(rdata); + if (rc == PJ_TRUE) { + return rc; + } + + return PJ_FALSE; +} + +void ast_res_pjsip_cleanup_message_filter(void) { - ast_sip_unregister_service(&multihomed_module); - ast_sip_unregister_supplement(&multihomed_supplement); - ast_sip_session_unregister_supplement(&multihomed_session_supplement); + ast_sip_unregister_service(&filter_module); + ast_sip_unregister_supplement(&filter_supplement); + ast_sip_session_unregister_supplement(&filter_session_supplement); } -int ast_res_pjsip_init_message_ip_updater(void) +int ast_res_pjsip_init_message_filter(void) { - if (ast_sip_session_register_supplement(&multihomed_session_supplement)) { - ast_log(LOG_ERROR, "Could not register multihomed session supplement for outgoing requests\n"); + if (ast_sip_session_register_supplement(&filter_session_supplement)) { + ast_log(LOG_ERROR, "Could not register message filter session supplement for outgoing requests\n"); return -1; } - if (ast_sip_register_supplement(&multihomed_supplement)) { - ast_log(LOG_ERROR, "Could not register multihomed supplement for outgoing requests\n"); - ast_res_pjsip_cleanup_message_ip_updater(); + if (ast_sip_register_supplement(&filter_supplement)) { + ast_log(LOG_ERROR, "Could not register message filter supplement for outgoing requests\n"); + ast_res_pjsip_cleanup_message_filter(); return -1; } - if (ast_sip_register_service(&multihomed_module)) { - ast_log(LOG_ERROR, "Could not register multihomed module for incoming and outgoing requests\n"); - ast_res_pjsip_cleanup_message_ip_updater(); + if (ast_sip_register_service(&filter_module)) { + ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n"); + ast_res_pjsip_cleanup_message_filter(); return -1; } diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index c413cb0e13c..18525bf6cd4 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -34,6 +34,7 @@ #include "asterisk/taskprocessor.h" #include "asterisk/threadpool.h" #include "asterisk/datastore.h" +#include "res_pjsip/include/res_pjsip_private.h" /*** DOCUMENTATION @@ -1459,10 +1460,27 @@ static int validate_publish_config(struct ast_sip_outbound_publish *publish) ast_log(LOG_ERROR, "No server URI specified on outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); return -1; + } else if (ast_sip_validate_uri_length(publish->server_uri)) { + ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s' on outbound publish '%s'\n", + publish->server_uri, + ast_sorcery_object_get_id(publish)); + return -1; } else if (ast_strlen_zero(publish->event)) { ast_log(LOG_ERROR, "No event type specified for outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); return -1; + } else if (!ast_strlen_zero(publish->from_uri) + && ast_sip_validate_uri_length(publish->from_uri)) { + ast_log(LOG_ERROR, "From URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s' on outbound publish '%s'\n", + publish->from_uri, + ast_sorcery_object_get_id(publish)); + return -1; + } else if (!ast_strlen_zero(publish->to_uri) + && ast_sip_validate_uri_length(publish->to_uri)) { + ast_log(LOG_ERROR, "To URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s' on outbound publish '%s'\n", + publish->to_uri, + ast_sorcery_object_get_id(publish)); + return -1; } return 0; } diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index bbb286acf42..4697e5cf748 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1428,7 +1428,7 @@ static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, vo ast_sorcery_object_get_id(applied)); return -1; } else if (ast_sip_validate_uri_length(applied->server_uri)) { - ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjpropject limit '%s'\n", + ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n", ast_sorcery_object_get_id(applied)); return -1; } else if (ast_strlen_zero(applied->client_uri)) { @@ -1436,7 +1436,7 @@ static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, vo ast_sorcery_object_get_id(applied)); return -1; } else if (ast_sip_validate_uri_length(applied->client_uri)) { - ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjpropject limit '%s'\n", + ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n", ast_sorcery_object_get_id(applied)); return -1; } else if (applied->line && ast_strlen_zero(applied->endpoint)) { From 087f667ab11fea1487d9195549268ed5cf2ee831 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 25 Aug 2017 17:01:57 -0500 Subject: [PATCH 1485/1578] AST-2017-008: Improve RTP and RTCP packet processing. Validate RTCP packets before processing them. * Validate that the received packet is of a minimum length and apply the RFC3550 RTCP packet validation checks. * Fixed potentially reading garbage beyond the received RTCP record data. * Fixed rtp->themssrc only being set once when the remote could change the SSRC. We would effectively stop handling the RTCP statistic records. * Fixed rtp->themssrc to not treat a zero value as special by adding rtp->themssrc_valid to indicate if rtp->themssrc is available. ASTERISK-27274 Make strict RTP learning more flexible. Direct media can cause strict RTP to attempt to learn a remote address again before it has had a chance to learn the remote address the first time. Because of the rapid relearn requests, strict RTP could latch onto the first remote address and fail to latch onto the direct media remote address. As a result, you have one way audio until the call is placed on and off hold. The new algorithm learns remote addresses for a set time (1.5 seconds) before locking the remote address. In addition, we must see a configured number of remote packets from the same address in a row before switching. * Fixed strict RTP learning from always accepting the first new address packet as the new stream. * Fixed strict RTP to initialize the expected sequence number with the last received sequence number instead of the last transmitted sequence number. * Fixed the predicted next sequence number calculation in rtp_learning_rtp_seq_update() to handle overflow. ASTERISK-27252 Change-Id: Ia2d3aa6e0f22906c25971e74f10027d96525f31c --- res/res_rtp_asterisk.c | 532 +++++++++++++++++++++++++++++++++-------- 1 file changed, 430 insertions(+), 102 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index f6a0ec08876..1440eb0e199 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -125,7 +125,9 @@ enum strict_rtp_state { STRICT_RTP_CLOSED, /*! Drop all RTP packets not coming from source that was learned */ }; -#define DEFAULT_STRICT_RTP STRICT_RTP_CLOSED +#define STRICT_RTP_LEARN_TIMEOUT 1500 /*!< milliseconds */ + +#define DEFAULT_STRICT_RTP -1 /*!< Enabled */ #define DEFAULT_ICESUPPORT 1 extern struct ast_srtp_res *res_srtp; @@ -226,9 +228,11 @@ static AST_RWLIST_HEAD_STATIC(host_candidates, ast_ice_host_candidate); /*! \brief RTP learning mode tracking information */ struct rtp_learning_info { - int max_seq; /*!< The highest sequence number received */ - int packets; /*!< The number of remaining packets before the source is accepted */ + struct ast_sockaddr proposed_address; /*!< Proposed remote address for strict RTP */ + struct timeval start; /*!< The time learning mode was started */ struct timeval received; /*!< The time of the last received packet */ + int max_seq; /*!< The highest sequence number received */ + int packets; /*!< The number of remaining packets before the source is accepted */ }; #ifdef HAVE_OPENSSL_SRTP @@ -266,7 +270,7 @@ struct ast_rtp { unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */ char cname[AST_UUID_STR_LEN]; /*!< Our local CNAME */ unsigned int themssrc; /*!< Their SSRC */ - unsigned int rxssrc; + unsigned int themssrc_valid; /*!< True if their SSRC is available. */ unsigned int lastts; unsigned int lastrxts; unsigned int lastividtimestamp; @@ -2036,7 +2040,7 @@ static void dtls_perform_setup(struct dtls_details *dtls) #endif #ifdef HAVE_PJPROJECT -static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq); +static void rtp_learning_start(struct ast_rtp *rtp); /* PJPROJECT ICE callback */ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) @@ -2078,8 +2082,8 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) return; } - rtp->strict_rtp_state = STRICT_RTP_LEARN; - rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); + ast_verb(4, "%p -- Strict RTP learning after ICE completion\n", rtp); + rtp_learning_start(rtp); ao2_unlock(instance); } @@ -2828,7 +2832,7 @@ static int create_new_socket(const char *type, int af) */ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq) { - info->max_seq = seq - 1; + info->max_seq = seq; info->packets = learning_min_sequential; memset(&info->received, 0, sizeof(info->received)); } @@ -2845,14 +2849,17 @@ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq) */ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq) { + /* + * During the learning mode the minimum amount of media we'll accept is + * 10ms so give a reasonable 5ms buffer just in case we get it sporadically. + */ if (!ast_tvzero(info->received) && ast_tvdiff_ms(ast_tvnow(), info->received) < 5) { - /* During the probation period the minimum amount of media we'll accept is - * 10ms so give a reasonable 5ms buffer just in case we get it sporadically. + /* + * Reject a flood of packets as acceptable for learning. + * Reset the needed packets. */ - return 1; - } - - if (seq == info->max_seq + 1) { + info->packets = learning_min_sequential - 1; + } else if (seq == (uint16_t) (info->max_seq + 1)) { /* packet is in sequence */ info->packets--; } else { @@ -2862,7 +2869,23 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t info->max_seq = seq; info->received = ast_tvnow(); - return (info->packets == 0); + return info->packets; +} + +/*! + * \brief Start the strictrtp learning mode. + * + * \param rtp RTP session description + * + * \return Nothing + */ +static void rtp_learning_start(struct ast_rtp *rtp) +{ + rtp->strict_rtp_state = STRICT_RTP_LEARN; + memset(&rtp->rtp_source_learn.proposed_address, 0, + sizeof(rtp->rtp_source_learn.proposed_address)); + rtp->rtp_source_learn.start = ast_tvnow(); + rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t) rtp->lastrxseqno); } #ifdef HAVE_PJPROJECT @@ -3123,10 +3146,7 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_ { int x, startplace; - rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); - if (strictrtp) { - rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); - } + rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_CLOSED : STRICT_RTP_OPEN); /* Create a new socket for us to listen on and use */ if ((rtp->s = @@ -3762,7 +3782,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) struct ast_sockaddr remote_address = { { 0, } }; struct ast_rtp_rtcp_report_block *report_block = NULL; RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, - ast_rtp_rtcp_report_alloc(rtp->themssrc ? 1 : 0), + ast_rtp_rtcp_report_alloc(rtp->themssrc_valid ? 1 : 0), ao2_cleanup); if (!rtp || !rtp->rtcp) { @@ -3782,7 +3802,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost); gettimeofday(&now, NULL); - rtcp_report->reception_report_count = rtp->themssrc ? 1 : 0; + rtcp_report->reception_report_count = rtp->themssrc_valid ? 1 : 0; rtcp_report->ssrc = rtp->ssrc; rtcp_report->type = sr ? RTCP_PT_SR : RTCP_PT_RR; if (sr) { @@ -3792,7 +3812,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) rtcp_report->sender_information.octet_count = rtp->txoctetcount; } - if (rtp->themssrc) { + if (rtp->themssrc_valid) { report_block = ast_calloc(1, sizeof(*report_block)); if (!report_block) { return 1; @@ -4181,6 +4201,10 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr */ return 0; } + if (!rtp->themssrc_valid) { + /* We don't know their SSRC value so we don't know who to update. */ + return 0; + } /* Prepare RTCP FIR (PT=206, FMT=4) */ rtp->rtcp->firseq++; @@ -4778,93 +4802,293 @@ static struct ast_rtp_instance *rtp_find_instance_by_ssrc(struct ast_rtp_instanc return found; } +static const char *rtcp_payload_type2str(unsigned int pt) +{ + const char *str; + + switch (pt) { + case RTCP_PT_SR: + str = "Sender Report"; + break; + case RTCP_PT_RR: + str = "Receiver Report"; + break; + case RTCP_PT_FUR: + /* Full INTRA-frame Request / Fast Update Request */ + str = "H.261 FUR"; + break; + case RTCP_PT_PSFB: + /* Payload Specific Feed Back */ + str = "PSFB"; + break; + case RTCP_PT_SDES: + str = "Source Description"; + break; + case RTCP_PT_BYE: + str = "BYE"; + break; + default: + str = "Unknown"; + break; + } + return str; +} + +/* + * Unshifted RTCP header bit field masks + */ +#define RTCP_LENGTH_MASK 0xFFFF +#define RTCP_PAYLOAD_TYPE_MASK 0xFF +#define RTCP_REPORT_COUNT_MASK 0x1F +#define RTCP_PADDING_MASK 0x01 +#define RTCP_VERSION_MASK 0x03 + +/* + * RTCP header bit field shift offsets + */ +#define RTCP_LENGTH_SHIFT 0 +#define RTCP_PAYLOAD_TYPE_SHIFT 16 +#define RTCP_REPORT_COUNT_SHIFT 24 +#define RTCP_PADDING_SHIFT 29 +#define RTCP_VERSION_SHIFT 30 + +#define RTCP_VERSION 2U +#define RTCP_VERSION_SHIFTED (RTCP_VERSION << RTCP_VERSION_SHIFT) +#define RTCP_VERSION_MASK_SHIFTED (RTCP_VERSION_MASK << RTCP_VERSION_SHIFT) + +/* + * RTCP first packet record validity header mask and value. + * + * RFC3550 intentionally defines the encoding of RTCP_PT_SR and RTCP_PT_RR + * such that they differ in the least significant bit. Either of these two + * payload types MUST be the first RTCP packet record in a compound packet. + * + * RFC3550 checks the padding bit in the algorithm they use to check the + * RTCP packet for validity. However, we aren't masking the padding bit + * to check since we don't know if it is a compound RTCP packet or not. + */ +#define RTCP_VALID_MASK (RTCP_VERSION_MASK_SHIFTED | (((RTCP_PAYLOAD_TYPE_MASK & ~0x1)) << RTCP_PAYLOAD_TYPE_SHIFT)) +#define RTCP_VALID_VALUE (RTCP_VERSION_SHIFTED | (RTCP_PT_SR << RTCP_PAYLOAD_TYPE_SHIFT)) + +#define RTCP_SR_BLOCK_WORD_LENGTH 5 +#define RTCP_RR_BLOCK_WORD_LENGTH 6 +#define RTCP_HEADER_SSRC_LENGTH 2 + static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr) { struct ast_rtp_instance *transport = instance; struct ast_rtp *transport_rtp = ast_rtp_instance_get_data(instance); unsigned int *rtcpheader = (unsigned int *)(rtcpdata); - int packetwords, position = 0; + unsigned int packetwords; + unsigned int position; + unsigned int first_word; + /*! True if we have seen an acceptable SSRC to learn the remote RTCP address */ + unsigned int ssrc_seen; int report_counter = 0; struct ast_rtp_rtcp_report_block *report_block; struct ast_frame *f = &ast_null_frame; packetwords = size / 4; - ast_debug(1, "Got RTCP report of %zu bytes\n", size); + ast_debug(1, "Got RTCP report of %zu bytes from %s\n", + size, ast_sockaddr_stringify(addr)); + + /* + * Validate the RTCP packet according to an adapted and slightly + * modified RFC3550 validation algorithm. + */ + if (packetwords < RTCP_HEADER_SSRC_LENGTH) { + ast_debug(1, "%p -- RTCP from %s: Frame size (%u words) is too short\n", + transport_rtp, ast_sockaddr_stringify(addr), packetwords); + return &ast_null_frame; + } + position = 0; + first_word = ntohl(rtcpheader[position]); + if ((first_word & RTCP_VALID_MASK) != RTCP_VALID_VALUE) { + ast_debug(1, "%p -- RTCP from %s: Failed first packet validity check\n", + transport_rtp, ast_sockaddr_stringify(addr)); + return &ast_null_frame; + } + do { + position += ((first_word >> RTCP_LENGTH_SHIFT) & RTCP_LENGTH_MASK) + 1; + if (packetwords <= position) { + break; + } + first_word = ntohl(rtcpheader[position]); + } while ((first_word & RTCP_VERSION_MASK_SHIFTED) == RTCP_VERSION_SHIFTED); + if (position != packetwords) { + ast_debug(1, "%p -- RTCP from %s: Failed packet version or length check\n", + transport_rtp, ast_sockaddr_stringify(addr)); + return &ast_null_frame; + } + + /* + * Note: RFC3605 points out that true NAT (vs NAPT) can cause RTCP + * to have a different IP address and port than RTP. Otherwise, when + * strictrtp is enabled we could reject RTCP packets not coming from + * the learned RTP IP address if it is available. + */ + + /* + * strictrtp safety needs SSRC to match before we use the + * sender's address for symmetrical RTP to send our RTCP + * reports. + * + * If strictrtp is not enabled then claim to have already seen + * a matching SSRC so we'll accept this packet's address for + * symmetrical RTP. + */ + ssrc_seen = transport_rtp->strict_rtp_state == STRICT_RTP_OPEN; + position = 0; while (position < packetwords) { - int i, pt, rc; + unsigned int i; + unsigned int pt; + unsigned int rc; + unsigned int ssrc; + /*! True if the ssrc value we have is valid and not garbage because it doesn't exist. */ + unsigned int ssrc_valid; unsigned int length; + unsigned int min_length; + struct ast_json *message_blob; RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, NULL, ao2_cleanup); struct ast_rtp_instance *child; struct ast_rtp *rtp; i = position; - length = ntohl(rtcpheader[i]); - pt = (length & 0xff0000) >> 16; - rc = (length & 0x1f000000) >> 24; - length &= 0xffff; - - rtcp_report = ast_rtp_rtcp_report_alloc(rc); - if (!rtcp_report) { + first_word = ntohl(rtcpheader[i]); + pt = (first_word >> RTCP_PAYLOAD_TYPE_SHIFT) & RTCP_PAYLOAD_TYPE_MASK; + rc = (first_word >> RTCP_REPORT_COUNT_SHIFT) & RTCP_REPORT_COUNT_MASK; + /* RFC3550 says 'length' is the number of words in the packet - 1 */ + length = ((first_word >> RTCP_LENGTH_SHIFT) & RTCP_LENGTH_MASK) + 1; + + /* Check expected RTCP packet record length */ + min_length = RTCP_HEADER_SSRC_LENGTH; + switch (pt) { + case RTCP_PT_SR: + min_length += RTCP_SR_BLOCK_WORD_LENGTH; + /* fall through */ + case RTCP_PT_RR: + min_length += (rc * RTCP_RR_BLOCK_WORD_LENGTH); + break; + case RTCP_PT_FUR: + case RTCP_PT_PSFB: + break; + case RTCP_PT_SDES: + case RTCP_PT_BYE: + /* + * There may not be a SSRC/CSRC present. The packet is + * useless but still valid if it isn't present. + * + * We don't know what min_length should be so disable the check + */ + min_length = length; + break; + default: + ast_debug(1, "%p -- RTCP from %s: %u(%s) skipping record\n", + transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt)); + if (rtcp_debug_test_addr(addr)) { + ast_verbose("\n"); + ast_verbose("RTCP from %s: %u(%s) skipping record\n", + ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt)); + } + position += length; + continue; + } + if (length < min_length) { + ast_debug(1, "%p -- RTCP from %s: %u(%s) length field less than expected minimum. Min:%u Got:%u\n", + transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt), + min_length - 1, length - 1); return &ast_null_frame; } - rtcp_report->reception_report_count = rc; - rtcp_report->ssrc = ntohl(rtcpheader[i + 1]); - if ((i + length) > packetwords) { - if (rtpdebug) { - ast_debug(1, "RTCP Read too short\n"); + /* Get the RTCP record SSRC if defined for the record */ + ssrc_valid = 1; + switch (pt) { + case RTCP_PT_SR: + case RTCP_PT_RR: + rtcp_report = ast_rtp_rtcp_report_alloc(rc); + if (!rtcp_report) { + return &ast_null_frame; } - return &ast_null_frame; + rtcp_report->reception_report_count = rc; + + ssrc = ntohl(rtcpheader[i + 1]); + rtcp_report->ssrc = ssrc; + break; + case RTCP_PT_FUR: + case RTCP_PT_PSFB: + ssrc = ntohl(rtcpheader[i + 1]); + break; + case RTCP_PT_SDES: + case RTCP_PT_BYE: + default: + ssrc = 0; + ssrc_valid = 0; + break; } if (rtcp_debug_test_addr(addr)) { - ast_verbose("\n\nGot RTCP from %s\n", - ast_sockaddr_stringify(addr)); - ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" : - (pt == RTCP_PT_RR) ? "Receiver Report" : - (pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown"); - ast_verbose("Reception reports: %d\n", rc); - ast_verbose("SSRC of sender: %u\n", rtcp_report->ssrc); + ast_verbose("\n"); + ast_verbose("RTCP from %s\n", ast_sockaddr_stringify(addr)); + ast_verbose("PT: %u(%s)\n", pt, rtcp_payload_type2str(pt)); + ast_verbose("Reception reports: %u\n", rc); + ast_verbose("SSRC of sender: %u\n", ssrc); } /* Determine the appropriate instance for this */ - child = rtp_find_instance_by_ssrc(transport, transport_rtp, rtcp_report->ssrc); - if (child != transport) { - /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order - * is always parent->child or that the child lock is not held when acquiring the parent lock. - */ - ao2_lock(child); - instance = child; - rtp = ast_rtp_instance_get_data(instance); + if (ssrc_valid) { + child = rtp_find_instance_by_ssrc(transport, transport_rtp, ssrc); + if (child != transport) { + /* + * It is safe to hold the child lock while holding the parent lock. + * We guarantee that the locking order is always parent->child or + * that the child lock is not held when acquiring the parent lock. + */ + ao2_lock(child); + instance = child; + rtp = ast_rtp_instance_get_data(instance); + } else { + /* The child is the parent! We don't need to unlock it. */ + child = NULL; + rtp = transport_rtp; + } } else { - /* The child is the parent! We don't need to unlock it. */ child = NULL; rtp = transport_rtp; } - if ((rtp->strict_rtp_state != STRICT_RTP_OPEN) && (rtcp_report->ssrc != rtp->themssrc)) { - /* Skip over this RTCP record as it does not contain the correct SSRC */ - position += (length + 1); - ast_debug(1, "%p -- Received RTCP report from %s, dropping due to strict RTP protection. Received SSRC '%u' but expected '%u'\n", - rtp, ast_sockaddr_stringify(addr), rtcp_report->ssrc, rtp->themssrc); - continue; + if (ssrc_valid && rtp->themssrc_valid) { + if (ssrc != rtp->themssrc) { + /* + * Skip over this RTCP record as it does not contain the + * correct SSRC. We should not act upon RTCP records + * for a different stream. + */ + position += length; + ast_debug(1, "%p -- RTCP from %s: Skipping record, received SSRC '%u' != expected '%u'\n", + rtp, ast_sockaddr_stringify(addr), ssrc, rtp->themssrc); + if (child) { + ao2_unlock(child); + } + continue; + } + ssrc_seen = 1; } - if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { + if (ssrc_seen && ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { /* Send to whoever sent to us */ if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) { ast_sockaddr_copy(&rtp->rtcp->them, addr); if (rtpdebug) { ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", - ast_sockaddr_stringify(&rtp->rtcp->them)); + ast_sockaddr_stringify(addr)); } } } - i += 2; /* Advance past header and ssrc */ + i += RTCP_HEADER_SSRC_LENGTH; /* Advance past header and ssrc */ switch (pt) { case RTCP_PT_SR: gettimeofday(&rtp->rtcp->rxlsr, NULL); @@ -4888,7 +5112,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c rtcp_report->sender_information.packet_count, rtcp_report->sender_information.octet_count); } - i += 5; + i += RTCP_SR_BLOCK_WORD_LENGTH; /* Intentional fall through */ case RTCP_PT_RR: if (rtcp_report->type != RTCP_PT_SR) { @@ -4948,9 +5172,9 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c */ message_blob = ast_json_pack("{s: s, s: s, s: f}", - "from", ast_sockaddr_stringify(&transport_rtp->rtcp->them), - "to", transport_rtp->rtcp->local_addr_str, - "rtt", rtp->rtcp->rtt); + "from", ast_sockaddr_stringify(addr), + "to", transport_rtp->rtcp->local_addr_str, + "rtt", rtp->rtcp->rtt); ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(), rtcp_report, message_blob); @@ -4996,21 +5220,19 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c case RTCP_PT_SDES: if (rtcp_debug_test_addr(addr)) { ast_verbose("Received an SDES from %s\n", - ast_sockaddr_stringify(&transport_rtp->rtcp->them)); + ast_sockaddr_stringify(addr)); } break; case RTCP_PT_BYE: if (rtcp_debug_test_addr(addr)) { ast_verbose("Received a BYE from %s\n", - ast_sockaddr_stringify(&transport_rtp->rtcp->them)); + ast_sockaddr_stringify(addr)); } break; default: - ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s\n", - pt, ast_sockaddr_stringify(&transport_rtp->rtcp->them)); break; } - position += (length + 1); + position += length; rtp->rtcp->rtcp_info = 1; if (child) { @@ -5019,7 +5241,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c } return f; - } /*! \pre instance is locked */ @@ -5343,31 +5564,133 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */ - if (rtp->strict_rtp_state == STRICT_RTP_LEARN) { - if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { - /* We are learning a new address but have received traffic from the existing address, - * accept it but reset the current learning for the new source so it only takes over - * once sufficient traffic has been received. */ - rtp_learning_seq_init(&rtp->rtp_source_learn, seqno); + switch (rtp->strict_rtp_state) { + case STRICT_RTP_LEARN: + /* + * Scenario setup: + * PartyA -- Ast1 -- Ast2 -- PartyB + * + * The learning timeout is necessary for Ast1 to handle the above + * setup where PartyA calls PartyB and Ast2 initiates direct media + * between Ast1 and PartyB. Ast1 may lock onto the Ast2 stream and + * never learn the PartyB stream when it starts. The timeout makes + * Ast1 stay in the learning state long enough to see and learn the + * RTP stream from PartyB. + * + * To mitigate against attack, the learning state cannot switch + * streams while there are competing streams. The competing streams + * interfere with each other's qualification. Once we accept a + * stream and reach the timeout, an attacker cannot interfere + * anymore. + * + * Here are a few scenarios and each one assumes that the streams + * are continuous: + * + * 1) We already have a known stream source address and the known + * stream wants to change to a new source address. An attacking + * stream will block learning the new stream source. After the + * timeout we re-lock onto the original stream source address which + * likely went away. The result is one way audio. + * + * 2) We already have a known stream source address and the known + * stream doesn't want to change source addresses. An attacking + * stream will not be able to replace the known stream. After the + * timeout we re-lock onto the known stream. The call is not + * affected. + * + * 3) We don't have a known stream source address. This presumably + * is the start of a call. Competing streams will result in staying + * in learning mode until a stream becomes the victor and we reach + * the timeout. We cannot exit learning if we have no known stream + * to lock onto. The result is one way audio until there is a victor. + * + * If we learn a stream source address before the timeout we will be + * in scenario 1) or 2) when a competing stream starts. + */ + if (!ast_sockaddr_isnull(&rtp->strict_rtp_address) + && STRICT_RTP_LEARN_TIMEOUT < ast_tvdiff_ms(ast_tvnow(), rtp->rtp_source_learn.start)) { + ast_verb(4, "%p -- Strict RTP learning complete - Locking on source address %s\n", + rtp, ast_sockaddr_stringify(&rtp->strict_rtp_address)); + rtp->strict_rtp_state = STRICT_RTP_CLOSED; } else { - /* Start trying to learn from the new address. If we pass a probationary period with - * it, that means we've stopped getting RTP from the original source and we should - * switch to it. + struct ast_sockaddr target_address; + + if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { + /* + * We are open to learning a new address but have received + * traffic from the current address, accept it and reset + * the learning counts for a new source. When no more + * current source packets arrive a new source can take over + * once sufficient traffic is received. + */ + rtp_learning_seq_init(&rtp->rtp_source_learn, seqno); + break; + } + + /* + * We give preferential treatment to the requested target address + * (negotiated SDP address) where we are to send our RTP. However, + * the other end has no obligation to send from that address even + * though it is practically a requirement when NAT is involved. */ - if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) { - ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n", - rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets); - return &ast_null_frame; + ast_rtp_instance_get_requested_target_address(instance, &target_address); + if (!ast_sockaddr_cmp(&target_address, &addr)) { + /* Accept the negotiated target RTP stream as the source */ + ast_verb(4, "%p -- Strict RTP switching to RTP target address %s as source\n", + rtp, ast_sockaddr_stringify(&addr)); + ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); + rtp_learning_seq_init(&rtp->rtp_source_learn, seqno); + break; } - ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); - ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr)); - rtp->strict_rtp_state = STRICT_RTP_CLOSED; + /* + * Trying to learn a new address. If we pass a probationary period + * with it, that means we've stopped getting RTP from the original + * source and we should switch to it. + */ + if (!ast_sockaddr_cmp(&rtp->rtp_source_learn.proposed_address, &addr)) { + if (!rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) { + /* Accept the new RTP stream */ + ast_verb(4, "%p -- Strict RTP switching source address to %s\n", + rtp, ast_sockaddr_stringify(&addr)); + ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); + rtp_learning_seq_init(&rtp->rtp_source_learn, seqno); + break; + } + /* Not ready to accept the RTP stream candidate */ + ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets.\n", + rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets); + } else { + /* + * This is either an attacking stream or + * the start of the expected new stream. + */ + ast_sockaddr_copy(&rtp->rtp_source_learn.proposed_address, &addr); + rtp_learning_seq_init(&rtp->rtp_source_learn, seqno); + ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Qualifying new stream.\n", + rtp, ast_sockaddr_stringify(&addr)); + } + return &ast_null_frame; + } + /* Fall through */ + case STRICT_RTP_CLOSED: + /* + * We should not allow a stream address change if the SSRC matches + * once strictrtp learning is closed. Any kind of address change + * like this should have happened while we were in the learning + * state. We do not want to allow the possibility of an attacker + * interfering with the RTP stream after the learning period. + * An attacker could manage to get an RTCP packet redirected to + * them which can contain the SSRC value. + */ + if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { + break; } - } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED && ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n", rtp, ast_sockaddr_stringify(&addr)); return &ast_null_frame; + case STRICT_RTP_OPEN: + break; } /* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */ @@ -5404,7 +5727,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc AST_LIST_HEAD_INIT_NOLOCK(&frames); /* Force a marker bit and change SSRC if the SSRC changes */ - if (rtp->rxssrc && rtp->rxssrc != ssrc) { + if (rtp->themssrc_valid && rtp->themssrc != ssrc) { struct ast_frame *f, srcupdate = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_SRCCHANGE, @@ -5432,8 +5755,10 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->rtcp->received_prior = 0; } } - - rtp->rxssrc = ssrc; + /* Bundled children cannot change/learn their SSRC implicitly. */ + ast_assert(!child || (rtp->themssrc_valid && rtp->themssrc == ssrc)); + rtp->themssrc = ssrc; /* Record their SSRC to put in future RR */ + rtp->themssrc_valid = 1; /* Remove any padding bytes that may be present */ if (padding) { @@ -5487,10 +5812,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc prev_seqno = rtp->lastrxseqno; rtp->lastrxseqno = seqno; - if (!rtp->themssrc) { - rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */ - } - /* If we are directly bridged to another instance send the audio directly out, * but only after updating core information about the received traffic so that @@ -5899,13 +6220,14 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct rtp->rxseqno = 0; - if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN && !ast_sockaddr_isnull(addr) && - ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) { + if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN + && !ast_sockaddr_isnull(addr) && ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) { /* We only need to learn a new strict source address if we've been told the source is * changing to something different. */ - rtp->strict_rtp_state = STRICT_RTP_LEARN; - rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno); + ast_verb(4, "%p -- Strict RTP learning after remote address set to: %s\n", + rtp, ast_sockaddr_stringify(addr)); + rtp_learning_start(rtp); } } @@ -6189,11 +6511,12 @@ static const char *ast_rtp_get_cname(struct ast_rtp_instance *instance) return rtp->cname; } +/*! \pre instance is locked */ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned int ssrc) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - if (rtp->themssrc == ssrc) { + if (rtp->themssrc_valid && rtp->themssrc == ssrc) { return; } @@ -6202,6 +6525,8 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned struct ast_rtp *bundled_rtp; int index; + ast_assert(rtp->themssrc_valid); + ao2_unlock(instance); /* The child lock can't be held while accessing the parent */ @@ -6223,6 +6548,7 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned } rtp->themssrc = ssrc; + rtp->themssrc_valid = 1; } static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num) @@ -6232,6 +6558,7 @@ static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream rtp->stream_num = stream_num; } +/*! \pre child is locked */ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent) { struct ast_rtp *child_rtp = ast_rtp_instance_get_data(child); @@ -6274,6 +6601,7 @@ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instanc /* Children maintain a reference to the parent to guarantee that the transport doesn't go away on them */ child_rtp->bundled = ao2_bump(parent); + ast_assert(child_rtp->themssrc_valid); mapping.ssrc = child_rtp->themssrc; mapping.instance = child; From 1199927fc09a57b90dd2426ae209666b3a838811 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 13 Sep 2017 11:46:27 +0300 Subject: [PATCH 1486/1578] cdr_mysql.c: Apply cdrzone to start and answer Change-Id: I7de0a5adc89824a5f2b696fc22c80fc22dff36b0 --- addons/cdr_mysql.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c index f8f4192acde..1c116636fb1 100644 --- a/addons/cdr_mysql.c +++ b/addons/cdr_mysql.c @@ -258,9 +258,7 @@ static int mysql_log(struct ast_cdr *cdr) /* Need the type and value to determine if we want the raw value or not */ if (entry->staticvalue) { value = ast_strdupa(entry->staticvalue); - } else if ((!strcmp(cdrname, "answer") || - !strcmp(cdrname, "end") || - !strcmp(cdrname, "disposition") || + } else if ((!strcmp(cdrname, "disposition") || !strcmp(cdrname, "amaflags")) && (strstr(entry->type, "int") || strstr(entry->type, "dec") || @@ -270,7 +268,8 @@ static int mysql_log(struct ast_cdr *cdr) strstr(entry->type, "numeric") || strstr(entry->type, "fixed"))) { ast_cdr_format_var(cdr, cdrname, &value, workspace, sizeof(workspace), 1); - } else if (!strcmp(cdrname, "start")) { + } else if (!strcmp(cdrname, "start") || !strcmp(cdrname, "answer") || + !strcmp(cdrname, "end")) { struct ast_tm tm; char timestr[128]; ast_localtime(&cdr->start, &tm, ast_str_strlen(cdrzone) ? ast_str_buffer(cdrzone) : NULL); @@ -364,7 +363,7 @@ static void free_strings(void) } static int my_unload_module(int reload) -{ +{ struct column *entry; ast_cli_unregister_multiple(cdr_mysql_status_cli, sizeof(cdr_mysql_status_cli) / sizeof(struct ast_cli_entry)); From 55567ee1d893b353906a3d1406d85ee9e904e415 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 13 Sep 2017 15:14:25 -0400 Subject: [PATCH 1487/1578] res_calendar: Plug memory leak and micro-optimization ast_variables_destroy is NULL safe, so there is no need to check its argument before passing it. ASTERISK-25524 #close Reported by: Jesper Change-Id: Ib0f8057642e9d471960f1a79fd42e5a3ce587d3b --- res/res_calendar.c | 5 +---- res/res_calendar_caldav.c | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/res/res_calendar.c b/res/res_calendar.c index bf385dba692..3369f38cef4 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -339,10 +339,7 @@ static void calendar_destructor(void *obj) } ast_calendar_clear_events(cal); ast_string_field_free_memory(cal); - if (cal->vars) { - ast_variables_destroy(cal->vars); - cal->vars = NULL; - } + ast_variables_destroy(cal->vars); ao2_ref(cal->events, -1); ao2_unlock(cal); } diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c index b6822b0854d..248c80e6544 100644 --- a/res/res_calendar_caldav.c +++ b/res/res_calendar_caldav.c @@ -78,6 +78,7 @@ static void caldav_destructor(void *obj) if (pvt->session) { ne_session_destroy(pvt->session); } + ne_uri_free(&pvt->uri); ast_string_field_free_memory(pvt); ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); From 56f0d5fc0f25b82d0e5a95f7de58f52261ebc118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 19 Sep 2017 08:34:28 -0300 Subject: [PATCH 1488/1578] res_config_pgsql: Add missing \n in debug log and update copyright year Change-Id: I4ba338ecbdecc6a814a902eddc4121c8ef3cda58 --- res/res_config_pgsql.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 536c9e17331..332b35d6cd9 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999 - 2016, Digium, Inc. + * Copyright (C) 1999 - 2017, Digium, Inc. * * Manuel Guesdon - PostgreSQL RealTime Driver Author/Adaptor * Mark Spencer - Asterisk Author @@ -1035,7 +1035,7 @@ static int store_pgsql(const char *database, const char *table, const struct ast numrows = atoi(PQcmdTuples(result)); ast_mutex_unlock(&pgsql_lock); - ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s.", table); + ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s.\n", table); /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html * An integer greater than zero indicates the number of rows affected From 6fd3db51e878f679851afd9e12c14dc5dc7d7276 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 19 Sep 2017 12:53:41 +0000 Subject: [PATCH 1489/1578] app_confbridge: Only create a channel that records audio. This change makes it so that the conference recorder channel that is created only contains audio formats and an audio stream. This is because the underlying application used by ConfBridge to record, MixMonitor, only allows recording audio. Having additional streams (and in particular a video stream) can result in clients needlessly renegotiating to add a video stream that will never receive video. Change-Id: I89d38aedc9205eca7741d5435e73e73bb9de97a0 --- apps/confbridge/conf_chan_record.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/confbridge/conf_chan_record.c b/apps/confbridge/conf_chan_record.c index 5d3a7dbbe7c..239fb912c86 100644 --- a/apps/confbridge/conf_chan_record.c +++ b/apps/confbridge/conf_chan_record.c @@ -65,7 +65,7 @@ static struct ast_channel *rec_request(const char *type, struct ast_format_cap * if (!capabilities) { return NULL; } - ast_format_cap_append_by_type(capabilities, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_by_type(capabilities, AST_MEDIA_TYPE_AUDIO); chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CBRec/%s-%08x", From a5f1d58fe1a5fe14061afc879872ed033e089880 Mon Sep 17 00:00:00 2001 From: "David J. Pryke" Date: Tue, 19 Sep 2017 10:34:01 -0400 Subject: [PATCH 1490/1578] chan_sip: Expose read-only access to the full SIP INVITE Request-URI Provide a way to get the contents of the the Request URI from the initial SIP INVITE in dial plan function call. (In this case "${CHANNEL(ruri)}") ASTERISK-27278 Reported by: David J. Pryke Tested by: David J. Pryke Change-Id: I1dd4d6988eed1b6c98a9701e0e833a15ef0dac3e --- channels/sip/dialplan_functions.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/channels/sip/dialplan_functions.c b/channels/sip/dialplan_functions.c index 59e841df478..36d4ea9e40c 100644 --- a/channels/sip/dialplan_functions.c +++ b/channels/sip/dialplan_functions.c @@ -41,6 +41,9 @@ R/O Get the URI from the Contact: header. + + R/O Get the Request-URI from the INVITE header. + R/O Get the useragent. @@ -162,6 +165,9 @@ int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *p ast_copy_string(buf, p->from, buflen); } else if (!strcasecmp(args.param, "uri")) { ast_copy_string(buf, p->uri, buflen); + } else if (!strcasecmp(args.param, "ruri")) { + char *tmpruri = REQ_OFFSET_TO_STR(&p->initreq, rlpart2); + ast_copy_string(buf, tmpruri, buflen); } else if (!strcasecmp(args.param, "useragent")) { ast_copy_string(buf, p->useragent, buflen); } else if (!strcasecmp(args.param, "peername")) { From b748038230eff01d592df6fe2bdb392f600577c0 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 19 Sep 2017 09:38:30 -0600 Subject: [PATCH 1491/1578] res_pjsip_pubsub: Check for Content-Type header in rx_notify_request pubsub_on_rx_notify_request wasn't checking for a null Content-Type header before checking that it was application/simple-message-summary. ASTERISK-27279 Reported by: Ross Beer Change-Id: Iec2a6c4d2e74af37ff779ecc9fd35644c5c4ea52 --- res/res_pjsip_pubsub.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 81b25ac2e4e..b0365d9d44b 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -3524,10 +3524,12 @@ static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata) return PJ_TRUE; } +static pjsip_media_type simple_message_summary; + static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata) { - if (pj_stricmp2(&rdata->msg_info.msg->body->content_type.type, "application") == 0 && - pj_stricmp2(&rdata->msg_info.msg->body->content_type.subtype, "simple-message-summary") == 0) { + if (rdata->msg_info.msg->body && + pjsip_media_type_cmp(&rdata->msg_info.msg->body->content_type, &simple_message_summary, 0) == 0) { return pubsub_on_rx_mwi_notify_request(rdata); } return PJ_FALSE; @@ -5363,6 +5365,8 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } + pjsip_media_type_init2(&simple_message_summary, "application", "simple-message-summary"); + if (ast_sched_start_thread(sched)) { ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n"); ast_sched_context_destroy(sched); From 1e4c1cec7fcaf1730c8176e44aaf51fdccdb70da Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Mon, 18 Sep 2017 16:51:15 +0200 Subject: [PATCH 1492/1578] res_srtp: lower log level of auth failures Previously, sRTP authentication failures were reported on log level WARNING. When such failures happen, each RT(C)P packet is affected, spamming the log. Now, those failures are reported at log level VERBOSE 2. Furthermore, the amount is further reduced (previously all two seconds, now all three seconds). Additionally, the new log entry informs whether media (RTP) or statistics (RTCP) are affected. ASTERISK-16898 #close Change-Id: I6c98d46b711f56e08655abeb01c951ab8e8d7fa0 --- res/res_srtp.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/res/res_srtp.c b/res/res_srtp.c index caedfb6c879..295c332e26e 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -446,11 +446,26 @@ static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rt } if (res != err_status_ok && res != err_status_replay_fail ) { - if ((srtp->warned >= 10) && !((srtp->warned - 10) % 100)) { - ast_log(AST_LOG_WARNING, "SRTP unprotect failed with: %s %d\n", srtp_errstr(res), srtp->warned); - srtp->warned = 11; + /* + * Authentication failures happen when an active attacker tries to + * insert malicious RTP packets. Furthermore, authentication failures + * happen, when the other party encrypts the sRTP data in an unexpected + * way. This happens quite often with RTCP. Therefore, when you see + * authentication failures, try to identify the implementation + * (author and product name) used by your other party. Try to investigate + * whether they use a custom library or an outdated version of libSRTP. + */ + if (rtcp) { + ast_verb(2, "SRTCP unprotect failed on SSRC %u because of %s\n", + ast_rtp_instance_get_ssrc(srtp->rtp), srtp_errstr(res)); } else { - srtp->warned++; + if ((srtp->warned >= 10) && !((srtp->warned - 10) % 150)) { + ast_verb(2, "SRTP unprotect failed on SSRC %u because of %s %d\n", + ast_rtp_instance_get_ssrc(srtp->rtp), srtp_errstr(res), srtp->warned); + srtp->warned = 11; + } else { + srtp->warned++; + } } errno = EAGAIN; return -1; From 6b7d5671d1c8b12f1fc968eeb34898e762c1fb1f Mon Sep 17 00:00:00 2001 From: Jean Aunis Date: Thu, 7 Sep 2017 11:41:09 +0200 Subject: [PATCH 1493/1578] bridge : Fix one-way direct-media when early bridging with native_rtp When two channels were early bridged in a native_rtp bridge, the RTP description on one side was not updated when the other side answered. This patch forbids non-answered channels to enter a native_rtp bridge, and triggers a bridge reconfiguration when an ANSWER frame is received. ASTERISK-27257 Change-Id: If1aaee1b4ed9658a1aa91ab715ee0a6413b878df --- bridges/bridge_native_rtp.c | 3 ++- include/asterisk/bridge_technology.h | 4 +++- main/bridge_channel.c | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index a46b4202771..edbfe5858e9 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -598,7 +598,8 @@ static int native_rtp_framehook_consume(void *data, enum ast_frame_type type) */ static int native_rtp_bridge_capable(struct ast_channel *chan) { - return !ast_channel_has_hook_requiring_audio(chan); + return !ast_channel_has_hook_requiring_audio(chan) + && ast_channel_state(chan) == AST_STATE_UP; } /*! diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridge_technology.h index def7b19335f..eaea28de530 100644 --- a/include/asterisk/bridge_technology.h +++ b/include/asterisk/bridge_technology.h @@ -108,11 +108,13 @@ struct ast_bridge_technology { * * \note On entry, bridge is already locked. * - * \note The bridge technology must tollerate a failed to join channel + * \note The bridge technology must tolerate a failed to join channel * until it can be kicked from the bridge. * * \note A channel may be in a suspended state already when joining a bridge * technology. The technology must handle this case. + * + * \note A channel may not be answered when joining a bridge technology. */ int (*join)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); /*! diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 66292bf9212..89e55713fba 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -2313,6 +2313,10 @@ static void bridge_channel_handle_control(struct ast_bridge_channel *bridge_chan case AST_CONTROL_ANSWER: if (ast_channel_state(chan) != AST_STATE_UP) { ast_answer(chan); + ast_bridge_channel_lock_bridge(bridge_channel); + bridge_channel->bridge->reconfigured = 1; + bridge_reconfigured(bridge_channel->bridge, 0); + ast_bridge_unlock(bridge_channel->bridge); } else { ast_indicate(chan, -1); } From b6aa728a584ea857fc2b33b8d50348c283ffa185 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 19 Sep 2017 04:44:28 -0600 Subject: [PATCH 1494/1578] chan_pjsip: Ignore AST_CONTROL_STREAM_TOPOLOGY_CHANGED for now chan_pjsip_indicate was missing a case for the recently added AST_CONTROL_STREAM_TOPOLOGY_CHANGED condition and was returning an error and causing the call to be hung up instead of just ignoring it. ASTERISK-27260 Reported by: Daniel Heckl Change-Id: I4fecbb00a0b8a853da85155065c1a6bddf235e80 --- channels/chan_pjsip.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 841654c927a..84b508b6117 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1738,6 +1738,8 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi topology = data; res = handle_topology_request_change(channel->session, topology); break; + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + break; case -1: res = -1; break; From e666051d790bb2a9d1e9ff6bb11bd69db6e0efba Mon Sep 17 00:00:00 2001 From: Ben Ford Date: Fri, 15 Sep 2017 09:43:21 -0500 Subject: [PATCH 1495/1578] res_pjsip_session: Check for removed stream state. When a sip session is refreshed, the stream topology is looped through, checking each stream for compatible formats. This would cause a crash if the stream state was AST_STREAM_STATE_REMOVED, since the formats would never be set for this stream, causing a NULL value to be returned from ast_stream_get_formats. This commit adds a check for streams with removed states. Also removed a stray semicolon. Change-Id: Ic86f8b65a4a26a60885b28b8b1a0b22e1b471d42 --- main/bridge.c | 2 +- res/res_pjsip_sdp_rtp.c | 2 +- res/res_pjsip_session.c | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/main/bridge.c b/main/bridge.c index ab12ecf6466..5d9c0c1f756 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -1741,7 +1741,7 @@ int ast_bridge_join(struct ast_bridge *bridge, ao2_ref(bridge_channel, -1); -join_exit:; +join_exit: ast_bridge_run_after_callback(chan); bridge_channel_impart_signal(chan); if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index e095f06604c..8ec57aa8e1e 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1338,7 +1338,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as media->desc.port = 0; media->desc.port_count = 1; - if (remote) { + if (remote && remote->media[ast_stream_get_position(stream)]) { pjmedia_sdp_media *remote_media = remote->media[ast_stream_get_position(stream)]; int index; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 64416a0636f..77ddfbc146b 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1455,6 +1455,10 @@ int ast_sip_session_refresh(struct ast_sip_session *session, continue; } + /* No need to do anything with stream if it's media state is removed */ + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + continue; + } /* Enforce the configured allowed codecs on audio and video streams */ if (ast_stream_get_type(stream) == AST_MEDIA_TYPE_AUDIO || ast_stream_get_type(stream) == AST_MEDIA_TYPE_VIDEO) { @@ -1465,14 +1469,12 @@ int ast_sip_session_refresh(struct ast_sip_session *session, ast_sip_session_media_state_free(media_state); return 0; } - ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap); if (!ast_format_cap_count(joint_cap)) { ao2_ref(joint_cap, -1); - ast_sip_session_media_state_free(media_state); - return 0; + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + continue; } - ast_stream_set_formats(stream, joint_cap); } From cad68137a7f461a9308a0b53ab1ac86482206a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 19 Sep 2017 07:22:50 -0300 Subject: [PATCH 1496/1578] res_config_pgsql: Fix removed support to previous for versions PostgreSQL 9.1 In PostgreSQL 9.1 the backslash are string literals and not the escape of characters. In previous issue ASTERISK_26057 was fixed the use of escape LIKE but the support for old version of Postgresql than 9.1 was dropped. The sentence before make was "ESCAPE '\'" but in version before than 9.1 need it to be as follow "ESCAPE '\\'". ASTERISK-27283 Change-Id: I96d9ee1ed7693ab17503cb36a9cd72847165f949 --- res/res_config_pgsql.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 536c9e17331..2310f39def4 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -52,6 +52,7 @@ AST_THREADSTORAGE(semibuf_buf); static PGconn *pgsqlConn = NULL; static int version; #define has_schema_support (version > 70300 ? 1 : 0) +#define USE_BACKSLASH_AS_STRING (version >= 90100 ? 1 : 0) #define MAX_DB_OPTION_SIZE 64 @@ -384,7 +385,7 @@ static struct columns *find_column(struct tables *t, const char *colname) } #define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE")) -static char *ESCAPE_CLAUSE = " ESCAPE '\\'"; +#define ESCAPE_CLAUSE (USE_BACKSLASH_AS_STRING ? " ESCAPE '\\'" : " ESCAPE '\\\\'") static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields) { From 971548405bd82746229cad4958b10707e759816e Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 20 Sep 2017 09:45:16 -0600 Subject: [PATCH 1497/1578] res_pjsip_session: Change some asserts to warning/debug messages There was an issue reported where an SDP received on a 183 Session Progress message caused a crash because the pending streams had already been processed when the OK was received. In that case the pending topology was legitimately NULL. There was an assert for an incorrect number of streams in the topology but not one for topology being NULL. In any case, if you're not in dev-mode the asserts don't do anything and since the scenario is legit, the asserts weren't appropriate anyway. * Changed several asserts to warning or debug messages and return codes as appropriate. ASTERISK-27264 Reported by: Daniel Heckl Change-Id: I58daaa9d2938fa980857ab3ec41925ab5ff9c848 --- res/res_pjsip_session.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 64416a0636f..978c95a0c4c 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -277,7 +277,11 @@ int ast_sip_session_is_pending_stream_default(const struct ast_sip_session *sess { int index; - ast_assert(session->pending_media_state->topology != NULL); + if (!session->pending_media_state->topology) { + ast_log(LOG_WARNING, "Pending topology was NULL for channel '%s'\n", + session->channel ? ast_channel_name(session->channel) : "unknown"); + return 0; + } if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { return 0; @@ -766,6 +770,30 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ int i; struct ast_stream_topology *topology; + /* This situation can legitimately happen when an SDP is received in a + * 183 Session Progress message. In that case, everything's been done + * by the time this function is called and there are no more pending + * streams. + */ + if (!session->pending_media_state->topology) { + ast_debug(1, "Pending topology was NULL for channel '%s'\n", + session->channel ? ast_channel_name(session->channel) : "unknown"); + return 0; + } + + /* If we're handling negotiated streams, then we should already have set + * up session media instances (and Asterisk streams) that correspond to + * the local SDP, and there should be the same number of session medias + * and streams as there are local SDP streams + */ + if (ast_stream_topology_get_count(session->pending_media_state->topology) != local->media_count + || AST_VECTOR_SIZE(&session->pending_media_state->sessions) != local->media_count) { + ast_log(LOG_WARNING, "Local SDP for channel '%s' contains %d media streams while we expected it to contain %u\n", + session->channel ? ast_channel_name(session->channel) : "unknown", + ast_stream_topology_get_count(session->pending_media_state->topology), local->media_count); + return -1; + } + for (i = 0; i < local->media_count; ++i) { struct ast_sip_session_media *session_media; struct ast_stream *stream; @@ -774,14 +802,6 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ continue; } - /* If we're handling negotiated streams, then we should already have set - * up session media instances (and Asterisk streams) that correspond to - * the local SDP, and there should be the same number of session medias - * and streams as there are local SDP streams - */ - ast_assert(i < AST_VECTOR_SIZE(&session->pending_media_state->sessions)); - ast_assert(i < ast_stream_topology_get_count(session->pending_media_state->topology)); - session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i); stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i); @@ -816,9 +836,6 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ continue; } - ast_assert(i < AST_VECTOR_SIZE(&session->pending_media_state->sessions)); - ast_assert(i < ast_stream_topology_get_count(session->pending_media_state->topology)); - session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, i); stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i); From f2985e310663b67ccc948515efeae500bdf94a0c Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sat, 16 Sep 2017 11:19:59 -0300 Subject: [PATCH 1498/1578] bridge: Change participant SFU streams when source streams change. Some endpoints do not like a stream being reused for a new media stream. The frame/jitterbuffer can rely on underlying attributes of the media stream in order to order the packets. When a new stream takes its place without any notice the buffer can get confused and the media ends up getting dropped. This change uses the SSRC change to determine that a new source is reusing an existing stream and then bridge_softmix renegotiates each participant such that they see a new media stream. This causes the frame/jitterbuffer to start fresh and work as expected. ASTERISK-27277 Change-Id: I30ccbdba16ca073d7f31e0e59ab778c153afae07 --- bridges/bridge_softmix.c | 135 +++++++++++++++++++++++++-- channels/chan_iax2.c | 1 + channels/chan_pjsip.c | 2 + funcs/func_frame_trace.c | 3 + include/asterisk/frame.h | 1 + include/asterisk/res_pjsip_session.h | 2 + main/channel.c | 2 + res/res_pjsip_sdp_rtp.c | 13 +++ res/res_pjsip_session.c | 12 ++- 9 files changed, 162 insertions(+), 9 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 59b16b78ed5..5e0a4856ff5 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -79,7 +79,7 @@ struct softmix_stats { struct softmix_translate_helper_entry { int num_times_requested; /*!< Once this entry is no longer requested, free the trans_pvt - and re-init if it was usable. */ + and re-init if it was usable. */ struct ast_format *dst_format; /*!< The destination format for this helper */ struct ast_trans_pvt *trans_pvt; /*!< the translator for this slot. */ struct ast_frame *out_frame; /*!< The output frame from the last translation */ @@ -493,21 +493,21 @@ static int append_source_streams(struct ast_stream_topology *dest, for (i = 0; i < ast_stream_topology_get_count(source); ++i) { struct ast_stream *stream; struct ast_stream *stream_clone; - char *stream_clone_name; - size_t stream_clone_name_len; + char *stream_clone_name = NULL; stream = ast_stream_topology_get_stream(source, i); if (!is_video_source(stream)) { continue; } - /* The +3 is for the two underscore separators and null terminator */ - stream_clone_name_len = SOFTBRIDGE_VIDEO_DEST_LEN + strlen(channel_name) + strlen(ast_stream_get_name(stream)) + 3; - stream_clone_name = ast_alloca(stream_clone_name_len); - snprintf(stream_clone_name, stream_clone_name_len, "%s_%s_%s", SOFTBRIDGE_VIDEO_DEST_PREFIX, - channel_name, ast_stream_get_name(stream)); + if (ast_asprintf(&stream_clone_name, "%s_%s_%s", SOFTBRIDGE_VIDEO_DEST_PREFIX, + channel_name, ast_stream_get_name(stream)) < 0) { + ast_free(stream_clone_name); + return -1; + } stream_clone = ast_stream_clone(stream, stream_clone_name); + ast_free(stream_clone_name); if (!stream_clone) { return -1; } @@ -987,6 +987,120 @@ static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bri } } +static int remove_all_original_streams(struct ast_stream_topology *dest, + const struct ast_stream_topology *source, + const struct ast_stream_topology *original) +{ + int i; + + for (i = 0; i < ast_stream_topology_get_count(source); ++i) { + struct ast_stream *stream; + int original_index; + + stream = ast_stream_topology_get_stream(source, i); + + /* Mark the existing stream as removed so we get a new one, this will get + * reused on a subsequent renegotiation. + */ + for (original_index = 0; original_index < ast_stream_topology_get_count(original); ++original_index) { + struct ast_stream *original_stream = ast_stream_topology_get_stream(original, original_index); + + if (!strcmp(ast_stream_get_name(stream), ast_stream_get_name(original_stream))) { + struct ast_stream *removed; + + /* Since the participant is still going to be in the bridge we + * change the name so that routing does not attempt to route video + * to this stream. + */ + removed = ast_stream_clone(stream, "removed"); + if (!removed) { + return -1; + } + + ast_stream_set_state(removed, AST_STREAM_STATE_REMOVED); + + /* The destination topology can only ever contain the same, or more, + * streams than the original so this is safe. + */ + if (ast_stream_topology_set_stream(dest, original_index, removed)) { + ast_stream_free(removed); + return -1; + } + + break; + } + } + } + + return 0; +} + +static void sfu_topologies_on_source_change(struct ast_bridge_channel *source, struct ast_bridge_channels_list *participants) +{ + struct ast_stream_topology *source_video = NULL; + struct ast_bridge_channel *participant; + int res; + + source_video = ast_stream_topology_alloc(); + if (!source_video) { + return; + } + + ast_channel_lock(source->chan); + res = append_source_streams(source_video, ast_channel_name(source->chan), ast_channel_get_stream_topology(source->chan)); + ast_channel_unlock(source->chan); + if (res) { + goto cleanup; + } + + AST_LIST_TRAVERSE(participants, participant, entry) { + struct ast_stream_topology *original_topology; + struct ast_stream_topology *participant_topology; + + if (participant == source) { + continue; + } + + ast_channel_lock(participant->chan); + original_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(participant->chan)); + ast_channel_unlock(participant->chan); + if (!original_topology) { + goto cleanup; + } + + participant_topology = ast_stream_topology_clone(original_topology); + if (!participant_topology) { + ast_stream_topology_free(original_topology); + goto cleanup; + } + + /* We add all the source streams back in, if any removed streams are already present they will + * get used first followed by appending new ones. + */ + if (append_all_streams(participant_topology, source_video)) { + ast_stream_topology_free(participant_topology); + ast_stream_topology_free(original_topology); + goto cleanup; + } + + /* And the original existing streams get marked as removed. This causes the remote side to see + * a new stream for the source streams. + */ + if (remove_all_original_streams(participant_topology, source_video, original_topology)) { + ast_stream_topology_free(participant_topology); + ast_stream_topology_free(original_topology); + goto cleanup; + } + + ast_channel_request_stream_topology_change(participant->chan, participant_topology, NULL); + ast_stream_topology_free(participant_topology); + ast_stream_topology_free(original_topology); + } + +cleanup: + ast_stream_topology_free(source_video); +} + /*! * \internal * \brief Determine what to do with a control frame. @@ -1016,6 +1130,11 @@ static int softmix_bridge_write_control(struct ast_bridge *bridge, struct ast_br softmix_data->last_video_update = ast_tvnow(); } break; + case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED: + if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU) { + sfu_topologies_on_source_change(bridge_channel, &bridge->channels); + } + break; default: break; } diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 490c4cea51c..04aa228bfaf 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1433,6 +1433,7 @@ static int iax2_is_control_frame_allowed(int subtype) /* Intended only for internal stream topology manipulation. */ case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: /* Intended only for internal stream topology change notification. */ + case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED: case AST_CONTROL_STREAM_STOP: case AST_CONTROL_STREAM_SUSPEND: case AST_CONTROL_STREAM_RESTART: diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 84b508b6117..7520c2b0ec9 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1740,6 +1740,8 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi break; case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: break; + case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED: + break; case -1: res = -1; break; diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c index 49abfdf140b..e88cafaf6e6 100644 --- a/funcs/func_frame_trace.c +++ b/funcs/func_frame_trace.c @@ -342,6 +342,9 @@ static void print_frame(struct ast_frame *frame) case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: ast_verbose("SubClass: STREAM_TOPOLOGY_CHANGED\n"); break; + case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED: + ast_verbose("SubClass: STREAM_TOPOLOGY_SOURCE_CHANGED\n"); + break; case AST_CONTROL_STREAM_STOP: ast_verbose("SubClass: STREAM_STOP\n"); break; diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 8f0daccb702..eb6a6479a5d 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -301,6 +301,7 @@ enum ast_control_frame_type { AST_CONTROL_MASQUERADE_NOTIFY = 34, /*!< A masquerade is about to begin/end. (Never sent as a frame but directly with ast_indicate_data().) */ AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE = 35, /*!< Channel indication that a stream topology change has been requested */ AST_CONTROL_STREAM_TOPOLOGY_CHANGED = 36, /*!< Channel indication that a stream topology change has occurred */ + AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED = 37, /*!< Channel indication that one of the source streams has changed its source */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index d5b6fa194e8..fcb14b79d91 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -109,6 +109,8 @@ struct ast_sip_session_media { char mslabel[AST_UUID_STR_LEN]; /*! \brief Track label */ char label[AST_UUID_STR_LEN]; + /*! \brief The underlying session has been changed in some fashion */ + unsigned int changed; }; /*! diff --git a/main/channel.c b/main/channel.c index 74de9caac8f..ecc771c1d9a 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4228,6 +4228,7 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con case AST_CONTROL_MASQUERADE_NOTIFY: case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED: case AST_CONTROL_STREAM_STOP: case AST_CONTROL_STREAM_SUSPEND: case AST_CONTROL_STREAM_REVERSE: @@ -4528,6 +4529,7 @@ static int indicate_data_internal(struct ast_channel *chan, int _condition, cons case AST_CONTROL_UPDATE_RTP_PEER: case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED: case AST_CONTROL_STREAM_STOP: case AST_CONTROL_STREAM_SUSPEND: case AST_CONTROL_STREAM_REVERSE: diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index e095f06604c..88b94ee43f6 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1022,6 +1022,19 @@ static void process_ssrc_attributes(struct ast_sip_session *session, struct ast_ continue; } + /* If we are currently negotiating as a result of the remote side renegotiating then + * determine if the source for this stream has changed. + */ + if (pjmedia_sdp_neg_get_state(session->inv_session->neg) == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER && + session->active_media_state) { + struct ast_rtp_instance_stats stats = { 0, }; + + if (!ast_rtp_instance_get_stats(session_media->rtp, &stats, AST_RTP_INSTANCE_STAT_REMOTE_SSRC) && + stats.remote_ssrc != ssrc) { + session_media->changed = 1; + } + } + ast_rtp_instance_set_remote_ssrc(session_media->rtp, ssrc); } } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 64416a0636f..4b3bdb81287 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -765,6 +765,7 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ { int i; struct ast_stream_topology *topology; + unsigned int changed = 0; for (i = 0; i < local->media_count; ++i) { struct ast_sip_session_media *session_media; @@ -802,6 +803,9 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ if (handle_negotiated_sdp_session_media(session_media, session, local, remote, i, stream)) { return -1; } + + changed |= session_media->changed; + session_media->changed = 0; } /* Apply the pending media state to the channel and make it active */ @@ -858,7 +862,13 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ ast_channel_unlock(session->channel); - ast_queue_frame(session->channel, &ast_null_frame); + if (changed) { + struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED }; + + ast_queue_frame(session->channel, &f); + } else { + ast_queue_frame(session->channel, &ast_null_frame); + } return 0; } From 7c93982e9d8d11f615b99602637eafa5d6bd35a7 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 19 Sep 2017 14:28:37 -0500 Subject: [PATCH 1499/1578] res_rtp_asterisk.c: Fix bundled SSRC handling. Assertions in the v15+ AST-2017-008 patches found that we were not handling the case if the incoming SDP did not specify the required SSRC attributes for bundled to work. * Be strict on matching SSRC for bundled instances including the parent instance. If the SSRC doesn't match then discard the packet. Bundled has to tell us in the SDP signaling what SSRC to expect. Otherwise, we will not know how to find the bundled instance structure. Change-Id: I152830bbff71c662408909042068fada39e617f9 --- res/res_rtp_asterisk.c | 98 ++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 1440eb0e199..c8cc04f96c8 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -257,6 +257,8 @@ struct ice_wrap { struct rtp_ssrc_mapping { /*! \brief The received SSRC */ unsigned int ssrc; + /*! True if the SSRC is available. Otherwise, this is a placeholder mapping until the SSRC is set. */ + unsigned int ssrc_valid; /*! \brief The RTP instance this SSRC belongs to*/ struct ast_rtp_instance *instance; }; @@ -3344,7 +3346,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, * \return 0 if element does not match. * \return Non-zero if element matches. */ -#define SSRC_MAPPING_ELEM_CMP(elem, value) (elem.instance == value) +#define SSRC_MAPPING_ELEM_CMP(elem, value) ((elem).instance == (value)) /*! \pre instance is locked */ static int ast_rtp_destroy(struct ast_rtp_instance *instance) @@ -4788,18 +4790,26 @@ static struct ast_rtp_instance *rtp_find_instance_by_ssrc(struct ast_rtp_instanc struct ast_rtp *rtp, unsigned int ssrc) { int index; - struct ast_rtp_instance *found = instance; + if (!AST_VECTOR_SIZE(&rtp->ssrc_mapping)) { + /* This instance is not bundled */ + return instance; + } + + /* Find the bundled child instance */ for (index = 0; index < AST_VECTOR_SIZE(&rtp->ssrc_mapping); ++index) { struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&rtp->ssrc_mapping, index); - if (mapping->ssrc == ssrc) { - found = mapping->instance; - break; + if (mapping->ssrc_valid && mapping->ssrc == ssrc) { + return mapping->instance; } } - return found; + /* Does the SSRC match the bundled parent? */ + if (rtp->themssrc_valid && rtp->themssrc == ssrc) { + return instance; + } + return NULL; } static const char *rtcp_payload_type2str(unsigned int pt) @@ -5040,7 +5050,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c /* Determine the appropriate instance for this */ if (ssrc_valid) { child = rtp_find_instance_by_ssrc(transport, transport_rtp, ssrc); - if (child != transport) { + if (child && child != transport) { /* * It is safe to hold the child lock while holding the parent lock. * We guarantee that the locking order is always parent->child or @@ -5551,6 +5561,10 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* Determine the appropriate instance for this */ child = rtp_find_instance_by_ssrc(instance, rtp, ssrc); + if (!child) { + /* Neither the bundled parent nor any child has this SSRC */ + return &ast_null_frame; + } if (child != instance) { /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order * is always parent->child or that the child lock is not held when acquiring the parent lock. @@ -5726,39 +5740,42 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc timestamp = ntohl(rtpheader[1]); AST_LIST_HEAD_INIT_NOLOCK(&frames); - /* Force a marker bit and change SSRC if the SSRC changes */ - if (rtp->themssrc_valid && rtp->themssrc != ssrc) { - struct ast_frame *f, srcupdate = { - AST_FRAME_CONTROL, - .subclass.integer = AST_CONTROL_SRCCHANGE, - }; - if (!mark) { - if (rtpdebug) { - ast_debug(1, "Forcing Marker bit, because SSRC has changed\n"); + /* Only non-bundled instances can change/learn the remote's SSRC implicitly. */ + if (!child && !AST_VECTOR_SIZE(&rtp->ssrc_mapping)) { + /* Force a marker bit and change SSRC if the SSRC changes */ + if (rtp->themssrc_valid && rtp->themssrc != ssrc) { + struct ast_frame *f, srcupdate = { + AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_SRCCHANGE, + }; + + if (!mark) { + if (rtpdebug) { + ast_debug(1, "Forcing Marker bit, because SSRC has changed\n"); + } + mark = 1; } - mark = 1; - } - f = ast_frisolate(&srcupdate); - AST_LIST_INSERT_TAIL(&frames, f, frame_list); + f = ast_frisolate(&srcupdate); + AST_LIST_INSERT_TAIL(&frames, f, frame_list); - rtp->seedrxseqno = 0; - rtp->rxcount = 0; - rtp->rxoctetcount = 0; - rtp->cycles = 0; - rtp->lastrxseqno = 0; - rtp->last_seqno = 0; - rtp->last_end_timestamp = 0; - if (rtp->rtcp) { - rtp->rtcp->expected_prior = 0; - rtp->rtcp->received_prior = 0; + rtp->seedrxseqno = 0; + rtp->rxcount = 0; + rtp->rxoctetcount = 0; + rtp->cycles = 0; + rtp->lastrxseqno = 0; + rtp->last_seqno = 0; + rtp->last_end_timestamp = 0; + if (rtp->rtcp) { + rtp->rtcp->expected_prior = 0; + rtp->rtcp->received_prior = 0; + } } + + rtp->themssrc = ssrc; /* Record their SSRC to put in future RR */ + rtp->themssrc_valid = 1; } - /* Bundled children cannot change/learn their SSRC implicitly. */ - ast_assert(!child || (rtp->themssrc_valid && rtp->themssrc == ssrc)); - rtp->themssrc = ssrc; /* Record their SSRC to put in future RR */ - rtp->themssrc_valid = 1; /* Remove any padding bytes that may be present */ if (padding) { @@ -6520,13 +6537,14 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned return; } + rtp->themssrc = ssrc; + rtp->themssrc_valid = 1; + /* If this is bundled we need to update the SSRC mapping */ if (rtp->bundled) { struct ast_rtp *bundled_rtp; int index; - ast_assert(rtp->themssrc_valid); - ao2_unlock(instance); /* The child lock can't be held while accessing the parent */ @@ -6536,8 +6554,9 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned for (index = 0; index < AST_VECTOR_SIZE(&bundled_rtp->ssrc_mapping); ++index) { struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&bundled_rtp->ssrc_mapping, index); - if (mapping->ssrc == rtp->themssrc) { + if (mapping->instance == instance) { mapping->ssrc = ssrc; + mapping->ssrc_valid = 1; break; } } @@ -6546,9 +6565,6 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned ao2_lock(instance); } - - rtp->themssrc = ssrc; - rtp->themssrc_valid = 1; } static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num) @@ -6601,8 +6617,8 @@ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instanc /* Children maintain a reference to the parent to guarantee that the transport doesn't go away on them */ child_rtp->bundled = ao2_bump(parent); - ast_assert(child_rtp->themssrc_valid); mapping.ssrc = child_rtp->themssrc; + mapping.ssrc_valid = child_rtp->themssrc_valid; mapping.instance = child; ao2_unlock(child); From 6c0e13da221dcc119acd0f8cbcb00d2a61692ee6 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 21 Sep 2017 08:47:11 -0600 Subject: [PATCH 1500/1578] res_pjsip_session/BUNDLE: Handle no audio codecs on endpoint When an INVITE came in with both audio and video streams but there were no audio codecs defined for the endpoint, we weren't declining the audio stream. Since it's usually the first/transport stream, when the video stream was processed and tried to use the transport, it was empty and caused a crash. We now decline the the stream if there are no matching codecs so when the video stream is processed, it's now the first/transport stream and processes normally. Change-Id: Ic854eda54c95031e66b076ecfae3041d34daa692 --- res/res_pjsip_session.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 163c2b8681e..d50937fd44f 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -549,6 +549,16 @@ static int set_mid_and_bundle_group(struct ast_sip_session *session, return 0; } +static void remove_stream_from_bundle(struct ast_sip_session_media *session_media, + struct ast_stream *stream) +{ + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + ast_free(session_media->mid); + session_media->mid = NULL; + session_media->bundle_group = -1; + session_media->bundled = 0; +} + static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp) { int i; @@ -611,9 +621,7 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd if (!remote_stream->desc.port || is_stream_limitation_reached(type, session->endpoint, type_streams)) { ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n", ast_codec_media_type2str(type), i); - ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); - session_media->bundle_group = -1; - session_media->bundled = 0; + remove_stream_from_bundle(session_media, stream); continue; } @@ -628,6 +636,11 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd if (res < 0) { /* Catastrophic failure. Abort! */ return -1; + } else if (res == 0) { + ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n", + ast_codec_media_type2str(type), i); + remove_stream_from_bundle(session_media, stream); + continue; } else if (res > 0) { ast_debug(1, "Media stream '%s' handled by %s\n", ast_codec_media_type2str(session_media->type), @@ -655,8 +668,12 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd if (res < 0) { /* Catastrophic failure. Abort! */ return -1; - } - if (res > 0) { + } else if (res == 0) { + ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n", + ast_codec_media_type2str(type), i); + remove_stream_from_bundle(session_media, stream); + continue; + } else if (res > 0) { ast_debug(1, "Media stream '%s' handled by %s\n", ast_codec_media_type2str(session_media->type), handler->id); From ebd0a4bebf7ffc143800de47e52b9e46dd630aac Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Fri, 22 Sep 2017 11:02:11 -0400 Subject: [PATCH 1501/1578] res_pjsip: Use ast_sip_is_content_type() where appropriate Change-Id: If3ab0d73d79ac4623308bd48508af2bfd554937d --- res/res_pjsip_messaging.c | 4 ++-- res/res_pjsip_publish_asterisk.c | 6 ++---- res/res_pjsip_pubsub.c | 15 ++++++--------- res/res_pjsip_session.c | 5 +++-- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index d31e10129c1..b6e7a64c368 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -69,8 +69,8 @@ static enum pjsip_status_code check_content_type(const pjsip_rx_data *rdata) &rdata->msg_info.msg->body->content_type, "text", "plain"); } else { res = rdata->msg_info.ctype && - !pj_strcmp2(&rdata->msg_info.ctype->media.type, "text") && - !pj_strcmp2(&rdata->msg_info.ctype->media.subtype, "plain"); + ast_sip_is_content_type( + &rdata->msg_info.ctype->media, "text", "plain"); } return res ? PJSIP_SC_OK : PJSIP_SC_UNSUPPORTED_MEDIA_TYPE; diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 7e87762fd34..fa5e4ced710 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -605,8 +605,7 @@ static int asterisk_publication_devicestate_state_change(struct ast_sip_publicat } /* We only accept JSON for content */ - if (pj_strcmp2(&body->content_type.type, "application") || - pj_strcmp2(&body->content_type.subtype, "json")) { + if (!ast_sip_is_content_type(&body->content_type, "application", "json")) { ast_debug(2, "Received unsupported content type for Asterisk event on resource '%s'\n", ast_sorcery_object_get_id(config)); return -1; @@ -697,8 +696,7 @@ static int asterisk_publication_mwi_state_change(struct ast_sip_publication *pub } /* We only accept JSON for content */ - if (pj_strcmp2(&body->content_type.type, "application") || - pj_strcmp2(&body->content_type.subtype, "json")) { + if (!ast_sip_is_content_type(&body->content_type, "application", "json")) { ast_debug(2, "Received unsupported content type for Asterisk event on resource '%s'\n", ast_sorcery_object_get_id(config)); return -1; diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index b0365d9d44b..bcf8677284c 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -516,6 +516,8 @@ AST_RWLIST_HEAD_STATIC(subscriptions, sip_subscription_tree); AST_RWLIST_HEAD_STATIC(body_generators, ast_sip_pubsub_body_generator); AST_RWLIST_HEAD_STATIC(body_supplements, ast_sip_pubsub_body_supplement); +static pjsip_media_type rlmi_media_type; + static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event); static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body); @@ -2022,8 +2024,6 @@ static void *rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len) static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *body_parts, unsigned int full_state) { - static const pj_str_t rlmi_type = { "application", 11 }; - static const pj_str_t rlmi_subtype = { "rlmi+xml", 8 }; pj_xml_node *rlmi; pj_xml_node *name; pjsip_multipart_part *rlmi_part; @@ -2054,9 +2054,7 @@ static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_sub rlmi_part = pjsip_multipart_create_part(pool); rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body); - pj_strdup(pool, &rlmi_part->body->content_type.type, &rlmi_type); - pj_strdup(pool, &rlmi_part->body->content_type.subtype, &rlmi_subtype); - pj_list_init(&rlmi_part->body->content_type.param); + pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &rlmi_media_type); rlmi_part->body->data = pj_xml_clone(pool, rlmi); rlmi_part->body->clone_data = rlmi_clone_data; @@ -3524,12 +3522,11 @@ static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata) return PJ_TRUE; } -static pjsip_media_type simple_message_summary; - static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata) { if (rdata->msg_info.msg->body && - pjsip_media_type_cmp(&rdata->msg_info.msg->body->content_type, &simple_message_summary, 0) == 0) { + ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type, + "application", "simple-message-summary")) { return pubsub_on_rx_mwi_notify_request(rdata); } return PJ_FALSE; @@ -5365,7 +5362,7 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - pjsip_media_type_init2(&simple_message_summary, "application", "simple-message-summary"); + pjsip_media_type_init2(&rlmi_media_type, "application", "rlmi+xml"); if (ast_sched_start_thread(sched)) { ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n"); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 163c2b8681e..c6ea4460aef 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -3979,8 +3979,9 @@ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_trans int stream; /* SDP produced by us directly will never be multipart */ - if (!transport_state || hook || !tdata->msg->body || pj_stricmp2(&tdata->msg->body->content_type.type, "application") || - pj_stricmp2(&tdata->msg->body->content_type.subtype, "sdp") || ast_strlen_zero(transport->external_media_address)) { + if (!transport_state || hook || !tdata->msg->body || + !ast_sip_is_content_type(&tdata->msg->body->content_type, "application", "sdp") || + ast_strlen_zero(transport->external_media_address)) { return; } From 36690c26f88374dbd71aab899479a4dd671d6408 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Fri, 22 Sep 2017 15:29:24 -0500 Subject: [PATCH 1502/1578] res_pjsip_session: Don't end session when receiving a 500 on a reinvite During a reinvite, if a remote endpoint error occurs and it returns a 500 the session would end. This patch makes it so the session is not terminated, but continues as it was. The reason for this is because some endpoints may send non session terminating "server errors" like a failed codec negotiation. So in this case instead of ending the call it can hopefully continue. In the case of a real server error the session is already "doomed", will be known soon enough and appropriately ended by Asterisk later. Change-Id: Ifeedae86b8cb44b92d52c79046522ec5f0aff1d5 --- res/res_pjsip_session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 2beb6dcd508..e25ba0aebe2 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -3485,8 +3485,8 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans ast_sip_session_send_request_with_cb(session, tdata, cb); return; } - if (tsx->status_code != 488) { - /* Other reinvite failures (except 488) result in destroying the session. */ + if (tsx->status_code != 488 && tsx->status_code != 500) { + /* Other reinvite failures (except 488 and 500) result in destroying the session. */ if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS && tdata) { ast_sip_session_send_request(session, tdata); From 601e0c563fb9c936bf20da7b2cd746e21022e405 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 22 Sep 2017 22:49:21 +0000 Subject: [PATCH 1503/1578] res_pjsip_session: Reduce (and improve) SDP renegotiation. When pruning a request to change the topology of a channel be more intelligent about the resulting topology that is actually used for SDP renegotiation. In a case where a stream has not already been negotiated we don't need to renegotiate and offer a declined stream. This can occur if something in Asterisk (such as ConfBridge) requests to add video to a PJSIP channel that has no video codecs configured. In this case since the stream did not already exist we can safely remove the stream from the requested topology, resulting in no renegotiation occurring. In a case where a renegotiation is requested with a codec that is not supported we can reuse the formats of the existing stream if it exists to ensure that the stream continues to flow, instead of removing it. Change-Id: I636540798d55922377318fe619c510fb6ed125fb --- res/res_pjsip_session.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 2beb6dcd508..d61799bea32 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1482,8 +1482,15 @@ int ast_sip_session_refresh(struct ast_sip_session *session, * are configurable on the endpoint. */ for (index = 0; index < ast_stream_topology_get_count(media_state->topology); ++index) { + struct ast_stream *existing_stream = NULL; + stream = ast_stream_topology_get_stream(media_state->topology, index); + if (session->active_media_state->topology && + index < ast_stream_topology_get_count(session->active_media_state->topology)) { + existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, index); + } + if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) { if (index < AST_VECTOR_SIZE(&media_state->sessions)) { struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index); @@ -1516,8 +1523,28 @@ int ast_sip_session_refresh(struct ast_sip_session *session, ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap); if (!ast_format_cap_count(joint_cap)) { ao2_ref(joint_cap, -1); - ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); - continue; + + if (!existing_stream) { + /* If there is no existing stream we can just not have this stream in the topology + * at all. + */ + ast_stream_topology_del_stream(media_state->topology, index); + index -= 1; + continue; + } else if (ast_stream_get_state(stream) != ast_stream_get_state(existing_stream) || + strcmp(ast_stream_get_name(stream), ast_stream_get_name(existing_stream))) { + /* If the underlying stream is a different type or different name then we have to + * mark it as removed, as it is replacing an existing stream. We do this so order + * is preserved. + */ + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + continue; + } else { + /* However if the stream is otherwise remaining the same we can keep the formats + * that exist on it already which allows media to continue to flow. + */ + joint_cap = ao2_bump(ast_stream_get_formats(existing_stream)); + } } ast_stream_set_formats(stream, joint_cap); } From 0fad11f21c309b44ada3572f593b6dd6588baa28 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sat, 23 Sep 2017 13:32:26 -0400 Subject: [PATCH 1504/1578] app_stream_echo: Don't echo declined streams Discovered while experimenting with Cyber Mega Phone 2K Ultimate Dynamic Edition after accepting the audio request but declining the video one. Change-Id: Iaa86d41fccfbc1b559a30ccf740d78a3b5f8a98c --- apps/app_stream_echo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/app_stream_echo.c b/apps/app_stream_echo.c index 9695dcc8725..717ed1c8860 100644 --- a/apps/app_stream_echo.c +++ b/apps/app_stream_echo.c @@ -249,6 +249,11 @@ static struct ast_stream_topology *stream_echo_topology_alloc( continue; } + if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + /* Don't copy removed/declined streams */ + continue; + } + do { stream = ast_stream_clone(stream, NULL); From c3c73b3511462ab06e3b6d84e31be2d0838fc0ef Mon Sep 17 00:00:00 2001 From: StefanEng86 Date: Fri, 15 Sep 2017 09:59:59 +0200 Subject: [PATCH 1505/1578] app_queue: Only do announcement logic between ringing cycles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch reverts the change by patch 2263 from old reviewboard. Note that reverting that 2263-patch still preserves the behaviour that the commit log of the 2263-patch claimed to add. The reason for this is: The function wait_for_answer is only called from try_calling which in turn is only called from the main for loop in queue_exec, and earlier in that loop we already check the things that's removed by this patch. There's no need to check those things twice each loop iteration, and I think the proper place to check it is before each ringing cycle. By checking it in wait_for_answer, you allow the issue explained in the jira - that the head caller hears announcements while the agents' sip phones are actively ringing. Reported-by: Stefan Engström Tested-by: Stefan Engström ASTERISK-27216 #close Change-Id: Ic4290dc75256f9743900c6762ee1bb915f672db0 --- apps/app_queue.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index ef40a891cae..b6079afd582 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4831,7 +4831,7 @@ static void update_connected_line_from_peer(struct ast_channel *chan, struct ast * * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward() */ -static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int ringing) +static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed) { const char *queue = qe->parent->name; struct callattempt *o, *start = NULL, *prev = NULL; @@ -5349,16 +5349,6 @@ skip_frame:; } } - /* Make a position announcement, if enabled */ - if (qe->parent->announcefrequency && qe->parent->announce_to_first_user) { - say_position(qe, ringing); - } - - /* Make a periodic announcement, if enabled */ - if (qe->parent->periodicannouncefrequency && qe->parent->announce_to_first_user) { - say_periodic_announcement(qe, ringing); - } - if (!*to) { for (o = start; o; o = o->call_next) { if (o->chan) { @@ -6788,7 +6778,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a ring_one(qe, outgoing, &numbusies); lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), - forwardsallowed, ringing); + forwardsallowed); ao2_lock(qe->parent); if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { @@ -8259,14 +8249,14 @@ static int queue_exec(struct ast_channel *chan, const char *data) if (makeannouncement) { /* Make a position announcement, if enabled */ - if (qe.parent->announcefrequency) + if (qe.parent->announcefrequency && qe.parent->announce_to_first_user) if ((res = say_position(&qe,ringing))) goto stop; } makeannouncement = 1; /* Make a periodic announcement, if enabled */ - if (qe.parent->periodicannouncefrequency) { + if (qe.parent->periodicannouncefrequency && qe.parent->announce_to_first_user) { if ((res = say_periodic_announcement(&qe,ringing))) { goto stop; } From 4275ca16a147c1772a700c1cfda3983ecec6c79d Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 25 Sep 2017 06:25:06 -0600 Subject: [PATCH 1506/1578] build: A few gcc 7 error fixes Change-Id: I7b5300fbf1af7d88d47129db13ad6dbdc9b553ec --- apps/app_meetme.c | 25 ++++++++++++++----------- channels/chan_dahdi.c | 3 ++- channels/sig_pri.c | 8 ++++---- channels/sig_pri.h | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/app_meetme.c b/apps/app_meetme.c index d98c418c354..7ca9ba39f05 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -2251,20 +2251,23 @@ static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_ if (trunk_ref->ring_timeout) { snprintf(ring_timeout, sizeof(ring_timeout), "%u", trunk_ref->ring_timeout); - } else + } else { strcpy(ring_timeout, "(none)"); + } if (trunk_ref->ring_delay) { snprintf(ring_delay, sizeof(ring_delay), "%u", trunk_ref->ring_delay); - } else + } else { strcpy(ring_delay, "(none)"); - ast_cli(a->fd, "=== ==> Trunk Name: %s\n" - "=== ==> State: %s\n" - "=== ==> RingTimeout: %s\n" - "=== ==> RingDelay: %s\n", - trunk_ref->trunk->name, - trunkstate2str(trunk_ref->state), - ring_timeout, ring_delay); + } + + ast_cli(a->fd, "=== ==> Trunk Name: %s\n" + "=== ==> State: %s\n" + "=== ==> RingTimeout: %s\n" + "=== ==> RingDelay: %s\n", + trunk_ref->trunk->name, + trunkstate2str(trunk_ref->state), + ring_timeout, ring_delay); } ast_cli(a->fd, "=== ---------------------------------------------------------\n" "===\n"); @@ -3199,7 +3202,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc const char *agifiledefault = "conf-background.agi", *tmpvar; char meetmesecs[30] = ""; char exitcontext[AST_MAX_CONTEXT] = ""; - char recordingtmp[AST_MAX_EXTENSION] = ""; + char recordingtmp[AST_MAX_EXTENSION * 2] = ""; char members[10] = ""; int dtmf = 0, opt_waitmarked_timeout = 0; time_t timeout = 0; @@ -4517,7 +4520,7 @@ static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char char currenttime[32] = ""; char eatime[32] = ""; char bookid[51] = ""; - char recordingtmp[AST_MAX_EXTENSION] = ""; + char recordingtmp[AST_MAX_EXTENSION * 2] = ""; char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */ char adminopts[OPTIONS_LEN + 1] = ""; struct ast_tm tm, etm; diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 4f717ffacc7..828753a05d9 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "sig_analog.h" /* Analog signaling is currently still present in chan_dahdi for use with @@ -14210,7 +14211,7 @@ static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct int trunkgroup; int x, y, fd = a->fd; int interfaceid = 0; - char db_chan_name[20], db_answer[5]; + char db_chan_name[20], db_answer[15]; struct dahdi_pvt *tmp; struct dahdi_pri *pri; diff --git a/channels/sig_pri.c b/channels/sig_pri.c index 1b228af9958..fbc4e40f056 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -2040,7 +2040,7 @@ static void *do_idle_thread(void *v_pvt) struct sig_pri_chan *pvt = v_pvt; struct ast_channel *chan = pvt->owner; struct ast_frame *f; - char ex[80]; + char ex[128]; /* Wait up to 30 seconds for an answer */ int timeout_ms = 30000; int ms; @@ -2279,7 +2279,7 @@ static void sig_pri_party_name_convert(struct ast_party_name *ast_name, const st */ static void sig_pri_party_number_convert(struct ast_party_number *ast_number, const struct pri_party_number *pri_number, struct sig_pri_span *pri) { - char number[AST_MAX_EXTENSION]; + char number[AST_MAX_EXTENSION * 2]; apply_plan_to_existing_number(number, sizeof(number), pri, pri_number->str, pri_number->plan); @@ -6233,7 +6233,7 @@ static void *pri_dchannel(void *vpri) struct timeval lastidle = { 0, 0 }; pthread_t p; struct ast_channel *idle; - char idlen[80]; + char idlen[128]; int nextidle = -1; int haveidles; int activeidles; @@ -6639,7 +6639,7 @@ static void *pri_dchannel(void *vpri) e->service_ack.changestatus, PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span); } else { char db_chan_name[20]; - char db_answer[5]; + char db_answer[15]; int ch; unsigned *why; diff --git a/channels/sig_pri.h b/channels/sig_pri.h index d3e5350c877..8c9babd4ec7 100644 --- a/channels/sig_pri.h +++ b/channels/sig_pri.h @@ -300,7 +300,7 @@ struct sig_pri_chan { char cid_name[AST_MAX_EXTENSION]; char cid_ani[AST_MAX_EXTENSION]; /*! \brief User tag for party id's sent from this device driver. */ - char user_tag[AST_MAX_EXTENSION]; + char user_tag[AST_MAX_EXTENSION * 2]; char exten[AST_MAX_EXTENSION]; /* Internal variables -- Don't touch */ From 08e67f814be0c38775e1a8ea24a01e600f2ba5ee Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 25 Sep 2017 10:59:17 -0500 Subject: [PATCH 1507/1578] channel.c: Fix invalid reference in conditionaled out code. ASTERISK-27289 Change-Id: I7a415948116493050614d9f4fa91ffbe0c21ec4c --- main/channel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/channel.c b/main/channel.c index ecc771c1d9a..7d6e5db07ac 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4060,7 +4060,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int } #else int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), - ast_format_get_sample_rate(f->subclass.codec), + ast_format_get_sample_rate(f->subclass.format), ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); if (jump - MONITOR_DELAY >= 0) { if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump - f->samples, SEEK_FORCECUR) == -1) { @@ -5203,7 +5203,7 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame } #else int jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)), - ast_format_get_sample_rate(f->subclass.codec), + ast_format_get_sample_rate(f->subclass.format), ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); if (jump - MONITOR_DELAY >= 0) { if (ast_seekstream(ast_channel_monitor(chan)->write_stream, jump - cur->samples, SEEK_FORCECUR) == -1) { From b74cbadd05d1ba42d66ba43a690c45f5d2c5f706 Mon Sep 17 00:00:00 2001 From: Kevin Harwell Date: Mon, 25 Sep 2017 12:30:56 -0500 Subject: [PATCH 1508/1578] res_pjsip_session: outgoing call did not offer all configured codecs For some scenarios when an outgoing call was made only a subset of the configured codecs were offered. If the codecs being offered happened to not have a codec supported by the phone then the call would fail. For instance Alice and Bob both are configured in Asterisk for g722 and ulaw( allow=!all,g722,ulaw). Alice's endpoint however only supports g722 while Bob's only supports ulaw. When Alice calls Bob, Alice negotiates g722 fine with Asterisk. But when Asterisk sends the outgoing offer to Bob it only contains g722 and not both g722 and ulaw, so the call ends. This patch makes it so all the audio codecs configured on the endpoint always get sent, and not just a subset. However priority is given to those codecs that are compatible with the "other side". ASTERISK-27259 #close Change-Id: Iffabc373bd94cd1dc700925dcfe406e12918c696 --- res/res_pjsip_session.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 76dafb378bd..8b0ca2f73c1 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2459,6 +2459,16 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint continue; } + if (ast_stream_get_type(req_stream) == AST_MEDIA_TYPE_AUDIO) { + /* + * By appending codecs from the endpoint after compatible ones this + * guarantees that priority is given to those while also allowing + * translation to occur for non-compatible. + */ + ast_format_cap_append_from_cap(joint_cap, + endpoint->media.codecs, AST_MEDIA_TYPE_AUDIO); + } + ast_stream_set_formats(clone_stream, joint_cap); ao2_ref(joint_cap, -1); From 0cbeaa55890c9439ce29e62dd360d8a0f14da836 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 25 Sep 2017 14:09:33 -0400 Subject: [PATCH 1509/1578] pjproject: Patch to correct STUN FINGERPRINT usage Change-Id: I0e453253dff1388b0186b36c754457c1d0d12db6 --- .../0080-STUN-Fingerprint-with-ICE.patch | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 third-party/pjproject/patches/0080-STUN-Fingerprint-with-ICE.patch diff --git a/third-party/pjproject/patches/0080-STUN-Fingerprint-with-ICE.patch b/third-party/pjproject/patches/0080-STUN-Fingerprint-with-ICE.patch new file mode 100644 index 00000000000..96d44fa2ef8 --- /dev/null +++ b/third-party/pjproject/patches/0080-STUN-Fingerprint-with-ICE.patch @@ -0,0 +1,35 @@ +From 28490e9ddee0937516f9edcaf95d274fe5ceaf4c Mon Sep 17 00:00:00 2001 +From: Sean Bright +Date: Mon, 25 Sep 2017 14:06:53 -0400 +Subject: [PATCH] ICE: Use STUN FINGERPRINT attribute when sending keepalives + +Per RFC 5245 Section 10: + + If STUN is being used for keepalives, a STUN Binding Indication is + used [RFC5389]. The Indication MUST NOT utilize any authentication + mechanism. It SHOULD contain the FINGERPRINT attribute to aid in + demultiplexing, but SHOULD NOT contain any other attributes. +--- + pjnath/src/pjnath/ice_session.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c +index 159d7b1..f90005a 100644 +--- a/pjnath/src/pjnath/ice_session.c ++++ b/pjnath/src/pjnath/ice_session.c +@@ -1217,10 +1217,8 @@ static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now) + msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data); + msg_data->transport_id = the_check->lcand->transport_id; + +- /* Temporarily disable FINGERPRINT. The Binding Indication +- * SHOULD NOT contain any attributes. +- */ +- saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_FALSE); ++ /* Make sure that the FINGERPRINT attribute is used per RFC 5245 Section 10 */ ++ saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_TRUE); + + /* Send to session */ + addr_len = pj_sockaddr_get_len(&the_check->rcand->addr); +-- +2.7.4 + From 721947ebae1961c1f765eaeb60abb1a71cf97ce0 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 25 Sep 2017 14:00:53 -0400 Subject: [PATCH 1510/1578] webrtc: Allow 'webrtc' to be set on endpoints without dtls_ca_file If using a legitimate certificate from a trusted certificate authority, you don't need to provide CA file. Change-Id: I8623973b4209b44889243716d7880274caed8a6d --- res/res_pjsip/pjsip_configuration.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index cba8a7e7fba..3a752c90ddd 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1363,10 +1363,9 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o endpoint->media.rtp.dtls_cfg.default_setup = AST_RTP_DTLS_SETUP_ACTPASS; endpoint->media.rtp.dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT; - if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile) || - (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.cafile))) { + if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile)) { ast_log(LOG_ERROR, "WebRTC can't be enabled on endpoint '%s' - a DTLS cert " - "or ca file has not been specified", ast_sorcery_object_get_id(endpoint)); + "has not been specified", ast_sorcery_object_get_id(endpoint)); return -1; } } From c9e972a26a5e76d95b00a55dd9ea55da0d173028 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 26 Sep 2017 11:55:29 -0400 Subject: [PATCH 1511/1578] res_rtp_asterisk: Trim trailing byte off of SDES packet This could have been fixed by subtracting 1 from the final value of 'len' but the way the packet was being constructed was confusing so I took the opportunity to (I think) make it more clear. We were sending 1 extra byte at the end of the SDES RTCP packet which caused Chrome to complain (in its debug log): Too little data (1 byte) remaining in buffer to parse RTCP header (4 bytes). We now send the correct number of bytes. Change-Id: I9dcf087cdaf97da0374ae0acb7d379746a71e81b --- res/res_rtp_asterisk.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index c8cc04f96c8..35cb0876398 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -3771,6 +3771,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref); int res; int len = 0; + uint16_t sdes_packet_len_bytes, sdes_packet_len_rounded; struct timeval now; unsigned int now_lsw; unsigned int now_msw; @@ -3778,7 +3779,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) unsigned int lost_packets; int fraction_lost; struct timeval dlsr = { 0, }; - unsigned char bdata[512] = ""; + unsigned char bdata[AST_UUID_STR_LEN + 128] = ""; /* More than enough */ int rate = rtp_get_rate(rtp->f.subclass.format); int ice; struct ast_sockaddr remote_address = { { 0, } }; @@ -3858,12 +3859,35 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (rtcp_report->reception_report_count << 24) | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1))); - put_unaligned_uint32(rtcpheader + len, htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | (2 + (AST_UUID_STR_LEN / 4)))); + sdes_packet_len_bytes = + 4 + /* RTCP Header */ + 4 + /* SSRC */ + 1 + /* Type (CNAME) */ + 1 + /* Text Length */ + AST_UUID_STR_LEN /* Text and NULL terminator */ + ; + + /* Round to 32 bit boundary */ + sdes_packet_len_rounded = (sdes_packet_len_bytes + 3) & ~0x3; + + put_unaligned_uint32(rtcpheader + len, htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | ((sdes_packet_len_rounded / 4) - 1))); put_unaligned_uint32(rtcpheader + len + 4, htonl(rtcp_report->ssrc)); - put_unaligned_uint16(rtcpheader + len + 8, htonl(0x01 << 24)); - put_unaligned_uint16(rtcpheader + len + 9, htonl(AST_UUID_STR_LEN << 24)); + rtcpheader[len + 8] = 0x01; /* CNAME */ + rtcpheader[len + 9] = AST_UUID_STR_LEN - 1; /* Number of bytes of text */ memcpy(rtcpheader + len + 10, rtp->cname, AST_UUID_STR_LEN); - len += 12 + AST_UUID_STR_LEN; + len += 10 + AST_UUID_STR_LEN; + + /* Padding - Note that we don't set the padded bit on the packet. From + * RFC 3550 Section 6.5: + * + * No length octet follows the null item type octet, but additional null + * octets MUST be included if needed to pad until the next 32-bit + * boundary. Note that this padding is separate from that indicated by + * the P bit in the RTCP header. + * + * These bytes will already be zeroed out during array initialization. + */ + len += (sdes_packet_len_rounded - sdes_packet_len_bytes); if (rtp->bundled) { ast_rtp_instance_get_remote_address(instance, &remote_address); From 9d65057cdf0ee9a8ca0bafc85b76663238a27418 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 13 Sep 2017 21:31:52 -0500 Subject: [PATCH 1512/1578] res_rtp_asterisk.c: Fix bridge_p2p_rtp_write() reentrancy potential. The bridge_p2p_rtp_write() has potential reentrancy problems. * Accessing the bridged RTP members must be done with the instance1 lock held. The DTMF and asymmetric codec checks must be split to be done with the correct RTP instance struct locked. i.e., They must be done when working on the appropriate side of the point to point bridge. * Forcing the RTP mark bit was referencing the wrong side of the point to point bridge. The set mark bit is used everywhere else to set the mark bit when sending not receiving. The patches for ASTERISK_26745 and ASTERISK_27158 did not take into account that not everything carried by RTP uses a codec. The telephony DTMF events are not exchanged with a codec. As a result when RFC2833/RFC4733 sent digits you would crash if "core set debug 1" is enabled, the DTMF digits would always get passed to the core even though the local native RTP bridge is active, and the DTMF digits would go out using the wrong SSRC id. * Add protection for non-format payload types like DTMF when updating the lastrxformat and lasttxformat. Also protect against non-format payload types when checking for asymmetric codecs. ASTERISK-27292 Change-Id: I6344ab7de21e26f84503c4d1fca1a41579364186 --- res/res_rtp_asterisk.c | 85 +++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index c8cc04f96c8..b114c36a0a0 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -5316,7 +5316,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, struct ast_rtp_instance *instance1, unsigned int *rtpheader, int len, int hdrlen) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - struct ast_rtp *bridged = ast_rtp_instance_get_data(instance1); + struct ast_rtp *bridged; int res = 0, payload = 0, bridged_payload = 0, mark; RAII_VAR(struct ast_rtp_payload_type *, payload_type, NULL, ao2_cleanup); int reconstruct = ntohl(rtpheader[0]); @@ -5326,7 +5326,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, /* Get fields from packet */ payload = (reconstruct & 0x7f0000) >> 16; - mark = (((reconstruct & 0x800000) >> 23) != 0); + mark = (reconstruct & 0x800000) >> 23; /* Check what the payload value should be */ payload_type = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payload); @@ -5349,12 +5349,6 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, return -1; } - /* If bridged peer is in dtmf, feed all packets to core until it finishes to avoid infinite dtmf */ - if (bridged->sending_digit) { - ast_debug(1, "Feeding packets to core until DTMF finishes\n"); - return -1; - } - /* * Even if we are no longer in dtmf, we could still be receiving * re-transmissions of the last dtmf end still. Feed those to the @@ -5365,35 +5359,10 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, return -1; } - - ao2_replace(rtp->lastrxformat, payload_type->format); - ao2_replace(bridged->lasttxformat, payload_type->format); - - /* - * If bridged peer has already received rtp, perform the asymmetric codec check - * if that feature has been activated - */ - if (!bridged->asymmetric_codec && bridged->lastrxformat != ast_format_none) { - if (ast_format_cmp(bridged->lasttxformat, bridged->lastrxformat) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_debug(1, "Asymmetric RTP codecs detected (TX: %s, RX: %s) sending frame to core\n", - ast_format_get_name(bridged->lasttxformat), - ast_format_get_name(bridged->lastrxformat)); - return -1; - } + if (payload_type->asterisk_format) { + ao2_replace(rtp->lastrxformat, payload_type->format); } - /* If the marker bit has been explicitly set turn it on */ - if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) { - mark = 1; - ast_clear_flag(rtp, FLAG_NEED_MARKER_BIT); - } - - /* Reconstruct part of the packet */ - reconstruct &= 0xFF80FFFF; - reconstruct |= (bridged_payload << 16); - reconstruct |= (mark << 23); - rtpheader[0] = htonl(reconstruct); - /* * We have now determined that we need to send the RTP packet * out the bridged instance to do local bridging so we must unlock @@ -5409,6 +5378,40 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, ao2_unlock(instance); ao2_lock(instance1); + /* + * Get the peer rtp pointer now to emphasize that using it + * must happen while instance1 is locked. + */ + bridged = ast_rtp_instance_get_data(instance1); + + + /* If bridged peer is in dtmf, feed all packets to core until it finishes to avoid infinite dtmf */ + if (bridged->sending_digit) { + ast_debug(1, "Feeding packet to core until DTMF finishes\n"); + ao2_unlock(instance1); + ao2_lock(instance); + return -1; + } + + if (payload_type->asterisk_format) { + /* + * If bridged peer has already received rtp, perform the asymmetric codec check + * if that feature has been activated + */ + if (!bridged->asymmetric_codec + && bridged->lastrxformat != ast_format_none + && ast_format_cmp(payload_type->format, bridged->lastrxformat) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_debug(1, "Asymmetric RTP codecs detected (TX: %s, RX: %s) sending frame to core\n", + ast_format_get_name(payload_type->format), + ast_format_get_name(bridged->lastrxformat)); + ao2_unlock(instance1); + ao2_lock(instance); + return -1; + } + + ao2_replace(bridged->lasttxformat, payload_type->format); + } + ast_rtp_instance_get_remote_address(instance1, &remote_address); if (ast_sockaddr_isnull(&remote_address)) { @@ -5418,6 +5421,18 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, return 0; } + /* If the marker bit has been explicitly set turn it on */ + if (ast_test_flag(bridged, FLAG_NEED_MARKER_BIT)) { + mark = 1; + ast_clear_flag(bridged, FLAG_NEED_MARKER_BIT); + } + + /* Reconstruct part of the packet */ + reconstruct &= 0xFF80FFFF; + reconstruct |= (bridged_payload << 16); + reconstruct |= (mark << 23); + rtpheader[0] = htonl(reconstruct); + /* Send the packet back out */ res = rtp_sendto(instance1, (void *)rtpheader, len, 0, &remote_address, &ice); if (res < 0) { From 61ea87223339ab835593ed75e9d5a265a05f3ff2 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 26 Sep 2017 10:01:48 -0600 Subject: [PATCH 1513/1578] pjsip_message_filter: Fix regression causing bad contact address The "res_pjsip: Filter out non SIP(S) requests" commit moved the filtering of messages to pjproject's PJSIP_MOD_PRIORITY_TRANSPORT_LAYER in order to filter out incoming bad uri schemes as early as possible. Since the change affected outgoing messages as well and the TRANSPORT layer is the last to be run on outgoing messages, we were overwriting the setting of external_signaling_address (which is set earlier by res_pjsip_nat) with an internal address. * pjsip_message_filter now registers itself as a pjproject module twice. Once in the TSX layer for the outgoing messages (as it was originally), then a second time in the TRANSPORT layer for the incoming messages to catch the invalid uri schemes. ASTERISK-27295 Reported by: Sean Bright Change-Id: I2c90190c43370f8a9d1c4693a19fd65840689c8c --- res/res_pjsip/pjsip_message_filter.c | 32 ++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/res/res_pjsip/pjsip_message_filter.c b/res/res_pjsip/pjsip_message_filter.c index 63b8bd5af55..d2f9b9562e3 100644 --- a/res/res_pjsip/pjsip_message_filter.c +++ b/res/res_pjsip/pjsip_message_filter.c @@ -36,13 +36,19 @@ struct filter_message_restrictions { unsigned int disallow_from_domain_modification; }; -static pjsip_module filter_module = { - .name = { "Message Filtering", 17 }, +static pjsip_module filter_module_transport = { + .name = { "Message Filtering Transport", 27 }, .id = -1, .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, + .on_rx_request = filter_on_rx_message, +}; + +static pjsip_module filter_module_tsx = { + .name = { "Message Filtering TSX", 21 }, + .id = -1, + .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1, .on_tx_request = filter_on_tx_message, .on_tx_response = filter_on_tx_message, - .on_rx_request = filter_on_rx_message, }; /*! \brief Helper function to get (or allocate if not already present) restrictions on a message */ @@ -50,13 +56,13 @@ static struct filter_message_restrictions *get_restrictions(pjsip_tx_data *tdata { struct filter_message_restrictions *restrictions; - restrictions = ast_sip_mod_data_get(tdata->mod_data, filter_module.id, MOD_DATA_RESTRICTIONS); + restrictions = ast_sip_mod_data_get(tdata->mod_data, filter_module_tsx.id, MOD_DATA_RESTRICTIONS); if (restrictions) { return restrictions; } restrictions = PJ_POOL_ALLOC_T(tdata->pool, struct filter_message_restrictions); - ast_sip_mod_data_set(tdata->pool, tdata->mod_data, filter_module.id, MOD_DATA_RESTRICTIONS, restrictions); + ast_sip_mod_data_set(tdata->pool, tdata->mod_data, filter_module_tsx.id, MOD_DATA_RESTRICTIONS, restrictions); return restrictions; } @@ -217,7 +223,8 @@ static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata) static pj_status_t filter_on_tx_message(pjsip_tx_data *tdata) { - struct filter_message_restrictions *restrictions = ast_sip_mod_data_get(tdata->mod_data, filter_module.id, MOD_DATA_RESTRICTIONS); + struct filter_message_restrictions *restrictions = + ast_sip_mod_data_get(tdata->mod_data, filter_module_transport.id, MOD_DATA_RESTRICTIONS); pjsip_tpmgr_fla2_param prm; pjsip_cseq_hdr *cseq; pjsip_via_hdr *via; @@ -277,7 +284,7 @@ static pj_status_t filter_on_tx_message(pjsip_tx_data *tdata) /* prm.ret_addr is allocated from the tdata pool OR the transport so it is perfectly fine to just do an assignment like this */ pj_strassign(&uri->host, &prm.ret_addr); uri->port = prm.ret_port; - ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n", + ast_debug(5, "Re-wrote Contact URI host/port to %.*s:%d (this may be re-written again later)\n", (int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port); if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || @@ -498,7 +505,8 @@ static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata) void ast_res_pjsip_cleanup_message_filter(void) { - ast_sip_unregister_service(&filter_module); + ast_sip_unregister_service(&filter_module_tsx); + ast_sip_unregister_service(&filter_module_transport); ast_sip_unregister_supplement(&filter_supplement); ast_sip_session_unregister_supplement(&filter_session_supplement); } @@ -516,7 +524,13 @@ int ast_res_pjsip_init_message_filter(void) return -1; } - if (ast_sip_register_service(&filter_module)) { + if (ast_sip_register_service(&filter_module_transport)) { + ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n"); + ast_res_pjsip_cleanup_message_filter(); + return -1; + } + + if (ast_sip_register_service(&filter_module_tsx)) { ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n"); ast_res_pjsip_cleanup_message_filter(); return -1; From a6dc0527a2d7a8659b204e2b1f7efadb5d67a3ab Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 27 Sep 2017 11:16:16 -0500 Subject: [PATCH 1514/1578] res_pjsip_outbound_publish.c: Fix misplaced parenthesis. The pjsip_publishc_init() call was referenced with a misplaced parentheses. As a result, outbound publication messages went out with an expiration of 1 second. ASTERISK-27298 Change-Id: I93622eabc8ee83e7a22e98c107f921284c605a08 --- res/res_pjsip_outbound_publish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 18525bf6cd4..0fac8adf6b9 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -986,7 +986,7 @@ static int sip_outbound_publisher_init(void *data) pj_cstr(&event, publish->event); if (pjsip_publishc_init(publisher->client, &event, &server_uri, &from_uri, &to_uri, - publish->expiration != PJ_SUCCESS)) { + publish->expiration) != PJ_SUCCESS) { ast_log(LOG_ERROR, "Failed to initialize publishing client on outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); From f21408c8669f42849fd10f27b357c84bc8f7eb44 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 28 Sep 2017 10:33:00 +0000 Subject: [PATCH 1515/1578] res_stasis: Add 'video_sfu' as a requested bridge type. This change adds 'video_sfu' as a requested bridge type when creating a bridge. By specifying this a mixing type bridge is created that exchanges video in an SFU fashion. Change-Id: I2ada47cf5f3fc176518b647c0b4aa39d55339606 --- res/res_stasis.c | 19 ++++++++++++++++++- rest-api/api-docs/bridges.json | 4 ++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/res/res_stasis.c b/res/res_stasis.c index 899c8f720a2..f99dcee372e 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -766,6 +766,7 @@ static struct ast_bridge *bridge_create_common(const char *type, const char *nam int flags = AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM | AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY; + enum ast_bridge_video_mode_type video_mode = AST_BRIDGE_VIDEO_MODE_TALKER_SRC; if (invisible) { flags |= AST_BRIDGE_FLAG_INVISIBLE; @@ -782,9 +783,17 @@ static struct ast_bridge *bridge_create_common(const char *type, const char *nam } else if (!strcmp(requested_type, "dtmf_events") || !strcmp(requested_type, "proxy_media")) { capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE; + } else if (!strcmp(requested_type, "video_sfu")) { + video_mode = AST_BRIDGE_VIDEO_MODE_SFU; } } + /* For an SFU video bridge we ensure it always remains in multimix for the best experience. */ + if (video_mode == AST_BRIDGE_VIDEO_MODE_SFU) { + capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX; + flags &= ~AST_BRIDGE_FLAG_SMART; + } + if (!capabilities /* Holding and mixing capabilities don't mix. */ || ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING) @@ -794,7 +803,15 @@ static struct ast_bridge *bridge_create_common(const char *type, const char *nam bridge = bridge_stasis_new(capabilities, flags, name, id); if (bridge) { - ast_bridge_set_talker_src_video_mode(bridge); + if (video_mode == AST_BRIDGE_VIDEO_MODE_SFU) { + ast_bridge_set_sfu_video_mode(bridge); + /* We require a minimum 5 seconds between video updates to stop floods from clients, + * this should rarely be changed but should become configurable in the future. + */ + ast_bridge_set_video_update_discard(bridge, 5); + } else { + ast_bridge_set_talker_src_video_mode(bridge); + } if (!ao2_link(app_bridges, bridge)) { ast_bridge_destroy(bridge, 0); bridge = NULL; diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json index 03a1e7a69e3..877fdf84da1 100644 --- a/rest-api/api-docs/bridges.json +++ b/rest-api/api-docs/bridges.json @@ -26,7 +26,7 @@ "parameters": [ { "name": "type", - "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media).", + "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu).", "paramType": "query", "required": false, "allowMultiple": false, @@ -65,7 +65,7 @@ "parameters": [ { "name": "type", - "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media) to set.", + "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu) to set.", "paramType": "query", "required": false, "allowMultiple": false, From d1de7948fe92ed39f441df645f236db8ef64d7de Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 27 Sep 2017 12:45:21 -0600 Subject: [PATCH 1516/1578] logger: Bring back ability to turn debug on by source file Somewhere along the way we lost the ability to debug individual source files. For modules, this wasn't a big deal but all the source files in ./main are in the one "core" module so debugging individual core capabilities was almost impossible. * Added a test to DEBUG_ATLEAST that also checks __FILE__ instead of just module name. Any source file will work even if it's in a module subdirectory. Change-Id: Icc0af41837f3b1679dec7af21fa32cd1f7469f6e --- include/asterisk/logger.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index 849f986b3dd..8b1e5fe0159 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -429,7 +429,9 @@ void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid); #define DEBUG_ATLEAST(level) \ (option_debug >= (level) \ - || (ast_opt_dbg_module && (int)ast_debug_get_by_module(AST_MODULE) >= (level))) + || (ast_opt_dbg_module \ + && ((int)ast_debug_get_by_module(AST_MODULE) >= (level) \ + || (int)ast_debug_get_by_module(__FILE__) >= (level)))) /*! * \brief Log a DEBUG message From 80097676e77d557bca703a9ceee4bd54a7e689de Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 21 Sep 2017 14:43:09 -0500 Subject: [PATCH 1517/1578] heap.c: No need to calloc heap pointer array. Change-Id: I5ae2f316229f336eb90d99c7af7ed07a33097e68 --- main/heap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/heap.c b/main/heap.c index 0f0bafd18ee..b7d28ce2fea 100644 --- a/main/heap.c +++ b/main/heap.c @@ -144,9 +144,9 @@ struct ast_heap *ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_f if (!(h->heap = #ifdef __AST_DEBUG_MALLOC - __ast_calloc(1, h->avail_len * sizeof(void *), file, lineno, func) + __ast_malloc(h->avail_len * sizeof(void *), file, lineno, func) #else - ast_calloc(1, h->avail_len * sizeof(void *)) + ast_malloc(h->avail_len * sizeof(void *)) #endif )) { ast_free(h); From b2dbfe23ef175b8d25ae990163e4ff475bb60b3b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 28 Sep 2017 17:37:15 -0500 Subject: [PATCH 1518/1578] app_queue.c: Fix announcements when announce-to-first-user not enabled. The previous patch for ASTERISK-27216 made it so you wouldn't get any position or periodic announcements unless you had announce-to-first-user enabled. The announce-to-first-user feature was added by ASTERISK_21782 as a result of the patch which introduced the redundant announcements that ASTERISK-27216 removes. * By noting that the makeannouncement variable is used to suppresses the first user announcement, we set its initial value to the announce-to-first-user enable setting. ASTERISK-27216 Change-Id: Ieaeb7dbea8ae7073086b775fbafe0625b000b10a --- apps/app_queue.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index b6079afd582..0efb2e6831b 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -8229,7 +8229,7 @@ static int queue_exec(struct ast_channel *chan, const char *data) goto stop; } - makeannouncement = 0; + makeannouncement = qe.parent->announce_to_first_user; for (;;) { /* This is the wait loop for the head caller*/ @@ -8249,15 +8249,17 @@ static int queue_exec(struct ast_channel *chan, const char *data) if (makeannouncement) { /* Make a position announcement, if enabled */ - if (qe.parent->announcefrequency && qe.parent->announce_to_first_user) - if ((res = say_position(&qe,ringing))) + if (qe.parent->announcefrequency) { + if ((res = say_position(&qe, ringing))) { goto stop; + } + } } makeannouncement = 1; /* Make a periodic announcement, if enabled */ - if (qe.parent->periodicannouncefrequency && qe.parent->announce_to_first_user) { - if ((res = say_periodic_announcement(&qe,ringing))) { + if (qe.parent->periodicannouncefrequency) { + if ((res = say_periodic_announcement(&qe, ringing))) { goto stop; } } From 2301447a207fa9249d6b9d82492bde45112454f5 Mon Sep 17 00:00:00 2001 From: krells Date: Thu, 28 Sep 2017 09:56:14 +0200 Subject: [PATCH 1519/1578] res_calendar_icalendar: Filter out occurrences superceded by another VEVENT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we are loading the calendars, we call libical's icalcomponent_foreach_recurrence method for each VEVENT component that we have in our calendar. That method has no knowledge concerning the existence of the other VEVENT components and will feed our callback with all ocurrences matching the requested time span. The occurrences generated by icalcomponent_foreach_recurrence while expanding a recurring VEVENT's RRULE and RDATE properties can be superceded by an other VEVENT sharing the same UID. I use an external iterator (in libical terminology) to avoid messing with the internal ones from the calling function, and search for VEVENTS which could supersede the current occurrence. The event which can invalidate this occurence needs to have: - the same UID as our recurrent component (comp) - a RECURRENCE-ID property, which represents the start time of this occurrence If one component is found, just clean and return. ASTERISK-27296 #close Reported by: Benoît Dereck-Tricot Change-Id: I8587ae3eaa765af7cb21eda3b6bf84e8a1c87af8 --- res/res_calendar_icalendar.c | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c index 4139cf449ef..58876c187b7 100644 --- a/res/res_calendar_icalendar.c +++ b/res/res_calendar_icalendar.c @@ -177,7 +177,7 @@ static time_t icalfloat_to_timet(icaltimetype time) } /* span->start & span->end may be dates or floating times which have no timezone, - * which would mean that they should apply to the local timezone for all recepients. + * which would mean that they should apply to the local timezone for all recipients. * For example, if a meeting was set for 1PM-2PM floating time, people in different time * zones would not be scheduled at the same local times. Dates are often treated as * floating times, so all day events will need to be converted--so we can trust the @@ -249,7 +249,42 @@ static void icalendar_add_event(icalcomponent *comp, struct icaltime_span *span, } } - /* Get the attendees */ + /* + * If comp has an RRULE and/or RDATE property, we need to check whether + * another vevent component supercedes this span. Such a component would + * have two characteristics: + * - its UID is the same as comp + * - its RECURRENCE-ID property is the same time as span->start + */ + if (icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY) + || icalcomponent_get_first_property(comp, ICAL_RDATE_PROPERTY)) { + icalcompiter comp_iter; + icaltimetype span_start = icaltime_from_timet_with_zone( + event->start, icaltime_is_date(start), icaltime_get_timezone(start)); + + icaltime_set_timezone(&span_start, icaltime_get_timezone(start)); + for (comp_iter = icalcomponent_begin_component(pvt->data, ICAL_VEVENT_COMPONENT); + icalcompiter_deref(&comp_iter); + icalcompiter_next(&comp_iter)) { + icalcomponent *vevent = icalcompiter_deref(&comp_iter); + icalproperty *uid = icalcomponent_get_first_property(vevent, ICAL_UID_PROPERTY); + + if (uid && !strcmp(icalproperty_get_value_as_string(uid), event->uid)) { + icaltimetype recurrence_id = icalcomponent_get_recurrenceid(vevent); + + /* Set the same timezone that we want to compare against */ + icaltime_set_timezone(&recurrence_id, icaltime_get_timezone(start)); + + if (!icaltime_compare(recurrence_id, span_start) + && icaltime_is_date(span_start) == icaltime_is_date(recurrence_id)) { + event = ast_calendar_unref_event(event); + return; + } + } + } + } + + /* Get the attendees */ for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY); prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) { struct ast_calendar_attendee *attendee; From 7d04544986980aed9eca9e13d6b849ff3b372f35 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 4 Oct 2017 11:46:44 -0400 Subject: [PATCH 1520/1578] res_pjsip: Fix issues that prevented shutdown of modules. res_pjsip and res_pjsip_session had circular references, preventing both modules from shutting down. * Move session supplement registration to res_pjsip. * Use create internal functions for use by pjsip_message_filter.c. ASTERISK-27306 Change-Id: Ifbd5c19ec848010111afeab2436f9699da06ba6b --- include/asterisk/res_pjsip_session.h | 7 ++ res/res_pjsip.c | 23 +++- res/res_pjsip/include/res_pjsip_private.h | 26 +++++ res/res_pjsip/pjsip_message_filter.c | 24 ++--- res/res_pjsip/pjsip_session.c | 121 ++++++++++++++++++++++ res/res_pjsip_session.c | 70 +------------ 6 files changed, 183 insertions(+), 88 deletions(-) create mode 100644 res/res_pjsip/pjsip_session.c diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index fcb14b79d91..70f94682e0e 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -587,6 +587,13 @@ int ast_sip_session_register_supplement(struct ast_sip_session_supplement *suppl */ void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement); +/*! + * \brief Add supplements to a SIP session + * + * \param session The session to initialize + */ +int ast_sip_session_add_supplements(struct ast_sip_session *session); + /*! * \brief Alternative for ast_datastore_alloc() * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 6c1f7765949..ac275bd0841 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3516,7 +3516,7 @@ int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, AST_RWLIST_HEAD_STATIC(supplements, ast_sip_supplement); -int ast_sip_register_supplement(struct ast_sip_supplement *supplement) +void internal_sip_register_supplement(struct ast_sip_supplement *supplement) { struct ast_sip_supplement *iter; int inserted = 0; @@ -3534,22 +3534,39 @@ int ast_sip_register_supplement(struct ast_sip_supplement *supplement) if (!inserted) { AST_RWLIST_INSERT_TAIL(&supplements, supplement, next); } +} + +int ast_sip_register_supplement(struct ast_sip_supplement *supplement) +{ + internal_sip_register_supplement(supplement); ast_module_ref(ast_module_info->self); + return 0; } -void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement) +int internal_sip_unregister_supplement(struct ast_sip_supplement *supplement) { struct ast_sip_supplement *iter; SCOPED_LOCK(lock, &supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + int res = -1; + AST_RWLIST_TRAVERSE_SAFE_BEGIN(&supplements, iter, next) { if (supplement == iter) { AST_RWLIST_REMOVE_CURRENT(next); - ast_module_unref(ast_module_info->self); + res = 0; break; } } AST_RWLIST_TRAVERSE_SAFE_END; + + return res; +} + +void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement) +{ + if (!internal_sip_unregister_supplement(supplement)) { + ast_module_unref(ast_module_info->self); + } } static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg) diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 9fd7aed9766..5ce3c6fafc9 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -326,6 +326,18 @@ int internal_sip_register_service(pjsip_module *module); */ int internal_sip_unregister_service(pjsip_module *module); +/*! + * \internal + * \brief Used by res_pjsip.so to register a supplement without adding a self reference + */ +void internal_sip_register_supplement(struct ast_sip_supplement *supplement); + +/*! + * \internal + * \brief Used by res_pjsip.so to unregister a supplement without removing a self reference + */ +int internal_sip_unregister_supplement(struct ast_sip_supplement *supplement); + /*! * \internal * \brief Used by res_pjsip.so to register an endpoint formatter without adding a self reference @@ -338,6 +350,20 @@ void internal_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter */ int internal_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj); +struct ast_sip_session_supplement; + +/*! + * \internal + * \brief Used by res_pjsip.so to register a session supplement without adding a self reference + */ +void internal_sip_session_register_supplement(struct ast_sip_session_supplement *supplement); + +/*! + * \internal + * \brief Used by res_pjsip.so to unregister a session supplement without removing a self reference + */ +int internal_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement); + /*! * \internal * \brief Finds or creates contact_status for a contact diff --git a/res/res_pjsip/pjsip_message_filter.c b/res/res_pjsip/pjsip_message_filter.c index d2f9b9562e3..978aeb0704b 100644 --- a/res/res_pjsip/pjsip_message_filter.c +++ b/res/res_pjsip/pjsip_message_filter.c @@ -505,32 +505,24 @@ static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata) void ast_res_pjsip_cleanup_message_filter(void) { - ast_sip_unregister_service(&filter_module_tsx); - ast_sip_unregister_service(&filter_module_transport); - ast_sip_unregister_supplement(&filter_supplement); - ast_sip_session_unregister_supplement(&filter_session_supplement); + internal_sip_unregister_service(&filter_module_tsx); + internal_sip_unregister_service(&filter_module_transport); + internal_sip_unregister_supplement(&filter_supplement); + internal_sip_session_unregister_supplement(&filter_session_supplement); } int ast_res_pjsip_init_message_filter(void) { - if (ast_sip_session_register_supplement(&filter_session_supplement)) { - ast_log(LOG_ERROR, "Could not register message filter session supplement for outgoing requests\n"); - return -1; - } - - if (ast_sip_register_supplement(&filter_supplement)) { - ast_log(LOG_ERROR, "Could not register message filter supplement for outgoing requests\n"); - ast_res_pjsip_cleanup_message_filter(); - return -1; - } + internal_sip_session_register_supplement(&filter_session_supplement); + internal_sip_register_supplement(&filter_supplement); - if (ast_sip_register_service(&filter_module_transport)) { + if (internal_sip_register_service(&filter_module_transport)) { ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n"); ast_res_pjsip_cleanup_message_filter(); return -1; } - if (ast_sip_register_service(&filter_module_tsx)) { + if (internal_sip_register_service(&filter_module_tsx)) { ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n"); ast_res_pjsip_cleanup_message_filter(); return -1; diff --git a/res/res_pjsip/pjsip_session.c b/res/res_pjsip/pjsip_session.c new file mode 100644 index 00000000000..cea72436ab5 --- /dev/null +++ b/res/res_pjsip/pjsip_session.c @@ -0,0 +1,121 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2017, CFWare, LLC + * + * Corey Farrell + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include "asterisk.h" + +#include +#include +#include + +#include "asterisk/res_pjsip.h" +#include "asterisk/res_pjsip_session.h" +#include "include/res_pjsip_private.h" +#include "asterisk/linkedlists.h" +#include "asterisk/lock.h" +#include "asterisk/module.h" + + +AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement); + +void internal_sip_session_register_supplement(struct ast_sip_session_supplement *supplement) +{ + struct ast_sip_session_supplement *iter; + int inserted = 0; + SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + + if (!supplement->response_priority) { + supplement->response_priority = AST_SIP_SESSION_BEFORE_MEDIA; + } + + AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) { + if (iter->priority > supplement->priority) { + AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next); + inserted = 1; + break; + } + } + AST_RWLIST_TRAVERSE_SAFE_END; + + if (!inserted) { + AST_RWLIST_INSERT_TAIL(&session_supplements, supplement, next); + } +} + +int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement) +{ + internal_sip_session_register_supplement(supplement); + ast_module_ref(AST_MODULE_SELF); + + return 0; +} + +int internal_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement) +{ + struct ast_sip_session_supplement *iter; + int res = -1; + SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) { + if (supplement == iter) { + AST_RWLIST_REMOVE_CURRENT(next); + res = 0; + break; + } + } + AST_RWLIST_TRAVERSE_SAFE_END; + + return res; +} + +void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement) +{ + if (!internal_sip_session_unregister_supplement(supplement)) { + ast_module_unref(AST_MODULE_SELF); + } +} + +static struct ast_sip_session_supplement *supplement_dup(const struct ast_sip_session_supplement *src) +{ + struct ast_sip_session_supplement *dst = ast_calloc(1, sizeof(*dst)); + + if (!dst) { + return NULL; + } + /* Will need to revisit if shallow copy becomes an issue */ + *dst = *src; + + return dst; +} + +int ast_sip_session_add_supplements(struct ast_sip_session *session) +{ + struct ast_sip_session_supplement *iter; + SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_TRAVERSE(&session_supplements, iter, next) { + struct ast_sip_session_supplement *copy = supplement_dup(iter); + + if (!copy) { + return -1; + } + AST_LIST_INSERT_TAIL(&session->supplements, copy, next); + } + + return 0; +} + diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 70c88a50499..fab275733fc 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -907,59 +907,6 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ return 0; } -AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement); - -int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement) -{ - struct ast_sip_session_supplement *iter; - int inserted = 0; - SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); - - if (!supplement->response_priority) { - supplement->response_priority = AST_SIP_SESSION_BEFORE_MEDIA; - } - - AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) { - if (iter->priority > supplement->priority) { - AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next); - inserted = 1; - break; - } - } - AST_RWLIST_TRAVERSE_SAFE_END; - - if (!inserted) { - AST_RWLIST_INSERT_TAIL(&session_supplements, supplement, next); - } - ast_module_ref(ast_module_info->self); - return 0; -} - -void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement) -{ - struct ast_sip_session_supplement *iter; - SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); - AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) { - if (supplement == iter) { - AST_RWLIST_REMOVE_CURRENT(next); - ast_module_unref(ast_module_info->self); - break; - } - } - AST_RWLIST_TRAVERSE_SAFE_END; -} - -static struct ast_sip_session_supplement *supplement_dup(const struct ast_sip_session_supplement *src) -{ - struct ast_sip_session_supplement *dst = ast_calloc(1, sizeof(*dst)); - if (!dst) { - return NULL; - } - /* Will need to revisit if shallow copy becomes an issue */ - *dst = *src; - return dst; -} - #define DATASTORE_BUCKETS 53 #define MEDIA_BUCKETS 7 @@ -2045,21 +1992,6 @@ static void session_destructor(void *obj) ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name); } -static int add_supplements(struct ast_sip_session *session) -{ - struct ast_sip_session_supplement *iter; - SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); - - AST_RWLIST_TRAVERSE(&session_supplements, iter, next) { - struct ast_sip_session_supplement *copy = supplement_dup(iter); - if (!copy) { - return -1; - } - AST_LIST_INSERT_TAIL(&session->supplements, copy, next); - } - return 0; -} - /*! \brief Destructor for SIP channel */ static void sip_channel_destroy(void *obj) { @@ -2166,7 +2098,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, session->dtmf = endpoint->dtmf; - if (add_supplements(session)) { + if (ast_sip_session_add_supplements(session)) { /* Release the ref held by session->inv_session */ ao2_ref(session, -1); return NULL; From 65399a5edac34b4b2b9982fc0ad82489350b57d2 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Wed, 4 Oct 2017 11:59:49 -0400 Subject: [PATCH 1521/1578] res_pjsip: Add REF_DEBUG info to module references. This provides better information to REF_DEBUG log for troubleshooting when the system is unable to unload res_pjsip.so during shutdown due to module references. ASTERISK-27306 Change-Id: I63197ad33d1aebe60d12e0a6561718bdc54e4612 --- include/asterisk/res_pjsip.h | 18 ++++++++--- include/asterisk/res_pjsip_session.h | 10 ++++-- res/res_pjsip.c | 48 +++++++++++----------------- res/res_pjsip.exports.in | 1 + res/res_pjsip/pjsip_session.c | 10 +++--- res/res_pjsip_session.exports.in | 1 + 6 files changed, 48 insertions(+), 40 deletions(-) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index b6403d6fadc..e6ccf0a1d4f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -925,7 +925,9 @@ enum ast_sip_contact_filter { * \retval 0 Success * \retval -1 Failure */ -int ast_sip_register_service(pjsip_module *module); +#define ast_sip_register_service(module) \ + __ast_sip_register_service(module, __FILE__, __LINE__, __PRETTY_FUNCTION__) +int __ast_sip_register_service(pjsip_module *module, const char *file, int line, const char *func); /*! * This is the opposite of ast_sip_register_service(). Unregistering a @@ -934,7 +936,9 @@ int ast_sip_register_service(pjsip_module *module); * * \param module The PJSIP module to unregister */ -void ast_sip_unregister_service(pjsip_module *module); +#define ast_sip_unregister_service(module) \ + __ast_sip_unregister_service(module, __FILE__, __LINE__, __PRETTY_FUNCTION__) +void __ast_sip_unregister_service(pjsip_module *module, const char *file, int line, const char *func); /*! * \brief Register a SIP authenticator @@ -2615,14 +2619,20 @@ struct ast_sip_supplement { * \retval 0 Success * \retval -1 Failure */ -int ast_sip_register_supplement(struct ast_sip_supplement *supplement); +#define ast_sip_register_supplement(supplement) \ + __ast_sip_register_supplement(supplement, __FILE__, __LINE__, __PRETTY_FUNCTION__) +int __ast_sip_register_supplement(struct ast_sip_supplement *supplement, + const char *file, int line, const char *func); /*! * \brief Unregister a an supplement to SIP out of dialog processing * * \param supplement The supplement to unregister */ -void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement); +#define ast_sip_unregister_supplement(supplement) \ + __ast_sip_unregister_supplement(supplement, __FILE__, __LINE__, __PRETTY_FUNCTION__) +void __ast_sip_unregister_supplement(struct ast_sip_supplement *supplement, + const char *file, int line, const char *func); /*! * \brief Retrieve the global MWI taskprocessor high water alert trigger level. diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 70f94682e0e..b7a22b93790 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -578,14 +578,20 @@ void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler * * \retval 0 Success * \retval -1 Failure */ -int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement); +#define ast_sip_session_register_supplement(supplement) \ + __ast_sip_session_register_supplement(supplement, __FILE__, __LINE__, __PRETTY_FUNCTION__) +int __ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement, + const char *file, int line, const char *func); /*! * \brief Unregister a an supplement to SIP session processing * * \param supplement The supplement to unregister */ -void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement); +#define ast_sip_session_unregister_supplement(supplement) \ + __ast_sip_session_unregister_supplement(supplement, __FILE__, __LINE__, __PRETTY_FUNCTION__) +void __ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement, + const char *file, int line, const char *func); /*! * \brief Add supplements to a SIP session diff --git a/res/res_pjsip.c b/res/res_pjsip.c index ac275bd0841..fb919b32b2b 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2422,25 +2422,20 @@ static int register_service_noref(void *data) return 0; } -static int register_service(void *data) -{ - int res; - - if (!(res = register_service_noref(data))) { - ast_module_ref(ast_module_info->self); - } - - return res; -} - int internal_sip_register_service(pjsip_module *module) { return ast_sip_push_task_synchronous(NULL, register_service_noref, &module); } -int ast_sip_register_service(pjsip_module *module) +int __ast_sip_register_service(pjsip_module *module, const char *file, int line, const char *func) { - return ast_sip_push_task_synchronous(NULL, register_service, &module); + int res; + + if (!(res = ast_sip_push_task_synchronous(NULL, register_service_noref, &module))) { + __ast_module_ref(ast_module_info->self, file, line, func); + } + + return res; } static int unregister_service_noref(void *data) @@ -2454,25 +2449,16 @@ static int unregister_service_noref(void *data) return 0; } -static int unregister_service(void *data) -{ - int res; - - if (!(res = unregister_service_noref(data))) { - ast_module_unref(ast_module_info->self); - } - - return res; -} - int internal_sip_unregister_service(pjsip_module *module) { return ast_sip_push_task_synchronous(NULL, unregister_service_noref, &module); } -void ast_sip_unregister_service(pjsip_module *module) +void __ast_sip_unregister_service(pjsip_module *module, const char *file, int line, const char *func) { - ast_sip_push_task_synchronous(NULL, unregister_service, &module); + if (!ast_sip_push_task_synchronous(NULL, unregister_service_noref, &module)) { + __ast_module_unref(ast_module_info->self, file, line, func); + } } static struct ast_sip_authenticator *registered_authenticator; @@ -3536,10 +3522,11 @@ void internal_sip_register_supplement(struct ast_sip_supplement *supplement) } } -int ast_sip_register_supplement(struct ast_sip_supplement *supplement) +int __ast_sip_register_supplement(struct ast_sip_supplement *supplement, + const char *file, int line, const char *func) { internal_sip_register_supplement(supplement); - ast_module_ref(ast_module_info->self); + __ast_module_ref(ast_module_info->self, file, line, func); return 0; } @@ -3562,10 +3549,11 @@ int internal_sip_unregister_supplement(struct ast_sip_supplement *supplement) return res; } -void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement) +void __ast_sip_unregister_supplement(struct ast_sip_supplement *supplement, + const char *file, int line, const char *func) { if (!internal_sip_unregister_supplement(supplement)) { - ast_module_unref(ast_module_info->self); + __ast_module_unref(ast_module_info->self, file, line, func); } } diff --git a/res/res_pjsip.exports.in b/res/res_pjsip.exports.in index 4adecd419c2..7ac2b7e83aa 100644 --- a/res/res_pjsip.exports.in +++ b/res/res_pjsip.exports.in @@ -1,6 +1,7 @@ { global: LINKER_SYMBOL_PREFIXast_sip_*; + LINKER_SYMBOL_PREFIX__ast_sip_*; LINKER_SYMBOL_PREFIXast_copy_pj_str; LINKER_SYMBOL_PREFIXast_copy_pj_str2; LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint; diff --git a/res/res_pjsip/pjsip_session.c b/res/res_pjsip/pjsip_session.c index cea72436ab5..4f3e3be5566 100644 --- a/res/res_pjsip/pjsip_session.c +++ b/res/res_pjsip/pjsip_session.c @@ -56,10 +56,11 @@ void internal_sip_session_register_supplement(struct ast_sip_session_supplement } } -int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement) +int __ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement, + const char *file, int line, const char *func) { internal_sip_session_register_supplement(supplement); - ast_module_ref(AST_MODULE_SELF); + __ast_module_ref(AST_MODULE_SELF, file, line, func); return 0; } @@ -82,10 +83,11 @@ int internal_sip_session_unregister_supplement(struct ast_sip_session_supplement return res; } -void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement) +void __ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement, + const char *file, int line, const char *func) { if (!internal_sip_session_unregister_supplement(supplement)) { - ast_module_unref(AST_MODULE_SELF); + __ast_module_unref(AST_MODULE_SELF, file, line, func); } } diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in index b7bd21b893d..d65b247c7a1 100644 --- a/res/res_pjsip_session.exports.in +++ b/res/res_pjsip_session.exports.in @@ -1,6 +1,7 @@ { global: LINKER_SYMBOL_PREFIXast_sip_session_*; + LINKER_SYMBOL_PREFIX__ast_sip_session_*; LINKER_SYMBOL_PREFIXast_sip_dialog_get_session; LINKER_SYMBOL_PREFIXast_sip_channel_pvt_alloc; local: From 59b6e8467a399b5654e640455c0f5683ce029cd6 Mon Sep 17 00:00:00 2001 From: Daniel Tryba Date: Mon, 2 Oct 2017 14:48:41 +0200 Subject: [PATCH 1522/1578] res_pjsip_caller_id chan_sip: Comply to RFC 3323 values for privacy Currently privacy requests are only granted if the Privacy header value is exactly "id" (defined in RFC 3325). It ignores any other possible value (or a combination there of). This patch reverses the logic from testing for "id" to grant privacy, to testing for "none" and granting privacy for any other value. "none" must not be used in combination with any other value (RFC 3323 section 4.2). ASTERISK-27284 #close Change-Id: If438a21f31a962da32d7a33ff33bdeb1e776fe56 --- channels/chan_sip.c | 2 +- res/res_pjsip_caller_id.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 8a30e0c00e8..62ff505fc4a 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -18127,7 +18127,7 @@ static int get_pai(struct sip_pvt *p, struct sip_request *req) } ast_copy_string(privacy, sip_get_header(req, "Privacy"), sizeof(privacy)); - if (!ast_strlen_zero(privacy) && !strncmp(privacy, "id", 2)) { + if (!ast_strlen_zero(privacy) && strcasecmp(privacy, "none")) { callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; } if (!cid_name) { diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 470d90f43ee..64191a75099 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -149,12 +149,12 @@ static int set_id_from_pai(pjsip_rx_data *rdata, struct ast_party_id *id) } privacy = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &privacy_str, NULL); - if (privacy && !pj_stricmp2(&privacy->hvalue, "id")) { - id->number.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; - id->name.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; - } else { + if (!privacy || !pj_stricmp2(&privacy->hvalue, "none")) { id->number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; id->name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + } else { + id->number.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; + id->name.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; } return 0; From 0b6be1b2d4063e539561f46fe4f1df71c8db556a Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 5 Oct 2017 20:55:31 -0400 Subject: [PATCH 1523/1578] res_sdp_translator_pjmedia: Fix test unregistration. ASTERISK-27306 Change-Id: Ib3ed47167cb697ab7bd0a56cab589893f491651b --- res/res_sdp_translator_pjmedia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c index d80f3d554be..772be272c8f 100644 --- a/res/res_sdp_translator_pjmedia.c +++ b/res/res_sdp_translator_pjmedia.c @@ -585,7 +585,7 @@ static int unload_module(void) ast_sdp_unregister_translator(&pjmedia_translator); pj_caching_pool_destroy(&sdp_caching_pool); AST_TEST_UNREGISTER(pjmedia_to_sdp_test); - AST_TEST_REGISTER(sdp_to_pjmedia_test); + AST_TEST_UNREGISTER(sdp_to_pjmedia_test); return 0; } From 0f3e725503a84ce9b39120b5f74f1e504d18a98a Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 5 Oct 2017 21:23:31 -0400 Subject: [PATCH 1524/1578] main/strings: Fix uninitialized value. ast_strings_match uses sscanf and checks for non-zero return to verify a token was parsed. This is incorrect as sscanf returns EOF (-1) for errors. ASTERISK-27318 #close Change-Id: Ifcece92605f58116eff24c5a0a3b0ee08b3c87b1 --- main/strings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/strings.c b/main/strings.c index 3207fa15e4d..82e315aeacb 100644 --- a/main/strings.c +++ b/main/strings.c @@ -312,7 +312,7 @@ int ast_strings_match(const char *left, const char *op, const char *right) } equals: - scan_numeric = (sscanf(left, "%lf", &left_num) && sscanf(internal_right, "%lf", &right_num)); + scan_numeric = (sscanf(left, "%lf", &left_num) > 0 && sscanf(internal_right, "%lf", &right_num) > 0); if (internal_op[0] == '=') { if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) { From b35ac9e566666fb5f8d98db522ec56353f915a77 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 5 Oct 2017 16:54:12 -0400 Subject: [PATCH 1525/1578] res_pjsip: Fix leak of fake_auth references. pjsip_distributor leaks references to fake_auth when the default realm has not changed. ASTERISK-27306 Change-Id: I3fcf103b3680ad2d1d4610dcd6738eeaebf4d202 --- res/res_pjsip/pjsip_distributor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index cf1b04a8bd4..b4828d89fb0 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -1142,9 +1142,9 @@ static void global_loaded(const char *object_type) fake_auth = alloc_artificial_auth(default_realm); if (fake_auth) { ao2_global_obj_replace_unref(artificial_auth, fake_auth); - ao2_ref(fake_auth, -1); } } + ao2_cleanup(fake_auth); ast_sip_get_unidentified_request_thresholds(&unidentified_count, &unidentified_period, &unidentified_prune_interval); From 3bd00c4a7eeb9da143b5f7ff1ec12bdfcc2c5af7 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 5 Oct 2017 18:59:06 -0400 Subject: [PATCH 1526/1578] vector: multiple evaluation of elem in AST_VECTOR_ADD_SORTED. Use temporary variable to prevent multiple evaluations of elem argument. This resolves a memory leak in res_pjproject startup. ASTERISK-27317 #close Change-Id: Ib960d7f5576f9e1a3c478ecb48995582a574e06d --- include/asterisk/vector.h | 10 +++++++--- tests/test_vector.c | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index 2de84d295ab..1e6fe038cf3 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -304,27 +304,31 @@ AST_VECTOR(ast_vector_int, int); * \brief Add an element into a sorted vector * * \param vec Sorted vector to add to. - * \param elem Element to insert. + * \param elem Element to insert. Must not be an array type. * \param cmp A strcmp compatible compare function. * * \return 0 on success. * \return Non-zero on failure. * * \warning Use of this macro on an unsorted vector will produce unpredictable results + * \warning 'elem' must not be an array type so passing 'x' where 'x' is defined as + * 'char x[4]' will fail to compile. However casting 'x' as 'char *' does + * result in a value that CAN be used. */ #define AST_VECTOR_ADD_SORTED(vec, elem, cmp) ({ \ int res = 0; \ size_t __idx = (vec)->current; \ + typeof(elem) __elem = (elem); \ do { \ if (__make_room((vec)->current, vec) != 0) { \ res = -1; \ break; \ } \ - while (__idx > 0 && (cmp((vec)->elems[__idx - 1], elem) > 0)) { \ + while (__idx > 0 && (cmp((vec)->elems[__idx - 1], __elem) > 0)) { \ (vec)->elems[__idx] = (vec)->elems[__idx - 1]; \ __idx--; \ } \ - (vec)->elems[__idx] = elem; \ + (vec)->elems[__idx] = __elem; \ (vec)->current++; \ } while (0); \ res; \ diff --git a/tests/test_vector.c b/tests/test_vector.c index 8e0d121ddf2..2dfcc60a8c6 100644 --- a/tests/test_vector.c +++ b/tests/test_vector.c @@ -210,7 +210,7 @@ AST_TEST_DEFINE(basic_ops) ast_test_validate_cleanup(test, AST_VECTOR_ADD_SORTED(&sv1, ZZZ, strcmp) == 0, rc, cleanup); ast_test_validate_cleanup(test, AST_VECTOR_ADD_SORTED(&sv1, CCC, strcmp) == 0, rc, cleanup); ast_test_validate_cleanup(test, AST_VECTOR_ADD_SORTED(&sv1, AAA, strcmp) == 0, rc, cleanup); - ast_test_validate_cleanup(test, AST_VECTOR_ADD_SORTED(&sv1, CCC2, strcmp) == 0, rc, cleanup); + ast_test_validate_cleanup(test, AST_VECTOR_ADD_SORTED(&sv1, (char*)CCC2, strcmp) == 0, rc, cleanup); ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 0) == AAA, rc, cleanup); ast_test_validate_cleanup(test, AST_VECTOR_GET(&sv1, 1) == BBB, rc, cleanup); From a68a91f722b7b29bdf77dc4264b5d554ae4ea692 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 5 Oct 2017 17:26:14 -0400 Subject: [PATCH 1527/1578] res_pjsip: Fix leak of persistent endpoint references. Do not manually call sip_endpoint_apply_handler from load_all_endpoints. This is not necessary and causes memory leaks. Additionally reinitialize persistent->aors when we reuse a persistent object with a new endpoint. ASTERISK-27306 Change-Id: I59bbfc8da8a14d5f4af8c5bb1e71f8592ae823eb --- res/res_pjsip/pjsip_configuration.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 3a752c90ddd..653cb98ac77 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1315,6 +1315,14 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_ ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_OFFLINE); ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK); + } else if (strcmp(persistent->aors, endpoint->aors)) { + char *new_aors = ast_strdup(endpoint->aors); + + /* make sure we don't NULL persistent->aors if allocation fails. */ + if (new_aors) { + ast_free(persistent->aors); + persistent->aors = new_aors; + } } ao2_ref(persistent->endpoint, +1); @@ -1821,20 +1829,12 @@ static struct ast_cli_entry cli_commands[] = { struct ast_sip_cli_formatter_entry *channel_formatter; struct ast_sip_cli_formatter_entry *endpoint_formatter; -static int on_load_endpoint(void *obj, void *arg, int flags) -{ - return sip_endpoint_apply_handler(sip_sorcery, obj); -} - static void load_all_endpoints(void) { struct ao2_container *endpoints; endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); - if (endpoints) { - ao2_callback(endpoints, OBJ_NODATA, on_load_endpoint, NULL); - ao2_ref(endpoints, -1); - } + ao2_cleanup(endpoints); } int ast_res_pjsip_initialize_configuration(void) From f4798faacc34d97e5d93bde3bbacca84f83f5c78 Mon Sep 17 00:00:00 2001 From: Matt Jordan Date: Fri, 6 Oct 2017 10:51:17 -0500 Subject: [PATCH 1528/1578] res_corosync: Fix linking issue with Corosync 2.x At some point in time in the history of Corosync (certainly within the 2.x branch), the corosync_cfg_state_track function was removed. Unfortunately, the cfg library is only linked if this function is present. Without the cfg library being linked to res_corosync, loading of res_corosync will fail. This patch makes it so that detecting corosync's core libraries, determined by the COROSYNC external library checks, links both the cpg and cfg libraries with res_corosync. Change-Id: I674e9e1c8fea11c3bf81154aaa7c1fd43f945465 --- configure | 4 ++-- configure.ac | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 368e6b453e0..59bc3b10b15 100755 --- a/configure +++ b/configure @@ -31953,7 +31953,7 @@ if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lcpg ${pbxlibdir} -lcpg $LIBS" +LIBS="-lcpg ${pbxlibdir} -lcpg -lcfg $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -31995,7 +31995,7 @@ fi # now check for the header. if test "${AST_COROSYNC_FOUND}" = "yes"; then - COROSYNC_LIB="${pbxlibdir} -lcpg -lcpg" + COROSYNC_LIB="${pbxlibdir} -lcpg -lcpg -lcfg" # if --with-COROSYNC=DIR has been specified, use it. if test "x${COROSYNC_DIR}" != "x"; then COROSYNC_INCLUDE="-I${COROSYNC_DIR}/include" diff --git a/configure.ac b/configure.ac index cf4518c2103..9f95786e113 100644 --- a/configure.ac +++ b/configure.ac @@ -2425,7 +2425,7 @@ fi AST_EXT_LIB_CHECK([CODEC2], [codec2], [codec2_create], [codec2/codec2.h]) -AST_EXT_LIB_CHECK([COROSYNC], [cpg], [cpg_join], [corosync/cpg.h], [-lcpg]) +AST_EXT_LIB_CHECK([COROSYNC], [cpg], [cpg_join], [corosync/cpg.h], [-lcpg -lcfg]) AST_EXT_LIB_CHECK([COROSYNC_CFG_STATE_TRACK], [cfg], [corosync_cfg_state_track], [corosync/cfg.h], [-lcfg]) AST_EXT_LIB_CHECK([SPEEX], [speex], [speex_encode], [speex/speex.h], [-lm]) From eb224fea5e02ce4073a48032a7030e129118a49c Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 7 Oct 2017 16:47:53 -0400 Subject: [PATCH 1529/1578] res_pjsip_session: Fix format_cap leak. ASTERISK-27306 Change-Id: I2c8d3fc148f9f53715c958314e1146f9611741f3 --- res/res_pjsip_session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 70c88a50499..a666658d460 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1547,6 +1547,7 @@ int ast_sip_session_refresh(struct ast_sip_session *session, } } ast_stream_set_formats(stream, joint_cap); + ao2_cleanup(joint_cap); } ++type_streams[ast_stream_get_type(stream)]; From feeb0974eb330cb92c9d6c0f54a388267a6f3bbc Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Sun, 8 Oct 2017 16:11:10 +0200 Subject: [PATCH 1530/1578] tcptls: Do not re-bind to wildcard on client creation. Since ASTERISK-26922, this issue affected only those chan_sip which were * enabled for dual-stack (bindaddr=::), and * enabled for TCP (tcpenable=yes) and/or TLS (tlsenable=yes), and * tried to register and/or invite a IPv4-only service, * via TCP and/or TLS. Now, ast_tcptls_client_create does not re-bind to [::] anymore. ASTERISK-27324 #close Change-Id: I4b242837bdeb1ec7130dc82505c6180a946fd9b5 --- main/tcptls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/tcptls.c b/main/tcptls.c index ebe86f3e005..dbcff9da21b 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -572,7 +572,8 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s /* if a local address was specified, bind to it so the connection will originate from the desired address */ - if (!ast_sockaddr_isnull(&desc->local_address)) { + if (!ast_sockaddr_isnull(&desc->local_address) && + !ast_sockaddr_is_any(&desc->local_address)) { setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); if (ast_bind(desc->accept_fd, &desc->local_address)) { ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", From a0a1f95abfe04d51a52cfb3b9db1e69a9e12c659 Mon Sep 17 00:00:00 2001 From: hajekd Date: Sun, 8 Oct 2017 21:05:56 +0200 Subject: [PATCH 1531/1578] res/res_ari.c Fix: Memory leaks in ARI when using Content-Type: application/json ASTERISK-27305 Reported by: David Hajek Tested by: David Hajek Change-Id: Ife3e289062e6cf7d0e7d342dbf79ed96feff441e --- res/res_ari.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_ari.c b/res/res_ari.c index 054d3bf3c59..5145499bef5 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -884,7 +884,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser, RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy); struct ast_variable *var; const char *app_name = NULL; - RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_free); + RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_unref); int debug_app = 0; if (!response_body) { From ad38a55a2d6b765f6a0dee51dfa9681e0aafb167 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Mon, 9 Oct 2017 09:15:54 -0400 Subject: [PATCH 1532/1578] res_config_sqlite: Don't enable SQLite CDRs when running 'make samples' Change-Id: I65a5190b2732b2246d67472db70dd37db64ddad4 --- configs/samples/res_config_sqlite.conf.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/samples/res_config_sqlite.conf.sample b/configs/samples/res_config_sqlite.conf.sample index 04e6ae2e74d..2d14d46a3dd 100644 --- a/configs/samples/res_config_sqlite.conf.sample +++ b/configs/samples/res_config_sqlite.conf.sample @@ -8,4 +8,4 @@ dbfile => /var/lib/asterisk/sqlite.db ; extconfig.conf, the value given here is used. If cdr_table is omitted, CDR ; support is simply disabled. config_table => ast_config -cdr_table => ast_cdr +; cdr_table => ast_cdr From fb19799b622bf41897f91b06ec8be81f858eac92 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 20 Sep 2017 18:36:15 -0500 Subject: [PATCH 1533/1578] res_pjsip_registrar.c: Update remove_existing AOR contact handling. When "rewrite_contact" is enabled, the "max_contacts" count option can block re-registrations because the source port from the endpoint can be random. When the re-registration is blocked, the endpoint may give up re-registering and require manual intervention. * The "remove_existing" option now allows a registration to succeed by displacing any existing contacts that now exceed the "max_contacts" count. Any removed contacts are the next to expire. The behaviour change is beneficial when "rewrite_contact" is enabled and "max_contacts" is greater than one. The removed contact is likely the old contact created by "rewrite_contact" that the device is refreshing. ASTERISK-27192 Change-Id: I64c107a10b70db1697d17136051ae6bf22b5314b --- CHANGES | 13 +++ configs/samples/pjsip.conf.sample | 10 +- include/asterisk/vector.h | 8 ++ res/res_pjsip.c | 32 +++++- res/res_pjsip_registrar.c | 156 +++++++++++++++++++++++++++--- 5 files changed, 198 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index dde24e2caec..4d1395fba46 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,19 @@ chan_sip headers be retrieved from the REFER message and made accessible to the dialplan in the hash TRANSFER_DATA. +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 15.0.0 to Asterisk 15.1.0 ------------ +------------------------------------------------------------------------------ + +res_pjsip +------------------ + * The "remove_existing" option now allows a registration to succeed by + displacing any existing contacts that now exceed the "max_contacts" count. + Any removed contacts are the next to expire. The behaviour change is + beneficial when "rewrite_contact" is enabled and "max_contacts" is greater + than one. The removed contact is likely the old contact created by + "rewrite_contact" that the device is refreshing. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 9a2592bedcf..c535aaf04c4 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -918,7 +918,13 @@ ;max_contacts=0 ; Maximum number of contacts that can bind to an AoR (default: ; "0") ;minimum_expiration=60 ; Minimum keep alive time for an AoR (default: "60") -;remove_existing=no ; Determines whether new contacts replace existing ones +;remove_existing=no ; Allow a registration to succeed by displacing any existing + ; contacts that now exceed the max_contacts count. Any + ; removed contacts are the next to expire. The behaviour is + ; beneficial when rewrite_contact is enabled and max_contacts + ; is greater than one. The removed contact is likely the old + ; contact created by rewrite_contact that the device is + ; refreshing. ; (default: "no") ;type= ; Must be of type aor (default: "") ;qualify_frequency=0 ; Interval at which to qualify an AoR (default: "0") @@ -1157,7 +1163,7 @@ ;outbound_auth= ; Authentication object(s) to be used for outbound ; publishes. - ; This is a comma-delimited list of auth sections + ; This is a comma-delimited list of auth sections ; defined in pjsip.conf used to respond to outbound ; authentication challenges. ; Using the same auth section for inbound and diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index 1e6fe038cf3..68ce13065df 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -547,6 +547,14 @@ AST_VECTOR(ast_vector_int, int); */ #define AST_VECTOR_SIZE(vec) (vec)->current +/*! + * \brief Get the maximum number of elements the vector can currently hold. + * + * \param vec Vector to query. + * \return Maximum number of elements the vector can currently hold. + */ +#define AST_VECTOR_MAX_SIZE(vec) (vec)->max + /*! * \brief Reset vector. * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 6c1f7765949..cbeb5ea3d4a 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1448,6 +1448,18 @@ It only limits contacts added through external interaction, such as registration. + The rewrite_contact option + registers the source address as the contact address to help with + NAT and reusing connection oriented transports such as TCP and + TLS. Unfortunately, refreshing a registration may register a + different contact address and exceed + max_contacts. The + remove_existing option can help by + removing the soonest to expire contact(s) over + max_contacts which is likely the + old rewrite_contact contact source + address being refreshed. + This should be set to 1 and remove_existing set to yes if you wish to stick with the older chan_sip behaviour. @@ -1457,15 +1469,29 @@ Minimum keep alive time for an AoR - Minimum time to keep a peer with an explict expiration. Time in seconds. + Minimum time to keep a peer with an explicit expiration. Time in seconds. Determines whether new contacts replace existing ones. - On receiving a new registration to the AoR should it remove - the existing contact that was registered against it? + On receiving a new registration to the AoR should it remove enough + existing contacts not added or updated by the registration to + satisfy max_contacts? Any removed + contacts will expire the soonest. + The rewrite_contact option + registers the source address as the contact address to help with + NAT and reusing connection oriented transports such as TCP and + TLS. Unfortunately, refreshing a registration may register a + different contact address and exceed + max_contacts. The + remove_existing option can help by + removing the soonest to expire contact(s) over + max_contacts which is likely the + old rewrite_contact contact source + address being refreshed. + This should be set to yes and max_contacts set to 1 if you wish to stick with the older chan_sip behaviour. diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index ba1c074b369..32906011ac1 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -129,7 +129,8 @@ static int registrar_find_contact(void *obj, void *arg, int flags) /*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted) { - pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; + pjsip_contact_hdr *previous = NULL; + pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; struct registrar_contact_details details = { .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256), }; @@ -140,15 +141,18 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) { int expiration = registrar_get_expiration(aor, contact, rdata); - RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup); + struct ast_sip_contact *existing; char contact_uri[pjsip_max_url_size]; if (contact->star) { /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */ - if ((expiration != 0) || previous) { + if (expiration != 0 || previous) { pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return -1; } + /* Count all contacts to delete */ + *deleted = ao2_container_count(contacts); + previous = contact; continue; } else if (previous && previous->star) { /* If there is a previous contact and it is a '*' this is a deal breaker */ @@ -177,14 +181,16 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co } /* Determine if this is an add, update, or delete for policy enforcement purposes */ - if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) { + existing = ao2_callback(contacts, 0, registrar_find_contact, &details); + ao2_cleanup(existing); + if (!existing) { if (expiration) { - (*added)++; + ++*added; } } else if (expiration) { - (*updated)++; + ++*updated; } else { - (*deleted)++; + ++*deleted; } } @@ -219,7 +225,7 @@ static int registrar_delete_contact(void *obj, void *arg, int flags) contact->user_agent); } - return 0; + return CMP_MATCH; } /*! \brief Internal function which adds a contact to a response */ @@ -351,6 +357,96 @@ static void register_contact_transport_shutdown_cb(void *data) ao2_ref(aor, -1); } +AST_VECTOR(excess_contact_vector, struct ast_sip_contact *); + +static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact *right) +{ + struct ast_sip_contact *left_contact = left; + struct ast_sip_contact *right_contact = right; + + /* Sort from soonest to expire to last to expire */ + return ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time); +} + +static int vec_contact_add(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct excess_contact_vector *contact_vec = arg; + + /* + * Performance wise, an insertion sort is fine because we + * shouldn't need to remove more than a handful of contacts. + * I expect we'll typically be removing only one contact. + */ + AST_VECTOR_ADD_SORTED(contact_vec, contact, vec_contact_cmp); + if (AST_VECTOR_SIZE(contact_vec) == AST_VECTOR_MAX_SIZE(contact_vec)) { + /* + * We added a contact over the number we need to remove. + * Remove the longest to expire contact from the vector + * which is the last element in the vector. It may be + * the one we just added or the one we just added pushed + * out an earlier contact from removal consideration. + */ + --AST_VECTOR_SIZE(contact_vec); + } + return 0; +} + +/*! + * \internal + * \brief Remove excess existing contacts that expire the soonest. + * \since 13.18.0 + * + * \param contacts Container of unmodified contacts that could remove. + * \param to_remove Maximum number of contacts to remove. + * + * \return Nothing + */ +static void remove_excess_contacts(struct ao2_container *contacts, unsigned int to_remove) +{ + struct excess_contact_vector contact_vec; + + /* + * Create a sorted vector to hold the to_remove soonest to + * expire contacts. The vector has an extra space to + * temporarily hold the longest to expire contact that we + * won't remove. + */ + if (AST_VECTOR_INIT(&contact_vec, to_remove + 1)) { + return; + } + ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, vec_contact_add, &contact_vec); + + /* + * The vector should always be populated with the number + * of contacts we need to remove. Just in case, we will + * remove all contacts in the vector even if the contacts + * container had fewer contacts than there should be. + */ + ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove); + to_remove = AST_VECTOR_SIZE(&contact_vec); + + /* Remove the excess contacts that expire the soonest */ + while (to_remove--) { + struct ast_sip_contact *contact; + + contact = AST_VECTOR_GET(&contact_vec, to_remove); + + ast_sip_location_delete_contact(contact); + ast_verb(3, "Removed contact '%s' from AOR '%s' due to remove_existing\n", + contact->uri, contact->aor); + ast_test_suite_event_notify("AOR_CONTACT_REMOVED", + "Contact: %s\r\n" + "AOR: %s\r\n" + "UserAgent: %s", + contact->uri, + contact->aor, + contact->user_agent); + } + + AST_VECTOR_FREE(&contact_vec); +} + static int register_aor_core(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, @@ -359,7 +455,10 @@ static int register_aor_core(pjsip_rx_data *rdata, { static const pj_str_t USER_AGENT = { "User-Agent", 10 }; - int added = 0, updated = 0, deleted = 0; + int added = 0; + int updated = 0; + int deleted = 0; + int contact_count; pjsip_contact_hdr *contact_hdr = NULL; struct registrar_contact_details details = { 0, }; pjsip_tx_data *tdata; @@ -396,7 +495,14 @@ static int register_aor_core(pjsip_rx_data *rdata, return PJ_TRUE; } - if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) { + if (aor->remove_existing) { + /* Cumulative number of contacts affected by this registration */ + contact_count = MAX(updated + added - deleted, 0); + } else { + /* Total contacts after this registration */ + contact_count = ao2_container_count(contacts) + added - deleted; + } + if (contact_count > aor->max_contacts) { /* Enforce the maximum number of contacts */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts"); @@ -405,7 +511,9 @@ static int register_aor_core(pjsip_rx_data *rdata, return PJ_TRUE; } - if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) { + details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), + "Contact Comparison", 256, 256); + if (!details.pool) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } @@ -446,7 +554,8 @@ static int register_aor_core(pjsip_rx_data *rdata, if (contact_hdr->star) { /* A star means to unregister everything, so do so for the possible contacts */ - ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name); + ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, + registrar_delete_contact, (void *)aor_name); break; } @@ -459,7 +568,8 @@ static int register_aor_core(pjsip_rx_data *rdata, details.uri = pjsip_uri_get_uri(contact_hdr->uri); pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)); - if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) { + contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details); + if (!contact) { int prune_on_boot = 0; pj_str_t host_name; @@ -600,15 +710,29 @@ static int register_aor_core(pjsip_rx_data *rdata, pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); - /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER - * do so + /* + * If the AOR is configured to remove any contacts over max_contacts + * that have not been updated/added/deleted as a result of this + * REGISTER do so. + * + * The contacts container currently holds the existing contacts that + * were not affected by this REGISTER. */ if (aor->remove_existing) { - ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL); + /* Total contacts after this registration */ + contact_count = ao2_container_count(contacts) + updated + added; + if (contact_count > aor->max_contacts) { + /* Remove excess existing contacts that expire the soonest */ + remove_excess_contacts(contacts, contact_count - aor->max_contacts); + } } /* Re-retrieve contacts. Caller will clean up the original container. */ contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); + if (!contacts) { + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); + return PJ_TRUE; + } response_contact = ao2_callback(contacts, 0, NULL, NULL); /* Send a response containing all of the contacts (including static) that are present on this AOR */ From e769846f11d9159dc8647a7ff219088f076299ab Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 29 Sep 2017 12:31:18 -0500 Subject: [PATCH 1534/1578] cdr.h: Fix doxygen comments. * Also some misc formatting in cdr.c. Change-Id: Ied89a28802a662c37c43326a1aafdce596e0df4a --- include/asterisk/cdr.h | 44 +++++++++++++++++++++--------------------- main/cdr.c | 18 ++++++++++------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h index f752f7f9fcf..e10da822327 100644 --- a/include/asterisk/cdr.h +++ b/include/asterisk/cdr.h @@ -217,19 +217,19 @@ /*! \brief CDR engine settings */ enum ast_cdr_settings { - CDR_ENABLED = 1 << 0, /*< Enable CDRs */ - CDR_BATCHMODE = 1 << 1, /*< Whether or not we should dispatch CDRs in batches */ - CDR_UNANSWERED = 1 << 2, /*< Log unanswered CDRs */ - CDR_CONGESTION = 1 << 3, /*< Treat congestion as if it were a failed call */ - CDR_END_BEFORE_H_EXTEN = 1 << 4, /*< End the CDR before the 'h' extension runs */ - CDR_INITIATED_SECONDS = 1 << 5, /*< Include microseconds into the billing time */ - CDR_DEBUG = 1 << 6, /*< Enables extra debug statements */ + CDR_ENABLED = 1 << 0, /*!< Enable CDRs */ + CDR_BATCHMODE = 1 << 1, /*!< Whether or not we should dispatch CDRs in batches */ + CDR_UNANSWERED = 1 << 2, /*!< Log unanswered CDRs */ + CDR_CONGESTION = 1 << 3, /*!< Treat congestion as if it were a failed call */ + CDR_END_BEFORE_H_EXTEN = 1 << 4, /*!< End the CDR before the 'h' extension runs */ + CDR_INITIATED_SECONDS = 1 << 5, /*!< Include microseconds into the billing time */ + CDR_DEBUG = 1 << 6, /*!< Enables extra debug statements */ }; /*! \brief CDR Batch Mode settings */ enum ast_cdr_batch_mode_settings { - BATCH_MODE_SCHEDULER_ONLY = 1 << 0, /*< Don't spawn a thread to handle the batches - do it on the scheduler */ - BATCH_MODE_SAFE_SHUTDOWN = 1 << 1, /*< During safe shutdown, submit the batched CDRs */ + BATCH_MODE_SCHEDULER_ONLY = 1 << 0, /*!< Don't spawn a thread to handle the batches - do it on the scheduler */ + BATCH_MODE_SAFE_SHUTDOWN = 1 << 1, /*!< During safe shutdown, submit the batched CDRs */ }; /*! @@ -237,14 +237,14 @@ enum ast_cdr_batch_mode_settings { * state of a CDR object based on these flags. */ enum ast_cdr_options { - AST_CDR_FLAG_KEEP_VARS = (1 << 0), /*< Copy variables during the operation */ - AST_CDR_FLAG_DISABLE = (1 << 1), /*< Disable the current CDR */ - AST_CDR_FLAG_DISABLE_ALL = (3 << 1), /*< Disable the CDR and all future CDRs */ - AST_CDR_FLAG_PARTY_A = (1 << 3), /*< Set the channel as party A */ - AST_CDR_FLAG_FINALIZE = (1 << 4), /*< Finalize the current CDRs */ - AST_CDR_FLAG_SET_ANSWER = (1 << 5), /*< If the channel is answered, set the answer time to now */ - AST_CDR_FLAG_RESET = (1 << 6), /*< If set, set the start and answer time to now */ - AST_CDR_LOCK_APP = (1 << 7), /*< Prevent any further changes to the application field/data field for this CDR */ + AST_CDR_FLAG_KEEP_VARS = (1 << 0), /*!< Copy variables during the operation */ + AST_CDR_FLAG_DISABLE = (1 << 1), /*!< Disable the current CDR */ + AST_CDR_FLAG_DISABLE_ALL = (3 << 1), /*!< Disable the CDR and all future CDRs */ + AST_CDR_FLAG_PARTY_A = (1 << 3), /*!< Set the channel as party A */ + AST_CDR_FLAG_FINALIZE = (1 << 4), /*!< Finalize the current CDRs */ + AST_CDR_FLAG_SET_ANSWER = (1 << 5), /*!< If the channel is answered, set the answer time to now */ + AST_CDR_FLAG_RESET = (1 << 6), /*!< If set, set the start and answer time to now */ + AST_CDR_LOCK_APP = (1 << 7), /*!< Prevent any further changes to the application field/data field for this CDR */ }; /*! @@ -262,11 +262,11 @@ enum ast_cdr_disposition { /*! \brief The global options available for CDRs */ struct ast_cdr_config { - struct ast_flags settings; /*< CDR settings */ + struct ast_flags settings; /*!< CDR settings */ struct batch_settings { - unsigned int time; /*< Time between batches */ - unsigned int size; /*< Size to trigger a batch */ - struct ast_flags settings; /*< Settings for batches */ + unsigned int time; /*!< Time between batches */ + unsigned int size; /*!< Size to trigger a batch */ + struct ast_flags settings; /*!< Settings for batches */ } batch_settings; }; @@ -312,7 +312,7 @@ struct ast_cdr { unsigned int flags; /*! Unique Channel Identifier */ char uniqueid[AST_MAX_UNIQUEID]; - /* Linked group Identifier */ + /*! Linked group Identifier */ char linkedid[AST_MAX_UNIQUEID]; /*! User field */ char userfield[AST_MAX_USER_FIELD]; diff --git a/main/cdr.c b/main/cdr.c index 1817e80a7b4..9b042681220 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -220,7 +220,7 @@ static int cdr_toggle_runtime_options(void); /*! \brief The configuration settings for this module */ struct module_config { - struct ast_cdr_config *general; /*< CDR global settings */ + struct ast_cdr_config *general; /*!< CDR global settings */ }; /*! \brief The container for the module configuration */ @@ -1458,7 +1458,8 @@ static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked /* SINGLE STATE */ -static void single_state_init_function(struct cdr_object *cdr) { +static void single_state_init_function(struct cdr_object *cdr) +{ cdr->start = ast_tvnow(); cdr_object_check_party_a_answer(cdr); } @@ -2023,6 +2024,7 @@ static int cdr_object_finalize_party_b(void *obj, void *arg, int flags) struct cdr_object *cdr = obj; struct ast_channel_snapshot *party_b = arg; struct cdr_object *it_cdr; + for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { if (it_cdr->party_b.snapshot && !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) { @@ -2040,6 +2042,7 @@ static int cdr_object_update_party_b(void *obj, void *arg, int flags) struct cdr_object *cdr = obj; struct ast_channel_snapshot *party_b = arg; struct cdr_object *it_cdr; + for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { if (!it_cdr->fn_table->process_party_b) { continue; @@ -2912,7 +2915,7 @@ void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char } } -/* +/*! * \internal * \brief Callback that finds all CDRs that reference a particular channel by name */ @@ -2928,7 +2931,7 @@ static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags) return 0; } -/* +/*! * \internal * \brief Callback that finds a CDR by channel name */ @@ -3165,8 +3168,9 @@ int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, ao2_lock(cdr); for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (++x > 1) + if (++x > 1) { ast_str_append(buf, 0, "\n"); + } AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) { if (!(var = ast_var_name(variable))) { @@ -3249,6 +3253,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flag struct cdr_object *cdr = obj; struct party_b_userfield_update *info = arg; struct cdr_object *it_cdr; + for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) { continue; @@ -3830,6 +3835,7 @@ static void cli_show_channel(struct ast_cli_args *a) ao2_lock(cdr); for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { struct timeval end; + if (snapshot_is_dialed(it_cdr->party_a.snapshot)) { continue; } @@ -4320,5 +4326,3 @@ int ast_cdr_engine_reload(void) return cdr_toggle_runtime_options(); } - - From 62980eedc3c11d97ae511be1ca728235a8d5a1d0 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 29 Sep 2017 12:07:14 -0500 Subject: [PATCH 1535/1578] cdr.c: Use current ao2 flag names Change-Id: Ib59d7d2f2a4a822754628f2c48a308d6791a6e6e --- main/cdr.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 1817e80a7b4..e06c1e86e2d 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -785,11 +785,11 @@ static int cdr_object_channel_hash_fn(const void *obj, const int flags) const struct cdr_object *cdr; const char *key; - switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) { - case OBJ_KEY: + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: key = obj; break; - case OBJ_POINTER: + case OBJ_SEARCH_OBJECT: cdr = obj; key = cdr->uniqueid; break; @@ -810,14 +810,14 @@ static int cdr_object_channel_cmp_fn(void *obj, void *arg, int flags) const char *right_key = arg; int cmp; - switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) { - case OBJ_POINTER: + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: right_key = right->uniqueid; /* Fall through */ - case OBJ_KEY: + case OBJ_SEARCH_KEY: cmp = strcmp(left->uniqueid, right_key); break; - case OBJ_PARTIAL_KEY: + case OBJ_SEARCH_PARTIAL_KEY: /* * We could also use a partial key struct containing a length * so strlen() does not get called for every comparison instead. @@ -1572,7 +1572,7 @@ static enum process_bridge_enter_results single_state_process_bridge_enter(struc !success && (channel_id = ao2_iterator_next(&it_cdrs)); ao2_ref(channel_id, -1)) { RAII_VAR(struct cdr_object *, cand_cdr_master, - ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY), + ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY), ao2_cleanup); struct cdr_object *cand_cdr; @@ -1722,7 +1722,7 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct !success && (channel_id = ao2_iterator_next(&it_cdrs)); ao2_ref(channel_id, -1)) { RAII_VAR(struct cdr_object *, cand_cdr_master, - ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY), + ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY), ao2_cleanup); struct cdr_object *cand_cdr; @@ -1963,9 +1963,9 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str /* Figure out who is running this show */ if (caller) { - cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_KEY); + cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_SEARCH_KEY); } else { - cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_KEY); + cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_SEARCH_KEY); } if (!cdr) { @@ -2119,7 +2119,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription /* Handle Party A */ if (!cdr) { - cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_KEY); + cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_SEARCH_KEY); } if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name); @@ -2225,7 +2225,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); RAII_VAR(struct cdr_object *, cdr, - ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY), + ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY), ao2_cleanup); struct cdr_object *it_cdr; struct bridge_leave_data leave_data = { @@ -2382,7 +2382,7 @@ static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_sna it_channels = ao2_iterator_init(bridge->channels, 0); while ((channel_id = ao2_iterator_next(&it_channels))) { RAII_VAR(struct cdr_object *, cand_cdr, - ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY), + ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY), ao2_cleanup); if (!cand_cdr) { @@ -2528,7 +2528,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription * struct ast_bridge_snapshot *bridge = update->bridge; struct ast_channel_snapshot *channel = update->channel; RAII_VAR(struct cdr_object *, cdr, - ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY), + ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY), ao2_cleanup); RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); @@ -2596,7 +2596,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s (unsigned int)stasis_message_timestamp(message)->tv_sec, (unsigned int)stasis_message_timestamp(message)->tv_usec); - cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY); + cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name); ast_assert(0); @@ -4246,8 +4246,8 @@ int ast_cdr_engine_init(void) stasis_message_router_add(stasis_router, ast_parked_call_type(), handle_parked_call_message, NULL); stasis_message_router_add(stasis_router, cdr_sync_message_type(), handle_cdr_sync_message, NULL); - active_cdrs_by_channel = ao2_container_alloc(NUM_CDR_BUCKETS, - cdr_object_channel_hash_fn, cdr_object_channel_cmp_fn); + active_cdrs_by_channel = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, + NUM_CDR_BUCKETS, cdr_object_channel_hash_fn, NULL, cdr_object_channel_cmp_fn); if (!active_cdrs_by_channel) { return -1; } From 2e4b5fadbd919589ad44fdb1782b8db4ebb7e145 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 2 Oct 2017 17:41:12 -0500 Subject: [PATCH 1536/1578] cdr.c: Replace inlined code with ao2_t_replace() Change-Id: I9f424f5282ca7d833592f958d95f1b2bafb549b0 --- main/cdr.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 1817e80a7b4..1a3ff87b365 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -751,11 +751,7 @@ static void free_variables(struct varshead *headp) */ static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src) { - if (dst->snapshot) { - ao2_t_ref(dst->snapshot, -1, "release old snapshot during copy"); - } - dst->snapshot = src->snapshot; - ao2_t_ref(dst->snapshot, +1, "bump new snapshot during copy"); + ao2_t_replace(dst->snapshot, src->snapshot, "CDR snapshot copy"); strcpy(dst->userfield, src->userfield); dst->flags = src->flags; copy_variables(&dst->variables, &src->variables); @@ -1358,11 +1354,7 @@ static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot) { cdr_object_update_cid(old_snapshot, new_snapshot); - if (old_snapshot->snapshot) { - ao2_t_ref(old_snapshot->snapshot, -1, "Drop ref for swap"); - } - ao2_t_ref(new_snapshot, +1, "Bump ref for swap"); - old_snapshot->snapshot = new_snapshot; + ao2_t_replace(old_snapshot->snapshot, new_snapshot, "Swap CDR shapshot"); } /* BASE METHOD IMPLEMENTATIONS */ From fdf9aacca3bc4fc2c04fab3f5bd6eb3c81cdb3c6 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 3 Oct 2017 16:09:58 -0500 Subject: [PATCH 1537/1578] cdr.c: Replace redundant check with an ast_assert() The only caller of cdr_object_fn_table.process_party_b() explicitly does the check before calling. Change-Id: Ib0c53cdf5048227842846e0df9d2c19117c45618 --- main/cdr.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 1817e80a7b4..0703f9ecc24 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1623,11 +1623,9 @@ static int single_state_process_parking_bridge_enter(struct cdr_object *cdr, str static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot) { ast_assert(snapshot != NULL); + ast_assert(cdr->party_b.snapshot + && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name)); - if (!cdr->party_b.snapshot - || strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) { - return; - } cdr_object_swap_snapshot(&cdr->party_b, snapshot); /* If party B hangs up, finalize this CDR */ @@ -1823,10 +1821,9 @@ static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struc static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot) { - if (!cdr->party_b.snapshot - || strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) { - return; - } + ast_assert(cdr->party_b.snapshot + && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name)); + cdr_object_swap_snapshot(&cdr->party_b, snapshot); /* If party B hangs up, finalize this CDR */ From fae09c6676a2e68163c08d7b3ef27a0daabaf4a7 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 9 Oct 2017 23:51:03 -0400 Subject: [PATCH 1538/1578] res_pjproject: Fix cleanup of buildopts vector. ASTERISK-27306 Change-Id: I3bed0edf3f55b1d4adcbabb25ec14f11dc766c72 --- res/res_pjproject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 1d9d73eaab6..46c82aa9e68 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -544,7 +544,7 @@ static int unload_module(void) pj_log_set_log_func(log_cb_orig); pj_log_set_decor(decor_orig); - AST_VECTOR_REMOVE_CMP_UNORDERED(&buildopts, NULL, NOT_EQUALS, ast_free); + AST_VECTOR_CALLBACK_VOID(&buildopts, ast_free); AST_VECTOR_FREE(&buildopts); ast_debug(3, "Stopped PJPROJECT logging to Asterisk logger\n"); From b228f5c5e63361e675687d3fab1133f250955dcc Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 10 Oct 2017 15:42:46 +0300 Subject: [PATCH 1539/1578] declare optional openssl dependencies in moduleinfo Declare optional openssl dependencies in: * res_rtp_asterisk.c * tcptls.c ASTERISK-27328 #close Change-Id: I2636f1c05b8104b4fe6f36cce0ebd9a98b9c78ab --- main/tcptls.c | 1 + res/res_rtp_asterisk.c | 1 + 2 files changed, 2 insertions(+) diff --git a/main/tcptls.c b/main/tcptls.c index ebe86f3e005..2e8d84b3066 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -26,6 +26,7 @@ */ /*** MODULEINFO + openssl core ***/ diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 7bf5b00642a..f5d91345832 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -29,6 +29,7 @@ */ /*** MODULEINFO + openssl pjproject core ***/ From 11cefdf6215e665f82408ffbf596da7e9845be57 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Tue, 10 Oct 2017 17:49:15 +0300 Subject: [PATCH 1540/1578] cdr_mysql: avoid releasing a config string Fixes a memory corruption issue after a reload of cdr_mysql. Issue was accidentally included in 747beb1ed159f89a3b58742e4257740b3d6d6bba . ASTERISK-27270 #close Change-Id: I90b6a9d18710c0f9009466370bd5f4bac5d5d12e --- addons/cdr_mysql.c | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c index 1c116636fb1..1f973625191 100644 --- a/addons/cdr_mysql.c +++ b/addons/cdr_mysql.c @@ -510,7 +510,6 @@ static int my_load_module(int reload) } else { calldate_compat = 0; } - ast_free(compat); if (res < 0) { if (reload) { From b0408d05c0c02c83e44302bb8ca65ebad6010d25 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 2 Oct 2017 16:46:19 -0500 Subject: [PATCH 1541/1578] cdr.c: Eliminated simple RAII_VAR usages. Change-Id: I150505db307249a962987e7b941bdd369bb91f35 --- main/cdr.c | 127 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 54 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index b94bbcfea52..1ea244545c6 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1564,11 +1564,10 @@ static enum process_bridge_enter_results single_state_process_bridge_enter(struc for (it_cdrs = ao2_iterator_init(bridge->channels, 0); !success && (channel_id = ao2_iterator_next(&it_cdrs)); ao2_ref(channel_id, -1)) { - RAII_VAR(struct cdr_object *, cand_cdr_master, - ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY), - ao2_cleanup); + struct cdr_object *cand_cdr_master; struct cdr_object *cand_cdr; + cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); if (!cand_cdr_master) { continue; } @@ -1590,6 +1589,7 @@ static enum process_bridge_enter_results single_state_process_bridge_enter(struc break; } ao2_unlock(cand_cdr_master); + ao2_cleanup(cand_cdr_master); } ao2_iterator_destroy(&it_cdrs); @@ -1712,11 +1712,10 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct for (it_cdrs = ao2_iterator_init(bridge->channels, 0); !success && (channel_id = ao2_iterator_next(&it_cdrs)); ao2_ref(channel_id, -1)) { - RAII_VAR(struct cdr_object *, cand_cdr_master, - ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY), - ao2_cleanup); + struct cdr_object *cand_cdr_master; struct cdr_object *cand_cdr; + cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); if (!cand_cdr_master) { continue; } @@ -1751,6 +1750,7 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct break; } ao2_unlock(cand_cdr_master); + ao2_cleanup(cand_cdr_master); } ao2_iterator_destroy(&it_cdrs); @@ -1921,7 +1921,7 @@ static int dial_status_end(const char *dialstatus) static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message) { RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup); + struct cdr_object *cdr; struct ast_multi_channel_blob *payload = stasis_message_data(message); struct ast_channel_snapshot *caller; struct ast_channel_snapshot *peer; @@ -1957,7 +1957,6 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str } else { cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_SEARCH_KEY); } - if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name); ast_assert(0); @@ -1997,15 +1996,12 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str struct cdr_object *new_cdr; new_cdr = cdr_object_create_and_append(cdr); - if (!new_cdr) { - ao2_unlock(cdr); - return; + if (new_cdr) { + new_cdr->fn_table->process_dial_begin(new_cdr, caller, peer); } - new_cdr->fn_table->process_dial_begin(new_cdr, - caller, - peer); } ao2_unlock(cdr); + ao2_cleanup(cdr); } static int cdr_object_finalize_party_b(void *obj, void *arg, int flags) @@ -2079,7 +2075,7 @@ static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot, */ static void handle_channel_cache_message(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup); + struct cdr_object *cdr; RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); struct stasis_cache_update *update = stasis_message_data(message); struct ast_channel_snapshot *old_snapshot; @@ -2107,12 +2103,11 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription } cdr->is_root = 1; ao2_link(active_cdrs_by_channel, cdr); + } else { + cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_SEARCH_KEY); } /* Handle Party A */ - if (!cdr) { - cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_SEARCH_KEY); - } if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name); ast_assert(0); @@ -2120,6 +2115,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription ao2_lock(cdr); if (new_snapshot) { int all_reject = 1; + for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { if (!it_cdr->fn_table->process_party_a) { continue; @@ -2129,6 +2125,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) { /* We're not hung up and we have a new snapshot - we need a new CDR */ struct cdr_object *new_cdr; + new_cdr = cdr_object_create_and_append(cdr); if (new_cdr) { new_cdr->fn_table->process_party_a(new_cdr, new_snapshot); @@ -2154,6 +2151,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription old_snapshot); } + ao2_cleanup(cdr); } struct bridge_leave_data { @@ -2216,9 +2214,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * struct ast_channel_snapshot *channel = update->channel; RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - RAII_VAR(struct cdr_object *, cdr, - ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY), - ao2_cleanup); + struct cdr_object *cdr; struct cdr_object *it_cdr; struct bridge_leave_data leave_data = { .bridge = bridge, @@ -2239,6 +2235,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * (unsigned int)stasis_message_timestamp(message)->tv_sec, (unsigned int)stasis_message_timestamp(message)->tv_usec); + cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name); ast_assert(0); @@ -2259,16 +2256,16 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * } } ao2_unlock(cdr); - if (!left_bridge) { - return; - } - if (strcmp(bridge->subclass, "parking")) { - /* Party B */ + /* Party B */ + if (left_bridge + && strcmp(bridge->subclass, "parking")) { ao2_callback(active_cdrs_by_channel, OBJ_NODATA, - cdr_object_party_b_left_bridge_cb, - &leave_data); + cdr_object_party_b_left_bridge_cb, + &leave_data); } + + ao2_cleanup(cdr); } /*! @@ -2373,17 +2370,14 @@ static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_sna it_channels = ao2_iterator_init(bridge->channels, 0); while ((channel_id = ao2_iterator_next(&it_channels))) { - RAII_VAR(struct cdr_object *, cand_cdr, - ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY), - ao2_cleanup); + struct cdr_object *cand_cdr; - if (!cand_cdr) { - ao2_ref(channel_id, -1); - continue; + cand_cdr = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); + if (cand_cdr) { + bridge_candidate_process(cdr, cand_cdr); + ao2_ref(cand_cdr, -1); } - bridge_candidate_process(cdr, cand_cdr); - ao2_ref(channel_id, -1); } ao2_iterator_destroy(&it_channels); @@ -2519,9 +2513,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription * struct ast_bridge_blob *update = stasis_message_data(message); struct ast_bridge_snapshot *bridge = update->bridge; struct ast_channel_snapshot *channel = update->channel; - RAII_VAR(struct cdr_object *, cdr, - ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY), - ao2_cleanup); + struct cdr_object *cdr; RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); @@ -2538,6 +2530,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription * (unsigned int)stasis_message_timestamp(message)->tv_sec, (unsigned int)stasis_message_timestamp(message)->tv_usec); + cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name); ast_assert(0); @@ -2549,6 +2542,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription * } else { handle_standard_bridge_enter_message(cdr, bridge, channel); } + ao2_cleanup(cdr); } /*! @@ -2563,7 +2557,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s { struct ast_parked_call_payload *payload = stasis_message_data(message); struct ast_channel_snapshot *channel = payload->parkee; - RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup); + struct cdr_object *cdr; RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); int unhandled = 1; @@ -2605,7 +2599,9 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s if (unhandled) { /* Nothing handled the messgae - we need a new one! */ - struct cdr_object *new_cdr = cdr_object_create_and_append(cdr); + struct cdr_object *new_cdr; + + new_cdr = cdr_object_create_and_append(cdr); if (new_cdr) { /* As the new CDR is created in the single state, it is guaranteed * to have a function for the parked call message and will handle @@ -2616,6 +2612,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s ao2_unlock(cdr); + ao2_cleanup(cdr); } /*! @@ -3108,15 +3105,16 @@ static struct cdr_object *cdr_object_get_by_name(const char *name) int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length) { - RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup); + struct cdr_object *cdr; struct cdr_object *cdr_obj; - if (!cdr) { - ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name); + if (ast_strlen_zero(name)) { return 1; } - if (ast_strlen_zero(name)) { + cdr = cdr_object_get_by_name(channel_name); + if (!cdr) { + ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name); return 1; } @@ -3130,18 +3128,20 @@ int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size ao2_unlock(cdr); + ao2_cleanup(cdr); return 0; } int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep) { - RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup); + struct cdr_object *cdr; struct cdr_object *it_cdr; struct ast_var_t *variable; const char *var; char workspace[256]; int total = 0, x = 0, i; + cdr = cdr_object_get_by_name(channel_name); if (!cdr) { RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); @@ -3190,6 +3190,7 @@ int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, } } ao2_unlock(cdr); + ao2_cleanup(cdr); return total; } @@ -3257,7 +3258,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flag void ast_cdr_setuserfield(const char *channel_name, const char *userfield) { - RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup); + struct cdr_object *cdr; struct party_b_userfield_update party_b_info = { .channel_name = channel_name, .userfield = userfield, @@ -3265,6 +3266,7 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) struct cdr_object *it_cdr; /* Handle Party A */ + cdr = cdr_object_get_by_name(channel_name); if (cdr) { ao2_lock(cdr); for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { @@ -3281,6 +3283,7 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) cdr_object_update_party_b_userfield_cb, &party_b_info); + ao2_cleanup(cdr); } static void post_cdr(struct ast_cdr *cdr) @@ -3319,9 +3322,10 @@ static void post_cdr(struct ast_cdr *cdr) int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option) { - RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup); + struct cdr_object *cdr; struct cdr_object *it_cdr; + cdr = cdr_object_get_by_name(channel_name); if (!cdr) { return -1; } @@ -3339,14 +3343,16 @@ int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option) } ao2_unlock(cdr); + ao2_cleanup(cdr); return 0; } int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option) { - RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup); + struct cdr_object *cdr; struct cdr_object *it_cdr; + cdr = cdr_object_get_by_name(channel_name); if (!cdr) { return -1; } @@ -3360,15 +3366,17 @@ int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option } ao2_unlock(cdr); + ao2_cleanup(cdr); return 0; } int ast_cdr_reset(const char *channel_name, int keep_variables) { - RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup); + struct cdr_object *cdr; struct ast_var_t *vardata; struct cdr_object *it_cdr; + cdr = cdr_object_get_by_name(channel_name); if (!cdr) { return -1; } @@ -3396,6 +3404,7 @@ int ast_cdr_reset(const char *channel_name, int keep_variables) } ao2_unlock(cdr); + ao2_cleanup(cdr); return 0; } @@ -3805,7 +3814,7 @@ static void cli_show_channel(struct ast_cli_args *a) char answer_time_buffer[64]; char end_time_buffer[64]; const char *channel_name = a->argv[3]; - RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup); + struct cdr_object *cdr; #define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n" #define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n" @@ -3850,6 +3859,9 @@ static void cli_show_channel(struct ast_cli_args *a) (long)ast_tvdiff_ms(end, it_cdr->start) / 1000); } ao2_unlock(cdr); + + ao2_cleanup(cdr); + #undef FORMAT_STRING #undef TITLE_STRING } @@ -4264,8 +4276,6 @@ int ast_cdr_engine_init(void) void ast_cdr_engine_term(void) { RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - RAII_VAR(void *, payload, NULL, ao2_cleanup); - RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); /* Since this is called explicitly during process shutdown, we might not have ever * been initialized. If so, the config object will be NULL. @@ -4275,9 +4285,16 @@ void ast_cdr_engine_term(void) } if (cdr_sync_message_type()) { + void *payload; + struct stasis_message *message; + + if (!stasis_router) { + return; + } + /* Make sure we have the needed items */ payload = ao2_alloc(sizeof(*payload), NULL); - if (!stasis_router || !payload) { + if (!payload) { return; } @@ -4287,6 +4304,8 @@ void ast_cdr_engine_term(void) if (message) { stasis_message_router_publish_sync(stasis_router, message); } + ao2_cleanup(message); + ao2_cleanup(payload); } if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) { From b1d9fc87bc8a874230fd961779cd874ef7e987a0 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Tue, 3 Oct 2017 22:16:49 +0200 Subject: [PATCH 1542/1578] contrib/thirdparty/sip_to_pjsip: add additional flag mappings add mappings for udptl redundancy, rtptimeout, and debug flags Change-Id: Ie73cf5c83c05dee01eb9624ede76c1a30225d73a --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index 98a5e9546a0..eb3aab3b857 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -116,6 +116,27 @@ def set_dtmfmode(key, val, section, pjsip, nmapped): set_value(key, 'none', section, pjsip, nmapped) +def setup_udptl(section, pjsip, nmapped): + """Sets values from udptl into the appropriate pjsip.conf options.""" + try: + val = sip.get(section, 't38pt_udptl')[0] + except LookupError: + try: + val = sip.get('general', 't38pt_udptl')[0] + except LookupError: + return + + ec = 'none' + if 'yes' in val: + set_value('t38_udptl', 'yes', section, pjsip, nmapped) + if 'no' in val: + set_value('t38_udptl', 'no', section, pjsip, nmapped) + if 'redundancy' in val: + ec = 'redundancy' + if 'fec' in val: + ec = 'fec' + set_value('t38_udptl_ec', ec, section, pjsip, nmapped) + def from_nat(key, val, section, pjsip, nmapped): """Sets values from nat into the appropriate pjsip.conf options.""" # nat from sip.conf can be comma separated list of values: @@ -387,6 +408,7 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ['allow', merge_value], ['nat', from_nat], # rtp_symmetric, force_rport, # rewrite_contact + ['rtptimeout', set_value('rtp_timeout')], ['icesupport', set_value('ice_support')], ['autoframing', set_value('use_ptime')], ['outboundproxy', set_value('outbound_proxy')], @@ -1068,6 +1090,7 @@ def map_peer(sip, section, pjsip, nmapped): except LookupError: pass # key not found in sip.conf + setup_udptl(section, pjsip, nmapped) def find_non_mapped(sections, nmapped): """ @@ -1101,6 +1124,13 @@ def map_system(sip, pjsip, nmapped): except LookupError: pass + + try: + sipdebug = sip.get('general', 'sipdebug')[0] + set_value('debug', sipdebug, 'global', pjsip, nmapped, 'global') + except LookupError: + pass + try: useroption_parsing = sip.get('general', 'legacy_useroption_parsing')[0] set_value('ignore_uri_user_options', useroption_parsing, 'global', pjsip, nmapped, 'global') From 3ad7d2f36ca155e6ee823a48175e5951829e1a20 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Tue, 10 Oct 2017 13:01:05 -0400 Subject: [PATCH 1543/1578] app_originate: Set ORIGINATE_STATUS correctly on failure We were ignoring the return value from ast_pbx_outgoing_exten() and ast_pbx_outgoing_app() which could fail before setting the reason code. This resulted in failures being reported as success. ASTERISK-25266 #close Reported by: Allen Ford Change-Id: Idf16237b7e41b527d2c69c865829128686beeb3b --- apps/app_originate.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/apps/app_originate.c b/apps/app_originate.c index 8edccc720fa..30fa565bea8 100644 --- a/apps/app_originate.c +++ b/apps/app_originate.c @@ -155,6 +155,7 @@ static int originate_exec(struct ast_channel *chan, const char *data) char *parse; char *chantech, *chandata; int res = -1; + int continue_in_dialplan = 0; int outgoing_status = 0; unsigned int timeout = 30; static const char default_exten[] = "s"; @@ -223,6 +224,12 @@ static int originate_exec(struct ast_channel *chan, const char *data) predial_callee = opt_args[OPT_ARG_PREDIAL_CALLEE]; } + if (strcasecmp(args.type, "exten") && strcasecmp(args.type, "app")) { + ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n", + args.type); + goto return_cleanup; + } + if (!strcasecmp(args.type, "exten")) { int priority = 1; /* Initialized in case priority not specified */ const char *exten = args.arg2; @@ -241,25 +248,32 @@ static int originate_exec(struct ast_channel *chan, const char *data) ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n", chantech, chandata, args.arg1, exten, priority); - ast_pbx_outgoing_exten_predial(chantech, cap_slin, chandata, + res = ast_pbx_outgoing_exten_predial(chantech, cap_slin, chandata, timeout * 1000, args.arg1, exten, priority, &outgoing_status, AST_OUTGOING_WAIT, NULL, NULL, NULL, NULL, NULL, 0, NULL, predial_callee); - } else if (!strcasecmp(args.type, "app")) { + } else { ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n", chantech, chandata, args.arg1, S_OR(args.arg2, "")); - ast_pbx_outgoing_app_predial(chantech, cap_slin, chandata, + res = ast_pbx_outgoing_app_predial(chantech, cap_slin, chandata, timeout * 1000, args.arg1, args.arg2, &outgoing_status, AST_OUTGOING_WAIT, NULL, NULL, NULL, NULL, NULL, NULL, predial_callee); - } else { - ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n", - args.type); - goto return_cleanup; } - res = 0; + /* + * Getting here means that we have passed the various validation checks and + * have at least attempted the dial. If we have a reason (outgoing_status), + * we clear our error indicator so that we ultimately report the right thing + * to the caller. + */ + if (res && outgoing_status) { + res = 0; + } + + /* We need to exit cleanly if we've gotten this far */ + continue_in_dialplan = 1; return_cleanup: if (res) { @@ -292,7 +306,7 @@ static int originate_exec(struct ast_channel *chan, const char *data) ao2_cleanup(cap_slin); ast_autoservice_stop(chan); - return res; + return continue_in_dialplan ? 0 : -1; } static int unload_module(void) From fd3101e8ad320848e966d09f8b64f51628855257 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Tue, 10 Oct 2017 16:09:14 -0400 Subject: [PATCH 1544/1578] astobj2: Run weakproxy callbacks outside of lock. Copy the list of weakproxy callbacks to temporary memory so they can be run without holding the weakproxy lock. Change-Id: Ib167622a8a0f873fd73938f7611b2a5914308047 --- include/asterisk/astobj2.h | 4 ++++ main/astobj2.c | 41 ++++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index 484e1e35caa..9b5ec123bcd 100644 --- a/include/asterisk/astobj2.h +++ b/include/asterisk/astobj2.h @@ -671,6 +671,10 @@ int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, v * of the cb / data pair. If it was subscribed multiple times it must be * unsubscribed as many times. The OBJ_MULTIPLE flag can be used to remove * matching subscriptions. + * + * \note When it's time to run callbacks they are copied to a temporary list so the + * weakproxy can be unlocked before running. That means it's possible for + * this function to find nothing before the callback is run in another thread. */ int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags); diff --git a/main/astobj2.c b/main/astobj2.c index d534900ddfe..da2d44e514a 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -82,8 +82,6 @@ struct ao2_weakproxy_notification { AST_LIST_ENTRY(ao2_weakproxy_notification) list; }; -static void weakproxy_run_callbacks(struct ao2_weakproxy *weakproxy); - struct ao2_lock_priv { ast_mutex_t lock; }; @@ -469,7 +467,7 @@ int __ao2_ref(void *user_data, int delta, struct astobj2_lockobj *obj_lockobj; int current_value; int ret; - void *weakproxy = NULL; + struct ao2_weakproxy *weakproxy = NULL; if (obj == NULL) { if (ref_log && user_data) { @@ -498,6 +496,8 @@ int __ao2_ref(void *user_data, int delta, #endif if (weakproxy) { + struct ao2_weakproxy cbs; + if (current_value == 1) { /* The only remaining reference is the one owned by the weak object */ struct astobj2 *internal_weakproxy; @@ -508,8 +508,9 @@ int __ao2_ref(void *user_data, int delta, internal_weakproxy->priv_data.weakptr = NULL; obj->priv_data.weakptr = NULL; - /* Notify the subscribers that weakproxy now points to NULL. */ - weakproxy_run_callbacks(weakproxy); + /* transfer list to local copy so callbacks are run with weakproxy unlocked. */ + cbs.destroyed_cb = weakproxy->destroyed_cb; + AST_LIST_HEAD_INIT_NOLOCK(&weakproxy->destroyed_cb); /* weak is already unlinked from obj so this won't recurse */ ao2_ref(user_data, -1); @@ -518,6 +519,14 @@ int __ao2_ref(void *user_data, int delta, ao2_unlock(weakproxy); if (current_value == 1) { + struct ao2_weakproxy_notification *destroyed_cb; + + /* Notify the subscribers that weakproxy now points to NULL. */ + while ((destroyed_cb = AST_LIST_REMOVE_HEAD(&cbs.destroyed_cb, list))) { + destroyed_cb->cb(weakproxy, destroyed_cb->data); + ast_free(destroyed_cb); + } + ao2_ref(weakproxy, -1); } } @@ -796,16 +805,6 @@ void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const } -static void weakproxy_run_callbacks(struct ao2_weakproxy *weakproxy) -{ - struct ao2_weakproxy_notification *destroyed_cb; - - while ((destroyed_cb = AST_LIST_REMOVE_HEAD(&weakproxy->destroyed_cb, list))) { - destroyed_cb->cb(weakproxy, destroyed_cb->data); - ast_free(destroyed_cb); - } -} - void *__ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *tag, const char *file, int line, const char *func) { @@ -951,6 +950,7 @@ int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, v { struct astobj2 *weakproxy_internal = INTERNAL_OBJ_CHECK(weakproxy); int ret = -1; + int hasobj; if (!weakproxy_internal || weakproxy_internal->priv_data.magic != AO2_WEAK) { return -1; @@ -960,7 +960,8 @@ int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, v ao2_lock(weakproxy); } - if (weakproxy_internal->priv_data.weakptr) { + hasobj = weakproxy_internal->priv_data.weakptr != NULL; + if (hasobj) { struct ao2_weakproxy *weak = weakproxy; struct ao2_weakproxy_notification *sub = ast_calloc(1, sizeof(*sub)); @@ -970,15 +971,17 @@ int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, v AST_LIST_INSERT_HEAD(&weak->destroyed_cb, sub, list); ret = 0; } - } else { - cb(weakproxy, data); - ret = 0; } if (!(flags & OBJ_NOLOCK)) { ao2_unlock(weakproxy); } + if (!hasobj) { + cb(weakproxy, data); + ret = 0; + } + return ret; } From b058f8673aa9d82504bd357dd49f8ec1ba61a47e Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 9 Oct 2017 18:51:05 -0400 Subject: [PATCH 1545/1578] astobj2: Add ao2_weakproxy_find function. This function finds a weak proxy in an ao2_container and returns the real object associated with it. Change-Id: I9da822049747275f5961b5c0a7f14e87157d65d8 --- include/asterisk/astobj2.h | 11 ++++++++++ main/astobj2_container.c | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index 9b5ec123bcd..a18f099c09f 100644 --- a/include/asterisk/astobj2.h +++ b/include/asterisk/astobj2.h @@ -1775,6 +1775,17 @@ void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags, void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags, const char *tag, const char *file, int line, const char *func); +/*! + * \brief Perform an ao2_find on a container with ao2_weakproxy objects, returning the real object. + * + * \note Only OBJ_SEARCH_* and OBJ_NOLOCK flags are supported by this function. + * \see ao2_callback for description of arguments. + */ +#define ao2_weakproxy_find(c, arg, flags, tag) \ + __ao2_weakproxy_find(c, arg, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__) +void *__ao2_weakproxy_find(struct ao2_container *c, const void *arg, enum search_flags flags, + const char *tag, const char *file, int line, const char *func); + /*! \brief * * diff --git a/main/astobj2_container.c b/main/astobj2_container.c index a978db3d467..c75dff991b8 100644 --- a/main/astobj2_container.c +++ b/main/astobj2_container.c @@ -437,6 +437,48 @@ void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags fla return __ao2_callback(c, flags, c->cmp_fn, arged, tag, file, line, func); } +void *__ao2_weakproxy_find(struct ao2_container *c, const void *arg, enum search_flags flags, + const char *tag, const char *file, int line, const char *func) +{ + void *proxy; + void *obj = NULL; + enum ao2_lock_req orig_lock; + + ast_assert(!!c); + ast_assert(flags & OBJ_SEARCH_MASK); + ast_assert(!(flags & ~(OBJ_SEARCH_MASK | OBJ_NOLOCK))); + + if (flags & OBJ_NOLOCK) { + orig_lock = __adjust_lock(c, AO2_LOCK_REQ_RDLOCK, 1); + } else { + orig_lock = AO2_LOCK_REQ_RDLOCK; + ao2_rdlock(c); + } + + while ((proxy = ao2_find(c, arg, flags | OBJ_NOLOCK))) { + obj = __ao2_weakproxy_get_object(proxy, 0, tag ?: __PRETTY_FUNCTION__, file, line, func); + + if (obj) { + ao2_ref(proxy, -1); + break; + } + + /* Upgrade to a write lock */ + __adjust_lock(c, AO2_LOCK_REQ_WRLOCK, 1); + ao2_unlink_flags(c, proxy, OBJ_NOLOCK); + ao2_ref(proxy, -1); + } + + if (flags & OBJ_NOLOCK) { + /* We'll keep any upgraded lock */ + __adjust_lock(c, orig_lock, 1); + } else { + ao2_unlock(c); + } + + return obj; +} + /*! * initialize an iterator so we start from the first object */ From 77746238043b8ce8f69a5cb5398b538a2f681a8e Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 9 Oct 2017 22:55:44 -0400 Subject: [PATCH 1546/1578] named_locks: Use ao2_weakproxy_find. Change-Id: I0ce8a1b7101b6caac6a19f83a89f00eaba1e9d9c --- main/named_locks.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/main/named_locks.c b/main/named_locks.c index 27772f23be2..b38539c2f2a 100644 --- a/main/named_locks.c +++ b/main/named_locks.c @@ -108,31 +108,21 @@ static void named_lock_proxy_cb(void *weakproxy, void *data) struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func, enum ast_named_lock_type lock_type, const char *keyspace, const char *key) { - struct named_lock_proxy *proxy = NULL; - struct ast_named_lock *lock = NULL; + struct named_lock_proxy *proxy; + struct ast_named_lock *lock; int keylen = strlen(keyspace) + strlen(key) + 2; char *concat_key = ast_alloca(keylen); sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */ ao2_lock(named_locks); - proxy = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); - if (proxy) { + lock = __ao2_weakproxy_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK, + __PRETTY_FUNCTION__, filename, lineno, func); + if (lock) { + ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type); ao2_unlock(named_locks); - lock = __ao2_weakproxy_get_object(proxy, 0, __PRETTY_FUNCTION__, filename, lineno, func); - if (lock) { - /* We have an existing lock and it's not being destroyed. */ - ao2_ref(proxy, -1); - ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type); - - return lock; - } - - /* the old proxy is being destroyed, clean list before creating/adding new one */ - ao2_lock(named_locks); - ao2_unlink_flags(named_locks, proxy, OBJ_NOLOCK); - ao2_ref(proxy, -1); + return lock; } proxy = ao2_t_weakproxy_alloc(sizeof(*proxy) + keylen, NULL, concat_key); From b8dadccbe148c9113565f497da39a5e97d4ac533 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 9 Oct 2017 22:00:45 -0400 Subject: [PATCH 1547/1578] sorcery: Use ao2_weakproxy to hold list of instances. * Store weak proxy objects in instances container. * Remove special unreference function and replace with macro that calls ao2_cleanup. * Add REF_DEBUG information to ast_sorcery_open. Change-Id: I5a150a4e13cee319d46b5a4654f95a4623a978f8 --- include/asterisk/sorcery.h | 11 +++-- main/sorcery.c | 95 +++++++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h index 89663381683..bfb2c39ad34 100644 --- a/include/asterisk/sorcery.h +++ b/include/asterisk/sorcery.h @@ -392,9 +392,9 @@ int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface); * \retval non-NULL success * \retval NULL if allocation failed */ -struct ast_sorcery *__ast_sorcery_open(const char *module); +struct ast_sorcery *__ast_sorcery_open(const char *module, const char *file, int line, const char *func); -#define ast_sorcery_open() __ast_sorcery_open(AST_MODULE) +#define ast_sorcery_open() __ast_sorcery_open(AST_MODULE, __FILE__, __LINE__, __PRETTY_FUNCTION__) /*! * \brief Retrieves an existing sorcery instance by module name @@ -1280,8 +1280,13 @@ int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object); * \brief Decrease the reference count of a sorcery structure * * \param sorcery Pointer to a sorcery structure + * + * \note Prior to 16.0.0 this was a function which had to be used. + * Now you can use any variant of ao2_cleanup or ao2_ref to + * release a reference. */ -void ast_sorcery_unref(struct ast_sorcery *sorcery); +#define ast_sorcery_unref(sorcery) \ + ao2_cleanup(sorcery) /*! * \brief Get the unique identifier of a sorcery object diff --git a/main/sorcery.c b/main/sorcery.c index 0bb2826c818..6694167cd23 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -207,6 +207,13 @@ struct ast_sorcery_object_field { intptr_t args[]; }; +/*! \brief Proxy object for sorcery */ +struct sorcery_proxy { + AO2_WEAKPROXY(); + /*! \brief The name of the module owning this sorcery instance */ + char module_name[0]; +}; + /*! \brief Full structure for sorcery */ struct ast_sorcery { /*! \brief Container for known object types */ @@ -215,8 +222,8 @@ struct ast_sorcery { /*! \brief Observers */ struct ao2_container *observers; - /*! \brief The name of the module owning this sorcery instance */ - char module_name[0]; + /*! \brief Pointer to module_name in the associated sorcery_proxy. */ + char *module_name; }; /*! \brief Structure for passing load/reload details */ @@ -449,8 +456,8 @@ static void sorcery_cleanup(void) /*! \brief Compare function for sorcery instances */ static int sorcery_instance_cmp(void *obj, void *arg, int flags) { - const struct ast_sorcery *object_left = obj; - const struct ast_sorcery *object_right = arg; + const struct sorcery_proxy *object_left = obj; + const struct sorcery_proxy *object_right = arg; const char *right_key = arg; int cmp; @@ -477,7 +484,7 @@ static int sorcery_instance_cmp(void *obj, void *arg, int flags) /*! \brief Hashing function for sorcery instances */ static int sorcery_instance_hash(const void *obj, const int flags) { - const struct ast_sorcery *object; + const struct sorcery_proxy *object; const char *key; switch (flags & OBJ_SEARCH_MASK) { @@ -752,55 +759,83 @@ static int sorcery_type_cmp(void *obj, void *arg, int flags) return CMP_MATCH; } -struct ast_sorcery *__ast_sorcery_open(const char *module_name) +static void sorcery_proxy_cb(void *weakproxy, void *data) { + ao2_unlink(instances, weakproxy); +} + +struct ast_sorcery *__ast_sorcery_open(const char *module_name, const char *file, int line, const char *func) +{ + struct sorcery_proxy *proxy; struct ast_sorcery *sorcery; ast_assert(module_name != NULL); ao2_wrlock(instances); - if ((sorcery = ao2_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) { - goto done; + sorcery = __ao2_weakproxy_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK, + __PRETTY_FUNCTION__, file, line, func); + if (sorcery) { + ao2_unlock(instances); + + return sorcery; } - if (!(sorcery = ao2_alloc(sizeof(*sorcery) + strlen(module_name) + 1, sorcery_destructor))) { - goto done; + proxy = ao2_t_weakproxy_alloc(sizeof(*proxy) + strlen(module_name) + 1, NULL, module_name); + if (!proxy) { + goto failure_cleanup; + } + strcpy(proxy->module_name, module_name); /* Safe */ + + sorcery = __ao2_alloc(sizeof(*sorcery), sorcery_destructor, AO2_ALLOC_OPT_LOCK_MUTEX, module_name, file, line, func); + if (!sorcery) { + goto failure_cleanup; + } + + sorcery->module_name = proxy->module_name; + + /* We have exclusive access to proxy and sorcery, no need for locking here. */ + if (ao2_t_weakproxy_set_object(proxy, sorcery, OBJ_NOLOCK, "weakproxy link")) { + goto failure_cleanup; + } + + if (ao2_weakproxy_subscribe(proxy, sorcery_proxy_cb, NULL, OBJ_NOLOCK)) { + goto failure_cleanup; } if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) { - ao2_ref(sorcery, -1); - sorcery = NULL; - goto done; + goto failure_cleanup; } if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) { - ao2_ref(sorcery, -1); - sorcery = NULL; - goto done; + goto failure_cleanup; } - strcpy(sorcery->module_name, module_name); /* Safe */ - if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) { ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name); - ao2_cleanup(sorcery); - sorcery = NULL; - goto done; + goto failure_cleanup; } - ao2_link_flags(instances, sorcery, OBJ_NOLOCK); + ao2_link_flags(instances, proxy, OBJ_NOLOCK); + ao2_ref(proxy, -1); NOTIFY_GLOBAL_OBSERVERS(observers, instance_created, module_name, sorcery); -done: ao2_unlock(instances); return sorcery; + +failure_cleanup: + /* cleanup of sorcery may result in locking instances, so make sure we unlock first. */ + ao2_unlock(instances); + ao2_cleanup(sorcery); + ao2_cleanup(proxy); + + return NULL; } /*! \brief Search function for sorcery instances */ struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module_name) { - return ao2_find(instances, module_name, OBJ_SEARCH_KEY); + return ao2_weakproxy_find(instances, module_name, OBJ_SEARCH_KEY, ""); } /*! \brief Destructor function for object types */ @@ -2293,18 +2328,6 @@ int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object) return res; } -void ast_sorcery_unref(struct ast_sorcery *sorcery) -{ - if (sorcery) { - /* One ref for what we just released, the other for the instances container. */ - ao2_wrlock(instances); - if (ao2_ref(sorcery, -1) == 2) { - ao2_unlink_flags(instances, sorcery, OBJ_NOLOCK); - } - ao2_unlock(instances); - } -} - const char *ast_sorcery_object_get_id(const void *object) { const struct ast_sorcery_object_details *details = object; From be7da57546afa88a5cca059427f76494d05de9bd Mon Sep 17 00:00:00 2001 From: Nathan Bruning Date: Fri, 6 Oct 2017 09:39:42 +0200 Subject: [PATCH 1548/1578] app_queue.c: clear moh field in init_queue ASTERISK-27301 #close Change-Id: Ic31361f34e2de3b6470e68fc37205a7711082eba --- apps/app_queue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index 0efb2e6831b..e3a4e22a9f0 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2760,6 +2760,7 @@ static void init_queue(struct call_queue *q) } q->found = 1; + ast_string_field_set(q, moh, ""); ast_string_field_set(q, sound_next, "queue-youarenext"); ast_string_field_set(q, sound_thereare, "queue-thereare"); ast_string_field_set(q, sound_calls, "queue-callswaiting"); From ab4d36533cf561015819c26a2dc594efd05e23b1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 11 Oct 2017 06:03:41 -0600 Subject: [PATCH 1549/1578] chan_vpb: Fix a gcc 7 out-of-bounds complaint chan_vpb was trying to use sizeof(*p->play_dtmf), where p->play_dtmf is defined as char[16], to get the length of the array but since p->play_dtmf is an actual array, sizeof(*p->play_dtmf) returns the size of the first array element, which is 1. gcc7 validly complains because the context in which it's used could cause an out-of-bounds condition. Change-Id: If9c4bfdb6b02fa72d39e0c09bf88900663c000ba --- channels/chan_vpb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index d7e9732e0bc..6e77dc2724e 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -1791,7 +1791,7 @@ static int vpb_digit_end(struct ast_channel *ast, char digit, unsigned int durat ast_verb(4, "%s: vpb_digit: asked to play digit[%s]\n", p->dev, s); ast_mutex_lock(&p->play_dtmf_lock); - strncat(p->play_dtmf, s, sizeof(*p->play_dtmf) - strlen(p->play_dtmf) - 1); + strncat(p->play_dtmf, s, sizeof(p->play_dtmf) - strlen(p->play_dtmf) - 1); ast_mutex_unlock(&p->play_dtmf_lock); ast_mutex_unlock(&p->lock); From e8bde6916ab0003e6737a320074b1c6ae1516db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=C3=A1n=20C=20McCord?= Date: Fri, 6 Oct 2017 21:48:48 -0400 Subject: [PATCH 1550/1578] ari/bridge: Add mute, dtmf suppression controls Add bridge_features structure to bridge creation. Specifically, this implements mute and DTMF suppression, but others should be able to be easily added to the same structure. ASTERISK-27322 #close Reported by: Darren Sessions Sponsored by: AVOXI Change-Id: Id4002adfb65c9a8027ee9e1a5f477e0f01cf9d61 --- include/asterisk/stasis_app.h | 32 ++++++++++++++++++++++++++++ res/ari/resource_bridges.c | 6 ++++++ res/ari/resource_bridges.h | 4 ++++ res/res_ari_bridges.c | 14 ++++++++++++ res/stasis/control.c | 39 +++++++++++++++++++++++++++++++++- rest-api/api-docs/bridges.json | 18 ++++++++++++++++ 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h index ca5c25111cb..8ef2bda1cdb 100644 --- a/include/asterisk/stasis_app.h +++ b/include/asterisk/stasis_app.h @@ -792,6 +792,38 @@ int stasis_app_control_add_channel_to_bridge( int stasis_app_control_remove_channel_from_bridge( struct stasis_app_control *control, struct ast_bridge *bridge); +/*! + * \brief Initialize bridge features into a channel control + * + * \note Bridge features on a control are destroyed after each bridge session, + * so new features need to be initialized before each bridge add. + * + * \param control Control in which to store the features + * + * \return non-zero on failure + * \return zero on success + */ +int stasis_app_control_bridge_features_init( + struct stasis_app_control *control); + +/*! + * \brief Set whether DTMF from the channel is absorbed instead of passing through to the bridge + * + * \param control Control whose channel should have its DTMF absorbed when bridged + * \param absorb Whether DTMF should be absorbed (1) instead of passed through (0). + */ +void stasis_app_control_absorb_dtmf_in_bridge( + struct stasis_app_control *control, int absorb); + +/*! + * \brief Set whether audio from the channel is muted instead of passing through to the bridge + * + * \param control Control whose channel should have its audio muted when bridged + * \param mute Whether audio should be muted (1) instead of passed through (0). + */ +void stasis_app_control_mute_in_bridge( + struct stasis_app_control *control, int mute); + /*! * \since 12 * \brief Gets the bridge currently associated with a control object. diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index f243086c978..aab78ce189c 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -218,6 +218,12 @@ void ast_ari_bridges_add_channel(struct ast_variable *headers, return; } } + + /* Apply bridge features to each of the channel controls */ + if (!stasis_app_control_bridge_features_init(list->controls[i])) { + stasis_app_control_absorb_dtmf_in_bridge(list->controls[i], args->absorb_dtmf); + stasis_app_control_mute_in_bridge(list->controls[i], args->mute); + } } for (i = 0; i < list->count; ++i) { diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h index e75d8e02873..72dba1e0c5f 100644 --- a/res/ari/resource_bridges.h +++ b/res/ari/resource_bridges.h @@ -150,6 +150,10 @@ struct ast_ari_bridges_add_channel_args { char *channel_parse; /*! Channel's role in the bridge */ const char *role; + /*! Absorb DTMF coming from this channel, preventing it to pass through to the bridge */ + int absorb_dtmf; + /*! Mute audio from this channel, preventing it to pass through to the bridge */ + int mute; }; /*! * \brief Body parsing function for /bridges/{bridgeId}/addChannel. diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 65bf7ed3e73..35fd3bd7ff1 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -430,6 +430,14 @@ int ast_ari_bridges_add_channel_parse_body( if (field) { args->role = ast_json_string_get(field); } + field = ast_json_object_get(body, "absorbDTMF"); + if (field) { + args->absorb_dtmf = ast_json_is_true(field); + } + field = ast_json_object_get(body, "mute"); + if (field) { + args->mute = ast_json_is_true(field); + } return 0; } @@ -499,6 +507,12 @@ static void ast_ari_bridges_add_channel_cb( if (strcmp(i->name, "role") == 0) { args.role = (i->value); } else + if (strcmp(i->name, "absorbDTMF") == 0) { + args.absorb_dtmf = ast_true(i->value); + } else + if (strcmp(i->name, "mute") == 0) { + args.mute = ast_true(i->value); + } else {} } for (i = path_vars; i; i = i->next) { diff --git a/res/stasis/control.c b/res/stasis/control.c index 01c04dffee7..dc005a1e5d9 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -35,6 +35,7 @@ #include "asterisk/bridge.h" #include "asterisk/bridge_after.h" #include "asterisk/bridge_basic.h" +#include "asterisk/bridge_features.h" #include "asterisk/frame.h" #include "asterisk/pbx.h" #include "asterisk/musiconhold.h" @@ -61,6 +62,10 @@ struct stasis_app_control { * When a channel is in a bridge, the bridge that it is in. */ struct ast_bridge *bridge; + /*! + * Bridge features which should be applied to the channel when it enters the next bridge. These only apply to the next bridge and will be emptied thereafter. + */ + struct ast_bridge_features *bridge_features; /*! * Holding place for channel's PBX while imparted to a bridge. */ @@ -99,6 +104,8 @@ static void control_dtor(void *obj) ast_cond_destroy(&control->wait_cond); AST_LIST_HEAD_DESTROY(&control->add_rules); AST_LIST_HEAD_DESTROY(&control->remove_rules); + ast_bridge_features_destroy(control->bridge_features); + } struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app) @@ -1161,6 +1168,7 @@ static void set_interval_hook(struct ast_channel *chan) int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap) { int res; + struct ast_bridge_features *features; if (!control || !bridge) { return -1; @@ -1205,6 +1213,10 @@ int control_swap_channel_in_bridge(struct stasis_app_control *control, struct as ast_channel_pbx_set(chan, NULL); } + /* Pull bridge features from the control */ + features = control->bridge_features; + control->bridge_features = NULL; + ast_assert(stasis_app_get_bridge(control) == NULL); /* We need to set control->bridge here since bridge_after_cb may be run * before ast_bridge_impart returns. bridge_after_cb gets a reason @@ -1220,7 +1232,7 @@ int control_swap_channel_in_bridge(struct stasis_app_control *control, struct as res = ast_bridge_impart(bridge, chan, swap, - NULL, /* features */ + features, /* features */ AST_BRIDGE_IMPART_CHAN_DEPARTABLE); if (res != 0) { /* ast_bridge_impart failed before it could spawn the depart @@ -1316,6 +1328,31 @@ int stasis_app_control_queue_control(struct stasis_app_control *control, return ast_queue_control(control->channel, frame_type); } +int stasis_app_control_bridge_features_init( + struct stasis_app_control *control) +{ + struct ast_bridge_features *features; + + features = ast_bridge_features_new(); + if (!features) { + return 1; + } + control->bridge_features = features; + return 0; +} + +void stasis_app_control_absorb_dtmf_in_bridge( + struct stasis_app_control *control, int absorb) +{ + control->bridge_features->dtmf_passthrough = !absorb; +} + +void stasis_app_control_mute_in_bridge( + struct stasis_app_control *control, int mute) +{ + control->bridge_features->mute = mute; +} + void control_flush_queue(struct stasis_app_control *control) { struct ao2_iterator iter; diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json index 877fdf84da1..cf8ee3156b3 100644 --- a/rest-api/api-docs/bridges.json +++ b/rest-api/api-docs/bridges.json @@ -169,6 +169,24 @@ "required": false, "allowMultiple": false, "dataType": "string" + }, + { + "name": "absorbDTMF", + "description": "Absorb DTMF coming from this channel, preventing it to pass through to the bridge", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "boolean", + "defaultValue": false + }, + { + "name": "mute", + "description": "Mute audio from this channel, preventing it to pass through to the bridge", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "boolean", + "defaultValue": false } ], "errorResponses": [ From e5b9eb0460f29fdf99e681732c5cbe9675d864f8 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Oct 2017 18:12:04 -0500 Subject: [PATCH 1551/1578] cdr.c: Defer misc checks. Try to defer some checks until needed in case there is an early exit. Change-Id: Ibc6b34c38a4f60ad4f9b67984b7d070a07257064 --- main/cdr.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 1ea244545c6..d34503d123a 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1935,6 +1935,10 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str if (!peer && !caller) { return; } + if (filter_channel_snapshot(peer) || (caller && filter_channel_snapshot(caller))) { + return; + } + dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus"); if (dial_status_blob) { dial_status = ast_json_string_get(dial_status_blob); @@ -1947,10 +1951,6 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str (unsigned int)stasis_message_timestamp(message)->tv_sec, (unsigned int)stasis_message_timestamp(message)->tv_usec); - if (filter_channel_snapshot(peer) || (caller && filter_channel_snapshot(caller))) { - return; - } - /* Figure out who is running this show */ if (caller) { cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_SEARCH_KEY); @@ -2080,8 +2080,6 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription struct stasis_cache_update *update = stasis_message_data(message); struct ast_channel_snapshot *old_snapshot; struct ast_channel_snapshot *new_snapshot; - const char *uniqueid; - const char *name; struct cdr_object *it_cdr; ast_assert(update != NULL); @@ -2089,8 +2087,6 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription old_snapshot = stasis_message_data(update->old_snapshot); new_snapshot = stasis_message_data(update->new_snapshot); - uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid; - name = new_snapshot ? new_snapshot->name : old_snapshot->name; if (filter_channel_cache_message(old_snapshot, new_snapshot)) { return; @@ -2104,11 +2100,17 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription cdr->is_root = 1; ao2_link(active_cdrs_by_channel, cdr); } else { + const char *uniqueid; + + uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid; cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_SEARCH_KEY); } /* Handle Party A */ if (!cdr) { + const char *name; + + name = new_snapshot ? new_snapshot->name : old_snapshot->name; ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name); ast_assert(0); } else { @@ -4318,7 +4320,7 @@ int ast_cdr_engine_reload(void) RAII_VAR(struct module_config *, old_mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); RAII_VAR(struct module_config *, mod_cfg, NULL, ao2_cleanup); - if (process_config(1)) { + if (!old_mod_cfg || process_config(1)) { return -1; } From a56316423f113423a1fe070d2749932fbdfccb9a Mon Sep 17 00:00:00 2001 From: Daniel Tryba Date: Fri, 6 Oct 2017 12:14:40 +0200 Subject: [PATCH 1552/1578] res_pjsip: Prevent "user=phone" being added multiple times to header ast_sip_add_usereqphone adds "user=phone" to the header every time is is called without checking whether the param already exists. Preventing this by searching to string representation of header for "user=phone". ASTERISK-26988 #close Change-Id: Ib84383b07254de357dc6a98d91fc1d2c2c3719e6 --- res/res_pjsip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index a784e126232..f81d34ca447 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -3095,6 +3095,11 @@ void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t return; } + if (pjsip_param_find(&sip_uri->other_param, &STR_USER)) { + /* Don't add it if it's already there */ + return; + } + param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = STR_USER; param->value = STR_PHONE; From 6576e4320a623dd6efdce29476c76db50209a70c Mon Sep 17 00:00:00 2001 From: Daniel Tryba Date: Fri, 6 Oct 2017 11:55:38 +0200 Subject: [PATCH 1553/1578] res_pjsip_session: Prevent user=phone being added to anonimized URIs. Move ast_sip_add_usereqphone to be called after anonymization of URIs, to prevent the user_eq_phone adding "user=phone" to URIs containing a username that is not a phonenumber (RFC3261 19.1.1). An extra call to ast_sip_add_usereqphone on the saved version before anonymization is added to add user=phone" to the PAI. ASTERISK-27047 #close Change-Id: Ie5644bc66341b86dc08b1f7442210de2e6acdec6 --- res/res_pjsip_session.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 49f2f17c26e..d8789ae52ea 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1329,10 +1329,9 @@ static void set_from_header(struct ast_sip_session *session) pj_strdup2(dlg_pool, &dlg_info_uri->host, session->endpoint->fromdomain); } - ast_sip_add_usereqphone(session->endpoint, dlg_pool, dlg_info->uri); - /* We need to save off the non-anonymized From for RPID/PAI generation (for domain) */ session->saved_from_hdr = pjsip_hdr_clone(dlg_pool, dlg_info); + ast_sip_add_usereqphone(session->endpoint, dlg_pool, session->saved_from_hdr->uri); /* In chan_sip, fromuser and fromdomain trump restricted so we only * anonymize if they're not set. @@ -1348,7 +1347,9 @@ static void set_from_header(struct ast_sip_session *session) if (ast_strlen_zero(session->endpoint->fromdomain)) { pj_strdup2(dlg_pool, &dlg_info_uri->host, "anonymous.invalid"); } - } + } else { + ast_sip_add_usereqphone(session->endpoint, dlg_pool, dlg_info->uri); + } } int ast_sip_session_refresh(struct ast_sip_session *session, From 21c0283b7882eae035bca8def02c283720445701 Mon Sep 17 00:00:00 2001 From: Thomas Sevestre Date: Fri, 25 Aug 2017 13:19:00 +0000 Subject: [PATCH 1554/1578] features, manager : Add CancelAtxfer AMI action Add action to cancel feature attended transfer with AMI interface ASTERISK-27215 #close Change-Id: Iab8a81362b5a1757e2608f70b014ef863200cb42 --- CHANGES | 4 ++ include/asterisk/features_config.h | 15 ++++++++ main/features_config.c | 15 ++++++++ main/manager.c | 62 ++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/CHANGES b/CHANGES index 4d1395fba46..63c8c6f7cec 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,10 @@ res_pjsip than one. The removed contact is likely the old contact created by "rewrite_contact" that the device is refreshing. +AMI +------------------ + * Added a new CancelAtxfer action that cancels an attended transfer. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- ------------------------------------------------------------------------------ diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h index baaff183b30..1bce50bba23 100644 --- a/include/asterisk/features_config.h +++ b/include/asterisk/features_config.h @@ -116,6 +116,21 @@ struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_ch */ char *ast_get_chan_features_xferfailsound(struct ast_channel *chan); +/*! + * \brief Get the transfer configuration option atxferabort + * + * \note The channel should be locked before calling this function. + * \note The returned value has to be freed. + * + * If no channel is provided, then option is pulled from the global + * transfer configuration. + * + * \param chan The channel to get configuration options for + * \retval NULL Failed to get configuration + * \retval non-NULL The atxferabort + */ +char *ast_get_chan_features_atxferabort(struct ast_channel *chan); + /*! * \brief Configuration relating to call pickup */ diff --git a/main/features_config.c b/main/features_config.c index 8307b120918..72cd0404f7a 100644 --- a/main/features_config.c +++ b/main/features_config.c @@ -1173,6 +1173,21 @@ char *ast_get_chan_features_xferfailsound(struct ast_channel *chan) return res; } +char *ast_get_chan_features_atxferabort(struct ast_channel *chan) +{ + char *res; + struct ast_features_xfer_config *cfg = ast_get_chan_features_xfer_config(chan); + + if (!cfg) { + return NULL; + } + + res = ast_strdup(cfg->atxferabort); + ao2_ref(cfg, -1); + + return res; +} + struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan) { RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup); diff --git a/main/manager.c b/main/manager.c index e67efe3f3fc..5c0b318b96e 100644 --- a/main/manager.c +++ b/main/manager.c @@ -628,6 +628,25 @@ AttendedTransfer + + + Cancel an attended transfer. + + + + + The transferer channel. + + + + Cancel an attended transfer. Note, this uses the configured cancel attended transfer + feature option (atxferabort) to cancel the transfer. If not available this action will fail. + + + + AttendedTransfer + + Originate a call. @@ -4959,6 +4978,47 @@ static int action_atxfer(struct mansession *s, const struct message *m) return 0; } +static int action_cancel_atxfer(struct mansession *s, const struct message *m) +{ + const char *name = astman_get_header(m, "Channel"); + struct ast_channel *chan = NULL; + char *feature_code; + const char *digit; + + if (ast_strlen_zero(name)) { + astman_send_error(s, m, "No channel specified"); + return 0; + } + + if (!(chan = ast_channel_get_by_name(name))) { + astman_send_error(s, m, "Channel specified does not exist"); + return 0; + } + + ast_channel_lock(chan); + feature_code = ast_get_chan_features_atxferabort(chan); + ast_channel_unlock(chan); + + if (!feature_code) { + astman_send_error(s, m, "No disconnect feature code found"); + ast_channel_unref(chan); + return 0; + } + + for (digit = feature_code; *digit; ++digit) { + struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit }; + ast_queue_frame(chan, &f); + } + ast_free(feature_code); + + chan = ast_channel_unref(chan); + + astman_send_ack(s, m, "CancelAtxfer successfully queued"); + + return 0; +} + + static int check_blacklist(const char *cmd) { char *cmd_copy, *cur_cmd; @@ -8679,6 +8739,7 @@ static void manager_shutdown(void) ast_manager_unregister("ListCategories"); ast_manager_unregister("Redirect"); ast_manager_unregister("Atxfer"); + ast_manager_unregister("CancelAtxfer"); ast_manager_unregister("Originate"); ast_manager_unregister("Command"); ast_manager_unregister("ExtensionState"); @@ -8894,6 +8955,7 @@ static int __init_manager(int reload, int by_external_config) ast_manager_register_xml_core("ListCategories", EVENT_FLAG_CONFIG, action_listcategories); ast_manager_register_xml_core("Redirect", EVENT_FLAG_CALL, action_redirect); ast_manager_register_xml_core("Atxfer", EVENT_FLAG_CALL, action_atxfer); + ast_manager_register_xml_core("CancelAtxfer", EVENT_FLAG_CALL, action_cancel_atxfer); ast_manager_register_xml_core("Originate", EVENT_FLAG_ORIGINATE, action_originate); ast_manager_register_xml_core("Command", EVENT_FLAG_COMMAND, action_command); ast_manager_register_xml_core("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate); From c80c8f2ab968e9cf4de1db1fccfece990318671e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Oct 2017 18:03:11 -0500 Subject: [PATCH 1555/1578] cdr.c: Fix setting dnid, callingsubaddr, and calledsubaddr The string comparisons for setting these CDR variables was inverted. We were repeatedly setting these CDR variables only if the channel snapshots had the same value. ASTERISK-27335 Change-Id: I9482073524411e7ea6c03805b16de200cb1669ea --- main/cdr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index d34503d123a..fc125f25474 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1333,13 +1333,13 @@ static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, stru set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr); return; } - if (!strcmp(old_snapshot->snapshot->caller_dnid, new_snapshot->caller_dnid)) { + if (strcmp(old_snapshot->snapshot->caller_dnid, new_snapshot->caller_dnid)) { set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid); } - if (!strcmp(old_snapshot->snapshot->caller_subaddr, new_snapshot->caller_subaddr)) { + if (strcmp(old_snapshot->snapshot->caller_subaddr, new_snapshot->caller_subaddr)) { set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr); } - if (!strcmp(old_snapshot->snapshot->dialed_subaddr, new_snapshot->dialed_subaddr)) { + if (strcmp(old_snapshot->snapshot->dialed_subaddr, new_snapshot->dialed_subaddr)) { set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr); } } From 7c7a9178740587fc5a120d59608ce3005478b5af Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Oct 2017 18:08:33 -0500 Subject: [PATCH 1556/1578] cdr.c: Set stringfields only if they are different. The CDR performance gets worse the further it gets behind in processing stasis messages. One of the reasons is we were repeatedly setting string fields to potentially the same string in base_process_party_a(). Setting a string field involves allocating room for the new string out of a memory pool which may have to allocate even more memory. * Check to see if the string field is already set to the desired string. ASTERISK-27335 Change-Id: I3ccb7e23f1488417e08cafe477755033eed65a7c --- main/cdr.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index fc125f25474..6a3365ea08e 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1378,8 +1378,12 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps */ if (!ast_test_flag(&snapshot->flags, AST_FLAG_SUBROUTINE_EXEC) || ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) { - ast_string_field_set(cdr, context, snapshot->context); - ast_string_field_set(cdr, exten, snapshot->exten); + if (strcmp(cdr->context, snapshot->context)) { + ast_string_field_set(cdr, context, snapshot->context); + } + if (strcmp(cdr->exten, snapshot->exten)) { + ast_string_field_set(cdr, exten, snapshot->exten); + } } cdr_object_swap_snapshot(&cdr->party_a, snapshot); @@ -1389,11 +1393,15 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps * of "AppDialX". Prevent that, and any other application changes we might not want * here. */ - if (!ast_strlen_zero(snapshot->appl) - && (strncasecmp(snapshot->appl, "appdial", 7) || ast_strlen_zero(cdr->appl)) - && !ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP)) { - ast_string_field_set(cdr, appl, snapshot->appl); - ast_string_field_set(cdr, data, snapshot->data); + if (!ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP) + && !ast_strlen_zero(snapshot->appl) + && (strncasecmp(snapshot->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) { + if (strcmp(cdr->appl, snapshot->appl)) { + ast_string_field_set(cdr, appl, snapshot->appl); + } + if (strcmp(cdr->data, snapshot->data)) { + ast_string_field_set(cdr, data, snapshot->data); + } /* Dial (app_dial) is a special case. Because pre-dial handlers, which * execute before the dial begins, will alter the application/data to @@ -1405,7 +1413,9 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps } } - ast_string_field_set(cdr, linkedid, snapshot->linkedid); + if (strcmp(cdr->linkedid, snapshot->linkedid)) { + ast_string_field_set(cdr, linkedid, snapshot->linkedid); + } cdr_object_check_party_a_answer(cdr); cdr_object_check_party_a_hangup(cdr); From 2eea087401041e36b39fa6c248394eeefedd7ccf Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 6 Oct 2017 13:45:30 -0500 Subject: [PATCH 1557/1578] cdr.c: Defer getting ao2_global_obj_ref() until needed. The CDR performance gets worse the further it gets behind in processing stasis messages. One of the reasons is we were getting the global config even if we didn't need it. * Most uses of the global config were only needed on off nominal code paths so it makes sense to not get it until absolutely needed. ASTERISK-27335 Change-Id: I00c63b7ec233e5bfffd5d976f05568613d3c2365 --- main/cdr.c | 81 +++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 6a3365ea08e..dc5c947fd94 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -949,6 +949,28 @@ static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr) return new_cdr; } +/*! + * \internal + * \brief Determine if CDR flag is configured. + * + * \param cdr_flag The configured CDR flag to check. + * + * \retval 0 if the CDR flag is not configured. + * \retval non-zero if the CDR flag is configured. + * + * \return Nothing + */ +static int is_cdr_flag_set(unsigned int cdr_flag) +{ + struct module_config *mod_cfg; + int flag_set; + + mod_cfg = ao2_global_obj_ref(module_configs); + flag_set = mod_cfg && ast_test_flag(&mod_cfg->general->settings, cdr_flag); + ao2_cleanup(mod_cfg); + return flag_set; +} + /*! * \brief Return whether or not a channel has changed its state in the dialplan, subject * to endbeforehexten logic @@ -962,12 +984,9 @@ static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr) static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); - /* If we ignore hangup logic, don't indicate that we're executing anything new */ - if (ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN) - && ast_test_flag(&new_snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) { + if (ast_test_flag(&new_snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC) + && is_cdr_flag_set(CDR_END_BEFORE_H_EXTEN)) { return 0; } @@ -975,10 +994,11 @@ static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot, * will attempt to clear the application and restore the dummy originate application * of "AppDialX". Ignore application changes to AppDialX as a result. */ - if (strcmp(new_snapshot->appl, old_snapshot->appl) && strncasecmp(new_snapshot->appl, "appdial", 7) + if (strcmp(new_snapshot->appl, old_snapshot->appl) + && strncasecmp(new_snapshot->appl, "appdial", 7) && (strcmp(new_snapshot->context, old_snapshot->context) - || strcmp(new_snapshot->exten, old_snapshot->exten) - || new_snapshot->priority != old_snapshot->priority)) { + || strcmp(new_snapshot->exten, old_snapshot->exten) + || new_snapshot->priority != old_snapshot->priority)) { return 1; } @@ -1050,15 +1070,15 @@ static long cdr_object_get_duration(struct cdr_object *cdr) */ static long cdr_object_get_billsec(struct cdr_object *cdr) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); long int ms; if (ast_tvzero(cdr->answer)) { return 0; } + ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer); - if (ast_test_flag(&mod_cfg->general->settings, CDR_INITIATED_SECONDS) - && (ms % 1000 >= 500)) { + if (ms % 1000 >= 500 + && is_cdr_flag_set(CDR_INITIATED_SECONDS)) { ms = (ms / 1000) + 1; } else { ms = ms / 1000; @@ -1219,16 +1239,13 @@ static void cdr_object_dispatch(struct cdr_object *cdr) */ static void cdr_object_set_disposition(struct cdr_object *cdr, int hangupcause) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); - /* Change the disposition based on the hang up cause */ switch (hangupcause) { case AST_CAUSE_BUSY: cdr->disposition = AST_CDR_BUSY; break; case AST_CAUSE_CONGESTION: - if (!ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION)) { + if (!is_cdr_flag_set(CDR_CONGESTION)) { cdr->disposition = AST_CDR_FAILED; } else { cdr->disposition = AST_CDR_CONGESTION; @@ -1295,10 +1312,8 @@ static void cdr_object_finalize(struct cdr_object *cdr) */ static void cdr_object_check_party_a_hangup(struct cdr_object *cdr) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - - if (ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN) - && ast_test_flag(&cdr->party_a.snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) { + if (ast_test_flag(&cdr->party_a.snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC) + && is_cdr_flag_set(CDR_END_BEFORE_H_EXTEN)) { cdr_object_finalize(cdr); } @@ -1361,13 +1376,11 @@ static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot, static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - ast_assert(strcasecmp(snapshot->name, cdr->party_a.snapshot->name) == 0); /* Finalize the CDR if we're in hangup logic and we're set to do so */ if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC) - && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) { + && is_cdr_flag_set(CDR_END_BEFORE_H_EXTEN)) { cdr_object_finalize(cdr); return 0; } @@ -1651,9 +1664,6 @@ static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_chan */ static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); - if (!strcmp(dial_status, "ANSWER")) { return AST_CDR_ANSWERED; } else if (!strcmp(dial_status, "BUSY")) { @@ -1661,7 +1671,7 @@ static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_stat } else if (!strcmp(dial_status, "CANCEL") || !strcmp(dial_status, "NOANSWER")) { return AST_CDR_NOANSWER; } else if (!strcmp(dial_status, "CONGESTION")) { - if (!ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION)) { + if (!is_cdr_flag_set(CDR_CONGESTION)) { return AST_CDR_FAILED; } else { return AST_CDR_CONGESTION; @@ -1871,11 +1881,8 @@ static void finalized_state_init_function(struct cdr_object *cdr) static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); - if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC) - && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) { + && is_cdr_flag_set(CDR_END_BEFORE_H_EXTEN)) { return 0; } @@ -2054,13 +2061,10 @@ static int cdr_object_update_party_b(void *obj, void *arg, int flags) static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); - /* If we're dead, we don't need a new CDR */ if (!new_snapshot || (ast_test_flag(&new_snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC) - && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN))) { + && is_cdr_flag_set(CDR_END_BEFORE_H_EXTEN))) { return 0; } @@ -2660,8 +2664,7 @@ void ast_cdr_set_config(struct ast_cdr_config *config) int ast_cdr_is_enabled(void) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - return ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED); + return is_cdr_flag_set(CDR_ENABLED); } int ast_cdr_backend_suspend(const char *name) @@ -3155,13 +3158,9 @@ int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, cdr = cdr_object_get_by_name(channel_name); if (!cdr) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); - - if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) { + if (is_cdr_flag_set(CDR_ENABLED)) { ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name); } - return 0; } From f369be21a81608460cc29d81528e8b267b08ca6a Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 29 Sep 2017 14:26:41 -0500 Subject: [PATCH 1558/1578] cdr.c: Eliminated many calls to ao2_global_obj_ref(). The CDR performance gets worse the further it gets behind in processing stasis messages. One of the reasons is we were getting the global config to determine if we needed to log a debugging message. * Many calls to ao2_global_obj_ref() were just so we could determine if debug mode is enabled. Made a global flag to check instead. * Eliminated many RAII_VAR() usages associated with the remaining ao2_global_obj_ref() calls. * Added missing NULL checks for the returned ao2_global_obj_ref() value. ASTERISK-27335 Change-Id: Iceaad93172862f610cad0188956634187bfcc7cd --- main/cdr.c | 307 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 184 insertions(+), 123 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index dc5c947fd94..def3871bc0f 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -207,9 +207,16 @@ #define DEFAULT_BATCH_SCHEDULER_ONLY "0" #define DEFAULT_BATCH_SAFE_SHUTDOWN "1" -#define CDR_DEBUG(mod_cfg, fmt, ...) \ +#define cdr_set_debug_mode(mod_cfg) \ do { \ - if (ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG)) { \ + cdr_debug_enabled = ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG); \ + } while (0) + +static int cdr_debug_enabled; + +#define CDR_DEBUG(fmt, ...) \ + do { \ + if (cdr_debug_enabled) { \ ast_verbose((fmt), ##__VA_ARGS__); \ } \ } while (0) @@ -237,6 +244,7 @@ static struct aco_type general_option = { static void *module_config_alloc(void); static void module_config_destructor(void *obj); +static void module_config_post_apply(void); /*! \brief The file definition */ static struct aco_file module_file_conf = { @@ -247,10 +255,23 @@ static struct aco_file module_file_conf = { CONFIG_INFO_CORE("cdr", cfg_info, module_configs, module_config_alloc, .files = ACO_FILES(&module_file_conf), + .post_apply_config = module_config_post_apply, ); static struct aco_type *general_options[] = ACO_TYPES(&general_option); +static void module_config_post_apply(void) +{ + struct module_config *mod_cfg; + + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + return; + } + cdr_set_debug_mode(mod_cfg); + ao2_cleanup(mod_cfg); +} + /*! \brief Dispose of a module config object */ static void module_config_destructor(void *obj) { @@ -764,9 +785,7 @@ static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr */ static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - - CDR_DEBUG(mod_cfg, "%p - Transitioning CDR for %s from state %s to %s\n", + CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n", cdr, cdr->party_a.snapshot->name, cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name); cdr->fn_table = fn_table; @@ -874,7 +893,6 @@ static void cdr_object_dtor(void *obj) */ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); struct cdr_object *cdr; ast_assert(chan != NULL); @@ -897,7 +915,7 @@ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan) cdr->party_a.snapshot = chan; ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation"); - CDR_DEBUG(mod_cfg, "%p - Created CDR for channel %s\n", cdr, chan->name); + CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->name); cdr_object_transition_state(cdr, &single_state_fn_table); @@ -1221,13 +1239,11 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr) */ static void cdr_object_dispatch(struct cdr_object *cdr) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); struct ast_cdr *pub_cdr; - CDR_DEBUG(mod_cfg, "%p - Dispatching CDR for Party A %s, Party B %s\n", cdr, - cdr->party_a.snapshot->name, - cdr->party_b.snapshot ? cdr->party_b.snapshot->name : ""); + CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr, + cdr->party_a.snapshot->name, + cdr->party_b.snapshot ? cdr->party_b.snapshot->name : ""); pub_cdr = cdr_object_create_public_records(cdr); cdr_detach(pub_cdr); } @@ -1327,13 +1343,12 @@ static void cdr_object_check_party_a_hangup(struct cdr_object *cdr) * \brief Check to see if a CDR needs to be answered based on its Party A. * Note that this is safe to call as much as you want - we won't answer twice */ -static void cdr_object_check_party_a_answer(struct cdr_object *cdr) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - +static void cdr_object_check_party_a_answer(struct cdr_object *cdr) +{ if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) { cdr->answer = ast_tvnow(); /* tv_usec is suseconds_t, which could be int or long */ - CDR_DEBUG(mod_cfg, "%p - Set answered time to %ld.%06ld\n", cdr, + CDR_DEBUG("%p - Set answered time to %ld.%06ld\n", cdr, (long)cdr->answer.tv_sec, (long)cdr->answer.tv_usec); } @@ -1489,15 +1504,13 @@ static void single_state_process_party_b(struct cdr_object *cdr, struct ast_chan static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - if (caller && !strcasecmp(cdr->party_a.snapshot->name, caller->name)) { base_process_party_a(cdr, caller); - CDR_DEBUG(mod_cfg, "%p - Updated Party A %s snapshot\n", cdr, - cdr->party_a.snapshot->name); + CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr, + cdr->party_a.snapshot->name); cdr_object_swap_snapshot(&cdr->party_b, peer); - CDR_DEBUG(mod_cfg, "%p - Updated Party B %s snapshot\n", cdr, - cdr->party_b.snapshot->name); + CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr, + cdr->party_b.snapshot->name); /* If we have two parties, lock the application that caused the * two parties to be associated. This prevents mid-call event @@ -1507,8 +1520,8 @@ static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_ch } else if (!strcasecmp(cdr->party_a.snapshot->name, peer->name)) { /* We're the entity being dialed, i.e., outbound origination */ base_process_party_a(cdr, peer); - CDR_DEBUG(mod_cfg, "%p - Updated Party A %s snapshot\n", cdr, - cdr->party_a.snapshot->name); + CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr, + cdr->party_a.snapshot->name); } cdr_object_transition_state(cdr, &dial_state_fn_table); @@ -1530,7 +1543,6 @@ static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_ch static int single_state_bridge_enter_comparison(struct cdr_object *cdr, struct cdr_object *cand_cdr) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); struct cdr_object_snapshot *party_a; /* Don't match on ourselves */ @@ -1541,7 +1553,7 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr, /* Try the candidate CDR's Party A first */ party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a); if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) { - CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n", + CDR_DEBUG("%p - Party A %s has new Party B %s\n", cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name); cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a); if (!cand_cdr->party_b.snapshot) { @@ -1561,7 +1573,7 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr, } party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b); if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) { - CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n", + CDR_DEBUG("%p - Party A %s has new Party B %s\n", cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name); cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b); return 0; @@ -1937,7 +1949,6 @@ static int dial_status_end(const char *dialstatus) */ static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); struct cdr_object *cdr; struct ast_multi_channel_blob *payload = stasis_message_data(message); struct ast_channel_snapshot *caller; @@ -1961,12 +1972,12 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str dial_status = ast_json_string_get(dial_status_blob); } - CDR_DEBUG(mod_cfg, "Dial %s message for %s, %s: %u.%08u\n", - ast_strlen_zero(dial_status) ? "Begin" : "End", - caller ? caller->name : "(none)", - peer ? peer->name : "(none)", - (unsigned int)stasis_message_timestamp(message)->tv_sec, - (unsigned int)stasis_message_timestamp(message)->tv_usec); + CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n", + ast_strlen_zero(dial_status) ? "Begin" : "End", + caller ? caller->name : "(none)", + peer ? peer->name : "(none)", + (unsigned int)stasis_message_timestamp(message)->tv_sec, + (unsigned int)stasis_message_timestamp(message)->tv_usec); /* Figure out who is running this show */ if (caller) { @@ -1986,10 +1997,10 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str if (!it_cdr->fn_table->process_dial_begin) { continue; } - CDR_DEBUG(mod_cfg, "%p - Processing Dial Begin message for channel %s, peer %s\n", - it_cdr, - caller ? caller->name : "(none)", - peer ? peer->name : "(none)"); + CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n", + it_cdr, + caller ? caller->name : "(none)", + peer ? peer->name : "(none)"); res &= it_cdr->fn_table->process_dial_begin(it_cdr, caller, peer); @@ -1997,10 +2008,10 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str if (!it_cdr->fn_table->process_dial_end) { continue; } - CDR_DEBUG(mod_cfg, "%p - Processing Dial End message for channel %s, peer %s\n", - it_cdr, - caller ? caller->name : "(none)", - peer ? peer->name : "(none)"); + CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n", + it_cdr, + caller ? caller->name : "(none)", + peer ? peer->name : "(none)"); it_cdr->fn_table->process_dial_end(it_cdr, caller, peer, @@ -2090,7 +2101,6 @@ static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot, static void handle_channel_cache_message(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct cdr_object *cdr; - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); struct stasis_cache_update *update = stasis_message_data(message); struct ast_channel_snapshot *old_snapshot; struct ast_channel_snapshot *new_snapshot; @@ -2148,7 +2158,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription } } } else { - CDR_DEBUG(mod_cfg, "%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name); + CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name); for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { cdr_object_finalize(it_cdr); } @@ -2228,8 +2238,6 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * struct ast_bridge_blob *update = stasis_message_data(message); struct ast_bridge_snapshot *bridge = update->bridge; struct ast_channel_snapshot *channel = update->channel; - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); struct cdr_object *cdr; struct cdr_object *it_cdr; struct bridge_leave_data leave_data = { @@ -2246,10 +2254,10 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * return; } - CDR_DEBUG(mod_cfg, "Bridge Leave message for %s: %u.%08u\n", - channel->name, - (unsigned int)stasis_message_timestamp(message)->tv_sec, - (unsigned int)stasis_message_timestamp(message)->tv_usec); + CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n", + channel->name, + (unsigned int)stasis_message_timestamp(message)->tv_sec, + (unsigned int)stasis_message_timestamp(message)->tv_usec); cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { @@ -2264,8 +2272,8 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * if (!it_cdr->fn_table->process_bridge_leave) { continue; } - CDR_DEBUG(mod_cfg, "%p - Processing Bridge Leave for %s\n", - it_cdr, channel->name); + CDR_DEBUG("%p - Processing Bridge Leave for %s\n", + it_cdr, channel->name); if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) { ast_string_field_set(it_cdr, bridge, ""); left_bridge = 1; @@ -2293,8 +2301,6 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, struct cdr_object_snapshot *party_b) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); struct cdr_object *new_cdr; new_cdr = cdr_object_create_and_append(cdr); @@ -2305,7 +2311,7 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, cdr_object_check_party_a_answer(new_cdr); ast_string_field_set(new_cdr, bridge, cdr->bridge); cdr_object_transition_state(new_cdr, &bridge_state_fn_table); - CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n", + CDR_DEBUG("%p - Party A %s has new Party B %s\n", new_cdr, new_cdr->party_a.snapshot->name, party_b->snapshot->name); } @@ -2324,8 +2330,6 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, */ static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); struct cdr_object_snapshot *party_a; struct cdr_object *cand_cdr; @@ -2358,7 +2362,7 @@ static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *b && strcasecmp(cand_cdr->party_b.snapshot->name, cdr->party_a.snapshot->name)) { bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a); } else { - CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n", + CDR_DEBUG("%p - Party A %s has new Party B %s\n", cand_cdr, cand_cdr->party_a.snapshot->name, cdr->party_a.snapshot->name); cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a); @@ -2408,8 +2412,6 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); int res = 1; struct cdr_object *it_cdr; struct cdr_object *new_cdr; @@ -2421,8 +2423,8 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr, res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel); } if (it_cdr->fn_table->process_party_a) { - CDR_DEBUG(mod_cfg, "%p - Updating Party A %s snapshot\n", it_cdr, - channel->name); + CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr, + channel->name); it_cdr->fn_table->process_party_a(it_cdr, channel); } } @@ -2448,8 +2450,6 @@ static void handle_standard_bridge_enter_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); enum process_bridge_enter_results result; struct cdr_object *it_cdr; struct cdr_object *new_cdr; @@ -2459,15 +2459,15 @@ static void handle_standard_bridge_enter_message(struct cdr_object *cdr, for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { if (it_cdr->fn_table->process_party_a) { - CDR_DEBUG(mod_cfg, "%p - Updating Party A %s snapshot\n", it_cdr, - channel->name); + CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr, + channel->name); it_cdr->fn_table->process_party_a(it_cdr, channel); } /* Notify all states that they have entered a bridge */ if (it_cdr->fn_table->process_bridge_enter) { - CDR_DEBUG(mod_cfg, "%p - Processing bridge enter for %s\n", it_cdr, - channel->name); + CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr, + channel->name); result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel); switch (result) { case BRIDGE_ENTER_ONLY_PARTY: @@ -2530,8 +2530,6 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription * struct ast_bridge_snapshot *bridge = update->bridge; struct ast_channel_snapshot *channel = update->channel; struct cdr_object *cdr; - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); if (filter_bridge_messages(bridge)) { return; @@ -2541,10 +2539,10 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription * return; } - CDR_DEBUG(mod_cfg, "Bridge Enter message for channel %s: %u.%08u\n", - channel->name, - (unsigned int)stasis_message_timestamp(message)->tv_sec, - (unsigned int)stasis_message_timestamp(message)->tv_usec); + CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n", + channel->name, + (unsigned int)stasis_message_timestamp(message)->tv_sec, + (unsigned int)stasis_message_timestamp(message)->tv_usec); cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { @@ -2574,8 +2572,6 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s struct ast_parked_call_payload *payload = stasis_message_data(message); struct ast_channel_snapshot *channel = payload->parkee; struct cdr_object *cdr; - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); int unhandled = 1; struct cdr_object *it_cdr; @@ -2593,10 +2589,10 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s return; } - CDR_DEBUG(mod_cfg, "Parked Call message for channel %s: %u.%08u\n", - channel->name, - (unsigned int)stasis_message_timestamp(message)->tv_sec, - (unsigned int)stasis_message_timestamp(message)->tv_usec); + CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n", + channel->name, + (unsigned int)stasis_message_timestamp(message)->tv_sec, + (unsigned int)stasis_message_timestamp(message)->tv_usec); cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { @@ -2646,20 +2642,37 @@ static void handle_cdr_sync_message(void *data, struct stasis_subscription *sub, struct ast_cdr_config *ast_cdr_get_config(void) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - ao2_ref(mod_cfg->general, +1); - return mod_cfg->general; + struct ast_cdr_config *general; + struct module_config *mod_cfg; + + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + return NULL; + } + general = ao2_bump(mod_cfg->general); + ao2_cleanup(mod_cfg); + return general; } void ast_cdr_set_config(struct ast_cdr_config *config) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; + + if (!config) { + return; + } + + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + return; + } - ao2_cleanup(mod_cfg->general); - mod_cfg->general = config; - ao2_ref(mod_cfg->general, +1); + ao2_replace(mod_cfg->general, config); + cdr_set_debug_mode(mod_cfg); cdr_toggle_runtime_options(); + + ao2_cleanup(mod_cfg); } int ast_cdr_is_enabled(void) @@ -3299,15 +3312,20 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) static void post_cdr(struct ast_cdr *cdr) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; struct cdr_beitem *i; + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + return; + } + for (; cdr ; cdr = cdr->next) { /* For people, who don't want to see unanswered single-channel events */ if (!ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) { - ast_debug(1, "Skipping CDR for %s since we weren't answered\n", cdr->channel); + ast_debug(1, "Skipping CDR for %s since we weren't answered\n", cdr->channel); continue; } @@ -3329,6 +3347,7 @@ static void post_cdr(struct ast_cdr *cdr) } AST_RWLIST_UNLOCK(&be_list); } + ao2_cleanup(mod_cfg); } int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option) @@ -3547,7 +3566,7 @@ static void *do_batch_backend_process(void *data) static void cdr_submit_batch(int do_shutdown) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; struct cdr_batch_item *oldbatchitems = NULL; pthread_t batch_post_thread = AST_PTHREADT_NULL; @@ -3562,9 +3581,13 @@ static void cdr_submit_batch(int do_shutdown) reset_batch(); ast_mutex_unlock(&cdr_batch_lock); + mod_cfg = ao2_global_obj_ref(module_configs); + /* if configured, spawn a new thread to post these CDRs, also try to save as much as possible if we are shutting down safely */ - if (ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) || do_shutdown) { + if (!mod_cfg + || ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) + || do_shutdown) { ast_debug(1, "CDR single-threaded batch processing begins now\n"); do_batch_backend_process(oldbatchitems); } else { @@ -3575,17 +3598,27 @@ static void cdr_submit_batch(int do_shutdown) ast_debug(1, "CDR multi-threaded batch processing begins now\n"); } } + + ao2_cleanup(mod_cfg); } static int submit_scheduled_batch(const void *data) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; + cdr_submit_batch(0); - /* manually reschedule from this point in time */ + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + return 0; + } + + /* manually reschedule from this point in time */ ast_mutex_lock(&cdr_sched_lock); cdr_sched = ast_sched_add(sched, mod_cfg->general->batch_settings.time * 1000, submit_scheduled_batch, NULL); ast_mutex_unlock(&cdr_sched_lock); + + ao2_cleanup(mod_cfg); /* returning zero so the scheduler does not automatically reschedule */ return 0; } @@ -3619,7 +3652,7 @@ static void cdr_detach(struct ast_cdr *cdr) } /* maybe they disabled CDR stuff completely, so just drop it */ - if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) { + if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) { ast_debug(1, "Dropping CDR !\n"); ast_cdr_free(cdr); return; @@ -3697,7 +3730,7 @@ static void *do_cdr(void *data) static char *handle_cli_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; switch (cmd) { case CLI_INIT: @@ -3715,6 +3748,11 @@ static char *handle_cli_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a return CLI_SHOWUSAGE; } + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + ast_cli(a->fd, "Could not set CDR debugging mode\n"); + return CLI_SUCCESS; + } if (!strcasecmp(a->argv[3], "on") && !ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) { ast_set_flag(&mod_cfg->general->settings, CDR_DEBUG); @@ -3724,6 +3762,8 @@ static char *handle_cli_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a ast_clear_flag(&mod_cfg->general->settings, CDR_DEBUG); ast_cli(a->fd, "CDR debugging disabled\n"); } + cdr_set_debug_mode(mod_cfg); + ao2_cleanup(mod_cfg); return CLI_SUCCESS; } @@ -3910,7 +3950,7 @@ static char *handle_cli_show(struct ast_cli_entry *e, int cmd, struct ast_cli_ar static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct cdr_beitem *beitem = NULL; - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; int cnt = 0; long nextbatchtime = 0; @@ -3929,6 +3969,11 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_ return CLI_SHOWUSAGE; } + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + return CLI_FAILURE; + } + ast_cli(a->fd, "\n"); ast_cli(a->fd, "Call Detail Record (CDR) settings\n"); ast_cli(a->fd, "----------------------------------\n"); @@ -3965,12 +4010,13 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, "\n"); } + ao2_cleanup(mod_cfg); return CLI_SUCCESS; } static char *handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; switch (cmd) { case CLI_INIT: @@ -3987,18 +4033,20 @@ static char *handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_ return CLI_SHOWUSAGE; } - if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) { - ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n"); - return CLI_SUCCESS; + mod_cfg = ao2_global_obj_ref(module_configs); + if (!mod_cfg) { + return CLI_FAILURE; } - if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) { + if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) { + ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n"); + } else if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) { ast_cli(a->fd, "Cannot submit CDR batch: batch mode not enabled.\n"); - return CLI_SUCCESS; + } else { + submit_unscheduled_batch(); + ast_cli(a->fd, "Submitted CDRs to backend engines for processing. This may take a while.\n"); } - - submit_unscheduled_batch(); - ast_cli(a->fd, "Submitted CDRs to backend engines for processing. This may take a while.\n"); + ao2_cleanup(mod_cfg); return CLI_SUCCESS; } @@ -4094,8 +4142,6 @@ static int create_subscriptions(void) static int process_config(int reload) { - RAII_VAR(struct module_config *, mod_cfg, module_config_alloc(), ao2_cleanup); - if (!reload) { if (aco_info_init(&cfg_info)) { return 1; @@ -4114,19 +4160,26 @@ static int process_config(int reload) aco_option_register(&cfg_info, "time", ACO_EXACT, general_options, DEFAULT_BATCH_TIME, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_cdr_config, batch_settings.time), 0, MAX_BATCH_TIME); } - if (aco_process_config(&cfg_info, reload)) { - if (!mod_cfg) { + if (aco_process_config(&cfg_info, reload) == ACO_PROCESS_ERROR) { + struct module_config *mod_cfg; + + if (reload) { return 1; } + /* If we couldn't process the configuration and this wasn't a reload, * create a default config */ - if (!reload && !(aco_set_defaults(&general_option, "general", mod_cfg->general))) { - ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n"); - ao2_global_obj_replace_unref(module_configs, mod_cfg); - return 0; + mod_cfg = module_config_alloc(); + if (!mod_cfg + || aco_set_defaults(&general_option, "general", mod_cfg->general)) { + ao2_cleanup(mod_cfg); + return 1; } - return 1; + ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n"); + ao2_global_obj_replace_unref(module_configs, mod_cfg); + cdr_set_debug_mode(mod_cfg); + ao2_cleanup(mod_cfg); } return 0; @@ -4213,13 +4266,15 @@ static void cdr_container_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt) */ static int cdr_toggle_runtime_options(void) { - RAII_VAR(struct module_config *, mod_cfg, - ao2_global_obj_ref(module_configs), ao2_cleanup); + struct module_config *mod_cfg; - if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) { + mod_cfg = ao2_global_obj_ref(module_configs); + if (mod_cfg + && ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) { if (create_subscriptions()) { destroy_subscriptions(); ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n"); + ao2_cleanup(mod_cfg); return -1; } if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) { @@ -4231,8 +4286,9 @@ static int cdr_toggle_runtime_options(void) destroy_subscriptions(); ast_log(LOG_NOTICE, "CDR logging disabled.\n"); } + ao2_cleanup(mod_cfg); - return 0; + return mod_cfg ? 0 : -1; } int ast_cdr_engine_init(void) @@ -4326,22 +4382,27 @@ void ast_cdr_engine_term(void) int ast_cdr_engine_reload(void) { - RAII_VAR(struct module_config *, old_mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup); - RAII_VAR(struct module_config *, mod_cfg, NULL, ao2_cleanup); + struct module_config *old_mod_cfg; + struct module_config *mod_cfg; + + old_mod_cfg = ao2_global_obj_ref(module_configs); if (!old_mod_cfg || process_config(1)) { + ao2_cleanup(old_mod_cfg); return -1; } mod_cfg = ao2_global_obj_ref(module_configs); - - if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) || - !(ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE))) { + if (!mod_cfg + || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) + || !ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) { /* If batch mode used to be enabled, finalize the batch */ if (ast_test_flag(&old_mod_cfg->general->settings, CDR_BATCHMODE)) { finalize_batch_mode(); } } + ao2_cleanup(mod_cfg); + ao2_cleanup(old_mod_cfg); return cdr_toggle_runtime_options(); } From 44d9446eb5002f59a64ada561b9732064da64aaf Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Fri, 13 Oct 2017 15:12:07 +0200 Subject: [PATCH 1559/1578] tcptls: NULL-check the parameter of ast_ssl_teardown before accessing it. This avoids a crash on stopping a chan_sip which failed to start its TLS server. ASTERISK-27339 #close Change-Id: I327fc70db68eaaca5b50a15c7fd687fde79263d5 --- main/tcptls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/tcptls.c b/main/tcptls.c index dbcff9da21b..a25e25b53a6 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -500,7 +500,7 @@ int ast_ssl_setup(struct ast_tls_config *cfg) void ast_ssl_teardown(struct ast_tls_config *cfg) { #ifdef DO_SSL - if (cfg->ssl_ctx) { + if (cfg && cfg->ssl_ctx) { SSL_CTX_free(cfg->ssl_ctx); cfg->ssl_ctx = NULL; } From ee65d5ac7c6a47734662a431b4cea54cd3d58a3b Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 13 Oct 2017 09:51:09 -0400 Subject: [PATCH 1560/1578] ast_bt_get_symbols: Prevent double-free. It's possible for bfdobj to be created but syms not created. If syms was not allocated in the current loop iteration but was allocated in the previous iteration it would crash. ASTERISK-27340 Change-Id: I5b110c609f6dfe91339f782a99a431bca5837363 --- main/backtrace.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main/backtrace.c b/main/backtrace.c index 0b29385fdc4..aed4ffd94a7 100644 --- a/main/backtrace.c +++ b/main/backtrace.c @@ -172,6 +172,7 @@ char **__ast_bt_get_symbols(void **addresses, size_t num_frames) if (bfdobj) { bfd_close(bfdobj); ast_std_free(syms); + syms = NULL; } /* Default output, if we cannot find the information within BFD */ From 7d51a79beb903874da97f52a31fabfdd94ac3680 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Thu, 12 Oct 2017 17:03:45 +0000 Subject: [PATCH 1561/1578] bridge_simple: Improve renegotiation success rate. When making channels compatible the bridge_simple module will renegotiate one to better match the other. Some endpoints incorrectly terminate the call if this process fails. To better handle this scenario the audio streams present on the new requested topology will include any existing negotiated formats that happen to exist on the first valid audio stream. This ensures formats are persent that are known to be acceptable to the remote endpoint. ASTERISK-27259 Change-Id: I8fc0cc03e8bcfd0be8302f13b9f32d8268977f43 --- bridges/bridge_simple.c | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index a49bc39f3a2..7ee1966741b 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -113,6 +113,58 @@ static struct ast_bridge_technology simple_bridge = { .stream_topology_changed = simple_bridge_stream_topology_changed, }; +static void simple_bridge_request_stream_topology_change(struct ast_channel *chan, + struct ast_stream_topology *requested_topology) +{ + struct ast_stream_topology *existing_topology = ast_channel_get_stream_topology(chan); + struct ast_stream *stream; + struct ast_format_cap *audio_formats = NULL; + struct ast_stream_topology *new_topology; + int i; + + /* We find an existing stream with negotiated audio formats that we can place into + * any audio streams in the new topology to ensure that negotiation succeeds. Some + * endpoints incorrectly terminate the call if SDP negotiation fails. + */ + for (i = 0; i < ast_stream_topology_get_count(existing_topology); ++i) { + stream = ast_stream_topology_get_stream(existing_topology, i); + + if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO || + ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + continue; + } + + audio_formats = ast_stream_get_formats(stream); + break; + } + + if (!audio_formats) { + ast_channel_request_stream_topology_change(chan, requested_topology, &simple_bridge); + return; + } + + new_topology = ast_stream_topology_clone(requested_topology); + if (!new_topology) { + ast_channel_request_stream_topology_change(chan, requested_topology, &simple_bridge); + return; + } + + for (i = 0; i < ast_stream_topology_get_count(new_topology); ++i) { + stream = ast_stream_topology_get_stream(new_topology, i); + + if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO || + ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + continue; + } + + ast_format_cap_append_from_cap(ast_stream_get_formats(stream), audio_formats, AST_MEDIA_TYPE_AUDIO); + } + + ast_channel_request_stream_topology_change(chan, new_topology, &simple_bridge); + + ast_stream_topology_free(new_topology); +} + static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { @@ -135,9 +187,9 @@ static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, /* Align topologies according to size or first channel to join */ if (ast_stream_topology_get_count(t0) < ast_stream_topology_get_count(t1)) { - ast_channel_request_stream_topology_change(c0, t1, &simple_bridge); + simple_bridge_request_stream_topology_change(c0, t1); } else { - ast_channel_request_stream_topology_change(c1, t0, &simple_bridge); + simple_bridge_request_stream_topology_change(c1, t0); } } From 8f65d91dfd1509a84d84cdc977d66c52ad925fc7 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Fri, 13 Oct 2017 16:43:12 +0200 Subject: [PATCH 1562/1578] res_pjsip_session: Rewrite o= with external_media_address. PJSIP allows a domain name as external_media_address. This allows chan_pjsip to be used behind a NAT with changing IP addresses. The IP address of that domain is resolved to the c= line already. This change sets also the o= line to that domain. ASTERISK-27341 #close Change-Id: I690163b6e762042ec38b3995aa5c9bea909d8ec4 --- res/res_pjsip_session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index d8789ae52ea..37ff5310503 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -4006,6 +4006,7 @@ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_trans if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) { ast_debug(5, "Setting external media address to %s\n", ast_sockaddr_stringify_host(&transport_state->external_media_address)); pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address)); + pj_strdup2(tdata->pool, &sdp->origin.addr, transport->external_media_address); } } From c4f40b778a8acb996a5076fa384f87ce37bce9f6 Mon Sep 17 00:00:00 2001 From: Guido Falsi Date: Sat, 14 Oct 2017 11:11:24 +0200 Subject: [PATCH 1563/1578] chan_dahdi: wrap include file which is not present on BSD systems in #ifdef The sys/sysmacros.h include file does not exist in BSD systems and is not required to build this module there. Since an "#if defined(__NetBSD__) || defined(__FreeBSD__)" section already exist I moved that include line inside it's #else branch. ASTERISK-27343 #close Change-Id: Ibfb64f4e9a0ce8b6eda7a7695cfe57916f175dc1 --- channels/chan_dahdi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 828753a05d9..b20a0f33acc 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -56,11 +56,12 @@ #if defined(__NetBSD__) || defined(__FreeBSD__) #include +#else +#include #endif #include #include #include -#include #include "sig_analog.h" /* Analog signaling is currently still present in chan_dahdi for use with From da24d425eb3082b4da639174c4e9814036b0e869 Mon Sep 17 00:00:00 2001 From: Torrey Searle Date: Wed, 11 Oct 2017 13:04:12 +0200 Subject: [PATCH 1564/1578] contrib/script/sip_to_pjsip: implement 'all' for allow/disallow when 'all' is specified in an allow or disallow section, it should erase all values from the inverse section in the default config. E.G. allow=all should erase any deny values from default config & vice-versa ASTERISK-27333 #close Change-Id: I99219478fb98f08751d769daaee0b7795118a5a6 --- contrib/scripts/sip_to_pjsip/sip_to_pjsip.py | 44 +++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py index eb3aab3b857..533e4baecb6 100755 --- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py +++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py @@ -77,6 +77,46 @@ def _merge_value(k, v, s, r, n): section_to if section_to else section, pjsip, nmapped, type) +def merge_codec_value(key=None, val=None, section=None, pjsip=None, + nmapped=None, type='endpoint', section_to=None, + key_to=None): + """Merge values from allow/deny with those from the default. Special treatment for all""" + def _merge_codec_value(k, v, s, r, n): + merge_codec_value(key if key else k, v, s, r, n, type, section_to, key_to) + + # if no value or section return the merge_codec_value + # function with the enclosed key and type + if not val and not section: + return _merge_codec_value + + if key == 'allow': + try: + disallow = sip.get(section, 'disallow')[0] + if disallow == 'all': + #don't inherit + for i in sip.get(section, 'allow'): + set_value(key, i, section, pjsip, nmapped, type) + else: + merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to) + except LookupError: + print "lookup error" + merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to) + return + elif key == 'disallow': + try: + allow = sip.get(section, 'allow')[0] + if allow == 'all': + #don't inherit + for i in sip.get(section, 'disallow'): + set_value(key, i, section, pjsip, nmapped, type) + else: + merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to) + except LookupError: + merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to) + return + else: + merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to) + def non_mapped(nmapped): """Write non-mapped sip.conf values to the non-mapped object""" @@ -404,8 +444,8 @@ def from_dtlsenable(key, val, section, pjsip, nmapped): ########################################################################### ['context', set_value], ['dtmfmode', set_dtmfmode], - ['disallow', merge_value], - ['allow', merge_value], + ['disallow', merge_codec_value], + ['allow', merge_codec_value], ['nat', from_nat], # rtp_symmetric, force_rport, # rewrite_contact ['rtptimeout', set_value('rtp_timeout')], From fe1120cf8891ddbd59bc2a6924714921d3868575 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 2 Oct 2017 17:42:48 -0500 Subject: [PATCH 1565/1578] cdr.c: Add container to key off of Party B channel names. The CDR performance gets worse the further it gets behind in processing stasis messages. One of the reasons is because of a n*m loop used when processing Party B information. * Added a new CDR container that is keyed to Party B so we don't need such a large loop when processing Party B information. NOTE: To reduce the size of the patch I deferred to another patch the renaming of the Party A active_cdrs_by_channel container to active_cdrs_master and renaming the container's hash and cmp functions appropriately. ASTERISK-27335 Change-Id: I0bf66e8868f8adaa4b5dcf9e682e34951c350249 --- main/cdr.c | 415 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 291 insertions(+), 124 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index def3871bc0f..2037e8364a3 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -351,6 +351,9 @@ static ast_cond_t cdr_pending_cond; /*! \brief A container of the active CDRs indexed by Party A channel id */ static struct ao2_container *active_cdrs_by_channel; +/*! \brief A container of all active CDRs indexed by Party B channel name */ +static struct ao2_container *active_cdrs_all; + /*! \brief Message router for stasis messages regarding channel state */ static struct stasis_message_router *stasis_router; @@ -713,6 +716,7 @@ struct cdr_object { AST_STRING_FIELD(data); /*!< The data for the last accepted application party A was in */ AST_STRING_FIELD(context); /*!< The accepted context for Party A */ AST_STRING_FIELD(exten); /*!< The accepted extension for Party A */ + AST_STRING_FIELD(party_b_name); /*!< Party B channel name. Cached here as it is the all CDRs container key */ ); struct cdr_object *next; /*!< The next CDR object in the chain */ struct cdr_object *last; /*!< The last CDR object in the chain */ @@ -848,6 +852,110 @@ static int cdr_object_channel_cmp_fn(void *obj, void *arg, int flags) return cmp ? 0 : CMP_MATCH; } +/*! + * \internal + * \brief Hash function for all CDR container indexed by Party B channel name. + */ +static int cdr_all_hash_fn(const void *obj, const int flags) +{ + const struct cdr_object *cdr; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + break; + case OBJ_SEARCH_OBJECT: + cdr = obj; + key = cdr->party_b_name; + break; + default: + ast_assert(0); + return 0; + } + return ast_str_case_hash(key); +} + +/*! + * \internal + * \brief Comparison function for all CDR container indexed by Party B channel name. + */ +static int cdr_all_cmp_fn(void *obj, void *arg, int flags) +{ + struct cdr_object *left = obj; + struct cdr_object *right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = right->party_b_name; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcasecmp(left->party_b_name, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + /* + * We could also use a partial key struct containing a length + * so strlen() does not get called for every comparison instead. + */ + cmp = strncasecmp(left->party_b_name, right_key, strlen(right_key)); + break; + default: + /* Sort can only work on something with a full or partial key. */ + ast_assert(0); + cmp = 0; + break; + } + return cmp ? 0 : CMP_MATCH; +} + +/*! + * \internal + * \brief Relink the CDR because Party B's snapshot changed. + * \since 13.19.0 + * + * \return Nothing + */ +static void cdr_all_relink(struct cdr_object *cdr) +{ + ao2_lock(active_cdrs_all); + if (cdr->party_b.snapshot) { + if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->name)) { + ao2_unlink_flags(active_cdrs_all, cdr, OBJ_NOLOCK); + ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->name); + ao2_link_flags(active_cdrs_all, cdr, OBJ_NOLOCK); + } + } else { + ao2_unlink_flags(active_cdrs_all, cdr, OBJ_NOLOCK); + ast_string_field_set(cdr, party_b_name, ""); + } + ao2_unlock(active_cdrs_all); +} + +/*! + * \internal + * \brief Unlink the master CDR and chained records from the active_cdrs_all container. + * \since 13.19.0 + * + * \return Nothing + */ +static void cdr_all_unlink(struct cdr_object *cdr) +{ + struct cdr_object *cur; + struct cdr_object *next; + + ast_assert(cdr->is_root); + + ao2_lock(active_cdrs_all); + for (cur = cdr->next; cur; cur = next) { + next = cur->next; + ao2_unlink_flags(active_cdrs_all, cur, OBJ_NOLOCK); + ast_string_field_set(cur, party_b_name, ""); + } + ao2_unlock(active_cdrs_all); +} + /*! * \brief \ref cdr_object Destructor */ @@ -1509,6 +1617,7 @@ static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_ch CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr, cdr->party_a.snapshot->name); cdr_object_swap_snapshot(&cdr->party_b, peer); + cdr_all_relink(cdr); CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr, cdr->party_b.snapshot->name); @@ -1556,6 +1665,7 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr, CDR_DEBUG("%p - Party A %s has new Party B %s\n", cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name); cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a); + cdr_all_relink(cdr); if (!cand_cdr->party_b.snapshot) { /* We just stole them - finalize their CDR. Note that this won't * transition their state, it just sets the end time and the @@ -1576,6 +1686,7 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr, CDR_DEBUG("%p - Party A %s has new Party B %s\n", cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name); cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b); + cdr_all_relink(cdr); return 0; } @@ -1728,8 +1839,6 @@ static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channe static enum process_bridge_enter_results dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel) { - struct ao2_iterator it_cdrs; - char *channel_id; int success = 0; ast_string_field_set(cdr, bridge, bridge->uniqueid); @@ -1741,50 +1850,51 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct return BRIDGE_ENTER_ONLY_PARTY; } - for (it_cdrs = ao2_iterator_init(bridge->channels, 0); - !success && (channel_id = ao2_iterator_next(&it_cdrs)); - ao2_ref(channel_id, -1)) { - struct cdr_object *cand_cdr_master; - struct cdr_object *cand_cdr; + /* If we don't have a Party B (originated channel), skip it */ + if (cdr->party_b.snapshot) { + struct ao2_iterator it_cdrs; + char *channel_id; - cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); - if (!cand_cdr_master) { - continue; - } + for (it_cdrs = ao2_iterator_init(bridge->channels, 0); + !success && (channel_id = ao2_iterator_next(&it_cdrs)); + ao2_ref(channel_id, -1)) { + struct cdr_object *cand_cdr_master; + struct cdr_object *cand_cdr; - ao2_lock(cand_cdr_master); - for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) { - /* Skip any records that are not in a bridge or in this bridge. - * I'm not sure how that would happen, but it pays to be careful. */ - if (cand_cdr->fn_table != &bridge_state_fn_table || - strcmp(cdr->bridge, cand_cdr->bridge)) { + cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); + if (!cand_cdr_master) { continue; } - /* If we don't have a Party B (originated channel), skip it */ - if (!cdr->party_b.snapshot) { - continue; - } + ao2_lock(cand_cdr_master); + for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) { + /* Skip any records that are not in a bridge or in this bridge. + * I'm not sure how that would happen, but it pays to be careful. */ + if (cand_cdr->fn_table != &bridge_state_fn_table + || strcmp(cdr->bridge, cand_cdr->bridge)) { + continue; + } - /* Skip any records that aren't our Party B */ - if (strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) { - continue; - } - cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a); - /* If they have a Party B, they joined up with someone else as their - * Party A. Don't finalize them as they're active. Otherwise, we - * have stolen them so they need to be finalized. - */ - if (!cand_cdr->party_b.snapshot) { - cdr_object_finalize(cand_cdr); + /* Skip any records that aren't our Party B */ + if (strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) { + continue; + } + cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a); + /* If they have a Party B, they joined up with someone else as their + * Party A. Don't finalize them as they're active. Otherwise, we + * have stolen them so they need to be finalized. + */ + if (!cand_cdr->party_b.snapshot) { + cdr_object_finalize(cand_cdr); + } + success = 1; + break; } - success = 1; - break; + ao2_unlock(cand_cdr_master); + ao2_cleanup(cand_cdr_master); } - ao2_unlock(cand_cdr_master); - ao2_cleanup(cand_cdr_master); + ao2_iterator_destroy(&it_cdrs); } - ao2_iterator_destroy(&it_cdrs); /* We always transition state, even if we didn't get a peer */ cdr_object_transition_state(cdr, &bridge_state_fn_table); @@ -2032,38 +2142,54 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str ao2_cleanup(cdr); } -static int cdr_object_finalize_party_b(void *obj, void *arg, int flags) +static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int flags) { struct cdr_object *cdr = obj; - struct ast_channel_snapshot *party_b = arg; - struct cdr_object *it_cdr; - for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (it_cdr->party_b.snapshot - && !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) { - /* Don't transition to the finalized state - let the Party A do - * that when its ready - */ - cdr_object_finalize(it_cdr); - } + if (!strcasecmp(cdr->party_b_name, arg)) { +#ifdef AST_DEVMODE + struct ast_channel_snapshot *party_b = data; + + /* + * For sanity's sake we also assert the party_b snapshot + * is consistent with the key. + */ + ast_assert(cdr->party_b.snapshot + && !strcasecmp(cdr->party_b.snapshot->name, party_b->name)); +#endif + + /* Don't transition to the finalized state - let the Party A do + * that when its ready + */ + cdr_object_finalize(cdr); } return 0; } -static int cdr_object_update_party_b(void *obj, void *arg, int flags) +static int cdr_object_update_party_b(void *obj, void *arg, void *data, int flags) { struct cdr_object *cdr = obj; - struct ast_channel_snapshot *party_b = arg; - struct cdr_object *it_cdr; - for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (!it_cdr->fn_table->process_party_b) { - continue; - } - if (it_cdr->party_b.snapshot - && !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) { - it_cdr->fn_table->process_party_b(it_cdr, party_b); + if (cdr->fn_table->process_party_b + && !strcasecmp(cdr->party_b_name, arg)) { + struct ast_channel_snapshot *party_b = data; + + /* + * For sanity's sake we also check the party_b snapshot + * for consistency with the key. The callback needs and + * asserts the snapshot to be this way. + */ + if (!cdr->party_b.snapshot + || strcasecmp(cdr->party_b.snapshot->name, party_b->name)) { + ast_log(LOG_NOTICE, + "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n", + cdr->linkedid, + cdr->party_a.snapshot->name, + cdr->party_b_name); + return 0; } + + cdr->fn_table->process_party_b(cdr, party_b); } return 0; } @@ -2137,44 +2263,46 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription name = new_snapshot ? new_snapshot->name : old_snapshot->name; ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name); ast_assert(0); - } else { - ao2_lock(cdr); - if (new_snapshot) { - int all_reject = 1; + } else if (new_snapshot) { + int all_reject = 1; - for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (!it_cdr->fn_table->process_party_a) { - continue; - } - all_reject &= it_cdr->fn_table->process_party_a(it_cdr, new_snapshot); + ao2_lock(cdr); + for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { + if (!it_cdr->fn_table->process_party_a) { + continue; } - if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) { - /* We're not hung up and we have a new snapshot - we need a new CDR */ - struct cdr_object *new_cdr; + all_reject &= it_cdr->fn_table->process_party_a(it_cdr, new_snapshot); + } + if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) { + /* We're not hung up and we have a new snapshot - we need a new CDR */ + struct cdr_object *new_cdr; - new_cdr = cdr_object_create_and_append(cdr); - if (new_cdr) { - new_cdr->fn_table->process_party_a(new_cdr, new_snapshot); - } - } - } else { - CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name); - for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - cdr_object_finalize(it_cdr); + new_cdr = cdr_object_create_and_append(cdr); + if (new_cdr) { + new_cdr->fn_table->process_party_a(new_cdr, new_snapshot); } - cdr_object_dispatch(cdr); - ao2_unlink(active_cdrs_by_channel, cdr); } ao2_unlock(cdr); + } else { + ao2_lock(cdr); + CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name); + for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { + cdr_object_finalize(it_cdr); + } + cdr_object_dispatch(cdr); + ao2_unlock(cdr); + + cdr_all_unlink(cdr); + ao2_unlink(active_cdrs_by_channel, cdr); } /* Handle Party B */ if (new_snapshot) { - ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_update_party_b, - new_snapshot); + ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY, + cdr_object_update_party_b, (char *) new_snapshot->name, new_snapshot); } else { - ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_finalize_party_b, - old_snapshot); + ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY, + cdr_object_finalize_party_b, (char *) old_snapshot->name, old_snapshot); } ao2_cleanup(cdr); @@ -2186,29 +2314,25 @@ struct bridge_leave_data { }; /*! \brief Callback used to notify CDRs of a Party B leaving the bridge */ -static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, int flags) +static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, void *data, int flags) { struct cdr_object *cdr = obj; - struct bridge_leave_data *leave_data = arg; - struct cdr_object *it_cdr; + struct bridge_leave_data *leave_data = data; + + if (cdr->fn_table == &bridge_state_fn_table + && !strcmp(cdr->bridge, leave_data->bridge->uniqueid) + && !strcasecmp(cdr->party_b_name, arg)) { + /* + * For sanity's sake we also assert the party_b snapshot + * is consistent with the key. + */ + ast_assert(cdr->party_b.snapshot + && !strcasecmp(cdr->party_b.snapshot->name, leave_data->channel->name)); - if (strcmp(cdr->bridge, leave_data->bridge->uniqueid)) { - return 0; - } - for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (it_cdr->fn_table != &bridge_state_fn_table) { - continue; - } - if (!it_cdr->party_b.snapshot) { - continue; - } - if (strcasecmp(it_cdr->party_b.snapshot->name, leave_data->channel->name)) { - continue; - } /* It is our Party B, in our bridge. Set the end time and let the handler * transition our CDR appropriately when we leave the bridge. */ - cdr_object_finalize(it_cdr); + cdr_object_finalize(cdr); } return 0; } @@ -2284,8 +2408,8 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * /* Party B */ if (left_bridge && strcmp(bridge->subclass, "parking")) { - ao2_callback(active_cdrs_by_channel, OBJ_NODATA, - cdr_object_party_b_left_bridge_cb, + ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY, + cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->name, &leave_data); } @@ -2308,6 +2432,7 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, return; } cdr_object_snapshot_copy(&new_cdr->party_b, party_b); + cdr_all_relink(new_cdr); cdr_object_check_party_a_answer(new_cdr); ast_string_field_set(new_cdr, bridge, cdr->bridge); cdr_object_transition_state(new_cdr, &bridge_state_fn_table); @@ -2366,6 +2491,7 @@ static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *b cand_cdr, cand_cdr->party_a.snapshot->name, cdr->party_a.snapshot->name); cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a); + cdr_all_relink(cand_cdr); /* It's possible that this joined at one point and was never chosen * as party A. Clear their end time, as it would be set in such a * case. @@ -3262,21 +3388,24 @@ struct party_b_userfield_update { }; /*! \brief Callback used to update the userfield on Party B on all CDRs */ -static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flags) +static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *data, int flags) { struct cdr_object *cdr = obj; - struct party_b_userfield_update *info = arg; - struct cdr_object *it_cdr; - for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) { - continue; - } - if (it_cdr->party_b.snapshot - && !strcasecmp(it_cdr->party_b.snapshot->name, info->channel_name)) { - strcpy(it_cdr->party_b.userfield, info->userfield); - } + if ((cdr->fn_table != &finalized_state_fn_table || !cdr->next) + && !strcasecmp(cdr->party_b_name, arg)) { + struct party_b_userfield_update *info = data; + + /* + * For sanity's sake we also assert the party_b snapshot + * is consistent with the key. + */ + ast_assert(cdr->party_b.snapshot + && !strcasecmp(cdr->party_b.snapshot->name, info->channel_name)); + + strcpy(cdr->party_b.userfield, info->userfield); } + return 0; } @@ -3284,8 +3413,8 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) { struct cdr_object *cdr; struct party_b_userfield_update party_b_info = { - .channel_name = channel_name, - .userfield = userfield, + .channel_name = channel_name, + .userfield = userfield, }; struct cdr_object *it_cdr; @@ -3303,9 +3432,9 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) } /* Handle Party B */ - ao2_callback(active_cdrs_by_channel, OBJ_NODATA, - cdr_object_update_party_b_userfield_cb, - &party_b_info); + ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY, + cdr_object_update_party_b_userfield_cb, (char *) party_b_info.channel_name, + &party_b_info); ao2_cleanup(cdr); } @@ -3485,6 +3614,7 @@ int ast_cdr_fork(const char *channel_name, struct ast_flags *options) if (cdr_obj->party_b.snapshot) { new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot; ao2_ref(new_cdr->party_b.snapshot, +1); + cdr_all_relink(new_cdr); strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield); new_cdr->party_b.flags = cdr_obj->party_b.flags; if (ast_test_flag(options, AST_CDR_FLAG_KEEP_VARS)) { @@ -4074,7 +4204,9 @@ static int cdr_object_dispatch_all_cb(void *obj, void *arg, int flags) cdr_object_dispatch(cdr); ao2_unlock(cdr); - return 0; + cdr_all_unlink(cdr); + + return CMP_MATCH; } static void finalize_batch_mode(void) @@ -4200,8 +4332,8 @@ static void cdr_engine_shutdown(void) STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type); - ao2_callback(active_cdrs_by_channel, OBJ_NODATA, cdr_object_dispatch_all_cb, - NULL); + ao2_callback(active_cdrs_by_channel, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, + cdr_object_dispatch_all_cb, NULL); finalize_batch_mode(); ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sched_context_destroy(sched); @@ -4213,8 +4345,12 @@ static void cdr_engine_shutdown(void) ao2_global_obj_release(module_configs); ao2_container_unregister("cdrs_by_channel"); - ao2_ref(active_cdrs_by_channel, -1); + ao2_cleanup(active_cdrs_by_channel); active_cdrs_by_channel = NULL; + + ao2_container_unregister("cdrs_all"); + ao2_cleanup(active_cdrs_all); + active_cdrs_all = NULL; } static void cdr_enable_batch_mode(struct ast_cdr_config *config) @@ -4261,6 +4397,30 @@ static void cdr_container_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt) } } +/*! + * \internal + * \brief Print all CDR container object. + * \since 13.19.0 + * + * \param v_obj A pointer to the object we want printed. + * \param where User data needed by prnt to determine where to put output. + * \param prnt Print output callback function to use. + * + * \return Nothing + */ +static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt) +{ + struct cdr_object *cdr = v_obj; + + if (!cdr) { + return; + } + prnt(where, "Party A: %s; Party B: %s; Bridge %s", + cdr->party_a.snapshot->name, + cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "", + cdr->bridge); +} + /*! * \brief Checks if CDRs are enabled and enables/disables the necessary options */ @@ -4327,6 +4487,13 @@ int ast_cdr_engine_init(void) } ao2_container_register("cdrs_by_channel", active_cdrs_by_channel, cdr_container_print_fn); + active_cdrs_all = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, + NUM_CDR_BUCKETS, cdr_all_hash_fn, NULL, cdr_all_cmp_fn); + if (!active_cdrs_all) { + return -1; + } + ao2_container_register("cdrs_all", active_cdrs_all, cdr_all_print_fn); + sched = ast_sched_context_create(); if (!sched) { ast_log(LOG_ERROR, "Unable to create schedule context.\n"); From 73164d0d7f2147ae37c930504d5bec4e6fdf8569 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 6 Oct 2017 15:55:26 -0500 Subject: [PATCH 1566/1578] cdr.c: Rename the Party A CDR container. * Rename the Party A CDR container from active_cdrs_by_channel to active_cdrs_master. * Renamed the support functions associated with active_cdrs_master appropriately. ASTERISK-27335 Change-Id: I6104bb3edc3a0b7243ce502e45e8832b0cff14f7 --- main/cdr.c | 83 +++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/main/cdr.c b/main/cdr.c index 2037e8364a3..fdf76454014 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -348,8 +348,8 @@ AST_MUTEX_DEFINE_STATIC(cdr_batch_lock); AST_MUTEX_DEFINE_STATIC(cdr_pending_lock); static ast_cond_t cdr_pending_cond; -/*! \brief A container of the active CDRs indexed by Party A channel id */ -static struct ao2_container *active_cdrs_by_channel; +/*! \brief A container of the active master CDRs indexed by Party A channel uniqueid */ +static struct ao2_container *active_cdrs_master; /*! \brief A container of all active CDRs indexed by Party B channel name */ static struct ao2_container *active_cdrs_all; @@ -709,7 +709,7 @@ struct cdr_object { struct ast_flags flags; /*!< Flags on the CDR */ AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(linkedid); /*!< Linked ID. Cached here as it may change out from party A, which must be immutable */ - AST_STRING_FIELD(uniqueid); /*!< Unique id of party A. Cached here as it is the primary key of this CDR */ + AST_STRING_FIELD(uniqueid); /*!< Unique id of party A. Cached here as it is the master CDR container key */ AST_STRING_FIELD(name); /*!< Channel name of party A. Cached here as the party A address may change */ AST_STRING_FIELD(bridge); /*!< The bridge the party A happens to be in. */ AST_STRING_FIELD(appl); /*!< The last accepted application party A was in */ @@ -797,9 +797,12 @@ static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_objec cdr->fn_table->init_function(cdr); } } -/*! \internal - * \brief Hash function for containers of CDRs indexing by Party A uniqueid */ -static int cdr_object_channel_hash_fn(const void *obj, const int flags) + +/*! + * \internal + * \brief Hash function for master CDR container indexed by Party A uniqueid. + */ +static int cdr_master_hash_fn(const void *obj, const int flags) { const struct cdr_object *cdr; const char *key; @@ -819,10 +822,11 @@ static int cdr_object_channel_hash_fn(const void *obj, const int flags) return ast_str_case_hash(key); } -/*! \internal - * \brief Comparison function for containers of CDRs indexing by Party A uniqueid +/*! + * \internal + * \brief Comparison function for master CDR container indexed by Party A uniqueid. */ -static int cdr_object_channel_cmp_fn(void *obj, void *arg, int flags) +static int cdr_master_cmp_fn(void *obj, void *arg, int flags) { struct cdr_object *left = obj; struct cdr_object *right = arg; @@ -1713,7 +1717,7 @@ static enum process_bridge_enter_results single_state_process_bridge_enter(struc struct cdr_object *cand_cdr_master; struct cdr_object *cand_cdr; - cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); + cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY); if (!cand_cdr_master) { continue; } @@ -1861,7 +1865,7 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct struct cdr_object *cand_cdr_master; struct cdr_object *cand_cdr; - cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); + cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY); if (!cand_cdr_master) { continue; } @@ -2091,9 +2095,9 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str /* Figure out who is running this show */ if (caller) { - cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_SEARCH_KEY); + cdr = ao2_find(active_cdrs_master, caller->uniqueid, OBJ_SEARCH_KEY); } else { - cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_SEARCH_KEY); + cdr = ao2_find(active_cdrs_master, peer->uniqueid, OBJ_SEARCH_KEY); } if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name); @@ -2248,12 +2252,12 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription return; } cdr->is_root = 1; - ao2_link(active_cdrs_by_channel, cdr); + ao2_link(active_cdrs_master, cdr); } else { const char *uniqueid; uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid; - cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_SEARCH_KEY); + cdr = ao2_find(active_cdrs_master, uniqueid, OBJ_SEARCH_KEY); } /* Handle Party A */ @@ -2293,7 +2297,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription ao2_unlock(cdr); cdr_all_unlink(cdr); - ao2_unlink(active_cdrs_by_channel, cdr); + ao2_unlink(active_cdrs_master, cdr); } /* Handle Party B */ @@ -2383,7 +2387,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription * (unsigned int)stasis_message_timestamp(message)->tv_sec, (unsigned int)stasis_message_timestamp(message)->tv_usec); - cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); + cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name); ast_assert(0); @@ -2518,7 +2522,7 @@ static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_sna while ((channel_id = ao2_iterator_next(&it_channels))) { struct cdr_object *cand_cdr; - cand_cdr = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY); + cand_cdr = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY); if (cand_cdr) { bridge_candidate_process(cdr, cand_cdr); ao2_ref(cand_cdr, -1); @@ -2670,7 +2674,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription * (unsigned int)stasis_message_timestamp(message)->tv_sec, (unsigned int)stasis_message_timestamp(message)->tv_usec); - cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); + cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name); ast_assert(0); @@ -2720,7 +2724,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s (unsigned int)stasis_message_timestamp(message)->tv_sec, (unsigned int)stasis_message_timestamp(message)->tv_usec); - cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY); + cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY); if (!cdr) { ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name); ast_assert(0); @@ -2903,7 +2907,7 @@ static int ast_cdr_generic_unregister(struct be_list *generic_list, const char * return 0; } - active_count = ao2_container_count(active_cdrs_by_channel); + active_count = ao2_container_count(active_cdrs_master); if (!match->suspended && active_count != 0) { AST_RWLIST_UNLOCK(generic_list); @@ -3126,7 +3130,7 @@ int ast_cdr_setvar(const char *channel_name, const char *name, const char *value } } - it_cdrs = ao2_callback(active_cdrs_by_channel, OBJ_MULTIPLE, cdr_object_select_all_by_name_cb, arg); + it_cdrs = ao2_callback(active_cdrs_master, OBJ_MULTIPLE, cdr_object_select_all_by_name_cb, arg); if (!it_cdrs) { ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name); return -1; @@ -3254,7 +3258,7 @@ static struct cdr_object *cdr_object_get_by_name(const char *name) } param = ast_strdupa(name); - return ao2_callback(active_cdrs_by_channel, 0, cdr_object_get_by_name_cb, param); + return ao2_callback(active_cdrs_master, 0, cdr_object_get_by_name_cb, param); } int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length) @@ -3907,7 +3911,7 @@ static char *cli_complete_show(struct ast_cli_args *a) struct ao2_iterator it_cdrs; struct cdr_object *cdr; - it_cdrs = ao2_iterator_init(active_cdrs_by_channel, 0); + it_cdrs = ao2_iterator_init(active_cdrs_master, 0); while ((cdr = ao2_iterator_next(&it_cdrs))) { if (!strncasecmp(a->word, cdr->party_a.snapshot->name, wordlen) && (++which > a->n)) { @@ -3939,7 +3943,7 @@ static void cli_show_channels(struct ast_cli_args *a) ast_cli(a->fd, "--------------------------------------------------\n"); ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration"); - it_cdrs = ao2_iterator_init(active_cdrs_by_channel, 0); + it_cdrs = ao2_iterator_init(active_cdrs_master, 0); for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) { struct cdr_object *it_cdr; struct timeval start_time = { 0, }; @@ -4332,7 +4336,7 @@ static void cdr_engine_shutdown(void) STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type); - ao2_callback(active_cdrs_by_channel, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, + ao2_callback(active_cdrs_master, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, cdr_object_dispatch_all_cb, NULL); finalize_batch_mode(); ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); @@ -4344,9 +4348,9 @@ static void cdr_engine_shutdown(void) aco_info_destroy(&cfg_info); ao2_global_obj_release(module_configs); - ao2_container_unregister("cdrs_by_channel"); - ao2_cleanup(active_cdrs_by_channel); - active_cdrs_by_channel = NULL; + ao2_container_unregister("cdrs_master"); + ao2_cleanup(active_cdrs_master); + active_cdrs_master = NULL; ao2_container_unregister("cdrs_all"); ao2_cleanup(active_cdrs_all); @@ -4375,25 +4379,28 @@ static void cdr_enable_batch_mode(struct ast_cdr_config *config) /*! * \internal - * \brief Print channel object key (name). + * \brief Print master CDR container object. * \since 12.0.0 * - * \param v_obj A pointer to the object we want the key printed. + * \param v_obj A pointer to the object we want printed. * \param where User data needed by prnt to determine where to put output. * \param prnt Print output callback function to use. * * \return Nothing */ -static void cdr_container_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt) +static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt) { struct cdr_object *cdr = v_obj; struct cdr_object *it_cdr; + if (!cdr) { return; } for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { - prnt(where, "Party A: %s; Party B: %s; Bridge %s\n", it_cdr->party_a.snapshot->name, it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "", - it_cdr->bridge); + prnt(where, "Party A: %s; Party B: %s; Bridge %s\n", + it_cdr->party_a.snapshot->name, + it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "", + it_cdr->bridge); } } @@ -4480,12 +4487,12 @@ int ast_cdr_engine_init(void) stasis_message_router_add(stasis_router, ast_parked_call_type(), handle_parked_call_message, NULL); stasis_message_router_add(stasis_router, cdr_sync_message_type(), handle_cdr_sync_message, NULL); - active_cdrs_by_channel = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, - NUM_CDR_BUCKETS, cdr_object_channel_hash_fn, NULL, cdr_object_channel_cmp_fn); - if (!active_cdrs_by_channel) { + active_cdrs_master = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, + NUM_CDR_BUCKETS, cdr_master_hash_fn, NULL, cdr_master_cmp_fn); + if (!active_cdrs_master) { return -1; } - ao2_container_register("cdrs_by_channel", active_cdrs_by_channel, cdr_container_print_fn); + ao2_container_register("cdrs_master", active_cdrs_master, cdr_master_print_fn); active_cdrs_all = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NUM_CDR_BUCKETS, cdr_all_hash_fn, NULL, cdr_all_cmp_fn); From 5d8c517960d4d807f4b242a775c232bbcf18c044 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Sat, 14 Oct 2017 19:41:37 +0000 Subject: [PATCH 1567/1578] bridge_softmix: Reduce topology cloning and improve renegotiation. As channels join and leave an SFU the bridge_softmix module needs to renegotiate to add and remove their streams from the other participants. Previously this was done by constructing the ideal stream topology every time but in the case of leave this was incomplete. This change makes it so bridge_softmix keeps an ideal stream topology for each channel and uses it when making changes. This ensures that when we request a renegotiation we are always certain that we are aiming for the best stream topology possible. In the case of a channel leaving this ensures that we try to have an existing participant fill their place if a participant has a fixed limit on the maximum number of video streams they allow. ASTERISK-27354 Change-Id: I58070f421ddeadd2844a33b869b052630cf2e514 --- bridges/bridge_softmix.c | 141 +++++------------- .../include/bridge_softmix_internal.h | 2 + 2 files changed, 38 insertions(+), 105 deletions(-) diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 5e0a4856ff5..9197df6fb5f 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -573,27 +573,24 @@ static int append_all_streams(struct ast_stream_topology *dest, */ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast_bridge_channels_list *participants) { - struct ast_stream_topology *joiner_topology = NULL; struct ast_stream_topology *joiner_video = NULL; - struct ast_stream_topology *existing_video = NULL; struct ast_bridge_channel *participant; int res; + struct softmix_channel *sc; joiner_video = ast_stream_topology_alloc(); if (!joiner_video) { return; } + sc = joiner->tech_pvt; + ast_channel_lock(joiner->chan); res = append_source_streams(joiner_video, ast_channel_name(joiner->chan), ast_channel_get_stream_topology(joiner->chan)); + sc->topology = ast_stream_topology_clone(ast_channel_get_stream_topology(joiner->chan)); ast_channel_unlock(joiner->chan); - if (res) { - goto cleanup; - } - - existing_video = ast_stream_topology_alloc(); - if (!existing_video) { + if (res || !sc->topology) { goto cleanup; } @@ -602,7 +599,7 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast continue; } ast_channel_lock(participant->chan); - res = append_source_streams(existing_video, ast_channel_name(participant->chan), + res = append_source_streams(sc->topology, ast_channel_name(participant->chan), ast_channel_get_stream_topology(participant->chan)); ast_channel_unlock(participant->chan); if (res) { @@ -610,41 +607,22 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast } } - ast_channel_lock(joiner->chan); - joiner_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(joiner->chan)); - ast_channel_unlock(joiner->chan); - if (!joiner_topology) { - goto cleanup; - } - if (append_all_streams(joiner_topology, existing_video)) { - goto cleanup; - } - ast_channel_request_stream_topology_change(joiner->chan, joiner_topology, NULL); + ast_channel_request_stream_topology_change(joiner->chan, sc->topology, NULL); AST_LIST_TRAVERSE(participants, participant, entry) { - struct ast_stream_topology *participant_topology; - if (participant == joiner) { continue; } - ast_channel_lock(participant->chan); - participant_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(participant->chan)); - ast_channel_unlock(participant->chan); - if (!participant_topology) { - goto cleanup; - } - if (append_all_streams(participant_topology, joiner_video)) { - ast_stream_topology_free(participant_topology); + + sc = participant->tech_pvt; + if (append_all_streams(sc->topology, joiner_video)) { goto cleanup; } - ast_channel_request_stream_topology_change(participant->chan, participant_topology, NULL); - ast_stream_topology_free(participant_topology); + ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL); } cleanup: ast_stream_topology_free(joiner_video); - ast_stream_topology_free(existing_video); - ast_stream_topology_free(joiner_topology); } /*! \brief Function called when a channel is joined into the bridge */ @@ -718,65 +696,36 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan return 0; } -static int remove_destination_streams(struct ast_stream_topology *dest, - const char *channel_name, - const struct ast_stream_topology *source) +static void remove_destination_streams(struct ast_stream_topology *topology, + const char *channel_name) { int i; - for (i = 0; i < ast_stream_topology_get_count(source); ++i) { + for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { struct ast_stream *stream; - struct ast_stream *stream_clone; - stream = ast_stream_topology_get_stream(source, i); - - stream_clone = ast_stream_clone(stream, NULL); - if (!stream_clone) { - continue; - } + stream = ast_stream_topology_get_stream(topology, i); if (is_video_dest(stream, channel_name, NULL)) { - ast_stream_set_state(stream_clone, AST_STREAM_STATE_REMOVED); - } - - if (ast_stream_topology_append_stream(dest, stream_clone) < 0) { - ast_stream_free(stream_clone); + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); } } - - return 0; } static int sfu_topologies_on_leave(struct ast_bridge_channel *leaver, struct ast_bridge_channels_list *participants) { - struct ast_stream_topology *leaver_topology; struct ast_bridge_channel *participant; - - leaver_topology = ast_stream_topology_alloc(); - if (!leaver_topology) { - return -1; - } + struct softmix_channel *sc; AST_LIST_TRAVERSE(participants, participant, entry) { - struct ast_stream_topology *participant_topology; - - participant_topology = ast_stream_topology_alloc(); - if (!participant_topology) { - continue; - } - - ast_channel_lock(participant->chan); - remove_destination_streams(participant_topology, ast_channel_name(leaver->chan), ast_channel_get_stream_topology(participant->chan)); - ast_channel_unlock(participant->chan); - ast_channel_request_stream_topology_change(participant->chan, participant_topology, NULL); - ast_stream_topology_free(participant_topology); + sc = participant->tech_pvt; + remove_destination_streams(sc->topology, ast_channel_name(leaver->chan)); + ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL); } - ast_channel_lock(leaver->chan); - remove_destination_streams(leaver_topology, "", ast_channel_get_stream_topology(leaver->chan)); - ast_channel_unlock(leaver->chan); - ast_channel_request_stream_topology_change(leaver->chan, leaver_topology, NULL); - ast_stream_topology_free(leaver_topology); + sc = leaver->tech_pvt; + remove_destination_streams(sc->topology, ""); + ast_channel_request_stream_topology_change(leaver->chan, sc->topology, NULL); return 0; } @@ -806,6 +755,8 @@ static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_ch bridge_channel->tech_pvt = NULL; + ast_stream_topology_free(sc->topology); + /* Drop mutex lock */ ast_mutex_destroy(&sc->lock); @@ -1055,30 +1006,23 @@ static void sfu_topologies_on_source_change(struct ast_bridge_channel *source, s AST_LIST_TRAVERSE(participants, participant, entry) { struct ast_stream_topology *original_topology; - struct ast_stream_topology *participant_topology; + struct softmix_channel *sc; if (participant == source) { continue; } - ast_channel_lock(participant->chan); - original_topology = ast_stream_topology_clone(ast_channel_get_stream_topology(participant->chan)); - ast_channel_unlock(participant->chan); - if (!original_topology) { - goto cleanup; - } + sc = participant->tech_pvt; - participant_topology = ast_stream_topology_clone(original_topology); - if (!participant_topology) { - ast_stream_topology_free(original_topology); + original_topology = ast_stream_topology_clone(sc->topology); + if (!original_topology) { goto cleanup; } /* We add all the source streams back in, if any removed streams are already present they will * get used first followed by appending new ones. */ - if (append_all_streams(participant_topology, source_video)) { - ast_stream_topology_free(participant_topology); + if (append_all_streams(sc->topology, source_video)) { ast_stream_topology_free(original_topology); goto cleanup; } @@ -1086,14 +1030,12 @@ static void sfu_topologies_on_source_change(struct ast_bridge_channel *source, s /* And the original existing streams get marked as removed. This causes the remote side to see * a new stream for the source streams. */ - if (remove_all_original_streams(participant_topology, source_video, original_topology)) { - ast_stream_topology_free(participant_topology); + if (remove_all_original_streams(sc->topology, source_video, original_topology)) { ast_stream_topology_free(original_topology); goto cleanup; } - ast_channel_request_stream_topology_change(participant->chan, participant_topology, NULL); - ast_stream_topology_free(participant_topology); + ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL); ast_stream_topology_free(original_topology); } @@ -2144,7 +2086,6 @@ AST_TEST_DEFINE(sfu_remove_destination_streams) { "", 4, { 0, 1, 2, 3 }, }, }; struct ast_stream_topology *orig = NULL; - struct ast_stream_topology *result = NULL; int i; switch (cmd) { @@ -2168,20 +2109,11 @@ AST_TEST_DEFINE(sfu_remove_destination_streams) for (i = 0; i < ARRAY_LEN(removal_results); ++i) { int j; - result = ast_stream_topology_alloc(); - if (!result) { - ast_test_status_update(test, "Unable to allocate result stream topology\n"); - goto end; - } - - if (remove_destination_streams(result, removal_results[i].channel_name, orig)) { - ast_test_status_update(test, "Failure while attempting to remove video streams\n"); - goto end; - } + remove_destination_streams(orig, removal_results[i].channel_name); - if (ast_stream_topology_get_count(result) != removal_results[i].num_streams) { + if (ast_stream_topology_get_count(orig) != removal_results[i].num_streams) { ast_test_status_update(test, "Resulting topology has %d streams, when %d are expected\n", - ast_stream_topology_get_count(result), removal_results[i].num_streams); + ast_stream_topology_get_count(orig), removal_results[i].num_streams); goto end; } @@ -2190,7 +2122,7 @@ AST_TEST_DEFINE(sfu_remove_destination_streams) struct ast_stream *expected; int orig_index; - actual = ast_stream_topology_get_stream(result, j); + actual = ast_stream_topology_get_stream(orig, j); orig_index = removal_results[i].params_index[j]; expected = ast_stream_topology_get_stream(orig, orig_index); @@ -2221,7 +2153,6 @@ AST_TEST_DEFINE(sfu_remove_destination_streams) end: ast_stream_topology_free(orig); - ast_stream_topology_free(result); return res; } diff --git a/bridges/bridge_softmix/include/bridge_softmix_internal.h b/bridges/bridge_softmix/include/bridge_softmix_internal.h index f93e6639159..01e65aa1f8e 100644 --- a/bridges/bridge_softmix/include/bridge_softmix_internal.h +++ b/bridges/bridge_softmix/include/bridge_softmix_internal.h @@ -167,6 +167,8 @@ struct softmix_channel { short our_buf[MAX_DATALEN]; /*! Data pertaining to talker mode for video conferencing */ struct video_follow_talker_data video_talker; + /*! The ideal stream topology for the channel */ + struct ast_stream_topology *topology; }; struct softmix_bridge_data { From 95b45d1c46b35232ee0b9bdb3135b080c164c7c6 Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Wed, 18 Oct 2017 10:30:25 +0200 Subject: [PATCH 1568/1578] res_srtp: Add support for libsrtp2 with AES-GCM. Beside allowing AES-GCM again, this adds AES-192 again. ASTERISK-27356 Change-Id: Ia97a435faf26300335d9552fa676b5d17e5f7233 --- configure | 104 +++++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + res/srtp/srtp_compat.h | 12 +++++ 3 files changed, 117 insertions(+) diff --git a/configure b/configure index 59bc3b10b15..588fbfd0be8 100755 --- a/configure +++ b/configure @@ -33793,6 +33793,110 @@ fi +if test "x${PBX_SRTP_192}" != "x1" -a "${USE_SRTP_192}" != "no"; then + pbxlibdir="" + # if --with-SRTP_192=DIR has been specified, use it. + if test "x${SRTP_192_DIR}" != "x"; then + if test -d ${SRTP_192_DIR}/lib; then + pbxlibdir="-L${SRTP_192_DIR}/lib" + else + pbxlibdir="-L${SRTP_192_DIR}" + fi + fi + pbxfuncname="srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_192_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp2_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp2" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp2... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp2 ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_192_FOUND=yes +else + AST_SRTP_192_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_192_FOUND}" = "yes"; then + SRTP_192_LIB="${pbxlibdir} -lsrtp2 " + # if --with-SRTP_192=DIR has been specified, use it. + if test "x${SRTP_192_DIR}" != "x"; then + SRTP_192_INCLUDE="-I${SRTP_192_DIR}/include" + fi + SRTP_192_INCLUDE="${SRTP_192_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_192_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_192_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_192_HEADER_FOUND=1 +else + SRTP_192_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_192_HEADER_FOUND}" = "x0" ; then + SRTP_192_LIB="" + SRTP_192_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_192_LIB="" + fi + PBX_SRTP_192=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_192 1 +_ACEOF + + fi + fi +fi + + + if test "x${PBX_SRTP_GCM}" != "x1" -a "${USE_SRTP_GCM}" != "no"; then pbxlibdir="" # if --with-SRTP_GCM=DIR has been specified, use it. diff --git a/configure.ac b/configure.ac index 9f95786e113..c729b94aba2 100644 --- a/configure.ac +++ b/configure.ac @@ -2520,6 +2520,7 @@ AST_EXT_LIB_CHECK_SHARED([SRTP], [srtp2], [srtp_init], [srtp2/srtp.h], [], [], [ if test "x$PBX_SRTP" = x1; then AST_EXT_LIB_CHECK([SRTP_256], [srtp2], [srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_192], [srtp2], [srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80]) AST_EXT_LIB_CHECK([SRTP_GCM], [srtp2], [srtp_crypto_policy_set_aes_gcm_128_8_auth]) AST_EXT_LIB_CHECK([SRTP_SHUTDOWN], [srtp2], [srtp_shutdown], [srtp2/srtp.h]) diff --git a/res/srtp/srtp_compat.h b/res/srtp/srtp_compat.h index 56ffca1cc2d..dbd8ddee0f6 100644 --- a/res/srtp/srtp_compat.h +++ b/res/srtp/srtp_compat.h @@ -16,6 +16,18 @@ #define crypto_policy_set_aes_gcm_128_8_auth srtp_crypto_policy_set_aes_gcm_128_8_auth #define crypto_policy_set_aes_gcm_256_8_auth srtp_crypto_policy_set_aes_gcm_256_8_auth +#if defined(SRTP_AES_GCM_128_KEY_LEN_WSALT) +#define AES_128_GCM_KEYSIZE_WSALT SRTP_AES_GCM_128_KEY_LEN_WSALT +#else +#define AES_128_GCM_KEYSIZE_WSALT SRTP_AES_128_GCM_KEYSIZE_WSALT +#endif + +#if defined(SRTP_AES_GCM_256_KEY_LEN_WSALT) +#define AES_256_GCM_KEYSIZE_WSALT SRTP_AES_GCM_256_KEY_LEN_WSALT +#else +#define AES_256_GCM_KEYSIZE_WSALT SRTP_AES_256_GCM_KEYSIZE_WSALT +#endif + #define err_status_t srtp_err_status_t #define err_status_ok srtp_err_status_ok #define err_status_fail srtp_err_status_fail From 955a891a84203fdab9dade2049bb8268d69a2949 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 16 Oct 2017 11:53:07 -0400 Subject: [PATCH 1569/1578] app_macro deprecation. * Mark the module deprecated. * Disable the module by default. * Produce a warning the first time a macro is used. * Note deprecation related options in app_dial and app_queue. ASTERISK-27350 Change-Id: I560ea043bacdbc5534a17d97854273d52c2f1bdc --- CHANGES | 6 ++++++ UPGRADE.txt | 5 +++++ apps/app_dial.c | 4 ++++ apps/app_macro.c | 12 ++++++++++-- apps/app_queue.c | 3 +++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 63c8c6f7cec..68617a44189 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,12 @@ --- Functionality changes from Asterisk 15 to Asterisk 16 -------------------- ------------------------------------------------------------------------------ +app_macro +------------------ + * The app_macro module is now deprecated and by default it is no longer + built. Users should migrate to app_stack (Gosub). A warning is logged + the first time any Macro is used. + chan_sip ------------------ * New function SIP_HEADERS() enumerates all headers in the incoming INVITE. diff --git a/UPGRADE.txt b/UPGRADE.txt index 1fe82c04eae..39c0f8cec85 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -26,6 +26,11 @@ New in 16.0.0: +app_macro: + - The app_macro module is now deprecated and by default it is no longer + built. Users should migrate to app_stack (Gosub). A warning is logged + the first time any Macro is used. + New in 15.0.0: Build System: diff --git a/apps/app_dial.c b/apps/app_dial.c index 847a095f44a..8c51f3f1a48 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -324,6 +324,10 @@ Be aware of the limitations that macros have, specifically with regards to use of the WaitExten application. For more information, see the documentation for Macro(). + + Macros are deprecated, GoSub should be used instead, + see the U option. + From a9e9608982bcdf983848e0db83bfa08eefc14d7f Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Mon, 23 Oct 2017 13:42:37 -0400 Subject: [PATCH 1577/1578] test_config: Fix failure and segfault when config_hook is run twice. On second run the config_hook test was unexpectedly failing to load test_config.conf because it was still unmodified since the last load. This is fixed by not passing CONFIG_FLAG_FILEUNCHANGED for the initial loads, only using it when we are tested that a reload of unmodified files do not initiate the hook. ASTERISK-25960 Change-Id: Ifd679509a23ed163e5cc647490bf7df4ae3cd856 --- tests/test_config.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_config.c b/tests/test_config.c index 8675cb8906f..d74726a1a78 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -957,7 +957,8 @@ AST_TEST_DEFINE(config_hook) { enum ast_test_result_state res = AST_TEST_FAIL; enum config_hook_flags hook_flags = { 0, }; - struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; + struct ast_flags config_flags = { 0 }; + struct ast_flags reload_flags = { CONFIG_FLAG_FILEUNCHANGED }; struct ast_config *cfg; switch (cmd) { @@ -1025,7 +1026,7 @@ AST_TEST_DEFINE(config_hook) * Hook should not run */ hook_run = 0; - cfg = ast_config_load(CONFIG_FILE, config_flags); + cfg = ast_config_load(CONFIG_FILE, reload_flags); /* Only destroy this cfg conditionally. Otherwise a crash happens. */ if (cfg != CONFIG_STATUS_FILEUNCHANGED) { ast_config_destroy(cfg); From 7126520b3e92e8ab09573930deef4d78e0c02d5f Mon Sep 17 00:00:00 2001 From: Alexander Traud Date: Tue, 24 Oct 2017 14:24:17 +0200 Subject: [PATCH 1578/1578] lpc10: Avoid compiler warning when DONT_OPTIMIZE/COMPILE_DOUBLE. ASTERISK-23556 Reported by: Marcello Ceschia Change-Id: Ic27e88e0336a0d83877dc857938659dc5560b93c --- codecs/lpc10/invert.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codecs/lpc10/invert.c b/codecs/lpc10/invert.c index 912117f9c5e..03c27e20d13 100644 --- a/codecs/lpc10/invert.c +++ b/codecs/lpc10/invert.c @@ -93,7 +93,8 @@ extern int invert_(integer *order, real *phi, real *psi, real *rc); /* Subroutine */ int invert_(integer *order, real *phi, real *psi, real *rc) { /* System generated locals */ - integer phi_dim1, phi_offset, i__1, i__2, i__3; + unsigned i__2; + integer phi_dim1, phi_offset, i__1, i__3; real r__1, r__2; /* Local variables */